From: Keith Monahan <[email protected]> The LASI interrupt request register (IRR) was latched: set when a source asserted and then never cleared or re-evaluated against the mask, so a masked or dropped request stayed set forever. The parisc core I/O dispatcher reads IRR to find its interrupt source, so the stuck bit was returned on every later interrupt as an "unexpected core I/O interrupt". On an installed HP-UX system an unacknowledged i82596 LAN interrupt latched this way and the flood wedged the boot.
Derive IRR as (pending & unmasked) with IPR tracking each source's level, matching the hardware and the in-tree parisc gsc/lasi driver. Signed-off-by: Keith Monahan <[email protected]> Signed-off-by: Helge Deller <[email protected]> --- hw/misc/lasi.c | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/hw/misc/lasi.c b/hw/misc/lasi.c index e8e1578b75..f0dfd78b4d 100644 --- a/hw/misc/lasi.c +++ b/hw/misc/lasi.c @@ -62,7 +62,15 @@ static MemTxResult lasi_chip_read_with_attrs(void *opaque, hwaddr addr, switch (addr) { case LASI_IRR: - val = s->irr; + /* + * The interrupt request register reports the interrupts that are both + * pending and unmasked, derived live from IPR and IMR rather than + * latched, so masking or deasserting a source removes it immediately. + * The parisc core I/O interrupt dispatcher reads IRR; a latched bit + * that never cleared would be redelivered forever as a phantom + * "unexpected" interrupt. + */ + val = s->ipr & s->imr; break; case LASI_IMR: val = s->imr; @@ -234,13 +242,18 @@ static void lasi_set_irq(void *opaque, int irq, int level) if (level) { s->ipr |= bit; - if (bit & s->imr) { + if ((bit & s->imr) && (s->icr & ICR_BUS_ERROR_BIT) == 0) { uint32_t iar = s->iar; - s->irr |= bit; - if ((s->icr & ICR_BUS_ERROR_BIT) == 0) { - stl_be_phys(&address_space_memory, iar & -32, iar & 31); - } + stl_be_phys(&address_space_memory, iar & -32, iar & 31); } + } else { + /* + * The interrupt sources are level triggered, so a source that drops + * its request must clear its pending bit. Otherwise the bit stays set + * in IPR (and hence IRR) and is redelivered as a phantom "unexpected" + * core I/O interrupt on every later interrupt. + */ + s->ipr &= ~bit; } } -- 2.54.0
