The MP tables on many SMP motherboards fail to build entries for the INTerrupt routing of cards with PCI bridges on them.

In the long term we are going to have to write code that probes the PCI subsystem and rebuilds an in-core MP table from scratch. In the meantime a patch can be added to i386/i386/mp_machdep.c to get around the problem. Besides the obvious downside of needing to build a custom kernel this patch method also requires that the PCI-bridged card be kept in the specific slot for which the patch is written.

Method:

Identify the APIC INT#s acssociated with each slot. To get an accurate MP table you might need to boot an SMP kernel. If this is a "chicken & egg" problem, turn off PnP options in the BIOS which would reassign INTs, thus perverting the mptable output.

From the mptable output identify the APIC INT to PCI associations:

Bus:            Bus ID  Type
                 0       ISA   
                 1       PCI

I/O Ints:       Type    Polarity    Trigger     Bus ID   IRQ    APIC ID INT#
                INT     active-lo       level        1  20:A          2   16
                INT     active-lo       level        1  19:A          2   17
                INT     active-lo       level        1  18:A          2   18
                INT     active-lo       level        1  17:A          2   19

From the dmesg ouput identify the APIC INT PCI slot associations of any NON-bridged PCI cards:

de0 <Digital 21040 Ethernet> rev 35 int a irq 19 on pci0:17
de1 <Digital 21040 Ethernet> rev 35 int a irq 16 on pci0:20
                                              ^^       ^ ^^

We now know that whichever PCI slot the de0 card is in is connected to APIC INT# 19, and the slot occuppied by de1 is connected to APIC INT# 16. Assumming that de1 is in slot #1 and de0 is in slot #4, we arrive at this mapping:

Note that nothing requires that the APIC INT#s / PCI slots follow this (or any) logical ordering, but they usually do. In some cases you may need to boot with a NON-bridged PCI card in each respective slot to map them all correctly. Also note that this test card must be a card that generates INTs (eg, NOT a vga card) to get the required info out of dmesg. An additional complication is that the PCI bus is mis-numbered in the above MP table. Specifically, the PCI bus is given the # '1' in the table, but it is really PCI bus #0 from the point of view of the entire PCI sub-system. The spec says that the PCI bus can be numbered anyway you want IF there is only ONE PCI bus, which is what the failing MP BIOS is assumming. BUT the bridged PCI card adds a second PCI bus, invalidating this assumption. So just consider the primary bus to be numbered '0', and the bridged card to be numbered '1'. When adding a second bridged card, go have a couple beers... (editorial comment: this whole thing sucks...)

Identify the PCI bus# and device#s used by the PCI-bridged card.

From the dmesg ouput for the bridged (failing) PCI card:

ahc0 <Adaptec 3940 Ultra SCSI host adapter> rev 0 int a irq 10 on pci1:4
                                                                     ^ ^
ahc1 <Adaptec 3940 Ultra SCSI host adapter> rev 0 int a irq 9 on pci1:5
                                                                    ^ ^

Choose a specific PCI slot for the PCI-bridged card.

From the first step we determined which slot used which APIC INT. For the purposes of this discussion let's assume we are now placing the bridged PCI card into slot #2, so that its 1st INT will be connected to APIC INT #17, and its 2nd INT will be connected to APIC INT #18 (hopefully!). Modify the relevant lines of the following patch to reflect this information:

    if ( (pciBus == ?) && (pciDevice == ?) )
                    ^ PCI bus#          ^ device#
         return ?;
                ^ APIC INTerrupt#
becomes:
    if ( (pciBus == 1) && (pciDevice == 4) )
         return 17;
    if ( (pciBus == 1) && (pciDevice == 5) )
         return 18;

Apply the patch to mp_machdep.c with the above info plugged in.

*** mp_machdep.c.orig    Thu Dec 12 01:43:52 1996
--- mp_machdep.c         Sat Apr 19 11:44:18 1997
***************
*** xxx,yyy ****
  pci_apic_pin(int pciBus, int pciDevice, int pciInt)
  {
      int	intr;
  
      --pciInt;                                 /* zero based */
  
--- xxx,yyy ----
  pci_apic_pin(int pciBus, int pciDevice, int pciInt)
  {
      int	intr;
+ 
+     if ( (pciBus == 1) && (pciDevice == 4) )
+          return 17;
+     if ( (pciBus == 1) && (pciDevice == 5) )
+          return 18;
  
      --pciInt;                                 /* zero based */