FAILED: patch "[PATCH] iio: common: st_sensors: honour channel endianness in" failed to apply to 6.6-stable tree
Subsystems (2)
[email protected]
maintainerThe patch below does not apply to the 6.6-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
To reproduce the conflict and resubmit, you may use the following commands:
git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-6.6.y
git checkout FETCH_HEAD
git cherry-pick -x 55052184ac9011db2ea983e54d6c21f0b1079a12
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '2026071348-glorify-lapel-3161@gregkh' --subject-prefix 'PATCH 6.6.y' 'HEAD^..'
Possible dependencies:
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From 55052184ac9011db2ea983e54d6c21f0b1079a12 Mon Sep 17 00:00:00 2001
From: Herman van Hazendonk <[email protected]>
Date: Tue, 16 Jun 2026 15:02:04 +0200
Subject: [PATCH] iio: common: st_sensors: honour channel endianness in
read_axis_data
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
st_sensors_read_axis_data() unconditionally decoded multi-byte results with get_unaligned_le16() / get_unaligned_le24() regardless of the channel's declared scan_type.endianness.
For every ST sensor that has used this helper since it was introduced this happened to be fine because the ST IMU/accel/gyro/pressure families publish their data registers as little-endian and the channel specs in those drivers declare IIO_LE accordingly.
The LSM303DLH magnetometer however publishes its X/Y/Z output as a pair of big-endian bytes (the H register sits at the lower address, 0x03/0x05/0x07, and the L register immediately after), and its channel specs in st_magn_core.c correctly declare IIO_BE -- but read_axis_data() ignored that and decoded as little-endian, swapping the high and low bytes of every magnetometer sample. The LSM303DLHC and LSM303DLM share the same st_magn_16bit_channels (IIO_BE) and were therefore byte-swapped by the same bug; users of those parts will see different in_magn_*_raw values after this fix lands.
The bug is most visible on a stationary chip: in earth's field the true X reading is small and the high byte sits at 0x00, so swapping the bytes pins sysfs X at exactly the low byte's pattern (e.g. 0x00F0 = 240). Y and Z still appear "to vary" because their magnitudes are larger and the noise in the low byte produces big swings in the swapped high byte:
before (LSM303DLH flat, sysfs in_magn_*_raw):
X=240 (stuck), Y= 12032..23296, Z=-16128..-9728
after (direct i2c-dev big-endian decode, same chip same orientation):
X≈-4096, Y≈210, Z≈80 (sensible values reflecting earth's
ambient field at low gauss range)
Fix read_axis_data() to dispatch on ch->scan_type.endianness and call get_unaligned_be16() / get_unaligned_be24() when the channel declares IIO_BE. Existing IIO_LE consumers (st_accel, st_gyro, st_pressure, st_lsm6dsx and others) are unaffected because their channel specs already declare IIO_LE and the LE path is unchanged.
While restructuring the branches, replace the previously implicit silent-success-with-uninitialised-*data fall-through for byte_for_channel outside 1..3 with an explicit return -EINVAL. No in-tree ST sensor publishes such a channel, but the new behaviour is strictly safer than handing userspace garbage.
drivers/iio/common/st_sensors/st_sensors_core.c +17 -6
@@ -498,6 +498,7 @@ static int st_sensors_read_axis_data(struct iio_dev *indio_dev,u8 *outdata;struct st_sensor_data *sdata =iio_priv (indio_dev);unsigned int byte_for_channel; +u32 tmp; byte_for_channel =DIV_ROUND_UP (ch->scan_type.realbits + ch->scan_type.shift,8 );
@@ -508,12 +509,22 @@ static int st_sensors_read_axis_data(struct iio_dev *indio_dev,if (err <0 )return err; -if (byte_for_channel ==1 ) - *data = (s8)*outdata; -else if (byte_for_channel ==2 ) - *data = (s16 )get_unaligned_le16 (outdata); -else if (byte_for_channel ==3 ) - *data = (s32 )sign_extend32 (get_unaligned_le24 (outdata),23 ); +if (byte_for_channel ==1 ) { + tmp = *outdata; + }else if (byte_for_channel ==2 ) { +if (ch->scan_type.endianness ==IIO_BE ) + tmp =get_unaligned_be16 (outdata); +else + tmp =get_unaligned_le16 (outdata); + }else if (byte_for_channel ==3 ) { +if (ch->scan_type.endianness ==IIO_BE ) + tmp =get_unaligned_be24 (outdata); +else + tmp =get_unaligned_le24 (outdata); + }else { +return -EINVAL ; + } + *data =sign_extend32 (tmp,BYTES_TO_BITS (byte_for_channel) -1 );return 0 ; }
Sasha Levin
maintainerPATCH 1/2 bitops: make BYTES_TO_BITS() treewide-available
From: Alexander Lobakin <[email protected]>
[ Upstream commit 7d8296b250f2eed73f1758607926d4d258dea5d4 ]
Avoid open-coding that simple expression each time by moving BYTES_TO_BITS() from the probes code to <linux/bitops.h> to export it to the rest of the kernel.
Simplify the macro while at it. BITS_PER_LONG / sizeof(long) always equals to %BITS_PER_BYTE, regardless of the target architecture. Do the same for the tools ecosystem as well (incl. its version of bitops.h). The previous implementation had its implicit type of long, while the new one is int, so adjust the format literal accordingly in the perf code.
Stable-dep-of: 55052184ac90 ("iio: common: st_sensors: honour channel endianness in read_axis_data")
--- include/linux/bitops.h | 2 ++ kernel/trace/trace_probe.c | 2 -- tools/include/linux/bitops.h | 2 ++ tools/perf/util/probe-finder.c | 4 +--- 4 files changed, 5 insertions(+), 5 deletions(-)
include/linux/bitops.h +2 -0
@@ -20,6 +20,8 @@#define BITS_TO_U32 (nr) __KERNEL_DIV_ROUND_UP(nr, BITS_PER_TYPE(u32))#define BITS_TO_BYTES (nr) __KERNEL_DIV_ROUND_UP(nr, BITS_PER_TYPE(char)) +#define BYTES_TO_BITS (nb) ((nb) * BITS_PER_BYTE) +extern unsigned int __sw_hweight8 (unsigned int w);extern unsigned int __sw_hweight16 (unsigned int w);extern unsigned int __sw_hweight32 (unsigned int w);
kernel/trace/trace_probe.c +0 -2
@@ -1219,8 +1219,6 @@ parse_probe_arg(char *arg, const struct fetch_type *type,return ret; } -#define BYTES_TO_BITS (nb) ((BITS_PER_LONG * (nb)) / sizeof(long)) -/* Bitfield type needs to be parsed into a fetch function */ static int __parse_bitfield_probe_arg(const char *bf, const struct fetch_type *t,
tools/include/linux/bitops.h +2 -0
@@ -20,6 +20,8 @@#define BITS_TO_U32 (nr) DIV_ROUND_UP(nr, BITS_PER_TYPE(u32))#define BITS_TO_BYTES (nr) DIV_ROUND_UP(nr, BITS_PER_TYPE(char)) +#define BYTES_TO_BITS (nb) ((nb) * BITS_PER_BYTE) +extern unsigned int __sw_hweight8 (unsigned int w);extern unsigned int __sw_hweight16 (unsigned int w);extern unsigned int __sw_hweight32 (unsigned int w);
tools/perf/util/probe-finder.c +1 -3
@@ -304,8 +304,6 @@ static int convert_variable_location(Dwarf_Die *vr_die, Dwarf_Addr addr,return ret2; } -#define BYTES_TO_BITS (nb) ((nb) * BITS_PER_LONG / sizeof(long)) -static int convert_variable_type (Dwarf_Die *vr_die,struct probe_trace_arg *tvar,const char *cast,bool user_access)
@@ -335,7 +333,7 @@ static int convert_variable_type(Dwarf_Die *vr_die, total =dwarf_bytesize (vr_die);if (boffs <0 || total <0 )return -ENOENT ; - ret =snprintf (buf,16 ,"b%d@%d/%zd" , bsize, boffs, + ret =snprintf (buf,16 ,"b%d@%d/%d" , bsize, boffs,BYTES_TO_BITS (total)); goto formatted; }
Signature · 1 line
2.53.0
Sasha Levin
maintainerPATCH 2/2 iio: common: st_sensors: honour channel endianness in read_axis_data
From: Herman van Hazendonk <[email protected]>
[ Upstream commit 55052184ac9011db2ea983e54d6c21f0b1079a12 ]
st_sensors_read_axis_data() unconditionally decoded multi-byte results with get_unaligned_le16() / get_unaligned_le24() regardless of the channel's declared scan_type.endianness.
For every ST sensor that has used this helper since it was introduced this happened to be fine because the ST IMU/accel/gyro/pressure families publish their data registers as little-endian and the channel specs in those drivers declare IIO_LE accordingly.
The LSM303DLH magnetometer however publishes its X/Y/Z output as a pair of big-endian bytes (the H register sits at the lower address, 0x03/0x05/0x07, and the L register immediately after), and its channel specs in st_magn_core.c correctly declare IIO_BE -- but read_axis_data() ignored that and decoded as little-endian, swapping the high and low bytes of every magnetometer sample. The LSM303DLHC and LSM303DLM share the same st_magn_16bit_channels (IIO_BE) and were therefore byte-swapped by the same bug; users of those parts will see different in_magn_*_raw values after this fix lands.
The bug is most visible on a stationary chip: in earth's field the true X reading is small and the high byte sits at 0x00, so swapping the bytes pins sysfs X at exactly the low byte's pattern (e.g. 0x00F0 = 240). Y and Z still appear "to vary" because their magnitudes are larger and the noise in the low byte produces big swings in the swapped high byte:
before (LSM303DLH flat, sysfs in_magn_*_raw):
X=240 (stuck), Y= 12032..23296, Z=-16128..-9728
after (direct i2c-dev big-endian decode, same chip same orientation):
X≈-4096, Y≈210, Z≈80 (sensible values reflecting earth's
ambient field at low gauss range)
Fix read_axis_data() to dispatch on ch->scan_type.endianness and call get_unaligned_be16() / get_unaligned_be24() when the channel declares IIO_BE. Existing IIO_LE consumers (st_accel, st_gyro, st_pressure, st_lsm6dsx and others) are unaffected because their channel specs already declare IIO_LE and the LE path is unchanged.
While restructuring the branches, replace the previously implicit silent-success-with-uninitialised-*data fall-through for byte_for_channel outside 1..3 with an explicit return -EINVAL. No in-tree ST sensor publishes such a channel, but the new behaviour is strictly safer than handing userspace garbage.
--- .../iio/common/st_sensors/st_sensors_core.c | 23 ++++++++++++++----- 1 file changed, 17 insertions(+), 6 deletions(-)
drivers/iio/common/st_sensors/st_sensors_core.c +17 -6
@@ -498,6 +498,7 @@ static int st_sensors_read_axis_data(struct iio_dev *indio_dev,u8 *outdata;struct st_sensor_data *sdata =iio_priv (indio_dev);unsigned int byte_for_channel; +u32 tmp; byte_for_channel =DIV_ROUND_UP (ch->scan_type.realbits + ch->scan_type.shift,8 );
@@ -510,12 +511,22 @@ static int st_sensors_read_axis_data(struct iio_dev *indio_dev,if (err <0 ) goto st_sensors_free_memory; -if (byte_for_channel ==1 ) - *data = (s8)*outdata; -else if (byte_for_channel ==2 ) - *data = (s16 )get_unaligned_le16 (outdata); -else if (byte_for_channel ==3 ) - *data = (s32 )sign_extend32 (get_unaligned_le24 (outdata),23 ); +if (byte_for_channel ==1 ) { + tmp = *outdata; + }else if (byte_for_channel ==2 ) { +if (ch->scan_type.endianness ==IIO_BE ) + tmp =get_unaligned_be16 (outdata); +else + tmp =get_unaligned_le16 (outdata); + }else if (byte_for_channel ==3 ) { +if (ch->scan_type.endianness ==IIO_BE ) + tmp =get_unaligned_be24 (outdata); +else + tmp =get_unaligned_le24 (outdata); + }else { +return -EINVAL ; + } + *data =sign_extend32 (tmp,BYTES_TO_BITS (byte_for_channel) -1 ); st_sensors_free_memory:kfree (outdata);
Signature · 1 line
2.53.0