Linux Audio

Check our new training course

Open-source upstreaming

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