iio: imu: adis16400: Fix buffer alignment requirements.
authorJonathan Cameron <Jonathan.Cameron@huawei.com>
Sun, 13 Jun 2021 15:10:39 +0000 (16:10 +0100)
committerJonathan Cameron <Jonathan.Cameron@huawei.com>
Tue, 19 Oct 2021 07:29:22 +0000 (08:29 +0100)
iio_push_to_buffers_with_timestamp() requires that the buffer
is 8 byte alignment to ensure an inserted timestamp is naturally aligned.

This requirement was not met here when burst mode is in use beause
of a leading u16. Use the new iio_push_to_buffers_with_ts_unaligned()
function that has more relaxed requirements.

It is somewhat complex to access that actual data length, but a
safe bound can be found by using scan_bytes - sizeof(timestamp) so that
is used in this path.

More efficient approaches exist, but this ensure correctness at the
cost of using a bounce buffer.

Fixes: 5075e0720d93 ("iio: imu: adis: generalize burst mode support")
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Reviewed-by: Nuno Sá <nuno.sa@analog.com>
Link: https://lore.kernel.org/r/20210613151039.569883-5-jic23@kernel.org
drivers/iio/imu/adis16400.c

index b12917a..9fd30e6 100644 (file)
@@ -641,13 +641,23 @@ static irqreturn_t adis16400_trigger_handler(int irq, void *p)
        if (ret)
                dev_err(&adis->spi->dev, "Failed to read data: %d\n", ret);
 
-       if (st->variant->flags & ADIS16400_BURST_DIAG_STAT)
+       if (st->variant->flags & ADIS16400_BURST_DIAG_STAT) {
                buffer = adis->buffer + sizeof(u16);
-       else
-               buffer = adis->buffer;
+               /*
+                * The size here is always larger than, or equal to the true
+                * size of the channel data. This may result in a larger copy
+                * than necessary, but as the target buffer will be
+                * buffer->scan_bytes this will be safe.
+                */
+               iio_push_to_buffers_with_ts_unaligned(indio_dev, buffer,
+                                                     indio_dev->scan_bytes - sizeof(pf->timestamp),
+                                                     pf->timestamp);
+       } else {
+               iio_push_to_buffers_with_timestamp(indio_dev,
+                                                  adis->buffer,
+                                                  pf->timestamp);
+       }
 
-       iio_push_to_buffers_with_timestamp(indio_dev, buffer,
-               pf->timestamp);
 
        iio_trigger_notify_done(indio_dev->trig);