Re: [PATCH] ACPI PCI IRQ routing rework

Bjorn Helgaas
2004-05-17T14:57:55Z

On Monday 17 May 2004 4:09 am, SEN,SOURAV (HP-India,ex2) wrote:
> For large IO configs, this _may_ lead to kernel panic-ing
> when the driver calls pci_enable_device(). And this panic
> is not due to some driver bug either.

True, ia64 currently panics when we run out of interrupt vectors.
That is true both with and without my patch. I agree that's a
problem we should address, but I think that should be done with
a separate patch, since it's an ia64-only problem.

Or are you saying that my patch introduces a new panic situation
that didn't exist before? I don't think that's the case, but
please point it out more explicitly if it is.

> So, when we run out of interrupt vectors (I am talking
> w.r.t ia64) instead of panic-ing in assign_irq_vector()
> why not give error return to clients of pci_enable_device()
> after printing some messages. This way kernel at least
> does not panic. If the card which could not be claimed
> due to this limitation is indispensable, then some
> other method can be tried out by sysadmins by gracefully
> shutting down the system -- better than panic.
>
> Thanks
> Sourav
> HP-STS, Bangalore
> +91-80-2205-1897
>
>
> + -----Original Message-----
> + From: linux-ia64-owner@vger.kernel.org
> + [mailto:linux-ia64-owner@vger.kernel.org]On Behalf Of Bjorn Helgaas
> + Sent: Saturday, May 15, 2004 10:51 PM
> + To: acpi-devel@lists.sourceforge.net
> + Cc: Len Brown; David Mosberger; Andi Kleen; Jun Nakajima;
> + linux-ia64@vger.kernel.org
> + Subject: [PATCH] ACPI PCI IRQ routing rework
> +
> +
> + This patch changes the way we handle ACPI PRTs (PCI Routing Tables).
> +
> + Previously, the arch code looked through all the PRT entries once at
> + boot-time (in mp_parse_prt() or iosapic_parse_prt()), allocating IRQs
> + and programming the IO-APICs or IOSAPICs.
> +
> + I think it's better to pull all the PRT knowledge out of the arch
> + code and do the IRQ allocation and IO-APIC programming at the time
> + of pci_enable_device(). That reduces IRQ usage (since many PRT
> + entries are never used) and is a step toward allowing the addition
> + of new root bridges and PRTs at run-time.
> +
> + The architecture supplies
> +
> + unsigned int
> + acpi_register_gsi(u32 gsi, int edge_level, int active_high_low);
> +
> + which is called by acpi_pci_irq_enable(). That way ACPI supplies
> + all the information from the PRT, and the arch sets up the routing
> + and returns the IRQ it allocated.
> +
> + I've tested this on several ia64 boxes (mostly HP), and a small
> + x86_64 box. It compiles for i386, but I don't have a way to test
> + that. I'm interested in any feedback or testing reports.
> +
> + === arch/i386/kernel/mpparse.c 1.71 vs edited ==> + --- 1.71/arch/i386/kernel/mpparse.c Fri Apr 30 23:27:25 2004
> + +++ edited/arch/i386/kernel/mpparse.c Sat May 15 09:13:26 2004
> + @@ -1027,94 +1027,58 @@
> +
> + extern FADT_DESCRIPTOR acpi_fadt;
> +
> + -#ifdef CONFIG_ACPI_PCI
> + +#endif /*CONFIG_X86_IO_APIC && CONFIG_ACPI_INTERPRETER*/
> + +
> + +#ifdef CONFIG_X86_IO_APIC
> +
> + -void __init mp_parse_prt (void)
> + +void mp_register_gsi (u32 gsi, int edge_level, int active_high_low)
> + {
> + - struct list_head *node = NULL;
> + - struct acpi_prt_entry *entry = NULL;
> + int ioapic = -1;
> + int ioapic_pin = 0;
> + - int gsi = 0;
> + int idx, bit = 0;
> + - int edge_level = 0;
> + - int active_high_low = 0;
> +
> + - /*
> + - * Parsing through the PCI Interrupt Routing Table
> + (PRT) and program
> + - * routing for all entries.
> + - */
> + - list_for_each(node, &acpi_prt.entries) {
> + - entry = list_entry(node, struct acpi_prt_entry, node);
> + + /* Don't set up the ACPI SCI because it's already set up */
> + + if (acpi_fadt.sci_int = gsi)
> + + return;
> + +
> + + ioapic = mp_find_ioapic(gsi);
> + + if (ioapic < 0) {
> + + printk(KERN_WARNING "No IOAPIC for GSI 0x%x\n", gsi);
> + + return;
> + + }
> + +
> + + ioapic_pin = gsi - mp_ioapic_routing[ioapic].gsi_base;
> +
> + - /* Need to get gsi for dynamic entry */
> + - if (entry->link.handle) {
> + - gsi =
> + acpi_pci_link_get_irq(entry->link.handle, entry->link.index,
> + &edge_level, &active_high_low);
> + - if (!gsi)
> + - continue;
> + - }
> + - else {
> + - /* Hardwired GSI. Assume PCI standard
> + settings */
> + - gsi = entry->link.index;
> + - edge_level = 1;
> + - active_high_low = 1;
> + - }
> + -
> + - /* Don't set up the ACPI SCI because it's
> + already set up */
> + - if (acpi_fadt.sci_int = gsi) {
> + - /* we still need to set entry's irq */
> + - acpi_gsi_to_irq(gsi, &entry->irq);
> + - continue;
> + - }
> + -
> + - ioapic = mp_find_ioapic(gsi);
> + - if (ioapic < 0)
> + - continue;
> + - ioapic_pin = gsi - mp_ioapic_routing[ioapic].gsi_base;
> + -
> + - if (es7000_plat) {
> + - if (!ioapic && (gsi < 16))
> + - gsi += 16;
> + - }
> + -
> + - /*
> + - * Avoid pin reprogramming. PRTs typically
> + include entries
> + - * with redundant pin->gsi mappings (but unique
> + PCI devices);
> + - * we only only program the IOAPIC on the first.
> + - */
> + - bit = ioapic_pin % 32;
> + - idx = (ioapic_pin < 32) ? 0 : (ioapic_pin / 32);
> + - if (idx > 3) {
> + - printk(KERN_ERR "Invalid reference to
> + IOAPIC pin "
> + - "%d-%d\n",
> + mp_ioapic_routing[ioapic].apic_id,
> + - ioapic_pin);
> + - continue;
> + - }
> + - if ((1<<bit) &
> + mp_ioapic_routing[ioapic].pin_programmed[idx]) {
> + - Dprintk(KERN_DEBUG "Pin %d-%d already
> + programmed\n",
> + -
> + mp_ioapic_routing[ioapic].apic_id, ioapic_pin);
> + - acpi_gsi_to_irq(gsi, &entry->irq);
> + - continue;
> + - }
> + -
> + - mp_ioapic_routing[ioapic].pin_programmed[idx]
> + |= (1<<bit);
> + -
> + - if (!io_apic_set_pci_routing(ioapic,
> + ioapic_pin, gsi, edge_level, active_high_low)) {
> + - acpi_gsi_to_irq(gsi, &entry->irq);
> + - }
> + - printk(KERN_DEBUG "%02x:%02x:%02x[%c] -> %d-%d
> + -> IRQ %d %s %s\n",
> + - entry->id.segment, entry->id.bus,
> + - entry->id.device, ('A' + entry->pin),
> + - mp_ioapic_routing[ioapic].apic_id, ioapic_pin,
> + - entry->irq, edge_level ? "level" : "edge",
> + - active_high_low ? "low" : "high");
> + + if (es7000_plat) {
> + + if (!ioapic && (gsi < 16))
> + + gsi += 16;
> + }
> +
> + - print_IO_APIC();
> + + /*
> + + * Avoid pin reprogramming. PRTs typically include entries
> + + * with redundant pin->gsi mappings (but unique PCI devices);
> + + * we only only program the IOAPIC on the first.
> + + */
> + + bit = ioapic_pin % 32;
> + + idx = (ioapic_pin < 32) ? 0 : (ioapic_pin / 32);
> + + if (idx > 3) {
> + + printk(KERN_ERR "Invalid reference to IOAPIC pin "
> + + "%d-%d\n", mp_ioapic_routing[ioapic].apic_id,
> + + ioapic_pin);
> + + return;
> + + }
> + + if ((1<<bit) & mp_ioapic_routing[ioapic].pin_programmed[idx]) {
> + + Dprintk(KERN_DEBUG "Pin %d-%d already programmed\n",
> + + mp_ioapic_routing[ioapic].apic_id, ioapic_pin);
> + + return;
> + + }
> +
> + - return;
> + + mp_ioapic_routing[ioapic].pin_programmed[idx] |= (1<<bit);
> + +
> + + io_apic_set_pci_routing(ioapic, ioapic_pin, gsi,
> + + edge_level = ACPI_EDGE_SENSITIVE ? 0 : 1,
> + + active_high_low = ACPI_ACTIVE_HIGH ? 0 : 1);
> + }
> +
> + -#endif /*CONFIG_ACPI_PCI*/
> + -#endif /*CONFIG_X86_IO_APIC && CONFIG_ACPI_INTERPRETER*/
> + +#endif /*CONFIG_X86_IO_APIC*/
> + #endif /*CONFIG_ACPI_BOOT*/
> + === arch/i386/kernel/acpi/boot.c 1.60 vs edited ==> + --- 1.60/arch/i386/kernel/acpi/boot.c Fri Apr 23 06:39:18 2004
> + +++ edited/arch/i386/kernel/acpi/boot.c Sat May 15 09:13:26 2004
> + @@ -438,6 +438,28 @@
> + return 0;
> + }
> +
> + +unsigned int acpi_register_gsi(u32 gsi, int edge_level, int
> + active_high_low)
> + +{
> + + static u16 irq_mask;
> + + unsigned int irq;
> + + extern void eisa_set_level_irq(unsigned int irq);
> + +
> + + /*
> + + * Make sure all (legacy) PCI IRQs are set as level-triggered.
> + + */
> + + if ((gsi < 16) && !((1 << gsi) & irq_mask)) {
> + + printk(KERN_DEBUG PREFIX "Setting GSI 0x%x as
> + level-triggered\n", gsi);
> + + irq_mask |= (1 << gsi);
> + + eisa_set_level_irq(gsi);
> + + }
> + +
> + +#ifdef CONFIG_X86_IO_APIC
> + + mp_register_gsi(gsi, edge_level, active_high_low);
> + +#endif
> + + acpi_gsi_to_irq(gsi, &irq);
> + + return irq;
> + +}
> + +
> + static unsigned long __init
> + acpi_scan_rsdp (
> + unsigned long start,
> + === arch/i386/pci/acpi.c 1.13 vs edited ==> + --- 1.13/arch/i386/pci/acpi.c Fri Apr 30 23:27:25 2004
> + +++ edited/arch/i386/pci/acpi.c Sat May 15 10:56:08 2004
> + @@ -1,6 +1,8 @@
> + #include <linux/pci.h>
> + #include <linux/acpi.h>
> + #include <linux/init.h>
> + +#include <linux/irq.h>
> + +#include <asm/hw_irq.h>
> + #include "pci.h"
> +
> + struct pci_bus * __devinit pci_acpi_scan_root(struct
> + acpi_device *device, int domain, int busnum)
> + @@ -15,18 +17,28 @@
> +
> + static int __init pci_acpi_init(void)
> + {
> + + struct pci_dev *dev = NULL;
> + +
> + if (pcibios_scanned)
> + return 0;
> +
> + - if (!acpi_noirq) {
> + - if (!acpi_pci_irq_init()) {
> + - printk(KERN_INFO "PCI: Using ACPI for
> + IRQ routing\n");
> + - pcibios_scanned++;
> + - pcibios_enable_irq = acpi_pci_irq_enable;
> + - } else
> + - printk(KERN_WARNING "PCI: Invalid
> + ACPI-PCI IRQ routing table\n");
> + + if (acpi_noirq)
> + + return 0;
> +
> + - }
> + + printk(KERN_INFO "PCI: Using ACPI for IRQ routing\n");
> + + acpi_irq_penalty_init();
> + + pcibios_scanned++;
> + + pcibios_enable_irq = acpi_pci_irq_enable;
> + +
> + + /*
> + + * PCI IRQ routing is set up by pci_enable_device(), but we
> + + * also do it here in case there are still broken drivers that
> + + * don't use pci_enable_device().
> + + */
> + + while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID,
> + dev)) != NULL)
> + + acpi_pci_irq_enable(dev);
> + +
> + + print_IO_APIC();
> +
> + return 0;
> + }
> + === arch/ia64/kernel/acpi.c 1.68 vs edited ==> + --- 1.68/arch/ia64/kernel/acpi.c Thu Apr 8 19:30:12 2004
> + +++ edited/arch/ia64/kernel/acpi.c Sat May 15 09:13:27 2004
> + @@ -508,9 +508,14 @@
> + #endif /* CONFIG_ACPI_NUMA */
> +
> + unsigned int
> + -acpi_register_gsi (u32 gsi, int polarity, int trigger)
> + +acpi_register_gsi (u32 gsi, int edge_level, int active_high_low)
> + {
> + - return acpi_register_irq(gsi, polarity, trigger);
> + + if (has_8259 && gsi < 16)
> + + return isa_irq_to_vector(gsi);
> + +
> + + return iosapic_register_intr(gsi,
> + + (active_high_low = ACPI_ACTIVE_HIGH) ?
> + IOSAPIC_POL_HIGH : IOSAPIC_POL_LOW,
> + + (edge_level = ACPI_EDGE_SENSITIVE) ?
> + IOSAPIC_EDGE : IOSAPIC_LEVEL);
> + }
> + EXPORT_SYMBOL(acpi_register_gsi);
> +
> + @@ -535,7 +540,7 @@
> + if (fadt->iapc_boot_arch & BAF_LEGACY_DEVICES)
> + acpi_legacy_devices = 1;
> +
> + - acpi_register_gsi(fadt->sci_int, ACPI_ACTIVE_LOW,
> + ACPI_LEVEL_SENSITIVE);
> + + acpi_register_gsi(fadt->sci_int, ACPI_LEVEL_SENSITIVE,
> + ACPI_ACTIVE_LOW);
> + return 0;
> + }
> +
> + @@ -658,17 +663,5 @@
> + }
> + return 0;
> + }
> + -
> + -int
> + -acpi_register_irq (u32 gsi, u32 polarity, u32 trigger)
> + -{
> + - if (has_8259 && gsi < 16)
> + - return isa_irq_to_vector(gsi);
> + -
> + - return iosapic_register_intr(gsi,
> + - (polarity = ACPI_ACTIVE_HIGH) ?
> + IOSAPIC_POL_HIGH : IOSAPIC_POL_LOW,
> + - (trigger = ACPI_EDGE_SENSITIVE) ?
> + IOSAPIC_EDGE : IOSAPIC_LEVEL);
> + -}
> + -EXPORT_SYMBOL(acpi_register_irq);
> +
> + #endif /* CONFIG_ACPI_BOOT */
> + === arch/ia64/kernel/iosapic.c 1.42 vs edited ==> + --- 1.42/arch/ia64/kernel/iosapic.c Fri May 14 20:00:12 2004
> + +++ edited/arch/ia64/kernel/iosapic.c Sat May 15 09:13:27 2004
> + @@ -173,7 +173,7 @@
> + }
> +
> + static void
> + -set_rte (unsigned int vector, unsigned int dest, int mask)
> + +set_rte (unsigned int vector, unsigned int dest)
> + {
> + unsigned long pol, trigger, dmode, flags;
> + u32 low32, high32;
> + @@ -207,10 +207,11 @@
> + }
> + #endif
> +
> + + /* the RTE always starts masked; the IRQ startup unmasks it */
> + low32 = ((pol << IOSAPIC_POLARITY_SHIFT) |
> + (trigger << IOSAPIC_TRIGGER_SHIFT) |
> + (dmode << IOSAPIC_DELIVERY_SHIFT) |
> + - ((mask ? 1 : 0) << IOSAPIC_MASK_SHIFT) |
> + + (1 << IOSAPIC_MASK_SHIFT) |
> + vector);
> +
> + /* dest contains both id and eid */
> + @@ -512,6 +513,42 @@
> + }
> + }
> +
> + +static unsigned int
> + +dest_cpu_lid (void)
> + +{
> + +#ifdef CONFIG_SMP
> + + static int cpu = -1;
> + +
> + + /*
> + + * If the platform supports redirection via XTP, let it
> + + * distribute interrupts.
> + + */
> + + if (smp_int_redirect & SMP_IRQ_REDIRECTION)
> + + return hard_smp_processor_id();
> + +
> + + /*
> + + * Some interrupts (ACPI SCI, for instance) are registered
> + + * before the BSP is marked as online.
> + + */
> + + if (!cpu_online(smp_processor_id()))
> + + return hard_smp_processor_id();
> + +
> + + /*
> + + * Otherwise, round-robin interrupt vectors across all the
> + + * processors. (It'd be nice if we could be smarter in the
> + + * case of NUMA.)
> + + */
> + + do {
> + + if (++cpu >= NR_CPUS)
> + + cpu = 0;
> + + } while (!cpu_online(cpu));
> + +
> + + return cpu_physical_id(cpu);
> + +#else
> + + return hard_smp_processor_id();
> + +#endif
> + +}
> + +
> + /*
> + * ACPI can describe IOSAPIC interrupts via static tables
> + and namespace
> + * methods. This provides an interface to register those
> + interrupts and
> + @@ -522,21 +559,35 @@
> + unsigned long polarity, unsigned long trigger)
> + {
> + int vector;
> + - unsigned int dest = (ia64_getreg(_IA64_REG_CR_LID) >>
> + 16) & 0xffff;
> + + unsigned int dest;
> + + unsigned long flags;
> +
> + - vector = gsi_to_vector(gsi);
> + - if (vector < 0)
> + - vector = assign_irq_vector(AUTO_ASSIGN);
> + + /*
> + + * If this GSI has already been registered (i.e., it's a
> + + * shared interrupt, or we lost a race to register it),
> + + * don't touch the RTE.
> + + */
> + + spin_lock_irqsave(&iosapic_lock, flags);
> + + {
> + + vector = gsi_to_vector(gsi);
> + + if (vector > 0) {
> + + spin_unlock_irqrestore(&iosapic_lock, flags);
> + + return vector;
> + + }
> +
> + - register_intr(gsi, vector, IOSAPIC_LOWEST_PRIORITY,
> + - polarity, trigger);
> + + vector = assign_irq_vector(AUTO_ASSIGN);
> + + dest = dest_cpu_lid();
> + + register_intr(gsi, vector, IOSAPIC_LOWEST_PRIORITY,
> + + polarity, trigger);
> + + }
> + + spin_unlock_irqrestore(&iosapic_lock, flags);
> +
> + - printk(KERN_INFO "GSI 0x%x(%s,%s) -> CPU 0x%04x vector %d\n",
> + - gsi, (polarity = IOSAPIC_POL_HIGH ? "high" : "low"),
> + - (trigger = IOSAPIC_EDGE ? "edge" : "level"),
> + dest, vector);
> + + printk(KERN_INFO "GSI 0x%x (%s, %s) -> CPU %d (0x%04x)
> + vector %d\n",
> + + gsi, (trigger = IOSAPIC_EDGE ? "edge" : "level"),
> + + (polarity = IOSAPIC_POL_HIGH ? "high" : "low"),
> + + cpu_logical_id(dest), dest, vector);
> +
> + - /* program the IOSAPIC routing table */
> + - set_rte(vector, dest, 0);
> + + set_rte(vector, dest);
> + return vector;
> + }
> +
> + @@ -576,15 +627,14 @@
> + return -1;
> + }
> +
> + - register_intr(gsi, vector, delivery, polarity,
> + - trigger);
> + + register_intr(gsi, vector, delivery, polarity, trigger);
> +
> + - printk(KERN_INFO "PLATFORM int 0x%x: GSI 0x%x(%s,%s) ->
> + CPU 0x%04x vector %d\n",
> + - int_type, gsi, (polarity = IOSAPIC_POL_HIGH ?
> + "high" : "low"),
> + - (trigger = IOSAPIC_EDGE ? "edge" : "level"),
> + dest, vector);
> + + printk(KERN_INFO "PLATFORM int 0x%x: GSI 0x%x (%s, %s)
> + -> CPU %d (0x%04x) vector %d\n",
> + + int_type, gsi, (trigger = IOSAPIC_EDGE ? "edge"
> + : "level"),
> + + (polarity = IOSAPIC_POL_HIGH ? "high" : "low"),
> + + cpu_logical_id(dest), dest, vector);
> +
> + - /* program the IOSAPIC routing table */
> + - set_rte(vector, dest, 0);
> + + set_rte(vector, dest);
> + return vector;
> + }
> +
> + @@ -605,12 +655,12 @@
> +
> + register_intr(gsi, vector, IOSAPIC_LOWEST_PRIORITY,
> + polarity, trigger);
> +
> + - DBG("ISA: IRQ %u -> GSI 0x%x (%s,%s) -> CPU 0x%04x vector %d\n",
> + - isa_irq, gsi, polarity = IOSAPIC_POL_HIGH ? "high" : "low",
> + - trigger = IOSAPIC_EDGE ? "edge" : "level", dest, vector);
> + + DBG("ISA: IRQ %u -> GSI 0x%x (%s,%s) -> CPU %d (0x%04x)
> + vector %d\n",
> + + isa_irq, gsi, trigger = IOSAPIC_EDGE ? "edge" : "level",
> + + polarity = IOSAPIC_POL_HIGH ? "high" : "low",
> + + cpu_logical_id(dest), dest, vector);
> +
> + - /* program the IOSAPIC routing table */
> + - set_rte(vector, dest, 0);
> + + set_rte(vector, dest);
> + }
> +
> + void __init
> + @@ -665,104 +715,3 @@
> + iosapic_override_isa_irq(isa_irq,
> + isa_irq, IOSAPIC_POL_HIGH, IOSAPIC_EDGE);
> + }
> + }
> + -
> + -void
> + -iosapic_enable_intr (unsigned int vector)
> + -{
> + - unsigned int dest;
> + - irq_desc_t *desc;
> + -
> + - /*
> + - * In the case of a shared interrupt, do not re-route
> + the vector, and
> + - * especially do not mask a running interrupt (startup
> + will not get
> + - * called for a shared interrupt).
> + - */
> + - desc = irq_descp(vector);
> + - if (desc->action)
> + - return;
> + -
> + -#ifdef CONFIG_SMP
> + - /*
> + - * For platforms that do not support interrupt redirect
> + via the XTP interface, we
> + - * can round-robin the PCI device interrupts to the processors
> + - */
> + - if (!(smp_int_redirect & SMP_IRQ_REDIRECTION)) {
> + - static int cpu_index = -1;
> + -
> + - do
> + - if (++cpu_index >= NR_CPUS)
> + - cpu_index = 0;
> + - while (!cpu_online(cpu_index));
> + -
> + - dest = cpu_physical_id(cpu_index) & 0xffff;
> + - } else {
> + - /*
> + - * Direct the interrupt vector to the current
> + cpu, platform redirection
> + - * will distribute them.
> + - */
> + - dest = (ia64_getreg(_IA64_REG_CR_LID) >> 16) & 0xffff;
> + - }
> + -#else
> + - /* direct the interrupt vector to the running cpu id */
> + - dest = (ia64_getreg(_IA64_REG_CR_LID) >> 16) & 0xffff;
> + -#endif
> + - set_rte(vector, dest, 1);
> + -
> + - printk(KERN_INFO "IOSAPIC: vector %d -> CPU 0x%04x, enabled\n",
> + - vector, dest);
> + -}
> + -
> + -#ifdef CONFIG_ACPI_PCI
> + -
> + -void __init
> + -iosapic_parse_prt (void)
> + -{
> + - struct acpi_prt_entry *entry;
> + - struct list_head *node;
> + - unsigned int gsi;
> + - int vector;
> + - char pci_id[16];
> + - struct hw_interrupt_type *irq_type = &irq_type_iosapic_level;
> + - irq_desc_t *idesc;
> + -
> + - list_for_each(node, &acpi_prt.entries) {
> + - entry = list_entry(node, struct acpi_prt_entry, node);
> + -
> + - /* We're only interested in static (non-link)
> + entries. */
> + - if (entry->link.handle)
> + - continue;
> + -
> + - gsi = entry->link.index;
> + -
> + - vector = gsi_to_vector(gsi);
> + - if (vector < 0) {
> + - if (find_iosapic(gsi) < 0)
> + - continue;
> + -
> + - /* allocate a vector for this interrupt line */
> + - if (pcat_compat && (gsi < 16))
> + - vector = isa_irq_to_vector(gsi);
> + - else
> + - /* new GSI; allocate a vector for it */
> + - vector = assign_irq_vector(AUTO_ASSIGN);
> + -
> + - register_intr(gsi, vector,
> + IOSAPIC_LOWEST_PRIORITY, IOSAPIC_POL_LOW,
> + - IOSAPIC_LEVEL);
> + - }
> + - entry->irq = vector;
> + - snprintf(pci_id, sizeof(pci_id), "%02x:%02x:%02x[%c]",
> + - entry->id.segment, entry->id.bus,
> + entry->id.device, 'A' + entry->pin);
> + -
> + - /*
> + - * If vector was previously initialized to a different
> + - * handler, re-initialize.
> + - */
> + - idesc = irq_descp(vector);
> + - if (idesc->handler != irq_type)
> + - register_intr(gsi, vector,
> + IOSAPIC_LOWEST_PRIORITY, IOSAPIC_POL_LOW,
> + - IOSAPIC_LEVEL);
> + -
> + - }
> + -}
> + -
> + -#endif /* CONFIG_ACPI */
> + === arch/ia64/pci/pci.c 1.48 vs edited ==> + --- 1.48/arch/ia64/pci/pci.c Wed Apr 21 15:26:09 2004
> + +++ edited/arch/ia64/pci/pci.c Sat May 15 10:56:31 2004
> + @@ -134,10 +134,18 @@
> + static int __init
> + pci_acpi_init (void)
> + {
> + - if (!acpi_pci_irq_init())
> + - printk(KERN_INFO "PCI: Using ACPI for IRQ routing\n");
> + - else
> + - printk(KERN_WARNING "PCI: Invalid ACPI-PCI IRQ
> + routing table\n");
> + + struct pci_dev *dev = NULL;
> + +
> + + printk(KERN_INFO "PCI: Using ACPI for IRQ routing\n");
> + +
> + + /*
> + + * PCI IRQ routing is set up by pci_enable_device(), but we
> + + * also do it here in case there are still broken drivers that
> + + * don't use pci_enable_device().
> + + */
> + + while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID,
> + dev)) != NULL)
> + + acpi_pci_irq_enable(dev);
> + +
> + return 0;
> + }
> +
> + === arch/x86_64/kernel/mpparse.c 1.26 vs edited ==> + --- 1.26/arch/x86_64/kernel/mpparse.c Fri Apr 23 13:43:21 2004
> + +++ edited/arch/x86_64/kernel/mpparse.c Sat May 15 09:13:30 2004
> + @@ -887,84 +887,48 @@
> +
> + extern FADT_DESCRIPTOR acpi_fadt;
> +
> + -#ifdef CONFIG_ACPI_PCI
> + -
> + -void __init mp_parse_prt (void)
> + +void mp_register_gsi (u32 gsi, int edge_level, int active_high_low)
> + {
> + - struct list_head *node = NULL;
> + - struct acpi_prt_entry *entry = NULL;
> + int ioapic = -1;
> + int ioapic_pin = 0;
> + - int gsi = 0;
> + int idx, bit = 0;
> + - int edge_level = 0;
> + - int active_high_low = 0;
> + -
> + - /*
> + - * Parsing through the PCI Interrupt Routing Table
> + (PRT) and program
> + - * routing for all static (IOAPIC-direct) entries.
> + - */
> + - list_for_each(node, &acpi_prt.entries) {
> + - entry = list_entry(node, struct acpi_prt_entry, node);
> + -
> + - /* Need to get gsi for dynamic entry */
> + - if (entry->link.handle) {
> + - gsi =
> + acpi_pci_link_get_irq(entry->link.handle, entry->link.index,
> + &edge_level, &active_high_low);
> + - if (!gsi)
> + - continue;
> + - } else {
> + - /* Hardwired GSI. Assume PCI standard
> + settings */
> + - gsi = entry->link.index;
> + - edge_level = 1;
> + - active_high_low = 1;
> + - }
> + -
> + - /* Don't set up the ACPI SCI because it's
> + already set up */
> + - if (acpi_fadt.sci_int = gsi)
> + - continue;
> +
> + - ioapic = mp_find_ioapic(gsi);
> + - if (ioapic < 0)
> + - continue;
> + - ioapic_pin = gsi - mp_ioapic_routing[ioapic].gsi_start;
> + + /* Don't set up the ACPI SCI because it's already set up */
> + + if (acpi_fadt.sci_int = gsi)
> + + return;
> + +
> + + ioapic = mp_find_ioapic(gsi);
> + + if (ioapic < 0) {
> + + printk(KERN_WARNING "No IOAPIC for GSI 0x%x\n", gsi);
> + + return;
> + + }
> +
> + - /*
> + - * Avoid pin reprogramming. PRTs typically
> + include entries
> + - * with redundant pin->gsi mappings (but unique
> + PCI devices);
> + - * we only only program the IOAPIC on the first.
> + - */
> + - bit = ioapic_pin % 32;
> + - idx = (ioapic_pin < 32) ? 0 : (ioapic_pin / 32);
> + - if (idx > 3) {
> + - printk(KERN_ERR "Invalid reference to
> + IOAPIC pin "
> + - "%d-%d\n",
> + mp_ioapic_routing[ioapic].apic_id,
> + - ioapic_pin);
> + - continue;
> + - }
> + - if ((1<<bit) &
> + mp_ioapic_routing[ioapic].pin_programmed[idx]) {
> + - Dprintk(KERN_DEBUG "Pin %d-%d already
> + programmed\n",
> + -
> + mp_ioapic_routing[ioapic].apic_id, ioapic_pin);
> + - acpi_gsi_to_irq(gsi, &entry->irq);
> + - continue;
> + - }
> + + ioapic_pin = gsi - mp_ioapic_routing[ioapic].gsi_start;
> +
> + - mp_ioapic_routing[ioapic].pin_programmed[idx]
> + |= (1<<bit);
> + - if (!io_apic_set_pci_routing(ioapic,
> + ioapic_pin, gsi, edge_level, active_high_low)) {
> + - acpi_gsi_to_irq(gsi, &entry->irq);
> + - }
> + - printk(KERN_DEBUG "%02x:%02x:%02x[%c] -> %d-%d
> + -> IRQ %d\n",
> + - entry->id.segment, entry->id.bus,
> + - entry->id.device, ('A' + entry->pin),
> + - mp_ioapic_routing[ioapic].apic_id, ioapic_pin,
> + - entry->irq);
> + + /*
> + + * Avoid pin reprogramming. PRTs typically include entries
> + + * with redundant pin->gsi mappings (but unique PCI devices);
> + + * we only only program the IOAPIC on the first.
> + + */
> + + bit = ioapic_pin % 32;
> + + idx = (ioapic_pin < 32) ? 0 : (ioapic_pin / 32);
> + + if (idx > 3) {
> + + printk(KERN_ERR "Invalid reference to IOAPIC pin "
> + + "%d-%d\n", mp_ioapic_routing[ioapic].apic_id,
> + + ioapic_pin);
> + + return;
> + + }
> + + if ((1<<bit) & mp_ioapic_routing[ioapic].pin_programmed[idx]) {
> + + Dprintk(KERN_DEBUG "Pin %d-%d already programmed\n",
> + + mp_ioapic_routing[ioapic].apic_id, ioapic_pin);
> + + return;
> + }
> + -
> + - print_IO_APIC();
> +
> + - return;
> + + mp_ioapic_routing[ioapic].pin_programmed[idx] |= (1<<bit);
> + + io_apic_set_pci_routing(ioapic, ioapic_pin, gsi,
> + + edge_level = ACPI_EDGE_SENSITIVE ? 0 : 1,
> + + active_high_low = ACPI_ACTIVE_HIGH ? 0 : 1);
> + }
> + -
> + -#endif /*CONFIG_ACPI_PCI*/
> +
> + #endif /*CONFIG_X86_IO_APIC*/
> +
> + === drivers/acpi/pci_irq.c 1.27 vs edited ==> + --- 1.27/drivers/acpi/pci_irq.c Sat Apr 24 00:17:22 2004
> + +++ edited/drivers/acpi/pci_irq.c Sat May 15 09:13:31 2004
> + @@ -35,12 +35,6 @@
> + #include <linux/pm.h>
> + #include <linux/pci.h>
> + #include <linux/acpi.h>
> + -#ifdef CONFIG_X86_IO_APIC
> + -#include <asm/mpspec.h>
> + -#endif
> + -#ifdef CONFIG_IOSAPIC
> + -# include <asm/iosapic.h>
> + -#endif
> + #include <acpi/acpi_bus.h>
> + #include <acpi/acpi_drivers.h>
> +
> + @@ -50,10 +44,6 @@
> +
> + struct acpi_prt_list acpi_prt;
> +
> + -#ifdef CONFIG_X86
> + -extern void eisa_set_level_irq(unsigned int irq);
> + -#endif
> + -
> +
> + /*
> + --------------------------------------------------------------
> + ------------
> + PCI IRQ Routing Table (PRT) Support
> + @@ -237,12 +227,18 @@
> + PCI Interrupt Routing Support
> +
> + --------------------------------------------------------------
> + ------------ */
> +
> + -int
> + -acpi_pci_irq_lookup (struct pci_bus *bus, int device, int pin)
> + +static int
> + +acpi_pci_irq_lookup (
> + + struct pci_bus *bus,
> + + int device,
> + + int pin,
> + + int *edge_level,
> + + int *active_high_low)
> + {
> + struct acpi_prt_entry *entry = NULL;
> + int segment = pci_domain_nr(bus);
> + int bus_nr = bus->number;
> + + int irq;
> +
> + ACPI_FUNCTION_TRACE("acpi_pci_irq_lookup");
> +
> + @@ -255,28 +251,30 @@
> + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "PRT entry not
> + found\n"));
> + return_VALUE(0);
> + }
> + -
> + - if (!entry->irq && entry->link.handle) {
> + - entry->irq =
> + acpi_pci_link_get_irq(entry->link.handle, entry->link.index,
> + NULL, NULL);
> + - if (!entry->irq) {
> + +
> + + if (entry->link.handle) {
> + + irq = acpi_pci_link_get_irq(entry->link.handle,
> + entry->link.index, edge_level, active_high_low);
> + + if (!irq) {
> + ACPI_DEBUG_PRINT((ACPI_DB_WARN,
> + "Invalid IRQ link routing entry\n"));
> + return_VALUE(0);
> + }
> + - }
> + - else if (!entry->irq) {
> + - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Invalid static
> + routing entry (IRQ 0)\n"));
> + - return_VALUE(0);
> + + } else {
> + + irq = entry->link.index;
> + + *edge_level = ACPI_LEVEL_SENSITIVE;
> + + *active_high_low = ACPI_ACTIVE_LOW;
> + }
> +
> + - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found IRQ %d\n", entry->irq));
> + + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found IRQ %d\n", irq));
> +
> + - return_VALUE(entry->irq);
> + + return_VALUE(irq);
> + }
> +
> + static int
> + acpi_pci_irq_derive (
> + struct pci_dev *dev,
> + - int pin)
> + + int pin,
> + + int *edge_level,
> + + int *active_high_low)
> + {
> + struct pci_dev *bridge = dev;
> + int irq = 0;
> + @@ -308,8 +306,8 @@
> + pin = bridge_pin;
> + }
> +
> + - irq = acpi_pci_irq_lookup(bridge->bus,
> + - PCI_SLOT(bridge->devfn), pin);
> + + irq = acpi_pci_irq_lookup(bridge->bus,
> + PCI_SLOT(bridge->devfn),
> + + pin, edge_level, active_high_low);
> + }
> +
> + if (!irq) {
> + @@ -330,6 +328,8 @@
> + {
> + int irq = 0;
> + u8 pin = 0;
> + + int edge_level = ACPI_LEVEL_SENSITIVE;
> + + int active_high_low = ACPI_ACTIVE_LOW;
> +
> + ACPI_FUNCTION_TRACE("acpi_pci_irq_enable");
> +
> + @@ -352,21 +352,22 @@
> + * First we check the PCI IRQ routing table (PRT) for
> + an IRQ. PRT
> + * values override any BIOS-assigned IRQs set during boot.
> + */
> + - irq = acpi_pci_irq_lookup(dev->bus, PCI_SLOT(dev->devfn), pin);
> + + irq = acpi_pci_irq_lookup(dev->bus,
> + PCI_SLOT(dev->devfn), pin, &edge_level, &active_high_low);
> +
> + /*
> + * If no PRT entry was found, we'll try to derive an
> + IRQ from the
> + * device's parent bridge.
> + */
> + if (!irq)
> + - irq = acpi_pci_irq_derive(dev, pin);
> + + irq = acpi_pci_irq_derive(dev, pin,
> + &edge_level, &active_high_low);
> +
> + /*
> + * No IRQ known to the ACPI subsystem - maybe the BIOS /
> + * driver reported one, then use it. Exit in any case.
> + */
> + if (!irq) {
> + - printk(KERN_WARNING PREFIX "No IRQ known for
> + interrupt pin %c of device %s", ('A' + pin), pci_name(dev));
> + + printk(KERN_WARNING PREFIX "PCI interrupt
> + %s[%c]: no GSI",
> + + pci_name(dev), ('A' + pin));
> + /* Interrupt Line values above 0xF are forbidden */
> + if (dev->irq && (dev->irq <= 0xF)) {
> + printk(" - using IRQ %d\n", dev->irq);
> + @@ -378,62 +379,14 @@
> + }
> + }
> +
> + - dev->irq = irq;
> + + dev->irq = acpi_register_gsi(irq, edge_level, active_high_low);
> +
> + - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device %s using IRQ
> + %d\n", pci_name(dev), dev->irq));
> + -
> + - /*
> + - * Make sure all (legacy) PCI IRQs are set as level-triggered.
> + - */
> + -#ifdef CONFIG_X86
> + - {
> + - static u16 irq_mask;
> + - if ((dev->irq < 16) && !((1 << dev->irq) & irq_mask)) {
> + - ACPI_DEBUG_PRINT((ACPI_DB_INFO,
> + "Setting IRQ %d as level-triggered\n", dev->irq));
> + - irq_mask |= (1 << dev->irq);
> + - eisa_set_level_irq(dev->irq);
> + - }
> + - }
> + -#endif
> + -#ifdef CONFIG_IOSAPIC
> + - if (acpi_irq_model = ACPI_IRQ_MODEL_IOSAPIC)
> + - iosapic_enable_intr(dev->irq);
> + -#endif
> + + printk(KERN_INFO PREFIX "PCI interrupt %s[%c] -> GSI 0x%x "
> + + "(%s, %s) -> IRQ %d\n",
> + + pci_name(dev), 'A' + pin, irq,
> + + (edge_level = ACPI_LEVEL_SENSITIVE) ? "level" : "edge",
> + + (active_high_low = ACPI_ACTIVE_LOW) ? "low" : "high",
> + + dev->irq);
> +
> + return_VALUE(dev->irq);
> + -}
> + -
> + -
> + -int __init
> + -acpi_pci_irq_init (void)
> + -{
> + - struct pci_dev *dev = NULL;
> + -
> + - ACPI_FUNCTION_TRACE("acpi_pci_irq_init");
> + -
> + - if (!acpi_prt.count) {
> + - printk(KERN_WARNING PREFIX "ACPI tables contain
> + no PCI IRQ "
> + - "routing entries\n");
> + - return_VALUE(-ENODEV);
> + - }
> + -
> + - /* Make sure all link devices have a valid IRQ. */
> + - if (acpi_pci_link_check()) {
> + - return_VALUE(-ENODEV);
> + - }
> + -
> + -#ifdef CONFIG_X86_IO_APIC
> + - /* Program IOAPICs using data from PRT entries. */
> + - if (acpi_irq_model = ACPI_IRQ_MODEL_IOAPIC)
> + - mp_parse_prt();
> + -#endif
> + -#ifdef CONFIG_IOSAPIC
> + - if (acpi_irq_model = ACPI_IRQ_MODEL_IOSAPIC)
> + - iosapic_parse_prt();
> + -#endif
> + -
> + - while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID,
> + dev)) != NULL)
> + - acpi_pci_irq_enable(dev);
> + -
> + - return_VALUE(0);
> + }
> + === drivers/acpi/pci_link.c 1.28 vs edited ==> + --- 1.28/drivers/acpi/pci_link.c Mon May 10 14:42:35 2004
> + +++ edited/drivers/acpi/pci_link.c Sat May 15 09:13:31 2004
> + @@ -487,13 +487,13 @@
> + };
> +
> + int
> + -acpi_pci_link_check (void)
> + +acpi_irq_penalty_init(void)
> + {
> + struct list_head *node = NULL;
> + struct acpi_pci_link *link = NULL;
> + int i = 0;
> +
> + - ACPI_FUNCTION_TRACE("acpi_pci_link_check");
> + + ACPI_FUNCTION_TRACE("acpi_irq_penalty_init");
> +
> + /*
> + * Update penalties to facilitate IRQ balancing.
> + === drivers/serial/8250_acpi.c 1.8 vs edited ==> + --- 1.8/drivers/serial/8250_acpi.c Mon Mar 15 15:53:32 2004
> + +++ edited/drivers/serial/8250_acpi.c Sat May 15 09:13:31 2004
> + @@ -58,28 +58,18 @@
> + static acpi_status acpi_serial_ext_irq(struct serial_struct *req,
> + struct
> + acpi_resource_ext_irq *ext_irq)
> + {
> + - if (ext_irq->number_of_interrupts > 0) {
> + -#ifdef CONFIG_IA64
> + - req->irq = acpi_register_irq(ext_irq->interrupts[0],
> + - ext_irq->active_high_low,
> + ext_irq->edge_level);
> + -#else
> + - req->irq = ext_irq->interrupts[0];
> + -#endif
> + - }
> + + if (ext_irq->number_of_interrupts > 0)
> + + req->irq = acpi_register_gsi(ext_irq->interrupts[0],
> + + ext_irq->edge_level,
> + ext_irq->active_high_low);
> + return AE_OK;
> + }
> +
> + static acpi_status acpi_serial_irq(struct serial_struct *req,
> + struct acpi_resource_irq *irq)
> + {
> + - if (irq->number_of_interrupts > 0) {
> + -#ifdef CONFIG_IA64
> + - req->irq = acpi_register_irq(irq->interrupts[0],
> + - irq->active_high_low, irq->edge_level);
> + -#else
> + - req->irq = irq->interrupts[0];
> + -#endif
> + - }
> + + if (irq->number_of_interrupts > 0)
> + + req->irq = acpi_register_gsi(irq->interrupts[0],
> + + irq->edge_level, irq->active_high_low);
> + return AE_OK;
> + }
> +
> + === drivers/serial/8250_hcdp.c 1.6 vs edited ==> + --- 1.6/drivers/serial/8250_hcdp.c Tue May 4 10:54:32 2004
> + +++ edited/drivers/serial/8250_hcdp.c Sat May 15 09:13:32 2004
> + @@ -183,16 +183,12 @@
> + }
> +
> + if (HCDP_IRQ_SUPPORTED(hcdp_dev)) {
> + -#ifdef CONFIG_IA64
> + if (HCDP_PCI_UART(hcdp_dev))
> + - port.irq = acpi_register_irq(gsi,
> + - ACPI_ACTIVE_LOW,
> + ACPI_LEVEL_SENSITIVE);
> + + port.irq = acpi_register_gsi(gsi,
> + + ACPI_LEVEL_SENSITIVE,
> + ACPI_ACTIVE_LOW);
> + else
> + - port.irq = acpi_register_irq(gsi,
> + - ACPI_ACTIVE_HIGH,
> + ACPI_EDGE_SENSITIVE);
> + -#else
> + - port.irq = gsi;
> + -#endif
> + + port.irq = acpi_register_gsi(gsi,
> + + ACPI_EDGE_SENSITIVE,
> + ACPI_ACTIVE_HIGH);
> + port.flags |= UPF_AUTO_IRQ;
> +
> + if (HCDP_PCI_UART(hcdp_dev))
> + === include/acpi/acpi_drivers.h 1.17 vs edited ==> + --- 1.17/include/acpi/acpi_drivers.h Mon Dec 15 17:46:29 2003
> + +++ edited/include/acpi/acpi_drivers.h Sat May 15 09:13:32 2004
> + @@ -55,7 +55,7 @@
> +
> + /* ACPI PCI Interrupt Link (pci_link.c) */
> +
> + -int acpi_pci_link_check (void);
> + +int acpi_irq_penalty_init (void);
> + int acpi_pci_link_get_irq (acpi_handle handle, int index,
> + int* edge_level, int* active_high_low);
> +
> + /* ACPI PCI Interrupt Routing (pci_irq.c) */
> + === include/asm-i386/mpspec.h 1.20 vs edited ==> + --- 1.20/include/asm-i386/mpspec.h Mon Apr 12 11:55:30 2004
> + +++ edited/include/asm-i386/mpspec.h Sat May 15 09:13:32 2004
> + @@ -33,7 +33,7 @@
> + extern void mp_register_ioapic (u8 id, u32 address, u32 gsi_base);
> + extern void mp_override_legacy_irq (u8 bus_irq, u8 polarity,
> + u8 trigger, u32 gsi);
> + extern void mp_config_acpi_legacy_irqs (void);
> + -extern void mp_parse_prt (void);
> + +extern void mp_register_gsi (u32 gsi, int edge_level, int
> + active_high_low);
> + #endif /*CONFIG_ACPI_BOOT*/
> +
> + #define PHYSID_ARRAY_SIZE BITS_TO_LONGS(MAX_APICS)
> + === include/asm-ia64/iosapic.h 1.13 vs edited ==> + --- 1.13/include/asm-ia64/iosapic.h Fri Feb 27 04:39:17 2004
> + +++ edited/include/asm-ia64/iosapic.h Sat May 15 09:13:33 2004
> + @@ -60,7 +60,6 @@
> + unsigned int gsi_base);
> + extern int gsi_to_vector (unsigned int gsi);
> + extern int gsi_to_irq (unsigned int gsi);
> + -extern void __init iosapic_parse_prt (void);
> + extern void iosapic_enable_intr (unsigned int vector);
> + extern int iosapic_register_intr (unsigned int gsi, unsigned
> + long polarity,
> + unsigned long trigger);
> + === include/asm-x86_64/mpspec.h 1.11 vs edited ==> + --- 1.11/include/asm-x86_64/mpspec.h Mon Apr 12 11:55:30 2004
> + +++ edited/include/asm-x86_64/mpspec.h Sat May 15 09:13:33 2004
> + @@ -189,7 +189,7 @@
> + extern void mp_register_ioapic (u8 id, u32 address, u32 gsi_base);
> + extern void mp_override_legacy_irq (u8 bus_irq, u8 polarity,
> + u8 trigger, u32 gsi);
> + extern void mp_config_acpi_legacy_irqs (void);
> + -extern void mp_parse_prt (void);
> + +extern void mp_register_gsi (u32 gsi, int edge_level, int
> + active_high_low);
> + #endif /*CONFIG_X86_IO_APIC*/
> + #endif
> +
> + === include/linux/acpi.h 1.33 vs edited ==> + --- 1.33/include/linux/acpi.h Fri Apr 2 06:48:53 2004
> + +++ edited/include/linux/acpi.h Sat May 15 09:13:33 2004
> + @@ -437,7 +437,7 @@
> + struct pci_dev;
> +
> + int acpi_pci_irq_enable (struct pci_dev *dev);
> + -int acpi_pci_irq_init (void);
> + +unsigned int acpi_register_gsi (u32 gsi, int edge_level, int
> + active_high_low);
> + int acpi_gsi_to_irq (u32 gsi, unsigned int *irq);
> +
> + struct acpi_pci_driver {
> + -
> + To unsubscribe from this list: send the line "unsubscribe
> + linux-ia64" in
> + the body of a message to majordomo@vger.kernel.org
> + More majordomo info at http://vger.kernel.org/majordomo-info.html
> +
>

--
Bjorn Helgaas - bjorn.helgaas at hp.com
Linux and Open Source Lab
Hewlett-Packard Company