[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-ia64-devel] [PATCH] implement PHYSDEVOP_pirq_eoi_gmfn and related stuff.
IA64: implement PHYSDEVOP_pirq_eoi_gmfn and related stuff. This patch is ia64 counter part of 18844:c820bf73a914. Signed-off-by: Isaku Yamahata <yamahata@xxxxxxxxxxxxx> diff --git a/xen/arch/ia64/xen/domain.c b/xen/arch/ia64/xen/domain.c --- a/xen/arch/ia64/xen/domain.c +++ b/xen/arch/ia64/xen/domain.c @@ -1653,6 +1653,11 @@ int domain_relinquish_resources(struct d /*fallthrough*/ case RELRES_mm_teardown: + if (d->arch.pirq_eoi_map != NULL) { + put_page(virt_to_page(d->arch.pirq_eoi_map)); + d->arch.pirq_eoi_map = NULL; + } + /* Tear down shadow mode stuff. */ ret = mm_teardown(d); if (ret != 0) diff --git a/xen/arch/ia64/xen/hypercall.c b/xen/arch/ia64/xen/hypercall.c --- a/xen/arch/ia64/xen/hypercall.c +++ b/xen/arch/ia64/xen/hypercall.c @@ -341,7 +341,39 @@ long do_physdev_op(int cmd, XEN_GUEST_HA ret = -EFAULT; if ( copy_from_guest(&eoi, arg, 1) != 0 ) break; + ret = -EINVAL; + if ( eoi.irq < 0 || eoi.irq >= NR_IRQS ) + break; + if ( current->domain->arch.pirq_eoi_map ) + evtchn_unmask(current->domain->pirq_to_evtchn[eoi.irq]); ret = pirq_guest_eoi(current->domain, eoi.irq); + break; + } + + case PHYSDEVOP_pirq_eoi_gmfn: { + struct physdev_pirq_eoi_gmfn info; + unsigned long mfn; + + BUILD_BUG_ON(NR_IRQS > (PAGE_SIZE * 8)); + + ret = -EFAULT; + if ( copy_from_guest(&info, arg, 1) != 0 ) + break; + + ret = -EINVAL; + mfn = gmfn_to_mfn(current->domain, info.gmfn); + if ( !mfn_valid(mfn) || !get_page(mfn_to_page(mfn), current->domain) ) + break; + + if ( cmpxchg(¤t->domain->arch.pirq_eoi_map_mfn, 0, mfn) != 0 ) + { + put_page(mfn_to_page(mfn)); + ret = -EBUSY; + break; + } + + current->domain->arch.pirq_eoi_map = mfn_to_virt(mfn); + ret = 0; break; } diff --git a/xen/arch/ia64/xen/irq.c b/xen/arch/ia64/xen/irq.c --- a/xen/arch/ia64/xen/irq.c +++ b/xen/arch/ia64/xen/irq.c @@ -312,16 +312,41 @@ typedef struct { struct domain *guest[IRQ_MAX_GUESTS]; } irq_guest_action_t; +static inline void set_pirq_eoi(struct domain *d, unsigned int irq) +{ + if ( d->arch.pirq_eoi_map ) + set_bit(irq, d->arch.pirq_eoi_map); +} + +static inline void clear_pirq_eoi(struct domain *d, unsigned int irq) +{ + if ( d->arch.pirq_eoi_map ) + clear_bit(irq, d->arch.pirq_eoi_map); +} + +static void _irq_guest_eoi(irq_desc_t *desc) +{ + irq_guest_action_t *action = (irq_guest_action_t *)desc->action; + unsigned int i, vector = desc - irq_desc; + + if ( !(desc->status & IRQ_GUEST_EOI_PENDING) ) + return; + + for ( i = 0; i < action->nr_guests; ++i ) + clear_pirq_eoi(action->guest[i], vector); + + desc->status &= ~(IRQ_INPROGRESS|IRQ_GUEST_EOI_PENDING); + desc->handler->enable(vector); +} + static struct timer irq_guest_eoi_timer[NR_IRQS]; static void irq_guest_eoi_timer_fn(void *data) { irq_desc_t *desc = data; - unsigned vector = desc - irq_desc; unsigned long flags; spin_lock_irqsave(&desc->lock, flags); - desc->status &= ~IRQ_INPROGRESS; - desc->handler->enable(vector); + _irq_guest_eoi(desc); spin_unlock_irqrestore(&desc->lock, flags); } @@ -355,8 +380,22 @@ void __do_IRQ_guest(int irq) if ( already_pending == action->nr_guests ) { + stop_timer(&irq_guest_eoi_timer[irq]); desc->handler->disable(irq); - stop_timer(&irq_guest_eoi_timer[irq]); + desc->status |= IRQ_GUEST_EOI_PENDING; + for ( i = 0; i < already_pending; ++i ) + { + d = action->guest[i]; + set_pirq_eoi(d, irq); + /* + * Could check here whether the guest unmasked the event by now + * (or perhaps just re-issue the send_guest_pirq()), and if it + * can now accept the event, + * - clear all the pirq_eoi bits we already set, + * - re-enable the vector, and + * - skip the timer setup below. + */ + } init_timer(&irq_guest_eoi_timer[irq], irq_guest_eoi_timer_fn, desc, smp_processor_id()); set_timer(&irq_guest_eoi_timer[irq], NOW() + MILLISECS(1)); @@ -379,16 +418,25 @@ int pirq_guest_eoi(struct domain *d, int int pirq_guest_eoi(struct domain *d, int irq) { irq_desc_t *desc; + irq_guest_action_t *action; if ( (irq < 0) || (irq >= NR_IRQS) ) return -EINVAL; desc = &irq_desc[irq]; spin_lock_irq(&desc->lock); - if ( test_and_clear_bit(irq, &d->pirq_mask) && - (--((irq_guest_action_t *)desc->action)->in_flight == 0) ) + action = (irq_guest_action_t *)desc->action; + + if ( action->ack_type == ACKTYPE_NONE ) { - ASSERT(((irq_guest_action_t*)desc->action)->ack_type == ACKTYPE_UNMASK); + ASSERT(!test_bit(irq, d->pirq_mask)); + stop_timer(&irq_guest_eoi_timer[irq]); + _irq_guest_eoi(desc); + } + + if ( test_and_clear_bit(irq, &d->pirq_mask) && (--action->in_flight == 0) ) + { + ASSERT(action->ack_type == ACKTYPE_UNMASK); desc->handler->end(irq); } spin_unlock_irq(&desc->lock); @@ -488,6 +536,11 @@ int pirq_guest_bind(struct vcpu *v, int action->guest[action->nr_guests++] = v->domain; + if ( action->ack_type != ACKTYPE_NONE ) + set_pirq_eoi(v->domain, irq); + else + clear_pirq_eoi(v->domain, irq); + out: spin_unlock_irqrestore(&desc->lock, flags); return rc; diff --git a/xen/include/asm-ia64/domain.h b/xen/include/asm-ia64/domain.h --- a/xen/include/asm-ia64/domain.h +++ b/xen/include/asm-ia64/domain.h @@ -177,6 +177,10 @@ struct arch_domain { /* Address of SAL emulator data */ struct xen_sal_data *sal_data; + /* Shared page for notifying that explicit PIRQ EOI is required. */ + unsigned long *pirq_eoi_map; + unsigned long pirq_eoi_map_mfn; + /* Address of efi_runtime_services_t (placed in domain memory) */ void *efi_runtime; /* Address of fpswa_interface_t (placed in domain memory) */ -- yamahata _______________________________________________ Xen-ia64-devel mailing list Xen-ia64-devel@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-ia64-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |