Commit 15c7fab0 authored by Krzysztof Kozlowski's avatar Krzysztof Kozlowski Committed by Mark Brown

ASoC: qcom: Move Soundwire runtime stream alloc to soundcards

Currently the Qualcomm Soundwire controller in its DAI startup op
allocates the Soundwire stream runtime.  This works fine for existing
designs, but has limitations for stream runtimes with multiple
controllers, like upcoming Qualcomm X1E80100 SoC with four WSA8840
speakers on two Soundwire controllers.

When two Soundwire controllers are added to sound card codecs, Soundwire
startup() is called twice, one for each Soundwire controller, and second
execution overwrites what was set before.  During shutdown() this causes
double free.

It is expected to have only one Soundwire stream runtime, thus it should
be allocated from SoC soundcard context startup(), not from each
Soundwire startup().  Such way will properly handle both cases: one and
two Soundwire controllers in the stream runtime.
Signed-off-by: default avatarKrzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
Reviewed-by: default avatarPierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Link: https://lore.kernel.org/r/20231128165638.757665-2-krzysztof.kozlowski@linaro.orgSigned-off-by: default avatarMark Brown <broonie@kernel.org>
parent d32bac9c
...@@ -1265,10 +1265,7 @@ static int qcom_swrm_startup(struct snd_pcm_substream *substream, ...@@ -1265,10 +1265,7 @@ static int qcom_swrm_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai) struct snd_soc_dai *dai)
{ {
struct qcom_swrm_ctrl *ctrl = dev_get_drvdata(dai->dev); struct qcom_swrm_ctrl *ctrl = dev_get_drvdata(dai->dev);
struct snd_soc_pcm_runtime *rtd = substream->private_data; int ret;
struct sdw_stream_runtime *sruntime;
struct snd_soc_dai *codec_dai;
int ret, i;
ret = pm_runtime_get_sync(ctrl->dev); ret = pm_runtime_get_sync(ctrl->dev);
if (ret < 0 && ret != -EACCES) { if (ret < 0 && ret != -EACCES) {
...@@ -1279,33 +1276,7 @@ static int qcom_swrm_startup(struct snd_pcm_substream *substream, ...@@ -1279,33 +1276,7 @@ static int qcom_swrm_startup(struct snd_pcm_substream *substream,
return ret; return ret;
} }
sruntime = sdw_alloc_stream(dai->name);
if (!sruntime) {
ret = -ENOMEM;
goto err_alloc;
}
ctrl->sruntime[dai->id] = sruntime;
for_each_rtd_codec_dais(rtd, i, codec_dai) {
ret = snd_soc_dai_set_stream(codec_dai, sruntime,
substream->stream);
if (ret < 0 && ret != -ENOTSUPP) {
dev_err(dai->dev, "Failed to set sdw stream on %s\n",
codec_dai->name);
goto err_set_stream;
}
}
return 0; return 0;
err_set_stream:
sdw_release_stream(sruntime);
err_alloc:
pm_runtime_mark_last_busy(ctrl->dev);
pm_runtime_put_autosuspend(ctrl->dev);
return ret;
} }
static void qcom_swrm_shutdown(struct snd_pcm_substream *substream, static void qcom_swrm_shutdown(struct snd_pcm_substream *substream,
...@@ -1314,8 +1285,6 @@ static void qcom_swrm_shutdown(struct snd_pcm_substream *substream, ...@@ -1314,8 +1285,6 @@ static void qcom_swrm_shutdown(struct snd_pcm_substream *substream,
struct qcom_swrm_ctrl *ctrl = dev_get_drvdata(dai->dev); struct qcom_swrm_ctrl *ctrl = dev_get_drvdata(dai->dev);
swrm_wait_for_wr_fifo_done(ctrl); swrm_wait_for_wr_fifo_done(ctrl);
sdw_release_stream(ctrl->sruntime[dai->id]);
ctrl->sruntime[dai->id] = NULL;
pm_runtime_mark_last_busy(ctrl->dev); pm_runtime_mark_last_busy(ctrl->dev);
pm_runtime_put_autosuspend(ctrl->dev); pm_runtime_put_autosuspend(ctrl->dev);
......
...@@ -31,6 +31,17 @@ static int sc8280xp_snd_init(struct snd_soc_pcm_runtime *rtd) ...@@ -31,6 +31,17 @@ static int sc8280xp_snd_init(struct snd_soc_pcm_runtime *rtd)
return qcom_snd_wcd_jack_setup(rtd, &data->jack, &data->jack_setup); return qcom_snd_wcd_jack_setup(rtd, &data->jack, &data->jack_setup);
} }
static void sc8280xp_snd_shutdown(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
struct sc8280xp_snd_data *pdata = snd_soc_card_get_drvdata(rtd->card);
struct sdw_stream_runtime *sruntime = pdata->sruntime[cpu_dai->id];
pdata->sruntime[cpu_dai->id] = NULL;
sdw_release_stream(sruntime);
}
static int sc8280xp_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, static int sc8280xp_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
struct snd_pcm_hw_params *params) struct snd_pcm_hw_params *params)
{ {
...@@ -91,6 +102,8 @@ static int sc8280xp_snd_hw_free(struct snd_pcm_substream *substream) ...@@ -91,6 +102,8 @@ static int sc8280xp_snd_hw_free(struct snd_pcm_substream *substream)
} }
static const struct snd_soc_ops sc8280xp_be_ops = { static const struct snd_soc_ops sc8280xp_be_ops = {
.startup = qcom_snd_sdw_startup,
.shutdown = sc8280xp_snd_shutdown,
.hw_params = sc8280xp_snd_hw_params, .hw_params = sc8280xp_snd_hw_params,
.hw_free = sc8280xp_snd_hw_free, .hw_free = sc8280xp_snd_hw_free,
.prepare = sc8280xp_snd_prepare, .prepare = sc8280xp_snd_prepare,
......
...@@ -66,7 +66,19 @@ static int sm8250_snd_startup(struct snd_pcm_substream *substream) ...@@ -66,7 +66,19 @@ static int sm8250_snd_startup(struct snd_pcm_substream *substream)
default: default:
break; break;
} }
return 0;
return qcom_snd_sdw_startup(substream);
}
static void sm2450_snd_shutdown(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
struct sm8250_snd_data *data = snd_soc_card_get_drvdata(rtd->card);
struct sdw_stream_runtime *sruntime = data->sruntime[cpu_dai->id];
data->sruntime[cpu_dai->id] = NULL;
sdw_release_stream(sruntime);
} }
static int sm8250_snd_hw_params(struct snd_pcm_substream *substream, static int sm8250_snd_hw_params(struct snd_pcm_substream *substream,
...@@ -103,6 +115,7 @@ static int sm8250_snd_hw_free(struct snd_pcm_substream *substream) ...@@ -103,6 +115,7 @@ static int sm8250_snd_hw_free(struct snd_pcm_substream *substream)
static const struct snd_soc_ops sm8250_be_ops = { static const struct snd_soc_ops sm8250_be_ops = {
.startup = sm8250_snd_startup, .startup = sm8250_snd_startup,
.shutdown = sm2450_snd_shutdown,
.hw_params = sm8250_snd_hw_params, .hw_params = sm8250_snd_hw_params,
.hw_free = sm8250_snd_hw_free, .hw_free = sm8250_snd_hw_free,
.prepare = sm8250_snd_prepare, .prepare = sm8250_snd_prepare,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment