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