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