diff options
author | Nipun Gupta <nipun.gupta@nxp.com> | 2017-04-17 20:27:17 (GMT) |
---|---|---|
committer | Xie Xiaobo <xiaobo.xie@nxp.com> | 2017-09-25 07:25:17 (GMT) |
commit | d66cebc5f4cc19589efb86b68e4d13cb14e2715d (patch) | |
tree | 533e9f3bfc07e3d90fe25de23b92b242a8eb6b4f /drivers | |
parent | 614c461eed9413ea40e45b68b46b481caa578124 (diff) | |
download | linux-d66cebc5f4cc19589efb86b68e4d13cb14e2715d.tar.xz |
staging: fsl-mc: Configure the SMMU using 'iommu-map' DT property
fsl-mc devices needs to configure SMMU driver using the 'iommu-map'
property. They first create the iommu_fwspec and then populate
it with the stream-id and smr mask before the device gets registered
with the SMMU driver.
Signed-off-by: Nipun Gupta <nipun.gupta@nxp.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/staging/fsl-mc/bus/Makefile | 3 | ||||
-rw-r--r-- | drivers/staging/fsl-mc/bus/fsl-mc-bus.c | 17 | ||||
-rw-r--r-- | drivers/staging/fsl-mc/bus/fsl-mc-iommu.c | 78 | ||||
-rw-r--r-- | drivers/staging/fsl-mc/include/mc.h | 3 |
4 files changed, 97 insertions, 4 deletions
diff --git a/drivers/staging/fsl-mc/bus/Makefile b/drivers/staging/fsl-mc/bus/Makefile index 39248ac..e7e2239 100644 --- a/drivers/staging/fsl-mc/bus/Makefile +++ b/drivers/staging/fsl-mc/bus/Makefile @@ -18,7 +18,8 @@ mc-bus-driver-objs := fsl-mc-bus.o \ irq-gic-v3-its-fsl-mc-msi.o \ dpmcp.o \ dpbp.o \ - dpcon.o + dpcon.o \ + fsl-mc-iommu.o # MC DPIO driver obj-$(CONFIG_FSL_MC_DPIO) += dpio/ diff --git a/drivers/staging/fsl-mc/bus/fsl-mc-bus.c b/drivers/staging/fsl-mc/bus/fsl-mc-bus.c index b1defca..f38efea 100644 --- a/drivers/staging/fsl-mc/bus/fsl-mc-bus.c +++ b/drivers/staging/fsl-mc/bus/fsl-mc-bus.c @@ -521,6 +521,8 @@ int fsl_mc_device_add(struct dprc_obj_desc *obj_desc, struct fsl_mc_device *mc_dev = NULL; struct fsl_mc_bus *mc_bus = NULL; struct fsl_mc_device *parent_mc_dev; + struct device *fsl_mc_platform_dev; + struct device_node *fsl_mc_platform_node; if (dev_is_fsl_mc(parent_dev)) parent_mc_dev = to_fsl_mc_device(parent_dev); @@ -613,9 +615,14 @@ int fsl_mc_device_add(struct dprc_obj_desc *obj_desc, goto error_cleanup_dev; } - /* Objects are coherent, unless 'no shareability' flag set. */ - if (!(obj_desc->flags & DPRC_OBJ_FLAG_NO_MEM_SHAREABILITY)) - arch_setup_dma_ops(&mc_dev->dev, 0, 0, NULL, true); + fsl_mc_platform_dev = &mc_dev->dev; + while (dev_is_fsl_mc(fsl_mc_platform_dev)) + fsl_mc_platform_dev = fsl_mc_platform_dev->parent; + fsl_mc_platform_node = fsl_mc_platform_dev->of_node; + + /* Set up the iommu configuration for the devices. */ + fsl_mc_dma_configure(mc_dev, fsl_mc_platform_node, + !(obj_desc->flags & DPRC_OBJ_FLAG_NO_MEM_SHAREABILITY)); /* * The device-specific probe callback will get invoked by device_add() @@ -656,6 +663,10 @@ void fsl_mc_device_remove(struct fsl_mc_device *mc_dev) * The device-specific remove callback will get invoked by device_del() */ device_del(&mc_dev->dev); + + if (strcmp(mc_dev->obj_desc.type, "dprc") != 0) + mc_dev->dev.iommu_fwspec = NULL; + put_device(&mc_dev->dev); } EXPORT_SYMBOL_GPL(fsl_mc_device_remove); diff --git a/drivers/staging/fsl-mc/bus/fsl-mc-iommu.c b/drivers/staging/fsl-mc/bus/fsl-mc-iommu.c new file mode 100644 index 0000000..bd841c9 --- /dev/null +++ b/drivers/staging/fsl-mc/bus/fsl-mc-iommu.c @@ -0,0 +1,78 @@ +/* + * Copyright 2016 Freescale Semiconductor, Inc. + * Copyright 2017 NXP + * Author: Nipun Gupta <nipun.gupta@nxp.com> + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include <linux/iommu.h> +#include <linux/of.h> +#include <linux/of_iommu.h> +#include "../include/mc.h" + +/* Setup the IOMMU for the DPRC container */ +static const struct iommu_ops +*fsl_mc_iommu_configure(struct fsl_mc_device *mc_dev, + struct device_node *fsl_mc_platform_node) +{ + struct of_phandle_args iommu_spec; + const struct iommu_ops *ops; + u32 iommu_phandle; + struct device_node *iommu_node; + const __be32 *map = NULL; + int iommu_cells, map_len, ret; + + map = of_get_property(fsl_mc_platform_node, "iommu-map", &map_len); + if (!map) + return NULL; + + ops = mc_dev->dev.bus->iommu_ops; + if (!ops || !ops->of_xlate) + return NULL; + + iommu_phandle = be32_to_cpup(map + 1); + iommu_node = of_find_node_by_phandle(iommu_phandle); + + if (of_property_read_u32(iommu_node, "#iommu-cells", &iommu_cells)) { + pr_err("%s: missing #iommu-cells property\n", iommu_node->name); + return NULL; + } + + /* Initialize the fwspec */ + ret = iommu_fwspec_init(&mc_dev->dev, &iommu_node->fwnode, ops); + if (ret) + return NULL; + + /* + * Fill in the required stream-id before calling the iommu's + * ops->xlate callback. + */ + iommu_spec.np = iommu_node; + iommu_spec.args[0] = mc_dev->icid; + iommu_spec.args_count = 1; + + ret = ops->of_xlate(&mc_dev->dev, &iommu_spec); + if (ret) + return NULL; + + of_node_put(iommu_spec.np); + + return ops; +} + +/* Set up DMA configuration for fsl-mc devices */ +void fsl_mc_dma_configure(struct fsl_mc_device *mc_dev, + struct device_node *fsl_mc_platform_node, int coherent) +{ + const struct iommu_ops *ops; + + ops = fsl_mc_iommu_configure(mc_dev, fsl_mc_platform_node); + + mc_dev->dev.coherent_dma_mask = DMA_BIT_MASK(48); + mc_dev->dev.dma_mask = &mc_dev->dev.coherent_dma_mask; + arch_setup_dma_ops(&mc_dev->dev, 0, + mc_dev->dev.coherent_dma_mask + 1, ops, coherent); +} diff --git a/drivers/staging/fsl-mc/include/mc.h b/drivers/staging/fsl-mc/include/mc.h index 1c46c0c..fb7a3b6 100644 --- a/drivers/staging/fsl-mc/include/mc.h +++ b/drivers/staging/fsl-mc/include/mc.h @@ -198,4 +198,7 @@ int __must_check fsl_mc_allocate_irqs(struct fsl_mc_device *mc_dev); void fsl_mc_free_irqs(struct fsl_mc_device *mc_dev); +void fsl_mc_dma_configure(struct fsl_mc_device *mc_dev, + struct device_node *fsl_mc_platform_node, int coherent); + #endif /* _FSL_MC_H_ */ |