[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
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |