From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1LwBE6-0004b0-9S for qemu-devel@nongnu.org; Tue, 21 Apr 2009 04:21:10 -0400 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1LwBE1-0004ZJ-Cs for qemu-devel@nongnu.org; Tue, 21 Apr 2009 04:21:09 -0400 Received: from [199.232.76.173] (port=47368 helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1LwBE1-0004Z7-3C for qemu-devel@nongnu.org; Tue, 21 Apr 2009 04:21:05 -0400 Received: from mx20.gnu.org ([199.232.41.8]:55938) by monty-python.gnu.org with esmtps (TLS-1.0:RSA_AES_256_CBC_SHA1:32) (Exim 4.60) (envelope-from ) id 1LwBE0-0001HU-Ks for qemu-devel@nongnu.org; Tue, 21 Apr 2009 04:21:04 -0400 Received: from mx2.redhat.com ([66.187.237.31]) by mx20.gnu.org with esmtp (Exim 4.60) (envelope-from ) id 1LwBDz-0006HJ-O4 for qemu-devel@nongnu.org; Tue, 21 Apr 2009 04:21:04 -0400 Received: from int-mx2.corp.redhat.com (int-mx2.corp.redhat.com [172.16.27.26]) by mx2.redhat.com (8.13.8/8.13.8) with ESMTP id n3L8L2Vo018828 for ; Tue, 21 Apr 2009 04:21:02 -0400 Received: from ns3.rdu.redhat.com (ns3.rdu.redhat.com [10.11.255.199]) by int-mx2.corp.redhat.com (8.13.1/8.13.1) with ESMTP id n3L8L2RL003812 for ; Tue, 21 Apr 2009 04:21:02 -0400 Received: from dhcp-1-237.tlv.redhat.com (dhcp-1-237.tlv.redhat.com [10.35.1.237]) by ns3.rdu.redhat.com (8.13.8/8.13.8) with ESMTP id n3L8L1aw031550 for ; Tue, 21 Apr 2009 04:21:01 -0400 Date: Tue, 21 Apr 2009 11:21:00 +0300 From: Gleb Natapov Message-ID: <20090421082100.GB10126@redhat.com> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Subject: [Qemu-devel] [PATCH v2] Change RTC time drift IRQ re-injection List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org Currently IRQ are reinjected as soon as they are acknowledged to the RTC, but Windows sometimes do acknowledgement in a loop with global interrupt disabled waiting for interrupt to be cleared and it does not mask RTC vector in PIC/APIC while doing this. In such situation interrupt injection always fails and RTC interrupt is never cleared. Instead of reinjecting coalesced IRQs on acknowledgement the patch below reinjects them by accelerating RTC clock a bit. This way RTC interrupt is not constantly raced after coalesced interrupt. Signed-off-by: Gleb Natapov diff --git a/hw/mc146818rtc.c b/hw/mc146818rtc.c index 9640afe..00cb12f 100644 --- a/hw/mc146818rtc.c +++ b/hw/mc146818rtc.c @@ -73,6 +73,7 @@ struct RTCState { #ifdef TARGET_I386 uint32_t irq_coalesced; uint32_t period; + QEMUTimer *coalesced_timer; #endif QEMUTimer *second_timer; QEMUTimer *second_timer2; @@ -93,6 +94,37 @@ static void rtc_irq_raise(qemu_irq irq) { static void rtc_set_time(RTCState *s); static void rtc_copy_date(RTCState *s); +#ifdef TARGET_I386 +static void rtc_coalesced_timer_update(RTCState *s) +{ + if (s->irq_coalesced == 0) { + qemu_del_timer(s->coalesced_timer); + } else { + /* divide each RTC interval to 2 - 8 smaller intervals */ + int c = MIN(s->irq_coalesced, 7) + 1; + int64_t next_clock = qemu_get_clock(vm_clock) + + muldiv64(s->period / c, ticks_per_sec, 32768); + qemu_mod_timer(s->coalesced_timer, next_clock); + } +} + +static void rtc_coalesced_timer(void *opaque) +{ + RTCState *s = opaque; + + if (s->irq_coalesced != 0) { + apic_reset_irq_delivered(); + s->cmos_data[RTC_REG_C] |= 0xc0; + rtc_irq_raise(s->irq); + if (apic_get_irq_delivered()) { + s->irq_coalesced--; + } + } + + rtc_coalesced_timer_update(s); +} +#endif + static void rtc_timer_update(RTCState *s, int64_t current_time) { int period_code, period; @@ -138,14 +170,18 @@ static void rtc_periodic_timer(void *opaque) RTCState *s = opaque; rtc_timer_update(s, s->next_periodic_time); -#ifdef TARGET_I386 - if ((s->cmos_data[RTC_REG_C] & 0xc0) && rtc_td_hack) { - s->irq_coalesced++; - return; - } -#endif if (s->cmos_data[RTC_REG_B] & REG_B_PIE) { s->cmos_data[RTC_REG_C] |= 0xc0; +#ifdef TARGET_I386 + if(rtc_td_hack) { + apic_reset_irq_delivered(); + rtc_irq_raise(s->irq); + if (!apic_get_irq_delivered()) { + s->irq_coalesced++; + rtc_coalesced_timer_update(s); + } + } else +#endif rtc_irq_raise(s->irq); } if (s->cmos_data[RTC_REG_B] & REG_B_SQWE) { @@ -415,15 +451,6 @@ static uint32_t cmos_ioport_read(void *opaque, uint32_t addr) case RTC_REG_C: ret = s->cmos_data[s->cmos_index]; qemu_irq_lower(s->irq); -#ifdef TARGET_I386 - if(s->irq_coalesced) { - apic_reset_irq_delivered(); - qemu_irq_raise(s->irq); - if (apic_get_irq_delivered()) - s->irq_coalesced--; - break; - } -#endif s->cmos_data[RTC_REG_C] = 0x00; break; default: @@ -536,6 +563,7 @@ static int rtc_load_td(QEMUFile *f, void *opaque, int version_id) s->irq_coalesced = qemu_get_be32(f); s->period = qemu_get_be32(f); + rtc_coalesced_timer_update(s) return 0; } #endif @@ -558,6 +586,10 @@ RTCState *rtc_init_sqw(int base, qemu_irq irq, qemu_irq sqw_irq, int base_year) s->periodic_timer = qemu_new_timer(vm_clock, rtc_periodic_timer, s); +#ifdef TARGET_I386 + if (rtc_td_hack) + s->coalesced_timer = qemu_new_timer(vm_clock, rtc_coalesced_timer, s); +#endif s->second_timer = qemu_new_timer(vm_clock, rtc_update_second, s); s->second_timer2 = qemu_new_timer(vm_clock, -- Gleb.