Hello.

This patch stops the qemu seconds timer when the RTC is not used. Once
the cmos is accessed, the skipped seconds are accounted for, and the
timer is enabled again.

In case interrupts are to be delivered, the timer is not disabled.


I have obviously gone mad from staring too much at PowerTOP, as this
really is a micro-optimization. On the other hand, this change
eliminates the last host-induced periodic timer in my kvm setup, so it
seems worth the trouble.

Please comment, does it make sense?


Anders.

diff --git a/qemu/hw/mc146818rtc.c b/qemu/hw/mc146818rtc.c
index e1e6427..fd00f3a 100644
--- a/qemu/hw/mc146818rtc.c
+++ b/qemu/hw/mc146818rtc.c
@@ -72,6 +72,7 @@ struct RTCState {
 
 static void rtc_set_time(RTCState *s);
 static void rtc_copy_date(RTCState *s);
+static void rtc_catchup(RTCState *s);
 
 static void rtc_timer_update(RTCState *s, int64_t current_time)
 {
@@ -108,6 +109,8 @@ static void cmos_ioport_write(void *opaque, uint32_t addr, uint32_t data)
 {
     RTCState *s = opaque;
 
+    rtc_catchup(s);
+
     if ((addr & 1) == 0) {
         s->cmos_index = data & 0x7f;
     } else {
@@ -334,13 +337,48 @@ static void rtc_update_second2(void *opaque)
     s->cmos_data[RTC_REG_A] &= ~REG_A_UIP;
 
     s->next_second_time += ticks_per_sec;
-    qemu_mod_timer(s->second_timer, s->next_second_time);
+
+    /* Keep going only if interrupts are needed */
+    if (s->cmos_data[RTC_REG_B] & (REG_B_AIE | REG_B_UIE)) {
+        qemu_mod_timer(s->second_timer, s->next_second_time);
+    }
+}
+
+static void rtc_catchup(RTCState *s)
+{
+    int64_t now;
+
+    if (!qemu_timer_pending(s->second_timer) &&
+        !qemu_timer_pending(s->second_timer2)) {
+
+        /* Count the seconds passed since last access */
+        now = qemu_get_clock(vm_clock);
+
+        while (s->next_second_time <= now) {
+            rtc_next_second(&s->current_tm);
+            s->next_second_time += ticks_per_sec;
+        }
+
+        if (!(s->cmos_data[RTC_REG_B] & REG_B_SET)) {
+            rtc_copy_date(s);
+        }
+
+        /* Restart the right timer */
+        if ((s->next_second_time - now) < ticks_per_sec/100) {
+            rtc_update_second(s);
+        } else {
+            qemu_mod_timer(s->second_timer, s->next_second_time);
+        }
+    }
 }
 
 static uint32_t cmos_ioport_read(void *opaque, uint32_t addr)
 {
     RTCState *s = opaque;
     int ret;
+
+    rtc_catchup(s);
+
     if ((addr & 1) == 0) {
         return 0xff;
     } else {

Reply via email to