Interrupt handling is a fundamental part of the Linux kernel. Most ofthe kernel's functionality, in particular the parts of interest toembedded developers, in some way involve interrupt handling.
This article describes the most important concepts related to the Linux kernel's interrupthandling mechanisms. These concepts include the relevantcode and data structures. Sample code from Linux kernel version 2.6.12is also provided.
struct irqdesc and do_IRQ
Each interrupt source available to the system has allocated to it asingle struct irqdesc structure. This structure stores important information for theinterrupt controller, handler and others:
The handle field points to a high-level “handler” for the interruptline asserting the interrupt request. In ARM architectures, the handleris called do_level_IRQ :
void do_level_IRQ (unsigned int irq,
Do_level_ IRQ acknowledgesthe interrupt request, then invokes the list of device interrupthandlers registered with that interrupt source by calling __do_irq . We will come back to thisfunction in a moment.
The chip field refers to the functions that manage the interruptcontroller hardware. It is not uncommon for hardware that supportsLinux to contain several different interrupt controllers, each havingits own procedure for enabling, disabling and acknowledging interrupts.Most PCs have two interrupt controllers; some microcontrollers used inembedded applications have one or two built-in controllers, with one ormore “external” interrupt controllers implemented using programmablelogic devices.
The struct irqchip structure looks like this:
The action field of struct irqdesc maintains a list of structirqaction structures, each of which represents a device interrupthandler that has registered with the interrupt request line using request_irq . The __do_irq function “walks” this listeach time the interrupt request line is serviced:
The pend field is an ARM-specific field, used to make sure thatpending interrupt requests are fully serviced during interrupthandling.
The chipdata field is another ARM-specific field, used by interruptcontroller handlers as a private data pointer. Some ARM implementationslike SA1111 use this field to store the physical address of theinterrupt controller that manages the request line. Others, likeAT91RM920, use this pointer to store the physical address of the GPIO controller that manages the line.
The data field is another ARM-specific field, used by deviceinterrupt handlers as a private data pointer. Many device drivers usesthis field to store a pointer to per device data structures.
The disable_depth fieldkeeps interrupt enable and disable requests balanced. An interruptrequest line is not truly disabled until the number of disable requestsmatches the number of enable requests.
Handling an interrupt request
When the host microcontroller responds to an interrupt request, controlfirst goes to a bit of assembly language code that knows how to storeregister values and other information critical to restoring the machinestate after the interrupt is serviced. In ARM machines, the function iscalled __irq_svc :
With the current processor state saved away, ARM machines theninvoke asm_do_IRQ :
The desc->handle() invocation calls do_level_IRQ or do_edge_IRQ , depending onthe type of interrupt request line being serviced.
A basic interrupt handler
The CogentComputer Systems , Inc. CSB637 single board computer has apushbutton connected to GPIO PB29. When pressed, this pushbutton sendsan edge-triggered interrupt to the GPIO controller, which forwards therequest to the interrupt controller.
(A bit of magic further demultiplexes the interrupt request to aunique irqdesc. This magic is necessary because the AT91RM9200's GPIOcontrollers each have only one line leading to the chip's interruptcontroller. This magic is well hidden from device interrupt handlers.)
A simple “device interrupt handler” for this pushbutton might looklike the following:
This code would be registered with the Linux kernel's request_irq function:
Probe_irq_on and probe_irq_off
The Linux kernel's interrupt management system can help you determinewhich physical interrupt request line is assigned to your device. Thisfeature is also useful for confirming that the interrupt request lineis actually functioning before your system commits to using it.
The following code shows how to “probe” for an interrupt requestline:
“Virtual” interrupt descriptors
A multifunction chip might use one interrupt request line to signalinterrupt requests from all of its onboard functions. Many multichannelUART chips have only a singleinterrupt request line leading back to the host microcontroller, forexample.
Device drivers for multifunction chips can often be made morereusable and flexible if they can focus on only one feature of thetarget chip. The SM501graphics processor has built-in AC97, UART and USBH, butonly one interrupt request line back to the host processor.
Rather than writing a combined video-plus-audio-plus-USB that wouldonly be useful for that chip, with some effort it is possible to re-usethe Linux kernel's standard framebuffer, audio and USBdevice drivers instead.
To do so, you must “demultiplex” the interrupt request line for themultifunction chip so that the signaling sub-component can be servicedby the right driver. Under Linux, this is done by creating “virtualinterrupt descriptors” that look like unique interrupt sources for thepurposes of device drivers:
The device interrupt handler for the physical interrupt request linegets the interrupt request first. It then reads the interrupt statusfrom the chip, and redirects the interrupt request to the descriptorassociated with the function requesting service:
A clear understanding of the Linux kernel's interrupt handlingmechanism is essential if you are to write solid, reusable deviceinterrupt handlers. It is also mandatory if you are to successfullyport Linux to custom hardware.
BillGatliff is a freelance embedded developer and training consultant with10 years of experience using GNU and other tools for building embeddedsystems targeting automotive, aerospace, and medical instrumentationapplications. He is a contributing editor for Embedded Systems Design,author of the Embedded GNU Jumpstart and Embedded Linux Jumpstartseries of training materials. He con be contacted firstname.lastname@example.org.
This article is excerpted from a paper of the same name presentedat the Embedded Systems Conference Boston 2006. Used with permission ofthe Embedded Systems Conference. For more information, please visit www.embedded.com/esc/boston/.