From nobody Mon Feb 9 06:26:19 2026 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zoho.com; dkim=fail spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1495193030693520.2112192386968; Fri, 19 May 2017 04:23:50 -0700 (PDT) Received: from localhost ([::1]:57934 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dBg0a-0006GE-7n for importer@patchew.org; Fri, 19 May 2017 07:23:48 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:49313) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dBfyE-0004GV-F1 for qemu-devel@nongnu.org; Fri, 19 May 2017 07:21:23 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1dBfyC-0000tZ-Ht for qemu-devel@nongnu.org; Fri, 19 May 2017 07:21:22 -0400 Received: from mail-wm0-x242.google.com ([2a00:1450:400c:c09::242]:33789) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1dBfyC-0000t1-8T for qemu-devel@nongnu.org; Fri, 19 May 2017 07:21:20 -0400 Received: by mail-wm0-x242.google.com with SMTP id b84so1791794wmh.0 for ; Fri, 19 May 2017 04:21:20 -0700 (PDT) Received: from 640k.lan (94-39-157-43.adsl-ull.clienti.tiscali.it. [94.39.157.43]) by smtp.gmail.com with ESMTPSA id v65sm2640095wmv.5.2017.05.19.04.21.17 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 19 May 2017 04:21:18 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=sender:from:to:cc:subject:date:message-id:in-reply-to:references; bh=KHQFnnfRU4aj5x3+Aex7iEYcfgRRSUJDqZu4ep4ltuM=; b=KIBzDZyCqEJLpXbxb6d6C2hxDFuIHA2WEDd2nEOyWbS9t801/yHmc6F0/HBuQbV2kr Qq0TMvMi7vU8XJbZJoSv3J3SUGYNboRWQg4Wr4aTRJMNnlMnMO4E2Q0K5syeK2MODWE0 BoOKHPU7wvTGxaypiCJAFmjdBx2y/j42MdvxvZ4rHiNp2PCx5jOYIpR116xjtPKowvPi R7z2ZZcKmWavVNxOhWr9+no12JYybChNe44FY0/P6tq2bq146L0gKjMRrUwM2Q1us97t jRssTtli86jGHICfEOPSR+lEmzDBHsxBKZ7OxJus0xB4FwZitqM2M7XEX+Y50BrBa2Si SV9Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:from:to:cc:subject:date:message-id :in-reply-to:references; bh=KHQFnnfRU4aj5x3+Aex7iEYcfgRRSUJDqZu4ep4ltuM=; b=iJtVcpaBti+4Ch4YsVIJGxjYu4Vmty1RFckbPtph9l+bKlpfr/Lpzb1MvSnGyFY6OZ nHMer1w+K8JCVR/yOPzvFbr6rzSsdMyFXXuht2TmEfWeIpNp90i9qzx73rAMKZwaqrnI m5BaJHvNOlUTgib8xARdBabTeOEPIkuuLPA4gnl/5kN0zW0+Uiw2e/WcpvLyyIRJJhUj pjxqs2mD56SL2jrmXWuECA/a00HQmSMGMfIIYPNF+7GHRMEfdT+dMHw7OGCRw56iuZDR j13O4NO7FPg5/w+B+IKyraVk5UwmiJep18xvlXP+0BO2+AKsGbf4I7q0tx/RLjZ1d3+F jVhg== X-Gm-Message-State: AODbwcAtg4DQrUEMjKpdq2Z/xOG2lme04qPEJ6mBZGCif7q14h4LA6xD UY/IOV+eQygexgwkYig= X-Received: by 10.28.129.201 with SMTP id c192mr17187353wmd.0.1495192878874; Fri, 19 May 2017 04:21:18 -0700 (PDT) From: Paolo Bonzini To: qemu-devel@nongnu.org Date: Fri, 19 May 2017 13:20:54 +0200 Message-Id: <1495192872-27667-3-git-send-email-pbonzini@redhat.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1495192872-27667-1-git-send-email-pbonzini@redhat.com> References: <1495192872-27667-1-git-send-email-pbonzini@redhat.com> X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 2a00:1450:400c:c09::242 Subject: [Qemu-devel] [PULL 02/20] mc146818rtc: precisely count the clock for periodic timer 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: Xiao Guangrong , Tai Yunfang Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZohoMail: RDKM_2 RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" From: Tai Yunfang There are two issues in current code: 1) If the period is changed by re-configuring RegA, the coalesced irq will be scaled to reflect the new period, however, it calculates the new interrupt number like this: s->irq_coalesced =3D (s->irq_coalesced * s->period) / period; There are some clocks will be lost if they are not enough to be squeezed to a single new period that will cause the VM clock slower In order to fix the issue, we calculate the interrupt window based on the precise clock rather than period, then the clocks lost during period is scaled can be compensated properly 2) If periodic_timer_update() is called due to RegA reconfiguration, i.e, the period is updated, current time is not the start point for the next periodic timer, instead, which should start from the last interrupt, otherwise, the clock in VM will become slow This patch takes the clocks from last interrupt to current clock into account and compensates the clocks for the next interrupt, especially if a complete interrupt was lost in this window, the time can be caught up by LOST_TICK_POLICY_SLEW Signed-off-by: Tai Yunfang Signed-off-by: Xiao Guangrong Message-Id: <20170510083259.3900-3-xiaoguangrong@tencent.com> Signed-off-by: Paolo Bonzini --- hw/timer/mc146818rtc.c | 120 +++++++++++++++++++++++++++++++++++++++------= ---- 1 file changed, 97 insertions(+), 23 deletions(-) diff --git a/hw/timer/mc146818rtc.c b/hw/timer/mc146818rtc.c index 7d78391..aeb60cc 100644 --- a/hw/timer/mc146818rtc.c +++ b/hw/timer/mc146818rtc.c @@ -146,31 +146,100 @@ static void rtc_coalesced_timer(void *opaque) } #endif =20 -/* handle periodic timer */ -static void periodic_timer_update(RTCState *s, int64_t current_time) +static uint32_t rtc_periodic_clock_ticks(RTCState *s) { - int period_code, period; - int64_t cur_clock, next_irq_clock; + int period_code; + + if (!(s->cmos_data[RTC_REG_B] & REG_B_PIE)) { + return 0; + } =20 period_code =3D s->cmos_data[RTC_REG_A] & 0x0f; - if (period_code !=3D 0 - && (s->cmos_data[RTC_REG_B] & REG_B_PIE)) { - if (period_code <=3D 2) - period_code +=3D 7; - /* period in 32 Khz cycles */ - period =3D 1 << (period_code - 1); -#ifdef TARGET_I386 - if (period !=3D s->period) { - s->irq_coalesced =3D (s->irq_coalesced * s->period) / period; - DPRINTF_C("cmos: coalesced irqs scaled to %d\n", s->irq_coales= ced); - } - s->period =3D period; -#endif + if (!period_code) { + return 0; + } + + if (period_code <=3D 2) { + period_code +=3D 7; + } + + /* period in 32 Khz cycles */ + return 1 << (period_code - 1); +} + +/* + * handle periodic timer. @old_period indicates the periodic timer update + * is just due to period adjustment. + */ +static void +periodic_timer_update(RTCState *s, int64_t current_time, uint32_t old_peri= od) +{ + uint32_t period; + int64_t cur_clock, next_irq_clock, lost_clock =3D 0; + + period =3D rtc_periodic_clock_ticks(s); + + if (period) { /* compute 32 khz clock */ cur_clock =3D muldiv64(current_time, RTC_CLOCK_RATE, NANOSECONDS_PER_SECOND); =20 - next_irq_clock =3D (cur_clock & ~(period - 1)) + period; + /* + * if the periodic timer's update is due to period re-configuration, + * we should count the clock since last interrupt. + */ + if (old_period) { + int64_t last_periodic_clock, next_periodic_clock; + + next_periodic_clock =3D muldiv64(s->next_periodic_time, + RTC_CLOCK_RATE, NANOSECONDS_PER_SECOND= ); + last_periodic_clock =3D next_periodic_clock - old_period; + lost_clock =3D cur_clock - last_periodic_clock; + assert(lost_clock >=3D 0); + } + +#ifdef TARGET_I386 + /* + * s->irq_coalesced can change for two reasons: + * + * a) if one or more periodic timer interrupts have been lost, + * lost_clock will be more that a period. + * + * b) when the period may be reconfigured, we expect the OS to + * treat delayed tick as the new period. So, when switching + * from a shorter to a longer period, scale down the missing, + * because the OS will treat past delayed ticks as longer + * (leftovers are put back into lost_clock). When switching + * to a shorter period, scale up the missing ticks since the + * OS handler will treat past delayed ticks as shorter. + */ + if (s->lost_tick_policy =3D=3D LOST_TICK_POLICY_SLEW) { + uint32_t old_irq_coalesced =3D s->irq_coalesced; + + s->period =3D period; + lost_clock +=3D old_irq_coalesced * old_period; + s->irq_coalesced =3D lost_clock / s->period; + lost_clock %=3D s->period; + if (old_irq_coalesced !=3D s->irq_coalesced || + old_period !=3D s->period) { + DPRINTF_C("cmos: coalesced irqs scaled from %d to %d, " + "period scaled from %d to %d\n", old_irq_coalesc= ed, + s->irq_coalesced, old_period, s->period); + rtc_coalesced_timer_update(s); + } + } else +#endif + { + /* + * no way to compensate the interrupt if LOST_TICK_POLICY_SLEW + * is not used, we should make the time progress anyway. + */ + lost_clock =3D MIN(lost_clock, period); + } + + assert(lost_clock >=3D 0 && lost_clock <=3D period); + + next_irq_clock =3D cur_clock + period - lost_clock; s->next_periodic_time =3D muldiv64(next_irq_clock, NANOSECONDS_PER= _SECOND, RTC_CLOCK_RATE) + 1; timer_mod(s->periodic_timer, s->next_periodic_time); @@ -186,7 +255,7 @@ static void rtc_periodic_timer(void *opaque) { RTCState *s =3D opaque; =20 - periodic_timer_update(s, s->next_periodic_time); + periodic_timer_update(s, s->next_periodic_time, 0); s->cmos_data[RTC_REG_C] |=3D REG_C_PF; if (s->cmos_data[RTC_REG_B] & REG_B_PIE) { s->cmos_data[RTC_REG_C] |=3D REG_C_IRQF; @@ -391,6 +460,7 @@ static void cmos_ioport_write(void *opaque, hwaddr addr, uint64_t data, unsigned size) { RTCState *s =3D opaque; + uint32_t old_period; bool update_periodic_timer; =20 if ((addr & 1) =3D=3D 0) { @@ -425,6 +495,7 @@ static void cmos_ioport_write(void *opaque, hwaddr addr, break; case RTC_REG_A: update_periodic_timer =3D (s->cmos_data[RTC_REG_A] ^ data) & 0= x0f; + old_period =3D rtc_periodic_clock_ticks(s); =20 if ((data & 0x60) =3D=3D 0x60) { if (rtc_running(s)) { @@ -450,7 +521,8 @@ static void cmos_ioport_write(void *opaque, hwaddr addr, (s->cmos_data[RTC_REG_A] & REG_A_UIP); =20 if (update_periodic_timer) { - periodic_timer_update(s, qemu_clock_get_ns(rtc_clock)); + periodic_timer_update(s, qemu_clock_get_ns(rtc_clock), + old_period); } =20 check_update_timer(s); @@ -458,6 +530,7 @@ static void cmos_ioport_write(void *opaque, hwaddr addr, case RTC_REG_B: update_periodic_timer =3D (s->cmos_data[RTC_REG_B] ^ data) & REG_B_PIE; + old_period =3D rtc_periodic_clock_ticks(s); =20 if (data & REG_B_SET) { /* update cmos to when the rtc was stopping */ @@ -487,7 +560,8 @@ static void cmos_ioport_write(void *opaque, hwaddr addr, s->cmos_data[RTC_REG_B] =3D data; =20 if (update_periodic_timer) { - periodic_timer_update(s, qemu_clock_get_ns(rtc_clock)); + periodic_timer_update(s, qemu_clock_get_ns(rtc_clock), + old_period); } =20 check_update_timer(s); @@ -757,7 +831,7 @@ static int rtc_post_load(void *opaque, int version_id) uint64_t now =3D qemu_clock_get_ns(rtc_clock); if (now < s->next_periodic_time || now > (s->next_periodic_time + get_max_clock_jump())) { - periodic_timer_update(s, qemu_clock_get_ns(rtc_clock)); + periodic_timer_update(s, qemu_clock_get_ns(rtc_clock), 0); } } =20 @@ -822,7 +896,7 @@ static void rtc_notify_clock_reset(Notifier *notifier, = void *data) int64_t now =3D *(int64_t *)data; =20 rtc_set_date_from_host(ISA_DEVICE(s)); - periodic_timer_update(s, now); + periodic_timer_update(s, now, 0); check_update_timer(s); #ifdef TARGET_I386 if (s->lost_tick_policy =3D=3D LOST_TICK_POLICY_SLEW) { --=20 1.8.3.1