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