Chapter 14: Kernel Activities
*/
if (unlikely((desc->status &
(IRQ_PENDING | IRQ_MASKED | IRQ_DISABLED)) ==
(IRQ_PENDING | IRQ_MASKED))) {
desc->chip->unmask(irq);
desc->status &= ~IRQ_MASKED;
}
desc->status &= ~IRQ_PENDING;
action_ret = handle_IRQ_event(irq, action);
} while ((desc->status & (IRQ_PENDING | IRQ_DISABLED)) == IRQ_PENDING);
Processing the IRQ runs in a loop. Suppose we are at the point right beneath the call to
handle_IRQ_event. While the ISR handlers for the firstIRQ were running, a second IRQ could
have appeared as shown before. This is indicated byIRQ_PENDING. If the flag is set (and the IRQ has not
been disabled in the meantime), another IRQ is waiting to be processed, and the loop is started again
from the beginning.
In this case, however, the IRQ will have beenmasked. The IRQ must thus be unmasked with
chip->unmaskand theIRQ_MASKEDflag be removed. This guarantees that only one interrupt can occur
during the execution ofhandle_IRQ_event.
After removing theIRQ_PENDINGflag — technically, one IRQ is still pending right now, but it is going to
be processed immediately —handle_IRQ_eventcan also serve the second IRQ.
Level-Triggered Interrupts
Level-triggered interrupts are alittle easier to process than their edge-triggered relatives. This is
also reflected in the code flow diagram of the flow handlerhandle_level_irq, which is depicted in
Figure 14-6.
Abort processing
No ISR registered or IRQ disabled? Abort processing
Set IRQ_INPROGRESS
Remove IRQ_INPROGRESS
Irq not disabled? chip->unmask
handle_level_irq
mask_ack_irq
IRQ_INPROGRESS?
handle_IRQ_event
Figure 14-6: Code flow diagram forhandle_level_irq.
Note that level-triggered interrupts must be masked when they are processed, so the first thing that
needstobedoneistocallmask_ack_irq. This auxiliary function masks and acknowledges the IRQ by