|
@@ -303,6 +303,61 @@ void acpi_pci_irq_del_prt(struct pci_bus *bus)
|
|
|
/* --------------------------------------------------------------------------
|
|
|
PCI Interrupt Routing Support
|
|
|
-------------------------------------------------------------------------- */
|
|
|
+#ifdef CONFIG_X86_IO_APIC
|
|
|
+extern int noioapicquirk;
|
|
|
+extern int noioapicreroute;
|
|
|
+
|
|
|
+static int bridge_has_boot_interrupt_variant(struct pci_bus *bus)
|
|
|
+{
|
|
|
+ struct pci_bus *bus_it;
|
|
|
+
|
|
|
+ for (bus_it = bus ; bus_it ; bus_it = bus_it->parent) {
|
|
|
+ if (!bus_it->self)
|
|
|
+ return 0;
|
|
|
+ if (bus_it->self->irq_reroute_variant)
|
|
|
+ return bus_it->self->irq_reroute_variant;
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * 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). When this INTx generation cannot be disabled,
|
|
|
+ * we reroute these interrupts to their legacy equivalent to get rid of
|
|
|
+ * spurious interrupts.
|
|
|
+ */
|
|
|
+static int acpi_reroute_boot_interrupt(struct pci_dev *dev,
|
|
|
+ struct acpi_prt_entry *entry)
|
|
|
+{
|
|
|
+ if (noioapicquirk || noioapicreroute) {
|
|
|
+ return 0;
|
|
|
+ } else {
|
|
|
+ switch (bridge_has_boot_interrupt_variant(dev->bus)) {
|
|
|
+ case 0:
|
|
|
+ /* no rerouting necessary */
|
|
|
+ return 0;
|
|
|
+ case INTEL_IRQ_REROUTE_VARIANT:
|
|
|
+ /*
|
|
|
+ * Remap according to INTx routing table in 6700PXH
|
|
|
+ * specs, intel order number 302628-002, section
|
|
|
+ * 2.15.2. Other chipsets (80332, ...) have the same
|
|
|
+ * mapping and are handled here as well.
|
|
|
+ */
|
|
|
+ dev_info(&dev->dev, "PCI IRQ %d -> rerouted to legacy "
|
|
|
+ "IRQ %d\n", entry->index,
|
|
|
+ (entry->index % 4) + 16);
|
|
|
+ entry->index = (entry->index % 4) + 16;
|
|
|
+ return 1;
|
|
|
+ default:
|
|
|
+ dev_warn(&dev->dev, "Cannot reroute IRQ %d to legacy "
|
|
|
+ "IRQ: unknown mapping\n", entry->index);
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+#endif /* CONFIG_X86_IO_APIC */
|
|
|
+
|
|
|
static struct acpi_prt_entry *acpi_pci_irq_lookup(struct pci_dev *dev, int pin)
|
|
|
{
|
|
|
struct acpi_prt_entry *entry;
|
|
@@ -311,6 +366,9 @@ static struct acpi_prt_entry *acpi_pci_irq_lookup(struct pci_dev *dev, int pin)
|
|
|
|
|
|
entry = acpi_pci_irq_find_prt_entry(dev, pin);
|
|
|
if (entry) {
|
|
|
+#ifdef CONFIG_X86_IO_APIC
|
|
|
+ acpi_reroute_boot_interrupt(dev, entry);
|
|
|
+#endif /* CONFIG_X86_IO_APIC */
|
|
|
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found %s[%c] _PRT entry\n",
|
|
|
pci_name(dev), pin_name(pin)));
|
|
|
return entry;
|