Skip to contentSkip to conversation

To use DMA generic APIs for Samsung DMA

PATCH RESEND Superseded Boojin Kim 7 participants 73 messages Jul 25, 2011 – Jul 28, 2011

Subsystems (10)

v4 of 8 Superseded Latest is v8 →

lore
Share & tools
lore

Boojin Kim

author
#0 lore raw

v4 cover To use DMA generic APIs for Samsung DMA

This patchset adds support DMA generic APIs for Samsung DMA and is re-sent by the request of DMA maintainer, Vinod Koul.

V4 has the changes about 3 patches from V3.
Changes from V3:
- Divided '[03/13 patch] DMA: PL330: Add DMA capabilites' on V3 patchset into two patches.
- One is '03/14 patch' for supporting DMA_SLAVE_CONFIG command.
- Another is '04/14 patch' for supporting DMA_CYCLIC capability.
- Code clean-up
- Remove unnecessary vairable referance on '01/14 patch'.
- Remove redunancy code on '06/14 patch'

[PATCH V4 01/14] DMA: PL330: Add support runtime PM for PL330 DMAC [PATCH V4 02/14] DMA: PL330: Update PL330 DMA API driver
[PATCH V4 03/14] DMA: PL330: Support DMA_SLAVE_CONFIG command
[PATCH V4 04/14] DMA: PL330: Add DMA_CYCLIC capability
[PATCH V4 05/14] ARM: SAMSUNG: Update to use PL330-DMA driver
[PATCH V4 06/14] ARM: SAMSUNG: Add common DMA operations
[PATCH V4 07/14] ARM: EXYNOS4: Use generic DMA PL330 driver
[PATCH V4 08/14] ARM: S5PV210: Use generic DMA PL330 driver
[PATCH V4 09/14] ARM: S5PC100: Use generic DMA PL330 driver
[PATCH V4 10/14] ARM: S5P64X0: Use generic DMA PL330 driver
[PATCH V4 11/14] ARM: SAMSUNG: Remove S3C-PL330-DMA driver
[PATCH V4 12/14] spi/s3c64xx: Add support DMA engine API
[PATCH V4 13/14] ASoC: Samsung: Update DMA interface
[PATCH V4 14/14] ARM: SAMSUNG: Remove Samsung specific enum type for dma direction

author
#1 lore raw

PATCH v4 1/14 DMA: PL330: Add support runtime PM for PL330 DMAC

---
 drivers/dma/pl330.c |   75 +++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 73 insertions(+), 2 deletions(-)
drivers/dma/pl330.c +73 -2
index 6abe1ec..b7ecf47 100644
@@ -17,6 +17,7 @@
 #include <linux/interrupt.h>
 #include <linux/amba/bus.h>
 #include <linux/amba/pl330.h>
+#include <linux/pm_runtime.h>
 
 #define NR_DEFAULT_DESC	16
 
@@ -83,6 +84,8 @@ struct dma_pl330_dmac {
 
 	/* Peripheral channels connected to this DMAC */
 	struct dma_pl330_chan peripherals[0]; /* keep at end */
+
+	struct clk *clk;
 };
 
 struct dma_pl330_desc {
@@ -696,6 +699,30 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id)
 		goto probe_err1;
 	}
 
+	pdmac->clk = clk_get(&adev->dev, "dma");
+	if (IS_ERR(pdmac->clk)) {
+		dev_err(&adev->dev, "Cannot get operation clock.\n");
+		ret = -EINVAL;
+		goto probe_err1;
+	}
+
+	amba_set_drvdata(adev, pdmac);
+
+#ifdef CONFIG_PM_RUNTIME
+	/* to use the runtime PM helper functions */
+	pm_runtime_enable(&adev->dev);
+
+	/* enable the power domain */
+	if (pm_runtime_get_sync(&adev->dev)) {
+		dev_err(&adev->dev, "failed to get runtime pm\n");
+		ret = -ENODEV;
+		goto probe_err1;
+	}
+#else
+	/* enable dma clk */
+	clk_enable(pdmac->clk);
+#endif
+
 	irq = adev->irq[0];
 	ret = request_irq(irq, pl330_irq_handler, 0,
 			dev_name(&adev->dev), pi);
@@ -763,8 +790,6 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id)
 		goto probe_err4;
 	}
 
-	amba_set_drvdata(adev, pdmac);
-
 	dev_info(&adev->dev,
 		"Loaded driver for PL330 DMAC-%d\n", adev->periphid);
 	dev_info(&adev->dev,
@@ -825,6 +850,13 @@ static int __devexit pl330_remove(struct amba_device *adev)
 	res = &adev->res;
 	release_mem_region(res->start, resource_size(res));
 
+#ifdef CONFIG_PM_RUNTIME
+	pm_runtime_put(&adev->dev);
+	pm_runtime_disable(&adev->dev);
+#else
+	clk_disable(pdmac->clk);
+#endif
+
 	kfree(pdmac);
 
 	return 0;
@@ -838,10 +870,49 @@ static struct amba_id pl330_ids[] = {
 	{ 0, 0 },
 };
 
+#ifdef CONFIG_PM_RUNTIME
+static int pl330_runtime_suspend(struct device *dev)
+{
+	struct dma_pl330_dmac *pdmac = dev_get_drvdata(dev);
+
+	if (!pdmac) {
+		dev_err(dev, "failed to get dmac\n");
+		return -ENODEV;
+	}
+
+	clk_disable(pdmac->clk);
+
+	return 0;
+}
+
+static int pl330_runtime_resume(struct device *dev)
+{
+	struct dma_pl330_dmac *pdmac = dev_get_drvdata(dev);
+
+	if (!pdmac) {
+		dev_err(dev, "failed to get dmac\n");
+		return -ENODEV;
+	}
+
+	clk_enable(pdmac->clk);
+
+	return 0;
+}
+#else
+#define pl330_runtime_suspend	NULL
+#define pl330_runtime_resume	NULL
+#endif /* CONFIG_PM_RUNTIME */
+
+static const struct dev_pm_ops pl330_pm_ops = {
+	.runtime_suspend = pl330_runtime_suspend,
+	.runtime_resume = pl330_runtime_resume,
+};
+
 static struct amba_driver pl330_driver = {
 	.drv = {
 		.owner = THIS_MODULE,
 		.name = "dma-pl330",
+		.pm = &pl330_pm_ops,
 	},
 	.id_table = pl330_ids,
 	.probe = pl330_probe,
Signature · 1 line
1.7.1
#2 lore raw

PATCH v4 1/14 DMA: PL330: Add support runtime PM for PL330 DMAC

Quoted 120 lines · Boojin Kim
---
 drivers/dma/pl330.c |   75 +++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 73 insertions(+), 2 deletions(-)
drivers/dma/pl330.c +70 -2
index 6abe1ec..b7ecf47 100644
@@ -17,6 +17,7 @@
 #include <linux/interrupt.h>
 #include <linux/amba/bus.h>
 #include <linux/amba/pl330.h>
+#include <linux/pm_runtime.h>
 
 #define NR_DEFAULT_DESC	16
 
@@ -83,6 +84,8 @@ struct dma_pl330_dmac {
 
 	/* Peripheral channels connected to this DMAC */
 	struct dma_pl330_chan peripherals[0]; /* keep at end */
+
+	struct clk *clk;
 };
 
 struct dma_pl330_desc {
@@ -696,6 +699,30 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id)
 		goto probe_err1;
 	}
 
+	pdmac->clk = clk_get(&adev->dev, "dma");
+	if (IS_ERR(pdmac->clk)) {
+		dev_err(&adev->dev, "Cannot get operation clock.\n");
+		ret = -EINVAL;
+		goto probe_err1;
+	}
+
+	amba_set_drvdata(adev, pdmac);
+
+#ifdef CONFIG_PM_RUNTIME
+	/* to use the runtime PM helper functions */
+	pm_runtime_enable(&adev->dev);
+
+	/* enable the power domain */
+	if (pm_runtime_get_sync(&adev->dev)) {
+		dev_err(&adev->dev, "failed to get runtime pm\n");
+		ret = -ENODEV;
+		goto probe_err1;
+	}
+#else
+	/* enable dma clk */
+	clk_enable(pdmac->clk);
+#endif
+
 	irq = adev->irq[0];
 	ret = request_irq(irq, pl330_irq_handler, 0,
 			dev_name(&adev->dev), pi);
@@ -763,8 +790,6 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id)
 		goto probe_err4;
 	}
 
-	amba_set_drvdata(adev, pdmac);
-
 	dev_info(&adev->dev,
 		"Loaded driver for PL330 DMAC-%d\n", adev->periphid);
 	dev_info(&adev->dev,
@@ -825,6 +850,13 @@ static int __devexit pl330_remove(struct amba_device *adev)
 	res = &adev->res;
 	release_mem_region(res->start, resource_size(res));
 
+#ifdef CONFIG_PM_RUNTIME
+	pm_runtime_put(&adev->dev);
+	pm_runtime_disable(&adev->dev);
+#else
+	clk_disable(pdmac->clk);
+#endif
+
 	kfree(pdmac);
 
 	return 0;
@@ -838,10 +870,49 @@ static struct amba_id pl330_ids[] = {
 	{ 0, 0 },
 };
 
+#ifdef CONFIG_PM_RUNTIME
+static int pl330_runtime_suspend(struct device *dev)
+{
+	struct dma_pl330_dmac *pdmac = dev_get_drvdata(dev);
+
+	if (!pdmac) {
+		dev_err(dev, "failed to get dmac\n");
+		return -ENODEV;
+	}
+
+	clk_disable(pdmac->clk);
+
+	return 0;
+}
+
+static int pl330_runtime_resume(struct device *dev)
+{
+	struct dma_pl330_dmac *pdmac = dev_get_drvdata(dev);
+
+	if (!pdmac) {
+		dev_err(dev, "failed to get dmac\n");
+		return -ENODEV;
+	}
+
+	clk_enable(pdmac->clk);
+
+	return 0;
+}
+#else
+#define pl330_runtime_suspend	NULL
+#define pl330_runtime_resume	NULL
+#endif /* CONFIG_PM_RUNTIME */
+
+static const struct dev_pm_ops pl330_pm_ops = {
+	.runtime_suspend = pl330_runtime_suspend,
+	.runtime_resume = pl330_runtime_resume,

drivers/dma/pl330.c static struct amba_id pl330_ids[] = { · line 918

Quoted 10 lines
drivers/dma/pl330.c +3 -0
+};
+
 static struct amba_driver pl330_driver = {
 	.drv = {
 		.owner = THIS_MODULE,
 		.name = "dma-pl330",
+		.pm = &pl330_pm_ops,
 	},
 	.id_table = pl330_ids,
 	.probe = pl330_probe,

I have a question for runtime PM of PL330 DMAC

This patch support runtime PM for PL330 DMAC, but the clock of "dma" is always on. If the clock of "dma" is always on, additional power(10mA) is consumed. I tested it.

I think that the PL330 DMAC only turn on the clock of "dma" when using DMA.

Thanks,
Chanwoo Choi

author
#3 lore raw

PATCH v4 2/14 DMA: PL330: Update PL330 DMA API driver

In reply to Boojin Kim

This patch updates following 3 items.
1. Removes unneccessary code.
2. Add AMBA, PL330 configuration
3. Change the meaning of 'peri_id' variable from PL330 event number to specific dma id by user.

---
 drivers/dma/Kconfig        |    3 ++-
 drivers/dma/pl330.c        |   31 ++++++++++++++++---------------
 include/linux/amba/pl330.h |    2 +-
 3 files changed, 19 insertions(+), 17 deletions(-)
drivers/dma/Kconfig +2 -1
index 25cf327..569cb14 100644
@@ -193,7 +193,8 @@ config ARCH_HAS_ASYNC_TX_FIND_CHANNEL
 config PL330_DMA
 	tristate "DMA API Driver for PL330"
 	select DMA_ENGINE
-	depends on PL330
+	depends on ARM_AMBA
+	select PL330
 	help
 	  Select if your platform has one or more PL330 DMACs.
 	  You need to provide platform specific settings via
drivers/dma/pl330.c +16 -15
index b7ecf47..586ab39 100644
@@ -455,7 +455,7 @@ static struct dma_pl330_desc *pl330_get_desc(struct dma_pl330_chan *pch)
 	async_tx_ack(&desc->txd);
 
 	desc->req.rqtype = peri->rqtype;
-	desc->req.peri = peri->peri_id;
+	desc->req.peri = pch->chan.chan_id;
 
 	dma_async_tx_descriptor_init(&desc->txd, &pch->chan);
 
@@ -577,7 +577,7 @@ pl330_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
 	struct dma_pl330_peri *peri = chan->private;
 	struct scatterlist *sg;
 	unsigned long flags;
-	int i, burst_size;
+	int i;
 	dma_addr_t addr;
 
 	if (unlikely(!pch || !sgl || !sg_len))
@@ -594,7 +594,6 @@ pl330_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
 	}
 
 	addr = peri->fifo_addr;
-	burst_size = peri->burst_sz;
 
 	first = NULL;
 
@@ -642,7 +641,7 @@ pl330_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
 				sg_dma_address(sg), addr, sg_dma_len(sg));
 		}
 
-		desc->rqcfg.brst_size = burst_size;
+		desc->rqcfg.brst_size = peri->burst_sz;
 		desc->rqcfg.brst_len = 1;
 	}
 
@@ -748,17 +747,19 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id)
 		struct dma_pl330_peri *peri = &pdat->peri[i];
 		pch = &pdmac->peripherals[i];
 
-		switch (peri->rqtype) {
-		case MEMTOMEM:
-			dma_cap_set(DMA_MEMCPY, pd->cap_mask);
-			break;
-		case MEMTODEV:
-		case DEVTOMEM:
-			dma_cap_set(DMA_SLAVE, pd->cap_mask);
-			break;
-		default:
-			dev_err(&adev->dev, "DEVTODEV Not Supported\n");
-			continue;
+		if (peri) {
+			switch (peri->rqtype) {
+			case MEMTOMEM:
+				dma_cap_set(DMA_MEMCPY, pd->cap_mask);
+				break;
+			case MEMTODEV:
+			case DEVTOMEM:
+				dma_cap_set(DMA_SLAVE, pd->cap_mask);
+				break;
+			default:
+				dev_err(&adev->dev, "DEVTODEV Not Supported\n");
+				continue;
+			}
 		}
 
 		INIT_LIST_HEAD(&pch->work_list);
include/linux/amba/pl330.h +1 -1
index cbee7de..17b0ada 100644
@@ -19,7 +19,7 @@ struct dma_pl330_peri {
 	 * Peri_Req i/f of the DMAC that is
 	 * peripheral could be reached from.
 	 */
-	u8 peri_id; /* {0, 31} */
+	u8 peri_id; /* specific dma id */
 	enum pl330_reqtype rqtype;
 
 	/* For M->D and D->M Channels */
Signature · 1 line
1.7.1
#4 lore raw

PATCH v4 2/14 DMA: PL330: Update PL330 DMA API driver

drivers/dma/pl330.c static struct dma_pl330_desc *pl330_get_desc(struct dma_pl330_chan *pch) · line 458

Quoted 10 lines · Boojin Kim
drivers/dma/pl330.c +1 -1
index b7ecf47..586ab39 100644
@@ -455,7 +455,7 @@ static struct dma_pl330_desc *pl330_get_desc(struct dma_pl330_chan *pch)
 ? ? ? ?async_tx_ack(&desc->txd);
 
 ? ? ? ?desc->req.rqtype = peri->rqtype;
- ? ? ? desc->req.peri = peri->peri_id;
+ ? ? ? desc->req.peri = pch->chan.chan_id;

Btw, I plan to revert this if my patch is accepted that proposes to free chan_id solely for use by DMAC drivers(which we should employ to pass paltform assigned channel ID to client drivers)

Quoted 19 lines
drivers/dma/pl330.c +4 -11
@@ -748,17 +747,19 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id)
 ? ? ? ? ? ? ? ?struct dma_pl330_peri *peri = &pdat->peri[i];
 ? ? ? ? ? ? ? ?pch = &pdmac->peripherals[i];
 
- ? ? ? ? ? ? ? switch (peri->rqtype) {
- ? ? ? ? ? ? ? case MEMTOMEM:
- ? ? ? ? ? ? ? ? ? ? ? dma_cap_set(DMA_MEMCPY, pd->cap_mask);
- ? ? ? ? ? ? ? ? ? ? ? break;
- ? ? ? ? ? ? ? case MEMTODEV:
- ? ? ? ? ? ? ? case DEVTOMEM:
- ? ? ? ? ? ? ? ? ? ? ? dma_cap_set(DMA_SLAVE, pd->cap_mask);
- ? ? ? ? ? ? ? ? ? ? ? break;
- ? ? ? ? ? ? ? default:
- ? ? ? ? ? ? ? ? ? ? ? dev_err(&adev->dev, "DEVTODEV Not Supported\n");
- ? ? ? ? ? ? ? ? ? ? ? continue;
+ ? ? ? ? ? ? ? if (peri) {
+ ? ? ? ? ? ? ? ? ? ? ? switch (peri->rqtype) {
+ ? ? ? ? ? ? ? ? ? ? ? case MEMTOMEM:
+ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? dma_cap_set(DMA_MEMCPY, pd->cap_mask);

drivers/dma/pl330.c pl330_probe(struct amba_device *adev, const struct amba_id *id) · line 763

Quoted 10 lines
drivers/dma/pl330.c +9 -0
+ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? break;
+ ? ? ? ? ? ? ? ? ? ? ? case MEMTODEV:
+ ? ? ? ? ? ? ? ? ? ? ? case DEVTOMEM:
+ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? dma_cap_set(DMA_SLAVE, pd->cap_mask);
+ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? break;
+ ? ? ? ? ? ? ? ? ? ? ? default:
+ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? dev_err(&adev->dev, "DEVTODEV Not Supported\n");
+ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? continue;
+ ? ? ? ? ? ? ? ? ? ? ? }
 ? ? ? ? ? ? ? ?}

If you pass platform data correctly, you don't need to check against NULL peri.

author
#5 lore raw

PATCH v4 2/14 DMA: PL330: Update PL330 DMA API driver

Quoted 54 lines

-----Original Message-----
From: Jassi Brar [mailto:jassisinghbrar at gmail.com]
Sent: Monday, July 25, 2011 5:58 PM
To: Boojin Kim
Cc: linux-arm-kernel at lists.infradead.org; linux-samsung-soc at vger.kernel.org; Vinod Koul; Dan Williams; Kukjin Kim; Grant Likely; Mark Brown
Subject: Re: [PATCH V4 02/14] DMA: PL330: Update PL330 DMA API driver

drivers/dma/pl330.c static struct dma_pl330_desc *pl330_get_desc(struct

Quoted 5 lines · Boojin Kim
drivers/dma/pl330.c +0 -0
index b7ecf47..586ab39 100644
@@ -455,7 +455,7 @@ static struct dma_pl330_desc *pl330_get_desc(struct

dma_pl330_chan *pch)

drivers/dma/pl330.c static struct dma_pl330_desc *pl330_get_desc(struct dma_pl330_chan *pch) · line 458

Quoted 5 lines
drivers/dma/pl330.c +1 -1
       async_tx_ack(&desc->txd);
 
       desc->req.rqtype = peri->rqtype;
-       desc->req.peri = peri->peri_id;
+       desc->req.peri = pch->chan.chan_id;

Btw, I plan to revert this if my patch is accepted that proposes to free chan_id solely for use by DMAC drivers(which we should employ to pass paltform assigned channel ID to client drivers)

drivers/dma/pl330.c pl330_probe(struct amba_device *adev, const struct

Quoted 1 line
drivers/dma/pl330.c +0 -0
@@ -748,17 +747,19 @@ pl330_probe(struct amba_device *adev, const struct

amba_id *id)

Quoted 15 lines
drivers/dma/pl330.c +1 -11
               struct dma_pl330_peri *peri = &pdat->peri[i];
               pch = &pdmac->peripherals[i];
 
-               switch (peri->rqtype) {
-               case MEMTOMEM:
-                       dma_cap_set(DMA_MEMCPY, pd->cap_mask);
-                       break;
-               case MEMTODEV:
-               case DEVTOMEM:
-                       dma_cap_set(DMA_SLAVE, pd->cap_mask);
-                       break;
-               default:
-                       dev_err(&adev->dev, "DEVTODEV Not Supported\n");
-                       continue;
+               if (peri) {

drivers/dma/pl330.c pl330_probe(struct amba_device *adev, const struct amba_id *id)

Quoted 10 lines
drivers/dma/pl330.c +10 -0
+                       switch (peri->rqtype) {
+                       case MEMTOMEM:
+                               dma_cap_set(DMA_MEMCPY, pd->cap_mask);
+                               break;
+                       case MEMTODEV:
+                       case DEVTOMEM:
+                               dma_cap_set(DMA_SLAVE, pd->cap_mask);
+                               break;
+                       default:
+                               dev_err(&adev->dev, "DEVTODEV Not
Quoted 6 lines

Supported\n");

drivers/dma/pl330.c pl330_probe(struct amba_device *adev, const struct amba_id *id) · line 763

Quoted 3 lines
drivers/dma/pl330.c +2 -0
+                               continue;
+                       }
               }

If you pass platform data correctly, you don't need to check against NULL peri.

Ok, It may be excessive error check. I will remove this point.

author
#6 lore raw

PATCH v4 3/14 DMA: PL330: Support DMA_SLAVE_CONFIG command

In reply to Boojin Kim

This patch adds support DMA_SLAVE_CONFIG command.

---
 drivers/dma/pl330.c |   53 +++++++++++++++++++++++++++++++++++++-------------
 1 files changed, 39 insertions(+), 14 deletions(-)
drivers/dma/pl330.c +39 -14
index 586ab39..880f010 100644
@@ -256,25 +256,50 @@ static int pl330_alloc_chan_resources(struct dma_chan *chan)
 static int pl330_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, unsigned long arg)
 {
 	struct dma_pl330_chan *pch = to_pchan(chan);
-	struct dma_pl330_desc *desc;
+	struct dma_pl330_desc *desc, *_dt;
 	unsigned long flags;
+	struct dma_pl330_dmac *pdmac = pch->dmac;
+	struct dma_slave_config *slave_config;
+	struct dma_pl330_peri *peri;
+	LIST_HEAD(list);
 
-	/* Only supports DMA_TERMINATE_ALL */
-	if (cmd != DMA_TERMINATE_ALL)
-		return -ENXIO;
-
-	spin_lock_irqsave(&pch->lock, flags);
-
-	/* FLUSH the PL330 Channel thread */
-	pl330_chan_ctrl(pch->pl330_chid, PL330_OP_FLUSH);
+	switch (cmd) {
+	case DMA_TERMINATE_ALL:
+		spin_lock_irqsave(&pch->lock, flags);
 
-	/* Mark all desc done */
-	list_for_each_entry(desc, &pch->work_list, node)
-		desc->status = DONE;
+		/* FLUSH the PL330 Channel thread */
+		pl330_chan_ctrl(pch->pl330_chid, PL330_OP_FLUSH);
 
-	spin_unlock_irqrestore(&pch->lock, flags);
+		/* Mark all desc done */
+		list_for_each_entry_safe(desc, _dt, &pch->work_list , node) {
+			desc->status = DONE;
+			pch->completed = desc->txd.cookie;
+			list_move_tail(&desc->node, &list);
+		}
 
-	pl330_tasklet((unsigned long) pch);
+		list_splice_tail_init(&list, &pdmac->desc_pool);
+		spin_unlock_irqrestore(&pch->lock, flags);
+		break;
+	case DMA_SLAVE_CONFIG:
+		slave_config = (struct dma_slave_config *)arg;
+		peri = pch->chan.private;
+
+		if (slave_config->direction == DMA_TO_DEVICE) {
+			if (slave_config->dst_addr)
+				peri->fifo_addr = slave_config->dst_addr;
+			if (slave_config->dst_addr_width)
+				peri->burst_sz = __ffs(slave_config->dst_addr_width);
+		} else if (slave_config->direction == DMA_FROM_DEVICE) {
+			if (slave_config->src_addr)
+				peri->fifo_addr = slave_config->src_addr;
+			if (slave_config->src_addr_width)
+				peri->burst_sz = __ffs(slave_config->src_addr_width);
+		}
+		break;
+	default:
+		dev_err(pch->dmac->pif.dev, "Not supported command.\n");
+		return -ENXIO;
+	}
 
 	return 0;
 }
Signature · 1 line
1.7.1
#7 lore raw

PATCH v4 3/14 DMA: PL330: Support DMA_SLAVE_CONFIG command

Quoted 52 lines · Boojin Kim

This patch adds support DMA_SLAVE_CONFIG command.

---
 drivers/dma/pl330.c |   53 +++++++++++++++++++++++++++++++++++++-------------
 1 files changed, 39 insertions(+), 14 deletions(-)
drivers/dma/pl330.c +18 -14
index 586ab39..880f010 100644
@@ -256,25 +256,50 @@ static int pl330_alloc_chan_resources(struct dma_chan *chan)
 static int pl330_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, unsigned long arg)
 {
 	struct dma_pl330_chan *pch = to_pchan(chan);
-	struct dma_pl330_desc *desc;
+	struct dma_pl330_desc *desc, *_dt;
 	unsigned long flags;
+	struct dma_pl330_dmac *pdmac = pch->dmac;
+	struct dma_slave_config *slave_config;
+	struct dma_pl330_peri *peri;
+	LIST_HEAD(list);
 
-	/* Only supports DMA_TERMINATE_ALL */
-	if (cmd != DMA_TERMINATE_ALL)
-		return -ENXIO;
-
-	spin_lock_irqsave(&pch->lock, flags);
-
-	/* FLUSH the PL330 Channel thread */
-	pl330_chan_ctrl(pch->pl330_chid, PL330_OP_FLUSH);
+	switch (cmd) {
+	case DMA_TERMINATE_ALL:
+		spin_lock_irqsave(&pch->lock, flags);
 
-	/* Mark all desc done */
-	list_for_each_entry(desc, &pch->work_list, node)
-		desc->status = DONE;
+		/* FLUSH the PL330 Channel thread */
+		pl330_chan_ctrl(pch->pl330_chid, PL330_OP_FLUSH);
 
-	spin_unlock_irqrestore(&pch->lock, flags);
+		/* Mark all desc done */
+		list_for_each_entry_safe(desc, _dt, &pch->work_list , node) {
+			desc->status = DONE;
+			pch->completed = desc->txd.cookie;
+			list_move_tail(&desc->node, &list);
+		}
 
-	pl330_tasklet((unsigned long) pch);
+		list_splice_tail_init(&list, &pdmac->desc_pool);
+		spin_unlock_irqrestore(&pch->lock, flags);

drivers/dma/pl330.c static int pl330_alloc_chan_resources(struct dma_chan *chan) · line 291

Quoted 10 lines
drivers/dma/pl330.c +10 -0
+		break;
+	case DMA_SLAVE_CONFIG:
+		slave_config = (struct dma_slave_config *)arg;
+		peri = pch->chan.private;
+
+		if (slave_config->direction == DMA_TO_DEVICE) {
+			if (slave_config->dst_addr)
+				peri->fifo_addr = slave_config->dst_addr;
+			if (slave_config->dst_addr_width)
+				peri->burst_sz = __ffs(slave_config->dst_addr_width);

This doesn't sound right, why can't you use xxx_maxburst field instead?

drivers/dma/pl330.c static int pl330_alloc_chan_resources(struct dma_chan *chan) · line 296

Quoted 5 lines
drivers/dma/pl330.c +5 -0
+		} else if (slave_config->direction == DMA_FROM_DEVICE) {
+			if (slave_config->src_addr)
+				peri->fifo_addr = slave_config->src_addr;
+			if (slave_config->src_addr_width)
+				peri->burst_sz = __ffs(slave_config->src_addr_width);

ditto...

Quoted 9 lines
drivers/dma/pl330.c +6 -0
+		}
+		break;
+	default:
+		dev_err(pch->dmac->pif.dev, "Not supported command.\n");
+		return -ENXIO;
+	}
 
 	return 0;
 }
Signature · 2 lines
~Vinod Koul
Intel Corp.
author
#8 lore raw

PATCH v4 3/14 DMA: PL330: Support DMA_SLAVE_CONFIG command

Vinod Koul Wrote:

Quoted 62 lines

Sent: Monday, July 25, 2011 7:27 PM
To: Boojin Kim
Cc: vinod.koul at intel.com; linux-arm-kernel at lists.infradead.org; linux- samsung-soc at vger.kernel.org; Kukjin Kim; Jassi Brar; Grant Likely; Mark Brown; Dan Williams
Subject: Re: [PATCH V4 03/14] DMA: PL330: Support DMA_SLAVE_CONFIG command

Quoted 5 lines · Boojin Kim

This patch adds support DMA_SLAVE_CONFIG command.

---
 drivers/dma/pl330.c |   53 +++++++++++++++++++++++++++++++++++++----

---------

drivers/dma/pl330.c static int pl330_alloc_chan_resources(struct

Quoted 7 lines
 1 files changed, 39 insertions(+), 14 deletions(-)
drivers/dma/pl330.c +0 -0
index 586ab39..880f010 100644
@@ -256,25 +256,50 @@ static int pl330_alloc_chan_resources(struct

dma_chan *chan)

drivers/dma/pl330.c static int pl330_alloc_chan_resources(struct · line 256

Quoted 1 line
drivers/dma/pl330.c +0 -0
 static int pl330_control(struct dma_chan *chan, enum dma_ctrl_cmd

cmd, unsigned long arg)

Quoted 21 lines
drivers/dma/pl330.c +8 -9
 {
 	struct dma_pl330_chan *pch = to_pchan(chan);
-	struct dma_pl330_desc *desc;
+	struct dma_pl330_desc *desc, *_dt;
 	unsigned long flags;
+	struct dma_pl330_dmac *pdmac = pch->dmac;
+	struct dma_slave_config *slave_config;
+	struct dma_pl330_peri *peri;
+	LIST_HEAD(list);
 
-	/* Only supports DMA_TERMINATE_ALL */
-	if (cmd != DMA_TERMINATE_ALL)
-		return -ENXIO;
-
-	spin_lock_irqsave(&pch->lock, flags);
-
-	/* FLUSH the PL330 Channel thread */
-	pl330_chan_ctrl(pch->pl330_chid, PL330_OP_FLUSH);
+	switch (cmd) {
+	case DMA_TERMINATE_ALL:
+		spin_lock_irqsave(&pch->lock, flags);

drivers/dma/pl330.c static int pl330_alloc_chan_resources(struct dma_chan *chan)

Quoted 10 lines
drivers/dma/pl330.c +4 -4
 
-	/* Mark all desc done */
-	list_for_each_entry(desc, &pch->work_list, node)
-		desc->status = DONE;
+		/* FLUSH the PL330 Channel thread */
+		pl330_chan_ctrl(pch->pl330_chid, PL330_OP_FLUSH);
 
-	spin_unlock_irqrestore(&pch->lock, flags);
+		/* Mark all desc done */
+		list_for_each_entry_safe(desc, _dt, &pch->work_list , node)

{

Quoted 5 lines
drivers/dma/pl330.c +4 -0
+			desc->status = DONE;
+			pch->completed = desc->txd.cookie;
+			list_move_tail(&desc->node, &list);
+		}
 
Quoted 15 lines
Quoted 4 lines
drivers/dma/pl330.c +3 -1
-	pl330_tasklet((unsigned long) pch);
+		list_splice_tail_init(&list, &pdmac->desc_pool);
+		spin_unlock_irqrestore(&pch->lock, flags);
+		break;

drivers/dma/pl330.c static int pl330_alloc_chan_resources(struct dma_chan *chan)

Quoted 10 lines
drivers/dma/pl330.c +9 -0
+	case DMA_SLAVE_CONFIG:
+		slave_config = (struct dma_slave_config *)arg;
+		peri = pch->chan.private;
+
+		if (slave_config->direction == DMA_TO_DEVICE) {
+			if (slave_config->dst_addr)
+				peri->fifo_addr = slave_config->dst_addr;
+			if (slave_config->dst_addr_width)
+				peri->burst_sz = __ffs(slave_config-
 dst_addr_width);

This doesn't sound right, why can't you use xxx_maxburst field instead?

Can you explain the problem in more detail?
Do you mean that 'xxx_maxburst' takes place of 'xxx_addr_width' or __ffs() isn't proper here?

Additionally, I will modify this code to consider '_maxburst' field.

Quoted 21 lines

drivers/dma/pl330.c static int pl330_alloc_chan_resources(struct dma_chan *chan)

Quoted 7 lines
drivers/dma/pl330.c +5 -0
+		} else if (slave_config->direction == DMA_FROM_DEVICE) {
+			if (slave_config->src_addr)
+				peri->fifo_addr = slave_config->src_addr;
+			if (slave_config->src_addr_width)
+				peri->burst_sz = __ffs(slave_config-
 src_addr_width);

ditto...

Quoted 9 lines
drivers/dma/pl330.c +6 -0
+		}
+		break;
+	default:
+		dev_err(pch->dmac->pif.dev, "Not supported command.\n");
+		return -ENXIO;
+	}
 

return 0;
}

--
~Vinod Koul
Intel Corp.

#9 lore raw

PATCH v4 3/14 DMA: PL330: Support DMA_SLAVE_CONFIG command

Quoted 78 lines · Boojin Kim

Vinod Koul Wrote:

Quoted 62 lines

Sent: Monday, July 25, 2011 7:27 PM
To: Boojin Kim
Cc: vinod.koul at intel.com; linux-arm-kernel at lists.infradead.org; linux- samsung-soc at vger.kernel.org; Kukjin Kim; Jassi Brar; Grant Likely; Mark Brown; Dan Williams
Subject: Re: [PATCH V4 03/14] DMA: PL330: Support DMA_SLAVE_CONFIG command

Quoted 5 lines · Boojin Kim

This patch adds support DMA_SLAVE_CONFIG command.

---
 drivers/dma/pl330.c |   53 +++++++++++++++++++++++++++++++++++++----

---------

drivers/dma/pl330.c static int pl330_alloc_chan_resources(struct

Quoted 7 lines
 1 files changed, 39 insertions(+), 14 deletions(-)
drivers/dma/pl330.c +0 -0
index 586ab39..880f010 100644
@@ -256,25 +256,50 @@ static int pl330_alloc_chan_resources(struct

dma_chan *chan)

drivers/dma/pl330.c static int pl330_alloc_chan_resources(struct · line 256

Quoted 1 line
drivers/dma/pl330.c +0 -0
 static int pl330_control(struct dma_chan *chan, enum dma_ctrl_cmd

cmd, unsigned long arg)

Quoted 21 lines
drivers/dma/pl330.c +8 -9
 {
 	struct dma_pl330_chan *pch = to_pchan(chan);
-	struct dma_pl330_desc *desc;
+	struct dma_pl330_desc *desc, *_dt;
 	unsigned long flags;
+	struct dma_pl330_dmac *pdmac = pch->dmac;
+	struct dma_slave_config *slave_config;
+	struct dma_pl330_peri *peri;
+	LIST_HEAD(list);
 
-	/* Only supports DMA_TERMINATE_ALL */
-	if (cmd != DMA_TERMINATE_ALL)
-		return -ENXIO;
-
-	spin_lock_irqsave(&pch->lock, flags);
-
-	/* FLUSH the PL330 Channel thread */
-	pl330_chan_ctrl(pch->pl330_chid, PL330_OP_FLUSH);
+	switch (cmd) {
+	case DMA_TERMINATE_ALL:
+		spin_lock_irqsave(&pch->lock, flags);

drivers/dma/pl330.c static int pl330_alloc_chan_resources(struct dma_chan *chan)

Quoted 10 lines
drivers/dma/pl330.c +4 -4
 
-	/* Mark all desc done */
-	list_for_each_entry(desc, &pch->work_list, node)
-		desc->status = DONE;
+		/* FLUSH the PL330 Channel thread */
+		pl330_chan_ctrl(pch->pl330_chid, PL330_OP_FLUSH);
 
-	spin_unlock_irqrestore(&pch->lock, flags);
+		/* Mark all desc done */
+		list_for_each_entry_safe(desc, _dt, &pch->work_list , node)

{

Quoted 5 lines
drivers/dma/pl330.c +4 -0
+			desc->status = DONE;
+			pch->completed = desc->txd.cookie;
+			list_move_tail(&desc->node, &list);
+		}
 
Quoted 15 lines
Quoted 4 lines
drivers/dma/pl330.c +3 -1
-	pl330_tasklet((unsigned long) pch);
+		list_splice_tail_init(&list, &pdmac->desc_pool);
+		spin_unlock_irqrestore(&pch->lock, flags);
+		break;

drivers/dma/pl330.c static int pl330_alloc_chan_resources(struct dma_chan *chan)

Quoted 10 lines
drivers/dma/pl330.c +9 -0
+	case DMA_SLAVE_CONFIG:
+		slave_config = (struct dma_slave_config *)arg;
+		peri = pch->chan.private;
+
+		if (slave_config->direction == DMA_TO_DEVICE) {
+			if (slave_config->dst_addr)
+				peri->fifo_addr = slave_config->dst_addr;
+			if (slave_config->dst_addr_width)
+				peri->burst_sz = __ffs(slave_config-
 dst_addr_width);

This doesn't sound right, why can't you use xxx_maxburst field instead?

Quoted 5 lines

Can you explain the problem in more detail?
Do you mean that 'xxx_maxburst' takes place of 'xxx_addr_width' or __ffs() isn't proper here?

Additionally, I will modify this code to consider '_maxburst' field.

__ffs is okay and sensible.
I meant you should use proper fields for passing info, which in this case would be dst_maxburst for specifying destination burst sizes

Signature · 2 lines
~Vinod Koul
Intel Corp.
author
#10 lore raw

PATCH v4 3/14 DMA: PL330: Support DMA_SLAVE_CONFIG command

Vinod Koul Wrote:

Quoted 96 lines

Sent: Monday, July 25, 2011 10:48 PM
To: Boojin Kim
Cc: vinod.koul at intel.com; linux-arm-kernel at lists.infradead.org; linux- samsung-soc at vger.kernel.org; 'Kukjin Kim'; 'Jassi Brar'; 'Grant Likely'; 'Mark Brown'; 'Dan Williams'
Subject: RE: [PATCH V4 03/14] DMA: PL330: Support DMA_SLAVE_CONFIG command

Quoted 4 lines · Boojin Kim

Vinod Koul Wrote:

Quoted 3 lines

Sent: Monday, July 25, 2011 7:27 PM
To: Boojin Kim
Cc: vinod.koul at intel.com; linux-arm-kernel at lists.infradead.org;

linux-

Quoted 11 lines
Quoted 11 lines

samsung-soc at vger.kernel.org; Kukjin Kim; Jassi Brar; Grant Likely; Mark Brown; Dan Williams
Subject: Re: [PATCH V4 03/14] DMA: PL330: Support DMA_SLAVE_CONFIG command

Quoted 5 lines · Boojin Kim

This patch adds support DMA_SLAVE_CONFIG command.

---
 drivers/dma/pl330.c |   53

+++++++++++++++++++++++++++++++++++++----

Quoted 8 lines
Quoted 8 lines

---------

drivers/dma/pl330.c static int

Quoted 7 lines
 1 files changed, 39 insertions(+), 14 deletions(-)
drivers/dma/pl330.c +0 -0
index 586ab39..880f010 100644
@@ -256,25 +256,50 @@ static int

pl330_alloc_chan_resources(struct

Quoted 2 lines
Quoted 2 lines

dma_chan *chan)

Quoted 1 line
drivers/dma/pl330.c +0 -0
 static int pl330_control(struct dma_chan *chan, enum

dma_ctrl_cmd

Quoted 39 lines
Quoted 29 lines

cmd, unsigned long arg)

Quoted 28 lines
drivers/dma/pl330.c +10 -12
 {
 	struct dma_pl330_chan *pch = to_pchan(chan);
-	struct dma_pl330_desc *desc;
+	struct dma_pl330_desc *desc, *_dt;
 	unsigned long flags;
+	struct dma_pl330_dmac *pdmac = pch->dmac;
+	struct dma_slave_config *slave_config;
+	struct dma_pl330_peri *peri;
+	LIST_HEAD(list);
 
-	/* Only supports DMA_TERMINATE_ALL */
-	if (cmd != DMA_TERMINATE_ALL)
-		return -ENXIO;
-
-	spin_lock_irqsave(&pch->lock, flags);
-
-	/* FLUSH the PL330 Channel thread */
-	pl330_chan_ctrl(pch->pl330_chid, PL330_OP_FLUSH);
+	switch (cmd) {
+	case DMA_TERMINATE_ALL:
+		spin_lock_irqsave(&pch->lock, flags);
 
-	/* Mark all desc done */
-	list_for_each_entry(desc, &pch->work_list, node)
-		desc->status = DONE;
+		/* FLUSH the PL330 Channel thread */
+		pl330_chan_ctrl(pch->pl330_chid, PL330_OP_FLUSH);
 
Quoted 3 lines

drivers/dma/pl330.c static int pl330_alloc_chan_resources(struct dma_chan *chan)

Quoted 3 lines
drivers/dma/pl330.c +2 -1
-	spin_unlock_irqrestore(&pch->lock, flags);
+		/* Mark all desc done */
+		list_for_each_entry_safe(desc, _dt, &pch-

work_list , node)

Quoted 6 lines

{

Quoted 5 lines
drivers/dma/pl330.c +4 -0
+			desc->status = DONE;
+			pch->completed = desc->txd.cookie;
+			list_move_tail(&desc->node, &list);
+		}
 
Quoted 16 lines
Quoted 11 lines

drivers/dma/pl330.c static int pl330_alloc_chan_resources(struct dma_chan *chan)

Quoted 11 lines
drivers/dma/pl330.c +10 -1
-	pl330_tasklet((unsigned long) pch);
+		list_splice_tail_init(&list, &pdmac->desc_pool);
+		spin_unlock_irqrestore(&pch->lock, flags);
+		break;
+	case DMA_SLAVE_CONFIG:
+		slave_config = (struct dma_slave_config *)arg;
+		peri = pch->chan.private;
+
+		if (slave_config->direction == DMA_TO_DEVICE) {
+			if (slave_config->dst_addr)
+				peri->fifo_addr = slave_config-

dst_addr;

Quoted 4 lines

drivers/dma/pl330.c static int · line 292

Quoted 3 lines
drivers/dma/pl330.c +2 -0
+			if (slave_config->dst_addr_width)
+				peri->burst_sz = __ffs(slave_config-
 dst_addr_width);

This doesn't sound right, why can't you use xxx_maxburst field

instead?

Quoted 2 lines

Can you explain the problem in more detail?
Do you mean that 'xxx_maxburst' takes place of 'xxx_addr_width' or

Quoted 7 lines

__ffs()

Quoted 3 lines

isn't proper here?

Additionally, I will modify this code to consider '_maxburst' field.

__ffs is okay and sensible.
I meant you should use proper fields for passing info, which in this case would be dst_maxburst for specifying destination burst sizes

I think the naming seems to make confusion.
'Peri->burst_sz' on this code means the width of fifo in bytes of the peri. It's same with the meaning 'xxx_addr_width'. So, I think it's proper usage. 'peri->burst_sz' is passed to PL330 HW. PL330 HW wants to get the power of 2 based the fifo width for it.
For example, If fifo width is 8 bytes, PL330 HW should get '3' for it. And I will modify code to consider xxx_maxburst.

Quoted 3 lines

--
~Vinod Koul
Intel Corp.

#11 lore raw

PATCH v4 3/14 DMA: PL330: Support DMA_SLAVE_CONFIG command

Quoted 10 lines · Boojin Kim

Vinod Koul Wrote:

Quoted 2 lines

I meant you should use proper fields for passing info, which in this case would be dst_maxburst for specifying destination burst sizes

I think the naming seems to make confusion.
'Peri->burst_sz' on this code means the width of fifo in bytes of the peri. It's same with the meaning 'xxx_addr_width'. So, I think it's proper usage. 'peri->burst_sz' is passed to PL330 HW. PL330 HW wants to get the power of 2 based the fifo width for it.
For example, If fifo width is 8 bytes, PL330 HW should get '3' for it. And I will modify code to consider xxx_maxburst.

IMHO from your description above, peri->burst_sz is misnamed. Please add a comment at this location to say something like:

	/* peri->burst_sz is the peripheral fifo width */

to explain this.

Thanks.

author
#12 lore raw

PATCH v4 4/14 DMA: PL330: Add DMA_CYCLIC capability

In reply to Boojin Kim

This patch adds DMA_CYCLIC capability that is used for audio driver. DMA driver with DMA_CYCLIC capability reuses the dma requests that were submitted through tx_submit().

---
 drivers/dma/pl330.c |  111 +++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 111 insertions(+), 0 deletions(-)
drivers/dma/pl330.c +111 -0
index 880f010..121c75a 100644
@@ -69,6 +69,11 @@ struct dma_pl330_chan {
 	 * NULL if the channel is available to be acquired.
 	 */
 	void *pl330_chid;
+
+	/* taks for cyclic capability */
+	struct tasklet_struct *cyclic_task;
+
+	bool cyclic;
 };
 
 struct dma_pl330_dmac {
@@ -184,6 +189,41 @@ static inline void fill_queue(struct dma_pl330_chan *pch)
 	}
 }
 
+static void pl330_tasklet_cyclic(unsigned long data)
+{
+	struct dma_pl330_chan *pch = (struct dma_pl330_chan *)data;
+	struct dma_pl330_desc *desc, *_dt;
+	unsigned long flags;
+	LIST_HEAD(list);
+
+	spin_lock_irqsave(&pch->lock, flags);
+
+	/* Pick up ripe tomatoes */
+	list_for_each_entry_safe(desc, _dt, &pch->work_list, node)
+		if (desc->status == DONE) {
+			dma_async_tx_callback callback;
+
+			list_move_tail(&desc->node, &pch->work_list);
+			pch->completed = desc->txd.cookie;
+
+			desc->status = PREP;
+
+			/* Try to submit a req imm.
+			next to the last completed cookie */
+			fill_queue(pch);
+
+			/* Make sure the PL330 Channel thread is active */
+			pl330_chan_ctrl(pch->pl330_chid, PL330_OP_START);
+
+			callback = desc->txd.callback;
+			if (callback)
+				callback(desc->txd.callback_param);
+
+		}
+
+	spin_unlock_irqrestore(&pch->lock, flags);
+}
+
 static void pl330_tasklet(unsigned long data)
 {
 	struct dma_pl330_chan *pch = (struct dma_pl330_chan *)data;
@@ -227,6 +267,9 @@ static void dma_pl330_rqcb(void *token, enum pl330_op_err err)
 
 	spin_unlock_irqrestore(&pch->lock, flags);
 
+	if (pch->cyclic_task)
+		tasklet_schedule(pch->cyclic_task);
+	else
 	tasklet_schedule(&pch->task);
 }
 
@@ -316,6 +359,15 @@ static void pl330_free_chan_resources(struct dma_chan *chan)
 	pl330_release_channel(pch->pl330_chid);
 	pch->pl330_chid = NULL;
 
+	if (pch->cyclic) {
+		pch->cyclic = false;
+		list_splice_tail_init(&pch->work_list, &pch->dmac->desc_pool);
+		if (pch->cyclic_task) {
+			tasklet_kill(pch->cyclic_task);
+			pch->cyclic_task = NULL;
+		}
+	}
+
 	spin_unlock_irqrestore(&pch->lock, flags);
 }
 
@@ -547,6 +599,63 @@ static inline int get_burst_len(struct dma_pl330_desc *desc, size_t len)
 	return burst_len;
 }
 
+static struct dma_async_tx_descriptor *pl330_prep_dma_cyclic(
+		struct dma_chan *chan, dma_addr_t dma_addr, size_t len,
+		size_t period_len, enum dma_data_direction direction)
+{
+	struct dma_pl330_desc *desc;
+	struct dma_pl330_chan *pch = to_pchan(chan);
+	struct dma_pl330_peri *peri = chan->private;
+	dma_addr_t dst;
+	dma_addr_t src;
+
+	pch = to_pchan(chan);
+	if (!pch)
+		return NULL;
+
+	desc = pl330_get_desc(pch);
+	if (!desc) {
+		dev_err(pch->dmac->pif.dev, "%s:%d Unable to fetch desc\n",
+			__func__, __LINE__);
+		return NULL;
+	}
+
+	switch (direction) {
+	case DMA_TO_DEVICE:
+		desc->rqcfg.src_inc = 1;
+		desc->rqcfg.dst_inc = 0;
+		src = dma_addr;
+		dst = peri->fifo_addr;
+		break;
+	case DMA_FROM_DEVICE:
+		desc->rqcfg.src_inc = 0;
+		desc->rqcfg.dst_inc = 1;
+		src = peri->fifo_addr;
+		dst = dma_addr;
+		break;
+	default:
+		dev_err(pch->dmac->pif.dev, "%s:%d Invalid dma direction\n",
+		__func__, __LINE__);
+		return NULL;
+	}
+
+	desc->rqcfg.brst_size = peri->burst_sz;
+	desc->rqcfg.brst_len = 1;
+
+	if (!pch->cyclic_task) {
+		pch->cyclic_task =
+			kmalloc(sizeof(struct tasklet_struct), GFP_KERNEL);
+		tasklet_init(pch->cyclic_task,
+			pl330_tasklet_cyclic, (unsigned int)pch);
+	}
+
+	pch->cyclic = true;
+
+	fill_px(&desc->px, dst, src, period_len);
+
+	return &desc->txd;
+}
+
 static struct dma_async_tx_descriptor *
 pl330_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dst,
 		dma_addr_t src, size_t len, unsigned long flags)
@@ -780,6 +889,7 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id)
 			case MEMTODEV:
 			case DEVTOMEM:
 				dma_cap_set(DMA_SLAVE, pd->cap_mask);
+				dma_cap_set(DMA_CYCLIC, pd->cap_mask);
 				break;
 			default:
 				dev_err(&adev->dev, "DEVTODEV Not Supported\n");
@@ -805,6 +915,7 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id)
 	pd->device_alloc_chan_resources = pl330_alloc_chan_resources;
 	pd->device_free_chan_resources = pl330_free_chan_resources;
 	pd->device_prep_dma_memcpy = pl330_prep_dma_memcpy;
+	pd->device_prep_dma_cyclic = pl330_prep_dma_cyclic;
 	pd->device_tx_status = pl330_tx_status;
 	pd->device_prep_slave_sg = pl330_prep_slave_sg;
 	pd->device_control = pl330_control;
Signature · 1 line
1.7.1
#13 lore raw

PATCH v4 4/14 DMA: PL330: Add DMA_CYCLIC capability

Quoted 8 lines · Boojin Kim
drivers/dma/pl330.c +8 -0
+static void pl330_tasklet_cyclic(unsigned long data)
+{
+	struct dma_pl330_chan *pch = (struct dma_pl330_chan *)data;
+	struct dma_pl330_desc *desc, *_dt;
+	unsigned long flags;
+	LIST_HEAD(list);
+
+	spin_lock_irqsave(&pch->lock, flags);

...

drivers/dma/pl330.c static inline void fill_queue(struct dma_pl330_chan *pch) · line 220

Quoted 3 lines
drivers/dma/pl330.c +3 -0
+			callback = desc->txd.callback;
+			if (callback)
+				callback(desc->txd.callback_param);

On this again - what if the callback wants to terminate the DMA activity because there's no more audio data to be sent/received from the device?

Quoted 1 line

+

Useless blank line.

Quoted 9 lines
drivers/dma/pl330.c +5 -0
+		}
+
+	spin_unlock_irqrestore(&pch->lock, flags);
+}
+
 static void pl330_tasklet(unsigned long data)
 {
 	struct dma_pl330_chan *pch = (struct dma_pl330_chan *)data;

drivers/dma/pl330.c static void dma_pl330_rqcb(void *token, enum pl330_op_err err) · line 273

Quoted 7 lines
drivers/dma/pl330.c +3 -0
@@ -227,6 +267,9 @@ static void dma_pl330_rqcb(void *token, enum pl330_op_err err)
 
 	spin_unlock_irqrestore(&pch->lock, flags);
 
+	if (pch->cyclic_task)
+		tasklet_schedule(pch->cyclic_task);
+	else
 	tasklet_schedule(&pch->task);

Indentation error.

Quoted 25 lines
drivers/dma/pl330.c +12 -0
 }
 
@@ -316,6 +359,15 @@ static void pl330_free_chan_resources(struct dma_chan *chan)
 	pl330_release_channel(pch->pl330_chid);
 	pch->pl330_chid = NULL;
 
+	if (pch->cyclic) {
+		pch->cyclic = false;
+		list_splice_tail_init(&pch->work_list, &pch->dmac->desc_pool);
+		if (pch->cyclic_task) {
+			tasklet_kill(pch->cyclic_task);
+			pch->cyclic_task = NULL;
+		}
+	}
+
 	spin_unlock_irqrestore(&pch->lock, flags);
 }
 
@@ -547,6 +599,63 @@ static inline int get_burst_len(struct dma_pl330_desc *desc, size_t len)
 	return burst_len;
 }
 
+static struct dma_async_tx_descriptor *pl330_prep_dma_cyclic(
+		struct dma_chan *chan, dma_addr_t dma_addr, size_t len,
+		size_t period_len, enum dma_data_direction direction)

drivers/dma/pl330.c static inline int get_burst_len(struct dma_pl330_desc *desc, size_t len) · line 614

Quoted 10 lines
drivers/dma/pl330.c +10 -0
+{
+	struct dma_pl330_desc *desc;
+	struct dma_pl330_chan *pch = to_pchan(chan);
+	struct dma_pl330_peri *peri = chan->private;
+	dma_addr_t dst;
+	dma_addr_t src;
+
+	pch = to_pchan(chan);
+	if (!pch)
+		return NULL;

You've already done the to_pchan() thing when declaring pch. You've already dereferenced 'chan', so there's no way that pch could be NULL here.

Quoted 25 lines
drivers/dma/pl330.c +25 -0
+
+	desc = pl330_get_desc(pch);
+	if (!desc) {
+		dev_err(pch->dmac->pif.dev, "%s:%d Unable to fetch desc\n",
+			__func__, __LINE__);
+		return NULL;
+	}
+
+	switch (direction) {
+	case DMA_TO_DEVICE:
+		desc->rqcfg.src_inc = 1;
+		desc->rqcfg.dst_inc = 0;
+		src = dma_addr;
+		dst = peri->fifo_addr;
+		break;
+	case DMA_FROM_DEVICE:
+		desc->rqcfg.src_inc = 0;
+		desc->rqcfg.dst_inc = 1;
+		src = peri->fifo_addr;
+		dst = dma_addr;
+		break;
+	default:
+		dev_err(pch->dmac->pif.dev, "%s:%d Invalid dma direction\n",
+		__func__, __LINE__);
+		return NULL;

drivers/dma/pl330.c static inline int get_burst_len(struct dma_pl330_desc *desc, size_t len) · line 649

Quoted 10 lines
drivers/dma/pl330.c +10 -0
+	}
+
+	desc->rqcfg.brst_size = peri->burst_sz;
+	desc->rqcfg.brst_len = 1;
+
+	if (!pch->cyclic_task) {
+		pch->cyclic_task =
+			kmalloc(sizeof(struct tasklet_struct), GFP_KERNEL);
+		tasklet_init(pch->cyclic_task,
+			pl330_tasklet_cyclic, (unsigned int)pch);

Here you allocate memory for the cyclic task. Above you set this pointer to NULL. That sounds like a memory leak to me. Why are you kmallocing this memory - why can't it be part of the dma_pl330_chan structure? It's only 28 bytes.

author
#14 lore raw

PATCH v4 4/14 DMA: PL330: Add DMA_CYCLIC capability

Russell King - ARM Linux Wrote:

Quoted 3 lines

Sent: Monday, July 25, 2011 6:28 PM
To: Boojin Kim
Cc: linux-arm-kernel at lists.infradead.org;

linux-samsung-soc at vger.kernel.org;

Quoted 13 lines

Kukjin Kim; Vinod Koul; Jassi Brar; Grant Likely; Mark Brown; Dan Williams
Subject: Re: [PATCH V4 04/14] DMA: PL330: Add DMA_CYCLIC capability

Quoted 8 lines · Boojin Kim
drivers/dma/pl330.c +8 -0
+static void pl330_tasklet_cyclic(unsigned long data)
+{
+	struct dma_pl330_chan *pch = (struct dma_pl330_chan *)data;
+	struct dma_pl330_desc *desc, *_dt;
+	unsigned long flags;
+	LIST_HEAD(list);
+
+	spin_lock_irqsave(&pch->lock, flags);

...

Quoted 6 lines

drivers/dma/pl330.c static inline void fill_queue(struct dma_pl330_chan *pch) · line 220

Quoted 3 lines
drivers/dma/pl330.c +3 -0
+			callback = desc->txd.callback;
+			if (callback)
+				callback(desc->txd.callback_param);

On this again - what if the callback wants to terminate the DMA activity because there's no more audio data to be sent/received from the device?

Do you mean what is happened if the callback() is called after channel is terminated ?
Or What is happened if Callback() calls 'dma_release_channel()' to terminate DMA?

Quoted 4 lines
Quoted 2 lines

+

Useless blank line.

I will address your comment.

Quoted 12 lines

drivers/dma/pl330.c static void dma_pl330_rqcb(void *token, enum

Quoted 10 lines
drivers/dma/pl330.c +5 -0
+		}
+
+	spin_unlock_irqrestore(&pch->lock, flags);
+}
+
 static void pl330_tasklet(unsigned long data)
 {
 	struct dma_pl330_chan *pch = (struct dma_pl330_chan *)data;
@@ -227,6 +267,9 @@ static void dma_pl330_rqcb(void *token, enum

pl330_op_err err)

Quoted 1 line
Quoted 8 lines

drivers/dma/pl330.c static void dma_pl330_rqcb(void *token, enum pl330_op_err err) · line 273

Quoted 6 lines
drivers/dma/pl330.c +3 -0
 	spin_unlock_irqrestore(&pch->lock, flags);
 
+	if (pch->cyclic_task)
+		tasklet_schedule(pch->cyclic_task);
+	else
 	tasklet_schedule(&pch->task);

Indentation error.

Sorry again.. I will address your comment.

Quoted 4 lines

Review static void pl330_free_chan_resources(struct

Quoted 4 lines

}

(quoted diff) +0 -0
@@ -316,6 +359,15 @@ static void pl330_free_chan_resources(struct

dma_chan

Quoted 7 lines

*chan)

drivers/dma/pl330.c static void pl330_free_chan_resources(struct dma_chan *chan)

Quoted 6 lines
drivers/dma/pl330.c +3 -0
 	pl330_release_channel(pch->pl330_chid);
 	pch->pl330_chid = NULL;
 
+	if (pch->cyclic) {
+		pch->cyclic = false;
+		list_splice_tail_init(&pch->work_list,

&pch->dmac->desc_pool);

Quoted 10 lines

drivers/dma/pl330.c static inline int get_burst_len(struct

Quoted 10 lines
drivers/dma/pl330.c +6 -0
+		if (pch->cyclic_task) {
+			tasklet_kill(pch->cyclic_task);
+			pch->cyclic_task = NULL;
+		}
+	}
+
 	spin_unlock_irqrestore(&pch->lock, flags);
 }
 
@@ -547,6 +599,63 @@ static inline int get_burst_len(struct

dma_pl330_desc

Quoted 13 lines

*desc, size_t len)

Quoted 12 lines
drivers/dma/pl330.c +9 -0
 	return burst_len;
 }
 
+static struct dma_async_tx_descriptor *pl330_prep_dma_cyclic(
+		struct dma_chan *chan, dma_addr_t dma_addr, size_t len,
+		size_t period_len, enum dma_data_direction direction)
+{
+	struct dma_pl330_desc *desc;
+	struct dma_pl330_chan *pch = to_pchan(chan);
+	struct dma_pl330_peri *peri = chan->private;
+	dma_addr_t dst;
+	dma_addr_t src;
Quoted 8 lines

drivers/dma/pl330.c static inline int get_burst_len(struct dma_pl330_desc *desc, size_t len) · line 614

Quoted 4 lines
drivers/dma/pl330.c +4 -0
+
+	pch = to_pchan(chan);
+	if (!pch)
+		return NULL;

You've already done the to_pchan() thing when declaring pch. You've already dereferenced 'chan', so there's no way that pch could be NULL here.

I will address your comment.

Quoted 33 lines
Quoted 33 lines
drivers/dma/pl330.c +32 -0
+
+	desc = pl330_get_desc(pch);
+	if (!desc) {
+		dev_err(pch->dmac->pif.dev, "%s:%d Unable to fetch desc\n",
+			__func__, __LINE__);
+		return NULL;
+	}
+
+	switch (direction) {
+	case DMA_TO_DEVICE:
+		desc->rqcfg.src_inc = 1;
+		desc->rqcfg.dst_inc = 0;
+		src = dma_addr;
+		dst = peri->fifo_addr;
+		break;
+	case DMA_FROM_DEVICE:
+		desc->rqcfg.src_inc = 0;
+		desc->rqcfg.dst_inc = 1;
+		src = peri->fifo_addr;
+		dst = dma_addr;
+		break;
+	default:
+		dev_err(pch->dmac->pif.dev, "%s:%d Invalid dma direction\n",
+		__func__, __LINE__);
+		return NULL;
+	}
+
+	desc->rqcfg.brst_size = peri->burst_sz;
+	desc->rqcfg.brst_len = 1;
+
+	if (!pch->cyclic_task) {
+		pch->cyclic_task =
Quoted 8 lines

drivers/dma/pl330.c static inline int get_burst_len(struct dma_pl330_desc *desc, size_t len) · line 649

Quoted 3 lines
drivers/dma/pl330.c +3 -0
+			kmalloc(sizeof(struct tasklet_struct), GFP_KERNEL);
+		tasklet_init(pch->cyclic_task,
+			pl330_tasklet_cyclic, (unsigned int)pch);

Here you allocate memory for the cyclic task. Above you set this pointer to NULL. That sounds like a memory leak to me. Why are you kmallocing this memory - why can't it be part of the dma_pl330_chan structure? It's only 28 bytes.

It's my mistake. I should have been free of the memory.

And the reason why I use kmalloc for 'cyclic_task' is following. This memory size for 'cyclic_tasklet' is the 896 bytes ( = the number of channel * sizeof(struct tasklet_struct)= 32*28) for each DMAC. And This memory size is increased according to the number of DMAC.
And Samsung has the DMAC that is dedicated for Mem-to-Mem operation. If I make 'cyclic_task' be part of dma_pl330_chan, this DMAC that is dedicated for Mem-to-Mem operation should hold unused data.
So, I think it's loss that all dma channels hold own 'cyclic_task'.

#15 lore raw

PATCH v4 4/14 DMA: PL330: Add DMA_CYCLIC capability

Quoted 17 lines · Boojin Kim
Quoted 10 lines · Boojin Kim
Quoted 8 lines
drivers/dma/pl330.c +8 -0
+static void pl330_tasklet_cyclic(unsigned long data)
+{
+	struct dma_pl330_chan *pch = (struct dma_pl330_chan *)data;
+	struct dma_pl330_desc *desc, *_dt;
+	unsigned long flags;
+	LIST_HEAD(list);
+
+	spin_lock_irqsave(&pch->lock, flags);

...

Quoted 6 lines

drivers/dma/pl330.c static inline void fill_queue(struct dma_pl330_chan *pch) · line 220

Quoted 3 lines
drivers/dma/pl330.c +3 -0
+			callback = desc->txd.callback;
+			if (callback)
+				callback(desc->txd.callback_param);

On this again - what if the callback wants to terminate the DMA activity because there's no more audio data to be sent/received from the device?

Quoted 4 lines

Do you mean what is happened if the callback() is called after channel is terminated ?
Or What is happened if Callback() calls 'dma_release_channel()' to terminate DMA?

No. I mean what if the callback wants to call dmaengine_terminate_all().

Quoted 13 lines
Quoted 10 lines

drivers/dma/pl330.c static inline int get_burst_len(struct dma_pl330_desc *desc, size_t len) · line 649

Quoted 5 lines
drivers/dma/pl330.c +5 -0
+	if (!pch->cyclic_task) {
+		pch->cyclic_task =
+			kmalloc(sizeof(struct tasklet_struct), GFP_KERNEL);
+		tasklet_init(pch->cyclic_task,
+			pl330_tasklet_cyclic, (unsigned int)pch);

Here you allocate memory for the cyclic task. Above you set this pointer to NULL. That sounds like a memory leak to me. Why are you kmallocing this memory - why can't it be part of the dma_pl330_chan structure? It's only 28 bytes.

It's my mistake. I should have been free of the memory.

Quoted 8 lines

And the reason why I use kmalloc for 'cyclic_task' is following. This memory size for 'cyclic_tasklet' is the 896 bytes ( = the number of channel * sizeof(struct tasklet_struct)= 32*28) for each DMAC. And This memory size is increased according to the number of DMAC.
And Samsung has the DMAC that is dedicated for Mem-to-Mem operation. If I make 'cyclic_task' be part of dma_pl330_chan, this DMAC that is dedicated for Mem-to-Mem operation should hold unused data.
So, I think it's loss that all dma channels hold own 'cyclic_task'.

Could you re-use the tasklet that already exists?

#16 lore raw

PATCH v4 4/14 DMA: PL330: Add DMA_CYCLIC capability

Quoted 18 lines · Russell King - ARM Linux
Quoted 17 lines · Boojin Kim
Quoted 16 lines · Boojin Kim
Quoted 8 lines
drivers/dma/pl330.c +8 -0
+static void pl330_tasklet_cyclic(unsigned long data)
+{
+	struct dma_pl330_chan *pch = (struct dma_pl330_chan *)data;
+	struct dma_pl330_desc *desc, *_dt;
+	unsigned long flags;
+	LIST_HEAD(list);
+
+	spin_lock_irqsave(&pch->lock, flags);

...

drivers/dma/pl330.c static inline void fill_queue(struct dma_pl330_chan *pch) · line 220

Quoted 3 lines
drivers/dma/pl330.c +3 -0
+			callback = desc->txd.callback;
+			if (callback)
+				callback(desc->txd.callback_param);

On this again - what if the callback wants to terminate the DMA activity because there's no more audio data to be sent/received from the device?

Quoted 6 lines
Quoted 4 lines

Do you mean what is happened if the callback() is called after channel is terminated ?
Or What is happened if Callback() calls 'dma_release_channel()' to terminate DMA?

No. I mean what if the callback wants to call dmaengine_terminate_all().

you are supposed to drop the lock here, that way callback can call any DMA API, otherwise it will result in deadlock.
This make me wonder you haven't read the documentation at all, please ensure you have read Documentation/dmaengine.txt before next posting

Quoted 24 lines
Quoted 14 lines
Quoted 11 lines

drivers/dma/pl330.c static inline int get_burst_len(struct dma_pl330_desc *desc, size_t len) · line 649

Quoted 6 lines
drivers/dma/pl330.c +5 -0
+	if (!pch->cyclic_task) {
+		pch->cyclic_task =
+			kmalloc(sizeof(struct tasklet_struct), GFP_KERNEL);
+		tasklet_init(pch->cyclic_task,
+			pl330_tasklet_cyclic, (unsigned int)pch);

Here you allocate memory for the cyclic task. Above you set this pointer to NULL. That sounds like a memory leak to me. Why are you kmallocing this memory - why can't it be part of the dma_pl330_chan structure? It's only 28 bytes.

It's my mistake. I should have been free of the memory.

Quoted 8 lines

And the reason why I use kmalloc for 'cyclic_task' is following. This memory size for 'cyclic_tasklet' is the 896 bytes ( = the number of channel * sizeof(struct tasklet_struct)= 32*28) for each DMAC. And This memory size is increased according to the number of DMAC.
And Samsung has the DMAC that is dedicated for Mem-to-Mem operation. If I make 'cyclic_task' be part of dma_pl330_chan, this DMAC that is dedicated for Mem-to-Mem operation should hold unused data.
So, I think it's loss that all dma channels hold own 'cyclic_task'.

Could you re-use the tasklet that already exists?

Signature · 2 lines
~Vinod Koul
Intel Corp.
#17 lore raw

PATCH v4 4/14 DMA: PL330: Add DMA_CYCLIC capability

Quoted 24 lines · Vinod Koul
Quoted 23 lines · Russell King - ARM Linux
Quoted 21 lines · Boojin Kim
Quoted 10 lines · Boojin Kim
Quoted 8 lines
drivers/dma/pl330.c +8 -0
+static void pl330_tasklet_cyclic(unsigned long data)
+{
+	struct dma_pl330_chan *pch = (struct dma_pl330_chan *)data;
+	struct dma_pl330_desc *desc, *_dt;
+	unsigned long flags;
+	LIST_HEAD(list);
+
+	spin_lock_irqsave(&pch->lock, flags);

...

Quoted 6 lines

drivers/dma/pl330.c static inline void fill_queue(struct dma_pl330_chan *pch) · line 220

Quoted 3 lines
drivers/dma/pl330.c +3 -0
+			callback = desc->txd.callback;
+			if (callback)
+				callback(desc->txd.callback_param);

On this again - what if the callback wants to terminate the DMA activity because there's no more audio data to be sent/received from the device?

Do you mean what is happened if the callback() is called after channel is terminated ?
Or What is happened if Callback() calls 'dma_release_channel()' to terminate DMA?

Quoted 5 lines
Quoted 1 line

No. I mean what if the callback wants to call dmaengine_terminate_all().

you are supposed to drop the lock here, that way callback can call any DMA API, otherwise it will result in deadlock.
This make me wonder you haven't read the documentation at all, please ensure you have read Documentation/dmaengine.txt before next posting

I know that very well thank you. Please look at my previous post in the previous round of patches, and the response from Boojin Kim to see why I used this as an *EXAMPLE* to get this fixed.

#18 lore raw

PATCH v4 4/14 DMA: PL330: Add DMA_CYCLIC capability

Quoted 26 lines · Russell King - ARM Linux
Quoted 25 lines · Vinod Koul
Quoted 24 lines · Russell King - ARM Linux
Quoted 17 lines · Boojin Kim
Quoted 10 lines · Boojin Kim
Quoted 8 lines
drivers/dma/pl330.c +8 -0
+static void pl330_tasklet_cyclic(unsigned long data)
+{
+	struct dma_pl330_chan *pch = (struct dma_pl330_chan *)data;
+	struct dma_pl330_desc *desc, *_dt;
+	unsigned long flags;
+	LIST_HEAD(list);
+
+	spin_lock_irqsave(&pch->lock, flags);

...

Quoted 6 lines

drivers/dma/pl330.c static inline void fill_queue(struct dma_pl330_chan *pch) · line 220

Quoted 3 lines
drivers/dma/pl330.c +3 -0
+			callback = desc->txd.callback;
+			if (callback)
+				callback(desc->txd.callback_param);

On this again - what if the callback wants to terminate the DMA activity because there's no more audio data to be sent/received from the device?

Quoted 4 lines

Do you mean what is happened if the callback() is called after channel is terminated ?
Or What is happened if Callback() calls 'dma_release_channel()' to terminate DMA?

No. I mean what if the callback wants to call dmaengine_terminate_all().

Quoted 8 lines
Quoted 4 lines

you are supposed to drop the lock here, that way callback can call any DMA API, otherwise it will result in deadlock.
This make me wonder you haven't read the documentation at all, please ensure you have read Documentation/dmaengine.txt before next posting

I know that very well thank you. Please look at my previous post in the previous round of patches, and the response from Boojin Kim to see why I used this as an *EXAMPLE* to get this fixed.

Russell,
Sorry that was not intended for you but for the author of patch Boojin Kim... Agree on your EXAMPLE, just wanted to ensure authors have read it as going thru this patch made it clear that they haven't.

Signature · 2 lines
~Vinod Koul
Intel Corp.
#19 lore raw

PATCH v4 4/14 DMA: PL330: Add DMA_CYCLIC capability

Quoted 7 lines · Vinod Koul
Quoted 3 lines

I know that very well thank you. Please look at my previous post in the previous round of patches, and the response from Boojin Kim to see why I used this as an *EXAMPLE* to get this fixed.

Russell,
Sorry that was not intended for you but for the author of patch Boojin Kim... Agree on your EXAMPLE, just wanted to ensure authors have read it as going thru this patch made it clear that they haven't.

That wasn't obvious because of the To: and the use of 'you' in your reply.

In any case, let's fix up the documentation to be a little more complete and expansive about these conditions, and improve its formatting so it's easier to read.

A few points:

1. This really should describe the dma_slave_config structure in detail (or refer to the documentation in dmaengine.h) especially describing what is mandatory there.

2. Note the filter function thing - I think this should be mandatory for slave and cyclic channels. These typically have a DMA request signal associated with each channel, and so 'any random channel' isn't really acceptable like it is for the async_tx APIs.

3. I think this should specify that dmaengine_slave_config() should be specified as mandatory after obtaining the DMA engine channel.

Any comments on this before I prepare this as a proper patch?

Documentation/dmaengine.txt +140 -64
index 5a0cb1e..8ba8d3c 100644
@@ -10,87 +10,163 @@
 Below is a guide to device driver writers on how to use the Slave-DMA API of the
 DMA Engine. This is applicable only for slave DMA usage only.
 
-The slave DMA usage consists of following steps
+The slave DMA usage consists of following steps:
 1. Allocate a DMA slave channel
 2. Set slave and controller specific parameters
 3. Get a descriptor for transaction
 4. Submit the transaction and wait for callback notification
+5. Issue pending requests
 
 1. Allocate a DMA slave channel
-Channel allocation is slightly different in the slave DMA context, client
-drivers typically need a channel from a particular DMA controller only and even
-in some cases a specific channel is desired. To request a channel
-dma_request_channel() API is used.
-
-Interface:
-struct dma_chan *dma_request_channel(dma_cap_mask_t mask,
-		dma_filter_fn filter_fn,
-		void *filter_param);
-where dma_filter_fn is defined as:
-typedef bool (*dma_filter_fn)(struct dma_chan *chan, void *filter_param);
-
-When the optional 'filter_fn' parameter is set to NULL dma_request_channel
-simply returns the first channel that satisfies the capability mask.  Otherwise,
-when the mask parameter is insufficient for specifying the necessary channel,
-the filter_fn routine can be used to disposition the available channels in the
-system. The filter_fn routine is called once for each free channel in the
-system.  Upon seeing a suitable channel filter_fn returns DMA_ACK which flags
-that channel to be the return value from dma_request_channel.  A channel
-allocated via this interface is exclusive to the caller, until
-dma_release_channel() is called.
+
+   Channel allocation is slightly different in the slave DMA context,
+   client drivers typically need a channel from a particular DMA
+   controller only and even in some cases a specific channel is desired.
+   To request a channel dma_request_channel() API is used.
+
+   Interface:
+	struct dma_chan *dma_request_channel(dma_cap_mask_t mask,
+			dma_filter_fn filter_fn,
+			void *filter_param);
+   where dma_filter_fn is defined as:
+	typedef bool (*dma_filter_fn)(struct dma_chan *chan, void *filter_param);
+
+   The 'filter_fn' parameter is optional, but highly recommended for
+   slave and cyclic channels as they typically need to obtain a specific
+   DMA channel.
+
+   When the optional 'filter_fn' parameter is NULL, dma_request_channel()
+   simply returns the first channel that satisfies the capability mask.
+
+   Otherwise, the 'filter_fn' routine will be called once for each free
+   channel which has a capability in 'mask'.  'filter_fn' is expected to
+   return 'true' when the desired DMA channel is found.
+
+   A channel allocated via this interface is exclusive to the caller,
+   until dma_release_channel() is called.
 
 2. Set slave and controller specific parameters
-Next step is always to pass some specific information to the DMA driver. Most of
-the generic information which a slave DMA can use is in struct dma_slave_config.
-It allows the clients to specify DMA direction, DMA addresses, bus widths, DMA
-burst lengths etc. If some DMA controllers have more parameters to be sent then
-they should try to embed struct dma_slave_config in their controller specific
-structure. That gives flexibility to client to pass more parameters, if
-required.
-
-Interface:
-int dmaengine_slave_config(struct dma_chan *chan,
-					  struct dma_slave_config *config)
+
+   Next step is always to pass some specific information to the DMA
+   driver.  Most of the generic information which a slave DMA can use
+   is in struct dma_slave_config.  This allows the clients to specify
+   DMA direction, DMA addresses, bus widths, DMA burst lengths etc
+   for the peripheral.
+
+   If some DMA controllers have more parameters to be sent then they
+   should try to embed struct dma_slave_config in their controller
+   specific structure. That gives flexibility to client to pass more
+   parameters, if required.
+
+   Interface:
+	int dmaengine_slave_config(struct dma_chan *chan,
+				  struct dma_slave_config *config)
 
 3. Get a descriptor for transaction
-For slave usage the various modes of slave transfers supported by the
-DMA-engine are:
-slave_sg	- DMA a list of scatter gather buffers from/to a peripheral
-dma_cyclic	- Perform a cyclic DMA operation from/to a peripheral till the
+
+   For slave usage the various modes of slave transfers supported by the
+   DMA-engine are:
+
+   slave_sg	- DMA a list of scatter gather buffers from/to a peripheral
+   dma_cyclic	- Perform a cyclic DMA operation from/to a peripheral till the
 		  operation is explicitly stopped.
-The non NULL return of this transfer API represents a "descriptor" for the given
-transaction.
 
-Interface:
-struct dma_async_tx_descriptor *(*chan->device->device_prep_dma_sg)(
+   A non-NULL return of this transfer API represents a "descriptor" for
+   the given transaction.
+
+   Interface:
+	struct dma_async_tx_descriptor *(*chan->device->device_prep_dma_sg)(
 		struct dma_chan *chan,
 		struct scatterlist *dst_sg, unsigned int dst_nents,
 		struct scatterlist *src_sg, unsigned int src_nents,
 		unsigned long flags);
-struct dma_async_tx_descriptor *(*chan->device->device_prep_dma_cyclic)(
+
+	struct dma_async_tx_descriptor *(*chan->device->device_prep_dma_cyclic)(
 		struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len,
 		size_t period_len, enum dma_data_direction direction);
 
+   Once a descriptor has been obtained, the callback information can be
+   added and must then be submitted.  Some DMA engine drivers may hold a
+   spinlock between a successful preparation and submission so it is
+   important that these two operations are closely paired.
+
+   Note:
+	Although the async_tx API specifies that completion callback
+	routines cannot submit any new operations, this is not the
+	case for slave/cyclic DMA.
+
+	For slave DMA, the subsequent transaction may not be available
+	for submission prior to callback function being invoked, so
+	slave DMA callbacks are permitted to prepare and submit a new
+	transaction.
+
+	For cyclic DMA, a callback function may wish to terminate the
+	DMA via dmaengine_terminate_all().
+
+	Therefore, it is important that DMA engine drivers drop any
+	locks before calling the callback function which may cause a
+	deadlock.
+
+	Note that callbacks will always be invoked from the DMA
+	engines tasklet, never from interrupt context.
+
 4. Submit the transaction and wait for callback notification
-To schedule the transaction to be scheduled by dma device, the "descriptor"
-returned in above (3) needs to be submitted.
-To tell the dma driver that a transaction is ready to be serviced, the
-descriptor->submit() callback needs to be invoked. This chains the descriptor to
-the pending queue.
-The transactions in the pending queue can be activated by calling the
-issue_pending API. If channel is idle then the first transaction in queue is
-started and subsequent ones queued up.
-On completion of the DMA operation the next in queue is submitted and a tasklet
-triggered. The tasklet would then call the client driver completion callback
-routine for notification, if set.
-Interface:
-void dma_async_issue_pending(struct dma_chan *chan);
-
-==============================================================================
-
-Additional usage notes for dma driver writers
-1/ Although DMA engine specifies that completion callback routines cannot submit
-any new operations, but typically for slave DMA subsequent transaction may not
-be available for submit prior to callback routine being called. This requirement
-is not a requirement for DMA-slave devices. But they should take care to drop
-the spin-lock they might be holding before calling the callback routine
+
+   Once the descriptor has been prepared and the callback information
+   added, it must be placed on the DMA engine drivers pending queue.
+
+   Interface:
+	dma_cookie_t dmaengine_submit(struct dma_async_tx_descriptor *desc)
+
+   This returns a cookie can be used to check the progress of DMA engine
+   activity via other DMA engine calls not covered in this document.
+
+   dmaengine_submit() will not start the DMA operation, it merely adds
+   it to the pending queue.  For this, see step 5, dma_async_issue_pending.
+
+5. Issue pending DMA requests
+
+   The transactions in the pending queue can be activated by calling the
+   issue_pending API. If channel is idle then the first transaction in
+   queue is started and subsequent ones queued up.
+
+   On completion of each DMA operation, the next in queue is started and
+   a tasklet triggered. The tasklet will then call the client driver
+   completion callback routine for notification, if set.
+
+   Interface:
+	void dma_async_issue_pending(struct dma_chan *chan);
+
+Further APIs:
+
+1. int dmaengine_terminate_all(struct dma_chan *chan)
+
+   This causes all activity for the DMA channel to be stopped, and may
+   discard data in the DMA FIFO which hasn't been fully transferred.
+   No callback functions will be called for any incomplete transfers.
+
+2. int dmaengine_pause(struct dma_chan *chan)
+
+   This pauses activity on the DMA channel without data loss.
+
+3. int dmaengine_resume(struct dma_chan *chan)
+
+   Resume a previously paused DMA channel.  It is invalid to resume a
+   channel which is not currently paused.
+
+4. enum dma_status dma_async_is_tx_complete(struct dma_chan *chan,
+        dma_cookie_t cookie, dma_cookie_t *last, dma_cookie_t *used)
+
+   This can be used to check the status of the channel.  Please see
+   the documentation in include/linux/dmaengine.h for a more complete
+   description of this API.
+
+   This can be used in conjunction with dma_async_is_complete() and
+   the cookie returned from 'descriptor->submit()' to check for
+   completion of a specific DMA transaction.
+
+   Note:
+	Not all DMA engine drivers can return reliable information for
+	a running DMA channel.  It is recommended that DMA engine users
+	pause or stop (via dmaengine_terminate_all) the channel before
+	using this API.
#20 lore raw

PATCH v4 4/14 DMA: PL330: Add DMA_CYCLIC capability

Quoted 10 lines · Russell King - ARM Linux
Quoted 7 lines · Vinod Koul
Quoted 3 lines

I know that very well thank you. Please look at my previous post in the previous round of patches, and the response from Boojin Kim to see why I used this as an *EXAMPLE* to get this fixed.

Russell,
Sorry that was not intended for you but for the author of patch Boojin Kim... Agree on your EXAMPLE, just wanted to ensure authors have read it as going thru this patch made it clear that they haven't.

That wasn't obvious because of the To: and the use of 'you' in your reply.

Laziness on a rainy monday evening caused me to miss that

Quoted 10 lines

In any case, let's fix up the documentation to be a little more complete and expansive about these conditions, and improve its formatting so it's easier to read.

A few points:

1. This really should describe the dma_slave_config structure in detail (or refer to the documentation in dmaengine.h) especially describing what is mandatory there.

I think you missed mandatory fields here, Pls note I am dropping the direction field in this, as we have discussed it makes no sense

Quoted 152 lines

2. Note the filter function thing - I think this should be mandatory for slave and cyclic channels. These typically have a DMA request signal associated with each channel, and so 'any random channel' isn't really acceptable like it is for the async_tx APIs.

3. I think this should specify that dmaengine_slave_config() should be specified as mandatory after obtaining the DMA engine channel.

Any comments on this before I prepare this as a proper patch?

Documentation/dmaengine.txt +72 -42
index 5a0cb1e..8ba8d3c 100644
@@ -10,87 +10,163 @@
 Below is a guide to device driver writers on how to use the Slave-DMA API of the
 DMA Engine. This is applicable only for slave DMA usage only.
 
-The slave DMA usage consists of following steps
+The slave DMA usage consists of following steps:
 1. Allocate a DMA slave channel
 2. Set slave and controller specific parameters
 3. Get a descriptor for transaction
 4. Submit the transaction and wait for callback notification
+5. Issue pending requests
 
 1. Allocate a DMA slave channel
-Channel allocation is slightly different in the slave DMA context, client
-drivers typically need a channel from a particular DMA controller only and even
-in some cases a specific channel is desired. To request a channel
-dma_request_channel() API is used.
-
-Interface:
-struct dma_chan *dma_request_channel(dma_cap_mask_t mask,
-		dma_filter_fn filter_fn,
-		void *filter_param);
-where dma_filter_fn is defined as:
-typedef bool (*dma_filter_fn)(struct dma_chan *chan, void *filter_param);
-
-When the optional 'filter_fn' parameter is set to NULL dma_request_channel
-simply returns the first channel that satisfies the capability mask.  Otherwise,
-when the mask parameter is insufficient for specifying the necessary channel,
-the filter_fn routine can be used to disposition the available channels in the
-system. The filter_fn routine is called once for each free channel in the
-system.  Upon seeing a suitable channel filter_fn returns DMA_ACK which flags
-that channel to be the return value from dma_request_channel.  A channel
-allocated via this interface is exclusive to the caller, until
-dma_release_channel() is called.
+
+   Channel allocation is slightly different in the slave DMA context,
+   client drivers typically need a channel from a particular DMA
+   controller only and even in some cases a specific channel is desired.
+   To request a channel dma_request_channel() API is used.
+
+   Interface:
+	struct dma_chan *dma_request_channel(dma_cap_mask_t mask,
+			dma_filter_fn filter_fn,
+			void *filter_param);
+   where dma_filter_fn is defined as:
+	typedef bool (*dma_filter_fn)(struct dma_chan *chan, void *filter_param);
+
+   The 'filter_fn' parameter is optional, but highly recommended for
+   slave and cyclic channels as they typically need to obtain a specific
+   DMA channel.
+
+   When the optional 'filter_fn' parameter is NULL, dma_request_channel()
+   simply returns the first channel that satisfies the capability mask.
+
+   Otherwise, the 'filter_fn' routine will be called once for each free
+   channel which has a capability in 'mask'.  'filter_fn' is expected to
+   return 'true' when the desired DMA channel is found.
+
+   A channel allocated via this interface is exclusive to the caller,
+   until dma_release_channel() is called.
 
 2. Set slave and controller specific parameters
-Next step is always to pass some specific information to the DMA driver. Most of
-the generic information which a slave DMA can use is in struct dma_slave_config.
-It allows the clients to specify DMA direction, DMA addresses, bus widths, DMA
-burst lengths etc. If some DMA controllers have more parameters to be sent then
-they should try to embed struct dma_slave_config in their controller specific
-structure. That gives flexibility to client to pass more parameters, if
-required.
-
-Interface:
-int dmaengine_slave_config(struct dma_chan *chan,
-					  struct dma_slave_config *config)
+
+   Next step is always to pass some specific information to the DMA
+   driver.  Most of the generic information which a slave DMA can use
+   is in struct dma_slave_config.  This allows the clients to specify
+   DMA direction, DMA addresses, bus widths, DMA burst lengths etc
+   for the peripheral.
+
+   If some DMA controllers have more parameters to be sent then they
+   should try to embed struct dma_slave_config in their controller
+   specific structure. That gives flexibility to client to pass more
+   parameters, if required.
+
+   Interface:
+	int dmaengine_slave_config(struct dma_chan *chan,
+				  struct dma_slave_config *config)
 
 3. Get a descriptor for transaction
-For slave usage the various modes of slave transfers supported by the
-DMA-engine are:
-slave_sg	- DMA a list of scatter gather buffers from/to a peripheral
-dma_cyclic	- Perform a cyclic DMA operation from/to a peripheral till the
+
+   For slave usage the various modes of slave transfers supported by the
+   DMA-engine are:
+
+   slave_sg	- DMA a list of scatter gather buffers from/to a peripheral
+   dma_cyclic	- Perform a cyclic DMA operation from/to a peripheral till the
 		  operation is explicitly stopped.
-The non NULL return of this transfer API represents a "descriptor" for the given
-transaction.
 
-Interface:
-struct dma_async_tx_descriptor *(*chan->device->device_prep_dma_sg)(
+   A non-NULL return of this transfer API represents a "descriptor" for
+   the given transaction.
+
+   Interface:
+	struct dma_async_tx_descriptor *(*chan->device->device_prep_dma_sg)(
 		struct dma_chan *chan,
 		struct scatterlist *dst_sg, unsigned int dst_nents,
 		struct scatterlist *src_sg, unsigned int src_nents,
 		unsigned long flags);
-struct dma_async_tx_descriptor *(*chan->device->device_prep_dma_cyclic)(
+
+	struct dma_async_tx_descriptor *(*chan->device->device_prep_dma_cyclic)(
 		struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len,
 		size_t period_len, enum dma_data_direction direction);
 
+   Once a descriptor has been obtained, the callback information can be
+   added and must then be submitted.  Some DMA engine drivers may hold a
+   spinlock between a successful preparation and submission so it is
+   important that these two operations are closely paired.
+
+   Note:
+	Although the async_tx API specifies that completion callback
+	routines cannot submit any new operations, this is not the
+	case for slave/cyclic DMA.
+
+	For slave DMA, the subsequent transaction may not be available
+	for submission prior to callback function being invoked, so
+	slave DMA callbacks are permitted to prepare and submit a new
+	transaction.
+
+	For cyclic DMA, a callback function may wish to terminate the

Documentation/dmaengine.txt line 113

Quoted 10 lines
Documentation/dmaengine.txt +9 -0
+	DMA via dmaengine_terminate_all().
+
+	Therefore, it is important that DMA engine drivers drop any
+	locks before calling the callback function which may cause a
+	deadlock.
+
+	Note that callbacks will always be invoked from the DMA
+	engines tasklet, never from interrupt context.
+
 4. Submit the transaction and wait for callback notification

As you are adding 5 for issue pending then this needs change

Quoted 26 lines
Documentation/dmaengine.txt +4 -22
-To schedule the transaction to be scheduled by dma device, the "descriptor"
-returned in above (3) needs to be submitted.
-To tell the dma driver that a transaction is ready to be serviced, the
-descriptor->submit() callback needs to be invoked. This chains the descriptor to
-the pending queue.
-The transactions in the pending queue can be activated by calling the
-issue_pending API. If channel is idle then the first transaction in queue is
-started and subsequent ones queued up.
-On completion of the DMA operation the next in queue is submitted and a tasklet
-triggered. The tasklet would then call the client driver completion callback
-routine for notification, if set.
-Interface:
-void dma_async_issue_pending(struct dma_chan *chan);
-
-==============================================================================
-
-Additional usage notes for dma driver writers
-1/ Although DMA engine specifies that completion callback routines cannot submit
-any new operations, but typically for slave DMA subsequent transaction may not
-be available for submit prior to callback routine being called. This requirement
-is not a requirement for DMA-slave devices. But they should take care to drop
-the spin-lock they might be holding before calling the callback routine
+
+   Once the descriptor has been prepared and the callback information
+   added, it must be placed on the DMA engine drivers pending queue.
+

Documentation/dmaengine.txt line 127

Quoted 10 lines
Documentation/dmaengine.txt +10 -0
+   Interface:
+	dma_cookie_t dmaengine_submit(struct dma_async_tx_descriptor *desc)
+
+   This returns a cookie can be used to check the progress of DMA engine
+   activity via other DMA engine calls not covered in this document.
+
+   dmaengine_submit() will not start the DMA operation, it merely adds
+   it to the pending queue.  For this, see step 5, dma_async_issue_pending.
+
+5. Issue pending DMA requests

and getting callback notification

Quoted 46 lines
Documentation/dmaengine.txt +45 -0
+
+   The transactions in the pending queue can be activated by calling the
+   issue_pending API. If channel is idle then the first transaction in
+   queue is started and subsequent ones queued up.
+
+   On completion of each DMA operation, the next in queue is started and
+   a tasklet triggered. The tasklet will then call the client driver
+   completion callback routine for notification, if set.
+
+   Interface:
+	void dma_async_issue_pending(struct dma_chan *chan);
+
+Further APIs:
+
+1. int dmaengine_terminate_all(struct dma_chan *chan)
+
+   This causes all activity for the DMA channel to be stopped, and may
+   discard data in the DMA FIFO which hasn't been fully transferred.
+   No callback functions will be called for any incomplete transfers.
+
+2. int dmaengine_pause(struct dma_chan *chan)
+
+   This pauses activity on the DMA channel without data loss.
+
+3. int dmaengine_resume(struct dma_chan *chan)
+
+   Resume a previously paused DMA channel.  It is invalid to resume a
+   channel which is not currently paused.
+
+4. enum dma_status dma_async_is_tx_complete(struct dma_chan *chan,
+        dma_cookie_t cookie, dma_cookie_t *last, dma_cookie_t *used)
+
+   This can be used to check the status of the channel.  Please see
+   the documentation in include/linux/dmaengine.h for a more complete
+   description of this API.
+
+   This can be used in conjunction with dma_async_is_complete() and
+   the cookie returned from 'descriptor->submit()' to check for
+   completion of a specific DMA transaction.
+
+   Note:
+	Not all DMA engine drivers can return reliable information for
+	a running DMA channel.  It is recommended that DMA engine users
+	pause or stop (via dmaengine_terminate_all) the channel before
+	using this API.
Signature · 2 lines
~Vinod Koul
Intel Corp.
#21 lore raw

PATCH 1/1 Improve slave/cyclic DMA engine documentation (was: [PATCH V4 04/14] DMA: PL330: Add DMA_CYCLIC capability)

Here's an updated patch.

8<----------
From: Russell King <[email protected]>
DMAEngine: Improve slave/cyclic documentation

Improve the documentation for the slave and cyclic DMA engine support reformatting it for easier reading, adding further APIs, splitting it into five steps, and including references to the documentation in dmaengine.h.

---
 Documentation/dmaengine.txt |  211 ++++++++++++++++++++++++++++++-------------
 1 files changed, 146 insertions(+), 65 deletions(-)
Documentation/dmaengine.txt +146 -65
index 5a0cb1e..8c2e888 100644
@@ -10,87 +10,168 @@
 Below is a guide to device driver writers on how to use the Slave-DMA API of the
 DMA Engine. This is applicable only for slave DMA usage only.
 
-The slave DMA usage consists of following steps
+The slave DMA usage consists of following steps:
 1. Allocate a DMA slave channel
 2. Set slave and controller specific parameters
 3. Get a descriptor for transaction
 4. Submit the transaction and wait for callback notification
+5. Issue pending requests
 
 1. Allocate a DMA slave channel
-Channel allocation is slightly different in the slave DMA context, client
-drivers typically need a channel from a particular DMA controller only and even
-in some cases a specific channel is desired. To request a channel
-dma_request_channel() API is used.
-
-Interface:
-struct dma_chan *dma_request_channel(dma_cap_mask_t mask,
-		dma_filter_fn filter_fn,
-		void *filter_param);
-where dma_filter_fn is defined as:
-typedef bool (*dma_filter_fn)(struct dma_chan *chan, void *filter_param);
-
-When the optional 'filter_fn' parameter is set to NULL dma_request_channel
-simply returns the first channel that satisfies the capability mask.  Otherwise,
-when the mask parameter is insufficient for specifying the necessary channel,
-the filter_fn routine can be used to disposition the available channels in the
-system. The filter_fn routine is called once for each free channel in the
-system.  Upon seeing a suitable channel filter_fn returns DMA_ACK which flags
-that channel to be the return value from dma_request_channel.  A channel
-allocated via this interface is exclusive to the caller, until
-dma_release_channel() is called.
+
+   Channel allocation is slightly different in the slave DMA context,
+   client drivers typically need a channel from a particular DMA
+   controller only and even in some cases a specific channel is desired.
+   To request a channel dma_request_channel() API is used.
+
+   Interface:
+	struct dma_chan *dma_request_channel(dma_cap_mask_t mask,
+			dma_filter_fn filter_fn,
+			void *filter_param);
+   where dma_filter_fn is defined as:
+	typedef bool (*dma_filter_fn)(struct dma_chan *chan, void *filter_param);
+
+   The 'filter_fn' parameter is optional, but highly recommended for
+   slave and cyclic channels as they typically need to obtain a specific
+   DMA channel.
+
+   When the optional 'filter_fn' parameter is NULL, dma_request_channel()
+   simply returns the first channel that satisfies the capability mask.
+
+   Otherwise, the 'filter_fn' routine will be called once for each free
+   channel which has a capability in 'mask'.  'filter_fn' is expected to
+   return 'true' when the desired DMA channel is found.
+
+   A channel allocated via this interface is exclusive to the caller,
+   until dma_release_channel() is called.
 
 2. Set slave and controller specific parameters
-Next step is always to pass some specific information to the DMA driver. Most of
-the generic information which a slave DMA can use is in struct dma_slave_config.
-It allows the clients to specify DMA direction, DMA addresses, bus widths, DMA
-burst lengths etc. If some DMA controllers have more parameters to be sent then
-they should try to embed struct dma_slave_config in their controller specific
-structure. That gives flexibility to client to pass more parameters, if
-required.
-
-Interface:
-int dmaengine_slave_config(struct dma_chan *chan,
-					  struct dma_slave_config *config)
+
+   Next step is always to pass some specific information to the DMA
+   driver.  Most of the generic information which a slave DMA can use
+   is in struct dma_slave_config.  This allows the clients to specify
+   DMA direction, DMA addresses, bus widths, DMA burst lengths etc
+   for the peripheral.
+
+   If some DMA controllers have more parameters to be sent then they
+   should try to embed struct dma_slave_config in their controller
+   specific structure. That gives flexibility to client to pass more
+   parameters, if required.
+
+   Interface:
+	int dmaengine_slave_config(struct dma_chan *chan,
+				  struct dma_slave_config *config)
+
+   Please see the dma_slave_config structure definition in dmaengine.h
+   for a detailed explaination of the struct members.  Please note
+   that the 'direction' member will be going away as it duplicates the
+   direction given in the prepare call.
 
 3. Get a descriptor for transaction
-For slave usage the various modes of slave transfers supported by the
-DMA-engine are:
-slave_sg	- DMA a list of scatter gather buffers from/to a peripheral
-dma_cyclic	- Perform a cyclic DMA operation from/to a peripheral till the
+
+   For slave usage the various modes of slave transfers supported by the
+   DMA-engine are:
+
+   slave_sg	- DMA a list of scatter gather buffers from/to a peripheral
+   dma_cyclic	- Perform a cyclic DMA operation from/to a peripheral till the
 		  operation is explicitly stopped.
-The non NULL return of this transfer API represents a "descriptor" for the given
-transaction.
 
-Interface:
-struct dma_async_tx_descriptor *(*chan->device->device_prep_dma_sg)(
+   A non-NULL return of this transfer API represents a "descriptor" for
+   the given transaction.
+
+   Interface:
+	struct dma_async_tx_descriptor *(*chan->device->device_prep_dma_sg)(
 		struct dma_chan *chan,
 		struct scatterlist *dst_sg, unsigned int dst_nents,
 		struct scatterlist *src_sg, unsigned int src_nents,
 		unsigned long flags);
-struct dma_async_tx_descriptor *(*chan->device->device_prep_dma_cyclic)(
+
+	struct dma_async_tx_descriptor *(*chan->device->device_prep_dma_cyclic)(
 		struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len,
 		size_t period_len, enum dma_data_direction direction);
 
-4. Submit the transaction and wait for callback notification
-To schedule the transaction to be scheduled by dma device, the "descriptor"
-returned in above (3) needs to be submitted.
-To tell the dma driver that a transaction is ready to be serviced, the
-descriptor->submit() callback needs to be invoked. This chains the descriptor to
-the pending queue.
-The transactions in the pending queue can be activated by calling the
-issue_pending API. If channel is idle then the first transaction in queue is
-started and subsequent ones queued up.
-On completion of the DMA operation the next in queue is submitted and a tasklet
-triggered. The tasklet would then call the client driver completion callback
-routine for notification, if set.
-Interface:
-void dma_async_issue_pending(struct dma_chan *chan);
-
-==============================================================================
-
-Additional usage notes for dma driver writers
-1/ Although DMA engine specifies that completion callback routines cannot submit
-any new operations, but typically for slave DMA subsequent transaction may not
-be available for submit prior to callback routine being called. This requirement
-is not a requirement for DMA-slave devices. But they should take care to drop
-the spin-lock they might be holding before calling the callback routine
+   Once a descriptor has been obtained, the callback information can be
+   added and must then be submitted.  Some DMA engine drivers may hold a
+   spinlock between a successful preparation and submission so it is
+   important that these two operations are closely paired.
+
+   Note:
+	Although the async_tx API specifies that completion callback
+	routines cannot submit any new operations, this is not the
+	case for slave/cyclic DMA.
+
+	For slave DMA, the subsequent transaction may not be available
+	for submission prior to callback function being invoked, so
+	slave DMA callbacks are permitted to prepare and submit a new
+	transaction.
+
+	For cyclic DMA, a callback function may wish to terminate the
+	DMA via dmaengine_terminate_all().
+
+	Therefore, it is important that DMA engine drivers drop any
+	locks before calling the callback function which may cause a
+	deadlock.
+
+	Note that callbacks will always be invoked from the DMA
+	engines tasklet, never from interrupt context.
+
+4. Submit the transaction
+
+   Once the descriptor has been prepared and the callback information
+   added, it must be placed on the DMA engine drivers pending queue.
+
+   Interface:
+	dma_cookie_t dmaengine_submit(struct dma_async_tx_descriptor *desc)
+
+   This returns a cookie can be used to check the progress of DMA engine
+   activity via other DMA engine calls not covered in this document.
+
+   dmaengine_submit() will not start the DMA operation, it merely adds
+   it to the pending queue.  For this, see step 5, dma_async_issue_pending.
+
+5. Issue pending DMA requests and wait for callback notification
+
+   The transactions in the pending queue can be activated by calling the
+   issue_pending API. If channel is idle then the first transaction in
+   queue is started and subsequent ones queued up.
+
+   On completion of each DMA operation, the next in queue is started and
+   a tasklet triggered. The tasklet will then call the client driver
+   completion callback routine for notification, if set.
+
+   Interface:
+	void dma_async_issue_pending(struct dma_chan *chan);
+
+Further APIs:
+
+1. int dmaengine_terminate_all(struct dma_chan *chan)
+
+   This causes all activity for the DMA channel to be stopped, and may
+   discard data in the DMA FIFO which hasn't been fully transferred.
+   No callback functions will be called for any incomplete transfers.
+
+2. int dmaengine_pause(struct dma_chan *chan)
+
+   This pauses activity on the DMA channel without data loss.
+
+3. int dmaengine_resume(struct dma_chan *chan)
+
+   Resume a previously paused DMA channel.  It is invalid to resume a
+   channel which is not currently paused.
+
+4. enum dma_status dma_async_is_tx_complete(struct dma_chan *chan,
+        dma_cookie_t cookie, dma_cookie_t *last, dma_cookie_t *used)
+
+   This can be used to check the status of the channel.  Please see
+   the documentation in include/linux/dmaengine.h for a more complete
+   description of this API.
+
+   This can be used in conjunction with dma_async_is_complete() and
+   the cookie returned from 'descriptor->submit()' to check for
+   completion of a specific DMA transaction.
+
+   Note:
+	Not all DMA engine drivers can return reliable information for
+	a running DMA channel.  It is recommended that DMA engine users
+	pause or stop (via dmaengine_terminate_all) the channel before
+	using this API.
#22 lore raw

PATCH 1/1 Improve slave/cyclic DMA engine documentation (was: [PATCH V4 04/14] DMA: PL330: Add DMA_CYCLIC capability)

Quoted 21 lines · Russell King - ARM Linux

Here's an updated patch.

8<----------
From: Russell King <[email protected]>
DMAEngine: Improve slave/cyclic documentation

Improve the documentation for the slave and cyclic DMA engine support reformatting it for easier reading, adding further APIs, splitting it into five steps, and including references to the documentation in dmaengine.h.

---
 Documentation/dmaengine.txt |  211 ++++++++++++++++++++++++++++++-------------
 1 files changed, 146 insertions(+), 65 deletions(-)
Documentation/dmaengine.txt +0 -0
index 5a0cb1e..8c2e888 100644

Documentation/dmaengine.txt line 18

Quoted 10 lines
Documentation/dmaengine.txt +2 -1
@@ -10,87 +10,168 @@
 Below is a guide to device driver writers on how to use the Slave-DMA API of the
 DMA Engine. This is applicable only for slave DMA usage only.
 
-The slave DMA usage consists of following steps
+The slave DMA usage consists of following steps:
 1. Allocate a DMA slave channel
 2. Set slave and controller specific parameters
 3. Get a descriptor for transaction
 4. Submit the transaction and wait for callback notification
+5. Issue pending requests

Thanks Russell,

Applied with change to 4 above. Moved "and wait for callback notification" to 5.

Quoted 228 lines
Documentation/dmaengine.txt +144 -64
 1. Allocate a DMA slave channel
-Channel allocation is slightly different in the slave DMA context, client
-drivers typically need a channel from a particular DMA controller only and even
-in some cases a specific channel is desired. To request a channel
-dma_request_channel() API is used.
-
-Interface:
-struct dma_chan *dma_request_channel(dma_cap_mask_t mask,
-		dma_filter_fn filter_fn,
-		void *filter_param);
-where dma_filter_fn is defined as:
-typedef bool (*dma_filter_fn)(struct dma_chan *chan, void *filter_param);
-
-When the optional 'filter_fn' parameter is set to NULL dma_request_channel
-simply returns the first channel that satisfies the capability mask.  Otherwise,
-when the mask parameter is insufficient for specifying the necessary channel,
-the filter_fn routine can be used to disposition the available channels in the
-system. The filter_fn routine is called once for each free channel in the
-system.  Upon seeing a suitable channel filter_fn returns DMA_ACK which flags
-that channel to be the return value from dma_request_channel.  A channel
-allocated via this interface is exclusive to the caller, until
-dma_release_channel() is called.
+
+   Channel allocation is slightly different in the slave DMA context,
+   client drivers typically need a channel from a particular DMA
+   controller only and even in some cases a specific channel is desired.
+   To request a channel dma_request_channel() API is used.
+
+   Interface:
+	struct dma_chan *dma_request_channel(dma_cap_mask_t mask,
+			dma_filter_fn filter_fn,
+			void *filter_param);
+   where dma_filter_fn is defined as:
+	typedef bool (*dma_filter_fn)(struct dma_chan *chan, void *filter_param);
+
+   The 'filter_fn' parameter is optional, but highly recommended for
+   slave and cyclic channels as they typically need to obtain a specific
+   DMA channel.
+
+   When the optional 'filter_fn' parameter is NULL, dma_request_channel()
+   simply returns the first channel that satisfies the capability mask.
+
+   Otherwise, the 'filter_fn' routine will be called once for each free
+   channel which has a capability in 'mask'.  'filter_fn' is expected to
+   return 'true' when the desired DMA channel is found.
+
+   A channel allocated via this interface is exclusive to the caller,
+   until dma_release_channel() is called.
 
 2. Set slave and controller specific parameters
-Next step is always to pass some specific information to the DMA driver. Most of
-the generic information which a slave DMA can use is in struct dma_slave_config.
-It allows the clients to specify DMA direction, DMA addresses, bus widths, DMA
-burst lengths etc. If some DMA controllers have more parameters to be sent then
-they should try to embed struct dma_slave_config in their controller specific
-structure. That gives flexibility to client to pass more parameters, if
-required.
-
-Interface:
-int dmaengine_slave_config(struct dma_chan *chan,
-					  struct dma_slave_config *config)
+
+   Next step is always to pass some specific information to the DMA
+   driver.  Most of the generic information which a slave DMA can use
+   is in struct dma_slave_config.  This allows the clients to specify
+   DMA direction, DMA addresses, bus widths, DMA burst lengths etc
+   for the peripheral.
+
+   If some DMA controllers have more parameters to be sent then they
+   should try to embed struct dma_slave_config in their controller
+   specific structure. That gives flexibility to client to pass more
+   parameters, if required.
+
+   Interface:
+	int dmaengine_slave_config(struct dma_chan *chan,
+				  struct dma_slave_config *config)
+
+   Please see the dma_slave_config structure definition in dmaengine.h
+   for a detailed explaination of the struct members.  Please note
+   that the 'direction' member will be going away as it duplicates the
+   direction given in the prepare call.
 
 3. Get a descriptor for transaction
-For slave usage the various modes of slave transfers supported by the
-DMA-engine are:
-slave_sg	- DMA a list of scatter gather buffers from/to a peripheral
-dma_cyclic	- Perform a cyclic DMA operation from/to a peripheral till the
+
+   For slave usage the various modes of slave transfers supported by the
+   DMA-engine are:
+
+   slave_sg	- DMA a list of scatter gather buffers from/to a peripheral
+   dma_cyclic	- Perform a cyclic DMA operation from/to a peripheral till the
 		  operation is explicitly stopped.
-The non NULL return of this transfer API represents a "descriptor" for the given
-transaction.
 
-Interface:
-struct dma_async_tx_descriptor *(*chan->device->device_prep_dma_sg)(
+   A non-NULL return of this transfer API represents a "descriptor" for
+   the given transaction.
+
+   Interface:
+	struct dma_async_tx_descriptor *(*chan->device->device_prep_dma_sg)(
 		struct dma_chan *chan,
 		struct scatterlist *dst_sg, unsigned int dst_nents,
 		struct scatterlist *src_sg, unsigned int src_nents,
 		unsigned long flags);
-struct dma_async_tx_descriptor *(*chan->device->device_prep_dma_cyclic)(
+
+	struct dma_async_tx_descriptor *(*chan->device->device_prep_dma_cyclic)(
 		struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len,
 		size_t period_len, enum dma_data_direction direction);
 
-4. Submit the transaction and wait for callback notification
-To schedule the transaction to be scheduled by dma device, the "descriptor"
-returned in above (3) needs to be submitted.
-To tell the dma driver that a transaction is ready to be serviced, the
-descriptor->submit() callback needs to be invoked. This chains the descriptor to
-the pending queue.
-The transactions in the pending queue can be activated by calling the
-issue_pending API. If channel is idle then the first transaction in queue is
-started and subsequent ones queued up.
-On completion of the DMA operation the next in queue is submitted and a tasklet
-triggered. The tasklet would then call the client driver completion callback
-routine for notification, if set.
-Interface:
-void dma_async_issue_pending(struct dma_chan *chan);
-
-==============================================================================
-
-Additional usage notes for dma driver writers
-1/ Although DMA engine specifies that completion callback routines cannot submit
-any new operations, but typically for slave DMA subsequent transaction may not
-be available for submit prior to callback routine being called. This requirement
-is not a requirement for DMA-slave devices. But they should take care to drop
-the spin-lock they might be holding before calling the callback routine
+   Once a descriptor has been obtained, the callback information can be
+   added and must then be submitted.  Some DMA engine drivers may hold a
+   spinlock between a successful preparation and submission so it is
+   important that these two operations are closely paired.
+
+   Note:
+	Although the async_tx API specifies that completion callback
+	routines cannot submit any new operations, this is not the
+	case for slave/cyclic DMA.
+
+	For slave DMA, the subsequent transaction may not be available
+	for submission prior to callback function being invoked, so
+	slave DMA callbacks are permitted to prepare and submit a new
+	transaction.
+
+	For cyclic DMA, a callback function may wish to terminate the
+	DMA via dmaengine_terminate_all().
+
+	Therefore, it is important that DMA engine drivers drop any
+	locks before calling the callback function which may cause a
+	deadlock.
+
+	Note that callbacks will always be invoked from the DMA
+	engines tasklet, never from interrupt context.
+
+4. Submit the transaction
+
+   Once the descriptor has been prepared and the callback information
+   added, it must be placed on the DMA engine drivers pending queue.
+
+   Interface:
+	dma_cookie_t dmaengine_submit(struct dma_async_tx_descriptor *desc)
+
+   This returns a cookie can be used to check the progress of DMA engine
+   activity via other DMA engine calls not covered in this document.
+
+   dmaengine_submit() will not start the DMA operation, it merely adds
+   it to the pending queue.  For this, see step 5, dma_async_issue_pending.
+
+5. Issue pending DMA requests and wait for callback notification
+
+   The transactions in the pending queue can be activated by calling the
+   issue_pending API. If channel is idle then the first transaction in
+   queue is started and subsequent ones queued up.
+
+   On completion of each DMA operation, the next in queue is started and
+   a tasklet triggered. The tasklet will then call the client driver
+   completion callback routine for notification, if set.
+
+   Interface:
+	void dma_async_issue_pending(struct dma_chan *chan);
+
+Further APIs:
+
+1. int dmaengine_terminate_all(struct dma_chan *chan)
+
+   This causes all activity for the DMA channel to be stopped, and may
+   discard data in the DMA FIFO which hasn't been fully transferred.
+   No callback functions will be called for any incomplete transfers.
+
+2. int dmaengine_pause(struct dma_chan *chan)
+
+   This pauses activity on the DMA channel without data loss.
+
+3. int dmaengine_resume(struct dma_chan *chan)
+
+   Resume a previously paused DMA channel.  It is invalid to resume a
+   channel which is not currently paused.
+
+4. enum dma_status dma_async_is_tx_complete(struct dma_chan *chan,
+        dma_cookie_t cookie, dma_cookie_t *last, dma_cookie_t *used)
+
+   This can be used to check the status of the channel.  Please see
+   the documentation in include/linux/dmaengine.h for a more complete
+   description of this API.
+
+   This can be used in conjunction with dma_async_is_complete() and
+   the cookie returned from 'descriptor->submit()' to check for
+   completion of a specific DMA transaction.
+
+   Note:
+	Not all DMA engine drivers can return reliable information for
+	a running DMA channel.  It is recommended that DMA engine users
+	pause or stop (via dmaengine_terminate_all) the channel before
+	using this API.
 

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel at lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

Signature · 2 lines
~Vinod Koul
Intel Corp.
#23 lore raw

PATCH 1/1 Improve slave/cyclic DMA engine documentation (was: [PATCH V4 04/14] DMA: PL330: Add DMA_CYCLIC capability)

Quoted 34 lines · Vinod Koul
Quoted 26 lines · Russell King - ARM Linux

Here's an updated patch.

8<----------
From: Russell King <[email protected]>
DMAEngine: Improve slave/cyclic documentation

Improve the documentation for the slave and cyclic DMA engine support reformatting it for easier reading, adding further APIs, splitting it into five steps, and including references to the documentation in dmaengine.h.

---
?Documentation/dmaengine.txt | ?211 ++++++++++++++++++++++++++++++------------- ?1 files changed, 146 insertions(+), 65 deletions(-)

Documentation/dmaengine.txt +0 -0
index 5a0cb1e..8c2e888 100644
@@ -10,87 +10,168 @@

?Below is a guide to device driver writers on how to use the Slave-DMA API of the ?DMA Engine. This is applicable only for slave DMA usage only.

Documentation/dmaengine.txt +1 -1
-The slave DMA usage consists of following steps
+The slave DMA usage consists of following steps:
Quoted 5 lines

?1. Allocate a DMA slave channel
?2. Set slave and controller specific parameters ?3. Get a descriptor for transaction
?4. Submit the transaction and wait for callback notification +5. Issue pending requests

Thanks Russell,

Quoted 3 lines

Applied with change to 4 above. Moved "and wait for callback notification" to 5.

Dear Vinod,

Since it came from the RMK, most probably it'll be the best.

But applying patches upon personal timeout seems very dangerous.

People not responding doesn't mean only either people agree completely or they don't care. Some might be interested but too busy with current tasks that they need time to check... please make some policy for such cases.

It already happened with the patch from Rob, which you probably have to revert.

IMHO, if nobody replied, maybe you could first ack the patch and wait for, say a week, before applying?
That way people will know they have to hurry if they care otherwise the patch is going upstream as such.

Thanks
-Jassi

#24 lore raw

PATCH 1/1 Improve slave/cyclic DMA engine documentation (was: [PATCH V4 04/14] DMA: PL330: Add DMA_CYCLIC capability)

Quoted 5 lines · Jassi Brar

Dear Vinod,

Since it came from the RMK, most probably it'll be the best.

But applying patches upon personal timeout seems very dangerous.

Ehh what? Is there any contention over this documentation patch?

It's not adding anything new, it's just documenting the facts as they stand today about the API and its use.

Quoted 11 lines

People not responding doesn't mean only either people agree completely or they don't care. Some might be interested but too busy with current tasks that they need time to check... please make some policy for such cases.

It already happened with the patch from Rob, which you probably have to revert.

IMHO, if nobody replied, maybe you could first ack the patch and wait for, say a week, before applying?
That way people will know they have to hurry if they care otherwise the patch is going upstream as such.

A week is far too long. That's how patches get lost and missed.

#25 lore raw

PATCH 1/1 Improve slave/cyclic DMA engine documentation (was: [PATCH V4 04/14] DMA: PL330: Add DMA_CYCLIC capability)

Quoted 8 lines · Russell King - ARM Linux
Quoted 5 lines · Jassi Brar

Dear Vinod,

?Since it came from the RMK, most probably it'll be the best.

But applying patches upon personal timeout seems very dangerous.

Ehh what? ?Is there any contention over this documentation patch?

I haven't yet read it... even after reading I would object only if I found your patch disturbing enough to disrupt my bowel movements. Which I don't think would be the case.

I just observed it is second time that Vinod applied a patch without any ack or prior alert.

Quoted 8 lines
Quoted 8 lines

People not responding doesn't mean only either people agree completely or they don't care. Some might be interested but too busy with current tasks that they need time to check... please make some policy for such cases.

It already happened with the patch from Rob, which you probably have to revert.

Quoted 7 lines
Quoted 4 lines

IMHO, if nobody replied, maybe you could first ack the patch and wait for, say a week, before applying?
That way people will know they have to hurry if they care otherwise the patch is going upstream as such.

A week is far too long. ?That's how patches get lost and missed.

He may decide to wait shorter, but imho a week after the first ack isn't that long.

#26 lore raw

PATCH 1/1 Improve slave/cyclic DMA engine documentation (was: [PATCH V4 04/14] DMA: PL330: Add DMA_CYCLIC capability)

Quoted 9 lines · Jassi Brar
Quoted 7 lines · Russell King - ARM Linux
Quoted 5 lines · Jassi Brar

Dear Vinod,

?Since it came from the RMK, most probably it'll be the best.

But applying patches upon personal timeout seems very dangerous.

Quoted 7 lines
Quoted 1 line

Ehh what? ?Is there any contention over this documentation patch?

I haven't yet read it... even after reading I would object only if I found your patch disturbing enough to disrupt my bowel movements. Which I don't think would be the case.

I just observed it is second time that Vinod applied a patch without any ack or prior alert.

Applying patches without waiting for other Acks is absolutely a reasonable thing for a maintainer to do. The job of maintainership is to apply good judgement on when patches can immediately be applied (and therefore no longer consuming limited attention) and when patches need further acks.

g.

#27 lore raw

PATCH 1/1 Improve slave/cyclic DMA engine documentation (was: [PATCH V4 04/14] DMA: PL330: Add DMA_CYCLIC capability)

In reply to Jassi Brar
Quoted 9 lines · Jassi Brar
Quoted 7 lines · Russell King - ARM Linux
Quoted 5 lines · Jassi Brar

Dear Vinod,

?Since it came from the RMK, most probably it'll be the best.

But applying patches upon personal timeout seems very dangerous.

Quoted 7 lines
Quoted 1 line

Ehh what? ?Is there any contention over this documentation patch?

I haven't yet read it... even after reading I would object only if I found your patch disturbing enough to disrupt my bowel movements. Which I don't think would be the case.

I just observed it is second time that Vinod applied a patch without any ack or prior alert.

That's what happens - no one says "I'm going to apply this patch" before they apply it. They just apply it to their tree and move on. Vinod, being the nominated maintainer for the slave DMA engine support has the authority to do that for that area of code.

#28 lore raw

PATCH 1/1 Improve slave/cyclic DMA engine documentation (was: [PATCH V4 04/14] DMA: PL330: Add DMA_CYCLIC capability)

In reply to Jassi Brar
Quoted 5 lines · Jassi Brar
Quoted 3 lines · Russell King - ARM Linux
Quoted 2 lines · Jassi Brar

Dear Vinod,

Quoted 8 lines
Quoted 5 lines
Quoted 3 lines

Since it came from the RMK, most probably it'll be the best.

But applying patches upon personal timeout seems very dangerous.

Ehh what? Is there any contention over this documentation patch?

I haven't yet read it... even after reading I would object only if I found your patch disturbing enough to disrupt my bowel movements. Which I don't think would be the case.

Jassi,
Since this was a doc patch, I applied it soon enough, doesn't sound dangerous to me !
If you have any updates you would like, pls feel free to send a patch.

Quoted 3 lines

I just observed it is second time that Vinod applied a patch without any ack or prior alert.

And you can't ignore the fact that you had almost _two_ weeks to ack the patch from Rob, but....
You will get ample time to ack a patch, if you don't you can always point out and I will do the right thing, which in this case was to revert.

Quoted 23 lines
Quoted 9 lines
Quoted 9 lines

People not responding doesn't mean only either people agree completely or they don't care. Some might be interested but too busy with current tasks that they need time to check... please make some policy for such cases.

It already happened with the patch from Rob, which you probably have to revert.

Quoted 7 lines
Quoted 4 lines

IMHO, if nobody replied, maybe you could first ack the patch and wait for, say a week, before applying?
That way people will know they have to hurry if they care otherwise the patch is going upstream as such.

A week is far too long. That's how patches get lost and missed.

He may decide to wait shorter, but imho a week after the first ack isn't that long.

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel at lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

#29 lore raw

PATCH 1/1 Improve slave/cyclic DMA engine documentation (was: [PATCH V4 04/14] DMA: PL330: Add DMA_CYCLIC capability)

In reply to Vinod Koul
Quoted 34 lines · Vinod Koul
Quoted 21 lines · Russell King - ARM Linux

Here's an updated patch.

8<----------
From: Russell King <[email protected]>
DMAEngine: Improve slave/cyclic documentation

Improve the documentation for the slave and cyclic DMA engine support reformatting it for easier reading, adding further APIs, splitting it into five steps, and including references to the documentation in dmaengine.h.

---
 Documentation/dmaengine.txt |  211 ++++++++++++++++++++++++++++++-------------
 1 files changed, 146 insertions(+), 65 deletions(-)
Documentation/dmaengine.txt +0 -0
index 5a0cb1e..8c2e888 100644

Documentation/dmaengine.txt line 18

Quoted 10 lines
Documentation/dmaengine.txt +2 -1
@@ -10,87 +10,168 @@
 Below is a guide to device driver writers on how to use the Slave-DMA API of the
 DMA Engine. This is applicable only for slave DMA usage only.
 
-The slave DMA usage consists of following steps
+The slave DMA usage consists of following steps:
 1. Allocate a DMA slave channel
 2. Set slave and controller specific parameters
 3. Get a descriptor for transaction
 4. Submit the transaction and wait for callback notification
+5. Issue pending requests

Thanks Russell,

Quoted 2 lines

Applied with change to 4 above. Moved "and wait for callback notification" to 5.

BTW, did you apply this one or the later one with the improved documentation for dma mapping and fixed interface for slave transfers etc. ?

#30 lore raw

PATCH 1/1 Improve slave/cyclic DMA engine documentation (was: [PATCH V4 04/14] DMA: PL330: Add DMA_CYCLIC capability)

Quoted 35 lines · Russell King - ARM Linux
Quoted 34 lines · Vinod Koul
Quoted 21 lines · Russell King - ARM Linux

Here's an updated patch.

8<----------
From: Russell King <[email protected]>
DMAEngine: Improve slave/cyclic documentation

Improve the documentation for the slave and cyclic DMA engine support reformatting it for easier reading, adding further APIs, splitting it into five steps, and including references to the documentation in dmaengine.h.

---
 Documentation/dmaengine.txt |  211 ++++++++++++++++++++++++++++++-------------
 1 files changed, 146 insertions(+), 65 deletions(-)
Documentation/dmaengine.txt +0 -0
index 5a0cb1e..8c2e888 100644

Documentation/dmaengine.txt line 18

Quoted 10 lines
Documentation/dmaengine.txt +2 -1
@@ -10,87 +10,168 @@
 Below is a guide to device driver writers on how to use the Slave-DMA API of the
 DMA Engine. This is applicable only for slave DMA usage only.
 
-The slave DMA usage consists of following steps
+The slave DMA usage consists of following steps:
 1. Allocate a DMA slave channel
 2. Set slave and controller specific parameters
 3. Get a descriptor for transaction
 4. Submit the transaction and wait for callback notification
+5. Issue pending requests

Thanks Russell,

Quoted 6 lines
Quoted 2 lines

Applied with change to 4 above. Moved "and wait for callback notification" to 5.

BTW, did you apply this one or the later one with the improved documentation for dma mapping and fixed interface for slave transfers etc. ?

I changed it to second one, not pushed yet.
I am rebasing the tree to 3.0. You should see updated version in tree later in the evening today

Signature · 1 line
~Vinod
#31 lore raw

PATCH 1/1 Improve slave/cyclic DMA engine documentation (was: [PATCH V4 04/14] DMA: PL330: Add DMA_CYCLIC capability)

In reply to Russell King - ARM Linux
Quoted 1 line · Russell King - ARM Linux

Here's an updated patch.

Sorry, another one. I've corrected the slave_sg preparation interface, and added a paragraph on preparing the scatterlist for the DMA operation, including mentioning which struct device should be used for this.

8<----------
From: Russell King <[email protected]>
DMAEngine: Improve slave/cyclic documentation

Improve the documentation for the slave and cyclic DMA engine support reformatting it for easier reading, adding further APIs, splitting it into five steps, and including references to the documentation in dmaengine.h.

---
 Documentation/dmaengine.txt |  232 ++++++++++++++++++++++++++++++-------------
 1 files changed, 163 insertions(+), 69 deletions(-)
Documentation/dmaengine.txt +163 -69
index 5a0cb1e..c7131a8 100644
@@ -10,87 +10,181 @@
 Below is a guide to device driver writers on how to use the Slave-DMA API of the
 DMA Engine. This is applicable only for slave DMA usage only.
 
-The slave DMA usage consists of following steps
+The slave DMA usage consists of following steps:
 1. Allocate a DMA slave channel
 2. Set slave and controller specific parameters
 3. Get a descriptor for transaction
 4. Submit the transaction and wait for callback notification
+5. Issue pending requests
 
 1. Allocate a DMA slave channel
-Channel allocation is slightly different in the slave DMA context, client
-drivers typically need a channel from a particular DMA controller only and even
-in some cases a specific channel is desired. To request a channel
-dma_request_channel() API is used.
-
-Interface:
-struct dma_chan *dma_request_channel(dma_cap_mask_t mask,
-		dma_filter_fn filter_fn,
-		void *filter_param);
-where dma_filter_fn is defined as:
-typedef bool (*dma_filter_fn)(struct dma_chan *chan, void *filter_param);
-
-When the optional 'filter_fn' parameter is set to NULL dma_request_channel
-simply returns the first channel that satisfies the capability mask.  Otherwise,
-when the mask parameter is insufficient for specifying the necessary channel,
-the filter_fn routine can be used to disposition the available channels in the
-system. The filter_fn routine is called once for each free channel in the
-system.  Upon seeing a suitable channel filter_fn returns DMA_ACK which flags
-that channel to be the return value from dma_request_channel.  A channel
-allocated via this interface is exclusive to the caller, until
-dma_release_channel() is called.
+
+   Channel allocation is slightly different in the slave DMA context,
+   client drivers typically need a channel from a particular DMA
+   controller only and even in some cases a specific channel is desired.
+   To request a channel dma_request_channel() API is used.
+
+   Interface:
+	struct dma_chan *dma_request_channel(dma_cap_mask_t mask,
+			dma_filter_fn filter_fn,
+			void *filter_param);
+   where dma_filter_fn is defined as:
+	typedef bool (*dma_filter_fn)(struct dma_chan *chan, void *filter_param);
+
+   The 'filter_fn' parameter is optional, but highly recommended for
+   slave and cyclic channels as they typically need to obtain a specific
+   DMA channel.
+
+   When the optional 'filter_fn' parameter is NULL, dma_request_channel()
+   simply returns the first channel that satisfies the capability mask.
+
+   Otherwise, the 'filter_fn' routine will be called once for each free
+   channel which has a capability in 'mask'.  'filter_fn' is expected to
+   return 'true' when the desired DMA channel is found.
+
+   A channel allocated via this interface is exclusive to the caller,
+   until dma_release_channel() is called.
 
 2. Set slave and controller specific parameters
-Next step is always to pass some specific information to the DMA driver. Most of
-the generic information which a slave DMA can use is in struct dma_slave_config.
-It allows the clients to specify DMA direction, DMA addresses, bus widths, DMA
-burst lengths etc. If some DMA controllers have more parameters to be sent then
-they should try to embed struct dma_slave_config in their controller specific
-structure. That gives flexibility to client to pass more parameters, if
-required.
-
-Interface:
-int dmaengine_slave_config(struct dma_chan *chan,
-					  struct dma_slave_config *config)
+
+   Next step is always to pass some specific information to the DMA
+   driver.  Most of the generic information which a slave DMA can use
+   is in struct dma_slave_config.  This allows the clients to specify
+   DMA direction, DMA addresses, bus widths, DMA burst lengths etc
+   for the peripheral.
+
+   If some DMA controllers have more parameters to be sent then they
+   should try to embed struct dma_slave_config in their controller
+   specific structure. That gives flexibility to client to pass more
+   parameters, if required.
+
+   Interface:
+	int dmaengine_slave_config(struct dma_chan *chan,
+				  struct dma_slave_config *config)
+
+   Please see the dma_slave_config structure definition in dmaengine.h
+   for a detailed explaination of the struct members.  Please note
+   that the 'direction' member will be going away as it duplicates the
+   direction given in the prepare call.
 
 3. Get a descriptor for transaction
-For slave usage the various modes of slave transfers supported by the
-DMA-engine are:
-slave_sg	- DMA a list of scatter gather buffers from/to a peripheral
-dma_cyclic	- Perform a cyclic DMA operation from/to a peripheral till the
+
+   For slave usage the various modes of slave transfers supported by the
+   DMA-engine are:
+
+   slave_sg	- DMA a list of scatter gather buffers from/to a peripheral
+   dma_cyclic	- Perform a cyclic DMA operation from/to a peripheral till the
 		  operation is explicitly stopped.
-The non NULL return of this transfer API represents a "descriptor" for the given
-transaction.
-
-Interface:
-struct dma_async_tx_descriptor *(*chan->device->device_prep_dma_sg)(
-		struct dma_chan *chan,
-		struct scatterlist *dst_sg, unsigned int dst_nents,
-		struct scatterlist *src_sg, unsigned int src_nents,
+
+   A non-NULL return of this transfer API represents a "descriptor" for
+   the given transaction.
+
+   Interface:
+	struct dma_async_tx_descriptor *(*chan->device->device_prep_slave_sg)(
+		struct dma_chan *chan, struct scatterlist *sgl,
+		unsigned int sg_len, enum dma_data_direction direction,
 		unsigned long flags);
-struct dma_async_tx_descriptor *(*chan->device->device_prep_dma_cyclic)(
+
+	struct dma_async_tx_descriptor *(*chan->device->device_prep_dma_cyclic)(
 		struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len,
 		size_t period_len, enum dma_data_direction direction);
 
-4. Submit the transaction and wait for callback notification
-To schedule the transaction to be scheduled by dma device, the "descriptor"
-returned in above (3) needs to be submitted.
-To tell the dma driver that a transaction is ready to be serviced, the
-descriptor->submit() callback needs to be invoked. This chains the descriptor to
-the pending queue.
-The transactions in the pending queue can be activated by calling the
-issue_pending API. If channel is idle then the first transaction in queue is
-started and subsequent ones queued up.
-On completion of the DMA operation the next in queue is submitted and a tasklet
-triggered. The tasklet would then call the client driver completion callback
-routine for notification, if set.
-Interface:
-void dma_async_issue_pending(struct dma_chan *chan);
-
-==============================================================================
-
-Additional usage notes for dma driver writers
-1/ Although DMA engine specifies that completion callback routines cannot submit
-any new operations, but typically for slave DMA subsequent transaction may not
-be available for submit prior to callback routine being called. This requirement
-is not a requirement for DMA-slave devices. But they should take care to drop
-the spin-lock they might be holding before calling the callback routine
+   The peripheral driver is expected to have mapped the scatterlist for
+   the DMA operation prior to calling device_prep_slave_sg, and must
+   keep the scatterlist mapped until the DMA operation has completed.
+   The scatterlist must be mapped using the DMA struct device.  So,
+   normal setup should look like this:
+
+	nr_sg = dma_map_sg(chan->device->dev, sgl, sg_len);
+	if (nr_sg == 0)
+		/* error */
+
+	desc = chan->device->device_prep_slave_sg(chan, sgl, nr_sg,
+			direction, flags);
+
+   Once a descriptor has been obtained, the callback information can be
+   added and the descriptor must then be submitted.  Some DMA engine
+   drivers may hold a spinlock between a successful preparation and
+   submission so it is important that these two operations are closely
+   paired.
+
+   Note:
+	Although the async_tx API specifies that completion callback
+	routines cannot submit any new operations, this is not the
+	case for slave/cyclic DMA.
+
+	For slave DMA, the subsequent transaction may not be available
+	for submission prior to callback function being invoked, so
+	slave DMA callbacks are permitted to prepare and submit a new
+	transaction.
+
+	For cyclic DMA, a callback function may wish to terminate the
+	DMA via dmaengine_terminate_all().
+
+	Therefore, it is important that DMA engine drivers drop any
+	locks before calling the callback function which may cause a
+	deadlock.
+
+	Note that callbacks will always be invoked from the DMA
+	engines tasklet, never from interrupt context.
+
+4. Submit the transaction
+
+   Once the descriptor has been prepared and the callback information
+   added, it must be placed on the DMA engine drivers pending queue.
+
+   Interface:
+	dma_cookie_t dmaengine_submit(struct dma_async_tx_descriptor *desc)
+
+   This returns a cookie can be used to check the progress of DMA engine
+   activity via other DMA engine calls not covered in this document.
+
+   dmaengine_submit() will not start the DMA operation, it merely adds
+   it to the pending queue.  For this, see step 5, dma_async_issue_pending.
+
+5. Issue pending DMA requests and wait for callback notification
+
+   The transactions in the pending queue can be activated by calling the
+   issue_pending API. If channel is idle then the first transaction in
+   queue is started and subsequent ones queued up.
+
+   On completion of each DMA operation, the next in queue is started and
+   a tasklet triggered. The tasklet will then call the client driver
+   completion callback routine for notification, if set.
+
+   Interface:
+	void dma_async_issue_pending(struct dma_chan *chan);
+
+Further APIs:
+
+1. int dmaengine_terminate_all(struct dma_chan *chan)
+
+   This causes all activity for the DMA channel to be stopped, and may
+   discard data in the DMA FIFO which hasn't been fully transferred.
+   No callback functions will be called for any incomplete transfers.
+
+2. int dmaengine_pause(struct dma_chan *chan)
+
+   This pauses activity on the DMA channel without data loss.
+
+3. int dmaengine_resume(struct dma_chan *chan)
+
+   Resume a previously paused DMA channel.  It is invalid to resume a
+   channel which is not currently paused.
+
+4. enum dma_status dma_async_is_tx_complete(struct dma_chan *chan,
+        dma_cookie_t cookie, dma_cookie_t *last, dma_cookie_t *used)
+
+   This can be used to check the status of the channel.  Please see
+   the documentation in include/linux/dmaengine.h for a more complete
+   description of this API.
+
+   This can be used in conjunction with dma_async_is_complete() and
+   the cookie returned from 'descriptor->submit()' to check for
+   completion of a specific DMA transaction.
+
+   Note:
+	Not all DMA engine drivers can return reliable information for
+	a running DMA channel.  It is recommended that DMA engine users
+	pause or stop (via dmaengine_terminate_all) the channel before
+	using this API.
author
#32 lore raw

PATCH v4 4/14 DMA: PL330: Add DMA_CYCLIC capability

In reply to Vinod Koul

Vinod Koul Wrote:

Quoted 33 lines

Sent: Monday, July 25, 2011 7:48 PM
To: Russell King - ARM Linux
Cc: vinod.koul at intel.com; Boojin Kim; 'Kukjin Kim'; 'Jassi Brar'; 'Grant Likely'; linux-samsung-soc at vger.kernel.org; 'Mark Brown'; 'Dan Williams'; linux-arm-kernel at lists.infradead.org
Subject: Re: [PATCH V4 04/14] DMA: PL330: Add DMA_CYCLIC capability

Quoted 11 lines · Russell King - ARM Linux
Quoted 10 lines · Boojin Kim
Quoted 10 lines · Boojin Kim
Quoted 8 lines
drivers/dma/pl330.c +8 -0
+static void pl330_tasklet_cyclic(unsigned long data)
+{
+	struct dma_pl330_chan *pch = (struct dma_pl330_chan *)data;
+	struct dma_pl330_desc *desc, *_dt;
+	unsigned long flags;
+	LIST_HEAD(list);
+
+	spin_lock_irqsave(&pch->lock, flags);

...

Quoted 5 lines
Quoted 5 lines
Quoted 5 lines

drivers/dma/pl330.c static inline void fill_queue(struct dma_pl330_chan *pch) · line 220

Quoted 3 lines
drivers/dma/pl330.c +3 -0
+			callback = desc->txd.callback;
+			if (callback)
+				callback(desc->txd.callback_param);

On this again - what if the callback wants to terminate the DMA

activity

Quoted 1 line
Quoted 1 line
Quoted 1 line

because there's no more audio data to be sent/received from the

device?

Quoted 2 lines
Quoted 2 lines

Do you mean what is happened if the callback() is called after

channel is

Quoted 2 lines
Quoted 2 lines

terminated ?
Or What is happened if Callback() calls 'dma_release_channel()' to

terminate

Quoted 8 lines
Quoted 3 lines
Quoted 1 line

DMA?

No. I mean what if the callback wants to call

dmaengine_terminate_all().
you are supposed to drop the lock here, that way callback can call any DMA API, otherwise it will result in deadlock.
This make me wonder you haven't read the documentation at all, please ensure you have read Documentation/dmaengine.txt before next posting

I found the deadlock problem that you post. I will fix it and read the document again.

Quoted 37 lines
Quoted 4 lines
Quoted 4 lines
Quoted 4 lines

drivers/dma/pl330.c static inline int get_burst_len(struct dma_pl330_desc *desc, size_t len)

Quoted 4 lines
drivers/dma/pl330.c +3 -0
+	if (!pch->cyclic_task) {
+		pch->cyclic_task =
+			kmalloc(sizeof(struct tasklet_struct),

GFP_KERNEL);

Quoted 4 lines
Quoted 4 lines
Quoted 4 lines

drivers/dma/pl330.c static inline int get_burst_len(struct dma_pl330_desc *desc, size_t len) · line 649

Quoted 2 lines
drivers/dma/pl330.c +2 -0
+		tasklet_init(pch->cyclic_task,
+			pl330_tasklet_cyclic, (unsigned int)pch);

Here you allocate memory for the cyclic task. Above you set this

pointer

Quoted 1 line
Quoted 1 line
Quoted 1 line

to NULL. That sounds like a memory leak to me. Why are you

kmallocing

Quoted 1 line
Quoted 1 line
Quoted 1 line

this memory - why can't it be part of the dma_pl330_chan

structure? It's

Quoted 6 lines
Quoted 6 lines
Quoted 1 line

only 28 bytes.

It's my mistake. I should have been free of the memory.

And the reason why I use kmalloc for 'cyclic_task' is following. This memory size for 'cyclic_tasklet' is the 896 bytes ( = the

number of

Quoted 1 line
Quoted 1 line

channel * sizeof(struct tasklet_struct)= 32*28) for each DMAC. And

This

Quoted 2 lines
Quoted 2 lines

memory size is increased according to the number of DMAC. And Samsung has the DMAC that is dedicated for Mem-to-Mem

operation. If I

Quoted 1 line
Quoted 1 line

make 'cyclic_task' be part of dma_pl330_chan, this DMAC that is

dedicated

Quoted 4 lines
Quoted 2 lines

for Mem-to-Mem operation should hold unused data.
So, I think it's loss that all dma channels hold own 'cyclic_task'.

Could you re-use the tasklet that already exists?

--
~Vinod Koul
Intel Corp.

author
#33 lore raw

PATCH v4 4/14 DMA: PL330: Add DMA_CYCLIC capability

In reply to Russell King - ARM Linux

Russell King - ARM Linux Wrote:

Quoted 28 lines

Sent: Monday, July 25, 2011 7:36 PM
To: Boojin Kim
Cc: linux-arm-kernel at lists.infradead.org; linux-samsung- soc at vger.kernel.org; 'Kukjin Kim'; 'Vinod Koul'; 'Jassi Brar'; 'Grant Likely'; 'Mark Brown'; 'Dan Williams'
Subject: Re: [PATCH V4 04/14] DMA: PL330: Add DMA_CYCLIC capability

Quoted 10 lines · Boojin Kim
Quoted 10 lines · Boojin Kim
Quoted 8 lines
drivers/dma/pl330.c +8 -0
+static void pl330_tasklet_cyclic(unsigned long data)
+{
+	struct dma_pl330_chan *pch = (struct dma_pl330_chan *)data;
+	struct dma_pl330_desc *desc, *_dt;
+	unsigned long flags;
+	LIST_HEAD(list);
+
+	spin_lock_irqsave(&pch->lock, flags);

...

Quoted 5 lines
Quoted 5 lines

drivers/dma/pl330.c static inline void fill_queue(struct dma_pl330_chan *pch) · line 220

Quoted 3 lines
drivers/dma/pl330.c +3 -0
+			callback = desc->txd.callback;
+			if (callback)
+				callback(desc->txd.callback_param);

On this again - what if the callback wants to terminate the DMA

activity

Quoted 1 line
Quoted 1 line

because there's no more audio data to be sent/received from the

device?

Quoted 2 lines

Do you mean what is happened if the callback() is called after

Quoted 8 lines

channel is

Quoted 2 lines

terminated ?
Or What is happened if Callback() calls 'dma_release_channel()' to

terminate

Quoted 1 line

DMA?

No. I mean what if the callback wants to call
dmaengine_terminate_all().

I found the deadlock problem that you and Vinod post. I will fix it.

Quoted 25 lines
Quoted 4 lines
Quoted 4 lines

drivers/dma/pl330.c static inline int get_burst_len(struct dma_pl330_desc *desc, size_t len)

Quoted 4 lines
drivers/dma/pl330.c +3 -0
+	if (!pch->cyclic_task) {
+		pch->cyclic_task =
+			kmalloc(sizeof(struct tasklet_struct),

GFP_KERNEL);

Quoted 4 lines
Quoted 4 lines

drivers/dma/pl330.c static inline int get_burst_len(struct dma_pl330_desc *desc, size_t len) · line 649

Quoted 2 lines
drivers/dma/pl330.c +2 -0
+		tasklet_init(pch->cyclic_task,
+			pl330_tasklet_cyclic, (unsigned int)pch);

Here you allocate memory for the cyclic task. Above you set this

pointer

Quoted 1 line
Quoted 1 line

to NULL. That sounds like a memory leak to me. Why are you

kmallocing

Quoted 1 line
Quoted 1 line

this memory - why can't it be part of the dma_pl330_chan structure?

It's

Quoted 6 lines
Quoted 1 line

only 28 bytes.

It's my mistake. I should have been free of the memory.

And the reason why I use kmalloc for 'cyclic_task' is following. This memory size for 'cyclic_tasklet' is the 896 bytes ( = the

number of

Quoted 1 line

channel * sizeof(struct tasklet_struct)= 32*28) for each DMAC. And

This

Quoted 2 lines

memory size is increased according to the number of DMAC. And Samsung has the DMAC that is dedicated for Mem-to-Mem operation.

Quoted 7 lines

If I

Quoted 1 line

make 'cyclic_task' be part of dma_pl330_chan, this DMAC that is

dedicated

Quoted 2 lines

for Mem-to-Mem operation should hold unused data.
So, I think it's loss that all dma channels hold own 'cyclic_task'.

Could you re-use the tasklet that already exists?

Yes, It can be re-used. But, This tasklet should be initialized on each request by using 'tasklet_init()' because it needs the own channel as its parameter.

#34 lore raw

PATCH v4 4/14 DMA: PL330: Add DMA_CYCLIC capability

In reply to Boojin Kim
Quoted 22 lines · Boojin Kim

This patch adds DMA_CYCLIC capability that is used for audio driver. DMA driver with DMA_CYCLIC capability reuses the dma requests that were submitted through tx_submit().

---
?drivers/dma/pl330.c | ?111 +++++++++++++++++++++++++++++++++++++++++++++++++++ ?1 files changed, 111 insertions(+), 0 deletions(-)

drivers/dma/pl330.c +0 -0
index 880f010..121c75a 100644
@@ -69,6 +69,11 @@ struct dma_pl330_chan {

? ? ? ? * NULL if the channel is available to be acquired. ? ? ? ? */
? ? ? ?void *pl330_chid;

drivers/dma/pl330.c +5 -0
+
+ ? ? ? /* taks for cyclic capability */
+ ? ? ? struct tasklet_struct *cyclic_task;
+
+ ? ? ? bool cyclic;
Quoted 1 line

?};

We already have a tasklet_struct member here.
This 'cyclic' flag can indicate if we are doing cyclic or serial transfers. So, this cyclic_task seems unnecessary.

Quoted 24 lines
drivers/dma/pl330.c +24 -0
+static void pl330_tasklet_cyclic(unsigned long data)
+{
+ ? ? ? struct dma_pl330_chan *pch = (struct dma_pl330_chan *)data;
+ ? ? ? struct dma_pl330_desc *desc, *_dt;
+ ? ? ? unsigned long flags;
+ ? ? ? LIST_HEAD(list);
+
+ ? ? ? spin_lock_irqsave(&pch->lock, flags);
+
+ ? ? ? /* Pick up ripe tomatoes */
+ ? ? ? list_for_each_entry_safe(desc, _dt, &pch->work_list, node)
+ ? ? ? ? ? ? ? if (desc->status == DONE) {
+ ? ? ? ? ? ? ? ? ? ? ? dma_async_tx_callback callback;
+
+ ? ? ? ? ? ? ? ? ? ? ? list_move_tail(&desc->node, &pch->work_list);
+ ? ? ? ? ? ? ? ? ? ? ? pch->completed = desc->txd.cookie;
+
+ ? ? ? ? ? ? ? ? ? ? ? desc->status = PREP;
+
+ ? ? ? ? ? ? ? ? ? ? ? /* Try to submit a req imm.
+ ? ? ? ? ? ? ? ? ? ? ? next to the last completed cookie */
+ ? ? ? ? ? ? ? ? ? ? ? fill_queue(pch);
+
+ ? ? ? ? ? ? ? ? ? ? ? /* Make sure the PL330 Channel thread is active */

drivers/dma/pl330.c

Quoted 10 lines
drivers/dma/pl330.c +10 -0
+ ? ? ? ? ? ? ? ? ? ? ? pl330_chan_ctrl(pch->pl330_chid, PL330_OP_START);
+
+ ? ? ? ? ? ? ? ? ? ? ? callback = desc->txd.callback;
+ ? ? ? ? ? ? ? ? ? ? ? if (callback)
+ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? callback(desc->txd.callback_param);
+
+ ? ? ? ? ? ? ? }
+
+ ? ? ? spin_unlock_irqrestore(&pch->lock, flags);
+}

Please merge this with pl330_tasklet and use 'cyclic' flag to differentiate.

drivers/dma/pl330.c static void dma_pl330_rqcb(void *token, enum pl330_op_err err) · line 273

Quoted 8 lines
drivers/dma/pl330.c +3 -0
@@ -227,6 +267,9 @@ static void dma_pl330_rqcb(void *token, enum pl330_op_err err)
 
 ? ? ? ?spin_unlock_irqrestore(&pch->lock, flags);
 
+ ? ? ? if (pch->cyclic_task)
+ ? ? ? ? ? ? ? tasklet_schedule(pch->cyclic_task);
+ ? ? ? else
 ? ? ? ?tasklet_schedule(&pch->task);

A tab here please, and check for 'cyclic' flag.

Quoted 5 lines
drivers/dma/pl330.c +1 -0
@@ -316,6 +359,15 @@ static void pl330_free_chan_resources(struct dma_chan *chan)
 ? ? ? ?pl330_release_channel(pch->pl330_chid);
 ? ? ? ?pch->pl330_chid = NULL;
 
+ ? ? ? if (pch->cyclic) {

drivers/dma/pl330.c static void pl330_free_chan_resources(struct dma_chan *chan) · line 372

Quoted 10 lines
drivers/dma/pl330.c +8 -0
+ ? ? ? ? ? ? ? pch->cyclic = false;
+ ? ? ? ? ? ? ? list_splice_tail_init(&pch->work_list, &pch->dmac->desc_pool);
+ ? ? ? ? ? ? ? if (pch->cyclic_task) {
+ ? ? ? ? ? ? ? ? ? ? ? tasklet_kill(pch->cyclic_task);
+ ? ? ? ? ? ? ? ? ? ? ? pch->cyclic_task = NULL;
+ ? ? ? ? ? ? ? }
+ ? ? ? }
+
 ? ? ? ?spin_unlock_irqrestore(&pch->lock, flags);
 ?}

To be explicit, please initialize 'cyclic' flag to false in pl330_alloc_chan_resources

author
#35 lore raw

PATCH v4 4/14 DMA: PL330: Add DMA_CYCLIC capability

Jassi Brar Wrote:

Quoted 28 lines

Sent: Monday, July 25, 2011 8:24 PM
To: Boojin Kim
Cc: linux-arm-kernel at lists.infradead.org; linux-samsung- soc at vger.kernel.org; Vinod Koul; Dan Williams; Kukjin Kim; Grant Likely; Mark Brown
Subject: Re: [PATCH V4 04/14] DMA: PL330: Add DMA_CYCLIC capability

Quoted 7 lines · Boojin Kim

This patch adds DMA_CYCLIC capability that is used for audio driver. DMA driver with DMA_CYCLIC capability reuses the dma requests that were submitted through tx_submit().

---
 drivers/dma/pl330.c |  111

+++++++++++++++++++++++++++++++++++++++++++++++++++

Quoted 11 lines
 1 files changed, 111 insertions(+), 0 deletions(-)
drivers/dma/pl330.c +1 -0
index 880f010..121c75a 100644
@@ -69,6 +69,11 @@ struct dma_pl330_chan {
        * NULL if the channel is available to be acquired.
        */
       void *pl330_chid;
+
Quoted 8 lines

drivers/dma/pl330.c struct dma_pl330_chan { · line 77

Quoted 5 lines
drivers/dma/pl330.c +4 -0
+       /* taks for cyclic capability */
+       struct tasklet_struct *cyclic_task;
+
+       bool cyclic;
 };

We already have a tasklet_struct member here.
This 'cyclic' flag can indicate if we are doing cyclic or serial transfers. So, this cyclic_task seems unnecessary.

I will change cyclic operation base on your comment. Cyclic_task will be removed.

Quoted 69 lines
Quoted 15 lines
drivers/dma/pl330.c +14 -0
+static void pl330_tasklet_cyclic(unsigned long data)
+{
+       struct dma_pl330_chan *pch = (struct dma_pl330_chan *)data;
+       struct dma_pl330_desc *desc, *_dt;
+       unsigned long flags;
+       LIST_HEAD(list);
+
+       spin_lock_irqsave(&pch->lock, flags);
+
+       /* Pick up ripe tomatoes */
+       list_for_each_entry_safe(desc, _dt, &pch->work_list, node)
+               if (desc->status == DONE) {
+                       dma_async_tx_callback callback;
+

drivers/dma/pl330.c static inline void fill_queue(struct dma_pl330_chan *pch)

Quoted 10 lines
drivers/dma/pl330.c +10 -0
+                       list_move_tail(&desc->node, &pch->work_list);
+                       pch->completed = desc->txd.cookie;
+
+                       desc->status = PREP;
+
+                       /* Try to submit a req imm.
+                       next to the last completed cookie */
+                       fill_queue(pch);
+
+                       /* Make sure the PL330 Channel thread is active

*/

Quoted 1 line

+ pl330_chan_ctrl(pch->pl330_chid,

PL330_OP_START);

drivers/dma/pl330.c static inline void fill_queue(struct dma_pl330_chan *pch) · line 225

Quoted 9 lines
drivers/dma/pl330.c +9 -0
+
+                       callback = desc->txd.callback;
+                       if (callback)
+                               callback(desc->txd.callback_param);
+
+               }
+
+       spin_unlock_irqrestore(&pch->lock, flags);
+}

Please merge this with pl330_tasklet and use 'cyclic' flag to differentiate.

drivers/dma/pl330.c static void dma_pl330_rqcb(void *token, enum

Quoted 1 line
drivers/dma/pl330.c +0 -0
@@ -227,6 +267,9 @@ static void dma_pl330_rqcb(void *token, enum

pl330_op_err err)

drivers/dma/pl330.c static void dma_pl330_rqcb(void *token, enum pl330_op_err err) · line 273

Quoted 7 lines
drivers/dma/pl330.c +3 -0
       spin_unlock_irqrestore(&pch->lock, flags);
 
+       if (pch->cyclic_task)
+               tasklet_schedule(pch->cyclic_task);
+       else
       tasklet_schedule(&pch->task);

A tab here please, and check for 'cyclic' flag.

drivers/dma/pl330.c static void pl330_free_chan_resources(struct

Quoted 1 line
drivers/dma/pl330.c +0 -0
@@ -316,6 +359,15 @@ static void pl330_free_chan_resources(struct

dma_chan *chan)

Quoted 5 lines
drivers/dma/pl330.c +2 -0
       pl330_release_channel(pch->pl330_chid);
       pch->pl330_chid = NULL;
 
+       if (pch->cyclic) {
+               pch->cyclic = false;

drivers/dma/pl330.c static void pl330_free_chan_resources(struct dma_chan *chan) · line 372

Quoted 10 lines
drivers/dma/pl330.c +7 -0
+               list_splice_tail_init(&pch->work_list, &pch->dmac-
 desc_pool);
+               if (pch->cyclic_task) {
+                       tasklet_kill(pch->cyclic_task);
+                       pch->cyclic_task = NULL;
+               }
+       }
+
       spin_unlock_irqrestore(&pch->lock, flags);
 }
Quoted 2 lines

To be explicit, please initialize 'cyclic' flag to false in pl330_alloc_chan_resources

I will address your comment.

author
#36 lore raw

PATCH v4 5/14 ARM: SAMSUNG: Update to use PL330-DMA driver

In reply to Boojin Kim

This patch adds to support PL330-DMA driver on DMADEVICE for S5P SoCs.

---
 arch/arm/mach-exynos4/include/mach/dma.h           |    4 +-
 arch/arm/mach-s5p64x0/include/mach/dma.h           |    2 +-
 arch/arm/mach-s5pc100/include/mach/dma.h           |    2 +-
 arch/arm/mach-s5pv210/include/mach/dma.h           |    2 +-
 arch/arm/plat-samsung/Kconfig                      |    8 +++++++
 .../include/plat/{s3c-dma-pl330.h => dma-pl330.h}  |   21 +++++++++++++------
 .../plat-samsung/include/plat/s3c-pl330-pdata.h    |    2 +-
 7 files changed, 28 insertions(+), 13 deletions(-)
 rename arch/arm/plat-samsung/include/plat/{s3c-dma-pl330.h => dma-pl330.h} (84%)
arch/arm/mach-exynos4/include/mach/dma.h +2 -2
index 81209eb..201842a 100644
@@ -20,7 +20,7 @@
 #ifndef __MACH_DMA_H
 #define __MACH_DMA_H
 
-/* This platform uses the common S3C DMA API driver for PL330 */
-#include <plat/s3c-dma-pl330.h>
+/* This platform uses the common DMA API driver for PL330 */
+#include <plat/dma-pl330.h>
 
 #endif /* __MACH_DMA_H */
arch/arm/mach-s5p64x0/include/mach/dma.h +1 -1
index 81209eb..1beae2c 100644
@@ -21,6 +21,6 @@
 #define __MACH_DMA_H
 
 /* This platform uses the common S3C DMA API driver for PL330 */
-#include <plat/s3c-dma-pl330.h>
+#include <plat/dma-pl330.h>
 
 #endif /* __MACH_DMA_H */
arch/arm/mach-s5pc100/include/mach/dma.h +1 -1
index 81209eb..1beae2c 100644
@@ -21,6 +21,6 @@
 #define __MACH_DMA_H
 
 /* This platform uses the common S3C DMA API driver for PL330 */
-#include <plat/s3c-dma-pl330.h>
+#include <plat/dma-pl330.h>
 
 #endif /* __MACH_DMA_H */
arch/arm/mach-s5pv210/include/mach/dma.h +1 -1
index 81209eb..1beae2c 100644
@@ -21,6 +21,6 @@
 #define __MACH_DMA_H
 
 /* This platform uses the common S3C DMA API driver for PL330 */
-#include <plat/s3c-dma-pl330.h>
+#include <plat/dma-pl330.h>
 
 #endif /* __MACH_DMA_H */
arch/arm/plat-samsung/Kconfig +8 -0
index 4d79519..cb170a6 100644
@@ -300,6 +300,14 @@ config S3C_PL330_DMA
 	help
 	  S3C DMA API Driver for PL330 DMAC.
 
+config DMADEV_PL330
+	bool
+	select DMADEVICES
+	select PL330_DMA
+	select ARM_AMBA
+	help
+	  Use DMA device engine for PL330 DMAC.
+
 comment "Power management"
 
 config SAMSUNG_PM_DEBUG
arch/arm/plat-samsung/include/plat/dma-pl330.h renamed from arch/arm/plat-samsung/include/plat/s3c-dma-pl330.h +14 -7
similarity index 84%
rename from arch/arm/plat-samsung/include/plat/s3c-dma-pl330.h
rename to arch/arm/plat-samsung/include/plat/dma-pl330.h
index 8107442..c402719 100644
@@ -8,19 +8,18 @@
  * (at your option) any later version.
  */
 
-#ifndef	__S3C_DMA_PL330_H_
-#define	__S3C_DMA_PL330_H_
-
-#define S3C2410_DMAF_AUTOSTART		(1 << 0)
-#define S3C2410_DMAF_CIRCULAR		(1 << 1)
+#ifndef __DMA_PL330_H_
+#define __DMA_PL330_H_ __FILE__
 
+#define S3C2410_DMAF_AUTOSTART	(1 << 0)
+#define S3C2410_DMAF_CIRCULAR	(1 << 1)
 /*
  * PL330 can assign any channel to communicate with
  * any of the peripherals attched to the DMAC.
  * For the sake of consistency across client drivers,
  * We keep the channel names unchanged and only add
  * missing peripherals are added.
- * Order is not important since S3C PL330 API driver
+ * Order is not important since DMA PL330 API driver
  * use these just as IDs.
  */
 enum dma_ch {
@@ -84,6 +83,14 @@ enum dma_ch {
 	DMACH_SLIMBUS4_TX,
 	DMACH_SLIMBUS5_RX,
 	DMACH_SLIMBUS5_TX,
+	DMACH_MTOM_0,
+	DMACH_MTOM_1,
+	DMACH_MTOM_2,
+	DMACH_MTOM_3,
+	DMACH_MTOM_4,
+	DMACH_MTOM_5,
+	DMACH_MTOM_6,
+	DMACH_MTOM_7,
 	/* END Marker, also used to denote a reserved channel */
 	DMACH_MAX,
 };
@@ -95,4 +102,4 @@ static inline bool s3c_dma_has_circular(void)
 
 #include <plat/dma.h>
 
-#endif	/* __S3C_DMA_PL330_H_ */
+#endif	/* __DMA_PL330_H_ */
arch/arm/plat-samsung/include/plat/s3c-pl330-pdata.h +1 -1
index bf5e2a9..64fdf66 100644
@@ -12,7 +12,7 @@
 #ifndef __S3C_PL330_PDATA_H
 #define __S3C_PL330_PDATA_H
 
-#include <plat/s3c-dma-pl330.h>
+#include <plat/dma-pl330.h>
 
 /*
  * Every PL330 DMAC has max 32 peripheral interfaces,
Signature · 1 line
1.7.1
#37 lore raw

PATCH v4 5/14 ARM: SAMSUNG: Update to use PL330-DMA driver

Quoted 95 lines · Boojin Kim

This patch adds to support PL330-DMA driver on DMADEVICE for S5P SoCs.

---
 arch/arm/mach-exynos4/include/mach/dma.h           |    4 +-
 arch/arm/mach-s5p64x0/include/mach/dma.h           |    2 +-
 arch/arm/mach-s5pc100/include/mach/dma.h           |    2 +-
 arch/arm/mach-s5pv210/include/mach/dma.h           |    2 +-
 arch/arm/plat-samsung/Kconfig                      |    8 +++++++
 .../include/plat/{s3c-dma-pl330.h => dma-pl330.h}  |   21 +++++++++++++------
 .../plat-samsung/include/plat/s3c-pl330-pdata.h    |    2 +-
 7 files changed, 28 insertions(+), 13 deletions(-)
 rename arch/arm/plat-samsung/include/plat/{s3c-dma-pl330.h => dma-pl330.h} (84%)
arch/arm/mach-exynos4/include/mach/dma.h +2 -2
index 81209eb..201842a 100644
@@ -20,7 +20,7 @@
 #ifndef __MACH_DMA_H
 #define __MACH_DMA_H
 
-/* This platform uses the common S3C DMA API driver for PL330 */
-#include <plat/s3c-dma-pl330.h>
+/* This platform uses the common DMA API driver for PL330 */
+#include <plat/dma-pl330.h>
 
 #endif /* __MACH_DMA_H */
arch/arm/mach-s5p64x0/include/mach/dma.h +1 -1
index 81209eb..1beae2c 100644
@@ -21,6 +21,6 @@
 #define __MACH_DMA_H
 
 /* This platform uses the common S3C DMA API driver for PL330 */
-#include <plat/s3c-dma-pl330.h>
+#include <plat/dma-pl330.h>
 
 #endif /* __MACH_DMA_H */
arch/arm/mach-s5pc100/include/mach/dma.h +1 -1
index 81209eb..1beae2c 100644
@@ -21,6 +21,6 @@
 #define __MACH_DMA_H
 
 /* This platform uses the common S3C DMA API driver for PL330 */
-#include <plat/s3c-dma-pl330.h>
+#include <plat/dma-pl330.h>
 
 #endif /* __MACH_DMA_H */
arch/arm/mach-s5pv210/include/mach/dma.h +1 -1
index 81209eb..1beae2c 100644
@@ -21,6 +21,6 @@
 #define __MACH_DMA_H
 
 /* This platform uses the common S3C DMA API driver for PL330 */
-#include <plat/s3c-dma-pl330.h>
+#include <plat/dma-pl330.h>
 
 #endif /* __MACH_DMA_H */
arch/arm/plat-samsung/Kconfig +8 -0
index 4d79519..cb170a6 100644
@@ -300,6 +300,14 @@ config S3C_PL330_DMA
 	help
 	  S3C DMA API Driver for PL330 DMAC.
 
+config DMADEV_PL330
+	bool
+	select DMADEVICES
+	select PL330_DMA
+	select ARM_AMBA
+	help
+	  Use DMA device engine for PL330 DMAC.
+
 comment "Power management"
 
 config SAMSUNG_PM_DEBUG
arch/arm/plat-samsung/include/plat/dma-pl330.h renamed from arch/arm/plat-samsung/include/plat/s3c-dma-pl330.h +0 -0
similarity index 84%
rename from arch/arm/plat-samsung/include/plat/s3c-dma-pl330.h
rename to arch/arm/plat-samsung/include/plat/dma-pl330.h
index 8107442..c402719 100644
@@ -8,19 +8,18 @@
  * (at your option) any later version.
  */
 

arch/arm/plat-samsung/include/plat/dma-pl330.h line 15

Quoted 10 lines
arch/arm/plat-samsung/include/plat/dma-pl330.h renamed from arch/arm/plat-samsung/include/plat/s3c-dma-pl330.h +4 -5
-#ifndef	__S3C_DMA_PL330_H_
-#define	__S3C_DMA_PL330_H_
-
-#define S3C2410_DMAF_AUTOSTART		(1 << 0)
-#define S3C2410_DMAF_CIRCULAR		(1 << 1)
+#ifndef __DMA_PL330_H_
+#define __DMA_PL330_H_ __FILE__
 
+#define S3C2410_DMAF_AUTOSTART	(1 << 0)
+#define S3C2410_DMAF_CIRCULAR	(1 << 1)

this looks like bogus diff and can be avoided

Quoted 45 lines
arch/arm/plat-samsung/include/plat/dma-pl330.h renamed from arch/arm/plat-samsung/include/plat/s3c-dma-pl330.h +10 -2
 /*
  * PL330 can assign any channel to communicate with
  * any of the peripherals attched to the DMAC.
  * For the sake of consistency across client drivers,
  * We keep the channel names unchanged and only add
  * missing peripherals are added.
- * Order is not important since S3C PL330 API driver
+ * Order is not important since DMA PL330 API driver
  * use these just as IDs.
  */
 enum dma_ch {
@@ -84,6 +83,14 @@ enum dma_ch {
 	DMACH_SLIMBUS4_TX,
 	DMACH_SLIMBUS5_RX,
 	DMACH_SLIMBUS5_TX,
+	DMACH_MTOM_0,
+	DMACH_MTOM_1,
+	DMACH_MTOM_2,
+	DMACH_MTOM_3,
+	DMACH_MTOM_4,
+	DMACH_MTOM_5,
+	DMACH_MTOM_6,
+	DMACH_MTOM_7,
 	/* END Marker, also used to denote a reserved channel */
 	DMACH_MAX,
 };
@@ -95,4 +102,4 @@ static inline bool s3c_dma_has_circular(void)
 
 #include <plat/dma.h>
 
-#endif	/* __S3C_DMA_PL330_H_ */
+#endif	/* __DMA_PL330_H_ */
arch/arm/plat-samsung/include/plat/s3c-pl330-pdata.h +1 -1
index bf5e2a9..64fdf66 100644
@@ -12,7 +12,7 @@
 #ifndef __S3C_PL330_PDATA_H
 #define __S3C_PL330_PDATA_H
 
-#include <plat/s3c-dma-pl330.h>
+#include <plat/dma-pl330.h>
 
 /*
  * Every PL330 DMAC has max 32 peripheral interfaces,
Signature · 2 lines
~Vinod Koul
Intel Corp.
#38 lore raw

PATCH v4 5/14 ARM: SAMSUNG: Update to use PL330-DMA driver

In reply to Boojin Kim
Quoted 8 lines · Boojin Kim
arch/arm/plat-samsung/Kconfig +0 -0
index 4d79519..cb170a6 100644
@@ -300,6 +300,14 @@ config S3C_PL330_DMA

? ? ? ?help
? ? ? ? ?S3C DMA API Driver for PL330 DMAC.

arch/arm/plat-samsung/Kconfig

Quoted 8 lines
arch/arm/plat-samsung/Kconfig +8 -0
+config DMADEV_PL330
+ ? ? ? bool
+ ? ? ? select DMADEVICES
+ ? ? ? select PL330_DMA
+ ? ? ? select ARM_AMBA
+ ? ? ? help
+ ? ? ? ? Use DMA device engine for PL330 DMAC.
+

If this is for the 'wrapper' dma driver, please use S3C or similar prefix.

Quoted 11 lines
arch/arm/plat-samsung/include/plat/dma-pl330.h renamed from arch/arm/plat-samsung/include/plat/s3c-dma-pl330.h +0 -0
similarity index 84%
rename from arch/arm/plat-samsung/include/plat/s3c-dma-pl330.h
rename to arch/arm/plat-samsung/include/plat/dma-pl330.h
index 8107442..c402719 100644
@@ -8,19 +8,18 @@

?* (at your option) any later version.
?*/

arch/arm/plat-samsung/include/plat/dma-pl330.h

Quoted 7 lines
arch/arm/plat-samsung/include/plat/dma-pl330.h renamed from arch/arm/plat-samsung/include/plat/s3c-dma-pl330.h +2 -5
-#ifndef ? ? ? ?__S3C_DMA_PL330_H_
-#define ? ? ? ?__S3C_DMA_PL330_H_
-
-#define S3C2410_DMAF_AUTOSTART ? ? ? ? (1 << 0)
-#define S3C2410_DMAF_CIRCULAR ? ? ? ? ?(1 << 1)
+#ifndef __DMA_PL330_H_
+#define __DMA_PL330_H_ __FILE__

To respect namespaces, please preserve S3C prefix because the file is Samsung specific.

Quoted 12 lines
arch/arm/plat-samsung/include/plat/dma-pl330.h renamed from arch/arm/plat-samsung/include/plat/s3c-dma-pl330.h +8 -0
@@ -84,6 +83,14 @@ enum dma_ch {
 ? ? ? ?DMACH_SLIMBUS4_TX,
 ? ? ? ?DMACH_SLIMBUS5_RX,
 ? ? ? ?DMACH_SLIMBUS5_TX,
+ ? ? ? DMACH_MTOM_0,
+ ? ? ? DMACH_MTOM_1,
+ ? ? ? DMACH_MTOM_2,
+ ? ? ? DMACH_MTOM_3,
+ ? ? ? DMACH_MTOM_4,
+ ? ? ? DMACH_MTOM_5,
+ ? ? ? DMACH_MTOM_6,
+ ? ? ? DMACH_MTOM_7,
Quoted 3 lines

? ? ? ?/* END Marker, also used to denote a reserved channel */ ? ? ? ?DMACH_MAX,
?};

Naming mem->mem channels should be unnecessary.
Not sure what you have in mind.

author
#39 lore raw

PATCH v4 6/14 ARM: SAMSUNG: Add common DMA operations

In reply to Boojin Kim

This patch adds common DMA operations which are used for Samsung DMA drivers. Currently there are two types of DMA driver for Samsung SoCs. The one is S3C-DMA for S3C SoCs and the other is PL330-DMA for S5P SoCs. This patch provides funcion pointers for common DMA operations to DMA client driver like SPI and Audio. It makes DMA client drivers support multi-platform.
In addition, this common DMA operations implement the shared actions that are needed for DMA client driver. For example shared actions are filter() function for dma_request_channel() and parameter passing for device_prep_slave_sg().

---
 arch/arm/mach-s3c2410/include/mach/dma.h       |    8 ++-
 arch/arm/mach-s3c64xx/include/mach/dma.h       |    4 +
 arch/arm/plat-samsung/Makefile                 |    6 +-
 arch/arm/plat-samsung/dma-ops.c                |  133 ++++++++++++++++++++++++
 arch/arm/plat-samsung/include/plat/dma-ops.h   |   64 +++++++++++
 arch/arm/plat-samsung/include/plat/dma-pl330.h |    4 +
 arch/arm/plat-samsung/include/plat/dma.h       |    1 +
 arch/arm/plat-samsung/s3c-dma-ops.c            |  133 ++++++++++++++++++++++++
 8 files changed, 350 insertions(+), 3 deletions(-)
 create mode 100644 arch/arm/plat-samsung/dma-ops.c
 create mode 100644 arch/arm/plat-samsung/include/plat/dma-ops.h
 create mode 100644 arch/arm/plat-samsung/s3c-dma-ops.c
arch/arm/mach-s3c2410/include/mach/dma.h +7 -1
index b2b2a5b..e61a91f 100644
@@ -13,7 +13,6 @@
 #ifndef __ASM_ARCH_DMA_H
 #define __ASM_ARCH_DMA_H __FILE__
 
-#include <plat/dma.h>
 #include <linux/sysdev.h>
 
 #define MAX_DMA_TRANSFER_SIZE   0x100000 /* Data Unit is half word  */
@@ -51,6 +50,13 @@ enum dma_ch {
 	DMACH_MAX,		/* the end entry */
 };
 
+static inline bool samsung_dma_is_dmadev(void)
+{
+	return false;
+}
+
+#include <plat/dma.h>
+
 #define DMACH_LOW_LEVEL	(1<<28)	/* use this to specifiy hardware ch no */
 
 /* we have 4 dma channels */
arch/arm/mach-s3c64xx/include/mach/dma.h +4 -0
index 0a5d926..49c3a53 100644
@@ -63,6 +63,10 @@ static __inline__ bool s3c_dma_has_circular(void)
 	return true;
 }
 
+static inline bool samsung_dma_is_dmadev(void)
+{
+	return false;
+}
 #define S3C2410_DMAF_CIRCULAR		(1 << 0)
 
 #include <plat/dma.h>
arch/arm/plat-samsung/Makefile +4 -2
index 53eb15b..9ecf2aa 100644
@@ -62,9 +62,11 @@ obj-$(CONFIG_SAMSUNG_DEV_PWM)	+= dev-pwm.o
 
 # DMA support
 
-obj-$(CONFIG_S3C_DMA)		+= dma.o
+obj-$(CONFIG_S3C_DMA)		+= dma.o s3c-dma-ops.o
 
-obj-$(CONFIG_S3C_PL330_DMA)	+= s3c-pl330.o
+obj-$(CONFIG_DMADEV_PL330)	+= dma-ops.o
+
+obj-$(CONFIG_S3C_PL330_DMA)	+= s3c-pl330.o s3c-dma-ops.o
 
 # PM support
 
arch/arm/plat-samsung/dma-ops.c new file +133 -0

133 lines not on this page · raw message

arch/arm/plat-samsung/include/plat/dma-ops.h new file +64 -0

64 lines not on this page · raw message

arch/arm/plat-samsung/include/plat/dma-pl330.h +4 -0
index c402719..687489e 100644
@@ -100,6 +100,10 @@ static inline bool s3c_dma_has_circular(void)
 	return true;
 }
 
+static inline bool samsung_dma_is_dmadev(void)
+{
+	return true;
+}
 #include <plat/dma.h>
 
 #endif	/* __DMA_PL330_H_ */
arch/arm/plat-samsung/include/plat/dma.h +1 -0
index 2e8f8c6..e87c6be 100644
@@ -125,3 +125,4 @@ extern int s3c2410_dma_set_opfn(unsigned int, s3c2410_dma_opfn_t rtn);
 extern int s3c2410_dma_set_buffdone_fn(unsigned int, s3c2410_dma_cbfn_t rtn);
 
 
+#include <plat/dma-ops.h>
arch/arm/plat-samsung/s3c-dma-ops.c new file +133 -0

133 lines not on this page · raw message

Signature · 1 line
1.7.1
#40 lore raw

PATCH v4 6/14 ARM: SAMSUNG: Add common DMA operations

Quoted 7 lines · Boojin Kim
arch/arm/plat-samsung/dma-ops.c new file +7 -0
+static unsigned samsung_dmadev_request(enum dma_ch dma_ch,
+				struct samsung_dma_info *info)
+{
+	struct dma_chan *chan;
+	dma_cap_mask_t mask;
+	struct dma_slave_config slave_config;
+

arch/arm/plat-samsung/dma-ops.c line 46

Quoted 10 lines
arch/arm/plat-samsung/dma-ops.c new file +10 -0
+	dma_cap_zero(mask);
+	dma_cap_set(info->cap, mask);
+
+	chan = dma_request_channel(mask, pl330_filter, (void *)dma_ch);
+
+	if (info->direction == DMA_FROM_DEVICE) {
+		memset(&slave_config, 0, sizeof(struct dma_slave_config));
+		slave_config.direction = info->direction;
+		slave_config.src_addr = info->fifo;
+		slave_config.src_addr_width = info->width;

This should really set slave_config.src_maxburst to something sensible too, even if that's just '1'.

arch/arm/plat-samsung/dma-ops.c line 52

Quoted 6 lines
arch/arm/plat-samsung/dma-ops.c new file +6 -0
+		dmaengine_slave_config(chan, &slave_config);
+	} else if (info->direction == DMA_TO_DEVICE) {
+		memset(&slave_config, 0, sizeof(struct dma_slave_config));
+		slave_config.direction = info->direction;
+		slave_config.dst_addr = info->fifo;
+		slave_config.dst_addr_width = info->width;

Ditto for dst_maxburst.

arch/arm/plat-samsung/dma-ops.c line 56

Quoted 4 lines
arch/arm/plat-samsung/dma-ops.c new file +4 -0
+		dmaengine_slave_config(chan, &slave_config);
+	}
+
+	return (unsigned)chan;

I hope these interfaces yet cleaned away soon so that these casts can be killed off.

arch/arm/plat-samsung/include/plat/dma-ops.h line 21

Quoted 4 lines
arch/arm/plat-samsung/include/plat/dma-ops.h new file +4 -0
+struct samsung_dma_prep_info {
+	enum dma_transaction_type cap;
+	enum dma_data_direction direction;
+	unsigned buf;

dma_addr_t ?

arch/arm/plat-samsung/include/plat/dma-ops.h line 32

Quoted 11 lines
arch/arm/plat-samsung/include/plat/dma-ops.h new file +11 -0
+	unsigned long period;
+	unsigned long len;
+	void (*fp)(void *data);
+	void *fp_param;
+};
+
+struct samsung_dma_info {
+	enum dma_transaction_type cap;
+	enum dma_data_direction direction;
+	enum dma_slave_buswidth width;
+	unsigned fifo;

dma_addr_t ?

arch/arm/plat-samsung/include/plat/dma-ops.h line 37

Quoted 5 lines
arch/arm/plat-samsung/include/plat/dma-ops.h new file +5 -0
+	struct s3c2410_dma_client *client;
+};
+
+struct samsung_dma_ops {
+	bool init;

Unused?

author
#41 lore raw

PATCH v4 6/14 ARM: SAMSUNG: Add common DMA operations

Russell King - ARM Linux Wrote:

Quoted 3 lines

Sent: Monday, July 25, 2011 6:36 PM
To: Boojin Kim
Cc: linux-arm-kernel at lists.infradead.org;

linux-samsung-soc at vger.kernel.org;

Quoted 15 lines

Kukjin Kim; Vinod Koul; Jassi Brar; Grant Likely; Mark Brown; Dan Williams
Subject: Re: [PATCH V4 06/14] ARM: SAMSUNG: Add common DMA operations

Quoted 11 lines · Boojin Kim
arch/arm/plat-samsung/dma-ops.c new file +11 -0
+static unsigned samsung_dmadev_request(enum dma_ch dma_ch,
+				struct samsung_dma_info *info)
+{
+	struct dma_chan *chan;
+	dma_cap_mask_t mask;
+	struct dma_slave_config slave_config;
+
+	dma_cap_zero(mask);
+	dma_cap_set(info->cap, mask);
+
+	chan = dma_request_channel(mask, pl330_filter, (void *)dma_ch);
Quoted 8 lines

arch/arm/plat-samsung/dma-ops.c line 46

Quoted 6 lines
arch/arm/plat-samsung/dma-ops.c new file +6 -0
+
+	if (info->direction == DMA_FROM_DEVICE) {
+		memset(&slave_config, 0, sizeof(struct dma_slave_config));
+		slave_config.direction = info->direction;
+		slave_config.src_addr = info->fifo;
+		slave_config.src_addr_width = info->width;

This should really set slave_config.src_maxburst to something sensible

too,

Quoted 1 line

even if that's just '1'.

I will address your comment.

Quoted 39 lines

arch/arm/plat-samsung/dma-ops.c line 52

Quoted 7 lines
arch/arm/plat-samsung/dma-ops.c new file +6 -0
+		dmaengine_slave_config(chan, &slave_config);
+	} else if (info->direction == DMA_TO_DEVICE) {
+		memset(&slave_config, 0, sizeof(struct dma_slave_config));
+		slave_config.direction = info->direction;
+		slave_config.dst_addr = info->fifo;
+		slave_config.dst_addr_width = info->width;

Ditto for dst_maxburst.

arch/arm/plat-samsung/dma-ops.c line 56

Quoted 4 lines
arch/arm/plat-samsung/dma-ops.c new file +4 -0
+		dmaengine_slave_config(chan, &slave_config);
+	}
+
+	return (unsigned)chan;

I hope these interfaces yet cleaned away soon so that these casts can be killed off.

arch/arm/plat-samsung/include/plat/dma-ops.h line 21

Quoted 4 lines
arch/arm/plat-samsung/include/plat/dma-ops.h new file +4 -0
+struct samsung_dma_prep_info {
+	enum dma_transaction_type cap;
+	enum dma_data_direction direction;
+	unsigned buf;

dma_addr_t ?

arch/arm/plat-samsung/include/plat/dma-ops.h line 32

Quoted 11 lines
arch/arm/plat-samsung/include/plat/dma-ops.h new file +11 -0
+	unsigned long period;
+	unsigned long len;
+	void (*fp)(void *data);
+	void *fp_param;
+};
+
+struct samsung_dma_info {
+	enum dma_transaction_type cap;
+	enum dma_data_direction direction;
+	enum dma_slave_buswidth width;
+	unsigned fifo;

dma_addr_t ?

Quoted 7 lines

arch/arm/plat-samsung/include/plat/dma-ops.h line 37

Quoted 5 lines
arch/arm/plat-samsung/include/plat/dma-ops.h new file +5 -0
+	struct s3c2410_dma_client *client;
+};
+
+struct samsung_dma_ops {
+	bool init;

Unused?

Yes, It's my mistake. I will address your comment.

#42 lore raw

PATCH v4 6/14 ARM: SAMSUNG: Add common DMA operations

In reply to Boojin Kim

arch/arm/plat-samsung/dma-ops.c line 28

Quoted 11 lines · Boojin Kim
arch/arm/plat-samsung/dma-ops.c new file +11 -0
+
+static bool pl330_filter(struct dma_chan *chan, void *param)
+{
+ ? ? ? struct dma_pl330_peri *peri = (struct dma_pl330_peri *)chan->private;
+ ? ? ? unsigned dma_ch = (unsigned)param;
+
+ ? ? ? if (peri->peri_id != dma_ch)
+ ? ? ? ? ? ? ? return false;
+
+ ? ? ? return true;
+}

This is what I meant... if we keep chan_id for paltform assigned IDs, these filter functions could simply become

static bool pl330_filter(struct dma_chan *chan, void *param)

{
        return chan->chan_id == param
}

And ideally in the long run, we could just drop the filter callback and add expected channel ID to the request_channel call.

Quoted 19 lines
arch/arm/plat-samsung/s3c-dma-ops.c new file +19 -0
+
+static inline int s3c_dma_trigger(unsigned ch)
+{
+ ? ? ? return s3c2410_dma_ctrl(ch, S3C2410_DMAOP_START);
+}
+
+static inline int s3c_dma_started(unsigned ch)
+{
+ ? ? ? return s3c2410_dma_ctrl(ch, S3C2410_DMAOP_STARTED);
+}
+
+static inline int s3c_dma_flush(unsigned ch)
+{
+ ? ? ? return s3c2410_dma_ctrl(ch, S3C2410_DMAOP_FLUSH);
+}
+
+static inline int s3c_dma_stop(unsigned ch)
+{
+ ? ? ? return s3c2410_dma_ctrl(ch, S3C2410_DMAOP_STOP);

arch/arm/plat-samsung/s3c-dma-ops.c

Quoted 10 lines
arch/arm/plat-samsung/s3c-dma-ops.c new file +10 -0
+}
+
+static struct samsung_dma_ops s3c_dma_ops = {
+ ? ? ? .request ? ? ? ?= s3c_dma_request,
+ ? ? ? .release ? ? ? ?= s3c_dma_release,
+ ? ? ? .prepare ? ? ? ?= s3c_dma_prepare,
+ ? ? ? .trigger ? ? ? ?= s3c_dma_trigger,
+ ? ? ? .started ? ? ? ?= s3c_dma_started,
+ ? ? ? .flush ? ? ? ? ?= s3c_dma_flush,
+ ? ? ? .stop ? ? ? ? ? = s3c_dma_stop,

These last 4 should be gnereallized into one callback with OP argument.

#43 lore raw

PATCH v4 6/14 ARM: SAMSUNG: Add common DMA operations

Quoted 16 lines · Jassi Brar

arch/arm/plat-samsung/dma-ops.c line 28

Quoted 11 lines · Boojin Kim
arch/arm/plat-samsung/dma-ops.c new file +11 -0
+
+static bool pl330_filter(struct dma_chan *chan, void *param)
+{
+ ? ? ? struct dma_pl330_peri *peri = (struct dma_pl330_peri *)chan->private;
+ ? ? ? unsigned dma_ch = (unsigned)param;
+
+ ? ? ? if (peri->peri_id != dma_ch)
+ ? ? ? ? ? ? ? return false;
+
+ ? ? ? return true;
+}

This is what I meant... if we keep chan_id for paltform assigned IDs, these filter functions could simply become

Quoted 7 lines

static bool pl330_filter(struct dma_chan *chan, void *param)

{
        return chan->chan_id == param
}

And ideally in the long run, we could just drop the filter callback and add expected channel ID to the request_channel call.

So what if you have a PL080 and PL330 drivers registered with the DMA engine code, and you need to match a specific PL330 channel?

#44 lore raw

PATCH v4 6/14 ARM: SAMSUNG: Add common DMA operations

Quoted 22 lines · Russell King - ARM Linux
Quoted 21 lines · Jassi Brar

arch/arm/plat-samsung/dma-ops.c line 28

Quoted 11 lines · Boojin Kim
arch/arm/plat-samsung/dma-ops.c new file +11 -0
+
+static bool pl330_filter(struct dma_chan *chan, void *param)
+{
+ ? ? ? struct dma_pl330_peri *peri = (struct dma_pl330_peri *)chan->private;
+ ? ? ? unsigned dma_ch = (unsigned)param;
+
+ ? ? ? if (peri->peri_id != dma_ch)
+ ? ? ? ? ? ? ? return false;
+
+ ? ? ? return true;
+}

This is what I meant... if we keep chan_id for paltform assigned IDs, these filter functions could simply become

static bool pl330_filter(struct dma_chan *chan, void *param) {
? ? ? ? return chan->chan_id == param
}

Quoted 6 lines
Quoted 2 lines

And ideally in the long run, we could just drop the filter callback and add expected channel ID to the request_channel call.

So what if you have a PL080 and PL330 drivers registered with the DMA engine code, and you need to match a specific PL330 channel?

Before we start, let me be clear that I don't say it's all possible today as such.
We will need changes to the API and modifications to the damc/client drivers (which are already misusing the API as it turns out).

I hope we agree, clients (esp 'generic' ones of the future) should not ask for channels from a particular dmac. They should simply tell DMA API, what capabilities they expect from the allocated channel - of whatever index on whichever dmac. And the platform should have specified capabilities of a channel
while introducing it to the DMA API. Yes, imho, DMA API should
only work with a pool of channels and not dmacs - it shouldn't matter from which dmac a channel comes.

So when a client asks for a channel, the dmaengine would return the first free channel that has just as much the requested capability.

That is, the generic filter function would look equivalent of :-

      return is_free(chan) && (cap_requested == cap_of(chan) & cap_requested)

Now it all boils down to defining the set of _practically_ possible capabilities and a method to exchange them between the API, Client and DMAC drivers.

The above is the overall approach.

The following is my idea of implementing it as of now, I am open to suggestions.

Assuming :-
***********
There are no more than 256 types of DMA'able devices
(MMC, USB, SPI etc) -- [8bits]

A type of device never has more than 16 instances in a platform
(MMC-0, MMC-1, MMC-2 etc) -- [4bits]

Mem->Mem, Mem->Dev, Dev->Mem, Dev->Dev capability in [4bits]

Max_Burst_Len for any channel is less than 64KB, in power of two [4bits] Support programmable Max_Burst_Len(tunable in geometric steps of 2) [1bit]

Max_RW_width/fifo_width is less than 128, in power of two -- [3bits] Support programmable Max_RW_Width(tunable in geometric steps of 2) [1bit]

Finally, No platform has more than 128 channels with identicial capabilities [7bits]

For a channel, when specific values of these fields are appended together, we get a unqiue 32-bits value called 'chan_id'

Though we can use 64-bits to store the capabilities if we think number or size of these fields need to be increased.

Thanks,
Jassi

#45 lore raw

PATCH v4 6/14 ARM: SAMSUNG: Add common DMA operations

Quoted 2 lines · Jassi Brar

Before we start, let me be clear that I don't say it's all possible today as such.

It _is_ possible today.

1. Arrange for individual DMA engine drivers to provide a filter function - eg, pl08x_filter_id() for pl08x channels.

2. Have the filter function check chan->device->dev->driver == its own struct driver as the very first thing, and reject on failure.

3. Have its own matching algorithm using whatever data is appropriate for the DMA engine driver.

4. Platforms (or SoC code) provide the match function plus match data via platform data to each driver.

That is essentially (except for (2)) how we deal with differing DMA engine drivers with AMBA peripherals, and it seems to work remarkably well.

Quoted 8 lines

I hope we agree, clients (esp 'generic' ones of the future) should not ask for channels from a particular dmac. They should simply tell DMA API, what capabilities they expect from the allocated channel - of whatever index on whichever dmac. And the platform should have specified capabilities of a channel
while introducing it to the DMA API. Yes, imho, DMA API should
only work with a pool of channels and not dmacs - it shouldn't matter from which dmac a channel comes.

You're quite clearly confused. "DMA API" has not very much to do with the subject we're discussing. The "DMA API" is the API for mapping and unmapping buffers for DMA. It has not much to do with the DMA engine API. So I'm not going to bother trying to decode what you said above until you start using the right terminology. I'm a stickler for that, get used to it.

No point talking about how round bananas are when you're actually discussing orange fruit.

Quoted 2 lines

So when a client asks for a channel, the dmaengine would return the first free channel that has just as much the requested capability.

No. For slave DMA, peripheral drivers normally need a specific channel on the DMA controller. Peripheral drivers normally do not know which channel they need, or even which DMA controller they require. That information is specific to the platform and SoC.

So, returning the "first free channel that matches the capability" is senseless - insane - for slave DMA.

Quoted 7 lines

That is, the generic filter function would look equivalent of :-

      return is_free(chan) && (cap_requested == cap_of(chan) & cap_requested)

Now it all boils down to defining the set of _practically_ possible capabilities and a method to exchange them between the API, Client and DMAC drivers.

What are these capabilities?

Quoted 9 lines

The above is the overall approach.

The following is my idea of implementing it as of now, I am open to suggestions.

Assuming :-
***********
There are no more than 256 types of DMA'able devices
(MMC, USB, SPI etc) -- [8bits]

Quoted 4 lines

A type of device never has more than 16 instances in a platform
(MMC-0, MMC-1, MMC-2 etc) -- [4bits]

Mem->Mem, Mem->Dev, Dev->Mem, Dev->Dev capability in [4bits]

No. You're being far too specific to your own DMA controller. Many DMA controllers (eg, PL08x) have a number of physical channels, all of which can be programmed for M2M, M2P, P2M and P2P. There is nothing in the design which restricts what a channel can do.

So to put that as the basis for a generic match algorithm is absolutely senseless.

Quoted 8 lines

Max_Burst_Len for any channel is less than 64KB, in power of two [4bits] Support programmable Max_Burst_Len(tunable in geometric steps of 2) [1bit]

Max_RW_width/fifo_width is less than 128, in power of two -- [3bits] Support programmable Max_RW_Width(tunable in geometric steps of 2) [1bit]

Finally, No platform has more than 128 channels with identicial capabilities [7bits]

There is absolutely no way that this will work in reality - are you on a different planet? As has already been described to you, MMCI can use one DMA channel, and programs it according to the DMA direction, and has in the past adjusted the burst size according to what's going on with the driver.

With your model, it would have to claim N channels from the DMA engine for all possible different configurations.

That's utterly unworkable and unrealistic.

So no, I don't think your idea of 'capabilities' is any solution. It just creates yet more problems - more than it solves.

#46 lore raw

PATCH v4 6/14 ARM: SAMSUNG: Add common DMA operations

Quoted 9 lines · Russell King - ARM Linux

1. Arrange for individual DMA engine drivers to provide a filter ? function - eg, pl08x_filter_id() for pl08x channels.

2. Have the filter function check chan->device->dev->driver == its ? own struct driver as the very first thing, and reject on failure.

3. Have its own matching algorithm using whatever data is appropriate ? for the DMA engine driver.

IMHO it should be possible to have client drivers not use platform specific details while choosing a channel. Otherwise, they are not really 'generic' 'platform-independent' client drivers.

Quoted 16 lines
Quoted 8 lines

I hope we agree, clients (esp 'generic' ones of the future) should not ask for channels from a particular dmac. They should simply tell DMA API, what capabilities they expect from the allocated channel - of whatever index on whichever dmac. And the platform should have specified capabilities of a channel while introducing it to the DMA API. ? Yes, imho, DMA API should only work with a pool of channels and not dmacs - it shouldn't matter from which dmac a channel comes.

You're quite clearly confused. ?"DMA API" has not very much to do with the subject we're discussing. ?The "DMA API" is the API for mapping and unmapping buffers for DMA. ?It has not much to do with the DMA engine API. ?So I'm not going to bother trying to decode what you said above until you start using the right terminology. ?I'm a stickler for that, get used to it.

Quoted 2 lines

No point talking about how round bananas are when you're actually discussing orange fruit.

Sorry, my carelessness.
I should have written DMAENGINE API, instead of DMA API.

If you want I can repost with s/DMA API/DMAENGINE API/

Quoted 6 lines
Quoted 3 lines

So when a client asks for a channel, the dmaengine would return the first free channel that has just as much the requested capability.

No. ?For slave DMA, peripheral drivers normally need a specific channel on the DMA controller.

Of course they do.
And It is the responsibility of platform to encode such information as a 'capability' of the channel. Capability to reach a particular peripheral, say.

Quoted 3 lines

?Peripheral drivers normally do not
know which channel they need, or even which DMA controller they require. ?That information is specific to the platform and SoC.

For that very reason I proposed, say, if MMC client driver is probed for 2nd instance
of MMC controller, it should ask for the following capabilities
(MMC << TYPE_SHFT) | (2 << INST_SHFT) //I don't show other
fields for simplicity

It is the job of _platform_ to set TYPE and INSTANCE fields to 'MMC' and 2 resp _only_ for the channel(s) that can reach its MMC_2 controller.

That way, when the client 'generically' asks for DMA_MMC_2, it will be given only one of those channels that can talk to second instance of MMC controller.

Quoted 9 lines
Quoted 7 lines

That is, the generic filter function would look equivalent of :-

? ? ? return is_free(chan) && (cap_requested == cap_of(chan) & cap_requested)

Now it all boils down to defining the set of _practically_ possible capabilities and a method to exchange them between the API, Client and DMAC drivers.

What are these capabilities?

I had mentioned the list below under 'Assuming'. We may add more.

Quoted 13 lines
Quoted 13 lines

The above is the overall approach.

The following is my idea of implementing it as of now, I am open to suggestions.

Assuming :-
***********
There are no more than 256 types of DMA'able devices ?(MMC, USB, SPI etc) -- ?[8bits]

A type of device never has more than 16 instances in a platform ?(MMC-0, MMC-1, MMC-2 etc) -- ?[4bits]

Quoted 6 lines
Quoted 1 line

Mem->Mem, Mem->Dev, Dev->Mem, Dev->Dev capability in [4bits]

No. ?You're being far too specific to your own DMA controller. ?Many DMA controllers (eg, PL08x) have a number of physical channels, all of which can be programmed for M2M, M2P, P2M and P2P. ?There is nothing in the design which restricts what a channel can do.

I am not being specific, at least not on this point. Btw, I have worked on pl080 as well and I have tried to be not specific to not only pl330 but also pl080.

If you notice I have assigned 4bits to the field. Each of the 4 bits can be set independently.
So, a capable pl08x channel can set all 4 bits to indicate that it can do all 4 types
- M2M, M2P, P2M and P2P.

Quoted 9 lines
Quoted 8 lines

Max_Burst_Len for any channel is less than 64KB, in power of two [4bits] Support programmable Max_Burst_Len(tunable in geometric steps of 2) ?[1bit]

Max_RW_width/fifo_width is less than 128, in power of two -- [3bits] Support programmable Max_RW_Width(tunable in geometric steps of 2) ?[1bit]

Finally, No platform has more than 128 channels with identicial capabilities [7bits]

Quoted 8 lines

There is absolutely no way that this will work in reality - are you on a different planet? ?As has already been described to you, MMCI can use one DMA channel, and programs it according to the DMA direction, and has in the past adjusted the burst size according to what's going on with the driver.

With your model, it would have to claim N channels from the DMA engine for all possible different configurations.

I don't think so.
What I proposed is only a list of capabilities and method to _select_ a suitable channel in a platform independent way.

For example, if MMCI driver wants to be able to change directions, it should specify Mem->Dev and Dev->Mem capability while requesting a channel. And use slave_config call to switch directions. (and yes we have to modify slave_config call and maybe some other parts too)

For being able to change burst size, it could set some 'ignore' bit + default value
to the 'fifo_width' field so that DMAENGINE ignores checking the fifo_width capability and upon slave_config either set requested burst_size if supported or return error if the requested burst size is not supported. That is implementation detail.

Sincerely, I would to know other capabilities that are more flexible than I have assumed here or missed altogether.

I have not yet written any code. I just wanted to share my belief that it is possible
to have client drivers truly independent of the platform they run on. And by not using platform_data of DMA channels.

Probably you don't, but if you do want, I can send rudimentary implementation of what I propose, in a few days.

Thanks

author
#47 lore raw

PATCH v4 6/14 ARM: SAMSUNG: Add common DMA operations

In reply to Jassi Brar

Jassi Brar Wrote:

Quoted 25 lines

Sent: Monday, July 25, 2011 8:52 PM
To: Boojin Kim
Cc: linux-arm-kernel at lists.infradead.org; linux-samsung- soc at vger.kernel.org; Vinod Koul; Dan Williams; Kukjin Kim; Grant Likely; Mark Brown
Subject: Re: [PATCH V4 06/14] ARM: SAMSUNG: Add common DMA operations

arch/arm/plat-samsung/dma-ops.c line 28

Quoted 12 lines · Boojin Kim
arch/arm/plat-samsung/dma-ops.c new file +4 -0
+
+static bool pl330_filter(struct dma_chan *chan, void *param)
+{
+       struct dma_pl330_peri *peri = (struct dma_pl330_peri *)chan-

private;

arch/arm/plat-samsung/dma-ops.c new file +7 -0
+       unsigned dma_ch = (unsigned)param;
+
+       if (peri->peri_id != dma_ch)
+               return false;
+
+       return true;
+}

This is what I meant... if we keep chan_id for paltform assigned IDs, these filter functions could simply become

Quoted 7 lines

static bool pl330_filter(struct dma_chan *chan, void *param)

{
        return chan->chan_id == param
}

And ideally in the long run, we could just drop the filter callback and add expected channel ID to the request_channel call.

The chan_id is set by dmaengine. So, We don't use it to hold the user specific Id.

Quoted 26 lines
Quoted 26 lines
arch/arm/plat-samsung/s3c-dma-ops.c new file +23 -0
+
+static inline int s3c_dma_trigger(unsigned ch)
+{
+       return s3c2410_dma_ctrl(ch, S3C2410_DMAOP_START);
+}
+
+static inline int s3c_dma_started(unsigned ch)
+{
+       return s3c2410_dma_ctrl(ch, S3C2410_DMAOP_STARTED);
+}
+
+static inline int s3c_dma_flush(unsigned ch)
+{
+       return s3c2410_dma_ctrl(ch, S3C2410_DMAOP_FLUSH);
+}
+
+static inline int s3c_dma_stop(unsigned ch)
+{
+       return s3c2410_dma_ctrl(ch, S3C2410_DMAOP_STOP);
+}
+
+static struct samsung_dma_ops s3c_dma_ops = {
+       .request        = s3c_dma_request,
Quoted 8 lines

arch/arm/plat-samsung/s3c-dma-ops.c line 126

Quoted 6 lines
arch/arm/plat-samsung/s3c-dma-ops.c new file +6 -0
+       .release        = s3c_dma_release,
+       .prepare        = s3c_dma_prepare,
+       .trigger        = s3c_dma_trigger,
+       .started        = s3c_dma_started,
+       .flush          = s3c_dma_flush,
+       .stop           = s3c_dma_stop,

These last 4 should be gnereallized into one callback with OP argument.

I don't have any idea about it. Can you explain it in more detail?

#48 lore raw

PATCH v4 6/14 ARM: SAMSUNG: Add common DMA operations

Quoted 31 lines · Boojin Kim

Jassi Brar Wrote:

Quoted 30 lines

Sent: Monday, July 25, 2011 8:52 PM
To: Boojin Kim
Cc: linux-arm-kernel at lists.infradead.org; linux-samsung- soc at vger.kernel.org; Vinod Koul; Dan Williams; Kukjin Kim; Grant Likely; Mark Brown
Subject: Re: [PATCH V4 06/14] ARM: SAMSUNG: Add common DMA operations

arch/arm/plat-samsung/dma-ops.c line 28

Quoted 12 lines · Boojin Kim
arch/arm/plat-samsung/dma-ops.c new file +4 -0
+
+static bool pl330_filter(struct dma_chan *chan, void *param)
+{
+ ? ? ? struct dma_pl330_peri *peri = (struct dma_pl330_peri *)chan-

private;
+ ? ? ? unsigned dma_ch = (unsigned)param;

arch/arm/plat-samsung/dma-ops.c new file +6 -0
+
+ ? ? ? if (peri->peri_id != dma_ch)
+ ? ? ? ? ? ? ? return false;
+
+ ? ? ? return true;
+}

This is what I meant... if we keep chan_id for paltform assigned IDs, these filter functions could simply become

static bool pl330_filter(struct dma_chan *chan, void *param) {
? ? ? ? return chan->chan_id == param
}

Quoted 4 lines
Quoted 2 lines

And ideally in the long run, we could just drop the filter callback and add expected channel ID to the request_channel call.

The chan_id is set by dmaengine. So, We don't use it to hold the user specific Id.

Not for long.
See https://lkml.org/lkml/2011/7/26/245

Quoted 31 lines
Quoted 23 lines
Quoted 23 lines
arch/arm/plat-samsung/s3c-dma-ops.c new file +23 -0
+
+static inline int s3c_dma_trigger(unsigned ch)
+{
+ ? ? ? return s3c2410_dma_ctrl(ch, S3C2410_DMAOP_START);
+}
+
+static inline int s3c_dma_started(unsigned ch)
+{
+ ? ? ? return s3c2410_dma_ctrl(ch, S3C2410_DMAOP_STARTED);
+}
+
+static inline int s3c_dma_flush(unsigned ch)
+{
+ ? ? ? return s3c2410_dma_ctrl(ch, S3C2410_DMAOP_FLUSH);
+}
+
+static inline int s3c_dma_stop(unsigned ch)
+{
+ ? ? ? return s3c2410_dma_ctrl(ch, S3C2410_DMAOP_STOP);
+}
+
+static struct samsung_dma_ops s3c_dma_ops = {
+ ? ? ? .request ? ? ? ?= s3c_dma_request,
Quoted 8 lines
Quoted 6 lines

+ ? ? ? .release ? ? ? ?= s3c_dma_release,
+ ? ? ? .prepare ? ? ? ?= s3c_dma_prepare,
+ ? ? ? .trigger ? ? ? ?= s3c_dma_trigger,
+ ? ? ? .started ? ? ? ?= s3c_dma_started,
+ ? ? ? .flush ? ? ? ? ?= s3c_dma_flush,
+ ? ? ? .stop ? ? ? ? ? = s3c_dma_stop,

These last 4 should be gnereallized into one callback with OP argument.

Quoted 1 line

I don't have any idea about it. Can you explain it in more detail?

static int s3c_dma_control(unsigned ch, enum s3c2410_chan_op/*or similar*/ op)

 {
        return s3c2410_dma_ctrl(ch, op);

}

static struct samsung_dma_ops s3c_dma_ops = {

        .request        = s3c_dma_request,
        .release        = s3c_dma_release,
        .prepare        = s3c_dma_prepare,
        .control        = s3c_dma_control,
author
#49 lore raw

PATCH v4 6/14 ARM: SAMSUNG: Add common DMA operations

Quoted 91 lines · Jassi Brar

Sent: Wednesday, July 27, 2011 10:34 AM
To: Boojin Kim
Cc: linux-arm-kernel at lists.infradead.org; linux-samsung- soc at vger.kernel.org; Vinod Koul; Dan Williams; Kukjin Kim; Grant Likely; Mark Brown
Subject: Re: [PATCH V4 06/14] ARM: SAMSUNG: Add common DMA operations

Quoted 7 lines · Boojin Kim

Jassi Brar Wrote:

Quoted 6 lines

Sent: Monday, July 25, 2011 8:52 PM
To: Boojin Kim
Cc: linux-arm-kernel at lists.infradead.org; linux-samsung- soc at vger.kernel.org; Vinod Koul; Dan Williams; Kukjin Kim; Grant Likely; Mark Brown
Subject: Re: [PATCH V4 06/14] ARM: SAMSUNG: Add common DMA

operations

Quoted 2 lines
Quoted 2 lines

On Mon, Jul 25, 2011 at 6:58 AM, Boojin Kim

<[email protected]>

Quoted 6 lines
Quoted 6 lines

arch/arm/plat-samsung/dma-ops.c

Quoted 4 lines · wrote:
arch/arm/plat-samsung/dma-ops.c new file +4 -0
+
+static bool pl330_filter(struct dma_chan *chan, void *param)
+{
+       struct dma_pl330_peri *peri = (struct dma_pl330_peri

*)chan-

Quoted 9 lines
Quoted 9 lines

arch/arm/plat-samsung/dma-ops.c line 28

Quoted 8 lines

private;

arch/arm/plat-samsung/dma-ops.c new file +7 -0
+       unsigned dma_ch = (unsigned)param;
+
+       if (peri->peri_id != dma_ch)
+               return false;
+
+       return true;
+}

This is what I meant... if we keep chan_id for paltform assigned

IDs,

Quoted 10 lines
Quoted 9 lines

these filter functions could simply become

static bool pl330_filter(struct dma_chan *chan, void *param)

{
        return chan->chan_id == param
}

And ideally in the long run, we could just drop the filter callback and add expected channel ID to the request_channel call.

The chan_id is set by dmaengine. So, We don't use it to hold the

user specific

Quoted 1 line

Id.

Not for long.
See https://lkml.org/lkml/2011/7/26/245

Quoted 23 lines
Quoted 23 lines
Quoted 23 lines
arch/arm/plat-samsung/s3c-dma-ops.c new file +23 -0
+
+static inline int s3c_dma_trigger(unsigned ch)
+{
+       return s3c2410_dma_ctrl(ch, S3C2410_DMAOP_START);
+}
+
+static inline int s3c_dma_started(unsigned ch)
+{
+       return s3c2410_dma_ctrl(ch, S3C2410_DMAOP_STARTED);
+}
+
+static inline int s3c_dma_flush(unsigned ch)
+{
+       return s3c2410_dma_ctrl(ch, S3C2410_DMAOP_FLUSH);
+}
+
+static inline int s3c_dma_stop(unsigned ch)
+{
+       return s3c2410_dma_ctrl(ch, S3C2410_DMAOP_STOP);
+}
+
+static struct samsung_dma_ops s3c_dma_ops = {
+       .request        = s3c_dma_request,
Quoted 8 lines
Quoted 8 lines

arch/arm/plat-samsung/s3c-dma-ops.c line 126

Quoted 6 lines
arch/arm/plat-samsung/s3c-dma-ops.c new file +6 -0
+       .release        = s3c_dma_release,
+       .prepare        = s3c_dma_prepare,
+       .trigger        = s3c_dma_trigger,
+       .started        = s3c_dma_started,
+       .flush          = s3c_dma_flush,
+       .stop           = s3c_dma_stop,

These last 4 should be gnereallized into one callback with OP

argument.

Quoted 1 line

I don't have any idea about it. Can you explain it in more detail?

static int s3c_dma_control(unsigned ch, enum s3c2410_chan_op/*or similar*/ op)

 {
        return s3c2410_dma_ctrl(ch, op);
Quoted 7 lines

}

static struct samsung_dma_ops s3c_dma_ops = {

        .request        = s3c_dma_request,
        .release        = s3c_dma_release,
        .prepare        = s3c_dma_prepare,
        .control        = s3c_dma_control,

'Struct samsung_dma_ops' is used for both 'S3C-DMA-OPS' for 's3c dma' and 'DMA-OPS' for 'dmaengine'.
If I modify "Struct samsung_dma_ops" as your guide, It gives un-expectable effect to DMA-OPS.
Actually, We don't want the client with 'DMA-OPS' uses 'enum s3c2410_chan_op' operation anymore.

#50 lore raw

PATCH v4 6/14 ARM: SAMSUNG: Add common DMA operations

Quoted 99 lines · Boojin Kim
Quoted 93 lines · Jassi Brar

Sent: Wednesday, July 27, 2011 10:34 AM
To: Boojin Kim
Cc: linux-arm-kernel at lists.infradead.org; linux-samsung- soc at vger.kernel.org; Vinod Koul; Dan Williams; Kukjin Kim; Grant Likely; Mark Brown
Subject: Re: [PATCH V4 06/14] ARM: SAMSUNG: Add common DMA operations

Quoted 7 lines · Boojin Kim

Jassi Brar Wrote:

Quoted 6 lines

Sent: Monday, July 25, 2011 8:52 PM
To: Boojin Kim
Cc: linux-arm-kernel at lists.infradead.org; linux-samsung- soc at vger.kernel.org; Vinod Koul; Dan Williams; Kukjin Kim; Grant Likely; Mark Brown
Subject: Re: [PATCH V4 06/14] ARM: SAMSUNG: Add common DMA

operations

Quoted 2 lines
Quoted 2 lines

On Mon, Jul 25, 2011 at 6:58 AM, Boojin Kim

<[email protected]>

Quoted 6 lines
Quoted 6 lines

arch/arm/plat-samsung/dma-ops.c

Quoted 4 lines · wrote:
arch/arm/plat-samsung/dma-ops.c new file +4 -0
+
+static bool pl330_filter(struct dma_chan *chan, void *param)
+{
+ ? ? ? struct dma_pl330_peri *peri = (struct dma_pl330_peri

*)chan-

Quoted 9 lines
Quoted 9 lines

arch/arm/plat-samsung/dma-ops.c line 28

Quoted 8 lines

private;
+ ? ? ? unsigned dma_ch = (unsigned)param;

arch/arm/plat-samsung/dma-ops.c new file +6 -0
+
+ ? ? ? if (peri->peri_id != dma_ch)
+ ? ? ? ? ? ? ? return false;
+
+ ? ? ? return true;
+}

This is what I meant... if we keep chan_id for paltform assigned

IDs,

Quoted 10 lines
Quoted 9 lines

these filter functions could simply become

static bool pl330_filter(struct dma_chan *chan, void *param) {
? ? ? ? return chan->chan_id == param
}

And ideally in the long run, we could just drop the filter callback and add expected channel ID to the request_channel call.

The chan_id is set by dmaengine. So, We don't use it to hold the

user specific

Quoted 1 line

Id.

Not for long.
See ?https://lkml.org/lkml/2011/7/26/245

Quoted 23 lines
Quoted 23 lines
Quoted 23 lines
arch/arm/plat-samsung/s3c-dma-ops.c new file +23 -0
+
+static inline int s3c_dma_trigger(unsigned ch)
+{
+ ? ? ? return s3c2410_dma_ctrl(ch, S3C2410_DMAOP_START);
+}
+
+static inline int s3c_dma_started(unsigned ch)
+{
+ ? ? ? return s3c2410_dma_ctrl(ch, S3C2410_DMAOP_STARTED);
+}
+
+static inline int s3c_dma_flush(unsigned ch)
+{
+ ? ? ? return s3c2410_dma_ctrl(ch, S3C2410_DMAOP_FLUSH);
+}
+
+static inline int s3c_dma_stop(unsigned ch)
+{
+ ? ? ? return s3c2410_dma_ctrl(ch, S3C2410_DMAOP_STOP);
+}
+
+static struct samsung_dma_ops s3c_dma_ops = {
+ ? ? ? .request ? ? ? ?= s3c_dma_request,
Quoted 8 lines
Quoted 8 lines
Quoted 6 lines

+ ? ? ? .release ? ? ? ?= s3c_dma_release,
+ ? ? ? .prepare ? ? ? ?= s3c_dma_prepare,
+ ? ? ? .trigger ? ? ? ?= s3c_dma_trigger,
+ ? ? ? .started ? ? ? ?= s3c_dma_started,
+ ? ? ? .flush ? ? ? ? ?= s3c_dma_flush,
+ ? ? ? .stop ? ? ? ? ? = s3c_dma_stop,

These last 4 should be gnereallized into one callback with OP

argument.

Quoted 1 line

I don't have any idea about it. Can you explain it in more detail?

static int s3c_dma_control(unsigned ch, enum s3c2410_chan_op/*or similar*/ op)
?{
? ? ? ? return s3c2410_dma_ctrl(ch, op);
?}

Quoted 5 lines

static struct samsung_dma_ops s3c_dma_ops = {
? ? ? ? .request ? ? ? ?= s3c_dma_request,
? ? ? ? .release ? ? ? ?= s3c_dma_release,
? ? ? ? .prepare ? ? ? ?= s3c_dma_prepare,
? ? ? ? .control ? ? ? ?= s3c_dma_control,

Quoted 6 lines

'Struct samsung_dma_ops' is used for both 'S3C-DMA-OPS' for 's3c dma' and 'DMA-OPS' for 'dmaengine'.
If I modify "Struct samsung_dma_ops" as your guide, It gives un-expectable effect to DMA-OPS.
Actually, We don't want the client with 'DMA-OPS' uses 'enum s3c2410_chan_op' operation anymore.

" enum s3c2410_chan_op /* or similar */ " <<<< note 'or similar'

Defining a callback for each value of the argument doesn't make sense.

author
#51 lore raw

PATCH v4 6/14 ARM: SAMSUNG: Add common DMA operations

Quoted 116 lines · Jassi Brar

Sent: Wednesday, July 27, 2011 4:58 PM
To: Boojin Kim
Cc: Kukjin Kim; Vinod Koul; Mark Brown; Grant Likely; linux-samsung- soc at vger.kernel.org; Dan Williams; linux-arm-
kernel at lists.infradead.org
Subject: Re: [PATCH V4 06/14] ARM: SAMSUNG: Add common DMA operations

Quoted 7 lines · Boojin Kim
Quoted 6 lines · Jassi Brar

Sent: Wednesday, July 27, 2011 10:34 AM
To: Boojin Kim
Cc: linux-arm-kernel at lists.infradead.org; linux-samsung- soc at vger.kernel.org; Vinod Koul; Dan Williams; Kukjin Kim; Grant Likely; Mark Brown
Subject: Re: [PATCH V4 06/14] ARM: SAMSUNG: Add common DMA

operations

Quoted 2 lines
Quoted 2 lines

On Tue, Jul 26, 2011 at 3:05 PM, Boojin Kim

<[email protected]>

Quoted 29 lines
Quoted 29 lines
Quoted 7 lines · wrote:

Jassi Brar Wrote:

Quoted 6 lines

Sent: Monday, July 25, 2011 8:52 PM
To: Boojin Kim
Cc: linux-arm-kernel at lists.infradead.org; linux-samsung- soc at vger.kernel.org; Vinod Koul; Dan Williams; Kukjin Kim; Grant Likely; Mark Brown
Subject: Re: [PATCH V4 06/14] ARM: SAMSUNG: Add common DMA

operations

Quoted 2 lines
Quoted 2 lines

On Mon, Jul 25, 2011 at 6:58 AM, Boojin Kim

<[email protected]>

Quoted 6 lines
Quoted 6 lines

arch/arm/plat-samsung/dma-ops.c

Quoted 4 lines · wrote:
arch/arm/plat-samsung/dma-ops.c new file +4 -0
+
+static bool pl330_filter(struct dma_chan *chan, void *param)
+{
+       struct dma_pl330_peri *peri = (struct dma_pl330_peri

*)chan-

Quoted 9 lines
Quoted 9 lines

arch/arm/plat-samsung/dma-ops.c line 28

Quoted 8 lines

private;

arch/arm/plat-samsung/dma-ops.c new file +7 -0
+       unsigned dma_ch = (unsigned)param;
+
+       if (peri->peri_id != dma_ch)
+               return false;
+
+       return true;
+}

This is what I meant... if we keep chan_id for paltform assigned

IDs,

Quoted 8 lines
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines

these filter functions could simply become

static bool pl330_filter(struct dma_chan *chan, void *param)

{
        return chan->chan_id == param
}

And ideally in the long run, we could just drop the filter

callback

Quoted 48 lines
Quoted 48 lines
Quoted 2 lines
Quoted 1 line

and add expected channel ID to the request_channel call.

The chan_id is set by dmaengine. So, We don't use it to hold the

user specific

Quoted 1 line

Id.

Not for long.
See https://lkml.org/lkml/2011/7/26/245

Quoted 23 lines
Quoted 23 lines
Quoted 23 lines
arch/arm/plat-samsung/s3c-dma-ops.c new file +23 -0
+
+static inline int s3c_dma_trigger(unsigned ch)
+{
+       return s3c2410_dma_ctrl(ch, S3C2410_DMAOP_START);
+}
+
+static inline int s3c_dma_started(unsigned ch)
+{
+       return s3c2410_dma_ctrl(ch, S3C2410_DMAOP_STARTED);
+}
+
+static inline int s3c_dma_flush(unsigned ch)
+{
+       return s3c2410_dma_ctrl(ch, S3C2410_DMAOP_FLUSH);
+}
+
+static inline int s3c_dma_stop(unsigned ch)
+{
+       return s3c2410_dma_ctrl(ch, S3C2410_DMAOP_STOP);
+}
+
+static struct samsung_dma_ops s3c_dma_ops = {
+       .request        = s3c_dma_request,
Quoted 8 lines
Quoted 8 lines

arch/arm/plat-samsung/s3c-dma-ops.c line 126

Quoted 6 lines
arch/arm/plat-samsung/s3c-dma-ops.c new file +6 -0
+       .release        = s3c_dma_release,
+       .prepare        = s3c_dma_prepare,
+       .trigger        = s3c_dma_trigger,
+       .started        = s3c_dma_started,
+       .flush          = s3c_dma_flush,
+       .stop           = s3c_dma_stop,

These last 4 should be gnereallized into one callback with OP

argument.

Quoted 1 line

I don't have any idea about it. Can you explain it in more detail?

static int s3c_dma_control(unsigned ch, enum s3c2410_chan_op/*or similar*/ op)

 {
        return s3c2410_dma_ctrl(ch, op);

}

Quoted 6 lines
Quoted 5 lines

static struct samsung_dma_ops s3c_dma_ops = {

        .request        = s3c_dma_request,
        .release        = s3c_dma_release,
        .prepare        = s3c_dma_prepare,
        .control        = s3c_dma_control,

'Struct samsung_dma_ops' is used for both 'S3C-DMA-OPS' for 's3c

dma' and

Quoted 2 lines

'DMA-OPS' for 'dmaengine'.
If I modify "Struct samsung_dma_ops" as your guide, It gives un-

expectable

Quoted 8 lines
Quoted 2 lines

effect to DMA-OPS.
Actually, We don't want the client with 'DMA-OPS' uses 'enum

s3c2410_chan_op'

Quoted 1 line

operation anymore.

" enum s3c2410_chan_op /* or similar */ " <<<< note 'or similar'

Defining a callback for each value of the argument doesn't make sense.

Yes, The command may not be 'enum s3c2410_chan_op'. But it's very similar with 'enum s3c2410_chan_op'.
So, It brings same result that I sad.
Actually, I quietly agree with your comment. If the 'struct samsung_dma_ops' is only used for 's3c-dma-ops', I would address your comment. But, 'struct samsung_dma_ops' is used for all Samsung dma clients. I aim that 'struct samsung_dma_ops' provide the DMA clients with 'dmaengine' friendly DMA interface without any other command.

author
#52 lore raw

PATCH v4 7/14 ARM: EXYNOS4: Use generic DMA PL330 driver

In reply to Boojin Kim

This patch makes Samsung EXYNOS4 to use DMA PL330 driver on DMADEVICE. The EXYNOS4 uses DMA generic APIs instead of SAMSUNG specific S3C-PL330 APIs.

---
 arch/arm/mach-exynos4/Kconfig |    2 +-
 arch/arm/mach-exynos4/clock.c |   16 +-
 arch/arm/mach-exynos4/dma.c   |  323 +++++++++++++++++++++++++++--------------
 3 files changed, 221 insertions(+), 120 deletions(-)
arch/arm/mach-exynos4/Kconfig +1 -1
index 1435fc3..5cc9b7a 100644
@@ -11,7 +11,7 @@ if ARCH_EXYNOS4
 
 config CPU_EXYNOS4210
 	bool
-	select S3C_PL330_DMA
+	select DMADEV_PL330
 	help
 	  Enable EXYNOS4210 CPU support
 
arch/arm/mach-exynos4/clock.c +9 -7
index 871f9d5..1b2e78c 100644
@@ -47,6 +47,11 @@ static struct clk clk_sclk_usbphy1 = {
 	.id		= -1,
 };
 
+static struct clk dummy_apb_pclk = {
+	.name		= "apb_pclk",
+	.id		= -1,
+};
+
 static int exynos4_clksrc_mask_top_ctrl(struct clk *clk, int enable)
 {
 	return s5p_gatectrl(S5P_CLKSRC_MASK_TOP, clk, enable);
@@ -485,16 +490,11 @@ static struct clk init_clocks_off[] = {
 		.enable		= exynos4_clk_ip_fsys_ctrl,
 		.ctrlbit	= (1 << 10),
 	}, {
-		.name		= "pdma",
-		.id		= 0,
+		.name		= "dma",
+		.id		= -1,
 		.enable		= exynos4_clk_ip_fsys_ctrl,
 		.ctrlbit	= (1 << 0),
 	}, {
-		.name		= "pdma",
-		.id		= 1,
-		.enable		= exynos4_clk_ip_fsys_ctrl,
-		.ctrlbit	= (1 << 1),
-	}, {
 		.name		= "adc",
 		.id		= -1,
 		.enable		= exynos4_clk_ip_peril_ctrl,
@@ -1212,5 +1212,7 @@ void __init exynos4_register_clocks(void)
 	s3c_register_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off));
 	s3c_disable_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off));
 
+	s3c24xx_register_clock(&dummy_apb_pclk);
+
 	s3c_pwmclk_init();
 }
arch/arm/mach-exynos4/dma.c +211 -112

362 lines not on this page · raw message

Signature · 1 line
1.7.1
#53 lore raw

PATCH v4 7/14 ARM: EXYNOS4: Use generic DMA PL330 driver

Quoted 26 lines · Boojin Kim
arch/arm/mach-exynos4/dma.c +0 -0
index 564bb53..e1c00cf 100644
@@ -21,151 +21,250 @@

?* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ?*/

-#include <linux/platform_device.h>
?#include <linux/dma-mapping.h>

arch/arm/mach-exynos4/dma.c +3 -0
+#include <linux/amba/bus.h>
+#include <linux/amba/pl330.h>
 
+#include <asm/irq.h>

?#include <plat/devs.h>
?#include <plat/irqs.h>

?#include <mach/map.h>
?#include <mach/irqs.h>

arch/arm/mach-exynos4/dma.c +1 -2
-
-#include <plat/s3c-pl330-pdata.h>
+#include <mach/dma.h>

?static u64 dma_dmamask = DMA_BIT_MASK(32);

arch/arm/mach-exynos4/dma.c +0 -1
-static struct resource exynos4_pdma0_resource[] = {

arch/arm/mach-exynos4/dma.c

Quoted 10 lines
arch/arm/mach-exynos4/dma.c +1 -9
- ? ? ? [0] = {
- ? ? ? ? ? ? ? .start ?= EXYNOS4_PA_PDMA0,
- ? ? ? ? ? ? ? .end ? ?= EXYNOS4_PA_PDMA0 + SZ_4K,
- ? ? ? ? ? ? ? .flags ?= IORESOURCE_MEM,
- ? ? ? },
- ? ? ? [1] = {
- ? ? ? ? ? ? ? .start ?= IRQ_PDMA0,
- ? ? ? ? ? ? ? .end ? ?= IRQ_PDMA0,
- ? ? ? ? ? ? ? .flags ?= IORESOURCE_IRQ,
+struct dma_pl330_peri pdma0_peri[32] = {

Please remove 32 from the list (it seems you don't always pass 32 elements) Also for completeness, please explicitly write element indices below because it's not some array of randomly placed elements.
Same for every other such occurance.

Quoted 128 lines

+ ? ? ? {
+ ? ? ? ? ? ? ? .peri_id = (u8)DMACH_PCM0_RX,
+ ? ? ? ? ? ? ? .rqtype = DEVTOMEM,
+ ? ? ? }, {
+ ? ? ? ? ? ? ? .peri_id = (u8)DMACH_PCM0_TX,
+ ? ? ? ? ? ? ? .rqtype = MEMTODEV,
+ ? ? ? }, {
+ ? ? ? ? ? ? ? .peri_id = (u8)DMACH_PCM2_RX,
+ ? ? ? ? ? ? ? .rqtype = DEVTOMEM,
+ ? ? ? }, {
+ ? ? ? ? ? ? ? .peri_id = (u8)DMACH_PCM2_TX,
+ ? ? ? ? ? ? ? .rqtype = MEMTODEV,
+ ? ? ? ? ? ? ? .burst_sz = 4,
+ ? ? ? }, {
+ ? ? ? ? ? ? ? .peri_id = (u8)DMACH_MSM_REQ0,
+ ? ? ? }, {
+ ? ? ? ? ? ? ? .peri_id = (u8)DMACH_MSM_REQ2,
+ ? ? ? }, {
+ ? ? ? ? ? ? ? .peri_id = (u8)DMACH_SPI0_RX,
+ ? ? ? ? ? ? ? .rqtype = DEVTOMEM,
+ ? ? ? ? ? ? ? .burst_sz = 1,
+ ? ? ? }, {
+ ? ? ? ? ? ? ? .peri_id = (u8)DMACH_SPI0_TX,
+ ? ? ? ? ? ? ? .rqtype = MEMTODEV,
+ ? ? ? ? ? ? ? .burst_sz = 1,
+ ? ? ? }, {
+ ? ? ? ? ? ? ? .peri_id = (u8)DMACH_SPI2_RX,
+ ? ? ? ? ? ? ? .rqtype = DEVTOMEM,
+ ? ? ? ? ? ? ? .burst_sz = 1,
+ ? ? ? }, {
+ ? ? ? ? ? ? ? .peri_id = (u8)DMACH_SPI2_TX,
+ ? ? ? ? ? ? ? .rqtype = MEMTODEV,
+ ? ? ? ? ? ? ? .burst_sz = 1,
+ ? ? ? }, {
+ ? ? ? ? ? ? ? .peri_id = (u8)DMACH_I2S0S_TX,
+ ? ? ? ? ? ? ? .rqtype = MEMTODEV,
+ ? ? ? }, {
+ ? ? ? ? ? ? ? .peri_id = (u8)DMACH_I2S0_RX,
+ ? ? ? ? ? ? ? .rqtype = DEVTOMEM,
+ ? ? ? }, {
+ ? ? ? ? ? ? ? .peri_id = (u8)DMACH_I2S0_TX,
+ ? ? ? ? ? ? ? .rqtype = MEMTODEV,
+ ? ? ? }, {
+ ? ? ? ? ? ? ? .peri_id = (u8)DMACH_UART0_RX,
+ ? ? ? ? ? ? ? .rqtype = DEVTOMEM,
+ ? ? ? ? ? ? ? .burst_sz = 4,
+ ? ? ? }, {
+ ? ? ? ? ? ? ? .peri_id = (u8)DMACH_UART0_TX,
+ ? ? ? ? ? ? ? .rqtype = MEMTODEV,
+ ? ? ? ? ? ? ? .burst_sz = 4,
+ ? ? ? }, {
+ ? ? ? ? ? ? ? .peri_id = (u8)DMACH_UART2_RX,
+ ? ? ? ? ? ? ? .rqtype = DEVTOMEM,
+ ? ? ? ? ? ? ? .burst_sz = 4,
+ ? ? ? }, {
+ ? ? ? ? ? ? ? .peri_id = (u8)DMACH_UART2_TX,
+ ? ? ? ? ? ? ? .rqtype = MEMTODEV,
+ ? ? ? ? ? ? ? .burst_sz = 4,
+ ? ? ? }, {
+ ? ? ? ? ? ? ? .peri_id = (u8)DMACH_UART4_RX,
+ ? ? ? ? ? ? ? .rqtype = DEVTOMEM,
+ ? ? ? ? ? ? ? .burst_sz = 4,
+ ? ? ? }, {
+ ? ? ? ? ? ? ? .peri_id = (u8)DMACH_UART4_TX,
+ ? ? ? ? ? ? ? .rqtype = MEMTODEV,
+ ? ? ? ? ? ? ? .burst_sz = 4,
+ ? ? ? }, {
+ ? ? ? ? ? ? ? .peri_id = (u8)DMACH_SLIMBUS0_RX,
+ ? ? ? ? ? ? ? .rqtype = DEVTOMEM,
+ ? ? ? }, {
+ ? ? ? ? ? ? ? .peri_id = (u8)DMACH_SLIMBUS0_TX,
+ ? ? ? ? ? ? ? .rqtype = MEMTODEV,
+ ? ? ? }, {
+ ? ? ? ? ? ? ? .peri_id = (u8)DMACH_SLIMBUS2_RX,
+ ? ? ? ? ? ? ? .rqtype = DEVTOMEM,
+ ? ? ? }, {
+ ? ? ? ? ? ? ? .peri_id = (u8)DMACH_SLIMBUS2_TX,
+ ? ? ? ? ? ? ? .rqtype = MEMTODEV,
+ ? ? ? }, {
+ ? ? ? ? ? ? ? .peri_id = (u8)DMACH_SLIMBUS4_RX,
+ ? ? ? ? ? ? ? .rqtype = DEVTOMEM,
+ ? ? ? }, {
+ ? ? ? ? ? ? ? .peri_id = (u8)DMACH_SLIMBUS4_TX,
+ ? ? ? ? ? ? ? .rqtype = MEMTODEV,
+ ? ? ? }, {
+ ? ? ? ? ? ? ? .peri_id = (u8)DMACH_AC97_MICIN,
+ ? ? ? ? ? ? ? .rqtype = DEVTOMEM,
+ ? ? ? ? ? ? ? .burst_sz = 4,
+ ? ? ? }, {
+ ? ? ? ? ? ? ? .peri_id = (u8)DMACH_AC97_PCMIN,
+ ? ? ? ? ? ? ? .rqtype = DEVTOMEM,
+ ? ? ? ? ? ? ? .burst_sz = 4,
+ ? ? ? }, {
+ ? ? ? ? ? ? ? .peri_id = (u8)DMACH_AC97_PCMOUT,
+ ? ? ? ? ? ? ? .rqtype = MEMTODEV,
+ ? ? ? ? ? ? ? .burst_sz = 4,
? ? ? ?},
?};

arch/arm/mach-exynos4/dma.c +0 -27
-static struct s3c_pl330_platdata exynos4_pdma0_pdata = {
- ? ? ? .peri = {
- ? ? ? ? ? ? ? [0] = DMACH_PCM0_RX,
- ? ? ? ? ? ? ? [1] = DMACH_PCM0_TX,
- ? ? ? ? ? ? ? [2] = DMACH_PCM2_RX,
- ? ? ? ? ? ? ? [3] = DMACH_PCM2_TX,
- ? ? ? ? ? ? ? [4] = DMACH_MSM_REQ0,
- ? ? ? ? ? ? ? [5] = DMACH_MSM_REQ2,
- ? ? ? ? ? ? ? [6] = DMACH_SPI0_RX,
- ? ? ? ? ? ? ? [7] = DMACH_SPI0_TX,
- ? ? ? ? ? ? ? [8] = DMACH_SPI2_RX,
- ? ? ? ? ? ? ? [9] = DMACH_SPI2_TX,
- ? ? ? ? ? ? ? [10] = DMACH_I2S0S_TX,
- ? ? ? ? ? ? ? [11] = DMACH_I2S0_RX,
- ? ? ? ? ? ? ? [12] = DMACH_I2S0_TX,
- ? ? ? ? ? ? ? [13] = DMACH_I2S2_RX,
- ? ? ? ? ? ? ? [14] = DMACH_I2S2_TX,
- ? ? ? ? ? ? ? [15] = DMACH_UART0_RX,
- ? ? ? ? ? ? ? [16] = DMACH_UART0_TX,
- ? ? ? ? ? ? ? [17] = DMACH_UART2_RX,
- ? ? ? ? ? ? ? [18] = DMACH_UART2_TX,
- ? ? ? ? ? ? ? [19] = DMACH_UART4_RX,
- ? ? ? ? ? ? ? [20] = DMACH_UART4_TX,
- ? ? ? ? ? ? ? [21] = DMACH_SLIMBUS0_RX,
- ? ? ? ? ? ? ? [22] = DMACH_SLIMBUS0_TX,
- ? ? ? ? ? ? ? [23] = DMACH_SLIMBUS2_RX,
- ? ? ? ? ? ? ? [24] = DMACH_SLIMBUS2_TX,

arch/arm/mach-exynos4/dma.c

Quoted 10 lines
arch/arm/mach-exynos4/dma.c +2 -8
- ? ? ? ? ? ? ? [25] = DMACH_SLIMBUS4_RX,
- ? ? ? ? ? ? ? [26] = DMACH_SLIMBUS4_TX,
- ? ? ? ? ? ? ? [27] = DMACH_AC97_MICIN,
- ? ? ? ? ? ? ? [28] = DMACH_AC97_PCMIN,
- ? ? ? ? ? ? ? [29] = DMACH_AC97_PCMOUT,
- ? ? ? ? ? ? ? [30] = DMACH_MAX,
- ? ? ? ? ? ? ? [31] = DMACH_MAX,
- ? ? ? },
+struct dma_pl330_platdata exynos4_pdma0_pdata = {
+ ? ? ? .nr_valid_peri = 32,

Perhaps, this is why you had to add the NULL peri check. Please use ARRAY_SIZE here.
Same for every other such occurance.

author
#54 lore raw

PATCH v4 7/14 ARM: EXYNOS4: Use generic DMA PL330 driver

Jassi Brar Wrote:

Quoted 46 lines

Sent: Monday, July 25, 2011 9:00 PM
To: Boojin Kim
Cc: linux-arm-kernel at lists.infradead.org; linux-samsung- soc at vger.kernel.org; Vinod Koul; Dan Williams; Kukjin Kim; Grant Likely; Mark Brown
Subject: Re: [PATCH V4 07/14] ARM: EXYNOS4: Use generic DMA PL330 driver

arch/arm/mach-

Quoted 1 line · Boojin Kim
arch/arm/mach- renamed from arch/arm/mach-exynos4/dma.c +0 -0

exynos4/dma.c

Quoted 33 lines

index 564bb53..e1c00cf 100644

arch/arm/mach-exynos4/dma.c +4 -12
@@ -21,151 +21,250 @@
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
 
-#include <linux/platform_device.h>
 #include <linux/dma-mapping.h>
+#include <linux/amba/bus.h>
+#include <linux/amba/pl330.h>
 
+#include <asm/irq.h>
 #include <plat/devs.h>
 #include <plat/irqs.h>
 
 #include <mach/map.h>
 #include <mach/irqs.h>
-
-#include <plat/s3c-pl330-pdata.h>
+#include <mach/dma.h>
 
 static u64 dma_dmamask = DMA_BIT_MASK(32);
 
-static struct resource exynos4_pdma0_resource[] = {
-       [0] = {
-               .start  = EXYNOS4_PA_PDMA0,
-               .end    = EXYNOS4_PA_PDMA0 + SZ_4K,
-               .flags  = IORESOURCE_MEM,
-       },
-       [1] = {
-               .start  = IRQ_PDMA0,
-               .end    = IRQ_PDMA0,
Quoted 8 lines

arch/arm/mach-exynos4/dma.c line 38

Quoted 2 lines
arch/arm/mach-exynos4/dma.c +1 -1
-               .flags  = IORESOURCE_IRQ,
+struct dma_pl330_peri pdma0_peri[32] = {

Please remove 32 from the list (it seems you don't always pass 32 elements)
Also for completeness, please explicitly write element indices below because
it's not some array of randomly placed elements.
Same for every other such occurance.

I will address your comment.

Quoted 134 lines
Quoted 134 lines
arch/arm/mach-exynos4/dma.c +96 -32
+       {
+               .peri_id = (u8)DMACH_PCM0_RX,
+               .rqtype = DEVTOMEM,
+       }, {
+               .peri_id = (u8)DMACH_PCM0_TX,
+               .rqtype = MEMTODEV,
+       }, {
+               .peri_id = (u8)DMACH_PCM2_RX,
+               .rqtype = DEVTOMEM,
+       }, {
+               .peri_id = (u8)DMACH_PCM2_TX,
+               .rqtype = MEMTODEV,
+               .burst_sz = 4,
+       }, {
+               .peri_id = (u8)DMACH_MSM_REQ0,
+       }, {
+               .peri_id = (u8)DMACH_MSM_REQ2,
+       }, {
+               .peri_id = (u8)DMACH_SPI0_RX,
+               .rqtype = DEVTOMEM,
+               .burst_sz = 1,
+       }, {
+               .peri_id = (u8)DMACH_SPI0_TX,
+               .rqtype = MEMTODEV,
+               .burst_sz = 1,
+       }, {
+               .peri_id = (u8)DMACH_SPI2_RX,
+               .rqtype = DEVTOMEM,
+               .burst_sz = 1,
+       }, {
+               .peri_id = (u8)DMACH_SPI2_TX,
+               .rqtype = MEMTODEV,
+               .burst_sz = 1,
+       }, {
+               .peri_id = (u8)DMACH_I2S0S_TX,
+               .rqtype = MEMTODEV,
+       }, {
+               .peri_id = (u8)DMACH_I2S0_RX,
+               .rqtype = DEVTOMEM,
+       }, {
+               .peri_id = (u8)DMACH_I2S0_TX,
+               .rqtype = MEMTODEV,
+       }, {
+               .peri_id = (u8)DMACH_UART0_RX,
+               .rqtype = DEVTOMEM,
+               .burst_sz = 4,
+       }, {
+               .peri_id = (u8)DMACH_UART0_TX,
+               .rqtype = MEMTODEV,
+               .burst_sz = 4,
+       }, {
+               .peri_id = (u8)DMACH_UART2_RX,
+               .rqtype = DEVTOMEM,
+               .burst_sz = 4,
+       }, {
+               .peri_id = (u8)DMACH_UART2_TX,
+               .rqtype = MEMTODEV,
+               .burst_sz = 4,
+       }, {
+               .peri_id = (u8)DMACH_UART4_RX,
+               .rqtype = DEVTOMEM,
+               .burst_sz = 4,
+       }, {
+               .peri_id = (u8)DMACH_UART4_TX,
+               .rqtype = MEMTODEV,
+               .burst_sz = 4,
+       }, {
+               .peri_id = (u8)DMACH_SLIMBUS0_RX,
+               .rqtype = DEVTOMEM,
+       }, {
+               .peri_id = (u8)DMACH_SLIMBUS0_TX,
+               .rqtype = MEMTODEV,
+       }, {
+               .peri_id = (u8)DMACH_SLIMBUS2_RX,
+               .rqtype = DEVTOMEM,
+       }, {
+               .peri_id = (u8)DMACH_SLIMBUS2_TX,
+               .rqtype = MEMTODEV,
+       }, {
+               .peri_id = (u8)DMACH_SLIMBUS4_RX,
+               .rqtype = DEVTOMEM,
+       }, {
+               .peri_id = (u8)DMACH_SLIMBUS4_TX,
+               .rqtype = MEMTODEV,
+       }, {
+               .peri_id = (u8)DMACH_AC97_MICIN,
+               .rqtype = DEVTOMEM,
+               .burst_sz = 4,
+       }, {
+               .peri_id = (u8)DMACH_AC97_PCMIN,
+               .rqtype = DEVTOMEM,
+               .burst_sz = 4,
+       }, {
+               .peri_id = (u8)DMACH_AC97_PCMOUT,
+               .rqtype = MEMTODEV,
+               .burst_sz = 4,
       },
 };
 
 
 
-static struct s3c_pl330_platdata exynos4_pdma0_pdata = {
-       .peri = {
-               [0] = DMACH_PCM0_RX,
-               [1] = DMACH_PCM0_TX,
-               [2] = DMACH_PCM2_RX,
-               [3] = DMACH_PCM2_TX,
-               [4] = DMACH_MSM_REQ0,
-               [5] = DMACH_MSM_REQ2,
-               [6] = DMACH_SPI0_RX,
-               [7] = DMACH_SPI0_TX,
-               [8] = DMACH_SPI2_RX,
-               [9] = DMACH_SPI2_TX,
-               [10] = DMACH_I2S0S_TX,
-               [11] = DMACH_I2S0_RX,
-               [12] = DMACH_I2S0_TX,
-               [13] = DMACH_I2S2_RX,
-               [14] = DMACH_I2S2_TX,
-               [15] = DMACH_UART0_RX,
-               [16] = DMACH_UART0_TX,
-               [17] = DMACH_UART2_RX,
-               [18] = DMACH_UART2_TX,
-               [19] = DMACH_UART4_RX,
-               [20] = DMACH_UART4_TX,
-               [21] = DMACH_SLIMBUS0_RX,
-               [22] = DMACH_SLIMBUS0_TX,
-               [23] = DMACH_SLIMBUS2_RX,
-               [24] = DMACH_SLIMBUS2_TX,
-               [25] = DMACH_SLIMBUS4_RX,
-               [26] = DMACH_SLIMBUS4_TX,
-               [27] = DMACH_AC97_MICIN,
-               [28] = DMACH_AC97_PCMIN,
-               [29] = DMACH_AC97_PCMOUT,
Quoted 8 lines

arch/arm/mach-exynos4/dma.c line 139

Quoted 5 lines
arch/arm/mach-exynos4/dma.c +2 -3
-               [30] = DMACH_MAX,
-               [31] = DMACH_MAX,
-       },
+struct dma_pl330_platdata exynos4_pdma0_pdata = {
+       .nr_valid_peri = 32,

Perhaps, this is why you had to add the NULL peri check. Please use ARRAY_SIZE here.
Same for every other such occurance.

I will address your comment.

author
#55 lore raw

PATCH v4 8/14 ARM: S5PV210: Use generic DMA PL330 driver

In reply to Boojin Kim

This patch makes Samsung S5PV210 to use DMA PL330 driver on DMADEVICE. The S5PV210 uses DMA generic APIs instead of SAMSUNG specific S3C-PL330 APIs.

---
 arch/arm/mach-s5pv210/Kconfig |    2 +-
 arch/arm/mach-s5pv210/clock.c |   16 +-
 arch/arm/mach-s5pv210/dma.c   |  346 +++++++++++++++++++++++++++--------------
 3 files changed, 241 insertions(+), 123 deletions(-)
arch/arm/mach-s5pv210/Kconfig +1 -1
index 37b5a97..fb11e38 100644
@@ -11,7 +11,7 @@ if ARCH_S5PV210
 
 config CPU_S5PV210
 	bool
-	select S3C_PL330_DMA
+	select DMADEV_PL330
 	select S5P_EXT_INT
 	select S5P_HRT
 	select S5PV210_PM if PM
arch/arm/mach-s5pv210/clock.c +8 -8
index 2d59949..dbe7285 100644
@@ -221,6 +221,11 @@ static struct clk clk_pcmcdclk2 = {
 	.id		= -1,
 };
 
+static struct clk dummy_apb_pclk = {
+	.name		= "apb_pclk",
+	.id		= -1,
+};
+
 static struct clk *clkset_vpllsrc_list[] = {
 	[0] = &clk_fin_vpll,
 	[1] = &clk_sclk_hdmi27m,
@@ -311,18 +316,12 @@ static struct clk_ops clk_fout_apll_ops = {
 
 static struct clk init_clocks_off[] = {
 	{
-		.name		= "pdma",
-		.id		= 0,
+		.name		= "dma",
+		.id		= -1,
 		.parent		= &clk_hclk_psys.clk,
 		.enable		= s5pv210_clk_ip0_ctrl,
 		.ctrlbit	= (1 << 3),
 	}, {
-		.name		= "pdma",
-		.id		= 1,
-		.parent		= &clk_hclk_psys.clk,
-		.enable		= s5pv210_clk_ip0_ctrl,
-		.ctrlbit	= (1 << 4),
-	}, {
 		.name		= "rot",
 		.id		= -1,
 		.parent		= &clk_hclk_dsys.clk,
@@ -1239,5 +1238,6 @@ void __init s5pv210_register_clocks(void)
 	s3c_register_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off));
 	s3c_disable_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off));
 
+	s3c24xx_register_clock(&dummy_apb_pclk);
 	s3c_pwmclk_init();
 }
arch/arm/mach-s5pv210/dma.c +232 -114

387 lines not on this page · raw message

Signature · 1 line
1.7.1
author
#56 lore raw

PATCH v4 9/14 ARM: S5PC100: Use generic DMA PL330 driver

In reply to Boojin Kim

This patch makes Samsung S5PC100 to use DMA PL330 driver on DMADEVICE. The S5PC100 uses DMA generic APIs instead of SAMSUNG specific S3C-PL330 APIs.

---
 arch/arm/mach-s5pc100/Kconfig |    2 +-
 arch/arm/mach-s5pc100/clock.c |   23 +--
 arch/arm/mach-s5pc100/dma.c   |  357 ++++++++++++++++++++++++++++-------------
 3 files changed, 253 insertions(+), 129 deletions(-)
arch/arm/mach-s5pc100/Kconfig +1 -1
index 608722f..379fadc 100644
@@ -10,7 +10,7 @@ if ARCH_S5PC100
 config CPU_S5PC100
 	bool
 	select S5P_EXT_INT
-	select S3C_PL330_DMA
+	select DMADEV_PL330
 	help
 	  Enable S5PC100 CPU support
 
arch/arm/mach-s5pc100/clock.c +9 -14
index 0305e9b..891acfe 100644
@@ -34,6 +34,11 @@ static struct clk s5p_clk_otgphy = {
 	.id		= -1,
 };
 
+static struct clk dummy_apb_pclk = {
+	.name		= "apb_pclk",
+	.id		= -1,
+};
+
 static struct clk *clk_src_mout_href_list[] = {
 	[0] = &s5p_clk_27m,
 	[1] = &clk_fin_hpll,
@@ -416,12 +421,6 @@ static struct clk init_clocks_off[] = {
 		.enable		= s5pc100_d0_0_ctrl,
 		.ctrlbit	= (1 << 4),
 	}, {
-		.name		= "mdma",
-		.id		= -1,
-		.parent		= &clk_div_d0_bus.clk,
-		.enable		= s5pc100_d0_0_ctrl,
-		.ctrlbit	= (1 << 3),
-	}, {
 		.name		= "cfcon",
 		.id		= -1,
 		.parent		= &clk_div_d0_bus.clk,
@@ -488,14 +487,8 @@ static struct clk init_clocks_off[] = {
 		.enable		= s5pc100_d1_0_ctrl,
 		.ctrlbit	= (1 << 2),
 	}, {
-		.name		= "pdma",
-		.id		= 1,
-		.parent		= &clk_div_d1_bus.clk,
-		.enable		= s5pc100_d1_0_ctrl,
-		.ctrlbit	= (1 << 1),
-	}, {
-		.name		= "pdma",
-		.id		= 0,
+		.name		= "dma",
+		.id		= -1,
 		.parent		= &clk_div_d1_bus.clk,
 		.enable		= s5pc100_d1_0_ctrl,
 		.ctrlbit	= (1 << 0),
@@ -1394,5 +1387,7 @@ void __init s5pc100_register_clocks(void)
 	s3c_register_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off));
 	s3c_disable_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off));
 
+	s3c24xx_register_clock(&dummy_apb_pclk);
+
 	s3c_pwmclk_init();
 }
arch/arm/mach-s5pc100/dma.c +243 -114

397 lines not on this page · raw message

Signature · 1 line
1.7.1
author
#57 lore raw

PATCH v4 10/14 ARM: S5P64X0: Use generic DMA PL330 driver

In reply to Boojin Kim

This patch makes Samsung S5P64X0 to use DMA PL330 driver on DMADEVICE. The S5P64X0 uses DMA generic APIs instead of SAMSUNG specific S3C-PL330 APIs.

---
 arch/arm/mach-s5p64x0/Kconfig         |    4 +-
 arch/arm/mach-s5p64x0/clock-s5p6440.c |    9 +-
 arch/arm/mach-s5p64x0/clock-s5p6450.c |    9 +-
 arch/arm/mach-s5p64x0/dma.c           |  317 +++++++++++++++++++++++----------
 4 files changed, 242 insertions(+), 97 deletions(-)
arch/arm/mach-s5p64x0/Kconfig +2 -2
index 017af4c..7108e7e 100644
@@ -9,14 +9,14 @@ if ARCH_S5P64X0
 
 config CPU_S5P6440
 	bool
-	select S3C_PL330_DMA
+	select DMADEV_PL330
 	select S5P_HRT
 	help
 	  Enable S5P6440 CPU support
 
 config CPU_S5P6450
 	bool
-	select S3C_PL330_DMA
+	select DMADEV_PL330
 	select S5P_HRT
 	help
 	  Enable S5P6450 CPU support
arch/arm/mach-s5p64x0/clock-s5p6440.c +8 -1
index 9f12c2e..5f7ad9e 100644
@@ -153,7 +153,7 @@ static struct clk init_clocks_off[] = {
 		.enable		= s5p64x0_hclk0_ctrl,
 		.ctrlbit	= (1 << 8),
 	}, {
-		.name		= "pdma",
+		.name		= "dma",
 		.id		= -1,
 		.parent		= &clk_hclk_low.clk,
 		.enable		= s5p64x0_hclk0_ctrl,
@@ -533,6 +533,11 @@ static struct clksrc_clk *sysclks[] = {
 	&clk_pclk_low,
 };
 
+static struct clk dummy_apb_pclk = {
+	.name		= "apb_pclk",
+	.id		= -1,
+};
+
 void __init_or_cpufreq s5p6440_setup_clocks(void)
 {
 	struct clk *xtal_clk;
@@ -615,5 +620,7 @@ void __init s5p6440_register_clocks(void)
 	s3c_register_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off));
 	s3c_disable_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off));
 
+	s3c24xx_register_clock(&dummy_apb_pclk);
+
 	s3c_pwmclk_init();
 }
arch/arm/mach-s5p64x0/clock-s5p6450.c +8 -1
index 4eec457..62d4707 100644
@@ -189,7 +189,7 @@ static struct clk init_clocks_off[] = {
 		.enable		= s5p64x0_hclk0_ctrl,
 		.ctrlbit	= (1 << 3),
 	}, {
-		.name		= "pdma",
+		.name		= "dma",
 		.id		= -1,
 		.parent		= &clk_hclk_low.clk,
 		.enable		= s5p64x0_hclk0_ctrl,
@@ -583,6 +583,11 @@ static struct clksrc_clk *sysclks[] = {
 	&clk_sclk_audio0,
 };
 
+static struct clk dummy_apb_pclk = {
+	.name		= "apb_pclk",
+	.id		= -1,
+};
+
 void __init_or_cpufreq s5p6450_setup_clocks(void)
 {
 	struct clk *xtal_clk;
@@ -662,5 +667,7 @@ void __init s5p6450_register_clocks(void)
 	s3c_register_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off));
 	s3c_disable_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off));
 
+	s3c24xx_register_clock(&dummy_apb_pclk);
+
 	s3c_pwmclk_init();
 }
arch/arm/mach-s5p64x0/dma.c +224 -93

354 lines not on this page · raw message

Signature · 1 line
1.7.1
author
#58 lore raw

PATCH v4 11/14 ARM: SAMSUNG: Remove S3C-PL330-DMA driver

In reply to Boojin Kim

Since DMA generic APIs can be used for Samsung DMA now so that the s3c-pl330 which includes Samsung specific DMA APIs can be removed.

---
 arch/arm/plat-samsung/Kconfig                      |    6 -
 arch/arm/plat-samsung/Makefile                     |    2 -
 arch/arm/plat-samsung/include/plat/dma-pl330.h     |    9 +-
 .../plat-samsung/include/plat/s3c-pl330-pdata.h    |   32 -
 arch/arm/plat-samsung/s3c-pl330.c                  | 1244 --------------------
 5 files changed, 6 insertions(+), 1287 deletions(-)
 delete mode 100644 arch/arm/plat-samsung/include/plat/s3c-pl330-pdata.h
 delete mode 100644 arch/arm/plat-samsung/s3c-pl330.c
arch/arm/plat-samsung/Kconfig +0 -6
index cb170a6..db789d7 100644
@@ -294,12 +294,6 @@ config S3C_DMA
 	help
 	  Internal configuration for S3C DMA core
 
-config S3C_PL330_DMA
-	bool
-	select PL330
-	help
-	  S3C DMA API Driver for PL330 DMAC.
-
 config DMADEV_PL330
 	bool
 	select DMADEVICES
arch/arm/plat-samsung/Makefile +0 -2
index 9ecf2aa..ea98621 100644
@@ -66,8 +66,6 @@ obj-$(CONFIG_S3C_DMA)		+= dma.o s3c-dma-ops.o
 
 obj-$(CONFIG_DMADEV_PL330)	+= dma-ops.o
 
-obj-$(CONFIG_S3C_PL330_DMA)	+= s3c-pl330.o s3c-dma-ops.o
-
 # PM support
 
 obj-$(CONFIG_PM)		+= pm.o
arch/arm/plat-samsung/include/plat/dma-pl330.h +6 -3
index 687489e..ded416c 100644
@@ -11,8 +11,6 @@
 #ifndef __DMA_PL330_H_
 #define __DMA_PL330_H_ __FILE__
 
-#define S3C2410_DMAF_AUTOSTART	(1 << 0)
-#define S3C2410_DMAF_CIRCULAR	(1 << 1)
 /*
  * PL330 can assign any channel to communicate with
  * any of the peripherals attched to the DMAC.
@@ -95,6 +93,10 @@ enum dma_ch {
 	DMACH_MAX,
 };
 
+struct s3c2410_dma_client {
+	char	*name;
+};
+
 static inline bool s3c_dma_has_circular(void)
 {
 	return true;
@@ -104,6 +106,7 @@ static inline bool samsung_dma_is_dmadev(void)
 {
 	return true;
 }
-#include <plat/dma.h>
+
+#include <plat/dma-ops.h>
 
 #endif	/* __DMA_PL330_H_ */
arch/arm/plat-samsung/include/plat/s3c-pl330-pdata.h deleted +0 -32
deleted file mode 100644
index 64fdf66..0000000
@@ -1,32 +0,0 @@
-/* linux/arch/arm/plat-samsung/include/plat/s3c-pl330-pdata.h
- *
- * Copyright (C) 2010 Samsung Electronics Co. Ltd.
- *	Jaswinder Singh <[email protected]>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#ifndef __S3C_PL330_PDATA_H
-#define __S3C_PL330_PDATA_H
-
-#include <plat/dma-pl330.h>
-
-/*
- * Every PL330 DMAC has max 32 peripheral interfaces,
- * of which some may be not be really used in your
- * DMAC's configuration.
- * Populate this array of 32 peri i/fs with relevant
- * channel IDs for used peri i/f and DMACH_MAX for
- * those unused.
- *
- * The platforms just need to provide this info
- * to the S3C DMA API driver for PL330.
- */
-struct s3c_pl330_platdata {
-	enum dma_ch peri[32];
-};
-
-#endif /* __S3C_PL330_PDATA_H */
arch/arm/plat-samsung/s3c-pl330.c deleted +0 -1244

1,244 lines not on this page · raw message

Signature · 1 line
1.7.1
author
#59 lore raw

PATCH v4 12/14 spi/s3c64xx: Add support DMA engine API

In reply to Boojin Kim

This patch adds to support DMA generic API to transfer raw SPI data. Basiclly the spi driver uses DMA generic API if architecture supports it. Otherwise, uses Samsung specific S3C-PL330 APIs.

---
 drivers/spi/spi_s3c64xx.c |  141 ++++++++++++++++++++++-----------------------
 1 files changed, 69 insertions(+), 72 deletions(-)
drivers/spi/spi_s3c64xx.c +69 -72
index 8945e20..a4cf76a 100644
@@ -172,6 +172,9 @@ struct s3c64xx_spi_driver_data {
 	unsigned                        state;
 	unsigned                        cur_mode, cur_bpw;
 	unsigned                        cur_speed;
+	unsigned			rx_ch;
+	unsigned			tx_ch;
+	struct samsung_dma_ops		*ops;
 };
 
 static struct s3c2410_dma_client s3c64xx_spi_dma_client = {
@@ -227,6 +230,38 @@ static void flush_fifo(struct s3c64xx_spi_driver_data *sdd)
 	writel(val, regs + S3C64XX_SPI_CH_CFG);
 }
 
+static void s3c64xx_spi_dma_rxcb(void *data)
+{
+	struct s3c64xx_spi_driver_data *sdd
+		= (struct s3c64xx_spi_driver_data *)data;
+	unsigned long flags;
+
+	spin_lock_irqsave(&sdd->lock, flags);
+
+	sdd->state &= ~RXBUSY;
+	/* If the other done */
+	if (!(sdd->state & TXBUSY))
+		complete(&sdd->xfer_completion);
+
+	spin_unlock_irqrestore(&sdd->lock, flags);
+}
+
+static void s3c64xx_spi_dma_txcb(void *data)
+{
+	struct s3c64xx_spi_driver_data *sdd
+		= (struct s3c64xx_spi_driver_data *)data;
+	unsigned long flags;
+
+	spin_lock_irqsave(&sdd->lock, flags);
+
+	sdd->state &= ~TXBUSY;
+	/* If the other done */
+	if (!(sdd->state & RXBUSY))
+		complete(&sdd->xfer_completion);
+
+	spin_unlock_irqrestore(&sdd->lock, flags);
+}
+
 static void enable_datapath(struct s3c64xx_spi_driver_data *sdd,
 				struct spi_device *spi,
 				struct spi_transfer *xfer, int dma_mode)
@@ -234,6 +269,7 @@ static void enable_datapath(struct s3c64xx_spi_driver_data *sdd,
 	struct s3c64xx_spi_info *sci = sdd->cntrlr_info;
 	void __iomem *regs = sdd->regs;
 	u32 modecfg, chcfg;
+	struct samsung_dma_prep_info info;
 
 	modecfg = readl(regs + S3C64XX_SPI_MODE_CFG);
 	modecfg &= ~(S3C64XX_SPI_MODE_TXDMA_ON | S3C64XX_SPI_MODE_RXDMA_ON);
@@ -259,10 +295,14 @@ static void enable_datapath(struct s3c64xx_spi_driver_data *sdd,
 		chcfg |= S3C64XX_SPI_CH_TXCH_ON;
 		if (dma_mode) {
 			modecfg |= S3C64XX_SPI_MODE_TXDMA_ON;
-			s3c2410_dma_config(sdd->tx_dmach, sdd->cur_bpw / 8);
-			s3c2410_dma_enqueue(sdd->tx_dmach, (void *)sdd,
-						xfer->tx_dma, xfer->len);
-			s3c2410_dma_ctrl(sdd->tx_dmach, S3C2410_DMAOP_START);
+			info.cap = DMA_SLAVE;
+			info.direction = DMA_TO_DEVICE;
+			info.buf = xfer->tx_dma;
+			info.len = xfer->len;
+			info.fp = s3c64xx_spi_dma_txcb;
+			info.fp_param = sdd;
+			sdd->ops->prepare(sdd->tx_ch, &info);
+			sdd->ops->trigger(sdd->tx_ch);
 		} else {
 			switch (sdd->cur_bpw) {
 			case 32:
@@ -294,10 +334,14 @@ static void enable_datapath(struct s3c64xx_spi_driver_data *sdd,
 			writel(((xfer->len * 8 / sdd->cur_bpw) & 0xffff)
 					| S3C64XX_SPI_PACKET_CNT_EN,
 					regs + S3C64XX_SPI_PACKET_CNT);
-			s3c2410_dma_config(sdd->rx_dmach, sdd->cur_bpw / 8);
-			s3c2410_dma_enqueue(sdd->rx_dmach, (void *)sdd,
-						xfer->rx_dma, xfer->len);
-			s3c2410_dma_ctrl(sdd->rx_dmach, S3C2410_DMAOP_START);
+			info.cap = DMA_SLAVE;
+			info.direction = DMA_FROM_DEVICE;
+			info.buf = xfer->rx_dma;
+			info.len = xfer->len;
+			info.fp = s3c64xx_spi_dma_rxcb;
+			info.fp_param = sdd;
+			sdd->ops->prepare(sdd->rx_ch, &info);
+			sdd->ops->trigger(sdd->rx_ch);
 		}
 	}
 
@@ -483,46 +527,6 @@ static void s3c64xx_spi_config(struct s3c64xx_spi_driver_data *sdd)
 	}
 }
 
-static void s3c64xx_spi_dma_rxcb(struct s3c2410_dma_chan *chan, void *buf_id,
-				 int size, enum s3c2410_dma_buffresult res)
-{
-	struct s3c64xx_spi_driver_data *sdd = buf_id;
-	unsigned long flags;
-
-	spin_lock_irqsave(&sdd->lock, flags);
-
-	if (res == S3C2410_RES_OK)
-		sdd->state &= ~RXBUSY;
-	else
-		dev_err(&sdd->pdev->dev, "DmaAbrtRx-%d\n", size);
-
-	/* If the other done */
-	if (!(sdd->state & TXBUSY))
-		complete(&sdd->xfer_completion);
-
-	spin_unlock_irqrestore(&sdd->lock, flags);
-}
-
-static void s3c64xx_spi_dma_txcb(struct s3c2410_dma_chan *chan, void *buf_id,
-				 int size, enum s3c2410_dma_buffresult res)
-{
-	struct s3c64xx_spi_driver_data *sdd = buf_id;
-	unsigned long flags;
-
-	spin_lock_irqsave(&sdd->lock, flags);
-
-	if (res == S3C2410_RES_OK)
-		sdd->state &= ~TXBUSY;
-	else
-		dev_err(&sdd->pdev->dev, "DmaAbrtTx-%d \n", size);
-
-	/* If the other done */
-	if (!(sdd->state & RXBUSY))
-		complete(&sdd->xfer_completion);
-
-	spin_unlock_irqrestore(&sdd->lock, flags);
-}
-
 #define XFER_DMAADDR_INVALID DMA_BIT_MASK(32)
 
 static int s3c64xx_spi_map_mssg(struct s3c64xx_spi_driver_data *sdd,
@@ -697,12 +701,10 @@ static void handle_msg(struct s3c64xx_spi_driver_data *sdd,
 			if (use_dma) {
 				if (xfer->tx_buf != NULL
 						&& (sdd->state & TXBUSY))
-					s3c2410_dma_ctrl(sdd->tx_dmach,
-							S3C2410_DMAOP_FLUSH);
+					sdd->ops->stop(sdd->tx_ch);
 				if (xfer->rx_buf != NULL
 						&& (sdd->state & RXBUSY))
-					s3c2410_dma_ctrl(sdd->rx_dmach,
-							S3C2410_DMAOP_FLUSH);
+					sdd->ops->stop(sdd->rx_ch);
 			}
 
 			goto out;
@@ -742,24 +744,19 @@ out:
 
 static int acquire_dma(struct s3c64xx_spi_driver_data *sdd)
 {
-	if (s3c2410_dma_request(sdd->rx_dmach,
-					&s3c64xx_spi_dma_client, NULL) < 0) {
-		dev_err(&sdd->pdev->dev, "cannot get RxDMA\n");
-		return 0;
-	}
-	s3c2410_dma_set_buffdone_fn(sdd->rx_dmach, s3c64xx_spi_dma_rxcb);
-	s3c2410_dma_devconfig(sdd->rx_dmach, S3C2410_DMASRC_HW,
-					sdd->sfr_start + S3C64XX_SPI_RX_DATA);
-
-	if (s3c2410_dma_request(sdd->tx_dmach,
-					&s3c64xx_spi_dma_client, NULL) < 0) {
-		dev_err(&sdd->pdev->dev, "cannot get TxDMA\n");
-		s3c2410_dma_free(sdd->rx_dmach, &s3c64xx_spi_dma_client);
-		return 0;
-	}
-	s3c2410_dma_set_buffdone_fn(sdd->tx_dmach, s3c64xx_spi_dma_txcb);
-	s3c2410_dma_devconfig(sdd->tx_dmach, S3C2410_DMASRC_MEM,
-					sdd->sfr_start + S3C64XX_SPI_TX_DATA);
+
+	struct samsung_dma_info info;
+	sdd->ops = samsung_dma_get_ops();
+
+	info.cap = DMA_SLAVE;
+	info.client = &s3c64xx_spi_dma_client;
+	info.direction = DMA_FROM_DEVICE;
+	info.fifo = sdd->sfr_start + S3C64XX_SPI_RX_DATA;
+	info.width = sdd->cur_bpw / 8;
+	sdd->rx_ch = sdd->ops->request(sdd->rx_dmach, &info);
+	info.direction = DMA_TO_DEVICE;
+	info.fifo = sdd->sfr_start + S3C64XX_SPI_TX_DATA;
+	sdd->tx_ch = sdd->ops->request(sdd->tx_dmach, &info);
 
 	return 1;
 }
@@ -800,8 +797,8 @@ static void s3c64xx_spi_work(struct work_struct *work)
 	spin_unlock_irqrestore(&sdd->lock, flags);
 
 	/* Free DMA channels */
-	s3c2410_dma_free(sdd->tx_dmach, &s3c64xx_spi_dma_client);
-	s3c2410_dma_free(sdd->rx_dmach, &s3c64xx_spi_dma_client);
+	sdd->ops->release(sdd->rx_ch, &s3c64xx_spi_dma_client);
+	sdd->ops->release(sdd->tx_ch, &s3c64xx_spi_dma_client);
 }
 
 static int s3c64xx_spi_transfer(struct spi_device *spi,
Signature · 1 line
1.7.1
#60 lore raw

PATCH v4 12/14 spi/s3c64xx: Add support DMA engine API

drivers/spi/spi_s3c64xx.c static void flush_fifo(struct s3c64xx_spi_driver_data *sdd) · line 236

Quoted 4 lines · Boojin Kim
drivers/spi/spi_s3c64xx.c +4 -0
+static void s3c64xx_spi_dma_rxcb(void *data)
+{
+	struct s3c64xx_spi_driver_data *sdd
+		= (struct s3c64xx_spi_driver_data *)data;

You never need explicit casts from void * or to void *. Please remove these.

author
#61 lore raw

PATCH v4 12/14 spi/s3c64xx: Add support DMA engine API

Russell King - ARM Linux Wrote:

Quoted 3 lines

Sent: Monday, July 25, 2011 6:40 PM
To: Boojin Kim
Cc: linux-arm-kernel at lists.infradead.org;

linux-samsung-soc at vger.kernel.org;

Quoted 11 lines

Kukjin Kim; Vinod Koul; Jassi Brar; Grant Likely; Mark Brown; Dan Williams
Subject: Re: [PATCH V4 12/14] spi/s3c64xx: Add support DMA engine API

drivers/spi/spi_s3c64xx.c static void flush_fifo(struct s3c64xx_spi_driver_data *sdd) · line 236

Quoted 4 lines · Boojin Kim
drivers/spi/spi_s3c64xx.c +4 -0
+static void s3c64xx_spi_dma_rxcb(void *data)
+{
+	struct s3c64xx_spi_driver_data *sdd
+		= (struct s3c64xx_spi_driver_data *)data;

You never need explicit casts from void * or to void *. Please remove these.

I will address your comment.

#62 lore raw

PATCH v4 12/14 spi/s3c64xx: Add support DMA engine API

In reply to Boojin Kim
Quoted 51 lines · Boojin Kim

This patch adds to support DMA generic API to transfer raw SPI data. Basiclly the spi driver uses DMA generic API if architecture supports it. Otherwise, uses Samsung specific S3C-PL330 APIs.

---
 drivers/spi/spi_s3c64xx.c |  141 ++++++++++++++++++++++-----------------------
 1 files changed, 69 insertions(+), 72 deletions(-)
drivers/spi/spi_s3c64xx.c +24 -0
index 8945e20..a4cf76a 100644
@@ -172,6 +172,9 @@ struct s3c64xx_spi_driver_data {
 	unsigned                        state;
 	unsigned                        cur_mode, cur_bpw;
 	unsigned                        cur_speed;
+	unsigned			rx_ch;
+	unsigned			tx_ch;
+	struct samsung_dma_ops		*ops;
 };
 
 static struct s3c2410_dma_client s3c64xx_spi_dma_client = {
@@ -227,6 +230,38 @@ static void flush_fifo(struct s3c64xx_spi_driver_data *sdd)
 	writel(val, regs + S3C64XX_SPI_CH_CFG);
 }
 
+static void s3c64xx_spi_dma_rxcb(void *data)
+{
+	struct s3c64xx_spi_driver_data *sdd
+		= (struct s3c64xx_spi_driver_data *)data;
+	unsigned long flags;
+
+	spin_lock_irqsave(&sdd->lock, flags);
+
+	sdd->state &= ~RXBUSY;
+	/* If the other done */
+	if (!(sdd->state & TXBUSY))
+		complete(&sdd->xfer_completion);
+
+	spin_unlock_irqrestore(&sdd->lock, flags);
+}
+
+static void s3c64xx_spi_dma_txcb(void *data)
+{
+	struct s3c64xx_spi_driver_data *sdd
+		= (struct s3c64xx_spi_driver_data *)data;
+	unsigned long flags;

drivers/spi/spi_s3c64xx.c static void flush_fifo(struct s3c64xx_spi_driver_data *sdd) · line 263

Quoted 10 lines
drivers/spi/spi_s3c64xx.c +10 -0
+
+	spin_lock_irqsave(&sdd->lock, flags);
+
+	sdd->state &= ~TXBUSY;
+	/* If the other done */
+	if (!(sdd->state & RXBUSY))
+		complete(&sdd->xfer_completion);
+
+	spin_unlock_irqrestore(&sdd->lock, flags);
+}

I don't see much diff in these two functions and you should be able to use a generic one which takes care of both TX and RX, does your callback data know if the channel is for TX or RX? If not then a helper to do above should take care well and making code simpler

Quoted 161 lines
drivers/spi/spi_s3c64xx.c +35 -72
+
 static void enable_datapath(struct s3c64xx_spi_driver_data *sdd,
 				struct spi_device *spi,
 				struct spi_transfer *xfer, int dma_mode)
@@ -234,6 +269,7 @@ static void enable_datapath(struct s3c64xx_spi_driver_data *sdd,
 	struct s3c64xx_spi_info *sci = sdd->cntrlr_info;
 	void __iomem *regs = sdd->regs;
 	u32 modecfg, chcfg;
+	struct samsung_dma_prep_info info;
 
 	modecfg = readl(regs + S3C64XX_SPI_MODE_CFG);
 	modecfg &= ~(S3C64XX_SPI_MODE_TXDMA_ON | S3C64XX_SPI_MODE_RXDMA_ON);
@@ -259,10 +295,14 @@ static void enable_datapath(struct s3c64xx_spi_driver_data *sdd,
 		chcfg |= S3C64XX_SPI_CH_TXCH_ON;
 		if (dma_mode) {
 			modecfg |= S3C64XX_SPI_MODE_TXDMA_ON;
-			s3c2410_dma_config(sdd->tx_dmach, sdd->cur_bpw / 8);
-			s3c2410_dma_enqueue(sdd->tx_dmach, (void *)sdd,
-						xfer->tx_dma, xfer->len);
-			s3c2410_dma_ctrl(sdd->tx_dmach, S3C2410_DMAOP_START);
+			info.cap = DMA_SLAVE;
+			info.direction = DMA_TO_DEVICE;
+			info.buf = xfer->tx_dma;
+			info.len = xfer->len;
+			info.fp = s3c64xx_spi_dma_txcb;
+			info.fp_param = sdd;
+			sdd->ops->prepare(sdd->tx_ch, &info);
+			sdd->ops->trigger(sdd->tx_ch);
 		} else {
 			switch (sdd->cur_bpw) {
 			case 32:
@@ -294,10 +334,14 @@ static void enable_datapath(struct s3c64xx_spi_driver_data *sdd,
 			writel(((xfer->len * 8 / sdd->cur_bpw) & 0xffff)
 					| S3C64XX_SPI_PACKET_CNT_EN,
 					regs + S3C64XX_SPI_PACKET_CNT);
-			s3c2410_dma_config(sdd->rx_dmach, sdd->cur_bpw / 8);
-			s3c2410_dma_enqueue(sdd->rx_dmach, (void *)sdd,
-						xfer->rx_dma, xfer->len);
-			s3c2410_dma_ctrl(sdd->rx_dmach, S3C2410_DMAOP_START);
+			info.cap = DMA_SLAVE;
+			info.direction = DMA_FROM_DEVICE;
+			info.buf = xfer->rx_dma;
+			info.len = xfer->len;
+			info.fp = s3c64xx_spi_dma_rxcb;
+			info.fp_param = sdd;
+			sdd->ops->prepare(sdd->rx_ch, &info);
+			sdd->ops->trigger(sdd->rx_ch);
 		}
 	}
 
@@ -483,46 +527,6 @@ static void s3c64xx_spi_config(struct s3c64xx_spi_driver_data *sdd)
 	}
 }
 
-static void s3c64xx_spi_dma_rxcb(struct s3c2410_dma_chan *chan, void *buf_id,
-				 int size, enum s3c2410_dma_buffresult res)
-{
-	struct s3c64xx_spi_driver_data *sdd = buf_id;
-	unsigned long flags;
-
-	spin_lock_irqsave(&sdd->lock, flags);
-
-	if (res == S3C2410_RES_OK)
-		sdd->state &= ~RXBUSY;
-	else
-		dev_err(&sdd->pdev->dev, "DmaAbrtRx-%d\n", size);
-
-	/* If the other done */
-	if (!(sdd->state & TXBUSY))
-		complete(&sdd->xfer_completion);
-
-	spin_unlock_irqrestore(&sdd->lock, flags);
-}
-
-static void s3c64xx_spi_dma_txcb(struct s3c2410_dma_chan *chan, void *buf_id,
-				 int size, enum s3c2410_dma_buffresult res)
-{
-	struct s3c64xx_spi_driver_data *sdd = buf_id;
-	unsigned long flags;
-
-	spin_lock_irqsave(&sdd->lock, flags);
-
-	if (res == S3C2410_RES_OK)
-		sdd->state &= ~TXBUSY;
-	else
-		dev_err(&sdd->pdev->dev, "DmaAbrtTx-%d \n", size);
-
-	/* If the other done */
-	if (!(sdd->state & RXBUSY))
-		complete(&sdd->xfer_completion);
-
-	spin_unlock_irqrestore(&sdd->lock, flags);
-}
-
 #define XFER_DMAADDR_INVALID DMA_BIT_MASK(32)
 
 static int s3c64xx_spi_map_mssg(struct s3c64xx_spi_driver_data *sdd,
@@ -697,12 +701,10 @@ static void handle_msg(struct s3c64xx_spi_driver_data *sdd,
 			if (use_dma) {
 				if (xfer->tx_buf != NULL
 						&& (sdd->state & TXBUSY))
-					s3c2410_dma_ctrl(sdd->tx_dmach,
-							S3C2410_DMAOP_FLUSH);
+					sdd->ops->stop(sdd->tx_ch);
 				if (xfer->rx_buf != NULL
 						&& (sdd->state & RXBUSY))
-					s3c2410_dma_ctrl(sdd->rx_dmach,
-							S3C2410_DMAOP_FLUSH);
+					sdd->ops->stop(sdd->rx_ch);
 			}
 
 			goto out;
@@ -742,24 +744,19 @@ out:
 
 static int acquire_dma(struct s3c64xx_spi_driver_data *sdd)
 {
-	if (s3c2410_dma_request(sdd->rx_dmach,
-					&s3c64xx_spi_dma_client, NULL) < 0) {
-		dev_err(&sdd->pdev->dev, "cannot get RxDMA\n");
-		return 0;
-	}
-	s3c2410_dma_set_buffdone_fn(sdd->rx_dmach, s3c64xx_spi_dma_rxcb);
-	s3c2410_dma_devconfig(sdd->rx_dmach, S3C2410_DMASRC_HW,
-					sdd->sfr_start + S3C64XX_SPI_RX_DATA);
-
-	if (s3c2410_dma_request(sdd->tx_dmach,
-					&s3c64xx_spi_dma_client, NULL) < 0) {
-		dev_err(&sdd->pdev->dev, "cannot get TxDMA\n");
-		s3c2410_dma_free(sdd->rx_dmach, &s3c64xx_spi_dma_client);
-		return 0;
-	}
-	s3c2410_dma_set_buffdone_fn(sdd->tx_dmach, s3c64xx_spi_dma_txcb);
-	s3c2410_dma_devconfig(sdd->tx_dmach, S3C2410_DMASRC_MEM,
-					sdd->sfr_start + S3C64XX_SPI_TX_DATA);
+
+	struct samsung_dma_info info;
+	sdd->ops = samsung_dma_get_ops();
+
+	info.cap = DMA_SLAVE;
+	info.client = &s3c64xx_spi_dma_client;
+	info.direction = DMA_FROM_DEVICE;
+	info.fifo = sdd->sfr_start + S3C64XX_SPI_RX_DATA;
+	info.width = sdd->cur_bpw / 8;
+	sdd->rx_ch = sdd->ops->request(sdd->rx_dmach, &info);
+	info.direction = DMA_TO_DEVICE;
+	info.fifo = sdd->sfr_start + S3C64XX_SPI_TX_DATA;
+	sdd->tx_ch = sdd->ops->request(sdd->tx_dmach, &info);
 
 	return 1;
 }
@@ -800,8 +797,8 @@ static void s3c64xx_spi_work(struct work_struct *work)
 	spin_unlock_irqrestore(&sdd->lock, flags);
 
 	/* Free DMA channels */
-	s3c2410_dma_free(sdd->tx_dmach, &s3c64xx_spi_dma_client);
-	s3c2410_dma_free(sdd->rx_dmach, &s3c64xx_spi_dma_client);
+	sdd->ops->release(sdd->rx_ch, &s3c64xx_spi_dma_client);
+	sdd->ops->release(sdd->tx_ch, &s3c64xx_spi_dma_client);
 }
 
 static int s3c64xx_spi_transfer(struct spi_device *spi,
Signature · 2 lines
~Vinod Koul
Intel Corp.
author
#63 lore raw

PATCH v4 12/14 spi/s3c64xx: Add support DMA engine API

Vinod Koul Wrote:

Quoted 68 lines

Sent: Monday, July 25, 2011 8:17 PM
To: Boojin Kim
Cc: vinod.koul at intel.com; linux-arm-kernel at lists.infradead.org; linux- samsung-soc at vger.kernel.org; Kukjin Kim; Jassi Brar; Grant Likely; Mark Brown; Dan Williams
Subject: Re: [PATCH V4 12/14] spi/s3c64xx: Add support DMA engine API

Quoted 10 lines · Boojin Kim

This patch adds to support DMA generic API to transfer raw SPI data. Basiclly the spi driver uses DMA generic API if architecture supports it. Otherwise, uses Samsung specific S3C-PL330 APIs.

---
 drivers/spi/spi_s3c64xx.c |  141 ++++++++++++++++++++++-------------

----------

drivers/spi/spi_s3c64xx.c static void flush_fifo(struct

Quoted 17 lines
 1 files changed, 69 insertions(+), 72 deletions(-)
drivers/spi/spi_s3c64xx.c +3 -0
index 8945e20..a4cf76a 100644
@@ -172,6 +172,9 @@ struct s3c64xx_spi_driver_data {
 	unsigned                        state;
 	unsigned                        cur_mode, cur_bpw;
 	unsigned                        cur_speed;
+	unsigned			rx_ch;
+	unsigned			tx_ch;
+	struct samsung_dma_ops		*ops;
 };
 
 static struct s3c2410_dma_client s3c64xx_spi_dma_client = {
@@ -227,6 +230,38 @@ static void flush_fifo(struct

s3c64xx_spi_driver_data *sdd)

Quoted 31 lines
drivers/spi/spi_s3c64xx.c +28 -0
 	writel(val, regs + S3C64XX_SPI_CH_CFG);
 }
 
+static void s3c64xx_spi_dma_rxcb(void *data)
+{
+	struct s3c64xx_spi_driver_data *sdd
+		= (struct s3c64xx_spi_driver_data *)data;
+	unsigned long flags;
+
+	spin_lock_irqsave(&sdd->lock, flags);
+
+	sdd->state &= ~RXBUSY;
+	/* If the other done */
+	if (!(sdd->state & TXBUSY))
+		complete(&sdd->xfer_completion);
+
+	spin_unlock_irqrestore(&sdd->lock, flags);
+}
+
+static void s3c64xx_spi_dma_txcb(void *data)
+{
+	struct s3c64xx_spi_driver_data *sdd
+		= (struct s3c64xx_spi_driver_data *)data;
+	unsigned long flags;
+
+	spin_lock_irqsave(&sdd->lock, flags);
+
+	sdd->state &= ~TXBUSY;
+	/* If the other done */
+	if (!(sdd->state & RXBUSY))
+		complete(&sdd->xfer_completion);
Quoted 8 lines

drivers/spi/spi_s3c64xx.c static void flush_fifo(struct s3c64xx_spi_driver_data *sdd) · line 247

Quoted 3 lines
drivers/spi/spi_s3c64xx.c +3 -0
+
+	spin_unlock_irqrestore(&sdd->lock, flags);
+}

I don't see much diff in these two functions and you should be able to use a generic one which takes care of both TX and RX, does your callback
data know if the channel is for TX or RX? If not then a helper to do above should take care well and making code simpler

I'm very agree with you.
But, I think it isn't deeply related to this patch series. So, I wish to make and submit it after this patch series is finished.

Quoted 177 lines

drivers/spi/spi_s3c64xx.c static void enable_datapath(struct

Quoted 6 lines
drivers/spi/spi_s3c64xx.c +1 -0
+
 static void enable_datapath(struct s3c64xx_spi_driver_data *sdd,
 				struct spi_device *spi,
 				struct spi_transfer *xfer, int dma_mode)
@@ -234,6 +269,7 @@ static void enable_datapath(struct

s3c64xx_spi_driver_data *sdd,

drivers/spi/spi_s3c64xx.c static void enable_datapath(struct s3c64xx_spi_driver_data *sdd,

Quoted 7 lines
drivers/spi/spi_s3c64xx.c +1 -0
 	struct s3c64xx_spi_info *sci = sdd->cntrlr_info;
 	void __iomem *regs = sdd->regs;
 	u32 modecfg, chcfg;
+	struct samsung_dma_prep_info info;
 
 	modecfg = readl(regs + S3C64XX_SPI_MODE_CFG);
 	modecfg &= ~(S3C64XX_SPI_MODE_TXDMA_ON |

S3C64XX_SPI_MODE_RXDMA_ON);

drivers/spi/spi_s3c64xx.c static void enable_datapath(struct

Quoted 1 line
drivers/spi/spi_s3c64xx.c +0 -0
@@ -259,10 +295,14 @@ static void enable_datapath(struct

s3c64xx_spi_driver_data *sdd,

drivers/spi/spi_s3c64xx.c static void enable_datapath(struct s3c64xx_spi_driver_data *sdd,

Quoted 7 lines
drivers/spi/spi_s3c64xx.c +0 -4
 		chcfg |= S3C64XX_SPI_CH_TXCH_ON;
 		if (dma_mode) {
 			modecfg |= S3C64XX_SPI_MODE_TXDMA_ON;
-			s3c2410_dma_config(sdd->tx_dmach, sdd->cur_bpw / 8);
-			s3c2410_dma_enqueue(sdd->tx_dmach, (void *)sdd,
-						xfer->tx_dma, xfer->len);
-			s3c2410_dma_ctrl(sdd->tx_dmach,

S3C2410_DMAOP_START);

drivers/spi/spi_s3c64xx.c static void enable_datapath(struct

Quoted 12 lines
drivers/spi/spi_s3c64xx.c +8 -0
+			info.cap = DMA_SLAVE;
+			info.direction = DMA_TO_DEVICE;
+			info.buf = xfer->tx_dma;
+			info.len = xfer->len;
+			info.fp = s3c64xx_spi_dma_txcb;
+			info.fp_param = sdd;
+			sdd->ops->prepare(sdd->tx_ch, &info);
+			sdd->ops->trigger(sdd->tx_ch);
 		} else {
 			switch (sdd->cur_bpw) {
 			case 32:
@@ -294,10 +334,14 @@ static void enable_datapath(struct

s3c64xx_spi_driver_data *sdd,

drivers/spi/spi_s3c64xx.c static void enable_datapath(struct s3c64xx_spi_driver_data *sdd,

Quoted 7 lines
drivers/spi/spi_s3c64xx.c +0 -4
 			writel(((xfer->len * 8 / sdd->cur_bpw) & 0xffff)
 					| S3C64XX_SPI_PACKET_CNT_EN,
 					regs + S3C64XX_SPI_PACKET_CNT);
-			s3c2410_dma_config(sdd->rx_dmach, sdd->cur_bpw / 8);
-			s3c2410_dma_enqueue(sdd->rx_dmach, (void *)sdd,
-						xfer->rx_dma, xfer->len);
-			s3c2410_dma_ctrl(sdd->rx_dmach,

S3C2410_DMAOP_START);

drivers/spi/spi_s3c64xx.c static void s3c64xx_spi_config(struct

Quoted 12 lines
drivers/spi/spi_s3c64xx.c +8 -0
+			info.cap = DMA_SLAVE;
+			info.direction = DMA_FROM_DEVICE;
+			info.buf = xfer->rx_dma;
+			info.len = xfer->len;
+			info.fp = s3c64xx_spi_dma_rxcb;
+			info.fp_param = sdd;
+			sdd->ops->prepare(sdd->rx_ch, &info);
+			sdd->ops->trigger(sdd->rx_ch);
 		}
 	}
 
@@ -483,46 +527,6 @@ static void s3c64xx_spi_config(struct

s3c64xx_spi_driver_data *sdd)

drivers/spi/spi_s3c64xx.c static void s3c64xx_spi_config(struct · line 486

Quoted 4 lines
drivers/spi/spi_s3c64xx.c +0 -1
 	}
 }
 
-static void s3c64xx_spi_dma_rxcb(struct s3c2410_dma_chan *chan,

void *buf_id,

Quoted 10 lines
drivers/spi/spi_s3c64xx.c +0 -10
-				 int size, enum s3c2410_dma_buffresult res)
-{
-	struct s3c64xx_spi_driver_data *sdd = buf_id;
-	unsigned long flags;
-
-	spin_lock_irqsave(&sdd->lock, flags);
-
-	if (res == S3C2410_RES_OK)
-		sdd->state &= ~RXBUSY;
-	else

drivers/spi/spi_s3c64xx.c static void s3c64xx_spi_config(struct s3c64xx_spi_driver_data *sdd)

Quoted 10 lines
drivers/spi/spi_s3c64xx.c +0 -10
-		dev_err(&sdd->pdev->dev, "DmaAbrtRx-%d\n", size);
-
-	/* If the other done */
-	if (!(sdd->state & TXBUSY))
-		complete(&sdd->xfer_completion);
-
-	spin_unlock_irqrestore(&sdd->lock, flags);
-}
-
-static void s3c64xx_spi_dma_txcb(struct s3c2410_dma_chan *chan,

void *buf_id,

drivers/spi/spi_s3c64xx.c static void handle_msg(struct

Quoted 23 lines
drivers/spi/spi_s3c64xx.c +0 -19
-				 int size, enum s3c2410_dma_buffresult res)
-{
-	struct s3c64xx_spi_driver_data *sdd = buf_id;
-	unsigned long flags;
-
-	spin_lock_irqsave(&sdd->lock, flags);
-
-	if (res == S3C2410_RES_OK)
-		sdd->state &= ~TXBUSY;
-	else
-		dev_err(&sdd->pdev->dev, "DmaAbrtTx-%d \n", size);
-
-	/* If the other done */
-	if (!(sdd->state & RXBUSY))
-		complete(&sdd->xfer_completion);
-
-	spin_unlock_irqrestore(&sdd->lock, flags);
-}
-
 #define XFER_DMAADDR_INVALID DMA_BIT_MASK(32)
 
 static int s3c64xx_spi_map_mssg(struct s3c64xx_spi_driver_data *sdd,
@@ -697,12 +701,10 @@ static void handle_msg(struct

s3c64xx_spi_driver_data *sdd,

drivers/spi/spi_s3c64xx.c static void s3c64xx_spi_work(struct work_struct

Quoted 53 lines
drivers/spi/spi_s3c64xx.c +15 -22
 			if (use_dma) {
 				if (xfer->tx_buf != NULL
 						&& (sdd->state & TXBUSY))
-					s3c2410_dma_ctrl(sdd->tx_dmach,
-							S3C2410_DMAOP_FLUSH);
+					sdd->ops->stop(sdd->tx_ch);
 				if (xfer->rx_buf != NULL
 						&& (sdd->state & RXBUSY))
-					s3c2410_dma_ctrl(sdd->rx_dmach,
-							S3C2410_DMAOP_FLUSH);
+					sdd->ops->stop(sdd->rx_ch);
 			}
 
 			goto out;
@@ -742,24 +744,19 @@ out:
 
 static int acquire_dma(struct s3c64xx_spi_driver_data *sdd)
 {
-	if (s3c2410_dma_request(sdd->rx_dmach,
-					&s3c64xx_spi_dma_client, NULL) < 0) {
-		dev_err(&sdd->pdev->dev, "cannot get RxDMA\n");
-		return 0;
-	}
-	s3c2410_dma_set_buffdone_fn(sdd->rx_dmach, s3c64xx_spi_dma_rxcb);
-	s3c2410_dma_devconfig(sdd->rx_dmach, S3C2410_DMASRC_HW,
-					sdd->sfr_start + S3C64XX_SPI_RX_DATA);
-
-	if (s3c2410_dma_request(sdd->tx_dmach,
-					&s3c64xx_spi_dma_client, NULL) < 0) {
-		dev_err(&sdd->pdev->dev, "cannot get TxDMA\n");
-		s3c2410_dma_free(sdd->rx_dmach, &s3c64xx_spi_dma_client);
-		return 0;
-	}
-	s3c2410_dma_set_buffdone_fn(sdd->tx_dmach, s3c64xx_spi_dma_txcb);
-	s3c2410_dma_devconfig(sdd->tx_dmach, S3C2410_DMASRC_MEM,
-					sdd->sfr_start + S3C64XX_SPI_TX_DATA);
+
+	struct samsung_dma_info info;
+	sdd->ops = samsung_dma_get_ops();
+
+	info.cap = DMA_SLAVE;
+	info.client = &s3c64xx_spi_dma_client;
+	info.direction = DMA_FROM_DEVICE;
+	info.fifo = sdd->sfr_start + S3C64XX_SPI_RX_DATA;
+	info.width = sdd->cur_bpw / 8;
+	sdd->rx_ch = sdd->ops->request(sdd->rx_dmach, &info);
+	info.direction = DMA_TO_DEVICE;
+	info.fifo = sdd->sfr_start + S3C64XX_SPI_TX_DATA;
+	sdd->tx_ch = sdd->ops->request(sdd->tx_dmach, &info);
 
 	return 1;
 }
@@ -800,8 +797,8 @@ static void s3c64xx_spi_work(struct work_struct

*work)

drivers/spi/spi_s3c64xx.c static void s3c64xx_spi_work(struct work_struct *work) · line 804

Quoted 10 lines
drivers/spi/spi_s3c64xx.c +2 -2
 	spin_unlock_irqrestore(&sdd->lock, flags);
 
 	/* Free DMA channels */
-	s3c2410_dma_free(sdd->tx_dmach, &s3c64xx_spi_dma_client);
-	s3c2410_dma_free(sdd->rx_dmach, &s3c64xx_spi_dma_client);
+	sdd->ops->release(sdd->rx_ch, &s3c64xx_spi_dma_client);
+	sdd->ops->release(sdd->tx_ch, &s3c64xx_spi_dma_client);
 }
 
 static int s3c64xx_spi_transfer(struct spi_device *spi,

--
~Vinod Koul
Intel Corp.

#64 lore raw

PATCH v4 12/14 spi/s3c64xx: Add support DMA engine API

Quoted 77 lines · Boojin Kim

Vinod Koul Wrote:

Quoted 68 lines

Sent: Monday, July 25, 2011 8:17 PM
To: Boojin Kim
Cc: vinod.koul at intel.com; linux-arm-kernel at lists.infradead.org; linux- samsung-soc at vger.kernel.org; Kukjin Kim; Jassi Brar; Grant Likely; Mark Brown; Dan Williams
Subject: Re: [PATCH V4 12/14] spi/s3c64xx: Add support DMA engine API

Quoted 10 lines · Boojin Kim

This patch adds to support DMA generic API to transfer raw SPI data. Basiclly the spi driver uses DMA generic API if architecture supports it. Otherwise, uses Samsung specific S3C-PL330 APIs.

---
 drivers/spi/spi_s3c64xx.c |  141 ++++++++++++++++++++++-------------

----------

drivers/spi/spi_s3c64xx.c static void flush_fifo(struct

Quoted 17 lines
 1 files changed, 69 insertions(+), 72 deletions(-)
drivers/spi/spi_s3c64xx.c +3 -0
index 8945e20..a4cf76a 100644
@@ -172,6 +172,9 @@ struct s3c64xx_spi_driver_data {
 	unsigned                        state;
 	unsigned                        cur_mode, cur_bpw;
 	unsigned                        cur_speed;
+	unsigned			rx_ch;
+	unsigned			tx_ch;
+	struct samsung_dma_ops		*ops;
 };
 
 static struct s3c2410_dma_client s3c64xx_spi_dma_client = {
@@ -227,6 +230,38 @@ static void flush_fifo(struct

s3c64xx_spi_driver_data *sdd)

Quoted 31 lines
drivers/spi/spi_s3c64xx.c +28 -0
 	writel(val, regs + S3C64XX_SPI_CH_CFG);
 }
 
+static void s3c64xx_spi_dma_rxcb(void *data)
+{
+	struct s3c64xx_spi_driver_data *sdd
+		= (struct s3c64xx_spi_driver_data *)data;
+	unsigned long flags;
+
+	spin_lock_irqsave(&sdd->lock, flags);
+
+	sdd->state &= ~RXBUSY;
+	/* If the other done */
+	if (!(sdd->state & TXBUSY))
+		complete(&sdd->xfer_completion);
+
+	spin_unlock_irqrestore(&sdd->lock, flags);
+}
+
+static void s3c64xx_spi_dma_txcb(void *data)
+{
+	struct s3c64xx_spi_driver_data *sdd
+		= (struct s3c64xx_spi_driver_data *)data;
+	unsigned long flags;
+
+	spin_lock_irqsave(&sdd->lock, flags);
+
+	sdd->state &= ~TXBUSY;
+	/* If the other done */
+	if (!(sdd->state & RXBUSY))
+		complete(&sdd->xfer_completion);
Quoted 8 lines

drivers/spi/spi_s3c64xx.c static void flush_fifo(struct s3c64xx_spi_driver_data *sdd) · line 247

Quoted 3 lines
drivers/spi/spi_s3c64xx.c +3 -0
+
+	spin_unlock_irqrestore(&sdd->lock, flags);
+}

I don't see much diff in these two functions and you should be able to use a generic one which takes care of both TX and RX, does your callback
data know if the channel is for TX or RX? If not then a helper to do above should take care well and making code simpler

Quoted 4 lines

I'm very agree with you.
But, I think it isn't deeply related to this patch series. So, I wish to make and submit it after this patch series is finished.

Since you are reworking this driver would make sense to do now, it doesn't sound to be a big change.

Signature · 2 lines
~Vinod Koul
Intel Corp.
author
#65 lore raw

PATCH v4 12/14 spi/s3c64xx: Add support DMA engine API

Vinod Koul Wrote:

Quoted 90 lines

Sent: Tuesday, July 26, 2011 7:15 PM
To: Boojin Kim
Cc: vinod.koul at intel.com; 'Kukjin Kim'; 'Jassi Brar'; 'Grant Likely'; linux-samsung-soc at vger.kernel.org; 'Mark Brown'; 'Dan Williams'; linux-arm-kernel at lists.infradead.org
Subject: RE: [PATCH V4 12/14] spi/s3c64xx: Add support DMA engine API

Quoted 4 lines · Boojin Kim

Vinod Koul Wrote:

Quoted 3 lines

Sent: Monday, July 25, 2011 8:17 PM
To: Boojin Kim
Cc: vinod.koul at intel.com; linux-arm-kernel at lists.infradead.org;

linux-

Quoted 3 lines
Quoted 3 lines

samsung-soc at vger.kernel.org; Kukjin Kim; Jassi Brar; Grant Likely; Mark Brown; Dan Williams
Subject: Re: [PATCH V4 12/14] spi/s3c64xx: Add support DMA engine

API

Quoted 7 lines
Quoted 7 lines · Boojin Kim
Quoted 5 lines

This patch adds to support DMA generic API to transfer raw SPI data. Basiclly the spi driver uses DMA generic API if architecture supports it. Otherwise, uses Samsung specific S3C-PL330 APIs.

Quoted 5 lines
Quoted 5 lines
Quoted 5 lines
---
 drivers/spi/spi_s3c64xx.c |  141 ++++++++++++++++++++++---------

----

Quoted 4 lines
Quoted 4 lines

----------

Review

Quoted 3 lines
 1 files changed, 69 insertions(+), 72 deletions(-)
(quoted diff) +0 -0

b/drivers/spi/spi_s3c64xx.c

Quoted 42 lines
Quoted 42 lines

drivers/spi/spi_s3c64xx.c static void flush_fifo(struct

Quoted 14 lines

index 8945e20..a4cf76a 100644

drivers/spi/spi_s3c64xx.c +3 -0
@@ -172,6 +172,9 @@ struct s3c64xx_spi_driver_data {
 	unsigned                        state;
 	unsigned                        cur_mode, cur_bpw;
 	unsigned                        cur_speed;
+	unsigned			rx_ch;
+	unsigned			tx_ch;
+	struct samsung_dma_ops		*ops;
 };
 
 static struct s3c2410_dma_client s3c64xx_spi_dma_client = {
@@ -227,6 +230,38 @@ static void flush_fifo(struct

s3c64xx_spi_driver_data *sdd)

Quoted 27 lines
drivers/spi/spi_s3c64xx.c +24 -0
 	writel(val, regs + S3C64XX_SPI_CH_CFG);
 }
 
+static void s3c64xx_spi_dma_rxcb(void *data)
+{
+	struct s3c64xx_spi_driver_data *sdd
+		= (struct s3c64xx_spi_driver_data *)data;
+	unsigned long flags;
+
+	spin_lock_irqsave(&sdd->lock, flags);
+
+	sdd->state &= ~RXBUSY;
+	/* If the other done */
+	if (!(sdd->state & TXBUSY))
+		complete(&sdd->xfer_completion);
+
+	spin_unlock_irqrestore(&sdd->lock, flags);
+}
+
+static void s3c64xx_spi_dma_txcb(void *data)
+{
+	struct s3c64xx_spi_driver_data *sdd
+		= (struct s3c64xx_spi_driver_data *)data;
+	unsigned long flags;
+
+	spin_lock_irqsave(&sdd->lock, flags);
+
Quoted 8 lines
Quoted 8 lines

drivers/spi/spi_s3c64xx.c static void flush_fifo(struct s3c64xx_spi_driver_data *sdd) · line 263

Quoted 7 lines
drivers/spi/spi_s3c64xx.c +7 -0
+	sdd->state &= ~TXBUSY;
+	/* If the other done */
+	if (!(sdd->state & RXBUSY))
+		complete(&sdd->xfer_completion);
+
+	spin_unlock_irqrestore(&sdd->lock, flags);
+}

I don't see much diff in these two functions and you should be

able to

Quoted 3 lines
Quoted 3 lines

use a generic one which takes care of both TX and RX, does your callback
data know if the channel is for TX or RX? If not then a helper to

do

Quoted 8 lines
Quoted 3 lines
Quoted 1 line

above should take care well and making code simpler

I'm very agree with you.
But, I think it isn't deeply related to this patch series. So, I

wish to make

Quoted 2 lines

and submit it after this patch series is finished.

Since you are reworking this driver would make sense to do now, it doesn't sound to be a big change.

Ok. I will follow your request.
I will make new patch for it and send it with V5 patchset.

Quoted 4 lines

--
~Vinod Koul
Intel Corp.

author
#66 lore raw

PATCH v4 13/14 ASoC: Samsung: Update DMA interface

In reply to Boojin Kim

This patch adds to support the DMA PL330 driver that uses DMA generic API. Samsung sound driver uses DMA generic API if architecture supports it. Otherwise, use samsung specific S3C-PL330 API driver to transfer PCM data.

Cc Jassi Brar <[email protected]>
Cc Liam Girdwood <[email protected]>
Cc Mark Brown <[email protected]>
---
 arch/arm/mach-s3c2410/include/mach/dma.h       |   10 +-
 arch/arm/mach-s3c64xx/include/mach/dma.h       |    2 +-
 arch/arm/plat-samsung/include/plat/dma-pl330.h |    2 +-
 sound/soc/samsung/ac97.c                       |   10 ++-
 sound/soc/samsung/dma.c                        |  144 ++++++++++--------------
 sound/soc/samsung/dma.h                        |    4 +-
 6 files changed, 78 insertions(+), 94 deletions(-)
arch/arm/mach-s3c2410/include/mach/dma.h +5 -5
index e61a91f..4e485ba 100644
@@ -50,6 +50,11 @@ enum dma_ch {
 	DMACH_MAX,		/* the end entry */
 };
 
+static inline bool samsung_dma_has_circular(void)
+{
+	return false;
+}
+
 static inline bool samsung_dma_is_dmadev(void)
 {
 	return false;
@@ -202,9 +207,4 @@ struct s3c2410_dma_chan {
 
 typedef unsigned long dma_device_t;
 
-static inline bool s3c_dma_has_circular(void)
-{
-	return false;
-}
-
 #endif /* __ASM_ARCH_DMA_H */
arch/arm/mach-s3c64xx/include/mach/dma.h +1 -1
index 49c3a53..74fdf25 100644
@@ -58,7 +58,7 @@ enum dma_ch {
 	DMACH_MAX		/* the end */
 };
 
-static __inline__ bool s3c_dma_has_circular(void)
+static inline bool samsung_dma_has_circular(void)
 {
 	return true;
 }
arch/arm/plat-samsung/include/plat/dma-pl330.h +1 -1
index ded416c..c64b845 100644
@@ -97,7 +97,7 @@ struct s3c2410_dma_client {
 	char	*name;
 };
 
-static inline bool s3c_dma_has_circular(void)
+static inline bool samsung_dma_has_circular(void)
 {
 	return true;
 }
sound/soc/samsung/ac97.c +8 -2
index f97110e..b4f9b00 100644
@@ -271,7 +271,10 @@ static int s3c_ac97_trigger(struct snd_pcm_substream *substream, int cmd,
 
 	writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL);
 
-	s3c2410_dma_ctrl(dma_data->channel, S3C2410_DMAOP_STARTED);
+	if (!dma_data->ops)
+		dma_data->ops = samsung_dma_get_ops();
+
+	dma_data->ops->started(dma_data->channel);
 
 	return 0;
 }
@@ -317,7 +320,10 @@ static int s3c_ac97_mic_trigger(struct snd_pcm_substream *substream,
 
 	writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL);
 
-	s3c2410_dma_ctrl(dma_data->channel, S3C2410_DMAOP_STARTED);
+	if (!dma_data->ops)
+		dma_data->ops = samsung_dma_get_ops();
+
+	dma_data->ops->started(dma_data->channel);
 
 	return 0;
 }
sound/soc/samsung/dma.c +60 -84

233 lines not on this page · raw message

sound/soc/samsung/dma.h +3 -1
index c506592..7d1ead7 100644
@@ -6,7 +6,7 @@
  *  Free Software Foundation;  either version 2 of the  License, or (at your
  *  option) any later version.
  *
- *  ALSA PCM interface for the Samsung S3C24xx CPU
+ *  ALSA PCM interface for the Samsung SoC
  */
 
 #ifndef _S3C_AUDIO_H
@@ -17,6 +17,8 @@ struct s3c_dma_params {
 	int channel;				/* Channel ID */
 	dma_addr_t dma_addr;
 	int dma_size;			/* Size of the DMA transfer */
+	unsigned ch;
+	struct samsung_dma_ops *ops;
 };
 
 #endif
Signature · 1 line
1.7.1
author
#67 lore raw

PATCH v4 14/14 ARM: SAMSUNG: Remove Samsung specific enum type for dma direction

In reply to Boojin Kim

This patch removes the samsung specific enum type 's3c2410_dmasrc' and uses 'dma_data_direction' instead.

---
 arch/arm/mach-s3c2410/include/mach/dma.h         |    2 +-
 arch/arm/mach-s3c2412/dma.c                      |    4 ++--
 arch/arm/mach-s3c64xx/dma.c                      |   10 +++++-----
 arch/arm/mach-s3c64xx/include/mach/dma.h         |    2 +-
 arch/arm/plat-s3c24xx/dma.c                      |   10 +++++-----
 arch/arm/plat-samsung/include/plat/dma-s3c24xx.h |    2 +-
 arch/arm/plat-samsung/include/plat/dma.h         |    9 +++------
 arch/arm/plat-samsung/s3c-dma-ops.c              |    5 +----
 drivers/mmc/host/s3cmci.c                        |    6 +++---
 9 files changed, 22 insertions(+), 28 deletions(-)
arch/arm/mach-s3c2410/include/mach/dma.h +1 -1
index 4e485ba..ae8e482 100644
@@ -174,7 +174,7 @@ struct s3c2410_dma_chan {
 	struct s3c2410_dma_client *client;
 
 	/* channel configuration */
-	enum s3c2410_dmasrc	 source;
+	enum dma_data_direction	 source;
 	enum dma_ch		 req_ch;
 	unsigned long		 dev_addr;
 	unsigned long		 load_timeout;
arch/arm/mach-s3c2412/dma.c +2 -2
index 7abecfc..b4fc3ba 100644
@@ -148,11 +148,11 @@ static struct s3c24xx_dma_map __initdata s3c2412_dma_mappings[] = {
 
 static void s3c2412_dma_direction(struct s3c2410_dma_chan *chan,
 				  struct s3c24xx_dma_map *map,
-				  enum s3c2410_dmasrc dir)
+				  enum dma_data_direction dir)
 {
 	unsigned long chsel;
 
-	if (dir == S3C2410_DMASRC_HW)
+	if (dir == DMA_FROM_DEVICE)
 		chsel = map->channels_rx[0];
 	else
 		chsel = map->channels[0];
arch/arm/mach-s3c64xx/dma.c +5 -5
index b197171..d96ed4c 100644
@@ -147,14 +147,14 @@ static void s3c64xx_dma_fill_lli(struct s3c2410_dma_chan *chan,
 	u32 control0, control1;
 
 	switch (chan->source) {
-	case S3C2410_DMASRC_HW:
+	case DMA_FROM_DEVICE:
 		src = chan->dev_addr;
 		dst = data;
 		control0 = PL080_CONTROL_SRC_AHB2;
 		control0 |= PL080_CONTROL_DST_INCR;
 		break;
 
-	case S3C2410_DMASRC_MEM:
+	case DMA_TO_DEVICE:
 		src = data;
 		dst = chan->dev_addr;
 		control0 = PL080_CONTROL_DST_AHB2;
@@ -416,7 +416,7 @@ EXPORT_SYMBOL(s3c2410_dma_enqueue);
 
 
 int s3c2410_dma_devconfig(unsigned int channel,
-			  enum s3c2410_dmasrc source,
+			  enum dma_data_direction source,
 			  unsigned long devaddr)
 {
 	struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel);
@@ -437,11 +437,11 @@ int s3c2410_dma_devconfig(unsigned int channel,
 	pr_debug("%s: peripheral %d\n", __func__, peripheral);
 
 	switch (source) {
-	case S3C2410_DMASRC_HW:
+	case DMA_FROM_DEVICE:
 		config = 2 << PL080_CONFIG_FLOW_CONTROL_SHIFT;
 		config |= peripheral << PL080_CONFIG_SRC_SEL_SHIFT;
 		break;
-	case S3C2410_DMASRC_MEM:
+	case DMA_TO_DEVICE:
 		config = 1 << PL080_CONFIG_FLOW_CONTROL_SHIFT;
 		config |= peripheral << PL080_CONFIG_DST_SEL_SHIFT;
 		break;
arch/arm/mach-s3c64xx/include/mach/dma.h +1 -1
index 74fdf25..fe1a98c 100644
@@ -99,7 +99,7 @@ struct s3c2410_dma_chan {
 	unsigned char		 peripheral;
 
 	unsigned int		 flags;
-	enum s3c2410_dmasrc	 source;
+	enum dma_data_direction	 source;
 
 
 	dma_addr_t		dev_addr;
arch/arm/plat-s3c24xx/dma.c +5 -5
index a79a8cc..036ff81 100644
@@ -1094,14 +1094,14 @@ EXPORT_SYMBOL(s3c2410_dma_config);
  *
  * configure the dma source/destination hardware type and address
  *
- * source:    S3C2410_DMASRC_HW: source is hardware
- *            S3C2410_DMASRC_MEM: source is memory
+ * source:    DMA_FROM_DEVICE: source is hardware
+ *            DMA_TO_DEVICE: source is memory
  *
  * devaddr:   physical address of the source
 */
 
 int s3c2410_dma_devconfig(unsigned int channel,
-			  enum s3c2410_dmasrc source,
+			  enum dma_data_direction source,
 			  unsigned long devaddr)
 {
 	struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel);
@@ -1131,7 +1131,7 @@ int s3c2410_dma_devconfig(unsigned int channel,
 	 hwcfg |= S3C2410_DISRCC_INC;
 
 	switch (source) {
-	case S3C2410_DMASRC_HW:
+	case DMA_FROME_DEVICE:
 		/* source is hardware */
 		pr_debug("%s: hw source, devaddr=%08lx, hwcfg=%d\n",
 			 __func__, devaddr, hwcfg);
@@ -1142,7 +1142,7 @@ int s3c2410_dma_devconfig(unsigned int channel,
 		chan->addr_reg = dma_regaddr(chan, S3C2410_DMA_DIDST);
 		break;
 
-	case S3C2410_DMASRC_MEM:
+	case DMA_TO_DEVICE:
 		/* source is memory */
 		pr_debug("%s: mem source, devaddr=%08lx, hwcfg=%d\n",
 			 __func__, devaddr, hwcfg);
arch/arm/plat-samsung/include/plat/dma-s3c24xx.h +1 -1
index 336d5ac..1982829 100644
@@ -47,7 +47,7 @@ struct s3c24xx_dma_selection {
 
 	void	(*direction)(struct s3c2410_dma_chan *chan,
 			     struct s3c24xx_dma_map *map,
-			     enum s3c2410_dmasrc dir);
+			     enum dma_data_direction dir);
 };
 
 extern int s3c24xx_dma_init_map(struct s3c24xx_dma_selection *sel);
arch/arm/plat-samsung/include/plat/dma.h +3 -6
index e87c6be..b395398 100644
@@ -10,17 +10,14 @@
  * published by the Free Software Foundation.
 */
 
+#include <linux/dma-mapping.h>
+
 enum s3c2410_dma_buffresult {
 	S3C2410_RES_OK,
 	S3C2410_RES_ERR,
 	S3C2410_RES_ABORT
 };
 
-enum s3c2410_dmasrc {
-	S3C2410_DMASRC_HW,		/* source is memory */
-	S3C2410_DMASRC_MEM		/* source is hardware */
-};
-
 /* enum s3c2410_chan_op
  *
  * operation codes passed to the DMA code by the user, and also used
@@ -111,7 +108,7 @@ extern int s3c2410_dma_config(unsigned int channel, int xferunit);
 */
 
 extern int s3c2410_dma_devconfig(unsigned int channel,
-		enum s3c2410_dmasrc source, unsigned long devaddr);
+		enum dma_data_direction source, unsigned long devaddr);
 
 /* s3c2410_dma_getposition
  *
arch/arm/plat-samsung/s3c-dma-ops.c +1 -4
index 33ab324..582333c 100644
@@ -48,10 +48,7 @@ static unsigned s3c_dma_request(enum dma_ch dma_ch,
 	data->ch = dma_ch;
 	list_add_tail(&data->node, &dma_list);
 
-	if (info->direction == DMA_FROM_DEVICE)
-		s3c2410_dma_devconfig(dma_ch, S3C2410_DMASRC_HW, info->fifo);
-	else
-		s3c2410_dma_devconfig(dma_ch, S3C2410_DMASRC_MEM, info->fifo);
+	s3c2410_dma_devconfig(dma_ch, info->direction, info->fifo);
 
 	if (info->cap == DMA_CYCLIC)
 		s3c2410_dma_setflags(dma_ch, S3C2410_DMAF_CIRCULAR);
drivers/mmc/host/s3cmci.c +3 -3
index a04f87d..03cfdab 100644
@@ -913,9 +913,9 @@ request_done:
 }
 
 static void s3cmci_dma_setup(struct s3cmci_host *host,
-			     enum s3c2410_dmasrc source)
+			     enum dma_data_direction source)
 {
-	static enum s3c2410_dmasrc last_source = -1;
+	static enum dma_data_direction last_source = -1;
 	static int setup_ok;
 
 	if (last_source == source)
@@ -1087,7 +1087,7 @@ static int s3cmci_prepare_dma(struct s3cmci_host *host, struct mmc_data *data)
 
 	BUG_ON((data->flags & BOTH_DIR) == BOTH_DIR);
 
-	s3cmci_dma_setup(host, rw ? S3C2410_DMASRC_MEM : S3C2410_DMASRC_HW);
+	s3cmci_dma_setup(host, rw ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
 	s3c2410_dma_ctrl(host->dma, S3C2410_DMAOP_FLUSH);
 
 	dma_len = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
Signature · 1 line
1.7.1
#69 lore raw

PATCH v4 14/14 ARM: SAMSUNG: Remove Samsung specific enum type for dma direction

Quoted 11 lines · Jassi Brar
Quoted 5 lines · Boojin Kim

This patch removes the samsung specific enum type 's3c2410_dmasrc' and uses 'dma_data_direction' instead.

If this patch was first in the patchset, probably it could have been already merged.

Indeed. If you move this to the front when you post the next version then it can be merged right away.

author
#70 lore raw

PATCH v4 14/14 ARM: SAMSUNG: Remove Samsung specific enum type for dma direction

Grant Likely Wrote:

Quoted 17 lines

Likely
Sent: Tuesday, July 26, 2011 6:16 AM
To: Jassi Brar
Cc: Boojin Kim; linux-arm-kernel at lists.infradead.org; linux-samsung- soc at vger.kernel.org; Vinod Koul; Dan Williams; Kukjin Kim; Mark Brown
Subject: Re: [PATCH V4 14/14] ARM: SAMSUNG: Remove Samsung specific enum type for dma direction

Quoted 1 line · Jassi Brar

On Mon, Jul 25, 2011 at 6:58 AM, Boojin Kim <[email protected]>

Quoted 6 lines · wrote:
Quoted 5 lines

This patch removes the samsung specific enum type 's3c2410_dmasrc' and uses 'dma_data_direction' instead.

Quoted 7 lines
Quoted 4 lines

If this patch was first in the patchset, probably it could have been already merged.

Indeed. If you move this to the front when you post the next version then it can be merged right away.

I tried to move it ahead. But It made some conflicts. So, I pushed as it is on V5 release.
Sorry.. I would have noticed it before I release V5.

Quoted 2 lines
#71 lore raw

v4 cover To use DMA generic APIs for Samsung DMA

In reply to Boojin Kim
Quoted 13 lines · Boojin Kim

This patchset adds support DMA generic APIs for Samsung DMA and is re-sent by the request of DMA maintainer, Vinod Koul.

V4 has the changes about 3 patches from V3.
Changes from V3:
- Divided '[03/13 patch] DMA: PL330: Add DMA capabilites' on V3 patchset into two patches.
- One is '03/14 patch' for supporting DMA_SLAVE_CONFIG command.
- Another is '04/14 patch' for supporting DMA_CYCLIC capability.
- Code clean-up
- Remove unnecessary vairable referance on '01/14 patch'.
- Remove redunancy code on '06/14 patch'

Quoted 15 lines

[PATCH V4 01/14] DMA: PL330: Add support runtime PM for PL330 DMAC [PATCH V4 02/14] DMA: PL330: Update PL330 DMA API driver
[PATCH V4 03/14] DMA: PL330: Support DMA_SLAVE_CONFIG command
[PATCH V4 04/14] DMA: PL330: Add DMA_CYCLIC capability
[PATCH V4 05/14] ARM: SAMSUNG: Update to use PL330-DMA driver
[PATCH V4 06/14] ARM: SAMSUNG: Add common DMA operations
[PATCH V4 07/14] ARM: EXYNOS4: Use generic DMA PL330 driver
[PATCH V4 08/14] ARM: S5PV210: Use generic DMA PL330 driver
[PATCH V4 09/14] ARM: S5PC100: Use generic DMA PL330 driver
[PATCH V4 10/14] ARM: S5P64X0: Use generic DMA PL330 driver
[PATCH V4 11/14] ARM: SAMSUNG: Remove S3C-PL330-DMA driver
[PATCH V4 12/14] spi/s3c64xx: Add support DMA engine API
[PATCH V4 13/14] ASoC: Samsung: Update DMA interface
[PATCH V4 14/14] ARM: SAMSUNG: Remove Samsung specific enum type for dma direction

Thanks for resending I will review them now, You should use git --cover-letter to generate this

Signature · 2 lines
~Vinod Koul
Intel Corp.
#72 lore raw

v4 cover To use DMA generic APIs for Samsung DMA

Quoted 29 lines · Vinod Koul
Quoted 13 lines · Boojin Kim

This patchset adds support DMA generic APIs for Samsung DMA and is re-sent by the request of DMA maintainer, Vinod Koul.

V4 has the changes about 3 patches from V3.
Changes from V3:
- Divided '[03/13 patch] DMA: PL330: Add DMA capabilites' on V3 patchset into two patches.
- One is '03/14 patch' for supporting DMA_SLAVE_CONFIG command.
- Another is '04/14 patch' for supporting DMA_CYCLIC capability.
- Code clean-up
- Remove unnecessary vairable referance on '01/14 patch'.
- Remove redunancy code on '06/14 patch'

Quoted 15 lines

[PATCH V4 01/14] DMA: PL330: Add support runtime PM for PL330 DMAC [PATCH V4 02/14] DMA: PL330: Update PL330 DMA API driver
[PATCH V4 03/14] DMA: PL330: Support DMA_SLAVE_CONFIG command
[PATCH V4 04/14] DMA: PL330: Add DMA_CYCLIC capability
[PATCH V4 05/14] ARM: SAMSUNG: Update to use PL330-DMA driver
[PATCH V4 06/14] ARM: SAMSUNG: Add common DMA operations
[PATCH V4 07/14] ARM: EXYNOS4: Use generic DMA PL330 driver
[PATCH V4 08/14] ARM: S5PV210: Use generic DMA PL330 driver
[PATCH V4 09/14] ARM: S5PC100: Use generic DMA PL330 driver
[PATCH V4 10/14] ARM: S5P64X0: Use generic DMA PL330 driver
[PATCH V4 11/14] ARM: SAMSUNG: Remove S3C-PL330-DMA driver
[PATCH V4 12/14] spi/s3c64xx: Add support DMA engine API
[PATCH V4 13/14] ASoC: Samsung: Update DMA interface
[PATCH V4 14/14] ARM: SAMSUNG: Remove Samsung specific enum type for dma direction

Quoted 3 lines

Thanks for resending I will review them now, You should use git --cover-letter to generate this

Also I noticed the whole patch set doesn't have any acks from previous posting. If a patch has got ack from someone and it is not changed at all in next posting then you can carry that ack.
Makes things easier for me to track while applying

Signature · 2 lines
~Vinod Koul
Intel Corp.