diff options
-rw-r--r-- | drivers/acpi/pci_irq.c | 56 | ||||
-rw-r--r-- | drivers/pci/quirks.c | 28 | ||||
-rw-r--r-- | include/linux/pci.h | 6 |
3 files changed, 90 insertions, 0 deletions
diff --git a/drivers/acpi/pci_irq.c b/drivers/acpi/pci_irq.c index 89022a74faee..b37cb0a9826e 100644 --- a/drivers/acpi/pci_irq.c +++ b/drivers/acpi/pci_irq.c | |||
@@ -384,6 +384,27 @@ acpi_pci_free_irq(struct acpi_prt_entry *entry, | |||
384 | return irq; | 384 | return irq; |
385 | } | 385 | } |
386 | 386 | ||
387 | #ifdef CONFIG_X86_IO_APIC | ||
388 | extern int noioapicquirk; | ||
389 | |||
390 | static int bridge_has_boot_interrupt_variant(struct pci_bus *bus) | ||
391 | { | ||
392 | struct pci_bus *bus_it; | ||
393 | |||
394 | for (bus_it = bus ; bus_it ; bus_it = bus_it->parent) { | ||
395 | if (!bus_it->self) | ||
396 | return 0; | ||
397 | |||
398 | printk(KERN_INFO "vendor=%04x device=%04x\n", bus_it->self->vendor, | ||
399 | bus_it->self->device); | ||
400 | |||
401 | if (bus_it->self->irq_reroute_variant) | ||
402 | return bus_it->self->irq_reroute_variant; | ||
403 | } | ||
404 | return 0; | ||
405 | } | ||
406 | #endif /* CONFIG_X86_IO_APIC */ | ||
407 | |||
387 | /* | 408 | /* |
388 | * acpi_pci_irq_lookup | 409 | * acpi_pci_irq_lookup |
389 | * success: return IRQ >= 0 | 410 | * success: return IRQ >= 0 |
@@ -413,6 +434,41 @@ acpi_pci_irq_lookup(struct pci_bus *bus, | |||
413 | } | 434 | } |
414 | 435 | ||
415 | ret = func(entry, triggering, polarity, link); | 436 | ret = func(entry, triggering, polarity, link); |
437 | |||
438 | #ifdef CONFIG_X86_IO_APIC | ||
439 | /* | ||
440 | * Some chipsets (e.g. intel 6700PXH) generate a legacy INTx when the | ||
441 | * IRQ entry in the chipset's IO-APIC is masked (as, e.g. the RT kernel | ||
442 | * does during interrupt handling). When this INTx generation cannot be | ||
443 | * disabled, we reroute these interrupts to their legacy equivalent to | ||
444 | * get rid of spurious interrupts. | ||
445 | */ | ||
446 | if (!noioapicquirk) { | ||
447 | switch (bridge_has_boot_interrupt_variant(bus)) { | ||
448 | case 0: | ||
449 | /* no rerouting necessary */ | ||
450 | break; | ||
451 | |||
452 | case INTEL_IRQ_REROUTE_VARIANT: | ||
453 | /* | ||
454 | * Remap according to INTx routing table in 6700PXH | ||
455 | * specs, intel order number 302628-002, section | ||
456 | * 2.15.2. Other chipsets (80332, ...) have the same | ||
457 | * mapping and are handled here as well. | ||
458 | */ | ||
459 | printk(KERN_INFO "pci irq %d -> rerouted to legacy " | ||
460 | "irq %d\n", ret, (ret % 4) + 16); | ||
461 | ret = (ret % 4) + 16; | ||
462 | break; | ||
463 | |||
464 | default: | ||
465 | printk(KERN_INFO "not rerouting irq %d to legacy irq: " | ||
466 | "unknown mapping\n", ret); | ||
467 | break; | ||
468 | } | ||
469 | } | ||
470 | #endif /* CONFIG_X86_IO_APIC */ | ||
471 | |||
416 | return ret; | 472 | return ret; |
417 | } | 473 | } |
418 | 474 | ||
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index eb97564316d0..ac634ae2eb08 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c | |||
@@ -1365,6 +1365,34 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x260b, quirk_intel_pcie_pm); | |||
1365 | 1365 | ||
1366 | #ifdef CONFIG_X86_IO_APIC | 1366 | #ifdef CONFIG_X86_IO_APIC |
1367 | /* | 1367 | /* |
1368 | * Boot interrupts on some chipsets cannot be turned off. For these chipsets, | ||
1369 | * remap the original interrupt in the linux kernel to the boot interrupt, so | ||
1370 | * that a PCI device's interrupt handler is installed on the boot interrupt | ||
1371 | * line instead. | ||
1372 | */ | ||
1373 | static void quirk_reroute_to_boot_interrupts_intel(struct pci_dev *dev) | ||
1374 | { | ||
1375 | int i; | ||
1376 | |||
1377 | if (noioapicquirk) | ||
1378 | return; | ||
1379 | |||
1380 | dev->irq_reroute_variant = INTEL_IRQ_REROUTE_VARIANT; | ||
1381 | |||
1382 | printk(KERN_INFO "PCI quirk: reroute interrupts for 0x%04x:0x%04x\n", | ||
1383 | dev->vendor, dev->device); | ||
1384 | return; | ||
1385 | } | ||
1386 | DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_80333_0, quirk_reroute_to_boot_interrupts_intel); | ||
1387 | DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_80333_1, quirk_reroute_to_boot_interrupts_intel); | ||
1388 | DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB2_0, quirk_reroute_to_boot_interrupts_intel); | ||
1389 | DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PXH_0, quirk_reroute_to_boot_interrupts_intel); | ||
1390 | DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PXH_1, quirk_reroute_to_boot_interrupts_intel); | ||
1391 | DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PXHV, quirk_reroute_to_boot_interrupts_intel); | ||
1392 | DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_80332_0, quirk_reroute_to_boot_interrupts_intel); | ||
1393 | DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_80332_1, quirk_reroute_to_boot_interrupts_intel); | ||
1394 | |||
1395 | /* | ||
1368 | * On some chipsets we can disable the generation of legacy INTx boot | 1396 | * On some chipsets we can disable the generation of legacy INTx boot |
1369 | * interrupts. | 1397 | * interrupts. |
1370 | */ | 1398 | */ |
diff --git a/include/linux/pci.h b/include/linux/pci.h index d18b1dd49fab..6755cf5ac109 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h | |||
@@ -117,6 +117,11 @@ enum pci_dev_flags { | |||
117 | PCI_DEV_FLAGS_MSI_INTX_DISABLE_BUG = (__force pci_dev_flags_t) 1, | 117 | PCI_DEV_FLAGS_MSI_INTX_DISABLE_BUG = (__force pci_dev_flags_t) 1, |
118 | }; | 118 | }; |
119 | 119 | ||
120 | enum pci_irq_reroute_variant { | ||
121 | INTEL_IRQ_REROUTE_VARIANT = 1, | ||
122 | MAX_IRQ_REROUTE_VARIANTS = 3 | ||
123 | }; | ||
124 | |||
120 | typedef unsigned short __bitwise pci_bus_flags_t; | 125 | typedef unsigned short __bitwise pci_bus_flags_t; |
121 | enum pci_bus_flags { | 126 | enum pci_bus_flags { |
122 | PCI_BUS_FLAGS_NO_MSI = (__force pci_bus_flags_t) 1, | 127 | PCI_BUS_FLAGS_NO_MSI = (__force pci_bus_flags_t) 1, |
@@ -194,6 +199,7 @@ struct pci_dev { | |||
194 | unsigned int no_d1d2:1; /* only allow d0 or d3 */ | 199 | unsigned int no_d1d2:1; /* only allow d0 or d3 */ |
195 | unsigned int block_ucfg_access:1; /* userspace config space access is blocked */ | 200 | unsigned int block_ucfg_access:1; /* userspace config space access is blocked */ |
196 | unsigned int broken_parity_status:1; /* Device generates false positive parity */ | 201 | unsigned int broken_parity_status:1; /* Device generates false positive parity */ |
202 | unsigned int irq_reroute_variant:2; /* device needs IRQ rerouting variant */ | ||
197 | unsigned int msi_enabled:1; | 203 | unsigned int msi_enabled:1; |
198 | unsigned int msix_enabled:1; | 204 | unsigned int msix_enabled:1; |
199 | unsigned int is_managed:1; | 205 | unsigned int is_managed:1; |