[PATCH V7 01/11] iommu/of: Refactor of_iommu_configure() for error handling
Tomasz Nowicki
tn at semihalf.com
Wed Jan 25 10:13:20 PST 2017
Hi Robin,
On 25.01.2017 18:35, Robin Murphy wrote:
> Hi Tomasz,
>
> On 25/01/17 17:17, Tomasz Nowicki wrote:
>> Hi Sricharan,
>>
>> On 23.01.2017 17:18, Sricharan R wrote:
>>> From: Robin Murphy <robin.murphy at arm.com>
>>>
>>> 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.
>>>
>>> Signed-off-by: Robin Murphy <robin.murphy at arm.com>
>>> ---
>>> 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 0f57ddc..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);
>>>
>>> - ops = of_iommu_get_ops(iommu_spec.np);
>>> - 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 = of_iommu_get_ops(np);
>>> -
>>> - 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);
>> I gave the whole patch set a try on ThunderX. really_probe() is failing
>> on dma_configure()->of_pci_iommu_init() for each PCI device.
> When you say "failing", do you mean cleanly, or with a crash? I've
> managed to hit __of_match_node() dereferencing NULL from
> of_iommu_xlate() in a horribly complicated chain of events, which I'm
> trying to figure out now, and I wonder if the two might be related.
>
Cleanly, of_pci_iommu_init()->of_pci_map_rid() can't find "iommu-map"
property for my case. Probably not related to your crash.
Thanks,
Tomasz
More information about the linux-arm-kernel
mailing list