summaryrefslogtreecommitdiffstats
path: root/hw/timer
diff options
context:
space:
mode:
authorPeter Maydell2020-07-27 17:45:50 +0200
committerPeter Maydell2020-08-03 18:56:11 +0200
commit13557fd392890cbd985bceba7f717e01efd674b8 (patch)
treec4d5d792312b99073390774f2a4dd7e6def1e1f7 /hw/timer
parenthw/arm/nrf51_soc: Set system_clock_scale (diff)
downloadqemu-13557fd392890cbd985bceba7f717e01efd674b8.tar.gz
qemu-13557fd392890cbd985bceba7f717e01efd674b8.tar.xz
qemu-13557fd392890cbd985bceba7f717e01efd674b8.zip
hw/timer/imx_epit: Avoid assertion when CR.SWR is written
The imx_epit device has a software-controllable reset triggered by setting the SWR bit in the CR register. An error in commit cc2722ec83ad9 means that we will end up assert()ing if the guest does this, because the code in imx_epit_write() starts ptimer transactions, and then imx_epit_reset() also starts ptimer transactions, triggering "ptimer_transaction_begin: Assertion `!s->in_transaction' failed". The cleanest way to avoid this double-transaction is to move the start-transaction for the CR write handling down below the check of the SWR bit. Fixes: https://bugs.launchpad.net/qemu/+bug/1880424 Fixes: cc2722ec83ad944505fe Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org> Message-id: 20200727154550.3409-1-peter.maydell@linaro.org
Diffstat (limited to 'hw/timer')
-rw-r--r--hw/timer/imx_epit.c13
1 files changed, 10 insertions, 3 deletions
diff --git a/hw/timer/imx_epit.c b/hw/timer/imx_epit.c
index baf6338e1a..ebd58254d1 100644
--- a/hw/timer/imx_epit.c
+++ b/hw/timer/imx_epit.c
@@ -199,15 +199,22 @@ static void imx_epit_write(void *opaque, hwaddr offset, uint64_t value,
switch (offset >> 2) {
case 0: /* CR */
- ptimer_transaction_begin(s->timer_cmp);
- ptimer_transaction_begin(s->timer_reload);
oldcr = s->cr;
s->cr = value & 0x03ffffff;
if (s->cr & CR_SWR) {
/* handle the reset */
imx_epit_reset(DEVICE(s));
- } else {
+ /*
+ * TODO: could we 'break' here? following operations appear
+ * to duplicate the work imx_epit_reset() already did.
+ */
+ }
+
+ ptimer_transaction_begin(s->timer_cmp);
+ ptimer_transaction_begin(s->timer_reload);
+
+ if (!(s->cr & CR_SWR)) {
imx_epit_set_freq(s);
}