From mboxrd@z Thu Jan 1 00:00:00 1970 From: "Jan Beulich" Subject: [PATCH 2/2, v2] replace d->nr_pirqs sized arrays with radix tree Date: Tue, 03 May 2011 15:09:09 +0100 Message-ID: <4DC028A5020000780003F694@vpn.id2.novell.com> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="=__Part7C50FC95.1__=" Return-path: List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Sender: xen-devel-bounces@lists.xensource.com Errors-To: xen-devel-bounces@lists.xensource.com To: "xen-devel@lists.xensource.com" Cc: Allen M Kay List-Id: xen-devel@lists.xenproject.org This is a MIME message. If you are reading this text, you may want to consider changing to a mail reader or gateway that understands how to properly handle MIME multipart messages. --=__Part7C50FC95.1__= Content-Type: text/plain; charset=US-ASCII Content-Transfer-Encoding: quoted-printable Content-Disposition: inline With this it is questionable whether retaining struct domain's nr_pirqs is actually necessary - the value now only serves for bounds checking, and this boundary could easily be nr_irqs. Another thing to consider is whether it's worth storing the pirq number in struct pirq, to avoid passing the number and a pointer to quite a number of functions. Note that ia64, the build of which is broken currently anyway, is only partially fixed up. v2: adjustments for split setup/teardown of translation data Signed-off-by: Jan Beulich --- 2011-04-29.orig/xen/arch/ia64/vmx/vmx_interrupt.c +++ 2011-04-29/xen/arch/ia64/vmx/vmx_interrupt.c @@ -155,13 +155,13 @@ void hvm_isa_irq_deassert(struct domain=20 /* dummy */ } =20 -int msixtbl_pt_register(struct domain *d, int pirq, uint64_t gtable) +int msixtbl_pt_register(struct domain *d, struct pirq *pirq, uint64_t = gtable) { /* dummy */ return -ENOSYS; } =20 -void msixtbl_pt_unregister(struct domain *d, int pirq) +void msixtbl_pt_unregister(struct domain *d, struct pirq *pirq) { /* dummy */ } --- 2011-04-29.orig/xen/arch/ia64/xen/hypercall.c +++ 2011-04-29/xen/arch/ia64/xen/hypercall.c @@ -65,8 +65,11 @@ static long __do_pirq_guest_eoi(struct d { if ( pirq < 0 || pirq >=3D NR_IRQS ) return -EINVAL; - if ( d->arch.pirq_eoi_map ) - evtchn_unmask(d->pirq_to_evtchn[pirq]); + if ( d->arch.pirq_eoi_map ) { + spin_lock(&d->event_lock); + evtchn_unmask(pirq_to_evtchn(d, pirq)); + spin_unlock(&d->event_lock); + } return pirq_guest_eoi(d, pirq); } =20 --- 2011-04-29.orig/xen/arch/ia64/xen/irq.c +++ 2011-04-29/xen/arch/ia64/xen/irq.c @@ -363,15 +363,17 @@ void __do_IRQ_guest(int irq) irq_desc_t *desc =3D &irq_desc[irq]; irq_guest_action_t *action =3D (irq_guest_action_t *)desc->action; struct domain *d; + struct pirq *pirq; int i, already_pending =3D 0; =20 for ( i =3D 0; i < action->nr_guests; i++ ) { d =3D action->guest[i]; + pirq =3D pirq_info(d, irq); if ( (action->ack_type !=3D ACKTYPE_NONE) && - !test_and_set_bit(irq, &d->pirq_mask) ) + !test_and_set_bool(pirq->masked) ) action->in_flight++; - if ( hvm_do_IRQ_dpci(d, irq) ) + if ( hvm_do_IRQ_dpci(d, pirq) ) { if ( action->ack_type =3D=3D ACKTYPE_NONE ) { @@ -379,7 +381,7 @@ void __do_IRQ_guest(int irq) desc->status |=3D IRQ_INPROGRESS; /* = cleared during hvm eoi */ } } - else if ( send_guest_pirq(d, irq) && + else if ( send_guest_pirq(d, pirq) && (action->ack_type =3D=3D ACKTYPE_NONE) ) { already_pending++; @@ -423,26 +425,23 @@ static int pirq_acktype(int irq) return ACKTYPE_NONE; } =20 -int pirq_guest_eoi(struct domain *d, int irq) +int pirq_guest_eoi(struct domain *d, struct pirq *pirq) { irq_desc_t *desc; irq_guest_action_t *action; =20 - if ( (irq < 0) || (irq >=3D NR_IRQS) ) - return -EINVAL; - desc =3D &irq_desc[irq]; spin_lock_irq(&desc->lock); action =3D (irq_guest_action_t *)desc->action; =20 if ( action->ack_type =3D=3D ACKTYPE_NONE ) { - ASSERT(!test_bit(irq, d->pirq_mask)); + ASSERT(!pirq->masked); stop_timer(&irq_guest_eoi_timer[irq]); _irq_guest_eoi(desc); } =20 - if ( test_and_clear_bit(irq, &d->pirq_mask) && (--action->in_flight = =3D=3D 0) ) + if ( test_and_clear_bool(pirq->masked) && (--action->in_flight =3D=3D = 0) ) { ASSERT(action->ack_type =3D=3D ACKTYPE_UNMASK); desc->handler->end(irq); @@ -455,22 +454,27 @@ int pirq_guest_eoi(struct domain *d, int =20 int pirq_guest_unmask(struct domain *d) { - int irq; + unsigned int pirq =3D 0, n, i; + unsigned long indexes[16]; + struct pirq *pirqs[ARRAY_SIZE(indexes)]; shared_info_t *s =3D d->shared_info; =20 - for ( irq =3D find_first_bit(d->pirq_mask, NR_IRQS); - irq < NR_IRQS; - irq =3D find_next_bit(d->pirq_mask, NR_IRQS, irq+1) ) - { - if ( !test_bit(d->pirq_to_evtchn[irq], &s->evtchn_mask[0]) ) - pirq_guest_eoi(d, irq); - - } + do { + n =3D radix_tree_gang_lookup(&d->pirq_tree, (void **)pirqs, pirq, + ARRAY_SIZE(pirqs), indexes); + for ( i =3D 0; i < n; ++i ) + { + pirq =3D indexes[i]; + if ( pirqs[i]->masked && + !test_bit(pirqs[i]->evtchn, &s->evtchn_mask[0]) ) + pirq_guest_eoi(d, pirqs[i]); + } + } while ( ++pirq < d->nr_pirqs && n =3D=3D ARRAY_SIZE(pirqs) ); =20 return 0; } =20 -int pirq_guest_bind(struct vcpu *v, int irq, int will_share) +int pirq_guest_bind(struct vcpu *v, int irq, struct pirq *pirq, int = will_share) { irq_desc_t *desc =3D &irq_desc[irq]; irq_guest_action_t *action; @@ -554,7 +558,7 @@ int pirq_guest_bind(struct vcpu *v, int=20 return rc; } =20 -void pirq_guest_unbind(struct domain *d, int irq) +void pirq_guest_unbind(struct domain *d, int irq, struct pirq *pirq) { irq_desc_t *desc =3D &irq_desc[irq]; irq_guest_action_t *action; @@ -572,7 +576,7 @@ void pirq_guest_unbind(struct domain *d, action->nr_guests--; =20 if ( action->ack_type =3D=3D ACKTYPE_UNMASK ) - if ( test_and_clear_bit(irq, &d->pirq_mask) && + if ( test_and_clear_bool(pirq->masked) && (--action->in_flight =3D=3D 0) ) desc->handler->end(irq); =20 --- 2011-04-29.orig/xen/arch/x86/domain.c +++ 2011-04-29/xen/arch/x86/domain.c @@ -608,25 +608,9 @@ int arch_domain_create(struct domain *d, share_xen_page_with_guest( virt_to_page(d->shared_info), d, XENSHARE_writable); =20 - d->arch.pirq_irq =3D xmalloc_array(int, d->nr_pirqs); - if ( !d->arch.pirq_irq ) - goto fail; - memset(d->arch.pirq_irq, 0, - d->nr_pirqs * sizeof(*d->arch.pirq_irq)); - if ( (rc =3D init_domain_irq_mapping(d)) !=3D 0 ) goto fail; =20 - if ( is_hvm_domain(d) ) - { - d->arch.pirq_emuirq =3D xmalloc_array(int, d->nr_pirqs); - if ( !d->arch.pirq_emuirq ) - goto fail; - for (i =3D 0; i < d->nr_pirqs; i++) - d->arch.pirq_emuirq[i] =3D IRQ_UNBOUND; - } - - if ( (rc =3D iommu_domain_init(d)) !=3D 0 ) goto fail; =20 @@ -660,8 +644,6 @@ int arch_domain_create(struct domain *d, fail: d->is_dying =3D DOMDYING_dead; vmce_destroy_msr(d); - xfree(d->arch.pirq_irq); - xfree(d->arch.pirq_emuirq); cleanup_domain_irq_mapping(d); free_xenheap_page(d->shared_info); if ( paging_initialised ) @@ -714,8 +696,6 @@ void arch_domain_destroy(struct domain * #endif =20 free_xenheap_page(d->shared_info); - xfree(d->arch.pirq_irq); - xfree(d->arch.pirq_emuirq); cleanup_domain_irq_mapping(d); } =20 --- 2011-04-29.orig/xen/arch/x86/hvm/hvm.c +++ 2011-04-29/xen/arch/x86/hvm/hvm.c @@ -252,32 +252,36 @@ void hvm_migrate_timers(struct vcpu *v) pt_migrate(v); } =20 -void hvm_migrate_pirqs(struct vcpu *v) +static int hvm_migrate_pirq(struct domain *d, unsigned int pirq, + struct hvm_pirq_dpci *pirq_dpci, void *arg) { - int pirq, irq; - struct irq_desc *desc; - struct domain *d =3D v->domain; - struct hvm_irq_dpci *hvm_irq_dpci =3D d->arch.hvm_domain.irq.dpci; - =20 - if ( !iommu_enabled || (hvm_irq_dpci =3D=3D NULL) ) - return; + struct vcpu *v =3D arg; =20 - spin_lock(&d->event_lock); - for ( pirq =3D find_first_bit(hvm_irq_dpci->mapping, d->nr_pirqs); - pirq < d->nr_pirqs; - pirq =3D find_next_bit(hvm_irq_dpci->mapping, d->nr_pirqs, pirq = + 1) ) + if ( (pirq_dpci->flags & HVM_IRQ_DPCI_MACH_MSI) && + (pirq_dpci->gmsi.dest_vcpu_id =3D=3D v->vcpu_id) ) { - if ( !(hvm_irq_dpci->mirq[pirq].flags & HVM_IRQ_DPCI_MACH_MSI) || - (hvm_irq_dpci->mirq[pirq].gmsi.dest_vcpu_id !=3D v->vcpu_id= ) ) - continue; - desc =3D domain_spin_lock_irq_desc(v->domain, pirq, NULL); - if (!desc) - continue; - irq =3D desc - irq_desc; - ASSERT(MSI_IRQ(irq)); + struct irq_desc *desc =3D + pirq_spin_lock_irq_desc(d, dpci_pirq(pirq_dpci), NULL); + + if ( !desc ) + return 0; + ASSERT(MSI_IRQ(desc - irq_desc)); irq_set_affinity(desc, cpumask_of(v->processor)); spin_unlock_irq(&desc->lock); } + + return 0; +} + +void hvm_migrate_pirqs(struct vcpu *v) +{ + struct domain *d =3D v->domain; + + if ( !iommu_enabled || !d->arch.hvm_domain.irq.dpci ) + return; + + spin_lock(&d->event_lock); + pt_pirq_iterate(d, hvm_migrate_pirq, v); spin_unlock(&d->event_lock); } =20 @@ -501,8 +505,6 @@ int hvm_domain_initialise(struct domain=20 return rc; } =20 -extern void msixtbl_pt_cleanup(struct domain *d); - void hvm_domain_relinquish_resources(struct domain *d) { hvm_destroy_ioreq_page(d, &d->arch.hvm_domain.ioreq); --- 2011-04-29.orig/xen/arch/x86/hvm/irq.c +++ 2011-04-29/xen/arch/x86/hvm/irq.c @@ -33,7 +33,7 @@ static void assert_irq(struct domain *d, int pirq =3D domain_emuirq_to_pirq(d, ioapic_gsi); if ( pirq !=3D IRQ_UNBOUND ) { - send_guest_pirq(d, pirq); + send_guest_pirq(d, pirq_info(d, pirq)); return; } vioapic_irq_positive_edge(d, ioapic_gsi); --- 2011-04-29.orig/xen/arch/x86/hvm/vmsi.c +++ 2011-04-29/xen/arch/x86/hvm/vmsi.c @@ -65,11 +65,10 @@ static void vmsi_inj_irq( } } =20 -int vmsi_deliver(struct domain *d, int pirq) +int vmsi_deliver(struct domain *d, const struct hvm_pirq_dpci *pirq_dpci) { - struct hvm_irq_dpci *hvm_irq_dpci =3D d->arch.hvm_domain.irq.dpci; - uint32_t flags =3D hvm_irq_dpci->mirq[pirq].gmsi.gflags; - int vector =3D hvm_irq_dpci->mirq[pirq].gmsi.gvec; + uint32_t flags =3D pirq_dpci->gmsi.gflags; + int vector =3D pirq_dpci->gmsi.gvec; uint8_t dest =3D (uint8_t)flags; uint8_t dest_mode =3D !!(flags & VMSI_DM_MASK); uint8_t delivery_mode =3D (flags & VMSI_DELIV_MASK) >> GLFAGS_SHIFT_DE= LIV_MODE; @@ -82,11 +81,7 @@ int vmsi_deliver(struct domain *d, int p "vector=3D%x trig_mode=3D%x\n", dest, dest_mode, delivery_mode, vector, trig_mode); =20 - if ( !( hvm_irq_dpci->mirq[pirq].flags & HVM_IRQ_DPCI_GUEST_MSI ) ) - { - gdprintk(XENLOG_WARNING, "pirq %x not msi \n", pirq); - return 0; - } + ASSERT(pirq_dpci->flags & HVM_IRQ_DPCI_GUEST_MSI); =20 switch ( delivery_mode ) { @@ -349,7 +344,7 @@ static void del_msixtbl_entry(struct msi call_rcu(&entry->rcu, free_msixtbl_entry); } =20 -int msixtbl_pt_register(struct domain *d, int pirq, uint64_t gtable) +int msixtbl_pt_register(struct domain *d, struct pirq *pirq, uint64_t = gtable) { struct irq_desc *irq_desc; struct msi_desc *msi_desc; @@ -358,6 +353,7 @@ int msixtbl_pt_register(struct domain *d int r =3D -EINVAL; =20 ASSERT(spin_is_locked(&pcidevs_lock)); + ASSERT(spin_is_locked(&d->event_lock)); =20 /* * xmalloc() with irq_disabled causes the failure of check_lock()=20 @@ -367,7 +363,7 @@ int msixtbl_pt_register(struct domain *d if ( !new_entry ) return -ENOMEM; =20 - irq_desc =3D domain_spin_lock_irq_desc(d, pirq, NULL); + irq_desc =3D pirq_spin_lock_irq_desc(d, pirq, NULL); if ( !irq_desc ) { xfree(new_entry); @@ -404,7 +400,7 @@ out: return r; } =20 -void msixtbl_pt_unregister(struct domain *d, int pirq) +void msixtbl_pt_unregister(struct domain *d, struct pirq *pirq) { struct irq_desc *irq_desc; struct msi_desc *msi_desc; @@ -412,8 +408,9 @@ void msixtbl_pt_unregister(struct domain struct msixtbl_entry *entry; =20 ASSERT(spin_is_locked(&pcidevs_lock)); + ASSERT(spin_is_locked(&d->event_lock)); =20 - irq_desc =3D domain_spin_lock_irq_desc(d, pirq, NULL); + irq_desc =3D pirq_spin_lock_irq_desc(d, pirq, NULL); if ( !irq_desc ) return; =20 @@ -447,7 +444,7 @@ found: spin_unlock_irq(&irq_desc->lock); } =20 -void msixtbl_pt_cleanup(struct domain *d, int pirq) +void msixtbl_pt_cleanup(struct domain *d) { struct msixtbl_entry *entry, *temp; unsigned long flags; --- 2011-04-29.orig/xen/arch/x86/irq.c +++ 2011-04-29/xen/arch/x86/irq.c @@ -814,7 +814,7 @@ static void irq_guest_eoi_timer_fn(void=20 { struct domain *d =3D action->guest[i]; unsigned int pirq =3D domain_irq_to_pirq(d, irq); - if ( test_and_clear_bit(pirq, d->pirq_mask) ) + if ( test_and_clear_bool(pirq_info(d, pirq)->masked) ) action->in_flight--; } } @@ -874,11 +874,12 @@ static void __do_IRQ_guest(int irq) =20 for ( i =3D 0; i < action->nr_guests; i++ ) { - unsigned int pirq; + struct pirq *pirq; + d =3D action->guest[i]; - pirq =3D domain_irq_to_pirq(d, irq); + pirq =3D pirq_info(d, domain_irq_to_pirq(d, irq)); if ( (action->ack_type !=3D ACKTYPE_NONE) && - !test_and_set_bit(pirq, d->pirq_mask) ) + !test_and_set_bool(pirq->masked) ) action->in_flight++; if ( hvm_do_IRQ_dpci(d, pirq) ) { @@ -950,28 +951,71 @@ struct irq_desc *domain_spin_lock_irq_de return desc; } =20 -static int prepare_domain_irq_pirq(struct domain *d, int irq, int pirq) +/* + * Same with struct pirq already looked up, and d->event_lock already + * held (thus the PIRQ <-> IRQ mapping can't change under our feet). + */ +struct irq_desc *pirq_spin_lock_irq_desc( + struct domain *d, const struct pirq *pirq, unsigned long *pflags) +{ + int irq =3D pirq->arch.irq; + struct irq_desc *desc; + unsigned long flags; + + ASSERT(spin_is_locked(&d->event_lock)); + + if ( irq <=3D 0 ) + return NULL; + + desc =3D irq_to_desc(irq); + spin_lock_irqsave(&desc->lock, flags); + + if ( pflags ) + *pflags =3D flags; + + ASSERT(pirq =3D=3D pirq_info(d, domain_irq_to_pirq(d, irq))); + ASSERT(irq =3D=3D pirq->arch.irq); + + return desc; +} + +static int prepare_domain_irq_pirq(struct domain *d, int irq, int pirq, + struct pirq **pinfo) { int err =3D radix_tree_insert(&d->arch.irq_pirq, irq, NULL, NULL, NULL); + struct pirq *info; =20 - return err !=3D -EEXIST ? err : 0; + if ( err && err !=3D -EEXIST ) + return err; + info =3D pirq_get_info(d, pirq); + if ( !info ) + { + if ( !err ) + radix_tree_delete(&d->arch.irq_pirq, irq, NULL); + return -ENOMEM; + } + *pinfo =3D info; + return 0; } =20 -static void set_domain_irq_pirq(struct domain *d, int irq, int pirq) +static void set_domain_irq_pirq(struct domain *d, int irq, int pirq, + struct pirq *info) { *radix_tree_lookup_slot(&d->arch.irq_pirq, irq) =3D (void *)(long)pirq= ; - d->arch.pirq_irq[pirq] =3D irq; + info->arch.irq =3D irq; } =20 -static void clear_domain_irq_pirq(struct domain *d, int irq, int pirq) +static void clear_domain_irq_pirq(struct domain *d, int irq, struct pirq = *pirq) { - d->arch.pirq_irq[pirq] =3D 0; + pirq->arch.irq =3D 0; *radix_tree_lookup_slot(&d->arch.irq_pirq, irq) =3D NULL; } =20 -static void cleanup_domain_irq_pirq(struct domain *d, int irq, int pirq) +static void cleanup_domain_irq_pirq(struct domain *d, int irq, int pirq, + struct pirq *info) { + pirq_cleanup_check(info, d, pirq); radix_tree_delete(&d->arch.irq_pirq, irq, NULL); } =20 @@ -987,10 +1031,12 @@ int init_domain_irq_mapping(struct domai for ( i =3D 1; platform_legacy_irq(i); ++i ) if ( !IO_APIC_IRQ(i) ) { - err =3D prepare_domain_irq_pirq(d, i, i); + struct pirq *info; + + err =3D prepare_domain_irq_pirq(d, i, i, &info); if ( err ) break; - set_domain_irq_pirq(d, i, i); + set_domain_irq_pirq(d, i, i, info); } =20 return err; @@ -1008,6 +1054,48 @@ void cleanup_domain_irq_mapping(struct d irq_slot_free, NULL); } =20 +struct pirq *alloc_pirq_struct(struct domain *d) +{ + size_t sz =3D is_hvm_domain(d) ? sizeof(struct pirq) : + offsetof(struct pirq, arch.hvm); + struct pirq *pirq =3D xmalloc_bytes(sz); + + if ( pirq ) + { + memset(pirq, 0, sz); + if ( is_hvm_domain(d) ) + { + pirq->arch.hvm.emuirq =3D IRQ_UNBOUND; + pt_pirq_init(d, &pirq->arch.hvm.dpci); + } + } + + return pirq; +} + +void (pirq_cleanup_check)(struct pirq *info, struct domain *d, int pirq) +{ + /* + * Check whether all fields have their default values, and delete + * the entry from the tree if so. + * + * NB: Common parts were already checked. + */ + if ( info->arch.irq ) + return; + + if ( is_hvm_domain(d) ) + { + if ( info->arch.hvm.emuirq !=3D IRQ_UNBOUND ) + return; + if ( !pt_pirq_cleanup_check(&info->arch.hvm.dpci) ) + return; + } + + if ( radix_tree_delete(&d->pirq_tree, pirq, NULL) !=3D info ) + BUG(); +} + /* Flush all ready EOIs from the top of this CPU's pending-EOI stack. */ static void flush_ready_eoi(void) { @@ -1068,18 +1156,22 @@ static void set_eoi_ready(void *data) flush_ready_eoi(); } =20 -static void __pirq_guest_eoi(struct domain *d, int pirq) +void pirq_guest_eoi(struct domain *d, struct pirq *pirq) +{ + struct irq_desc *desc; + + ASSERT(local_irq_is_enabled()); + desc =3D pirq_spin_lock_irq_desc(d, pirq, NULL); + if ( desc ) + desc_guest_eoi(d, desc, pirq); +} + +void desc_guest_eoi(struct domain *d, struct irq_desc *desc, struct pirq = *pirq) { - struct irq_desc *desc; irq_guest_action_t *action; cpumask_t cpu_eoi_map; int irq; =20 - ASSERT(local_irq_is_enabled()); - desc =3D domain_spin_lock_irq_desc(d, pirq, NULL); - if ( desc =3D=3D NULL ) - return; - if ( !(desc->status & IRQ_GUEST) ) { spin_unlock_irq(&desc->lock); @@ -1091,12 +1183,12 @@ static void __pirq_guest_eoi(struct doma =20 if ( action->ack_type =3D=3D ACKTYPE_NONE ) { - ASSERT(!test_bit(pirq, d->pirq_mask)); + ASSERT(!pirq->masked); stop_timer(&action->eoi_timer); _irq_guest_eoi(desc); } =20 - if ( unlikely(!test_and_clear_bit(pirq, d->pirq_mask)) || + if ( unlikely(!test_and_clear_bool(pirq->masked)) || unlikely(--action->in_flight !=3D 0) ) { spin_unlock_irq(&desc->lock); @@ -1131,27 +1223,23 @@ static void __pirq_guest_eoi(struct doma on_selected_cpus(&cpu_eoi_map, set_eoi_ready, desc, 0); } =20 -int pirq_guest_eoi(struct domain *d, int irq) -{ - if ( (irq < 0) || (irq >=3D d->nr_pirqs) ) - return -EINVAL; - - __pirq_guest_eoi(d, irq); - - return 0; -} - int pirq_guest_unmask(struct domain *d) { - unsigned int irq, nr =3D d->nr_pirqs; + unsigned int pirq =3D 0, n, i; + unsigned long indexes[16]; + struct pirq *pirqs[ARRAY_SIZE(indexes)]; =20 - for ( irq =3D find_first_bit(d->pirq_mask, nr); - irq < nr; - irq =3D find_next_bit(d->pirq_mask, nr, irq+1) ) - { - if ( !test_bit(d->pirq_to_evtchn[irq], &shared_info(d, evtchn_mask= )) ) - __pirq_guest_eoi(d, irq); - } + do { + n =3D radix_tree_gang_lookup(&d->pirq_tree, (void **)pirqs, pirq, + ARRAY_SIZE(pirqs), indexes); + for ( i =3D 0; i < n; ++i ) + { + pirq =3D indexes[i]; + if ( pirqs[i]->masked && + !test_bit(pirqs[i]->evtchn, &shared_info(d, evtchn_mask))= ) + pirq_guest_eoi(d, pirqs[i]); + } + } while ( ++pirq < d->nr_pirqs && n =3D=3D ARRAY_SIZE(pirqs) ); =20 return 0; } @@ -1221,7 +1309,7 @@ int pirq_shared(struct domain *d, int pi return shared; } =20 -int pirq_guest_bind(struct vcpu *v, int pirq, int will_share) +int pirq_guest_bind(struct vcpu *v, int pirq, struct pirq *info, int = will_share) { unsigned int irq; struct irq_desc *desc; @@ -1233,7 +1321,7 @@ int pirq_guest_bind(struct vcpu *v, int=20 BUG_ON(!local_irq_is_enabled()); =20 retry: - desc =3D domain_spin_lock_irq_desc(v->domain, pirq, NULL); + desc =3D pirq_spin_lock_irq_desc(v->domain, info, NULL); if ( desc =3D=3D NULL ) { rc =3D -EINVAL; @@ -1334,7 +1422,7 @@ int pirq_guest_bind(struct vcpu *v, int=20 } =20 static irq_guest_action_t *__pirq_guest_unbind( - struct domain *d, int pirq, struct irq_desc *desc) + struct domain *d, int pirq, struct pirq *info, struct irq_desc *desc) { unsigned int irq; irq_guest_action_t *action; @@ -1363,13 +1451,13 @@ static irq_guest_action_t *__pirq_guest_ switch ( action->ack_type ) { case ACKTYPE_UNMASK: - if ( test_and_clear_bit(pirq, d->pirq_mask) && + if ( test_and_clear_bool(info->masked) && (--action->in_flight =3D=3D 0) ) desc->handler->end(irq); break; case ACKTYPE_EOI: /* NB. If #guests =3D=3D 0 then we clear the eoi_map later on. */ - if ( test_and_clear_bit(pirq, d->pirq_mask) && + if ( test_and_clear_bool(info->masked) && (--action->in_flight =3D=3D 0) && (action->nr_guests !=3D 0) ) { @@ -1387,9 +1475,9 @@ static irq_guest_action_t *__pirq_guest_ =20 /* * The guest cannot re-bind to this IRQ until this function returns. = So, - * when we have flushed this IRQ from pirq_mask, it should remain = flushed. + * when we have flushed this IRQ from ->masked, it should remain = flushed. */ - BUG_ON(test_bit(pirq, d->pirq_mask)); + BUG_ON(info->masked); =20 if ( action->nr_guests !=3D 0 ) return NULL; @@ -1427,7 +1515,7 @@ static irq_guest_action_t *__pirq_guest_ return action; } =20 -void pirq_guest_unbind(struct domain *d, int pirq) +void pirq_guest_unbind(struct domain *d, int pirq, struct pirq *info) { irq_guest_action_t *oldaction =3D NULL; struct irq_desc *desc; @@ -1436,19 +1524,19 @@ void pirq_guest_unbind(struct domain *d, WARN_ON(!spin_is_locked(&d->event_lock)); =20 BUG_ON(!local_irq_is_enabled()); - desc =3D domain_spin_lock_irq_desc(d, pirq, NULL); + desc =3D pirq_spin_lock_irq_desc(d, info, NULL); =20 if ( desc =3D=3D NULL ) { - irq =3D -domain_pirq_to_irq(d, pirq); + irq =3D -info->arch.irq; BUG_ON(irq <=3D 0); desc =3D irq_to_desc(irq); spin_lock_irq(&desc->lock); - clear_domain_irq_pirq(d, irq, pirq); + clear_domain_irq_pirq(d, irq, info); } else { - oldaction =3D __pirq_guest_unbind(d, pirq, desc); + oldaction =3D __pirq_guest_unbind(d, pirq, info, desc); } =20 spin_unlock_irq(&desc->lock); @@ -1459,10 +1547,10 @@ void pirq_guest_unbind(struct domain *d, xfree(oldaction); } else if ( irq > 0 ) - cleanup_domain_irq_pirq(d, irq, pirq); + cleanup_domain_irq_pirq(d, irq, pirq, info); } =20 -static int pirq_guest_force_unbind(struct domain *d, int irq) +static int pirq_guest_force_unbind(struct domain *d, int irq, struct pirq = *info) { struct irq_desc *desc; irq_guest_action_t *action, *oldaction =3D NULL; @@ -1471,7 +1559,7 @@ static int pirq_guest_force_unbind(struc WARN_ON(!spin_is_locked(&d->event_lock)); =20 BUG_ON(!local_irq_is_enabled()); - desc =3D domain_spin_lock_irq_desc(d, irq, NULL); + desc =3D pirq_spin_lock_irq_desc(d, info, NULL); BUG_ON(desc =3D=3D NULL); =20 if ( !(desc->status & IRQ_GUEST) ) @@ -1491,7 +1579,7 @@ static int pirq_guest_force_unbind(struc goto out; =20 bound =3D 1; - oldaction =3D __pirq_guest_unbind(d, irq, desc); + oldaction =3D __pirq_guest_unbind(d, irq, info, desc); =20 out: spin_unlock_irq(&desc->lock); @@ -1505,6 +1593,13 @@ static int pirq_guest_force_unbind(struc return bound; } =20 +static inline bool_t is_free_pirq(const struct domain *d, + const struct pirq *pirq) +{ + return !pirq || (!pirq->arch.irq && (!is_hvm_domain(d) || + pirq->arch.hvm.emuirq =3D=3D IRQ_UNBOUND)); +} + int get_free_pirq(struct domain *d, int type, int index) { int i; @@ -1514,29 +1609,17 @@ int get_free_pirq(struct domain *d, int=20 if ( type =3D=3D MAP_PIRQ_TYPE_GSI ) { for ( i =3D 16; i < nr_irqs_gsi; i++ ) - if ( !d->arch.pirq_irq[i] ) - { - if ( !is_hvm_domain(d) || - d->arch.pirq_emuirq[i] =3D=3D IRQ_UNBOUND ) - break; - } - if ( i =3D=3D nr_irqs_gsi ) - return -ENOSPC; + if ( is_free_pirq(d, pirq_info(d, i)) ) + return i; } else { for ( i =3D d->nr_pirqs - 1; i >=3D nr_irqs_gsi; i-- ) - if ( !d->arch.pirq_irq[i] ) - { - if ( !is_hvm_domain(d) || - d->arch.pirq_emuirq[i] =3D=3D IRQ_UNBOUND ) - break; - } - if ( i < nr_irqs_gsi ) - return -ENOSPC; + if ( is_free_pirq(d, pirq_info(d, i)) ) + return i; } =20 - return i; + return -ENOSPC; } =20 int map_domain_pirq( @@ -1544,6 +1627,7 @@ int map_domain_pirq( { int ret =3D 0; int old_irq, old_pirq; + struct pirq *info; struct irq_desc *desc; unsigned long flags; struct msi_desc *msi_desc; @@ -1583,7 +1667,7 @@ int map_domain_pirq( return ret; } =20 - ret =3D prepare_domain_irq_pirq(d, irq, pirq); + ret =3D prepare_domain_irq_pirq(d, irq, pirq, &info); if ( ret ) return ret; =20 @@ -1608,20 +1692,20 @@ int map_domain_pirq( dprintk(XENLOG_G_ERR, "dom%d: irq %d in use\n", d->domain_id, irq); desc->handler =3D &pci_msi_type; - set_domain_irq_pirq(d, irq, pirq); + set_domain_irq_pirq(d, irq, pirq, info); setup_msi_irq(pdev, msi_desc, irq); spin_unlock_irqrestore(&desc->lock, flags); } else { spin_lock_irqsave(&desc->lock, flags); - set_domain_irq_pirq(d, irq, pirq); + set_domain_irq_pirq(d, irq, pirq, info); spin_unlock_irqrestore(&desc->lock, flags); } =20 done: if ( ret ) - cleanup_domain_irq_pirq(d, irq, pirq); + cleanup_domain_irq_pirq(d, irq, pirq, info); return ret; } =20 @@ -1632,6 +1716,7 @@ int unmap_domain_pirq(struct domain *d,=20 struct irq_desc *desc; int irq, ret =3D 0; bool_t forced_unbind; + struct pirq *info; struct msi_desc *msi_desc =3D NULL; =20 if ( (pirq < 0) || (pirq >=3D d->nr_pirqs) ) @@ -1640,8 +1725,8 @@ int unmap_domain_pirq(struct domain *d,=20 ASSERT(spin_is_locked(&pcidevs_lock)); ASSERT(spin_is_locked(&d->event_lock)); =20 - irq =3D domain_pirq_to_irq(d, pirq); - if ( irq <=3D 0 ) + info =3D pirq_info(d, pirq); + if ( !info || (irq =3D info->arch.irq) <=3D 0 ) { dprintk(XENLOG_G_ERR, "dom%d: pirq %d not mapped\n", d->domain_id, pirq); @@ -1649,7 +1734,7 @@ int unmap_domain_pirq(struct domain *d,=20 goto done; } =20 - forced_unbind =3D pirq_guest_force_unbind(d, pirq); + forced_unbind =3D pirq_guest_force_unbind(d, pirq, info); if ( forced_unbind ) dprintk(XENLOG_G_WARNING, "dom%d: forcing unbind of pirq %d\n", d->domain_id, pirq); @@ -1664,10 +1749,10 @@ int unmap_domain_pirq(struct domain *d,=20 BUG_ON(irq !=3D domain_pirq_to_irq(d, pirq)); =20 if ( !forced_unbind ) - clear_domain_irq_pirq(d, irq, pirq); + clear_domain_irq_pirq(d, irq, info); else { - d->arch.pirq_irq[pirq] =3D -irq; + info->arch.irq =3D -irq; *radix_tree_lookup_slot(&d->arch.irq_pirq, irq) =3D (void = *)(long)-pirq; } =20 @@ -1676,7 +1761,7 @@ int unmap_domain_pirq(struct domain *d,=20 msi_free_irq(msi_desc); =20 if ( !forced_unbind ) - cleanup_domain_irq_pirq(d, irq, pirq); + cleanup_domain_irq_pirq(d, irq, pirq, info); =20 ret =3D irq_deny_access(d, pirq); if ( ret ) @@ -1698,7 +1783,7 @@ void free_domain_pirqs(struct domain *d) spin_lock(&d->event_lock); =20 for ( i =3D 0; i < d->nr_pirqs; i++ ) - if ( d->arch.pirq_irq[i] > 0 ) + if ( domain_pirq_to_irq(d, i) > 0 ) unmap_domain_pirq(d, i); =20 spin_unlock(&d->event_lock); @@ -1714,6 +1799,7 @@ static void dump_irqs(unsigned char key) struct irq_cfg *cfg; irq_guest_action_t *action; struct domain *d; + const struct pirq *info; unsigned long flags; =20 printk("Guest interrupt information:\n"); @@ -1748,20 +1834,18 @@ static void dump_irqs(unsigned char key) { d =3D action->guest[i]; pirq =3D domain_irq_to_pirq(d, irq); + info =3D pirq_info(d, pirq); printk("%u:%3d(%c%c%c%c)", d->domain_id, pirq, - (test_bit(d->pirq_to_evtchn[pirq], + (test_bit(info->evtchn, &shared_info(d, evtchn_pending)) ? 'P' : '-'), - (test_bit(d->pirq_to_evtchn[pirq] / - BITS_PER_EVTCHN_WORD(d), + (test_bit(info->evtchn / BITS_PER_EVTCHN_WORD(d), &vcpu_info(d->vcpu[0], evtchn_pending_sel= )) ? 'S' : '-'), - (test_bit(d->pirq_to_evtchn[pirq], - &shared_info(d, evtchn_mask)) ? + (test_bit(info->evtchn, &shared_info(d, evtchn_mask= )) ? 'M' : '-'), - (test_bit(pirq, d->pirq_mask) ? - 'M' : '-')); + (info->masked ? 'M' : '-')); if ( i !=3D action->nr_guests ) printk(","); } @@ -1868,6 +1952,7 @@ void fixup_irqs(void) int map_domain_emuirq_pirq(struct domain *d, int pirq, int emuirq) { int old_emuirq =3D IRQ_UNBOUND, old_pirq =3D IRQ_UNBOUND; + struct pirq *info; =20 ASSERT(spin_is_locked(&d->event_lock)); =20 @@ -1894,6 +1979,10 @@ int map_domain_emuirq_pirq(struct domain return 0; } =20 + info =3D pirq_get_info(d, pirq); + if ( !info ) + return -ENOMEM; + /* do not store emuirq mappings for pt devices */ if ( emuirq !=3D IRQ_PT ) { @@ -1909,10 +1998,11 @@ int map_domain_emuirq_pirq(struct domain (void *)((long)pirq + 1); break; default: + pirq_cleanup_check(info, d, pirq); return err; } } - d->arch.pirq_emuirq[pirq] =3D emuirq; + info->arch.hvm.emuirq =3D emuirq; =20 return 0; } @@ -1920,6 +2010,7 @@ int map_domain_emuirq_pirq(struct domain int unmap_domain_pirq_emuirq(struct domain *d, int pirq) { int emuirq, ret =3D 0; + struct pirq *info; =20 if ( !is_hvm_domain(d) ) return -EINVAL; @@ -1938,7 +2029,12 @@ int unmap_domain_pirq_emuirq(struct doma goto done; } =20 - d->arch.pirq_emuirq[pirq] =3D IRQ_UNBOUND; + info =3D pirq_info(d, pirq); + if ( info ) + { + info->arch.hvm.emuirq =3D IRQ_UNBOUND; + pirq_cleanup_check(info, d, pirq); + } if ( emuirq !=3D IRQ_PT ) radix_tree_delete(&d->arch.hvm_domain.emuirq_pirq, emuirq, NULL); =20 @@ -1946,16 +2042,9 @@ int unmap_domain_pirq_emuirq(struct doma return ret; } =20 -int hvm_domain_use_pirq(struct domain *d, int pirq) +bool_t hvm_domain_use_pirq(const struct domain *d, const struct pirq = *pirq) { - int emuirq; - =20 - if ( !is_hvm_domain(d) ) - return 0; - - emuirq =3D domain_pirq_to_emuirq(d, pirq); - if ( emuirq !=3D IRQ_UNBOUND && d->pirq_to_evtchn[pirq] !=3D 0 ) - return 1; - else - return 0; + return is_hvm_domain(d) && + pirq->arch.hvm.emuirq !=3D IRQ_UNBOUND && + pirq->evtchn !=3D 0; } --- 2011-04-29.orig/xen/arch/x86/physdev.c +++ 2011-04-29/xen/arch/x86/physdev.c @@ -258,20 +258,28 @@ ret_t do_physdev_op(int cmd, XEN_GUEST_H { case PHYSDEVOP_eoi: { struct physdev_eoi eoi; + struct pirq *pirq; + ret =3D -EFAULT; if ( copy_from_guest(&eoi, arg, 1) !=3D 0 ) break; ret =3D -EINVAL; if ( eoi.irq >=3D v->domain->nr_pirqs ) break; + spin_lock(&v->domain->event_lock); + pirq =3D pirq_info(v->domain, eoi.irq); + if ( !pirq ) { + spin_unlock(&v->domain->event_lock); + break; + } if ( !is_hvm_domain(v->domain) && v->domain->arch.pv_domain.pirq_eoi_map ) - evtchn_unmask(v->domain->pirq_to_evtchn[eoi.irq]); + evtchn_unmask(pirq->evtchn); if ( !is_hvm_domain(v->domain) || - domain_pirq_to_emuirq(v->domain, eoi.irq) =3D=3D IRQ_PT ) - ret =3D pirq_guest_eoi(v->domain, eoi.irq); - else - ret =3D 0; + pirq->arch.hvm.emuirq =3D=3D IRQ_PT ) + pirq_guest_eoi(v->domain, pirq); + spin_unlock(&v->domain->event_lock); + ret =3D 0; break; } =20 @@ -564,11 +572,23 @@ ret_t do_physdev_op(int cmd, XEN_GUEST_H break; =20 spin_lock(&d->event_lock); - out.pirq =3D get_free_pirq(d, out.type, 0); - d->arch.pirq_irq[out.pirq] =3D PIRQ_ALLOCATED; + ret =3D get_free_pirq(d, out.type, 0); + if ( ret >=3D 0 ) + { + struct pirq *info =3D pirq_get_info(d, ret); + + if ( info ) + info->arch.irq =3D PIRQ_ALLOCATED; + else + ret =3D -ENOMEM; + } spin_unlock(&d->event_lock); =20 - ret =3D copy_to_guest(arg, &out, 1) ? -EFAULT : 0; + if ( ret >=3D 0 ) + { + out.pirq =3D ret; + ret =3D copy_to_guest(arg, &out, 1) ? -EFAULT : 0; + } =20 rcu_unlock_domain(d); break; --- 2011-04-29.orig/xen/common/domain.c +++ 2011-04-29/xen/common/domain.c @@ -290,13 +290,7 @@ struct domain *domain_create( if ( d->nr_pirqs > nr_irqs ) d->nr_pirqs =3D nr_irqs; =20 - d->pirq_to_evtchn =3D xmalloc_array(u16, d->nr_pirqs); - d->pirq_mask =3D xmalloc_array( - unsigned long, BITS_TO_LONGS(d->nr_pirqs)); - if ( (d->pirq_to_evtchn =3D=3D NULL) || (d->pirq_mask =3D=3D = NULL) ) - goto fail; - memset(d->pirq_to_evtchn, 0, d->nr_pirqs * sizeof(*d->pirq_to_evtc= hn)); - bitmap_zero(d->pirq_mask, d->nr_pirqs); + INIT_RADIX_TREE(&d->pirq_tree, 0); =20 if ( evtchn_init(d) !=3D 0 ) goto fail; @@ -346,6 +340,7 @@ struct domain *domain_create( { evtchn_destroy(d); evtchn_destroy_final(d); + radix_tree_destroy(&d->pirq_tree, free_pirq_struct, NULL); } if ( init_status & INIT_rangeset ) rangeset_domain_destroy(d); @@ -353,8 +348,6 @@ struct domain *domain_create( watchdog_domain_destroy(d); if ( init_status & INIT_xsm ) xsm_free_security_domain(d); - xfree(d->pirq_mask); - xfree(d->pirq_to_evtchn); free_cpumask_var(d->domain_dirty_cpumask); free_domain_struct(d); return NULL; @@ -680,8 +673,7 @@ static void complete_domain_destroy(stru =20 evtchn_destroy_final(d); =20 - xfree(d->pirq_mask); - xfree(d->pirq_to_evtchn); + radix_tree_destroy(&d->pirq_tree, free_pirq_struct, NULL); =20 xsm_free_security_domain(d); free_cpumask_var(d->domain_dirty_cpumask); @@ -963,6 +955,20 @@ long vm_assist(struct domain *p, unsigne return -ENOSYS; } =20 +struct pirq *pirq_get_info(struct domain *d, int pirq) +{ + struct pirq *info =3D pirq_info(d, pirq); + + if ( !info && (info =3D alloc_pirq_struct(d)) !=3D NULL && + radix_tree_insert(&d->pirq_tree, pirq, info, NULL, NULL) ) + { + free_pirq_struct(info); + info =3D NULL; + } + + return info; +} + struct migrate_info { long (*func)(void *data); void *data; --- 2011-04-29.orig/xen/common/event_channel.c +++ 2011-04-29/xen/common/event_channel.c @@ -325,6 +325,7 @@ static long evtchn_bind_pirq(evtchn_bind struct evtchn *chn; struct domain *d =3D current->domain; struct vcpu *v =3D d->vcpu[0]; + struct pirq *info; int port, pirq =3D bind->pirq; long rc; =20 @@ -336,7 +337,7 @@ static long evtchn_bind_pirq(evtchn_bind =20 spin_lock(&d->event_lock); =20 - if ( d->pirq_to_evtchn[pirq] !=3D 0 ) + if ( pirq_to_evtchn(d, pirq) !=3D 0 ) ERROR_EXIT(-EEXIST); =20 if ( (port =3D get_free_port(d)) < 0 ) @@ -344,14 +345,18 @@ static long evtchn_bind_pirq(evtchn_bind =20 chn =3D evtchn_from_port(d, port); =20 - d->pirq_to_evtchn[pirq] =3D port; + info =3D pirq_get_info(d, pirq); + if ( !info ) + ERROR_EXIT(-ENOMEM); + info->evtchn =3D port; rc =3D (!is_hvm_domain(d) - ? pirq_guest_bind( - v, pirq, !!(bind->flags & BIND_PIRQ__WILL_SHARE)) + ? pirq_guest_bind(v, pirq, info, + !!(bind->flags & BIND_PIRQ__WILL_SHARE)) : 0); if ( rc !=3D 0 ) { - d->pirq_to_evtchn[pirq] =3D 0; + info->evtchn =3D 0; + pirq_cleanup_check(info, d, pirq); goto out; } =20 @@ -404,12 +409,18 @@ static long __evtchn_close(struct domain case ECS_UNBOUND: break; =20 - case ECS_PIRQ: + case ECS_PIRQ: { + struct pirq *pirq =3D pirq_info(d1, chn1->u.pirq.irq); + + if ( !pirq ) + break; if ( !is_hvm_domain(d1) ) - pirq_guest_unbind(d1, chn1->u.pirq.irq); - d1->pirq_to_evtchn[chn1->u.pirq.irq] =3D 0; + pirq_guest_unbind(d1, chn1->u.pirq.irq, pirq); + pirq->evtchn =3D 0; + pirq_cleanup_check(pirq, d1, chn1->u.pirq.irq); unlink_pirq_port(chn1, d1->vcpu[chn1->notify_vcpu_id]); break; + } =20 case ECS_VIRQ: for_each_vcpu ( d1, v ) @@ -659,9 +670,9 @@ void send_guest_global_virq(struct domai spin_unlock_irqrestore(&v->virq_lock, flags); } =20 -int send_guest_pirq(struct domain *d, int pirq) +int send_guest_pirq(struct domain *d, const struct pirq *pirq) { - int port =3D d->pirq_to_evtchn[pirq]; + int port; struct evtchn *chn; =20 /* @@ -670,7 +681,7 @@ int send_guest_pirq(struct domain *d, in * HVM guests: Port is legitimately zero when the guest disables the * emulated interrupt/evtchn. */ - if ( port =3D=3D 0 ) + if ( pirq =3D=3D NULL || (port =3D pirq->evtchn) =3D=3D 0 ) { BUG_ON(!is_hvm_domain(d)); return 0; @@ -812,13 +823,10 @@ int evtchn_unmask(unsigned int port) struct domain *d =3D current->domain; struct vcpu *v; =20 - spin_lock(&d->event_lock); + ASSERT(spin_is_locked(&d->event_lock)); =20 if ( unlikely(!port_is_valid(d, port)) ) - { - spin_unlock(&d->event_lock); return -EINVAL; - } =20 v =3D d->vcpu[evtchn_from_port(d, port)->notify_vcpu_id]; =20 @@ -834,8 +842,6 @@ int evtchn_unmask(unsigned int port) vcpu_mark_events_pending(v); } =20 - spin_unlock(&d->event_lock); - return 0; } =20 @@ -960,7 +966,9 @@ long do_event_channel_op(int cmd, XEN_GU struct evtchn_unmask unmask; if ( copy_from_guest(&unmask, arg, 1) !=3D 0 ) return -EFAULT; + spin_lock(¤t->domain->event_lock); rc =3D evtchn_unmask(unmask.port); + spin_unlock(¤t->domain->event_lock); break; } =20 --- 2011-04-29.orig/xen/common/radix-tree.c +++ 2011-04-29/xen/common/radix-tree.c @@ -225,7 +225,8 @@ EXPORT_SYMBOL(radix_tree_lookup); =20 static unsigned int __lookup(struct radix_tree_root *root, void **results, unsigned long = index, - unsigned int max_items, unsigned long *next_index) + unsigned int max_items, unsigned long *indexes, + unsigned long *next_index) { unsigned int nr_found =3D 0; unsigned int shift, height; @@ -235,8 +236,11 @@ __lookup(struct radix_tree_root *root, v height =3D root->height; if (index > radix_tree_maxindex(height)) if (height =3D=3D 0) { - if (root->rnode && index =3D=3D 0) + if (root->rnode && index =3D=3D 0) { + if (indexes) + indexes[nr_found] =3D index; results[nr_found++] =3D root->rnode; + } goto out; } =20 @@ -265,6 +269,8 @@ __lookup(struct radix_tree_root *root, v for (i =3D index & RADIX_TREE_MAP_MASK; i < RADIX_TREE_MAP_SIZE; i++) = { index++; if (slot->slots[i]) { + if (indexes) + indexes[nr_found] =3D index - 1; results[nr_found++] =3D slot->slots[i]; if (nr_found =3D=3D max_items) goto out; @@ -281,6 +287,7 @@ __lookup(struct radix_tree_root *root, v * @results: where the results of the lookup are placed * @first_index: start the lookup from this key * @max_items: place up to this many items at *results + * @indexes: (optional) array to store indexes of items. * * Performs an index-ascending scan of the tree for present items. = Places * them at *@results and returns the number of items which were placed at @@ -290,7 +297,8 @@ __lookup(struct radix_tree_root *root, v */ unsigned int radix_tree_gang_lookup(struct radix_tree_root *root, void **results, - unsigned long first_index, unsigned int max_items) + unsigned long first_index, unsigned int max_items, + unsigned long *indexes) { const unsigned long max_index =3D radix_tree_maxindex(root->height); unsigned long cur_index =3D first_index; @@ -303,7 +311,7 @@ radix_tree_gang_lookup(struct radix_tree if (cur_index > max_index) break; nr_found =3D __lookup(root, results + ret, cur_index, - max_items - ret, &next_index); + max_items - ret, indexes + ret, &next_index); ret +=3D nr_found; if (next_index =3D=3D 0) break; --- 2011-04-29.orig/xen/drivers/passthrough/io.c +++ 2011-04-29/xen/drivers/passthrough/io.c @@ -35,18 +35,28 @@ bool_t pt_irq_need_timer(uint32_t flags) return !(flags & (HVM_IRQ_DPCI_GUEST_MSI | HVM_IRQ_DPCI_TRANSLATE)); } =20 +static int pt_irq_guest_eoi(struct domain *d, unsigned int pirq, + struct hvm_pirq_dpci *pirq_dpci, void *arg) +{ + if ( __test_and_clear_bit(_HVM_IRQ_DPCI_EOI_LATCH_SHIFT, + &pirq_dpci->flags) ) + { + pirq_dpci->masked =3D 0; + pirq_dpci->pending =3D 0; + pirq_guest_eoi(d, dpci_pirq(pirq_dpci)); + } + + return 0; +} + static void pt_irq_time_out(void *data) { - struct hvm_mirq_dpci_mapping *irq_map =3D data; - unsigned int guest_gsi, machine_gsi =3D 0; + struct hvm_pirq_dpci *irq_map =3D data; + unsigned int guest_gsi; struct hvm_irq_dpci *dpci =3D NULL; struct dev_intx_gsi_link *digl; struct hvm_girq_dpci_mapping *girq; uint32_t device, intx; - unsigned int nr_pirqs =3D irq_map->dom->nr_pirqs; - DECLARE_BITMAP(machine_gsi_map, nr_pirqs); - - bitmap_zero(machine_gsi_map, nr_pirqs); =20 spin_lock(&irq_map->dom->event_lock); =20 @@ -57,32 +67,18 @@ static void pt_irq_time_out(void *data) guest_gsi =3D digl->gsi; list_for_each_entry ( girq, &dpci->girq[guest_gsi], list ) { - machine_gsi =3D girq->machine_gsi; - set_bit(machine_gsi, machine_gsi_map); + struct pirq *pirq =3D pirq_info(irq_map->dom, girq->machine_gs= i); + + pirq_dpci(pirq)->flags |=3D HVM_IRQ_DPCI_EOI_LATCH; } device =3D digl->device; intx =3D digl->intx; hvm_pci_intx_deassert(irq_map->dom, device, intx); } =20 - for ( machine_gsi =3D find_first_bit(machine_gsi_map, nr_pirqs); - machine_gsi < nr_pirqs; - machine_gsi =3D find_next_bit(machine_gsi_map, nr_pirqs, - machine_gsi + 1) ) - { - clear_bit(machine_gsi, dpci->dirq_mask); - dpci->mirq[machine_gsi].pending =3D 0; - } + pt_pirq_iterate(irq_map->dom, pt_irq_guest_eoi, NULL); =20 spin_unlock(&irq_map->dom->event_lock); - - for ( machine_gsi =3D find_first_bit(machine_gsi_map, nr_pirqs); - machine_gsi < nr_pirqs; - machine_gsi =3D find_next_bit(machine_gsi_map, nr_pirqs, - machine_gsi + 1) ) - { - pirq_guest_eoi(irq_map->dom, machine_gsi); - } } =20 struct hvm_irq_dpci *domain_get_irq_dpci(const struct domain *d) @@ -95,10 +91,6 @@ struct hvm_irq_dpci *domain_get_irq_dpci =20 void free_hvm_irq_dpci(struct hvm_irq_dpci *dpci) { - xfree(dpci->mirq); - xfree(dpci->dirq_mask); - xfree(dpci->mapping); - xfree(dpci->hvm_timer); xfree(dpci); } =20 @@ -106,7 +98,9 @@ int pt_irq_create_bind_vtd( struct domain *d, xen_domctl_bind_pt_irq_t *pt_irq_bind) { struct hvm_irq_dpci *hvm_irq_dpci =3D NULL; - uint32_t machine_gsi, guest_gsi; + struct hvm_pirq_dpci *pirq_dpci; + struct pirq *info; + uint32_t guest_gsi; uint32_t device, intx, link; struct dev_intx_gsi_link *digl; struct hvm_girq_dpci_mapping *girq; @@ -129,63 +123,45 @@ int pt_irq_create_bind_vtd( memset(hvm_irq_dpci, 0, sizeof(*hvm_irq_dpci)); tasklet_init(&hvm_irq_dpci->dirq_tasklet, hvm_dirq_assist, (unsigned long)d); - hvm_irq_dpci->mirq =3D xmalloc_array(struct hvm_mirq_dpci_mapping,= - d->nr_pirqs); - hvm_irq_dpci->dirq_mask =3D xmalloc_array(unsigned long, - BITS_TO_LONGS(d->nr_pirqs)= ); - hvm_irq_dpci->mapping =3D xmalloc_array(unsigned long, - BITS_TO_LONGS(d->nr_pirqs));= - hvm_irq_dpci->hvm_timer =3D xmalloc_array(struct timer, d->nr_pirq= s); - if ( !hvm_irq_dpci->mirq || - !hvm_irq_dpci->dirq_mask || - !hvm_irq_dpci->mapping || - !hvm_irq_dpci->hvm_timer) - { - spin_unlock(&d->event_lock); - free_hvm_irq_dpci(hvm_irq_dpci); - return -ENOMEM; - } - memset(hvm_irq_dpci->mirq, 0, - d->nr_pirqs * sizeof(*hvm_irq_dpci->mirq)); - bitmap_zero(hvm_irq_dpci->dirq_mask, d->nr_pirqs); - bitmap_zero(hvm_irq_dpci->mapping, d->nr_pirqs); - memset(hvm_irq_dpci->hvm_timer, 0, - d->nr_pirqs * sizeof(*hvm_irq_dpci->hvm_timer)); - for ( int i =3D 0; i < d->nr_pirqs; i++ ) { - INIT_LIST_HEAD(&hvm_irq_dpci->mirq[i].digl_list); - hvm_irq_dpci->mirq[i].gmsi.dest_vcpu_id =3D -1; - } for ( int i =3D 0; i < NR_HVM_IRQS; i++ ) INIT_LIST_HEAD(&hvm_irq_dpci->girq[i]); =20 d->arch.hvm_domain.irq.dpci =3D hvm_irq_dpci; } =20 + info =3D pirq_get_info(d, pirq); + if ( !info ) + { + spin_unlock(&d->event_lock); + return -ENOMEM; + } + pirq_dpci =3D pirq_dpci(info); + if ( pt_irq_bind->irq_type =3D=3D PT_IRQ_TYPE_MSI ) { uint8_t dest, dest_mode; int dest_vcpu_id; =20 - if ( !test_and_set_bit(pirq, hvm_irq_dpci->mapping)) + if ( !(pirq_dpci->flags & HVM_IRQ_DPCI_MAPPED) ) { - hvm_irq_dpci->mirq[pirq].flags =3D HVM_IRQ_DPCI_MACH_MSI | - HVM_IRQ_DPCI_GUEST_MSI; - hvm_irq_dpci->mirq[pirq].gmsi.gvec =3D pt_irq_bind->u.msi.gvec= ; - hvm_irq_dpci->mirq[pirq].gmsi.gflags =3D pt_irq_bind->u.msi.gf= lags; + pirq_dpci->flags =3D HVM_IRQ_DPCI_MAPPED | HVM_IRQ_DPCI_MACH_M= SI | + HVM_IRQ_DPCI_GUEST_MSI; + pirq_dpci->gmsi.gvec =3D pt_irq_bind->u.msi.gvec; + pirq_dpci->gmsi.gflags =3D pt_irq_bind->u.msi.gflags; /* bind after hvm_irq_dpci is setup to avoid race with irq = handler*/ - rc =3D pirq_guest_bind(d->vcpu[0], pirq, 0); + rc =3D pirq_guest_bind(d->vcpu[0], pirq, info, 0); if ( rc =3D=3D 0 && pt_irq_bind->u.msi.gtable ) { - rc =3D msixtbl_pt_register(d, pirq, pt_irq_bind->u.msi.gta= ble); + rc =3D msixtbl_pt_register(d, info, pt_irq_bind->u.msi.gta= ble); if ( unlikely(rc) ) - pirq_guest_unbind(d, pirq); + pirq_guest_unbind(d, pirq, info); } if ( unlikely(rc) ) { - hvm_irq_dpci->mirq[pirq].gmsi.gflags =3D 0; - hvm_irq_dpci->mirq[pirq].gmsi.gvec =3D 0; - hvm_irq_dpci->mirq[pirq].flags =3D 0; - clear_bit(pirq, hvm_irq_dpci->mapping); + pirq_dpci->gmsi.gflags =3D 0; + pirq_dpci->gmsi.gvec =3D 0; + pirq_dpci->flags =3D 0; + pirq_cleanup_check(info, d, pirq); spin_unlock(&d->event_lock); return rc; } @@ -194,34 +170,33 @@ int pt_irq_create_bind_vtd( { uint32_t mask =3D HVM_IRQ_DPCI_MACH_MSI | HVM_IRQ_DPCI_GUEST_M= SI; =20 - if ( (hvm_irq_dpci->mirq[pirq].flags & mask) !=3D mask) + if ( (pirq_dpci->flags & mask) !=3D mask) { spin_unlock(&d->event_lock); return -EBUSY; } =20 /* if pirq is already mapped as vmsi, update the guest = data/addr */ - if ( hvm_irq_dpci->mirq[pirq].gmsi.gvec !=3D pt_irq_bind->u.ms= i.gvec || - hvm_irq_dpci->mirq[pirq].gmsi.gflags !=3D pt_irq_bind-= >u.msi.gflags) { + if ( pirq_dpci->gmsi.gvec !=3D pt_irq_bind->u.msi.gvec || + pirq_dpci->gmsi.gflags !=3D pt_irq_bind->u.msi.gflags) { /* Directly clear pending EOIs before enabling new MSI = info. */ - pirq_guest_eoi(d, pirq); + pirq_guest_eoi(d, info); =20 - hvm_irq_dpci->mirq[pirq].gmsi.gvec =3D pt_irq_bind->u.msi.= gvec; - hvm_irq_dpci->mirq[pirq].gmsi.gflags =3D pt_irq_bind->u.ms= i.gflags; + pirq_dpci->gmsi.gvec =3D pt_irq_bind->u.msi.gvec; + pirq_dpci->gmsi.gflags =3D pt_irq_bind->u.msi.gflags; } } /* Caculate dest_vcpu_id for MSI-type pirq migration */ - dest =3D hvm_irq_dpci->mirq[pirq].gmsi.gflags & VMSI_DEST_ID_MASK;= - dest_mode =3D !!(hvm_irq_dpci->mirq[pirq].gmsi.gflags & VMSI_DM_MA= SK); + dest =3D pirq_dpci->gmsi.gflags & VMSI_DEST_ID_MASK; + dest_mode =3D !!(pirq_dpci->gmsi.gflags & VMSI_DM_MASK); dest_vcpu_id =3D hvm_girq_dest_2_vcpu_id(d, dest, dest_mode); - hvm_irq_dpci->mirq[pirq].gmsi.dest_vcpu_id =3D dest_vcpu_id; + pirq_dpci->gmsi.dest_vcpu_id =3D dest_vcpu_id; spin_unlock(&d->event_lock); if ( dest_vcpu_id >=3D 0 ) hvm_migrate_pirqs(d->vcpu[dest_vcpu_id]); } else { - machine_gsi =3D pt_irq_bind->machine_irq; device =3D pt_irq_bind->u.pci.device; intx =3D pt_irq_bind->u.pci.intx; guest_gsi =3D hvm_pci_intx_gsi(device, intx); @@ -247,50 +222,51 @@ int pt_irq_create_bind_vtd( digl->intx =3D intx; digl->gsi =3D guest_gsi; digl->link =3D link; - list_add_tail(&digl->list, - &hvm_irq_dpci->mirq[machine_gsi].digl_list); + list_add_tail(&digl->list, &pirq_dpci->digl_list); =20 girq->device =3D device; girq->intx =3D intx; - girq->machine_gsi =3D machine_gsi; + girq->machine_gsi =3D pirq; list_add_tail(&girq->list, &hvm_irq_dpci->girq[guest_gsi]); =20 /* Bind the same mirq once in the same domain */ - if ( !test_and_set_bit(machine_gsi, hvm_irq_dpci->mapping)) + if ( !(pirq_dpci->flags & HVM_IRQ_DPCI_MAPPED) ) { unsigned int share; =20 - hvm_irq_dpci->mirq[machine_gsi].dom =3D d; + pirq_dpci->dom =3D d; if ( pt_irq_bind->irq_type =3D=3D PT_IRQ_TYPE_MSI_TRANSLATE ) { - hvm_irq_dpci->mirq[machine_gsi].flags =3D HVM_IRQ_DPCI_MAC= H_MSI | - HVM_IRQ_DPCI_GUEST= _PCI | - HVM_IRQ_DPCI_TRANS= LATE; + pirq_dpci->flags =3D HVM_IRQ_DPCI_MAPPED | + HVM_IRQ_DPCI_MACH_MSI | + HVM_IRQ_DPCI_GUEST_PCI | + HVM_IRQ_DPCI_TRANSLATE; share =3D 0; } else /* PT_IRQ_TYPE_PCI */ { - hvm_irq_dpci->mirq[machine_gsi].flags =3D HVM_IRQ_DPCI_MAC= H_PCI | - HVM_IRQ_DPCI_GUEST= _PCI; + pirq_dpci->flags =3D HVM_IRQ_DPCI_MAPPED | + HVM_IRQ_DPCI_MACH_PCI | + HVM_IRQ_DPCI_GUEST_PCI; share =3D BIND_PIRQ__WILL_SHARE; } =20 /* Init timer before binding */ - if ( pt_irq_need_timer(hvm_irq_dpci->mirq[machine_gsi].flags) = ) - init_timer(&hvm_irq_dpci->hvm_timer[machine_gsi], - pt_irq_time_out, &hvm_irq_dpci->mirq[machine_gs= i], 0); + if ( pt_irq_need_timer(pirq_dpci->flags) ) + init_timer(&pirq_dpci->timer, pt_irq_time_out, pirq_dpci, = 0); /* Deal with gsi for legacy devices */ - rc =3D pirq_guest_bind(d->vcpu[0], machine_gsi, share); + rc =3D pirq_guest_bind(d->vcpu[0], pirq, info, share); if ( unlikely(rc) ) { - if ( pt_irq_need_timer(hvm_irq_dpci->mirq[machine_gsi].fla= gs) ) - kill_timer(&hvm_irq_dpci->hvm_timer[machine_gsi]); - hvm_irq_dpci->mirq[machine_gsi].dom =3D NULL; - clear_bit(machine_gsi, hvm_irq_dpci->mapping); + if ( pt_irq_need_timer(pirq_dpci->flags) ) + kill_timer(&pirq_dpci->timer); + pirq_dpci->dom =3D NULL; list_del(&girq->list); xfree(girq); list_del(&digl->list); hvm_irq_dpci->link_cnt[link]--; + pirq_dpci->flags =3D 0; + pirq_cleanup_check(info, d, pirq); spin_unlock(&d->event_lock); xfree(digl); return rc; @@ -302,7 +278,7 @@ int pt_irq_create_bind_vtd( if ( iommu_verbose ) dprintk(VTDPREFIX, "d%d: bind: m_gsi=3D%u g_gsi=3D%u device=3D%u = intx=3D%u\n", - d->domain_id, machine_gsi, guest_gsi, device, intx); + d->domain_id, pirq, guest_gsi, device, intx); } return 0; } @@ -311,11 +287,12 @@ int pt_irq_destroy_bind_vtd( struct domain *d, xen_domctl_bind_pt_irq_t *pt_irq_bind) { struct hvm_irq_dpci *hvm_irq_dpci =3D NULL; + struct hvm_pirq_dpci *pirq_dpci; uint32_t machine_gsi, guest_gsi; uint32_t device, intx, link; - struct list_head *digl_list, *tmp; - struct dev_intx_gsi_link *digl; + struct dev_intx_gsi_link *digl, *tmp; struct hvm_girq_dpci_mapping *girq; + struct pirq *pirq; =20 machine_gsi =3D pt_irq_bind->machine_irq; device =3D pt_irq_bind->u.pci.device; @@ -350,14 +327,14 @@ int pt_irq_destroy_bind_vtd( } } =20 + pirq =3D pirq_info(d, machine_gsi); + pirq_dpci =3D pirq_dpci(pirq); + /* clear the mirq info */ - if ( test_bit(machine_gsi, hvm_irq_dpci->mapping)) + if ( pirq_dpci && (pirq_dpci->flags & HVM_IRQ_DPCI_MAPPED) ) { - list_for_each_safe ( digl_list, tmp, - &hvm_irq_dpci->mirq[machine_gsi].digl_list ) + list_for_each_entry_safe ( digl, tmp, &pirq_dpci->digl_list, list = ) { - digl =3D list_entry(digl_list, - struct dev_intx_gsi_link, list); if ( digl->device =3D=3D device && digl->intx =3D=3D intx && digl->link =3D=3D link && @@ -368,15 +345,15 @@ int pt_irq_destroy_bind_vtd( } } =20 - if ( list_empty(&hvm_irq_dpci->mirq[machine_gsi].digl_list) ) + if ( list_empty(&pirq_dpci->digl_list) ) { - pirq_guest_unbind(d, machine_gsi); - msixtbl_pt_unregister(d, machine_gsi); - if ( pt_irq_need_timer(hvm_irq_dpci->mirq[machine_gsi].flags) = ) - kill_timer(&hvm_irq_dpci->hvm_timer[machine_gsi]); - hvm_irq_dpci->mirq[machine_gsi].dom =3D NULL; - hvm_irq_dpci->mirq[machine_gsi].flags =3D 0; - clear_bit(machine_gsi, hvm_irq_dpci->mapping); + pirq_guest_unbind(d, machine_gsi, pirq); + msixtbl_pt_unregister(d, pirq); + if ( pt_irq_need_timer(pirq_dpci->flags) ) + kill_timer(&pirq_dpci->timer); + pirq_dpci->dom =3D NULL; + pirq_dpci->flags =3D 0; + pirq_cleanup_check(pirq, d, machine_gsi); } } spin_unlock(&d->event_lock); @@ -389,120 +366,156 @@ int pt_irq_destroy_bind_vtd( return 0; } =20 -int hvm_do_IRQ_dpci(struct domain *d, unsigned int mirq) +void pt_pirq_init(struct domain *d, struct hvm_pirq_dpci *dpci) +{ + INIT_LIST_HEAD(&dpci->digl_list); + dpci->gmsi.dest_vcpu_id =3D -1; +} + +bool_t pt_pirq_cleanup_check(struct hvm_pirq_dpci *dpci) +{ + return !dpci->flags; +} + +int pt_pirq_iterate(struct domain *d, + int (*cb)(struct domain *, unsigned int, + struct hvm_pirq_dpci *, void *), + void *arg) +{ + int rc =3D 0; + unsigned int pirq =3D 0, n, i; + unsigned long indexes[8]; + struct pirq *pirqs[ARRAY_SIZE(indexes)]; + + ASSERT(spin_is_locked(&d->event_lock)); + + do { + n =3D radix_tree_gang_lookup(&d->pirq_tree, (void **)pirqs, pirq, + ARRAY_SIZE(pirqs), indexes); + for ( i =3D 0; i < n; ++i ) + { + struct hvm_pirq_dpci *pirq_dpci =3D pirq_dpci(pirqs[i]); + + pirq =3D indexes[i]; + if ( (pirq_dpci->flags & HVM_IRQ_DPCI_MAPPED) ) + rc =3D cb(d, pirq, pirq_dpci, arg); + } + } while ( !rc && ++pirq < d->nr_pirqs && n =3D=3D ARRAY_SIZE(pirqs) = ); + + return rc; +} + +int hvm_do_IRQ_dpci(struct domain *d, struct pirq *pirq) { struct hvm_irq_dpci *dpci =3D domain_get_irq_dpci(d); + struct hvm_pirq_dpci *pirq_dpci =3D pirq_dpci(pirq); =20 - ASSERT(spin_is_locked(&irq_desc[domain_pirq_to_irq(d, mirq)].lock)); - if ( !iommu_enabled || !dpci || !test_bit(mirq, dpci->mapping)) + if ( !iommu_enabled || !dpci || !pirq_dpci || + !(pirq_dpci->flags & HVM_IRQ_DPCI_MAPPED) ) return 0; =20 - set_bit(mirq, dpci->dirq_mask); + pirq_dpci->masked =3D 1; tasklet_schedule(&dpci->dirq_tasklet); return 1; } =20 #ifdef SUPPORT_MSI_REMAPPING /* called with d->event_lock held */ -static void __msi_pirq_eoi(struct domain *d, int pirq) +static void __msi_pirq_eoi(struct domain *d, struct hvm_pirq_dpci = *pirq_dpci) { - struct hvm_irq_dpci *hvm_irq_dpci =3D d->arch.hvm_domain.irq.dpci; irq_desc_t *desc; =20 - if ( ( pirq >=3D 0 ) && ( pirq < d->nr_pirqs ) && - test_bit(pirq, hvm_irq_dpci->mapping) && - ( hvm_irq_dpci->mirq[pirq].flags & HVM_IRQ_DPCI_MACH_MSI) ) + if ( (pirq_dpci->flags & HVM_IRQ_DPCI_MAPPED) && + (pirq_dpci->flags & HVM_IRQ_DPCI_MACH_MSI) ) { + struct pirq *pirq =3D dpci_pirq(pirq_dpci); + BUG_ON(!local_irq_is_enabled()); - desc =3D domain_spin_lock_irq_desc(d, pirq, NULL); + desc =3D pirq_spin_lock_irq_desc(d, pirq, NULL); if ( !desc ) return; =20 desc->status &=3D ~IRQ_INPROGRESS; - spin_unlock_irq(&desc->lock); + desc_guest_eoi(d, desc, pirq); + } +} =20 - pirq_guest_eoi(d, pirq); +static int _hvm_dpci_msi_eoi(struct domain *d, unsigned int pirq, + struct hvm_pirq_dpci *pirq_dpci, void *arg) +{ + int vector =3D (long)arg; + + if ( (pirq_dpci->flags & HVM_IRQ_DPCI_MACH_MSI) && + (pirq_dpci->gmsi.gvec =3D=3D vector) ) + { + int dest =3D pirq_dpci->gmsi.gflags & VMSI_DEST_ID_MASK; + int dest_mode =3D !!(pirq_dpci->gmsi.gflags & VMSI_DM_MASK); + + if ( vlapic_match_dest(vcpu_vlapic(current), NULL, 0, dest, + dest_mode) ) + { + __msi_pirq_eoi(d, pirq_dpci); + return 1; + } } + + return 0; } =20 void hvm_dpci_msi_eoi(struct domain *d, int vector) { - int pirq, dest, dest_mode; - struct hvm_irq_dpci *hvm_irq_dpci =3D d->arch.hvm_domain.irq.dpci; - - if ( !iommu_enabled || (hvm_irq_dpci =3D=3D NULL) ) + if ( !iommu_enabled || !d->arch.hvm_domain.irq.dpci ) return; =20 spin_lock(&d->event_lock); - for ( pirq =3D find_first_bit(hvm_irq_dpci->mapping, d->nr_pirqs); - pirq < d->nr_pirqs; - pirq =3D find_next_bit(hvm_irq_dpci->mapping, d->nr_pirqs, pirq = + 1) ) - { - if ( (!(hvm_irq_dpci->mirq[pirq].flags & HVM_IRQ_DPCI_MACH_MSI)) = || - (hvm_irq_dpci->mirq[pirq].gmsi.gvec !=3D vector) ) - continue; - - dest =3D hvm_irq_dpci->mirq[pirq].gmsi.gflags & VMSI_DEST_ID_MASK;= - dest_mode =3D !!(hvm_irq_dpci->mirq[pirq].gmsi.gflags & VMSI_DM_MA= SK); - if ( vlapic_match_dest(vcpu_vlapic(current), NULL, 0, dest, = dest_mode) ) - break; - } - if ( pirq < d->nr_pirqs ) - __msi_pirq_eoi(d, pirq); + pt_pirq_iterate(d, _hvm_dpci_msi_eoi, (void *)(long)vector); spin_unlock(&d->event_lock); } =20 -extern int vmsi_deliver(struct domain *d, int pirq); -static int hvm_pci_msi_assert(struct domain *d, int pirq) +static int hvm_pci_msi_assert(struct domain *d, + struct hvm_pirq_dpci *pirq_dpci) { + struct pirq *pirq =3D dpci_pirq(pirq_dpci); + if ( hvm_domain_use_pirq(d, pirq) ) return send_guest_pirq(d, pirq); else - return vmsi_deliver(d, pirq); + return vmsi_deliver(d, pirq_dpci); } #endif =20 -static void hvm_dirq_assist(unsigned long _d) +static int _hvm_dirq_assist(struct domain *d, unsigned int pirq, + struct hvm_pirq_dpci *pirq_dpci, void *arg) { - unsigned int pirq; uint32_t device, intx; - struct domain *d =3D (struct domain *)_d; - struct hvm_irq_dpci *hvm_irq_dpci =3D d->arch.hvm_domain.irq.dpci; struct dev_intx_gsi_link *digl; =20 - ASSERT(hvm_irq_dpci); - - for ( pirq =3D find_first_bit(hvm_irq_dpci->dirq_mask, d->nr_pirqs); - pirq < d->nr_pirqs; - pirq =3D find_next_bit(hvm_irq_dpci->dirq_mask, d->nr_pirqs, = pirq + 1) ) + if ( test_and_clear_bool(pirq_dpci->masked) ) { - if ( !test_and_clear_bit(pirq, hvm_irq_dpci->dirq_mask) ) - continue; - - spin_lock(&d->event_lock); #ifdef SUPPORT_MSI_REMAPPING - if ( hvm_irq_dpci->mirq[pirq].flags & HVM_IRQ_DPCI_GUEST_MSI ) + if ( pirq_dpci->flags & HVM_IRQ_DPCI_GUEST_MSI ) { - hvm_pci_msi_assert(d, pirq); - spin_unlock(&d->event_lock); - continue; + hvm_pci_msi_assert(d, pirq_dpci); + return 0; } #endif - list_for_each_entry ( digl, &hvm_irq_dpci->mirq[pirq].digl_list, = list ) + list_for_each_entry ( digl, &pirq_dpci->digl_list, list ) { + struct pirq *info =3D dpci_pirq(pirq_dpci); + device =3D digl->device; intx =3D digl->intx; - if ( hvm_domain_use_pirq(d, pirq) ) - send_guest_pirq(d, pirq); + if ( hvm_domain_use_pirq(d, info) ) + send_guest_pirq(d, info); else hvm_pci_intx_assert(d, device, intx); - hvm_irq_dpci->mirq[pirq].pending++; + pirq_dpci->pending++; =20 #ifdef SUPPORT_MSI_REMAPPING - if ( hvm_irq_dpci->mirq[pirq].flags & HVM_IRQ_DPCI_TRANSLATE = ) + if ( pirq_dpci->flags & HVM_IRQ_DPCI_TRANSLATE ) { /* for translated MSI to INTx interrupt, eoi as early as = possible */ - __msi_pirq_eoi(d, pirq); + __msi_pirq_eoi(d, pirq_dpci); } #endif } @@ -514,37 +527,50 @@ static void hvm_dirq_assist(unsigned lon * guest will never deal with the irq, then the physical = interrupt line * will never be deasserted. */ - if ( pt_irq_need_timer(hvm_irq_dpci->mirq[pirq].flags) ) - set_timer(&hvm_irq_dpci->hvm_timer[pirq], - NOW() + PT_IRQ_TIME_OUT); - spin_unlock(&d->event_lock); + if ( pt_irq_need_timer(pirq_dpci->flags) ) + set_timer(&pirq_dpci->timer, NOW() + PT_IRQ_TIME_OUT); } + + return 0; +} + +static void hvm_dirq_assist(unsigned long _d) +{ + struct domain *d =3D (struct domain *)_d; + + ASSERT(d->arch.hvm_domain.irq.dpci); + + spin_lock(&d->event_lock); + pt_pirq_iterate(d, _hvm_dirq_assist, NULL); + spin_unlock(&d->event_lock); } =20 static void __hvm_dpci_eoi(struct domain *d, - struct hvm_irq_dpci *hvm_irq_dpci, struct hvm_girq_dpci_mapping *girq, union vioapic_redir_entry *ent) { - uint32_t device, intx, machine_gsi; + uint32_t device, intx; + struct pirq *pirq; + struct hvm_pirq_dpci *pirq_dpci; =20 device =3D girq->device; intx =3D girq->intx; hvm_pci_intx_deassert(d, device, intx); =20 - machine_gsi =3D girq->machine_gsi; + pirq =3D pirq_info(d, girq->machine_gsi); + pirq_dpci =3D pirq_dpci(pirq); =20 /* * No need to get vector lock for timer * since interrupt is still not EOIed */ - if ( --hvm_irq_dpci->mirq[machine_gsi].pending || + if ( --pirq_dpci->pending || ( ent && ent->fields.mask ) || - ! pt_irq_need_timer(hvm_irq_dpci->mirq[machine_gsi].flags) ) + ! pt_irq_need_timer(pirq_dpci->flags) ) return; =20 - stop_timer(&hvm_irq_dpci->hvm_timer[machine_gsi]); - pirq_guest_eoi(d, machine_gsi); + stop_timer(&pirq_dpci->timer); + pirq_guest_eoi(d, pirq); } =20 void hvm_dpci_eoi(struct domain *d, unsigned int guest_gsi, @@ -569,7 +595,7 @@ void hvm_dpci_eoi(struct domain *d, unsi goto unlock; =20 list_for_each_entry ( girq, &hvm_irq_dpci->girq[guest_gsi], list ) - __hvm_dpci_eoi(d, hvm_irq_dpci, girq, ent); + __hvm_dpci_eoi(d, girq, ent); =20 unlock: spin_unlock(&d->event_lock); --- 2011-04-29.orig/xen/drivers/passthrough/pci.c +++ 2011-04-29/xen/drivers/passthrough/pci.c @@ -236,12 +236,28 @@ out: return ret; } =20 +static int pci_clean_dpci_irq(struct domain *d, unsigned int pirq, + struct hvm_pirq_dpci *pirq_dpci, void *arg) +{ + struct dev_intx_gsi_link *digl, *tmp; + + pirq_guest_unbind(d, pirq, dpci_pirq(pirq_dpci)); + + if ( pt_irq_need_timer(pirq_dpci->flags) ) + kill_timer(&pirq_dpci->timer); + + list_for_each_entry_safe ( digl, tmp, &pirq_dpci->digl_list, list ) + { + list_del(&digl->list); + xfree(digl); + } + + return 0; +} + static void pci_clean_dpci_irqs(struct domain *d) { struct hvm_irq_dpci *hvm_irq_dpci =3D NULL; - uint32_t i; - struct list_head *digl_list, *tmp; - struct dev_intx_gsi_link *digl; =20 if ( !iommu_enabled ) return; @@ -255,24 +271,7 @@ static void pci_clean_dpci_irqs(struct d { tasklet_kill(&hvm_irq_dpci->dirq_tasklet); =20 - for ( i =3D find_first_bit(hvm_irq_dpci->mapping, d->nr_pirqs); - i < d->nr_pirqs; - i =3D find_next_bit(hvm_irq_dpci->mapping, d->nr_pirqs, i + = 1) ) - { - pirq_guest_unbind(d, i); - - if ( pt_irq_need_timer(hvm_irq_dpci->mirq[i].flags) ) - kill_timer(&hvm_irq_dpci->hvm_timer[i]); - - list_for_each_safe ( digl_list, tmp, - &hvm_irq_dpci->mirq[i].digl_list ) - { - digl =3D list_entry(digl_list, - struct dev_intx_gsi_link, list); - list_del(&digl->list); - xfree(digl); - } - } + pt_pirq_iterate(d, pci_clean_dpci_irq, NULL); =20 d->arch.hvm_domain.irq.dpci =3D NULL; free_hvm_irq_dpci(hvm_irq_dpci); --- 2011-04-29.orig/xen/drivers/passthrough/vtd/x86/vtd.c +++ 2011-04-29/xen/drivers/passthrough/vtd/x86/vtd.c @@ -68,12 +68,32 @@ void *__init map_to_nocache_virt(int nr_ return (void *)fix_to_virt(FIX_IOMMU_REGS_BASE_0 + nr_iommus); } =20 -void hvm_dpci_isairq_eoi(struct domain *d, unsigned int isairq) +static int _hvm_dpci_isairq_eoi(struct domain *d, unsigned int pirq, + struct hvm_pirq_dpci *pirq_dpci, void = *arg) { struct hvm_irq *hvm_irq =3D &d->arch.hvm_domain.irq; - struct hvm_irq_dpci *dpci =3D NULL; + unsigned int isairq =3D (long)arg; struct dev_intx_gsi_link *digl, *tmp; - int i; + + list_for_each_entry_safe ( digl, tmp, &pirq_dpci->digl_list, list ) + { + if ( hvm_irq->pci_link.route[digl->link] =3D=3D isairq ) + { + hvm_pci_intx_deassert(d, digl->device, digl->intx); + if ( --pirq_dpci->pending =3D=3D 0 ) + { + stop_timer(&pirq_dpci->timer); + pirq_guest_eoi(d, dpci_pirq(pirq_dpci)); + } + } + } + + return 0; +} + +void hvm_dpci_isairq_eoi(struct domain *d, unsigned int isairq) +{ + struct hvm_irq_dpci *dpci =3D NULL; =20 ASSERT(isairq < NR_ISAIRQS); if ( !iommu_enabled) @@ -83,29 +103,10 @@ void hvm_dpci_isairq_eoi(struct domain * =20 dpci =3D domain_get_irq_dpci(d); =20 - if ( !dpci || !test_bit(isairq, dpci->isairq_map) ) + if ( dpci && test_bit(isairq, dpci->isairq_map) ) { - spin_unlock(&d->event_lock); - return; - } - /* Multiple mirq may be mapped to one isa irq */ - for ( i =3D find_first_bit(dpci->mapping, d->nr_pirqs); - i < d->nr_pirqs; - i =3D find_next_bit(dpci->mapping, d->nr_pirqs, i + 1) ) - { - list_for_each_entry_safe ( digl, tmp, - &dpci->mirq[i].digl_list, list ) - { - if ( hvm_irq->pci_link.route[digl->link] =3D=3D isairq ) - { - hvm_pci_intx_deassert(d, digl->device, digl->intx); - if ( --dpci->mirq[i].pending =3D=3D 0 ) - { - stop_timer(&dpci->hvm_timer[i]); - pirq_guest_eoi(d, i); - } - } - } + /* Multiple mirq may be mapped to one isa irq */ + pt_pirq_iterate(d, _hvm_dpci_isairq_eoi, (void *)(long)isairq); } spin_unlock(&d->event_lock); } --- 2011-04-29.orig/xen/include/asm-ia64/domain.h +++ 2011-04-29/xen/include/asm-ia64/domain.h @@ -11,6 +11,7 @@ #include #include #include +#include #include #include =20 @@ -316,6 +317,23 @@ struct arch_vcpu { cpumask_t cache_coherent_map; }; =20 +struct arch_pirq { + struct hvm_pirq_dpci dpci; +}; + +#define pirq_dpci(pirq) ((pirq) ? &(pirq)->arch.dpci : NULL) +#define dpci_pirq(dpci) container_of(dpci, struct pirq, arch.dpci) + +#define alloc_pirq_struct(d) ({ \ + struct pirq *pirq =3D xmalloc(struct pirq); \ + if ( pirq ) \ + { \ + memset(pirq, 0, sizeof(*pirq)); \ + pt_pirq_init(d, &pirq->arch.dpci); \ + } \ + pirq; \ +}) + #include /* for KERNEL_DS */ #include =20 --- 2011-04-29.orig/xen/include/asm-x86/domain.h +++ 2011-04-29/xen/include/asm-x86/domain.h @@ -286,9 +286,6 @@ struct arch_domain =20 /* NB. protected by d->event_lock and by irq_desc[irq].lock */ struct radix_tree_root irq_pirq; - int *pirq_irq; - /* pirq to emulated irq */ - int *pirq_emuirq; =20 /* Maximum physical-address bitwidth supported by this guest. */ unsigned int physaddr_bitsize; --- 2011-04-29.orig/xen/include/asm-x86/hvm/irq.h +++ 2011-04-29/xen/include/asm-x86/hvm/irq.h @@ -111,4 +111,6 @@ struct hvm_intack hvm_vcpu_ack_pending_i */ #define SUPPORT_MSI_REMAPPING 1 =20 +void msixtbl_pt_cleanup(struct domain *d); + #endif /* __ASM_X86_HVM_IRQ_H__ */ --- 2011-04-29.orig/xen/include/asm-x86/irq.h +++ 2011-04-29/xen/include/asm-x86/irq.h @@ -7,6 +7,7 @@ #include #include #include +#include #include #include =20 @@ -105,6 +106,20 @@ extern unsigned int io_apic_irqs; =20 DECLARE_PER_CPU(unsigned int, irq_count); =20 +struct pirq; +struct arch_pirq { + int irq; + union { + struct hvm_pirq { + int emuirq; + struct hvm_pirq_dpci dpci; + } hvm; + }; +}; + +#define pirq_dpci(pirq) ((pirq) ? &(pirq)->arch.hvm.dpci : NULL) +#define dpci_pirq(pd) container_of(pd, struct pirq, arch.hvm.dpci) + int pirq_shared(struct domain *d , int irq); =20 int map_domain_pirq(struct domain *d, int pirq, int irq, int type, @@ -114,7 +129,7 @@ int get_free_pirq(struct domain *d, int=20 void free_domain_pirqs(struct domain *d); int map_domain_emuirq_pirq(struct domain *d, int pirq, int irq); int unmap_domain_pirq_emuirq(struct domain *d, int pirq); -int hvm_domain_use_pirq(struct domain *d, int irq); +bool_t hvm_domain_use_pirq(const struct domain *, const struct pirq *); =20 int init_irq_data(void); =20 @@ -146,11 +161,11 @@ void irq_set_affinity(struct irq_desc *, int init_domain_irq_mapping(struct domain *); void cleanup_domain_irq_mapping(struct domain *); =20 -#define domain_pirq_to_irq(d, pirq) ((d)->arch.pirq_irq[pirq]) +#define domain_pirq_to_irq(d, pirq) pirq_field(d, pirq, arch.irq) #define domain_irq_to_pirq(d, irq) \ ((long)radix_tree_lookup(&(d)->arch.irq_pirq, irq)) #define PIRQ_ALLOCATED -1 -#define domain_pirq_to_emuirq(d, pirq) ((d)->arch.pirq_emuirq[pirq]) +#define domain_pirq_to_emuirq(d, pirq) pirq_field(d, pirq, arch.hvm.emuirq= ) #define domain_emuirq_to_pirq(d, emuirq) \ (((long)radix_tree_lookup(&(d)->arch.hvm_domain.emuirq_pirq, emuirq) = ?: \ IRQ_UNBOUND + 1) - 1) --- 2011-04-29.orig/xen/include/xen/domain.h +++ 2011-04-29/xen/include/xen/domain.h @@ -38,6 +38,12 @@ struct vcpu_guest_context *alloc_vcpu_gu void free_vcpu_guest_context(struct vcpu_guest_context *); #endif =20 +/* Allocate/free a PIRQ structure. */ +#ifndef alloc_pirq_struct +struct pirq *alloc_pirq_struct(struct domain *); +#endif +#define free_pirq_struct xfree + /* * Initialise/destroy arch-specific details of a VCPU. * - vcpu_initialise() is called after the basic generic fields of the --- 2011-04-29.orig/xen/include/xen/event.h +++ 2011-04-29/xen/include/xen/event.h @@ -36,7 +36,7 @@ void send_guest_global_virq(struct domai * @pirq: Physical IRQ number * Returns TRUE if the delivery port was already pending. */ -int send_guest_pirq(struct domain *d, int pirq); +int send_guest_pirq(struct domain *, const struct pirq *); =20 /* Send a notification from a given domain's event-channel port. */ int evtchn_send(struct domain *d, unsigned int lport); --- 2011-04-29.orig/xen/include/xen/hvm/irq.h +++ 2011-04-29/xen/include/xen/hvm/irq.h @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include =20 struct dev_intx_gsi_link { @@ -38,11 +38,15 @@ struct dev_intx_gsi_link { =20 #define _HVM_IRQ_DPCI_MACH_PCI_SHIFT 0 #define _HVM_IRQ_DPCI_MACH_MSI_SHIFT 1 +#define _HVM_IRQ_DPCI_MAPPED_SHIFT 2 +#define _HVM_IRQ_DPCI_EOI_LATCH_SHIFT 3 #define _HVM_IRQ_DPCI_GUEST_PCI_SHIFT 4 #define _HVM_IRQ_DPCI_GUEST_MSI_SHIFT 5 #define _HVM_IRQ_DPCI_TRANSLATE_SHIFT 15 #define HVM_IRQ_DPCI_MACH_PCI (1 << _HVM_IRQ_DPCI_MACH_PCI_SHIFT) #define HVM_IRQ_DPCI_MACH_MSI (1 << _HVM_IRQ_DPCI_MACH_MSI_SHIFT) +#define HVM_IRQ_DPCI_MAPPED (1 << _HVM_IRQ_DPCI_MAPPED_SHIFT) +#define HVM_IRQ_DPCI_EOI_LATCH (1 << _HVM_IRQ_DPCI_EOI_LATCH_SHIFT) #define HVM_IRQ_DPCI_GUEST_PCI (1 << _HVM_IRQ_DPCI_GUEST_PCI_SHIFT) #define HVM_IRQ_DPCI_GUEST_MSI (1 << _HVM_IRQ_DPCI_GUEST_MSI_SHIFT) #define HVM_IRQ_DPCI_TRANSLATE (1 << _HVM_IRQ_DPCI_TRANSLATE_SHIFT) @@ -63,14 +67,6 @@ struct hvm_gmsi_info { int dest_vcpu_id; /* -1 :multi-dest, non-negative: dest_vcpu_id */ }; =20 -struct hvm_mirq_dpci_mapping { - uint32_t flags; - int pending; - struct list_head digl_list; - struct domain *dom; - struct hvm_gmsi_info gmsi; -}; - struct hvm_girq_dpci_mapping { struct list_head list; uint8_t device; @@ -88,20 +84,33 @@ struct hvm_girq_dpci_mapping { =20 /* Protected by domain's event_lock */ struct hvm_irq_dpci { - /* Machine IRQ to guest device/intx mapping. */ - unsigned long *mapping; - struct hvm_mirq_dpci_mapping *mirq; - unsigned long *dirq_mask; /* Guest IRQ to guest device/intx mapping. */ struct list_head girq[NR_HVM_IRQS]; /* Record of mapped ISA IRQs */ DECLARE_BITMAP(isairq_map, NR_ISAIRQS); /* Record of mapped Links */ uint8_t link_cnt[NR_LINK]; - struct timer *hvm_timer; struct tasklet dirq_tasklet; }; =20 +/* Machine IRQ to guest device/intx mapping. */ +struct hvm_pirq_dpci { + uint32_t flags; + bool_t masked; + uint16_t pending; + struct list_head digl_list; + struct domain *dom; + struct hvm_gmsi_info gmsi; + struct timer timer; +}; + +void pt_pirq_init(struct domain *, struct hvm_pirq_dpci *); +bool_t pt_pirq_cleanup_check(struct hvm_pirq_dpci *); +int pt_pirq_iterate(struct domain *d, + int (*cb)(struct domain *, unsigned int pirq, + struct hvm_pirq_dpci *, void *arg), + void *arg); + /* Modify state of a PCI INTx wire. */ void hvm_pci_intx_assert( struct domain *d, unsigned int device, unsigned int intx); @@ -120,4 +129,6 @@ void hvm_maybe_deassert_evtchn_irq(void) void hvm_assert_evtchn_irq(struct vcpu *v); void hvm_set_callback_via(struct domain *d, uint64_t via); =20 +int vmsi_deliver(struct domain *, const struct hvm_pirq_dpci *); + #endif /* __XEN_HVM_IRQ_H__ */ --- 2011-04-29.orig/xen/include/xen/iommu.h +++ 2011-04-29/xen/include/xen/iommu.h @@ -88,7 +88,9 @@ int iommu_unmap_page(struct domain *d, u void iommu_pte_flush(struct domain *d, u64 gfn, u64 *pte, int order, int = present); void iommu_set_pgd(struct domain *d); void iommu_domain_teardown(struct domain *d); -int hvm_do_IRQ_dpci(struct domain *d, unsigned int irq); + +struct pirq; +int hvm_do_IRQ_dpci(struct domain *, struct pirq *); int dpci_ioport_intercept(ioreq_t *p); int pt_irq_create_bind_vtd(struct domain *d, xen_domctl_bind_pt_irq_t *pt_irq_bind); --- 2011-04-29.orig/xen/include/xen/irq.h +++ 2011-04-29/xen/include/xen/irq.h @@ -135,13 +135,41 @@ extern void no_action(int cpl, void *dev =20 struct domain; struct vcpu; -extern int pirq_guest_eoi(struct domain *d, int irq); + +struct pirq { + u16 evtchn; + bool_t masked; + struct arch_pirq arch; +}; + +#define pirq_info(d, p) ((struct pirq *)radix_tree_lookup(&(d)->pirq_tree,= p)) + +/* Use this instead of pirq_info() if the structure may need allocating. = */ +extern struct pirq *pirq_get_info(struct domain *, int pirq); + +#define pirq_field(d, p, f) ({ \ + const struct pirq *__pi =3D pirq_info(d, p); \ + __pi ? __pi->f : 0; \ +}) +#define pirq_to_evtchn(d, pirq) pirq_field(d, pirq, evtchn) +#define pirq_masked(d, pirq) pirq_field(d, pirq, masked) + +void pirq_cleanup_check(struct pirq *, struct domain *, int); + +#define pirq_cleanup_check(info, d, pirq) \ + ((info)->evtchn ? pirq_cleanup_check(info, d, pirq) : (void)0) + +extern void pirq_guest_eoi(struct domain *, struct pirq *); +extern void desc_guest_eoi(struct domain *, struct irq_desc *, struct = pirq *); extern int pirq_guest_unmask(struct domain *d); -extern int pirq_guest_bind(struct vcpu *v, int irq, int will_share); -extern void pirq_guest_unbind(struct domain *d, int irq); +extern int pirq_guest_bind(struct vcpu *, int pirq, struct pirq *, + int will_share); +extern void pirq_guest_unbind(struct domain *d, int pirq, struct pirq *); extern void pirq_set_affinity(struct domain *d, int irq, const cpumask_t = *); extern irq_desc_t *domain_spin_lock_irq_desc( struct domain *d, int irq, unsigned long *pflags); +extern irq_desc_t *pirq_spin_lock_irq_desc( + struct domain *, const struct pirq *, unsigned long *pflags); =20 static inline void set_native_irq_info(unsigned int irq, const cpumask_t = *mask) { --- 2011-04-29.orig/xen/include/xen/pci.h +++ 2011-04-29/xen/include/xen/pci.h @@ -117,8 +117,9 @@ int pci_find_cap_offset(u8 bus, u8 dev,=20 int pci_find_next_cap(u8 bus, unsigned int devfn, u8 pos, int cap); int pci_find_ext_capability(int seg, int bus, int devfn, int cap); =20 -int msixtbl_pt_register(struct domain *d, int pirq, uint64_t gtable); -void msixtbl_pt_unregister(struct domain *d, int pirq); +struct pirq; +int msixtbl_pt_register(struct domain *, struct pirq *, uint64_t gtable); +void msixtbl_pt_unregister(struct domain *, struct pirq *); void pci_enable_acs(struct pci_dev *pdev); =20 #endif /* __XEN_PCI_H__ */ --- 2011-04-29.orig/xen/include/xen/radix-tree.h +++ 2011-04-29/xen/include/xen/radix-tree.h @@ -72,6 +72,7 @@ void *radix_tree_delete(struct radix_tre void(*node_free)(struct radix_tree_node *)); unsigned int radix_tree_gang_lookup(struct radix_tree_root *root, void **results, - unsigned long first_index, unsigned int max_items);= + unsigned long first_index, unsigned int max_items, + unsigned long *indexes); =20 #endif /* _XEN_RADIX_TREE_H */ --- 2011-04-29.orig/xen/include/xen/sched.h +++ 2011-04-29/xen/include/xen/sched.h @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -234,13 +235,11 @@ struct domain struct grant_table *grant_table; =20 /* - * Interrupt to event-channel mappings. Updates should be protected = by the=20 - * domain's event-channel spinlock. Read accesses can also synchronise= on=20 - * the lock, but races don't usually matter. + * Interrupt to event-channel mappings and other per-guest-pirq data. + * Protected by the domain's event-channel spinlock. */ unsigned int nr_pirqs; - u16 *pirq_to_evtchn; - unsigned long *pirq_mask; + struct radix_tree_root pirq_tree; =20 /* I/O capabilities (access to IRQs and memory-mapped I/O). */ struct rangeset *iomem_caps; --=__Part7C50FC95.1__= Content-Type: text/plain; name="pirq-info-radix-tree.patch" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="pirq-info-radix-tree.patch" With this it is questionable whether retaining struct domain's nr_pirqs=0Ai= s actually necessary - the value now only serves for bounds checking,=0Aand= this boundary could easily be nr_irqs.=0A=0AAnother thing to consider is = whether it's worth storing the pirq number=0Ain struct pirq, to avoid = passing the number and a pointer to quite a=0Anumber of functions.=0A=0ANot= e that ia64, the build of which is broken currently anyway, is only=0Aparti= ally fixed up.=0A=0Av2: adjustments for split setup/teardown of translation= data=0A=0ASigned-off-by: Jan Beulich =0A=0A--- = 2011-04-29.orig/xen/arch/ia64/vmx/vmx_interrupt.c=0A+++ 2011-04-29/xen/arch= /ia64/vmx/vmx_interrupt.c=0A@@ -155,13 +155,13 @@ void hvm_isa_irq_deassert= (struct domain =0A /* dummy */=0A }=0A =0A-int msixtbl_pt_register(stru= ct domain *d, int pirq, uint64_t gtable)=0A+int msixtbl_pt_register(struct = domain *d, struct pirq *pirq, uint64_t gtable)=0A {=0A /* dummy */=0A = return -ENOSYS;=0A }=0A =0A-void msixtbl_pt_unregister(struct domain = *d, int pirq)=0A+void msixtbl_pt_unregister(struct domain *d, struct pirq = *pirq)=0A {=0A /* dummy */=0A }=0A--- 2011-04-29.orig/xen/arch/ia64/xen= /hypercall.c=0A+++ 2011-04-29/xen/arch/ia64/xen/hypercall.c=0A@@ -65,8 = +65,11 @@ static long __do_pirq_guest_eoi(struct d=0A {=0A if ( pirq = < 0 || pirq >=3D NR_IRQS )=0A return -EINVAL;=0A- if ( = d->arch.pirq_eoi_map )=0A- evtchn_unmask(d->pirq_to_evtchn[pir= q]);=0A+ if ( d->arch.pirq_eoi_map ) {=0A+ spin_lock(&= d->event_lock);=0A+ evtchn_unmask(pirq_to_evtchn(d, pirq));=0A+= spin_unlock(&d->event_lock);=0A+ }=0A return = pirq_guest_eoi(d, pirq);=0A }=0A =0A--- 2011-04-29.orig/xen/arch/ia64/xen/i= rq.c=0A+++ 2011-04-29/xen/arch/ia64/xen/irq.c=0A@@ -363,15 +363,17 @@ void = __do_IRQ_guest(int irq)=0A irq_desc_t *desc =3D &irq_desc[irq];= =0A irq_guest_action_t *action =3D (irq_guest_action_t *)desc->action;= =0A struct domain *d;=0A+ struct pirq *pirq;=0A int = i, already_pending =3D 0;=0A =0A for ( i =3D 0; i < = action->nr_guests; i++ )=0A {=0A d =3D action->guest[i];=0A+ = pirq =3D pirq_info(d, irq);=0A if ( (action->ack_type !=3D = ACKTYPE_NONE) &&=0A- !test_and_set_bit(irq, &d->pirq_mask) = )=0A+ !test_and_set_bool(pirq->masked) )=0A = action->in_flight++;=0A- if ( hvm_do_IRQ_dpci(d, irq) )=0A+ = if ( hvm_do_IRQ_dpci(d, pirq) )=0A {=0A = if ( action->ack_type =3D=3D ACKTYPE_NONE )=0A {=0A@@ = -379,7 +381,7 @@ void __do_IRQ_guest(int irq)=0A = desc->status |=3D IRQ_INPROGRESS; /* cleared during hvm eoi */=0A = }=0A }=0A- else if ( send_guest_pirq(d, irq) = &&=0A+ else if ( send_guest_pirq(d, pirq) &&=0A = (action->ack_type =3D=3D ACKTYPE_NONE) )=0A {=0A = already_pending++;=0A@@ -423,26 +425,23 @@ static int pirq_acktype(= int irq)=0A return ACKTYPE_NONE;=0A }=0A =0A-int pirq_guest_eoi(struct = domain *d, int irq)=0A+int pirq_guest_eoi(struct domain *d, struct pirq = *pirq)=0A {=0A irq_desc_t *desc;=0A irq_guest_action_t *action;=0A = =0A- if ( (irq < 0) || (irq >=3D NR_IRQS) )=0A- return = -EINVAL;=0A-=0A desc =3D &irq_desc[irq];=0A spin_lock_irq(&desc->lo= ck);=0A action =3D (irq_guest_action_t *)desc->action;=0A =0A if ( = action->ack_type =3D=3D ACKTYPE_NONE )=0A {=0A- ASSERT(!test_bit= (irq, d->pirq_mask));=0A+ ASSERT(!pirq->masked);=0A = stop_timer(&irq_guest_eoi_timer[irq]);=0A _irq_guest_eoi(desc);=0A = }=0A =0A- if ( test_and_clear_bit(irq, &d->pirq_mask) && (--action->= in_flight =3D=3D 0) )=0A+ if ( test_and_clear_bool(pirq->masked) && = (--action->in_flight =3D=3D 0) )=0A {=0A ASSERT(action->ack_typ= e =3D=3D ACKTYPE_UNMASK);=0A desc->handler->end(irq);=0A@@ -455,22 = +454,27 @@ int pirq_guest_eoi(struct domain *d, int=0A =0A int pirq_guest_u= nmask(struct domain *d)=0A {=0A- int irq;=0A+ unsigned = int pirq =3D 0, n, i;=0A+ unsigned long indexes[16];=0A+ struct pirq = *pirqs[ARRAY_SIZE(indexes)];=0A shared_info_t *s =3D d->shared_info;=0A= =0A- for ( irq =3D find_first_bit(d->pirq_mask, NR_IRQS);=0A- = irq < NR_IRQS;=0A- irq =3D find_next_bit(d->pirq_mask, NR_IRQS, = irq+1) )=0A- {=0A- if ( !test_bit(d->pirq_to_evtchn[irq], = &s->evtchn_mask[0]) )=0A- pirq_guest_eoi(d, irq);=0A-=0A- = }=0A+ do {=0A+ n =3D radix_tree_gang_lookup(&d->pirq_tree, (void = **)pirqs, pirq,=0A+ ARRAY_SIZE(pirqs), = indexes);=0A+ for ( i =3D 0; i < n; ++i )=0A+ {=0A+ = pirq =3D indexes[i];=0A+ if ( pirqs[i]->masked &&=0A+ = !test_bit(pirqs[i]->evtchn, &s->evtchn_mask[0]) )=0A+ = pirq_guest_eoi(d, pirqs[i]);=0A+ }=0A+ } while ( ++pirq < = d->nr_pirqs && n =3D=3D ARRAY_SIZE(pirqs) );=0A =0A return 0;=0A }=0A = =0A-int pirq_guest_bind(struct vcpu *v, int irq, int will_share)=0A+int = pirq_guest_bind(struct vcpu *v, int irq, struct pirq *pirq, int will_share)= =0A {=0A irq_desc_t *desc =3D &irq_desc[irq];=0A irq_guest_= action_t *action;=0A@@ -554,7 +558,7 @@ int pirq_guest_bind(struct vcpu = *v, int =0A return rc;=0A }=0A =0A-void pirq_guest_unbind(struct = domain *d, int irq)=0A+void pirq_guest_unbind(struct domain *d, int irq, = struct pirq *pirq)=0A {=0A irq_desc_t *desc =3D &irq_desc[irq];= =0A irq_guest_action_t *action;=0A@@ -572,7 +576,7 @@ void pirq_guest_u= nbind(struct domain *d,=0A action->nr_guests--;=0A =0A if ( = action->ack_type =3D=3D ACKTYPE_UNMASK )=0A- if ( test_and_clear_bit= (irq, &d->pirq_mask) &&=0A+ if ( test_and_clear_bool(pirq->masked) = &&=0A (--action->in_flight =3D=3D 0) )=0A = desc->handler->end(irq);=0A =0A--- 2011-04-29.orig/xen/arch/x86/domain.c=0A= +++ 2011-04-29/xen/arch/x86/domain.c=0A@@ -608,25 +608,9 @@ int arch_domain= _create(struct domain *d,=0A share_xen_page_with_guest(=0A = virt_to_page(d->shared_info), d, XENSHARE_writable);=0A =0A- = d->arch.pirq_irq =3D xmalloc_array(int, d->nr_pirqs);=0A- if ( = !d->arch.pirq_irq )=0A- goto fail;=0A- memset(d->arch.pir= q_irq, 0,=0A- d->nr_pirqs * sizeof(*d->arch.pirq_irq));=0A-= =0A if ( (rc =3D init_domain_irq_mapping(d)) !=3D 0 )=0A = goto fail;=0A =0A- if ( is_hvm_domain(d) )=0A- {=0A- = d->arch.pirq_emuirq =3D xmalloc_array(int, d->nr_pirqs);=0A- = if ( !d->arch.pirq_emuirq )=0A- goto fail;=0A- = for (i =3D 0; i < d->nr_pirqs; i++)=0A- d->arch.pirq_emuirq[= i] =3D IRQ_UNBOUND;=0A- }=0A-=0A-=0A if ( (rc =3D iommu_doma= in_init(d)) !=3D 0 )=0A goto fail;=0A =0A@@ -660,8 +644,6 @@ = int arch_domain_create(struct domain *d,=0A fail:=0A d->is_dying =3D = DOMDYING_dead;=0A vmce_destroy_msr(d);=0A- xfree(d->arch.pirq_irq);= =0A- xfree(d->arch.pirq_emuirq);=0A cleanup_domain_irq_mapping(d);= =0A free_xenheap_page(d->shared_info);=0A if ( paging_initialised = )=0A@@ -714,8 +696,6 @@ void arch_domain_destroy(struct domain *=0A = #endif=0A =0A free_xenheap_page(d->shared_info);=0A- xfree(d->arch.p= irq_irq);=0A- xfree(d->arch.pirq_emuirq);=0A cleanup_domain_irq_mapp= ing(d);=0A }=0A =0A--- 2011-04-29.orig/xen/arch/x86/hvm/hvm.c=0A+++ = 2011-04-29/xen/arch/x86/hvm/hvm.c=0A@@ -252,32 +252,36 @@ void hvm_migrate_= timers(struct vcpu *v)=0A pt_migrate(v);=0A }=0A =0A-void hvm_migrate_p= irqs(struct vcpu *v)=0A+static int hvm_migrate_pirq(struct domain *d, = unsigned int pirq,=0A+ struct hvm_pirq_dpci = *pirq_dpci, void *arg)=0A {=0A- int pirq, irq;=0A- struct irq_desc = *desc;=0A- struct domain *d =3D v->domain;=0A- struct hvm_irq_dpci = *hvm_irq_dpci =3D d->arch.hvm_domain.irq.dpci;=0A- =0A- if ( = !iommu_enabled || (hvm_irq_dpci =3D=3D NULL) )=0A- return;=0A+ = struct vcpu *v =3D arg;=0A =0A- spin_lock(&d->event_lock);=0A- for ( = pirq =3D find_first_bit(hvm_irq_dpci->mapping, d->nr_pirqs);=0A- = pirq < d->nr_pirqs;=0A- pirq =3D find_next_bit(hvm_irq_dpci->mappi= ng, d->nr_pirqs, pirq + 1) )=0A+ if ( (pirq_dpci->flags & HVM_IRQ_DPCI_M= ACH_MSI) &&=0A+ (pirq_dpci->gmsi.dest_vcpu_id =3D=3D v->vcpu_id) = )=0A {=0A- if ( !(hvm_irq_dpci->mirq[pirq].flags & HVM_IRQ_DPCI_= MACH_MSI) ||=0A- (hvm_irq_dpci->mirq[pirq].gmsi.dest_vcpu_id = !=3D v->vcpu_id) )=0A- continue;=0A- desc =3D domain_spin= _lock_irq_desc(v->domain, pirq, NULL);=0A- if (!desc)=0A- = continue;=0A- irq =3D desc - irq_desc;=0A- ASSERT(MSI_IRQ(ir= q));=0A+ struct irq_desc *desc =3D=0A+ pirq_spin_lock_irq= _desc(d, dpci_pirq(pirq_dpci), NULL);=0A+=0A+ if ( !desc )=0A+ = return 0;=0A+ ASSERT(MSI_IRQ(desc - irq_desc));=0A = irq_set_affinity(desc, cpumask_of(v->processor));=0A spin_unlock_ir= q(&desc->lock);=0A }=0A+=0A+ return 0;=0A+}=0A+=0A+void hvm_migrate_= pirqs(struct vcpu *v)=0A+{=0A+ struct domain *d =3D v->domain;=0A+=0A+ = if ( !iommu_enabled || !d->arch.hvm_domain.irq.dpci )=0A+ = return;=0A+=0A+ spin_lock(&d->event_lock);=0A+ pt_pirq_iterate(d, = hvm_migrate_pirq, v);=0A spin_unlock(&d->event_lock);=0A }=0A =0A@@ = -501,8 +505,6 @@ int hvm_domain_initialise(struct domain =0A return = rc;=0A }=0A =0A-extern void msixtbl_pt_cleanup(struct domain *d);=0A-=0A = void hvm_domain_relinquish_resources(struct domain *d)=0A {=0A = hvm_destroy_ioreq_page(d, &d->arch.hvm_domain.ioreq);=0A--- 2011-04-29.orig= /xen/arch/x86/hvm/irq.c=0A+++ 2011-04-29/xen/arch/x86/hvm/irq.c=0A@@ -33,7 = +33,7 @@ static void assert_irq(struct domain *d,=0A int pirq =3D = domain_emuirq_to_pirq(d, ioapic_gsi);=0A if ( pirq !=3D IRQ_UNBOUND = )=0A {=0A- send_guest_pirq(d, pirq);=0A+ send_guest_pirq(= d, pirq_info(d, pirq));=0A return;=0A }=0A vioapic_irq_posi= tive_edge(d, ioapic_gsi);=0A--- 2011-04-29.orig/xen/arch/x86/hvm/vmsi.c=0A+= ++ 2011-04-29/xen/arch/x86/hvm/vmsi.c=0A@@ -65,11 +65,10 @@ static void = vmsi_inj_irq(=0A }=0A }=0A =0A-int vmsi_deliver(struct domain *d, int = pirq)=0A+int vmsi_deliver(struct domain *d, const struct hvm_pirq_dpci = *pirq_dpci)=0A {=0A- struct hvm_irq_dpci *hvm_irq_dpci =3D d->arch.hvm_d= omain.irq.dpci;=0A- uint32_t flags =3D hvm_irq_dpci->mirq[pirq].gmsi.gfl= ags;=0A- int vector =3D hvm_irq_dpci->mirq[pirq].gmsi.gvec;=0A+ = uint32_t flags =3D pirq_dpci->gmsi.gflags;=0A+ int vector =3D pirq_dpci-= >gmsi.gvec;=0A uint8_t dest =3D (uint8_t)flags;=0A uint8_t = dest_mode =3D !!(flags & VMSI_DM_MASK);=0A uint8_t delivery_mode =3D = (flags & VMSI_DELIV_MASK) >> GLFAGS_SHIFT_DELIV_MODE;=0A@@ -82,11 +81,7 @@ = int vmsi_deliver(struct domain *d, int p=0A "vector=3D%x = trig_mode=3D%x\n",=0A dest, dest_mode, delivery_mode, = vector, trig_mode);=0A =0A- if ( !( hvm_irq_dpci->mirq[pirq].flags & = HVM_IRQ_DPCI_GUEST_MSI ) )=0A- {=0A- gdprintk(XENLOG_WARNING, = "pirq %x not msi \n", pirq);=0A- return 0;=0A- }=0A+ = ASSERT(pirq_dpci->flags & HVM_IRQ_DPCI_GUEST_MSI);=0A =0A switch ( = delivery_mode )=0A {=0A@@ -349,7 +344,7 @@ static void del_msixtbl_entr= y(struct msi=0A call_rcu(&entry->rcu, free_msixtbl_entry);=0A }=0A = =0A-int msixtbl_pt_register(struct domain *d, int pirq, uint64_t gtable)=0A= +int msixtbl_pt_register(struct domain *d, struct pirq *pirq, uint64_t = gtable)=0A {=0A struct irq_desc *irq_desc;=0A struct msi_desc = *msi_desc;=0A@@ -358,6 +353,7 @@ int msixtbl_pt_register(struct domain = *d=0A int r =3D -EINVAL;=0A =0A ASSERT(spin_is_locked(&pcidevs_lock= ));=0A+ ASSERT(spin_is_locked(&d->event_lock));=0A =0A /*=0A * = xmalloc() with irq_disabled causes the failure of check_lock() =0A@@ = -367,7 +363,7 @@ int msixtbl_pt_register(struct domain *d=0A if ( = !new_entry )=0A return -ENOMEM;=0A =0A- irq_desc =3D domain_spin= _lock_irq_desc(d, pirq, NULL);=0A+ irq_desc =3D pirq_spin_lock_irq_desc(= d, pirq, NULL);=0A if ( !irq_desc )=0A {=0A xfree(new_entry= );=0A@@ -404,7 +400,7 @@ out:=0A return r;=0A }=0A =0A-void msixtbl_pt_= unregister(struct domain *d, int pirq)=0A+void msixtbl_pt_unregister(struct= domain *d, struct pirq *pirq)=0A {=0A struct irq_desc *irq_desc;=0A = struct msi_desc *msi_desc;=0A@@ -412,8 +408,9 @@ void msixtbl_pt_unregist= er(struct domain=0A struct msixtbl_entry *entry;=0A =0A ASSERT(spin= _is_locked(&pcidevs_lock));=0A+ ASSERT(spin_is_locked(&d->event_lock));= =0A =0A- irq_desc =3D domain_spin_lock_irq_desc(d, pirq, NULL);=0A+ = irq_desc =3D pirq_spin_lock_irq_desc(d, pirq, NULL);=0A if ( !irq_desc = )=0A return;=0A =0A@@ -447,7 +444,7 @@ found:=0A spin_unlock_ir= q(&irq_desc->lock);=0A }=0A =0A-void msixtbl_pt_cleanup(struct domain *d, = int pirq)=0A+void msixtbl_pt_cleanup(struct domain *d)=0A {=0A struct = msixtbl_entry *entry, *temp;=0A unsigned long flags;=0A--- 2011-04-29.o= rig/xen/arch/x86/irq.c=0A+++ 2011-04-29/xen/arch/x86/irq.c=0A@@ -814,7 = +814,7 @@ static void irq_guest_eoi_timer_fn(void =0A {=0A = struct domain *d =3D action->guest[i];=0A unsigned int = pirq =3D domain_irq_to_pirq(d, irq);=0A- if ( test_and_clear_bit= (pirq, d->pirq_mask) )=0A+ if ( test_and_clear_bool(pirq_info(d,= pirq)->masked) )=0A action->in_flight--;=0A }=0A = }=0A@@ -874,11 +874,12 @@ static void __do_IRQ_guest(int irq)=0A =0A = for ( i =3D 0; i < action->nr_guests; i++ )=0A {=0A- unsigned = int pirq;=0A+ struct pirq *pirq;=0A+=0A d =3D action->guest[= i];=0A- pirq =3D domain_irq_to_pirq(d, irq);=0A+ pirq =3D = pirq_info(d, domain_irq_to_pirq(d, irq));=0A if ( (action->ack_type= !=3D ACKTYPE_NONE) &&=0A- !test_and_set_bit(pirq, d->pirq_mask= ) )=0A+ !test_and_set_bool(pirq->masked) )=0A = action->in_flight++;=0A if ( hvm_do_IRQ_dpci(d, pirq) )=0A = {=0A@@ -950,28 +951,71 @@ struct irq_desc *domain_spin_lock_irq_de=0A = return desc;=0A }=0A =0A-static int prepare_domain_irq_pirq(struct domain = *d, int irq, int pirq)=0A+/*=0A+ * Same with struct pirq already looked = up, and d->event_lock already=0A+ * held (thus the PIRQ <-> IRQ mapping = can't change under our feet).=0A+ */=0A+struct irq_desc *pirq_spin_lock_irq= _desc(=0A+ struct domain *d, const struct pirq *pirq, unsigned long = *pflags)=0A+{=0A+ int irq =3D pirq->arch.irq;=0A+ struct irq_desc = *desc;=0A+ unsigned long flags;=0A+=0A+ ASSERT(spin_is_locked(&d->eve= nt_lock));=0A+=0A+ if ( irq <=3D 0 )=0A+ return NULL;=0A+=0A+ = desc =3D irq_to_desc(irq);=0A+ spin_lock_irqsave(&desc->lock, flags);=0A= +=0A+ if ( pflags )=0A+ *pflags =3D flags;=0A+=0A+ ASSERT(pirq= =3D=3D pirq_info(d, domain_irq_to_pirq(d, irq)));=0A+ ASSERT(irq = =3D=3D pirq->arch.irq);=0A+=0A+ return desc;=0A+}=0A+=0A+static int = prepare_domain_irq_pirq(struct domain *d, int irq, int pirq,=0A+ = struct pirq **pinfo)=0A {=0A int err =3D = radix_tree_insert(&d->arch.irq_pirq, irq, NULL,=0A = NULL, NULL);=0A+ struct pirq *info;=0A =0A- return err !=3D = -EEXIST ? err : 0;=0A+ if ( err && err !=3D -EEXIST )=0A+ return = err;=0A+ info =3D pirq_get_info(d, pirq);=0A+ if ( !info )=0A+ = {=0A+ if ( !err )=0A+ radix_tree_delete(&d->arch.irq_pirq= , irq, NULL);=0A+ return -ENOMEM;=0A+ }=0A+ *pinfo =3D = info;=0A+ return 0;=0A }=0A =0A-static void set_domain_irq_pirq(struct = domain *d, int irq, int pirq)=0A+static void set_domain_irq_pirq(struct = domain *d, int irq, int pirq,=0A+ struct = pirq *info)=0A {=0A *radix_tree_lookup_slot(&d->arch.irq_pirq, irq) = =3D (void *)(long)pirq;=0A- d->arch.pirq_irq[pirq] =3D irq;=0A+ = info->arch.irq =3D irq;=0A }=0A =0A-static void clear_domain_irq_pirq(struc= t domain *d, int irq, int pirq)=0A+static void clear_domain_irq_pirq(struct= domain *d, int irq, struct pirq *pirq)=0A {=0A- d->arch.pirq_irq[pirq] = =3D 0;=0A+ pirq->arch.irq =3D 0;=0A *radix_tree_lookup_slot(&d->arch= .irq_pirq, irq) =3D NULL;=0A }=0A =0A-static void cleanup_domain_irq_pirq(s= truct domain *d, int irq, int pirq)=0A+static void cleanup_domain_irq_pirq(= struct domain *d, int irq, int pirq,=0A+ = struct pirq *info)=0A {=0A+ pirq_cleanup_check(info, d, pirq);=0A = radix_tree_delete(&d->arch.irq_pirq, irq, NULL);=0A }=0A =0A@@ -987,10 = +1031,12 @@ int init_domain_irq_mapping(struct domai=0A for ( i =3D 1; = platform_legacy_irq(i); ++i )=0A if ( !IO_APIC_IRQ(i) )=0A = {=0A- err =3D prepare_domain_irq_pirq(d, i, i);=0A+ = struct pirq *info;=0A+=0A+ err =3D prepare_domain_irq_pirq(d, = i, i, &info);=0A if ( err )=0A break;=0A- = set_domain_irq_pirq(d, i, i);=0A+ set_domain_irq_pirq(d, = i, i, info);=0A }=0A =0A return err;=0A@@ -1008,6 +1054,48 @@ = void cleanup_domain_irq_mapping(struct d=0A = irq_slot_free, NULL);=0A }=0A =0A+struct pirq *alloc_pirq_struct(struct = domain *d)=0A+{=0A+ size_t sz =3D is_hvm_domain(d) ? sizeof(struct = pirq) :=0A+ offsetof(struct pirq, = arch.hvm);=0A+ struct pirq *pirq =3D xmalloc_bytes(sz);=0A+=0A+ if ( = pirq )=0A+ {=0A+ memset(pirq, 0, sz);=0A+ if ( is_hvm_doma= in(d) )=0A+ {=0A+ pirq->arch.hvm.emuirq =3D IRQ_UNBOUND;= =0A+ pt_pirq_init(d, &pirq->arch.hvm.dpci);=0A+ }=0A+ = }=0A+=0A+ return pirq;=0A+}=0A+=0A+void (pirq_cleanup_check)(struct = pirq *info, struct domain *d, int pirq)=0A+{=0A+ /*=0A+ * Check = whether all fields have their default values, and delete=0A+ * the = entry from the tree if so.=0A+ *=0A+ * NB: Common parts were = already checked.=0A+ */=0A+ if ( info->arch.irq )=0A+ = return;=0A+=0A+ if ( is_hvm_domain(d) )=0A+ {=0A+ if ( = info->arch.hvm.emuirq !=3D IRQ_UNBOUND )=0A+ return;=0A+ = if ( !pt_pirq_cleanup_check(&info->arch.hvm.dpci) )=0A+ = return;=0A+ }=0A+=0A+ if ( radix_tree_delete(&d->pirq_tree, pirq, = NULL) !=3D info )=0A+ BUG();=0A+}=0A+=0A /* Flush all ready EOIs = from the top of this CPU's pending-EOI stack. */=0A static void flush_ready= _eoi(void)=0A {=0A@@ -1068,18 +1156,22 @@ static void set_eoi_ready(void = *data)=0A flush_ready_eoi();=0A }=0A =0A-static void __pirq_guest_eoi(s= truct domain *d, int pirq)=0A+void pirq_guest_eoi(struct domain *d, struct = pirq *pirq)=0A+{=0A+ struct irq_desc *desc;=0A+=0A+ ASSERT(local_irq_= is_enabled());=0A+ desc =3D pirq_spin_lock_irq_desc(d, pirq, NULL);=0A+ = if ( desc )=0A+ desc_guest_eoi(d, desc, pirq);=0A+}=0A+=0A+void = desc_guest_eoi(struct domain *d, struct irq_desc *desc, struct pirq = *pirq)=0A {=0A- struct irq_desc *desc;=0A irq_guest_action_t= *action;=0A cpumask_t cpu_eoi_map;=0A int = irq;=0A =0A- ASSERT(local_irq_is_enabled());=0A- desc =3D = domain_spin_lock_irq_desc(d, pirq, NULL);=0A- if ( desc =3D=3D NULL = )=0A- return;=0A-=0A if ( !(desc->status & IRQ_GUEST) )=0A = {=0A spin_unlock_irq(&desc->lock);=0A@@ -1091,12 +1183,12 @@ = static void __pirq_guest_eoi(struct doma=0A =0A if ( action->ack_type = =3D=3D ACKTYPE_NONE )=0A {=0A- ASSERT(!test_bit(pirq, d->pirq_ma= sk));=0A+ ASSERT(!pirq->masked);=0A stop_timer(&action->eoi_= timer);=0A _irq_guest_eoi(desc);=0A }=0A =0A- if ( = unlikely(!test_and_clear_bit(pirq, d->pirq_mask)) ||=0A+ if ( unlikely(!= test_and_clear_bool(pirq->masked)) ||=0A unlikely(--action->in_fli= ght !=3D 0) )=0A {=0A spin_unlock_irq(&desc->lock);=0A@@ = -1131,27 +1223,23 @@ static void __pirq_guest_eoi(struct doma=0A = on_selected_cpus(&cpu_eoi_map, set_eoi_ready, desc, 0);=0A }=0A =0A-int = pirq_guest_eoi(struct domain *d, int irq)=0A-{=0A- if ( (irq < 0) || = (irq >=3D d->nr_pirqs) )=0A- return -EINVAL;=0A-=0A- __pirq_guest= _eoi(d, irq);=0A-=0A- return 0;=0A-}=0A-=0A int pirq_guest_unmask(struct= domain *d)=0A {=0A- unsigned int irq, nr =3D d->nr_pirqs;=0A+ = unsigned int pirq =3D 0, n, i;=0A+ unsigned long indexes[16];=0A+ = struct pirq *pirqs[ARRAY_SIZE(indexes)];=0A =0A- for ( irq =3D = find_first_bit(d->pirq_mask, nr);=0A- irq < nr;=0A- irq = =3D find_next_bit(d->pirq_mask, nr, irq+1) )=0A- {=0A- if ( = !test_bit(d->pirq_to_evtchn[irq], &shared_info(d, evtchn_mask)) )=0A- = __pirq_guest_eoi(d, irq);=0A- }=0A+ do {=0A+ n =3D = radix_tree_gang_lookup(&d->pirq_tree, (void **)pirqs, pirq,=0A+ = ARRAY_SIZE(pirqs), indexes);=0A+ for ( i =3D = 0; i < n; ++i )=0A+ {=0A+ pirq =3D indexes[i];=0A+ = if ( pirqs[i]->masked &&=0A+ !test_bit(pirqs[i]->evtch= n, &shared_info(d, evtchn_mask)) )=0A+ pirq_guest_eoi(d, = pirqs[i]);=0A+ }=0A+ } while ( ++pirq < d->nr_pirqs && n =3D=3D = ARRAY_SIZE(pirqs) );=0A =0A return 0;=0A }=0A@@ -1221,7 +1309,7 @@ int = pirq_shared(struct domain *d, int pi=0A return shared;=0A }=0A =0A-int = pirq_guest_bind(struct vcpu *v, int pirq, int will_share)=0A+int pirq_guest= _bind(struct vcpu *v, int pirq, struct pirq *info, int will_share)=0A {=0A = unsigned int irq;=0A struct irq_desc *desc;=0A@@ = -1233,7 +1321,7 @@ int pirq_guest_bind(struct vcpu *v, int =0A = BUG_ON(!local_irq_is_enabled());=0A =0A retry:=0A- desc =3D domain_spin= _lock_irq_desc(v->domain, pirq, NULL);=0A+ desc =3D pirq_spin_lock_irq_d= esc(v->domain, info, NULL);=0A if ( desc =3D=3D NULL )=0A {=0A = rc =3D -EINVAL;=0A@@ -1334,7 +1422,7 @@ int pirq_guest_bind(struct = vcpu *v, int =0A }=0A =0A static irq_guest_action_t *__pirq_guest_unbind(= =0A- struct domain *d, int pirq, struct irq_desc *desc)=0A+ struct = domain *d, int pirq, struct pirq *info, struct irq_desc *desc)=0A {=0A = unsigned int irq;=0A irq_guest_action_t *action;=0A@@ -1363,13 = +1451,13 @@ static irq_guest_action_t *__pirq_guest_=0A switch ( = action->ack_type )=0A {=0A case ACKTYPE_UNMASK:=0A- if ( = test_and_clear_bit(pirq, d->pirq_mask) &&=0A+ if ( test_and_clear_bo= ol(info->masked) &&=0A (--action->in_flight =3D=3D 0) )=0A = desc->handler->end(irq);=0A break;=0A case ACKTYPE_EOI= :=0A /* NB. If #guests =3D=3D 0 then we clear the eoi_map later = on. */=0A- if ( test_and_clear_bit(pirq, d->pirq_mask) &&=0A+ = if ( test_and_clear_bool(info->masked) &&=0A (--action->in_fl= ight =3D=3D 0) &&=0A (action->nr_guests !=3D 0) )=0A = {=0A@@ -1387,9 +1475,9 @@ static irq_guest_action_t *__pirq_guest_=0A =0A = /*=0A * The guest cannot re-bind to this IRQ until this function = returns. So,=0A- * when we have flushed this IRQ from pirq_mask, it = should remain flushed.=0A+ * when we have flushed this IRQ from = ->masked, it should remain flushed.=0A */=0A- BUG_ON(test_bit(pirq,= d->pirq_mask));=0A+ BUG_ON(info->masked);=0A =0A if ( action->nr_gu= ests !=3D 0 )=0A return NULL;=0A@@ -1427,7 +1515,7 @@ static = irq_guest_action_t *__pirq_guest_=0A return action;=0A }=0A =0A-void = pirq_guest_unbind(struct domain *d, int pirq)=0A+void pirq_guest_unbind(str= uct domain *d, int pirq, struct pirq *info)=0A {=0A irq_guest_action_t = *oldaction =3D NULL;=0A struct irq_desc *desc;=0A@@ -1436,19 +1524,19 = @@ void pirq_guest_unbind(struct domain *d,=0A WARN_ON(!spin_is_locked(= &d->event_lock));=0A =0A BUG_ON(!local_irq_is_enabled());=0A- desc = =3D domain_spin_lock_irq_desc(d, pirq, NULL);=0A+ desc =3D pirq_spin_loc= k_irq_desc(d, info, NULL);=0A =0A if ( desc =3D=3D NULL )=0A {=0A- = irq =3D -domain_pirq_to_irq(d, pirq);=0A+ irq =3D -info->arch= .irq;=0A BUG_ON(irq <=3D 0);=0A desc =3D irq_to_desc(irq);= =0A spin_lock_irq(&desc->lock);=0A- clear_domain_irq_pirq(d,= irq, pirq);=0A+ clear_domain_irq_pirq(d, irq, info);=0A }=0A = else=0A {=0A- oldaction =3D __pirq_guest_unbind(d, pirq, = desc);=0A+ oldaction =3D __pirq_guest_unbind(d, pirq, info, = desc);=0A }=0A =0A spin_unlock_irq(&desc->lock);=0A@@ -1459,10 = +1547,10 @@ void pirq_guest_unbind(struct domain *d,=0A xfree(oldac= tion);=0A }=0A else if ( irq > 0 )=0A- cleanup_domain_irq_pi= rq(d, irq, pirq);=0A+ cleanup_domain_irq_pirq(d, irq, pirq, = info);=0A }=0A =0A-static int pirq_guest_force_unbind(struct domain *d, = int irq)=0A+static int pirq_guest_force_unbind(struct domain *d, int irq, = struct pirq *info)=0A {=0A struct irq_desc *desc;=0A irq_guest_acti= on_t *action, *oldaction =3D NULL;=0A@@ -1471,7 +1559,7 @@ static int = pirq_guest_force_unbind(struc=0A WARN_ON(!spin_is_locked(&d->event_lock= ));=0A =0A BUG_ON(!local_irq_is_enabled());=0A- desc =3D domain_spin= _lock_irq_desc(d, irq, NULL);=0A+ desc =3D pirq_spin_lock_irq_desc(d, = info, NULL);=0A BUG_ON(desc =3D=3D NULL);=0A =0A if ( !(desc->statu= s & IRQ_GUEST) )=0A@@ -1491,7 +1579,7 @@ static int pirq_guest_force_unbind= (struc=0A goto out;=0A =0A bound =3D 1;=0A- oldaction =3D = __pirq_guest_unbind(d, irq, desc);=0A+ oldaction =3D __pirq_guest_unbind= (d, irq, info, desc);=0A =0A out:=0A spin_unlock_irq(&desc->lock);=0A@= @ -1505,6 +1593,13 @@ static int pirq_guest_force_unbind(struc=0A = return bound;=0A }=0A =0A+static inline bool_t is_free_pirq(const struct = domain *d,=0A+ const struct pirq = *pirq)=0A+{=0A+ return !pirq || (!pirq->arch.irq && (!is_hvm_domain(d) = ||=0A+ pirq->arch.hvm.emuirq =3D=3D IRQ_UNBOUND));=0A+}=0A+=0A int = get_free_pirq(struct domain *d, int type, int index)=0A {=0A int = i;=0A@@ -1514,29 +1609,17 @@ int get_free_pirq(struct domain *d, int =0A = if ( type =3D=3D MAP_PIRQ_TYPE_GSI )=0A {=0A for ( i =3D 16; = i < nr_irqs_gsi; i++ )=0A- if ( !d->arch.pirq_irq[i] )=0A- = {=0A- if ( !is_hvm_domain(d) ||=0A- = d->arch.pirq_emuirq[i] =3D=3D IRQ_UNBOUND )=0A- = break;=0A- }=0A- if ( i =3D=3D nr_irqs_gsi )=0A- = return -ENOSPC;=0A+ if ( is_free_pirq(d, pirq_info(d, i)) = )=0A+ return i;=0A }=0A else=0A {=0A = for ( i =3D d->nr_pirqs - 1; i >=3D nr_irqs_gsi; i-- )=0A- if ( = !d->arch.pirq_irq[i] )=0A- {=0A- if ( !is_hvm_dom= ain(d) ||=0A- d->arch.pirq_emuirq[i] =3D=3D = IRQ_UNBOUND )=0A- break;=0A- }=0A- if = ( i < nr_irqs_gsi )=0A- return -ENOSPC;=0A+ if ( = is_free_pirq(d, pirq_info(d, i)) )=0A+ return i;=0A = }=0A =0A- return i;=0A+ return -ENOSPC;=0A }=0A =0A int map_domain_pi= rq(=0A@@ -1544,6 +1627,7 @@ int map_domain_pirq(=0A {=0A int ret =3D = 0;=0A int old_irq, old_pirq;=0A+ struct pirq *info;=0A struct = irq_desc *desc;=0A unsigned long flags;=0A struct msi_desc = *msi_desc;=0A@@ -1583,7 +1667,7 @@ int map_domain_pirq(=0A return = ret;=0A }=0A =0A- ret =3D prepare_domain_irq_pirq(d, irq, pirq);=0A+= ret =3D prepare_domain_irq_pirq(d, irq, pirq, &info);=0A if ( ret = )=0A return ret;=0A =0A@@ -1608,20 +1692,20 @@ int map_domain_pirq(= =0A dprintk(XENLOG_G_ERR, "dom%d: irq %d in use\n",=0A = d->domain_id, irq);=0A desc->handler =3D &pci_msi_type;=0A- = set_domain_irq_pirq(d, irq, pirq);=0A+ set_domain_irq_pirq(d, = irq, pirq, info);=0A setup_msi_irq(pdev, msi_desc, irq);=0A = spin_unlock_irqrestore(&desc->lock, flags);=0A }=0A else=0A = {=0A spin_lock_irqsave(&desc->lock, flags);=0A- set_domain_i= rq_pirq(d, irq, pirq);=0A+ set_domain_irq_pirq(d, irq, pirq, = info);=0A spin_unlock_irqrestore(&desc->lock, flags);=0A }=0A = =0A done:=0A if ( ret )=0A- cleanup_domain_irq_pirq(d, irq, = pirq);=0A+ cleanup_domain_irq_pirq(d, irq, pirq, info);=0A = return ret;=0A }=0A =0A@@ -1632,6 +1716,7 @@ int unmap_domain_pirq(struct = domain *d, =0A struct irq_desc *desc;=0A int irq, ret =3D 0;=0A = bool_t forced_unbind;=0A+ struct pirq *info;=0A struct msi_desc = *msi_desc =3D NULL;=0A =0A if ( (pirq < 0) || (pirq >=3D d->nr_pirqs) = )=0A@@ -1640,8 +1725,8 @@ int unmap_domain_pirq(struct domain *d, =0A = ASSERT(spin_is_locked(&pcidevs_lock));=0A ASSERT(spin_is_locked(&d->eve= nt_lock));=0A =0A- irq =3D domain_pirq_to_irq(d, pirq);=0A- if ( irq = <=3D 0 )=0A+ info =3D pirq_info(d, pirq);=0A+ if ( !info || (irq =3D = info->arch.irq) <=3D 0 )=0A {=0A dprintk(XENLOG_G_ERR, "dom%d: = pirq %d not mapped\n",=0A d->domain_id, pirq);=0A@@ = -1649,7 +1734,7 @@ int unmap_domain_pirq(struct domain *d, =0A = goto done;=0A }=0A =0A- forced_unbind =3D pirq_guest_force_unbind(d,= pirq);=0A+ forced_unbind =3D pirq_guest_force_unbind(d, pirq, = info);=0A if ( forced_unbind )=0A dprintk(XENLOG_G_WARNING, = "dom%d: forcing unbind of pirq %d\n",=0A d->domain_id, = pirq);=0A@@ -1664,10 +1749,10 @@ int unmap_domain_pirq(struct domain *d, = =0A BUG_ON(irq !=3D domain_pirq_to_irq(d, pirq));=0A =0A if ( = !forced_unbind )=0A- clear_domain_irq_pirq(d, irq, pirq);=0A+ = clear_domain_irq_pirq(d, irq, info);=0A else=0A {=0A- = d->arch.pirq_irq[pirq] =3D -irq;=0A+ info->arch.irq =3D -irq;=0A = *radix_tree_lookup_slot(&d->arch.irq_pirq, irq) =3D (void *)(long)-pir= q;=0A }=0A =0A@@ -1676,7 +1761,7 @@ int unmap_domain_pirq(struct = domain *d, =0A msi_free_irq(msi_desc);=0A =0A if ( !forced_unbi= nd )=0A- cleanup_domain_irq_pirq(d, irq, pirq);=0A+ = cleanup_domain_irq_pirq(d, irq, pirq, info);=0A =0A ret =3D irq_deny_ac= cess(d, pirq);=0A if ( ret )=0A@@ -1698,7 +1783,7 @@ void free_domain_p= irqs(struct domain *d)=0A spin_lock(&d->event_lock);=0A =0A for ( = i =3D 0; i < d->nr_pirqs; i++ )=0A- if ( d->arch.pirq_irq[i] > 0 = )=0A+ if ( domain_pirq_to_irq(d, i) > 0 )=0A unmap_domai= n_pirq(d, i);=0A =0A spin_unlock(&d->event_lock);=0A@@ -1714,6 +1799,7 = @@ static void dump_irqs(unsigned char key)=0A struct irq_cfg *cfg;=0A = irq_guest_action_t *action;=0A struct domain *d;=0A+ const = struct pirq *info;=0A unsigned long flags;=0A =0A printk("Guest = interrupt information:\n");=0A@@ -1748,20 +1834,18 @@ static void = dump_irqs(unsigned char key)=0A {=0A d =3D = action->guest[i];=0A pirq =3D domain_irq_to_pirq(d, = irq);=0A+ info =3D pirq_info(d, pirq);=0A = printk("%u:%3d(%c%c%c%c)",=0A d->domain_id, = pirq,=0A- (test_bit(d->pirq_to_evtchn[pirq],=0A+ = (test_bit(info->evtchn,=0A = &shared_info(d, evtchn_pending)) ?=0A 'P' : = '-'),=0A- (test_bit(d->pirq_to_evtchn[pirq] /=0A- = BITS_PER_EVTCHN_WORD(d),=0A+ = (test_bit(info->evtchn / BITS_PER_EVTCHN_WORD(d),=0A = &vcpu_info(d->vcpu[0], evtchn_pending_sel)) ?=0A = 'S' : '-'),=0A- (test_bit(d->pirq_to_ev= tchn[pirq],=0A- &shared_info(d, evtchn_mask= )) ?=0A+ (test_bit(info->evtchn, &shared_info(d, = evtchn_mask)) ?=0A 'M' : '-'),=0A- = (test_bit(pirq, d->pirq_mask) ?=0A- 'M' : = '-'));=0A+ (info->masked ? 'M' : '-'));=0A = if ( i !=3D action->nr_guests )=0A printk(",");= =0A }=0A@@ -1868,6 +1952,7 @@ void fixup_irqs(void)=0A int = map_domain_emuirq_pirq(struct domain *d, int pirq, int emuirq)=0A {=0A = int old_emuirq =3D IRQ_UNBOUND, old_pirq =3D IRQ_UNBOUND;=0A+ struct = pirq *info;=0A =0A ASSERT(spin_is_locked(&d->event_lock));=0A =0A@@ = -1894,6 +1979,10 @@ int map_domain_emuirq_pirq(struct domain=0A = return 0;=0A }=0A =0A+ info =3D pirq_get_info(d, pirq);=0A+ if ( = !info )=0A+ return -ENOMEM;=0A+=0A /* do not store emuirq = mappings for pt devices */=0A if ( emuirq !=3D IRQ_PT )=0A {=0A@@ = -1909,10 +1998,11 @@ int map_domain_emuirq_pirq(struct domain=0A = (void *)((long)pirq + 1);=0A break;=0A = default:=0A+ pirq_cleanup_check(info, d, pirq);=0A = return err;=0A }=0A }=0A- d->arch.pirq_emuirq[pirq] =3D = emuirq;=0A+ info->arch.hvm.emuirq =3D emuirq;=0A =0A return 0;=0A = }=0A@@ -1920,6 +2010,7 @@ int map_domain_emuirq_pirq(struct domain=0A int = unmap_domain_pirq_emuirq(struct domain *d, int pirq)=0A {=0A int = emuirq, ret =3D 0;=0A+ struct pirq *info;=0A =0A if ( !is_hvm_domain= (d) )=0A return -EINVAL;=0A@@ -1938,7 +2029,12 @@ int unmap_domain_= pirq_emuirq(struct doma=0A goto done;=0A }=0A =0A- = d->arch.pirq_emuirq[pirq] =3D IRQ_UNBOUND;=0A+ info =3D pirq_info(d, = pirq);=0A+ if ( info )=0A+ {=0A+ info->arch.hvm.emuirq =3D = IRQ_UNBOUND;=0A+ pirq_cleanup_check(info, d, pirq);=0A+ }=0A = if ( emuirq !=3D IRQ_PT )=0A radix_tree_delete(&d->arch.hvm_domain.= emuirq_pirq, emuirq, NULL);=0A =0A@@ -1946,16 +2042,9 @@ int unmap_domain_p= irq_emuirq(struct doma=0A return ret;=0A }=0A =0A-int hvm_domain_use_pi= rq(struct domain *d, int pirq)=0A+bool_t hvm_domain_use_pirq(const struct = domain *d, const struct pirq *pirq)=0A {=0A- int emuirq;=0A- =0A- = if ( !is_hvm_domain(d) )=0A- return 0;=0A-=0A- emuirq =3D = domain_pirq_to_emuirq(d, pirq);=0A- if ( emuirq !=3D IRQ_UNBOUND && = d->pirq_to_evtchn[pirq] !=3D 0 )=0A- return 1;=0A- else=0A- = return 0;=0A+ return is_hvm_domain(d) &&=0A+ pirq->arch.hvm.= emuirq !=3D IRQ_UNBOUND &&=0A+ pirq->evtchn !=3D 0;=0A }=0A--- = 2011-04-29.orig/xen/arch/x86/physdev.c=0A+++ 2011-04-29/xen/arch/x86/physde= v.c=0A@@ -258,20 +258,28 @@ ret_t do_physdev_op(int cmd, XEN_GUEST_H=0A = {=0A case PHYSDEVOP_eoi: {=0A struct physdev_eoi eoi;=0A+ = struct pirq *pirq;=0A+=0A ret =3D -EFAULT;=0A if ( = copy_from_guest(&eoi, arg, 1) !=3D 0 )=0A break;=0A = ret =3D -EINVAL;=0A if ( eoi.irq >=3D v->domain->nr_pirqs )=0A = break;=0A+ spin_lock(&v->domain->event_lock);=0A+ = pirq =3D pirq_info(v->domain, eoi.irq);=0A+ if ( !pirq ) {=0A+ = spin_unlock(&v->domain->event_lock);=0A+ break;=0A+ = }=0A if ( !is_hvm_domain(v->domain) &&=0A v->domain->= arch.pv_domain.pirq_eoi_map )=0A- evtchn_unmask(v->domain->pirq_= to_evtchn[eoi.irq]);=0A+ evtchn_unmask(pirq->evtchn);=0A = if ( !is_hvm_domain(v->domain) ||=0A- domain_pirq_to_emuirq(v-= >domain, eoi.irq) =3D=3D IRQ_PT )=0A- ret =3D pirq_guest_eoi(v->= domain, eoi.irq);=0A- else=0A- ret =3D 0;=0A+ = pirq->arch.hvm.emuirq =3D=3D IRQ_PT )=0A+ pirq_guest_eoi(v->dom= ain, pirq);=0A+ spin_unlock(&v->domain->event_lock);=0A+ ret = =3D 0;=0A break;=0A }=0A =0A@@ -564,11 +572,23 @@ ret_t = do_physdev_op(int cmd, XEN_GUEST_H=0A break;=0A =0A = spin_lock(&d->event_lock);=0A- out.pirq =3D get_free_pirq(d, = out.type, 0);=0A- d->arch.pirq_irq[out.pirq] =3D PIRQ_ALLOCATED;=0A+= ret =3D get_free_pirq(d, out.type, 0);=0A+ if ( ret >=3D 0 = )=0A+ {=0A+ struct pirq *info =3D pirq_get_info(d, = ret);=0A+=0A+ if ( info )=0A+ info->arch.irq =3D = PIRQ_ALLOCATED;=0A+ else=0A+ ret =3D -ENOMEM;=0A+= }=0A spin_unlock(&d->event_lock);=0A =0A- ret =3D = copy_to_guest(arg, &out, 1) ? -EFAULT : 0;=0A+ if ( ret >=3D 0 = )=0A+ {=0A+ out.pirq =3D ret;=0A+ ret =3D = copy_to_guest(arg, &out, 1) ? -EFAULT : 0;=0A+ }=0A =0A = rcu_unlock_domain(d);=0A break;=0A--- 2011-04-29.orig/xen/common/do= main.c=0A+++ 2011-04-29/xen/common/domain.c=0A@@ -290,13 +290,7 @@ struct = domain *domain_create(=0A if ( d->nr_pirqs > nr_irqs )=0A = d->nr_pirqs =3D nr_irqs;=0A =0A- d->pirq_to_evtchn =3D xmalloc_ar= ray(u16, d->nr_pirqs);=0A- d->pirq_mask =3D xmalloc_array(=0A- = unsigned long, BITS_TO_LONGS(d->nr_pirqs));=0A- if ( = (d->pirq_to_evtchn =3D=3D NULL) || (d->pirq_mask =3D=3D NULL) )=0A- = goto fail;=0A- memset(d->pirq_to_evtchn, 0, d->nr_pirqs * = sizeof(*d->pirq_to_evtchn));=0A- bitmap_zero(d->pirq_mask, = d->nr_pirqs);=0A+ INIT_RADIX_TREE(&d->pirq_tree, 0);=0A =0A = if ( evtchn_init(d) !=3D 0 )=0A goto fail;=0A@@ -346,6 +340,7 = @@ struct domain *domain_create(=0A {=0A evtchn_destroy(d);=0A = evtchn_destroy_final(d);=0A+ radix_tree_destroy(&d->pirq_tre= e, free_pirq_struct, NULL);=0A }=0A if ( init_status & INIT_rangese= t )=0A rangeset_domain_destroy(d);=0A@@ -353,8 +348,6 @@ struct = domain *domain_create(=0A watchdog_domain_destroy(d);=0A if ( = init_status & INIT_xsm )=0A xsm_free_security_domain(d);=0A- = xfree(d->pirq_mask);=0A- xfree(d->pirq_to_evtchn);=0A free_cpumask_v= ar(d->domain_dirty_cpumask);=0A free_domain_struct(d);=0A return = NULL;=0A@@ -680,8 +673,7 @@ static void complete_domain_destroy(stru=0A = =0A evtchn_destroy_final(d);=0A =0A- xfree(d->pirq_mask);=0A- = xfree(d->pirq_to_evtchn);=0A+ radix_tree_destroy(&d->pirq_tree, = free_pirq_struct, NULL);=0A =0A xsm_free_security_domain(d);=0A = free_cpumask_var(d->domain_dirty_cpumask);=0A@@ -963,6 +955,20 @@ long = vm_assist(struct domain *p, unsigne=0A return -ENOSYS;=0A }=0A = =0A+struct pirq *pirq_get_info(struct domain *d, int pirq)=0A+{=0A+ = struct pirq *info =3D pirq_info(d, pirq);=0A+=0A+ if ( !info && (info = =3D alloc_pirq_struct(d)) !=3D NULL &&=0A+ radix_tree_insert(&d->pi= rq_tree, pirq, info, NULL, NULL) )=0A+ {=0A+ free_pirq_struct(in= fo);=0A+ info =3D NULL;=0A+ }=0A+=0A+ return info;=0A+}=0A+= =0A struct migrate_info {=0A long (*func)(void *data);=0A void = *data;=0A--- 2011-04-29.orig/xen/common/event_channel.c=0A+++ 2011-04-29/xe= n/common/event_channel.c=0A@@ -325,6 +325,7 @@ static long evtchn_bind_pirq= (evtchn_bind=0A struct evtchn *chn;=0A struct domain *d =3D = current->domain;=0A struct vcpu *v =3D d->vcpu[0];=0A+ struct = pirq *info;=0A int port, pirq =3D bind->pirq;=0A long = rc;=0A =0A@@ -336,7 +337,7 @@ static long evtchn_bind_pirq(evtchn= _bind=0A =0A spin_lock(&d->event_lock);=0A =0A- if ( d->pirq_to_evtc= hn[pirq] !=3D 0 )=0A+ if ( pirq_to_evtchn(d, pirq) !=3D 0 )=0A = ERROR_EXIT(-EEXIST);=0A =0A if ( (port =3D get_free_port(d)) < 0 = )=0A@@ -344,14 +345,18 @@ static long evtchn_bind_pirq(evtchn_bind=0A =0A = chn =3D evtchn_from_port(d, port);=0A =0A- d->pirq_to_evtchn[pirq] = =3D port;=0A+ info =3D pirq_get_info(d, pirq);=0A+ if ( !info )=0A+ = ERROR_EXIT(-ENOMEM);=0A+ info->evtchn =3D port;=0A rc =3D = (!is_hvm_domain(d)=0A- ? pirq_guest_bind(=0A- v, = pirq, !!(bind->flags & BIND_PIRQ__WILL_SHARE))=0A+ ? pirq_guest_bi= nd(v, pirq, info,=0A+ !!(bind->flags & = BIND_PIRQ__WILL_SHARE))=0A : 0);=0A if ( rc !=3D 0 )=0A = {=0A- d->pirq_to_evtchn[pirq] =3D 0;=0A+ info->evtchn =3D = 0;=0A+ pirq_cleanup_check(info, d, pirq);=0A goto out;=0A = }=0A =0A@@ -404,12 +409,18 @@ static long __evtchn_close(struct = domain=0A case ECS_UNBOUND:=0A break;=0A =0A- case = ECS_PIRQ:=0A+ case ECS_PIRQ: {=0A+ struct pirq *pirq =3D = pirq_info(d1, chn1->u.pirq.irq);=0A+=0A+ if ( !pirq )=0A+ = break;=0A if ( !is_hvm_domain(d1) )=0A- pirq_guest_unbi= nd(d1, chn1->u.pirq.irq);=0A- d1->pirq_to_evtchn[chn1->u.pirq.irq] = =3D 0;=0A+ pirq_guest_unbind(d1, chn1->u.pirq.irq, pirq);=0A+ = pirq->evtchn =3D 0;=0A+ pirq_cleanup_check(pirq, d1, chn1->u.pi= rq.irq);=0A unlink_pirq_port(chn1, d1->vcpu[chn1->notify_vcpu_id]);= =0A break;=0A+ }=0A =0A case ECS_VIRQ:=0A for_each_v= cpu ( d1, v )=0A@@ -659,9 +670,9 @@ void send_guest_global_virq(struct = domai=0A spin_unlock_irqrestore(&v->virq_lock, flags);=0A }=0A =0A-int = send_guest_pirq(struct domain *d, int pirq)=0A+int send_guest_pirq(struct = domain *d, const struct pirq *pirq)=0A {=0A- int port =3D d->pirq_to_evt= chn[pirq];=0A+ int port;=0A struct evtchn *chn;=0A =0A /*=0A@@ = -670,7 +681,7 @@ int send_guest_pirq(struct domain *d, in=0A * HVM = guests: Port is legitimately zero when the guest disables the=0A * = emulated interrupt/evtchn.=0A */=0A- if ( port =3D=3D 0 )=0A+ = if ( pirq =3D=3D NULL || (port =3D pirq->evtchn) =3D=3D 0 )=0A {=0A = BUG_ON(!is_hvm_domain(d));=0A return 0;=0A@@ -812,13 +823,10 = @@ int evtchn_unmask(unsigned int port)=0A struct domain *d =3D = current->domain;=0A struct vcpu *v;=0A =0A- spin_lock(&d->event_lo= ck);=0A+ ASSERT(spin_is_locked(&d->event_lock));=0A =0A if ( = unlikely(!port_is_valid(d, port)) )=0A- {=0A- spin_unlock(&d->eve= nt_lock);=0A return -EINVAL;=0A- }=0A =0A v =3D d->vcpu[evtc= hn_from_port(d, port)->notify_vcpu_id];=0A =0A@@ -834,8 +842,6 @@ int = evtchn_unmask(unsigned int port)=0A vcpu_mark_events_pending(v);=0A= }=0A =0A- spin_unlock(&d->event_lock);=0A-=0A return 0;=0A = }=0A =0A@@ -960,7 +966,9 @@ long do_event_channel_op(int cmd, XEN_GU=0A = struct evtchn_unmask unmask;=0A if ( copy_from_guest(&unmask, = arg, 1) !=3D 0 )=0A return -EFAULT;=0A+ spin_lock(&curre= nt->domain->event_lock);=0A rc =3D evtchn_unmask(unmask.port);=0A+ = spin_unlock(¤t->domain->event_lock);=0A break;=0A = }=0A =0A--- 2011-04-29.orig/xen/common/radix-tree.c=0A+++ 2011-04-29/xen/co= mmon/radix-tree.c=0A@@ -225,7 +225,8 @@ EXPORT_SYMBOL(radix_tree_lookup);= =0A =0A static unsigned int=0A __lookup(struct radix_tree_root *root, void = **results, unsigned long index,=0A- unsigned int max_items, = unsigned long *next_index)=0A+ unsigned int max_items, unsigned = long *indexes,=0A+ unsigned long *next_index)=0A {=0A unsigned = int nr_found =3D 0;=0A unsigned int shift, height;=0A@@ -235,8 +236,11 = @@ __lookup(struct radix_tree_root *root, v=0A height =3D root->height;= =0A if (index > radix_tree_maxindex(height))=0A if (height = =3D=3D 0) {=0A- if (root->rnode && index =3D=3D 0)=0A+ = if (root->rnode && index =3D=3D 0) {=0A+ if (indexes)=0A+ = indexes[nr_found] =3D index;=0A = results[nr_found++] =3D root->rnode;=0A+ }=0A goto = out;=0A }=0A =0A@@ -265,6 +269,8 @@ __lookup(struct radix_tree_root= *root, v=0A for (i =3D index & RADIX_TREE_MAP_MASK; i < RADIX_TREE_MAP= _SIZE; i++) {=0A index++;=0A if (slot->slots[i]) {=0A+ = if (indexes)=0A+ indexes[nr_found] =3D index - 1;=0A = results[nr_found++] =3D slot->slots[i];=0A if = (nr_found =3D=3D max_items)=0A goto out;=0A@@ -281,6 = +287,7 @@ __lookup(struct radix_tree_root *root, v=0A * @results: where = the results of the lookup are placed=0A * @first_index: start the lookup = from this key=0A * @max_items: place up to this many items at *results=0A+= * @indexes: (optional) array to store indexes of items.=0A *=0A * = Performs an index-ascending scan of the tree for present items. Places=0A = * them at *@results and returns the number of items which were placed = at=0A@@ -290,7 +297,8 @@ __lookup(struct radix_tree_root *root, v=0A = */=0A unsigned int=0A radix_tree_gang_lookup(struct radix_tree_root *root, = void **results,=0A- unsigned long first_index, = unsigned int max_items)=0A+ unsigned long first_index= , unsigned int max_items,=0A+ unsigned long = *indexes)=0A {=0A const unsigned long max_index =3D radix_tree_maxindex= (root->height);=0A unsigned long cur_index =3D first_index;=0A@@ = -303,7 +311,7 @@ radix_tree_gang_lookup(struct radix_tree=0A if = (cur_index > max_index)=0A break;=0A nr_found =3D = __lookup(root, results + ret, cur_index,=0A- = max_items - ret, &next_index);=0A+ max_items - = ret, indexes + ret, &next_index);=0A ret +=3D nr_found;=0A = if (next_index =3D=3D 0)=0A break;=0A--- 2011-04-29.orig/xen/dr= ivers/passthrough/io.c=0A+++ 2011-04-29/xen/drivers/passthrough/io.c=0A@@ = -35,18 +35,28 @@ bool_t pt_irq_need_timer(uint32_t flags)=0A return = !(flags & (HVM_IRQ_DPCI_GUEST_MSI | HVM_IRQ_DPCI_TRANSLATE));=0A }=0A = =0A+static int pt_irq_guest_eoi(struct domain *d, unsigned int pirq,=0A+ = struct hvm_pirq_dpci *pirq_dpci, void *arg)=0A+{= =0A+ if ( __test_and_clear_bit(_HVM_IRQ_DPCI_EOI_LATCH_SHIFT,=0A+ = &pirq_dpci->flags) )=0A+ {=0A+ pirq_dpci->= masked =3D 0;=0A+ pirq_dpci->pending =3D 0;=0A+ pirq_guest_eo= i(d, dpci_pirq(pirq_dpci));=0A+ }=0A+=0A+ return 0;=0A+}=0A+=0A = static void pt_irq_time_out(void *data)=0A {=0A- struct hvm_mirq_dpci_ma= pping *irq_map =3D data;=0A- unsigned int guest_gsi, machine_gsi =3D = 0;=0A+ struct hvm_pirq_dpci *irq_map =3D data;=0A+ unsigned int = guest_gsi;=0A struct hvm_irq_dpci *dpci =3D NULL;=0A struct = dev_intx_gsi_link *digl;=0A struct hvm_girq_dpci_mapping *girq;=0A = uint32_t device, intx;=0A- unsigned int nr_pirqs =3D irq_map->dom->nr_pi= rqs;=0A- DECLARE_BITMAP(machine_gsi_map, nr_pirqs);=0A-=0A- = bitmap_zero(machine_gsi_map, nr_pirqs);=0A =0A spin_lock(&irq_map->dom-= >event_lock);=0A =0A@@ -57,32 +67,18 @@ static void pt_irq_time_out(void = *data)=0A guest_gsi =3D digl->gsi;=0A list_for_each_entry = ( girq, &dpci->girq[guest_gsi], list )=0A {=0A- = machine_gsi =3D girq->machine_gsi;=0A- set_bit(machine_gsi, = machine_gsi_map);=0A+ struct pirq *pirq =3D pirq_info(irq_map->d= om, girq->machine_gsi);=0A+=0A+ pirq_dpci(pirq)->flags |=3D = HVM_IRQ_DPCI_EOI_LATCH;=0A }=0A device =3D digl->device;=0A= intx =3D digl->intx;=0A hvm_pci_intx_deassert(irq_map->dom= , device, intx);=0A }=0A =0A- for ( machine_gsi =3D find_first_bit(m= achine_gsi_map, nr_pirqs);=0A- machine_gsi < nr_pirqs;=0A- = machine_gsi =3D find_next_bit(machine_gsi_map, nr_pirqs,=0A- = machine_gsi + 1) )=0A- {=0A- clear_bit(m= achine_gsi, dpci->dirq_mask);=0A- dpci->mirq[machine_gsi].pending = =3D 0;=0A- }=0A+ pt_pirq_iterate(irq_map->dom, pt_irq_guest_eoi, = NULL);=0A =0A spin_unlock(&irq_map->dom->event_lock);=0A-=0A- for ( = machine_gsi =3D find_first_bit(machine_gsi_map, nr_pirqs);=0A- = machine_gsi < nr_pirqs;=0A- machine_gsi =3D find_next_bit(machine_= gsi_map, nr_pirqs,=0A- machine_gsi + = 1) )=0A- {=0A- pirq_guest_eoi(irq_map->dom, machine_gsi);=0A- = }=0A }=0A =0A struct hvm_irq_dpci *domain_get_irq_dpci(const struct domain = *d)=0A@@ -95,10 +91,6 @@ struct hvm_irq_dpci *domain_get_irq_dpci=0A =0A = void free_hvm_irq_dpci(struct hvm_irq_dpci *dpci)=0A {=0A- xfree(dpci->m= irq);=0A- xfree(dpci->dirq_mask);=0A- xfree(dpci->mapping);=0A- = xfree(dpci->hvm_timer);=0A xfree(dpci);=0A }=0A =0A@@ -106,7 +98,9 @@ = int pt_irq_create_bind_vtd(=0A struct domain *d, xen_domctl_bind_pt_irq= _t *pt_irq_bind)=0A {=0A struct hvm_irq_dpci *hvm_irq_dpci =3D = NULL;=0A- uint32_t machine_gsi, guest_gsi;=0A+ struct hvm_pirq_dpci = *pirq_dpci;=0A+ struct pirq *info;=0A+ uint32_t guest_gsi;=0A = uint32_t device, intx, link;=0A struct dev_intx_gsi_link *digl;=0A = struct hvm_girq_dpci_mapping *girq;=0A@@ -129,63 +123,45 @@ int pt_irq_crea= te_bind_vtd(=0A memset(hvm_irq_dpci, 0, sizeof(*hvm_irq_dpci));=0A = tasklet_init(&hvm_irq_dpci->dirq_tasklet,=0A = hvm_dirq_assist, (unsigned long)d);=0A- hvm_irq_dpci->mirq =3D = xmalloc_array(struct hvm_mirq_dpci_mapping,=0A- = d->nr_pirqs);=0A- hvm_irq_dpci->dirq_mask =3D = xmalloc_array(unsigned long,=0A- = BITS_TO_LONGS(d->nr_pirqs));=0A- hvm_irq_dpci->mapping =3D = xmalloc_array(unsigned long,=0A- = BITS_TO_LONGS(d->nr_pirqs));=0A- hvm_irq_dpci->hvm_timer =3D = xmalloc_array(struct timer, d->nr_pirqs);=0A- if ( !hvm_irq_dpci->mi= rq ||=0A- !hvm_irq_dpci->dirq_mask ||=0A- = !hvm_irq_dpci->mapping ||=0A- !hvm_irq_dpci->hvm_timer)=0A- = {=0A- spin_unlock(&d->event_lock);=0A- free_hvm_i= rq_dpci(hvm_irq_dpci);=0A- return -ENOMEM;=0A- }=0A- = memset(hvm_irq_dpci->mirq, 0,=0A- d->nr_pirqs * sizeof(*hv= m_irq_dpci->mirq));=0A- bitmap_zero(hvm_irq_dpci->dirq_mask, = d->nr_pirqs);=0A- bitmap_zero(hvm_irq_dpci->mapping, d->nr_pirqs);= =0A- memset(hvm_irq_dpci->hvm_timer, 0,=0A- = d->nr_pirqs * sizeof(*hvm_irq_dpci->hvm_timer));=0A- for ( int i = =3D 0; i < d->nr_pirqs; i++ ) {=0A- INIT_LIST_HEAD(&hvm_irq_dpci= ->mirq[i].digl_list);=0A- hvm_irq_dpci->mirq[i].gmsi.dest_vcpu_i= d =3D -1;=0A- }=0A for ( int i =3D 0; i < NR_HVM_IRQS; i++ = )=0A INIT_LIST_HEAD(&hvm_irq_dpci->girq[i]);=0A =0A = d->arch.hvm_domain.irq.dpci =3D hvm_irq_dpci;=0A }=0A =0A+ info =3D = pirq_get_info(d, pirq);=0A+ if ( !info )=0A+ {=0A+ spin_unlock= (&d->event_lock);=0A+ return -ENOMEM;=0A+ }=0A+ pirq_dpci =3D = pirq_dpci(info);=0A+=0A if ( pt_irq_bind->irq_type =3D=3D PT_IRQ_TYPE_M= SI )=0A {=0A uint8_t dest, dest_mode;=0A int dest_vcpu_= id;=0A =0A- if ( !test_and_set_bit(pirq, hvm_irq_dpci->mapping))=0A+= if ( !(pirq_dpci->flags & HVM_IRQ_DPCI_MAPPED) )=0A {=0A- = hvm_irq_dpci->mirq[pirq].flags =3D HVM_IRQ_DPCI_MACH_MSI |=0A- = HVM_IRQ_DPCI_GUEST_MSI;=0A- = hvm_irq_dpci->mirq[pirq].gmsi.gvec =3D pt_irq_bind->u.msi.gvec;=0A- = hvm_irq_dpci->mirq[pirq].gmsi.gflags =3D pt_irq_bind->u.msi.gflag= s;=0A+ pirq_dpci->flags =3D HVM_IRQ_DPCI_MAPPED | HVM_IRQ_DPCI_M= ACH_MSI |=0A+ HVM_IRQ_DPCI_GUEST_MSI;=0A+ = pirq_dpci->gmsi.gvec =3D pt_irq_bind->u.msi.gvec;=0A+ = pirq_dpci->gmsi.gflags =3D pt_irq_bind->u.msi.gflags;=0A /* = bind after hvm_irq_dpci is setup to avoid race with irq handler*/=0A- = rc =3D pirq_guest_bind(d->vcpu[0], pirq, 0);=0A+ rc =3D = pirq_guest_bind(d->vcpu[0], pirq, info, 0);=0A if ( rc =3D=3D = 0 && pt_irq_bind->u.msi.gtable )=0A {=0A- rc = =3D msixtbl_pt_register(d, pirq, pt_irq_bind->u.msi.gtable);=0A+ = rc =3D msixtbl_pt_register(d, info, pt_irq_bind->u.msi.gtable);=0A = if ( unlikely(rc) )=0A- pirq_guest_unbind(d= , pirq);=0A+ pirq_guest_unbind(d, pirq, info);=0A = }=0A if ( unlikely(rc) )=0A {=0A- = hvm_irq_dpci->mirq[pirq].gmsi.gflags =3D 0;=0A- = hvm_irq_dpci->mirq[pirq].gmsi.gvec =3D 0;=0A- hvm_irq_dpci->= mirq[pirq].flags =3D 0;=0A- clear_bit(pirq, hvm_irq_dpci->ma= pping);=0A+ pirq_dpci->gmsi.gflags =3D 0;=0A+ = pirq_dpci->gmsi.gvec =3D 0;=0A+ pirq_dpci->flags =3D = 0;=0A+ pirq_cleanup_check(info, d, pirq);=0A = spin_unlock(&d->event_lock);=0A return rc;=0A = }=0A@@ -194,34 +170,33 @@ int pt_irq_create_bind_vtd(=0A {=0A = uint32_t mask =3D HVM_IRQ_DPCI_MACH_MSI | HVM_IRQ_DPCI_GUEST_MSI;=0A= =0A- if ( (hvm_irq_dpci->mirq[pirq].flags & mask) !=3D = mask)=0A+ if ( (pirq_dpci->flags & mask) !=3D mask)=0A = {=0A spin_unlock(&d->event_lock);=0A = return -EBUSY;=0A }=0A =0A /* if pirq is already = mapped as vmsi, update the guest data/addr */=0A- if ( = hvm_irq_dpci->mirq[pirq].gmsi.gvec !=3D pt_irq_bind->u.msi.gvec ||=0A- = hvm_irq_dpci->mirq[pirq].gmsi.gflags !=3D pt_irq_bind->u.msi= .gflags) {=0A+ if ( pirq_dpci->gmsi.gvec !=3D pt_irq_bind->u.msi= .gvec ||=0A+ pirq_dpci->gmsi.gflags !=3D pt_irq_bind->u.msi= .gflags) {=0A /* Directly clear pending EOIs before = enabling new MSI info. */=0A- pirq_guest_eoi(d, pirq);=0A+ = pirq_guest_eoi(d, info);=0A =0A- hvm_irq_dpci-= >mirq[pirq].gmsi.gvec =3D pt_irq_bind->u.msi.gvec;=0A- = hvm_irq_dpci->mirq[pirq].gmsi.gflags =3D pt_irq_bind->u.msi.gflags;=0A+ = pirq_dpci->gmsi.gvec =3D pt_irq_bind->u.msi.gvec;=0A+ = pirq_dpci->gmsi.gflags =3D pt_irq_bind->u.msi.gflags;=0A = }=0A }=0A /* Caculate dest_vcpu_id for MSI-type pirq = migration */=0A- dest =3D hvm_irq_dpci->mirq[pirq].gmsi.gflags & = VMSI_DEST_ID_MASK;=0A- dest_mode =3D !!(hvm_irq_dpci->mirq[pirq].gms= i.gflags & VMSI_DM_MASK);=0A+ dest =3D pirq_dpci->gmsi.gflags & = VMSI_DEST_ID_MASK;=0A+ dest_mode =3D !!(pirq_dpci->gmsi.gflags & = VMSI_DM_MASK);=0A dest_vcpu_id =3D hvm_girq_dest_2_vcpu_id(d, = dest, dest_mode);=0A- hvm_irq_dpci->mirq[pirq].gmsi.dest_vcpu_id = =3D dest_vcpu_id;=0A+ pirq_dpci->gmsi.dest_vcpu_id =3D dest_vcpu_id;= =0A spin_unlock(&d->event_lock);=0A if ( dest_vcpu_id >=3D = 0 )=0A hvm_migrate_pirqs(d->vcpu[dest_vcpu_id]);=0A }=0A = else=0A {=0A- machine_gsi =3D pt_irq_bind->machine_irq;=0A = device =3D pt_irq_bind->u.pci.device;=0A intx =3D pt_irq_bind-= >u.pci.intx;=0A guest_gsi =3D hvm_pci_intx_gsi(device, intx);=0A@@ = -247,50 +222,51 @@ int pt_irq_create_bind_vtd(=0A digl->intx =3D = intx;=0A digl->gsi =3D guest_gsi;=0A digl->link =3D = link;=0A- list_add_tail(&digl->list,=0A- = &hvm_irq_dpci->mirq[machine_gsi].digl_list);=0A+ list_add_tail(&digl= ->list, &pirq_dpci->digl_list);=0A =0A girq->device =3D device;=0A = girq->intx =3D intx;=0A- girq->machine_gsi =3D machine_gsi;= =0A+ girq->machine_gsi =3D pirq;=0A list_add_tail(&girq->lis= t, &hvm_irq_dpci->girq[guest_gsi]);=0A =0A /* Bind the same mirq = once in the same domain */=0A- if ( !test_and_set_bit(machine_gsi, = hvm_irq_dpci->mapping))=0A+ if ( !(pirq_dpci->flags & HVM_IRQ_DPCI_M= APPED) )=0A {=0A unsigned int share;=0A =0A- = hvm_irq_dpci->mirq[machine_gsi].dom =3D d;=0A+ pirq_dpci->dom = =3D d;=0A if ( pt_irq_bind->irq_type =3D=3D PT_IRQ_TYPE_MSI_TRA= NSLATE )=0A {=0A- hvm_irq_dpci->mirq[machine_gsi= ].flags =3D HVM_IRQ_DPCI_MACH_MSI |=0A- = HVM_IRQ_DPCI_GUEST_PCI |=0A- = HVM_IRQ_DPCI_TRANSLATE;=0A+ = pirq_dpci->flags =3D HVM_IRQ_DPCI_MAPPED |=0A+ = HVM_IRQ_DPCI_MACH_MSI |=0A+ = HVM_IRQ_DPCI_GUEST_PCI |=0A+ HVM_IRQ_DPCI= _TRANSLATE;=0A share =3D 0;=0A }=0A = else /* PT_IRQ_TYPE_PCI */=0A {=0A- = hvm_irq_dpci->mirq[machine_gsi].flags =3D HVM_IRQ_DPCI_MACH_PCI |=0A- = HVM_IRQ_DPCI_GUEST_PCI;= =0A+ pirq_dpci->flags =3D HVM_IRQ_DPCI_MAPPED |=0A+ = HVM_IRQ_DPCI_MACH_PCI |=0A+ = HVM_IRQ_DPCI_GUEST_PCI;=0A share =3D = BIND_PIRQ__WILL_SHARE;=0A }=0A =0A /* Init timer = before binding */=0A- if ( pt_irq_need_timer(hvm_irq_dpci->mirq[= machine_gsi].flags) )=0A- init_timer(&hvm_irq_dpci->hvm_time= r[machine_gsi],=0A- pt_irq_time_out, &hvm_irq_dpc= i->mirq[machine_gsi], 0);=0A+ if ( pt_irq_need_timer(pirq_dpci->= flags) )=0A+ init_timer(&pirq_dpci->timer, pt_irq_time_out, = pirq_dpci, 0);=0A /* Deal with gsi for legacy devices */=0A- = rc =3D pirq_guest_bind(d->vcpu[0], machine_gsi, share);=0A+ = rc =3D pirq_guest_bind(d->vcpu[0], pirq, info, share);=0A = if ( unlikely(rc) )=0A {=0A- if ( pt_irq_need_ti= mer(hvm_irq_dpci->mirq[machine_gsi].flags) )=0A- = kill_timer(&hvm_irq_dpci->hvm_timer[machine_gsi]);=0A- = hvm_irq_dpci->mirq[machine_gsi].dom =3D NULL;=0A- clear_bit(= machine_gsi, hvm_irq_dpci->mapping);=0A+ if ( pt_irq_need_ti= mer(pirq_dpci->flags) )=0A+ kill_timer(&pirq_dpci->timer= );=0A+ pirq_dpci->dom =3D NULL;=0A = list_del(&girq->list);=0A xfree(girq);=0A = list_del(&digl->list);=0A hvm_irq_dpci->link_cnt[link]--;= =0A+ pirq_dpci->flags =3D 0;=0A+ pirq_cleanup= _check(info, d, pirq);=0A spin_unlock(&d->event_lock);=0A = xfree(digl);=0A return rc;=0A@@ -302,7 = +278,7 @@ int pt_irq_create_bind_vtd(=0A if ( iommu_verbose )=0A = dprintk(VTDPREFIX,=0A "d%d: bind: m_gsi=3D%u = g_gsi=3D%u device=3D%u intx=3D%u\n",=0A- d->domain_id, = machine_gsi, guest_gsi, device, intx);=0A+ d->domain_id,= pirq, guest_gsi, device, intx);=0A }=0A return 0;=0A }=0A@@ = -311,11 +287,12 @@ int pt_irq_destroy_bind_vtd(=0A struct domain *d, = xen_domctl_bind_pt_irq_t *pt_irq_bind)=0A {=0A struct hvm_irq_dpci = *hvm_irq_dpci =3D NULL;=0A+ struct hvm_pirq_dpci *pirq_dpci;=0A = uint32_t machine_gsi, guest_gsi;=0A uint32_t device, intx, link;=0A- = struct list_head *digl_list, *tmp;=0A- struct dev_intx_gsi_link = *digl;=0A+ struct dev_intx_gsi_link *digl, *tmp;=0A struct = hvm_girq_dpci_mapping *girq;=0A+ struct pirq *pirq;=0A =0A = machine_gsi =3D pt_irq_bind->machine_irq;=0A device =3D pt_irq_bind->u.= pci.device;=0A@@ -350,14 +327,14 @@ int pt_irq_destroy_bind_vtd(=0A = }=0A }=0A =0A+ pirq =3D pirq_info(d, machine_gsi);=0A+ = pirq_dpci =3D pirq_dpci(pirq);=0A+=0A /* clear the mirq info */=0A- = if ( test_bit(machine_gsi, hvm_irq_dpci->mapping))=0A+ if ( pirq_dpci = && (pirq_dpci->flags & HVM_IRQ_DPCI_MAPPED) )=0A {=0A- = list_for_each_safe ( digl_list, tmp,=0A- &hvm_irq_dpci->mirq= [machine_gsi].digl_list )=0A+ list_for_each_entry_safe ( digl, tmp, = &pirq_dpci->digl_list, list )=0A {=0A- digl =3D = list_entry(digl_list,=0A- struct dev_intx_gsi_link, = list);=0A if ( digl->device =3D=3D device &&=0A = digl->intx =3D=3D intx &&=0A digl->link =3D=3D link = &&=0A@@ -368,15 +345,15 @@ int pt_irq_destroy_bind_vtd(=0A = }=0A }=0A =0A- if ( list_empty(&hvm_irq_dpci->mirq[machine_g= si].digl_list) )=0A+ if ( list_empty(&pirq_dpci->digl_list) )=0A = {=0A- pirq_guest_unbind(d, machine_gsi);=0A- = msixtbl_pt_unregister(d, machine_gsi);=0A- if ( pt_irq_need_time= r(hvm_irq_dpci->mirq[machine_gsi].flags) )=0A- kill_timer(&h= vm_irq_dpci->hvm_timer[machine_gsi]);=0A- hvm_irq_dpci->mirq[mac= hine_gsi].dom =3D NULL;=0A- hvm_irq_dpci->mirq[machine_gsi].fl= ags =3D 0;=0A- clear_bit(machine_gsi, hvm_irq_dpci->mapping);=0A= + pirq_guest_unbind(d, machine_gsi, pirq);=0A+ = msixtbl_pt_unregister(d, pirq);=0A+ if ( pt_irq_need_timer(pirq_= dpci->flags) )=0A+ kill_timer(&pirq_dpci->timer);=0A+ = pirq_dpci->dom =3D NULL;=0A+ pirq_dpci->flags =3D 0;=0A+ = pirq_cleanup_check(pirq, d, machine_gsi);=0A }=0A = }=0A spin_unlock(&d->event_lock);=0A@@ -389,120 +366,156 @@ int = pt_irq_destroy_bind_vtd(=0A return 0;=0A }=0A =0A-int hvm_do_IRQ_dpci(s= truct domain *d, unsigned int mirq)=0A+void pt_pirq_init(struct domain *d, = struct hvm_pirq_dpci *dpci)=0A+{=0A+ INIT_LIST_HEAD(&dpci->digl_list);= =0A+ dpci->gmsi.dest_vcpu_id =3D -1;=0A+}=0A+=0A+bool_t pt_pirq_cleanup_= check(struct hvm_pirq_dpci *dpci)=0A+{=0A+ return !dpci->flags;=0A+}=0A+= =0A+int pt_pirq_iterate(struct domain *d,=0A+ int = (*cb)(struct domain *, unsigned int,=0A+ = struct hvm_pirq_dpci *, void *),=0A+ void *arg)=0A+{=0A+= int rc =3D 0;=0A+ unsigned int pirq =3D 0, n, i;=0A+ unsigned = long indexes[8];=0A+ struct pirq *pirqs[ARRAY_SIZE(indexes)];=0A+=0A+ = ASSERT(spin_is_locked(&d->event_lock));=0A+=0A+ do {=0A+ n =3D = radix_tree_gang_lookup(&d->pirq_tree, (void **)pirqs, pirq,=0A+ = ARRAY_SIZE(pirqs), indexes);=0A+ for ( i =3D = 0; i < n; ++i )=0A+ {=0A+ struct hvm_pirq_dpci *pirq_dpci= =3D pirq_dpci(pirqs[i]);=0A+=0A+ pirq =3D indexes[i];=0A+ = if ( (pirq_dpci->flags & HVM_IRQ_DPCI_MAPPED) )=0A+ = rc =3D cb(d, pirq, pirq_dpci, arg);=0A+ }=0A+ } while ( !rc && = ++pirq < d->nr_pirqs && n =3D=3D ARRAY_SIZE(pirqs) );=0A+=0A+ return = rc;=0A+}=0A+=0A+int hvm_do_IRQ_dpci(struct domain *d, struct pirq = *pirq)=0A {=0A struct hvm_irq_dpci *dpci =3D domain_get_irq_dpci(d);=0A= + struct hvm_pirq_dpci *pirq_dpci =3D pirq_dpci(pirq);=0A =0A- = ASSERT(spin_is_locked(&irq_desc[domain_pirq_to_irq(d, mirq)].lock));=0A- = if ( !iommu_enabled || !dpci || !test_bit(mirq, dpci->mapping))=0A+ if = ( !iommu_enabled || !dpci || !pirq_dpci ||=0A+ !(pirq_dpci->flags = & HVM_IRQ_DPCI_MAPPED) )=0A return 0;=0A =0A- set_bit(mirq, = dpci->dirq_mask);=0A+ pirq_dpci->masked =3D 1;=0A tasklet_schedule(&= dpci->dirq_tasklet);=0A return 1;=0A }=0A =0A #ifdef SUPPORT_MSI_REMAPP= ING=0A /* called with d->event_lock held */=0A-static void __msi_pirq_eoi(s= truct domain *d, int pirq)=0A+static void __msi_pirq_eoi(struct domain *d, = struct hvm_pirq_dpci *pirq_dpci)=0A {=0A- struct hvm_irq_dpci *hvm_irq_d= pci =3D d->arch.hvm_domain.irq.dpci;=0A irq_desc_t *desc;=0A =0A- = if ( ( pirq >=3D 0 ) && ( pirq < d->nr_pirqs ) &&=0A- test_bit(pirq= , hvm_irq_dpci->mapping) &&=0A- ( hvm_irq_dpci->mirq[pirq].flags & = HVM_IRQ_DPCI_MACH_MSI) )=0A+ if ( (pirq_dpci->flags & HVM_IRQ_DPCI_MAPPE= D) &&=0A+ (pirq_dpci->flags & HVM_IRQ_DPCI_MACH_MSI) )=0A = {=0A+ struct pirq *pirq =3D dpci_pirq(pirq_dpci);=0A+=0A = BUG_ON(!local_irq_is_enabled());=0A- desc =3D domain_spin_lock_irq_= desc(d, pirq, NULL);=0A+ desc =3D pirq_spin_lock_irq_desc(d, pirq, = NULL);=0A if ( !desc )=0A return;=0A =0A = desc->status &=3D ~IRQ_INPROGRESS;=0A- spin_unlock_irq(&desc->lock)= ;=0A+ desc_guest_eoi(d, desc, pirq);=0A+ }=0A+}=0A =0A- = pirq_guest_eoi(d, pirq);=0A+static int _hvm_dpci_msi_eoi(struct domain *d, = unsigned int pirq,=0A+ struct hvm_pirq_dpci = *pirq_dpci, void *arg)=0A+{=0A+ int vector =3D (long)arg;=0A+=0A+ if = ( (pirq_dpci->flags & HVM_IRQ_DPCI_MACH_MSI) &&=0A+ (pirq_dpci->gms= i.gvec =3D=3D vector) )=0A+ {=0A+ int dest =3D pirq_dpci->gmsi.gf= lags & VMSI_DEST_ID_MASK;=0A+ int dest_mode =3D !!(pirq_dpci->gmsi.g= flags & VMSI_DM_MASK);=0A+=0A+ if ( vlapic_match_dest(vcpu_vlapic(cu= rrent), NULL, 0, dest,=0A+ dest_mode) )=0A+ = {=0A+ __msi_pirq_eoi(d, pirq_dpci);=0A+ return = 1;=0A+ }=0A }=0A+=0A+ return 0;=0A }=0A =0A void hvm_dpci_msi= _eoi(struct domain *d, int vector)=0A {=0A- int pirq, dest, dest_mode;= =0A- struct hvm_irq_dpci *hvm_irq_dpci =3D d->arch.hvm_domain.irq.dpci;= =0A-=0A- if ( !iommu_enabled || (hvm_irq_dpci =3D=3D NULL) )=0A+ if = ( !iommu_enabled || !d->arch.hvm_domain.irq.dpci )=0A return;=0A = =0A spin_lock(&d->event_lock);=0A- for ( pirq =3D find_first_bit(hvm= _irq_dpci->mapping, d->nr_pirqs);=0A- pirq < d->nr_pirqs;=0A- = pirq =3D find_next_bit(hvm_irq_dpci->mapping, d->nr_pirqs, pirq + 1) = )=0A- {=0A- if ( (!(hvm_irq_dpci->mirq[pirq].flags & HVM_IRQ_DPCI= _MACH_MSI)) ||=0A- (hvm_irq_dpci->mirq[pirq].gmsi.gvec !=3D = vector) )=0A- continue;=0A-=0A- dest =3D hvm_irq_dpci->mi= rq[pirq].gmsi.gflags & VMSI_DEST_ID_MASK;=0A- dest_mode =3D = !!(hvm_irq_dpci->mirq[pirq].gmsi.gflags & VMSI_DM_MASK);=0A- if ( = vlapic_match_dest(vcpu_vlapic(current), NULL, 0, dest, dest_mode) )=0A- = break;=0A- }=0A- if ( pirq < d->nr_pirqs )=0A- = __msi_pirq_eoi(d, pirq);=0A+ pt_pirq_iterate(d, _hvm_dpci_msi_eoi, = (void *)(long)vector);=0A spin_unlock(&d->event_lock);=0A }=0A = =0A-extern int vmsi_deliver(struct domain *d, int pirq);=0A-static int = hvm_pci_msi_assert(struct domain *d, int pirq)=0A+static int hvm_pci_msi_as= sert(struct domain *d,=0A+ struct hvm_pirq_dpc= i *pirq_dpci)=0A {=0A+ struct pirq *pirq =3D dpci_pirq(pirq_dpci);=0A+= =0A if ( hvm_domain_use_pirq(d, pirq) )=0A return send_guest_pi= rq(d, pirq);=0A else=0A- return vmsi_deliver(d, pirq);=0A+ = return vmsi_deliver(d, pirq_dpci);=0A }=0A #endif=0A =0A-static void = hvm_dirq_assist(unsigned long _d)=0A+static int _hvm_dirq_assist(struct = domain *d, unsigned int pirq,=0A+ struct = hvm_pirq_dpci *pirq_dpci, void *arg)=0A {=0A- unsigned int pirq;=0A = uint32_t device, intx;=0A- struct domain *d =3D (struct domain = *)_d;=0A- struct hvm_irq_dpci *hvm_irq_dpci =3D d->arch.hvm_domain.irq.d= pci;=0A struct dev_intx_gsi_link *digl;=0A =0A- ASSERT(hvm_irq_dpci)= ;=0A-=0A- for ( pirq =3D find_first_bit(hvm_irq_dpci->dirq_mask, = d->nr_pirqs);=0A- pirq < d->nr_pirqs;=0A- pirq =3D = find_next_bit(hvm_irq_dpci->dirq_mask, d->nr_pirqs, pirq + 1) )=0A+ if = ( test_and_clear_bool(pirq_dpci->masked) )=0A {=0A- if ( = !test_and_clear_bit(pirq, hvm_irq_dpci->dirq_mask) )=0A- = continue;=0A-=0A- spin_lock(&d->event_lock);=0A #ifdef SUPPORT_MSI_R= EMAPPING=0A- if ( hvm_irq_dpci->mirq[pirq].flags & HVM_IRQ_DPCI_GUES= T_MSI )=0A+ if ( pirq_dpci->flags & HVM_IRQ_DPCI_GUEST_MSI )=0A = {=0A- hvm_pci_msi_assert(d, pirq);=0A- spin_unloc= k(&d->event_lock);=0A- continue;=0A+ hvm_pci_msi_asse= rt(d, pirq_dpci);=0A+ return 0;=0A }=0A #endif=0A- = list_for_each_entry ( digl, &hvm_irq_dpci->mirq[pirq].digl_list, list = )=0A+ list_for_each_entry ( digl, &pirq_dpci->digl_list, list )=0A = {=0A+ struct pirq *info =3D dpci_pirq(pirq_dpci);=0A+=0A = device =3D digl->device;=0A intx =3D digl->intx;=0A= - if ( hvm_domain_use_pirq(d, pirq) )=0A- = send_guest_pirq(d, pirq);=0A+ if ( hvm_domain_use_pirq(d, info) = )=0A+ send_guest_pirq(d, info);=0A else=0A = hvm_pci_intx_assert(d, device, intx);=0A- hvm_irq_dpc= i->mirq[pirq].pending++;=0A+ pirq_dpci->pending++;=0A =0A = #ifdef SUPPORT_MSI_REMAPPING=0A- if ( hvm_irq_dpci->mirq[pirq].f= lags & HVM_IRQ_DPCI_TRANSLATE )=0A+ if ( pirq_dpci->flags & = HVM_IRQ_DPCI_TRANSLATE )=0A {=0A /* for = translated MSI to INTx interrupt, eoi as early as possible */=0A- = __msi_pirq_eoi(d, pirq);=0A+ __msi_pirq_eoi(d, = pirq_dpci);=0A }=0A #endif=0A }=0A@@ -514,37 +527,50 = @@ static void hvm_dirq_assist(unsigned lon=0A * guest will never = deal with the irq, then the physical interrupt line=0A * will = never be deasserted.=0A */=0A- if ( pt_irq_need_timer(hvm_i= rq_dpci->mirq[pirq].flags) )=0A- set_timer(&hvm_irq_dpci->hvm_ti= mer[pirq],=0A- NOW() + PT_IRQ_TIME_OUT);=0A- = spin_unlock(&d->event_lock);=0A+ if ( pt_irq_need_timer(pirq_dpci->f= lags) )=0A+ set_timer(&pirq_dpci->timer, NOW() + PT_IRQ_TIME_OUT= );=0A }=0A+=0A+ return 0;=0A+}=0A+=0A+static void hvm_dirq_assist(un= signed long _d)=0A+{=0A+ struct domain *d =3D (struct domain = *)_d;=0A+=0A+ ASSERT(d->arch.hvm_domain.irq.dpci);=0A+=0A+ spin_lock(= &d->event_lock);=0A+ pt_pirq_iterate(d, _hvm_dirq_assist, NULL);=0A+ = spin_unlock(&d->event_lock);=0A }=0A =0A static void __hvm_dpci_eoi(struct = domain *d,=0A- struct hvm_irq_dpci *hvm_irq_dpci,= =0A struct hvm_girq_dpci_mapping *girq,=0A = union vioapic_redir_entry *ent)=0A {=0A- uint32_t = device, intx, machine_gsi;=0A+ uint32_t device, intx;=0A+ struct = pirq *pirq;=0A+ struct hvm_pirq_dpci *pirq_dpci;=0A =0A device =3D = girq->device;=0A intx =3D girq->intx;=0A hvm_pci_intx_deassert(d, = device, intx);=0A =0A- machine_gsi =3D girq->machine_gsi;=0A+ pirq = =3D pirq_info(d, girq->machine_gsi);=0A+ pirq_dpci =3D pirq_dpci(pirq);= =0A =0A /*=0A * No need to get vector lock for timer=0A * = since interrupt is still not EOIed=0A */=0A- if ( --hvm_irq_dpci->m= irq[machine_gsi].pending ||=0A+ if ( --pirq_dpci->pending ||=0A = ( ent && ent->fields.mask ) ||=0A- ! pt_irq_need_timer(hvm_irq_dpc= i->mirq[machine_gsi].flags) )=0A+ ! pt_irq_need_timer(pirq_dpci->fl= ags) )=0A return;=0A =0A- stop_timer(&hvm_irq_dpci->hvm_timer[ma= chine_gsi]);=0A- pirq_guest_eoi(d, machine_gsi);=0A+ stop_timer(&pirq= _dpci->timer);=0A+ pirq_guest_eoi(d, pirq);=0A }=0A =0A void hvm_dpci_eo= i(struct domain *d, unsigned int guest_gsi,=0A@@ -569,7 +595,7 @@ void = hvm_dpci_eoi(struct domain *d, unsi=0A goto unlock;=0A =0A = list_for_each_entry ( girq, &hvm_irq_dpci->girq[guest_gsi], list )=0A- = __hvm_dpci_eoi(d, hvm_irq_dpci, girq, ent);=0A+ __hvm_dpci_eoi(d,= girq, ent);=0A =0A unlock:=0A spin_unlock(&d->event_lock);=0A--- = 2011-04-29.orig/xen/drivers/passthrough/pci.c=0A+++ 2011-04-29/xen/drivers/= passthrough/pci.c=0A@@ -236,12 +236,28 @@ out:=0A return ret;=0A }=0A = =0A+static int pci_clean_dpci_irq(struct domain *d, unsigned int pirq,=0A+ = struct hvm_pirq_dpci *pirq_dpci, void = *arg)=0A+{=0A+ struct dev_intx_gsi_link *digl, *tmp;=0A+=0A+ = pirq_guest_unbind(d, pirq, dpci_pirq(pirq_dpci));=0A+=0A+ if ( = pt_irq_need_timer(pirq_dpci->flags) )=0A+ kill_timer(&pirq_dpci->tim= er);=0A+=0A+ list_for_each_entry_safe ( digl, tmp, &pirq_dpci->digl_list= , list )=0A+ {=0A+ list_del(&digl->list);=0A+ xfree(digl);= =0A+ }=0A+=0A+ return 0;=0A+}=0A+=0A static void pci_clean_dpci_irqs(= struct domain *d)=0A {=0A struct hvm_irq_dpci *hvm_irq_dpci =3D = NULL;=0A- uint32_t i;=0A- struct list_head *digl_list, *tmp;=0A- = struct dev_intx_gsi_link *digl;=0A =0A if ( !iommu_enabled )=0A = return;=0A@@ -255,24 +271,7 @@ static void pci_clean_dpci_irqs(struct = d=0A {=0A tasklet_kill(&hvm_irq_dpci->dirq_tasklet);=0A =0A- = for ( i =3D find_first_bit(hvm_irq_dpci->mapping, d->nr_pirqs);=0A- = i < d->nr_pirqs;=0A- i =3D find_next_bit(hvm_irq_dp= ci->mapping, d->nr_pirqs, i + 1) )=0A- {=0A- pirq_guest_u= nbind(d, i);=0A-=0A- if ( pt_irq_need_timer(hvm_irq_dpci->mirq[i= ].flags) )=0A- kill_timer(&hvm_irq_dpci->hvm_timer[i]);=0A-= =0A- list_for_each_safe ( digl_list, tmp,=0A- = &hvm_irq_dpci->mirq[i].digl_list )=0A- {=0A- = digl =3D list_entry(digl_list,=0A- = struct dev_intx_gsi_link, list);=0A- list_del(&digl->list= );=0A- xfree(digl);=0A- }=0A- }=0A+ = pt_pirq_iterate(d, pci_clean_dpci_irq, NULL);=0A =0A d->arch.hvm_d= omain.irq.dpci =3D NULL;=0A free_hvm_irq_dpci(hvm_irq_dpci);=0A--- = 2011-04-29.orig/xen/drivers/passthrough/vtd/x86/vtd.c=0A+++ 2011-04-29/xen/= drivers/passthrough/vtd/x86/vtd.c=0A@@ -68,12 +68,32 @@ void *__init = map_to_nocache_virt(int nr_=0A return (void *)fix_to_virt(FIX_IOMMU_REG= S_BASE_0 + nr_iommus);=0A }=0A =0A-void hvm_dpci_isairq_eoi(struct domain = *d, unsigned int isairq)=0A+static int _hvm_dpci_isairq_eoi(struct domain = *d, unsigned int pirq,=0A+ struct hvm_pirq_d= pci *pirq_dpci, void *arg)=0A {=0A struct hvm_irq *hvm_irq =3D = &d->arch.hvm_domain.irq;=0A- struct hvm_irq_dpci *dpci =3D NULL;=0A+ = unsigned int isairq =3D (long)arg;=0A struct dev_intx_gsi_link *digl, = *tmp;=0A- int i;=0A+=0A+ list_for_each_entry_safe ( digl, tmp, = &pirq_dpci->digl_list, list )=0A+ {=0A+ if ( hvm_irq->pci_link.ro= ute[digl->link] =3D=3D isairq )=0A+ {=0A+ hvm_pci_intx_de= assert(d, digl->device, digl->intx);=0A+ if ( --pirq_dpci->pendi= ng =3D=3D 0 )=0A+ {=0A+ stop_timer(&pirq_dpci->ti= mer);=0A+ pirq_guest_eoi(d, dpci_pirq(pirq_dpci));=0A+ = }=0A+ }=0A+ }=0A+=0A+ return 0;=0A+}=0A+=0A+void = hvm_dpci_isairq_eoi(struct domain *d, unsigned int isairq)=0A+{=0A+ = struct hvm_irq_dpci *dpci =3D NULL;=0A =0A ASSERT(isairq < NR_ISAIRQS);= =0A if ( !iommu_enabled)=0A@@ -83,29 +103,10 @@ void hvm_dpci_isairq_eo= i(struct domain *=0A =0A dpci =3D domain_get_irq_dpci(d);=0A =0A- = if ( !dpci || !test_bit(isairq, dpci->isairq_map) )=0A+ if ( dpci && = test_bit(isairq, dpci->isairq_map) )=0A {=0A- spin_unlock(&d->ev= ent_lock);=0A- return;=0A- }=0A- /* Multiple mirq may be = mapped to one isa irq */=0A- for ( i =3D find_first_bit(dpci->mapping, = d->nr_pirqs);=0A- i < d->nr_pirqs;=0A- i =3D find_next_bi= t(dpci->mapping, d->nr_pirqs, i + 1) )=0A- {=0A- list_for_each_en= try_safe ( digl, tmp,=0A- &dpci->mirq[i].digl_list, list )=0A- = {=0A- if ( hvm_irq->pci_link.route[digl->link] =3D=3D = isairq )=0A- {=0A- hvm_pci_intx_deassert(d, = digl->device, digl->intx);=0A- if ( --dpci->mirq[i].pending = =3D=3D 0 )=0A- {=0A- stop_timer(&dpci->hv= m_timer[i]);=0A- pirq_guest_eoi(d, i);=0A- = }=0A- }=0A- }=0A+ /* Multiple mirq may be = mapped to one isa irq */=0A+ pt_pirq_iterate(d, _hvm_dpci_isairq_eoi= , (void *)(long)isairq);=0A }=0A spin_unlock(&d->event_lock);=0A = }=0A--- 2011-04-29.orig/xen/include/asm-ia64/domain.h=0A+++ 2011-04-29/xen/= include/asm-ia64/domain.h=0A@@ -11,6 +11,7 @@=0A #include =0A = #include =0A #include =0A+#include = =0A #include =0A #include =0A =0A@@ -316,6 = +317,23 @@ struct arch_vcpu {=0A cpumask_t cache_coherent_map;=0A = };=0A =0A+struct arch_pirq {=0A+ struct hvm_pirq_dpci dpci;=0A+};=0A+=0A= +#define pirq_dpci(pirq) ((pirq) ? &(pirq)->arch.dpci : NULL)=0A+#define = dpci_pirq(dpci) container_of(dpci, struct pirq, arch.dpci)=0A+=0A+#define = alloc_pirq_struct(d) ({ \=0A+ struct pirq *pirq =3D xmalloc(struct = pirq); \=0A+ if ( pirq ) \=0A+ { \=0A+ memset(pirq, 0, = sizeof(*pirq)); \=0A+ pt_pirq_init(d, &pirq->arch.dpci); \=0A+ } = \=0A+ pirq; \=0A+})=0A+=0A #include /* for KERNEL_DS = */=0A #include =0A =0A--- 2011-04-29.orig/xen/include/asm-x8= 6/domain.h=0A+++ 2011-04-29/xen/include/asm-x86/domain.h=0A@@ -286,9 = +286,6 @@ struct arch_domain=0A =0A /* NB. protected by d->event_lock = and by irq_desc[irq].lock */=0A struct radix_tree_root irq_pirq;=0A- = int *pirq_irq;=0A- /* pirq to emulated irq */=0A- int *pirq_emuirq;= =0A =0A /* Maximum physical-address bitwidth supported by this guest. = */=0A unsigned int physaddr_bitsize;=0A--- 2011-04-29.orig/xen/include/= asm-x86/hvm/irq.h=0A+++ 2011-04-29/xen/include/asm-x86/hvm/irq.h=0A@@ = -111,4 +111,6 @@ struct hvm_intack hvm_vcpu_ack_pending_i=0A */=0A = #define SUPPORT_MSI_REMAPPING 1=0A =0A+void msixtbl_pt_cleanup(struct = domain *d);=0A+=0A #endif /* __ASM_X86_HVM_IRQ_H__ */=0A--- 2011-04-29.orig= /xen/include/asm-x86/irq.h=0A+++ 2011-04-29/xen/include/asm-x86/irq.h=0A@@ = -7,6 +7,7 @@=0A #include =0A #include =0A = #include =0A+#include =0A #include =0A #include =0A =0A@@ -105,6 +106,20 @@ extern unsigned = int io_apic_irqs;=0A =0A DECLARE_PER_CPU(unsigned int, irq_count);=0A = =0A+struct pirq;=0A+struct arch_pirq {=0A+ int irq;=0A+ union {=0A+ = struct hvm_pirq {=0A+ int emuirq;=0A+ struct = hvm_pirq_dpci dpci;=0A+ } hvm;=0A+ };=0A+};=0A+=0A+#define = pirq_dpci(pirq) ((pirq) ? &(pirq)->arch.hvm.dpci : NULL)=0A+#define = dpci_pirq(pd) container_of(pd, struct pirq, arch.hvm.dpci)=0A+=0A int = pirq_shared(struct domain *d , int irq);=0A =0A int map_domain_pirq(struct = domain *d, int pirq, int irq, int type,=0A@@ -114,7 +129,7 @@ int = get_free_pirq(struct domain *d, int =0A void free_domain_pirqs(struct = domain *d);=0A int map_domain_emuirq_pirq(struct domain *d, int pirq, int = irq);=0A int unmap_domain_pirq_emuirq(struct domain *d, int pirq);=0A-int = hvm_domain_use_pirq(struct domain *d, int irq);=0A+bool_t hvm_domain_use_pi= rq(const struct domain *, const struct pirq *);=0A =0A int init_irq_data(v= oid);=0A =0A@@ -146,11 +161,11 @@ void irq_set_affinity(struct irq_desc = *,=0A int init_domain_irq_mapping(struct domain *);=0A void cleanup_domain_= irq_mapping(struct domain *);=0A =0A-#define domain_pirq_to_irq(d, pirq) = ((d)->arch.pirq_irq[pirq])=0A+#define domain_pirq_to_irq(d, pirq) = pirq_field(d, pirq, arch.irq)=0A #define domain_irq_to_pirq(d, irq) \=0A = ((long)radix_tree_lookup(&(d)->arch.irq_pirq, irq))=0A #define PIRQ_ALLOC= ATED -1=0A-#define domain_pirq_to_emuirq(d, pirq) ((d)->arch.pirq_emuirq[pi= rq])=0A+#define domain_pirq_to_emuirq(d, pirq) pirq_field(d, pirq, = arch.hvm.emuirq)=0A #define domain_emuirq_to_pirq(d, emuirq) \=0A = (((long)radix_tree_lookup(&(d)->arch.hvm_domain.emuirq_pirq, emuirq) ?: = \=0A IRQ_UNBOUND + 1) - 1)=0A--- 2011-04-29.orig/xen/include/xen/domai= n.h=0A+++ 2011-04-29/xen/include/xen/domain.h=0A@@ -38,6 +38,12 @@ struct = vcpu_guest_context *alloc_vcpu_gu=0A void free_vcpu_guest_context(struct = vcpu_guest_context *);=0A #endif=0A =0A+/* Allocate/free a PIRQ structure. = */=0A+#ifndef alloc_pirq_struct=0A+struct pirq *alloc_pirq_struct(struct = domain *);=0A+#endif=0A+#define free_pirq_struct xfree=0A+=0A /*=0A * = Initialise/destroy arch-specific details of a VCPU.=0A * - vcpu_initialis= e() is called after the basic generic fields of the=0A--- 2011-04-29.orig/x= en/include/xen/event.h=0A+++ 2011-04-29/xen/include/xen/event.h=0A@@ -36,7 = +36,7 @@ void send_guest_global_virq(struct domai=0A * @pirq: = Physical IRQ number=0A * Returns TRUE if the delivery port was already = pending.=0A */=0A-int send_guest_pirq(struct domain *d, int pirq);=0A+int = send_guest_pirq(struct domain *, const struct pirq *);=0A =0A /* Send a = notification from a given domain's event-channel port. */=0A int evtchn_sen= d(struct domain *d, unsigned int lport);=0A--- 2011-04-29.orig/xen/include/= xen/hvm/irq.h=0A+++ 2011-04-29/xen/include/xen/hvm/irq.h=0A@@ -25,7 +25,7 = @@=0A #include =0A #include =0A #include = =0A-#include =0A+#include =0A = #include =0A =0A struct dev_intx_gsi_link {=0A@@ -38,11 = +38,15 @@ struct dev_intx_gsi_link {=0A =0A #define _HVM_IRQ_DPCI_MACH_PCI_= SHIFT 0=0A #define _HVM_IRQ_DPCI_MACH_MSI_SHIFT = 1=0A+#define _HVM_IRQ_DPCI_MAPPED_SHIFT 2=0A+#define = _HVM_IRQ_DPCI_EOI_LATCH_SHIFT 3=0A #define _HVM_IRQ_DPCI_GUEST_PC= I_SHIFT 4=0A #define _HVM_IRQ_DPCI_GUEST_MSI_SHIFT = 5=0A #define _HVM_IRQ_DPCI_TRANSLATE_SHIFT 15=0A #define = HVM_IRQ_DPCI_MACH_PCI (1 << _HVM_IRQ_DPCI_MACH_PCI_SHIFT)=0A = #define HVM_IRQ_DPCI_MACH_MSI (1 << _HVM_IRQ_DPCI_MACH_MSI_SHIFT)=0A= +#define HVM_IRQ_DPCI_MAPPED (1 << _HVM_IRQ_DPCI_MAPPED_SHIFT)=0A+= #define HVM_IRQ_DPCI_EOI_LATCH (1 << _HVM_IRQ_DPCI_EOI_LATCH_SHIFT)= =0A #define HVM_IRQ_DPCI_GUEST_PCI (1 << _HVM_IRQ_DPCI_GUEST_PCI_SHIF= T)=0A #define HVM_IRQ_DPCI_GUEST_MSI (1 << _HVM_IRQ_DPCI_GUEST_MSI_SH= IFT)=0A #define HVM_IRQ_DPCI_TRANSLATE (1 << _HVM_IRQ_DPCI_TRANSLATE_= SHIFT)=0A@@ -63,14 +67,6 @@ struct hvm_gmsi_info {=0A int dest_vcpu_id;= /* -1 :multi-dest, non-negative: dest_vcpu_id */=0A };=0A =0A-struct = hvm_mirq_dpci_mapping {=0A- uint32_t flags;=0A- int pending;=0A- = struct list_head digl_list;=0A- struct domain *dom;=0A- struct = hvm_gmsi_info gmsi;=0A-};=0A-=0A struct hvm_girq_dpci_mapping {=0A = struct list_head list;=0A uint8_t device;=0A@@ -88,20 +84,33 @@ struct = hvm_girq_dpci_mapping {=0A =0A /* Protected by domain's event_lock */=0A = struct hvm_irq_dpci {=0A- /* Machine IRQ to guest device/intx mapping. = */=0A- unsigned long *mapping;=0A- struct hvm_mirq_dpci_mapping = *mirq;=0A- unsigned long *dirq_mask;=0A /* Guest IRQ to guest = device/intx mapping. */=0A struct list_head girq[NR_HVM_IRQS];=0A = /* Record of mapped ISA IRQs */=0A DECLARE_BITMAP(isairq_map, = NR_ISAIRQS);=0A /* Record of mapped Links */=0A uint8_t link_cnt[NR= _LINK];=0A- struct timer *hvm_timer;=0A struct tasklet dirq_tasklet;= =0A };=0A =0A+/* Machine IRQ to guest device/intx mapping. */=0A+struct = hvm_pirq_dpci {=0A+ uint32_t flags;=0A+ bool_t masked;=0A+ = uint16_t pending;=0A+ struct list_head digl_list;=0A+ struct domain = *dom;=0A+ struct hvm_gmsi_info gmsi;=0A+ struct timer timer;=0A+};=0A= +=0A+void pt_pirq_init(struct domain *, struct hvm_pirq_dpci *);=0A+bool_t = pt_pirq_cleanup_check(struct hvm_pirq_dpci *);=0A+int pt_pirq_iterate(struc= t domain *d,=0A+ int (*cb)(struct domain *, unsigned = int pirq,=0A+ struct hvm_pirq_dpci *, void = *arg),=0A+ void *arg);=0A+=0A /* Modify state of a PCI = INTx wire. */=0A void hvm_pci_intx_assert(=0A struct domain *d, = unsigned int device, unsigned int intx);=0A@@ -120,4 +129,6 @@ void = hvm_maybe_deassert_evtchn_irq(void)=0A void hvm_assert_evtchn_irq(struct = vcpu *v);=0A void hvm_set_callback_via(struct domain *d, uint64_t via);=0A = =0A+int vmsi_deliver(struct domain *, const struct hvm_pirq_dpci *);=0A+=0A= #endif /* __XEN_HVM_IRQ_H__ */=0A--- 2011-04-29.orig/xen/include/xen/iommu= .h=0A+++ 2011-04-29/xen/include/xen/iommu.h=0A@@ -88,7 +88,9 @@ int = iommu_unmap_page(struct domain *d, u=0A void iommu_pte_flush(struct domain = *d, u64 gfn, u64 *pte, int order, int present);=0A void iommu_set_pgd(struc= t domain *d);=0A void iommu_domain_teardown(struct domain *d);=0A-int = hvm_do_IRQ_dpci(struct domain *d, unsigned int irq);=0A+=0A+struct = pirq;=0A+int hvm_do_IRQ_dpci(struct domain *, struct pirq *);=0A int = dpci_ioport_intercept(ioreq_t *p);=0A int pt_irq_create_bind_vtd(struct = domain *d,=0A xen_domctl_bind_pt_irq_t = *pt_irq_bind);=0A--- 2011-04-29.orig/xen/include/xen/irq.h=0A+++ 2011-04-29= /xen/include/xen/irq.h=0A@@ -135,13 +135,41 @@ extern void no_action(int = cpl, void *dev=0A =0A struct domain;=0A struct vcpu;=0A-extern int = pirq_guest_eoi(struct domain *d, int irq);=0A+=0A+struct pirq {=0A+ u16 = evtchn;=0A+ bool_t masked;=0A+ struct arch_pirq arch;=0A+};=0A+=0A+#d= efine pirq_info(d, p) ((struct pirq *)radix_tree_lookup(&(d)->pirq_tree, = p))=0A+=0A+/* Use this instead of pirq_info() if the structure may need = allocating. */=0A+extern struct pirq *pirq_get_info(struct domain *, int = pirq);=0A+=0A+#define pirq_field(d, p, f) ({ \=0A+ const struct pirq = *__pi =3D pirq_info(d, p); \=0A+ __pi ? __pi->f : 0; \=0A+})=0A+#define = pirq_to_evtchn(d, pirq) pirq_field(d, pirq, evtchn)=0A+#define pirq_masked(= d, pirq) pirq_field(d, pirq, masked)=0A+=0A+void pirq_cleanup_check(struct = pirq *, struct domain *, int);=0A+=0A+#define pirq_cleanup_check(info, d, = pirq) \=0A+ ((info)->evtchn ? pirq_cleanup_check(info, d, pirq) : = (void)0)=0A+=0A+extern void pirq_guest_eoi(struct domain *, struct pirq = *);=0A+extern void desc_guest_eoi(struct domain *, struct irq_desc *, = struct pirq *);=0A extern int pirq_guest_unmask(struct domain *d);=0A-exter= n int pirq_guest_bind(struct vcpu *v, int irq, int will_share);=0A-extern = void pirq_guest_unbind(struct domain *d, int irq);=0A+extern int pirq_guest= _bind(struct vcpu *, int pirq, struct pirq *,=0A+ int will_share);=0A+ex= tern void pirq_guest_unbind(struct domain *d, int pirq, struct pirq *);=0A = extern void pirq_set_affinity(struct domain *d, int irq, const cpumask_t = *);=0A extern irq_desc_t *domain_spin_lock_irq_desc(=0A struct domain = *d, int irq, unsigned long *pflags);=0A+extern irq_desc_t *pirq_spin_lock_i= rq_desc(=0A+ struct domain *, const struct pirq *, unsigned long = *pflags);=0A =0A static inline void set_native_irq_info(unsigned int irq, = const cpumask_t *mask)=0A {=0A--- 2011-04-29.orig/xen/include/xen/pci.h=0A+= ++ 2011-04-29/xen/include/xen/pci.h=0A@@ -117,8 +117,9 @@ int pci_find_cap_= offset(u8 bus, u8 dev, =0A int pci_find_next_cap(u8 bus, unsigned int = devfn, u8 pos, int cap);=0A int pci_find_ext_capability(int seg, int bus, = int devfn, int cap);=0A =0A-int msixtbl_pt_register(struct domain *d, int = pirq, uint64_t gtable);=0A-void msixtbl_pt_unregister(struct domain *d, = int pirq);=0A+struct pirq;=0A+int msixtbl_pt_register(struct domain *, = struct pirq *, uint64_t gtable);=0A+void msixtbl_pt_unregister(struct = domain *, struct pirq *);=0A void pci_enable_acs(struct pci_dev *pdev);=0A = =0A #endif /* __XEN_PCI_H__ */=0A--- 2011-04-29.orig/xen/include/xen/radix-= tree.h=0A+++ 2011-04-29/xen/include/xen/radix-tree.h=0A@@ -72,6 +72,7 @@ = void *radix_tree_delete(struct radix_tre=0A = void(*node_free)(struct radix_tree_node *));=0A unsigned int=0A radix_tree_= gang_lookup(struct radix_tree_root *root, void **results,=0A- = unsigned long first_index, unsigned int max_items);=0A+ = unsigned long first_index, unsigned int max_items,=0A+ = unsigned long *indexes);=0A =0A #endif /* _XEN_RADIX_TREE_H = */=0A--- 2011-04-29.orig/xen/include/xen/sched.h=0A+++ 2011-04-29/xen/inclu= de/xen/sched.h=0A@@ -21,6 +21,7 @@=0A #include =0A #include = =0A #include =0A+#include =0A = #include =0A #include =0A #include = =0A@@ -234,13 +235,11 @@ struct domain=0A struct = grant_table *grant_table;=0A =0A /*=0A- * Interrupt to event-channe= l mappings. Updates should be protected by the =0A- * domain's = event-channel spinlock. Read accesses can also synchronise on =0A- * = the lock, but races don't usually matter.=0A+ * Interrupt to event-chan= nel mappings and other per-guest-pirq data.=0A+ * Protected by the = domain's event-channel spinlock.=0A */=0A unsigned int = nr_pirqs;=0A- u16 *pirq_to_evtchn;=0A- unsigned long = *pirq_mask;=0A+ struct radix_tree_root pirq_tree;=0A =0A /* I/O = capabilities (access to IRQs and memory-mapped I/O). */=0A struct = rangeset *iomem_caps;=0A --=__Part7C50FC95.1__= Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Disposition: inline _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel --=__Part7C50FC95.1__=--