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 ssize_t
opal_get_sys_param(u32 param_id
, u32 length
, void *buffer
)
48 token
= opal_async_get_token_interruptible();
50 if (token
!= -ERESTARTSYS
)
51 pr_err("%s: Couldn't get the token, returning\n",
57 ret
= opal_get_param(token
, param_id
, (u64
)buffer
, length
);
58 if (ret
!= OPAL_ASYNC_COMPLETION
) {
59 ret
= opal_error_code(ret
);
63 ret
= opal_async_wait_response(token
, &msg
);
65 pr_err("%s: Failed to wait for the async response, %zd\n",
70 ret
= opal_error_code(opal_get_async_rc(msg
));
73 opal_async_release_token(token
);
78 static int opal_set_sys_param(u32 param_id
, u32 length
, void *buffer
)
83 token
= opal_async_get_token_interruptible();
85 if (token
!= -ERESTARTSYS
)
86 pr_err("%s: Couldn't get the token, returning\n",
92 ret
= opal_set_param(token
, param_id
, (u64
)buffer
, length
);
94 if (ret
!= OPAL_ASYNC_COMPLETION
) {
95 ret
= opal_error_code(ret
);
99 ret
= opal_async_wait_response(token
, &msg
);
101 pr_err("%s: Failed to wait for the async response, %d\n",
106 ret
= opal_error_code(opal_get_async_rc(msg
));
109 opal_async_release_token(token
);
114 static ssize_t
sys_param_show(struct kobject
*kobj
,
115 struct kobj_attribute
*kobj_attr
, char *buf
)
117 struct param_attr
*attr
= container_of(kobj_attr
, struct param_attr
,
121 mutex_lock(&opal_sysparam_mutex
);
122 ret
= opal_get_sys_param(attr
->param_id
, attr
->param_size
,
127 memcpy(buf
, param_data_buf
, attr
->param_size
);
129 ret
= attr
->param_size
;
131 mutex_unlock(&opal_sysparam_mutex
);
135 static ssize_t
sys_param_store(struct kobject
*kobj
,
136 struct kobj_attribute
*kobj_attr
, const char *buf
, size_t count
)
138 struct param_attr
*attr
= container_of(kobj_attr
, struct param_attr
,
142 /* MAX_PARAM_DATA_LEN is sizeof(param_data_buf) */
143 if (count
> MAX_PARAM_DATA_LEN
)
144 count
= MAX_PARAM_DATA_LEN
;
146 mutex_lock(&opal_sysparam_mutex
);
147 memcpy(param_data_buf
, buf
, count
);
148 ret
= opal_set_sys_param(attr
->param_id
, attr
->param_size
,
150 mutex_unlock(&opal_sysparam_mutex
);
156 void __init
opal_sys_param_init(void)
158 struct device_node
*sysparam
;
159 struct param_attr
*attr
;
165 pr_warn("SYSPARAM: opal kobject is not available\n");
169 /* Some systems do not use sysparams; this is not an error */
170 sysparam
= of_find_node_by_path("/ibm,opal/sysparams");
174 if (!of_device_is_compatible(sysparam
, "ibm,opal-sysparams")) {
175 pr_err("SYSPARAM: Opal sysparam node not compatible\n");
179 sysparam_kobj
= kobject_create_and_add("sysparams", opal_kobj
);
180 if (!sysparam_kobj
) {
181 pr_err("SYSPARAM: Failed to create sysparam kobject\n");
185 /* Allocate big enough buffer for any get/set transactions */
186 param_data_buf
= kzalloc(MAX_PARAM_DATA_LEN
, GFP_KERNEL
);
187 if (!param_data_buf
) {
188 pr_err("SYSPARAM: Failed to allocate memory for param data "
193 /* Number of parameters exposed through DT */
194 count
= of_property_count_strings(sysparam
, "param-name");
196 pr_err("SYSPARAM: No string found of property param-name in "
197 "the node %s\n", sysparam
->name
);
201 id
= kzalloc(sizeof(*id
) * count
, GFP_KERNEL
);
203 pr_err("SYSPARAM: Failed to allocate memory to read parameter "
208 size
= kzalloc(sizeof(*size
) * count
, GFP_KERNEL
);
210 pr_err("SYSPARAM: Failed to allocate memory to read parameter "
215 perm
= kzalloc(sizeof(*perm
) * count
, GFP_KERNEL
);
217 pr_err("SYSPARAM: Failed to allocate memory to read supported "
218 "action on the parameter");
222 if (of_property_read_u32_array(sysparam
, "param-id", id
, count
)) {
223 pr_err("SYSPARAM: Missing property param-id in the DT\n");
227 if (of_property_read_u32_array(sysparam
, "param-len", size
, count
)) {
228 pr_err("SYSPARAM: Missing property param-len in the DT\n");
233 if (of_property_read_u8_array(sysparam
, "param-perm", perm
, count
)) {
234 pr_err("SYSPARAM: Missing property param-perm in the DT\n");
238 attr
= kzalloc(sizeof(*attr
) * count
, GFP_KERNEL
);
240 pr_err("SYSPARAM: Failed to allocate memory for parameter "
245 /* For each of the parameters, populate the parameter attributes */
246 for (i
= 0; i
< count
; i
++) {
247 if (size
[i
] > MAX_PARAM_DATA_LEN
) {
248 pr_warn("SYSPARAM: Not creating parameter %d as size "
249 "exceeds buffer length\n", i
);
253 sysfs_attr_init(&attr
[i
].kobj_attr
.attr
);
254 attr
[i
].param_id
= id
[i
];
255 attr
[i
].param_size
= size
[i
];
256 if (of_property_read_string_index(sysparam
, "param-name", i
,
257 &attr
[i
].kobj_attr
.attr
.name
))
260 /* If the parameter is read-only or read-write */
261 switch (perm
[i
] & 3) {
262 case OPAL_SYSPARAM_READ
:
263 attr
[i
].kobj_attr
.attr
.mode
= 0444;
265 case OPAL_SYSPARAM_WRITE
:
266 attr
[i
].kobj_attr
.attr
.mode
= 0200;
268 case OPAL_SYSPARAM_RW
:
269 attr
[i
].kobj_attr
.attr
.mode
= 0644;
275 attr
[i
].kobj_attr
.show
= sys_param_show
;
276 attr
[i
].kobj_attr
.store
= sys_param_store
;
278 if (sysfs_create_file(sysparam_kobj
, &attr
[i
].kobj_attr
.attr
)) {
279 pr_err("SYSPARAM: Failed to create sysfs file %s\n",
280 attr
[i
].kobj_attr
.attr
.name
);
288 of_node_put(sysparam
);
300 kfree(param_data_buf
);
302 kobject_put(sysparam_kobj
);
304 of_node_put(sysparam
);