diff options
Diffstat (limited to 'drivers/xen')
-rw-r--r-- | drivers/xen/grant-dma-ops.c | 46 |
1 files changed, 39 insertions, 7 deletions
diff --git a/drivers/xen/grant-dma-ops.c b/drivers/xen/grant-dma-ops.c index 1e797a043980..9784a77fa3c9 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,15 +293,43 @@ static const struct dma_map_ops xen_grant_dma_ops = { .dma_supported = xen_grant_dma_supported, }; +static struct device_node *xen_dt_get_node(struct device *dev) +{ + if (dev_is_pci(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); + } + + return of_node_get(dev->of_node); +} + static int xen_dt_grant_init_backend_domid(struct device *dev, + struct device_node *np, domid_t *backend_domid) { - 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_dbg(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_dbg(dev, "Cannot translate ID\n"); + return -ESRCH; + } + } else { + if (of_parse_phandle_with_args(np, "iommus", "#iommu-cells", + 0, &iommu_spec)) { + dev_dbg(dev, "Cannot parse iommus property\n"); + return -ESRCH; + } } if (!of_device_is_compatible(iommu_spec.np, "xen,grant-dma") || @@ -324,10 +353,13 @@ static int xen_dt_grant_init_backend_domid(struct device *dev, static int xen_grant_init_backend_domid(struct device *dev, domid_t *backend_domid) { + struct device_node *np; int ret = -ENODEV; - if (dev->of_node) { - ret = xen_dt_grant_init_backend_domid(dev, backend_domid); + np = xen_dt_get_node(dev); + if (np) { + ret = xen_dt_grant_init_backend_domid(dev, np, backend_domid); + of_node_put(np); } else if (IS_ENABLED(CONFIG_XEN_VIRTIO_FORCE_GRANT) || xen_pv_domain()) { dev_info(dev, "Using dom0 as backend\n"); *backend_domid = 0; |