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	[COUNTER_COUNT_MODE_INTERRUPT_ON_TERMINAL_COUNT] = "interrupt on terminal count",
93	[COUNTER_COUNT_MODE_HARDWARE_RETRIGGERABLE_ONESHOT] = "hardware retriggerable one-shot",
94	[COUNTER_COUNT_MODE_RATE_GENERATOR] = "rate generator",
95	[COUNTER_COUNT_MODE_SQUARE_WAVE_MODE] = "square wave mode",
96	[COUNTER_COUNT_MODE_SOFTWARE_TRIGGERED_STROBE] = "software triggered strobe",
97	[COUNTER_COUNT_MODE_HARDWARE_TRIGGERED_STROBE] = "hardware triggered strobe",
98};
99
100static const char *const counter_signal_polarity_str[] = {
101	[COUNTER_SIGNAL_POLARITY_POSITIVE] = "positive",
102	[COUNTER_SIGNAL_POLARITY_NEGATIVE] = "negative"
103};
104
105static ssize_t counter_comp_u8_show(struct device *dev,
106				    struct device_attribute *attr, char *buf)
107{
108	const struct counter_attribute *const a = to_counter_attribute(attr);
109	struct counter_device *const counter = counter_from_dev(dev);
110	int err;
111	u8 data = 0;
112
113	switch (a->scope) {
114	case COUNTER_SCOPE_DEVICE:
115		err = a->comp.device_u8_read(counter, &data);
116		break;
117	case COUNTER_SCOPE_SIGNAL:
118		err = a->comp.signal_u8_read(counter, a->parent, &data);
119		break;
120	case COUNTER_SCOPE_COUNT:
121		err = a->comp.count_u8_read(counter, a->parent, &data);
122		break;
123	default:
124		return -EINVAL;
125	}
126	if (err < 0)
127		return err;
128
129	if (a->comp.type == COUNTER_COMP_BOOL)
130		/* data should already be boolean but ensure just to be safe */
131		data = !!data;
132
133	return sysfs_emit(buf, "%u\n", (unsigned int)data);
134}
135
136static ssize_t counter_comp_u8_store(struct device *dev,
137				     struct device_attribute *attr,
138				     const char *buf, size_t len)
139{
140	const struct counter_attribute *const a = to_counter_attribute(attr);
141	struct counter_device *const counter = counter_from_dev(dev);
142	int err;
143	bool bool_data = 0;
144	u8 data = 0;
145
146	if (a->comp.type == COUNTER_COMP_BOOL) {
147		err = kstrtobool(buf, &bool_data);
148		data = bool_data;
149	} else
150		err = kstrtou8(buf, 0, &data);
151	if (err < 0)
152		return err;
153
154	switch (a->scope) {
155	case COUNTER_SCOPE_DEVICE:
156		err = a->comp.device_u8_write(counter, data);
157		break;
158	case COUNTER_SCOPE_SIGNAL:
159		err = a->comp.signal_u8_write(counter, a->parent, data);
160		break;
161	case COUNTER_SCOPE_COUNT:
162		err = a->comp.count_u8_write(counter, a->parent, data);
163		break;
164	default:
165		return -EINVAL;
166	}
167	if (err < 0)
168		return err;
169
170	return len;
171}
172
173static ssize_t counter_comp_u32_show(struct device *dev,
174				     struct device_attribute *attr, char *buf)
175{
176	const struct counter_attribute *const a = to_counter_attribute(attr);
177	struct counter_device *const counter = counter_from_dev(dev);
178	const struct counter_available *const avail = a->comp.priv;
179	int err;
180	u32 data = 0;
181
182	switch (a->scope) {
183	case COUNTER_SCOPE_DEVICE:
184		err = a->comp.device_u32_read(counter, &data);
185		break;
186	case COUNTER_SCOPE_SIGNAL:
187		err = a->comp.signal_u32_read(counter, a->parent, &data);
188		break;
189	case COUNTER_SCOPE_COUNT:
190		if (a->comp.type == COUNTER_COMP_SYNAPSE_ACTION)
191			err = a->comp.action_read(counter, a->parent,
192						  a->comp.priv, &data);
193		else
194			err = a->comp.count_u32_read(counter, a->parent, &data);
195		break;
196	default:
197		return -EINVAL;
198	}
199	if (err < 0)
200		return err;
201
202	switch (a->comp.type) {
203	case COUNTER_COMP_FUNCTION:
204		return sysfs_emit(buf, "%s\n", counter_function_str[data]);
205	case COUNTER_COMP_SIGNAL_LEVEL:
206		return sysfs_emit(buf, "%s\n", counter_signal_value_str[data]);
207	case COUNTER_COMP_SYNAPSE_ACTION:
208		return sysfs_emit(buf, "%s\n", counter_synapse_action_str[data]);
209	case COUNTER_COMP_ENUM:
210		return sysfs_emit(buf, "%s\n", avail->strs[data]);
211	case COUNTER_COMP_COUNT_DIRECTION:
212		return sysfs_emit(buf, "%s\n", counter_count_direction_str[data]);
213	case COUNTER_COMP_COUNT_MODE:
214		return sysfs_emit(buf, "%s\n", counter_count_mode_str[data]);
215	case COUNTER_COMP_SIGNAL_POLARITY:
216		return sysfs_emit(buf, "%s\n", counter_signal_polarity_str[data]);
217	default:
218		return sysfs_emit(buf, "%u\n", (unsigned int)data);
219	}
220}
221
222static int counter_find_enum(u32 *const enum_item, const u32 *const enums,
223			     const size_t num_enums, const char *const buf,
224			     const char *const string_array[])
225{
226	size_t index;
227
228	for (index = 0; index < num_enums; index++) {
229		*enum_item = enums[index];
230		if (sysfs_streq(buf, string_array[*enum_item]))
231			return 0;
232	}
233
234	return -EINVAL;
235}
236
237static ssize_t counter_comp_u32_store(struct device *dev,
238				      struct device_attribute *attr,
239				      const char *buf, size_t len)
240{
241	const struct counter_attribute *const a = to_counter_attribute(attr);
242	struct counter_device *const counter = counter_from_dev(dev);
243	struct counter_count *const count = a->parent;
244	struct counter_synapse *const synapse = a->comp.priv;
245	const struct counter_available *const avail = a->comp.priv;
246	int err;
247	u32 data = 0;
248
249	switch (a->comp.type) {
250	case COUNTER_COMP_FUNCTION:
251		err = counter_find_enum(&data, count->functions_list,
252					count->num_functions, buf,
253					counter_function_str);
254		break;
255	case COUNTER_COMP_SYNAPSE_ACTION:
256		err = counter_find_enum(&data, synapse->actions_list,
257					synapse->num_actions, buf,
258					counter_synapse_action_str);
259		break;
260	case COUNTER_COMP_ENUM:
261		err = __sysfs_match_string(avail->strs, avail->num_items, buf);
262		data = err;
263		break;
264	case COUNTER_COMP_COUNT_MODE:
265		err = counter_find_enum(&data, avail->enums, avail->num_items,
266					buf, counter_count_mode_str);
267		break;
268	case COUNTER_COMP_SIGNAL_POLARITY:
269		err = counter_find_enum(&data, avail->enums, avail->num_items,
270					buf, counter_signal_polarity_str);
271		break;
272	default:
273		err = kstrtou32(buf, 0, &data);
274		break;
275	}
276	if (err < 0)
277		return err;
278
279	switch (a->scope) {
280	case COUNTER_SCOPE_DEVICE:
281		err = a->comp.device_u32_write(counter, data);
282		break;
283	case COUNTER_SCOPE_SIGNAL:
284		err = a->comp.signal_u32_write(counter, a->parent, data);
285		break;
286	case COUNTER_SCOPE_COUNT:
287		if (a->comp.type == COUNTER_COMP_SYNAPSE_ACTION)
288			err = a->comp.action_write(counter, count, synapse,
289						   data);
290		else
291			err = a->comp.count_u32_write(counter, count, data);
292		break;
293	default:
294		return -EINVAL;
295	}
296	if (err < 0)
297		return err;
298
299	return len;
300}
301
302static ssize_t counter_comp_u64_show(struct device *dev,
303				     struct device_attribute *attr, char *buf)
304{
305	const struct counter_attribute *const a = to_counter_attribute(attr);
306	struct counter_device *const counter = counter_from_dev(dev);
307	int err;
308	u64 data = 0;
309
310	switch (a->scope) {
311	case COUNTER_SCOPE_DEVICE:
312		err = a->comp.device_u64_read(counter, &data);
313		break;
314	case COUNTER_SCOPE_SIGNAL:
315		err = a->comp.signal_u64_read(counter, a->parent, &data);
316		break;
317	case COUNTER_SCOPE_COUNT:
318		err = a->comp.count_u64_read(counter, a->parent, &data);
319		break;
320	default:
321		return -EINVAL;
322	}
323	if (err < 0)
324		return err;
325
326	return sysfs_emit(buf, "%llu\n", (unsigned long long)data);
327}
328
329static ssize_t counter_comp_u64_store(struct device *dev,
330				      struct device_attribute *attr,
331				      const char *buf, size_t len)
332{
333	const struct counter_attribute *const a = to_counter_attribute(attr);
334	struct counter_device *const counter = counter_from_dev(dev);
335	int err;
336	u64 data = 0;
337
338	err = kstrtou64(buf, 0, &data);
339	if (err < 0)
340		return err;
341
342	switch (a->scope) {
343	case COUNTER_SCOPE_DEVICE:
344		err = a->comp.device_u64_write(counter, data);
345		break;
346	case COUNTER_SCOPE_SIGNAL:
347		err = a->comp.signal_u64_write(counter, a->parent, data);
348		break;
349	case COUNTER_SCOPE_COUNT:
350		err = a->comp.count_u64_write(counter, a->parent, data);
351		break;
352	default:
353		return -EINVAL;
354	}
355	if (err < 0)
356		return err;
357
358	return len;
359}
360
361static ssize_t counter_comp_array_u32_show(struct device *dev,
362					   struct device_attribute *attr,
363					   char *buf)
364{
365	const struct counter_attribute *const a = to_counter_attribute(attr);
366	struct counter_device *const counter = counter_from_dev(dev);
367	const struct counter_array *const element = a->comp.priv;
368	int err;
369	u32 data = 0;
370
371	if (a->scope != COUNTER_SCOPE_SIGNAL ||
372	    element->type != COUNTER_COMP_SIGNAL_POLARITY)
373		return -EINVAL;
374
375	err = a->comp.signal_array_u32_read(counter, a->parent, element->idx,
376					    &data);
377	if (err < 0)
378		return err;
379
380	return sysfs_emit(buf, "%s\n", counter_signal_polarity_str[data]);
381}
382
383static ssize_t counter_comp_array_u32_store(struct device *dev,
384					    struct device_attribute *attr,
385					    const char *buf, size_t len)
386{
387	const struct counter_attribute *const a = to_counter_attribute(attr);
388	struct counter_device *const counter = counter_from_dev(dev);
389	const struct counter_array *const element = a->comp.priv;
390	int err;
391	u32 data = 0;
392
393	if (element->type != COUNTER_COMP_SIGNAL_POLARITY ||
394	    a->scope != COUNTER_SCOPE_SIGNAL)
395		return -EINVAL;
396
397	err = counter_find_enum(&data, element->avail->enums,
398				element->avail->num_items, buf,
399				counter_signal_polarity_str);
400	if (err < 0)
401		return err;
402
403	err = a->comp.signal_array_u32_write(counter, a->parent, element->idx,
404					     data);
405	if (err < 0)
406		return err;
407
408	return len;
409}
410
411static ssize_t counter_comp_array_u64_show(struct device *dev,
412					   struct device_attribute *attr,
413					   char *buf)
414{
415	const struct counter_attribute *const a = to_counter_attribute(attr);
416	struct counter_device *const counter = counter_from_dev(dev);
417	const struct counter_array *const element = a->comp.priv;
418	int err;
419	u64 data = 0;
420
421	switch (a->scope) {
422	case COUNTER_SCOPE_DEVICE:
423		err = a->comp.device_array_u64_read(counter, element->idx,
424						    &data);
425		break;
426	case COUNTER_SCOPE_SIGNAL:
427		err = a->comp.signal_array_u64_read(counter, a->parent,
428						    element->idx, &data);
429		break;
430	case COUNTER_SCOPE_COUNT:
431		err = a->comp.count_array_u64_read(counter, a->parent,
432						   element->idx, &data);
433		break;
434	default:
435		return -EINVAL;
436	}
437	if (err < 0)
438		return err;
439
440	return sysfs_emit(buf, "%llu\n", (unsigned long long)data);
441}
442
443static ssize_t counter_comp_array_u64_store(struct device *dev,
444					    struct device_attribute *attr,
445					    const char *buf, size_t len)
446{
447	const struct counter_attribute *const a = to_counter_attribute(attr);
448	struct counter_device *const counter = counter_from_dev(dev);
449	const struct counter_array *const element = a->comp.priv;
450	int err;
451	u64 data = 0;
452
453	err = kstrtou64(buf, 0, &data);
454	if (err < 0)
455		return err;
456
457	switch (a->scope) {
458	case COUNTER_SCOPE_DEVICE:
459		err = a->comp.device_array_u64_write(counter, element->idx,
460						     data);
461		break;
462	case COUNTER_SCOPE_SIGNAL:
463		err = a->comp.signal_array_u64_write(counter, a->parent,
464						     element->idx, data);
465		break;
466	case COUNTER_SCOPE_COUNT:
467		err = a->comp.count_array_u64_write(counter, a->parent,
468						    element->idx, data);
469		break;
470	default:
471		return -EINVAL;
472	}
473	if (err < 0)
474		return err;
475
476	return len;
477}
478
479static ssize_t enums_available_show(const u32 *const enums,
480				    const size_t num_enums,
481				    const char *const strs[], char *buf)
482{
483	size_t len = 0;
484	size_t index;
485
486	for (index = 0; index < num_enums; index++)
487		len += sysfs_emit_at(buf, len, "%s\n", strs[enums[index]]);
488
489	return len;
490}
491
492static ssize_t strs_available_show(const struct counter_available *const avail,
493				   char *buf)
494{
495	size_t len = 0;
496	size_t index;
497
498	for (index = 0; index < avail->num_items; index++)
499		len += sysfs_emit_at(buf, len, "%s\n", avail->strs[index]);
500
501	return len;
502}
503
504static ssize_t counter_comp_available_show(struct device *dev,
505					   struct device_attribute *attr,
506					   char *buf)
507{
508	const struct counter_attribute *const a = to_counter_attribute(attr);
509	const struct counter_count *const count = a->parent;
510	const struct counter_synapse *const synapse = a->comp.priv;
511	const struct counter_available *const avail = a->comp.priv;
512
513	switch (a->comp.type) {
514	case COUNTER_COMP_FUNCTION:
515		return enums_available_show(count->functions_list,
516					    count->num_functions,
517					    counter_function_str, buf);
518	case COUNTER_COMP_SYNAPSE_ACTION:
519		return enums_available_show(synapse->actions_list,
520					    synapse->num_actions,
521					    counter_synapse_action_str, buf);
522	case COUNTER_COMP_ENUM:
523		return strs_available_show(avail, buf);
524	case COUNTER_COMP_COUNT_MODE:
525		return enums_available_show(avail->enums, avail->num_items,
526					    counter_count_mode_str, buf);
527	default:
528		return -EINVAL;
529	}
530}
531
532static int counter_avail_attr_create(struct device *const dev,
533	struct counter_attribute_group *const group,
534	const struct counter_comp *const comp, void *const parent)
535{
536	struct counter_attribute *counter_attr;
537	struct device_attribute *dev_attr;
538
539	counter_attr = devm_kzalloc(dev, sizeof(*counter_attr), GFP_KERNEL);
540	if (!counter_attr)
541		return -ENOMEM;
542
543	/* Configure Counter attribute */
544	counter_attr->comp.type = comp->type;
545	counter_attr->comp.priv = comp->priv;
546	counter_attr->parent = parent;
547
548	/* Initialize sysfs attribute */
549	dev_attr = &counter_attr->dev_attr;
550	sysfs_attr_init(&dev_attr->attr);
551
552	/* Configure device attribute */
553	dev_attr->attr.name = devm_kasprintf(dev, GFP_KERNEL, "%s_available",
554					     comp->name);
555	if (!dev_attr->attr.name)
556		return -ENOMEM;
557	dev_attr->attr.mode = 0444;
558	dev_attr->show = counter_comp_available_show;
559
560	/* Store list node */
561	list_add(&counter_attr->l, &group->attr_list);
562	group->num_attr++;
563
564	return 0;
565}
566
567static int counter_attr_create(struct device *const dev,
568			       struct counter_attribute_group *const group,
569			       const struct counter_comp *const comp,
570			       const enum counter_scope scope,
571			       void *const parent)
572{
573	const struct counter_array *const array = comp->priv;
574	struct counter_attribute *counter_attr;
575	struct device_attribute *dev_attr;
576
577	counter_attr = devm_kzalloc(dev, sizeof(*counter_attr), GFP_KERNEL);
578	if (!counter_attr)
579		return -ENOMEM;
580
581	/* Configure Counter attribute */
582	counter_attr->comp = *comp;
583	counter_attr->scope = scope;
584	counter_attr->parent = parent;
585
586	/* Configure device attribute */
587	dev_attr = &counter_attr->dev_attr;
588	sysfs_attr_init(&dev_attr->attr);
589	dev_attr->attr.name = comp->name;
590	switch (comp->type) {
591	case COUNTER_COMP_U8:
592	case COUNTER_COMP_BOOL:
593		if (comp->device_u8_read) {
594			dev_attr->attr.mode |= 0444;
595			dev_attr->show = counter_comp_u8_show;
596		}
597		if (comp->device_u8_write) {
598			dev_attr->attr.mode |= 0200;
599			dev_attr->store = counter_comp_u8_store;
600		}
601		break;
602	case COUNTER_COMP_SIGNAL_LEVEL:
603	case COUNTER_COMP_FUNCTION:
604	case COUNTER_COMP_SYNAPSE_ACTION:
605	case COUNTER_COMP_ENUM:
606	case COUNTER_COMP_COUNT_DIRECTION:
607	case COUNTER_COMP_COUNT_MODE:
608	case COUNTER_COMP_SIGNAL_POLARITY:
609		if (comp->device_u32_read) {
610			dev_attr->attr.mode |= 0444;
611			dev_attr->show = counter_comp_u32_show;
612		}
613		if (comp->device_u32_write) {
614			dev_attr->attr.mode |= 0200;
615			dev_attr->store = counter_comp_u32_store;
616		}
617		break;
618	case COUNTER_COMP_U64:
619		if (comp->device_u64_read) {
620			dev_attr->attr.mode |= 0444;
621			dev_attr->show = counter_comp_u64_show;
622		}
623		if (comp->device_u64_write) {
624			dev_attr->attr.mode |= 0200;
625			dev_attr->store = counter_comp_u64_store;
626		}
627		break;
628	case COUNTER_COMP_ARRAY:
629		switch (array->type) {
630		case COUNTER_COMP_SIGNAL_POLARITY:
631			if (comp->signal_array_u32_read) {
632				dev_attr->attr.mode |= 0444;
633				dev_attr->show = counter_comp_array_u32_show;
634			}
635			if (comp->signal_array_u32_write) {
636				dev_attr->attr.mode |= 0200;
637				dev_attr->store = counter_comp_array_u32_store;
638			}
639			break;
640		case COUNTER_COMP_U64:
641			if (comp->device_array_u64_read) {
642				dev_attr->attr.mode |= 0444;
643				dev_attr->show = counter_comp_array_u64_show;
644			}
645			if (comp->device_array_u64_write) {
646				dev_attr->attr.mode |= 0200;
647				dev_attr->store = counter_comp_array_u64_store;
648			}
649			break;
650		default:
651			return -EINVAL;
652		}
653		break;
654	default:
655		return -EINVAL;
656	}
657
658	/* Store list node */
659	list_add(&counter_attr->l, &group->attr_list);
660	group->num_attr++;
661
662	/* Create "*_available" attribute if needed */
663	switch (comp->type) {
664	case COUNTER_COMP_FUNCTION:
665	case COUNTER_COMP_SYNAPSE_ACTION:
666	case COUNTER_COMP_ENUM:
667	case COUNTER_COMP_COUNT_MODE:
668		return counter_avail_attr_create(dev, group, comp, parent);
669	default:
670		return 0;
671	}
672}
673
674static ssize_t counter_comp_name_show(struct device *dev,
675				      struct device_attribute *attr, char *buf)
676{
677	return sysfs_emit(buf, "%s\n", to_counter_attribute(attr)->comp.name);
678}
679
680static int counter_name_attr_create(struct device *const dev,
681				    struct counter_attribute_group *const group,
682				    const char *const name)
683{
684	struct counter_attribute *counter_attr;
685
686	counter_attr = devm_kzalloc(dev, sizeof(*counter_attr), GFP_KERNEL);
687	if (!counter_attr)
688		return -ENOMEM;
689
690	/* Configure Counter attribute */
691	counter_attr->comp.name = name;
692
693	/* Configure device attribute */
694	sysfs_attr_init(&counter_attr->dev_attr.attr);
695	counter_attr->dev_attr.attr.name = "name";
696	counter_attr->dev_attr.attr.mode = 0444;
697	counter_attr->dev_attr.show = counter_comp_name_show;
698
699	/* Store list node */
700	list_add(&counter_attr->l, &group->attr_list);
701	group->num_attr++;
702
703	return 0;
704}
705
706static ssize_t counter_comp_id_show(struct device *dev,
707				    struct device_attribute *attr, char *buf)
708{
709	const size_t id = (size_t)to_counter_attribute(attr)->comp.priv;
710
711	return sysfs_emit(buf, "%zu\n", id);
712}
713
714static int counter_comp_id_attr_create(struct device *const dev,
715				       struct counter_attribute_group *const group,
716				       const char *name, const size_t id)
717{
718	struct counter_attribute *counter_attr;
719
720	/* Allocate Counter attribute */
721	counter_attr = devm_kzalloc(dev, sizeof(*counter_attr), GFP_KERNEL);
722	if (!counter_attr)
723		return -ENOMEM;
724
725	/* Generate component ID name */
726	name = devm_kasprintf(dev, GFP_KERNEL, "%s_component_id", name);
727	if (!name)
728		return -ENOMEM;
729
730	/* Configure Counter attribute */
731	counter_attr->comp.priv = (void *)id;
732
733	/* Configure device attribute */
734	sysfs_attr_init(&counter_attr->dev_attr.attr);
735	counter_attr->dev_attr.attr.name = name;
736	counter_attr->dev_attr.attr.mode = 0444;
737	counter_attr->dev_attr.show = counter_comp_id_show;
738
739	/* Store list node */
740	list_add(&counter_attr->l, &group->attr_list);
741	group->num_attr++;
742
743	return 0;
744}
745
746static int counter_ext_attrs_create(struct device *const dev,
747				    struct counter_attribute_group *const group,
748				    const struct counter_comp *const ext,
749				    const enum counter_scope scope,
750				    void *const parent, const size_t id)
751{
752	int err;
753
754	/* Create main extension attribute */
755	err = counter_attr_create(dev, group, ext, scope, parent);
756	if (err < 0)
757		return err;
758
759	/* Create extension id attribute */
760	return counter_comp_id_attr_create(dev, group, ext->name, id);
761}
762
763static int counter_array_attrs_create(struct device *const dev,
764				      struct counter_attribute_group *const group,
765				      const struct counter_comp *const comp,
766				      const enum counter_scope scope,
767				      void *const parent, const size_t id)
768{
769	const struct counter_array *const array = comp->priv;
770	struct counter_comp ext = *comp;
771	struct counter_array *element;
772	size_t idx;
773	int err;
774
775	/* Create an attribute for each array element */
776	for (idx = 0; idx < array->length; idx++) {
777		/* Generate array element attribute name */
778		ext.name = devm_kasprintf(dev, GFP_KERNEL, "%s%zu", comp->name,
779					  idx);
780		if (!ext.name)
781			return -ENOMEM;
782
783		/* Allocate and configure array element */
784		element = devm_kzalloc(dev, sizeof(*element), GFP_KERNEL);
785		if (!element)
786			return -ENOMEM;
787		element->type = array->type;
788		element->avail = array->avail;
789		element->idx = idx;
790		ext.priv = element;
791
792		/* Create all attributes associated with the array element */
793		err = counter_ext_attrs_create(dev, group, &ext, scope, parent,
794					       id + idx);
795		if (err < 0)
796			return err;
797	}
798
799	return 0;
800}
801
802static int counter_sysfs_exts_add(struct device *const dev,
803				  struct counter_attribute_group *const group,
804				  const struct counter_comp *const exts,
805				  const size_t num_ext,
806				  const enum counter_scope scope,
807				  void *const parent)
808{
809	size_t i;
810	const struct counter_comp *ext;
811	int err;
812	size_t id = 0;
813	const struct counter_array *array;
814
815	/* Create attributes for each extension */
816	for (i = 0; i < num_ext; i++) {
817		ext = &exts[i];
818		if (ext->type == COUNTER_COMP_ARRAY) {
819			err = counter_array_attrs_create(dev, group, ext, scope,
820							 parent, id);
821			array = ext->priv;
822			id += array->length;
823		} else {
824			err = counter_ext_attrs_create(dev, group, ext, scope,
825						       parent, id);
826			id++;
827		}
828		if (err < 0)
829			return err;
830	}
831
832	return 0;
833}
834
835static struct counter_comp counter_signal_comp = {
836	.type = COUNTER_COMP_SIGNAL_LEVEL,
837	.name = "signal",
838};
839
840static int counter_signal_attrs_create(struct counter_device *const counter,
841	struct counter_attribute_group *const cattr_group,
842	struct counter_signal *const signal)
843{
844	const enum counter_scope scope = COUNTER_SCOPE_SIGNAL;
845	struct device *const dev = &counter->dev;
846	int err;
847	struct counter_comp comp;
848
849	/* Create main Signal attribute */
850	comp = counter_signal_comp;
851	comp.signal_u32_read = counter->ops->signal_read;
852	err = counter_attr_create(dev, cattr_group, &comp, scope, signal);
853	if (err < 0)
854		return err;
855
856	/* Create Signal name attribute */
857	err = counter_name_attr_create(dev, cattr_group, signal->name);
858	if (err < 0)
859		return err;
860
861	/* Add Signal extensions */
862	return counter_sysfs_exts_add(dev, cattr_group, signal->ext,
863				      signal->num_ext, scope, signal);
864}
865
866static int counter_sysfs_signals_add(struct counter_device *const counter,
867	struct counter_attribute_group *const groups)
868{
869	size_t i;
870	int err;
871
872	/* Add each Signal */
873	for (i = 0; i < counter->num_signals; i++) {
874		/* Generate Signal attribute directory name */
875		groups[i].name = devm_kasprintf(&counter->dev, GFP_KERNEL,
876						"signal%zu", i);
877		if (!groups[i].name)
878			return -ENOMEM;
879
880		/* Create all attributes associated with Signal */
881		err = counter_signal_attrs_create(counter, groups + i,
882						  counter->signals + i);
883		if (err < 0)
884			return err;
885	}
886
887	return 0;
888}
889
890static int counter_sysfs_synapses_add(struct counter_device *const counter,
891	struct counter_attribute_group *const group,
892	struct counter_count *const count)
893{
894	size_t i;
895
896	/* Add each Synapse */
897	for (i = 0; i < count->num_synapses; i++) {
898		struct device *const dev = &counter->dev;
899		struct counter_synapse *synapse;
900		size_t id;
901		struct counter_comp comp;
902		int err;
903
904		synapse = count->synapses + i;
905
906		/* Generate Synapse action name */
907		id = synapse->signal - counter->signals;
908		comp.name = devm_kasprintf(dev, GFP_KERNEL, "signal%zu_action",
909					   id);
910		if (!comp.name)
911			return -ENOMEM;
912
913		/* Create action attribute */
914		comp.type = COUNTER_COMP_SYNAPSE_ACTION;
915		comp.action_read = counter->ops->action_read;
916		comp.action_write = counter->ops->action_write;
917		comp.priv = synapse;
918		err = counter_attr_create(dev, group, &comp,
919					  COUNTER_SCOPE_COUNT, count);
920		if (err < 0)
921			return err;
922
923		/* Create Synapse component ID attribute */
924		err = counter_comp_id_attr_create(dev, group, comp.name, i);
925		if (err < 0)
926			return err;
927	}
928
929	return 0;
930}
931
932static struct counter_comp counter_count_comp =
933	COUNTER_COMP_COUNT_U64("count", NULL, NULL);
934
935static struct counter_comp counter_function_comp = {
936	.type = COUNTER_COMP_FUNCTION,
937	.name = "function",
938};
939
940static int counter_count_attrs_create(struct counter_device *const counter,
941	struct counter_attribute_group *const cattr_group,
942	struct counter_count *const count)
943{
944	const enum counter_scope scope = COUNTER_SCOPE_COUNT;
945	struct device *const dev = &counter->dev;
946	int err;
947	struct counter_comp comp;
948
949	/* Create main Count attribute */
950	comp = counter_count_comp;
951	comp.count_u64_read = counter->ops->count_read;
952	comp.count_u64_write = counter->ops->count_write;
953	err = counter_attr_create(dev, cattr_group, &comp, scope, count);
954	if (err < 0)
955		return err;
956
957	/* Create Count name attribute */
958	err = counter_name_attr_create(dev, cattr_group, count->name);
959	if (err < 0)
960		return err;
961
962	/* Create Count function attribute */
963	comp = counter_function_comp;
964	comp.count_u32_read = counter->ops->function_read;
965	comp.count_u32_write = counter->ops->function_write;
966	err = counter_attr_create(dev, cattr_group, &comp, scope, count);
967	if (err < 0)
968		return err;
969
970	/* Add Count extensions */
971	return counter_sysfs_exts_add(dev, cattr_group, count->ext,
972				      count->num_ext, scope, count);
973}
974
975static int counter_sysfs_counts_add(struct counter_device *const counter,
976	struct counter_attribute_group *const groups)
977{
978	size_t i;
979	struct counter_count *count;
980	int err;
981
982	/* Add each Count */
983	for (i = 0; i < counter->num_counts; i++) {
984		count = counter->counts + i;
985
986		/* Generate Count attribute directory name */
987		groups[i].name = devm_kasprintf(&counter->dev, GFP_KERNEL,
988						"count%zu", i);
989		if (!groups[i].name)
990			return -ENOMEM;
991
992		/* Add sysfs attributes of the Synapses */
993		err = counter_sysfs_synapses_add(counter, groups + i, count);
994		if (err < 0)
995			return err;
996
997		/* Create all attributes associated with Count */
998		err = counter_count_attrs_create(counter, groups + i, count);
999		if (err < 0)
1000			return err;
1001	}
1002
1003	return 0;
1004}
1005
1006static int counter_num_signals_read(struct counter_device *counter, u8 *val)
1007{
1008	*val = counter->num_signals;
1009	return 0;
1010}
1011
1012static int counter_num_counts_read(struct counter_device *counter, u8 *val)
1013{
1014	*val = counter->num_counts;
1015	return 0;
1016}
1017
1018static int counter_events_queue_size_read(struct counter_device *counter,
1019					  u64 *val)
1020{
1021	*val = kfifo_size(&counter->events);
1022	return 0;
1023}
1024
1025static int counter_events_queue_size_write(struct counter_device *counter,
1026					   u64 val)
1027{
1028	DECLARE_KFIFO_PTR(events, struct counter_event);
1029	int err;
1030	unsigned long flags;
1031
1032	/* Allocate new events queue */
1033	err = kfifo_alloc(&events, val, GFP_KERNEL);
1034	if (err)
1035		return err;
1036
1037	/* Swap in new events queue */
1038	mutex_lock(&counter->events_out_lock);
1039	spin_lock_irqsave(&counter->events_in_lock, flags);
1040	kfifo_free(&counter->events);
1041	counter->events.kfifo = events.kfifo;
1042	spin_unlock_irqrestore(&counter->events_in_lock, flags);
1043	mutex_unlock(&counter->events_out_lock);
1044
1045	return 0;
1046}
1047
1048static struct counter_comp counter_num_signals_comp =
1049	COUNTER_COMP_DEVICE_U8("num_signals", counter_num_signals_read, NULL);
1050
1051static struct counter_comp counter_num_counts_comp =
1052	COUNTER_COMP_DEVICE_U8("num_counts", counter_num_counts_read, NULL);
1053
1054static struct counter_comp counter_events_queue_size_comp =
1055	COUNTER_COMP_DEVICE_U64("events_queue_size",
1056				counter_events_queue_size_read,
1057				counter_events_queue_size_write);
1058
1059static int counter_sysfs_attr_add(struct counter_device *const counter,
1060				  struct counter_attribute_group *cattr_group)
1061{
1062	const enum counter_scope scope = COUNTER_SCOPE_DEVICE;
1063	struct device *const dev = &counter->dev;
1064	int err;
1065
1066	/* Add Signals sysfs attributes */
1067	err = counter_sysfs_signals_add(counter, cattr_group);
1068	if (err < 0)
1069		return err;
1070	cattr_group += counter->num_signals;
1071
1072	/* Add Counts sysfs attributes */
1073	err = counter_sysfs_counts_add(counter, cattr_group);
1074	if (err < 0)
1075		return err;
1076	cattr_group += counter->num_counts;
1077
1078	/* Create name attribute */
1079	err = counter_name_attr_create(dev, cattr_group, counter->name);
1080	if (err < 0)
1081		return err;
1082
1083	/* Create num_signals attribute */
1084	err = counter_attr_create(dev, cattr_group, &counter_num_signals_comp,
1085				  scope, NULL);
1086	if (err < 0)
1087		return err;
1088
1089	/* Create num_counts attribute */
1090	err = counter_attr_create(dev, cattr_group, &counter_num_counts_comp,
1091				  scope, NULL);
1092	if (err < 0)
1093		return err;
1094
1095	/* Create events_queue_size attribute */
1096	err = counter_attr_create(dev, cattr_group,
1097				  &counter_events_queue_size_comp, scope, NULL);
1098	if (err < 0)
1099		return err;
1100
1101	/* Add device extensions */
1102	return counter_sysfs_exts_add(dev, cattr_group, counter->ext,
1103				      counter->num_ext, scope, NULL);
1104
1105	return 0;
1106}
1107
1108/**
1109 * counter_sysfs_add - Adds Counter sysfs attributes to the device structure
1110 * @counter:	Pointer to the Counter device structure
1111 *
1112 * Counter sysfs attributes are created and added to the respective device
1113 * structure for later registration to the system. Resource-managed memory
1114 * allocation is performed by this function, and this memory should be freed
1115 * when no longer needed (automatically by a device_unregister call, or
1116 * manually by a devres_release_all call).
1117 */
1118int counter_sysfs_add(struct counter_device *const counter)
1119{
1120	struct device *const dev = &counter->dev;
1121	const size_t num_groups = counter->num_signals + counter->num_counts + 1;
1122	struct counter_attribute_group *cattr_groups;
1123	size_t i, j;
1124	int err;
1125	struct attribute_group *groups;
1126	struct counter_attribute *p;
1127
1128	/* Allocate space for attribute groups (signals, counts, and ext) */
1129	cattr_groups = devm_kcalloc(dev, num_groups, sizeof(*cattr_groups),
1130				    GFP_KERNEL);
1131	if (!cattr_groups)
1132		return -ENOMEM;
1133
1134	/* Initialize attribute lists */
1135	for (i = 0; i < num_groups; i++)
1136		INIT_LIST_HEAD(&cattr_groups[i].attr_list);
1137
1138	/* Add Counter device sysfs attributes */
1139	err = counter_sysfs_attr_add(counter, cattr_groups);
1140	if (err < 0)
1141		return err;
1142
1143	/* Allocate attribute group pointers for association with device */
1144	dev->groups = devm_kcalloc(dev, num_groups + 1, sizeof(*dev->groups),
1145				   GFP_KERNEL);
1146	if (!dev->groups)
1147		return -ENOMEM;
1148
1149	/* Allocate space for attribute groups */
1150	groups = devm_kcalloc(dev, num_groups, sizeof(*groups), GFP_KERNEL);
1151	if (!groups)
1152		return -ENOMEM;
1153
1154	/* Prepare each group of attributes for association */
1155	for (i = 0; i < num_groups; i++) {
1156		groups[i].name = cattr_groups[i].name;
1157
1158		/* Allocate space for attribute pointers */
1159		groups[i].attrs = devm_kcalloc(dev,
1160					       cattr_groups[i].num_attr + 1,
1161					       sizeof(*groups[i].attrs),
1162					       GFP_KERNEL);
1163		if (!groups[i].attrs)
1164			return -ENOMEM;
1165
1166		/* Add attribute pointers to attribute group */
1167		j = 0;
1168		list_for_each_entry(p, &cattr_groups[i].attr_list, l)
1169			groups[i].attrs[j++] = &p->dev_attr.attr;
1170
1171		/* Associate attribute group */
1172		dev->groups[i] = &groups[i];
1173	}
1174
1175	return 0;
1176}
1177