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 
22 static 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  */
35 struct 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  */
53 struct counter_attribute_group {
54 	const char *name;
55 	struct list_head attr_list;
56 	size_t num_attr;
57 };
58 
59 static 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 
70 static const char *const counter_signal_value_str[] = {
71 	[COUNTER_SIGNAL_LEVEL_LOW] = "low",
72 	[COUNTER_SIGNAL_LEVEL_HIGH] = "high"
73 };
74 
75 static 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 
82 static const char *const counter_count_direction_str[] = {
83 	[COUNTER_COUNT_DIRECTION_FORWARD] = "forward",
84 	[COUNTER_COUNT_DIRECTION_BACKWARD] = "backward"
85 };
86 
87 static 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 
94 static 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 
125 static 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 
162 static 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 
209 static 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 
224 static 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 
285 static 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 
312 static 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 
344 static 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 
357 static 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 
369 static 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 
397 static 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 
432 static 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 
511 static 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 
517 static 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 
543 static 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 
551 static 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 
583 static struct counter_comp counter_signal_comp = {
584 	.type = COUNTER_COMP_SIGNAL_LEVEL,
585 	.name = "signal",
586 };
587 
588 static 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 
628 static 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 
652 static 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 
694 static struct counter_comp counter_count_comp =
695 	COUNTER_COMP_COUNT_U64("count", NULL, NULL);
696 
697 static struct counter_comp counter_function_comp = {
698 	.type = COUNTER_COMP_FUNCTION,
699 	.name = "function",
700 };
701 
702 static 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 
751 static 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 
782 static int counter_num_signals_read(struct counter_device *counter, u8 *val)
783 {
784 	*val = counter->num_signals;
785 	return 0;
786 }
787 
788 static int counter_num_counts_read(struct counter_device *counter, u8 *val)
789 {
790 	*val = counter->num_counts;
791 	return 0;
792 }
793 
794 static 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 
801 static 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 
824 static struct counter_comp counter_num_signals_comp =
825 	COUNTER_COMP_DEVICE_U8("num_signals", counter_num_signals_read, NULL);
826 
827 static struct counter_comp counter_num_counts_comp =
828 	COUNTER_COMP_DEVICE_U8("num_counts", counter_num_counts_read, NULL);
829 
830 static 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 
835 static 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  */
906 int 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 }
965