From a0664417b70424a123ea779b905ecfd62bd08340 Mon Sep 17 00:00:00 2001 From: Gleb Natapov <gleb@redhat.com> Date: Wed, 9 Dec 2009 11:03:48 -0200 Subject: [PATCH 3/4] fix rtc-td-hack on host without high-res timers RH-Author: Gleb Natapov <gleb@redhat.com> Message-id: <20091209110348.GI7645@redhat.com> Patchwork-id: 3880 O-Subject: [PATCH KVM 5.5 5.4.Z] fix rtc-td-hack on host without high-res timers Bugzilla: 543137 RH-Acked-by: Juan Quintela <quintela@redhat.com> RH-Acked-by: Dor Laor <dlaor@redhat.com> RH-Acked-by: Avi Kivity <avi@redhat.com> On hosts without high-res timers it is impossible to inject rtc interrupt faster then 1kHz. Windows sometimes configures RTC to generate 1kHz interrupts, so we can't inject missed interrupts when running on such hosts. Always injecting an interrupt on REG_C read is also not an option since Windows wait for REG_C to become zero with interrupt disabled during boot. This patch uses mixed approach: accelerate timer + inject up to 1000 interrupts on REG_C read. BZ: 543137 Upstream status: should be in staging already Signed-off-by: Gleb Natapov <gleb@redhat.com> -- Gleb. Signed-off-by: Eduardo Habkost <ehabkost@redhat.com> --- qemu/hw/mc146818rtc.c | 17 +++++++++++++++++ 1 files changed, 17 insertions(+), 0 deletions(-) diff --git a/qemu/hw/mc146818rtc.c b/qemu/hw/mc146818rtc.c index 80e564c..c839acd 100644 --- a/qemu/hw/mc146818rtc.c +++ b/qemu/hw/mc146818rtc.c @@ -31,6 +31,8 @@ //#define DEBUG_CMOS +#define RTC_REINJECT_ON_ACK_COUNT 1000 + #define RTC_SECONDS 0 #define RTC_SECONDS_ALARM 1 #define RTC_MINUTES 2 @@ -75,6 +77,7 @@ struct RTCState { /* second update */ int64_t next_second_time; #ifdef TARGET_I386 + uint16_t irq_reinject_on_ack_count; uint32_t irq_coalesced; uint32_t period; QEMUTimer *coalesced_timer; @@ -173,6 +176,8 @@ static void rtc_periodic_timer(void *opaque) s->cmos_data[RTC_REG_C] |= 0xc0; #ifdef TARGET_I386 if(rtc_td_hack) { + if (s->irq_reinject_on_ack_count >= RTC_REINJECT_ON_ACK_COUNT) + s->irq_reinject_on_ack_count = 0; apic_reset_irq_delivered(); rtc_irq_raise(s->irq); if (!apic_get_irq_delivered()) { @@ -452,6 +457,18 @@ 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 && + s->irq_reinject_on_ack_count < RTC_REINJECT_ON_ACK_COUNT) { + s->irq_reinject_on_ack_count++; + 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: -- 1.6.3.rc4.29.g8146