]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
ENGR00295201 ipuv3: vdic: kernel dump when run deinterlace stress test
authorSandor Yu <R01008@freescale.com>
Wed, 15 Jan 2014 08:50:04 +0000 (16:50 +0800)
committerLothar Waßmann <LW@KARO-electronics.de>
Wed, 20 Aug 2014 08:06:55 +0000 (10:06 +0200)
Kernel will dump when run deinterlace stress test.
It is caused by vditmpbuf being reallocated by another thread
when one thread accesses it.
Issue is fixed by putting these code in mutex.

Kernel dump log:
[Playing  ][Vol=01][00:00:10/00:00:30][fps:32]Unable to handle kernel
paging request at virtual address 607d6085
pgd = 80004000
[607d6085] *pgd=00000000
Internal error: Oops: 5 [#1] SMP ARM
Modules linked in:
CPU: 0 PID: 50 Comm: ipu2_task Not tainted 3.10.17-02308-g3700819 #28
task: ac1dc700 ti: ac1ba000 task.ti: ac1ba000
PC is at __kmalloc+0x40/0x114
LR is at __kmalloc+0x14/0x114
pc : [<800bbd40>]    lr : [<800bbd14>]    psr: 200f0013
sp : ac1bbbc8  ip : 008cc000  fp : 00001e40
r10: ac772e00  r9 : 0057b255  r8 : 000000d0
r7 : 00000790  r6 : ac773800  r5 : 607d6085  r4 : ac001b00
r3 : 00000000  r2 : 814f92a0  r1 : 000000d0  r0 : 000398c9
Flags: nzCv  IRQs on  FIQs on  Mode SVC_32  ISA ARM  Segment kernel
Control: 10c53c7d  Table: 3c4c004a  DAC: 00000015
Process ipu2_task (pid: 50, stack limit = 0xac1ba238)
Stack: (0xac1bbbc8 to 0xac1bc000)

Signed-off-by: Sandor Yu <R01008@freescale.com>
drivers/mxc/ipu3/ipu_device.c

index 8f6b957de3b0bd41f7f7ef25553a606ff55e3a04..f1f6ad16ff201fde12938f9f34e471d527b2e156 100644 (file)
@@ -286,6 +286,7 @@ struct ipu_task_entry {
        u8      task_in_list;
        u8      split_done;
        struct mutex split_lock;
+       struct mutex vdic_lock;
        wait_queue_head_t split_waitq;
 
        struct list_head node;
@@ -1697,10 +1698,12 @@ static int queue_split_task(struct ipu_task_entry *t,
        int i, j;
        struct ipu_task_entry *tsk = NULL;
        struct mutex *lock = &t->split_lock;
+       struct mutex *vdic_lock = &t->vdic_lock;
 
        dev_dbg(t->dev, "Split task 0x%p, no-0x%x, size:%d\n",
                         t, t->task_no, size);
        mutex_init(lock);
+       mutex_init(vdic_lock);
        init_waitqueue_head(&t->split_waitq);
        INIT_LIST_HEAD(&t->split_list);
        for (j = 0; j < size; j++) {
@@ -2389,11 +2392,13 @@ static void vdi_split_process(struct ipu_soc *ipu, struct ipu_task_entry *t)
        u32 line_size;
        unsigned char  *base_off;
        struct ipu_task_entry *parent = t->parent;
+       struct mutex *lock = &parent->vdic_lock;
 
        if (!parent) {
                dev_err(t->dev, "ERR[0x%x]invalid parent\n", t->task_no);
                return;
        }
+       mutex_lock(lock);
        stripe_mode = t->task_no & 0xf;
        task_no = t->task_no >> 4;
 
@@ -2410,6 +2415,7 @@ static void vdi_split_process(struct ipu_soc *ipu, struct ipu_task_entry *t)
        vdi_size = vdi_save_lines * line_size;
        if (vdi_save_lines <= 0) {
                dev_err(t->dev, "[0x%p] vdi_save_line error\n", (void *)t);
+               mutex_unlock(lock);
                return;
        }
 
@@ -2425,6 +2431,7 @@ static void vdi_split_process(struct ipu_soc *ipu, struct ipu_task_entry *t)
                if (parent->vditmpbuf[0] == NULL) {
                        dev_err(t->dev,
                                "[0x%p]Falied Alloc vditmpbuf[0]\n", (void *)t);
+                       mutex_unlock(lock);
                        return;
                }
                memset(parent->vditmpbuf[0], 0, vdi_size);
@@ -2433,6 +2440,7 @@ static void vdi_split_process(struct ipu_soc *ipu, struct ipu_task_entry *t)
                if (parent->vditmpbuf[1] == NULL) {
                        dev_err(t->dev,
                                "[0x%p]Falied Alloc vditmpbuf[1]\n", (void *)t);
+                       mutex_unlock(lock);
                        return;
                }
                memset(parent->vditmpbuf[1], 0, vdi_size);
@@ -2451,6 +2459,7 @@ static void vdi_split_process(struct ipu_soc *ipu, struct ipu_task_entry *t)
        }
        if (base_off == NULL) {
                dev_err(t->dev, "ERR[0x%p]Failed get virtual address\n", t);
+               mutex_unlock(lock);
                return;
        }
 
@@ -2573,6 +2582,7 @@ static void vdi_split_process(struct ipu_soc *ipu, struct ipu_task_entry *t)
        }
        if (!pfn_valid(t->output.paddr >> PAGE_SHIFT))
                iounmap(base_off);
+       mutex_unlock(lock);
 }
 
 static void do_task_release(struct ipu_task_entry *t, int fail)