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

From: Sa, Nuno
Date: Mon May 04 2020 - 04:24:57 EST


> From: Jonathan Cameron <jic23@xxxxxxxxxx>
> Sent: Samstag, 2. Mai 2020 19:19
> 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
>
> [External]
>
> On Mon, 27 Apr 2020 12:09:18 +0000
> "Sa, Nuno" <Nuno.Sa@xxxxxxxxxx> wrote:
>
> > > 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...
>
> That's liable to be flakey as there is no requirement for the scan_mask to
> be ordered or indeed not have holes.
>

Yes, but the patch is adding this code:

`
for_each_set_bit(ch, buffer->channel_mask, indio_dev-
num_channels)
set_bit(indio_dev->channels[ch].scan_index, trialmask);
`

So, As I'm understanding we always enable the scan element on which a channel is inserted.
In the end, for a traditional driver with all different scan indexes, the resulting scan mask will
be the same as the channel mask if I'm not missing any subtlety here...

> >
> > > 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.
>
> Its more subtle than that. Because of the mux, a number of different
> channels can
> be enabled by different consumers, but all that is exposed to the driver is
> the resulting fused scan_mask across all consumers. It has no idea what
> channels
> have been enabled if they lie within a scan_mask element.
>
> Hence, whilst there can be individual channel enable and disable attributes
> they driver only seems enable and disable of scan mask elements. That
> means
> it needs to turn on ALL of the channels within one scan mask element.
> To do anything more complex requires us to carry all the following to the
> demux
> calculator
>
> 1) scan_mask
> 2) channel_mask
> 3) mapping from channel mask to scan mask
>
> It could be done, but it's potentially nasty. Even then we don't want to
> get into breaking out particular elements within a scan mask element so we'd
> end up providing all enabled channels (within each scan mask element)
> to the all consumers who are after any of them.
>
> We'd also have to expose the fused channel mask as well as scan mask
> to the driver which is not exactly elegant.
>
> That's why I'd suggest initial work uses scan mask as the fundamental
> unit of enable / disable, not the channel mask.
>
> Nothing stops then improving that later to deal with the channel mask
> fusion needed to work out the enables, but it's not something I'd do
> for step 1.
>
> >
> > 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...
>
> Hmm. I think we are talking about different things. Let me give an example.
>
> 8 channels in scan mask element 0 size 8 bits, 8 channels in scan mask
> element 1
>
> Enable a channel in scan mask element 0 on consumer 0, and a
> different one on consumer 1. If they were in different scan mask elements
> we'd deliver the first element only to consumer 0 and the second element
> only to consumer 1 (that's what the demux does for us)
>
> Here, in what I would suggest for the initial implementation, channel mask
> is not exposed at all to buffer setup op (update_scan_mask) - so we
> don't know which channels in that scan mask element are needed.
> Only answer, turn all 8 on.
>
> In this case we would deliver one 8 bit buffer element to each of the
> consumers
> but it would include the values for all 8 channels (but none from the 8
> channels
> in our second scan mask element).
>
> This keeps the channel mask logic (for now) separate from the demux
> and the buffered capture setup logic, but at the cost of sampling channels
> no one cares about. Note we often do that anyway as a lot of hardware does
> not have per channel enables, or is more efficient if we grab all the channels
> in a single transaction.
>

Hmm, I see your point now. Looking at the patchset, it also looks like that there's
no intention of doing the demux at the channel/bit level. I also agree on keeping the
granularity at the scan_element level otherwise it can be really unpleasant to implement
and "read" the demux code.

I was more looking for the possibility of passing the channel_mask to the drivers instead
of the scan_mask (when it makes sense to do so) so we can only sample the channels we
are interested in. In the end, we would push the complete scan_element to the iio_buffer
only with the bits we are interested in...

That being sad, I'm also not seeing a big problem in just enabling all the channels for a given
scan element but I might be missing something.

- Nuno SÃ