asoc: msm-pcm: Added lock in controls _put() and _get() callback

There is race condition around private data used in put() and get()
of few mixer ctls with close() callback. Added global mutex lock and
code changes to protect such critical section by accessing such lock.

Change-Id: Ic160b0c7c29d0ea5d517b3bacc53828d8d61e085
Signed-off-by: Ajit Pandey <ajitp@codeaurora.org>
This commit is contained in:
Ajit Pandey 2019-09-05 16:26:01 +05:30
parent fa018867ef
commit a557d960dd
2 changed files with 105 additions and 18 deletions

View File

@ -8,6 +8,7 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/time.h>
#include <linux/mutex.h>
#include <linux/wait.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
@ -897,19 +898,25 @@ static int msm_pcm_playback_close(struct snd_pcm_substream *substream)
pr_debug("%s: cmd_pending 0x%lx\n", __func__, prtd->cmd_pending);
if (!component) {
pr_err("%s: component is NULL\n", __func__);
return -EINVAL;
}
pdata = (struct msm_plat_data *) dev_get_drvdata(component->dev);
if (!pdata) {
pr_err("%s: platform data is NULL\n", __func__);
return -EINVAL;
}
mutex_lock(&pdata->lock);
if (prtd->audio_client) {
dir = IN;
if (!component) {
pr_err("%s: component is NULL\n", __func__);
return -EINVAL;
}
/*
* Unvote to downgrade the Rx thread priority from
* RT Thread for Low-Latency use case.
*/
pdata = (struct msm_plat_data *)
dev_get_drvdata(component->dev);
if (pdata) {
if (pdata->perf_mode == LOW_LATENCY_PCM_MODE)
apr_end_rx_rt(prtd->audio_client->apr);
@ -943,7 +950,7 @@ static int msm_pcm_playback_close(struct snd_pcm_substream *substream)
msm_adsp_clean_mixer_ctl_pp_event_queue(soc_prtd);
kfree(prtd);
runtime->private_data = NULL;
mutex_unlock(&pdata->lock);
return 0;
}
@ -1035,9 +1042,25 @@ static int msm_pcm_capture_close(struct snd_pcm_substream *substream)
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_soc_pcm_runtime *soc_prtd = substream->private_data;
struct msm_audio *prtd = runtime->private_data;
struct snd_soc_component *component =
snd_soc_rtdcom_lookup(soc_prtd, DRV_NAME);
struct msm_plat_data *pdata;
int dir = OUT;
pr_debug("%s\n", __func__);
if (!component) {
pr_err("%s: component is NULL\n", __func__);
return -EINVAL;
}
pdata = (struct msm_plat_data *) dev_get_drvdata(component->dev);
if (!pdata) {
pr_err("%s: platform data is NULL\n", __func__);
return -EINVAL;
}
mutex_lock(&pdata->lock);
if (prtd->audio_client) {
q6asm_cmd(prtd->audio_client, CMD_CLOSE);
q6asm_audio_client_buf_free_contiguous(dir,
@ -1049,7 +1072,7 @@ static int msm_pcm_capture_close(struct snd_pcm_substream *substream)
SNDRV_PCM_STREAM_CAPTURE);
kfree(prtd);
runtime->private_data = NULL;
mutex_unlock(&pdata->lock);
return 0;
}
@ -1316,6 +1339,7 @@ static int msm_pcm_adsp_stream_cmd_put(struct snd_kcontrol *kcontrol,
goto done;
}
mutex_lock(&pdata->lock);
event_data = (struct msm_adsp_event_data *)ucontrol->value.bytes.data;
if ((event_data->event_type < ADSP_STREAM_PP_EVENT) ||
(event_data->event_type >= ADSP_STREAM_EVENT_MAX)) {
@ -1338,6 +1362,7 @@ static int msm_pcm_adsp_stream_cmd_put(struct snd_kcontrol *kcontrol,
pr_err("%s: failed to send stream event cmd, err = %d\n",
__func__, ret);
done:
mutex_unlock(&pdata->lock);
return ret;
}
@ -1513,25 +1538,46 @@ static int msm_pcm_volume_ctl_put(struct snd_kcontrol *kcontrol,
{
int rc = 0;
struct snd_pcm_volume *vol = snd_kcontrol_chip(kcontrol);
struct msm_plat_data *pdata = NULL;
struct snd_pcm_substream *substream =
vol->pcm->streams[vol->stream].substream;
struct snd_soc_pcm_runtime *soc_prtd = NULL;
struct snd_soc_component *component = NULL;
struct msm_audio *prtd;
int volume = ucontrol->value.integer.value[0];
pr_debug("%s: volume : 0x%x\n", __func__, volume);
if (!substream) {
pr_err("%s substream not found\n", __func__);
pr_err("%s: substream not found\n", __func__);
return -ENODEV;
}
if (!substream->runtime) {
pr_err("%s substream runtime not found\n", __func__);
soc_prtd = substream->private_data;
if (!substream->runtime || !soc_prtd) {
pr_err("%s: substream runtime or private_data not found\n",
__func__);
return 0;
}
component = snd_soc_rtdcom_lookup(soc_prtd, DRV_NAME);
if (!component) {
pr_err("%s: component is NULL\n", __func__);
return -EINVAL;
}
pdata = (struct msm_plat_data *) dev_get_drvdata(component->dev);
if (!pdata) {
pr_err("%s: pdata not found\n", __func__);
return -ENODEV;
}
mutex_lock(&pdata->lock);
prtd = substream->runtime->private_data;
if (prtd) {
rc = msm_pcm_set_volume(prtd, volume);
prtd->volume = volume;
}
mutex_unlock(&pdata->lock);
return rc;
}
@ -1711,9 +1757,27 @@ static int msm_pcm_chmap_ctl_put(struct snd_kcontrol *kcontrol,
substream = snd_pcm_chmap_substream(info, idx);
if (!substream)
return -ENODEV;
if (!substream->runtime)
rtd = substream->private_data;
if (rtd) {
component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
if (component) {
pdata = (struct msm_plat_data *)
dev_get_drvdata(component->dev);
if (!pdata) {
pr_err("%s: pdata not found\n", __func__);
return -ENODEV;
}
} else {
pr_err("%s: component is NULL\n", __func__);
return -EINVAL;
}
}
if (!substream->runtime || !rtd)
return 0;
mutex_lock(&pdata->lock);
prtd = substream->runtime->private_data;
if (prtd) {
prtd->set_channel_map = true;
@ -1722,13 +1786,9 @@ static int msm_pcm_chmap_ctl_put(struct snd_kcontrol *kcontrol,
(char)(ucontrol->value.integer.value[i]);
/* update chmixer_pspd chmap cached with routing driver as well */
rtd = substream->private_data;
if (rtd) {
component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
if (component) {
fe_id = rtd->dai_link->id;
pdata = (struct msm_plat_data *)
dev_get_drvdata(component->dev);
chmixer_pspd = pdata ?
pdata->chmixer_pspd[fe_id][SESSION_TYPE_RX] : NULL;
@ -1742,6 +1802,7 @@ static int msm_pcm_chmap_ctl_put(struct snd_kcontrol *kcontrol,
}
}
}
mutex_unlock(&pdata->lock);
return 0;
}
@ -1753,16 +1814,37 @@ static int msm_pcm_chmap_ctl_get(struct snd_kcontrol *kcontrol,
unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
struct snd_pcm_substream *substream;
struct msm_audio *prtd;
struct snd_soc_pcm_runtime *rtd = NULL;
struct msm_plat_data *pdata = NULL;
struct snd_soc_component *component = NULL;
pr_debug("%s", __func__);
substream = snd_pcm_chmap_substream(info, idx);
if (!substream)
return -ENODEV;
rtd = substream->private_data;
if (rtd) {
component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
if (component) {
pdata = (struct msm_plat_data *)
dev_get_drvdata(component->dev);
if (!pdata) {
pr_err("%s: pdata not found\n", __func__);
return -ENODEV;
}
} else {
pr_err("%s: component is NULL\n", __func__);
return -EINVAL;
}
}
memset(ucontrol->value.integer.value, 0,
sizeof(ucontrol->value.integer.value));
if (!substream->runtime)
if (!substream->runtime || !rtd)
return 0; /* no channels set */
mutex_lock(&pdata->lock);
prtd = substream->runtime->private_data;
if (prtd && prtd->set_channel_map == true) {
@ -1774,6 +1856,7 @@ static int msm_pcm_chmap_ctl_get(struct snd_kcontrol *kcontrol,
ucontrol->value.integer.value[i] = 0;
}
mutex_unlock(&pdata->lock);
return 0;
}
@ -2043,6 +2126,7 @@ static int msm_pcm_channel_mixer_cfg_ctl_put(struct snd_kcontrol *kcontrol,
return -EINVAL;
}
mutex_lock(&pdata->lock);
prtd = substream->runtime ? substream->runtime->private_data : NULL;
if (chmixer_pspd->enable && prtd) {
if (session_type == SESSION_TYPE_RX &&
@ -2095,6 +2179,7 @@ static int msm_pcm_channel_mixer_cfg_ctl_put(struct snd_kcontrol *kcontrol,
if (reset_override_in_ch_map)
chmixer_pspd->override_in_ch_map = false;
mutex_unlock(&pdata->lock);
return ret;
}
@ -2756,7 +2841,7 @@ static int msm_pcm_probe(struct platform_device *pdev)
} else {
pdata->perf_mode = LEGACY_PCM_MODE;
}
mutex_init(&pdata->lock);
dev_set_drvdata(&pdev->dev, pdata);
@ -2779,6 +2864,7 @@ static int msm_pcm_remove(struct platform_device *pdev)
kfree(pdata->chmixer_pspd[i][SESSION_TYPE_TX]);
}
}
mutex_destroy(&pdata->lock);
kfree(pdata);
snd_soc_unregister_component(&pdev->dev);
return 0;

View File

@ -117,6 +117,7 @@ struct msm_plat_data {
struct msm_pcm_ch_map *ch_map[MSM_FRONTEND_DAI_MAX];
struct snd_pcm *pcm_device[MSM_FRONTEND_DAI_MM_SIZE];
struct msm_pcm_channel_mixer *chmixer_pspd[MSM_FRONTEND_DAI_MM_SIZE][2];
struct mutex lock;
};
struct msm_pcm_ch_map {