1 /*
2  * PowerNV system parameter code
3  *
4  * Copyright (C) 2013 IBM
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20 
21 #include <linux/kobject.h>
22 #include <linux/mutex.h>
23 #include <linux/slab.h>
24 #include <linux/of.h>
25 #include <linux/gfp.h>
26 #include <linux/stat.h>
27 #include <asm/opal.h>
28 
29 #define MAX_PARAM_DATA_LEN	64
30 
31 static DEFINE_MUTEX(opal_sysparam_mutex);
32 static struct kobject *sysparam_kobj;
33 static void *param_data_buf;
34 
35 struct param_attr {
36 	struct list_head list;
37 	u32 param_id;
38 	u32 param_size;
39 	struct kobj_attribute kobj_attr;
40 };
41 
42 static int opal_get_sys_param(u32 param_id, u32 length, void *buffer)
43 {
44 	struct opal_msg msg;
45 	int ret, token;
46 
47 	token = opal_async_get_token_interruptible();
48 	if (token < 0) {
49 		if (token != -ERESTARTSYS)
50 			pr_err("%s: Couldn't get the token, returning\n",
51 					__func__);
52 		ret = token;
53 		goto out;
54 	}
55 
56 	ret = opal_get_param(token, param_id, (u64)buffer, length);
57 	if (ret != OPAL_ASYNC_COMPLETION)
58 		goto out_token;
59 
60 	ret = opal_async_wait_response(token, &msg);
61 	if (ret) {
62 		pr_err("%s: Failed to wait for the async response, %d\n",
63 				__func__, ret);
64 		goto out_token;
65 	}
66 
67 	ret = be64_to_cpu(msg.params[1]);
68 
69 out_token:
70 	opal_async_release_token(token);
71 out:
72 	return ret;
73 }
74 
75 static int opal_set_sys_param(u32 param_id, u32 length, void *buffer)
76 {
77 	struct opal_msg msg;
78 	int ret, token;
79 
80 	token = opal_async_get_token_interruptible();
81 	if (token < 0) {
82 		if (token != -ERESTARTSYS)
83 			pr_err("%s: Couldn't get the token, returning\n",
84 					__func__);
85 		ret = token;
86 		goto out;
87 	}
88 
89 	ret = opal_set_param(token, param_id, (u64)buffer, length);
90 
91 	if (ret != OPAL_ASYNC_COMPLETION)
92 		goto out_token;
93 
94 	ret = opal_async_wait_response(token, &msg);
95 	if (ret) {
96 		pr_err("%s: Failed to wait for the async response, %d\n",
97 				__func__, ret);
98 		goto out_token;
99 	}
100 
101 	ret = be64_to_cpu(msg.params[1]);
102 
103 out_token:
104 	opal_async_release_token(token);
105 out:
106 	return ret;
107 }
108 
109 static ssize_t sys_param_show(struct kobject *kobj,
110 		struct kobj_attribute *kobj_attr, char *buf)
111 {
112 	struct param_attr *attr = container_of(kobj_attr, struct param_attr,
113 			kobj_attr);
114 	int ret;
115 
116 	mutex_lock(&opal_sysparam_mutex);
117 	ret = opal_get_sys_param(attr->param_id, attr->param_size,
118 			param_data_buf);
119 	if (ret)
120 		goto out;
121 
122 	memcpy(buf, param_data_buf, attr->param_size);
123 
124 	ret = attr->param_size;
125 out:
126 	mutex_unlock(&opal_sysparam_mutex);
127 	return ret;
128 }
129 
130 static ssize_t sys_param_store(struct kobject *kobj,
131 		struct kobj_attribute *kobj_attr, const char *buf, size_t count)
132 {
133 	struct param_attr *attr = container_of(kobj_attr, struct param_attr,
134 			kobj_attr);
135 	int ret;
136 
137 	mutex_lock(&opal_sysparam_mutex);
138 	memcpy(param_data_buf, buf, count);
139 	ret = opal_set_sys_param(attr->param_id, attr->param_size,
140 			param_data_buf);
141 	mutex_unlock(&opal_sysparam_mutex);
142 	if (!ret)
143 		ret = count;
144 	return ret;
145 }
146 
147 void __init opal_sys_param_init(void)
148 {
149 	struct device_node *sysparam;
150 	struct param_attr *attr;
151 	u32 *id, *size;
152 	int count, i;
153 	u8 *perm;
154 
155 	if (!opal_kobj) {
156 		pr_warn("SYSPARAM: opal kobject is not available\n");
157 		goto out;
158 	}
159 
160 	sysparam_kobj = kobject_create_and_add("sysparams", opal_kobj);
161 	if (!sysparam_kobj) {
162 		pr_err("SYSPARAM: Failed to create sysparam kobject\n");
163 		goto out;
164 	}
165 
166 	/* Allocate big enough buffer for any get/set transactions */
167 	param_data_buf = kzalloc(MAX_PARAM_DATA_LEN, GFP_KERNEL);
168 	if (!param_data_buf) {
169 		pr_err("SYSPARAM: Failed to allocate memory for param data "
170 				"buf\n");
171 		goto out_kobj_put;
172 	}
173 
174 	sysparam = of_find_node_by_path("/ibm,opal/sysparams");
175 	if (!sysparam) {
176 		pr_err("SYSPARAM: Opal sysparam node not found\n");
177 		goto out_param_buf;
178 	}
179 
180 	if (!of_device_is_compatible(sysparam, "ibm,opal-sysparams")) {
181 		pr_err("SYSPARAM: Opal sysparam node not compatible\n");
182 		goto out_node_put;
183 	}
184 
185 	/* Number of parameters exposed through DT */
186 	count = of_property_count_strings(sysparam, "param-name");
187 	if (count < 0) {
188 		pr_err("SYSPARAM: No string found of property param-name in "
189 				"the node %s\n", sysparam->name);
190 		goto out_node_put;
191 	}
192 
193 	id = kzalloc(sizeof(*id) * count, GFP_KERNEL);
194 	if (!id) {
195 		pr_err("SYSPARAM: Failed to allocate memory to read parameter "
196 				"id\n");
197 		goto out_node_put;
198 	}
199 
200 	size = kzalloc(sizeof(*size) * count, GFP_KERNEL);
201 	if (!size) {
202 		pr_err("SYSPARAM: Failed to allocate memory to read parameter "
203 				"size\n");
204 		goto out_free_id;
205 	}
206 
207 	perm = kzalloc(sizeof(*perm) * count, GFP_KERNEL);
208 	if (!perm) {
209 		pr_err("SYSPARAM: Failed to allocate memory to read supported "
210 				"action on the parameter");
211 		goto out_free_size;
212 	}
213 
214 	if (of_property_read_u32_array(sysparam, "param-id", id, count)) {
215 		pr_err("SYSPARAM: Missing property param-id in the DT\n");
216 		goto out_free_perm;
217 	}
218 
219 	if (of_property_read_u32_array(sysparam, "param-len", size, count)) {
220 		pr_err("SYSPARAM: Missing propery param-len in the DT\n");
221 		goto out_free_perm;
222 	}
223 
224 
225 	if (of_property_read_u8_array(sysparam, "param-perm", perm, count)) {
226 		pr_err("SYSPARAM: Missing propery param-perm in the DT\n");
227 		goto out_free_perm;
228 	}
229 
230 	attr = kzalloc(sizeof(*attr) * count, GFP_KERNEL);
231 	if (!attr) {
232 		pr_err("SYSPARAM: Failed to allocate memory for parameter "
233 				"attributes\n");
234 		goto out_free_perm;
235 	}
236 
237 	/* For each of the parameters, populate the parameter attributes */
238 	for (i = 0; i < count; i++) {
239 		sysfs_attr_init(&attr[i].kobj_attr.attr);
240 		attr[i].param_id = id[i];
241 		attr[i].param_size = size[i];
242 		if (of_property_read_string_index(sysparam, "param-name", i,
243 				&attr[i].kobj_attr.attr.name))
244 			continue;
245 
246 		/* If the parameter is read-only or read-write */
247 		switch (perm[i] & 3) {
248 		case OPAL_SYSPARAM_READ:
249 			attr[i].kobj_attr.attr.mode = S_IRUGO;
250 			break;
251 		case OPAL_SYSPARAM_WRITE:
252 			attr[i].kobj_attr.attr.mode = S_IWUGO;
253 			break;
254 		case OPAL_SYSPARAM_RW:
255 			attr[i].kobj_attr.attr.mode = S_IRUGO | S_IWUGO;
256 			break;
257 		default:
258 			break;
259 		}
260 
261 		attr[i].kobj_attr.show = sys_param_show;
262 		attr[i].kobj_attr.store = sys_param_store;
263 
264 		if (sysfs_create_file(sysparam_kobj, &attr[i].kobj_attr.attr)) {
265 			pr_err("SYSPARAM: Failed to create sysfs file %s\n",
266 					attr[i].kobj_attr.attr.name);
267 			goto out_free_attr;
268 		}
269 	}
270 
271 	kfree(perm);
272 	kfree(size);
273 	kfree(id);
274 	of_node_put(sysparam);
275 	return;
276 
277 out_free_attr:
278 	kfree(attr);
279 out_free_perm:
280 	kfree(perm);
281 out_free_size:
282 	kfree(size);
283 out_free_id:
284 	kfree(id);
285 out_node_put:
286 	of_node_put(sysparam);
287 out_param_buf:
288 	kfree(param_data_buf);
289 out_kobj_put:
290 	kobject_put(sysparam_kobj);
291 out:
292 	return;
293 }
294