From bdf4bc487e18613ea944934cd827c0f47f20d1aa Mon Sep 17 00:00:00 2001 From: Tomasz Lauda Date: Sat, 26 Oct 2019 11:35:52 +0200 Subject: [PATCH] hda-dma: implement proper xrun checking Implements proper overrun and underrun detection flow. We should return error in case HDA-DMA link detects one. Signed-off-by: Tomasz Lauda --- src/drivers/intel/cavs/hda-dma.c | 33 +++++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/src/drivers/intel/cavs/hda-dma.c b/src/drivers/intel/cavs/hda-dma.c index be43b7d87..613a4d5c6 100644 --- a/src/drivers/intel/cavs/hda-dma.c +++ b/src/drivers/intel/cavs/hda-dma.c @@ -297,7 +297,6 @@ static void hda_dma_post_copy(struct dma_chan_data *chan, int bytes) static int hda_dma_link_copy_ch(struct dma_chan_data *chan, int bytes) { - uint32_t dgcs = 0; int ret = 0; tracev_hddma("hda-dmac: %d channel %d -> copy 0x%x bytes", @@ -305,11 +304,6 @@ static int hda_dma_link_copy_ch(struct dma_chan_data *chan, int bytes) hda_dma_get_dbg_vals(chan, HDA_DBG_PRE, HDA_DBG_LINK); - /* clear link xruns */ - dgcs = dma_chan_reg_read(chan, DGCS); - if (dgcs & DGCS_BOR) - dma_chan_reg_update_bits(chan, DGCS, DGCS_BOR, DGCS_BOR); - hda_dma_post_copy(chan, bytes); hda_dma_get_dbg_vals(chan, HDA_DBG_POST, HDA_DBG_LINK); @@ -791,6 +785,26 @@ static int hda_dma_remove(struct dma *dma) return 0; } +static int hda_dma_link_check_xrun(struct dma_chan_data *chan) +{ + uint32_t dgcs; + + if (chan->direction == DMA_DIR_MEM_TO_DEV || + chan->direction == DMA_DIR_DEV_TO_MEM) { + /* check for link xruns */ + dgcs = dma_chan_reg_read(chan, DGCS); + if (dgcs & DGCS_BOR) { + trace_hddma_error("hda_dma_link_check_xrun() error: " + "xrun detected"); + dma_chan_reg_update_bits(chan, DGCS, DGCS_BOR, + DGCS_BOR); + return -ENODATA; + } + } + + return 0; +} + static int hda_dma_avail_data_size(struct dma_chan_data *chan) { struct hda_chan_data *hda_chan = dma_chan_get_data(chan); @@ -847,12 +861,17 @@ static int hda_dma_data_size(struct dma_chan_data *channel, uint32_t *avail, uint32_t *free) { uint32_t flags; + int ret = 0; tracev_hddma("hda-dmac: %d channel %d -> get_data_size", channel->dma->plat_data.id, channel->index); irq_local_disable(flags); + ret = hda_dma_link_check_xrun(channel); + if (ret < 0) + return ret; + if (channel->direction == DMA_DIR_HMEM_TO_LMEM || channel->direction == DMA_DIR_DEV_TO_MEM) *avail = hda_dma_avail_data_size(channel); @@ -861,7 +880,7 @@ static int hda_dma_data_size(struct dma_chan_data *channel, irq_local_enable(flags); - return 0; + return ret; } static int hda_dma_get_attribute(struct dma *dma, uint32_t type,