summaryrefslogtreecommitdiff
path: root/drivers/mxc
diff options
context:
space:
mode:
authorRichard Liu <xuegang.liu@nxp.com>2020-09-01 10:14:57 +0000
committerXianzhong <xianzhong.li@nxp.com>2020-09-04 10:15:05 +0800
commitb6106c5de2529b01ce5bb3380fd93328b55d5528 (patch)
tree3754feb771ef0c8fd6188fc9cd5e470e36201fd2 /drivers/mxc
parent9ef46bda523088bfba51b7432acd2c1e21e547d5 (diff)
MA-17683 [#imx-2302] Fix video playback "rcu stall" issue on 8mq
Loop play a video AVC_1080p_24fps_90Mbps_bird90.m2ts met UI freeze and "rcu stall". Enable CONFIG_DEBUG_SPINLOCK kernel debug get below call stack, the reason is due to spin_lock be used in IRQ interrupt and caused deadlock. 8mq board enabled Video overlay feature, there are two fences enabled: out fence (represent frame on screen) and android out fence (new added, represent frame off screen). When there are two fences sync_file_set_fence() will call dma_fence_array_create() to register irq_dma_fence_array_work(), then gckOS_DestroySignal() will be called in IRQ which use spin_lock cause deadlock. Fix solution is use spin_lock_irqsave() instead of spin_lock() for Database->lock if it is not called in IRQ interrupt. Call stack: [ 608.902810] dump_backtrace.cfi_jt+0x0/0x4 [ 608.906914] show_stack+0x18/0x24 [ 608.910237] dump_stack+0xb8/0x114 [ 608.913644] spin_bug+0xb0/0xb4 [ 608.916788] do_raw_spin_lock+0xac/0x124 [ 608.920714] _raw_spin_lock+0x20/0x2c [ 608.924384] gckOS_DestroySignal+0x6c/0x170 [ 608.928572] viv_fence_release+0x28/0x40 [ 608.932502] dma_fence_release+0x13c/0x280 [ 608.936603] dma_fence_array_release+0x74/0x98 [ 608.941049] dma_fence_release+0x13c/0x280 [ 608.945150] irq_dma_fence_array_work+0x6c/0x9c [ 608.949690] irq_work_run_list+0xb4/0x148 [ 608.953702] irq_work_run+0x20/0x40 [ 608.957193] handle_IPI+0x10c/0x180 [ 608.960686] efi_header_end+0x13c/0x15c [ 608.964526] el1_irq+0x104/0x200 [ 608.967761] radix_tree_lookup+0x38/0x84 [ 608.971686] gckOS_WaitSignal+0x54/0x258 [ 608.975615] gckKERNEL_Dispatch+0x1460/0x1754 [ 608.979977] gckDEVICE_Dispatch+0x1a0/0x1a4 [ 608.984165] drv_ioctl+0xb8/0x184 [ 608.987487] do_vfs_ioctl+0x3a0/0x6f0 [ 608.991154] __arm64_sys_ioctl+0x78/0xa4 [ 608.995082] el0_svc_common+0xb4/0x18c [ 608.998834] el0_svc_handler+0x74/0x98 [ 609.002589] el0_svc+0x8/0xc Change-Id: Idf16a5707add70246c74d2f1446f7dbb7037f5f0 Signed-off-by: Haoran.Wang <elven.wang@nxp.com> Signed-off-by: Richard Liu <xuegang.liu@nxp.com>
Diffstat (limited to 'drivers/mxc')
-rw-r--r--drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_os.c52
1 files changed, 44 insertions, 8 deletions
diff --git a/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_os.c b/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_os.c
index c441cf714de0..1e24c229f3cd 100644
--- a/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_os.c
+++ b/drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_os.c
@@ -271,11 +271,16 @@ _AllocateIntegerId(
{
int result;
gctINT next;
+ unsigned long flags = 0;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0)
idr_preload(GFP_KERNEL | gcdNOWARN);
- spin_lock(&Database->lock);
+ if(in_irq()){
+ spin_lock(&Database->lock);
+ }else{
+ spin_lock_irqsave(&Database->lock, flags);
+ }
next = (Database->curr + 1 <= 0) ? 1 : Database->curr + 1;
@@ -289,7 +294,11 @@ _AllocateIntegerId(
Database->curr = *Id = result;
}
- spin_unlock(&Database->lock);
+ if(in_irq()){
+ spin_unlock(&Database->lock);
+ }else{
+ spin_unlock_irqrestore(&Database->lock, flags);
+ }
idr_preload_end();
@@ -304,7 +313,11 @@ again:
return gcvSTATUS_OUT_OF_MEMORY;
}
- spin_lock(&Database->lock);
+ if(in_irq()){
+ spin_lock(&Database->lock);
+ }else{
+ spin_lock_irqsave(&Database->lock, flags);
+ }
next = (Database->curr + 1 <= 0) ? 1 : Database->curr + 1;
@@ -316,7 +329,11 @@ again:
Database->curr = *Id;
}
- spin_unlock(&Database->lock);
+ if(in_irq()){
+ spin_unlock(&Database->lock);
+ }else{
+ spin_unlock_irqrestore(&Database->lock, flags);
+ }
if (result == -EAGAIN)
{
@@ -340,12 +357,21 @@ _QueryIntegerId(
)
{
gctPOINTER pointer;
+ unsigned long flags = 0;
- spin_lock(&Database->lock);
+ if(in_irq()){
+ spin_lock(&Database->lock);
+ }else{
+ spin_lock_irqsave(&Database->lock, flags);
+ }
pointer = idr_find(&Database->idr, Id);
- spin_unlock(&Database->lock);
+ if(in_irq()){
+ spin_unlock(&Database->lock);
+ }else{
+ spin_unlock_irqrestore(&Database->lock, flags);
+ }
if (pointer)
{
@@ -369,11 +395,21 @@ _DestroyIntegerId(
IN gctUINT32 Id
)
{
- spin_lock(&Database->lock);
+ unsigned long flags = 0;
+
+ if(in_irq()){
+ spin_lock(&Database->lock);
+ }else{
+ spin_lock_irqsave(&Database->lock, flags);
+ }
idr_remove(&Database->idr, Id);
- spin_unlock(&Database->lock);
+ if(in_irq()){
+ spin_unlock(&Database->lock);
+ }else{
+ spin_unlock_irqrestore(&Database->lock, flags);
+ }
return gcvSTATUS_OK;
}