diff options
Diffstat (limited to 'drivers/bus/fsl-mc/fsl-mc-bus.c')
-rw-r--r-- | drivers/bus/fsl-mc/fsl-mc-bus.c | 43 |
1 files changed, 43 insertions, 0 deletions
diff --git a/drivers/bus/fsl-mc/fsl-mc-bus.c b/drivers/bus/fsl-mc/fsl-mc-bus.c index 9c08b82ecc3e..ea61ebbe6ee0 100644 --- a/drivers/bus/fsl-mc/fsl-mc-bus.c +++ b/drivers/bus/fsl-mc/fsl-mc-bus.c @@ -19,6 +19,7 @@ #include <linux/bitops.h> #include <linux/msi.h> #include <linux/dma-mapping.h> +#include <linux/dma-map-ops.h> #include <linux/acpi.h> #include <linux/iommu.h> #include <linux/io.h> @@ -138,14 +139,56 @@ static int fsl_mc_dma_configure(struct device *dev) struct device *dma_dev = dev; struct fsl_mc_device *mc_dev = to_fsl_mc_device(dev); u32 input_id = mc_dev->icid; + struct iommu_fwspec *fwspec; + const struct iommu_ops *iommu_ops; + int ret; + + /* Skip DMA setup for devices that are not DMA masters */ + if (dev->type == &fsl_mc_bus_dpmcp_type || + dev->type == &fsl_mc_bus_dpbp_type || + dev->type == &fsl_mc_bus_dpcon_type || + dev->type == &fsl_mc_bus_dpio_type) + return 0; while (dev_is_fsl_mc(dma_dev)) dma_dev = dma_dev->parent; + +#if 0 if (dev_of_node(dma_dev)) return of_dma_configure_id(dev, dma_dev->of_node, 0, &input_id); return acpi_dma_configure_id(dev, DEV_DMA_COHERENT, &input_id); +#else + fwspec = dev_iommu_fwspec_get(dma_dev); + if (!fwspec) + return -ENODEV; + iommu_ops = iommu_ops_from_fwnode(fwspec->iommu_fwnode); + if (!iommu_ops) + return -ENODEV; + + ret = iommu_fwspec_init(dev, fwspec->iommu_fwnode, iommu_ops); + if (ret) + return ret; + + ret = iommu_fwspec_add_ids(dev, &input_id, 1); + if (ret) { + iommu_fwspec_free(dev); + return ret; + } + + if (!device_iommu_mapped(dev)) { + ret = iommu_probe_device(dev); + if (ret) { + iommu_fwspec_free(dev); + return ret; + } + } + + arch_setup_dma_ops(dev, 0, *dma_dev->dma_mask + 1, iommu_ops, true); + + return 0; +#endif } static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, |