drm/msm/gpu: Capture the state of the GPU
authorJordan Crouse <jcrouse@codeaurora.org>
Tue, 24 Jul 2018 16:33:24 +0000 (10:33 -0600)
committerRob Clark <robdclark@gmail.com>
Mon, 30 Jul 2018 12:49:45 +0000 (08:49 -0400)
Add the infrastructure to capture the current state of the GPU and
store it in memory so that it can be dumped later.

For now grab the same basic ringbuffer information and registers
that are provided by the debugfs 'gpu' node but obviously this should
be extended to capture a much larger set of GPU information.

Signed-off-by: Jordan Crouse <jcrouse@codeaurora.org>
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/a5xx_gpu.c
drivers/gpu/drm/msm/adreno/adreno_gpu.c
drivers/gpu/drm/msm/adreno/adreno_gpu.h
drivers/gpu/drm/msm/msm_gpu.h

index 3ebbeb3a9b68f1080cfec70ad3ef197456871b66..b707b5bca9ab6bbe3e275cabc4db889a5b9c53b9 100644 (file)
@@ -427,6 +427,19 @@ static void a3xx_dump(struct msm_gpu *gpu)
                        gpu_read(gpu, REG_A3XX_RBBM_STATUS));
        adreno_dump(gpu);
 }
+
+static struct msm_gpu_state *a3xx_gpu_state_get(struct msm_gpu *gpu)
+{
+       struct msm_gpu_state *state = adreno_gpu_state_get(gpu);
+
+       if (IS_ERR(state))
+               return state;
+
+       state->rbbm_status = gpu_read(gpu, REG_A3XX_RBBM_STATUS);
+
+       return state;
+}
+
 /* Register offset defines for A3XX */
 static const unsigned int a3xx_register_offsets[REG_ADRENO_REGISTER_MAX] = {
        REG_ADRENO_DEFINE(REG_ADRENO_CP_RB_BASE, REG_AXXX_CP_RB_BASE),
@@ -453,6 +466,8 @@ static const struct adreno_gpu_funcs funcs = {
 #ifdef CONFIG_DEBUG_FS
                .show = a3xx_show,
 #endif
+               .gpu_state_get = a3xx_gpu_state_get,
+               .gpu_state_put = adreno_gpu_state_put,
        },
 };
 
index 16d3d596638e20477112a835a9a545d264623b23..17e97ebc10774ca3d405381b4e99f794a0096f91 100644 (file)
@@ -465,6 +465,18 @@ static void a4xx_show(struct msm_gpu *gpu, struct seq_file *m)
 }
 #endif
 
+static struct msm_gpu_state *a4xx_gpu_state_get(struct msm_gpu *gpu)
+{
+       struct msm_gpu_state *state = adreno_gpu_state_get(gpu);
+
+       if (IS_ERR(state))
+               return state;
+
+       state->rbbm_status = gpu_read(gpu, REG_A4XX_RBBM_STATUS);
+
+       return state;
+}
+
 /* Register offset defines for A4XX, in order of enum adreno_regs */
 static const unsigned int a4xx_register_offsets[REG_ADRENO_REGISTER_MAX] = {
        REG_ADRENO_DEFINE(REG_ADRENO_CP_RB_BASE, REG_A4XX_CP_RB_BASE),
@@ -541,6 +553,8 @@ static const struct adreno_gpu_funcs funcs = {
 #ifdef CONFIG_DEBUG_FS
                .show = a4xx_show,
 #endif
+               .gpu_state_get = a4xx_gpu_state_get,
+               .gpu_state_put = adreno_gpu_state_put,
        },
        .get_timestamp = a4xx_get_timestamp,
 };
index d39400e5bc42907866b4cf7d734ee7f6118c5399..9e85e4f7016d0cc7dee39204ed1be0b34082ec81 100644 (file)
@@ -1195,6 +1195,26 @@ static int a5xx_get_timestamp(struct msm_gpu *gpu, uint64_t *value)
        return 0;
 }
 
+static struct msm_gpu_state *a5xx_gpu_state_get(struct msm_gpu *gpu)
+{
+       struct msm_gpu_state *state;
+
+       /*
+        * Temporarily disable hardware clock gating before going into
+        * adreno_show to avoid issues while reading the registers
+        */
+       a5xx_set_hwcg(gpu, false);
+
+       state = adreno_gpu_state_get(gpu);
+
+       if (!IS_ERR(state))
+               state->rbbm_status = gpu_read(gpu, REG_A5XX_RBBM_STATUS);
+
+       a5xx_set_hwcg(gpu, true);
+
+       return state;
+}
+
 #ifdef CONFIG_DEBUG_FS
 static void a5xx_show(struct msm_gpu *gpu, struct seq_file *m)
 {
@@ -1244,6 +1264,8 @@ static const struct adreno_gpu_funcs funcs = {
                .debugfs_init = a5xx_debugfs_init,
 #endif
                .gpu_busy = a5xx_gpu_busy,
+               .gpu_state_get = a5xx_gpu_state_get,
+               .gpu_state_put = adreno_gpu_state_put,
        },
        .get_timestamp = a5xx_get_timestamp,
 };
index bcbf9f2a29f9c5f86bd960c5f5b1a1cefc6b4971..4286a539f40aaa0af1283214a8078820d5c8bb56 100644 (file)
@@ -368,6 +368,61 @@ bool adreno_idle(struct msm_gpu *gpu, struct msm_ringbuffer *ring)
        return false;
 }
 
+struct msm_gpu_state *adreno_gpu_state_get(struct msm_gpu *gpu)
+{
+       struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
+       struct msm_gpu_state *state;
+       int i, count = 0;
+
+       state = kzalloc(sizeof(*state), GFP_KERNEL);
+       if (!state)
+               return ERR_PTR(-ENOMEM);
+
+       do_gettimeofday(&state->time);
+
+       for (i = 0; i < gpu->nr_rings; i++) {
+               state->ring[i].fence = gpu->rb[i]->memptrs->fence;
+               state->ring[i].iova = gpu->rb[i]->iova;
+               state->ring[i].seqno = gpu->rb[i]->seqno;
+               state->ring[i].rptr = get_rptr(adreno_gpu, gpu->rb[i]);
+               state->ring[i].wptr = get_wptr(gpu->rb[i]);
+       }
+
+       /* Count the number of registers */
+       for (i = 0; adreno_gpu->registers[i] != ~0; i += 2)
+               count += adreno_gpu->registers[i + 1] -
+                       adreno_gpu->registers[i] + 1;
+
+       state->registers = kcalloc(count * 2, sizeof(u32), GFP_KERNEL);
+       if (state->registers) {
+               int pos = 0;
+
+               for (i = 0; adreno_gpu->registers[i] != ~0; i += 2) {
+                       u32 start = adreno_gpu->registers[i];
+                       u32 end   = adreno_gpu->registers[i + 1];
+                       u32 addr;
+
+                       for (addr = start; addr <= end; addr++) {
+                               state->registers[pos++] = addr;
+                               state->registers[pos++] = gpu_read(gpu, addr);
+                       }
+               }
+
+               state->nr_registers = count;
+       }
+
+       return state;
+}
+
+void adreno_gpu_state_put(struct msm_gpu_state *state)
+{
+       if (IS_ERR_OR_NULL(state))
+               return;
+
+       kfree(state->registers);
+       kfree(state);
+}
+
 #ifdef CONFIG_DEBUG_FS
 void adreno_show(struct msm_gpu *gpu, struct seq_file *m)
 {
index bc9ec27e9ed853c51e35c655a7e39bfb26ec2aa4..734e31a9631fc5387e96ce9c9b909d02c529e4d3 100644 (file)
@@ -229,6 +229,9 @@ int adreno_gpu_init(struct drm_device *drm, struct platform_device *pdev,
 void adreno_gpu_cleanup(struct adreno_gpu *gpu);
 
 
+struct msm_gpu_state *adreno_gpu_state_get(struct msm_gpu *gpu);
+void adreno_gpu_state_put(struct msm_gpu_state *state);
+
 /* ringbuffer helpers (the parts that are adreno specific) */
 
 static inline void
index b8241179175a2ca523b259777c481f53a460f2f9..de71cc04ecf3486b88f550e280676ec17709e764 100644 (file)
@@ -27,6 +27,7 @@
 
 struct msm_gem_submit;
 struct msm_gpu_perfcntr;
+struct msm_gpu_state;
 
 struct msm_gpu_config {
        const char *ioname;
@@ -69,6 +70,8 @@ struct msm_gpu_funcs {
        int (*debugfs_init)(struct msm_gpu *gpu, struct drm_minor *minor);
 #endif
        int (*gpu_busy)(struct msm_gpu *gpu, uint64_t *value);
+       struct msm_gpu_state *(*gpu_state_get)(struct msm_gpu *gpu);
+       void (*gpu_state_put)(struct msm_gpu_state *state);
 };
 
 struct msm_gpu {
@@ -175,6 +178,23 @@ struct msm_gpu_submitqueue {
        struct kref ref;
 };
 
+struct msm_gpu_state {
+       struct timeval time;
+
+       struct {
+               u64 iova;
+               u32 fence;
+               u32 seqno;
+               u32 rptr;
+               u32 wptr;
+       } ring[MSM_GPU_MAX_RINGS];
+
+       int nr_registers;
+       u32 *registers;
+
+       u32 rbbm_status;
+};
+
 static inline void gpu_write(struct msm_gpu *gpu, u32 reg, u32 data)
 {
        msm_writel(data, gpu->mmio + (reg << 2));