Repository navigation
Conversation
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
Suspend-target handling, DAPM endpoint coverage, and ACE2.x teardown currently prevent safe path retention.
Review effort: Balanced
Findings: 4
Open (4)
What changed in this PR
Adds suspend retention for D0i3-compatible SOF SoundWire audio paths.
Changes:
- Propagates suspend retention through DAPM and SoundWire streams.
- Keeps Intel SoundWire buses active during suspend.
- Adjusts trigger handling for retained streams.
| File | Description |
|---|---|
sound/soc/sof/pcm.c |
Marks connected DAPM widgets for retention. |
sound/soc/sof/intel/hda.c |
Propagates D0i3 compatibility to SoundWire. |
sound/soc/sof/intel/hda-dai-ops.c |
Handles resume triggers. |
sound/soc/sdw_utils/soc_sdw_utils.c |
Preserves retained streams across suspend. |
include/linux/soundwire/sdw.h |
Adds retention state and bus API. |
drivers/soundwire/stream.c |
Implements bus retention detection. |
drivers/soundwire/intel.c |
Avoids suspending retained controller state. |
drivers/soundwire/intel_auxdevice.c |
Skips bus power transitions when retained. |
drivers/soundwire/intel_ace2x.c |
Applies retention to ACE2.x controllers. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
ujfalusi
left a comment
There was a problem hiding this comment.
@bardliao, how about the codec drivers themself? I think that the one you use only marks the regcache cache only, but it would not be far fetched if a codec driver would actually do the right thing and powers down things in their PM suspend callback?
| swidget->spipe->started_count = 0; | ||
| break; | ||
| case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | ||
| case SNDRV_PCM_TRIGGER_RESUME: |
There was a problem hiding this comment.
with this patch: 8d544a0
you are not going to receive the RESUME trigger.
| break; | ||
| } | ||
| if (!list_entry_is_head(spcm, &sdev->pcm_list, list) && | ||
| spcm->stream[dir].d0i3_compatible) |
There was a problem hiding this comment.
this will mark DeepBuffer playback and capture also, which is not correct.
The definition to use is:
9e47005
There was a problem hiding this comment.
@ujfalusi Do you mean just test spcm->stream[substream->stream].suspend_ignored?
There was a problem hiding this comment.
* WoV streams can be indetified by:
* They are capture streams and
* They have the d0i3_compatible flag set and
* They don't use Deep Buffer
| return ret; | ||
| } | ||
|
|
||
| if (spcm->stream[dir].d0i3_compatible) { |
There was a problem hiding this comment.
this will break deepbuffer playback and capture during suspend, the definition to use is:
9e47005
Most SDW codec drivers don't do power down in their suspend callback. IOW the current solution applies to most codecs. We can handle the codecs that need to skip the device suspend in the future if needed. |
Operation whack-a-mole? |
0377bcf to
d247a69
Compare
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
Suspend policy is applied too broadly and required DAPM endpoints are omitted, potentially breaking wake-on-voice and deeper suspend states.
Review effort: Balanced
Findings: 6
Open (6)
Propagate suspend policy only for the active SOF suspend target · New Mark the starting DAI endpoint before walking connected widgets · New Avoid permanently ignoring suspend based only on topology compatibility Derive D0i3 retention from the actual suspend target Skip SoundWire teardown on suspend for retained streams Do not retain the bus for stopped D0i3 streams
d247a69 to
558587f
Compare
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
Suspend-ignore state is incomplete and persists beyond its valid lifecycle, causing both WoV failures and unintended bus retention.
Review effort: Balanced
Findings: 7
Open (7)
Clear or refcount widget suspend-ignore state after resume · New Mark the starting DAI endpoint before walking connected widgets Propagate suspend policy only for the active SOF suspend target Avoid permanently ignoring suspend based only on topology compatibility Derive D0i3 retention from the actual suspend target Skip SoundWire teardown on suspend for retained streams Do not retain the bus for stopped D0i3 streams
558587f to
9e0e7c2
Compare
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
Suspend-target mismatches and incomplete DAPM lifecycle handling can disable WoV paths or incorrectly keep inactive buses powered.
Review effort: Balanced
Findings: 2
Open (2)
Resolved since last review (6)
Mark the starting DAI endpoint before walking connected widgets Propagate suspend policy only for the active SOF suspend target Avoid permanently ignoring suspend based only on topology compatibility Derive D0i3 retention from the actual suspend target Skip SoundWire teardown on suspend for retained streams Do not retain the bus for stopped D0i3 streams
9e0e7c2 to
191e953
Compare
1e6f0a9 to
85dd853
Compare
85dd853 to
b23bbf5
Compare
b23bbf5 to
12804a5
Compare
12804a5 to
b8b88c7
Compare
b8b88c7 to
223704a
Compare
SOF needs to stop a frontend pipeline that was retained across S0ix when the system later transitions to S3. That frontend is already in the suspended state, so it will not receive a SUSPEND trigger, and SOF must issue the component STOP trigger directly. Export snd_soc_pcm_component_trigger() so it can be used from the SOF module. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: Bard Liao <yung-chuan.liao@linux.intel.com>
Keep connected DAPM endpoint widgets active while SOF retains a wake-on-voice PCM across suspend. Track ownership per PCM stream so shared widgets remain marked until their final WoV user releases them. Refresh DAPM endpoint path caches after changing ignore_suspend. A DROP on a suspended PCM does not issue STOP, so suspend_ignored can remain set if userspace prepares the PCM instead of resuming it. Clear suspend_ignored and release DAPM retention from hw_free and close, which may also run without START or RESUME. Clear them in prepare as a final fallback when a suspended PCM is prepared directly while suspend_ignored is still set. Signed-off-by: Bard Liao <yung-chuan.liao@linux.intel.com>
Every caller of sof_pcm_set_widget_ignore_suspend() updates the stream's suspend_ignored flag right after it: the flag is set when the DAPM widgets were successfully retained and cleared otherwise. Move these updates into sof_pcm_set_widget_ignore_suspend() so the suspend_ignored flag and the DAPM widget retention cannot get out of sync, and drop the open-coded assignments from sof_pcm_trigger() and the other callers. No functional change intended. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: Bard Liao <yung-chuan.liao@linux.intel.com>
Keep a SoundWire stream active during system suspend when it is used by a WoV stream. WoV streams can be identified by: They are capture streams and. They have the d0i3_compatible flag set and They don't use Deep Buffer. The decision is made in the BE SUSPEND trigger. The BE DAI trigger runs before the SoundWire link trigger, so the ignore_suspend flag of the SoundWire stream is updated before the link trigger decides whether to disable the stream. When a BE is shared by WoV and regular FEs, the BE only receives SUSPEND once the last FE is suspended, and all connected FEs are checked at that point regardless of their open or suspend order. A WoV PCM retained in a previous S0ix suspend stays in the SUSPENDED state and will not receive another SUSPEND trigger. If the system then enters a deeper suspend state, stop its FE and BE pipelines and release its DAPM retention at PM prepare time. Assisted-by: LLM Signed-off-by: Bard Liao <yung-chuan.liao@linux.intel.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Multiple FE streams can share a SoundWire BE, so prepare may arrive after another FE has enabled the shared stream. Skip sdw_prepare_stream() when the stream is already enabled. When hw_free is called for an enabled stream, disable it before depreparing. Propagate disable errors rather than attempting to deprepare an enabled stream. Signed-off-by: Bard Liao <yung-chuan.liao@linux.intel.com>
Two FEs sharing a BE can recover from system suspend differently: one prepares and starts again, while the other resumes. Their recovery callbacks can run concurrently. BE prepare checks the DPCM state and then calls the prepare callbacks without holding the BE stream lock used by trigger. A concurrent RESUME can therefore change the BE from SUSPEND to START and increment be_start while the other FE is still preparing. When prepare returns, it overwrites START with PREPARE. The subsequent START increments be_start to two but skips the hardware trigger and state update because it is not the first user, leaving the active BE in PREPARE. Both later STOP requests reject PREPARE, so neither decrements be_start nor stops the BE. This was observed with regular and retained capture FEs sharing a SoundWire BE: the firmware pipeline remained running and could not be reset before deletion, and the SoundWire stream remained enabled when teardown attempted to deprepare it. Serialize the state checks, prepare callbacks and PREPARE assignment with BE triggers for non-atomic PCMs, using their sleepable stream mutex. Do not hold an atomic PCM spinlock over prepare callbacks, which may sleep. Also handle the opposite recovery order. If another FE has already prepared or started the BE, RESUME must still account for its FE in be_start. Accept PREPARE and START as well as SUSPEND, and trigger only the first user. Use START when the BE has already been prepared, retaining RESUME for a BE that is still suspended. Roll back the increment if the hardware trigger fails. With POST trigger ordering, the BEs are resumed before the FE. If the FE RESUME trigger then fails, the PCM core does not undo it because the stream has not entered the running state, leaving be_start counting this FE. A later prepare and START of the FE would count it again, so the shared BE could never be stopped. Suspend the BEs again in that case. Failed START and PAUSE_RELEASE triggers are already undone by the PCM core, which issues STOP or PAUSE_PUSH through the regular DPCM path. This keeps the BE state and active-user count consistent so that only the last stopping FE shuts down the shared BE. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: Bard Liao <yung-chuan.liao@linux.intel.com>
A SoundWire capture BE shared by regular and WoV FEs can remain running across S0ix. Its HDA suspend trigger sets suspend_ignored and skips the pipeline and link DMA teardown. Recovery must consume that flag without starting the retained hardware again. The first BE trigger after system resume is not necessarily RESUME. A regular capture FE can recover through prepare followed by START. Also, when another FE has already prepared the shared BE, DPCM translates the first RESUME into START rather than resuming an unprepared stream. Only handling RESUME in the retained-stream shortcut lets START fall through to the normal HDA trigger callbacks. This unnecessarily pauses and restarts the retained IPC4 pipeline, starts the link DMA again and increments the BE pipeline's started_count even though its existing running reference was preserved during suspend. It also leaves suspend_ignored set after recovery. Consume suspend_ignored on either START or RESUME and return without retriggering the retained hardware. DPCM still accounts for the recovering FE in be_start, while the HDA pipeline keeps its existing running reference until the last BE user stops. Ordinary START triggers are unchanged when suspend_ignored is false. With IPC4 capture links the FE is triggered before the BE. If a regular FE has prepared the shared BE before a retained WoV FE resumes, the WoV FE trigger consumes its suspend_ignored flag before DPCM sends START to the BE, and its DPCM state is only updated after the trigger completes. Treat a WoV FE which is being triggered while its PCM is still SUSPENDED as resuming so the retained BE is not restarted. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: Bard Liao <yung-chuan.liao@linux.intel.com>
There was a problem hiding this comment.
🟡 Changes recommended
Legacy SoundWire retention propagation is missing, and partial backend resume failures can leak running-stream references.
5 open issues
Handle IPC failure while completing retained-stream cleanup Skip firmware IPC when cleaning up retained streams after a crash Restore each backend's prior state on frontend trigger failure Unwind partial backend resume references on failure · New Propagate retention through the legacy SoundWire trigger path · New
1 resolved since last review
Review effort: Balanced
| if (be->dpcm[stream].state != SND_SOC_DPCM_STATE_SUSPEND && | ||
| be->dpcm[stream].state != SND_SOC_DPCM_STATE_PREPARE && | ||
| be->dpcm[stream].state != SND_SOC_DPCM_STATE_START) |
| if (cmd == SNDRV_PCM_TRIGGER_SUSPEND || cmd == SNDRV_PCM_TRIGGER_STOP) | ||
| hda_dai_set_sdw_ignore_suspend(cpu_dai, substream->stream, retain); |


Wake-on-voice requires the DSP audio path to remain available while the
system is suspended. Although SOF can keep a D0i3-compatible PCM running,
SoundWire stream and Intel controller suspend handling may still disable
the stream or its bus, while DAPM may power down widgets on the path.
This series propagates the ignore-suspend requirement from SOF to the
SoundWire stream and connected DAPM widgets and keep the required
components alive during system suspend.