Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

hwmon: (tmp513) Fix division of negative numbers

Fix several issues with division of negative numbers in the tmp513
driver.

The docs on the DIV_ROUND_CLOSEST macro explain that dividing a negative
value by an unsigned type is undefined behavior. The driver was doing
this in several places, i.e. data->shunt_uohms has type of u32. The
actual "undefined" behavior is that it converts both values to unsigned
before doing the division, for example:

int ret = DIV_ROUND_CLOSEST(-100, 3U);

results in ret == 1431655732 instead of -33.

Furthermore the MILLI macro has a type of unsigned long. Multiplying a
signed long by an unsigned long results in an unsigned long.

So, we need to cast both MILLI and data data->shunt_uohms to long when
using the DIV_ROUND_CLOSEST macro.

Fixes: f07f9d2467f4 ("hwmon: (tmp513) Use SI constants from units.h")
Fixes: 59dfa75e5d82 ("hwmon: Add driver for Texas Instruments TMP512/513 sensor chips.")
Signed-off-by: David Lechner <dlechner@baylibre.com>
Link: https://lore.kernel.org/r/20250114-fix-si-prefix-macro-sign-bugs-v1-1-696fd8d10f00@baylibre.com
[groeck: Drop some continuation lines]
Signed-off-by: Guenter Roeck <linux@roeck-us.net>

authored by

David Lechner and committed by
Guenter Roeck
e2c68cea 5bc55a33

+4 -3
+4 -3
drivers/hwmon/tmp513.c
··· 207 207 *val = sign_extend32(regval, 208 208 reg == TMP51X_SHUNT_CURRENT_RESULT ? 209 209 16 - tmp51x_get_pga_shift(data) : 15); 210 - *val = DIV_ROUND_CLOSEST(*val * 10 * MILLI, data->shunt_uohms); 210 + *val = DIV_ROUND_CLOSEST(*val * 10 * (long)MILLI, (long)data->shunt_uohms); 211 + 211 212 break; 212 213 case TMP51X_BUS_VOLTAGE_RESULT: 213 214 case TMP51X_BUS_VOLTAGE_H_LIMIT: ··· 224 223 case TMP51X_BUS_CURRENT_RESULT: 225 224 // Current = (ShuntVoltage * CalibrationRegister) / 4096 226 225 *val = sign_extend32(regval, 15) * (long)data->curr_lsb_ua; 227 - *val = DIV_ROUND_CLOSEST(*val, MILLI); 226 + *val = DIV_ROUND_CLOSEST(*val, (long)MILLI); 228 227 break; 229 228 case TMP51X_LOCAL_TEMP_RESULT: 230 229 case TMP51X_REMOTE_TEMP_RESULT_1: ··· 264 263 * The user enter current value and we convert it to 265 264 * voltage. 1lsb = 10uV 266 265 */ 267 - val = DIV_ROUND_CLOSEST(val * data->shunt_uohms, 10 * MILLI); 266 + val = DIV_ROUND_CLOSEST(val * (long)data->shunt_uohms, 10 * (long)MILLI); 268 267 max_val = U16_MAX >> tmp51x_get_pga_shift(data); 269 268 regval = clamp_val(val, -max_val, max_val); 270 269 break;