ALi pIRQ, HP Notebook PCI IRQ quiks...

From: John Clemens (
Date: Fri Nov 16 2001 - 00:29:42 EST

A little while ago (a month?), I posted a message here asking what I could
do to get USB working on my laptop. All indications appeared that this
was an IRQ problem. I recieved only one response telling me I was most
likely screwed... undaunted I pressed on, and managed to get USB to work..
My question now is WHY??? I did some very unholy things to PCI setup, and
I'd like to know the "right way" of doing this..

Warning, long explination follows:

System is an HP Pavilion N5430 laptop (Mobile Duron, ALi Magik1 chipset.).
USB is the standard ALi OHCI USB controller. USB works under windows, and
shows up as IRQ 9 (however, it "skips" every now and then.. ie, like it
need to do a bus reset every 5 minutes or so). Under Linux, usb shows up
on IRQ 9 (shared with ACPI), and never works (no interrupts get through.)

lspci shows PCI config space always has the USB device configured to IRQ
9 (both regular and bus view). Everything points to both the BIOS and PCI
space thinking that USB should be on IRQ 9.... All, that is, except the
pIRQ table..

Using the dump_pirq utility from the pcmcia-cs package, you get the
following output:

Interrupt routing table found at address 0xfdf40:
  Version 1.0, size 0x00a0
  Interrupt router is device 00:07.0
  PCI exclusive interrupt mask: 0x0000 []
  Compatible router: vendor 0x10b9 device 0x1533

Device 00:0f.0 (slot 0): IDE interface

Device 00:02.0 (slot 0): USB Controller
  INTA: link 0x59, irq mask 0x0800 [11]

Device 00:08.0 (slot 1): Multimedia audio controller
  INTA: link 0x49, irq mask 0x0020 [5]

Device 00:04.0 (slot 0): CardBus bridge
  INTA: link 0x48, irq mask 0x0800 [11]
  INTB: link 0x48, irq mask 0x0800 [11]

Device 00:10.0 (slot 0): Ethernet controller
  INTA: link 0x48, irq mask 0x0800 [11]

Device 00:07.0 (slot 0): ISA bridge
  INTA: link 0x48, irq mask 0xdef8 [3,4,5,6,7,9,10,11,12,14,15]
  INTB: link 0x48, irq mask 0xdef8 [3,4,5,6,7,9,10,11,12,14,15]
  INTC: link 0x49, irq mask 0xdef8 [3,4,5,6,7,9,10,11,12,14,15]
  INTD: link 0x49, irq mask 0xdef8 [3,4,5,6,7,9,10,11,12,14,15]

Device 00:01.0 (slot 0): PCI bridge
  INTA: link 0x48, irq mask 0x0800 [11]

Device 01:00.0 (slot 0): VGA compatible controller
  INTA: link 0x48, irq mask 0x0800 [11]

Interrupt router at 00:07.0: AcerLabs Aladdin M1533 PCI-to-ISA bridge
  INT1 (link 1): irq 11
  INT2 (link 2): irq 11
  INT3 (link 3): unrouted
  INT4 (link 4): unrouted
  INT5 (link 5): unrouted
  INT6 (link 6): unrouted
  INT7 (link 7): unrouted
  INT8 (link 8): unrouted
  Serial IRQ: [enabled] [continuous] [frame=21] [pulse=12]

As you can see, according to the pIRQ routing table, the sound card is
wired to IRQ 5, and everything else, including USB, -can only be- IRQ 11.

So, doing some evil hackery, using the fact that in this laptop there's
only one PCI device on IRQ 9, I changed the PCI IRQ probing code to change
all PCI devices on IRQ 9 to IRQ 11.. the attached patch implements this...
yet even with this patch, i still need to call "setpci" to change the USB
IRQ in PCI config space to irq 11 (0xb)... then, and only then, can I
modprobe the usb-ohci driver, have it come up on IRQ 11, and it works

So, now I can use USB.. but I have many more questions for those PCI
experts out there...

        1) Why does this work? It appears that the pIRQ table is right,
but the BIOS and PCI config space are wrong. If this is the case, how
(should?) we teach linux to use the pIRQ table as it's guide over
everything else?

        2) Why does it work under windows on IRQ9?

        3) Shouldn't the call to pci_write_config_byte change the IRQ in
PCI config space? why do I need to call setpci to set the IRQ again from
user space to get lspci et al to report IRQ11?

        4) Why does linux seem to be ignoring the pIRQ table?

        5) Where is the "correct" place to put a hack like this?

        6) is there any way to make USB work on IRQ 9?, or are we talking
about an obnoxiously braindead bios?

More details available (I've been fooling with this for a little bit), but
i'm trying to keep this pretty brief. If anyone has any ideas, i'd be very
interested in hearing them.


John Clemens     ICQ: 7175925, IM: PianoManO8
      "I Hate Quotes" -- Samuel L. Clemens

diff -u --recursive linux-2.4.13-pre6/arch/i386/kernel/pci-i386.h linux/arch/i386/kernel/pci-i386.h --- linux-2.4.13-pre6/arch/i386/kernel/pci-i386.h Wed Jun 20 14:21:33 2001 +++ linux/arch/i386/kernel/pci-i386.h Tue Oct 23 23:13:08 2001 @@ -4,7 +4,7 @@ * (c) 1999 Martin Mares <> */

-#undef DEBUG +#define DEBUG

#ifdef DEBUG #define DBG(x...) printk(x) diff -u --recursive linux-2.4.13-pre6/arch/i386/kernel/pci-irq.c linux/arch/i386/kernel/pci-irq.c --- linux-2.4.13-pre6/arch/i386/kernel/pci-irq.c Thu Nov 15 21:18:03 2001 +++ linux/arch/i386/kernel/pci-irq.c Thu Oct 25 12:47:56 2001 @@ -588,9 +588,9 @@ irq = pirq & 0xf; DBG(" -> hardcoded IRQ %d\n", irq); msg = "Hardcoded"; - } else if (r->get && (irq = r->get(pirq_router_dev, dev, pirq))) { + /*} else if (r->get && (irq = r->get(pirq_router_dev, dev, pirq))) { DBG(" -> got IRQ %d\n", irq); - msg = "Found"; + msg = "Found";*/ } else if (newirq && r->set && (dev->class >> 8) != PCI_CLASS_DISPLAY_VGA) { DBG(" -> assigning IRQ %d", newirq); if (r->set(pirq_router_dev, dev, pirq, newirq)) { @@ -673,6 +673,10 @@ if (dev->irq >= 16) { DBG("%s: ignoring bogus IRQ %d\n", dev->slot_name, dev->irq); dev->irq = 0; + } + if (dev->irq == 9) { + pci_write_config_byte(dev, PCI_INTERRUPT_PIN, 0x0b); + dev->irq=11; } /* If the IRQ is already assigned to a PCI device, ignore its ISA use penalty */ if (pirq_penalty[dev->irq] >= 100 && pirq_penalty[dev->irq] < 100000)

- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to More majordomo info at Please read the FAQ at

This archive was generated by hypermail 2b29 : Fri Nov 23 2001 - 21:00:13 EST