Skip to content

Commit

Permalink
dai: stop DMA unconditionally on xrun
Browse files Browse the repository at this point in the history
Stops DMA unconditionally on xrun without waiting.
Data flush is not needed as pipeline will go through
prepare and restart anyway. Waiting here during xrun
recovery with multiple tasks running causes interrupt
stack overflow. Waiti instruction lowers irq level to
0, which allows to run multiple scheduled tasks in the
same time on the same irq level and ends in DSP panic.

Signed-off-by: Tomasz Lauda <tomasz.lauda@linux.intel.com>
  • Loading branch information
tlauda committed Aug 3, 2018
1 parent ef4fc53 commit b970243
Show file tree
Hide file tree
Showing 2 changed files with 22 additions and 6 deletions.
7 changes: 6 additions & 1 deletion src/audio/dai.c
Original file line number Diff line number Diff line change
Expand Up @@ -596,7 +596,12 @@ static int dai_comp_trigger(struct comp_dev *dev, int cmd)
break;
case COMP_TRIGGER_XRUN:
dd->xrun = 1;
/* fall through */
/* stop the DAI unconditionally */
dai_trigger(dd->dai, COMP_TRIGGER_STOP, dev->params.direction);
ret = dma_stop(dd->dma, dd->chan);
if (ret < 0)
return ret;
break;
case COMP_TRIGGER_PAUSE:
case COMP_TRIGGER_STOP:
wait_init(&dd->complete);
Expand Down
21 changes: 16 additions & 5 deletions src/drivers/dw-dma.c
Original file line number Diff line number Diff line change
Expand Up @@ -484,19 +484,30 @@ static int dw_dma_pause(struct dma *dma, int channel)
static int dw_dma_stop(struct dma *dma, int channel)
{
struct dma_pdata *p = dma_get_drvdata(dma);
int ret = 0;
int ret = 0;
int i = 0;
struct dw_lli2 *lli;
uint32_t flags;

spin_lock_irq(&dma->lock, flags);

trace_dma("DDi");

/* is channel stii active ? */
if ((dw_read(dma, DW_DMA_CHAN_EN) & (0x1 << channel))) {
trace_dma_error("ea0");
trace_error_value(channel);
dw_write(dma, DW_DMA_CHAN_EN, CHAN_DISABLE(channel));

#if DW_USE_HW_LLI
for (i = 0; i < p->chan[channel].desc_count; i++) {
lli = p->chan[channel].lli;
lli->ctrl_hi &= ~DW_CTLH_DONE(1);
lli++;
}

dcache_writeback_region(p->chan[channel].lli,
sizeof(struct dw_lli2) * p->chan[channel].desc_count);
#endif

dw_write(dma, DW_CLEAR_BLOCK, 0x1 << channel);

p->chan[channel].status = COMP_STATE_PREPARE;

spin_unlock_irq(&dma->lock, flags);
Expand Down

0 comments on commit b970243

Please sign in to comment.