opal-sensor-groups.c 5.1 KB

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