Concept of Shared IRQs in linux

In this post, i am gonna talk about the shared IRQ and how Linux kernel handle shared IRQs.

As wikipedia states “In a computer, an interrupt request (or IRQ) is a hardware signal sent to the processor that temporarily stops a running program and allows a special program, an interrupt handler, to run instead”.

In any embedded system, When a device needs the CPU it sends a request to the CPU. When the CPU gets this request it stops everything what it is doing (and save in memory where the CPU left for the task it was doing) and then it serve the device that sent the request. After serving the device, it gets the work what it was doing from cache/HDD and carry on what it was doing before that interrupt was sent. This request is known as IRQ (interrupt request). So, interrupts are interruptions of a program caused by hardware, when it needs an attention from CPU.

There are limited Interrupts lines(pins) are available on every SoC. Idealistically, one IRQ line can only serve one device. It menace that number of device that can communicate with the processor is equal to the number of IRQ lines available on processor. Which is not enough as per the modern embedded device complexity. As a solution of this situation, modern hardware,  has been designed to allow the sharing of interrupt line among couple of device. Its a responsibility of a software developer to enable/disable appropriate hardware for interrupt on shared line and maintain the list of IRQs for shared line. On the arrival of interrupt on shared line, appropriate ISR from list should gets called to server the device.

Here as a part of this post we will going to explore how shared IRQ can registered and used with Linux kernel.

request _irq() is the function, which is used to request and register normal IRQ with Linux kernel. The same function is used to registered shared IRQ. The difference is SA_SHIRQ bit must be specified in the flags argument when requesting shared interrupt. On the registration of shared IRQ kernel checks for any other  handler exists for that interrupt and  all of those previously registered also requested interrupt sharing. If it found any other handler for same IRQ number, it then checks dev_id parameter is unique, so that the kernel can differentiate the multiple handlers. So it is very essential that dev_id argument must be unique. The kernel keeps a list of shared handlers associated with the interrupt, and dev_id is used as the signature that differentiates between all handlers. If two drivers were to register same dev_id  as their signature on the same interrupt, things might get mixed up at interrupt occurrence , causing the kernel to oops when an interrupt arrived. When a hardware device raises the interrupts on IRQ line, the kernel invokes every handler registered for that interrupt, passing dev_id, which was used to register the handler via request_irq().

When interrupts occurs on shared IRQ line, kernel invokes each and every interrupt handler registered with it by passing each its own dev_id. Shared IRQ handler should quickly check the dev_id with its own to recognize its interrupts and it should quickly return with return value of IRQ_NONE if own device has not interrupted(dev_id does not match). If dev_id matches ISR should return IRQ_HANDLE so kernel stops calling nest interrupt handler. In addition to this, driver using shared IRQs should not enable or diable IRQ. If it does, things might go wrong for other devices sharing the line; disabling another device’s interrupts for even a short time may create latencies that are problematic for that device.

Be very cautious while playing with shared interrupts !!

cheers 🙂

6 Comments

Filed under interrupts in linux, Shared IRQ

6 responses to “Concept of Shared IRQs in linux

  1. Hi,
    could you elaborate your last two lines-
    “In addition to this, driver using shared IRQs should not enable or diable IRQ. If it does, things might go wrong for other devices sharing the line; disabling another device’s interrupts for even a short time may create latencies that are problematic for that device.”

    is it tell when an interrupt come on shared line best way to serve the interrupt is after receaving interrupt disable interrupt on current CPU and keep enable IRQ line so if any other device send an interrupt on shared IRQ line it will be take care by other CPUS

  2. It menace that suppose the IRQ line is shared between two devices A and B.
    Suppose that device A has generated the interrupt. Corresponding top half in driver which is serving device A is getting called. Now this handler had used disable_irq(int irq), which disable IRQ across all core(cpu). Suddenly, device B has generated the physical interrupt. But IRQ is disable, so IRQ handler serving device B will not get called.
    In this scenario interrupts from device B will be missed.

  3. In addition to this, driver using shared IRQs should not enable or diable IRQ. It menace that it can’t play with enable_irq or disable_irq.
    Which enable/ disable IRQs on all CPUs of SoC.

  4. Kushal

    Hi,
    What happens when two devices sharing interrupt lines generate interrupt at the same time ?? Which one will be serviced first and why ? If one is getting served at one time, another device interrupt will be lost or saved somewhere till first interrupt get processed ?

  5. shah.b

    When any shared IRQ line raise interrupt, the kernel must call all handlers for that interrupt line, to give each a chance to query its associated hardware to see if it needs attention. Driver code is supposed to poll device to find out which one raised the interrupt. It is possible for two different drivers to successfully handle an interrupt within the same pass through the handler list for a given interrupt.

    When your interrupt handler tells the kernel it handled the interrupt, that doesn’t stop the kernel from continuing to call any other handlers registered for that same interrupt.

    I hope it clear your doubt.

Leave a comment