[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH RFC 1/3] x86/hvm/rtc: Don't run the vpt timer when !REG_B.PIE.
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> --- xen/arch/x86/hvm/rtc.c | 52 ++++++++++++++++++++++++++++++++++--------- xen/include/asm-x86/hvm/vpt.h | 3 ++- 2 files changed, 43 insertions(+), 12 deletions(-) diff --git a/xen/arch/x86/hvm/rtc.c b/xen/arch/x86/hvm/rtc.c index cdedefe..cfc1af9 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,11 +103,30 @@ 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) { int period_code, period, delta; + s_time_t now; struct vcpu *v = vrtc_vcpu(s); ASSERT(spin_is_locked(&s->lock)); @@ -125,24 +144,28 @@ static void rtc_timer_update(RTCState *s) case RTC_REF_CLCK_4MHZ: if ( period_code != 0 ) { - if ( period_code != s->pt_code ) + now = NOW(); + 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->period = period; 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); + else + s->check_ticks_since = now; } break; } /* fall through */ default: destroy_periodic_time(&s->pt); - s->pt_code = 0; + s->period = 0; break; } } @@ -484,6 +507,7 @@ 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 @@ -492,6 +516,11 @@ static int rtc_ioport_write(void *opaque, uint32_t addr, uint32_t data) rtc_update_irq(s); if ( (data & RTC_PIE) && !(orig & RTC_PIE) ) rtc_timer_update(s); + else if ( !(data & RTC_PIE) && (orig & RTC_PIE) ) + { + destroy_periodic_time(&s->pt); + 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 +674,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 +682,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 +778,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.8.5.2 _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx http://lists.xen.org/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |