diff options
author | Ivan.liu <xiaowen.liu@nxp.com> | 2018-11-20 13:20:38 +0800 |
---|---|---|
committer | Jason Liu <jason.hui.liu@nxp.com> | 2019-02-12 10:35:24 +0800 |
commit | a3e787a96357e3066a092c6cd3c69a2c63714d68 (patch) | |
tree | 02a278475cf302fa1b89577fbdb96fa414513c41 /drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_os.c | |
parent | 128c71d26255a18e56ac0526cf1fa705f8885fe7 (diff) |
MA-13467 [#imx-1237] Fix kernel panic when running deqp module.
Unable to handle kernel paging request at virtual address 1000100
[<ffff000008274ed8>] prefetch_freepointer.isra.37+0x8/0x14
[<ffff0000087bd3b0>] sync_file_create+0x28/0xc0
[<ffff000008b7c7e4>] gckOS_CreateNativeFence+0x74/0x110
[<ffff000008b89a78>] gckKERNEL_Dispatch+0xa54/0x15b0
[<ffff000008b8a8b8>] gckDEVICE_Dispatch+0x2e4/0x2f8
[<ffff000008b81160>] drv_ioctl+0x110/0x21c
[<ffff0000082b4478>] do_vfs_ioctl+0xb8/0x8b0
[<ffff0000082b4cf4>] SyS_ioctl+0x84/0x98
The reference count should be increased in one spin lock cycle.
Move spin lock out of _QueryIntegerId function.
Move signal reference count to gckOS_CreateNativeFence.
Change-Id: I1bf89b4de6055e5d0009baf7287f600696c4a529
Signed-off-by: Ivan.liu <xiaowen.liu@nxp.com>
Diffstat (limited to 'drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_os.c')
-rw-r--r-- | drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_os.c | 72 |
1 files changed, 53 insertions, 19 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 bfd4f2fd2f82..bd3ea869c0e4 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 @@ -346,14 +346,8 @@ _QueryIntegerId( ) { gctPOINTER pointer; - unsigned long flags; - - spin_lock_irqsave(&Database->lock, flags); pointer = idr_find(&Database->idr, Id); - - spin_unlock_irqrestore(&Database->lock, flags); - if (pointer) { *KernelPointer = pointer; @@ -5587,9 +5581,14 @@ gckOS_DestroySignal( gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); gcmkVERIFY_ARGUMENT(Signal != gcvNULL); - gcmkONERROR(_QueryIntegerId(&Os->signalDB, (gctUINT32)(gctUINTPTR_T)Signal, (gctPOINTER)&signal)); - spin_lock_irqsave(&Os->signalDB.lock, flags); + status = _QueryIntegerId(&Os->signalDB, (gctUINT32)(gctUINTPTR_T)Signal, (gctPOINTER)&signal); + if (gcmIS_ERROR(status)) + { + spin_unlock_irqrestore(&Os->signalDB.lock, flags); + gcmkONERROR(status); + } + gcmkASSERT(signal->id == (gctUINT32)(gctUINTPTR_T)Signal); signal->ref--; @@ -5657,16 +5656,16 @@ gckOS_Signal( gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); gcmkVERIFY_ARGUMENT(Signal != gcvNULL); + spin_lock_irqsave(&Os->signalDB.lock, flags); status = _QueryIntegerId(&Os->signalDB, (gctUINT32)(gctUINTPTR_T)Signal, (gctPOINTER)&signal); - if (gcmIS_ERROR(status)) { + spin_unlock_irqrestore(&Os->signalDB.lock, flags); gcmkONERROR(status); } - spin_lock_irqsave(&Os->signalDB.lock, flags); /* * Signal saved in event is not referenced. Inc reference here to avoid * concurrent issue: signaling the signal while another thread is destroying @@ -5811,6 +5810,7 @@ gckOS_WaitSignal( gceSTATUS status; gcsSIGNAL_PTR signal; int done; + unsigned long flags; gcmkHEADER_ARG("Os=0x%X Signal=0x%X Wait=0x%08X", Os, Signal, Wait); @@ -5818,7 +5818,11 @@ gckOS_WaitSignal( gcmkVERIFY_OBJECT(Os, gcvOBJ_OS); gcmkVERIFY_ARGUMENT(Signal != gcvNULL); - gcmkONERROR(_QueryIntegerId(&Os->signalDB, (gctUINT32)(gctUINTPTR_T)Signal, (gctPOINTER)&signal)); + spin_lock_irqsave(&Os->signalDB.lock, flags); + status = _QueryIntegerId(&Os->signalDB, (gctUINT32)(gctUINTPTR_T)Signal, (gctPOINTER)&signal); + spin_unlock_irqrestore(&Os->signalDB.lock, flags); + + gcmkONERROR(status); gcmkASSERT(signal->id == (gctUINT32)(gctUINTPTR_T)Signal); @@ -5905,10 +5909,13 @@ _QuerySignal( */ gceSTATUS status; gcsSIGNAL_PTR signal = gcvNULL; + unsigned long flags; + spin_lock_irqsave(&Os->signalDB.lock, flags); status = _QueryIntegerId(&Os->signalDB, (gctUINT32)(gctUINTPTR_T)Signal, (gctPOINTER)&signal); + spin_unlock_irqrestore(&Os->signalDB.lock, flags); if (gcmIS_SUCCESS(status)) { @@ -5958,9 +5965,14 @@ gckOS_MapSignal( gcmkVERIFY_ARGUMENT(Signal != gcvNULL); gcmkVERIFY_ARGUMENT(MappedSignal != gcvNULL); - gcmkONERROR(_QueryIntegerId(&Os->signalDB, (gctUINT32)(gctUINTPTR_T)Signal, (gctPOINTER)&signal)); - spin_lock_irqsave(&Os->signalDB.lock, flags); + status = _QueryIntegerId(&Os->signalDB, (gctUINT32)(gctUINTPTR_T)Signal, (gctPOINTER)&signal); + if (gcmIS_ERROR(status)) + { + spin_unlock_irqrestore(&Os->signalDB.lock, flags); + gcmkONERROR(status); + } + signal->ref++; if (signal->ref <= 1) @@ -6671,14 +6683,21 @@ gckOS_CreateNativeFence( char name[32]; gcsSIGNAL_PTR signal; gceSTATUS status; + unsigned long flags; gcmkHEADER_ARG("Os=0x%X Timeline=0x%X Signal=%d", Os, Timeline, (gctUINT)(gctUINTPTR_T)Signal); - gcmkONERROR( - _QueryIntegerId(&Os->signalDB, + spin_lock_irqsave(&Os->signalDB.lock, flags); + status = _QueryIntegerId(&Os->signalDB, (gctUINT32)(gctUINTPTR_T)Signal, - (gctPOINTER)&signal)); + (gctPOINTER)&signal); + if (gcmIS_ERROR(status)) + { + spin_unlock_irqrestore(&Os->signalDB.lock, flags); + gcmkONERROR(status); + } + spin_unlock_irqrestore(&Os->signalDB.lock, flags); /* Cast timeline. */ timeline = (struct viv_sync_timeline *) Timeline; @@ -6943,14 +6962,29 @@ gckOS_CreateNativeFence( struct viv_sync_timeline *timeline; gcsSIGNAL_PTR signal = gcvNULL; gceSTATUS status = gcvSTATUS_OK; + unsigned long flags; /* Create fence. */ timeline = (struct viv_sync_timeline *) Timeline; - gcmkONERROR( - _QueryIntegerId(&Os->signalDB, + spin_lock_irqsave(&Os->signalDB.lock, flags); + status = _QueryIntegerId(&Os->signalDB, (gctUINT32)(gctUINTPTR_T)Signal, - (gctPOINTER)&signal)); + (gctPOINTER)&signal); + if (gcmIS_ERROR(status)) + { + spin_unlock_irqrestore(&Os->signalDB.lock, flags); + gcmkONERROR(status); + } + + signal->ref++; + if (signal->ref <= 1) + { + spin_unlock_irqrestore(&Os->signalDB.lock, flags); + /* The previous value is 0, it has been deleted. */ + gcmkONERROR(gcvSTATUS_INVALID_ARGUMENT); + } + spin_unlock_irqrestore(&Os->signalDB.lock, flags); fence = viv_fence_create(timeline, signal); |