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