aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKeir Fraser <keir.fraser@citrix.com>2008-07-31 09:51:06 +0100
committerKeir Fraser <keir.fraser@citrix.com>2008-07-31 09:51:06 +0100
commit1b45fb4c12d5eca59df6a532acd2b060d7c53f58 (patch)
treedada81d9677269a00581b3c95b1cd1549c38e2a6
parent438f8cbed5260f4319a2aa7eee506bc402691c44 (diff)
downloadxen-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.c15
-rw-r--r--xen/drivers/passthrough/iommu.c30
-rw-r--r--xen/drivers/passthrough/pci.c39
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);