Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * PowerNV system parameter code
0004  *
0005  * Copyright (C) 2013 IBM
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         /* MAX_PARAM_DATA_LEN is sizeof(param_data_buf) */
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     /* Some systems do not use sysparams; this is not an error */
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     /* Allocate big enough buffer for any get/set transactions */
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     /* Number of parameters exposed through DT */
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     /* For each of the parameters, populate the parameter attributes */
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         /* If the parameter is read-only or read-write */
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 }