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
|