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

[XEN][RFC PATCH v2 09/12] xen/arm: Implement device tree node addition functionalities


  • To: <xen-devel@xxxxxxxxxxxxxxxxxxxx>
  • From: Vikram Garhwal <fnu.vikram@xxxxxxxxxx>
  • Date: Mon, 8 Nov 2021 23:02:24 -0800
  • Arc-authentication-results: i=1; mx.microsoft.com 1; spf=pass (sender ip is 149.199.62.198) smtp.rcpttodomain=lists.xenproject.org smtp.mailfrom=xilinx.com; dmarc=pass (p=none sp=none pct=100) action=none header.from=xilinx.com; dkim=none (message not signed); arc=none
  • Arc-message-signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=wyrbSWuVg8mh72pt0EIeRsiFgh0ZFhFqclg9XrgPE/4=; b=g7FPXH2jJqWpJ4IuzNVeiwZqrGTUKKhm+6QCsJcMz4CQ9ItAuInxDStA/8jQfNDpfVd6LB7+1/cOQhoK33YlfDCAHwkWZfvL69DgpnKKRufxIgKW5WIhSxeM672Ni+g6yAg2AtQ9XGg+8kYmzcIYknyOuGZMrnagP0QvZvu5iXldPZl7Rj9xw6YT09wAKT84bQ6vnJbb3KreQT/Ou0lhvOKRE7B6k9fFCE2U+h4oQXr5vrLSX9eDFw6gObciJXDDwlgOcI3sOEa7kxN3egXykCfHmpUMP7yr3HRzkllCdkcTmIKgO6SRpFAqGMEeSAMijxVVpMLyPrQpieJItcDIVg==
  • Arc-seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=DQ/HRZVZRKHbJJj6B8yux5m0AaGx7aRxB7EwDCXGMprYHw6gZ8Gto5T1L9oH4hMw1SrihvlmBDCw3Rn6H3txqj+9JSMA+mrCgmgFg6Y44lHfqaVNsTtmAFMRyI5USGAEIeX8aHiaK/Kk/Yf5Sf+FwbZM6HxFz1o+q1rXzWsMHTPDymgORzgWg0pXfriOIbZFeW/K3uraZDYvLXwr32Dge0gjjImb1ycMeMzaxCCsqqKtsLDZtFq7iSoTjFRRwxtlWrxQz/NEK2BE8AXKK94Si3VZH4Myw+yDW7lEMpyOJLtSsLFU50GuzEXJ2IJMdnNEwJZEVFfCjyzKFpzjLt4WJw==
  • Cc: <sstabellini@xxxxxxxxxx>, <julien@xxxxxxx>, <bertrand.marquis@xxxxxxx>, <volodymyr_babchuk@xxxxxxxx>, Vikram Garhwal <fnu.vikram@xxxxxxxxxx>, Andrew Cooper <andrew.cooper3@xxxxxxxxxx>, George Dunlap <george.dunlap@xxxxxxxxxx>, Ian Jackson <iwj@xxxxxxxxxxxxxx>, Jan Beulich <jbeulich@xxxxxxxx>, Wei Liu <wl@xxxxxxx>
  • Delivery-date: Tue, 09 Nov 2021 07:03:11 +0000
  • List-id: Xen developer discussion <xen-devel.lists.xenproject.org>

Update sysctl XEN_SYSCTL_overlay to enable support for dtbo nodes addition using
device tree overlay.

xl overlay add file.dtbo:
    Each time overlay nodes are added using .dtbo, a new fdt(memcpy of
    device_tree_flattened) is created and updated with overlay nodes. This
    updated fdt is further unflattened to a dt_host_new. Next, it checks if any
    of the overlay nodes already exists in the dt_host. If overlay nodes doesn't
    exist then find the overlay nodes in dt_host_new, find the overlay node's
    parent in dt_host and add the nodes as child under their parent in the
    dt_host. The node is attached as the last node under target parent.

    Finally, add IRQs, add device to IOMMUs, set permissions and map MMIO for 
the
    overlay node.

When a node is added using overlay, a new entry is allocated in the
overlay_track to keep the track of memory allocation due to addition of overlay
node. This is helpful for freeing the memory allocated when a device tree node
is removed.

Signed-off-by: Vikram Garhwal <fnu.vikram@xxxxxxxxxx>
---
 xen/common/device_tree.c      |  41 +++++++++
 xen/common/sysctl.c           | 199 ++++++++++++++++++++++++++++++++++++++++++
 xen/include/xen/device_tree.h |   2 +
 3 files changed, 242 insertions(+)

diff --git a/xen/common/device_tree.c b/xen/common/device_tree.c
index 19320e1..5dff64c 100644
--- a/xen/common/device_tree.c
+++ b/xen/common/device_tree.c
@@ -386,6 +386,47 @@ void dt_print_node_names(struct dt_device_node *dt)
 }
 
 #if defined (CONFIG_OVERLAY_DTB)
+int overlay_add_node(struct dt_device_node *device_node,
+                  const char *parent_node_path)
+{
+    struct dt_device_node *parent_node;
+    struct dt_device_node *np;
+    struct dt_device_node *next_node;
+    struct dt_device_node *new_node;
+
+    parent_node = dt_find_node_by_path(parent_node_path);
+
+    new_node = device_node;
+
+    if ( new_node == NULL )
+        return -EINVAL;
+
+    if ( parent_node == NULL )
+    {
+        dt_dprintk("Node not found. Partial dtb will not be added");
+        return -EINVAL;
+    }
+
+    /*
+     * If node is found. We can attach the device_node as a child of the
+     * parent node. Iterate to the last child node of parent.
+     */
+
+    for ( np = parent_node->child; np->sibling != NULL; np = np->sibling )
+    {
+    }
+
+    next_node = np->allnext;
+    new_node->parent = parent_node;
+    np->sibling = new_node;
+    np->allnext = new_node;
+    /* Now plug next_node at the end of device_node. */
+    new_node->sibling = next_node;
+    new_node->allnext = next_node;
+    np->sibling->sibling = NULL;
+    return 0;
+}
+
 int overlay_remove_node(struct dt_device_node *device_node)
 {
     struct dt_device_node *np;
diff --git a/xen/common/sysctl.c b/xen/common/sysctl.c
index fca47f5..38824b2 100644
--- a/xen/common/sysctl.c
+++ b/xen/common/sysctl.c
@@ -331,6 +331,205 @@ out:
     spin_unlock(&overlay_lock);
     return rc;
 }
+
+/*
+ * Adds device tree nodes under target node.
+ * We use dt_host_new to unflatten the updated device_tree_flattened. This is
+ * done to avoid the removal of device_tree generation, iomem regions mapping 
to
+ * hardware domain done by handle_node().
+ */
+static long handle_add_overlay_nodes(void *overlay_fdt,
+                                     uint32_t overlay_fdt_size)
+{
+    int rc = 0;
+    struct dt_device_node *overlay_node;
+    char **node_full_path = NULL;
+    void *fdt = NULL;
+    struct dt_device_node *dt_host_new;
+    struct domain *d = hardware_domain;
+    struct overlay_track *tr = NULL;
+    unsigned int naddr;
+    unsigned int i, j;
+    int num_overlay_nodes;
+    u64 addr, size;
+
+    fdt = xmalloc_bytes(fdt_totalsize(device_tree_flattened));
+    if ( fdt == NULL )
+        return -ENOMEM;
+
+    num_overlay_nodes = overlay_node_count(overlay_fdt);
+    if ( num_overlay_nodes == 0 )
+        return -ENOMEM;
+
+    spin_lock(&overlay_lock);
+
+    memcpy(fdt, device_tree_flattened, fdt_totalsize(device_tree_flattened));
+
+    rc = check_overlay_fdt(overlay_fdt, overlay_fdt_size);
+    if ( rc )
+        goto err;
+
+    /*
+     * overlay_get_node_info is called to get the node information from dtbo.
+     * This is done before fdt_overlay_apply() because the overlay apply will
+     * erase the magic of overlay_fdt.
+     */
+    overlay_get_node_info(overlay_fdt, &node_full_path, num_overlay_nodes);
+
+    rc = fdt_overlay_apply(fdt, overlay_fdt);
+    if ( rc )
+    {
+        printk(XENLOG_ERR "Adding overlay node failed with error %d\n", rc);
+        goto err;
+    }
+
+    for ( j = 0; j < num_overlay_nodes; j++ ) {
+        /* Check if any of the node already exists in dt_host. */
+        overlay_node = dt_find_node_by_path(node_full_path[j]);
+        if ( overlay_node != NULL )
+        {
+            printk(XENLOG_ERR "node %s exists in device tree\n",
+                   node_full_path[j]);
+            rc = -EINVAL;
+            xfree(node_full_path);
+            goto err;
+        }
+    }
+
+    /* Unflatten the fdt into a new dt_host. */
+    unflatten_device_tree(fdt, &dt_host_new);
+
+    for ( j = 0; j < num_overlay_nodes; j++ ) {
+        dt_dprintk("Adding node: %s\n", node_full_path[j]);
+
+        /* Find the newly added node in dt_host_new by it's full path. */
+        overlay_node = _dt_find_node_by_path(dt_host_new, node_full_path[j]);
+        if ( overlay_node == NULL )
+        {
+            dt_dprintk("%s node not found\n", node_full_path[j]);
+            rc = -EFAULT;
+            goto remove_node;
+        }
+
+        /* Add the node to dt_host. */
+        rc = overlay_add_node(overlay_node, overlay_node->parent->full_name);
+        if ( rc )
+        {
+            /* Node not added in dt_host. */
+            goto remove_node;
+        }
+
+        /* Get the node from dt_host and add interrupt and IOMMUs. */
+        overlay_node = dt_find_node_by_path(overlay_node->full_name);
+        if ( overlay_node == NULL )
+        {
+            /* Sanity check. But code will never come here. */
+            printk(XENLOG_ERR "Cannot find %s node under updated dt_host\n",
+                   overlay_node->name);
+            goto remove_node;
+        }
+
+        /* First let's handle the interrupts. */
+        rc = handle_device_interrupts(d, overlay_node, false);
+        if ( rc )
+        {
+            printk(XENLOG_G_ERR "Interrupt failed\n");
+            goto remove_node;
+        }
+
+        /* Add device to IOMMUs */
+        rc = iommu_add_dt_device(overlay_node);
+        if ( rc < 0 )
+        {
+            printk(XENLOG_G_ERR "Failed to add %s to the IOMMU\n",
+                   dt_node_full_name(overlay_node));
+            goto remove_node;
+        }
+
+        /* Set permissions. */
+        naddr = dt_number_of_address(overlay_node);
+
+        dt_dprintk("%s passthrough = %d naddr = %u\n",
+                   dt_node_full_name(overlay_node), false, naddr);
+
+        /* Give permission and map MMIOs */
+        for ( i = 0; i < naddr; i++ )
+        {
+            struct map_range_data mr_data = { .d = d,
+                                              .p2mt = p2m_mmio_direct_c };
+            rc = dt_device_get_address(overlay_node, i, &addr, &size);
+            if ( rc )
+            {
+                printk(XENLOG_ERR "Unable to retrieve address %u for %s\n",
+                       i, dt_node_full_name(overlay_node));
+                goto remove_node;
+            }
+
+            rc = map_range_to_domain(overlay_node, addr, size, &mr_data);
+            if ( rc )
+                goto remove_node;
+        }
+    }
+
+    /* This will happen if everything above goes right. */
+    tr = xzalloc(struct overlay_track);
+    if ( tr == NULL )
+    {
+        rc = -ENOMEM;
+        goto remove_node;
+    }
+
+    tr->dt_host_new = dt_host_new;
+    tr->node_fullname = node_full_path;
+    tr->num_nodes = num_overlay_nodes;
+
+    if ( tr->node_fullname == NULL )
+    {
+        rc = -ENOMEM;
+        goto remove_node;
+    }
+
+    INIT_LIST_HEAD(&tr->entry);
+    list_add_tail(&tr->entry, &overlay_tracker);
+
+err:
+    spin_unlock(&overlay_lock);
+    xfree(fdt);
+    return rc;
+
+/*
+ * Failure case. We need to remove the nodes, free tracker(if tr exists) and
+ * dt_host_new.
+ */
+remove_node:
+    xfree(fdt);
+    rc = check_nodes(node_full_path, j);
+
+    if ( rc ) {
+        spin_unlock(&overlay_lock);
+        return rc;
+    }
+
+    rc = remove_nodes(node_full_path, j);
+
+    if ( rc ) {
+        printk(XENLOG_G_ERR "Removing node failed\n");
+        spin_unlock(&overlay_lock);
+        return rc;
+    }
+
+    spin_unlock(&overlay_lock);
+
+    xfree(dt_host_new);
+
+    if ( tr )
+        xfree(tr);
+
+    if ( node_full_path )
+        xfree(node_full_path);
+
+    return rc;
+}
 #endif
 
 long do_sysctl(XEN_GUEST_HANDLE_PARAM(xen_sysctl_t) u_sysctl)
diff --git a/xen/include/xen/device_tree.h b/xen/include/xen/device_tree.h
index cf29cf5..eafb269 100644
--- a/xen/include/xen/device_tree.h
+++ b/xen/include/xen/device_tree.h
@@ -554,6 +554,8 @@ int dt_find_node_by_gpath(XEN_GUEST_HANDLE(char) u_path, 
uint32_t u_plen,
 void dt_print_node_names(struct dt_device_node *dt);
 
 #if defined (CONFIG_OVERLAY_DTB)
+int overlay_add_node(struct dt_device_node *device_node,
+                  const char *parent_node_path);
 int overlay_remove_node(struct dt_device_node *device_node);
 #endif
 
-- 
2.7.4




 


Rackspace

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