struct list_head desc_completed;
 
        struct virt_dma_desc *cyclic;
+       struct virt_dma_desc *vd_terminated;
 };
 
 static inline struct virt_dma_chan *to_virt_chan(struct dma_chan *chan)
        tasklet_schedule(&vc->task);
 }
 
+/**
+ * vchan_terminate_vdesc - Disable pending cyclic callback
+ * @vd: virtual descriptor to be terminated
+ *
+ * vc.lock must be held by caller
+ */
+static inline void vchan_terminate_vdesc(struct virt_dma_desc *vd)
+{
+       struct virt_dma_chan *vc = to_virt_chan(vd->tx.chan);
+
+       /* free up stuck descriptor */
+       if (vc->vd_terminated)
+               vchan_vdesc_fini(vc->vd_terminated);
+
+       vc->vd_terminated = vd;
+       if (vc->cyclic == vd)
+               vc->cyclic = NULL;
+}
+
 /**
  * vchan_next_desc - peek at the next descriptor to be processed
  * @vc: virtual channel to obtain descriptor from
  * Makes sure that all scheduled or active callbacks have finished running. For
  * proper operation the caller has to ensure that no new callbacks are scheduled
  * after the invocation of this function started.
+ * Free up the terminated cyclic descriptor to prevent memory leakage.
  */
 static inline void vchan_synchronize(struct virt_dma_chan *vc)
 {
+       unsigned long flags;
+
        tasklet_kill(&vc->task);
+
+       spin_lock_irqsave(&vc->lock, flags);
+       if (vc->vd_terminated) {
+               vchan_vdesc_fini(vc->vd_terminated);
+               vc->vd_terminated = NULL;
+       }
+       spin_unlock_irqrestore(&vc->lock, flags);
 }
 
 #endif