static struct sf_pdma_desc *sf_pdma_alloc_desc(struct sf_pdma_chan *chan)
 {
        struct sf_pdma_desc *desc;
-       unsigned long flags;
-
-       spin_lock_irqsave(&chan->lock, flags);
-
-       if (chan->desc && !chan->desc->in_use) {
-               spin_unlock_irqrestore(&chan->lock, flags);
-               return chan->desc;
-       }
-
-       spin_unlock_irqrestore(&chan->lock, flags);
 
        desc = kzalloc(sizeof(*desc), GFP_NOWAIT);
        if (!desc)
        desc->async_tx = vchan_tx_prep(&chan->vchan, &desc->vdesc, flags);
 
        spin_lock_irqsave(&chan->vchan.lock, iflags);
-       chan->desc = desc;
        sf_pdma_fill_desc(desc, dest, src, len);
        spin_unlock_irqrestore(&chan->vchan.lock, iflags);
 
        unsigned long flags;
        u64 residue = 0;
        struct sf_pdma_desc *desc;
-       struct dma_async_tx_descriptor *tx;
+       struct dma_async_tx_descriptor *tx = NULL;
 
        spin_lock_irqsave(&chan->vchan.lock, flags);
 
-       tx = &chan->desc->vdesc.tx;
+       list_for_each_entry(vd, &chan->vchan.desc_submitted, node)
+               if (vd->tx.cookie == cookie)
+                       tx = &vd->tx;
+
+       if (!tx)
+               goto out;
+
        if (cookie == tx->chan->completed_cookie)
                goto out;
 
        writel(v, regs->ctrl);
 }
 
+static struct sf_pdma_desc *sf_pdma_get_first_pending_desc(struct sf_pdma_chan *chan)
+{
+       struct virt_dma_chan *vchan = &chan->vchan;
+       struct virt_dma_desc *vdesc;
+
+       if (list_empty(&vchan->desc_issued))
+               return NULL;
+
+       vdesc = list_first_entry(&vchan->desc_issued, struct virt_dma_desc, node);
+
+       return container_of(vdesc, struct sf_pdma_desc, vdesc);
+}
+
 static void sf_pdma_xfer_desc(struct sf_pdma_chan *chan)
 {
        struct sf_pdma_desc *desc = chan->desc;
 
        spin_lock_irqsave(&chan->vchan.lock, flags);
 
-       if (vchan_issue_pending(&chan->vchan) && chan->desc)
+       if (!chan->desc && vchan_issue_pending(&chan->vchan)) {
+               /* vchan_issue_pending has made a check that desc in not NULL */
+               chan->desc = sf_pdma_get_first_pending_desc(chan);
                sf_pdma_xfer_desc(chan);
+       }
 
        spin_unlock_irqrestore(&chan->vchan.lock, flags);
 }
        spin_lock_irqsave(&chan->vchan.lock, flags);
        list_del(&chan->desc->vdesc.node);
        vchan_cookie_complete(&chan->desc->vdesc);
+
+       chan->desc = sf_pdma_get_first_pending_desc(chan);
+       if (chan->desc)
+               sf_pdma_xfer_desc(chan);
+
        spin_unlock_irqrestore(&chan->vchan.lock, flags);
 }