[PATCH v2 4/4] hwmon: ltc2945: Fix possible overflows

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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



[Index of Archives]     [Device Tree Compilter]     [Device Tree Spec]     [Linux Driver Backports]     [Video for Linux]     [Linux USB Devel]     [Linux PCI Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [XFree86]     [Yosemite Backpacking]


  Powered by Linux