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