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

[Xen-changelog] [xen staging] xen/arm: assign devices to boot domains



commit 9ce974c47588351069dfe49bac94682689b1d492
Author:     Stefano Stabellini <sstabellini@xxxxxxxxxx>
AuthorDate: Thu Oct 3 10:34:05 2019 -0700
Commit:     Stefano Stabellini <sstabellini@xxxxxxxxxx>
CommitDate: Fri Oct 4 10:16:11 2019 -0700

    xen/arm: assign devices to boot domains
    
    Scan the user provided dtb fragment at boot. For each device node, map
    memory to guests, and route interrupts and setup the iommu.
    
    The memory region to remap is specified by the "xen,reg" property.
    
    The iommu is setup by passing the node of the device to assign on the
    host device tree. The path is specified in the device tree fragment as
    the "xen,path" string property.
    
    The interrupts are remapped based on the information from the
    corresponding node on the host device tree. Call
    handle_device_interrupts to remap interrupts. Interrupts related device
    tree properties are copied from the device tree fragment, same as all
    the other properties.
    
    Require both xen,reg and xen,path to be present, unless
    xen,force-assign-without-iommu is also set. In that case, tolerate a
    missing xen,path, also tolerate iommu setup failure for the passthrough
    device.
    
    Also set add the new flag XEN_DOMCTL_CDF_iommu so that dom0less domU
    can use the IOMMU if a partial dtb is specified.
    
    Signed-off-by: Stefano Stabellini <stefanos@xxxxxxxxxx>
    Reviewed-by: Julien Grall <julien.grall@xxxxxxx>
---
 xen/arch/arm/domain_build.c | 147 ++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 143 insertions(+), 4 deletions(-)

diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c
index 89a99e1fd2..8cf3309784 100644
--- a/xen/arch/arm/domain_build.c
+++ b/xen/arch/arm/domain_build.c
@@ -1712,6 +1712,90 @@ static int __init make_vpl011_uart_node(struct 
kernel_info *kinfo)
 }
 #endif
 
+/*
+ * Scan device tree properties for passthrough specific information.
+ * Returns < 0 on error
+ *         0 on success
+ */
+static int __init handle_passthrough_prop(struct kernel_info *kinfo,
+                                          const struct fdt_property *xen_reg,
+                                          const struct fdt_property *xen_path,
+                                          bool xen_force,
+                                          uint32_t address_cells, uint32_t 
size_cells)
+{
+    const __be32 *cell;
+    unsigned int i, len;
+    struct dt_device_node *node;
+    int res;
+    paddr_t mstart, size, gstart;
+
+    /* xen,reg specifies where to map the MMIO region */
+    cell = (const __be32 *)xen_reg->data;
+    len = fdt32_to_cpu(xen_reg->len) / ((address_cells * 2 + size_cells) *
+                                        sizeof(uint32_t));
+
+    for ( i = 0; i < len; i++ )
+    {
+        device_tree_get_reg(&cell, address_cells, size_cells,
+                            &mstart, &size);
+        gstart = dt_next_cell(address_cells, &cell);
+
+        if ( gstart & ~PAGE_MASK || mstart & ~PAGE_MASK || size & ~PAGE_MASK )
+        {
+            printk(XENLOG_ERR
+                    "DomU passthrough config has not page aligned 
addresses/sizes\n");
+            return -EINVAL;
+        }
+
+        res = map_regions_p2mt(kinfo->d,
+                               gaddr_to_gfn(gstart),
+                               PFN_DOWN(size),
+                               maddr_to_mfn(mstart),
+                               p2m_mmio_direct_dev);
+        if ( res < 0 )
+        {
+            printk(XENLOG_ERR
+                   "Failed to map %"PRIpaddr" to the guest at%"PRIpaddr"\n",
+                   mstart, gstart);
+            return -EFAULT;
+        }
+    }
+
+    /*
+     * If xen_force, we let the user assign a MMIO region with no
+     * associated path.
+     */
+    if ( xen_path == NULL )
+        return xen_force ? 0 : -EINVAL;
+
+    /*
+     * xen,path specifies the corresponding node in the host DT.
+     * Both interrupt mappings and IOMMU settings are based on it,
+     * as they are done based on the corresponding host DT node.
+     */
+    node = dt_find_node_by_path(xen_path->data);
+    if ( node == NULL )
+    {
+        printk(XENLOG_ERR "Couldn't find node %s in host_dt!\n",
+               (char *)xen_path->data);
+        return -EINVAL;
+    }
+
+    res = handle_device_interrupts(kinfo->d, node, true);
+    if ( res < 0 )
+        return res;
+
+    res = iommu_add_dt_device(node);
+    if ( res < 0 )
+        return res;
+
+    /* If xen_force, we allow assignment of devices without IOMMU protection. 
*/
+    if ( xen_force && !dt_device_is_protected(node) )
+        return 0;
+
+    return iommu_assign_dt_device(kinfo->d, node);
+}
+
 static int __init handle_prop_pfdt(struct kernel_info *kinfo,
                                    const void *pfdt, int nodeoff,
                                    uint32_t address_cells, uint32_t size_cells,
@@ -1719,7 +1803,9 @@ static int __init handle_prop_pfdt(struct kernel_info 
*kinfo,
 {
     void *fdt = kinfo->fdt;
     int propoff, nameoff, res;
-    const struct fdt_property *prop;
+    const struct fdt_property *prop, *xen_reg = NULL, *xen_path = NULL;
+    const char *name;
+    bool found, xen_force = false;
 
     for ( propoff = fdt_first_property_offset(pfdt, nodeoff);
           propoff >= 0;
@@ -1728,11 +1814,61 @@ static int __init handle_prop_pfdt(struct kernel_info 
*kinfo,
         if ( !(prop = fdt_get_property_by_offset(pfdt, propoff, NULL)) )
             return -FDT_ERR_INTERNAL;
 
+        found = false;
         nameoff = fdt32_to_cpu(prop->nameoff);
-        res = fdt_property(fdt, fdt_string(pfdt, nameoff),
-                           prop->data, fdt32_to_cpu(prop->len));
-        if ( res )
+        name = fdt_string(pfdt, nameoff);
+
+        if ( scan_passthrough_prop )
+        {
+            if ( dt_prop_cmp("xen,reg", name) == 0 )
+            {
+                xen_reg = prop;
+                found = true;
+            }
+            else if ( dt_prop_cmp("xen,path", name) == 0 )
+            {
+                xen_path = prop;
+                found = true;
+            }
+            else if ( dt_prop_cmp("xen,force-assign-without-iommu",
+                                  name) == 0 )
+            {
+                xen_force = true;
+                found = true;
+            }
+        }
+
+        /*
+         * Copy properties other than the ones above: xen,reg, xen,path,
+         * and xen,force-assign-without-iommu.
+         */
+        if ( !found )
+        {
+            res = fdt_property(fdt, name, prop->data, fdt32_to_cpu(prop->len));
+            if ( res )
+                return res;
+        }
+    }
+
+    /*
+     * Only handle passthrough properties if both xen,reg and xen,path
+     * are present, or if xen,force-assign-without-iommu is specified.
+     */
+    if ( xen_reg != NULL && (xen_path != NULL || xen_force) )
+    {
+        res = handle_passthrough_prop(kinfo, xen_reg, xen_path, xen_force,
+                                      address_cells, size_cells);
+        if ( res < 0 )
+        {
+            printk(XENLOG_ERR "Failed to assign device to %pd\n", kinfo->d);
             return res;
+        }
+    }
+    else if ( (xen_path && !xen_reg) || (xen_reg && !xen_path && !xen_force) )
+    {
+        printk(XENLOG_ERR "xen,reg or xen,path missing for %pd\n",
+               kinfo->d);
+        return -EINVAL;
     }
 
     /* FDT_ERR_NOTFOUND => There is no more properties for this node */
@@ -2289,6 +2425,9 @@ void __init create_domUs(void)
             panic("Missing property 'cpus' for domain %s\n",
                   dt_node_name(node));
 
+        if ( dt_find_compatible_node(node, NULL, "multiboot,device-tree") )
+            d_cfg.flags |= XEN_DOMCTL_CDF_iommu;
+
         d = domain_create(++max_init_domid, &d_cfg, false);
         if ( IS_ERR(d) )
             panic("Error creating domain %s\n", dt_node_name(node));
--
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®.