]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
dmaengine: edma: Simplify and optimize the edma_execute path
authorPeter Ujfalusi <peter.ujfalusi@ti.com>
Wed, 14 Oct 2015 11:42:45 +0000 (14:42 +0300)
committerVinod Koul <vinod.koul@intel.com>
Wed, 14 Oct 2015 14:27:10 +0000 (19:57 +0530)
The code path in edma_execute() and edma_callback() can be simplified
and make it more optimal.
There is not need to call in to edma_execute() when the transfer
has been finished for example.
Also the handling of missed/first or next batch of paRAMs can
be done in a more optimal way.

Signed-off-by: Peter Ujfalusi <peter.ujfalusi@ti.com>
Signed-off-by: Vinod Koul <vinod.koul@intel.com>
drivers/dma/edma.c

index 3e5d4f193005362bf0fd672a57ed7f1a2765af78..19fa49d6f5551c249346da5edae328c2e85a2bae 100644 (file)
@@ -154,15 +154,11 @@ static void edma_execute(struct edma_chan *echan)
        struct device *dev = echan->vchan.chan.device->dev;
        int i, j, left, nslots;
 
-       /* If either we processed all psets or we're still not started */
-       if (!echan->edesc ||
-           echan->edesc->pset_nr == echan->edesc->processed) {
-               /* Get next vdesc */
+       if (!echan->edesc) {
+               /* Setup is needed for the first transfer */
                vdesc = vchan_next_desc(&echan->vchan);
-               if (!vdesc) {
-                       echan->edesc = NULL;
+               if (!vdesc)
                        return;
-               }
                list_del(&vdesc->node);
                echan->edesc = to_edma_desc(&vdesc->tx);
        }
@@ -220,28 +216,26 @@ static void edma_execute(struct edma_chan *echan)
                                  echan->ecc->dummy_slot);
        }
 
-       if (edesc->processed <= MAX_NR_SG) {
-               dev_dbg(dev, "first transfer starting on channel %d\n",
-                       echan->ch_num);
-               edma_start(echan->ch_num);
-       } else {
-               dev_dbg(dev, "chan: %d: completed %d elements, resuming\n",
-                       echan->ch_num, edesc->processed);
-               edma_resume(echan->ch_num);
-       }
-
-       /*
-        * This happens due to setup times between intermediate transfers
-        * in long SG lists which have to be broken up into transfers of
-        * MAX_NR_SG
-        */
        if (echan->missed) {
+               /*
+                * This happens due to setup times between intermediate
+                * transfers in long SG lists which have to be broken up into
+                * transfers of MAX_NR_SG
+                */
                dev_dbg(dev, "missed event on channel %d\n", echan->ch_num);
                edma_clean_channel(echan->ch_num);
                edma_stop(echan->ch_num);
                edma_start(echan->ch_num);
                edma_trigger_channel(echan->ch_num);
                echan->missed = 0;
+       } else if (edesc->processed <= MAX_NR_SG) {
+               dev_dbg(dev, "first transfer starting on channel %d\n",
+                       echan->ch_num);
+               edma_start(echan->ch_num);
+       } else {
+               dev_dbg(dev, "chan: %d: completed %d elements, resuming\n",
+                       echan->ch_num, edesc->processed);
+               edma_resume(echan->ch_num);
        }
 }
 
@@ -259,20 +253,17 @@ static int edma_terminate_all(struct dma_chan *chan)
         * echan->edesc is NULL and exit.)
         */
        if (echan->edesc) {
-               int cyclic = echan->edesc->cyclic;
-
+               edma_stop(echan->ch_num);
+               /* Move the cyclic channel back to default queue */
+               if (echan->edesc->cyclic)
+                       edma_assign_channel_eventq(echan->ch_num,
+                                                  EVENTQ_DEFAULT);
                /*
                 * free the running request descriptor
                 * since it is not in any of the vdesc lists
                 */
                edma_desc_free(&echan->edesc->vdesc);
-
                echan->edesc = NULL;
-               edma_stop(echan->ch_num);
-               /* Move the cyclic channel back to default queue */
-               if (cyclic)
-                       edma_assign_channel_eventq(echan->ch_num,
-                                                  EVENTQ_DEFAULT);
        }
 
        vchan_get_all_descriptors(&echan->vchan, &head);
@@ -725,41 +716,33 @@ static void edma_callback(unsigned ch_num, u16 ch_status, void *data)
 
        edesc = echan->edesc;
 
-       /* Pause the channel for non-cyclic */
-       if (!edesc || (edesc && !edesc->cyclic))
-               edma_pause(echan->ch_num);
-
+       spin_lock(&echan->vchan.lock);
        switch (ch_status) {
        case EDMA_DMA_COMPLETE:
-               spin_lock(&echan->vchan.lock);
-
                if (edesc) {
                        if (edesc->cyclic) {
                                vchan_cyclic_callback(&edesc->vdesc);
+                               goto out;
                        } else if (edesc->processed == edesc->pset_nr) {
                                dev_dbg(dev, "Transfer complete, stopping channel %d\n", ch_num);
                                edesc->residue = 0;
                                edma_stop(echan->ch_num);
                                vchan_cookie_complete(&edesc->vdesc);
-                               edma_execute(echan);
+                               echan->edesc = NULL;
                        } else {
                                dev_dbg(dev, "Intermediate transfer complete on channel %d\n", ch_num);
 
+                               edma_pause(echan->ch_num);
+
                                /* Update statistics for tx_status */
                                edesc->residue -= edesc->sg_len;
                                edesc->residue_stat = edesc->residue;
                                edesc->processed_stat = edesc->processed;
-
-                               edma_execute(echan);
                        }
+                       edma_execute(echan);
                }
-
-               spin_unlock(&echan->vchan.lock);
-
                break;
        case EDMA_DMA_CC_ERROR:
-               spin_lock(&echan->vchan.lock);
-
                edma_read_slot(EDMA_CHAN_SLOT(echan->slot[0]), &p);
 
                /*
@@ -788,13 +771,12 @@ static void edma_callback(unsigned ch_num, u16 ch_status, void *data)
                        edma_start(echan->ch_num);
                        edma_trigger_channel(echan->ch_num);
                }
-
-               spin_unlock(&echan->vchan.lock);
-
                break;
        default:
                break;
        }
+out:
+       spin_unlock(&echan->vchan.lock);
 }
 
 /* Alloc channel resources */