diff options
| author | Subbaraman Narayanamurthy <subbaram@codeaurora.org> | 2017-06-02 11:38:58 -0700 |
|---|---|---|
| committer | Subbaraman Narayanamurthy <subbaram@codeaurora.org> | 2017-06-05 18:20:04 -0700 |
| commit | 4dba5345e14c61b041c0410b3d6614575515a57a (patch) | |
| tree | 64945d3356815d12ccf24c7da80cb7c3b216bd10 | |
| parent | 5404e35069576a8cd8203065f60975e34a5f727b (diff) | |
power: qpnp-fg-gen3: Fix possible integer overflow
Currently, DIV_ROUND_CLOSEST is used while finding the delta
between initial and final cc_soc_sw in terms of percentage. This
can go beyond 32 bits with the intermediate multiplication before
it is down-converted back to less than 32 bits. Fix this.
Also, when the cc_soc_sw delta is less than 50 %, discard the
data so that the last learned capacity won't be updated.
While at it, fix a similar use of DIV_ROUND_CLOSEST in another
place fg_encode_default() where an integer overflow can happen
if it is passed with large integer values.
Change-Id: Ia2b0f5456663a90bcd32a4fed52d1e579cff4e1f
Signed-off-by: Subbaraman Narayanamurthy <subbaram@codeaurora.org>
| -rw-r--r-- | drivers/power/supply/qcom/qpnp-fg-gen3.c | 16 |
1 files changed, 11 insertions, 5 deletions
diff --git a/drivers/power/supply/qcom/qpnp-fg-gen3.c b/drivers/power/supply/qcom/qpnp-fg-gen3.c index d0f7a5e1e227..6ef1eb379060 100644 --- a/drivers/power/supply/qcom/qpnp-fg-gen3.c +++ b/drivers/power/supply/qcom/qpnp-fg-gen3.c @@ -491,7 +491,7 @@ static void fg_encode_default(struct fg_sram_param *sp, int i, mask = 0xff; int64_t temp; - temp = DIV_ROUND_CLOSEST(val * sp[id].numrtr, sp[id].denmtr); + temp = (int64_t)div_s64((s64)val * sp[id].numrtr, sp[id].denmtr); pr_debug("temp: %llx id: %d, val: %d, buf: [ ", temp, id, val); for (i = 0; i < sp[id].len; i++) { buf[i] = temp & mask; @@ -1315,9 +1315,16 @@ static int fg_cap_learning_process_full_data(struct fg_chip *chip) return rc; } - cc_soc_delta_pct = DIV_ROUND_CLOSEST( - abs(cc_soc_sw - chip->cl.init_cc_soc_sw) * 100, - CC_SOC_30BIT); + cc_soc_delta_pct = + div64_s64((int64_t)(cc_soc_sw - chip->cl.init_cc_soc_sw) * 100, + CC_SOC_30BIT); + + /* If the delta is < 50%, then skip processing full data */ + if (cc_soc_delta_pct < 50) { + pr_err("cc_soc_delta_pct: %d\n", cc_soc_delta_pct); + return -ERANGE; + } + delta_cc_uah = div64_s64(chip->cl.learned_cc_uah * cc_soc_delta_pct, 100); chip->cl.final_cc_uah = chip->cl.init_cc_uah + delta_cc_uah; @@ -1387,7 +1394,6 @@ out: return rc; } -#define FULL_SOC_RAW 255 static void fg_cap_learning_update(struct fg_chip *chip) { int rc, batt_soc, batt_soc_msb; |
