diff --git a/xen/arch/x86/domain.c b/xen/arch/x86/domain.c index feda3ba..2f5a69a 100644 --- a/xen/arch/x86/domain.c +++ b/xen/arch/x86/domain.c @@ -510,8 +510,6 @@ void arch_domain_destroy(struct domain *d) pci_release_devices(d); free_domain_pirqs(d); - if ( !is_idle_domain(d) ) - iommu_domain_destroy(d); paging_final_teardown(d); diff --git a/xen/common/domain.c b/xen/common/domain.c index 32f1d48..a7b0207 100644 --- a/xen/common/domain.c +++ b/xen/common/domain.c @@ -385,6 +385,7 @@ int domain_kill(struct domain *d) v4v_destroy(d); evtchn_destroy(d); gnttab_release_mappings(d); + iommu_domain_destroy(d); /* fallthrough */ case DOMDYING_dying: rc = domain_relinquish_resources(d); diff --git a/xen/drivers/passthrough/pci.c b/xen/drivers/passthrough/pci.c index 723cff0..e90a335 100644 --- a/xen/drivers/passthrough/pci.c +++ b/xen/drivers/passthrough/pci.c @@ -75,6 +75,81 @@ struct pci_dev *pci_get_pdev(int bus, int devfn) return NULL; } +struct pci_dev *pci_get_bridge(u8 secondary) +{ + struct pci_dev *pdev = NULL, *m = NULL; + + spin_lock(&pcidevs_lock); + + list_for_each_entry ( pdev, &alldevs_list, alldevs_list ) + { + u8 type = pci_conf_read8(pdev->bus, + PCI_SLOT(pdev->devfn), + PCI_FUNC(pdev->devfn), + PCI_HEADER_TYPE); + if ( (type & 3) == PCI_HEADER_TYPE_BRIDGE ) + { + u8 sec = pci_conf_read8(pdev->bus, + PCI_SLOT(pdev->devfn), + PCI_FUNC(pdev->devfn), + PCI_SECONDARY_BUS); + if ( sec == secondary ) + { + m = pdev; + goto out; + } + } + } +out: + spin_unlock(&pcidevs_lock); + return m; +} + +struct pci_dev *pci_get_gfx(struct domain *d) +{ + struct pci_dev *pdev = NULL, *m = NULL; + + spin_lock(&pcidevs_lock); + + list_for_each_entry ( pdev, &alldevs_list, alldevs_list ) + { + if ( d == NULL || pdev->domain == d ) + { + u16 class = pci_conf_read16(pdev->bus, + PCI_SLOT(pdev->devfn), + PCI_FUNC(pdev->devfn), + PCI_CLASS_DEVICE); + + if ( class == 0x0300 ) + { + m = pdev; + goto out; + } + } + } +out: + spin_unlock(&pcidevs_lock); + return m; + +} + +struct pci_dev *pci_match_pdev(int (*match)(struct pci_dev *)) +{ + struct pci_dev *pdev = NULL, *m = NULL; + + spin_lock(&pcidevs_lock); + + list_for_each_entry ( pdev, &alldevs_list, alldevs_list ) + if ( match(pdev) ) + { + m = pdev; + goto out; + } +out: + spin_unlock(&pcidevs_lock); + return m; +} + struct pci_dev *pci_get_pdev_by_domain(struct domain *d, int bus, int devfn) { struct pci_dev *pdev = NULL; diff --git a/xen/drivers/passthrough/vtd/Makefile b/xen/drivers/passthrough/vtd/Makefile index 0e6f163..00ba797 100644 --- a/xen/drivers/passthrough/vtd/Makefile +++ b/xen/drivers/passthrough/vtd/Makefile @@ -6,3 +6,4 @@ obj-y += dmar.o obj-y += utils.o obj-y += qinval.o obj-y += intremap.o +obj-y += pci_reset.o diff --git a/xen/drivers/passthrough/vtd/iommu.c b/xen/drivers/passthrough/vtd/iommu.c index 687f3fd..df88dc7 100644 --- a/xen/drivers/passthrough/vtd/iommu.c +++ b/xen/drivers/passthrough/vtd/iommu.c @@ -21,7 +21,6 @@ #include #include -#include #include #include #include @@ -32,11 +31,13 @@ #include #include #include +#include #include #include "iommu.h" #include "dmar.h" #include "extern.h" #include "vtd.h" +#include "pci_reset.h" #define domain_iommu_domid(d) ((d)->arch.hvm_domain.hvm_iommu.iommu_domid) @@ -1503,6 +1504,15 @@ static int reassign_device_ownership( if ( (drhd = acpi_find_matched_drhd_unit(pdev)) == NULL ) return -ENODEV; + + /* Only do the reset here if target isn't dom0. + ** For the reassign to dom0 it's done in the iommu_domain_teardown + ** function because reassign_device_ownership happen too late in + ** the process. + */ + if (target->domain_id != 0) + pci_reset_device(bus, devfn); + pdev_iommu = drhd->iommu; domain_context_unmap(source, bus, devfn); @@ -1534,10 +1544,14 @@ static int reassign_device_ownership( void iommu_domain_teardown(struct domain *d) { struct hvm_iommu *hd = domain_hvm_iommu(d); + struct pci_dev *pdev = NULL; if ( list_empty(&acpi_drhd_units) ) return; + if ((pdev = pci_get_gfx(d))) + pci_reset_device(pdev->bus, pdev->devfn); + spin_lock(&hd->mapping_lock); iommu_free_pagetable(hd->pgd_maddr, agaw_to_level(hd->agaw)); hd->pgd_maddr = 0; diff --git a/xen/include/xen/pci.h b/xen/include/xen/pci.h index 6827e0d..9ed6f60 100644 --- a/xen/include/xen/pci.h +++ b/xen/include/xen/pci.h @@ -77,6 +77,9 @@ int pci_remove_device(u8 bus, u8 devfn); int pci_add_device_ext(u8 bus, u8 devfn, struct pci_dev_info *info); struct pci_dev *pci_get_pdev(int bus, int devfn); struct pci_dev *pci_get_pdev_by_domain(struct domain *d, int bus, int devfn); +struct pci_dev *pci_match_pdev(int (*match)(struct pci_dev *)); +struct pci_dev *pci_get_bridge(u8 secondary); +struct pci_dev *pci_get_gfx(struct domain *d); uint8_t pci_conf_read8( unsigned int bus, unsigned int dev, unsigned int func, unsigned int reg); diff --git a/xen/include/xen/pci_regs.h b/xen/include/xen/pci_regs.h index 361554c..20b00e8 100644 --- a/xen/include/xen/pci_regs.h +++ b/xen/include/xen/pci_regs.h @@ -210,6 +210,7 @@ #define PCI_CAP_ID_AGP3 0x0E /* AGP Target PCI-PCI bridge */ #define PCI_CAP_ID_EXP 0x10 /* PCI Express */ #define PCI_CAP_ID_MSIX 0x11 /* MSI-X */ +#define PCI_CAP_ID_AF 0x13 /* PCI Advanced Features */ #define PCI_CAP_LIST_NEXT 1 /* Next capability in the list */ #define PCI_CAP_FLAGS 2 /* Capability defined flags (16 bits) */ #define PCI_CAP_SIZEOF 4 @@ -315,6 +316,17 @@ #define PCI_CHSWP_EXT 0x40 /* ENUM# status - extraction */ #define PCI_CHSWP_INS 0x80 /* ENUM# status - insertion */ +/* PCI Advanced Feature registers */ + +#define PCI_AF_LENGTH 2 +#define PCI_AF_CAP 3 +#define PCI_AF_CAP_TP 0x01 +#define PCI_AF_CAP_FLR 0x02 +#define PCI_AF_CTRL 4 +#define PCI_AF_CTRL_FLR 0x01 +#define PCI_AF_STATUS 5 +#define PCI_AF_STATUS_TP 0x01 + /* PCI-X registers */ #define PCI_X_CMD 2 /* Modes & Features */