linux/drivers/gpu/drm/nouveau/nouveau_debugfs.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2009 Red Hat <bskeggs@redhat.com>
   3 *
   4 * Permission is hereby granted, free of charge, to any person obtaining
   5 * a copy of this software and associated documentation files (the
   6 * "Software"), to deal in the Software without restriction, including
   7 * without limitation the rights to use, copy, modify, merge, publish,
   8 * distribute, sublicense, and/or sell copies of the Software, and to
   9 * permit persons to whom the Software is furnished to do so, subject to
  10 * the following conditions:
  11 *
  12 * The above copyright notice and this permission notice (including the
  13 * next paragraph) shall be included in all copies or substantial
  14 * 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 OF
  18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
  19 * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
  20 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  21 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  22 * 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 int
  38nouveau_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 int
  50nouveau_debugfs_pstate_get(struct seq_file *m, void *data)
  51{
  52        struct drm_device *drm = m->private;
  53        struct nouveau_debugfs *debugfs = nouveau_debugfs(drm);
  54        struct nvif_object *ctrl = &debugfs->ctrl;
  55        struct nvif_control_pstate_info_v0 info = {};
  56        int ret, i;
  57
  58        if (!debugfs)
  59                return -ENODEV;
  60
  61        ret = nvif_mthd(ctrl, NVIF_CONTROL_PSTATE_INFO, &info, sizeof(info));
  62        if (ret)
  63                return ret;
  64
  65        for (i = 0; i < info.count + 1; i++) {
  66                const s32 state = i < info.count ? i :
  67                        NVIF_CONTROL_PSTATE_ATTR_V0_STATE_CURRENT;
  68                struct nvif_control_pstate_attr_v0 attr = {
  69                        .state = state,
  70                        .index = 0,
  71                };
  72
  73                ret = nvif_mthd(ctrl, NVIF_CONTROL_PSTATE_ATTR,
  74                                &attr, sizeof(attr));
  75                if (ret)
  76                        return ret;
  77
  78                if (i < info.count)
  79                        seq_printf(m, "%02x:", attr.state);
  80                else
  81                        seq_printf(m, "%s:", info.pwrsrc == 0 ? "DC" :
  82                                             info.pwrsrc == 1 ? "AC" : "--");
  83
  84                attr.index = 0;
  85                do {
  86                        attr.state = state;
  87                        ret = nvif_mthd(ctrl, NVIF_CONTROL_PSTATE_ATTR,
  88                                        &attr, sizeof(attr));
  89                        if (ret)
  90                                return ret;
  91
  92                        seq_printf(m, " %s %d", attr.name, attr.min);
  93                        if (attr.min != attr.max)
  94                                seq_printf(m, "-%d", attr.max);
  95                        seq_printf(m, " %s", attr.unit);
  96                } while (attr.index);
  97
  98                if (state >= 0) {
  99                        if (info.ustate_ac == state)
 100                                seq_printf(m, " AC");
 101                        if (info.ustate_dc == state)
 102                                seq_printf(m, " DC");
 103                        if (info.pstate == state)
 104                                seq_printf(m, " *");
 105                } else {
 106                        if (info.ustate_ac < -1)
 107                                seq_printf(m, " AC");
 108                        if (info.ustate_dc < -1)
 109                                seq_printf(m, " DC");
 110                }
 111
 112                seq_printf(m, "\n");
 113        }
 114
 115        return 0;
 116}
 117
 118static ssize_t
 119nouveau_debugfs_pstate_set(struct file *file, const char __user *ubuf,
 120                           size_t len, loff_t *offp)
 121{
 122        struct seq_file *m = file->private_data;
 123        struct drm_device *drm = m->private;
 124        struct nouveau_debugfs *debugfs = nouveau_debugfs(drm);
 125        struct nvif_object *ctrl = &debugfs->ctrl;
 126        struct nvif_control_pstate_user_v0 args = { .pwrsrc = -EINVAL };
 127        char buf[32] = {}, *tmp, *cur = buf;
 128        long value, ret;
 129
 130        if (!debugfs)
 131                return -ENODEV;
 132
 133        if (len >= sizeof(buf))
 134                return -EINVAL;
 135
 136        if (copy_from_user(buf, ubuf, len))
 137                return -EFAULT;
 138
 139        if ((tmp = strchr(buf, '\n')))
 140                *tmp = '\0';
 141
 142        if (!strncasecmp(cur, "dc:", 3)) {
 143                args.pwrsrc = 0;
 144                cur += 3;
 145        } else
 146        if (!strncasecmp(cur, "ac:", 3)) {
 147                args.pwrsrc = 1;
 148                cur += 3;
 149        }
 150
 151        if (!strcasecmp(cur, "none"))
 152                args.ustate = NVIF_CONTROL_PSTATE_USER_V0_STATE_UNKNOWN;
 153        else
 154        if (!strcasecmp(cur, "auto"))
 155                args.ustate = NVIF_CONTROL_PSTATE_USER_V0_STATE_PERFMON;
 156        else {
 157                ret = kstrtol(cur, 16, &value);
 158                if (ret)
 159                        return ret;
 160                args.ustate = value;
 161        }
 162
 163        ret = pm_runtime_get_sync(drm->dev);
 164        if (IS_ERR_VALUE(ret) && ret != -EACCES)
 165                return ret;
 166        ret = nvif_mthd(ctrl, NVIF_CONTROL_PSTATE_USER, &args, sizeof(args));
 167        pm_runtime_put_autosuspend(drm->dev);
 168        if (ret < 0)
 169                return ret;
 170
 171        return len;
 172}
 173
 174static int
 175nouveau_debugfs_pstate_open(struct inode *inode, struct file *file)
 176{
 177        return single_open(file, nouveau_debugfs_pstate_get, inode->i_private);
 178}
 179
 180static const struct file_operations nouveau_pstate_fops = {
 181        .owner = THIS_MODULE,
 182        .open = nouveau_debugfs_pstate_open,
 183        .read = seq_read,
 184        .write = nouveau_debugfs_pstate_set,
 185};
 186
 187static struct drm_info_list nouveau_debugfs_list[] = {
 188        { "vbios.rom", nouveau_debugfs_vbios_image, 0, NULL },
 189};
 190#define NOUVEAU_DEBUGFS_ENTRIES ARRAY_SIZE(nouveau_debugfs_list)
 191
 192static const struct nouveau_debugfs_files {
 193        const char *name;
 194        const struct file_operations *fops;
 195} nouveau_debugfs_files[] = {
 196        {"pstate", &nouveau_pstate_fops},
 197};
 198
 199int
 200nouveau_drm_debugfs_init(struct drm_minor *minor)
 201{
 202        struct dentry *dentry;
 203        int i;
 204
 205        for (i = 0; i < ARRAY_SIZE(nouveau_debugfs_files); i++) {
 206                dentry = debugfs_create_file(nouveau_debugfs_files[i].name,
 207                                             S_IRUGO | S_IWUSR,
 208                                             minor->debugfs_root, minor->dev,
 209                                             nouveau_debugfs_files[i].fops);
 210                if (!dentry)
 211                        return -ENOMEM;
 212        }
 213
 214        return drm_debugfs_create_files(nouveau_debugfs_list,
 215                                        NOUVEAU_DEBUGFS_ENTRIES,
 216                                        minor->debugfs_root, minor);
 217}
 218
 219int
 220nouveau_debugfs_init(struct nouveau_drm *drm)
 221{
 222        int ret;
 223
 224        drm->debugfs = kzalloc(sizeof(*drm->debugfs), GFP_KERNEL);
 225        if (!drm->debugfs)
 226                return -ENOMEM;
 227
 228        ret = nvif_object_init(&drm->client.device.object, 0,
 229                               NVIF_CLASS_CONTROL, NULL, 0,
 230                               &drm->debugfs->ctrl);
 231        if (ret)
 232                return ret;
 233
 234        return 0;
 235}
 236
 237void
 238nouveau_debugfs_fini(struct nouveau_drm *drm)
 239{
 240        if (drm->debugfs && drm->debugfs->ctrl.priv)
 241                nvif_object_fini(&drm->debugfs->ctrl);
 242
 243        kfree(drm->debugfs);
 244        drm->debugfs = NULL;
 245}
 246