Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * PowerNV OPAL Sensor-groups interface
0004  *
0005  * Copyright 2017 IBM Corp.
0006  */
0007 
0008 #define pr_fmt(fmt)     "opal-sensor-groups: " fmt
0009 
0010 #include <linux/of.h>
0011 #include <linux/kobject.h>
0012 #include <linux/slab.h>
0013 
0014 #include <asm/opal.h>
0015 
0016 static DEFINE_MUTEX(sg_mutex);
0017 
0018 static struct kobject *sg_kobj;
0019 
0020 struct sg_attr {
0021     u32 handle;
0022     struct kobj_attribute attr;
0023 };
0024 
0025 static struct sensor_group {
0026     char name[20];
0027     struct attribute_group sg;
0028     struct sg_attr *sgattrs;
0029 } *sgs;
0030 
0031 int sensor_group_enable(u32 handle, bool enable)
0032 {
0033     struct opal_msg msg;
0034     int token, ret;
0035 
0036     token = opal_async_get_token_interruptible();
0037     if (token < 0)
0038         return token;
0039 
0040     ret = opal_sensor_group_enable(handle, token, enable);
0041     if (ret == OPAL_ASYNC_COMPLETION) {
0042         ret = opal_async_wait_response(token, &msg);
0043         if (ret) {
0044             pr_devel("Failed to wait for the async response\n");
0045             ret = -EIO;
0046             goto out;
0047         }
0048         ret = opal_error_code(opal_get_async_rc(msg));
0049     } else {
0050         ret = opal_error_code(ret);
0051     }
0052 
0053 out:
0054     opal_async_release_token(token);
0055     return ret;
0056 }
0057 EXPORT_SYMBOL_GPL(sensor_group_enable);
0058 
0059 static ssize_t sg_store(struct kobject *kobj, struct kobj_attribute *attr,
0060             const char *buf, size_t count)
0061 {
0062     struct sg_attr *sattr = container_of(attr, struct sg_attr, attr);
0063     struct opal_msg msg;
0064     u32 data;
0065     int ret, token;
0066 
0067     ret = kstrtoint(buf, 0, &data);
0068     if (ret)
0069         return ret;
0070 
0071     if (data != 1)
0072         return -EINVAL;
0073 
0074     token = opal_async_get_token_interruptible();
0075     if (token < 0) {
0076         pr_devel("Failed to get token\n");
0077         return token;
0078     }
0079 
0080     ret = mutex_lock_interruptible(&sg_mutex);
0081     if (ret)
0082         goto out_token;
0083 
0084     ret = opal_sensor_group_clear(sattr->handle, token);
0085     switch (ret) {
0086     case OPAL_ASYNC_COMPLETION:
0087         ret = opal_async_wait_response(token, &msg);
0088         if (ret) {
0089             pr_devel("Failed to wait for the async response\n");
0090             ret = -EIO;
0091             goto out;
0092         }
0093         ret = opal_error_code(opal_get_async_rc(msg));
0094         if (!ret)
0095             ret = count;
0096         break;
0097     case OPAL_SUCCESS:
0098         ret = count;
0099         break;
0100     default:
0101         ret = opal_error_code(ret);
0102     }
0103 
0104 out:
0105     mutex_unlock(&sg_mutex);
0106 out_token:
0107     opal_async_release_token(token);
0108     return ret;
0109 }
0110 
0111 static struct sg_ops_info {
0112     int opal_no;
0113     const char *attr_name;
0114     ssize_t (*store)(struct kobject *kobj, struct kobj_attribute *attr,
0115             const char *buf, size_t count);
0116 } ops_info[] = {
0117     { OPAL_SENSOR_GROUP_CLEAR, "clear", sg_store },
0118 };
0119 
0120 static void add_attr(int handle, struct sg_attr *attr, int index)
0121 {
0122     attr->handle = handle;
0123     sysfs_attr_init(&attr->attr.attr);
0124     attr->attr.attr.name = ops_info[index].attr_name;
0125     attr->attr.attr.mode = 0220;
0126     attr->attr.store = ops_info[index].store;
0127 }
0128 
0129 static int __init add_attr_group(const __be32 *ops, int len, struct sensor_group *sg,
0130                u32 handle)
0131 {
0132     int i, j;
0133     int count = 0;
0134 
0135     for (i = 0; i < len; i++)
0136         for (j = 0; j < ARRAY_SIZE(ops_info); j++)
0137             if (be32_to_cpu(ops[i]) == ops_info[j].opal_no) {
0138                 add_attr(handle, &sg->sgattrs[count], j);
0139                 sg->sg.attrs[count] =
0140                     &sg->sgattrs[count].attr.attr;
0141                 count++;
0142             }
0143 
0144     return sysfs_create_group(sg_kobj, &sg->sg);
0145 }
0146 
0147 static int __init get_nr_attrs(const __be32 *ops, int len)
0148 {
0149     int i, j;
0150     int nr_attrs = 0;
0151 
0152     for (i = 0; i < len; i++)
0153         for (j = 0; j < ARRAY_SIZE(ops_info); j++)
0154             if (be32_to_cpu(ops[i]) == ops_info[j].opal_no)
0155                 nr_attrs++;
0156 
0157     return nr_attrs;
0158 }
0159 
0160 void __init opal_sensor_groups_init(void)
0161 {
0162     struct device_node *sg, *node;
0163     int i = 0;
0164 
0165     sg = of_find_compatible_node(NULL, NULL, "ibm,opal-sensor-group");
0166     if (!sg) {
0167         pr_devel("Sensor groups node not found\n");
0168         return;
0169     }
0170 
0171     sgs = kcalloc(of_get_child_count(sg), sizeof(*sgs), GFP_KERNEL);
0172     if (!sgs)
0173         return;
0174 
0175     sg_kobj = kobject_create_and_add("sensor_groups", opal_kobj);
0176     if (!sg_kobj) {
0177         pr_warn("Failed to create sensor group kobject\n");
0178         goto out_sgs;
0179     }
0180 
0181     for_each_child_of_node(sg, node) {
0182         const __be32 *ops;
0183         u32 sgid, len, nr_attrs, chipid;
0184 
0185         ops = of_get_property(node, "ops", &len);
0186         if (!ops)
0187             continue;
0188 
0189         nr_attrs = get_nr_attrs(ops, len);
0190         if (!nr_attrs)
0191             continue;
0192 
0193         sgs[i].sgattrs = kcalloc(nr_attrs, sizeof(*sgs[i].sgattrs),
0194                      GFP_KERNEL);
0195         if (!sgs[i].sgattrs)
0196             goto out_sgs_sgattrs;
0197 
0198         sgs[i].sg.attrs = kcalloc(nr_attrs + 1,
0199                       sizeof(*sgs[i].sg.attrs),
0200                       GFP_KERNEL);
0201 
0202         if (!sgs[i].sg.attrs) {
0203             kfree(sgs[i].sgattrs);
0204             goto out_sgs_sgattrs;
0205         }
0206 
0207         if (of_property_read_u32(node, "sensor-group-id", &sgid)) {
0208             pr_warn("sensor-group-id property not found\n");
0209             goto out_sgs_sgattrs;
0210         }
0211 
0212         if (!of_property_read_u32(node, "ibm,chip-id", &chipid))
0213             sprintf(sgs[i].name, "%pOFn%d", node, chipid);
0214         else
0215             sprintf(sgs[i].name, "%pOFn", node);
0216 
0217         sgs[i].sg.name = sgs[i].name;
0218         if (add_attr_group(ops, len, &sgs[i], sgid)) {
0219             pr_warn("Failed to create sensor attribute group %s\n",
0220                 sgs[i].sg.name);
0221             goto out_sgs_sgattrs;
0222         }
0223         i++;
0224     }
0225 
0226     return;
0227 
0228 out_sgs_sgattrs:
0229     while (--i >= 0) {
0230         kfree(sgs[i].sgattrs);
0231         kfree(sgs[i].sg.attrs);
0232     }
0233     kobject_put(sg_kobj);
0234 out_sgs:
0235     kfree(sgs);
0236 }