1 // SPDX-License-Identifier: GPL-2.0
3 * Generic Counter sysfs interface
4 * Copyright (C) 2020 William Breathitt Gray
6 #include <linux/counter.h>
7 #include <linux/device.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>
20 #include "counter-sysfs.h"
22 static inline struct counter_device
*counter_from_dev(struct device
*dev
)
24 return container_of(dev
, struct counter_device
, dev
);
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
35 struct counter_attribute
{
36 struct device_attribute dev_attr
;
39 struct counter_comp comp
;
40 enum counter_scope scope
;
44 #define to_counter_attribute(_dev_attr) \
45 container_of(_dev_attr, struct counter_attribute, dev_attr)
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
53 struct counter_attribute_group
{
55 struct list_head attr_list
;
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"
70 static const char *const counter_signal_value_str
[] = {
71 [COUNTER_SIGNAL_LEVEL_LOW
] = "low",
72 [COUNTER_SIGNAL_LEVEL_HIGH
] = "high"
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"
82 static const char *const counter_count_direction_str
[] = {
83 [COUNTER_COUNT_DIRECTION_FORWARD
] = "forward",
84 [COUNTER_COUNT_DIRECTION_BACKWARD
] = "backward"
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 [COUNTER_COUNT_MODE_INTERRUPT_ON_TERMINAL_COUNT
] = "interrupt on terminal count",
93 [COUNTER_COUNT_MODE_HARDWARE_RETRIGGERABLE_ONESHOT
] = "hardware retriggerable one-shot",
94 [COUNTER_COUNT_MODE_RATE_GENERATOR
] = "rate generator",
95 [COUNTER_COUNT_MODE_SQUARE_WAVE_MODE
] = "square wave mode",
96 [COUNTER_COUNT_MODE_SOFTWARE_TRIGGERED_STROBE
] = "software triggered strobe",
97 [COUNTER_COUNT_MODE_HARDWARE_TRIGGERED_STROBE
] = "hardware triggered strobe",
100 static const char *const counter_signal_polarity_str
[] = {
101 [COUNTER_SIGNAL_POLARITY_POSITIVE
] = "positive",
102 [COUNTER_SIGNAL_POLARITY_NEGATIVE
] = "negative"
105 static ssize_t
counter_comp_u8_show(struct device
*dev
,
106 struct device_attribute
*attr
, char *buf
)
108 const struct counter_attribute
*const a
= to_counter_attribute(attr
);
109 struct counter_device
*const counter
= counter_from_dev(dev
);
114 case COUNTER_SCOPE_DEVICE
:
115 err
= a
->comp
.device_u8_read(counter
, &data
);
117 case COUNTER_SCOPE_SIGNAL
:
118 err
= a
->comp
.signal_u8_read(counter
, a
->parent
, &data
);
120 case COUNTER_SCOPE_COUNT
:
121 err
= a
->comp
.count_u8_read(counter
, a
->parent
, &data
);
129 if (a
->comp
.type
== COUNTER_COMP_BOOL
)
130 /* data should already be boolean but ensure just to be safe */
133 return sysfs_emit(buf
, "%u\n", (unsigned int)data
);
136 static ssize_t
counter_comp_u8_store(struct device
*dev
,
137 struct device_attribute
*attr
,
138 const char *buf
, size_t len
)
140 const struct counter_attribute
*const a
= to_counter_attribute(attr
);
141 struct counter_device
*const counter
= counter_from_dev(dev
);
146 if (a
->comp
.type
== COUNTER_COMP_BOOL
) {
147 err
= kstrtobool(buf
, &bool_data
);
150 err
= kstrtou8(buf
, 0, &data
);
155 case COUNTER_SCOPE_DEVICE
:
156 err
= a
->comp
.device_u8_write(counter
, data
);
158 case COUNTER_SCOPE_SIGNAL
:
159 err
= a
->comp
.signal_u8_write(counter
, a
->parent
, data
);
161 case COUNTER_SCOPE_COUNT
:
162 err
= a
->comp
.count_u8_write(counter
, a
->parent
, data
);
173 static ssize_t
counter_comp_u32_show(struct device
*dev
,
174 struct device_attribute
*attr
, char *buf
)
176 const struct counter_attribute
*const a
= to_counter_attribute(attr
);
177 struct counter_device
*const counter
= counter_from_dev(dev
);
178 const struct counter_available
*const avail
= a
->comp
.priv
;
183 case COUNTER_SCOPE_DEVICE
:
184 err
= a
->comp
.device_u32_read(counter
, &data
);
186 case COUNTER_SCOPE_SIGNAL
:
187 err
= a
->comp
.signal_u32_read(counter
, a
->parent
, &data
);
189 case COUNTER_SCOPE_COUNT
:
190 if (a
->comp
.type
== COUNTER_COMP_SYNAPSE_ACTION
)
191 err
= a
->comp
.action_read(counter
, a
->parent
,
192 a
->comp
.priv
, &data
);
194 err
= a
->comp
.count_u32_read(counter
, a
->parent
, &data
);
202 switch (a
->comp
.type
) {
203 case COUNTER_COMP_FUNCTION
:
204 return sysfs_emit(buf
, "%s\n", counter_function_str
[data
]);
205 case COUNTER_COMP_SIGNAL_LEVEL
:
206 return sysfs_emit(buf
, "%s\n", counter_signal_value_str
[data
]);
207 case COUNTER_COMP_SYNAPSE_ACTION
:
208 return sysfs_emit(buf
, "%s\n", counter_synapse_action_str
[data
]);
209 case COUNTER_COMP_ENUM
:
210 return sysfs_emit(buf
, "%s\n", avail
->strs
[data
]);
211 case COUNTER_COMP_COUNT_DIRECTION
:
212 return sysfs_emit(buf
, "%s\n", counter_count_direction_str
[data
]);
213 case COUNTER_COMP_COUNT_MODE
:
214 return sysfs_emit(buf
, "%s\n", counter_count_mode_str
[data
]);
215 case COUNTER_COMP_SIGNAL_POLARITY
:
216 return sysfs_emit(buf
, "%s\n", counter_signal_polarity_str
[data
]);
218 return sysfs_emit(buf
, "%u\n", (unsigned int)data
);
222 static int counter_find_enum(u32
*const enum_item
, const u32
*const enums
,
223 const size_t num_enums
, const char *const buf
,
224 const char *const string_array
[])
228 for (index
= 0; index
< num_enums
; index
++) {
229 *enum_item
= enums
[index
];
230 if (sysfs_streq(buf
, string_array
[*enum_item
]))
237 static ssize_t
counter_comp_u32_store(struct device
*dev
,
238 struct device_attribute
*attr
,
239 const char *buf
, size_t len
)
241 const struct counter_attribute
*const a
= to_counter_attribute(attr
);
242 struct counter_device
*const counter
= counter_from_dev(dev
);
243 struct counter_count
*const count
= a
->parent
;
244 struct counter_synapse
*const synapse
= a
->comp
.priv
;
245 const struct counter_available
*const avail
= a
->comp
.priv
;
249 switch (a
->comp
.type
) {
250 case COUNTER_COMP_FUNCTION
:
251 err
= counter_find_enum(&data
, count
->functions_list
,
252 count
->num_functions
, buf
,
253 counter_function_str
);
255 case COUNTER_COMP_SYNAPSE_ACTION
:
256 err
= counter_find_enum(&data
, synapse
->actions_list
,
257 synapse
->num_actions
, buf
,
258 counter_synapse_action_str
);
260 case COUNTER_COMP_ENUM
:
261 err
= __sysfs_match_string(avail
->strs
, avail
->num_items
, buf
);
264 case COUNTER_COMP_COUNT_MODE
:
265 err
= counter_find_enum(&data
, avail
->enums
, avail
->num_items
,
266 buf
, counter_count_mode_str
);
268 case COUNTER_COMP_SIGNAL_POLARITY
:
269 err
= counter_find_enum(&data
, avail
->enums
, avail
->num_items
,
270 buf
, counter_signal_polarity_str
);
273 err
= kstrtou32(buf
, 0, &data
);
280 case COUNTER_SCOPE_DEVICE
:
281 err
= a
->comp
.device_u32_write(counter
, data
);
283 case COUNTER_SCOPE_SIGNAL
:
284 err
= a
->comp
.signal_u32_write(counter
, a
->parent
, data
);
286 case COUNTER_SCOPE_COUNT
:
287 if (a
->comp
.type
== COUNTER_COMP_SYNAPSE_ACTION
)
288 err
= a
->comp
.action_write(counter
, count
, synapse
,
291 err
= a
->comp
.count_u32_write(counter
, count
, data
);
302 static ssize_t
counter_comp_u64_show(struct device
*dev
,
303 struct device_attribute
*attr
, char *buf
)
305 const struct counter_attribute
*const a
= to_counter_attribute(attr
);
306 struct counter_device
*const counter
= counter_from_dev(dev
);
311 case COUNTER_SCOPE_DEVICE
:
312 err
= a
->comp
.device_u64_read(counter
, &data
);
314 case COUNTER_SCOPE_SIGNAL
:
315 err
= a
->comp
.signal_u64_read(counter
, a
->parent
, &data
);
317 case COUNTER_SCOPE_COUNT
:
318 err
= a
->comp
.count_u64_read(counter
, a
->parent
, &data
);
326 return sysfs_emit(buf
, "%llu\n", (unsigned long long)data
);
329 static ssize_t
counter_comp_u64_store(struct device
*dev
,
330 struct device_attribute
*attr
,
331 const char *buf
, size_t len
)
333 const struct counter_attribute
*const a
= to_counter_attribute(attr
);
334 struct counter_device
*const counter
= counter_from_dev(dev
);
338 err
= kstrtou64(buf
, 0, &data
);
343 case COUNTER_SCOPE_DEVICE
:
344 err
= a
->comp
.device_u64_write(counter
, data
);
346 case COUNTER_SCOPE_SIGNAL
:
347 err
= a
->comp
.signal_u64_write(counter
, a
->parent
, data
);
349 case COUNTER_SCOPE_COUNT
:
350 err
= a
->comp
.count_u64_write(counter
, a
->parent
, data
);
361 static ssize_t
counter_comp_array_u32_show(struct device
*dev
,
362 struct device_attribute
*attr
,
365 const struct counter_attribute
*const a
= to_counter_attribute(attr
);
366 struct counter_device
*const counter
= counter_from_dev(dev
);
367 const struct counter_array
*const element
= a
->comp
.priv
;
371 if (a
->scope
!= COUNTER_SCOPE_SIGNAL
||
372 element
->type
!= COUNTER_COMP_SIGNAL_POLARITY
)
375 err
= a
->comp
.signal_array_u32_read(counter
, a
->parent
, element
->idx
,
380 return sysfs_emit(buf
, "%s\n", counter_signal_polarity_str
[data
]);
383 static ssize_t
counter_comp_array_u32_store(struct device
*dev
,
384 struct device_attribute
*attr
,
385 const char *buf
, size_t len
)
387 const struct counter_attribute
*const a
= to_counter_attribute(attr
);
388 struct counter_device
*const counter
= counter_from_dev(dev
);
389 const struct counter_array
*const element
= a
->comp
.priv
;
393 if (element
->type
!= COUNTER_COMP_SIGNAL_POLARITY
||
394 a
->scope
!= COUNTER_SCOPE_SIGNAL
)
397 err
= counter_find_enum(&data
, element
->avail
->enums
,
398 element
->avail
->num_items
, buf
,
399 counter_signal_polarity_str
);
403 err
= a
->comp
.signal_array_u32_write(counter
, a
->parent
, element
->idx
,
411 static ssize_t
counter_comp_array_u64_show(struct device
*dev
,
412 struct device_attribute
*attr
,
415 const struct counter_attribute
*const a
= to_counter_attribute(attr
);
416 struct counter_device
*const counter
= counter_from_dev(dev
);
417 const struct counter_array
*const element
= a
->comp
.priv
;
422 case COUNTER_SCOPE_DEVICE
:
423 err
= a
->comp
.device_array_u64_read(counter
, element
->idx
,
426 case COUNTER_SCOPE_SIGNAL
:
427 err
= a
->comp
.signal_array_u64_read(counter
, a
->parent
,
428 element
->idx
, &data
);
430 case COUNTER_SCOPE_COUNT
:
431 err
= a
->comp
.count_array_u64_read(counter
, a
->parent
,
432 element
->idx
, &data
);
440 return sysfs_emit(buf
, "%llu\n", (unsigned long long)data
);
443 static ssize_t
counter_comp_array_u64_store(struct device
*dev
,
444 struct device_attribute
*attr
,
445 const char *buf
, size_t len
)
447 const struct counter_attribute
*const a
= to_counter_attribute(attr
);
448 struct counter_device
*const counter
= counter_from_dev(dev
);
449 const struct counter_array
*const element
= a
->comp
.priv
;
453 err
= kstrtou64(buf
, 0, &data
);
458 case COUNTER_SCOPE_DEVICE
:
459 err
= a
->comp
.device_array_u64_write(counter
, element
->idx
,
462 case COUNTER_SCOPE_SIGNAL
:
463 err
= a
->comp
.signal_array_u64_write(counter
, a
->parent
,
466 case COUNTER_SCOPE_COUNT
:
467 err
= a
->comp
.count_array_u64_write(counter
, a
->parent
,
479 static ssize_t
enums_available_show(const u32
*const enums
,
480 const size_t num_enums
,
481 const char *const strs
[], char *buf
)
486 for (index
= 0; index
< num_enums
; index
++)
487 len
+= sysfs_emit_at(buf
, len
, "%s\n", strs
[enums
[index
]]);
492 static ssize_t
strs_available_show(const struct counter_available
*const avail
,
498 for (index
= 0; index
< avail
->num_items
; index
++)
499 len
+= sysfs_emit_at(buf
, len
, "%s\n", avail
->strs
[index
]);
504 static ssize_t
counter_comp_available_show(struct device
*dev
,
505 struct device_attribute
*attr
,
508 const struct counter_attribute
*const a
= to_counter_attribute(attr
);
509 const struct counter_count
*const count
= a
->parent
;
510 const struct counter_synapse
*const synapse
= a
->comp
.priv
;
511 const struct counter_available
*const avail
= a
->comp
.priv
;
513 switch (a
->comp
.type
) {
514 case COUNTER_COMP_FUNCTION
:
515 return enums_available_show(count
->functions_list
,
516 count
->num_functions
,
517 counter_function_str
, buf
);
518 case COUNTER_COMP_SYNAPSE_ACTION
:
519 return enums_available_show(synapse
->actions_list
,
520 synapse
->num_actions
,
521 counter_synapse_action_str
, buf
);
522 case COUNTER_COMP_ENUM
:
523 return strs_available_show(avail
, buf
);
524 case COUNTER_COMP_COUNT_MODE
:
525 return enums_available_show(avail
->enums
, avail
->num_items
,
526 counter_count_mode_str
, buf
);
532 static int counter_avail_attr_create(struct device
*const dev
,
533 struct counter_attribute_group
*const group
,
534 const struct counter_comp
*const comp
, void *const parent
)
536 struct counter_attribute
*counter_attr
;
537 struct device_attribute
*dev_attr
;
539 counter_attr
= devm_kzalloc(dev
, sizeof(*counter_attr
), GFP_KERNEL
);
543 /* Configure Counter attribute */
544 counter_attr
->comp
.type
= comp
->type
;
545 counter_attr
->comp
.priv
= comp
->priv
;
546 counter_attr
->parent
= parent
;
548 /* Initialize sysfs attribute */
549 dev_attr
= &counter_attr
->dev_attr
;
550 sysfs_attr_init(&dev_attr
->attr
);
552 /* Configure device attribute */
553 dev_attr
->attr
.name
= devm_kasprintf(dev
, GFP_KERNEL
, "%s_available",
555 if (!dev_attr
->attr
.name
)
557 dev_attr
->attr
.mode
= 0444;
558 dev_attr
->show
= counter_comp_available_show
;
560 /* Store list node */
561 list_add(&counter_attr
->l
, &group
->attr_list
);
567 static int counter_attr_create(struct device
*const dev
,
568 struct counter_attribute_group
*const group
,
569 const struct counter_comp
*const comp
,
570 const enum counter_scope scope
,
573 const struct counter_array
*const array
= comp
->priv
;
574 struct counter_attribute
*counter_attr
;
575 struct device_attribute
*dev_attr
;
577 counter_attr
= devm_kzalloc(dev
, sizeof(*counter_attr
), GFP_KERNEL
);
581 /* Configure Counter attribute */
582 counter_attr
->comp
= *comp
;
583 counter_attr
->scope
= scope
;
584 counter_attr
->parent
= parent
;
586 /* Configure device attribute */
587 dev_attr
= &counter_attr
->dev_attr
;
588 sysfs_attr_init(&dev_attr
->attr
);
589 dev_attr
->attr
.name
= comp
->name
;
590 switch (comp
->type
) {
591 case COUNTER_COMP_U8
:
592 case COUNTER_COMP_BOOL
:
593 if (comp
->device_u8_read
) {
594 dev_attr
->attr
.mode
|= 0444;
595 dev_attr
->show
= counter_comp_u8_show
;
597 if (comp
->device_u8_write
) {
598 dev_attr
->attr
.mode
|= 0200;
599 dev_attr
->store
= counter_comp_u8_store
;
602 case COUNTER_COMP_SIGNAL_LEVEL
:
603 case COUNTER_COMP_FUNCTION
:
604 case COUNTER_COMP_SYNAPSE_ACTION
:
605 case COUNTER_COMP_ENUM
:
606 case COUNTER_COMP_COUNT_DIRECTION
:
607 case COUNTER_COMP_COUNT_MODE
:
608 case COUNTER_COMP_SIGNAL_POLARITY
:
609 if (comp
->device_u32_read
) {
610 dev_attr
->attr
.mode
|= 0444;
611 dev_attr
->show
= counter_comp_u32_show
;
613 if (comp
->device_u32_write
) {
614 dev_attr
->attr
.mode
|= 0200;
615 dev_attr
->store
= counter_comp_u32_store
;
618 case COUNTER_COMP_U64
:
619 if (comp
->device_u64_read
) {
620 dev_attr
->attr
.mode
|= 0444;
621 dev_attr
->show
= counter_comp_u64_show
;
623 if (comp
->device_u64_write
) {
624 dev_attr
->attr
.mode
|= 0200;
625 dev_attr
->store
= counter_comp_u64_store
;
628 case COUNTER_COMP_ARRAY
:
629 switch (array
->type
) {
630 case COUNTER_COMP_SIGNAL_POLARITY
:
631 if (comp
->signal_array_u32_read
) {
632 dev_attr
->attr
.mode
|= 0444;
633 dev_attr
->show
= counter_comp_array_u32_show
;
635 if (comp
->signal_array_u32_write
) {
636 dev_attr
->attr
.mode
|= 0200;
637 dev_attr
->store
= counter_comp_array_u32_store
;
640 case COUNTER_COMP_U64
:
641 if (comp
->device_array_u64_read
) {
642 dev_attr
->attr
.mode
|= 0444;
643 dev_attr
->show
= counter_comp_array_u64_show
;
645 if (comp
->device_array_u64_write
) {
646 dev_attr
->attr
.mode
|= 0200;
647 dev_attr
->store
= counter_comp_array_u64_store
;
658 /* Store list node */
659 list_add(&counter_attr
->l
, &group
->attr_list
);
662 /* Create "*_available" attribute if needed */
663 switch (comp
->type
) {
664 case COUNTER_COMP_FUNCTION
:
665 case COUNTER_COMP_SYNAPSE_ACTION
:
666 case COUNTER_COMP_ENUM
:
667 case COUNTER_COMP_COUNT_MODE
:
668 return counter_avail_attr_create(dev
, group
, comp
, parent
);
674 static ssize_t
counter_comp_name_show(struct device
*dev
,
675 struct device_attribute
*attr
, char *buf
)
677 return sysfs_emit(buf
, "%s\n", to_counter_attribute(attr
)->comp
.name
);
680 static int counter_name_attr_create(struct device
*const dev
,
681 struct counter_attribute_group
*const group
,
682 const char *const name
)
684 struct counter_attribute
*counter_attr
;
686 counter_attr
= devm_kzalloc(dev
, sizeof(*counter_attr
), GFP_KERNEL
);
690 /* Configure Counter attribute */
691 counter_attr
->comp
.name
= name
;
693 /* Configure device attribute */
694 sysfs_attr_init(&counter_attr
->dev_attr
.attr
);
695 counter_attr
->dev_attr
.attr
.name
= "name";
696 counter_attr
->dev_attr
.attr
.mode
= 0444;
697 counter_attr
->dev_attr
.show
= counter_comp_name_show
;
699 /* Store list node */
700 list_add(&counter_attr
->l
, &group
->attr_list
);
706 static ssize_t
counter_comp_id_show(struct device
*dev
,
707 struct device_attribute
*attr
, char *buf
)
709 const size_t id
= (size_t)to_counter_attribute(attr
)->comp
.priv
;
711 return sysfs_emit(buf
, "%zu\n", id
);
714 static int counter_comp_id_attr_create(struct device
*const dev
,
715 struct counter_attribute_group
*const group
,
716 const char *name
, const size_t id
)
718 struct counter_attribute
*counter_attr
;
720 /* Allocate Counter attribute */
721 counter_attr
= devm_kzalloc(dev
, sizeof(*counter_attr
), GFP_KERNEL
);
725 /* Generate component ID name */
726 name
= devm_kasprintf(dev
, GFP_KERNEL
, "%s_component_id", name
);
730 /* Configure Counter attribute */
731 counter_attr
->comp
.priv
= (void *)id
;
733 /* Configure device attribute */
734 sysfs_attr_init(&counter_attr
->dev_attr
.attr
);
735 counter_attr
->dev_attr
.attr
.name
= name
;
736 counter_attr
->dev_attr
.attr
.mode
= 0444;
737 counter_attr
->dev_attr
.show
= counter_comp_id_show
;
739 /* Store list node */
740 list_add(&counter_attr
->l
, &group
->attr_list
);
746 static int counter_ext_attrs_create(struct device
*const dev
,
747 struct counter_attribute_group
*const group
,
748 const struct counter_comp
*const ext
,
749 const enum counter_scope scope
,
750 void *const parent
, const size_t id
)
754 /* Create main extension attribute */
755 err
= counter_attr_create(dev
, group
, ext
, scope
, parent
);
759 /* Create extension id attribute */
760 return counter_comp_id_attr_create(dev
, group
, ext
->name
, id
);
763 static int counter_array_attrs_create(struct device
*const dev
,
764 struct counter_attribute_group
*const group
,
765 const struct counter_comp
*const comp
,
766 const enum counter_scope scope
,
767 void *const parent
, const size_t id
)
769 const struct counter_array
*const array
= comp
->priv
;
770 struct counter_comp ext
= *comp
;
771 struct counter_array
*element
;
775 /* Create an attribute for each array element */
776 for (idx
= 0; idx
< array
->length
; idx
++) {
777 /* Generate array element attribute name */
778 ext
.name
= devm_kasprintf(dev
, GFP_KERNEL
, "%s%zu", comp
->name
,
783 /* Allocate and configure array element */
784 element
= devm_kzalloc(dev
, sizeof(*element
), GFP_KERNEL
);
787 element
->type
= array
->type
;
788 element
->avail
= array
->avail
;
792 /* Create all attributes associated with the array element */
793 err
= counter_ext_attrs_create(dev
, group
, &ext
, scope
, parent
,
802 static int counter_sysfs_exts_add(struct device
*const dev
,
803 struct counter_attribute_group
*const group
,
804 const struct counter_comp
*const exts
,
805 const size_t num_ext
,
806 const enum counter_scope scope
,
810 const struct counter_comp
*ext
;
813 const struct counter_array
*array
;
815 /* Create attributes for each extension */
816 for (i
= 0; i
< num_ext
; i
++) {
818 if (ext
->type
== COUNTER_COMP_ARRAY
) {
819 err
= counter_array_attrs_create(dev
, group
, ext
, scope
,
824 err
= counter_ext_attrs_create(dev
, group
, ext
, scope
,
835 static struct counter_comp counter_signal_comp
= {
836 .type
= COUNTER_COMP_SIGNAL_LEVEL
,
840 static int counter_signal_attrs_create(struct counter_device
*const counter
,
841 struct counter_attribute_group
*const cattr_group
,
842 struct counter_signal
*const signal
)
844 const enum counter_scope scope
= COUNTER_SCOPE_SIGNAL
;
845 struct device
*const dev
= &counter
->dev
;
847 struct counter_comp comp
;
849 /* Create main Signal attribute */
850 comp
= counter_signal_comp
;
851 comp
.signal_u32_read
= counter
->ops
->signal_read
;
852 err
= counter_attr_create(dev
, cattr_group
, &comp
, scope
, signal
);
856 /* Create Signal name attribute */
857 err
= counter_name_attr_create(dev
, cattr_group
, signal
->name
);
861 /* Add Signal extensions */
862 return counter_sysfs_exts_add(dev
, cattr_group
, signal
->ext
,
863 signal
->num_ext
, scope
, signal
);
866 static int counter_sysfs_signals_add(struct counter_device
*const counter
,
867 struct counter_attribute_group
*const groups
)
872 /* Add each Signal */
873 for (i
= 0; i
< counter
->num_signals
; i
++) {
874 /* Generate Signal attribute directory name */
875 groups
[i
].name
= devm_kasprintf(&counter
->dev
, GFP_KERNEL
,
880 /* Create all attributes associated with Signal */
881 err
= counter_signal_attrs_create(counter
, groups
+ i
,
882 counter
->signals
+ i
);
890 static int counter_sysfs_synapses_add(struct counter_device
*const counter
,
891 struct counter_attribute_group
*const group
,
892 struct counter_count
*const count
)
896 /* Add each Synapse */
897 for (i
= 0; i
< count
->num_synapses
; i
++) {
898 struct device
*const dev
= &counter
->dev
;
899 struct counter_synapse
*synapse
;
901 struct counter_comp comp
;
904 synapse
= count
->synapses
+ i
;
906 /* Generate Synapse action name */
907 id
= synapse
->signal
- counter
->signals
;
908 comp
.name
= devm_kasprintf(dev
, GFP_KERNEL
, "signal%zu_action",
913 /* Create action attribute */
914 comp
.type
= COUNTER_COMP_SYNAPSE_ACTION
;
915 comp
.action_read
= counter
->ops
->action_read
;
916 comp
.action_write
= counter
->ops
->action_write
;
918 err
= counter_attr_create(dev
, group
, &comp
,
919 COUNTER_SCOPE_COUNT
, count
);
923 /* Create Synapse component ID attribute */
924 err
= counter_comp_id_attr_create(dev
, group
, comp
.name
, i
);
932 static struct counter_comp counter_count_comp
=
933 COUNTER_COMP_COUNT_U64("count", NULL
, NULL
);
935 static struct counter_comp counter_function_comp
= {
936 .type
= COUNTER_COMP_FUNCTION
,
940 static int counter_count_attrs_create(struct counter_device
*const counter
,
941 struct counter_attribute_group
*const cattr_group
,
942 struct counter_count
*const count
)
944 const enum counter_scope scope
= COUNTER_SCOPE_COUNT
;
945 struct device
*const dev
= &counter
->dev
;
947 struct counter_comp comp
;
949 /* Create main Count attribute */
950 comp
= counter_count_comp
;
951 comp
.count_u64_read
= counter
->ops
->count_read
;
952 comp
.count_u64_write
= counter
->ops
->count_write
;
953 err
= counter_attr_create(dev
, cattr_group
, &comp
, scope
, count
);
957 /* Create Count name attribute */
958 err
= counter_name_attr_create(dev
, cattr_group
, count
->name
);
962 /* Create Count function attribute */
963 comp
= counter_function_comp
;
964 comp
.count_u32_read
= counter
->ops
->function_read
;
965 comp
.count_u32_write
= counter
->ops
->function_write
;
966 err
= counter_attr_create(dev
, cattr_group
, &comp
, scope
, count
);
970 /* Add Count extensions */
971 return counter_sysfs_exts_add(dev
, cattr_group
, count
->ext
,
972 count
->num_ext
, scope
, count
);
975 static int counter_sysfs_counts_add(struct counter_device
*const counter
,
976 struct counter_attribute_group
*const groups
)
979 struct counter_count
*count
;
983 for (i
= 0; i
< counter
->num_counts
; i
++) {
984 count
= counter
->counts
+ i
;
986 /* Generate Count attribute directory name */
987 groups
[i
].name
= devm_kasprintf(&counter
->dev
, GFP_KERNEL
,
992 /* Add sysfs attributes of the Synapses */
993 err
= counter_sysfs_synapses_add(counter
, groups
+ i
, count
);
997 /* Create all attributes associated with Count */
998 err
= counter_count_attrs_create(counter
, groups
+ i
, count
);
1006 static int counter_num_signals_read(struct counter_device
*counter
, u8
*val
)
1008 *val
= counter
->num_signals
;
1012 static int counter_num_counts_read(struct counter_device
*counter
, u8
*val
)
1014 *val
= counter
->num_counts
;
1018 static int counter_events_queue_size_read(struct counter_device
*counter
,
1021 *val
= kfifo_size(&counter
->events
);
1025 static int counter_events_queue_size_write(struct counter_device
*counter
,
1028 DECLARE_KFIFO_PTR(events
, struct counter_event
);
1030 unsigned long flags
;
1032 /* Allocate new events queue */
1033 err
= kfifo_alloc(&events
, val
, GFP_KERNEL
);
1037 /* Swap in new events queue */
1038 mutex_lock(&counter
->events_out_lock
);
1039 spin_lock_irqsave(&counter
->events_in_lock
, flags
);
1040 kfifo_free(&counter
->events
);
1041 counter
->events
.kfifo
= events
.kfifo
;
1042 spin_unlock_irqrestore(&counter
->events_in_lock
, flags
);
1043 mutex_unlock(&counter
->events_out_lock
);
1048 static struct counter_comp counter_num_signals_comp
=
1049 COUNTER_COMP_DEVICE_U8("num_signals", counter_num_signals_read
, NULL
);
1051 static struct counter_comp counter_num_counts_comp
=
1052 COUNTER_COMP_DEVICE_U8("num_counts", counter_num_counts_read
, NULL
);
1054 static struct counter_comp counter_events_queue_size_comp
=
1055 COUNTER_COMP_DEVICE_U64("events_queue_size",
1056 counter_events_queue_size_read
,
1057 counter_events_queue_size_write
);
1059 static int counter_sysfs_attr_add(struct counter_device
*const counter
,
1060 struct counter_attribute_group
*cattr_group
)
1062 const enum counter_scope scope
= COUNTER_SCOPE_DEVICE
;
1063 struct device
*const dev
= &counter
->dev
;
1066 /* Add Signals sysfs attributes */
1067 err
= counter_sysfs_signals_add(counter
, cattr_group
);
1070 cattr_group
+= counter
->num_signals
;
1072 /* Add Counts sysfs attributes */
1073 err
= counter_sysfs_counts_add(counter
, cattr_group
);
1076 cattr_group
+= counter
->num_counts
;
1078 /* Create name attribute */
1079 err
= counter_name_attr_create(dev
, cattr_group
, counter
->name
);
1083 /* Create num_signals attribute */
1084 err
= counter_attr_create(dev
, cattr_group
, &counter_num_signals_comp
,
1089 /* Create num_counts attribute */
1090 err
= counter_attr_create(dev
, cattr_group
, &counter_num_counts_comp
,
1095 /* Create events_queue_size attribute */
1096 err
= counter_attr_create(dev
, cattr_group
,
1097 &counter_events_queue_size_comp
, scope
, NULL
);
1101 /* Add device extensions */
1102 return counter_sysfs_exts_add(dev
, cattr_group
, counter
->ext
,
1103 counter
->num_ext
, scope
, NULL
);
1109 * counter_sysfs_add - Adds Counter sysfs attributes to the device structure
1110 * @counter: Pointer to the Counter device structure
1112 * Counter sysfs attributes are created and added to the respective device
1113 * structure for later registration to the system. Resource-managed memory
1114 * allocation is performed by this function, and this memory should be freed
1115 * when no longer needed (automatically by a device_unregister call, or
1116 * manually by a devres_release_all call).
1118 int counter_sysfs_add(struct counter_device
*const counter
)
1120 struct device
*const dev
= &counter
->dev
;
1121 const size_t num_groups
= counter
->num_signals
+ counter
->num_counts
+ 1;
1122 struct counter_attribute_group
*cattr_groups
;
1125 struct attribute_group
*groups
;
1126 struct counter_attribute
*p
;
1128 /* Allocate space for attribute groups (signals, counts, and ext) */
1129 cattr_groups
= devm_kcalloc(dev
, num_groups
, sizeof(*cattr_groups
),
1134 /* Initialize attribute lists */
1135 for (i
= 0; i
< num_groups
; i
++)
1136 INIT_LIST_HEAD(&cattr_groups
[i
].attr_list
);
1138 /* Add Counter device sysfs attributes */
1139 err
= counter_sysfs_attr_add(counter
, cattr_groups
);
1143 /* Allocate attribute group pointers for association with device */
1144 dev
->groups
= devm_kcalloc(dev
, num_groups
+ 1, sizeof(*dev
->groups
),
1149 /* Allocate space for attribute groups */
1150 groups
= devm_kcalloc(dev
, num_groups
, sizeof(*groups
), GFP_KERNEL
);
1154 /* Prepare each group of attributes for association */
1155 for (i
= 0; i
< num_groups
; i
++) {
1156 groups
[i
].name
= cattr_groups
[i
].name
;
1158 /* Allocate space for attribute pointers */
1159 groups
[i
].attrs
= devm_kcalloc(dev
,
1160 cattr_groups
[i
].num_attr
+ 1,
1161 sizeof(*groups
[i
].attrs
),
1163 if (!groups
[i
].attrs
)
1166 /* Add attribute pointers to attribute group */
1168 list_for_each_entry(p
, &cattr_groups
[i
].attr_list
, l
)
1169 groups
[i
].attrs
[j
++] = &p
->dev_attr
.attr
;
1171 /* Associate attribute group */
1172 dev
->groups
[i
] = &groups
[i
];