2 * Copyright (C) 2009 Red Hat <bskeggs@redhat.com>
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:
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.
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.
28 * Ben Skeggs <bskeggs@redhat.com>
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"
38 nouveau_debugfs_vbios_image(struct seq_file
*m
, void *data
)
40 struct drm_info_node
*node
= (struct drm_info_node
*) m
->private;
41 struct nouveau_drm
*drm
= nouveau_drm(node
->minor
->dev
);
44 for (i
= 0; i
< drm
->vbios
.length
; i
++)
45 seq_printf(m
, "%c", drm
->vbios
.data
[i
]);
50 nouveau_debugfs_strap_peek(struct seq_file
*m
, void *data
)
52 struct drm_info_node
*node
= m
->private;
53 struct nouveau_drm
*drm
= nouveau_drm(node
->minor
->dev
);
56 ret
= pm_runtime_get_sync(drm
->dev
->dev
);
57 if (ret
< 0 && ret
!= -EACCES
) {
58 pm_runtime_put_autosuspend(drm
->dev
->dev
);
62 seq_printf(m
, "0x%08x\n",
63 nvif_rd32(&drm
->client
.device
.object
, 0x101000));
65 pm_runtime_mark_last_busy(drm
->dev
->dev
);
66 pm_runtime_put_autosuspend(drm
->dev
->dev
);
72 nouveau_debugfs_pstate_get(struct seq_file
*m
, void *data
)
74 struct drm_device
*drm
= m
->private;
75 struct nouveau_debugfs
*debugfs
= nouveau_debugfs(drm
);
76 struct nvif_object
*ctrl
= &debugfs
->ctrl
;
77 struct nvif_control_pstate_info_v0 info
= {};
83 ret
= nvif_mthd(ctrl
, NVIF_CONTROL_PSTATE_INFO
, &info
, sizeof(info
));
87 for (i
= 0; i
< info
.count
+ 1; i
++) {
88 const s32 state
= i
< info
.count
? i
:
89 NVIF_CONTROL_PSTATE_ATTR_V0_STATE_CURRENT
;
90 struct nvif_control_pstate_attr_v0 attr
= {
95 ret
= nvif_mthd(ctrl
, NVIF_CONTROL_PSTATE_ATTR
,
101 seq_printf(m
, "%02x:", attr
.state
);
103 seq_printf(m
, "%s:", info
.pwrsrc
== 0 ? "DC" :
104 info
.pwrsrc
== 1 ? "AC" : "--");
109 ret
= nvif_mthd(ctrl
, NVIF_CONTROL_PSTATE_ATTR
,
110 &attr
, sizeof(attr
));
114 seq_printf(m
, " %s %d", attr
.name
, attr
.min
);
115 if (attr
.min
!= attr
.max
)
116 seq_printf(m
, "-%d", attr
.max
);
117 seq_printf(m
, " %s", attr
.unit
);
118 } while (attr
.index
);
121 if (info
.ustate_ac
== state
)
122 seq_printf(m
, " AC");
123 if (info
.ustate_dc
== state
)
124 seq_printf(m
, " DC");
125 if (info
.pstate
== state
)
128 if (info
.ustate_ac
< -1)
129 seq_printf(m
, " AC");
130 if (info
.ustate_dc
< -1)
131 seq_printf(m
, " DC");
141 nouveau_debugfs_pstate_set(struct file
*file
, const char __user
*ubuf
,
142 size_t len
, loff_t
*offp
)
144 struct seq_file
*m
= file
->private_data
;
145 struct drm_device
*drm
= m
->private;
146 struct nouveau_debugfs
*debugfs
= nouveau_debugfs(drm
);
147 struct nvif_object
*ctrl
= &debugfs
->ctrl
;
148 struct nvif_control_pstate_user_v0 args
= { .pwrsrc
= -EINVAL
};
149 char buf
[32] = {}, *tmp
, *cur
= buf
;
155 if (len
>= sizeof(buf
))
158 if (copy_from_user(buf
, ubuf
, len
))
161 if ((tmp
= strchr(buf
, '\n')))
164 if (!strncasecmp(cur
, "dc:", 3)) {
168 if (!strncasecmp(cur
, "ac:", 3)) {
173 if (!strcasecmp(cur
, "none"))
174 args
.ustate
= NVIF_CONTROL_PSTATE_USER_V0_STATE_UNKNOWN
;
176 if (!strcasecmp(cur
, "auto"))
177 args
.ustate
= NVIF_CONTROL_PSTATE_USER_V0_STATE_PERFMON
;
179 ret
= kstrtol(cur
, 16, &value
);
185 ret
= pm_runtime_get_sync(drm
->dev
);
186 if (ret
< 0 && ret
!= -EACCES
) {
187 pm_runtime_put_autosuspend(drm
->dev
);
191 ret
= nvif_mthd(ctrl
, NVIF_CONTROL_PSTATE_USER
, &args
, sizeof(args
));
192 pm_runtime_put_autosuspend(drm
->dev
);
200 nouveau_debugfs_pstate_open(struct inode
*inode
, struct file
*file
)
202 return single_open(file
, nouveau_debugfs_pstate_get
, inode
->i_private
);
205 static const struct file_operations nouveau_pstate_fops
= {
206 .owner
= THIS_MODULE
,
207 .open
= nouveau_debugfs_pstate_open
,
209 .write
= nouveau_debugfs_pstate_set
,
212 static struct drm_info_list nouveau_debugfs_list
[] = {
213 { "vbios.rom", nouveau_debugfs_vbios_image
, 0, NULL
},
214 { "strap_peek", nouveau_debugfs_strap_peek
, 0, NULL
},
216 #define NOUVEAU_DEBUGFS_ENTRIES ARRAY_SIZE(nouveau_debugfs_list)
218 static const struct nouveau_debugfs_files
{
220 const struct file_operations
*fops
;
221 } nouveau_debugfs_files
[] = {
222 {"pstate", &nouveau_pstate_fops
},
226 nouveau_drm_debugfs_init(struct drm_minor
*minor
)
228 struct nouveau_drm
*drm
= nouveau_drm(minor
->dev
);
229 struct dentry
*dentry
;
232 for (i
= 0; i
< ARRAY_SIZE(nouveau_debugfs_files
); i
++) {
233 debugfs_create_file(nouveau_debugfs_files
[i
].name
,
235 minor
->debugfs_root
, minor
->dev
,
236 nouveau_debugfs_files
[i
].fops
);
239 drm_debugfs_create_files(nouveau_debugfs_list
,
240 NOUVEAU_DEBUGFS_ENTRIES
,
241 minor
->debugfs_root
, minor
);
243 /* Set the size of the vbios since we know it, and it's confusing to
244 * userspace if it wants to seek() but the file has a length of 0
246 dentry
= debugfs_lookup("vbios.rom", minor
->debugfs_root
);
250 d_inode(dentry
)->i_size
= drm
->vbios
.length
;
255 nouveau_debugfs_init(struct nouveau_drm
*drm
)
259 drm
->debugfs
= kzalloc(sizeof(*drm
->debugfs
), GFP_KERNEL
);
263 ret
= nvif_object_ctor(&drm
->client
.device
.object
, "debugfsCtrl", 0,
264 NVIF_CLASS_CONTROL
, NULL
, 0,
265 &drm
->debugfs
->ctrl
);
273 nouveau_debugfs_fini(struct nouveau_drm
*drm
)
275 if (drm
->debugfs
&& drm
->debugfs
->ctrl
.priv
)
276 nvif_object_dtor(&drm
->debugfs
->ctrl
);