summaryrefslogtreecommitdiff
path: root/sound/soc/fsl/fsl_asrc_m2m.c
diff options
context:
space:
mode:
authorShengjiu Wang <shengjiu.wang@freescale.com>2014-12-08 15:08:27 +0800
committerDong Aisheng <aisheng.dong@nxp.com>2019-11-25 15:48:20 +0800
commitb063e095e46db242817d39a3814a0e90ae5b3a1b (patch)
tree0514812a32338eb9b30e9c50a9eb034d8d04e3d6 /sound/soc/fsl/fsl_asrc_m2m.c
parent16d07ad5f792964b86359f4f2835657c865e1f77 (diff)
MLK-10048-3: ASoC: fsl_asrc: fix asrc crach when suspend/resume
merge 7e1a620a030d17f93fdd97d076f1cdd042e79337 The reason of crach is that some variables are not protected in function mxc_asrc_suspend(), when suspend, there is possibility to access one NULL pointer. Refine the spin lock usage, add protecting for pair_hold. Signed-off-by: Shengjiu Wang <shengjiu.wang@freescale.com> (cherry picked from commit e90c73f8170bc929cff54b0478da0573e4e26c23)
Diffstat (limited to 'sound/soc/fsl/fsl_asrc_m2m.c')
-rw-r--r--sound/soc/fsl/fsl_asrc_m2m.c36
1 files changed, 26 insertions, 10 deletions
diff --git a/sound/soc/fsl/fsl_asrc_m2m.c b/sound/soc/fsl/fsl_asrc_m2m.c
index 2ea40094e340..97c9f6af17d7 100644
--- a/sound/soc/fsl/fsl_asrc_m2m.c
+++ b/sound/soc/fsl/fsl_asrc_m2m.c
@@ -369,9 +369,10 @@ int fsl_asrc_process_buffer(struct fsl_asrc_pair *pair,
spin_unlock_irqrestore(&m2m->lock, lock_flags);
return -EFAULT;
}
- fsl_asrc_read_last_FIFO(pair);
spin_unlock_irqrestore(&m2m->lock, lock_flags);
+ fsl_asrc_read_last_FIFO(pair);
+
/* Update final lengths after getting last FIFO */
pbuf->input_buffer_length = m2m->dma_block[IN].length;
pbuf->output_buffer_length = m2m->dma_block[OUT].length;
@@ -485,6 +486,7 @@ static long fsl_asrc_ioctl_req_pair(struct fsl_asrc_pair *pair,
struct fsl_asrc_m2m *m2m = pair->private;
struct device *dev = &asrc_priv->pdev->dev;
struct asrc_req req;
+ unsigned long lock_flags;
long ret;
ret = copy_from_user(&req, user, sizeof(req));
@@ -499,7 +501,9 @@ static long fsl_asrc_ioctl_req_pair(struct fsl_asrc_pair *pair,
return ret;
}
+ spin_lock_irqsave(&m2m->lock, lock_flags);
m2m->pair_hold = 1;
+ spin_unlock_irqrestore(&m2m->lock, lock_flags);
pair->channels = req.chn_num;
req.index = pair->index;
@@ -571,9 +575,6 @@ static long fsl_asrc_ioctl_config_pair(struct fsl_asrc_pair *pair,
return -EBUSY;
}
- init_completion(&m2m->complete[IN]);
- init_completion(&m2m->complete[OUT]);
-
ret = copy_to_user(user, &config, sizeof(config));
if (ret) {
pair_err("failed to send config to user space: %ld\n", ret);
@@ -824,6 +825,9 @@ static int fsl_asrc_open(struct inode *inode, struct file *file)
pair->private = m2m;
pair->asrc_priv = asrc_priv;
+ init_completion(&m2m->complete[IN]);
+ init_completion(&m2m->complete[OUT]);
+
spin_lock_init(&m2m->lock);
file->private_data = pair;
@@ -846,9 +850,11 @@ static int fsl_asrc_close(struct inode *inode, struct file *file)
goto out;
/* Make sure we have clear the pointer */
+ spin_lock_irqsave(&asrc_priv->lock, lock_flags);
for (i = 0; i < ASRC_PAIR_MAX_NUM; i++)
if (asrc_priv->pair[i] == pair)
asrc_priv->pair[i] = NULL;
+ spin_unlock_irqrestore(&asrc_priv->lock, lock_flags);
if (m2m->asrc_active) {
m2m->asrc_active = 0;
@@ -861,8 +867,8 @@ static int fsl_asrc_close(struct inode *inode, struct file *file)
fsl_asrc_output_dma_callback((void *)pair);
}
+ spin_lock_irqsave(&m2m->lock, lock_flags);
if (m2m->pair_hold) {
- spin_lock_irqsave(&m2m->lock, lock_flags);
m2m->pair_hold = 0;
spin_unlock_irqrestore(&m2m->lock, lock_flags);
@@ -875,10 +881,13 @@ static int fsl_asrc_close(struct inode *inode, struct file *file)
kfree(m2m->dma_block[OUT].dma_vaddr);
fsl_asrc_release_pair(pair);
- }
+ } else
+ spin_unlock_irqrestore(&m2m->lock, lock_flags);
+ spin_lock_irqsave(&asrc_priv->lock, lock_flags);
kfree(m2m);
kfree(pair);
+ spin_unlock_irqrestore(&asrc_priv->lock, lock_flags);
file->private_data = NULL;
out:
@@ -920,22 +929,29 @@ static void fsl_asrc_m2m_suspend(struct fsl_asrc *asrc_priv)
{
struct fsl_asrc_pair *pair;
struct fsl_asrc_m2m *m2m;
+ unsigned long lock_flags;
int i;
for (i = 0; i < ASRC_PAIR_MAX_NUM; i++) {
+ spin_lock_irqsave(&asrc_priv->lock, lock_flags);
pair = asrc_priv->pair[i];
- if (!pair || !pair->private)
+ if (!pair || !pair->private) {
+ spin_unlock_irqrestore(&asrc_priv->lock, lock_flags);
continue;
-
+ }
m2m = pair->private;
if (!completion_done(&m2m->complete[IN])) {
- dmaengine_terminate_all(pair->dma_chan[IN]);
+ if (pair->dma_chan[IN])
+ dmaengine_terminate_all(pair->dma_chan[IN]);
fsl_asrc_input_dma_callback((void *)pair);
}
if (!completion_done(&m2m->complete[OUT])) {
- dmaengine_terminate_all(pair->dma_chan[OUT]);
+ if (pair->dma_chan[OUT])
+ dmaengine_terminate_all(pair->dma_chan[OUT]);
fsl_asrc_output_dma_callback((void *)pair);
}
+
+ spin_unlock_irqrestore(&asrc_priv->lock, lock_flags);
}
}