opal-sysparam.c 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * PowerNV system parameter code
  4. *
  5. * Copyright (C) 2013 IBM
  6. */
  7. #include <linux/kobject.h>
  8. #include <linux/mutex.h>
  9. #include <linux/slab.h>
  10. #include <linux/of.h>
  11. #include <linux/gfp.h>
  12. #include <linux/stat.h>
  13. #include <asm/opal.h>
  14. #define MAX_PARAM_DATA_LEN 64
  15. static DEFINE_MUTEX(opal_sysparam_mutex);
  16. static struct kobject *sysparam_kobj;
  17. static void *param_data_buf;
  18. struct param_attr {
  19. struct list_head list;
  20. u32 param_id;
  21. u32 param_size;
  22. struct kobj_attribute kobj_attr;
  23. };
  24. static ssize_t opal_get_sys_param(u32 param_id, u32 length, void *buffer)
  25. {
  26. struct opal_msg msg;
  27. ssize_t ret;
  28. int token;
  29. token = opal_async_get_token_interruptible();
  30. if (token < 0) {
  31. if (token != -ERESTARTSYS)
  32. pr_err("%s: Couldn't get the token, returning\n",
  33. __func__);
  34. ret = token;
  35. goto out;
  36. }
  37. ret = opal_get_param(token, param_id, (u64)buffer, length);
  38. if (ret != OPAL_ASYNC_COMPLETION) {
  39. ret = opal_error_code(ret);
  40. goto out_token;
  41. }
  42. ret = opal_async_wait_response(token, &msg);
  43. if (ret) {
  44. pr_err("%s: Failed to wait for the async response, %zd\n",
  45. __func__, ret);
  46. goto out_token;
  47. }
  48. ret = opal_error_code(opal_get_async_rc(msg));
  49. out_token:
  50. opal_async_release_token(token);
  51. out:
  52. return ret;
  53. }
  54. static int opal_set_sys_param(u32 param_id, u32 length, void *buffer)
  55. {
  56. struct opal_msg msg;
  57. int ret, token;
  58. token = opal_async_get_token_interruptible();
  59. if (token < 0) {
  60. if (token != -ERESTARTSYS)
  61. pr_err("%s: Couldn't get the token, returning\n",
  62. __func__);
  63. ret = token;
  64. goto out;
  65. }
  66. ret = opal_set_param(token, param_id, (u64)buffer, length);
  67. if (ret != OPAL_ASYNC_COMPLETION) {
  68. ret = opal_error_code(ret);
  69. goto out_token;
  70. }
  71. ret = opal_async_wait_response(token, &msg);
  72. if (ret) {
  73. pr_err("%s: Failed to wait for the async response, %d\n",
  74. __func__, ret);
  75. goto out_token;
  76. }
  77. ret = opal_error_code(opal_get_async_rc(msg));
  78. out_token:
  79. opal_async_release_token(token);
  80. out:
  81. return ret;
  82. }
  83. static ssize_t sys_param_show(struct kobject *kobj,
  84. struct kobj_attribute *kobj_attr, char *buf)
  85. {
  86. struct param_attr *attr = container_of(kobj_attr, struct param_attr,
  87. kobj_attr);
  88. ssize_t ret;
  89. mutex_lock(&opal_sysparam_mutex);
  90. ret = opal_get_sys_param(attr->param_id, attr->param_size,
  91. param_data_buf);
  92. if (ret)
  93. goto out;
  94. memcpy(buf, param_data_buf, attr->param_size);
  95. ret = attr->param_size;
  96. out:
  97. mutex_unlock(&opal_sysparam_mutex);
  98. return ret;
  99. }
  100. static ssize_t sys_param_store(struct kobject *kobj,
  101. struct kobj_attribute *kobj_attr, const char *buf, size_t count)
  102. {
  103. struct param_attr *attr = container_of(kobj_attr, struct param_attr,
  104. kobj_attr);
  105. ssize_t ret;
  106. /* MAX_PARAM_DATA_LEN is sizeof(param_data_buf) */
  107. if (count > MAX_PARAM_DATA_LEN)
  108. count = MAX_PARAM_DATA_LEN;
  109. mutex_lock(&opal_sysparam_mutex);
  110. memcpy(param_data_buf, buf, count);
  111. ret = opal_set_sys_param(attr->param_id, attr->param_size,
  112. param_data_buf);
  113. mutex_unlock(&opal_sysparam_mutex);
  114. if (!ret)
  115. ret = count;
  116. return ret;
  117. }
  118. void __init opal_sys_param_init(void)
  119. {
  120. struct device_node *sysparam;
  121. struct param_attr *attr;
  122. u32 *id, *size;
  123. int count, i;
  124. u8 *perm;
  125. if (!opal_kobj) {
  126. pr_warn("SYSPARAM: opal kobject is not available\n");
  127. goto out;
  128. }
  129. /* Some systems do not use sysparams; this is not an error */
  130. sysparam = of_find_node_by_path("/ibm,opal/sysparams");
  131. if (!sysparam)
  132. goto out;
  133. if (!of_device_is_compatible(sysparam, "ibm,opal-sysparams")) {
  134. pr_err("SYSPARAM: Opal sysparam node not compatible\n");
  135. goto out_node_put;
  136. }
  137. sysparam_kobj = kobject_create_and_add("sysparams", opal_kobj);
  138. if (!sysparam_kobj) {
  139. pr_err("SYSPARAM: Failed to create sysparam kobject\n");
  140. goto out_node_put;
  141. }
  142. /* Allocate big enough buffer for any get/set transactions */
  143. param_data_buf = kzalloc(MAX_PARAM_DATA_LEN, GFP_KERNEL);
  144. if (!param_data_buf) {
  145. pr_err("SYSPARAM: Failed to allocate memory for param data "
  146. "buf\n");
  147. goto out_kobj_put;
  148. }
  149. /* Number of parameters exposed through DT */
  150. count = of_property_count_strings(sysparam, "param-name");
  151. if (count < 0) {
  152. pr_err("SYSPARAM: No string found of property param-name in "
  153. "the node %pOFn\n", sysparam);
  154. goto out_param_buf;
  155. }
  156. id = kcalloc(count, sizeof(*id), GFP_KERNEL);
  157. if (!id) {
  158. pr_err("SYSPARAM: Failed to allocate memory to read parameter "
  159. "id\n");
  160. goto out_param_buf;
  161. }
  162. size = kcalloc(count, sizeof(*size), GFP_KERNEL);
  163. if (!size) {
  164. pr_err("SYSPARAM: Failed to allocate memory to read parameter "
  165. "size\n");
  166. goto out_free_id;
  167. }
  168. perm = kcalloc(count, sizeof(*perm), GFP_KERNEL);
  169. if (!perm) {
  170. pr_err("SYSPARAM: Failed to allocate memory to read supported "
  171. "action on the parameter");
  172. goto out_free_size;
  173. }
  174. if (of_property_read_u32_array(sysparam, "param-id", id, count)) {
  175. pr_err("SYSPARAM: Missing property param-id in the DT\n");
  176. goto out_free_perm;
  177. }
  178. if (of_property_read_u32_array(sysparam, "param-len", size, count)) {
  179. pr_err("SYSPARAM: Missing property param-len in the DT\n");
  180. goto out_free_perm;
  181. }
  182. if (of_property_read_u8_array(sysparam, "param-perm", perm, count)) {
  183. pr_err("SYSPARAM: Missing property param-perm in the DT\n");
  184. goto out_free_perm;
  185. }
  186. attr = kcalloc(count, sizeof(*attr), GFP_KERNEL);
  187. if (!attr) {
  188. pr_err("SYSPARAM: Failed to allocate memory for parameter "
  189. "attributes\n");
  190. goto out_free_perm;
  191. }
  192. /* For each of the parameters, populate the parameter attributes */
  193. for (i = 0; i < count; i++) {
  194. if (size[i] > MAX_PARAM_DATA_LEN) {
  195. pr_warn("SYSPARAM: Not creating parameter %d as size "
  196. "exceeds buffer length\n", i);
  197. continue;
  198. }
  199. sysfs_attr_init(&attr[i].kobj_attr.attr);
  200. attr[i].param_id = id[i];
  201. attr[i].param_size = size[i];
  202. if (of_property_read_string_index(sysparam, "param-name", i,
  203. &attr[i].kobj_attr.attr.name))
  204. continue;
  205. /* If the parameter is read-only or read-write */
  206. switch (perm[i] & 3) {
  207. case OPAL_SYSPARAM_READ:
  208. attr[i].kobj_attr.attr.mode = 0444;
  209. break;
  210. case OPAL_SYSPARAM_WRITE:
  211. attr[i].kobj_attr.attr.mode = 0200;
  212. break;
  213. case OPAL_SYSPARAM_RW:
  214. attr[i].kobj_attr.attr.mode = 0644;
  215. break;
  216. default:
  217. break;
  218. }
  219. attr[i].kobj_attr.show = sys_param_show;
  220. attr[i].kobj_attr.store = sys_param_store;
  221. if (sysfs_create_file(sysparam_kobj, &attr[i].kobj_attr.attr)) {
  222. pr_err("SYSPARAM: Failed to create sysfs file %s\n",
  223. attr[i].kobj_attr.attr.name);
  224. goto out_free_attr;
  225. }
  226. }
  227. kfree(perm);
  228. kfree(size);
  229. kfree(id);
  230. of_node_put(sysparam);
  231. return;
  232. out_free_attr:
  233. kfree(attr);
  234. out_free_perm:
  235. kfree(perm);
  236. out_free_size:
  237. kfree(size);
  238. out_free_id:
  239. kfree(id);
  240. out_param_buf:
  241. kfree(param_data_buf);
  242. out_kobj_put:
  243. kobject_put(sysparam_kobj);
  244. out_node_put:
  245. of_node_put(sysparam);
  246. out:
  247. return;
  248. }