2 * Copyright 2013 Red Hat Inc.
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
22 * Authors: Ben Skeggs <bskeggs@redhat.com>
26 #include <nvif/class.h>
27 #include <nvif/ioctl.h>
29 #include "nouveau_sysfs.h"
31 MODULE_PARM_DESC(pstate
, "enable sysfs pstate file, which will be moved in the future");
33 module_param_named(pstate
, nouveau_pstate
, int, 0400);
35 static inline struct drm_device
*
36 drm_device(struct device
*d
)
38 return dev_get_drvdata(d
);
41 #define snappendf(p,r,f,a...) do { \
42 snprintf(p, r, f, ##a); \
48 nouveau_sysfs_pstate_get(struct device
*d
, struct device_attribute
*a
, char *b
)
50 struct nouveau_sysfs
*sysfs
= nouveau_sysfs(drm_device(d
));
51 struct nvif_control_pstate_info_v0 info
= {};
52 size_t cnt
= PAGE_SIZE
;
56 ret
= nvif_mthd(&sysfs
->ctrl
, NVIF_CONTROL_PSTATE_INFO
,
61 for (i
= 0; i
< info
.count
+ 1; i
++) {
62 const s32 state
= i
< info
.count
? i
:
63 NVIF_CONTROL_PSTATE_ATTR_V0_STATE_CURRENT
;
64 struct nvif_control_pstate_attr_v0 attr
= {
69 ret
= nvif_mthd(&sysfs
->ctrl
, NVIF_CONTROL_PSTATE_ATTR
,
75 snappendf(buf
, cnt
, "%02x:", attr
.state
);
77 snappendf(buf
, cnt
, "%s:", info
.pwrsrc
== 0 ? "DC" :
78 info
.pwrsrc
== 1 ? "AC" :
84 ret
= nvif_mthd(&sysfs
->ctrl
,
85 NVIF_CONTROL_PSTATE_ATTR
,
90 snappendf(buf
, cnt
, " %s %d", attr
.name
, attr
.min
);
91 if (attr
.min
!= attr
.max
)
92 snappendf(buf
, cnt
, "-%d", attr
.max
);
93 snappendf(buf
, cnt
, " %s", attr
.unit
);
97 if (info
.ustate_ac
== state
)
98 snappendf(buf
, cnt
, " AC");
99 if (info
.ustate_dc
== state
)
100 snappendf(buf
, cnt
, " DC");
101 if (info
.pstate
== state
)
102 snappendf(buf
, cnt
, " *");
104 if (info
.ustate_ac
< -1)
105 snappendf(buf
, cnt
, " AC");
106 if (info
.ustate_dc
< -1)
107 snappendf(buf
, cnt
, " DC");
110 snappendf(buf
, cnt
, "\n");
117 nouveau_sysfs_pstate_set(struct device
*d
, struct device_attribute
*a
,
118 const char *buf
, size_t count
)
120 struct nouveau_sysfs
*sysfs
= nouveau_sysfs(drm_device(d
));
121 struct nvif_control_pstate_user_v0 args
= { .pwrsrc
= -EINVAL
};
125 if ((tmp
= strchr(buf
, '\n')))
128 if (!strncasecmp(buf
, "dc:", 3)) {
132 if (!strncasecmp(buf
, "ac:", 3)) {
137 if (!strcasecmp(buf
, "none"))
138 args
.ustate
= NVIF_CONTROL_PSTATE_USER_V0_STATE_UNKNOWN
;
140 if (!strcasecmp(buf
, "auto"))
141 args
.ustate
= NVIF_CONTROL_PSTATE_USER_V0_STATE_PERFMON
;
143 ret
= kstrtol(buf
, 16, &value
);
149 ret
= nvif_mthd(&sysfs
->ctrl
, NVIF_CONTROL_PSTATE_USER
,
150 &args
, sizeof(args
));
157 static DEVICE_ATTR(pstate
, S_IRUGO
| S_IWUSR
,
158 nouveau_sysfs_pstate_get
, nouveau_sysfs_pstate_set
);
161 nouveau_sysfs_fini(struct drm_device
*dev
)
163 struct nouveau_sysfs
*sysfs
= nouveau_sysfs(dev
);
164 struct nouveau_drm
*drm
= nouveau_drm(dev
);
165 struct nvif_device
*device
= &drm
->device
;
167 if (sysfs
&& sysfs
->ctrl
.priv
) {
168 device_remove_file(nvxx_device(device
)->dev
, &dev_attr_pstate
);
169 nvif_object_fini(&sysfs
->ctrl
);
177 nouveau_sysfs_init(struct drm_device
*dev
)
179 struct nouveau_drm
*drm
= nouveau_drm(dev
);
180 struct nvif_device
*device
= &drm
->device
;
181 struct nouveau_sysfs
*sysfs
;
187 sysfs
= drm
->sysfs
= kzalloc(sizeof(*sysfs
), GFP_KERNEL
);
191 ret
= nvif_object_init(&device
->object
, 0, NVIF_IOCTL_NEW_V0_CONTROL
,
192 NULL
, 0, &sysfs
->ctrl
);
194 device_create_file(nvxx_device(device
)->dev
, &dev_attr_pstate
);