Skip to content

Commit 7d55ec5

Browse files
ranj063kv2019i
authored andcommitted
fixup! ASoC: SOF: Intel: hda: make sure DAI widget is set up before IPC
Applications can free a PCM stream after system suspend without restarting them. The BE hw_free() should not free the DAI widget in this case. Add a new flag, configured to struct snd_sof_dai to indicate if the DAI has been configured during BE hw_params. and use it to check if hw_free() should free the DAI widget. With the addition of the new flag, it no longer makes sense to keep one function for DAI widget setup and free. So split the hda_ctrl_dai_widget_setup() function into 2 for setup and free separately. Signed-off-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
1 parent 93d91f0 commit 7d55ec5

File tree

5 files changed

+69
-31
lines changed

5 files changed

+69
-31
lines changed

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

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,10 @@ static int hda_link_dai_widget_update(struct sof_intel_hda_stream *hda_stream,
211211
}
212212

213213
/* set up/free DAI widget and send DAI_CONFIG IPC */
214-
return hda_ctrl_dai_widget_setup(w, widget_setup);
214+
if (widget_setup)
215+
return hda_ctrl_dai_widget_setup(w);
216+
217+
return hda_ctrl_dai_widget_free(w);
215218
}
216219

217220
static int hda_link_hw_params(struct snd_pcm_substream *substream,
@@ -447,8 +450,9 @@ static struct snd_soc_cdai_ops sof_probe_compr_ops = {
447450
#endif
448451
#endif
449452

450-
static int ssp_dai_config_update(struct snd_pcm_substream *substream, struct snd_soc_dai *dai,
451-
bool widget_setup)
453+
static int ssp_dai_hw_params(struct snd_pcm_substream *substream,
454+
struct snd_pcm_hw_params *params,
455+
struct snd_soc_dai *dai)
452456
{
453457
struct snd_soc_dapm_widget *w;
454458

@@ -457,20 +461,20 @@ static int ssp_dai_config_update(struct snd_pcm_substream *substream, struct snd
457461
else
458462
w = dai->capture_widget;
459463

460-
return hda_ctrl_dai_widget_setup(w, widget_setup);
461-
}
462-
463-
static int ssp_dai_hw_params(struct snd_pcm_substream *substream,
464-
struct snd_pcm_hw_params *params,
465-
struct snd_soc_dai *dai)
466-
{
467-
return ssp_dai_config_update(substream, dai, true);
464+
return hda_ctrl_dai_widget_setup(w);
468465
}
469466

470467
static int ssp_dai_hw_free(struct snd_pcm_substream *substream,
471468
struct snd_soc_dai *dai)
472469
{
473-
return ssp_dai_config_update(substream, dai, false);
470+
struct snd_soc_dapm_widget *w;
471+
472+
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
473+
w = dai->playback_widget;
474+
else
475+
w = dai->capture_widget;
476+
477+
return hda_ctrl_dai_widget_free(w);
474478
}
475479

476480
static const struct snd_soc_dai_ops ssp_dai_ops = {

sound/soc/sof/intel/hda.c

Lines changed: 49 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,7 @@
4141
#define EXCEPT_MAX_HDR_SIZE 0x400
4242
#define HDA_EXT_ROM_STATUS_SIZE 8
4343

44-
/*
45-
* Helper function to set up a DAI widget in the DSP and then send the updated DAI config during
46-
* hw_params or send the updated DAI_CONFIG and then free the DAI widget during hw_free
47-
*/
48-
int hda_ctrl_dai_widget_setup(struct snd_soc_dapm_widget *w, bool setup)
44+
int hda_ctrl_dai_widget_setup(struct snd_soc_dapm_widget *w)
4945
{
5046
struct snd_sof_widget *swidget = w->dobj.private;
5147
struct snd_soc_component *component = swidget->scomp;
@@ -66,28 +62,60 @@ int hda_ctrl_dai_widget_setup(struct snd_soc_dapm_widget *w, bool setup)
6662

6763
/*
6864
* For static pipelines, the DAI widget would already be set up and calling
69-
* sof_widget_setup()/free() simply returns without doing anything.
70-
* For dynamic pipelines, the DAI widget will be set up or freed here.
65+
* sof_widget_setup() simply returns without doing anything.
66+
* For dynamic pipelines, the DAI widget will be set up now.
7167
*/
72-
if (setup) {
73-
ret = sof_widget_setup(sdev, swidget);
74-
if (ret < 0) {
75-
dev_err(sdev->dev, "error: setting up DAI widget %s\n", w->name);
76-
return ret;
77-
}
68+
ret = sof_widget_setup(sdev, swidget);
69+
if (ret < 0) {
70+
dev_err(sdev->dev, "error: failed setting up DAI widget %s\n", w->name);
71+
return ret;
72+
}
7873

79-
/* send DAI_CONFIG IPC */
80-
return sof_ipc_tx_message(sdev->ipc, config->hdr.cmd, config, config->hdr.size,
81-
&reply, sizeof(reply));
74+
/* send DAI_CONFIG IPC */
75+
ret = sof_ipc_tx_message(sdev->ipc, config->hdr.cmd, config, config->hdr.size,
76+
&reply, sizeof(reply));
77+
if (ret < 0) {
78+
dev_err(sdev->dev, "error: failed setting DAI config for %s\n", w->name);
79+
return ret;
8280
}
8381

82+
sof_dai->configured = true;
83+
84+
return 0;
85+
}
86+
87+
int hda_ctrl_dai_widget_free(struct snd_soc_dapm_widget *w)
88+
{
89+
struct snd_sof_widget *swidget = w->dobj.private;
90+
struct snd_soc_component *component = swidget->scomp;
91+
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
92+
struct sof_ipc_dai_config *config;
93+
struct snd_sof_dai *sof_dai;
94+
struct sof_ipc_reply reply;
95+
int ret;
96+
97+
sof_dai = swidget->private;
98+
99+
if (!sof_dai || !sof_dai->dai_config) {
100+
dev_err(sdev->dev, "error: No config to free DAI %s\n", w->name);
101+
return -EINVAL;
102+
}
103+
104+
/* nothing to do if hw_free() is called without restarting the stream after resume. */
105+
if (!sof_dai->configured)
106+
return 0;
107+
108+
config = &sof_dai->dai_config[sof_dai->current_config];
109+
84110
ret = sof_ipc_tx_message(sdev->ipc, config->hdr.cmd, config, config->hdr.size,
85111
&reply, sizeof(reply));
86112
if (ret < 0) {
87-
dev_err(sdev->dev, "error: updating DAI config for %s\n", w->name);
113+
dev_err(sdev->dev, "error: failed resetting DAI config for %s\n", w->name);
88114
return ret;
89115
}
90116

117+
sof_dai->configured = false;
118+
91119
return sof_widget_free(sdev, swidget);
92120
}
93121

@@ -129,7 +157,10 @@ static int sdw_dai_config_ipc(struct snd_sof_dev *sdev,
129157
config->dai_index = (link_id << 8) | dai_id;
130158
config->alh.stream_id = alh_stream_id;
131159

132-
return hda_ctrl_dai_widget_setup(w, setup);
160+
if (setup)
161+
return hda_ctrl_dai_widget_setup(w);
162+
163+
return hda_ctrl_dai_widget_free(w);
133164
}
134165

135166
static int sdw_params_stream(struct device *dev,

sound/soc/sof/intel/hda.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -771,6 +771,7 @@ int hda_pci_intel_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
771771

772772
struct snd_sof_dai;
773773
struct sof_ipc_dai_config;
774-
int hda_ctrl_dai_widget_setup(struct snd_soc_dapm_widget *w, bool setup);
774+
int hda_ctrl_dai_widget_setup(struct snd_soc_dapm_widget *w);
775+
int hda_ctrl_dai_widget_free(struct snd_soc_dapm_widget *w);
775776

776777
#endif

sound/soc/sof/sof-audio.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,7 @@ int sof_widget_setup(struct snd_sof_dev *sdev, struct snd_sof_widget *swidget)
174174
return -ENOMEM;
175175

176176
dai = swidget->private;
177+
dai->configured = false;
177178
memcpy(comp, &dai->comp_dai, sizeof(struct sof_ipc_comp_dai));
178179

179180
/* append extended data to the end of the component */

sound/soc/sof/sof-audio.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@ struct snd_sof_dai {
134134
struct sof_ipc_comp_dai comp_dai;
135135
int number_configs;
136136
int current_config;
137+
bool configured; /* DAI configured during BE hw_params */
137138
struct sof_ipc_dai_config *dai_config;
138139
struct list_head list; /* list in sdev dai list */
139140
};

0 commit comments

Comments
 (0)