Skip to content

Commit 27547a3

Browse files
committed
Merge series "Add support for on demand pipeline setup/destroy" from Peter Ujfalusi <peter.ujfalusi@linux.intel.com>:
Hi, The previous, v2 of this series was sent by Daniel Baluta: https://lore.kernel.org/alsa-devel/20210917143659.401102-1-daniel.baluta@oss.nxp.com/ We have agreed that it might be better that someone from Intel is going to take it from here as we already have the infrastructure up to test and verify the dynamic pipelines support. Changes since v2 (sent by Daniel Baluta): - patch 10: Fix NULL point dereference in hda_dai_update_config() - I have kept Daniel's SoB for the series. Changes since v1: - Signed-off-by tag added by Daniel This series implements initial support for dynamic pipelines to setup/teardown pipeline as needed when a PCM is open/closed. Initially dynamic pipelines are only supported with single core setup which will be expanded with a follow-up series. Review with SOF community at thesofproject/linux#2794 The feature has been merged on 1st of April to sof-dev, all issues found since has been fixed and squashed to this upstream series. Regards, Peter --- Ranjani Sridharan (12): ASoC: topology: change the complete op in snd_soc_tplg_ops to return int ASoC: SOF: control: Add access field in struct snd_sof_control ASoC: SOF: topology: Add new token for dynamic pipeline ASoC: SOF: sof-audio: add helpers for widgets, kcontrols and dai config set up AsoC: dapm: export a couple of functions ASoC: SOF: Add new fields to snd_sof_route ASoC: SOF: restore kcontrols for widget during set up ASoC: SOF: Don't set up widgets during topology parsing ASoC: SOF: Introduce widget use_count ASoC: SOF: Intel: hda: make sure DAI widget is set up before IPC ASoC: SOF: Add support for dynamic pipelines ASoC: SOF: topology: Add kernel parameter for topology verification include/sound/soc-dpcm.h | 1 + include/sound/soc-topology.h | 2 +- include/uapi/sound/sof/tokens.h | 1 + sound/soc/intel/skylake/skl-topology.c | 6 +- sound/soc/soc-dapm.c | 2 + sound/soc/soc-pcm.c | 4 +- sound/soc/soc-topology.c | 10 +- sound/soc/sof/intel/hda-dai.c | 174 +++--- sound/soc/sof/intel/hda.c | 177 ++++-- sound/soc/sof/intel/hda.h | 5 + sound/soc/sof/ipc.c | 22 + sound/soc/sof/pcm.c | 58 +- sound/soc/sof/pm.c | 4 +- sound/soc/sof/sof-audio.c | 709 +++++++++++++++++++------ sound/soc/sof/sof-audio.h | 32 +- sound/soc/sof/sof-priv.h | 1 + sound/soc/sof/topology.c | 362 +++++-------- 17 files changed, 1032 insertions(+), 538 deletions(-) -- 2.33.0
2 parents 83bea08 + c0e7969 commit 27547a3

File tree

17 files changed

+1032
-538
lines changed

17 files changed

+1032
-538
lines changed

include/sound/soc-dpcm.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,7 @@ int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream, int cmd);
159159
int dpcm_be_dai_prepare(struct snd_soc_pcm_runtime *fe, int stream);
160160
int dpcm_dapm_stream_event(struct snd_soc_pcm_runtime *fe, int dir,
161161
int event);
162+
bool dpcm_end_walk_at_be(struct snd_soc_dapm_widget *widget, enum snd_soc_dapm_direction dir);
162163

163164
#define dpcm_be_dai_startup_rollback(fe, stream, last) \
164165
dpcm_be_dai_stop(fe, stream, 0, last)

include/sound/soc-topology.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ struct snd_soc_tplg_ops {
151151
struct snd_soc_tplg_hdr *);
152152

153153
/* completion - called at completion of firmware loading */
154-
void (*complete)(struct snd_soc_component *);
154+
int (*complete)(struct snd_soc_component *comp);
155155

156156
/* manifest - optional to inform component of manifest */
157157
int (*manifest)(struct snd_soc_component *, int index,

include/uapi/sound/sof/tokens.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
#define SOF_TKN_SCHED_CORE 203
5252
#define SOF_TKN_SCHED_FRAMES 204
5353
#define SOF_TKN_SCHED_TIME_DOMAIN 205
54+
#define SOF_TKN_SCHED_DYNAMIC_PIPELINE 206
5455

5556
/* volume */
5657
#define SOF_TKN_VOLUME_RAMP_STEP_TYPE 250

sound/soc/intel/skylake/skl-topology.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3637,7 +3637,7 @@ static int skl_manifest_load(struct snd_soc_component *cmpnt, int index,
36373637
return 0;
36383638
}
36393639

3640-
static void skl_tplg_complete(struct snd_soc_component *component)
3640+
static int skl_tplg_complete(struct snd_soc_component *component)
36413641
{
36423642
struct snd_soc_dobj *dobj;
36433643
struct snd_soc_acpi_mach *mach;
@@ -3646,7 +3646,7 @@ static void skl_tplg_complete(struct snd_soc_component *component)
36463646

36473647
val = kmalloc(sizeof(*val), GFP_KERNEL);
36483648
if (!val)
3649-
return;
3649+
return -ENOMEM;
36503650

36513651
mach = dev_get_platdata(component->card->dev);
36523652
list_for_each_entry(dobj, &component->dobj_list, list) {
@@ -3671,7 +3671,9 @@ static void skl_tplg_complete(struct snd_soc_component *component)
36713671
}
36723672
}
36733673
}
3674+
36743675
kfree(val);
3676+
return 0;
36753677
}
36763678

36773679
static struct snd_soc_tplg_ops skl_tplg_ops = {

sound/soc/soc-dapm.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1331,11 +1331,13 @@ int snd_soc_dapm_dai_get_connected_widgets(struct snd_soc_dai *dai, int stream,
13311331

13321332
return paths;
13331333
}
1334+
EXPORT_SYMBOL_GPL(snd_soc_dapm_dai_get_connected_widgets);
13341335

13351336
void snd_soc_dapm_dai_free_widgets(struct snd_soc_dapm_widget_list **list)
13361337
{
13371338
dapm_widget_list_free(list);
13381339
}
1340+
EXPORT_SYMBOL_GPL(snd_soc_dapm_dai_free_widgets);
13391341

13401342
/*
13411343
* Handler for regulator supply widget.

sound/soc/soc-pcm.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1262,8 +1262,7 @@ static int widget_in_list(struct snd_soc_dapm_widget_list *list,
12621262
return 0;
12631263
}
12641264

1265-
static bool dpcm_end_walk_at_be(struct snd_soc_dapm_widget *widget,
1266-
enum snd_soc_dapm_direction dir)
1265+
bool dpcm_end_walk_at_be(struct snd_soc_dapm_widget *widget, enum snd_soc_dapm_direction dir)
12671266
{
12681267
struct snd_soc_card *card = widget->dapm->card;
12691268
struct snd_soc_pcm_runtime *rtd;
@@ -1281,6 +1280,7 @@ static bool dpcm_end_walk_at_be(struct snd_soc_dapm_widget *widget,
12811280

12821281
return false;
12831282
}
1283+
EXPORT_SYMBOL_GPL(dpcm_end_walk_at_be);
12841284

12851285
int dpcm_path_get(struct snd_soc_pcm_runtime *fe,
12861286
int stream, struct snd_soc_dapm_widget_list **list)

sound/soc/soc-topology.c

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ struct soc_tplg {
7878
};
7979

8080
static int soc_tplg_process_headers(struct soc_tplg *tplg);
81-
static void soc_tplg_complete(struct soc_tplg *tplg);
81+
static int soc_tplg_complete(struct soc_tplg *tplg);
8282

8383
/* check we dont overflow the data for this control chunk */
8484
static int soc_tplg_check_elem_count(struct soc_tplg *tplg, size_t elem_size,
@@ -312,10 +312,12 @@ static int soc_tplg_dai_link_load(struct soc_tplg *tplg,
312312
}
313313

314314
/* tell the component driver that all firmware has been loaded in this request */
315-
static void soc_tplg_complete(struct soc_tplg *tplg)
315+
static int soc_tplg_complete(struct soc_tplg *tplg)
316316
{
317317
if (tplg->ops && tplg->ops->complete)
318-
tplg->ops->complete(tplg->comp);
318+
return tplg->ops->complete(tplg->comp);
319+
320+
return 0;
319321
}
320322

321323
/* add a dynamic kcontrol */
@@ -2625,7 +2627,7 @@ static int soc_tplg_load(struct soc_tplg *tplg)
26252627

26262628
ret = soc_tplg_process_headers(tplg);
26272629
if (ret == 0)
2628-
soc_tplg_complete(tplg);
2630+
return soc_tplg_complete(tplg);
26292631

26302632
return ret;
26312633
}

sound/soc/sof/intel/hda-dai.c

Lines changed: 106 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -155,49 +155,68 @@ static int hda_link_dma_params(struct hdac_ext_stream *stream,
155155
return 0;
156156
}
157157

158-
/* Send DAI_CONFIG IPC to the DAI that matches the dai_name and direction */
159-
static int hda_link_config_ipc(struct sof_intel_hda_stream *hda_stream,
160-
const char *dai_name, int channel, int dir)
158+
/* Update config for the DAI widget */
159+
static struct sof_ipc_dai_config *hda_dai_update_config(struct snd_soc_dapm_widget *w,
160+
int channel)
161161
{
162+
struct snd_sof_widget *swidget = w->dobj.private;
162163
struct sof_ipc_dai_config *config;
163164
struct snd_sof_dai *sof_dai;
164-
struct sof_ipc_reply reply;
165-
int ret = 0;
166165

167-
list_for_each_entry(sof_dai, &hda_stream->sdev->dai_list, list) {
168-
if (!sof_dai->cpu_dai_name)
169-
continue;
166+
if (!swidget)
167+
return NULL;
170168

171-
if (!strcmp(dai_name, sof_dai->cpu_dai_name) &&
172-
dir == sof_dai->comp_dai.direction) {
173-
config = sof_dai->dai_config;
169+
sof_dai = swidget->private;
174170

175-
if (!config) {
176-
dev_err(hda_stream->sdev->dev,
177-
"error: no config for DAI %s\n",
178-
sof_dai->name);
179-
return -EINVAL;
180-
}
171+
if (!sof_dai || !sof_dai->dai_config) {
172+
dev_err(swidget->scomp->dev, "error: No config for DAI %s\n", w->name);
173+
return NULL;
174+
}
181175

182-
/* update config with stream tag */
183-
config->hda.link_dma_ch = channel;
176+
config = &sof_dai->dai_config[sof_dai->current_config];
184177

185-
/* send IPC */
186-
ret = sof_ipc_tx_message(hda_stream->sdev->ipc,
187-
config->hdr.cmd,
188-
config,
189-
config->hdr.size,
190-
&reply, sizeof(reply));
178+
/* update config with stream tag */
179+
config->hda.link_dma_ch = channel;
191180

192-
if (ret < 0)
193-
dev_err(hda_stream->sdev->dev,
194-
"error: failed to set dai config for %s\n",
195-
sof_dai->name);
196-
return ret;
197-
}
181+
return config;
182+
}
183+
184+
static int hda_link_config_ipc(struct sof_intel_hda_stream *hda_stream,
185+
struct snd_soc_dapm_widget *w, int channel)
186+
{
187+
struct snd_sof_dev *sdev = hda_stream->sdev;
188+
struct sof_ipc_dai_config *config;
189+
struct sof_ipc_reply reply;
190+
191+
config = hda_dai_update_config(w, channel);
192+
if (!config) {
193+
dev_err(sdev->dev, "error: no config for DAI %s\n", w->name);
194+
return -ENOENT;
195+
}
196+
197+
/* send DAI_CONFIG IPC */
198+
return sof_ipc_tx_message(sdev->ipc, config->hdr.cmd, config, config->hdr.size,
199+
&reply, sizeof(reply));
200+
}
201+
202+
static int hda_link_dai_widget_update(struct sof_intel_hda_stream *hda_stream,
203+
struct snd_soc_dapm_widget *w,
204+
int channel, bool widget_setup)
205+
{
206+
struct snd_sof_dev *sdev = hda_stream->sdev;
207+
struct sof_ipc_dai_config *config;
208+
209+
config = hda_dai_update_config(w, channel);
210+
if (!config) {
211+
dev_err(sdev->dev, "error: no config for DAI %s\n", w->name);
212+
return -ENOENT;
198213
}
199214

200-
return -EINVAL;
215+
/* set up/free DAI widget and send DAI_CONFIG IPC */
216+
if (widget_setup)
217+
return hda_ctrl_dai_widget_setup(w);
218+
219+
return hda_ctrl_dai_widget_free(w);
201220
}
202221

203222
static int hda_link_hw_params(struct snd_pcm_substream *substream,
@@ -211,6 +230,7 @@ static int hda_link_hw_params(struct snd_pcm_substream *substream,
211230
struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
212231
struct sof_intel_hda_stream *hda_stream;
213232
struct hda_pipe_params p_params = {0};
233+
struct snd_soc_dapm_widget *w;
214234
struct hdac_ext_link *link;
215235
int stream_tag;
216236
int ret;
@@ -229,9 +249,13 @@ static int hda_link_hw_params(struct snd_pcm_substream *substream,
229249

230250
hda_stream = hstream_to_sof_hda_stream(link_dev);
231251

232-
/* update the DSP with the new tag */
233-
ret = hda_link_config_ipc(hda_stream, dai->name, stream_tag - 1,
234-
substream->stream);
252+
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
253+
w = dai->playback_widget;
254+
else
255+
w = dai->capture_widget;
256+
257+
/* set up the DAI widget and send the DAI_CONFIG with the new tag */
258+
ret = hda_link_dai_widget_update(hda_stream, w, stream_tag - 1, true);
235259
if (ret < 0)
236260
return ret;
237261

@@ -287,6 +311,7 @@ static int hda_link_pcm_trigger(struct snd_pcm_substream *substream,
287311
snd_soc_dai_get_dma_data(dai, substream);
288312
struct sof_intel_hda_stream *hda_stream;
289313
struct snd_soc_pcm_runtime *rtd;
314+
struct snd_soc_dapm_widget *w;
290315
struct hdac_ext_link *link;
291316
struct hdac_stream *hstream;
292317
struct hdac_bus *bus;
@@ -321,12 +346,16 @@ static int hda_link_pcm_trigger(struct snd_pcm_substream *substream,
321346
break;
322347
case SNDRV_PCM_TRIGGER_SUSPEND:
323348
case SNDRV_PCM_TRIGGER_STOP:
349+
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
350+
w = dai->playback_widget;
351+
else
352+
w = dai->capture_widget;
353+
324354
/*
325355
* clear link DMA channel. It will be assigned when
326356
* hw_params is set up again after resume.
327357
*/
328-
ret = hda_link_config_ipc(hda_stream, dai->name,
329-
DMA_CHAN_INVALID, substream->stream);
358+
ret = hda_link_config_ipc(hda_stream, w, DMA_CHAN_INVALID);
330359
if (ret < 0)
331360
return ret;
332361

@@ -357,6 +386,7 @@ static int hda_link_hw_free(struct snd_pcm_substream *substream,
357386
struct hdac_stream *hstream;
358387
struct snd_soc_pcm_runtime *rtd;
359388
struct hdac_ext_stream *link_dev;
389+
struct snd_soc_dapm_widget *w;
360390
int ret;
361391

362392
hstream = substream->runtime->private_data;
@@ -372,9 +402,13 @@ static int hda_link_hw_free(struct snd_pcm_substream *substream,
372402

373403
hda_stream = hstream_to_sof_hda_stream(link_dev);
374404

375-
/* free the link DMA channel in the FW */
376-
ret = hda_link_config_ipc(hda_stream, dai->name, DMA_CHAN_INVALID,
377-
substream->stream);
405+
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
406+
w = dai->playback_widget;
407+
else
408+
w = dai->capture_widget;
409+
410+
/* free the link DMA channel in the FW and the DAI widget */
411+
ret = hda_link_dai_widget_update(hda_stream, w, DMA_CHAN_INVALID, false);
378412
if (ret < 0)
379413
return ret;
380414

@@ -406,47 +440,51 @@ static const struct snd_soc_dai_ops hda_link_dai_ops = {
406440

407441
#endif
408442

409-
static int ssp_dai_hw_params(struct snd_pcm_substream *substream,
410-
struct snd_pcm_hw_params *params,
411-
struct snd_soc_dai *dai)
443+
static int ssp_dai_setup_or_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai,
444+
bool setup)
412445
{
413-
struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
414-
struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, SOF_AUDIO_PCM_DRV_NAME);
415-
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
416-
struct sof_ipc_fw_version *v = &sdev->fw_ready.version;
417-
struct sof_ipc_dai_config *config;
418-
struct snd_sof_dai *sof_dai;
419-
struct sof_ipc_reply reply;
420-
int ret;
446+
struct snd_soc_component *component;
447+
struct snd_sof_widget *swidget;
448+
struct snd_soc_dapm_widget *w;
449+
struct sof_ipc_fw_version *v;
450+
struct snd_sof_dev *sdev;
451+
452+
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
453+
w = dai->playback_widget;
454+
else
455+
w = dai->capture_widget;
456+
457+
swidget = w->dobj.private;
458+
component = swidget->scomp;
459+
sdev = snd_soc_component_get_drvdata(component);
460+
v = &sdev->fw_ready.version;
421461

422462
/* DAI_CONFIG IPC during hw_params is not supported in older firmware */
423463
if (v->abi_version < SOF_ABI_VER(3, 18, 0))
424464
return 0;
425465

426-
list_for_each_entry(sof_dai, &sdev->dai_list, list) {
427-
if (!sof_dai->cpu_dai_name || !sof_dai->dai_config)
428-
continue;
429-
430-
if (!strcmp(dai->name, sof_dai->cpu_dai_name) &&
431-
substream->stream == sof_dai->comp_dai.direction) {
432-
config = &sof_dai->dai_config[sof_dai->current_config];
466+
if (setup)
467+
return hda_ctrl_dai_widget_setup(w);
433468

434-
/* send IPC */
435-
ret = sof_ipc_tx_message(sdev->ipc, config->hdr.cmd, config,
436-
config->hdr.size, &reply, sizeof(reply));
469+
return hda_ctrl_dai_widget_free(w);
470+
}
437471

438-
if (ret < 0)
439-
dev_err(sdev->dev, "error: failed to set DAI config for %s\n",
440-
sof_dai->name);
441-
return ret;
442-
}
443-
}
472+
static int ssp_dai_hw_params(struct snd_pcm_substream *substream,
473+
struct snd_pcm_hw_params *params,
474+
struct snd_soc_dai *dai)
475+
{
476+
return ssp_dai_setup_or_free(substream, dai, true);
477+
}
444478

445-
return 0;
479+
static int ssp_dai_hw_free(struct snd_pcm_substream *substream,
480+
struct snd_soc_dai *dai)
481+
{
482+
return ssp_dai_setup_or_free(substream, dai, false);
446483
}
447484

448485
static const struct snd_soc_dai_ops ssp_dai_ops = {
449486
.hw_params = ssp_dai_hw_params,
487+
.hw_free = ssp_dai_hw_free,
450488
};
451489

452490
/*

0 commit comments

Comments
 (0)