summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLaurentiu Tudor <laurentiu.tudor@nxp.com>2020-02-13 11:59:12 +0200
committerRussell King (Oracle) <rmk+kernel@armlinux.org.uk>2021-07-02 16:36:37 +0100
commit3b4ad5b46d631c04726e3b7533b2360fa4a8b24f (patch)
treeb9f189cb3d8fd0c6ae3a80f1069c2397be165b0c
parent4a298afb00deeb0ad359662aa5227f9168e785ce (diff)
bus: fsl-mc: add custom .dma_configure implementation
The devices on this bus are not discovered by way of device tree but by queries to the firmware. It makes little sense to trick the generic of layer into thinking that these devices are of related so that we can get our dma configuration. Instead of doing that, add our custom dma configuration implementation. Signed-off-by: Laurentiu Tudor <laurentiu.tudor@nxp.com>
-rw-r--r--drivers/bus/fsl-mc/fsl-mc-bus.c43
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 861bc31ab661..c435f47ea012 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,