• Helge Deller's avatar
    parisc: Filter out spurious interrupts in PA-RISC irq handler · b1b4e435
    Helge Deller authored
    When detecting a serial port on newer PA-RISC machines (with iosapic) we have a
    long way to go to find the right IRQ line, registering it, then registering the
    serial port and the irq handler for the serial port. During this phase spurious
    interrupts for the serial port may happen which then crashes the kernel because
    the action handler might not have been set up yet.
    
    So, basically it's a race condition between the serial port hardware and the
    CPU which sets up the necessary fields in the irq sructs. The main reason for
    this race is, that we unmask the serial port irqs too early without having set
    up everything properly before (which isn't easily possible because we need the
    IRQ number to register the serial ports).
    
    This patch is a work-around for this problem. It adds checks to the CPU irq
    handler to verify if the IRQ action field has been initialized already. If not,
    we just skip this interrupt (which isn't critical for a serial port at bootup).
    The real fix would probably involve rewriting all PA-RISC specific IRQ code
    (for CPU, IOSAPIC, GSC and EISA) to use IRQ domains with proper parenting of
    the irq chips and proper irq enabling along this line.
    
    This bug has been in the PA-RISC port since the beginning, but the crashes
    happened very rarely with currently used hardware.  But on the latest machine
    which I bought (a C8000 workstation), which uses the fastest CPUs (4 x PA8900,
    1GHz) and which has the largest possible L1 cache size (64MB each), the kernel
    crashed at every boot because of this race. So, without this patch the machine
    would currently be unuseable.
    
    For the record, here is the flow logic:
    1. serial_init_chip() in 8250_gsc.c calls iosapic_serial_irq().
    2. iosapic_serial_irq() calls txn_alloc_irq() to find the irq.
    3. iosapic_serial_irq() calls cpu_claim_irq() to register the CPU irq
    4. cpu_claim_irq() unmasks the CPU irq (which it shouldn't!)
    5. serial_init_chip() then registers the 8250 port.
    Problems:
    - In step 4 the CPU irq shouldn't have been registered yet, but after step 5
    - If serial irq happens between 4 and 5 have finished, the kernel will crash
    Signed-off-by: default avatarHelge Deller <deller@gmx.de>
    b1b4e435
irq.c 15.1 KB