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

[Xen-devel] [PATCH 1/2] xen: devicetree: Introduce a helper to translate PCI requester ID



Each PCI(e) device under a root complex is uniquely identified by its
Requester ID (AKA RID). A Requester ID is a triplet of a Bus number,
Device number, and Function number. IOMMUs may distinguish PCI devices
through sideband data derived from the Requester ID. While a given PCI
device can only master through one IOMMU, a root complex may split
masters across a set of IOMMUs.

The generic 'iommus' property is using to describe this relationship.
This helper will be used to parse and map PCI Requester ID to IOMMU
match ID in later patches.

This patch is based on Linux of_pci.c:
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/of/of_pci.c
The commit id is: 987068fcbdb7a085bb11151b91dc6f4c956c4a1b

Signed-off-by: Wei Chen <Wei.Chen@xxxxxxx>
---
 xen/common/device_tree.c      | 89 +++++++++++++++++++++++++++++++++++++++++++
 xen/include/xen/device_tree.h | 23 +++++++++++
 2 files changed, 112 insertions(+)

diff --git a/xen/common/device_tree.c b/xen/common/device_tree.c
index 7b009ea..bf95cda 100644
--- a/xen/common/device_tree.c
+++ b/xen/common/device_tree.c
@@ -1663,6 +1663,95 @@ int dt_parse_phandle_with_args(const struct 
dt_device_node *np,
                                         index, out_args);
 }
 
+#define pr_err(fmt, ...) printk(XENLOG_ERR fmt, ## __VA_ARGS__)
+#define pr_info(fmt, ...) printk(XENLOG_INFO fmt, ## __VA_ARGS__)
+#define pr_debug(fmt, ...) printk(XENLOG_DEBUG fmt, ## __VA_ARGS__)
+
+int dt_pci_map_rid(struct dt_device_node *np, u32 rid,
+           const char *map_name, const char *map_mask_name,
+           struct dt_device_node **target, u32 *id_out)
+{
+    u32 map_mask, masked_rid, map_len;
+    const __be32 *map = NULL;
+
+    if ( !np || !map_name || (!target && !id_out) )
+        return -EINVAL;
+
+    map = dt_get_property(np, map_name, &map_len);
+    if ( !map )
+    {
+        if (target)
+            return -ENODEV;
+        /* Otherwise, no map implies no translation */
+        *id_out = rid;
+        return 0;
+    }
+
+    if ( !map_len || map_len % (4 * sizeof(*map)) )
+    {
+        pr_err("%s: Error: Bad %s length: %d\n", np->full_name,
+               map_name, map_len);
+        return -EINVAL;
+    }
+
+    /*
+     * Can be overridden by "{iommu,msi}-map-mask" property.
+     * If of_property_read_u32() fails, the default is used.
+     */
+    if ( !map_mask_name ||
+         !dt_property_read_u32(np, map_mask_name, &map_mask) )
+        /* The default is to select all bits. */
+        map_mask = 0xffffffff;
+
+    masked_rid = map_mask & rid;
+    for ( ; map_len > 0; map_len -= 4 * sizeof(*map), map += 4 )
+    {
+        struct dt_device_node *phandle_node;
+        u32 rid_base = be32_to_cpup(map + 0);
+        u32 phandle = be32_to_cpup(map + 1);
+        u32 out_base = be32_to_cpup(map + 2);
+        u32 rid_len = be32_to_cpup(map + 3);
+
+        if ( rid_base & ~map_mask )
+        {
+            pr_err("%s: Invalid %s translation - %s-mask (0x%x) ignores 
rid-base (0x%x)\n",
+                    np->full_name, map_name, map_name,
+                    map_mask, rid_base);
+            return -EFAULT;
+        }
+
+        if ( masked_rid < rid_base || masked_rid >= rid_base + rid_len )
+            continue;
+
+        phandle_node = dt_find_node_by_phandle(phandle);
+        if ( !phandle_node )
+            return -ENODEV;
+
+        if ( target )
+        {
+            if ( *target == NULL )
+                *target = phandle_node;
+
+            if ( *target != phandle_node )
+                continue;
+        }
+
+        if ( id_out )
+            *id_out = masked_rid - rid_base + out_base;
+
+        pr_info("%s: %s, using mask %08x, rid-base: %08x, out-base: %08x, 
length: %08x, rid: %08x -> %08x\n",
+                np->full_name, map_name, map_mask, rid_base, out_base,
+                rid_len, rid, *id_out);
+        return 0;
+    }
+
+    pr_err("%s: Invalid %s translation - no match for rid 0x%x on %s\n",
+           np->full_name, map_name, rid,
+           target && *target ? (*target)->full_name : "any target");
+
+    return -EFAULT;
+}
+
 /**
  * unflatten_dt_node - Alloc and populate a device_node from the flat tree
  * @fdt: The parent device tree blob
diff --git a/xen/include/xen/device_tree.h b/xen/include/xen/device_tree.h
index 0aecbe0..0bddd7f 100644
--- a/xen/include/xen/device_tree.h
+++ b/xen/include/xen/device_tree.h
@@ -486,6 +486,29 @@ int dt_find_node_by_gpath(XEN_GUEST_HANDLE(char) u_path, 
uint32_t u_plen,
                           struct dt_device_node **node);
 
 /**
+ * dt_pci_map_rid - Translate a requester ID through a downstream mapping.
+ * @np: root complex device node.
+ * @rid: PCI requester ID to map.
+ * @map_name: property name of the map to use.
+ * @map_mask_name: optional property name of the mask to use.
+ * @target: optional pointer to a target device node.
+ * @id_out: optional pointer to receive the translated ID.
+ *
+ * Given a PCI requester ID, look up the appropriate implementation-defined
+ * platform ID and/or the target device which receives transactions on that
+ * ID, as per the "iommu-map" and "msi-map" bindings. Either of @target or
+ * @id_out may be NULL if only the other is required. If @target points to
+ * a non-NULL device node pointer, only entries targeting that node will be
+ * matched; if it points to a NULL value, it will receive the device node of
+ * the first matching target phandle, with a reference held.
+ *
+ * Return: 0 on success or a standard error code on failure.
+ */
+int dt_pci_map_rid(struct dt_device_node *np, u32 rid,
+           const char *map_name, const char *map_mask_name,
+           struct dt_device_node **target, u32 *id_out);
+
+/**
  * dt_get_parent - Get a node's parent if any
  * @node: Node to get parent
  *
-- 
2.7.4


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
https://lists.xen.org/xen-devel

 


Rackspace

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