aboutsummaryrefslogtreecommitdiff
path: root/hw/intc
diff options
context:
space:
mode:
authorJean-Christophe Dubois <jcd@tribudubois.net>2018-01-10 21:43:27 +0100
committerMark Cave-Ayland <mark.cave-ayland@ilande.co.uk>2018-01-24 19:19:50 +0000
commit05b9ec96c1ae87fa2a61b2dcd62ee1263255c9e5 (patch)
treed78727e7d24381b5c4482e3e7d8687f33f5db205 /hw/intc
parent52483b067cce4a88ffbf8fbeea26de7549d2ad23 (diff)
downloadqemu-05b9ec96c1ae87fa2a61b2dcd62ee1263255c9e5.zip
qemu-05b9ec96c1ae87fa2a61b2dcd62ee1263255c9e5.tar.gz
qemu-05b9ec96c1ae87fa2a61b2dcd62ee1263255c9e5.tar.bz2
sparc/leon3 irqmp: fix IRQ software ack
With the LEON3 IRQ controller IRQs can be acknowledged 2 ways: * Explicitly by software writing to the CLEAR_OFFSET register * Implicitly when the procesor is done running the trap handler attached to the IRQ. The actual IRQMP code only allows the implicit processor triggered IRQ ack. If software write explicitly to the CLEAR_OFFSET register, this will clear the pending bit in the register value but this will not lower the ongoing raised IRQ with the processor. The IRQ will be kept raised to the LEON processor until the related trap handler is run and the processor implicitly ack the interrupt. So with the actual IRQMP code trap handler have to be run even if the software has already done its job by clearing the pending bit. This feature has been tested on another LEON3 simulator (tsim_leon3 from Gaisler) and it turns out that the Qemu implementation is not equivalent to the tsim one. In tsim, if software does clear a pending interrupt before the related interrupt handler is triggered the said interrupt handler will not be called. This patch brings the Qemu IRQMP implementation in line with the tsim implementation by allowing IRQ to be acknowledged by software only. Signed-off-by: Jean-Christophe Dubois <jcd@tribudubois.net> Reviewed-by: Fabien Chouteau <chouteau@adacore.com> Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Diffstat (limited to 'hw/intc')
-rw-r--r--hw/intc/grlib_irqmp.c17
1 files changed, 11 insertions, 6 deletions
diff --git a/hw/intc/grlib_irqmp.c b/hw/intc/grlib_irqmp.c
index 94659ee..d6f9cb3 100644
--- a/hw/intc/grlib_irqmp.c
+++ b/hw/intc/grlib_irqmp.c
@@ -106,6 +106,15 @@ static void grlib_irqmp_check_irqs(IRQMPState *state)
}
}
+static void grlib_irqmp_ack_mask(IRQMPState *state, uint32_t mask)
+{
+ /* Clear registers */
+ state->pending &= ~mask;
+ state->force[0] &= ~mask; /* Only CPU 0 (No SMP support) */
+
+ grlib_irqmp_check_irqs(state);
+}
+
void grlib_irqmp_ack(DeviceState *dev, int intno)
{
IRQMP *irqmp = GRLIB_IRQMP(dev);
@@ -120,11 +129,7 @@ void grlib_irqmp_ack(DeviceState *dev, int intno)
trace_grlib_irqmp_ack(intno);
- /* Clear registers */
- state->pending &= ~mask;
- state->force[0] &= ~mask; /* Only CPU 0 (No SMP support) */
-
- grlib_irqmp_check_irqs(state);
+ grlib_irqmp_ack_mask(state, mask);
}
void grlib_irqmp_set_irq(void *opaque, int irq, int level)
@@ -251,7 +256,7 @@ static void grlib_irqmp_write(void *opaque, hwaddr addr,
case CLEAR_OFFSET:
value &= ~1; /* clean up the value */
- state->pending &= ~value;
+ grlib_irqmp_ack_mask(state, value);
return;
case MP_STATUS_OFFSET: