summaryrefslogtreecommitdiff
path: root/drivers/soc/qcom/qdsp6v2/voice_svc.c
diff options
context:
space:
mode:
authorsmanag <smanag@codeaurora.org>2017-11-14 14:57:57 +0530
committerGerrit - the friendly Code Review server <code-review@localhost>2018-02-20 18:01:58 -0800
commit6ff791a34d68cab5428d1d3a68853559f439e722 (patch)
treee5a9e8d377398018a612404bba5c63b32c7502f1 /drivers/soc/qcom/qdsp6v2/voice_svc.c
parenta961632a48ed39c18014debc4201e3ea5b6e3dd0 (diff)
drivers: soc: Synchronize apr callback and voice svc release
Issue is seen when apr callback is received while voice_svc_release is in process of freeing the driver private data. Avoid invalid access of private data pointer by putting the callback and release functions in the same locked context. Change-Id: I93af13cab0a3c7e653a9bc9fa7f4f86bfa0502df Signed-off-by: smanag <smanag@codeaurora.org>
Diffstat (limited to 'drivers/soc/qcom/qdsp6v2/voice_svc.c')
-rw-r--r--drivers/soc/qcom/qdsp6v2/voice_svc.c40
1 files changed, 38 insertions, 2 deletions
diff --git a/drivers/soc/qcom/qdsp6v2/voice_svc.c b/drivers/soc/qcom/qdsp6v2/voice_svc.c
index fe5458974406..c560ec7d7401 100644
--- a/drivers/soc/qcom/qdsp6v2/voice_svc.c
+++ b/drivers/soc/qcom/qdsp6v2/voice_svc.c
@@ -14,6 +14,7 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
+#include <linux/spinlock.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/slab.h>
@@ -67,7 +68,11 @@ static void *dummy_q6_mvm;
static void *dummy_q6_cvs;
dev_t device_num;
+static spinlock_t voicesvc_lock;
+static bool is_released;
static int voice_svc_dummy_reg(void);
+static int voice_svc_dummy_dereg(void);
+
static int32_t qdsp_dummy_apr_callback(struct apr_client_data *data,
void *priv);
@@ -82,10 +87,16 @@ static int32_t qdsp_apr_callback(struct apr_client_data *data, void *priv)
return -EINVAL;
}
+ spin_lock(&voicesvc_lock);
+ if (is_released) {
+ spin_unlock(&voicesvc_lock);
+ return 0;
+ }
prtd = (struct voice_svc_prvt *)priv;
if (prtd == NULL) {
pr_err("%s: private data is NULL\n", __func__);
+ spin_unlock(&voicesvc_lock);
return -EINVAL;
}
@@ -128,6 +139,7 @@ static int32_t qdsp_apr_callback(struct apr_client_data *data, void *priv)
spin_unlock_irqrestore(&prtd->response_lock,
spin_flags);
+ spin_unlock(&voicesvc_lock);
return -ENOMEM;
}
@@ -156,6 +168,7 @@ static int32_t qdsp_apr_callback(struct apr_client_data *data, void *priv)
__func__);
}
+ spin_unlock(&voicesvc_lock);
return 0;
}
@@ -614,6 +627,21 @@ err:
return -EINVAL;
}
+static int voice_svc_dummy_dereg(void)
+{
+ pr_debug("%s\n", __func__);
+ if (dummy_q6_mvm != NULL) {
+ apr_deregister(dummy_q6_mvm);
+ dummy_q6_mvm = NULL;
+ }
+
+ if (dummy_q6_cvs != NULL) {
+ apr_deregister(dummy_q6_cvs);
+ dummy_q6_cvs = NULL;
+ }
+ return 0;
+}
+
static int voice_svc_open(struct inode *inode, struct file *file)
{
struct voice_svc_prvt *prtd = NULL;
@@ -637,6 +665,7 @@ static int voice_svc_open(struct inode *inode, struct file *file)
mutex_init(&prtd->response_mutex_lock);
file->private_data = (void *)prtd;
+ is_released = 0;
/* Current APR implementation doesn't support session based
* multiple service registrations. The apr_deregister()
* function sets the destination and client IDs to zero, if
@@ -669,6 +698,11 @@ static int voice_svc_release(struct inode *inode, struct file *file)
goto done;
}
+ mutex_lock(&prtd->response_mutex_lock);
+ if (reg_dummy_sess) {
+ voice_svc_dummy_dereg();
+ reg_dummy_sess = 0;
+ }
if (prtd->apr_q6_cvs != NULL) {
svc_name = VOICE_SVC_MVM_STR;
handle = &prtd->apr_q6_cvs;
@@ -685,7 +719,6 @@ static int voice_svc_release(struct inode *inode, struct file *file)
pr_err("%s: Failed to dereg MVM %d\n", __func__, ret);
}
- mutex_lock(&prtd->response_mutex_lock);
spin_lock_irqsave(&prtd->response_lock, spin_flags);
while (!list_empty(&prtd->response_queue)) {
@@ -703,9 +736,11 @@ static int voice_svc_release(struct inode *inode, struct file *file)
mutex_destroy(&prtd->response_mutex_lock);
+ spin_lock(&voicesvc_lock);
kfree(file->private_data);
file->private_data = NULL;
-
+ is_released = 1;
+ spin_unlock(&voicesvc_lock);
done:
return ret;
}
@@ -774,6 +809,7 @@ static int voice_svc_probe(struct platform_device *pdev)
goto add_err;
}
pr_debug("%s: Device created\n", __func__);
+ spin_lock_init(&voicesvc_lock);
goto done;
add_err: