hvm_isa_irq_assert(d, RTC_IRQ);
}
-static void rtc_periodic_cb(struct vcpu *v, void *opaque)
+void rtc_periodic_interrupt(void *opaque)
{
RTCState *s = opaque;
spin_lock(&s->lock);
- s->hw.cmos_data[RTC_REG_C] |= RTC_PF | RTC_IRQF;
+ if ( s->hw.cmos_data[RTC_REG_C] & RTC_PF )
+ destroy_periodic_time(&s->pt);
+ else
+ {
+ s->hw.cmos_data[RTC_REG_C] |= RTC_PF;
+ if ( s->hw.cmos_data[RTC_REG_B] & RTC_PIE )
+ rtc_toggle_irq(s);
+ }
spin_unlock(&s->lock);
}
{
period = 1 << (period_code - 1); /* period in 32 Khz cycles */
period = DIV_ROUND(period * 1000000000ULL, 32768); /* in ns */
- create_periodic_time(v, &s->pt, period, period, RTC_IRQ,
- rtc_periodic_cb, s);
+ create_periodic_time(v, &s->pt, period, period, RTC_IRQ, NULL, s);
break;
}
/* fall through */
guest_usec = get_localtime_us(d) % USEC_PER_SEC;
if (guest_usec >= (USEC_PER_SEC - 244))
{
- /* RTC is in update cycle when enabling UIE */
+ /* RTC is in update cycle */
s->hw.cmos_data[RTC_REG_A] |= RTC_UIP;
next_update_time = (USEC_PER_SEC - guest_usec) * NS_PER_USEC;
expire_time = NOW() + next_update_time;
stop_timer(&s->alarm_timer);
- if ((s->hw.cmos_data[RTC_REG_B] & RTC_AIE) &&
+ if (!(s->hw.cmos_data[RTC_REG_C] & RTC_AF) &&
!(s->hw.cmos_data[RTC_REG_B] & RTC_SET))
{
s->current_tm = gmtime(get_localtime(d));
break;
}
s->hw.cmos_data[RTC_REG_B] = data;
- check_update_timer(s);
- alarm_timer_update(s);
+ if ( (data ^ orig) & RTC_SET )
+ check_update_timer(s);
+ if ( (data ^ orig) & (RTC_24H | RTC_DM_BINARY | RTC_SET) )
+ alarm_timer_update(s);
break;
case RTC_REG_C:
case RTC_REG_D:
hvm_isa_irq_deassert(vrtc_domain(s), RTC_IRQ);
s->hw.cmos_data[RTC_REG_C] = 0x00;
check_update_timer(s);
+ alarm_timer_update(s);
+ rtc_timer_update(s);
break;
default:
ret = s->hw.cmos_data[s->hw.cmos_index];
#include <asm/hvm/vpt.h>
#include <asm/event.h>
#include <asm/apic.h>
+#include <asm/mc146818rtc.h>
#define mode_is(d, name) \
((d)->arch.hvm_domain.params[HVM_PARAM_TIMER_MODE] == HVMPTM_##name)
struct periodic_time *pt, *temp, *earliest_pt = NULL;
uint64_t max_lag = -1ULL;
int irq, is_lapic;
+ void *pt_priv;
spin_lock(&v->arch.hvm_vcpu.tm_lock);
earliest_pt->irq_issued = 1;
irq = earliest_pt->irq;
is_lapic = (earliest_pt->source == PTSRC_lapic);
+ pt_priv = earliest_pt->priv;
spin_unlock(&v->arch.hvm_vcpu.tm_lock);
if ( is_lapic )
- {
vlapic_set_irq(vcpu_vlapic(v), irq, 0);
- }
+ else if ( irq == RTC_IRQ && pt_priv )
+ rtc_periodic_interrupt(pt_priv);
else
{
hvm_isa_irq_deassert(v->domain, irq);