diff options
author | Xianzhong <b07117@freescale.com> | 2014-03-31 16:20:02 +0800 |
---|---|---|
committer | Jason Liu <r64343@freescale.com> | 2014-06-06 15:14:13 +0800 |
commit | 7f6fafdcf393ec24d30251e44962d9ed62bd6e2f (patch) | |
tree | c57293c9ad2a55fac0f62f39a31523529ce1bb56 /drivers | |
parent | 8743b30d8d93510f233c95b5f3232dc81ab9d82d (diff) |
ENGR00306397 [#1118] use BUG_ON to check if GPU clock is off
Access GPU register will cause system hang(bus lock-up) without log when clock is off,
GPU kernel BUG_ON is added to check if GPU clock is off when read & write GPU registers,
GPU clock issue can be easily identified with the detailed kernel panic log as below:
kernel BUG at drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_os.c:2423!
Unable to handle kernel NULL pointer dereference at virtual address 0000000
...
[<c0050008>] (__bug+0x1c/0x28) from [<c046bb3c>] (gckOS_ReadRegisterEx+0xbc/0xdc)
[<c046bb3c>] (gckOS_ReadRegisterEx+0xbc/0xdc) from [<c047eab4>] (gckHARDWARE_QueryIdle+0x4c/0xbc)
[<c047eab4>] (gckHARDWARE_QueryIdle+0x4c/0xbc) from [<c0475e0c>] (_TryToIdleGPU+0x70/0x12c)
Mutex protection is not necessary for interrupt handling, because GPU clock is only turned off
by interrupt worker thread during clock gating.
Date: Apr 11, 2014
Signed-off-by: Xianzhong <b07117@freescale.com>
Acked-by: Jason Liu
(cherry picked from commit 50c3767eb19bb22f395215755dac220f4bbb2f14)
(cherry picked from commit faf4eb3fd5a66661782f8d0395a27016d7a8fc52)
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_os.c | 37 |
1 files changed, 37 insertions, 0 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 45c42a4908ea..79ca3e3b17ff 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 @@ -211,6 +211,9 @@ struct _gckOS /* workqueue for os timer. */ struct workqueue_struct * workqueue; + + int gpu_clk_on[3]; + struct mutex gpu_clk_mutex; }; typedef struct _gcsSIGNAL * gcsSIGNAL_PTR; @@ -1111,6 +1114,8 @@ gckOS_Construct( gcmkONERROR(gcvSTATUS_OUT_OF_MEMORY); } + mutex_init(&os->gpu_clk_mutex); + /* Return pointer to the gckOS object. */ *Os = os; @@ -2425,7 +2430,17 @@ gckOS_ReadRegisterEx( gcmkVERIFY_ARGUMENT(Address < Os->device->requestedRegisterMemSizes[Core]); gcmkVERIFY_ARGUMENT(Data != gcvNULL); + if(Address != 0x10) mutex_lock(&Os->gpu_clk_mutex); + BUG_ON(!Os->gpu_clk_on[Core]); + + if(Address) + { + gctUINT32 AQHiClockControl = readl((gctUINT8 *)Os->device->registerBases[Core]); + BUG_ON((AQHiClockControl & 0x3) == 0x3); + } + *Data = readl((gctUINT8 *)Os->device->registerBases[Core] + Address); + if(Address != 0x10) mutex_unlock(&Os->gpu_clk_mutex); /* Success. */ gcmkFOOTER_ARG("*Data=0x%08x", *Data); @@ -2475,7 +2490,17 @@ gckOS_WriteRegisterEx( gcmkVERIFY_ARGUMENT(Address < Os->device->requestedRegisterMemSizes[Core]); + mutex_lock(&Os->gpu_clk_mutex); + BUG_ON(!Os->gpu_clk_on[Core]); + + if(Address) + { + gctUINT32 AQHiClockControl = readl((gctUINT8 *)Os->device->registerBases[Core]); + BUG_ON((AQHiClockControl & 0x3) == 0x3); + } + writel(Data, (gctUINT8 *)Os->device->registerBases[Core] + Address); + mutex_unlock(&Os->gpu_clk_mutex); /* Success. */ gcmkFOOTER_NO(); @@ -7020,6 +7045,7 @@ gckOS_SetGPUPower( #if LINUX_VERSION_CODE < KERNEL_VERSION(3,5,0) if (Clock == gcvTRUE) { if (oldClockState == gcvFALSE) { + mutex_lock(&Os->gpu_clk_mutex); switch (Core) { case gcvCORE_MAJOR: clk_enable(clk_3dcore); @@ -7037,9 +7063,12 @@ gckOS_SetGPUPower( default: break; } + Os->gpu_clk_on[Core] = 1; + mutex_unlock(&Os->gpu_clk_mutex); } } else { if (oldClockState == gcvTRUE) { + mutex_lock(&Os->gpu_clk_mutex); switch (Core) { case gcvCORE_MAJOR: if (cpu_is_mx6q()) @@ -7057,11 +7086,14 @@ gckOS_SetGPUPower( default: break; } + Os->gpu_clk_on[Core] = 0; + mutex_unlock(&Os->gpu_clk_mutex); } } #else if (Clock == gcvTRUE) { if (oldClockState == gcvFALSE) { + mutex_lock(&Os->gpu_clk_mutex); switch (Core) { case gcvCORE_MAJOR: clk_prepare(clk_3dcore); @@ -7086,9 +7118,12 @@ gckOS_SetGPUPower( default: break; } + Os->gpu_clk_on[Core] = 1; + mutex_unlock(&Os->gpu_clk_mutex); } } else { if (oldClockState == gcvTRUE) { + mutex_lock(&Os->gpu_clk_mutex); switch (Core) { case gcvCORE_MAJOR: clk_disable(clk_3dshader); @@ -7113,6 +7148,8 @@ gckOS_SetGPUPower( default: break; } + Os->gpu_clk_on[Core] = 0; + mutex_unlock(&Os->gpu_clk_mutex); } } #endif |