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

[Xen-devel] [PATCH] PIT acceleration enhancement



PIT acceleration enhancement
add a new flag in HV to control whether re-arm the actimer and handle guest PIT 
io, by this we can
* stop the actimer and io interception if guest change previous periodic mode 
to other mode.
* safely handle reinitialization of periodic mode from guest

Signed-off-by: Edwin Zhai <edwin.zhai@xxxxxxxxx>
Signed-off-by: Yunhong Jiang <yunhong.jiang@xxxxxxxxx>
Signed-off-by: Eddie Dong <eddie.dong@xxxxxxxxx>

diff -r 13e9fdaeed27 tools/ioemu/hw/i8254.c
--- a/tools/ioemu/hw/i8254.c    Wed Feb 22 09:54:20 2006 +0100
+++ b/tools/ioemu/hw/i8254.c    Wed Feb 22 22:22:51 2006 +0800
@@ -50,19 +50,18 @@ typedef struct PITChannelState {
     int64_t next_transition_time;
     QEMUTimer *irq_timer;
     int irq;
-    int hvm_channel; /* Is this accelerated by HVM ? */
 } PITChannelState;
 
 struct PITState {
     PITChannelState channels[3];
+    /* currently operate which channel for hvm use */
+    int hvm_channel;
 };
 
 static PITState pit_state;
 
 static void pit_irq_timer_update(PITChannelState *s, int64_t current_time);
 
-/* currently operate which channel for hvm use */
-int hvm_channel = -1;
 extern FILE *logfile;
 static int pit_get_count(PITChannelState *s)
 {
@@ -215,56 +214,62 @@ int pit_get_gate(PITState *pit, int chan
     return s->gate;
 }
 
+/* change config for HVM accelerated pit channel */
 void pit_reset_hvm_vectors()
 {
     extern shared_iopage_t *shared_page;
     ioreq_t *req; 
-    int irq, i;
+    int irq;
     PITChannelState *s;
 
     irq = 0;
 
-    for(i = 0; i < 3; i++) {
-        if (pit_state.channels[i].hvm_channel)
-             break;
-    }
-    
-    if (i == 3)
-        return;
-
     /* Assumes just one HVM accelerated channel */
-    hvm_channel = i;
-    s = &pit_state.channels[hvm_channel];
+    s = &pit_state.channels[pit_state.hvm_channel];
     fprintf(logfile,
-       "HVM_PIT:guest init pit channel %d!\n", hvm_channel);
+       "HVM_PIT:guest init pit channel %d!\n", pit_state.hvm_channel);
     req = &shared_page->vcpu_iodata[0].vp_ioreq;
 
     req->state = STATE_IORESP_HOOK;
     /*
      * info passed to HV as following
      * -- init count:16 bit, timer vec:8 bit,
-     * PIT channel(0~2):2 bit, rw mode:2 bit
+     * PIT channel(0~2):2 bit, rw mode:2 bit,
+     * PIT mode(0~5):3 bit
      */
     req->u.data = s->count;
     req->u.data |= (irq << 16);
-    req->u.data |= (hvm_channel << 24);
+    req->u.data |= (pit_state.hvm_channel << 24);
     req->u.data |= ((s->rw_mode) << 26);
+    req->u.data |= ((s->mode) << 28);
+
+    /* HVM acceleration only for mode 2 */
+    if (s->mode != 2)
+        pit_state.hvm_channel = -1;
+
     fprintf(logfile, "HVM_PIT:pass info 0x%llx to HV!\n", req->u.data);
 }
 
-static inline void pit_load_count(PITChannelState *s, int val)
+static inline void pit_load_count(PITChannelState *s, int val, int chn)
 {
     if (val == 0)
         val = 0x10000;
     s->count_load_time = qemu_get_clock(vm_clock);
     s->count = val;
 
-    /* guest init this pit channel for periodic mode. we do not update related
-     * timer so the channel never send intr from device model*/
-    if (hvm_channel != -1 && s->mode == 2) {
+    /* first time for periodic mode, mark this channel as HVM accelerated */
+    if (s->mode == 2) {
+        if (pit_state.hvm_channel == -1)
+            pit_state.hvm_channel = chn;
+        else if (pit_state.hvm_channel != chn){
+            fprintf(logfile, "HVM_PIT:should not set another pit channel as 
mode 2!\n");
+            return;
+        }
+    }
+
+    /* change something for hvm channel, e.g the mode,freq or vec */
+    if (pit_state.hvm_channel == chn)
         pit_reset_hvm_vectors();
-        hvm_channel = -1;
-    }
 
 /*    pit_irq_timer_update(s, s->count_load_time);*/
 }
@@ -323,22 +328,20 @@ static void pit_ioport_write(void *opaqu
         }
     } else {
         s = &pit->channels[addr];
-        s->hvm_channel = 1;
-        hvm_channel = addr;
         switch(s->write_state) {
         default:
         case RW_STATE_LSB:
-            pit_load_count(s, val);
+            pit_load_count(s, val, addr);
             break;
         case RW_STATE_MSB:
-            pit_load_count(s, val << 8);
+            pit_load_count(s, val << 8, addr);
             break;
         case RW_STATE_WORD0:
             s->write_latch = val;
             s->write_state = RW_STATE_WORD1;
             break;
         case RW_STATE_WORD1:
-            pit_load_count(s, s->write_latch | (val << 8));
+            pit_load_count(s, s->write_latch | (val << 8), addr);
             s->write_state = RW_STATE_WORD0;
             break;
         }
@@ -493,11 +496,12 @@ static void pit_reset(void *opaque)
     PITChannelState *s;
     int i;
 
+    pit->hvm_channel = -1;
     for(i = 0;i < 3; i++) {
         s = &pit->channels[i];
         s->mode = 3;
         s->gate = (i != 2);
-        pit_load_count(s, 0);
+        pit_load_count(s, 0, i);
     }
 }
 
@@ -506,6 +510,7 @@ PITState *pit_init(int base, int irq)
     PITState *pit = &pit_state;
     PITChannelState *s;
 
+    pit->hvm_channel = -1;
     s = &pit->channels[0];
     /* the timer 0 is connected to an IRQ */
     s->irq_timer = qemu_new_timer(vm_clock, pit_irq_timer, s);
diff -r 13e9fdaeed27 xen/arch/x86/hvm/hvm.c
--- a/xen/arch/x86/hvm/hvm.c    Wed Feb 22 09:54:20 2006 +0100
+++ b/xen/arch/x86/hvm/hvm.c    Wed Feb 22 22:22:51 2006 +0800
@@ -186,6 +186,7 @@ static void hvm_get_info(struct domain *
     unmap_domain_page(p);
 }
 
+extern void pit_init(struct hvm_virpit *vpit, struct vcpu *v);
 void hvm_setup_platform(struct domain* d)
 {
     struct hvm_domain *platform;
@@ -204,6 +205,8 @@ void hvm_setup_platform(struct domain* d
         spin_lock_init(&d->arch.hvm_domain.round_robin_lock);
         hvm_vioapic_init(d);
     }
+
+    pit_init(&platform->vpit, current);
 }
 
 void pic_irq_request(int *interrupt_request, int level)
diff -r 13e9fdaeed27 xen/arch/x86/hvm/intercept.c
--- a/xen/arch/x86/hvm/intercept.c      Wed Feb 22 09:54:20 2006 +0100
+++ b/xen/arch/x86/hvm/intercept.c      Wed Feb 22 22:22:51 2006 +0800
@@ -35,6 +35,8 @@ extern struct hvm_mmio_handler vioapic_m
 extern struct hvm_mmio_handler vioapic_mmio_handler;
 
 #define HVM_MMIO_HANDLER_NR 2
+/* only accelerate for pit mode 2 */
+#define HVM_PIT_ACCEL_MODE 2
 
 struct hvm_mmio_handler *hvm_mmio_handlers[HVM_MMIO_HANDLER_NR] =
 {
@@ -305,6 +307,10 @@ int intercept_pit_io(ioreq_t *p)
     struct vcpu *v = current;
     struct hvm_virpit *vpit = &(v->domain->arch.hvm_domain.vpit);
 
+    /* handle io only if accelerated pit mode */
+    if (vpit->mode != HVM_PIT_ACCEL_MODE)
+        return 0;
+
     if (p->size != 1 ||
         p->pdata_valid ||
         p->type != IOREQ_TYPE_PIO)
@@ -353,6 +359,10 @@ static void pit_timer_fn(void *data)
     struct vcpu *v = data;
     struct hvm_virpit *vpit = &(v->domain->arch.hvm_domain.vpit);
 
+    /* re-arm actimer only if accelerated pit mode */
+    if (vpit->mode != HVM_PIT_ACCEL_MODE)
+        return;
+
     /* pick up missed timer tick */
     missed_ticks(vpit);
 
@@ -375,6 +385,13 @@ void pickup_deactive_ticks(struct hvm_vi
     }
 }
 
+void pit_init(struct hvm_virpit *vpit, struct vcpu *v)
+{
+    vpit->mode = -1;
+    init_timer(&vpit->pit_timer, pit_timer_fn, v, v->processor);
+    register_portio_handler(0x40, 4, intercept_pit_io); 
+}
+
 /* Only some PIT operations such as load init counter need a hypervisor hook.
  * leave all other operations in user space DM
  */
@@ -383,19 +400,18 @@ void hvm_hooks_assist(struct vcpu *v)
     vcpu_iodata_t *vio = get_vio(v->domain, v->vcpu_id);
     ioreq_t *p = &vio->vp_ioreq;
     struct hvm_virpit *vpit = &(v->domain->arch.hvm_domain.vpit);
-    int rw_mode, reinit = 0;
+    int rw_mode, mode;
 
     /* load init count*/
     if (p->state == STATE_IORESP_HOOK) {
-        /* set up actimer, handle re-init */
-        if ( active_timer(&(vpit->pit_timer)) ) {
-            HVM_DBG_LOG(DBG_LEVEL_1, "HVM_PIT: guest reset PIT with channel 
%lx!\n", (unsigned long) ((p->u.data >> 24) & 0x3) );
-            stop_timer(&(vpit->pit_timer));
-            reinit = 1;
- 
-        }
-        else {
-            init_timer(&vpit->pit_timer, pit_timer_fn, v, v->processor);
+
+        mode = ((p->u.data >> 28) & 0x7);
+
+        /* new mode is not accelerated mode */
+        if (mode != HVM_PIT_ACCEL_MODE) {
+            vpit->mode = mode;
+            p->state = STATE_IORESP_READY;
+            return;
         }
 
         /* init count for this channel */
@@ -433,16 +449,18 @@ void hvm_hooks_assist(struct vcpu *v)
             break;
         }
 
+        /* XXX: any race condition with pit_timer_fn?? */
         vpit->scheduled = NOW() + vpit->period;
-        set_timer(&vpit->pit_timer, vpit->scheduled);
+
+        /* orignal mode is not accelerated mode */
+        if (vpit->mode != HVM_PIT_ACCEL_MODE) {
+            vpit->mode = mode;
+            set_timer(&vpit->pit_timer, vpit->scheduled);
+        }
 
         /*restore the state*/
         p->state = STATE_IORESP_READY;
 
-        /* register handler to intercept the PIT io when vm_exit */
-        if (!reinit) {
-            register_portio_handler(0x40, 4, intercept_pit_io); 
-        }
     }
 }
 
diff -r 13e9fdaeed27 xen/include/asm-x86/hvm/vpit.h
--- a/xen/include/asm-x86/hvm/vpit.h    Wed Feb 22 09:54:20 2006 +0100
+++ b/xen/include/asm-x86/hvm/vpit.h    Wed Feb 22 22:22:51 2006 +0800
@@ -43,6 +43,7 @@ struct hvm_virpit {
     s_time_t scheduled;         /* scheduled timer interrupt */
     struct timer pit_timer;     /* periodic timer for mode 2*/
     unsigned int channel;       /* the pit channel, counter 0~2 */
+    unsigned int mode;          /* the pit mode, only acceleration for mode 2 
*/
     unsigned int pending_intr_nr; /* the couner for pending timer interrupts */
     u32 period;                 /* pit frequency in ns */
     int first_injected;         /* flag to prevent shadow window */


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


 


Rackspace

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