Skip to content

Commit d2011be

Browse files
William Breathitt Graygregkh
authored andcommitted
counter: Introduce the COUNTER_COMP_ARRAY component type
The COUNTER_COMP_ARRAY Counter component type is introduced to enable support for Counter array components. With Counter array components, exposure for buffers on counter devices can be defined via new Counter array component macros. This should simplify code for driver authors who would otherwise need to define individual Counter components for each array element. Eight Counter array component macros are introduced:: DEFINE_COUNTER_ARRAY_U64(_name, _length) DEFINE_COUNTER_ARRAY_CAPTURE(_name, _length) DEFINE_COUNTER_ARRAY_POLARITY(_name, _enums, _length) COUNTER_COMP_DEVICE_ARRAY_U64(_name, _read, _write, _array) COUNTER_COMP_COUNT_ARRAY_U64(_name, _read, _write, _array) COUNTER_COMP_SIGNAL_ARRAY_U64(_name, _read, _write, _array) COUNTER_COMP_ARRAY_CAPTURE(_read, _write, _array) COUNTER_COMP_ARRAY_POLARITY(_read, _write, _array) Eight Counter array callbacks are introduced as well:: int (*signal_array_u32_read)(struct counter_device *counter, struct counter_signal *signal, size_t idx, u32 *val); int (*signal_array_u32_write)(struct counter_device *counter, struct counter_signal *signal, size_t idx, u32 val); int (*device_array_u64_read)(struct counter_device *counter, size_t idx, u64 *val); int (*count_array_u64_read)(struct counter_device *counter, struct counter_count *count, size_t idx, u64 *val); int (*signal_array_u64_read)(struct counter_device *counter, struct counter_signal *signal, size_t idx, u64 *val); int (*device_array_u64_write)(struct counter_device *counter, size_t idx, u64 val); int (*count_array_u64_write)(struct counter_device *counter, struct counter_count *count, size_t idx, u64 val); int (*signal_array_u64_write)(struct counter_device *counter, struct counter_signal *signal, size_t idx, u64 val); Driver authors can handle reads/writes for an array component by receiving an element index via the `idx` parameter and processing the respective value via the `val` parameter. For example, suppose a driver wants to expose a Count's read-only capture buffer of four elements using a callback `foobar_capture_read()`:: DEFINE_COUNTER_ARRAY_CAPTURE(foobar_capture_array, 4); COUNTER_COMP_ARRAY_CAPTURE(foobar_capture_read, NULL, foobar_capture_array) Respective sysfs attributes for each array element would appear for the respective Count: * /sys/bus/counter/devices/counterX/countY/capture0 * /sys/bus/counter/devices/counterX/countY/capture1 * /sys/bus/counter/devices/counterX/countY/capture2 * /sys/bus/counter/devices/counterX/countY/capture3 If a user tries to read _capture2_ for example, `idx` will be `2` when passed to the `foobar_capture_read()` callback, and thus the driver knows which array element to handle. Counter arrays for polarity elements can be defined in a similar manner as u64 elements:: const enum counter_signal_polarity foobar_polarity_states[] = { COUNTER_SIGNAL_POLARITY_POSITIVE, COUNTER_SIGNAL_POLARITY_NEGATIVE, }; DEFINE_COUNTER_ARRAY_POLARITY(foobar_polarity_array, foobar_polarity_states, 4); COUNTER_COMP_ARRAY_POLARITY(foobar_polarity_read, foobar_polarity_write, foobar_polarity_array) Tested-by: Julien Panis <[email protected]> Link: https://lore.kernel.org/r/5310c22520aeae65b1b74952419f49ac4c8e1ec1.1664204990.git.william.gray@linaro.org/ Signed-off-by: William Breathitt Gray <[email protected]> Link: https://lore.kernel.org/r/a51fd608704bdfc5a0efa503fc5481df34241e0a.1664318353.git.william.gray@linaro.org Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent bb4bbbe commit d2011be

File tree

3 files changed

+446
-20
lines changed

3 files changed

+446
-20
lines changed

drivers/counter/counter-chrdev.c

Lines changed: 116 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,11 @@ struct counter_comp_node {
4040
a.signal_u32_read == b.signal_u32_read || \
4141
a.device_u64_read == b.device_u64_read || \
4242
a.count_u64_read == b.count_u64_read || \
43-
a.signal_u64_read == b.signal_u64_read)
43+
a.signal_u64_read == b.signal_u64_read || \
44+
a.signal_array_u32_read == b.signal_array_u32_read || \
45+
a.device_array_u64_read == b.device_array_u64_read || \
46+
a.count_array_u64_read == b.count_array_u64_read || \
47+
a.signal_array_u64_read == b.signal_array_u64_read)
4448

4549
#define counter_comp_read_is_set(comp) \
4650
(comp.action_read || \
@@ -52,7 +56,11 @@ struct counter_comp_node {
5256
comp.signal_u32_read || \
5357
comp.device_u64_read || \
5458
comp.count_u64_read || \
55-
comp.signal_u64_read)
59+
comp.signal_u64_read || \
60+
comp.signal_array_u32_read || \
61+
comp.device_array_u64_read || \
62+
comp.count_array_u64_read || \
63+
comp.signal_array_u64_read)
5664

5765
static ssize_t counter_chrdev_read(struct file *filp, char __user *buf,
5866
size_t len, loff_t *f_ps)
@@ -228,6 +236,31 @@ static int counter_disable_events(struct counter_device *const counter)
228236
return err;
229237
}
230238

239+
static int counter_get_ext(const struct counter_comp *const ext,
240+
const size_t num_ext, const size_t component_id,
241+
size_t *const ext_idx, size_t *const id)
242+
{
243+
struct counter_array *element;
244+
245+
*id = 0;
246+
for (*ext_idx = 0; *ext_idx < num_ext; (*ext_idx)++) {
247+
if (*id == component_id)
248+
return 0;
249+
250+
if (ext->type == COUNTER_COMP_ARRAY) {
251+
element = ext->priv;
252+
253+
if (component_id - *id < element->length)
254+
return 0;
255+
256+
*id += element->length;
257+
} else
258+
(*id)++;
259+
}
260+
261+
return -EINVAL;
262+
}
263+
231264
static int counter_add_watch(struct counter_device *const counter,
232265
const unsigned long arg)
233266
{
@@ -237,6 +270,7 @@ static int counter_add_watch(struct counter_device *const counter,
237270
size_t parent, id;
238271
struct counter_comp *ext;
239272
size_t num_ext;
273+
size_t ext_idx, ext_id;
240274
int err = 0;
241275

242276
if (copy_from_user(&watch, uwatch, sizeof(watch)))
@@ -314,11 +348,11 @@ static int counter_add_watch(struct counter_device *const counter,
314348
comp_node.comp.priv = counter->counts[parent].synapses + id;
315349
break;
316350
case COUNTER_COMPONENT_EXTENSION:
317-
if (id >= num_ext)
318-
return -EINVAL;
319-
id = array_index_nospec(id, num_ext);
351+
err = counter_get_ext(ext, num_ext, id, &ext_idx, &ext_id);
352+
if (err < 0)
353+
return err;
320354

321-
comp_node.comp = ext[id];
355+
comp_node.comp = ext[ext_idx];
322356
break;
323357
default:
324358
return -EINVAL;
@@ -451,14 +485,56 @@ void counter_chrdev_remove(struct counter_device *const counter)
451485
kfifo_free(&counter->events);
452486
}
453487

488+
static int counter_get_array_data(struct counter_device *const counter,
489+
const enum counter_scope scope,
490+
void *const parent,
491+
const struct counter_comp *const comp,
492+
const size_t idx, u64 *const value)
493+
{
494+
const struct counter_array *const element = comp->priv;
495+
u32 value_u32 = 0;
496+
int ret;
497+
498+
switch (element->type) {
499+
case COUNTER_COMP_SIGNAL_POLARITY:
500+
if (scope != COUNTER_SCOPE_SIGNAL)
501+
return -EINVAL;
502+
ret = comp->signal_array_u32_read(counter, parent, idx,
503+
&value_u32);
504+
*value = value_u32;
505+
return ret;
506+
case COUNTER_COMP_U64:
507+
switch (scope) {
508+
case COUNTER_SCOPE_DEVICE:
509+
return comp->device_array_u64_read(counter, idx, value);
510+
case COUNTER_SCOPE_SIGNAL:
511+
return comp->signal_array_u64_read(counter, parent, idx,
512+
value);
513+
case COUNTER_SCOPE_COUNT:
514+
return comp->count_array_u64_read(counter, parent, idx,
515+
value);
516+
default:
517+
return -EINVAL;
518+
}
519+
default:
520+
return -EINVAL;
521+
}
522+
}
523+
454524
static int counter_get_data(struct counter_device *const counter,
455525
const struct counter_comp_node *const comp_node,
456526
u64 *const value)
457527
{
458528
const struct counter_comp *const comp = &comp_node->comp;
459-
void *const parent = comp_node->parent;
529+
const enum counter_scope scope = comp_node->component.scope;
530+
const size_t id = comp_node->component.id;
531+
struct counter_signal *const signal = comp_node->parent;
532+
struct counter_count *const count = comp_node->parent;
460533
u8 value_u8 = 0;
461534
u32 value_u32 = 0;
535+
const struct counter_comp *ext;
536+
size_t num_ext;
537+
size_t ext_idx, ext_id;
462538
int ret;
463539

464540
if (comp_node->component.type == COUNTER_COMPONENT_NONE)
@@ -467,15 +543,15 @@ static int counter_get_data(struct counter_device *const counter,
467543
switch (comp->type) {
468544
case COUNTER_COMP_U8:
469545
case COUNTER_COMP_BOOL:
470-
switch (comp_node->component.scope) {
546+
switch (scope) {
471547
case COUNTER_SCOPE_DEVICE:
472548
ret = comp->device_u8_read(counter, &value_u8);
473549
break;
474550
case COUNTER_SCOPE_SIGNAL:
475-
ret = comp->signal_u8_read(counter, parent, &value_u8);
551+
ret = comp->signal_u8_read(counter, signal, &value_u8);
476552
break;
477553
case COUNTER_SCOPE_COUNT:
478-
ret = comp->count_u8_read(counter, parent, &value_u8);
554+
ret = comp->count_u8_read(counter, count, &value_u8);
479555
break;
480556
default:
481557
return -EINVAL;
@@ -488,38 +564,60 @@ static int counter_get_data(struct counter_device *const counter,
488564
case COUNTER_COMP_COUNT_DIRECTION:
489565
case COUNTER_COMP_COUNT_MODE:
490566
case COUNTER_COMP_SIGNAL_POLARITY:
491-
switch (comp_node->component.scope) {
567+
switch (scope) {
492568
case COUNTER_SCOPE_DEVICE:
493569
ret = comp->device_u32_read(counter, &value_u32);
494570
break;
495571
case COUNTER_SCOPE_SIGNAL:
496-
ret = comp->signal_u32_read(counter, parent,
572+
ret = comp->signal_u32_read(counter, signal,
497573
&value_u32);
498574
break;
499575
case COUNTER_SCOPE_COUNT:
500-
ret = comp->count_u32_read(counter, parent, &value_u32);
576+
ret = comp->count_u32_read(counter, count, &value_u32);
501577
break;
502578
default:
503579
return -EINVAL;
504580
}
505581
*value = value_u32;
506582
return ret;
507583
case COUNTER_COMP_U64:
508-
switch (comp_node->component.scope) {
584+
switch (scope) {
509585
case COUNTER_SCOPE_DEVICE:
510586
return comp->device_u64_read(counter, value);
511587
case COUNTER_SCOPE_SIGNAL:
512-
return comp->signal_u64_read(counter, parent, value);
588+
return comp->signal_u64_read(counter, signal, value);
513589
case COUNTER_SCOPE_COUNT:
514-
return comp->count_u64_read(counter, parent, value);
590+
return comp->count_u64_read(counter, count, value);
515591
default:
516592
return -EINVAL;
517593
}
518594
case COUNTER_COMP_SYNAPSE_ACTION:
519-
ret = comp->action_read(counter, parent, comp->priv,
520-
&value_u32);
595+
ret = comp->action_read(counter, count, comp->priv, &value_u32);
521596
*value = value_u32;
522597
return ret;
598+
case COUNTER_COMP_ARRAY:
599+
switch (scope) {
600+
case COUNTER_SCOPE_DEVICE:
601+
ext = counter->ext;
602+
num_ext = counter->num_ext;
603+
break;
604+
case COUNTER_SCOPE_SIGNAL:
605+
ext = signal->ext;
606+
num_ext = signal->num_ext;
607+
break;
608+
case COUNTER_SCOPE_COUNT:
609+
ext = count->ext;
610+
num_ext = count->num_ext;
611+
break;
612+
default:
613+
return -EINVAL;
614+
}
615+
ret = counter_get_ext(ext, num_ext, id, &ext_idx, &ext_id);
616+
if (ret < 0)
617+
return ret;
618+
619+
return counter_get_array_data(counter, scope, comp_node->parent,
620+
comp, id - ext_id, value);
523621
default:
524622
return -EINVAL;
525623
}

0 commit comments

Comments
 (0)