[PATCH 3/3] hwmon: (sht4x) Fix jiffies wraparound in heater-ready check

From: Tom Verdonck

Date: Fri Sep 25 2026 - 14:24:38 EST


sht4x stores in ->heating_complete the jiffies deadline at which the
current heater pulse finishes. It is set once at probe (to jiffies) and
only updated when the heater is explicitly enabled via sysfs, so in the
common case where the heater is never used it stays frozen at its probe
value.

->heating_complete is an unsigned long compared with time_before(),
whose signed difference is only meaningful while the two values are
within LONG_MAX jiffies of each other. Because the deadline is frozen,
jiffies keeps advancing away from it, and after 2^31 jiffies the
difference flips sign. On a 32-bit HZ=100 kernel that happens ~248.5
days after boot. time_before() in sht4x_read_values() then wrongly
reports that heating is still in progress and the read path executes

msleep(jiffies_to_msecs(data->heating_complete - curr_jiffies));

with a bogus, huge delta, blocking the temperature read for a very long
time instead of returning data. The heater_enable sysfs attributes are
affected the same way (spurious -EBUSY and "1" readback).

Store the deadline as a 64-bit jiffies value and compare it with
get_jiffies_64()/time_before64(), which does not wrap in any practical
uptime.

Fixes: 0eed6fc3d2b9 ("hwmon: (sht4x): add heater support")
Cc: stable@xxxxxxxxxxxxxxx
Signed-off-by: Tom Verdonck <tom.verdonck@xxxxxxxxxxx>
---
drivers/hwmon/sht4x.c | 18 +++++++++---------
1 file changed, 9 insertions(+), 9 deletions(-)

diff --git a/drivers/hwmon/sht4x.c b/drivers/hwmon/sht4x.c
index a97dda9e92dc..da2b6130fca7 100644
--- a/drivers/hwmon/sht4x.c
+++ b/drivers/hwmon/sht4x.c
@@ -67,7 +67,7 @@ DECLARE_CRC8_TABLE(sht4x_crc8_table);
*/
struct sht4x_data {
struct i2c_client *client;
- unsigned long heating_complete; /* in jiffies */
+ u64 heating_complete; /* in jiffies */
bool data_pending;
u32 heater_power; /* in milli-watts */
u32 heater_time; /* in milli-seconds */
@@ -92,14 +92,14 @@ static int sht4x_read_values(struct sht4x_data *data)
u8 crc;
u8 cmd[SHT4X_CMD_LEN] = {SHT4X_CMD_MEASURE_HPM};
u8 raw_data[SHT4X_RESPONSE_LENGTH];
- unsigned long curr_jiffies;
+ u64 curr_jiffies;

- curr_jiffies = jiffies;
- if (time_before(curr_jiffies, data->heating_complete))
+ curr_jiffies = get_jiffies_64();
+ if (time_before64(curr_jiffies, data->heating_complete))
msleep(jiffies_to_msecs(data->heating_complete - curr_jiffies));

if (data->data_pending &&
- time_before(jiffies, data->heating_complete + data->update_interval)) {
+ time_before64(get_jiffies_64(), data->heating_complete + data->update_interval)) {
data->data_pending = false;
} else {
next_update = data->last_updated +
@@ -237,7 +237,7 @@ static ssize_t heater_enable_show(struct device *dev,
{
struct sht4x_data *data = dev_get_drvdata(dev);

- return sysfs_emit(buf, "%u\n", time_before(jiffies, data->heating_complete));
+ return sysfs_emit(buf, "%u\n", time_before64(get_jiffies_64(), data->heating_complete));
}

static ssize_t heater_enable_store(struct device *dev,
@@ -279,14 +279,14 @@ static ssize_t heater_enable_store(struct device *dev,

guard(hwmon_lock)(dev);

- if (time_before(jiffies, data->heating_complete))
+ if (time_before64(get_jiffies_64(), data->heating_complete))
return -EBUSY;

ret = i2c_master_send(data->client, &cmd, SHT4X_CMD_LEN);
if (ret < 0)
return ret;

- data->heating_complete = jiffies + msecs_to_jiffies(heating_time_bound);
+ data->heating_complete = get_jiffies_64() + msecs_to_jiffies(heating_time_bound);
data->data_pending = true;
return count;
}
@@ -410,7 +410,7 @@ static int sht4x_probe(struct i2c_client *client)
data->client = client;
data->heater_power = 200;
data->heater_time = 1000;
- data->heating_complete = jiffies;
+ data->heating_complete = get_jiffies_64();

crc8_populate_msb(sht4x_crc8_table, SHT4X_CRC8_POLYNOMIAL);

--
2.53.0