linux-sh.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [RFC 2/4] dmaengine: rcar-dmac: add iommu support for slave transfers
@ 2016-01-08  8:23 Niklas Söderlund
  0 siblings, 0 replies; only message in thread
From: Niklas Söderlund @ 2016-01-08  8:23 UTC (permalink / raw)
  To: linux-sh

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(-)

diff --git a/drivers/dma/sh/rcar-dmac.c b/drivers/dma/sh/rcar-dmac.c
index 7820d07..c1138a1 100644
--- a/drivers/dma/sh/rcar-dmac.c
+++ b/drivers/dma/sh/rcar-dmac.c
@@ -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)
-- 
2.6.4


^ permalink raw reply related	[flat|nested] only message in thread

only message in thread, other threads:[~2016-01-08  8:23 UTC | newest]

Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2016-01-08  8:23 [RFC 2/4] dmaengine: rcar-dmac: add iommu support for slave transfers Niklas Söderlund

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).