aboutsummaryrefslogtreecommitdiff
path: root/hw/intc
diff options
context:
space:
mode:
authorAlistair Francis <alistair.francis@wdc.com>2020-11-11 15:13:24 -0800
committerAlistair Francis <alistair.francis@wdc.com>2020-11-13 21:43:48 -0800
commitdeef3d2568a7fbaa62d9bee07708cf3a4dc3ac53 (patch)
tree77551af72cda7c437999ddfe2255447905e33501 /hw/intc
parent3a129aea81f8875d510283ddef35bc614c524892 (diff)
downloadqemu-deef3d2568a7fbaa62d9bee07708cf3a4dc3ac53.zip
qemu-deef3d2568a7fbaa62d9bee07708cf3a4dc3ac53.tar.gz
qemu-deef3d2568a7fbaa62d9bee07708cf3a4dc3ac53.tar.bz2
intc/ibex_plic: Ensure we don't loose interrupts
If an interrupt occurs between when we claim and complete an interrupt we currently drop the interrupt in ibex_plic_irqs_set_pending(). This somewhat matches hardware that also ignore the interrupt between the claim and complete process. In the case of hardware though the physical interrupt line will still be asserted after we have completed the interrupt. This means we will still act on the interrupt after the complete process. In QEMU we don't and instead we drop the interrupt as it is never recorded. This patch changed the behaviour of the Ibex PLIC so that we save all interrupts that occur while we are between claiming and completing an interrupt so that we can act on them after the completition process. This fixes interrupts being dropped when running Tock on OpenTitain in QEMU. Signed-off-by: Alistair Francis <alistair.francis@wdc.com> Message-id: e7bcf98c6925b1e6e7828e7c3f85293a09a65b12.1605136387.git.alistair.francis@wdc.com
Diffstat (limited to 'hw/intc')
-rw-r--r--hw/intc/ibex_plic.c17
1 files changed, 16 insertions, 1 deletions
diff --git a/hw/intc/ibex_plic.c b/hw/intc/ibex_plic.c
index db9e0aa..341c9db 100644
--- a/hw/intc/ibex_plic.c
+++ b/hw/intc/ibex_plic.c
@@ -48,6 +48,7 @@ static void ibex_plic_irqs_set_pending(IbexPlicState *s, int irq, bool level)
* The interrupt has been claimed, but not completed.
* The pending bit can't be set.
*/
+ s->hidden_pending[pending_num] |= level << (irq % 32);
return;
}
@@ -176,8 +177,21 @@ static void ibex_plic_write(void *opaque, hwaddr addr,
s->claim = 0;
}
if (s->claimed[value / 32] & 1 << (value % 32)) {
+ int pending_num = value / 32;
+
/* This value was already claimed, clear it. */
- s->claimed[value / 32] &= ~(1 << (value % 32));
+ s->claimed[pending_num] &= ~(1 << (value % 32));
+
+ if (s->hidden_pending[pending_num] & (1 << (value % 32))) {
+ /*
+ * If the bit in hidden_pending is set then that means we
+ * received an interrupt between claiming and completing
+ * the interrupt that hasn't since been de-asserted.
+ * On hardware this would trigger an interrupt, so let's
+ * trigger one here as well.
+ */
+ s->pending[pending_num] |= 1 << (value % 32);
+ }
}
}
@@ -239,6 +253,7 @@ static void ibex_plic_realize(DeviceState *dev, Error **errp)
int i;
s->pending = g_new0(uint32_t, s->pending_num);
+ s->hidden_pending = g_new0(uint32_t, s->pending_num);
s->claimed = g_new0(uint32_t, s->pending_num);
s->source = g_new0(uint32_t, s->source_num);
s->priority = g_new0(uint32_t, s->priority_num);