qemu-devel
[Top][All Lists]
Advanced

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

[Qemu-devel] [PATCH] Fix sci irq set when acpi timer about to wrap


From: Dor Laor
Subject: [Qemu-devel] [PATCH] Fix sci irq set when acpi timer about to wrap
Date: Thu, 13 Mar 2008 01:00:38 +0200

>From 498f162fc9d9fb897c756273c481101a44a220de Mon Sep 17 00:00:00 2001
From: Dor Laor <address@hidden>
Date: Thu, 13 Mar 2008 00:11:41 +0200
Subject: [PATCH] Fix sci irq set when acpi timer about to wrap.

The acpi timer should generate sci irq when enabled and
when bit 23 of the timer counter toogles.
It fixes time reading by the performance counter api of windows guest.

Signed-off-by: Yaniv Kamay <address@hidden>
Signed-off-by: Dor Laor <address@hidden>
---
 qemu/hw/acpi.c |   81
+++++++++++++++++++++++++++++--------------------------
 1 files changed, 43 insertions(+), 38 deletions(-)

diff --git a/qemu/hw/acpi.c b/qemu/hw/acpi.c
index e44c8b5..8c47969 100644
--- a/qemu/hw/acpi.c
+++ b/qemu/hw/acpi.c
@@ -53,12 +53,15 @@ typedef struct PIIX4PMState {
     uint8_t smb_data[32];
     uint8_t smb_index;
     qemu_irq irq;
+    int64_t pmtmr;
 } PIIX4PMState;
 
 #define RTC_EN (1 << 10)
 #define PWRBTN_EN (1 << 8)
 #define GBL_EN (1 << 5)
 #define TMROF_EN (1 << 0)
+#define TIMER_OVERFLOW_CNT (1 << 23)
+#define TIMER_MASK 0xffffffLL
 
 #define SCI_EN (1 << 0)
 
@@ -77,47 +80,58 @@ typedef struct PIIX4PMState {
 
 PIIX4PMState *pm_state;
 
+static void update_pmtmr(PIIX4PMState *s)
+{
+    int64_t pmtmr;
+
+    pmtmr = muldiv64(qemu_get_clock(vm_clock), PM_FREQ, ticks_per_sec)
& TIMER_MASK;
+
+    if (!(s->pmsts & TMROF_EN)) {
+        if ((pmtmr ^ s->pmtmr) & TIMER_OVERFLOW_CNT) {
+            s->pmsts |= TMROF_EN;
+            if (s->pmen & TMROF_EN)
+                qemu_set_irq(s->irq, 1);
+        } else {
+            /* Calculate when the timer will neet to set the overflow
bit again */
+            uint64_t delta = TIMER_OVERFLOW_CNT - (pmtmr &
(TIMER_OVERFLOW_CNT - 1));
+
+            delta = muldiv64(delta, ticks_per_sec, PM_FREQ);
+            qemu_mod_timer(s->tmr_timer, qemu_get_clock(vm_clock) +
delta);
+        }
+    }
+
+    s->pmtmr = pmtmr;
+}
+
 static uint32_t get_pmtmr(PIIX4PMState *s)
 {
-    uint32_t d;
-    d = muldiv64(qemu_get_clock(vm_clock), PM_FREQ, ticks_per_sec);
-    return d & 0xffffff;
+     update_pmtmr(s);
+     return s->pmtmr & TIMER_MASK;
 }
 
+
 static int get_pmsts(PIIX4PMState *s)
 {
-    int64_t d;
-    int pmsts;
-    pmsts = s->pmsts;
-    d = muldiv64(qemu_get_clock(vm_clock), PM_FREQ, ticks_per_sec);
-    if (d >= s->tmr_overflow_time)
-        s->pmsts |= TMROF_EN;
-    return pmsts;
+    /* Just increase the accurancy by double computing the timer value
*/
+    update_pmtmr(s);
+
+    return s->pmsts;
 }
 
 static void pm_update_sci(PIIX4PMState *s)
 {
-    int sci_level, pmsts;
-    int64_t expire_time;
-
-    pmsts = get_pmsts(s);
-    sci_level = (((pmsts & s->pmen) &
-                  (RTC_EN | PWRBTN_EN | GBL_EN | TMROF_EN)) != 0);
-    qemu_set_irq(s->irq, sci_level);
-    /* schedule a timer interruption if needed */
-    if ((s->pmen & TMROF_EN) && !(pmsts & TMROF_EN)) {
-        expire_time = muldiv64(s->tmr_overflow_time, ticks_per_sec,
PM_FREQ);
-        qemu_mod_timer(s->tmr_timer, expire_time);
-        s->tmr_overflow_time += 0x800000;
-    } else {
-        qemu_del_timer(s->tmr_timer);
-    }
+    int sci_level;
+
+    sci_level = (((s->pmsts & s->pmen) & 
+                   (RTC_EN | PWRBTN_EN | GBL_EN | TMROF_EN)) != 0);
+    if (!sci_level)
+        qemu_set_irq(s->irq, sci_level);
 }
 
 static void pm_tmr_timer(void *opaque)
 {
     PIIX4PMState *s = opaque;
-    pm_update_sci(s);
+    update_pmtmr(s);
 }
 
 static void pm_ioport_writew(void *opaque, uint32_t addr, uint32_t val)
@@ -126,18 +140,9 @@ static void pm_ioport_writew(void *opaque, uint32_t
addr, uint32_t val)
     addr &= 0x3f;
     switch(addr) {
     case 0x00:
-        {
-            int64_t d;
-            int pmsts;
-            pmsts = get_pmsts(s);
-            if (pmsts & val & TMROF_EN) {
-                /* if TMRSTS is reset, then compute the new overflow
time */
-                d = muldiv64(qemu_get_clock(vm_clock), PM_FREQ,
ticks_per_sec);
-                s->tmr_overflow_time = (d + 0x800000LL) & ~0x7fffffLL;
-            }
-            s->pmsts &= ~val;
-            pm_update_sci(s);
-        }
+        s->pmsts &= ~val;
+        update_pmtmr(s);
+        pm_update_sci(s);
         break;
     case 0x02:
         s->pmen = val;
-- 
1.5.4.1

Attachment: 0001-Fix-sci-irq-set-when-acpi-timer-about-to-wrap.patch
Description: application/mbox


reply via email to

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