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