[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-changelog] [xen staging] iommu/arm: Introduce iommu_add_dt_device API



commit 3e27f7d4cf434fd2cee6ecb5aeebf117e1e9572c
Author:     Oleksandr Tyshchenko <oleksandr_tyshchenko@xxxxxxxx>
AuthorDate: Thu Sep 26 14:20:33 2019 +0300
Commit:     Julien Grall <julien.grall@xxxxxxx>
CommitDate: Thu Sep 26 15:51:52 2019 +0100

    iommu/arm: Introduce iommu_add_dt_device API
    
    The main puprose of this patch is to add a way to register DT device
    (which is behind the IOMMU) using the generic IOMMU DT bindings [1]
    before assigning that device to a domain.
    
    So, this patch adds new "iommu_add_dt_device" API for adding DT device
    to the IOMMU using generic IOMMU DT bindings and previously added
    "iommu_fwspec" support. As devices can be assigned to the hardware domain
    and other domains this function is called from two places: handle_device()
    and iommu_do_dt_domctl().
    
    Besides that, this patch adds new "dt_xlate" callback (borrowed from
    Linux "of_xlate") for providing the driver with DT IOMMU specifier
    which describes the IOMMU master interfaces of that device (device IDs, 
etc).
    According to the generic IOMMU DT bindings the context of required
    properties for IOMMU device/master node (#iommu-cells, iommus) depends
    on many factors and is really driver depended thing.
    
    Please note, all IOMMU drivers which support generic IOMMU DT bindings
    should use "dt_xlate" and "add_device" callbacks.
    
    [1] 
https://www.kernel.org/doc/Documentation/devicetree/bindings/iommu/iommu.txt
    
    Signed-off-by: Oleksandr Tyshchenko <oleksandr_tyshchenko@xxxxxxxx>
    Acked-by: Julien Grall <julien.grall@xxxxxxx>
    Acked-by: Jan Beulich <jbeulich@xxxxxxxx>
---
 xen/arch/arm/domain_build.c           | 25 +++++++++---
 xen/drivers/passthrough/device_tree.c | 77 +++++++++++++++++++++++++++++++++++
 xen/include/xen/iommu.h               | 21 ++++++++++
 3 files changed, 118 insertions(+), 5 deletions(-)

diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c
index a0fee1ef13..b84a4483cc 100644
--- a/xen/arch/arm/domain_build.c
+++ b/xen/arch/arm/domain_build.c
@@ -1243,6 +1243,7 @@ static int __init map_device_children(struct domain *d,
  *  - Give permission to the guest to manage IRQ and MMIO range
  *  - Retrieve the IRQ configuration (i.e edge/level) from device tree
  * When the device is not marked for guest passthrough:
+ *  - Try to call iommu_add_dt_device to protect the device by an IOMMU
  *  - Assign the device to the guest if it's protected by an IOMMU
  *  - Map the IRQs and iomem regions to DOM0
  */
@@ -1263,16 +1264,30 @@ static int __init handle_device(struct domain *d, 
struct dt_device_node *dev,
     dt_dprintk("%s passthrough = %d nirq = %d naddr = %u\n",
                dt_node_full_name(dev), need_mapping, nirq, naddr);
 
-    if ( dt_device_is_protected(dev) && need_mapping )
+    if ( need_mapping )
     {
-        dt_dprintk("%s setup iommu\n", dt_node_full_name(dev));
-        res = iommu_assign_dt_device(d, dev);
-        if ( res )
+        dt_dprintk("Check if %s is behind the IOMMU and add it\n",
+                   dt_node_full_name(dev));
+
+        res = iommu_add_dt_device(dev);
+        if ( res < 0 )
         {
-            printk(XENLOG_ERR "Failed to setup the IOMMU for %s\n",
+            printk(XENLOG_ERR "Failed to add %s to the IOMMU\n",
                    dt_node_full_name(dev));
             return res;
         }
+
+        if ( dt_device_is_protected(dev) )
+        {
+            dt_dprintk("%s setup iommu\n", dt_node_full_name(dev));
+            res = iommu_assign_dt_device(d, dev);
+            if ( res )
+            {
+                printk(XENLOG_ERR "Failed to setup the IOMMU for %s\n",
+                       dt_node_full_name(dev));
+                return res;
+            }
+        }
     }
 
     /* Give permission and map IRQs */
diff --git a/xen/drivers/passthrough/device_tree.c 
b/xen/drivers/passthrough/device_tree.c
index 921a6e5f1e..cc900bac70 100644
--- a/xen/drivers/passthrough/device_tree.c
+++ b/xen/drivers/passthrough/device_tree.c
@@ -22,6 +22,8 @@
 #include <xen/sched.h>
 #include <xsm/xsm.h>
 
+#include <asm/iommu_fwspec.h>
+
 static spinlock_t dtdevs_lock = SPIN_LOCK_UNLOCKED;
 
 int iommu_assign_dt_device(struct domain *d, struct dt_device_node *dev)
@@ -125,6 +127,68 @@ int iommu_release_dt_devices(struct domain *d)
     return 0;
 }
 
+int iommu_add_dt_device(struct dt_device_node *np)
+{
+    const struct iommu_ops *ops = iommu_get_ops();
+    struct dt_phandle_args iommu_spec;
+    struct device *dev = dt_to_dev(np);
+    int rc = 1, index = 0;
+
+    if ( !iommu_enabled )
+        return 1;
+
+    if ( !ops )
+        return -EINVAL;
+
+    if ( dev_iommu_fwspec_get(dev) )
+        return -EEXIST;
+
+    /*
+     * According to the Documentation/devicetree/bindings/iommu/iommu.txt
+     * from Linux.
+     */
+    while ( !dt_parse_phandle_with_args(np, "iommus", "#iommu-cells",
+                                        index, &iommu_spec) )
+    {
+        /*
+         * The driver which supports generic IOMMU DT bindings must have
+         * these callback implemented.
+         */
+        if ( !ops->add_device || !ops->dt_xlate )
+            return -EINVAL;
+
+        if ( !dt_device_is_available(iommu_spec.np) )
+            break;
+
+        rc = iommu_fwspec_init(dev, &iommu_spec.np->dev);
+        if ( rc )
+            break;
+
+        /*
+         * Provide DT IOMMU specifier which describes the IOMMU master
+         * interfaces of that device (device IDs, etc) to the driver.
+         * The driver is responsible to decide how to interpret them.
+         */
+        rc = ops->dt_xlate(dev, &iommu_spec);
+        if ( rc )
+            break;
+
+        index++;
+    }
+
+    /*
+     * Add master device to the IOMMU if latter is present and available.
+     * The driver is responsible to mark that device as protected.
+     */
+    if ( !rc )
+        rc = ops->add_device(0, dev);
+
+    if ( rc < 0 )
+        iommu_fwspec_free(dev);
+
+    return rc;
+}
+
 int iommu_do_dt_domctl(struct xen_domctl *domctl, struct domain *d,
                        XEN_GUEST_HANDLE_PARAM(xen_domctl_t) u_domctl)
 {
@@ -166,6 +230,19 @@ int iommu_do_dt_domctl(struct xen_domctl *domctl, struct 
domain *d,
             break;
         }
 
+        ret = iommu_add_dt_device(dev);
+        /*
+         * Ignore "-EEXIST" error code as it would mean that the device is
+         * already added to the IOMMU (positive result). Such happens after
+         * re-creating guest domain.
+         */
+        if ( ret < 0 && ret != -EEXIST )
+        {
+            printk(XENLOG_G_ERR "Failed to add %s to the IOMMU\n",
+                   dt_node_full_name(dev));
+            break;
+        }
+
         ret = iommu_assign_dt_device(d, dev);
 
         if ( ret )
diff --git a/xen/include/xen/iommu.h b/xen/include/xen/iommu.h
index 7c3003f3f1..974bd3ffe8 100644
--- a/xen/include/xen/iommu.h
+++ b/xen/include/xen/iommu.h
@@ -182,6 +182,17 @@ int iommu_deassign_dt_device(struct domain *d, struct 
dt_device_node *dev);
 int iommu_dt_domain_init(struct domain *d);
 int iommu_release_dt_devices(struct domain *d);
 
+/*
+ * Helper to add master device to the IOMMU using generic IOMMU DT bindings.
+ *
+ * Return values:
+ *  0 : device is protected by an IOMMU
+ * <0 : device is not protected by an IOMMU, but must be (error condition)
+ * >0 : device doesn't need to be protected by an IOMMU
+ *      (IOMMU is not enabled/present or device is not connected to it).
+ */
+int iommu_add_dt_device(struct dt_device_node *np);
+
 int iommu_do_dt_domctl(struct xen_domctl *, struct domain *,
                        XEN_GUEST_HANDLE_PARAM(xen_domctl_t));
 
@@ -250,6 +261,16 @@ struct iommu_ops {
     int __must_check (*iotlb_flush_all)(struct domain *d);
     int (*get_reserved_device_memory)(iommu_grdm_t *, void *);
     void (*dump_p2m_table)(struct domain *d);
+
+#ifdef CONFIG_HAS_DEVICE_TREE
+    /*
+     * All IOMMU drivers which support generic IOMMU DT bindings should use
+     * this callback. This is a way for the framework to provide the driver
+     * with DT IOMMU specifier which describes the IOMMU master interfaces of
+     * that device (device IDs, etc).
+     */
+    int (*dt_xlate)(device_t *dev, const struct dt_phandle_args *args);
+#endif
 };
 
 #include <asm/iommu.h>
--
generated by git-patchbot for /home/xen/git/xen.git#staging

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxxx
https://lists.xenproject.org/xen-changelog

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.