John
John

Reputation: 3520

Linux IRQ: unmasking IRQ within ISR

I have an IRQ which is using handle_level_irq(). Most of the time, the ISR requires that a bottom half be scheduled, but occasionally, it is able to determine it is spurious, and does not want to schedule a bottom half (for performance reasons). The problem is, in the latter case, there is a race condition. If the ISR determines it is spurious, it will unmask the interrupt and prepare to exit (note -- the ISR is not protected by desc->lock at this point). But then, the interrupt is triggered on the second CPU, which, according to handle_level_irq(), grabs desc->lock, masks the IRQ, determines the ISR is in progress on the first CPU, so it unlocks desc->lock and exits. The original ISR on the first CPU would also then exit, leaving the interrupt masked for all time.

I'd like to be able to NOT schedule the bottom half unless I need to, so is there some way for the ISR to unmask itself while avoiding the above race condition?

Upvotes: 0

Views: 825

Answers (1)

artless-noise-bye-due2AI
artless-noise-bye-due2AI

Reputation: 22395

The issue is the IRQ is level trigger and you have a spurious value. How is a level value suppose to resolve itself if it is receiving a spurious interrupt? Ie, by nature of the spurious, the interrupt is currently at the active level. This is why Linux is masking interrupts to prevent deadlock of the CPU with spurious interrupts.

You could change the interrupt level to edge triggered and on the next edge change back to level triggered. This will dismiss the spurious level until the hardware de-asserts it. When the hardware re-asserts the interrupt, an edge will happen and at this point level triggering can be re-installed.

For this reason, most peripherals are edge triggered unless the interrupt line is shared. This issue may be in your interrupt controller and not the handle_level_irq() code. You haven't given a version or supplied the driver you use.

If the line is not shared and your controller supports edge triggering, I would convert your code to use the edge. See more at Wikipedia.

Upvotes: 0

Related Questions