[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Qemu-devel] [PATCH v8 4/4] arm_mptimer: Convert to use ptimer
From: |
Peter Crosthwaite |
Subject: |
Re: [Qemu-devel] [PATCH v8 4/4] arm_mptimer: Convert to use ptimer |
Date: |
Wed, 6 Jan 2016 05:17:44 -0800 |
User-agent: |
Mutt/1.5.21 (2010-09-15) |
On Tue, Jan 05, 2016 at 05:33:29AM +0300, Dmitry Osipenko wrote:
> Current ARM MPTimer implementation uses QEMUTimer for the actual timer,
> this implementation isn't complete and mostly tries to duplicate of what
> generic ptimer is already doing fine.
>
> Conversion to ptimer brings the following benefits and fixes:
> - Simple timer pausing implementation
> - Fixes counter value preservation after stopping the timer
> - Code simplification and reduction
>
> Bump VMSD to version 3, since VMState is changed and is not compatible
> with the previous implementation.
>
> Signed-off-by: Dmitry Osipenko <address@hidden>
> ---
> hw/timer/arm_mptimer.c | 110
> ++++++++++++++++++-----------------------
> include/hw/timer/arm_mptimer.h | 4 +-
> 2 files changed, 49 insertions(+), 65 deletions(-)
>
> diff --git a/hw/timer/arm_mptimer.c b/hw/timer/arm_mptimer.c
> index 3e59c2a..c06da5e 100644
> --- a/hw/timer/arm_mptimer.c
> +++ b/hw/timer/arm_mptimer.c
> @@ -19,8 +19,9 @@
> * with this program; if not, see <http://www.gnu.org/licenses/>.
> */
>
> +#include "hw/ptimer.h"
> #include "hw/timer/arm_mptimer.h"
> -#include "qemu/timer.h"
> +#include "qemu/main-loop.h"
> #include "qom/cpu.h"
>
> /* This device implements the per-cpu private timer and watchdog block
> @@ -47,28 +48,10 @@ static inline uint32_t timerblock_scale(TimerBlock *tb)
> return (((tb->control >> 8) & 0xff) + 1) * 10;
> }
>
> -static void timerblock_reload(TimerBlock *tb, int restart)
> -{
> - if (tb->count == 0) {
> - return;
> - }
> - if (restart) {
> - tb->tick = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
> - }
> - tb->tick += (int64_t)tb->count * timerblock_scale(tb);
> - timer_mod(tb->timer, tb->tick);
> -}
> -
> static void timerblock_tick(void *opaque)
> {
> TimerBlock *tb = (TimerBlock *)opaque;
> tb->status = 1;
> - if (tb->control & 2) {
> - tb->count = tb->load;
> - timerblock_reload(tb, 0);
> - } else {
> - tb->count = 0;
> - }
> timerblock_update_irq(tb);
> }
>
> @@ -76,21 +59,11 @@ static uint64_t timerblock_read(void *opaque, hwaddr addr,
> unsigned size)
> {
> TimerBlock *tb = (TimerBlock *)opaque;
> - int64_t val;
> switch (addr) {
> case 0: /* Load */
> return tb->load;
> case 4: /* Counter. */
> - if (((tb->control & 1) == 0) || (tb->count == 0)) {
> - return 0;
> - }
> - /* Slow and ugly, but hopefully won't happen too often. */
> - val = tb->tick - qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
> - val /= timerblock_scale(tb);
> - if (val < 0) {
> - val = 0;
> - }
> - return val;
> + return ptimer_get_count(tb->timer);
> case 8: /* Control. */
> return tb->control;
> case 12: /* Interrupt status. */
> @@ -100,6 +73,19 @@ static uint64_t timerblock_read(void *opaque, hwaddr addr,
> }
> }
>
> +static void timerblock_run(TimerBlock *tb, uint64_t count, int set_count)
> +{
> + if (set_count) {
> + if (((tb->control & 3) == 3) && (count == 0)) {
Parentheses around == expressions should not be needed.
> + count = tb->load;
> + }
> + ptimer_set_count(tb->timer, count);
> + }
> + if ((tb->control & 1) && (count != 0)) {
This can check against tb->load instead of count to avoid dummy
pass of tb->load to this fn ...
> + ptimer_run(tb->timer, !(tb->control & 2));
> + }
> +}
> +
> static void timerblock_write(void *opaque, hwaddr addr,
> uint64_t value, unsigned size)
> {
> @@ -108,32 +94,34 @@ static void timerblock_write(void *opaque, hwaddr addr,
> switch (addr) {
> case 0: /* Load */
> tb->load = value;
> - /* Fall through. */
> - case 4: /* Counter. */
> - if ((tb->control & 1) && tb->count) {
> - /* Cancel the previous timer. */
> - timer_del(tb->timer);
> + /* Setting load to 0 stops the timer. */
> + if (tb->load == 0) {
> + ptimer_stop(tb->timer);
> }
> - tb->count = value;
> - if (tb->control & 1) {
> - timerblock_reload(tb, 1);
> + ptimer_set_limit(tb->timer, tb->load, 1);
> + timerblock_run(tb, tb->load, 0);
> + break;
> + case 4: /* Counter. */
> + /* Setting counter to 0 stops the one-shot timer. */
> + if (!(tb->control & 2) && (value == 0)) {
> + ptimer_stop(tb->timer);
> }
> + timerblock_run(tb, value, 1);
... then this would just need to be elsed.
> break;
> case 8: /* Control. */
> old = tb->control;
> tb->control = value;
> - if (value & 1) {
> - if ((old & 1) && (tb->count != 0)) {
> - /* Do nothing if timer is ticking right now. */
> - break;
> - }
> - if (tb->control & 2) {
> - tb->count = tb->load;
> - }
> - timerblock_reload(tb, 1);
> - } else if (old & 1) {
> - /* Shutdown the timer. */
> - timer_del(tb->timer);
> + /* Timer mode switch requires ptimer to be stopped. */
Is it worth adding this to ptimer? It seems ptimer can now handle
every other case of running configuration change except this one
case.
> + if ((old & 3) != (tb->control & 3)) {
> + ptimer_stop(tb->timer);
> + }
> + if (!(tb->control & 1)) {
> + break;
> + }
> + ptimer_set_period(tb->timer, timerblock_scale(tb));
> + if ((old & 3) != (tb->control & 3)) {
> + value = ptimer_get_count(tb->timer);
> + timerblock_run(tb, value, 1);
Is this reachable when the load value is still 0?
Following on from the suggested refactor before, I think timerblock_run
should split off the count set to a new helper. Then this is
timerblock_setcount(tb, value);
timerblock_run(tb);
and the boolean arg and dummy pass of tb->load as count are unneeded.
Regards,
Peter
> }
> break;
> case 12: /* Interrupt status. */
> @@ -184,13 +172,12 @@ static const MemoryRegionOps timerblock_ops = {
>
> static void timerblock_reset(TimerBlock *tb)
> {
> - tb->count = 0;
> tb->load = 0;
> tb->control = 0;
> tb->status = 0;
> - tb->tick = 0;
> if (tb->timer) {
> - timer_del(tb->timer);
> + ptimer_stop(tb->timer);
> + ptimer_set_limit(tb->timer, 0, 1);
> }
> }
>
> @@ -235,7 +222,8 @@ static void arm_mptimer_realize(DeviceState *dev, Error
> **errp)
> */
> for (i = 0; i < s->num_cpu; i++) {
> TimerBlock *tb = &s->timerblock[i];
> - tb->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, timerblock_tick, tb);
> + QEMUBH *bh = qemu_bh_new(timerblock_tick, tb);
> + tb->timer = ptimer_init(bh);
> sysbus_init_irq(sbd, &tb->irq);
> memory_region_init_io(&tb->iomem, OBJECT(s), &timerblock_ops, tb,
> "arm_mptimer_timerblock", 0x20);
> @@ -245,26 +233,24 @@ static void arm_mptimer_realize(DeviceState *dev, Error
> **errp)
>
> static const VMStateDescription vmstate_timerblock = {
> .name = "arm_mptimer_timerblock",
> - .version_id = 2,
> - .minimum_version_id = 2,
> + .version_id = 3,
> + .minimum_version_id = 3,
> .fields = (VMStateField[]) {
> - VMSTATE_UINT32(count, TimerBlock),
> VMSTATE_UINT32(load, TimerBlock),
> VMSTATE_UINT32(control, TimerBlock),
> VMSTATE_UINT32(status, TimerBlock),
> - VMSTATE_INT64(tick, TimerBlock),
> - VMSTATE_TIMER_PTR(timer, TimerBlock),
> + VMSTATE_PTIMER(timer, TimerBlock),
> VMSTATE_END_OF_LIST()
> }
> };
>
> static const VMStateDescription vmstate_arm_mptimer = {
> .name = "arm_mptimer",
> - .version_id = 2,
> - .minimum_version_id = 2,
> + .version_id = 3,
> + .minimum_version_id = 3,
> .fields = (VMStateField[]) {
> VMSTATE_STRUCT_VARRAY_UINT32(timerblock, ARMMPTimerState, num_cpu,
> - 2, vmstate_timerblock, TimerBlock),
> + 3, vmstate_timerblock, TimerBlock),
> VMSTATE_END_OF_LIST()
> }
> };
> diff --git a/include/hw/timer/arm_mptimer.h b/include/hw/timer/arm_mptimer.h
> index b34cba0..93db61b 100644
> --- a/include/hw/timer/arm_mptimer.h
> +++ b/include/hw/timer/arm_mptimer.h
> @@ -27,12 +27,10 @@
>
> /* State of a single timer or watchdog block */
> typedef struct {
> - uint32_t count;
> uint32_t load;
> uint32_t control;
> uint32_t status;
> - int64_t tick;
> - QEMUTimer *timer;
> + struct ptimer_state *timer;
> qemu_irq irq;
> MemoryRegion iomem;
> } TimerBlock;
> --
> 2.6.4
>
- Re: [Qemu-devel] [PATCH v8 1/4] hw/ptimer: Fix issues caused by the adjusted timer limit value, (continued)
[Qemu-devel] [PATCH v8 2/4] hw/ptimer: Perform tick and counter wrap around if timer already expired, Dmitry Osipenko, 2016/01/04
[Qemu-devel] [PATCH v8 3/4] hw/ptimer: Update .delta on period/freq change, Dmitry Osipenko, 2016/01/04
[Qemu-devel] [PATCH v8 4/4] arm_mptimer: Convert to use ptimer, Dmitry Osipenko, 2016/01/04
- Re: [Qemu-devel] [PATCH v8 4/4] arm_mptimer: Convert to use ptimer,
Peter Crosthwaite <=