host: add a completion work to notify host side

We need to wait until the last bytes/period is finished in dai,
before we can notify host side about that, otherwise, host side
will trigger stop too early, and we will miss rendering them.

Signed-off-by: Keyon Jie <yang.jie@linux.intel.com>
This commit is contained in:
Keyon Jie 2017-02-11 10:17:52 +08:00 committed by Liam Girdwood
parent 1e524a17f0
commit 9e58cf39a5
4 changed files with 47 additions and 0 deletions

View File

@ -64,6 +64,7 @@ struct host_data {
completion_t complete;
struct period_desc *period;
struct comp_buffer *dma_buffer;
struct work work;
/* local and host DMA buffer info */
struct hc_buf host;
@ -220,6 +221,10 @@ static void host_dma_cb_playback(struct comp_dev *dev,
/* end of stream, stop */
next->size = 0;
need_copy = 0;
/* will notify host side once dai tell us */
wait_init(&dev->pipeline->complete);
work_schedule_default(&hd->work, PLATFORM_HOST_FINISH_DELAY);
goto next_copy;
}
@ -354,6 +359,38 @@ static void host_dma_cb(void *data, uint32_t type, struct dma_sg_elem *next)
host_dma_cb_capture(dev, next);
}
/* We need to wait until the last bytes/period is finished in dai, before we
* can notify host side about that, otherwise, host side will trigger stop too
* early, and we will miss rendering them.
* This work should be scheduled once the copy for host component is finished,
* and wait a timeout inside the work for pipeline->complete, which should be
* set in the endpoint(dai) rendering finishing callback.
*/
static uint32_t host_finish_work(void *data, uint32_t udelay)
{
struct comp_dev *dev = (struct comp_dev *)data;
struct host_data *hd = comp_get_drvdata(dev);
int ret;
dev->pipeline->complete.timeout = PLATFORM_HOST_FINISH_TIMEOUT;
ret = wait_for_completion_timeout(&dev->pipeline->complete);
if (ret < 0)
trace_comp_error("eHf");
else {
trace_comp("hFw");
/* update for host side */
if (hd->host_pos) {
*hd->host_pos = hd->host_pos_read;
/* send the last notification to host */
ipc_stream_send_notification(dev, &hd->cp);
}
}
return 0;
}
static struct comp_dev *host_new(uint32_t type, uint32_t index,
uint32_t direction)
{
@ -389,6 +426,7 @@ static struct comp_dev *host_new(uint32_t type, uint32_t index,
hd->source = NULL;
hd->sink = NULL;
hd->split_remaining = 0;
work_init(&hd->work, host_finish_work, dev, WORK_ASYNC);
/* init buffer elems */
list_init(&hd->config.elem_list);

View File

@ -141,6 +141,7 @@ struct pipeline *pipeline_new(uint32_t id)
list_init(&p->host_ep_list);
list_init(&p->dai_ep_list);
list_init(&p->buffer_list);
wait_init(&p->complete);
spinlock_init(&p->lock);
list_item_prepend(&p->list, &pipe_data->pipeline_list);

View File

@ -39,6 +39,7 @@
#include <reef/dma.h>
#include <reef/audio/component.h>
#include <reef/trace.h>
#include <reef/wait.h>
#define trace_pipe(__e) trace_event(TRACE_CLASS_PIPE, __e)
#define trace_pipe_error(__e) trace_error(TRACE_CLASS_PIPE, __e)
@ -50,6 +51,7 @@
struct pipeline {
uint32_t id; /* id */
spinlock_t lock;
completion_t complete; /* indicate if the pipeline data is finished*/
/* lists */
struct list_item host_ep_list; /* list of host endpoints */

View File

@ -86,6 +86,12 @@
/* WorkQ window size in microseconds */
#define PLATFORM_WORKQ_WINDOW 2000
/* Host finish work schedule delay in microseconds */
#define PLATFORM_HOST_FINISH_DELAY 100
/* Host finish work(drain from host to dai) timeout in microseconds */
#define PLATFORM_HOST_FINISH_TIMEOUT 50000
/* Platform defined panic code */
#define platform_panic(__x) \
shim_write(SHIM_IPCXL, ((shim_read(SHIM_IPCXL) & 0xc0000000) |\