nouveau_sysfs.c 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  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. #include "nouveau_sysfs.h"
  25. #include <core/object.h>
  26. #include <core/class.h>
  27. static inline struct drm_device *
  28. drm_device(struct device *d)
  29. {
  30. return pci_get_drvdata(to_pci_dev(d));
  31. }
  32. #define snappendf(p,r,f,a...) do { \
  33. snprintf(p, r, f, ##a); \
  34. r -= strlen(p); \
  35. p += strlen(p); \
  36. } while(0)
  37. static ssize_t
  38. nouveau_sysfs_pstate_get(struct device *d, struct device_attribute *a, char *b)
  39. {
  40. struct nouveau_sysfs *sysfs = nouveau_sysfs(drm_device(d));
  41. struct nv_control_pstate_info info;
  42. size_t cnt = PAGE_SIZE;
  43. char *buf = b;
  44. int ret, i;
  45. ret = nv_exec(sysfs->ctrl, NV_CONTROL_PSTATE_INFO, &info, sizeof(info));
  46. if (ret)
  47. return ret;
  48. for (i = 0; i < info.count + 1; i++) {
  49. const s32 state = i < info.count ? i :
  50. NV_CONTROL_PSTATE_ATTR_STATE_CURRENT;
  51. struct nv_control_pstate_attr attr = {
  52. .state = state,
  53. .index = 0,
  54. };
  55. ret = nv_exec(sysfs->ctrl, NV_CONTROL_PSTATE_ATTR,
  56. &attr, sizeof(attr));
  57. if (ret)
  58. return ret;
  59. if (i < info.count)
  60. snappendf(buf, cnt, "%02x:", attr.state);
  61. else
  62. snappendf(buf, cnt, "--:");
  63. attr.index = 0;
  64. do {
  65. attr.state = state;
  66. ret = nv_exec(sysfs->ctrl, NV_CONTROL_PSTATE_ATTR,
  67. &attr, sizeof(attr));
  68. if (ret)
  69. return ret;
  70. snappendf(buf, cnt, " %s %d", attr.name, attr.min);
  71. if (attr.min != attr.max)
  72. snappendf(buf, cnt, "-%d", attr.max);
  73. snappendf(buf, cnt, " %s", attr.unit);
  74. } while (attr.index);
  75. if ((state >= 0 && info.pstate == state) ||
  76. (state < 0 && info.ustate < 0))
  77. snappendf(buf, cnt, " *");
  78. snappendf(buf, cnt, "\n");
  79. }
  80. return strlen(b);
  81. }
  82. static ssize_t
  83. nouveau_sysfs_pstate_set(struct device *d, struct device_attribute *a,
  84. const char *buf, size_t count)
  85. {
  86. struct nouveau_sysfs *sysfs = nouveau_sysfs(drm_device(d));
  87. struct nv_control_pstate_user args;
  88. long value, ret;
  89. char *tmp;
  90. if ((tmp = strchr(buf, '\n')))
  91. *tmp = '\0';
  92. if (!strcasecmp(buf, "none"))
  93. args.state = NV_CONTROL_PSTATE_USER_STATE_UNKNOWN;
  94. else
  95. if (!strcasecmp(buf, "auto"))
  96. args.state = NV_CONTROL_PSTATE_USER_STATE_PERFMON;
  97. else {
  98. ret = kstrtol(buf, 16, &value);
  99. if (ret)
  100. return ret;
  101. args.state = value;
  102. }
  103. ret = nv_exec(sysfs->ctrl, NV_CONTROL_PSTATE_USER, &args, sizeof(args));
  104. if (ret < 0)
  105. return ret;
  106. return count;
  107. }
  108. static DEVICE_ATTR(pstate, S_IRUGO | S_IWUSR,
  109. nouveau_sysfs_pstate_get, nouveau_sysfs_pstate_set);
  110. void
  111. nouveau_sysfs_fini(struct drm_device *dev)
  112. {
  113. struct nouveau_sysfs *sysfs = nouveau_sysfs(dev);
  114. struct nouveau_drm *drm = nouveau_drm(dev);
  115. if (sysfs->ctrl) {
  116. device_remove_file(&dev->pdev->dev, &dev_attr_pstate);
  117. nouveau_object_del(nv_object(drm), NVDRM_DEVICE, NVDRM_CONTROL);
  118. }
  119. drm->sysfs = NULL;
  120. kfree(sysfs);
  121. }
  122. int
  123. nouveau_sysfs_init(struct drm_device *dev)
  124. {
  125. struct nouveau_drm *drm = nouveau_drm(dev);
  126. struct nouveau_sysfs *sysfs;
  127. int ret;
  128. sysfs = drm->sysfs = kzalloc(sizeof(*sysfs), GFP_KERNEL);
  129. if (!sysfs)
  130. return -ENOMEM;
  131. ret = nouveau_object_new(nv_object(drm), NVDRM_DEVICE, NVDRM_CONTROL,
  132. NV_CONTROL_CLASS, NULL, 0, &sysfs->ctrl);
  133. if (ret == 0)
  134. device_create_file(&dev->pdev->dev, &dev_attr_pstate);
  135. return 0;
  136. }