On Mon, Aug 05, 2013 at 02:07:04PM +0800, Jingchang Lu wrote:
> Add Freescale enhanced direct memory(eDMA) controller support.
> The eDMA controller deploys DMAMUXs routing DMA request sources(slot)
> to eDMA channels.
> This module can be found on Vybrid and LS-1 SoCs.
> 
> Signed-off-by: Alison Wang <b18...@freescale.com>
> Signed-off-by: Xiaochun Li <b41...@freescale.com>
> Signed-off-by: Jingchang Lu <b35...@freescale.com>
> ---

> +
> +static void fsl_edma_free_desc(struct virt_dma_desc *vdesc)
> +{
> +     struct fsl_edma_desc *fsl_desc;
> +     int i;
> +
> +     fsl_desc = to_fsl_edma_desc(vdesc);
> +     for (i = 0; i < fsl_desc->n_tcds; i++)
> +                     dma_pool_free(fsl_desc->echan->tcd_pool,
> +                                     fsl_desc->tcd[i].vtcd,
> +                                     fsl_desc->tcd[i].ptcd);
> +     kfree(fsl_desc);
should this be called with lock held or not?

> +}
> +
> +static int fsl_edma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
> +             unsigned long arg)
> +{
> +     struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan);
> +     struct dma_slave_config *cfg = (void *)arg;
> +
> +     switch (cmd) {
> +     case DMA_TERMINATE_ALL:
> +             fsl_edma_disable_request(fsl_chan);
> +             fsl_chan->edesc = NULL;
> +             vchan_free_chan_resources(&fsl_chan->vchan);
> +             return 0;
empty line here pls

> +     case DMA_SLAVE_CONFIG:
> +             fsl_chan->fsc.dir = cfg->direction;
> +             if (cfg->direction == DMA_DEV_TO_MEM) {
> +                     fsl_chan->fsc.dev_addr = cfg->src_addr;
> +                     fsl_chan->fsc.addr_width = cfg->src_addr_width;
> +                     fsl_chan->fsc.burst = cfg->src_maxburst;
> +             } else {
i would prefer you check for DMA_MEM_TO_DEV here and discard rest of the cases
if sent as error

> +                     fsl_chan->fsc.dev_addr = cfg->dst_addr;
> +                     fsl_chan->fsc.addr_width = cfg->dst_addr_width;
> +                     fsl_chan->fsc.burst = cfg->dst_maxburst;
> +             }
> +             fsl_chan->fsc.attr = 
> fsl_edma_get_tcd_attr(fsl_chan->fsc.addr_width);
> +             return 0;
> +     default:
> +             return -ENOSYS;
-ENXIO perhaps...

> +     }
> +}
> +

> +static struct fsl_edma_desc *fsl_edma_alloc_desc(struct fsl_edma_chan 
> *fsl_chan,
> +             int sg_len)
> +{
> +     struct fsl_edma_desc *fsl_desc;
> +     int size, i;
> +
> +     size = sizeof(struct fsl_edma_desc);
> +     size += sizeof(struct fsl_edma_sw_tcd) * sg_len;
> +     fsl_desc = kzalloc(size, GFP_KERNEL);
how about, kzalloc(sizeof(*fsl_desc) * sg_len, GFP_NOWAIT)
> +     if (!fsl_desc)
> +             return NULL;
> +
> +     fsl_desc->echan = fsl_chan;
> +     fsl_desc->n_tcds = sg_len;
> +     for (i = 0; i < sg_len; i++) {
> +             fsl_desc->tcd[i].vtcd = dma_pool_alloc(fsl_chan->tcd_pool,
> +                                     GFP_ATOMIC, &fsl_desc->tcd[i].ptcd);
> +             if (!fsl_desc->tcd[i].vtcd)
> +                     goto free_on_err;
> +     }
> +     return fsl_desc;
empty line here

> +free_on_err:
> +     while (--i >= 0)
> +             dma_pool_free(fsl_chan->tcd_pool, fsl_desc->tcd[i].vtcd,
> +                             fsl_desc->tcd[i].ptcd);
> +     kfree(fsl_desc);
> +     return NULL;
> +}
> +
> +static struct dma_async_tx_descriptor *fsl_edma_prep_dma_cyclic(
> +             struct dma_chan *chan, dma_addr_t dma_addr, size_t buf_len,
> +             size_t period_len, enum dma_transfer_direction direction,
> +             unsigned long flags, void *context)
> +{
> +     struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan);
> +     struct fsl_edma_desc *fsl_desc;
> +     dma_addr_t dma_buf_next;
> +     int sg_len, i;
> +     u32 src_addr, dst_addr, last_sg, nbytes;
> +     u16 soff, doff, iter;
> +
> +     sg_len = buf_len / period_len;
> +     fsl_desc = fsl_edma_alloc_desc(fsl_chan, sg_len);
> +     if (!fsl_desc)
> +             return NULL;
> +     fsl_desc->iscyclic = true;
> +
> +     dma_buf_next = dma_addr;
> +     nbytes = fsl_chan->fsc.addr_width * fsl_chan->fsc.burst;
> +     iter = period_len / nbytes;
> +     for (i = 0; i < sg_len; i++) {
> +             if (dma_buf_next >= dma_addr + buf_len)
> +                     dma_buf_next = dma_addr;
> +
> +             /* get next sg's physical address */
> +             last_sg = fsl_desc->tcd[(i + 1) % sg_len].ptcd;
> +
> +             if (fsl_chan->fsc.dir == DMA_MEM_TO_DEV) {
> +                     src_addr = dma_buf_next;
> +                     dst_addr = fsl_chan->fsc.dev_addr;
> +                     soff = fsl_chan->fsc.addr_width;
> +                     doff = 0;
> +             } else {
again check for dirrection would be apt

> +                     src_addr = fsl_chan->fsc.dev_addr;
> +                     dst_addr = dma_buf_next;
> +                     soff = 0;
> +                     doff = fsl_chan->fsc.addr_width;
> +             }
> +
> +             fill_tcd_params(fsl_desc->tcd[i].vtcd, src_addr, dst_addr,
> +                             fsl_chan->fsc.attr, soff, nbytes, 0,
> +                             iter, iter, doff, last_sg, true, false, true);
> +             dma_buf_next += period_len;
> +     }
> +
> +     return vchan_tx_prep(&fsl_chan->vchan, &fsl_desc->vdesc, flags);
> +}
> +
> +static struct dma_async_tx_descriptor *fsl_edma_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 fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan);
> +     struct fsl_edma_desc *fsl_desc;
> +     struct scatterlist *sg;
> +     u32 src_addr, dst_addr, last_sg, nbytes;
> +     u16 soff, doff, iter;
> +     int i;
> +
> +     fsl_desc = fsl_edma_alloc_desc(fsl_chan, sg_len);
> +     if (!fsl_desc)
> +             return NULL;
> +     fsl_desc->iscyclic = false;
> +
> +     nbytes = fsl_chan->fsc.addr_width * fsl_chan->fsc.burst;
> +     for_each_sg(sgl, sg, sg_len, i) {
> +             /* get next sg's physical address */
> +             last_sg = fsl_desc->tcd[(i + 1) % sg_len].ptcd;
> +
> +             if (fsl_chan->fsc.dir == DMA_MEM_TO_DEV) {
> +                     src_addr = sg_dma_address(sg);
> +                     dst_addr = fsl_chan->fsc.dev_addr;
> +                     soff = fsl_chan->fsc.addr_width;
> +                     doff = 0;
> +             } else {
ditto

> +                     src_addr = fsl_chan->fsc.dev_addr;
> +                     dst_addr = sg_dma_address(sg);
> +                     soff = 0;
> +                     doff = fsl_chan->fsc.addr_width;
> +             }
> +
> +             iter = sg_dma_len(sg) / nbytes;
> +             if (i < sg_len - 1) {
> +                     last_sg = fsl_desc->tcd[(i + 1)].ptcd;
> +                     fill_tcd_params(fsl_desc->tcd[i].vtcd, src_addr,
> +                             dst_addr, fsl_chan->fsc.attr, soff, nbytes, 0,
> +                             iter, iter, doff, last_sg, false, false, true);
> +             } else {
> +                     last_sg = 0;
> +                     fill_tcd_params(fsl_desc->tcd[i].vtcd, src_addr,
> +                             dst_addr, fsl_chan->fsc.attr, soff, nbytes, 0,
> +                             iter, iter, doff, last_sg, true, true, false);
> +             }
> +     }
> +
> +     return vchan_tx_prep(&fsl_chan->vchan, &fsl_desc->vdesc, flags);
> +}
> +

> +
> +static struct dma_chan *fsl_edma_xlate(struct of_phandle_args *dma_spec,
> +             struct of_dma *ofdma)
> +{
> +     dma_cap_mask_t mask;
> +     struct fsl_edma_filter_param fparam;
> +
> +     if (dma_spec->args_count != 2)
> +             return NULL;
> +
> +     fparam.mux_id = dma_spec->args[0];
> +     fparam.slot_id = dma_spec->args[1];
> +
> +     dma_cap_zero(mask);
> +     dma_cap_set(DMA_SLAVE, mask);
not cyclic?

> +     return dma_request_channel(mask, fsl_edma_filter_fn, (void *)&fparam);
> +}
> +

> +static int __init fsl_edma_module_init(void)
> +{
> +     return platform_driver_probe(&fsl_edma_driver, fsl_edma_probe);
> +}
> +module_init(fsl_edma_module_init);
> +
> +MODULE_DESCRIPTION("Freescale eDMA engine driver");
> +MODULE_LICENSE("GPL v2");
MODULE_ALAIS?

~Vinod
-- 
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to