[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH RFC v2 1/3] x86/hvm/rtc: Don't run the vpt timer when !REG_B.PIE.
From: Tim Deegan <tim@xxxxxxx> If the guest has not asked for interrupts, don't run the vpt timer to generate them. This is a prerequisite for a patch to simplify how the vpt interacts with the RTC, and also gets rid of a timer series in Xen in a case where it's unlikely to be needed. Instead, calculate the correct value for REG_C.PF whenever REG_C is read or PIE is enabled. This allow a guest to poll for the PF bit while not asking for actual timer interrupts. Such a guest would no longer get the benefit of the vpt's timer modes. Signed-off-by: Tim Deegan <tim@xxxxxxx> Signed-off-by: Andrew Cooper <andrew.cooper3@xxxxxxxxxx> --- Changes in v2: * Reduce scope of `now` in rtc_timer_update() * Merge PIE logic in REG_B write * Tightly couple setting s->period with creating/destroying timers, so the timer change gets properly recreated when the guest sets REG_B.PIE --- xen/arch/x86/hvm/rtc.c | 58 ++++++++++++++++++++++++++++++++--------- xen/include/asm-x86/hvm/vpt.h | 3 ++- 2 files changed, 48 insertions(+), 13 deletions(-) diff --git a/xen/arch/x86/hvm/rtc.c b/xen/arch/x86/hvm/rtc.c index cdedefe..1455bc6 100644 --- a/xen/arch/x86/hvm/rtc.c +++ b/xen/arch/x86/hvm/rtc.c @@ -94,7 +94,7 @@ bool_t rtc_periodic_interrupt(void *opaque) { /* VM is ignoring its RTC; no point in running the timer */ destroy_periodic_time(&s->pt); - s->pt_code = 0; + s->period = 0; } if ( !(s->hw.cmos_data[RTC_REG_C] & RTC_IRQF) ) ret = 0; @@ -103,6 +103,24 @@ bool_t rtc_periodic_interrupt(void *opaque) return ret; } +/* Check whether the REG_C.PF bit should have been set by a tick since + * the last time we looked. This is used to track ticks when REG_B.PIE + * is clear; when PIE is set, PF ticks are handled by the VPT callbacks. */ +static void check_for_pf_ticks(RTCState *s) +{ + s_time_t now; + + if ( s->period == 0 || (s->hw.cmos_data[RTC_REG_B] & RTC_PIE) ) + return; + + now = NOW(); + if ( (now - s->start_time) / s->period + != (s->check_ticks_since - s->start_time) / s->period ) + s->hw.cmos_data[RTC_REG_C] |= RTC_PF; + + s->check_ticks_since = now; +} + /* Enable/configure/disable the periodic timer based on the RTC_PIE and * RTC_RATE_SELECT settings */ static void rtc_timer_update(RTCState *s) @@ -125,24 +143,31 @@ static void rtc_timer_update(RTCState *s) case RTC_REF_CLCK_4MHZ: if ( period_code != 0 ) { - if ( period_code != s->pt_code ) + period = 1 << (period_code - 1); /* period in 32 Khz cycles */ + period = DIV_ROUND(period * 1000000000ULL, 32768); /* in ns */ + if ( period != s->period ) { - s->pt_code = period_code; - period = 1 << (period_code - 1); /* period in 32 Khz cycles */ - period = DIV_ROUND(period * 1000000000ULL, 32768); /* in ns */ + s_time_t now = NOW(); + if ( v->domain->arch.hvm_domain.params[HVM_PARAM_VPT_ALIGN] ) delta = 0; else - delta = period - ((NOW() - s->start_time) % period); - create_periodic_time(v, &s->pt, delta, period, - RTC_IRQ, NULL, s); + delta = period - ((now - s->start_time) % period); + if ( s->hw.cmos_data[RTC_REG_B] & RTC_PIE ) + { + create_periodic_time(v, &s->pt, delta, period, + RTC_IRQ, NULL, s); + s->period = period; + } + else + s->check_ticks_since = now; } break; } /* fall through */ default: destroy_periodic_time(&s->pt); - s->pt_code = 0; + s->period = 0; break; } } @@ -484,14 +509,22 @@ static int rtc_ioport_write(void *opaque, uint32_t addr, uint32_t data) if ( orig & RTC_SET ) rtc_set_time(s); } + check_for_pf_ticks(s); s->hw.cmos_data[RTC_REG_B] = data; /* * If the interrupt is already set when the interrupt becomes * enabled, raise an interrupt immediately. */ rtc_update_irq(s); - if ( (data & RTC_PIE) && !(orig & RTC_PIE) ) + if ( (data ^ orig) & RTC_PIE ) + { + if ( !(data & RTC_PIE) ) + { + destroy_periodic_time(&s->pt); + s->period = 0; + } rtc_timer_update(s); + } if ( (data ^ orig) & RTC_SET ) check_update_timer(s); if ( (data ^ orig) & (RTC_24H | RTC_DM_BINARY | RTC_SET) ) @@ -645,6 +678,7 @@ static uint32_t rtc_ioport_read(RTCState *s, uint32_t addr) ret |= RTC_UIP; break; case RTC_REG_C: + check_for_pf_ticks(s); ret = s->hw.cmos_data[s->hw.cmos_index]; s->hw.cmos_data[RTC_REG_C] = 0x00; if ( (ret & RTC_IRQF) && !rtc_mode_is(s, no_ack) ) @@ -652,7 +686,7 @@ static uint32_t rtc_ioport_read(RTCState *s, uint32_t addr) rtc_update_irq(s); check_update_timer(s); alarm_timer_update(s); - rtc_timer_update(s); + s->pt_dead_ticks = 0; break; default: ret = s->hw.cmos_data[s->hw.cmos_index]; @@ -748,7 +782,7 @@ void rtc_reset(struct domain *d) RTCState *s = domain_vrtc(d); destroy_periodic_time(&s->pt); - s->pt_code = 0; + s->period = 0; s->pt.source = PTSRC_isa; } diff --git a/xen/include/asm-x86/hvm/vpt.h b/xen/include/asm-x86/hvm/vpt.h index 87c3a66..9f48635 100644 --- a/xen/include/asm-x86/hvm/vpt.h +++ b/xen/include/asm-x86/hvm/vpt.h @@ -113,7 +113,8 @@ typedef struct RTCState { /* periodic timer */ struct periodic_time pt; s_time_t start_time; - int pt_code; + s_time_t check_ticks_since; + int period; uint8_t pt_dead_ticks; uint32_t use_timer; spinlock_t lock; -- 1.7.10.4 _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx http://lists.xen.org/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |