The kernel's interrupt handling data structures are set up by the device drivers as they request control of the system's interrupts. To do this the device driver uses a set of Linux kernel services that are used to request an interrupt, enable it and to disable it.
The individual device drivers call these routines to register their interrupt handling routine addresses. Some interrupts are fixed by convention for the PC architecture and so the driver just requests its interrupt. There may be times when an ISA device driver does not know which interrupt the device will use. Linux supports interrupt polling to allow the device driver to find the device's interrupt number. The device driver does something to the device which will cause it to interrupt. Then, all of the unassigned interrupts in the system are enabled and Linux waits a short while for the device to interrupt. The interrupt status registers are then read and returned the device driver which uses them to determine which interrupt the device is using.
PCI based systems are much more dynamic than ISA based systems. The interrupt pin that an ISA device uses is often set using jumpers on the hardware device and fixed in the device driver. On the other hand, PCI devices have their interrupts allocated by the system as it is initialized. Each PCI device may use one of four interrupt pins, A, B, C or D. This was fixed when the device was built and most devices default to interrupt on pin A. The PCI interrupt lines A, B, C and D for each PCI slot are routed to the interrupt controller. So, Pin A from PCI slot 4 might be routed to pin 6 of the interrupt controller, pin B of PCI slot 4 to pin 7 of the interrupt controller and so on. How the PCI interrupts are routed is entirely system specific and there must be some set up code which understands this PCI interrupt routing topology. On Intel based PCs this is the system BIOS code that runs at boot time but for system's without BIOS (for example Alpha AXP based systems) the Linux kernel does this setup.
The PCI set up code writes the pin number of the interrupt controller into the PCI configuration header for each device. It determines the interrupt pin (or IRQ) number using its knowledge of the PCI interrupt routing topology together with the devices PCI slot number and which PCI interrupt pin (A, B, C or D) that it is using. It writes this information into the interrupt line field that is reserved for this purpose. When the device driver runs it reads this information and uses it to request control of the interrupt from the Linux kernel.
There may be a large number of PCI interrupt sources in the system, for example when PCI-PCI bridges are used. The number of interrupt sources may exceed the number of pins on the system's programmable interrupt controllers. In this case, PCI devices may share interrupts, one pin on the interrupt controller taking interrupts from more than one PCI device. Linux supports this by allowing the first requestor of an interrupt source declare whether it may be shared. Sharing interrupts results in several irqaction data structures being point at by one entry in the irq_action vector. When a shared interrupt happens, Linux will call all of the interrupt handlers for that source. Any device driver that can share interrupts (which should be all PCI device drivers) must be prepared to have its interrupt handler called when there is no interrupt to be serviced.