[Sound-open-firmware] [PATCH v3 24/27] dw-dma: handle different cases in irq handler

Keyon Jie yang.jie at linux.intel.com
Sat Feb 11 03:18:04 CET 2017


After finished a transfer copy, check for reload channel:
1. if next.size is DMA_RELOAD_END, stop this dma copy;
2. if next.size > 0 but not DMA_RELOAD_LLI, use next
element for next copy;
3. if we are waiting for pause, pause it;
4. otherwise, reload lli.

Signed-off-by: Keyon Jie <yang.jie at linux.intel.com>
---
 src/audio/dai.c        |  2 +-
 src/audio/host.c       |  2 +-
 src/drivers/dw-dma.c   | 30 ++++++++++++++++++------------
 src/include/reef/dma.h |  7 +++++++
 4 files changed, 27 insertions(+), 14 deletions(-)

diff --git a/src/audio/dai.c b/src/audio/dai.c
index 186532f..230acbf 100644
--- a/src/audio/dai.c
+++ b/src/audio/dai.c
@@ -141,7 +141,7 @@ static void dai_dma_cb(void *data, uint32_t type, struct dma_sg_elem *next)
 			dai_cmd(dev, COMP_CMD_STOP, NULL);
 
 			/* stop dma immediatly */
-			next->size = 0;
+			next->size = DMA_RELOAD_END;
 
 			/* let any waiters know we have completed */
 			wait_completed(&dev->pipeline->complete);
diff --git a/src/audio/host.c b/src/audio/host.c
index 5c9f1ad..8f50e4f 100644
--- a/src/audio/host.c
+++ b/src/audio/host.c
@@ -220,7 +220,7 @@ static void host_dma_cb_playback(struct comp_dev *dev,
 	if (hd->host_avail < local_elem->size) {
 		if (hd->host_avail == 0) {
 			/* end of stream, stop */
-			next->size = 0;
+			next->size = DMA_RELOAD_END;
 			need_copy = 0;
 
 			/* will notify host side once dai tell us */
diff --git a/src/drivers/dw-dma.c b/src/drivers/dw-dma.c
index c073ed5..43ba230 100644
--- a/src/drivers/dw-dma.c
+++ b/src/drivers/dw-dma.c
@@ -387,7 +387,6 @@ out:
 static int dw_dma_release(struct dma *dma, int channel)
 {
 	struct dma_pdata *p = dma_get_drvdata(dma);
-	struct dma_sg_elem next;
 	uint32_t flags;
 
 	spin_lock_irq(&dma->lock, flags);
@@ -395,8 +394,6 @@ static int dw_dma_release(struct dma *dma, int channel)
 	trace_dma("Dpr");
 
 	if (p->chan[channel].status == DMA_STATUS_PAUSED) {
-		if (p->chan[channel].cb && p->chan[channel].cb_type & DMA_IRQ_TYPE_LLIST)
-			p->chan[channel].cb(p->chan[channel].cb_data, DMA_IRQ_TYPE_LLIST, &next);
 		dw_dma_chan_reload_lli(dma, channel);
 	}
 
@@ -834,20 +831,29 @@ static void dw_dma_irq_handler(void *data)
 		if ((status_tfr & mask) &&
 			(p->chan[i].cb_type & DMA_IRQ_TYPE_LLIST)) {
 
-			if (p->chan[i].status == DMA_STATUS_PAUSING) {
-				p->chan[i].status = DMA_STATUS_PAUSED;
-				continue;
-			}
-
-			next.size = 0;
+			next.size = DMA_RELOAD_LLI; /* will reload lli by default */
 			if (p->chan[i].cb)
 				p->chan[i].cb(p->chan[i].cb_data,
 					DMA_IRQ_TYPE_LLIST, &next);
 
-			/* check for reload channel */
-			if (next.size > 0)
+			/* check for reload channel:
+			 * next.size is DMA_RELOAD_END, stop this dma copy;
+			 * next.size > 0 but not DMA_RELOAD_LLI, use next
+			 * element for next copy;
+			 * if we are waiting for pause, pause it;
+			 * otherwise, reload lli
+			 */
+			if (next.size == DMA_RELOAD_END) {
+				p->chan[i].status = DMA_STATUS_IDLE;
+				continue;
+			}
+			else if (next.size != DMA_RELOAD_LLI)
 				dw_dma_chan_reload_next(dma, i, &next);
-			else
+			/* reload lli, but let's check if we are pausing first */
+			else if (p->chan[i].status == DMA_STATUS_PAUSING) {
+				p->chan[i].status = DMA_STATUS_PAUSED;
+				continue;
+			} else
 				dw_dma_chan_reload_lli(dma, i);
 		}
 #if DW_USE_HW_LLI
diff --git a/src/include/reef/dma.h b/src/include/reef/dma.h
index 6de2ede..6311260 100644
--- a/src/include/reef/dma.h
+++ b/src/include/reef/dma.h
@@ -59,6 +59,13 @@
 #define DMA_IRQ_TYPE_BLOCK	(1 << 0)
 #define DMA_IRQ_TYPE_LLIST	(1 << 1)
 
+
+/* We will use this macro in cb handler to inform dma that
+ * we need to stop the reload for specail purpose
+ */
+#define DMA_RELOAD_END	0
+#define DMA_RELOAD_LLI	0xFFFFFFFF
+
 struct dma;
 
 struct dma_sg_elem {
-- 
2.7.4



More information about the Sound-open-firmware mailing list