diff mbox

[2/6,v2] iommu: of: make of_pci_map_rid() available for other devices too

Message ID 1523960514-25457-3-git-send-email-nipun.gupta@nxp.com (mailing list archive)
State New, archived
Delegated to: Bjorn Helgaas
Headers show

Commit Message

Nipun Gupta April 17, 2018, 10:21 a.m. UTC
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(-)

Comments

Robin Murphy April 17, 2018, 4:52 p.m. UTC | #1
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)
>   {
>
Bharat Bhushan April 18, 2018, 5:09 a.m. UTC | #2
> -----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)

> >   {

> >
Nipun Gupta April 18, 2018, 6:21 a.m. UTC | #3
> -----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 mbox

Patch

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)
 {