aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorRobert Lippert <roblip@gmail.com>2017-11-27 18:51:55 -0500
committerGuenter Roeck <linux@roeck-us.net>2017-11-27 23:29:22 -0500
commitbd467e4eababe4c04272c1e646f066db02734c79 (patch)
treec0a485e360a00fa99ce2d5aa9be80f9fbcc57e97 /drivers
parented81cc612c92167fe7606773e036ee5ccef6c190 (diff)
hwmon: (pmbus) Use 64bit math for DIRECT format values
Power values in the 100s of watt range can easily blow past 32bit math limits when processing everything in microwatts. Use 64bit math instead to avoid these issues on common 32bit ARM BMC platforms. Fixes: 442aba78728e ("hwmon: PMBus device driver") Signed-off-by: Robert Lippert <rlippert@google.com> Signed-off-by: Guenter Roeck <linux@roeck-us.net>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/hwmon/pmbus/pmbus_core.c21
1 files changed, 12 insertions, 9 deletions
diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c
index 52a58b8b6e1b..a139940cd991 100644
--- a/drivers/hwmon/pmbus/pmbus_core.c
+++ b/drivers/hwmon/pmbus/pmbus_core.c
@@ -21,6 +21,7 @@
21 21
22#include <linux/debugfs.h> 22#include <linux/debugfs.h>
23#include <linux/kernel.h> 23#include <linux/kernel.h>
24#include <linux/math64.h>
24#include <linux/module.h> 25#include <linux/module.h>
25#include <linux/init.h> 26#include <linux/init.h>
26#include <linux/err.h> 27#include <linux/err.h>
@@ -499,8 +500,8 @@ static long pmbus_reg2data_linear(struct pmbus_data *data,
499static long pmbus_reg2data_direct(struct pmbus_data *data, 500static long pmbus_reg2data_direct(struct pmbus_data *data,
500 struct pmbus_sensor *sensor) 501 struct pmbus_sensor *sensor)
501{ 502{
502 long val = (s16) sensor->data; 503 s64 b, val = (s16)sensor->data;
503 long m, b, R; 504 s32 m, R;
504 505
505 m = data->info->m[sensor->class]; 506 m = data->info->m[sensor->class];
506 b = data->info->b[sensor->class]; 507 b = data->info->b[sensor->class];
@@ -528,11 +529,12 @@ static long pmbus_reg2data_direct(struct pmbus_data *data,
528 R--; 529 R--;
529 } 530 }
530 while (R < 0) { 531 while (R < 0) {
531 val = DIV_ROUND_CLOSEST(val, 10); 532 val = div_s64(val + 5LL, 10L); /* round closest */
532 R++; 533 R++;
533 } 534 }
534 535
535 return (val - b) / m; 536 val = div_s64(val - b, m);
537 return clamp_val(val, LONG_MIN, LONG_MAX);
536} 538}
537 539
538/* 540/*
@@ -656,7 +658,8 @@ static u16 pmbus_data2reg_linear(struct pmbus_data *data,
656static u16 pmbus_data2reg_direct(struct pmbus_data *data, 658static u16 pmbus_data2reg_direct(struct pmbus_data *data,
657 struct pmbus_sensor *sensor, long val) 659 struct pmbus_sensor *sensor, long val)
658{ 660{
659 long m, b, R; 661 s64 b, val64 = val;
662 s32 m, R;
660 663
661 m = data->info->m[sensor->class]; 664 m = data->info->m[sensor->class];
662 b = data->info->b[sensor->class]; 665 b = data->info->b[sensor->class];
@@ -673,18 +676,18 @@ static u16 pmbus_data2reg_direct(struct pmbus_data *data,
673 R -= 3; /* Adjust R and b for data in milli-units */ 676 R -= 3; /* Adjust R and b for data in milli-units */
674 b *= 1000; 677 b *= 1000;
675 } 678 }
676 val = val * m + b; 679 val64 = val64 * m + b;
677 680
678 while (R > 0) { 681 while (R > 0) {
679 val *= 10; 682 val64 *= 10;
680 R--; 683 R--;
681 } 684 }
682 while (R < 0) { 685 while (R < 0) {
683 val = DIV_ROUND_CLOSEST(val, 10); 686 val64 = div_s64(val64 + 5LL, 10L); /* round closest */
684 R++; 687 R++;
685 } 688 }
686 689
687 return val; 690 return (u16)clamp_val(val64, S16_MIN, S16_MAX);
688} 691}
689 692
690static u16 pmbus_data2reg_vid(struct pmbus_data *data, 693static u16 pmbus_data2reg_vid(struct pmbus_data *data,