diff options
-rw-r--r-- | drivers/gpu/drm/nouveau/Makefile | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_drm.c | 3 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_drm.h | 10 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_sysfs.c | 162 | ||||
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_sysfs.h | 19 |
5 files changed, 191 insertions, 5 deletions
diff --git a/drivers/gpu/drm/nouveau/Makefile b/drivers/gpu/drm/nouveau/Makefile index e61dcbe09f08..64b4691b294a 100644 --- a/drivers/gpu/drm/nouveau/Makefile +++ b/drivers/gpu/drm/nouveau/Makefile | |||
@@ -300,7 +300,7 @@ include $(src)/dispnv04/Makefile | |||
300 | nouveau-y += nv50_display.o | 300 | nouveau-y += nv50_display.o |
301 | 301 | ||
302 | # drm/pm | 302 | # drm/pm |
303 | nouveau-y += nouveau_hwmon.o | 303 | nouveau-y += nouveau_hwmon.o nouveau_sysfs.o |
304 | 304 | ||
305 | # other random bits | 305 | # other random bits |
306 | nouveau-$(CONFIG_COMPAT) += nouveau_ioc32.o | 306 | nouveau-$(CONFIG_COMPAT) += nouveau_ioc32.o |
diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c index 9b3231459c7d..2418b0de589e 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.c +++ b/drivers/gpu/drm/nouveau/nouveau_drm.c | |||
@@ -46,6 +46,7 @@ | |||
46 | #include "nouveau_gem.h" | 46 | #include "nouveau_gem.h" |
47 | #include "nouveau_agp.h" | 47 | #include "nouveau_agp.h" |
48 | #include "nouveau_vga.h" | 48 | #include "nouveau_vga.h" |
49 | #include "nouveau_sysfs.h" | ||
49 | #include "nouveau_hwmon.h" | 50 | #include "nouveau_hwmon.h" |
50 | #include "nouveau_acpi.h" | 51 | #include "nouveau_acpi.h" |
51 | #include "nouveau_bios.h" | 52 | #include "nouveau_bios.h" |
@@ -384,6 +385,7 @@ nouveau_drm_load(struct drm_device *dev, unsigned long flags) | |||
384 | goto fail_dispinit; | 385 | goto fail_dispinit; |
385 | } | 386 | } |
386 | 387 | ||
388 | nouveau_sysfs_init(dev); | ||
387 | nouveau_hwmon_init(dev); | 389 | nouveau_hwmon_init(dev); |
388 | nouveau_accel_init(drm); | 390 | nouveau_accel_init(drm); |
389 | nouveau_fbcon_init(dev); | 391 | nouveau_fbcon_init(dev); |
@@ -421,6 +423,7 @@ nouveau_drm_unload(struct drm_device *dev) | |||
421 | nouveau_fbcon_fini(dev); | 423 | nouveau_fbcon_fini(dev); |
422 | nouveau_accel_fini(drm); | 424 | nouveau_accel_fini(drm); |
423 | nouveau_hwmon_fini(dev); | 425 | nouveau_hwmon_fini(dev); |
426 | nouveau_sysfs_fini(dev); | ||
424 | 427 | ||
425 | if (dev->mode_config.num_crtc) | 428 | if (dev->mode_config.num_crtc) |
426 | nouveau_display_fini(dev); | 429 | nouveau_display_fini(dev); |
diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.h b/drivers/gpu/drm/nouveau/nouveau_drm.h index e6d6a6b0053f..71ed2dadae61 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.h +++ b/drivers/gpu/drm/nouveau/nouveau_drm.h | |||
@@ -51,10 +51,11 @@ struct nouveau_drm_tile { | |||
51 | }; | 51 | }; |
52 | 52 | ||
53 | enum nouveau_drm_handle { | 53 | enum nouveau_drm_handle { |
54 | NVDRM_CLIENT = 0xffffffff, | 54 | NVDRM_CLIENT = 0xffffffff, |
55 | NVDRM_DEVICE = 0xdddddddd, | 55 | NVDRM_DEVICE = 0xdddddddd, |
56 | NVDRM_PUSH = 0xbbbb0000, /* |= client chid */ | 56 | NVDRM_CONTROL = 0xdddddddc, |
57 | NVDRM_CHAN = 0xcccc0000, /* |= client chid */ | 57 | NVDRM_PUSH = 0xbbbb0000, /* |= client chid */ |
58 | NVDRM_CHAN = 0xcccc0000, /* |= client chid */ | ||
58 | }; | 59 | }; |
59 | 60 | ||
60 | struct nouveau_cli { | 61 | struct nouveau_cli { |
@@ -130,6 +131,7 @@ struct nouveau_drm { | |||
130 | 131 | ||
131 | /* power management */ | 132 | /* power management */ |
132 | struct nouveau_hwmon *hwmon; | 133 | struct nouveau_hwmon *hwmon; |
134 | struct nouveau_sysfs *sysfs; | ||
133 | 135 | ||
134 | /* display power reference */ | 136 | /* display power reference */ |
135 | bool have_disp_power_ref; | 137 | bool have_disp_power_ref; |
diff --git a/drivers/gpu/drm/nouveau/nouveau_sysfs.c b/drivers/gpu/drm/nouveau/nouveau_sysfs.c new file mode 100644 index 000000000000..89201a17ce75 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nouveau_sysfs.c | |||
@@ -0,0 +1,162 @@ | |||
1 | /* | ||
2 | * Copyright 2013 Red Hat Inc. | ||
3 | * | ||
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: | ||
10 | * | ||
11 | * The above copyright notice and this permission notice shall be included in | ||
12 | * all copies or substantial portions of the Software. | ||
13 | * | ||
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. | ||
21 | * | ||
22 | * Authors: Ben Skeggs <bskeggs@redhat.com> | ||
23 | */ | ||
24 | |||
25 | #include "nouveau_sysfs.h" | ||
26 | |||
27 | #include <core/object.h> | ||
28 | #include <core/class.h> | ||
29 | |||
30 | static inline struct drm_device * | ||
31 | drm_device(struct device *d) | ||
32 | { | ||
33 | return pci_get_drvdata(to_pci_dev(d)); | ||
34 | } | ||
35 | |||
36 | #define snappendf(p,r,f,a...) do { \ | ||
37 | snprintf(p, r, f, ##a); \ | ||
38 | r -= strlen(p); \ | ||
39 | p += strlen(p); \ | ||
40 | } while(0) | ||
41 | |||
42 | static ssize_t | ||
43 | nouveau_sysfs_pstate_get(struct device *d, struct device_attribute *a, char *b) | ||
44 | { | ||
45 | struct nouveau_sysfs *sysfs = nouveau_sysfs(drm_device(d)); | ||
46 | struct nv_control_pstate_info info; | ||
47 | size_t cnt = PAGE_SIZE; | ||
48 | char *buf = b; | ||
49 | int ret, i; | ||
50 | |||
51 | ret = nv_exec(sysfs->ctrl, NV_CONTROL_PSTATE_INFO, &info, sizeof(info)); | ||
52 | if (ret) | ||
53 | return ret; | ||
54 | |||
55 | for (i = 0; i < info.count + 1; i++) { | ||
56 | const s32 state = i < info.count ? i : | ||
57 | NV_CONTROL_PSTATE_ATTR_STATE_CURRENT; | ||
58 | struct nv_control_pstate_attr attr = { | ||
59 | .state = state, | ||
60 | .index = 0, | ||
61 | }; | ||
62 | |||
63 | ret = nv_exec(sysfs->ctrl, NV_CONTROL_PSTATE_ATTR, | ||
64 | &attr, sizeof(attr)); | ||
65 | if (ret) | ||
66 | return ret; | ||
67 | |||
68 | if (i < info.count) | ||
69 | snappendf(buf, cnt, "%02x:", attr.state); | ||
70 | else | ||
71 | snappendf(buf, cnt, "--:"); | ||
72 | |||
73 | attr.index = 0; | ||
74 | do { | ||
75 | attr.state = state; | ||
76 | ret = nv_exec(sysfs->ctrl, NV_CONTROL_PSTATE_ATTR, | ||
77 | &attr, sizeof(attr)); | ||
78 | if (ret) | ||
79 | return ret; | ||
80 | |||
81 | snappendf(buf, cnt, " %s %d", attr.name, attr.min); | ||
82 | if (attr.min != attr.max) | ||
83 | snappendf(buf, cnt, "-%d", attr.max); | ||
84 | snappendf(buf, cnt, " %s", attr.unit); | ||
85 | } while (attr.index); | ||
86 | |||
87 | if ((state >= 0 && info.pstate == state) || | ||
88 | (state < 0 && info.ustate < 0)) | ||
89 | snappendf(buf, cnt, " *"); | ||
90 | snappendf(buf, cnt, "\n"); | ||
91 | } | ||
92 | |||
93 | return strlen(b); | ||
94 | } | ||
95 | |||
96 | static ssize_t | ||
97 | nouveau_sysfs_pstate_set(struct device *d, struct device_attribute *a, | ||
98 | const char *buf, size_t count) | ||
99 | { | ||
100 | struct nouveau_sysfs *sysfs = nouveau_sysfs(drm_device(d)); | ||
101 | struct nv_control_pstate_user args; | ||
102 | long value, ret; | ||
103 | char *tmp; | ||
104 | |||
105 | if ((tmp = strchr(buf, '\n'))) | ||
106 | *tmp = '\0'; | ||
107 | |||
108 | if (!strcasecmp(buf, "none")) | ||
109 | args.state = NV_CONTROL_PSTATE_USER_STATE_UNKNOWN; | ||
110 | else | ||
111 | if (!strcasecmp(buf, "auto")) | ||
112 | args.state = NV_CONTROL_PSTATE_USER_STATE_PERFMON; | ||
113 | else { | ||
114 | ret = kstrtol(buf, 16, &value); | ||
115 | if (ret) | ||
116 | return ret; | ||
117 | args.state = value; | ||
118 | } | ||
119 | |||
120 | ret = nv_exec(sysfs->ctrl, NV_CONTROL_PSTATE_USER, &args, sizeof(args)); | ||
121 | if (ret < 0) | ||
122 | return ret; | ||
123 | |||
124 | return count; | ||
125 | } | ||
126 | |||
127 | static DEVICE_ATTR(pstate, S_IRUGO | S_IWUSR, | ||
128 | nouveau_sysfs_pstate_get, nouveau_sysfs_pstate_set); | ||
129 | |||
130 | void | ||
131 | nouveau_sysfs_fini(struct drm_device *dev) | ||
132 | { | ||
133 | struct nouveau_sysfs *sysfs = nouveau_sysfs(dev); | ||
134 | struct nouveau_drm *drm = nouveau_drm(dev); | ||
135 | |||
136 | if (sysfs->ctrl) { | ||
137 | device_remove_file(&dev->pdev->dev, &dev_attr_pstate); | ||
138 | nouveau_object_del(nv_object(drm), NVDRM_DEVICE, NVDRM_CONTROL); | ||
139 | } | ||
140 | |||
141 | drm->sysfs = NULL; | ||
142 | kfree(sysfs); | ||
143 | } | ||
144 | |||
145 | int | ||
146 | nouveau_sysfs_init(struct drm_device *dev) | ||
147 | { | ||
148 | struct nouveau_drm *drm = nouveau_drm(dev); | ||
149 | struct nouveau_sysfs *sysfs; | ||
150 | int ret; | ||
151 | |||
152 | sysfs = drm->sysfs = kzalloc(sizeof(*sysfs), GFP_KERNEL); | ||
153 | if (!sysfs) | ||
154 | return -ENOMEM; | ||
155 | |||
156 | ret = nouveau_object_new(nv_object(drm), NVDRM_DEVICE, NVDRM_CONTROL, | ||
157 | NV_CONTROL_CLASS, NULL, 0, &sysfs->ctrl); | ||
158 | if (ret == 0) | ||
159 | device_create_file(&dev->pdev->dev, &dev_attr_pstate); | ||
160 | |||
161 | return 0; | ||
162 | } | ||
diff --git a/drivers/gpu/drm/nouveau/nouveau_sysfs.h b/drivers/gpu/drm/nouveau/nouveau_sysfs.h new file mode 100644 index 000000000000..74b47f1e01ed --- /dev/null +++ b/drivers/gpu/drm/nouveau/nouveau_sysfs.h | |||
@@ -0,0 +1,19 @@ | |||
1 | #ifndef __NOUVEAU_SYSFS_H__ | ||
2 | #define __NOUVEAU_SYSFS_H__ | ||
3 | |||
4 | #include "nouveau_drm.h" | ||
5 | |||
6 | struct nouveau_sysfs { | ||
7 | struct nouveau_object *ctrl; | ||
8 | }; | ||
9 | |||
10 | static inline struct nouveau_sysfs * | ||
11 | nouveau_sysfs(struct drm_device *dev) | ||
12 | { | ||
13 | return nouveau_drm(dev)->sysfs; | ||
14 | } | ||
15 | |||
16 | int nouveau_sysfs_init(struct drm_device *); | ||
17 | void nouveau_sysfs_fini(struct drm_device *); | ||
18 | |||
19 | #endif | ||