mirror of https://github.com/torvalds/linux.git
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: f07f9d2467 ("hwmon: (tmp513) Use SI constants from units.h")
Fixes: 59dfa75e5d ("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>
This commit is contained in:
parent
5bc55a333a
commit
e2c68cea43
|
|
@ -207,7 +207,8 @@ static int tmp51x_get_value(struct tmp51x_data *data, u8 reg, u8 pos,
|
||||||
*val = sign_extend32(regval,
|
*val = sign_extend32(regval,
|
||||||
reg == TMP51X_SHUNT_CURRENT_RESULT ?
|
reg == TMP51X_SHUNT_CURRENT_RESULT ?
|
||||||
16 - tmp51x_get_pga_shift(data) : 15);
|
16 - tmp51x_get_pga_shift(data) : 15);
|
||||||
*val = DIV_ROUND_CLOSEST(*val * 10 * MILLI, data->shunt_uohms);
|
*val = DIV_ROUND_CLOSEST(*val * 10 * (long)MILLI, (long)data->shunt_uohms);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case TMP51X_BUS_VOLTAGE_RESULT:
|
case TMP51X_BUS_VOLTAGE_RESULT:
|
||||||
case TMP51X_BUS_VOLTAGE_H_LIMIT:
|
case TMP51X_BUS_VOLTAGE_H_LIMIT:
|
||||||
|
|
@ -223,7 +224,7 @@ static int tmp51x_get_value(struct tmp51x_data *data, u8 reg, u8 pos,
|
||||||
case TMP51X_BUS_CURRENT_RESULT:
|
case TMP51X_BUS_CURRENT_RESULT:
|
||||||
// Current = (ShuntVoltage * CalibrationRegister) / 4096
|
// Current = (ShuntVoltage * CalibrationRegister) / 4096
|
||||||
*val = sign_extend32(regval, 15) * (long)data->curr_lsb_ua;
|
*val = sign_extend32(regval, 15) * (long)data->curr_lsb_ua;
|
||||||
*val = DIV_ROUND_CLOSEST(*val, MILLI);
|
*val = DIV_ROUND_CLOSEST(*val, (long)MILLI);
|
||||||
break;
|
break;
|
||||||
case TMP51X_LOCAL_TEMP_RESULT:
|
case TMP51X_LOCAL_TEMP_RESULT:
|
||||||
case TMP51X_REMOTE_TEMP_RESULT_1:
|
case TMP51X_REMOTE_TEMP_RESULT_1:
|
||||||
|
|
@ -263,7 +264,7 @@ static int tmp51x_set_value(struct tmp51x_data *data, u8 reg, long val)
|
||||||
* The user enter current value and we convert it to
|
* The user enter current value and we convert it to
|
||||||
* voltage. 1lsb = 10uV
|
* voltage. 1lsb = 10uV
|
||||||
*/
|
*/
|
||||||
val = DIV_ROUND_CLOSEST(val * data->shunt_uohms, 10 * MILLI);
|
val = DIV_ROUND_CLOSEST(val * (long)data->shunt_uohms, 10 * (long)MILLI);
|
||||||
max_val = U16_MAX >> tmp51x_get_pga_shift(data);
|
max_val = U16_MAX >> tmp51x_get_pga_shift(data);
|
||||||
regval = clamp_val(val, -max_val, max_val);
|
regval = clamp_val(val, -max_val, max_val);
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue