* [PATCH 0/2] Convert sparc devices to new ptimer API
@ 2019-10-17 13:23 Peter Maydell
2019-10-17 13:23 ` [PATCH 1/2] hw/timer/grlib_gptimer.c: Switch to transaction-based " Peter Maydell
` (2 more replies)
0 siblings, 3 replies; 11+ messages in thread
From: Peter Maydell @ 2019-10-17 13:23 UTC (permalink / raw)
To: qemu-devel; +Cc: KONRAD Frederic, Mark Cave-Ayland, Fabien Chouteau
This patchset converts the devices used by sparc machines to the new
ptimer API.
Currently the ptimer design uses a QEMU bottom-half as its mechanism
for calling back into the device model using the ptimer when the
timer has expired. Unfortunately this design is fatally flawed,
because it means that there is a lag between the ptimer updating its
own state and the device callback function updating device state, and
guest accesses to device registers between the two can return
inconsistent device state. This was reported as a bug in a specific
timer device but it's a problem with the generic ptimer code:
https://bugs.launchpad.net/qemu/+bug/1777777
The updates to the individual ptimer devices are straightforward:
we need to add begin/commit calls around the various places that
modify the ptimer state, and use the new ptimer_init() function
to create the timer.
Testing has been 'make check', and a quick smoke test of a sparc
linux boot image I had lying around, which obviously doesn't
exercise the devices very much, so more specific testing would
be appreciated. I'm happy for these patches to go in via the
sparc tree if you want, or I can collect them up with the other
ptimer-related changes I'm sending for other archs.
thanks
--PMM
Peter Maydell (2):
hw/timer/grlib_gptimer.c: Switch to transaction-based ptimer API
hw/timer/slavio_timer.c: Switch to transaction-based ptimer API
hw/timer/grlib_gptimer.c | 28 ++++++++++++++++++++++++----
hw/timer/slavio_timer.c | 20 ++++++++++++++++----
2 files changed, 40 insertions(+), 8 deletions(-)
--
2.20.1
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH 1/2] hw/timer/grlib_gptimer.c: Switch to transaction-based ptimer API
2019-10-17 13:23 [PATCH 0/2] Convert sparc devices to new ptimer API Peter Maydell
@ 2019-10-17 13:23 ` Peter Maydell
2019-10-17 14:19 ` Richard Henderson
2019-10-17 14:46 ` Philippe Mathieu-Daudé
2019-10-17 13:23 ` [PATCH 2/2] hw/timer/slavio_timer.c: " Peter Maydell
2019-10-20 16:11 ` [PATCH 0/2] Convert sparc devices to new " Mark Cave-Ayland
2 siblings, 2 replies; 11+ messages in thread
From: Peter Maydell @ 2019-10-17 13:23 UTC (permalink / raw)
To: qemu-devel; +Cc: KONRAD Frederic, Mark Cave-Ayland, Fabien Chouteau
Switch the grlib_gptimer code away from bottom-half based ptimers to
the new transaction-based ptimer API. This just requires adding
begin/commit calls around the various places that modify the ptimer
state, and using the new ptimer_init() function to create the timer.
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
hw/timer/grlib_gptimer.c | 28 ++++++++++++++++++++++++----
1 file changed, 24 insertions(+), 4 deletions(-)
diff --git a/hw/timer/grlib_gptimer.c b/hw/timer/grlib_gptimer.c
index bb09268ea14..7a9371c0e30 100644
--- a/hw/timer/grlib_gptimer.c
+++ b/hw/timer/grlib_gptimer.c
@@ -29,7 +29,6 @@
#include "hw/irq.h"
#include "hw/ptimer.h"
#include "hw/qdev-properties.h"
-#include "qemu/main-loop.h"
#include "qemu/module.h"
#include "trace.h"
@@ -63,7 +62,6 @@ typedef struct GPTimer GPTimer;
typedef struct GPTimerUnit GPTimerUnit;
struct GPTimer {
- QEMUBH *bh;
struct ptimer_state *ptimer;
qemu_irq irq;
@@ -93,6 +91,17 @@ struct GPTimerUnit {
uint32_t config;
};
+static void grlib_gptimer_tx_begin(GPTimer *timer)
+{
+ ptimer_transaction_begin(timer->ptimer);
+}
+
+static void grlib_gptimer_tx_commit(GPTimer *timer)
+{
+ ptimer_transaction_commit(timer->ptimer);
+}
+
+/* Must be called within grlib_gptimer_tx_begin/commit block */
static void grlib_gptimer_enable(GPTimer *timer)
{
assert(timer != NULL);
@@ -115,6 +124,7 @@ static void grlib_gptimer_enable(GPTimer *timer)
ptimer_run(timer->ptimer, 1);
}
+/* Must be called within grlib_gptimer_tx_begin/commit block */
static void grlib_gptimer_restart(GPTimer *timer)
{
assert(timer != NULL);
@@ -141,7 +151,9 @@ static void grlib_gptimer_set_scaler(GPTimerUnit *unit, uint32_t scaler)
trace_grlib_gptimer_set_scaler(scaler, value);
for (i = 0; i < unit->nr_timers; i++) {
+ ptimer_transaction_begin(unit->timers[i].ptimer);
ptimer_set_freq(unit->timers[i].ptimer, value);
+ ptimer_transaction_commit(unit->timers[i].ptimer);
}
}
@@ -266,8 +278,10 @@ static void grlib_gptimer_write(void *opaque, hwaddr addr,
switch (timer_addr) {
case COUNTER_OFFSET:
trace_grlib_gptimer_writel(id, addr, value);
+ grlib_gptimer_tx_begin(&unit->timers[id]);
unit->timers[id].counter = value;
grlib_gptimer_enable(&unit->timers[id]);
+ grlib_gptimer_tx_commit(&unit->timers[id]);
return;
case COUNTER_RELOAD_OFFSET:
@@ -291,6 +305,7 @@ static void grlib_gptimer_write(void *opaque, hwaddr addr,
/* gptimer_restart calls gptimer_enable, so if "enable" and "load"
bits are present, we just have to call restart. */
+ grlib_gptimer_tx_begin(&unit->timers[id]);
if (value & GPTIMER_LOAD) {
grlib_gptimer_restart(&unit->timers[id]);
} else if (value & GPTIMER_ENABLE) {
@@ -301,6 +316,7 @@ static void grlib_gptimer_write(void *opaque, hwaddr addr,
value &= ~(GPTIMER_LOAD & GPTIMER_DEBUG_HALT);
unit->timers[id].config = value;
+ grlib_gptimer_tx_commit(&unit->timers[id]);
return;
default:
@@ -344,9 +360,11 @@ static void grlib_gptimer_reset(DeviceState *d)
timer->counter = 0;
timer->reload = 0;
timer->config = 0;
+ ptimer_transaction_begin(timer->ptimer);
ptimer_stop(timer->ptimer);
ptimer_set_count(timer->ptimer, 0);
ptimer_set_freq(timer->ptimer, unit->freq_hz);
+ ptimer_transaction_commit(timer->ptimer);
}
}
@@ -365,14 +383,16 @@ static void grlib_gptimer_realize(DeviceState *dev, Error **errp)
GPTimer *timer = &unit->timers[i];
timer->unit = unit;
- timer->bh = qemu_bh_new(grlib_gptimer_hit, timer);
- timer->ptimer = ptimer_init_with_bh(timer->bh, PTIMER_POLICY_DEFAULT);
+ timer->ptimer = ptimer_init(grlib_gptimer_hit, timer,
+ PTIMER_POLICY_DEFAULT);
timer->id = i;
/* One IRQ line for each timer */
sysbus_init_irq(sbd, &timer->irq);
+ ptimer_transaction_begin(timer->ptimer);
ptimer_set_freq(timer->ptimer, unit->freq_hz);
+ ptimer_transaction_commit(timer->ptimer);
}
memory_region_init_io(&unit->iomem, OBJECT(unit), &grlib_gptimer_ops,
--
2.20.1
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH 2/2] hw/timer/slavio_timer.c: Switch to transaction-based ptimer API
2019-10-17 13:23 [PATCH 0/2] Convert sparc devices to new ptimer API Peter Maydell
2019-10-17 13:23 ` [PATCH 1/2] hw/timer/grlib_gptimer.c: Switch to transaction-based " Peter Maydell
@ 2019-10-17 13:23 ` Peter Maydell
2019-10-17 14:21 ` Richard Henderson
2019-10-17 14:54 ` Philippe Mathieu-Daudé
2019-10-20 16:11 ` [PATCH 0/2] Convert sparc devices to new " Mark Cave-Ayland
2 siblings, 2 replies; 11+ messages in thread
From: Peter Maydell @ 2019-10-17 13:23 UTC (permalink / raw)
To: qemu-devel; +Cc: KONRAD Frederic, Mark Cave-Ayland, Fabien Chouteau
Switch the slavio_timer code away from bottom-half based ptimers to
the new transaction-based ptimer API. This just requires adding
begin/commit calls around the various places that modify the ptimer
state, and using the new ptimer_init() function to create the timer.
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
hw/timer/slavio_timer.c | 20 ++++++++++++++++----
1 file changed, 16 insertions(+), 4 deletions(-)
diff --git a/hw/timer/slavio_timer.c b/hw/timer/slavio_timer.c
index 692d213897d..0e2efe6fe89 100644
--- a/hw/timer/slavio_timer.c
+++ b/hw/timer/slavio_timer.c
@@ -30,7 +30,6 @@
#include "hw/sysbus.h"
#include "migration/vmstate.h"
#include "trace.h"
-#include "qemu/main-loop.h"
#include "qemu/module.h"
/*
@@ -213,6 +212,7 @@ static void slavio_timer_mem_writel(void *opaque, hwaddr addr,
saddr = addr >> 2;
switch (saddr) {
case TIMER_LIMIT:
+ ptimer_transaction_begin(t->timer);
if (slavio_timer_is_user(tc)) {
uint64_t count;
@@ -236,6 +236,7 @@ static void slavio_timer_mem_writel(void *opaque, hwaddr addr,
}
}
}
+ ptimer_transaction_commit(t->timer);
break;
case TIMER_COUNTER:
if (slavio_timer_is_user(tc)) {
@@ -247,7 +248,9 @@ static void slavio_timer_mem_writel(void *opaque, hwaddr addr,
t->reached = 0;
count = ((uint64_t)t->counthigh) << 32 | t->count;
trace_slavio_timer_mem_writel_limit(timer_index, count);
+ ptimer_transaction_begin(t->timer);
ptimer_set_count(t->timer, LIMIT_TO_PERIODS(t->limit - count));
+ ptimer_transaction_commit(t->timer);
} else {
trace_slavio_timer_mem_writel_counter_invalid();
}
@@ -255,13 +258,16 @@ static void slavio_timer_mem_writel(void *opaque, hwaddr addr,
case TIMER_COUNTER_NORST:
// set limit without resetting counter
t->limit = val & TIMER_MAX_COUNT32;
+ ptimer_transaction_begin(t->timer);
if (t->limit == 0) { /* free-run */
ptimer_set_limit(t->timer, LIMIT_TO_PERIODS(TIMER_MAX_COUNT32), 0);
} else {
ptimer_set_limit(t->timer, LIMIT_TO_PERIODS(t->limit), 0);
}
+ ptimer_transaction_commit(t->timer);
break;
case TIMER_STATUS:
+ ptimer_transaction_begin(t->timer);
if (slavio_timer_is_user(tc)) {
// start/stop user counter
if (val & 1) {
@@ -273,6 +279,7 @@ static void slavio_timer_mem_writel(void *opaque, hwaddr addr,
}
}
t->run = val & 1;
+ ptimer_transaction_commit(t->timer);
break;
case TIMER_MODE:
if (timer_index == 0) {
@@ -282,6 +289,7 @@ static void slavio_timer_mem_writel(void *opaque, hwaddr addr,
unsigned int processor = 1 << i;
CPUTimerState *curr_timer = &s->cputimer[i + 1];
+ ptimer_transaction_begin(curr_timer->timer);
// check for a change in timer mode for this processor
if ((val & processor) != (s->cputimer_mode & processor)) {
if (val & processor) { // counter -> user timer
@@ -308,6 +316,7 @@ static void slavio_timer_mem_writel(void *opaque, hwaddr addr,
trace_slavio_timer_mem_writel_mode_counter(timer_index);
}
}
+ ptimer_transaction_commit(curr_timer->timer);
}
} else {
trace_slavio_timer_mem_writel_mode_invalid();
@@ -367,10 +376,12 @@ static void slavio_timer_reset(DeviceState *d)
curr_timer->count = 0;
curr_timer->reached = 0;
if (i <= s->num_cpus) {
+ ptimer_transaction_begin(curr_timer->timer);
ptimer_set_limit(curr_timer->timer,
LIMIT_TO_PERIODS(TIMER_MAX_COUNT32), 1);
ptimer_run(curr_timer->timer, 0);
curr_timer->run = 1;
+ ptimer_transaction_commit(curr_timer->timer);
}
}
s->cputimer_mode = 0;
@@ -380,7 +391,6 @@ static void slavio_timer_init(Object *obj)
{
SLAVIO_TIMERState *s = SLAVIO_TIMER(obj);
SysBusDevice *dev = SYS_BUS_DEVICE(obj);
- QEMUBH *bh;
unsigned int i;
TimerContext *tc;
@@ -392,9 +402,11 @@ static void slavio_timer_init(Object *obj)
tc->s = s;
tc->timer_index = i;
- bh = qemu_bh_new(slavio_timer_irq, tc);
- s->cputimer[i].timer = ptimer_init_with_bh(bh, PTIMER_POLICY_DEFAULT);
+ s->cputimer[i].timer = ptimer_init(slavio_timer_irq, tc,
+ PTIMER_POLICY_DEFAULT);
+ ptimer_transaction_begin(s->cputimer[i].timer);
ptimer_set_period(s->cputimer[i].timer, TIMER_PERIOD);
+ ptimer_transaction_commit(s->cputimer[i].timer);
size = i == 0 ? SYS_TIMER_SIZE : CPU_TIMER_SIZE;
snprintf(timer_name, sizeof(timer_name), "timer-%i", i);
--
2.20.1
^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [PATCH 1/2] hw/timer/grlib_gptimer.c: Switch to transaction-based ptimer API
2019-10-17 13:23 ` [PATCH 1/2] hw/timer/grlib_gptimer.c: Switch to transaction-based " Peter Maydell
@ 2019-10-17 14:19 ` Richard Henderson
2019-10-17 14:46 ` Philippe Mathieu-Daudé
1 sibling, 0 replies; 11+ messages in thread
From: Richard Henderson @ 2019-10-17 14:19 UTC (permalink / raw)
To: Peter Maydell, qemu-devel
Cc: KONRAD Frederic, Mark Cave-Ayland, Fabien Chouteau
On 10/17/19 6:23 AM, Peter Maydell wrote:
> Switch the grlib_gptimer code away from bottom-half based ptimers to
> the new transaction-based ptimer API. This just requires adding
> begin/commit calls around the various places that modify the ptimer
> state, and using the new ptimer_init() function to create the timer.
>
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> ---
> hw/timer/grlib_gptimer.c | 28 ++++++++++++++++++++++++----
> 1 file changed, 24 insertions(+), 4 deletions(-)
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
r~
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH 2/2] hw/timer/slavio_timer.c: Switch to transaction-based ptimer API
2019-10-17 13:23 ` [PATCH 2/2] hw/timer/slavio_timer.c: " Peter Maydell
@ 2019-10-17 14:21 ` Richard Henderson
2019-10-17 14:54 ` Philippe Mathieu-Daudé
1 sibling, 0 replies; 11+ messages in thread
From: Richard Henderson @ 2019-10-17 14:21 UTC (permalink / raw)
To: Peter Maydell, qemu-devel
Cc: KONRAD Frederic, Mark Cave-Ayland, Fabien Chouteau
On 10/17/19 6:23 AM, Peter Maydell wrote:
> Switch the slavio_timer code away from bottom-half based ptimers to
> the new transaction-based ptimer API. This just requires adding
> begin/commit calls around the various places that modify the ptimer
> state, and using the new ptimer_init() function to create the timer.
>
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> ---
> hw/timer/slavio_timer.c | 20 ++++++++++++++++----
> 1 file changed, 16 insertions(+), 4 deletions(-)
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
r~
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH 1/2] hw/timer/grlib_gptimer.c: Switch to transaction-based ptimer API
2019-10-17 13:23 ` [PATCH 1/2] hw/timer/grlib_gptimer.c: Switch to transaction-based " Peter Maydell
2019-10-17 14:19 ` Richard Henderson
@ 2019-10-17 14:46 ` Philippe Mathieu-Daudé
1 sibling, 0 replies; 11+ messages in thread
From: Philippe Mathieu-Daudé @ 2019-10-17 14:46 UTC (permalink / raw)
To: Peter Maydell, qemu-devel
Cc: KONRAD Frederic, Mark Cave-Ayland, Fabien Chouteau
On 10/17/19 3:23 PM, Peter Maydell wrote:
> Switch the grlib_gptimer code away from bottom-half based ptimers to
> the new transaction-based ptimer API. This just requires adding
> begin/commit calls around the various places that modify the ptimer
> state, and using the new ptimer_init() function to create the timer.
>
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> ---
> hw/timer/grlib_gptimer.c | 28 ++++++++++++++++++++++++----
> 1 file changed, 24 insertions(+), 4 deletions(-)
>
> diff --git a/hw/timer/grlib_gptimer.c b/hw/timer/grlib_gptimer.c
> index bb09268ea14..7a9371c0e30 100644
> --- a/hw/timer/grlib_gptimer.c
> +++ b/hw/timer/grlib_gptimer.c
> @@ -29,7 +29,6 @@
> #include "hw/irq.h"
> #include "hw/ptimer.h"
> #include "hw/qdev-properties.h"
> -#include "qemu/main-loop.h"
> #include "qemu/module.h"
>
> #include "trace.h"
> @@ -63,7 +62,6 @@ typedef struct GPTimer GPTimer;
> typedef struct GPTimerUnit GPTimerUnit;
>
> struct GPTimer {
> - QEMUBH *bh;
> struct ptimer_state *ptimer;
>
> qemu_irq irq;
> @@ -93,6 +91,17 @@ struct GPTimerUnit {
> uint32_t config;
> };
>
> +static void grlib_gptimer_tx_begin(GPTimer *timer)
> +{
> + ptimer_transaction_begin(timer->ptimer);
> +}
> +
> +static void grlib_gptimer_tx_commit(GPTimer *timer)
> +{
> + ptimer_transaction_commit(timer->ptimer);
> +}
> +
> +/* Must be called within grlib_gptimer_tx_begin/commit block */
> static void grlib_gptimer_enable(GPTimer *timer)
> {
> assert(timer != NULL);
> @@ -115,6 +124,7 @@ static void grlib_gptimer_enable(GPTimer *timer)
> ptimer_run(timer->ptimer, 1);
> }
>
> +/* Must be called within grlib_gptimer_tx_begin/commit block */
> static void grlib_gptimer_restart(GPTimer *timer)
> {
> assert(timer != NULL);
> @@ -141,7 +151,9 @@ static void grlib_gptimer_set_scaler(GPTimerUnit *unit, uint32_t scaler)
> trace_grlib_gptimer_set_scaler(scaler, value);
>
> for (i = 0; i < unit->nr_timers; i++) {
> + ptimer_transaction_begin(unit->timers[i].ptimer);
> ptimer_set_freq(unit->timers[i].ptimer, value);
> + ptimer_transaction_commit(unit->timers[i].ptimer);
> }
> }
>
> @@ -266,8 +278,10 @@ static void grlib_gptimer_write(void *opaque, hwaddr addr,
> switch (timer_addr) {
> case COUNTER_OFFSET:
> trace_grlib_gptimer_writel(id, addr, value);
> + grlib_gptimer_tx_begin(&unit->timers[id]);
> unit->timers[id].counter = value;
> grlib_gptimer_enable(&unit->timers[id]);
> + grlib_gptimer_tx_commit(&unit->timers[id]);
> return;
>
> case COUNTER_RELOAD_OFFSET:
> @@ -291,6 +305,7 @@ static void grlib_gptimer_write(void *opaque, hwaddr addr,
> /* gptimer_restart calls gptimer_enable, so if "enable" and "load"
> bits are present, we just have to call restart. */
>
> + grlib_gptimer_tx_begin(&unit->timers[id]);
> if (value & GPTIMER_LOAD) {
> grlib_gptimer_restart(&unit->timers[id]);
> } else if (value & GPTIMER_ENABLE) {
> @@ -301,6 +316,7 @@ static void grlib_gptimer_write(void *opaque, hwaddr addr,
> value &= ~(GPTIMER_LOAD & GPTIMER_DEBUG_HALT);
>
> unit->timers[id].config = value;
> + grlib_gptimer_tx_commit(&unit->timers[id]);
> return;
>
> default:
> @@ -344,9 +360,11 @@ static void grlib_gptimer_reset(DeviceState *d)
> timer->counter = 0;
> timer->reload = 0;
> timer->config = 0;
> + ptimer_transaction_begin(timer->ptimer);
> ptimer_stop(timer->ptimer);
> ptimer_set_count(timer->ptimer, 0);
> ptimer_set_freq(timer->ptimer, unit->freq_hz);
> + ptimer_transaction_commit(timer->ptimer);
> }
> }
>
> @@ -365,14 +383,16 @@ static void grlib_gptimer_realize(DeviceState *dev, Error **errp)
> GPTimer *timer = &unit->timers[i];
>
> timer->unit = unit;
> - timer->bh = qemu_bh_new(grlib_gptimer_hit, timer);
> - timer->ptimer = ptimer_init_with_bh(timer->bh, PTIMER_POLICY_DEFAULT);
> + timer->ptimer = ptimer_init(grlib_gptimer_hit, timer,
> + PTIMER_POLICY_DEFAULT);
> timer->id = i;
>
> /* One IRQ line for each timer */
> sysbus_init_irq(sbd, &timer->irq);
>
> + ptimer_transaction_begin(timer->ptimer);
> ptimer_set_freq(timer->ptimer, unit->freq_hz);
> + ptimer_transaction_commit(timer->ptimer);
> }
>
> memory_region_init_io(&unit->iomem, OBJECT(unit), &grlib_gptimer_ops,
>
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH 2/2] hw/timer/slavio_timer.c: Switch to transaction-based ptimer API
2019-10-17 13:23 ` [PATCH 2/2] hw/timer/slavio_timer.c: " Peter Maydell
2019-10-17 14:21 ` Richard Henderson
@ 2019-10-17 14:54 ` Philippe Mathieu-Daudé
2019-10-17 15:00 ` Peter Maydell
1 sibling, 1 reply; 11+ messages in thread
From: Philippe Mathieu-Daudé @ 2019-10-17 14:54 UTC (permalink / raw)
To: Peter Maydell, qemu-devel
Cc: KONRAD Frederic, Mark Cave-Ayland, Fabien Chouteau
Hi Peter,
On 10/17/19 3:23 PM, Peter Maydell wrote:
> Switch the slavio_timer code away from bottom-half based ptimers to
> the new transaction-based ptimer API. This just requires adding
> begin/commit calls around the various places that modify the ptimer
> state, and using the new ptimer_init() function to create the timer.
>
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> ---
> hw/timer/slavio_timer.c | 20 ++++++++++++++++----
> 1 file changed, 16 insertions(+), 4 deletions(-)
>
> diff --git a/hw/timer/slavio_timer.c b/hw/timer/slavio_timer.c
> index 692d213897d..0e2efe6fe89 100644
> --- a/hw/timer/slavio_timer.c
> +++ b/hw/timer/slavio_timer.c
> @@ -30,7 +30,6 @@
> #include "hw/sysbus.h"
> #include "migration/vmstate.h"
> #include "trace.h"
> -#include "qemu/main-loop.h"
> #include "qemu/module.h"
>
> /*
> @@ -213,6 +212,7 @@ static void slavio_timer_mem_writel(void *opaque, hwaddr addr,
> saddr = addr >> 2;
> switch (saddr) {
> case TIMER_LIMIT:
> + ptimer_transaction_begin(t->timer);
> if (slavio_timer_is_user(tc)) {
> uint64_t count;
This part is odd since there is a check on t->timer != NULL later, and
ptimer_transaction_commit() can't take NULL.
This won't happen if you restrict to ptimer_* calls:
-- >8 --
@@ -222,18 +222,22 @@ static void slavio_timer_mem_writel(void *opaque,
hwaddr addr,
t->reached = 0;
count = ((uint64_t)t->counthigh << 32) | t->count;
trace_slavio_timer_mem_writel_limit(timer_index, count);
+ ptimer_transaction_begin(t->timer);
ptimer_set_count(t->timer, LIMIT_TO_PERIODS(t->limit -
count));
+ ptimer_transaction_commit(t->timer);
} else {
// set limit, reset counter
qemu_irq_lower(t->irq);
t->limit = val & TIMER_MAX_COUNT32;
if (t->timer) {
+ ptimer_transaction_begin(t->timer);
if (t->limit == 0) { /* free-run */
ptimer_set_limit(t->timer,
LIMIT_TO_PERIODS(TIMER_MAX_COUNT32), 1);
} else {
ptimer_set_limit(t->timer,
LIMIT_TO_PERIODS(t->limit), 1);
}
+ ptimer_transaction_commit(t->timer);
}
}
break;
---
>
> @@ -236,6 +236,7 @@ static void slavio_timer_mem_writel(void *opaque, hwaddr addr,
> }
> }
> }
> + ptimer_transaction_commit(t->timer);
> break;
> case TIMER_COUNTER:
> if (slavio_timer_is_user(tc)) {
> @@ -247,7 +248,9 @@ static void slavio_timer_mem_writel(void *opaque, hwaddr addr,
> t->reached = 0;
> count = ((uint64_t)t->counthigh) << 32 | t->count;
> trace_slavio_timer_mem_writel_limit(timer_index, count);
> + ptimer_transaction_begin(t->timer);
> ptimer_set_count(t->timer, LIMIT_TO_PERIODS(t->limit - count));
> + ptimer_transaction_commit(t->timer);
> } else {
> trace_slavio_timer_mem_writel_counter_invalid();
> }
> @@ -255,13 +258,16 @@ static void slavio_timer_mem_writel(void *opaque, hwaddr addr,
> case TIMER_COUNTER_NORST:
> // set limit without resetting counter
> t->limit = val & TIMER_MAX_COUNT32;
> + ptimer_transaction_begin(t->timer);
> if (t->limit == 0) { /* free-run */
> ptimer_set_limit(t->timer, LIMIT_TO_PERIODS(TIMER_MAX_COUNT32), 0);
> } else {
> ptimer_set_limit(t->timer, LIMIT_TO_PERIODS(t->limit), 0);
> }
> + ptimer_transaction_commit(t->timer);
> break;
> case TIMER_STATUS:
> + ptimer_transaction_begin(t->timer);
> if (slavio_timer_is_user(tc)) {
I'd move the begin() here.
> // start/stop user counter
> if (val & 1) {
> @@ -273,6 +279,7 @@ static void slavio_timer_mem_writel(void *opaque, hwaddr addr,
> }
> }
> t->run = val & 1;
> + ptimer_transaction_commit(t->timer);
> break;
> case TIMER_MODE:
> if (timer_index == 0) {
> @@ -282,6 +289,7 @@ static void slavio_timer_mem_writel(void *opaque, hwaddr addr,
> unsigned int processor = 1 << i;
> CPUTimerState *curr_timer = &s->cputimer[i + 1];
>
> + ptimer_transaction_begin(curr_timer->timer);
> // check for a change in timer mode for this processor
> if ((val & processor) != (s->cputimer_mode & processor)) {
Ditto, begin() here.
> if (val & processor) { // counter -> user timer
> @@ -308,6 +316,7 @@ static void slavio_timer_mem_writel(void *opaque, hwaddr addr,
> trace_slavio_timer_mem_writel_mode_counter(timer_index);
> }
> }
> + ptimer_transaction_commit(curr_timer->timer);
> }
> } else {
> trace_slavio_timer_mem_writel_mode_invalid();
> @@ -367,10 +376,12 @@ static void slavio_timer_reset(DeviceState *d)
> curr_timer->count = 0;
> curr_timer->reached = 0;
> if (i <= s->num_cpus) {
> + ptimer_transaction_begin(curr_timer->timer);
> ptimer_set_limit(curr_timer->timer,
> LIMIT_TO_PERIODS(TIMER_MAX_COUNT32), 1);
> ptimer_run(curr_timer->timer, 0);
> curr_timer->run = 1;
> + ptimer_transaction_commit(curr_timer->timer);
> }
> }
> s->cputimer_mode = 0;
> @@ -380,7 +391,6 @@ static void slavio_timer_init(Object *obj)
> {
> SLAVIO_TIMERState *s = SLAVIO_TIMER(obj);
> SysBusDevice *dev = SYS_BUS_DEVICE(obj);
> - QEMUBH *bh;
> unsigned int i;
> TimerContext *tc;
>
> @@ -392,9 +402,11 @@ static void slavio_timer_init(Object *obj)
> tc->s = s;
> tc->timer_index = i;
>
> - bh = qemu_bh_new(slavio_timer_irq, tc);
> - s->cputimer[i].timer = ptimer_init_with_bh(bh, PTIMER_POLICY_DEFAULT);
> + s->cputimer[i].timer = ptimer_init(slavio_timer_irq, tc,
> + PTIMER_POLICY_DEFAULT);
> + ptimer_transaction_begin(s->cputimer[i].timer);
> ptimer_set_period(s->cputimer[i].timer, TIMER_PERIOD);
> + ptimer_transaction_commit(s->cputimer[i].timer);
>
> size = i == 0 ? SYS_TIMER_SIZE : CPU_TIMER_SIZE;
> snprintf(timer_name, sizeof(timer_name), "timer-%i", i);
>
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH 2/2] hw/timer/slavio_timer.c: Switch to transaction-based ptimer API
2019-10-17 14:54 ` Philippe Mathieu-Daudé
@ 2019-10-17 15:00 ` Peter Maydell
2019-10-17 15:22 ` Philippe Mathieu-Daudé
0 siblings, 1 reply; 11+ messages in thread
From: Peter Maydell @ 2019-10-17 15:00 UTC (permalink / raw)
To: Philippe Mathieu-Daudé
Cc: KONRAD Frederic, Mark Cave-Ayland, QEMU Developers,
Fabien Chouteau
On Thu, 17 Oct 2019 at 15:54, Philippe Mathieu-Daudé <philmd@redhat.com> wrote:
>
> Hi Peter,
>
> On 10/17/19 3:23 PM, Peter Maydell wrote:
> > Switch the slavio_timer code away from bottom-half based ptimers to
> > the new transaction-based ptimer API. This just requires adding
> > begin/commit calls around the various places that modify the ptimer
> > state, and using the new ptimer_init() function to create the timer.
> >
> > Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
> > ---
> > hw/timer/slavio_timer.c | 20 ++++++++++++++++----
> > 1 file changed, 16 insertions(+), 4 deletions(-)
> >
> > diff --git a/hw/timer/slavio_timer.c b/hw/timer/slavio_timer.c
> > index 692d213897d..0e2efe6fe89 100644
> > --- a/hw/timer/slavio_timer.c
> > +++ b/hw/timer/slavio_timer.c
> > @@ -30,7 +30,6 @@
> > #include "hw/sysbus.h"
> > #include "migration/vmstate.h"
> > #include "trace.h"
> > -#include "qemu/main-loop.h"
> > #include "qemu/module.h"
> >
> > /*
> > @@ -213,6 +212,7 @@ static void slavio_timer_mem_writel(void *opaque, hwaddr addr,
> > saddr = addr >> 2;
> > switch (saddr) {
> > case TIMER_LIMIT:
> > + ptimer_transaction_begin(t->timer);
> > if (slavio_timer_is_user(tc)) {
> > uint64_t count;
>
>
> This part is odd since there is a check on t->timer != NULL later, and
> ptimer_transaction_commit() can't take NULL.
Hmm, I hadn't noticed that. I think the bug is the check
for NULL, though, beacuse the slavio_timer_init() function
always initializes all the timer pointers, so there's
no situation where the pointer can be non-NULL as far
as I can see. So I think I'd rather fix this by removing
the NULL pointer check...
> > @@ -255,13 +258,16 @@ static void slavio_timer_mem_writel(void *opaque, hwaddr addr,
> > case TIMER_COUNTER_NORST:
> > // set limit without resetting counter
> > t->limit = val & TIMER_MAX_COUNT32;
> > + ptimer_transaction_begin(t->timer);
> > if (t->limit == 0) { /* free-run */
> > ptimer_set_limit(t->timer, LIMIT_TO_PERIODS(TIMER_MAX_COUNT32), 0);
> > } else {
> > ptimer_set_limit(t->timer, LIMIT_TO_PERIODS(t->limit), 0);
> > }
> > + ptimer_transaction_commit(t->timer);
> > break;
> > case TIMER_STATUS:
> > + ptimer_transaction_begin(t->timer);
> > if (slavio_timer_is_user(tc)) {
>
> I'd move the begin() here.
This would be awkward because then it won't neatly nest with
the commit call unless you add an extra if() for the
commit or otherwise rearrange/duplicate code...
> > // start/stop user counter
> > if (val & 1) {
> > @@ -273,6 +279,7 @@ static void slavio_timer_mem_writel(void *opaque, hwaddr addr,
> > }
> > }
> > t->run = val & 1;
> > + ptimer_transaction_commit(t->timer);
...because the commit should come after we have finished
updating the timer state (t->run in this case), because
the trigger callback slavio_timer_irq() otherwise sees
inconsistent half-updated state if commit() calls it.
thanks
-- PMM
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH 2/2] hw/timer/slavio_timer.c: Switch to transaction-based ptimer API
2019-10-17 15:00 ` Peter Maydell
@ 2019-10-17 15:22 ` Philippe Mathieu-Daudé
2019-10-17 15:31 ` Peter Maydell
0 siblings, 1 reply; 11+ messages in thread
From: Philippe Mathieu-Daudé @ 2019-10-17 15:22 UTC (permalink / raw)
To: Peter Maydell
Cc: KONRAD Frederic, Mark Cave-Ayland, QEMU Developers,
Fabien Chouteau
On 10/17/19 5:00 PM, Peter Maydell wrote:
> On Thu, 17 Oct 2019 at 15:54, Philippe Mathieu-Daudé <philmd@redhat.com> wrote:
>>
>> Hi Peter,
>>
>> On 10/17/19 3:23 PM, Peter Maydell wrote:
>>> Switch the slavio_timer code away from bottom-half based ptimers to
>>> the new transaction-based ptimer API. This just requires adding
>>> begin/commit calls around the various places that modify the ptimer
>>> state, and using the new ptimer_init() function to create the timer.
>>>
>>> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
>>> ---
>>> hw/timer/slavio_timer.c | 20 ++++++++++++++++----
>>> 1 file changed, 16 insertions(+), 4 deletions(-)
>>>
>>> diff --git a/hw/timer/slavio_timer.c b/hw/timer/slavio_timer.c
>>> index 692d213897d..0e2efe6fe89 100644
>>> --- a/hw/timer/slavio_timer.c
>>> +++ b/hw/timer/slavio_timer.c
>>> @@ -30,7 +30,6 @@
>>> #include "hw/sysbus.h"
>>> #include "migration/vmstate.h"
>>> #include "trace.h"
>>> -#include "qemu/main-loop.h"
>>> #include "qemu/module.h"
>>>
>>> /*
>>> @@ -213,6 +212,7 @@ static void slavio_timer_mem_writel(void *opaque, hwaddr addr,
>>> saddr = addr >> 2;
>>> switch (saddr) {
>>> case TIMER_LIMIT:
>>> + ptimer_transaction_begin(t->timer);
>>> if (slavio_timer_is_user(tc)) {
>>> uint64_t count;
>>
>>
>> This part is odd since there is a check on t->timer != NULL later, and
>> ptimer_transaction_commit() can't take NULL.
>
> Hmm, I hadn't noticed that. I think the bug is the check
> for NULL, though, beacuse the slavio_timer_init() function
> always initializes all the timer pointers, so there's
> no situation where the pointer can be non-NULL as far
> as I can see. So I think I'd rather fix this by removing
> the NULL pointer check...
Yes, you are correct.
>>> @@ -255,13 +258,16 @@ static void slavio_timer_mem_writel(void *opaque, hwaddr addr,
>>> case TIMER_COUNTER_NORST:
>>> // set limit without resetting counter
>>> t->limit = val & TIMER_MAX_COUNT32;
>>> + ptimer_transaction_begin(t->timer);
>>> if (t->limit == 0) { /* free-run */
>>> ptimer_set_limit(t->timer, LIMIT_TO_PERIODS(TIMER_MAX_COUNT32), 0);
>>> } else {
>>> ptimer_set_limit(t->timer, LIMIT_TO_PERIODS(t->limit), 0);
>>> }
>>> + ptimer_transaction_commit(t->timer);
>>> break;
>>> case TIMER_STATUS:
>>> + ptimer_transaction_begin(t->timer);
>>> if (slavio_timer_is_user(tc)) {
>>
>> I'd move the begin() here.
>
> This would be awkward because then it won't neatly nest with
> the commit call unless you add an extra if() for the
> commit or otherwise rearrange/duplicate code...
>
>>> // start/stop user counter
>>> if (val & 1) {
>>> @@ -273,6 +279,7 @@ static void slavio_timer_mem_writel(void *opaque, hwaddr addr,
>>> }
>>> }
>>> t->run = val & 1;
>>> + ptimer_transaction_commit(t->timer);
>
> ...because the commit should come after we have finished
> updating the timer state (t->run in this case), because
> the trigger callback slavio_timer_irq() otherwise sees
> inconsistent half-updated state if commit() calls it.
Oh, slavio_timer_irq() calls slavio_timer_get_out() which accesses the
ptimer... OK I missed that.
Whew we need to be extra cautious with this API...
If possible I'd rather see the patch removing the NULL check previous to
this one, anyway:
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Thanks,
Phil.
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH 2/2] hw/timer/slavio_timer.c: Switch to transaction-based ptimer API
2019-10-17 15:22 ` Philippe Mathieu-Daudé
@ 2019-10-17 15:31 ` Peter Maydell
0 siblings, 0 replies; 11+ messages in thread
From: Peter Maydell @ 2019-10-17 15:31 UTC (permalink / raw)
To: Philippe Mathieu-Daudé
Cc: KONRAD Frederic, Mark Cave-Ayland, QEMU Developers,
Fabien Chouteau
On Thu, 17 Oct 2019 at 16:22, Philippe Mathieu-Daudé <philmd@redhat.com> wrote:
> On 10/17/19 5:00 PM, Peter Maydell wrote:
> > ...because the commit should come after we have finished
> > updating the timer state (t->run in this case), because
> > the trigger callback slavio_timer_irq() otherwise sees
> > inconsistent half-updated state if commit() calls it.
>
> Oh, slavio_timer_irq() calls slavio_timer_get_out() which accesses the
> ptimer... OK I missed that.
>
> Whew we need to be extra cautious with this API...
Yes. If the callback function is a trivial "just update
the interrupt register bit and set an irq line" one, like
about half the ptimer users, then it doesn't matter too
much where the commit call goes, but for those users who
do more complicated work in the timer callback it gets
a little trickier (and I didn't realise this wrinkle until
about halfway through doing the API conversion work).
It doesn't much matter where the begin call goes (an odd
asymmetry), but the commit call is effectively a "voluntarily
yield control to the callback function" and so its placement
can be important.
> If possible I'd rather see the patch removing the NULL check previous to
> this one, anyway:
> Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Thanks; I'll add the NULL-check cleanup in v2. Coverity will
probably complain otherwise.
thanks
-- PMM
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH 0/2] Convert sparc devices to new ptimer API
2019-10-17 13:23 [PATCH 0/2] Convert sparc devices to new ptimer API Peter Maydell
2019-10-17 13:23 ` [PATCH 1/2] hw/timer/grlib_gptimer.c: Switch to transaction-based " Peter Maydell
2019-10-17 13:23 ` [PATCH 2/2] hw/timer/slavio_timer.c: " Peter Maydell
@ 2019-10-20 16:11 ` Mark Cave-Ayland
2 siblings, 0 replies; 11+ messages in thread
From: Mark Cave-Ayland @ 2019-10-20 16:11 UTC (permalink / raw)
To: Peter Maydell, qemu-devel; +Cc: KONRAD Frederic, Fabien Chouteau
On 17/10/2019 14:23, Peter Maydell wrote:
> This patchset converts the devices used by sparc machines to the new
> ptimer API.
>
> Currently the ptimer design uses a QEMU bottom-half as its mechanism
> for calling back into the device model using the ptimer when the
> timer has expired. Unfortunately this design is fatally flawed,
> because it means that there is a lag between the ptimer updating its
> own state and the device callback function updating device state, and
> guest accesses to device registers between the two can return
> inconsistent device state. This was reported as a bug in a specific
> timer device but it's a problem with the generic ptimer code:
> https://bugs.launchpad.net/qemu/+bug/1777777
>
> The updates to the individual ptimer devices are straightforward:
> we need to add begin/commit calls around the various places that
> modify the ptimer state, and use the new ptimer_init() function
> to create the timer.
>
> Testing has been 'make check', and a quick smoke test of a sparc
> linux boot image I had lying around, which obviously doesn't
> exercise the devices very much, so more specific testing would
> be appreciated. I'm happy for these patches to go in via the
> sparc tree if you want, or I can collect them up with the other
> ptimer-related changes I'm sending for other archs.
>
> thanks
> --PMM
I've given these patches a spin on my OpenBIOS test images and I don't see any
obvious regressions, so for the sun4m (slavio) part:
Tested-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Frederic, are you able to make sure that the leon3 parts don't cause any problems?
Currently I don't have any outstanding SPARC patches, so if you want to include them
in a ptimer-related PR then that's fine with me.
ATB,
Mark.
^ permalink raw reply [flat|nested] 11+ messages in thread
end of thread, other threads:[~2019-10-20 16:15 UTC | newest]
Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2019-10-17 13:23 [PATCH 0/2] Convert sparc devices to new ptimer API Peter Maydell
2019-10-17 13:23 ` [PATCH 1/2] hw/timer/grlib_gptimer.c: Switch to transaction-based " Peter Maydell
2019-10-17 14:19 ` Richard Henderson
2019-10-17 14:46 ` Philippe Mathieu-Daudé
2019-10-17 13:23 ` [PATCH 2/2] hw/timer/slavio_timer.c: " Peter Maydell
2019-10-17 14:21 ` Richard Henderson
2019-10-17 14:54 ` Philippe Mathieu-Daudé
2019-10-17 15:00 ` Peter Maydell
2019-10-17 15:22 ` Philippe Mathieu-Daudé
2019-10-17 15:31 ` Peter Maydell
2019-10-20 16:11 ` [PATCH 0/2] Convert sparc devices to new " Mark Cave-Ayland
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).