From ce3ff350c4a3b9466bd67bfe2adb2e3bea732b9e Mon Sep 17 00:00:00 2001 From: Tom Verdonck Date: Fri, 25 Sep 2026 20:23:24 +0200 Subject: [PATCH] hwmon: (sht4x) Fix jiffies wraparound in heater-ready check 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@vger.kernel.org Signed-off-by: Tom Verdonck Link: https://patch.msgid.link/7b2087ccb963e097cf3f6333efaec0c46549003b.1790358356.git.tom.verdonck@inspiral.be [groeck: Squashed 'Fix torn read' patch into this one] Signed-off-by: Guenter Roeck --- drivers/hwmon/sht4x.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/drivers/hwmon/sht4x.c b/drivers/hwmon/sht4x.c index a97dda9e92dc..27fddff70354 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,9 @@ 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)); + guard(hwmon_lock)(dev); + + 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 +281,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 +412,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);