From 1017f8e6af897685a4f00ee45653de132620ac11 Mon Sep 17 00:00:00 2001 From: Sandor Yu Date: Wed, 15 Jan 2014 16:50:04 +0800 Subject: [PATCH] ENGR00295201 ipuv3: vdic: kernel dump when run deinterlace stress test 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 --- drivers/mxc/ipu3/ipu_device.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/mxc/ipu3/ipu_device.c b/drivers/mxc/ipu3/ipu_device.c index 8f6b957de3b0..f1f6ad16ff20 100644 --- a/drivers/mxc/ipu3/ipu_device.c +++ b/drivers/mxc/ipu3/ipu_device.c @@ -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) -- 2.39.2