Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright (C) 2009 Red Hat <bskeggs@redhat.com>
0003  *
0004  * Permission is hereby granted, free of charge, to any person obtaining
0005  * a copy of this software and associated documentation files (the
0006  * "Software"), to deal in the Software without restriction, including
0007  * without limitation the rights to use, copy, modify, merge, publish,
0008  * distribute, sublicense, and/or sell copies of the Software, and to
0009  * permit persons to whom the Software is furnished to do so, subject to
0010  * the following conditions:
0011  *
0012  * The above copyright notice and this permission notice (including the
0013  * next paragraph) shall be included in all copies or substantial
0014  * portions of the Software.
0015  *
0016  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
0017  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
0018  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
0019  * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
0020  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
0021  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
0022  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
0023  *
0024  */
0025 
0026 /*
0027  * Authors:
0028  *  Ben Skeggs <bskeggs@redhat.com>
0029  */
0030 
0031 #include <linux/debugfs.h>
0032 #include <nvif/class.h>
0033 #include <nvif/if0001.h>
0034 #include "nouveau_debugfs.h"
0035 #include "nouveau_drv.h"
0036 
0037 static int
0038 nouveau_debugfs_vbios_image(struct seq_file *m, void *data)
0039 {
0040     struct drm_info_node *node = (struct drm_info_node *) m->private;
0041     struct nouveau_drm *drm = nouveau_drm(node->minor->dev);
0042     int i;
0043 
0044     for (i = 0; i < drm->vbios.length; i++)
0045         seq_printf(m, "%c", drm->vbios.data[i]);
0046     return 0;
0047 }
0048 
0049 static int
0050 nouveau_debugfs_strap_peek(struct seq_file *m, void *data)
0051 {
0052     struct drm_info_node *node = m->private;
0053     struct nouveau_drm *drm = nouveau_drm(node->minor->dev);
0054     int ret;
0055 
0056     ret = pm_runtime_get_sync(drm->dev->dev);
0057     if (ret < 0 && ret != -EACCES) {
0058         pm_runtime_put_autosuspend(drm->dev->dev);
0059         return ret;
0060     }
0061 
0062     seq_printf(m, "0x%08x\n",
0063            nvif_rd32(&drm->client.device.object, 0x101000));
0064 
0065     pm_runtime_mark_last_busy(drm->dev->dev);
0066     pm_runtime_put_autosuspend(drm->dev->dev);
0067 
0068     return 0;
0069 }
0070 
0071 static int
0072 nouveau_debugfs_pstate_get(struct seq_file *m, void *data)
0073 {
0074     struct drm_device *drm = m->private;
0075     struct nouveau_debugfs *debugfs = nouveau_debugfs(drm);
0076     struct nvif_object *ctrl = &debugfs->ctrl;
0077     struct nvif_control_pstate_info_v0 info = {};
0078     int ret, i;
0079 
0080     if (!debugfs)
0081         return -ENODEV;
0082 
0083     ret = nvif_mthd(ctrl, NVIF_CONTROL_PSTATE_INFO, &info, sizeof(info));
0084     if (ret)
0085         return ret;
0086 
0087     for (i = 0; i < info.count + 1; i++) {
0088         const s32 state = i < info.count ? i :
0089             NVIF_CONTROL_PSTATE_ATTR_V0_STATE_CURRENT;
0090         struct nvif_control_pstate_attr_v0 attr = {
0091             .state = state,
0092             .index = 0,
0093         };
0094 
0095         ret = nvif_mthd(ctrl, NVIF_CONTROL_PSTATE_ATTR,
0096                 &attr, sizeof(attr));
0097         if (ret)
0098             return ret;
0099 
0100         if (i < info.count)
0101             seq_printf(m, "%02x:", attr.state);
0102         else
0103             seq_printf(m, "%s:", info.pwrsrc == 0 ? "DC" :
0104                          info.pwrsrc == 1 ? "AC" : "--");
0105 
0106         attr.index = 0;
0107         do {
0108             attr.state = state;
0109             ret = nvif_mthd(ctrl, NVIF_CONTROL_PSTATE_ATTR,
0110                     &attr, sizeof(attr));
0111             if (ret)
0112                 return ret;
0113 
0114             seq_printf(m, " %s %d", attr.name, attr.min);
0115             if (attr.min != attr.max)
0116                 seq_printf(m, "-%d", attr.max);
0117             seq_printf(m, " %s", attr.unit);
0118         } while (attr.index);
0119 
0120         if (state >= 0) {
0121             if (info.ustate_ac == state)
0122                 seq_printf(m, " AC");
0123             if (info.ustate_dc == state)
0124                 seq_printf(m, " DC");
0125             if (info.pstate == state)
0126                 seq_printf(m, " *");
0127         } else {
0128             if (info.ustate_ac < -1)
0129                 seq_printf(m, " AC");
0130             if (info.ustate_dc < -1)
0131                 seq_printf(m, " DC");
0132         }
0133 
0134         seq_printf(m, "\n");
0135     }
0136 
0137     return 0;
0138 }
0139 
0140 static ssize_t
0141 nouveau_debugfs_pstate_set(struct file *file, const char __user *ubuf,
0142                size_t len, loff_t *offp)
0143 {
0144     struct seq_file *m = file->private_data;
0145     struct drm_device *drm = m->private;
0146     struct nouveau_debugfs *debugfs = nouveau_debugfs(drm);
0147     struct nvif_object *ctrl = &debugfs->ctrl;
0148     struct nvif_control_pstate_user_v0 args = { .pwrsrc = -EINVAL };
0149     char buf[32] = {}, *tmp, *cur = buf;
0150     long value, ret;
0151 
0152     if (!debugfs)
0153         return -ENODEV;
0154 
0155     if (len >= sizeof(buf))
0156         return -EINVAL;
0157 
0158     if (copy_from_user(buf, ubuf, len))
0159         return -EFAULT;
0160 
0161     if ((tmp = strchr(buf, '\n')))
0162         *tmp = '\0';
0163 
0164     if (!strncasecmp(cur, "dc:", 3)) {
0165         args.pwrsrc = 0;
0166         cur += 3;
0167     } else
0168     if (!strncasecmp(cur, "ac:", 3)) {
0169         args.pwrsrc = 1;
0170         cur += 3;
0171     }
0172 
0173     if (!strcasecmp(cur, "none"))
0174         args.ustate = NVIF_CONTROL_PSTATE_USER_V0_STATE_UNKNOWN;
0175     else
0176     if (!strcasecmp(cur, "auto"))
0177         args.ustate = NVIF_CONTROL_PSTATE_USER_V0_STATE_PERFMON;
0178     else {
0179         ret = kstrtol(cur, 16, &value);
0180         if (ret)
0181             return ret;
0182         args.ustate = value;
0183     }
0184 
0185     ret = pm_runtime_get_sync(drm->dev);
0186     if (ret < 0 && ret != -EACCES) {
0187         pm_runtime_put_autosuspend(drm->dev);
0188         return ret;
0189     }
0190 
0191     ret = nvif_mthd(ctrl, NVIF_CONTROL_PSTATE_USER, &args, sizeof(args));
0192     pm_runtime_put_autosuspend(drm->dev);
0193     if (ret < 0)
0194         return ret;
0195 
0196     return len;
0197 }
0198 
0199 static int
0200 nouveau_debugfs_pstate_open(struct inode *inode, struct file *file)
0201 {
0202     return single_open(file, nouveau_debugfs_pstate_get, inode->i_private);
0203 }
0204 
0205 static const struct file_operations nouveau_pstate_fops = {
0206     .owner = THIS_MODULE,
0207     .open = nouveau_debugfs_pstate_open,
0208     .read = seq_read,
0209     .write = nouveau_debugfs_pstate_set,
0210     .release = single_release,
0211 };
0212 
0213 static struct drm_info_list nouveau_debugfs_list[] = {
0214     { "vbios.rom",  nouveau_debugfs_vbios_image, 0, NULL },
0215     { "strap_peek", nouveau_debugfs_strap_peek, 0, NULL },
0216 };
0217 #define NOUVEAU_DEBUGFS_ENTRIES ARRAY_SIZE(nouveau_debugfs_list)
0218 
0219 static const struct nouveau_debugfs_files {
0220     const char *name;
0221     const struct file_operations *fops;
0222 } nouveau_debugfs_files[] = {
0223     {"pstate", &nouveau_pstate_fops},
0224 };
0225 
0226 void
0227 nouveau_drm_debugfs_init(struct drm_minor *minor)
0228 {
0229     struct nouveau_drm *drm = nouveau_drm(minor->dev);
0230     struct dentry *dentry;
0231     int i;
0232 
0233     for (i = 0; i < ARRAY_SIZE(nouveau_debugfs_files); i++) {
0234         debugfs_create_file(nouveau_debugfs_files[i].name,
0235                     S_IRUGO | S_IWUSR,
0236                     minor->debugfs_root, minor->dev,
0237                     nouveau_debugfs_files[i].fops);
0238     }
0239 
0240     drm_debugfs_create_files(nouveau_debugfs_list,
0241                  NOUVEAU_DEBUGFS_ENTRIES,
0242                  minor->debugfs_root, minor);
0243 
0244     /* Set the size of the vbios since we know it, and it's confusing to
0245      * userspace if it wants to seek() but the file has a length of 0
0246      */
0247     dentry = debugfs_lookup("vbios.rom", minor->debugfs_root);
0248     if (!dentry)
0249         return;
0250 
0251     d_inode(dentry)->i_size = drm->vbios.length;
0252     dput(dentry);
0253 }
0254 
0255 int
0256 nouveau_debugfs_init(struct nouveau_drm *drm)
0257 {
0258     drm->debugfs = kzalloc(sizeof(*drm->debugfs), GFP_KERNEL);
0259     if (!drm->debugfs)
0260         return -ENOMEM;
0261 
0262     return nvif_object_ctor(&drm->client.device.object, "debugfsCtrl", 0,
0263                 NVIF_CLASS_CONTROL, NULL, 0,
0264                 &drm->debugfs->ctrl);
0265 }
0266 
0267 void
0268 nouveau_debugfs_fini(struct nouveau_drm *drm)
0269 {
0270     if (drm->debugfs && drm->debugfs->ctrl.priv)
0271         nvif_object_dtor(&drm->debugfs->ctrl);
0272 
0273     kfree(drm->debugfs);
0274     drm->debugfs = NULL;
0275 }