[PATCH 1/2] hw/timer/xilinx_timer: Start on the enable edge
Sebastian Huber <[email protected]>
| Newsgroups | org.nongnu.qemu-devel |
|---|---|
| Message-ID | <[email protected]> |
Every write to a control register which has the enable bit set restarted the count from the load value. A guest which clears the interrupt of a periodic timer writes that register with the enable bit still set, so every period gained the latency of the interrupt. Start the count only where the enable bit goes from zero to one. Signed-off-by: Sebastian Huber <[email protected]> --- hw/timer/xilinx_timer.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/hw/timer/xilinx_timer.c b/hw/timer/xilinx_timer.c index 8a502dae0e..dff439c623 100644 --- a/hw/timer/xilinx_timer.c +++ b/hw/timer/xilinx_timer.c @@ -175,17 +175,25 @@ timer_write(void *opaque, hwaddr addr, addr &= 3; switch (addr) { - case R_TCSR: + case R_TCSR: { + uint32_t old = xt->regs[R_TCSR]; + if (value & TCSR_TINT) value &= ~TCSR_TINT; xt->regs[addr] = value & 0x7ff; - if (value & TCSR_ENT) { + /* + * Only a transition of the enable bit to one starts the count. + * A write which leaves the bit set, such as the acknowledge of + * an interrupt, does not restart it. + */ + if ((value & TCSR_ENT) && !(old & TCSR_ENT)) { ptimer_transaction_begin(xt->ptimer); timer_enable(xt); ptimer_transaction_commit(xt->ptimer); } break; + } default: if (addr < ARRAY_SIZE(xt->regs)) -- 2.51.0