From 02200b5f682730669a6c7d48e5a9cab29c283e45 Mon Sep 17 00:00:00 2001 From: Zhengchun Li Date: Tue, 18 Feb 2025 18:20:15 +0800 Subject: [PATCH 1/6] asoc: Update dai link for ACM8625S AMP. ACM8625S using i2s dai quin_mi2s_rx. Add ACM8625S AMP dai on dai link. Change-Id: I0653d41b212e954e80fcf70dc4dc2bc7c0739405 Signed-off-by: Zhengchun Li --- asoc/msm_dailink.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/asoc/msm_dailink.h b/asoc/msm_dailink.h index c7353b9ae05d..ef588206d321 100644 --- a/asoc/msm_dailink.h +++ b/asoc/msm_dailink.h @@ -957,7 +957,8 @@ SND_SOC_DAILINK_DEFS(quat_mi2s_tx, SND_SOC_DAILINK_DEFS(quin_mi2s_rx, DAILINK_COMP_ARRAY(COMP_CPU("msm-dai-q6-mi2s.8")), - DAILINK_COMP_ARRAY(COMP_CODEC("msm-stub-codec.1", "msm-stub-rx")), + DAILINK_COMP_ARRAY(COMP_CODEC("msm-stub-codec.1", "msm-stub-rx"), + COMP_CODEC("acm8625s_codec", "acm8625s-hifi")), DAILINK_COMP_ARRAY(COMP_PLATFORM("msm-pcm-routing"))); SND_SOC_DAILINK_DEFS(quin_mi2s_tx, From 62a56196062d4c8cd71b3b9cc05fa6a72b07cc15 Mon Sep 17 00:00:00 2001 From: Shalini Manjunatha Date: Fri, 4 Jul 2025 17:54:32 +0530 Subject: [PATCH 2/6] asoc: handle heap overflow in effect driver adds a variable prev_config_param_length to track the previous configuration parameter length. This is initialized to 0 and updated after processing the EQ_CONFIG command. This allows the function to compare the current and previous configuration parameter lengths to determine if memory reallocation is necessary. Change-Id: Ib03406b862b6299c421840cc193760096e2db5d9 (cherry picked from commit f770020be262cc1470eea0ce5261e08c74685764) --- asoc/msm-audio-effects-q6-v2.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/asoc/msm-audio-effects-q6-v2.c b/asoc/msm-audio-effects-q6-v2.c index cb795f5bef45..4a7b4b32654e 100644 --- a/asoc/msm-audio-effects-q6-v2.c +++ b/asoc/msm-audio-effects-q6-v2.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* Copyright (c) 2013-2021, The Linux Foundation. All rights reserved. * Copyright (c) 2023, Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ #include @@ -1091,7 +1092,7 @@ int msm_audio_effects_popless_eq_handler(struct audio_client *ac, u32 packed_data_size = 0; u8 *eq_config_data = NULL; u32 *updt_config_data = NULL; - int config_param_length; + int config_param_length, prev_config_param_length = 0; pr_debug("%s\n", __func__); if (!ac || (devices == -EINVAL) || (num_commands == -EINVAL)) { @@ -1211,7 +1212,12 @@ int msm_audio_effects_popless_eq_handler(struct audio_client *ac, if (!eq_config_data) eq_config_data = kzalloc(config_param_length, GFP_KERNEL); - else + else if (config_param_length != prev_config_param_length) { + if (eq_config_data) + kfree(eq_config_data); + eq_config_data = kzalloc(config_param_length, + GFP_KERNEL); + } else memset(eq_config_data, 0, config_param_length); if (!eq_config_data) { pr_err("%s, EQ_CONFIG:memory alloc failed\n", @@ -1238,6 +1244,7 @@ int msm_audio_effects_popless_eq_handler(struct audio_client *ac, *updt_config_data++ = eq->per_band_cfg[idx].band_idx; } + prev_config_param_length = config_param_length; break; case EQ_BAND_INDEX: if (length != 1 || index_offset != 0) { @@ -1320,7 +1327,8 @@ int msm_audio_effects_popless_eq_handler(struct audio_client *ac, pr_debug("%s: did not send pp params\n", __func__); invalid_config: kfree(params); - kfree(eq_config_data); + if (eq_config_data) + kfree(eq_config_data); return rc; } EXPORT_SYMBOL(msm_audio_effects_popless_eq_handler); From ad1e75a8ed2b8330151841b8bc322b150a9411c8 Mon Sep 17 00:00:00 2001 From: Shalini Manjunatha Date: Mon, 16 Jun 2025 19:10:01 +0530 Subject: [PATCH 3/6] asoc: compress: race condition handling in stream cmd put function protect driver data using mutex lock available to protect against race condtion due to multiple thread access. Change-Id: I7dbff3448958b1700ecca2a090fcb915d5809f30 (cherry picked from commit a9530af1782911e76fa765fd9db7c1ad20710f1d) --- asoc/msm-compress-q6-v2.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/asoc/msm-compress-q6-v2.c b/asoc/msm-compress-q6-v2.c index 14f549310547..df48c414b05b 100644 --- a/asoc/msm-compress-q6-v2.c +++ b/asoc/msm-compress-q6-v2.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* Copyright (c) 2012-2021, The Linux Foundation. All rights reserved. * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.​ */ @@ -4219,6 +4220,7 @@ static int msm_compr_adsp_stream_cmd_put(struct snd_kcontrol *kcontrol, return -EINVAL; } + mutex_lock(&pdata->lock); cstream = pdata->cstream[fe_id]; if (cstream == NULL) { pr_err("%s cstream is null\n", __func__); @@ -4231,7 +4233,6 @@ static int msm_compr_adsp_stream_cmd_put(struct snd_kcontrol *kcontrol, return -EINVAL; } - mutex_lock(&pdata->lock); if (prtd->audio_client == NULL) { pr_err("%s: audio_client is null\n", __func__); ret = -EINVAL; From bf2e9f51c58f437dcfed7a607dd7e89280d09c57 Mon Sep 17 00:00:00 2001 From: Shalini Manjunatha Date: Thu, 5 Jun 2025 18:01:42 +0530 Subject: [PATCH 4/6] asoc: lsm: thread safety issue while accessing substream data Added mutex protection while accessing substream data to avoid potential race conditions when accessing this resource from multiple threads. Change-Id: I92e368a73ec2c683c7fcbb4579a19214cc60d1d2 --- asoc/msm-lsm-client.c | 43 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 40 insertions(+), 3 deletions(-) diff --git a/asoc/msm-lsm-client.c b/asoc/msm-lsm-client.c index bd9b73571263..b18a558848d2 100644 --- a/asoc/msm-lsm-client.c +++ b/asoc/msm-lsm-client.c @@ -42,6 +42,11 @@ #define LSM_IS_LAST_STAGE(client, stage_idx) \ (client->num_stages == (stage_idx + 1)) +struct lsm_char_dev { + /* Protects access to LSM client sessions and shared resources */ + struct mutex lock; +}; + static struct snd_pcm_hardware msm_pcm_hardware_capture = { .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_BLOCK_TRANSFER | @@ -3106,9 +3111,11 @@ static int msm_lsm_close(struct snd_pcm_substream *substream) { unsigned long flags; struct snd_pcm_runtime *runtime = substream->runtime; - struct lsm_priv *prtd = runtime->private_data; + struct lsm_priv *prtd = NULL; struct snd_soc_pcm_runtime *rtd; struct msm_pcm_stream_app_type_cfg cfg_data = {0}; + struct lsm_char_dev *lsm_dev; + struct snd_soc_component *component = NULL; int ret = 0; int be_id = 0; int fe_id = 0; @@ -3117,12 +3124,29 @@ static int msm_lsm_close(struct snd_pcm_substream *substream) pr_err("%s: Invalid private_data", __func__); return -EINVAL; } - if (!prtd || !prtd->lsm_client) { - pr_err("%s: No LSM session active\n", __func__); + if (!component || !component->dev) { + pr_err("%s: Invalid component\n", __func__); return -EINVAL; } rtd = substream->private_data; + lsm_dev = (struct lsm_char_dev *) dev_get_drvdata(component->dev); + if (!lsm_dev) { + pr_err("%s: platform data is NULL\n", __func__); + return -EINVAL; + } + mutex_lock(&lsm_dev->lock); + if (!runtime) { + pr_err("%s: Invalid runtime", __func__); + mutex_unlock(&lsm_dev->lock); + return -EINVAL; + } + prtd = runtime->private_data; + if (!prtd || !prtd->lsm_client) { + pr_err("%s: No LSM session active\n", __func__); + mutex_unlock(&lsm_dev->lock); + return -EINVAL; + } dev_dbg(rtd->dev, "%s\n", __func__); if (prtd->lsm_client->started) { if (prtd->lsm_client->lab_enable) { @@ -3232,6 +3256,7 @@ static int msm_lsm_close(struct snd_pcm_substream *substream) mutex_destroy(&prtd->lsm_api_lock); kfree(prtd); runtime->private_data = NULL; + mutex_unlock(&lsm_dev->lock); return 0; } @@ -3629,6 +3654,14 @@ static struct snd_soc_component_driver msm_soc_component = { static int msm_lsm_probe(struct platform_device *pdev) { + struct lsm_char_dev *lsm_dev; + + lsm_dev = devm_kzalloc(&pdev->dev, sizeof(*lsm_dev), GFP_KERNEL); + if (!lsm_dev) + return -ENOMEM; + + mutex_init(&lsm_dev->lock); + dev_set_drvdata(&pdev->dev, lsm_dev); return snd_soc_register_component(&pdev->dev, &msm_soc_component, NULL, 0); @@ -3636,6 +3669,10 @@ static int msm_lsm_probe(struct platform_device *pdev) static int msm_lsm_remove(struct platform_device *pdev) { + struct lsm_char_dev *lsm_dev; + lsm_dev = dev_get_drvdata(&pdev->dev); + mutex_destroy(&lsm_dev->lock); + snd_soc_unregister_component(&pdev->dev); return 0; From 5fceb1d45f380d709de958a5c45c167708e027b3 Mon Sep 17 00:00:00 2001 From: Akshaya Chirikonda Date: Fri, 13 Jun 2025 12:54:00 +0530 Subject: [PATCH 5/6] asoc: lsm: Race condition protection in confidence levels handling Added mutex protection around freeing confidence_levels to prevent potential race conditions when accessing this memory. Change-Id: I38ec13791a0e99f3ea5f3b2aaf983a1860e7aeeb --- asoc/msm-lsm-client.c | 40 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/asoc/msm-lsm-client.c b/asoc/msm-lsm-client.c index b18a558848d2..85566e51dd76 100644 --- a/asoc/msm-lsm-client.c +++ b/asoc/msm-lsm-client.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2013-2020, The Linux Foundation. All rights reserved. - * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ #include #include @@ -688,15 +688,47 @@ static int msm_lsm_set_conf(struct snd_pcm_substream *substream, struct lsm_params_info_v2 *p_info) { struct snd_pcm_runtime *runtime = substream->runtime; - struct lsm_priv *prtd = runtime->private_data; + struct lsm_priv *prtd = NULL; struct snd_soc_pcm_runtime *rtd = substream->private_data; int rc = 0; + struct lsm_char_dev *lsm_dev; + struct snd_soc_component *component = NULL; + + if (!rtd) { + pr_err("%s substream runtime or private_data not found\n", + __func__); + return -EINVAL; + } + component = snd_soc_rtdcom_lookup(rtd, DRV_NAME); + if (!component || !component->dev) { + pr_err("%s: invalid component\n", __func__); + return -EINVAL; + } + lsm_dev = (struct lsm_char_dev *) dev_get_drvdata(component->dev); + if (!lsm_dev) { + pr_err("%s: platform data is NULL\n", __func__); + return -EINVAL; + } + + mutex_lock(&lsm_dev->lock); + if (!runtime) { + pr_err("%s: Invalid runtime", __func__); + mutex_unlock(&lsm_dev->lock); + return -EINVAL; + } + prtd = runtime->private_data; + if (!prtd || !prtd->lsm_client) { + pr_err("%s: No LSM session active\n", __func__); + mutex_unlock(&lsm_dev->lock); + return -EINVAL; + } if (p_info->param_type == LSM_MULTI_SND_MODEL_CONFIDENCE_LEVELS) { if (p_info->param_size > MAX_KEYWORDS_SUPPORTED) { dev_err(rtd->dev, "%s: invalid number of snd_model keywords %d, the max is %d\n", __func__, p_info->param_size, MAX_KEYWORDS_SUPPORTED); + mutex_unlock(&lsm_dev->lock); return -EINVAL; } @@ -707,6 +739,7 @@ static int msm_lsm_set_conf(struct snd_pcm_substream *substream, dev_err(rtd->dev, "%s: get_conf_levels failed for snd_model %d, err = %d\n", __func__, p_info->model_id, rc); + mutex_unlock(&lsm_dev->lock); return rc; } @@ -727,6 +760,7 @@ static int msm_lsm_set_conf(struct snd_pcm_substream *substream, dev_err(rtd->dev, "%s: invalid confidence levels %d\n", __func__, p_info->param_size); + mutex_unlock(&lsm_dev->lock); return -EINVAL; } @@ -738,6 +772,7 @@ static int msm_lsm_set_conf(struct snd_pcm_substream *substream, dev_err(rtd->dev, "%s: get_conf_levels failed, err = %d\n", __func__, rc); + mutex_unlock(&lsm_dev->lock); return rc; } @@ -754,6 +789,7 @@ static int msm_lsm_set_conf(struct snd_pcm_substream *substream, prtd->lsm_client->confidence_levels = NULL; } } + mutex_unlock(&lsm_dev->lock); return rc; } From 86664f1bbf83f1dc16f77cd8ffab6ce3a3eb35bd Mon Sep 17 00:00:00 2001 From: Shalini Manjunatha Date: Fri, 13 Jun 2025 12:59:44 +0530 Subject: [PATCH 6/6] asoc: lsm: thread safety issue in hw params management Added mutex protection while accessing lsm client hw params to avoid potential race conditions when accessing this resource from multiple threads. Change-Id: Ib2cbb954cb145a7a194e8af753cdaf434835b245 --- asoc/msm-lsm-client.c | 67 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 63 insertions(+), 4 deletions(-) diff --git a/asoc/msm-lsm-client.c b/asoc/msm-lsm-client.c index 85566e51dd76..7d69b97ca7c6 100644 --- a/asoc/msm-lsm-client.c +++ b/asoc/msm-lsm-client.c @@ -1030,23 +1030,63 @@ static int msm_lsm_check_and_set_lab_controls(struct snd_pcm_substream *substrea u32 enable, struct lsm_params_info_v2 *p_info) { struct snd_pcm_runtime *runtime = substream->runtime; - struct lsm_priv *prtd = runtime->private_data; + struct lsm_priv *prtd = NULL; struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct lsm_hw_params *out_hw_params = &prtd->lsm_client->out_hw_params; + struct lsm_hw_params *out_hw_params = NULL; + struct snd_soc_component *component = NULL; + struct lsm_char_dev *lsm_dev = NULL; u8 *chmap = NULL; u32 ch_idx; int rc = 0, stage_idx = p_info->stage_idx; + if (!rtd) { + pr_err("%s substream runtime or private_data not found\n", + __func__); + return -EINVAL; + } + component = snd_soc_rtdcom_lookup(rtd, DRV_NAME); + if (!component || !component->dev) { + pr_err("%s: invalid component\n", __func__); + return -EINVAL; + } + lsm_dev = (struct lsm_char_dev *) dev_get_drvdata(component->dev); + if (!lsm_dev) { + pr_err("%s: platform data is NULL\n", __func__); + return -EINVAL; + } + + mutex_lock(&lsm_dev->lock); + if (!runtime) { + pr_err("%s: Invalid runtime", __func__); + mutex_unlock(&lsm_dev->lock); + return -EINVAL; + } + prtd = runtime->private_data; + if (!prtd || !prtd->lsm_client) { + pr_err("%s: No LSM session active\n", __func__); + mutex_unlock(&lsm_dev->lock); + return -EINVAL; + } + out_hw_params = &prtd->lsm_client->out_hw_params; + if (!out_hw_params) { + pr_err("%s: Invalid hw params\n", __func__); + mutex_unlock(&lsm_dev->lock); + return -EINVAL; + } + if (prtd->lsm_client->stage_cfg[stage_idx].lab_enable == enable) { dev_dbg(rtd->dev, "%s: Lab for session %d, stage %d already %s\n", __func__, prtd->lsm_client->session, stage_idx, enable ? "enabled" : "disabled"); + mutex_unlock(&lsm_dev->lock); return rc; } chmap = kzalloc(out_hw_params->num_chs, GFP_KERNEL); - if (!chmap) + if (!chmap) { + mutex_unlock(&lsm_dev->lock); return -ENOMEM; + } rc = q6lsm_lab_control(prtd->lsm_client, enable, p_info); if (rc) { @@ -1087,6 +1127,7 @@ static int msm_lsm_check_and_set_lab_controls(struct snd_pcm_substream *substrea fail: kfree(chmap); + mutex_unlock(&lsm_dev->lock); return rc; } @@ -3301,21 +3342,36 @@ static int msm_lsm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { struct snd_pcm_runtime *runtime = substream->runtime; - struct lsm_priv *prtd = runtime->private_data; + struct lsm_priv *prtd = NULL; struct lsm_hw_params *out_hw_params = NULL; struct lsm_hw_params *in_hw_params = NULL; struct snd_soc_pcm_runtime *rtd; + struct lsm_char_dev *lsm_dev = NULL; + struct snd_soc_component *component = NULL; if (!substream->private_data) { pr_err("%s: Invalid private_data", __func__); return -EINVAL; } rtd = substream->private_data; + component = snd_soc_rtdcom_lookup(rtd, DRV_NAME); + if (!component || !component->dev) { + pr_err("%s: Invalid component\n", __func__); + return -EINVAL; + } + lsm_dev = (struct lsm_char_dev *) dev_get_drvdata(component->dev); + if (!lsm_dev) { + pr_err("%s: platform data is NULL\n", __func__); + return -EINVAL; + } + mutex_lock(&lsm_dev->lock); + prtd = runtime->private_data; if (!prtd || !params) { dev_err(rtd->dev, "%s: invalid params prtd %pK params %pK", __func__, prtd, params); + mutex_unlock(&lsm_dev->lock); return -EINVAL; } in_hw_params = &prtd->lsm_client->in_hw_params; @@ -3330,6 +3386,7 @@ static int msm_lsm_hw_params(struct snd_pcm_substream *substream, "%s: Invalid Params sample rate %d period count %d\n", __func__, out_hw_params->sample_rate, out_hw_params->period_count); + mutex_unlock(&lsm_dev->lock); return -EINVAL; } @@ -3340,6 +3397,7 @@ static int msm_lsm_hw_params(struct snd_pcm_substream *substream, } else { dev_err(rtd->dev, "%s: Invalid Format 0x%x\n", __func__, params_format(params)); + mutex_unlock(&lsm_dev->lock); return -EINVAL; } @@ -3360,6 +3418,7 @@ static int msm_lsm_hw_params(struct snd_pcm_substream *substream, */ memcpy(in_hw_params, out_hw_params, sizeof(struct lsm_hw_params)); + mutex_unlock(&lsm_dev->lock); return 0; }