}
 
 void idxd_dma_complete_txd(struct idxd_desc *desc,
-                          enum idxd_complete_type comp_type)
+                          enum idxd_complete_type comp_type,
+                          bool free_desc)
 {
        struct dma_async_tx_descriptor *tx;
        struct dmaengine_result res;
                tx->callback = NULL;
                tx->callback_result = NULL;
        }
+
+       if (free_desc)
+               idxd_free_desc(desc->wq, desc);
 }
 
 static void op_flag_setup(unsigned long flags, u32 *desc_flags)
        cookie = dma_cookie_assign(tx);
 
        rc = idxd_submit_desc(wq, desc);
-       if (rc < 0)
+       if (rc < 0) {
+               idxd_free_desc(wq, desc);
                return rc;
+       }
 
        return cookie;
 }
 
 void idxd_unregister_dma_channel(struct idxd_wq *wq);
 void idxd_parse_completion_status(u8 status, enum dmaengine_tx_result *res);
 void idxd_dma_complete_txd(struct idxd_desc *desc,
-                          enum idxd_complete_type comp_type);
+                          enum idxd_complete_type comp_type, bool free_desc);
 
 /* cdev */
 int idxd_cdev_register(void);
 static inline void perfmon_exit(void) {}
 #endif
 
-static inline void complete_desc(struct idxd_desc *desc, enum idxd_complete_type reason)
-{
-       idxd_dma_complete_txd(desc, reason);
-       idxd_free_desc(desc->wq, desc);
-}
-
 #endif
 
        if (!head)
                return;
 
-       llist_for_each_entry_safe(desc, itr, head, llnode) {
-               idxd_dma_complete_txd(desc, IDXD_COMPLETE_ABORT);
-               idxd_free_desc(desc->wq, desc);
-       }
+       llist_for_each_entry_safe(desc, itr, head, llnode)
+               idxd_dma_complete_txd(desc, IDXD_COMPLETE_ABORT, true);
 }
 
 static void idxd_flush_work_list(struct idxd_irq_entry *ie)
 
        list_for_each_entry_safe(desc, iter, &ie->work_list, list) {
                list_del(&desc->list);
-               idxd_dma_complete_txd(desc, IDXD_COMPLETE_ABORT);
-               idxd_free_desc(desc->wq, desc);
+               idxd_dma_complete_txd(desc, IDXD_COMPLETE_ABORT, true);
        }
 }
 
 
                         * and 0xff, which DSA_COMP_STATUS_MASK can mask out.
                         */
                        if (unlikely(desc->completion->status == IDXD_COMP_DESC_ABORT)) {
-                               complete_desc(desc, IDXD_COMPLETE_ABORT);
+                               idxd_dma_complete_txd(desc, IDXD_COMPLETE_ABORT, true);
                                continue;
                        }
 
-                       complete_desc(desc, IDXD_COMPLETE_NORMAL);
+                       idxd_dma_complete_txd(desc, IDXD_COMPLETE_NORMAL, true);
                } else {
                        spin_lock(&irq_entry->list_lock);
                        list_add_tail(&desc->list,
                 * and 0xff, which DSA_COMP_STATUS_MASK can mask out.
                 */
                if (unlikely(desc->completion->status == IDXD_COMP_DESC_ABORT)) {
-                       complete_desc(desc, IDXD_COMPLETE_ABORT);
+                       idxd_dma_complete_txd(desc, IDXD_COMPLETE_ABORT, true);
                        continue;
                }
 
-               complete_desc(desc, IDXD_COMPLETE_NORMAL);
+               idxd_dma_complete_txd(desc, IDXD_COMPLETE_NORMAL, true);
        }
 }
 
 
        spin_unlock(&ie->list_lock);
 
        if (found)
-               complete_desc(found, IDXD_COMPLETE_ABORT);
+               idxd_dma_complete_txd(found, IDXD_COMPLETE_ABORT, false);
 }
 
 int idxd_submit_desc(struct idxd_wq *wq, struct idxd_desc *desc)
        void __iomem *portal;
        int rc;
 
-       if (idxd->state != IDXD_DEV_ENABLED) {
-               idxd_free_desc(wq, desc);
+       if (idxd->state != IDXD_DEV_ENABLED)
                return -EIO;
-       }
 
-       if (!percpu_ref_tryget_live(&wq->wq_active)) {
-               idxd_free_desc(wq, desc);
+       if (!percpu_ref_tryget_live(&wq->wq_active))
                return -ENXIO;
-       }
 
        portal = idxd_wq_portal_addr(wq);
 
                        /* abort operation frees the descriptor */
                        if (ie)
                                llist_abort_desc(wq, ie, desc);
-                       else
-                               idxd_free_desc(wq, desc);
                        return rc;
                }
        }