Path: blob/master/arch/powerpc/platforms/powernv/opal-sysparam.c
26481 views
// SPDX-License-Identifier: GPL-2.0-or-later1/*2* PowerNV system parameter code3*4* Copyright (C) 2013 IBM5*/67#include <linux/kobject.h>8#include <linux/mutex.h>9#include <linux/slab.h>10#include <linux/of.h>11#include <linux/gfp.h>12#include <linux/stat.h>13#include <asm/opal.h>1415#define MAX_PARAM_DATA_LEN 641617static DEFINE_MUTEX(opal_sysparam_mutex);18static struct kobject *sysparam_kobj;19static void *param_data_buf;2021struct param_attr {22struct list_head list;23u32 param_id;24u32 param_size;25struct kobj_attribute kobj_attr;26};2728static ssize_t opal_get_sys_param(u32 param_id, u32 length, void *buffer)29{30struct opal_msg msg;31ssize_t ret;32int token;3334token = opal_async_get_token_interruptible();35if (token < 0) {36if (token != -ERESTARTSYS)37pr_err("%s: Couldn't get the token, returning\n",38__func__);39ret = token;40goto out;41}4243ret = opal_get_param(token, param_id, (u64)buffer, length);44if (ret != OPAL_ASYNC_COMPLETION) {45ret = opal_error_code(ret);46goto out_token;47}4849ret = opal_async_wait_response(token, &msg);50if (ret) {51pr_err("%s: Failed to wait for the async response, %zd\n",52__func__, ret);53goto out_token;54}5556ret = opal_error_code(opal_get_async_rc(msg));5758out_token:59opal_async_release_token(token);60out:61return ret;62}6364static int opal_set_sys_param(u32 param_id, u32 length, void *buffer)65{66struct opal_msg msg;67int ret, token;6869token = opal_async_get_token_interruptible();70if (token < 0) {71if (token != -ERESTARTSYS)72pr_err("%s: Couldn't get the token, returning\n",73__func__);74ret = token;75goto out;76}7778ret = opal_set_param(token, param_id, (u64)buffer, length);7980if (ret != OPAL_ASYNC_COMPLETION) {81ret = opal_error_code(ret);82goto out_token;83}8485ret = opal_async_wait_response(token, &msg);86if (ret) {87pr_err("%s: Failed to wait for the async response, %d\n",88__func__, ret);89goto out_token;90}9192ret = opal_error_code(opal_get_async_rc(msg));9394out_token:95opal_async_release_token(token);96out:97return ret;98}99100static ssize_t sys_param_show(struct kobject *kobj,101struct kobj_attribute *kobj_attr, char *buf)102{103struct param_attr *attr = container_of(kobj_attr, struct param_attr,104kobj_attr);105ssize_t ret;106107mutex_lock(&opal_sysparam_mutex);108ret = opal_get_sys_param(attr->param_id, attr->param_size,109param_data_buf);110if (ret)111goto out;112113memcpy(buf, param_data_buf, attr->param_size);114115ret = attr->param_size;116out:117mutex_unlock(&opal_sysparam_mutex);118return ret;119}120121static ssize_t sys_param_store(struct kobject *kobj,122struct kobj_attribute *kobj_attr, const char *buf, size_t count)123{124struct param_attr *attr = container_of(kobj_attr, struct param_attr,125kobj_attr);126ssize_t ret;127128/* MAX_PARAM_DATA_LEN is sizeof(param_data_buf) */129if (count > MAX_PARAM_DATA_LEN)130count = MAX_PARAM_DATA_LEN;131132mutex_lock(&opal_sysparam_mutex);133memcpy(param_data_buf, buf, count);134ret = opal_set_sys_param(attr->param_id, attr->param_size,135param_data_buf);136mutex_unlock(&opal_sysparam_mutex);137if (!ret)138ret = count;139return ret;140}141142void __init opal_sys_param_init(void)143{144struct device_node *sysparam;145struct param_attr *attr;146u32 *id, *size;147int count, i;148u8 *perm;149150if (!opal_kobj) {151pr_warn("SYSPARAM: opal kobject is not available\n");152goto out;153}154155/* Some systems do not use sysparams; this is not an error */156sysparam = of_find_node_by_path("/ibm,opal/sysparams");157if (!sysparam)158goto out;159160if (!of_device_is_compatible(sysparam, "ibm,opal-sysparams")) {161pr_err("SYSPARAM: Opal sysparam node not compatible\n");162goto out_node_put;163}164165sysparam_kobj = kobject_create_and_add("sysparams", opal_kobj);166if (!sysparam_kobj) {167pr_err("SYSPARAM: Failed to create sysparam kobject\n");168goto out_node_put;169}170171/* Allocate big enough buffer for any get/set transactions */172param_data_buf = kzalloc(MAX_PARAM_DATA_LEN, GFP_KERNEL);173if (!param_data_buf) {174pr_err("SYSPARAM: Failed to allocate memory for param data "175"buf\n");176goto out_kobj_put;177}178179/* Number of parameters exposed through DT */180count = of_property_count_strings(sysparam, "param-name");181if (count < 0) {182pr_err("SYSPARAM: No string found of property param-name in "183"the node %pOFn\n", sysparam);184goto out_param_buf;185}186187id = kcalloc(count, sizeof(*id), GFP_KERNEL);188if (!id) {189pr_err("SYSPARAM: Failed to allocate memory to read parameter "190"id\n");191goto out_param_buf;192}193194size = kcalloc(count, sizeof(*size), GFP_KERNEL);195if (!size) {196pr_err("SYSPARAM: Failed to allocate memory to read parameter "197"size\n");198goto out_free_id;199}200201perm = kcalloc(count, sizeof(*perm), GFP_KERNEL);202if (!perm) {203pr_err("SYSPARAM: Failed to allocate memory to read supported "204"action on the parameter");205goto out_free_size;206}207208if (of_property_read_u32_array(sysparam, "param-id", id, count)) {209pr_err("SYSPARAM: Missing property param-id in the DT\n");210goto out_free_perm;211}212213if (of_property_read_u32_array(sysparam, "param-len", size, count)) {214pr_err("SYSPARAM: Missing property param-len in the DT\n");215goto out_free_perm;216}217218219if (of_property_read_u8_array(sysparam, "param-perm", perm, count)) {220pr_err("SYSPARAM: Missing property param-perm in the DT\n");221goto out_free_perm;222}223224attr = kcalloc(count, sizeof(*attr), GFP_KERNEL);225if (!attr) {226pr_err("SYSPARAM: Failed to allocate memory for parameter "227"attributes\n");228goto out_free_perm;229}230231/* For each of the parameters, populate the parameter attributes */232for (i = 0; i < count; i++) {233if (size[i] > MAX_PARAM_DATA_LEN) {234pr_warn("SYSPARAM: Not creating parameter %d as size "235"exceeds buffer length\n", i);236continue;237}238239sysfs_attr_init(&attr[i].kobj_attr.attr);240attr[i].param_id = id[i];241attr[i].param_size = size[i];242if (of_property_read_string_index(sysparam, "param-name", i,243&attr[i].kobj_attr.attr.name))244continue;245246/* If the parameter is read-only or read-write */247switch (perm[i] & 3) {248case OPAL_SYSPARAM_READ:249attr[i].kobj_attr.attr.mode = 0444;250break;251case OPAL_SYSPARAM_WRITE:252attr[i].kobj_attr.attr.mode = 0200;253break;254case OPAL_SYSPARAM_RW:255attr[i].kobj_attr.attr.mode = 0644;256break;257default:258break;259}260261attr[i].kobj_attr.show = sys_param_show;262attr[i].kobj_attr.store = sys_param_store;263264if (sysfs_create_file(sysparam_kobj, &attr[i].kobj_attr.attr)) {265pr_err("SYSPARAM: Failed to create sysfs file %s\n",266attr[i].kobj_attr.attr.name);267goto out_free_attr;268}269}270271kfree(perm);272kfree(size);273kfree(id);274of_node_put(sysparam);275return;276277out_free_attr:278kfree(attr);279out_free_perm:280kfree(perm);281out_free_size:282kfree(size);283out_free_id:284kfree(id);285out_param_buf:286kfree(param_data_buf);287out_kobj_put:288kobject_put(sysparam_kobj);289out_node_put:290of_node_put(sysparam);291out:292return;293}294295296