Skip to contentSkip to conversation

dmaengine: sun6i: Fixes and upgrade for audio transfers

PATCH Superseded Jean-Francois Moine 4 participants 15 messages Mar 10, 2016 – Mar 11, 2016

Subsystems (2)

v1 of 6 Superseded Latest is v6 →

lore
Share & tools
lore
#0 lore raw

cover dmaengine: sun6i: Fixes and upgrade for audio transfers

This patch series contains the required fixes and changes to the sun6i DMA driver for audio streaming.
These ones have been tested in a Allwinner H3 (Orange PI 2).

Jean-Francois Moine (5):
dmaengine: sun6i: Fix the access of the IRQ register
dmaengine: sun6i: Fix impossible settings of burst and bus width
dmaengine: sun6i: Add 4 as a possible bust value
dmaengine: sun6i: Set default values to burst and bus width
dmaengine: sun6i: Add cyclic capability

 drivers/dma/sun6i-dma.c | 180 +++++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 161 insertions(+), 19 deletions(-)
Signature · 1 line
2.7.2
#1 lore raw

PATCH 1/5 dmaengine: sun6i: Fix the access of the IRQ register

The address of the IRQ register is computed, but its value was not used and the register access was done by the channel index instead. Then, only the first DMA channel was working.

---
 drivers/dma/sun6i-dma.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/dma/sun6i-dma.c +2 -2
index 2db12e4..2ec320d 100644
@@ -381,9 +381,9 @@ static int sun6i_dma_start_desc(struct sun6i_vchan *vchan)
 	irq_reg = pchan->idx / DMA_IRQ_CHAN_NR;
 	irq_offset = pchan->idx % DMA_IRQ_CHAN_NR;
 
-	irq_val = readl(sdev->base + DMA_IRQ_EN(irq_offset));
+	irq_val = readl(sdev->base + DMA_IRQ_EN(irq_reg));
 	irq_val |= DMA_IRQ_QUEUE << (irq_offset * DMA_IRQ_CHAN_WIDTH);
-	writel(irq_val, sdev->base + DMA_IRQ_EN(irq_offset));
+	writel(irq_val, sdev->base + DMA_IRQ_EN(irq_reg));
 
 	writel(pchan->desc->p_lli, pchan->base + DMA_CHAN_LLI_ADDR);
 	writel(DMA_CHAN_ENABLE_START, pchan->base + DMA_CHAN_ENABLE);
Signature · 1 line
2.7.2
#2 lore raw

PATCH 1/5 dmaengine: sun6i: Fix the access of the IRQ register

Quoted 1 line · Jean-Francois Moine

The address of the IRQ register is computed, but its value was not

						^^^^^^^

it's

Quoted 2 lines

used and the register access was done by the channel index instead. Then, only the first DMA channel was working.

Signature · 1 line
~Vinod
#3 lore raw

PATCH 1/5 dmaengine: sun6i: Fix the access of the IRQ register

Quoted 8 lines · On Fri, 11 Mar 2016 12:09:56 +0530 Vinod Koul <[email protected]> wrote:
Quoted 1 line · Jean-Francois Moine

The address of the IRQ register is computed, but its value was not

						^^^^^^^

it's

Quoted 2 lines

used and the register access was done by the channel index instead. Then, only the first DMA channel was working.

No. 'its value' is 'the value of the address'. I will re-phrase.

Signature · 2 lines
Ken ar c'henta?	|	      ** Breizh ha Linux atav! **
Jef		|		http://moinejf.free.fr/
#4 lore raw

PATCH 1/5 dmaengine: sun6i: Fix the access of the IRQ register

In reply to Jean-Francois Moine
Quoted 5 lines · Jean-Francois Moine

The address of the IRQ register is computed, but its value was not used and the register access was done by the channel index instead. Then, only the first DMA channel was working.

Thanks!
Maxime

Signature · 10 lines
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20160311/df8a2c8b/attachment.sig>
#5 lore raw

PATCH 2/5 dmaengine: sun6i: Fix impossible settings of burst and bus width

In reply to Jean-Francois Moine

In the commit 1f9cd915b64bb95f "dmaengine: sun6i: Fix memcpy operation", the signed values returned by convert_burst() and convert_buswidth() were stored in an unsigned value.
Then, these values were considered as errors when non null. As a result, setting burst or buswidth to values different from 1 was making the DMA transfers to be rejected.

---
 drivers/dma/sun6i-dma.c | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)
drivers/dma/sun6i-dma.c +5 -5
index 2ec320d..3579ee7 100644
@@ -281,25 +281,25 @@ static inline int sun6i_dma_cfg_lli(struct sun6i_dma_lli *lli,
 				    dma_addr_t dst, u32 len,
 				    struct dma_slave_config *config)
 {
-	u8 src_width, dst_width, src_burst, dst_burst;
+	s8 src_width, dst_width, src_burst, dst_burst;
 
 	if (!config)
 		return -EINVAL;
 
 	src_burst = convert_burst(config->src_maxburst);
-	if (src_burst)
+	if (src_burst < 0)
 		return src_burst;
 
 	dst_burst = convert_burst(config->dst_maxburst);
-	if (dst_burst)
+	if (dst_burst < 0)
 		return dst_burst;
 
 	src_width = convert_buswidth(config->src_addr_width);
-	if (src_width)
+	if (src_width < 0)
 		return src_width;
 
 	dst_width = convert_buswidth(config->dst_addr_width);
-	if (dst_width)
+	if (dst_width < 0)
 		return dst_width;
 
 	lli->cfg = DMA_CHAN_CFG_SRC_BURST(src_burst) |
Signature · 1 line
2.7.2
#6 lore raw

PATCH 2/5 dmaengine: sun6i: Fix impossible settings of burst and bus width

Quoted 6 lines · Jean-Francois Moine

In the commit 1f9cd915b64bb95f "dmaengine: sun6i: Fix memcpy operation", the signed values returned by convert_burst() and convert_buswidth() were stored in an unsigned value.
Then, these values were considered as errors when non null. As a result, setting burst or buswidth to values different from 1 was making the DMA transfers to be rejected.

A value of 0 for burst does not make sense. Frr buswidth this in undefined. So what are we gaining from 0 value and how is it fixing something which is passed as wrong argument?

Quoted 44 lines
---
 drivers/dma/sun6i-dma.c | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)
drivers/dma/sun6i-dma.c +5 -5
index 2ec320d..3579ee7 100644
@@ -281,25 +281,25 @@ static inline int sun6i_dma_cfg_lli(struct sun6i_dma_lli *lli,
 				    dma_addr_t dst, u32 len,
 				    struct dma_slave_config *config)
 {
-	u8 src_width, dst_width, src_burst, dst_burst;
+	s8 src_width, dst_width, src_burst, dst_burst;
 
 	if (!config)
 		return -EINVAL;
 
 	src_burst = convert_burst(config->src_maxburst);
-	if (src_burst)
+	if (src_burst < 0)
 		return src_burst;
 
 	dst_burst = convert_burst(config->dst_maxburst);
-	if (dst_burst)
+	if (dst_burst < 0)
 		return dst_burst;
 
 	src_width = convert_buswidth(config->src_addr_width);
-	if (src_width)
+	if (src_width < 0)
 		return src_width;
 
 	dst_width = convert_buswidth(config->dst_addr_width);
-	if (dst_width)
+	if (dst_width < 0)
 		return dst_width;
 
 	lli->cfg = DMA_CHAN_CFG_SRC_BURST(src_burst) |
Signature · 1 line
2.7.2
Signature · 1 line
~Vinod
#7 lore raw

PATCH 2/5 dmaengine: sun6i: Fix impossible settings of burst and bus width

Quoted 11 lines · On Fri, 11 Mar 2016 12:12:27 +0530 Vinod Koul <[email protected]> wrote:
Quoted 6 lines · Jean-Francois Moine

In the commit 1f9cd915b64bb95f "dmaengine: sun6i: Fix memcpy operation", the signed values returned by convert_burst() and convert_buswidth() were stored in an unsigned value.
Then, these values were considered as errors when non null. As a result, setting burst or buswidth to values different from 1 was making the DMA transfers to be rejected.

A value of 0 for burst does not make sense. Frr buswidth this in undefined. So what are we gaining from 0 value and how is it fixing something which is passed as wrong argument?

The problem is not the null value, but a value different from 1:
8 as the burst or 4 as the bus width were rejected.

Signature · 2 lines
Ken ar c'henta?	|	      ** Breizh ha Linux atav! **
Jef		|		http://moinejf.free.fr/
#8 lore raw

PATCH 2/5 dmaengine: sun6i: Fix impossible settings of burst and bus width

In reply to Jean-Francois Moine
Quoted 1 line · Jean-Francois Moine

In the commit 1f9cd915b64bb95f "dmaengine: sun6i: Fix memcpy operation",

The commit title should be enclosed in parenthesis.

Quoted 7 lines

the signed values returned by convert_burst() and convert_buswidth() were stored in an unsigned value.
Then, these values were considered as errors when non null. As a result, setting burst or buswidth to values different from 1 was making the DMA transfers to be rejected.

Otherwise, Acked-by: Maxime Ripard <[email protected]>

Thanks!

Signature · 10 lines
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20160311/98f60af3/attachment.sig>
#9 lore raw

PATCH 3/5 dmaengine: sun6i: Add 4 as a possible bust value

In reply to Jean-Francois Moine

Some DMA transfers, as for H3 audio, ask for 4 as a bust value.

---
 drivers/dma/sun6i-dma.c | 2 ++
 1 file changed, 2 insertions(+)
drivers/dma/sun6i-dma.c +2 -0
index 3579ee7..7c98c0d 100644
@@ -238,6 +238,8 @@ static inline s8 convert_burst(u32 maxburst)
 	switch (maxburst) {
 	case 1:
 		return 0;
+	case 4:
+		return 1;
 	case 8:
 		return 2;
 	default:
Signature · 1 line
2.7.2
#11 lore raw

PATCH 4/5 dmaengine: sun6i: Set default values to burst and bus width

In reply to Jean-Francois Moine

When defining the DMA transfer, the sound PCM DMA engine sets only the burst and bus width values on the DMA side.
This was making the audio transfers to be rejected because of invalid values on the memory side.

---
 drivers/dma/sun6i-dma.c | 20 ++++++++++++++++----
 1 file changed, 16 insertions(+), 4 deletions(-)
drivers/dma/sun6i-dma.c +16 -4
index 7c98c0d..c27d572 100644
@@ -288,19 +288,31 @@ static inline int sun6i_dma_cfg_lli(struct sun6i_dma_lli *lli,
 	if (!config)
 		return -EINVAL;
 
-	src_burst = convert_burst(config->src_maxburst);
+	if (config->src_maxburst == 0)
+		src_burst = convert_burst(config->dst_maxburst);
+	else
+		src_burst = convert_burst(config->src_maxburst);
 	if (src_burst < 0)
 		return src_burst;
 
-	dst_burst = convert_burst(config->dst_maxburst);
+	if (config->dst_maxburst == 0)
+		dst_burst = convert_burst(config->src_maxburst);
+	else
+		dst_burst = convert_burst(config->dst_maxburst);
 	if (dst_burst < 0)
 		return dst_burst;
 
-	src_width = convert_buswidth(config->src_addr_width);
+	if (config->src_addr_width == DMA_SLAVE_BUSWIDTH_UNDEFINED)
+		src_width = convert_buswidth(config->dst_addr_width);
+	else
+		src_width = convert_buswidth(config->src_addr_width);
 	if (src_width < 0)
 		return src_width;
 
-	dst_width = convert_buswidth(config->dst_addr_width);
+	if (config->dst_addr_width == DMA_SLAVE_BUSWIDTH_UNDEFINED)
+		dst_width = convert_buswidth(config->src_addr_width);
+	else
+		dst_width = convert_buswidth(config->dst_addr_width);
 	if (dst_width < 0)
 		return dst_width;
 
Signature · 1 line
2.7.2
#12 lore raw

PATCH 4/5 dmaengine: sun6i: Set default values to burst and bus width

Quoted 4 lines · Jean-Francois Moine

When defining the DMA transfer, the sound PCM DMA engine sets only the burst and bus width values on the DMA side.
This was making the audio transfers to be rejected because of invalid values on the memory side.

I think there is a misunderstanding of the API. The slave configuration set thru dma_slave_config is only intended for peripheral and not for memory.

In memory case you need to assume values based on system. DMA to memory is usually done for max throughput and these parameters do not make sense there.

Quoted 11 lines
---
 drivers/dma/sun6i-dma.c | 20 ++++++++++++++++----
 1 file changed, 16 insertions(+), 4 deletions(-)
drivers/dma/sun6i-dma.c +0 -0
index 7c98c0d..c27d572 100644

drivers/dma/sun6i-dma.c static inline int sun6i_dma_cfg_lli(struct sun6i_dma_lli *lli, · line 294

Quoted 8 lines
drivers/dma/sun6i-dma.c +4 -1
@@ -288,19 +288,31 @@ static inline int sun6i_dma_cfg_lli(struct sun6i_dma_lli *lli,
 	if (!config)
 		return -EINVAL;
 
-	src_burst = convert_burst(config->src_maxburst);
+	if (config->src_maxburst == 0)
+		src_burst = convert_burst(config->dst_maxburst);
+	else
+		src_burst = convert_burst(config->src_maxburst);

No 0 is error for the transfer direction and don't assume default for peripheral, that is just wrong

Signature · 1 line
~Vinod
#13 lore raw

PATCH 5/5 dmaengine: sun6i: Add cyclic capability

In reply to Jean-Francois Moine

DMA cyclic transfers are required by audio streaming.

---
 drivers/dma/sun6i-dma.c | 144 +++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 136 insertions(+), 8 deletions(-)
drivers/dma/sun6i-dma.c +136 -8
index c27d572..06d0306 100644
@@ -146,6 +146,8 @@ struct sun6i_vchan {
 	struct dma_slave_config	cfg;
 	struct sun6i_pchan	*phy;
 	u8			port;
+	u8			irq_type;
+	bool			cyclic;
 };
 
 struct sun6i_dma_dev {
@@ -256,6 +258,30 @@ static inline s8 convert_buswidth(enum dma_slave_buswidth addr_width)
 	return addr_width >> 1;
 }
 
+static size_t sun6i_get_chan_size(struct sun6i_pchan *pchan)
+{
+	struct sun6i_desc *txd = pchan->desc;
+	struct sun6i_dma_lli *lli;
+	size_t bytes;
+	dma_addr_t pos;
+
+	pos = readl(pchan->base + DMA_CHAN_LLI_ADDR);
+	bytes = readl(pchan->base + DMA_CHAN_CUR_CNT);
+
+	if (pos == LLI_LAST_ITEM)
+		return bytes;
+
+	for (lli = txd->v_lli; lli; lli = lli->v_lli_next) {
+		if (lli->p_lli_next == pos) {
+			for (lli = lli->v_lli_next; lli; lli = lli->v_lli_next)
+				bytes += lli->len;
+			break;
+		}
+	}
+
+	return bytes;
+}
+
 static void *sun6i_dma_lli_add(struct sun6i_dma_lli *prev,
 			       struct sun6i_dma_lli *next,
 			       dma_addr_t next_phy,
@@ -395,8 +421,12 @@ static int sun6i_dma_start_desc(struct sun6i_vchan *vchan)
 	irq_reg = pchan->idx / DMA_IRQ_CHAN_NR;
 	irq_offset = pchan->idx % DMA_IRQ_CHAN_NR;
 
+	vchan->irq_type = vchan->cyclic ? DMA_IRQ_PKG : DMA_IRQ_QUEUE;
+
 	irq_val = readl(sdev->base + DMA_IRQ_EN(irq_reg));
-	irq_val |= DMA_IRQ_QUEUE << (irq_offset * DMA_IRQ_CHAN_WIDTH);
+	irq_val &= ~((DMA_IRQ_HALF | DMA_IRQ_PKG | DMA_IRQ_QUEUE) <<
+			(irq_offset * DMA_IRQ_CHAN_WIDTH));
+	irq_val |= vchan->irq_type << (irq_offset * DMA_IRQ_CHAN_WIDTH);
 	writel(irq_val, sdev->base + DMA_IRQ_EN(irq_reg));
 
 	writel(pchan->desc->p_lli, pchan->base + DMA_CHAN_LLI_ADDR);
@@ -493,11 +523,12 @@ static irqreturn_t sun6i_dma_interrupt(int irq, void *dev_id)
 		writel(status, sdev->base + DMA_IRQ_STAT(i));
 
 		for (j = 0; (j < DMA_IRQ_CHAN_NR) && status; j++) {
-			if (status & DMA_IRQ_QUEUE) {
-				pchan = sdev->pchans + j;
-				vchan = pchan->vchan;
-
-				if (vchan) {
+			pchan = sdev->pchans + j;
+			vchan = pchan->vchan;
+			if (vchan && (status & vchan->irq_type)) {
+				if (vchan->cyclic) {
+					vchan_cyclic_callback(&pchan->desc->vd);
+				} else {
 					spin_lock(&vchan->vc.lock);
 					vchan_cookie_complete(&pchan->desc->vd);
 					pchan->done = pchan->desc;
@@ -657,6 +688,76 @@ err_lli_free:
 	return NULL;
 }
 
+static struct dma_async_tx_descriptor *sun6i_dma_prep_dma_cyclic(
+					struct dma_chan *chan,
+					dma_addr_t buf_addr,
+					size_t buf_len,
+					size_t period_len,
+					enum dma_transfer_direction dir,
+					unsigned long flags)
+{
+	struct sun6i_dma_dev *sdev = to_sun6i_dma_dev(chan->device);
+	struct sun6i_vchan *vchan = to_sun6i_vchan(chan);
+	struct dma_slave_config *sconfig = &vchan->cfg;
+	struct sun6i_dma_lli *v_lli, *prev = NULL;
+	struct sun6i_desc *txd;
+	dma_addr_t p_lli;
+	unsigned int i, periods = buf_len / period_len;
+	int ret;
+
+	if (vchan->cyclic && vchan->phy && vchan->phy->desc)
+		return NULL;
+
+	txd = kzalloc(sizeof(*txd), GFP_NOWAIT);
+	if (!txd)
+		return NULL;
+
+	for (i = 0; i < periods; i++){
+		v_lli = dma_pool_alloc(sdev->pool, GFP_NOWAIT, &p_lli);
+		if (!v_lli) {
+			dev_err(sdev->slave.dev, "Failed to alloc lli memory\n");
+			goto err_lli_free;
+		}
+		if (dir == DMA_MEM_TO_DEV) {
+			ret = sun6i_dma_cfg_lli(v_lli,
+						buf_addr + period_len * i,
+						sconfig->dst_addr,
+						period_len, sconfig);
+			v_lli->cfg |= DMA_CHAN_CFG_DST_IO_MODE |
+					DMA_CHAN_CFG_SRC_LINEAR_MODE |
+					DMA_CHAN_CFG_SRC_DRQ(DRQ_SDRAM) |
+					DMA_CHAN_CFG_DST_DRQ(vchan->port);
+		} else {
+			ret = sun6i_dma_cfg_lli(v_lli,
+						sconfig->src_addr,
+						buf_addr + period_len * i,
+						period_len, sconfig);
+			v_lli->cfg |= DMA_CHAN_CFG_DST_LINEAR_MODE |
+					DMA_CHAN_CFG_SRC_IO_MODE |
+					DMA_CHAN_CFG_DST_DRQ(DRQ_SDRAM) |
+					DMA_CHAN_CFG_SRC_DRQ(vchan->port);
+		}
+		if (ret < 0)
+			goto err_cur_lli_free;
+
+		prev = sun6i_dma_lli_add(prev, v_lli, p_lli, txd);
+	}
+
+	prev->p_lli_next = txd->p_lli;		/* cyclic list */
+
+	vchan->cyclic = true;
+
+	return vchan_tx_prep(&vchan->vc, &txd->vd, flags);
+
+err_cur_lli_free:
+	dma_pool_free(sdev->pool, v_lli, p_lli);
+err_lli_free:
+	for (prev = txd->v_lli; prev; prev = prev->v_lli_next)
+		dma_pool_free(sdev->pool, prev, virt_to_phys(prev));
+	kfree(txd);
+	return NULL;
+}
+
 static int sun6i_dma_config(struct dma_chan *chan,
 			    struct dma_slave_config *config)
 {
@@ -726,6 +827,16 @@ static int sun6i_dma_terminate_all(struct dma_chan *chan)
 
 	spin_lock_irqsave(&vchan->vc.lock, flags);
 
+	if (vchan->cyclic) {
+		vchan->cyclic = false;
+		if (pchan && pchan->desc) {
+			struct virt_dma_desc *vd = &pchan->desc->vd;
+			struct virt_dma_chan *vc = &vchan->vc;
+
+			list_add_tail(&vd->node, &vc->desc_completed);
+		}
+	}
+
 	vchan_get_all_descriptors(&vchan->vc, &head);
 
 	if (pchan) {
@@ -773,7 +884,7 @@ static enum dma_status sun6i_dma_tx_status(struct dma_chan *chan,
 	} else if (!pchan || !pchan->desc) {
 		bytes = 0;
 	} else {
-		bytes = readl(pchan->base + DMA_CHAN_CUR_CNT);
+		bytes = sun6i_get_chan_size(pchan);
 	}
 
 	spin_unlock_irqrestore(&vchan->vc.lock, flags);
@@ -792,6 +903,11 @@ static void sun6i_dma_issue_pending(struct dma_chan *chan)
 	spin_lock_irqsave(&vchan->vc.lock, flags);
 
 	if (vchan_issue_pending(&vchan->vc)) {
+		if (vchan->phy && vchan->cyclic) {
+			sun6i_dma_start_desc(vchan);
+			goto out;
+		}
+
 		spin_lock(&sdev->lock);
 
 		if (!vchan->phy && list_empty(&vchan->node)) {
@@ -806,10 +922,19 @@ static void sun6i_dma_issue_pending(struct dma_chan *chan)
 		dev_dbg(chan2dev(chan), "vchan %p: nothing to issue\n",
 			&vchan->vc);
 	}
-
+out:
 	spin_unlock_irqrestore(&vchan->vc.lock, flags);
 }
 
+static int sun6i_dma_alloc_chan_resources(struct dma_chan *chan)
+{
+	struct sun6i_vchan *vchan = to_sun6i_vchan(chan);
+
+	vchan->cyclic = false;
+
+	return 0;
+}
+
 static void sun6i_dma_free_chan_resources(struct dma_chan *chan)
 {
 	struct sun6i_dma_dev *sdev = to_sun6i_dma_dev(chan->device);
@@ -977,13 +1102,16 @@ static int sun6i_dma_probe(struct platform_device *pdev)
 	dma_cap_set(DMA_PRIVATE, sdc->slave.cap_mask);
 	dma_cap_set(DMA_MEMCPY, sdc->slave.cap_mask);
 	dma_cap_set(DMA_SLAVE, sdc->slave.cap_mask);
+	dma_cap_set(DMA_CYCLIC, sdc->slave.cap_mask);
 
 	INIT_LIST_HEAD(&sdc->slave.channels);
+	sdc->slave.device_alloc_chan_resources	= sun6i_dma_alloc_chan_resources;
 	sdc->slave.device_free_chan_resources	= sun6i_dma_free_chan_resources;
 	sdc->slave.device_tx_status		= sun6i_dma_tx_status;
 	sdc->slave.device_issue_pending		= sun6i_dma_issue_pending;
 	sdc->slave.device_prep_slave_sg		= sun6i_dma_prep_slave_sg;
 	sdc->slave.device_prep_dma_memcpy	= sun6i_dma_prep_dma_memcpy;
+	sdc->slave.device_prep_dma_cyclic	= sun6i_dma_prep_dma_cyclic;
 	sdc->slave.copy_align			= DMAENGINE_ALIGN_4_BYTES;
 	sdc->slave.device_config		= sun6i_dma_config;
 	sdc->slave.device_pause			= sun6i_dma_pause;
Signature · 1 line
2.7.2
#14 lore raw

PATCH 5/5 dmaengine: sun6i: Add cyclic capability

drivers/dma/sun6i-dma.c err_lli_free: · line 709

Quoted 3 lines · Jean-Francois Moine
drivers/dma/sun6i-dma.c +3 -0
+
+	if (vchan->cyclic && vchan->phy && vchan->phy->desc)
+		return NULL;

why check for vchan->cyclic? you are setting that at the end!

drivers/dma/sun6i-dma.c static void sun6i_dma_issue_pending(struct dma_chan *chan) · line 909

Quoted 8 lines
drivers/dma/sun6i-dma.c +4 -0
@@ -792,6 +903,11 @@ static void sun6i_dma_issue_pending(struct dma_chan *chan)
 	spin_lock_irqsave(&vchan->vc.lock, flags);
 
 	if (vchan_issue_pending(&vchan->vc)) {
+		if (vchan->phy && vchan->cyclic) {
+			sun6i_dma_start_desc(vchan);
+			goto out;
+		}

Why should this be cyclic specfic, Channel start should be same for all channels?

drivers/dma/sun6i-dma.c static void sun6i_dma_issue_pending(struct dma_chan *chan) · line 933

Quoted 5 lines
drivers/dma/sun6i-dma.c +5 -0
+static int sun6i_dma_alloc_chan_resources(struct dma_chan *chan)
+{
+	struct sun6i_vchan *vchan = to_sun6i_vchan(chan);
+
+	vchan->cyclic = false;

why do you need to set this here?

Signature · 1 line
~Vinod