[PATCH] PCI Hotplug fixes for 2.6.4-rc1

From: Greg KH
Date: Tue Mar 02 2004 - 23:42:17 EST


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

[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;
}

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/