From: John Pruitt <jpruitt@xxxxxxxxxxxxxxxx> Use 64-bit values for intermediate calculations. Check for overflows and return INT_MAX if overflows happened. Signed-off-by: John Pruitt <jpruitt@xxxxxxxxxxxxxxxx> Signed-off-by: "Cormier, Jonathan" <jcormier@xxxxxxxxxxxxxxxx> --- drivers/hwmon/ltc2945.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/drivers/hwmon/ltc2945.c b/drivers/hwmon/ltc2945.c index fc7d399b2c85..7239422fc6db 100644 --- a/drivers/hwmon/ltc2945.c +++ b/drivers/hwmon/ltc2945.c @@ -126,6 +126,10 @@ static long long ltc2945_reg_to_val(struct device *dev, u8 reg) } val *= 1000; val = DIV_ROUND_CLOSEST_ULL(val, shunt_resistor); + /* check for overflow, use MAX value if it happened */ + if (val > INT_MAX) + val = INT_MAX; + break; case LTC2945_VIN_H: case LTC2945_MAX_VIN_H: @@ -159,12 +163,14 @@ static long long ltc2945_reg_to_val(struct device *dev, u8 reg) } static int ltc2945_val_to_reg(struct device *dev, u8 reg, - unsigned long val) + unsigned long val_32) { struct ltc2945_data *data = dev_get_drvdata(dev); struct regmap *regmap = data->regmap; u32 shunt_resistor = data->shunt_resistor; unsigned int control; + /* use 64-bit val for intermediate calculations */ + unsigned long long val = val_32; int ret; switch (reg) { @@ -184,7 +190,7 @@ static int ltc2945_val_to_reg(struct device *dev, u8 reg, if (control & CONTROL_MULT_SELECT) { /* 25 mV * 25 uV = 0.625 uV resolution. */ val *= shunt_resistor; - val = DIV_ROUND_CLOSEST(val, 625 * 1000); + val = DIV_ROUND_CLOSEST_ULL(val, 625LL * 1000LL); } else { /* * 0.5 mV * 25 uV = 0.0125 uV resolution. @@ -192,7 +198,7 @@ static int ltc2945_val_to_reg(struct device *dev, u8 reg, * accept loss of accuracy. */ val *= shunt_resistor; - val = DIV_ROUND_CLOSEST(val, 25 * 1000) * 2; + val = DIV_ROUND_CLOSEST_ULL(val, 25LL * 1000LL) * 2; } break; case LTC2945_VIN_H: @@ -201,7 +207,7 @@ static int ltc2945_val_to_reg(struct device *dev, u8 reg, case LTC2945_MAX_VIN_THRES_H: case LTC2945_MIN_VIN_THRES_H: /* 25 mV resolution. */ - val /= 25; + val = DIV_ROUND_CLOSEST_ULL(val, 25LL); break; case LTC2945_ADIN_H: case LTC2945_MAX_ADIN_H: @@ -218,11 +224,15 @@ static int ltc2945_val_to_reg(struct device *dev, u8 reg, case LTC2945_MIN_SENSE_THRES_H: /* 25 uV resolution. Convert to mA. */ val *= shunt_resistor; - val = DIV_ROUND_CLOSEST(val, 25 * 1000); + val = DIV_ROUND_CLOSEST_ULL(val, 25LL * 1000LL); break; default: return -EINVAL; } + /* If val is too large, just return the max value */ + if (val > INT_MAX) + return INT_MAX; + return val; } -- 2.25.1