Skip to content

Commit 31cd6e4

Browse files
ranj063broonie
authored andcommitted
ASoC: SOF: topology: Add ops for setting up and tearing down pipelines
Introduce two new ops, set_up_all_pipelines and tear_down_all_pipelines in struct ipc_tplg_ops and define these for IPC3. Signed-off-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com> Reviewed-by: Péter Ujfalusi <peter.ujfalusi@linux.intel.com> Reviewed-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com> Reviewed-by: Bard Liao <yung-chuan.liao@linux.intel.com> Link: https://lore.kernel.org/r/20220317175044.1752400-19-ranjani.sridharan@linux.intel.com Signed-off-by: Mark Brown <broonie@kernel.org>
1 parent 3816bbe commit 31cd6e4

5 files changed

Lines changed: 235 additions & 226 deletions

File tree

sound/soc/sof/ipc3-topology.c

Lines changed: 197 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2057,6 +2057,201 @@ static int sof_ipc3_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget
20572057
return ret;
20582058
}
20592059

2060+
static int sof_ipc3_set_up_all_pipelines(struct snd_sof_dev *sdev, bool verify)
2061+
{
2062+
struct sof_ipc_fw_version *v = &sdev->fw_ready.version;
2063+
struct snd_sof_widget *swidget;
2064+
struct snd_sof_route *sroute;
2065+
int ret;
2066+
2067+
/* restore pipeline components */
2068+
list_for_each_entry(swidget, &sdev->widget_list, list) {
2069+
/* only set up the widgets belonging to static pipelines */
2070+
if (!verify && swidget->dynamic_pipeline_widget)
2071+
continue;
2072+
2073+
/*
2074+
* For older firmware, skip scheduler widgets in this loop,
2075+
* sof_widget_setup() will be called in the 'complete pipeline' loop
2076+
*/
2077+
if (v->abi_version < SOF_ABI_VER(3, 19, 0) &&
2078+
swidget->id == snd_soc_dapm_scheduler)
2079+
continue;
2080+
2081+
/* update DAI config. The IPC will be sent in sof_widget_setup() */
2082+
if (WIDGET_IS_DAI(swidget->id)) {
2083+
struct snd_sof_dai *dai = swidget->private;
2084+
struct sof_dai_private_data *private;
2085+
struct sof_ipc_dai_config *config;
2086+
2087+
if (!dai || !dai->private)
2088+
continue;
2089+
private = dai->private;
2090+
if (!private->dai_config)
2091+
continue;
2092+
2093+
config = private->dai_config;
2094+
/*
2095+
* The link DMA channel would be invalidated for running
2096+
* streams but not for streams that were in the PAUSED
2097+
* state during suspend. So invalidate it here before setting
2098+
* the dai config in the DSP.
2099+
*/
2100+
if (config->type == SOF_DAI_INTEL_HDA)
2101+
config->hda.link_dma_ch = DMA_CHAN_INVALID;
2102+
}
2103+
2104+
ret = sof_widget_setup(sdev, swidget);
2105+
if (ret < 0)
2106+
return ret;
2107+
}
2108+
2109+
/* restore pipeline connections */
2110+
list_for_each_entry(sroute, &sdev->route_list, list) {
2111+
/* only set up routes belonging to static pipelines */
2112+
if (!verify && (sroute->src_widget->dynamic_pipeline_widget ||
2113+
sroute->sink_widget->dynamic_pipeline_widget))
2114+
continue;
2115+
2116+
/*
2117+
* For virtual routes, both sink and source are not buffer. IPC3 only supports
2118+
* connections between a buffer and a component. Ignore the rest.
2119+
*/
2120+
if (sroute->src_widget->id != snd_soc_dapm_buffer &&
2121+
sroute->sink_widget->id != snd_soc_dapm_buffer)
2122+
continue;
2123+
2124+
ret = sof_route_setup(sdev, sroute->src_widget->widget,
2125+
sroute->sink_widget->widget);
2126+
if (ret < 0) {
2127+
dev_err(sdev->dev, "%s: route set up failed\n", __func__);
2128+
return ret;
2129+
}
2130+
}
2131+
2132+
/* complete pipeline */
2133+
list_for_each_entry(swidget, &sdev->widget_list, list) {
2134+
switch (swidget->id) {
2135+
case snd_soc_dapm_scheduler:
2136+
/* only complete static pipelines */
2137+
if (!verify && swidget->dynamic_pipeline_widget)
2138+
continue;
2139+
2140+
if (v->abi_version < SOF_ABI_VER(3, 19, 0)) {
2141+
ret = sof_widget_setup(sdev, swidget);
2142+
if (ret < 0)
2143+
return ret;
2144+
}
2145+
2146+
swidget->complete = sof_ipc3_complete_pipeline(sdev, swidget);
2147+
if (swidget->complete < 0)
2148+
return swidget->complete;
2149+
break;
2150+
default:
2151+
break;
2152+
}
2153+
}
2154+
2155+
return 0;
2156+
}
2157+
2158+
/*
2159+
* Free the PCM, its associated widgets and set the prepared flag to false for all PCMs that
2160+
* did not get suspended(ex: paused streams) so the widgets can be set up again during resume.
2161+
*/
2162+
static int sof_tear_down_left_over_pipelines(struct snd_sof_dev *sdev)
2163+
{
2164+
struct snd_sof_widget *swidget;
2165+
struct snd_sof_pcm *spcm;
2166+
int dir, ret;
2167+
2168+
/*
2169+
* free all PCMs and their associated DAPM widgets if their connected DAPM widget
2170+
* list is not NULL. This should only be true for paused streams at this point.
2171+
* This is equivalent to the handling of FE DAI suspend trigger for running streams.
2172+
*/
2173+
list_for_each_entry(spcm, &sdev->pcm_list, list) {
2174+
for_each_pcm_streams(dir) {
2175+
struct snd_pcm_substream *substream = spcm->stream[dir].substream;
2176+
2177+
if (!substream || !substream->runtime)
2178+
continue;
2179+
2180+
if (spcm->stream[dir].list) {
2181+
ret = sof_pcm_stream_free(sdev, substream, spcm, dir, true);
2182+
if (ret < 0)
2183+
return ret;
2184+
}
2185+
}
2186+
}
2187+
2188+
/*
2189+
* free any left over DAI widgets. This is equivalent to the handling of suspend trigger
2190+
* for the BE DAI for running streams.
2191+
*/
2192+
list_for_each_entry(swidget, &sdev->widget_list, list)
2193+
if (WIDGET_IS_DAI(swidget->id) && swidget->use_count == 1) {
2194+
ret = sof_widget_free(sdev, swidget);
2195+
if (ret < 0)
2196+
return ret;
2197+
}
2198+
2199+
return 0;
2200+
}
2201+
2202+
/*
2203+
* For older firmware, this function doesn't free widgets for static pipelines during suspend.
2204+
* It only resets use_count for all widgets.
2205+
*/
2206+
static int sof_ipc3_tear_down_all_pipelines(struct snd_sof_dev *sdev, bool verify)
2207+
{
2208+
struct sof_ipc_fw_version *v = &sdev->fw_ready.version;
2209+
struct snd_sof_widget *swidget;
2210+
struct snd_sof_route *sroute;
2211+
int ret;
2212+
2213+
/*
2214+
* This function is called during suspend and for one-time topology verification during
2215+
* first boot. In both cases, there is no need to protect swidget->use_count and
2216+
* sroute->setup because during suspend all running streams are suspended and during
2217+
* topology loading the sound card unavailable to open PCMs.
2218+
*/
2219+
list_for_each_entry(swidget, &sdev->widget_list, list) {
2220+
if (swidget->dynamic_pipeline_widget)
2221+
continue;
2222+
2223+
/* Do not free widgets for static pipelines with FW ABI older than 3.19 */
2224+
if (!verify && !swidget->dynamic_pipeline_widget &&
2225+
v->abi_version < SOF_ABI_VER(3, 19, 0)) {
2226+
swidget->use_count = 0;
2227+
swidget->complete = 0;
2228+
continue;
2229+
}
2230+
2231+
ret = sof_widget_free(sdev, swidget);
2232+
if (ret < 0)
2233+
return ret;
2234+
}
2235+
2236+
/*
2237+
* Tear down all pipelines associated with PCMs that did not get suspended
2238+
* and unset the prepare flag so that they can be set up again during resume.
2239+
* Skip this step for older firmware.
2240+
*/
2241+
if (!verify && v->abi_version >= SOF_ABI_VER(3, 19, 0)) {
2242+
ret = sof_tear_down_left_over_pipelines(sdev);
2243+
if (ret < 0) {
2244+
dev_err(sdev->dev, "failed to tear down paused pipelines\n");
2245+
return ret;
2246+
}
2247+
}
2248+
2249+
list_for_each_entry(sroute, &sdev->route_list, list)
2250+
sroute->setup = false;
2251+
2252+
return 0;
2253+
}
2254+
20602255
/* token list for each topology object */
20612256
static enum sof_tokens host_token_list[] = {
20622257
SOF_CORE_TOKENS,
@@ -2164,4 +2359,6 @@ const struct sof_ipc_tplg_ops ipc3_tplg_ops = {
21642359
.widget_free = sof_ipc3_widget_free,
21652360
.widget_setup = sof_ipc3_widget_setup,
21662361
.dai_config = sof_ipc3_dai_config,
2362+
.set_up_all_pipelines = sof_ipc3_set_up_all_pipelines,
2363+
.tear_down_all_pipelines = sof_ipc3_tear_down_all_pipelines,
21672364
};

sound/soc/sof/pm.c

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ static int sof_resume(struct device *dev, bool runtime_resume)
7171
{
7272
struct snd_sof_dev *sdev = dev_get_drvdata(dev);
7373
const struct sof_ipc_pm_ops *pm_ops = sdev->ipc->ops->pm;
74+
const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg;
7475
u32 old_state = sdev->dsp_power_state.state;
7576
int ret;
7677

@@ -144,12 +145,12 @@ static int sof_resume(struct device *dev, bool runtime_resume)
144145
}
145146

146147
/* restore pipelines */
147-
ret = sof_set_up_pipelines(sdev, false);
148-
if (ret < 0) {
149-
dev_err(sdev->dev,
150-
"error: failed to restore pipeline after resume %d\n",
151-
ret);
152-
return ret;
148+
if (tplg_ops->set_up_all_pipelines) {
149+
ret = tplg_ops->set_up_all_pipelines(sdev, false);
150+
if (ret < 0) {
151+
dev_err(sdev->dev, "Failed to restore pipeline after resume %d\n", ret);
152+
return ret;
153+
}
153154
}
154155

155156
/* Notify clients not managed by pm framework about core resume */
@@ -169,6 +170,7 @@ static int sof_suspend(struct device *dev, bool runtime_suspend)
169170
{
170171
struct snd_sof_dev *sdev = dev_get_drvdata(dev);
171172
const struct sof_ipc_pm_ops *pm_ops = sdev->ipc->ops->pm;
173+
const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg;
172174
pm_message_t pm_state;
173175
u32 target_state = 0;
174176
int ret;
@@ -204,7 +206,8 @@ static int sof_suspend(struct device *dev, bool runtime_suspend)
204206
goto suspend;
205207
}
206208

207-
sof_tear_down_pipelines(sdev, false);
209+
if (tplg_ops->tear_down_all_pipelines)
210+
tplg_ops->tear_down_all_pipelines(sdev, false);
208211

209212
/* release trace */
210213
snd_sof_release_trace(sdev);

0 commit comments

Comments
 (0)