aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGleb Natapov <gleb@redhat.com>2009-12-08 15:50:54 +0200
committerAnthony Liguori <aliguori@us.ibm.com>2009-12-12 08:17:28 -0600
commit5b6321a237e00e7642f0c205e13a1382988e59c2 (patch)
tree13ecab76a7ffd1eaebe9daf1b172231ec666a0df
parent5e0c45584215c4ade73d8285da701ca445232286 (diff)
fix rtc-td-hack on host without high-res timers
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. Signed-off-by: Gleb Natapov <gleb@redhat.com> Signed-off-by: Anthony Liguori <aliguori@us.ibm.com> (cherry picked from commit ba32edab7fdab0e74b54696942b4127d26861cf6)
-rw-r--r--hw/mc146818rtc.c17
1 files changed, 17 insertions, 0 deletions
diff --git a/hw/mc146818rtc.c b/hw/mc146818rtc.c
index b8c7b0c1b8..e4d55c7c79 100644
--- a/hw/mc146818rtc.c
+++ b/hw/mc146818rtc.c
@@ -30,6 +30,8 @@
//#define DEBUG_CMOS
+#define RTC_REINJECT_ON_ACK_COUNT 1000
+
#define RTC_SECONDS 0
#define RTC_SECONDS_ALARM 1
#define RTC_MINUTES 2
@@ -76,6 +78,7 @@ struct RTCState {
int64_t next_periodic_time;
/* second update */
int64_t next_second_time;
+ uint16_t irq_reinject_on_ack_count;
uint32_t irq_coalesced;
uint32_t period;
QEMUTimer *coalesced_timer;
@@ -180,6 +183,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()) {
@@ -458,6 +463,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: