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: Subbaraman Narayanamurthy <subbaram@codeaurora.org>
diff --git a/drivers/power/supply/qcom/fg-core.h b/drivers/power/supply/qcom/fg-core.h
index 9179325..99120f4 100644
--- a/drivers/power/supply/qcom/fg-core.h
+++ b/drivers/power/supply/qcom/fg-core.h
@@ -458,7 +458,6 @@
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;
diff --git a/drivers/power/supply/qcom/fg-memif.c b/drivers/power/supply/qcom/fg-memif.c
index 279b097..d9b5ad7 100644
--- a/drivers/power/supply/qcom/fg-memif.c
+++ b/drivers/power/supply/qcom/fg-memif.c
@@ -746,15 +746,12 @@
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 @@
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 @@
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) {
- 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;
- }
+ rc = -ETIMEDOUT;
+ pr_err("wait for mem_grant timed out, val=0x%x\n", val);
+ fg_dump_regs(chip);
- 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;
- }
+release:
+ val = 0;
+ mask = MEM_ACCESS_REQ_BIT | IACS_SLCT_BIT;
+ 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;
+ }
- return -ETIMEDOUT;
+ mask = MEM_ARB_LO_LATENCY_EN_BIT | MEM_ARB_REQ_BIT;
+ 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;
diff --git a/drivers/power/supply/qcom/qpnp-fg-gen3.c b/drivers/power/supply/qcom/qpnp-fg-gen3.c
index df3e25f..1ae7b6c 100644
--- a/drivers/power/supply/qcom/qpnp-fg-gen3.c
+++ b/drivers/power/supply/qcom/qpnp-fg-gen3.c
@@ -4227,25 +4227,6 @@
/* 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 @@
/* 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 @@
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 @@
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 @@
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",