From patchwork Tue Jun 18 16:52:57 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?C=C3=A9dric_Le_Goater?= X-Patchwork-Id: 11002383 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 16E5B6C5 for ; Tue, 18 Jun 2019 17:32:31 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id EC9B728B00 for ; Tue, 18 Jun 2019 17:32:30 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id E102F28B2B; Tue, 18 Jun 2019 17:32:30 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-5.2 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1 Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id D0DE828B00 for ; Tue, 18 Jun 2019 17:32:29 +0000 (UTC) Received: from localhost ([::1]:60552 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.86_2) (envelope-from ) id 1hdHy9-0006am-8g for patchwork-qemu-devel@patchwork.kernel.org; Tue, 18 Jun 2019 13:32:29 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:60609) by lists.gnu.org with esmtp (Exim 4.86_2) (envelope-from ) id 1hdHNL-0000GV-2L for qemu-devel@nongnu.org; Tue, 18 Jun 2019 12:54:28 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1hdHNJ-0004WW-Dh for qemu-devel@nongnu.org; Tue, 18 Jun 2019 12:54:26 -0400 Received: from 6.mo1.mail-out.ovh.net ([46.105.43.205]:36949) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1hdHNH-0004Ip-D5 for qemu-devel@nongnu.org; Tue, 18 Jun 2019 12:54:25 -0400 Received: from player157.ha.ovh.net (unknown [10.109.159.132]) by mo1.mail-out.ovh.net (Postfix) with ESMTP id 21AF217F201 for ; Tue, 18 Jun 2019 18:54:13 +0200 (CEST) Received: from kaod.org (lfbn-1-10649-41.w90-89.abo.wanadoo.fr [90.89.235.41]) (Authenticated sender: clg@kaod.org) by player157.ha.ovh.net (Postfix) with ESMTPSA id 2E4ED6EB527C; Tue, 18 Jun 2019 16:54:07 +0000 (UTC) From: =?utf-8?q?C=C3=A9dric_Le_Goater?= To: Peter Maydell Date: Tue, 18 Jun 2019 18:52:57 +0200 Message-Id: <20190618165311.27066-8-clg@kaod.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20190618165311.27066-1-clg@kaod.org> References: <20190618165311.27066-1-clg@kaod.org> MIME-Version: 1.0 X-Ovh-Tracer-Id: 1672242837034666769 X-VR-SPAMSTATE: OK X-VR-SPAMSCORE: -100 X-VR-SPAMCAUSE: gggruggvucftvghtrhhoucdtuddrgeduvddrtddtgdejjecutefuodetggdotefrodftvfcurfhrohhfihhlvgemucfqggfjpdevjffgvefmvefgnecuuegrihhlohhuthemucehtddtnecusecvtfgvtghiphhivghnthhsucdlqddutddtmd X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 46.105.43.205 Subject: [Qemu-devel] [PATCH v2 07/21] aspeed/timer: Fix behaviour running Linux X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Andrew Jeffery , =?utf-8?q?C=C3=A9dric_Le_Goater?= , qemu-arm@nongnu.org, qemu-devel@nongnu.org, Joel Stanley Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" X-Virus-Scanned: ClamAV using ClamSMTP From: Joel Stanley 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 [clg: - merged a fix from Andrew Jeffery "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 --- 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 2c3a4d0fe770..537f072cf87f 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)