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