[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [PATCH 1/2] xen: devicetree: Introduce a helper to translate PCI requester ID
On Fri, 30 Jun 2017, Wei Chen wrote: > 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__) I wouldn't define pr_* in device_tree.c just for this function. I would use printk(XENLOG_* directly and dt_dprintk. > +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) 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 |