1
0
Fork 0

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>
(cherry picked from commit b6106c5de2529b01ce5bb3380fd93328b55d5528)
5.4-rM2-2.2.x-imx-squashed
Richard Liu 2020-09-01 10:14:57 +00:00 committed by Xianzhong
parent 8c5e7b55ac
commit add79449db
1 changed files with 44 additions and 8 deletions

View File

@ -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;
}