ChangeSet 1.1621, 2004/03/01 09:48:14-08:00, torben.mathiasen@hp.com

[PATCH] PCI Hotplug: Patch to get cpqphp working with IOAPIC

On Fri, Feb 13 2004, Sy, Dely L wrote:
> Since filling out the INTERRUPT_LINE is needed for systems running
> with legacy irqs and not needed for systems running with IO-APIC.  The

> possible
> solutions:
> 1) Best is there is a run-time check (a flag or an API call) that tells
>    whether the system is running on legacy mode or IO-APIC mode. Is there
>    such check that you know of?

Dan suggested that we look at what IRQ the hotplug controller has been
assigned in the MPS table. If its < 0x10 we're in legacy/mapped mode.
That would probaly work

> > >
> > > Do those servers work on 2.6.2 without my patch?
> > >
>
> > Yes
>
> They work but they get dev->irq = 9 or 11 in the APIC enabled mode.
> Correct?
>

Yes. All hot-added adapters get legacy IRQs like IRQ5 in the example
below where eth2 was added after bootup:


linux:~ # cat /proc/interrupts
           CPU0       CPU1       CPU2       CPU3
0:     831113          0          0          0    IO-APIC-edge  timer
1:        255          0          0          0    IO-APIC-edge  i8042
2:          0          0          0          0          XT-PIC  cascade
5:          0          0          0          0          XT-PIC  eth2
8:          2          0          0          0    IO-APIC-edge  rtc
12:         92          0          0          0   IO-APIC-edge  i8042
14:         29          0          0          0   IO-APIC-edge  ide0
20:          0          0          0          0   IO-APIC-level cciss0
21:          0          0          0          0   IO-APIC-level cciss1
29:        107          0          0          0   IO-APIC-level eth0
30:       7702          0          0          0   IO-APIC-level aic7xxx
31:         30          0          0          0   IO-APIC-level aic7xxx
34:        336          0          0          0   IO-APIC-level
cpqphp.o, cpqphp.o
NMI:          0          0          0          0
LOC:     830760     830893     830892     830891
ERR:          0
MIS:          0

I attached a patch that does the legacy mode check that Dan suggested
and IRQs for hot-added adapters seems to be given out in the APIC range.


 drivers/pci/hotplug/cpqphp.h      |    1 
 drivers/pci/hotplug/cpqphp_core.c |    5 ++++
 drivers/pci/hotplug/cpqphp_ctrl.c |   47 +++++++++++++++++++-------------------
 drivers/pci/hotplug/cpqphp_pci.c  |   36 ++++++++++++++---------------
 4 files changed, 48 insertions(+), 41 deletions(-)


diff -Nru a/drivers/pci/hotplug/cpqphp.h b/drivers/pci/hotplug/cpqphp.h
--- a/drivers/pci/hotplug/cpqphp.h	Tue Mar  2 19:43:03 2004
+++ b/drivers/pci/hotplug/cpqphp.h	Tue Mar  2 19:43:03 2004
@@ -444,6 +444,7 @@
 
 /* Global variables */
 extern int cpqhp_debug;
+extern int cpqhp_legacy_mode;
 extern struct controller *cpqhp_ctrl_list;
 extern struct pci_func *cpqhp_slot_list[256];
 
diff -Nru a/drivers/pci/hotplug/cpqphp_core.c b/drivers/pci/hotplug/cpqphp_core.c
--- a/drivers/pci/hotplug/cpqphp_core.c	Tue Mar  2 19:43:03 2004
+++ b/drivers/pci/hotplug/cpqphp_core.c	Tue Mar  2 19:43:03 2004
@@ -49,6 +49,7 @@
 
 /* Global variables */
 int cpqhp_debug;
+int cpqhp_legacy_mode;
 struct controller *cpqhp_ctrl_list;	/* = NULL */
 struct pci_func *cpqhp_slot_list[256];
 
@@ -1169,6 +1170,10 @@
 	 */
 	// The next line is required for cpqhp_find_available_resources
 	ctrl->interrupt = pdev->irq;
+	if (ctrl->interrupt < 0x10) {
+		cpqhp_legacy_mode = 1;
+		dbg("System seems to be configured for Full Table Mapped MPS mode\n");
+	}
 
 	ctrl->cfgspc_irq = 0;
 	pci_read_config_byte(pdev, PCI_INTERRUPT_LINE, &ctrl->cfgspc_irq);
diff -Nru a/drivers/pci/hotplug/cpqphp_ctrl.c b/drivers/pci/hotplug/cpqphp_ctrl.c
--- a/drivers/pci/hotplug/cpqphp_ctrl.c	Tue Mar  2 19:43:03 2004
+++ b/drivers/pci/hotplug/cpqphp_ctrl.c	Tue Mar  2 19:43:03 2004
@@ -3020,33 +3020,34 @@
 				}
 			}
 		}		// End of base register loop
+		if (cpqhp_legacy_mode) {
+			// Figure out which interrupt pin this function uses
+			rc = pci_bus_read_config_byte (pci_bus, devfn, 
+				PCI_INTERRUPT_PIN, &temp_byte);
 
-#if !defined(CONFIG_X86_IO_APIC)
-		// Figure out which interrupt pin this function uses
-		rc = pci_bus_read_config_byte (pci_bus, devfn, PCI_INTERRUPT_PIN, &temp_byte);
-
-		// If this function needs an interrupt and we are behind a bridge
-		// and the pin is tied to something that's alread mapped,
-		// set this one the same
-		if (temp_byte && resources->irqs && 
-		    (resources->irqs->valid_INT & 
-		     (0x01 << ((temp_byte + resources->irqs->barber_pole - 1) & 0x03)))) {
-			// We have to share with something already set up
-			IRQ = resources->irqs->interrupt[(temp_byte + resources->irqs->barber_pole - 1) & 0x03];
-		} else {
-			// Program IRQ based on card type
-			rc = pci_bus_read_config_byte (pci_bus, devfn, 0x0B, &class_code);
-
-			if (class_code == PCI_BASE_CLASS_STORAGE) {
-				IRQ = cpqhp_disk_irq;
+			// If this function needs an interrupt and we are behind a bridge
+			// and the pin is tied to something that's alread mapped,
+			// set this one the same
+			if (temp_byte && resources->irqs && 
+			    (resources->irqs->valid_INT & 
+			     (0x01 << ((temp_byte + resources->irqs->barber_pole - 1) & 0x03)))) {
+				// We have to share with something already set up
+				IRQ = resources->irqs->interrupt[(temp_byte + 
+					resources->irqs->barber_pole - 1) & 0x03];
 			} else {
-				IRQ = cpqhp_nic_irq;
+				// Program IRQ based on card type
+				rc = pci_bus_read_config_byte (pci_bus, devfn, 0x0B, &class_code);
+
+				if (class_code == PCI_BASE_CLASS_STORAGE) {
+					IRQ = cpqhp_disk_irq;
+				} else {
+					IRQ = cpqhp_nic_irq;
+				}
 			}
-		}
 
-		// IRQ Line
-		rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_INTERRUPT_LINE, IRQ);
-#endif
+			// IRQ Line
+			rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_INTERRUPT_LINE, IRQ);
+		}
 
 		if (!behind_bridge) {
 			rc = cpqhp_set_irq(func->bus, func->device, temp_byte + 0x09, IRQ);
diff -Nru a/drivers/pci/hotplug/cpqphp_pci.c b/drivers/pci/hotplug/cpqphp_pci.c
--- a/drivers/pci/hotplug/cpqphp_pci.c	Tue Mar  2 19:43:03 2004
+++ b/drivers/pci/hotplug/cpqphp_pci.c	Tue Mar  2 19:43:03 2004
@@ -151,32 +151,32 @@
  */
 int cpqhp_set_irq (u8 bus_num, u8 dev_num, u8 int_pin, u8 irq_num)
 {
-#if !defined(CONFIG_X86_IO_APIC)	
 	int rc;
 	u16 temp_word;
 	struct pci_dev fakedev;
 	struct pci_bus fakebus;
 
-	fakedev.devfn = dev_num << 3;
-	fakedev.bus = &fakebus;
-	fakebus.number = bus_num;
-	dbg("%s: dev %d, bus %d, pin %d, num %d\n",
-	    __FUNCTION__, dev_num, bus_num, int_pin, irq_num);
-	rc = pcibios_set_irq_routing(&fakedev, int_pin - 0x0a, irq_num);
-	dbg("%s: rc %d\n", __FUNCTION__, rc);
-	if (!rc)
-		return !rc;
+	if (cpqhp_legacy_mode) {
+		fakedev.devfn = dev_num << 3;
+		fakedev.bus = &fakebus;
+		fakebus.number = bus_num;
+		dbg("%s: dev %d, bus %d, pin %d, num %d\n",
+		    __FUNCTION__, dev_num, bus_num, int_pin, irq_num);
+		rc = pcibios_set_irq_routing(&fakedev, int_pin - 0x0a, irq_num);
+		dbg("%s: rc %d\n", __FUNCTION__, rc);
+		if (!rc)
+			return !rc;
 
-	// set the Edge Level Control Register (ELCR)
-	temp_word = inb(0x4d0);
-	temp_word |= inb(0x4d1) << 8;
+		// set the Edge Level Control Register (ELCR)
+		temp_word = inb(0x4d0);
+		temp_word |= inb(0x4d1) << 8;
 
-	temp_word |= 0x01 << irq_num;
+		temp_word |= 0x01 << irq_num;
 
-	// This should only be for x86 as it sets the Edge Level Control Register
-	outb((u8) (temp_word & 0xFF), 0x4d0);
-	outb((u8) ((temp_word & 0xFF00) >> 8), 0x4d1);
-#endif
+		// This should only be for x86 as it sets the Edge Level Control Register
+		outb((u8) (temp_word & 0xFF), 0x4d0);
+		outb((u8) ((temp_word & 0xFF00) >> 8), 0x4d1);
+	}
 
 	return 0;
 }
