opal-sysparam.c 7.4 KB

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