From: Gleb Natapov <gleb@redhat.com>
To: qemu-devel@nongnu.org
Subject: [Qemu-devel] [PATCH] Change RTC time drift IRQ re-injection
Date: Mon, 6 Apr 2009 16:25:26 +0300 [thread overview]
Message-ID: <20090406132526.GA9153@redhat.com> (raw)
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 <gleb@redhat.com>
diff --git a/hw/mc146818rtc.c b/hw/mc146818rtc.c
index 5b08d72..22b7a7f 100644
--- a/hw/mc146818rtc.c
+++ b/hw/mc146818rtc.c
@@ -71,6 +71,7 @@ struct RTCState {
#ifdef TARGET_I386
uint32_t irq_coalesced;
uint32_t period;
+ QEMUTimer *coalesced_timer;
#endif
QEMUTimer *second_timer;
QEMUTimer *second_timer2;
@@ -91,6 +92,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;
@@ -132,13 +164,17 @@ static void rtc_periodic_timer(void *opaque)
RTCState *s = opaque;
rtc_timer_update(s, s->next_periodic_time);
+ s->cmos_data[RTC_REG_C] |= 0xc0;
#ifdef TARGET_I386
- if ((s->cmos_data[RTC_REG_C] & 0xc0) && rtc_td_hack) {
- s->irq_coalesced++;
- return;
- }
+ 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
- s->cmos_data[RTC_REG_C] |= 0xc0;
rtc_irq_raise(s->irq);
}
@@ -402,15 +438,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:
@@ -512,6 +539,7 @@ static void rtc_save_td(QEMUFile *f, void *opaque)
qemu_put_be32(f, s->irq_coalesced);
qemu_put_be32(f, s->period);
+ qemu_put_timer(f, s->coalesced_timer);
}
static int rtc_load_td(QEMUFile *f, void *opaque, int version_id)
@@ -523,6 +551,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);
+ qemu_get_timer(f, s->coalesced_timer);
return 0;
}
#endif
@@ -544,6 +573,10 @@ RTCState *rtc_init(int base, qemu_irq 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.
next reply other threads:[~2009-04-06 13:25 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2009-04-06 13:25 Gleb Natapov [this message]
2009-04-18 14:55 ` [Qemu-devel] [PATCH] Change RTC time drift IRQ re-injection Anthony Liguori
2009-04-19 14:06 ` Dor Laor
2009-04-21 8:18 ` Gleb Natapov
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20090406132526.GA9153@redhat.com \
--to=gleb@redhat.com \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).