1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * PowerNV system parameter code
5 * Copyright (C) 2013 IBM
8 #include <linux/kobject.h>
9 #include <linux/mutex.h>
10 #include <linux/slab.h>
12 #include <linux/gfp.h>
13 #include <linux/stat.h>
16 #define MAX_PARAM_DATA_LEN 64
18 static DEFINE_MUTEX(opal_sysparam_mutex
);
19 static struct kobject
*sysparam_kobj
;
20 static void *param_data_buf
;
23 struct list_head list
;
26 struct kobj_attribute kobj_attr
;
29 static ssize_t
opal_get_sys_param(u32 param_id
, u32 length
, void *buffer
)
35 token
= opal_async_get_token_interruptible();
37 if (token
!= -ERESTARTSYS
)
38 pr_err("%s: Couldn't get the token, returning\n",
44 ret
= opal_get_param(token
, param_id
, (u64
)buffer
, length
);
45 if (ret
!= OPAL_ASYNC_COMPLETION
) {
46 ret
= opal_error_code(ret
);
50 ret
= opal_async_wait_response(token
, &msg
);
52 pr_err("%s: Failed to wait for the async response, %zd\n",
57 ret
= opal_error_code(opal_get_async_rc(msg
));
60 opal_async_release_token(token
);
65 static int opal_set_sys_param(u32 param_id
, u32 length
, void *buffer
)
70 token
= opal_async_get_token_interruptible();
72 if (token
!= -ERESTARTSYS
)
73 pr_err("%s: Couldn't get the token, returning\n",
79 ret
= opal_set_param(token
, param_id
, (u64
)buffer
, length
);
81 if (ret
!= OPAL_ASYNC_COMPLETION
) {
82 ret
= opal_error_code(ret
);
86 ret
= opal_async_wait_response(token
, &msg
);
88 pr_err("%s: Failed to wait for the async response, %d\n",
93 ret
= opal_error_code(opal_get_async_rc(msg
));
96 opal_async_release_token(token
);
101 static ssize_t
sys_param_show(struct kobject
*kobj
,
102 struct kobj_attribute
*kobj_attr
, char *buf
)
104 struct param_attr
*attr
= container_of(kobj_attr
, struct param_attr
,
108 mutex_lock(&opal_sysparam_mutex
);
109 ret
= opal_get_sys_param(attr
->param_id
, attr
->param_size
,
114 memcpy(buf
, param_data_buf
, attr
->param_size
);
116 ret
= attr
->param_size
;
118 mutex_unlock(&opal_sysparam_mutex
);
122 static ssize_t
sys_param_store(struct kobject
*kobj
,
123 struct kobj_attribute
*kobj_attr
, const char *buf
, size_t count
)
125 struct param_attr
*attr
= container_of(kobj_attr
, struct param_attr
,
129 /* MAX_PARAM_DATA_LEN is sizeof(param_data_buf) */
130 if (count
> MAX_PARAM_DATA_LEN
)
131 count
= MAX_PARAM_DATA_LEN
;
133 mutex_lock(&opal_sysparam_mutex
);
134 memcpy(param_data_buf
, buf
, count
);
135 ret
= opal_set_sys_param(attr
->param_id
, attr
->param_size
,
137 mutex_unlock(&opal_sysparam_mutex
);
143 void __init
opal_sys_param_init(void)
145 struct device_node
*sysparam
;
146 struct param_attr
*attr
;
152 pr_warn("SYSPARAM: opal kobject is not available\n");
156 /* Some systems do not use sysparams; this is not an error */
157 sysparam
= of_find_node_by_path("/ibm,opal/sysparams");
161 if (!of_device_is_compatible(sysparam
, "ibm,opal-sysparams")) {
162 pr_err("SYSPARAM: Opal sysparam node not compatible\n");
166 sysparam_kobj
= kobject_create_and_add("sysparams", opal_kobj
);
167 if (!sysparam_kobj
) {
168 pr_err("SYSPARAM: Failed to create sysparam kobject\n");
172 /* Allocate big enough buffer for any get/set transactions */
173 param_data_buf
= kzalloc(MAX_PARAM_DATA_LEN
, GFP_KERNEL
);
174 if (!param_data_buf
) {
175 pr_err("SYSPARAM: Failed to allocate memory for param data "
180 /* Number of parameters exposed through DT */
181 count
= of_property_count_strings(sysparam
, "param-name");
183 pr_err("SYSPARAM: No string found of property param-name in "
184 "the node %pOFn\n", sysparam
);
188 id
= kcalloc(count
, sizeof(*id
), GFP_KERNEL
);
190 pr_err("SYSPARAM: Failed to allocate memory to read parameter "
195 size
= kcalloc(count
, sizeof(*size
), GFP_KERNEL
);
197 pr_err("SYSPARAM: Failed to allocate memory to read parameter "
202 perm
= kcalloc(count
, sizeof(*perm
), GFP_KERNEL
);
204 pr_err("SYSPARAM: Failed to allocate memory to read supported "
205 "action on the parameter");
209 if (of_property_read_u32_array(sysparam
, "param-id", id
, count
)) {
210 pr_err("SYSPARAM: Missing property param-id in the DT\n");
214 if (of_property_read_u32_array(sysparam
, "param-len", size
, count
)) {
215 pr_err("SYSPARAM: Missing property param-len in the DT\n");
220 if (of_property_read_u8_array(sysparam
, "param-perm", perm
, count
)) {
221 pr_err("SYSPARAM: Missing property param-perm in the DT\n");
225 attr
= kcalloc(count
, sizeof(*attr
), GFP_KERNEL
);
227 pr_err("SYSPARAM: Failed to allocate memory for parameter "
232 /* For each of the parameters, populate the parameter attributes */
233 for (i
= 0; i
< count
; i
++) {
234 if (size
[i
] > MAX_PARAM_DATA_LEN
) {
235 pr_warn("SYSPARAM: Not creating parameter %d as size "
236 "exceeds buffer length\n", i
);
240 sysfs_attr_init(&attr
[i
].kobj_attr
.attr
);
241 attr
[i
].param_id
= id
[i
];
242 attr
[i
].param_size
= size
[i
];
243 if (of_property_read_string_index(sysparam
, "param-name", i
,
244 &attr
[i
].kobj_attr
.attr
.name
))
247 /* If the parameter is read-only or read-write */
248 switch (perm
[i
] & 3) {
249 case OPAL_SYSPARAM_READ
:
250 attr
[i
].kobj_attr
.attr
.mode
= 0444;
252 case OPAL_SYSPARAM_WRITE
:
253 attr
[i
].kobj_attr
.attr
.mode
= 0200;
255 case OPAL_SYSPARAM_RW
:
256 attr
[i
].kobj_attr
.attr
.mode
= 0644;
262 attr
[i
].kobj_attr
.show
= sys_param_show
;
263 attr
[i
].kobj_attr
.store
= sys_param_store
;
265 if (sysfs_create_file(sysparam_kobj
, &attr
[i
].kobj_attr
.attr
)) {
266 pr_err("SYSPARAM: Failed to create sysfs file %s\n",
267 attr
[i
].kobj_attr
.attr
.name
);
275 of_node_put(sysparam
);
287 kfree(param_data_buf
);
289 kobject_put(sysparam_kobj
);
291 of_node_put(sysparam
);