Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/arch/powerpc/platforms/powernv/opal-sensor-groups.c
26481 views
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
}
241
242