Introduce the Counter character device interface
Subsystems (11)
v15 cover Introduce the Counter character device interface
Changes in v15:
- Move the description for the member 'lock' in the 'quad8' structure as a separate patch
- Reorganize the "counter: Internalize sysfs interface code" patch to not call chrdev code; respective code moved to the "counter: Add character device interface" patch with the other chrdev code
- Custom enums removed from the ftm-quaddec.c, stm32-lptimer-cnt.c, and stm32-timer-cnt.c files; respective drivers refactored to use the COUNTER_FUNCTION_* and COUNTER_SYNAPSE_* enum constants instead
For convenience, this patchset is also available on my personal git
repo: https://gitlab.com/vilhelmgray/iio/-/tree/counter_chrdev_v15
The patches preceding "counter: Internalize sysfs interface code" are primarily cleanup and fixes that can be picked up and applied now to the IIO tree if so desired. The "counter: Internalize sysfs interface code" patch as well may be considered for pickup because it is relatively safe and makes no changes to the userspace interface.
To summarize the main points of this patchset: there are no changes to the existing Counter sysfs userspace interface; a Counter character device interface is introduced that allows Counter events and associated data to be read() by userspace; the events_configure() and watch_validate() driver callbacks are introduced to support Counter events; and IRQ support is added to the 104-QUAD-8 driver, serving as an example of how to support the new Counter events functionality.
William Breathitt Gray (13):
counter: 104-quad-8: Describe member 'lock' in 'quad8'
counter: Internalize sysfs interface code
counter: Update counter.h comments to reflect sysfs internalization
docs: counter: Update to reflect sysfs internalization
counter: Move counter enums to uapi header
counter: Add character device interface
docs: counter: Document character device interface tools/counter: Create Counter tools
counter: Implement signalZ_action_component_id sysfs attribute
counter: Implement *_component_id sysfs attributes
counter: Implement events_queue_size sysfs attribute
counter: 104-quad-8: Replace mutex with spinlock
counter: 104-quad-8: Add IRQ support for the ACCES 104-QUAD-8
Documentation/ABI/testing/sysfs-bus-counter | 38 +- Documentation/driver-api/generic-counter.rst | 358 +++- .../userspace-api/ioctl/ioctl-number.rst | 1 + MAINTAINERS | 3 +- drivers/counter/104-quad-8.c | 700 ++++---- drivers/counter/Kconfig | 6 +- drivers/counter/Makefile | 1 + drivers/counter/counter-chrdev.c | 553 ++++++ drivers/counter/counter-chrdev.h | 14 + drivers/counter/counter-core.c | 191 +++ drivers/counter/counter-sysfs.c | 962 +++++++++++ drivers/counter/counter-sysfs.h | 13 + drivers/counter/counter.c | 1496 ----------------- drivers/counter/ftm-quaddec.c | 60 +- drivers/counter/intel-qep.c | 144 +- drivers/counter/interrupt-cnt.c | 62 +- drivers/counter/microchip-tcb-capture.c | 91 +- drivers/counter/stm32-lptimer-cnt.c | 226 +-- drivers/counter/stm32-timer-cnt.c | 179 +- drivers/counter/ti-eqep.c | 180 +- include/linux/counter.h | 715 ++++---- include/linux/counter_enum.h | 45 - include/uapi/linux/counter.h | 154 ++ tools/Makefile | 13 +- tools/counter/Build | 1 + tools/counter/Makefile | 53 + tools/counter/counter_example.c | 93 + 27 files changed, 3568 insertions(+), 2784 deletions(-) create mode 100644 drivers/counter/counter-chrdev.c create mode 100644 drivers/counter/counter-chrdev.h create mode 100644 drivers/counter/counter-core.c create mode 100644 drivers/counter/counter-sysfs.c create mode 100644 drivers/counter/counter-sysfs.h delete mode 100644 drivers/counter/counter.c delete mode 100644 include/linux/counter_enum.h create mode 100644 include/uapi/linux/counter.h create mode 100644 tools/counter/Build create mode 100644 tools/counter/Makefile create mode 100644 tools/counter/counter_example.c
base-commit: c886885336b0b5f1a08ce580f7201a2ca30ab041
prerequisite-patch-id: 8ca55ffcdd5d060dd5fa2b4dd50bf01dc1026da6
prerequisite-patch-id: 46ef2668ca6bdc0d08dd488fe1d2b886189a5652
prerequisite-patch-id: 2df1946c917d6408148306db30a071e67b00ad73
prerequisite-patch-id: f81579f50552e6041a95403cc743c5f36962b111
prerequisite-patch-id: 8a6860e75cdec162812c56dc39c5d7fc6fc5154e
Signature · 1 line
2.32.0
PATCH v15 1/13 counter: 104-quad-8: Describe member 'lock' in 'quad8'
This adds a kernel-doc comment line describing the 'lock' member of the 'quad8' structure.
--- drivers/counter/104-quad-8.c | 1 + 1 file changed, 1 insertion(+)
drivers/counter/104-quad-8.c +1 -0
@@ -28,6 +28,7 @@ MODULE_PARM_DESC(base, "ACCES 104-QUAD-8 base addresses");/** * struct quad8 - device private data structure +* @lock: lock to prevent clobbering device states during R/W ops * @counter: instance of the counter_device * @fck_prescaler: array of filter clock prescaler configurations * @preset: array of preset values
Signature · 1 line
2.32.0
Re: [PATCH v15 01/13] counter: 104-quad-8: Describe member 'lock' in 'quad8'
Quoted 5 lines · On Mon, 9 Aug 2021 21:37:26 +0900 William Breathitt Gray…
This adds a kernel-doc comment line describing the 'lock' member of the 'quad8' structure.
Signed-off-by William Breathitt Gray <[email protected]>
Initially I was confused as to when Syed had acked a new patch, but then realised you have pulled it out of the later spinlock conversion patch which Syed had indeed acked, so fair enough.
Applied to the togreg branch of iio.git and (unlike yesterday) pushed out as testing for 0-day to poke at it.
Quoted 16 lines
--- drivers/counter/104-quad-8.c | 1 + 1 file changed, 1 insertion(+)drivers/counter/104-quad-8.c +1
-0@@ -28,6 +28,7 @@ MODULE_PARM_DESC(base, "ACCES 104-QUAD-8 base addresses");/** * struct quad8 - device private data structure +* @lock: lock to prevent clobbering device states during R/W ops * @counter: instance of the counter_device * @fck_prescaler: array of filter clock prescaler configurations * @preset: array of preset values
PATCH v15 2/13 counter: Internalize sysfs interface code
In reply to William Breathitt GrayThis is a reimplementation of the Generic Counter driver interface. There are no modifications to the Counter subsystem userspace interface, so existing userspace applications should continue to run seamlessly.
The purpose of this patch is to internalize the sysfs interface code among the various counter drivers into a shared module. Counter drivers pass and take data natively (i.e. u8, u64, etc.) and the shared counter module handles the translation between the sysfs interface and the device drivers. This guarantees a standard userspace interface for all counter drivers, and helps generalize the Generic Counter driver ABI in order to support the Generic Counter chrdev interface (introduced in a subsequent patch) without significant changes to the existing counter drivers.
Note, Counter device registration is the same as before: drivers populate a struct counter_device with components and callbacks, then pass the structure to the devm_counter_register function. However, what's different now is how the Counter subsystem code handles this registration internally.
Whereas before callbacks would interact directly with sysfs data, this interaction is now abstracted and instead callbacks interact with native C data types. The counter_comp structure forms the basis for Counter extensions.
The counter-sysfs.c file contains the code to parse through the counter_device structure and register the requested components and extensions. Attributes are created and populated based on type, with respective translation functions to handle the mapping between sysfs and the counter driver callbacks.
The translation performed for each attribute is straightforward: the attribute type and data is parsed from the counter_attribute structure, the respective counter driver read/write callback is called, and sysfs I/O is handled before or after the driver read/write function is called.
--- MAINTAINERS | 1 - drivers/counter/104-quad-8.c | 449 +++---- drivers/counter/Makefile | 1 + drivers/counter/counter-core.c | 142 +++ drivers/counter/counter-sysfs.c | 852 +++++++++++++ drivers/counter/counter-sysfs.h | 13 + drivers/counter/counter.c | 1496 ----------------------- drivers/counter/ftm-quaddec.c | 60 +- drivers/counter/intel-qep.c | 144 +-- drivers/counter/interrupt-cnt.c | 62 +- drivers/counter/microchip-tcb-capture.c | 91 +- drivers/counter/stm32-lptimer-cnt.c | 226 ++-- drivers/counter/stm32-timer-cnt.c | 179 ++- drivers/counter/ti-eqep.c | 180 +-- include/linux/counter.h | 658 +++++----- include/linux/counter_enum.h | 45 - 16 files changed, 1965 insertions(+), 2634 deletions(-) create mode 100644 drivers/counter/counter-core.c create mode 100644 drivers/counter/counter-sysfs.c create mode 100644 drivers/counter/counter-sysfs.h delete mode 100644 drivers/counter/counter.c delete mode 100644 include/linux/counter_enum.h
MAINTAINERS +0 -1
@@ -4764,7 +4764,6 @@ F: Documentation/ABI/testing/sysfs-bus-counter F: Documentation/driver-api/generic-counter.rst F: drivers/counter/ F: include/linux/counter.h -F: include/linux/counter_enum.h CP2615 I2C DRIVER M: Bence Csókás <[email protected]>
drivers/counter/104-quad-8.c +191 -258
796 lines not on this page · raw message
drivers/counter/Makefile +1 -0
@@ -4,6 +4,7 @@ # obj-$(CONFIG_COUNTER) += counter.o +counter-y := counter-core.o counter-sysfs.o obj-$(CONFIG_104_QUAD_8) += 104-quad-8.o obj-$(CONFIG_INTERRUPT_CNT) += interrupt-cnt.o
drivers/counter/counter-core.c new file +142 -0
142 lines not on this page · raw message
drivers/counter/counter-sysfs.c new file +852 -0
852 lines not on this page · raw message
drivers/counter/counter-sysfs.h new file +13 -0
@@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* +* Counter sysfs interface +* Copyright (C) 2020 William Breathitt Gray +*/ +#ifndef _COUNTER_SYSFS_H_ +#define _COUNTER_SYSFS_H_ + +#include <linux/counter.h> + +int counter_sysfs_add (struct counter_device *const counter); + +#endif /* _COUNTER_SYSFS_H_ */
drivers/counter/counter.c deleted +0 -1496
1,183 lines not on this page · raw message
drivers/counter/ftm-quaddec.c +23 -37
60 lines not on this page · raw message
drivers/counter/intel-qep.c +61 -83
144 lines not on this page · raw message
drivers/counter/interrupt-cnt.c +26 -36
62 lines not on this page · raw message
drivers/counter/microchip-tcb-capture.c +39 -52
91 lines not on this page · raw message
drivers/counter/stm32-lptimer-cnt.c +113 -113
226 lines not on this page · raw message
drivers/counter/stm32-timer-cnt.c +68 -111
179 lines not on this page · raw message
drivers/counter/ti-eqep.c +98 -82
180 lines not on this page · raw message
include/linux/counter.h +338 -320
658 lines not on this page · raw message
include/linux/counter_enum.h deleted +0 -45
45 lines not on this page · raw message
The rest of this diff is not shown. View the raw message.
Signature · 1 line
2.32.0
Part of the diff is not shown here. View the raw message.
Jonathan Cameron
maintainerRe: [PATCH v15 02/13] counter: Internalize sysfs interface code
Quoted 36 lines · On Mon, 9 Aug 2021 21:37:27 +0900 William Breathitt Gray…
This is a reimplementation of the Generic Counter driver interface. There are no modifications to the Counter subsystem userspace interface, so existing userspace applications should continue to run seamlessly.
The purpose of this patch is to internalize the sysfs interface code among the various counter drivers into a shared module. Counter drivers pass and take data natively (i.e. u8, u64, etc.) and the shared counter module handles the translation between the sysfs interface and the device drivers. This guarantees a standard userspace interface for all counter drivers, and helps generalize the Generic Counter driver ABI in order to support the Generic Counter chrdev interface (introduced in a subsequent patch) without significant changes to the existing counter drivers.
Note, Counter device registration is the same as before: drivers populate a struct
counter_devicewith components and callbacks, then pass the structure to thedevm_counter_registerfunction. However, what's different now is how the Counter subsystem code handles this registration internally.Whereas before callbacks would interact directly with sysfs data, this interaction is now abstracted and instead callbacks interact with native C data types. The
counter_compstructure forms the basis for Counter extensions.The
counter-sysfs.cfile contains the code to parse through thecounter_devicestructure and register the requested components and extensions. Attributes are created and populated based on type, with respective translation functions to handle the mapping between sysfs and the counter driver callbacks.The translation performed for each attribute is straightforward: the attribute type and data is parsed from the
counter_attributestructure, the respective counter driver read/write callback is called, and sysfs I/O is handled before or after the driver read/write function is called.
Quoted 11 lines
Cc Jarkko Nikula <[email protected]>Cc Patrick Havelange <[email protected]>Cc Kamel Bouhara <[email protected]>Cc Fabrice Gasnier <[email protected]>Cc Maxime Coquelin <[email protected]>Cc Alexandre Torgue <[email protected]>Cc Dan Carpenter <[email protected]>Reviewed-by David Lechner <[email protected]>Tested-by David Lechner <[email protected]>Signed-off-by William Breathitt Gray <[email protected]>
Hi William,
Given we haven't had any of the reviews of the stm32 and ftm-quadec changes I took a closer look myself.
A side effect of the warning fixes is that we now have some 'magic numbers' for register fields. Some of them were there already, but now there are more.
My suggestions is that you use some defines (or indeed the original enums if appropriate) to provide text names to the register field values. I've highlighted another driver that does it the way I'd like to see it done.
So unfortunately it looks like this this refactor is going to be in the next kernel cycle :( Hopefully we can get it queued up early though so you have something to do any revisions of the latter patches against.
Jonathan
...
Quoted 12 lines
drivers/counter/microchip-tcb-capture.c +4
-4-static int mchp_tc_count_action_set (struct counter_device *counter, -struct counter_count *count, -struct counter_synapse *synapse, -size_t action) +static int mchp_tc_count_action_write (struct counter_device *counter, +struct counter_count *count, +struct counter_synapse *synapse, +enum counter_synapse_action action) {struct mchp_tc_data *const priv = counter->priv;u32 edge =ATMEL_TC_ETRGEDG_NONE ;
drivers/counter/microchip-tcb-capture.c static int mchp_tc_count_action_set(struct counter_device *counter, · line 209
Quoted 6 lines
drivers/counter/microchip-tcb-capture.c +1
-1@@ -217,16 +205,16 @@ static int mchp_tc_count_action_set(struct counter_device *counter,return -EINVAL ;switch (action) { -case MCHP_TC_SYNAPSE_ACTION_NONE : +case COUNTER_SYNAPSE_ACTION_NONE : edge =ATMEL_TC_ETRGEDG_NONE ;
This is a good example of the sort of use of defines for field values I'm suggesting for other similar cases. Basically do it like this.
Quoted 96 lines
drivers/counter/microchip-tcb-capture.c +3
-3break ; -case MCHP_TC_SYNAPSE_ACTION_RISING_EDGE : +case COUNTER_SYNAPSE_ACTION_RISING_EDGE : edge =ATMEL_TC_ETRGEDG_RISING ;break ; -case MCHP_TC_SYNAPSE_ACTION_FALLING_EDGE : +case COUNTER_SYNAPSE_ACTION_FALLING_EDGE : edge =ATMEL_TC_ETRGEDG_FALLING ;break ; -case MCHP_TC_SYNAPSE_ACTION_BOTH_EDGE : +case COUNTER_SYNAPSE_ACTION_BOTH_EDGES : edge =ATMEL_TC_ETRGEDG_BOTH ;break ;default :@@ -240,8 +228,7 @@ static int mchp_tc_count_action_set(struct counter_device *counter, }drivers/counter/stm32-lptimer-cnt.c +12
-28@@ -17,6 +17,7 @@#include <linux/module.h> #include <linux/pinctrl/consumer.h> #include <linux/platform_device.h> +#include <linux/types.h> struct stm32_lptim_cnt {struct counter_device counter;@@ -107,11 +108,7 @@ static int stm32_lptim_setup(struct stm32_lptim_cnt *priv, int enable)return regmap_update_bits (priv->regmap,STM32_LPTIM_CFGR , mask, val); } -/** -* enum stm32_lptim_cnt_function - enumerates LPTimer counter & encoder modes -* @STM32_LPTIM_COUNTER_INCREASE: up count on IN1 rising, falling or both edges -* @STM32_LPTIM_ENCODER_BOTH_EDGE: count on both edges (IN1 & IN2 quadrature) -* +/* * In non-quadrature mode, device counts up on active edge. * In quadrature mode, encoder counting scenarios are as follows: * +---------+----------+--------------------+--------------------+ @@ -129,33 +126,20 @@ static int stm32_lptim_setup(struct stm32_lptim_cnt *priv, int enable)* | edges | Low -> | Up | Down | Down | Up | * +---------+----------+----------+---------+----------+---------+ */ -enum stm32_lptim_cnt_function { -STM32_LPTIM_COUNTER_INCREASE , -STM32_LPTIM_ENCODER_BOTH_EDGE , -}; -static const enum counter_function stm32_lptim_cnt_functions[] = { - [STM32_LPTIM_COUNTER_INCREASE ] =COUNTER_FUNCTION_INCREASE , - [STM32_LPTIM_ENCODER_BOTH_EDGE ] =COUNTER_FUNCTION_QUADRATURE_X4 , -}; - -enum stm32_lptim_synapse_action { -STM32_LPTIM_SYNAPSE_ACTION_RISING_EDGE , -STM32_LPTIM_SYNAPSE_ACTION_FALLING_EDGE , -STM32_LPTIM_SYNAPSE_ACTION_BOTH_EDGES , -STM32_LPTIM_SYNAPSE_ACTION_NONE , +COUNTER_FUNCTION_INCREASE , +COUNTER_FUNCTION_QUADRATURE_X4 , };static const enum counter_synapse_action stm32_lptim_cnt_synapse_actions[] = { -/* Index must match with stm32_lptim_cnt_polarity[] (priv->polarity) */ - [STM32_LPTIM_SYNAPSE_ACTION_RISING_EDGE ] =COUNTER_SYNAPSE_ACTION_RISING_EDGE , - [STM32_LPTIM_SYNAPSE_ACTION_FALLING_EDGE ] =COUNTER_SYNAPSE_ACTION_FALLING_EDGE , - [STM32_LPTIM_SYNAPSE_ACTION_BOTH_EDGES ] =COUNTER_SYNAPSE_ACTION_BOTH_EDGES , - [STM32_LPTIM_SYNAPSE_ACTION_NONE ] =COUNTER_SYNAPSE_ACTION_NONE , +COUNTER_SYNAPSE_ACTION_RISING_EDGE , +COUNTER_SYNAPSE_ACTION_FALLING_EDGE , +COUNTER_SYNAPSE_ACTION_BOTH_EDGES , +COUNTER_SYNAPSE_ACTION_NONE , };static int stm32_lptim_cnt_read (struct counter_device *counter, -struct counter_count *count,unsigned long *val) +struct counter_count *count,u64 *val) {struct stm32_lptim_cnt *const priv = counter->priv;u32 cnt;@@ -170,28 +154,28 @@ static int stm32_lptim_cnt_read(struct counter_device *counter,return 0 ; } -static int stm32_lptim_cnt_function_get (struct counter_device *counter, -struct counter_count *count, -size_t *function) +static int stm32_lptim_cnt_function_read (struct counter_device *counter, +struct counter_count *count, +enum counter_function *function) {struct stm32_lptim_cnt *const priv = counter->priv;
drivers/counter/stm32-lptimer-cnt.c static int stm32_lptim_cnt_read(struct counter_device *counter, · line 168
Quoted 10 lines
drivers/counter/stm32-lptimer-cnt.c +2
-3if (!priv->quadrature_mode) { - *function =STM32_LPTIM_COUNTER_INCREASE ; + *function =COUNTER_FUNCTION_INCREASE ;return 0 ; } -if (priv->polarity ==STM32_LPTIM_SYNAPSE_ACTION_BOTH_EDGES ) { - *function =STM32_LPTIM_ENCODER_BOTH_EDGE ; +if (priv->polarity ==2 ) {
This wants to have some sort of define for the register field value it corresponds to.
Quoted 35 lines
drivers/counter/stm32-lptimer-cnt.c +7
-6+ *function =COUNTER_FUNCTION_QUADRATURE_X4 ;return 0 ; }return -EINVAL ; } -static int stm32_lptim_cnt_function_set (struct counter_device *counter, -struct counter_count *count, -size_t function) +static int stm32_lptim_cnt_function_write (struct counter_device *counter, +struct counter_count *count, +enum counter_function function) {struct stm32_lptim_cnt *const priv = counter->priv;@@ -199,12 +183,12 @@ static int stm32_lptim_cnt_function_set(struct counter_device *counter,return -EBUSY ;switch (function) { -case STM32_LPTIM_COUNTER_INCREASE : +case COUNTER_FUNCTION_INCREASE : priv->quadrature_mode =0 ;return 0 ; -case STM32_LPTIM_ENCODER_BOTH_EDGE : +case COUNTER_FUNCTION_QUADRATURE_X4 : priv->quadrature_mode =1 ; - priv->polarity =STM32_LPTIM_SYNAPSE_ACTION_BOTH_EDGES ; + priv->polarity =2 ;return 0 ;default :/* should never reach this path */ @@ -212,9 +196,9 @@ static int stm32_lptim_cnt_function_set(struct counter_device *counter, } }
...
Quoted 29 lines
drivers/counter/stm32-lptimer-cnt.c +7
-12-static int stm32_lptim_cnt_action_get (struct counter_device *counter, -struct counter_count *count, -struct counter_synapse *synapse, -size_t *action) +static int stm32_lptim_cnt_action_read (struct counter_device *counter, +struct counter_count *count, +struct counter_synapse *synapse, +enum counter_synapse_action *action) {struct stm32_lptim_cnt *const priv = counter->priv; -size_t function; +enum counter_function function;int err; - err =stm32_lptim_cnt_function_get (counter, count, &function); + err =stm32_lptim_cnt_function_read (counter, count, &function);if (err)return err;switch (function) { -case STM32_LPTIM_COUNTER_INCREASE : +case COUNTER_FUNCTION_INCREASE :/* LP Timer acts as up-counter on input 1 */ -if (synapse->signal->id == count->synapses[0 ].signal->id) - *action = priv->polarity; -else - *action =STM32_LPTIM_SYNAPSE_ACTION_NONE ; -return 0 ;
drivers/counter/stm32-lptimer-cnt.c static ssize_t stm32_lptim_cnt_enable_write(struct counter_device *counter, · line 297
Quoted 10 lines
drivers/counter/stm32-lptimer-cnt.c +7
-3-case STM32_LPTIM_ENCODER_BOTH_EDGE : - *action = priv->polarity; -return 0 ; +if (synapse->signal->id != count->synapses[0 ].signal->id) { + *action =COUNTER_SYNAPSE_ACTION_NONE ; +return 0 ; + } + +switch (priv->polarity) { +case 0 :
These correspond to particular bits. As you use them elsewhere I think you need some defines.
Quoted 170 lines
drivers/counter/stm32-lptimer-cnt.c +53
-21+ *action =COUNTER_SYNAPSE_ACTION_RISING_EDGE ; +return 0 ; +case 1 : + *action =COUNTER_SYNAPSE_ACTION_FALLING_EDGE ; +return 0 ; +case 2 : + *action =COUNTER_SYNAPSE_ACTION_BOTH_EDGES ; +return 0 ; +default : +/* should never reach this path */ +return -EINVAL ; + } +case COUNTER_FUNCTION_QUADRATURE_X4 : +switch (priv->polarity) { +case 0 : + *action =COUNTER_SYNAPSE_ACTION_RISING_EDGE ; +return 0 ; +case 1 : + *action =COUNTER_SYNAPSE_ACTION_FALLING_EDGE ; +return 0 ; +case 2 : + *action =COUNTER_SYNAPSE_ACTION_BOTH_EDGES ; +return 0 ; +default : +/* should never reach this path */ +return -EINVAL ; + }default :/* should never reach this path */ return -EINVAL ; } } -static int stm32_lptim_cnt_action_set (struct counter_device *counter, -struct counter_count *count, -struct counter_synapse *synapse, -size_t action) +static int stm32_lptim_cnt_action_write (struct counter_device *counter, +struct counter_count *count, +struct counter_synapse *synapse, +enum counter_synapse_action action) {struct stm32_lptim_cnt *const priv = counter->priv; -size_t function; +enum counter_function function;int err;if (stm32_lptim_is_enabled (priv))return -EBUSY ; - err =stm32_lptim_cnt_function_get (counter, count, &function); + err =stm32_lptim_cnt_function_read (counter, count, &function);if (err)return err;/* only set polarity when in counter mode (on input 1) */ -if (function ==STM32_LPTIM_COUNTER_INCREASE - && synapse->signal->id == count->synapses[0 ].signal->id) { -switch (action) { -case STM32_LPTIM_SYNAPSE_ACTION_RISING_EDGE : -case STM32_LPTIM_SYNAPSE_ACTION_FALLING_EDGE : -case STM32_LPTIM_SYNAPSE_ACTION_BOTH_EDGES : - priv->polarity = action; -return 0 ; - } - } +if (function !=COUNTER_FUNCTION_INCREASE + || synapse->signal->id != count->synapses[0 ].signal->id) +return -EINVAL ; -return -EINVAL ; +switch (action) { +case COUNTER_SYNAPSE_ACTION_RISING_EDGE : + priv->polarity =0 ; +return 0 ; +case COUNTER_SYNAPSE_ACTION_FALLING_EDGE : + priv->polarity =1 ; +return 0 ; +case COUNTER_SYNAPSE_ACTION_BOTH_EDGES : + priv->polarity =2 ; +return 0 ; +default : +return -EINVAL ; + } }static const struct counter_ops stm32_lptim_cnt_ops = { .count_read = stm32_lptim_cnt_read, - .function_get = stm32_lptim_cnt_function_get, - .function_set = stm32_lptim_cnt_function_set, - .action_get = stm32_lptim_cnt_action_get, - .action_set = stm32_lptim_cnt_action_set, + .function_read = stm32_lptim_cnt_function_read, + .function_write = stm32_lptim_cnt_function_write, + .action_read = stm32_lptim_cnt_action_read, + .action_write = stm32_lptim_cnt_action_write, };static struct counter_signal stm32_lptim_cnt_signals[] = {drivers/counter/stm32-timer-cnt.c +10
-24@@ -13,6 +13,7 @@#include <linux/module.h> #include <linux/pinctrl/consumer.h> #include <linux/platform_device.h> +#include <linux/types.h> #define TIM_CCMR_CCXS (BIT(8) | BIT(0))#define TIM_CCMR_MASK (TIM_CCMR_CC1S | TIM_CCMR_CC2S | \@@ -36,29 +37,15 @@ struct stm32_timer_cnt {struct stm32_timer_regs bak; }; -/** -* enum stm32_count_function - enumerates stm32 timer counter encoder modes -* @STM32_COUNT_SLAVE_MODE_DISABLED: counts on internal clock when CEN=1 -* @STM32_COUNT_ENCODER_MODE_1: counts TI1FP1 edges, depending on TI2FP2 level -* @STM32_COUNT_ENCODER_MODE_2: counts TI2FP2 edges, depending on TI1FP1 level -* @STM32_COUNT_ENCODER_MODE_3: counts on both TI1FP1 and TI2FP2 edges -*/ -enum stm32_count_function { -STM32_COUNT_SLAVE_MODE_DISABLED , -STM32_COUNT_ENCODER_MODE_1 , -STM32_COUNT_ENCODER_MODE_2 , -STM32_COUNT_ENCODER_MODE_3 , -}; -static const enum counter_function stm32_count_functions[] = { - [STM32_COUNT_SLAVE_MODE_DISABLED ] =COUNTER_FUNCTION_INCREASE , - [STM32_COUNT_ENCODER_MODE_1 ] =COUNTER_FUNCTION_QUADRATURE_X2_A , - [STM32_COUNT_ENCODER_MODE_2 ] =COUNTER_FUNCTION_QUADRATURE_X2_B , - [STM32_COUNT_ENCODER_MODE_3 ] =COUNTER_FUNCTION_QUADRATURE_X4 , +COUNTER_FUNCTION_INCREASE , +COUNTER_FUNCTION_QUADRATURE_X2_A , +COUNTER_FUNCTION_QUADRATURE_X2_B , +COUNTER_FUNCTION_QUADRATURE_X4 , };static int stm32_count_read (struct counter_device *counter, -struct counter_count *count,unsigned long *val) +struct counter_count *count,u64 *val) {struct stm32_timer_cnt *const priv = counter->priv;u32 cnt;@@ -70,8 +57,7 @@ static int stm32_count_read(struct counter_device *counter, }static int stm32_count_write (struct counter_device *counter, -struct counter_count *count, -const unsigned long val) +struct counter_count *count,const u64 val) {struct stm32_timer_cnt *const priv = counter->priv;u32 ceiling;@@ -83,9 +69,9 @@ static int stm32_count_write(struct counter_device *counter,return regmap_write (priv->regmap,TIM_CNT , val); } -static int stm32_count_function_get (struct counter_device *counter, -struct counter_count *count, -size_t *function) +static int stm32_count_function_read (struct counter_device *counter, +struct counter_count *count, +enum counter_function *function) {struct stm32_timer_cnt *const priv = counter->priv;u32 smcr;
drivers/counter/stm32-timer-cnt.c static int stm32_count_function_get(struct counter_device *counter, · line 82
Quoted 3 lines
drivers/counter/stm32-timer-cnt.c +0
-0@@ -94,40 +80,40 @@ static int stm32_count_function_get(struct counter_device *counter,switch (smcr &TIM_SMCR_SMS ) {case 0 :
As below, these case values should be named.
Quoted 24 lines
drivers/counter/stm32-timer-cnt.c +5
-7- *function =STM32_COUNT_SLAVE_MODE_DISABLED ; + *function =COUNTER_FUNCTION_INCREASE ;return 0 ;case 1 : - *function =STM32_COUNT_ENCODER_MODE_1 ; + *function =COUNTER_FUNCTION_QUADRATURE_X2_A ;return 0 ;case 2 : - *function =STM32_COUNT_ENCODER_MODE_2 ; + *function =COUNTER_FUNCTION_QUADRATURE_X2_B ;return 0 ;case 3 : - *function =STM32_COUNT_ENCODER_MODE_3 ; + *function =COUNTER_FUNCTION_QUADRATURE_X4 ;return 0 ;default :return -EINVAL ; } } -static int stm32_count_function_set (struct counter_device *counter, -struct counter_count *count, -size_t function) +static int stm32_count_function_write(struct counter_device *counter,
drivers/counter/stm32-timer-cnt.c static int stm32_count_function_get(struct counter_device *counter, · line 108
Quoted 10 lines
drivers/counter/stm32-timer-cnt.c +3
-1+struct counter_count *count, + enum counter_function function) { struct stm32_timer_cnt *const priv = counter->priv;u32 cr1, sms;switch (function) { -case STM32_COUNT_SLAVE_MODE_DISABLED : +case COUNTER_FUNCTION_INCREASE : sms =0 ;
This code is odd in the original driver as sms is just set to the values of the 'function' enum. Having said that, I think with the refactored code you want some symbolic names (defines) for the register field values.
Quoted 14 lines
drivers/counter/stm32-timer-cnt.c +3
-3break ; -case STM32_COUNT_ENCODER_MODE_1 : +case COUNTER_FUNCTION_QUADRATURE_X2_A : sms =1 ;break ; -case STM32_COUNT_ENCODER_MODE_2 : +case COUNTER_FUNCTION_QUADRATURE_X2_B : sms =2 ;break ; -case STM32_COUNT_ENCODER_MODE_3 : +case COUNTER_FUNCTION_QUADRATURE_X4 : sms =3 ;break ;default :
...
PATCH v15 3/13 counter: Update counter.h comments to reflect sysfs internalization
In reply to William Breathitt GrayThe Counter subsystem architecture and driver implementations have changed in order to handle Counter sysfs interactions in a more consistent way. This patch updates the Generic Counter interface header file comments to reflect the changes.
--- drivers/counter/counter-core.c | 3 ++ include/linux/counter.h | 62 ++++++++++++++++------------------ 2 files changed, 33 insertions(+), 32 deletions(-)
drivers/counter/counter-core.c +3 -0
@@ -38,6 +38,9 @@ static struct bus_type counter_bus_type = {* This function registers a Counter to the system. A sysfs "counter" directory * will be created and populated with sysfs attributes correlating with the * Counter Signals, Synapses, and Counts respectively. +* +* RETURNS: +* 0 on success, negative error number on failure. */ int counter_register (struct counter_device *const counter) {
include/linux/counter.h +30 -32
97 lines not on this page · raw message
Signature · 1 line
2.32.0
PATCH v15 4/13 docs: counter: Update to reflect sysfs internalization
In reply to William Breathitt GrayThe Counter subsystem architecture and driver implementations have changed in order to handle Counter sysfs interactions in a more consistent way. This patch updates the Generic Counter interface documentation to reflect the changes.
--- Documentation/ABI/testing/sysfs-bus-counter | 9 +- Documentation/driver-api/generic-counter.rst | 243 ++++++++++++++----- 2 files changed, 185 insertions(+), 67 deletions(-)
Documentation/ABI/testing/sysfs-bus-counter +8 -1
@@ -286,7 +286,14 @@ What: /sys/bus/counter/devices/counterX/signalY/signal KernelVersion: 5.2 Contact: [email protected] Description: - Signal data of Signal Y represented as a string. + Signal level state of Signal Y. The following signal level + states are available: + + low: + Low level state. + + high: + High level state. What: /sys/bus/counter/devices/counterX/signalY/synchronous_mode KernelVersion: 5.2
Documentation/driver-api/generic-counter.rst +177 -66
262 lines not on this page · raw message
Signature · 1 line
2.32.0
PATCH v15 5/13 counter: Move counter enums to uapi header
In reply to William Breathitt GrayThis is in preparation for a subsequent patch implementing a character device interface for the Counter subsystem.
--- MAINTAINERS | 1 + include/linux/counter.h | 42 +-------------------------- include/uapi/linux/counter.h | 56 ++++++++++++++++++++++++++++++++++++ 3 files changed, 58 insertions(+), 41 deletions(-) create mode 100644 include/uapi/linux/counter.h
MAINTAINERS +1 -0
@@ -4764,6 +4764,7 @@ F: Documentation/ABI/testing/sysfs-bus-counter F: Documentation/driver-api/generic-counter.rst F: drivers/counter/ F: include/linux/counter.h +F: include/uapi/linux/counter.h CP2615 I2C DRIVER M: Bence Csókás <[email protected]>
include/linux/counter.h +1 -41
54 lines not on this page · raw message
include/uapi/linux/counter.h new file +56 -0
56 lines not on this page · raw message
Signature · 1 line
2.32.0
PATCH v15 6/13 counter: Add character device interface
In reply to William Breathitt GrayThis patch introduces a character device interface for the Counter subsystem. Device data is exposed through standard character device read operations. Device data is gathered when a Counter event is pushed by the respective Counter device driver. Configuration is handled via ioctl operations on the respective Counter character device node.
--- drivers/counter/Makefile | 2 +- drivers/counter/counter-chrdev.c | 553 +++++++++++++++++++++++++++++++ drivers/counter/counter-chrdev.h | 14 + drivers/counter/counter-core.c | 60 +++- include/linux/counter.h | 51 +++ include/uapi/linux/counter.h | 98 ++++++ 6 files changed, 770 insertions(+), 8 deletions(-) create mode 100644 drivers/counter/counter-chrdev.c create mode 100644 drivers/counter/counter-chrdev.h
drivers/counter/Makefile +1 -1
@@ -4,7 +4,7 @@ # obj-$(CONFIG_COUNTER) += counter.o -counter-y := counter-core.o counter-sysfs.o +counter-y := counter-core.o counter-sysfs.o counter-chrdev.o obj-$(CONFIG_104_QUAD_8) += 104-quad-8.o obj-$(CONFIG_INTERRUPT_CNT) += interrupt-cnt.o
drivers/counter/counter-chrdev.c new file +553 -0
553 lines not on this page · raw message
drivers/counter/counter-chrdev.h new file +14 -0
@@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* +* Counter character device interface +* Copyright (C) 2020 William Breathitt Gray +*/ +#ifndef _COUNTER_CHRDEV_H_ +#define _COUNTER_CHRDEV_H_ + +#include <linux/counter.h> + +int counter_chrdev_add (struct counter_device *const counter); +void counter_chrdev_remove (struct counter_device *const counter); + +#endif /* _COUNTER_CHRDEV_H_ */
drivers/counter/counter-core.c +53 -7
127 lines not on this page · raw message
include/linux/counter.h +51 -0
96 lines not on this page · raw message
include/uapi/linux/counter.h +98 -0
110 lines not on this page · raw message
Signature · 1 line
2.32.0
PATCH v15 7/13 docs: counter: Document character device interface
In reply to William Breathitt GrayThis patch adds high-level documentation about the Counter subsystem character device interface.
--- Documentation/driver-api/generic-counter.rst | 177 ++++++++++++++---- .../userspace-api/ioctl/ioctl-number.rst | 1 + 2 files changed, 137 insertions(+), 41 deletions(-)
Documentation/driver-api/generic-counter.rst +136 -41
@@ -223,19 +223,6 @@ whether an input line is differential or single-ended) and instead focus on the core idea of what the data and process represent (e.g. position as interpreted from quadrature encoding data). -Userspace Interface -=================== - -Several sysfs attributes are generated by the Generic Counter interface, -and reside under the /sys/bus/counter/devices/counterX directory, where -counterX refers to the respective counter device. Please see -Documentation/ABI/testing/sysfs-bus-counter for detailed -information on each Generic Counter interface sysfs attribute. - -Through these sysfs attributes, programs and scripts may interact with -the Generic Counter paradigm Counts, Signals, and Synapses of respective -counter devices. - Driver API ==========
@@ -388,16 +375,16 @@ userspace interface components:: / driver callbacks / ------------------- | - +---------------+ - | - V - +--------------------+ - | Counter sysfs | - +--------------------+ - | Translates to the | - | standard Counter | - | sysfs output | - +--------------------+ + +---------------+---------------+ + | | + V V + +--------------------+ +---------------------+ + | Counter sysfs | | Counter chrdev | + +--------------------+ +---------------------+ + | Translates to the | | Translates to the | + | standard Counter | | standard Counter | + | sysfs output | | character device | + +--------------------+ +---------------------+ Thereafter, data can be transferred directly between the Counter device driver and Counter userspace interface::
@@ -428,23 +415,30 @@ driver and Counter userspace interface:: / u64 / ---------- | - +---------------+ - | - V - +--------------------+ - | Counter sysfs | - +--------------------+ - | Translates to the | - | standard Counter | - | sysfs output | - |--------------------| - | Type: const char * | - | Value: "42" | - +--------------------+ - | - --------------- - / const char * / - --------------- + +---------------+---------------+ + | | + V V + +--------------------+ +---------------------+ + | Counter sysfs | | Counter chrdev | + +--------------------+ +---------------------+ + | Translates to the | | Translates to the | + | standard Counter | | standard Counter | + | sysfs output | | character device | + |--------------------| |---------------------| + | Type: const char * | | Type: u64 | + | Value: "42" | | Value: 42 | + +--------------------+ +---------------------+ + | | + --------------- ----------------------- + / const char * / / struct counter_event / + --------------- ----------------------- + | | + | V + | +-----------+ + | | read | + | +-----------+ + | \ Count: 42 / + | ----------- | V +--------------------------------------------------+
@@ -453,7 +447,7 @@ driver and Counter userspace interface:: \ Count: "42" / -------------------------------------------------- -There are three primary components involved: +There are four primary components involved: Counter device driver ---------------------
@@ -473,3 +467,104 @@ and vice versa. Please refer to the ``Documentation/ABI/testing/sysfs-bus-counter`` file for a detailed breakdown of the available Generic Counter interface sysfs attributes. + +Counter chrdev +-------------- +Translates counter data to the standard Counter character device; data +is transferred via standard character device read calls, while Counter +events are configured via ioctl calls. + +Sysfs Interface +=============== + +Several sysfs attributes are generated by the Generic Counter interface, +and reside under the ``/sys/bus/counter/devices/counterX`` directory, +where ``X`` is to the respective counter device id. Please see +``Documentation/ABI/testing/sysfs-bus-counter`` for detailed information +on each Generic Counter interface sysfs attribute. + +Through these sysfs attributes, programs and scripts may interact with +the Generic Counter paradigm Counts, Signals, and Synapses of respective +counter devices. + +Counter Character Device +======================== + +Counter character device nodes are created under the ``/dev`` directory +as ``counterX``, where ``X`` is the respective counter device id. +Defines for the standard Counter data types are exposed via the +userspace ``include/uapi/linux/counter.h`` file. + +Counter events +-------------- +Counter device drivers can support Counter events by utilizing the +``counter_push_event`` function:: + + void counter_push_event(struct counter_device *const counter, const u8 event, + const u8 channel); + +The event id is specified by the ``event`` parameter; the event channel +id is specified by the ``channel`` parameter. When this function is +called, the Counter data associated with the respective event is +gathered, and a ``struct counter_event`` is generated for each datum and +pushed to userspace. + +Counter events can be configured by users to report various Counter +data of interest. This can be conceptualized as a list of Counter +component read calls to perform. For example: + + +-------------------------------------------------+ + | COUNTER_EVENT_OVERFLOW | COUNTER_EVENT_INDEX | + +========================+========================+ + | Channel 0 | Channel 0 | + +------------------------+------------------------+ + | * Count 0 | * Signal 0 | + | * Count 1 | * Signal 0 Extension 0 | + | * Signal 3 | * Extension 4 | + | * Count 4 Extension 2 +------------------------+ + | * Signal 5 Extension 0 | Channel 1 | + | +------------------------+ + | | * Signal 4 | + | | * Signal 4 Extension 0 | + | | * Count 7 | + +------------------------+------------------------+ + +When ``counter_push_event(counter, COUNTER_EVENT_INDEX, 1)`` is called +for example, it will go down the list for the ``COUNTER_EVENT_INDEX`` +event channel 1 and execute the read callbacks for Signal 4, Signal 4 +Extension 0, and Count 4 -- the data returned for each is pushed to a +kfifo as a ``struct counter_event``, which userspace can retrieve via a +standard read operation on the respective character device node. + +Userspace +--------- +Userspace applications can configure Counter events via ioctl operations +on the Counter character device node. There following ioctl codes are +supported and provided by the ``linux/counter.h`` userspace header file: + +* :c:macro:`COUNTER_ADD_WATCH_IOCTL` + +* :c:macro:`COUNTER_ENABLE_EVENTS_IOCTL` + +* :c:macro:`COUNTER_DISABLE_EVENTS_IOCTL` + +To configure events to gather Counter data, users first populate a +``struct counter_watch`` with the relevant event id, event channel id, +and the information for the desired Counter component from which to +read, and then pass it via the ``COUNTER_ADD_WATCH_IOCTL`` ioctl +command. + +Note that an event can be watched without gathering Counter data by +setting the ``component.type`` member equal to +``COUNTER_COMPONENT_NONE``. With this configuration the Counter +character device will simply populate the event timestamps for those +respective ``struct counter_event`` elements and ignore the component +value. + +The ``COUNTER_ADD_WATCH_IOCTL`` command will buffer these Counter +watches. When ready, the ``COUNTER_ENABLE_EVENTS_IOCTL`` ioctl command +may be used to activate these Counter watches. + +Userspace applications can then execute a ``read`` operation (optionally +calling ``poll`` first) on the Counter character device node to retrieve +``struct counter_event`` elements with the desired data.
Documentation/userspace-api/ioctl/ioctl-number.rst +1 -0
@@ -88,6 +88,7 @@ Code Seq# Include File Comments <http://infiniband.sourceforge.net/> 0x20 all drivers/cdrom/cm206.h 0x22 all scsi/sg.h +0x3E 00-0F linux/counter.h <mailto:[email protected]> '!' 00-1F uapi/linux/seccomp.h '#' 00-3F IEEE 1394 Subsystem Block for the entire subsystem
Signature · 1 line
2.32.0
Jonathan Cameron
maintainerRe: [PATCH v15 07/13] docs: counter: Document character device interface
Quoted 4 lines · On Mon, 9 Aug 2021 21:37:32 +0900 William Breathitt Gray…
This patch adds high-level documentation about the Counter subsystem character device interface.
Signed-off-by William Breathitt Gray <[email protected]>
Hi William,
Trivial probable typo inline.
I'm struggling somewhat with these interfaces because I simply don't know enough about how people use counters to know whether they provide everything people will want. They feel similar to the event handling type functions you can set up in motor drives, so they may well make sense, but ideally we need review from someone (other than yourself!) who actually uses this stuff on a regular basis.
If we don't get any additional review I guess we go ahead anyway next cycle.
Jonathan
Quoted 17 lines
---
Documentation/driver-api/generic-counter.rst +15
-0+ +Counter events can be configured by users to report various Counter +data of interest. This can be conceptualized as a list of Counter +component read calls to perform. For example: + + +-------------------------------------------------+ + | COUNTER_EVENT_OVERFLOW | COUNTER_EVENT_INDEX | + +========================+========================+ + | Channel 0 | Channel 0 | + +------------------------+------------------------+ + | * Count 0 | * Signal 0 | + | * Count 1 | * Signal 0 Extension 0 | + | * Signal 3 | * Extension 4 | + | * Count 4 Extension 2 +------------------------+ + | * Signal 5 Extension 0 | Channel 1 |
Documentation/driver-api/generic-counter.rst and vice versa. · line 535
Quoted 10 lines
Documentation/driver-api/generic-counter.rst +10
-0+ | +------------------------+ + | | * Signal 4 | + | | * Signal 4 Extension 0 | + | | * Count 7 | + +------------------------+------------------------+ + +When ``counter_push_event(counter, COUNTER_EVENT_INDEX, 1)`` is called +for example, it will go down the list for the ``COUNTER_EVENT_INDEX`` +event channel 1 and execute the read callbacks for Signal 4, Signal 4 +Extension 0, and Count 4 -- the data returned for each is pushed to a
Count 7?
Quoted 5 lines
Documentation/driver-api/generic-counter.rst +3
-0+kfifo as a ``struct counter_event``, which userspace can retrieve via a +standard read operation on the respective character device node. + Block for the entire subsystem
Re: [PATCH v15 07/13] docs: counter: Document character device interface
Quoted 45 lines · Jonathan Cameron
Quoted 4 lines · On Mon, 9 Aug 2021 21:37:32 +0900 William Breathitt Gray…
This patch adds high-level documentation about the Counter subsystem character device interface.
Signed-off-by William Breathitt Gray <[email protected]>Hi William,
Trivial probable typo inline.
I'm struggling somewhat with these interfaces because I simply don't know enough about how people use counters to know whether they provide everything people will want. They feel similar to the event handling type functions you can set up in motor drives, so they may well make sense, but ideally we need review from someone (other than yourself!) who actually uses this stuff on a regular basis.
If we don't get any additional review I guess we go ahead anyway next cycle.
Jonathan
Quoted 21 lines
---
Documentation/driver-api/generic-counter.rst +19
-0+ +Counter events can be configured by users to report various Counter +data of interest. This can be conceptualized as a list of Counter +component read calls to perform. For example: + + +-------------------------------------------------+ + | COUNTER_EVENT_OVERFLOW | COUNTER_EVENT_INDEX | + +========================+========================+ + | Channel 0 | Channel 0 | + +------------------------+------------------------+ + | * Count 0 | * Signal 0 | + | * Count 1 | * Signal 0 Extension 0 | + | * Signal 3 | * Extension 4 | + | * Count 4 Extension 2 +------------------------+ + | * Signal 5 Extension 0 | Channel 1 | + | +------------------------+ + | | * Signal 4 | + | | * Signal 4 Extension 0 | + | | * Count 7 |
Quoted 8 lines
Documentation/driver-api/generic-counter.rst and vice versa. · line 535
Quoted 6 lines
Documentation/driver-api/generic-counter.rst +6
-0+ +------------------------+------------------------+ + +When ``counter_push_event(counter, COUNTER_EVENT_INDEX, 1)`` is called +for example, it will go down the list for the ``COUNTER_EVENT_INDEX`` +event channel 1 and execute the read callbacks for Signal 4, Signal 4 +Extension 0, and Count 4 -- the data returned for each is pushed to aCount 7?
Looks like my finger slipped on my numpad and hit 4 when I intended 7. I'll fix this for v16, thanks.
William Breathitt Gray
Re: [PATCH v15 07/13] docs: counter: Document character device interface
(dropped most CCs)
Hello William,
I spotted a minor error while browsing documentation updates.
Quoted 3 lines · William Breathitt Gray
Quoted 2 lines · Jonathan Cameron
On Mon, 9 Aug 2021 21:37:32 +0900
William Breathitt Gray <[email protected]> wrote:
...
Quoted 6 lines
Quoted 6 lines
Documentation/driver-api/generic-counter.rst and vice versa. · line 516
Quoted 6 lines
Documentation/driver-api/generic-counter.rst +6
-0+ +Counter events can be configured by users to report various Counter +data of interest. This can be conceptualized as a list of Counter +component read calls to perform. For example: + + +-------------------------------------------------+
This needs to be:
+------------------------+------------------------+
, so that the table structure can be properly recognized by Sphinx (kernel-doc tool).
Thanks, Akira
Quoted 15 lines
Quoted 15 lines
Quoted 15 lines
Documentation/driver-api/generic-counter.rst +15
-0+ | COUNTER_EVENT_OVERFLOW | COUNTER_EVENT_INDEX | + +========================+========================+ + | Channel 0 | Channel 0 | + +------------------------+------------------------+ + | * Count 0 | * Signal 0 | + | * Count 1 | * Signal 0 Extension 0 | + | * Signal 3 | * Extension 4 | + | * Count 4 Extension 2 +------------------------+ + | * Signal 5 Extension 0 | Channel 1 | + | +------------------------+ + | | * Signal 4 | + | | * Signal 4 Extension 0 | + | | * Count 7 | + +------------------------+------------------------+ +
PATCH v15 8/13 tools/counter: Create Counter tools
In reply to William Breathitt GrayThis creates an example Counter program under tools/counter/* to exemplify the Counter character device interface.
--- MAINTAINERS | 1 + tools/Makefile | 13 ++--- tools/counter/Build | 1 + tools/counter/Makefile | 53 +++++++++++++++++++ tools/counter/counter_example.c | 93 +++++++++++++++++++++++++++++++++ 5 files changed, 155 insertions(+), 6 deletions(-) create mode 100644 tools/counter/Build create mode 100644 tools/counter/Makefile create mode 100644 tools/counter/counter_example.c
MAINTAINERS +1 -0
@@ -4765,6 +4765,7 @@ F: Documentation/driver-api/generic-counter.rst F: drivers/counter/ F: include/linux/counter.h F: include/uapi/linux/counter.h +F: tools/counter/ CP2615 I2C DRIVER M: Bence Csókás <[email protected]>
tools/Makefile +7 -6
@@ -12,6 +12,7 @@ help: @echo ' acpi - ACPI tools' @echo ' bpf - misc BPF tools' @echo ' cgroup - cgroup tools' + @echo ' counter - counter tools' @echo ' cpupower - a tool for all things x86 CPU power' @echo ' debugging - tools for debugging' @echo ' firewire - the userspace part of nosy, an IEEE-1394 traffic sniffer'
@@ -65,7 +66,7 @@ acpi: FORCE cpupower: FORCE $(call descend,power/$@) -cgroup firewire hv guest bootconfig spi usb virtio vm bpf iio gpio objtool leds wmi pci firmware debugging tracing: FORCE +cgroup counter firewire hv guest bootconfig spi usb virtio vm bpf iio gpio objtool leds wmi pci firmware debugging tracing: FORCE $(call descend,$@) bpf/%: FORCE
@@ -100,7 +101,7 @@ freefall: FORCE kvm_stat: FORCE $(call descend,kvm/$@) -all: acpi cgroup cpupower gpio hv firewire liblockdep \ +all: acpi cgroup counter cpupower gpio hv firewire liblockdep \ perf selftests bootconfig spi turbostat usb \ virtio vm bpf x86_energy_perf_policy \ tmon freefall iio objtool kvm_stat wmi \
@@ -112,7 +113,7 @@ acpi_install: cpupower_install: $(call descend,power/$(@:_install=),install) -cgroup_install firewire_install gpio_install hv_install iio_install perf_install bootconfig_install spi_install usb_install virtio_install vm_install bpf_install objtool_install wmi_install pci_install debugging_install tracing_install: +cgroup_install counter_install firewire_install gpio_install hv_install iio_install perf_install bootconfig_install spi_install usb_install virtio_install vm_install bpf_install objtool_install wmi_install pci_install debugging_install tracing_install: $(call descend,$(@:_install=),install) liblockdep_install:
@@ -133,7 +134,7 @@ freefall_install: kvm_stat_install: $(call descend,kvm/$(@:_install=),install) -install: acpi_install cgroup_install cpupower_install gpio_install \ +install: acpi_install cgroup_install counter_install cpupower_install gpio_install \ hv_install firewire_install iio_install liblockdep_install \ perf_install selftests_install turbostat_install usb_install \ virtio_install vm_install bpf_install x86_energy_perf_policy_install \
@@ -147,7 +148,7 @@ acpi_clean: cpupower_clean: $(call descend,power/cpupower,clean) -cgroup_clean hv_clean firewire_clean bootconfig_clean spi_clean usb_clean virtio_clean vm_clean wmi_clean bpf_clean iio_clean gpio_clean objtool_clean leds_clean pci_clean firmware_clean debugging_clean tracing_clean: +cgroup_clean counter_clean hv_clean firewire_clean bootconfig_clean spi_clean usb_clean virtio_clean vm_clean wmi_clean bpf_clean iio_clean gpio_clean objtool_clean leds_clean pci_clean firmware_clean debugging_clean tracing_clean: $(call descend,$(@:_clean=),clean) liblockdep_clean:
@@ -181,7 +182,7 @@ freefall_clean: build_clean: $(call descend,build,clean) -clean: acpi_clean cgroup_clean cpupower_clean hv_clean firewire_clean \ +clean: acpi_clean cgroup_clean counter_clean cpupower_clean hv_clean firewire_clean \ perf_clean selftests_clean turbostat_clean bootconfig_clean spi_clean usb_clean virtio_clean \ vm_clean bpf_clean iio_clean x86_energy_perf_policy_clean tmon_clean \ freefall_clean build_clean libbpf_clean libsubcmd_clean liblockdep_clean \
tools/counter/Build new file +1 -0
@@ -0,0 +1 @@ +counter_example-y += counter_example.o
tools/counter/Makefile new file +53 -0
53 lines not on this page · raw message
tools/counter/counter_example.c new file +93 -0
93 lines not on this page · raw message
Signature · 1 line
2.32.0
PATCH v15 9/13 counter: Implement signalZ_action_component_id sysfs attribute
In reply to William Breathitt GrayThe Generic Counter chrdev interface expects users to supply component IDs in order to select Synapses for requests. In order for users to know what component ID belongs to which Synapse this information must be exposed. The signalZ_action_component_id attribute provides a way for users to discover what component ID belongs to the respective Synapse.
--- Documentation/ABI/testing/sysfs-bus-counter | 7 ++++ drivers/counter/counter-sysfs.c | 46 ++++++++++++++++++++- 2 files changed, 52 insertions(+), 1 deletion(-)
Documentation/ABI/testing/sysfs-bus-counter +7 -0
@@ -203,6 +203,13 @@ Description: both edges: Any state transition. +What: /sys/bus/counter/devices/counterX/countY/signalZ_action_component_id +KernelVersion: 5.15 +Contact: [email protected] +Description: + Read-only attribute that indicates the component ID of the + respective Synapse of Count Y for Signal Z. + What: /sys/bus/counter/devices/counterX/countY/spike_filter_ns KernelVersion: 5.14 Contact: [email protected]
drivers/counter/counter-sysfs.c +45 -1
64 lines not on this page · raw message
Signature · 1 line
2.32.0
Jonathan Cameron
maintainerRe: [PATCH v15 09/13] counter: Implement signalZ_action_component_id sysfs attribute
Quoted 18 lines · On Mon, 9 Aug 2021 21:37:34 +0900 William Breathitt Gray…
The Generic Counter chrdev interface expects users to supply component IDs in order to select Synapses for requests. In order for users to know what component ID belongs to which Synapse this information must be exposed. The
signalZ_action_component_idattribute provides a way for users to discover what component ID belongs to the respective Synapse.Cc Gwendal Grignou <[email protected]>Cc Dan Carpenter <[email protected]>Reviewed-by David Lechner <[email protected]>Signed-off-by William Breathitt Gray <[email protected]>---
Contact: [email protected]
drivers/counter/counter-sysfs.c +0
-0
drivers/counter/counter-sysfs.c static int counter_avail_attr_create(struct device *const dev, · line 396
Quoted 4 lines
drivers/counter/counter-sysfs.c +0
-1@@ -393,7 +393,6 @@ static int counter_avail_attr_create(struct device *const dev,struct counter_attribute *counter_attr;struct device_attribute *dev_attr; -/* Allocate Counter attribute */
Trivial, but this is an unrelated change and shouldn't be in this patch (it's just noise).
Quoted 7 lines
drivers/counter/counter-sysfs.c +0
-0counter_attr =devm_kzalloc (dev,sizeof (*counter_attr),GFP_KERNEL );if (!counter_attr)return -ENOMEM ;@@ -535,6 +534,46 @@ static int counter_name_attr_create(struct device *const dev,return 0 ; }
PATCH v15 10/13 counter: Implement *_component_id sysfs attributes
In reply to William Breathitt GrayThe Generic Counter chrdev interface expects users to supply component IDs in order to select extensions for requests. In order for users to know what component ID belongs to which extension this information must be exposed. The *_component_id attribute provides a way for users to discover what component ID belongs to which respective extension.
--- Documentation/ABI/testing/sysfs-bus-counter | 16 +++++++++- drivers/counter/counter-sysfs.c | 33 +++++++++++++++++---- 2 files changed, 42 insertions(+), 7 deletions(-)
Documentation/ABI/testing/sysfs-bus-counter +15 -1
@@ -203,12 +203,26 @@ Description: both edges: Any state transition. +What: /sys/bus/counter/devices/counterX/countY/ceiling_component_id +What: /sys/bus/counter/devices/counterX/countY/floor_component_id +What: /sys/bus/counter/devices/counterX/countY/count_mode_component_id +What: /sys/bus/counter/devices/counterX/countY/direction_component_id +What: /sys/bus/counter/devices/counterX/countY/enable_component_id +What: /sys/bus/counter/devices/counterX/countY/error_noise_component_id +What: /sys/bus/counter/devices/counterX/countY/prescaler_component_id +What: /sys/bus/counter/devices/counterX/countY/preset_component_id +What: /sys/bus/counter/devices/counterX/countY/preset_enable_component_id What: /sys/bus/counter/devices/counterX/countY/signalZ_action_component_id +What: /sys/bus/counter/devices/counterX/signalY/cable_fault_component_id +What: /sys/bus/counter/devices/counterX/signalY/cable_fault_enable_component_id +What: /sys/bus/counter/devices/counterX/signalY/filter_clock_prescaler_component_id +What: /sys/bus/counter/devices/counterX/signalY/index_polarity_component_id +What: /sys/bus/counter/devices/counterX/signalY/synchronous_mode_component_id KernelVersion: 5.15 Contact: [email protected] Description: Read-only attribute that indicates the component ID of the - respective Synapse of Count Y for Signal Z. + respective extension or Synapse. What: /sys/bus/counter/devices/counterX/countY/spike_filter_ns KernelVersion: 5.14
drivers/counter/counter-sysfs.c +27 -6
@@ -588,6 +588,7 @@ static int counter_signal_attrs_create(struct counter_device *const counter,int err;struct counter_comp comp;size_t i; +struct counter_comp *ext;/* Create main Signal attribute */ comp = counter_signal_comp;
@@ -603,8 +604,14 @@ static int counter_signal_attrs_create(struct counter_device *const counter,/* Create an attribute for each extension */ for (i =0 ; i < signal->num_ext; i++) { - err =counter_attr_create (dev, cattr_group, signal->ext + i, - scope, signal); + ext = &signal->ext[i]; + + err =counter_attr_create (dev, cattr_group, ext, scope, signal); +if (err <0 ) +return err; + + err =counter_comp_id_attr_create (dev, cattr_group, ext->name, + i);if (err <0 )return err; }
@@ -695,6 +702,7 @@ static int counter_count_attrs_create(struct counter_device *const counter,int err;struct counter_comp comp;size_t i; +struct counter_comp *ext;/* Create main Count attribute */ comp = counter_count_comp;
@@ -719,8 +727,14 @@ static int counter_count_attrs_create(struct counter_device *const counter,/* Create an attribute for each extension */ for (i =0 ; i < count->num_ext; i++) { - err =counter_attr_create (dev, cattr_group, count->ext + i, - scope, count); + ext = &count->ext[i]; + + err =counter_attr_create (dev, cattr_group, ext, scope, count); +if (err <0 ) +return err; + + err =counter_comp_id_attr_create (dev, cattr_group, ext->name, + i);if (err <0 )return err; }
@@ -784,6 +798,7 @@ static int counter_sysfs_attr_add(struct counter_device *const counter,struct device *const dev = &counter->dev;int err;size_t i; +struct counter_comp *ext;/* Add Signals sysfs attributes */ err =counter_sysfs_signals_add (counter, cattr_group);
@@ -816,8 +831,14 @@ static int counter_sysfs_attr_add(struct counter_device *const counter,/* Create an attribute for each extension */ for (i =0 ; i < counter->num_ext; i++) { - err =counter_attr_create (dev, cattr_group, counter->ext + i, - scope,NULL ); + ext = &counter->ext[i]; + + err =counter_attr_create (dev, cattr_group, ext, scope,NULL ); +if (err <0 ) +return err; + + err =counter_comp_id_attr_create (dev, cattr_group, ext->name, + i);if (err <0 )return err; }
Signature · 1 line
2.32.0
PATCH v15 11/13 counter: Implement events_queue_size sysfs attribute
In reply to William Breathitt GrayThe events_queue_size sysfs attribute provides a way for users to dynamically configure the Counter events queue size for the Counter character device interface. The size is in number of struct counter_event data structures. The number of elements will be rounded-up to a power of 2 due to a requirement of the kfifo_alloc function called during reallocation of the queue.
--- Documentation/ABI/testing/sysfs-bus-counter | 8 ++++ drivers/counter/counter-sysfs.c | 45 +++++++++++++++++++++ 2 files changed, 53 insertions(+)
Documentation/ABI/testing/sysfs-bus-counter +8 -0
@@ -233,6 +233,14 @@ Description: shorter or equal to configured value are ignored. Value 0 means filter is disabled. +What: /sys/bus/counter/devices/counterX/events_queue_size +KernelVersion: 5.15 +Contact: [email protected] +Description: + Size of the Counter events queue in number of struct + counter_event data structures. The number of elements will be + rounded-up to a power of 2. + What: /sys/bus/counter/devices/counterX/name KernelVersion: 5.2 Contact: [email protected]
drivers/counter/counter-sysfs.c +45 -0
74 lines not on this page · raw message
Signature · 1 line
2.32.0
PATCH v15 12/13 counter: 104-quad-8: Replace mutex with spinlock
In reply to William Breathitt GrayThis patch replaces the mutex I/O lock with a spinlock. This is in preparation for a subsequent patch adding IRQ support for 104-QUAD-8 devices; we can't sleep in an interrupt context, so we'll need to use a spinlock instead.
--- drivers/counter/104-quad-8.c | 89 +++++++++++++++++++++--------------- 1 file changed, 52 insertions(+), 37 deletions(-)
drivers/counter/104-quad-8.c +52 -37
@@ -16,6 +16,7 @@#include <linux/module.h> #include <linux/moduleparam.h> #include <linux/types.h> +#include <linux/spinlock.h> #define QUAD8_EXTENT 32
@@ -43,7 +44,7 @@ MODULE_PARM_DESC(base, "ACCES 104-QUAD-8 base addresses");* @base: base port address of the device */ struct quad8 { -struct mutex lock; +spinlock_t lock;struct counter_device counter;unsigned int fck_prescaler[QUAD8_NUM_COUNTERS ];unsigned int preset[QUAD8_NUM_COUNTERS ];
@@ -124,6 +125,7 @@ static int quad8_count_read(struct counter_device *counter,unsigned int flags;unsigned int borrow;unsigned int carry; +unsigned long irqflags;int i; flags =inb (base_offset +1 );
@@ -133,7 +135,7 @@ static int quad8_count_read(struct counter_device *counter,/* Borrow XOR Carry effectively doubles count range */ *val = (unsigned long )(borrow ^ carry) <<24 ; -mutex_lock (&priv->lock); +spin_lock_irqsave (&priv->lock, irqflags);/* Reset Byte Pointer; transfer Counter to Output Latch */ outb(QUAD8_CTR_RLD | QUAD8_RLD_RESET_BP | QUAD8_RLD_CNTR_OUT,
@@ -142,7 +144,7 @@ static int quad8_count_read(struct counter_device *counter,for (i =0 ; i <3 ; i++) *val |= (unsigned long )inb (base_offset) << (8 * i); -mutex_unlock (&priv->lock); +spin_unlock_irqrestore (&priv->lock, irqflags);return 0 ; }
@@ -152,13 +154,14 @@ static int quad8_count_write(struct counter_device *counter, {struct quad8 *const priv = counter->priv;const int base_offset = priv->base +2 * count->id; +unsigned long irqflags;int i;/* Only 24-bit values are supported */ if (val >0xFFFFFF )return -ERANGE ; -mutex_lock (&priv->lock); +spin_lock_irqsave (&priv->lock, irqflags);/* Reset Byte Pointer */ outb (QUAD8_CTR_RLD |QUAD8_RLD_RESET_BP , base_offset +1 );
@@ -183,7 +186,7 @@ static int quad8_count_write(struct counter_device *counter,/* Reset Error flag */ outb (QUAD8_CTR_RLD |QUAD8_RLD_RESET_E , base_offset +1 ); -mutex_unlock (&priv->lock); +spin_unlock_irqrestore (&priv->lock, irqflags);return 0 ; }
@@ -201,8 +204,9 @@ static int quad8_function_read(struct counter_device *counter, {struct quad8 *const priv = counter->priv;const int id = count->id; +unsigned long irqflags; -mutex_lock (&priv->lock); +spin_lock_irqsave (&priv->lock, irqflags);if (priv->quadrature_mode[id])switch (priv->quadrature_scale[id]) {
@@ -219,7 +223,7 @@ static int quad8_function_read(struct counter_device *counter,else *function =COUNTER_FUNCTION_PULSE_DIRECTION ; -mutex_unlock (&priv->lock); +spin_unlock_irqrestore (&priv->lock, irqflags);return 0 ; }
@@ -234,10 +238,11 @@ static int quad8_function_write(struct counter_device *counter,unsigned int *const scale = priv->quadrature_scale + id;unsigned int *const synchronous_mode = priv->synchronous_mode + id;const int base_offset = priv->base +2 * id +1 ; +unsigned long irqflags;unsigned int mode_cfg;unsigned int idr_cfg; -mutex_lock (&priv->lock); +spin_lock_irqsave (&priv->lock, irqflags); mode_cfg = priv->count_mode[id] <<1 ; idr_cfg = priv->index_polarity[id] <<1 ;
@@ -272,7 +277,7 @@ static int quad8_function_write(struct counter_device *counter,break ;default :/* should never reach this path */ -mutex_unlock (&priv->lock); +spin_unlock_irqrestore (&priv->lock, irqflags);return -EINVAL ; } }
@@ -280,7 +285,7 @@ static int quad8_function_write(struct counter_device *counter,/* Load mode configuration to Counter Mode Register */ outb (QUAD8_CTR_CMR | mode_cfg, base_offset); -mutex_unlock (&priv->lock); +spin_unlock_irqrestore (&priv->lock, irqflags);return 0 ; }
@@ -406,9 +411,10 @@ static int quad8_index_polarity_set(struct counter_device *counter,struct quad8 *const priv = counter->priv;const size_t channel_id = signal->id -16 ;const int base_offset = priv->base +2 * channel_id +1 ; +unsigned long irqflags;unsigned int idr_cfg = index_polarity <<1 ; -mutex_lock (&priv->lock); +spin_lock_irqsave (&priv->lock, irqflags); idr_cfg |= priv->synchronous_mode[channel_id];
@@ -417,7 +423,7 @@ static int quad8_index_polarity_set(struct counter_device *counter,/* Load Index Control configuration to Index Control Register */ outb (QUAD8_CTR_IDR | idr_cfg, base_offset); -mutex_unlock (&priv->lock); +spin_unlock_irqrestore (&priv->lock, irqflags);return 0 ; }
@@ -446,15 +452,16 @@ static int quad8_synchronous_mode_set(struct counter_device *counter,struct quad8 *const priv = counter->priv;const size_t channel_id = signal->id -16 ;const int base_offset = priv->base +2 * channel_id +1 ; +unsigned long irqflags;unsigned int idr_cfg = synchronous_mode; -mutex_lock (&priv->lock); +spin_lock_irqsave (&priv->lock, irqflags); idr_cfg |= priv->index_polarity[channel_id] <<1 ;/* Index function must be non-synchronous in non-quadrature mode */ if (synchronous_mode && !priv->quadrature_mode[channel_id]) { -mutex_unlock (&priv->lock); +spin_unlock_irqrestore (&priv->lock, irqflags);return -EINVAL ; }
@@ -463,7 +470,7 @@ static int quad8_synchronous_mode_set(struct counter_device *counter,/* Load Index Control configuration to Index Control Register */ outb (QUAD8_CTR_IDR | idr_cfg, base_offset); -mutex_unlock (&priv->lock); +spin_unlock_irqrestore (&priv->lock, irqflags);return 0 ; }
@@ -510,6 +517,7 @@ static int quad8_count_mode_write(struct counter_device *counter,unsigned int count_mode;unsigned int mode_cfg;const int base_offset = priv->base +2 * count->id +1 ; +unsigned long irqflags;/* Map Generic Counter count mode to 104-QUAD-8 count mode */ switch (cnt_mode) {
@@ -530,7 +538,7 @@ static int quad8_count_mode_write(struct counter_device *counter,return -EINVAL ; } -mutex_lock (&priv->lock); +spin_lock_irqsave (&priv->lock, irqflags); priv->count_mode[count->id] = count_mode;
@@ -544,7 +552,7 @@ static int quad8_count_mode_write(struct counter_device *counter,/* Load mode configuration to Counter Mode Register */ outb (QUAD8_CTR_CMR | mode_cfg, base_offset); -mutex_unlock (&priv->lock); +spin_unlock_irqrestore (&priv->lock, irqflags);return 0 ; }
@@ -564,9 +572,10 @@ static int quad8_count_enable_write(struct counter_device *counter, {struct quad8 *const priv = counter->priv;const int base_offset = priv->base +2 * count->id; +unsigned long irqflags;unsigned int ior_cfg; -mutex_lock (&priv->lock); +spin_lock_irqsave (&priv->lock, irqflags); priv->ab_enable[count->id] = enable;
@@ -575,7 +584,7 @@ static int quad8_count_enable_write(struct counter_device *counter,/* Load I/O control configuration */ outb (QUAD8_CTR_IOR | ior_cfg, base_offset +1 ); -mutex_unlock (&priv->lock); +spin_unlock_irqrestore (&priv->lock, irqflags);return 0 ; }
@@ -626,16 +635,17 @@ static int quad8_count_preset_write(struct counter_device *counter, struct counter_count *count, u64 preset) {struct quad8 *const priv = counter->priv; +unsigned long irqflags;/* Only 24-bit values are supported */ if (preset >0xFFFFFF )return -ERANGE ; -mutex_lock (&priv->lock); +spin_lock_irqsave (&priv->lock, irqflags);quad8_preset_register_set (priv, count->id, preset); -mutex_unlock (&priv->lock); +spin_unlock_irqrestore (&priv->lock, irqflags);return 0 ; }
@@ -644,8 +654,9 @@ static int quad8_count_ceiling_read(struct counter_device *counter, struct counter_count *count, u64 *ceiling) { struct quad8 *const priv = counter->priv; +unsigned long irqflags; -mutex_lock (&priv->lock); +spin_lock_irqsave (&priv->lock, irqflags);/* Range Limit and Modulo-N count modes use preset value as ceiling */ switch (priv->count_mode[count->id]) {
@@ -659,7 +670,7 @@ static int quad8_count_ceiling_read(struct counter_device *counter,break ; } -mutex_unlock (&priv->lock); +spin_unlock_irqrestore (&priv->lock, irqflags);return 0 ; }
@@ -668,23 +679,24 @@ static int quad8_count_ceiling_write(struct counter_device *counter, struct counter_count *count, u64 ceiling) {struct quad8 *const priv = counter->priv; +unsigned long irqflags;/* Only 24-bit values are supported */ if (ceiling >0xFFFFFF )return -ERANGE ; -mutex_lock (&priv->lock); +spin_lock_irqsave (&priv->lock, irqflags);/* Range Limit and Modulo-N count modes use preset value as ceiling */ switch (priv->count_mode[count->id]) {case 1 :case 3 :quad8_preset_register_set (priv, count->id, ceiling); -mutex_unlock (&priv->lock); +spin_unlock_irqrestore (&priv->lock, irqflags);return 0 ; } -mutex_unlock (&priv->lock); +spin_unlock_irqrestore (&priv->lock, irqflags);return -EINVAL ; }
@@ -706,12 +718,13 @@ static int quad8_count_preset_enable_write(struct counter_device *counter, {struct quad8 *const priv = counter->priv;const int base_offset = priv->base +2 * count->id +1 ; +unsigned long irqflags;unsigned int ior_cfg;/* Preset enable is active low in Input/Output Control register */ preset_enable = !preset_enable; -mutex_lock (&priv->lock); +spin_lock_irqsave (&priv->lock, irqflags); priv->preset_enable[count->id] = preset_enable;
@@ -720,7 +733,7 @@ static int quad8_count_preset_enable_write(struct counter_device *counter,/* Load I/O control configuration to Input / Output Control Register */ outb (QUAD8_CTR_IOR | ior_cfg, base_offset); -mutex_unlock (&priv->lock); +spin_unlock_irqrestore (&priv->lock, irqflags);return 0 ; }
@@ -731,22 +744,23 @@ static int quad8_signal_cable_fault_read(struct counter_device *counter, {struct quad8 *const priv = counter->priv;const size_t channel_id = signal->id /2 ; +unsigned long irqflags;bool disabled;unsigned int status; -mutex_lock (&priv->lock); +spin_lock_irqsave (&priv->lock, irqflags); disabled = !(priv->cable_fault_enable &BIT (channel_id));if (disabled) { -mutex_unlock (&priv->lock); +spin_unlock_irqrestore (&priv->lock, irqflags);return -EINVAL ; }/* Logic 0 = cable fault */ status =inb (priv->base +QUAD8_DIFF_ENCODER_CABLE_STATUS ); -mutex_unlock (&priv->lock); +spin_unlock_irqrestore (&priv->lock, irqflags);/* Mask respective channel and invert logic */ *cable_fault = !(status &BIT (channel_id));
@@ -772,9 +786,10 @@ static int quad8_signal_cable_fault_enable_write(struct counter_device *counter, {struct quad8 *const priv = counter->priv;const size_t channel_id = signal->id /2 ; +unsigned long irqflags;unsigned int cable_fault_enable; -mutex_lock (&priv->lock); +spin_lock_irqsave (&priv->lock, irqflags);if (enable) priv->cable_fault_enable |=BIT (channel_id);
@@ -786,7 +801,7 @@ static int quad8_signal_cable_fault_enable_write(struct counter_device *counter,outb (cable_fault_enable, priv->base +QUAD8_DIFF_ENCODER_CABLE_STATUS ); -mutex_unlock (&priv->lock); +spin_unlock_irqrestore (&priv->lock, irqflags);return 0 ; }
@@ -809,8 +824,9 @@ static int quad8_signal_fck_prescaler_write(struct counter_device *counter,struct quad8 *const priv = counter->priv;const size_t channel_id = signal->id /2 ;const int base_offset = priv->base +2 * channel_id; +unsigned long irqflags; -mutex_lock (&priv->lock); +spin_lock_irqsave (&priv->lock, irqflags); priv->fck_prescaler[channel_id] = prescaler;
@@ -822,7 +838,7 @@ static int quad8_signal_fck_prescaler_write(struct counter_device *counter,outb (QUAD8_CTR_RLD |QUAD8_RLD_RESET_BP |QUAD8_RLD_PRESET_PSC , base_offset +1 ); -mutex_unlock (&priv->lock); +spin_unlock_irqrestore (&priv->lock, irqflags);return 0 ; }
@@ -991,8 +1007,7 @@ static int quad8_probe(struct device *dev, unsigned int id) priv->counter.priv = priv; priv->base = base[id]; -/* Initialize mutex */ -mutex_init (&priv->lock); +spin_lock_init (&priv->lock);/* Reset all counters and disable interrupt function */ outb (QUAD8_CHAN_OP_RESET_COUNTERS , base[id] +QUAD8_REG_CHAN_OP );
Signature · 1 line
2.32.0
PATCH v15 13/13 counter: 104-quad-8: Add IRQ support for the ACCES 104-QUAD-8
In reply to William Breathitt GrayThe LSI/CSI LS7266R1 chip provides programmable output via the FLG pins. When interrupts are enabled on the ACCES 104-QUAD-8, they occur whenever FLG1 is active. Four functions are available for the FLG1 signal: Carry, Compare, Carry-Borrow, and Index.
Carry:
Interrupt generated on active low Carry signal. Carry signal toggles every time the respective channel's counter overflows.
Compare:
Interrupt generated on active low Compare signal. Compare signal toggles every time respective channel's preset register is equal to the respective channel's counter.
Carry-Borrow:
Interrupt generated on active low Carry signal and active low Borrow signal. Carry signal toggles every time the respective channel's counter overflows. Borrow signal toggles every time the respective channel's counter underflows.
Index:
Interrupt generated on active high Index signal.
These four functions correspond respectivefly to the following four Counter event types: COUNTER_EVENT_OVERFLOW, COUNTER_EVENT_THRESHOLD, COUNTER_EVENT_OVERFLOW_UNDERFLOW, and COUNTER_EVENT_INDEX. Interrupts push Counter events to event channel X, where 'X' is the respective channel whose FLG1 activated.
This patch adds IRQ support for the ACCES 104-QUAD-8. The interrupt line numbers for the devices may be configured via the irq array module parameter.
--- drivers/counter/104-quad-8.c | 167 +++++++++++++++++++++++++++++++++-- drivers/counter/Kconfig | 6 +- 2 files changed, 164 insertions(+), 9 deletions(-)
drivers/counter/104-quad-8.c +161 -6
@@ -11,6 +11,7 @@#include <linux/errno.h> #include <linux/io.h> #include <linux/ioport.h> +#include <linux/interrupt.h> #include <linux/isa.h> #include <linux/kernel.h> #include <linux/module.h>
@@ -25,6 +26,10 @@ static unsigned int num_quad8;module_param_hw_array (base, uint, ioport, &num_quad8,0 );MODULE_PARM_DESC (base,"ACCES 104-QUAD-8 base addresses" ); +static unsigned int irq[max_num_isa_dev (QUAD8_EXTENT )]; +module_param_hw_array (irq, uint, irq,NULL ,0 ); +MODULE_PARM_DESC (irq,"ACCES 104-QUAD-8 interrupt line numbers" ); +#define QUAD8_NUM_COUNTERS 8/**
@@ -38,6 +43,8 @@ MODULE_PARM_DESC(base, "ACCES 104-QUAD-8 base addresses");* @quadrature_scale: array of quadrature mode scale configurations * @ab_enable: array of A and B inputs enable configurations * @preset_enable: array of set_to_preset_on_index attribute configurations +* @irq_trigger: array of current IRQ trigger function configurations +* @next_irq_trigger: array of next IRQ trigger function configurations * @synchronous_mode: array of index function synchronous mode configurations * @index_polarity: array of index function polarity configurations * @cable_fault_enable: differential encoder cable status enable configurations
@@ -53,13 +60,17 @@ struct quad8 {unsigned int quadrature_scale[QUAD8_NUM_COUNTERS ];unsigned int ab_enable[QUAD8_NUM_COUNTERS ];unsigned int preset_enable[QUAD8_NUM_COUNTERS ]; +unsigned int irq_trigger[QUAD8_NUM_COUNTERS ]; +unsigned int next_irq_trigger[QUAD8_NUM_COUNTERS ];unsigned int synchronous_mode[QUAD8_NUM_COUNTERS ];unsigned int index_polarity[QUAD8_NUM_COUNTERS ];unsigned int cable_fault_enable;unsigned int base; }; +#define QUAD8_REG_INTERRUPT_STATUS 0x10#define QUAD8_REG_CHAN_OP 0x11 +#define QUAD8_REG_INDEX_INTERRUPT 0x12#define QUAD8_REG_INDEX_INPUT_LEVELS 0x16#define QUAD8_DIFF_ENCODER_CABLE_STATUS 0x17/* Borrow Toggle flip-flop */
@@ -92,8 +103,8 @@ struct quad8 {#define QUAD8_RLD_CNTR_OUT 0x10/* Transfer Preset Register LSB to FCK Prescaler */ #define QUAD8_RLD_PRESET_PSC 0x18 -#define QUAD8_CHAN_OP_ENABLE_COUNTERS 0x00#define QUAD8_CHAN_OP_RESET_COUNTERS 0x01 +#define QUAD8_CHAN_OP_ENABLE_INTERRUPT_FUNC 0x04#define QUAD8_CMR_QUADRATURE_X1 0x08#define QUAD8_CMR_QUADRATURE_X2 0x10#define QUAD8_CMR_QUADRATURE_X4 0x18
@@ -378,13 +389,103 @@ static int quad8_action_read(struct counter_device *counter, } } +enum { +QUAD8_EVENT_NONE =-1 , +QUAD8_EVENT_CARRY =0 , +QUAD8_EVENT_COMPARE =1 , +QUAD8_EVENT_CARRY_BORROW =2 , +QUAD8_EVENT_INDEX =3 , +}; + +static int quad8_events_configure (struct counter_device *counter) +{ +struct quad8 *const priv = counter->priv; +unsigned long irq_enabled =0 ; +unsigned long irqflags; +size_t channel; +unsigned long ior_cfg; +unsigned long base_offset; + +spin_lock_irqsave (&priv->lock, irqflags); + +/* Enable interrupts for the requested channels, disable for the rest */ +for (channel =0 ; channel <QUAD8_NUM_COUNTERS ; channel++) { +if (priv->next_irq_trigger[channel] ==QUAD8_EVENT_NONE ) +continue ; + +if (priv->irq_trigger[channel] != priv->next_irq_trigger[channel]) { +/* Save new IRQ function configuration */ + priv->irq_trigger[channel] = priv->next_irq_trigger[channel]; + +/* Load configuration to I/O Control Register */ + ior_cfg = priv->ab_enable[channel] | + priv->preset_enable[channel] <<1 | + priv->irq_trigger[channel] <<3 ; + base_offset = priv->base +2 * channel +1 ; +outb (QUAD8_CTR_IOR | ior_cfg, base_offset); + } + +/* Reset next IRQ trigger function configuration */ + priv->next_irq_trigger[channel] =QUAD8_EVENT_NONE ; + +/* Enable IRQ line */ + irq_enabled |=BIT (channel); + } + +outb (irq_enabled, priv->base +QUAD8_REG_INDEX_INTERRUPT ); + +spin_unlock_irqrestore (&priv->lock, irqflags); + +return 0 ; +} + +static int quad8_watch_validate (struct counter_device *counter, +const struct counter_watch *watch) +{ +struct quad8 *const priv = counter->priv; + +if (watch->channel >QUAD8_NUM_COUNTERS -1 ) +return -EINVAL ; + +switch (watch->event) { +case COUNTER_EVENT_OVERFLOW : +if (priv->next_irq_trigger[watch->channel] ==QUAD8_EVENT_NONE ) + priv->next_irq_trigger[watch->channel] =QUAD8_EVENT_CARRY ; +else if (priv->next_irq_trigger[watch->channel] !=QUAD8_EVENT_CARRY ) +return -EINVAL ; +return 0 ; +case COUNTER_EVENT_THRESHOLD : +if (priv->next_irq_trigger[watch->channel] ==QUAD8_EVENT_NONE ) + priv->next_irq_trigger[watch->channel] =QUAD8_EVENT_COMPARE ; +else if (priv->next_irq_trigger[watch->channel] !=QUAD8_EVENT_COMPARE ) +return -EINVAL ; +return 0 ; +case COUNTER_EVENT_OVERFLOW_UNDERFLOW : +if (priv->next_irq_trigger[watch->channel] ==QUAD8_EVENT_NONE ) + priv->next_irq_trigger[watch->channel] =QUAD8_EVENT_CARRY_BORROW ; +else if (priv->next_irq_trigger[watch->channel] !=QUAD8_EVENT_CARRY_BORROW ) +return -EINVAL ; +return 0 ; +case COUNTER_EVENT_INDEX : +if (priv->next_irq_trigger[watch->channel] ==QUAD8_EVENT_NONE ) + priv->next_irq_trigger[watch->channel] =QUAD8_EVENT_INDEX ; +else if (priv->next_irq_trigger[watch->channel] !=QUAD8_EVENT_INDEX ) +return -EINVAL ; +return 0 ; +default : +return -EINVAL ; + } +} +static const struct counter_ops quad8_ops = { .signal_read = quad8_signal_read, .count_read = quad8_count_read, .count_write = quad8_count_write, .function_read = quad8_function_read, .function_write = quad8_function_write, - .action_read = quad8_action_read + .action_read = quad8_action_read, + .events_configure = quad8_events_configure, + .watch_validate = quad8_watch_validate, };static const char *const quad8_index_polarity_modes[] = {
@@ -579,7 +680,8 @@ static int quad8_count_enable_write(struct counter_device *counter, priv->ab_enable[count->id] = enable; - ior_cfg = enable | priv->preset_enable[count->id] <<1 ; + ior_cfg = enable | priv->preset_enable[count->id] <<1 | + priv->irq_trigger[count->id] <<3 ;/* Load I/O control configuration */ outb (QUAD8_CTR_IOR | ior_cfg, base_offset +1 );
@@ -728,7 +830,8 @@ static int quad8_count_preset_enable_write(struct counter_device *counter, priv->preset_enable[count->id] = preset_enable; - ior_cfg = priv->ab_enable[count->id] | preset_enable <<1 ; + ior_cfg = priv->ab_enable[count->id] | preset_enable <<1 | + priv->irq_trigger[count->id] <<3 ;/* Load I/O control configuration to Input / Output Control Register */ outb (QUAD8_CTR_IOR | ior_cfg, base_offset);
@@ -980,11 +1083,54 @@ static struct counter_count quad8_counts[] = {QUAD8_COUNT (7 ,"Channel 8 Count" ) }; +static irqreturn_t quad8_irq_handler (int irq,void *private) +{ +struct quad8 *const priv = private; +const unsigned long base = priv->base; +unsigned long irq_status; +unsigned long channel; +u8 event; + + irq_status =inb (base +QUAD8_REG_INTERRUPT_STATUS ); +if (!irq_status) +return IRQ_NONE ; + +for_each_set_bit (channel, &irq_status,QUAD8_NUM_COUNTERS ) { +switch (priv->irq_trigger[channel]) { +case QUAD8_EVENT_CARRY : + event =COUNTER_EVENT_OVERFLOW ; +break ; +case QUAD8_EVENT_COMPARE : + event =COUNTER_EVENT_THRESHOLD ; +break ; +case QUAD8_EVENT_CARRY_BORROW : + event =COUNTER_EVENT_OVERFLOW_UNDERFLOW ; +break ; +case QUAD8_EVENT_INDEX : + event =COUNTER_EVENT_INDEX ; +break ; +default : +/* should never reach this path */ +WARN_ONCE (true,"invalid interrupt trigger function %u configured for channel %lu\n" , + priv->irq_trigger[channel], channel); +continue ; + } + +counter_push_event (&priv->counter, event, channel); + } + +/* Clear pending interrupts on device */ +outb (QUAD8_CHAN_OP_ENABLE_INTERRUPT_FUNC , base +QUAD8_REG_CHAN_OP ); + +return IRQ_HANDLED ; +} +static int quad8_probe (struct device *dev,unsigned int id) {struct quad8 *priv;int i, j;unsigned int base_offset; +int err;if (!devm_request_region (dev, base[id],QUAD8_EXTENT ,dev_name (dev))) { dev_err(dev, "Unable to lock port addresses (0x%X-0x%X)\n",
@@ -1009,6 +1155,8 @@ static int quad8_probe(struct device *dev, unsigned int id)spin_lock_init (&priv->lock); +/* Reset Index/Interrupt Register */ +outb (0x00 , base[id] +QUAD8_REG_INDEX_INTERRUPT );/* Reset all counters and disable interrupt function */ outb (QUAD8_CHAN_OP_RESET_COUNTERS , base[id] +QUAD8_REG_CHAN_OP );/* Set initial configuration for all counters */
@@ -1035,11 +1183,18 @@ static int quad8_probe(struct device *dev, unsigned int id)outb (QUAD8_CTR_IOR , base_offset +1 );/* Disable index function; negative index polarity */ outb (QUAD8_CTR_IDR , base_offset +1 ); +/* Initialize next IRQ trigger function configuration */ + priv->next_irq_trigger[i] =QUAD8_EVENT_NONE ; }/* Disable Differential Encoder Cable Status for all channels */ outb (0xFF , base[id] +QUAD8_DIFF_ENCODER_CABLE_STATUS ); -/* Enable all counters */ -outb (QUAD8_CHAN_OP_ENABLE_COUNTERS , base[id] +QUAD8_REG_CHAN_OP ); +/* Enable all counters and enable interrupt function */ +outb (QUAD8_CHAN_OP_ENABLE_INTERRUPT_FUNC , base[id] +QUAD8_REG_CHAN_OP ); + + err =devm_request_irq (dev, irq[id], quad8_irq_handler,IRQF_SHARED , + priv->counter.name, priv); +if (err) +return err;return devm_counter_register (dev, &priv->counter); }
drivers/counter/Kconfig +3 -3
@@ -23,11 +23,11 @@ config 104_QUAD_8 A counter's respective error flag may be cleared by performing a write operation on the respective count value attribute. Although the 104-QUAD-8 counters have a 25-bit range, only the lower 24 bits may be - set, either directly or via the counter's preset attribute. Interrupts - are not supported by this driver. + set, either directly or via the counter's preset attribute. The base port addresses for the devices may be configured via the base - array module parameter. + array module parameter. The interrupt line numbers for the devices may + be configured via the irq array module parameter. config INTERRUPT_CNT tristate "Interrupt counter driver"
Signature · 1 line
2.32.0
Jonathan Cameron
maintainerQuoted 9 lines · On Mon, 9 Aug 2021 21:37:25 +0900 William Breathitt Gray…
Changes in v15:
- Move the description for the member 'lock' in the 'quad8' structure as a separate patch
- Reorganize the "counter: Internalize sysfs interface code" patch to not call chrdev code; respective code moved to the "counter: Add character device interface" patch with the other chrdev code
- Custom enums removed from theftm-quaddec.c,stm32-lptimer-cnt.c, andstm32-timer-cnt.cfiles; respective drivers refactored to use the COUNTER_FUNCTION_* and COUNTER_SYNAPSE_* enum constants instead
Given this last one isn't trivial, I'll let patch 2 onwards sit on the list for a little while just to see if anyone wants to take a look at those changes. Then I'll take up to patch 5. Whilst some are precursors to the later patches, they don't do any harm and will reduce the amount we are asking people to review going forwards.
As for the chrdev part. My gut feeling is that needs more eyes
yet despite being fairly stable in form for a while now. I'll try and take another look, and would definitely encourage others to look at it as well.
New ABI is hard to get right so needs a bit more time than many other forms of patch set.
Jonathan
Quoted 80 lines
For convenience, this patchset is also available on my personal git
repo: https://gitlab.com/vilhelmgray/iio/-/tree/counter_chrdev_v15The patches preceding "counter: Internalize sysfs interface code" are primarily cleanup and fixes that can be picked up and applied now to the IIO tree if so desired. The "counter: Internalize sysfs interface code" patch as well may be considered for pickup because it is relatively safe and makes no changes to the userspace interface.
To summarize the main points of this patchset: there are no changes to the existing Counter sysfs userspace interface; a Counter character device interface is introduced that allows Counter events and associated data to be
read()by userspace; theevents_configure()andwatch_validate()driver callbacks are introduced to support Counter events; and IRQ support is added to the 104-QUAD-8 driver, serving as an example of how to support the new Counter events functionality.William Breathitt Gray (13):
counter: 104-quad-8: Describe member 'lock' in 'quad8'
counter: Internalize sysfs interface code
counter: Updatecounter.hcomments to reflect sysfs internalization
docs: counter: Update to reflect sysfs internalization
counter: Move counter enums to uapi header
counter: Add character device interface
docs: counter: Document character device interfacetools/counter: Create Counter tools
counter: ImplementsignalZ_action_component_idsysfs attribute
counter: Implement*_component_idsysfs attributes
counter: Implementevents_queue_sizesysfs attribute
counter: 104-quad-8: Replace mutex with spinlock
counter: 104-quad-8: Add IRQ support for the ACCES 104-QUAD-8Documentation/ABI/testing/sysfs-bus-counter | 38 +- Documentation/driver-api/generic-counter.rst | 358 +++- .../userspace-api/ioctl/ioctl-number.rst | 1 + MAINTAINERS | 3 +- drivers/counter/104-quad-8.c | 700 ++++---- drivers/counter/Kconfig | 6 +- drivers/counter/Makefile | 1 + drivers/counter/counter-chrdev.c | 553 ++++++ drivers/counter/counter-chrdev.h | 14 + drivers/counter/counter-core.c | 191 +++ drivers/counter/counter-sysfs.c | 962 +++++++++++ drivers/counter/counter-sysfs.h | 13 + drivers/counter/counter.c | 1496 ----------------- drivers/counter/ftm-quaddec.c | 60 +- drivers/counter/intel-qep.c | 144 +- drivers/counter/interrupt-cnt.c | 62 +- drivers/counter/microchip-tcb-capture.c | 91 +- drivers/counter/stm32-lptimer-cnt.c | 226 +-- drivers/counter/stm32-timer-cnt.c | 179 +- drivers/counter/ti-eqep.c | 180 +- include/linux/counter.h | 715 ++++---- include/linux/counter_enum.h | 45 - include/uapi/linux/counter.h | 154 ++ tools/Makefile | 13 +- tools/counter/Build | 1 + tools/counter/Makefile | 53 + tools/counter/counter_example.c | 93 + 27 files changed, 3568 insertions(+), 2784 deletions(-) create mode 100644 drivers/counter/counter-chrdev.c create mode 100644 drivers/counter/counter-chrdev.h create mode 100644 drivers/counter/counter-core.c create mode 100644 drivers/counter/counter-sysfs.c create mode 100644 drivers/counter/counter-sysfs.h delete mode 100644 drivers/counter/counter.c delete mode 100644 include/linux/counter_enum.h create mode 100644 include/uapi/linux/counter.h create mode 100644 tools/counter/Build create mode 100644 tools/counter/Makefile create mode 100644 tools/counter/counter_example.cbase-commit:
c886885336b0b5f1a08ce580f7201a2ca30ab041
prerequisite-patch-id:8ca55ffcdd5d060dd5fa2b4dd50bf01dc1026da6
prerequisite-patch-id:46ef2668ca6bdc0d08dd488fe1d2b886189a5652
prerequisite-patch-id:2df1946c917d6408148306db30a071e67b00ad73
prerequisite-patch-id:f81579f50552e6041a95403cc743c5f36962b111
prerequisite-patch-id:8a6860e75cdec162812c56dc39c5d7fc6fc5154e