Skip to contentSkip to conversation

pmbus: core: Use 64-bit ints for returned sensor values

PATCH In review Eddie James 2 participants 3 messages May 11, 2018 – May 17, 2018 Hardware monitoring

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 pmbus: core: Use 64-bit ints for returned sensor values

It's possible to overflow sensor values, especially for power sensors reporting micro Watts. Use 64-bit values to prevent overflow.

---
 drivers/hwmon/pmbus/pmbus_core.c | 33 +++++++++++++++++----------------
 1 file changed, 17 insertions(+), 16 deletions(-)
drivers/hwmon/pmbus/pmbus_core.c +17 -16
index d0ffa4b..4957243 100644
@@ -629,12 +629,12 @@ static struct pmbus_data *pmbus_update_device(struct device *dev)
  * Convert linear sensor values to milli- or micro-units
  * depending on sensor type.
  */
-static long pmbus_reg2data_linear(struct pmbus_data *data,
-				  struct pmbus_sensor *sensor)
+static s64 pmbus_reg2data_linear(struct pmbus_data *data,
+				 struct pmbus_sensor *sensor)
 {
 	s16 exponent;
 	s32 mantissa;
-	long val;
+	s64 val;
 
 	if (sensor->class == PSC_VOLTAGE_OUT) {	/* LINEAR16 */
 		exponent = data->exponent[sensor->page];
@@ -648,11 +648,11 @@ static long pmbus_reg2data_linear(struct pmbus_data *data,
 
 	/* scale result to milli-units for all sensors except fans */
 	if (sensor->class != PSC_FAN)
-		val = val * 1000L;
+		val = val * 1000LL;
 
 	/* scale result to micro-units for power sensors */
 	if (sensor->class == PSC_POWER)
-		val = val * 1000L;
+		val = val * 1000LL;
 
 	if (exponent >= 0)
 		val <<= exponent;
@@ -666,10 +666,10 @@ static long pmbus_reg2data_linear(struct pmbus_data *data,
  * Convert direct sensor values to milli- or micro-units
  * depending on sensor type.
  */
-static long pmbus_reg2data_direct(struct pmbus_data *data,
-				  struct pmbus_sensor *sensor)
+static s64 pmbus_reg2data_direct(struct pmbus_data *data,
+				 struct pmbus_sensor *sensor)
 {
-	long val = (s16) sensor->data;
+	s64 val = sensor->data;
 	long m, b, R;
 
 	m = data->info->m[sensor->class];
@@ -694,23 +694,24 @@ static long pmbus_reg2data_direct(struct pmbus_data *data,
 	}
 
 	while (R > 0) {
-		val *= 10;
+		val *= 10LL;
 		R--;
 	}
 	while (R < 0) {
-		val = DIV_ROUND_CLOSEST(val, 10);
+		val = DIV_ROUND_CLOSEST_ULL(val, 10);
 		R++;
 	}
 
-	return (val - b) / m;
+	val -= b;
+	return do_div(val, m);
 }
 
 /*
  * Convert VID sensor values to milli- or micro-units
  * depending on sensor type.
  */
-static long pmbus_reg2data_vid(struct pmbus_data *data,
-			       struct pmbus_sensor *sensor)
+static s64 pmbus_reg2data_vid(struct pmbus_data *data,
+			      struct pmbus_sensor *sensor)
 {
 	long val = sensor->data;
 	long rv = 0;
@@ -728,9 +729,9 @@ static long pmbus_reg2data_vid(struct pmbus_data *data,
 	return rv;
 }
 
-static long pmbus_reg2data(struct pmbus_data *data, struct pmbus_sensor *sensor)
+static s64 pmbus_reg2data(struct pmbus_data *data, struct pmbus_sensor *sensor)
 {
-	long val;
+	s64 val;
 
 	if (!sensor->convert)
 		return sensor->data;
@@ -968,7 +969,7 @@ static ssize_t pmbus_show_sensor(struct device *dev,
 	if (sensor->data < 0)
 		return sensor->data;
 
-	return snprintf(buf, PAGE_SIZE, "%ld\n", pmbus_reg2data(data, sensor));
+	return snprintf(buf, PAGE_SIZE, "%lld\n", pmbus_reg2data(data, sensor));
 }
 
 static ssize_t pmbus_set_sensor(struct device *dev,
Signature · 1 line
1.8.3.1
#1 lore raw
Quoted 2 lines · Eddie James

It's possible to overflow sensor values, especially for power sensors reporting micro Watts. Use 64-bit values to prevent overflow.

Cancel that. This has been fixed in linux-next with bd467e4eababe4c04272c1e646f066db02734c79

I'll port it to dev-4.13

Thanks,
Eddie

Quoted 105 lines
---
  drivers/hwmon/pmbus/pmbus_core.c | 33 +++++++++++++++++----------------
  1 file changed, 17 insertions(+), 16 deletions(-)
drivers/hwmon/pmbus/pmbus_core.c +17 -16
index d0ffa4b..4957243 100644
@@ -629,12 +629,12 @@ static struct pmbus_data *pmbus_update_device(struct device *dev)
   * Convert linear sensor values to milli- or micro-units
   * depending on sensor type.
   */
-static long pmbus_reg2data_linear(struct pmbus_data *data,
-				  struct pmbus_sensor *sensor)
+static s64 pmbus_reg2data_linear(struct pmbus_data *data,
+				 struct pmbus_sensor *sensor)
  {
  	s16 exponent;
  	s32 mantissa;
-	long val;
+	s64 val;
 
  	if (sensor->class == PSC_VOLTAGE_OUT) {	/* LINEAR16 */
  		exponent = data->exponent[sensor->page];
@@ -648,11 +648,11 @@ static long pmbus_reg2data_linear(struct pmbus_data *data,
 
  	/* scale result to milli-units for all sensors except fans */
  	if (sensor->class != PSC_FAN)
-		val = val * 1000L;
+		val = val * 1000LL;
 
  	/* scale result to micro-units for power sensors */
  	if (sensor->class == PSC_POWER)
-		val = val * 1000L;
+		val = val * 1000LL;
 
  	if (exponent >= 0)
  		val <<= exponent;
@@ -666,10 +666,10 @@ static long pmbus_reg2data_linear(struct pmbus_data *data,
   * Convert direct sensor values to milli- or micro-units
   * depending on sensor type.
   */
-static long pmbus_reg2data_direct(struct pmbus_data *data,
-				  struct pmbus_sensor *sensor)
+static s64 pmbus_reg2data_direct(struct pmbus_data *data,
+				 struct pmbus_sensor *sensor)
  {
-	long val = (s16) sensor->data;
+	s64 val = sensor->data;
  	long m, b, R;
 
  	m = data->info->m[sensor->class];
@@ -694,23 +694,24 @@ static long pmbus_reg2data_direct(struct pmbus_data *data,
  	}
 
  	while (R > 0) {
-		val *= 10;
+		val *= 10LL;
  		R--;
  	}
  	while (R < 0) {
-		val = DIV_ROUND_CLOSEST(val, 10);
+		val = DIV_ROUND_CLOSEST_ULL(val, 10);
  		R++;
  	}
 
-	return (val - b) / m;
+	val -= b;
+	return do_div(val, m);
  }
 
  /*
   * Convert VID sensor values to milli- or micro-units
   * depending on sensor type.
   */
-static long pmbus_reg2data_vid(struct pmbus_data *data,
-			       struct pmbus_sensor *sensor)
+static s64 pmbus_reg2data_vid(struct pmbus_data *data,
+			      struct pmbus_sensor *sensor)
  {
  	long val = sensor->data;
  	long rv = 0;
@@ -728,9 +729,9 @@ static long pmbus_reg2data_vid(struct pmbus_data *data,
  	return rv;
  }
 
-static long pmbus_reg2data(struct pmbus_data *data, struct pmbus_sensor *sensor)
+static s64 pmbus_reg2data(struct pmbus_data *data, struct pmbus_sensor *sensor)
  {
-	long val;
+	s64 val;
 
  	if (!sensor->convert)
  		return sensor->data;
@@ -968,7 +969,7 @@ static ssize_t pmbus_show_sensor(struct device *dev,
  	if (sensor->data < 0)
  		return sensor->data;
 
-	return snprintf(buf, PAGE_SIZE, "%ld\n", pmbus_reg2data(data, sensor));
+	return snprintf(buf, PAGE_SIZE, "%lld\n", pmbus_reg2data(data, sensor));
  }
 
  static ssize_t pmbus_set_sensor(struct device *dev,
#2 lore raw
Quoted 10 lines · Eddie James
Quoted 3 lines · Eddie James

It's possible to overflow sensor values, especially for power sensors reporting micro Watts. Use 64-bit values to prevent overflow.

Cancel that. This has been fixed in linux-next with bd467e4eababe4c04272c1e646f066db02734c79

I have cherry picked this into dev-4.13.

Cheers,

Joel