]> xenbits.xensource.com Git - people/iwj/xen.git/commitdiff
x86/HVM: adjust IRQ (de-)assertion
authorJan Beulich <jbeulich@suse.com>
Tue, 21 May 2013 08:12:50 +0000 (10:12 +0200)
committerJan Beulich <jbeulich@suse.com>
Tue, 21 May 2013 08:12:50 +0000 (10:12 +0200)
De-assertion should only happen when RTC_IRQF gets cleared, i.e. upon
REG_C reads. Assertion should be done only when the flag transitions
from 0 to 1.

Signed-off-by: Jan Beulich <jbeulich@suse.com>
Tested-by: Roger Pau Monné <roger.pau@citrix.com> (FreeBSD guest)
xen/arch/x86/hvm/rtc.c

index b728d5e3db06b72a84f4d889537eeb95d6a870e3..b215886ef04844ec1cf2798bace5e4bfc75790d4 100644 (file)
@@ -52,23 +52,19 @@ static inline int convert_hour(RTCState *s, int hour);
 
 static void rtc_update_irq(RTCState *s)
 {
-    struct domain *d = vrtc_domain(s);
-    uint8_t irqf;
-
     ASSERT(spin_is_locked(&s->lock));
 
-    /* IRQ is raised if any source is both raised & enabled */
-    irqf = (s->hw.cmos_data[RTC_REG_B]
-            & s->hw.cmos_data[RTC_REG_C]
-            & (RTC_PF|RTC_AF|RTC_UF))
-        ? RTC_IRQF : 0;
+    if ( s->hw.cmos_data[RTC_REG_C] & RTC_IRQF )
+        return;
 
-    s->hw.cmos_data[RTC_REG_C] &= ~RTC_IRQF;
-    s->hw.cmos_data[RTC_REG_C] |= irqf;
+    /* IRQ is raised if any source is both raised & enabled */
+    if ( !(s->hw.cmos_data[RTC_REG_B] &
+           s->hw.cmos_data[RTC_REG_C] &
+           (RTC_PF | RTC_AF | RTC_UF)) )
+        return;
 
-    hvm_isa_irq_deassert(d, RTC_IRQ);
-    if ( irqf )
-        hvm_isa_irq_assert(d, RTC_IRQ);
+    s->hw.cmos_data[RTC_REG_C] |= RTC_IRQF;
+    hvm_isa_irq_assert(vrtc_domain(s), RTC_IRQ);
 }
 
 void rtc_periodic_interrupt(void *opaque)
@@ -631,6 +627,8 @@ static uint32_t rtc_ioport_read(RTCState *s, uint32_t addr)
     case RTC_REG_C:
         ret = s->hw.cmos_data[s->hw.cmos_index];
         s->hw.cmos_data[RTC_REG_C] = 0x00;
+        if ( ret & RTC_IRQF )
+            hvm_isa_irq_deassert(d, RTC_IRQ);
         rtc_update_irq(s);
         check_update_timer(s);
         alarm_timer_update(s);