Linux Audio

Check our new training course

Loading...
Note: File does not exist in v4.6.
  1// SPDX-License-Identifier: GPL-2.0-only
  2/* Copyright (c) 2016-2017 The Linux Foundation. All rights reserved.
  3 */
  4
  5#include <linux/types.h>
  6#include <linux/debugfs.h>
  7
  8#include <drm/drm_debugfs.h>
  9#include <drm/drm_file.h>
 10#include <drm/drm_print.h>
 11
 12#include "a5xx_gpu.h"
 13
 14static void pfp_print(struct msm_gpu *gpu, struct drm_printer *p)
 15{
 16	int i;
 17
 18	drm_printf(p, "PFP state:\n");
 19
 20	for (i = 0; i < 36; i++) {
 21		gpu_write(gpu, REG_A5XX_CP_PFP_STAT_ADDR, i);
 22		drm_printf(p, "  %02x: %08x\n", i,
 23			gpu_read(gpu, REG_A5XX_CP_PFP_STAT_DATA));
 24	}
 25}
 26
 27static void me_print(struct msm_gpu *gpu, struct drm_printer *p)
 28{
 29	int i;
 30
 31	drm_printf(p, "ME state:\n");
 32
 33	for (i = 0; i < 29; i++) {
 34		gpu_write(gpu, REG_A5XX_CP_ME_STAT_ADDR, i);
 35		drm_printf(p, "  %02x: %08x\n", i,
 36			gpu_read(gpu, REG_A5XX_CP_ME_STAT_DATA));
 37	}
 38}
 39
 40static void meq_print(struct msm_gpu *gpu, struct drm_printer *p)
 41{
 42	int i;
 43
 44	drm_printf(p, "MEQ state:\n");
 45	gpu_write(gpu, REG_A5XX_CP_MEQ_DBG_ADDR, 0);
 46
 47	for (i = 0; i < 64; i++) {
 48		drm_printf(p, "  %02x: %08x\n", i,
 49			gpu_read(gpu, REG_A5XX_CP_MEQ_DBG_DATA));
 50	}
 51}
 52
 53static void roq_print(struct msm_gpu *gpu, struct drm_printer *p)
 54{
 55	int i;
 56
 57	drm_printf(p, "ROQ state:\n");
 58	gpu_write(gpu, REG_A5XX_CP_ROQ_DBG_ADDR, 0);
 59
 60	for (i = 0; i < 512 / 4; i++) {
 61		uint32_t val[4];
 62		int j;
 63		for (j = 0; j < 4; j++)
 64			val[j] = gpu_read(gpu, REG_A5XX_CP_ROQ_DBG_DATA);
 65		drm_printf(p, "  %02x: %08x %08x %08x %08x\n", i,
 66			val[0], val[1], val[2], val[3]);
 67	}
 68}
 69
 70static int show(struct seq_file *m, void *arg)
 71{
 72	struct drm_info_node *node = (struct drm_info_node *) m->private;
 73	struct drm_device *dev = node->minor->dev;
 74	struct msm_drm_private *priv = dev->dev_private;
 75	struct drm_printer p = drm_seq_file_printer(m);
 76	void (*show)(struct msm_gpu *gpu, struct drm_printer *p) =
 77		node->info_ent->data;
 78
 79	show(priv->gpu, &p);
 80	return 0;
 81}
 82
 83#define ENT(n) { .name = #n, .show = show, .data = n ##_print }
 84static struct drm_info_list a5xx_debugfs_list[] = {
 85	ENT(pfp),
 86	ENT(me),
 87	ENT(meq),
 88	ENT(roq),
 89};
 90
 91/* for debugfs files that can be written to, we can't use drm helper: */
 92static int
 93reset_set(void *data, u64 val)
 94{
 95	struct drm_device *dev = data;
 96	struct msm_drm_private *priv = dev->dev_private;
 97	struct msm_gpu *gpu = priv->gpu;
 98	struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
 99	struct a5xx_gpu *a5xx_gpu = to_a5xx_gpu(adreno_gpu);
100
101	if (!capable(CAP_SYS_ADMIN))
102		return -EINVAL;
103
104	/* TODO do we care about trying to make sure the GPU is idle?
105	 * Since this is just a debug feature limited to CAP_SYS_ADMIN,
106	 * maybe it is fine to let the user keep both pieces if they
107	 * try to reset an active GPU.
108	 */
109
110	mutex_lock(&gpu->lock);
111
112	release_firmware(adreno_gpu->fw[ADRENO_FW_PM4]);
113	adreno_gpu->fw[ADRENO_FW_PM4] = NULL;
114
115	release_firmware(adreno_gpu->fw[ADRENO_FW_PFP]);
116	adreno_gpu->fw[ADRENO_FW_PFP] = NULL;
117
118	if (a5xx_gpu->pm4_bo) {
119		msm_gem_unpin_iova(a5xx_gpu->pm4_bo, gpu->aspace);
120		drm_gem_object_put(a5xx_gpu->pm4_bo);
121		a5xx_gpu->pm4_bo = NULL;
122	}
123
124	if (a5xx_gpu->pfp_bo) {
125		msm_gem_unpin_iova(a5xx_gpu->pfp_bo, gpu->aspace);
126		drm_gem_object_put(a5xx_gpu->pfp_bo);
127		a5xx_gpu->pfp_bo = NULL;
128	}
129
130	gpu->needs_hw_init = true;
131
132	pm_runtime_get_sync(&gpu->pdev->dev);
133	gpu->funcs->recover(gpu);
134
135	pm_runtime_put_sync(&gpu->pdev->dev);
136	mutex_unlock(&gpu->lock);
137
138	return 0;
139}
140
141DEFINE_DEBUGFS_ATTRIBUTE(reset_fops, NULL, reset_set, "%llx\n");
142
143
144void a5xx_debugfs_init(struct msm_gpu *gpu, struct drm_minor *minor)
145{
146	struct drm_device *dev;
147
148	if (!minor)
149		return;
150
151	dev = minor->dev;
152
153	drm_debugfs_create_files(a5xx_debugfs_list,
154				 ARRAY_SIZE(a5xx_debugfs_list),
155				 minor->debugfs_root, minor);
156
157	debugfs_create_file_unsafe("reset", S_IWUGO, minor->debugfs_root, dev,
158				&reset_fops);
159}