opal-sensor-groups.c 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * PowerNV OPAL Sensor-groups interface
  4. *
  5. * Copyright 2017 IBM Corp.
  6. */
  7. #define pr_fmt(fmt) "opal-sensor-groups: " 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(sg_mutex);
  13. static struct kobject *sg_kobj;
  14. struct sg_attr {
  15. u32 handle;
  16. struct kobj_attribute attr;
  17. };
  18. static struct sensor_group {
  19. char name[20];
  20. struct attribute_group sg;
  21. struct sg_attr *sgattrs;
  22. } *sgs;
  23. int sensor_group_enable(u32 handle, bool enable)
  24. {
  25. struct opal_msg msg;
  26. int token, ret;
  27. token = opal_async_get_token_interruptible();
  28. if (token < 0)
  29. return token;
  30. ret = opal_sensor_group_enable(handle, token, enable);
  31. if (ret == OPAL_ASYNC_COMPLETION) {
  32. ret = opal_async_wait_response(token, &msg);
  33. if (ret) {
  34. pr_devel("Failed to wait for the async response\n");
  35. ret = -EIO;
  36. goto out;
  37. }
  38. ret = opal_error_code(opal_get_async_rc(msg));
  39. } else {
  40. ret = opal_error_code(ret);
  41. }
  42. out:
  43. opal_async_release_token(token);
  44. return ret;
  45. }
  46. EXPORT_SYMBOL_GPL(sensor_group_enable);
  47. static ssize_t sg_store(struct kobject *kobj, struct kobj_attribute *attr,
  48. const char *buf, size_t count)
  49. {
  50. struct sg_attr *sattr = container_of(attr, struct sg_attr, attr);
  51. struct opal_msg msg;
  52. u32 data;
  53. int ret, token;
  54. ret = kstrtoint(buf, 0, &data);
  55. if (ret)
  56. return ret;
  57. if (data != 1)
  58. return -EINVAL;
  59. token = opal_async_get_token_interruptible();
  60. if (token < 0) {
  61. pr_devel("Failed to get token\n");
  62. return token;
  63. }
  64. ret = mutex_lock_interruptible(&sg_mutex);
  65. if (ret)
  66. goto out_token;
  67. ret = opal_sensor_group_clear(sattr->handle, token);
  68. switch (ret) {
  69. case OPAL_ASYNC_COMPLETION:
  70. ret = opal_async_wait_response(token, &msg);
  71. if (ret) {
  72. pr_devel("Failed to wait for the async response\n");
  73. ret = -EIO;
  74. goto out;
  75. }
  76. ret = opal_error_code(opal_get_async_rc(msg));
  77. if (!ret)
  78. ret = count;
  79. break;
  80. case OPAL_SUCCESS:
  81. ret = count;
  82. break;
  83. default:
  84. ret = opal_error_code(ret);
  85. }
  86. out:
  87. mutex_unlock(&sg_mutex);
  88. out_token:
  89. opal_async_release_token(token);
  90. return ret;
  91. }
  92. static struct sg_ops_info {
  93. int opal_no;
  94. const char *attr_name;
  95. ssize_t (*store)(struct kobject *kobj, struct kobj_attribute *attr,
  96. const char *buf, size_t count);
  97. } ops_info[] = {
  98. { OPAL_SENSOR_GROUP_CLEAR, "clear", sg_store },
  99. };
  100. static void add_attr(int handle, struct sg_attr *attr, int index)
  101. {
  102. attr->handle = handle;
  103. sysfs_attr_init(&attr->attr.attr);
  104. attr->attr.attr.name = ops_info[index].attr_name;
  105. attr->attr.attr.mode = 0220;
  106. attr->attr.store = ops_info[index].store;
  107. }
  108. static int __init add_attr_group(const __be32 *ops, int len, struct sensor_group *sg,
  109. u32 handle)
  110. {
  111. int i, j;
  112. int count = 0;
  113. for (i = 0; i < len; i++)
  114. for (j = 0; j < ARRAY_SIZE(ops_info); j++)
  115. if (be32_to_cpu(ops[i]) == ops_info[j].opal_no) {
  116. add_attr(handle, &sg->sgattrs[count], j);
  117. sg->sg.attrs[count] =
  118. &sg->sgattrs[count].attr.attr;
  119. count++;
  120. }
  121. return sysfs_create_group(sg_kobj, &sg->sg);
  122. }
  123. static int __init get_nr_attrs(const __be32 *ops, int len)
  124. {
  125. int i, j;
  126. int nr_attrs = 0;
  127. for (i = 0; i < len; i++)
  128. for (j = 0; j < ARRAY_SIZE(ops_info); j++)
  129. if (be32_to_cpu(ops[i]) == ops_info[j].opal_no)
  130. nr_attrs++;
  131. return nr_attrs;
  132. }
  133. void __init opal_sensor_groups_init(void)
  134. {
  135. struct device_node *sg, *node;
  136. int i = 0;
  137. sg = of_find_compatible_node(NULL, NULL, "ibm,opal-sensor-group");
  138. if (!sg) {
  139. pr_devel("Sensor groups node not found\n");
  140. return;
  141. }
  142. sgs = kcalloc(of_get_child_count(sg), sizeof(*sgs), GFP_KERNEL);
  143. if (!sgs)
  144. goto out_sg_put;
  145. sg_kobj = kobject_create_and_add("sensor_groups", opal_kobj);
  146. if (!sg_kobj) {
  147. pr_warn("Failed to create sensor group kobject\n");
  148. goto out_sgs;
  149. }
  150. for_each_child_of_node(sg, node) {
  151. const __be32 *ops;
  152. u32 sgid, len, nr_attrs, chipid;
  153. ops = of_get_property(node, "ops", &len);
  154. if (!ops)
  155. continue;
  156. nr_attrs = get_nr_attrs(ops, len);
  157. if (!nr_attrs)
  158. continue;
  159. sgs[i].sgattrs = kcalloc(nr_attrs, sizeof(*sgs[i].sgattrs),
  160. GFP_KERNEL);
  161. if (!sgs[i].sgattrs)
  162. goto out_sgs_sgattrs;
  163. sgs[i].sg.attrs = kcalloc(nr_attrs + 1,
  164. sizeof(*sgs[i].sg.attrs),
  165. GFP_KERNEL);
  166. if (!sgs[i].sg.attrs) {
  167. kfree(sgs[i].sgattrs);
  168. goto out_sgs_sgattrs;
  169. }
  170. if (of_property_read_u32(node, "sensor-group-id", &sgid)) {
  171. pr_warn("sensor-group-id property not found\n");
  172. goto out_sgs_sgattrs;
  173. }
  174. if (!of_property_read_u32(node, "ibm,chip-id", &chipid))
  175. sprintf(sgs[i].name, "%pOFn%d", node, chipid);
  176. else
  177. sprintf(sgs[i].name, "%pOFn", node);
  178. sgs[i].sg.name = sgs[i].name;
  179. if (add_attr_group(ops, len, &sgs[i], sgid)) {
  180. pr_warn("Failed to create sensor attribute group %s\n",
  181. sgs[i].sg.name);
  182. goto out_sgs_sgattrs;
  183. }
  184. i++;
  185. }
  186. of_node_put(sg);
  187. return;
  188. out_sgs_sgattrs:
  189. while (--i >= 0) {
  190. kfree(sgs[i].sgattrs);
  191. kfree(sgs[i].sg.attrs);
  192. }
  193. kobject_put(sg_kobj);
  194. of_node_put(node);
  195. out_sgs:
  196. kfree(sgs);
  197. out_sg_put:
  198. of_node_put(sg);
  199. }