# HG changeset patch
# User Tim Deegan <Tim.Deegan@xxxxxxxxxxxxx>
# Node ID 5f7b5e5ca14b6c00d8ac23d1a2ece62fcbaebc03
# Parent 992723a0ceb1b5e474797ca2634a07d1ba3faff6
[HVM] Decouple the RTC from the PIT periodic timer
Signed-off-by: Tim Deegan <Tim.Deegan@xxxxxxxxxxxxx>
---
xen/arch/x86/hvm/hvm.c | 17 +++++++
xen/arch/x86/hvm/i8259.c | 12 ----
xen/arch/x86/hvm/rtc.c | 92 +++++++++++++++++++++++++-------------
xen/arch/x86/hvm/svm/svm.c | 23 +--------
xen/arch/x86/hvm/vioapic.c | 4 -
xen/arch/x86/hvm/vmx/vmcs.c | 2
xen/arch/x86/hvm/vmx/vmx.c | 22 ++-------
xen/include/asm-x86/hvm/hvm.h | 1
xen/include/asm-x86/hvm/vmx/vmx.h | 1
xen/include/asm-x86/hvm/vpt.h | 8 ++-
10 files changed, 97 insertions(+), 85 deletions(-)
diff -r 992723a0ceb1 -r 5f7b5e5ca14b xen/arch/x86/hvm/hvm.c
--- a/xen/arch/x86/hvm/hvm.c Thu Nov 16 15:20:05 2006 +0000
+++ b/xen/arch/x86/hvm/hvm.c Thu Nov 16 17:07:23 2006 +0000
@@ -74,6 +74,20 @@ void hvm_set_guest_time(struct vcpu *v,
hvm_funcs.set_tsc_offset(v, v->arch.hvm_vcpu.cache_tsc_offset);
}
+void hvm_migrate_timers(struct vcpu *v)
+{
+ struct periodic_time *pt = &v->domain->arch.hvm_domain.pl_time.periodic_tm;
+ struct PMTState *vpmt = &v->domain->arch.hvm_domain.pl_time.vpmt;
+
+ if ( pt->enabled )
+ {
+ migrate_timer(&pt->timer, v->processor);
+ }
+ migrate_timer(&vcpu_vlapic(v)->vlapic_timer, v->processor);
+ migrate_timer(&vpmt->timer, v->processor);
+ rtc_migrate_timers(v);
+}
+
void hvm_do_resume(struct vcpu *v)
{
ioreq_t *p;
@@ -91,6 +105,9 @@ void hvm_do_resume(struct vcpu *v)
}
pickup_deactive_ticks(pt);
}
+
+ /* Re-enable the RTC timer if needed */
+ rtc_thaw(v);
/* NB. Optimised for common case (p->state == STATE_IOREQ_NONE). */
p = &get_vio(v->domain, v->vcpu_id)->vp_ioreq;
diff -r 992723a0ceb1 -r 5f7b5e5ca14b xen/arch/x86/hvm/i8259.c
--- a/xen/arch/x86/hvm/i8259.c Thu Nov 16 15:20:05 2006 +0000
+++ b/xen/arch/x86/hvm/i8259.c Thu Nov 16 17:07:23 2006 +0000
@@ -536,8 +536,6 @@ int is_periodic_irq(struct vcpu *v, int
int vec;
struct periodic_time *pt =
&(v->domain->arch.hvm_domain.pl_time.periodic_tm);
- struct RTCState *vrtc =
- &(v->domain->arch.hvm_domain.pl_time.vrtc);
if (pt->irq == 0) { /* Is it pit irq? */
if (type == APIC_DM_EXTINT)
@@ -549,16 +547,6 @@ int is_periodic_irq(struct vcpu *v, int
return 1;
}
- if (pt->irq == 8) { /* Or rtc irq? */
- if (type == APIC_DM_EXTINT)
- vec = domain_vpic(v->domain)->pics[1].irq_base;
- else
- vec = domain_vioapic(v->domain)->redirtbl[8].fields.vector;
-
- if (irq == vec)
- return is_rtc_periodic_irq(vrtc);
- }
-
return 0;
}
diff -r 992723a0ceb1 -r 5f7b5e5ca14b xen/arch/x86/hvm/rtc.c
--- a/xen/arch/x86/hvm/rtc.c Thu Nov 16 15:20:05 2006 +0000
+++ b/xen/arch/x86/hvm/rtc.c Thu Nov 16 17:07:23 2006 +0000
@@ -30,40 +30,43 @@
/* #define DEBUG_RTC */
-void rtc_periodic_cb(struct vcpu *v, void *opaque)
-{
- RTCState *s = opaque;
- s->cmos_data[RTC_REG_C] |= 0xc0;
-}
-
-int is_rtc_periodic_irq(void *opaque)
-{
- RTCState *s = opaque;
- return !(s->cmos_data[RTC_REG_C] & RTC_AF ||
- s->cmos_data[RTC_REG_C] & RTC_UF);
-}
-
-static void rtc_timer_update(RTCState *s, int64_t current_time)
+/* Callback that fires the RTC's periodic interrupt */
+void rtc_pie_callback(void *opaque)
+{
+ RTCState *s = opaque;
+ struct hvm_domain *plat = &s->vcpu->domain->arch.hvm_domain;
+ struct vpic *pic = &plat->vpic;
+ /* Record that we have fired */
+ s->cmos_data[RTC_REG_C] |= (RTC_IRQF|RTC_PF); /* 0xc0 */
+ /* Fire */
+ pic_set_irq(pic, s->irq, 1);
+ /* Remember to fire again */
+ s->next_pie = NOW() + s->period;
+ set_timer(&s->pie_timer, s->next_pie);
+}
+
+/* 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;
int period;
- period_code = s->cmos_data[RTC_REG_A] & 0x0f;
+ period_code = s->cmos_data[RTC_REG_A] & RTC_RATE_SELECT;
if (period_code != 0 && (s->cmos_data[RTC_REG_B] & RTC_PIE)) {
if (period_code <= 2)
period_code += 7;
period = 1 << (period_code - 1); /* period in 32 Khz cycles */
period = DIV_ROUND((period * 1000000000ULL), 32768); /* period in ns */
-
+ s->period = period;
#ifdef DEBUG_RTC
printk("HVM_RTC: period = %uns\n", period);
#endif
-
- s->pt = create_periodic_time(period, RTC_IRQ, 0, rtc_periodic_cb, s);
- } else if (s->pt) {
- destroy_periodic_time(s->pt);
- s->pt = NULL;
+ s->next_pie = NOW() + s->period;
+ set_timer(&s->pie_timer, s->next_pie);
+ } else {
+ stop_timer(&s->pie_timer);
}
}
@@ -105,7 +108,7 @@ static int rtc_ioport_write(void *opaque
/* UIP bit is read only */
s->cmos_data[RTC_REG_A] = (data & ~RTC_UIP) |
(s->cmos_data[RTC_REG_A] & RTC_UIP);
- rtc_timer_update(s, hvm_get_clock(s->vcpu));
+ rtc_timer_update(s);
break;
case RTC_REG_B:
if (data & RTC_SET) {
@@ -119,14 +122,14 @@ static int rtc_ioport_write(void *opaque
}
}
s->cmos_data[RTC_REG_B] = data;
- rtc_timer_update(s, hvm_get_clock(s->vcpu));
+ rtc_timer_update(s);
break;
case RTC_REG_C:
case RTC_REG_D:
/* cannot write to them */
break;
+ }
return 1;
- }
}
return 0;
}
@@ -172,7 +175,7 @@ static void rtc_copy_date(RTCState *s)
s->cmos_data[RTC_SECONDS] = to_bcd(s, tm->tm_sec);
s->cmos_data[RTC_MINUTES] = to_bcd(s, tm->tm_min);
- if (s->cmos_data[RTC_REG_B] & 0x02) {
+ if (s->cmos_data[RTC_REG_B] & RTC_24H) {
/* 24 hour format */
s->cmos_data[RTC_HOURS] = to_bcd(s, tm->tm_hour);
} else {
@@ -245,7 +248,7 @@ static void rtc_update_second(void *opaq
RTCState *s = opaque;
/* if the oscillator is not in normal operation, we do not update */
- if ((s->cmos_data[RTC_REG_A] & 0x70) != 0x20) {
+ if ((s->cmos_data[RTC_REG_A] & RTC_DIV_CTL) != RTC_REF_CLCK_32KHZ) {
s->next_second_time += 1000000000ULL;
set_timer(&s->second_timer, s->next_second_time);
} else {
@@ -361,22 +364,48 @@ static int handle_rtc_io(ioreq_t *p)
return 0;
}
+/* Stop the periodic interrupts from this RTC */
+void rtc_freeze(struct vcpu *v)
+{
+ RTCState *s = &v->domain->arch.hvm_domain.pl_time.vrtc;
+ stop_timer(&s->pie_timer);
+}
+
+/* Start them again */
+void rtc_thaw(struct vcpu *v)
+{
+ RTCState *s = &v->domain->arch.hvm_domain.pl_time.vrtc;
+ if ( (s->cmos_data[RTC_REG_A] & RTC_RATE_SELECT) /* Period is not zero */
+ && (s->cmos_data[RTC_REG_B] & RTC_PIE) )
+ set_timer(&s->pie_timer, s->next_pie);
+}
+
+/* Move the RTC timers on to this vcpu's current cpu */
+void rtc_migrate_timers(struct vcpu *v)
+{
+ RTCState *s = &v->domain->arch.hvm_domain.pl_time.vrtc;
+ migrate_timer(&s->second_timer, v->processor);
+ migrate_timer(&s->second_timer2, v->processor);
+ migrate_timer(&s->pie_timer, v->processor);
+}
+
void rtc_init(struct vcpu *v, int base, int irq)
{
RTCState *s = &v->domain->arch.hvm_domain.pl_time.vrtc;
s->vcpu = v;
s->irq = irq;
- s->cmos_data[RTC_REG_A] = 0x26;
- s->cmos_data[RTC_REG_B] = 0x02;
- s->cmos_data[RTC_REG_C] = 0x00;
- s->cmos_data[RTC_REG_D] = 0x80;
+ s->cmos_data[RTC_REG_A] = RTC_REF_CLCK_32KHZ | 6; /* ~1kHz */
+ s->cmos_data[RTC_REG_B] = RTC_24H;
+ s->cmos_data[RTC_REG_C] = 0;
+ s->cmos_data[RTC_REG_D] = RTC_VRT;
s->current_tm = gmtime(get_localtime(v->domain));
rtc_copy_date(s);
init_timer(&s->second_timer, rtc_update_second, s, v->processor);
init_timer(&s->second_timer2, rtc_update_second2, s, v->processor);
+ init_timer(&s->pie_timer, rtc_pie_callback, s, v->processor);
s->next_second_time = NOW() + 1000000000ULL;
set_timer(&s->second_timer2, s->next_second_time);
@@ -390,4 +419,5 @@ void rtc_deinit(struct domain *d)
kill_timer(&s->second_timer);
kill_timer(&s->second_timer2);
-}
+ kill_timer(&s->pie_timer);
+}
diff -r 992723a0ceb1 -r 5f7b5e5ca14b xen/arch/x86/hvm/svm/svm.c
--- a/xen/arch/x86/hvm/svm/svm.c Thu Nov 16 15:20:05 2006 +0000
+++ b/xen/arch/x86/hvm/svm/svm.c Thu Nov 16 17:07:23 2006 +0000
@@ -723,7 +723,10 @@ static void svm_freeze_time(struct vcpu
&& !v->arch.hvm_vcpu.guest_time ) {
v->arch.hvm_vcpu.guest_time = hvm_get_guest_time(v);
if ( test_bit(_VCPUF_blocked, &v->vcpu_flags) )
+ {
stop_timer(&pt->timer);
+ rtc_freeze(v);
+ }
}
}
@@ -850,24 +853,6 @@ int start_svm(void)
}
-static void svm_migrate_timers(struct vcpu *v)
-{
- struct periodic_time *pt =
- &(v->domain->arch.hvm_domain.pl_time.periodic_tm);
- struct RTCState *vrtc = &v->domain->arch.hvm_domain.pl_time.vrtc;
- struct PMTState *vpmt = &v->domain->arch.hvm_domain.pl_time.vpmt;
-
- if ( pt->enabled )
- {
- migrate_timer(&pt->timer, v->processor);
- }
- migrate_timer(&vcpu_vlapic(v)->vlapic_timer, v->processor);
- migrate_timer(&vrtc->second_timer, v->processor);
- migrate_timer(&vrtc->second_timer2, v->processor);
- migrate_timer(&vpmt->timer, v->processor);
-}
-
-
void arch_svm_do_resume(struct vcpu *v)
{
/* pinning VCPU to a different core? */
@@ -880,7 +865,7 @@ void arch_svm_do_resume(struct vcpu *v)
printk("VCPU core pinned: %d to %d\n",
v->arch.hvm_svm.launch_core, smp_processor_id() );
v->arch.hvm_svm.launch_core = smp_processor_id();
- svm_migrate_timers( v );
+ hvm_migrate_timers( v );
hvm_do_resume( v );
reset_stack_and_jump( svm_asm_do_resume );
}
diff -r 992723a0ceb1 -r 5f7b5e5ca14b xen/arch/x86/hvm/vioapic.c
--- a/xen/arch/x86/hvm/vioapic.c Thu Nov 16 15:20:05 2006 +0000
+++ b/xen/arch/x86/hvm/vioapic.c Thu Nov 16 17:07:23 2006 +0000
@@ -471,8 +471,8 @@ void vioapic_set_irq(struct domain *d, i
struct vioapic *vioapic = domain_vioapic(d);
uint32_t bit;
- HVM_DBG_LOG(DBG_LEVEL_IOAPIC, "ioapic_set_irq "
- "irq %x level %x\n", irq, level);
+ HVM_DBG_LOG(DBG_LEVEL_IOAPIC, "ioapic_set_irq irq %x level %x",
+ irq, level);
if ( (irq < 0) || (irq >= VIOAPIC_NUM_PINS) )
return;
diff -r 992723a0ceb1 -r 5f7b5e5ca14b xen/arch/x86/hvm/vmx/vmcs.c
--- a/xen/arch/x86/hvm/vmx/vmcs.c Thu Nov 16 15:20:05 2006 +0000
+++ b/xen/arch/x86/hvm/vmx/vmcs.c Thu Nov 16 17:07:23 2006 +0000
@@ -486,7 +486,7 @@ void arch_vmx_do_resume(struct vcpu *v)
{
vmx_clear_vmcs(v);
vmx_load_vmcs(v);
- vmx_migrate_timers(v);
+ hvm_migrate_timers(v);
vmx_set_host_env(v);
}
diff -r 992723a0ceb1 -r 5f7b5e5ca14b xen/arch/x86/hvm/vmx/vmx.c
--- a/xen/arch/x86/hvm/vmx/vmx.c Thu Nov 16 15:20:05 2006 +0000
+++ b/xen/arch/x86/hvm/vmx/vmx.c Thu Nov 16 17:07:23 2006 +0000
@@ -376,14 +376,18 @@ static inline void vmx_restore_dr(struct
static void vmx_freeze_time(struct vcpu *v)
{
- struct periodic_time *pt=&v->domain->arch.hvm_domain.pl_time.periodic_tm;
+ struct hvm_domain *plat = &v->domain->arch.hvm_domain;
+ struct periodic_time *pt = &plat->pl_time.periodic_tm;
if ( pt->enabled && pt->first_injected
&& (v->vcpu_id == pt->bind_vcpu)
&& !v->arch.hvm_vcpu.guest_time ) {
v->arch.hvm_vcpu.guest_time = hvm_get_guest_time(v);
if ( !test_bit(_VCPUF_blocked, &v->vcpu_flags) )
+ {
stop_timer(&pt->timer);
+ rtc_freeze(v);
+ }
}
}
@@ -407,22 +411,6 @@ static void stop_vmx(void)
return;
__vmxoff();
clear_in_cr4(X86_CR4_VMXE);
-}
-
-void vmx_migrate_timers(struct vcpu *v)
-{
- struct periodic_time *pt = &v->domain->arch.hvm_domain.pl_time.periodic_tm;
- struct RTCState *vrtc = &v->domain->arch.hvm_domain.pl_time.vrtc;
- struct PMTState *vpmt = &v->domain->arch.hvm_domain.pl_time.vpmt;
-
- if ( pt->enabled )
- {
- migrate_timer(&pt->timer, v->processor);
- }
- migrate_timer(&vcpu_vlapic(v)->vlapic_timer, v->processor);
- migrate_timer(&vrtc->second_timer, v->processor);
- migrate_timer(&vrtc->second_timer2, v->processor);
- migrate_timer(&vpmt->timer, v->processor);
}
static void vmx_store_cpu_guest_regs(
diff -r 992723a0ceb1 -r 5f7b5e5ca14b xen/include/asm-x86/hvm/hvm.h
--- a/xen/include/asm-x86/hvm/hvm.h Thu Nov 16 15:20:05 2006 +0000
+++ b/xen/include/asm-x86/hvm/hvm.h Thu Nov 16 17:07:23 2006 +0000
@@ -161,6 +161,7 @@ hvm_get_guest_ctrl_reg(struct vcpu *v, u
void hvm_stts(struct vcpu *v);
void hvm_set_guest_time(struct vcpu *v, u64 gtime);
+void hvm_migrate_timers(struct vcpu *v);
void hvm_do_resume(struct vcpu *v);
static inline void
diff -r 992723a0ceb1 -r 5f7b5e5ca14b xen/include/asm-x86/hvm/vmx/vmx.h
--- a/xen/include/asm-x86/hvm/vmx/vmx.h Thu Nov 16 15:20:05 2006 +0000
+++ b/xen/include/asm-x86/hvm/vmx/vmx.h Thu Nov 16 17:07:23 2006 +0000
@@ -29,7 +29,6 @@ extern void vmx_asm_vmexit_handler(struc
extern void vmx_asm_vmexit_handler(struct cpu_user_regs);
extern void vmx_asm_do_vmentry(void);
extern void vmx_intr_assist(void);
-extern void vmx_migrate_timers(struct vcpu *v);
extern void arch_vmx_do_resume(struct vcpu *);
extern void set_guest_time(struct vcpu *v, u64 gtime);
diff -r 992723a0ceb1 -r 5f7b5e5ca14b xen/include/asm-x86/hvm/vpt.h
--- a/xen/include/asm-x86/hvm/vpt.h Thu Nov 16 15:20:05 2006 +0000
+++ b/xen/include/asm-x86/hvm/vpt.h Thu Nov 16 17:07:23 2006 +0000
@@ -67,8 +67,10 @@ typedef struct RTCState {
int64_t next_second_time;
struct timer second_timer;
struct timer second_timer2;
+ struct timer pie_timer;
+ int period;
+ s_time_t next_pie;
struct vcpu *vcpu;
- struct periodic_time *pt;
} RTCState;
#define FREQUENCE_PMTIMER 3579545
@@ -143,9 +145,11 @@ void pit_init(struct vcpu *v, unsigned l
void pit_init(struct vcpu *v, unsigned long cpu_khz);
void rtc_init(struct vcpu *v, int base, int irq);
void rtc_deinit(struct domain *d);
+void rtc_freeze(struct vcpu *v);
+void rtc_thaw(struct vcpu *v);
+void rtc_migrate_timers(struct vcpu *v);
void pmtimer_init(struct vcpu *v, int base);
void pmtimer_deinit(struct domain *d);
-int is_rtc_periodic_irq(void *opaque);
void pt_timer_fn(void *data);
void pit_time_fired(struct vcpu *v, void *priv);
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|