|
@@ -129,6 +129,7 @@ static void hidma_process_completed(struct hidma_chan *mchan)
|
|
|
struct dmaengine_result result;
|
|
|
|
|
|
desc = &mdesc->desc;
|
|
|
+ last_cookie = desc->cookie;
|
|
|
|
|
|
spin_lock_irqsave(&mchan->lock, irqflags);
|
|
|
dma_cookie_complete(desc);
|
|
@@ -137,15 +138,15 @@ static void hidma_process_completed(struct hidma_chan *mchan)
|
|
|
llstat = hidma_ll_status(mdma->lldev, mdesc->tre_ch);
|
|
|
dmaengine_desc_get_callback(desc, &cb);
|
|
|
|
|
|
- last_cookie = desc->cookie;
|
|
|
dma_run_dependencies(desc);
|
|
|
|
|
|
spin_lock_irqsave(&mchan->lock, irqflags);
|
|
|
list_move(&mdesc->node, &mchan->free);
|
|
|
|
|
|
- if (llstat == DMA_COMPLETE)
|
|
|
+ if (llstat == DMA_COMPLETE) {
|
|
|
+ mchan->last_success = last_cookie;
|
|
|
result.result = DMA_TRANS_NOERROR;
|
|
|
- else
|
|
|
+ } else
|
|
|
result.result = DMA_TRANS_ABORTED;
|
|
|
|
|
|
spin_unlock_irqrestore(&mchan->lock, irqflags);
|
|
@@ -246,6 +247,19 @@ static void hidma_issue_pending(struct dma_chan *dmach)
|
|
|
hidma_ll_start(dmadev->lldev);
|
|
|
}
|
|
|
|
|
|
+static inline bool hidma_txn_is_success(dma_cookie_t cookie,
|
|
|
+ dma_cookie_t last_success, dma_cookie_t last_used)
|
|
|
+{
|
|
|
+ if (last_success <= last_used) {
|
|
|
+ if ((cookie <= last_success) || (cookie > last_used))
|
|
|
+ return true;
|
|
|
+ } else {
|
|
|
+ if ((cookie <= last_success) && (cookie > last_used))
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+}
|
|
|
+
|
|
|
static enum dma_status hidma_tx_status(struct dma_chan *dmach,
|
|
|
dma_cookie_t cookie,
|
|
|
struct dma_tx_state *txstate)
|
|
@@ -254,8 +268,13 @@ static enum dma_status hidma_tx_status(struct dma_chan *dmach,
|
|
|
enum dma_status ret;
|
|
|
|
|
|
ret = dma_cookie_status(dmach, cookie, txstate);
|
|
|
- if (ret == DMA_COMPLETE)
|
|
|
- return ret;
|
|
|
+ if (ret == DMA_COMPLETE) {
|
|
|
+ bool is_success;
|
|
|
+
|
|
|
+ is_success = hidma_txn_is_success(cookie, mchan->last_success,
|
|
|
+ dmach->cookie);
|
|
|
+ return is_success ? ret : DMA_ERROR;
|
|
|
+ }
|
|
|
|
|
|
if (mchan->paused && (ret == DMA_IN_PROGRESS)) {
|
|
|
unsigned long flags;
|
|
@@ -406,6 +425,7 @@ static int hidma_terminate_channel(struct dma_chan *chan)
|
|
|
hidma_process_completed(mchan);
|
|
|
|
|
|
spin_lock_irqsave(&mchan->lock, irqflags);
|
|
|
+ mchan->last_success = 0;
|
|
|
list_splice_init(&mchan->active, &list);
|
|
|
list_splice_init(&mchan->prepared, &list);
|
|
|
list_splice_init(&mchan->completed, &list);
|