From 22471b8a0f1262192fb3698bd2ea1080d9176e6a Mon Sep 17 00:00:00 2001 From: Dmitry Osipenko Date: Mon, 24 Oct 2016 16:26:51 +0100 Subject: [PATCH] hw/ptimer: Add "no immediate trigger" policy Performing trigger on setting (or starting to run with) counter = 0 could be a wrong behaviour for some of the timers, provide "no immediate trigger" policy to maintain correct behaviour for such timers. Signed-off-by: Dmitry Osipenko Message-id: 72c0319cf2ec599f22397b7da280c06c34dc40dd.1475421224.git.digetx@gmail.com Reviewed-by: Peter Maydell Signed-off-by: Peter Maydell --- hw/core/ptimer.c | 20 ++++++++++++++++---- include/hw/ptimer.h | 4 ++++ 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/hw/core/ptimer.c b/hw/core/ptimer.c index 1aa019447f..ed3fb6c66d 100644 --- a/hw/core/ptimer.c +++ b/hw/core/ptimer.c @@ -13,7 +13,8 @@ #include "sysemu/replay.h" #include "sysemu/qtest.h" -#define DELTA_ADJUST 1 +#define DELTA_ADJUST 1 +#define DELTA_NO_ADJUST -1 struct ptimer_state { @@ -43,8 +44,11 @@ static void ptimer_reload(ptimer_state *s, int delta_adjust) uint64_t period = s->period; uint64_t delta = s->delta; - if (delta == 0) { + if (delta == 0 && !(s->policy_mask & PTIMER_POLICY_NO_IMMEDIATE_TRIGGER)) { ptimer_trigger(s); + } + + if (delta == 0) { delta = s->delta = s->limit; } @@ -58,7 +62,9 @@ static void ptimer_reload(ptimer_state *s, int delta_adjust) } if (s->policy_mask & PTIMER_POLICY_WRAP_AFTER_ONE_PERIOD) { - delta += delta_adjust; + if (delta_adjust != DELTA_NO_ADJUST) { + delta += delta_adjust; + } } if (delta == 0 && (s->policy_mask & PTIMER_POLICY_CONTINUOUS_TRIGGER)) { @@ -67,6 +73,12 @@ static void ptimer_reload(ptimer_state *s, int delta_adjust) } } + if (delta == 0 && (s->policy_mask & PTIMER_POLICY_NO_IMMEDIATE_TRIGGER)) { + if (delta_adjust != DELTA_NO_ADJUST) { + delta = 1; + } + } + if (delta == 0) { if (!qtest_enabled()) { fprintf(stderr, "Timer with delta zero, disabling\n"); @@ -111,7 +123,7 @@ static void ptimer_tick(void *opaque) if (s->limit == 0) { /* If a "continuous trigger" policy is not used and limit == 0, we should error out. */ - delta_adjust = 0; + delta_adjust = DELTA_NO_ADJUST; } ptimer_reload(s, delta_adjust); diff --git a/include/hw/ptimer.h b/include/hw/ptimer.h index b2fb4f9864..911cc11bac 100644 --- a/include/hw/ptimer.h +++ b/include/hw/ptimer.h @@ -43,6 +43,10 @@ * re-trigger every period. */ #define PTIMER_POLICY_CONTINUOUS_TRIGGER (1 << 1) +/* Starting to run with/setting counter to "0" won't trigger immediately, + * but after a one period for both oneshot and periodic modes. */ +#define PTIMER_POLICY_NO_IMMEDIATE_TRIGGER (1 << 2) + /* ptimer.c */ typedef struct ptimer_state ptimer_state; typedef void (*ptimer_cb)(void *opaque);