xen/passthrough: Introduce iommu_construct
authorJulien Grall <julien.grall@linaro.org>
Tue, 28 Apr 2015 14:32:31 +0000 (15:32 +0100)
committerIan Campbell <ian.campbell@citrix.com>
Fri, 8 May 2015 14:41:58 +0000 (15:41 +0100)
This new function will correctly initialize the IOMMU page table for the
current domain.

Also use it in iommu_assign_dt_device even though the current IOMMU
implementation on ARM shares P2M with the processor.

Signed-off-by: Julien Grall <julien.grall@linaro.org>
Acked-by: Jan Beulich <jbeulich@suse.com>
Acked-by: Ian Campbell <ian.campbell@citrix.com>
xen/drivers/passthrough/arm/iommu.c
xen/drivers/passthrough/device_tree.c
xen/drivers/passthrough/iommu.c
xen/drivers/passthrough/pci.c
xen/include/xen/iommu.h

index 3007b992e7029d60a8feb1de440c08fcb60a3799..92346579a93c3cc501a44a8c28a5805eb4eb9633 100644 (file)
@@ -68,3 +68,9 @@ void arch_iommu_domain_destroy(struct domain *d)
 {
     iommu_dt_domain_destroy(d);
 }
+
+int arch_iommu_populate_page_table(struct domain *d)
+{
+    /* The IOMMU shares the p2m with the CPU */
+    return -ENOSYS;
+}
index 377d41d43bb583e0c0bf491249997836dbc08d2f..4d82a097594e4c669ca3e24461fd6961c608a7b6 100644 (file)
@@ -41,6 +41,18 @@ int iommu_assign_dt_device(struct domain *d, struct dt_device_node *dev)
     if ( !list_empty(&dev->domain_list) )
         goto fail;
 
+    if ( need_iommu(d) <= 0 )
+    {
+        /*
+         * The hwdom is forced to use IOMMU for protecting assigned
+         * device. Therefore the IOMMU data is already set up.
+         */
+        ASSERT(!is_hardware_domain(d));
+        rc = iommu_construct(d);
+        if ( rc )
+            goto fail;
+    }
+
     rc = hd->platform_ops->assign_device(d, 0, dt_to_dev(dev));
 
     if ( rc )
index 92ea26f8b49c60f3cdfcf57adaaa83380900e745..ae42aaefc49168c93de68f92300769d5cb98819a 100644 (file)
@@ -187,6 +187,32 @@ void iommu_teardown(struct domain *d)
     tasklet_schedule(&iommu_pt_cleanup_tasklet);
 }
 
+int iommu_construct(struct domain *d)
+{
+    if ( need_iommu(d) > 0 )
+        return 0;
+
+    if ( !iommu_use_hap_pt(d) )
+    {
+        int rc;
+
+        rc = arch_iommu_populate_page_table(d);
+        if ( rc )
+            return rc;
+    }
+
+    d->need_iommu = 1;
+    /*
+     * There may be dirty cache lines when a device is assigned
+     * and before need_iommu(d) becoming true, this will cause
+     * memory_type_changed lose effect if memory type changes.
+     * Call memory_type_changed here to amend this.
+     */
+    memory_type_changed(d);
+
+    return 0;
+}
+
 void iommu_domain_destroy(struct domain *d)
 {
     struct hvm_iommu *hd = domain_hvm_iommu(d);
index 9f3413c63f5d0da153bcd59371195d4e3bc9f4d4..af2642393f39fe0942f797c478bcc29bb368afdb 100644 (file)
@@ -1358,25 +1358,11 @@ static int assign_device(struct domain *d, u16 seg, u8 bus, u8 devfn)
     if ( !spin_trylock(&pcidevs_lock) )
         return -ERESTART;
 
-    if ( need_iommu(d) <= 0 )
+    rc = iommu_construct(d);
+    if ( rc )
     {
-        if ( !iommu_use_hap_pt(d) )
-        {
-            rc = arch_iommu_populate_page_table(d);
-            if ( rc )
-            {
-                spin_unlock(&pcidevs_lock);
-                return rc;
-            }
-        }
-        d->need_iommu = 1;
-        /*
-         * There may be dirty cache lines when a device is assigned
-         * and before need_iommu(d) becoming true, this will cause
-         * memory_type_changed lose effect if memory type changes.
-         * Call memory_type_changed here to amend this.
-         */
-        memory_type_changed(d);
+        spin_unlock(&pcidevs_lock);
+        return rc;
     }
 
     pdev = pci_get_pdev_by_domain(hardware_domain, seg, bus, devfn);
index bf4aff06d1d00eb0cbf52789350dff00c2aa94bb..e9d2d5c28023507881ecc8eb3b3d008fb0aeb692 100644 (file)
@@ -65,6 +65,8 @@ int arch_iommu_domain_init(struct domain *d);
 int arch_iommu_populate_page_table(struct domain *d);
 void arch_iommu_check_autotranslated_hwdom(struct domain *d);
 
+int iommu_construct(struct domain *d);
+
 /* Function used internally, use iommu_domain_destroy */
 void iommu_teardown(struct domain *d);