Skip to content

Commit b970243

Browse files
committed
dai: stop DMA unconditionally on xrun
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>
1 parent ef4fc53 commit b970243

File tree

2 files changed

+22
-6
lines changed

2 files changed

+22
-6
lines changed

src/audio/dai.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -596,7 +596,12 @@ static int dai_comp_trigger(struct comp_dev *dev, int cmd)
596596
break;
597597
case COMP_TRIGGER_XRUN:
598598
dd->xrun = 1;
599-
/* fall through */
599+
/* stop the DAI unconditionally */
600+
dai_trigger(dd->dai, COMP_TRIGGER_STOP, dev->params.direction);
601+
ret = dma_stop(dd->dma, dd->chan);
602+
if (ret < 0)
603+
return ret;
604+
break;
600605
case COMP_TRIGGER_PAUSE:
601606
case COMP_TRIGGER_STOP:
602607
wait_init(&dd->complete);

src/drivers/dw-dma.c

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -484,19 +484,30 @@ static int dw_dma_pause(struct dma *dma, int channel)
484484
static int dw_dma_stop(struct dma *dma, int channel)
485485
{
486486
struct dma_pdata *p = dma_get_drvdata(dma);
487-
int ret = 0;
487+
int ret = 0;
488+
int i = 0;
489+
struct dw_lli2 *lli;
488490
uint32_t flags;
489491

490492
spin_lock_irq(&dma->lock, flags);
491493

492494
trace_dma("DDi");
493495

494-
/* is channel stii active ? */
495-
if ((dw_read(dma, DW_DMA_CHAN_EN) & (0x1 << channel))) {
496-
trace_dma_error("ea0");
497-
trace_error_value(channel);
496+
dw_write(dma, DW_DMA_CHAN_EN, CHAN_DISABLE(channel));
497+
498+
#if DW_USE_HW_LLI
499+
for (i = 0; i < p->chan[channel].desc_count; i++) {
500+
lli = p->chan[channel].lli;
501+
lli->ctrl_hi &= ~DW_CTLH_DONE(1);
502+
lli++;
498503
}
499504

505+
dcache_writeback_region(p->chan[channel].lli,
506+
sizeof(struct dw_lli2) * p->chan[channel].desc_count);
507+
#endif
508+
509+
dw_write(dma, DW_CLEAR_BLOCK, 0x1 << channel);
510+
500511
p->chan[channel].status = COMP_STATE_PREPARE;
501512

502513
spin_unlock_irq(&dma->lock, flags);

0 commit comments

Comments
 (0)