aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStefan Assmann <sassmann@suse.de>2008-06-11 10:35:17 -0400
committerIngo Molnar <mingo@elte.hu>2008-07-08 11:50:53 -0400
commite1d3a90846b40ad3160bf4b648d36c6badad39ac (patch)
tree3c078d2b6046d90d1045efbcefe6a76a424a6f63
parent426b3b8d535e3e141331dc19c40f457b997c4d6d (diff)
pci, acpi: reroute PCI interrupt to legacy boot interrupt equivalent
Some chipsets (e.g. intel 6700PXH) generate a legacy INTx when the IRQ entry in the chipset's IO-APIC is masked (as, e.g. the RT kernel does during interrupt handling). On chipsets where this INTx generation cannot be disabled, we reroute the valid interrupts to their legacy equivalent to get rid of spurious interrupts that might otherwise bring down (vital) interrupt lines through spurious interrupt detection in note_interrupt(). This patch benefited from discussions with Alexander Graf, Torsten Duwe, Ihno Krumreich, Daniel Gollub, Hannes Reinecke. The conclusions we drew and the patch itself are the authors' responsibility alone. Signed-off-by: Stefan Assmann <sassmann@suse.de> Signed-off-by: Olaf Dabrunz <od@suse.de> Signed-off-by: Ingo Molnar <mingo@elte.hu>
-rw-r--r--drivers/acpi/pci_irq.c56
-rw-r--r--drivers/pci/quirks.c28
-rw-r--r--include/linux/pci.h6
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
388extern int noioapicquirk;
389
390static 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 */
1373static 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}
1386DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_80333_0, quirk_reroute_to_boot_interrupts_intel);
1387DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_80333_1, quirk_reroute_to_boot_interrupts_intel);
1388DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB2_0, quirk_reroute_to_boot_interrupts_intel);
1389DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PXH_0, quirk_reroute_to_boot_interrupts_intel);
1390DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PXH_1, quirk_reroute_to_boot_interrupts_intel);
1391DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PXHV, quirk_reroute_to_boot_interrupts_intel);
1392DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_80332_0, quirk_reroute_to_boot_interrupts_intel);
1393DECLARE_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
120enum pci_irq_reroute_variant {
121 INTEL_IRQ_REROUTE_VARIANT = 1,
122 MAX_IRQ_REROUTE_VARIANTS = 3
123};
124
120typedef unsigned short __bitwise pci_bus_flags_t; 125typedef unsigned short __bitwise pci_bus_flags_t;
121enum pci_bus_flags { 126enum 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;