summary refs log tree commit diff
diff options
context:
space:
mode:
authorMario Six <mario.six@gdsys.cc>2016-03-18 14:57:19 +0100
committerVinod Koul <vinod.koul@intel.com>2016-04-04 09:50:10 -0700
commit237ec70903bcf50768138b6c663c67ef1f946cc8 (patch)
tree33e0b685d807f2ce2f1d01876981a304e9e95bdf
parentf55532a0c0b8bb6148f4e07853b876ef73bc69ca (diff)
downloadlinux-237ec70903bcf50768138b6c663c67ef1f946cc8.tar.gz
dmaengine: mpc512x: Fix hanging DMA device transfer for MPC8308
Since the MPC8308 has no external request lines to initiate DMA transfers,
all transfers must be triggered by software.

Because of this, the current implementation of DMA transfers from and to
devices on MPC8308 SoCs using major and minor loops is faulty: After the
completion of the first major loop, the DMA engine resets the start flag in
the channel's TCD, thus halting the transfer. The driver would have to set
the start bit again to trigger the next iteration of the major loop; on
MPC512x SoCs, this is done via the external request lines, so in this case,
the driver doesn't have to interfer in any way.

This has the effect that on MPC8308s, every DMA transfer to or from a
device hangs after executing the first major loop.

The patch fixes this behavior by using just one major loop for the whole
DMA transfer on MPC8308s.

Signed-off-by: Mario Six <mario.six@gdsys.cc>
Signed-off-by: Vinod Koul <vinod.koul@intel.com>
-rw-r--r--drivers/dma/mpc512x_dma.c38
1 files changed, 24 insertions, 14 deletions
diff --git a/drivers/dma/mpc512x_dma.c b/drivers/dma/mpc512x_dma.c
index aae76fb39adc..3a9104a1041c 100644
--- a/drivers/dma/mpc512x_dma.c
+++ b/drivers/dma/mpc512x_dma.c
@@ -760,21 +760,31 @@ mpc_dma_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
 		tcd->ssize = MPC_DMA_TSIZE_4;
 		tcd->dsize = MPC_DMA_TSIZE_4;
 
-		len = sg_dma_len(sg);
-		tcd->nbytes = tcd_nunits * 4;
-		if (!IS_ALIGNED(len, tcd->nbytes))
-			goto err_prep;
-
-		iter = len / tcd->nbytes;
-		if (iter >= 1 << 15) {
-			/* len is too big */
-			goto err_prep;
+		if (mdma->is_mpc8308) {
+			tcd->nbytes = sg_dma_len(sg);
+			if (!IS_ALIGNED(tcd->nbytes, 4))
+				goto err_prep;
+
+			/* No major loops for MPC8303 */
+			tcd->biter = 1;
+			tcd->citer = 1;
+		} else {
+			len = sg_dma_len(sg);
+			tcd->nbytes = tcd_nunits * 4;
+			if (!IS_ALIGNED(len, tcd->nbytes))
+				goto err_prep;
+
+			iter = len / tcd->nbytes;
+			if (iter >= 1 << 15) {
+				/* len is too big */
+				goto err_prep;
+			}
+			/* citer_linkch contains the high bits of iter */
+			tcd->biter = iter & 0x1ff;
+			tcd->biter_linkch = iter >> 9;
+			tcd->citer = tcd->biter;
+			tcd->citer_linkch = tcd->biter_linkch;
 		}
-		/* citer_linkch contains the high bits of iter */
-		tcd->biter = iter & 0x1ff;
-		tcd->biter_linkch = iter >> 9;
-		tcd->citer = tcd->biter;
-		tcd->citer_linkch = tcd->biter_linkch;
 
 		tcd->e_sg = 0;
 		tcd->d_req = 1;