[PATCH v4 1/7] iio: introduce IIO_DECLARE_BUFFER_WITH_TS macros

David Lechner posted 7 patches 9 months, 2 weeks ago
There is a newer version of this series
[PATCH v4 1/7] iio: introduce IIO_DECLARE_BUFFER_WITH_TS macros
Posted by David Lechner 9 months, 2 weeks ago
Add new macros to help with the common case of declaring a buffer that
is safe to use with iio_push_to_buffers_with_ts(). This is not trivial
to do correctly because of the alignment requirements of the timestamp.
This will make it easier for both authors and reviewers.

To avoid double __align() attributes in cases where we also need DMA
alignment, add a 2nd variant IIO_DECLARE_DMA_BUFFER_WITH_TS().

Signed-off-by: David Lechner <dlechner@baylibre.com>
---

v4 changes:
* Drop the static_asserts(). Some 32-bit arches were triggering one, so
  we had to address the problem instead of hoping that it didn't exist.
  The other made a multi-statement macro, which isn't the best practice
  and didn't have a way to make a really helpful error message. The
  condition we were trying to catch is still caught by -Wvla.
* Changed __align(IIO_DMA_MINALIGN) to __align(MAX(IIO_DMA_MINALIGN,
  sizeof(s64))). As the build-bots found, there are some 32-bit arches
  where IIO_DMA_MINALIGN is 4, but we still need 8-byte alignment for
  the timestamp.

v3 changes:
* Use leading double-underscore for "private" macro to match "private"
  functions that do the same.
* Use static_assert() from linux/build_bug.h instead of _Static_assert()
* Fix incorrectly using sizeof(IIO_DMA_MINALIGN).
* Add check that count argument is constant. (Note, I didn't include a
  message in this static assert because it already gives a reasonable
  message.)

/home/david/work/bl/linux/drivers/iio/accel/sca3300.c:482:51: error: expression in static assertion is not constant
  482 |         IIO_DECLARE_BUFFER_WITH_TS(s16, channels, val);
      |                                                   ^~~

v2 changes:
* Add 2nd macro for DMA alignment
---
 include/linux/iio/iio.h | 37 +++++++++++++++++++++++++++++++++++++
 1 file changed, 37 insertions(+)

diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h
index 638cf2420fbd85cf2924d09d061df601d1d4bb2a..95d90740b4ffb3ebd819d03ad2bd05ecf40d4384 100644
--- a/include/linux/iio/iio.h
+++ b/include/linux/iio/iio.h
@@ -7,9 +7,12 @@
 #ifndef _INDUSTRIAL_IO_H_
 #define _INDUSTRIAL_IO_H_
 
+#include <linux/align.h>
+#include <linux/build_bug.h>
 #include <linux/device.h>
 #include <linux/cdev.h>
 #include <linux/compiler_types.h>
+#include <linux/minmax.h>
 #include <linux/slab.h>
 #include <linux/iio/types.h>
 /* IIO TODO LIST */
@@ -777,6 +780,40 @@ static inline void *iio_device_get_drvdata(const struct iio_dev *indio_dev)
  * them safe for use with non-coherent DMA.
  */
 #define IIO_DMA_MINALIGN ARCH_DMA_MINALIGN
+
+#define __IIO_DECLARE_BUFFER_WITH_TS(type, name, count) \
+	type name[ALIGN((count), sizeof(s64) / sizeof(type)) + sizeof(s64) / sizeof(type)]
+
+/**
+ * IIO_DECLARE_BUFFER_WITH_TS() - Declare a buffer with timestamp
+ * @type: element type of the buffer
+ * @name: identifier name of the buffer
+ * @count: number of elements in the buffer
+ *
+ * Declares a buffer that is safe to use with iio_push_to_buffer_with_ts(). In
+ * addition to allocating enough space for @count elements of @type, it also
+ * allocates space for a s64 timestamp at the end of the buffer and ensures
+ * proper alignment of the timestamp.
+ */
+#define IIO_DECLARE_BUFFER_WITH_TS(type, name, count) \
+	__IIO_DECLARE_BUFFER_WITH_TS(type, name, count) __aligned(sizeof(s64))
+
+/**
+ * IIO_DECLARE_DMA_BUFFER_WITH_TS() - Declare a DMA-aligned buffer with timestamp
+ * @type: element type of the buffer
+ * @name: identifier name of the buffer
+ * @count: number of elements in the buffer
+ *
+ * Same as IIO_DECLARE_BUFFER_WITH_TS(), but is uses __aligned(IIO_DMA_MINALIGN)
+ * to ensure that the buffer doesn't share cachelines with anything that comes
+ * before it in a struct. This should not be used for stack-allocated buffers
+ * as stack memory cannot generally be used for DMA.
+ */
+#define IIO_DECLARE_DMA_BUFFER_WITH_TS(type, name, count)	\
+	__IIO_DECLARE_BUFFER_WITH_TS(type, name, count)		\
+	/* IIO_DMA_MINALIGN may be 4 on some 32-bit arches. */	\
+	__aligned(MAX(IIO_DMA_MINALIGN, sizeof(s64)))
+
 struct iio_dev *iio_device_alloc(struct device *parent, int sizeof_priv);
 
 /* The information at the returned address is guaranteed to be cacheline aligned */

-- 
2.43.0
Re: [PATCH v4 1/7] iio: introduce IIO_DECLARE_BUFFER_WITH_TS macros
Posted by David Lechner 9 months, 2 weeks ago
On 4/28/25 3:23 PM, David Lechner wrote:
> Add new macros to help with the common case of declaring a buffer that
> is safe to use with iio_push_to_buffers_with_ts(). This is not trivial
> to do correctly because of the alignment requirements of the timestamp.
> This will make it easier for both authors and reviewers.
> 
> To avoid double __align() attributes in cases where we also need DMA
> alignment, add a 2nd variant IIO_DECLARE_DMA_BUFFER_WITH_TS().
> 
> Signed-off-by: David Lechner <dlechner@baylibre.com>
> ---

...

> +/**
> + * IIO_DECLARE_DMA_BUFFER_WITH_TS() - Declare a DMA-aligned buffer with timestamp
> + * @type: element type of the buffer
> + * @name: identifier name of the buffer
> + * @count: number of elements in the buffer
> + *
> + * Same as IIO_DECLARE_BUFFER_WITH_TS(), but is uses __aligned(IIO_DMA_MINALIGN)
> + * to ensure that the buffer doesn't share cachelines with anything that comes
> + * before it in a struct. This should not be used for stack-allocated buffers
> + * as stack memory cannot generally be used for DMA.
> + */
> +#define IIO_DECLARE_DMA_BUFFER_WITH_TS(type, name, count)	\
> +	__IIO_DECLARE_BUFFER_WITH_TS(type, name, count)		\
> +	/* IIO_DMA_MINALIGN may be 4 on some 32-bit arches. */	\
> +	__aligned(MAX(IIO_DMA_MINALIGN, sizeof(s64)))

I just realized my logic behind this is faulty. It assumes sizeof(s64) ==
__alignof__(s64), but that isn't always true and that is what caused the builds
to hit the static_assert() on v3.

We should be able to leave this as __aligned(IIO_DMA_MINALIGN)

And have this (with better error message):

static assert(IIO_DMA_MINALIGN % __alignof__(s64) == 0);
Re: [PATCH v4 1/7] iio: introduce IIO_DECLARE_BUFFER_WITH_TS macros
Posted by David Lechner 9 months, 2 weeks ago
On 4/28/25 9:12 PM, David Lechner wrote:
> On 4/28/25 3:23 PM, David Lechner wrote:
>> Add new macros to help with the common case of declaring a buffer that
>> is safe to use with iio_push_to_buffers_with_ts(). This is not trivial
>> to do correctly because of the alignment requirements of the timestamp.
>> This will make it easier for both authors and reviewers.
>>
>> To avoid double __align() attributes in cases where we also need DMA
>> alignment, add a 2nd variant IIO_DECLARE_DMA_BUFFER_WITH_TS().
>>
>> Signed-off-by: David Lechner <dlechner@baylibre.com>
>> ---
> 
> ...
> 
>> +/**
>> + * IIO_DECLARE_DMA_BUFFER_WITH_TS() - Declare a DMA-aligned buffer with timestamp
>> + * @type: element type of the buffer
>> + * @name: identifier name of the buffer
>> + * @count: number of elements in the buffer
>> + *
>> + * Same as IIO_DECLARE_BUFFER_WITH_TS(), but is uses __aligned(IIO_DMA_MINALIGN)
>> + * to ensure that the buffer doesn't share cachelines with anything that comes
>> + * before it in a struct. This should not be used for stack-allocated buffers
>> + * as stack memory cannot generally be used for DMA.
>> + */
>> +#define IIO_DECLARE_DMA_BUFFER_WITH_TS(type, name, count)	\
>> +	__IIO_DECLARE_BUFFER_WITH_TS(type, name, count)		\
>> +	/* IIO_DMA_MINALIGN may be 4 on some 32-bit arches. */	\
>> +	__aligned(MAX(IIO_DMA_MINALIGN, sizeof(s64)))
> 
> I just realized my logic behind this is faulty. It assumes sizeof(s64) ==
> __alignof__(s64), but that isn't always true and that is what caused the builds
> to hit the static_assert() on v3.
> 
> We should be able to leave this as __aligned(IIO_DMA_MINALIGN)
> 
> And have this (with better error message):
> 
> static assert(IIO_DMA_MINALIGN % __alignof__(s64) == 0);

I was working late yesterday and should have saved that reply until morning
to think about it more!

We do want to align to to sizeof(s64) instead of __alignof__(s64) to avoid
issues with, e.g. 32-bit kernel and 64-bit userspace (same reason that
aligned_s64 exists and always uses 8-byte alignment).

So I think this patch is correct as-is after all.
Re: [PATCH v4 1/7] iio: introduce IIO_DECLARE_BUFFER_WITH_TS macros
Posted by Nuno Sá 9 months, 2 weeks ago
On Tue, 2025-04-29 at 14:31 -0500, David Lechner wrote:
> On 4/28/25 9:12 PM, David Lechner wrote:
> > On 4/28/25 3:23 PM, David Lechner wrote:
> > > Add new macros to help with the common case of declaring a buffer that
> > > is safe to use with iio_push_to_buffers_with_ts(). This is not trivial
> > > to do correctly because of the alignment requirements of the timestamp.
> > > This will make it easier for both authors and reviewers.
> > > 
> > > To avoid double __align() attributes in cases where we also need DMA
> > > alignment, add a 2nd variant IIO_DECLARE_DMA_BUFFER_WITH_TS().
> > > 
> > > Signed-off-by: David Lechner <dlechner@baylibre.com>
> > > ---
> > 
> > ...
> > 
> > > +/**
> > > + * IIO_DECLARE_DMA_BUFFER_WITH_TS() - Declare a DMA-aligned buffer with
> > > timestamp
> > > + * @type: element type of the buffer
> > > + * @name: identifier name of the buffer
> > > + * @count: number of elements in the buffer
> > > + *
> > > + * Same as IIO_DECLARE_BUFFER_WITH_TS(), but is uses
> > > __aligned(IIO_DMA_MINALIGN)
> > > + * to ensure that the buffer doesn't share cachelines with anything that
> > > comes
> > > + * before it in a struct. This should not be used for stack-allocated
> > > buffers
> > > + * as stack memory cannot generally be used for DMA.
> > > + */
> > > +#define IIO_DECLARE_DMA_BUFFER_WITH_TS(type, name, count)	\
> > > +	__IIO_DECLARE_BUFFER_WITH_TS(type, name, count)		\
> > > +	/* IIO_DMA_MINALIGN may be 4 on some 32-bit arches. */	\
> > > +	__aligned(MAX(IIO_DMA_MINALIGN, sizeof(s64)))
> > 
> > I just realized my logic behind this is faulty. It assumes sizeof(s64) ==
> > __alignof__(s64), but that isn't always true and that is what caused the
> > builds
> > to hit the static_assert() on v3.
> > 
> > We should be able to leave this as __aligned(IIO_DMA_MINALIGN)
> > 
> > And have this (with better error message):
> > 
> > static assert(IIO_DMA_MINALIGN % __alignof__(s64) == 0);
> 
> I was working late yesterday and should have saved that reply until morning
> to think about it more!
> 
> We do want to align to to sizeof(s64) instead of __alignof__(s64) to avoid
> issues with, e.g. 32-bit kernel and 64-bit userspace (same reason that
> aligned_s64 exists and always uses 8-byte alignment).

What issues could we have? In your inner macros I think you still make sure we
pad everything up to sizeof(s64) right? Am I missing any subtle issue?

but...

> 
> So I think this patch is correct as-is after all.

FWIW, I do prefer this approach or what Andy suggest (min as sizeof(s64)).

- Nuno Sá
Re: [PATCH v4 1/7] iio: introduce IIO_DECLARE_BUFFER_WITH_TS macros
Posted by Andy Shevchenko 9 months, 2 weeks ago
On Tue, Apr 29, 2025 at 10:31 PM David Lechner <dlechner@baylibre.com> wrote:
> On 4/28/25 9:12 PM, David Lechner wrote:
> > On 4/28/25 3:23 PM, David Lechner wrote:
> >> Add new macros to help with the common case of declaring a buffer that
> >> is safe to use with iio_push_to_buffers_with_ts(). This is not trivial
> >> to do correctly because of the alignment requirements of the timestamp.
> >> This will make it easier for both authors and reviewers.
> >>
> >> To avoid double __align() attributes in cases where we also need DMA
> >> alignment, add a 2nd variant IIO_DECLARE_DMA_BUFFER_WITH_TS().

...

> >> +/**
> >> + * IIO_DECLARE_DMA_BUFFER_WITH_TS() - Declare a DMA-aligned buffer with timestamp
> >> + * @type: element type of the buffer
> >> + * @name: identifier name of the buffer
> >> + * @count: number of elements in the buffer
> >> + *
> >> + * Same as IIO_DECLARE_BUFFER_WITH_TS(), but is uses __aligned(IIO_DMA_MINALIGN)
> >> + * to ensure that the buffer doesn't share cachelines with anything that comes
> >> + * before it in a struct. This should not be used for stack-allocated buffers
> >> + * as stack memory cannot generally be used for DMA.
> >> + */
> >> +#define IIO_DECLARE_DMA_BUFFER_WITH_TS(type, name, count)   \
> >> +    __IIO_DECLARE_BUFFER_WITH_TS(type, name, count)         \
> >> +    /* IIO_DMA_MINALIGN may be 4 on some 32-bit arches. */  \
> >> +    __aligned(MAX(IIO_DMA_MINALIGN, sizeof(s64)))
> >
> > I just realized my logic behind this is faulty. It assumes sizeof(s64) ==
> > __alignof__(s64), but that isn't always true and that is what caused the builds
> > to hit the static_assert() on v3.
> >
> > We should be able to leave this as __aligned(IIO_DMA_MINALIGN)
> >
> > And have this (with better error message):
> >
> > static assert(IIO_DMA_MINALIGN % __alignof__(s64) == 0);
>
> I was working late yesterday and should have saved that reply until morning
> to think about it more!
>
> We do want to align to to sizeof(s64) instead of __alignof__(s64) to avoid
> issues with, e.g. 32-bit kernel and 64-bit userspace (same reason that
> aligned_s64 exists and always uses 8-byte alignment).
>
> So I think this patch is correct as-is after all.

I'm wondering, shouldn't it be better just to make sure that
IIO_DMA_MINALIGN is always bigger or equal to sizeof(s64)?

-- 
With Best Regards,
Andy Shevchenko
Re: [PATCH v4 1/7] iio: introduce IIO_DECLARE_BUFFER_WITH_TS macros
Posted by David Lechner 9 months, 2 weeks ago
On 4/29/25 2:36 PM, Andy Shevchenko wrote:
> On Tue, Apr 29, 2025 at 10:31 PM David Lechner <dlechner@baylibre.com> wrote:
>> On 4/28/25 9:12 PM, David Lechner wrote:
>>> On 4/28/25 3:23 PM, David Lechner wrote:
>>>> Add new macros to help with the common case of declaring a buffer that
>>>> is safe to use with iio_push_to_buffers_with_ts(). This is not trivial
>>>> to do correctly because of the alignment requirements of the timestamp.
>>>> This will make it easier for both authors and reviewers.
>>>>
>>>> To avoid double __align() attributes in cases where we also need DMA
>>>> alignment, add a 2nd variant IIO_DECLARE_DMA_BUFFER_WITH_TS().
> 
> ...
> 
>>>> +/**
>>>> + * IIO_DECLARE_DMA_BUFFER_WITH_TS() - Declare a DMA-aligned buffer with timestamp
>>>> + * @type: element type of the buffer
>>>> + * @name: identifier name of the buffer
>>>> + * @count: number of elements in the buffer
>>>> + *
>>>> + * Same as IIO_DECLARE_BUFFER_WITH_TS(), but is uses __aligned(IIO_DMA_MINALIGN)
>>>> + * to ensure that the buffer doesn't share cachelines with anything that comes
>>>> + * before it in a struct. This should not be used for stack-allocated buffers
>>>> + * as stack memory cannot generally be used for DMA.
>>>> + */
>>>> +#define IIO_DECLARE_DMA_BUFFER_WITH_TS(type, name, count)   \
>>>> +    __IIO_DECLARE_BUFFER_WITH_TS(type, name, count)         \
>>>> +    /* IIO_DMA_MINALIGN may be 4 on some 32-bit arches. */  \
>>>> +    __aligned(MAX(IIO_DMA_MINALIGN, sizeof(s64)))
>>>
>>> I just realized my logic behind this is faulty. It assumes sizeof(s64) ==
>>> __alignof__(s64), but that isn't always true and that is what caused the builds
>>> to hit the static_assert() on v3.
>>>
>>> We should be able to leave this as __aligned(IIO_DMA_MINALIGN)
>>>
>>> And have this (with better error message):
>>>
>>> static assert(IIO_DMA_MINALIGN % __alignof__(s64) == 0);
>>
>> I was working late yesterday and should have saved that reply until morning
>> to think about it more!
>>
>> We do want to align to to sizeof(s64) instead of __alignof__(s64) to avoid
>> issues with, e.g. 32-bit kernel and 64-bit userspace (same reason that
>> aligned_s64 exists and always uses 8-byte alignment).
>>
>> So I think this patch is correct as-is after all.
> 
> I'm wondering, shouldn't it be better just to make sure that
> IIO_DMA_MINALIGN is always bigger or equal to sizeof(s64)?
> 

Sounds reasonable to me. From what I have seen while working on this is that
there are quite a few drivers using IIO_DMA_MINALIGN expecting it to be
sufficient for timestamp alignment, which as it seems is not always the case.

I'll wait for Jonathan to weigh in though before spinning up a new patch.
Re: [PATCH v4 1/7] iio: introduce IIO_DECLARE_BUFFER_WITH_TS macros
Posted by Jonathan Cameron 9 months, 1 week ago
On Tue, 29 Apr 2025 14:47:41 -0500
David Lechner <dlechner@baylibre.com> wrote:

> On 4/29/25 2:36 PM, Andy Shevchenko wrote:
> > On Tue, Apr 29, 2025 at 10:31 PM David Lechner <dlechner@baylibre.com> wrote:  
> >> On 4/28/25 9:12 PM, David Lechner wrote:  
> >>> On 4/28/25 3:23 PM, David Lechner wrote:  
> >>>> Add new macros to help with the common case of declaring a buffer that
> >>>> is safe to use with iio_push_to_buffers_with_ts(). This is not trivial
> >>>> to do correctly because of the alignment requirements of the timestamp.
> >>>> This will make it easier for both authors and reviewers.
> >>>>
> >>>> To avoid double __align() attributes in cases where we also need DMA
> >>>> alignment, add a 2nd variant IIO_DECLARE_DMA_BUFFER_WITH_TS().  
> > 
> > ...
> >   
> >>>> +/**
> >>>> + * IIO_DECLARE_DMA_BUFFER_WITH_TS() - Declare a DMA-aligned buffer with timestamp
> >>>> + * @type: element type of the buffer
> >>>> + * @name: identifier name of the buffer
> >>>> + * @count: number of elements in the buffer
> >>>> + *
> >>>> + * Same as IIO_DECLARE_BUFFER_WITH_TS(), but is uses __aligned(IIO_DMA_MINALIGN)
> >>>> + * to ensure that the buffer doesn't share cachelines with anything that comes
> >>>> + * before it in a struct. This should not be used for stack-allocated buffers
> >>>> + * as stack memory cannot generally be used for DMA.
> >>>> + */
> >>>> +#define IIO_DECLARE_DMA_BUFFER_WITH_TS(type, name, count)   \
> >>>> +    __IIO_DECLARE_BUFFER_WITH_TS(type, name, count)         \
> >>>> +    /* IIO_DMA_MINALIGN may be 4 on some 32-bit arches. */  \
> >>>> +    __aligned(MAX(IIO_DMA_MINALIGN, sizeof(s64)))  
> >>>
> >>> I just realized my logic behind this is faulty. It assumes sizeof(s64) ==
> >>> __alignof__(s64), but that isn't always true and that is what caused the builds
> >>> to hit the static_assert() on v3.
> >>>
> >>> We should be able to leave this as __aligned(IIO_DMA_MINALIGN)
> >>>
> >>> And have this (with better error message):
> >>>
> >>> static assert(IIO_DMA_MINALIGN % __alignof__(s64) == 0);  
> >>
> >> I was working late yesterday and should have saved that reply until morning
> >> to think about it more!
> >>
> >> We do want to align to to sizeof(s64) instead of __alignof__(s64) to avoid
> >> issues with, e.g. 32-bit kernel and 64-bit userspace (same reason that
> >> aligned_s64 exists and always uses 8-byte alignment).
> >>
> >> So I think this patch is correct as-is after all.  
> > 
> > I'm wondering, shouldn't it be better just to make sure that
> > IIO_DMA_MINALIGN is always bigger or equal to sizeof(s64)?
> >   
> 
> Sounds reasonable to me. From what I have seen while working on this is that
> there are quite a few drivers using IIO_DMA_MINALIGN expecting it to be
> sufficient for timestamp alignment, which as it seems is not always the case.
> 
> I'll wait for Jonathan to weigh in though before spinning up a new patch.
> 
It would be very odd if we ever see a platform with a DMA alignment requirement
that is not a multiple of sizeof(s64) just forcing IIO_DMA_MINALIGN to max
of the arch constraint and sizeof(s64) seems fine to me and fixes up
all those other drivers that were assuming this was true already...
I thought it was and only got fussy for this macro :(


Jonathan