`
`CHAPTER 10
`Interrupt Handling
`
`Chapter 10
`
`Although some devices can be controlled using nothing but their I/O regions, most
`real devices are a bit more complicated than that. Devices have to deal with the
`external world, which often includes things such as spinning disks, moving tape,
`wires to distant places, and so on. Much has to be done in a time frame that is differ-
`ent from, and far slower than, that of the processor. Since it is almost always undesir-
`able to have the processor wait on external events, there must be a way for a device
`to let the processor know when something has happened.
`
`That way, of course, is interrupts. An interrupt is simply a signal that the hardware
`can send when it wants the processor’s attention. Linux handles interrupts in much
`the same way that it handles signals in user space. For the most part, a driver need
`only register a handler for its device’s interrupts, and handle them properly when
`they arrive. Of course, underneath that simple picture there is some complexity; in
`particular, interrupt handlers are somewhat limited in the actions they can perform
`as a result of how they are run.
`
`It is difficult to demonstrate the use of interrupts without a real hardware device to
`generate them. Thus, the sample code used in this chapter works with the parallel
`port. Such ports are starting to become scarce on modern hardware, but, with luck,
`most people are still able to get their hands on a system with an available port. We’ll
`be working with the short module from the previous chapter; with some small addi-
`tions it can generate and handle interrupts from the parallel port. The module’s
`name, short, actually means short int (it is C, isn’t it?), to remind us that it handles
`interrupts.
`
`Before we get into the topic, however, it is time for one cautionary note. Interrupt
`handlers, by their nature, run concurrently with other code. Thus, they inevitably
`raise issues of concurrency and contention for data structures and hardware. If you
`succumbed to the temptation to pass over the discussion in Chapter 5, we under-
`stand. But we also recommend that you turn back and have another look now. A
`solid understanding of concurrency control techniques is vital when working with
`interrupts.
`
`258
`
`This is the Title of the Book, eMatter Edition
`Copyright © 2005 O’Reilly & Associates, Inc. All rights reserved.
`
`EX. 2004.001
`
`
`
`,ch10.10847 Page 259 Friday, January 21, 2005 10:54 AM
`
`Preparing the Parallel Port
`Although the parallel interface is simple, it can trigger interrupts. This capability is
`used by the printer to notify the lp driver that it is ready to accept the next character
`in the buffer.
`
`Like most devices, the parallel port doesn’t actually generate interrupts before it’s
`instructed to do so; the parallel standard states that setting bit 4 of port 2 (0x37a,
`0x27a, or whatever) enables interrupt reporting. A simple outb call to set the bit is
`performed by short at module initialization.
`
`Once interrupts are enabled, the parallel interface generates an interrupt whenever
`the electrical signal at pin 10 (the so-called ACK bit) changes from low to high. The
`simplest way to force the interface to generate interrupts (short of hooking up a
`printer to the port) is to connect pins 9 and 10 of the parallel connector. A short
`length of wire inserted into the appropriate holes in the parallel port connector on
`the back of your system creates this connection. The pinout of the parallel port is
`shown in Figure 9-1.
`
`Pin 9 is the most significant bit of the parallel data byte. If you write binary data to
`/dev/short0, you generate several interrupts. Writing ASCII text to the port won’t
`generate any interrupts, though, because the ASCII character set has no entries with
`the top bit set.
`
`If you’d rather avoid wiring pins together, but you do have a printer at hand, you can
`run the sample interrupt handler using a real printer, as shown later. However, note
`that the probing functions we introduce depend on the jumper between pin 9 and 10
`being in place, and you need it to experiment with probing using our code.
`
`Installing an Interrupt Handler
`If you want to actually “see” interrupts being generated, writing to the hardware
`device isn’t enough; a software handler must be configured in the system. If the
`Linux kernel hasn’t been told to expect your interrupt, it simply acknowledges and
`ignores it.
`
`Interrupt lines are a precious and often limited resource, particularly when there are
`only 15 or 16 of them. The kernel keeps a registry of interrupt lines, similar to the
`registry of I/O ports. A module is expected to request an interrupt channel (or IRQ,
`for interrupt request) before using it and to release it when finished. In many situa-
`tions, modules are also expected to be able to share interrupt lines with other driv-
`ers, as we will see. The following functions, declared in <linux/interrupt.h>,
`implement the interrupt registration interface:
`
`int request_irq(unsigned int irq,
` irqreturn_t (*handler)(int, void *, struct pt_regs *),
` unsigned long flags,
`
`This is the Title of the Book, eMatter Edition
`Copyright © 2005 O’Reilly & Associates, Inc. All rights reserved.
`
`Installing an Interrupt Handler
`
`|
`
`259
`
`EX. 2004.002
`
`
`
`,ch10.10847 Page 260 Friday, January 21, 2005 10:54 AM
`
` const char *dev_name,
` void *dev_id);
`
`void free_irq(unsigned int irq, void *dev_id);
`The value returned 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 -EBUSY 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 mask of options (described later) related to interrupt
`management.
`const char *dev_name
`The string passed to request_irq is used in /proc/interrupts 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 the sec-
`tion “Implementing a Handler.”
`
`The bits that can be set in flags 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 sec-
`tion “Fast and Slow Handlers”).
`SA_SHIRQ
`This bit signals that the interrupt can be shared between devices. The concept of
`sharing is outlined in the section “Interrupt Sharing.”
`SA_SAMPLE_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 num-
`bers 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
`
`260
`
`|
`
`Chapter 10:
`
`Interrupt Handling
`
`This is the Title of the Book, eMatter Edition
`Copyright © 2005 O’Reilly & Associates, Inc. All rights reserved.
`
`EX. 2004.003
`
`
`
`,ch10.10847 Page 261 Friday, January 21, 2005 10:54 AM
`
`predictable (for example, vertical blanking of a frame grabber), the flag is not
`worth setting—it 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 handler can be installed either at driver initialization or when the
`device is first opened. Although installing the interrupt handler from within the mod-
`ule’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 lim-
`ited, 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 pro-
`vider (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 instructed to generate interrupts. The place to call free_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 discussion 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 pro-
`cess to keep the device open. short, therefore, requests the interrupt from within its
`initialization function (short_init) instead of doing it in short_open, as a real device
`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 rele-
`vant to the current discussion. short_base is the base I/O address of the parallel inter-
`face being used; register 2 of the interface is written to enable interrupt reporting.
`
`if (short_irq >= 0) {
` result = request_irq(short_irq, short_interrupt,
` SA_INTERRUPT, "short", NULL);
` if (result) {
` printk(KERN_INFO "short: can't get assigned irq %i\n",
` short_irq);
`
`This is the Title of the Book, eMatter Edition
`Copyright © 2005 O’Reilly & Associates, Inc. All rights reserved.
`
`Installing an Interrupt Handler
`
`|
`
`261
`
`EX. 2004.004
`
`
`
`,ch10.10847 Page 262 Friday, January 21, 2005 10:54 AM
`
` short_irq = -1;
` }
` else { /* actually enable it -- assume this *is* a parallel port */
` outb(0x10,short_base+2);
` }
`}
`The code shows that the handler being installed is a fast handler (SA_INTERRUPT),
`doesn’t support interrupt sharing (SA_SHIRQ is missing), and doesn’t contribute to
`system entropy (SA_SAMPLE_RANDOM is missing, too). The outb call then enables inter-
`rupt reporting for the parallel port.
`
`For what it’s worth, the i386 and x86_64 architectures define a function for query-
`ing the availability of an interrupt line:
`
`int can_request_irq(unsigned int irq, unsigned long flags);
`This function returns a nonzero value if an attempt to allocate the given interrupt suc-
`ceeds. Note, however, that things can always change between calls to can_request_irq
`and request_irq.
`
`The /proc Interface
`Whenever a hardware interrupt reaches the processor, an internal counter is incre-
`mented, providing a way to check whether the device is working as expected.
`Reported interrupts are shown in /proc/interrupts. The following snapshot was taken
`on a two-processor Pentium system:
`
`root@montalcino:/bike/corbet/write/ldd3/src/short# m /proc/interrupts
` CPU0 CPU1
` 0: 4848108 34 IO-APIC-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/interrupts 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
`
`262
`
`|
`
`Chapter 10:
`
`Interrupt Handling
`
`This is the Title of the Book, eMatter Edition
`Copyright © 2005 O’Reilly & Associates, Inc. All rights reserved.
`
`EX. 2004.005
`
`
`
`,ch10.10847 Page 263 Friday, January 21, 2005 10:54 AM
`
`interrupts on the first CPU as a way of maximizing cache locality.* The last two col-
`umns give information on the programmable interrupt controller that handles the inter-
`rupt (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_name
`argument to request_irq).
`
`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 low-level statistics about system activity, including (but not limited to) the
`number of interrupts received since system boot. Each line of stat begins with a text
`string that is the key to the line; the intr mark is what we are looking for. The fol-
`lowing (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 number is the total of all interrupts, while each of the others 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 currently installed. If the driver you’re
`testing acquires and releases the interrupt at each open and close cycle, you may find
`/proc/stat more useful than /proc/interrupts.
`
`Another difference between the two files is that interrupts is not architecture depen-
`dent (except, perhaps, for a couple of lines at the end), whereas stat is; the number of
`fields depends on the hardware underlying the kernel. The number of available inter-
`rupts 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 include/
`asm-i386/irq.h, depends on Linux using the architectural limit instead of an imple-
`mentation-specific limit (such as the 16 interrupt sources of the old-fashioned PC
`interrupt controller).
`
`The following is a snapshot of /proc/interrupts 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: 26722 146 IO-SAPIC-level usb-uhci
` 64: 3 6 IO-SAPIC-edge ide0
` 80: 4 2 IO-SAPIC-edge keyboard
` 89: 0 0 IO-SAPIC-edge PS/2 Mouse
`239: 5606341 5606052 SAPIC timer
`
`* Although, some larger systems explicitly use interrupt balancing schemes to spread the interrupt load across
`the system.
`
`This is the Title of the Book, eMatter Edition
`Copyright © 2005 O’Reilly & Associates, Inc. All rights reserved.
`
`Installing an Interrupt Handler
`
`|
`
`263
`
`EX. 2004.006
`
`
`
`,ch10.10847 Page 264 Friday, January 21, 2005 10:54 AM
`
`254: 67575 52815 SAPIC IPI
`NMI: 0 0
`ERR: 0
`
`Autodetecting the IRQ Number
`One of the most challenging problems for a driver at initialization time can be how
`to determine which IRQ line is going to be used by the device. The driver needs the
`information in order to correctly install the handler. Even though a programmer
`could require the user to specify the interrupt number at load time, this is a bad prac-
`tice, because most of the time the user doesn’t know the number, either because he
`didn’t configure the jumpers or because the device is jumperless. Most users want
`their hardware to “just work” and are not interested in issues like interrupt num-
`bers. So autodetection of the 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 by default with the
`parallel port. The implementation is straightforward, as shown by short itself:
`
`if (short_irq < 0) /* not yet specified: force the default on */
` switch(short_base) {
` case 0x378: short_irq = 7; break;
` case 0x278: short_irq = 2; break;
` case 0x3bc: short_irq = 5; break;
` }
`The code assigns the interrupt number according to the chosen base I/O address,
`while allowing the user to override the default at load time with something like:
`
`insmod ./short.ko irq=x
`short_base defaults to 0x378, so short_irq defaults 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 read-
`ing 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.
`
`264
`
`|
`
`Chapter 10:
`
`Interrupt Handling
`
`This is the Title of the Book, eMatter Edition
`Copyright © 2005 O’Reilly & Associates, Inc. All rights reserved.
`
`EX. 2004.007
`
`
`
`,ch10.10847 Page 265 Friday, January 21, 2005 10:54 AM
`
`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.
`
`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 num-
`ber 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 pre-
`serve the returned bit mask, and pass it to probe_irq_off later. After this call, the
`driver should arrange for its device to generate at least one interrupt.
`int probe_irq_off(unsigned long);
`After the device has requested an interrupt, the driver calls this function, passing
`as its argument 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 inter-
`rupts occurred, 0 is returned (therefore, IRQ 0 can’t be probed for, but no cus-
`tom 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 enable interrupts on the device after the call to
`probe_irq_on 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 short module demonstrates how to use such probing. If you load the module
`with probe=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;
` }
`
`This is the Title of the Book, eMatter Edition
`Copyright © 2005 O’Reilly & Associates, Inc. All rights reserved.
`
`Installing an Interrupt Handler
`
`|
`
`265
`
`EX. 2004.008
`
`
`
`,ch10.10847 Page 266 Friday, January 21, 2005 10:54 AM
`
` /*
` * 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 && count++ < 5);
`if (short_irq < 0)
` printk("short: probe failed %i times, giving up\n", count);
`Note the use of udelay 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 actu-
`ally be delivered.
`
`Probing might be a lengthy task. While this is not true for short, probing a frame
`grabber, for example, requires a delay of at least 20 ms (which is ages for the proces-
`sor), 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 func-
`tion (which is not recommended).
`
`It’s interesting to note that on some platforms (PowerPC, M68k, most MIPS imple-
`mentations, and both SPARC versions) probing is unnecessary, and, therefore, the
`previous functions are just empty placeholders, sometimes called “useless ISA non-
`sense.” On other platforms, probing is implemented only for ISA devices. Anyway,
`most architectures define the functions (even if they are empty) to ease porting exist-
`ing device drivers.
`
`Do-it-yourself probing
`Probing can also be implemented in the driver itself without too much trouble. It is a
`rare driver that must implement its own probing, but seeing how it works gives some
`insight into the process. To that end, the short module performs do-it-yourself detec-
`tion of the IRQ line if it is loaded with probe=2.
`
`The mechanism is the same as the one described earlier: enable all unused inter-
`rupts, then wait and see what happens. We can, however, exploit our knowledge of
`the device. Often a device can be configured to use one IRQ number from a set of
`three or four; probing just those IRQs enables us to detect the right one, without
`having to test for all possible IRQs.
`
`The short implementation assumes that 3, 5, 7, and 9 are the only possible IRQ val-
`ues. These numbers are actually the values that some parallel devices allow you to
`select.
`
`The following code probes by testing all “possible” interrupts and looking at what
`happens. 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.
`
`266
`
`|
`
`Chapter 10:
`
`Interrupt Handling
`
`This is the Title of the Book, eMatter Edition
`Copyright © 2005 O’Reilly & Associates, Inc. All rights reserved.
`
`EX. 2004.009
`
`
`
`,ch10.10847 Page 267 Friday, January 21, 2005 10:54 AM
`
`int trials[ ] = {3, 5, 7, 9, 0};
`int tried[ ] = {0, 0, 0, 0, 0};
`int i, count = 0;
`
`/*
` * 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 (i = 0; trials[i]; i++)
` tried[i] = request_irq(trials[i], short_probing,
` SA_INTERRUPT, "short probe", 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,short_base+2); /* disable */
` udelay(5); /* give it some time */
`
` /* the value has been set by the handler */
` if (short_irq = = 0) { /* none of them? */
` printk(KERN_INFO "short: no irq reported by probe\n");
` }
` /*
` * If more than one line has been activated, the result is
` * negative. We should service the interrupt (but the lpt port
` * doesn't need it) and loop over again. Do it at most 5 times
` */
`} while (short_irq <=0 && count++ < 5);
`
`/* end of loop, uninstall the handler */
`for (i = 0; trials[i]; i++)
` if (tried[i] = = 0)
` free_irq(trials[i], NULL);
`
`if (short_irq < 0)
` printk("short: probe failed %i times, giving up\n", count);
`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 <asm/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 value in short_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)
`{
`
`This is the Title of the Book, eMatter Edition
`Copyright © 2005 O’Reilly & Associates, Inc. All rights reserved.
`
`Installing an Interrupt Handler
`
`|
`
`267
`
`EX. 2004.010
`
`
`
`,ch10.10847 Page 268 Friday, January 21, 2005 10:54 AM
`
` 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.
`
`Fast and Slow Handlers
`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 inter-
`rupts while they were being handled. Otherwise, tasks requiring quick attention
`could be delayed for too long.
`
`In modern kernels, most of the differences between fast and slow interrupts have dis-
`appeared. There remains only one: fast interrupts (those that were requested with
`the SA_INTERRUPT 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 most readers, although someone with a taste for hard-
`ware and some experience with her computer might be interested in going deeper. If
`you don’t care about the internal details, you can skip to the next section.
`
`The internals of interrupt handling 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, and 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 handling can be found in entry.S, an assembly-language
`file that handles much of the machine-level work. By way of a bit of assembler trick-
`ery 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 acknowledge the interrupt so that the interrupt con-
`troller can go on to other things. It then obtains a spinlock for the given IRQ number,
`thus preventing any other CPU from handling this IRQ. It clears a couple of status
`
`268
`
`|
`
`Chapter 10:
`
`Interrupt Handling
`
`This is the Title of the Book, eMatter Edition
`Copyright © 2005 O’Reilly & Associates, Inc. All rights reserved.
`
`EX. 2004.011
`
`
`
`,ch10.10847 Page 269 Friday, January 21, 2005 10:54 AM
`
`bits (including 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 “reg-
`ular 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_WAITING status bit for each IRQ that cur-
`rently lacks a handler. When the interrupt happens, do_IRQ clears that bit and then
`returns, because no handler is registered. probe_irq_off, when called by a driver,
`needs to search for only the IRQ that no longer has IRQ_WAITING set.
`
`Implementing a Handler
`So far, we’ve learned to register an interrupt handler but not to write one. Actually,
`there’s nothing unusual about a handler—it’s ordinary C code.
`
`The only peculiarity is that a handler runs at interrupt time and, therefore, suffers
`some restrictions on what it can do. These restrictions are the same as those we saw
`with kernel timers. A handler can’t transfer data to or from user space, because it
`doesn’t execute in the context of a process. Handlers also cannot do anything that
`would sleep, such as calling wait_event, allocating memory with anything other than
`GFP_ATOMIC, or locking a semaphore. Finally, handlers cannot call schedule.
`
`The role of an interrupt handler is to give feedback to its device about interrupt
`reception and to read or write data according to the meaning of the interrupt being
`serviced. The first step usually consists of clearing a bit on the interface board; most
`hardware devices won’t generate other interrupts until their “interrupt-pending” bit
`has been cleared. Depending on how your hardware works, this step may need to be
`performed last instead of first; there is no catch-all rule here. Some devices don’t
`require this step, because they don’t have an “interrupt-pending” bit; such devices
`are a minority, although the parallel port is one of t