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 <tomasz.lauda@linux.intel.com>
This commit is contained in:
Tomasz Lauda 2019-10-26 11:35:52 +02:00 committed by Liam Girdwood
parent 78b022bfd3
commit bdf4bc487e
1 changed files with 26 additions and 7 deletions

View File

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