public inbox for linux-acpi@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH] ACPI PCI IRQ routing rework
@ 2004-05-15 17:20 Bjorn Helgaas
       [not found] ` <200405151120.45753.bjorn.helgaas-VXdhtT5mjnY@public.gmane.org>
                   ` (2 more replies)
  0 siblings, 3 replies; 6+ messages in thread
From: Bjorn Helgaas @ 2004-05-15 17:20 UTC (permalink / raw)
  To: acpi-devel
  Cc: Len Brown, David Mosberger, Andi Kleen, Jun Nakajima, linux-ia64

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 {

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] ACPI PCI IRQ routing rework
       [not found] ` <200405151120.45753.bjorn.helgaas-VXdhtT5mjnY@public.gmane.org>
@ 2004-05-15 20:23   ` Bjorn Helgaas
  0 siblings, 0 replies; 6+ messages in thread
From: Bjorn Helgaas @ 2004-05-15 20:23 UTC (permalink / raw)
  To: acpi-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f
  Cc: Len Brown, David Mosberger, Andi Kleen, Jun Nakajima,
	linux-ia64-u79uwXL29TY76Z2rM5mHXA

Andi's x86-64 update that showed up in linux-2.5 today touches
mp_parse_prt(), one of the functions I changed.

Here's an updated patch:

===== 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 14:16:59 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 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.61 vs edited =====
--- 1.61/arch/i386/kernel/acpi/boot.c	Sat May 15 00:11:59 2004
+++ edited/arch/i386/kernel/acpi/boot.c	Sat May 15 14:12:30 2004
@@ -428,6 +428,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 14:12:31 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.69 vs edited =====
--- 1.69/arch/ia64/kernel/acpi.c	Sat May 15 00:11:59 2004
+++ edited/arch/ia64/kernel/acpi.c	Sat May 15 14:12:32 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;
 }
 
@@ -648,17 +653,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 14:12:32 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 14:12:33 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.27 vs edited =====
--- 1.27/arch/x86_64/kernel/mpparse.c	Sat May 15 07:32:27 2004
+++ edited/arch/x86_64/kernel/mpparse.c	Sat May 15 14:16:33 2004
@@ -887,88 +887,49 @@
 
 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);
+	/* 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;
+	}
 
-		/* 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 up the 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_start;
-
-		/* 
-		 * 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\n",
-			entry->id.segment, entry->id.bus,
-			entry->id.device, ('A' + entry->pin), 
-			mp_ioapic_routing[ioapic].apic_id, ioapic_pin,
-			entry->irq);
+	ioapic_pin = gsi - mp_ioapic_routing[ioapic].gsi_start;
+
+	/* 
+	 * Avoid pin reprogramming.  PRTs typically include entries  
+	 * with redundant pin->gsi mappings (but unique PCI devices);
+	 * we 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);
 
-#endif /*CONFIG_ACPI_PCI*/
+	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_X86_IO_APIC*/
-
 #endif /*CONFIG_ACPI_BOOT*/
===== 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 14:12:34 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 14:12:35 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 14:12:35 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 14:12:36 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 14:12:36 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 14:12:37 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 14:12:37 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 14:12:37 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 14:12:38 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 {


-------------------------------------------------------
This SF.Net email is sponsored by: SourceForge.net Broadband
Sign-up now for SourceForge Broadband and get the fastest
6.0/768 connection for only $19.95/mo for the first 3 months!
http://ads.osdn.com/?ad_id=2562&alloc_id=6184&op=click

^ permalink raw reply	[flat|nested] 6+ messages in thread

* RE: [PATCH] ACPI PCI IRQ routing rework
  2004-05-15 17:20 [PATCH] ACPI PCI IRQ routing rework Bjorn Helgaas
       [not found] ` <200405151120.45753.bjorn.helgaas-VXdhtT5mjnY@public.gmane.org>
@ 2004-05-17 10:09 ` Sourav Sen
  2004-05-17 15:41 ` Andi Kleen
  2 siblings, 0 replies; 6+ messages in thread
From: Sourav Sen @ 2004-05-17 10:09 UTC (permalink / raw)
  To: HELGAAS,BJORN (HP-Ft. Collins), acpi-devel
  Cc: 'Len Brown', MOSBERGER,DAVID (HP-PaloAlto,unix3),
	'Andi Kleen', 'Jun Nakajima', linux-ia64

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. 

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
+ 

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] ACPI PCI IRQ routing rework
       [not found] <A11077E28200D51182EA00D0B77552530E8A8522@xin02.india.hp.com>
@ 2004-05-17 14:57 ` Bjorn Helgaas
       [not found]   ` <200405170857.55814.bjorn.helgaas-VXdhtT5mjnY@public.gmane.org>
  0 siblings, 1 reply; 6+ messages in thread
From: Bjorn Helgaas @ 2004-05-17 14:57 UTC (permalink / raw)
  To: SEN,SOURAV (HP-India,ex2)
  Cc: acpi-devel, Len Brown, Mosberger, David, Andi Kleen, Jun Nakajima,
	linux-ia64

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

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] ACPI PCI IRQ routing rework
  2004-05-15 17:20 [PATCH] ACPI PCI IRQ routing rework Bjorn Helgaas
       [not found] ` <200405151120.45753.bjorn.helgaas-VXdhtT5mjnY@public.gmane.org>
  2004-05-17 10:09 ` Sourav Sen
@ 2004-05-17 15:41 ` Andi Kleen
  2 siblings, 0 replies; 6+ messages in thread
From: Andi Kleen @ 2004-05-17 15:41 UTC (permalink / raw)
  To: Bjorn Helgaas; +Cc: acpi-devel, len.brown, davidm, jun.nakajima, linux-ia64

On Sat, 15 May 2004 11:20:45 -0600
Bjorn Helgaas <bjorn.helgaas@hp.com> wrote:

> 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.

I like this change very much. It should make PRT misrouting problems 
easier to debug, because the system will be already up and running
then (at least with modular drivers). 

Also things that are not needed are not configured and that reduces
the potential for bugs.

-Andi

^ permalink raw reply	[flat|nested] 6+ messages in thread

* RE: [PATCH] ACPI PCI IRQ routing rework
       [not found]   ` <200405170857.55814.bjorn.helgaas-VXdhtT5mjnY@public.gmane.org>
@ 2004-05-18  4:39     ` Sourav Sen
  0 siblings, 0 replies; 6+ messages in thread
From: Sourav Sen @ 2004-05-18  4:39 UTC (permalink / raw)
  To: HELGAAS,BJORN (HP-Ft. Collins)
  Cc: acpi-devel-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f, Len Brown,
	MOSBERGER,DAVID (HP-PaloAlto,unix3), Andi Kleen, Jun Nakajima,
	linux-ia64-u79uwXL29TY76Z2rM5mHXA

+ Or are you saying that my patch introduces a new panic situation
+ that didn't exist before?  

No, I am not saying that. I was referring to the same old panic in 
assign_irq_vector(). 

--Sourav


-------------------------------------------------------
This SF.Net email is sponsored by: SourceForge.net Broadband
Sign-up now for SourceForge Broadband and get the fastest
6.0/768 connection for only $19.95/mo for the first 3 months!
http://ads.osdn.com/?ad_id=2562&alloc_id=6184&op=click

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2004-05-18  4:39 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2004-05-15 17:20 [PATCH] ACPI PCI IRQ routing rework Bjorn Helgaas
     [not found] ` <200405151120.45753.bjorn.helgaas-VXdhtT5mjnY@public.gmane.org>
2004-05-15 20:23   ` Bjorn Helgaas
2004-05-17 10:09 ` Sourav Sen
2004-05-17 15:41 ` Andi Kleen
     [not found] <A11077E28200D51182EA00D0B77552530E8A8522@xin02.india.hp.com>
2004-05-17 14:57 ` Bjorn Helgaas
     [not found]   ` <200405170857.55814.bjorn.helgaas-VXdhtT5mjnY@public.gmane.org>
2004-05-18  4:39     ` Sourav Sen

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox