Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How shared IRQ races are avoided in Linux

I am considering an upcoming situation in an embedded Linux project (no hardware yet) where two external chips will need to share a single physical IRQ line. This line is capable in hardware of edge triggering but not level triggered interrupts.

Looking at the shared irq support in Linux, I understand that the way this would work with two separate drivers is that each would have their interrupt handler called, check their hardware and handle if appropriate.

However I imagine the following race condition and would like to know if I'm missing something or what might be done to work around this. Let's say there are two external interrupt sources, devices A and B:

  1. device B interrupt occurs, IRQ goes active
  2. IRQ edge causes Linux core interrupt handler to run
  3. ISR for device A runs, finds no interrupt pending
  4. device A interrupt occurs, IRQ stays active (wire-OR)
  5. ISR for device B runs, finds interrupt pending, handles and clears it
  6. core interrupt handler exits
  7. IRQ stays active, no more edges are generated, IRQ is locked up

It seems that for this to be fixed, the core interrupt handler would have to check the IRQ level after running all handlers, and if still active, run them all again. Will Linux do this? I don't think the interrupt core knows how to check the level of an IRQ line.

Is this race something that can actually happen, and if so how do I deal with this?

like image 766
blueshift Avatar asked Jan 11 '12 07:01

blueshift


1 Answers

Basically, with the hardware you've described, doing a wired-or for the interrupts will NEVER work correctly on it's own.

If you want to do wired-or, you really need to be using level-sensitive IRQ inputs. If that's not feasible, then perhaps you can add in some kind of interrupt controller. That device would take N level-sensitive inputs, and have one output, and some kind of 'clear'. When the interrupt controller gets a clear it would lower it's output, then re-assert the output if any of it's inputs were still asserted.

On the software side, you could look at is running the IRQ line to another processor input. This would allow you to at least check the state, but the Linux core ISR handling isn't going to know anything about this, and so you'll have to patch in something to get it to check it and cycle through the ISRs again. Also, this means that in heavy interrupt loading situations you're NEVER going to get out of this ISR. Given that you're doing a wire-or on the IRQs, I'm kind of assuming these devices won't be interrupting too often.

One other thing is to look really hard at the processor. There may be some kind of trick you can pull with the interrupt setup in order to get it to recognize the interrupt again.

I wouldn't try anything too tricky myself, I'd either separate the sources onto separate IRQ inputs, change to a level-sensitive input, or add an interrupt controller chip.

like image 197
Michael Kohne Avatar answered Oct 19 '22 09:10

Michael Kohne