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