passthrough: re-attempt ACS and ATS enabling when devices get reported by Dom0
authorJan Beulich <jbeulich@suse.com>
Wed, 2 Nov 2011 12:53:05 +0000 (13:53 +0100)
committerJan Beulich <jbeulich@suse.com>
Wed, 2 Nov 2011 12:53:05 +0000 (13:53 +0100)
Since extended config space accesses may not be possible when
scan_pci_devices() runs (due to MMCFG resources not being reserved in
the E820 table, which the specification allows to be the case),
functionality enabling of which requires such must be re-attempted
when it is known whether MMCFG is safe to use.

Signed-off-by: Jan Beulich <jbeulich@suse.com>
Acked-by: "Kay, Allen M" <allen.m.kay@intel.com>
xen/drivers/passthrough/iommu.c
xen/drivers/passthrough/pci.c
xen/drivers/passthrough/vtd/iommu.c
xen/include/xen/iommu.h
xen/include/xen/pci.h

index 4fb8ba4c2e7cf115bf5cadcef9cfbb3e7ce5689a..cd6174df17b3299996348fda3d41a525d9f5f2e5 100644 (file)
@@ -150,6 +150,23 @@ int iommu_add_device(struct pci_dev *pdev)
     return hd->platform_ops->add_device(pdev);
 }
 
+int iommu_enable_device(struct pci_dev *pdev)
+{
+    struct hvm_iommu *hd;
+
+    if ( !pdev->domain )
+        return -EINVAL;
+
+    ASSERT(spin_is_locked(&pcidevs_lock));
+
+    hd = domain_hvm_iommu(pdev->domain);
+    if ( !iommu_enabled || !hd->platform_ops ||
+         !hd->platform_ops->enable_device )
+        return 0;
+
+    return hd->platform_ops->enable_device(pdev);
+}
+
 int iommu_remove_device(struct pci_dev *pdev)
 {
     struct hvm_iommu *hd;
index d0e2ae4cd0894e38480a3ad24c60c7f4515bed08..8edb707ae9ed54ae0aa0a49e599660cef2e45a65 100644 (file)
@@ -258,7 +258,7 @@ struct pci_dev *pci_get_pdev_by_domain(
  * pci_enable_acs - enable ACS if hardware support it
  * @dev: the PCI device
  */
-void pci_enable_acs(struct pci_dev *pdev)
+static void pci_enable_acs(struct pci_dev *pdev)
 {
     int pos;
     u16 cap, ctrl, seg = pdev->seg;
@@ -409,8 +409,11 @@ int pci_add_device(u16 seg, u8 bus, u8 devfn, const struct pci_dev_info *info)
         }
 
         list_add(&pdev->domain_list, &dom0->arch.pdev_list);
-        pci_enable_acs(pdev);
     }
+    else
+        iommu_enable_device(pdev);
+
+    pci_enable_acs(pdev);
 
 out:
     spin_unlock(&pcidevs_lock);
index d10a4f770f4538ba3bd1b01fdad5648cf4f1fc41..7717ab4ee960bc1a0e257977e31f14ea3b122542 100644 (file)
@@ -1900,6 +1900,19 @@ static int intel_iommu_add_device(struct pci_dev *pdev)
     return ret;
 }
 
+static int intel_iommu_enable_device(struct pci_dev *pdev)
+{
+    struct acpi_drhd_unit *drhd = acpi_find_matched_drhd_unit(pdev);
+    int ret = drhd ? ats_device(pdev, drhd) : -ENODEV;
+
+    if ( ret <= 0 )
+        return ret;
+
+    ret = enable_ats_device(pdev->seg, pdev->bus, pdev->devfn);
+
+    return ret >= 0 ? 0 : ret;
+}
+
 static int intel_iommu_remove_device(struct pci_dev *pdev)
 {
     struct acpi_rmrr_unit *rmrr;
@@ -1930,7 +1943,6 @@ static int intel_iommu_remove_device(struct pci_dev *pdev)
 static void __init setup_dom0_device(struct pci_dev *pdev)
 {
     domain_context_mapping(pdev->domain, pdev->seg, pdev->bus, pdev->devfn);
-    pci_enable_acs(pdev);
     pci_vtd_quirk(pdev);
 }
 
@@ -2301,6 +2313,7 @@ const struct iommu_ops intel_iommu_ops = {
     .init = intel_iommu_domain_init,
     .dom0_init = intel_iommu_dom0_init,
     .add_device = intel_iommu_add_device,
+    .enable_device = intel_iommu_enable_device,
     .remove_device = intel_iommu_remove_device,
     .assign_device  = intel_iommu_assign_device,
     .teardown = iommu_domain_teardown,
index e659e497257cec0e46ffc96ee50f35cc640811a0..837e60dc2820f0149b4360a65f62cc13828aa0f6 100644 (file)
@@ -70,6 +70,7 @@ int iommu_enable_x2apic_IR(void);
 void iommu_disable_x2apic_IR(void);
 
 int iommu_add_device(struct pci_dev *pdev);
+int iommu_enable_device(struct pci_dev *pdev);
 int iommu_remove_device(struct pci_dev *pdev);
 int iommu_domain_init(struct domain *d);
 void iommu_dom0_init(struct domain *d);
@@ -120,6 +121,7 @@ struct iommu_ops {
     int (*init)(struct domain *d);
     void (*dom0_init)(struct domain *d);
     int (*add_device)(struct pci_dev *pdev);
+    int (*enable_device)(struct pci_dev *pdev);
     int (*remove_device)(struct pci_dev *pdev);
     int (*assign_device)(struct domain *d, u16 seg, u8 bus, u8 devfn);
     void (*teardown)(struct domain *d);
index 462b4505b197295ff77f0f1b0d417fb3309694e3..edc9201991b083b5b05f177a26d522c13747e156 100644 (file)
@@ -134,6 +134,5 @@ struct pirq;
 int msixtbl_pt_register(struct domain *, struct pirq *, uint64_t gtable);
 void msixtbl_pt_unregister(struct domain *, struct pirq *);
 void msixtbl_pt_cleanup(struct domain *d);
-void pci_enable_acs(struct pci_dev *pdev);
 
 #endif /* __XEN_PCI_H__ */