mirror of
https://github.com/torvalds/linux.git
synced 2025-12-07 20:06:24 +00:00
ASoC: qcom: sdw: fix memory leak for sdw_stream_runtime
For some reason we endedup allocating sdw_stream_runtime for every cpu dai,
this has two issues.
1. we never set snd_soc_dai_set_stream for non soundwire dai, which
means there is no way that we can free this, resulting in memory leak
2. startup and shutdown callbacks can be called without
hw_params callback called. This combination results in memory leak
because machine driver sruntime array pointer is only set in hw_params
callback.
Fix this by
1. adding a helper function to get sdw_runtime for substream
which can be used by shutdown callback to get hold of sruntime to free.
2. only allocate sdw_runtime for soundwire dais.
Fixes: d32bac9cb0 ("ASoC: qcom: Add helper for allocating Soundwire stream runtime")
Cc: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
Cc: Stable@vger.kernel.org
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@oss.qualcomm.com>
Tested-by: Steev Klimaszewski <threeway@gmail.com> # Thinkpad X13s
Link: https://patch.msgid.link/20251022143349.1081513-2-srinivas.kandagatla@oss.qualcomm.com
Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
committed by
Mark Brown
parent
45f5c9eec4
commit
bcba172793
@@ -317,7 +317,7 @@ static void sc7280_snd_shutdown(struct snd_pcm_substream *substream)
|
||||
struct snd_soc_card *card = rtd->card;
|
||||
struct sc7280_snd_data *data = snd_soc_card_get_drvdata(card);
|
||||
struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
|
||||
struct sdw_stream_runtime *sruntime = data->sruntime[cpu_dai->id];
|
||||
struct sdw_stream_runtime *sruntime = qcom_snd_sdw_get_stream(substream);
|
||||
|
||||
switch (cpu_dai->id) {
|
||||
case MI2S_PRIMARY:
|
||||
|
||||
@@ -73,7 +73,7 @@ static void sc8280xp_snd_shutdown(struct snd_pcm_substream *substream)
|
||||
struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
|
||||
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];
|
||||
struct sdw_stream_runtime *sruntime = qcom_snd_sdw_get_stream(substream);
|
||||
|
||||
pdata->sruntime[cpu_dai->id] = NULL;
|
||||
sdw_release_stream(sruntime);
|
||||
|
||||
@@ -7,6 +7,37 @@
|
||||
#include <sound/soc.h>
|
||||
#include "sdw.h"
|
||||
|
||||
static bool qcom_snd_is_sdw_dai(int id)
|
||||
{
|
||||
switch (id) {
|
||||
case WSA_CODEC_DMA_RX_0:
|
||||
case WSA_CODEC_DMA_TX_0:
|
||||
case WSA_CODEC_DMA_RX_1:
|
||||
case WSA_CODEC_DMA_TX_1:
|
||||
case WSA_CODEC_DMA_TX_2:
|
||||
case RX_CODEC_DMA_RX_0:
|
||||
case TX_CODEC_DMA_TX_0:
|
||||
case RX_CODEC_DMA_RX_1:
|
||||
case TX_CODEC_DMA_TX_1:
|
||||
case RX_CODEC_DMA_RX_2:
|
||||
case TX_CODEC_DMA_TX_2:
|
||||
case RX_CODEC_DMA_RX_3:
|
||||
case TX_CODEC_DMA_TX_3:
|
||||
case RX_CODEC_DMA_RX_4:
|
||||
case TX_CODEC_DMA_TX_4:
|
||||
case RX_CODEC_DMA_RX_5:
|
||||
case TX_CODEC_DMA_TX_5:
|
||||
case RX_CODEC_DMA_RX_6:
|
||||
case RX_CODEC_DMA_RX_7:
|
||||
case SLIMBUS_0_RX...SLIMBUS_6_TX:
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* qcom_snd_sdw_startup() - Helper to start Soundwire stream for SoC audio card
|
||||
* @substream: The PCM substream from audio, as passed to snd_soc_ops->startup()
|
||||
@@ -29,6 +60,9 @@ int qcom_snd_sdw_startup(struct snd_pcm_substream *substream)
|
||||
u32 rx_ch_cnt = 0, tx_ch_cnt = 0;
|
||||
int ret, i, j;
|
||||
|
||||
if (!qcom_snd_is_sdw_dai(cpu_dai->id))
|
||||
return 0;
|
||||
|
||||
sruntime = sdw_alloc_stream(cpu_dai->name, SDW_STREAM_PCM);
|
||||
if (!sruntime)
|
||||
return -ENOMEM;
|
||||
@@ -89,19 +123,8 @@ int qcom_snd_sdw_prepare(struct snd_pcm_substream *substream,
|
||||
if (!sruntime)
|
||||
return 0;
|
||||
|
||||
switch (cpu_dai->id) {
|
||||
case WSA_CODEC_DMA_RX_0:
|
||||
case WSA_CODEC_DMA_RX_1:
|
||||
case RX_CODEC_DMA_RX_0:
|
||||
case RX_CODEC_DMA_RX_1:
|
||||
case TX_CODEC_DMA_TX_0:
|
||||
case TX_CODEC_DMA_TX_1:
|
||||
case TX_CODEC_DMA_TX_2:
|
||||
case TX_CODEC_DMA_TX_3:
|
||||
break;
|
||||
default:
|
||||
if (!qcom_snd_is_sdw_dai(cpu_dai->id))
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (*stream_prepared)
|
||||
return 0;
|
||||
@@ -129,9 +152,7 @@ int qcom_snd_sdw_prepare(struct snd_pcm_substream *substream,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(qcom_snd_sdw_prepare);
|
||||
|
||||
int qcom_snd_sdw_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params,
|
||||
struct sdw_stream_runtime **psruntime)
|
||||
struct sdw_stream_runtime *qcom_snd_sdw_get_stream(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
|
||||
struct snd_soc_dai *codec_dai;
|
||||
@@ -139,21 +160,23 @@ int qcom_snd_sdw_hw_params(struct snd_pcm_substream *substream,
|
||||
struct sdw_stream_runtime *sruntime;
|
||||
int i;
|
||||
|
||||
switch (cpu_dai->id) {
|
||||
case WSA_CODEC_DMA_RX_0:
|
||||
case RX_CODEC_DMA_RX_0:
|
||||
case RX_CODEC_DMA_RX_1:
|
||||
case TX_CODEC_DMA_TX_0:
|
||||
case TX_CODEC_DMA_TX_1:
|
||||
case TX_CODEC_DMA_TX_2:
|
||||
case TX_CODEC_DMA_TX_3:
|
||||
for_each_rtd_codec_dais(rtd, i, codec_dai) {
|
||||
sruntime = snd_soc_dai_get_stream(codec_dai, substream->stream);
|
||||
if (sruntime != ERR_PTR(-ENOTSUPP))
|
||||
*psruntime = sruntime;
|
||||
}
|
||||
break;
|
||||
if (!qcom_snd_is_sdw_dai(cpu_dai->id))
|
||||
return NULL;
|
||||
|
||||
for_each_rtd_codec_dais(rtd, i, codec_dai) {
|
||||
sruntime = snd_soc_dai_get_stream(codec_dai, substream->stream);
|
||||
if (sruntime != ERR_PTR(-ENOTSUPP))
|
||||
return sruntime;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(qcom_snd_sdw_get_stream);
|
||||
|
||||
int qcom_snd_sdw_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params,
|
||||
struct sdw_stream_runtime **psruntime)
|
||||
{
|
||||
*psruntime = qcom_snd_sdw_get_stream(substream);
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -166,23 +189,13 @@ int qcom_snd_sdw_hw_free(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
|
||||
struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
|
||||
|
||||
switch (cpu_dai->id) {
|
||||
case WSA_CODEC_DMA_RX_0:
|
||||
case WSA_CODEC_DMA_RX_1:
|
||||
case RX_CODEC_DMA_RX_0:
|
||||
case RX_CODEC_DMA_RX_1:
|
||||
case TX_CODEC_DMA_TX_0:
|
||||
case TX_CODEC_DMA_TX_1:
|
||||
case TX_CODEC_DMA_TX_2:
|
||||
case TX_CODEC_DMA_TX_3:
|
||||
if (sruntime && *stream_prepared) {
|
||||
sdw_disable_stream(sruntime);
|
||||
sdw_deprepare_stream(sruntime);
|
||||
*stream_prepared = false;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
if (!qcom_snd_is_sdw_dai(cpu_dai->id))
|
||||
return 0;
|
||||
|
||||
if (sruntime && *stream_prepared) {
|
||||
sdw_disable_stream(sruntime);
|
||||
sdw_deprepare_stream(sruntime);
|
||||
*stream_prepared = false;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -10,6 +10,7 @@ int qcom_snd_sdw_startup(struct snd_pcm_substream *substream);
|
||||
int qcom_snd_sdw_prepare(struct snd_pcm_substream *substream,
|
||||
struct sdw_stream_runtime *runtime,
|
||||
bool *stream_prepared);
|
||||
struct sdw_stream_runtime *qcom_snd_sdw_get_stream(struct snd_pcm_substream *stream);
|
||||
int qcom_snd_sdw_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params,
|
||||
struct sdw_stream_runtime **psruntime);
|
||||
|
||||
@@ -117,7 +117,7 @@ static void sm8250_snd_shutdown(struct snd_pcm_substream *substream)
|
||||
struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
|
||||
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];
|
||||
struct sdw_stream_runtime *sruntime = qcom_snd_sdw_get_stream(substream);
|
||||
|
||||
data->sruntime[cpu_dai->id] = NULL;
|
||||
sdw_release_stream(sruntime);
|
||||
|
||||
@@ -55,7 +55,7 @@ static void x1e80100_snd_shutdown(struct snd_pcm_substream *substream)
|
||||
struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
|
||||
struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
|
||||
struct x1e80100_snd_data *data = snd_soc_card_get_drvdata(rtd->card);
|
||||
struct sdw_stream_runtime *sruntime = data->sruntime[cpu_dai->id];
|
||||
struct sdw_stream_runtime *sruntime = qcom_snd_sdw_get_stream(substream);
|
||||
|
||||
data->sruntime[cpu_dai->id] = NULL;
|
||||
sdw_release_stream(sruntime);
|
||||
|
||||
Reference in New Issue
Block a user