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