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

counter-sysfs.c (26087B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Generic Counter sysfs interface
      4 * Copyright (C) 2020 William Breathitt Gray
      5 */
      6#include <linux/counter.h>
      7#include <linux/device.h>
      8#include <linux/err.h>
      9#include <linux/gfp.h>
     10#include <linux/kernel.h>
     11#include <linux/kfifo.h>
     12#include <linux/kstrtox.h>
     13#include <linux/list.h>
     14#include <linux/mutex.h>
     15#include <linux/spinlock.h>
     16#include <linux/string.h>
     17#include <linux/sysfs.h>
     18#include <linux/types.h>
     19
     20#include "counter-sysfs.h"
     21
     22static inline struct counter_device *counter_from_dev(struct device *dev)
     23{
     24	return container_of(dev, struct counter_device, dev);
     25}
     26
     27/**
     28 * struct counter_attribute - Counter sysfs attribute
     29 * @dev_attr:	device attribute for sysfs
     30 * @l:		node to add Counter attribute to attribute group list
     31 * @comp:	Counter component callbacks and data
     32 * @scope:	Counter scope of the attribute
     33 * @parent:	pointer to the parent component
     34 */
     35struct counter_attribute {
     36	struct device_attribute dev_attr;
     37	struct list_head l;
     38
     39	struct counter_comp comp;
     40	enum counter_scope scope;
     41	void *parent;
     42};
     43
     44#define to_counter_attribute(_dev_attr) \
     45	container_of(_dev_attr, struct counter_attribute, dev_attr)
     46
     47/**
     48 * struct counter_attribute_group - container for attribute group
     49 * @name:	name of the attribute group
     50 * @attr_list:	list to keep track of created attributes
     51 * @num_attr:	number of attributes
     52 */
     53struct counter_attribute_group {
     54	const char *name;
     55	struct list_head attr_list;
     56	size_t num_attr;
     57};
     58
     59static const char *const counter_function_str[] = {
     60	[COUNTER_FUNCTION_INCREASE] = "increase",
     61	[COUNTER_FUNCTION_DECREASE] = "decrease",
     62	[COUNTER_FUNCTION_PULSE_DIRECTION] = "pulse-direction",
     63	[COUNTER_FUNCTION_QUADRATURE_X1_A] = "quadrature x1 a",
     64	[COUNTER_FUNCTION_QUADRATURE_X1_B] = "quadrature x1 b",
     65	[COUNTER_FUNCTION_QUADRATURE_X2_A] = "quadrature x2 a",
     66	[COUNTER_FUNCTION_QUADRATURE_X2_B] = "quadrature x2 b",
     67	[COUNTER_FUNCTION_QUADRATURE_X4] = "quadrature x4"
     68};
     69
     70static const char *const counter_signal_value_str[] = {
     71	[COUNTER_SIGNAL_LEVEL_LOW] = "low",
     72	[COUNTER_SIGNAL_LEVEL_HIGH] = "high"
     73};
     74
     75static const char *const counter_synapse_action_str[] = {
     76	[COUNTER_SYNAPSE_ACTION_NONE] = "none",
     77	[COUNTER_SYNAPSE_ACTION_RISING_EDGE] = "rising edge",
     78	[COUNTER_SYNAPSE_ACTION_FALLING_EDGE] = "falling edge",
     79	[COUNTER_SYNAPSE_ACTION_BOTH_EDGES] = "both edges"
     80};
     81
     82static const char *const counter_count_direction_str[] = {
     83	[COUNTER_COUNT_DIRECTION_FORWARD] = "forward",
     84	[COUNTER_COUNT_DIRECTION_BACKWARD] = "backward"
     85};
     86
     87static const char *const counter_count_mode_str[] = {
     88	[COUNTER_COUNT_MODE_NORMAL] = "normal",
     89	[COUNTER_COUNT_MODE_RANGE_LIMIT] = "range limit",
     90	[COUNTER_COUNT_MODE_NON_RECYCLE] = "non-recycle",
     91	[COUNTER_COUNT_MODE_MODULO_N] = "modulo-n"
     92};
     93
     94static ssize_t counter_comp_u8_show(struct device *dev,
     95				    struct device_attribute *attr, char *buf)
     96{
     97	const struct counter_attribute *const a = to_counter_attribute(attr);
     98	struct counter_device *const counter = counter_from_dev(dev);
     99	int err;
    100	u8 data = 0;
    101
    102	switch (a->scope) {
    103	case COUNTER_SCOPE_DEVICE:
    104		err = a->comp.device_u8_read(counter, &data);
    105		break;
    106	case COUNTER_SCOPE_SIGNAL:
    107		err = a->comp.signal_u8_read(counter, a->parent, &data);
    108		break;
    109	case COUNTER_SCOPE_COUNT:
    110		err = a->comp.count_u8_read(counter, a->parent, &data);
    111		break;
    112	default:
    113		return -EINVAL;
    114	}
    115	if (err < 0)
    116		return err;
    117
    118	if (a->comp.type == COUNTER_COMP_BOOL)
    119		/* data should already be boolean but ensure just to be safe */
    120		data = !!data;
    121
    122	return sysfs_emit(buf, "%u\n", (unsigned int)data);
    123}
    124
    125static ssize_t counter_comp_u8_store(struct device *dev,
    126				     struct device_attribute *attr,
    127				     const char *buf, size_t len)
    128{
    129	const struct counter_attribute *const a = to_counter_attribute(attr);
    130	struct counter_device *const counter = counter_from_dev(dev);
    131	int err;
    132	bool bool_data = 0;
    133	u8 data = 0;
    134
    135	if (a->comp.type == COUNTER_COMP_BOOL) {
    136		err = kstrtobool(buf, &bool_data);
    137		data = bool_data;
    138	} else
    139		err = kstrtou8(buf, 0, &data);
    140	if (err < 0)
    141		return err;
    142
    143	switch (a->scope) {
    144	case COUNTER_SCOPE_DEVICE:
    145		err = a->comp.device_u8_write(counter, data);
    146		break;
    147	case COUNTER_SCOPE_SIGNAL:
    148		err = a->comp.signal_u8_write(counter, a->parent, data);
    149		break;
    150	case COUNTER_SCOPE_COUNT:
    151		err = a->comp.count_u8_write(counter, a->parent, data);
    152		break;
    153	default:
    154		return -EINVAL;
    155	}
    156	if (err < 0)
    157		return err;
    158
    159	return len;
    160}
    161
    162static ssize_t counter_comp_u32_show(struct device *dev,
    163				     struct device_attribute *attr, char *buf)
    164{
    165	const struct counter_attribute *const a = to_counter_attribute(attr);
    166	struct counter_device *const counter = counter_from_dev(dev);
    167	const struct counter_available *const avail = a->comp.priv;
    168	int err;
    169	u32 data = 0;
    170
    171	switch (a->scope) {
    172	case COUNTER_SCOPE_DEVICE:
    173		err = a->comp.device_u32_read(counter, &data);
    174		break;
    175	case COUNTER_SCOPE_SIGNAL:
    176		err = a->comp.signal_u32_read(counter, a->parent, &data);
    177		break;
    178	case COUNTER_SCOPE_COUNT:
    179		if (a->comp.type == COUNTER_COMP_SYNAPSE_ACTION)
    180			err = a->comp.action_read(counter, a->parent,
    181						  a->comp.priv, &data);
    182		else
    183			err = a->comp.count_u32_read(counter, a->parent, &data);
    184		break;
    185	default:
    186		return -EINVAL;
    187	}
    188	if (err < 0)
    189		return err;
    190
    191	switch (a->comp.type) {
    192	case COUNTER_COMP_FUNCTION:
    193		return sysfs_emit(buf, "%s\n", counter_function_str[data]);
    194	case COUNTER_COMP_SIGNAL_LEVEL:
    195		return sysfs_emit(buf, "%s\n", counter_signal_value_str[data]);
    196	case COUNTER_COMP_SYNAPSE_ACTION:
    197		return sysfs_emit(buf, "%s\n", counter_synapse_action_str[data]);
    198	case COUNTER_COMP_ENUM:
    199		return sysfs_emit(buf, "%s\n", avail->strs[data]);
    200	case COUNTER_COMP_COUNT_DIRECTION:
    201		return sysfs_emit(buf, "%s\n", counter_count_direction_str[data]);
    202	case COUNTER_COMP_COUNT_MODE:
    203		return sysfs_emit(buf, "%s\n", counter_count_mode_str[data]);
    204	default:
    205		return sysfs_emit(buf, "%u\n", (unsigned int)data);
    206	}
    207}
    208
    209static int counter_find_enum(u32 *const enum_item, const u32 *const enums,
    210			     const size_t num_enums, const char *const buf,
    211			     const char *const string_array[])
    212{
    213	size_t index;
    214
    215	for (index = 0; index < num_enums; index++) {
    216		*enum_item = enums[index];
    217		if (sysfs_streq(buf, string_array[*enum_item]))
    218			return 0;
    219	}
    220
    221	return -EINVAL;
    222}
    223
    224static ssize_t counter_comp_u32_store(struct device *dev,
    225				      struct device_attribute *attr,
    226				      const char *buf, size_t len)
    227{
    228	const struct counter_attribute *const a = to_counter_attribute(attr);
    229	struct counter_device *const counter = counter_from_dev(dev);
    230	struct counter_count *const count = a->parent;
    231	struct counter_synapse *const synapse = a->comp.priv;
    232	const struct counter_available *const avail = a->comp.priv;
    233	int err;
    234	u32 data = 0;
    235
    236	switch (a->comp.type) {
    237	case COUNTER_COMP_FUNCTION:
    238		err = counter_find_enum(&data, count->functions_list,
    239					count->num_functions, buf,
    240					counter_function_str);
    241		break;
    242	case COUNTER_COMP_SYNAPSE_ACTION:
    243		err = counter_find_enum(&data, synapse->actions_list,
    244					synapse->num_actions, buf,
    245					counter_synapse_action_str);
    246		break;
    247	case COUNTER_COMP_ENUM:
    248		err = __sysfs_match_string(avail->strs, avail->num_items, buf);
    249		data = err;
    250		break;
    251	case COUNTER_COMP_COUNT_MODE:
    252		err = counter_find_enum(&data, avail->enums, avail->num_items,
    253					buf, counter_count_mode_str);
    254		break;
    255	default:
    256		err = kstrtou32(buf, 0, &data);
    257		break;
    258	}
    259	if (err < 0)
    260		return err;
    261
    262	switch (a->scope) {
    263	case COUNTER_SCOPE_DEVICE:
    264		err = a->comp.device_u32_write(counter, data);
    265		break;
    266	case COUNTER_SCOPE_SIGNAL:
    267		err = a->comp.signal_u32_write(counter, a->parent, data);
    268		break;
    269	case COUNTER_SCOPE_COUNT:
    270		if (a->comp.type == COUNTER_COMP_SYNAPSE_ACTION)
    271			err = a->comp.action_write(counter, count, synapse,
    272						   data);
    273		else
    274			err = a->comp.count_u32_write(counter, count, data);
    275		break;
    276	default:
    277		return -EINVAL;
    278	}
    279	if (err < 0)
    280		return err;
    281
    282	return len;
    283}
    284
    285static ssize_t counter_comp_u64_show(struct device *dev,
    286				     struct device_attribute *attr, char *buf)
    287{
    288	const struct counter_attribute *const a = to_counter_attribute(attr);
    289	struct counter_device *const counter = counter_from_dev(dev);
    290	int err;
    291	u64 data = 0;
    292
    293	switch (a->scope) {
    294	case COUNTER_SCOPE_DEVICE:
    295		err = a->comp.device_u64_read(counter, &data);
    296		break;
    297	case COUNTER_SCOPE_SIGNAL:
    298		err = a->comp.signal_u64_read(counter, a->parent, &data);
    299		break;
    300	case COUNTER_SCOPE_COUNT:
    301		err = a->comp.count_u64_read(counter, a->parent, &data);
    302		break;
    303	default:
    304		return -EINVAL;
    305	}
    306	if (err < 0)
    307		return err;
    308
    309	return sysfs_emit(buf, "%llu\n", (unsigned long long)data);
    310}
    311
    312static ssize_t counter_comp_u64_store(struct device *dev,
    313				      struct device_attribute *attr,
    314				      const char *buf, size_t len)
    315{
    316	const struct counter_attribute *const a = to_counter_attribute(attr);
    317	struct counter_device *const counter = counter_from_dev(dev);
    318	int err;
    319	u64 data = 0;
    320
    321	err = kstrtou64(buf, 0, &data);
    322	if (err < 0)
    323		return err;
    324
    325	switch (a->scope) {
    326	case COUNTER_SCOPE_DEVICE:
    327		err = a->comp.device_u64_write(counter, data);
    328		break;
    329	case COUNTER_SCOPE_SIGNAL:
    330		err = a->comp.signal_u64_write(counter, a->parent, data);
    331		break;
    332	case COUNTER_SCOPE_COUNT:
    333		err = a->comp.count_u64_write(counter, a->parent, data);
    334		break;
    335	default:
    336		return -EINVAL;
    337	}
    338	if (err < 0)
    339		return err;
    340
    341	return len;
    342}
    343
    344static ssize_t enums_available_show(const u32 *const enums,
    345				    const size_t num_enums,
    346				    const char *const strs[], char *buf)
    347{
    348	size_t len = 0;
    349	size_t index;
    350
    351	for (index = 0; index < num_enums; index++)
    352		len += sysfs_emit_at(buf, len, "%s\n", strs[enums[index]]);
    353
    354	return len;
    355}
    356
    357static ssize_t strs_available_show(const struct counter_available *const avail,
    358				   char *buf)
    359{
    360	size_t len = 0;
    361	size_t index;
    362
    363	for (index = 0; index < avail->num_items; index++)
    364		len += sysfs_emit_at(buf, len, "%s\n", avail->strs[index]);
    365
    366	return len;
    367}
    368
    369static ssize_t counter_comp_available_show(struct device *dev,
    370					   struct device_attribute *attr,
    371					   char *buf)
    372{
    373	const struct counter_attribute *const a = to_counter_attribute(attr);
    374	const struct counter_count *const count = a->parent;
    375	const struct counter_synapse *const synapse = a->comp.priv;
    376	const struct counter_available *const avail = a->comp.priv;
    377
    378	switch (a->comp.type) {
    379	case COUNTER_COMP_FUNCTION:
    380		return enums_available_show(count->functions_list,
    381					    count->num_functions,
    382					    counter_function_str, buf);
    383	case COUNTER_COMP_SYNAPSE_ACTION:
    384		return enums_available_show(synapse->actions_list,
    385					    synapse->num_actions,
    386					    counter_synapse_action_str, buf);
    387	case COUNTER_COMP_ENUM:
    388		return strs_available_show(avail, buf);
    389	case COUNTER_COMP_COUNT_MODE:
    390		return enums_available_show(avail->enums, avail->num_items,
    391					    counter_count_mode_str, buf);
    392	default:
    393		return -EINVAL;
    394	}
    395}
    396
    397static int counter_avail_attr_create(struct device *const dev,
    398	struct counter_attribute_group *const group,
    399	const struct counter_comp *const comp, void *const parent)
    400{
    401	struct counter_attribute *counter_attr;
    402	struct device_attribute *dev_attr;
    403
    404	counter_attr = devm_kzalloc(dev, sizeof(*counter_attr), GFP_KERNEL);
    405	if (!counter_attr)
    406		return -ENOMEM;
    407
    408	/* Configure Counter attribute */
    409	counter_attr->comp.type = comp->type;
    410	counter_attr->comp.priv = comp->priv;
    411	counter_attr->parent = parent;
    412
    413	/* Initialize sysfs attribute */
    414	dev_attr = &counter_attr->dev_attr;
    415	sysfs_attr_init(&dev_attr->attr);
    416
    417	/* Configure device attribute */
    418	dev_attr->attr.name = devm_kasprintf(dev, GFP_KERNEL, "%s_available",
    419					     comp->name);
    420	if (!dev_attr->attr.name)
    421		return -ENOMEM;
    422	dev_attr->attr.mode = 0444;
    423	dev_attr->show = counter_comp_available_show;
    424
    425	/* Store list node */
    426	list_add(&counter_attr->l, &group->attr_list);
    427	group->num_attr++;
    428
    429	return 0;
    430}
    431
    432static int counter_attr_create(struct device *const dev,
    433			       struct counter_attribute_group *const group,
    434			       const struct counter_comp *const comp,
    435			       const enum counter_scope scope,
    436			       void *const parent)
    437{
    438	struct counter_attribute *counter_attr;
    439	struct device_attribute *dev_attr;
    440
    441	counter_attr = devm_kzalloc(dev, sizeof(*counter_attr), GFP_KERNEL);
    442	if (!counter_attr)
    443		return -ENOMEM;
    444
    445	/* Configure Counter attribute */
    446	counter_attr->comp = *comp;
    447	counter_attr->scope = scope;
    448	counter_attr->parent = parent;
    449
    450	/* Configure device attribute */
    451	dev_attr = &counter_attr->dev_attr;
    452	sysfs_attr_init(&dev_attr->attr);
    453	dev_attr->attr.name = comp->name;
    454	switch (comp->type) {
    455	case COUNTER_COMP_U8:
    456	case COUNTER_COMP_BOOL:
    457		if (comp->device_u8_read) {
    458			dev_attr->attr.mode |= 0444;
    459			dev_attr->show = counter_comp_u8_show;
    460		}
    461		if (comp->device_u8_write) {
    462			dev_attr->attr.mode |= 0200;
    463			dev_attr->store = counter_comp_u8_store;
    464		}
    465		break;
    466	case COUNTER_COMP_SIGNAL_LEVEL:
    467	case COUNTER_COMP_FUNCTION:
    468	case COUNTER_COMP_SYNAPSE_ACTION:
    469	case COUNTER_COMP_ENUM:
    470	case COUNTER_COMP_COUNT_DIRECTION:
    471	case COUNTER_COMP_COUNT_MODE:
    472		if (comp->device_u32_read) {
    473			dev_attr->attr.mode |= 0444;
    474			dev_attr->show = counter_comp_u32_show;
    475		}
    476		if (comp->device_u32_write) {
    477			dev_attr->attr.mode |= 0200;
    478			dev_attr->store = counter_comp_u32_store;
    479		}
    480		break;
    481	case COUNTER_COMP_U64:
    482		if (comp->device_u64_read) {
    483			dev_attr->attr.mode |= 0444;
    484			dev_attr->show = counter_comp_u64_show;
    485		}
    486		if (comp->device_u64_write) {
    487			dev_attr->attr.mode |= 0200;
    488			dev_attr->store = counter_comp_u64_store;
    489		}
    490		break;
    491	default:
    492		return -EINVAL;
    493	}
    494
    495	/* Store list node */
    496	list_add(&counter_attr->l, &group->attr_list);
    497	group->num_attr++;
    498
    499	/* Create "*_available" attribute if needed */
    500	switch (comp->type) {
    501	case COUNTER_COMP_FUNCTION:
    502	case COUNTER_COMP_SYNAPSE_ACTION:
    503	case COUNTER_COMP_ENUM:
    504	case COUNTER_COMP_COUNT_MODE:
    505		return counter_avail_attr_create(dev, group, comp, parent);
    506	default:
    507		return 0;
    508	}
    509}
    510
    511static ssize_t counter_comp_name_show(struct device *dev,
    512				      struct device_attribute *attr, char *buf)
    513{
    514	return sysfs_emit(buf, "%s\n", to_counter_attribute(attr)->comp.name);
    515}
    516
    517static int counter_name_attr_create(struct device *const dev,
    518				    struct counter_attribute_group *const group,
    519				    const char *const name)
    520{
    521	struct counter_attribute *counter_attr;
    522
    523	counter_attr = devm_kzalloc(dev, sizeof(*counter_attr), GFP_KERNEL);
    524	if (!counter_attr)
    525		return -ENOMEM;
    526
    527	/* Configure Counter attribute */
    528	counter_attr->comp.name = name;
    529
    530	/* Configure device attribute */
    531	sysfs_attr_init(&counter_attr->dev_attr.attr);
    532	counter_attr->dev_attr.attr.name = "name";
    533	counter_attr->dev_attr.attr.mode = 0444;
    534	counter_attr->dev_attr.show = counter_comp_name_show;
    535
    536	/* Store list node */
    537	list_add(&counter_attr->l, &group->attr_list);
    538	group->num_attr++;
    539
    540	return 0;
    541}
    542
    543static ssize_t counter_comp_id_show(struct device *dev,
    544				    struct device_attribute *attr, char *buf)
    545{
    546	const size_t id = (size_t)to_counter_attribute(attr)->comp.priv;
    547
    548	return sysfs_emit(buf, "%zu\n", id);
    549}
    550
    551static int counter_comp_id_attr_create(struct device *const dev,
    552				       struct counter_attribute_group *const group,
    553				       const char *name, const size_t id)
    554{
    555	struct counter_attribute *counter_attr;
    556
    557	/* Allocate Counter attribute */
    558	counter_attr = devm_kzalloc(dev, sizeof(*counter_attr), GFP_KERNEL);
    559	if (!counter_attr)
    560		return -ENOMEM;
    561
    562	/* Generate component ID name */
    563	name = devm_kasprintf(dev, GFP_KERNEL, "%s_component_id", name);
    564	if (!name)
    565		return -ENOMEM;
    566
    567	/* Configure Counter attribute */
    568	counter_attr->comp.priv = (void *)id;
    569
    570	/* Configure device attribute */
    571	sysfs_attr_init(&counter_attr->dev_attr.attr);
    572	counter_attr->dev_attr.attr.name = name;
    573	counter_attr->dev_attr.attr.mode = 0444;
    574	counter_attr->dev_attr.show = counter_comp_id_show;
    575
    576	/* Store list node */
    577	list_add(&counter_attr->l, &group->attr_list);
    578	group->num_attr++;
    579
    580	return 0;
    581}
    582
    583static struct counter_comp counter_signal_comp = {
    584	.type = COUNTER_COMP_SIGNAL_LEVEL,
    585	.name = "signal",
    586};
    587
    588static int counter_signal_attrs_create(struct counter_device *const counter,
    589	struct counter_attribute_group *const cattr_group,
    590	struct counter_signal *const signal)
    591{
    592	const enum counter_scope scope = COUNTER_SCOPE_SIGNAL;
    593	struct device *const dev = &counter->dev;
    594	int err;
    595	struct counter_comp comp;
    596	size_t i;
    597	struct counter_comp *ext;
    598
    599	/* Create main Signal attribute */
    600	comp = counter_signal_comp;
    601	comp.signal_u32_read = counter->ops->signal_read;
    602	err = counter_attr_create(dev, cattr_group, &comp, scope, signal);
    603	if (err < 0)
    604		return err;
    605
    606	/* Create Signal name attribute */
    607	err = counter_name_attr_create(dev, cattr_group, signal->name);
    608	if (err < 0)
    609		return err;
    610
    611	/* Create an attribute for each extension */
    612	for (i = 0; i < signal->num_ext; i++) {
    613		ext = &signal->ext[i];
    614
    615		err = counter_attr_create(dev, cattr_group, ext, scope, signal);
    616		if (err < 0)
    617			return err;
    618
    619		err = counter_comp_id_attr_create(dev, cattr_group, ext->name,
    620						  i);
    621		if (err < 0)
    622			return err;
    623	}
    624
    625	return 0;
    626}
    627
    628static int counter_sysfs_signals_add(struct counter_device *const counter,
    629	struct counter_attribute_group *const groups)
    630{
    631	size_t i;
    632	int err;
    633
    634	/* Add each Signal */
    635	for (i = 0; i < counter->num_signals; i++) {
    636		/* Generate Signal attribute directory name */
    637		groups[i].name = devm_kasprintf(&counter->dev, GFP_KERNEL,
    638						"signal%zu", i);
    639		if (!groups[i].name)
    640			return -ENOMEM;
    641
    642		/* Create all attributes associated with Signal */
    643		err = counter_signal_attrs_create(counter, groups + i,
    644						  counter->signals + i);
    645		if (err < 0)
    646			return err;
    647	}
    648
    649	return 0;
    650}
    651
    652static int counter_sysfs_synapses_add(struct counter_device *const counter,
    653	struct counter_attribute_group *const group,
    654	struct counter_count *const count)
    655{
    656	size_t i;
    657
    658	/* Add each Synapse */
    659	for (i = 0; i < count->num_synapses; i++) {
    660		struct device *const dev = &counter->dev;
    661		struct counter_synapse *synapse;
    662		size_t id;
    663		struct counter_comp comp;
    664		int err;
    665
    666		synapse = count->synapses + i;
    667
    668		/* Generate Synapse action name */
    669		id = synapse->signal - counter->signals;
    670		comp.name = devm_kasprintf(dev, GFP_KERNEL, "signal%zu_action",
    671					   id);
    672		if (!comp.name)
    673			return -ENOMEM;
    674
    675		/* Create action attribute */
    676		comp.type = COUNTER_COMP_SYNAPSE_ACTION;
    677		comp.action_read = counter->ops->action_read;
    678		comp.action_write = counter->ops->action_write;
    679		comp.priv = synapse;
    680		err = counter_attr_create(dev, group, &comp,
    681					  COUNTER_SCOPE_COUNT, count);
    682		if (err < 0)
    683			return err;
    684
    685		/* Create Synapse component ID attribute */
    686		err = counter_comp_id_attr_create(dev, group, comp.name, i);
    687		if (err < 0)
    688			return err;
    689	}
    690
    691	return 0;
    692}
    693
    694static struct counter_comp counter_count_comp =
    695	COUNTER_COMP_COUNT_U64("count", NULL, NULL);
    696
    697static struct counter_comp counter_function_comp = {
    698	.type = COUNTER_COMP_FUNCTION,
    699	.name = "function",
    700};
    701
    702static int counter_count_attrs_create(struct counter_device *const counter,
    703	struct counter_attribute_group *const cattr_group,
    704	struct counter_count *const count)
    705{
    706	const enum counter_scope scope = COUNTER_SCOPE_COUNT;
    707	struct device *const dev = &counter->dev;
    708	int err;
    709	struct counter_comp comp;
    710	size_t i;
    711	struct counter_comp *ext;
    712
    713	/* Create main Count attribute */
    714	comp = counter_count_comp;
    715	comp.count_u64_read = counter->ops->count_read;
    716	comp.count_u64_write = counter->ops->count_write;
    717	err = counter_attr_create(dev, cattr_group, &comp, scope, count);
    718	if (err < 0)
    719		return err;
    720
    721	/* Create Count name attribute */
    722	err = counter_name_attr_create(dev, cattr_group, count->name);
    723	if (err < 0)
    724		return err;
    725
    726	/* Create Count function attribute */
    727	comp = counter_function_comp;
    728	comp.count_u32_read = counter->ops->function_read;
    729	comp.count_u32_write = counter->ops->function_write;
    730	err = counter_attr_create(dev, cattr_group, &comp, scope, count);
    731	if (err < 0)
    732		return err;
    733
    734	/* Create an attribute for each extension */
    735	for (i = 0; i < count->num_ext; i++) {
    736		ext = &count->ext[i];
    737
    738		err = counter_attr_create(dev, cattr_group, ext, scope, count);
    739		if (err < 0)
    740			return err;
    741
    742		err = counter_comp_id_attr_create(dev, cattr_group, ext->name,
    743						  i);
    744		if (err < 0)
    745			return err;
    746	}
    747
    748	return 0;
    749}
    750
    751static int counter_sysfs_counts_add(struct counter_device *const counter,
    752	struct counter_attribute_group *const groups)
    753{
    754	size_t i;
    755	struct counter_count *count;
    756	int err;
    757
    758	/* Add each Count */
    759	for (i = 0; i < counter->num_counts; i++) {
    760		count = counter->counts + i;
    761
    762		/* Generate Count attribute directory name */
    763		groups[i].name = devm_kasprintf(&counter->dev, GFP_KERNEL,
    764						"count%zu", i);
    765		if (!groups[i].name)
    766			return -ENOMEM;
    767
    768		/* Add sysfs attributes of the Synapses */
    769		err = counter_sysfs_synapses_add(counter, groups + i, count);
    770		if (err < 0)
    771			return err;
    772
    773		/* Create all attributes associated with Count */
    774		err = counter_count_attrs_create(counter, groups + i, count);
    775		if (err < 0)
    776			return err;
    777	}
    778
    779	return 0;
    780}
    781
    782static int counter_num_signals_read(struct counter_device *counter, u8 *val)
    783{
    784	*val = counter->num_signals;
    785	return 0;
    786}
    787
    788static int counter_num_counts_read(struct counter_device *counter, u8 *val)
    789{
    790	*val = counter->num_counts;
    791	return 0;
    792}
    793
    794static int counter_events_queue_size_read(struct counter_device *counter,
    795					  u64 *val)
    796{
    797	*val = kfifo_size(&counter->events);
    798	return 0;
    799}
    800
    801static int counter_events_queue_size_write(struct counter_device *counter,
    802					   u64 val)
    803{
    804	DECLARE_KFIFO_PTR(events, struct counter_event);
    805	int err;
    806	unsigned long flags;
    807
    808	/* Allocate new events queue */
    809	err = kfifo_alloc(&events, val, GFP_KERNEL);
    810	if (err)
    811		return err;
    812
    813	/* Swap in new events queue */
    814	mutex_lock(&counter->events_out_lock);
    815	spin_lock_irqsave(&counter->events_in_lock, flags);
    816	kfifo_free(&counter->events);
    817	counter->events.kfifo = events.kfifo;
    818	spin_unlock_irqrestore(&counter->events_in_lock, flags);
    819	mutex_unlock(&counter->events_out_lock);
    820
    821	return 0;
    822}
    823
    824static struct counter_comp counter_num_signals_comp =
    825	COUNTER_COMP_DEVICE_U8("num_signals", counter_num_signals_read, NULL);
    826
    827static struct counter_comp counter_num_counts_comp =
    828	COUNTER_COMP_DEVICE_U8("num_counts", counter_num_counts_read, NULL);
    829
    830static struct counter_comp counter_events_queue_size_comp =
    831	COUNTER_COMP_DEVICE_U64("events_queue_size",
    832				counter_events_queue_size_read,
    833				counter_events_queue_size_write);
    834
    835static int counter_sysfs_attr_add(struct counter_device *const counter,
    836				  struct counter_attribute_group *cattr_group)
    837{
    838	const enum counter_scope scope = COUNTER_SCOPE_DEVICE;
    839	struct device *const dev = &counter->dev;
    840	int err;
    841	size_t i;
    842	struct counter_comp *ext;
    843
    844	/* Add Signals sysfs attributes */
    845	err = counter_sysfs_signals_add(counter, cattr_group);
    846	if (err < 0)
    847		return err;
    848	cattr_group += counter->num_signals;
    849
    850	/* Add Counts sysfs attributes */
    851	err = counter_sysfs_counts_add(counter, cattr_group);
    852	if (err < 0)
    853		return err;
    854	cattr_group += counter->num_counts;
    855
    856	/* Create name attribute */
    857	err = counter_name_attr_create(dev, cattr_group, counter->name);
    858	if (err < 0)
    859		return err;
    860
    861	/* Create num_signals attribute */
    862	err = counter_attr_create(dev, cattr_group, &counter_num_signals_comp,
    863				  scope, NULL);
    864	if (err < 0)
    865		return err;
    866
    867	/* Create num_counts attribute */
    868	err = counter_attr_create(dev, cattr_group, &counter_num_counts_comp,
    869				  scope, NULL);
    870	if (err < 0)
    871		return err;
    872
    873	/* Create events_queue_size attribute */
    874	err = counter_attr_create(dev, cattr_group,
    875				  &counter_events_queue_size_comp, scope, NULL);
    876	if (err < 0)
    877		return err;
    878
    879	/* Create an attribute for each extension */
    880	for (i = 0; i < counter->num_ext; i++) {
    881		ext = &counter->ext[i];
    882
    883		err = counter_attr_create(dev, cattr_group, ext, scope, NULL);
    884		if (err < 0)
    885			return err;
    886
    887		err = counter_comp_id_attr_create(dev, cattr_group, ext->name,
    888						  i);
    889		if (err < 0)
    890			return err;
    891	}
    892
    893	return 0;
    894}
    895
    896/**
    897 * counter_sysfs_add - Adds Counter sysfs attributes to the device structure
    898 * @counter:	Pointer to the Counter device structure
    899 *
    900 * Counter sysfs attributes are created and added to the respective device
    901 * structure for later registration to the system. Resource-managed memory
    902 * allocation is performed by this function, and this memory should be freed
    903 * when no longer needed (automatically by a device_unregister call, or
    904 * manually by a devres_release_all call).
    905 */
    906int counter_sysfs_add(struct counter_device *const counter)
    907{
    908	struct device *const dev = &counter->dev;
    909	const size_t num_groups = counter->num_signals + counter->num_counts + 1;
    910	struct counter_attribute_group *cattr_groups;
    911	size_t i, j;
    912	int err;
    913	struct attribute_group *groups;
    914	struct counter_attribute *p;
    915
    916	/* Allocate space for attribute groups (signals, counts, and ext) */
    917	cattr_groups = devm_kcalloc(dev, num_groups, sizeof(*cattr_groups),
    918				    GFP_KERNEL);
    919	if (!cattr_groups)
    920		return -ENOMEM;
    921
    922	/* Initialize attribute lists */
    923	for (i = 0; i < num_groups; i++)
    924		INIT_LIST_HEAD(&cattr_groups[i].attr_list);
    925
    926	/* Add Counter device sysfs attributes */
    927	err = counter_sysfs_attr_add(counter, cattr_groups);
    928	if (err < 0)
    929		return err;
    930
    931	/* Allocate attribute group pointers for association with device */
    932	dev->groups = devm_kcalloc(dev, num_groups + 1, sizeof(*dev->groups),
    933				   GFP_KERNEL);
    934	if (!dev->groups)
    935		return -ENOMEM;
    936
    937	/* Allocate space for attribute groups */
    938	groups = devm_kcalloc(dev, num_groups, sizeof(*groups), GFP_KERNEL);
    939	if (!groups)
    940		return -ENOMEM;
    941
    942	/* Prepare each group of attributes for association */
    943	for (i = 0; i < num_groups; i++) {
    944		groups[i].name = cattr_groups[i].name;
    945
    946		/* Allocate space for attribute pointers */
    947		groups[i].attrs = devm_kcalloc(dev,
    948					       cattr_groups[i].num_attr + 1,
    949					       sizeof(*groups[i].attrs),
    950					       GFP_KERNEL);
    951		if (!groups[i].attrs)
    952			return -ENOMEM;
    953
    954		/* Add attribute pointers to attribute group */
    955		j = 0;
    956		list_for_each_entry(p, &cattr_groups[i].attr_list, l)
    957			groups[i].attrs[j++] = &p->dev_attr.attr;
    958
    959		/* Associate attribute group */
    960		dev->groups[i] = &groups[i];
    961	}
    962
    963	return 0;
    964}