root/arch/powerpc/platforms/powernv/opal-sensor-groups.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. sensor_group_enable
  2. sg_store
  3. add_attr
  4. add_attr_group
  5. get_nr_attrs
  6. opal_sensor_groups_init

   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 
  16 DEFINE_MUTEX(sg_mutex);
  17 
  18 static struct kobject *sg_kobj;
  19 
  20 struct sg_attr {
  21         u32 handle;
  22         struct kobj_attribute attr;
  23 };
  24 
  25 static struct sensor_group {
  26         char name[20];
  27         struct attribute_group sg;
  28         struct sg_attr *sgattrs;
  29 } *sgs;
  30 
  31 int 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 
  53 out:
  54         opal_async_release_token(token);
  55         return ret;
  56 }
  57 EXPORT_SYMBOL_GPL(sensor_group_enable);
  58 
  59 static 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 
 104 out:
 105         mutex_unlock(&sg_mutex);
 106 out_token:
 107         opal_async_release_token(token);
 108         return ret;
 109 }
 110 
 111 static 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 
 120 static 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 
 129 static 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 
 147 static 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 
 160 void __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 
 228 out_sgs_sgattrs:
 229         while (--i >= 0) {
 230                 kfree(sgs[i].sgattrs);
 231                 kfree(sgs[i].sg.attrs);
 232         }
 233         kobject_put(sg_kobj);
 234 out_sgs:
 235         kfree(sgs);
 236 }

/* [<][>][^][v][top][bottom][index][help] */