Add the rt linux 4.1.3-rt3 as base
[kvmfornfv.git] / kernel / arch / powerpc / platforms / powernv / opal-sysparam.c
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 ssize_t opal_get_sys_param(u32 param_id, u32 length, void *buffer)
43 {
44         struct opal_msg msg;
45         ssize_t ret;
46         int token;
47
48         token = opal_async_get_token_interruptible();
49         if (token < 0) {
50                 if (token != -ERESTARTSYS)
51                         pr_err("%s: Couldn't get the token, returning\n",
52                                         __func__);
53                 ret = token;
54                 goto out;
55         }
56
57         ret = opal_get_param(token, param_id, (u64)buffer, length);
58         if (ret != OPAL_ASYNC_COMPLETION)
59                 goto out_token;
60
61         ret = opal_async_wait_response(token, &msg);
62         if (ret) {
63                 pr_err("%s: Failed to wait for the async response, %zd\n",
64                                 __func__, ret);
65                 goto out_token;
66         }
67
68         ret = be64_to_cpu(msg.params[1]);
69
70 out_token:
71         opal_async_release_token(token);
72 out:
73         return ret;
74 }
75
76 static int opal_set_sys_param(u32 param_id, u32 length, void *buffer)
77 {
78         struct opal_msg msg;
79         int ret, token;
80
81         token = opal_async_get_token_interruptible();
82         if (token < 0) {
83                 if (token != -ERESTARTSYS)
84                         pr_err("%s: Couldn't get the token, returning\n",
85                                         __func__);
86                 ret = token;
87                 goto out;
88         }
89
90         ret = opal_set_param(token, param_id, (u64)buffer, length);
91
92         if (ret != OPAL_ASYNC_COMPLETION)
93                 goto out_token;
94
95         ret = opal_async_wait_response(token, &msg);
96         if (ret) {
97                 pr_err("%s: Failed to wait for the async response, %d\n",
98                                 __func__, ret);
99                 goto out_token;
100         }
101
102         ret = be64_to_cpu(msg.params[1]);
103
104 out_token:
105         opal_async_release_token(token);
106 out:
107         return ret;
108 }
109
110 static ssize_t sys_param_show(struct kobject *kobj,
111                 struct kobj_attribute *kobj_attr, char *buf)
112 {
113         struct param_attr *attr = container_of(kobj_attr, struct param_attr,
114                         kobj_attr);
115         ssize_t ret;
116
117         mutex_lock(&opal_sysparam_mutex);
118         ret = opal_get_sys_param(attr->param_id, attr->param_size,
119                         param_data_buf);
120         if (ret)
121                 goto out;
122
123         memcpy(buf, param_data_buf, attr->param_size);
124
125         ret = attr->param_size;
126 out:
127         mutex_unlock(&opal_sysparam_mutex);
128         return ret;
129 }
130
131 static ssize_t sys_param_store(struct kobject *kobj,
132                 struct kobj_attribute *kobj_attr, const char *buf, size_t count)
133 {
134         struct param_attr *attr = container_of(kobj_attr, struct param_attr,
135                         kobj_attr);
136         ssize_t ret;
137
138         /* MAX_PARAM_DATA_LEN is sizeof(param_data_buf) */
139         if (count > MAX_PARAM_DATA_LEN)
140                 count = MAX_PARAM_DATA_LEN;
141
142         mutex_lock(&opal_sysparam_mutex);
143         memcpy(param_data_buf, buf, count);
144         ret = opal_set_sys_param(attr->param_id, attr->param_size,
145                         param_data_buf);
146         mutex_unlock(&opal_sysparam_mutex);
147         if (!ret)
148                 ret = count;
149         return ret;
150 }
151
152 void __init opal_sys_param_init(void)
153 {
154         struct device_node *sysparam;
155         struct param_attr *attr;
156         u32 *id, *size;
157         int count, i;
158         u8 *perm;
159
160         if (!opal_kobj) {
161                 pr_warn("SYSPARAM: opal kobject is not available\n");
162                 goto out;
163         }
164
165         sysparam_kobj = kobject_create_and_add("sysparams", opal_kobj);
166         if (!sysparam_kobj) {
167                 pr_err("SYSPARAM: Failed to create sysparam kobject\n");
168                 goto out;
169         }
170
171         /* Allocate big enough buffer for any get/set transactions */
172         param_data_buf = kzalloc(MAX_PARAM_DATA_LEN, GFP_KERNEL);
173         if (!param_data_buf) {
174                 pr_err("SYSPARAM: Failed to allocate memory for param data "
175                                 "buf\n");
176                 goto out_kobj_put;
177         }
178
179         sysparam = of_find_node_by_path("/ibm,opal/sysparams");
180         if (!sysparam) {
181                 pr_err("SYSPARAM: Opal sysparam node not found\n");
182                 goto out_param_buf;
183         }
184
185         if (!of_device_is_compatible(sysparam, "ibm,opal-sysparams")) {
186                 pr_err("SYSPARAM: Opal sysparam node not compatible\n");
187                 goto out_node_put;
188         }
189
190         /* Number of parameters exposed through DT */
191         count = of_property_count_strings(sysparam, "param-name");
192         if (count < 0) {
193                 pr_err("SYSPARAM: No string found of property param-name in "
194                                 "the node %s\n", sysparam->name);
195                 goto out_node_put;
196         }
197
198         id = kzalloc(sizeof(*id) * count, GFP_KERNEL);
199         if (!id) {
200                 pr_err("SYSPARAM: Failed to allocate memory to read parameter "
201                                 "id\n");
202                 goto out_node_put;
203         }
204
205         size = kzalloc(sizeof(*size) * count, GFP_KERNEL);
206         if (!size) {
207                 pr_err("SYSPARAM: Failed to allocate memory to read parameter "
208                                 "size\n");
209                 goto out_free_id;
210         }
211
212         perm = kzalloc(sizeof(*perm) * count, GFP_KERNEL);
213         if (!perm) {
214                 pr_err("SYSPARAM: Failed to allocate memory to read supported "
215                                 "action on the parameter");
216                 goto out_free_size;
217         }
218
219         if (of_property_read_u32_array(sysparam, "param-id", id, count)) {
220                 pr_err("SYSPARAM: Missing property param-id in the DT\n");
221                 goto out_free_perm;
222         }
223
224         if (of_property_read_u32_array(sysparam, "param-len", size, count)) {
225                 pr_err("SYSPARAM: Missing property param-len in the DT\n");
226                 goto out_free_perm;
227         }
228
229
230         if (of_property_read_u8_array(sysparam, "param-perm", perm, count)) {
231                 pr_err("SYSPARAM: Missing property param-perm in the DT\n");
232                 goto out_free_perm;
233         }
234
235         attr = kzalloc(sizeof(*attr) * count, GFP_KERNEL);
236         if (!attr) {
237                 pr_err("SYSPARAM: Failed to allocate memory for parameter "
238                                 "attributes\n");
239                 goto out_free_perm;
240         }
241
242         /* For each of the parameters, populate the parameter attributes */
243         for (i = 0; i < count; i++) {
244                 if (size[i] > MAX_PARAM_DATA_LEN) {
245                         pr_warn("SYSPARAM: Not creating parameter %d as size "
246                                 "exceeds buffer length\n", i);
247                         continue;
248                 }
249
250                 sysfs_attr_init(&attr[i].kobj_attr.attr);
251                 attr[i].param_id = id[i];
252                 attr[i].param_size = size[i];
253                 if (of_property_read_string_index(sysparam, "param-name", i,
254                                 &attr[i].kobj_attr.attr.name))
255                         continue;
256
257                 /* If the parameter is read-only or read-write */
258                 switch (perm[i] & 3) {
259                 case OPAL_SYSPARAM_READ:
260                         attr[i].kobj_attr.attr.mode = S_IRUGO;
261                         break;
262                 case OPAL_SYSPARAM_WRITE:
263                         attr[i].kobj_attr.attr.mode = S_IWUSR;
264                         break;
265                 case OPAL_SYSPARAM_RW:
266                         attr[i].kobj_attr.attr.mode = S_IRUGO | S_IWUSR;
267                         break;
268                 default:
269                         break;
270                 }
271
272                 attr[i].kobj_attr.show = sys_param_show;
273                 attr[i].kobj_attr.store = sys_param_store;
274
275                 if (sysfs_create_file(sysparam_kobj, &attr[i].kobj_attr.attr)) {
276                         pr_err("SYSPARAM: Failed to create sysfs file %s\n",
277                                         attr[i].kobj_attr.attr.name);
278                         goto out_free_attr;
279                 }
280         }
281
282         kfree(perm);
283         kfree(size);
284         kfree(id);
285         of_node_put(sysparam);
286         return;
287
288 out_free_attr:
289         kfree(attr);
290 out_free_perm:
291         kfree(perm);
292 out_free_size:
293         kfree(size);
294 out_free_id:
295         kfree(id);
296 out_node_put:
297         of_node_put(sysparam);
298 out_param_buf:
299         kfree(param_data_buf);
300 out_kobj_put:
301         kobject_put(sysparam_kobj);
302 out:
303         return;
304 }