Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit bd8070f3 authored by Ashay Jaiswal's avatar Ashay Jaiswal Committed by Gerrit - the friendly Code Review server
Browse files

power: qpnp-fg-gen3: fix variable range overflow



cc_soc calculation might result in variable overflow
for larger value of cc_soc, update/typecast all the
variables to 64-bit during calculations.

Change-Id: Ic137fb5f258ae83f70e88b1858a8ebf2b9d1a4c1
Signed-off-by: default avatarAshay Jaiswal <ashayj@codeaurora.org>
Signed-off-by: default avatarChinkit Kumar,Kirti Kumar Parmar <parma@codeaurora.org>
parent cbfc0b35
Loading
Loading
Loading
Loading
+25 −17
Original line number Diff line number Diff line
@@ -573,14 +573,15 @@ static int fg_get_charge_raw(struct fg_chip *chip, int *val)
		return rc;
	}

	*val = div_s64(cc_soc * chip->cl.nom_cap_uah, CC_SOC_30BIT);
	*val = div_s64((int64_t)cc_soc * chip->cl.nom_cap_uah, CC_SOC_30BIT);
	return 0;
}

#define BATT_SOC_32BIT	GENMASK(31, 0)
static int fg_get_charge_counter_shadow(struct fg_chip *chip, int *val)
{
	int rc, batt_soc;
	int rc;
	unsigned int batt_soc;

	rc = fg_get_sram_prop(chip, FG_SRAM_BATT_SOC, &batt_soc);
	if (rc < 0) {
@@ -588,13 +589,15 @@ static int fg_get_charge_counter_shadow(struct fg_chip *chip, int *val)
		return rc;
	}

	*val = div_u64((u32)batt_soc * chip->cl.learned_cc_uah, BATT_SOC_32BIT);
	*val = div_u64((uint64_t)batt_soc * chip->cl.learned_cc_uah,
							BATT_SOC_32BIT);
	return 0;
}

static int fg_get_charge_counter(struct fg_chip *chip, int *val)
{
	int rc, cc_soc;
	int rc;
	int cc_soc;

	rc = fg_get_sram_prop(chip, FG_SRAM_CC_SOC_SW, &cc_soc);
	if (rc < 0) {
@@ -602,7 +605,7 @@ static int fg_get_charge_counter(struct fg_chip *chip, int *val)
		return rc;
	}

	*val = div_s64(cc_soc * chip->cl.learned_cc_uah, CC_SOC_30BIT);
	*val = div_s64((int64_t)cc_soc * chip->cl.learned_cc_uah, CC_SOC_30BIT);
	return 0;
}

@@ -1296,7 +1299,7 @@ static bool is_parallel_charger_available(struct fg_chip *chip)
	return true;
}

static int fg_prime_cc_soc_sw(struct fg_chip *chip, int cc_soc_sw)
static int fg_prime_cc_soc_sw(struct fg_chip *chip, unsigned int cc_soc_sw)
{
	int rc;

@@ -1306,7 +1309,7 @@ static int fg_prime_cc_soc_sw(struct fg_chip *chip, int cc_soc_sw)
	if (rc < 0)
		pr_err("Error in writing cc_soc_sw, rc=%d\n", rc);
	else
		fg_dbg(chip, FG_STATUS, "cc_soc_sw: %x\n", cc_soc_sw);
		fg_dbg(chip, FG_STATUS, "cc_soc_sw: %u\n", cc_soc_sw);

	return rc;
}
@@ -1469,8 +1472,10 @@ static void fg_cap_learning_post_process(struct fg_chip *chip)

static int fg_cap_learning_process_full_data(struct fg_chip *chip)
{
	int rc, cc_soc_sw, cc_soc_delta_pct;
	int rc;
	unsigned int cc_soc_sw;
	int64_t delta_cc_uah;
	unsigned int cc_soc_delta_pct;

	rc = fg_get_sram_prop(chip, FG_SRAM_CC_SOC_SW, &cc_soc_sw);
	if (rc < 0) {
@@ -1488,31 +1493,32 @@ static int fg_cap_learning_process_full_data(struct fg_chip *chip)
		return -ERANGE;
	}

	delta_cc_uah = div64_s64(chip->cl.learned_cc_uah * cc_soc_delta_pct,
	delta_cc_uah = div64_u64(chip->cl.learned_cc_uah * cc_soc_delta_pct,
				100);
	chip->cl.final_cc_uah = chip->cl.init_cc_uah + delta_cc_uah;
	fg_dbg(chip, FG_CAP_LEARN, "Current cc_soc=%d cc_soc_delta_pct=%d total_cc_uah=%lld\n",
	fg_dbg(chip, FG_CAP_LEARN, "Current cc_soc=%d cc_soc_delta_pct=%u total_cc_uah=%llu\n",
		cc_soc_sw, cc_soc_delta_pct, chip->cl.final_cc_uah);
	return 0;
}

static int fg_cap_learning_begin(struct fg_chip *chip, u32 batt_soc)
{
	int rc, cc_soc_sw, batt_soc_msb;
	int rc;
	unsigned int batt_soc_msb, cc_soc_sw;

	batt_soc_msb = batt_soc >> 24;
	if (DIV_ROUND_CLOSEST(batt_soc_msb * 100, FULL_SOC_RAW) >
		chip->dt.cl_start_soc) {
		fg_dbg(chip, FG_CAP_LEARN, "Battery SOC %d is high!, not starting\n",
		fg_dbg(chip, FG_CAP_LEARN, "Battery SOC %u is high!, not starting\n",
			batt_soc_msb);
		return -EINVAL;
	}

	chip->cl.init_cc_uah = div64_s64(chip->cl.learned_cc_uah * batt_soc_msb,
	chip->cl.init_cc_uah = div64_u64(chip->cl.learned_cc_uah * batt_soc_msb,
					FULL_SOC_RAW);

	/* Prime cc_soc_sw with battery SOC when capacity learning begins */
	cc_soc_sw = div64_s64((int64_t)batt_soc * CC_SOC_30BIT,
	cc_soc_sw = div64_u64((uint64_t)batt_soc * CC_SOC_30BIT,
				BATT_SOC_32BIT);
	rc = fg_prime_cc_soc_sw(chip, cc_soc_sw);
	if (rc < 0) {
@@ -1529,7 +1535,8 @@ static int fg_cap_learning_begin(struct fg_chip *chip, u32 batt_soc)

static int fg_cap_learning_done(struct fg_chip *chip)
{
	int rc, cc_soc_sw;
	int rc;
	unsigned int cc_soc_sw;

	rc = fg_cap_learning_process_full_data(chip);
	if (rc < 0) {
@@ -1553,7 +1560,8 @@ static int fg_cap_learning_done(struct fg_chip *chip)

static void fg_cap_learning_update(struct fg_chip *chip)
{
	int rc, batt_soc, batt_soc_msb, cc_soc_sw;
	int rc;
	unsigned int batt_soc, batt_soc_msb, cc_soc_sw;
	bool input_present = is_input_present(chip);
	bool prime_cc = false;

@@ -1640,7 +1648,7 @@ static void fg_cap_learning_update(struct fg_chip *chip)
		if (chip->charge_done)
			cc_soc_sw = CC_SOC_30BIT;
		else
			cc_soc_sw = div_u64((u32)batt_soc *
			cc_soc_sw = div_u64((uint64_t)batt_soc *
					CC_SOC_30BIT, BATT_SOC_32BIT);

		rc = fg_prime_cc_soc_sw(chip, cc_soc_sw);