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