]> Pileus Git - ~andy/linux/blobdiff - drivers/dma/pl330.c
Merge branch 'for-linus' of git://git.infradead.org/users/vkoul/slave-dma
[~andy/linux] / drivers / dma / pl330.c
index c90edecee4633c3b7d9b76777534ab424a66ac7a..73fa9b7a10ab36b05dbc54c2850325c1e1a0b566 100644 (file)
@@ -543,7 +543,9 @@ struct dma_pl330_chan {
        /* DMA-Engine Channel */
        struct dma_chan chan;
 
-       /* List of to be xfered descriptors */
+       /* List of submitted descriptors */
+       struct list_head submitted_list;
+       /* List of issued descriptors */
        struct list_head work_list;
        /* List of completed descriptors */
        struct list_head completed_list;
@@ -578,12 +580,16 @@ struct dma_pl330_dmac {
        /* DMA-Engine Device */
        struct dma_device ddma;
 
+       /* Holds info about sg limitations */
+       struct device_dma_parameters dma_parms;
+
        /* Pool of descriptors available for the DMAC's channels */
        struct list_head desc_pool;
        /* To protect desc_pool manipulation */
        spinlock_t pool_lock;
 
        /* Peripheral channels connected to this DMAC */
+       unsigned int num_peripherals;
        struct dma_pl330_chan *peripherals; /* keep at end */
 };
 
@@ -606,11 +612,6 @@ struct dma_pl330_desc {
        struct dma_pl330_chan *pchan;
 };
 
-struct dma_pl330_filter_args {
-       struct dma_pl330_dmac *pdmac;
-       unsigned int chan_id;
-};
-
 static inline void _callback(struct pl330_req *r, enum pl330_op_err err)
 {
        if (r && r->xfer_cb)
@@ -2298,16 +2299,6 @@ static void dma_pl330_rqcb(void *token, enum pl330_op_err err)
        tasklet_schedule(&pch->task);
 }
 
-static bool pl330_dt_filter(struct dma_chan *chan, void *param)
-{
-       struct dma_pl330_filter_args *fargs = param;
-
-       if (chan->device != &fargs->pdmac->ddma)
-               return false;
-
-       return (chan->chan_id == fargs->chan_id);
-}
-
 bool pl330_filter(struct dma_chan *chan, void *param)
 {
        u8 *peri_id;
@@ -2325,23 +2316,16 @@ static struct dma_chan *of_dma_pl330_xlate(struct of_phandle_args *dma_spec,
 {
        int count = dma_spec->args_count;
        struct dma_pl330_dmac *pdmac = ofdma->of_dma_data;
-       struct dma_pl330_filter_args fargs;
-       dma_cap_mask_t cap;
-
-       if (!pdmac)
-               return NULL;
+       unsigned int chan_id;
 
        if (count != 1)
                return NULL;
 
-       fargs.pdmac = pdmac;
-       fargs.chan_id = dma_spec->args[0];
-
-       dma_cap_zero(cap);
-       dma_cap_set(DMA_SLAVE, cap);
-       dma_cap_set(DMA_CYCLIC, cap);
+       chan_id = dma_spec->args[0];
+       if (chan_id >= pdmac->num_peripherals)
+               return NULL;
 
-       return dma_request_channel(cap, pl330_dt_filter, &fargs);
+       return dma_get_slave_channel(&pdmac->peripherals[chan_id].chan);
 }
 
 static int pl330_alloc_chan_resources(struct dma_chan *chan)
@@ -2385,6 +2369,11 @@ static int pl330_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, unsigned
                pl330_chan_ctrl(pch->pl330_chid, PL330_OP_FLUSH);
 
                /* Mark all desc done */
+               list_for_each_entry(desc, &pch->submitted_list, node) {
+                       desc->status = FREE;
+                       dma_cookie_complete(&desc->txd);
+               }
+
                list_for_each_entry(desc, &pch->work_list , node) {
                        desc->status = FREE;
                        dma_cookie_complete(&desc->txd);
@@ -2395,6 +2384,7 @@ static int pl330_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, unsigned
                        dma_cookie_complete(&desc->txd);
                }
 
+               list_splice_tail_init(&pch->submitted_list, &pdmac->desc_pool);
                list_splice_tail_init(&pch->work_list, &pdmac->desc_pool);
                list_splice_tail_init(&pch->completed_list, &pdmac->desc_pool);
                spin_unlock_irqrestore(&pch->lock, flags);
@@ -2453,7 +2443,14 @@ pl330_tx_status(struct dma_chan *chan, dma_cookie_t cookie,
 
 static void pl330_issue_pending(struct dma_chan *chan)
 {
-       pl330_tasklet((unsigned long) to_pchan(chan));
+       struct dma_pl330_chan *pch = to_pchan(chan);
+       unsigned long flags;
+
+       spin_lock_irqsave(&pch->lock, flags);
+       list_splice_tail_init(&pch->submitted_list, &pch->work_list);
+       spin_unlock_irqrestore(&pch->lock, flags);
+
+       pl330_tasklet((unsigned long)pch);
 }
 
 /*
@@ -2480,11 +2477,11 @@ static dma_cookie_t pl330_tx_submit(struct dma_async_tx_descriptor *tx)
 
                dma_cookie_assign(&desc->txd);
 
-               list_move_tail(&desc->node, &pch->work_list);
+               list_move_tail(&desc->node, &pch->submitted_list);
        }
 
        cookie = dma_cookie_assign(&last->txd);
-       list_add_tail(&last->node, &pch->work_list);
+       list_add_tail(&last->node, &pch->submitted_list);
        spin_unlock_irqrestore(&pch->lock, flags);
 
        return cookie;
@@ -2960,6 +2957,8 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id)
        else
                num_chan = max_t(int, pi->pcfg.num_peri, pi->pcfg.num_chan);
 
+       pdmac->num_peripherals = num_chan;
+
        pdmac->peripherals = kzalloc(num_chan * sizeof(*pch), GFP_KERNEL);
        if (!pdmac->peripherals) {
                ret = -ENOMEM;
@@ -2974,6 +2973,7 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id)
                else
                        pch->chan.private = adev->dev.of_node;
 
+               INIT_LIST_HEAD(&pch->submitted_list);
                INIT_LIST_HEAD(&pch->work_list);
                INIT_LIST_HEAD(&pch->completed_list);
                spin_lock_init(&pch->lock);
@@ -3021,6 +3021,9 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id)
                        "unable to register DMA to the generic DT DMA helpers\n");
                }
        }
+
+       adev->dev.dma_parms = &pdmac->dma_parms;
+
        /*
         * This is the limit for transfers with a buswidth of 1, larger
         * buswidths will have larger limits.