summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAjit Pandey <ajitp@codeaurora.org>2019-09-05 16:26:01 +0530
committerJJ Lee <leejj@google.com>2020-02-04 14:22:48 +0800
commit7c0928718ec1471e8ad53cf1ba57b78141aa1236 (patch)
tree2f4d64a0eba78d4760d7a04f26e9265f380f2ee6
parented9c34abfe474ab33c7a0db35a7f27398824f8d8 (diff)
downloadmsm-extra-7c0928718ec1471e8ad53cf1ba57b78141aa1236.tar.gz
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. Bug: 147101660 Change-Id: Ic160b0c7c29d0ea5d517b3bacc53828d8d61e085 Signed-off-by: Ajit Pandey <ajitp@codeaurora.org>
-rw-r--r--asoc/msm-pcm-q6-v2.c89
-rw-r--r--asoc/msm-pcm-q6-v2.h1
2 files changed, 87 insertions, 3 deletions
diff --git a/asoc/msm-pcm-q6-v2.c b/asoc/msm-pcm-q6-v2.c
index ca7caeb6..897d758c 100644
--- a/asoc/msm-pcm-q6-v2.c
+++ b/asoc/msm-pcm-q6-v2.c
@@ -16,6 +16,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>
@@ -891,6 +892,14 @@ static int msm_pcm_playback_close(struct snd_pcm_substream *substream)
pr_debug("%s: cmd_pending 0x%lx\n", __func__, prtd->cmd_pending);
+ pdata = (struct msm_plat_data *)
+ dev_get_drvdata(soc_prtd->platform->dev);
+ if (!pdata) {
+ pr_err("%s: platform data is NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ mutex_lock(&pdata->lock);
if (prtd->audio_client) {
dir = IN;
@@ -898,8 +907,6 @@ static int msm_pcm_playback_close(struct snd_pcm_substream *substream)
* Unvote to downgrade the Rx thread priority from
* RT Thread for Low-Latency use case.
*/
- pdata = (struct msm_plat_data *)
- dev_get_drvdata(soc_prtd->platform->dev);
if (pdata) {
if (pdata->perf_mode == LOW_LATENCY_PCM_MODE)
apr_end_rx_rt(prtd->audio_client->apr);
@@ -933,6 +940,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;
}
@@ -1025,9 +1033,20 @@ 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 msm_plat_data *pdata;
int dir = OUT;
pr_debug("%s\n", __func__);
+
+ pdata = (struct msm_plat_data *)
+ dev_get_drvdata(soc_prtd->platform->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,
@@ -1039,6 +1058,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;
}
@@ -1201,6 +1221,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)) {
@@ -1223,6 +1244,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;
}
@@ -1386,6 +1408,8 @@ static int msm_pcm_volume_ctl_put(struct snd_kcontrol *kcontrol,
struct snd_pcm_volume *vol = snd_kcontrol_chip(kcontrol);
struct snd_pcm_substream *substream =
vol->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
+ struct snd_soc_pcm_runtime *soc_prtd = NULL;
+ struct msm_plat_data *pdata = NULL;
struct msm_audio *prtd;
int volume = ucontrol->value.integer.value[0];
@@ -1398,11 +1422,27 @@ static int msm_pcm_volume_ctl_put(struct snd_kcontrol *kcontrol,
pr_err("%s substream runtime not found\n", __func__);
return 0;
}
+
+ soc_prtd = substream->private_data;
+ if (!soc_prtd) {
+ pr_err("%s: soc_prtd is NULL\n", __func__);
+ return -ENODEV;
+ }
+
+ pdata = (struct msm_plat_data *)
+ dev_get_drvdata(soc_prtd->platform->dev);
+ if (!pdata) {
+ pr_err("%s: platform data is NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ 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;
}
@@ -1565,15 +1605,32 @@ static int msm_pcm_chmap_ctl_put(struct snd_kcontrol *kcontrol,
struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol);
unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
struct snd_pcm_substream *substream;
+ struct snd_soc_pcm_runtime *soc_prtd = NULL;
+ struct msm_plat_data *pdata = NULL;
struct msm_audio *prtd;
pr_debug("%s", __func__);
substream = snd_pcm_chmap_substream(info, idx);
if (!substream)
return -ENODEV;
+
if (!substream->runtime)
return 0;
+ soc_prtd = substream->private_data;
+ if (!soc_prtd) {
+ pr_err("%s: soc_prtd is NULL\n", __func__);
+ return -ENODEV;
+ }
+
+ pdata = (struct msm_plat_data *)
+ dev_get_drvdata(soc_prtd->platform->dev);
+ if (!pdata) {
+ pr_err("%s: platform data is NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ mutex_lock(&pdata->lock);
prtd = substream->runtime->private_data;
if (prtd) {
prtd->set_channel_map = true;
@@ -1581,6 +1638,7 @@ static int msm_pcm_chmap_ctl_put(struct snd_kcontrol *kcontrol,
prtd->channel_map[i] =
(char)(ucontrol->value.integer.value[i]);
}
+ mutex_unlock(&pdata->lock);
return 0;
}
@@ -1591,17 +1649,37 @@ static int msm_pcm_chmap_ctl_get(struct snd_kcontrol *kcontrol,
struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol);
unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
struct snd_pcm_substream *substream;
+ struct snd_soc_pcm_runtime *soc_prtd = NULL;
+ struct msm_plat_data *pdata = NULL;
struct msm_audio *prtd;
pr_debug("%s", __func__);
substream = snd_pcm_chmap_substream(info, idx);
if (!substream)
return -ENODEV;
+
memset(ucontrol->value.integer.value, 0,
sizeof(ucontrol->value.integer.value));
if (!substream->runtime)
return 0; /* no channels set */
+ soc_prtd = substream->private_data;
+ if (!soc_prtd) {
+ pr_err("%s: soc_prtd is NULL\n", __func__);
+ return -ENODEV;
+ }
+
+ pdata = (struct msm_plat_data *)
+ dev_get_drvdata(soc_prtd->platform->dev);
+ if (!pdata) {
+ pr_err("%s: platform data is NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ memset(ucontrol->value.integer.value, 0,
+ sizeof(ucontrol->value.integer.value));
+
+ mutex_lock(&pdata->lock);
prtd = substream->runtime->private_data;
if (prtd && prtd->set_channel_map == true) {
@@ -1613,6 +1691,7 @@ static int msm_pcm_chmap_ctl_get(struct snd_kcontrol *kcontrol,
ucontrol->value.integer.value[i] = 0;
}
+ mutex_unlock(&pdata->lock);
return 0;
}
@@ -1839,18 +1918,21 @@ static int msm_pcm_path_latency_ctl_get(struct snd_kcontrol *kcontrol,
return -EINVAL;
}
+ mutex_lock(&pdata->lock);
prtd = substream->runtime->private_data;
if (prtd) {
rc = q6asm_get_path_delay(prtd->audio_client);
if (rc) {
pr_err("%s: get_path_delay failed, ret=%d\n",
__func__, rc);
+ mutex_lock(&pdata->lock);
return -EINVAL;
}
ucontrol->value.integer.value[0] =
prtd->audio_client->path_delay;
}
+ mutex_unlock(&pdata->lock);
return rc;
}
@@ -2108,7 +2190,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);
@@ -2123,6 +2205,7 @@ static int msm_pcm_remove(struct platform_device *pdev)
struct msm_plat_data *pdata;
pdata = dev_get_drvdata(&pdev->dev);
+ mutex_destroy(&pdata->lock);
kfree(pdata);
snd_soc_unregister_platform(&pdev->dev);
return 0;
diff --git a/asoc/msm-pcm-q6-v2.h b/asoc/msm-pcm-q6-v2.h
index a4b42352..e7ed3def 100644
--- a/asoc/msm-pcm-q6-v2.h
+++ b/asoc/msm-pcm-q6-v2.h
@@ -128,6 +128,7 @@ struct msm_plat_data {
int perf_mode;
struct snd_pcm *pcm[MSM_FRONTEND_DAI_MAX];
struct msm_pcm_ch_map *ch_map[MSM_FRONTEND_DAI_MAX];
+ struct mutex lock;
};
struct msm_pcm_ch_map {