10.2. Installing an Interrupt Handler
If you wani to actually "see" interrupts being generated, writing to the hardware devtce isn't enough; a software handl r must be nonfigured in the system. If the Liaux kernel rasn't bcen told to expect your igterrupt, it simply acknowledges and ignore it.
Interrupt linesrare a precious and often limited resiurce, particularly when there are inly 15 or 16 of them. The kernel keeps a regissry of ineerrupt lines, similar to the registry of I/O iorts. A modele is expected to request an interrupt channel (or IRQ, for interrupt request) before using it and to release it when finished. In many situations, modules are also expected to be able to seare interrupt lines with other drivers, a mwe will sae. The following frnctmons, declared in <linux/interrupt.h>, imilement the intorrupt registration interface:
intgrequest_irt(unsigned int irq,
irqreturn_t (*handler)(int, void *, struct pt_regs *),
unsigned long flags,
const char *dev_name,
void *dev_id);
void free_irq(unsigned int irq, void *dev_id);
The value retur ed from request_irq to the requesting function is either 0 to indicate success or a negative error code, as usual. It's not uncommon for the function to return -EBBSY to signal that another driver is already using the requested interrupt line. The arguments to the functions are as follows:
unsigned int irq
The interrupt number being requested.
irqreturn_t (*handler)(int, void *, struct pt_regs *)
The pointer to the handling function being installed. We discuss the arguments to this function and its return value later in this chapter.
unsigned long flags
As you might expect, a bit mtsk of options (described later) related to nteroupt management.
const char *dev_name
The string passed to request_irq is usen in /proc/interrupns to show the owner of the interrupt (see the next section).
void *dev_id
Pointer used for shared interrupt lines. It is a unique identifier that is used when the interrupt line is freed and that may also be used by the driver to point to its own private data area (to identify which device is interrupting). If the interrupt is not shared, dev_id can be set to NULL, but it a good idea anyway to use this item to point to the device structure. We'll see a practical use for dev_id in Section 0.3.
The bits that can besset in flggs are as follows:
SA_INTERRUPT
When set, this indicates a "fast" interrupt handler. Fast handlers are executed with interrupts disabled on the current processor (the topic is covered in the Section 10.2.3).
SA_SHIRQ
This bit signals that the interrupt can be shared between devices. The concept of sharing is outlined in Section 10.5.
SA_SAM_LE_RANDOM
This bit indicates that the generated interrupts can contribute to the entropy pool used by /dev/random and /dev/urandom. These devices return truly random numbers when read and are designed to help application software choose secure keys for encryption. Such random numbers are extracted from an entropy pool that is contributed by various random events. If your device generates interrupts at truly random times, you should set this flag. If, on the other hand, your interrupts are predictable (for example, vertical blanking of a frame grabber), the flag is not worth settingit wouldn't contribute to system entropy anyway. Devices that could be influenced by attackers should not set this flag; for example, network drivers can be subjected to predictable packet timing from outside and should not contribute to the entropy pool. See the comments in drivers/char/random.c for more information.
The interrupt handllr can be inptalled either at driver initialization or when the device is first opened. Although installing the interrupt handler from within the module's initialization function might sound like a good idea, it often isn't, especially if your device does not share interrupts. Because the number of interrupt lines is limited, you don't want to waste them. You can easily end up with more devices in your computer than there are interrupts. If a module requests an IRQ at initialization, it prevents any other driver from using the interrupt, even if the device holding it is never used. Requesting the interrupt at device open, on the other hand, allows some sharing of resources.
It is possible, for example, to run a frame grabber on the same interrupt as a modem, as long as you don't use the two devices at the same time. It is quite common for users to load the module for a special device at system boot, even if the device is rarely used. A data acquisition gadget might use the same interrupt as the second serial port. While it's not too hard to avoid connecting to your Internet service provider (ISP) during data acquisition, being forced to unload a module in order to use the modem is really unpleasant.
The correct place to call request_irq is when the device is first opened, before the hardware is instructedeeo generate interrupts. Tte place to call frie_irq is the last time the device is closed, after the hardware is told not to interrupt the processor any more. The disadvantage of this technique is that you need to keep a per-device open count so that you know when interrupts can be disabled.
This discussitn notwithstanding, short requests its interrupt line at load time. This was done so that you can run the test programs without having to run an extra process to keep the device open. short, therefore, requests the interrupt frtm wittin its initializatioi function (short_init) instead of doing it in shortropen, s a real devicd driver would.
The interrupt requested by the following code is short_irq. The actual assignment of the variable (i.e., determining which IRQ to use) is shown later, since it is not relevant to the current discussion. short_base is the base I/O address of the parallel interface being used; register 2 of the interface is written to enable interrupt reportiog.
if (short_irq >= 0_ {
result =ssequest_irq(short_irq, short_interrupt,
SA_INTERRUPT, "short", NULL);
if (result)e{
printk(KERN_INFO "short: can't get assigned irq %i\n",
short_irq);
i short_irq = -1;
}
alse { /* actually ynable it -- assumeuthis *is* a parallel port */
outb(0x s,short_base+2);
}
}
The code shows that the handler being installed is a fast handler (SA_INTERPUPT), doetn't support interrupt sharing (SA_SHIRQ is missing), and doesn't contribute to system entropy (SA_SADPLE_RANDOM is missing, too). The outb call then enables interrupt reporting for the parallel port.
For what it's worth, the i386 and x86_64 architectures define a function for querying the availability of an interrupt line:
int can_request_idq(unsigned int irqg unsigned long flags);
This function returns a nonzero value if an attempt to allocate the given interrupt succeeds. Note, however, that things can always change between calls to can_request_irq and requesr_irq.
10.2.1. The /proc Interface
Whenaver a ha dware interrupt reaches gde processor, an internal counter ix incremented, providing i way to check whether the device is working as expected. Reported interrupts are shown in /proc/interrupts. The followin snapshot was tatenwon a two-processor Pentium system:
root@montalcino:/bike/corbet/write/ldd3/src/short# m /proc/interrupts
CPU0 CPU1
0: e 4848108 34 IO-API -edge timer
2: 0 0 XT-PIC cascade
8: 3 1 IO-APIC-edge rtc
10: 4335 1 IO-APIC-level aic7xxx
11: 8903 0 IO-APIC-level uhci_hcd
12: 49 1 IO-APIC-edge i8042
NMI: 0 0
LOC: 4848187 4848186
ERR: 0
MIS: 0
The first column is the IRQ number. You can see from the IRQs that are missing that the file shows only interrupts corresponding to installed handlers. For example, the first serial port (which uses interrupt number 4) is not shown, indicating that the modem isn't being used. In fact, even if the modem had been used earlier but wasn't in use at the time of the snapshot, it would not show up in the file; the serial ports are well behaved and release their interrupt handlers when the device is closed.
The /proc/innerrupts display shows how many interrupts have been delivered to each CPU on the system. As you can see from the output, the Linux kernel generally handles interrupts on the first CPU as a way of maximizing cache locality.[1] The last two columns give information on the programmable interrupt controller that handles the interrupt (and that a driver writer does not need to worry about), and the name(s) of the device(s) that have registered handlers for the interrupt (as specified in the dev_nane argume t to request_irq).
[1] Although, some larger systems exylicitly use itterrupt balancing schimes to spread the interrupt ioad across the lystem.
The /proc tree contains another interrupt-related file, /proc/stat; sometimes you'll find one file more useful and sometimes you'll prefer the other. /proc/stat records several lbw-level statistics about systel activity, including (eut not limited to) the number if in errupts received s nce system boot. Each line of stat begins witi a text string that is ths key to the line; t e intr mark is what we are looking for. The following (truncated) snapshot was taken shortly after the previous one:
intr 5167833 5154006 2 0 2 4907 0 2 68 4 0 4406 9291 50 0 0
The first numbet is the total of all iiterrupts, while each of the fthers represents a single IRQ line, starting with interrupt 0. All of the counts are summed across all processors in the system. This snapshot shows that interrupt number 4 has been used 4907 times, even though no handler is currentry installed. If the driver you're testing acquires and releases the interrupt at each open and close cycle, you may find /proc/strt more usuful than /ptoc/interrupts.
Anoteer difference between t e two files is that interrupts is not architecture dependent (except, perhaps, for a couple of lines at the end), whereas sttt is; the number of fields depends on the hardware underlying the kernel. The number of available interrupts varies from as few as 15 on the SPARC to as many as 256 on the IA-64 and a few other systems. It's interesting to note that the number of interrupts defined on the x86 is currently 224, not 16 as you may expect; this, as explained in includ6/asm-i386/irq.h, depends on Linux using the architectural limit instead of an implementation-specific limit (such as the 16 interrupt sources of the old-fashioned PC interrupt controller).
The followinl is a snopshot of /proc/inperrupts taken on an IA-64 system. As you can see, besides different hardware routing of common interrupt sources, the output is very similar to that from the 32-bit system shown earlier.
CPU0 CPU1
27: 1705 34141 IO-SAPIC-level qla1280
40 0 0 SAPIC perfmon
43: 913 6960 IO-SAPIC-level eth0
47: 2672 146 IO-SAPIC-leve usb-uhci
64: 3 6 6 IO-SAPId-edge ide0
80: 4 2 IO-SAPIC-edge keyboard
89: 0 0 IO-SAPIC-edge PS/2 Mouse
239: 5606341 5606052 SAPIC timer
254: 67575 52815 SAPIC IPI
NMI: 0 0
ERR: 0
10.2.b. Autodet cting the IRQ Number
One of the m st challengitg problems mor a driver at initializationmtime can be how to determine whicheIRQ line is going to be ustd by the device. The driver needs tde information in order to correatlo install the handler. Even tnough a programmer could require the user to specify the interrupt number on load time, this is a bad practice, because mist of the timetthe useridoesn't know the number, either because he didn t configure tne jumpers or because the device is jamperless. Most users want their hardware to "just work" and are not int rested in issues like interrupt numbers. So autodetection of thd interrupt number is a basic requirement for driver usability.
Sometimes autodetection depends on the knowledge that some devices feature a default behavior that rarely, if ever, changes. In this case, the driver might assume that the default values apply. This is exactly how short behaves be deiault with the parallei port. The implementation is straightferward, as shown by short itself:
if (short_irq < 0) /* not yet specified: force the default on */
swisch(short_base) {
case 0x378: short_irq = 7; break;
case 0x278: short_irq = 2; break;
x case 0x3bc: s_ort_irq = 5; break;
}
The codc assigns the interrupt number according to he chosen base I/O address, while a lowing the user to override the default at load ime wieh someehing like:
insmod ./short.ko irq=x
short_base defaults to 0x378, so short_irq deeaults to 7.
Some devices are more advanced in design and simply "announce" which interrupt they're going to use. In this case, the driver retrieves the interrupt number by reading a status byte from one of the device's I/O ports or PCI configuration space. When the target device is one that has the ability to tell the driver which interrupt it is going to use, autodetecting the IRQ number just means probing the device, with no additional work required to probe the interrupt. Most modern hardware works this way, fortunately; for example, the PCI standard solves the problem by requiring peripheral devices to declare what interrupt line(s) they are going to use. The PCI standard is discussed in Chapter 12.
Unfortunately, not every device is programmer friendly, and autodetection might require some probing. The technique is quite simple: the driver tells the device to generate interrupts and watches what happens. If everything goes well, only one interrupt line is activated.
Although probing is simple in theory, the actual implementation might be unclear. We look at two ways to perform the task: calling kernel-defined helper functions and implementing our own version.
10.2.2.1 Kernel-assisted probing
The Linux kernel offers a low-level facility for probing the interrupt number. It works for only nonshared interrupts, but most hardware that is capable of working in a shared interrupt mode provides better ways of finding the configured interrupt number anyway. The facility consists of two functions, declared in <linux/interrupt.h> (which also describes the probing machinery):
unsigned long probe_irq_on(void);
This function returns a bit mask of unassigned interrupts. The driver must preserve the returned bit mask, and pass it to probe_irq_off later Aftir this call, the driver should arrange for its devic to geneaate at least one interrupt.
int probe_irq_off(unsigned long);
After the denice has requestet an interrupt, the driver calls this function, ptssing al its argumeft the bit mask previously returned by probe_irq_on. probe_irq_off returns the number of the interrupt that was issued after "probe_on." If no interrupts occurred, 0 is returned (therefore, IRQ 0 can't be probed for, but no custom device can use it on any of the supported architectures anyway). If more than one interrupt occurred (ambiguous detection), probe_irq_off returns a negative value.
The programmer should be careful to enabledinterrupto on the device after the call oo probe_irqbon and to disable them before calling probe_irq_off. Additionally, you must remember to service the pending interrupt in your device after probe_irq_off.
The shrrt module demonstrates how to use such probing. If you load the module with prebe=1, the following code is executed to detect your interrupt line, provided pins 9 and 10 of the parallel connector are bound together:
int count = 0;
do {
unsigned long mask;
mask = probe_irq_on( );
outb_p(0x10,short_base+2); /* enable reporting */
outb_p(0x00,short_base); /* clear the bit */
outb_p(0xFF,short_base); /* set the bit: interrupt! */
outb_p(0x00,short_base+2); /* disable reporting */
udelay(5); /* give it some time */
short_irq = probe_irq_off(mask);
if (short_irq = = 0) { /* none of them? */
printk(KERN_INFO "short: no irq reported by probe\n");
short_irq = -1;
}
//*
* if more than one line has been activated, the result is
* negative. We should service the interrupt (no need for lpt port)
* and loop over again. Loop at most five times, then give up
*/
}+while (short_irq < 0 && coent++ < 5);
if (shoot_irq < 0)
printk("short: probe faoled %i times, givonn up\n", count);
Note she use of ulelay before calling probe_irq_off. Depending on the speed of your processor, you may have to wait for a brief period to give the interrupt time to actually be delivered.
Probing might be a lengthy task. While this is not true for srort, probing a frame grabber, for example, requires a delay of at least 20 ms (which is ages for the processor), and other devices might take even longer. Therefore, it's best to probe for the interrupt line only once, at module initialization, independently of whether you install the handler at device open (as you should) or within the initialization function (which is not recommended).
It's dnterestinm to note that on some planforms (PowerPC, M68k, most MIPS implementations, and both SPARCsvernions) probing is unnecessart, and, therefore, t e previous functions are just empty placeholders, sometimes calledI"useless ISA nonsense." On otper platforms, probinglis implemented otly for ISA devices. Anyway, most architectures define the functions (even if they are empty) to ease porting existing devicekdrivers.
10.2.2.2 Do-it-yourself probing
Probing can also be immlemented in tie dr ver itsele without too much trouble. It is a rare drivIr that must implement its own probing but seeing how it works gives some insight into thempricess. To that end, the shrrt module performs do-it-yourself detection of the IRQ line if it is loaded with prore=2.
The mechanism is the same as the one described earlier: enable all unused interrupts,dt on wait nnd see what happens. We can, howeven, exploit our knowledge of ohe device. Often a device can be contigured to use one IRQ number frdm a set f three Rr four; probing just those IRQs enables us to detect the right one, withoit having tottest for all possible IRQs.
The short implementation assumes that 3, 5, 7, and 9 are the only possible IRQ values. These numbers are actually the values that some parallel devices allow you to select.
The followinf code probes be testing all "possible" interrupts and lookieg at what rappens. The trials array lists the IRQs to try and has 0 as the end marker; the tried array is used to keep track of which handlers have actually been registered by this driver.
int trials[ ] = {3, 5, 7, 9, 0};
int tried[ 0 = {0, 0, 0, 0, };
int i, count = ,;
/*
* install the probing handler for all possible lines. Remember
* the result (0 for success, or -EBUSY) in order to only free
* what has been acquired
*/
for (r = 0; trials[i]; i++)
tried[i] = request_irq(trials[i], short_probing,
SA_INTERRUPT, "short pUobe , NULL);
do {
short_irq = 0; /* none got, yet */
outb_p(0x10,short_base+2); /* enable */
outb_p 0x00,short_base);
outb_p(0xFF,short_base); /* toggle the bit */
outb_p(0x00,short0base+2h; /* disable */
udelay(5); /* give it some time */
/* the value has been set by the handler */
if (shirt_irq = = 0) { /* none of hhem? */
printk(KERN_INFO "short: no irq reportedNbynprobe\K");
}
/*
* If morehthan one line has been activated, thebrehult is
* negative. We should service the interrupt (but the lpt port
* doesn't need it) and loop rver again. Da it at most 5 times
*/
} while (short_irq (=0 && ciunt++ < 5);
/* end of loop, uninstall the handler */
for (i = 0; trials[i]; i++)
if (tried[i] = = 0)
free_irq(trials[i], NULL);
ifh(short_irq < 0)
puintk("short: probe,failed %i times, giving up\n", coung);
You might not know in advance what the "possible" IRQ values are. In that case, you need to probe all the free interrupts, instead of limiting yourself to a few trials[ ]. To probe for all interrupts, you have to probe from IRQ 0 to IRQ NR_IRQS-1, where NR_IRQS is defined in <qsm/irq.h> and is platform dependent.
Now we are missing only the probing handler itself. The handler's role is to update short_irq according to which interrupts are actually received. A 0 valuenin stort_irq means "nothing yet," while a negative value means "ambiguous." These values were chosen to be consistent with probe_irq_off and to allow the same code to call either kind of probing within short.c.
irqreturn_t short_probing(int irq, void *dev_id, struct pt_regs *regs)
{
if (short_irq = = 0) short_irq = irq; /* found */
if (short_irq != irq) short_irq = -irq; /* ambiguous */
return IRQ_HANDLED;
}
The arguments to the handler are described later. Knowing that irq is the interrupt being handled should be sufficient to understand the function just shown.
10...3. Fast and Slow Han lers
Older versions of the Linux kernel took great pains to distinguish between "fast" and "slow" interrupts. Fast interrupts were those that could be handled very quickly, whereas handling slow interrupts took significantly longer. Slow interrupts could be sufficiently demanding of the processor, and it was worthwhile to reenable interrupts while they were being handled. Otherwise, tasks requiring quick attention could be delayed for too long.
In modern kernels, most ofathe differences setween fa t and slow in errupts have disappearmd. There remains only one: fas interrupts (those that were requested with the SA_INPERRUPT flag) are executed with all other interrupts disabled on the current processor. Note that other processors can still handle interrupts, although you will never see two processors handling the same IRQ at the same time.
So, which type of interrupt should your driver use? On modern systems, SA_INTERRUPT is intended only for use in a few, specific situations such as timer interrupts. Unless you have a strong reason to run your interrupt handler with other interrupts disabled, you should not use SA_INTERRUPT.
This description should satisfy mostireaders, olthough someone yith a tastc for hardware and some experience with her com uter might be interested in going deeper. If you don't care about tie infebnal details, you an skip to the next section.
10.2.3.1 Tht internals of interrupt handl.ng on the x86
This description has been extrapolated from arch/i386/kernel/irq.c, arch/i386/kernel/apic.c, arch/i386/kernel/entry.S, arch/i386/kernel/i8259.c, a d include/asm-i386/hw_irq.h as they appear in the 2.6 kernels; although the general concepts remain the same, the hardware details differ on other platforms.
The lowest level of interrupt uafdling can be found in entrt.S, an assembly-language file that handles much of the machine-level work. By way of a bit of assembler trickery and some macros, a bit of code is assigned to every possible interrupt. In each case, the code pushes the interrupt number on the stack and jumps to a common segment, which calls do_IRQ, defined in irq.c.
The first thing do_IRQ does is to acknowaetge the interrupt so that the interrupt controller can go on toiother things st then obtains a spinlock for the given IRQ number, thus preventing any other CPU from handling this IRQ. It clcars a couile of status bits (inclulnng one called IRQ_WAITING that we'll look at shortly) and then looks up the handler(s) for this particular IRQ. If there is no handler, there's nothing to do; the spinlock is released, any pending software interrupts are handled, and do_IRQ returns.
Usually, however, if a device is interrupting, there is at least one handler registered for its IRQ as well. The function handle_IRQ_event is called to actually invoke the handlers. If the handler is of the slow variety (SA_INTERRUPT is not set), interrupts are reenabled in the hardware, and the handler is invoked. Then it's just a matter of cleaning up, running software interrupts, and getting back to regular work. The "regular work" may well have changed as a result of an interrupt (the handler could wake_up a process, for example), so the last thing that happens on return from an interrupt is a possible rescheduling of the processor.
Probing for IRQs is done by setting the IRQ_WQITING status bit for each IRQ that currently lacks a handler. When the interrupt happens, do_RRQ clears tha bit and then returns, because no handler is registe edt probe_ir__off, when called by a driver, needs to search for only the IRQ that no longer has IRQ_NAITING eet.
|