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 int 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	return 0;
 27}
 28
 29static int me_print(struct msm_gpu *gpu, struct drm_printer *p)
 30{
 31	int i;
 32
 33	drm_printf(p, "ME state:\n");
 34
 35	for (i = 0; i < 29; i++) {
 36		gpu_write(gpu, REG_A5XX_CP_ME_STAT_ADDR, i);
 37		drm_printf(p, "  %02x: %08x\n", i,
 38			gpu_read(gpu, REG_A5XX_CP_ME_STAT_DATA));
 39	}
 40
 41	return 0;
 42}
 43
 44static int meq_print(struct msm_gpu *gpu, struct drm_printer *p)
 45{
 46	int i;
 47
 48	drm_printf(p, "MEQ state:\n");
 49	gpu_write(gpu, REG_A5XX_CP_MEQ_DBG_ADDR, 0);
 50
 51	for (i = 0; i < 64; i++) {
 52		drm_printf(p, "  %02x: %08x\n", i,
 53			gpu_read(gpu, REG_A5XX_CP_MEQ_DBG_DATA));
 54	}
 55
 56	return 0;
 57}
 58
 59static int roq_print(struct msm_gpu *gpu, struct drm_printer *p)
 60{
 61	int i;
 62
 63	drm_printf(p, "ROQ state:\n");
 64	gpu_write(gpu, REG_A5XX_CP_ROQ_DBG_ADDR, 0);
 65
 66	for (i = 0; i < 512 / 4; i++) {
 67		uint32_t val[4];
 68		int j;
 69		for (j = 0; j < 4; j++)
 70			val[j] = gpu_read(gpu, REG_A5XX_CP_ROQ_DBG_DATA);
 71		drm_printf(p, "  %02x: %08x %08x %08x %08x\n", i,
 72			val[0], val[1], val[2], val[3]);
 73	}
 74
 75	return 0;
 76}
 77
 78static int show(struct seq_file *m, void *arg)
 79{
 80	struct drm_info_node *node = (struct drm_info_node *) m->private;
 81	struct drm_device *dev = node->minor->dev;
 82	struct msm_drm_private *priv = dev->dev_private;
 83	struct drm_printer p = drm_seq_file_printer(m);
 84	int (*show)(struct msm_gpu *gpu, struct drm_printer *p) =
 85		node->info_ent->data;
 86
 87	return show(priv->gpu, &p);
 88}
 89
 90#define ENT(n) { .name = #n, .show = show, .data = n ##_print }
 91static struct drm_info_list a5xx_debugfs_list[] = {
 92	ENT(pfp),
 93	ENT(me),
 94	ENT(meq),
 95	ENT(roq),
 96};
 97
 98/* for debugfs files that can be written to, we can't use drm helper: */
 99static int
100reset_set(void *data, u64 val)
101{
102	struct drm_device *dev = data;
103	struct msm_drm_private *priv = dev->dev_private;
104	struct msm_gpu *gpu = priv->gpu;
105	struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
106	struct a5xx_gpu *a5xx_gpu = to_a5xx_gpu(adreno_gpu);
107
108	if (!capable(CAP_SYS_ADMIN))
109		return -EINVAL;
110
111	/* TODO do we care about trying to make sure the GPU is idle?
112	 * Since this is just a debug feature limited to CAP_SYS_ADMIN,
113	 * maybe it is fine to let the user keep both pieces if they
114	 * try to reset an active GPU.
115	 */
116
117	mutex_lock(&dev->struct_mutex);
118
119	release_firmware(adreno_gpu->fw[ADRENO_FW_PM4]);
120	adreno_gpu->fw[ADRENO_FW_PM4] = NULL;
121
122	release_firmware(adreno_gpu->fw[ADRENO_FW_PFP]);
123	adreno_gpu->fw[ADRENO_FW_PFP] = NULL;
124
125	if (a5xx_gpu->pm4_bo) {
126		msm_gem_unpin_iova(a5xx_gpu->pm4_bo, gpu->aspace);
127		drm_gem_object_put(a5xx_gpu->pm4_bo);
128		a5xx_gpu->pm4_bo = NULL;
129	}
130
131	if (a5xx_gpu->pfp_bo) {
132		msm_gem_unpin_iova(a5xx_gpu->pfp_bo, gpu->aspace);
133		drm_gem_object_put(a5xx_gpu->pfp_bo);
134		a5xx_gpu->pfp_bo = NULL;
135	}
136
137	gpu->needs_hw_init = true;
138
139	pm_runtime_get_sync(&gpu->pdev->dev);
140	gpu->funcs->recover(gpu);
141
142	pm_runtime_put_sync(&gpu->pdev->dev);
143	mutex_unlock(&dev->struct_mutex);
144
145	return 0;
146}
147
148DEFINE_SIMPLE_ATTRIBUTE(reset_fops, NULL, reset_set, "%llx\n");
149
150
151int a5xx_debugfs_init(struct msm_gpu *gpu, struct drm_minor *minor)
152{
153	struct drm_device *dev;
154	int ret;
155
156	if (!minor)
157		return 0;
158
159	dev = minor->dev;
160
161	ret = drm_debugfs_create_files(a5xx_debugfs_list,
162			ARRAY_SIZE(a5xx_debugfs_list),
163			minor->debugfs_root, minor);
164
165	if (ret) {
166		DRM_DEV_ERROR(dev->dev, "could not install a5xx_debugfs_list\n");
167		return ret;
168	}
169
170	debugfs_create_file("reset", S_IWUGO, minor->debugfs_root, dev,
171			    &reset_fops);
172
173	return 0;
174}