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


Reply via email to