[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-arm] [PATCH 08/19] aspeed/timer: Fix behaviour running Linux
From: |
Cédric Le Goater |
Subject: |
[Qemu-arm] [PATCH 08/19] aspeed/timer: Fix behaviour running Linux |
Date: |
Sat, 25 May 2019 17:12:30 +0200 |
From: Joel Stanley <address@hidden>
The Linux kernel driver was updated in commit 4451d3f59f2a
("clocksource/drivers/fttmr010: Fix set_next_event handler) to fix an
issue observed on hardware:
> RELOAD register is loaded into COUNT register when the aspeed timer
> is enabled, which means the next event may be delayed because timer
> interrupt won't be generated until <0xFFFFFFFF - current_count +
> cycles>.
When running under Qemu, the system appeared "laggy". The guest is now
scheduling timer events too regularly, starving the host of CPU time.
This patch modifies the timer model to attempt to schedule the timer
expiry as the guest requests, but if we have missed the deadline we
re interrupt and try again, which allows the guest to catch up.
Provides expected behaviour with old and new guest code.
Fixes: c04bd47db6b9 ("hw/timer: Add ASPEED timer device model")
Signed-off-by: Joel Stanley <address@hidden>
[clg: - merged a fix from Andrew Jeffery <address@hidden>
"Fire interrupt on failure to meet deadline"
https://lists.ozlabs.org/pipermail/openbmc/2019-January/014641.html
- adapted commit log
- checkpatch fixes ]
Signed-off-by: Cédric Le Goater <address@hidden>
---
hw/timer/aspeed_timer.c | 59 ++++++++++++++++++++++-------------------
1 file changed, 31 insertions(+), 28 deletions(-)
diff --git a/hw/timer/aspeed_timer.c b/hw/timer/aspeed_timer.c
index 5c786e512815..9ffd8e09f670 100644
--- a/hw/timer/aspeed_timer.c
+++ b/hw/timer/aspeed_timer.c
@@ -109,37 +109,40 @@ static inline uint64_t calculate_time(struct AspeedTimer
*t, uint32_t ticks)
static uint64_t calculate_next(struct AspeedTimer *t)
{
- uint64_t next = 0;
- uint32_t rate = calculate_rate(t);
+ uint64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+ uint64_t next;
- while (!next) {
- /* We don't know the relationship between the values in the match
- * registers, so sort using MAX/MIN/zero. We sort in that order as the
- * timer counts down to zero. */
- uint64_t seq[] = {
- calculate_time(t, MAX(t->match[0], t->match[1])),
- calculate_time(t, MIN(t->match[0], t->match[1])),
- calculate_time(t, 0),
- };
- uint64_t reload_ns;
- uint64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
-
- if (now < seq[0]) {
- next = seq[0];
- } else if (now < seq[1]) {
- next = seq[1];
- } else if (now < seq[2]) {
- next = seq[2];
- } else if (t->reload) {
- reload_ns = muldiv64(t->reload, NANOSECONDS_PER_SECOND, rate);
- t->start = now - ((now - t->start) % reload_ns);
- } else {
- /* no reload value, return 0 */
- break;
- }
+ /*
+ * We don't know the relationship between the values in the match
+ * registers, so sort using MAX/MIN/zero. We sort in that order as
+ * the timer counts down to zero.
+ */
+
+ next = calculate_time(t, MAX(t->match[0], t->match[1]));
+ if (now < next) {
+ return next;
+ }
+
+ next = calculate_time(t, MIN(t->match[0], t->match[1]));
+ if (now < next) {
+ return next;
+ }
+
+ next = calculate_time(t, 0);
+ if (now < next) {
+ return next;
+ }
+
+ /* We've missed all deadlines, fire interrupt and try again */
+ timer_del(&t->timer);
+
+ if (timer_overflow_interrupt(t)) {
+ t->level = !t->level;
+ qemu_set_irq(t->irq, t->level);
}
- return next;
+ t->start = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+ return calculate_time(t, MAX(MAX(t->match[0], t->match[1]), 0));
}
static void aspeed_timer_mod(AspeedTimer *t)
--
2.20.1
- [Qemu-arm] [PATCH 00/19] aspeed: machine extensions and fixes, Cédric Le Goater, 2019/05/25
- [Qemu-arm] [PATCH 01/19] hw/arm/aspeed: Use object_initialize_child for correct ref. counting, Cédric Le Goater, 2019/05/25
- [Qemu-arm] [PATCH 02/19] aspeed: add a per SoC mapping for the interrupt space, Cédric Le Goater, 2019/05/25
- [Qemu-arm] [PATCH 03/19] aspeed: add a per SoC mapping for the memory space, Cédric Le Goater, 2019/05/25
- [Qemu-arm] [PATCH 05/19] hw/arm/aspeed: Add RTC to SoC, Cédric Le Goater, 2019/05/25
- [Qemu-arm] [PATCH 04/19] hw: timer: Add ASPEED RTC device, Cédric Le Goater, 2019/05/25
- [Qemu-arm] [PATCH 06/19] aspeed: introduce a configurable number of CPU per machine, Cédric Le Goater, 2019/05/25
- [Qemu-arm] [PATCH 07/19] aspeed: add support for multiple NICs, Cédric Le Goater, 2019/05/25
- [Qemu-arm] [PATCH 08/19] aspeed/timer: Fix behaviour running Linux,
Cédric Le Goater <=
- [Qemu-arm] [PATCH 09/19] aspeed/timer: Status register contains reload for stopped timer, Cédric Le Goater, 2019/05/25
- [Qemu-arm] [PATCH 10/19] aspeed/timer: Fix match calculations, Cédric Le Goater, 2019/05/25
- [Qemu-arm] [PATCH 11/19] aspeed/timer: Provide back-pressure information for short periods, Cédric Le Goater, 2019/05/25
- [Qemu-arm] [PATCH 19/19] aspeed/smc: Calculate checksum on normal DMA, Cédric Le Goater, 2019/05/25
- [Qemu-arm] [PATCH 18/19] aspeed/smc: inject errors in DMA checksum, Cédric Le Goater, 2019/05/25
- [Qemu-arm] [PATCH 17/19] aspeed/smc: add DMA calibration settings, Cédric Le Goater, 2019/05/25
- [Qemu-arm] [PATCH 15/19] aspeed: add a RAM memory region container, Cédric Le Goater, 2019/05/25
- [Qemu-arm] [PATCH 16/19] aspeed/smc: add support for DMAs, Cédric Le Goater, 2019/05/25
- [Qemu-arm] [PATCH 14/19] aspeed: remove the "ram" link, Cédric Le Goater, 2019/05/25
- [Qemu-arm] [PATCH 13/19] aspeed/smc: add a 'sdram_base' propertie, Cédric Le Goater, 2019/05/25