linux/arch/powerpc/platforms/powernv/opal-sensor-groups.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * PowerNV OPAL Sensor-groups interface
   4 *
   5 * Copyright 2017 IBM Corp.
   6 */
   7
   8#define pr_fmt(fmt)     "opal-sensor-groups: " fmt
   9
  10#include <linux/of.h>
  11#include <linux/kobject.h>
  12#include <linux/slab.h>
  13
  14#include <asm/opal.h>
  15
  16static DEFINE_MUTEX(sg_mutex);
  17
  18static struct kobject *sg_kobj;
  19
  20struct sg_attr {
  21        u32 handle;
  22        struct kobj_attribute attr;
  23};
  24
  25static struct sensor_group {
  26        char name[20];
  27        struct attribute_group sg;
  28        struct sg_attr *sgattrs;
  29} *sgs;
  30
  31int sensor_group_enable(u32 handle, bool enable)
  32{
  33        struct opal_msg msg;
  34        int token, ret;
  35
  36        token = opal_async_get_token_interruptible();
  37        if (token < 0)
  38                return token;
  39
  40        ret = opal_sensor_group_enable(handle, token, enable);
  41        if (ret == OPAL_ASYNC_COMPLETION) {
  42                ret = opal_async_wait_response(token, &msg);
  43                if (ret) {
  44                        pr_devel("Failed to wait for the async response\n");
  45                        ret = -EIO;
  46                        goto out;
  47                }
  48                ret = opal_error_code(opal_get_async_rc(msg));
  49        } else {
  50                ret = opal_error_code(ret);
  51        }
  52
  53out:
  54        opal_async_release_token(token);
  55        return ret;
  56}
  57EXPORT_SYMBOL_GPL(sensor_group_enable);
  58
  59static ssize_t sg_store(struct kobject *kobj, struct kobj_attribute *attr,
  60                        const char *buf, size_t count)
  61{
  62        struct sg_attr *sattr = container_of(attr, struct sg_attr, attr);
  63        struct opal_msg msg;
  64        u32 data;
  65        int ret, token;
  66
  67        ret = kstrtoint(buf, 0, &data);
  68        if (ret)
  69                return ret;
  70
  71        if (data != 1)
  72                return -EINVAL;
  73
  74        token = opal_async_get_token_interruptible();
  75        if (token < 0) {
  76                pr_devel("Failed to get token\n");
  77                return token;
  78        }
  79
  80        ret = mutex_lock_interruptible(&sg_mutex);
  81        if (ret)
  82                goto out_token;
  83
  84        ret = opal_sensor_group_clear(sattr->handle, token);
  85        switch (ret) {
  86        case OPAL_ASYNC_COMPLETION:
  87                ret = opal_async_wait_response(token, &msg);
  88                if (ret) {
  89                        pr_devel("Failed to wait for the async response\n");
  90                        ret = -EIO;
  91                        goto out;
  92                }
  93                ret = opal_error_code(opal_get_async_rc(msg));
  94                if (!ret)
  95                        ret = count;
  96                break;
  97        case OPAL_SUCCESS:
  98                ret = count;
  99                break;
 100        default:
 101                ret = opal_error_code(ret);
 102        }
 103
 104out:
 105        mutex_unlock(&sg_mutex);
 106out_token:
 107        opal_async_release_token(token);
 108        return ret;
 109}
 110
 111static struct sg_ops_info {
 112        int opal_no;
 113        const char *attr_name;
 114        ssize_t (*store)(struct kobject *kobj, struct kobj_attribute *attr,
 115                        const char *buf, size_t count);
 116} ops_info[] = {
 117        { OPAL_SENSOR_GROUP_CLEAR, "clear", sg_store },
 118};
 119
 120static void add_attr(int handle, struct sg_attr *attr, int index)
 121{
 122        attr->handle = handle;
 123        sysfs_attr_init(&attr->attr.attr);
 124        attr->attr.attr.name = ops_info[index].attr_name;
 125        attr->attr.attr.mode = 0220;
 126        attr->attr.store = ops_info[index].store;
 127}
 128
 129static int add_attr_group(const __be32 *ops, int len, struct sensor_group *sg,
 130                           u32 handle)
 131{
 132        int i, j;
 133        int count = 0;
 134
 135        for (i = 0; i < len; i++)
 136                for (j = 0; j < ARRAY_SIZE(ops_info); j++)
 137                        if (be32_to_cpu(ops[i]) == ops_info[j].opal_no) {
 138                                add_attr(handle, &sg->sgattrs[count], j);
 139                                sg->sg.attrs[count] =
 140                                        &sg->sgattrs[count].attr.attr;
 141                                count++;
 142                        }
 143
 144        return sysfs_create_group(sg_kobj, &sg->sg);
 145}
 146
 147static int get_nr_attrs(const __be32 *ops, int len)
 148{
 149        int i, j;
 150        int nr_attrs = 0;
 151
 152        for (i = 0; i < len; i++)
 153                for (j = 0; j < ARRAY_SIZE(ops_info); j++)
 154                        if (be32_to_cpu(ops[i]) == ops_info[j].opal_no)
 155                                nr_attrs++;
 156
 157        return nr_attrs;
 158}
 159
 160void __init opal_sensor_groups_init(void)
 161{
 162        struct device_node *sg, *node;
 163        int i = 0;
 164
 165        sg = of_find_compatible_node(NULL, NULL, "ibm,opal-sensor-group");
 166        if (!sg) {
 167                pr_devel("Sensor groups node not found\n");
 168                return;
 169        }
 170
 171        sgs = kcalloc(of_get_child_count(sg), sizeof(*sgs), GFP_KERNEL);
 172        if (!sgs)
 173                return;
 174
 175        sg_kobj = kobject_create_and_add("sensor_groups", opal_kobj);
 176        if (!sg_kobj) {
 177                pr_warn("Failed to create sensor group kobject\n");
 178                goto out_sgs;
 179        }
 180
 181        for_each_child_of_node(sg, node) {
 182                const __be32 *ops;
 183                u32 sgid, len, nr_attrs, chipid;
 184
 185                ops = of_get_property(node, "ops", &len);
 186                if (!ops)
 187                        continue;
 188
 189                nr_attrs = get_nr_attrs(ops, len);
 190                if (!nr_attrs)
 191                        continue;
 192
 193                sgs[i].sgattrs = kcalloc(nr_attrs, sizeof(*sgs[i].sgattrs),
 194                                         GFP_KERNEL);
 195                if (!sgs[i].sgattrs)
 196                        goto out_sgs_sgattrs;
 197
 198                sgs[i].sg.attrs = kcalloc(nr_attrs + 1,
 199                                          sizeof(*sgs[i].sg.attrs),
 200                                          GFP_KERNEL);
 201
 202                if (!sgs[i].sg.attrs) {
 203                        kfree(sgs[i].sgattrs);
 204                        goto out_sgs_sgattrs;
 205                }
 206
 207                if (of_property_read_u32(node, "sensor-group-id", &sgid)) {
 208                        pr_warn("sensor-group-id property not found\n");
 209                        goto out_sgs_sgattrs;
 210                }
 211
 212                if (!of_property_read_u32(node, "ibm,chip-id", &chipid))
 213                        sprintf(sgs[i].name, "%pOFn%d", node, chipid);
 214                else
 215                        sprintf(sgs[i].name, "%pOFn", node);
 216
 217                sgs[i].sg.name = sgs[i].name;
 218                if (add_attr_group(ops, len, &sgs[i], sgid)) {
 219                        pr_warn("Failed to create sensor attribute group %s\n",
 220                                sgs[i].sg.name);
 221                        goto out_sgs_sgattrs;
 222                }
 223                i++;
 224        }
 225
 226        return;
 227
 228out_sgs_sgattrs:
 229        while (--i >= 0) {
 230                kfree(sgs[i].sgattrs);
 231                kfree(sgs[i].sg.attrs);
 232        }
 233        kobject_put(sg_kobj);
 234out_sgs:
 235        kfree(sgs);
 236}
 237