[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-changelog] [xen-unstable] [HVM] Enable more than one platform timer (PIT/RTC/HPET)



# HG changeset patch
# User kfraser@xxxxxxxxxxxxxxxxxxxxx
# Date 1166611043 0
# Node ID 2a1edeedf28d9c72492255fba638fbca61da7ee3
# Parent  b17d1bc1febf265b3700dbd34d511947c0cd02e2
[HVM] Enable more than one platform timer (PIT/RTC/HPET)
programmed as periodic timer and adds them to abstract layer, which
keeps track of pending_intr_nr to avoid time interrupt lost and
sync'ed timer with TSC.

It also makes some cleanup to the time related code.

Signed-off-by: Xiaowei Yang <xiaowei.yang@xxxxxxxxx>
Signed-off-by: Yunhong Jiang <yunhong.jiang@xxxxxxxxx>
---
 xen/arch/x86/domain.c            |    3 +
 xen/arch/x86/hvm/Makefile        |    1 
 xen/arch/x86/hvm/hvm.c           |   67 ++--------------------------
 xen/arch/x86/hvm/i8254.c         |   53 +++++++++++++++-------
 xen/arch/x86/hvm/intercept.c     |   92 --------------------------------------
 xen/arch/x86/hvm/io.c            |   20 --------
 xen/arch/x86/hvm/irq.c           |   48 ++++++++++++++++++++
 xen/arch/x86/hvm/pmtimer.c       |    8 +++
 xen/arch/x86/hvm/rtc.c           |   80 +++++++++++++--------------------
 xen/arch/x86/hvm/svm/intr.c      |   12 +----
 xen/arch/x86/hvm/svm/svm.c       |    3 -
 xen/arch/x86/hvm/vlapic.c        |   27 -----------
 xen/arch/x86/hvm/vmx/intr.c      |    8 ---
 xen/arch/x86/hvm/vmx/vmx.c       |   11 ----
 xen/arch/x86/hvm/vpic.c          |   16 ------
 xen/include/asm-x86/hvm/hvm.h    |    2 
 xen/include/asm-x86/hvm/io.h     |    2 
 xen/include/asm-x86/hvm/irq.h    |    5 ++
 xen/include/asm-x86/hvm/vcpu.h   |    1 
 xen/include/asm-x86/hvm/vlapic.h |    2 
 xen/include/asm-x86/hvm/vpt.h    |   93 ++++++++++++++++++---------------------
 21 files changed, 196 insertions(+), 358 deletions(-)

diff -r b17d1bc1febf -r 2a1edeedf28d xen/arch/x86/domain.c
--- a/xen/arch/x86/domain.c     Wed Dec 20 10:14:50 2006 +0000
+++ b/xen/arch/x86/domain.c     Wed Dec 20 10:37:23 2006 +0000
@@ -726,6 +726,9 @@ void context_switch(struct vcpu *prev, s
 
     local_irq_disable();
 
+    if ( is_hvm_vcpu(prev) )
+        pt_freeze_time(prev);
+
     set_current(next);
 
     if ( (per_cpu(curr_vcpu, cpu) == next) || is_idle_vcpu(next) )
diff -r b17d1bc1febf -r 2a1edeedf28d xen/arch/x86/hvm/Makefile
--- a/xen/arch/x86/hvm/Makefile Wed Dec 20 10:14:50 2006 +0000
+++ b/xen/arch/x86/hvm/Makefile Wed Dec 20 10:37:23 2006 +0000
@@ -10,6 +10,7 @@ obj-y += platform.o
 obj-y += platform.o
 obj-y += pmtimer.o
 obj-y += rtc.o
+obj-y += vpt.o
 obj-y += vioapic.o
 obj-y += vlapic.o
 obj-y += vpic.o
diff -r b17d1bc1febf -r 2a1edeedf28d xen/arch/x86/hvm/hvm.c
--- a/xen/arch/x86/hvm/hvm.c    Wed Dec 20 10:14:50 2006 +0000
+++ b/xen/arch/x86/hvm/hvm.c    Wed Dec 20 10:37:23 2006 +0000
@@ -82,56 +82,21 @@ u64 hvm_get_guest_time(struct vcpu *v)
     return host_tsc + v->arch.hvm_vcpu.cache_tsc_offset;
 }
 
-void hvm_freeze_time(struct vcpu *v)
-{
-    struct periodic_time *pt=&v->domain->arch.hvm_domain.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);
-        }
-    }
-}
-
 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);
-    }
+    pit_migrate_timers(v);
+    rtc_migrate_timers(v);
+    pmtimer_migrate_timers(v);
     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;
-    struct periodic_time *pt = &v->domain->arch.hvm_domain.pl_time.periodic_tm;
 
     hvm_stts(v);
 
-    /* Pick up the elapsed PIT ticks and re-enable pit_timer. */
-    if ( pt->enabled && (v->vcpu_id == pt->bind_vcpu) && pt->first_injected )
-    {
-        if ( v->arch.hvm_vcpu.guest_time )
-        {
-            hvm_set_guest_time(v, v->arch.hvm_vcpu.guest_time);
-            v->arch.hvm_vcpu.guest_time = 0;
-        }
-        pickup_deactive_ticks(pt);
-    }
-
-    /* Re-enable the RTC timer if needed */
-    rtc_thaw(v);
+    pt_thaw_time(v);
 
     /* NB. Optimised for common case (p->state == STATE_IOREQ_NONE). */
     p = &get_vio(v->domain, v->vcpu_id)->vp_ioreq;
@@ -182,7 +147,7 @@ int hvm_domain_initialise(struct domain 
 
 void hvm_domain_destroy(struct domain *d)
 {
-    kill_timer(&d->arch.hvm_domain.pl_time.periodic_tm.timer);
+    pit_deinit(d);
     rtc_deinit(d);
     pmtimer_deinit(d);
 
@@ -196,7 +161,6 @@ void hvm_domain_destroy(struct domain *d
 
 int hvm_vcpu_initialise(struct vcpu *v)
 {
-    struct hvm_domain *platform;
     int rc;
 
     if ( (rc = vlapic_init(v)) != 0 )
@@ -214,14 +178,11 @@ int hvm_vcpu_initialise(struct vcpu *v)
         get_vio(v->domain, v->vcpu_id)->vp_eport =
             v->arch.hvm_vcpu.xen_port;
 
+    INIT_LIST_HEAD(&v->arch.hvm_vcpu.tm_list);
+
     if ( v->vcpu_id != 0 )
         return 0;
 
-    /* XXX Below should happen in hvm_domain_initialise(). */
-    platform = &v->domain->arch.hvm_domain;
-
-    init_timer(&platform->pl_time.periodic_tm.timer,
-               pt_timer_fn, v, v->processor);
     rtc_init(v, RTC_PORT(0), RTC_IRQ);
     pmtimer_init(v, ACPI_PM_TMR_BLK_ADDRESS);
 
@@ -238,20 +199,6 @@ void hvm_vcpu_destroy(struct vcpu *v)
 
     /* Event channel is already freed by evtchn_destroy(). */
     /*free_xen_event_channel(v, v->arch.hvm_vcpu.xen_port);*/
-}
-
-int cpu_get_interrupt(struct vcpu *v, int *type)
-{
-    int vector;
-
-    if ( (vector = cpu_get_apic_interrupt(v, type)) != -1 )
-        return vector;
-
-    if ( (v->vcpu_id == 0) &&
-         ((vector = cpu_get_pic_interrupt(v, type)) != -1) )
-        return vector;
-
-    return -1;
 }
 
 static void hvm_vcpu_down(void)
diff -r b17d1bc1febf -r 2a1edeedf28d xen/arch/x86/hvm/i8254.c
--- a/xen/arch/x86/hvm/i8254.c  Wed Dec 20 10:14:50 2006 +0000
+++ b/xen/arch/x86/hvm/i8254.c  Wed Dec 20 10:37:23 2006 +0000
@@ -81,7 +81,7 @@ static int pit_get_count(PITChannelState
     uint64_t d;
     int  counter;
 
-    d = muldiv64(hvm_get_clock(s->vcpu) - s->count_load_time, PIT_FREQ, 
ticks_per_sec(s->vcpu));
+    d = muldiv64(hvm_get_guest_time(s->pt.vcpu) - s->count_load_time, 
PIT_FREQ, ticks_per_sec(s->pt.vcpu));
     switch(s->mode) {
     case 0:
     case 1:
@@ -106,7 +106,7 @@ static int pit_get_out1(PITChannelState 
     uint64_t d;
     int out;
 
-    d = muldiv64(current_time - s->count_load_time, PIT_FREQ, 
ticks_per_sec(s->vcpu));
+    d = muldiv64(current_time - s->count_load_time, PIT_FREQ, 
ticks_per_sec(s->pt.vcpu));
     switch(s->mode) {
     default:
     case 0:
@@ -153,7 +153,7 @@ void pit_set_gate(PITState *pit, int cha
     case 5:
         if (s->gate < val) {
             /* restart counting on rising edge */
-            s->count_load_time = hvm_get_clock(s->vcpu);
+            s->count_load_time = hvm_get_guest_time(s->pt.vcpu);
 //            pit_irq_timer_update(s, s->count_load_time);
         }
         break;
@@ -161,7 +161,7 @@ void pit_set_gate(PITState *pit, int cha
     case 3:
         if (s->gate < val) {
             /* restart counting on rising edge */
-            s->count_load_time = hvm_get_clock(s->vcpu);
+            s->count_load_time = hvm_get_guest_time(s->pt.vcpu);
 //            pit_irq_timer_update(s, s->count_load_time);
         }
         /* XXX: disable/enable counting */
@@ -179,7 +179,7 @@ void pit_time_fired(struct vcpu *v, void
 void pit_time_fired(struct vcpu *v, void *priv)
 {
     PITChannelState *s = priv;
-    s->count_load_time = hvm_get_clock(v);
+    s->count_load_time = hvm_get_guest_time(v);
 }
 
 static inline void pit_load_count(PITChannelState *s, int val)
@@ -190,7 +190,7 @@ static inline void pit_load_count(PITCha
 
     if (val == 0)
         val = 0x10000;
-    s->count_load_time = hvm_get_clock(s->vcpu);
+    s->count_load_time = hvm_get_guest_time(s->pt.vcpu);
     s->count = val;
     period = DIV_ROUND((val * 1000000000ULL), PIT_FREQ);
 
@@ -209,16 +209,17 @@ static inline void pit_load_count(PITCha
     switch (s->mode) {
         case 2:
             /* create periodic time */
-            s->pt = create_periodic_time (period, 0, 0, pit_time_fired, s);
+            create_periodic_time(&s->pt, period, 0, 0, pit_time_fired, s);
             break;
         case 1:
             /* create one shot time */
-            s->pt = create_periodic_time (period, 0, 1, pit_time_fired, s);
+            create_periodic_time(&s->pt, period, 0, 1, pit_time_fired, s);
 #ifdef DEBUG_PIT
             printk("HVM_PIT: create one shot time.\n");
 #endif
             break;
         default:
+            destroy_periodic_time(&s->pt);
             break;
     }
 }
@@ -253,7 +254,7 @@ static void pit_ioport_write(void *opaqu
                     if (!(val & 0x10) && !s->status_latched) {
                         /* status latch */
                         /* XXX: add BCD and null count */
-                        s->status =  (pit_get_out1(s, hvm_get_clock(s->vcpu)) 
<< 7) |
+                        s->status =  (pit_get_out1(s, 
hvm_get_guest_time(s->pt.vcpu)) << 7) |
                             (s->rw_mode << 4) |
                             (s->mode << 1) |
                             s->bcd;
@@ -359,10 +360,7 @@ static void pit_reset(void *opaque)
 
     for(i = 0;i < 3; i++) {
         s = &pit->channels[i];
-        if ( s -> pt ) {
-            destroy_periodic_time (s->pt);
-            s->pt = NULL;
-        }
+        destroy_periodic_time(&s->pt);
         s->mode = 0xff; /* the init mode */
         s->gate = (i != 2);
         pit_load_count(s, 0);
@@ -375,10 +373,11 @@ void pit_init(struct vcpu *v, unsigned l
     PITChannelState *s;
 
     s = &pit->channels[0];
+    s->pt.vcpu = v;
     /* the timer 0 is connected to an IRQ */
-    s->vcpu = v;
-    s++; s->vcpu = v;
-    s++; s->vcpu = v;
+    init_timer(&s->pt.timer, pt_timer_fn, &s->pt, v->processor);
+    s++; s->pt.vcpu = v;
+    s++; s->pt.vcpu = v;
 
     register_portio_handler(v->domain, PIT_BASE, 4, handle_pit_io);
     /* register the speaker port */
@@ -391,6 +390,25 @@ void pit_init(struct vcpu *v, unsigned l
     return;
 }
 
+void pit_migrate_timers(struct vcpu *v)
+{
+    PITState *pit = &v->domain->arch.hvm_domain.pl_time.vpit;
+    PITChannelState *s;
+
+    s = &pit->channels[0];
+    if ( s->pt.vcpu == v && s->pt.enabled )
+        migrate_timer(&s->pt.timer, v->processor);
+}
+
+void pit_deinit(struct domain *d)
+{
+    PITState *pit = &d->arch.hvm_domain.pl_time.vpit;
+    PITChannelState *s;
+
+    s = &pit->channels[0];
+    kill_timer(&s->pt.timer);
+}
+
 /* the intercept action for PIT DM retval:0--not handled; 1--handled */  
 static int handle_pit_io(ioreq_t *p)
 {
@@ -426,7 +444,8 @@ static uint32_t speaker_ioport_read(void
 static uint32_t speaker_ioport_read(void *opaque, uint32_t addr)
 {
     PITState *pit = opaque;
-    int out = pit_get_out(pit, 2, hvm_get_clock(pit->channels[2].vcpu));
+    int out = pit_get_out(pit, 2,
+                          hvm_get_guest_time(pit->channels[2].pt.vcpu));
     /* Refresh clock toggles at about 15us. We approximate as 2^14ns. */
     unsigned int refresh_clock = ((unsigned int)NOW() >> 14) & 1;
     return ((pit->speaker_data_on << 1) | pit_get_gate(pit, 2) |
diff -r b17d1bc1febf -r 2a1edeedf28d xen/arch/x86/hvm/intercept.c
--- a/xen/arch/x86/hvm/intercept.c      Wed Dec 20 10:14:50 2006 +0000
+++ b/xen/arch/x86/hvm/intercept.c      Wed Dec 20 10:37:23 2006 +0000
@@ -263,98 +263,6 @@ int register_io_handler(
 
     return 1;
 }
-
-static __inline__ void missed_ticks(struct periodic_time *pt)
-{
-    s_time_t missed_ticks;
-
-    missed_ticks = NOW() - pt->scheduled;
-    if ( missed_ticks > 0 ) {
-        missed_ticks = missed_ticks / (s_time_t) pt->period + 1;
-        if ( missed_ticks > 1000 ) {
-            /* TODO: Adjust guest time togther */
-            pt->pending_intr_nr++;
-        }
-        else {
-            pt->pending_intr_nr += missed_ticks;
-        }
-        pt->scheduled += missed_ticks * pt->period;
-    }
-}
-
-/* hook function for the platform periodic time */
-void pt_timer_fn(void *data)
-{
-    struct vcpu *v = data;
-    struct periodic_time *pt = &v->domain->arch.hvm_domain.pl_time.periodic_tm;
-
-    pt->pending_intr_nr++;
-    pt->scheduled += pt->period;
-
-    /* Pick up missed timer ticks. */
-    missed_ticks(pt);
-
-    /* No need to run the timer while a VCPU is descheduled. */
-    if ( test_bit(_VCPUF_running, &v->vcpu_flags) )
-        set_timer(&pt->timer, pt->scheduled);
-
-    vcpu_kick(v);
-}
-
-/* pick up missed timer ticks at deactive time */
-void pickup_deactive_ticks(struct periodic_time *pt)
-{
-    if ( !active_timer(&(pt->timer)) ) {
-        missed_ticks(pt);
-        set_timer(&pt->timer, pt->scheduled);
-    }
-}
-
-/*
- * period: fire frequency in ns.
- */
-struct periodic_time * create_periodic_time(
-        u32 period, 
-        char irq,
-        char one_shot,
-        time_cb *cb,
-        void *data)
-{
-    struct periodic_time *pt = 
&(current->domain->arch.hvm_domain.pl_time.periodic_tm);
-    if ( pt->enabled ) {
-        stop_timer (&pt->timer);
-        pt->enabled = 0;
-    }
-    pt->bind_vcpu = 0; /* timer interrupt delivered to BSP by default */
-    pt->pending_intr_nr = 0;
-    pt->first_injected = 0;
-    if (period < 900000) { /* < 0.9 ms */
-        printk("HVM_PlatformTime: program too small period %u\n",period);
-        period = 900000;   /* force to 0.9ms */
-    }
-    pt->period = period;
-    pt->irq = irq;
-    pt->period_cycles = (u64)period * cpu_khz / 1000000L;
-    pt->one_shot = one_shot;
-    if ( one_shot ) {
-        printk("HVM_PL: No support for one shot platform time yet\n");
-    }
-    pt->scheduled = NOW() + period;
-    set_timer (&pt->timer,pt->scheduled);
-    pt->enabled = 1;
-    pt->cb = cb;
-    pt->priv = data;
-    return pt;
-}
-
-void destroy_periodic_time(struct periodic_time *pt)
-{
-    if ( pt->enabled ) {
-        stop_timer(&pt->timer);
-        pt->enabled = 0;
-    }
-}
-
 /*
  * Local variables:
  * mode: C
diff -r b17d1bc1febf -r 2a1edeedf28d xen/arch/x86/hvm/io.c
--- a/xen/arch/x86/hvm/io.c     Wed Dec 20 10:14:50 2006 +0000
+++ b/xen/arch/x86/hvm/io.c     Wed Dec 20 10:37:23 2006 +0000
@@ -691,25 +691,7 @@ static void hvm_mmio_assist(struct cpu_u
 
 void hvm_interrupt_post(struct vcpu *v, int vector, int type)
 {
-    struct  periodic_time *pt = 
-        &(v->domain->arch.hvm_domain.pl_time.periodic_tm);
-
-    if ( pt->enabled && v->vcpu_id == pt->bind_vcpu 
-            && is_periodic_irq(v, vector, type) ) {
-        if ( !pt->first_injected ) {
-            pt->pending_intr_nr = 0;
-            pt->last_plt_gtime = hvm_get_guest_time(v);
-            pt->scheduled = NOW() + pt->period;
-            set_timer(&pt->timer, pt->scheduled);
-            pt->first_injected = 1;
-        } else {
-            pt->pending_intr_nr--;
-            pt->last_plt_gtime += pt->period_cycles;
-            hvm_set_guest_time(v, pt->last_plt_gtime);
-        }
-        if (pt->cb)
-            pt->cb(v, pt->priv);
-    }
+    pt_intr_post(v, vector, type);
     
     switch(type) {
     case APIC_DM_EXTINT:
diff -r b17d1bc1febf -r 2a1edeedf28d xen/arch/x86/hvm/irq.c
--- a/xen/arch/x86/hvm/irq.c    Wed Dec 20 10:14:50 2006 +0000
+++ b/xen/arch/x86/hvm/irq.c    Wed Dec 20 10:37:23 2006 +0000
@@ -225,3 +225,51 @@ void hvm_set_callback_gsi(struct domain 
     dprintk(XENLOG_G_INFO, "Dom%u callback GSI changed %u -> %u\n",
             d->domain_id, old_gsi, gsi);
 }
+
+int cpu_has_pending_irq(struct vcpu *v)
+{
+    struct hvm_domain *plat = &v->domain->arch.hvm_domain;
+    int dummy;
+
+    /* APIC */
+    if ( cpu_get_apic_interrupt(v, &dummy) != -1 )
+        return 1;
+
+    /* PIC */
+    if ( !vlapic_accept_pic_intr(v) )
+        return 0;
+
+    return plat->irq.vpic[0].int_output;
+}
+
+int cpu_get_interrupt(struct vcpu *v, int *type)
+{
+    int vector;
+
+    if ( (vector = cpu_get_apic_interrupt(v, type)) != -1 )
+        return vector;
+
+    if ( (v->vcpu_id == 0) &&
+         ((vector = cpu_get_pic_interrupt(v, type)) != -1) )
+        return vector;
+
+    return -1;
+}
+
+int get_intr_vector(struct vcpu* v, int irq, int type)
+{
+    if ( type == APIC_DM_EXTINT )
+        return v->domain->arch.hvm_domain.irq.vpic[irq >> 3].irq_base
+                + (irq & 0x7);
+
+    return domain_vioapic(v->domain)->redirtbl[irq].fields.vector;
+}
+
+int is_irq_masked(struct vcpu *v, int irq)
+{
+    if ( v->domain->arch.hvm_domain.irq.vpic[irq >> 3].imr & (1 << (irq & 7))
+            && domain_vioapic(v->domain)->redirtbl[irq].fields.mask )
+        return 1;
+
+    return 0;
+}
diff -r b17d1bc1febf -r 2a1edeedf28d xen/arch/x86/hvm/pmtimer.c
--- a/xen/arch/x86/hvm/pmtimer.c        Wed Dec 20 10:14:50 2006 +0000
+++ b/xen/arch/x86/hvm/pmtimer.c        Wed Dec 20 10:37:23 2006 +0000
@@ -55,6 +55,14 @@ void pmtimer_init(struct vcpu *v, int ba
     register_portio_handler(v->domain, base, 4, handle_pmt_io);
 }
 
+void pmtimer_migrate_timers(struct vcpu *v)
+{
+    struct PMTState *vpmt = &v->domain->arch.hvm_domain.pl_time.vpmt;
+
+    if (vpmt->vcpu == v)
+        migrate_timer(&vpmt->timer, v->processor);
+}
+
 void pmtimer_deinit(struct domain *d)
 {
     PMTState *s = &d->arch.hvm_domain.pl_time.vpmt;
diff -r b17d1bc1febf -r 2a1edeedf28d xen/arch/x86/hvm/rtc.c
--- a/xen/arch/x86/hvm/rtc.c    Wed Dec 20 10:14:50 2006 +0000
+++ b/xen/arch/x86/hvm/rtc.c    Wed Dec 20 10:37:23 2006 +0000
@@ -30,17 +30,18 @@
 
 /* #define DEBUG_RTC */
 
-/* Callback that fires the RTC's periodic interrupt */
-void rtc_pie_callback(void *opaque)
-{
-    RTCState *s = opaque;
-    /* Record that we have fired */
-    s->cmos_data[RTC_REG_C] |= (RTC_IRQF|RTC_PF); /* 0xc0 */
-    /* Fire */
-    hvm_isa_irq_assert(s->vcpu->domain, s->irq);
-    /* Remember to fire again */
-    s->next_pie = NOW() + s->period;
-    set_timer(&s->pie_timer, s->next_pie);
+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);
 }
 
 /* Enable/configure/disable the periodic timer based on the RTC_PIE and
@@ -58,17 +59,13 @@ static void rtc_timer_update(RTCState *s
         
         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->next_pie = NOW() + s->period;
-        set_timer(&s->pie_timer, s->next_pie);
-    }
-    else
-    {
-        stop_timer(&s->pie_timer);
-    }
+        create_periodic_time(&s->pt, period, RTC_IRQ, 0, rtc_periodic_cb, s);
+    } 
+    else
+        destroy_periodic_time(&s->pt);
 }
 
 static void rtc_set_time(RTCState *s);
@@ -292,8 +289,8 @@ static void rtc_update_second2(void *opa
               s->current_tm.tm_hour) )
         {
             s->cmos_data[RTC_REG_C] |= 0xa0; 
-            hvm_isa_irq_deassert(s->vcpu->domain, s->irq);
-            hvm_isa_irq_assert(s->vcpu->domain, s->irq);
+            hvm_isa_irq_deassert(s->pt.vcpu->domain, s->irq);
+            hvm_isa_irq_assert(s->pt.vcpu->domain, s->irq);
         }
     }
 
@@ -301,8 +298,8 @@ static void rtc_update_second2(void *opa
     if ( s->cmos_data[RTC_REG_B] & RTC_UIE )
     {
         s->cmos_data[RTC_REG_C] |= 0x90; 
-        hvm_isa_irq_deassert(s->vcpu->domain, s->irq);
-        hvm_isa_irq_assert(s->vcpu->domain, s->irq);
+        hvm_isa_irq_deassert(s->pt.vcpu->domain, s->irq);
+        hvm_isa_irq_assert(s->pt.vcpu->domain, s->irq);
     }
 
     /* clear update in progress bit */
@@ -336,7 +333,7 @@ static uint32_t rtc_ioport_read(void *op
         break;
     case RTC_REG_C:
         ret = s->cmos_data[s->cmos_index];
-        hvm_isa_irq_deassert(s->vcpu->domain, s->irq);
+        hvm_isa_irq_deassert(s->pt.vcpu->domain, s->irq);
         s->cmos_data[RTC_REG_C] = 0x00; 
         break;
     default:
@@ -377,36 +374,25 @@ 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);
+
+    if ( s->pt.vcpu == v )
+    {
+        if ( s->pt.enabled )
+            migrate_timer(&s->pt.timer, v->processor);
+        migrate_timer(&s->second_timer, v->processor);
+        migrate_timer(&s->second_timer2, 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->pt.vcpu = v;
     s->irq = irq;
     s->cmos_data[RTC_REG_A] = RTC_REF_CLCK_32KHZ | 6; /* ~1kHz */
     s->cmos_data[RTC_REG_B] = RTC_24H;
@@ -416,9 +402,9 @@ void rtc_init(struct vcpu *v, int base, 
     s->current_tm = gmtime(get_localtime(v->domain));
     rtc_copy_date(s);
 
+    init_timer(&s->pt.timer, pt_timer_fn, &s->pt, v->processor);
     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);
@@ -430,7 +416,7 @@ void rtc_deinit(struct domain *d)
 {
     RTCState *s = &d->arch.hvm_domain.pl_time.vrtc;
 
+    kill_timer(&s->pt.timer);
     kill_timer(&s->second_timer);
     kill_timer(&s->second_timer2);
-    kill_timer(&s->pie_timer);
-}
+}
diff -r b17d1bc1febf -r 2a1edeedf28d xen/arch/x86/hvm/svm/intr.c
--- a/xen/arch/x86/hvm/svm/intr.c       Wed Dec 20 10:14:50 2006 +0000
+++ b/xen/arch/x86/hvm/svm/intr.c       Wed Dec 20 10:37:23 2006 +0000
@@ -63,8 +63,7 @@ asmlinkage void svm_intr_assist(void)
 {
     struct vcpu *v = current;
     struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb;
-    struct hvm_domain *plat=&v->domain->arch.hvm_domain;
-    struct periodic_time *pt = &plat->pl_time.periodic_tm;
+    struct periodic_time *pt;
     int intr_type = APIC_DM_EXTINT;
     int intr_vector = -1;
     int re_injecting = 0;
@@ -95,11 +94,7 @@ asmlinkage void svm_intr_assist(void)
     /* Now let's check for newer interrrupts  */
     else
     {
-        if ( (v->vcpu_id == 0) && pt->enabled && pt->pending_intr_nr )
-        {
-            hvm_isa_irq_deassert(current->domain, pt->irq);
-            hvm_isa_irq_assert(current->domain, pt->irq);
-        }
+        pt_update_irq(v);
 
         hvm_set_callback_irq_level();
 
@@ -130,8 +125,7 @@ asmlinkage void svm_intr_assist(void)
     case APIC_DM_FIXED:
     case APIC_DM_LOWEST:
         /* Re-injecting a PIT interruptt? */
-        if ( re_injecting && pt->enabled && 
-             is_periodic_irq(v, intr_vector, intr_type) )
+        if ( re_injecting && (pt = is_pt_irq(v, intr_vector, intr_type)) )
             ++pt->pending_intr_nr;
         /* let's inject this interrupt */
         TRACE_3D(TRC_VMX_INTR, v->domain->domain_id, intr_vector, 0);
diff -r b17d1bc1febf -r 2a1edeedf28d xen/arch/x86/hvm/svm/svm.c
--- a/xen/arch/x86/hvm/svm/svm.c        Wed Dec 20 10:14:50 2006 +0000
+++ b/xen/arch/x86/hvm/svm/svm.c        Wed Dec 20 10:37:23 2006 +0000
@@ -46,6 +46,7 @@
 #include <asm/hvm/svm/intr.h>
 #include <asm/x86_emulate.h>
 #include <public/sched.h>
+#include <asm/hvm/vpt.h>
 
 #define SVM_EXTRA_DEBUG
 
@@ -770,7 +771,6 @@ static void arch_svm_do_launch(struct vc
 
 static void svm_ctxt_switch_from(struct vcpu *v)
 {
-    hvm_freeze_time(v);
     svm_save_dr(v);
 }
 
@@ -1994,6 +1994,7 @@ static inline void svm_do_msr_access(
         switch (ecx)
         {
         case MSR_IA32_TIME_STAMP_COUNTER:
+            pt_reset(v);
             hvm_set_guest_time(v, msr_content);
             break;
         case MSR_IA32_SYSENTER_CS:
diff -r b17d1bc1febf -r 2a1edeedf28d xen/arch/x86/hvm/vlapic.c
--- a/xen/arch/x86/hvm/vlapic.c Wed Dec 20 10:14:50 2006 +0000
+++ b/xen/arch/x86/hvm/vlapic.c Wed Dec 20 10:37:23 2006 +0000
@@ -154,16 +154,6 @@ int vlapic_set_irq(struct vlapic *vlapic
     return ret;
 }
 
-s_time_t get_apictime_scheduled(struct vcpu *v)
-{
-    struct vlapic *vlapic = vcpu_vlapic(v);
-
-    if ( !vlapic_lvt_enabled(vlapic, APIC_LVTT) )
-        return -1;
-
-    return vlapic->vlapic_timer.expires;
-}
-
 int vlapic_find_highest_isr(struct vlapic *vlapic)
 {
     int result;
@@ -836,23 +826,6 @@ int cpu_get_apic_interrupt(struct vcpu *
     return highest_irr;
 }
 
-/* check to see if there is pending interrupt  */
-int cpu_has_pending_irq(struct vcpu *v)
-{
-    struct hvm_domain *plat = &v->domain->arch.hvm_domain;
-    int dummy;
-
-    /* APIC */
-    if ( cpu_get_apic_interrupt(v, &dummy) != -1 )
-        return 1;
-
-    /* PIC */
-    if ( !vlapic_accept_pic_intr(v) )
-        return 0;
-
-    return plat->irq.vpic[0].int_output;
-}
-
 void vlapic_post_injection(struct vcpu *v, int vector, int deliver_mode)
 {
     struct vlapic *vlapic = vcpu_vlapic(v);
diff -r b17d1bc1febf -r 2a1edeedf28d xen/arch/x86/hvm/vmx/intr.c
--- a/xen/arch/x86/hvm/vmx/intr.c       Wed Dec 20 10:14:50 2006 +0000
+++ b/xen/arch/x86/hvm/vmx/intr.c       Wed Dec 20 10:37:23 2006 +0000
@@ -91,17 +91,11 @@ asmlinkage void vmx_intr_assist(void)
     int highest_vector;
     unsigned long eflags;
     struct vcpu *v = current;
-    struct hvm_domain *plat=&v->domain->arch.hvm_domain;
-    struct periodic_time *pt = &plat->pl_time.periodic_tm;
     unsigned int idtv_info_field;
     unsigned long inst_len;
     int    has_ext_irq;
 
-    if ( (v->vcpu_id == 0) && pt->enabled && pt->pending_intr_nr )
-    {
-        hvm_isa_irq_deassert(current->domain, pt->irq);
-        hvm_isa_irq_assert(current->domain, pt->irq);
-    }
+    pt_update_irq(v);
 
     hvm_set_callback_irq_level();
 
diff -r b17d1bc1febf -r 2a1edeedf28d xen/arch/x86/hvm/vmx/vmx.c
--- a/xen/arch/x86/hvm/vmx/vmx.c        Wed Dec 20 10:14:50 2006 +0000
+++ b/xen/arch/x86/hvm/vmx/vmx.c        Wed Dec 20 10:37:23 2006 +0000
@@ -46,6 +46,7 @@
 #include <asm/hvm/vpic.h>
 #include <asm/hvm/vlapic.h>
 #include <asm/x86_emulate.h>
+#include <asm/hvm/vpt.h>
 
 static void vmx_ctxt_switch_from(struct vcpu *v);
 static void vmx_ctxt_switch_to(struct vcpu *v);
@@ -372,8 +373,6 @@ static inline void vmx_restore_dr(struct
 
 static void vmx_ctxt_switch_from(struct vcpu *v)
 {
-    hvm_freeze_time(v);
-
     /* NB. MSR_SHADOW_GS_BASE may be changed by swapgs instrucion in guest,
      * so we must save it. */
     rdmsrl(MSR_SHADOW_GS_BASE, v->arch.hvm_vmx.msr_state.shadow_gs);
@@ -2072,13 +2071,7 @@ static inline int vmx_do_msr_write(struc
 
     switch (ecx) {
     case MSR_IA32_TIME_STAMP_COUNTER:
-        {
-            struct periodic_time *pt =
-                &(v->domain->arch.hvm_domain.pl_time.periodic_tm);
-            if ( pt->enabled && pt->first_injected
-                    && v->vcpu_id == pt->bind_vcpu )
-                pt->first_injected = 0;
-        }
+        pt_reset(v);
         hvm_set_guest_time(v, msr_content);
         break;
     case MSR_IA32_SYSENTER_CS:
diff -r b17d1bc1febf -r 2a1edeedf28d xen/arch/x86/hvm/vpic.c
--- a/xen/arch/x86/hvm/vpic.c   Wed Dec 20 10:14:50 2006 +0000
+++ b/xen/arch/x86/hvm/vpic.c   Wed Dec 20 10:37:23 2006 +0000
@@ -445,19 +445,3 @@ int cpu_get_pic_interrupt(struct vcpu *v
     *type = APIC_DM_EXTINT;
     return vector;
 }
-
-int is_periodic_irq(struct vcpu *v, int irq, int type)
-{
-    int vec;
-    struct periodic_time *pt = &v->domain->arch.hvm_domain.pl_time.periodic_tm;
-
-    if ( pt->irq != 0 )
-        return 0;
-
-    if ( type == APIC_DM_EXTINT )
-        vec = v->domain->arch.hvm_domain.irq.vpic[0].irq_base;
-    else
-        vec = domain_vioapic(v->domain)->redirtbl[0].fields.vector;
-
-    return (irq == vec);
-}
diff -r b17d1bc1febf -r 2a1edeedf28d xen/include/asm-x86/hvm/hvm.h
--- a/xen/include/asm-x86/hvm/hvm.h     Wed Dec 20 10:14:50 2006 +0000
+++ b/xen/include/asm-x86/hvm/hvm.h     Wed Dec 20 10:37:23 2006 +0000
@@ -223,7 +223,7 @@ void hvm_cpuid(unsigned int input, unsig
                                    unsigned int *ecx, unsigned int *edx);
 void hvm_stts(struct vcpu *v);
 void hvm_set_guest_time(struct vcpu *v, u64 gtime);
-void hvm_freeze_time(struct vcpu *v);
+u64 hvm_get_guest_time(struct vcpu *v);
 void hvm_migrate_timers(struct vcpu *v);
 void hvm_do_resume(struct vcpu *v);
 
diff -r b17d1bc1febf -r 2a1edeedf28d xen/include/asm-x86/hvm/io.h
--- a/xen/include/asm-x86/hvm/io.h      Wed Dec 20 10:14:50 2006 +0000
+++ b/xen/include/asm-x86/hvm/io.h      Wed Dec 20 10:37:23 2006 +0000
@@ -147,8 +147,6 @@ extern void handle_mmio(unsigned long gp
 extern void handle_mmio(unsigned long gpa);
 extern void hvm_interrupt_post(struct vcpu *v, int vector, int type);
 extern void hvm_io_assist(struct vcpu *v);
-extern int cpu_get_interrupt(struct vcpu *v, int *type);
-extern int cpu_has_pending_irq(struct vcpu *v);
 
 #endif /* __ASM_X86_HVM_IO_H__ */
 
diff -r b17d1bc1febf -r 2a1edeedf28d xen/include/asm-x86/hvm/irq.h
--- a/xen/include/asm-x86/hvm/irq.h     Wed Dec 20 10:14:50 2006 +0000
+++ b/xen/include/asm-x86/hvm/irq.h     Wed Dec 20 10:37:23 2006 +0000
@@ -104,4 +104,9 @@ void hvm_set_callback_irq_level(void);
 void hvm_set_callback_irq_level(void);
 void hvm_set_callback_gsi(struct domain *d, unsigned int gsi);
 
+int cpu_get_interrupt(struct vcpu *v, int *type);
+int cpu_has_pending_irq(struct vcpu *v);
+int get_intr_vector(struct vcpu* vcpu, int irq, int type);
+int is_irq_masked(struct vcpu *v, int irq);
+
 #endif /* __ASM_X86_HVM_IRQ_H__ */
diff -r b17d1bc1febf -r 2a1edeedf28d xen/include/asm-x86/hvm/vcpu.h
--- a/xen/include/asm-x86/hvm/vcpu.h    Wed Dec 20 10:14:50 2006 +0000
+++ b/xen/include/asm-x86/hvm/vcpu.h    Wed Dec 20 10:37:23 2006 +0000
@@ -35,6 +35,7 @@ struct hvm_vcpu {
     struct vlapic       vlapic;
     s64                 cache_tsc_offset;
     u64                 guest_time;
+    struct list_head    tm_list;
 
     /* For AP startup */
     unsigned long       init_sipi_sipi_state;
diff -r b17d1bc1febf -r 2a1edeedf28d xen/include/asm-x86/hvm/vlapic.h
--- a/xen/include/asm-x86/hvm/vlapic.h  Wed Dec 20 10:14:50 2006 +0000
+++ b/xen/include/asm-x86/hvm/vlapic.h  Wed Dec 20 10:37:23 2006 +0000
@@ -89,8 +89,6 @@ struct vlapic *apic_round_robin(
 struct vlapic *apic_round_robin(
     struct domain *d, uint8_t vector, uint32_t bitmap);
 
-s_time_t get_apictime_scheduled(struct vcpu *v);
-
 int vlapic_match_logical_addr(struct vlapic *vlapic, uint8_t mda);
 
 #endif /* __ASM_X86_HVM_VLAPIC_H__ */
diff -r b17d1bc1febf -r 2a1edeedf28d xen/include/asm-x86/hvm/vpt.h
--- a/xen/include/asm-x86/hvm/vpt.h     Wed Dec 20 10:14:50 2006 +0000
+++ b/xen/include/asm-x86/hvm/vpt.h     Wed Dec 20 10:37:23 2006 +0000
@@ -27,10 +27,32 @@
 #include <xen/errno.h>
 #include <xen/time.h>
 #include <xen/timer.h>
+#include <xen/list.h>
 #include <asm/hvm/vpic.h>
 
 #define PIT_FREQ 1193181
 #define PIT_BASE 0x40
+
+/*
+ * Abstract layer of periodic time, one short time.
+ */
+typedef void time_cb(struct vcpu *v, void *opaque);
+
+struct periodic_time {
+    struct list_head list;
+    char enabled;
+    char one_shot;              /* one shot time */
+    int irq;
+    struct vcpu *vcpu;          /* vcpu timer interrupt delivers to */
+    u32 pending_intr_nr;        /* the couner for pending timer interrupts */
+    u32 period;                 /* frequency in ns */
+    u64 period_cycles;          /* frequency in cpu cycles */
+    s_time_t scheduled;         /* scheduled timer interrupt */
+    u64 last_plt_gtime;         /* platform time when last IRQ is injected */
+    struct timer timer;         /* ac_timer */
+    time_cb *cb;
+    void *priv;                 /* ponit back to platform time source */
+};
 
 typedef struct PITChannelState {
     int count; /* can be 65536 */
@@ -47,8 +69,7 @@ typedef struct PITChannelState {
     u8 gate; /* timer start */
     s64 count_load_time;
     /* irq handling */
-    struct vcpu      *vcpu;
-    struct periodic_time *pt;
+    struct periodic_time pt;
 } PITChannelState;
 
 typedef struct PITState {
@@ -66,10 +87,7 @@ 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
@@ -82,58 +100,35 @@ typedef struct PMTState {
     struct vcpu *vcpu;
 } PMTState;
 
-/*
- * Abstract layer of periodic time, one short time.
- */
-typedef void time_cb(struct vcpu *v, void *opaque);
-
-struct periodic_time {
-    char enabled;               /* enabled */
-    char one_shot;              /* one shot time */
-    char irq;
-    char first_injected;        /* flag to prevent shadow window */
-    u32 bind_vcpu;              /* vcpu timer interrupt delivers to */
-    u32 pending_intr_nr;        /* the couner for pending timer interrupts */
-    u32 period;                 /* frequency in ns */
-    u64 period_cycles;          /* frequency in cpu cycles */
-    s_time_t scheduled;         /* scheduled timer interrupt */
-    u64 last_plt_gtime;         /* platform time when last IRQ is injected */
-    struct timer timer;         /* ac_timer */
-    time_cb *cb;
-    void *priv;                 /* ponit back to platform time source */
+struct pl_time {    /* platform time */
+    struct PITState  vpit;
+    struct RTCState  vrtc;
+    struct PMTState  vpmt;
 };
-
-struct pl_time {    /* platform time */
-    struct periodic_time periodic_tm;
-    struct PITState      vpit;
-    struct RTCState      vrtc;
-    struct PMTState      vpmt;
-};
-
-extern u64 hvm_get_guest_time(struct vcpu *v);
-static inline int64_t hvm_get_clock(struct vcpu *v)
-{
-    return hvm_get_guest_time(v);
-}
 
 #define ticks_per_sec(v) (v->domain->arch.hvm_domain.tsc_frequency)
 
-/* to hook the ioreq packet to get the PIT initialization info */
-extern void hvm_hooks_assist(struct vcpu *v);
-extern void pickup_deactive_ticks(struct periodic_time *vpit);
-extern struct periodic_time *create_periodic_time(
-    u32 period, char irq, char one_shot, time_cb *cb, void *data);
-extern void destroy_periodic_time(struct periodic_time *pt);
+void pt_freeze_time(struct vcpu *v);
+void pt_thaw_time(struct vcpu *v);
+void pt_timer_fn(void *data);
+void pt_update_irq(struct vcpu *v);
+struct periodic_time *is_pt_irq(struct vcpu *v, int vector, int type);
+void pt_intr_post(struct vcpu *v, int vector, int type);
+void pt_reset(struct vcpu *v);
+void create_periodic_time(struct periodic_time *pt, u32 period, char irq, 
+                          char one_shot, time_cb *cb, void *data);
+void destroy_periodic_time(struct periodic_time *pt);
+
 int pv_pit_handler(int port, int data, int write);
 void pit_init(struct vcpu *v, unsigned long cpu_khz);
+void pit_migrate_timers(struct vcpu *v);
+void pit_deinit(struct domain *d);
 void rtc_init(struct vcpu *v, int base, int irq);
+void rtc_migrate_timers(struct vcpu *v);
 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);
+int is_rtc_periodic_irq(void *opaque);
 void pmtimer_init(struct vcpu *v, int base);
+void pmtimer_migrate_timers(struct vcpu *v);
 void pmtimer_deinit(struct domain *d);
-void pt_timer_fn(void *data);
-void pit_time_fired(struct vcpu *v, void *priv);
 
 #endif /* __ASM_X86_HVM_VPT_H__ */

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.