123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187 |
- /* Copyright (c) 2016-2017 The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- */
- #include <linux/types.h>
- #include <linux/debugfs.h>
- #include <drm/drm_print.h>
- #include "a5xx_gpu.h"
- static int pfp_print(struct msm_gpu *gpu, struct drm_printer *p)
- {
- int i;
- drm_printf(p, "PFP state:\n");
- for (i = 0; i < 36; i++) {
- gpu_write(gpu, REG_A5XX_CP_PFP_STAT_ADDR, i);
- drm_printf(p, " %02x: %08x\n", i,
- gpu_read(gpu, REG_A5XX_CP_PFP_STAT_DATA));
- }
- return 0;
- }
- static int me_print(struct msm_gpu *gpu, struct drm_printer *p)
- {
- int i;
- drm_printf(p, "ME state:\n");
- for (i = 0; i < 29; i++) {
- gpu_write(gpu, REG_A5XX_CP_ME_STAT_ADDR, i);
- drm_printf(p, " %02x: %08x\n", i,
- gpu_read(gpu, REG_A5XX_CP_ME_STAT_DATA));
- }
- return 0;
- }
- static int meq_print(struct msm_gpu *gpu, struct drm_printer *p)
- {
- int i;
- drm_printf(p, "MEQ state:\n");
- gpu_write(gpu, REG_A5XX_CP_MEQ_DBG_ADDR, 0);
- for (i = 0; i < 64; i++) {
- drm_printf(p, " %02x: %08x\n", i,
- gpu_read(gpu, REG_A5XX_CP_MEQ_DBG_DATA));
- }
- return 0;
- }
- static int roq_print(struct msm_gpu *gpu, struct drm_printer *p)
- {
- int i;
- drm_printf(p, "ROQ state:\n");
- gpu_write(gpu, REG_A5XX_CP_ROQ_DBG_ADDR, 0);
- for (i = 0; i < 512 / 4; i++) {
- uint32_t val[4];
- int j;
- for (j = 0; j < 4; j++)
- val[j] = gpu_read(gpu, REG_A5XX_CP_ROQ_DBG_DATA);
- drm_printf(p, " %02x: %08x %08x %08x %08x\n", i,
- val[0], val[1], val[2], val[3]);
- }
- return 0;
- }
- static int show(struct seq_file *m, void *arg)
- {
- struct drm_info_node *node = (struct drm_info_node *) m->private;
- struct drm_device *dev = node->minor->dev;
- struct msm_drm_private *priv = dev->dev_private;
- struct drm_printer p = drm_seq_file_printer(m);
- int (*show)(struct msm_gpu *gpu, struct drm_printer *p) =
- node->info_ent->data;
- return show(priv->gpu, &p);
- }
- #define ENT(n) { .name = #n, .show = show, .data = n ##_print }
- static struct drm_info_list a5xx_debugfs_list[] = {
- ENT(pfp),
- ENT(me),
- ENT(meq),
- ENT(roq),
- };
- /* for debugfs files that can be written to, we can't use drm helper: */
- static int
- reset_set(void *data, u64 val)
- {
- struct drm_device *dev = data;
- struct msm_drm_private *priv = dev->dev_private;
- struct msm_gpu *gpu = priv->gpu;
- struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
- struct a5xx_gpu *a5xx_gpu = to_a5xx_gpu(adreno_gpu);
- if (!capable(CAP_SYS_ADMIN))
- return -EINVAL;
- /* TODO do we care about trying to make sure the GPU is idle?
- * Since this is just a debug feature limited to CAP_SYS_ADMIN,
- * maybe it is fine to let the user keep both pieces if they
- * try to reset an active GPU.
- */
- mutex_lock(&dev->struct_mutex);
- release_firmware(adreno_gpu->fw[ADRENO_FW_PM4]);
- adreno_gpu->fw[ADRENO_FW_PM4] = NULL;
- release_firmware(adreno_gpu->fw[ADRENO_FW_PFP]);
- adreno_gpu->fw[ADRENO_FW_PFP] = NULL;
- if (a5xx_gpu->pm4_bo) {
- if (a5xx_gpu->pm4_iova)
- msm_gem_put_iova(a5xx_gpu->pm4_bo, gpu->aspace);
- drm_gem_object_put(a5xx_gpu->pm4_bo);
- a5xx_gpu->pm4_bo = NULL;
- }
- if (a5xx_gpu->pfp_bo) {
- if (a5xx_gpu->pfp_iova)
- msm_gem_put_iova(a5xx_gpu->pfp_bo, gpu->aspace);
- drm_gem_object_put(a5xx_gpu->pfp_bo);
- a5xx_gpu->pfp_bo = NULL;
- }
- gpu->needs_hw_init = true;
- pm_runtime_get_sync(&gpu->pdev->dev);
- gpu->funcs->recover(gpu);
- pm_runtime_put_sync(&gpu->pdev->dev);
- mutex_unlock(&dev->struct_mutex);
- return 0;
- }
- DEFINE_SIMPLE_ATTRIBUTE(reset_fops, NULL, reset_set, "%llx\n");
- int a5xx_debugfs_init(struct msm_gpu *gpu, struct drm_minor *minor)
- {
- struct drm_device *dev;
- struct dentry *ent;
- int ret;
- if (!minor)
- return 0;
- dev = minor->dev;
- ret = drm_debugfs_create_files(a5xx_debugfs_list,
- ARRAY_SIZE(a5xx_debugfs_list),
- minor->debugfs_root, minor);
- if (ret) {
- dev_err(dev->dev, "could not install a5xx_debugfs_list\n");
- return ret;
- }
- ent = debugfs_create_file("reset", S_IWUGO,
- minor->debugfs_root,
- dev, &reset_fops);
- if (!ent)
- return -ENOMEM;
- return 0;
- }
|