pipeline: fix aborting STOP or PAUSE propagation

When trigger.aborted is set, pipeline_trigger_run() also returns
PPL_STATUS_PATH_STOP. So the current test for trigger.aborted in
pipeline_task_cmd() after pipeline_trigger_run() is a left-over from
an earlier implementation and is never entered with the current flow.
In the current implementation, a typical playback topology like
[pipeline A] PCM -> ... - [pipeline B] mixer -> ... -> DAI
when a pause is triggered mixer will stop its propagation, set
trigger.aborted on pipeline B to true and return
PPL_STATUS_PATH_STOP. pipeline_task_cmd() is still running in the
context of pipeline A, so it will detect PPL_STATUS_PATH_STOP, check
that trigger.aborted is not set and terminate the task. Then the
scheduler will run the task for pipeline B, that one will verify,
that trigger.host == NULL, then find the trigger.aborted to be true
and will keep the task running.

In a topology, where the PCM, the mixer and the DAI all belong to the
same pipeline, when PAUSE is triggered, the whole pipeline should be
left running which is what this patch achieves by checkint
trigger.aborted when PPL_STATUS_PATH_STOP is returned by
pipeline_trigger_run().

BugLink: https://github.com/thesofproject/sof/issues/5257
Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
This commit is contained in:
Guennadi Liakhovetski 2022-02-16 11:10:14 +01:00 committed by Liam Girdwood
parent 8b519858c5
commit c04b7fc13e
1 changed files with 9 additions and 9 deletions

View File

@ -81,15 +81,7 @@ static enum task_state pipeline_task_cmd(struct pipeline *p,
if (err == PPL_STATUS_PATH_STOP) { if (err == PPL_STATUS_PATH_STOP) {
/* comp_trigger() interrupted trigger propagation or an xrun occurred */ /* comp_trigger() interrupted trigger propagation or an xrun occurred */
err = SOF_TASK_STATE_COMPLETED; if (p->trigger.aborted && p->status == COMP_STATE_PAUSED) {
} 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 */
err = SOF_TASK_STATE_RESCHEDULE;
} else if (p->status == COMP_STATE_PAUSED) {
if (p->trigger.aborted) {
p->status = COMP_STATE_ACTIVE; p->status = COMP_STATE_ACTIVE;
/* /*
* the pipeline aborted a STOP or a PAUSE * the pipeline aborted a STOP or a PAUSE
@ -99,6 +91,14 @@ static enum task_state pipeline_task_cmd(struct pipeline *p,
} else { } else {
err = SOF_TASK_STATE_COMPLETED; 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 */
err = SOF_TASK_STATE_RESCHEDULE;
} else if (p->status == COMP_STATE_PAUSED) {
err = SOF_TASK_STATE_COMPLETED;
} else { } else {
p->status = COMP_STATE_ACTIVE; p->status = COMP_STATE_ACTIVE;
err = SOF_TASK_STATE_RESCHEDULE; err = SOF_TASK_STATE_RESCHEDULE;