WARNING - OLD ARCHIVES

This is an archived copy of the Xen.org mailing list, which we have preserved to ensure that existing links to archives are not broken. The live archive, which contains the latest emails, can be found at http://lists.xen.org/
   
 
 
Xen 
 
Home Products Support Community News
 
   
 

xen-devel

[Xen-devel] [PATCH] PIT acceleration enhancement

To: Ian Pratt <Ian.Pratt@xxxxxxxxxxxx>, Keir Fraser <Keir.Fraser@xxxxxxxxxxxx>
Subject: [Xen-devel] [PATCH] PIT acceleration enhancement
From: Edwin Zhai <edwin.zhai@xxxxxxxxx>
Date: Wed, 22 Feb 2006 23:07:58 +0800
Cc: xen-devel@xxxxxxxxxxxxxxxxxxx
Delivery-date: Wed, 22 Feb 2006 15:21:50 +0000
Envelope-to: www-data@xxxxxxxxxxxxxxxxxxx
List-help: <mailto:xen-devel-request@lists.xensource.com?subject=help>
List-id: Xen developer discussion <xen-devel.lists.xensource.com>
List-post: <mailto:xen-devel@lists.xensource.com>
List-subscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-devel>, <mailto:xen-devel-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-devel>, <mailto:xen-devel-request@lists.xensource.com?subject=unsubscribe>
Sender: xen-devel-bounces@xxxxxxxxxxxxxxxxxxx
User-agent: Mutt/1.5.8i
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

<Prev in Thread] Current Thread [Next in Thread>