Blame SOURCES/kvm-mc146818rtc-fix-timer-interrupt-reinjection.patch

8b1478
From ae11a1ea30f43abebd96a22988619eb9f52e6a4e Mon Sep 17 00:00:00 2001
8b1478
From: Marcelo Tosatti <mtosatti@redhat.com>
8b1478
Date: Wed, 4 Dec 2019 15:21:07 +0100
8b1478
Subject: [PATCH 1/3] mc146818rtc: fix timer interrupt reinjection
8b1478
8b1478
RH-Author: Marcelo Tosatti <mtosatti@redhat.com>
8b1478
Message-id: <20191204152436.680299856@amt.cnet>
8b1478
Patchwork-id: 92889
8b1478
O-Subject: [RHEL-7.8 qemu-kvm-rhev PATCH 1/3] mc146818rtc: fix timer interrupt reinjection
8b1478
Bugzilla: 1639098
8b1478
RH-Acked-by: Laszlo Ersek <lersek@redhat.com>
8b1478
RH-Acked-by: Paolo Bonzini <pbonzini@redhat.com>
8b1478
RH-Acked-by: Vitaly Kuznetsov <vkuznets@redhat.com>
8b1478
8b1478
BZ: 1639098
8b1478
Brew: https://brewweb.engineering.redhat.com/brew/taskinfo?taskID=24854309
8b1478
BRANCH: rhv7/master-2.12.0
8b1478
Upstream: b429de730174b388ea5760e3debb0d542ea3c261
8b1478
of pbonzini's for-upstream tree.
8b1478
8b1478
commit 369b41359af46bded5799c9ef8be2b641d92e043 broke timer interrupt
8b1478
reinjection when there is no period change by the guest.
8b1478
8b1478
In that case, old_period is 0, which ends up zeroing irq_coalesced
8b1478
(counter of reinjected interrupts).
8b1478
8b1478
The consequence is Windows 7 is unable to synchronize time via NTP.
8b1478
Easily reproducible by playing a fullscreen video with cirrus and VNC.
8b1478
8b1478
Fix by not updating s->irq_coalesced when old_period is 0.
8b1478
8b1478
V2: reorganize code (Paolo Bonzini)
8b1478
8b1478
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
8b1478
Message-Id: <20191010123008.GA19158@amt.cnet>
8b1478
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
8b1478
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
8b1478
---
8b1478
 hw/timer/mc146818rtc.c | 53 +++++++++++++++++++++++++-------------------------
8b1478
 1 file changed, 27 insertions(+), 26 deletions(-)
8b1478
8b1478
diff --git a/hw/timer/mc146818rtc.c b/hw/timer/mc146818rtc.c
8b1478
index 68c353f..296d974 100644
8b1478
--- a/hw/timer/mc146818rtc.c
8b1478
+++ b/hw/timer/mc146818rtc.c
8b1478
@@ -197,24 +197,28 @@ periodic_timer_update(RTCState *s, int64_t current_time, uint32_t old_period)
8b1478
 
8b1478
     period = rtc_periodic_clock_ticks(s);
8b1478
 
8b1478
-    if (period) {
8b1478
-        /* compute 32 khz clock */
8b1478
-        cur_clock =
8b1478
-            muldiv64(current_time, RTC_CLOCK_RATE, NANOSECONDS_PER_SECOND);
8b1478
+    if (!period) {
8b1478
+        s->irq_coalesced = 0;
8b1478
+        timer_del(s->periodic_timer);
8b1478
+        return;
8b1478
+    }
8b1478
 
8b1478
-        /*
8b1478
-        * if the periodic timer's update is due to period re-configuration,
8b1478
-        * we should count the clock since last interrupt.
8b1478
-        */
8b1478
-        if (old_period) {
8b1478
-            int64_t last_periodic_clock, next_periodic_clock;
8b1478
-
8b1478
-            next_periodic_clock = muldiv64(s->next_periodic_time,
8b1478
-                                    RTC_CLOCK_RATE, NANOSECONDS_PER_SECOND);
8b1478
-            last_periodic_clock = next_periodic_clock - old_period;
8b1478
-            lost_clock = cur_clock - last_periodic_clock;
8b1478
-            assert(lost_clock >= 0);
8b1478
-        }
8b1478
+    /* compute 32 khz clock */
8b1478
+    cur_clock =
8b1478
+        muldiv64(current_time, RTC_CLOCK_RATE, NANOSECONDS_PER_SECOND);
8b1478
+
8b1478
+    /*
8b1478
+     * if the periodic timer's update is due to period re-configuration,
8b1478
+     * we should count the clock since last interrupt.
8b1478
+     */
8b1478
+    if (old_period) {
8b1478
+        int64_t last_periodic_clock, next_periodic_clock;
8b1478
+
8b1478
+        next_periodic_clock = muldiv64(s->next_periodic_time,
8b1478
+                                RTC_CLOCK_RATE, NANOSECONDS_PER_SECOND);
8b1478
+        last_periodic_clock = next_periodic_clock - old_period;
8b1478
+        lost_clock = cur_clock - last_periodic_clock;
8b1478
+        assert(lost_clock >= 0);
8b1478
 
8b1478
         /*
8b1478
          * s->irq_coalesced can change for two reasons:
8b1478
@@ -245,22 +249,19 @@ periodic_timer_update(RTCState *s, int64_t current_time, uint32_t old_period)
8b1478
                 rtc_coalesced_timer_update(s);
8b1478
             }
8b1478
         } else {
8b1478
-           /*
8b1478
+            /*
8b1478
              * no way to compensate the interrupt if LOST_TICK_POLICY_SLEW
8b1478
              * is not used, we should make the time progress anyway.
8b1478
              */
8b1478
             lost_clock = MIN(lost_clock, period);
8b1478
         }
8b1478
+    }
8b1478
 
8b1478
-        assert(lost_clock >= 0 && lost_clock <= period);
8b1478
+    assert(lost_clock >= 0 && lost_clock <= period);
8b1478
 
8b1478
-        next_irq_clock = cur_clock + period - lost_clock;
8b1478
-        s->next_periodic_time = periodic_clock_to_ns(next_irq_clock) + 1;
8b1478
-        timer_mod(s->periodic_timer, s->next_periodic_time);
8b1478
-    } else {
8b1478
-        s->irq_coalesced = 0;
8b1478
-        timer_del(s->periodic_timer);
8b1478
-    }
8b1478
+    next_irq_clock = cur_clock + period - lost_clock;
8b1478
+    s->next_periodic_time = periodic_clock_to_ns(next_irq_clock) + 1;
8b1478
+    timer_mod(s->periodic_timer, s->next_periodic_time);
8b1478
 }
8b1478
 
8b1478
 static void rtc_periodic_timer(void *opaque)
8b1478
-- 
8b1478
1.8.3.1
8b1478