diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2019-10-15 18:15:59 +0100 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2019-10-15 18:15:59 +0100 |
commit | 69b81893bc28feb678188fbcdce52eff1609bdad (patch) | |
tree | 850e918d11bc031e9a2cd07da526dfea4af6bc65 /hw/timer | |
parent | 3af78db68176a049e2570822f64604e0692c1447 (diff) | |
parent | 19845504da1bdee4be7d0fba33da5be9efa4c11b (diff) | |
download | qemu-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.c | 12 | ||||
-rw-r--r-- | hw/timer/altera_timer.c | 2 | ||||
-rw-r--r-- | hw/timer/arm_mptimer.c | 18 | ||||
-rw-r--r-- | hw/timer/arm_timer.c | 16 | ||||
-rw-r--r-- | hw/timer/aspeed_timer.c | 213 | ||||
-rw-r--r-- | hw/timer/cmsdk-apb-dualtimer.c | 14 | ||||
-rw-r--r-- | hw/timer/cmsdk-apb-timer.c | 15 | ||||
-rw-r--r-- | hw/timer/digic-timer.c | 16 | ||||
-rw-r--r-- | hw/timer/etraxfs_timer.c | 6 | ||||
-rw-r--r-- | hw/timer/exynos4210_mct.c | 107 | ||||
-rw-r--r-- | hw/timer/exynos4210_pwm.c | 17 | ||||
-rw-r--r-- | hw/timer/exynos4210_rtc.c | 22 | ||||
-rw-r--r-- | hw/timer/grlib_gptimer.c | 2 | ||||
-rw-r--r-- | hw/timer/imx_epit.c | 32 | ||||
-rw-r--r-- | hw/timer/imx_gpt.c | 21 | ||||
-rw-r--r-- | hw/timer/lm32_timer.c | 2 | ||||
-rw-r--r-- | hw/timer/milkymist-sysctl.c | 4 | ||||
-rw-r--r-- | hw/timer/mss-timer.c | 11 | ||||
-rw-r--r-- | hw/timer/puv3_ost.c | 2 | ||||
-rw-r--r-- | hw/timer/sh_timer.c | 2 | ||||
-rw-r--r-- | hw/timer/slavio_timer.c | 2 | ||||
-rw-r--r-- | hw/timer/xilinx_timer.c | 2 |
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); } |