drm/msm/adreno: dump scratch regs and other info on hang
authorRob Clark <robdclark@gmail.com>
Sun, 19 Apr 2015 14:14:09 +0000 (10:14 -0400)
committerRob Clark <robdclark@gmail.com>
Thu, 11 Jun 2015 17:11:00 +0000 (13:11 -0400)
Dump a bit more info when the GPU hangs, without having hang_debug
enabled (which dumps a *lot* of registers).  Also dump the scratch
registers, as they are useful for determining where in the cmdstream
the GPU hung (and they seem always safe to read when GPU has hung).

Note that the freedreno gallium driver emits increasing counter values
to SCRATCH6 (to identify tile #) and SCRATCH7 (to identify draw #), so
these two in particular can be used to "triangulate" where in the
cmdstream the GPU hung.

Signed-off-by: Rob Clark <robdclark@gmail.com>
drivers/gpu/drm/msm/adreno/a3xx_gpu.c
drivers/gpu/drm/msm/adreno/a4xx_gpu.c
drivers/gpu/drm/msm/adreno/adreno_gpu.c
drivers/gpu/drm/msm/adreno/adreno_gpu.h

index b66c53bdc039cafffd3be36a4fe39ccfb92fb470..0f0c45665dbd11c0be1bd4f80dba54af6523dea6 100644 (file)
@@ -295,9 +295,12 @@ static int a3xx_hw_init(struct msm_gpu *gpu)
 
 static void a3xx_recover(struct msm_gpu *gpu)
 {
+       adreno_dump_info(gpu);
+
        /* dump registers before resetting gpu, if enabled: */
        if (hang_debug)
                a3xx_dump(gpu);
+
        gpu_write(gpu, REG_A3XX_RBBM_SW_RESET_CMD, 1);
        gpu_read(gpu, REG_A3XX_RBBM_SW_RESET_CMD);
        gpu_write(gpu, REG_A3XX_RBBM_SW_RESET_CMD, 0);
index 91221836c5ad0fec1467fb482dbd6e3c79064fd6..a53f1be05f75fbcd9c99e9980f16ef4987595410 100644 (file)
@@ -268,6 +268,8 @@ static int a4xx_hw_init(struct msm_gpu *gpu)
 
 static void a4xx_recover(struct msm_gpu *gpu)
 {
+       adreno_dump_info(gpu);
+
        /* dump registers before resetting gpu, if enabled: */
        if (hang_debug)
                a4xx_dump(gpu);
@@ -505,7 +507,6 @@ static const unsigned int a4xx_register_offsets[REG_ADRENO_REGISTER_MAX] = {
 
 static void a4xx_dump(struct msm_gpu *gpu)
 {
-       adreno_dump(gpu);
        printk("status:   %08x\n",
                        gpu_read(gpu, REG_A4XX_RBBM_STATUS));
        adreno_dump(gpu);
index bbdcab0a56c1734d672457623d0eb071b881ceda..a1e861316590747d07d47b71ea5b7ed065641433 100644 (file)
@@ -249,8 +249,13 @@ void adreno_show(struct msm_gpu *gpu, struct seq_file *m)
 }
 #endif
 
-/* would be nice to not have to duplicate the _show() stuff with printk(): */
-void adreno_dump(struct msm_gpu *gpu)
+/* Dump common gpu status and scratch registers on any hang, to make
+ * the hangcheck logs more useful.  The scratch registers seem always
+ * safe to read when GPU has hung (unlike some other regs, depending
+ * on how the GPU hung), and they are useful to match up to cmdstream
+ * dumps when debugging hangs:
+ */
+void adreno_dump_info(struct msm_gpu *gpu)
 {
        struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
        int i;
@@ -266,6 +271,18 @@ void adreno_dump(struct msm_gpu *gpu)
        printk("wptr:     %d\n", adreno_gpu->memptrs->wptr);
        printk("rb wptr:  %d\n", get_wptr(gpu->rb));
 
+       for (i = 0; i < 8; i++) {
+               printk("CP_SCRATCH_REG%d: %u\n", i,
+                       gpu_read(gpu, REG_AXXX_CP_SCRATCH_REG0 + i));
+       }
+}
+
+/* would be nice to not have to duplicate the _show() stuff with printk(): */
+void adreno_dump(struct msm_gpu *gpu)
+{
+       struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
+       int i;
+
        /* dump these out in a form that can be parsed by demsm: */
        printk("IO:region %s 00000000 00020000\n", gpu->name);
        for (i = 0; adreno_gpu->registers[i] != ~0; i += 2) {
index a0cc30977e671d7286d52bba94cb3d09192c55d6..2b6b57baf6fdca0467fc4539b3883a5e1ee4cd1e 100644 (file)
@@ -233,6 +233,7 @@ void adreno_idle(struct msm_gpu *gpu);
 #ifdef CONFIG_DEBUG_FS
 void adreno_show(struct msm_gpu *gpu, struct seq_file *m);
 #endif
+void adreno_dump_info(struct msm_gpu *gpu);
 void adreno_dump(struct msm_gpu *gpu);
 void adreno_wait_ring(struct msm_gpu *gpu, uint32_t ndwords);