0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/kobject.h>
0009 #include <linux/mutex.h>
0010 #include <linux/slab.h>
0011 #include <linux/of.h>
0012 #include <linux/gfp.h>
0013 #include <linux/stat.h>
0014 #include <asm/opal.h>
0015
0016 #define MAX_PARAM_DATA_LEN 64
0017
0018 static DEFINE_MUTEX(opal_sysparam_mutex);
0019 static struct kobject *sysparam_kobj;
0020 static void *param_data_buf;
0021
0022 struct param_attr {
0023 struct list_head list;
0024 u32 param_id;
0025 u32 param_size;
0026 struct kobj_attribute kobj_attr;
0027 };
0028
0029 static ssize_t opal_get_sys_param(u32 param_id, u32 length, void *buffer)
0030 {
0031 struct opal_msg msg;
0032 ssize_t ret;
0033 int token;
0034
0035 token = opal_async_get_token_interruptible();
0036 if (token < 0) {
0037 if (token != -ERESTARTSYS)
0038 pr_err("%s: Couldn't get the token, returning\n",
0039 __func__);
0040 ret = token;
0041 goto out;
0042 }
0043
0044 ret = opal_get_param(token, param_id, (u64)buffer, length);
0045 if (ret != OPAL_ASYNC_COMPLETION) {
0046 ret = opal_error_code(ret);
0047 goto out_token;
0048 }
0049
0050 ret = opal_async_wait_response(token, &msg);
0051 if (ret) {
0052 pr_err("%s: Failed to wait for the async response, %zd\n",
0053 __func__, ret);
0054 goto out_token;
0055 }
0056
0057 ret = opal_error_code(opal_get_async_rc(msg));
0058
0059 out_token:
0060 opal_async_release_token(token);
0061 out:
0062 return ret;
0063 }
0064
0065 static int opal_set_sys_param(u32 param_id, u32 length, void *buffer)
0066 {
0067 struct opal_msg msg;
0068 int ret, token;
0069
0070 token = opal_async_get_token_interruptible();
0071 if (token < 0) {
0072 if (token != -ERESTARTSYS)
0073 pr_err("%s: Couldn't get the token, returning\n",
0074 __func__);
0075 ret = token;
0076 goto out;
0077 }
0078
0079 ret = opal_set_param(token, param_id, (u64)buffer, length);
0080
0081 if (ret != OPAL_ASYNC_COMPLETION) {
0082 ret = opal_error_code(ret);
0083 goto out_token;
0084 }
0085
0086 ret = opal_async_wait_response(token, &msg);
0087 if (ret) {
0088 pr_err("%s: Failed to wait for the async response, %d\n",
0089 __func__, ret);
0090 goto out_token;
0091 }
0092
0093 ret = opal_error_code(opal_get_async_rc(msg));
0094
0095 out_token:
0096 opal_async_release_token(token);
0097 out:
0098 return ret;
0099 }
0100
0101 static ssize_t sys_param_show(struct kobject *kobj,
0102 struct kobj_attribute *kobj_attr, char *buf)
0103 {
0104 struct param_attr *attr = container_of(kobj_attr, struct param_attr,
0105 kobj_attr);
0106 ssize_t ret;
0107
0108 mutex_lock(&opal_sysparam_mutex);
0109 ret = opal_get_sys_param(attr->param_id, attr->param_size,
0110 param_data_buf);
0111 if (ret)
0112 goto out;
0113
0114 memcpy(buf, param_data_buf, attr->param_size);
0115
0116 ret = attr->param_size;
0117 out:
0118 mutex_unlock(&opal_sysparam_mutex);
0119 return ret;
0120 }
0121
0122 static ssize_t sys_param_store(struct kobject *kobj,
0123 struct kobj_attribute *kobj_attr, const char *buf, size_t count)
0124 {
0125 struct param_attr *attr = container_of(kobj_attr, struct param_attr,
0126 kobj_attr);
0127 ssize_t ret;
0128
0129
0130 if (count > MAX_PARAM_DATA_LEN)
0131 count = MAX_PARAM_DATA_LEN;
0132
0133 mutex_lock(&opal_sysparam_mutex);
0134 memcpy(param_data_buf, buf, count);
0135 ret = opal_set_sys_param(attr->param_id, attr->param_size,
0136 param_data_buf);
0137 mutex_unlock(&opal_sysparam_mutex);
0138 if (!ret)
0139 ret = count;
0140 return ret;
0141 }
0142
0143 void __init opal_sys_param_init(void)
0144 {
0145 struct device_node *sysparam;
0146 struct param_attr *attr;
0147 u32 *id, *size;
0148 int count, i;
0149 u8 *perm;
0150
0151 if (!opal_kobj) {
0152 pr_warn("SYSPARAM: opal kobject is not available\n");
0153 goto out;
0154 }
0155
0156
0157 sysparam = of_find_node_by_path("/ibm,opal/sysparams");
0158 if (!sysparam)
0159 goto out;
0160
0161 if (!of_device_is_compatible(sysparam, "ibm,opal-sysparams")) {
0162 pr_err("SYSPARAM: Opal sysparam node not compatible\n");
0163 goto out_node_put;
0164 }
0165
0166 sysparam_kobj = kobject_create_and_add("sysparams", opal_kobj);
0167 if (!sysparam_kobj) {
0168 pr_err("SYSPARAM: Failed to create sysparam kobject\n");
0169 goto out_node_put;
0170 }
0171
0172
0173 param_data_buf = kzalloc(MAX_PARAM_DATA_LEN, GFP_KERNEL);
0174 if (!param_data_buf) {
0175 pr_err("SYSPARAM: Failed to allocate memory for param data "
0176 "buf\n");
0177 goto out_kobj_put;
0178 }
0179
0180
0181 count = of_property_count_strings(sysparam, "param-name");
0182 if (count < 0) {
0183 pr_err("SYSPARAM: No string found of property param-name in "
0184 "the node %pOFn\n", sysparam);
0185 goto out_param_buf;
0186 }
0187
0188 id = kcalloc(count, sizeof(*id), GFP_KERNEL);
0189 if (!id) {
0190 pr_err("SYSPARAM: Failed to allocate memory to read parameter "
0191 "id\n");
0192 goto out_param_buf;
0193 }
0194
0195 size = kcalloc(count, sizeof(*size), GFP_KERNEL);
0196 if (!size) {
0197 pr_err("SYSPARAM: Failed to allocate memory to read parameter "
0198 "size\n");
0199 goto out_free_id;
0200 }
0201
0202 perm = kcalloc(count, sizeof(*perm), GFP_KERNEL);
0203 if (!perm) {
0204 pr_err("SYSPARAM: Failed to allocate memory to read supported "
0205 "action on the parameter");
0206 goto out_free_size;
0207 }
0208
0209 if (of_property_read_u32_array(sysparam, "param-id", id, count)) {
0210 pr_err("SYSPARAM: Missing property param-id in the DT\n");
0211 goto out_free_perm;
0212 }
0213
0214 if (of_property_read_u32_array(sysparam, "param-len", size, count)) {
0215 pr_err("SYSPARAM: Missing property param-len in the DT\n");
0216 goto out_free_perm;
0217 }
0218
0219
0220 if (of_property_read_u8_array(sysparam, "param-perm", perm, count)) {
0221 pr_err("SYSPARAM: Missing property param-perm in the DT\n");
0222 goto out_free_perm;
0223 }
0224
0225 attr = kcalloc(count, sizeof(*attr), GFP_KERNEL);
0226 if (!attr) {
0227 pr_err("SYSPARAM: Failed to allocate memory for parameter "
0228 "attributes\n");
0229 goto out_free_perm;
0230 }
0231
0232
0233 for (i = 0; i < count; i++) {
0234 if (size[i] > MAX_PARAM_DATA_LEN) {
0235 pr_warn("SYSPARAM: Not creating parameter %d as size "
0236 "exceeds buffer length\n", i);
0237 continue;
0238 }
0239
0240 sysfs_attr_init(&attr[i].kobj_attr.attr);
0241 attr[i].param_id = id[i];
0242 attr[i].param_size = size[i];
0243 if (of_property_read_string_index(sysparam, "param-name", i,
0244 &attr[i].kobj_attr.attr.name))
0245 continue;
0246
0247
0248 switch (perm[i] & 3) {
0249 case OPAL_SYSPARAM_READ:
0250 attr[i].kobj_attr.attr.mode = 0444;
0251 break;
0252 case OPAL_SYSPARAM_WRITE:
0253 attr[i].kobj_attr.attr.mode = 0200;
0254 break;
0255 case OPAL_SYSPARAM_RW:
0256 attr[i].kobj_attr.attr.mode = 0644;
0257 break;
0258 default:
0259 break;
0260 }
0261
0262 attr[i].kobj_attr.show = sys_param_show;
0263 attr[i].kobj_attr.store = sys_param_store;
0264
0265 if (sysfs_create_file(sysparam_kobj, &attr[i].kobj_attr.attr)) {
0266 pr_err("SYSPARAM: Failed to create sysfs file %s\n",
0267 attr[i].kobj_attr.attr.name);
0268 goto out_free_attr;
0269 }
0270 }
0271
0272 kfree(perm);
0273 kfree(size);
0274 kfree(id);
0275 of_node_put(sysparam);
0276 return;
0277
0278 out_free_attr:
0279 kfree(attr);
0280 out_free_perm:
0281 kfree(perm);
0282 out_free_size:
0283 kfree(size);
0284 out_free_id:
0285 kfree(id);
0286 out_param_buf:
0287 kfree(param_data_buf);
0288 out_kobj_put:
0289 kobject_put(sysparam_kobj);
0290 out_node_put:
0291 of_node_put(sysparam);
0292 out:
0293 return;
0294 }