[PATCH RFC v12 3/7] dma: mpc512x: add support for peripheral transfers

Alexander Popov a13xp0p0v88 at gmail.com
Thu May 8 19:49:20 EST 2014


Hello, Vinod.
Thanks for your feedback.

2014-05-02 21:03 GMT+04:00 Vinod Koul <vinod.koul at intel.com>:
> On Wed, Apr 23, 2014 at 05:53:25PM +0400, Alexander Popov wrote:
>> +static struct dma_async_tx_descriptor *
>> +mpc_dma_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
>> +             unsigned int sg_len, enum dma_transfer_direction direction,
>> +             unsigned long flags, void *context)
>> +{
>> +     struct mpc_dma *mdma = dma_chan_to_mpc_dma(chan);
>> +     struct mpc_dma_chan *mchan = dma_chan_to_mpc_dma_chan(chan);
>> +     struct mpc_dma_desc *mdesc = NULL;
>> +     dma_addr_t per_paddr;
>> +     u32 tcd_nunits;
>> +     struct mpc_dma_tcd *tcd;
>> +     unsigned long iflags;
>> +     struct scatterlist *sg;
>> +     size_t len;
>> +     int iter, i;
>> +
>> +     /* Currently there is no proper support for scatter/gather */
> Why? Is this HW or SW limitation?
This is the software limitation.

As Gerhard noticed, unfortunately the Linux DMA API combines
peripheral access with scatter/gather function.

But the original MPC512x DMA driver already uses scatter/gather feature
of the hardware for chaining together individual mpc_dma_desc's
in mpc_dma_execute() while mpc_dma_desc itself cannot use
scatter/gather feature, because each mpc_dma_desc is associated
with exactly one mpc_dma_tcd.

>> +             if (direction == DMA_DEV_TO_MEM) {
>> +                     tcd->saddr = per_paddr;
>> +                     tcd->daddr = sg_dma_address(sg);
>> +                     tcd->soff = 0;
>> +                     tcd->doff = 4;
> what are these?
SOFF is source address signed offset. It is applied to the current
source address to form the next-state value as each source read is completed.
DOFF is destination address signed offset.

>> +     case DMA_TERMINATE_ALL:
>> +             /* Disable channel requests */
>> +             mdma = dma_chan_to_mpc_dma(chan);
>> +
>> +             spin_lock_irqsave(&mchan->lock, flags);
>> +
>> +             out_8(&mdma->regs->dmacerq, chan->chan_id);
>> +             list_splice_tail_init(&mchan->prepared, &mchan->free);
>> +             list_splice_tail_init(&mchan->queued, &mchan->free);
>> +             list_splice_tail_init(&mchan->active, &mchan->free);
>> +
>> +             spin_unlock_irqrestore(&mchan->lock, flags);
>> +
>> +             return 0;
> empty line after this pls
ok

>> +     case DMA_SLAVE_CONFIG:
>> +             /*
>> +              * Constraints:
>> +              *  - only transfers between a peripheral device and
>> +              *     memory are supported;
>> +              *  - minimal transfer chunk is 4 bytes and consequently
>> +              *     source and destination addresses must be 4-byte aligned
>> +              *     and transfer size must be aligned on (4 * maxburst)
>> +              *     boundary;
>> +              *  - during the transfer RAM address is being incremented by
>> +              *     the size of minimal transfer chunk;
>> +              *  - peripheral port's address is constant during the transfer.
>> +              */
>> +
>> +             cfg = (void *)arg;
>> +
>> +             if (cfg->src_addr_width != DMA_SLAVE_BUSWIDTH_4_BYTES ||
>> +                 cfg->dst_addr_width != DMA_SLAVE_BUSWIDTH_4_BYTES ||
> and why this limtation, doesnt seem covered above?
I created this limitation because FIFO registers of LPC and SDHC
support _only_ 4-byte access.

I tried to cover this limitation in the statement "minimal transfer chunk
is 4 bytes". Should I make it more explicit?

>> +                 !IS_ALIGNED(cfg->src_addr, 4) ||
>> +                 !IS_ALIGNED(cfg->dst_addr, 4)) {
>> +                     return -EINVAL;
>> +             }
>> +
>> +             spin_lock_irqsave(&mchan->lock, flags);
>> +
>> +             mchan->src_per_paddr = cfg->src_addr;
>> +             mchan->src_tcd_nunits = cfg->src_maxburst;
>> +             mchan->dst_per_paddr = cfg->dst_addr;
>> +             mchan->dst_tcd_nunits = cfg->dst_maxburst;
>> +
>> +             /* Apply defaults */
>> +             if (mchan->src_tcd_nunits == 0)
>> +                     mchan->src_tcd_nunits = 1;
>> +             if (mchan->dst_tcd_nunits == 0)
>> +                     mchan->dst_tcd_nunits = 1;
>> +
>> +             spin_unlock_irqrestore(&mchan->lock, flags);
>> +
>> +             return 0;
> empty line here too
ok

Best regards,
Alexander


More information about the Linuxppc-dev mailing list