diff options
author | Keir Fraser <keir.fraser@citrix.com> | 2008-07-31 09:51:06 +0100 |
---|---|---|
committer | Keir Fraser <keir.fraser@citrix.com> | 2008-07-31 09:51:06 +0100 |
commit | 1b45fb4c12d5eca59df6a532acd2b060d7c53f58 (patch) | |
tree | dada81d9677269a00581b3c95b1cd1549c38e2a6 | |
parent | 438f8cbed5260f4319a2aa7eee506bc402691c44 (diff) | |
download | xen-1b45fb4c12d5eca59df6a532acd2b060d7c53f58.tar.gz xen-1b45fb4c12d5eca59df6a532acd2b060d7c53f58.tar.bz2 xen-1b45fb4c12d5eca59df6a532acd2b060d7c53f58.zip |
vtd: Fix bug #1306: Dom0 hangs when destroying guest with MSI NIC assigned
Signed-off-by: Shan Haitao <haitao.shan@intel.com>
-rw-r--r-- | xen/arch/x86/msi.c | 15 | ||||
-rw-r--r-- | xen/drivers/passthrough/iommu.c | 30 | ||||
-rw-r--r-- | xen/drivers/passthrough/pci.c | 39 |
3 files changed, 48 insertions, 36 deletions
diff --git a/xen/arch/x86/msi.c b/xen/arch/x86/msi.c index d6c4d0b1e6..91e725049a 100644 --- a/xen/arch/x86/msi.c +++ b/xen/arch/x86/msi.c @@ -761,14 +761,13 @@ retry: { desc = &irq_desc[entry->vector]; - local_irq_save(flags); - if ( !spin_trylock(&desc->lock) ) - { - local_irq_restore(flags); - goto retry; - } - - spin_lock_irqsave(&desc->lock, flags); + local_irq_save(flags); + if ( !spin_trylock(&desc->lock) ) + { + local_irq_restore(flags); + goto retry; + } + if ( desc->handler == &pci_msi_type ) { /* MSI is not shared, so should be released already */ diff --git a/xen/drivers/passthrough/iommu.c b/xen/drivers/passthrough/iommu.c index 2e2afaeb13..0a3fc48da9 100644 --- a/xen/drivers/passthrough/iommu.c +++ b/xen/drivers/passthrough/iommu.c @@ -126,14 +126,12 @@ static int iommu_populate_page_table(struct domain *d) return 0; } + void iommu_domain_destroy(struct domain *d) { - struct hvm_irq_dpci *hvm_irq_dpci = domain_get_irq_dpci(d); - uint32_t i; struct hvm_iommu *hd = domain_hvm_iommu(d); - struct list_head *ioport_list, *digl_list, *tmp; + struct list_head *ioport_list, *tmp; struct g2m_ioport *ioport; - struct dev_intx_gsi_link *digl; if ( !iommu_enabled || !hd->platform_ops ) return; @@ -148,30 +146,6 @@ void iommu_domain_destroy(struct domain *d) return; } - if ( hvm_irq_dpci != NULL ) - { - for ( i = 0; i < NR_IRQS; i++ ) - { - if ( !(hvm_irq_dpci->mirq[i].flags & HVM_IRQ_DPCI_VALID) ) - continue; - - pirq_guest_unbind(d, i); - kill_timer(&hvm_irq_dpci->hvm_timer[irq_to_vector(i)]); - - list_for_each_safe ( digl_list, tmp, - &hvm_irq_dpci->mirq[i].digl_list ) - { - digl = list_entry(digl_list, - struct dev_intx_gsi_link, list); - list_del(&digl->list); - xfree(digl); - } - } - - d->arch.hvm_domain.irq.dpci = NULL; - xfree(hvm_irq_dpci); - } - if ( hd ) { list_for_each_safe ( ioport_list, tmp, &hd->g2m_ioport_list ) diff --git a/xen/drivers/passthrough/pci.c b/xen/drivers/passthrough/pci.c index b38e04e908..df7161d539 100644 --- a/xen/drivers/passthrough/pci.c +++ b/xen/drivers/passthrough/pci.c @@ -152,11 +152,50 @@ int pci_remove_device(u8 bus, u8 devfn) return ret; } +static void pci_clean_dpci_irqs(struct domain *d) +{ + struct hvm_irq_dpci *hvm_irq_dpci = domain_get_irq_dpci(d); + uint32_t i; + struct list_head *digl_list, *tmp; + struct dev_intx_gsi_link *digl; + + if ( !iommu_enabled ) + return; + + if ( !is_hvm_domain(d) && !need_iommu(d) ) + return; + + if ( hvm_irq_dpci != NULL ) + { + for ( i = 0; i < NR_IRQS; i++ ) + { + if ( !(hvm_irq_dpci->mirq[i].flags & HVM_IRQ_DPCI_VALID) ) + continue; + + pirq_guest_unbind(d, i); + kill_timer(&hvm_irq_dpci->hvm_timer[irq_to_vector(i)]); + + list_for_each_safe ( digl_list, tmp, + &hvm_irq_dpci->mirq[i].digl_list ) + { + digl = list_entry(digl_list, + struct dev_intx_gsi_link, list); + list_del(&digl->list); + xfree(digl); + } + } + + d->arch.hvm_domain.irq.dpci = NULL; + xfree(hvm_irq_dpci); + } +} + void pci_release_devices(struct domain *d) { struct pci_dev *pdev; u8 bus, devfn; + pci_clean_dpci_irqs(d); while ( (pdev = pci_lock_domain_pdev(d, -1, -1)) ) { pci_cleanup_msi(pdev); |