Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/drivers/counter/counter-sysfs.c
26278 views
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
}
1177
1178