Skip to content

Commit

Permalink
ASoC: SOF: sof-pcm/pm: On system suspend, move the paused streams to …
Browse files Browse the repository at this point in the history
…suspended state

Paused streams will not receive a suspend trigger, they will be marked by
ALSA core as suspended and it's state is saved.
Since the pause stream is not in a fully stopped state, for example DMA
might be still enabled (just the trigger source is removed/disabled) we
need to make sure that the hardware is ready to handle the suspend.

This involves a bit more than just stopping a DMA since we also need to
communicate with the firmware in a delicate sequence to follow IP
programming flows.
To make things a bit more challenging, these flows are different between
IPC versions due to the fact that they use different messages to implement
the same functionality.

To avoid adding yet another path, callbacks and sequencing for handling the
corner case of suspending while a stream is paused, and do this for each
IPC versions and platforms, we can move the stream back to running just to
put it to suspended state.

In this way we will essentially reduce the suspend cases to two:
no audio and running audio (the paused audio becomes a running audio case),
cutting down on the probability of misaligned handling of cases.

Link: thesofproject#5035
  • Loading branch information
ujfalusi committed Jun 11, 2024
1 parent f5ad418 commit 25924f0
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 0 deletions.
58 changes: 58 additions & 0 deletions sound/soc/sof/pcm.c
Original file line number Diff line number Diff line change
Expand Up @@ -689,6 +689,64 @@ static snd_pcm_sframes_t sof_pcm_delay(struct snd_soc_component *component,
return 0;
}

int sof_pcm_suspend_paused(struct snd_sof_dev *sdev)
{
struct snd_pcm_substream *substream;
struct snd_sof_pcm *spcm;
int dir, ret;

/*
* Search for streams which was in paused state at suspend to properly
* suspend it.
* Due to the differences in flows between IPC versions it is preferred
* to use the high level pcm ops to move the stream to running then to
* suspended instead of trying to hand-replicate the flows.
*/
list_for_each_entry(spcm, &sdev->pcm_list, list) {
for_each_pcm_streams(dir) {
substream = spcm->stream[dir].substream;
if (!substream || !substream->runtime)
continue;

/*
* Paused streams will not receive a suspend trigger
* but moved to suspended state.
*/
if (!(substream->runtime->state == SNDRV_PCM_STATE_SUSPENDED &&
substream->runtime->suspended_state == SNDRV_PCM_STATE_PAUSED))
continue;

/*
* The stream needs to be released and then suspended to
* make sure that it is in a state where it can handle
* the system suspend
*/
ret = substream->ops->trigger(substream,
SNDRV_PCM_TRIGGER_PAUSE_RELEASE);
if (ret) {
dev_err(sdev->dev,
"%s: PAUSE_RELEASE failed for %s (id: %d): %d\n",
__func__, substream->name,
spcm->pcm.pcm_id, ret);
return ret;
}

ret = substream->ops->trigger(substream,
SNDRV_PCM_TRIGGER_SUSPEND);
if (ret) {
dev_err(sdev->dev,
"%s: SUSPEND failed for %s (id: %d): %d\n",
__func__, substream->name,
spcm->pcm.pcm_id, ret);
return ret;
}
}
}

return 0;
}
EXPORT_SYMBOL(sof_pcm_suspend_paused);

void snd_sof_new_platform_drv(struct snd_sof_dev *sdev)
{
struct snd_soc_component_driver *pd = &sdev->plat_drv;
Expand Down
10 changes: 10 additions & 0 deletions sound/soc/sof/pm.c
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,16 @@ static int sof_suspend(struct device *dev, bool runtime_suspend)
if (runtime_suspend && !sof_ops(sdev)->runtime_suspend)
return 0;

/*
* On system suspend we need to properly suspend paused streams since
* they have not receiving a suspend trigger.
*/
if (!runtime_suspend) {
ret = sof_pcm_suspend_paused(sdev);
if (ret < 0)
return ret;
}

/* Prepare the DSP for system suspend */
if (!runtime_suspend) {
ret = snd_sof_dsp_suspend_early(sdev);
Expand Down
1 change: 1 addition & 0 deletions sound/soc/sof/sof-priv.h
Original file line number Diff line number Diff line change
Expand Up @@ -703,6 +703,7 @@ int snd_sof_prepare(struct device *dev);
void snd_sof_complete(struct device *dev);

void snd_sof_new_platform_drv(struct snd_sof_dev *sdev);
int sof_pcm_suspend_paused(struct snd_sof_dev *sdev);

/*
* Compress support
Expand Down

0 comments on commit 25924f0

Please sign in to comment.