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

Commit 0d054777 authored by Subbaraman Narayanamurthy's avatar Subbaraman Narayanamurthy
Browse files

power: qpnp-fg-gen3: poll for MEM_GNT instead of interrupt for DMA



Currently, for accessing FG SRAM by DMA, SW is requesting for
accessing and waiting for MEM_GNT interrupt to complete the SRAM
transaction. However, in certain cases where the CPU's interrupt
is kept disabled by some other driver long enough, MEM_GNT irq is
not handled on time. This leads to FG SRAM transaction timing out
ending up in fuel gauging performance issues in addition to
dumping peripheral registers frequently.

Workaround this issue by polling for MEM_GNT bit after requesting
DMA. This way, FG SRAM transactions can be made reliably.

Change-Id: Ic4639d5035fb47b1ae36405be53116c2f9222140
Signed-off-by: default avatarSubbaraman Narayanamurthy <subbaram@codeaurora.org>
parent 87b21110
Loading
Loading
Loading
Loading
+0 −1
Original line number Diff line number Diff line
@@ -458,7 +458,6 @@ struct fg_chip {
	bool			qnovo_enable;
	struct completion	soc_update;
	struct completion	soc_ready;
	struct completion	mem_grant;
	struct delayed_work	profile_load_work;
	struct work_struct	status_change_work;
	struct delayed_work	ttf_work;
+32 −39
Original line number Diff line number Diff line
@@ -746,15 +746,12 @@ int fg_interleaved_mem_write(struct fg_chip *chip, u16 address, u8 offset,
	return rc;
}

#define MEM_GRANT_WAIT_MS	200
#define MEM_GNT_WAIT_TIME_US	10000
#define MEM_GNT_RETRIES		20
static int fg_direct_mem_request(struct fg_chip *chip, bool request)
{
	int rc, ret;
	int rc, ret, i = 0;
	u8 val, mask;
	bool tried_again = false;

	if (request)
		reinit_completion(&chip->mem_grant);

	mask = MEM_ACCESS_REQ_BIT | IACS_SLCT_BIT;
	val = request ? MEM_ACCESS_REQ_BIT : 0;
@@ -769,7 +766,7 @@ static int fg_direct_mem_request(struct fg_chip *chip, bool request)
	rc = fg_masked_write(chip, MEM_IF_MEM_ARB_CFG(chip), mask, val);
	if (rc < 0) {
		pr_err("failed to configure mem_if_mem_arb_cfg rc:%d\n", rc);
		return rc;
		goto release;
	}

	if (request)
@@ -780,43 +777,39 @@ static int fg_direct_mem_request(struct fg_chip *chip, bool request)
	if (!request)
		return 0;

wait:
	ret = wait_for_completion_interruptible_timeout(
		&chip->mem_grant, msecs_to_jiffies(MEM_GRANT_WAIT_MS));
	/* If we were interrupted wait again one more time. */
	if (ret <= 0) {
		if ((ret == -ERESTARTSYS || ret == 0) && !tried_again) {
			pr_debug("trying again, ret=%d\n", ret);
			tried_again = true;
			goto wait;
		} else {
			pr_err("wait for mem_grant timed out ret=%d\n",
				ret);
			fg_dump_regs(chip);
	while (i < MEM_GNT_RETRIES) {
		rc = fg_read(chip, MEM_IF_INT_RT_STS(chip), &val, 1);
		if (rc < 0) {
			pr_err("Error in reading MEM_IF_INT_RT_STS, rc=%d\n",
				rc);
			goto release;
		}

		if (val & MEM_GNT_BIT)
			return 0;

		usleep_range(MEM_GNT_WAIT_TIME_US, MEM_GNT_WAIT_TIME_US + 1);
		i++;
	}

	if (ret <= 0) {
	rc = -ETIMEDOUT;
	pr_err("wait for mem_grant timed out, val=0x%x\n", val);
	fg_dump_regs(chip);

release:
	val = 0;
	mask = MEM_ACCESS_REQ_BIT | IACS_SLCT_BIT;
		rc = fg_masked_write(chip, MEM_IF_MEM_INTF_CFG(chip), mask,
					val);
		if (rc < 0) {
			pr_err("failed to configure mem_if_mem_intf_cfg rc=%d\n",
				rc);
			return rc;
	ret = fg_masked_write(chip, MEM_IF_MEM_INTF_CFG(chip), mask, val);
	if (ret < 0) {
		pr_err("failed to configure mem_if_mem_intf_cfg rc=%d\n", rc);
		return ret;
	}

	mask = MEM_ARB_LO_LATENCY_EN_BIT | MEM_ARB_REQ_BIT;
		rc = fg_masked_write(chip, MEM_IF_MEM_ARB_CFG(chip), mask,
					val);
		if (rc < 0) {
			pr_err("failed to configure mem_if_mem_arb_cfg rc:%d\n",
				rc);
			return rc;
		}

		return -ETIMEDOUT;
	ret = fg_masked_write(chip, MEM_IF_MEM_ARB_CFG(chip), mask, val);
	if (ret < 0) {
		pr_err("failed to configure mem_if_mem_arb_cfg rc:%d\n", rc);
		return ret;
	}

	return rc;
+18 −38
Original line number Diff line number Diff line
@@ -4227,25 +4227,6 @@ static int fg_adjust_timebase(struct fg_chip *chip)

/* INTERRUPT HANDLERS STAY HERE */

static irqreturn_t fg_dma_grant_irq_handler(int irq, void *data)
{
	struct fg_chip *chip = data;
	u8 status;
	int rc;

	rc = fg_read(chip, MEM_IF_INT_RT_STS(chip), &status, 1);
	if (rc < 0) {
		pr_err("failed to read addr=0x%04x, rc=%d\n",
			MEM_IF_INT_RT_STS(chip), rc);
		return IRQ_HANDLED;
	}

	fg_dbg(chip, FG_IRQ, "irq %d triggered, status:%d\n", irq, status);
	complete_all(&chip->mem_grant);

	return IRQ_HANDLED;
}

static irqreturn_t fg_mem_xcp_irq_handler(int irq, void *data)
{
	struct fg_chip *chip = data;
@@ -4533,7 +4514,7 @@ static struct fg_irq_info fg_irqs[FG_IRQ_MAX] = {
	/* MEM_IF irqs */
	[DMA_GRANT_IRQ] = {
		.name		= "dma-grant",
		.handler	= fg_dma_grant_irq_handler,
		.handler	= fg_dummy_irq_handler,
		.wakeable	= true,
	},
	[MEM_XCP_IRQ] = {
@@ -5210,7 +5191,6 @@ static int fg_gen3_probe(struct platform_device *pdev)
	mutex_init(&chip->qnovo_esr_ctrl_lock);
	init_completion(&chip->soc_update);
	init_completion(&chip->soc_ready);
	init_completion(&chip->mem_grant);
	INIT_DELAYED_WORK(&chip->profile_load_work, profile_load_work);
	INIT_DELAYED_WORK(&chip->pl_enable_work, pl_enable_work);
	INIT_WORK(&chip->status_change_work, status_change_work);
@@ -5226,23 +5206,6 @@ static int fg_gen3_probe(struct platform_device *pdev)

	platform_set_drvdata(pdev, chip);

	rc = fg_register_interrupts(chip);
	if (rc < 0) {
		dev_err(chip->dev, "Error in registering interrupts, rc:%d\n",
			rc);
		goto exit;
	}

	/* Keep SOC_UPDATE irq disabled until we require it */
	if (fg_irqs[SOC_UPDATE_IRQ].irq)
		disable_irq_nosync(fg_irqs[SOC_UPDATE_IRQ].irq);

	/* Keep BSOC_DELTA_IRQ disabled until we require it */
	vote(chip->delta_bsoc_irq_en_votable, DELTA_BSOC_IRQ_VOTER, false, 0);

	/* Keep BATT_MISSING_IRQ disabled until we require it */
	vote(chip->batt_miss_irq_en_votable, BATT_MISS_IRQ_VOTER, false, 0);

	rc = fg_hw_init(chip);
	if (rc < 0) {
		dev_err(chip->dev, "Error in initializing FG hardware, rc:%d\n",
@@ -5270,6 +5233,23 @@ static int fg_gen3_probe(struct platform_device *pdev)
		goto exit;
	}

	rc = fg_register_interrupts(chip);
	if (rc < 0) {
		dev_err(chip->dev, "Error in registering interrupts, rc:%d\n",
			rc);
		goto exit;
	}

	/* Keep SOC_UPDATE irq disabled until we require it */
	if (fg_irqs[SOC_UPDATE_IRQ].irq)
		disable_irq_nosync(fg_irqs[SOC_UPDATE_IRQ].irq);

	/* Keep BSOC_DELTA_IRQ disabled until we require it */
	vote(chip->delta_bsoc_irq_en_votable, DELTA_BSOC_IRQ_VOTER, false, 0);

	/* Keep BATT_MISSING_IRQ disabled until we require it */
	vote(chip->batt_miss_irq_en_votable, BATT_MISS_IRQ_VOTER, false, 0);

	rc = fg_debugfs_create(chip);
	if (rc < 0) {
		dev_err(chip->dev, "Error in creating debugfs entries, rc:%d\n",