diff mbox

[060/133] dma: pl330: Fix cyclic transfers

Message ID 1376692475-28413-61-git-send-email-kamal@canonical.com
State New
Headers show

Commit Message

Kamal Mostafa Aug. 16, 2013, 10:33 p.m. UTC
3.8.13.7 -stable review patch.  If anyone has any objections, please let me know.

------------------

From: Lars-Peter Clausen <lars@metafoo.de>

commit fc51446021f42aca8906e701fc2292965aafcb15 upstream.

Allocate a descriptor for each period of a cyclic transfer, not just the first.
Also since the callback needs to be called for each finished period make sure to
initialize the callback and callback_param fields of each descriptor in a cyclic
transfer.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Signed-off-by: Vinod Koul <vinod.koul@intel.com>
Signed-off-by: Kamal Mostafa <kamal@canonical.com>
---
 drivers/dma/pl330.c | 93 ++++++++++++++++++++++++++++++++++++++---------------
 1 file changed, 67 insertions(+), 26 deletions(-)

Comments

Kamal Mostafa Aug. 21, 2013, 7:40 p.m. UTC | #1
On Fri, 2013-08-16 at 15:33 -0700, Kamal Mostafa wrote:
> 3.8.13.7 -stable review patch.  If anyone has any objections, please let me know.


Actually, I'm dropping this patch from 3.8-stable pending resolution of
the "flags parameter" bug found by Luis and Lars in this earlier stable@
thread:

> Subject: Patch "dma: pl330: Fix cyclic transfers" has been added
>          to the 3.4-stable tree
> > 
> >  * function pl330_prep_dma_cyclic() signature doesn't contain the
> >    'flags' parameter introduced by commit
> >    ec8b5e48c03790a68cb875fe5064007a9cbdfdd0
> >
> Hm, that's actually a bug in the original patch. spin_lock_irqsave()
> should
> not be using the flags parameter, but instead a variable placed on the
> stack. Things will still work by using the parameter, but it's not
> exactly
> how things are supposed to be done.
> - Lars

As Greg mentioned before, if someone wants to re-submit a fixed version
of this we'd take it for stable 3.4 through 3.8.

 -Kamal



> ------------------
> 
> From: Lars-Peter Clausen <lars@metafoo.de>
> 
> commit fc51446021f42aca8906e701fc2292965aafcb15 upstream.
> 
> Allocate a descriptor for each period of a cyclic transfer, not just the first.
> Also since the callback needs to be called for each finished period make sure to
> initialize the callback and callback_param fields of each descriptor in a cyclic
> transfer.
> 
> Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
> Signed-off-by: Vinod Koul <vinod.koul@intel.com>
> Signed-off-by: Kamal Mostafa <kamal@canonical.com>
> ---
>  drivers/dma/pl330.c | 93 ++++++++++++++++++++++++++++++++++++++---------------
>  1 file changed, 67 insertions(+), 26 deletions(-)
> 
> diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c
> index 4bed3f1..9cfe424 100644
> --- a/drivers/dma/pl330.c
> +++ b/drivers/dma/pl330.c
> @@ -2501,6 +2501,10 @@ static dma_cookie_t pl330_tx_submit(struct dma_async_tx_descriptor *tx)
>  	/* Assign cookies to all nodes */
>  	while (!list_empty(&last->node)) {
>  		desc = list_entry(last->node.next, struct dma_pl330_desc, node);
> +		if (pch->cyclic) {
> +			desc->txd.callback = last->txd.callback;
> +			desc->txd.callback_param = last->txd.callback_param;
> +		}
>  
>  		dma_cookie_assign(&desc->txd);
>  
> @@ -2684,45 +2688,82 @@ static struct dma_async_tx_descriptor *pl330_prep_dma_cyclic(
>  		size_t period_len, enum dma_transfer_direction direction,
>  		unsigned long flags, void *context)
>  {
> -	struct dma_pl330_desc *desc;
> +	struct dma_pl330_desc *desc = NULL, *first = NULL;
>  	struct dma_pl330_chan *pch = to_pchan(chan);
> +	struct dma_pl330_dmac *pdmac = pch->dmac;
> +	unsigned int i;
>  	dma_addr_t dst;
>  	dma_addr_t src;
>  
> -	desc = pl330_get_desc(pch);
> -	if (!desc) {
> -		dev_err(pch->dmac->pif.dev, "%s:%d Unable to fetch desc\n",
> -			__func__, __LINE__);
> +	if (len % period_len != 0)
>  		return NULL;
> -	}
>  
> -	switch (direction) {
> -	case DMA_MEM_TO_DEV:
> -		desc->rqcfg.src_inc = 1;
> -		desc->rqcfg.dst_inc = 0;
> -		desc->req.rqtype = MEMTODEV;
> -		src = dma_addr;
> -		dst = pch->fifo_addr;
> -		break;
> -	case DMA_DEV_TO_MEM:
> -		desc->rqcfg.src_inc = 0;
> -		desc->rqcfg.dst_inc = 1;
> -		desc->req.rqtype = DEVTOMEM;
> -		src = pch->fifo_addr;
> -		dst = dma_addr;
> -		break;
> -	default:
> +	if (!is_slave_direction(direction)) {
>  		dev_err(pch->dmac->pif.dev, "%s:%d Invalid dma direction\n",
>  		__func__, __LINE__);
>  		return NULL;
>  	}
>  
> -	desc->rqcfg.brst_size = pch->burst_sz;
> -	desc->rqcfg.brst_len = 1;
> +	for (i = 0; i < len / period_len; i++) {
> +		desc = pl330_get_desc(pch);
> +		if (!desc) {
> +			dev_err(pch->dmac->pif.dev, "%s:%d Unable to fetch desc\n",
> +				__func__, __LINE__);
>  
> -	pch->cyclic = true;
> +			if (!first)
> +				return NULL;
> +
> +			spin_lock_irqsave(&pdmac->pool_lock, flags);
> +
> +			while (!list_empty(&first->node)) {
> +				desc = list_entry(first->node.next,
> +						struct dma_pl330_desc, node);
> +				list_move_tail(&desc->node, &pdmac->desc_pool);
> +			}
> +
> +			list_move_tail(&first->node, &pdmac->desc_pool);
>  
> -	fill_px(&desc->px, dst, src, period_len);
> +			spin_unlock_irqrestore(&pdmac->pool_lock, flags);
> +
> +			return NULL;
> +		}
> +
> +		switch (direction) {
> +		case DMA_MEM_TO_DEV:
> +			desc->rqcfg.src_inc = 1;
> +			desc->rqcfg.dst_inc = 0;
> +			desc->req.rqtype = MEMTODEV;
> +			src = dma_addr;
> +			dst = pch->fifo_addr;
> +			break;
> +		case DMA_DEV_TO_MEM:
> +			desc->rqcfg.src_inc = 0;
> +			desc->rqcfg.dst_inc = 1;
> +			desc->req.rqtype = DEVTOMEM;
> +			src = pch->fifo_addr;
> +			dst = dma_addr;
> +			break;
> +		default:
> +			break;
> +		}
> +
> +		desc->rqcfg.brst_size = pch->burst_sz;
> +		desc->rqcfg.brst_len = 1;
> +		fill_px(&desc->px, dst, src, period_len);
> +
> +		if (!first)
> +			first = desc;
> +		else
> +			list_add_tail(&desc->node, &first->node);
> +
> +		dma_addr += period_len;
> +	}
> +
> +	if (!desc)
> +		return NULL;
> +
> +	pch->cyclic = true;
> +	desc->txd.flags = flags;
>  
>  	return &desc->txd;
>  }
diff mbox

Patch

diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c
index 4bed3f1..9cfe424 100644
--- a/drivers/dma/pl330.c
+++ b/drivers/dma/pl330.c
@@ -2501,6 +2501,10 @@  static dma_cookie_t pl330_tx_submit(struct dma_async_tx_descriptor *tx)
 	/* Assign cookies to all nodes */
 	while (!list_empty(&last->node)) {
 		desc = list_entry(last->node.next, struct dma_pl330_desc, node);
+		if (pch->cyclic) {
+			desc->txd.callback = last->txd.callback;
+			desc->txd.callback_param = last->txd.callback_param;
+		}
 
 		dma_cookie_assign(&desc->txd);
 
@@ -2684,45 +2688,82 @@  static struct dma_async_tx_descriptor *pl330_prep_dma_cyclic(
 		size_t period_len, enum dma_transfer_direction direction,
 		unsigned long flags, void *context)
 {
-	struct dma_pl330_desc *desc;
+	struct dma_pl330_desc *desc = NULL, *first = NULL;
 	struct dma_pl330_chan *pch = to_pchan(chan);
+	struct dma_pl330_dmac *pdmac = pch->dmac;
+	unsigned int i;
 	dma_addr_t dst;
 	dma_addr_t src;
 
-	desc = pl330_get_desc(pch);
-	if (!desc) {
-		dev_err(pch->dmac->pif.dev, "%s:%d Unable to fetch desc\n",
-			__func__, __LINE__);
+	if (len % period_len != 0)
 		return NULL;
-	}
 
-	switch (direction) {
-	case DMA_MEM_TO_DEV:
-		desc->rqcfg.src_inc = 1;
-		desc->rqcfg.dst_inc = 0;
-		desc->req.rqtype = MEMTODEV;
-		src = dma_addr;
-		dst = pch->fifo_addr;
-		break;
-	case DMA_DEV_TO_MEM:
-		desc->rqcfg.src_inc = 0;
-		desc->rqcfg.dst_inc = 1;
-		desc->req.rqtype = DEVTOMEM;
-		src = pch->fifo_addr;
-		dst = dma_addr;
-		break;
-	default:
+	if (!is_slave_direction(direction)) {
 		dev_err(pch->dmac->pif.dev, "%s:%d Invalid dma direction\n",
 		__func__, __LINE__);
 		return NULL;
 	}
 
-	desc->rqcfg.brst_size = pch->burst_sz;
-	desc->rqcfg.brst_len = 1;
+	for (i = 0; i < len / period_len; i++) {
+		desc = pl330_get_desc(pch);
+		if (!desc) {
+			dev_err(pch->dmac->pif.dev, "%s:%d Unable to fetch desc\n",
+				__func__, __LINE__);
 
-	pch->cyclic = true;
+			if (!first)
+				return NULL;
+
+			spin_lock_irqsave(&pdmac->pool_lock, flags);
+
+			while (!list_empty(&first->node)) {
+				desc = list_entry(first->node.next,
+						struct dma_pl330_desc, node);
+				list_move_tail(&desc->node, &pdmac->desc_pool);
+			}
+
+			list_move_tail(&first->node, &pdmac->desc_pool);
 
-	fill_px(&desc->px, dst, src, period_len);
+			spin_unlock_irqrestore(&pdmac->pool_lock, flags);
+
+			return NULL;
+		}
+
+		switch (direction) {
+		case DMA_MEM_TO_DEV:
+			desc->rqcfg.src_inc = 1;
+			desc->rqcfg.dst_inc = 0;
+			desc->req.rqtype = MEMTODEV;
+			src = dma_addr;
+			dst = pch->fifo_addr;
+			break;
+		case DMA_DEV_TO_MEM:
+			desc->rqcfg.src_inc = 0;
+			desc->rqcfg.dst_inc = 1;
+			desc->req.rqtype = DEVTOMEM;
+			src = pch->fifo_addr;
+			dst = dma_addr;
+			break;
+		default:
+			break;
+		}
+
+		desc->rqcfg.brst_size = pch->burst_sz;
+		desc->rqcfg.brst_len = 1;
+		fill_px(&desc->px, dst, src, period_len);
+
+		if (!first)
+			first = desc;
+		else
+			list_add_tail(&desc->node, &first->node);
+
+		dma_addr += period_len;
+	}
+
+	if (!desc)
+		return NULL;
+
+	pch->cyclic = true;
+	desc->txd.flags = flags;
 
 	return &desc->txd;
 }