[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [RFC PATCH 1/5] ioreq-server: centralize access to ioreq structures
On 30/01/14 14:19, Paul Durrant wrote: > To simplify creation of the ioreq server abstraction in a > subsequent patch, this patch centralizes all use of the shared > ioreq structure and the buffered ioreq ring to the source module > xen/arch/x86/hvm/hvm.c. > Also, re-work hvm_send_assist_req() slightly to complete IO > immediately in the case where there is no emulator (i.e. the shared > IOREQ ring has not been set). This should handle the case currently > covered by has_dm in hvmemul_do_io(). > > Signed-off-by: Paul Durrant <paul.durrant@xxxxxxxxxx> > --- > xen/arch/x86/hvm/emulate.c | 40 +++------------ > xen/arch/x86/hvm/hvm.c | 98 > ++++++++++++++++++++++++++++++++++++- > xen/arch/x86/hvm/io.c | 94 +---------------------------------- > xen/include/asm-x86/hvm/hvm.h | 3 +- > xen/include/asm-x86/hvm/support.h | 9 ---- > 5 files changed, 108 insertions(+), 136 deletions(-) > > diff --git a/xen/arch/x86/hvm/emulate.c b/xen/arch/x86/hvm/emulate.c > index 868aa1d..d1d3a6f 100644 > --- a/xen/arch/x86/hvm/emulate.c > +++ b/xen/arch/x86/hvm/emulate.c > @@ -57,24 +57,11 @@ static int hvmemul_do_io( > int value_is_ptr = (p_data == NULL); > struct vcpu *curr = current; > struct hvm_vcpu_io *vio; > - ioreq_t *p = get_ioreq(curr); > - ioreq_t _ioreq; > + ioreq_t p[1]; I know it will make the patch sightly larger by modifying the indirection of p, but having an array of 1 item on the stack is seems silly. > unsigned long ram_gfn = paddr_to_pfn(ram_gpa); > p2m_type_t p2mt; > struct page_info *ram_page; > int rc; > - bool_t has_dm = 1; > - > - /* > - * Domains without a backing DM, don't have an ioreq page. Just > - * point to a struct on the stack, initialising the state as needed. > - */ > - if ( !p ) > - { > - has_dm = 0; > - p = &_ioreq; > - p->state = STATE_IOREQ_NONE; > - } > > /* Check for paged out page */ > ram_page = get_page_from_gfn(curr->domain, ram_gfn, &p2mt, P2M_UNSHARE); > @@ -173,15 +160,6 @@ static int hvmemul_do_io( > return X86EMUL_UNHANDLEABLE; > } > > - if ( p->state != STATE_IOREQ_NONE ) > - { > - gdprintk(XENLOG_WARNING, "WARNING: io already pending (%d)?\n", > - p->state); > - if ( ram_page ) > - put_page(ram_page); > - return X86EMUL_UNHANDLEABLE; > - } > - > vio->io_state = > (p_data == NULL) ? HVMIO_dispatched : HVMIO_awaiting_completion; > vio->io_size = size; > @@ -193,6 +171,7 @@ static int hvmemul_do_io( > if ( vio->mmio_retrying ) > *reps = 1; > > + p->state = STATE_IOREQ_NONE; > p->dir = dir; > p->data_is_ptr = value_is_ptr; > p->type = is_mmio ? IOREQ_TYPE_COPY : IOREQ_TYPE_PIO; > @@ -232,20 +211,15 @@ static int hvmemul_do_io( > vio->io_state = HVMIO_handle_mmio_awaiting_completion; > break; > case X86EMUL_UNHANDLEABLE: > - /* If there is no backing DM, just ignore accesses */ > - if ( !has_dm ) > + rc = X86EMUL_RETRY; > + if ( !hvm_send_assist_req(curr, p) ) > { > rc = X86EMUL_OKAY; > vio->io_state = HVMIO_none; > } > - else > - { > - rc = X86EMUL_RETRY; > - if ( !hvm_send_assist_req(curr) ) > - vio->io_state = HVMIO_none; > - else if ( p_data == NULL ) > - rc = X86EMUL_OKAY; > - } > + else if ( p_data == NULL ) > + rc = X86EMUL_OKAY; > + > break; > default: > BUG(); > diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c > index 69f7e74..71a44db 100644 > --- a/xen/arch/x86/hvm/hvm.c > +++ b/xen/arch/x86/hvm/hvm.c > @@ -345,6 +345,14 @@ void hvm_migrate_pirqs(struct vcpu *v) > spin_unlock(&d->event_lock); > } > > +static ioreq_t *get_ioreq(struct vcpu *v) > +{ > + struct domain *d = v->domain; > + shared_iopage_t *p = d->arch.hvm_domain.ioreq.va; newline here... > + ASSERT((v == current) || spin_is_locked(&d->arch.hvm_domain.ioreq.lock)); .. and here. (I realise that this is just code motion, but might as well take the opportunity to fix the style.) > + return p ? &p->vcpu_ioreq[v->vcpu_id] : NULL; > +} > + > void hvm_do_resume(struct vcpu *v) > { > ioreq_t *p; > @@ -1287,7 +1295,86 @@ void hvm_vcpu_down(struct vcpu *v) > } > } > > -bool_t hvm_send_assist_req(struct vcpu *v) > +int hvm_buffered_io_send(ioreq_t *p) > +{ > + struct vcpu *v = current; > + struct hvm_ioreq_page *iorp = &v->domain->arch.hvm_domain.buf_ioreq; > + buffered_iopage_t *pg = iorp->va; > + buf_ioreq_t bp; > + /* Timeoffset sends 64b data, but no address. Use two consecutive slots. > */ > + int qw = 0; > + > + /* Ensure buffered_iopage fits in a page */ > + BUILD_BUG_ON(sizeof(buffered_iopage_t) > PAGE_SIZE); > + > + /* > + * Return 0 for the cases we can't deal with: > + * - 'addr' is only a 20-bit field, so we cannot address beyond 1MB > + * - we cannot buffer accesses to guest memory buffers, as the guest > + * may expect the memory buffer to be synchronously accessed > + * - the count field is usually used with data_is_ptr and since we don't > + * support data_is_ptr we do not waste space for the count field > either > + */ > + if ( (p->addr > 0xffffful) || p->data_is_ptr || (p->count != 1) ) > + return 0; > + > + bp.type = p->type; > + bp.dir = p->dir; > + switch ( p->size ) > + { > + case 1: > + bp.size = 0; > + break; > + case 2: > + bp.size = 1; > + break; > + case 4: > + bp.size = 2; > + break; > + case 8: > + bp.size = 3; > + qw = 1; > + break; > + default: > + gdprintk(XENLOG_WARNING, "unexpected ioreq size: %u\n", p->size); > + return 0; > + } > + > + bp.data = p->data; > + bp.addr = p->addr; > + > + spin_lock(&iorp->lock); > + > + if ( (pg->write_pointer - pg->read_pointer) >= > + (IOREQ_BUFFER_SLOT_NUM - qw) ) > + { > + /* The queue is full: send the iopacket through the normal path. */ > + spin_unlock(&iorp->lock); > + return 0; > + } > + > + memcpy(&pg->buf_ioreq[pg->write_pointer % IOREQ_BUFFER_SLOT_NUM], > + &bp, sizeof(bp)); > + > + if ( qw ) > + { > + bp.data = p->data >> 32; > + memcpy(&pg->buf_ioreq[(pg->write_pointer+1) % IOREQ_BUFFER_SLOT_NUM], > + &bp, sizeof(bp)); > + } > + > + /* Make the ioreq_t visible /before/ write_pointer. */ > + wmb(); > + pg->write_pointer += qw ? 2 : 1; > + > + notify_via_xen_event_channel(v->domain, > + v->domain->arch.hvm_domain.params[HVM_PARAM_BUFIOREQ_EVTCHN]); > + spin_unlock(&iorp->lock); > + > + return 1; > +} > + > +bool_t hvm_send_assist_req(struct vcpu *v, ioreq_t *proto_p) > { > ioreq_t *p; > > @@ -1305,6 +1392,15 @@ bool_t hvm_send_assist_req(struct vcpu *v) > return 0; > } > > + p->dir = proto_p->dir; > + p->data_is_ptr = proto_p->data_is_ptr; > + p->type = proto_p->type; > + p->size = proto_p->size; > + p->addr = proto_p->addr; > + p->count = proto_p->count; > + p->df = proto_p->df; > + p->data = proto_p->data; > + > prepare_wait_on_xen_event_channel(v->arch.hvm_vcpu.xen_port); > > /* > diff --git a/xen/arch/x86/hvm/io.c b/xen/arch/x86/hvm/io.c > index bf6309d..576641c 100644 > --- a/xen/arch/x86/hvm/io.c > +++ b/xen/arch/x86/hvm/io.c > @@ -46,85 +46,6 @@ > #include <xen/iocap.h> > #include <public/hvm/ioreq.h> > > -int hvm_buffered_io_send(ioreq_t *p) > -{ > - struct vcpu *v = current; > - struct hvm_ioreq_page *iorp = &v->domain->arch.hvm_domain.buf_ioreq; > - buffered_iopage_t *pg = iorp->va; > - buf_ioreq_t bp; > - /* Timeoffset sends 64b data, but no address. Use two consecutive slots. > */ > - int qw = 0; > - > - /* Ensure buffered_iopage fits in a page */ > - BUILD_BUG_ON(sizeof(buffered_iopage_t) > PAGE_SIZE); > - > - /* > - * Return 0 for the cases we can't deal with: > - * - 'addr' is only a 20-bit field, so we cannot address beyond 1MB > - * - we cannot buffer accesses to guest memory buffers, as the guest > - * may expect the memory buffer to be synchronously accessed > - * - the count field is usually used with data_is_ptr and since we don't > - * support data_is_ptr we do not waste space for the count field > either > - */ > - if ( (p->addr > 0xffffful) || p->data_is_ptr || (p->count != 1) ) > - return 0; > - > - bp.type = p->type; > - bp.dir = p->dir; > - switch ( p->size ) > - { > - case 1: > - bp.size = 0; > - break; > - case 2: > - bp.size = 1; > - break; > - case 4: > - bp.size = 2; > - break; > - case 8: > - bp.size = 3; > - qw = 1; > - break; > - default: > - gdprintk(XENLOG_WARNING, "unexpected ioreq size: %u\n", p->size); > - return 0; > - } > - > - bp.data = p->data; > - bp.addr = p->addr; > - > - spin_lock(&iorp->lock); > - > - if ( (pg->write_pointer - pg->read_pointer) >= > - (IOREQ_BUFFER_SLOT_NUM - qw) ) > - { > - /* The queue is full: send the iopacket through the normal path. */ > - spin_unlock(&iorp->lock); > - return 0; > - } > - > - memcpy(&pg->buf_ioreq[pg->write_pointer % IOREQ_BUFFER_SLOT_NUM], > - &bp, sizeof(bp)); > - > - if ( qw ) > - { > - bp.data = p->data >> 32; > - memcpy(&pg->buf_ioreq[(pg->write_pointer+1) % IOREQ_BUFFER_SLOT_NUM], > - &bp, sizeof(bp)); > - } > - > - /* Make the ioreq_t visible /before/ write_pointer. */ > - wmb(); > - pg->write_pointer += qw ? 2 : 1; > - > - notify_via_xen_event_channel(v->domain, > - v->domain->arch.hvm_domain.params[HVM_PARAM_BUFIOREQ_EVTCHN]); > - spin_unlock(&iorp->lock); > - > - return 1; > -} > - > void send_timeoffset_req(unsigned long timeoff) > { > ioreq_t p[1]; > @@ -150,25 +71,14 @@ void send_timeoffset_req(unsigned long timeoff) > void send_invalidate_req(void) > { > struct vcpu *v = current; > - ioreq_t *p = get_ioreq(v); > - > - if ( !p ) > - return; > - > - if ( p->state != STATE_IOREQ_NONE ) > - { > - gdprintk(XENLOG_ERR, "WARNING: send invalidate req with something " > - "already pending (%d)?\n", p->state); > - domain_crash(v->domain); > - return; > - } > + ioreq_t p[1]; This can all be reduced to a single item, and even using C structure initialisation rather than 4 explicit assignments. ~Andrew > > p->type = IOREQ_TYPE_INVALIDATE; > p->size = 4; > p->dir = IOREQ_WRITE; > p->data = ~0UL; /* flush all */ > > - (void)hvm_send_assist_req(v); > + (void)hvm_send_assist_req(v, p); > } > > int handle_mmio(void) > diff --git a/xen/include/asm-x86/hvm/hvm.h b/xen/include/asm-x86/hvm/hvm.h > index ccca5df..4e8fee8 100644 > --- a/xen/include/asm-x86/hvm/hvm.h > +++ b/xen/include/asm-x86/hvm/hvm.h > @@ -26,6 +26,7 @@ > #include <asm/hvm/asid.h> > #include <public/domctl.h> > #include <public/hvm/save.h> > +#include <public/hvm/ioreq.h> > #include <asm/mm.h> > > /* Interrupt acknowledgement sources. */ > @@ -223,7 +224,7 @@ int prepare_ring_for_helper(struct domain *d, unsigned > long gmfn, > struct page_info **_page, void **_va); > void destroy_ring_for_helper(void **_va, struct page_info *page); > > -bool_t hvm_send_assist_req(struct vcpu *v); > +bool_t hvm_send_assist_req(struct vcpu *v, ioreq_t *p); > > void hvm_get_guest_pat(struct vcpu *v, u64 *guest_pat); > int hvm_set_guest_pat(struct vcpu *v, u64 guest_pat); > diff --git a/xen/include/asm-x86/hvm/support.h > b/xen/include/asm-x86/hvm/support.h > index 3529499..b6af3c5 100644 > --- a/xen/include/asm-x86/hvm/support.h > +++ b/xen/include/asm-x86/hvm/support.h > @@ -22,19 +22,10 @@ > #define __ASM_X86_HVM_SUPPORT_H__ > > #include <xen/types.h> > -#include <public/hvm/ioreq.h> > #include <xen/sched.h> > #include <xen/hvm/save.h> > #include <asm/processor.h> > > -static inline ioreq_t *get_ioreq(struct vcpu *v) > -{ > - struct domain *d = v->domain; > - shared_iopage_t *p = d->arch.hvm_domain.ioreq.va; > - ASSERT((v == current) || spin_is_locked(&d->arch.hvm_domain.ioreq.lock)); > - return p ? &p->vcpu_ioreq[v->vcpu_id] : NULL; > -} > - > #define HVM_DELIVER_NO_ERROR_CODE -1 > > #ifndef NDEBUG _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx http://lists.xen.org/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |