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@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 {