Message ID | 1523960514-25457-3-git-send-email-nipun.gupta@nxp.com (mailing list archive) |
---|---|
State | New, archived |
Delegated to: | Bjorn Helgaas |
Headers | show |
On 17/04/18 11:21, Nipun Gupta wrote: > iommu-map property is also used by devices with fsl-mc. This > patch moves the of_pci_map_rid to generic location, so that it > can be used by other busses too. > > Signed-off-by: Nipun Gupta <nipun.gupta@nxp.com> > --- > drivers/iommu/of_iommu.c | 106 +++++++++++++++++++++++++++++++++++++++++++++-- Doesn't this break "msi-parent" parsing for !CONFIG_OF_IOMMU? I guess you don't want fsl-mc to have to depend on PCI, but this looks like a step in the wrong direction. I'm not entirely sure where of_map_rid() fits best, but from a quick look around the least-worst option might be drivers/of/of_address.c, unless Rob and Frank have a better idea of where generic DT-based ID translation routines could live? > drivers/of/irq.c | 6 +-- > drivers/pci/of.c | 101 -------------------------------------------- > include/linux/of_iommu.h | 11 +++++ > include/linux/of_pci.h | 10 ----- > 5 files changed, 117 insertions(+), 117 deletions(-) > > diff --git a/drivers/iommu/of_iommu.c b/drivers/iommu/of_iommu.c > index 5c36a8b..4e7712f 100644 > --- a/drivers/iommu/of_iommu.c > +++ b/drivers/iommu/of_iommu.c > @@ -138,6 +138,106 @@ static int of_iommu_xlate(struct device *dev, > return ops->of_xlate(dev, iommu_spec); > } > > +/** > + * of_map_rid - Translate a requester ID through a downstream mapping. > + * @np: root complex device node. > + * @rid: device 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 device 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 of_map_rid(struct device_node *np, u32 rid, > + const char *map_name, const char *map_mask_name, > + struct device_node **target, u32 *id_out) > +{ > + u32 map_mask, masked_rid; > + int map_len; > + const __be32 *map = NULL; > + > + if (!np || !map_name || (!target && !id_out)) > + return -EINVAL; > + > + map = of_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("%pOF: Error: Bad %s length: %d\n", np, > + map_name, map_len); > + return -EINVAL; > + } > + > + /* The default is to select all bits. */ > + map_mask = 0xffffffff; > + > + /* > + * Can be overridden by "{iommu,msi}-map-mask" property. > + */ > + if (map_mask_name) > + of_property_read_u32(np, map_mask_name, &map_mask); > + > + masked_rid = map_mask & rid; > + for ( ; map_len > 0; map_len -= 4 * sizeof(*map), map += 4) { > + struct 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("%pOF: Invalid %s translation - %s-mask (0x%x) ignores rid-base (0x%x)\n", > + np, map_name, map_name, > + map_mask, rid_base); > + return -EFAULT; > + } > + > + if (masked_rid < rid_base || masked_rid >= rid_base + rid_len) > + continue; > + > + phandle_node = of_find_node_by_phandle(phandle); > + if (!phandle_node) > + return -ENODEV; > + > + if (target) { > + if (*target) > + of_node_put(phandle_node); > + else > + *target = phandle_node; > + > + if (*target != phandle_node) > + continue; > + } > + > + if (id_out) > + *id_out = masked_rid - rid_base + out_base; > + > + pr_debug("%pOF: %s, using mask %08x, rid-base: %08x, out-base: %08x, length: %08x, rid: %08x -> %08x\n", > + np, map_name, map_mask, rid_base, out_base, > + rid_len, rid, masked_rid - rid_base + out_base); > + return 0; > + } > + > + pr_err("%pOF: Invalid %s translation - no match for rid 0x%x on %pOF\n", > + np, map_name, rid, target && *target ? *target : NULL); > + return -EFAULT; > +} > + > struct of_pci_iommu_alias_info { > struct device *dev; > struct device_node *np; > @@ -149,9 +249,9 @@ static int of_pci_iommu_init(struct pci_dev *pdev, u16 alias, void *data) > struct of_phandle_args iommu_spec = { .args_count = 1 }; > int err; > > - err = of_pci_map_rid(info->np, alias, "iommu-map", > - "iommu-map-mask", &iommu_spec.np, > - iommu_spec.args); > + err = of_map_rid(info->np, alias, "iommu-map", > + "iommu-map-mask", &iommu_spec.np, > + iommu_spec.args); Super-nit: Apparently I missed rewrapping this to 2 lines in d87beb749281, but if it's being touched again, that would be nice ;) Robin. > if (err) > return err == -ENODEV ? NO_IOMMU : err; > > diff --git a/drivers/of/irq.c b/drivers/of/irq.c > index 02ad93a..b72eeec 100644 > --- a/drivers/of/irq.c > +++ b/drivers/of/irq.c > @@ -22,7 +22,7 @@ > #include <linux/module.h> > #include <linux/of.h> > #include <linux/of_irq.h> > -#include <linux/of_pci.h> > +#include <linux/of_iommu.h> > #include <linux/string.h> > #include <linux/slab.h> > > @@ -588,8 +588,8 @@ static u32 __of_msi_map_rid(struct device *dev, struct device_node **np, > * "msi-map" property. > */ > for (parent_dev = dev; parent_dev; parent_dev = parent_dev->parent) > - if (!of_pci_map_rid(parent_dev->of_node, rid_in, "msi-map", > - "msi-map-mask", np, &rid_out)) > + if (!of_map_rid(parent_dev->of_node, rid_in, "msi-map", > + "msi-map-mask", np, &rid_out)) > break; > return rid_out; > } > diff --git a/drivers/pci/of.c b/drivers/pci/of.c > index a28355c..d2cebbe 100644 > --- a/drivers/pci/of.c > +++ b/drivers/pci/of.c > @@ -362,107 +362,6 @@ int of_pci_get_host_bridge_resources(struct device_node *dev, > EXPORT_SYMBOL_GPL(of_pci_get_host_bridge_resources); > #endif /* CONFIG_OF_ADDRESS */ > > -/** > - * of_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 of_pci_map_rid(struct device_node *np, u32 rid, > - const char *map_name, const char *map_mask_name, > - struct device_node **target, u32 *id_out) > -{ > - u32 map_mask, masked_rid; > - int map_len; > - const __be32 *map = NULL; > - > - if (!np || !map_name || (!target && !id_out)) > - return -EINVAL; > - > - map = of_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("%pOF: Error: Bad %s length: %d\n", np, > - map_name, map_len); > - return -EINVAL; > - } > - > - /* The default is to select all bits. */ > - map_mask = 0xffffffff; > - > - /* > - * Can be overridden by "{iommu,msi}-map-mask" property. > - * If of_property_read_u32() fails, the default is used. > - */ > - if (map_mask_name) > - of_property_read_u32(np, map_mask_name, &map_mask); > - > - masked_rid = map_mask & rid; > - for ( ; map_len > 0; map_len -= 4 * sizeof(*map), map += 4) { > - struct 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("%pOF: Invalid %s translation - %s-mask (0x%x) ignores rid-base (0x%x)\n", > - np, map_name, map_name, > - map_mask, rid_base); > - return -EFAULT; > - } > - > - if (masked_rid < rid_base || masked_rid >= rid_base + rid_len) > - continue; > - > - phandle_node = of_find_node_by_phandle(phandle); > - if (!phandle_node) > - return -ENODEV; > - > - if (target) { > - if (*target) > - of_node_put(phandle_node); > - else > - *target = phandle_node; > - > - if (*target != phandle_node) > - continue; > - } > - > - if (id_out) > - *id_out = masked_rid - rid_base + out_base; > - > - pr_debug("%pOF: %s, using mask %08x, rid-base: %08x, out-base: %08x, length: %08x, rid: %08x -> %08x\n", > - np, map_name, map_mask, rid_base, out_base, > - rid_len, rid, masked_rid - rid_base + out_base); > - return 0; > - } > - > - pr_err("%pOF: Invalid %s translation - no match for rid 0x%x on %pOF\n", > - np, map_name, rid, target && *target ? *target : NULL); > - return -EFAULT; > -} > - > #if IS_ENABLED(CONFIG_OF_IRQ) > /** > * of_irq_parse_pci - Resolve the interrupt for a PCI device > diff --git a/include/linux/of_iommu.h b/include/linux/of_iommu.h > index 4fa654e..432b53c 100644 > --- a/include/linux/of_iommu.h > +++ b/include/linux/of_iommu.h > @@ -15,6 +15,10 @@ extern int of_get_dma_window(struct device_node *dn, const char *prefix, > extern const struct iommu_ops *of_iommu_configure(struct device *dev, > struct device_node *master_np); > > +int of_map_rid(struct device_node *np, u32 rid, > + const char *map_name, const char *map_mask_name, > + struct device_node **target, u32 *id_out); > + > #else > > static inline int of_get_dma_window(struct device_node *dn, const char *prefix, > @@ -30,6 +34,13 @@ static inline const struct iommu_ops *of_iommu_configure(struct device *dev, > return NULL; > } > > +static inline int of_map_rid(struct device_node *np, u32 rid, > + const char *map_name, const char *map_mask_name, > + struct device_node **target, u32 *id_out) > +{ > + return -EINVAL; > +} > + > #endif /* CONFIG_OF_IOMMU */ > > extern struct of_device_id __iommu_of_table; > diff --git a/include/linux/of_pci.h b/include/linux/of_pci.h > index 091033a..a23b44a 100644 > --- a/include/linux/of_pci.h > +++ b/include/linux/of_pci.h > @@ -17,9 +17,6 @@ struct device_node *of_pci_find_child_device(struct device_node *parent, > int of_get_pci_domain_nr(struct device_node *node); > int of_pci_get_max_link_speed(struct device_node *node); > void of_pci_check_probe_only(void); > -int of_pci_map_rid(struct device_node *np, u32 rid, > - const char *map_name, const char *map_mask_name, > - struct device_node **target, u32 *id_out); > #else > static inline struct device_node *of_pci_find_child_device(struct device_node *parent, > unsigned int devfn) > @@ -44,13 +41,6 @@ static inline int of_pci_get_devfn(struct device_node *np) > return -1; > } > > -static inline int of_pci_map_rid(struct device_node *np, u32 rid, > - const char *map_name, const char *map_mask_name, > - struct device_node **target, u32 *id_out) > -{ > - return -EINVAL; > -} > - > static inline int > of_pci_get_max_link_speed(struct device_node *node) > { >
> -----Original Message----- > From: Robin Murphy [mailto:robin.murphy@arm.com] > Sent: Tuesday, April 17, 2018 10:23 PM > To: Nipun Gupta <nipun.gupta@nxp.com>; robh+dt@kernel.org; > frowand.list@gmail.com > Cc: will.deacon@arm.com; mark.rutland@arm.com; catalin.marinas@arm.com; > hch@lst.de; gregkh@linuxfoundation.org; joro@8bytes.org; > m.szyprowski@samsung.com; shawnguo@kernel.org; bhelgaas@google.com; > iommu@lists.linux-foundation.org; linux-kernel@vger.kernel.org; > devicetree@vger.kernel.org; linux-arm-kernel@lists.infradead.org; linuxppc- > dev@lists.ozlabs.org; linux-pci@vger.kernel.org; Bharat Bhushan > <bharat.bhushan@nxp.com>; stuyoder@gmail.com; Laurentiu Tudor > <laurentiu.tudor@nxp.com>; Leo Li <leoyang.li@nxp.com> > Subject: Re: [PATCH 2/6 v2] iommu: of: make of_pci_map_rid() available for > other devices too > > On 17/04/18 11:21, Nipun Gupta wrote: > > iommu-map property is also used by devices with fsl-mc. This patch > > moves the of_pci_map_rid to generic location, so that it can be used > > by other busses too. Nipun, please clarify that only function name is changed and rest of body is same. > > > > Signed-off-by: Nipun Gupta <nipun.gupta@nxp.com> > > --- > > drivers/iommu/of_iommu.c | 106 > > +++++++++++++++++++++++++++++++++++++++++++++-- > > Doesn't this break "msi-parent" parsing for !CONFIG_OF_IOMMU? Yes, this will be a problem with MSI > I guess you > don't want fsl-mc to have to depend on PCI, but this looks like a step in the > wrong direction. > > I'm not entirely sure where of_map_rid() fits best, but from a quick look around > the least-worst option might be drivers/of/of_address.c, unless Rob and Frank > have a better idea of where generic DT-based ID translation routines could live? drivers/of/address.c may be proper place to move until someone have better idea. Thanks -Bharat > > > drivers/of/irq.c | 6 +-- > > drivers/pci/of.c | 101 -------------------------------------------- > > include/linux/of_iommu.h | 11 +++++ > > include/linux/of_pci.h | 10 ----- > > 5 files changed, 117 insertions(+), 117 deletions(-) > > > > diff --git a/drivers/iommu/of_iommu.c b/drivers/iommu/of_iommu.c index > > 5c36a8b..4e7712f 100644 > > --- a/drivers/iommu/of_iommu.c > > +++ b/drivers/iommu/of_iommu.c > > @@ -138,6 +138,106 @@ static int of_iommu_xlate(struct device *dev, > > return ops->of_xlate(dev, iommu_spec); > > } > > > > +/** > > + * of_map_rid - Translate a requester ID through a downstream mapping. > > + * @np: root complex device node. > > + * @rid: device 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 device 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 of_map_rid(struct device_node *np, u32 rid, > > + const char *map_name, const char *map_mask_name, > > + struct device_node **target, u32 *id_out) { > > + u32 map_mask, masked_rid; > > + int map_len; > > + const __be32 *map = NULL; > > + > > + if (!np || !map_name || (!target && !id_out)) > > + return -EINVAL; > > + > > + map = of_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("%pOF: Error: Bad %s length: %d\n", np, > > + map_name, map_len); > > + return -EINVAL; > > + } > > + > > + /* The default is to select all bits. */ > > + map_mask = 0xffffffff; > > + > > + /* > > + * Can be overridden by "{iommu,msi}-map-mask" property. > > + */ > > + if (map_mask_name) > > + of_property_read_u32(np, map_mask_name, &map_mask); > > + > > + masked_rid = map_mask & rid; > > + for ( ; map_len > 0; map_len -= 4 * sizeof(*map), map += 4) { > > + struct 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("%pOF: Invalid %s translation - %s-mask (0x%x) > ignores rid-base (0x%x)\n", > > + np, map_name, map_name, > > + map_mask, rid_base); > > + return -EFAULT; > > + } > > + > > + if (masked_rid < rid_base || masked_rid >= rid_base + rid_len) > > + continue; > > + > > + phandle_node = of_find_node_by_phandle(phandle); > > + if (!phandle_node) > > + return -ENODEV; > > + > > + if (target) { > > + if (*target) > > + of_node_put(phandle_node); > > + else > > + *target = phandle_node; > > + > > + if (*target != phandle_node) > > + continue; > > + } > > + > > + if (id_out) > > + *id_out = masked_rid - rid_base + out_base; > > + > > + pr_debug("%pOF: %s, using mask %08x, rid-base: %08x, out- > base: %08x, length: %08x, rid: %08x -> %08x\n", > > + np, map_name, map_mask, rid_base, out_base, > > + rid_len, rid, masked_rid - rid_base + out_base); > > + return 0; > > + } > > + > > + pr_err("%pOF: Invalid %s translation - no match for rid 0x%x on > %pOF\n", > > + np, map_name, rid, target && *target ? *target : NULL); > > + return -EFAULT; > > +} > > + > > struct of_pci_iommu_alias_info { > > struct device *dev; > > struct device_node *np; > > @@ -149,9 +249,9 @@ static int of_pci_iommu_init(struct pci_dev *pdev, u16 > alias, void *data) > > struct of_phandle_args iommu_spec = { .args_count = 1 }; > > int err; > > > > - err = of_pci_map_rid(info->np, alias, "iommu-map", > > - "iommu-map-mask", &iommu_spec.np, > > - iommu_spec.args); > > + err = of_map_rid(info->np, alias, "iommu-map", > > + "iommu-map-mask", &iommu_spec.np, > > + iommu_spec.args); > > Super-nit: Apparently I missed rewrapping this to 2 lines in d87beb749281, but if > it's being touched again, that would be nice ;) > > Robin. > > > if (err) > > return err == -ENODEV ? NO_IOMMU : err; > > > > diff --git a/drivers/of/irq.c b/drivers/of/irq.c index > > 02ad93a..b72eeec 100644 > > --- a/drivers/of/irq.c > > +++ b/drivers/of/irq.c > > @@ -22,7 +22,7 @@ > > #include <linux/module.h> > > #include <linux/of.h> > > #include <linux/of_irq.h> > > -#include <linux/of_pci.h> > > +#include <linux/of_iommu.h> > > #include <linux/string.h> > > #include <linux/slab.h> > > > > @@ -588,8 +588,8 @@ static u32 __of_msi_map_rid(struct device *dev, > struct device_node **np, > > * "msi-map" property. > > */ > > for (parent_dev = dev; parent_dev; parent_dev = parent_dev->parent) > > - if (!of_pci_map_rid(parent_dev->of_node, rid_in, "msi-map", > > - "msi-map-mask", np, &rid_out)) > > + if (!of_map_rid(parent_dev->of_node, rid_in, "msi-map", > > + "msi-map-mask", np, &rid_out)) > > break; > > return rid_out; > > } > > diff --git a/drivers/pci/of.c b/drivers/pci/of.c index > > a28355c..d2cebbe 100644 > > --- a/drivers/pci/of.c > > +++ b/drivers/pci/of.c > > @@ -362,107 +362,6 @@ int of_pci_get_host_bridge_resources(struct > device_node *dev, > > EXPORT_SYMBOL_GPL(of_pci_get_host_bridge_resources); > > #endif /* CONFIG_OF_ADDRESS */ > > > > -/** > > - * of_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 of_pci_map_rid(struct device_node *np, u32 rid, > > - const char *map_name, const char *map_mask_name, > > - struct device_node **target, u32 *id_out) > > -{ > > - u32 map_mask, masked_rid; > > - int map_len; > > - const __be32 *map = NULL; > > - > > - if (!np || !map_name || (!target && !id_out)) > > - return -EINVAL; > > - > > - map = of_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("%pOF: Error: Bad %s length: %d\n", np, > > - map_name, map_len); > > - return -EINVAL; > > - } > > - > > - /* The default is to select all bits. */ > > - map_mask = 0xffffffff; > > - > > - /* > > - * Can be overridden by "{iommu,msi}-map-mask" property. > > - * If of_property_read_u32() fails, the default is used. > > - */ > > - if (map_mask_name) > > - of_property_read_u32(np, map_mask_name, &map_mask); > > - > > - masked_rid = map_mask & rid; > > - for ( ; map_len > 0; map_len -= 4 * sizeof(*map), map += 4) { > > - struct 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("%pOF: Invalid %s translation - %s-mask (0x%x) > ignores rid-base (0x%x)\n", > > - np, map_name, map_name, > > - map_mask, rid_base); > > - return -EFAULT; > > - } > > - > > - if (masked_rid < rid_base || masked_rid >= rid_base + rid_len) > > - continue; > > - > > - phandle_node = of_find_node_by_phandle(phandle); > > - if (!phandle_node) > > - return -ENODEV; > > - > > - if (target) { > > - if (*target) > > - of_node_put(phandle_node); > > - else > > - *target = phandle_node; > > - > > - if (*target != phandle_node) > > - continue; > > - } > > - > > - if (id_out) > > - *id_out = masked_rid - rid_base + out_base; > > - > > - pr_debug("%pOF: %s, using mask %08x, rid-base: %08x, out- > base: %08x, length: %08x, rid: %08x -> %08x\n", > > - np, map_name, map_mask, rid_base, out_base, > > - rid_len, rid, masked_rid - rid_base + out_base); > > - return 0; > > - } > > - > > - pr_err("%pOF: Invalid %s translation - no match for rid 0x%x on > %pOF\n", > > - np, map_name, rid, target && *target ? *target : NULL); > > - return -EFAULT; > > -} > > - > > #if IS_ENABLED(CONFIG_OF_IRQ) > > /** > > * of_irq_parse_pci - Resolve the interrupt for a PCI device diff > > --git a/include/linux/of_iommu.h b/include/linux/of_iommu.h index > > 4fa654e..432b53c 100644 > > --- a/include/linux/of_iommu.h > > +++ b/include/linux/of_iommu.h > > @@ -15,6 +15,10 @@ extern int of_get_dma_window(struct device_node > *dn, const char *prefix, > > extern const struct iommu_ops *of_iommu_configure(struct device *dev, > > struct device_node *master_np); > > > > +int of_map_rid(struct device_node *np, u32 rid, > > + const char *map_name, const char *map_mask_name, > > + struct device_node **target, u32 *id_out); > > + > > #else > > > > static inline int of_get_dma_window(struct device_node *dn, const > > char *prefix, @@ -30,6 +34,13 @@ static inline const struct iommu_ops > *of_iommu_configure(struct device *dev, > > return NULL; > > } > > > > +static inline int of_map_rid(struct device_node *np, u32 rid, > > + const char *map_name, const char > *map_mask_name, > > + struct device_node **target, u32 *id_out) { > > + return -EINVAL; > > +} > > + > > #endif /* CONFIG_OF_IOMMU */ > > > > extern struct of_device_id __iommu_of_table; diff --git > > a/include/linux/of_pci.h b/include/linux/of_pci.h index > > 091033a..a23b44a 100644 > > --- a/include/linux/of_pci.h > > +++ b/include/linux/of_pci.h > > @@ -17,9 +17,6 @@ struct device_node *of_pci_find_child_device(struct > device_node *parent, > > int of_get_pci_domain_nr(struct device_node *node); > > int of_pci_get_max_link_speed(struct device_node *node); > > void of_pci_check_probe_only(void); > > -int of_pci_map_rid(struct device_node *np, u32 rid, > > - const char *map_name, const char *map_mask_name, > > - struct device_node **target, u32 *id_out); > > #else > > static inline struct device_node *of_pci_find_child_device(struct device_node > *parent, > > unsigned int devfn) > > @@ -44,13 +41,6 @@ static inline int of_pci_get_devfn(struct device_node > *np) > > return -1; > > } > > > > -static inline int of_pci_map_rid(struct device_node *np, u32 rid, > > - const char *map_name, const char *map_mask_name, > > - struct device_node **target, u32 *id_out) > > -{ > > - return -EINVAL; > > -} > > - > > static inline int > > of_pci_get_max_link_speed(struct device_node *node) > > { > >
> -----Original Message----- > From: Robin Murphy [mailto:robin.murphy@arm.com] > Sent: Tuesday, April 17, 2018 10:23 PM > To: Nipun Gupta <nipun.gupta@nxp.com>; robh+dt@kernel.org; > frowand.list@gmail.com > Cc: will.deacon@arm.com; mark.rutland@arm.com; catalin.marinas@arm.com; > hch@lst.de; gregkh@linuxfoundation.org; joro@8bytes.org; > m.szyprowski@samsung.com; shawnguo@kernel.org; bhelgaas@google.com; > iommu@lists.linux-foundation.org; linux-kernel@vger.kernel.org; > devicetree@vger.kernel.org; linux-arm-kernel@lists.infradead.org; linuxppc- > dev@lists.ozlabs.org; linux-pci@vger.kernel.org; Bharat Bhushan > <bharat.bhushan@nxp.com>; stuyoder@gmail.com; Laurentiu Tudor > <laurentiu.tudor@nxp.com>; Leo Li <leoyang.li@nxp.com> > Subject: Re: [PATCH 2/6 v2] iommu: of: make of_pci_map_rid() available for > other devices too > > On 17/04/18 11:21, Nipun Gupta wrote: > > iommu-map property is also used by devices with fsl-mc. This patch > > moves the of_pci_map_rid to generic location, so that it can be used > > by other busses too. > > > > Signed-off-by: Nipun Gupta <nipun.gupta@nxp.com> > > --- > > drivers/iommu/of_iommu.c | 106 > > +++++++++++++++++++++++++++++++++++++++++++++-- > > Doesn't this break "msi-parent" parsing for !CONFIG_OF_IOMMU? I guess you > don't want fsl-mc to have to depend on PCI, but this looks like a step in the > wrong direction. Thanks for pointing out. Agree, this will break "msi-parent" parsing for !CONFIG_OF_IOMMU case. > > I'm not entirely sure where of_map_rid() fits best, but from a quick look around > the least-worst option might be drivers/of/of_address.c, unless Rob and Frank > have a better idea of where generic DT-based ID translation routines could live? > > > drivers/of/irq.c | 6 +-- > > drivers/pci/of.c | 101 -------------------------------------------- > > include/linux/of_iommu.h | 11 +++++ > > include/linux/of_pci.h | 10 ----- > > 5 files changed, 117 insertions(+), 117 deletions(-) > > [...] > > struct of_pci_iommu_alias_info { > > struct device *dev; > > struct device_node *np; > > @@ -149,9 +249,9 @@ static int of_pci_iommu_init(struct pci_dev *pdev, u16 > alias, void *data) > > struct of_phandle_args iommu_spec = { .args_count = 1 }; > > int err; > > > > - err = of_pci_map_rid(info->np, alias, "iommu-map", > > - "iommu-map-mask", &iommu_spec.np, > > - iommu_spec.args); > > + err = of_map_rid(info->np, alias, "iommu-map", > > + "iommu-map-mask", &iommu_spec.np, > > + iommu_spec.args); > > Super-nit: Apparently I missed rewrapping this to 2 lines in d87beb749281, but if > it's being touched again, that would be nice ;) Sure.. I'll take care of this in the next version :) Regards, Nipun
diff --git a/drivers/iommu/of_iommu.c b/drivers/iommu/of_iommu.c index 5c36a8b..4e7712f 100644 --- a/drivers/iommu/of_iommu.c +++ b/drivers/iommu/of_iommu.c @@ -138,6 +138,106 @@ static int of_iommu_xlate(struct device *dev, return ops->of_xlate(dev, iommu_spec); } +/** + * of_map_rid - Translate a requester ID through a downstream mapping. + * @np: root complex device node. + * @rid: device 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 device 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 of_map_rid(struct device_node *np, u32 rid, + const char *map_name, const char *map_mask_name, + struct device_node **target, u32 *id_out) +{ + u32 map_mask, masked_rid; + int map_len; + const __be32 *map = NULL; + + if (!np || !map_name || (!target && !id_out)) + return -EINVAL; + + map = of_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("%pOF: Error: Bad %s length: %d\n", np, + map_name, map_len); + return -EINVAL; + } + + /* The default is to select all bits. */ + map_mask = 0xffffffff; + + /* + * Can be overridden by "{iommu,msi}-map-mask" property. + */ + if (map_mask_name) + of_property_read_u32(np, map_mask_name, &map_mask); + + masked_rid = map_mask & rid; + for ( ; map_len > 0; map_len -= 4 * sizeof(*map), map += 4) { + struct 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("%pOF: Invalid %s translation - %s-mask (0x%x) ignores rid-base (0x%x)\n", + np, map_name, map_name, + map_mask, rid_base); + return -EFAULT; + } + + if (masked_rid < rid_base || masked_rid >= rid_base + rid_len) + continue; + + phandle_node = of_find_node_by_phandle(phandle); + if (!phandle_node) + return -ENODEV; + + if (target) { + if (*target) + of_node_put(phandle_node); + else + *target = phandle_node; + + if (*target != phandle_node) + continue; + } + + if (id_out) + *id_out = masked_rid - rid_base + out_base; + + pr_debug("%pOF: %s, using mask %08x, rid-base: %08x, out-base: %08x, length: %08x, rid: %08x -> %08x\n", + np, map_name, map_mask, rid_base, out_base, + rid_len, rid, masked_rid - rid_base + out_base); + return 0; + } + + pr_err("%pOF: Invalid %s translation - no match for rid 0x%x on %pOF\n", + np, map_name, rid, target && *target ? *target : NULL); + return -EFAULT; +} + struct of_pci_iommu_alias_info { struct device *dev; struct device_node *np; @@ -149,9 +249,9 @@ static int of_pci_iommu_init(struct pci_dev *pdev, u16 alias, void *data) struct of_phandle_args iommu_spec = { .args_count = 1 }; int err; - err = of_pci_map_rid(info->np, alias, "iommu-map", - "iommu-map-mask", &iommu_spec.np, - iommu_spec.args); + err = of_map_rid(info->np, alias, "iommu-map", + "iommu-map-mask", &iommu_spec.np, + iommu_spec.args); if (err) return err == -ENODEV ? NO_IOMMU : err; diff --git a/drivers/of/irq.c b/drivers/of/irq.c index 02ad93a..b72eeec 100644 --- a/drivers/of/irq.c +++ b/drivers/of/irq.c @@ -22,7 +22,7 @@ #include <linux/module.h> #include <linux/of.h> #include <linux/of_irq.h> -#include <linux/of_pci.h> +#include <linux/of_iommu.h> #include <linux/string.h> #include <linux/slab.h> @@ -588,8 +588,8 @@ static u32 __of_msi_map_rid(struct device *dev, struct device_node **np, * "msi-map" property. */ for (parent_dev = dev; parent_dev; parent_dev = parent_dev->parent) - if (!of_pci_map_rid(parent_dev->of_node, rid_in, "msi-map", - "msi-map-mask", np, &rid_out)) + if (!of_map_rid(parent_dev->of_node, rid_in, "msi-map", + "msi-map-mask", np, &rid_out)) break; return rid_out; } diff --git a/drivers/pci/of.c b/drivers/pci/of.c index a28355c..d2cebbe 100644 --- a/drivers/pci/of.c +++ b/drivers/pci/of.c @@ -362,107 +362,6 @@ int of_pci_get_host_bridge_resources(struct device_node *dev, EXPORT_SYMBOL_GPL(of_pci_get_host_bridge_resources); #endif /* CONFIG_OF_ADDRESS */ -/** - * of_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 of_pci_map_rid(struct device_node *np, u32 rid, - const char *map_name, const char *map_mask_name, - struct device_node **target, u32 *id_out) -{ - u32 map_mask, masked_rid; - int map_len; - const __be32 *map = NULL; - - if (!np || !map_name || (!target && !id_out)) - return -EINVAL; - - map = of_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("%pOF: Error: Bad %s length: %d\n", np, - map_name, map_len); - return -EINVAL; - } - - /* The default is to select all bits. */ - map_mask = 0xffffffff; - - /* - * Can be overridden by "{iommu,msi}-map-mask" property. - * If of_property_read_u32() fails, the default is used. - */ - if (map_mask_name) - of_property_read_u32(np, map_mask_name, &map_mask); - - masked_rid = map_mask & rid; - for ( ; map_len > 0; map_len -= 4 * sizeof(*map), map += 4) { - struct 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("%pOF: Invalid %s translation - %s-mask (0x%x) ignores rid-base (0x%x)\n", - np, map_name, map_name, - map_mask, rid_base); - return -EFAULT; - } - - if (masked_rid < rid_base || masked_rid >= rid_base + rid_len) - continue; - - phandle_node = of_find_node_by_phandle(phandle); - if (!phandle_node) - return -ENODEV; - - if (target) { - if (*target) - of_node_put(phandle_node); - else - *target = phandle_node; - - if (*target != phandle_node) - continue; - } - - if (id_out) - *id_out = masked_rid - rid_base + out_base; - - pr_debug("%pOF: %s, using mask %08x, rid-base: %08x, out-base: %08x, length: %08x, rid: %08x -> %08x\n", - np, map_name, map_mask, rid_base, out_base, - rid_len, rid, masked_rid - rid_base + out_base); - return 0; - } - - pr_err("%pOF: Invalid %s translation - no match for rid 0x%x on %pOF\n", - np, map_name, rid, target && *target ? *target : NULL); - return -EFAULT; -} - #if IS_ENABLED(CONFIG_OF_IRQ) /** * of_irq_parse_pci - Resolve the interrupt for a PCI device diff --git a/include/linux/of_iommu.h b/include/linux/of_iommu.h index 4fa654e..432b53c 100644 --- a/include/linux/of_iommu.h +++ b/include/linux/of_iommu.h @@ -15,6 +15,10 @@ extern int of_get_dma_window(struct device_node *dn, const char *prefix, extern const struct iommu_ops *of_iommu_configure(struct device *dev, struct device_node *master_np); +int of_map_rid(struct device_node *np, u32 rid, + const char *map_name, const char *map_mask_name, + struct device_node **target, u32 *id_out); + #else static inline int of_get_dma_window(struct device_node *dn, const char *prefix, @@ -30,6 +34,13 @@ static inline const struct iommu_ops *of_iommu_configure(struct device *dev, return NULL; } +static inline int of_map_rid(struct device_node *np, u32 rid, + const char *map_name, const char *map_mask_name, + struct device_node **target, u32 *id_out) +{ + return -EINVAL; +} + #endif /* CONFIG_OF_IOMMU */ extern struct of_device_id __iommu_of_table; diff --git a/include/linux/of_pci.h b/include/linux/of_pci.h index 091033a..a23b44a 100644 --- a/include/linux/of_pci.h +++ b/include/linux/of_pci.h @@ -17,9 +17,6 @@ struct device_node *of_pci_find_child_device(struct device_node *parent, int of_get_pci_domain_nr(struct device_node *node); int of_pci_get_max_link_speed(struct device_node *node); void of_pci_check_probe_only(void); -int of_pci_map_rid(struct device_node *np, u32 rid, - const char *map_name, const char *map_mask_name, - struct device_node **target, u32 *id_out); #else static inline struct device_node *of_pci_find_child_device(struct device_node *parent, unsigned int devfn) @@ -44,13 +41,6 @@ static inline int of_pci_get_devfn(struct device_node *np) return -1; } -static inline int of_pci_map_rid(struct device_node *np, u32 rid, - const char *map_name, const char *map_mask_name, - struct device_node **target, u32 *id_out) -{ - return -EINVAL; -} - static inline int of_pci_get_max_link_speed(struct device_node *node) {
iommu-map property is also used by devices with fsl-mc. This patch moves the of_pci_map_rid to generic location, so that it can be used by other busses too. Signed-off-by: Nipun Gupta <nipun.gupta@nxp.com> --- drivers/iommu/of_iommu.c | 106 +++++++++++++++++++++++++++++++++++++++++++++-- drivers/of/irq.c | 6 +-- drivers/pci/of.c | 101 -------------------------------------------- include/linux/of_iommu.h | 11 +++++ include/linux/of_pci.h | 10 ----- 5 files changed, 117 insertions(+), 117 deletions(-)