316 lines · c
1/*2 * Copyright (C) 2009 Red Hat <bskeggs@redhat.com>3 *4 * Permission is hereby granted, free of charge, to any person obtaining5 * a copy of this software and associated documentation files (the6 * "Software"), to deal in the Software without restriction, including7 * without limitation the rights to use, copy, modify, merge, publish,8 * distribute, sublicense, and/or sell copies of the Software, and to9 * permit persons to whom the Software is furnished to do so, subject to10 * the following conditions:11 *12 * The above copyright notice and this permission notice (including the13 * next paragraph) shall be included in all copies or substantial14 * portions of the Software.15 *16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,17 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.19 * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE20 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION21 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION22 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.23 *24 */25 26/*27 * Authors:28 * Ben Skeggs <bskeggs@redhat.com>29 */30 31#include <linux/debugfs.h>32#include <nvif/class.h>33#include <nvif/if0001.h>34#include "nouveau_debugfs.h"35#include "nouveau_drv.h"36 37static int38nouveau_debugfs_vbios_image(struct seq_file *m, void *data)39{40 struct drm_info_node *node = (struct drm_info_node *) m->private;41 struct nouveau_drm *drm = nouveau_drm(node->minor->dev);42 int i;43 44 for (i = 0; i < drm->vbios.length; i++)45 seq_printf(m, "%c", drm->vbios.data[i]);46 return 0;47}48 49static int50nouveau_debugfs_strap_peek(struct seq_file *m, void *data)51{52 struct drm_info_node *node = m->private;53 struct nouveau_drm *drm = nouveau_drm(node->minor->dev);54 int ret;55 56 ret = pm_runtime_get_sync(drm->dev->dev);57 if (ret < 0 && ret != -EACCES) {58 pm_runtime_put_autosuspend(drm->dev->dev);59 return ret;60 }61 62 seq_printf(m, "0x%08x\n",63 nvif_rd32(&drm->client.device.object, 0x101000));64 65 pm_runtime_mark_last_busy(drm->dev->dev);66 pm_runtime_put_autosuspend(drm->dev->dev);67 68 return 0;69}70 71static int72nouveau_debugfs_pstate_get(struct seq_file *m, void *data)73{74 struct drm_device *drm = m->private;75 struct nouveau_debugfs *debugfs = nouveau_debugfs(drm);76 struct nvif_object *ctrl;77 struct nvif_control_pstate_info_v0 info = {};78 int ret, i;79 80 if (!debugfs)81 return -ENODEV;82 83 ctrl = &debugfs->ctrl;84 ret = nvif_mthd(ctrl, NVIF_CONTROL_PSTATE_INFO, &info, sizeof(info));85 if (ret)86 return ret;87 88 for (i = 0; i < info.count + 1; i++) {89 const s32 state = i < info.count ? i :90 NVIF_CONTROL_PSTATE_ATTR_V0_STATE_CURRENT;91 struct nvif_control_pstate_attr_v0 attr = {92 .state = state,93 .index = 0,94 };95 96 ret = nvif_mthd(ctrl, NVIF_CONTROL_PSTATE_ATTR,97 &attr, sizeof(attr));98 if (ret)99 return ret;100 101 if (i < info.count)102 seq_printf(m, "%02x:", attr.state);103 else104 seq_printf(m, "%s:", info.pwrsrc == 0 ? "DC" :105 info.pwrsrc == 1 ? "AC" : "--");106 107 attr.index = 0;108 do {109 attr.state = state;110 ret = nvif_mthd(ctrl, NVIF_CONTROL_PSTATE_ATTR,111 &attr, sizeof(attr));112 if (ret)113 return ret;114 115 seq_printf(m, " %s %d", attr.name, attr.min);116 if (attr.min != attr.max)117 seq_printf(m, "-%d", attr.max);118 seq_printf(m, " %s", attr.unit);119 } while (attr.index);120 121 if (state >= 0) {122 if (info.ustate_ac == state)123 seq_puts(m, " AC");124 if (info.ustate_dc == state)125 seq_puts(m, " DC");126 if (info.pstate == state)127 seq_puts(m, " *");128 } else {129 if (info.ustate_ac < -1)130 seq_puts(m, " AC");131 if (info.ustate_dc < -1)132 seq_puts(m, " DC");133 }134 135 seq_putc(m, '\n');136 }137 138 return 0;139}140 141static ssize_t142nouveau_debugfs_pstate_set(struct file *file, const char __user *ubuf,143 size_t len, loff_t *offp)144{145 struct seq_file *m = file->private_data;146 struct drm_device *drm = m->private;147 struct nouveau_debugfs *debugfs = nouveau_debugfs(drm);148 struct nvif_control_pstate_user_v0 args = { .pwrsrc = -EINVAL };149 char buf[32] = {}, *tmp, *cur = buf;150 long value, ret;151 152 if (!debugfs)153 return -ENODEV;154 155 if (len >= sizeof(buf))156 return -EINVAL;157 158 if (copy_from_user(buf, ubuf, len))159 return -EFAULT;160 161 if ((tmp = strchr(buf, '\n')))162 *tmp = '\0';163 164 if (!strncasecmp(cur, "dc:", 3)) {165 args.pwrsrc = 0;166 cur += 3;167 } else168 if (!strncasecmp(cur, "ac:", 3)) {169 args.pwrsrc = 1;170 cur += 3;171 }172 173 if (!strcasecmp(cur, "none"))174 args.ustate = NVIF_CONTROL_PSTATE_USER_V0_STATE_UNKNOWN;175 else176 if (!strcasecmp(cur, "auto"))177 args.ustate = NVIF_CONTROL_PSTATE_USER_V0_STATE_PERFMON;178 else {179 ret = kstrtol(cur, 16, &value);180 if (ret)181 return ret;182 args.ustate = value;183 }184 185 ret = pm_runtime_get_sync(drm->dev);186 if (ret < 0 && ret != -EACCES) {187 pm_runtime_put_autosuspend(drm->dev);188 return ret;189 }190 191 ret = nvif_mthd(&debugfs->ctrl, NVIF_CONTROL_PSTATE_USER,192 &args, sizeof(args));193 pm_runtime_put_autosuspend(drm->dev);194 if (ret < 0)195 return ret;196 197 return len;198}199 200static int201nouveau_debugfs_pstate_open(struct inode *inode, struct file *file)202{203 return single_open(file, nouveau_debugfs_pstate_get, inode->i_private);204}205 206static void207nouveau_debugfs_gpuva_regions(struct seq_file *m, struct nouveau_uvmm *uvmm)208{209 MA_STATE(mas, &uvmm->region_mt, 0, 0);210 struct nouveau_uvma_region *reg;211 212 seq_puts (m, " VA regions | start | range | end \n");213 seq_puts (m, "----------------------------------------------------------------------------\n");214 mas_for_each(&mas, reg, ULONG_MAX)215 seq_printf(m, " | 0x%016llx | 0x%016llx | 0x%016llx\n",216 reg->va.addr, reg->va.range, reg->va.addr + reg->va.range);217}218 219static int220nouveau_debugfs_gpuva(struct seq_file *m, void *data)221{222 struct drm_info_node *node = (struct drm_info_node *) m->private;223 struct nouveau_drm *drm = nouveau_drm(node->minor->dev);224 struct nouveau_cli *cli;225 226 mutex_lock(&drm->clients_lock);227 list_for_each_entry(cli, &drm->clients, head) {228 struct nouveau_uvmm *uvmm = nouveau_cli_uvmm(cli);229 230 if (!uvmm)231 continue;232 233 nouveau_uvmm_lock(uvmm);234 drm_debugfs_gpuva_info(m, &uvmm->base);235 seq_puts(m, "\n");236 nouveau_debugfs_gpuva_regions(m, uvmm);237 nouveau_uvmm_unlock(uvmm);238 }239 mutex_unlock(&drm->clients_lock);240 241 return 0;242}243 244static const struct file_operations nouveau_pstate_fops = {245 .owner = THIS_MODULE,246 .open = nouveau_debugfs_pstate_open,247 .read = seq_read,248 .write = nouveau_debugfs_pstate_set,249 .release = single_release,250};251 252static struct drm_info_list nouveau_debugfs_list[] = {253 { "vbios.rom", nouveau_debugfs_vbios_image, 0, NULL },254 { "strap_peek", nouveau_debugfs_strap_peek, 0, NULL },255 DRM_DEBUGFS_GPUVA_INFO(nouveau_debugfs_gpuva, NULL),256};257#define NOUVEAU_DEBUGFS_ENTRIES ARRAY_SIZE(nouveau_debugfs_list)258 259static const struct nouveau_debugfs_files {260 const char *name;261 const struct file_operations *fops;262} nouveau_debugfs_files[] = {263 {"pstate", &nouveau_pstate_fops},264};265 266void267nouveau_drm_debugfs_init(struct drm_minor *minor)268{269 struct nouveau_drm *drm = nouveau_drm(minor->dev);270 struct dentry *dentry;271 int i;272 273 for (i = 0; i < ARRAY_SIZE(nouveau_debugfs_files); i++) {274 debugfs_create_file(nouveau_debugfs_files[i].name,275 S_IRUGO | S_IWUSR,276 minor->debugfs_root, minor->dev,277 nouveau_debugfs_files[i].fops);278 }279 280 drm_debugfs_create_files(nouveau_debugfs_list,281 NOUVEAU_DEBUGFS_ENTRIES,282 minor->debugfs_root, minor);283 284 /* Set the size of the vbios since we know it, and it's confusing to285 * userspace if it wants to seek() but the file has a length of 0286 */287 dentry = debugfs_lookup("vbios.rom", minor->debugfs_root);288 if (!dentry)289 return;290 291 d_inode(dentry)->i_size = drm->vbios.length;292 dput(dentry);293}294 295int296nouveau_debugfs_init(struct nouveau_drm *drm)297{298 drm->debugfs = kzalloc(sizeof(*drm->debugfs), GFP_KERNEL);299 if (!drm->debugfs)300 return -ENOMEM;301 302 return nvif_object_ctor(&drm->client.device.object, "debugfsCtrl", 0,303 NVIF_CLASS_CONTROL, NULL, 0,304 &drm->debugfs->ctrl);305}306 307void308nouveau_debugfs_fini(struct nouveau_drm *drm)309{310 if (drm->debugfs && drm->debugfs->ctrl.priv)311 nvif_object_dtor(&drm->debugfs->ctrl);312 313 kfree(drm->debugfs);314 drm->debugfs = NULL;315}316