From 3f6e6a13c1a059d44b9a55ec7af8c01ef096ff7e Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Mon, 24 Oct 2016 16:26:52 +0100 Subject: [PATCH] hw/ptimer: Add "no immediate reload" policy Immediate counter re-load on setting (or on starting to run with) counter = 0 is a wrong behaviour for some of the timers. Add "no immediate reload" policy that provides correct behaviour for such timers. Signed-off-by: Dmitry Osipenko Message-id: bf9385cd2550ca451d564fa46007688cee3f3d9d.1475421224.git.digetx@gmail.com Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/core/ptimer.c | 31 ++++++++++++++++++++++++++----- include/hw/ptimer.h | 4 ++++ 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/hw/core/ptimer.c b/hw/core/ptimer.c index ed3fb6c66d..2a69dafca6 100644 --- a/hw/core/ptimer.c +++ b/hw/core/ptimer.c @@ -48,7 +48,7 @@ static void ptimer_reload(ptimer_state *s, int delta_adjust) ptimer_trigger(s); } - if (delta == 0) { + if (delta == 0 && !(s->policy_mask & PTIMER_POLICY_NO_IMMEDIATE_RELOAD)) { delta = s->delta = s->limit; } @@ -79,6 +79,12 @@ static void ptimer_reload(ptimer_state *s, int delta_adjust) } } + if (delta == 0 && (s->policy_mask & PTIMER_POLICY_NO_IMMEDIATE_RELOAD)) { + if (s->enabled == 1 && s->limit != 0) { + delta = 1; + } + } + if (delta == 0) { if (!qtest_enabled()) { fprintf(stderr, "Timer with delta zero, disabling\n"); @@ -113,21 +119,36 @@ static void ptimer_reload(ptimer_state *s, int delta_adjust) static void ptimer_tick(void *opaque) { ptimer_state *s = (ptimer_state *)opaque; - ptimer_trigger(s); - s->delta = 0; + bool trigger = true; + if (s->enabled == 2) { + s->delta = 0; s->enabled = 0; } else { int delta_adjust = DELTA_ADJUST; - if (s->limit == 0) { + if (s->delta == 0 || s->limit == 0) { /* If a "continuous trigger" policy is not used and limit == 0, - we should error out. */ + we should error out. delta == 0 means that this tick is + caused by a "no immediate reload" policy, so it shouldn't + be adjusted. */ delta_adjust = DELTA_NO_ADJUST; } + if (!(s->policy_mask & PTIMER_POLICY_NO_IMMEDIATE_TRIGGER)) { + /* Avoid re-trigger on deferred reload if "no immediate trigger" + policy isn't used. */ + trigger = (delta_adjust == DELTA_ADJUST); + } + + s->delta = s->limit; + ptimer_reload(s, delta_adjust); } + + if (trigger) { + ptimer_trigger(s); + } } uint64_t ptimer_get_count(ptimer_state *s) diff --git a/include/hw/ptimer.h b/include/hw/ptimer.h index 911cc11bac..5455340187 100644 --- a/include/hw/ptimer.h +++ b/include/hw/ptimer.h @@ -47,6 +47,10 @@ * but after a one period for both oneshot and periodic modes. */ #define PTIMER_POLICY_NO_IMMEDIATE_TRIGGER (1 << 2) +/* Starting to run with/setting counter to "0" won't re-load counter + * immediately, but after a one period. */ +#define PTIMER_POLICY_NO_IMMEDIATE_RELOAD (1 << 3) + /* ptimer.c */ typedef struct ptimer_state ptimer_state; typedef void (*ptimer_cb)(void *opaque); -- 2.11.0