RE: [RFC PATCH 4/4] iio: Track enabled channels on a per channel basis

From: Sa, Nuno
Date: Mon Apr 27 2020 - 08:09:39 EST


> From: linux-iio-owner@xxxxxxxxxxxxxxx <linux-iio-owner@xxxxxxxxxxxxxxx>
> On Behalf Of Jonathan Cameron
> Sent: Sonntag, 26. April 2020 12:51
> To: Sa, Nuno <Nuno.Sa@xxxxxxxxxx>
> Cc: Ardelean, Alexandru <alexandru.Ardelean@xxxxxxxxxx>; linux-
> iio@xxxxxxxxxxxxxxx; linux-kernel@xxxxxxxxxxxxxxx; lars@xxxxxxxxxx
> Subject: Re: [RFC PATCH 4/4] iio: Track enabled channels on a per channel
> basis
>
> On Fri, 24 Apr 2020 07:51:05 +0000
> "Sa, Nuno" <Nuno.Sa@xxxxxxxxxx> wrote:
>
> > > From: linux-iio-owner@xxxxxxxxxxxxxxx <linux-iio-
> owner@xxxxxxxxxxxxxxx>
> > > On Behalf Of Alexandru Ardelean
> > > Sent: Freitag, 24. April 2020 07:18
> > > To: linux-iio@xxxxxxxxxxxxxxx; linux-kernel@xxxxxxxxxxxxxxx
> > > Cc: jic23@xxxxxxxxxx; lars@xxxxxxxxxx; Ardelean, Alexandru
> > > <alexandru.Ardelean@xxxxxxxxxx>
> > > Subject: [RFC PATCH 4/4] iio: Track enabled channels on a per channel
> basis
> > >
> > > From: Lars-Peter Clausen <lars@xxxxxxxxxx>
> > >
> > > Now that we support multiple channels with the same scan index we can
> no
> > > longer use the scan mask to track which channels have been enabled.
> > > Otherwise it is not possible to enable channels with the same scan index
> > > independently.
> > >
> > > Introduce a new channel mask which is used instead of the scan mask to
> > > track which channels are enabled. Whenever the channel mask is
> changed a
> > > new scan mask is computed based on it.
> > >
> > > Signed-off-by: Lars-Peter Clausen <lars@xxxxxxxxxx>
> > > Signed-off-by: Alexandru Ardelean <alexandru.ardelean@xxxxxxxxxx>
> > > ---
> > > drivers/iio/industrialio-buffer.c | 62 +++++++++++++++++++++----------
> > > drivers/iio/inkern.c | 19 +++++++++-
> > > include/linux/iio/buffer_impl.h | 3 ++
> > > include/linux/iio/consumer.h | 2 +
> > > 4 files changed, 64 insertions(+), 22 deletions(-)
> > >
> > > diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-
> buffer.c
> > > index c06691281287..1821a3e32fb3 100644
> > > --- a/drivers/iio/industrialio-buffer.c
> > > +++ b/drivers/iio/industrialio-buffer.c
> > > @@ -216,12 +216,20 @@ int iio_buffer_alloc_scanmask(struct iio_buffer
> > > *buffer,
> > > if (buffer->scan_mask == NULL)
> > > return -ENOMEM;
> > >
> > > + buffer->channel_mask = bitmap_zalloc(indio_dev->num_channels,
> > > + GFP_KERNEL);
> > > + if (buffer->channel_mask == NULL) {
> > > + bitmap_free(buffer->scan_mask);
> > > + return -ENOMEM;
> > > + }
> > > +
> > > return 0;
> > > }
> > > EXPORT_SYMBOL_GPL(iio_buffer_alloc_scanmask);
> > >
> > > void iio_buffer_free_scanmask(struct iio_buffer *buffer)
> > > {
> > > + bitmap_free(buffer->channel_mask);
> > > bitmap_free(buffer->scan_mask);
> > > }
> > > EXPORT_SYMBOL_GPL(iio_buffer_free_scanmask);
> > > @@ -285,7 +293,7 @@ static ssize_t iio_scan_el_show(struct device
> *dev,
> > >
> > > /* Ensure ret is 0 or 1. */
> > > ret = !!test_bit(to_iio_dev_attr(attr)->address,
> > > - indio_dev->buffer->scan_mask);
> > > + indio_dev->buffer->channel_mask);
> > >
> > > return sprintf(buf, "%d\n", ret);
> > > }
> > > @@ -330,11 +338,12 @@ static bool iio_validate_scan_mask(struct
> iio_dev
> > > *indio_dev,
> > > * buffers might request, hence this code only verifies that the
> > > * individual buffers request is plausible.
> > > */
> > > -static int iio_scan_mask_set(struct iio_dev *indio_dev,
> > > - struct iio_buffer *buffer, int bit)
> > > +static int iio_channel_mask_set(struct iio_dev *indio_dev,
> > > + struct iio_buffer *buffer, int bit)
> > > {
> > > const unsigned long *mask;
> > > unsigned long *trialmask;
> > > + unsigned int ch;
> > >
> > > trialmask = bitmap_zalloc(indio_dev->masklength, GFP_KERNEL);
> > > if (trialmask == NULL)
> > > @@ -343,8 +352,11 @@ static int iio_scan_mask_set(struct iio_dev
> > > *indio_dev,
> > > WARN(1, "Trying to set scanmask prior to registering
> > > buffer\n");
> > > goto err_invalid_mask;
> > > }
> > > - bitmap_copy(trialmask, buffer->scan_mask, indio_dev-
> > > >masklength);
> > > - set_bit(bit, trialmask);
> > > +
> > > + set_bit(bit, buffer->channel_mask);
> > > +
> > > + for_each_set_bit(ch, buffer->channel_mask, indio_dev-
> > > >num_channels)
> > > + set_bit(indio_dev->channels[ch].scan_index, trialmask);
> >
> > So, here if the channels all have the same scan_index, we will end up with a
> scan_mask which is
> > different that channel_mask, right? I saw that in our internal driver's we
> then just access the
> > channel_mask field directly to know what pieces/channels do we need to
> enable prior to
> > buffering, which implies including buffer_impl.h.
> Given that we handle the demux only at the level of scan elements that
> won't work in general
> (even if it wasn't a horrible layering issue).

Yes, and the driver just adds 16 channels and points all of them to scan_index 0. It then
sets real_bits and the shift so that userspace can get the right channel bit. So, in the end
we have just one buffer/scan element with 16bits. My problem here is more architectural...
We should not directly include "buffer_impl.h" in drivers...

> >
> > So, for me it would make sense to compute scan_mask so that it will be the
> same as channel_mask
> > (hmm but that would be a problem when computing the buffer size...) and
> drivers can correctly use
> > ` validate_scan_mask ()` cb. Alternatively, we need to expose
> channel_mask either on a new cb or
> > change the ` validate_scan_mask ()` footprint.
>
> Excellent points. We need to address support for:
>
> 1) available_scan_mask - if we have complicated rules on mixtures of
> channels inside
> a given buffer element.

Maybe one solution to expose channel mask is to check if channel_mask != scan_mask
before calling the ` validate_scan_mask()`. If it is, we pass channel_mask to the callback.
Driver's should then know what to do with it...

> 2) channel enabling though I'm sort of inclined to say that if you are using this
> approach
> you only get information on channels that make up a scan mask element.
> Tough luck you
> may end up enabling more than you'd like.

Not sure if I'm fully understanding this point. I believe with this approach channel
enablement works as before since the core is kind of mapping channel_mask to
scan_mask. So if we have 16 channels using only 1 scan_element we can still
enable/disable all 16 channels.

In the end, if we have a traditional driver with one channel per scan_index, channel_mask
should be equal to scan_mask. As we start to have more than one channel pointing to the
same scan_index, these masks will be different.

> It might be possible to make switch to using a channel mask but given the
> channel index is
> implicit that is going to be at least a little bit nasty.
>
> How much does it hurt to not have the ability to separately control channels
> within
> a given buffer element? Userspace can enable / disable them but reality is
> you'll

As long as we are "ok" with the extra amount of allocated memory, I think it would work.
Though drivers will have to replicate the same data trough all the enabled scan elements...

- Nuno SÃ

> get data for all the channels in a buffer element if any of them are enabled.
>
> Given the demux will copy the whole element anyway (don't want to waste
> time doing
> masking inside an element), userspace might get these extra channels
> anyway if another
> consumer has enabled them.
>
> Jonathan
>
>
> >
> > - Nuno SÃ