powerpc/cell: Fix cell iommu after it_page_shift changes
[linux/fpc-iii.git] / arch / powerpc / platforms / powernv / opal-sysparam.c
blob9d1acf22a099dfc1bf474f6244af11d1153742f6
1 /*
2 * PowerNV system parameter code
4 * Copyright (C) 2013 IBM
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.
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.
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
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>
29 #define MAX_PARAM_DATA_LEN 64
31 static DEFINE_MUTEX(opal_sysparam_mutex);
32 static struct kobject *sysparam_kobj;
33 static void *param_data_buf;
35 struct param_attr {
36 struct list_head list;
37 u32 param_id;
38 u32 param_size;
39 struct kobj_attribute kobj_attr;
42 static ssize_t opal_get_sys_param(u32 param_id, u32 length, void *buffer)
44 struct opal_msg msg;
45 ssize_t ret;
46 int token;
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;
57 ret = opal_get_param(token, param_id, (u64)buffer, length);
58 if (ret != OPAL_ASYNC_COMPLETION)
59 goto out_token;
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;
68 ret = be64_to_cpu(msg.params[1]);
70 out_token:
71 opal_async_release_token(token);
72 out:
73 return ret;
76 static int opal_set_sys_param(u32 param_id, u32 length, void *buffer)
78 struct opal_msg msg;
79 int ret, token;
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;
90 ret = opal_set_param(token, param_id, (u64)buffer, length);
92 if (ret != OPAL_ASYNC_COMPLETION)
93 goto out_token;
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;
102 ret = be64_to_cpu(msg.params[1]);
104 out_token:
105 opal_async_release_token(token);
106 out:
107 return ret;
110 static ssize_t sys_param_show(struct kobject *kobj,
111 struct kobj_attribute *kobj_attr, char *buf)
113 struct param_attr *attr = container_of(kobj_attr, struct param_attr,
114 kobj_attr);
115 ssize_t ret;
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;
123 memcpy(buf, param_data_buf, attr->param_size);
125 ret = attr->param_size;
126 out:
127 mutex_unlock(&opal_sysparam_mutex);
128 return ret;
131 static ssize_t sys_param_store(struct kobject *kobj,
132 struct kobj_attribute *kobj_attr, const char *buf, size_t count)
134 struct param_attr *attr = container_of(kobj_attr, struct param_attr,
135 kobj_attr);
136 ssize_t ret;
138 /* MAX_PARAM_DATA_LEN is sizeof(param_data_buf) */
139 if (count > MAX_PARAM_DATA_LEN)
140 count = MAX_PARAM_DATA_LEN;
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;
152 void __init opal_sys_param_init(void)
154 struct device_node *sysparam;
155 struct param_attr *attr;
156 u32 *id, *size;
157 int count, i;
158 u8 *perm;
160 if (!opal_kobj) {
161 pr_warn("SYSPARAM: opal kobject is not available\n");
162 goto out;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
272 attr[i].kobj_attr.show = sys_param_show;
273 attr[i].kobj_attr.store = sys_param_store;
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;
282 kfree(perm);
283 kfree(size);
284 kfree(id);
285 of_node_put(sysparam);
286 return;
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;