Message ID | 350cafba81d3220b64efdb019bd76c08eb1e5d10.1613131238.git.vilhelm.gray@gmail.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | Introduce the Counter character device interface | expand |
On Fri, 12 Feb 2021 21:13:42 +0900 William Breathitt Gray <vilhelm.gray@gmail.com> wrote: > This patch adds high-level documentation about the Counter subsystem > character device interface. > > Signed-off-by: William Breathitt Gray <vilhelm.gray@gmail.com> > --- > Documentation/driver-api/generic-counter.rst | 243 +++++++++++++++--- > .../userspace-api/ioctl/ioctl-number.rst | 1 + > 2 files changed, 203 insertions(+), 41 deletions(-) > > diff --git a/Documentation/driver-api/generic-counter.rst b/Documentation/driver-api/generic-counter.rst > index f6397218aa4c..3be109dc81bb 100644 > --- a/Documentation/driver-api/generic-counter.rst > +++ b/Documentation/driver-api/generic-counter.rst > @@ -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,170 @@ 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: > + > +* COUNTER_ADD_WATCH_IOCTL: > + Queues a Counter watch for the specified event. The queued watches > + will not be applied until ``COUNTER_ENABLE_EVENTS_IOCTL`` is called. > + > +* COUNTER_ENABLE_EVENTS_IOCTL: > + Enables monitoring the events specified by the Counter watches that > + were queued by ``COUNTER_ADD_WATCH_IOCTL``. If events are already > + enabled, the new set of watches replaces the old one. Calling this > + ioctl also has the effect of clearing the queue of watches added by > + ``COUNTER_ADD_WATCH_IOCTL``. > + > +* COUNTER_DISABLE_EVENTS_IOCTL: > + Stops monitoring the previously enabled events. Is there a way to remove a watch? > + > +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. > + > +For example, the following userspace code opens ``/dev/counter0``, > +configures the ``COUNTER_EVENT_INDEX`` event channel 0 to gather Count 0 > +and Count 1, and prints out the data as it becomes available on the > +character device node:: > + Consider adding an example program under tools/ > + #include <fcntl.h> > + #include <linux/counter.h> > + #include <stdio.h> > + #include <string.h> > + #include <sys/ioctl.h> > + #include <unistd.h> > + > + struct counter_watch watches[2] = { > + { > + .component.type = COUNTER_COMPONENT_COUNT, > + .component.scope = COUNTER_SCOPE_COUNT, > + .component.parent = 0, Good to add comments on what these elements actually are? > + .event = COUNTER_EVENT_INDEX, > + .channel = 0, > + }, > + { > + .component.type = COUNTER_COMPONENT_COUNT, > + .component.scope = COUNTER_SCOPE_COUNT, > + .component.parent = 1, > + .event = COUNTER_EVENT_INDEX, > + .channel = 0, > + }, > + }; > + > + int main(void) > + { > + int fd; > + struct counter_event event_data[2]; > + > + fd = open("/dev/counter0", O_RDWR); > + > + ioctl(fd, COUNTER_ADD_WATCH_IOCTL, watches); > + ioctl(fd, COUNTER_ADD_WATCH_IOCTL, watches + 1); > + ioctl(fd, COUNTER_ENABLE_EVENTS_IOCTL); > + > + for (;;) { > + read(fd, event_data, sizeof(event_data)); > + > + printf("Timestamp 0: %llu\tCount 0: %llu\n" > + "Error Message 0: %s\n" > + "Timestamp 1: %llu\tCount 1: %llu\n" > + "Error Message 1: %s\n", > + (unsigned long long)event_data[0].timestamp, > + (unsigned long long)event_data[0].value, > + strerror(event_data[0].status), > + (unsigned long long)event_data[1].timestamp, > + (unsigned long long)event_data[1].value, > + strerror(event_data[1].status)); > + } > + > + return 0; > + } > diff --git a/Documentation/userspace-api/ioctl/ioctl-number.rst b/Documentation/userspace-api/ioctl/ioctl-number.rst > index a4c75a28c839..8ddca931ec4e 100644 > --- a/Documentation/userspace-api/ioctl/ioctl-number.rst > +++ b/Documentation/userspace-api/ioctl/ioctl-number.rst > @@ -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:linux-iio@vger.kernel.org> > '!' 00-1F uapi/linux/seccomp.h > '#' 00-3F IEEE 1394 Subsystem > Block for the entire subsystem
Hi! > > +* COUNTER_ENABLE_EVENTS_IOCTL: > > + Enables monitoring the events specified by the Counter watches that > > + were queued by ``COUNTER_ADD_WATCH_IOCTL``. If events are already > > + enabled, the new set of watches replaces the old one. Calling this > > + ioctl also has the effect of clearing the queue of watches added by > > + ``COUNTER_ADD_WATCH_IOCTL``. > > + > > +* COUNTER_DISABLE_EVENTS_IOCTL: > > + Stops monitoring the previously enabled events. > > Is there a way to remove a watch? Is there a way to eat all kernel memory and crash the system by adding too many watches? > > +For example, the following userspace code opens ``/dev/counter0``, > > +configures the ``COUNTER_EVENT_INDEX`` event channel 0 to gather Count 0 > > +and Count 1, and prints out the data as it becomes available on the > > +character device node:: > > + > > Consider adding an example program under tools/ > > > + #include <fcntl.h> > > + #include <linux/counter.h> > > + #include <stdio.h> > > + #include <string.h> > > + #include <sys/ioctl.h> > > + #include <unistd.h> > > + > > + struct counter_watch watches[2] = { > > + { > > + .component.type = COUNTER_COMPONENT_COUNT, > > + .component.scope = COUNTER_SCOPE_COUNT, > > + .component.parent = 0, > > Good to add comments on what these elements actually are? > > + fd = open("/dev/counter0", O_RDWR); > > + > > + ioctl(fd, COUNTER_ADD_WATCH_IOCTL, watches); > > + ioctl(fd, COUNTER_ADD_WATCH_IOCTL, watches + 1); > > + ioctl(fd, COUNTER_ENABLE_EVENTS_IOCTL); > > + for (;;) { > > + read(fd, event_data, sizeof(event_data)); If this goes to tools it really should have error handling and handling of short read. Best regards, Pavel
On Sun, Feb 14, 2021 at 05:48:19PM +0000, Jonathan Cameron wrote: > On Fri, 12 Feb 2021 21:13:42 +0900 > William Breathitt Gray <vilhelm.gray@gmail.com> wrote: > > > This patch adds high-level documentation about the Counter subsystem > > character device interface. > > > > Signed-off-by: William Breathitt Gray <vilhelm.gray@gmail.com> > > --- > > Documentation/driver-api/generic-counter.rst | 243 +++++++++++++++--- > > .../userspace-api/ioctl/ioctl-number.rst | 1 + > > 2 files changed, 203 insertions(+), 41 deletions(-) > > > > diff --git a/Documentation/driver-api/generic-counter.rst b/Documentation/driver-api/generic-counter.rst > > index f6397218aa4c..3be109dc81bb 100644 > > --- a/Documentation/driver-api/generic-counter.rst > > +++ b/Documentation/driver-api/generic-counter.rst > > @@ -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,170 @@ 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: > > + > > +* COUNTER_ADD_WATCH_IOCTL: > > + Queues a Counter watch for the specified event. The queued watches > > + will not be applied until ``COUNTER_ENABLE_EVENTS_IOCTL`` is called. > > + > > +* COUNTER_ENABLE_EVENTS_IOCTL: > > + Enables monitoring the events specified by the Counter watches that > > + were queued by ``COUNTER_ADD_WATCH_IOCTL``. If events are already > > + enabled, the new set of watches replaces the old one. Calling this > > + ioctl also has the effect of clearing the queue of watches added by > > + ``COUNTER_ADD_WATCH_IOCTL``. > > + > > +* COUNTER_DISABLE_EVENTS_IOCTL: > > + Stops monitoring the previously enabled events. > > Is there a way to remove a watch? Both COUNTER_ENABLE_EVENTS_IOCTL and COUNTER_DISABLE_EVENTS_IOCTL remove the watches -- the only difference is that COUNTER_ENABLE_EVENTS_IOCTL will also swap in a new set of watches. The watches are also removed if a user closes the cdev. If you mean whether there is a way to selectively remove a single watch, then the process for that would be to generate a new set of watches using COUNTER_ADD_WATCH_IOCTL and then swap them in by using COUNTER_ENABLE_EVENTS_IOCTL. This swap happens atomically so there's no risk of missing an event. The user should already know the current configuration of watches because they are the ones who added them after opening the cdev, so we don't need to worry about dealing with an old unknown watch configuration created by someone else. > > + > > +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. > > + > > +For example, the following userspace code opens ``/dev/counter0``, > > +configures the ``COUNTER_EVENT_INDEX`` event channel 0 to gather Count 0 > > +and Count 1, and prints out the data as it becomes available on the > > +character device node:: > > + > > Consider adding an example program under tools/ I can put this example program we have here below under tools/. I'd like to create a more general Counter test program in the future, but I think it will be a more involved project to undertake right now given the differences between the possible configurations available and possible for the Counter drivers we have. > > + #include <fcntl.h> > > + #include <linux/counter.h> > > + #include <stdio.h> > > + #include <string.h> > > + #include <sys/ioctl.h> > > + #include <unistd.h> > > + > > + struct counter_watch watches[2] = { > > + { > > + .component.type = COUNTER_COMPONENT_COUNT, > > + .component.scope = COUNTER_SCOPE_COUNT, > > + .component.parent = 0, > > Good to add comments on what these elements actually are? Ack. William Breathitt Gray
On Mon, Feb 22, 2021 at 11:11:33AM +0100, Pavel Machek wrote: > Hi! > > > > +* COUNTER_ENABLE_EVENTS_IOCTL: > > > + Enables monitoring the events specified by the Counter watches that > > > + were queued by ``COUNTER_ADD_WATCH_IOCTL``. If events are already > > > + enabled, the new set of watches replaces the old one. Calling this > > > + ioctl also has the effect of clearing the queue of watches added by > > > + ``COUNTER_ADD_WATCH_IOCTL``. > > > + > > > +* COUNTER_DISABLE_EVENTS_IOCTL: > > > + Stops monitoring the previously enabled events. > > > > Is there a way to remove a watch? > > Is there a way to eat all kernel memory and crash the system by adding > too many watches? There can only ever be as many watches as there are Counter components for the respective Counter device. This is enforced by counter_set_event_node() which checks whether a particular watch has been created before and returns an EINVAL if it so has. > > > +For example, the following userspace code opens ``/dev/counter0``, > > > +configures the ``COUNTER_EVENT_INDEX`` event channel 0 to gather Count 0 > > > +and Count 1, and prints out the data as it becomes available on the > > > +character device node:: > > > + > > > > Consider adding an example program under tools/ > > > > > + #include <fcntl.h> > > > + #include <linux/counter.h> > > > + #include <stdio.h> > > > + #include <string.h> > > > + #include <sys/ioctl.h> > > > + #include <unistd.h> > > > + > > > + struct counter_watch watches[2] = { > > > + { > > > + .component.type = COUNTER_COMPONENT_COUNT, > > > + .component.scope = COUNTER_SCOPE_COUNT, > > > + .component.parent = 0, > > > > Good to add comments on what these elements actually are? > > > > + fd = open("/dev/counter0", O_RDWR); > > > + > > > + ioctl(fd, COUNTER_ADD_WATCH_IOCTL, watches); > > > + ioctl(fd, COUNTER_ADD_WATCH_IOCTL, watches + 1); > > > + ioctl(fd, COUNTER_ENABLE_EVENTS_IOCTL); > > > > + for (;;) { > > > + read(fd, event_data, sizeof(event_data)); > > If this goes to tools it really should have error handling and > handling of short read. > > Best regards, > Pavel > > -- > http://www.livejournal.com/~pavelmachek Ack. I'll improve the error handling for this. William Breathitt Gray
diff --git a/Documentation/driver-api/generic-counter.rst b/Documentation/driver-api/generic-counter.rst index f6397218aa4c..3be109dc81bb 100644 --- a/Documentation/driver-api/generic-counter.rst +++ b/Documentation/driver-api/generic-counter.rst @@ -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,170 @@ 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: + +* COUNTER_ADD_WATCH_IOCTL: + Queues a Counter watch for the specified event. The queued watches + will not be applied until ``COUNTER_ENABLE_EVENTS_IOCTL`` is called. + +* COUNTER_ENABLE_EVENTS_IOCTL: + Enables monitoring the events specified by the Counter watches that + were queued by ``COUNTER_ADD_WATCH_IOCTL``. If events are already + enabled, the new set of watches replaces the old one. Calling this + ioctl also has the effect of clearing the queue of watches added by + ``COUNTER_ADD_WATCH_IOCTL``. + +* COUNTER_DISABLE_EVENTS_IOCTL: + Stops monitoring the previously enabled events. + +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. + +For example, the following userspace code opens ``/dev/counter0``, +configures the ``COUNTER_EVENT_INDEX`` event channel 0 to gather Count 0 +and Count 1, and prints out the data as it becomes available on the +character device node:: + + #include <fcntl.h> + #include <linux/counter.h> + #include <stdio.h> + #include <string.h> + #include <sys/ioctl.h> + #include <unistd.h> + + struct counter_watch watches[2] = { + { + .component.type = COUNTER_COMPONENT_COUNT, + .component.scope = COUNTER_SCOPE_COUNT, + .component.parent = 0, + .event = COUNTER_EVENT_INDEX, + .channel = 0, + }, + { + .component.type = COUNTER_COMPONENT_COUNT, + .component.scope = COUNTER_SCOPE_COUNT, + .component.parent = 1, + .event = COUNTER_EVENT_INDEX, + .channel = 0, + }, + }; + + int main(void) + { + int fd; + struct counter_event event_data[2]; + + fd = open("/dev/counter0", O_RDWR); + + ioctl(fd, COUNTER_ADD_WATCH_IOCTL, watches); + ioctl(fd, COUNTER_ADD_WATCH_IOCTL, watches + 1); + ioctl(fd, COUNTER_ENABLE_EVENTS_IOCTL); + + for (;;) { + read(fd, event_data, sizeof(event_data)); + + printf("Timestamp 0: %llu\tCount 0: %llu\n" + "Error Message 0: %s\n" + "Timestamp 1: %llu\tCount 1: %llu\n" + "Error Message 1: %s\n", + (unsigned long long)event_data[0].timestamp, + (unsigned long long)event_data[0].value, + strerror(event_data[0].status), + (unsigned long long)event_data[1].timestamp, + (unsigned long long)event_data[1].value, + strerror(event_data[1].status)); + } + + return 0; + } diff --git a/Documentation/userspace-api/ioctl/ioctl-number.rst b/Documentation/userspace-api/ioctl/ioctl-number.rst index a4c75a28c839..8ddca931ec4e 100644 --- a/Documentation/userspace-api/ioctl/ioctl-number.rst +++ b/Documentation/userspace-api/ioctl/ioctl-number.rst @@ -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:linux-iio@vger.kernel.org> '!' 00-1F uapi/linux/seccomp.h '#' 00-3F IEEE 1394 Subsystem Block for the entire subsystem
This patch adds high-level documentation about the Counter subsystem character device interface. Signed-off-by: William Breathitt Gray <vilhelm.gray@gmail.com> --- Documentation/driver-api/generic-counter.rst | 243 +++++++++++++++--- .../userspace-api/ioctl/ioctl-number.rst | 1 + 2 files changed, 203 insertions(+), 41 deletions(-)