xref: /openbmc/linux/arch/powerpc/platforms/powernv/opal-sensor-groups.c (revision 4f2c0a4acffbec01079c28f839422e64ddeff004)
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  
sensor_group_enable(u32 handle,bool enable)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  
sg_store(struct kobject * kobj,struct kobj_attribute * attr,const char * buf,size_t count)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  
add_attr(int handle,struct sg_attr * attr,int index)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  
add_attr_group(const __be32 * ops,int len,struct sensor_group * sg,u32 handle)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  
get_nr_attrs(const __be32 * ops,int len)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  
opal_sensor_groups_init(void)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