Re: [PATCH v5 3/5] counter: Add character device interface

2020-10-25 Thread William Breathitt Gray
On Sun, Oct 25, 2020 at 11:34:43AM -0500, David Lechner wrote:
> On 10/25/20 8:18 AM, William Breathitt Gray wrote:
> > On Tue, Oct 20, 2020 at 11:06:42AM -0500, David Lechner wrote:
> >> On 10/18/20 11:58 AM, William Breathitt Gray wrote:
> >>> On Wed, Oct 14, 2020 at 05:40:44PM -0500, David Lechner wrote:
>  On 9/26/20 9:18 PM, William Breathitt Gray wrote:
> > +static ssize_t counter_chrdev_read(struct file *filp, char __user *buf,
> > +  size_t len, loff_t *f_ps)
> > +{
> > +   struct counter_device *const counter = filp->private_data;
> > +   int err;
> > +   unsigned long flags;
> > +   unsigned int copied;
> > +
> > +   if (len < sizeof(struct counter_event))
> > +   return -EINVAL;
> > +
> > +   do {
> > +   if (kfifo_is_empty(>events)) {
> > +   if (filp->f_flags & O_NONBLOCK)
> > +   return -EAGAIN;
> > +
> > +   err = 
> > wait_event_interruptible(counter->events_wait,
> > +   
> > !kfifo_is_empty(>events));
> > +   if (err)
> > +   return err;
> > +   }
> > +
> > +   raw_spin_lock_irqsave(>events_lock, flags);
> > +   err = kfifo_to_user(>events, buf, len, 
> > );
> > +   raw_spin_unlock_irqrestore(>events_lock, 
> > flags);
> > +   if (err)
> > +   return err;
> > +   } while (!copied);
> > +
> > +   return copied;
> > +}
> 
>  All other uses of kfifo_to_user() I saw use a mutex instead of spin
>  lock. I don't see a reason for disabling interrupts here.
> >>>
> >>> The Counter character device interface is special in this case because
> >>> counter->events could be accessed from an interrupt context. This is
> >>> possible if counter_push_event() is called for an interrupt (as is the
> >>> case for the 104_quad_8 driver). In this case, we can't use mutex
> >>> because we can't sleep in an interrupt context, so our only option is to
> >>> use spin lock.
> >>>
> >>
> >>
> >> The way I understand it, locking is only needed for concurrent readers
> >> and locking between reader and writer is not needed.
> > 
> > You're right, it does say in the kfifo.h comments that with only one
> > concurrent reader and one current write, we don't need extra locking to
> > use these macros. Because we only have one kfifo_to_user() operating on
> > counter->events, does that mean we don't need locking at all here for
> > the counter_chrdev_read() function?
> > 
> > William Breathitt Gray
> > 
> 
> Even if we have the policy that only one file handle to the chrdev
> can be open at a time, it is still possible that the it could be
> read from multiple threads. So it I think it makes sense to keep
> it just to be safe.

All right, I'll keep the locks in the code for now to keep it safe in
case we have multiple threads reading.

William Breathitt Gray


signature.asc
Description: PGP signature


Re: [PATCH v5 3/5] counter: Add character device interface

2020-10-25 Thread David Lechner




diff --git a/drivers/counter/counter-sysfs.c b/drivers/counter/counter-sysfs.c
index e66ed99dd5ea..cefef61f170d 100644
--- a/drivers/counter/counter-sysfs.c
+++ b/drivers/counter/counter-sysfs.c



Not sure why sysfs changes are in the chrdev patch. Are these
changes related somehow?


Sorry, I forgot to explain this in the cover letter. The changes here
are only useful for the character device interface. These changes
introduce the extensionZ_name and extensionZ_width sysfs attributes.

In the character device interface, extensions are selected by their id
number, and the value returned depends on the type of data. The new
sysfs attributes introduced here allow users to match the id of an
extension with its name, as well as the bit width of the value returned
so that the user knows whether to use the value_u8 or value_u64 union
member in struct counter_event.



Are we sure that all value types will always be CPU-endian unsigned
integers? Or should we make an enum to describe the data type instead
of just the width?


It should be safe to assume that the character device interface will
only ever return CPU-endian unsigned integers. The device driver should
handle the conversion of any strange endianness from the device before
the character device interface, while userspace is the one responsible
for interpreting the meaning of count in the context of the application.

Let's create a scenario for the sake of example. Suppose we want to use
a counter device to track the vertical position of a component moved by
a linear actuator. The operator considers some vertical position as the
horizon, where anything above would be a positive position and anything
below a negative position. The counter device stores its count in
big-endian format; but the system CPU expects little-endian.

The flow of data for this scenario would look like the following (where
BE = big-endian, LE = little-endian):

+--+ +---+  ++
| Raw data | - BE -> | Device driver | -> LE -> | chrdev | - u64 ->
+--+ +---+  ++

At this point, the userspace application would read the unsigned integer
from the character device and determine how to interpret the position --
whether the count be converted to a signed value to represent a negative
physical position.

Whether or not a position should be considered negative is dependent on
the user application and context. Because the character device does not
know the context of the user application, it should only provide
unsigned integers in order to ensure a standard interface for counter
devices; userspace will be responsible for interpreting those counts to
something meaningful for the context of their applications.

William Breathitt Gray



Sounds reasonable to me.


Re: [PATCH v5 3/5] counter: Add character device interface

2020-10-25 Thread David Lechner

On 10/25/20 8:18 AM, William Breathitt Gray wrote:

On Tue, Oct 20, 2020 at 11:06:42AM -0500, David Lechner wrote:

On 10/18/20 11:58 AM, William Breathitt Gray wrote:

On Wed, Oct 14, 2020 at 05:40:44PM -0500, David Lechner wrote:

On 9/26/20 9:18 PM, William Breathitt Gray wrote:

+static ssize_t counter_chrdev_read(struct file *filp, char __user *buf,
+  size_t len, loff_t *f_ps)
+{
+   struct counter_device *const counter = filp->private_data;
+   int err;
+   unsigned long flags;
+   unsigned int copied;
+
+   if (len < sizeof(struct counter_event))
+   return -EINVAL;
+
+   do {
+   if (kfifo_is_empty(>events)) {
+   if (filp->f_flags & O_NONBLOCK)
+   return -EAGAIN;
+
+   err = wait_event_interruptible(counter->events_wait,
+   !kfifo_is_empty(>events));
+   if (err)
+   return err;
+   }
+
+   raw_spin_lock_irqsave(>events_lock, flags);
+   err = kfifo_to_user(>events, buf, len, );
+   raw_spin_unlock_irqrestore(>events_lock, flags);
+   if (err)
+   return err;
+   } while (!copied);
+
+   return copied;
+}


All other uses of kfifo_to_user() I saw use a mutex instead of spin
lock. I don't see a reason for disabling interrupts here.


The Counter character device interface is special in this case because
counter->events could be accessed from an interrupt context. This is
possible if counter_push_event() is called for an interrupt (as is the
case for the 104_quad_8 driver). In this case, we can't use mutex
because we can't sleep in an interrupt context, so our only option is to
use spin lock.




The way I understand it, locking is only needed for concurrent readers
and locking between reader and writer is not needed.


You're right, it does say in the kfifo.h comments that with only one
concurrent reader and one current write, we don't need extra locking to
use these macros. Because we only have one kfifo_to_user() operating on
counter->events, does that mean we don't need locking at all here for
the counter_chrdev_read() function?

William Breathitt Gray



Even if we have the policy that only one file handle to the chrdev
can be open at a time, it is still possible that the it could be
read from multiple threads. So it I think it makes sense to keep
it just to be safe.


Re: [PATCH v5 3/5] counter: Add character device interface

2020-10-25 Thread William Breathitt Gray
On Tue, Oct 20, 2020 at 11:06:42AM -0500, David Lechner wrote:
> On 10/18/20 11:58 AM, William Breathitt Gray wrote:
> > On Wed, Oct 14, 2020 at 05:40:44PM -0500, David Lechner wrote:
> >> On 9/26/20 9:18 PM, William Breathitt Gray wrote:
> >>> +static ssize_t counter_chrdev_read(struct file *filp, char __user *buf,
> >>> +size_t len, loff_t *f_ps)
> >>> +{
> >>> + struct counter_device *const counter = filp->private_data;
> >>> + int err;
> >>> + unsigned long flags;
> >>> + unsigned int copied;
> >>> +
> >>> + if (len < sizeof(struct counter_event))
> >>> + return -EINVAL;
> >>> +
> >>> + do {
> >>> + if (kfifo_is_empty(>events)) {
> >>> + if (filp->f_flags & O_NONBLOCK)
> >>> + return -EAGAIN;
> >>> +
> >>> + err = wait_event_interruptible(counter->events_wait,
> >>> + !kfifo_is_empty(>events));
> >>> + if (err)
> >>> + return err;
> >>> + }
> >>> +
> >>> + raw_spin_lock_irqsave(>events_lock, flags);
> >>> + err = kfifo_to_user(>events, buf, len, );
> >>> + raw_spin_unlock_irqrestore(>events_lock, flags);
> >>> + if (err)
> >>> + return err;
> >>> + } while (!copied);
> >>> +
> >>> + return copied;
> >>> +}
> >>
> >> All other uses of kfifo_to_user() I saw use a mutex instead of spin
> >> lock. I don't see a reason for disabling interrupts here.
> > 
> > The Counter character device interface is special in this case because
> > counter->events could be accessed from an interrupt context. This is
> > possible if counter_push_event() is called for an interrupt (as is the
> > case for the 104_quad_8 driver). In this case, we can't use mutex
> > because we can't sleep in an interrupt context, so our only option is to
> > use spin lock.
> > 
> 
> 
> The way I understand it, locking is only needed for concurrent readers
> and locking between reader and writer is not needed.

You're right, it does say in the kfifo.h comments that with only one
concurrent reader and one current write, we don't need extra locking to
use these macros. Because we only have one kfifo_to_user() operating on
counter->events, does that mean we don't need locking at all here for
the counter_chrdev_read() function?

William Breathitt Gray


signature.asc
Description: PGP signature


Re: [PATCH v5 3/5] counter: Add character device interface

2020-10-25 Thread William Breathitt Gray
On Tue, Oct 20, 2020 at 10:53:32AM -0500, David Lechner wrote:
> >>> +
> >>> +static int counter_chrdev_release(struct inode *inode, struct file *filp)
> >>> +{
> >>> + struct counter_device *const counter = filp->private_data;
> >>> + unsigned long flags;
> >>> +
> >>> + put_device(>dev);
> >>
> >> put_device() should be at the end of the function in case it is the last
> >> reference.
> > 
> > put_device() shouldn't affect the counter_device events members, so I
> > don't think there's a difference in this case if it's called at the
> > beginning or end of the counter_chrdev_release function.
> > 
> 
> It isn't possible the some memory allocated with devm_kalloc() could be
> be referenced after calling put_device() now or in the future?

You're right, if put_device() is called before then we could end up in a
garbage state where the device memory is released but events list has
not yet been freed. I'll move put_device() to after the events list is
freed then.

> >>> diff --git a/drivers/counter/counter-sysfs.c 
> >>> b/drivers/counter/counter-sysfs.c
> >>> index e66ed99dd5ea..cefef61f170d 100644
> >>> --- a/drivers/counter/counter-sysfs.c
> >>> +++ b/drivers/counter/counter-sysfs.c
> >>
> >>
> >> Not sure why sysfs changes are in the chrdev patch. Are these
> >> changes related somehow?
> > 
> > Sorry, I forgot to explain this in the cover letter. The changes here
> > are only useful for the character device interface. These changes
> > introduce the extensionZ_name and extensionZ_width sysfs attributes.
> > 
> > In the character device interface, extensions are selected by their id
> > number, and the value returned depends on the type of data. The new
> > sysfs attributes introduced here allow users to match the id of an
> > extension with its name, as well as the bit width of the value returned
> > so that the user knows whether to use the value_u8 or value_u64 union
> > member in struct counter_event.
> > 
> 
> Are we sure that all value types will always be CPU-endian unsigned
> integers? Or should we make an enum to describe the data type instead
> of just the width?

It should be safe to assume that the character device interface will
only ever return CPU-endian unsigned integers. The device driver should
handle the conversion of any strange endianness from the device before
the character device interface, while userspace is the one responsible
for interpreting the meaning of count in the context of the application.

Let's create a scenario for the sake of example. Suppose we want to use
a counter device to track the vertical position of a component moved by
a linear actuator. The operator considers some vertical position as the
horizon, where anything above would be a positive position and anything
below a negative position. The counter device stores its count in
big-endian format; but the system CPU expects little-endian.

The flow of data for this scenario would look like the following (where
BE = big-endian, LE = little-endian):

+--+ +---+  ++
| Raw data | - BE -> | Device driver | -> LE -> | chrdev | - u64 ->
+--+ +---+  ++

At this point, the userspace application would read the unsigned integer
from the character device and determine how to interpret the position --
whether the count be converted to a signed value to represent a negative
physical position.

Whether or not a position should be considered negative is dependent on
the user application and context. Because the character device does not
know the context of the user application, it should only provide
unsigned integers in order to ensure a standard interface for counter
devices; userspace will be responsible for interpreting those counts to
something meaningful for the context of their applications.

William Breathitt Gray


signature.asc
Description: PGP signature


Re: [PATCH v5 3/5] counter: Add character device interface

2020-10-20 Thread David Lechner

On 10/18/20 11:58 AM, William Breathitt Gray wrote:

On Wed, Oct 14, 2020 at 05:40:44PM -0500, David Lechner wrote:

On 9/26/20 9:18 PM, William Breathitt Gray wrote:

+static ssize_t counter_chrdev_read(struct file *filp, char __user *buf,
+  size_t len, loff_t *f_ps)
+{
+   struct counter_device *const counter = filp->private_data;
+   int err;
+   unsigned long flags;
+   unsigned int copied;
+
+   if (len < sizeof(struct counter_event))
+   return -EINVAL;
+
+   do {
+   if (kfifo_is_empty(>events)) {
+   if (filp->f_flags & O_NONBLOCK)
+   return -EAGAIN;
+
+   err = wait_event_interruptible(counter->events_wait,
+   !kfifo_is_empty(>events));
+   if (err)
+   return err;
+   }
+
+   raw_spin_lock_irqsave(>events_lock, flags);
+   err = kfifo_to_user(>events, buf, len, );
+   raw_spin_unlock_irqrestore(>events_lock, flags);
+   if (err)
+   return err;
+   } while (!copied);
+
+   return copied;
+}


All other uses of kfifo_to_user() I saw use a mutex instead of spin
lock. I don't see a reason for disabling interrupts here.


The Counter character device interface is special in this case because
counter->events could be accessed from an interrupt context. This is
possible if counter_push_event() is called for an interrupt (as is the
case for the 104_quad_8 driver). In this case, we can't use mutex
because we can't sleep in an interrupt context, so our only option is to
use spin lock.




The way I understand it, locking is only needed for concurrent readers
and locking between reader and writer is not needed.


Re: [PATCH v5 3/5] counter: Add character device interface

2020-10-20 Thread David Lechner




+static long counter_chrdev_ioctl(struct file *filp, unsigned int cmd,
+unsigned long arg)
+{
+   struct counter_device *const counter = filp->private_data;
+   raw_spinlock_t *const events_lock = >events_lock;
+   unsigned long flags;
+   struct list_head *const events_list = >events_list;
+   struct list_head *const next_events_list = >next_events_list;
+
+   switch (cmd) {
+   case COUNTER_CLEAR_WATCHES_IOCTL:
+   raw_spin_lock_irqsave(events_lock, flags);
+   counter_events_list_free(events_list);
+   raw_spin_unlock_irqrestore(events_lock, flags);
+   counter_events_list_free(next_events_list);


I think this ioctl is doing too much. If we have to use it for both
stopping events and clearing the list accumulated by
COUNTER_SET_WATCH_IOCTL, then we have a race condition of no events
after clearing watches during the time we are adding new ones and
until we load the new ones.

It would probably make more sense to call this ioctl
COUNTER_STOP_WATCHES_IOCTL and move counter_events_list_free(
next_events_list) to the end of COUNTER_LOAD_WATCHES_IOCTL.


I don't think we will necessarily have a race condition here.
COUNTER_CLEAR_WATCHES_IOCTL is intended to just clear the watches; e.g.
bring us back to a clear state when some sort of job has completely
finished and the user is no longer going to watch events for a while
(maybe they're adjusting the conveyor for the next job or some similar
operation).

I think the scenario you're concerned about is when you need to swap
watches in the middle of a job without losing events. In this case, you
wouldn't need to use COUNTER_CLEAR_WATCHES_IOCTL at all. Instead, you
would just set up the watches via COUNTER_SET_WATCH_IOCTL, and then use
COUNTER_LOAD_WATCHES_IOCTL to perform the swap; after
COUNTER_LOAD_WATCHES_IOCTL completes, next_events_list is empty (thanks
to list_replace_init()) and you're ready for the next set of watches.



Got it. I think I missed the fact that list_replace_init() clears
next_events_list.


+
+static int counter_chrdev_release(struct inode *inode, struct file *filp)
+{
+   struct counter_device *const counter = filp->private_data;
+   unsigned long flags;
+
+   put_device(>dev);


put_device() should be at the end of the function in case it is the last
reference.


put_device() shouldn't affect the counter_device events members, so I
don't think there's a difference in this case if it's called at the
beginning or end of the counter_chrdev_release function.



It isn't possible the some memory allocated with devm_kalloc() could be
be referenced after calling put_device() now or in the future?


+}
+EXPORT_SYMBOL_GPL(counter_push_event);




diff --git a/drivers/counter/counter-sysfs.c b/drivers/counter/counter-sysfs.c
index e66ed99dd5ea..cefef61f170d 100644
--- a/drivers/counter/counter-sysfs.c
+++ b/drivers/counter/counter-sysfs.c



Not sure why sysfs changes are in the chrdev patch. Are these
changes related somehow?


Sorry, I forgot to explain this in the cover letter. The changes here
are only useful for the character device interface. These changes
introduce the extensionZ_name and extensionZ_width sysfs attributes.

In the character device interface, extensions are selected by their id
number, and the value returned depends on the type of data. The new
sysfs attributes introduced here allow users to match the id of an
extension with its name, as well as the bit width of the value returned
so that the user knows whether to use the value_u8 or value_u64 union
member in struct counter_event.



Are we sure that all value types will always be CPU-endian unsigned
integers? Or should we make an enum to describe the data type instead
of just the width?


Re: [PATCH v5 3/5] counter: Add character device interface

2020-10-18 Thread William Breathitt Gray
On Wed, Oct 14, 2020 at 05:40:44PM -0500, David Lechner wrote:
> On 9/26/20 9:18 PM, William Breathitt Gray wrote:
> > +static ssize_t counter_chrdev_read(struct file *filp, char __user *buf,
> > +  size_t len, loff_t *f_ps)
> > +{
> > +   struct counter_device *const counter = filp->private_data;
> > +   int err;
> > +   unsigned long flags;
> > +   unsigned int copied;
> > +
> > +   if (len < sizeof(struct counter_event))
> > +   return -EINVAL;
> > +
> > +   do {
> > +   if (kfifo_is_empty(>events)) {
> > +   if (filp->f_flags & O_NONBLOCK)
> > +   return -EAGAIN;
> > +
> > +   err = wait_event_interruptible(counter->events_wait,
> > +   !kfifo_is_empty(>events));
> > +   if (err)
> > +   return err;
> > +   }
> > +
> > +   raw_spin_lock_irqsave(>events_lock, flags);
> > +   err = kfifo_to_user(>events, buf, len, );
> > +   raw_spin_unlock_irqrestore(>events_lock, flags);
> > +   if (err)
> > +   return err;
> > +   } while (!copied);
> > +
> > +   return copied;
> > +}
> 
> All other uses of kfifo_to_user() I saw use a mutex instead of spin
> lock. I don't see a reason for disabling interrupts here.

The Counter character device interface is special in this case because
counter->events could be accessed from an interrupt context. This is
possible if counter_push_event() is called for an interrupt (as is the
case for the 104_quad_8 driver). In this case, we can't use mutex
because we can't sleep in an interrupt context, so our only option is to
use spin lock.

William Breathitt Gray


signature.asc
Description: PGP signature


Re: [PATCH v5 3/5] counter: Add character device interface

2020-10-18 Thread William Breathitt Gray
On Tue, Oct 13, 2020 at 08:40:18PM -0500, David Lechner wrote:
> On 9/26/20 9:18 PM, William Breathitt Gray wrote:
> > This 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.
> > 
> 
> Probably don't need to duplicate the full documentation in the commit
> message.

Ack.

> > diff --git a/drivers/counter/counter-chrdev.c 
> > b/drivers/counter/counter-chrdev.c
> > new file mode 100644
> > index ..2be3846e4105
> > --- /dev/null
> > +++ b/drivers/counter/counter-chrdev.c
> 
> 
> > +
> > +static int counter_set_event_node(struct counter_device *const counter,
> > + struct counter_watch *const watch,
> > + const struct counter_comp_node *const cfg)
> > +{
> > +   struct counter_event_node *event_node;
> > +   int err;
> > +   struct counter_comp_node *comp_node;
> > +
> > +   /* Search for event in the list */
> > +   list_for_each_entry(event_node, >next_events_list, l)
> > +   if (event_node->event == watch->event &&
> > +   event_node->channel == watch->channel)
> > +   break;
> > +
> > +   /* If event is not already in the list */
> > +   if (_node->l == >next_events_list) {
> > +   /* Allocate new event node */
> > +   event_node = kmalloc(sizeof(*event_node), GFP_ATOMIC);
> > +   if (!event_node)
> > +   return -ENOMEM;
> > +
> > +   /* Configure event node and add to the list */
> > +   event_node->event = watch->event;
> > +   event_node->channel = watch->channel;
> > +   INIT_LIST_HEAD(_node->comp_list);
> > +   list_add(_node->l, >next_events_list);
> > +   }
> > +
> > +   /* Check if component watch has already been set before */
> > +   list_for_each_entry(comp_node, _node->comp_list, l)
> > +   if (comp_node->parent == cfg->parent &&
> > +   comp_node->comp.count_u8_read == cfg->comp.count_u8_read)
> > +   return -EINVAL;
> 
> There are already enough things that could cause EINVAL, we could
> probably skip this duplicate check to make troubleshooting easier.

I'm not sure it would be safe to remove this check. This prevents
duplicate watches from being allocated for the same component -- the
rationale is that there's no benefit in repeating a component value grab
for the same event. Although a typical user will not have the motivation
to do this, a bad actor could purposely keep allocating duplicate
watches in order to starve all the available memory.

> > +
> > +   /* Allocate component node */
> > +   comp_node = kmalloc(sizeof(*comp_node), GFP_ATOMIC);
> > +   if (!comp_node) {
> > +   err = -ENOMEM;
> > +   goto err_comp_node;
> 
> Since there is only one goto, we could just handle the error and
> return here instead.

Ack.

> > +   }
> > +   *comp_node = *cfg;
> > +
> > +   /* Add component node to event node */
> > +   list_add_tail(_node->l, _node->comp_list);
> > +
> > +   return 0;
> > +
> > +err_comp_node:
> 
> A comment explaining the list_empty() check would be nice.
> It makes sense if you think about it, but it is not super
> obvious.

Ack.

> > +   if (list_empty(_node->comp_list)) {
> > +   list_del(_node->l);
> > +   kfree(event_node);
> > +   }
> > +   return err;
> > +}
> > +
> > +static int counter_set_watch(struct counter_device *const counter,
> > +const unsigned long arg)
> > +{
> > +   void __user *const uwatch = (void __user *)arg;
> > +   struct counter_watch watch;
> > +   struct counter_comp_node comp_node;
> > +   size_t parent, id;
> > +   struct counter_comp *ext;
> > +   size_t num_ext;
> > +
> > +   if (copy_from_user(, uwatch, sizeof(watch)))
> > +   return -EFAULT;
> > +   parent = watch.component.parent;
> > +   id = watch.component.id;
> > +
> > +   /* Configure parent component info for comp node */
> > +   switch (watch.component.scope) {
> > +   case COUNTER_SCOPE_DEVICE:
> > +   comp_node.parent = NULL;
> > +
> > +   ext = counter->ext;
> > +   num_ext = counter->num_ext;
> > +   break;
> > +   case COUNTER_SCOPE_SIGNAL:
> > +   if (counter->num_signals < parent + 1)
> 
> I think it would be more conventional this way:
> 
>   if (parent >= counter->num_signals)

Ack.

> > +   return -EINVAL;
> > +
> > +   comp_node.parent = counter->signals + parent;
> > +
> > +   ext = counter->signals[parent].ext;
> > +   num_ext = counter->signals[parent].num_ext;
> > +   break;
> > +   case COUNTER_SCOPE_COUNT:
> > +   if (counter->num_counts < parent + 1)
> 
> Same here.

Ack.

> > +   

Re: [PATCH v5 3/5] counter: Add character device interface

2020-10-14 Thread David Lechner

On 9/26/20 9:18 PM, William Breathitt Gray wrote:

+static ssize_t counter_chrdev_read(struct file *filp, char __user *buf,
+  size_t len, loff_t *f_ps)
+{
+   struct counter_device *const counter = filp->private_data;
+   int err;
+   unsigned long flags;
+   unsigned int copied;
+
+   if (len < sizeof(struct counter_event))
+   return -EINVAL;
+
+   do {
+   if (kfifo_is_empty(>events)) {
+   if (filp->f_flags & O_NONBLOCK)
+   return -EAGAIN;
+
+   err = wait_event_interruptible(counter->events_wait,
+   !kfifo_is_empty(>events));
+   if (err)
+   return err;
+   }
+
+   raw_spin_lock_irqsave(>events_lock, flags);
+   err = kfifo_to_user(>events, buf, len, );
+   raw_spin_unlock_irqrestore(>events_lock, flags);
+   if (err)
+   return err;
+   } while (!copied);
+
+   return copied;
+}


All other uses of kfifo_to_user() I saw use a mutex instead of spin
lock. I don't see a reason for disabling interrupts here.

Example:


static ssize_t iio_event_chrdev_read(struct file *filep,
 char __user *buf,
 size_t count,
 loff_t *f_ps)
{
struct iio_dev *indio_dev = filep->private_data;
struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev);
struct iio_event_interface *ev_int = iio_dev_opaque->event_interface;
unsigned int copied;
int ret;

if (!indio_dev->info)
return -ENODEV;

if (count < sizeof(struct iio_event_data))
return -EINVAL;

do {
if (kfifo_is_empty(_int->det_events)) {
if (filep->f_flags & O_NONBLOCK)
return -EAGAIN;

ret = wait_event_interruptible(ev_int->wait,
!kfifo_is_empty(_int->det_events) ||
indio_dev->info == NULL);
if (ret)
return ret;
if (indio_dev->info == NULL)
return -ENODEV;
}

if (mutex_lock_interruptible(_int->read_lock))
return -ERESTARTSYS;
ret = kfifo_to_user(_int->det_events, buf, count, );
mutex_unlock(_int->read_lock);

if (ret)
return ret;

/*
 * If we couldn't read anything from the fifo (a different
 * thread might have been faster) we either return -EAGAIN if
 * the file descriptor is non-blocking, otherwise we go back to
 * sleep and wait for more data to arrive.
 */
if (copied == 0 && (filep->f_flags & O_NONBLOCK))
return -EAGAIN;

} while (copied == 0);

return copied;
}


Re: [PATCH v5 3/5] counter: Add character device interface

2020-10-14 Thread David Lechner

On 10/14/20 2:05 PM, William Breathitt Gray wrote:

On Wed, Oct 14, 2020 at 12:43:08PM -0500, David Lechner wrote:

On 9/26/20 9:18 PM, William Breathitt Gray wrote:

diff --git a/drivers/counter/counter-chrdev.c b/drivers/counter/counter-chrdev.c
new file mode 100644
index ..2be3846e4105
--- /dev/null
+++ b/drivers/counter/counter-chrdev.c




+/**
+ * counter_push_event - queue event for userspace reading
+ * @counter:   pointer to Counter structure
+ * @event: triggered event
+ * @channel:   event channel
+ *
+ * Note: If no one is watching for the respective event, it is silently
+ * discarded.
+ *
+ * RETURNS:
+ * 0 on success, negative error number on failure.
+ */
+int counter_push_event(struct counter_device *const counter, const u8 event,
+  const u8 channel)
+{
+   struct counter_event ev = {0};
+   unsigned int copied = 0;
+   unsigned long flags;
+   struct counter_event_node *event_node;
+   struct counter_comp_node *comp_node;
+   int err;
+
+   ev.timestamp = ktime_get_ns();
+   ev.watch.event = event;
+   ev.watch.channel = channel;
+
+   raw_spin_lock_irqsave(>events_lock, flags);
+
+   /* Search for event in the list */
+   list_for_each_entry(event_node, >events_list, l)
+   if (event_node->event == event &&
+   event_node->channel == channel)
+   break;
+
+   /* If event is not in the list */
+   if (_node->l == >events_list)
+   goto exit_early;
+
+   /* Read and queue relevant comp for userspace */
+   list_for_each_entry(comp_node, _node->comp_list, l) {
+   err = counter_get_data(counter, comp_node, _u8);


Currently all counter devices are memory mapped devices so calling
counter_get_data() here with interrupts disabled is probably OK, but
if any counter drivers are added that use I2C/SPI/etc. that will take
a long time to read, it would cause problems leaving interrupts
disabled here.

Brainstorming: Would it make sense to separate the event from the
component value being read? As I mentioned in one of my previous
reviews, I think there are some cases where we would just want to
know when an event happened and not read any additional data anyway.
In the case of a slow communication bus, this would also let us
queue the event in the kfifo and notify poll right away and then
defer the reads in a workqueue for later.


I don't see any problems with reporting just an event without any
component value attached (e.g. userspace could handle the component
reads via sysfs at a later point). We would just need a way to inform
userspace that the struct counter_component in the struct counter_watch
returned should be ignored.

Perhaps we can add an additional member to struct counter_watch
indicating whether it's an empty watch; or alternatively, add a new
component scope define to differentiate between an actual component and
an empty one (e.g. COUNTER_SCOPE_EVENT). What do you think?

William Breathitt Gray



I made the same suggestion in one of my other replies - except
I called it COUNTER_SCOPE_NONE.


Re: [PATCH v5 3/5] counter: Add character device interface

2020-10-14 Thread William Breathitt Gray
On Wed, Oct 14, 2020 at 12:43:08PM -0500, David Lechner wrote:
> On 9/26/20 9:18 PM, William Breathitt Gray wrote:
> > diff --git a/drivers/counter/counter-chrdev.c 
> > b/drivers/counter/counter-chrdev.c
> > new file mode 100644
> > index ..2be3846e4105
> > --- /dev/null
> > +++ b/drivers/counter/counter-chrdev.c
> 
> 
> > +/**
> > + * counter_push_event - queue event for userspace reading
> > + * @counter:   pointer to Counter structure
> > + * @event: triggered event
> > + * @channel:   event channel
> > + *
> > + * Note: If no one is watching for the respective event, it is silently
> > + * discarded.
> > + *
> > + * RETURNS:
> > + * 0 on success, negative error number on failure.
> > + */
> > +int counter_push_event(struct counter_device *const counter, const u8 
> > event,
> > +  const u8 channel)
> > +{
> > +   struct counter_event ev = {0};
> > +   unsigned int copied = 0;
> > +   unsigned long flags;
> > +   struct counter_event_node *event_node;
> > +   struct counter_comp_node *comp_node;
> > +   int err;
> > +
> > +   ev.timestamp = ktime_get_ns();
> > +   ev.watch.event = event;
> > +   ev.watch.channel = channel;
> > +
> > +   raw_spin_lock_irqsave(>events_lock, flags);
> > +
> > +   /* Search for event in the list */
> > +   list_for_each_entry(event_node, >events_list, l)
> > +   if (event_node->event == event &&
> > +   event_node->channel == channel)
> > +   break;
> > +
> > +   /* If event is not in the list */
> > +   if (_node->l == >events_list)
> > +   goto exit_early;
> > +
> > +   /* Read and queue relevant comp for userspace */
> > +   list_for_each_entry(comp_node, _node->comp_list, l) {
> > +   err = counter_get_data(counter, comp_node, _u8);
> 
> Currently all counter devices are memory mapped devices so calling
> counter_get_data() here with interrupts disabled is probably OK, but
> if any counter drivers are added that use I2C/SPI/etc. that will take
> a long time to read, it would cause problems leaving interrupts
> disabled here.
> 
> Brainstorming: Would it make sense to separate the event from the
> component value being read? As I mentioned in one of my previous
> reviews, I think there are some cases where we would just want to
> know when an event happened and not read any additional data anyway.
> In the case of a slow communication bus, this would also let us
> queue the event in the kfifo and notify poll right away and then
> defer the reads in a workqueue for later.

I don't see any problems with reporting just an event without any
component value attached (e.g. userspace could handle the component
reads via sysfs at a later point). We would just need a way to inform
userspace that the struct counter_component in the struct counter_watch
returned should be ignored.

Perhaps we can add an additional member to struct counter_watch
indicating whether it's an empty watch; or alternatively, add a new
component scope define to differentiate between an actual component and
an empty one (e.g. COUNTER_SCOPE_EVENT). What do you think?

William Breathitt Gray


signature.asc
Description: PGP signature


Re: [PATCH v5 3/5] counter: Add character device interface

2020-10-14 Thread David Lechner

On 9/26/20 9:18 PM, William Breathitt Gray wrote:

diff --git a/drivers/counter/counter-chrdev.c b/drivers/counter/counter-chrdev.c
new file mode 100644
index ..2be3846e4105
--- /dev/null
+++ b/drivers/counter/counter-chrdev.c




+/**
+ * counter_push_event - queue event for userspace reading
+ * @counter:   pointer to Counter structure
+ * @event: triggered event
+ * @channel:   event channel
+ *
+ * Note: If no one is watching for the respective event, it is silently
+ * discarded.
+ *
+ * RETURNS:
+ * 0 on success, negative error number on failure.
+ */
+int counter_push_event(struct counter_device *const counter, const u8 event,
+  const u8 channel)
+{
+   struct counter_event ev = {0};
+   unsigned int copied = 0;
+   unsigned long flags;
+   struct counter_event_node *event_node;
+   struct counter_comp_node *comp_node;
+   int err;
+
+   ev.timestamp = ktime_get_ns();
+   ev.watch.event = event;
+   ev.watch.channel = channel;
+
+   raw_spin_lock_irqsave(>events_lock, flags);
+
+   /* Search for event in the list */
+   list_for_each_entry(event_node, >events_list, l)
+   if (event_node->event == event &&
+   event_node->channel == channel)
+   break;
+
+   /* If event is not in the list */
+   if (_node->l == >events_list)
+   goto exit_early;
+
+   /* Read and queue relevant comp for userspace */
+   list_for_each_entry(comp_node, _node->comp_list, l) {
+   err = counter_get_data(counter, comp_node, _u8);


Currently all counter devices are memory mapped devices so calling
counter_get_data() here with interrupts disabled is probably OK, but
if any counter drivers are added that use I2C/SPI/etc. that will take
a long time to read, it would cause problems leaving interrupts
disabled here.

Brainstorming: Would it make sense to separate the event from the
component value being read? As I mentioned in one of my previous
reviews, I think there are some cases where we would just want to
know when an event happened and not read any additional data anyway.
In the case of a slow communication bus, this would also let us
queue the event in the kfifo and notify poll right away and then
defer the reads in a workqueue for later.




+   if (err)
+   goto err_counter_get_data;
+
+   ev.watch.component = comp_node->component;
+
+   copied += kfifo_put(>events, ev);
+   }
+
+   if (copied)
+   wake_up_poll(>events_wait, EPOLLIN);
+
+exit_early:
+   raw_spin_unlock_irqrestore(>events_lock, flags);
+
+   return 0;
+
+err_counter_get_data:
+   raw_spin_unlock_irqrestore(>events_lock, flags);
+   return err;
+}




Re: [PATCH v5 3/5] counter: Add character device interface

2020-10-13 Thread David Lechner

On 9/26/20 9:18 PM, William Breathitt Gray wrote:

This 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.



Probably don't need to duplicate the full documentation in the commit
message.



diff --git a/drivers/counter/counter-chrdev.c b/drivers/counter/counter-chrdev.c
new file mode 100644
index ..2be3846e4105
--- /dev/null
+++ b/drivers/counter/counter-chrdev.c




+
+static int counter_set_event_node(struct counter_device *const counter,
+ struct counter_watch *const watch,
+ const struct counter_comp_node *const cfg)
+{
+   struct counter_event_node *event_node;
+   int err;
+   struct counter_comp_node *comp_node;
+
+   /* Search for event in the list */
+   list_for_each_entry(event_node, >next_events_list, l)
+   if (event_node->event == watch->event &&
+   event_node->channel == watch->channel)
+   break;
+
+   /* If event is not already in the list */
+   if (_node->l == >next_events_list) {
+   /* Allocate new event node */
+   event_node = kmalloc(sizeof(*event_node), GFP_ATOMIC);
+   if (!event_node)
+   return -ENOMEM;
+
+   /* Configure event node and add to the list */
+   event_node->event = watch->event;
+   event_node->channel = watch->channel;
+   INIT_LIST_HEAD(_node->comp_list);
+   list_add(_node->l, >next_events_list);
+   }
+
+   /* Check if component watch has already been set before */
+   list_for_each_entry(comp_node, _node->comp_list, l)
+   if (comp_node->parent == cfg->parent &&
+   comp_node->comp.count_u8_read == cfg->comp.count_u8_read)
+   return -EINVAL;


There are already enough things that could cause EINVAL, we could
probably skip this duplicate check to make troubleshooting easier.


+
+   /* Allocate component node */
+   comp_node = kmalloc(sizeof(*comp_node), GFP_ATOMIC);
+   if (!comp_node) {
+   err = -ENOMEM;
+   goto err_comp_node;


Since there is only one goto, we could just handle the error and
return here instead.


+   }
+   *comp_node = *cfg;
+
+   /* Add component node to event node */
+   list_add_tail(_node->l, _node->comp_list);
+
+   return 0;
+
+err_comp_node:


A comment explaining the list_empty() check would be nice.
It makes sense if you think about it, but it is not super
obvious.


+   if (list_empty(_node->comp_list)) {
+   list_del(_node->l);
+   kfree(event_node);
+   }
+   return err;
+}
+
+static int counter_set_watch(struct counter_device *const counter,
+const unsigned long arg)
+{
+   void __user *const uwatch = (void __user *)arg;
+   struct counter_watch watch;
+   struct counter_comp_node comp_node;
+   size_t parent, id;
+   struct counter_comp *ext;
+   size_t num_ext;
+
+   if (copy_from_user(, uwatch, sizeof(watch)))
+   return -EFAULT;
+   parent = watch.component.parent;
+   id = watch.component.id;
+
+   /* Configure parent component info for comp node */
+   switch (watch.component.scope) {
+   case COUNTER_SCOPE_DEVICE:
+   comp_node.parent = NULL;
+
+   ext = counter->ext;
+   num_ext = counter->num_ext;
+   break;
+   case COUNTER_SCOPE_SIGNAL:
+   if (counter->num_signals < parent + 1)


I think it would be more conventional this way:

if (parent >= counter->num_signals)


+   return -EINVAL;
+
+   comp_node.parent = counter->signals + parent;
+
+   ext = counter->signals[parent].ext;
+   num_ext = counter->signals[parent].num_ext;
+   break;
+   case COUNTER_SCOPE_COUNT:
+   if (counter->num_counts < parent + 1)


Same here.


+   return -EINVAL;
+
+   comp_node.parent = counter->counts + parent;
+
+   ext = counter->counts[parent].ext;
+   num_ext = counter->counts[parent].num_ext;
+   break;
+   default:
+   return -EINVAL;
+   }
+
+   /* Configure component info for comp node */
+   switch (watch.component.type) {
+   case COUNTER_COMPONENT_SIGNAL:
+   if (watch.component.scope != COUNTER_SCOPE_SIGNAL)
+   return -EINVAL;
+
+   comp_node.comp.type = COUNTER_COMP_SIGNAL_LEVEL;
+   comp_node.comp.signal_u8_read = 

[PATCH v5 3/5] counter: Add character device interface

2020-09-26 Thread William Breathitt Gray
This 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.

A high-level view of how a count value is passed down from a counter
driver is exemplified by the following. The driver callbacks are first
registered to the Counter core component for use by the Counter
userspace interface components:

++
| Counter device driver  |
++
| Processes data from device |
++
|
 ---
/ driver callbacks /
---
|
V
+--+
| Counter core |
+--+
| Routes device driver |
| callbacks to the |
| userspace interfaces |
+--+
|
 ---
/ driver callbacks /
---
|
+---+---+
|   |
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:

 --
/ Counter device   \
+--+
| Count register: 0x28 |
+--+
|
 -
/ raw count data /
-
|
V
++
| Counter device driver  |
++
| Processes data from device |
||
| Type: u64  |
| Value: 42  |
++
|
 --
/ u64 /
--
|
+---+---+
|   |
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
+--+
| `/sys/bus/counter/devices/counterX/countY/count` |