Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions drivers/soundwire/intel.c
Original file line number Diff line number Diff line change
Expand Up @@ -953,6 +953,9 @@ static int intel_component_dais_suspend(struct snd_soc_component *component)
struct sdw_cdns *cdns = snd_soc_dai_get_drvdata(dai);
struct sdw_cdns_dai_runtime *dai_runtime;

if (sdw_bus_ignore_suspend(&cdns->bus))
continue;

dai_runtime = cdns->dai_runtime_array[dai->id];

if (dai_runtime)
Expand Down
3 changes: 3 additions & 0 deletions drivers/soundwire/intel_ace2x.c
Original file line number Diff line number Diff line change
Expand Up @@ -952,6 +952,9 @@ static int intel_component_dais_suspend(struct snd_soc_component *component)
struct sdw_cdns *cdns = snd_soc_dai_get_drvdata(dai);
struct sdw_cdns_dai_runtime *dai_runtime;

if (sdw_bus_ignore_suspend(&cdns->bus))
continue;

dai_runtime = cdns->dai_runtime_array[dai->id];

if (dai_runtime)
Expand Down
9 changes: 9 additions & 0 deletions drivers/soundwire/intel_auxdevice.c
Original file line number Diff line number Diff line change
Expand Up @@ -647,6 +647,9 @@ static int __maybe_unused intel_suspend(struct device *dev)
return 0;
}

if (sdw_bus_ignore_suspend(bus))
return 0;

/* Prevent runtime PM from racing with the code below. */
pm_runtime_disable(dev);

Expand Down Expand Up @@ -734,6 +737,12 @@ static int __maybe_unused intel_resume(struct device *dev)
return 0;
}

if (sdw_bus_ignore_suspend(bus)) {
dev_dbg(dev, "SoundWire master %d remained active during system suspend\n",
bus->link_id);
return 0;
}

ret = sdw_intel_link_power_up(sdw);
if (ret) {
dev_err(dev, "%s failed: %d\n", __func__, ret);
Expand Down
19 changes: 19 additions & 0 deletions drivers/soundwire/stream.c
Original file line number Diff line number Diff line change
Expand Up @@ -1679,6 +1679,25 @@ int sdw_enable_stream(struct sdw_stream_runtime *stream)
}
EXPORT_SYMBOL(sdw_enable_stream);

bool sdw_bus_ignore_suspend(struct sdw_bus *bus)
{
struct sdw_master_runtime *m_rt;
bool ret = false;

mutex_lock(&bus->bus_lock);
list_for_each_entry(m_rt, &bus->m_rt_list, bus_node) {
if (m_rt->stream->state == SDW_STREAM_ENABLED &&
m_rt->stream->ignore_suspend) {
ret = true;
break;
}
}
mutex_unlock(&bus->bus_lock);

return ret;
}
EXPORT_SYMBOL(sdw_bus_ignore_suspend);

static int _sdw_disable_stream(struct sdw_stream_runtime *stream)
{
struct sdw_master_runtime *m_rt;
Expand Down
3 changes: 3 additions & 0 deletions include/linux/soundwire/sdw.h
Original file line number Diff line number Diff line change
Expand Up @@ -976,6 +976,7 @@ struct sdw_stream_params {
* @master_list: List of Master runtime(s) in this stream.
* master_list can contain only one m_rt per Master instance
* for a stream
* @ignore_suspend: stream keeps running during system suspend
*/
struct sdw_stream_runtime {
const char *name;
Expand All @@ -984,6 +985,7 @@ struct sdw_stream_runtime {
enum sdw_stream_type type;
int m_rt_count;
struct list_head master_list;
bool ignore_suspend;
};

/**
Expand Down Expand Up @@ -1086,6 +1088,7 @@ int sdw_stream_remove_master(struct sdw_bus *bus,
int sdw_startup_stream(void *sdw_substream);
int sdw_prepare_stream(struct sdw_stream_runtime *stream);
int sdw_enable_stream(struct sdw_stream_runtime *stream);
bool sdw_bus_ignore_suspend(struct sdw_bus *bus);
int sdw_disable_stream(struct sdw_stream_runtime *stream);
int sdw_deprepare_stream(struct sdw_stream_runtime *stream);
void sdw_shutdown_stream(void *sdw_substream);
Expand Down
21 changes: 20 additions & 1 deletion sound/soc/sdw_utils/soc_sdw_utils.c
Original file line number Diff line number Diff line change
Expand Up @@ -1880,6 +1880,9 @@ int asoc_sdw_prepare(struct snd_pcm_substream *substream)
return PTR_ERR(sdw_stream);
}

if (sdw_stream->state == SDW_STREAM_ENABLED)
return 0;

return sdw_prepare_stream(sdw_stream);
}
EXPORT_SYMBOL_NS(asoc_sdw_prepare, "SND_SOC_SDW_UTILS");
Expand All @@ -1902,6 +1905,10 @@ int asoc_sdw_trigger(struct snd_pcm_substream *substream, int cmd)

switch (cmd) {
case SNDRV_PCM_TRIGGER_RESUME:
if (sdw_stream->state == SDW_STREAM_ENABLED) {
ret = 0;
break;
}
/*
* The peripherals lose their port configuration when the
* controller is power-gated during system suspend, and an
Expand All @@ -1923,10 +1930,12 @@ int asoc_sdw_trigger(struct snd_pcm_substream *substream, int cmd)
break;

case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_STOP:
ret = sdw_disable_stream(sdw_stream);
break;
case SNDRV_PCM_TRIGGER_SUSPEND:
ret = sdw_stream->ignore_suspend ? 0 : sdw_disable_stream(sdw_stream);
Comment thread
bardliao marked this conversation as resolved.
break;
default:
ret = -EINVAL;
break;
Expand Down Expand Up @@ -2005,6 +2014,16 @@ int asoc_sdw_hw_free(struct snd_pcm_substream *substream)
return PTR_ERR(sdw_stream);
}

if (sdw_stream->state == SDW_STREAM_ENABLED) {
int ret;

ret = sdw_disable_stream(sdw_stream);
if (ret) {
dev_err(rtd->dev, "failed to disable SoundWire stream: %d\n", ret);
return ret;
}
}

return sdw_deprepare_stream(sdw_stream);
}
EXPORT_SYMBOL_NS(asoc_sdw_hw_free, "SND_SOC_SDW_UTILS");
Expand Down
1 change: 1 addition & 0 deletions sound/soc/soc-component.c
Original file line number Diff line number Diff line change
Expand Up @@ -1224,6 +1224,7 @@ int snd_soc_pcm_component_trigger(struct snd_pcm_substream *substream,

return ret;
}
EXPORT_SYMBOL_GPL(snd_soc_pcm_component_trigger);

int snd_soc_pcm_component_pm_runtime_get(struct snd_soc_pcm_runtime *rtd,
void *stream)
Expand Down
48 changes: 42 additions & 6 deletions sound/soc/soc-pcm.c
Original file line number Diff line number Diff line change
Expand Up @@ -2266,14 +2266,22 @@ int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream,
be->dpcm[stream].state = SND_SOC_DPCM_STATE_START;
break;
case SNDRV_PCM_TRIGGER_RESUME:
if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_SUSPEND))
/*
* Another FE may already have prepared or restarted the BE.
* Count this FE as well, but only trigger the first user.
*/
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)
Comment thread
Copilot marked this conversation as resolved.
Comment on lines +2273 to +2275
goto next;

be->dpcm[stream].be_start++;
if (be->dpcm[stream].be_start != 1)
goto next;

ret = soc_pcm_trigger(be_substream, cmd);
ret = soc_pcm_trigger(be_substream,
be->dpcm[stream].state == SND_SOC_DPCM_STATE_PREPARE ?
SNDRV_PCM_TRIGGER_START : cmd);
if (ret) {
be->dpcm[stream].be_start--;
goto next;
Expand Down Expand Up @@ -2413,6 +2421,21 @@ static int dpcm_dai_trigger_fe_be(struct snd_pcm_substream *substream,
fe->dai_link->name, cmd);

ret = soc_pcm_trigger(substream, cmd);
/*
* The PCM core undoes failed START and PAUSE_RELEASE triggers,
* but not RESUME because the stream is not running yet. Drop
* the BE reference taken for this FE so be_start stays balanced.
*/
if (ret < 0 && cmd == SNDRV_PCM_TRIGGER_RESUME) {
int rollback_ret;

rollback_ret = dpcm_be_dai_trigger(fe, substream->stream,
SNDRV_PCM_TRIGGER_SUSPEND);
if (rollback_ret < 0)
dev_err(fe->dev,
"failed to roll back BE resume after FE trigger failure: %d\n",
rollback_ret);
}
}
end:
return snd_soc_ret(fe->dev, ret, "trigger FE cmd: %d failed\n", cmd);
Expand Down Expand Up @@ -2502,6 +2525,7 @@ static int dpcm_fe_dai_trigger(struct snd_pcm_substream *substream, int cmd)
int dpcm_be_dai_prepare(struct snd_soc_pcm_runtime *fe, int stream)
{
struct snd_soc_dpcm *dpcm;
unsigned long flags = 0;
int ret = 0;

for_each_dpcm_be(fe, stream, dpcm) {
Expand All @@ -2510,27 +2534,39 @@ int dpcm_be_dai_prepare(struct snd_soc_pcm_runtime *fe, int stream)
struct snd_pcm_substream *be_substream =
snd_soc_dpcm_get_substream(be, stream);

/*
* Non-atomic prepare callbacks may sleep. Serialize them with
* BE triggers using the stream mutex, not an atomic stream lock.
*/
if (be_substream->pcm->nonatomic)
snd_pcm_stream_lock_irqsave_nested(be_substream, flags);

/* is this op for this BE ? */
if (!snd_soc_dpcm_can_be_update(fe, be, stream))
continue;
goto next;

if (!snd_soc_dpcm_can_be_prepared(fe, be, stream))
continue;
goto next;

if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) &&
(be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP) &&
(be->dpcm[stream].state != SND_SOC_DPCM_STATE_SUSPEND) &&
(be->dpcm[stream].state != SND_SOC_DPCM_STATE_PAUSED))
continue;
goto next;

dev_dbg(be->dev, "ASoC: prepare BE %s\n",
be->dai_link->name);

ret = __soc_pcm_prepare(be, be_substream);
if (ret < 0)
break;
goto next;

be->dpcm[stream].state = SND_SOC_DPCM_STATE_PREPARE;
next:
if (be_substream->pcm->nonatomic)
snd_pcm_stream_unlock_irqrestore(be_substream, flags);
if (ret < 0)
break;
}

/*
Expand Down
8 changes: 8 additions & 0 deletions sound/soc/sof/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -690,6 +690,7 @@ int snd_sof_device_probe(struct device *dev, struct snd_sof_pdata *plat_data)
INIT_LIST_HEAD(&sdev->dai_list);
INIT_LIST_HEAD(&sdev->dai_link_list);
INIT_LIST_HEAD(&sdev->route_list);
INIT_LIST_HEAD(&sdev->ignore_suspend_widget_list);
INIT_LIST_HEAD(&sdev->ipc_client_list);
INIT_LIST_HEAD(&sdev->ipc_rx_handler_list);
INIT_LIST_HEAD(&sdev->fw_state_handler_list);
Expand Down Expand Up @@ -751,6 +752,7 @@ int snd_sof_device_remove(struct device *dev)
{
struct snd_sof_dev *sdev = dev_get_drvdata(dev);
struct snd_sof_pdata *pdata = sdev->pdata;
struct snd_sof_ignore_suspend_widget *isw, *tmp;
int ret;
bool aborted = false;

Expand All @@ -770,6 +772,12 @@ int snd_sof_device_remove(struct device *dev)
*/
snd_sof_machine_unregister(sdev, pdata);

/* topology is unloaded by now, free any leftover ignore_suspend widget entries */
list_for_each_entry_safe(isw, tmp, &sdev->ignore_suspend_widget_list, list) {
list_del(&isw->list);
kfree(isw);
}

/*
* Balance the runtime pm usage count in case we are faced with an
* exception and we forcably prevented D3 power state to preserve
Expand Down
4 changes: 4 additions & 0 deletions sound/soc/sof/intel/hda-dai-ops.c
Original file line number Diff line number Diff line change
Expand Up @@ -580,6 +580,10 @@ static int hda_ipc3_post_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *c
{
struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(cpu_dai, substream->stream);

if (sdev->fw_state != SOF_FW_BOOT_COMPLETE &&
(cmd == SNDRV_PCM_TRIGGER_STOP || cmd == SNDRV_PCM_TRIGGER_SUSPEND))
return 0;

switch (cmd) {
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_STOP:
Expand Down
Loading
Loading