• Grant Grundler's avatar
    [PARISC] Disable nesting of interrupts · 3f902886
    Grant Grundler authored
    Disable nesting of interrupts - still has holes
    
    The offending sequence starts out like this:
    1) take external interrupt
    2) set_eiem() to only allow TIMER_IRQ; local interrupts still disabled
    3) read the EIRR to get a "list" of pending interrupts
    4) clear EIRR of pending interrupts we intend to handle
    5) call __do_IRQ() to handle IRQ.
    6) handle_IRQ_event() enables local interrupts (I-Bit)
    7) take a timer interrupt
    8) read EIRR to get a new list of pending interrupts
    9) clear EIRR of pending interrupts we just read
    10) handle pending interrupts found in (8)
    11) set_eiem(cpu_eiem) and return
            [ TROUBLE! all enabled CPU IRQs are unmasked. }
    12) handle remaining interrupts pending from (3)
            e.g. call __do_IRQ() -> handle_IRQ_event()..etc
            [ TROUBLE! call to handle_IRQ_event() can now enable *any* IRQ. }
    13) set_eiem(cpu_eiem) and return
    
    The problem is we now get into ugly race conditions with Timer and IPI
    interrupts at this point.  I'm not exactly sure what happens when
    things go wrong (perhaps nest calls to IPI or timer interrupt?).
    But I'm certain it's not good.
    
    This sequence will break sooner if (10) would accidentally leave
    interrupts enabled.
    
    I'm pretty sure the right answer is now to make cpu_eiem
    a per CPU variable since all external interrupts on parisc
    are per CPU. This means we will NOT need to send an IPI to
    every CPU in the system when enabling or disabling an IRQ
    since only one CPU needs to change it's EIEM.
    
    Thanks to James Bottomley for (once again) pointing out the problem.
    Signed-off-by: default avatarGrant Grundler <grundler@parisc-linux.org>
    Signed-off-by: default avatarKyle McMartin <kyle@parisc-linux.org>
    3f902886
irq.c 8.4 KB