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