Merge tag 'drm-intel-next-2023-08-03' of git://anongit.freedesktop.org/drm/drm-intel...
[platform/kernel/linux-starfive.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         [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
100 static const char *const counter_signal_polarity_str[] = {
101         [COUNTER_SIGNAL_POLARITY_POSITIVE] = "positive",
102         [COUNTER_SIGNAL_POLARITY_NEGATIVE] = "negative"
103 };
104
105 static 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
136 static 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
173 static 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
222 static int counter_find_enum(u32 *const enum_item, const u32 *const enums,
223                              const size_t num_enums, const char *const buf,
224                              const char *const string_array[])
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
237 static 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
302 static 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
329 static 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
361 static 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
383 static 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
411 static 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
443 static 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
479 static 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
492 static 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
504 static 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
532 static int counter_avail_attr_create(struct device *const dev,
533         struct counter_attribute_group *const group,
534         const struct counter_comp *const comp, void *const parent)
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
567 static int counter_attr_create(struct device *const dev,
568                                struct counter_attribute_group *const group,
569                                const struct counter_comp *const comp,
570                                const enum counter_scope scope,
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
674 static 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
680 static 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
706 static 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
714 static int counter_comp_id_attr_create(struct device *const dev,
715                                        struct counter_attribute_group *const group,
716                                        const char *name, const size_t id)
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
746 static int counter_ext_attrs_create(struct device *const dev,
747                                     struct counter_attribute_group *const group,
748                                     const struct counter_comp *const ext,
749                                     const enum counter_scope scope,
750                                     void *const parent, const size_t id)
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
763 static int counter_array_attrs_create(struct device *const dev,
764                                       struct counter_attribute_group *const group,
765                                       const struct counter_comp *const comp,
766                                       const enum counter_scope scope,
767                                       void *const parent, const size_t id)
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
802 static int counter_sysfs_exts_add(struct device *const dev,
803                                   struct counter_attribute_group *const group,
804                                   const struct counter_comp *const exts,
805                                   const size_t num_ext,
806                                   const enum counter_scope scope,
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
835 static struct counter_comp counter_signal_comp = {
836         .type = COUNTER_COMP_SIGNAL_LEVEL,
837         .name = "signal",
838 };
839
840 static int counter_signal_attrs_create(struct counter_device *const counter,
841         struct counter_attribute_group *const cattr_group,
842         struct counter_signal *const signal)
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
866 static 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
890 static int counter_sysfs_synapses_add(struct counter_device *const counter,
891         struct counter_attribute_group *const group,
892         struct counter_count *const count)
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
932 static struct counter_comp counter_count_comp =
933         COUNTER_COMP_COUNT_U64("count", NULL, NULL);
934
935 static struct counter_comp counter_function_comp = {
936         .type = COUNTER_COMP_FUNCTION,
937         .name = "function",
938 };
939
940 static int counter_count_attrs_create(struct counter_device *const counter,
941         struct counter_attribute_group *const cattr_group,
942         struct counter_count *const count)
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
975 static 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
1006 static int counter_num_signals_read(struct counter_device *counter, u8 *val)
1007 {
1008         *val = counter->num_signals;
1009         return 0;
1010 }
1011
1012 static int counter_num_counts_read(struct counter_device *counter, u8 *val)
1013 {
1014         *val = counter->num_counts;
1015         return 0;
1016 }
1017
1018 static 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
1025 static 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
1048 static struct counter_comp counter_num_signals_comp =
1049         COUNTER_COMP_DEVICE_U8("num_signals", counter_num_signals_read, NULL);
1050
1051 static struct counter_comp counter_num_counts_comp =
1052         COUNTER_COMP_DEVICE_U8("num_counts", counter_num_counts_read, NULL);
1053
1054 static struct counter_comp counter_events_queue_size_comp =
1055         COUNTER_COMP_DEVICE_U64("events_queue_size",
1056                                 counter_events_queue_size_read,
1057                                 counter_events_queue_size_write);
1058
1059 static 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  */
1118 int 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 }