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