From b063e095e46db242817d39a3814a0e90ae5b3a1b Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Mon, 8 Dec 2014 15:08:27 +0800 Subject: 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 (cherry picked from commit e90c73f8170bc929cff54b0478da0573e4e26c23) --- sound/soc/fsl/fsl_asrc_m2m.c | 36 ++++++++++++++++++++++++++---------- 1 file changed, 26 insertions(+), 10 deletions(-) (limited to 'sound/soc/fsl/fsl_asrc_m2m.c') 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); } } -- cgit v1.2.3