Skip to content

[DNM] ASoC: soc-pcm/soc-compress: Unwind FE/BE triggers on failure - #5989

Open
ujfalusi wants to merge 7 commits into
thesofproject:topic/sof-devfrom
ujfalusi:peter/sof/pr/asoc-fe-be-trigger-unwind
Open

ujfalusi wants to merge 7 commits into
thesofproject:topic/sof-devfrom
ujfalusi:peter/sof/pr/asoc-fe-be-trigger-unwind

Conversation

@ujfalusi

Copy link
Copy Markdown
Collaborator

For CI testing before sending upstream

Hi,

This series is the follow-up promised in the compressed audio series
review [1]: if a trigger fails part way through the DPCM FE-BE sequence,
the already triggered FE or BEs are left in the new state.

The PCM core issues an undo trigger for a single substream only, not for
the failing substream of a linked group, not for a failed RESUME and not
for triggers deferred by DPCM during a runtime update. The compress core
does not undo failed triggers at all. The undo trigger from the PCM core
is also propagated to all BEs of the FE, which can stop a BE shared with
another running FE.

Patches 1-2 fix the BE reference handling on RESUME and on failing
PAUSE_RELEASE.
Patch 3 is a no-functional-change move of the per BE trigger handling to
a helper.
Patch 4 unwinds the BEs in dpcm_be_dai_trigger().
Patch 5 unwinds the FE/BE sequence in soc-pcm and ignores the undo
STOP/PAUSE_PUSH from the PCM core when the FE has not been started.
Patches 6-7 do the same for compressed streams.

Only failing START, RESUME and PAUSE_RELEASE are unwound (with STOP,
SUSPEND and PAUSE_PUSH), failing stop-direction triggers are not.

Testing was done with SOF (IPC4) on a SoundWire laptop by injecting
trigger failures in the FE and BE drivers for PCM and compressed
playback, with both FE-first and BE-first trigger ordering and with a BE
shared between FEs. Without the series a single failed trigger leaves
the stream unusable in several cases (failed BE PAUSE_RELEASE, failed
compressed START, failed FE START with a shared BE running), with the
series all cases recover.
The rollback of multiple BEs within one FE (patch 4) is not covered by
the testing due to lack of device.

Multiple AI tools were used for static code path validation which did
resulted additional patches as issues found by the analysis.

[1] https://lore.kernel.org/linux-sound/asS7ktuZo6z68chF@sirena.co.uk/

Regards,
Peter

Peter Ujfalusi (7):
ASoC: soc-pcm: Take a BE reference on RESUME when the BE is already
running
ASoC: soc-pcm: Restore the pause state when BE PAUSE_RELEASE fails
ASoC: soc-pcm: Move the BE trigger handling to a helper function
ASoC: soc-pcm: Unwind the triggered BEs on failure
ASoC: soc-pcm: Unwind the FE and BE triggers on failure
ASoC: soc-component: Unwind the compress trigger of components on
failure
ASoC: soc-compress: Unwind the FE and BE triggers on failure

include/sound/soc-dpcm.h | 18 +++
sound/soc/soc-component.c | 22 ++-
sound/soc/soc-compress.c | 39 +++--
sound/soc/soc-pcm.c | 307 ++++++++++++++++++++++----------------
4 files changed, 246 insertions(+), 140 deletions(-)

--
2.56.0

Copilot AI balanced review requested due to automatic review settings October 20, 2026 11:58

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Rollback can consume another frontend’s backend reference and interrupt its running stream.

1 open issue
What changed in this PR

This PR adds failure rollback to ASoC PCM and compressed-audio trigger sequences to restore frontends and backends after partial failures.

Changes:

  • Fix shared-backend RESUME references and failed PAUSE_RELEASE accounting.
  • Unwind successful triggers when a later backend, frontend, or component fails.
  • Ignore redundant PCM-core undo triggers after rollback.
File Description
sound/​soc/​soc-pcm.c Refactors backend triggers and adds frontend/backend rollback.
sound/​soc/​soc-compress.c Adds compressed frontend/backend trigger rollback.
sound/​soc/​soc-component.c Unwinds previously triggered compressed components.
include/​sound/​soc-dpcm.h Adds the shared inverse-trigger helper.

Review effort: Balanced

Comment thread sound/soc/soc-pcm.c Outdated
Copilot AI balanced review requested due to automatic review settings October 20, 2026 13:20
@ujfalusi
ujfalusi force-pushed the peter/sof/pr/asoc-fe-be-trigger-unwind branch from 6588eb0 to a5c2ba0 Compare October 20, 2026 13:20
@ujfalusi

Copy link
Copy Markdown
Collaborator Author

Changes since v1:

  • the unwind now tracks per FE/BE link whether the reference was taken (snd_soc_dpcm.trigger_ref) and only unwinds those links, in all three rollback paths.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

RESUME rollback can suspend a shared backend still needed by a paused frontend, preventing playback recovery.

1 open issue
1 resolved since last review

Review effort: Balanced

Comment thread sound/soc/soc-pcm.c Outdated
@ujfalusi
ujfalusi force-pushed the peter/sof/pr/asoc-fe-be-trigger-unwind branch from a5c2ba0 to e7773a0 Compare October 20, 2026 13:39
Copilot AI balanced review requested due to automatic review settings October 21, 2026 13:50
@ujfalusi
ujfalusi force-pushed the peter/sof/pr/asoc-fe-be-trigger-unwind branch from e7773a0 to 50b4c09 Compare October 21, 2026 13:50
@ujfalusi

Copy link
Copy Markdown
Collaborator Author

Changes since v2:
Patch 1: now also restarts a paused BE on RESUME, and is retitled.
Patch 2: clears the pause references when an FE or BE is opened.
Patch 4:
When unwinding a RESUME, it pauses the BE instead of suspending it if another FE still has it paused.
The helpers moved to soc-internal.h, without the export.
Patch 6: now also covers the non-DPCM compress trigger.
Style and naming: the parentheses and prototype cleanup in patch 3, and the helper rename across patches 4–7.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

Concurrency-sensitive shared-backend transitions and the untested multi-backend rollback path require human validation.

1 open issue

Review effort: Balanced

@ujfalusi

Copy link
Copy Markdown
Collaborator Author

the build fails are fixed by: #5995

Copilot AI balanced review requested due to automatic review settings October 22, 2026 09:52
@ujfalusi
ujfalusi force-pushed the peter/sof/pr/asoc-fe-be-trigger-unwind branch from 50b4c09 to 645a425 Compare October 22, 2026 09:52
The SUSPEND trigger drops the be_start reference of the FE for every BE
in START state, but RESUME only takes a reference if the BE is in SUSPEND
state.

If a BE is shared between FEs, the BE is moved to SUSPEND state only when
the last FE is suspended and it is moved back to START state when the
first FE is resumed. The rest of the FEs will skip the BE on RESUME and
the be_start counter ends up being lower than the number of FEs using
the BE, which will cause the BE to be stopped while it is still in use
by another FE.

The BE is also skipped on RESUME if it has been paused in the meantime by
another FE which has been resumed already, leaving the BE paused while
the resumed FE is running.

Handle these cases similarly to START: if the BE is already running,
take a reference for the FE and if the BE is paused, release it.

The BE is still skipped if another FE has resumed and then stopped or
re-prepared it while this FE is suspended. The suspended FE does not
hold a reference on the BE and its DPCM state is STOP, handling this
would need the suspended state of the FE to be tracked.

Fixes: 848aedf ("ASoC: soc-pcm: test refcount before triggering")
Cc: stable@vger.kernel.org
Signed-off-by: Peter Ujfalusi <peter.ujfalusi@linux.intel.com>
On PAUSE_RELEASE the fe_pause flag is cleared and the be_pause counter is
decremented before the BE is triggered, but only the be_start counter is
restored if the trigger fails.

The BE stays in PAUSED state while the pause reference of the FE is
lost. When the stream is closed later, the PCM core releases the pause
before stopping the stream which takes the be_pause counter negative and
the STOP will be handled as a pause/stop transition, leaving the BE in
PAUSED state.

For example with SOF the BE pipeline cannot be freed on close and the
stream is not usable anymore after this.

Restore the fe_pause and be_pause as well when the PAUSE_RELEASE fails.

The pause references are also not cleared when the FE or the BE is
opened. If the PAUSE_RELEASE fails again when the paused stream is
closed, the PCM core does not send STOP for it and the fe_pause and
be_pause would be carried over to the next use of the FE and the BE.
Clear them on open, as it is done for be_start.

Fixes: 9995c1d ("ASoC: soc-pcm: improve BE transition for PAUSE_RELEASE")
Cc: stable@vger.kernel.org # 6.1+
Signed-off-by: Peter Ujfalusi <peter.ujfalusi@linux.intel.com>
Move the trigger handling of a single BE out from dpcm_be_dai_trigger()
to a new helper function to make it possible to re-use it for unwinding
the BE triggers in case of an error.

While at it, drop the unnecessary parentheses in the moved conditions and
put the dpcm_be_dai_trigger() prototype on a single line.

No functional change.

Signed-off-by: Peter Ujfalusi <peter.ujfalusi@linux.intel.com>
If the trigger of a BE fails in dpcm_be_dai_trigger() then the BEs which
have been already triggered are left in the new state with the be_start
and be_pause reference counts taken for the FE.

The PCM core issues an undo trigger for a single substream, but not for
the failing substream of a linked group and the compress core does not
undo failed triggers at all. dpcm_run_update_startup() also expects
that the BEs are stopped on failure. The references and BE states will
remain unbalanced, the BEs might be left running.

Unwind the already triggered BEs when a START, RESUME or PAUSE_RELEASE
fails with the corresponding STOP, SUSPEND or PAUSE_PUSH command.

Record in the DPCM link if the BE reference has been taken for the FE
and only unwind those BEs. The state of a BE which has been skipped can
be changed by the trigger of another FE between the trigger and the
unwind, so the decision cannot be made on the BE state at unwind time.

The per BE trigger handling takes care of the reference counting and
the pause/stop transitions. The STOP used to unwind a failed START must
not be handled as a pause/stop transition since the START does not take
the BE pause reference: the FE can be paused when new BEs are started by
dpcm_run_update_startup().

The SUSPEND used to unwind a RESUME must not suspend the BE if another FE
has paused it in the meantime, this would leave the BE in SUSPEND state
and the PAUSE_RELEASE of the other FE would skip it. Pause the BE instead,
as it would have been done by the PAUSE_PUSH of the other FE without the
RESUME.

Add the dpcm_be_dai_trigger_unwind() function and the
snd_soc_trigger_unwind_cmd() helper to soc-internal.h so they can be
used to unwind the BEs when the FE trigger fails and by soc-compress as
well.

Failing STOP, SUSPEND or PAUSE_PUSH is not unwound.

Signed-off-by: Peter Ujfalusi <peter.ujfalusi@linux.intel.com>
If the FE is triggered before the BEs and the BE trigger fails then the
FE is left in the new state. If the BEs are triggered first and the FE
trigger fails then the BEs are left in the new state.

For a single substream the PCM core issues an undo trigger after a
failed START (STOP) or PAUSE_RELEASE (PAUSE_PUSH), but there is no undo
for the failing substream of a linked group, for a failed RESUME or for
a trigger which has been deferred by DPCM during a runtime update.

Unwind the part which has been successfully triggered when START, RESUME
or PAUSE_RELEASE fails, the same way as soc_pcm_trigger() rolls back the
DAIs and components.

With the unwind in place the undo trigger from the PCM core is redundant
and it is also harmful already without the unwind: the undo is
propagated to the BEs as well, regardless of whether they have been
triggered for this FE or not. If a BE is shared with another running FE
then its be_start reference is dropped without being taken and the BE
is stopped under the other FE. The FE components also receive a STOP or
PAUSE_PUSH without the corresponding successful START or PAUSE_RELEASE.

This has been observed with SOF using FE-first trigger order (as used by
IPC4 for capture) when the START of the Speaker PCM fails while the
Deepbuffer Speaker PCM is running on the same BE: the BE is stopped and
the Deepbuffer playback fails.

Ignore the STOP and PAUSE_PUSH if the FE is not in a state where these
are valid. The dpcm state of the FE is only updated on successful
trigger, so it can be used to detect this case.

Link: https://lore.kernel.org/linux-sound/asS7ktuZo6z68chF@sirena.co.uk/
Suggested-by: Mark Brown <broonie@kernel.org>
Signed-off-by: Peter Ujfalusi <peter.ujfalusi@linux.intel.com>
…lure

snd_soc_component_compr_trigger() returns on the first failing component
leaving the components which have been triggered before in the new state.

The compress core does not issue any undo trigger on failure, so these
components would be left running.

Unwind the already triggered components when a START, RESUME or
PAUSE_RELEASE fails with the corresponding STOP, SUSPEND or PAUSE_PUSH
command.

Do the same in soc_compr_trigger() for non-DPCM compressed streams if
the CPU DAI trigger fails after the components have been triggered.

Signed-off-by: Peter Ujfalusi <peter.ujfalusi@linux.intel.com>
If the FE is triggered before the BEs and the BE trigger fails then the
FE is left in the new state. If the BEs are triggered first and the FE
trigger fails then the BEs are left in the new state. The same is true
for the FE CPU DAI if the component trigger fails.

The compress core does not issue any undo trigger on failure and
soc_compr_free_fe() will only stop the stream if the FE is in START
state, leaving the FE or the BEs running with unbalanced reference
counts after the stream is closed.

For example with SOF the pipelines of the stream cannot be set up again
after such failure and the stream is not usable anymore.

Unwind the part which has been successfully triggered when START or
PAUSE_RELEASE fails, the same way as it is done in soc-pcm.

Link: https://lore.kernel.org/linux-sound/asS7ktuZo6z68chF@sirena.co.uk/
Suggested-by: Mark Brown <broonie@kernel.org>
Signed-off-by: Peter Ujfalusi <peter.ujfalusi@linux.intel.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

Shared-backend reference accounting and rollback interactions warrant human review, particularly because multi-backend rollback lacks reported hardware validation.

No open issues 🎉

1 resolved since last review

Review effort: Balanced

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants