diff --git a/sound/soc/sof/ipc3-topology.c b/sound/soc/sof/ipc3-topology.c index 2c7a5e7a364c..d96555438c6b 100644 --- a/sound/soc/sof/ipc3-topology.c +++ b/sound/soc/sof/ipc3-topology.c @@ -2309,6 +2309,44 @@ static int sof_tear_down_left_over_pipelines(struct snd_sof_dev *sdev) return 0; } +static int sof_ipc3_free_widgets_in_list(struct snd_sof_dev *sdev, bool include_scheduler, + bool *dyn_widgets, bool verify) +{ + struct sof_ipc_fw_version *v = &sdev->fw_ready.version; + struct snd_sof_widget *swidget; + int ret; + + list_for_each_entry(swidget, &sdev->widget_list, list) { + if (swidget->dynamic_pipeline_widget) { + *dyn_widgets = true; + continue; + } + + /* Do not free widgets for static pipelines with FW older than SOF2.2 */ + if (!verify && !swidget->dynamic_pipeline_widget && + SOF_FW_VER(v->major, v->minor, v->micro) < SOF_FW_VER(2, 2, 0)) { + mutex_lock(&swidget->setup_mutex); + swidget->use_count = 0; + mutex_unlock(&swidget->setup_mutex); + if (swidget->spipe) + swidget->spipe->complete = 0; + continue; + } + + if (include_scheduler && swidget->id != snd_soc_dapm_scheduler) + continue; + + if (!include_scheduler && swidget->id == snd_soc_dapm_scheduler) + continue; + + ret = sof_widget_free(sdev, swidget); + if (ret < 0) + return ret; + } + + return 0; +} + /* * For older firmware, this function doesn't free widgets for static pipelines during suspend. * It only resets use_count for all widgets. @@ -2325,29 +2363,18 @@ static int sof_ipc3_tear_down_all_pipelines(struct snd_sof_dev *sdev, bool verif * This function is called during suspend and for one-time topology verification during * first boot. In both cases, there is no need to protect swidget->use_count and * sroute->setup because during suspend all running streams are suspended and during - * topology loading the sound card unavailable to open PCMs. + * topology loading the sound card unavailable to open PCMs. Do not free the scheduler + * widgets yet so that the secondary cores do not get powered down before all the widgets + * associated with the scheduler are freed. */ - list_for_each_entry(swidget, &sdev->widget_list, list) { - if (swidget->dynamic_pipeline_widget) { - dyn_widgets = true; - continue; - } + ret = sof_ipc3_free_widgets_in_list(sdev, false, &dyn_widgets, verify); + if (ret < 0) + return ret; - /* Do not free widgets for static pipelines with FW older than SOF2.2 */ - if (!verify && !swidget->dynamic_pipeline_widget && - SOF_FW_VER(v->major, v->minor, v->micro) < SOF_FW_VER(2, 2, 0)) { - mutex_lock(&swidget->setup_mutex); - swidget->use_count = 0; - mutex_unlock(&swidget->setup_mutex); - if (swidget->spipe) - swidget->spipe->complete = 0; - continue; - } - - ret = sof_widget_free(sdev, swidget); - if (ret < 0) - return ret; - } + /* free all the scheduler widgets now */ + ret = sof_ipc3_free_widgets_in_list(sdev, true, &dyn_widgets, verify); + if (ret < 0) + return ret; /* * Tear down all pipelines associated with PCMs that did not get suspended