]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
ENGR00233577 ASRC: add spinlock to protect ASRC pair resource
authorChen Liangjun <b36089@freescale.com>
Mon, 12 Nov 2012 13:29:32 +0000 (21:29 +0800)
committerLothar Waßmann <LW@KARO-electronics.de>
Fri, 24 May 2013 06:35:42 +0000 (08:35 +0200)
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 <b36089@freescale.com>
drivers/mxc/asrc/mxc_asrc.c

index 228f733b43fb6f6ca386a402298149081b81a729..d7edf78cc87d9fb2d789c3f4233e6ee936bfe067 100644 (file)
@@ -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);