Re: [2/2] dmaengine: mpc512x: add slave sg and device control operations
From: Alexander Popov <hidden>
Date: 2013-05-16 13:04:16
Also in:
lkml
Subsystem:
dma generic offload engine subsystem, the rest · Maintainers:
Vinod Koul, Linus Torvalds
Hello Anatolij, I've made SCLPC device driver use .device_prep_slave_sg() from your patch and before I send the second version of it I would like to propose some improvements:
diff --git a/drivers/dma/mpc512x_dma.c b/drivers/dma/mpc512x_dma.c
index 1c822b1..80d8633 100644
--- a/drivers/dma/mpc512x_dma.c
+++ b/drivers/dma/mpc512x_dma.c@@ -28,11 +28,6 @@ * file called COPYING. */ -/* - * This is initial version of MPC5121 DMA driver. Only memory to memory - * transfers are supported (tested using dmatest module). - */ - #include <linux/module.h> #include <linux/dmaengine.h> #include <linux/dma-mapping.h>
@@ -191,6 +186,7 @@ struct mpc_dma_chan { struct list_head completed; struct mpc_dma_tcd *tcd; dma_addr_t tcd_paddr; + u32 tcd_nunits; /* Lock for this structure */ spinlock_t lock;
@@ -276,6 +272,7 @@ static void mpc_dma_execute(struct mpc_dma_chan *mchan) mdma->tcd[cid].e_sg = 1; switch (cid) { + case 26: case 30: out_8(&mdma->regs->dmaserq, cid); break;
@@ -664,9 +661,8 @@ static struct dma_async_tx_descriptor*mpc_dma_prep_slave_sg(
struct mpc_dma_chan *mchan = dma_chan_to_mpc_dma_chan(chan);
struct mpc_dma_desc *mdesc = NULL;
struct mpc_dma_tcd *tcd;
- unsigned long flags;
+ unsigned long iflags;
struct scatterlist *sg;
- dma_addr_t dst, src;
size_t len;
int iter, i;
@@ -674,12 +670,12 @@ static struct dma_async_tx_descriptor*mpc_dma_prep_slave_sg(
return NULL;
for_each_sg(sgl, sg, sg_len, i) {
- spin_lock_irqsave(&mchan->lock, flags);
+ spin_lock_irqsave(&mchan->lock, iflags);
mdesc = list_first_entry(&mchan->free, struct mpc_dma_desc,
node);
if (!mdesc) {
- spin_unlock_irqrestore(&mchan->lock, flags);
+ spin_unlock_irqrestore(&mchan->lock, iflags);
/* try to free completed descriptors */
mpc_dma_process_completed(mdma);
return NULL;@@ -687,7 +683,7 @@ static struct dma_async_tx_descriptor*mpc_dma_prep_slave_sg(
list_del(&mdesc->node);
- spin_unlock_irqrestore(&mchan->lock, flags);
+ spin_unlock_irqrestore(&mchan->lock, iflags);
mdesc->error = 0;
tcd = mdesc->tcd;@@ -696,40 +692,43 @@ static struct dma_async_tx_descriptor*mpc_dma_prep_slave_sg(
memset(tcd, 0, sizeof(struct mpc_dma_tcd));
if (direction == DMA_DEV_TO_MEM) {
- dst = sg_dma_address(sg);
- src = mchan->per_paddr;
+ tcd->saddr = mchan->per_paddr;
+ tcd->daddr = sg_dma_address(sg);
+ tcd->soff = 0;
+ tcd->doff = 4;
} else if (direction == DMA_MEM_TO_DEV) {
- dst = mchan->per_paddr;
- src = sg_dma_address(sg);
- } else {
- return NULL;
- }
-
- len = sg_dma_len(sg);
-
- if (direction == DMA_MEM_TO_DEV) {
tcd->saddr = sg_dma_address(sg);
tcd->daddr = mchan->per_paddr;
tcd->soff = 4;
tcd->doff = 0;
} else {
- tcd->saddr = mchan->per_paddr;
- tcd->daddr = sg_dma_address(sg);
- tcd->soff = 0;
- tcd->doff = 4;
+ return NULL;
}
-
tcd->ssize = MPC_DMA_TSIZE_4;
tcd->dsize = MPC_DMA_TSIZE_4;
- tcd->nbytes = 64;
- iter = sg_dma_len(sg) / 64;
+ if (!IS_ALIGNED(sg_dma_address(sg), 4))
+ return NULL;
+
+ len = sg_dma_len(sg);
+ if (mchan->tcd_nunits)
+ tcd->nbytes = mchan->tcd_nunits * 4;
+ else
+ tcd->nbytes = 64;
- /* citer_linkch contains the high bits of iter */
- tcd->citer_linkch = iter >> 9;
- tcd->biter_linkch = iter >> 9;
- tcd->citer = iter & 0x1ff;
- tcd->biter = iter & 0x1ff;
+ if (!IS_ALIGNED(len, tcd->nbytes))
+ return NULL;
+
+ iter = len / tcd->nbytes;
+ if (iter > ((1 << 15) - 1)) { /* maximum biter */
+ return NULL; /* len is too big */
+ } else {
+ /* 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;
@@ -745,9 +744,9 @@ static struct dma_async_tx_descriptor*mpc_dma_prep_slave_sg(
}
/* Place descriptor in prepared list */
- spin_lock_irqsave(&mchan->lock, flags);
+ spin_lock_irqsave(&mchan->lock, iflags);
list_add_tail(&mdesc->node, &mchan->prepared);
- spin_unlock_irqrestore(&mchan->lock, flags);
+ spin_unlock_irqrestore(&mchan->lock, iflags);
return &mdesc->desc;
}@@ -772,10 +771,13 @@ static int mpc_dma_device_control(structdma_chan *chan, enum dma_ctrl_cmd cmd,
cfg->dst_addr_width != DMA_SLAVE_BUSWIDTH_4_BYTES)
return -EINVAL;
- if (cfg->direction == DMA_DEV_TO_MEM)
+ if (cfg->direction == DMA_DEV_TO_MEM) {
mchan->per_paddr = cfg->src_addr;
- else
+ mchan->tcd_nunits = cfg->src_maxburst;
+ } else {
mchan->per_paddr = cfg->dst_addr;
+ mchan->tcd_nunits = cfg->dst_maxburst;
+ }
return 0;
default:
2013/3/31 Anatolij Gustschin [off-list ref]:Prepare the driver to support slave sg operation.
Thanks. Best regards, Alexander