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
counter_comp_u8_show(struct device * dev,struct device_attribute * attr,char * buf)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
counter_comp_u8_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t len)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
counter_comp_u32_show(struct device * dev,struct device_attribute * attr,char * buf)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
counter_find_enum(u32 * const enum_item,const u32 * const enums,const size_t num_enums,const char * const buf,const char * const string_array[])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
counter_comp_u32_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t len)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
counter_comp_u64_show(struct device * dev,struct device_attribute * attr,char * buf)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
counter_comp_u64_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t len)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
enums_available_show(const u32 * const enums,const size_t num_enums,const char * const strs[],char * buf)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
strs_available_show(const struct counter_available * const avail,char * buf)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
counter_comp_available_show(struct device * dev,struct device_attribute * attr,char * buf)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
counter_avail_attr_create(struct device * const dev,struct counter_attribute_group * const group,const struct counter_comp * const comp,void * const parent)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
counter_attr_create(struct device * const dev,struct counter_attribute_group * const group,const struct counter_comp * const comp,const enum counter_scope scope,void * const parent)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
counter_comp_name_show(struct device * dev,struct device_attribute * attr,char * buf)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
counter_name_attr_create(struct device * const dev,struct counter_attribute_group * const group,const char * const name)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
counter_comp_id_show(struct device * dev,struct device_attribute * attr,char * buf)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
counter_comp_id_attr_create(struct device * const dev,struct counter_attribute_group * const group,const char * name,const size_t id)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
counter_signal_attrs_create(struct counter_device * const counter,struct counter_attribute_group * const cattr_group,struct counter_signal * const signal)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
counter_sysfs_signals_add(struct counter_device * const counter,struct counter_attribute_group * const groups)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
counter_sysfs_synapses_add(struct counter_device * const counter,struct counter_attribute_group * const group,struct counter_count * const count)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
counter_count_attrs_create(struct counter_device * const counter,struct counter_attribute_group * const cattr_group,struct counter_count * const count)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
counter_sysfs_counts_add(struct counter_device * const counter,struct counter_attribute_group * const groups)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
counter_num_signals_read(struct counter_device * counter,u8 * val)777 static int counter_num_signals_read(struct counter_device *counter, u8 *val)
778 {
779 *val = counter->num_signals;
780 return 0;
781 }
782
counter_num_counts_read(struct counter_device * counter,u8 * val)783 static int counter_num_counts_read(struct counter_device *counter, u8 *val)
784 {
785 *val = counter->num_counts;
786 return 0;
787 }
788
counter_events_queue_size_read(struct counter_device * counter,u64 * val)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
counter_events_queue_size_write(struct counter_device * counter,u64 val)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
counter_sysfs_attr_add(struct counter_device * const counter,struct counter_attribute_group * cattr_group)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 */
counter_sysfs_add(struct counter_device * const counter)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 }
960