dai: refactor xrun checking

Refactors code for underrun and overrun detection. We should report
an xrun only if DMA get data size or DMA copy fails. In other case
even 0 available copy bytes doesn't mean anything, because we are always
copying as much as possible. Buffer could potentially be filled up front.

Signed-off-by: Tomasz Lauda <tomasz.lauda@linux.intel.com>
This commit is contained in:
Tomasz Lauda 2019-10-26 11:50:25 +02:00 committed by Liam Girdwood
parent c7ca517461
commit 15201664ca
1 changed files with 18 additions and 25 deletions

View File

@ -598,34 +598,24 @@ static int dai_comp_trigger(struct comp_dev *dev, int cmd)
return ret;
}
/* check if xrun occurred */
static int dai_check_for_xrun(struct comp_dev *dev, uint32_t copy_bytes)
/* report xrun occurrence */
static void dai_report_xrun(struct comp_dev *dev, uint32_t bytes)
{
struct dai_data *dd = comp_get_drvdata(dev);
struct comp_buffer *local_buffer;
/* data available for copy or just starting */
if (copy_bytes || dd->start_position == dev->position)
return 0;
/* xrun occurred */
if (dev->params.direction == SOF_IPC_STREAM_PLAYBACK) {
trace_dai_error_with_ids(dev, "dai_check_for_xrun() "
"error: underrun due to no data "
"available");
trace_dai_error_with_ids(dev, "dai_report_xrun() error: "
"underrun due to no data available");
local_buffer = list_first_item(&dev->bsource_list,
struct comp_buffer, sink_list);
comp_underrun(dev, local_buffer, copy_bytes);
comp_underrun(dev, local_buffer, bytes);
} else {
trace_dai_error_with_ids(dev, "dai_check_for_xrun() "
"error: overrun due to no data "
"available");
trace_dai_error_with_ids(dev, "dai_report_xrun() error: "
"overrun due to no data available");
local_buffer = list_first_item(&dev->bsink_list,
struct comp_buffer, source_list);
comp_overrun(dev, local_buffer, copy_bytes);
comp_overrun(dev, local_buffer, bytes);
}
return -ENODATA;
}
/* copy and process stream data from source to sink buffers */
@ -642,8 +632,10 @@ static int dai_copy(struct comp_dev *dev)
/* get data sizes from DMA */
ret = dma_get_data_size(dd->chan, &avail_bytes, &free_bytes);
if (ret < 0)
if (ret < 0) {
dai_report_xrun(dev, 0);
return ret;
}
/* calculate minimum size to copy */
if (dev->params.direction == SOF_IPC_STREAM_PLAYBACK) {
@ -658,14 +650,15 @@ static int dai_copy(struct comp_dev *dev)
tracev_dai_with_ids(dev, "dai_copy(), copy_bytes = 0x%x", copy_bytes);
/* check for underrun or overrun */
ret = dai_check_for_xrun(dev, copy_bytes);
if (ret < 0)
return ret;
/* return if it's not stream start */
if (!copy_bytes && dd->start_position != dev->position)
return 0;
ret = dma_copy(dd->chan, copy_bytes, 0);
if (ret < 0)
trace_dai_error("dai_copy() error: ret = %u", ret);
if (ret < 0) {
dai_report_xrun(dev, copy_bytes);
return ret;
}
return ret;
}