Commit 8ba75b20 authored by Josh Lehan's avatar Josh Lehan Committed by Guenter Roeck

hwmon: (pmbus/core) Use s64 instead of long for calculations

Using s64 type, instead of long type, for internal calculations and for
the sysfs interface.

This allows 64-bit values to appear correctly on 32-bit kernels.
As wattage is reported in microwatts, monitoring a power supply over
2KW requires this.

Although it may seem unlikely to run a 32-bit kernel on such a large
machine, enterprise servers often include a BMC, and the BMC might be
running a 32-bit kernel.
Signed-off-by: default avatarJosh Lehan <krellan@google.com>
[groeck: Removed Change-Id and other tags, reformatted description]
Signed-off-by: default avatarGuenter Roeck <linux@roeck-us.net>
parent 5c9353f5
...@@ -628,12 +628,12 @@ static struct pmbus_data *pmbus_update_device(struct device *dev) ...@@ -628,12 +628,12 @@ static struct pmbus_data *pmbus_update_device(struct device *dev)
* Convert linear sensor values to milli- or micro-units * Convert linear sensor values to milli- or micro-units
* depending on sensor type. * depending on sensor type.
*/ */
static long pmbus_reg2data_linear(struct pmbus_data *data, static s64 pmbus_reg2data_linear(struct pmbus_data *data,
struct pmbus_sensor *sensor) struct pmbus_sensor *sensor)
{ {
s16 exponent; s16 exponent;
s32 mantissa; s32 mantissa;
long val; s64 val;
if (sensor->class == PSC_VOLTAGE_OUT) { /* LINEAR16 */ if (sensor->class == PSC_VOLTAGE_OUT) { /* LINEAR16 */
exponent = data->exponent[sensor->page]; exponent = data->exponent[sensor->page];
...@@ -647,11 +647,11 @@ static long pmbus_reg2data_linear(struct pmbus_data *data, ...@@ -647,11 +647,11 @@ static long pmbus_reg2data_linear(struct pmbus_data *data,
/* scale result to milli-units for all sensors except fans */ /* scale result to milli-units for all sensors except fans */
if (sensor->class != PSC_FAN) if (sensor->class != PSC_FAN)
val = val * 1000L; val = val * 1000LL;
/* scale result to micro-units for power sensors */ /* scale result to micro-units for power sensors */
if (sensor->class == PSC_POWER) if (sensor->class == PSC_POWER)
val = val * 1000L; val = val * 1000LL;
if (exponent >= 0) if (exponent >= 0)
val <<= exponent; val <<= exponent;
...@@ -665,8 +665,8 @@ static long pmbus_reg2data_linear(struct pmbus_data *data, ...@@ -665,8 +665,8 @@ static long pmbus_reg2data_linear(struct pmbus_data *data,
* Convert direct sensor values to milli- or micro-units * Convert direct sensor values to milli- or micro-units
* depending on sensor type. * depending on sensor type.
*/ */
static long pmbus_reg2data_direct(struct pmbus_data *data, static s64 pmbus_reg2data_direct(struct pmbus_data *data,
struct pmbus_sensor *sensor) struct pmbus_sensor *sensor)
{ {
s64 b, val = (s16)sensor->data; s64 b, val = (s16)sensor->data;
s32 m, R; s32 m, R;
...@@ -702,15 +702,15 @@ static long pmbus_reg2data_direct(struct pmbus_data *data, ...@@ -702,15 +702,15 @@ static long pmbus_reg2data_direct(struct pmbus_data *data,
} }
val = div_s64(val - b, m); val = div_s64(val - b, m);
return clamp_val(val, LONG_MIN, LONG_MAX); return val;
} }
/* /*
* Convert VID sensor values to milli- or micro-units * Convert VID sensor values to milli- or micro-units
* depending on sensor type. * depending on sensor type.
*/ */
static long pmbus_reg2data_vid(struct pmbus_data *data, static s64 pmbus_reg2data_vid(struct pmbus_data *data,
struct pmbus_sensor *sensor) struct pmbus_sensor *sensor)
{ {
long val = sensor->data; long val = sensor->data;
long rv = 0; long rv = 0;
...@@ -740,9 +740,9 @@ static long pmbus_reg2data_vid(struct pmbus_data *data, ...@@ -740,9 +740,9 @@ static long pmbus_reg2data_vid(struct pmbus_data *data,
return rv; 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) if (!sensor->convert)
return sensor->data; return sensor->data;
...@@ -766,7 +766,7 @@ static long pmbus_reg2data(struct pmbus_data *data, struct pmbus_sensor *sensor) ...@@ -766,7 +766,7 @@ static long pmbus_reg2data(struct pmbus_data *data, struct pmbus_sensor *sensor)
#define MIN_MANTISSA (511 * 1000) #define MIN_MANTISSA (511 * 1000)
static u16 pmbus_data2reg_linear(struct pmbus_data *data, static u16 pmbus_data2reg_linear(struct pmbus_data *data,
struct pmbus_sensor *sensor, long val) struct pmbus_sensor *sensor, s64 val)
{ {
s16 exponent = 0, mantissa; s16 exponent = 0, mantissa;
bool negative = false; bool negative = false;
...@@ -788,8 +788,8 @@ static u16 pmbus_data2reg_linear(struct pmbus_data *data, ...@@ -788,8 +788,8 @@ static u16 pmbus_data2reg_linear(struct pmbus_data *data,
val <<= -data->exponent[sensor->page]; val <<= -data->exponent[sensor->page];
else else
val >>= data->exponent[sensor->page]; val >>= data->exponent[sensor->page];
val = DIV_ROUND_CLOSEST(val, 1000); val = DIV_ROUND_CLOSEST_ULL(val, 1000);
return val & 0xffff; return clamp_val(val, 0, 0xffff);
} }
if (val < 0) { if (val < 0) {
...@@ -799,14 +799,14 @@ static u16 pmbus_data2reg_linear(struct pmbus_data *data, ...@@ -799,14 +799,14 @@ static u16 pmbus_data2reg_linear(struct pmbus_data *data,
/* Power is in uW. Convert to mW before converting. */ /* Power is in uW. Convert to mW before converting. */
if (sensor->class == PSC_POWER) if (sensor->class == PSC_POWER)
val = DIV_ROUND_CLOSEST(val, 1000L); val = DIV_ROUND_CLOSEST_ULL(val, 1000);
/* /*
* For simplicity, convert fan data to milli-units * For simplicity, convert fan data to milli-units
* before calculating the exponent. * before calculating the exponent.
*/ */
if (sensor->class == PSC_FAN) if (sensor->class == PSC_FAN)
val = val * 1000; val = val * 1000LL;
/* Reduce large mantissa until it fits into 10 bit */ /* Reduce large mantissa until it fits into 10 bit */
while (val >= MAX_MANTISSA && exponent < 15) { while (val >= MAX_MANTISSA && exponent < 15) {
...@@ -820,11 +820,7 @@ static u16 pmbus_data2reg_linear(struct pmbus_data *data, ...@@ -820,11 +820,7 @@ static u16 pmbus_data2reg_linear(struct pmbus_data *data,
} }
/* Convert mantissa from milli-units to units */ /* Convert mantissa from milli-units to units */
mantissa = DIV_ROUND_CLOSEST(val, 1000); mantissa = clamp_val(DIV_ROUND_CLOSEST_ULL(val, 1000), 0, 0x3ff);
/* Ensure that resulting number is within range */
if (mantissa > 0x3ff)
mantissa = 0x3ff;
/* restore sign */ /* restore sign */
if (negative) if (negative)
...@@ -835,9 +831,9 @@ static u16 pmbus_data2reg_linear(struct pmbus_data *data, ...@@ -835,9 +831,9 @@ static u16 pmbus_data2reg_linear(struct pmbus_data *data,
} }
static u16 pmbus_data2reg_direct(struct pmbus_data *data, static u16 pmbus_data2reg_direct(struct pmbus_data *data,
struct pmbus_sensor *sensor, long val) struct pmbus_sensor *sensor, s64 val)
{ {
s64 b, val64 = val; s64 b;
s32 m, R; s32 m, R;
m = data->info->m[sensor->class]; m = data->info->m[sensor->class];
...@@ -855,30 +851,30 @@ static u16 pmbus_data2reg_direct(struct pmbus_data *data, ...@@ -855,30 +851,30 @@ static u16 pmbus_data2reg_direct(struct pmbus_data *data,
R -= 3; /* Adjust R and b for data in milli-units */ R -= 3; /* Adjust R and b for data in milli-units */
b *= 1000; b *= 1000;
} }
val64 = val64 * m + b; val = val * m + b;
while (R > 0) { while (R > 0) {
val64 *= 10; val *= 10;
R--; R--;
} }
while (R < 0) { while (R < 0) {
val64 = div_s64(val64 + 5LL, 10L); /* round closest */ val = div_s64(val + 5LL, 10L); /* round closest */
R++; R++;
} }
return (u16)clamp_val(val64, S16_MIN, S16_MAX); return (u16)clamp_val(val, S16_MIN, S16_MAX);
} }
static u16 pmbus_data2reg_vid(struct pmbus_data *data, static u16 pmbus_data2reg_vid(struct pmbus_data *data,
struct pmbus_sensor *sensor, long val) struct pmbus_sensor *sensor, s64 val)
{ {
val = clamp_val(val, 500, 1600); val = clamp_val(val, 500, 1600);
return 2 + DIV_ROUND_CLOSEST((1600 - val) * 100, 625); return 2 + DIV_ROUND_CLOSEST_ULL((1600LL - val) * 100LL, 625);
} }
static u16 pmbus_data2reg(struct pmbus_data *data, static u16 pmbus_data2reg(struct pmbus_data *data,
struct pmbus_sensor *sensor, long val) struct pmbus_sensor *sensor, s64 val)
{ {
u16 regval; u16 regval;
...@@ -944,7 +940,7 @@ static int pmbus_get_boolean(struct pmbus_data *data, struct pmbus_boolean *b, ...@@ -944,7 +940,7 @@ static int pmbus_get_boolean(struct pmbus_data *data, struct pmbus_boolean *b,
WARN(1, "Bad boolean descriptor %p: s1=%p, s2=%p\n", b, s1, s2); WARN(1, "Bad boolean descriptor %p: s1=%p, s2=%p\n", b, s1, s2);
return 0; return 0;
} else { } else {
long v1, v2; s64 v1, v2;
if (s1->data < 0) if (s1->data < 0)
return s1->data; return s1->data;
...@@ -981,7 +977,7 @@ static ssize_t pmbus_show_sensor(struct device *dev, ...@@ -981,7 +977,7 @@ static ssize_t pmbus_show_sensor(struct device *dev,
if (sensor->data < 0) if (sensor->data < 0)
return sensor->data; 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, static ssize_t pmbus_set_sensor(struct device *dev,
...@@ -992,11 +988,11 @@ static ssize_t pmbus_set_sensor(struct device *dev, ...@@ -992,11 +988,11 @@ static ssize_t pmbus_set_sensor(struct device *dev,
struct pmbus_data *data = i2c_get_clientdata(client); struct pmbus_data *data = i2c_get_clientdata(client);
struct pmbus_sensor *sensor = to_pmbus_sensor(devattr); struct pmbus_sensor *sensor = to_pmbus_sensor(devattr);
ssize_t rv = count; ssize_t rv = count;
long val = 0; s64 val;
int ret; int ret;
u16 regval; u16 regval;
if (kstrtol(buf, 10, &val) < 0) if (kstrtos64(buf, 10, &val) < 0)
return -EINVAL; return -EINVAL;
mutex_lock(&data->update_lock); mutex_lock(&data->update_lock);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment