From patchwork Wed Sep 7 13:22:16 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dmitry Osipenko X-Patchwork-Id: 9319267 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id DE47B60752 for ; Wed, 7 Sep 2016 13:28:20 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id C9A9C292CF for ; Wed, 7 Sep 2016 13:28:20 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id BE613292E0; Wed, 7 Sep 2016 13:28:20 +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=-6.0 required=2.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED, DKIM_SIGNED, FREEMAIL_FROM, RCVD_IN_DNSWL_HI, RCVD_IN_SORBS_WEB, T_DKIM_INVALID autolearn=ham version=3.3.1 Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 2D281292E2 for ; Wed, 7 Sep 2016 13:28:20 +0000 (UTC) Received: from localhost ([::1]:41002 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bhctn-0005Gm-49 for patchwork-qemu-devel@patchwork.kernel.org; Wed, 07 Sep 2016 09:28:19 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:46338) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bhcp1-0001Z8-M2 for qemu-devel@nongnu.org; Wed, 07 Sep 2016 09:23:24 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1bhcoz-0005fa-F6 for qemu-devel@nongnu.org; Wed, 07 Sep 2016 09:23:23 -0400 Received: from mail-lf0-x241.google.com ([2a00:1450:4010:c07::241]:35793) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bhcoz-0005fV-2X; Wed, 07 Sep 2016 09:23:21 -0400 Received: by mail-lf0-x241.google.com with SMTP id s64so834315lfs.2; Wed, 07 Sep 2016 06:23:20 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:cc:subject:date:message-id:in-reply-to:references :in-reply-to:references; bh=rGYzjLdOtI8IbtVS+tL/n0dzaPNNOyC8quB9/aLVBTA=; b=mK63B+eVRrcTeC066er6GtJqbCV/vZpK9cg5mTrabbKwsTQQ0BHllihhZg2TGjvMbY 7OqmQx9uOmNR6JbDJbu5t3TrF6lpOMoQKyW/UjHHcjhpVZjyr2FSTfpF6ptfEa7LPtWV ncS8qFkU3UfLY+VKAYf6Ho/lXihDdRpupQgEV2rN7txBjitIGiygYwFUNGv8WQIl4JEr NlvNrKPFEFpyZSZ4jcWi1CCi+EzT9MLvv294vi2dcIrYVhU6hpDdGY8NQi6cDVkhhWSs ri6KSqFaC+5LwKuwMos91mw7iG6gyrD9BrpDDGNXv/RwFTtepfxCMhHrLB8LoKbPIbkt zeQQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:in-reply-to:references; bh=rGYzjLdOtI8IbtVS+tL/n0dzaPNNOyC8quB9/aLVBTA=; b=FkmF6c4hsHBgfQ3Q5heY49vryBzQShRaMUp6D6beFmMsc5EKj1ecefY3dqk1RgXw0t i+2Ai4L5aDsdl9sYYZ+5hBHEvzq0ZpYdUunEegNPvOiIpUzKAQgU3DkiF1txoK4PLpT7 xlb9Ql9V6Og0iCRln9yfpfuSQ6AqauBzvM/lU1WL7wozqy3fkTB5BRBCBAfCXv9JdBrC ZRPEesmzQXWfoSZYVgyeAkf3BCyfn/tFFNASgIsZxA54GOgcUjYL0EQwUriS1NEmNb0l eR0B+fkEZgqp7HRdrvnCbvc0npafjOy3ZSHCE4j5CBSCV+0F3dHL4TJFAdUAW4bgwAIv RrUw== X-Gm-Message-State: AE9vXwMKv1M3RY6ocHzVGJuya2eTzYYrf56yh6uls02VHysnt8MzkakgTQ5L5Ap4x2OYDQ== X-Received: by 10.25.150.208 with SMTP id y199mr26499lfd.92.1473254600232; Wed, 07 Sep 2016 06:23:20 -0700 (PDT) Received: from localhost.localdomain (ppp109-252-52-17.pppoe.spdop.ru. [109.252.52.17]) by smtp.gmail.com with ESMTPSA id h29sm11375lfi.18.2016.09.07.06.23.19 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Wed, 07 Sep 2016 06:23:19 -0700 (PDT) From: Dmitry Osipenko To: QEMU Developers , qemu-arm@nongnu.org Date: Wed, 7 Sep 2016 16:22:16 +0300 Message-Id: <586d1643bf90bab81322ae34b9b68c10458249a9.1473252818.git.digetx@gmail.com> X-Mailer: git-send-email 2.9.3 In-Reply-To: References: In-Reply-To: References: X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 2a00:1450:4010:c07::241 Subject: [Qemu-devel] [PATCH v16 05/16] hw/ptimer: Add "wraparound after one period" policy X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Peter Maydell , Peter Crosthwaite Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" X-Virus-Scanned: ClamAV using ClamSMTP Currently, periodic counter wraps around immediately once counter reaches "0", this is wrong behaviour for some of the timers, resulting in one period being lost. Add new ptimer policy that provides correct behaviour for such timers, so that counter stays with "0" for a one period before wrapping around. Signed-off-by: Dmitry Osipenko --- hw/core/ptimer.c | 43 ++++++++++++++++++++++++++++--------------- include/hw/ptimer.h | 4 ++++ 2 files changed, 32 insertions(+), 15 deletions(-) diff --git a/hw/core/ptimer.c b/hw/core/ptimer.c index c45c835..e9b2e15 100644 --- a/hw/core/ptimer.c +++ b/hw/core/ptimer.c @@ -35,16 +35,17 @@ static void ptimer_trigger(ptimer_state *s) } } -static void ptimer_reload(ptimer_state *s) +static void ptimer_reload(ptimer_state *s, int delta_adjust) { uint32_t period_frac = s->period_frac; uint64_t period = s->period; + uint64_t delta = s->delta; - if (s->delta == 0) { + if (delta == 0) { ptimer_trigger(s); - s->delta = s->limit; + delta = s->delta = s->limit; } - if (s->delta == 0 || s->period == 0) { + if (delta == 0 || s->period == 0) { if (!qtest_enabled()) { fprintf(stderr, "Timer with period zero, disabling\n"); } @@ -53,6 +54,10 @@ static void ptimer_reload(ptimer_state *s) return; } + if (s->policy_mask & PTIMER_POLICY_WRAP_AFTER_ONE_PERIOD) { + delta += delta_adjust; + } + /* * Artificially limit timeout rate to something * achievable under QEMU. Otherwise, QEMU spends all @@ -62,15 +67,15 @@ static void ptimer_reload(ptimer_state *s) * on the current generation of host machines. */ - if (s->enabled == 1 && (s->delta * period < 10000) && !use_icount) { - period = 10000 / s->delta; + if (s->enabled == 1 && (delta * period < 10000) && !use_icount) { + period = 10000 / delta; period_frac = 0; } s->last_event = s->next_event; - s->next_event = s->last_event + s->delta * period; + s->next_event = s->last_event + delta * period; if (period_frac) { - s->next_event += ((int64_t)period_frac * s->delta) >> 32; + s->next_event += ((int64_t)period_frac * delta) >> 32; } timer_mod(s->timer, s->next_event); } @@ -83,7 +88,7 @@ static void ptimer_tick(void *opaque) if (s->enabled == 2) { s->enabled = 0; } else { - ptimer_reload(s); + ptimer_reload(s, 1); } } @@ -91,7 +96,7 @@ uint64_t ptimer_get_count(ptimer_state *s) { uint64_t counter; - if (s->enabled) { + if (s->enabled && s->delta != 0) { int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); int64_t next = s->next_event; bool expired = (now - next >= 0); @@ -145,6 +150,14 @@ uint64_t ptimer_get_count(ptimer_state *s) div += 1; } counter = rem / div; + + if (!oneshot && s->delta == s->limit) { + /* Before wrapping around, timer should stay with counter = 0 + for a one period. The delta has been adjusted by +1 for + the wrapped around counter, so taking a modulo of limit + 1 + gives that period. */ + counter %= s->limit + 1; + } } } else { counter = s->delta; @@ -157,7 +170,7 @@ void ptimer_set_count(ptimer_state *s, uint64_t count) s->delta = count; if (s->enabled) { s->next_event = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); - ptimer_reload(s); + ptimer_reload(s, 0); } } @@ -174,7 +187,7 @@ void ptimer_run(ptimer_state *s, int oneshot) s->enabled = oneshot ? 2 : 1; if (was_disabled) { s->next_event = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); - ptimer_reload(s); + ptimer_reload(s, 0); } } @@ -198,7 +211,7 @@ void ptimer_set_period(ptimer_state *s, int64_t period) s->period_frac = 0; if (s->enabled) { s->next_event = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); - ptimer_reload(s); + ptimer_reload(s, 0); } } @@ -210,7 +223,7 @@ void ptimer_set_freq(ptimer_state *s, uint32_t freq) s->period_frac = (1000000000ll << 32) / freq; if (s->enabled) { s->next_event = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); - ptimer_reload(s); + ptimer_reload(s, 0); } } @@ -223,7 +236,7 @@ void ptimer_set_limit(ptimer_state *s, uint64_t limit, int reload) s->delta = limit; if (s->enabled && reload) { s->next_event = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); - ptimer_reload(s); + ptimer_reload(s, 0); } } diff --git a/include/hw/ptimer.h b/include/hw/ptimer.h index 7b0fc13..a13a12e 100644 --- a/include/hw/ptimer.h +++ b/include/hw/ptimer.h @@ -34,6 +34,10 @@ * counter = counter value at the moment of change (.i.e. one less). */ #define PTIMER_POLICY_DEFAULT 0 +/* Periodic timer counter stays with "0" for a one period before wrapping + * around. */ +#define PTIMER_POLICY_WRAP_AFTER_ONE_PERIOD (1 << 0) + /* ptimer.c */ typedef struct ptimer_state ptimer_state; typedef void (*ptimer_cb)(void *opaque);