[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCHv1 1/2] passthrough: use per-interrupt lock when injecting an interrupt
The use of the per-domain event_lock in hvm_dirq_assist() does not scale with many VCPUs or interrupts. Add a per-interrupt lock to reduce contention. When a interrupt for a passthrough device is being setup or teared down, we must take both the event_lock and this new lock. Signed-off-by: David Vrabel <david.vrabel@xxxxxxxxxx> --- xen/drivers/passthrough/io.c | 34 +++++++++++++++++++++++----------- xen/include/xen/hvm/irq.h | 1 + 2 files changed, 24 insertions(+), 11 deletions(-) diff --git a/xen/drivers/passthrough/io.c b/xen/drivers/passthrough/io.c index bda9374..7c86c20 100644 --- a/xen/drivers/passthrough/io.c +++ b/xen/drivers/passthrough/io.c @@ -106,7 +106,7 @@ static void pt_pirq_softirq_reset(struct hvm_pirq_dpci *pirq_dpci) { struct domain *d = pirq_dpci->dom; - ASSERT(spin_is_locked(&d->event_lock)); + ASSERT(spin_is_locked(&pirq_dpci->lock)); switch ( cmpxchg(&pirq_dpci->state, 1 << STATE_SCHED, 0) ) { @@ -209,7 +209,6 @@ int pt_irq_create_bind( if ( pirq < 0 || pirq >= d->nr_pirqs ) return -EINVAL; - restart: spin_lock(&d->event_lock); hvm_irq_dpci = domain_get_irq_dpci(d); @@ -237,6 +236,8 @@ int pt_irq_create_bind( } pirq_dpci = pirq_dpci(info); + spin_lock(&pirq_dpci->lock); + /* * A crude 'while' loop with us dropping the spinlock and giving * the softirq_dpci a chance to run. @@ -245,11 +246,11 @@ int pt_irq_create_bind( * would have spun forever and would do the same thing (wait to flush out * outstanding hvm_dirq_assist calls. */ - if ( pt_pirq_softirq_active(pirq_dpci) ) + while ( pt_pirq_softirq_active(pirq_dpci) ) { - spin_unlock(&d->event_lock); + spin_unlock(&pirq_dpci->lock); cpu_relax(); - goto restart; + spin_lock(&pirq_dpci->lock); } switch ( pt_irq_bind->irq_type ) @@ -301,6 +302,7 @@ int pt_irq_create_bind( pirq_dpci->dom = NULL; pirq_dpci->flags = 0; pirq_cleanup_check(info, d); + spin_unlock(&pirq_dpci->lock); spin_unlock(&d->event_lock); return rc; } @@ -311,6 +313,7 @@ int pt_irq_create_bind( if ( (pirq_dpci->flags & mask) != mask ) { + spin_unlock(&pirq_dpci->lock); spin_unlock(&d->event_lock); return -EBUSY; } @@ -331,6 +334,7 @@ int pt_irq_create_bind( dest_mode = !!(pirq_dpci->gmsi.gflags & VMSI_DM_MASK); dest_vcpu_id = hvm_girq_dest_2_vcpu_id(d, dest, dest_mode); pirq_dpci->gmsi.dest_vcpu_id = dest_vcpu_id; + spin_unlock(&pirq_dpci->lock); spin_unlock(&d->event_lock); if ( dest_vcpu_id >= 0 ) hvm_migrate_pirqs(d->vcpu[dest_vcpu_id]); @@ -351,6 +355,7 @@ int pt_irq_create_bind( if ( !digl || !girq ) { + spin_unlock(&pirq_dpci->lock); spin_unlock(&d->event_lock); xfree(girq); xfree(digl); @@ -412,6 +417,7 @@ int pt_irq_create_bind( hvm_irq_dpci->link_cnt[link]--; pirq_dpci->flags = 0; pirq_cleanup_check(info, d); + spin_unlock(&pirq_dpci->lock); spin_unlock(&d->event_lock); xfree(girq); xfree(digl); @@ -419,6 +425,7 @@ int pt_irq_create_bind( } } + spin_unlock(&pirq_dpci->lock); spin_unlock(&d->event_lock); if ( iommu_verbose ) @@ -430,6 +437,7 @@ int pt_irq_create_bind( } default: + spin_unlock(&pirq_dpci->lock); spin_unlock(&d->event_lock); return -EOPNOTSUPP; } @@ -481,6 +489,8 @@ int pt_irq_destroy_bind( pirq = pirq_info(d, machine_gsi); pirq_dpci = pirq_dpci(pirq); + spin_lock(&pirq_dpci->lock); + if ( pt_irq_bind->irq_type != PT_IRQ_TYPE_MSI ) { unsigned int bus = pt_irq_bind->u.pci.bus; @@ -549,6 +559,7 @@ int pt_irq_destroy_bind( pirq_cleanup_check(pirq, d); } + spin_unlock(&pirq_dpci->lock); spin_unlock(&d->event_lock); if ( what && iommu_verbose ) @@ -566,6 +577,7 @@ int pt_irq_destroy_bind( void pt_pirq_init(struct domain *d, struct hvm_pirq_dpci *dpci) { + spin_lock_init(&dpci->lock); INIT_LIST_HEAD(&dpci->digl_list); dpci->gmsi.dest_vcpu_id = -1; } @@ -621,7 +633,7 @@ int hvm_do_IRQ_dpci(struct domain *d, struct pirq *pirq) return 1; } -/* called with d->event_lock held */ +/* called with pirq_dhci->lock held */ static void __msi_pirq_eoi(struct hvm_pirq_dpci *pirq_dpci) { irq_desc_t *desc; @@ -675,7 +687,7 @@ static void hvm_dirq_assist(struct domain *d, struct hvm_pirq_dpci *pirq_dpci) { ASSERT(d->arch.hvm_domain.irq.dpci); - spin_lock(&d->event_lock); + spin_lock(&pirq_dpci->lock); if ( test_and_clear_bool(pirq_dpci->masked) ) { struct pirq *pirq = dpci_pirq(pirq_dpci); @@ -687,7 +699,7 @@ static void hvm_dirq_assist(struct domain *d, struct hvm_pirq_dpci *pirq_dpci) if ( pirq_dpci->flags & HVM_IRQ_DPCI_GUEST_MSI ) { - spin_unlock(&d->event_lock); + spin_unlock(&pirq_dpci->lock); return; } } @@ -695,7 +707,7 @@ static void hvm_dirq_assist(struct domain *d, struct hvm_pirq_dpci *pirq_dpci) if ( pirq_dpci->flags & HVM_IRQ_DPCI_GUEST_MSI ) { vmsi_deliver_pirq(d, pirq_dpci); - spin_unlock(&d->event_lock); + spin_unlock(&pirq_dpci->lock); return; } @@ -709,7 +721,7 @@ static void hvm_dirq_assist(struct domain *d, struct hvm_pirq_dpci *pirq_dpci) { /* for translated MSI to INTx interrupt, eoi as early as possible */ __msi_pirq_eoi(pirq_dpci); - spin_unlock(&d->event_lock); + spin_unlock(&pirq_dpci->lock); return; } @@ -723,7 +735,7 @@ static void hvm_dirq_assist(struct domain *d, struct hvm_pirq_dpci *pirq_dpci) ASSERT(pt_irq_need_timer(pirq_dpci->flags)); set_timer(&pirq_dpci->timer, NOW() + PT_IRQ_TIME_OUT); } - spin_unlock(&d->event_lock); + spin_unlock(&pirq_dpci->lock); } static void __hvm_dpci_eoi(struct domain *d, diff --git a/xen/include/xen/hvm/irq.h b/xen/include/xen/hvm/irq.h index 4c9cb20..8b8e461 100644 --- a/xen/include/xen/hvm/irq.h +++ b/xen/include/xen/hvm/irq.h @@ -91,6 +91,7 @@ struct hvm_irq_dpci { /* Machine IRQ to guest device/intx mapping. */ struct hvm_pirq_dpci { + spinlock_t lock; uint32_t flags; unsigned int state; bool_t masked; -- 2.1.4 _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx http://lists.xen.org/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |