Re: [PATCH V2] xen/virtio: Handle PCI devices which Host controller is described in DT
From: Oleksandr Tyshchenko
Date: Fri Oct 21 2022 - 02:38:18 EST
On 21.10.22 09:08, Xenia Ragiadakou wrote:
Hello Xenia
> On 10/20/22 23:07, Oleksandr Tyshchenko wrote:
> Hi Oleksandr
>>
>> On 20.10.22 21:11, Xenia Ragiadakou wrote:
>>
>> Hello Xenia
>>
>>
>>> On 10/20/22 17:12, Oleksandr Tyshchenko wrote:
>>>>
>>>> On 20.10.22 11:24, Xenia Ragiadakou wrote:
>>>>> On 10/19/22 22:41, Oleksandr Tyshchenko wrote:
>>>>>
>>>>> Hi Oleksandr
>>>>
>>>>
>>>> Hello Xenia
>>>>
>>>>
>>>>>
>>>>>>
>>>>>> On 19.10.22 11:47, Xenia Ragiadakou wrote:
>>>>>>
>>>>>> Hello Xenia
>>>>>>
>>>>>>> On 10/19/22 03:58, Stefano Stabellini wrote:
>>>>>>>> On Sat, 15 Oct 2022, Oleksandr Tyshchenko wrote:
>>>>>>>>> From: Oleksandr Tyshchenko <oleksandr_tyshchenko@xxxxxxxx>
>>>>>>>>>
>>>>>>>>> Use the same "xen-grant-dma" device concept for the PCI devices
>>>>>>>>> behind device-tree based PCI Host controller, but with one
>>>>>>>>> modification.
>>>>>>>>> Unlike for platform devices, we cannot use generic IOMMU bindings
>>>>>>>>> (iommus property), as we need to support more flexible
>>>>>>>>> configuration.
>>>>>>>>> The problem is that PCI devices under the single PCI Host
>>>>>>>>> controller
>>>>>>>>> may have the backends running in different Xen domains and thus
>>>>>>>>> have
>>>>>>>>> different endpoints ID (backend domains ID).
>>>>>>>>>
>>>>>>>>> So use generic PCI-IOMMU bindings instead
>>>>>>>>> (iommu-map/iommu-map-mask
>>>>>>>>> properties) which allows us to describe relationship between PCI
>>>>>>>>> devices and backend domains ID properly.
>>>>>>>>>
>>>>>>>>> Signed-off-by: Oleksandr Tyshchenko
>>>>>>>>> <oleksandr_tyshchenko@xxxxxxxx>
>>>>>>>>
>>>>>>>> Now that I understood the approach and the reasons for it, I can
>>>>>>>> review
>>>>>>>> the patch :-)
>>>>>>>>
>>>>>>>> Please add an example of the bindings in the commit message.
>>>>>>>>
>>>>>>>>
>>>>>>>>> ---
>>>>>>>>> Slightly RFC. This is needed to support Xen grant mappings for
>>>>>>>>> virtio-pci devices
>>>>>>>>> on Arm at some point in the future. The Xen toolstack side is not
>>>>>>>>> completely ready yet.
>>>>>>>>> Here, for PCI devices we use more flexible way to pass backend
>>>>>>>>> domid
>>>>>>>>> to the guest
>>>>>>>>> than for platform devices.
>>>>>>>>>
>>>>>>>>> Changes V1 -> V2:
>>>>>>>>> - update commit description
>>>>>>>>> - rebase
>>>>>>>>> - rework to use generic PCI-IOMMU bindings instead of
>>>>>>>>> generic
>>>>>>>>> IOMMU bindings
>>>>>>>>>
>>>>>>>>> Previous discussion is at:
>>>>>>>>> https://urldefense.com/v3/__https://lore.kernel.org/xen-devel/20221006174804.2003029-1-olekstysh@xxxxxxxxx/__;!!GF_29dbcQIUBPA!3-vq7Edm3XfKtD5cnNjnOzDQvuo_XrhJ73yH-nPfqOkGGU0IjLG7R7MR_nAJCAPeOutHRLT44wKYwQwz3SauACie_ZAy$
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> [lore[.]kernel[.]org]
>>>>>>>>>
>>>>>>>>> Based on:
>>>>>>>>> https://urldefense.com/v3/__https://git.kernel.org/pub/scm/linux/kernel/git/xen/tip.git/log/?h=for-linus-6.1__;!!GF_29dbcQIUBPA!3-vq7Edm3XfKtD5cnNjnOzDQvuo_XrhJ73yH-nPfqOkGGU0IjLG7R7MR_nAJCAPeOutHRLT44wKYwQwz3SauAEnMDHAq$
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> [git[.]kernel[.]org]
>>>>>>>>> ---
>>>>>>>>> drivers/xen/grant-dma-ops.c | 87
>>>>>>>>> ++++++++++++++++++++++++++++++++-----
>>>>>>>>> 1 file changed, 76 insertions(+), 11 deletions(-)
>>>>>>>>>
>>>>>>>>> diff --git a/drivers/xen/grant-dma-ops.c
>>>>>>>>> b/drivers/xen/grant-dma-ops.c
>>>>>>>>> index daa525df7bdc..b79d9d6ce154 100644
>>>>>>>>> --- a/drivers/xen/grant-dma-ops.c
>>>>>>>>> +++ b/drivers/xen/grant-dma-ops.c
>>>>>>>>> @@ -10,6 +10,7 @@
>>>>>>>>> #include <linux/module.h>
>>>>>>>>> #include <linux/dma-map-ops.h>
>>>>>>>>> #include <linux/of.h>
>>>>>>>>> +#include <linux/pci.h>
>>>>>>>>> #include <linux/pfn.h>
>>>>>>>>> #include <linux/xarray.h>
>>>>>>>>> #include <linux/virtio_anchor.h>
>>>>>>>>> @@ -292,12 +293,55 @@ static const struct dma_map_ops
>>>>>>>>> xen_grant_dma_ops = {
>>>>>>>>> .dma_supported = xen_grant_dma_supported,
>>>>>>>>> };
>>>>>>>>> +static struct device_node *xen_dt_get_pci_host_node(struct
>>>>>>>>> device
>>>>>>>>> *dev)
>>>>>>>>> +{
>>>>>>>>> + struct pci_dev *pdev = to_pci_dev(dev);
>>>>>>>>> + struct pci_bus *bus = pdev->bus;
>>>>>>>>> +
>>>>>>>>> + /* Walk up to the root bus to look for PCI Host
>>>>>>>>> controller */
>>>>>>>>> + while (!pci_is_root_bus(bus))
>>>>>>>>> + bus = bus->parent;
>>>>>>>>> +
>>>>>>>>> + return of_node_get(bus->bridge->parent->of_node);
>>>>>>>>> +}
>>>>>>>>
>>>>>>>> It seems silly that we need to walk the hierachy that way, but I
>>>>>>>> couldn't find another way to do it
>>>>>>>>
>>>>>>>>
>>>>>>>>> +static struct device_node *xen_dt_get_node(struct device *dev)
>>>>>>>>> +{
>>>>>>>>> + if (dev_is_pci(dev))
>>>>>>>>> + return xen_dt_get_pci_host_node(dev);
>>>>>>>>> +
>>>>>>>>> + return of_node_get(dev->of_node);
>>>>>>>>> +}
>>>>>>>>> +
>>>>>>>>> +static int xen_dt_map_id(struct device *dev, struct device_node
>>>>>>>>> **iommu_np,
>>>>>>>>> + u32 *sid)
>>>>>>>>> +{
>>>>>>>>> + struct pci_dev *pdev = to_pci_dev(dev);
>>>>>>>>> + u32 rid = PCI_DEVID(pdev->bus->number, pdev->devfn);
>>>>>>>>> + struct device_node *host_np;
>>>>>>>>> + int ret;
>>>>>>>>> +
>>>>>>>>> + host_np = xen_dt_get_pci_host_node(dev);
>>>>>>>>> + if (!host_np)
>>>>>>>>> + return -ENODEV;
>>>>>>>>> +
>>>>>>>>> + ret = of_map_id(host_np, rid, "iommu-map", "iommu-map-mask",
>>>>>>>>> iommu_np, sid);
>>>>>>>>> + of_node_put(host_np);
>>>>>>>>> + return ret;
>>>>>>>>> +}
>>>>>>>>> +
>>>>>>>>> static bool xen_is_dt_grant_dma_device(struct device *dev)
>>>>>>>>> {
>>>>>>>>> - struct device_node *iommu_np;
>>>>>>>>> + struct device_node *iommu_np = NULL;
>>>>>>>>> bool has_iommu;
>>>>>>>>> - iommu_np = of_parse_phandle(dev->of_node, "iommus", 0);
>>>>>>>>> + if (dev_is_pci(dev)) {
>>>>>>>>> + if (xen_dt_map_id(dev, &iommu_np, NULL))
>>>>>>>>> + return false;
>>>>>>>>> + } else
>>>>>>>>> + iommu_np = of_parse_phandle(dev->of_node, "iommus", 0);
>>>>>>>>> +
>>>>>>>>> has_iommu = iommu_np &&
>>>>>>>>> of_device_is_compatible(iommu_np,
>>>>>>>>> "xen,grant-dma");
>>>>>>>>> of_node_put(iommu_np);
>>>>>>>>> @@ -307,9 +351,17 @@ static bool
>>>>>>>>> xen_is_dt_grant_dma_device(struct
>>>>>>>>> device *dev)
>>>>>>>>> bool xen_is_grant_dma_device(struct device *dev)
>>>>>>>>> {
>>>>>>>>> + struct device_node *np;
>>>>>>>>> +
>>>>>>>>> /* XXX Handle only DT devices for now */
>>>>>>>>> - if (dev->of_node)
>>>>>>>>> - return xen_is_dt_grant_dma_device(dev);
>>>>>>>>> + np = xen_dt_get_node(dev);
>>>>>>>>> + if (np) {
>>>>>>>>> + bool ret;
>>>>>>>>> +
>>>>>>>>> + ret = xen_is_dt_grant_dma_device(dev);
>>>>>>>>> + of_node_put(np);
>>>>>>>>> + return ret;
>>>>>>>>> + }
>>>>>>>>
>>>>>>>> We don't need to walk the PCI hierachy twice. Maybe we can add the
>>>>>>>> of_node check directly to xen_is_dt_grant_dma_device?
>>>>>>>>
>>>>>>>
>>>>>>> I think in general we could pass directly the host bridge device if
>>>>>>> dev_is_pci(dev) (which can be retrieved with
>>>>>>> pci_get_host_bridge_device(to_pci_dev(dev), and after done with it
>>>>>>> pci_put_host_bridge_device(phb)).
>>>>>>> So that, xen_is_dt_grant_dma_device() and
>>>>>>> xen_dt_grant_init_backend_domid() won't need to discover it
>>>>>>> themselves.
>>>>>>> This will simplify the code.
>>>>>>
>>>>>>
>>>>>> Good point. I have some remark. Can we use pci_find_host_bridge()
>>>>>> instead? This way we don't have to add #include "../pci/pci.h", and
>>>>>> have
>>>>>> to drop reference afterwards.
>>>>>>
>>>>>> With that xen_dt_get_pci_host_node() will became the following:
>>>>>>
>>>>>>
>>>>>> static struct device_node *xen_dt_get_pci_host_node(struct device
>>>>>> *dev)
>>>>>> {
>>>>>> struct pci_host_bridge *bridge =
>>>>>> pci_find_host_bridge(to_pci_dev(dev)->bus);
>>>>>>
>>>>>> return of_node_get(bridge->dev.parent->of_node);
>>>>>> }
>>>>>>
>>>>>
>>>>> You are right. I prefer your version instead of the above.
>>>>
>>>>
>>>> ok, thanks
>>>>
>>>>
>>>>>
>>>>>
>>>>>>
>>>>>> With Stefano's suggestion, we won't walk the PCI hierarchy twice
>>>>>> when
>>>>>> executing xen_is_grant_dma_device() for PCI device:
>>>>>>
>>>>>> xen_is_grant_dma_device() -> xen_is_dt_grant_dma_device() ->
>>>>>> xen_dt_map_id() -> xen_dt_get_pci_host_node()
>>>>>>
>>>>>>
>>>>>> What do you think?
>>>>>>
>>>>>
>>>>> I was thinking passing the device_node along with the device in the
>>>>> function arguments. More specifically, of doing this (not tested,
>>>>> just
>>>>> an idea):
>>>>>
>>>>> bool xen_is_grant_dma_device(struct device *dev)
>>>>> {
>>>>> struct device_node *np;
>>>>> bool has_iommu = false;
>>>>>
>>>>> /* XXX Handle only DT devices for now */
>>>>> np = xen_dt_get_node(dev);
>>>>> if (np)
>>>>> has_iommu = xen_is_dt_grant_dma_device(dev, np);
>>>>> of_node_put(np);
>>>>> return has_iommu;
>>>>> }
>>>>>
>>>>> static bool xen_is_dt_grant_dma_device(struct device *dev,
>>>>> struct device_node *np)
>>>>> {
>>>>> struct device_node *iommu_np = NULL;
>>>>> bool has_iommu;
>>>>>
>>>>> if (dev_is_pci(dev)) {
>>>>> struct pci_dev *pdev = to_pci_dev(dev);
>>>>> u32 id = PCI_DEVID(pdev->bus->number, pdev->devfn);
>>>>> of_map_id(np, id, "iommu-map", "iommu-map-mask", &iommu_np,
>>>>> NULL);
>>>>> } else {
>>>>> iommu_np = of_parse_phandle(np, "iommus", 0);
>>>>> }
>>>>>
>>>>> has_iommu = iommu_np && of_device_is_compatible(iommu_np,
>>>>> "xen,grant-dma");
>>>>> of_node_put(iommu_np);
>>>>>
>>>>> return has_iommu;
>>>>> }
>>>>
>>>>
>>>> I got it.
>>>>
>>>> xen_is_grant_dma_device() for V3 won't call xen_dt_get_node(), but
>>>> call
>>>> xen_is_dt_grant_dma_device() directly.
>>>>
>>>> static bool xen_is_dt_grant_dma_device(struct device *dev)
>>>> {
>>>> struct device_node *iommu_np = NULL;
>>>> bool has_iommu;
>>>>
>>>> if (dev_is_pci(dev)) {
>>>> if (xen_dt_map_id(dev, &iommu_np, NULL))
>>>> return false;
>>>> } else if (dev->of_node)
>>>> iommu_np = of_parse_phandle(dev->of_node, "iommus", 0);
>>>> else
>>>> return false;
>>>>
>>>> has_iommu = iommu_np &&
>>>> of_device_is_compatible(iommu_np, "xen,grant-dma");
>>>> of_node_put(iommu_np);
>>>>
>>>> return has_iommu;
>>>> }
>>>>
>>>> bool xen_is_grant_dma_device(struct device *dev)
>>>> {
>>>> /* XXX Handle only DT devices for now */
>>>> return xen_is_dt_grant_dma_device(dev);
>>>> }
>>>>
>>>>
>>>
>>> Ok. One difference, that I see from the previous, is that here you
>>> don't use the dynamic interface when you access the dev->of_node
>>> (of_node_get/of_node_put). Before, this was guarded through the
>>> external xen_dt_get_node().
>>>
>>> I suspect that the same needs to be done for the function
>>> xen_grant_setup_dma_ops(). There, also, the code walks up to the root
>>> bus twice.
>>
>>
>> Hmm, xen_dt_grant_init_backend_domid() should only be called if we deal
>> with device-tree based device.
>>
>> I think you are completely right, thanks!
>>
>> In order to address both your comments, I think I need to rework the
>> code (taking into the account your example with
>> xen_is_dt_grant_dma_device()
>>
>> provided a few letters ago and extrapolate this example to
>> xen_dt_grant_init_backend_domid()). Below the patch (not tested) which
>> seems to address both your comments (also I dropped
>>
>> xen_dt_map_id() and squashed xen_dt_get_pci_host_node() with
>> xen_dt_get_node()).
>>
>>
>> diff --git a/drivers/xen/grant-dma-ops.c b/drivers/xen/grant-dma-ops.c
>> index daa525df7bdc..dae24dbd2ef7 100644
>> --- a/drivers/xen/grant-dma-ops.c
>> +++ b/drivers/xen/grant-dma-ops.c
>> @@ -10,6 +10,7 @@
>> #include <linux/module.h>
>> #include <linux/dma-map-ops.h>
>> #include <linux/of.h>
>> +#include <linux/pci.h>
>> #include <linux/pfn.h>
>> #include <linux/xarray.h>
>> #include <linux/virtio_anchor.h>
>> @@ -292,12 +293,33 @@ static const struct dma_map_ops
>> xen_grant_dma_ops = {
>> .dma_supported = xen_grant_dma_supported,
>> };
>>
>> -static bool xen_is_dt_grant_dma_device(struct device *dev)
>> +static struct device_node *xen_dt_get_node(struct device *dev)
>> {
>> - struct device_node *iommu_np;
>> + if (dev_is_pci(dev)) {
>> + struct pci_dev *pdev = to_pci_dev(dev);
>> + struct pci_host_bridge *bridge =
>> pci_find_host_bridge(pdev->bus);
>> +
>> + return of_node_get(bridge->dev.parent->of_node);
>> + }
>> +
>> + return of_node_get(dev->of_node);
>> +}
>> +
>
> It does not seem right to me to expose the struct pci_host_bridge
> (which we would need to check if it is null by the way). I would
> prefer your version for the above i.e
> static struct device_node *xen_dt_get_node(struct device *dev)
> {
> if (dev_is_pci(dev)) {
> struct pci_bus *bus = to_pci_dev(dev)->bus;
>
> /* Walk up to the root bus to look for PCI Host controller */
> while (!pci_is_root_bus(bus))
> bus = bus->parent;
> return of_node_get(bus->bridge->parent->of_node);
> }
>
> return of_node_get(dev->of_node);
> }
ok, will return it back
>
>> +static bool xen_is_dt_grant_dma_device(struct device *dev,
>> + struct device_node *np)
>> +{
>> + struct device_node *iommu_np = NULL;
>> bool has_iommu;
>>
>> - iommu_np = of_parse_phandle(dev->of_node, "iommus", 0);
>> + if (dev_is_pci(dev)) {
>> + struct pci_dev *pdev = to_pci_dev(dev);
>> + u32 rid = PCI_DEVID(pdev->bus->number, pdev->devfn);
>> +
>> + if (of_map_id(np, rid, "iommu-map", "iommu-map-mask",
>> &iommu_np, NULL))
>> + return false;
>> + } else
>> + iommu_np = of_parse_phandle(np, "iommus", 0);
>> +
>> has_iommu = iommu_np &&
>> of_device_is_compatible(iommu_np,
>> "xen,grant-dma");
>> of_node_put(iommu_np);
>> @@ -307,9 +329,17 @@ static bool xen_is_dt_grant_dma_device(struct
>> device *dev)
>>
>> bool xen_is_grant_dma_device(struct device *dev)
>> {
>> + struct device_node *np;
>> +
>> /* XXX Handle only DT devices for now */
>> - if (dev->of_node)
>> - return xen_is_dt_grant_dma_device(dev);
>> + np = xen_dt_get_node(dev);
>> + if (np) {
>> + bool ret;
>> +
>> + ret = xen_is_dt_grant_dma_device(dev, np);
>> + of_node_put(np);
>> + return ret;
>> + }
>>
>> return false;
>> }
>
>> @@ -323,14 +353,26 @@ bool xen_virtio_mem_acc(struct virtio_device *dev)
>> }
>>
>> static int xen_dt_grant_init_backend_domid(struct device *dev,
>> + struct device_node *np,
>> struct
>> xen_grant_dma_data *data)
>> {
>> - struct of_phandle_args iommu_spec;
>> + struct of_phandle_args iommu_spec = { .args_count = 1 };
>>
>> - if (of_parse_phandle_with_args(dev->of_node, "iommus",
>> "#iommu-cells",
>> - 0, &iommu_spec)) {
>> - dev_err(dev, "Cannot parse iommus property\n");
>> - return -ESRCH;
>> + if (dev_is_pci(dev)) {
>> + struct pci_dev *pdev = to_pci_dev(dev);
>> + u32 rid = PCI_DEVID(pdev->bus->number, pdev->devfn);
>> +
>> + if (of_map_id(np, rid, "iommu-map", "iommu-map-mask",
>> &iommu_spec.np,
>> + iommu_spec.args)) {
>> + dev_err(dev, "Cannot translate ID\n");
>> + return -ESRCH;
>> + }
>> + } else {
>> + if (of_parse_phandle_with_args(np, "iommus",
>> "#iommu-cells",
>> + 0, &iommu_spec)) {
>> + dev_err(dev, "Cannot parse iommus property\n");
>> + return -ESRCH;
>> + }
>> }
>>
>
> IMO, instead of passing struct xen_grant_dma_data *data to
> xen_dt_grant_init_backend_domid(), you could pass domid_t
> *backend_domid (e.g xen_dt_grant_init_backend_domid(dev, np,
> &data->backend_domid)).
> I think this way the internal struct xen_grant_dma_datain is
> manipulated in a single place and xen_dt_grant_init_backend_domid()
> does not depend on it.
Although I think it is not directly related to current patch, I agree we
could make this change as we touch the list of arguments for
xen_dt_grant_init_backend_domid() anyway.
>
>
>> if (!of_device_is_compatible(iommu_spec.np,
>> "xen,grant-dma") ||
>> @@ -354,6 +396,7 @@ static int xen_dt_grant_init_backend_domid(struct
>> device *dev,
>> void xen_grant_setup_dma_ops(struct device *dev)
>> {
>> struct xen_grant_dma_data *data;
>> + struct device_node *np;
>>
>> data = find_xen_grant_dma_data(dev);
>> if (data) {
>> @@ -365,8 +408,13 @@ void xen_grant_setup_dma_ops(struct device *dev)
>> if (!data)
>> goto err;
>>
>> - if (dev->of_node) {
>> - if (xen_dt_grant_init_backend_domid(dev, data))
>> + np = xen_dt_get_node(dev);
>> + if (np) {
>> + int ret;
>> +
>> + ret = xen_dt_grant_init_backend_domid(dev, np, data);
>> + of_node_put(np);
>> + if (ret)
>> goto err;
>> } else if (IS_ENABLED(CONFIG_XEN_VIRTIO_FORCE_GRANT)) {
>> dev_info(dev, "Using dom0 as backend\n");
>>
>>
>> Does it look ok now?
>
> That is what I had in mind.
Great, thanks!
> I do not know if Stefano agrees with this approach.
We will see
>
>>>
>>>
>>>>>
>>>>> I 'm wondering ... is it possible for the host bridge device node to
>>>>> have the iommus property set? meaning that all of its pci devs will
>>>>> have the same backend?
>>>>
>>>> Good question. I think, it is possible... This is technically what
>>>> V1 is
>>>> doing.
>>>>
>>>>
>>>> Are you asking because to support "iommus" for PCI devices as well to
>>>> describe that use-case with all PCI devices having the same
>>>> endpoint ID
>>>> (backend ID)?
>>>> If yes, I think, this could be still described by "iommu-map"
>>>> property,
>>>> something like that (if we don't want to describe mapping for each PCI
>>>> device one-by-one).
>>>>
>>>> iommu-map = <0x0 &iommu X 0x1>;
>>>>
>>>> iommu-map-mask = <0x0>;
>>>>
>>>> where the X is backend ID.
>>>>
>>>>
>>>> It feels to me that it should be written down somewhere that for
>>>> platform devices we expect "iommus" and for PCI devices we expect
>>>> "iommu-map/iommu-map-mask" to be present.
>>>
>>> Thanks for the clarification, now I got it. Yes I agree.
>>
>>
>> ok, good
>>
>>
>>>
>>>>>
>>>>>
>>>>>>>
>>>>>>>>
>>>>>>>>> return false;
>>>>>>>>> }
>>>>>>>>> @@ -325,12 +377,19 @@ bool xen_virtio_mem_acc(struct
>>>>>>>>> virtio_device
>>>>>>>>> *dev)
>>>>>>>>> static int xen_dt_grant_init_backend_domid(struct device
>>>>>>>>> *dev,
>>>>>>>>> struct xen_grant_dma_data *data)
>>>>>>>>> {
>>>>>>>>> - struct of_phandle_args iommu_spec;
>>>>>>>>> + struct of_phandle_args iommu_spec = { .args_count = 1 };
>>>>>>>>> - if (of_parse_phandle_with_args(dev->of_node, "iommus",
>>>>>>>>> "#iommu-cells",
>>>>>>>>> - 0, &iommu_spec)) {
>>>>>>>>> - dev_err(dev, "Cannot parse iommus property\n");
>>>>>>>>> - return -ESRCH;
>>>>>>>>> + if (dev_is_pci(dev)) {
>>>>>>>>> + if (xen_dt_map_id(dev, &iommu_spec.np,
>>>>>>>>> iommu_spec.args)) {
>>>>>>>>> + dev_err(dev, "Cannot translate ID\n");
>>>>>>>>> + return -ESRCH;
>>>>>>>>> + }
>>>>>>>>> + } else {
>>>>>>>>> + if (of_parse_phandle_with_args(dev->of_node, "iommus",
>>>>>>>>> "#iommu-cells",
>>>>>>>>> + 0, &iommu_spec)) {
>>>>>>>>> + dev_err(dev, "Cannot parse iommus property\n");
>>>>>>>>> + return -ESRCH;
>>>>>>>>> + }
>>>>>>>>> }
>>>>>>>>> if (!of_device_is_compatible(iommu_spec.np,
>>>>>>>>> "xen,grant-dma") ||
>>>>>>>>> @@ -354,6 +413,7 @@ static int
>>>>>>>>> xen_dt_grant_init_backend_domid(struct device *dev,
>>>>>>>>> void xen_grant_setup_dma_ops(struct device *dev)
>>>>>>>>> {
>>>>>>>>> struct xen_grant_dma_data *data;
>>>>>>>>> + struct device_node *np;
>>>>>>>>> data = find_xen_grant_dma_data(dev);
>>>>>>>>> if (data) {
>>>>>>>>> @@ -365,8 +425,13 @@ void xen_grant_setup_dma_ops(struct device
>>>>>>>>> *dev)
>>>>>>>>> if (!data)
>>>>>>>>> goto err;
>>>>>>>>> - if (dev->of_node) {
>>>>>>>>> - if (xen_dt_grant_init_backend_domid(dev, data))
>>>>>>>>> + np = xen_dt_get_node(dev);
>>>>>>>>> + if (np) {
>>>>>>>>> + int ret;
>>>>>>>>> +
>>>>>>>>> + ret = xen_dt_grant_init_backend_domid(dev, data);
>>>>>>>>> + of_node_put(np);
>>>>>>>>> + if (ret)
>>>>>>>>> goto err;
>>>>>>>>> } else if (IS_ENABLED(CONFIG_XEN_VIRTIO_FORCE_GRANT)) {
>>>>>>>>> dev_info(dev, "Using dom0 as backend\n");
>>>>>>>>> --
>>>>>>>>> 2.25.1
>>>>>>>>>
>>>>>>>>
>>>>>>>
>>>>>
>>>
>
--
Regards,
Oleksandr Tyshchenko