|
[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 |