All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC 00/34] PL08x DMA conversion to virt-dma
@ 2012-05-29  9:30 Russell King - ARM Linux
  2012-05-29  9:35 ` [RFC 01/34] dmaengine: split out virtual channel DMA support from sa11x0 driver Russell King
                   ` (33 more replies)
  0 siblings, 34 replies; 80+ messages in thread
From: Russell King - ARM Linux @ 2012-05-29  9:30 UTC (permalink / raw)
  To: linux-arm-kernel

This is merely a posting to show folk where I am with this; this is
still work in progress.

What this represents is a _significant_ rework of the PL08x driver.
It's guaranteed that any patches to this driver will conflict with
this work - moreover, patches which have already gone into this
merge window for this driver _already_ conflict with it.  This set
is based on v3.4.

 drivers/dma/Kconfig        |    5 +
 drivers/dma/Makefile       |    1 +
 drivers/dma/amba-pl08x.c   |  938 ++++++++++++++++++++++----------------------
 drivers/dma/sa11x0-dma.c   |  249 ++++--------
 drivers/dma/virt-dma.c     |  123 ++++++
 drivers/dma/virt-dma.h     |  152 +++++++
 include/linux/amba/pl08x.h |  153 +-------
 7 files changed, 837 insertions(+), 784 deletions(-)

Also note that the first few patches in this series are common to some
other branches (namely OMAP, and SA11x0 DMA engine branches so may appear
separately in other postings.)

^ permalink raw reply	[flat|nested] 80+ messages in thread

* [RFC 01/34] dmaengine: split out virtual channel DMA support from sa11x0 driver
  2012-05-29  9:30 [RFC 00/34] PL08x DMA conversion to virt-dma Russell King - ARM Linux
@ 2012-05-29  9:35 ` Russell King
  2012-05-29  9:35 ` [RFC 02/34] dmaengine: virt-dma: vchan_find_desc() Russell King
                   ` (32 subsequent siblings)
  33 siblings, 0 replies; 80+ messages in thread
From: Russell King @ 2012-05-29  9:35 UTC (permalink / raw)
  To: linux-arm-kernel

Split the virtual slave channel DMA support from the sa11x0 driver so
this code can be shared with other slave DMA engine drivers.

Acked-by: Linus Walleij <linus.walleij@linaro.org>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/dma/Kconfig      |    4 +
 drivers/dma/Makefile     |    1 +
 drivers/dma/sa11x0-dma.c |  249 ++++++++++++++-------------------------------
 drivers/dma/virt-dma.c   |   99 ++++++++++++++++++
 drivers/dma/virt-dma.h   |  138 +++++++++++++++++++++++++
 5 files changed, 320 insertions(+), 171 deletions(-)
 create mode 100644 drivers/dma/virt-dma.c
 create mode 100644 drivers/dma/virt-dma.h

diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
index ef378b5..b792b03 100644
--- a/drivers/dma/Kconfig
+++ b/drivers/dma/Kconfig
@@ -254,6 +254,7 @@ config DMA_SA11X0
 	tristate "SA-11x0 DMA support"
 	depends on ARCH_SA1100
 	select DMA_ENGINE
+	select DMA_VIRTUAL_CHANNELS
 	help
 	  Support the DMA engine found on Intel StrongARM SA-1100 and
 	  SA-1110 SoCs.  This DMA engine can only be used with on-chip
@@ -262,6 +263,9 @@ config DMA_SA11X0
 config DMA_ENGINE
 	bool
 
+config DMA_VIRTUAL_CHANNELS
+	tristate
+
 comment "DMA Clients"
 	depends on DMA_ENGINE
 
diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile
index 86b795b..fc05f7d 100644
--- a/drivers/dma/Makefile
+++ b/drivers/dma/Makefile
@@ -2,6 +2,7 @@ ccflags-$(CONFIG_DMADEVICES_DEBUG)  := -DDEBUG
 ccflags-$(CONFIG_DMADEVICES_VDEBUG) += -DVERBOSE_DEBUG
 
 obj-$(CONFIG_DMA_ENGINE) += dmaengine.o
+obj-$(CONFIG_DMA_VIRTUAL_CHANNELS) += virt-dma.o
 obj-$(CONFIG_NET_DMA) += iovlock.o
 obj-$(CONFIG_INTEL_MID_DMAC) += intel_mid_dma.o
 obj-$(CONFIG_DMATEST) += dmatest.o
diff --git a/drivers/dma/sa11x0-dma.c b/drivers/dma/sa11x0-dma.c
index ec78cce..5f1d2e6 100644
--- a/drivers/dma/sa11x0-dma.c
+++ b/drivers/dma/sa11x0-dma.c
@@ -21,6 +21,8 @@
 #include <linux/slab.h>
 #include <linux/spinlock.h>
 
+#include "virt-dma.h"
+
 #define NR_PHY_CHAN	6
 #define DMA_ALIGN	3
 #define DMA_MAX_SIZE	0x1fff
@@ -72,12 +74,11 @@ struct sa11x0_dma_sg {
 };
 
 struct sa11x0_dma_desc {
-	struct dma_async_tx_descriptor tx;
+	struct virt_dma_desc	vd;
+
 	u32			ddar;
 	size_t			size;
 
-	/* maybe protected by c->lock */
-	struct list_head	node;
 	unsigned		sglen;
 	struct sa11x0_dma_sg	sg[0];
 };
@@ -85,15 +86,11 @@ struct sa11x0_dma_desc {
 struct sa11x0_dma_phy;
 
 struct sa11x0_dma_chan {
-	struct dma_chan		chan;
-	spinlock_t		lock;
-	dma_cookie_t		lc;
+	struct virt_dma_chan	vc;
 
-	/* protected by c->lock */
+	/* protected by c->vc.lock */
 	struct sa11x0_dma_phy	*phy;
 	enum dma_status		status;
-	struct list_head	desc_submitted;
-	struct list_head	desc_issued;
 
 	/* protected by d->lock */
 	struct list_head	node;
@@ -109,7 +106,7 @@ struct sa11x0_dma_phy {
 
 	struct sa11x0_dma_chan	*vchan;
 
-	/* Protected by c->lock */
+	/* Protected by c->vc.lock */
 	unsigned		sg_load;
 	struct sa11x0_dma_desc	*txd_load;
 	unsigned		sg_done;
@@ -127,13 +124,12 @@ struct sa11x0_dma_dev {
 	spinlock_t		lock;
 	struct tasklet_struct	task;
 	struct list_head	chan_pending;
-	struct list_head	desc_complete;
 	struct sa11x0_dma_phy	phy[NR_PHY_CHAN];
 };
 
 static struct sa11x0_dma_chan *to_sa11x0_dma_chan(struct dma_chan *chan)
 {
-	return container_of(chan, struct sa11x0_dma_chan, chan);
+	return container_of(chan, struct sa11x0_dma_chan, vc.chan);
 }
 
 static struct sa11x0_dma_dev *to_sa11x0_dma(struct dma_device *dmadev)
@@ -141,27 +137,26 @@ static struct sa11x0_dma_dev *to_sa11x0_dma(struct dma_device *dmadev)
 	return container_of(dmadev, struct sa11x0_dma_dev, slave);
 }
 
-static struct sa11x0_dma_desc *to_sa11x0_dma_tx(struct dma_async_tx_descriptor *tx)
+static struct sa11x0_dma_desc *sa11x0_dma_next_desc(struct sa11x0_dma_chan *c)
 {
-	return container_of(tx, struct sa11x0_dma_desc, tx);
+	struct virt_dma_desc *vd = vchan_next_desc(&c->vc);
+
+	return vd ? container_of(vd, struct sa11x0_dma_desc, vd) : NULL;
 }
 
-static struct sa11x0_dma_desc *sa11x0_dma_next_desc(struct sa11x0_dma_chan *c)
+static void sa11x0_dma_free_desc(struct virt_dma_desc *vd)
 {
-	if (list_empty(&c->desc_issued))
-		return NULL;
-
-	return list_first_entry(&c->desc_issued, struct sa11x0_dma_desc, node);
+	kfree(container_of(vd, struct sa11x0_dma_desc, vd));
 }
 
 static void sa11x0_dma_start_desc(struct sa11x0_dma_phy *p, struct sa11x0_dma_desc *txd)
 {
-	list_del(&txd->node);
+	list_del(&txd->vd.node);
 	p->txd_load = txd;
 	p->sg_load = 0;
 
 	dev_vdbg(p->dev->slave.dev, "pchan %u: txd %p[%x]: starting: DDAR:%x\n",
-		p->num, txd, txd->tx.cookie, txd->ddar);
+		p->num, &txd->vd, txd->vd.tx.cookie, txd->ddar);
 }
 
 static void noinline sa11x0_dma_start_sg(struct sa11x0_dma_phy *p,
@@ -229,21 +224,13 @@ static void noinline sa11x0_dma_complete(struct sa11x0_dma_phy *p,
 	struct sa11x0_dma_desc *txd = p->txd_done;
 
 	if (++p->sg_done == txd->sglen) {
-		struct sa11x0_dma_dev *d = p->dev;
-
-		dev_vdbg(d->slave.dev, "pchan %u: txd %p[%x]: completed\n",
-			p->num, p->txd_done, p->txd_done->tx.cookie);
-
-		c->lc = txd->tx.cookie;
-
-		spin_lock(&d->lock);
-		list_add_tail(&txd->node, &d->desc_complete);
-		spin_unlock(&d->lock);
+		vchan_cookie_complete(&txd->vd);
 
 		p->sg_done = 0;
 		p->txd_done = p->txd_load;
 
-		tasklet_schedule(&d->task);
+		if (!p->txd_done)
+			tasklet_schedule(&p->dev->task);
 	}
 
 	sa11x0_dma_start_sg(p, c);
@@ -280,7 +267,7 @@ static irqreturn_t sa11x0_dma_irq(int irq, void *dev_id)
 	if (c) {
 		unsigned long flags;
 
-		spin_lock_irqsave(&c->lock, flags);
+		spin_lock_irqsave(&c->vc.lock, flags);
 		/*
 		 * Now that we're holding the lock, check that the vchan
 		 * really is associated with this pchan before touching the
@@ -294,7 +281,7 @@ static irqreturn_t sa11x0_dma_irq(int irq, void *dev_id)
 			if (dcsr & DCSR_DONEB)
 				sa11x0_dma_complete(p, c);
 		}
-		spin_unlock_irqrestore(&c->lock, flags);
+		spin_unlock_irqrestore(&c->vc.lock, flags);
 	}
 
 	return IRQ_HANDLED;
@@ -332,28 +319,15 @@ static void sa11x0_dma_tasklet(unsigned long arg)
 	struct sa11x0_dma_dev *d = (struct sa11x0_dma_dev *)arg;
 	struct sa11x0_dma_phy *p;
 	struct sa11x0_dma_chan *c;
-	struct sa11x0_dma_desc *txd, *txn;
-	LIST_HEAD(head);
 	unsigned pch, pch_alloc = 0;
 
 	dev_dbg(d->slave.dev, "tasklet enter\n");
 
-	/* Get the completed tx descriptors */
-	spin_lock_irq(&d->lock);
-	list_splice_init(&d->desc_complete, &head);
-	spin_unlock_irq(&d->lock);
-
-	list_for_each_entry(txd, &head, node) {
-		c = to_sa11x0_dma_chan(txd->tx.chan);
-
-		dev_dbg(d->slave.dev, "vchan %p: txd %p[%x] completed\n",
-			c, txd, txd->tx.cookie);
-
-		spin_lock_irq(&c->lock);
+	list_for_each_entry(c, &d->slave.channels, vc.chan.device_node) {
+		spin_lock_irq(&c->vc.lock);
 		p = c->phy;
-		if (p) {
-			if (!p->txd_done)
-				sa11x0_dma_start_txd(c);
+		if (p && !p->txd_done) {
+			sa11x0_dma_start_txd(c);
 			if (!p->txd_done) {
 				/* No current txd associated with this channel */
 				dev_dbg(d->slave.dev, "pchan %u: free\n", p->num);
@@ -363,7 +337,7 @@ static void sa11x0_dma_tasklet(unsigned long arg)
 				p->vchan = NULL;
 			}
 		}
-		spin_unlock_irq(&c->lock);
+		spin_unlock_irq(&c->vc.lock);
 	}
 
 	spin_lock_irq(&d->lock);
@@ -380,7 +354,7 @@ static void sa11x0_dma_tasklet(unsigned long arg)
 			/* Mark this channel allocated */
 			p->vchan = c;
 
-			dev_dbg(d->slave.dev, "pchan %u: alloc vchan %p\n", pch, c);
+			dev_dbg(d->slave.dev, "pchan %u: alloc vchan %p\n", pch, &c->vc);
 		}
 	}
 	spin_unlock_irq(&d->lock);
@@ -390,42 +364,18 @@ static void sa11x0_dma_tasklet(unsigned long arg)
 			p = &d->phy[pch];
 			c = p->vchan;
 
-			spin_lock_irq(&c->lock);
+			spin_lock_irq(&c->vc.lock);
 			c->phy = p;
 
 			sa11x0_dma_start_txd(c);
-			spin_unlock_irq(&c->lock);
+			spin_unlock_irq(&c->vc.lock);
 		}
 	}
 
-	/* Now free the completed tx descriptor, and call their callbacks */
-	list_for_each_entry_safe(txd, txn, &head, node) {
-		dma_async_tx_callback callback = txd->tx.callback;
-		void *callback_param = txd->tx.callback_param;
-
-		dev_dbg(d->slave.dev, "txd %p[%x]: callback and free\n",
-			txd, txd->tx.cookie);
-
-		kfree(txd);
-
-		if (callback)
-			callback(callback_param);
-	}
-
 	dev_dbg(d->slave.dev, "tasklet exit\n");
 }
 
 
-static void sa11x0_dma_desc_free(struct sa11x0_dma_dev *d, struct list_head *head)
-{
-	struct sa11x0_dma_desc *txd, *txn;
-
-	list_for_each_entry_safe(txd, txn, head, node) {
-		dev_dbg(d->slave.dev, "txd %p: freeing\n", txd);
-		kfree(txd);
-	}
-}
-
 static int sa11x0_dma_alloc_chan_resources(struct dma_chan *chan)
 {
 	return 0;
@@ -436,18 +386,12 @@ static void sa11x0_dma_free_chan_resources(struct dma_chan *chan)
 	struct sa11x0_dma_chan *c = to_sa11x0_dma_chan(chan);
 	struct sa11x0_dma_dev *d = to_sa11x0_dma(chan->device);
 	unsigned long flags;
-	LIST_HEAD(head);
 
-	spin_lock_irqsave(&c->lock, flags);
-	spin_lock(&d->lock);
+	spin_lock_irqsave(&d->lock, flags);
 	list_del_init(&c->node);
-	spin_unlock(&d->lock);
-
-	list_splice_tail_init(&c->desc_submitted, &head);
-	list_splice_tail_init(&c->desc_issued, &head);
-	spin_unlock_irqrestore(&c->lock, flags);
+	spin_unlock_irqrestore(&d->lock, flags);
 
-	sa11x0_dma_desc_free(d, &head);
+	vchan_free_chan_resources(&c->vc);
 }
 
 static dma_addr_t sa11x0_dma_pos(struct sa11x0_dma_phy *p)
@@ -473,21 +417,15 @@ static enum dma_status sa11x0_dma_tx_status(struct dma_chan *chan,
 	struct sa11x0_dma_dev *d = to_sa11x0_dma(chan->device);
 	struct sa11x0_dma_phy *p;
 	struct sa11x0_dma_desc *txd;
-	dma_cookie_t last_used, last_complete;
 	unsigned long flags;
 	enum dma_status ret;
 	size_t bytes = 0;
 
-	last_used = c->chan.cookie;
-	last_complete = c->lc;
-
-	ret = dma_async_is_complete(cookie, last_complete, last_used);
-	if (ret == DMA_SUCCESS) {
-		dma_set_tx_state(state, last_complete, last_used, 0);
+	ret = dma_cookie_status(&c->vc.chan, cookie, state);
+	if (ret == DMA_SUCCESS)
 		return ret;
-	}
 
-	spin_lock_irqsave(&c->lock, flags);
+	spin_lock_irqsave(&c->vc.lock, flags);
 	p = c->phy;
 	ret = c->status;
 	if (p) {
@@ -524,12 +462,13 @@ static enum dma_status sa11x0_dma_tx_status(struct dma_chan *chan,
 		if (txd != p->txd_load && p->txd_load)
 			bytes += p->txd_load->size;
 	}
-	list_for_each_entry(txd, &c->desc_issued, node) {
+	list_for_each_entry(txd, &c->vc.desc_issued, vd.node) {
 		bytes += txd->size;
 	}
-	spin_unlock_irqrestore(&c->lock, flags);
+	spin_unlock_irqrestore(&c->vc.lock, flags);
 
-	dma_set_tx_state(state, last_complete, last_used, bytes);
+	if (state)
+		state->residue = bytes;
 
 	dev_vdbg(d->slave.dev, "tx_status: bytes 0x%zx\n", bytes);
 
@@ -547,40 +486,20 @@ static void sa11x0_dma_issue_pending(struct dma_chan *chan)
 	struct sa11x0_dma_dev *d = to_sa11x0_dma(chan->device);
 	unsigned long flags;
 
-	spin_lock_irqsave(&c->lock, flags);
-	list_splice_tail_init(&c->desc_submitted, &c->desc_issued);
-	if (!list_empty(&c->desc_issued)) {
-		spin_lock(&d->lock);
-		if (!c->phy && list_empty(&c->node)) {
-			list_add_tail(&c->node, &d->chan_pending);
-			tasklet_schedule(&d->task);
-			dev_dbg(d->slave.dev, "vchan %p: issued\n", c);
+	spin_lock_irqsave(&c->vc.lock, flags);
+	if (vchan_issue_pending(&c->vc)) {
+		if (!c->phy) {
+			spin_lock(&d->lock);
+			if (list_empty(&c->node)) {
+				list_add_tail(&c->node, &d->chan_pending);
+				tasklet_schedule(&d->task);
+				dev_dbg(d->slave.dev, "vchan %p: issued\n", &c->vc);
+			}
+			spin_unlock(&d->lock);
 		}
-		spin_unlock(&d->lock);
 	} else
-		dev_dbg(d->slave.dev, "vchan %p: nothing to issue\n", c);
-	spin_unlock_irqrestore(&c->lock, flags);
-}
-
-static dma_cookie_t sa11x0_dma_tx_submit(struct dma_async_tx_descriptor *tx)
-{
-	struct sa11x0_dma_chan *c = to_sa11x0_dma_chan(tx->chan);
-	struct sa11x0_dma_desc *txd = to_sa11x0_dma_tx(tx);
-	unsigned long flags;
-
-	spin_lock_irqsave(&c->lock, flags);
-	c->chan.cookie += 1;
-	if (c->chan.cookie < 0)
-		c->chan.cookie = 1;
-	txd->tx.cookie = c->chan.cookie;
-
-	list_add_tail(&txd->node, &c->desc_submitted);
-	spin_unlock_irqrestore(&c->lock, flags);
-
-	dev_dbg(tx->chan->device->dev, "vchan %p: txd %p[%x]: submitted\n",
-		c, txd, txd->tx.cookie);
-
-	return txd->tx.cookie;
+		dev_dbg(d->slave.dev, "vchan %p: nothing to issue\n", &c->vc);
+	spin_unlock_irqrestore(&c->vc.lock, flags);
 }
 
 static struct dma_async_tx_descriptor *sa11x0_dma_prep_slave_sg(
@@ -596,7 +515,7 @@ static struct dma_async_tx_descriptor *sa11x0_dma_prep_slave_sg(
 	/* SA11x0 channels can only operate in their native direction */
 	if (dir != (c->ddar & DDAR_RW ? DMA_DEV_TO_MEM : DMA_MEM_TO_DEV)) {
 		dev_err(chan->device->dev, "vchan %p: bad DMA direction: DDAR:%08x dir:%u\n",
-			c, c->ddar, dir);
+			&c->vc, c->ddar, dir);
 		return NULL;
 	}
 
@@ -612,14 +531,14 @@ static struct dma_async_tx_descriptor *sa11x0_dma_prep_slave_sg(
 			j += DIV_ROUND_UP(len, DMA_MAX_SIZE & ~DMA_ALIGN) - 1;
 		if (addr & DMA_ALIGN) {
 			dev_dbg(chan->device->dev, "vchan %p: bad buffer alignment: %08x\n",
-				c, addr);
+				&c->vc, addr);
 			return NULL;
 		}
 	}
 
 	txd = kzalloc(sizeof(*txd) + j * sizeof(txd->sg[0]), GFP_ATOMIC);
 	if (!txd) {
-		dev_dbg(chan->device->dev, "vchan %p: kzalloc failed\n", c);
+		dev_dbg(chan->device->dev, "vchan %p: kzalloc failed\n", &c->vc);
 		return NULL;
 	}
 
@@ -655,17 +574,14 @@ static struct dma_async_tx_descriptor *sa11x0_dma_prep_slave_sg(
 		} while (len);
 	}
 
-	dma_async_tx_descriptor_init(&txd->tx, &c->chan);
-	txd->tx.flags = flags;
-	txd->tx.tx_submit = sa11x0_dma_tx_submit;
 	txd->ddar = c->ddar;
 	txd->size = size;
 	txd->sglen = j;
 
 	dev_dbg(chan->device->dev, "vchan %p: txd %p: size %u nr %u\n",
-		c, txd, txd->size, txd->sglen);
+		&c->vc, &txd->vd, txd->size, txd->sglen);
 
-	return &txd->tx;
+	return vchan_tx_prep(&c->vc, &txd->vd, flags);
 }
 
 static int sa11x0_dma_slave_config(struct sa11x0_dma_chan *c, struct dma_slave_config *cfg)
@@ -695,8 +611,8 @@ static int sa11x0_dma_slave_config(struct sa11x0_dma_chan *c, struct dma_slave_c
 	if (maxburst == 8)
 		ddar |= DDAR_BS;
 
-	dev_dbg(c->chan.device->dev, "vchan %p: dma_slave_config addr %x width %u burst %u\n",
-		c, addr, width, maxburst);
+	dev_dbg(c->vc.chan.device->dev, "vchan %p: dma_slave_config addr %x width %u burst %u\n",
+		&c->vc, addr, width, maxburst);
 
 	c->ddar = ddar | (addr & 0xf0000000) | (addr & 0x003ffffc) << 6;
 
@@ -718,16 +634,13 @@ static int sa11x0_dma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
 		return sa11x0_dma_slave_config(c, (struct dma_slave_config *)arg);
 
 	case DMA_TERMINATE_ALL:
-		dev_dbg(d->slave.dev, "vchan %p: terminate all\n", c);
+		dev_dbg(d->slave.dev, "vchan %p: terminate all\n", &c->vc);
 		/* Clear the tx descriptor lists */
-		spin_lock_irqsave(&c->lock, flags);
-		list_splice_tail_init(&c->desc_submitted, &head);
-		list_splice_tail_init(&c->desc_issued, &head);
+		spin_lock_irqsave(&c->vc.lock, flags);
+		vchan_get_all_descriptors(&c->vc, &head);
 
 		p = c->phy;
 		if (p) {
-			struct sa11x0_dma_desc *txd, *txn;
-
 			dev_dbg(d->slave.dev, "pchan %u: terminating\n", p->num);
 			/* vchan is assigned to a pchan - stop the channel */
 			writel(DCSR_RUN | DCSR_IE |
@@ -735,17 +648,13 @@ static int sa11x0_dma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
 				DCSR_STRTB | DCSR_DONEB,
 				p->base + DMA_DCSR_C);
 
-			list_for_each_entry_safe(txd, txn, &d->desc_complete, node)
-				if (txd->tx.chan == &c->chan)
-					list_move(&txd->node, &head);
-
 			if (p->txd_load) {
 				if (p->txd_load != p->txd_done)
-					list_add_tail(&p->txd_load->node, &head);
+					list_add_tail(&p->txd_load->vd.node, &head);
 				p->txd_load = NULL;
 			}
 			if (p->txd_done) {
-				list_add_tail(&p->txd_done->node, &head);
+				list_add_tail(&p->txd_done->vd.node, &head);
 				p->txd_done = NULL;
 			}
 			c->phy = NULL;
@@ -754,14 +663,14 @@ static int sa11x0_dma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
 			spin_unlock(&d->lock);
 			tasklet_schedule(&d->task);
 		}
-		spin_unlock_irqrestore(&c->lock, flags);
-		sa11x0_dma_desc_free(d, &head);
+		spin_unlock_irqrestore(&c->vc.lock, flags);
+		vchan_dma_desc_free_list(&c->vc, &head);
 		ret = 0;
 		break;
 
 	case DMA_PAUSE:
-		dev_dbg(d->slave.dev, "vchan %p: pause\n", c);
-		spin_lock_irqsave(&c->lock, flags);
+		dev_dbg(d->slave.dev, "vchan %p: pause\n", &c->vc);
+		spin_lock_irqsave(&c->vc.lock, flags);
 		if (c->status == DMA_IN_PROGRESS) {
 			c->status = DMA_PAUSED;
 
@@ -774,26 +683,26 @@ static int sa11x0_dma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
 				spin_unlock(&d->lock);
 			}
 		}
-		spin_unlock_irqrestore(&c->lock, flags);
+		spin_unlock_irqrestore(&c->vc.lock, flags);
 		ret = 0;
 		break;
 
 	case DMA_RESUME:
-		dev_dbg(d->slave.dev, "vchan %p: resume\n", c);
-		spin_lock_irqsave(&c->lock, flags);
+		dev_dbg(d->slave.dev, "vchan %p: resume\n", &c->vc);
+		spin_lock_irqsave(&c->vc.lock, flags);
 		if (c->status == DMA_PAUSED) {
 			c->status = DMA_IN_PROGRESS;
 
 			p = c->phy;
 			if (p) {
 				writel(DCSR_RUN | DCSR_IE, p->base + DMA_DCSR_S);
-			} else if (!list_empty(&c->desc_issued)) {
+			} else if (!list_empty(&c->vc.desc_issued)) {
 				spin_lock(&d->lock);
 				list_add_tail(&c->node, &d->chan_pending);
 				spin_unlock(&d->lock);
 			}
 		}
-		spin_unlock_irqrestore(&c->lock, flags);
+		spin_unlock_irqrestore(&c->vc.lock, flags);
 		ret = 0;
 		break;
 
@@ -853,15 +762,13 @@ static int __devinit sa11x0_dma_init_dmadev(struct dma_device *dmadev,
 			return -ENOMEM;
 		}
 
-		c->chan.device = dmadev;
 		c->status = DMA_IN_PROGRESS;
 		c->ddar = chan_desc[i].ddar;
 		c->name = chan_desc[i].name;
-		spin_lock_init(&c->lock);
-		INIT_LIST_HEAD(&c->desc_submitted);
-		INIT_LIST_HEAD(&c->desc_issued);
 		INIT_LIST_HEAD(&c->node);
-		list_add_tail(&c->chan.device_node, &dmadev->channels);
+
+		c->vc.desc_free = sa11x0_dma_free_desc;
+		vchan_init(&c->vc, dmadev);
 	}
 
 	return dma_async_device_register(dmadev);
@@ -890,8 +797,9 @@ static void sa11x0_dma_free_channels(struct dma_device *dmadev)
 {
 	struct sa11x0_dma_chan *c, *cn;
 
-	list_for_each_entry_safe(c, cn, &dmadev->channels, chan.device_node) {
-		list_del(&c->chan.device_node);
+	list_for_each_entry_safe(c, cn, &dmadev->channels, vc.chan.device_node) {
+		list_del(&c->vc.chan.device_node);
+		tasklet_kill(&c->vc.task);
 		kfree(c);
 	}
 }
@@ -915,7 +823,6 @@ static int __devinit sa11x0_dma_probe(struct platform_device *pdev)
 
 	spin_lock_init(&d->lock);
 	INIT_LIST_HEAD(&d->chan_pending);
-	INIT_LIST_HEAD(&d->desc_complete);
 
 	d->base = ioremap(res->start, resource_size(res));
 	if (!d->base) {
diff --git a/drivers/dma/virt-dma.c b/drivers/dma/virt-dma.c
new file mode 100644
index 0000000..bd85b05
--- /dev/null
+++ b/drivers/dma/virt-dma.c
@@ -0,0 +1,99 @@
+/*
+ * Virtual DMA channel support for DMAengine
+ *
+ * Copyright (C) 2012 Russell King
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/device.h>
+#include <linux/dmaengine.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+
+#include "virt-dma.h"
+
+static struct virt_dma_desc *to_virt_desc(struct dma_async_tx_descriptor *tx)
+{
+	return container_of(tx, struct virt_dma_desc, tx);
+}
+
+dma_cookie_t vchan_tx_submit(struct dma_async_tx_descriptor *tx)
+{
+	struct virt_dma_chan *vc = to_virt_chan(tx->chan);
+	struct virt_dma_desc *vd = to_virt_desc(tx);
+	unsigned long flags;
+	dma_cookie_t cookie;
+
+	spin_lock_irqsave(&vc->lock, flags);
+	cookie = dma_cookie_assign(tx);
+
+	list_add_tail(&vd->node, &vc->desc_submitted);
+	spin_unlock_irqrestore(&vc->lock, flags);
+
+	dev_dbg(vc->chan.device->dev, "vchan %p: txd %p[%x]: submitted\n",
+		vc, vd, cookie);
+
+	return cookie;
+}
+EXPORT_SYMBOL_GPL(vchan_tx_submit);
+
+/*
+ * This tasklet handles the completion of a DMA descriptor by
+ * calling its callback and freeing it.
+ */
+static void vchan_complete(unsigned long arg)
+{
+	struct virt_dma_chan *vc = (struct virt_dma_chan *)arg;
+	LIST_HEAD(head);
+
+	spin_lock_irq(&vc->lock);
+	list_splice_tail_init(&vc->desc_completed, &head);
+	spin_unlock_irq(&vc->lock);
+
+	while (!list_empty(&head)) {
+		struct virt_dma_desc *vd = list_first_entry(&head,
+				struct virt_dma_desc, node);
+		dma_async_tx_callback cb = vd->tx.callback;
+		void *cb_data = vd->tx.callback_param;
+
+		list_del(&vd->node);
+
+		vc->desc_free(vd);
+
+		if (cb)
+			cb(cb_data);
+	}
+}
+
+void vchan_dma_desc_free_list(struct virt_dma_chan *vc, struct list_head *head)
+{
+	while (!list_empty(head)) {
+		struct virt_dma_desc *vd = list_first_entry(head,
+			struct virt_dma_desc, node);
+		list_del(&vd->node);
+		dev_dbg(vc->chan.device->dev, "txd %p: freeing\n", vd);
+		vc->desc_free(vd);
+	}
+}
+EXPORT_SYMBOL_GPL(vchan_dma_desc_free_list);
+
+void vchan_init(struct virt_dma_chan *vc, struct dma_device *dmadev)
+{
+	dma_cookie_init(&vc->chan);
+
+	spin_lock_init(&vc->lock);
+	INIT_LIST_HEAD(&vc->desc_submitted);
+	INIT_LIST_HEAD(&vc->desc_issued);
+	INIT_LIST_HEAD(&vc->desc_completed);
+
+	tasklet_init(&vc->task, vchan_complete, (unsigned long)vc);
+
+	vc->chan.device = dmadev;
+	list_add_tail(&vc->chan.device_node, &dmadev->channels);
+}
+EXPORT_SYMBOL_GPL(vchan_init);
+
+MODULE_AUTHOR("Russell King");
+MODULE_LICENSE("GPL");
diff --git a/drivers/dma/virt-dma.h b/drivers/dma/virt-dma.h
new file mode 100644
index 0000000..825bb96
--- /dev/null
+++ b/drivers/dma/virt-dma.h
@@ -0,0 +1,138 @@
+/*
+ * Virtual DMA channel support for DMAengine
+ *
+ * Copyright (C) 2012 Russell King
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef VIRT_DMA_H
+#define VIRT_DMA_H
+
+#include <linux/dmaengine.h>
+#include <linux/interrupt.h>
+
+#include "dmaengine.h"
+
+struct virt_dma_desc {
+	struct dma_async_tx_descriptor tx;
+	/* protected by vc.lock */
+	struct list_head node;
+};
+
+struct virt_dma_chan {
+	struct dma_chan	chan;
+	struct tasklet_struct task;
+	void (*desc_free)(struct virt_dma_desc *);
+
+	spinlock_t lock;
+
+	/* protected by vc.lock */
+	struct list_head desc_submitted;
+	struct list_head desc_issued;
+	struct list_head desc_completed;
+};
+
+static inline struct virt_dma_chan *to_virt_chan(struct dma_chan *chan)
+{
+	return container_of(chan, struct virt_dma_chan, chan);
+}
+
+void vchan_dma_desc_free_list(struct virt_dma_chan *vc, struct list_head *head);
+
+void vchan_init(struct virt_dma_chan *vc, struct dma_device *dmadev);
+
+/**
+ * vchan_tx_prep - prepare a descriptor
+ * vc: virtual channel allocating this descriptor
+ * vd: virtual descriptor to prepare
+ * tx_flags: flags argument passed in to prepare function
+ */
+static inline struct dma_async_tx_descriptor *vchan_tx_prep(struct virt_dma_chan *vc,
+	struct virt_dma_desc *vd, unsigned long tx_flags)
+{
+	extern dma_cookie_t vchan_tx_submit(struct dma_async_tx_descriptor *);
+
+	dma_async_tx_descriptor_init(&vd->tx, &vc->chan);
+	vd->tx.flags = tx_flags;
+	vd->tx.tx_submit = vchan_tx_submit;
+
+	return &vd->tx;
+}
+
+/**
+ * vchan_issue_pending - move submitted descriptors to issued list
+ * vc: virtual channel to update
+ *
+ * vc.lock must be held by caller
+ */
+static inline bool vchan_issue_pending(struct virt_dma_chan *vc)
+{
+	list_splice_tail_init(&vc->desc_submitted, &vc->desc_issued);
+	return !list_empty(&vc->desc_issued);
+}
+
+/**
+ * vchan_cookie_complete - report completion of a descriptor
+ * vd: virtual descriptor to update
+ *
+ * vc.lock must be held by caller
+ */
+static inline void vchan_cookie_complete(struct virt_dma_desc *vd)
+{
+	struct virt_dma_chan *vc = to_virt_chan(vd->tx.chan);
+
+	dma_cookie_complete(&vd->tx);
+	dev_vdbg(vc->chan.device->dev, "txd %p[%x]: marked complete\n",
+		vd, vd->tx.cookie);
+	list_add_tail(&vd->node, &vc->desc_completed);
+
+	tasklet_schedule(&vc->task);
+}
+
+/**
+ * vchan_next_desc - peek at the next descriptor to be processed
+ * vc: virtual channel to obtain descriptor from
+ *
+ * vc.lock must be held by caller
+ */
+static inline struct virt_dma_desc *vchan_next_desc(struct virt_dma_chan *vc)
+{
+	if (list_empty(&vc->desc_issued))
+		return NULL;
+
+	return list_first_entry(&vc->desc_issued, struct virt_dma_desc, node);
+}
+
+/**
+ * vchan_get_all_descriptors - obtain all submitted and issued descriptors
+ * vc: virtual channel to get descriptors from
+ * head: list of descriptors found
+ *
+ * vc.lock must be held by caller
+ *
+ * Removes all submitted and issued descriptors from internal lists, and
+ * provides a list of all descriptors found
+ */
+static inline void vchan_get_all_descriptors(struct virt_dma_chan *vc,
+	struct list_head *head)
+{
+	list_splice_tail_init(&vc->desc_submitted, head);
+	list_splice_tail_init(&vc->desc_issued, head);
+	list_splice_tail_init(&vc->desc_completed, head);
+}
+
+static inline void vchan_free_chan_resources(struct virt_dma_chan *vc)
+{
+	unsigned long flags;
+	LIST_HEAD(head);
+
+	spin_lock_irqsave(&vc->lock, flags);
+	vchan_get_all_descriptors(vc, &head);
+	spin_unlock_irqrestore(&vc->lock, flags);
+
+	vchan_dma_desc_free_list(vc, &head);
+}
+
+#endif
-- 
1.7.4.4

^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [RFC 02/34] dmaengine: virt-dma: vchan_find_desc()
  2012-05-29  9:30 [RFC 00/34] PL08x DMA conversion to virt-dma Russell King - ARM Linux
  2012-05-29  9:35 ` [RFC 01/34] dmaengine: split out virtual channel DMA support from sa11x0 driver Russell King
@ 2012-05-29  9:35 ` Russell King
  2012-05-30  7:48   ` Linus Walleij
  2012-05-29  9:36 ` [RFC 03/34] dmaengine: virt-dma: add support for cyclic DMA periodic callbacks Russell King
                   ` (31 subsequent siblings)
  33 siblings, 1 reply; 80+ messages in thread
From: Russell King @ 2012-05-29  9:35 UTC (permalink / raw)
  To: linux-arm-kernel

Add a function to find a descriptor within the depths of the
virtualized DMA channel support.  Needed for tx_status functionality.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/dma/virt-dma.c |   13 +++++++++++++
 drivers/dma/virt-dma.h |    2 +-
 2 files changed, 14 insertions(+), 1 deletions(-)

diff --git a/drivers/dma/virt-dma.c b/drivers/dma/virt-dma.c
index bd85b05..a8054fc 100644
--- a/drivers/dma/virt-dma.c
+++ b/drivers/dma/virt-dma.c
@@ -39,6 +39,19 @@ dma_cookie_t vchan_tx_submit(struct dma_async_tx_descriptor *tx)
 }
 EXPORT_SYMBOL_GPL(vchan_tx_submit);
 
+struct virt_dma_desc *vchan_find_desc(struct virt_dma_chan *vc,
+	dma_cookie_t cookie)
+{
+	struct virt_dma_desc *vd;
+
+	list_for_each_entry(vd, &vc->desc_issued, node)
+		if (vd->tx.cookie == cookie)
+			return vd;
+
+	return NULL;
+}
+EXPORT_SYMBOL_GPL(vchan_find_desc);
+
 /*
  * This tasklet handles the completion of a DMA descriptor by
  * calling its callback and freeing it.
diff --git a/drivers/dma/virt-dma.h b/drivers/dma/virt-dma.h
index 825bb96..44ec57e 100644
--- a/drivers/dma/virt-dma.h
+++ b/drivers/dma/virt-dma.h
@@ -40,8 +40,8 @@ static inline struct virt_dma_chan *to_virt_chan(struct dma_chan *chan)
 }
 
 void vchan_dma_desc_free_list(struct virt_dma_chan *vc, struct list_head *head);
-
 void vchan_init(struct virt_dma_chan *vc, struct dma_device *dmadev);
+struct virt_dma_desc *vchan_find_desc(struct virt_dma_chan *, dma_cookie_t);
 
 /**
  * vchan_tx_prep - prepare a descriptor
-- 
1.7.4.4

^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [RFC 03/34] dmaengine: virt-dma: add support for cyclic DMA periodic callbacks
  2012-05-29  9:30 [RFC 00/34] PL08x DMA conversion to virt-dma Russell King - ARM Linux
  2012-05-29  9:35 ` [RFC 01/34] dmaengine: split out virtual channel DMA support from sa11x0 driver Russell King
  2012-05-29  9:35 ` [RFC 02/34] dmaengine: virt-dma: vchan_find_desc() Russell King
@ 2012-05-29  9:36 ` Russell King
  2012-05-30  7:52   ` Linus Walleij
  2012-05-29  9:36 ` [RFC 04/34] dmaengine: PL08x: remove runtime PM support Russell King
                   ` (30 subsequent siblings)
  33 siblings, 1 reply; 80+ messages in thread
From: Russell King @ 2012-05-29  9:36 UTC (permalink / raw)
  To: linux-arm-kernel

Add support for cyclic DMA's periodic callbacks.  Drivers are expected
to call vchan_cyclic_callback() when a period has completed, which will
schedule the tasklet to make the callback into the driver.

As callbacks are made from tasklet context, it is important to realise
that we don't guarantee a callback for each completed period, but for
N completed periods where N may be greater than one.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/dma/virt-dma.c |   19 +++++++++++++++----
 drivers/dma/virt-dma.h |   14 ++++++++++++++
 2 files changed, 29 insertions(+), 4 deletions(-)

diff --git a/drivers/dma/virt-dma.c b/drivers/dma/virt-dma.c
index a8054fc..6f80432 100644
--- a/drivers/dma/virt-dma.c
+++ b/drivers/dma/virt-dma.c
@@ -59,17 +59,28 @@ EXPORT_SYMBOL_GPL(vchan_find_desc);
 static void vchan_complete(unsigned long arg)
 {
 	struct virt_dma_chan *vc = (struct virt_dma_chan *)arg;
+	struct virt_dma_desc *vd;
+	dma_async_tx_callback cb = NULL;
+	void *cb_data = NULL;
 	LIST_HEAD(head);
 
 	spin_lock_irq(&vc->lock);
 	list_splice_tail_init(&vc->desc_completed, &head);
+	vd = vc->cyclic;
+	if (vd) {
+		vc->cyclic = NULL;
+		cb = vd->tx.callback;
+		cb_data = vd->tx.callback_param;
+	}
 	spin_unlock_irq(&vc->lock);
 
+	if (cb)
+		cb(cb_data);
+
 	while (!list_empty(&head)) {
-		struct virt_dma_desc *vd = list_first_entry(&head,
-				struct virt_dma_desc, node);
-		dma_async_tx_callback cb = vd->tx.callback;
-		void *cb_data = vd->tx.callback_param;
+		vd = list_first_entry(&head, struct virt_dma_desc, node);
+		cb = vd->tx.callback;
+		cb_data = vd->tx.callback_param;
 
 		list_del(&vd->node);
 
diff --git a/drivers/dma/virt-dma.h b/drivers/dma/virt-dma.h
index 44ec57e..85c19d6 100644
--- a/drivers/dma/virt-dma.h
+++ b/drivers/dma/virt-dma.h
@@ -32,6 +32,8 @@ struct virt_dma_chan {
 	struct list_head desc_submitted;
 	struct list_head desc_issued;
 	struct list_head desc_completed;
+
+	struct virt_dma_desc *cyclic;
 };
 
 static inline struct virt_dma_chan *to_virt_chan(struct dma_chan *chan)
@@ -92,6 +94,18 @@ static inline void vchan_cookie_complete(struct virt_dma_desc *vd)
 }
 
 /**
+ * vchan_cyclic_callback - report the completion of a period
+ * vd: virtual descriptor
+ */
+static inline void vchan_cyclic_callback(struct virt_dma_desc *vd)
+{
+	struct virt_dma_chan *vc = to_virt_chan(vd->tx.chan);
+
+	vc->cyclic = vd;
+	tasklet_schedule(&vc->task);
+}
+
+/**
  * vchan_next_desc - peek at the next descriptor to be processed
  * vc: virtual channel to obtain descriptor from
  *
-- 
1.7.4.4

^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [RFC 04/34] dmaengine: PL08x: remove runtime PM support
  2012-05-29  9:30 [RFC 00/34] PL08x DMA conversion to virt-dma Russell King - ARM Linux
                   ` (2 preceding siblings ...)
  2012-05-29  9:36 ` [RFC 03/34] dmaengine: virt-dma: add support for cyclic DMA periodic callbacks Russell King
@ 2012-05-29  9:36 ` Russell King
  2012-05-31  0:46   ` Linus Walleij
  2012-05-29  9:36 ` [RFC 05/34] dmaengine: PL08x: fix missed dma_transfer_direction fixup Russell King
                   ` (29 subsequent siblings)
  33 siblings, 1 reply; 80+ messages in thread
From: Russell King @ 2012-05-29  9:36 UTC (permalink / raw)
  To: linux-arm-kernel

The runtime PM support conflicts with the generic AMBA bus PM, and also
causes a potential deadlock with the PL011 driver as it results in
interrupts being enabled beneath a spinlock.

I don't presently see any solution to this other than by removing the
runtime PM support entirely from the DMA engine driver.  Alternative
suggestions welcome.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/dma/amba-pl08x.c |   10 ----------
 1 files changed, 0 insertions(+), 10 deletions(-)

diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c
index 3d704ab..8931682 100644
--- a/drivers/dma/amba-pl08x.c
+++ b/drivers/dma/amba-pl08x.c
@@ -400,7 +400,6 @@ pl08x_get_phy_channel(struct pl08x_driver_data *pl08x,
 		return NULL;
 	}
 
-	pm_runtime_get_sync(&pl08x->adev->dev);
 	return ch;
 }
 
@@ -414,8 +413,6 @@ static inline void pl08x_put_phy_channel(struct pl08x_driver_data *pl08x,
 	/* Stop the channel and clear its interrupts */
 	pl08x_terminate_phy_chan(pl08x, ch);
 
-	pm_runtime_put(&pl08x->adev->dev);
-
 	/* Mark it as free */
 	ch->serving = NULL;
 	spin_unlock_irqrestore(&ch->lock, flags);
@@ -1842,9 +1839,6 @@ static int pl08x_probe(struct amba_device *adev, const struct amba_id *id)
 		goto out_no_pl08x;
 	}
 
-	pm_runtime_set_active(&adev->dev);
-	pm_runtime_enable(&adev->dev);
-
 	/* Initialize memcpy engine */
 	dma_cap_set(DMA_MEMCPY, pl08x->memcpy.cap_mask);
 	pl08x->memcpy.dev = &adev->dev;
@@ -1983,7 +1977,6 @@ static int pl08x_probe(struct amba_device *adev, const struct amba_id *id)
 		 amba_part(adev), amba_rev(adev),
 		 (unsigned long long)adev->res.start, adev->irq[0]);
 
-	pm_runtime_put(&adev->dev);
 	return 0;
 
 out_no_slave_reg:
@@ -2002,9 +1995,6 @@ static int pl08x_probe(struct amba_device *adev, const struct amba_id *id)
 	dma_pool_destroy(pl08x->pool);
 out_no_lli_pool:
 out_no_platdata:
-	pm_runtime_put(&adev->dev);
-	pm_runtime_disable(&adev->dev);
-
 	kfree(pl08x);
 out_no_pl08x:
 	amba_release_regions(adev);
-- 
1.7.4.4

^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [RFC 05/34] dmaengine: PL08x: fix missed dma_transfer_direction fixup
  2012-05-29  9:30 [RFC 00/34] PL08x DMA conversion to virt-dma Russell King - ARM Linux
                   ` (3 preceding siblings ...)
  2012-05-29  9:36 ` [RFC 04/34] dmaengine: PL08x: remove runtime PM support Russell King
@ 2012-05-29  9:36 ` Russell King
  2012-05-31  0:47   ` Linus Walleij
  2012-05-29  9:37 ` [RFC 06/34] dmaengine: PL08x: remove redundant spinlock Russell King
                   ` (28 subsequent siblings)
  33 siblings, 1 reply; 80+ messages in thread
From: Russell King @ 2012-05-29  9:36 UTC (permalink / raw)
  To: linux-arm-kernel

db8196df4 (dmaengine: move drivers to dma_transfer_direction) missed
fixing up the "DMA_NONE" case.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/dma/amba-pl08x.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c
index 8931682..a5bb7f8 100644
--- a/drivers/dma/amba-pl08x.c
+++ b/drivers/dma/amba-pl08x.c
@@ -1283,7 +1283,7 @@ static struct dma_async_tx_descriptor *pl08x_prep_dma_memcpy(
 	}
 	list_add_tail(&dsg->node, &txd->dsg_list);
 
-	txd->direction = DMA_NONE;
+	txd->direction = DMA_MEM_TO_MEM;
 	dsg->src_addr = src;
 	dsg->dst_addr = dest;
 	dsg->len = len;
-- 
1.7.4.4

^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [RFC 06/34] dmaengine: PL08x: remove redundant spinlock
  2012-05-29  9:30 [RFC 00/34] PL08x DMA conversion to virt-dma Russell King - ARM Linux
                   ` (4 preceding siblings ...)
  2012-05-29  9:36 ` [RFC 05/34] dmaengine: PL08x: fix missed dma_transfer_direction fixup Russell King
@ 2012-05-29  9:37 ` Russell King
  2012-05-31  0:48   ` Linus Walleij
  2012-05-29  9:37 ` [RFC 07/34] dmaengine: PL08x: remove circular_buffer boolean from channel data Russell King
                   ` (27 subsequent siblings)
  33 siblings, 1 reply; 80+ messages in thread
From: Russell King @ 2012-05-29  9:37 UTC (permalink / raw)
  To: linux-arm-kernel

The pl08x_driver_data spinlock is only ever initialized.  Nothing else
uses it.  Let's get rid of it.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/dma/amba-pl08x.c |    3 ---
 1 files changed, 0 insertions(+), 3 deletions(-)

diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c
index a5bb7f8..219769f 100644
--- a/drivers/dma/amba-pl08x.c
+++ b/drivers/dma/amba-pl08x.c
@@ -142,7 +142,6 @@ struct pl08x_driver_data {
 	int pool_ctr;
 	u8 lli_buses;
 	u8 mem_buses;
-	spinlock_t lock;
 };
 
 /*
@@ -1888,8 +1887,6 @@ static int pl08x_probe(struct amba_device *adev, const struct amba_id *id)
 		goto out_no_lli_pool;
 	}
 
-	spin_lock_init(&pl08x->lock);
-
 	pl08x->base = ioremap(adev->res.start, resource_size(&adev->res));
 	if (!pl08x->base) {
 		ret = -ENOMEM;
-- 
1.7.4.4

^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [RFC 07/34] dmaengine: PL08x: remove circular_buffer boolean from channel data
  2012-05-29  9:30 [RFC 00/34] PL08x DMA conversion to virt-dma Russell King - ARM Linux
                   ` (5 preceding siblings ...)
  2012-05-29  9:37 ` [RFC 06/34] dmaengine: PL08x: remove redundant spinlock Russell King
@ 2012-05-29  9:37 ` Russell King
  2012-05-31  0:49   ` Linus Walleij
  2012-05-29  9:37 ` [RFC 08/34] dmaengine: PL08x: clean up get_signal/put_signal Russell King
                   ` (26 subsequent siblings)
  33 siblings, 1 reply; 80+ messages in thread
From: Russell King @ 2012-05-29  9:37 UTC (permalink / raw)
  To: linux-arm-kernel

Circular buffers are not handled in this way; we have a separate API
call now to setup circular buffers.  So lets not mislead people with
this bool.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/dma/amba-pl08x.c   |    7 -------
 include/linux/amba/pl08x.h |    4 ----
 2 files changed, 0 insertions(+), 11 deletions(-)

diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c
index 219769f..d8d5d27 100644
--- a/drivers/dma/amba-pl08x.c
+++ b/drivers/dma/amba-pl08x.c
@@ -1694,13 +1694,6 @@ static int pl08x_dma_init_virtual_channels(struct pl08x_driver_data *pl08x,
 				return -ENOMEM;
 			}
 		}
-		if (chan->cd->circular_buffer) {
-			dev_err(&pl08x->adev->dev,
-				"channel %s: circular buffers not supported\n",
-				chan->name);
-			kfree(chan);
-			continue;
-		}
 		dev_dbg(&pl08x->adev->dev,
 			 "initialize virtual channel \"%s\"\n",
 			 chan->name);
diff --git a/include/linux/amba/pl08x.h b/include/linux/amba/pl08x.h
index e64ce2c..22590cc 100644
--- a/include/linux/amba/pl08x.h
+++ b/include/linux/amba/pl08x.h
@@ -51,9 +51,6 @@ enum {
  * can be the address of a FIFO register for burst requests for example.
  * This can be left undefined if the PrimeCell API is used for configuring
  * this.
- * @circular_buffer: whether the buffer passed in is circular and
- * shall simply be looped round round (like a record baby round
- * round round round)
  * @single: the device connected to this channel will request single DMA
  * transfers, not bursts. (Bursts are default.)
  * @periph_buses: the device connected to this channel is accessible via
@@ -66,7 +63,6 @@ struct pl08x_channel_data {
 	u32 muxval;
 	u32 cctl;
 	dma_addr_t addr;
-	bool circular_buffer;
 	bool single;
 	u8 periph_buses;
 };
-- 
1.7.4.4

^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [RFC 08/34] dmaengine: PL08x: clean up get_signal/put_signal
  2012-05-29  9:30 [RFC 00/34] PL08x DMA conversion to virt-dma Russell King - ARM Linux
                   ` (6 preceding siblings ...)
  2012-05-29  9:37 ` [RFC 07/34] dmaengine: PL08x: remove circular_buffer boolean from channel data Russell King
@ 2012-05-29  9:37 ` Russell King
  2012-05-31  0:53   ` Linus Walleij
  2012-05-29  9:38 ` [RFC 09/34] dmaengine: PL08x: move private data structures into amba-pl08x.c Russell King
                   ` (25 subsequent siblings)
  33 siblings, 1 reply; 80+ messages in thread
From: Russell King @ 2012-05-29  9:37 UTC (permalink / raw)
  To: linux-arm-kernel

Try to avoid dereferencing the DMA engine's channel struct in these
platform helpers; instead, pass a pointer to the channel data into
get_signal(), and the returned signal number to put_signal().

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/dma/amba-pl08x.c   |    4 ++--
 include/linux/amba/pl08x.h |    4 ++--
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c
index d8d5d27..757a65d 100644
--- a/drivers/dma/amba-pl08x.c
+++ b/drivers/dma/amba-pl08x.c
@@ -870,7 +870,7 @@ static int prep_phy_channel(struct pl08x_dma_chan *plchan,
 	 * Can the platform allow us to use this channel?
 	 */
 	if (plchan->slave && pl08x->pd->get_signal) {
-		ret = pl08x->pd->get_signal(plchan);
+		ret = pl08x->pd->get_signal(plchan->cd);
 		if (ret < 0) {
 			dev_dbg(&pl08x->adev->dev,
 				"unable to use physical channel %d for transfer on %s due to platform restrictions\n",
@@ -905,7 +905,7 @@ static void release_phy_channel(struct pl08x_dma_chan *plchan)
 	struct pl08x_driver_data *pl08x = plchan->host;
 
 	if ((plchan->phychan->signal >= 0) && pl08x->pd->put_signal) {
-		pl08x->pd->put_signal(plchan);
+		pl08x->pd->put_signal(plchan->cd, plchan->phychan->signal);
 		plchan->phychan->signal = -1;
 	}
 	pl08x_put_phy_channel(pl08x, plchan->phychan);
diff --git a/include/linux/amba/pl08x.h b/include/linux/amba/pl08x.h
index 22590cc..85e3a53 100644
--- a/include/linux/amba/pl08x.h
+++ b/include/linux/amba/pl08x.h
@@ -222,8 +222,8 @@ struct pl08x_platform_data {
 	const struct pl08x_channel_data *slave_channels;
 	unsigned int num_slave_channels;
 	struct pl08x_channel_data memcpy_channel;
-	int (*get_signal)(struct pl08x_dma_chan *);
-	void (*put_signal)(struct pl08x_dma_chan *);
+	int (*get_signal)(const struct pl08x_channel_data *);
+	void (*put_signal)(const struct pl08x_channel_data *, int);
 	u8 lli_buses;
 	u8 mem_buses;
 };
-- 
1.7.4.4

^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [RFC 09/34] dmaengine: PL08x: move private data structures into amba-pl08x.c
  2012-05-29  9:30 [RFC 00/34] PL08x DMA conversion to virt-dma Russell King - ARM Linux
                   ` (7 preceding siblings ...)
  2012-05-29  9:37 ` [RFC 08/34] dmaengine: PL08x: clean up get_signal/put_signal Russell King
@ 2012-05-29  9:38 ` Russell King
  2012-05-31  0:54   ` Linus Walleij
  2012-05-29  9:38 ` [RFC 10/34] dmaengine: PL08x: constify channel names and bus_id strings Russell King
                   ` (24 subsequent siblings)
  33 siblings, 1 reply; 80+ messages in thread
From: Russell King @ 2012-05-29  9:38 UTC (permalink / raw)
  To: linux-arm-kernel

Move the driver private data structures into the driver itself, rather
than having them exposed to everyone in a header file.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/dma/amba-pl08x.c   |  136 +++++++++++++++++++++++++++++++++++++++++++
 include/linux/amba/pl08x.h |  138 +-------------------------------------------
 2 files changed, 138 insertions(+), 136 deletions(-)

diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c
index 757a65d..d3ba147 100644
--- a/drivers/dma/amba-pl08x.c
+++ b/drivers/dma/amba-pl08x.c
@@ -90,6 +90,7 @@
 #define DRIVER_NAME	"pl08xdmac"
 
 static struct amba_driver pl08x_amba_driver;
+struct pl08x_driver_data;
 
 /**
  * struct vendor_data - vendor-specific config parameters for PL08x derivatives
@@ -115,6 +116,141 @@ struct pl08x_lli {
 };
 
 /**
+ * struct pl08x_bus_data - information of source or destination
+ * busses for a transfer
+ * @addr: current address
+ * @maxwidth: the maximum width of a transfer on this bus
+ * @buswidth: the width of this bus in bytes: 1, 2 or 4
+ */
+struct pl08x_bus_data {
+	dma_addr_t addr;
+	u8 maxwidth;
+	u8 buswidth;
+};
+
+/**
+ * struct pl08x_phy_chan - holder for the physical channels
+ * @id: physical index to this channel
+ * @lock: a lock to use when altering an instance of this struct
+ * @signal: the physical signal (aka channel) serving this physical channel
+ * right now
+ * @serving: the virtual channel currently being served by this physical
+ * channel
+ */
+struct pl08x_phy_chan {
+	unsigned int id;
+	void __iomem *base;
+	spinlock_t lock;
+	int signal;
+	struct pl08x_dma_chan *serving;
+};
+
+/**
+ * struct pl08x_sg - structure containing data per sg
+ * @src_addr: src address of sg
+ * @dst_addr: dst address of sg
+ * @len: transfer len in bytes
+ * @node: node for txd's dsg_list
+ */
+struct pl08x_sg {
+	dma_addr_t src_addr;
+	dma_addr_t dst_addr;
+	size_t len;
+	struct list_head node;
+};
+
+/**
+ * struct pl08x_txd - wrapper for struct dma_async_tx_descriptor
+ * @tx: async tx descriptor
+ * @node: node for txd list for channels
+ * @dsg_list: list of children sg's
+ * @direction: direction of transfer
+ * @llis_bus: DMA memory address (physical) start for the LLIs
+ * @llis_va: virtual memory address start for the LLIs
+ * @cctl: control reg values for current txd
+ * @ccfg: config reg values for current txd
+ */
+struct pl08x_txd {
+	struct dma_async_tx_descriptor tx;
+	struct list_head node;
+	struct list_head dsg_list;
+	enum dma_transfer_direction direction;
+	dma_addr_t llis_bus;
+	struct pl08x_lli *llis_va;
+	/* Default cctl value for LLIs */
+	u32 cctl;
+	/*
+	 * Settings to be put into the physical channel when we
+	 * trigger this txd.  Other registers are in llis_va[0].
+	 */
+	u32 ccfg;
+};
+
+/**
+ * struct pl08x_dma_chan_state - holds the PL08x specific virtual channel
+ * states
+ * @PL08X_CHAN_IDLE: the channel is idle
+ * @PL08X_CHAN_RUNNING: the channel has allocated a physical transport
+ * channel and is running a transfer on it
+ * @PL08X_CHAN_PAUSED: the channel has allocated a physical transport
+ * channel, but the transfer is currently paused
+ * @PL08X_CHAN_WAITING: the channel is waiting for a physical transport
+ * channel to become available (only pertains to memcpy channels)
+ */
+enum pl08x_dma_chan_state {
+	PL08X_CHAN_IDLE,
+	PL08X_CHAN_RUNNING,
+	PL08X_CHAN_PAUSED,
+	PL08X_CHAN_WAITING,
+};
+
+/**
+ * struct pl08x_dma_chan - this structure wraps a DMA ENGINE channel
+ * @chan: wrappped abstract channel
+ * @phychan: the physical channel utilized by this channel, if there is one
+ * @phychan_hold: if non-zero, hold on to the physical channel even if we
+ * have no pending entries
+ * @tasklet: tasklet scheduled by the IRQ to handle actual work etc
+ * @name: name of channel
+ * @cd: channel platform data
+ * @runtime_addr: address for RX/TX according to the runtime config
+ * @runtime_direction: current direction of this channel according to
+ * runtime config
+ * @pend_list: queued transactions pending on this channel
+ * @at: active transaction on this channel
+ * @lock: a lock for this channel data
+ * @host: a pointer to the host (internal use)
+ * @state: whether the channel is idle, paused, running etc
+ * @slave: whether this channel is a device (slave) or for memcpy
+ * @device_fc: Flow Controller Settings for ccfg register. Only valid for slave
+ * channels. Fill with 'true' if peripheral should be flow controller. Direction
+ * will be selected at Runtime.
+ * @waiting: a TX descriptor on this channel which is waiting for a physical
+ * channel to become available
+ */
+struct pl08x_dma_chan {
+	struct dma_chan chan;
+	struct pl08x_phy_chan *phychan;
+	int phychan_hold;
+	struct tasklet_struct tasklet;
+	char *name;
+	const struct pl08x_channel_data *cd;
+	dma_addr_t src_addr;
+	dma_addr_t dst_addr;
+	u32 src_cctl;
+	u32 dst_cctl;
+	enum dma_transfer_direction runtime_direction;
+	struct list_head pend_list;
+	struct pl08x_txd *at;
+	spinlock_t lock;
+	struct pl08x_driver_data *host;
+	enum pl08x_dma_chan_state state;
+	bool slave;
+	bool device_fc;
+	struct pl08x_txd *waiting;
+};
+
+/**
  * struct pl08x_driver_data - the local state holder for the PL08x
  * @slave: slave engine for this instance
  * @memcpy: memcpy engine for this instance
diff --git a/include/linux/amba/pl08x.h b/include/linux/amba/pl08x.h
index 85e3a53..48d02bf 100644
--- a/include/linux/amba/pl08x.h
+++ b/include/linux/amba/pl08x.h
@@ -21,8 +21,9 @@
 #include <linux/dmaengine.h>
 #include <linux/interrupt.h>
 
-struct pl08x_lli;
 struct pl08x_driver_data;
+struct pl08x_phy_chan;
+struct pl08x_txd;
 
 /* Bitmasks for selecting AHB ports for DMA transfers */
 enum {
@@ -68,141 +69,6 @@ struct pl08x_channel_data {
 };
 
 /**
- * Struct pl08x_bus_data - information of source or destination
- * busses for a transfer
- * @addr: current address
- * @maxwidth: the maximum width of a transfer on this bus
- * @buswidth: the width of this bus in bytes: 1, 2 or 4
- */
-struct pl08x_bus_data {
-	dma_addr_t addr;
-	u8 maxwidth;
-	u8 buswidth;
-};
-
-/**
- * struct pl08x_phy_chan - holder for the physical channels
- * @id: physical index to this channel
- * @lock: a lock to use when altering an instance of this struct
- * @signal: the physical signal (aka channel) serving this physical channel
- * right now
- * @serving: the virtual channel currently being served by this physical
- * channel
- */
-struct pl08x_phy_chan {
-	unsigned int id;
-	void __iomem *base;
-	spinlock_t lock;
-	int signal;
-	struct pl08x_dma_chan *serving;
-};
-
-/**
- * struct pl08x_sg - structure containing data per sg
- * @src_addr: src address of sg
- * @dst_addr: dst address of sg
- * @len: transfer len in bytes
- * @node: node for txd's dsg_list
- */
-struct pl08x_sg {
-	dma_addr_t src_addr;
-	dma_addr_t dst_addr;
-	size_t len;
-	struct list_head node;
-};
-
-/**
- * struct pl08x_txd - wrapper for struct dma_async_tx_descriptor
- * @tx: async tx descriptor
- * @node: node for txd list for channels
- * @dsg_list: list of children sg's
- * @direction: direction of transfer
- * @llis_bus: DMA memory address (physical) start for the LLIs
- * @llis_va: virtual memory address start for the LLIs
- * @cctl: control reg values for current txd
- * @ccfg: config reg values for current txd
- */
-struct pl08x_txd {
-	struct dma_async_tx_descriptor tx;
-	struct list_head node;
-	struct list_head dsg_list;
-	enum dma_transfer_direction direction;
-	dma_addr_t llis_bus;
-	struct pl08x_lli *llis_va;
-	/* Default cctl value for LLIs */
-	u32 cctl;
-	/*
-	 * Settings to be put into the physical channel when we
-	 * trigger this txd.  Other registers are in llis_va[0].
-	 */
-	u32 ccfg;
-};
-
-/**
- * struct pl08x_dma_chan_state - holds the PL08x specific virtual channel
- * states
- * @PL08X_CHAN_IDLE: the channel is idle
- * @PL08X_CHAN_RUNNING: the channel has allocated a physical transport
- * channel and is running a transfer on it
- * @PL08X_CHAN_PAUSED: the channel has allocated a physical transport
- * channel, but the transfer is currently paused
- * @PL08X_CHAN_WAITING: the channel is waiting for a physical transport
- * channel to become available (only pertains to memcpy channels)
- */
-enum pl08x_dma_chan_state {
-	PL08X_CHAN_IDLE,
-	PL08X_CHAN_RUNNING,
-	PL08X_CHAN_PAUSED,
-	PL08X_CHAN_WAITING,
-};
-
-/**
- * struct pl08x_dma_chan - this structure wraps a DMA ENGINE channel
- * @chan: wrappped abstract channel
- * @phychan: the physical channel utilized by this channel, if there is one
- * @phychan_hold: if non-zero, hold on to the physical channel even if we
- * have no pending entries
- * @tasklet: tasklet scheduled by the IRQ to handle actual work etc
- * @name: name of channel
- * @cd: channel platform data
- * @runtime_addr: address for RX/TX according to the runtime config
- * @runtime_direction: current direction of this channel according to
- * runtime config
- * @pend_list: queued transactions pending on this channel
- * @at: active transaction on this channel
- * @lock: a lock for this channel data
- * @host: a pointer to the host (internal use)
- * @state: whether the channel is idle, paused, running etc
- * @slave: whether this channel is a device (slave) or for memcpy
- * @device_fc: Flow Controller Settings for ccfg register. Only valid for slave
- * channels. Fill with 'true' if peripheral should be flow controller. Direction
- * will be selected at Runtime.
- * @waiting: a TX descriptor on this channel which is waiting for a physical
- * channel to become available
- */
-struct pl08x_dma_chan {
-	struct dma_chan chan;
-	struct pl08x_phy_chan *phychan;
-	int phychan_hold;
-	struct tasklet_struct tasklet;
-	char *name;
-	const struct pl08x_channel_data *cd;
-	dma_addr_t src_addr;
-	dma_addr_t dst_addr;
-	u32 src_cctl;
-	u32 dst_cctl;
-	enum dma_transfer_direction runtime_direction;
-	struct list_head pend_list;
-	struct pl08x_txd *at;
-	spinlock_t lock;
-	struct pl08x_driver_data *host;
-	enum pl08x_dma_chan_state state;
-	bool slave;
-	bool device_fc;
-	struct pl08x_txd *waiting;
-};
-
-/**
  * struct pl08x_platform_data - the platform configuration for the PL08x
  * PrimeCells.
  * @slave_channels: the channels defined for the different devices on the
-- 
1.7.4.4

^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [RFC 10/34] dmaengine: PL08x: constify channel names and bus_id strings
  2012-05-29  9:30 [RFC 00/34] PL08x DMA conversion to virt-dma Russell King - ARM Linux
                   ` (8 preceding siblings ...)
  2012-05-29  9:38 ` [RFC 09/34] dmaengine: PL08x: move private data structures into amba-pl08x.c Russell King
@ 2012-05-29  9:38 ` Russell King
  2012-05-31  0:55   ` Linus Walleij
  2012-05-29  9:38 ` [RFC 11/34] dmaengine: PL08x: get src/dst addr direct from dma_slave_config struct Russell King
                   ` (23 subsequent siblings)
  33 siblings, 1 reply; 80+ messages in thread
From: Russell King @ 2012-05-29  9:38 UTC (permalink / raw)
  To: linux-arm-kernel

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/dma/amba-pl08x.c   |    2 +-
 include/linux/amba/pl08x.h |    2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c
index d3ba147..0ba1426 100644
--- a/drivers/dma/amba-pl08x.c
+++ b/drivers/dma/amba-pl08x.c
@@ -233,7 +233,7 @@ struct pl08x_dma_chan {
 	struct pl08x_phy_chan *phychan;
 	int phychan_hold;
 	struct tasklet_struct tasklet;
-	char *name;
+	const char *name;
 	const struct pl08x_channel_data *cd;
 	dma_addr_t src_addr;
 	dma_addr_t dst_addr;
diff --git a/include/linux/amba/pl08x.h b/include/linux/amba/pl08x.h
index 48d02bf..158ce26 100644
--- a/include/linux/amba/pl08x.h
+++ b/include/linux/amba/pl08x.h
@@ -58,7 +58,7 @@ enum {
  * these buses (use PL08X_AHB1 | PL08X_AHB2).
  */
 struct pl08x_channel_data {
-	char *bus_id;
+	const char *bus_id;
 	int min_signal;
 	int max_signal;
 	u32 muxval;
-- 
1.7.4.4

^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [RFC 11/34] dmaengine: PL08x: get src/dst addr direct from dma_slave_config struct
  2012-05-29  9:30 [RFC 00/34] PL08x DMA conversion to virt-dma Russell King - ARM Linux
                   ` (9 preceding siblings ...)
  2012-05-29  9:38 ` [RFC 10/34] dmaengine: PL08x: constify channel names and bus_id strings Russell King
@ 2012-05-29  9:38 ` Russell King
  2012-05-31  0:56   ` Linus Walleij
  2012-05-29  9:39 ` [RFC 12/34] dmaengine: PL08x: get rid of device_fc in struct pl08x_dma_chan Russell King
                   ` (22 subsequent siblings)
  33 siblings, 1 reply; 80+ messages in thread
From: Russell King @ 2012-05-29  9:38 UTC (permalink / raw)
  To: linux-arm-kernel

Add a dma_slave_config struct to struct pl08x_dma_chan, and move the
src_addr/dst_addr arguments into this struct.  This is a step away
from using the dma_slave_config's direction member.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/dma/amba-pl08x.c |   15 +++++++--------
 1 files changed, 7 insertions(+), 8 deletions(-)

diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c
index 0ba1426..f83db39 100644
--- a/drivers/dma/amba-pl08x.c
+++ b/drivers/dma/amba-pl08x.c
@@ -235,8 +235,7 @@ struct pl08x_dma_chan {
 	struct tasklet_struct tasklet;
 	const char *name;
 	const struct pl08x_channel_data *cd;
-	dma_addr_t src_addr;
-	dma_addr_t dst_addr;
+	struct dma_slave_config cfg;
 	u32 src_cctl;
 	u32 dst_cctl;
 	enum dma_transfer_direction runtime_direction;
@@ -1241,6 +1240,8 @@ static int dma_set_runtime_config(struct dma_chan *chan,
 		return -EINVAL;
 	}
 
+	plchan->cfg = *config;
+
 	cctl |= width << PL080_CONTROL_SWIDTH_SHIFT;
 	cctl |= width << PL080_CONTROL_DWIDTH_SHIFT;
 
@@ -1259,12 +1260,10 @@ static int dma_set_runtime_config(struct dma_chan *chan,
 	plchan->device_fc = config->device_fc;
 
 	if (plchan->runtime_direction == DMA_DEV_TO_MEM) {
-		plchan->src_addr = config->src_addr;
 		plchan->src_cctl = pl08x_cctl(cctl) | PL080_CONTROL_DST_INCR |
 			pl08x_select_bus(plchan->cd->periph_buses,
 					 pl08x->mem_buses);
 	} else {
-		plchan->dst_addr = config->dst_addr;
 		plchan->dst_cctl = pl08x_cctl(cctl) | PL080_CONTROL_SRC_INCR |
 			pl08x_select_bus(pl08x->mem_buses,
 					 plchan->cd->periph_buses);
@@ -1478,10 +1477,10 @@ static struct dma_async_tx_descriptor *pl08x_prep_slave_sg(
 
 	if (direction == DMA_MEM_TO_DEV) {
 		txd->cctl = plchan->dst_cctl;
-		slave_addr = plchan->dst_addr;
+		slave_addr = plchan->cfg.dst_addr;
 	} else if (direction == DMA_DEV_TO_MEM) {
 		txd->cctl = plchan->src_cctl;
-		slave_addr = plchan->src_addr;
+		slave_addr = plchan->cfg.src_addr;
 	} else {
 		pl08x_free_txd(pl08x, txd);
 		dev_err(&pl08x->adev->dev,
@@ -1783,8 +1782,8 @@ static void pl08x_dma_slave_init(struct pl08x_dma_chan *chan)
 
 	chan->slave = true;
 	chan->name = chan->cd->bus_id;
-	chan->src_addr = chan->cd->addr;
-	chan->dst_addr = chan->cd->addr;
+	chan->cfg.src_addr = chan->cd->addr;
+	chan->cfg.dst_addr = chan->cd->addr;
 	chan->src_cctl = cctl | PL080_CONTROL_DST_INCR |
 		pl08x_select_bus(chan->cd->periph_buses, chan->host->mem_buses);
 	chan->dst_cctl = cctl | PL080_CONTROL_SRC_INCR |
-- 
1.7.4.4

^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [RFC 12/34] dmaengine: PL08x: get rid of device_fc in struct pl08x_dma_chan
  2012-05-29  9:30 [RFC 00/34] PL08x DMA conversion to virt-dma Russell King - ARM Linux
                   ` (10 preceding siblings ...)
  2012-05-29  9:38 ` [RFC 11/34] dmaengine: PL08x: get src/dst addr direct from dma_slave_config struct Russell King
@ 2012-05-29  9:39 ` Russell King
  2012-05-31  0:57   ` Linus Walleij
  2012-05-29  9:39 ` [RFC 13/34] dmaengine: PL08x: move the bus and increment selection to dma prepare function Russell King
                   ` (21 subsequent siblings)
  33 siblings, 1 reply; 80+ messages in thread
From: Russell King @ 2012-05-29  9:39 UTC (permalink / raw)
  To: linux-arm-kernel

As we now store the dma_slave_config in pl08x_dma_chan, we don't need
to store this separately.  Use the one in dma_slave_config directly.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/dma/amba-pl08x.c |    8 +-------
 1 files changed, 1 insertions(+), 7 deletions(-)

diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c
index f83db39..0f27c77 100644
--- a/drivers/dma/amba-pl08x.c
+++ b/drivers/dma/amba-pl08x.c
@@ -222,9 +222,6 @@ enum pl08x_dma_chan_state {
  * @host: a pointer to the host (internal use)
  * @state: whether the channel is idle, paused, running etc
  * @slave: whether this channel is a device (slave) or for memcpy
- * @device_fc: Flow Controller Settings for ccfg register. Only valid for slave
- * channels. Fill with 'true' if peripheral should be flow controller. Direction
- * will be selected at Runtime.
  * @waiting: a TX descriptor on this channel which is waiting for a physical
  * channel to become available
  */
@@ -245,7 +242,6 @@ struct pl08x_dma_chan {
 	struct pl08x_driver_data *host;
 	enum pl08x_dma_chan_state state;
 	bool slave;
-	bool device_fc;
 	struct pl08x_txd *waiting;
 };
 
@@ -1257,8 +1253,6 @@ static int dma_set_runtime_config(struct dma_chan *chan,
 	cctl |= burst << PL080_CONTROL_SB_SIZE_SHIFT;
 	cctl |= burst << PL080_CONTROL_DB_SIZE_SHIFT;
 
-	plchan->device_fc = config->device_fc;
-
 	if (plchan->runtime_direction == DMA_DEV_TO_MEM) {
 		plchan->src_cctl = pl08x_cctl(cctl) | PL080_CONTROL_DST_INCR |
 			pl08x_select_bus(plchan->cd->periph_buses,
@@ -1488,7 +1482,7 @@ static struct dma_async_tx_descriptor *pl08x_prep_slave_sg(
 		return NULL;
 	}
 
-	if (plchan->device_fc)
+	if (plchan->cfg.device_fc)
 		tmp = (direction == DMA_MEM_TO_DEV) ? PL080_FLOW_MEM2PER_PER :
 			PL080_FLOW_PER2MEM_PER;
 	else
-- 
1.7.4.4

^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [RFC 13/34] dmaengine: PL08x: move the bus and increment selection to dma prepare function
  2012-05-29  9:30 [RFC 00/34] PL08x DMA conversion to virt-dma Russell King - ARM Linux
                   ` (11 preceding siblings ...)
  2012-05-29  9:39 ` [RFC 12/34] dmaengine: PL08x: get rid of device_fc in struct pl08x_dma_chan Russell King
@ 2012-05-29  9:39 ` Russell King
  2012-05-31  0:57   ` Linus Walleij
  2012-05-29  9:39 ` [RFC 14/34] dmaengine: PL08x: extract function to to generate cctl values Russell King
                   ` (20 subsequent siblings)
  33 siblings, 1 reply; 80+ messages in thread
From: Russell King @ 2012-05-29  9:39 UTC (permalink / raw)
  To: linux-arm-kernel

Move the bus and transfer increment selection to the DMA prepare
function rather than the slave configuration function.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/dma/amba-pl08x.c |   26 ++++++++++++++------------
 1 files changed, 14 insertions(+), 12 deletions(-)

diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c
index 0f27c77..93ad50d 100644
--- a/drivers/dma/amba-pl08x.c
+++ b/drivers/dma/amba-pl08x.c
@@ -1254,13 +1254,9 @@ static int dma_set_runtime_config(struct dma_chan *chan,
 	cctl |= burst << PL080_CONTROL_DB_SIZE_SHIFT;
 
 	if (plchan->runtime_direction == DMA_DEV_TO_MEM) {
-		plchan->src_cctl = pl08x_cctl(cctl) | PL080_CONTROL_DST_INCR |
-			pl08x_select_bus(plchan->cd->periph_buses,
-					 pl08x->mem_buses);
+		plchan->src_cctl = pl08x_cctl(cctl);
 	} else {
-		plchan->dst_cctl = pl08x_cctl(cctl) | PL080_CONTROL_SRC_INCR |
-			pl08x_select_bus(pl08x->mem_buses,
-					 plchan->cd->periph_buses);
+		plchan->dst_cctl = pl08x_cctl(cctl);
 	}
 
 	dev_dbg(&pl08x->adev->dev,
@@ -1447,6 +1443,8 @@ static struct dma_async_tx_descriptor *pl08x_prep_slave_sg(
 	struct scatterlist *sg;
 	dma_addr_t slave_addr;
 	int ret, tmp;
+	u8 src_buses, dst_buses;
+	u32 cctl;
 
 	dev_dbg(&pl08x->adev->dev, "%s prepare transaction of %d bytes from %s\n",
 			__func__, sgl->length, plchan->name);
@@ -1470,11 +1468,15 @@ static struct dma_async_tx_descriptor *pl08x_prep_slave_sg(
 	txd->direction = direction;
 
 	if (direction == DMA_MEM_TO_DEV) {
-		txd->cctl = plchan->dst_cctl;
+		cctl = plchan->dst_cctl | PL080_CONTROL_SRC_INCR;
 		slave_addr = plchan->cfg.dst_addr;
+		src_buses = pl08x->mem_buses;
+		dst_buses = plchan->cd->periph_buses;
 	} else if (direction == DMA_DEV_TO_MEM) {
-		txd->cctl = plchan->src_cctl;
+		cctl = plchan->src_cctl | PL080_CONTROL_DST_INCR;
 		slave_addr = plchan->cfg.src_addr;
+		src_buses = plchan->cd->periph_buses;
+		dst_buses = pl08x->mem_buses;
 	} else {
 		pl08x_free_txd(pl08x, txd);
 		dev_err(&pl08x->adev->dev,
@@ -1482,6 +1484,8 @@ static struct dma_async_tx_descriptor *pl08x_prep_slave_sg(
 		return NULL;
 	}
 
+	txd->cctl = cctl | pl08x_select_bus(src_buses, dst_buses);
+
 	if (plchan->cfg.device_fc)
 		tmp = (direction == DMA_MEM_TO_DEV) ? PL080_FLOW_MEM2PER_PER :
 			PL080_FLOW_PER2MEM_PER;
@@ -1778,10 +1782,8 @@ static void pl08x_dma_slave_init(struct pl08x_dma_chan *chan)
 	chan->name = chan->cd->bus_id;
 	chan->cfg.src_addr = chan->cd->addr;
 	chan->cfg.dst_addr = chan->cd->addr;
-	chan->src_cctl = cctl | PL080_CONTROL_DST_INCR |
-		pl08x_select_bus(chan->cd->periph_buses, chan->host->mem_buses);
-	chan->dst_cctl = cctl | PL080_CONTROL_SRC_INCR |
-		pl08x_select_bus(chan->host->mem_buses, chan->cd->periph_buses);
+	chan->src_cctl = cctl;
+	chan->dst_cctl = cctl;
 }
 
 /*
-- 
1.7.4.4

^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [RFC 14/34] dmaengine: PL08x: extract function to to generate cctl values
  2012-05-29  9:30 [RFC 00/34] PL08x DMA conversion to virt-dma Russell King - ARM Linux
                   ` (12 preceding siblings ...)
  2012-05-29  9:39 ` [RFC 13/34] dmaengine: PL08x: move the bus and increment selection to dma prepare function Russell King
@ 2012-05-29  9:39 ` Russell King
  2012-05-31  1:00   ` Linus Walleij
  2012-05-29  9:40 ` [RFC 15/34] dmaengine: PL08x: ignore 'direction' argument in dma_slave_config Russell King
                   ` (19 subsequent siblings)
  33 siblings, 1 reply; 80+ messages in thread
From: Russell King @ 2012-05-29  9:39 UTC (permalink / raw)
  To: linux-arm-kernel

Extract the functionality from dma_slave_config to generate the cctl
values for a given bus width and burst size.  This allows us to use
this elsewhere in the driver, namely the prepare functions.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/dma/amba-pl08x.c |   53 +++++++++++++++++++++++++++------------------
 1 files changed, 32 insertions(+), 21 deletions(-)

diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c
index 93ad50d..54aa290 100644
--- a/drivers/dma/amba-pl08x.c
+++ b/drivers/dma/amba-pl08x.c
@@ -1203,14 +1203,40 @@ static u32 pl08x_burst(u32 maxburst)
 	return burst_sizes[i].reg;
 }
 
+static u32 pl08x_get_cctl(struct pl08x_dma_chan *plchan,
+	enum dma_slave_buswidth addr_width, u32 maxburst)
+{
+	u32 width, burst, cctl = 0;
+
+	width = pl08x_width(addr_width);
+	if (width == ~0)
+		return ~0;
+
+	cctl |= width << PL080_CONTROL_SWIDTH_SHIFT;
+	cctl |= width << PL080_CONTROL_DWIDTH_SHIFT;
+
+	/*
+	 * If this channel will only request single transfers, set this
+	 * down to ONE element.  Also select one element if no maxburst
+	 * is specified.
+	 */
+	if (plchan->cd->single)
+		maxburst = 1;
+
+	burst = pl08x_burst(maxburst);
+	cctl |= burst << PL080_CONTROL_SB_SIZE_SHIFT;
+	cctl |= burst << PL080_CONTROL_DB_SIZE_SHIFT;
+
+	return pl08x_cctl(cctl);
+}
+
 static int dma_set_runtime_config(struct dma_chan *chan,
 				  struct dma_slave_config *config)
 {
 	struct pl08x_dma_chan *plchan = to_pl08x_chan(chan);
 	struct pl08x_driver_data *pl08x = plchan->host;
 	enum dma_slave_buswidth addr_width;
-	u32 width, burst, maxburst;
-	u32 cctl = 0;
+	u32 maxburst, cctl = 0;
 
 	if (!plchan->slave)
 		return -EINVAL;
@@ -1229,8 +1255,8 @@ static int dma_set_runtime_config(struct dma_chan *chan,
 		return -EINVAL;
 	}
 
-	width = pl08x_width(addr_width);
-	if (width == ~0) {
+	cctl = pl08x_get_cctl(plchan, addr_width, maxburst);
+	if (cctl == ~0) {
 		dev_err(&pl08x->adev->dev,
 			"bad runtime_config: alien address width\n");
 		return -EINVAL;
@@ -1238,25 +1264,10 @@ static int dma_set_runtime_config(struct dma_chan *chan,
 
 	plchan->cfg = *config;
 
-	cctl |= width << PL080_CONTROL_SWIDTH_SHIFT;
-	cctl |= width << PL080_CONTROL_DWIDTH_SHIFT;
-
-	/*
-	 * If this channel will only request single transfers, set this
-	 * down to ONE element.  Also select one element if no maxburst
-	 * is specified.
-	 */
-	if (plchan->cd->single)
-		maxburst = 1;
-
-	burst = pl08x_burst(maxburst);
-	cctl |= burst << PL080_CONTROL_SB_SIZE_SHIFT;
-	cctl |= burst << PL080_CONTROL_DB_SIZE_SHIFT;
-
 	if (plchan->runtime_direction == DMA_DEV_TO_MEM) {
-		plchan->src_cctl = pl08x_cctl(cctl);
+		plchan->src_cctl = cctl;
 	} else {
-		plchan->dst_cctl = pl08x_cctl(cctl);
+		plchan->dst_cctl = cctl;
 	}
 
 	dev_dbg(&pl08x->adev->dev,
-- 
1.7.4.4

^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [RFC 15/34] dmaengine: PL08x: ignore 'direction' argument in dma_slave_config
  2012-05-29  9:30 [RFC 00/34] PL08x DMA conversion to virt-dma Russell King - ARM Linux
                   ` (13 preceding siblings ...)
  2012-05-29  9:39 ` [RFC 14/34] dmaengine: PL08x: extract function to to generate cctl values Russell King
@ 2012-05-29  9:40 ` Russell King
  2012-05-31  1:01   ` Linus Walleij
  2012-05-29  9:40 ` [RFC 16/34] dmaengine: PL08x: get rid of unnecessary checks " Russell King
                   ` (18 subsequent siblings)
  33 siblings, 1 reply; 80+ messages in thread
From: Russell King @ 2012-05-29  9:40 UTC (permalink / raw)
  To: linux-arm-kernel

Ignore the direction argument in dma_slave_config, and configure both
directions independently.  We still check that the configuration for
the intended direction is valid; this check will eventually be dropped.
This check is just for debugging at present.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/dma/amba-pl08x.c |   56 ++++++++++++++-------------------------------
 1 files changed, 18 insertions(+), 38 deletions(-)

diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c
index 54aa290..a99a59d 100644
--- a/drivers/dma/amba-pl08x.c
+++ b/drivers/dma/amba-pl08x.c
@@ -214,8 +214,6 @@ enum pl08x_dma_chan_state {
  * @name: name of channel
  * @cd: channel platform data
  * @runtime_addr: address for RX/TX according to the runtime config
- * @runtime_direction: current direction of this channel according to
- * runtime config
  * @pend_list: queued transactions pending on this channel
  * @at: active transaction on this channel
  * @lock: a lock for this channel data
@@ -235,7 +233,6 @@ struct pl08x_dma_chan {
 	struct dma_slave_config cfg;
 	u32 src_cctl;
 	u32 dst_cctl;
-	enum dma_transfer_direction runtime_direction;
 	struct list_head pend_list;
 	struct pl08x_txd *at;
 	spinlock_t lock;
@@ -1235,50 +1232,31 @@ static int dma_set_runtime_config(struct dma_chan *chan,
 {
 	struct pl08x_dma_chan *plchan = to_pl08x_chan(chan);
 	struct pl08x_driver_data *pl08x = plchan->host;
-	enum dma_slave_buswidth addr_width;
-	u32 maxburst, cctl = 0;
+	u32 src_cctl, dst_cctl;
 
 	if (!plchan->slave)
 		return -EINVAL;
 
-	/* Transfer direction */
-	plchan->runtime_direction = config->direction;
-	if (config->direction == DMA_MEM_TO_DEV) {
-		addr_width = config->dst_addr_width;
-		maxburst = config->dst_maxburst;
-	} else if (config->direction == DMA_DEV_TO_MEM) {
-		addr_width = config->src_addr_width;
-		maxburst = config->src_maxburst;
-	} else {
+	dst_cctl = pl08x_get_cctl(plchan, config->dst_addr_width,
+				  config->dst_maxburst);
+	if (dst_cctl == ~0 && config->direction == DMA_MEM_TO_DEV) {
 		dev_err(&pl08x->adev->dev,
-			"bad runtime_config: alien transfer direction\n");
+			"bad runtime_config: alien address width (M2D)\n");
 		return -EINVAL;
 	}
 
-	cctl = pl08x_get_cctl(plchan, addr_width, maxburst);
-	if (cctl == ~0) {
+	src_cctl = pl08x_get_cctl(plchan, config->src_addr_width,
+				  config->src_maxburst);
+	if (src_cctl == ~0 && config->direction == DMA_DEV_TO_MEM) {
 		dev_err(&pl08x->adev->dev,
-			"bad runtime_config: alien address width\n");
+			"bad runtime_config: alien address width (D2M)\n");
 		return -EINVAL;
 	}
 
+	plchan->dst_cctl = dst_cctl;
+	plchan->src_cctl = src_cctl;
 	plchan->cfg = *config;
 
-	if (plchan->runtime_direction == DMA_DEV_TO_MEM) {
-		plchan->src_cctl = cctl;
-	} else {
-		plchan->dst_cctl = cctl;
-	}
-
-	dev_dbg(&pl08x->adev->dev,
-		"configured channel %s (%s) for %s, data width %d, "
-		"maxburst %d words, LE, CCTL=0x%08x\n",
-		dma_chan_name(chan), plchan->name,
-		(config->direction == DMA_DEV_TO_MEM) ? "RX" : "TX",
-		addr_width,
-		maxburst,
-		cctl);
-
 	return 0;
 }
 
@@ -1466,11 +1444,6 @@ static struct dma_async_tx_descriptor *pl08x_prep_slave_sg(
 		return NULL;
 	}
 
-	if (direction != plchan->runtime_direction)
-		dev_err(&pl08x->adev->dev, "%s DMA setup does not match "
-			"the direction configured for the PrimeCell\n",
-			__func__);
-
 	/*
 	 * Set up addresses, the PrimeCell configured address
 	 * will take precedence since this may configure the
@@ -1495,6 +1468,13 @@ static struct dma_async_tx_descriptor *pl08x_prep_slave_sg(
 		return NULL;
 	}
 
+	if (cctl == ~0) {
+		pl08x_free_txd(pl08x, txd);
+		dev_err(&pl08x->adev->dev,
+			"DMA slave configuration botched?\n");
+		return NULL;
+	}
+
 	txd->cctl = cctl | pl08x_select_bus(src_buses, dst_buses);
 
 	if (plchan->cfg.device_fc)
-- 
1.7.4.4

^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [RFC 16/34] dmaengine: PL08x: get rid of unnecessary checks in dma_slave_config
  2012-05-29  9:30 [RFC 00/34] PL08x DMA conversion to virt-dma Russell King - ARM Linux
                   ` (14 preceding siblings ...)
  2012-05-29  9:40 ` [RFC 15/34] dmaengine: PL08x: ignore 'direction' argument in dma_slave_config Russell King
@ 2012-05-29  9:40 ` Russell King
  2012-05-31  1:02   ` Linus Walleij
  2012-05-29  9:40 ` [RFC 17/34] dmaengine: PL08x: split DMA signal muxing from channel alloc Russell King
                   ` (17 subsequent siblings)
  33 siblings, 1 reply; 80+ messages in thread
From: Russell King @ 2012-05-29  9:40 UTC (permalink / raw)
  To: linux-arm-kernel

Get rid of the unnecessary checks in dma_slave_config utilizing
the DMA direction.  This allows us to move the computation of
cctl to the prepare function.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/dma/amba-pl08x.c   |   41 +++++++++++++----------------------------
 include/linux/amba/pl08x.h |    5 +++--
 2 files changed, 16 insertions(+), 30 deletions(-)

diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c
index a99a59d..fa1f9d2 100644
--- a/drivers/dma/amba-pl08x.c
+++ b/drivers/dma/amba-pl08x.c
@@ -231,8 +231,6 @@ struct pl08x_dma_chan {
 	const char *name;
 	const struct pl08x_channel_data *cd;
 	struct dma_slave_config cfg;
-	u32 src_cctl;
-	u32 dst_cctl;
 	struct list_head pend_list;
 	struct pl08x_txd *at;
 	spinlock_t lock;
@@ -1231,30 +1229,15 @@ static int dma_set_runtime_config(struct dma_chan *chan,
 				  struct dma_slave_config *config)
 {
 	struct pl08x_dma_chan *plchan = to_pl08x_chan(chan);
-	struct pl08x_driver_data *pl08x = plchan->host;
-	u32 src_cctl, dst_cctl;
 
 	if (!plchan->slave)
 		return -EINVAL;
 
-	dst_cctl = pl08x_get_cctl(plchan, config->dst_addr_width,
-				  config->dst_maxburst);
-	if (dst_cctl == ~0 && config->direction == DMA_MEM_TO_DEV) {
-		dev_err(&pl08x->adev->dev,
-			"bad runtime_config: alien address width (M2D)\n");
+	/* Reject definitely invalid configurations */
+	if (config->src_addr_width == DMA_SLAVE_BUSWIDTH_8_BYTES ||
+	    config->dst_addr_width == DMA_SLAVE_BUSWIDTH_8_BYTES)
 		return -EINVAL;
-	}
 
-	src_cctl = pl08x_get_cctl(plchan, config->src_addr_width,
-				  config->src_maxburst);
-	if (src_cctl == ~0 && config->direction == DMA_DEV_TO_MEM) {
-		dev_err(&pl08x->adev->dev,
-			"bad runtime_config: alien address width (D2M)\n");
-		return -EINVAL;
-	}
-
-	plchan->dst_cctl = dst_cctl;
-	plchan->src_cctl = src_cctl;
 	plchan->cfg = *config;
 
 	return 0;
@@ -1403,7 +1386,7 @@ static struct dma_async_tx_descriptor *pl08x_prep_dma_memcpy(
 
 	/* Set platform data for m2m */
 	txd->ccfg |= PL080_FLOW_MEM2MEM << PL080_CONFIG_FLOW_CONTROL_SHIFT;
-	txd->cctl = pl08x->pd->memcpy_channel.cctl &
+	txd->cctl = pl08x->pd->memcpy_channel.cctl_memcpy &
 			~(PL080_CONTROL_DST_AHB2 | PL080_CONTROL_SRC_AHB2);
 
 	/* Both to be incremented or the code will break */
@@ -1430,10 +1413,11 @@ static struct dma_async_tx_descriptor *pl08x_prep_slave_sg(
 	struct pl08x_txd *txd;
 	struct pl08x_sg *dsg;
 	struct scatterlist *sg;
+	enum dma_slave_buswidth addr_width;
 	dma_addr_t slave_addr;
 	int ret, tmp;
 	u8 src_buses, dst_buses;
-	u32 cctl;
+	u32 maxburst, cctl;
 
 	dev_dbg(&pl08x->adev->dev, "%s prepare transaction of %d bytes from %s\n",
 			__func__, sgl->length, plchan->name);
@@ -1452,13 +1436,17 @@ static struct dma_async_tx_descriptor *pl08x_prep_slave_sg(
 	txd->direction = direction;
 
 	if (direction == DMA_MEM_TO_DEV) {
-		cctl = plchan->dst_cctl | PL080_CONTROL_SRC_INCR;
+		cctl = PL080_CONTROL_SRC_INCR;
 		slave_addr = plchan->cfg.dst_addr;
+		addr_width = plchan->cfg.dst_addr_width;
+		maxburst = plchan->cfg.dst_maxburst;
 		src_buses = pl08x->mem_buses;
 		dst_buses = plchan->cd->periph_buses;
 	} else if (direction == DMA_DEV_TO_MEM) {
-		cctl = plchan->src_cctl | PL080_CONTROL_DST_INCR;
+		cctl = PL080_CONTROL_DST_INCR;
 		slave_addr = plchan->cfg.src_addr;
+		addr_width = plchan->cfg.src_addr_width;
+		maxburst = plchan->cfg.src_maxburst;
 		src_buses = plchan->cd->periph_buses;
 		dst_buses = pl08x->mem_buses;
 	} else {
@@ -1468,6 +1456,7 @@ static struct dma_async_tx_descriptor *pl08x_prep_slave_sg(
 		return NULL;
 	}
 
+	cctl |= pl08x_get_cctl(plchan, addr_width, maxburst);
 	if (cctl == ~0) {
 		pl08x_free_txd(pl08x, txd);
 		dev_err(&pl08x->adev->dev,
@@ -1767,14 +1756,10 @@ static irqreturn_t pl08x_irq(int irq, void *dev)
 
 static void pl08x_dma_slave_init(struct pl08x_dma_chan *chan)
 {
-	u32 cctl = pl08x_cctl(chan->cd->cctl);
-
 	chan->slave = true;
 	chan->name = chan->cd->bus_id;
 	chan->cfg.src_addr = chan->cd->addr;
 	chan->cfg.dst_addr = chan->cd->addr;
-	chan->src_cctl = cctl;
-	chan->dst_cctl = cctl;
 }
 
 /*
diff --git a/include/linux/amba/pl08x.h b/include/linux/amba/pl08x.h
index 158ce26..2a5f64a 100644
--- a/include/linux/amba/pl08x.h
+++ b/include/linux/amba/pl08x.h
@@ -47,7 +47,8 @@ enum {
  * devices with static assignments
  * @muxval: a number usually used to poke into some mux regiser to
  * mux in the signal to this channel
- * @cctl_opt: default options for the channel control register
+ * @cctl_memcpy: options for the channel control register for memcpy
+ *  *** not used for slave channels ***
  * @addr: source/target address in physical memory for this DMA channel,
  * can be the address of a FIFO register for burst requests for example.
  * This can be left undefined if the PrimeCell API is used for configuring
@@ -62,7 +63,7 @@ struct pl08x_channel_data {
 	int min_signal;
 	int max_signal;
 	u32 muxval;
-	u32 cctl;
+	u32 cctl_memcpy;
 	dma_addr_t addr;
 	bool single;
 	u8 periph_buses;
-- 
1.7.4.4

^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [RFC 17/34] dmaengine: PL08x: split DMA signal muxing from channel alloc
  2012-05-29  9:30 [RFC 00/34] PL08x DMA conversion to virt-dma Russell King - ARM Linux
                   ` (15 preceding siblings ...)
  2012-05-29  9:40 ` [RFC 16/34] dmaengine: PL08x: get rid of unnecessary checks " Russell King
@ 2012-05-29  9:40 ` Russell King
  2012-05-31  1:03   ` Linus Walleij
  2012-05-29  9:41 ` [RFC 18/34] dmaengine: PL08x: move DMA signal muxing into pl08x_dma_chan struct Russell King
                   ` (16 subsequent siblings)
  33 siblings, 1 reply; 80+ messages in thread
From: Russell King @ 2012-05-29  9:40 UTC (permalink / raw)
  To: linux-arm-kernel

Split the DMA request mux signal handling from the physical channel
allocation code.  The physical channel has very little to do with the
DMA request input which will be used, so these should be two separate
operations.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/dma/amba-pl08x.c |   43 ++++++++++++++++++++++++++++++++++++-------
 1 files changed, 36 insertions(+), 7 deletions(-)

diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c
index fa1f9d2..7156d49 100644
--- a/drivers/dma/amba-pl08x.c
+++ b/drivers/dma/amba-pl08x.c
@@ -292,6 +292,39 @@ static inline struct pl08x_txd *to_pl08x_txd(struct dma_async_tx_descriptor *tx)
 }
 
 /*
+ * Mux handling.
+ *
+ * This gives us the DMA request input to the PL08x primecell which the
+ * peripheral described by the channel data will be routed to, possibly
+ * via a board/SoC specific external MUX.  One important point to note
+ * here is that this does not depend on the physical channel.
+ */
+static int pl08x_request_mux(struct pl08x_dma_chan *plchan, struct pl08x_phy_chan *ch)
+{
+	const struct pl08x_platform_data *pd = plchan->host->pd;
+	int ret;
+
+	if (pd->get_signal) {
+		ret = pd->get_signal(plchan->cd);
+		if (ret < 0)
+			return ret;
+
+		ch->signal = ret;
+	}
+	return 0;
+}
+
+static void pl08x_release_mux(struct pl08x_dma_chan *plchan)
+{
+	const struct pl08x_platform_data *pd = plchan->host->pd;
+
+	if (plchan->phychan->signal >= 0 && pd->put_signal) {
+		pd->put_signal(plchan->cd, plchan->phychan->signal);
+		plchan->phychan->signal = -1;
+	}
+}
+
+/*
  * Physical channel handling
  */
 
@@ -995,8 +1028,8 @@ static int prep_phy_channel(struct pl08x_dma_chan *plchan,
 	 * need, but for slaves the physical signals may be muxed!
 	 * Can the platform allow us to use this channel?
 	 */
-	if (plchan->slave && pl08x->pd->get_signal) {
-		ret = pl08x->pd->get_signal(plchan->cd);
+	if (plchan->slave) {
+		ret = pl08x_request_mux(plchan, ch);
 		if (ret < 0) {
 			dev_dbg(&pl08x->adev->dev,
 				"unable to use physical channel %d for transfer on %s due to platform restrictions\n",
@@ -1005,7 +1038,6 @@ static int prep_phy_channel(struct pl08x_dma_chan *plchan,
 			pl08x_put_phy_channel(pl08x, ch);
 			return -EBUSY;
 		}
-		ch->signal = ret;
 	}
 
 	plchan->phychan = ch;
@@ -1030,10 +1062,7 @@ static void release_phy_channel(struct pl08x_dma_chan *plchan)
 {
 	struct pl08x_driver_data *pl08x = plchan->host;
 
-	if ((plchan->phychan->signal >= 0) && pl08x->pd->put_signal) {
-		pl08x->pd->put_signal(plchan->cd, plchan->phychan->signal);
-		plchan->phychan->signal = -1;
-	}
+	pl08x_release_mux(plchan);
 	pl08x_put_phy_channel(pl08x, plchan->phychan);
 	plchan->phychan = NULL;
 }
-- 
1.7.4.4

^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [RFC 18/34] dmaengine: PL08x: move DMA signal muxing into pl08x_dma_chan struct
  2012-05-29  9:30 [RFC 00/34] PL08x DMA conversion to virt-dma Russell King - ARM Linux
                   ` (16 preceding siblings ...)
  2012-05-29  9:40 ` [RFC 17/34] dmaengine: PL08x: split DMA signal muxing from channel alloc Russell King
@ 2012-05-29  9:41 ` Russell King
  2012-05-31  1:03   ` Linus Walleij
  2012-05-29  9:41 ` [RFC 19/34] dmaengine: PL08x: track mux usage on a per-channel basis Russell King
                   ` (15 subsequent siblings)
  33 siblings, 1 reply; 80+ messages in thread
From: Russell King @ 2012-05-29  9:41 UTC (permalink / raw)
  To: linux-arm-kernel

Move the signal handling out of the physical channel structure into
the virtual channel structure, where it should belong as it has more
to do with the virtual channel than the physical one.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/dma/amba-pl08x.c |   26 ++++++++++++--------------
 1 files changed, 12 insertions(+), 14 deletions(-)

diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c
index 7156d49..e5b13e6 100644
--- a/drivers/dma/amba-pl08x.c
+++ b/drivers/dma/amba-pl08x.c
@@ -132,8 +132,6 @@ struct pl08x_bus_data {
  * struct pl08x_phy_chan - holder for the physical channels
  * @id: physical index to this channel
  * @lock: a lock to use when altering an instance of this struct
- * @signal: the physical signal (aka channel) serving this physical channel
- * right now
  * @serving: the virtual channel currently being served by this physical
  * channel
  */
@@ -141,7 +139,6 @@ struct pl08x_phy_chan {
 	unsigned int id;
 	void __iomem *base;
 	spinlock_t lock;
-	int signal;
 	struct pl08x_dma_chan *serving;
 };
 
@@ -222,6 +219,7 @@ enum pl08x_dma_chan_state {
  * @slave: whether this channel is a device (slave) or for memcpy
  * @waiting: a TX descriptor on this channel which is waiting for a physical
  * channel to become available
+ * @signal: the physical DMA request signal which this channel is using
  */
 struct pl08x_dma_chan {
 	struct dma_chan chan;
@@ -238,6 +236,7 @@ struct pl08x_dma_chan {
 	enum pl08x_dma_chan_state state;
 	bool slave;
 	struct pl08x_txd *waiting;
+	int signal;
 };
 
 /**
@@ -299,7 +298,7 @@ static inline struct pl08x_txd *to_pl08x_txd(struct dma_async_tx_descriptor *tx)
  * via a board/SoC specific external MUX.  One important point to note
  * here is that this does not depend on the physical channel.
  */
-static int pl08x_request_mux(struct pl08x_dma_chan *plchan, struct pl08x_phy_chan *ch)
+static int pl08x_request_mux(struct pl08x_dma_chan *plchan)
 {
 	const struct pl08x_platform_data *pd = plchan->host->pd;
 	int ret;
@@ -309,7 +308,7 @@ static int pl08x_request_mux(struct pl08x_dma_chan *plchan, struct pl08x_phy_cha
 		if (ret < 0)
 			return ret;
 
-		ch->signal = ret;
+		plchan->signal = ret;
 	}
 	return 0;
 }
@@ -318,9 +317,9 @@ static void pl08x_release_mux(struct pl08x_dma_chan *plchan)
 {
 	const struct pl08x_platform_data *pd = plchan->host->pd;
 
-	if (plchan->phychan->signal >= 0 && pd->put_signal) {
-		pd->put_signal(plchan->cd, plchan->phychan->signal);
-		plchan->phychan->signal = -1;
+	if (plchan->signal >= 0 && pd->put_signal) {
+		pd->put_signal(plchan->cd, plchan->signal);
+		plchan->signal = -1;
 	}
 }
 
@@ -545,7 +544,6 @@ pl08x_get_phy_channel(struct pl08x_driver_data *pl08x,
 
 		if (!ch->serving) {
 			ch->serving = virt_chan;
-			ch->signal = -1;
 			spin_unlock_irqrestore(&ch->lock, flags);
 			break;
 		}
@@ -1029,7 +1027,7 @@ static int prep_phy_channel(struct pl08x_dma_chan *plchan,
 	 * Can the platform allow us to use this channel?
 	 */
 	if (plchan->slave) {
-		ret = pl08x_request_mux(plchan, ch);
+		ret = pl08x_request_mux(plchan);
 		if (ret < 0) {
 			dev_dbg(&pl08x->adev->dev,
 				"unable to use physical channel %d for transfer on %s due to platform restrictions\n",
@@ -1043,15 +1041,15 @@ static int prep_phy_channel(struct pl08x_dma_chan *plchan,
 	plchan->phychan = ch;
 	dev_dbg(&pl08x->adev->dev, "allocated physical channel %d and signal %d for xfer on %s\n",
 		 ch->id,
-		 ch->signal,
+		 plchan->signal,
 		 plchan->name);
 
 got_channel:
 	/* Assign the flow control signal to this channel */
 	if (txd->direction == DMA_MEM_TO_DEV)
-		txd->ccfg |= ch->signal << PL080_CONFIG_DST_SEL_SHIFT;
+		txd->ccfg |= plchan->signal << PL080_CONFIG_DST_SEL_SHIFT;
 	else if (txd->direction == DMA_DEV_TO_MEM)
-		txd->ccfg |= ch->signal << PL080_CONFIG_SRC_SEL_SHIFT;
+		txd->ccfg |= plchan->signal << PL080_CONFIG_SRC_SEL_SHIFT;
 
 	plchan->phychan_hold++;
 
@@ -1818,6 +1816,7 @@ static int pl08x_dma_init_virtual_channels(struct pl08x_driver_data *pl08x,
 
 		chan->host = pl08x;
 		chan->state = PL08X_CHAN_IDLE;
+		chan->signal = -1;
 
 		if (slave) {
 			chan->cd = &pl08x->pd->slave_channels[i];
@@ -2054,7 +2053,6 @@ static int pl08x_probe(struct amba_device *adev, const struct amba_id *id)
 		ch->base = pl08x->base + PL080_Cx_BASE(i);
 		spin_lock_init(&ch->lock);
 		ch->serving = NULL;
-		ch->signal = -1;
 		dev_dbg(&adev->dev, "physical channel %d is %s\n",
 			i, pl08x_phy_channel_busy(ch) ? "BUSY" : "FREE");
 	}
-- 
1.7.4.4

^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [RFC 19/34] dmaengine: PL08x: track mux usage on a per-channel basis.
  2012-05-29  9:30 [RFC 00/34] PL08x DMA conversion to virt-dma Russell King - ARM Linux
                   ` (17 preceding siblings ...)
  2012-05-29  9:41 ` [RFC 18/34] dmaengine: PL08x: move DMA signal muxing into pl08x_dma_chan struct Russell King
@ 2012-05-29  9:41 ` Russell King
  2012-05-31  1:04   ` Linus Walleij
  2012-05-29  9:42 ` [RFC 20/34] dmaengine: PL08x: convert to a list of completed descriptors Russell King
                   ` (14 subsequent siblings)
  33 siblings, 1 reply; 80+ messages in thread
From: Russell King @ 2012-05-29  9:41 UTC (permalink / raw)
  To: linux-arm-kernel

Keep track of the number of descriptors currently using a MUX setting
on a per-channel basis.  This allows us to know when we have descriptors
queued somewhere which have been assigned a DMA request signal.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/dma/amba-pl08x.c |   18 +++++++++++++-----
 1 files changed, 13 insertions(+), 5 deletions(-)

diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c
index e5b13e6..3532833 100644
--- a/drivers/dma/amba-pl08x.c
+++ b/drivers/dma/amba-pl08x.c
@@ -220,6 +220,7 @@ enum pl08x_dma_chan_state {
  * @waiting: a TX descriptor on this channel which is waiting for a physical
  * channel to become available
  * @signal: the physical DMA request signal which this channel is using
+ * @mux_use: count of descriptors using this DMA request signal setting
  */
 struct pl08x_dma_chan {
 	struct dma_chan chan;
@@ -237,6 +238,7 @@ struct pl08x_dma_chan {
 	bool slave;
 	struct pl08x_txd *waiting;
 	int signal;
+	unsigned mux_use;
 };
 
 /**
@@ -303,10 +305,12 @@ static int pl08x_request_mux(struct pl08x_dma_chan *plchan)
 	const struct pl08x_platform_data *pd = plchan->host->pd;
 	int ret;
 
-	if (pd->get_signal) {
+	if (plchan->mux_use++ == 0 && pd->get_signal) {
 		ret = pd->get_signal(plchan->cd);
-		if (ret < 0)
+		if (ret < 0) {
+			plchan->mux_use = 0;
 			return ret;
+		}
 
 		plchan->signal = ret;
 	}
@@ -317,9 +321,13 @@ static void pl08x_release_mux(struct pl08x_dma_chan *plchan)
 {
 	const struct pl08x_platform_data *pd = plchan->host->pd;
 
-	if (plchan->signal >= 0 && pd->put_signal) {
-		pd->put_signal(plchan->cd, plchan->signal);
-		plchan->signal = -1;
+	if (plchan->signal >= 0) {
+		WARN_ON(plchan->mux_use == 0);
+
+		if (--plchan->mux_use == 0 && pd->put_signal) {
+			pd->put_signal(plchan->cd, plchan->signal);
+			plchan->signal = -1;
+		}
 	}
 }
 
-- 
1.7.4.4

^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [RFC 20/34] dmaengine: PL08x: convert to a list of completed descriptors
  2012-05-29  9:30 [RFC 00/34] PL08x DMA conversion to virt-dma Russell King - ARM Linux
                   ` (18 preceding siblings ...)
  2012-05-29  9:41 ` [RFC 19/34] dmaengine: PL08x: track mux usage on a per-channel basis Russell King
@ 2012-05-29  9:42 ` Russell King
  2012-05-31  1:04   ` Linus Walleij
  2012-05-29  9:42 ` [RFC 21/34] dmaengine: PL08x: move DMA signal muxing into slave prepare code Russell King
                   ` (13 subsequent siblings)
  33 siblings, 1 reply; 80+ messages in thread
From: Russell King @ 2012-05-29  9:42 UTC (permalink / raw)
  To: linux-arm-kernel

Convert PL08x to use a list of completed descriptors rather than
merely relying upon a single pointer.  This makes it possible to
schedule the tasklet for other purposes, and makes our behaviour
similar to virt-dma.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/dma/amba-pl08x.c |   30 ++++++++++++++++++++----------
 1 files changed, 20 insertions(+), 10 deletions(-)

diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c
index 3532833..93464ee 100644
--- a/drivers/dma/amba-pl08x.c
+++ b/drivers/dma/amba-pl08x.c
@@ -212,6 +212,7 @@ enum pl08x_dma_chan_state {
  * @cd: channel platform data
  * @runtime_addr: address for RX/TX according to the runtime config
  * @pend_list: queued transactions pending on this channel
+ * @done_list: list of completed transactions
  * @at: active transaction on this channel
  * @lock: a lock for this channel data
  * @host: a pointer to the host (internal use)
@@ -231,6 +232,7 @@ struct pl08x_dma_chan {
 	const struct pl08x_channel_data *cd;
 	struct dma_slave_config cfg;
 	struct list_head pend_list;
+	struct list_head done_list;
 	struct pl08x_txd *at;
 	spinlock_t lock;
 	struct pl08x_driver_data *host;
@@ -1663,18 +1665,11 @@ static void pl08x_tasklet(unsigned long data)
 {
 	struct pl08x_dma_chan *plchan = (struct pl08x_dma_chan *) data;
 	struct pl08x_driver_data *pl08x = plchan->host;
-	struct pl08x_txd *txd;
 	unsigned long flags;
+	LIST_HEAD(head);
 
 	spin_lock_irqsave(&plchan->lock, flags);
-
-	txd = plchan->at;
-	plchan->at = NULL;
-
-	if (txd) {
-		/* Update last completed */
-		dma_cookie_complete(&txd->tx);
-	}
+	list_splice_tail_init(&plchan->done_list, &head);
 
 	/* If a new descriptor is queued, set it up plchan->at is NULL here */
 	if (!list_empty(&plchan->pend_list)) {
@@ -1729,10 +1724,14 @@ static void pl08x_tasklet(unsigned long data)
 
 	spin_unlock_irqrestore(&plchan->lock, flags);
 
-	if (txd) {
+	while (!list_empty(&head)) {
+		struct pl08x_txd *txd = list_first_entry(&head,
+						struct pl08x_txd, node);
 		dma_async_tx_callback callback = txd->tx.callback;
 		void *callback_param = txd->tx.callback_param;
 
+		list_del(&txd->node);
+
 		/* Don't try to unmap buffers on slave channels */
 		if (!plchan->slave)
 			pl08x_unmap_buffers(txd);
@@ -1772,6 +1771,7 @@ static irqreturn_t pl08x_irq(int irq, void *dev)
 			/* Locate physical channel */
 			struct pl08x_phy_chan *phychan = &pl08x->phy_chans[i];
 			struct pl08x_dma_chan *plchan = phychan->serving;
+			struct pl08x_txd *tx;
 
 			if (!plchan) {
 				dev_err(&pl08x->adev->dev,
@@ -1780,6 +1780,15 @@ static irqreturn_t pl08x_irq(int irq, void *dev)
 				continue;
 			}
 
+			spin_lock(&plchan->lock);
+			tx = plchan->at;
+			if (tx) {
+				plchan->at = NULL;
+				dma_cookie_complete(&tx->tx);
+				list_add_tail(&tx->node, &plchan->done_list);
+			}
+			spin_unlock(&plchan->lock);
+
 			/* Schedule tasklet on this channel */
 			tasklet_schedule(&plchan->tasklet);
 			mask |= (1 << i);
@@ -1846,6 +1855,7 @@ static int pl08x_dma_init_virtual_channels(struct pl08x_driver_data *pl08x,
 
 		spin_lock_init(&chan->lock);
 		INIT_LIST_HEAD(&chan->pend_list);
+		INIT_LIST_HEAD(&chan->done_list);
 		tasklet_init(&chan->tasklet, pl08x_tasklet,
 			     (unsigned long) chan);
 
-- 
1.7.4.4

^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [RFC 21/34] dmaengine: PL08x: move DMA signal muxing into slave prepare code
  2012-05-29  9:30 [RFC 00/34] PL08x DMA conversion to virt-dma Russell King - ARM Linux
                   ` (19 preceding siblings ...)
  2012-05-29  9:42 ` [RFC 20/34] dmaengine: PL08x: convert to a list of completed descriptors Russell King
@ 2012-05-29  9:42 ` Russell King
  2012-05-31  1:11   ` Linus Walleij
  2012-05-29  9:42 ` [RFC 22/34] dmaengine: PL08x: remove waiting descriptor pointer Russell King
                   ` (12 subsequent siblings)
  33 siblings, 1 reply; 80+ messages in thread
From: Russell King @ 2012-05-29  9:42 UTC (permalink / raw)
  To: linux-arm-kernel

Move the DMA request muxing into the slave prepare code and txd
release/completion code.  This means we only hold the DMA request
mux while there are descriptors waiting to be started or are in
progress.

This leaves txd->direction as a write-only variable; remove it.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/dma/amba-pl08x.c |   79 ++++++++++++++++++---------------------------
 1 files changed, 32 insertions(+), 47 deletions(-)

diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c
index 93464ee..1554aec 100644
--- a/drivers/dma/amba-pl08x.c
+++ b/drivers/dma/amba-pl08x.c
@@ -161,7 +161,6 @@ struct pl08x_sg {
  * @tx: async tx descriptor
  * @node: node for txd list for channels
  * @dsg_list: list of children sg's
- * @direction: direction of transfer
  * @llis_bus: DMA memory address (physical) start for the LLIs
  * @llis_va: virtual memory address start for the LLIs
  * @cctl: control reg values for current txd
@@ -171,7 +170,6 @@ struct pl08x_txd {
 	struct dma_async_tx_descriptor tx;
 	struct list_head node;
 	struct list_head dsg_list;
-	enum dma_transfer_direction direction;
 	dma_addr_t llis_bus;
 	struct pl08x_lli *llis_va;
 	/* Default cctl value for LLIs */
@@ -990,6 +988,7 @@ static void pl08x_free_txd_list(struct pl08x_driver_data *pl08x,
 	if (!list_empty(&plchan->pend_list)) {
 		list_for_each_entry_safe(txdi,
 					 next, &plchan->pend_list, node) {
+			pl08x_release_mux(plchan);
 			list_del(&txdi->node);
 			pl08x_free_txd(pl08x, txdi);
 		}
@@ -1011,12 +1010,10 @@ static void pl08x_free_chan_resources(struct dma_chan *chan)
 /*
  * This should be called with the channel plchan->lock held
  */
-static int prep_phy_channel(struct pl08x_dma_chan *plchan,
-			    struct pl08x_txd *txd)
+static int prep_phy_channel(struct pl08x_dma_chan *plchan)
 {
 	struct pl08x_driver_data *pl08x = plchan->host;
 	struct pl08x_phy_chan *ch;
-	int ret;
 
 	/* Check if we already have a channel */
 	if (plchan->phychan) {
@@ -1031,36 +1028,11 @@ static int prep_phy_channel(struct pl08x_dma_chan *plchan,
 		return -EBUSY;
 	}
 
-	/*
-	 * OK we have a physical channel: for memcpy() this is all we
-	 * need, but for slaves the physical signals may be muxed!
-	 * Can the platform allow us to use this channel?
-	 */
-	if (plchan->slave) {
-		ret = pl08x_request_mux(plchan);
-		if (ret < 0) {
-			dev_dbg(&pl08x->adev->dev,
-				"unable to use physical channel %d for transfer on %s due to platform restrictions\n",
-				ch->id, plchan->name);
-			/* Release physical channel & return */
-			pl08x_put_phy_channel(pl08x, ch);
-			return -EBUSY;
-		}
-	}
-
 	plchan->phychan = ch;
-	dev_dbg(&pl08x->adev->dev, "allocated physical channel %d and signal %d for xfer on %s\n",
-		 ch->id,
-		 plchan->signal,
-		 plchan->name);
+	dev_dbg(&pl08x->adev->dev, "allocated physical channel %d for xfer on %s\n",
+		 ch->id, plchan->name);
 
 got_channel:
-	/* Assign the flow control signal to this channel */
-	if (txd->direction == DMA_MEM_TO_DEV)
-		txd->ccfg |= plchan->signal << PL080_CONFIG_DST_SEL_SHIFT;
-	else if (txd->direction == DMA_DEV_TO_MEM)
-		txd->ccfg |= plchan->signal << PL080_CONFIG_SRC_SEL_SHIFT;
-
 	plchan->phychan_hold++;
 
 	return 0;
@@ -1070,7 +1042,6 @@ static void release_phy_channel(struct pl08x_dma_chan *plchan)
 {
 	struct pl08x_driver_data *pl08x = plchan->host;
 
-	pl08x_release_mux(plchan);
 	pl08x_put_phy_channel(pl08x, plchan->phychan);
 	plchan->phychan = NULL;
 }
@@ -1333,19 +1304,12 @@ static int pl08x_prep_channel_resources(struct pl08x_dma_chan *plchan,
 	 * See if we already have a physical channel allocated,
 	 * else this is the time to try to get one.
 	 */
-	ret = prep_phy_channel(plchan, txd);
+	ret = prep_phy_channel(plchan);
 	if (ret) {
 		/*
 		 * No physical channel was available.
 		 *
 		 * memcpy transfers can be sorted out at submission time.
-		 *
-		 * Slave transfers may have been denied due to platform
-		 * channel muxing restrictions.  Since there is no guarantee
-		 * that this will ever be resolved, and the signal must be
-		 * acquired AFTER acquiring the physical channel, we will let
-		 * them be NACK:ed with -EBUSY here. The drivers can retry
-		 * the prep() call if they are eager on doing this using DMA.
 		 */
 		if (plchan->slave) {
 			pl08x_free_txd_list(pl08x, plchan);
@@ -1416,7 +1380,6 @@ static struct dma_async_tx_descriptor *pl08x_prep_dma_memcpy(
 	}
 	list_add_tail(&dsg->node, &txd->dsg_list);
 
-	txd->direction = DMA_MEM_TO_MEM;
 	dsg->src_addr = src;
 	dsg->dst_addr = dest;
 	dsg->len = len;
@@ -1470,8 +1433,6 @@ static struct dma_async_tx_descriptor *pl08x_prep_slave_sg(
 	 * will take precedence since this may configure the
 	 * channel target address dynamically at runtime.
 	 */
-	txd->direction = direction;
-
 	if (direction == DMA_MEM_TO_DEV) {
 		cctl = PL080_CONTROL_SRC_INCR;
 		slave_addr = plchan->cfg.dst_addr;
@@ -1512,9 +1473,28 @@ static struct dma_async_tx_descriptor *pl08x_prep_slave_sg(
 
 	txd->ccfg |= tmp << PL080_CONFIG_FLOW_CONTROL_SHIFT;
 
+	ret = pl08x_request_mux(plchan);
+	if (ret < 0) {
+		pl08x_free_txd(pl08x, txd);
+		dev_dbg(&pl08x->adev->dev,
+			"unable to mux for transfer on %s due to platform restrictions\n",
+			plchan->name);
+		return NULL;
+	}
+
+	dev_dbg(&pl08x->adev->dev, "allocated DMA request signal %d for xfer on %s\n",
+		 plchan->signal, plchan->name);
+
+	/* Assign the flow control signal to this channel */
+	if (direction == DMA_MEM_TO_DEV)
+		txd->ccfg |= plchan->signal << PL080_CONFIG_DST_SEL_SHIFT;
+	else
+		txd->ccfg |= plchan->signal << PL080_CONFIG_SRC_SEL_SHIFT;
+
 	for_each_sg(sgl, sg, sg_len, tmp) {
 		dsg = kzalloc(sizeof(struct pl08x_sg), GFP_NOWAIT);
 		if (!dsg) {
+			pl08x_release_mux(plchan);
 			pl08x_free_txd(pl08x, txd);
 			dev_err(&pl08x->adev->dev, "%s no mem for pl080 sg\n",
 					__func__);
@@ -1579,6 +1559,8 @@ static int pl08x_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
 		}
 		/* Dequeue jobs and free LLIs */
 		if (plchan->at) {
+			/* Killing this one off, release its mux */
+			pl08x_release_mux(plchan);
 			pl08x_free_txd(pl08x, plchan->at);
 			plchan->at = NULL;
 		}
@@ -1692,7 +1674,6 @@ static void pl08x_tasklet(unsigned long data)
 
 		/*
 		 * No more jobs, so free up the physical channel
-		 * Free any allocated signal on slave transfers too
 		 */
 		release_phy_channel(plchan);
 		plchan->state = PL08X_CHAN_IDLE;
@@ -1710,8 +1691,7 @@ static void pl08x_tasklet(unsigned long data)
 				int ret;
 
 				/* This should REALLY not fail now */
-				ret = prep_phy_channel(waiting,
-						       waiting->waiting);
+				ret = prep_phy_channel(waiting);
 				BUG_ON(ret);
 				waiting->phychan_hold--;
 				waiting->state = PL08X_CHAN_RUNNING;
@@ -1784,6 +1764,11 @@ static irqreturn_t pl08x_irq(int irq, void *dev)
 			tx = plchan->at;
 			if (tx) {
 				plchan->at = NULL;
+				/*
+				 * This descriptor is done, release its mux
+				 * reservation.
+				 */
+				pl08x_release_mux(plchan);
 				dma_cookie_complete(&tx->tx);
 				list_add_tail(&tx->node, &plchan->done_list);
 			}
-- 
1.7.4.4

^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [RFC 22/34] dmaengine: PL08x: remove waiting descriptor pointer
  2012-05-29  9:30 [RFC 00/34] PL08x DMA conversion to virt-dma Russell King - ARM Linux
                   ` (20 preceding siblings ...)
  2012-05-29  9:42 ` [RFC 21/34] dmaengine: PL08x: move DMA signal muxing into slave prepare code Russell King
@ 2012-05-29  9:42 ` Russell King
  2012-05-31  1:11   ` Linus Walleij
  2012-05-29  9:43 ` [RFC 23/34] dmaengine: PL08x: re-jig the starting of txds Russell King
                   ` (11 subsequent siblings)
  33 siblings, 1 reply; 80+ messages in thread
From: Russell King @ 2012-05-29  9:42 UTC (permalink / raw)
  To: linux-arm-kernel

As we no longer need to pass a descriptor to prep_phy_channel(), we
don't need to keep track of the descriptor which is waiting for a
channel to become available.  So let's get rid of it.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/dma/amba-pl08x.c |    8 +-------
 1 files changed, 1 insertions(+), 7 deletions(-)

diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c
index 1554aec..e1922f3 100644
--- a/drivers/dma/amba-pl08x.c
+++ b/drivers/dma/amba-pl08x.c
@@ -216,8 +216,6 @@ enum pl08x_dma_chan_state {
  * @host: a pointer to the host (internal use)
  * @state: whether the channel is idle, paused, running etc
  * @slave: whether this channel is a device (slave) or for memcpy
- * @waiting: a TX descriptor on this channel which is waiting for a physical
- * channel to become available
  * @signal: the physical DMA request signal which this channel is using
  * @mux_use: count of descriptors using this DMA request signal setting
  */
@@ -236,7 +234,6 @@ struct pl08x_dma_chan {
 	struct pl08x_driver_data *host;
 	enum pl08x_dma_chan_state state;
 	bool slave;
-	struct pl08x_txd *waiting;
 	int signal;
 	unsigned mux_use;
 };
@@ -1067,7 +1064,6 @@ static dma_cookie_t pl08x_tx_submit(struct dma_async_tx_descriptor *tx)
 	if (!plchan->slave && !plchan->phychan) {
 		/* Do this memcpy whenever there is a channel ready */
 		plchan->state = PL08X_CHAN_WAITING;
-		plchan->waiting = txd;
 	} else {
 		plchan->phychan_hold--;
 	}
@@ -1686,8 +1682,7 @@ static void pl08x_tasklet(unsigned long data)
 		 */
 		list_for_each_entry(waiting, &pl08x->memcpy.channels,
 				    chan.device_node) {
-			if (waiting->state == PL08X_CHAN_WAITING &&
-				waiting->waiting != NULL) {
+			if (waiting->state == PL08X_CHAN_WAITING) {
 				int ret;
 
 				/* This should REALLY not fail now */
@@ -1695,7 +1690,6 @@ static void pl08x_tasklet(unsigned long data)
 				BUG_ON(ret);
 				waiting->phychan_hold--;
 				waiting->state = PL08X_CHAN_RUNNING;
-				waiting->waiting = NULL;
 				pl08x_issue_pending(&waiting->chan);
 				break;
 			}
-- 
1.7.4.4

^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [RFC 23/34] dmaengine: PL08x: re-jig the starting of txds
  2012-05-29  9:30 [RFC 00/34] PL08x DMA conversion to virt-dma Russell King - ARM Linux
                   ` (21 preceding siblings ...)
  2012-05-29  9:42 ` [RFC 22/34] dmaengine: PL08x: remove waiting descriptor pointer Russell King
@ 2012-05-29  9:43 ` Russell King
  2012-05-31  1:14   ` Linus Walleij
  2012-05-29  9:43 ` [RFC 24/34] dmaengine: PL08x: split the pend_list in two Russell King
                   ` (10 subsequent siblings)
  33 siblings, 1 reply; 80+ messages in thread
From: Russell King @ 2012-05-29  9:43 UTC (permalink / raw)
  To: linux-arm-kernel

Rather than code the de-queue of the txd several times, move that into
the start_txd function.  Rename this to better illustrate what it's
now doing, and call this function when starting a delayed memcpy().

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/dma/amba-pl08x.c |   37 +++++++++++++++++--------------------
 1 files changed, 17 insertions(+), 20 deletions(-)

diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c
index e1922f3..1eb5885 100644
--- a/drivers/dma/amba-pl08x.c
+++ b/drivers/dma/amba-pl08x.c
@@ -347,20 +347,25 @@ static int pl08x_phy_channel_busy(struct pl08x_phy_chan *ch)
  * been set when the LLIs were constructed.  Poke them into the hardware
  * and start the transfer.
  */
-static void pl08x_start_txd(struct pl08x_dma_chan *plchan,
-	struct pl08x_txd *txd)
+static void pl08x_start_next_txd(struct pl08x_dma_chan *plchan)
 {
 	struct pl08x_driver_data *pl08x = plchan->host;
 	struct pl08x_phy_chan *phychan = plchan->phychan;
-	struct pl08x_lli *lli = &txd->llis_va[0];
+	struct pl08x_lli *lli;
+	struct pl08x_txd *txd;
 	u32 val;
 
+	txd = list_first_entry(&plchan->pend_list, struct pl08x_txd, node);
+	list_del(&txd->node);
+
 	plchan->at = txd;
 
 	/* Wait for channel inactive */
 	while (pl08x_phy_channel_busy(phychan))
 		cpu_relax();
 
+	lli = &txd->llis_va[0];
+
 	dev_vdbg(&pl08x->adev->dev,
 		"WRITE channel %d: csrc=0x%08x, cdst=0x%08x, "
 		"clli=0x%08x, cctl=0x%08x, ccfg=0x%08x\n",
@@ -1265,15 +1270,8 @@ static void pl08x_issue_pending(struct dma_chan *chan)
 
 	/* Take the first element in the queue and execute it */
 	if (!list_empty(&plchan->pend_list)) {
-		struct pl08x_txd *next;
-
-		next = list_first_entry(&plchan->pend_list,
-					struct pl08x_txd,
-					node);
-		list_del(&next->node);
 		plchan->state = PL08X_CHAN_RUNNING;
-
-		pl08x_start_txd(plchan, next);
+		pl08x_start_next_txd(plchan);
 	}
 
 	spin_unlock_irqrestore(&plchan->lock, flags);
@@ -1651,14 +1649,7 @@ static void pl08x_tasklet(unsigned long data)
 
 	/* If a new descriptor is queued, set it up plchan->at is NULL here */
 	if (!list_empty(&plchan->pend_list)) {
-		struct pl08x_txd *next;
-
-		next = list_first_entry(&plchan->pend_list,
-					struct pl08x_txd,
-					node);
-		list_del(&next->node);
-
-		pl08x_start_txd(plchan, next);
+		pl08x_start_next_txd(plchan);
 	} else if (plchan->phychan_hold) {
 		/*
 		 * This channel is still in use - we have a new txd being
@@ -1690,7 +1681,13 @@ static void pl08x_tasklet(unsigned long data)
 				BUG_ON(ret);
 				waiting->phychan_hold--;
 				waiting->state = PL08X_CHAN_RUNNING;
-				pl08x_issue_pending(&waiting->chan);
+				/*
+				 * Eww.  We know this isn't going to deadlock
+				 * but lockdep probably doens't.
+				 */
+				spin_lock(&waiting->lock);
+				pl08x_start_next_txd(waiting);
+				spin_unlock(&waiting->lock);
 				break;
 			}
 		}
-- 
1.7.4.4

^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [RFC 24/34] dmaengine: PL08x: split the pend_list in two
  2012-05-29  9:30 [RFC 00/34] PL08x DMA conversion to virt-dma Russell King - ARM Linux
                   ` (22 preceding siblings ...)
  2012-05-29  9:43 ` [RFC 23/34] dmaengine: PL08x: re-jig the starting of txds Russell King
@ 2012-05-29  9:43 ` Russell King
  2012-05-31  1:20   ` Linus Walleij
  2012-05-29  9:43 ` [RFC 25/34] dmaengine: PL08x: start next descriptor from irq context Russell King
                   ` (9 subsequent siblings)
  33 siblings, 1 reply; 80+ messages in thread
From: Russell King @ 2012-05-29  9:43 UTC (permalink / raw)
  To: linux-arm-kernel

Our behaviour wasn't correct; issue_pending is supposed to be called
before any submitted descriptors are available for processing by the
DMA engine.  Split the pend_list in two, one for submitted descriptors
and another list for issued descriptors.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/dma/amba-pl08x.c |   41 ++++++++++++++++++++++++++++-------------
 1 files changed, 28 insertions(+), 13 deletions(-)

diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c
index 1eb5885..4788ec0 100644
--- a/drivers/dma/amba-pl08x.c
+++ b/drivers/dma/amba-pl08x.c
@@ -210,6 +210,7 @@ enum pl08x_dma_chan_state {
  * @cd: channel platform data
  * @runtime_addr: address for RX/TX according to the runtime config
  * @pend_list: queued transactions pending on this channel
+ * @issued_list: issued transactions for this channel
  * @done_list: list of completed transactions
  * @at: active transaction on this channel
  * @lock: a lock for this channel data
@@ -228,6 +229,7 @@ struct pl08x_dma_chan {
 	const struct pl08x_channel_data *cd;
 	struct dma_slave_config cfg;
 	struct list_head pend_list;
+	struct list_head issued_list;
 	struct list_head done_list;
 	struct pl08x_txd *at;
 	spinlock_t lock;
@@ -355,7 +357,7 @@ static void pl08x_start_next_txd(struct pl08x_dma_chan *plchan)
 	struct pl08x_txd *txd;
 	u32 val;
 
-	txd = list_first_entry(&plchan->pend_list, struct pl08x_txd, node);
+	txd = list_first_entry(&plchan->issued_list, struct pl08x_txd, node);
 	list_del(&txd->node);
 
 	plchan->at = txd;
@@ -518,6 +520,15 @@ static u32 pl08x_getbytes_chan(struct pl08x_dma_chan *plchan)
 	}
 
 	/* Sum up all queued transactions */
+	if (!list_empty(&plchan->issued_list)) {
+		struct pl08x_txd *txdi;
+		list_for_each_entry(txdi, &plchan->issued_list, node) {
+			struct pl08x_sg *dsg;
+			list_for_each_entry(dsg, &txd->dsg_list, node)
+				bytes += dsg->len;
+		}
+	}
+
 	if (!list_empty(&plchan->pend_list)) {
 		struct pl08x_txd *txdi;
 		list_for_each_entry(txdi, &plchan->pend_list, node) {
@@ -984,16 +995,17 @@ static void pl08x_free_txd(struct pl08x_driver_data *pl08x,
 static void pl08x_free_txd_list(struct pl08x_driver_data *pl08x,
 				struct pl08x_dma_chan *plchan)
 {
-	struct pl08x_txd *txdi = NULL;
-	struct pl08x_txd *next;
+	LIST_HEAD(head);
+	struct pl08x_txd *txd;
 
-	if (!list_empty(&plchan->pend_list)) {
-		list_for_each_entry_safe(txdi,
-					 next, &plchan->pend_list, node) {
-			pl08x_release_mux(plchan);
-			list_del(&txdi->node);
-			pl08x_free_txd(pl08x, txdi);
-		}
+	list_splice_tail_init(&plchan->issued_list, &head);
+	list_splice_tail_init(&plchan->pend_list, &head);
+
+	while (!list_empty(&head)) {
+		txd = list_first_entry(&head, struct pl08x_txd, node);
+		pl08x_release_mux(plchan);
+		list_del(&txd->node);
+		pl08x_free_txd(pl08x, txd);
 	}
 }
 
@@ -1262,6 +1274,8 @@ static void pl08x_issue_pending(struct dma_chan *chan)
 	unsigned long flags;
 
 	spin_lock_irqsave(&plchan->lock, flags);
+	list_splice_tail_init(&plchan->pend_list, &plchan->issued_list);
+
 	/* Something is already active, or we're waiting for a channel... */
 	if (plchan->at || plchan->state == PL08X_CHAN_WAITING) {
 		spin_unlock_irqrestore(&plchan->lock, flags);
@@ -1269,7 +1283,7 @@ static void pl08x_issue_pending(struct dma_chan *chan)
 	}
 
 	/* Take the first element in the queue and execute it */
-	if (!list_empty(&plchan->pend_list)) {
+	if (!list_empty(&plchan->issued_list)) {
 		plchan->state = PL08X_CHAN_RUNNING;
 		pl08x_start_next_txd(plchan);
 	}
@@ -1648,9 +1662,9 @@ static void pl08x_tasklet(unsigned long data)
 	list_splice_tail_init(&plchan->done_list, &head);
 
 	/* If a new descriptor is queued, set it up plchan->at is NULL here */
-	if (!list_empty(&plchan->pend_list)) {
+	if (!list_empty(&plchan->issued_list)) {
 		pl08x_start_next_txd(plchan);
-	} else if (plchan->phychan_hold) {
+	} else if (!list_empty(&plchan->pend_list) || plchan->phychan_hold) {
 		/*
 		 * This channel is still in use - we have a new txd being
 		 * prepared and will soon be queued.  Don't give up the
@@ -1831,6 +1845,7 @@ static int pl08x_dma_init_virtual_channels(struct pl08x_driver_data *pl08x,
 
 		spin_lock_init(&chan->lock);
 		INIT_LIST_HEAD(&chan->pend_list);
+		INIT_LIST_HEAD(&chan->issued_list);
 		INIT_LIST_HEAD(&chan->done_list);
 		tasklet_init(&chan->tasklet, pl08x_tasklet,
 			     (unsigned long) chan);
-- 
1.7.4.4

^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [RFC 25/34] dmaengine: PL08x: start next descriptor from irq context
  2012-05-29  9:30 [RFC 00/34] PL08x DMA conversion to virt-dma Russell King - ARM Linux
                   ` (23 preceding siblings ...)
  2012-05-29  9:43 ` [RFC 24/34] dmaengine: PL08x: split the pend_list in two Russell King
@ 2012-05-29  9:43 ` Russell King
  2012-05-31  1:21   ` Linus Walleij
  2012-05-29  9:44 ` [RFC 26/34] dmaengine: PL08x: rejig physical channel allocation Russell King
                   ` (8 subsequent siblings)
  33 siblings, 1 reply; 80+ messages in thread
From: Russell King @ 2012-05-29  9:43 UTC (permalink / raw)
  To: linux-arm-kernel

Rather than waiting for the tasklet to run, we can start the next
descriptor from interrupt context, as soon as we know that the
previous descriptor has completed.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/dma/amba-pl08x.c |    9 +++++----
 1 files changed, 5 insertions(+), 4 deletions(-)

diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c
index 4788ec0..1118fc0 100644
--- a/drivers/dma/amba-pl08x.c
+++ b/drivers/dma/amba-pl08x.c
@@ -1661,10 +1661,7 @@ static void pl08x_tasklet(unsigned long data)
 	spin_lock_irqsave(&plchan->lock, flags);
 	list_splice_tail_init(&plchan->done_list, &head);
 
-	/* If a new descriptor is queued, set it up plchan->at is NULL here */
-	if (!list_empty(&plchan->issued_list)) {
-		pl08x_start_next_txd(plchan);
-	} else if (!list_empty(&plchan->pend_list) || plchan->phychan_hold) {
+	if (plchan->at || !list_empty(&plchan->pend_list) || plchan->phychan_hold) {
 		/*
 		 * This channel is still in use - we have a new txd being
 		 * prepared and will soon be queued.  Don't give up the
@@ -1776,6 +1773,10 @@ static irqreturn_t pl08x_irq(int irq, void *dev)
 				pl08x_release_mux(plchan);
 				dma_cookie_complete(&tx->tx);
 				list_add_tail(&tx->node, &plchan->done_list);
+
+				/* And start the next descriptor */
+				if (!list_empty(&plchan->issued_list))
+					pl08x_start_next_txd(plchan);
 			}
 			spin_unlock(&plchan->lock);
 
-- 
1.7.4.4

^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [RFC 26/34] dmaengine: PL08x: rejig physical channel allocation
  2012-05-29  9:30 [RFC 00/34] PL08x DMA conversion to virt-dma Russell King - ARM Linux
                   ` (24 preceding siblings ...)
  2012-05-29  9:43 ` [RFC 25/34] dmaengine: PL08x: start next descriptor from irq context Russell King
@ 2012-05-29  9:44 ` Russell King
  2012-05-31  1:23   ` Linus Walleij
  2012-05-29  9:44 ` [RFC 27/34] dmaengine: PL08x: convert to use virt-dma structs Russell King
                   ` (7 subsequent siblings)
  33 siblings, 1 reply; 80+ messages in thread
From: Russell King @ 2012-05-29  9:44 UTC (permalink / raw)
  To: linux-arm-kernel

Rework the physical channel allocation mechanism to only allocate
physical channels to virtual channels when they're about to be used.
This eliminates all the complexity with holding channels while
descriptors are being prepared, which is completely unnecessary.

This also brings this driver to a state where the generic virtual DMA
code can be used with this driver, and opens up the possibility of
properly scheduling and prioritorising physical DMA channels to
virtual DMA channels.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/dma/amba-pl08x.c |  268 +++++++++++++++++++---------------------------
 1 files changed, 112 insertions(+), 156 deletions(-)

diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c
index 1118fc0..5b6cd1e 100644
--- a/drivers/dma/amba-pl08x.c
+++ b/drivers/dma/amba-pl08x.c
@@ -203,8 +203,6 @@ enum pl08x_dma_chan_state {
  * struct pl08x_dma_chan - this structure wraps a DMA ENGINE channel
  * @chan: wrappped abstract channel
  * @phychan: the physical channel utilized by this channel, if there is one
- * @phychan_hold: if non-zero, hold on to the physical channel even if we
- * have no pending entries
  * @tasklet: tasklet scheduled by the IRQ to handle actual work etc
  * @name: name of channel
  * @cd: channel platform data
@@ -223,7 +221,6 @@ enum pl08x_dma_chan_state {
 struct pl08x_dma_chan {
 	struct dma_chan chan;
 	struct pl08x_phy_chan *phychan;
-	int phychan_hold;
 	struct tasklet_struct tasklet;
 	const char *name;
 	const struct pl08x_channel_data *cd;
@@ -580,19 +577,111 @@ pl08x_get_phy_channel(struct pl08x_driver_data *pl08x,
 	return ch;
 }
 
+/* Mark the physical channel as free.  Note, this write is atomic. */
 static inline void pl08x_put_phy_channel(struct pl08x_driver_data *pl08x,
 					 struct pl08x_phy_chan *ch)
 {
-	unsigned long flags;
+	ch->serving = NULL;
+}
 
-	spin_lock_irqsave(&ch->lock, flags);
+/*
+ * Try to allocate a physical channel.  When successful, assign it to
+ * this virtual channel, and initiate the next descriptor.  The
+ * virtual channel lock must be held at this point.
+ */
+static void pl08x_phy_alloc_and_start(struct pl08x_dma_chan *plchan)
+{
+	struct pl08x_driver_data *pl08x = plchan->host;
+	struct pl08x_phy_chan *ch;
 
-	/* Stop the channel and clear its interrupts */
-	pl08x_terminate_phy_chan(pl08x, ch);
+	ch = pl08x_get_phy_channel(pl08x, plchan);
+	if (!ch) {
+		dev_dbg(&pl08x->adev->dev, "no physical channel available for xfer on %s\n", plchan->name);
+		plchan->state = PL08X_CHAN_WAITING;
+		return;
+	}
 
-	/* Mark it as free */
-	ch->serving = NULL;
-	spin_unlock_irqrestore(&ch->lock, flags);
+	dev_dbg(&pl08x->adev->dev, "allocated physical channel %d for xfer on %s\n",
+		ch->id, plchan->name);
+
+	plchan->phychan = ch;
+	plchan->state = PL08X_CHAN_RUNNING;
+	pl08x_start_next_txd(plchan);
+}
+
+static void pl08x_phy_reassign_start(struct pl08x_phy_chan *ch,
+	struct pl08x_dma_chan *plchan)
+{
+	struct pl08x_driver_data *pl08x = plchan->host;
+
+	dev_dbg(&pl08x->adev->dev, "reassigned physical channel %d for xfer on %s\n",
+		ch->id, plchan->name);
+
+	/*
+	 * We do this without taking the lock; we're really only concerned
+	 * about whether this pointer is NULL or not, and we're guaranteed
+	 * that this will only be called when it _already_ is non-NULL.
+	 */
+	ch->serving = plchan;
+	plchan->phychan = ch;
+	plchan->state = PL08X_CHAN_RUNNING;
+	pl08x_start_next_txd(plchan);
+}
+
+/*
+ * Free a physical DMA channel, potentially reallocating it to another
+ * virtual channel if we have any pending.
+ */
+static void pl08x_phy_free(struct pl08x_dma_chan *plchan)
+{
+	struct pl08x_driver_data *pl08x = plchan->host;
+	struct pl08x_dma_chan *p, *next;
+
+ retry:
+	next = NULL;
+
+	/* Find a waiting virtual channel for the next transfer. */
+	list_for_each_entry(p, &pl08x->memcpy.channels, chan.device_node)
+		if (p->state == PL08X_CHAN_WAITING) {
+			next = p;
+			break;
+		}
+
+	if (!next) {
+		list_for_each_entry(p, &pl08x->slave.channels, chan.device_node)
+			if (p->state == PL08X_CHAN_WAITING) {
+				next = p;
+				break;
+			}
+	}
+
+	/* Ensure that the physical channel is stopped */
+	pl08x_terminate_phy_chan(pl08x, plchan->phychan);
+
+	if (next) {
+		bool success;
+
+		/*
+		 * Eww.  We know this isn't going to deadlock
+		 * but lockdep probably doesn't.
+		 */
+		spin_lock(&next->lock);
+		/* Re-check the state now that we have the lock */
+		success = next->state == PL08X_CHAN_WAITING;
+		if (success)
+			pl08x_phy_reassign_start(plchan->phychan, next);
+		spin_unlock(&next->lock);
+
+		/* If the state changed, try to find another channel */
+		if (!success)
+			goto retry;
+	} else {
+		/* No more jobs, so free up the physical channel */
+		pl08x_put_phy_channel(pl08x, plchan->phychan);
+	}
+
+	plchan->phychan = NULL;
+	plchan->state = PL08X_CHAN_IDLE;
 }
 
 /*
@@ -1021,45 +1110,6 @@ static void pl08x_free_chan_resources(struct dma_chan *chan)
 {
 }
 
-/*
- * This should be called with the channel plchan->lock held
- */
-static int prep_phy_channel(struct pl08x_dma_chan *plchan)
-{
-	struct pl08x_driver_data *pl08x = plchan->host;
-	struct pl08x_phy_chan *ch;
-
-	/* Check if we already have a channel */
-	if (plchan->phychan) {
-		ch = plchan->phychan;
-		goto got_channel;
-	}
-
-	ch = pl08x_get_phy_channel(pl08x, plchan);
-	if (!ch) {
-		/* No physical channel available, cope with it */
-		dev_dbg(&pl08x->adev->dev, "no physical channel available for xfer on %s\n", plchan->name);
-		return -EBUSY;
-	}
-
-	plchan->phychan = ch;
-	dev_dbg(&pl08x->adev->dev, "allocated physical channel %d for xfer on %s\n",
-		 ch->id, plchan->name);
-
-got_channel:
-	plchan->phychan_hold++;
-
-	return 0;
-}
-
-static void release_phy_channel(struct pl08x_dma_chan *plchan)
-{
-	struct pl08x_driver_data *pl08x = plchan->host;
-
-	pl08x_put_phy_channel(pl08x, plchan->phychan);
-	plchan->phychan = NULL;
-}
-
 static dma_cookie_t pl08x_tx_submit(struct dma_async_tx_descriptor *tx)
 {
 	struct pl08x_dma_chan *plchan = to_pl08x_chan(tx->chan);
@@ -1072,19 +1122,6 @@ static dma_cookie_t pl08x_tx_submit(struct dma_async_tx_descriptor *tx)
 
 	/* Put this onto the pending list */
 	list_add_tail(&txd->node, &plchan->pend_list);
-
-	/*
-	 * If there was no physical channel available for this memcpy,
-	 * stack the request up and indicate that the channel is waiting
-	 * for a free physical channel.
-	 */
-	if (!plchan->slave && !plchan->phychan) {
-		/* Do this memcpy whenever there is a channel ready */
-		plchan->state = PL08X_CHAN_WAITING;
-	} else {
-		plchan->phychan_hold--;
-	}
-
 	spin_unlock_irqrestore(&plchan->lock, flags);
 
 	return cookie;
@@ -1275,19 +1312,10 @@ static void pl08x_issue_pending(struct dma_chan *chan)
 
 	spin_lock_irqsave(&plchan->lock, flags);
 	list_splice_tail_init(&plchan->pend_list, &plchan->issued_list);
-
-	/* Something is already active, or we're waiting for a channel... */
-	if (plchan->at || plchan->state == PL08X_CHAN_WAITING) {
-		spin_unlock_irqrestore(&plchan->lock, flags);
-		return;
-	}
-
-	/* Take the first element in the queue and execute it */
 	if (!list_empty(&plchan->issued_list)) {
-		plchan->state = PL08X_CHAN_RUNNING;
-		pl08x_start_next_txd(plchan);
+		if (!plchan->phychan && plchan->state != PL08X_CHAN_WAITING)
+			pl08x_phy_alloc_and_start(plchan);
 	}
-
 	spin_unlock_irqrestore(&plchan->lock, flags);
 }
 
@@ -1295,48 +1323,18 @@ static int pl08x_prep_channel_resources(struct pl08x_dma_chan *plchan,
 					struct pl08x_txd *txd)
 {
 	struct pl08x_driver_data *pl08x = plchan->host;
-	unsigned long flags;
-	int num_llis, ret;
+	int num_llis;
 
 	num_llis = pl08x_fill_llis_for_desc(pl08x, txd);
 	if (!num_llis) {
+		unsigned long flags;
+
 		spin_lock_irqsave(&plchan->lock, flags);
 		pl08x_free_txd(pl08x, txd);
 		spin_unlock_irqrestore(&plchan->lock, flags);
+
 		return -EINVAL;
 	}
-
-	spin_lock_irqsave(&plchan->lock, flags);
-
-	/*
-	 * See if we already have a physical channel allocated,
-	 * else this is the time to try to get one.
-	 */
-	ret = prep_phy_channel(plchan);
-	if (ret) {
-		/*
-		 * No physical channel was available.
-		 *
-		 * memcpy transfers can be sorted out at submission time.
-		 */
-		if (plchan->slave) {
-			pl08x_free_txd_list(pl08x, plchan);
-			pl08x_free_txd(pl08x, txd);
-			spin_unlock_irqrestore(&plchan->lock, flags);
-			return -EBUSY;
-		}
-	} else
-		/*
-		 * Else we're all set, paused and ready to roll, status
-		 * will switch to PL08X_CHAN_RUNNING when we call
-		 * issue_pending(). If there is something running on the
-		 * channel already we don't change its state.
-		 */
-		if (plchan->state == PL08X_CHAN_IDLE)
-			plchan->state = PL08X_CHAN_PAUSED;
-
-	spin_unlock_irqrestore(&plchan->lock, flags);
-
 	return 0;
 }
 
@@ -1556,14 +1554,11 @@ static int pl08x_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
 		plchan->state = PL08X_CHAN_IDLE;
 
 		if (plchan->phychan) {
-			pl08x_terminate_phy_chan(pl08x, plchan->phychan);
-
 			/*
 			 * Mark physical channel as free and free any slave
 			 * signal
 			 */
-			release_phy_channel(plchan);
-			plchan->phychan_hold = 0;
+			pl08x_phy_free(plchan);
 		}
 		/* Dequeue jobs and free LLIs */
 		if (plchan->at) {
@@ -1660,50 +1655,6 @@ static void pl08x_tasklet(unsigned long data)
 
 	spin_lock_irqsave(&plchan->lock, flags);
 	list_splice_tail_init(&plchan->done_list, &head);
-
-	if (plchan->at || !list_empty(&plchan->pend_list) || plchan->phychan_hold) {
-		/*
-		 * This channel is still in use - we have a new txd being
-		 * prepared and will soon be queued.  Don't give up the
-		 * physical channel.
-		 */
-	} else {
-		struct pl08x_dma_chan *waiting = NULL;
-
-		/*
-		 * No more jobs, so free up the physical channel
-		 */
-		release_phy_channel(plchan);
-		plchan->state = PL08X_CHAN_IDLE;
-
-		/*
-		 * And NOW before anyone else can grab that free:d up
-		 * physical channel, see if there is some memcpy pending
-		 * that seriously needs to start because of being stacked
-		 * up while we were choking the physical channels with data.
-		 */
-		list_for_each_entry(waiting, &pl08x->memcpy.channels,
-				    chan.device_node) {
-			if (waiting->state == PL08X_CHAN_WAITING) {
-				int ret;
-
-				/* This should REALLY not fail now */
-				ret = prep_phy_channel(waiting);
-				BUG_ON(ret);
-				waiting->phychan_hold--;
-				waiting->state = PL08X_CHAN_RUNNING;
-				/*
-				 * Eww.  We know this isn't going to deadlock
-				 * but lockdep probably doens't.
-				 */
-				spin_lock(&waiting->lock);
-				pl08x_start_next_txd(waiting);
-				spin_unlock(&waiting->lock);
-				break;
-			}
-		}
-	}
-
 	spin_unlock_irqrestore(&plchan->lock, flags);
 
 	while (!list_empty(&head)) {
@@ -1774,9 +1725,14 @@ static irqreturn_t pl08x_irq(int irq, void *dev)
 				dma_cookie_complete(&tx->tx);
 				list_add_tail(&tx->node, &plchan->done_list);
 
-				/* And start the next descriptor */
+				/*
+				 * And start the next descriptor (if any),
+				 * otherwise free this channel.
+				 */
 				if (!list_empty(&plchan->issued_list))
 					pl08x_start_next_txd(plchan);
+				else
+					pl08x_phy_free(plchan);
 			}
 			spin_unlock(&plchan->lock);
 
-- 
1.7.4.4

^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [RFC 27/34] dmaengine: PL08x: convert to use virt-dma structs
  2012-05-29  9:30 [RFC 00/34] PL08x DMA conversion to virt-dma Russell King - ARM Linux
                   ` (25 preceding siblings ...)
  2012-05-29  9:44 ` [RFC 26/34] dmaengine: PL08x: rejig physical channel allocation Russell King
@ 2012-05-29  9:44 ` Russell King
  2012-05-31  1:23   ` Linus Walleij
  2012-05-29  9:44 ` [RFC 28/34] dmaengine: PL08x: use vchan's spinlock Russell King
                   ` (6 subsequent siblings)
  33 siblings, 1 reply; 80+ messages in thread
From: Russell King @ 2012-05-29  9:44 UTC (permalink / raw)
  To: linux-arm-kernel

Convert PL08x to use the virt-dma structures.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/dma/amba-pl08x.c |   57 +++++++++++++++++++++++----------------------
 1 files changed, 29 insertions(+), 28 deletions(-)

diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c
index 5b6cd1e..6fafebc 100644
--- a/drivers/dma/amba-pl08x.c
+++ b/drivers/dma/amba-pl08x.c
@@ -86,6 +86,7 @@
 #include <asm/hardware/pl080.h>
 
 #include "dmaengine.h"
+#include "virt-dma.h"
 
 #define DRIVER_NAME	"pl08xdmac"
 
@@ -158,7 +159,7 @@ struct pl08x_sg {
 
 /**
  * struct pl08x_txd - wrapper for struct dma_async_tx_descriptor
- * @tx: async tx descriptor
+ * @vd: virtual DMA descriptor
  * @node: node for txd list for channels
  * @dsg_list: list of children sg's
  * @llis_bus: DMA memory address (physical) start for the LLIs
@@ -167,7 +168,7 @@ struct pl08x_sg {
  * @ccfg: config reg values for current txd
  */
 struct pl08x_txd {
-	struct dma_async_tx_descriptor tx;
+	struct virt_dma_desc vd;
 	struct list_head node;
 	struct list_head dsg_list;
 	dma_addr_t llis_bus;
@@ -201,7 +202,7 @@ enum pl08x_dma_chan_state {
 
 /**
  * struct pl08x_dma_chan - this structure wraps a DMA ENGINE channel
- * @chan: wrappped abstract channel
+ * @vc: wrappped virtual channel
  * @phychan: the physical channel utilized by this channel, if there is one
  * @tasklet: tasklet scheduled by the IRQ to handle actual work etc
  * @name: name of channel
@@ -219,7 +220,7 @@ enum pl08x_dma_chan_state {
  * @mux_use: count of descriptors using this DMA request signal setting
  */
 struct pl08x_dma_chan {
-	struct dma_chan chan;
+	struct virt_dma_chan vc;
 	struct pl08x_phy_chan *phychan;
 	struct tasklet_struct tasklet;
 	const char *name;
@@ -280,12 +281,12 @@ struct pl08x_driver_data {
 
 static inline struct pl08x_dma_chan *to_pl08x_chan(struct dma_chan *chan)
 {
-	return container_of(chan, struct pl08x_dma_chan, chan);
+	return container_of(chan, struct pl08x_dma_chan, vc.chan);
 }
 
 static inline struct pl08x_txd *to_pl08x_txd(struct dma_async_tx_descriptor *tx)
 {
-	return container_of(tx, struct pl08x_txd, tx);
+	return container_of(tx, struct pl08x_txd, vd.tx);
 }
 
 /*
@@ -641,14 +642,14 @@ static void pl08x_phy_free(struct pl08x_dma_chan *plchan)
 	next = NULL;
 
 	/* Find a waiting virtual channel for the next transfer. */
-	list_for_each_entry(p, &pl08x->memcpy.channels, chan.device_node)
+	list_for_each_entry(p, &pl08x->memcpy.channels, vc.chan.device_node)
 		if (p->state == PL08X_CHAN_WAITING) {
 			next = p;
 			break;
 		}
 
 	if (!next) {
-		list_for_each_entry(p, &pl08x->slave.channels, chan.device_node)
+		list_for_each_entry(p, &pl08x->slave.channels, vc.chan.device_node)
 			if (p->state == PL08X_CHAN_WAITING) {
 				next = p;
 				break;
@@ -1344,9 +1345,9 @@ static struct pl08x_txd *pl08x_get_txd(struct pl08x_dma_chan *plchan,
 	struct pl08x_txd *txd = kzalloc(sizeof(*txd), GFP_NOWAIT);
 
 	if (txd) {
-		dma_async_tx_descriptor_init(&txd->tx, &plchan->chan);
-		txd->tx.flags = flags;
-		txd->tx.tx_submit = pl08x_tx_submit;
+		dma_async_tx_descriptor_init(&txd->vd.tx, &plchan->vc.chan);
+		txd->vd.tx.flags = flags;
+		txd->vd.tx.tx_submit = pl08x_tx_submit;
 		INIT_LIST_HEAD(&txd->node);
 		INIT_LIST_HEAD(&txd->dsg_list);
 
@@ -1406,7 +1407,7 @@ static struct dma_async_tx_descriptor *pl08x_prep_dma_memcpy(
 	if (ret)
 		return NULL;
 
-	return &txd->tx;
+	return &txd->vd.tx;
 }
 
 static struct dma_async_tx_descriptor *pl08x_prep_slave_sg(
@@ -1522,7 +1523,7 @@ static struct dma_async_tx_descriptor *pl08x_prep_slave_sg(
 	if (ret)
 		return NULL;
 
-	return &txd->tx;
+	return &txd->vd.tx;
 }
 
 static int pl08x_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
@@ -1620,11 +1621,11 @@ static void pl08x_ensure_on(struct pl08x_driver_data *pl08x)
 
 static void pl08x_unmap_buffers(struct pl08x_txd *txd)
 {
-	struct device *dev = txd->tx.chan->device->dev;
+	struct device *dev = txd->vd.tx.chan->device->dev;
 	struct pl08x_sg *dsg;
 
-	if (!(txd->tx.flags & DMA_COMPL_SKIP_SRC_UNMAP)) {
-		if (txd->tx.flags & DMA_COMPL_SRC_UNMAP_SINGLE)
+	if (!(txd->vd.tx.flags & DMA_COMPL_SKIP_SRC_UNMAP)) {
+		if (txd->vd.tx.flags & DMA_COMPL_SRC_UNMAP_SINGLE)
 			list_for_each_entry(dsg, &txd->dsg_list, node)
 				dma_unmap_single(dev, dsg->src_addr, dsg->len,
 						DMA_TO_DEVICE);
@@ -1634,8 +1635,8 @@ static void pl08x_unmap_buffers(struct pl08x_txd *txd)
 						DMA_TO_DEVICE);
 		}
 	}
-	if (!(txd->tx.flags & DMA_COMPL_SKIP_DEST_UNMAP)) {
-		if (txd->tx.flags & DMA_COMPL_DEST_UNMAP_SINGLE)
+	if (!(txd->vd.tx.flags & DMA_COMPL_SKIP_DEST_UNMAP)) {
+		if (txd->vd.tx.flags & DMA_COMPL_DEST_UNMAP_SINGLE)
 			list_for_each_entry(dsg, &txd->dsg_list, node)
 				dma_unmap_single(dev, dsg->dst_addr, dsg->len,
 						DMA_FROM_DEVICE);
@@ -1660,8 +1661,8 @@ static void pl08x_tasklet(unsigned long data)
 	while (!list_empty(&head)) {
 		struct pl08x_txd *txd = list_first_entry(&head,
 						struct pl08x_txd, node);
-		dma_async_tx_callback callback = txd->tx.callback;
-		void *callback_param = txd->tx.callback_param;
+		dma_async_tx_callback callback = txd->vd.tx.callback;
+		void *callback_param = txd->vd.tx.callback_param;
 
 		list_del(&txd->node);
 
@@ -1722,7 +1723,7 @@ static irqreturn_t pl08x_irq(int irq, void *dev)
 				 * reservation.
 				 */
 				pl08x_release_mux(plchan);
-				dma_cookie_complete(&tx->tx);
+				dma_cookie_complete(&tx->vd.tx);
 				list_add_tail(&tx->node, &plchan->done_list);
 
 				/*
@@ -1797,8 +1798,8 @@ static int pl08x_dma_init_virtual_channels(struct pl08x_driver_data *pl08x,
 			 "initialize virtual channel \"%s\"\n",
 			 chan->name);
 
-		chan->chan.device = dmadev;
-		dma_cookie_init(&chan->chan);
+		chan->vc.chan.device = dmadev;
+		dma_cookie_init(&chan->vc.chan);
 
 		spin_lock_init(&chan->lock);
 		INIT_LIST_HEAD(&chan->pend_list);
@@ -1807,7 +1808,7 @@ static int pl08x_dma_init_virtual_channels(struct pl08x_driver_data *pl08x,
 		tasklet_init(&chan->tasklet, pl08x_tasklet,
 			     (unsigned long) chan);
 
-		list_add_tail(&chan->chan.device_node, &dmadev->channels);
+		list_add_tail(&chan->vc.chan.device_node, &dmadev->channels);
 	}
 	dev_info(&pl08x->adev->dev, "initialized %d virtual %s channels\n",
 		 i, slave ? "slave" : "memcpy");
@@ -1820,8 +1821,8 @@ static void pl08x_free_virtual_channels(struct dma_device *dmadev)
 	struct pl08x_dma_chan *next;
 
 	list_for_each_entry_safe(chan,
-				 next, &dmadev->channels, chan.device_node) {
-		list_del(&chan->chan.device_node);
+				 next, &dmadev->channels, vc.chan.device_node) {
+		list_del(&chan->vc.chan.device_node);
 		kfree(chan);
 	}
 }
@@ -1872,7 +1873,7 @@ static int pl08x_debugfs_show(struct seq_file *s, void *data)
 	seq_printf(s, "\nPL08x virtual memcpy channels:\n");
 	seq_printf(s, "CHANNEL:\tSTATE:\n");
 	seq_printf(s, "--------\t------\n");
-	list_for_each_entry(chan, &pl08x->memcpy.channels, chan.device_node) {
+	list_for_each_entry(chan, &pl08x->memcpy.channels, vc.chan.device_node) {
 		seq_printf(s, "%s\t\t%s\n", chan->name,
 			   pl08x_state_str(chan->state));
 	}
@@ -1880,7 +1881,7 @@ static int pl08x_debugfs_show(struct seq_file *s, void *data)
 	seq_printf(s, "\nPL08x virtual slave channels:\n");
 	seq_printf(s, "CHANNEL:\tSTATE:\n");
 	seq_printf(s, "--------\t------\n");
-	list_for_each_entry(chan, &pl08x->slave.channels, chan.device_node) {
+	list_for_each_entry(chan, &pl08x->slave.channels, vc.chan.device_node) {
 		seq_printf(s, "%s\t\t%s\n", chan->name,
 			   pl08x_state_str(chan->state));
 	}
-- 
1.7.4.4

^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [RFC 28/34] dmaengine: PL08x: use vchan's spinlock
  2012-05-29  9:30 [RFC 00/34] PL08x DMA conversion to virt-dma Russell King - ARM Linux
                   ` (26 preceding siblings ...)
  2012-05-29  9:44 ` [RFC 27/34] dmaengine: PL08x: convert to use virt-dma structs Russell King
@ 2012-05-29  9:44 ` Russell King
  2012-05-31  1:24   ` Linus Walleij
  2012-05-29  9:45 ` [RFC 29/34] dmaengine: PL08x: convert to use vchan submitted/issued lists Russell King
                   ` (5 subsequent siblings)
  33 siblings, 1 reply; 80+ messages in thread
From: Russell King @ 2012-05-29  9:44 UTC (permalink / raw)
  To: linux-arm-kernel

Initialize the vchan struct, and use the provided spinlock rather than
our own.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/dma/Kconfig      |    1 +
 drivers/dma/amba-pl08x.c |   45 ++++++++++++++++++++-------------------------
 2 files changed, 21 insertions(+), 25 deletions(-)

diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
index b792b03..2e5ac10 100644
--- a/drivers/dma/Kconfig
+++ b/drivers/dma/Kconfig
@@ -53,6 +53,7 @@ config AMBA_PL08X
 	bool "ARM PrimeCell PL080 or PL081 support"
 	depends on ARM_AMBA && EXPERIMENTAL
 	select DMA_ENGINE
+	select DMA_VIRTUAL_CHANNELS
 	help
 	  Platform has a PL08x DMAC device
 	  which can provide DMA engine support
diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c
index 6fafebc..6e53a22 100644
--- a/drivers/dma/amba-pl08x.c
+++ b/drivers/dma/amba-pl08x.c
@@ -230,7 +230,6 @@ struct pl08x_dma_chan {
 	struct list_head issued_list;
 	struct list_head done_list;
 	struct pl08x_txd *at;
-	spinlock_t lock;
 	struct pl08x_driver_data *host;
 	enum pl08x_dma_chan_state state;
 	bool slave;
@@ -477,7 +476,7 @@ static u32 pl08x_getbytes_chan(struct pl08x_dma_chan *plchan)
 	unsigned long flags;
 	size_t bytes = 0;
 
-	spin_lock_irqsave(&plchan->lock, flags);
+	spin_lock_irqsave(&plchan->vc.lock, flags);
 	ch = plchan->phychan;
 	txd = plchan->at;
 
@@ -536,7 +535,7 @@ static u32 pl08x_getbytes_chan(struct pl08x_dma_chan *plchan)
 		}
 	}
 
-	spin_unlock_irqrestore(&plchan->lock, flags);
+	spin_unlock_irqrestore(&plchan->vc.lock, flags);
 
 	return bytes;
 }
@@ -666,12 +665,12 @@ static void pl08x_phy_free(struct pl08x_dma_chan *plchan)
 		 * Eww.  We know this isn't going to deadlock
 		 * but lockdep probably doesn't.
 		 */
-		spin_lock(&next->lock);
+		spin_lock(&next->vc.lock);
 		/* Re-check the state now that we have the lock */
 		success = next->state == PL08X_CHAN_WAITING;
 		if (success)
 			pl08x_phy_reassign_start(plchan->phychan, next);
-		spin_unlock(&next->lock);
+		spin_unlock(&next->vc.lock);
 
 		/* If the state changed, try to find another channel */
 		if (!success)
@@ -1118,12 +1117,12 @@ static dma_cookie_t pl08x_tx_submit(struct dma_async_tx_descriptor *tx)
 	unsigned long flags;
 	dma_cookie_t cookie;
 
-	spin_lock_irqsave(&plchan->lock, flags);
+	spin_lock_irqsave(&plchan->vc.lock, flags);
 	cookie = dma_cookie_assign(tx);
 
 	/* Put this onto the pending list */
 	list_add_tail(&txd->node, &plchan->pend_list);
-	spin_unlock_irqrestore(&plchan->lock, flags);
+	spin_unlock_irqrestore(&plchan->vc.lock, flags);
 
 	return cookie;
 }
@@ -1311,13 +1310,13 @@ static void pl08x_issue_pending(struct dma_chan *chan)
 	struct pl08x_dma_chan *plchan = to_pl08x_chan(chan);
 	unsigned long flags;
 
-	spin_lock_irqsave(&plchan->lock, flags);
+	spin_lock_irqsave(&plchan->vc.lock, flags);
 	list_splice_tail_init(&plchan->pend_list, &plchan->issued_list);
 	if (!list_empty(&plchan->issued_list)) {
 		if (!plchan->phychan && plchan->state != PL08X_CHAN_WAITING)
 			pl08x_phy_alloc_and_start(plchan);
 	}
-	spin_unlock_irqrestore(&plchan->lock, flags);
+	spin_unlock_irqrestore(&plchan->vc.lock, flags);
 }
 
 static int pl08x_prep_channel_resources(struct pl08x_dma_chan *plchan,
@@ -1330,9 +1329,9 @@ static int pl08x_prep_channel_resources(struct pl08x_dma_chan *plchan,
 	if (!num_llis) {
 		unsigned long flags;
 
-		spin_lock_irqsave(&plchan->lock, flags);
+		spin_lock_irqsave(&plchan->vc.lock, flags);
 		pl08x_free_txd(pl08x, txd);
-		spin_unlock_irqrestore(&plchan->lock, flags);
+		spin_unlock_irqrestore(&plchan->vc.lock, flags);
 
 		return -EINVAL;
 	}
@@ -1544,9 +1543,9 @@ static int pl08x_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
 	 * Anything succeeds on channels with no physical allocation and
 	 * no queued transfers.
 	 */
-	spin_lock_irqsave(&plchan->lock, flags);
+	spin_lock_irqsave(&plchan->vc.lock, flags);
 	if (!plchan->phychan && !plchan->at) {
-		spin_unlock_irqrestore(&plchan->lock, flags);
+		spin_unlock_irqrestore(&plchan->vc.lock, flags);
 		return 0;
 	}
 
@@ -1585,7 +1584,7 @@ static int pl08x_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
 		break;
 	}
 
-	spin_unlock_irqrestore(&plchan->lock, flags);
+	spin_unlock_irqrestore(&plchan->vc.lock, flags);
 
 	return ret;
 }
@@ -1654,9 +1653,9 @@ static void pl08x_tasklet(unsigned long data)
 	unsigned long flags;
 	LIST_HEAD(head);
 
-	spin_lock_irqsave(&plchan->lock, flags);
+	spin_lock_irqsave(&plchan->vc.lock, flags);
 	list_splice_tail_init(&plchan->done_list, &head);
-	spin_unlock_irqrestore(&plchan->lock, flags);
+	spin_unlock_irqrestore(&plchan->vc.lock, flags);
 
 	while (!list_empty(&head)) {
 		struct pl08x_txd *txd = list_first_entry(&head,
@@ -1671,9 +1670,9 @@ static void pl08x_tasklet(unsigned long data)
 			pl08x_unmap_buffers(txd);
 
 		/* Free the descriptor */
-		spin_lock_irqsave(&plchan->lock, flags);
+		spin_lock_irqsave(&plchan->vc.lock, flags);
 		pl08x_free_txd(pl08x, txd);
-		spin_unlock_irqrestore(&plchan->lock, flags);
+		spin_unlock_irqrestore(&plchan->vc.lock, flags);
 
 		/* Callback to signal completion */
 		if (callback)
@@ -1714,7 +1713,7 @@ static irqreturn_t pl08x_irq(int irq, void *dev)
 				continue;
 			}
 
-			spin_lock(&plchan->lock);
+			spin_lock(&plchan->vc.lock);
 			tx = plchan->at;
 			if (tx) {
 				plchan->at = NULL;
@@ -1735,7 +1734,7 @@ static irqreturn_t pl08x_irq(int irq, void *dev)
 				else
 					pl08x_phy_free(plchan);
 			}
-			spin_unlock(&plchan->lock);
+			spin_unlock(&plchan->vc.lock);
 
 			/* Schedule tasklet on this channel */
 			tasklet_schedule(&plchan->tasklet);
@@ -1798,17 +1797,13 @@ static int pl08x_dma_init_virtual_channels(struct pl08x_driver_data *pl08x,
 			 "initialize virtual channel \"%s\"\n",
 			 chan->name);
 
-		chan->vc.chan.device = dmadev;
-		dma_cookie_init(&chan->vc.chan);
-
-		spin_lock_init(&chan->lock);
 		INIT_LIST_HEAD(&chan->pend_list);
 		INIT_LIST_HEAD(&chan->issued_list);
 		INIT_LIST_HEAD(&chan->done_list);
 		tasklet_init(&chan->tasklet, pl08x_tasklet,
 			     (unsigned long) chan);
 
-		list_add_tail(&chan->vc.chan.device_node, &dmadev->channels);
+		vchan_init(&chan->vc, dmadev);
 	}
 	dev_info(&pl08x->adev->dev, "initialized %d virtual %s channels\n",
 		 i, slave ? "slave" : "memcpy");
-- 
1.7.4.4

^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [RFC 29/34] dmaengine: PL08x: convert to use vchan submitted/issued lists
  2012-05-29  9:30 [RFC 00/34] PL08x DMA conversion to virt-dma Russell King - ARM Linux
                   ` (27 preceding siblings ...)
  2012-05-29  9:44 ` [RFC 28/34] dmaengine: PL08x: use vchan's spinlock Russell King
@ 2012-05-29  9:45 ` Russell King
  2012-05-31  1:24   ` Linus Walleij
  2012-05-29  9:45 ` [RFC 30/34] dmaengine: PL08x: convert to use vchan done list Russell King
                   ` (4 subsequent siblings)
  33 siblings, 1 reply; 80+ messages in thread
From: Russell King @ 2012-05-29  9:45 UTC (permalink / raw)
  To: linux-arm-kernel

Convert to use the virtual dma channel submitted/issued descriptor
lists rather than our own private lists, and use the virtual dma
channel support functions to manage these lists.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/dma/amba-pl08x.c |   64 ++++++++++++---------------------------------
 1 files changed, 17 insertions(+), 47 deletions(-)

diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c
index 6e53a22..eb556c5 100644
--- a/drivers/dma/amba-pl08x.c
+++ b/drivers/dma/amba-pl08x.c
@@ -208,8 +208,6 @@ enum pl08x_dma_chan_state {
  * @name: name of channel
  * @cd: channel platform data
  * @runtime_addr: address for RX/TX according to the runtime config
- * @pend_list: queued transactions pending on this channel
- * @issued_list: issued transactions for this channel
  * @done_list: list of completed transactions
  * @at: active transaction on this channel
  * @lock: a lock for this channel data
@@ -226,8 +224,6 @@ struct pl08x_dma_chan {
 	const char *name;
 	const struct pl08x_channel_data *cd;
 	struct dma_slave_config cfg;
-	struct list_head pend_list;
-	struct list_head issued_list;
 	struct list_head done_list;
 	struct pl08x_txd *at;
 	struct pl08x_driver_data *host;
@@ -350,12 +346,12 @@ static void pl08x_start_next_txd(struct pl08x_dma_chan *plchan)
 {
 	struct pl08x_driver_data *pl08x = plchan->host;
 	struct pl08x_phy_chan *phychan = plchan->phychan;
+	struct virt_dma_desc *vd = vchan_next_desc(&plchan->vc);
+	struct pl08x_txd *txd = to_pl08x_txd(&vd->tx);
 	struct pl08x_lli *lli;
-	struct pl08x_txd *txd;
 	u32 val;
 
-	txd = list_first_entry(&plchan->issued_list, struct pl08x_txd, node);
-	list_del(&txd->node);
+	list_del(&txd->vd.node);
 
 	plchan->at = txd;
 
@@ -517,18 +513,18 @@ static u32 pl08x_getbytes_chan(struct pl08x_dma_chan *plchan)
 	}
 
 	/* Sum up all queued transactions */
-	if (!list_empty(&plchan->issued_list)) {
+	if (!list_empty(&plchan->vc.desc_issued)) {
 		struct pl08x_txd *txdi;
-		list_for_each_entry(txdi, &plchan->issued_list, node) {
+		list_for_each_entry(txdi, &plchan->vc.desc_issued, vd.node) {
 			struct pl08x_sg *dsg;
 			list_for_each_entry(dsg, &txd->dsg_list, node)
 				bytes += dsg->len;
 		}
 	}
 
-	if (!list_empty(&plchan->pend_list)) {
+	if (!list_empty(&plchan->vc.desc_submitted)) {
 		struct pl08x_txd *txdi;
-		list_for_each_entry(txdi, &plchan->pend_list, node) {
+		list_for_each_entry(txdi, &plchan->vc.desc_submitted, vd.node) {
 			struct pl08x_sg *dsg;
 			list_for_each_entry(dsg, &txd->dsg_list, node)
 				bytes += dsg->len;
@@ -1087,13 +1083,12 @@ static void pl08x_free_txd_list(struct pl08x_driver_data *pl08x,
 	LIST_HEAD(head);
 	struct pl08x_txd *txd;
 
-	list_splice_tail_init(&plchan->issued_list, &head);
-	list_splice_tail_init(&plchan->pend_list, &head);
+	vchan_get_all_descriptors(&plchan->vc, &head);
 
 	while (!list_empty(&head)) {
-		txd = list_first_entry(&head, struct pl08x_txd, node);
+		txd = list_first_entry(&head, struct pl08x_txd, vd.node);
 		pl08x_release_mux(plchan);
-		list_del(&txd->node);
+		list_del(&txd->vd.node);
 		pl08x_free_txd(pl08x, txd);
 	}
 }
@@ -1110,23 +1105,6 @@ static void pl08x_free_chan_resources(struct dma_chan *chan)
 {
 }
 
-static dma_cookie_t pl08x_tx_submit(struct dma_async_tx_descriptor *tx)
-{
-	struct pl08x_dma_chan *plchan = to_pl08x_chan(tx->chan);
-	struct pl08x_txd *txd = to_pl08x_txd(tx);
-	unsigned long flags;
-	dma_cookie_t cookie;
-
-	spin_lock_irqsave(&plchan->vc.lock, flags);
-	cookie = dma_cookie_assign(tx);
-
-	/* Put this onto the pending list */
-	list_add_tail(&txd->node, &plchan->pend_list);
-	spin_unlock_irqrestore(&plchan->vc.lock, flags);
-
-	return cookie;
-}
-
 static struct dma_async_tx_descriptor *pl08x_prep_dma_interrupt(
 		struct dma_chan *chan, unsigned long flags)
 {
@@ -1311,8 +1289,7 @@ static void pl08x_issue_pending(struct dma_chan *chan)
 	unsigned long flags;
 
 	spin_lock_irqsave(&plchan->vc.lock, flags);
-	list_splice_tail_init(&plchan->pend_list, &plchan->issued_list);
-	if (!list_empty(&plchan->issued_list)) {
+	if (vchan_issue_pending(&plchan->vc)) {
 		if (!plchan->phychan && plchan->state != PL08X_CHAN_WAITING)
 			pl08x_phy_alloc_and_start(plchan);
 	}
@@ -1338,16 +1315,11 @@ static int pl08x_prep_channel_resources(struct pl08x_dma_chan *plchan,
 	return 0;
 }
 
-static struct pl08x_txd *pl08x_get_txd(struct pl08x_dma_chan *plchan,
-	unsigned long flags)
+static struct pl08x_txd *pl08x_get_txd(struct pl08x_dma_chan *plchan)
 {
 	struct pl08x_txd *txd = kzalloc(sizeof(*txd), GFP_NOWAIT);
 
 	if (txd) {
-		dma_async_tx_descriptor_init(&txd->vd.tx, &plchan->vc.chan);
-		txd->vd.tx.flags = flags;
-		txd->vd.tx.tx_submit = pl08x_tx_submit;
-		INIT_LIST_HEAD(&txd->node);
 		INIT_LIST_HEAD(&txd->dsg_list);
 
 		/* Always enable error and terminal interrupts */
@@ -1370,7 +1342,7 @@ static struct dma_async_tx_descriptor *pl08x_prep_dma_memcpy(
 	struct pl08x_sg *dsg;
 	int ret;
 
-	txd = pl08x_get_txd(plchan, flags);
+	txd = pl08x_get_txd(plchan);
 	if (!txd) {
 		dev_err(&pl08x->adev->dev,
 			"%s no memory for descriptor\n", __func__);
@@ -1406,7 +1378,7 @@ static struct dma_async_tx_descriptor *pl08x_prep_dma_memcpy(
 	if (ret)
 		return NULL;
 
-	return &txd->vd.tx;
+	return vchan_tx_prep(&plchan->vc, &txd->vd, flags);
 }
 
 static struct dma_async_tx_descriptor *pl08x_prep_slave_sg(
@@ -1428,7 +1400,7 @@ static struct dma_async_tx_descriptor *pl08x_prep_slave_sg(
 	dev_dbg(&pl08x->adev->dev, "%s prepare transaction of %d bytes from %s\n",
 			__func__, sgl->length, plchan->name);
 
-	txd = pl08x_get_txd(plchan, flags);
+	txd = pl08x_get_txd(plchan);
 	if (!txd) {
 		dev_err(&pl08x->adev->dev, "%s no txd\n", __func__);
 		return NULL;
@@ -1522,7 +1494,7 @@ static struct dma_async_tx_descriptor *pl08x_prep_slave_sg(
 	if (ret)
 		return NULL;
 
-	return &txd->vd.tx;
+	return vchan_tx_prep(&plchan->vc, &txd->vd, flags);
 }
 
 static int pl08x_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
@@ -1729,7 +1701,7 @@ static irqreturn_t pl08x_irq(int irq, void *dev)
 				 * And start the next descriptor (if any),
 				 * otherwise free this channel.
 				 */
-				if (!list_empty(&plchan->issued_list))
+				if (vchan_next_desc(&plchan->vc))
 					pl08x_start_next_txd(plchan);
 				else
 					pl08x_phy_free(plchan);
@@ -1797,8 +1769,6 @@ static int pl08x_dma_init_virtual_channels(struct pl08x_driver_data *pl08x,
 			 "initialize virtual channel \"%s\"\n",
 			 chan->name);
 
-		INIT_LIST_HEAD(&chan->pend_list);
-		INIT_LIST_HEAD(&chan->issued_list);
 		INIT_LIST_HEAD(&chan->done_list);
 		tasklet_init(&chan->tasklet, pl08x_tasklet,
 			     (unsigned long) chan);
-- 
1.7.4.4

^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [RFC 30/34] dmaengine: PL08x: convert to use vchan done list
  2012-05-29  9:30 [RFC 00/34] PL08x DMA conversion to virt-dma Russell King - ARM Linux
                   ` (28 preceding siblings ...)
  2012-05-29  9:45 ` [RFC 29/34] dmaengine: PL08x: convert to use vchan submitted/issued lists Russell King
@ 2012-05-29  9:45 ` Russell King
  2012-05-31  1:24   ` Linus Walleij
  2012-05-29  9:45 ` [RFC 31/34] dmaengine: PL08x: fix tx_status function to return correct residue Russell King
                   ` (3 subsequent siblings)
  33 siblings, 1 reply; 80+ messages in thread
From: Russell King @ 2012-05-29  9:45 UTC (permalink / raw)
  To: linux-arm-kernel

Convert to use the virtual dma channel done list, tasklet, and
descriptor freeing.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/dma/amba-pl08x.c |  135 ++++++++++++++++++---------------------------
 1 files changed, 54 insertions(+), 81 deletions(-)

diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c
index eb556c5..2b9fe0e 100644
--- a/drivers/dma/amba-pl08x.c
+++ b/drivers/dma/amba-pl08x.c
@@ -160,16 +160,16 @@ struct pl08x_sg {
 /**
  * struct pl08x_txd - wrapper for struct dma_async_tx_descriptor
  * @vd: virtual DMA descriptor
- * @node: node for txd list for channels
  * @dsg_list: list of children sg's
  * @llis_bus: DMA memory address (physical) start for the LLIs
  * @llis_va: virtual memory address start for the LLIs
  * @cctl: control reg values for current txd
  * @ccfg: config reg values for current txd
+ * @done: this marks completed descriptors, which should not have their
+ *   mux released.
  */
 struct pl08x_txd {
 	struct virt_dma_desc vd;
-	struct list_head node;
 	struct list_head dsg_list;
 	dma_addr_t llis_bus;
 	struct pl08x_lli *llis_va;
@@ -180,6 +180,7 @@ struct pl08x_txd {
 	 * trigger this txd.  Other registers are in llis_va[0].
 	 */
 	u32 ccfg;
+	bool done;
 };
 
 /**
@@ -204,11 +205,9 @@ enum pl08x_dma_chan_state {
  * struct pl08x_dma_chan - this structure wraps a DMA ENGINE channel
  * @vc: wrappped virtual channel
  * @phychan: the physical channel utilized by this channel, if there is one
- * @tasklet: tasklet scheduled by the IRQ to handle actual work etc
  * @name: name of channel
  * @cd: channel platform data
  * @runtime_addr: address for RX/TX according to the runtime config
- * @done_list: list of completed transactions
  * @at: active transaction on this channel
  * @lock: a lock for this channel data
  * @host: a pointer to the host (internal use)
@@ -220,11 +219,9 @@ enum pl08x_dma_chan_state {
 struct pl08x_dma_chan {
 	struct virt_dma_chan vc;
 	struct pl08x_phy_chan *phychan;
-	struct tasklet_struct tasklet;
 	const char *name;
 	const struct pl08x_channel_data *cd;
 	struct dma_slave_config cfg;
-	struct list_head done_list;
 	struct pl08x_txd *at;
 	struct pl08x_driver_data *host;
 	enum pl08x_dma_chan_state state;
@@ -1077,6 +1074,52 @@ static void pl08x_free_txd(struct pl08x_driver_data *pl08x,
 	kfree(txd);
 }
 
+static void pl08x_unmap_buffers(struct pl08x_txd *txd)
+{
+	struct device *dev = txd->vd.tx.chan->device->dev;
+	struct pl08x_sg *dsg;
+
+	if (!(txd->vd.tx.flags & DMA_COMPL_SKIP_SRC_UNMAP)) {
+		if (txd->vd.tx.flags & DMA_COMPL_SRC_UNMAP_SINGLE)
+			list_for_each_entry(dsg, &txd->dsg_list, node)
+				dma_unmap_single(dev, dsg->src_addr, dsg->len,
+						DMA_TO_DEVICE);
+		else {
+			list_for_each_entry(dsg, &txd->dsg_list, node)
+				dma_unmap_page(dev, dsg->src_addr, dsg->len,
+						DMA_TO_DEVICE);
+		}
+	}
+	if (!(txd->vd.tx.flags & DMA_COMPL_SKIP_DEST_UNMAP)) {
+		if (txd->vd.tx.flags & DMA_COMPL_DEST_UNMAP_SINGLE)
+			list_for_each_entry(dsg, &txd->dsg_list, node)
+				dma_unmap_single(dev, dsg->dst_addr, dsg->len,
+						DMA_FROM_DEVICE);
+		else
+			list_for_each_entry(dsg, &txd->dsg_list, node)
+				dma_unmap_page(dev, dsg->dst_addr, dsg->len,
+						DMA_FROM_DEVICE);
+	}
+}
+
+static void pl08x_desc_free(struct virt_dma_desc *vd)
+{
+	struct pl08x_txd *txd = to_pl08x_txd(&vd->tx);
+	struct pl08x_dma_chan *plchan = to_pl08x_chan(vd->tx.chan);
+	struct pl08x_driver_data *pl08x = plchan->host;
+	unsigned long flags;
+
+	if (!plchan->slave)
+		pl08x_unmap_buffers(txd);
+
+	if (!txd->done)
+		pl08x_release_mux(plchan);
+
+	spin_lock_irqsave(&pl08x->lock, flags);
+	pl08x_free_txd(plchan->host, txd);
+	spin_unlock_irqrestore(&pl08x->lock, flags);
+}
+
 static void pl08x_free_txd_list(struct pl08x_driver_data *pl08x,
 				struct pl08x_dma_chan *plchan)
 {
@@ -1087,9 +1130,8 @@ static void pl08x_free_txd_list(struct pl08x_driver_data *pl08x,
 
 	while (!list_empty(&head)) {
 		txd = list_first_entry(&head, struct pl08x_txd, vd.node);
-		pl08x_release_mux(plchan);
 		list_del(&txd->vd.node);
-		pl08x_free_txd(pl08x, txd);
+		pl08x_desc_free(&txd->vd);
 	}
 }
 
@@ -1534,9 +1576,7 @@ static int pl08x_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
 		}
 		/* Dequeue jobs and free LLIs */
 		if (plchan->at) {
-			/* Killing this one off, release its mux */
-			pl08x_release_mux(plchan);
-			pl08x_free_txd(pl08x, plchan->at);
+			pl08x_desc_free(&plchan->at->vd);
 			plchan->at = NULL;
 		}
 		/* Dequeue jobs not yet fired as well */
@@ -1590,68 +1630,6 @@ static void pl08x_ensure_on(struct pl08x_driver_data *pl08x)
 	writel(PL080_CONFIG_ENABLE, pl08x->base + PL080_CONFIG);
 }
 
-static void pl08x_unmap_buffers(struct pl08x_txd *txd)
-{
-	struct device *dev = txd->vd.tx.chan->device->dev;
-	struct pl08x_sg *dsg;
-
-	if (!(txd->vd.tx.flags & DMA_COMPL_SKIP_SRC_UNMAP)) {
-		if (txd->vd.tx.flags & DMA_COMPL_SRC_UNMAP_SINGLE)
-			list_for_each_entry(dsg, &txd->dsg_list, node)
-				dma_unmap_single(dev, dsg->src_addr, dsg->len,
-						DMA_TO_DEVICE);
-		else {
-			list_for_each_entry(dsg, &txd->dsg_list, node)
-				dma_unmap_page(dev, dsg->src_addr, dsg->len,
-						DMA_TO_DEVICE);
-		}
-	}
-	if (!(txd->vd.tx.flags & DMA_COMPL_SKIP_DEST_UNMAP)) {
-		if (txd->vd.tx.flags & DMA_COMPL_DEST_UNMAP_SINGLE)
-			list_for_each_entry(dsg, &txd->dsg_list, node)
-				dma_unmap_single(dev, dsg->dst_addr, dsg->len,
-						DMA_FROM_DEVICE);
-		else
-			list_for_each_entry(dsg, &txd->dsg_list, node)
-				dma_unmap_page(dev, dsg->dst_addr, dsg->len,
-						DMA_FROM_DEVICE);
-	}
-}
-
-static void pl08x_tasklet(unsigned long data)
-{
-	struct pl08x_dma_chan *plchan = (struct pl08x_dma_chan *) data;
-	struct pl08x_driver_data *pl08x = plchan->host;
-	unsigned long flags;
-	LIST_HEAD(head);
-
-	spin_lock_irqsave(&plchan->vc.lock, flags);
-	list_splice_tail_init(&plchan->done_list, &head);
-	spin_unlock_irqrestore(&plchan->vc.lock, flags);
-
-	while (!list_empty(&head)) {
-		struct pl08x_txd *txd = list_first_entry(&head,
-						struct pl08x_txd, node);
-		dma_async_tx_callback callback = txd->vd.tx.callback;
-		void *callback_param = txd->vd.tx.callback_param;
-
-		list_del(&txd->node);
-
-		/* Don't try to unmap buffers on slave channels */
-		if (!plchan->slave)
-			pl08x_unmap_buffers(txd);
-
-		/* Free the descriptor */
-		spin_lock_irqsave(&plchan->vc.lock, flags);
-		pl08x_free_txd(pl08x, txd);
-		spin_unlock_irqrestore(&plchan->vc.lock, flags);
-
-		/* Callback to signal completion */
-		if (callback)
-			callback(callback_param);
-	}
-}
-
 static irqreturn_t pl08x_irq(int irq, void *dev)
 {
 	struct pl08x_driver_data *pl08x = dev;
@@ -1694,8 +1672,8 @@ static irqreturn_t pl08x_irq(int irq, void *dev)
 				 * reservation.
 				 */
 				pl08x_release_mux(plchan);
-				dma_cookie_complete(&tx->vd.tx);
-				list_add_tail(&tx->node, &plchan->done_list);
+				tx->done = true;
+				vchan_cookie_complete(&tx->vd);
 
 				/*
 				 * And start the next descriptor (if any),
@@ -1708,8 +1686,6 @@ static irqreturn_t pl08x_irq(int irq, void *dev)
 			}
 			spin_unlock(&plchan->vc.lock);
 
-			/* Schedule tasklet on this channel */
-			tasklet_schedule(&plchan->tasklet);
 			mask |= (1 << i);
 		}
 	}
@@ -1769,10 +1745,7 @@ static int pl08x_dma_init_virtual_channels(struct pl08x_driver_data *pl08x,
 			 "initialize virtual channel \"%s\"\n",
 			 chan->name);
 
-		INIT_LIST_HEAD(&chan->done_list);
-		tasklet_init(&chan->tasklet, pl08x_tasklet,
-			     (unsigned long) chan);
-
+		chan->vc.desc_free = pl08x_desc_free;
 		vchan_init(&chan->vc, dmadev);
 	}
 	dev_info(&pl08x->adev->dev, "initialized %d virtual %s channels\n",
-- 
1.7.4.4

^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [RFC 31/34] dmaengine: PL08x: fix tx_status function to return correct residue
  2012-05-29  9:30 [RFC 00/34] PL08x DMA conversion to virt-dma Russell King - ARM Linux
                   ` (29 preceding siblings ...)
  2012-05-29  9:45 ` [RFC 30/34] dmaengine: PL08x: convert to use vchan done list Russell King
@ 2012-05-29  9:45 ` Russell King
  2012-05-31  1:25   ` Linus Walleij
  2012-05-29  9:46 ` [RFC 32/34] dmaengine: PL08x: get rid of pl08x_prep_channel_resources Russell King
                   ` (2 subsequent siblings)
  33 siblings, 1 reply; 80+ messages in thread
From: Russell King @ 2012-05-29  9:45 UTC (permalink / raw)
  To: linux-arm-kernel

Now that we're converted to use the generic vchan support, we can fix
the residue return from tx_status to be compliant with dmaengine.  This
returns the number of bytes remaining for the _specified_ cookie, not
the number of bytes in all pending transfers on the channel.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/dma/amba-pl08x.c |   61 +++++++++++++++++++++++++--------------------
 1 files changed, 34 insertions(+), 27 deletions(-)

diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c
index 2b9fe0e..a8f2b20 100644
--- a/drivers/dma/amba-pl08x.c
+++ b/drivers/dma/amba-pl08x.c
@@ -466,10 +466,8 @@ static u32 pl08x_getbytes_chan(struct pl08x_dma_chan *plchan)
 {
 	struct pl08x_phy_chan *ch;
 	struct pl08x_txd *txd;
-	unsigned long flags;
 	size_t bytes = 0;
 
-	spin_lock_irqsave(&plchan->vc.lock, flags);
 	ch = plchan->phychan;
 	txd = plchan->at;
 
@@ -509,27 +507,6 @@ static u32 pl08x_getbytes_chan(struct pl08x_dma_chan *plchan)
 		}
 	}
 
-	/* Sum up all queued transactions */
-	if (!list_empty(&plchan->vc.desc_issued)) {
-		struct pl08x_txd *txdi;
-		list_for_each_entry(txdi, &plchan->vc.desc_issued, vd.node) {
-			struct pl08x_sg *dsg;
-			list_for_each_entry(dsg, &txd->dsg_list, node)
-				bytes += dsg->len;
-		}
-	}
-
-	if (!list_empty(&plchan->vc.desc_submitted)) {
-		struct pl08x_txd *txdi;
-		list_for_each_entry(txdi, &plchan->vc.desc_submitted, vd.node) {
-			struct pl08x_sg *dsg;
-			list_for_each_entry(dsg, &txd->dsg_list, node)
-				bytes += dsg->len;
-		}
-	}
-
-	spin_unlock_irqrestore(&plchan->vc.lock, flags);
-
 	return bytes;
 }
 
@@ -1164,23 +1141,53 @@ static enum dma_status pl08x_dma_tx_status(struct dma_chan *chan,
 		dma_cookie_t cookie, struct dma_tx_state *txstate)
 {
 	struct pl08x_dma_chan *plchan = to_pl08x_chan(chan);
+	struct virt_dma_desc *vd;
+	unsigned long flags;
 	enum dma_status ret;
+	size_t bytes = 0;
 
 	ret = dma_cookie_status(chan, cookie, txstate);
 	if (ret == DMA_SUCCESS)
 		return ret;
 
 	/*
+	 * There's no point calculating the residue if there's
+	 * no txstate to store the value.
+	 */
+	if (!txstate) {
+		if (plchan->state == PL08X_CHAN_PAUSED)
+			ret = DMA_PAUSED;
+		return ret;
+	}
+
+	spin_lock_irqsave(&plchan->vc.lock, flags);
+	ret = dma_cookie_status(chan, cookie, txstate);
+	if (ret != DMA_SUCCESS) {
+		vd = vchan_find_desc(&plchan->vc, cookie);
+		if (vd) {
+			/* On the issued list, so hasn't been processed yet */
+			struct pl08x_txd *txd = to_pl08x_txd(&vd->tx);
+			struct pl08x_sg *dsg;
+
+			list_for_each_entry(dsg, &txd->dsg_list, node)
+				bytes += dsg->len;
+		} else {
+			bytes = pl08x_getbytes_chan(plchan);
+		}
+	}
+	spin_unlock_irqrestore(&plchan->vc.lock, flags);
+
+	/*
 	 * This cookie not complete yet
 	 * Get number of bytes left in the active transactions and queue
 	 */
-	dma_set_residue(txstate, pl08x_getbytes_chan(plchan));
+	dma_set_residue(txstate, bytes);
 
-	if (plchan->state == PL08X_CHAN_PAUSED)
-		return DMA_PAUSED;
+	if (plchan->state == PL08X_CHAN_PAUSED && ret == DMA_IN_PROGRESS)
+		ret = DMA_PAUSED;
 
 	/* Whether waiting or running, we're in progress */
-	return DMA_IN_PROGRESS;
+	return ret;
 }
 
 /* PrimeCell DMA extension */
-- 
1.7.4.4

^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [RFC 32/34] dmaengine: PL08x: get rid of pl08x_prep_channel_resources
  2012-05-29  9:30 [RFC 00/34] PL08x DMA conversion to virt-dma Russell King - ARM Linux
                   ` (30 preceding siblings ...)
  2012-05-29  9:45 ` [RFC 31/34] dmaengine: PL08x: fix tx_status function to return correct residue Russell King
@ 2012-05-29  9:46 ` Russell King
  2012-05-31  1:25   ` Linus Walleij
  2012-05-29  9:46 ` [RFC 33/34] dmaengine: PL08x: get rid of write only pool_ctr and free_txd locking Russell King
  2012-05-29  9:46 ` [RFC 34/34] dmaengine: PL08x: ensure all descriptors are freed when channel is released Russell King
  33 siblings, 1 reply; 80+ messages in thread
From: Russell King @ 2012-05-29  9:46 UTC (permalink / raw)
  To: linux-arm-kernel

This function is now unnecessary; we can move its internals inline
instead.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/dma/amba-pl08x.c |   32 +++++++++-----------------------
 1 files changed, 9 insertions(+), 23 deletions(-)

diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c
index a8f2b20..9132993 100644
--- a/drivers/dma/amba-pl08x.c
+++ b/drivers/dma/amba-pl08x.c
@@ -1345,25 +1345,6 @@ static void pl08x_issue_pending(struct dma_chan *chan)
 	spin_unlock_irqrestore(&plchan->vc.lock, flags);
 }
 
-static int pl08x_prep_channel_resources(struct pl08x_dma_chan *plchan,
-					struct pl08x_txd *txd)
-{
-	struct pl08x_driver_data *pl08x = plchan->host;
-	int num_llis;
-
-	num_llis = pl08x_fill_llis_for_desc(pl08x, txd);
-	if (!num_llis) {
-		unsigned long flags;
-
-		spin_lock_irqsave(&plchan->vc.lock, flags);
-		pl08x_free_txd(pl08x, txd);
-		spin_unlock_irqrestore(&plchan->vc.lock, flags);
-
-		return -EINVAL;
-	}
-	return 0;
-}
-
 static struct pl08x_txd *pl08x_get_txd(struct pl08x_dma_chan *plchan)
 {
 	struct pl08x_txd *txd = kzalloc(sizeof(*txd), GFP_NOWAIT);
@@ -1423,9 +1404,11 @@ static struct dma_async_tx_descriptor *pl08x_prep_dma_memcpy(
 		txd->cctl |= pl08x_select_bus(pl08x->mem_buses,
 					      pl08x->mem_buses);
 
-	ret = pl08x_prep_channel_resources(plchan, txd);
-	if (ret)
+	ret = pl08x_fill_llis_for_desc(plchan->host, txd);
+	if (!ret) {
+		pl08x_free_txd(pl08x, txd);
 		return NULL;
+	}
 
 	return vchan_tx_prep(&plchan->vc, &txd->vd, flags);
 }
@@ -1539,9 +1522,12 @@ static struct dma_async_tx_descriptor *pl08x_prep_slave_sg(
 		}
 	}
 
-	ret = pl08x_prep_channel_resources(plchan, txd);
-	if (ret)
+	ret = pl08x_fill_llis_for_desc(plchan->host, txd);
+	if (!ret) {
+		pl08x_release_mux(plchan);
+		pl08x_free_txd(pl08x, txd);
 		return NULL;
+	}
 
 	return vchan_tx_prep(&plchan->vc, &txd->vd, flags);
 }
-- 
1.7.4.4

^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [RFC 33/34] dmaengine: PL08x: get rid of write only pool_ctr and free_txd locking
  2012-05-29  9:30 [RFC 00/34] PL08x DMA conversion to virt-dma Russell King - ARM Linux
                   ` (31 preceding siblings ...)
  2012-05-29  9:46 ` [RFC 32/34] dmaengine: PL08x: get rid of pl08x_prep_channel_resources Russell King
@ 2012-05-29  9:46 ` Russell King
  2012-05-31  1:26   ` Linus Walleij
  2012-05-29  9:46 ` [RFC 34/34] dmaengine: PL08x: ensure all descriptors are freed when channel is released Russell King
  33 siblings, 1 reply; 80+ messages in thread
From: Russell King @ 2012-05-29  9:46 UTC (permalink / raw)
  To: linux-arm-kernel

The free function says the pl08x lock should be taken before calling
it.  However, the DMA pool allocation/freeing is already properly
locked.  The only thing that would need this is pool_ctr, which
happens to be a write-only variable.

Let's get rid of this, and eliminate any need for additional locking
here.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/dma/amba-pl08x.c |   12 ------------
 1 files changed, 0 insertions(+), 12 deletions(-)

diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c
index 9132993..f2a29bf 100644
--- a/drivers/dma/amba-pl08x.c
+++ b/drivers/dma/amba-pl08x.c
@@ -240,7 +240,6 @@ struct pl08x_dma_chan {
  * @pd: platform data passed in from the platform/machine
  * @phy_chans: array of data for the physical channels
  * @pool: a pool for the LLI descriptors
- * @pool_ctr: counter of LLIs in the pool
  * @lli_buses: bitmask to or in to LLI pointer selecting AHB port for LLI
  * fetches
  * @mem_buses: set to indicate memory transfers on AHB2.
@@ -255,7 +254,6 @@ struct pl08x_driver_data {
 	struct pl08x_platform_data *pd;
 	struct pl08x_phy_chan *phy_chans;
 	struct dma_pool *pool;
-	int pool_ctr;
 	u8 lli_buses;
 	u8 mem_buses;
 };
@@ -814,8 +812,6 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x,
 		return 0;
 	}
 
-	pl08x->pool_ctr++;
-
 	bd.txd = txd;
 	bd.lli_bus = (pl08x->lli_buses & PL08X_AHB2) ? PL080_LLI_LM_AHB2 : 0;
 	cctl = txd->cctl;
@@ -1031,18 +1027,14 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x,
 	return num_llis;
 }
 
-/* You should call this with the struct pl08x lock held */
 static void pl08x_free_txd(struct pl08x_driver_data *pl08x,
 			   struct pl08x_txd *txd)
 {
 	struct pl08x_sg *dsg, *_dsg;
 
-	/* Free the LLI */
 	if (txd->llis_va)
 		dma_pool_free(pl08x->pool, txd->llis_va, txd->llis_bus);
 
-	pl08x->pool_ctr--;
-
 	list_for_each_entry_safe(dsg, _dsg, &txd->dsg_list, node) {
 		list_del(&dsg->node);
 		kfree(dsg);
@@ -1083,8 +1075,6 @@ static void pl08x_desc_free(struct virt_dma_desc *vd)
 {
 	struct pl08x_txd *txd = to_pl08x_txd(&vd->tx);
 	struct pl08x_dma_chan *plchan = to_pl08x_chan(vd->tx.chan);
-	struct pl08x_driver_data *pl08x = plchan->host;
-	unsigned long flags;
 
 	if (!plchan->slave)
 		pl08x_unmap_buffers(txd);
@@ -1092,9 +1082,7 @@ static void pl08x_desc_free(struct virt_dma_desc *vd)
 	if (!txd->done)
 		pl08x_release_mux(plchan);
 
-	spin_lock_irqsave(&pl08x->lock, flags);
 	pl08x_free_txd(plchan->host, txd);
-	spin_unlock_irqrestore(&pl08x->lock, flags);
 }
 
 static void pl08x_free_txd_list(struct pl08x_driver_data *pl08x,
-- 
1.7.4.4

^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [RFC 34/34] dmaengine: PL08x: ensure all descriptors are freed when channel is released
  2012-05-29  9:30 [RFC 00/34] PL08x DMA conversion to virt-dma Russell King - ARM Linux
                   ` (32 preceding siblings ...)
  2012-05-29  9:46 ` [RFC 33/34] dmaengine: PL08x: get rid of write only pool_ctr and free_txd locking Russell King
@ 2012-05-29  9:46 ` Russell King
  2012-05-31  1:27   ` Linus Walleij
  33 siblings, 1 reply; 80+ messages in thread
From: Russell King @ 2012-05-29  9:46 UTC (permalink / raw)
  To: linux-arm-kernel

Ensure all queued descriptors are freed when the channel is released,
ensuring we don't leak memory

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/dma/amba-pl08x.c |    2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)

diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c
index f2a29bf..23a2974 100644
--- a/drivers/dma/amba-pl08x.c
+++ b/drivers/dma/amba-pl08x.c
@@ -1110,6 +1110,8 @@ static int pl08x_alloc_chan_resources(struct dma_chan *chan)
 
 static void pl08x_free_chan_resources(struct dma_chan *chan)
 {
+	/* Ensure all queued descriptors are freed */
+	vchan_free_chan_resources(to_virt_chan(chan));
 }
 
 static struct dma_async_tx_descriptor *pl08x_prep_dma_interrupt(
-- 
1.7.4.4

^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [RFC 02/34] dmaengine: virt-dma: vchan_find_desc()
  2012-05-29  9:35 ` [RFC 02/34] dmaengine: virt-dma: vchan_find_desc() Russell King
@ 2012-05-30  7:48   ` Linus Walleij
  0 siblings, 0 replies; 80+ messages in thread
From: Linus Walleij @ 2012-05-30  7:48 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, May 29, 2012 at 5:35 PM, Russell King
<rmk+kernel@arm.linux.org.uk> wrote:

> Add a function to find a descriptor within the depths of the
> virtualized DMA channel support. ?Needed for tx_status functionality.
>
> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

Acked-by: Linus Walleij <linus.walleij@linaro.org>

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 80+ messages in thread

* [RFC 03/34] dmaengine: virt-dma: add support for cyclic DMA periodic callbacks
  2012-05-29  9:36 ` [RFC 03/34] dmaengine: virt-dma: add support for cyclic DMA periodic callbacks Russell King
@ 2012-05-30  7:52   ` Linus Walleij
  2012-05-30  8:02     ` Russell King - ARM Linux
  0 siblings, 1 reply; 80+ messages in thread
From: Linus Walleij @ 2012-05-30  7:52 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, May 29, 2012 at 5:36 PM, Russell King
<rmk+kernel@arm.linux.org.uk> wrote:

> Add support for cyclic DMA's periodic callbacks. ?Drivers are expected
> to call vchan_cyclic_callback() when a period has completed, which will
> schedule the tasklet to make the callback into the driver.
>
> As callbacks are made from tasklet context, it is important to realise
> that we don't guarantee a callback for each completed period, but for
> N completed periods where N may be greater than one.

This last thing was something we have to fix right?
Like for each driver to keep a counter of completed periods
and call the handler repeatedly if N > 1.

Anyway this doesn't make the problem worse in any way so
Acked-by: Linus Walleij <linus.walleij@linaro.org>

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 80+ messages in thread

* [RFC 03/34] dmaengine: virt-dma: add support for cyclic DMA periodic callbacks
  2012-05-30  7:52   ` Linus Walleij
@ 2012-05-30  8:02     ` Russell King - ARM Linux
  2012-05-31  1:29       ` Linus Walleij
  2012-05-31  3:45       ` zhangfei gao
  0 siblings, 2 replies; 80+ messages in thread
From: Russell King - ARM Linux @ 2012-05-30  8:02 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, May 30, 2012 at 03:52:53PM +0800, Linus Walleij wrote:
> On Tue, May 29, 2012 at 5:36 PM, Russell King
> <rmk+kernel@arm.linux.org.uk> wrote:
> 
> > Add support for cyclic DMA's periodic callbacks. ?Drivers are expected
> > to call vchan_cyclic_callback() when a period has completed, which will
> > schedule the tasklet to make the callback into the driver.
> >
> > As callbacks are made from tasklet context, it is important to realise
> > that we don't guarantee a callback for each completed period, but for
> > N completed periods where N may be greater than one.
> 
> This last thing was something we have to fix right?
> Like for each driver to keep a counter of completed periods
> and call the handler repeatedly if N > 1.

No, I don't think we should do that - ALSA doesn't require it, and ALSA
is about the only user of this.  As I've said, DMA engine drivers should
implement a correct tx_status function, which returns the remaining bytes
to be transferred to the end of the buffer so it's possible to find out
how many periods have completed when the callback is called.

^ permalink raw reply	[flat|nested] 80+ messages in thread

* [RFC 04/34] dmaengine: PL08x: remove runtime PM support
  2012-05-29  9:36 ` [RFC 04/34] dmaengine: PL08x: remove runtime PM support Russell King
@ 2012-05-31  0:46   ` Linus Walleij
  2012-06-01 10:45     ` Russell King - ARM Linux
  0 siblings, 1 reply; 80+ messages in thread
From: Linus Walleij @ 2012-05-31  0:46 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, May 29, 2012 at 5:36 PM, Russell King
<rmk+kernel@arm.linux.org.uk> wrote:

> The runtime PM support conflicts with the generic AMBA bus PM, and also
> causes a potential deadlock with the PL011 driver as it results in
> interrupts being enabled beneath a spinlock.
>
> I don't presently see any solution to this other than by removing the
> runtime PM support entirely from the DMA engine driver. ?Alternative
> suggestions welcome.

I took a look again and cannot see any simple way to do this.

It basically looks like we need to have job submission put stuff
in a queue and kick a worker or kthread to have that do the
get_sync() operation and proceed to submit the descriptors,
lest we always run the risk of being in irq context.

Perfectly doable, but can be done at some other time.

So: Acked-by.

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 80+ messages in thread

* [RFC 05/34] dmaengine: PL08x: fix missed dma_transfer_direction fixup
  2012-05-29  9:36 ` [RFC 05/34] dmaengine: PL08x: fix missed dma_transfer_direction fixup Russell King
@ 2012-05-31  0:47   ` Linus Walleij
  2012-06-01 10:47     ` Russell King - ARM Linux
  0 siblings, 1 reply; 80+ messages in thread
From: Linus Walleij @ 2012-05-31  0:47 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, May 29, 2012 at 5:36 PM, Russell King
<rmk+kernel@arm.linux.org.uk> wrote:

> db8196df4 (dmaengine: move drivers to dma_transfer_direction) missed
> fixing up the "DMA_NONE" case.
>
> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

Looks like it should go into the -rc:s really?
Acked-by: Linus Walleij <linus.walleij@linaro.org>

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 80+ messages in thread

* [RFC 06/34] dmaengine: PL08x: remove redundant spinlock
  2012-05-29  9:37 ` [RFC 06/34] dmaengine: PL08x: remove redundant spinlock Russell King
@ 2012-05-31  0:48   ` Linus Walleij
  0 siblings, 0 replies; 80+ messages in thread
From: Linus Walleij @ 2012-05-31  0:48 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, May 29, 2012 at 5:37 PM, Russell King
<rmk+kernel@arm.linux.org.uk> wrote:

> The pl08x_driver_data spinlock is only ever initialized. ?Nothing else
> uses it. ?Let's get rid of it.
>
> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

This could also go into the -rc:s at this stage I believe.
Acked-by: Linus Walleij <linus.walleij@linaro.org>

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 80+ messages in thread

* [RFC 07/34] dmaengine: PL08x: remove circular_buffer boolean from channel data
  2012-05-29  9:37 ` [RFC 07/34] dmaengine: PL08x: remove circular_buffer boolean from channel data Russell King
@ 2012-05-31  0:49   ` Linus Walleij
  0 siblings, 0 replies; 80+ messages in thread
From: Linus Walleij @ 2012-05-31  0:49 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, May 29, 2012 at 5:37 PM, Russell King
<rmk+kernel@arm.linux.org.uk> wrote:

> Circular buffers are not handled in this way; we have a separate API
> call now to setup circular buffers. ?So lets not mislead people with
> this bool.
>
> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

Acked-by: Linus Walleij <linus.walleij@linaro.org>
Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 80+ messages in thread

* [RFC 08/34] dmaengine: PL08x: clean up get_signal/put_signal
  2012-05-29  9:37 ` [RFC 08/34] dmaengine: PL08x: clean up get_signal/put_signal Russell King
@ 2012-05-31  0:53   ` Linus Walleij
  2012-06-01 10:48     ` Russell King - ARM Linux
  0 siblings, 1 reply; 80+ messages in thread
From: Linus Walleij @ 2012-05-31  0:53 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, May 29, 2012 at 5:37 PM, Russell King
<rmk+kernel@arm.linux.org.uk> wrote:

> Try to avoid dereferencing the DMA engine's channel struct in these
> platform helpers; instead, pass a pointer to the channel data into
> get_signal(), and the returned signal number to put_signal().
>
> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

There is an in-tree user of this interface now, so it needs to be fixed
as part of this patch:
]$ grep -r pl080_get_signal .
./mach-spear6xx/spear6xx.c:	.get_signal = pl080_get_signal,
./plat-spear/include/plat/pl080.h:int pl080_get_signal(struct
pl08x_dma_chan *ch);
./plat-spear/pl080.c:int pl080_get_signal(struct pl08x_dma_chan *ch)
./mach-spear3xx/spear3xx.c:	.get_signal = pl080_get_signal,

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 80+ messages in thread

* [RFC 09/34] dmaengine: PL08x: move private data structures into amba-pl08x.c
  2012-05-29  9:38 ` [RFC 09/34] dmaengine: PL08x: move private data structures into amba-pl08x.c Russell King
@ 2012-05-31  0:54   ` Linus Walleij
  0 siblings, 0 replies; 80+ messages in thread
From: Linus Walleij @ 2012-05-31  0:54 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, May 29, 2012 at 5:38 PM, Russell King
<rmk+kernel@arm.linux.org.uk> wrote:

> Move the driver private data structures into the driver itself, rather
> than having them exposed to everyone in a header file.
>
> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

Acked-by: Linus Walleij <linus.walleij@linaro.org>

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 80+ messages in thread

* [RFC 10/34] dmaengine: PL08x: constify channel names and bus_id strings
  2012-05-29  9:38 ` [RFC 10/34] dmaengine: PL08x: constify channel names and bus_id strings Russell King
@ 2012-05-31  0:55   ` Linus Walleij
  0 siblings, 0 replies; 80+ messages in thread
From: Linus Walleij @ 2012-05-31  0:55 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, May 29, 2012 at 5:38 PM, Russell King
<rmk+kernel@arm.linux.org.uk> wrote:

> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

Acked-by: Linus Walleij <linus.walleij@linaro.org>

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 80+ messages in thread

* [RFC 11/34] dmaengine: PL08x: get src/dst addr direct from dma_slave_config struct
  2012-05-29  9:38 ` [RFC 11/34] dmaengine: PL08x: get src/dst addr direct from dma_slave_config struct Russell King
@ 2012-05-31  0:56   ` Linus Walleij
  0 siblings, 0 replies; 80+ messages in thread
From: Linus Walleij @ 2012-05-31  0:56 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, May 29, 2012 at 5:38 PM, Russell King
<rmk+kernel@arm.linux.org.uk> wrote:

> Add a dma_slave_config struct to struct pl08x_dma_chan, and move the
> src_addr/dst_addr arguments into this struct. ?This is a step away
> from using the dma_slave_config's direction member.
>
> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

Acked-by: Linus Walleij <linus.walleij@linaro.org>

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 80+ messages in thread

* [RFC 12/34] dmaengine: PL08x: get rid of device_fc in struct pl08x_dma_chan
  2012-05-29  9:39 ` [RFC 12/34] dmaengine: PL08x: get rid of device_fc in struct pl08x_dma_chan Russell King
@ 2012-05-31  0:57   ` Linus Walleij
  0 siblings, 0 replies; 80+ messages in thread
From: Linus Walleij @ 2012-05-31  0:57 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, May 29, 2012 at 5:39 PM, Russell King
<rmk+kernel@arm.linux.org.uk> wrote:

> As we now store the dma_slave_config in pl08x_dma_chan, we don't need
> to store this separately. ?Use the one in dma_slave_config directly.
>
> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

Acked-by: Linus Walleij <linus.walleij@linaro.org>

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 80+ messages in thread

* [RFC 13/34] dmaengine: PL08x: move the bus and increment selection to dma prepare function
  2012-05-29  9:39 ` [RFC 13/34] dmaengine: PL08x: move the bus and increment selection to dma prepare function Russell King
@ 2012-05-31  0:57   ` Linus Walleij
  0 siblings, 0 replies; 80+ messages in thread
From: Linus Walleij @ 2012-05-31  0:57 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, May 29, 2012 at 5:39 PM, Russell King
<rmk+kernel@arm.linux.org.uk> wrote:

> Move the bus and transfer increment selection to the DMA prepare
> function rather than the slave configuration function.
>
> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

Acked-by: Linus Walleij <linus.walleij@linaro.org>

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 80+ messages in thread

* [RFC 14/34] dmaengine: PL08x: extract function to to generate cctl values
  2012-05-29  9:39 ` [RFC 14/34] dmaengine: PL08x: extract function to to generate cctl values Russell King
@ 2012-05-31  1:00   ` Linus Walleij
  0 siblings, 0 replies; 80+ messages in thread
From: Linus Walleij @ 2012-05-31  1:00 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, May 29, 2012 at 5:39 PM, Russell King
<rmk+kernel@arm.linux.org.uk> wrote:

> Extract the functionality from dma_slave_config to generate the cctl
> values for a given bus width and burst size. ?This allows us to use
> this elsewhere in the driver, namely the prepare functions.
>
> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

Acked-by: Linus Walleij <linus.walleij@linaro.org>

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 80+ messages in thread

* [RFC 15/34] dmaengine: PL08x: ignore 'direction' argument in dma_slave_config
  2012-05-29  9:40 ` [RFC 15/34] dmaengine: PL08x: ignore 'direction' argument in dma_slave_config Russell King
@ 2012-05-31  1:01   ` Linus Walleij
  0 siblings, 0 replies; 80+ messages in thread
From: Linus Walleij @ 2012-05-31  1:01 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, May 29, 2012 at 5:40 PM, Russell King
<rmk+kernel@arm.linux.org.uk> wrote:

> Ignore the direction argument in dma_slave_config, and configure both
> directions independently. ?We still check that the configuration for
> the intended direction is valid; this check will eventually be dropped.
> This check is just for debugging at present.
>
> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

Acked-by: Linus Walleij <linus.walleij@linaro.org>

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 80+ messages in thread

* [RFC 16/34] dmaengine: PL08x: get rid of unnecessary checks in dma_slave_config
  2012-05-29  9:40 ` [RFC 16/34] dmaengine: PL08x: get rid of unnecessary checks " Russell King
@ 2012-05-31  1:02   ` Linus Walleij
  0 siblings, 0 replies; 80+ messages in thread
From: Linus Walleij @ 2012-05-31  1:02 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, May 29, 2012 at 5:40 PM, Russell King
<rmk+kernel@arm.linux.org.uk> wrote:

> Get rid of the unnecessary checks in dma_slave_config utilizing
> the DMA direction. ?This allows us to move the computation of
> cctl to the prepare function.
>
> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

Acked-by: Linus Walleij <linus.walleij@linaro.org>

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 80+ messages in thread

* [RFC 17/34] dmaengine: PL08x: split DMA signal muxing from channel alloc
  2012-05-29  9:40 ` [RFC 17/34] dmaengine: PL08x: split DMA signal muxing from channel alloc Russell King
@ 2012-05-31  1:03   ` Linus Walleij
  0 siblings, 0 replies; 80+ messages in thread
From: Linus Walleij @ 2012-05-31  1:03 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, May 29, 2012 at 5:40 PM, Russell King
<rmk+kernel@arm.linux.org.uk> wrote:

> Split the DMA request mux signal handling from the physical channel
> allocation code. ?The physical channel has very little to do with the
> DMA request input which will be used, so these should be two separate
> operations.
>
> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

Acked-by: Linus Walleij <linus.walleij@linaro.org>

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 80+ messages in thread

* [RFC 18/34] dmaengine: PL08x: move DMA signal muxing into pl08x_dma_chan struct
  2012-05-29  9:41 ` [RFC 18/34] dmaengine: PL08x: move DMA signal muxing into pl08x_dma_chan struct Russell King
@ 2012-05-31  1:03   ` Linus Walleij
  0 siblings, 0 replies; 80+ messages in thread
From: Linus Walleij @ 2012-05-31  1:03 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, May 29, 2012 at 5:41 PM, Russell King
<rmk+kernel@arm.linux.org.uk> wrote:

> Move the signal handling out of the physical channel structure into
> the virtual channel structure, where it should belong as it has more
> to do with the virtual channel than the physical one.
>
> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

Acked-by: Linus Walleij <linus.walleij@linaro.org>

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 80+ messages in thread

* [RFC 19/34] dmaengine: PL08x: track mux usage on a per-channel basis.
  2012-05-29  9:41 ` [RFC 19/34] dmaengine: PL08x: track mux usage on a per-channel basis Russell King
@ 2012-05-31  1:04   ` Linus Walleij
  0 siblings, 0 replies; 80+ messages in thread
From: Linus Walleij @ 2012-05-31  1:04 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, May 29, 2012 at 5:41 PM, Russell King
<rmk+kernel@arm.linux.org.uk> wrote:

> Keep track of the number of descriptors currently using a MUX setting
> on a per-channel basis. ?This allows us to know when we have descriptors
> queued somewhere which have been assigned a DMA request signal.
>
> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

Acked-by: Linus Walleij <linus.walleij@linaro.org>

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 80+ messages in thread

* [RFC 20/34] dmaengine: PL08x: convert to a list of completed descriptors
  2012-05-29  9:42 ` [RFC 20/34] dmaengine: PL08x: convert to a list of completed descriptors Russell King
@ 2012-05-31  1:04   ` Linus Walleij
  0 siblings, 0 replies; 80+ messages in thread
From: Linus Walleij @ 2012-05-31  1:04 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, May 29, 2012 at 5:42 PM, Russell King
<rmk+kernel@arm.linux.org.uk> wrote:

> Convert PL08x to use a list of completed descriptors rather than
> merely relying upon a single pointer. ?This makes it possible to
> schedule the tasklet for other purposes, and makes our behaviour
> similar to virt-dma.
>
> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

Acked-by: Linus Walleij <linus.walleij@linaro.org>

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 80+ messages in thread

* [RFC 21/34] dmaengine: PL08x: move DMA signal muxing into slave prepare code
  2012-05-29  9:42 ` [RFC 21/34] dmaengine: PL08x: move DMA signal muxing into slave prepare code Russell King
@ 2012-05-31  1:11   ` Linus Walleij
  0 siblings, 0 replies; 80+ messages in thread
From: Linus Walleij @ 2012-05-31  1:11 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, May 29, 2012 at 5:42 PM, Russell King
<rmk+kernel@arm.linux.org.uk> wrote:

> Move the DMA request muxing into the slave prepare code and txd
> release/completion code. ?This means we only hold the DMA request
> mux while there are descriptors waiting to be started or are in
> progress.
>
> This leaves txd->direction as a write-only variable; remove it.
>
> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

Acked-by: Linus Walleij <linus.walleij@linaro.org>

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 80+ messages in thread

* [RFC 22/34] dmaengine: PL08x: remove waiting descriptor pointer
  2012-05-29  9:42 ` [RFC 22/34] dmaengine: PL08x: remove waiting descriptor pointer Russell King
@ 2012-05-31  1:11   ` Linus Walleij
  0 siblings, 0 replies; 80+ messages in thread
From: Linus Walleij @ 2012-05-31  1:11 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, May 29, 2012 at 5:42 PM, Russell King
<rmk+kernel@arm.linux.org.uk> wrote:

> As we no longer need to pass a descriptor to prep_phy_channel(), we
> don't need to keep track of the descriptor which is waiting for a
> channel to become available. ?So let's get rid of it.
>
> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

Acked-by: Linus Walleij <linus.walleij@linaro.org>

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 80+ messages in thread

* [RFC 23/34] dmaengine: PL08x: re-jig the starting of txds
  2012-05-29  9:43 ` [RFC 23/34] dmaengine: PL08x: re-jig the starting of txds Russell King
@ 2012-05-31  1:14   ` Linus Walleij
  2012-06-01 10:52     ` Russell King - ARM Linux
  0 siblings, 1 reply; 80+ messages in thread
From: Linus Walleij @ 2012-05-31  1:14 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, May 29, 2012 at 5:43 PM, Russell King
<rmk+kernel@arm.linux.org.uk> wrote:

> Rather than code the de-queue of the txd several times, move that into
> the start_txd function. ?Rename this to better illustrate what it's
> now doing, and call this function when starting a delayed memcpy().
>
> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? /*
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?* Eww. ?We know this isn't going to deadlock
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?* but lockdep probably doens't.

Speling...

> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?*/
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? spin_lock(&waiting->lock);
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? pl08x_start_next_txd(waiting);
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? spin_unlock(&waiting->lock);

I've seen this construct in the past and have no better suggestions...

Acked-by: Linus Walleij <linus.walleij@linaro.org>

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 80+ messages in thread

* [RFC 24/34] dmaengine: PL08x: split the pend_list in two
  2012-05-29  9:43 ` [RFC 24/34] dmaengine: PL08x: split the pend_list in two Russell King
@ 2012-05-31  1:20   ` Linus Walleij
  0 siblings, 0 replies; 80+ messages in thread
From: Linus Walleij @ 2012-05-31  1:20 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, May 29, 2012 at 5:43 PM, Russell King
<rmk+kernel@arm.linux.org.uk> wrote:

> Our behaviour wasn't correct; issue_pending is supposed to be called
> before any submitted descriptors are available for processing by the
> DMA engine. ?Split the pend_list in two, one for submitted descriptors
> and another list for issued descriptors.
>
> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

I suspect many DMAengine drivers get this wrong, or rather, they merge the
semantics for submitted/issued like this driver used to do.

Dan, please check this, we might need to notify a few driver maintainers to
look at this and add TODO:s to their driver files.

Acked-by: Linus Walleij <linus.walleij@linaro.org>

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 80+ messages in thread

* [RFC 25/34] dmaengine: PL08x: start next descriptor from irq context
  2012-05-29  9:43 ` [RFC 25/34] dmaengine: PL08x: start next descriptor from irq context Russell King
@ 2012-05-31  1:21   ` Linus Walleij
  0 siblings, 0 replies; 80+ messages in thread
From: Linus Walleij @ 2012-05-31  1:21 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, May 29, 2012 at 5:43 PM, Russell King
<rmk+kernel@arm.linux.org.uk> wrote:

> Rather than waiting for the tasklet to run, we can start the next
> descriptor from interrupt context, as soon as we know that the
> previous descriptor has completed.
>
> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

Quicker and more elegant,
Acked-by: Linus Walleij <linus.walleij@linaro.org>

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 80+ messages in thread

* [RFC 26/34] dmaengine: PL08x: rejig physical channel allocation
  2012-05-29  9:44 ` [RFC 26/34] dmaengine: PL08x: rejig physical channel allocation Russell King
@ 2012-05-31  1:23   ` Linus Walleij
  0 siblings, 0 replies; 80+ messages in thread
From: Linus Walleij @ 2012-05-31  1:23 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, May 29, 2012 at 5:44 PM, Russell King
<rmk+kernel@arm.linux.org.uk> wrote:

> Rework the physical channel allocation mechanism to only allocate
> physical channels to virtual channels when they're about to be used.
> This eliminates all the complexity with holding channels while
> descriptors are being prepared, which is completely unnecessary.
>
> This also brings this driver to a state where the generic virtual DMA
> code can be used with this driver, and opens up the possibility of
> properly scheduling and prioritorising physical DMA channels to
> virtual DMA channels.
>
> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

Acked-by: Linus Walleij <linus.walleij@linaro.org>

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 80+ messages in thread

* [RFC 27/34] dmaengine: PL08x: convert to use virt-dma structs
  2012-05-29  9:44 ` [RFC 27/34] dmaengine: PL08x: convert to use virt-dma structs Russell King
@ 2012-05-31  1:23   ` Linus Walleij
  0 siblings, 0 replies; 80+ messages in thread
From: Linus Walleij @ 2012-05-31  1:23 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, May 29, 2012 at 5:44 PM, Russell King
<rmk+kernel@arm.linux.org.uk> wrote:

> Convert PL08x to use the virt-dma structures.
>
> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

Acked-by: Linus Walleij <linus.walleij@linaro.org>

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 80+ messages in thread

* [RFC 28/34] dmaengine: PL08x: use vchan's spinlock
  2012-05-29  9:44 ` [RFC 28/34] dmaengine: PL08x: use vchan's spinlock Russell King
@ 2012-05-31  1:24   ` Linus Walleij
  0 siblings, 0 replies; 80+ messages in thread
From: Linus Walleij @ 2012-05-31  1:24 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, May 29, 2012 at 5:44 PM, Russell King
<rmk+kernel@arm.linux.org.uk> wrote:

> Initialize the vchan struct, and use the provided spinlock rather than
> our own.
>
> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

Acked-by: Linus Walleij <linus.walleij@linaro.org>

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 80+ messages in thread

* [RFC 29/34] dmaengine: PL08x: convert to use vchan submitted/issued lists
  2012-05-29  9:45 ` [RFC 29/34] dmaengine: PL08x: convert to use vchan submitted/issued lists Russell King
@ 2012-05-31  1:24   ` Linus Walleij
  0 siblings, 0 replies; 80+ messages in thread
From: Linus Walleij @ 2012-05-31  1:24 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, May 29, 2012 at 5:45 PM, Russell King
<rmk+kernel@arm.linux.org.uk> wrote:

> Convert to use the virtual dma channel submitted/issued descriptor
> lists rather than our own private lists, and use the virtual dma
> channel support functions to manage these lists.
>
> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

Acked-by: Linus Walleij <linus.walleij@linaro.org>

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 80+ messages in thread

* [RFC 30/34] dmaengine: PL08x: convert to use vchan done list
  2012-05-29  9:45 ` [RFC 30/34] dmaengine: PL08x: convert to use vchan done list Russell King
@ 2012-05-31  1:24   ` Linus Walleij
  0 siblings, 0 replies; 80+ messages in thread
From: Linus Walleij @ 2012-05-31  1:24 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, May 29, 2012 at 5:45 PM, Russell King
<rmk+kernel@arm.linux.org.uk> wrote:

> Convert to use the virtual dma channel done list, tasklet, and
> descriptor freeing.
>
> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

Acked-by: Linus Walleij <linus.walleij@linaro.org>

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 80+ messages in thread

* [RFC 31/34] dmaengine: PL08x: fix tx_status function to return correct residue
  2012-05-29  9:45 ` [RFC 31/34] dmaengine: PL08x: fix tx_status function to return correct residue Russell King
@ 2012-05-31  1:25   ` Linus Walleij
  0 siblings, 0 replies; 80+ messages in thread
From: Linus Walleij @ 2012-05-31  1:25 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, May 29, 2012 at 5:45 PM, Russell King
<rmk+kernel@arm.linux.org.uk> wrote:

> Now that we're converted to use the generic vchan support, we can fix
> the residue return from tx_status to be compliant with dmaengine. ?This
> returns the number of bytes remaining for the _specified_ cookie, not
> the number of bytes in all pending transfers on the channel.
>
> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

Acked-by: Linus Walleij <linus.walleij@linaro.org>

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 80+ messages in thread

* [RFC 32/34] dmaengine: PL08x: get rid of pl08x_prep_channel_resources
  2012-05-29  9:46 ` [RFC 32/34] dmaengine: PL08x: get rid of pl08x_prep_channel_resources Russell King
@ 2012-05-31  1:25   ` Linus Walleij
  0 siblings, 0 replies; 80+ messages in thread
From: Linus Walleij @ 2012-05-31  1:25 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, May 29, 2012 at 5:46 PM, Russell King
<rmk+kernel@arm.linux.org.uk> wrote:

> This function is now unnecessary; we can move its internals inline
> instead.
>
> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

Acked-by: Linus Walleij <linus.walleij@linaro.org>

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 80+ messages in thread

* [RFC 33/34] dmaengine: PL08x: get rid of write only pool_ctr and free_txd locking
  2012-05-29  9:46 ` [RFC 33/34] dmaengine: PL08x: get rid of write only pool_ctr and free_txd locking Russell King
@ 2012-05-31  1:26   ` Linus Walleij
  0 siblings, 0 replies; 80+ messages in thread
From: Linus Walleij @ 2012-05-31  1:26 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, May 29, 2012 at 5:46 PM, Russell King
<rmk+kernel@arm.linux.org.uk> wrote:

> The free function says the pl08x lock should be taken before calling
> it. ?However, the DMA pool allocation/freeing is already properly
> locked. ?The only thing that would need this is pool_ctr, which
> happens to be a write-only variable.
>
> Let's get rid of this, and eliminate any need for additional locking
> here.
>
> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

Acked-by: Linus Walleij <linus.walleij@linaro.org>

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 80+ messages in thread

* [RFC 34/34] dmaengine: PL08x: ensure all descriptors are freed when channel is released
  2012-05-29  9:46 ` [RFC 34/34] dmaengine: PL08x: ensure all descriptors are freed when channel is released Russell King
@ 2012-05-31  1:27   ` Linus Walleij
  2012-06-01 10:55     ` Russell King - ARM Linux
  0 siblings, 1 reply; 80+ messages in thread
From: Linus Walleij @ 2012-05-31  1:27 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, May 29, 2012 at 5:46 PM, Russell King
<rmk+kernel@arm.linux.org.uk> wrote:

> Ensure all queued descriptors are freed when the channel is released,
> ensuring we don't leak memory
>
> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

Excellent series Russell, looking forward to a version that
applies on top of v3.5-rc:s and I'll test it. Would be great to get
this into the -next tree as soon as you think it's ripe.

Acked-by: Linus Walleij <linus.walleij@linaro.org>

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 80+ messages in thread

* [RFC 03/34] dmaengine: virt-dma: add support for cyclic DMA periodic callbacks
  2012-05-30  8:02     ` Russell King - ARM Linux
@ 2012-05-31  1:29       ` Linus Walleij
  2012-05-31  3:45       ` zhangfei gao
  1 sibling, 0 replies; 80+ messages in thread
From: Linus Walleij @ 2012-05-31  1:29 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, May 30, 2012 at 4:02 PM, Russell King - ARM Linux
<linux@arm.linux.org.uk> wrote:
> On Wed, May 30, 2012 at 03:52:53PM +0800, Linus Walleij wrote:
>>
>> This last thing was something we have to fix right?
>> Like for each driver to keep a counter of completed periods
>> and call the handler repeatedly if N > 1.
>
> No, I don't think we should do that - ALSA doesn't require it, and ALSA
> is about the only user of this.

OK then there won't be any problems, let's go ahead with this.

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 80+ messages in thread

* [RFC 03/34] dmaengine: virt-dma: add support for cyclic DMA periodic callbacks
  2012-05-30  8:02     ` Russell King - ARM Linux
  2012-05-31  1:29       ` Linus Walleij
@ 2012-05-31  3:45       ` zhangfei gao
  2012-05-31 19:17         ` Russell King - ARM Linux
  1 sibling, 1 reply; 80+ messages in thread
From: zhangfei gao @ 2012-05-31  3:45 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, May 30, 2012 at 4:02 PM, Russell King - ARM Linux
<linux@arm.linux.org.uk> wrote:
> On Wed, May 30, 2012 at 03:52:53PM +0800, Linus Walleij wrote:
>> On Tue, May 29, 2012 at 5:36 PM, Russell King
>> <rmk+kernel@arm.linux.org.uk> wrote:
>>
>> > Add support for cyclic DMA's periodic callbacks. ?Drivers are expected
>> > to call vchan_cyclic_callback() when a period has completed, which will
>> > schedule the tasklet to make the callback into the driver.
>> >
>> > As callbacks are made from tasklet context, it is important to realise
>> > that we don't guarantee a callback for each completed period, but for
>> > N completed periods where N may be greater than one.
>>
>> This last thing was something we have to fix right?
>> Like for each driver to keep a counter of completed periods
>> and call the handler repeatedly if N > 1.
>
> No, I don't think we should do that - ALSA doesn't require it, and ALSA
> is about the only user of this. ?As I've said, DMA engine drivers should
> implement a correct tx_status function, which returns the remaining bytes
> to be transferred to the end of the buffer so it's possible to find out
> how many periods have completed when the callback is called.

Could we directly use pos, but unmatch with dma_tx_state.residue.
For cyclic buffer, when pos reach to buffer size, pos will change to 0,
remaining bytes also 0, we may have to distinguish them.

^ permalink raw reply	[flat|nested] 80+ messages in thread

* [RFC 03/34] dmaengine: virt-dma: add support for cyclic DMA periodic callbacks
  2012-05-31  3:45       ` zhangfei gao
@ 2012-05-31 19:17         ` Russell King - ARM Linux
  2012-06-01  2:26           ` zhangfei gao
  0 siblings, 1 reply; 80+ messages in thread
From: Russell King - ARM Linux @ 2012-05-31 19:17 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, May 31, 2012 at 11:45:54AM +0800, zhangfei gao wrote:
> On Wed, May 30, 2012 at 4:02 PM, Russell King - ARM Linux
> <linux@arm.linux.org.uk> wrote:
> > On Wed, May 30, 2012 at 03:52:53PM +0800, Linus Walleij wrote:
> > No, I don't think we should do that - ALSA doesn't require it, and ALSA
> > is about the only user of this. ?As I've said, DMA engine drivers should
> > implement a correct tx_status function, which returns the remaining bytes
> > to be transferred to the end of the buffer so it's possible to find out
> > how many periods have completed when the callback is called.
> 
> Could we directly use pos, but unmatch with dma_tx_state.residue.
> For cyclic buffer, when pos reach to buffer size, pos will change to 0,
> remaining bytes also 0, we may have to distinguish them.

What pos?

The way I said above, you work out how many periods have expired by
using dma_tx_state.residue.  This tells you how many bytes are left to
transfer until the _end_ of the looped buffer.

>From that, you can tell directly how many periods have expired.

Really, ALSA is not interested in "how many periods have expired" but
is really after a regular update of where DMA is _now_, so it knows
how many bytes it can write into or read from the circular buffer.  It
really doesn't need to know that N periods have expired _if_ you're
capable of telling it exactly where the DMA is in the buffer.

And with a working dma_tx_state.residue, you can do exactly that.

^ permalink raw reply	[flat|nested] 80+ messages in thread

* [RFC 03/34] dmaengine: virt-dma: add support for cyclic DMA periodic callbacks
  2012-05-31 19:17         ` Russell King - ARM Linux
@ 2012-06-01  2:26           ` zhangfei gao
  2012-06-01 10:39             ` Russell King - ARM Linux
  0 siblings, 1 reply; 80+ messages in thread
From: zhangfei gao @ 2012-06-01  2:26 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Jun 1, 2012 at 3:17 AM, Russell King - ARM Linux
<linux@arm.linux.org.uk> wrote:
> On Thu, May 31, 2012 at 11:45:54AM +0800, zhangfei gao wrote:
>> On Wed, May 30, 2012 at 4:02 PM, Russell King - ARM Linux
>> <linux@arm.linux.org.uk> wrote:
>> > On Wed, May 30, 2012 at 03:52:53PM +0800, Linus Walleij wrote:
>> > No, I don't think we should do that - ALSA doesn't require it, and ALSA
>> > is about the only user of this. ?As I've said, DMA engine drivers should
>> > implement a correct tx_status function, which returns the remaining bytes
>> > to be transferred to the end of the buffer so it's possible to find out
>> > how many periods have completed when the callback is called.
>>
>> Could we directly use pos, but unmatch with dma_tx_state.residue.
>> For cyclic buffer, when pos reach to buffer size, pos will change to 0,
>> remaining bytes also 0, we may have to distinguish them.
>
> What pos?
>
> The way I said above, you work out how many periods have expired by
> using dma_tx_state.residue. ?This tells you how many bytes are left to
> transfer until the _end_ of the looped buffer.
>
> From that, you can tell directly how many periods have expired.
>
> Really, ALSA is not interested in "how many periods have expired" but
> is really after a regular update of where DMA is _now_, so it knows
> how many bytes it can write into or read from the circular buffer. ?It
> really doesn't need to know that N periods have expired _if_ you're
> capable of telling it exactly where the DMA is in the buffer.
>
> And with a working dma_tx_state.residue, you can do exactly that.

Thanks a lot.
Could we directly treat dma_tx_state.residue as "how many periods have expired"
or exactly where the DMA is in the buffer.
But the @residue: the remaining number of bytes left.
So if we set residue as remaining bytes,
dma driver: set residue = buf_len - expired bytes (position).
alsa driver: get expired bytes (position) = buf_len - residue.
But it is not a big deal.

^ permalink raw reply	[flat|nested] 80+ messages in thread

* [RFC 03/34] dmaengine: virt-dma: add support for cyclic DMA periodic callbacks
  2012-06-01  2:26           ` zhangfei gao
@ 2012-06-01 10:39             ` Russell King - ARM Linux
  0 siblings, 0 replies; 80+ messages in thread
From: Russell King - ARM Linux @ 2012-06-01 10:39 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Jun 01, 2012 at 10:26:37AM +0800, zhangfei gao wrote:
> Could we directly treat dma_tx_state.residue as "how many periods have expired"

Why change the behaviour and add complexity to _both_ sides of the API,
as well as confusion about what "residue" means?

^ permalink raw reply	[flat|nested] 80+ messages in thread

* [RFC 04/34] dmaengine: PL08x: remove runtime PM support
  2012-05-31  0:46   ` Linus Walleij
@ 2012-06-01 10:45     ` Russell King - ARM Linux
  0 siblings, 0 replies; 80+ messages in thread
From: Russell King - ARM Linux @ 2012-06-01 10:45 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, May 31, 2012 at 08:46:28AM +0800, Linus Walleij wrote:
> On Tue, May 29, 2012 at 5:36 PM, Russell King
> <rmk+kernel@arm.linux.org.uk> wrote:
> 
> > The runtime PM support conflicts with the generic AMBA bus PM, and also
> > causes a potential deadlock with the PL011 driver as it results in
> > interrupts being enabled beneath a spinlock.
> >
> > I don't presently see any solution to this other than by removing the
> > runtime PM support entirely from the DMA engine driver. ?Alternative
> > suggestions welcome.
> 
> I took a look again and cannot see any simple way to do this.
> 
> It basically looks like we need to have job submission put stuff
> in a queue and kick a worker or kthread to have that do the
> get_sync() operation and proceed to submit the descriptors,
> lest we always run the risk of being in irq context.
> 
> Perfectly doable, but can be done at some other time.

It becomes a lot easier towards the end of this series where we end up
separating the completion tasklet from the general management of the
DMA engine (through use of the virt-dma stuff.)

However, please realise that a lot of these problems aren't specific to
one DMA engine implementation, so we _really_ should be thinking about
how to provide libraries for DMA engine implementations to use.

^ permalink raw reply	[flat|nested] 80+ messages in thread

* [RFC 05/34] dmaengine: PL08x: fix missed dma_transfer_direction fixup
  2012-05-31  0:47   ` Linus Walleij
@ 2012-06-01 10:47     ` Russell King - ARM Linux
  0 siblings, 0 replies; 80+ messages in thread
From: Russell King - ARM Linux @ 2012-06-01 10:47 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, May 31, 2012 at 08:47:30AM +0800, Linus Walleij wrote:
> On Tue, May 29, 2012 at 5:36 PM, Russell King
> <rmk+kernel@arm.linux.org.uk> wrote:
> 
> > db8196df4 (dmaengine: move drivers to dma_transfer_direction) missed
> > fixing up the "DMA_NONE" case.
> >
> > Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
> 
> Looks like it should go into the -rc:s really?
> Acked-by: Linus Walleij <linus.walleij@linaro.org>

I don't think it's a big problem, the two enums resolve to the same
value.  It's just that it would be nice for folk who decide to change
stuff to actually check their changes better, so we didn't end up with
additional churn.

^ permalink raw reply	[flat|nested] 80+ messages in thread

* [RFC 08/34] dmaengine: PL08x: clean up get_signal/put_signal
  2012-05-31  0:53   ` Linus Walleij
@ 2012-06-01 10:48     ` Russell King - ARM Linux
  0 siblings, 0 replies; 80+ messages in thread
From: Russell King - ARM Linux @ 2012-06-01 10:48 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, May 31, 2012 at 08:53:33AM +0800, Linus Walleij wrote:
> On Tue, May 29, 2012 at 5:37 PM, Russell King
> <rmk+kernel@arm.linux.org.uk> wrote:
> 
> > Try to avoid dereferencing the DMA engine's channel struct in these
> > platform helpers; instead, pass a pointer to the channel data into
> > get_signal(), and the returned signal number to put_signal().
> >
> > Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
> 
> There is an in-tree user of this interface now, so it needs to be fixed
> as part of this patch:
> ]$ grep -r pl080_get_signal .
> ./mach-spear6xx/spear6xx.c:	.get_signal = pl080_get_signal,
> ./plat-spear/include/plat/pl080.h:int pl080_get_signal(struct
> pl08x_dma_chan *ch);
> ./plat-spear/pl080.c:int pl080_get_signal(struct pl08x_dma_chan *ch)
> ./mach-spear3xx/spear3xx.c:	.get_signal = pl080_get_signal,

I can't do that at the moment because that's come in during this merge
window and these patches are based on v3.4 at the moment.  In other
words, for the purposes of this series, the above simply does not exist.

^ permalink raw reply	[flat|nested] 80+ messages in thread

* [RFC 23/34] dmaengine: PL08x: re-jig the starting of txds
  2012-05-31  1:14   ` Linus Walleij
@ 2012-06-01 10:52     ` Russell King - ARM Linux
  2012-06-04 15:54       ` Linus Walleij
  0 siblings, 1 reply; 80+ messages in thread
From: Russell King - ARM Linux @ 2012-06-01 10:52 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, May 31, 2012 at 09:14:15AM +0800, Linus Walleij wrote:
> On Tue, May 29, 2012 at 5:43 PM, Russell King
> <rmk+kernel@arm.linux.org.uk> wrote:
> 
> > Rather than code the de-queue of the txd several times, move that into
> > the start_txd function. ?Rename this to better illustrate what it's
> > now doing, and call this function when starting a delayed memcpy().
> >
> > Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
> 
> > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? /*
> > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?* Eww. ?We know this isn't going to deadlock
> > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?* but lockdep probably doens't.
> 
> Speling...
> 
> > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?*/
> > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? spin_lock(&waiting->lock);
> > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? pl08x_start_next_txd(waiting);
> > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? spin_unlock(&waiting->lock);
> 
> I've seen this construct in the past and have no better suggestions...

I have no way to test whether my statement is true as I can't get enough
DMA engine usage through the PL011 transmit support to check what happens.
So the statement is purely theoretical.

> Acked-by: Linus Walleij <linus.walleij@linaro.org>
> 
> Yours,
> Linus Walleij
> 

^ permalink raw reply	[flat|nested] 80+ messages in thread

* [RFC 34/34] dmaengine: PL08x: ensure all descriptors are freed when channel is released
  2012-05-31  1:27   ` Linus Walleij
@ 2012-06-01 10:55     ` Russell King - ARM Linux
  0 siblings, 0 replies; 80+ messages in thread
From: Russell King - ARM Linux @ 2012-06-01 10:55 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, May 31, 2012 at 09:27:55AM +0800, Linus Walleij wrote:
> On Tue, May 29, 2012 at 5:46 PM, Russell King
> <rmk+kernel@arm.linux.org.uk> wrote:
> 
> > Ensure all queued descriptors are freed when the channel is released,
> > ensuring we don't leak memory
> >
> > Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
> 
> Excellent series Russell, looking forward to a version that
> applies on top of v3.5-rc:s and I'll test it. Would be great to get
> this into the -next tree as soon as you think it's ripe.
> 
> Acked-by: Linus Walleij <linus.walleij@linaro.org>

Note that I have four additional patches on top of this which I didn't
post, which I've kept up to date - two of them add the Versatile and
Realview support, though I've kept them in a slightly messy state to
work around some of the brokenness on the hardware I've experienced
(mostly just commenting out various bits of the DMA data for various
drivers.)

^ permalink raw reply	[flat|nested] 80+ messages in thread

* [RFC 23/34] dmaengine: PL08x: re-jig the starting of txds
  2012-06-01 10:52     ` Russell King - ARM Linux
@ 2012-06-04 15:54       ` Linus Walleij
  0 siblings, 0 replies; 80+ messages in thread
From: Linus Walleij @ 2012-06-04 15:54 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Jun 1, 2012 at 12:52 PM, Russell King - ARM Linux
<linux@arm.linux.org.uk> wrote:
> [Me]
>> > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?*/
>> > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? spin_lock(&waiting->lock);
>> > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? pl08x_start_next_txd(waiting);
>> > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? spin_unlock(&waiting->lock);
>>
>> I've seen this construct in the past and have no better suggestions...
>
> I have no way to test whether my statement is true as I can't get enough
> DMA engine usage through the PL011 transmit support to check what happens.
> So the statement is purely theoretical.

Doesn't memcpy work on the Versatile?

What I did to stress the PB11MPcore was to compile in the DMAengine
test client and torture the DMAC with a bunch of parallell memcpy()
threads causing it to fail channel allocation and other nasty stuff,
then put the console on DMA and pour a lot of text in and out of the
console on top of that.

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 80+ messages in thread

end of thread, other threads:[~2012-06-04 15:54 UTC | newest]

Thread overview: 80+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-05-29  9:30 [RFC 00/34] PL08x DMA conversion to virt-dma Russell King - ARM Linux
2012-05-29  9:35 ` [RFC 01/34] dmaengine: split out virtual channel DMA support from sa11x0 driver Russell King
2012-05-29  9:35 ` [RFC 02/34] dmaengine: virt-dma: vchan_find_desc() Russell King
2012-05-30  7:48   ` Linus Walleij
2012-05-29  9:36 ` [RFC 03/34] dmaengine: virt-dma: add support for cyclic DMA periodic callbacks Russell King
2012-05-30  7:52   ` Linus Walleij
2012-05-30  8:02     ` Russell King - ARM Linux
2012-05-31  1:29       ` Linus Walleij
2012-05-31  3:45       ` zhangfei gao
2012-05-31 19:17         ` Russell King - ARM Linux
2012-06-01  2:26           ` zhangfei gao
2012-06-01 10:39             ` Russell King - ARM Linux
2012-05-29  9:36 ` [RFC 04/34] dmaengine: PL08x: remove runtime PM support Russell King
2012-05-31  0:46   ` Linus Walleij
2012-06-01 10:45     ` Russell King - ARM Linux
2012-05-29  9:36 ` [RFC 05/34] dmaengine: PL08x: fix missed dma_transfer_direction fixup Russell King
2012-05-31  0:47   ` Linus Walleij
2012-06-01 10:47     ` Russell King - ARM Linux
2012-05-29  9:37 ` [RFC 06/34] dmaengine: PL08x: remove redundant spinlock Russell King
2012-05-31  0:48   ` Linus Walleij
2012-05-29  9:37 ` [RFC 07/34] dmaengine: PL08x: remove circular_buffer boolean from channel data Russell King
2012-05-31  0:49   ` Linus Walleij
2012-05-29  9:37 ` [RFC 08/34] dmaengine: PL08x: clean up get_signal/put_signal Russell King
2012-05-31  0:53   ` Linus Walleij
2012-06-01 10:48     ` Russell King - ARM Linux
2012-05-29  9:38 ` [RFC 09/34] dmaengine: PL08x: move private data structures into amba-pl08x.c Russell King
2012-05-31  0:54   ` Linus Walleij
2012-05-29  9:38 ` [RFC 10/34] dmaengine: PL08x: constify channel names and bus_id strings Russell King
2012-05-31  0:55   ` Linus Walleij
2012-05-29  9:38 ` [RFC 11/34] dmaengine: PL08x: get src/dst addr direct from dma_slave_config struct Russell King
2012-05-31  0:56   ` Linus Walleij
2012-05-29  9:39 ` [RFC 12/34] dmaengine: PL08x: get rid of device_fc in struct pl08x_dma_chan Russell King
2012-05-31  0:57   ` Linus Walleij
2012-05-29  9:39 ` [RFC 13/34] dmaengine: PL08x: move the bus and increment selection to dma prepare function Russell King
2012-05-31  0:57   ` Linus Walleij
2012-05-29  9:39 ` [RFC 14/34] dmaengine: PL08x: extract function to to generate cctl values Russell King
2012-05-31  1:00   ` Linus Walleij
2012-05-29  9:40 ` [RFC 15/34] dmaengine: PL08x: ignore 'direction' argument in dma_slave_config Russell King
2012-05-31  1:01   ` Linus Walleij
2012-05-29  9:40 ` [RFC 16/34] dmaengine: PL08x: get rid of unnecessary checks " Russell King
2012-05-31  1:02   ` Linus Walleij
2012-05-29  9:40 ` [RFC 17/34] dmaengine: PL08x: split DMA signal muxing from channel alloc Russell King
2012-05-31  1:03   ` Linus Walleij
2012-05-29  9:41 ` [RFC 18/34] dmaengine: PL08x: move DMA signal muxing into pl08x_dma_chan struct Russell King
2012-05-31  1:03   ` Linus Walleij
2012-05-29  9:41 ` [RFC 19/34] dmaengine: PL08x: track mux usage on a per-channel basis Russell King
2012-05-31  1:04   ` Linus Walleij
2012-05-29  9:42 ` [RFC 20/34] dmaengine: PL08x: convert to a list of completed descriptors Russell King
2012-05-31  1:04   ` Linus Walleij
2012-05-29  9:42 ` [RFC 21/34] dmaengine: PL08x: move DMA signal muxing into slave prepare code Russell King
2012-05-31  1:11   ` Linus Walleij
2012-05-29  9:42 ` [RFC 22/34] dmaengine: PL08x: remove waiting descriptor pointer Russell King
2012-05-31  1:11   ` Linus Walleij
2012-05-29  9:43 ` [RFC 23/34] dmaengine: PL08x: re-jig the starting of txds Russell King
2012-05-31  1:14   ` Linus Walleij
2012-06-01 10:52     ` Russell King - ARM Linux
2012-06-04 15:54       ` Linus Walleij
2012-05-29  9:43 ` [RFC 24/34] dmaengine: PL08x: split the pend_list in two Russell King
2012-05-31  1:20   ` Linus Walleij
2012-05-29  9:43 ` [RFC 25/34] dmaengine: PL08x: start next descriptor from irq context Russell King
2012-05-31  1:21   ` Linus Walleij
2012-05-29  9:44 ` [RFC 26/34] dmaengine: PL08x: rejig physical channel allocation Russell King
2012-05-31  1:23   ` Linus Walleij
2012-05-29  9:44 ` [RFC 27/34] dmaengine: PL08x: convert to use virt-dma structs Russell King
2012-05-31  1:23   ` Linus Walleij
2012-05-29  9:44 ` [RFC 28/34] dmaengine: PL08x: use vchan's spinlock Russell King
2012-05-31  1:24   ` Linus Walleij
2012-05-29  9:45 ` [RFC 29/34] dmaengine: PL08x: convert to use vchan submitted/issued lists Russell King
2012-05-31  1:24   ` Linus Walleij
2012-05-29  9:45 ` [RFC 30/34] dmaengine: PL08x: convert to use vchan done list Russell King
2012-05-31  1:24   ` Linus Walleij
2012-05-29  9:45 ` [RFC 31/34] dmaengine: PL08x: fix tx_status function to return correct residue Russell King
2012-05-31  1:25   ` Linus Walleij
2012-05-29  9:46 ` [RFC 32/34] dmaengine: PL08x: get rid of pl08x_prep_channel_resources Russell King
2012-05-31  1:25   ` Linus Walleij
2012-05-29  9:46 ` [RFC 33/34] dmaengine: PL08x: get rid of write only pool_ctr and free_txd locking Russell King
2012-05-31  1:26   ` Linus Walleij
2012-05-29  9:46 ` [RFC 34/34] dmaengine: PL08x: ensure all descriptors are freed when channel is released Russell King
2012-05-31  1:27   ` Linus Walleij
2012-06-01 10:55     ` Russell King - ARM Linux

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.