From 7145c98873e6b1eee7d21916a6da4cdb8c79c67e Mon Sep 17 00:00:00 2001 From: Chen Liangjun Date: Mon, 12 Nov 2012 21:29:32 +0800 Subject: [PATCH] ENGR00233577 ASRC: add spinlock to protect ASRC pair resource when quit from ASRC driver with CTRL + C, driver close() would free output buffer and close clock. However, it is possible that the buffer is accessed by work task(work task is trigger by interrupt and it would not be stopped by CTRL + C). So ASRC driver should promise that its pair resource(buffer, SDMA channel, and clock) would not be accessed after it is released. In this patch, add protect for pair resource. Signed-off-by: Chen Liangjun --- drivers/mxc/asrc/mxc_asrc.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/drivers/mxc/asrc/mxc_asrc.c b/drivers/mxc/asrc/mxc_asrc.c index 228f733b43fb..d7edf78cc87d 100644 --- a/drivers/mxc/asrc/mxc_asrc.c +++ b/drivers/mxc/asrc/mxc_asrc.c @@ -49,6 +49,7 @@ #define ASRC_RATIO_DECIMAL_DEPTH 26 DEFINE_SPINLOCK(data_lock); +DEFINE_SPINLOCK(pair_lock); DEFINE_SPINLOCK(input_int_lock); DEFINE_SPINLOCK(output_int_lock); @@ -992,6 +993,11 @@ static void asrc_output_task_worker(struct work_struct *w) unsigned long lock_flags; /* asrc output work struct */ + spin_lock_irqsave(&pair_lock, lock_flags); + if (!params->pair_hold) { + spin_unlock_irqrestore(&pair_lock, lock_flags); + return; + } switch (params->output_word_width) { case ASRC_WIDTH_24_BIT: asrc_read_output_FIFO_S24(params); @@ -1003,6 +1009,7 @@ static void asrc_output_task_worker(struct work_struct *w) default: pr_err("%s: error word width\n", __func__); } + spin_unlock_irqrestore(&pair_lock, lock_flags); /* finish receiving all output data */ spin_lock_irqsave(&output_int_lock, lock_flags); @@ -1542,13 +1549,18 @@ static long asrc_ioctl(struct file *file, case ASRC_RELEASE_PAIR: { enum asrc_pair_index index; + unsigned long lock_flags; if (copy_from_user (&index, (void __user *)arg, sizeof(enum asrc_pair_index))) { err = -EFAULT; break; } + params->asrc_active = 0; + spin_lock_irqsave(&pair_lock, lock_flags); + params->pair_hold = 0; + spin_unlock_irqrestore(&pair_lock, lock_flags); if (params->input_dma_channel) dma_release_channel(params->input_dma_channel); if (params->output_dma_channel) @@ -1557,8 +1569,6 @@ static long asrc_ioctl(struct file *file, mxc_free_dma_buf(params); asrc_release_pair(index); asrc_finish_conv(index); - params->asrc_active = 0; - params->pair_hold = 0; break; } case ASRC_CONVERT: @@ -1733,9 +1743,11 @@ static int mxc_asrc_open(struct inode *inode, struct file *file) static int mxc_asrc_close(struct inode *inode, struct file *file) { struct asrc_pair_params *pair_params; + unsigned long lock_flags; pair_params = file->private_data; if (pair_params) { if (pair_params->asrc_active) { + pair_params->asrc_active = 0; dmaengine_terminate_all( pair_params->input_dma_channel); dmaengine_terminate_all( @@ -1745,6 +1757,9 @@ static int mxc_asrc_close(struct inode *inode, struct file *file) wake_up_interruptible(&pair_params->output_wait_queue); } if (pair_params->pair_hold) { + spin_lock_irqsave(&pair_lock, lock_flags); + pair_params->pair_hold = 0; + spin_unlock_irqrestore(&pair_lock, lock_flags); if (pair_params->input_dma_channel) dma_release_channel( pair_params->input_dma_channel); -- 2.39.5