All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Zhang, Yang Z" <yang.z.zhang@intel.com>
To: "'qemu-devel@nongnu.org'" <qemu-devel@nongnu.org>
Cc: 'Paolo Bonzini' <pbonzini@redhat.com>,
	"'aliguori@us.ibm.com'" <aliguori@us.ibm.com>
Subject: [Qemu-devel] [PATCH v5 5/7] RTC:Add RTC update-ended interrupt support
Date: Wed, 9 May 2012 07:22:57 +0000	[thread overview]
Message-ID: <A9667DDFB95DB7438FA9D7D576C3D87E12C837@SHSMSX101.ccr.corp.intel.com> (raw)

There are no need to run a periodic timer to emulate updated-end
logic. Only run the timer when the UF or AF was clear.

Signed-off-by: Yang Zhang <yang.z.zhang@Intel.com>
---
 hw/mc146818rtc.c |   94 +++++++++++++++++++++++++++++++++++++++++++++++++----
 1 files changed, 86 insertions(+), 8 deletions(-)

diff --git a/hw/mc146818rtc.c b/hw/mc146818rtc.c
index c9b5232..be74399 100644
--- a/hw/mc146818rtc.c
+++ b/hw/mc146818rtc.c
@@ -100,6 +100,11 @@ typedef struct RTCState {
     /* periodic timer */
     QEMUTimer *periodic_timer;
     int64_t next_periodic_time;
+    /* update-ended timer */
+    QEMUTimer *update_timer;
+    QEMUTimer *update_timer2;
+    uint64_t next_update_time;
+    uint32_t use_timer;
     uint16_t irq_reinject_on_ack_count;
     uint32_t irq_coalesced;
     uint32_t period;
@@ -166,7 +171,8 @@ static void rtc_coalesced_timer(void *opaque)
 }
 #endif

-static void rtc_timer_update(RTCState *s, int64_t current_time)
+/* handle periodic timer */
+static void periodic_timer_update(RTCState *s, int64_t current_time)
 {
     int period_code, period;
     int64_t cur_clock, next_irq_clock;
@@ -204,7 +210,7 @@ static void rtc_periodic_timer(void *opaque)
 {
     RTCState *s = opaque;

-    rtc_timer_update(s, s->next_periodic_time);
+    periodic_timer_update(s, s->next_periodic_time);
     s->cmos_data[RTC_REG_C] |= REG_C_PF;
     if (s->cmos_data[RTC_REG_B] & REG_B_PIE) {
         s->cmos_data[RTC_REG_C] |= REG_C_IRQF;
@@ -231,6 +237,58 @@ static void rtc_periodic_timer(void *opaque)
     }
 }

+/* handle update-ended timer */
+static void check_update_timer(RTCState *s)
+{
+    uint64_t next_update_time, expire_time;
+    uint64_t guest_usec;
+    qemu_del_timer(s->update_timer);
+    qemu_del_timer(s->update_timer2);
+
+    if (!((s->cmos_data[RTC_REG_C] & (REG_C_UF | REG_C_AF)) ==
+            (REG_C_UF | REG_C_AF)) && !(s->cmos_data[RTC_REG_B] & REG_B_SET)) {
+        s->use_timer = 1;
+        guest_usec = get_guest_rtc_us(s) % USEC_PER_SEC;
+        if (guest_usec >= (USEC_PER_SEC - 244)) {
+            /* RTC is in update cycle when enabling UIE */
+            s->cmos_data[RTC_REG_A] |= REG_A_UIP;
+            next_update_time = (USEC_PER_SEC - guest_usec) * NS_PER_USEC;
+            expire_time = qemu_get_clock_ns(rtc_clock) + next_update_time;
+            qemu_mod_timer(s->update_timer2, expire_time);
+        } else {
+            next_update_time = (USEC_PER_SEC - guest_usec - 244) * NS_PER_USEC;
+            expire_time = qemu_get_clock_ns(rtc_clock) + next_update_time;
+            s->next_update_time = expire_time;
+            qemu_mod_timer(s->update_timer, expire_time);
+        }
+    } else {
+        s->use_timer = 0;
+    }
+}
+
+static void rtc_update_timer(void *opaque)
+{
+    RTCState *s = opaque;
+
+    if (rtc_running(s)) {
+        s->cmos_data[RTC_REG_A] |= REG_A_UIP;
+        qemu_mod_timer(s->update_timer2, s->next_update_time + 244000UL);
+    }
+}
+
+static void rtc_update_timer2(void *opaque)
+{
+    RTCState *s = opaque;
+
+    if (rtc_running(s)) {
+        s->cmos_data[RTC_REG_C] |= REG_C_UF;
+        s->cmos_data[RTC_REG_A] &= ~REG_A_UIP;
+        s->cmos_data[RTC_REG_C] |= REG_C_IRQF;
+        qemu_irq_raise(s->irq);
+    }
+    check_update_timer(s);
+}
+
 static void rtc_set_offset(RTCState *s, int32_t start_usec)
 {
     struct tm *tm = &s->current_tm;
@@ -297,13 +355,14 @@ static void cmos_ioport_write(void *opaque, uint32_t addr, uint32_t data)
                     rtc_set_time(s);
                     rtc_set_offset(s, 500000);
                     s->cmos_data[RTC_REG_A] &= ~REG_A_UIP;
+                    check_update_timer(s);
                     divider_reset = 0;
                 }
             }
             /* UIP bit is read only */
             s->cmos_data[RTC_REG_A] = (data & ~REG_A_UIP) |
                 (s->cmos_data[RTC_REG_A] & REG_A_UIP);
-            rtc_timer_update(s, qemu_get_clock_ns(rtc_clock));
+            periodic_timer_update(s, qemu_get_clock_ns(rtc_clock));
             break;
         case RTC_REG_B:
             if (data & REG_B_SET) {
@@ -330,7 +389,8 @@ static void cmos_ioport_write(void *opaque, uint32_t addr, uint32_t data)
                 }
             }
             s->cmos_data[RTC_REG_B] = data;
-            rtc_timer_update(s, qemu_get_clock_ns(rtc_clock));
+            periodic_timer_update(s, qemu_get_clock_ns(rtc_clock));
+            check_update_timer(s);
             break;
         case RTC_REG_C:
         case RTC_REG_D:
@@ -460,15 +520,25 @@ static uint32_t cmos_ioport_read(void *opaque, uint32_t 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)) {
-                ret |= REG_A_UIP;
+            if (s->use_timer == 0) {
+                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 = s->cmos_data[s->cmos_index];
             break;
         case RTC_REG_C:
             ret = s->cmos_data[s->cmos_index];
             qemu_irq_lower(s->irq);
             s->cmos_data[RTC_REG_C] = 0x00;
+            if (rtc_running(s)) {
+                rtc_calibrate_time(s);
+            }
+            if (ret & (REG_C_UF | REG_C_AF)) {
+                check_update_timer(s);
+            }
 #ifdef TARGET_I386
             if(s->irq_coalesced &&
                     (s->cmos_data[RTC_REG_B] & REG_B_PIE) &&
@@ -561,6 +631,9 @@ static const VMStateDescription vmstate_rtc = {
         VMSTATE_INT32(offset_usec, RTCState),
         VMSTATE_TIMER(periodic_timer, RTCState),
         VMSTATE_INT64(next_periodic_time, RTCState),
+        VMSTATE_TIMER(update_timer, RTCState),
+        VMSTATE_TIMER(update_timer2, RTCState),
+        VMSTATE_UINT64(next_update_time, RTCState),
         VMSTATE_UINT32_V(irq_coalesced, RTCState, 2),
         VMSTATE_UINT32_V(period, RTCState, 2),
         VMSTATE_END_OF_LIST()
@@ -573,7 +646,8 @@ static void rtc_notify_clock_reset(Notifier *notifier, void *data)
     int64_t now = *(int64_t *)data;

     rtc_set_date_from_host(&s->dev);
-    rtc_timer_update(s, now);
+    periodic_timer_update(s, now);
+    check_update_timer(s);
 #ifdef TARGET_I386
     if (s->lost_tick_policy == LOST_TICK_SLEW) {
         rtc_coalesced_timer_update(s);
@@ -595,6 +669,7 @@ static void rtc_reset(void *opaque)

     s->cmos_data[RTC_REG_B] &= ~(REG_B_PIE | REG_B_AIE | REG_B_SQWE);
     s->cmos_data[RTC_REG_C] &= ~(REG_C_UF | REG_C_IRQF | REG_C_PF | REG_C_AF);
+    check_update_timer(s);

     qemu_irq_lower(s->irq);

@@ -665,6 +740,9 @@ static int rtc_initfn(ISADevice *dev)
 #endif

     s->periodic_timer = qemu_new_timer_ns(rtc_clock, rtc_periodic_timer, s);
+    s->update_timer = qemu_new_timer_ns(rtc_clock, rtc_update_timer, s);
+    s->update_timer2 = qemu_new_timer_ns(rtc_clock, rtc_update_timer2, s);
+    check_update_timer(s);

     s->clock_reset_notifier.notify = rtc_notify_clock_reset;
     qemu_register_clock_reset_notifier(rtc_clock, &s->clock_reset_notifier);
--
1.7.1

                 reply	other threads:[~2012-05-09  7:23 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=A9667DDFB95DB7438FA9D7D576C3D87E12C837@SHSMSX101.ccr.corp.intel.com \
    --to=yang.z.zhang@intel.com \
    --cc=aliguori@us.ibm.com \
    --cc=pbonzini@redhat.com \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.