diff options
| author | Suresh Siddha <suresh.b.siddha@intel.com> | 2009-03-16 20:04:53 -0400 |
|---|---|---|
| committer | H. Peter Anvin <hpa@linux.intel.com> | 2009-03-17 18:36:40 -0400 |
| commit | 4c5502b1c5744b2090414e1b80ca6388d5c46e06 (patch) | |
| tree | 6447f553238a2522719fcf3c28b33a19e516f71c | |
| parent | 0ca0f16fd17c5d880dd0abbe03595b0c7c5b3c95 (diff) | |
x86, x2apic: fix lock ordering during IRQ migration
Impact: fix potential deadlock on x2apic
fix "hard-safe -> hard-unsafe lock order detected" with irq_2_ir_lock
On x2apic enabled system:
[ INFO: hard-safe -> hard-unsafe lock order detected ]
2.6.27-03151-g4480f15b #1
------------------------------------------------------
swapper/1 [HC0[0]:SC0[0]:HE0:SE1] is trying to acquire:
(irq_2_ir_lock){--..}, at: [<ffffffff8038ebc0>] get_irte+0x2f/0x95
and this task is already holding:
(&irq_desc_lock_class){+...}, at: [<ffffffff802649ed>] setup_irq+0x67/0x281
which would create a new lock dependency:
(&irq_desc_lock_class){+...} -> (irq_2_ir_lock){--..}
but this new dependency connects a hard-irq-safe lock:
(&irq_desc_lock_class){+...}
... which became hard-irq-safe at:
[<ffffffffffffffff>] 0xffffffffffffffff
to a hard-irq-unsafe lock:
(irq_2_ir_lock){--..}
... which became hard-irq-unsafe at:
... [<ffffffff802547b5>] __lock_acquire+0x571/0x706
[<ffffffff8025499f>] lock_acquire+0x55/0x71
[<ffffffff8062f2c4>] _spin_lock+0x2c/0x38
[<ffffffff8038ee50>] alloc_irte+0x8a/0x14b
[<ffffffff8021f733>] setup_IO_APIC_irq+0x119/0x30e
[<ffffffff8090860e>] setup_IO_APIC+0x146/0x6e5
[<ffffffff809058fc>] native_smp_prepare_cpus+0x24e/0x2e9
[<ffffffff808f982c>] kernel_init+0x5a/0x176
[<ffffffff8020c289>] child_rip+0xa/0x11
[<ffffffffffffffff>] 0xffffffffffffffff
Fix this theoretical lock order issue by using spin_lock_irqsave() instead of
spin_lock()
Signed-off-by: Suresh Siddha <suresh.b.siddha@intel.com>
Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
| -rw-r--r-- | drivers/pci/intr_remapping.c | 58 |
1 files changed, 33 insertions, 25 deletions
diff --git a/drivers/pci/intr_remapping.c b/drivers/pci/intr_remapping.c index 8e44db040db7..5ffa65fffb6a 100644 --- a/drivers/pci/intr_remapping.c +++ b/drivers/pci/intr_remapping.c | |||
| @@ -117,21 +117,22 @@ int get_irte(int irq, struct irte *entry) | |||
| 117 | { | 117 | { |
| 118 | int index; | 118 | int index; |
| 119 | struct irq_2_iommu *irq_iommu; | 119 | struct irq_2_iommu *irq_iommu; |
| 120 | unsigned long flags; | ||
| 120 | 121 | ||
| 121 | if (!entry) | 122 | if (!entry) |
| 122 | return -1; | 123 | return -1; |
| 123 | 124 | ||
| 124 | spin_lock(&irq_2_ir_lock); | 125 | spin_lock_irqsave(&irq_2_ir_lock, flags); |
| 125 | irq_iommu = valid_irq_2_iommu(irq); | 126 | irq_iommu = valid_irq_2_iommu(irq); |
| 126 | if (!irq_iommu) { | 127 | if (!irq_iommu) { |
| 127 | spin_unlock(&irq_2_ir_lock); | 128 | spin_unlock_irqrestore(&irq_2_ir_lock, flags); |
| 128 | return -1; | 129 | return -1; |
| 129 | } | 130 | } |
| 130 | 131 | ||
| 131 | index = irq_iommu->irte_index + irq_iommu->sub_handle; | 132 | index = irq_iommu->irte_index + irq_iommu->sub_handle; |
| 132 | *entry = *(irq_iommu->iommu->ir_table->base + index); | 133 | *entry = *(irq_iommu->iommu->ir_table->base + index); |
| 133 | 134 | ||
| 134 | spin_unlock(&irq_2_ir_lock); | 135 | spin_unlock_irqrestore(&irq_2_ir_lock, flags); |
| 135 | return 0; | 136 | return 0; |
| 136 | } | 137 | } |
| 137 | 138 | ||
| @@ -141,6 +142,7 @@ int alloc_irte(struct intel_iommu *iommu, int irq, u16 count) | |||
| 141 | struct irq_2_iommu *irq_iommu; | 142 | struct irq_2_iommu *irq_iommu; |
| 142 | u16 index, start_index; | 143 | u16 index, start_index; |
| 143 | unsigned int mask = 0; | 144 | unsigned int mask = 0; |
| 145 | unsigned long flags; | ||
| 144 | int i; | 146 | int i; |
| 145 | 147 | ||
| 146 | if (!count) | 148 | if (!count) |
| @@ -170,7 +172,7 @@ int alloc_irte(struct intel_iommu *iommu, int irq, u16 count) | |||
| 170 | return -1; | 172 | return -1; |
| 171 | } | 173 | } |
| 172 | 174 | ||
| 173 | spin_lock(&irq_2_ir_lock); | 175 | spin_lock_irqsave(&irq_2_ir_lock, flags); |
| 174 | do { | 176 | do { |
| 175 | for (i = index; i < index + count; i++) | 177 | for (i = index; i < index + count; i++) |
| 176 | if (table->base[i].present) | 178 | if (table->base[i].present) |
| @@ -182,7 +184,7 @@ int alloc_irte(struct intel_iommu *iommu, int irq, u16 count) | |||
| 182 | index = (index + count) % INTR_REMAP_TABLE_ENTRIES; | 184 | index = (index + count) % INTR_REMAP_TABLE_ENTRIES; |
| 183 | 185 | ||
| 184 | if (index == start_index) { | 186 | if (index == start_index) { |
| 185 | spin_unlock(&irq_2_ir_lock); | 187 | spin_unlock_irqrestore(&irq_2_ir_lock, flags); |
| 186 | printk(KERN_ERR "can't allocate an IRTE\n"); | 188 | printk(KERN_ERR "can't allocate an IRTE\n"); |
| 187 | return -1; | 189 | return -1; |
| 188 | } | 190 | } |
| @@ -193,7 +195,7 @@ int alloc_irte(struct intel_iommu *iommu, int irq, u16 count) | |||
| 193 | 195 | ||
| 194 | irq_iommu = irq_2_iommu_alloc(irq); | 196 | irq_iommu = irq_2_iommu_alloc(irq); |
| 195 | if (!irq_iommu) { | 197 | if (!irq_iommu) { |
| 196 | spin_unlock(&irq_2_ir_lock); | 198 | spin_unlock_irqrestore(&irq_2_ir_lock, flags); |
| 197 | printk(KERN_ERR "can't allocate irq_2_iommu\n"); | 199 | printk(KERN_ERR "can't allocate irq_2_iommu\n"); |
| 198 | return -1; | 200 | return -1; |
| 199 | } | 201 | } |
| @@ -203,7 +205,7 @@ int alloc_irte(struct intel_iommu *iommu, int irq, u16 count) | |||
| 203 | irq_iommu->sub_handle = 0; | 205 | irq_iommu->sub_handle = 0; |
| 204 | irq_iommu->irte_mask = mask; | 206 | irq_iommu->irte_mask = mask; |
| 205 | 207 | ||
| 206 | spin_unlock(&irq_2_ir_lock); | 208 | spin_unlock_irqrestore(&irq_2_ir_lock, flags); |
| 207 | 209 | ||
| 208 | return index; | 210 | return index; |
| 209 | } | 211 | } |
| @@ -223,30 +225,32 @@ int map_irq_to_irte_handle(int irq, u16 *sub_handle) | |||
| 223 | { | 225 | { |
| 224 | int index; | 226 | int index; |
| 225 | struct irq_2_iommu *irq_iommu; | 227 | struct irq_2_iommu *irq_iommu; |
| 228 | unsigned long flags; | ||
| 226 | 229 | ||
| 227 | spin_lock(&irq_2_ir_lock); | 230 | spin_lock_irqsave(&irq_2_ir_lock, flags); |
| 228 | irq_iommu = valid_irq_2_iommu(irq); | 231 | irq_iommu = valid_irq_2_iommu(irq); |
| 229 | if (!irq_iommu) { | 232 | if (!irq_iommu) { |
| 230 | spin_unlock(&irq_2_ir_lock); | 233 | spin_unlock_irqrestore(&irq_2_ir_lock, flags); |
| 231 | return -1; | 234 | return -1; |
| 232 | } | 235 | } |
| 233 | 236 | ||
| 234 | *sub_handle = irq_iommu->sub_handle; | 237 | *sub_handle = irq_iommu->sub_handle; |
| 235 | index = irq_iommu->irte_index; | 238 | index = irq_iommu->irte_index; |
| 236 | spin_unlock(&irq_2_ir_lock); | 239 | spin_unlock_irqrestore(&irq_2_ir_lock, flags); |
| 237 | return index; | 240 | return index; |
| 238 | } | 241 | } |
| 239 | 242 | ||
| 240 | int set_irte_irq(int irq, struct intel_iommu *iommu, u16 index, u16 subhandle) | 243 | int set_irte_irq(int irq, struct intel_iommu *iommu, u16 index, u16 subhandle) |
| 241 | { | 244 | { |
| 242 | struct irq_2_iommu *irq_iommu; | 245 | struct irq_2_iommu *irq_iommu; |
| 246 | unsigned long flags; | ||
| 243 | 247 | ||
| 244 | spin_lock(&irq_2_ir_lock); | 248 | spin_lock_irqsave(&irq_2_ir_lock, flags); |
| 245 | 249 | ||
| 246 | irq_iommu = irq_2_iommu_alloc(irq); | 250 | irq_iommu = irq_2_iommu_alloc(irq); |
| 247 | 251 | ||
| 248 | if (!irq_iommu) { | 252 | if (!irq_iommu) { |
| 249 | spin_unlock(&irq_2_ir_lock); | 253 | spin_unlock_irqrestore(&irq_2_ir_lock, flags); |
| 250 | printk(KERN_ERR "can't allocate irq_2_iommu\n"); | 254 | printk(KERN_ERR "can't allocate irq_2_iommu\n"); |
| 251 | return -1; | 255 | return -1; |
| 252 | } | 256 | } |
| @@ -256,7 +260,7 @@ int set_irte_irq(int irq, struct intel_iommu *iommu, u16 index, u16 subhandle) | |||
| 256 | irq_iommu->sub_handle = subhandle; | 260 | irq_iommu->sub_handle = subhandle; |
| 257 | irq_iommu->irte_mask = 0; | 261 | irq_iommu->irte_mask = 0; |
| 258 | 262 | ||
| 259 | spin_unlock(&irq_2_ir_lock); | 263 | spin_unlock_irqrestore(&irq_2_ir_lock, flags); |
| 260 | 264 | ||
| 261 | return 0; | 265 | return 0; |
| 262 | } | 266 | } |
| @@ -264,11 +268,12 @@ int set_irte_irq(int irq, struct intel_iommu *iommu, u16 index, u16 subhandle) | |||
| 264 | int clear_irte_irq(int irq, struct intel_iommu *iommu, u16 index) | 268 | int clear_irte_irq(int irq, struct intel_iommu *iommu, u16 index) |
| 265 | { | 269 | { |
| 266 | struct irq_2_iommu *irq_iommu; | 270 | struct irq_2_iommu *irq_iommu; |
| 271 | unsigned long flags; | ||
| 267 | 272 | ||
| 268 | spin_lock(&irq_2_ir_lock); | 273 | spin_lock_irqsave(&irq_2_ir_lock, flags); |
| 269 | irq_iommu = valid_irq_2_iommu(irq); | 274 | irq_iommu = valid_irq_2_iommu(irq); |
| 270 | if (!irq_iommu) { | 275 | if (!irq_iommu) { |
| 271 | spin_unlock(&irq_2_ir_lock); | 276 | spin_unlock_irqrestore(&irq_2_ir_lock, flags); |
| 272 | return -1; | 277 | return -1; |
| 273 | } | 278 | } |
| 274 | 279 | ||
| @@ -277,7 +282,7 @@ int clear_irte_irq(int irq, struct intel_iommu *iommu, u16 index) | |||
| 277 | irq_iommu->sub_handle = 0; | 282 | irq_iommu->sub_handle = 0; |
| 278 | irq_2_iommu(irq)->irte_mask = 0; | 283 | irq_2_iommu(irq)->irte_mask = 0; |
| 279 | 284 | ||
| 280 | spin_unlock(&irq_2_ir_lock); | 285 | spin_unlock_irqrestore(&irq_2_ir_lock, flags); |
| 281 | 286 | ||
| 282 | return 0; | 287 | return 0; |
| 283 | } | 288 | } |
| @@ -289,11 +294,12 @@ int modify_irte(int irq, struct irte *irte_modified) | |||
| 289 | struct irte *irte; | 294 | struct irte *irte; |
| 290 | struct intel_iommu *iommu; | 295 | struct intel_iommu *iommu; |
| 291 | struct irq_2_iommu *irq_iommu; | 296 | struct irq_2_iommu *irq_iommu; |
| 297 | unsigned long flags; | ||
| 292 | 298 | ||
| 293 | spin_lock(&irq_2_ir_lock); | 299 | spin_lock_irqsave(&irq_2_ir_lock, flags); |
| 294 | irq_iommu = valid_irq_2_iommu(irq); | 300 | irq_iommu = valid_irq_2_iommu(irq); |
| 295 | if (!irq_iommu) { | 301 | if (!irq_iommu) { |
| 296 | spin_unlock(&irq_2_ir_lock); | 302 | spin_unlock_irqrestore(&irq_2_ir_lock, flags); |
| 297 | return -1; | 303 | return -1; |
| 298 | } | 304 | } |
| 299 | 305 | ||
| @@ -306,7 +312,7 @@ int modify_irte(int irq, struct irte *irte_modified) | |||
| 306 | __iommu_flush_cache(iommu, irte, sizeof(*irte)); | 312 | __iommu_flush_cache(iommu, irte, sizeof(*irte)); |
| 307 | 313 | ||
| 308 | rc = qi_flush_iec(iommu, index, 0); | 314 | rc = qi_flush_iec(iommu, index, 0); |
| 309 | spin_unlock(&irq_2_ir_lock); | 315 | spin_unlock_irqrestore(&irq_2_ir_lock, flags); |
| 310 | 316 | ||
| 311 | return rc; | 317 | return rc; |
| 312 | } | 318 | } |
| @@ -317,11 +323,12 @@ int flush_irte(int irq) | |||
| 317 | int index; | 323 | int index; |
| 318 | struct intel_iommu *iommu; | 324 | struct intel_iommu *iommu; |
| 319 | struct irq_2_iommu *irq_iommu; | 325 | struct irq_2_iommu *irq_iommu; |
| 326 | unsigned long flags; | ||
| 320 | 327 | ||
| 321 | spin_lock(&irq_2_ir_lock); | 328 | spin_lock_irqsave(&irq_2_ir_lock, flags); |
| 322 | irq_iommu = valid_irq_2_iommu(irq); | 329 | irq_iommu = valid_irq_2_iommu(irq); |
| 323 | if (!irq_iommu) { | 330 | if (!irq_iommu) { |
| 324 | spin_unlock(&irq_2_ir_lock); | 331 | spin_unlock_irqrestore(&irq_2_ir_lock, flags); |
| 325 | return -1; | 332 | return -1; |
| 326 | } | 333 | } |
| 327 | 334 | ||
| @@ -330,7 +337,7 @@ int flush_irte(int irq) | |||
| 330 | index = irq_iommu->irte_index + irq_iommu->sub_handle; | 337 | index = irq_iommu->irte_index + irq_iommu->sub_handle; |
| 331 | 338 | ||
| 332 | rc = qi_flush_iec(iommu, index, irq_iommu->irte_mask); | 339 | rc = qi_flush_iec(iommu, index, irq_iommu->irte_mask); |
| 333 | spin_unlock(&irq_2_ir_lock); | 340 | spin_unlock_irqrestore(&irq_2_ir_lock, flags); |
| 334 | 341 | ||
| 335 | return rc; | 342 | return rc; |
| 336 | } | 343 | } |
| @@ -363,11 +370,12 @@ int free_irte(int irq) | |||
| 363 | struct irte *irte; | 370 | struct irte *irte; |
| 364 | struct intel_iommu *iommu; | 371 | struct intel_iommu *iommu; |
| 365 | struct irq_2_iommu *irq_iommu; | 372 | struct irq_2_iommu *irq_iommu; |
| 373 | unsigned long flags; | ||
| 366 | 374 | ||
| 367 | spin_lock(&irq_2_ir_lock); | 375 | spin_lock_irqsave(&irq_2_ir_lock, flags); |
| 368 | irq_iommu = valid_irq_2_iommu(irq); | 376 | irq_iommu = valid_irq_2_iommu(irq); |
| 369 | if (!irq_iommu) { | 377 | if (!irq_iommu) { |
| 370 | spin_unlock(&irq_2_ir_lock); | 378 | spin_unlock_irqrestore(&irq_2_ir_lock, flags); |
| 371 | return -1; | 379 | return -1; |
| 372 | } | 380 | } |
| 373 | 381 | ||
| @@ -387,7 +395,7 @@ int free_irte(int irq) | |||
| 387 | irq_iommu->sub_handle = 0; | 395 | irq_iommu->sub_handle = 0; |
| 388 | irq_iommu->irte_mask = 0; | 396 | irq_iommu->irte_mask = 0; |
| 389 | 397 | ||
| 390 | spin_unlock(&irq_2_ir_lock); | 398 | spin_unlock_irqrestore(&irq_2_ir_lock, flags); |
| 391 | 399 | ||
| 392 | return rc; | 400 | return rc; |
| 393 | } | 401 | } |
