Path: blob/master/arch/powerpc/platforms/powernv/opal-sensor-groups.c
26481 views
// SPDX-License-Identifier: GPL-2.0-or-later1/*2* PowerNV OPAL Sensor-groups interface3*4* Copyright 2017 IBM Corp.5*/67#define pr_fmt(fmt) "opal-sensor-groups: " fmt89#include <linux/of.h>10#include <linux/kobject.h>11#include <linux/slab.h>1213#include <asm/opal.h>1415static DEFINE_MUTEX(sg_mutex);1617static struct kobject *sg_kobj;1819struct sg_attr {20u32 handle;21struct kobj_attribute attr;22};2324static struct sensor_group {25char name[20];26struct attribute_group sg;27struct sg_attr *sgattrs;28} *sgs;2930int sensor_group_enable(u32 handle, bool enable)31{32struct opal_msg msg;33int token, ret;3435token = opal_async_get_token_interruptible();36if (token < 0)37return token;3839ret = opal_sensor_group_enable(handle, token, enable);40if (ret == OPAL_ASYNC_COMPLETION) {41ret = opal_async_wait_response(token, &msg);42if (ret) {43pr_devel("Failed to wait for the async response\n");44ret = -EIO;45goto out;46}47ret = opal_error_code(opal_get_async_rc(msg));48} else {49ret = opal_error_code(ret);50}5152out:53opal_async_release_token(token);54return ret;55}56EXPORT_SYMBOL_GPL(sensor_group_enable);5758static ssize_t sg_store(struct kobject *kobj, struct kobj_attribute *attr,59const char *buf, size_t count)60{61struct sg_attr *sattr = container_of(attr, struct sg_attr, attr);62struct opal_msg msg;63u32 data;64int ret, token;6566ret = kstrtoint(buf, 0, &data);67if (ret)68return ret;6970if (data != 1)71return -EINVAL;7273token = opal_async_get_token_interruptible();74if (token < 0) {75pr_devel("Failed to get token\n");76return token;77}7879ret = mutex_lock_interruptible(&sg_mutex);80if (ret)81goto out_token;8283ret = opal_sensor_group_clear(sattr->handle, token);84switch (ret) {85case OPAL_ASYNC_COMPLETION:86ret = opal_async_wait_response(token, &msg);87if (ret) {88pr_devel("Failed to wait for the async response\n");89ret = -EIO;90goto out;91}92ret = opal_error_code(opal_get_async_rc(msg));93if (!ret)94ret = count;95break;96case OPAL_SUCCESS:97ret = count;98break;99default:100ret = opal_error_code(ret);101}102103out:104mutex_unlock(&sg_mutex);105out_token:106opal_async_release_token(token);107return ret;108}109110static struct sg_ops_info {111int opal_no;112const char *attr_name;113ssize_t (*store)(struct kobject *kobj, struct kobj_attribute *attr,114const char *buf, size_t count);115} ops_info[] = {116{ OPAL_SENSOR_GROUP_CLEAR, "clear", sg_store },117};118119static void add_attr(int handle, struct sg_attr *attr, int index)120{121attr->handle = handle;122sysfs_attr_init(&attr->attr.attr);123attr->attr.attr.name = ops_info[index].attr_name;124attr->attr.attr.mode = 0220;125attr->attr.store = ops_info[index].store;126}127128static int __init add_attr_group(const __be32 *ops, int len, struct sensor_group *sg,129u32 handle)130{131int i, j;132int count = 0;133134for (i = 0; i < len; i++)135for (j = 0; j < ARRAY_SIZE(ops_info); j++)136if (be32_to_cpu(ops[i]) == ops_info[j].opal_no) {137add_attr(handle, &sg->sgattrs[count], j);138sg->sg.attrs[count] =139&sg->sgattrs[count].attr.attr;140count++;141}142143return sysfs_create_group(sg_kobj, &sg->sg);144}145146static int __init get_nr_attrs(const __be32 *ops, int len)147{148int i, j;149int nr_attrs = 0;150151for (i = 0; i < len; i++)152for (j = 0; j < ARRAY_SIZE(ops_info); j++)153if (be32_to_cpu(ops[i]) == ops_info[j].opal_no)154nr_attrs++;155156return nr_attrs;157}158159void __init opal_sensor_groups_init(void)160{161struct device_node *sg, *node;162int i = 0;163164sg = of_find_compatible_node(NULL, NULL, "ibm,opal-sensor-group");165if (!sg) {166pr_devel("Sensor groups node not found\n");167return;168}169170sgs = kcalloc(of_get_child_count(sg), sizeof(*sgs), GFP_KERNEL);171if (!sgs)172goto out_sg_put;173174sg_kobj = kobject_create_and_add("sensor_groups", opal_kobj);175if (!sg_kobj) {176pr_warn("Failed to create sensor group kobject\n");177goto out_sgs;178}179180for_each_child_of_node(sg, node) {181const __be32 *ops;182u32 sgid, len, nr_attrs, chipid;183184ops = of_get_property(node, "ops", &len);185if (!ops)186continue;187188nr_attrs = get_nr_attrs(ops, len);189if (!nr_attrs)190continue;191192sgs[i].sgattrs = kcalloc(nr_attrs, sizeof(*sgs[i].sgattrs),193GFP_KERNEL);194if (!sgs[i].sgattrs)195goto out_sgs_sgattrs;196197sgs[i].sg.attrs = kcalloc(nr_attrs + 1,198sizeof(*sgs[i].sg.attrs),199GFP_KERNEL);200201if (!sgs[i].sg.attrs) {202kfree(sgs[i].sgattrs);203goto out_sgs_sgattrs;204}205206if (of_property_read_u32(node, "sensor-group-id", &sgid)) {207pr_warn("sensor-group-id property not found\n");208goto out_sgs_sgattrs;209}210211if (!of_property_read_u32(node, "ibm,chip-id", &chipid))212sprintf(sgs[i].name, "%pOFn%d", node, chipid);213else214sprintf(sgs[i].name, "%pOFn", node);215216sgs[i].sg.name = sgs[i].name;217if (add_attr_group(ops, len, &sgs[i], sgid)) {218pr_warn("Failed to create sensor attribute group %s\n",219sgs[i].sg.name);220goto out_sgs_sgattrs;221}222i++;223}224of_node_put(sg);225226return;227228out_sgs_sgattrs:229while (--i >= 0) {230kfree(sgs[i].sgattrs);231kfree(sgs[i].sg.attrs);232}233kobject_put(sg_kobj);234of_node_put(node);235out_sgs:236kfree(sgs);237out_sg_put:238of_node_put(sg);239}240241242