@@ -13,6 +13,7 @@
#include <linux/dma-mapping.h>
#include <linux/dmaengine.h>
#include <linux/interrupt.h>
+#include <linux/iommu.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/mutex.h>
@@ -1101,10 +1102,49 @@ rcar_dmac_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t buf_addr,
return desc;
}
+static int rcar_dmac_iommu_map(struct dma_chan *chan, phys_addr_t addr,
+ size_t size)
+{
+ struct rcar_dmac_chan *rchan = to_rcar_dmac_chan(chan);
+ struct iommu_domain *domain;
+ phys_addr_t base;
+ size_t min_pagesz, sz = 0;
+ int ret;
+
+ if (!addr)
+ return 0;
+
+ domain = iommu_get_domain_for_dev(chan->device->dev);
+ if (!domain)
+ return 0;
+
+ /* do nothing if the address is already mapped to the domain */
+ /* FIXME: what happens if size is larger for the new mapping? */
+ if (iommu_iova_to_phys(domain, addr))
+ return 0;
+
+ min_pagesz = iommu_min_pgsize(domain);
+
+ /* align the address with the min page size */
+ base = addr & ~(min_pagesz - 1);
+
+ /* recalculate size for aligned address */
+ while (sz < size + addr - base)
+ sz += min_pagesz;
+
+ ret = iommu_map(domain, base, base, sz, IOMMU_READ | IOMMU_WRITE);
+ if (ret)
+ dev_err(chan->device->dev, "chan%u: failed to map %pap",
+ rchan->index, &addr);
+
+ return ret;
+}
+
static int rcar_dmac_device_config(struct dma_chan *chan,
struct dma_slave_config *cfg)
{
struct rcar_dmac_chan *rchan = to_rcar_dmac_chan(chan);
+ int ret = 0;
/*
* We could lock this, but you shouldn't be configuring the
@@ -1115,7 +1155,15 @@ static int rcar_dmac_device_config(struct dma_chan *chan,
rchan->src_xfer_size = cfg->src_addr_width;
rchan->dst_xfer_size = cfg->dst_addr_width;
- return 0;
+ ret = rcar_dmac_iommu_map(chan, rchan->src_slave_addr,
+ rchan->src_xfer_size);
+ if (ret)
+ return ret;
+
+ ret = rcar_dmac_iommu_map(chan, rchan->dst_slave_addr,
+ rchan->dst_xfer_size);
+
+ return ret;
}
static int rcar_dmac_chan_terminate_all(struct dma_chan *chan)
Enable slave transfers over IPMMU by mapping the slave addresses to the DMAC device iommu domain. The mapping is done directly when the slave device is configured and is never unmapped. The mapping is permanent for the device since there might be more then one channel that maps the same area. Think a rx/tx pair that operates on the same address but from separate channels. This makes it hard to map and unmap the addresses from device_alloc_chan_resources and device_free_chan_resources since all channels share the same iommu domain. Signed-off-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se> --- drivers/dma/sh/rcar-dmac.c | 50 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 49 insertions(+), 1 deletion(-)