Monday, January 18, 2016

How does Linux kernel handles shared IRQs?

Though this topic is discussed in many places and also covered in  Linux Device Drivers, 3rd edition, by Corbet et al. However I would still like to compile the topic in my own way.

The reason is that there are quite confusing things about this topic.


Basics :-

Each IRQ can be viewed via /proc/interrupts so the registered handlers come from the drivers that have invoked request_irq passing in the form:

irqreturn_t (*handler)(int, void *)

If the handler should not handle the particular interrupt it must return the kernel macro IRQ_NONE. Each Interrupt handler can get access to dev_id. Also usually there will be bit set in hardware for interrupts and also one may need to acknowledge the interrupt by clearning a bit in a hardware's memory mapped register. 


The Real Case :-

Notice that there will be multiple drivers registering  a single handler or multiple handlers, that means you have a single interrupt number or interrupt line and you have mapped multiple device drivers to listen to. Note that each device entry in the device tree will have a interrupt number which usually the drivers read while registering the interrupt. The case is like you have multiple device nodes in device tree with the same irq number representing a single interrupt line.


Key Points :-

1. All Interrupt handlers will be serviced.

2.Each driver will be aware of its own interrupts via memory mapped registers hence can easily check whether its his device is the cause of the interrupt or not. Each device virtual memory space is different so there is proper memory restriction already in place.

3.Each dev_id for the driver is unique however this may not be useful to check or differentiate shared interrupt handlers. Hence it wouldn't be correct to solve this problem from dev_id point of view as each irq handler gets the same value whatever by its own drivers.

Hence there is only one way to differentiate is a step(2) as mentioned in the article.

NOTE : Its a usual practice to trigger bottom-halves or any other logic in the IRQ handler only after checking the IRQ status from a memory mapped register. Hence the problem is default solved by a good programmer.


An Example :

Magnetic Card Driver's Interrupt handler:-


  static irqreturn_t timag_irq(int irq, void *dev)
{
            struct timag *mag_dev = dev;
            bool  over_or_under_flow = false;
            unsigned int status, irqclr = 0;

             status = timag_readl(mag_dev, REG_IRQSTATUS);

             if ((status & IRQENB_FIFO_IRQ) )  {
                timag_enable(mag_dev, true);

No comments:

Post a Comment