@@ -18,6 +18,7 @@
#include <linux/bitops.h>
#include <linux/msi.h>
#include <linux/dma-mapping.h>
+#include <linux/iommu.h>
#include "fsl-mc-private.h"
@@ -130,11 +131,58 @@ static int fsl_mc_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
static int fsl_mc_dma_configure(struct device *dev)
{
struct device *dma_dev = dev;
+ struct iommu_fwspec *fwspec;
+ const struct iommu_ops *iommu_ops;
+ struct fsl_mc_device *mc_dev = to_fsl_mc_device(dev);
+ int ret;
+ u32 icid;
+
+ /* 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;
- return of_dma_configure(dev, dma_dev->of_node, 0);
+ 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;
+
+ if (iommu_ops->of_xlate) {
+ struct of_phandle_args iommu_spec = {
+ .np = fwspec->iommu_fwnode->dev->of_node,
+ .args[0] = mc_dev->icid,
+ .args_count = 1
+ };
+
+ ret = iommu_ops->of_xlate(dev, &iommu_spec);
+ 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;
}
static ssize_t modalias_show(struct device *dev, struct device_attribute *attr,