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