ctrl.c 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  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 "ctrl.h"
  25. #include <core/client.h>
  26. #include <subdev/clk.h>
  27. #include <nvif/class.h>
  28. #include <nvif/ioctl.h>
  29. #include <nvif/unpack.h>
  30. static int
  31. nvkm_control_mthd_pstate_info(struct nvkm_control *ctrl, void *data, u32 size)
  32. {
  33. union {
  34. struct nvif_control_pstate_info_v0 v0;
  35. } *args = data;
  36. struct nvkm_clk *clk = ctrl->device->clk;
  37. int ret;
  38. nvif_ioctl(&ctrl->object, "control pstate info size %d\n", size);
  39. if (nvif_unpack(args->v0, 0, 0, false)) {
  40. nvif_ioctl(&ctrl->object, "control pstate info vers %d\n",
  41. args->v0.version);
  42. } else
  43. return ret;
  44. if (clk) {
  45. args->v0.count = clk->state_nr;
  46. args->v0.ustate_ac = clk->ustate_ac;
  47. args->v0.ustate_dc = clk->ustate_dc;
  48. args->v0.pwrsrc = clk->pwrsrc;
  49. args->v0.pstate = clk->pstate;
  50. } else {
  51. args->v0.count = 0;
  52. args->v0.ustate_ac = NVIF_CONTROL_PSTATE_INFO_V0_USTATE_DISABLE;
  53. args->v0.ustate_dc = NVIF_CONTROL_PSTATE_INFO_V0_USTATE_DISABLE;
  54. args->v0.pwrsrc = -ENOSYS;
  55. args->v0.pstate = NVIF_CONTROL_PSTATE_INFO_V0_PSTATE_UNKNOWN;
  56. }
  57. return 0;
  58. }
  59. static int
  60. nvkm_control_mthd_pstate_attr(struct nvkm_control *ctrl, void *data, u32 size)
  61. {
  62. union {
  63. struct nvif_control_pstate_attr_v0 v0;
  64. } *args = data;
  65. struct nvkm_clk *clk = ctrl->device->clk;
  66. const struct nvkm_domain *domain;
  67. struct nvkm_pstate *pstate;
  68. struct nvkm_cstate *cstate;
  69. int i = 0, j = -1;
  70. u32 lo, hi;
  71. int ret;
  72. nvif_ioctl(&ctrl->object, "control pstate attr size %d\n", size);
  73. if (nvif_unpack(args->v0, 0, 0, false)) {
  74. nvif_ioctl(&ctrl->object,
  75. "control pstate attr vers %d state %d index %d\n",
  76. args->v0.version, args->v0.state, args->v0.index);
  77. if (!clk)
  78. return -ENODEV;
  79. if (args->v0.state < NVIF_CONTROL_PSTATE_ATTR_V0_STATE_CURRENT)
  80. return -EINVAL;
  81. if (args->v0.state >= clk->state_nr)
  82. return -EINVAL;
  83. } else
  84. return ret;
  85. domain = clk->domains;
  86. while (domain->name != nv_clk_src_max) {
  87. if (domain->mname && ++j == args->v0.index)
  88. break;
  89. domain++;
  90. }
  91. if (domain->name == nv_clk_src_max)
  92. return -EINVAL;
  93. if (args->v0.state != NVIF_CONTROL_PSTATE_ATTR_V0_STATE_CURRENT) {
  94. list_for_each_entry(pstate, &clk->states, head) {
  95. if (i++ == args->v0.state)
  96. break;
  97. }
  98. lo = pstate->base.domain[domain->name];
  99. hi = lo;
  100. list_for_each_entry(cstate, &pstate->list, head) {
  101. lo = min(lo, cstate->domain[domain->name]);
  102. hi = max(hi, cstate->domain[domain->name]);
  103. }
  104. args->v0.state = pstate->pstate;
  105. } else {
  106. lo = max(nvkm_clk_read(clk, domain->name), 0);
  107. hi = lo;
  108. }
  109. snprintf(args->v0.name, sizeof(args->v0.name), "%s", domain->mname);
  110. snprintf(args->v0.unit, sizeof(args->v0.unit), "MHz");
  111. args->v0.min = lo / domain->mdiv;
  112. args->v0.max = hi / domain->mdiv;
  113. args->v0.index = 0;
  114. while ((++domain)->name != nv_clk_src_max) {
  115. if (domain->mname) {
  116. args->v0.index = ++j;
  117. break;
  118. }
  119. }
  120. return 0;
  121. }
  122. static int
  123. nvkm_control_mthd_pstate_user(struct nvkm_control *ctrl, void *data, u32 size)
  124. {
  125. union {
  126. struct nvif_control_pstate_user_v0 v0;
  127. } *args = data;
  128. struct nvkm_clk *clk = ctrl->device->clk;
  129. int ret;
  130. nvif_ioctl(&ctrl->object, "control pstate user size %d\n", size);
  131. if (nvif_unpack(args->v0, 0, 0, false)) {
  132. nvif_ioctl(&ctrl->object,
  133. "control pstate user vers %d ustate %d pwrsrc %d\n",
  134. args->v0.version, args->v0.ustate, args->v0.pwrsrc);
  135. if (!clk)
  136. return -ENODEV;
  137. } else
  138. return ret;
  139. if (args->v0.pwrsrc >= 0) {
  140. ret |= nvkm_clk_ustate(clk, args->v0.ustate, args->v0.pwrsrc);
  141. } else {
  142. ret |= nvkm_clk_ustate(clk, args->v0.ustate, 0);
  143. ret |= nvkm_clk_ustate(clk, args->v0.ustate, 1);
  144. }
  145. return ret;
  146. }
  147. static int
  148. nvkm_control_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size)
  149. {
  150. struct nvkm_control *ctrl = nvkm_control(object);
  151. switch (mthd) {
  152. case NVIF_CONTROL_PSTATE_INFO:
  153. return nvkm_control_mthd_pstate_info(ctrl, data, size);
  154. case NVIF_CONTROL_PSTATE_ATTR:
  155. return nvkm_control_mthd_pstate_attr(ctrl, data, size);
  156. case NVIF_CONTROL_PSTATE_USER:
  157. return nvkm_control_mthd_pstate_user(ctrl, data, size);
  158. default:
  159. break;
  160. }
  161. return -EINVAL;
  162. }
  163. static const struct nvkm_object_func
  164. nvkm_control = {
  165. .mthd = nvkm_control_mthd,
  166. };
  167. static int
  168. nvkm_control_new(struct nvkm_device *device, const struct nvkm_oclass *oclass,
  169. void *data, u32 size, struct nvkm_object **pobject)
  170. {
  171. struct nvkm_control *ctrl;
  172. if (!(ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL)))
  173. return -ENOMEM;
  174. *pobject = &ctrl->object;
  175. ctrl->device = device;
  176. nvkm_object_ctor(&nvkm_control, oclass, &ctrl->object);
  177. return 0;
  178. }
  179. const struct nvkm_device_oclass
  180. nvkm_control_oclass = {
  181. .base.oclass = NVIF_IOCTL_NEW_V0_CONTROL,
  182. .base.minver = -1,
  183. .base.maxver = -1,
  184. .ctor = nvkm_control_new,
  185. };