From: Praveen Talari <praveen.talari@oss.qualcomm.com>
To: Mukesh Kumar Savaliya <mukesh.savaliya@oss.qualcomm.com>,
Viken Dadhaniya <viken.dadhaniya@oss.qualcomm.com>,
Andi Shyti <andi.shyti@kernel.org>
Cc: linux-arm-msm@vger.kernel.org, linux-i2c@vger.kernel.org,
linux-kernel@vger.kernel.org,
Praveen Talari <praveen.talari@oss.qualcomm.com>,
Naresh Maramaina <naresh.maramaina@oss.qualcomm.com>
Subject: [PATCH v2 2/3] i2c: qcom-geni: use dedicated completions for abort and reset events
Date: Thu, 09 Jul 2026 09:50:41 +0530 [thread overview]
Message-ID: <20260709-fix_cancel_sequence_on_failure_for_i2c-v2-2-1db178c695bb@oss.qualcomm.com> (raw)
In-Reply-To: <20260709-fix_cancel_sequence_on_failure_for_i2c-v2-0-1db178c695bb@oss.qualcomm.com>
The driver uses a common completion event for transfer, abort and DMA
reset operations. This allows unrelated completion events to
prematurely wake abort and reset waiters, leading to incorrect
synchronization.
Introduce dedicated completions for abort, TX reset, and RX reset
operations, and signal them only from their respective interrupt
events. This removes the dependency on shared completion state and
eliminates the abort_done flag-based synchronization.
Co-developed-by: Naresh Maramaina <naresh.maramaina@oss.qualcomm.com>
Signed-off-by: Naresh Maramaina <naresh.maramaina@oss.qualcomm.com>
Signed-off-by: Praveen Talari <praveen.talari@oss.qualcomm.com>
---
drivers/i2c/busses/i2c-qcom-geni.c | 54 +++++++++++++++++++-------------------
1 file changed, 27 insertions(+), 27 deletions(-)
diff --git a/drivers/i2c/busses/i2c-qcom-geni.c b/drivers/i2c/busses/i2c-qcom-geni.c
index 15403edb355a..9490aee4928c 100644
--- a/drivers/i2c/busses/i2c-qcom-geni.c
+++ b/drivers/i2c/busses/i2c-qcom-geni.c
@@ -113,7 +113,10 @@ struct geni_i2c_dev {
int err;
struct i2c_adapter adap;
struct completion done;
+ struct completion abort_done;
struct completion cancel_done;
+ struct completion tx_reset_done;
+ struct completion rx_reset_done;
struct i2c_msg *cur;
int cur_wr;
int cur_rd;
@@ -127,7 +130,6 @@ struct geni_i2c_dev {
struct dma_chan *rx_c;
bool no_dma;
bool gpi_mode;
- bool abort_done;
bool is_tx_multi_desc_xfer;
u32 num_msgs;
struct geni_i2c_gpi_multi_desc_xfer i2c_multi_desc_config;
@@ -256,8 +258,6 @@ static void geni_i2c_err(struct geni_i2c_dev *gi2c, int err)
switch (err) {
case GENI_ABORT_DONE:
- gi2c->abort_done = true;
- break;
case NACK:
case GENI_TIMEOUT:
dev_dbg(gi2c->se.dev, "%s\n", gi2c_log[err].msg);
@@ -359,12 +359,18 @@ static irqreturn_t geni_i2c_irq(int irq, void *dev)
writel_relaxed(dm_rx_st, base + SE_DMA_RX_IRQ_CLR);
/* if this is err with done-bit not set, handle that through timeout. */
- if (m_stat & M_CMD_DONE_EN || m_stat & M_CMD_ABORT_EN ||
- dm_tx_st & TX_DMA_DONE || dm_tx_st & TX_RESET_DONE ||
- dm_rx_st & RX_DMA_DONE || dm_rx_st & RX_RESET_DONE)
+ if (m_stat & M_CMD_DONE_EN ||
+ dm_tx_st & TX_DMA_DONE ||
+ dm_rx_st & RX_DMA_DONE)
complete(&gi2c->done);
if (m_stat & M_CMD_CANCEL_EN)
complete(&gi2c->cancel_done);
+ if (m_stat & M_CMD_ABORT_EN)
+ complete(&gi2c->abort_done);
+ if (dm_tx_st & TX_RESET_DONE)
+ complete(&gi2c->tx_reset_done);
+ if (dm_rx_st & RX_RESET_DONE)
+ complete(&gi2c->rx_reset_done);
spin_unlock(&gi2c->lock);
@@ -376,17 +382,13 @@ static void geni_i2c_abort_xfer(struct geni_i2c_dev *gi2c)
unsigned long time_left = ABORT_TIMEOUT;
unsigned long flags;
+ reinit_completion(&gi2c->abort_done);
+
spin_lock_irqsave(&gi2c->lock, flags);
- geni_i2c_err(gi2c, GENI_TIMEOUT);
- gi2c->cur = NULL;
- gi2c->abort_done = false;
geni_se_abort_m_cmd(&gi2c->se);
spin_unlock_irqrestore(&gi2c->lock, flags);
- do {
- time_left = wait_for_completion_timeout(&gi2c->done, time_left);
- } while (!gi2c->abort_done && time_left);
-
+ time_left = wait_for_completion_timeout(&gi2c->abort_done, time_left);
if (!time_left)
dev_err(gi2c->se.dev, "Timeout abort_m_cmd\n");
}
@@ -414,31 +416,25 @@ static void geni_i2c_cancel_xfer(struct geni_i2c_dev *gi2c)
static void geni_i2c_rx_fsm_rst(struct geni_i2c_dev *gi2c)
{
- u32 val;
unsigned long time_left = RST_TIMEOUT;
+ reinit_completion(&gi2c->rx_reset_done);
writel_relaxed(1, gi2c->se.base + SE_DMA_RX_FSM_RST);
- do {
- time_left = wait_for_completion_timeout(&gi2c->done, time_left);
- val = readl_relaxed(gi2c->se.base + SE_DMA_RX_IRQ_STAT);
- } while (!(val & RX_RESET_DONE) && time_left);
- if (!(val & RX_RESET_DONE))
+ time_left = wait_for_completion_timeout(&gi2c->rx_reset_done, time_left);
+ if (!time_left)
dev_err(gi2c->se.dev, "Timeout resetting RX_FSM\n");
}
static void geni_i2c_tx_fsm_rst(struct geni_i2c_dev *gi2c)
{
- u32 val;
unsigned long time_left = RST_TIMEOUT;
+ reinit_completion(&gi2c->tx_reset_done);
writel_relaxed(1, gi2c->se.base + SE_DMA_TX_FSM_RST);
- do {
- time_left = wait_for_completion_timeout(&gi2c->done, time_left);
- val = readl_relaxed(gi2c->se.base + SE_DMA_TX_IRQ_STAT);
- } while (!(val & TX_RESET_DONE) && time_left);
- if (!(val & TX_RESET_DONE))
+ time_left = wait_for_completion_timeout(&gi2c->tx_reset_done, time_left);
+ if (!time_left)
dev_err(gi2c->se.dev, "Timeout resetting TX_FSM\n");
}
@@ -851,6 +847,7 @@ static int geni_i2c_gpi_xfer(struct geni_i2c_dev *gi2c, struct i2c_msg msgs[], i
for (i = 0; i < num; i++) {
gi2c->cur = &msgs[i];
gi2c->err = 0;
+ reinit_completion(&gi2c->done);
dev_dbg(gi2c->se.dev, "msg[%d].len:%d\n", i, gi2c->cur->len);
peripheral.stretch = 0;
@@ -920,6 +917,8 @@ static int geni_i2c_fifo_xfer(struct geni_i2c_dev *gi2c,
m_param |= ((msgs[i].addr << SLV_ADDR_SHFT) & SLV_ADDR_MSK);
gi2c->cur = &msgs[i];
+ gi2c->err = 0;
+ reinit_completion(&gi2c->done);
if (msgs[i].flags & I2C_M_RD)
ret = geni_i2c_rx_one_msg(gi2c, &msgs[i], m_param);
else
@@ -939,8 +938,6 @@ static int geni_i2c_xfer(struct i2c_adapter *adap,
struct geni_i2c_dev *gi2c = i2c_get_adapdata(adap);
int ret;
- gi2c->err = 0;
- reinit_completion(&gi2c->done);
ret = pm_runtime_get_sync(gi2c->se.dev);
if (ret < 0) {
dev_err(gi2c->se.dev, "error turning SE resources:%d\n", ret);
@@ -1132,7 +1129,10 @@ static int geni_i2c_probe(struct platform_device *pdev)
gi2c->adap.algo = &geni_i2c_algo;
init_completion(&gi2c->done);
+ init_completion(&gi2c->abort_done);
init_completion(&gi2c->cancel_done);
+ init_completion(&gi2c->tx_reset_done);
+ init_completion(&gi2c->rx_reset_done);
spin_lock_init(&gi2c->lock);
platform_set_drvdata(pdev, gi2c);
--
2.34.1
next prev parent reply other threads:[~2026-07-09 4:21 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-09 4:20 [PATCH v2 0/3] i2c: qcom-geni: improve transfer error recovery and synchronization Praveen Talari
2026-07-09 4:20 ` [PATCH v2 1/3] i2c: qcom-geni: use cancel command before abort on transfer timeout Praveen Talari
2026-07-09 4:20 ` Praveen Talari [this message]
2026-07-10 6:28 ` [PATCH v2 2/3] i2c: qcom-geni: use dedicated completions for abort and reset events Mukesh Savaliya
2026-07-09 4:20 ` [PATCH v2 3/3] i2c: qcom-geni: distinguish address-phase and data-phase NACK Praveen Talari
2026-07-10 11:36 ` Mukesh Savaliya
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260709-fix_cancel_sequence_on_failure_for_i2c-v2-2-1db178c695bb@oss.qualcomm.com \
--to=praveen.talari@oss.qualcomm.com \
--cc=andi.shyti@kernel.org \
--cc=linux-arm-msm@vger.kernel.org \
--cc=linux-i2c@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=mukesh.savaliya@oss.qualcomm.com \
--cc=naresh.maramaina@oss.qualcomm.com \
--cc=viken.dadhaniya@oss.qualcomm.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®