qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [PATCH v2 2/4] RTC:Add RTC update-ended interrupt logic


From: Zhang, Yang Z
Subject: [Qemu-devel] [PATCH v2 2/4] RTC:Add RTC update-ended interrupt logic
Date: Mon, 20 Feb 2012 00:25:26 +0000

Use timer to emulate RTC update-ended interrupt. The timer is enabled
only when UIE is setting.

Signed-off-by: Yang Zhang <address@hidden>

---
 hw/mc146818rtc.c |   53 ++++++++++++++++++++++++++++++++++++++++++++++++-----
 1 files changed, 48 insertions(+), 5 deletions(-)

diff --git a/hw/mc146818rtc.c b/hw/mc146818rtc.c
index b6655ae..bb1873b 100644
--- a/hw/mc146818rtc.c
+++ b/hw/mc146818rtc.c
@@ -93,9 +93,14 @@ typedef struct RTCState {
     qemu_irq irq;
     qemu_irq sqw_irq;
     int it_shift;
+
     /* periodic timer */
     QEMUTimer *periodic_timer;
     int64_t next_periodic_time;
+
+    /* update-ended timer */
+    QEMUTimer *update_timer;
+
     uint16_t irq_reinject_on_ack_count;
     uint32_t irq_coalesced;
     uint32_t period;
@@ -140,7 +145,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;
@@ -178,7 +184,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;
@@ -205,6 +211,40 @@ static void rtc_periodic_timer(void *opaque)
     }
 }

+/* handle update-ended timer */
+static void update_ended_timer_update(RTCState *s)
+{
+    struct timeval tv_now;
+    uint64_t next_update_time;
+    uint64_t expire_time;
+
+    if ((s->cmos_data[RTC_REG_B] & REG_B_UIE) &&
+            !(s->cmos_data[RTC_REG_B] & REG_B_SET)) {
+        gettimeofday(&tv_now, NULL);
+        next_update_time = USEC_PER_SEC -
+                           (tv_now.tv_usec + s->offset_usec) % 1000000;
+        expire_time = (get_ticks_per_sec() / USEC_PER_SEC) * next_update_time +
+                       qemu_get_clock_ns(rtc_clock);
+        qemu_mod_timer(s->update_timer, expire_time);
+    } else {
+        qemu_del_timer(s->update_timer);
+    }
+}
+
+static void rtc_update_timer(void *opaque)
+{
+    RTCState *s = opaque;
+
+    update_ended_timer_update(s);
+    if (!(s->cmos_data[RTC_REG_B] & REG_B_SET)) {
+        s->cmos_data[RTC_REG_C] |= REG_C_UF;
+        if (s->cmos_data[RTC_REG_B] & REG_B_UIE) {
+            s->cmos_data[RTC_REG_C] |= REG_C_IRQF;
+            qemu_irq_raise(s->irq);
+        }
+    }
+}
+
 static void rtc_set_offset(RTCState *s)
 {
     struct tm *tm = &s->current_tm;
@@ -256,7 +296,7 @@ static void cmos_ioport_write(void *opaque, uint32_t addr, 
uint32_t data)
             /* 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) {
@@ -279,7 +319,8 @@ static void cmos_ioport_write(void *opaque, uint32_t addr, 
uint32_t data)
             } else {
                 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));
+            update_ended_timer_update(s);
             break;
         case RTC_REG_C:
         case RTC_REG_D:
@@ -493,6 +534,7 @@ 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_UINT32_V(irq_coalesced, RTCState, 2),
         VMSTATE_UINT32_V(period, RTCState, 2),
         VMSTATE_END_OF_LIST()
@@ -505,7 +547,7 @@ 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);
 #ifdef TARGET_I386
     if (s->lost_tick_policy == LOST_TICK_SLEW) {
         rtc_coalesced_timer_update(s);
@@ -589,6 +631,7 @@ 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->clock_reset_notifier.notify = rtc_notify_clock_reset;
     qemu_register_clock_reset_notifier(rtc_clock, &s->clock_reset_notifier);
--
1.7.1




reply via email to

[Prev in Thread] Current Thread [Next in Thread]