Interrupt Handling

Chapter 10

An interrupt is simply a signal that the hardware can send when it wants the processor’s attention

The /proc Interface

  • Reported interrupts are shown in /proc/interrupts
    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
  • First column shows IRQ number
  • The last two columns give information on the programmable interrupt controller that handles the interrupt

Installing an Interrupt

  • Must tell kernel to expect an interrupt, if not, it simply acknowledges the interrupt and ignores it
  • int request_threaded_irq(unsigned int irq, irq_handler_t handler, irq_handler_t thread_fn, unsigned long flags, const char *name, void *dev);
  • thread_fn can be NULL if you only need a top half
  • Drivers can share handlers

Top and Bottom Halves

  • Top half runs asynchronously (not in process context) with interrupts disabled
  • It has to make a snap judgement about the interrupt
  • The bottom half is a regular function to be executed later when we have more time
  • interrupts are enabled during execution of the bottom half

Implementing a Handler

  • Can’t transfer data to and from user space. Doesn’t execute in context of a process
  • Can’t sleep
  • First step is often acknowledging the signal from the hardware
  • Might awaken processes sleeping if the interrupt signals an event they are waiting for
  • Should execute in a minimum amount of time
    • Use a bottom half for long computations

Enabling and Disabling Interrupts

  • void {disable_irq, disable_irq_nosync, enable_irq}(int irq);
    • Used to disable a single interrupt
  • void local_irq_save(unsigned long flags);, void local_irq_disable(void);
    • Diable all interrupts
  • void local_irq_restore(unsigned long flags);, void local_irq_enable(void);
    • Restores interrupts

Interrupt Sharing

  • Modern hardware has been designed to allow the sharing of interrupts; PCI bus requires it
  • Linux supports interrupt sharing on all buses

Installing a Shared Handler

  • The SA_SHIRQ bit must be specified in the flags argument when requesting the interrupt
  • The dev_id argument must be unique. Any pointer into the module’s address space will do, but dev_id definitely cannot be set to NULL
  • irq_request succeeds when one of the following is true:
    • The interrupt line is free
    • All handlers already registered for that line have also specified that the IRQ is to be shared

Running the Handler

  • use the dev_id argument to determine which, of possibly many, devices might be interrupting

Handler Arguments and Return Value

  • typedef irqreturn_t (*irq_handler_t)(int irq, void * dev_id);
  • Irq is the interrupt number, dev_id is a short of client data
  • Interrupt handlers should return a value indicating whether there was an actual interrupt to handle
    • IRQ_HANDLED if the IRQ was able to be handled by the top half
    • IRQ_WAKE_THREAD if the bottom half shold be scheduled
    • IRQ_NONE if there was nothing to handle (or IRQ wasn’t from device)

Interrupt Driven I/O

  • Buffer in case of read/write delay
  • Improve performance by handling part of action asynchronously
  • Read:
    • fill buffer from device during interrupt
    • copy to user from buffer on system call
  • Write:
    • copy from user to buffer on system call
    • write from buffer to device on interrupt