[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-arm] [PATCH v15 06/15] hw/ptimer: Add "wraparound after one period
From: |
Dmitry Osipenko |
Subject: |
[Qemu-arm] [PATCH v15 06/15] hw/ptimer: Add "wraparound after one period" policy |
Date: |
Thu, 21 Jul 2016 17:31:17 +0300 |
Currently, periodic counter wraps around immediately once counter reaches
"0", this is wrong behaviour for some of the timers, resulting in one period
being lost. Add new ptimer policy that provides correct behaviour for such
timers, so that counter stays with "0" for a one period before wrapping
around.
Signed-off-by: Dmitry Osipenko <address@hidden>
---
hw/core/ptimer.c | 43 ++++++++++++++++++++++++++++---------------
include/hw/ptimer.h | 3 +++
2 files changed, 31 insertions(+), 15 deletions(-)
diff --git a/hw/core/ptimer.c b/hw/core/ptimer.c
index 87af293..c697c08 100644
--- a/hw/core/ptimer.c
+++ b/hw/core/ptimer.c
@@ -34,22 +34,27 @@ static void ptimer_trigger(ptimer_state *s)
}
}
-static void ptimer_reload(ptimer_state *s)
+static void ptimer_reload(ptimer_state *s, int delta_adjust)
{
uint32_t period_frac = s->period_frac;
uint64_t period = s->period;
+ uint64_t delta = s->delta;
- if (s->delta == 0) {
+ if (delta == 0) {
ptimer_trigger(s);
- s->delta = s->limit;
+ delta = s->delta = s->limit;
}
- if (s->delta == 0 || s->period == 0) {
+ if (delta == 0 || s->period == 0) {
fprintf(stderr, "Timer with period zero, disabling\n");
timer_del(s->timer);
s->enabled = 0;
return;
}
+ if (s->policy_mask & PTIMER_POLICY_WRAP_AFTER_ONE_PERIOD) {
+ delta += delta_adjust;
+ }
+
/*
* Artificially limit timeout rate to something
* achievable under QEMU. Otherwise, QEMU spends all
@@ -59,15 +64,15 @@ static void ptimer_reload(ptimer_state *s)
* on the current generation of host machines.
*/
- if (s->enabled == 1 && (s->delta * period < 10000) && !use_icount) {
- period = 10000 / s->delta;
+ if (s->enabled == 1 && (delta * period < 10000) && !use_icount) {
+ period = 10000 / delta;
period_frac = 0;
}
s->last_event = s->next_event;
- s->next_event = s->last_event + s->delta * period;
+ s->next_event = s->last_event + delta * period;
if (period_frac) {
- s->next_event += ((int64_t)period_frac * s->delta) >> 32;
+ s->next_event += ((int64_t)period_frac * delta) >> 32;
}
timer_mod(s->timer, s->next_event);
}
@@ -80,7 +85,7 @@ static void ptimer_tick(void *opaque)
if (s->enabled == 2) {
s->enabled = 0;
} else {
- ptimer_reload(s);
+ ptimer_reload(s, 1);
}
}
@@ -88,7 +93,7 @@ uint64_t ptimer_get_count(ptimer_state *s)
{
uint64_t counter;
- if (s->enabled) {
+ if (s->enabled && s->delta != 0) {
int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
int64_t next = s->next_event;
int64_t last = s->last_event;
@@ -145,6 +150,14 @@ uint64_t ptimer_get_count(ptimer_state *s)
div += 1;
}
counter = rem / div + 1;
+
+ if (!oneshot && s->delta == s->limit) {
+ /* Before wrapping around, timer should stay with counter = 0
+ for a one period. The delta has been adjusted by +1 for
+ the wrapped around counter, so taking a modulo of limit + 1
+ gives that period. */
+ counter %= s->limit + 1;
+ }
}
} else {
counter = s->delta;
@@ -157,7 +170,7 @@ void ptimer_set_count(ptimer_state *s, uint64_t count)
s->delta = count;
if (s->enabled) {
s->next_event = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- ptimer_reload(s);
+ ptimer_reload(s, 0);
}
}
@@ -172,7 +185,7 @@ void ptimer_run(ptimer_state *s, int oneshot)
s->enabled = oneshot ? 2 : 1;
if (was_disabled) {
s->next_event = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- ptimer_reload(s);
+ ptimer_reload(s, 0);
}
}
@@ -196,7 +209,7 @@ void ptimer_set_period(ptimer_state *s, int64_t period)
s->period_frac = 0;
if (s->enabled) {
s->next_event = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- ptimer_reload(s);
+ ptimer_reload(s, 0);
}
}
@@ -208,7 +221,7 @@ void ptimer_set_freq(ptimer_state *s, uint32_t freq)
s->period_frac = (1000000000ll << 32) / freq;
if (s->enabled) {
s->next_event = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- ptimer_reload(s);
+ ptimer_reload(s, 0);
}
}
@@ -221,7 +234,7 @@ void ptimer_set_limit(ptimer_state *s, uint64_t limit, int
reload)
s->delta = limit;
if (s->enabled && reload) {
s->next_event = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
- ptimer_reload(s);
+ ptimer_reload(s, 0);
}
}
diff --git a/include/hw/ptimer.h b/include/hw/ptimer.h
index 80564ea..e8de48d 100644
--- a/include/hw/ptimer.h
+++ b/include/hw/ptimer.h
@@ -13,6 +13,9 @@
#include "migration/vmstate.h"
#define PTIMER_POLICY_DEFAULT 0
+/* Periodic timer counter stays with "0" for a one period before wrapping
+ * around. */
+#define PTIMER_POLICY_WRAP_AFTER_ONE_PERIOD (1 << 0)
/* ptimer.c */
typedef struct ptimer_state ptimer_state;
--
2.9.2
- [Qemu-arm] [PATCH v15 00/15] PTimer fixes/features and ARM MPTimer conversion, Dmitry Osipenko, 2016/07/21
- [Qemu-arm] [PATCH v15 02/15] hw/ptimer: Fix counter - 1 returned by ptimer_get_count for the active timer, Dmitry Osipenko, 2016/07/21
- [Qemu-arm] [PATCH v15 08/15] hw/ptimer: Add "continuous trigger" policy, Dmitry Osipenko, 2016/07/21
- [Qemu-arm] [PATCH v15 01/15] hw/ptimer: Change ptimer_get_count to return "1" for the expired timer, Dmitry Osipenko, 2016/07/21
- [Qemu-arm] [PATCH v15 03/15] hw/ptimer: Actually stop timer in case of error, Dmitry Osipenko, 2016/07/21
- [Qemu-arm] [PATCH v15 09/15] tests: ptimer: Add tests for "continuous trigger" policy, Dmitry Osipenko, 2016/07/21
- [Qemu-arm] [PATCH v15 06/15] hw/ptimer: Add "wraparound after one period" policy,
Dmitry Osipenko <=
- [Qemu-arm] [PATCH v15 05/15] tests: Add ptimer tests, Dmitry Osipenko, 2016/07/21
- [Qemu-arm] [PATCH v15 10/15] hw/ptimer: Add "no immediate trigger" policy, Dmitry Osipenko, 2016/07/21
- [Qemu-arm] [PATCH v15 12/15] hw/ptimer: Add "no immediate reload" policy, Dmitry Osipenko, 2016/07/21
- [Qemu-arm] [PATCH v15 07/15] tests: ptimer: Add tests for "wraparound after one period" policy, Dmitry Osipenko, 2016/07/21
- [Qemu-arm] [PATCH v15 04/15] hw/ptimer: Introduce timer policy feature, Dmitry Osipenko, 2016/07/21
- [Qemu-arm] [PATCH v15 13/15] tests: ptimer: Add tests for "no immediate reload" policy, Dmitry Osipenko, 2016/07/21
- [Qemu-arm] [PATCH v15 11/15] tests: ptimer: Add tests for "no immediate trigger" policy, Dmitry Osipenko, 2016/07/21
- [Qemu-arm] [PATCH v15 14/15] arm_mptimer: Convert to use ptimer, Dmitry Osipenko, 2016/07/21
- [Qemu-arm] [PATCH v15 15/15] tests: Add tests for the ARM MPTimer, Dmitry Osipenko, 2016/07/21