From b01422622b7c7293196fdaf1dbb4f495af44ecf9 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 8 Oct 2019 18:17:20 +0100 Subject: ptimer: Rename ptimer_init() to ptimer_init_with_bh() 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. We want to replace the bottom-half design with one where the guest device's callback is called either immediately (when the ptimer triggers by timeout) or when the device model code closes a transaction-begin/end section (when the ptimer triggers because the device model changed the ptimer's count value or other state). As the first step, rename ptimer_init() to ptimer_init_with_bh(), to free up the ptimer_init() name for the new API. We can then convert all the ptimer users away from ptimer_init_with_bh() before removing it entirely. (Commit created with git grep -l ptimer_init | xargs sed -i -e 's/ptimer_init/ptimer_init_with_bh/' and three overlong lines folded by hand.) Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20191008171740.9679-2-peter.maydell@linaro.org --- hw/timer/allwinner-a10-pit.c | 2 +- hw/timer/altera_timer.c | 2 +- hw/timer/arm_mptimer.c | 6 +++--- hw/timer/arm_timer.c | 2 +- hw/timer/cmsdk-apb-dualtimer.c | 2 +- hw/timer/cmsdk-apb-timer.c | 2 +- hw/timer/digic-timer.c | 2 +- hw/timer/etraxfs_timer.c | 6 +++--- hw/timer/exynos4210_mct.c | 7 ++++--- hw/timer/exynos4210_pwm.c | 2 +- hw/timer/exynos4210_rtc.c | 4 ++-- hw/timer/grlib_gptimer.c | 2 +- hw/timer/imx_epit.c | 4 ++-- hw/timer/imx_gpt.c | 2 +- hw/timer/lm32_timer.c | 2 +- hw/timer/milkymist-sysctl.c | 4 ++-- hw/timer/mss-timer.c | 2 +- hw/timer/puv3_ost.c | 2 +- hw/timer/sh_timer.c | 2 +- hw/timer/slavio_timer.c | 2 +- hw/timer/xilinx_timer.c | 2 +- 21 files changed, 31 insertions(+), 30 deletions(-) (limited to 'hw/timer') diff --git a/hw/timer/allwinner-a10-pit.c b/hw/timer/allwinner-a10-pit.c index ca5a905..28d055e 100644 --- a/hw/timer/allwinner-a10-pit.c +++ b/hw/timer/allwinner-a10-pit.c @@ -271,7 +271,7 @@ static void a10_pit_init(Object *obj) tc->container = s; tc->index = i; bh[i] = qemu_bh_new(a10_pit_timer_cb, tc); - s->timer[i] = ptimer_init(bh[i], PTIMER_POLICY_DEFAULT); + s->timer[i] = ptimer_init_with_bh(bh[i], PTIMER_POLICY_DEFAULT); } } diff --git a/hw/timer/altera_timer.c b/hw/timer/altera_timer.c index 936b313..ee32e0e 100644 --- a/hw/timer/altera_timer.c +++ b/hw/timer/altera_timer.c @@ -184,7 +184,7 @@ static void altera_timer_realize(DeviceState *dev, Error **errp) } t->bh = qemu_bh_new(timer_hit, t); - t->ptimer = ptimer_init(t->bh, PTIMER_POLICY_DEFAULT); + t->ptimer = ptimer_init_with_bh(t->bh, PTIMER_POLICY_DEFAULT); ptimer_set_freq(t->ptimer, t->freq_hz); memory_region_init_io(&t->mmio, OBJECT(t), &timer_ops, t, diff --git a/hw/timer/arm_mptimer.c b/hw/timer/arm_mptimer.c index 9f63abe..2a54a01 100644 --- a/hw/timer/arm_mptimer.c +++ b/hw/timer/arm_mptimer.c @@ -228,7 +228,7 @@ static void arm_mptimer_reset(DeviceState *dev) } } -static void arm_mptimer_init(Object *obj) +static void arm_mptimer_init_with_bh(Object *obj) { ARMMPTimerState *s = ARM_MPTIMER(obj); @@ -261,7 +261,7 @@ static void arm_mptimer_realize(DeviceState *dev, Error **errp) for (i = 0; i < s->num_cpu; i++) { TimerBlock *tb = &s->timerblock[i]; QEMUBH *bh = qemu_bh_new(timerblock_tick, tb); - tb->timer = ptimer_init(bh, PTIMER_POLICY); + tb->timer = ptimer_init_with_bh(bh, PTIMER_POLICY); sysbus_init_irq(sbd, &tb->irq); memory_region_init_io(&tb->iomem, OBJECT(s), &timerblock_ops, tb, "arm_mptimer_timerblock", 0x20); @@ -311,7 +311,7 @@ static const TypeInfo arm_mptimer_info = { .name = TYPE_ARM_MPTIMER, .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(ARMMPTimerState), - .instance_init = arm_mptimer_init, + .instance_init = arm_mptimer_init_with_bh, .class_init = arm_mptimer_class_init, }; diff --git a/hw/timer/arm_timer.c b/hw/timer/arm_timer.c index c2e6211..dc33ab3 100644 --- a/hw/timer/arm_timer.c +++ b/hw/timer/arm_timer.c @@ -173,7 +173,7 @@ static arm_timer_state *arm_timer_init(uint32_t freq) s->control = TIMER_CTRL_IE; bh = qemu_bh_new(arm_timer_tick, s); - s->timer = ptimer_init(bh, PTIMER_POLICY_DEFAULT); + s->timer = ptimer_init_with_bh(bh, PTIMER_POLICY_DEFAULT); vmstate_register(NULL, -1, &vmstate_arm_timer, s); return s; } diff --git a/hw/timer/cmsdk-apb-dualtimer.c b/hw/timer/cmsdk-apb-dualtimer.c index 5e2352d..44d23c8 100644 --- a/hw/timer/cmsdk-apb-dualtimer.c +++ b/hw/timer/cmsdk-apb-dualtimer.c @@ -453,7 +453,7 @@ static void cmsdk_apb_dualtimer_realize(DeviceState *dev, Error **errp) QEMUBH *bh = qemu_bh_new(cmsdk_dualtimermod_tick, m); m->parent = s; - m->timer = ptimer_init(bh, + m->timer = ptimer_init_with_bh(bh, PTIMER_POLICY_WRAP_AFTER_ONE_PERIOD | PTIMER_POLICY_TRIGGER_ONLY_ON_DECREMENT | PTIMER_POLICY_NO_IMMEDIATE_RELOAD | diff --git a/hw/timer/cmsdk-apb-timer.c b/hw/timer/cmsdk-apb-timer.c index c83e265..c9ce977 100644 --- a/hw/timer/cmsdk-apb-timer.c +++ b/hw/timer/cmsdk-apb-timer.c @@ -218,7 +218,7 @@ static void cmsdk_apb_timer_realize(DeviceState *dev, Error **errp) } bh = qemu_bh_new(cmsdk_apb_timer_tick, s); - s->timer = ptimer_init(bh, + s->timer = ptimer_init_with_bh(bh, PTIMER_POLICY_WRAP_AFTER_ONE_PERIOD | PTIMER_POLICY_TRIGGER_ONLY_ON_DECREMENT | PTIMER_POLICY_NO_IMMEDIATE_RELOAD | diff --git a/hw/timer/digic-timer.c b/hw/timer/digic-timer.c index 021c4ef..b111e1f 100644 --- a/hw/timer/digic-timer.c +++ b/hw/timer/digic-timer.c @@ -129,7 +129,7 @@ static void digic_timer_init(Object *obj) { DigicTimerState *s = DIGIC_TIMER(obj); - s->ptimer = ptimer_init(NULL, PTIMER_POLICY_DEFAULT); + s->ptimer = ptimer_init_with_bh(NULL, PTIMER_POLICY_DEFAULT); /* * FIXME: there is no documentation on Digic timer diff --git a/hw/timer/etraxfs_timer.c b/hw/timer/etraxfs_timer.c index d62025b..ab27fe1 100644 --- a/hw/timer/etraxfs_timer.c +++ b/hw/timer/etraxfs_timer.c @@ -328,9 +328,9 @@ static void etraxfs_timer_realize(DeviceState *dev, Error **errp) t->bh_t0 = qemu_bh_new(timer0_hit, t); t->bh_t1 = qemu_bh_new(timer1_hit, t); t->bh_wd = qemu_bh_new(watchdog_hit, t); - t->ptimer_t0 = ptimer_init(t->bh_t0, PTIMER_POLICY_DEFAULT); - t->ptimer_t1 = ptimer_init(t->bh_t1, PTIMER_POLICY_DEFAULT); - t->ptimer_wd = ptimer_init(t->bh_wd, PTIMER_POLICY_DEFAULT); + t->ptimer_t0 = ptimer_init_with_bh(t->bh_t0, PTIMER_POLICY_DEFAULT); + t->ptimer_t1 = ptimer_init_with_bh(t->bh_t1, PTIMER_POLICY_DEFAULT); + t->ptimer_wd = ptimer_init_with_bh(t->bh_wd, PTIMER_POLICY_DEFAULT); sysbus_init_irq(sbd, &t->irq); sysbus_init_irq(sbd, &t->nmi); diff --git a/hw/timer/exynos4210_mct.c b/hw/timer/exynos4210_mct.c index 77b9af0..9f2e8dd 100644 --- a/hw/timer/exynos4210_mct.c +++ b/hw/timer/exynos4210_mct.c @@ -1429,7 +1429,7 @@ static void exynos4210_mct_init(Object *obj) /* Global timer */ bh[0] = qemu_bh_new(exynos4210_gfrc_event, s); - s->g_timer.ptimer_frc = ptimer_init(bh[0], PTIMER_POLICY_DEFAULT); + s->g_timer.ptimer_frc = ptimer_init_with_bh(bh[0], PTIMER_POLICY_DEFAULT); memset(&s->g_timer.reg, 0, sizeof(struct gregs)); /* Local timers */ @@ -1437,8 +1437,9 @@ static void exynos4210_mct_init(Object *obj) bh[0] = qemu_bh_new(exynos4210_ltick_event, &s->l_timer[i]); bh[1] = qemu_bh_new(exynos4210_lfrc_event, &s->l_timer[i]); s->l_timer[i].tick_timer.ptimer_tick = - ptimer_init(bh[0], PTIMER_POLICY_DEFAULT); - s->l_timer[i].ptimer_frc = ptimer_init(bh[1], PTIMER_POLICY_DEFAULT); + ptimer_init_with_bh(bh[0], PTIMER_POLICY_DEFAULT); + s->l_timer[i].ptimer_frc = + ptimer_init_with_bh(bh[1], PTIMER_POLICY_DEFAULT); s->l_timer[i].id = i; } diff --git a/hw/timer/exynos4210_pwm.c b/hw/timer/exynos4210_pwm.c index b7fad2a..aa5dca6 100644 --- a/hw/timer/exynos4210_pwm.c +++ b/hw/timer/exynos4210_pwm.c @@ -393,7 +393,7 @@ static void exynos4210_pwm_init(Object *obj) for (i = 0; i < EXYNOS4210_PWM_TIMERS_NUM; i++) { bh = qemu_bh_new(exynos4210_pwm_tick, &s->timer[i]); sysbus_init_irq(dev, &s->timer[i].irq); - s->timer[i].ptimer = ptimer_init(bh, PTIMER_POLICY_DEFAULT); + s->timer[i].ptimer = ptimer_init_with_bh(bh, PTIMER_POLICY_DEFAULT); s->timer[i].id = i; s->timer[i].parent = s; } diff --git a/hw/timer/exynos4210_rtc.c b/hw/timer/exynos4210_rtc.c index ea68904..d5d7c91 100644 --- a/hw/timer/exynos4210_rtc.c +++ b/hw/timer/exynos4210_rtc.c @@ -558,12 +558,12 @@ static void exynos4210_rtc_init(Object *obj) QEMUBH *bh; bh = qemu_bh_new(exynos4210_rtc_tick, s); - s->ptimer = ptimer_init(bh, PTIMER_POLICY_DEFAULT); + s->ptimer = ptimer_init_with_bh(bh, PTIMER_POLICY_DEFAULT); ptimer_set_freq(s->ptimer, RTC_BASE_FREQ); exynos4210_rtc_update_freq(s, 0); bh = qemu_bh_new(exynos4210_rtc_1Hz_tick, s); - s->ptimer_1Hz = ptimer_init(bh, PTIMER_POLICY_DEFAULT); + s->ptimer_1Hz = ptimer_init_with_bh(bh, PTIMER_POLICY_DEFAULT); ptimer_set_freq(s->ptimer_1Hz, RTC_BASE_FREQ); sysbus_init_irq(dev, &s->alm_irq); diff --git a/hw/timer/grlib_gptimer.c b/hw/timer/grlib_gptimer.c index 32dbf87..bb09268 100644 --- a/hw/timer/grlib_gptimer.c +++ b/hw/timer/grlib_gptimer.c @@ -366,7 +366,7 @@ static void grlib_gptimer_realize(DeviceState *dev, Error **errp) timer->unit = unit; timer->bh = qemu_bh_new(grlib_gptimer_hit, timer); - timer->ptimer = ptimer_init(timer->bh, PTIMER_POLICY_DEFAULT); + timer->ptimer = ptimer_init_with_bh(timer->bh, PTIMER_POLICY_DEFAULT); timer->id = i; /* One IRQ line for each timer */ diff --git a/hw/timer/imx_epit.c b/hw/timer/imx_epit.c index f54e059..39810ac 100644 --- a/hw/timer/imx_epit.c +++ b/hw/timer/imx_epit.c @@ -317,10 +317,10 @@ static void imx_epit_realize(DeviceState *dev, Error **errp) 0x00001000); sysbus_init_mmio(sbd, &s->iomem); - s->timer_reload = ptimer_init(NULL, PTIMER_POLICY_DEFAULT); + s->timer_reload = ptimer_init_with_bh(NULL, PTIMER_POLICY_DEFAULT); bh = qemu_bh_new(imx_epit_cmp, s); - s->timer_cmp = ptimer_init(bh, PTIMER_POLICY_DEFAULT); + s->timer_cmp = ptimer_init_with_bh(bh, PTIMER_POLICY_DEFAULT); } static void imx_epit_class_init(ObjectClass *klass, void *data) diff --git a/hw/timer/imx_gpt.c b/hw/timer/imx_gpt.c index 49a441f..c535d19 100644 --- a/hw/timer/imx_gpt.c +++ b/hw/timer/imx_gpt.c @@ -492,7 +492,7 @@ static void imx_gpt_realize(DeviceState *dev, Error **errp) sysbus_init_mmio(sbd, &s->iomem); bh = qemu_bh_new(imx_gpt_timeout, s); - s->timer = ptimer_init(bh, PTIMER_POLICY_DEFAULT); + s->timer = ptimer_init_with_bh(bh, PTIMER_POLICY_DEFAULT); } static void imx_gpt_class_init(ObjectClass *klass, void *data) diff --git a/hw/timer/lm32_timer.c b/hw/timer/lm32_timer.c index cf316ed..fabde76 100644 --- a/hw/timer/lm32_timer.c +++ b/hw/timer/lm32_timer.c @@ -196,7 +196,7 @@ static void lm32_timer_realize(DeviceState *dev, Error **errp) LM32TimerState *s = LM32_TIMER(dev); s->bh = qemu_bh_new(timer_hit, s); - s->ptimer = ptimer_init(s->bh, PTIMER_POLICY_DEFAULT); + s->ptimer = ptimer_init_with_bh(s->bh, PTIMER_POLICY_DEFAULT); ptimer_set_freq(s->ptimer, s->freq_hz); } diff --git a/hw/timer/milkymist-sysctl.c b/hw/timer/milkymist-sysctl.c index 6aedc11..5193c03 100644 --- a/hw/timer/milkymist-sysctl.c +++ b/hw/timer/milkymist-sysctl.c @@ -294,8 +294,8 @@ static void milkymist_sysctl_realize(DeviceState *dev, Error **errp) s->bh0 = qemu_bh_new(timer0_hit, s); s->bh1 = qemu_bh_new(timer1_hit, s); - s->ptimer0 = ptimer_init(s->bh0, PTIMER_POLICY_DEFAULT); - s->ptimer1 = ptimer_init(s->bh1, PTIMER_POLICY_DEFAULT); + s->ptimer0 = ptimer_init_with_bh(s->bh0, PTIMER_POLICY_DEFAULT); + s->ptimer1 = ptimer_init_with_bh(s->bh1, PTIMER_POLICY_DEFAULT); ptimer_set_freq(s->ptimer0, s->freq_hz); ptimer_set_freq(s->ptimer1, s->freq_hz); diff --git a/hw/timer/mss-timer.c b/hw/timer/mss-timer.c index 45f1cf4..a34c240 100644 --- a/hw/timer/mss-timer.c +++ b/hw/timer/mss-timer.c @@ -229,7 +229,7 @@ static void mss_timer_init(Object *obj) struct Msf2Timer *st = &t->timers[i]; st->bh = qemu_bh_new(timer_hit, st); - st->ptimer = ptimer_init(st->bh, PTIMER_POLICY_DEFAULT); + st->ptimer = ptimer_init_with_bh(st->bh, PTIMER_POLICY_DEFAULT); ptimer_set_freq(st->ptimer, t->freq_hz); sysbus_init_irq(SYS_BUS_DEVICE(obj), &st->irq); } diff --git a/hw/timer/puv3_ost.c b/hw/timer/puv3_ost.c index 6fe3700..0898da5 100644 --- a/hw/timer/puv3_ost.c +++ b/hw/timer/puv3_ost.c @@ -129,7 +129,7 @@ static void puv3_ost_realize(DeviceState *dev, Error **errp) sysbus_init_irq(sbd, &s->irq); s->bh = qemu_bh_new(puv3_ost_tick, s); - s->ptimer = ptimer_init(s->bh, PTIMER_POLICY_DEFAULT); + s->ptimer = ptimer_init_with_bh(s->bh, PTIMER_POLICY_DEFAULT); ptimer_set_freq(s->ptimer, 50 * 1000 * 1000); memory_region_init_io(&s->iomem, OBJECT(s), &puv3_ost_ops, s, "puv3_ost", diff --git a/hw/timer/sh_timer.c b/hw/timer/sh_timer.c index adcc0c1..48a81b4 100644 --- a/hw/timer/sh_timer.c +++ b/hw/timer/sh_timer.c @@ -204,7 +204,7 @@ static void *sh_timer_init(uint32_t freq, int feat, qemu_irq irq) s->irq = irq; bh = qemu_bh_new(sh_timer_tick, s); - s->timer = ptimer_init(bh, PTIMER_POLICY_DEFAULT); + s->timer = ptimer_init_with_bh(bh, PTIMER_POLICY_DEFAULT); sh_timer_write(s, OFFSET_TCOR >> 2, s->tcor); sh_timer_write(s, OFFSET_TCNT >> 2, s->tcnt); diff --git a/hw/timer/slavio_timer.c b/hw/timer/slavio_timer.c index 38fd32b..692d213 100644 --- a/hw/timer/slavio_timer.c +++ b/hw/timer/slavio_timer.c @@ -393,7 +393,7 @@ static void slavio_timer_init(Object *obj) tc->timer_index = i; bh = qemu_bh_new(slavio_timer_irq, tc); - s->cputimer[i].timer = ptimer_init(bh, PTIMER_POLICY_DEFAULT); + s->cputimer[i].timer = ptimer_init_with_bh(bh, PTIMER_POLICY_DEFAULT); ptimer_set_period(s->cputimer[i].timer, TIMER_PERIOD); size = i == 0 ? SYS_TIMER_SIZE : CPU_TIMER_SIZE; diff --git a/hw/timer/xilinx_timer.c b/hw/timer/xilinx_timer.c index 3555182..92dbff3 100644 --- a/hw/timer/xilinx_timer.c +++ b/hw/timer/xilinx_timer.c @@ -221,7 +221,7 @@ static void xilinx_timer_realize(DeviceState *dev, Error **errp) xt->parent = t; xt->nr = i; xt->bh = qemu_bh_new(timer_hit, xt); - xt->ptimer = ptimer_init(xt->bh, PTIMER_POLICY_DEFAULT); + xt->ptimer = ptimer_init_with_bh(xt->bh, PTIMER_POLICY_DEFAULT); ptimer_set_freq(xt->ptimer, t->freq_hz); } -- cgit v1.1 From 5a65f7b5f4907ca70cb6eae1265e59ccbdfa0937 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 8 Oct 2019 18:17:23 +0100 Subject: hw/timer/arm_timer.c: Switch to transaction-based ptimer API Switch the arm_timer.c code away from bottom-half based ptimers to the new transaction-based ptimer API. This just requires adding begin/commit calls around the various arms of arm_timer_write() that modify the ptimer state, and using the new ptimer_init() function to create the timer. Fixes: https://bugs.launchpad.net/qemu/+bug/1777777 Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20191008171740.9679-5-peter.maydell@linaro.org --- hw/timer/arm_timer.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) (limited to 'hw/timer') diff --git a/hw/timer/arm_timer.c b/hw/timer/arm_timer.c index dc33ab3..af524fa 100644 --- a/hw/timer/arm_timer.c +++ b/hw/timer/arm_timer.c @@ -14,7 +14,6 @@ #include "hw/irq.h" #include "hw/ptimer.h" #include "hw/qdev-properties.h" -#include "qemu/main-loop.h" #include "qemu/module.h" #include "qemu/log.h" @@ -75,7 +74,10 @@ static uint32_t arm_timer_read(void *opaque, hwaddr offset) } } -/* Reset the timer limit after settings have changed. */ +/* + * Reset the timer limit after settings have changed. + * May only be called from inside a ptimer transaction block. + */ static void arm_timer_recalibrate(arm_timer_state *s, int reload) { uint32_t limit; @@ -102,13 +104,16 @@ static void arm_timer_write(void *opaque, hwaddr offset, switch (offset >> 2) { case 0: /* TimerLoad */ s->limit = value; + ptimer_transaction_begin(s->timer); arm_timer_recalibrate(s, 1); + ptimer_transaction_commit(s->timer); break; case 1: /* TimerValue */ /* ??? Linux seems to want to write to this readonly register. Ignore it. */ break; case 2: /* TimerControl */ + ptimer_transaction_begin(s->timer); if (s->control & TIMER_CTRL_ENABLE) { /* Pause the timer if it is running. This may cause some inaccuracy dure to rounding, but avoids a whole lot of other @@ -128,13 +133,16 @@ static void arm_timer_write(void *opaque, hwaddr offset, /* Restart the timer if still enabled. */ ptimer_run(s->timer, (s->control & TIMER_CTRL_ONESHOT) != 0); } + ptimer_transaction_commit(s->timer); break; case 3: /* TimerIntClr */ s->int_level = 0; break; case 6: /* TimerBGLoad */ s->limit = value; + ptimer_transaction_begin(s->timer); arm_timer_recalibrate(s, 0); + ptimer_transaction_commit(s->timer); break; default: qemu_log_mask(LOG_GUEST_ERROR, @@ -166,14 +174,12 @@ static const VMStateDescription vmstate_arm_timer = { static arm_timer_state *arm_timer_init(uint32_t freq) { arm_timer_state *s; - QEMUBH *bh; s = (arm_timer_state *)g_malloc0(sizeof(arm_timer_state)); s->freq = freq; s->control = TIMER_CTRL_IE; - bh = qemu_bh_new(arm_timer_tick, s); - s->timer = ptimer_init_with_bh(bh, PTIMER_POLICY_DEFAULT); + s->timer = ptimer_init(arm_timer_tick, s, PTIMER_POLICY_DEFAULT); vmstate_register(NULL, -1, &vmstate_arm_timer, s); return s; } -- cgit v1.1 From 827c421492cb414f1d388442e2a4deb6e971fc8a Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 8 Oct 2019 18:17:25 +0100 Subject: hw/timer/allwinner-a10-pit.c: Switch to transaction-based ptimer API Switch the allwinner-a10-pit 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 Reviewed-by: Richard Henderson Message-id: 20191008171740.9679-7-peter.maydell@linaro.org --- hw/timer/allwinner-a10-pit.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'hw/timer') diff --git a/hw/timer/allwinner-a10-pit.c b/hw/timer/allwinner-a10-pit.c index 28d055e..aae880f 100644 --- a/hw/timer/allwinner-a10-pit.c +++ b/hw/timer/allwinner-a10-pit.c @@ -22,7 +22,6 @@ #include "hw/timer/allwinner-a10-pit.h" #include "migration/vmstate.h" #include "qemu/log.h" -#include "qemu/main-loop.h" #include "qemu/module.h" static void a10_pit_update_irq(AwA10PITState *s) @@ -80,6 +79,7 @@ static uint64_t a10_pit_read(void *opaque, hwaddr offset, unsigned size) return 0; } +/* Must be called inside a ptimer transaction block for s->timer[index] */ static void a10_pit_set_freq(AwA10PITState *s, int index) { uint32_t prescaler, source, source_freq; @@ -118,6 +118,7 @@ static void a10_pit_write(void *opaque, hwaddr offset, uint64_t value, switch (offset & 0x0f) { case AW_A10_PIT_TIMER_CONTROL: s->control[index] = value; + ptimer_transaction_begin(s->timer[index]); a10_pit_set_freq(s, index); if (s->control[index] & AW_A10_PIT_TIMER_RELOAD) { ptimer_set_count(s->timer[index], s->interval[index]); @@ -131,10 +132,13 @@ static void a10_pit_write(void *opaque, hwaddr offset, uint64_t value, } else { ptimer_stop(s->timer[index]); } + ptimer_transaction_commit(s->timer[index]); break; case AW_A10_PIT_TIMER_INTERVAL: s->interval[index] = value; + ptimer_transaction_begin(s->timer[index]); ptimer_set_limit(s->timer[index], s->interval[index], 1); + ptimer_transaction_commit(s->timer[index]); break; case AW_A10_PIT_TIMER_COUNT: s->count[index] = value; @@ -225,8 +229,10 @@ static void a10_pit_reset(DeviceState *dev) s->control[i] = AW_A10_PIT_DEFAULT_CLOCK; s->interval[i] = 0; s->count[i] = 0; + ptimer_transaction_begin(s->timer[i]); ptimer_stop(s->timer[i]); a10_pit_set_freq(s, i); + ptimer_transaction_commit(s->timer[i]); } s->watch_dog_mode = 0; s->watch_dog_control = 0; @@ -255,7 +261,6 @@ static void a10_pit_init(Object *obj) { AwA10PITState *s = AW_A10_PIT(obj); SysBusDevice *sbd = SYS_BUS_DEVICE(obj); - QEMUBH * bh[AW_A10_PIT_TIMER_NR]; uint8_t i; for (i = 0; i < AW_A10_PIT_TIMER_NR; i++) { @@ -270,8 +275,7 @@ static void a10_pit_init(Object *obj) tc->container = s; tc->index = i; - bh[i] = qemu_bh_new(a10_pit_timer_cb, tc); - s->timer[i] = ptimer_init_with_bh(bh[i], PTIMER_POLICY_DEFAULT); + s->timer[i] = ptimer_init(a10_pit_timer_cb, tc, PTIMER_POLICY_DEFAULT); } } -- cgit v1.1 From 581b088035a16432aece13639985235e3689363e Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 8 Oct 2019 18:17:26 +0100 Subject: hw/timer/arm_mptimer.c: Switch to transaction-based ptimer API Switch the arm_mptimer.c 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 Reviewed-by: Richard Henderson Message-id: 20191008171740.9679-8-peter.maydell@linaro.org --- hw/timer/arm_mptimer.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) (limited to 'hw/timer') diff --git a/hw/timer/arm_mptimer.c b/hw/timer/arm_mptimer.c index 2a54a01..fdf97d1 100644 --- a/hw/timer/arm_mptimer.c +++ b/hw/timer/arm_mptimer.c @@ -27,7 +27,6 @@ #include "hw/timer/arm_mptimer.h" #include "migration/vmstate.h" #include "qapi/error.h" -#include "qemu/main-loop.h" #include "qemu/module.h" #include "hw/core/cpu.h" @@ -65,6 +64,7 @@ static inline uint32_t timerblock_scale(uint32_t control) return (((control >> 8) & 0xff) + 1) * 10; } +/* Must be called within a ptimer transaction block */ static inline void timerblock_set_count(struct ptimer_state *timer, uint32_t control, uint64_t *count) { @@ -77,6 +77,7 @@ static inline void timerblock_set_count(struct ptimer_state *timer, ptimer_set_count(timer, *count); } +/* Must be called within a ptimer transaction block */ static inline void timerblock_run(struct ptimer_state *timer, uint32_t control, uint32_t load) { @@ -124,6 +125,7 @@ static void timerblock_write(void *opaque, hwaddr addr, uint32_t control = tb->control; switch (addr) { case 0: /* Load */ + ptimer_transaction_begin(tb->timer); /* Setting load to 0 stops the timer without doing the tick if * prescaler = 0. */ @@ -132,8 +134,10 @@ static void timerblock_write(void *opaque, hwaddr addr, } ptimer_set_limit(tb->timer, value, 1); timerblock_run(tb->timer, control, value); + ptimer_transaction_commit(tb->timer); break; case 4: /* Counter. */ + ptimer_transaction_begin(tb->timer); /* Setting counter to 0 stops the one-shot timer, or periodic with * load = 0, without doing the tick if prescaler = 0. */ @@ -143,8 +147,10 @@ static void timerblock_write(void *opaque, hwaddr addr, } timerblock_set_count(tb->timer, control, &value); timerblock_run(tb->timer, control, value); + ptimer_transaction_commit(tb->timer); break; case 8: /* Control. */ + ptimer_transaction_begin(tb->timer); if ((control & 3) != (value & 3)) { ptimer_stop(tb->timer); } @@ -160,6 +166,7 @@ static void timerblock_write(void *opaque, hwaddr addr, timerblock_run(tb->timer, value, count); } tb->control = value; + ptimer_transaction_commit(tb->timer); break; case 12: /* Interrupt status. */ tb->status &= ~value; @@ -212,9 +219,11 @@ static void timerblock_reset(TimerBlock *tb) tb->control = 0; tb->status = 0; if (tb->timer) { + ptimer_transaction_begin(tb->timer); ptimer_stop(tb->timer); ptimer_set_limit(tb->timer, 0, 1); ptimer_set_period(tb->timer, timerblock_scale(0)); + ptimer_transaction_commit(tb->timer); } } @@ -260,8 +269,7 @@ static void arm_mptimer_realize(DeviceState *dev, Error **errp) */ for (i = 0; i < s->num_cpu; i++) { TimerBlock *tb = &s->timerblock[i]; - QEMUBH *bh = qemu_bh_new(timerblock_tick, tb); - tb->timer = ptimer_init_with_bh(bh, PTIMER_POLICY); + tb->timer = ptimer_init(timerblock_tick, tb, PTIMER_POLICY); sysbus_init_irq(sbd, &tb->irq); memory_region_init_io(&tb->iomem, OBJECT(s), &timerblock_ops, tb, "arm_mptimer_timerblock", 0x20); -- cgit v1.1 From da38e0680f8e5118131fd224d52e97d7db38a48c Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 8 Oct 2019 18:17:27 +0100 Subject: hw/timer/cmsdk-apb-dualtimer.c: Switch to transaction-based ptimer API Switch the cmsdk-apb-dualtimer 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 Reviewed-by: Richard Henderson Message-id: 20191008171740.9679-9-peter.maydell@linaro.org --- hw/timer/cmsdk-apb-dualtimer.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) (limited to 'hw/timer') diff --git a/hw/timer/cmsdk-apb-dualtimer.c b/hw/timer/cmsdk-apb-dualtimer.c index 44d23c8..e28ba9c 100644 --- a/hw/timer/cmsdk-apb-dualtimer.c +++ b/hw/timer/cmsdk-apb-dualtimer.c @@ -20,7 +20,6 @@ #include "qemu/log.h" #include "trace.h" #include "qapi/error.h" -#include "qemu/main-loop.h" #include "qemu/module.h" #include "hw/sysbus.h" #include "hw/irq.h" @@ -112,6 +111,8 @@ static void cmsdk_dualtimermod_write_control(CMSDKAPBDualTimerModule *m, /* Handle a write to the CONTROL register */ uint32_t changed; + ptimer_transaction_begin(m->timer); + newctrl &= R_CONTROL_VALID_MASK; changed = m->control ^ newctrl; @@ -213,6 +214,8 @@ static void cmsdk_dualtimermod_write_control(CMSDKAPBDualTimerModule *m, } m->control = newctrl; + + ptimer_transaction_commit(m->timer); } static uint64_t cmsdk_apb_dualtimer_read(void *opaque, hwaddr offset, @@ -330,6 +333,7 @@ static void cmsdk_apb_dualtimer_write(void *opaque, hwaddr offset, if (!(m->control & R_CONTROL_SIZE_MASK)) { value &= 0xffff; } + ptimer_transaction_begin(m->timer); if (!(m->control & R_CONTROL_MODE_MASK)) { /* * In free-running mode this won't set the limit but will @@ -346,6 +350,7 @@ static void cmsdk_apb_dualtimer_write(void *opaque, hwaddr offset, ptimer_run(m->timer, 1); } } + ptimer_transaction_commit(m->timer); break; case A_TIMER1BGLOAD: /* Set the limit, but not the current count */ @@ -357,7 +362,9 @@ static void cmsdk_apb_dualtimer_write(void *opaque, hwaddr offset, if (!(m->control & R_CONTROL_SIZE_MASK)) { value &= 0xffff; } + ptimer_transaction_begin(m->timer); ptimer_set_limit(m->timer, value, 0); + ptimer_transaction_commit(m->timer); break; case A_TIMER1CONTROL: cmsdk_dualtimermod_write_control(m, value); @@ -398,6 +405,7 @@ static void cmsdk_dualtimermod_reset(CMSDKAPBDualTimerModule *m) m->intstatus = 0; m->load = 0; m->value = 0xffffffff; + ptimer_transaction_begin(m->timer); ptimer_stop(m->timer); /* * We start in free-running mode, with VALUE at 0xffffffff, and @@ -406,6 +414,7 @@ static void cmsdk_dualtimermod_reset(CMSDKAPBDualTimerModule *m) */ ptimer_set_limit(m->timer, 0xffff, 1); ptimer_set_freq(m->timer, m->parent->pclk_frq); + ptimer_transaction_commit(m->timer); } static void cmsdk_apb_dualtimer_reset(DeviceState *dev) @@ -450,10 +459,9 @@ static void cmsdk_apb_dualtimer_realize(DeviceState *dev, Error **errp) for (i = 0; i < ARRAY_SIZE(s->timermod); i++) { CMSDKAPBDualTimerModule *m = &s->timermod[i]; - QEMUBH *bh = qemu_bh_new(cmsdk_dualtimermod_tick, m); m->parent = s; - m->timer = ptimer_init_with_bh(bh, + m->timer = ptimer_init(cmsdk_dualtimermod_tick, m, PTIMER_POLICY_WRAP_AFTER_ONE_PERIOD | PTIMER_POLICY_TRIGGER_ONLY_ON_DECREMENT | PTIMER_POLICY_NO_IMMEDIATE_RELOAD | -- cgit v1.1 From 19c12fe93ab9c65b56c7dfd467799a63c28d4bbd Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 8 Oct 2019 18:17:28 +0100 Subject: hw/timer/cmsdk-apb-timer.c: Switch to transaction-based ptimer API Switch the cmsdk-apb-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 Reviewed-by: Richard Henderson Message-id: 20191008171740.9679-10-peter.maydell@linaro.org --- hw/timer/cmsdk-apb-timer.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) (limited to 'hw/timer') diff --git a/hw/timer/cmsdk-apb-timer.c b/hw/timer/cmsdk-apb-timer.c index c9ce977..40728e8 100644 --- a/hw/timer/cmsdk-apb-timer.c +++ b/hw/timer/cmsdk-apb-timer.c @@ -29,7 +29,6 @@ #include "qemu/osdep.h" #include "qemu/log.h" -#include "qemu/main-loop.h" #include "qemu/module.h" #include "qapi/error.h" #include "trace.h" @@ -121,14 +120,17 @@ static void cmsdk_apb_timer_write(void *opaque, hwaddr offset, uint64_t value, "CMSDK APB timer: EXTIN input not supported\n"); } s->ctrl = value & 0xf; + ptimer_transaction_begin(s->timer); if (s->ctrl & R_CTRL_EN_MASK) { ptimer_run(s->timer, ptimer_get_limit(s->timer) == 0); } else { ptimer_stop(s->timer); } + ptimer_transaction_commit(s->timer); break; case A_RELOAD: /* Writing to reload also sets the current timer value */ + ptimer_transaction_begin(s->timer); if (!value) { ptimer_stop(s->timer); } @@ -140,8 +142,10 @@ static void cmsdk_apb_timer_write(void *opaque, hwaddr offset, uint64_t value, */ ptimer_run(s->timer, 0); } + ptimer_transaction_commit(s->timer); break; case A_VALUE: + ptimer_transaction_begin(s->timer); if (!value && !ptimer_get_limit(s->timer)) { ptimer_stop(s->timer); } @@ -149,6 +153,7 @@ static void cmsdk_apb_timer_write(void *opaque, hwaddr offset, uint64_t value, if (value && (s->ctrl & R_CTRL_EN_MASK)) { ptimer_run(s->timer, ptimer_get_limit(s->timer) == 0); } + ptimer_transaction_commit(s->timer); break; case A_INTSTATUS: /* Just one bit, which is W1C. */ @@ -191,9 +196,11 @@ static void cmsdk_apb_timer_reset(DeviceState *dev) trace_cmsdk_apb_timer_reset(); s->ctrl = 0; s->intstatus = 0; + ptimer_transaction_begin(s->timer); ptimer_stop(s->timer); /* Set the limit and the count */ ptimer_set_limit(s->timer, 0, 1); + ptimer_transaction_commit(s->timer); } static void cmsdk_apb_timer_init(Object *obj) @@ -210,21 +217,21 @@ static void cmsdk_apb_timer_init(Object *obj) static void cmsdk_apb_timer_realize(DeviceState *dev, Error **errp) { CMSDKAPBTIMER *s = CMSDK_APB_TIMER(dev); - QEMUBH *bh; if (s->pclk_frq == 0) { error_setg(errp, "CMSDK APB timer: pclk-frq property must be set"); return; } - bh = qemu_bh_new(cmsdk_apb_timer_tick, s); - s->timer = ptimer_init_with_bh(bh, + s->timer = ptimer_init(cmsdk_apb_timer_tick, s, PTIMER_POLICY_WRAP_AFTER_ONE_PERIOD | PTIMER_POLICY_TRIGGER_ONLY_ON_DECREMENT | PTIMER_POLICY_NO_IMMEDIATE_RELOAD | PTIMER_POLICY_NO_COUNTER_ROUND_DOWN); + ptimer_transaction_begin(s->timer); ptimer_set_freq(s->timer, s->pclk_frq); + ptimer_transaction_commit(s->timer); } static const VMStateDescription cmsdk_apb_timer_vmstate = { -- cgit v1.1 From 30e22c8733e8b2bed7dc77c4f9ebc7a4a4114632 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 8 Oct 2019 18:17:29 +0100 Subject: hw/timer/digic-timer.c: Switch to transaction-based ptimer API Switch the digic-timer.c 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 Reviewed-by: Richard Henderson Message-id: 20191008171740.9679-11-peter.maydell@linaro.org --- hw/timer/digic-timer.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) (limited to 'hw/timer') diff --git a/hw/timer/digic-timer.c b/hw/timer/digic-timer.c index b111e1f..3261222 100644 --- a/hw/timer/digic-timer.c +++ b/hw/timer/digic-timer.c @@ -29,7 +29,6 @@ #include "qemu/osdep.h" #include "hw/sysbus.h" #include "hw/ptimer.h" -#include "qemu/main-loop.h" #include "qemu/module.h" #include "qemu/log.h" @@ -52,7 +51,9 @@ static void digic_timer_reset(DeviceState *dev) { DigicTimerState *s = DIGIC_TIMER(dev); + ptimer_transaction_begin(s->ptimer); ptimer_stop(s->ptimer); + ptimer_transaction_commit(s->ptimer); s->control = 0; s->relvalue = 0; } @@ -93,16 +94,20 @@ static void digic_timer_write(void *opaque, hwaddr offset, break; } + ptimer_transaction_begin(s->ptimer); if (value & DIGIC_TIMER_CONTROL_EN) { ptimer_run(s->ptimer, 0); } s->control = (uint32_t)value; + ptimer_transaction_commit(s->ptimer); break; case DIGIC_TIMER_RELVALUE: s->relvalue = extract32(value, 0, 16); + ptimer_transaction_begin(s->ptimer); ptimer_set_limit(s->ptimer, s->relvalue, 1); + ptimer_transaction_commit(s->ptimer); break; case DIGIC_TIMER_VALUE: @@ -125,17 +130,24 @@ static const MemoryRegionOps digic_timer_ops = { .endianness = DEVICE_NATIVE_ENDIAN, }; +static void digic_timer_tick(void *opaque) +{ + /* Nothing to do on timer rollover */ +} + static void digic_timer_init(Object *obj) { DigicTimerState *s = DIGIC_TIMER(obj); - s->ptimer = ptimer_init_with_bh(NULL, PTIMER_POLICY_DEFAULT); + s->ptimer = ptimer_init(digic_timer_tick, NULL, PTIMER_POLICY_DEFAULT); /* * FIXME: there is no documentation on Digic timer * frequency setup so let it always run at 1 MHz */ + ptimer_transaction_begin(s->ptimer); ptimer_set_freq(s->ptimer, 1 * 1000 * 1000); + ptimer_transaction_commit(s->ptimer); memory_region_init_io(&s->iomem, OBJECT(s), &digic_timer_ops, s, TYPE_DIGIC_TIMER, 0x100); -- cgit v1.1 From 9ede4ec094340cd788e9260f72e64988c5738530 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 8 Oct 2019 18:17:30 +0100 Subject: hw/timer/exynos4210_mct.c: Switch GFRC to transaction-based ptimer API We want to switch the exynos MCT code away from bottom-half based ptimers to the new transaction-based ptimer API. The MCT is complicated and uses multiple different ptimers, so it's clearer to switch it a piece at a time. Here we change over only the GFRC. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20191008171740.9679-12-peter.maydell@linaro.org --- hw/timer/exynos4210_mct.c | 48 ++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 45 insertions(+), 3 deletions(-) (limited to 'hw/timer') diff --git a/hw/timer/exynos4210_mct.c b/hw/timer/exynos4210_mct.c index 9f2e8dd..fcf91c7 100644 --- a/hw/timer/exynos4210_mct.c +++ b/hw/timer/exynos4210_mct.c @@ -364,6 +364,7 @@ static void exynos4210_mct_update_freq(Exynos4210MCTState *s); /* * Set counter of FRC global timer. + * Must be called within exynos4210_gfrc_tx_begin/commit block. */ static void exynos4210_gfrc_set_count(Exynos4210MCTGT *s, uint64_t count) { @@ -385,6 +386,7 @@ static uint64_t exynos4210_gfrc_get_count(Exynos4210MCTGT *s) /* * Stop global FRC timer + * Must be called within exynos4210_gfrc_tx_begin/commit block. */ static void exynos4210_gfrc_stop(Exynos4210MCTGT *s) { @@ -395,6 +397,7 @@ static void exynos4210_gfrc_stop(Exynos4210MCTGT *s) /* * Start global FRC timer + * Must be called within exynos4210_gfrc_tx_begin/commit block. */ static void exynos4210_gfrc_start(Exynos4210MCTGT *s) { @@ -404,6 +407,21 @@ static void exynos4210_gfrc_start(Exynos4210MCTGT *s) } /* + * Start ptimer transaction for global FRC timer; this is just for + * consistency with the way we wrap operations like stop and run. + */ +static void exynos4210_gfrc_tx_begin(Exynos4210MCTGT *s) +{ + ptimer_transaction_begin(s->ptimer_frc); +} + +/* Commit ptimer transaction for global FRC timer. */ +static void exynos4210_gfrc_tx_commit(Exynos4210MCTGT *s) +{ + ptimer_transaction_commit(s->ptimer_frc); +} + +/* * Find next nearest Comparator. If current Comparator value equals to other * Comparator value, skip them both */ @@ -492,6 +510,7 @@ static uint64_t exynos4210_gcomp_get_distance(Exynos4210MCTState *s, int32_t id) /* * Restart global FRC timer + * Must be called within exynos4210_gfrc_tx_begin/commit block. */ static void exynos4210_gfrc_restart(Exynos4210MCTState *s) { @@ -933,6 +952,19 @@ static void exynos4210_ltick_event(void *opaque) exynos4210_ltick_int_start(&s->tick_timer); } +static void tx_ptimer_set_freq(ptimer_state *s, uint32_t freq) +{ + /* + * callers of exynos4210_mct_update_freq() never do anything + * else that needs to be in the same ptimer transaction, so + * to avoid a lot of repetition we have a convenience function + * for begin/set_freq/commit. + */ + ptimer_transaction_begin(s); + ptimer_set_freq(s, freq); + ptimer_transaction_commit(s); +} + /* update timer frequency */ static void exynos4210_mct_update_freq(Exynos4210MCTState *s) { @@ -945,7 +977,7 @@ static void exynos4210_mct_update_freq(Exynos4210MCTState *s) DPRINTF("freq=%dHz\n", s->freq); /* global timer */ - ptimer_set_freq(s->g_timer.ptimer_frc, s->freq); + tx_ptimer_set_freq(s->g_timer.ptimer_frc, s->freq); /* local timer */ ptimer_set_freq(s->l_timer[0].tick_timer.ptimer_tick, s->freq); @@ -965,7 +997,9 @@ static void exynos4210_mct_reset(DeviceState *d) /* global timer */ memset(&s->g_timer.reg, 0, sizeof(s->g_timer.reg)); + exynos4210_gfrc_tx_begin(&s->g_timer); exynos4210_gfrc_stop(&s->g_timer); + exynos4210_gfrc_tx_commit(&s->g_timer); /* local timer */ memset(s->l_timer[0].reg.cnt, 0, sizeof(s->l_timer[0].reg.cnt)); @@ -1144,7 +1178,9 @@ static void exynos4210_mct_write(void *opaque, hwaddr offset, } s->g_timer.reg.cnt = new_frc; + exynos4210_gfrc_tx_begin(&s->g_timer); exynos4210_gfrc_restart(s); + exynos4210_gfrc_tx_commit(&s->g_timer); break; case G_CNT_WSTAT: @@ -1168,7 +1204,9 @@ static void exynos4210_mct_write(void *opaque, hwaddr offset, s->g_timer.reg.wstat |= G_WSTAT_COMP_L(index); } + exynos4210_gfrc_tx_begin(&s->g_timer); exynos4210_gfrc_restart(s); + exynos4210_gfrc_tx_commit(&s->g_timer); break; case G_TCON: @@ -1178,6 +1216,8 @@ static void exynos4210_mct_write(void *opaque, hwaddr offset, DPRINTF("global timer write to reg.g_tcon %llx\n", value); + exynos4210_gfrc_tx_begin(&s->g_timer); + /* Start FRC if transition from disabled to enabled */ if ((value & G_TCON_TIMER_ENABLE) > (old_val & G_TCON_TIMER_ENABLE)) { @@ -1195,6 +1235,8 @@ static void exynos4210_mct_write(void *opaque, hwaddr offset, exynos4210_gfrc_restart(s); } } + + exynos4210_gfrc_tx_commit(&s->g_timer); break; case G_INT_CSTAT: @@ -1428,8 +1470,8 @@ static void exynos4210_mct_init(Object *obj) QEMUBH *bh[2]; /* Global timer */ - bh[0] = qemu_bh_new(exynos4210_gfrc_event, s); - s->g_timer.ptimer_frc = ptimer_init_with_bh(bh[0], PTIMER_POLICY_DEFAULT); + s->g_timer.ptimer_frc = ptimer_init(exynos4210_gfrc_event, s, + PTIMER_POLICY_DEFAULT); memset(&s->g_timer.reg, 0, sizeof(struct gregs)); /* Local timers */ -- cgit v1.1 From 50f07d76f4920988c9bddeb9854240ac9f761e2e Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 8 Oct 2019 18:17:31 +0100 Subject: hw/timer/exynos4210_mct.c: Switch LFRC to transaction-based ptimer API Switch the exynos MCT LFRC timers over to the ptimer transaction API. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20191008171740.9679-13-peter.maydell@linaro.org --- hw/timer/exynos4210_mct.c | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) (limited to 'hw/timer') diff --git a/hw/timer/exynos4210_mct.c b/hw/timer/exynos4210_mct.c index fcf91c7..82803ef 100644 --- a/hw/timer/exynos4210_mct.c +++ b/hw/timer/exynos4210_mct.c @@ -608,6 +608,7 @@ static uint64_t exynos4210_lfrc_get_count(Exynos4210MCTLT *s) /* * Set counter of FRC local timer. + * Must be called from within exynos4210_lfrc_tx_begin/commit block. */ static void exynos4210_lfrc_update_count(Exynos4210MCTLT *s) { @@ -620,6 +621,7 @@ static void exynos4210_lfrc_update_count(Exynos4210MCTLT *s) /* * Start local FRC timer + * Must be called from within exynos4210_lfrc_tx_begin/commit block. */ static void exynos4210_lfrc_start(Exynos4210MCTLT *s) { @@ -628,12 +630,25 @@ static void exynos4210_lfrc_start(Exynos4210MCTLT *s) /* * Stop local FRC timer + * Must be called from within exynos4210_lfrc_tx_begin/commit block. */ static void exynos4210_lfrc_stop(Exynos4210MCTLT *s) { ptimer_stop(s->ptimer_frc); } +/* Start ptimer transaction for local FRC timer */ +static void exynos4210_lfrc_tx_begin(Exynos4210MCTLT *s) +{ + ptimer_transaction_begin(s->ptimer_frc); +} + +/* Commit ptimer transaction for local FRC timer */ +static void exynos4210_lfrc_tx_commit(Exynos4210MCTLT *s) +{ + ptimer_transaction_commit(s->ptimer_frc); +} + /* * Local timer free running counter tick handler */ @@ -981,9 +996,9 @@ static void exynos4210_mct_update_freq(Exynos4210MCTState *s) /* local timer */ ptimer_set_freq(s->l_timer[0].tick_timer.ptimer_tick, s->freq); - ptimer_set_freq(s->l_timer[0].ptimer_frc, s->freq); + tx_ptimer_set_freq(s->l_timer[0].ptimer_frc, s->freq); ptimer_set_freq(s->l_timer[1].tick_timer.ptimer_tick, s->freq); - ptimer_set_freq(s->l_timer[1].ptimer_frc, s->freq); + tx_ptimer_set_freq(s->l_timer[1].ptimer_frc, s->freq); } } @@ -1012,7 +1027,9 @@ static void exynos4210_mct_reset(DeviceState *d) s->l_timer[i].tick_timer.count = 0; s->l_timer[i].tick_timer.distance = 0; s->l_timer[i].tick_timer.progress = 0; + exynos4210_lfrc_tx_begin(&s->l_timer[i]); ptimer_stop(s->l_timer[i].ptimer_frc); + exynos4210_lfrc_tx_commit(&s->l_timer[i]); exynos4210_ltick_timer_init(&s->l_timer[i].tick_timer); } @@ -1316,6 +1333,7 @@ static void exynos4210_mct_write(void *opaque, hwaddr offset, } /* Start or Stop local FRC if TCON changed */ + exynos4210_lfrc_tx_begin(&s->l_timer[lt_i]); if ((value & L_TCON_FRC_START) > (s->l_timer[lt_i].reg.tcon & L_TCON_FRC_START)) { DPRINTF("local timer[%d] start frc\n", lt_i); @@ -1326,6 +1344,7 @@ static void exynos4210_mct_write(void *opaque, hwaddr offset, DPRINTF("local timer[%d] stop frc\n", lt_i); exynos4210_lfrc_stop(&s->l_timer[lt_i]); } + exynos4210_lfrc_tx_commit(&s->l_timer[lt_i]); break; case L0_TCNTB: case L1_TCNTB: @@ -1477,11 +1496,11 @@ static void exynos4210_mct_init(Object *obj) /* Local timers */ for (i = 0; i < 2; i++) { bh[0] = qemu_bh_new(exynos4210_ltick_event, &s->l_timer[i]); - bh[1] = qemu_bh_new(exynos4210_lfrc_event, &s->l_timer[i]); s->l_timer[i].tick_timer.ptimer_tick = ptimer_init_with_bh(bh[0], PTIMER_POLICY_DEFAULT); s->l_timer[i].ptimer_frc = - ptimer_init_with_bh(bh[1], PTIMER_POLICY_DEFAULT); + ptimer_init(exynos4210_lfrc_event, &s->l_timer[i], + PTIMER_POLICY_DEFAULT); s->l_timer[i].id = i; } -- cgit v1.1 From 6c27ee94f34fb17588dd850fd8f7870d3314338f Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 8 Oct 2019 18:17:32 +0100 Subject: hw/timer/exynos4210_mct.c: Switch ltick to transaction-based ptimer API Switch the ltick ptimer over to the ptimer transaction API. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20191008171740.9679-14-peter.maydell@linaro.org --- hw/timer/exynos4210_mct.c | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) (limited to 'hw/timer') diff --git a/hw/timer/exynos4210_mct.c b/hw/timer/exynos4210_mct.c index 82803ef..7225758 100644 --- a/hw/timer/exynos4210_mct.c +++ b/hw/timer/exynos4210_mct.c @@ -58,7 +58,6 @@ #include "hw/sysbus.h" #include "migration/vmstate.h" #include "qemu/timer.h" -#include "qemu/main-loop.h" #include "qemu/module.h" #include "hw/ptimer.h" @@ -735,6 +734,7 @@ static uint32_t exynos4210_ltick_int_get_cnto(struct tick_timer *s) /* * Start local tick cnt timer. + * Must be called within exynos4210_ltick_tx_begin/commit block. */ static void exynos4210_ltick_cnt_start(struct tick_timer *s) { @@ -750,6 +750,7 @@ static void exynos4210_ltick_cnt_start(struct tick_timer *s) /* * Stop local tick cnt timer. + * Must be called within exynos4210_ltick_tx_begin/commit block. */ static void exynos4210_ltick_cnt_stop(struct tick_timer *s) { @@ -767,6 +768,18 @@ static void exynos4210_ltick_cnt_stop(struct tick_timer *s) } } +/* Start ptimer transaction for local tick timer */ +static void exynos4210_ltick_tx_begin(struct tick_timer *s) +{ + ptimer_transaction_begin(s->ptimer_tick); +} + +/* Commit ptimer transaction for local tick timer */ +static void exynos4210_ltick_tx_commit(struct tick_timer *s) +{ + ptimer_transaction_commit(s->ptimer_tick); +} + /* * Get counter for CNT timer */ @@ -812,6 +825,7 @@ static uint32_t exynos4210_ltick_cnt_get_cnto(struct tick_timer *s) /* * Set new values of counters for CNT and INT timers + * Must be called within exynos4210_ltick_tx_begin/commit block. */ static void exynos4210_ltick_set_cntb(struct tick_timer *s, uint32_t new_cnt, uint32_t new_int) @@ -885,7 +899,9 @@ static void exynos4210_ltick_recalc_count(struct tick_timer *s) static void exynos4210_ltick_timer_init(struct tick_timer *s) { exynos4210_ltick_int_stop(s); + exynos4210_ltick_tx_begin(s); exynos4210_ltick_cnt_stop(s); + exynos4210_ltick_tx_commit(s); s->count = 0; s->distance = 0; @@ -995,9 +1011,9 @@ static void exynos4210_mct_update_freq(Exynos4210MCTState *s) tx_ptimer_set_freq(s->g_timer.ptimer_frc, s->freq); /* local timer */ - ptimer_set_freq(s->l_timer[0].tick_timer.ptimer_tick, s->freq); + tx_ptimer_set_freq(s->l_timer[0].tick_timer.ptimer_tick, s->freq); tx_ptimer_set_freq(s->l_timer[0].ptimer_frc, s->freq); - ptimer_set_freq(s->l_timer[1].tick_timer.ptimer_tick, s->freq); + tx_ptimer_set_freq(s->l_timer[1].tick_timer.ptimer_tick, s->freq); tx_ptimer_set_freq(s->l_timer[1].ptimer_frc, s->freq); } } @@ -1304,6 +1320,7 @@ static void exynos4210_mct_write(void *opaque, hwaddr offset, s->l_timer[lt_i].reg.wstat |= L_WSTAT_TCON_WRITE; s->l_timer[lt_i].reg.tcon = value; + exynos4210_ltick_tx_begin(&s->l_timer[lt_i].tick_timer); /* Stop local CNT */ if ((value & L_TCON_TICK_START) < (old_val & L_TCON_TICK_START)) { @@ -1331,6 +1348,7 @@ static void exynos4210_mct_write(void *opaque, hwaddr offset, DPRINTF("local timer[%d] start int\n", lt_i); exynos4210_ltick_int_start(&s->l_timer[lt_i].tick_timer); } + exynos4210_ltick_tx_commit(&s->l_timer[lt_i].tick_timer); /* Start or Stop local FRC if TCON changed */ exynos4210_lfrc_tx_begin(&s->l_timer[lt_i]); @@ -1356,8 +1374,10 @@ static void exynos4210_mct_write(void *opaque, hwaddr offset, * Due to this we should reload timer to nearest moment when CNT is * expired and then in event handler update tcntb to new TCNTB value. */ + exynos4210_ltick_tx_begin(&s->l_timer[lt_i].tick_timer); exynos4210_ltick_set_cntb(&s->l_timer[lt_i].tick_timer, value, s->l_timer[lt_i].tick_timer.icntb); + exynos4210_ltick_tx_commit(&s->l_timer[lt_i].tick_timer); s->l_timer[lt_i].reg.wstat |= L_WSTAT_TCNTB_WRITE; s->l_timer[lt_i].reg.cnt[L_REG_CNT_TCNTB] = value; @@ -1486,7 +1506,6 @@ static void exynos4210_mct_init(Object *obj) int i; Exynos4210MCTState *s = EXYNOS4210_MCT(obj); SysBusDevice *dev = SYS_BUS_DEVICE(obj); - QEMUBH *bh[2]; /* Global timer */ s->g_timer.ptimer_frc = ptimer_init(exynos4210_gfrc_event, s, @@ -1495,9 +1514,9 @@ static void exynos4210_mct_init(Object *obj) /* Local timers */ for (i = 0; i < 2; i++) { - bh[0] = qemu_bh_new(exynos4210_ltick_event, &s->l_timer[i]); s->l_timer[i].tick_timer.ptimer_tick = - ptimer_init_with_bh(bh[0], PTIMER_POLICY_DEFAULT); + ptimer_init(exynos4210_ltick_event, &s->l_timer[i], + PTIMER_POLICY_DEFAULT); s->l_timer[i].ptimer_frc = ptimer_init(exynos4210_lfrc_event, &s->l_timer[i], PTIMER_POLICY_DEFAULT); -- cgit v1.1 From b1b104ed977177ad72573333b592314c5f626d56 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 8 Oct 2019 18:17:33 +0100 Subject: hw/timer/exynos4210_pwm.c: Switch to transaction-based ptimer API Switch the exynos4210_pwm 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 Reviewed-by: Richard Henderson Message-id: 20191008171740.9679-15-peter.maydell@linaro.org --- hw/timer/exynos4210_pwm.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) (limited to 'hw/timer') diff --git a/hw/timer/exynos4210_pwm.c b/hw/timer/exynos4210_pwm.c index aa5dca6..59a8c08 100644 --- a/hw/timer/exynos4210_pwm.c +++ b/hw/timer/exynos4210_pwm.c @@ -25,7 +25,6 @@ #include "hw/sysbus.h" #include "migration/vmstate.h" #include "qemu/timer.h" -#include "qemu/main-loop.h" #include "qemu/module.h" #include "hw/ptimer.h" @@ -150,7 +149,9 @@ static const VMStateDescription vmstate_exynos4210_pwm_state = { }; /* - * PWM update frequency + * PWM update frequency. + * Must be called within a ptimer_transaction_begin/commit block + * for s->timer[id].ptimer. */ static void exynos4210_pwm_update_freq(Exynos4210PWMState *s, uint32_t id) { @@ -281,12 +282,15 @@ static void exynos4210_pwm_write(void *opaque, hwaddr offset, /* update timers frequencies */ for (i = 0; i < EXYNOS4210_PWM_TIMERS_NUM; i++) { + ptimer_transaction_begin(s->timer[i].ptimer); exynos4210_pwm_update_freq(s, s->timer[i].id); + ptimer_transaction_commit(s->timer[i].ptimer); } break; case TCON: for (i = 0; i < EXYNOS4210_PWM_TIMERS_NUM; i++) { + ptimer_transaction_begin(s->timer[i].ptimer); if ((value & TCON_TIMER_MANUAL_UPD(i)) > (s->reg_tcon & TCON_TIMER_MANUAL_UPD(i))) { /* @@ -315,6 +319,7 @@ static void exynos4210_pwm_write(void *opaque, hwaddr offset, ptimer_stop(s->timer[i].ptimer); DPRINTF("stop timer %d\n", i); } + ptimer_transaction_commit(s->timer[i].ptimer); } s->reg_tcon = value; break; @@ -369,8 +374,10 @@ static void exynos4210_pwm_reset(DeviceState *d) s->timer[i].reg_tcmpb = 0; s->timer[i].reg_tcntb = 0; + ptimer_transaction_begin(s->timer[i].ptimer); exynos4210_pwm_update_freq(s, s->timer[i].id); ptimer_stop(s->timer[i].ptimer); + ptimer_transaction_commit(s->timer[i].ptimer); } } @@ -388,12 +395,12 @@ static void exynos4210_pwm_init(Object *obj) Exynos4210PWMState *s = EXYNOS4210_PWM(obj); SysBusDevice *dev = SYS_BUS_DEVICE(obj); int i; - QEMUBH *bh; for (i = 0; i < EXYNOS4210_PWM_TIMERS_NUM; i++) { - bh = qemu_bh_new(exynos4210_pwm_tick, &s->timer[i]); sysbus_init_irq(dev, &s->timer[i].irq); - s->timer[i].ptimer = ptimer_init_with_bh(bh, PTIMER_POLICY_DEFAULT); + s->timer[i].ptimer = ptimer_init(exynos4210_pwm_tick, + &s->timer[i], + PTIMER_POLICY_DEFAULT); s->timer[i].id = i; s->timer[i].parent = s; } -- cgit v1.1 From 2dd20308f77d544478b8d335b8929404f5eb2f4b Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 8 Oct 2019 18:17:34 +0100 Subject: hw/timer/exynos4210_rtc.c: Switch 1Hz ptimer to transaction-based API Switch the exynos41210_rtc 1Hz ptimer over to the transaction-based API. (We will switch the other ptimer used by this device in a separate commit.) Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20191008171740.9679-16-peter.maydell@linaro.org --- hw/timer/exynos4210_rtc.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'hw/timer') diff --git a/hw/timer/exynos4210_rtc.c b/hw/timer/exynos4210_rtc.c index d5d7c91..b7ae99e 100644 --- a/hw/timer/exynos4210_rtc.c +++ b/hw/timer/exynos4210_rtc.c @@ -401,6 +401,7 @@ static void exynos4210_rtc_write(void *opaque, hwaddr offset, } break; case RTCCON: + ptimer_transaction_begin(s->ptimer_1Hz); if (value & RTC_ENABLE) { exynos4210_rtc_update_freq(s, value); } @@ -430,6 +431,7 @@ static void exynos4210_rtc_write(void *opaque, hwaddr offset, ptimer_stop(s->ptimer); } } + ptimer_transaction_commit(s->ptimer_1Hz); s->reg_rtccon = value; break; case TICCNT: @@ -539,7 +541,9 @@ static void exynos4210_rtc_reset(DeviceState *d) exynos4210_rtc_update_freq(s, s->reg_rtccon); ptimer_stop(s->ptimer); + ptimer_transaction_begin(s->ptimer_1Hz); ptimer_stop(s->ptimer_1Hz); + ptimer_transaction_commit(s->ptimer_1Hz); } static const MemoryRegionOps exynos4210_rtc_ops = { @@ -562,9 +566,11 @@ static void exynos4210_rtc_init(Object *obj) ptimer_set_freq(s->ptimer, RTC_BASE_FREQ); exynos4210_rtc_update_freq(s, 0); - bh = qemu_bh_new(exynos4210_rtc_1Hz_tick, s); - s->ptimer_1Hz = ptimer_init_with_bh(bh, PTIMER_POLICY_DEFAULT); + s->ptimer_1Hz = ptimer_init(exynos4210_rtc_1Hz_tick, + s, PTIMER_POLICY_DEFAULT); + ptimer_transaction_begin(s->ptimer_1Hz); ptimer_set_freq(s->ptimer_1Hz, RTC_BASE_FREQ); + ptimer_transaction_commit(s->ptimer_1Hz); sysbus_init_irq(dev, &s->alm_irq); sysbus_init_irq(dev, &s->tick_irq); -- cgit v1.1 From 82c7f5faefeefec62e90f2764bc9bda4717007bb Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 8 Oct 2019 18:17:35 +0100 Subject: hw/timer/exynos4210_rtc.c: Switch main ptimer to transaction-based API Switch the exynos41210_rtc main ptimer over to the transaction-based API, completing the transition for this device. Signed-off-by: Peter Maydell Reviewed-by: Richard Henderson Message-id: 20191008171740.9679-17-peter.maydell@linaro.org --- hw/timer/exynos4210_rtc.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'hw/timer') diff --git a/hw/timer/exynos4210_rtc.c b/hw/timer/exynos4210_rtc.c index b7ae99e..f85483a 100644 --- a/hw/timer/exynos4210_rtc.c +++ b/hw/timer/exynos4210_rtc.c @@ -28,7 +28,6 @@ #include "qemu/osdep.h" #include "qemu-common.h" #include "qemu/log.h" -#include "qemu/main-loop.h" #include "qemu/module.h" #include "hw/sysbus.h" #include "migration/vmstate.h" @@ -195,6 +194,7 @@ static void check_alarm_raise(Exynos4210RTCState *s) * RTC update frequency * Parameters: * reg_value - current RTCCON register or his new value + * Must be called within a ptimer_transaction_begin/commit block for s->ptimer. */ static void exynos4210_rtc_update_freq(Exynos4210RTCState *s, uint32_t reg_value) @@ -402,6 +402,7 @@ static void exynos4210_rtc_write(void *opaque, hwaddr offset, break; case RTCCON: ptimer_transaction_begin(s->ptimer_1Hz); + ptimer_transaction_begin(s->ptimer); if (value & RTC_ENABLE) { exynos4210_rtc_update_freq(s, value); } @@ -432,6 +433,7 @@ static void exynos4210_rtc_write(void *opaque, hwaddr offset, } } ptimer_transaction_commit(s->ptimer_1Hz); + ptimer_transaction_commit(s->ptimer); s->reg_rtccon = value; break; case TICCNT: @@ -539,8 +541,10 @@ static void exynos4210_rtc_reset(DeviceState *d) s->reg_curticcnt = 0; + ptimer_transaction_begin(s->ptimer); exynos4210_rtc_update_freq(s, s->reg_rtccon); ptimer_stop(s->ptimer); + ptimer_transaction_commit(s->ptimer); ptimer_transaction_begin(s->ptimer_1Hz); ptimer_stop(s->ptimer_1Hz); ptimer_transaction_commit(s->ptimer_1Hz); @@ -559,12 +563,12 @@ static void exynos4210_rtc_init(Object *obj) { Exynos4210RTCState *s = EXYNOS4210_RTC(obj); SysBusDevice *dev = SYS_BUS_DEVICE(obj); - QEMUBH *bh; - bh = qemu_bh_new(exynos4210_rtc_tick, s); - s->ptimer = ptimer_init_with_bh(bh, PTIMER_POLICY_DEFAULT); + s->ptimer = ptimer_init(exynos4210_rtc_tick, s, PTIMER_POLICY_DEFAULT); + ptimer_transaction_begin(s->ptimer); ptimer_set_freq(s->ptimer, RTC_BASE_FREQ); exynos4210_rtc_update_freq(s, 0); + ptimer_transaction_commit(s->ptimer); s->ptimer_1Hz = ptimer_init(exynos4210_rtc_1Hz_tick, s, PTIMER_POLICY_DEFAULT); -- cgit v1.1 From cc2722ec83ad944505fe9371fc4a94efdf4fe90f Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 8 Oct 2019 18:17:36 +0100 Subject: hw/timer/imx_epit.c: Switch to transaction-based ptimer API Switch the imx_epit.c 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 Reviewed-by: Richard Henderson Message-id: 20191008171740.9679-18-peter.maydell@linaro.org --- hw/timer/imx_epit.c | 32 +++++++++++++++++++++++++++----- 1 file changed, 27 insertions(+), 5 deletions(-) (limited to 'hw/timer') diff --git a/hw/timer/imx_epit.c b/hw/timer/imx_epit.c index 39810ac..baf6338 100644 --- a/hw/timer/imx_epit.c +++ b/hw/timer/imx_epit.c @@ -17,7 +17,6 @@ #include "migration/vmstate.h" #include "hw/irq.h" #include "hw/misc/imx_ccm.h" -#include "qemu/main-loop.h" #include "qemu/module.h" #include "qemu/log.h" @@ -74,6 +73,10 @@ static void imx_epit_update_int(IMXEPITState *s) } } +/* + * Must be called from within a ptimer_transaction_begin/commit block + * for both s->timer_cmp and s->timer_reload. + */ static void imx_epit_set_freq(IMXEPITState *s) { uint32_t clksrc; @@ -105,6 +108,8 @@ static void imx_epit_reset(DeviceState *dev) s->lr = EPIT_TIMER_MAX; s->cmp = 0; s->cnt = 0; + ptimer_transaction_begin(s->timer_cmp); + ptimer_transaction_begin(s->timer_reload); /* stop both timers */ ptimer_stop(s->timer_cmp); ptimer_stop(s->timer_reload); @@ -117,6 +122,8 @@ static void imx_epit_reset(DeviceState *dev) /* if the timer is still enabled, restart it */ ptimer_run(s->timer_reload, 0); } + ptimer_transaction_commit(s->timer_cmp); + ptimer_transaction_commit(s->timer_reload); } static uint32_t imx_epit_update_count(IMXEPITState *s) @@ -164,6 +171,7 @@ static uint64_t imx_epit_read(void *opaque, hwaddr offset, unsigned size) return reg_value; } +/* Must be called from ptimer_transaction_begin/commit block for s->timer_cmp */ static void imx_epit_reload_compare_timer(IMXEPITState *s) { if ((s->cr & (CR_EN | CR_OCIEN)) == (CR_EN | CR_OCIEN)) { @@ -191,6 +199,8 @@ static void imx_epit_write(void *opaque, hwaddr offset, uint64_t value, switch (offset >> 2) { case 0: /* CR */ + ptimer_transaction_begin(s->timer_cmp); + ptimer_transaction_begin(s->timer_reload); oldcr = s->cr; s->cr = value & 0x03ffffff; @@ -231,6 +241,9 @@ static void imx_epit_write(void *opaque, hwaddr offset, uint64_t value, } else { ptimer_stop(s->timer_cmp); } + + ptimer_transaction_commit(s->timer_cmp); + ptimer_transaction_commit(s->timer_reload); break; case 1: /* SR - ACK*/ @@ -244,6 +257,8 @@ static void imx_epit_write(void *opaque, hwaddr offset, uint64_t value, case 2: /* LR - set ticks */ s->lr = value; + ptimer_transaction_begin(s->timer_cmp); + ptimer_transaction_begin(s->timer_reload); if (s->cr & CR_RLD) { /* Also set the limit if the LRD bit is set */ /* If IOVW bit is set then set the timer value */ @@ -255,12 +270,16 @@ static void imx_epit_write(void *opaque, hwaddr offset, uint64_t value, } imx_epit_reload_compare_timer(s); + ptimer_transaction_commit(s->timer_cmp); + ptimer_transaction_commit(s->timer_reload); break; case 3: /* CMP */ s->cmp = value; + ptimer_transaction_begin(s->timer_cmp); imx_epit_reload_compare_timer(s); + ptimer_transaction_commit(s->timer_cmp); break; @@ -281,6 +300,11 @@ static void imx_epit_cmp(void *opaque) imx_epit_update_int(s); } +static void imx_epit_reload(void *opaque) +{ + /* No action required on rollover of timer_reload */ +} + static const MemoryRegionOps imx_epit_ops = { .read = imx_epit_read, .write = imx_epit_write, @@ -308,7 +332,6 @@ static void imx_epit_realize(DeviceState *dev, Error **errp) { IMXEPITState *s = IMX_EPIT(dev); SysBusDevice *sbd = SYS_BUS_DEVICE(dev); - QEMUBH *bh; DPRINTF("\n"); @@ -317,10 +340,9 @@ static void imx_epit_realize(DeviceState *dev, Error **errp) 0x00001000); sysbus_init_mmio(sbd, &s->iomem); - s->timer_reload = ptimer_init_with_bh(NULL, PTIMER_POLICY_DEFAULT); + s->timer_reload = ptimer_init(imx_epit_reload, s, PTIMER_POLICY_DEFAULT); - bh = qemu_bh_new(imx_epit_cmp, s); - s->timer_cmp = ptimer_init_with_bh(bh, PTIMER_POLICY_DEFAULT); + s->timer_cmp = ptimer_init(imx_epit_cmp, s, PTIMER_POLICY_DEFAULT); } static void imx_epit_class_init(ObjectClass *klass, void *data) -- cgit v1.1 From 1b914994ea5e995f36fe751f7ed1d8858a87b032 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 8 Oct 2019 18:17:37 +0100 Subject: hw/timer/imx_gpt.c: Switch to transaction-based ptimer API Switch the imx_epit.c 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 Reviewed-by: Richard Henderson Message-id: 20191008171740.9679-19-peter.maydell@linaro.org --- hw/timer/imx_gpt.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) (limited to 'hw/timer') diff --git a/hw/timer/imx_gpt.c b/hw/timer/imx_gpt.c index c535d19..5c0d9a2 100644 --- a/hw/timer/imx_gpt.c +++ b/hw/timer/imx_gpt.c @@ -16,7 +16,6 @@ #include "hw/irq.h" #include "hw/timer/imx_gpt.h" #include "migration/vmstate.h" -#include "qemu/main-loop.h" #include "qemu/module.h" #include "qemu/log.h" @@ -127,6 +126,7 @@ static const IMXClk imx7_gpt_clocks[] = { CLK_NONE, /* 111 not defined */ }; +/* Must be called from within ptimer_transaction_begin/commit block */ static void imx_gpt_set_freq(IMXGPTState *s) { uint32_t clksrc = extract32(s->cr, GPT_CR_CLKSRC_SHIFT, 3); @@ -167,6 +167,7 @@ static inline uint32_t imx_gpt_find_limit(uint32_t count, uint32_t reg, return timeout; } +/* Must be called from within ptimer_transaction_begin/commit block */ static void imx_gpt_compute_next_timeout(IMXGPTState *s, bool event) { uint32_t timeout = GPT_TIMER_MAX; @@ -313,6 +314,7 @@ static uint64_t imx_gpt_read(void *opaque, hwaddr offset, unsigned size) static void imx_gpt_reset_common(IMXGPTState *s, bool is_soft_reset) { + ptimer_transaction_begin(s->timer); /* stop timer */ ptimer_stop(s->timer); @@ -350,6 +352,7 @@ static void imx_gpt_reset_common(IMXGPTState *s, bool is_soft_reset) if (s->freq && (s->cr & GPT_CR_EN)) { ptimer_run(s->timer, 1); } + ptimer_transaction_commit(s->timer); } static void imx_gpt_soft_reset(DeviceState *dev) @@ -382,6 +385,7 @@ static void imx_gpt_write(void *opaque, hwaddr offset, uint64_t value, imx_gpt_soft_reset(DEVICE(s)); } else { /* set our freq, as the source might have changed */ + ptimer_transaction_begin(s->timer); imx_gpt_set_freq(s); if ((oldreg ^ s->cr) & GPT_CR_EN) { @@ -397,12 +401,15 @@ static void imx_gpt_write(void *opaque, hwaddr offset, uint64_t value, ptimer_stop(s->timer); } } + ptimer_transaction_commit(s->timer); } break; case 1: /* Prescaler */ s->pr = value & 0xfff; + ptimer_transaction_begin(s->timer); imx_gpt_set_freq(s); + ptimer_transaction_commit(s->timer); break; case 2: /* SR */ @@ -414,13 +421,16 @@ static void imx_gpt_write(void *opaque, hwaddr offset, uint64_t value, s->ir = value & 0x3f; imx_gpt_update_int(s); + ptimer_transaction_begin(s->timer); imx_gpt_compute_next_timeout(s, false); + ptimer_transaction_commit(s->timer); break; case 4: /* OCR1 -- output compare register */ s->ocr1 = value; + ptimer_transaction_begin(s->timer); /* In non-freerun mode, reset count when this register is written */ if (!(s->cr & GPT_CR_FRR)) { s->next_timeout = GPT_TIMER_MAX; @@ -429,6 +439,7 @@ static void imx_gpt_write(void *opaque, hwaddr offset, uint64_t value, /* compute the new timeout */ imx_gpt_compute_next_timeout(s, false); + ptimer_transaction_commit(s->timer); break; @@ -436,7 +447,9 @@ static void imx_gpt_write(void *opaque, hwaddr offset, uint64_t value, s->ocr2 = value; /* compute the new timeout */ + ptimer_transaction_begin(s->timer); imx_gpt_compute_next_timeout(s, false); + ptimer_transaction_commit(s->timer); break; @@ -444,7 +457,9 @@ static void imx_gpt_write(void *opaque, hwaddr offset, uint64_t value, s->ocr3 = value; /* compute the new timeout */ + ptimer_transaction_begin(s->timer); imx_gpt_compute_next_timeout(s, false); + ptimer_transaction_commit(s->timer); break; @@ -484,15 +499,13 @@ static void imx_gpt_realize(DeviceState *dev, Error **errp) { IMXGPTState *s = IMX_GPT(dev); SysBusDevice *sbd = SYS_BUS_DEVICE(dev); - QEMUBH *bh; sysbus_init_irq(sbd, &s->irq); memory_region_init_io(&s->iomem, OBJECT(s), &imx_gpt_ops, s, TYPE_IMX_GPT, 0x00001000); sysbus_init_mmio(sbd, &s->iomem); - bh = qemu_bh_new(imx_gpt_timeout, s); - s->timer = ptimer_init_with_bh(bh, PTIMER_POLICY_DEFAULT); + s->timer = ptimer_init(imx_gpt_timeout, s, PTIMER_POLICY_DEFAULT); } static void imx_gpt_class_init(ObjectClass *klass, void *data) -- cgit v1.1 From 00ee4b0f485a96d91beb613ccd43044e354d97df Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Tue, 8 Oct 2019 18:17:38 +0100 Subject: hw/timer/mss-timerc: Switch to transaction-based ptimer API Switch the mss-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 Reviewed-by: Richard Henderson Message-id: 20191008171740.9679-20-peter.maydell@linaro.org --- hw/timer/mss-timer.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'hw/timer') diff --git a/hw/timer/mss-timer.c b/hw/timer/mss-timer.c index a34c240..b1c9a80 100644 --- a/hw/timer/mss-timer.c +++ b/hw/timer/mss-timer.c @@ -24,7 +24,6 @@ */ #include "qemu/osdep.h" -#include "qemu/main-loop.h" #include "qemu/module.h" #include "qemu/log.h" #include "hw/irq.h" @@ -67,6 +66,7 @@ static void timer_update_irq(struct Msf2Timer *st) qemu_set_irq(st->irq, (ier && isr)); } +/* Must be called from within a ptimer_transaction_begin/commit block */ static void timer_update(struct Msf2Timer *st) { uint64_t count; @@ -159,7 +159,9 @@ timer_write(void *opaque, hwaddr offset, switch (addr) { case R_TIM_CTRL: st->regs[R_TIM_CTRL] = value; + ptimer_transaction_begin(st->ptimer); timer_update(st); + ptimer_transaction_commit(st->ptimer); break; case R_TIM_RIS: @@ -171,7 +173,9 @@ timer_write(void *opaque, hwaddr offset, case R_TIM_LOADVAL: st->regs[R_TIM_LOADVAL] = value; if (st->regs[R_TIM_CTRL] & TIMER_CTRL_ENBL) { + ptimer_transaction_begin(st->ptimer); timer_update(st); + ptimer_transaction_commit(st->ptimer); } break; @@ -228,9 +232,10 @@ static void mss_timer_init(Object *obj) for (i = 0; i < NUM_TIMERS; i++) { struct Msf2Timer *st = &t->timers[i]; - st->bh = qemu_bh_new(timer_hit, st); - st->ptimer = ptimer_init_with_bh(st->bh, PTIMER_POLICY_DEFAULT); + st->ptimer = ptimer_init(timer_hit, st, PTIMER_POLICY_DEFAULT); + ptimer_transaction_begin(st->ptimer); ptimer_set_freq(st->ptimer, t->freq_hz); + ptimer_transaction_commit(st->ptimer); sysbus_init_irq(SYS_BUS_DEVICE(obj), &st->irq); } -- cgit v1.1 From 72d96f8e2288e4bc7b31011c0c3f00448e2cef19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Wed, 25 Sep 2019 16:32:29 +0200 Subject: aspeed/timer: Introduce an object class per SoC MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The most important changes will be on the register range 0x34 - 0x3C memops. Introduce class read/write operations to handle the differences between SoCs. Signed-off-by: Cédric Le Goater Reviewed-by: Joel Stanley Message-id: 20190925143248.10000-5-clg@kaod.org Signed-off-by: Peter Maydell --- hw/timer/aspeed_timer.c | 107 +++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 96 insertions(+), 11 deletions(-) (limited to 'hw/timer') diff --git a/hw/timer/aspeed_timer.c b/hw/timer/aspeed_timer.c index 2bda826..c78bc1b 100644 --- a/hw/timer/aspeed_timer.c +++ b/hw/timer/aspeed_timer.c @@ -253,13 +253,8 @@ static uint64_t aspeed_timer_read(void *opaque, hwaddr offset, unsigned size) case 0x40 ... 0x8c: /* Timers 5 - 8 */ value = aspeed_timer_get_value(&s->timers[(offset >> 4) - 1], reg); break; - /* Illegal */ - case 0x38: - case 0x3C: default: - qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n", - __func__, offset); - value = 0; + value = ASPEED_TIMER_GET_CLASS(s)->read(s, offset); break; } trace_aspeed_timer_read(offset, size, value); @@ -453,12 +448,8 @@ static void aspeed_timer_write(void *opaque, hwaddr offset, uint64_t value, case 0x40 ... 0x8c: aspeed_timer_set_value(s, (offset >> TIMER_NR_REGS) - 1, reg, tv); break; - /* Illegal */ - case 0x38: - case 0x3C: default: - qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n", - __func__, offset); + ASPEED_TIMER_GET_CLASS(s)->write(s, offset, value); break; } } @@ -472,6 +463,64 @@ static const MemoryRegionOps aspeed_timer_ops = { .valid.unaligned = false, }; +static uint64_t aspeed_2400_timer_read(AspeedTimerCtrlState *s, hwaddr offset) +{ + uint64_t value; + + switch (offset) { + case 0x38: + case 0x3C: + default: + qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n", + __func__, offset); + value = 0; + break; + } + return value; +} + +static void aspeed_2400_timer_write(AspeedTimerCtrlState *s, hwaddr offset, + uint64_t value) +{ + switch (offset) { + case 0x38: + case 0x3C: + default: + qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n", + __func__, offset); + break; + } +} + +static uint64_t aspeed_2500_timer_read(AspeedTimerCtrlState *s, hwaddr offset) +{ + uint64_t value; + + switch (offset) { + case 0x38: + case 0x3C: + default: + qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n", + __func__, offset); + value = 0; + break; + } + return value; +} + +static void aspeed_2500_timer_write(AspeedTimerCtrlState *s, hwaddr offset, + uint64_t value) +{ + switch (offset) { + case 0x38: + case 0x3C: + default: + qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n", + __func__, offset); + break; + } +} + static void aspeed_init_one_timer(AspeedTimerCtrlState *s, uint8_t id) { AspeedTimer *t = &s->timers[id]; @@ -570,11 +619,47 @@ static const TypeInfo aspeed_timer_info = { .parent = TYPE_SYS_BUS_DEVICE, .instance_size = sizeof(AspeedTimerCtrlState), .class_init = timer_class_init, + .class_size = sizeof(AspeedTimerClass), + .abstract = true, +}; + +static void aspeed_2400_timer_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + AspeedTimerClass *awc = ASPEED_TIMER_CLASS(klass); + + dc->desc = "ASPEED 2400 Timer"; + awc->read = aspeed_2400_timer_read; + awc->write = aspeed_2400_timer_write; +} + +static const TypeInfo aspeed_2400_timer_info = { + .name = TYPE_ASPEED_2400_TIMER, + .parent = TYPE_ASPEED_TIMER, + .class_init = aspeed_2400_timer_class_init, +}; + +static void aspeed_2500_timer_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + AspeedTimerClass *awc = ASPEED_TIMER_CLASS(klass); + + dc->desc = "ASPEED 2500 Timer"; + awc->read = aspeed_2500_timer_read; + awc->write = aspeed_2500_timer_write; +} + +static const TypeInfo aspeed_2500_timer_info = { + .name = TYPE_ASPEED_2500_TIMER, + .parent = TYPE_ASPEED_TIMER, + .class_init = aspeed_2500_timer_class_init, }; static void aspeed_timer_register_types(void) { type_register_static(&aspeed_timer_info); + type_register_static(&aspeed_2400_timer_info); + type_register_static(&aspeed_2500_timer_info); } type_init(aspeed_timer_register_types) -- cgit v1.1 From d85c87c1d1bf4353a4cb2c19988f81b9c667f7c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Wed, 25 Sep 2019 16:32:30 +0200 Subject: aspeed/timer: Add support for control register 3 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The AST2500 timer has a third control register that is used to implement a set-to-clear feature for the main control register. This models the behaviour expected by the AST2500 while maintaining the same behaviour for the AST2400. The vmstate version is not increased yet because the structure is modified again in the following patches. Based on previous work from Joel Stanley. Signed-off-by: Cédric Le Goater Reviewed-by: Joel Stanley Message-id: 20190925143248.10000-6-clg@kaod.org Signed-off-by: Peter Maydell --- hw/timer/aspeed_timer.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'hw/timer') diff --git a/hw/timer/aspeed_timer.c b/hw/timer/aspeed_timer.c index c78bc1b..d70e78a 100644 --- a/hw/timer/aspeed_timer.c +++ b/hw/timer/aspeed_timer.c @@ -498,6 +498,8 @@ static uint64_t aspeed_2500_timer_read(AspeedTimerCtrlState *s, hwaddr offset) switch (offset) { case 0x38: + value = s->ctrl3 & BIT(0); + break; case 0x3C: default: qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n", @@ -511,9 +513,24 @@ static uint64_t aspeed_2500_timer_read(AspeedTimerCtrlState *s, hwaddr offset) static void aspeed_2500_timer_write(AspeedTimerCtrlState *s, hwaddr offset, uint64_t value) { + const uint32_t tv = (uint32_t)(value & 0xFFFFFFFF); + uint8_t command; + switch (offset) { case 0x38: + command = (value >> 1) & 0xFF; + if (command == 0xAE) { + s->ctrl3 = 0x1; + } else if (command == 0xEA) { + s->ctrl3 = 0x0; + } + break; case 0x3C: + if (s->ctrl3 & BIT(0)) { + aspeed_timer_set_ctrl(s, s->ctrl & ~tv); + } + break; + default: qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n", __func__, offset); @@ -574,6 +591,7 @@ static void aspeed_timer_reset(DeviceState *dev) } s->ctrl = 0; s->ctrl2 = 0; + s->ctrl3 = 0; } static const VMStateDescription vmstate_aspeed_timer = { @@ -597,6 +615,7 @@ static const VMStateDescription vmstate_aspeed_timer_state = { .fields = (VMStateField[]) { VMSTATE_UINT32(ctrl, AspeedTimerCtrlState), VMSTATE_UINT32(ctrl2, AspeedTimerCtrlState), + VMSTATE_UINT32(ctrl3, AspeedTimerCtrlState), VMSTATE_STRUCT_ARRAY(timers, AspeedTimerCtrlState, ASPEED_TIMER_NR_TIMERS, 1, vmstate_aspeed_timer, AspeedTimer), -- cgit v1.1 From c20375dd8678eae2462a986938e6d119cb5abefa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Wed, 25 Sep 2019 16:32:31 +0200 Subject: aspeed/timer: Add AST2600 support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The AST2600 timer has a third control register that is used to implement a set-to-clear feature for the main control register. On the AST2600, it is not configurable via 0x38 (control register 3) as it is on the AST2500. Based on previous work from Joel Stanley. Signed-off-by: Cédric Le Goater Reviewed-by: Joel Stanley Message-id: 20190925143248.10000-7-clg@kaod.org Signed-off-by: Peter Maydell --- hw/timer/aspeed_timer.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) (limited to 'hw/timer') diff --git a/hw/timer/aspeed_timer.c b/hw/timer/aspeed_timer.c index d70e78a..7f73d0c 100644 --- a/hw/timer/aspeed_timer.c +++ b/hw/timer/aspeed_timer.c @@ -538,6 +538,40 @@ static void aspeed_2500_timer_write(AspeedTimerCtrlState *s, hwaddr offset, } } +static uint64_t aspeed_2600_timer_read(AspeedTimerCtrlState *s, hwaddr offset) +{ + uint64_t value; + + switch (offset) { + case 0x38: + case 0x3C: + default: + qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n", + __func__, offset); + value = 0; + break; + } + return value; +} + +static void aspeed_2600_timer_write(AspeedTimerCtrlState *s, hwaddr offset, + uint64_t value) +{ + const uint32_t tv = (uint32_t)(value & 0xFFFFFFFF); + + switch (offset) { + case 0x3C: + aspeed_timer_set_ctrl(s, s->ctrl & ~tv); + break; + + case 0x38: + default: + qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIx "\n", + __func__, offset); + break; + } +} + static void aspeed_init_one_timer(AspeedTimerCtrlState *s, uint8_t id) { AspeedTimer *t = &s->timers[id]; @@ -674,11 +708,28 @@ static const TypeInfo aspeed_2500_timer_info = { .class_init = aspeed_2500_timer_class_init, }; +static void aspeed_2600_timer_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + AspeedTimerClass *awc = ASPEED_TIMER_CLASS(klass); + + dc->desc = "ASPEED 2600 Timer"; + awc->read = aspeed_2600_timer_read; + awc->write = aspeed_2600_timer_write; +} + +static const TypeInfo aspeed_2600_timer_info = { + .name = TYPE_ASPEED_2600_TIMER, + .parent = TYPE_ASPEED_TIMER, + .class_init = aspeed_2600_timer_class_init, +}; + static void aspeed_timer_register_types(void) { type_register_static(&aspeed_timer_info); type_register_static(&aspeed_2400_timer_info); type_register_static(&aspeed_2500_timer_info); + type_register_static(&aspeed_2600_timer_info); } type_init(aspeed_timer_register_types) -- cgit v1.1 From fadefada4d07a3a77c4171244cded0e9af81331c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Le=20Goater?= Date: Wed, 25 Sep 2019 16:32:32 +0200 Subject: aspeed/timer: Add support for IRQ status register on the AST2600 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The AST2600 timer replaces control register 2 with a interrupt status register. It is set by hardware when an IRQ occurs and cleared by software. Modify the vmstate version to take into account the new fields. Based on previous work from Joel Stanley. Signed-off-by: Cédric Le Goater Reviewed-by: Joel Stanley Message-id: 20190925143248.10000-8-clg@kaod.org Signed-off-by: Peter Maydell --- hw/timer/aspeed_timer.c | 36 ++++++++++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 8 deletions(-) (limited to 'hw/timer') diff --git a/hw/timer/aspeed_timer.c b/hw/timer/aspeed_timer.c index 7f73d0c..bcce219 100644 --- a/hw/timer/aspeed_timer.c +++ b/hw/timer/aspeed_timer.c @@ -160,7 +160,9 @@ static uint64_t calculate_next(struct AspeedTimer *t) timer_del(&t->timer); if (timer_overflow_interrupt(t)) { + AspeedTimerCtrlState *s = timer_to_ctrl(t); t->level = !t->level; + s->irq_sts |= BIT(t->id); qemu_set_irq(t->irq, t->level); } @@ -199,7 +201,9 @@ static void aspeed_timer_expire(void *opaque) } if (interrupt) { + AspeedTimerCtrlState *s = timer_to_ctrl(t); t->level = !t->level; + s->irq_sts |= BIT(t->id); qemu_set_irq(t->irq, t->level); } @@ -244,9 +248,6 @@ static uint64_t aspeed_timer_read(void *opaque, hwaddr offset, unsigned size) case 0x30: /* Control Register */ value = s->ctrl; break; - case 0x34: /* Control Register 2 */ - value = s->ctrl2; - break; case 0x00 ... 0x2c: /* Timers 1 - 4 */ value = aspeed_timer_get_value(&s->timers[(offset >> 4)], reg); break; @@ -438,9 +439,6 @@ static void aspeed_timer_write(void *opaque, hwaddr offset, uint64_t value, case 0x30: aspeed_timer_set_ctrl(s, tv); break; - case 0x34: - aspeed_timer_set_ctrl2(s, tv); - break; /* Timer Registers */ case 0x00 ... 0x2c: aspeed_timer_set_value(s, (offset >> TIMER_NR_REGS), reg, tv); @@ -468,6 +466,9 @@ static uint64_t aspeed_2400_timer_read(AspeedTimerCtrlState *s, hwaddr offset) uint64_t value; switch (offset) { + case 0x34: + value = s->ctrl2; + break; case 0x38: case 0x3C: default: @@ -482,7 +483,12 @@ static uint64_t aspeed_2400_timer_read(AspeedTimerCtrlState *s, hwaddr offset) static void aspeed_2400_timer_write(AspeedTimerCtrlState *s, hwaddr offset, uint64_t value) { + const uint32_t tv = (uint32_t)(value & 0xFFFFFFFF); + switch (offset) { + case 0x34: + aspeed_timer_set_ctrl2(s, tv); + break; case 0x38: case 0x3C: default: @@ -497,6 +503,9 @@ static uint64_t aspeed_2500_timer_read(AspeedTimerCtrlState *s, hwaddr offset) uint64_t value; switch (offset) { + case 0x34: + value = s->ctrl2; + break; case 0x38: value = s->ctrl3 & BIT(0); break; @@ -517,6 +526,9 @@ static void aspeed_2500_timer_write(AspeedTimerCtrlState *s, hwaddr offset, uint8_t command; switch (offset) { + case 0x34: + aspeed_timer_set_ctrl2(s, tv); + break; case 0x38: command = (value >> 1) & 0xFF; if (command == 0xAE) { @@ -543,6 +555,9 @@ static uint64_t aspeed_2600_timer_read(AspeedTimerCtrlState *s, hwaddr offset) uint64_t value; switch (offset) { + case 0x34: + value = s->irq_sts; + break; case 0x38: case 0x3C: default: @@ -560,6 +575,9 @@ static void aspeed_2600_timer_write(AspeedTimerCtrlState *s, hwaddr offset, const uint32_t tv = (uint32_t)(value & 0xFFFFFFFF); switch (offset) { + case 0x34: + s->irq_sts &= tv; + break; case 0x3C: aspeed_timer_set_ctrl(s, s->ctrl & ~tv); break; @@ -626,6 +644,7 @@ static void aspeed_timer_reset(DeviceState *dev) s->ctrl = 0; s->ctrl2 = 0; s->ctrl3 = 0; + s->irq_sts = 0; } static const VMStateDescription vmstate_aspeed_timer = { @@ -644,12 +663,13 @@ static const VMStateDescription vmstate_aspeed_timer = { static const VMStateDescription vmstate_aspeed_timer_state = { .name = "aspeed.timerctrl", - .version_id = 1, - .minimum_version_id = 1, + .version_id = 2, + .minimum_version_id = 2, .fields = (VMStateField[]) { VMSTATE_UINT32(ctrl, AspeedTimerCtrlState), VMSTATE_UINT32(ctrl2, AspeedTimerCtrlState), VMSTATE_UINT32(ctrl3, AspeedTimerCtrlState), + VMSTATE_UINT32(irq_sts, AspeedTimerCtrlState), VMSTATE_STRUCT_ARRAY(timers, AspeedTimerCtrlState, ASPEED_TIMER_NR_TIMERS, 1, vmstate_aspeed_timer, AspeedTimer), -- cgit v1.1