Skip to content

Commit 8b00141

Browse files
ranj063broonie
authored andcommitted
ASoC: SOF: Introduce widget use_count
Add a new field, use_count to struct snd_sof_widget to keep track of the usage count for each widget. Since widgets can belong to multiple pipelines, this field will ensure that the widget is setup only when the first pipeline that needs it is started and freed when the last pipeline that needs it is stopped. There is no need to protect the widget use_count access as the core already handles mutual exclusion at the PCM level. Add a new helper sof_widget_free() to handle freeing the SOF widgets and export the sof_widget_setup/free() functions. Signed-off-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com> Reviewed-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com> Reviewed-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com> Reviewed-by: Kai Vehmanen <kai.vehmanen@linux.intel.com> Signed-off-by: Daniel Baluta <daniel.baluta@nxp.com> Signed-off-by: Peter Ujfalusi <peter.ujfalusi@linux.intel.com> Link: https://lore.kernel.org/r/20210927120517.20505-10-peter.ujfalusi@linux.intel.com Signed-off-by: Mark Brown <broonie@kernel.org>
1 parent 1b7d57d commit 8b00141

File tree

3 files changed

+97
-6
lines changed

3 files changed

+97
-6
lines changed

sound/soc/sof/ipc.c

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -744,9 +744,31 @@ int snd_sof_ipc_set_get_comp_data(struct snd_sof_control *scontrol,
744744
struct sof_ipc_fw_ready *ready = &sdev->fw_ready;
745745
struct sof_ipc_fw_version *v = &ready->version;
746746
struct sof_ipc_ctrl_data_params sparams;
747+
struct snd_sof_widget *swidget;
748+
bool widget_found = false;
747749
size_t send_bytes;
748750
int err;
749751

752+
list_for_each_entry(swidget, &sdev->widget_list, list) {
753+
if (swidget->comp_id == scontrol->comp_id) {
754+
widget_found = true;
755+
break;
756+
}
757+
}
758+
759+
if (!widget_found) {
760+
dev_err(sdev->dev, "error: can't find widget with id %d\n", scontrol->comp_id);
761+
return -EINVAL;
762+
}
763+
764+
/*
765+
* Volatile controls should always be part of static pipelines and the widget use_count
766+
* would always be > 0 in this case. For the others, just return the cached value if the
767+
* widget is not set up.
768+
*/
769+
if (!swidget->use_count)
770+
return 0;
771+
750772
/* read or write firmware volume */
751773
if (scontrol->readback_offset != 0) {
752774
/* write/read value header via mmaped region */

sound/soc/sof/sof-audio.c

Lines changed: 71 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,53 @@ static int sof_widget_kcontrol_setup(struct snd_sof_dev *sdev, struct snd_sof_wi
8383
return 0;
8484
}
8585

86-
static int sof_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget)
86+
int sof_widget_free(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget)
87+
{
88+
struct sof_ipc_free ipc_free = {
89+
.hdr = {
90+
.size = sizeof(ipc_free),
91+
.cmd = SOF_IPC_GLB_TPLG_MSG,
92+
},
93+
.id = swidget->comp_id,
94+
};
95+
struct sof_ipc_reply reply;
96+
int ret;
97+
98+
if (!swidget->private)
99+
return 0;
100+
101+
/* only free when use_count is 0 */
102+
if (--swidget->use_count)
103+
return 0;
104+
105+
switch (swidget->id) {
106+
case snd_soc_dapm_scheduler:
107+
ipc_free.hdr.cmd |= SOF_IPC_TPLG_PIPE_FREE;
108+
break;
109+
case snd_soc_dapm_buffer:
110+
ipc_free.hdr.cmd |= SOF_IPC_TPLG_BUFFER_FREE;
111+
break;
112+
default:
113+
ipc_free.hdr.cmd |= SOF_IPC_TPLG_COMP_FREE;
114+
break;
115+
}
116+
117+
ret = sof_ipc_tx_message(sdev->ipc, ipc_free.hdr.cmd, &ipc_free, sizeof(ipc_free),
118+
&reply, sizeof(reply));
119+
if (ret < 0) {
120+
dev_err(sdev->dev, "error: failed to free widget %s\n", swidget->widget->name);
121+
swidget->use_count++;
122+
return ret;
123+
}
124+
125+
swidget->complete = 0;
126+
dev_dbg(sdev->dev, "widget %s freed\n", swidget->widget->name);
127+
128+
return 0;
129+
}
130+
EXPORT_SYMBOL(sof_widget_free);
131+
132+
int sof_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget)
87133
{
88134
struct sof_ipc_pipe_new *pipeline;
89135
struct sof_ipc_comp_reply r;
@@ -97,11 +143,15 @@ static int sof_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swi
97143
if (!swidget->private)
98144
return 0;
99145

146+
/* widget already set up */
147+
if (++swidget->use_count > 1)
148+
return 0;
149+
100150
ret = sof_pipeline_core_enable(sdev, swidget);
101151
if (ret < 0) {
102152
dev_err(sdev->dev, "error: failed to enable target core: %d for widget %s\n",
103153
ret, swidget->widget->name);
104-
return ret;
154+
goto use_count_dec;
105155
}
106156

107157
switch (swidget->id) {
@@ -134,7 +184,7 @@ static int sof_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swi
134184
}
135185
if (ret < 0) {
136186
dev_err(sdev->dev, "error: failed to load widget %s\n", swidget->widget->name);
137-
return ret;
187+
goto use_count_dec;
138188
}
139189

140190
/* restore kcontrols for widget */
@@ -147,8 +197,13 @@ static int sof_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swi
147197

148198
dev_dbg(sdev->dev, "widget %s setup complete\n", swidget->widget->name);
149199

200+
return 0;
201+
202+
use_count_dec:
203+
swidget->use_count--;
150204
return ret;
151205
}
206+
EXPORT_SYMBOL(sof_widget_setup);
152207

153208
/*
154209
* helper to determine if there are only D0i3 compatible
@@ -258,6 +313,9 @@ int sof_set_up_pipelines(struct device *dev)
258313

259314
/* restore pipeline components */
260315
list_for_each_entry_reverse(swidget, &sdev->widget_list, list) {
316+
/* reset widget use_count after resuming */
317+
swidget->use_count = 0;
318+
261319
ret = sof_widget_setup(sdev, swidget);
262320
if (ret < 0)
263321
return ret;
@@ -325,16 +383,23 @@ int sof_set_up_pipelines(struct device *dev)
325383
return 0;
326384
}
327385

328-
/* This function doesn't free widgets. It only resets the set up status for all routes */
386+
/*
387+
* This function doesn't free widgets. It only resets the set up status for all routes and
388+
* use_count for all widgets.
389+
*/
329390
void sof_tear_down_pipelines(struct device *dev)
330391
{
331392
struct snd_sof_dev *sdev = dev_get_drvdata(dev);
393+
struct snd_sof_widget *swidget;
332394
struct snd_sof_route *sroute;
333395

334396
/*
335-
* No need to protect sroute->setup as this function is called only during the suspend
336-
* callback and all streams should be suspended by then
397+
* No need to protect swidget->use_count and sroute->setup as this function is called only
398+
* during the suspend callback and all streams should be suspended by then
337399
*/
400+
list_for_each_entry(swidget, &sdev->widget_list, list)
401+
swidget->use_count = 0;
402+
338403
list_for_each_entry(sroute, &sdev->route_list, list)
339404
sroute->setup = false;
340405
}

sound/soc/sof/sof-audio.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ struct snd_sof_widget {
8989
int comp_id;
9090
int pipeline_id;
9191
int complete;
92+
int use_count; /* use_count will be protected by the PCM mutex held by the core */
9293
int core;
9394
int id;
9495

@@ -252,4 +253,7 @@ bool snd_sof_dsp_only_d0i3_compatible_stream_active(struct snd_sof_dev *sdev);
252253
int sof_machine_register(struct snd_sof_dev *sdev, void *pdata);
253254
void sof_machine_unregister(struct snd_sof_dev *sdev, void *pdata);
254255

256+
int sof_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget);
257+
int sof_widget_free(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget);
258+
255259
#endif

0 commit comments

Comments
 (0)