[PATCH 06/17] hwmon: (adm1026) Fix overflows seen when writing into limit attributes

2016-12-04 Thread Guenter Roeck
Fix overflows seen when writing large values into voltage limit,
temperature limit, temperature offset, and DAC attributes.

Overflows are seen due to unbound multiplications and additions.

Signed-off-by: Guenter Roeck 
---
 drivers/hwmon/adm1026.c | 26 +-
 1 file changed, 17 insertions(+), 9 deletions(-)

diff --git a/drivers/hwmon/adm1026.c b/drivers/hwmon/adm1026.c
index e67b9a50ac7c..b2a5d9e5c590 100644
--- a/drivers/hwmon/adm1026.c
+++ b/drivers/hwmon/adm1026.c
@@ -197,8 +197,9 @@ static int adm1026_scaling[] = { /* .001 Volts */
};
 #define NEG12_OFFSET  16000
 #define SCALE(val, from, to) (((val)*(to) + ((from)/2))/(from))
-#define INS_TO_REG(n, val)  (clamp_val(SCALE(val, adm1026_scaling[n], 192),\
-   0, 255))
+#define INS_TO_REG(n, val) \
+   SCALE(clamp_val(val, 0, 255 * adm1026_scaling[n] / 192), \
+ adm1026_scaling[n], 192)
 #define INS_FROM_REG(n, val) (SCALE(val, 192, adm1026_scaling[n]))
 
 /*
@@ -215,11 +216,11 @@ static int adm1026_scaling[] = { /* .001 Volts */
 #define DIV_TO_REG(val) ((val) >= 8 ? 3 : (val) >= 4 ? 2 : (val) >= 2 ? 1 : 0)
 
 /* Temperature is reported in 1 degC increments */
-#define TEMP_TO_REG(val) (clamp_val(((val) + ((val) < 0 ? -500 : 500)) \
-   / 1000, -127, 127))
+#define TEMP_TO_REG(val) DIV_ROUND_CLOSEST(clamp_val(val, -128000, 127000), \
+  1000)
 #define TEMP_FROM_REG(val) ((val) * 1000)
-#define OFFSET_TO_REG(val) (clamp_val(((val) + ((val) < 0 ? -500 : 500)) \
- / 1000, -127, 127))
+#define OFFSET_TO_REG(val) DIV_ROUND_CLOSEST(clamp_val(val, -128000, 127000), \
+1000)
 #define OFFSET_FROM_REG(val) ((val) * 1000)
 
 #define PWM_TO_REG(val) (clamp_val(val, 0, 255))
@@ -233,7 +234,8 @@ static int adm1026_scaling[] = { /* .001 Volts */
  *   indicates that the DAC could be used to drive the fans, but in our
  *   example board (Arima HDAMA) it isn't connected to the fans at all.
  */
-#define DAC_TO_REG(val) (clamp_val(val) * 255) + 500) / 2500), 0, 255))
+#define DAC_TO_REG(val) DIV_ROUND_CLOSEST(clamp_val(val, 0, 2500) * 255, \
+ 2500)
 #define DAC_FROM_REG(val) (((val) * 2500) / 255)
 
 /*
@@ -593,7 +595,10 @@ static ssize_t set_in16_min(struct device *dev, struct 
device_attribute *attr,
return err;
 
mutex_lock(>update_lock);
-   data->in_min[16] = INS_TO_REG(16, val + NEG12_OFFSET);
+   data->in_min[16] = INS_TO_REG(16,
+ clamp_val(val, INT_MIN,
+   INT_MAX - NEG12_OFFSET) +
+ NEG12_OFFSET);
adm1026_write_value(client, ADM1026_REG_IN_MIN[16], data->in_min[16]);
mutex_unlock(>update_lock);
return count;
@@ -618,7 +623,10 @@ static ssize_t set_in16_max(struct device *dev, struct 
device_attribute *attr,
return err;
 
mutex_lock(>update_lock);
-   data->in_max[16] = INS_TO_REG(16, val+NEG12_OFFSET);
+   data->in_max[16] = INS_TO_REG(16,
+ clamp_val(val, INT_MIN,
+   INT_MAX - NEG12_OFFSET) +
+ NEG12_OFFSET);
adm1026_write_value(client, ADM1026_REG_IN_MAX[16], data->in_max[16]);
mutex_unlock(>update_lock);
return count;
-- 
2.5.0

--
To unsubscribe from this list: send the line "unsubscribe linux-hwmon" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 03/17] hwmon: (lm93) Fix overflows seen when writing into limit attributes

2016-12-04 Thread Guenter Roeck
Module test shows a large number of overflows, caused by missing clamps
as well as various conversions between variable types.

Also fix temperature calculations for hysteresis and offset registers.
For those, temperature calculations were a mix of millisecond and second
based, causing reported and accepted hysteresis and offset temperatures
to be widely off target.

This also changes the offset and base temperature attributes to be
officially reported and set in milli-degrees C. This was already the case
for the base temperature attribute, even though it was documented to be
reported and set in degrees C.

Signed-off-by: Guenter Roeck 
---
 Documentation/hwmon/lm93 | 26 -
 drivers/hwmon/lm93.c | 49 +---
 2 files changed, 39 insertions(+), 36 deletions(-)

diff --git a/Documentation/hwmon/lm93 b/Documentation/hwmon/lm93
index f3b2ad2ceb01..7bda7f0291e4 100644
--- a/Documentation/hwmon/lm93
+++ b/Documentation/hwmon/lm93
@@ -174,25 +174,25 @@ a "0" disables it. The h/w default is 0x0f (all 
temperatures bound).
 
 The function y = f(x) takes a source temperature x to a PWM output y.  This
 function of the LM93 is derived from a base temperature and a table of 12
-temperature offsets.  The base temperature is expressed in degrees C in the
-sysfs files temp_auto_base.  The offsets are expressed in cumulative
-degrees C, with the value of offset  for temperature value  being
+temperature offsets.  The base temperature is expressed in milli-degrees C in
+the sysfs files temp_auto_base.  The offsets are expressed in cumulative
+milli-degrees C, with the value of offset  for temperature value  being
 contained in the file temp_auto_offset.  E.g. if the base temperature
 is 40C:
 
  offset #  temp_auto_offset  range   pwm
 1  0   -25.00%
 2  0   -28.57%
-3  1   40C - 41C32.14%
-4  1   41C - 42C35.71%
-5  2   42C - 44C39.29%
-6  2   44C - 46C42.86%
-7  2   48C - 50C46.43%
-8  2   50C - 52C50.00%
-9  2   52C - 54C53.57%
-   10  2   54C - 56C57.14%
-   11  2   56C - 58C71.43%
-   12  2   58C - 60C85.71%
+3  500 40C - 41C32.14%
+4  500 41C - 42C35.71%
+5  100042C - 44C39.29%
+6  100044C - 46C42.86%
+7  100048C - 50C46.43%
+8  100050C - 52C50.00%
+9  100052C - 54C53.57%
+   10  100054C - 56C57.14%
+   11  100056C - 58C71.43%
+   12  100058C - 60C85.71%
> 60C   100.00%
 
 Valid offsets are in the range 0C <= x <= 7.5C in 0.5C increments.
diff --git a/drivers/hwmon/lm93.c b/drivers/hwmon/lm93.c
index 90bb04858117..7b3152368e3b 100644
--- a/drivers/hwmon/lm93.c
+++ b/drivers/hwmon/lm93.c
@@ -368,7 +368,7 @@ static unsigned LM93_IN_FROM_REG(int nr, u8 reg)
  * IN: mV, limits determined by channel nr
  * REG: scaling determined by channel nr
  */
-static u8 LM93_IN_TO_REG(int nr, unsigned val)
+static u8 LM93_IN_TO_REG(int nr, unsigned long val)
 {
/* range limit */
const long mv = clamp_val(val,
@@ -407,9 +407,13 @@ static unsigned LM93_IN_REL_FROM_REG(u8 reg, int upper, 
int vid)
  * upper also determines which nibble of the register is returned
  * (the other nibble will be 0x0)
  */
-static u8 LM93_IN_REL_TO_REG(unsigned val, int upper, int vid)
+static u8 LM93_IN_REL_TO_REG(unsigned long val, int upper, int vid)
 {
-   long uv_offset = vid * 1000 - val * 1;
+   long uv_offset;
+
+   val = clamp_val(val, 0, 100);
+   uv_offset = vid * 1000 - val * 1;
+
if (upper) {
uv_offset = clamp_val(uv_offset, 12500, 20);
return (u8)((uv_offset /  12500 - 1) << 4);
@@ -453,28 +457,23 @@ static int LM93_TEMP_OFFSET_MODE_FROM_REG(u8 sfc2, int nr)
  * This function is common to all 4-bit temperature offsets
  * reg is 4 bits right justified
  * mode 0 => 1C/bit, mode !0 => 0.5C/bit
+ * Return value in milli-degrees C.
  */
 static int LM93_TEMP_OFFSET_FROM_REG(u8 reg, int mode)
 {
-   return (reg & 0x0f) * (mode ? 5 : 10);
+   return (reg & 0x0f) * (mode ? 500 : 1000);
 }
 
-#define LM93_TEMP_OFFSET_MIN  (0)
-#define 

[PATCH 08/17] hwmon: (adt7470) Fix overflows seen when writing into limit attributes

2016-12-04 Thread Guenter Roeck
Fix overflows seen when writing large values into various temperature limit
attributes.

The input value passed to DIC_ROUND_CLOSEST() needs to be clamped to avoid
such overflows.

Signed-off-by: Guenter Roeck 
---
 drivers/hwmon/adt7470.c | 9 +++--
 1 file changed, 3 insertions(+), 6 deletions(-)

diff --git a/drivers/hwmon/adt7470.c b/drivers/hwmon/adt7470.c
index 6e60ca53406e..8996120b8170 100644
--- a/drivers/hwmon/adt7470.c
+++ b/drivers/hwmon/adt7470.c
@@ -483,8 +483,7 @@ static ssize_t set_temp_min(struct device *dev,
if (kstrtol(buf, 10, ))
return -EINVAL;
 
-   temp = DIV_ROUND_CLOSEST(temp, 1000);
-   temp = clamp_val(temp, -128, 127);
+   temp = DIV_ROUND_CLOSEST(clamp_val(temp, -128000, 127000), 1000);
 
mutex_lock(>lock);
data->temp_min[attr->index] = temp;
@@ -517,8 +516,7 @@ static ssize_t set_temp_max(struct device *dev,
if (kstrtol(buf, 10, ))
return -EINVAL;
 
-   temp = DIV_ROUND_CLOSEST(temp, 1000);
-   temp = clamp_val(temp, -128, 127);
+   temp = DIV_ROUND_CLOSEST(clamp_val(temp, -128000, 127000), 1000);
 
mutex_lock(>lock);
data->temp_max[attr->index] = temp;
@@ -880,8 +878,7 @@ static ssize_t set_pwm_tmin(struct device *dev,
if (kstrtol(buf, 10, ))
return -EINVAL;
 
-   temp = DIV_ROUND_CLOSEST(temp, 1000);
-   temp = clamp_val(temp, -128, 127);
+   temp = DIV_ROUND_CLOSEST(clamp_val(temp, -128000, 127000), 1000);
 
mutex_lock(>lock);
data->pwm_tmin[attr->index] = temp;
-- 
2.5.0

--
To unsubscribe from this list: send the line "unsubscribe linux-hwmon" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 16/17] hwmon: (gl518sm) Fix overflows seen when writing into limit attributes

2016-12-04 Thread Guenter Roeck
Writes into limit attributes can overflow due to additions and
multiplications with unchecked parameters.

Signed-off-by: Guenter Roeck 
---
 drivers/hwmon/gl518sm.c | 10 +-
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/drivers/hwmon/gl518sm.c b/drivers/hwmon/gl518sm.c
index 0212c8317bca..0a11a550c2a2 100644
--- a/drivers/hwmon/gl518sm.c
+++ b/drivers/hwmon/gl518sm.c
@@ -86,9 +86,8 @@ enum chips { gl518sm_r00, gl518sm_r80 };
 #define BOOL_FROM_REG(val) ((val) ? 0 : 1)
 #define BOOL_TO_REG(val)   ((val) ? 0 : 1)
 
-#define TEMP_TO_REG(val)   clamp_val(val) < 0 ? \
-   (val) - 500 : \
-   (val) + 500) / 1000) + 119), 0, 255)
+#define TEMP_TO_REG(val) (DIV_ROUND_CLOSEST(clamp_val(val, -119000, 136000), \
+   1000) + 119)
 #define TEMP_FROM_REG(val) (((val) - 119) * 1000)
 
 static inline u8 FAN_TO_REG(long rpm, int div)
@@ -101,10 +100,11 @@ static inline u8 FAN_TO_REG(long rpm, int div)
 }
 #define FAN_FROM_REG(val, div) ((val) == 0 ? 0 : (48 / ((val) * (div
 
-#define IN_TO_REG(val) clamp_valval) + 9) / 19), 0, 255)
+#define IN_TO_REG(val) DIV_ROUND_CLOSEST(clamp_val(val, 0, 255 * 19), 19)
 #define IN_FROM_REG(val)   ((val) * 19)
 
-#define VDD_TO_REG(val)clamp_valval) * 4 + 47) / 95), 0, 
255)
+#define VDD_TO_REG(val) \
+   DIV_ROUND_CLOSEST(clamp_val(val, 0, 255 * 95 / 4) * 4, 95)
 #define VDD_FROM_REG(val)  (((val) * 95 + 2) / 4)
 
 #define DIV_FROM_REG(val)  (1 << (val))
-- 
2.5.0

--
To unsubscribe from this list: send the line "unsubscribe linux-hwmon" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 12/17] hwmon: (dme1737) Fix overflows seen when writing into limit attributes

2016-12-04 Thread Guenter Roeck
Writes into voltage limit, temperature limit, and temperature zone
attributes can overflow due to unchecked parameters to multiplications
and additions.

Cc: Juerg Haefliger 
Signed-off-by: Guenter Roeck 
---
 drivers/hwmon/dme1737.c | 7 +--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/drivers/hwmon/dme1737.c b/drivers/hwmon/dme1737.c
index 8763c4a8280c..29d082c12c74 100644
--- a/drivers/hwmon/dme1737.c
+++ b/drivers/hwmon/dme1737.c
@@ -279,7 +279,8 @@ static inline int IN_FROM_REG(int reg, int nominal, int res)
 
 static inline int IN_TO_REG(long val, int nominal)
 {
-   return clamp_val((val * 192 + nominal / 2) / nominal, 0, 255);
+   return DIV_ROUND_CLOSEST(clamp_val(val, 0, 255 * nominal / 192) * 192,
+nominal);
 }
 
 /*
@@ -295,7 +296,7 @@ static inline int TEMP_FROM_REG(int reg, int res)
 
 static inline int TEMP_TO_REG(long val)
 {
-   return clamp_val((val < 0 ? val - 500 : val + 500) / 1000, -128, 127);
+   return DIV_ROUND_CLOSEST(clamp_val(val, -128000, 127000), 1000);
 }
 
 /* Temperature range */
@@ -1028,6 +1029,8 @@ static ssize_t set_zone(struct device *dev, struct 
device_attribute *attr,
if (err)
return err;
 
+   val = clamp_val(val, -256000, 255000);
+
mutex_lock(>update_lock);
switch (fn) {
case SYS_ZONE_AUTO_POINT1_TEMP_HYST:
-- 
2.5.0

--
To unsubscribe from this list: send the line "unsubscribe linux-hwmon" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 09/17] hwmon: (nct7802) Fix overflows seen when writing into limit attributes

2016-12-04 Thread Guenter Roeck
Fix overflows seen when writing voltage and temperature limit attributes.

The value passed to DIV_ROUND_CLOSEST() needs to be clamped.

Signed-off-by: Guenter Roeck 
---
 drivers/hwmon/nct7802.c | 7 ---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/drivers/hwmon/nct7802.c b/drivers/hwmon/nct7802.c
index 3ce33d244cc0..6fe71cfe0320 100644
--- a/drivers/hwmon/nct7802.c
+++ b/drivers/hwmon/nct7802.c
@@ -326,8 +326,9 @@ static int nct7802_write_voltage(struct nct7802_data *data, 
int nr, int index,
int shift = 8 - REG_VOLTAGE_LIMIT_MSB_SHIFT[index - 1][nr];
int err;
 
-   voltage = DIV_ROUND_CLOSEST(voltage, nct7802_vmul[nr]);
-   voltage = clamp_val(voltage, 0, 0x3ff);
+   voltage = DIV_ROUND_CLOSEST(clamp_val(voltage, 0,
+ 0x3ff * nct7802_vmul[nr]),
+   nct7802_vmul[nr]);
 
mutex_lock(>access_lock);
err = regmap_write(data->regmap,
@@ -402,7 +403,7 @@ static ssize_t store_temp(struct device *dev, struct 
device_attribute *attr,
if (err < 0)
return err;
 
-   val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), -128, 127);
+   val = DIV_ROUND_CLOSEST(clamp_val(val, -127000, 127000), 1000);
 
err = regmap_write(data->regmap, nr, val & 0xff);
return err ? : count;
-- 
2.5.0

--
To unsubscribe from this list: send the line "unsubscribe linux-hwmon" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 13/17] hwmon: (emc2103) Fix overflows seen when temperature limit attributes

2016-12-04 Thread Guenter Roeck
Writes into temperature limit attributes can overflow due to unbound
values passed to DIV_ROUND_CLOSEST().

Cc: Steve Glendinning 
Signed-off-by: Guenter Roeck 
---
 drivers/hwmon/emc2103.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/hwmon/emc2103.c b/drivers/hwmon/emc2103.c
index 24e395c5907d..4b870ee9b0d3 100644
--- a/drivers/hwmon/emc2103.c
+++ b/drivers/hwmon/emc2103.c
@@ -251,7 +251,7 @@ static ssize_t set_temp_min(struct device *dev, struct 
device_attribute *da,
if (result < 0)
return result;
 
-   val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), -63, 127);
+   val = DIV_ROUND_CLOSEST(clamp_val(val, -63000, 127000), 1000);
 
mutex_lock(>update_lock);
data->temp_min[nr] = val;
@@ -273,7 +273,7 @@ static ssize_t set_temp_max(struct device *dev, struct 
device_attribute *da,
if (result < 0)
return result;
 
-   val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), -63, 127);
+   val = DIV_ROUND_CLOSEST(clamp_val(val, -63000, 127000), 1000);
 
mutex_lock(>update_lock);
data->temp_max[nr] = val;
-- 
2.5.0

--
To unsubscribe from this list: send the line "unsubscribe linux-hwmon" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 05/17] hwmon: (adm1025) Fix overflows seen when writing voltage limits

2016-12-04 Thread Guenter Roeck
Writes into voltage limit attributes can overflow due to an unbound
multiplication.

Signed-off-by: Guenter Roeck 
---
 drivers/hwmon/adm1025.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/hwmon/adm1025.c b/drivers/hwmon/adm1025.c
index d6c767ace916..1abb4609b412 100644
--- a/drivers/hwmon/adm1025.c
+++ b/drivers/hwmon/adm1025.c
@@ -93,7 +93,7 @@ static const int in_scale[6] = { 2500, 2250, 3300, 5000, 
12000, 3300 };
 
 #define IN_FROM_REG(reg, scale)(((reg) * (scale) + 96) / 192)
 #define IN_TO_REG(val, scale)  ((val) <= 0 ? 0 : \
-(val) * 192 >= (scale) * 255 ? 255 : \
+(val) >= (scale) * 255 / 192 ? 255 : \
 ((val) * 192 + (scale) / 2) / (scale))
 
 #define TEMP_FROM_REG(reg) ((reg) * 1000)
-- 
2.5.0

--
To unsubscribe from this list: send the line "unsubscribe linux-hwmon" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 11/17] hwmon: (lm85) Fix overflows seen when writing voltage limit attributes

2016-12-04 Thread Guenter Roeck
Writes into voltage limit attributes can overflow due to an unbound
multiplication.

Signed-off-by: Guenter Roeck 
---
 drivers/hwmon/lm85.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/hwmon/lm85.c b/drivers/hwmon/lm85.c
index 6ff773fcaefb..29c8136ce9c5 100644
--- a/drivers/hwmon/lm85.c
+++ b/drivers/hwmon/lm85.c
@@ -136,7 +136,8 @@ static const int lm85_scaling[] = {  /* .001 Volts */
 #define SCALE(val, from, to)   (((val) * (to) + ((from) / 2)) / (from))
 
 #define INS_TO_REG(n, val) \
-   clamp_val(SCALE(val, lm85_scaling[n], 192), 0, 255)
+   SCALE(clamp_val(val, 0, 255 * lm85_scaling[n] / 192), \
+ lm85_scaling[n], 192)
 
 #define INSEXT_FROM_REG(n, val, ext)   \
SCALE(((val) << 4) + (ext), 192 << 4, lm85_scaling[n])
-- 
2.5.0

--
To unsubscribe from this list: send the line "unsubscribe linux-hwmon" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html