public inbox for linux-input@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/4] iio: buffer: fix timestamp alignment (in rare case)
@ 2026-03-01 20:24 David Lechner
  2026-03-01 20:24 ` [PATCH 1/4] iio: orientation: hid-sensor-rotation: add timestamp hack to not break userspace David Lechner
                   ` (3 more replies)
  0 siblings, 4 replies; 19+ messages in thread
From: David Lechner @ 2026-03-01 20:24 UTC (permalink / raw)
  To: Jiri Kosina, Jonathan Cameron, Srinivas Pandruvada, Nuno Sá,
	Andy Shevchenko, Lars Möllendorf, Lars-Peter Clausen,
	Greg Kroah-Hartman
  Cc: Jonathan Cameron, Lixu Zhang, linux-input, linux-iio,
	linux-kernel, David Lechner

In [1], it was pointed out that the iio_push_to_buffers_with_timestamp()
function is not putting the timestamp at the correct offset in the scan
buffer in rare cases where the largest scan element size is larger than
sizeof(int64_t).

[1]: https://lore.kernel.org/linux-iio/20260215162351.79f40b32@jic23-huawei/

This only affected one driver, namely hid-sensor-rotation since it is
the only driver that meets the condition. To fix things up, first we
fix the hid-sensor-rotation driver in a way that preserves compatibility
with the broken timestamp alignment. Then we are free to fix the core
IIO code without affecting any users.

Signed-off-by: David Lechner <dlechner@baylibre.com>
---
David Lechner (4):
      iio: orientation: hid-sensor-rotation: add timestamp hack to not break userspace
      iio: buffer: check return value of iio_compute_scan_bytes()
      iio: buffer: cache largest scan element size
      iio: buffer: fix timestamp alignment when quaternion in scan

 drivers/iio/industrialio-buffer.c             | 44 ++++++++++++++++++++-------
 drivers/iio/orientation/hid-sensor-rotation.c | 20 ++++++++++--
 include/linux/iio/buffer.h                    | 12 ++++++--
 include/linux/iio/iio.h                       |  3 ++
 4 files changed, 63 insertions(+), 16 deletions(-)
---
base-commit: 3fa5e5702a82d259897bd7e209469bc06368bf31
change-id: 20260228-iio-fix-timestamp-alignment-89ade1af458b

Best regards,
-- 
David Lechner <dlechner@baylibre.com>


^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCH 1/4] iio: orientation: hid-sensor-rotation: add timestamp hack to not break userspace
  2026-03-01 20:24 [PATCH 0/4] iio: buffer: fix timestamp alignment (in rare case) David Lechner
@ 2026-03-01 20:24 ` David Lechner
  2026-03-02  8:50   ` Andy Shevchenko
  2026-03-01 20:24 ` [PATCH 2/4] iio: buffer: check return value of iio_compute_scan_bytes() David Lechner
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 19+ messages in thread
From: David Lechner @ 2026-03-01 20:24 UTC (permalink / raw)
  To: Jiri Kosina, Jonathan Cameron, Srinivas Pandruvada, Nuno Sá,
	Andy Shevchenko, Lars Möllendorf, Lars-Peter Clausen,
	Greg Kroah-Hartman
  Cc: Jonathan Cameron, Lixu Zhang, linux-input, linux-iio,
	linux-kernel, David Lechner

Add a hack to push two timestamps in the hid-sensor-rotation scan data
to avoid breaking userspace applications that depend on the timestamp
being at the incorrect location in the scan data due to unintentional
misalignment in older kernels.

When this driver was written, the timestamp was in the correct location
because of the way iio_compute_scan_bytes() was implemented at the time.
(Samples were 24 bytes each.) Then commit 883f61653069 ("iio: buffer:
align the size of scan bytes to size of the largest element") changed
the computed scan_bytes to be a different size (32 bytes), which caused
iio_push_to_buffers_with_timestamp() to place the timestamp at an
incorrect offset.

There have been long periods of time (6 years each) where the timestamp
was in either location, so to not break either case, we open-code the
timestamps to be pushed to both locations in the scan data.

Reported-by: Jonathan Cameron <jic23@kernel.org>
Closes: https://lore.kernel.org/linux-iio/20260215162351.79f40b32@jic23-huawei/
Fixes: 883f61653069 ("iio: buffer: align the size of scan bytes to size of the largest element")
Signed-off-by: David Lechner <dlechner@baylibre.com>
---

I found that I could emulate this thanks to /dev/uhid. And thanks to AI
code generators, I was able to reasonably quickly make a script that
worked for emulating "HID-SENSOR-20008a". I'll include the script at the
end.

I set up the buffer like this:

cd /sys/bus/iio/devices/iio:device1/buffer0
echo 1 > in_rot_quaternion_en
echo 1 > in_timestamp_en
echo 1 > enable

Before this series is applied, we can see that the timestamp (group of 8
ending in "98 18") is at offset of 24 in the 32-byte data.

hd /dev/iio\:device1

00000000  6a 18 00 00 ac f3 ff ff  83 2d 00 00 02 d3 ff ff  |j........-......|
00000010  00 00 00 00 00 00 00 00  5a 17 a0 2a 73 cb 98 18  |........Z..*s...|

00000020  ad 17 00 00 6a f4 ff ff  35 2b 00 00 ca d0 ff ff  |....j...5+......|
00000030  00 00 00 00 00 00 00 00  2a a6 bb 30 73 cb 98 18  |........*..0s...|

00000040  92 1e 00 00 50 ec ff ff  ea c1 ff ff 78 f0 ff ff  |....P.......x...|
00000050  00 00 00 00 00 00 00 00  8f 3b a7 39 77 cb 98 18  |.........;.9w...|

After the first patch, we can see that the timestamp is now repeated at
both the correct and previous incorrect offsets (24 and 32). (Normally,
the last 8 bytes would be all 00 for padding.)

00000000  dd e0 ff ff 0e e0 ff ff  75 07 00 00 90 3f 00 00  |........u....?..|
00000010  f4 38 82 d0 3a cc 98 18  f4 38 82 d0 3a cc 98 18  |.8..:....8..:...|

00000020  a0 e0 ff ff 1d e0 ff ff  a0 0a 00 00 1c 3f 00 00  |.............?..|
00000030  3a 29 9f d6 3a cc 98 18  3a 29 9f d6 3a cc 98 18  |:)..:...:)..:...|

00000040  a9 e1 ff ff 1e 14 00 00  6c c1 ff ff 98 f2 ff ff  |........l.......|
00000050  39 21 77 11 55 cc 98 18  39 21 77 11 55 cc 98 18  |9!w.U...9!w.U...|

Test script:

import math
import os
import struct
import time

UHID_DESTROY = 1
UHID_CREATE2 = 11
UHID_INPUT2 = 12

UHID_DATA_MAX = 4096
BUS_USB = 0x03

class UHIDRotationSensor:
    def __init__(self, device_path: str = "/dev/uhid") -> None:
        """Initialize the virtual UHID rotation sensor.

        Args:
            device_path: Path to the UHID character device.
        """
        self.device_path = device_path
        self.fd = -1

    def open_device(self) -> None:
        """Open the UHID device."""
        self.fd = os.open(self.device_path, os.O_RDWR)

    def close_device(self) -> None:
        """Close the UHID device."""
        if self.fd >= 0:
            os.close(self.fd)
            self.fd = -1

    def create_device(self) -> None:
        """Create and register a virtual HID rotation sensor."""
        # HID descriptor for Sensor Device Orientation (HID-SENSOR-20008a)
        report_desc = bytes(
            [
                0x05,
                0x20,  # Usage Page: Sensor
                0x09,
                0x8A,  # Usage: Device Orientation (0x20008A)
                0xA1,
                0x01,  # Collection: Application

                # Input report (Report ID 1): quaternion x, y, z, w (s16)
                0x85,
                0x01,  # Report ID 1
                0x0A,
                0x83,
                0x04,  # Usage: Orientation Quaternion (0x200483)
                0x16,
                0x00,
                0x80,  # Logical Minimum: -32768
                0x26,
                0xFF,
                0x7F,  # Logical Maximum: 32767
                0x75,
                0x10,  # Report Size: 16
                0x95,
                0x04,  # Report Count: 4
                0x81,
                0x02,  # Input: Data, Variable, Absolute

                # Feature report (Report ID 2): report state, power state,
                # and report interval
                0x85,
                0x02,  # Report ID 2
                0x0A,
                0x16,
                0x03,  # Usage: Property Report State (0x200316)
                0x15,
                0x01,  # Logical Minimum: 1
                0x25,
                0x05,  # Logical Maximum: 5
                0x75,
                0x08,
                0x95,
                0x01,
                0xB1,
                0x02,  # Feature: Data, Variable, Absolute

                0x0A,
                0x19,
                0x03,  # Usage: Property Power State (0x200319)
                0x15,
                0x01,
                0x25,
                0x05,
                0x75,
                0x08,
                0x95,
                0x01,
                0xB1,
                0x02,  # Feature: Data, Variable, Absolute

                0x0A,
                0x0E,
                0x03,  # Usage: Property Report Interval (0x20030E)
                0x15,
                0x00,  # Logical Minimum: 0
                0x27,
                0xFF,
                0xFF,
                0xFF,
                0x7F,  # Logical Maximum: 2147483647
                0x75,
                0x20,  # Report Size: 32
                0x95,
                0x01,  # Report Count: 1
                0xB1,
                0x02,  # Feature: Data, Variable, Absolute

                0xC0,  # End Collection
            ]
        )

        # Build struct uhid_create2_req payload
        create_req_header = struct.pack(
            "<128s64s64sHHIIII",
            b"HID-SENSOR-20008a",  # name
            b"AD Inc",  # phys
            b"",  # uniq
            len(report_desc),  # rd_size
            BUS_USB,  # bus
            0x0001,  # vendor
            0x0001,  # product
            0,  # version
            0,  # country
        )

        create_req = (
            create_req_header
            + report_desc
            + b"\x00" * (UHID_DATA_MAX - len(report_desc))
        )
        event = struct.pack("<I", UHID_CREATE2) + create_req

        if self.fd < 0:
            raise RuntimeError("UHID device is not open")

        os.write(self.fd, event)

    def send_rotation_data(self, qx: int, qy: int, qz: int, qw: int) -> None:
        """Send one quaternion sample report.

        Args:
            qx: Quaternion X component (signed 16-bit).
            qy: Quaternion Y component (signed 16-bit).
            qz: Quaternion Z component (signed 16-bit).
            qw: Quaternion W component (signed 16-bit).
        """
        report_id = 1
        report = struct.pack(
            "<Bhhhh",
            report_id,
            max(-32768, min(32767, qx)),
            max(-32768, min(32767, qy)),
            max(-32768, min(32767, qz)),
            max(-32768, min(32767, qw)),
        )

        input_req = (
            struct.pack("<H", len(report))
            + report
            + b"\x00" * (UHID_DATA_MAX - len(report))
        )
        event = struct.pack("<I", UHID_INPUT2) + input_req

        if self.fd < 0:
            raise RuntimeError("UHID device is not open")

        os.write(self.fd, event)

    def run(self) -> None:
        """Run the virtual sensor simulation loop."""
        try:
            self.open_device()
            self.create_device()
            time.sleep(0.5)

            angle = 0.0
            while True:
                # Simulate changing orientation in quaternion form.
                half_angle = angle * 0.5
                qx = int(8192 * math.sin(half_angle * 0.7))
                qy = int(8192 * math.cos(half_angle * 0.5))
                qz = int(16384 * math.sin(half_angle))
                qw = int(16384 * math.cos(half_angle))

                self.send_rotation_data(qx, qy, qz, qw)
                angle += 0.1
                time.sleep(0.1)

        except KeyboardInterrupt:
            print("\nStopping...")
        finally:
            self.close_device()

if __name__ == "__main__":
    sensor = UHIDRotationSensor()
    sensor.run()
---
 drivers/iio/orientation/hid-sensor-rotation.c | 20 +++++++++++++++++---
 1 file changed, 17 insertions(+), 3 deletions(-)

diff --git a/drivers/iio/orientation/hid-sensor-rotation.c b/drivers/iio/orientation/hid-sensor-rotation.c
index e759f91a710a..a8bce5151dcb 100644
--- a/drivers/iio/orientation/hid-sensor-rotation.c
+++ b/drivers/iio/orientation/hid-sensor-rotation.c
@@ -20,7 +20,11 @@ struct dev_rot_state {
 	struct hid_sensor_hub_attribute_info quaternion;
 	struct {
 		s32 sampled_vals[4];
-		aligned_s64 timestamp;
+		/*
+		 * HACK: There are two copies of the same timestamp in case of
+		 * userspace depending on broken alignment from older kernels.
+		 */
+		aligned_s64 timestamp[2];
 	} scan;
 	int scale_pre_decml;
 	int scale_post_decml;
@@ -154,8 +158,18 @@ static int dev_rot_proc_event(struct hid_sensor_hub_device *hsdev,
 		if (!rot_state->timestamp)
 			rot_state->timestamp = iio_get_time_ns(indio_dev);
 
-		iio_push_to_buffers_with_timestamp(indio_dev, &rot_state->scan,
-						   rot_state->timestamp);
+		/*
+		 * HACK: IIO previously had an incorrect implementation of
+		 * iio_push_to_buffers_with_timestamp() that put the timestamp
+		 * in the last 8 bytes of the buffer, which was incorrect
+		 * according to the IIO ABI. To avoid breaking userspace that
+		 * depended on this broken behavior, we put the timestamp in
+		 * both the correct place and the old incorrect place.
+		 */
+		rot_state->scan.timestamp[0] = rot_state->timestamp;
+		rot_state->scan.timestamp[1] = rot_state->timestamp;
+
+		iio_push_to_buffers(indio_dev, &rot_state->scan);
 
 		rot_state->timestamp = 0;
 	}

-- 
2.43.0


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH 2/4] iio: buffer: check return value of iio_compute_scan_bytes()
  2026-03-01 20:24 [PATCH 0/4] iio: buffer: fix timestamp alignment (in rare case) David Lechner
  2026-03-01 20:24 ` [PATCH 1/4] iio: orientation: hid-sensor-rotation: add timestamp hack to not break userspace David Lechner
@ 2026-03-01 20:24 ` David Lechner
  2026-03-01 20:24 ` [PATCH 3/4] iio: buffer: cache largest scan element size David Lechner
  2026-03-01 20:24 ` [PATCH 4/4] iio: buffer: fix timestamp alignment when quaternion in scan David Lechner
  3 siblings, 0 replies; 19+ messages in thread
From: David Lechner @ 2026-03-01 20:24 UTC (permalink / raw)
  To: Jiri Kosina, Jonathan Cameron, Srinivas Pandruvada, Nuno Sá,
	Andy Shevchenko, Lars Möllendorf, Lars-Peter Clausen,
	Greg Kroah-Hartman
  Cc: Jonathan Cameron, Lixu Zhang, linux-input, linux-iio,
	linux-kernel, David Lechner

Check return value of iio_compute_scan_bytes() as it can return an
error.

The result is moved to an output parameter while we are touching this
as we will need to add a second output parameter in a later change.

The return type of iio_buffer_update_bytes_per_datum() also had to be
changed to propagate the error.

Signed-off-by: David Lechner <dlechner@baylibre.com>
---
 drivers/iio/industrialio-buffer.c | 36 +++++++++++++++++++++++++-----------
 1 file changed, 25 insertions(+), 11 deletions(-)

diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c
index 46f36a6ed271..71dfc81cb9e5 100644
--- a/drivers/iio/industrialio-buffer.c
+++ b/drivers/iio/industrialio-buffer.c
@@ -764,7 +764,8 @@ static int iio_storage_bytes_for_timestamp(struct iio_dev *indio_dev)
 }
 
 static int iio_compute_scan_bytes(struct iio_dev *indio_dev,
-				  const unsigned long *mask, bool timestamp)
+				  const unsigned long *mask, bool timestamp,
+				  unsigned int *scan_bytes)
 {
 	unsigned int bytes = 0;
 	int length, i, largest = 0;
@@ -790,8 +791,9 @@ static int iio_compute_scan_bytes(struct iio_dev *indio_dev,
 		largest = max(largest, length);
 	}
 
-	bytes = ALIGN(bytes, largest);
-	return bytes;
+	*scan_bytes = ALIGN(bytes, largest);
+
+	return 0;
 }
 
 static void iio_buffer_activate(struct iio_dev *indio_dev,
@@ -836,18 +838,23 @@ static int iio_buffer_disable(struct iio_buffer *buffer,
 	return buffer->access->disable(buffer, indio_dev);
 }
 
-static void iio_buffer_update_bytes_per_datum(struct iio_dev *indio_dev,
-					      struct iio_buffer *buffer)
+static int iio_buffer_update_bytes_per_datum(struct iio_dev *indio_dev,
+					     struct iio_buffer *buffer)
 {
 	unsigned int bytes;
+	int ret;
 
 	if (!buffer->access->set_bytes_per_datum)
-		return;
+		return 0;
 
-	bytes = iio_compute_scan_bytes(indio_dev, buffer->scan_mask,
-				       buffer->scan_timestamp);
+	ret = iio_compute_scan_bytes(indio_dev, buffer->scan_mask,
+				     buffer->scan_timestamp, &bytes);
+	if (ret)
+		return ret;
 
 	buffer->access->set_bytes_per_datum(buffer, bytes);
+
+	return 0;
 }
 
 static int iio_buffer_request_update(struct iio_dev *indio_dev,
@@ -855,7 +862,10 @@ static int iio_buffer_request_update(struct iio_dev *indio_dev,
 {
 	int ret;
 
-	iio_buffer_update_bytes_per_datum(indio_dev, buffer);
+	ret = iio_buffer_update_bytes_per_datum(indio_dev, buffer);
+	if (ret)
+		return ret;
+
 	if (buffer->access->request_update) {
 		ret = buffer->access->request_update(buffer);
 		if (ret) {
@@ -898,6 +908,7 @@ static int iio_verify_update(struct iio_dev *indio_dev,
 	struct iio_buffer *buffer;
 	bool scan_timestamp;
 	unsigned int modes;
+	int ret;
 
 	if (insert_buffer &&
 	    bitmap_empty(insert_buffer->scan_mask, masklength)) {
@@ -985,8 +996,11 @@ static int iio_verify_update(struct iio_dev *indio_dev,
 		scan_mask = compound_mask;
 	}
 
-	config->scan_bytes = iio_compute_scan_bytes(indio_dev,
-						    scan_mask, scan_timestamp);
+	ret = iio_compute_scan_bytes(indio_dev, scan_mask, scan_timestamp,
+				     &config->scan_bytes);
+	if (ret)
+		return ret;
+
 	config->scan_mask = scan_mask;
 	config->scan_timestamp = scan_timestamp;
 

-- 
2.43.0


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH 3/4] iio: buffer: cache largest scan element size
  2026-03-01 20:24 [PATCH 0/4] iio: buffer: fix timestamp alignment (in rare case) David Lechner
  2026-03-01 20:24 ` [PATCH 1/4] iio: orientation: hid-sensor-rotation: add timestamp hack to not break userspace David Lechner
  2026-03-01 20:24 ` [PATCH 2/4] iio: buffer: check return value of iio_compute_scan_bytes() David Lechner
@ 2026-03-01 20:24 ` David Lechner
  2026-03-02 12:16   ` Nuno Sá
  2026-03-02 20:47   ` Jonathan Cameron
  2026-03-01 20:24 ` [PATCH 4/4] iio: buffer: fix timestamp alignment when quaternion in scan David Lechner
  3 siblings, 2 replies; 19+ messages in thread
From: David Lechner @ 2026-03-01 20:24 UTC (permalink / raw)
  To: Jiri Kosina, Jonathan Cameron, Srinivas Pandruvada, Nuno Sá,
	Andy Shevchenko, Lars Möllendorf, Lars-Peter Clausen,
	Greg Kroah-Hartman
  Cc: Jonathan Cameron, Lixu Zhang, linux-input, linux-iio,
	linux-kernel, David Lechner

Cache the largest scan element size of elements enabled in a scan
buffer. This will be used later to ensure proper alignment of the
timestamp element in the scan buffer.

The new field could not be placed in struct iio_dev_opaque because we
will need to access it in a static inline function later, so we make it
__private instead. It is only intended to be used by core IIO code.

Signed-off-by: David Lechner <dlechner@baylibre.com>
---
 drivers/iio/industrialio-buffer.c | 14 +++++++++++---
 include/linux/iio/iio.h           |  3 +++
 2 files changed, 14 insertions(+), 3 deletions(-)

diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c
index 71dfc81cb9e5..83e9392f949f 100644
--- a/drivers/iio/industrialio-buffer.c
+++ b/drivers/iio/industrialio-buffer.c
@@ -765,7 +765,8 @@ static int iio_storage_bytes_for_timestamp(struct iio_dev *indio_dev)
 
 static int iio_compute_scan_bytes(struct iio_dev *indio_dev,
 				  const unsigned long *mask, bool timestamp,
-				  unsigned int *scan_bytes)
+				  unsigned int *scan_bytes,
+				  unsigned int *largest_element_size)
 {
 	unsigned int bytes = 0;
 	int length, i, largest = 0;
@@ -793,6 +794,9 @@ static int iio_compute_scan_bytes(struct iio_dev *indio_dev,
 
 	*scan_bytes = ALIGN(bytes, largest);
 
+	if (largest_element_size)
+		*largest_element_size = largest;
+
 	return 0;
 }
 
@@ -848,7 +852,7 @@ static int iio_buffer_update_bytes_per_datum(struct iio_dev *indio_dev,
 		return 0;
 
 	ret = iio_compute_scan_bytes(indio_dev, buffer->scan_mask,
-				     buffer->scan_timestamp, &bytes);
+				     buffer->scan_timestamp, &bytes, NULL);
 	if (ret)
 		return ret;
 
@@ -892,6 +896,7 @@ struct iio_device_config {
 	unsigned int watermark;
 	const unsigned long *scan_mask;
 	unsigned int scan_bytes;
+	unsigned int largest_scan_element_size;
 	bool scan_timestamp;
 };
 
@@ -997,7 +1002,8 @@ static int iio_verify_update(struct iio_dev *indio_dev,
 	}
 
 	ret = iio_compute_scan_bytes(indio_dev, scan_mask, scan_timestamp,
-				     &config->scan_bytes);
+				     &config->scan_bytes,
+				     &config->largest_scan_element_size);
 	if (ret)
 		return ret;
 
@@ -1155,6 +1161,8 @@ static int iio_enable_buffers(struct iio_dev *indio_dev,
 	indio_dev->active_scan_mask = config->scan_mask;
 	ACCESS_PRIVATE(indio_dev, scan_timestamp) = config->scan_timestamp;
 	indio_dev->scan_bytes = config->scan_bytes;
+	ACCESS_PRIVATE(indio_dev, largest_scan_element_size) =
+		config->largest_scan_element_size;
 	iio_dev_opaque->currentmode = config->mode;
 
 	iio_update_demux(indio_dev);
diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h
index a9ecff191bd9..85bcb5f8ae15 100644
--- a/include/linux/iio/iio.h
+++ b/include/linux/iio/iio.h
@@ -584,6 +584,8 @@ struct iio_buffer_setup_ops {
  *			and owner
  * @buffer:		[DRIVER] any buffer present
  * @scan_bytes:		[INTERN] num bytes captured to be fed to buffer demux
+ * @largest_scan_element_size: [INTERN] cache of the largest scan element size
+ *			       among the channels selected in the scan mask
  * @available_scan_masks: [DRIVER] optional array of allowed bitmasks. Sort the
  *			   array in order of preference, the most preferred
  *			   masks first.
@@ -610,6 +612,7 @@ struct iio_dev {
 
 	struct iio_buffer		*buffer;
 	int				scan_bytes;
+	unsigned int			__private largest_scan_element_size;
 
 	const unsigned long		*available_scan_masks;
 	unsigned int			__private masklength;

-- 
2.43.0


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH 4/4] iio: buffer: fix timestamp alignment when quaternion in scan
  2026-03-01 20:24 [PATCH 0/4] iio: buffer: fix timestamp alignment (in rare case) David Lechner
                   ` (2 preceding siblings ...)
  2026-03-01 20:24 ` [PATCH 3/4] iio: buffer: cache largest scan element size David Lechner
@ 2026-03-01 20:24 ` David Lechner
  2026-03-02  8:47   ` Andy Shevchenko
  2026-03-02 12:04   ` Nuno Sá
  3 siblings, 2 replies; 19+ messages in thread
From: David Lechner @ 2026-03-01 20:24 UTC (permalink / raw)
  To: Jiri Kosina, Jonathan Cameron, Srinivas Pandruvada, Nuno Sá,
	Andy Shevchenko, Lars Möllendorf, Lars-Peter Clausen,
	Greg Kroah-Hartman
  Cc: Jonathan Cameron, Lixu Zhang, linux-input, linux-iio,
	linux-kernel, David Lechner

Fix timestamp alignment when a scan buffer contains an element larger
than sizeof(int64_t). Currently s32 quaternions are the only such
element, and the one driver that has this (hid-sensor-rotation) has a
workaround in place already so this change does not affect it.

Previously, we assumed that the timestamp would always be 8-byte aligned
relative to the end of the scan buffer, but in the case of a scan buffer
a 16-byte quaternion vector, scan_bytes == 32, but the timestamp needs
to be placed at offset 16, not 24.

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

To test this, I used hid-sensor-rotation minus the first patch in the
series so that we can see that the timestamp actually moved to the
correct location.

Before this patch, the timestamp (8 bytes ending with "98 18") is in the
wrong location.

00000000  6a 18 00 00 ac f3 ff ff  83 2d 00 00 02 d3 ff ff  |j........-......|
00000010  00 00 00 00 00 00 00 00  5a 17 a0 2a 73 cb 98 18  |........Z..*s...|

00000020  ad 17 00 00 6a f4 ff ff  35 2b 00 00 ca d0 ff ff  |....j...5+......|
00000030  00 00 00 00 00 00 00 00  2a a6 bb 30 73 cb 98 18  |........*..0s...|

00000040  92 1e 00 00 50 ec ff ff  ea c1 ff ff 78 f0 ff ff  |....P.......x...|
00000050  00 00 00 00 00 00 00 00  8f 3b a7 39 77 cb 98 18  |.........;.9w...|

After this patch, timestamp is now in the correct location.

00000000  55 0f 00 00 dd 1f 00 00  af 0b 00 00 ec 3e 00 00  |U............>..|
00000010  c7 17 68 42 6d d0 98 18  00 00 00 00 00 00 00 00  |..hBm...........|

00000020  57 0e 00 00 c8 1f 00 00  d1 0e 00 00 42 3e 00 00  |W...........B>..|
00000030  56 a2 87 48 6d d0 98 18  00 00 00 00 00 00 00 00  |V..Hm...........|

00000040  a3 e2 ff ff d3 1b 00 00  0b c9 ff ff cc 20 00 00  |............. ..|
00000050  27 59 4d b3 72 d0 98 18  00 00 00 00 00 00 00 00  |'YM.r...........|

I also tested this with a different driver not affected by this bug to
make sure that the timestamp is still in the correct location for all
other drivers.
---
 include/linux/iio/buffer.h | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/include/linux/iio/buffer.h b/include/linux/iio/buffer.h
index d37f82678f71..ac19b39bdbe4 100644
--- a/include/linux/iio/buffer.h
+++ b/include/linux/iio/buffer.h
@@ -34,8 +34,16 @@ static inline int iio_push_to_buffers_with_timestamp(struct iio_dev *indio_dev,
 	void *data, int64_t timestamp)
 {
 	if (ACCESS_PRIVATE(indio_dev, scan_timestamp)) {
-		size_t ts_offset = indio_dev->scan_bytes / sizeof(int64_t) - 1;
-		((int64_t *)data)[ts_offset] = timestamp;
+		size_t ts_offset = indio_dev->scan_bytes -
+			ACCESS_PRIVATE(indio_dev, largest_scan_element_size);
+
+		/*
+		 * The size of indio_dev->scan_bytes is always aligned to
+		 * largest_scan_element_size (see iio_compute_scan_bytes()).
+		 * And this size is always going to be >= sizeof(timestamp).
+		 * So to correctly place the timestamp, it goes at this offset.
+		 */
+		*(int64_t *)(data + ts_offset) = timestamp;
 	}
 
 	return iio_push_to_buffers(indio_dev, data);

-- 
2.43.0


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* Re: [PATCH 4/4] iio: buffer: fix timestamp alignment when quaternion in scan
  2026-03-01 20:24 ` [PATCH 4/4] iio: buffer: fix timestamp alignment when quaternion in scan David Lechner
@ 2026-03-02  8:47   ` Andy Shevchenko
  2026-03-02 15:39     ` David Lechner
  2026-03-02 12:04   ` Nuno Sá
  1 sibling, 1 reply; 19+ messages in thread
From: Andy Shevchenko @ 2026-03-02  8:47 UTC (permalink / raw)
  To: David Lechner
  Cc: Jiri Kosina, Jonathan Cameron, Srinivas Pandruvada, Nuno Sá,
	Andy Shevchenko, Lars Möllendorf, Lars-Peter Clausen,
	Greg Kroah-Hartman, Jonathan Cameron, Lixu Zhang, linux-input,
	linux-iio, linux-kernel

On Sun, Mar 01, 2026 at 02:24:53PM -0600, David Lechner wrote:
> Fix timestamp alignment when a scan buffer contains an element larger
> than sizeof(int64_t). Currently s32 quaternions are the only such
> element, and the one driver that has this (hid-sensor-rotation) has a
> workaround in place already so this change does not affect it.
> 
> Previously, we assumed that the timestamp would always be 8-byte aligned
> relative to the end of the scan buffer, but in the case of a scan buffer
> a 16-byte quaternion vector, scan_bytes == 32, but the timestamp needs
> to be placed at offset 16, not 24.

...

> -		((int64_t *)data)[ts_offset] = timestamp;

> +		*(int64_t *)(data + ts_offset) = timestamp;

What's the point in modifying this? The comment you added suffice for
the original line.

-- 
With Best Regards,
Andy Shevchenko



^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 1/4] iio: orientation: hid-sensor-rotation: add timestamp hack to not break userspace
  2026-03-01 20:24 ` [PATCH 1/4] iio: orientation: hid-sensor-rotation: add timestamp hack to not break userspace David Lechner
@ 2026-03-02  8:50   ` Andy Shevchenko
  2026-03-02 15:18     ` David Lechner
  0 siblings, 1 reply; 19+ messages in thread
From: Andy Shevchenko @ 2026-03-02  8:50 UTC (permalink / raw)
  To: David Lechner
  Cc: Jiri Kosina, Jonathan Cameron, Srinivas Pandruvada, Nuno Sá,
	Andy Shevchenko, Lars Möllendorf, Lars-Peter Clausen,
	Greg Kroah-Hartman, Jonathan Cameron, Lixu Zhang, linux-input,
	linux-iio, linux-kernel

On Sun, Mar 01, 2026 at 02:24:50PM -0600, David Lechner wrote:
> Add a hack to push two timestamps in the hid-sensor-rotation scan data
> to avoid breaking userspace applications that depend on the timestamp
> being at the incorrect location in the scan data due to unintentional
> misalignment in older kernels.
> 
> When this driver was written, the timestamp was in the correct location
> because of the way iio_compute_scan_bytes() was implemented at the time.
> (Samples were 24 bytes each.) Then commit 883f61653069 ("iio: buffer:
> align the size of scan bytes to size of the largest element") changed
> the computed scan_bytes to be a different size (32 bytes), which caused
> iio_push_to_buffers_with_timestamp() to place the timestamp at an
> incorrect offset.
> 
> There have been long periods of time (6 years each) where the timestamp
> was in either location, so to not break either case, we open-code the
> timestamps to be pushed to both locations in the scan data.

...

> +		/*
> +		 * HACK: There are two copies of the same timestamp in case of

Usually we use FIXME in such cases. HACK is something which goes with
"do not apply".

Does it mean it will stay forever?

> +		 * userspace depending on broken alignment from older kernels.
> +		 */
> +		aligned_s64 timestamp[2];

...

> +		/*
> +		 * HACK: IIO previously had an incorrect implementation of

Ditto.

> +		 * iio_push_to_buffers_with_timestamp() that put the timestamp
> +		 * in the last 8 bytes of the buffer, which was incorrect
> +		 * according to the IIO ABI. To avoid breaking userspace that
> +		 * depended on this broken behavior, we put the timestamp in
> +		 * both the correct place and the old incorrect place.
> +		 */
> +		rot_state->scan.timestamp[0] = rot_state->timestamp;
> +		rot_state->scan.timestamp[1] = rot_state->timestamp;

-- 
With Best Regards,
Andy Shevchenko



^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 4/4] iio: buffer: fix timestamp alignment when quaternion in scan
  2026-03-01 20:24 ` [PATCH 4/4] iio: buffer: fix timestamp alignment when quaternion in scan David Lechner
  2026-03-02  8:47   ` Andy Shevchenko
@ 2026-03-02 12:04   ` Nuno Sá
  2026-03-02 15:42     ` David Lechner
  1 sibling, 1 reply; 19+ messages in thread
From: Nuno Sá @ 2026-03-02 12:04 UTC (permalink / raw)
  To: David Lechner, Jiri Kosina, Jonathan Cameron, Srinivas Pandruvada,
	Nuno Sá, Andy Shevchenko, Lars Möllendorf,
	Lars-Peter Clausen, Greg Kroah-Hartman
  Cc: Jonathan Cameron, Lixu Zhang, linux-input, linux-iio,
	linux-kernel

On Sun, 2026-03-01 at 14:24 -0600, David Lechner wrote:
> Fix timestamp alignment when a scan buffer contains an element larger
> than sizeof(int64_t). Currently s32 quaternions are the only such
> element, and the one driver that has this (hid-sensor-rotation) has a
> workaround in place already so this change does not affect it.
> 
> Previously, we assumed that the timestamp would always be 8-byte aligned
> relative to the end of the scan buffer, but in the case of a scan buffer
> a 16-byte quaternion vector, scan_bytes == 32, but the timestamp needs
> to be placed at offset 16, not 24.
> 
> Signed-off-by: David Lechner <dlechner@baylibre.com>
> ---
> 
> To test this, I used hid-sensor-rotation minus the first patch in the
> series so that we can see that the timestamp actually moved to the
> correct location.
> 
> Before this patch, the timestamp (8 bytes ending with "98 18") is in the
> wrong location.
> 
> 00000000  6a 18 00 00 ac f3 ff ff  83 2d 00 00 02 d3 ff ff  |j........-......|
> 00000010  00 00 00 00 00 00 00 00  5a 17 a0 2a 73 cb 98 18  |........Z..*s...|
> 
> 00000020  ad 17 00 00 6a f4 ff ff  35 2b 00 00 ca d0 ff ff  |....j...5+......|
> 00000030  00 00 00 00 00 00 00 00  2a a6 bb 30 73 cb 98 18  |........*..0s...|
> 
> 00000040  92 1e 00 00 50 ec ff ff  ea c1 ff ff 78 f0 ff ff  |....P.......x...|
> 00000050  00 00 00 00 00 00 00 00  8f 3b a7 39 77 cb 98 18  |.........;.9w...|
> 
> After this patch, timestamp is now in the correct location.
> 
> 00000000  55 0f 00 00 dd 1f 00 00  af 0b 00 00 ec 3e 00 00  |U............>..|
> 00000010  c7 17 68 42 6d d0 98 18  00 00 00 00 00 00 00 00  |..hBm...........|
> 
> 00000020  57 0e 00 00 c8 1f 00 00  d1 0e 00 00 42 3e 00 00  |W...........B>..|
> 00000030  56 a2 87 48 6d d0 98 18  00 00 00 00 00 00 00 00  |V..Hm...........|
> 
> 00000040  a3 e2 ff ff d3 1b 00 00  0b c9 ff ff cc 20 00 00  |............. ..|
> 00000050  27 59 4d b3 72 d0 98 18  00 00 00 00 00 00 00 00  |'YM.r...........|
> 
> I also tested this with a different driver not affected by this bug to
> make sure that the timestamp is still in the correct location for all
> other drivers.
> ---
>  include/linux/iio/buffer.h | 12 ++++++++++--
>  1 file changed, 10 insertions(+), 2 deletions(-)
> 
> diff --git a/include/linux/iio/buffer.h b/include/linux/iio/buffer.h
> index d37f82678f71..ac19b39bdbe4 100644
> --- a/include/linux/iio/buffer.h
> +++ b/include/linux/iio/buffer.h
> @@ -34,8 +34,16 @@ static inline int iio_push_to_buffers_with_timestamp(struct iio_dev *indio_dev,
>  	void *data, int64_t timestamp)
>  {
>  	if (ACCESS_PRIVATE(indio_dev, scan_timestamp)) {
> -		size_t ts_offset = indio_dev->scan_bytes / sizeof(int64_t) - 1;
> -		((int64_t *)data)[ts_offset] = timestamp;
> +		size_t ts_offset = indio_dev->scan_bytes -
> +			ACCESS_PRIVATE(indio_dev, largest_scan_element_size);

Given that we're adding a new private member, maybe we could just directly cache the ts_offset
in iio_compute_scan_bytes()? Would make the code a bit easier to follow IMHO

- Nuno Sá
> 

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 3/4] iio: buffer: cache largest scan element size
  2026-03-01 20:24 ` [PATCH 3/4] iio: buffer: cache largest scan element size David Lechner
@ 2026-03-02 12:16   ` Nuno Sá
  2026-03-02 15:35     ` David Lechner
  2026-03-02 20:47   ` Jonathan Cameron
  1 sibling, 1 reply; 19+ messages in thread
From: Nuno Sá @ 2026-03-02 12:16 UTC (permalink / raw)
  To: David Lechner, Jiri Kosina, Jonathan Cameron, Srinivas Pandruvada,
	Nuno Sá, Andy Shevchenko, Lars Möllendorf,
	Lars-Peter Clausen, Greg Kroah-Hartman
  Cc: Jonathan Cameron, Lixu Zhang, linux-input, linux-iio,
	linux-kernel

On Sun, 2026-03-01 at 14:24 -0600, David Lechner wrote:
> Cache the largest scan element size of elements enabled in a scan
> buffer. This will be used later to ensure proper alignment of the
> timestamp element in the scan buffer.
> 
> The new field could not be placed in struct iio_dev_opaque because we
> will need to access it in a static inline function later, so we make it
> __private instead. It is only intended to be used by core IIO code.
> 
> Signed-off-by: David Lechner <dlechner@baylibre.com>
> ---
>  drivers/iio/industrialio-buffer.c | 14 +++++++++++---
>  include/linux/iio/iio.h           |  3 +++
>  2 files changed, 14 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c
> index 71dfc81cb9e5..83e9392f949f 100644
> --- a/drivers/iio/industrialio-buffer.c
> +++ b/drivers/iio/industrialio-buffer.c
> @@ -765,7 +765,8 @@ static int iio_storage_bytes_for_timestamp(struct iio_dev *indio_dev)
>  
>  static int iio_compute_scan_bytes(struct iio_dev *indio_dev,
>  				  const unsigned long *mask, bool timestamp,
> -				  unsigned int *scan_bytes)
> +				  unsigned int *scan_bytes,
> +				  unsigned int *largest_element_size)
>  {
>  	unsigned int bytes = 0;
>  	int length, i, largest = 0;
> @@ -793,6 +794,9 @@ static int iio_compute_scan_bytes(struct iio_dev *indio_dev,
>  
>  	*scan_bytes = ALIGN(bytes, largest);
>  
> +	if (largest_element_size)
> +		*largest_element_size = largest;

I might be missing something but it seems we now have two paths:

1. Go with 32 bytes
2. Go with 24 bytes (natural alignment)

ABI was not clear so I'm not sure if we do want to enforce/treat repeated values as one single
element? If so, nothing to change. But if not, we could re-think the approach and save some bytes. 
Marginal savings though so If having the smaller buffer is not straight enough I would be ok with
the simplicity tradeoff.

- Nuno Sá

> +
>  	return 0;
>  }
>  
> @@ -848,7 +852,7 @@ static int iio_buffer_update_bytes_per_datum(struct iio_dev *indio_dev,
>  		return 0;
>  
>  	ret = iio_compute_scan_bytes(indio_dev, buffer->scan_mask,
> -				     buffer->scan_timestamp, &bytes);
> +				     buffer->scan_timestamp, &bytes, NULL);
>  	if (ret)
>  		return ret;
>  
> @@ -892,6 +896,7 @@ struct iio_device_config {
>  	unsigned int watermark;
>  	const unsigned long *scan_mask;
>  	unsigned int scan_bytes;
> +	unsigned int largest_scan_element_size;
>  	bool scan_timestamp;
>  };
>  
> @@ -997,7 +1002,8 @@ static int iio_verify_update(struct iio_dev *indio_dev,
>  	}
>  
>  	ret = iio_compute_scan_bytes(indio_dev, scan_mask, scan_timestamp,
> -				     &config->scan_bytes);
> +				     &config->scan_bytes,
> +				     &config->largest_scan_element_size);
>  	if (ret)
>  		return ret;
>  
> @@ -1155,6 +1161,8 @@ static int iio_enable_buffers(struct iio_dev *indio_dev,
>  	indio_dev->active_scan_mask = config->scan_mask;
>  	ACCESS_PRIVATE(indio_dev, scan_timestamp) = config->scan_timestamp;
>  	indio_dev->scan_bytes = config->scan_bytes;
> +	ACCESS_PRIVATE(indio_dev, largest_scan_element_size) =
> +		config->largest_scan_element_size;
>  	iio_dev_opaque->currentmode = config->mode;
>  
>  	iio_update_demux(indio_dev);
> diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h
> index a9ecff191bd9..85bcb5f8ae15 100644
> --- a/include/linux/iio/iio.h
> +++ b/include/linux/iio/iio.h
> @@ -584,6 +584,8 @@ struct iio_buffer_setup_ops {
>   *			and owner
>   * @buffer:		[DRIVER] any buffer present
>   * @scan_bytes:		[INTERN] num bytes captured to be fed to buffer demux
> + * @largest_scan_element_size: [INTERN] cache of the largest scan element size
> + *			       among the channels selected in the scan mask
>   * @available_scan_masks: [DRIVER] optional array of allowed bitmasks. Sort the
>   *			   array in order of preference, the most preferred
>   *			   masks first.
> @@ -610,6 +612,7 @@ struct iio_dev {
>  
>  	struct iio_buffer		*buffer;
>  	int				scan_bytes;
> +	unsigned int			__private largest_scan_element_size;
>  
>  	const unsigned long		*available_scan_masks;
>  	unsigned int			__private masklength;

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 1/4] iio: orientation: hid-sensor-rotation: add timestamp hack to not break userspace
  2026-03-02  8:50   ` Andy Shevchenko
@ 2026-03-02 15:18     ` David Lechner
  2026-03-02 20:39       ` Jonathan Cameron
  0 siblings, 1 reply; 19+ messages in thread
From: David Lechner @ 2026-03-02 15:18 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: Jiri Kosina, Jonathan Cameron, Srinivas Pandruvada, Nuno Sá,
	Andy Shevchenko, Lars Möllendorf, Lars-Peter Clausen,
	Greg Kroah-Hartman, Jonathan Cameron, Lixu Zhang, linux-input,
	linux-iio, linux-kernel

On 3/2/26 2:50 AM, Andy Shevchenko wrote:
> On Sun, Mar 01, 2026 at 02:24:50PM -0600, David Lechner wrote:
>> Add a hack to push two timestamps in the hid-sensor-rotation scan data
>> to avoid breaking userspace applications that depend on the timestamp
>> being at the incorrect location in the scan data due to unintentional
>> misalignment in older kernels.
>>
>> When this driver was written, the timestamp was in the correct location
>> because of the way iio_compute_scan_bytes() was implemented at the time.
>> (Samples were 24 bytes each.) Then commit 883f61653069 ("iio: buffer:
>> align the size of scan bytes to size of the largest element") changed
>> the computed scan_bytes to be a different size (32 bytes), which caused
>> iio_push_to_buffers_with_timestamp() to place the timestamp at an
>> incorrect offset.
>>
>> There have been long periods of time (6 years each) where the timestamp
>> was in either location, so to not break either case, we open-code the
>> timestamps to be pushed to both locations in the scan data.
> 
> ...
> 
>> +		/*
>> +		 * HACK: There are two copies of the same timestamp in case of
> 
> Usually we use FIXME in such cases. HACK is something which goes with
> "do not apply".
> 
> Does it mean it will stay forever?

Yes, it will have to stay forever because we can't break userspace.

My intention here was for HACK to mean "do not copy to another driver".


If we think that no one is depending on timestamps being in the wrong
offset, we could omit this change and apply only the rest of the series.
And then only apply this patch if anyone complains. I am just trying to
play it safe here and not risk breaking things.

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 3/4] iio: buffer: cache largest scan element size
  2026-03-02 12:16   ` Nuno Sá
@ 2026-03-02 15:35     ` David Lechner
  2026-03-02 16:18       ` Nuno Sá
  0 siblings, 1 reply; 19+ messages in thread
From: David Lechner @ 2026-03-02 15:35 UTC (permalink / raw)
  To: Nuno Sá, Jiri Kosina, Jonathan Cameron, Srinivas Pandruvada,
	Nuno Sá, Andy Shevchenko, Lars Möllendorf,
	Lars-Peter Clausen, Greg Kroah-Hartman
  Cc: Jonathan Cameron, Lixu Zhang, linux-input, linux-iio,
	linux-kernel

On 3/2/26 6:16 AM, Nuno Sá wrote:
> On Sun, 2026-03-01 at 14:24 -0600, David Lechner wrote:
>> Cache the largest scan element size of elements enabled in a scan
>> buffer. This will be used later to ensure proper alignment of the
>> timestamp element in the scan buffer.
>>
>> The new field could not be placed in struct iio_dev_opaque because we
>> will need to access it in a static inline function later, so we make it
>> __private instead. It is only intended to be used by core IIO code.
>>
>> Signed-off-by: David Lechner <dlechner@baylibre.com>
>> ---
>>  drivers/iio/industrialio-buffer.c | 14 +++++++++++---
>>  include/linux/iio/iio.h           |  3 +++
>>  2 files changed, 14 insertions(+), 3 deletions(-)
>>
>> diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c
>> index 71dfc81cb9e5..83e9392f949f 100644
>> --- a/drivers/iio/industrialio-buffer.c
>> +++ b/drivers/iio/industrialio-buffer.c
>> @@ -765,7 +765,8 @@ static int iio_storage_bytes_for_timestamp(struct iio_dev *indio_dev)
>>  
>>  static int iio_compute_scan_bytes(struct iio_dev *indio_dev,
>>  				  const unsigned long *mask, bool timestamp,
>> -				  unsigned int *scan_bytes)
>> +				  unsigned int *scan_bytes,
>> +				  unsigned int *largest_element_size)
>>  {
>>  	unsigned int bytes = 0;
>>  	int length, i, largest = 0;
>> @@ -793,6 +794,9 @@ static int iio_compute_scan_bytes(struct iio_dev *indio_dev,
>>  
>>  	*scan_bytes = ALIGN(bytes, largest);
>>  
>> +	if (largest_element_size)
>> +		*largest_element_size = largest;
> 
> I might be missing something but it seems we now have two paths:
> 
> 1. Go with 32 bytes
> 2. Go with 24 bytes (natural alignment)

Hmm... You are right, but we are safe for now because the only repeat is
a quaternion, which has repeat of 4, so we don't have a case with e.g.
24 bytes right now.

I can do a follow-up to future-proof iio_storage_bytes_for_si() to
handle repeat = 3 (or any other less likely value).

Without the repeat, the size is based on .storagebits, and .storagebits /
BITS_PER_BYTE is always a power of 2, so no problem there.

> 
> ABI was not clear so I'm not sure if we do want to enforce/treat repeated values as one single
> element

It has always been this way and we had some recent breakage because I didn't
know about this. This patch series is a direct result of that [1] because we
identified more bugs when analyzing it.

[1]: https://lore.kernel.org/linux-iio/bug-221077-217253@https.bugzilla.kernel.org%2F/

> If so, nothing to change. But if not, we could re-think the approach and save some bytes. 

It's too late and breaks usespace as we have seen.

> Marginal savings though so If having the smaller buffer is not straight enough I would be ok with
> the simplicity tradeoff.
> 
> - Nuno Sá
> 

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 4/4] iio: buffer: fix timestamp alignment when quaternion in scan
  2026-03-02  8:47   ` Andy Shevchenko
@ 2026-03-02 15:39     ` David Lechner
  2026-03-02 16:03       ` Andy Shevchenko
  0 siblings, 1 reply; 19+ messages in thread
From: David Lechner @ 2026-03-02 15:39 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: Jiri Kosina, Jonathan Cameron, Srinivas Pandruvada, Nuno Sá,
	Andy Shevchenko, Lars Möllendorf, Lars-Peter Clausen,
	Greg Kroah-Hartman, Jonathan Cameron, Lixu Zhang, linux-input,
	linux-iio, linux-kernel

On 3/2/26 2:47 AM, Andy Shevchenko wrote:
> On Sun, Mar 01, 2026 at 02:24:53PM -0600, David Lechner wrote:
>> Fix timestamp alignment when a scan buffer contains an element larger
>> than sizeof(int64_t). Currently s32 quaternions are the only such
>> element, and the one driver that has this (hid-sensor-rotation) has a
>> workaround in place already so this change does not affect it.
>>
>> Previously, we assumed that the timestamp would always be 8-byte aligned
>> relative to the end of the scan buffer, but in the case of a scan buffer
>> a 16-byte quaternion vector, scan_bytes == 32, but the timestamp needs
>> to be placed at offset 16, not 24.
> 
> ...
> 
>> -		((int64_t *)data)[ts_offset] = timestamp;
> 
>> +		*(int64_t *)(data + ts_offset) = timestamp;
> 
> What's the point in modifying this? The comment you added suffice for
> the original line.
> 

ts_offset is now in bytes rather than number of int64_t elements.
So ((int64_t *)data)[ts_offset] would now 8x past the end of the array.

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 4/4] iio: buffer: fix timestamp alignment when quaternion in scan
  2026-03-02 12:04   ` Nuno Sá
@ 2026-03-02 15:42     ` David Lechner
  2026-03-02 20:49       ` Jonathan Cameron
  0 siblings, 1 reply; 19+ messages in thread
From: David Lechner @ 2026-03-02 15:42 UTC (permalink / raw)
  To: Nuno Sá, Jiri Kosina, Jonathan Cameron, Srinivas Pandruvada,
	Nuno Sá, Andy Shevchenko, Lars Möllendorf,
	Lars-Peter Clausen, Greg Kroah-Hartman
  Cc: Jonathan Cameron, Lixu Zhang, linux-input, linux-iio,
	linux-kernel

On 3/2/26 6:04 AM, Nuno Sá wrote:
> On Sun, 2026-03-01 at 14:24 -0600, David Lechner wrote:
>> Fix timestamp alignment when a scan buffer contains an element larger
>> than sizeof(int64_t). Currently s32 quaternions are the only such
>> element, and the one driver that has this (hid-sensor-rotation) has a
>> workaround in place already so this change does not affect it.
>>
>> Previously, we assumed that the timestamp would always be 8-byte aligned
>> relative to the end of the scan buffer, but in the case of a scan buffer
>> a 16-byte quaternion vector, scan_bytes == 32, but the timestamp needs
>> to be placed at offset 16, not 24.
>>
>> Signed-off-by: David Lechner <dlechner@baylibre.com>
>> ---
>>
>> To test this, I used hid-sensor-rotation minus the first patch in the
>> series so that we can see that the timestamp actually moved to the
>> correct location.
>>
>> Before this patch, the timestamp (8 bytes ending with "98 18") is in the
>> wrong location.
>>
>> 00000000  6a 18 00 00 ac f3 ff ff  83 2d 00 00 02 d3 ff ff  |j........-......|
>> 00000010  00 00 00 00 00 00 00 00  5a 17 a0 2a 73 cb 98 18  |........Z..*s...|
>>
>> 00000020  ad 17 00 00 6a f4 ff ff  35 2b 00 00 ca d0 ff ff  |....j...5+......|
>> 00000030  00 00 00 00 00 00 00 00  2a a6 bb 30 73 cb 98 18  |........*..0s...|
>>
>> 00000040  92 1e 00 00 50 ec ff ff  ea c1 ff ff 78 f0 ff ff  |....P.......x...|
>> 00000050  00 00 00 00 00 00 00 00  8f 3b a7 39 77 cb 98 18  |.........;.9w...|
>>
>> After this patch, timestamp is now in the correct location.
>>
>> 00000000  55 0f 00 00 dd 1f 00 00  af 0b 00 00 ec 3e 00 00  |U............>..|
>> 00000010  c7 17 68 42 6d d0 98 18  00 00 00 00 00 00 00 00  |..hBm...........|
>>
>> 00000020  57 0e 00 00 c8 1f 00 00  d1 0e 00 00 42 3e 00 00  |W...........B>..|
>> 00000030  56 a2 87 48 6d d0 98 18  00 00 00 00 00 00 00 00  |V..Hm...........|
>>
>> 00000040  a3 e2 ff ff d3 1b 00 00  0b c9 ff ff cc 20 00 00  |............. ..|
>> 00000050  27 59 4d b3 72 d0 98 18  00 00 00 00 00 00 00 00  |'YM.r...........|
>>
>> I also tested this with a different driver not affected by this bug to
>> make sure that the timestamp is still in the correct location for all
>> other drivers.
>> ---
>>  include/linux/iio/buffer.h | 12 ++++++++++--
>>  1 file changed, 10 insertions(+), 2 deletions(-)
>>
>> diff --git a/include/linux/iio/buffer.h b/include/linux/iio/buffer.h
>> index d37f82678f71..ac19b39bdbe4 100644
>> --- a/include/linux/iio/buffer.h
>> +++ b/include/linux/iio/buffer.h
>> @@ -34,8 +34,16 @@ static inline int iio_push_to_buffers_with_timestamp(struct iio_dev *indio_dev,
>>  	void *data, int64_t timestamp)
>>  {
>>  	if (ACCESS_PRIVATE(indio_dev, scan_timestamp)) {
>> -		size_t ts_offset = indio_dev->scan_bytes / sizeof(int64_t) - 1;
>> -		((int64_t *)data)[ts_offset] = timestamp;
>> +		size_t ts_offset = indio_dev->scan_bytes -
>> +			ACCESS_PRIVATE(indio_dev, largest_scan_element_size);
> 
> Given that we're adding a new private member, maybe we could just directly cache the ts_offset
> in iio_compute_scan_bytes()? Would make the code a bit easier to follow IMHO
> 
> - Nuno Sá
>>

Clever. :-)

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 4/4] iio: buffer: fix timestamp alignment when quaternion in scan
  2026-03-02 15:39     ` David Lechner
@ 2026-03-02 16:03       ` Andy Shevchenko
  0 siblings, 0 replies; 19+ messages in thread
From: Andy Shevchenko @ 2026-03-02 16:03 UTC (permalink / raw)
  To: David Lechner
  Cc: Jiri Kosina, Jonathan Cameron, Srinivas Pandruvada, Nuno Sá,
	Andy Shevchenko, Lars Möllendorf, Lars-Peter Clausen,
	Greg Kroah-Hartman, Jonathan Cameron, Lixu Zhang, linux-input,
	linux-iio, linux-kernel

On Mon, Mar 02, 2026 at 09:39:30AM -0600, David Lechner wrote:
> On 3/2/26 2:47 AM, Andy Shevchenko wrote:
> > On Sun, Mar 01, 2026 at 02:24:53PM -0600, David Lechner wrote:

...

> >> -		((int64_t *)data)[ts_offset] = timestamp;
> > 
> >> +		*(int64_t *)(data + ts_offset) = timestamp;
> > 
> > What's the point in modifying this? The comment you added suffice for
> > the original line.
> 
> ts_offset is now in bytes rather than number of int64_t elements.
> So ((int64_t *)data)[ts_offset] would now 8x past the end of the array.

So semantic of the variable changed w/o name changing... OK.



-- 
With Best Regards,
Andy Shevchenko



^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 3/4] iio: buffer: cache largest scan element size
  2026-03-02 15:35     ` David Lechner
@ 2026-03-02 16:18       ` Nuno Sá
  0 siblings, 0 replies; 19+ messages in thread
From: Nuno Sá @ 2026-03-02 16:18 UTC (permalink / raw)
  To: David Lechner, Jiri Kosina, Jonathan Cameron, Srinivas Pandruvada,
	Nuno Sá, Andy Shevchenko, Lars Möllendorf,
	Lars-Peter Clausen, Greg Kroah-Hartman
  Cc: Jonathan Cameron, Lixu Zhang, linux-input, linux-iio,
	linux-kernel

On Mon, 2026-03-02 at 09:35 -0600, David Lechner wrote:
> On 3/2/26 6:16 AM, Nuno Sá wrote:
> > On Sun, 2026-03-01 at 14:24 -0600, David Lechner wrote:
> > > Cache the largest scan element size of elements enabled in a scan
> > > buffer. This will be used later to ensure proper alignment of the
> > > timestamp element in the scan buffer.
> > > 
> > > The new field could not be placed in struct iio_dev_opaque because we
> > > will need to access it in a static inline function later, so we make it
> > > __private instead. It is only intended to be used by core IIO code.
> > > 
> > > Signed-off-by: David Lechner <dlechner@baylibre.com>
> > > ---
> > >  drivers/iio/industrialio-buffer.c | 14 +++++++++++---
> > >  include/linux/iio/iio.h           |  3 +++
> > >  2 files changed, 14 insertions(+), 3 deletions(-)
> > > 
> > > diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c
> > > index 71dfc81cb9e5..83e9392f949f 100644
> > > --- a/drivers/iio/industrialio-buffer.c
> > > +++ b/drivers/iio/industrialio-buffer.c
> > > @@ -765,7 +765,8 @@ static int iio_storage_bytes_for_timestamp(struct iio_dev *indio_dev)
> > >  
> > >  static int iio_compute_scan_bytes(struct iio_dev *indio_dev,
> > >  				  const unsigned long *mask, bool timestamp,
> > > -				  unsigned int *scan_bytes)
> > > +				  unsigned int *scan_bytes,
> > > +				  unsigned int *largest_element_size)
> > >  {
> > >  	unsigned int bytes = 0;
> > >  	int length, i, largest = 0;
> > > @@ -793,6 +794,9 @@ static int iio_compute_scan_bytes(struct iio_dev *indio_dev,
> > >  
> > >  	*scan_bytes = ALIGN(bytes, largest);
> > >  
> > > +	if (largest_element_size)
> > > +		*largest_element_size = largest;
> > 
> > I might be missing something but it seems we now have two paths:
> > 
> > 1. Go with 32 bytes
> > 2. Go with 24 bytes (natural alignment)
> 
> Hmm... You are right, but we are safe for now because the only repeat is
> a quaternion, which has repeat of 4, so we don't have a case with e.g.
> 24 bytes right now.
> 
> I can do a follow-up to future-proof iio_storage_bytes_for_si() to
> handle repeat = 3 (or any other less likely value).
> 
> Without the repeat, the size is based on .storagebits, and .storagebits /
> BITS_PER_BYTE is always a power of 2, so no problem there.
> 
> > 
> > ABI was not clear so I'm not sure if we do want to enforce/treat repeated values as one single
> > element
> 
> It has always been this way and we had some recent breakage because I didn't
> know about this. This patch series is a direct result of that [1] because we
> identified more bugs when analyzing it.

Hmm true. If we shrink the buffer, userspace expecting timestamps at bit 24 will not work.


- Nuno Sá

> 
> [1]: https://lore.kernel.org/linux-iio/bug-221077-217253@https.bugzilla.kernel.org%2F/
> 
> > If so, nothing to change. But if not, we could re-think the approach and save some bytes. 
> 
> It's too late and breaks usespace as we have seen.
> 
> > Marginal savings though so If having the smaller buffer is not straight enough I would be ok
> > with
> > the simplicity tradeoff.
> > 
> > - Nuno Sá
> > 

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 1/4] iio: orientation: hid-sensor-rotation: add timestamp hack to not break userspace
  2026-03-02 15:18     ` David Lechner
@ 2026-03-02 20:39       ` Jonathan Cameron
  0 siblings, 0 replies; 19+ messages in thread
From: Jonathan Cameron @ 2026-03-02 20:39 UTC (permalink / raw)
  To: David Lechner
  Cc: Andy Shevchenko, Jiri Kosina, Srinivas Pandruvada, Nuno Sá,
	Andy Shevchenko, Lars Möllendorf, Lars-Peter Clausen,
	Greg Kroah-Hartman, Jonathan Cameron, Lixu Zhang, linux-input,
	linux-iio, linux-kernel

On Mon, 2 Mar 2026 09:18:56 -0600
David Lechner <dlechner@baylibre.com> wrote:

> On 3/2/26 2:50 AM, Andy Shevchenko wrote:
> > On Sun, Mar 01, 2026 at 02:24:50PM -0600, David Lechner wrote:  
> >> Add a hack to push two timestamps in the hid-sensor-rotation scan data
> >> to avoid breaking userspace applications that depend on the timestamp
> >> being at the incorrect location in the scan data due to unintentional
> >> misalignment in older kernels.
> >>
> >> When this driver was written, the timestamp was in the correct location
> >> because of the way iio_compute_scan_bytes() was implemented at the time.
> >> (Samples were 24 bytes each.) Then commit 883f61653069 ("iio: buffer:
> >> align the size of scan bytes to size of the largest element") changed
> >> the computed scan_bytes to be a different size (32 bytes), which caused
> >> iio_push_to_buffers_with_timestamp() to place the timestamp at an
> >> incorrect offset.
> >>
> >> There have been long periods of time (6 years each) where the timestamp
> >> was in either location, so to not break either case, we open-code the
> >> timestamps to be pushed to both locations in the scan data.  
> > 
> > ...
> >   
> >> +		/*
> >> +		 * HACK: There are two copies of the same timestamp in case of  
> > 
> > Usually we use FIXME in such cases. HACK is something which goes with
> > "do not apply".
> > 
> > Does it mean it will stay forever?  
> 
> Yes, it will have to stay forever because we can't break userspace.
> 
> My intention here was for HACK to mean "do not copy to another driver".
> 
> 
> If we think that no one is depending on timestamps being in the wrong
> offset, we could omit this change and apply only the rest of the series.
> And then only apply this patch if anyone complains. I am just trying to
> play it safe here and not risk breaking things.

I think it makes sense, but maybe label it something like

ABI regression avoidance: 

Good idea to just keep the wrongly aligned one as it removes the
risk and should do no harm as correct userspace should ignore the
second copy as it's in the padding.

Jonathan



^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 3/4] iio: buffer: cache largest scan element size
  2026-03-01 20:24 ` [PATCH 3/4] iio: buffer: cache largest scan element size David Lechner
  2026-03-02 12:16   ` Nuno Sá
@ 2026-03-02 20:47   ` Jonathan Cameron
  2026-03-02 21:58     ` David Lechner
  1 sibling, 1 reply; 19+ messages in thread
From: Jonathan Cameron @ 2026-03-02 20:47 UTC (permalink / raw)
  To: David Lechner
  Cc: Jiri Kosina, Srinivas Pandruvada, Nuno Sá, Andy Shevchenko,
	Lars Möllendorf, Lars-Peter Clausen, Greg Kroah-Hartman,
	Jonathan Cameron, Lixu Zhang, linux-input, linux-iio,
	linux-kernel

On Sun, 01 Mar 2026 14:24:52 -0600
David Lechner <dlechner@baylibre.com> wrote:

> Cache the largest scan element size of elements enabled in a scan
> buffer. This will be used later to ensure proper alignment of the
> timestamp element in the scan buffer.
Why can't we just stash the start of the timestamp? It's computed
a couple of lines up (or at least it's supposed to be computed there!)

	if (timestamp) {
		length = iio_storage_bytes_for_timestamp(indio_dev);
		if (length < 0)
			return length;

		bytes = ALIGN(bytes, length);

Or is that wrong currently?  If it is we need to fix that logic.

J
> 
> The new field could not be placed in struct iio_dev_opaque because we
> will need to access it in a static inline function later, so we make it
> __private instead. It is only intended to be used by core IIO code.
> 
> Signed-off-by: David Lechner <dlechner@baylibre.com>
> ---
>  drivers/iio/industrialio-buffer.c | 14 +++++++++++---
>  include/linux/iio/iio.h           |  3 +++
>  2 files changed, 14 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c
> index 71dfc81cb9e5..83e9392f949f 100644
> --- a/drivers/iio/industrialio-buffer.c
> +++ b/drivers/iio/industrialio-buffer.c
> @@ -765,7 +765,8 @@ static int iio_storage_bytes_for_timestamp(struct iio_dev *indio_dev)
>  
>  static int iio_compute_scan_bytes(struct iio_dev *indio_dev,
>  				  const unsigned long *mask, bool timestamp,
> -				  unsigned int *scan_bytes)
> +				  unsigned int *scan_bytes,
> +				  unsigned int *largest_element_size)
>  {
>  	unsigned int bytes = 0;
>  	int length, i, largest = 0;
> @@ -793,6 +794,9 @@ static int iio_compute_scan_bytes(struct iio_dev *indio_dev,
>  
>  	*scan_bytes = ALIGN(bytes, largest);
>  
> +	if (largest_element_size)
> +		*largest_element_size = largest;
> +
>  	return 0;
>  }
>  
> @@ -848,7 +852,7 @@ static int iio_buffer_update_bytes_per_datum(struct iio_dev *indio_dev,
>  		return 0;
>  
>  	ret = iio_compute_scan_bytes(indio_dev, buffer->scan_mask,
> -				     buffer->scan_timestamp, &bytes);
> +				     buffer->scan_timestamp, &bytes, NULL);
>  	if (ret)
>  		return ret;
>  
> @@ -892,6 +896,7 @@ struct iio_device_config {
>  	unsigned int watermark;
>  	const unsigned long *scan_mask;
>  	unsigned int scan_bytes;
> +	unsigned int largest_scan_element_size;
>  	bool scan_timestamp;
>  };
>  
> @@ -997,7 +1002,8 @@ static int iio_verify_update(struct iio_dev *indio_dev,
>  	}
>  
>  	ret = iio_compute_scan_bytes(indio_dev, scan_mask, scan_timestamp,
> -				     &config->scan_bytes);
> +				     &config->scan_bytes,
> +				     &config->largest_scan_element_size);
>  	if (ret)
>  		return ret;
>  
> @@ -1155,6 +1161,8 @@ static int iio_enable_buffers(struct iio_dev *indio_dev,
>  	indio_dev->active_scan_mask = config->scan_mask;
>  	ACCESS_PRIVATE(indio_dev, scan_timestamp) = config->scan_timestamp;
>  	indio_dev->scan_bytes = config->scan_bytes;
> +	ACCESS_PRIVATE(indio_dev, largest_scan_element_size) =
> +		config->largest_scan_element_size;
>  	iio_dev_opaque->currentmode = config->mode;
>  
>  	iio_update_demux(indio_dev);
> diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h
> index a9ecff191bd9..85bcb5f8ae15 100644
> --- a/include/linux/iio/iio.h
> +++ b/include/linux/iio/iio.h
> @@ -584,6 +584,8 @@ struct iio_buffer_setup_ops {
>   *			and owner
>   * @buffer:		[DRIVER] any buffer present
>   * @scan_bytes:		[INTERN] num bytes captured to be fed to buffer demux
> + * @largest_scan_element_size: [INTERN] cache of the largest scan element size
> + *			       among the channels selected in the scan mask
>   * @available_scan_masks: [DRIVER] optional array of allowed bitmasks. Sort the
>   *			   array in order of preference, the most preferred
>   *			   masks first.
> @@ -610,6 +612,7 @@ struct iio_dev {
>  
>  	struct iio_buffer		*buffer;
>  	int				scan_bytes;
> +	unsigned int			__private largest_scan_element_size;
>  
>  	const unsigned long		*available_scan_masks;
>  	unsigned int			__private masklength;
> 


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 4/4] iio: buffer: fix timestamp alignment when quaternion in scan
  2026-03-02 15:42     ` David Lechner
@ 2026-03-02 20:49       ` Jonathan Cameron
  0 siblings, 0 replies; 19+ messages in thread
From: Jonathan Cameron @ 2026-03-02 20:49 UTC (permalink / raw)
  To: David Lechner
  Cc: Nuno Sá, Jiri Kosina, Srinivas Pandruvada, Nuno Sá,
	Andy Shevchenko, Lars Möllendorf, Lars-Peter Clausen,
	Greg Kroah-Hartman, Jonathan Cameron, Lixu Zhang, linux-input,
	linux-iio, linux-kernel

On Mon, 2 Mar 2026 09:42:03 -0600
David Lechner <dlechner@baylibre.com> wrote:

> On 3/2/26 6:04 AM, Nuno Sá wrote:
> > On Sun, 2026-03-01 at 14:24 -0600, David Lechner wrote:  
> >> Fix timestamp alignment when a scan buffer contains an element larger
> >> than sizeof(int64_t). Currently s32 quaternions are the only such
> >> element, and the one driver that has this (hid-sensor-rotation) has a
> >> workaround in place already so this change does not affect it.
> >>
> >> Previously, we assumed that the timestamp would always be 8-byte aligned
> >> relative to the end of the scan buffer, but in the case of a scan buffer
> >> a 16-byte quaternion vector, scan_bytes == 32, but the timestamp needs
> >> to be placed at offset 16, not 24.
> >>
> >> Signed-off-by: David Lechner <dlechner@baylibre.com>
> >> ---
> >>
> >> To test this, I used hid-sensor-rotation minus the first patch in the
> >> series so that we can see that the timestamp actually moved to the
> >> correct location.
> >>
> >> Before this patch, the timestamp (8 bytes ending with "98 18") is in the
> >> wrong location.
> >>
> >> 00000000  6a 18 00 00 ac f3 ff ff  83 2d 00 00 02 d3 ff ff  |j........-......|
> >> 00000010  00 00 00 00 00 00 00 00  5a 17 a0 2a 73 cb 98 18  |........Z..*s...|
> >>
> >> 00000020  ad 17 00 00 6a f4 ff ff  35 2b 00 00 ca d0 ff ff  |....j...5+......|
> >> 00000030  00 00 00 00 00 00 00 00  2a a6 bb 30 73 cb 98 18  |........*..0s...|
> >>
> >> 00000040  92 1e 00 00 50 ec ff ff  ea c1 ff ff 78 f0 ff ff  |....P.......x...|
> >> 00000050  00 00 00 00 00 00 00 00  8f 3b a7 39 77 cb 98 18  |.........;.9w...|
> >>
> >> After this patch, timestamp is now in the correct location.
> >>
> >> 00000000  55 0f 00 00 dd 1f 00 00  af 0b 00 00 ec 3e 00 00  |U............>..|
> >> 00000010  c7 17 68 42 6d d0 98 18  00 00 00 00 00 00 00 00  |..hBm...........|
> >>
> >> 00000020  57 0e 00 00 c8 1f 00 00  d1 0e 00 00 42 3e 00 00  |W...........B>..|
> >> 00000030  56 a2 87 48 6d d0 98 18  00 00 00 00 00 00 00 00  |V..Hm...........|
> >>
> >> 00000040  a3 e2 ff ff d3 1b 00 00  0b c9 ff ff cc 20 00 00  |............. ..|
> >> 00000050  27 59 4d b3 72 d0 98 18  00 00 00 00 00 00 00 00  |'YM.r...........|
> >>
> >> I also tested this with a different driver not affected by this bug to
> >> make sure that the timestamp is still in the correct location for all
> >> other drivers.
> >> ---
> >>  include/linux/iio/buffer.h | 12 ++++++++++--
> >>  1 file changed, 10 insertions(+), 2 deletions(-)
> >>
> >> diff --git a/include/linux/iio/buffer.h b/include/linux/iio/buffer.h
> >> index d37f82678f71..ac19b39bdbe4 100644
> >> --- a/include/linux/iio/buffer.h
> >> +++ b/include/linux/iio/buffer.h
> >> @@ -34,8 +34,16 @@ static inline int iio_push_to_buffers_with_timestamp(struct iio_dev *indio_dev,
> >>  	void *data, int64_t timestamp)
> >>  {
> >>  	if (ACCESS_PRIVATE(indio_dev, scan_timestamp)) {
> >> -		size_t ts_offset = indio_dev->scan_bytes / sizeof(int64_t) - 1;
> >> -		((int64_t *)data)[ts_offset] = timestamp;
> >> +		size_t ts_offset = indio_dev->scan_bytes -
> >> +			ACCESS_PRIVATE(indio_dev, largest_scan_element_size);  
> > 
> > Given that we're adding a new private member, maybe we could just directly cache the ts_offset
> > in iio_compute_scan_bytes()? Would make the code a bit easier to follow IMHO
> > 
> > - Nuno Sá  
> >>  
> 
> Clever. :-)
Ah. I should have read on!

J

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH 3/4] iio: buffer: cache largest scan element size
  2026-03-02 20:47   ` Jonathan Cameron
@ 2026-03-02 21:58     ` David Lechner
  0 siblings, 0 replies; 19+ messages in thread
From: David Lechner @ 2026-03-02 21:58 UTC (permalink / raw)
  To: Jonathan Cameron
  Cc: Jiri Kosina, Srinivas Pandruvada, Nuno Sá, Andy Shevchenko,
	Lars Möllendorf, Lars-Peter Clausen, Greg Kroah-Hartman,
	Jonathan Cameron, Lixu Zhang, linux-input, linux-iio,
	linux-kernel

On 3/2/26 2:47 PM, Jonathan Cameron wrote:
> On Sun, 01 Mar 2026 14:24:52 -0600
> David Lechner <dlechner@baylibre.com> wrote:
> 
>> Cache the largest scan element size of elements enabled in a scan
>> buffer. This will be used later to ensure proper alignment of the
>> timestamp element in the scan buffer.
> Why can't we just stash the start of the timestamp?

This is exactly what Nuno suggested. ;-)


^ permalink raw reply	[flat|nested] 19+ messages in thread

end of thread, other threads:[~2026-03-02 21:58 UTC | newest]

Thread overview: 19+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-03-01 20:24 [PATCH 0/4] iio: buffer: fix timestamp alignment (in rare case) David Lechner
2026-03-01 20:24 ` [PATCH 1/4] iio: orientation: hid-sensor-rotation: add timestamp hack to not break userspace David Lechner
2026-03-02  8:50   ` Andy Shevchenko
2026-03-02 15:18     ` David Lechner
2026-03-02 20:39       ` Jonathan Cameron
2026-03-01 20:24 ` [PATCH 2/4] iio: buffer: check return value of iio_compute_scan_bytes() David Lechner
2026-03-01 20:24 ` [PATCH 3/4] iio: buffer: cache largest scan element size David Lechner
2026-03-02 12:16   ` Nuno Sá
2026-03-02 15:35     ` David Lechner
2026-03-02 16:18       ` Nuno Sá
2026-03-02 20:47   ` Jonathan Cameron
2026-03-02 21:58     ` David Lechner
2026-03-01 20:24 ` [PATCH 4/4] iio: buffer: fix timestamp alignment when quaternion in scan David Lechner
2026-03-02  8:47   ` Andy Shevchenko
2026-03-02 15:39     ` David Lechner
2026-03-02 16:03       ` Andy Shevchenko
2026-03-02 12:04   ` Nuno Sá
2026-03-02 15:42     ` David Lechner
2026-03-02 20:49       ` Jonathan Cameron

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox