Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  1/* Copyright (c) 2016-2017 The Linux Foundation. All rights reserved.
  2 *
  3 * This program is free software; you can redistribute it and/or modify
  4 * it under the terms of the GNU General Public License version 2 and
  5 * only version 2 as published by the Free Software Foundation.
  6 *
  7 * This program is distributed in the hope that it will be useful,
  8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 10 * GNU General Public License for more details.
 11 *
 12 */
 13
 14
 15#include <linux/types.h>
 16#include <linux/debugfs.h>
 17#include <drm/drm_print.h>
 18
 19#include "a5xx_gpu.h"
 20
 21static int pfp_print(struct msm_gpu *gpu, struct drm_printer *p)
 22{
 23	int i;
 24
 25	drm_printf(p, "PFP state:\n");
 26
 27	for (i = 0; i < 36; i++) {
 28		gpu_write(gpu, REG_A5XX_CP_PFP_STAT_ADDR, i);
 29		drm_printf(p, "  %02x: %08x\n", i,
 30			gpu_read(gpu, REG_A5XX_CP_PFP_STAT_DATA));
 31	}
 32
 33	return 0;
 34}
 35
 36static int me_print(struct msm_gpu *gpu, struct drm_printer *p)
 37{
 38	int i;
 39
 40	drm_printf(p, "ME state:\n");
 41
 42	for (i = 0; i < 29; i++) {
 43		gpu_write(gpu, REG_A5XX_CP_ME_STAT_ADDR, i);
 44		drm_printf(p, "  %02x: %08x\n", i,
 45			gpu_read(gpu, REG_A5XX_CP_ME_STAT_DATA));
 46	}
 47
 48	return 0;
 49}
 50
 51static int meq_print(struct msm_gpu *gpu, struct drm_printer *p)
 52{
 53	int i;
 54
 55	drm_printf(p, "MEQ state:\n");
 56	gpu_write(gpu, REG_A5XX_CP_MEQ_DBG_ADDR, 0);
 57
 58	for (i = 0; i < 64; i++) {
 59		drm_printf(p, "  %02x: %08x\n", i,
 60			gpu_read(gpu, REG_A5XX_CP_MEQ_DBG_DATA));
 61	}
 62
 63	return 0;
 64}
 65
 66static int roq_print(struct msm_gpu *gpu, struct drm_printer *p)
 67{
 68	int i;
 69
 70	drm_printf(p, "ROQ state:\n");
 71	gpu_write(gpu, REG_A5XX_CP_ROQ_DBG_ADDR, 0);
 72
 73	for (i = 0; i < 512 / 4; i++) {
 74		uint32_t val[4];
 75		int j;
 76		for (j = 0; j < 4; j++)
 77			val[j] = gpu_read(gpu, REG_A5XX_CP_ROQ_DBG_DATA);
 78		drm_printf(p, "  %02x: %08x %08x %08x %08x\n", i,
 79			val[0], val[1], val[2], val[3]);
 80	}
 81
 82	return 0;
 83}
 84
 85static int show(struct seq_file *m, void *arg)
 86{
 87	struct drm_info_node *node = (struct drm_info_node *) m->private;
 88	struct drm_device *dev = node->minor->dev;
 89	struct msm_drm_private *priv = dev->dev_private;
 90	struct drm_printer p = drm_seq_file_printer(m);
 91	int (*show)(struct msm_gpu *gpu, struct drm_printer *p) =
 92		node->info_ent->data;
 93
 94	return show(priv->gpu, &p);
 95}
 96
 97#define ENT(n) { .name = #n, .show = show, .data = n ##_print }
 98static struct drm_info_list a5xx_debugfs_list[] = {
 99	ENT(pfp),
100	ENT(me),
101	ENT(meq),
102	ENT(roq),
103};
104
105/* for debugfs files that can be written to, we can't use drm helper: */
106static int
107reset_set(void *data, u64 val)
108{
109	struct drm_device *dev = data;
110	struct msm_drm_private *priv = dev->dev_private;
111	struct msm_gpu *gpu = priv->gpu;
112	struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
113	struct a5xx_gpu *a5xx_gpu = to_a5xx_gpu(adreno_gpu);
114
115	if (!capable(CAP_SYS_ADMIN))
116		return -EINVAL;
117
118	/* TODO do we care about trying to make sure the GPU is idle?
119	 * Since this is just a debug feature limited to CAP_SYS_ADMIN,
120	 * maybe it is fine to let the user keep both pieces if they
121	 * try to reset an active GPU.
122	 */
123
124	mutex_lock(&dev->struct_mutex);
125
126	release_firmware(adreno_gpu->fw[ADRENO_FW_PM4]);
127	adreno_gpu->fw[ADRENO_FW_PM4] = NULL;
128
129	release_firmware(adreno_gpu->fw[ADRENO_FW_PFP]);
130	adreno_gpu->fw[ADRENO_FW_PFP] = NULL;
131
132	if (a5xx_gpu->pm4_bo) {
133		if (a5xx_gpu->pm4_iova)
134			msm_gem_put_iova(a5xx_gpu->pm4_bo, gpu->aspace);
135		drm_gem_object_unreference(a5xx_gpu->pm4_bo);
136		a5xx_gpu->pm4_bo = NULL;
137	}
138
139	if (a5xx_gpu->pfp_bo) {
140		if (a5xx_gpu->pfp_iova)
141			msm_gem_put_iova(a5xx_gpu->pfp_bo, gpu->aspace);
142		drm_gem_object_unreference(a5xx_gpu->pfp_bo);
143		a5xx_gpu->pfp_bo = NULL;
144	}
145
146	gpu->needs_hw_init = true;
147
148	pm_runtime_get_sync(&gpu->pdev->dev);
149	gpu->funcs->recover(gpu);
150
151	pm_runtime_put_sync(&gpu->pdev->dev);
152	mutex_unlock(&dev->struct_mutex);
153
154	return 0;
155}
156
157DEFINE_SIMPLE_ATTRIBUTE(reset_fops, NULL, reset_set, "%llx\n");
158
159
160int a5xx_debugfs_init(struct msm_gpu *gpu, struct drm_minor *minor)
161{
162	struct drm_device *dev;
163	struct dentry *ent;
164	int ret;
165
166	if (!minor)
167		return 0;
168
169	dev = minor->dev;
170
171	ret = drm_debugfs_create_files(a5xx_debugfs_list,
172			ARRAY_SIZE(a5xx_debugfs_list),
173			minor->debugfs_root, minor);
174
175	if (ret) {
176		dev_err(dev->dev, "could not install a5xx_debugfs_list\n");
177		return ret;
178	}
179
180	ent = debugfs_create_file("reset", S_IWUGO,
181		minor->debugfs_root,
182		dev, &reset_fops);
183	if (!ent)
184		return -ENOMEM;
185
186	return 0;
187}