* [Qemu-devel] [PATCH v2] Change RTC time drift IRQ re-injection
@ 2009-04-21 8:21 Gleb Natapov
2009-04-22 20:23 ` Anthony Liguori
0 siblings, 1 reply; 3+ messages in thread
From: Gleb Natapov @ 2009-04-21 8:21 UTC (permalink / raw)
To: qemu-devel
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 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.
^ permalink raw reply related [flat|nested] 3+ messages in thread
* Re: [Qemu-devel] [PATCH v2] Change RTC time drift IRQ re-injection
2009-04-21 8:21 [Qemu-devel] [PATCH v2] Change RTC time drift IRQ re-injection Gleb Natapov
@ 2009-04-22 20:23 ` Anthony Liguori
2009-04-22 20:28 ` Gleb Natapov
0 siblings, 1 reply; 3+ messages in thread
From: Anthony Liguori @ 2009-04-22 20:23 UTC (permalink / raw)
To: Gleb Natapov; +Cc: qemu-devel
Gleb Natapov wrote:
> 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>
>
Applied, but...
> @@ -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
You were missing a ';'. I added it.
--
Regards,
Anthony Liguori
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [Qemu-devel] [PATCH v2] Change RTC time drift IRQ re-injection
2009-04-22 20:23 ` Anthony Liguori
@ 2009-04-22 20:28 ` Gleb Natapov
0 siblings, 0 replies; 3+ messages in thread
From: Gleb Natapov @ 2009-04-22 20:28 UTC (permalink / raw)
To: Anthony Liguori; +Cc: qemu-devel
On Wed, Apr 22, 2009 at 03:23:46PM -0500, Anthony Liguori wrote:
> Gleb Natapov wrote:
>> 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>
>>
>
> Applied, but...
>
>> @@ -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
> You were missing a ';'. I added it.
>
Wow :(. I compiled it and even tested. Honestly! Something on the
internet eats semicolons.
--
Gleb.
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2009-04-22 20:28 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-04-21 8:21 [Qemu-devel] [PATCH v2] Change RTC time drift IRQ re-injection Gleb Natapov
2009-04-22 20:23 ` Anthony Liguori
2009-04-22 20:28 ` Gleb Natapov
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).