opal-psr.c 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * PowerNV OPAL Power-Shift-Ratio interface
  4. *
  5. * Copyright 2017 IBM Corp.
  6. */
  7. #define pr_fmt(fmt) "opal-psr: " fmt
  8. #include <linux/of.h>
  9. #include <linux/kobject.h>
  10. #include <linux/slab.h>
  11. #include <asm/opal.h>
  12. static DEFINE_MUTEX(psr_mutex);
  13. static struct kobject *psr_kobj;
  14. static struct psr_attr {
  15. u32 handle;
  16. struct kobj_attribute attr;
  17. } *psr_attrs;
  18. static ssize_t psr_show(struct kobject *kobj, struct kobj_attribute *attr,
  19. char *buf)
  20. {
  21. struct psr_attr *psr_attr = container_of(attr, struct psr_attr, attr);
  22. struct opal_msg msg;
  23. int psr, ret, token;
  24. token = opal_async_get_token_interruptible();
  25. if (token < 0) {
  26. pr_devel("Failed to get token\n");
  27. return token;
  28. }
  29. ret = mutex_lock_interruptible(&psr_mutex);
  30. if (ret)
  31. goto out_token;
  32. ret = opal_get_power_shift_ratio(psr_attr->handle, token,
  33. (u32 *)__pa(&psr));
  34. switch (ret) {
  35. case OPAL_ASYNC_COMPLETION:
  36. ret = opal_async_wait_response(token, &msg);
  37. if (ret) {
  38. pr_devel("Failed to wait for the async response\n");
  39. ret = -EIO;
  40. goto out;
  41. }
  42. ret = opal_error_code(opal_get_async_rc(msg));
  43. if (!ret) {
  44. ret = sprintf(buf, "%u\n", be32_to_cpu(psr));
  45. if (ret < 0)
  46. ret = -EIO;
  47. }
  48. break;
  49. case OPAL_SUCCESS:
  50. ret = sprintf(buf, "%u\n", be32_to_cpu(psr));
  51. if (ret < 0)
  52. ret = -EIO;
  53. break;
  54. default:
  55. ret = opal_error_code(ret);
  56. }
  57. out:
  58. mutex_unlock(&psr_mutex);
  59. out_token:
  60. opal_async_release_token(token);
  61. return ret;
  62. }
  63. static ssize_t psr_store(struct kobject *kobj, struct kobj_attribute *attr,
  64. const char *buf, size_t count)
  65. {
  66. struct psr_attr *psr_attr = container_of(attr, struct psr_attr, attr);
  67. struct opal_msg msg;
  68. int psr, ret, token;
  69. ret = kstrtoint(buf, 0, &psr);
  70. if (ret)
  71. return ret;
  72. token = opal_async_get_token_interruptible();
  73. if (token < 0) {
  74. pr_devel("Failed to get token\n");
  75. return token;
  76. }
  77. ret = mutex_lock_interruptible(&psr_mutex);
  78. if (ret)
  79. goto out_token;
  80. ret = opal_set_power_shift_ratio(psr_attr->handle, token, psr);
  81. switch (ret) {
  82. case OPAL_ASYNC_COMPLETION:
  83. ret = opal_async_wait_response(token, &msg);
  84. if (ret) {
  85. pr_devel("Failed to wait for the async response\n");
  86. ret = -EIO;
  87. goto out;
  88. }
  89. ret = opal_error_code(opal_get_async_rc(msg));
  90. if (!ret)
  91. ret = count;
  92. break;
  93. case OPAL_SUCCESS:
  94. ret = count;
  95. break;
  96. default:
  97. ret = opal_error_code(ret);
  98. }
  99. out:
  100. mutex_unlock(&psr_mutex);
  101. out_token:
  102. opal_async_release_token(token);
  103. return ret;
  104. }
  105. void __init opal_psr_init(void)
  106. {
  107. struct device_node *psr, *node;
  108. int i = 0;
  109. psr = of_find_compatible_node(NULL, NULL,
  110. "ibm,opal-power-shift-ratio");
  111. if (!psr) {
  112. pr_devel("Power-shift-ratio node not found\n");
  113. return;
  114. }
  115. psr_attrs = kcalloc(of_get_child_count(psr), sizeof(*psr_attrs),
  116. GFP_KERNEL);
  117. if (!psr_attrs)
  118. goto out_put_psr;
  119. psr_kobj = kobject_create_and_add("psr", opal_kobj);
  120. if (!psr_kobj) {
  121. pr_warn("Failed to create psr kobject\n");
  122. goto out;
  123. }
  124. for_each_child_of_node(psr, node) {
  125. if (of_property_read_u32(node, "handle",
  126. &psr_attrs[i].handle))
  127. goto out_kobj;
  128. sysfs_attr_init(&psr_attrs[i].attr.attr);
  129. if (of_property_read_string(node, "label",
  130. &psr_attrs[i].attr.attr.name))
  131. goto out_kobj;
  132. psr_attrs[i].attr.attr.mode = 0664;
  133. psr_attrs[i].attr.show = psr_show;
  134. psr_attrs[i].attr.store = psr_store;
  135. if (sysfs_create_file(psr_kobj, &psr_attrs[i].attr.attr)) {
  136. pr_devel("Failed to create psr sysfs file %s\n",
  137. psr_attrs[i].attr.attr.name);
  138. goto out_kobj;
  139. }
  140. i++;
  141. }
  142. of_node_put(psr);
  143. return;
  144. out_kobj:
  145. of_node_put(node);
  146. kobject_put(psr_kobj);
  147. out:
  148. kfree(psr_attrs);
  149. out_put_psr:
  150. of_node_put(psr);
  151. }