x86: Fix SCI on IOAPIC != 0
authorYinghai Lu <yinghai@kernel.org>
Wed, 10 Feb 2010 09:20:05 +0000 (01:20 -0800)
committerH. Peter Anvin <hpa@zytor.com>
Wed, 10 Feb 2010 21:47:39 +0000 (13:47 -0800)
Thomas Renninger <trenn@suse.de> reported on IBM x3330

booting a latest kernel on this machine results in:

PCI: PCI BIOS revision 2.10 entry at 0xfd61c, last bus=1
PCI: Using configuration type 1 for base access bio: create slab <bio-0> at 0
ACPI: SCI (IRQ30) allocation failed
ACPI Exception: AE_NOT_ACQUIRED, Unable to install System Control Interrupt handler (20090903/evevent-161)
ACPI: Unable to start the ACPI Interpreter

Later all kind of devices fail...

and bisect it down to this commit:
commit b9c61b70075c87a8612624736faf4a2de5b1ed30

    x86/pci: update pirq_enable_irq() to setup io apic routing

it turns out we need to set irq routing for the sci on ioapic1 early.

-v2: make it work without sparseirq too.
-v3: fix checkpatch.pl warning, and cc to stable

Reported-by: Thomas Renninger <trenn@suse.de>
Bisected-by: Thomas Renninger <trenn@suse.de>
Tested-by: Thomas Renninger <trenn@suse.de>
Signed-off-by: Yinghai Lu <yinghai@kernel.org>
LKML-Reference: <1265793639-15071-2-git-send-email-yinghai@kernel.org>
Cc: stable@kernel.org
Signed-off-by: H. Peter Anvin <hpa@zytor.com>
arch/x86/include/asm/io_apic.h
arch/x86/kernel/acpi/boot.c
arch/x86/kernel/apic/io_apic.c

index 7c7c16cde1f8f3b5ddcf65f6a2f40d537368ad86..5f61f6e0ffdd73039bff49159ff41034a6efdde4 100644 (file)
@@ -160,6 +160,7 @@ extern int io_apic_get_redir_entries(int ioapic);
 struct io_apic_irq_attr;
 extern int io_apic_set_pci_routing(struct device *dev, int irq,
                 struct io_apic_irq_attr *irq_attr);
+void setup_IO_APIC_irq_extra(u32 gsi);
 extern int (*ioapic_renumber_irq)(int ioapic, int irq);
 extern void ioapic_init_mappings(void);
 extern void ioapic_insert_resources(void);
index 0acbcdfa5ca43d5533b8ec42939e7d05888e2cc4..5c96b75c6ea8433baebd1c3b92dee16cf34c71df 100644 (file)
@@ -446,6 +446,12 @@ void __init acpi_pic_sci_set_trigger(unsigned int irq, u16 trigger)
 int acpi_gsi_to_irq(u32 gsi, unsigned int *irq)
 {
        *irq = gsi;
+
+#ifdef CONFIG_X86_IO_APIC
+       if (acpi_irq_model == ACPI_IRQ_MODEL_IOAPIC)
+               setup_IO_APIC_irq_extra(gsi);
+#endif
+
        return 0;
 }
 
@@ -473,7 +479,8 @@ int acpi_register_gsi(struct device *dev, u32 gsi, int trigger, int polarity)
                plat_gsi = mp_register_gsi(dev, gsi, trigger, polarity);
        }
 #endif
-       acpi_gsi_to_irq(plat_gsi, &irq);
+       irq = plat_gsi;
+
        return irq;
 }
 
index 53243ca7816d131ee2821733b722ec0e4d8bd0b3..5e4cce254e438e479d5002319cfda3a804e46c93 100644 (file)
@@ -1538,6 +1538,56 @@ static void __init setup_IO_APIC_irqs(void)
                        " (apicid-pin) not connected\n");
 }
 
+/*
+ * for the gsit that is not in first ioapic
+ * but could not use acpi_register_gsi()
+ * like some special sci in IBM x3330
+ */
+void setup_IO_APIC_irq_extra(u32 gsi)
+{
+       int apic_id = 0, pin, idx, irq;
+       int node = cpu_to_node(boot_cpu_id);
+       struct irq_desc *desc;
+       struct irq_cfg *cfg;
+
+       /*
+        * Convert 'gsi' to 'ioapic.pin'.
+        */
+       apic_id = mp_find_ioapic(gsi);
+       if (apic_id < 0)
+               return;
+
+       pin = mp_find_ioapic_pin(apic_id, gsi);
+       idx = find_irq_entry(apic_id, pin, mp_INT);
+       if (idx == -1)
+               return;
+
+       irq = pin_2_irq(idx, apic_id, pin);
+#ifdef CONFIG_SPARSE_IRQ
+       desc = irq_to_desc(irq);
+       if (desc)
+               return;
+#endif
+       desc = irq_to_desc_alloc_node(irq, node);
+       if (!desc) {
+               printk(KERN_INFO "can not get irq_desc for %d\n", irq);
+               return;
+       }
+
+       cfg = desc->chip_data;
+       add_pin_to_irq_node(cfg, node, apic_id, pin);
+
+       if (test_bit(pin, mp_ioapic_routing[apic_id].pin_programmed)) {
+               pr_debug("Pin %d-%d already programmed\n",
+                        mp_ioapics[apic_id].apicid, pin);
+               return;
+       }
+       set_bit(pin, mp_ioapic_routing[apic_id].pin_programmed);
+
+       setup_IO_APIC_irq(apic_id, pin, irq, desc,
+                       irq_trigger(idx), irq_polarity(idx));
+}
+
 /*
  * Set up the timer pin, possibly with the 8259A-master behind.
  */