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
35static ssize_t sg_store(struct kobject *kobj, struct kobj_attribute *attr,
36 const char *buf, size_t count)
37{
38 struct sg_attr *sattr = container_of(attr, struct sg_attr, attr);
39 struct opal_msg msg;
40 u32 data;
41 int ret, token;
42
43 ret = kstrtoint(buf, 0, &data);
44 if (ret)
45 return ret;
46
47 if (data != 1)
48 return -EINVAL;
49
50 token = opal_async_get_token_interruptible();
51 if (token < 0) {
52 pr_devel("Failed to get token\n");
53 return token;
54 }
55
56 ret = mutex_lock_interruptible(&sg_mutex);
57 if (ret)
58 goto out_token;
59
60 ret = opal_sensor_group_clear(sattr->handle, token);
61 switch (ret) {
62 case OPAL_ASYNC_COMPLETION:
63 ret = opal_async_wait_response(token, &msg);
64 if (ret) {
65 pr_devel("Failed to wait for the async response\n");
66 ret = -EIO;
67 goto out;
68 }
69 ret = opal_error_code(opal_get_async_rc(msg));
70 if (!ret)
71 ret = count;
72 break;
73 case OPAL_SUCCESS:
74 ret = count;
75 break;
76 default:
77 ret = opal_error_code(ret);
78 }
79
80out:
81 mutex_unlock(&sg_mutex);
82out_token:
83 opal_async_release_token(token);
84 return ret;
85}
86
87static struct sg_ops_info {
88 int opal_no;
89 const char *attr_name;
90 ssize_t (*store)(struct kobject *kobj, struct kobj_attribute *attr,
91 const char *buf, size_t count);
92} ops_info[] = {
93 { OPAL_SENSOR_GROUP_CLEAR, "clear", sg_store },
94};
95
96static void add_attr(int handle, struct sg_attr *attr, int index)
97{
98 attr->handle = handle;
99 sysfs_attr_init(&attr->attr.attr);
100 attr->attr.attr.name = ops_info[index].attr_name;
101 attr->attr.attr.mode = 0220;
102 attr->attr.store = ops_info[index].store;
103}
104
105static int add_attr_group(const __be32 *ops, int len, struct sensor_group *sg,
106 u32 handle)
107{
108 int i, j;
109 int count = 0;
110
111 for (i = 0; i < len; i++)
112 for (j = 0; j < ARRAY_SIZE(ops_info); j++)
113 if (be32_to_cpu(ops[i]) == ops_info[j].opal_no) {
114 add_attr(handle, &sg->sgattrs[count], j);
115 sg->sg.attrs[count] =
116 &sg->sgattrs[count].attr.attr;
117 count++;
118 }
119
120 return sysfs_create_group(sg_kobj, &sg->sg);
121}
122
123static int get_nr_attrs(const __be32 *ops, int len)
124{
125 int i, j;
126 int nr_attrs = 0;
127
128 for (i = 0; i < len; i++)
129 for (j = 0; j < ARRAY_SIZE(ops_info); j++)
130 if (be32_to_cpu(ops[i]) == ops_info[j].opal_no)
131 nr_attrs++;
132
133 return nr_attrs;
134}
135
136void __init opal_sensor_groups_init(void)
137{
138 struct device_node *sg, *node;
139 int i = 0;
140
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
147 sgs = kcalloc(of_get_child_count(sg), sizeof(*sgs), GFP_KERNEL);
148 if (!sgs)
149 return;
150
151 sg_kobj = kobject_create_and_add("sensor_groups", opal_kobj);
152 if (!sg_kobj) {
153 pr_warn("Failed to create sensor group kobject\n");
154 goto out_sgs;
155 }
156
157 for_each_child_of_node(sg, node) {
158 const __be32 *ops;
159 u32 sgid, len, nr_attrs, chipid;
160
161 ops = of_get_property(node, "ops", &len);
162 if (!ops)
163 continue;
164
165 nr_attrs = get_nr_attrs(ops, len);
166 if (!nr_attrs)
167 continue;
168
169 sgs[i].sgattrs = kcalloc(nr_attrs, sizeof(struct sg_attr),
170 GFP_KERNEL);
171 if (!sgs[i].sgattrs)
172 goto out_sgs_sgattrs;
173
174 sgs[i].sg.attrs = kcalloc(nr_attrs + 1,
175 sizeof(struct attribute *),
176 GFP_KERNEL);
177
178 if (!sgs[i].sg.attrs) {
179 kfree(sgs[i].sgattrs);
180 goto out_sgs_sgattrs;
181 }
182
183 if (of_property_read_u32(node, "sensor-group-id", &sgid)) {
184 pr_warn("sensor-group-id property not found\n");
185 goto out_sgs_sgattrs;
186 }
187
188 if (!of_property_read_u32(node, "ibm,chip-id", &chipid))
189 sprintf(sgs[i].name, "%s%d", node->name, chipid);
190 else
191 sprintf(sgs[i].name, "%s", node->name);
192
193 sgs[i].sg.name = sgs[i].name;
194 if (add_attr_group(ops, len, &sgs[i], sgid)) {
195 pr_warn("Failed to create sensor attribute group %s\n",
196 sgs[i].sg.name);
197 goto out_sgs_sgattrs;
198 }
199 i++;
200 }
201
202 return;
203
204out_sgs_sgattrs:
205 while (--i >= 0) {
206 kfree(sgs[i].sgattrs);
207 kfree(sgs[i].sg.attrs);
208 }
209 kobject_put(sg_kobj);
210out_sgs:
211 kfree(sgs);
212}
213