summary refs log tree commit diff stats
path: root/hw/timer/mc146818rtc.c
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2017-08-01 18:03:04 +0100
committerPeter Maydell <peter.maydell@linaro.org>2017-08-01 18:03:04 +0100
commit82d3d409b8b650164817ead0cb48298c6973d731 (patch)
tree76b2c0412952acc21ac9bf1e54d9899a9092ec8f /hw/timer/mc146818rtc.c
parent3b64f272d36b310587e606217db92b0bcb6673a1 (diff)
parent33f21e4f044ac1c37f60edc1f1aee628be8f463b (diff)
downloadfocaccia-qemu-82d3d409b8b650164817ead0cb48298c6973d731.tar.gz
focaccia-qemu-82d3d409b8b650164817ead0cb48298c6973d731.zip
Merge remote-tracking branch 'remotes/bonzini/tags/for-upstream' into staging
* Xen fix (Anthony)
* chardev fixes (Anton, Marc-André)
* small dead code removal (Zhongyi)
* documentation (Dan)
* bugfixes (David)
* decrease migration downtime (Jay)
* improved error output (Laurent)
* RTC tests and bugfix (me)
* Bluetooth clang analyzer fix (me)
* KVM CPU hotplug race (Peng Hao)
* Two other patches from Philippe's clang analyzer series

# gpg: Signature made Tue 01 Aug 2017 16:56:21 BST
# gpg:                using RSA key 0xBFFBD25F78C7AE83
# gpg: Good signature from "Paolo Bonzini <bonzini@gnu.org>"
# gpg:                 aka "Paolo Bonzini <pbonzini@redhat.com>"
# Primary key fingerprint: 46F5 9FBD 57D6 12E7 BFD4  E2F7 7E15 100C CD36 69B1
#      Subkey fingerprint: F133 3857 4B66 2389 866C  7682 BFFB D25F 78C7 AE83

* remotes/bonzini/tags/for-upstream:
  mc146818rtc: implement UIP latching as intended
  mc146818rtc: simplify check_update_timer
  rtc-test: introduce more update tests
  rtc-test: cleanup register_b_set_flag test
  hw/scsi/vmw_pvscsi: Convert to realize
  hw/scsi/vmw_pvscsi: Remove the dead error handling
  migration: optimize the downtime
  qemu-options: document existance of versioned machine types
  bt: stop the sdp memory allocation craziness
  exec: Add lock parameter to qemu_ram_ptr_length
  target-i386: kvm_get/put_vcpu_events don't handle sipi_vector
  docs: document deprecation policy & deprecated features in appendix
  char: don't exit on hmp 'chardev-add help'
  char-fd: remove useless chr pointer
  accel: cleanup error output
  cpu_physical_memory_sync_dirty_bitmap: Fix alignment check
  vl.c/exit: pause cpus before closing block devices

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'hw/timer/mc146818rtc.c')
-rw-r--r--hw/timer/mc146818rtc.c37
1 files changed, 19 insertions, 18 deletions
diff --git a/hw/timer/mc146818rtc.c b/hw/timer/mc146818rtc.c
index 1b8d3d7d4c..82843ed03f 100644
--- a/hw/timer/mc146818rtc.c
+++ b/hw/timer/mc146818rtc.c
@@ -291,26 +291,15 @@ static void check_update_timer(RTCState *s)
 
     /* From the data sheet: "Holding the dividers in reset prevents
      * interrupts from operating, while setting the SET bit allows"
-     * them to occur.  However, it will prevent an alarm interrupt
-     * from occurring, because the time of day is not updated.
+     * them to occur.
      */
     if ((s->cmos_data[RTC_REG_A] & 0x60) == 0x60) {
-        timer_del(s->update_timer);
-        return;
-    }
-    if ((s->cmos_data[RTC_REG_C] & REG_C_UF) &&
-        (s->cmos_data[RTC_REG_B] & REG_B_SET)) {
-        timer_del(s->update_timer);
-        return;
-    }
-    if ((s->cmos_data[RTC_REG_C] & REG_C_UF) &&
-        (s->cmos_data[RTC_REG_C] & REG_C_AF)) {
+        assert((s->cmos_data[RTC_REG_A] & REG_A_UIP) == 0);
         timer_del(s->update_timer);
         return;
     }
 
     guest_nsec = get_guest_rtc_ns(s) % NANOSECONDS_PER_SECOND;
-    /* if UF is clear, reprogram to next second */
     next_update_time = qemu_clock_get_ns(rtc_clock)
         + NANOSECONDS_PER_SECOND - guest_nsec;
 
@@ -321,7 +310,21 @@ static void check_update_timer(RTCState *s)
     s->next_alarm_time = next_update_time +
                          (next_alarm_sec - 1) * NANOSECONDS_PER_SECOND;
 
-    if (s->cmos_data[RTC_REG_C] & REG_C_UF) {
+    /* If update_in_progress latched the UIP bit, we must keep the timer
+     * programmed to the next second, so that UIP is cleared.  Otherwise,
+     * if UF is already set, we might be able to optimize.
+     */
+    if (!(s->cmos_data[RTC_REG_A] & REG_A_UIP) &&
+        (s->cmos_data[RTC_REG_C] & REG_C_UF)) {
+        /* If AF cannot change (i.e. either it is set already, or
+         * SET=1 and then the time is not updated), nothing to do.
+         */
+        if ((s->cmos_data[RTC_REG_B] & REG_B_SET) ||
+            (s->cmos_data[RTC_REG_C] & REG_C_AF)) {
+            timer_del(s->update_timer);
+            return;
+        }
+
         /* UF is set, but AF is clear.  Program the timer to target
          * the alarm time.  */
         next_update_time = s->next_alarm_time;
@@ -727,12 +730,10 @@ static uint64_t cmos_ioport_read(void *opaque, hwaddr addr,
             ret = s->cmos_data[s->cmos_index];
             break;
         case RTC_REG_A:
+            ret = s->cmos_data[s->cmos_index];
             if (update_in_progress(s)) {
-                s->cmos_data[s->cmos_index] |= REG_A_UIP;
-            } else {
-                s->cmos_data[s->cmos_index] &= ~REG_A_UIP;
+                ret |= REG_A_UIP;
             }
-            ret = s->cmos_data[s->cmos_index];
             break;
         case RTC_REG_C:
             ret = s->cmos_data[s->cmos_index];