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 static ssize_t sg_store(struct kobject *kobj, struct kobj_attribute *attr, 36 const char *buf, size_t count) 37 { 38 struct sg_attr *sattr = container_of(attr, struct sg_attr, attr); 39 struct opal_msg msg; 40 u32 data; 41 int ret, token; 42 43 ret = kstrtoint(buf, 0, &data); 44 if (ret) 45 return ret; 46 47 if (data != 1) 48 return -EINVAL; 49 50 token = opal_async_get_token_interruptible(); 51 if (token < 0) { 52 pr_devel("Failed to get token\n"); 53 return token; 54 } 55 56 ret = mutex_lock_interruptible(&sg_mutex); 57 if (ret) 58 goto out_token; 59 60 ret = opal_sensor_group_clear(sattr->handle, token); 61 switch (ret) { 62 case OPAL_ASYNC_COMPLETION: 63 ret = opal_async_wait_response(token, &msg); 64 if (ret) { 65 pr_devel("Failed to wait for the async response\n"); 66 ret = -EIO; 67 goto out; 68 } 69 ret = opal_error_code(opal_get_async_rc(msg)); 70 if (!ret) 71 ret = count; 72 break; 73 case OPAL_SUCCESS: 74 ret = count; 75 break; 76 default: 77 ret = opal_error_code(ret); 78 } 79 80 out: 81 mutex_unlock(&sg_mutex); 82 out_token: 83 opal_async_release_token(token); 84 return ret; 85 } 86 87 static struct sg_ops_info { 88 int opal_no; 89 const char *attr_name; 90 ssize_t (*store)(struct kobject *kobj, struct kobj_attribute *attr, 91 const char *buf, size_t count); 92 } ops_info[] = { 93 { OPAL_SENSOR_GROUP_CLEAR, "clear", sg_store }, 94 }; 95 96 static void add_attr(int handle, struct sg_attr *attr, int index) 97 { 98 attr->handle = handle; 99 sysfs_attr_init(&attr->attr.attr); 100 attr->attr.attr.name = ops_info[index].attr_name; 101 attr->attr.attr.mode = 0220; 102 attr->attr.store = ops_info[index].store; 103 } 104 105 static int add_attr_group(const __be32 *ops, int len, struct sensor_group *sg, 106 u32 handle) 107 { 108 int i, j; 109 int count = 0; 110 111 for (i = 0; i < len; i++) 112 for (j = 0; j < ARRAY_SIZE(ops_info); j++) 113 if (be32_to_cpu(ops[i]) == ops_info[j].opal_no) { 114 add_attr(handle, &sg->sgattrs[count], j); 115 sg->sg.attrs[count] = 116 &sg->sgattrs[count].attr.attr; 117 count++; 118 } 119 120 return sysfs_create_group(sg_kobj, &sg->sg); 121 } 122 123 static int get_nr_attrs(const __be32 *ops, int len) 124 { 125 int i, j; 126 int nr_attrs = 0; 127 128 for (i = 0; i < len; i++) 129 for (j = 0; j < ARRAY_SIZE(ops_info); j++) 130 if (be32_to_cpu(ops[i]) == ops_info[j].opal_no) 131 nr_attrs++; 132 133 return nr_attrs; 134 } 135 136 void __init opal_sensor_groups_init(void) 137 { 138 struct device_node *sg, *node; 139 int i = 0; 140 141 sg = of_find_compatible_node(NULL, NULL, "ibm,opal-sensor-group"); 142 if (!sg) { 143 pr_devel("Sensor groups node not found\n"); 144 return; 145 } 146 147 sgs = kcalloc(of_get_child_count(sg), sizeof(*sgs), GFP_KERNEL); 148 if (!sgs) 149 return; 150 151 sg_kobj = kobject_create_and_add("sensor_groups", opal_kobj); 152 if (!sg_kobj) { 153 pr_warn("Failed to create sensor group kobject\n"); 154 goto out_sgs; 155 } 156 157 for_each_child_of_node(sg, node) { 158 const __be32 *ops; 159 u32 sgid, len, nr_attrs, chipid; 160 161 ops = of_get_property(node, "ops", &len); 162 if (!ops) 163 continue; 164 165 nr_attrs = get_nr_attrs(ops, len); 166 if (!nr_attrs) 167 continue; 168 169 sgs[i].sgattrs = kcalloc(nr_attrs, sizeof(struct sg_attr), 170 GFP_KERNEL); 171 if (!sgs[i].sgattrs) 172 goto out_sgs_sgattrs; 173 174 sgs[i].sg.attrs = kcalloc(nr_attrs + 1, 175 sizeof(struct attribute *), 176 GFP_KERNEL); 177 178 if (!sgs[i].sg.attrs) { 179 kfree(sgs[i].sgattrs); 180 goto out_sgs_sgattrs; 181 } 182 183 if (of_property_read_u32(node, "sensor-group-id", &sgid)) { 184 pr_warn("sensor-group-id property not found\n"); 185 goto out_sgs_sgattrs; 186 } 187 188 if (!of_property_read_u32(node, "ibm,chip-id", &chipid)) 189 sprintf(sgs[i].name, "%s%d", node->name, chipid); 190 else 191 sprintf(sgs[i].name, "%s", node->name); 192 193 sgs[i].sg.name = sgs[i].name; 194 if (add_attr_group(ops, len, &sgs[i], sgid)) { 195 pr_warn("Failed to create sensor attribute group %s\n", 196 sgs[i].sg.name); 197 goto out_sgs_sgattrs; 198 } 199 i++; 200 } 201 202 return; 203 204 out_sgs_sgattrs: 205 while (--i >= 0) { 206 kfree(sgs[i].sgattrs); 207 kfree(sgs[i].sg.attrs); 208 } 209 kobject_put(sg_kobj); 210 out_sgs: 211 kfree(sgs); 212 } 213