Hello,

On 03/02/17 15:48, Sricharan R wrote:
> From: Robin Murphy <[email protected]>
> 
> In preparation for some upcoming cleverness, rework the control flow in
> of_iommu_configure() to minimise duplication and improve the propogation
> of errors. It's also as good a time as any to switch over from the
> now-just-a-compatibility-wrapper of_iommu_get_ops() to using the generic
> IOMMU instance interface directly.
> 
> Tested-by: Marek Szyprowski <[email protected]>
> Signed-off-by: Robin Murphy <[email protected]>
> ---
>  [*] Resolved a conflict while rebasing on top linux-next as the patch
>      is not there in mainline master.
> 
>         "iommu: Drop the of_iommu_{set/get}_ops() interface"
>         https://lkml.org/lkml/2017/1/3/489
> 
>  drivers/iommu/of_iommu.c | 83 
> +++++++++++++++++++++++++++++++-----------------
>  1 file changed, 53 insertions(+), 30 deletions(-)
> 
> diff --git a/drivers/iommu/of_iommu.c b/drivers/iommu/of_iommu.c
> index d7f480a..ee49081 100644
> --- a/drivers/iommu/of_iommu.c
> +++ b/drivers/iommu/of_iommu.c
> @@ -96,6 +96,28 @@ int of_get_dma_window(struct device_node *dn, const char 
> *prefix, int index,
>  }
>  EXPORT_SYMBOL_GPL(of_get_dma_window);
>  
> +static const struct iommu_ops
> +*of_iommu_xlate(struct device *dev, struct of_phandle_args *iommu_spec)
> +{
> +     const struct iommu_ops *ops;
> +     struct fwnode_handle *fwnode = &iommu_spec->np->fwnode;
> +     int err;
> +
> +     ops = iommu_get_instance(fwnode);
> +     if (!ops || !ops->of_xlate)
> +             return NULL;
> +
> +     err = iommu_fwspec_init(dev, &iommu_spec->np->fwnode, ops);
> +     if (err)
> +             return ERR_PTR(err);
> +
> +     err = ops->of_xlate(dev, iommu_spec);
> +     if (err)
> +             return ERR_PTR(err);
> +
> +     return ops;
> +}
> +
>  static int __get_pci_rid(struct pci_dev *pdev, u16 alias, void *data)
>  {
>       struct of_phandle_args *iommu_spec = data;
> @@ -105,10 +127,11 @@ static int __get_pci_rid(struct pci_dev *pdev, u16 
> alias, void *data)
>  }
>  
>  static const struct iommu_ops
> -*of_pci_iommu_configure(struct pci_dev *pdev, struct device_node *bridge_np)
> +*of_pci_iommu_init(struct pci_dev *pdev, struct device_node *bridge_np)
>  {
>       const struct iommu_ops *ops;
>       struct of_phandle_args iommu_spec;
> +     int err;
>  
>       /*
>        * Start by tracing the RID alias down the PCI topology as
> @@ -123,56 +146,56 @@ static int __get_pci_rid(struct pci_dev *pdev, u16 
> alias, void *data)
>        * bus into the system beyond, and which IOMMU it ends up at.
>        */
>       iommu_spec.np = NULL;
> -     if (of_pci_map_rid(bridge_np, iommu_spec.args[0], "iommu-map",
> -                        "iommu-map-mask", &iommu_spec.np, iommu_spec.args))
> -             return NULL;
> +     err = of_pci_map_rid(bridge_np, iommu_spec.args[0], "iommu-map",
> +                          "iommu-map-mask", &iommu_spec.np,
> +                          iommu_spec.args);
> +     if (err)
> +             return ERR_PTR(err);

This change doesn't work with of_pci_map_rid when the PCI RC isn't behind
an IOMMU:

        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;
        }

Previously with no iommu-map, we returned -ENODEV but it was discarded by
of_pci_iommu_configure. Now it is propagated and the whole device probing
fails. Instead, maybe of_pci_map_rid should always return 0 if no
iommu-map, and the caller should check if *target is still NULL?

Thanks,
Jean-Philippe

>  
> -     ops = iommu_get_instance(&iommu_spec.np->fwnode);
> -     if (!ops || !ops->of_xlate ||
> -         iommu_fwspec_init(&pdev->dev, &iommu_spec.np->fwnode, ops) ||
> -         ops->of_xlate(&pdev->dev, &iommu_spec))
> -             ops = NULL;
> +     ops = of_iommu_xlate(&pdev->dev, &iommu_spec);
>  
>       of_node_put(iommu_spec.np);
>       return ops;
>  }
>  
> -const struct iommu_ops *of_iommu_configure(struct device *dev,
> -                                        struct device_node *master_np)
> +static const struct iommu_ops
> +*of_platform_iommu_init(struct device *dev, struct device_node *np)
>  {
>       struct of_phandle_args iommu_spec;
> -     struct device_node *np;
>       const struct iommu_ops *ops = NULL;
>       int idx = 0;
>  
> -     if (dev_is_pci(dev))
> -             return of_pci_iommu_configure(to_pci_dev(dev), master_np);
> -
>       /*
>        * We don't currently walk up the tree looking for a parent IOMMU.
>        * See the `Notes:' section of
>        * Documentation/devicetree/bindings/iommu/iommu.txt
>        */
> -     while (!of_parse_phandle_with_args(master_np, "iommus",
> -                                        "#iommu-cells", idx,
> -                                        &iommu_spec)) {
> -             np = iommu_spec.np;
> -             ops = iommu_get_instance(&np->fwnode);
> -
> -             if (!ops || !ops->of_xlate ||
> -                 iommu_fwspec_init(dev, &np->fwnode, ops) ||
> -                 ops->of_xlate(dev, &iommu_spec))
> -                     goto err_put_node;
> -
> -             of_node_put(np);
> +     while (!of_parse_phandle_with_args(np, "iommus", "#iommu-cells",
> +                                        idx, &iommu_spec)) {
> +             ops = of_iommu_xlate(dev, &iommu_spec);
> +             of_node_put(iommu_spec.np);
>               idx++;
> +             if (IS_ERR_OR_NULL(ops))
> +                     break;
>       }
>  
>       return ops;
> +}
> +
> +const struct iommu_ops *of_iommu_configure(struct device *dev,
> +                                        struct device_node *master_np)
> +{
> +     const struct iommu_ops *ops;
> +
> +     if (!master_np)
> +             return NULL;
> +
> +     if (dev_is_pci(dev))
> +             ops = of_pci_iommu_init(to_pci_dev(dev), master_np);
> +     else
> +             ops = of_platform_iommu_init(dev, master_np);
>  
> -err_put_node:
> -     of_node_put(np);
> -     return NULL;
> +     return IS_ERR(ops) ? NULL : ops;
>  }
>  
>  static int __init of_iommu_init(void)
> 

_______________________________________________
iommu mailing list
[email protected]
https://lists.linuxfoundation.org/mailman/listinfo/iommu

Reply via email to