Implementing Handlers

Recall that the prototype of ISR functions is specified by irq_handler_t. I have not shown the actual definition of this typedef, but do so now:

<interrupt.h>

typedef irqreturn_t (*irq_handler_t)(int, void *);

irq specifies the IRQ number, and dev_id is the device ID passed when the handler is registered. irqreturn_t is another typedef to a simple integer.

Note that the prototype of ISRs was changed during the development of 2.6.19! Before, the arguments of the handler routine also included a pointer to the saved registers:

<interrupt.h>

irqreturn_t (*handler)(int irq, void *dev_id, struct pt_regs *regs);

Interrupt handlers are obviously hot code paths, and time is very critical. Although most handlers do not need the register state, time and stack space is required to pass a pointer to it to every ISR. Removing this pointer from the prototype is thus a good idea.16

Handlers that need the register set can still access it. The kernel defines a global per-CPU array that stores the registers, and get_irq_regs from >include/asm-generic/irq_regs.h> can be used to retrieve a pointer to the pt_regs instance. This instance contains the register setting that was active when the switch to kernel mode was made. The information is not used by normal device drivers but sometimes comes in useful when debugging kernel problems.

Again we emphasize that interrupt handlers can only use two return values: irq_handled if the IRQ was handled correctly, or irq_none if the ISR did not feel responsible for the IRQ.

What are the tasks of a handler routine? To service a shared interrupt, the routine must first check whether the IRQ is intended for it. If the peripheral device is of a more modern design, the hardware offers a simple method of performing this check, usually by means of a special device register. If the device has caused an interrupt, the register value is set to 1. In this case, the handler routine must restore the value to its default (usually 0) and then start normal servicing of the interrupt. If it finds the value 0, it can be sure that the managed device is not the source of the interrupt, and control can be returned to the higher-level code.

If a device does not have a state register of this kind, the option of manual polling still remains. Each time an interrupt occurs, the handler checks whether data are available for the device. If so, the data are processed. If not, the routine is terminated.

A handler routine can, of course, be responsible for several devices at the same time, for example, two network cards of the same type. If an IRQ is received, the same code is executed on both cards because both handler functions point to the same position in the kernel code. If the two devices use different IRQ numbers, the handler routine can differentiate between them. If they share a common IRQ, reference can still be made to the device-specific dev_id field to uniquely identify each card.

Continue reading here: Software Interrupts

Was this article helpful?

+1 0