aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/nouveau/nouveau_pm.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/nouveau/nouveau_pm.c')
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_pm.c259
1 files changed, 221 insertions, 38 deletions
diff --git a/drivers/gpu/drm/nouveau/nouveau_pm.c b/drivers/gpu/drm/nouveau/nouveau_pm.c
index a07f27447cf9..09b638435f8f 100644
--- a/drivers/gpu/drm/nouveau/nouveau_pm.c
+++ b/drivers/gpu/drm/nouveau/nouveau_pm.c
@@ -27,6 +27,9 @@
27#include "nouveau_drv.h" 27#include "nouveau_drv.h"
28#include "nouveau_pm.h" 28#include "nouveau_pm.h"
29 29
30#include <linux/hwmon.h>
31#include <linux/hwmon-sysfs.h>
32
30static int 33static int
31nouveau_pm_clock_set(struct drm_device *dev, u8 id, u32 khz) 34nouveau_pm_clock_set(struct drm_device *dev, u8 id, u32 khz)
32{ 35{
@@ -189,7 +192,7 @@ nouveau_pm_get_perflvl_info(struct device *d,
189static ssize_t 192static ssize_t
190nouveau_pm_get_perflvl(struct device *d, struct device_attribute *a, char *buf) 193nouveau_pm_get_perflvl(struct device *d, struct device_attribute *a, char *buf)
191{ 194{
192 struct drm_device *dev = pci_get_drvdata(to_pci_dev(d)); 195 struct drm_device *dev = pci_get_drvdata(to_pci_dev(d));
193 struct drm_nouveau_private *dev_priv = dev->dev_private; 196 struct drm_nouveau_private *dev_priv = dev->dev_private;
194 struct nouveau_pm_engine *pm = &dev_priv->engine.pm; 197 struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
195 struct nouveau_pm_level cur; 198 struct nouveau_pm_level cur;
@@ -215,7 +218,7 @@ static ssize_t
215nouveau_pm_set_perflvl(struct device *d, struct device_attribute *a, 218nouveau_pm_set_perflvl(struct device *d, struct device_attribute *a,
216 const char *buf, size_t count) 219 const char *buf, size_t count)
217{ 220{
218 struct drm_device *dev = pci_get_drvdata(to_pci_dev(d)); 221 struct drm_device *dev = pci_get_drvdata(to_pci_dev(d));
219 int ret; 222 int ret;
220 223
221 ret = nouveau_pm_profile_set(dev, buf); 224 ret = nouveau_pm_profile_set(dev, buf);
@@ -227,43 +230,14 @@ nouveau_pm_set_perflvl(struct device *d, struct device_attribute *a,
227DEVICE_ATTR(performance_level, S_IRUGO | S_IWUSR, 230DEVICE_ATTR(performance_level, S_IRUGO | S_IWUSR,
228 nouveau_pm_get_perflvl, nouveau_pm_set_perflvl); 231 nouveau_pm_get_perflvl, nouveau_pm_set_perflvl);
229 232
230int 233static int
231nouveau_pm_init(struct drm_device *dev) 234nouveau_sysfs_init(struct drm_device *dev)
232{ 235{
233 struct drm_nouveau_private *dev_priv = dev->dev_private; 236 struct drm_nouveau_private *dev_priv = dev->dev_private;
234 struct nouveau_pm_engine *pm = &dev_priv->engine.pm; 237 struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
235 struct device *d = &dev->pdev->dev; 238 struct device *d = &dev->pdev->dev;
236 char info[256];
237 int ret, i; 239 int ret, i;
238 240
239 nouveau_volt_init(dev);
240 nouveau_perf_init(dev);
241
242 NV_INFO(dev, "%d available performance level(s)\n", pm->nr_perflvl);
243 for (i = 0; i < pm->nr_perflvl; i++) {
244 nouveau_pm_perflvl_info(&pm->perflvl[i], info, sizeof(info));
245 NV_INFO(dev, "%d: %s", pm->perflvl[i].id, info);
246 }
247
248 /* determine current ("boot") performance level */
249 ret = nouveau_pm_perflvl_get(dev, &pm->boot);
250 if (ret == 0) {
251 pm->cur = &pm->boot;
252
253 nouveau_pm_perflvl_info(&pm->boot, info, sizeof(info));
254 NV_INFO(dev, "c: %s", info);
255 }
256
257 /* switch performance levels now if requested */
258 if (nouveau_perflvl != NULL) {
259 ret = nouveau_pm_profile_set(dev, nouveau_perflvl);
260 if (ret) {
261 NV_ERROR(dev, "error setting perflvl \"%s\": %d\n",
262 nouveau_perflvl, ret);
263 }
264 }
265
266 /* initialise sysfs */
267 ret = device_create_file(d, &dev_attr_performance_level); 241 ret = device_create_file(d, &dev_attr_performance_level);
268 if (ret) 242 if (ret)
269 return ret; 243 return ret;
@@ -290,17 +264,14 @@ nouveau_pm_init(struct drm_device *dev)
290 return 0; 264 return 0;
291} 265}
292 266
293void 267static void
294nouveau_pm_fini(struct drm_device *dev) 268nouveau_sysfs_fini(struct drm_device *dev)
295{ 269{
296 struct drm_nouveau_private *dev_priv = dev->dev_private; 270 struct drm_nouveau_private *dev_priv = dev->dev_private;
297 struct nouveau_pm_engine *pm = &dev_priv->engine.pm; 271 struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
298 struct device *d = &dev->pdev->dev; 272 struct device *d = &dev->pdev->dev;
299 int i; 273 int i;
300 274
301 if (pm->cur != &pm->boot)
302 nouveau_pm_perflvl_set(dev, &pm->boot);
303
304 device_remove_file(d, &dev_attr_performance_level); 275 device_remove_file(d, &dev_attr_performance_level);
305 for (i = 0; i < pm->nr_perflvl; i++) { 276 for (i = 0; i < pm->nr_perflvl; i++) {
306 struct nouveau_pm_level *pl = &pm->perflvl[i]; 277 struct nouveau_pm_level *pl = &pm->perflvl[i];
@@ -310,9 +281,221 @@ nouveau_pm_fini(struct drm_device *dev)
310 281
311 device_remove_file(d, &pl->dev_attr); 282 device_remove_file(d, &pl->dev_attr);
312 } 283 }
284}
285
286
287
288static ssize_t
289nouveau_hwmon_show_temp(struct device *d, struct device_attribute *a, char *buf)
290{
291 struct drm_device *dev = dev_get_drvdata(d);
292
293 return snprintf(buf, PAGE_SIZE, "%d\n", nouveau_temp_get(dev)*1000);
294}
295static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, nouveau_hwmon_show_temp,
296 NULL, 0);
297
298static ssize_t
299nouveau_hwmon_max_temp(struct device *d, struct device_attribute *a, char *buf)
300{
301 struct drm_device *dev = dev_get_drvdata(d);
302 struct drm_nouveau_private *dev_priv = dev->dev_private;
303 struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
304 struct nouveau_pm_threshold_temp *temp = &pm->threshold_temp;
305
306 return snprintf(buf, PAGE_SIZE, "%d\n", temp->down_clock*1000);
307}
308static ssize_t
309nouveau_hwmon_set_max_temp(struct device *d, struct device_attribute *a,
310 const char *buf, size_t count)
311{
312 struct drm_device *dev = dev_get_drvdata(d);
313 struct drm_nouveau_private *dev_priv = dev->dev_private;
314 struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
315 struct nouveau_pm_threshold_temp *temp = &pm->threshold_temp;
316 long value;
317
318 if (strict_strtoul(buf, 10, &value) == -EINVAL)
319 return count;
320
321 temp->down_clock = value/1000;
322
323 nouveau_temp_safety_checks(dev);
324
325 return count;
326}
327static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO | S_IWUSR, nouveau_hwmon_max_temp,
328 nouveau_hwmon_set_max_temp,
329 0);
330
331static ssize_t
332nouveau_hwmon_critical_temp(struct device *d, struct device_attribute *a,
333 char *buf)
334{
335 struct drm_device *dev = dev_get_drvdata(d);
336 struct drm_nouveau_private *dev_priv = dev->dev_private;
337 struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
338 struct nouveau_pm_threshold_temp *temp = &pm->threshold_temp;
339
340 return snprintf(buf, PAGE_SIZE, "%d\n", temp->critical*1000);
341}
342static ssize_t
343nouveau_hwmon_set_critical_temp(struct device *d, struct device_attribute *a,
344 const char *buf,
345 size_t count)
346{
347 struct drm_device *dev = dev_get_drvdata(d);
348 struct drm_nouveau_private *dev_priv = dev->dev_private;
349 struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
350 struct nouveau_pm_threshold_temp *temp = &pm->threshold_temp;
351 long value;
352
353 if (strict_strtoul(buf, 10, &value) == -EINVAL)
354 return count;
355
356 temp->critical = value/1000;
357
358 nouveau_temp_safety_checks(dev);
359
360 return count;
361}
362static SENSOR_DEVICE_ATTR(temp1_crit, S_IRUGO | S_IWUSR,
363 nouveau_hwmon_critical_temp,
364 nouveau_hwmon_set_critical_temp,
365 0);
366
367static ssize_t nouveau_hwmon_show_name(struct device *dev,
368 struct device_attribute *attr,
369 char *buf)
370{
371 return sprintf(buf, "nouveau\n");
372}
373static SENSOR_DEVICE_ATTR(name, S_IRUGO, nouveau_hwmon_show_name, NULL, 0);
374
375static ssize_t nouveau_hwmon_show_update_rate(struct device *dev,
376 struct device_attribute *attr,
377 char *buf)
378{
379 return sprintf(buf, "1000\n");
380}
381static SENSOR_DEVICE_ATTR(update_rate, S_IRUGO,
382 nouveau_hwmon_show_update_rate,
383 NULL, 0);
384
385static struct attribute *hwmon_attributes[] = {
386 &sensor_dev_attr_temp1_input.dev_attr.attr,
387 &sensor_dev_attr_temp1_max.dev_attr.attr,
388 &sensor_dev_attr_temp1_crit.dev_attr.attr,
389 &sensor_dev_attr_name.dev_attr.attr,
390 &sensor_dev_attr_update_rate.dev_attr.attr,
391 NULL
392};
393
394static const struct attribute_group hwmon_attrgroup = {
395 .attrs = hwmon_attributes,
396};
397
398static int
399nouveau_hwmon_init(struct drm_device *dev)
400{
401 struct drm_nouveau_private *dev_priv = dev->dev_private;
402 struct device *hwmon_dev;
403 int ret;
404
405 dev_priv->int_hwmon_dev = NULL;
406
407 hwmon_dev = hwmon_device_register(&dev->pdev->dev);
408 if (IS_ERR(hwmon_dev)) {
409 ret = PTR_ERR(hwmon_dev);
410 NV_ERROR(dev,
411 "Unable to register hwmon device: %d\n", ret);
412 return ret;
413 }
414 dev_set_drvdata(hwmon_dev, dev);
415 ret = sysfs_create_group(&hwmon_dev->kobj,
416 &hwmon_attrgroup);
417 if (ret) {
418 NV_ERROR(dev,
419 "Unable to create hwmon sysfs file: %d\n", ret);
420 hwmon_device_unregister(hwmon_dev);
421 return ret;
422 }
423
424 dev_priv->int_hwmon_dev = hwmon_dev;
425
426 return 0;
427}
428
429static void
430nouveau_hwmon_fini(struct drm_device *dev)
431{
432 struct drm_nouveau_private *dev_priv = dev->dev_private;
433
434 if (dev_priv->int_hwmon_dev) {
435 sysfs_remove_group(&dev_priv->int_hwmon_dev->kobj,
436 &hwmon_attrgroup);
437 hwmon_device_unregister(dev_priv->int_hwmon_dev);
438 }
439}
440
441
442int
443nouveau_pm_init(struct drm_device *dev)
444{
445 struct drm_nouveau_private *dev_priv = dev->dev_private;
446 struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
447 char info[256];
448 int ret, i;
449
450 nouveau_volt_init(dev);
451 nouveau_perf_init(dev);
452 nouveau_temp_init(dev);
453
454 NV_INFO(dev, "%d available performance level(s)\n", pm->nr_perflvl);
455 for (i = 0; i < pm->nr_perflvl; i++) {
456 nouveau_pm_perflvl_info(&pm->perflvl[i], info, sizeof(info));
457 NV_INFO(dev, "%d: %s", pm->perflvl[i].id, info);
458 }
459
460 /* determine current ("boot") performance level */
461 ret = nouveau_pm_perflvl_get(dev, &pm->boot);
462 if (ret == 0) {
463 pm->cur = &pm->boot;
464
465 nouveau_pm_perflvl_info(&pm->boot, info, sizeof(info));
466 NV_INFO(dev, "c: %s", info);
467 }
468
469 /* switch performance levels now if requested */
470 if (nouveau_perflvl != NULL) {
471 ret = nouveau_pm_profile_set(dev, nouveau_perflvl);
472 if (ret) {
473 NV_ERROR(dev, "error setting perflvl \"%s\": %d\n",
474 nouveau_perflvl, ret);
475 }
476 }
477
478 nouveau_sysfs_init(dev);
479 nouveau_hwmon_init(dev);
480
481 return 0;
482}
483
484void
485nouveau_pm_fini(struct drm_device *dev)
486{
487 struct drm_nouveau_private *dev_priv = dev->dev_private;
488 struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
489
490 if (pm->cur != &pm->boot)
491 nouveau_pm_perflvl_set(dev, &pm->boot);
313 492
314 nouveau_perf_fini(dev); 493 nouveau_perf_fini(dev);
315 nouveau_volt_fini(dev); 494 nouveau_volt_fini(dev);
495 nouveau_temp_fini(dev);
496
497 nouveau_hwmon_fini(dev);
498 nouveau_sysfs_fini(dev);
316} 499}
317 500
318void 501void