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_info_node *node = (struct drm_info_node *) m->private;
  53        struct nouveau_debugfs *debugfs = nouveau_debugfs(node->minor->dev);
  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_info_node *node = (struct drm_info_node *) m->private;
 124        struct nouveau_debugfs *debugfs = nouveau_debugfs(node->minor->dev);
 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 = nvif_mthd(ctrl, NVIF_CONTROL_PSTATE_USER, &args, sizeof(args));
 164        if (ret < 0)
 165                return ret;
 166
 167        return len;
 168}
 169
 170static int
 171nouveau_debugfs_pstate_open(struct inode *inode, struct file *file)
 172{
 173        return single_open(file, nouveau_debugfs_pstate_get, inode->i_private);
 174}
 175
 176static const struct file_operations nouveau_pstate_fops = {
 177        .owner = THIS_MODULE,
 178        .open = nouveau_debugfs_pstate_open,
 179        .read = seq_read,
 180        .write = nouveau_debugfs_pstate_set,
 181};
 182
 183static struct drm_info_list nouveau_debugfs_list[] = {
 184        { "vbios.rom", nouveau_debugfs_vbios_image, 0, NULL },
 185};
 186#define NOUVEAU_DEBUGFS_ENTRIES ARRAY_SIZE(nouveau_debugfs_list)
 187
 188static const struct nouveau_debugfs_files {
 189        const char *name;
 190        const struct file_operations *fops;
 191} nouveau_debugfs_files[] = {
 192        {"pstate", &nouveau_pstate_fops},
 193};
 194
 195static int
 196nouveau_debugfs_create_file(struct drm_minor *minor,
 197                const struct nouveau_debugfs_files *ndf)
 198{
 199        struct drm_info_node *node;
 200
 201        node = kmalloc(sizeof(*node), GFP_KERNEL);
 202        if (node == NULL)
 203                return -ENOMEM;
 204
 205        node->minor = minor;
 206        node->info_ent = (const void *)ndf->fops;
 207        node->dent = debugfs_create_file(ndf->name, S_IRUGO | S_IWUSR,
 208                                         minor->debugfs_root, node, ndf->fops);
 209        if (!node->dent) {
 210                kfree(node);
 211                return -ENOMEM;
 212        }
 213
 214        mutex_lock(&minor->debugfs_lock);
 215        list_add(&node->list, &minor->debugfs_list);
 216        mutex_unlock(&minor->debugfs_lock);
 217        return 0;
 218}
 219
 220int
 221nouveau_drm_debugfs_init(struct drm_minor *minor)
 222{
 223        int i, ret;
 224
 225        for (i = 0; i < ARRAY_SIZE(nouveau_debugfs_files); i++) {
 226                ret = nouveau_debugfs_create_file(minor,
 227                                                  &nouveau_debugfs_files[i]);
 228
 229                if (ret)
 230                        return ret;
 231        }
 232
 233        return drm_debugfs_create_files(nouveau_debugfs_list,
 234                                        NOUVEAU_DEBUGFS_ENTRIES,
 235                                        minor->debugfs_root, minor);
 236}
 237
 238void
 239nouveau_drm_debugfs_cleanup(struct drm_minor *minor)
 240{
 241        int i;
 242
 243        drm_debugfs_remove_files(nouveau_debugfs_list, NOUVEAU_DEBUGFS_ENTRIES,
 244                                 minor);
 245
 246        for (i = 0; i < ARRAY_SIZE(nouveau_debugfs_files); i++) {
 247                drm_debugfs_remove_files((struct drm_info_list *)
 248                                         nouveau_debugfs_files[i].fops,
 249                                         1, minor);
 250        }
 251}
 252
 253int
 254nouveau_debugfs_init(struct nouveau_drm *drm)
 255{
 256        int ret;
 257
 258        drm->debugfs = kzalloc(sizeof(*drm->debugfs), GFP_KERNEL);
 259        if (!drm->debugfs)
 260                return -ENOMEM;
 261
 262        ret = nvif_object_init(&drm->device.object, 0, NVIF_CLASS_CONTROL,
 263                               NULL, 0, &drm->debugfs->ctrl);
 264        if (ret)
 265                return ret;
 266
 267        return 0;
 268}
 269
 270void
 271nouveau_debugfs_fini(struct nouveau_drm *drm)
 272{
 273        if (drm->debugfs && drm->debugfs->ctrl.priv)
 274                nvif_object_fini(&drm->debugfs->ctrl);
 275
 276        kfree(drm->debugfs);
 277        drm->debugfs = NULL;
 278}
 279