cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

opal-sensor-groups.c (4982B)


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