aboutsummaryrefslogtreecommitdiff
path: root/hw/timer
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2019-10-15 18:15:59 +0100
committerPeter Maydell <peter.maydell@linaro.org>2019-10-15 18:15:59 +0100
commit69b81893bc28feb678188fbcdce52eff1609bdad (patch)
tree850e918d11bc031e9a2cd07da526dfea4af6bc65 /hw/timer
parent3af78db68176a049e2570822f64604e0692c1447 (diff)
parent19845504da1bdee4be7d0fba33da5be9efa4c11b (diff)
downloadqemu-69b81893bc28feb678188fbcdce52eff1609bdad.zip
qemu-69b81893bc28feb678188fbcdce52eff1609bdad.tar.gz
qemu-69b81893bc28feb678188fbcdce52eff1609bdad.tar.bz2
Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20191015' into staging
target-arm queue: * Add Aspeed AST2600 SoC support (but no new board model yet) * aspeed/wdt: Check correct register for clock source * bcm2835: code cleanups, better logging, trace events * implement v2.0 of the Arm semihosting specification * provide new 'transaction-based' ptimer API and use it for the Arm devices that use ptimers * ARM: KVM: support more than 256 CPUs # gpg: Signature made Tue 15 Oct 2019 18:09:42 BST # gpg: using RSA key E1A5C593CD419DE28E8315CF3C2525ED14360CDE # gpg: issuer "peter.maydell@linaro.org" # gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>" [ultimate] # gpg: aka "Peter Maydell <pmaydell@gmail.com>" [ultimate] # gpg: aka "Peter Maydell <pmaydell@chiark.greenend.org.uk>" [ultimate] # Primary key fingerprint: E1A5 C593 CD41 9DE2 8E83 15CF 3C25 25ED 1436 0CDE * remotes/pmaydell/tags/pull-target-arm-20191015: (67 commits) hw/misc/bcm2835_mbox: Add trace events hw/arm/bcm2835: Add various unimplemented peripherals hw/arm/bcm2835: Rename some definitions hw/arm/bcm2835_peripherals: Name various address spaces hw/arm/bcm2835_peripherals: Improve logging hw/arm/raspi: Use the IEC binary prefix definitions aspeed/soc: Add ASPEED Video stub aspeed: add support for the Aspeed MII controller of the AST2600 aspeed: Parameterise number of MACs m25p80: Add support for w25q512jv aspeed/soc: Add AST2600 support aspeed: Introduce an object class per SoC aspeed/i2c: Add AST2600 support aspeed/i2c: Introduce an object class per SoC hw/gpio: Add in AST2600 specific implementation aspeed/smc: Add AST2600 support aspeed/smc: Introduce segment operations hw: wdt_aspeed: Add AST2600 support watchdog/aspeed: Introduce an object class per SoC aspeed/sdmc: Add AST2600 support ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'hw/timer')
-rw-r--r--hw/timer/allwinner-a10-pit.c12
-rw-r--r--hw/timer/altera_timer.c2
-rw-r--r--hw/timer/arm_mptimer.c18
-rw-r--r--hw/timer/arm_timer.c16
-rw-r--r--hw/timer/aspeed_timer.c213
-rw-r--r--hw/timer/cmsdk-apb-dualtimer.c14
-rw-r--r--hw/timer/cmsdk-apb-timer.c15
-rw-r--r--hw/timer/digic-timer.c16
-rw-r--r--hw/timer/etraxfs_timer.c6
-rw-r--r--hw/timer/exynos4210_mct.c107
-rw-r--r--hw/timer/exynos4210_pwm.c17
-rw-r--r--hw/timer/exynos4210_rtc.c22
-rw-r--r--hw/timer/grlib_gptimer.c2
-rw-r--r--hw/timer/imx_epit.c32
-rw-r--r--hw/timer/imx_gpt.c21
-rw-r--r--hw/timer/lm32_timer.c2
-rw-r--r--hw/timer/milkymist-sysctl.c4
-rw-r--r--hw/timer/mss-timer.c11
-rw-r--r--hw/timer/puv3_ost.c2
-rw-r--r--hw/timer/sh_timer.c2
-rw-r--r--hw/timer/slavio_timer.c2
-rw-r--r--hw/timer/xilinx_timer.c2
22 files changed, 448 insertions, 90 deletions
diff --git a/hw/timer/allwinner-a10-pit.c b/hw/timer/allwinner-a10-pit.c
index ca5a905..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(bh[i], PTIMER_POLICY_DEFAULT);
+ s->timer[i] = ptimer_init(a10_pit_timer_cb, tc, 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..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);
}
}
@@ -228,7 +237,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);
@@ -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(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);
@@ -311,7 +319,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..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(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;
}
diff --git a/hw/timer/aspeed_timer.c b/hw/timer/aspeed_timer.c
index 2bda826..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,22 +248,14 @@ 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;
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);
@@ -443,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);
@@ -453,12 +446,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 +461,135 @@ 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 0x34:
+ value = s->ctrl2;
+ break;
+ 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)
+{
+ const uint32_t tv = (uint32_t)(value & 0xFFFFFFFF);
+
+ switch (offset) {
+ case 0x34:
+ aspeed_timer_set_ctrl2(s, tv);
+ break;
+ 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 0x34:
+ value = s->ctrl2;
+ break;
+ case 0x38:
+ value = s->ctrl3 & BIT(0);
+ break;
+ 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)
+{
+ const uint32_t tv = (uint32_t)(value & 0xFFFFFFFF);
+ uint8_t command;
+
+ switch (offset) {
+ case 0x34:
+ aspeed_timer_set_ctrl2(s, tv);
+ break;
+ 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);
+ break;
+ }
+}
+
+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:
+ 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 0x34:
+ s->irq_sts &= tv;
+ break;
+ 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];
@@ -525,6 +643,8 @@ 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 = {
@@ -543,11 +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),
@@ -570,11 +692,64 @@ 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_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)
diff --git a/hw/timer/cmsdk-apb-dualtimer.c b/hw/timer/cmsdk-apb-dualtimer.c
index 5e2352d..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(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 |
diff --git a/hw/timer/cmsdk-apb-timer.c b/hw/timer/cmsdk-apb-timer.c
index c83e265..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(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 = {
diff --git a/hw/timer/digic-timer.c b/hw/timer/digic-timer.c
index 021c4ef..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(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);
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..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"
@@ -364,6 +363,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 +385,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 +396,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 +406,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 +509,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)
{
@@ -589,6 +607,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)
{
@@ -601,6 +620,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)
{
@@ -609,12 +629,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
*/
@@ -701,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)
{
@@ -716,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)
{
@@ -733,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
*/
@@ -778,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)
@@ -851,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;
@@ -933,6 +983,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,13 +1008,13 @@ 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);
- 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[0].tick_timer.ptimer_tick, s->freq);
+ tx_ptimer_set_freq(s->l_timer[0].ptimer_frc, 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);
}
}
@@ -965,7 +1028,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));
@@ -978,7 +1043,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);
}
@@ -1144,7 +1211,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 +1237,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 +1249,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 +1268,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:
@@ -1245,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)) {
@@ -1272,8 +1348,10 @@ 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]);
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);
@@ -1284,6 +1362,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:
@@ -1295,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;
@@ -1425,20 +1506,20 @@ 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 */
- 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(exynos4210_gfrc_event, s,
+ PTIMER_POLICY_DEFAULT);
memset(&s->g_timer.reg, 0, sizeof(struct gregs));
/* 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(bh[0], PTIMER_POLICY_DEFAULT);
- s->l_timer[i].ptimer_frc = ptimer_init(bh[1], 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);
s->l_timer[i].id = i;
}
diff --git a/hw/timer/exynos4210_pwm.c b/hw/timer/exynos4210_pwm.c
index b7fad2a..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(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;
}
diff --git a/hw/timer/exynos4210_rtc.c b/hw/timer/exynos4210_rtc.c
index ea68904..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)
@@ -401,6 +401,8 @@ 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);
}
@@ -430,6 +432,8 @@ static void exynos4210_rtc_write(void *opaque, hwaddr offset,
ptimer_stop(s->ptimer);
}
}
+ ptimer_transaction_commit(s->ptimer_1Hz);
+ ptimer_transaction_commit(s->ptimer);
s->reg_rtccon = value;
break;
case TICCNT:
@@ -537,9 +541,13 @@ 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);
}
static const MemoryRegionOps exynos4210_rtc_ops = {
@@ -555,16 +563,18 @@ 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(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);
- bh = qemu_bh_new(exynos4210_rtc_1Hz_tick, s);
- s->ptimer_1Hz = ptimer_init(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);
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..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(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(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)
diff --git a/hw/timer/imx_gpt.c b/hw/timer/imx_gpt.c
index 49a441f..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(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)
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..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(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);
}
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);
}