summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorXianzhong <b07117@freescale.com>2014-03-31 16:20:02 +0800
committerLoren Huang <b02279@freescale.com>2014-08-15 11:24:55 +0800
commitf9d8d4a83eb0f44a3783d1c89c7cf0b4c07822ba (patch)
tree377fe93b078f039abca1d2b11aeb5495dc8aceed
parent0513e2bf200f3bf7aa8217d8b44e7edb53114b94 (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) (cherry picked from commit f8a666c09cd714a609812552b73603d23879b10f)
-rw-r--r--drivers/mxc/gpu-viv/hal/os/linux/kernel/gc_hal_kernel_os.c37
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