dmaengine: provide a common function for completing a dma descriptor
[deliverable/linux.git] / drivers / dma / pl330.c
index 571041477ab2984230fb1d6f4f9849276f0f046f..a81d0a5f8191565c76340ed1b51dd60d0bc7d7e5 100644 (file)
@@ -19,6 +19,9 @@
 #include <linux/amba/pl330.h>
 #include <linux/pm_runtime.h>
 #include <linux/scatterlist.h>
+#include <linux/of.h>
+
+#include "dmaengine.h"
 
 #define NR_DEFAULT_DESC        16
 
@@ -50,9 +53,6 @@ struct dma_pl330_chan {
        /* DMA-Engine Channel */
        struct dma_chan chan;
 
-       /* Last completed cookie */
-       dma_cookie_t completed;
-
        /* List of to be xfered descriptors */
        struct list_head work_list;
 
@@ -116,6 +116,9 @@ struct dma_pl330_desc {
        struct dma_pl330_chan *pchan;
 };
 
+/* forward declaration */
+static struct amba_driver pl330_driver;
+
 static inline struct dma_pl330_chan *
 to_pchan(struct dma_chan *ch)
 {
@@ -230,7 +233,7 @@ static void pl330_tasklet(unsigned long data)
        /* Pick up ripe tomatoes */
        list_for_each_entry_safe(desc, _dt, &pch->work_list, node)
                if (desc->status == DONE) {
-                       pch->completed = desc->txd.cookie;
+                       dma_cookie_complete(&desc->txd);
                        list_move_tail(&desc->node, &list);
                }
 
@@ -267,6 +270,32 @@ static void dma_pl330_rqcb(void *token, enum pl330_op_err err)
        tasklet_schedule(&pch->task);
 }
 
+bool pl330_filter(struct dma_chan *chan, void *param)
+{
+       u8 *peri_id;
+
+       if (chan->device->dev->driver != &pl330_driver.drv)
+               return false;
+
+#ifdef CONFIG_OF
+       if (chan->device->dev->of_node) {
+               const __be32 *prop_value;
+               phandle phandle;
+               struct device_node *node;
+
+               prop_value = ((struct property *)param)->value;
+               phandle = be32_to_cpup(prop_value++);
+               node = of_find_node_by_phandle(phandle);
+               return ((chan->private == node) &&
+                               (chan->chan_id == be32_to_cpup(prop_value)));
+       }
+#endif
+
+       peri_id = chan->private;
+       return *peri_id == (unsigned)param;
+}
+EXPORT_SYMBOL(pl330_filter);
+
 static int pl330_alloc_chan_resources(struct dma_chan *chan)
 {
        struct dma_pl330_chan *pch = to_pchan(chan);
@@ -275,7 +304,7 @@ static int pl330_alloc_chan_resources(struct dma_chan *chan)
 
        spin_lock_irqsave(&pch->lock, flags);
 
-       pch->completed = chan->cookie = 1;
+       chan->completed_cookie = chan->cookie = 1;
        pch->cyclic = false;
 
        pch->pl330_chid = pl330_request_channel(&pdmac->pif);
@@ -320,14 +349,14 @@ static int pl330_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, unsigned
        case DMA_SLAVE_CONFIG:
                slave_config = (struct dma_slave_config *)arg;
 
-               if (slave_config->direction == DMA_TO_DEVICE) {
+               if (slave_config->direction == DMA_MEM_TO_DEV) {
                        if (slave_config->dst_addr)
                                pch->fifo_addr = slave_config->dst_addr;
                        if (slave_config->dst_addr_width)
                                pch->burst_sz = __ffs(slave_config->dst_addr_width);
                        if (slave_config->dst_maxburst)
                                pch->burst_len = slave_config->dst_maxburst;
-               } else if (slave_config->direction == DMA_FROM_DEVICE) {
+               } else if (slave_config->direction == DMA_DEV_TO_MEM) {
                        if (slave_config->src_addr)
                                pch->fifo_addr = slave_config->src_addr;
                        if (slave_config->src_addr_width)
@@ -370,7 +399,7 @@ pl330_tx_status(struct dma_chan *chan, dma_cookie_t cookie,
        dma_cookie_t last_done, last_used;
        int ret;
 
-       last_done = pch->completed;
+       last_done = chan->completed_cookie;
        last_used = chan->cookie;
 
        ret = dma_async_is_complete(cookie, last_done, last_used);
@@ -400,26 +429,16 @@ static dma_cookie_t pl330_tx_submit(struct dma_async_tx_descriptor *tx)
        spin_lock_irqsave(&pch->lock, flags);
 
        /* Assign cookies to all nodes */
-       cookie = tx->chan->cookie;
-
        while (!list_empty(&last->node)) {
                desc = list_entry(last->node.next, struct dma_pl330_desc, node);
 
-               if (++cookie < 0)
-                       cookie = 1;
-               desc->txd.cookie = cookie;
+               dma_cookie_assign(&desc->txd);
 
                list_move_tail(&desc->node, &pch->work_list);
        }
 
-       if (++cookie < 0)
-               cookie = 1;
-       last->txd.cookie = cookie;
-
+       cookie = dma_cookie_assign(&last->txd);
        list_add_tail(&last->node, &pch->work_list);
-
-       tx->chan->cookie = cookie;
-
        spin_unlock_irqrestore(&pch->lock, flags);
 
        return cookie;
@@ -497,7 +516,7 @@ pluck_desc(struct dma_pl330_dmac *pdmac)
 static struct dma_pl330_desc *pl330_get_desc(struct dma_pl330_chan *pch)
 {
        struct dma_pl330_dmac *pdmac = pch->dmac;
-       struct dma_pl330_peri *peri = pch->chan.private;
+       u8 *peri_id = pch->chan.private;
        struct dma_pl330_desc *desc;
 
        /* Pluck one desc from the pool of DMAC */
@@ -522,13 +541,7 @@ static struct dma_pl330_desc *pl330_get_desc(struct dma_pl330_chan *pch)
        desc->txd.cookie = 0;
        async_tx_ack(&desc->txd);
 
-       if (peri) {
-               desc->req.rqtype = peri->rqtype;
-               desc->req.peri = pch->chan.chan_id;
-       } else {
-               desc->req.rqtype = MEMTOMEM;
-               desc->req.peri = 0;
-       }
+       desc->req.peri = peri_id ? pch->chan.chan_id : 0;
 
        dma_async_tx_descriptor_init(&desc->txd, &pch->chan);
 
@@ -597,7 +610,7 @@ static inline int get_burst_len(struct dma_pl330_desc *desc, size_t len)
 
 static struct dma_async_tx_descriptor *pl330_prep_dma_cyclic(
                struct dma_chan *chan, dma_addr_t dma_addr, size_t len,
-               size_t period_len, enum dma_data_direction direction)
+               size_t period_len, enum dma_transfer_direction direction)
 {
        struct dma_pl330_desc *desc;
        struct dma_pl330_chan *pch = to_pchan(chan);
@@ -612,15 +625,17 @@ static struct dma_async_tx_descriptor *pl330_prep_dma_cyclic(
        }
 
        switch (direction) {
-       case DMA_TO_DEVICE:
+       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_FROM_DEVICE:
+       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;
@@ -646,16 +661,12 @@ pl330_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dst,
 {
        struct dma_pl330_desc *desc;
        struct dma_pl330_chan *pch = to_pchan(chan);
-       struct dma_pl330_peri *peri = chan->private;
        struct pl330_info *pi;
        int burst;
 
        if (unlikely(!pch || !len))
                return NULL;
 
-       if (peri && peri->rqtype != MEMTOMEM)
-               return NULL;
-
        pi = &pch->dmac->pif;
 
        desc = __pl330_prep_dma_memcpy(pch, dst, src, len);
@@ -664,6 +675,7 @@ pl330_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dst,
 
        desc->rqcfg.src_inc = 1;
        desc->rqcfg.dst_inc = 1;
+       desc->req.rqtype = MEMTOMEM;
 
        /* Select max possible burst size */
        burst = pi->pcfg.data_bus_width / 8;
@@ -687,29 +699,18 @@ pl330_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dst,
 
 static struct dma_async_tx_descriptor *
 pl330_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
-               unsigned int sg_len, enum dma_data_direction direction,
+               unsigned int sg_len, enum dma_transfer_direction direction,
                unsigned long flg)
 {
        struct dma_pl330_desc *first, *desc = NULL;
        struct dma_pl330_chan *pch = to_pchan(chan);
-       struct dma_pl330_peri *peri = chan->private;
        struct scatterlist *sg;
        unsigned long flags;
        int i;
        dma_addr_t addr;
 
-       if (unlikely(!pch || !sgl || !sg_len || !peri))
-               return NULL;
-
-       /* Make sure the direction is consistent */
-       if ((direction == DMA_TO_DEVICE &&
-                               peri->rqtype != MEMTODEV) ||
-                       (direction == DMA_FROM_DEVICE &&
-                               peri->rqtype != DEVTOMEM)) {
-               dev_err(pch->dmac->pif.dev, "%s:%d Invalid Direction\n",
-                               __func__, __LINE__);
+       if (unlikely(!pch || !sgl || !sg_len))
                return NULL;
-       }
 
        addr = pch->fifo_addr;
 
@@ -747,14 +748,16 @@ pl330_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
                else
                        list_add_tail(&desc->node, &first->node);
 
-               if (direction == DMA_TO_DEVICE) {
+               if (direction == DMA_MEM_TO_DEV) {
                        desc->rqcfg.src_inc = 1;
                        desc->rqcfg.dst_inc = 0;
+                       desc->req.rqtype = MEMTODEV;
                        fill_px(&desc->px,
                                addr, sg_dma_address(sg), sg_dma_len(sg));
                } else {
                        desc->rqcfg.src_inc = 0;
                        desc->rqcfg.dst_inc = 1;
+                       desc->req.rqtype = DEVTOMEM;
                        fill_px(&desc->px,
                                sg_dma_address(sg), addr, sg_dma_len(sg));
                }
@@ -815,22 +818,12 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id)
        if (IS_ERR(pdmac->clk)) {
                dev_err(&adev->dev, "Cannot get operation clock.\n");
                ret = -EINVAL;
-               goto probe_err1;
+               goto probe_err2;
        }
 
        amba_set_drvdata(adev, pdmac);
 
-#ifdef CONFIG_PM_RUNTIME
-       /* to use the runtime PM helper functions */
-       pm_runtime_enable(&adev->dev);
-
-       /* enable the power domain */
-       if (pm_runtime_get_sync(&adev->dev)) {
-               dev_err(&adev->dev, "failed to get runtime pm\n");
-               ret = -ENODEV;
-               goto probe_err1;
-       }
-#else
+#ifndef CONFIG_PM_RUNTIME
        /* enable dma clk */
        clk_enable(pdmac->clk);
 #endif
@@ -839,11 +832,11 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id)
        ret = request_irq(irq, pl330_irq_handler, 0,
                        dev_name(&adev->dev), pi);
        if (ret)
-               goto probe_err2;
+               goto probe_err3;
 
        ret = pl330_add(pi);
        if (ret)
-               goto probe_err3;
+               goto probe_err4;
 
        INIT_LIST_HEAD(&pdmac->desc_pool);
        spin_lock_init(&pdmac->pool_lock);
@@ -856,32 +849,16 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id)
        INIT_LIST_HEAD(&pd->channels);
 
        /* Initialize channel parameters */
-       num_chan = max(pdat ? pdat->nr_valid_peri : 0, (u8)pi->pcfg.num_chan);
+       num_chan = max(pdat ? pdat->nr_valid_peri : (u8)pi->pcfg.num_peri,
+                       (u8)pi->pcfg.num_chan);
        pdmac->peripherals = kzalloc(num_chan * sizeof(*pch), GFP_KERNEL);
 
        for (i = 0; i < num_chan; i++) {
                pch = &pdmac->peripherals[i];
-               if (pdat) {
-                       struct dma_pl330_peri *peri = &pdat->peri[i];
-
-                       switch (peri->rqtype) {
-                       case MEMTOMEM:
-                               dma_cap_set(DMA_MEMCPY, pd->cap_mask);
-                               break;
-                       case MEMTODEV:
-                       case DEVTOMEM:
-                               dma_cap_set(DMA_SLAVE, pd->cap_mask);
-                               dma_cap_set(DMA_CYCLIC, pd->cap_mask);
-                               break;
-                       default:
-                               dev_err(&adev->dev, "DEVTODEV Not Supported\n");
-                               continue;
-                       }
-                       pch->chan.private = peri;
-               } else {
-                       dma_cap_set(DMA_MEMCPY, pd->cap_mask);
-                       pch->chan.private = NULL;
-               }
+               if (!adev->dev.of_node)
+                       pch->chan.private = pdat ? &pdat->peri_id[i] : NULL;
+               else
+                       pch->chan.private = adev->dev.of_node;
 
                INIT_LIST_HEAD(&pch->work_list);
                spin_lock_init(&pch->lock);
@@ -894,6 +871,15 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id)
        }
 
        pd->dev = &adev->dev;
+       if (pdat) {
+               pd->cap_mask = pdat->cap_mask;
+       } else {
+               dma_cap_set(DMA_MEMCPY, pd->cap_mask);
+               if (pi->pcfg.num_peri) {
+                       dma_cap_set(DMA_SLAVE, pd->cap_mask);
+                       dma_cap_set(DMA_CYCLIC, pd->cap_mask);
+               }
+       }
 
        pd->device_alloc_chan_resources = pl330_alloc_chan_resources;
        pd->device_free_chan_resources = pl330_free_chan_resources;
@@ -907,7 +893,7 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id)
        ret = dma_async_device_register(pd);
        if (ret) {
                dev_err(&adev->dev, "unable to register DMAC\n");
-               goto probe_err4;
+               goto probe_err5;
        }
 
        dev_info(&adev->dev,
@@ -920,10 +906,15 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id)
 
        return 0;
 
-probe_err4:
+probe_err5:
        pl330_del(pi);
-probe_err3:
+probe_err4:
        free_irq(irq, pi);
+probe_err3:
+#ifndef CONFIG_PM_RUNTIME
+       clk_disable(pdmac->clk);
+#endif
+       clk_put(pdmac->clk);
 probe_err2:
        iounmap(pi->base);
 probe_err1:
@@ -970,10 +961,7 @@ static int __devexit pl330_remove(struct amba_device *adev)
        res = &adev->res;
        release_mem_region(res->start, resource_size(res));
 
-#ifdef CONFIG_PM_RUNTIME
-       pm_runtime_put(&adev->dev);
-       pm_runtime_disable(&adev->dev);
-#else
+#ifndef CONFIG_PM_RUNTIME
        clk_disable(pdmac->clk);
 #endif
 
@@ -990,6 +978,8 @@ static struct amba_id pl330_ids[] = {
        { 0, 0 },
 };
 
+MODULE_DEVICE_TABLE(amba, pl330_ids);
+
 #ifdef CONFIG_PM_RUNTIME
 static int pl330_runtime_suspend(struct device *dev)
 {
This page took 0.028771 seconds and 5 git commands to generate.