throbber
,ch10.10847 Page 258 Friday, January 21, 2005 10:54 AM
`
`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

This document is available on Docket Alarm but you must sign up to view it.


Or .

Accessing this document will incur an additional charge of $.

After purchase, you can access this document again without charge.

Accept $ Charge
throbber

Still Working On It

This document is taking longer than usual to download. This can happen if we need to contact the court directly to obtain the document and their servers are running slowly.

Give it another minute or two to complete, and then try the refresh button.

throbber

A few More Minutes ... Still Working

It can take up to 5 minutes for us to download a document if the court servers are running slowly.

Thank you for your continued patience.

This document could not be displayed.

We could not find this document within its docket. Please go back to the docket page and check the link. If that does not work, go back to the docket and refresh it to pull the newest information.

Your account does not support viewing this document.

You need a Paid Account to view this document. Click here to change your account type.

Your account does not support viewing this document.

Set your membership status to view this document.

With a Docket Alarm membership, you'll get a whole lot more, including:

  • Up-to-date information for this case.
  • Email alerts whenever there is an update.
  • Full text search for other cases.
  • Get email alerts whenever a new case matches your search.

Become a Member

One Moment Please

The filing “” is large (MB) and is being downloaded.

Please refresh this page in a few minutes to see if the filing has been downloaded. The filing will also be emailed to you when the download completes.

Your document is on its way!

If you do not receive the document in five minutes, contact support at support@docketalarm.com.

Sealed Document

We are unable to display this document, it may be under a court ordered seal.

If you have proper credentials to access the file, you may proceed directly to the court's system using your government issued username and password.


Access Government Site

We are redirecting you
to a mobile optimized page.





Document Unreadable or Corrupt

Refresh this Document
Go to the Docket

We are unable to display this document.

Refresh this Document
Go to the Docket