diff --git a/src/audio/pipeline/pipeline-schedule.c b/src/audio/pipeline/pipeline-schedule.c index c5fb484bd080..16df23e7edb6 100644 --- a/src/audio/pipeline/pipeline-schedule.c +++ b/src/audio/pipeline/pipeline-schedule.c @@ -35,69 +35,12 @@ static void pipeline_schedule_cancel(struct pipeline *p) /* enable system agent panic, when there are no longer * DMA driven pipelines */ - sa_set_panic_on_delay(true); -} - -static enum task_state pipeline_task_cmd(struct pipeline *p, - struct sof_ipc_reply *reply) -{ - int err, cmd = p->trigger.cmd; - - if (!p->trigger.host) { - p->trigger.cmd = -EINVAL; - return p->status == COMP_STATE_PAUSED ? SOF_TASK_STATE_COMPLETED : - SOF_TASK_STATE_RESCHEDULE; - } - - err = pipeline_trigger_run(p, p->trigger.host, cmd); - if (err < 0) { - pipe_err(p, "pipeline_task_cmd(): failed to trigger components: %d", err); - reply->error = err; - err = SOF_TASK_STATE_COMPLETED; - } else { - switch (cmd) { - case COMP_TRIGGER_START: - case COMP_TRIGGER_RELEASE: - p->status = COMP_STATE_ACTIVE; - break; - case COMP_TRIGGER_PRE_START: - case COMP_TRIGGER_PRE_RELEASE: - p->status = COMP_STATE_PRE_ACTIVE; - break; - case COMP_TRIGGER_STOP: - case COMP_TRIGGER_PAUSE: - p->status = COMP_STATE_PAUSED; - } - - if (err == PPL_STATUS_PATH_STOP) { - pipe_warn(p, "pipeline_task_cmd(): stopping for xrun"); - err = SOF_TASK_STATE_COMPLETED; - } else if (p->trigger.cmd != cmd) { - /* PRE stage completed */ - if (p->trigger.delay) - return SOF_TASK_STATE_RESCHEDULE; - /* No delay: the final stage has already run too */ - } else if (p->status == COMP_STATE_PAUSED && !p->trigger.aborted) { - err = SOF_TASK_STATE_COMPLETED; - } else { - p->status = COMP_STATE_ACTIVE; - err = SOF_TASK_STATE_RESCHEDULE; - } - } - - p->trigger.cmd = -EINVAL; - - ipc_msg_reply(reply); - - return err; + if (!pipeline_is_timer_driven(p)) + sa_set_panic_on_delay(true); } static enum task_state pipeline_task(void *arg) { - struct sof_ipc_reply reply = { - .hdr.cmd = SOF_IPC_GLB_REPLY, - .hdr.size = sizeof(reply), - }; struct pipeline *p = arg; int err; @@ -136,16 +79,38 @@ static enum task_state pipeline_task(void *arg) return SOF_TASK_STATE_RESCHEDULE; } - if (p->trigger.cmd >= 0) - /* Process an offloaded command */ - return pipeline_task_cmd(p, &reply); + if (p->trigger.cmd >= 0) { + /* First pipeline task run for either START or RELEASE: PRE stage */ + struct sof_ipc_reply reply = { + .hdr.cmd = SOF_IPC_GLB_REPLY, + .hdr.size = sizeof(reply), + }; + int cmd = p->trigger.cmd; - if (p->status == COMP_STATE_PAUSED) - /* - * One of pipelines, being stopped, but not the one, that - * triggers all components - */ - return SOF_TASK_STATE_COMPLETED; + err = pipeline_trigger_run(p, p->trigger.host, cmd); + if (err < 0) { + pipe_err(p, "pipeline_task(): failed to trigger components: %d", err); + reply.error = err; + err = SOF_TASK_STATE_COMPLETED; + } else if (err == PPL_STATUS_PATH_STOP) { + pipe_warn(p, "pipeline_task(): stopping for xrun"); + err = SOF_TASK_STATE_COMPLETED; + } else if (p->trigger.cmd != cmd) { + /* PRE stage completed */ + if (p->trigger.delay) + return SOF_TASK_STATE_RESCHEDULE; + /* No delay: the final stage has already run too */ + } else { + p->status = COMP_STATE_ACTIVE; + err = SOF_TASK_STATE_RESCHEDULE; + } + + p->trigger.cmd = -EINVAL; + + ipc_msg_reply(&reply); + + return err; + } /* * The first execution of the pipeline task above has triggered all @@ -225,37 +190,23 @@ void pipeline_schedule_triggered(struct pipeline_walk_context *ctx, case COMP_TRIGGER_STOP: list_for_item(tlist, &ctx->pipelines) { p = container_of(tlist, struct pipeline, list); - if (pipeline_is_timer_driven(p) && - p->status != COMP_STATE_PAUSED) { - /* - * Paused pipelines have their tasks stopped - * already, use a running pipeline to trigger - * components. - */ - p->trigger.cmd = cmd; - p->trigger.host = ppl_data->start; - ppl_data->start = NULL; - } else { - pipeline_schedule_cancel(p); - p->status = COMP_STATE_PAUSED; - } + pipeline_schedule_cancel(p); + p->status = COMP_STATE_PAUSED; } break; case COMP_TRIGGER_PRE_RELEASE: case COMP_TRIGGER_PRE_START: list_for_item(tlist, &ctx->pipelines) { p = container_of(tlist, struct pipeline, list); - p->xrun_bytes = 0; - if (pipeline_is_timer_driven(p) && first_pipe) { - /* - * Use the first of connected pipelines to - * trigger, mark all other connected pipelines - * active immediately. - */ - p->trigger.cmd = cmd; - p->trigger.host = ppl_data->start; - first_pipe = false; + if (pipeline_is_timer_driven(p)) { + /* Use the first of connected pipelines to trigger */ + if (first_pipe) { + p->trigger.cmd = cmd; + p->trigger.host = ppl_data->start; + first_pipe = false; + } } else { + p->xrun_bytes = 0; p->status = COMP_STATE_ACTIVE; } pipeline_schedule_copy(p, 0); diff --git a/src/audio/pipeline/pipeline-stream.c b/src/audio/pipeline/pipeline-stream.c index baa67b958d87..1f4ba3966c07 100644 --- a/src/audio/pipeline/pipeline-stream.c +++ b/src/audio/pipeline/pipeline-stream.c @@ -61,6 +61,77 @@ pipeline_should_report_enodata_on_trigger(struct comp_dev *rsrc, return false; } +/* Runs in IPC or in pipeline task context */ +static int pipeline_comp_trigger(struct comp_dev *current, + struct comp_buffer *calling_buf, + struct pipeline_walk_context *ctx, int dir) +{ + struct pipeline_data *ppl_data = ctx->comp_data; + bool is_single_ppl = comp_is_single_pipeline(current, ppl_data->start); + bool is_same_sched, async; + int err; + + pipe_dbg(current->pipeline, + "pipeline_comp_trigger(), current->comp.id = %u, dir = %u", + dev_comp_id(current), dir); + + switch (ppl_data->cmd) { + case COMP_TRIGGER_PAUSE: + case COMP_TRIGGER_STOP: + /* + * PAUSE and STOP are triggered in IPC context, not from the + * pipeline task + */ + async = true; + break; + case COMP_TRIGGER_PRE_RELEASE: + case COMP_TRIGGER_PRE_START: + if (comp_get_endpoint_type(current) == COMP_ENDPOINT_DAI) { + struct dai_data *dd = comp_get_drvdata(current); + + ppl_data->delay_ms = dai_get_init_delay_ms(dd->dai); + } + + COMPILER_FALLTHROUGH; + case COMP_TRIGGER_RELEASE: + case COMP_TRIGGER_START: + async = !pipeline_is_timer_driven(current->pipeline); + break; + default: + return -EINVAL; + } + + is_same_sched = pipeline_is_same_sched_comp(current->pipeline, + ppl_data->start->pipeline); + + /* trigger should propagate to the connected pipelines, + * which need to be scheduled together + */ + if (!is_single_ppl && !is_same_sched) { + pipe_dbg(current->pipeline, + "pipeline_comp_trigger(), current is from another pipeline"); + + if (pipeline_should_report_enodata_on_trigger(current, ctx, dir)) + return -ENODATA; + + return 0; + } + + /* send command to the component and update pipeline state */ + err = comp_trigger(current, ppl_data->cmd); + if (err < 0 || err == PPL_STATUS_PATH_STOP) + return err; + + /* + * Add scheduling components to the list. This is only needed for the + * stopping flow. + */ + if (async) + pipeline_comp_trigger_sched_comp(current->pipeline, current, ctx); + + return pipeline_for_each_comp(current, ctx, dir); +} + static int pipeline_comp_copy(struct comp_dev *current, struct comp_buffer *calling_buf, struct pipeline_walk_context *ctx, int dir) @@ -238,22 +309,14 @@ int pipeline_trigger(struct pipeline *p, struct comp_dev *host, int cmd) pipe_info(p, "pipe trigger cmd %d", cmd); - p->trigger.aborted = false; - switch (cmd) { case COMP_TRIGGER_PAUSE: case COMP_TRIGGER_STOP: - if (p->status == COMP_STATE_PAUSED || p->xrun_bytes) { - /* The task isn't running, trigger inline */ - ret = pipeline_trigger_run(p, host, cmd); - return ret < 0 ? ret : 0; - } - - COMPILER_FALLTHROUGH; + /* Execute immediately */ + ret = pipeline_trigger_run(p, host, cmd); + return ret == PPL_STATUS_PATH_STOP ? 0 : ret; case COMP_TRIGGER_XRUN: - if (cmd == COMP_TRIGGER_XRUN) - pipeline_trigger_xrun(p, &host); - + pipeline_trigger_xrun(p, &host); COMPILER_FALLTHROUGH; case COMP_TRIGGER_PRE_RELEASE: case COMP_TRIGGER_PRE_START: @@ -261,84 +324,13 @@ int pipeline_trigger(struct pipeline *p, struct comp_dev *host, int cmd) ret = pipeline_trigger_list(p, host, cmd); if (ret < 0) return ret; - /* IPC response will be sent from the task, unless it was paused */ + /* IPC response will be sent from the task */ return 1; } return 0; } -/* Runs in IPC or in pipeline task context */ -static int pipeline_comp_trigger(struct comp_dev *current, - struct comp_buffer *calling_buf, - struct pipeline_walk_context *ctx, int dir) -{ - struct pipeline_data *ppl_data = ctx->comp_data; - bool is_single_ppl = comp_is_single_pipeline(current, ppl_data->start); - bool is_same_sched; - int err; - - pipe_dbg(current->pipeline, - "pipeline_comp_trigger(), current->comp.id = %u, dir = %u", - dev_comp_id(current), dir); - - switch (ppl_data->cmd) { - case COMP_TRIGGER_PRE_RELEASE: - case COMP_TRIGGER_PRE_START: - if (comp_get_endpoint_type(current) == COMP_ENDPOINT_DAI) { - struct dai_data *dd = comp_get_drvdata(current); - - ppl_data->delay_ms = dai_get_init_delay_ms(dd->dai); - } - break; - default: - return -EINVAL; - case COMP_TRIGGER_PAUSE: - case COMP_TRIGGER_STOP: - case COMP_TRIGGER_RELEASE: - case COMP_TRIGGER_START: - break; - } - - is_same_sched = pipeline_is_same_sched_comp(current->pipeline, - ppl_data->start->pipeline); - - /* trigger should propagate to the connected pipelines, - * which need to be scheduled together - */ - if (!is_single_ppl && !is_same_sched) { - pipe_dbg(current->pipeline, - "pipeline_comp_trigger(), current is from another pipeline"); - - if (pipeline_should_report_enodata_on_trigger(current, ctx, dir)) - return -ENODATA; - - return 0; - } - - /* send command to the component and update pipeline state */ - err = comp_trigger(current, ppl_data->cmd); - current->pipeline->trigger.aborted = err == PPL_STATUS_PATH_STOP; - if (err < 0 || err == PPL_STATUS_PATH_STOP) - return err; - - switch (ppl_data->cmd) { - case COMP_TRIGGER_PAUSE: - case COMP_TRIGGER_STOP: - if (pipeline_is_timer_driven(current->pipeline)) - current->pipeline->status = COMP_STATE_PAUSED; - } - - /* - * Add scheduling components to the list. This is only needed for - * asynchronous flows. - */ - if (!pipeline_is_timer_driven(current->pipeline)) - pipeline_comp_trigger_sched_comp(current->pipeline, current, ctx); - - return pipeline_for_each_comp(current, ctx, dir); -} - /* actually execute pipeline trigger, including components: either in IPC or in task context */ int pipeline_trigger_run(struct pipeline *p, struct comp_dev *host, int cmd) { @@ -356,7 +348,6 @@ int pipeline_trigger_run(struct pipeline *p, struct comp_dev *host, int cmd) pipe_dbg(p, "execute trigger cmd %d on pipe %u", cmd, p->pipeline_id); list_init(&walk_ctx.pipelines); - p->trigger.aborted = false; /* handle pipeline global checks before going into each components */ if (p->xrun_bytes) { @@ -403,7 +394,7 @@ int pipeline_trigger_run(struct pipeline *p, struct comp_dev *host, int cmd) ret = walk_ctx.comp_func(host, NULL, &walk_ctx, host->direction); if (ret < 0) - pipe_err(p, "pipeline_trigger_run(): ret = %d, host->comp.id = %u, cmd = %d", + pipe_err(p, "pipeline_trigger(): ret = %d, host->comp.id = %u, cmd = %d", ret, dev_comp_id(host), cmd); else if (ret == PPL_STATUS_PATH_STOP) ret = 0; diff --git a/src/include/sof/audio/pipeline.h b/src/include/sof/audio/pipeline.h index c19f6c0a69d1..a11519ba1645 100644 --- a/src/include/sof/audio/pipeline.h +++ b/src/include/sof/audio/pipeline.h @@ -77,7 +77,6 @@ struct pipeline { int cmd; struct comp_dev *host; unsigned int delay; /* period count */ - bool aborted; } trigger; };