[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
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |