* copy [http://www.pengutronix.de/software/ptxdist/temporary-src/references/my_irq_table.c this file] as '''my_pirq_table.c''' into kernel's '''arch/i386/pci/'''

* open '''arch/i386/pci/irq.c''' with your favorite editor and search for the functions '''pirq_find_routing_table()''' and '''pirq_check_routing_table()'''.

* open '''arch/i386/pci/irq.c''' with your favorite editor and search for the functions '''pirq_find_routing_table()''' and '''pirq_check_routing_table()'''.

* Remove them with the well known '''#if 0 / #endif''' directives.

* Remove them with the well known '''#if 0 / #endif''' directives.

−

* add a '''#include "my_pirq_table.c"''' to the code

+

* add a '''#include "my_pirq_table.c"''' to the code (''after'' the #defines for PIRQ_SIGNATURE/PIRQ_VERSION)

* modify '''arch/i386/pci/pci.h''' and define the '''DEBUG''' macro. Linux will output helpful info, when this macro is enabled.

* modify '''arch/i386/pci/pci.h''' and define the '''DEBUG''' macro. Linux will output helpful info, when this macro is enabled.

* modify '''my_pirq_table.c''' for your requirements. Search for ''TODO'' in the source where to change something

* modify '''my_pirq_table.c''' for your requirements. Search for ''TODO'' in the source where to change something

Line 31:

Line 29:

** select only one IRQ channel per INT?# in (it makes this job easier)

** select only one IRQ channel per INT?# in (it makes this job easier)

−

== Here what I did ==

+

== Here's what I did ==

−

I have two PCI devices connected to my Geode GX1 based board (Companion 5530 chipset):

+

I have two PCI devices connected to my Geode GX1 based board (CS5530 chipset):

* The internal USB OHCI

* The internal USB OHCI

* and an external Realtek 8139 network chip.

* and an external Realtek 8139 network chip.

Line 39:

Line 37:

There is no additional slot, it is a very small Win-Terminal.

There is no additional slot, it is a very small Win-Terminal.

−

I assumed the Realtek outputs its interrupt on its INTA# pin (the starting kernel will states this if the '''DEBUG''' macro in '''pci.h''' is defined, so read the ''dmesg'' output if you're unsure). The same I assumed for the USB device. Also I assumed RealTek's INTA# output is connected to chipset's

+

I assumed the Realtek outputs its interrupt on its INTA# pin (the starting kernel will state this if the '''DEBUG''' macro in '''pci.h''' is defined, so read the ''dmesg'' output if you're unsure). The same I assumed for the USB device. Also I assumed RealTek's INTA# output is connected to chipset's

To find a start, I tried to use IRQ15 and IRQ11 for these devices. I wanted the network device connected to IRQ15 (green line) and the USB device connected to IRQ11 (red line). The pci chip info the table needs I got from LinuxBios, when it scans the pci bus. So activate a higher level of debug output in LinuxBios to collect all information you need here. Ignore the black lines in the picture. They may exist or not.

+

To find a start, I tried to use IRQ15 and IRQ11 for these devices. I wanted the network device connected to IRQ15 (green line) and the USB device connected to IRQ11 (red line). The PCI chip info the table needs I got from coreboot, when it scans the PCI bus. So activate a higher level of debug output in coreboot to collect all information you need here. Ignore the black lines in the picture. They may or may not exist.

* "ping" the network card and check if its interrupt count increases. Check all the other pci devices in your system and let them generate interrupts. Always check '''/proc/interrupts''' to see which interrupt get this signal.

+

* "ping" the network card and check if its interrupt count increases. Check all the other PCI devices in your system and let them generate interrupts. Always check '''/proc/interrupts''' to see which interrupt get this signal.

* In my case I got nothing both on the network and the USB interrupt. A "ping" does not increase any interrupt count. Then I attached an USB hub to my system and IRQ15 count increases. '''BINGO!''' This means the network device isn't connected to chipset's INTA# input, its the USB device instead! And it also means INTB# does not receive any interrupt, so it seems not connected to any device. For the next step I used INTC# for the network device instead.

* In my case I got nothing both on the network and the USB interrupt. A "ping" does not increase any interrupt count. Then I attached an USB hub to my system and IRQ15 count increases. '''BINGO!''' This means the network device isn't connected to chipset's INTA# input, its the USB device instead! And it also means INTB# does not receive any interrupt, so it seems not connected to any device. For the next step I used INTC# for the network device instead.

−

Note: Check the interrupt steering setting the linux routing setup stores into the IRQ router! In my case it took hours to see, Linux didn't know my IRQ router! So the steering registers where still at their reset value, what means "No routing"! After adding the IRQ router support for my chipset it routes the interrupts!

+

Note: Check the interrupt steering setting the Linux routing setup stores into the IRQ router! In my case it took hours to see, Linux didn't know my IRQ router! So the steering registers were still at their reset value, which means "No routing"! After adding the IRQ router support for my chipset it routes the interrupts!

* I changed the routing table in "my_pirq_table.c" again to the routing shown below, rebuilt the kernel and reboot

* I changed the routing table in "my_pirq_table.c" again to the routing shown below, rebuilt the kernel and reboot

Line 78:

Line 76:

This is the [http://www.pengutronix.de/software/ptxdist/temporary-src/references/pci_irq_fake_2.c source] I used in this case.

This is the [http://www.pengutronix.de/software/ptxdist/temporary-src/references/pci_irq_fake_2.c source] I used in this case.

−

With this table also the network interrupt receives signals. Then I removed the "irqpoll" and reboot this kernel again. The system runs with interrupts only (and no more polling).

+

With this table also the network interrupt receives signals. Then I removed the "irqpoll" option and rebooted this kernel again. The system runs with interrupts only (and no more polling).

−

The interrupt routing table from '''my_pirq_table.c''' is now ready to be used in LinuxBIOS. Only the checksum may not usable.

+

The interrupt routing table from '''my_pirq_table.c''' is now ready to be used in coreboot. Only the checksum may not be usable.

−

My kernel patch ignores a wrong checksum but calculates the right one instead! See ''dmesg'''s output, search for the right checksum and change it in the source file. Rebuild LinuxBios with this new irq routing table and flash it into your target.

+

My kernel patch ignores a wrong checksum but calculates the right one instead! See ''dmesg'''s output, search for the right checksum and change it in the source file. Rebuild coreboot with this new IRQ routing table and flash it into your target.

open arch/i386/pci/irq.c with your favorite editor and search for the functions pirq_find_routing_table() and pirq_check_routing_table().

Remove them with the well known #if 0 / #endif directives.

add a #include "my_pirq_table.c" to the code (after the #defines for PIRQ_SIGNATURE/PIRQ_VERSION)

modify arch/i386/pci/pci.h and define the DEBUG macro. Linux will output helpful info, when this macro is enabled.

modify my_pirq_table.c for your requirements. Search for TODO in the source where to change something

define slot/device count

define the interrupt router

select some IRQ channels you like to use for the PCI devices

select only one IRQ channel per INT?# in (it makes this job easier)

Here's what I did

I have two PCI devices connected to my Geode GX1 based board (CS5530 chipset):

The internal USB OHCI

and an external Realtek 8139 network chip.

There is no additional slot, it is a very small Win-Terminal.

I assumed the Realtek outputs its interrupt on its INTA# pin (the starting kernel will state this if the DEBUG macro in pci.h is defined, so read the dmesg output if you're unsure). The same I assumed for the USB device. Also I assumed RealTek's INTA# output is connected to chipset's
INTA# input, and USB's INTA# output is connected to chipset's INTB# input.

To find a start, I tried to use IRQ15 and IRQ11 for these devices. I wanted the network device connected to IRQ15 (green line) and the USB device connected to IRQ11 (red line). The PCI chip info the table needs I got from coreboot, when it scans the PCI bus. So activate a higher level of debug output in coreboot to collect all information you need here. Ignore the black lines in the picture. They may or may not exist.

Building this kernel and preparing it for boot

The important kernel parameter is irqpoll. This lets the network card do its job without a valid interrupt routing! It slows down the system, but makes it work! (in my case the NFS root filesystem)

Boot this kernel (I did it with etherboot). When the system is up and running, login to it and run a

$ cat /proc/interrupts

to see what happens with the interrupts.

"ping" the network card and check if its interrupt count increases. Check all the other PCI devices in your system and let them generate interrupts. Always check /proc/interrupts to see which interrupt get this signal.

In my case I got nothing both on the network and the USB interrupt. A "ping" does not increase any interrupt count. Then I attached an USB hub to my system and IRQ15 count increases. BINGO! This means the network device isn't connected to chipset's INTA# input, its the USB device instead! And it also means INTB# does not receive any interrupt, so it seems not connected to any device. For the next step I used INTC# for the network device instead.

Note: Check the interrupt steering setting the Linux routing setup stores into the IRQ router! In my case it took hours to see, Linux didn't know my IRQ router! So the steering registers were still at their reset value, which means "No routing"! After adding the IRQ router support for my chipset it routes the interrupts!

I changed the routing table in "my_pirq_table.c" again to the routing shown below, rebuilt the kernel and reboot

With this table also the network interrupt receives signals. Then I removed the "irqpoll" option and rebooted this kernel again. The system runs with interrupts only (and no more polling).

The interrupt routing table from my_pirq_table.c is now ready to be used in coreboot. Only the checksum may not be usable.

My kernel patch ignores a wrong checksum but calculates the right one instead! See dmesg's output, search for the right checksum and change it in the source file. Rebuild coreboot with this new IRQ routing table and flash it into your target.

Now you can run an unpatched kernel on your system.

Required patches for Geode's companion CS5530

This patch is needed to let Linux know the Cyrix 5530 interrupt router.

This file is licensed under Creative CommonsAttribution 2.5 License.In short: you are free to distribute and modify the file as long as you attribute its author(s) or licensor(s).