return NULL;
}
-int sof_set_up_pipelines(struct device *dev)
+int sof_set_up_pipelines(struct device *dev, bool verify)
{
struct snd_sof_dev *sdev = dev_get_drvdata(dev);
struct snd_sof_widget *swidget;
/* restore pipeline components */
list_for_each_entry_reverse(swidget, &sdev->widget_list, list) {
/* only set up the widgets belonging to static pipelines */
- if (swidget->dynamic_pipeline_widget)
+ if (!verify && swidget->dynamic_pipeline_widget)
continue;
/* update DAI config. The IPC will be sent in sof_widget_setup() */
list_for_each_entry(sroute, &sdev->route_list, list) {
/* only set up routes belonging to static pipelines */
- if (sroute->src_widget->dynamic_pipeline_widget ||
- sroute->sink_widget->dynamic_pipeline_widget)
+ if (!verify && (sroute->src_widget->dynamic_pipeline_widget ||
+ sroute->sink_widget->dynamic_pipeline_widget))
continue;
ret = sof_route_setup_ipc(sdev, sroute);
switch (swidget->id) {
case snd_soc_dapm_scheduler:
/* only complete static pipelines */
- if (swidget->dynamic_pipeline_widget)
+ if (!verify && swidget->dynamic_pipeline_widget)
continue;
swidget->complete =
}
/*
- * This function doesn't free widgets. It only resets the set up status for all routes and
- * use_count for all widgets.
+ * This function doesn't free widgets during suspend. It only resets the set up status for all
+ * routes and use_count for all widgets.
*/
-void sof_tear_down_pipelines(struct device *dev)
+int sof_tear_down_pipelines(struct device *dev, bool verify)
{
struct snd_sof_dev *sdev = dev_get_drvdata(dev);
struct snd_sof_widget *swidget;
struct snd_sof_route *sroute;
+ int ret;
/*
- * No need to protect swidget->use_count and sroute->setup as this function is called only
- * during the suspend callback and all streams should be suspended by then
+ * 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 streams are suspended and during topology
+ * loading the sound card unavailable to open PCMs.
*/
- list_for_each_entry(swidget, &sdev->widget_list, list)
- swidget->use_count = 0;
+ list_for_each_entry_reverse(swidget, &sdev->widget_list, list) {
+ if (!verify) {
+ swidget->use_count = 0;
+ continue;
+ }
+
+ ret = sof_widget_free(sdev, swidget);
+ if (ret < 0)
+ return ret;
+ }
list_for_each_entry(sroute, &sdev->route_list, list)
sroute->setup = false;
+
+ return 0;
}
/*
int sof_pcm_dai_link_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hw_params *params);
/* PM */
-int sof_set_up_pipelines(struct device *dev);
-void sof_tear_down_pipelines(struct device *dev);
+int sof_set_up_pipelines(struct device *dev, bool verify);
+int sof_tear_down_pipelines(struct device *dev, bool verify);
int sof_set_hw_params_upon_resume(struct device *dev);
bool snd_sof_stream_suspend_ignored(struct snd_sof_dev *sdev);
bool snd_sof_dsp_only_d0i3_compatible_stream_active(struct snd_sof_dev *sdev);
}
}
+ /* verify topology components loading including dynamic pipelines */
+ if (sof_core_debug & SOF_DBG_VERIFY_TPLG) {
+ ret = sof_set_up_pipelines(scomp->dev, true);
+ if (ret < 0) {
+ dev_err(sdev->dev, "error: topology verification failed %d\n", ret);
+ return ret;
+ }
+
+ ret = sof_tear_down_pipelines(scomp->dev, true);
+ if (ret < 0) {
+ dev_err(sdev->dev, "error: topology tear down pipelines failed %d\n", ret);
+ return ret;
+ }
+ }
+
/* set up static pipelines */
- return sof_set_up_pipelines(scomp->dev);
+ return sof_set_up_pipelines(scomp->dev, false);
}
/* manifest - optional to inform component of manifest */