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>
25 #include <linux/gfp.h>
26 #include <linux/stat.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;
36 struct list_head list;
39 struct kobj_attribute kobj_attr;
42 static int opal_get_sys_param(u32 param_id, u32 length, void *buffer)
47 token = opal_async_get_token_interruptible();
49 if (token != -ERESTARTSYS)
50 pr_err("%s: Couldn't get the token, returning\n",
56 ret = opal_get_param(token, param_id, (u64)buffer, length);
57 if (ret != OPAL_ASYNC_COMPLETION)
60 ret = opal_async_wait_response(token, &msg);
62 pr_err("%s: Failed to wait for the async response, %d\n",
70 opal_async_release_token(token);
75 static int opal_set_sys_param(u32 param_id, u32 length, void *buffer)
80 token = opal_async_get_token_interruptible();
82 if (token != -ERESTARTSYS)
83 pr_err("%s: Couldn't get the token, returning\n",
89 ret = opal_set_param(token, param_id, (u64)buffer, length);
91 if (ret != OPAL_ASYNC_COMPLETION)
94 ret = opal_async_wait_response(token, &msg);
96 pr_err("%s: Failed to wait for the async response, %d\n",
104 opal_async_release_token(token);
109 static ssize_t sys_param_show(struct kobject *kobj,
110 struct kobj_attribute *kobj_attr, char *buf)
112 struct param_attr *attr = container_of(kobj_attr, struct param_attr,
116 mutex_lock(&opal_sysparam_mutex);
117 ret = opal_get_sys_param(attr->param_id, attr->param_size,
122 memcpy(buf, param_data_buf, attr->param_size);
125 mutex_unlock(&opal_sysparam_mutex);
126 return ret ? ret : attr->param_size;
129 static ssize_t sys_param_store(struct kobject *kobj,
130 struct kobj_attribute *kobj_attr, const char *buf, size_t count)
132 struct param_attr *attr = container_of(kobj_attr, struct param_attr,
136 mutex_lock(&opal_sysparam_mutex);
137 memcpy(param_data_buf, buf, count);
138 ret = opal_set_sys_param(attr->param_id, attr->param_size,
140 mutex_unlock(&opal_sysparam_mutex);
141 return ret ? ret : count;
144 void __init opal_sys_param_init(void)
146 struct device_node *sysparam;
147 struct param_attr *attr;
153 pr_warn("SYSPARAM: opal kobject is not available\n");
157 sysparam_kobj = kobject_create_and_add("sysparams", opal_kobj);
158 if (!sysparam_kobj) {
159 pr_err("SYSPARAM: Failed to create sysparam kobject\n");
163 /* Allocate big enough buffer for any get/set transactions */
164 param_data_buf = kzalloc(MAX_PARAM_DATA_LEN, GFP_KERNEL);
165 if (!param_data_buf) {
166 pr_err("SYSPARAM: Failed to allocate memory for param data "
171 sysparam = of_find_node_by_path("/ibm,opal/sysparams");
173 pr_err("SYSPARAM: Opal sysparam node not found\n");
177 if (!of_device_is_compatible(sysparam, "ibm,opal-sysparams")) {
178 pr_err("SYSPARAM: Opal sysparam node not compatible\n");
182 /* Number of parameters exposed through DT */
183 count = of_property_count_strings(sysparam, "param-name");
185 pr_err("SYSPARAM: No string found of property param-name in "
186 "the node %s\n", sysparam->name);
190 id = kzalloc(sizeof(*id) * count, GFP_KERNEL);
192 pr_err("SYSPARAM: Failed to allocate memory to read parameter "
197 size = kzalloc(sizeof(*size) * count, GFP_KERNEL);
199 pr_err("SYSPARAM: Failed to allocate memory to read parameter "
204 perm = kzalloc(sizeof(*perm) * count, GFP_KERNEL);
206 pr_err("SYSPARAM: Failed to allocate memory to read supported "
207 "action on the parameter");
211 if (of_property_read_u32_array(sysparam, "param-id", id, count)) {
212 pr_err("SYSPARAM: Missing property param-id in the DT\n");
216 if (of_property_read_u32_array(sysparam, "param-len", size, count)) {
217 pr_err("SYSPARAM: Missing propery param-len in the DT\n");
222 if (of_property_read_u8_array(sysparam, "param-perm", perm, count)) {
223 pr_err("SYSPARAM: Missing propery param-perm in the DT\n");
227 attr = kzalloc(sizeof(*attr) * count, GFP_KERNEL);
229 pr_err("SYSPARAM: Failed to allocate memory for parameter "
234 /* For each of the parameters, populate the parameter attributes */
235 for (i = 0; i < count; i++) {
236 sysfs_attr_init(&attr[i].kobj_attr.attr);
237 attr[i].param_id = id[i];
238 attr[i].param_size = size[i];
239 if (of_property_read_string_index(sysparam, "param-name", i,
240 &attr[i].kobj_attr.attr.name))
243 /* If the parameter is read-only or read-write */
244 switch (perm[i] & 3) {
245 case OPAL_SYSPARAM_READ:
246 attr[i].kobj_attr.attr.mode = S_IRUGO;
248 case OPAL_SYSPARAM_WRITE:
249 attr[i].kobj_attr.attr.mode = S_IWUGO;
251 case OPAL_SYSPARAM_RW:
252 attr[i].kobj_attr.attr.mode = S_IRUGO | S_IWUGO;
258 attr[i].kobj_attr.show = sys_param_show;
259 attr[i].kobj_attr.store = sys_param_store;
261 if (sysfs_create_file(sysparam_kobj, &attr[i].kobj_attr.attr)) {
262 pr_err("SYSPARAM: Failed to create sysfs file %s\n",
263 attr[i].kobj_attr.attr.name);
271 of_node_put(sysparam);
283 of_node_put(sysparam);
285 kfree(param_data_buf);
287 kobject_put(sysparam_kobj);