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