[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-Id: <20240307205539.217204-1-quic_msavaliy@quicinc.com>
Date: Fri, 8 Mar 2024 02:25:39 +0530
From: Mukesh Kumar Savaliya <quic_msavaliy@...cinc.com>
To: konrad.dybcio@...aro.org, andersson@...nel.org, vkoul@...nel.org,
andi.shyti@...nel.org, wsa@...nel.org, linux-arm-msm@...r.kernel.org,
dmaengine@...r.kernel.org, linux-kernel@...r.kernel.org,
linux-i2c@...r.kernel.org
Cc: quic_vdadhani@...cinc.com,
Mukesh Kumar Savaliya <quic_msavaliy@...cinc.com>
Subject: [PATCH v3] i2c: i2c-qcom-geni: Parse Error correctly in i2c GSI mode
I2C driver currently reports "DMA txn failed" error even though it's
NACK OR BUS_PROTO OR ARB_LOST. Detect NACK error when no device ACKs
on the bus instead of generic transfer failure which doesn't give any
specific clue.
Make Changes inside i2c driver callback handler function
i2c_gpi_cb_result() to parse these errors and make sure GSI driver
stores the error status during error interrupt.
Fixes: d8703554f4de ("i2c: qcom-geni: Add support for GPI DMA")
Co-developed-by: Viken Dadhaniya <quic_vdadhani@...cinc.com>
Signed-off-by: Viken Dadhaniya <quic_vdadhani@...cinc.com>
Signed-off-by: Mukesh Kumar Savaliya <quic_msavaliy@...cinc.com>
---
v2 -> v3:
- Modifed commit log reflecting an imperative mood.
v1 -> v2:
- Commit log changed we->We.
- Explained the problem that we are not detecing NACK error.
- Removed Heap based memory allocation and hence memory leakage issue.
- Used FIELD_GET and removed shiting and masking every time as suggested by Bjorn.
- Changed commit log to reflect the code changes done.
- Removed adding anything into struct gpi_i2c_config and created new structure
for error status as suggested by Bjorn.
---
drivers/dma/qcom/gpi.c | 12 +++++++++++-
drivers/i2c/busses/i2c-qcom-geni.c | 19 +++++++++++++++----
include/linux/dma/qcom-gpi-dma.h | 10 ++++++++++
3 files changed, 36 insertions(+), 5 deletions(-)
diff --git a/drivers/dma/qcom/gpi.c b/drivers/dma/qcom/gpi.c
index 1c93864e0e4d..e3508d51fdc9 100644
--- a/drivers/dma/qcom/gpi.c
+++ b/drivers/dma/qcom/gpi.c
@@ -1076,7 +1076,17 @@ static void gpi_process_xfer_compl_event(struct gchan *gchan,
dev_dbg(gpii->gpi_dev->dev, "Residue %d\n", result.residue);
dma_cookie_complete(&vd->tx);
- dmaengine_desc_get_callback_invoke(&vd->tx, &result);
+ if (gchan->protocol == QCOM_GPI_I2C) {
+ struct dmaengine_desc_callback cb;
+ struct gpi_i2c_result *i2c;
+
+ dmaengine_desc_get_callback(&vd->tx, &cb);
+ i2c = cb.callback_param;
+ i2c->status = compl_event->status;
+ dmaengine_desc_callback_invoke(&cb, &result);
+ } else {
+ dmaengine_desc_get_callback_invoke(&vd->tx, &result);
+ }
gpi_free_desc:
spin_lock_irqsave(&gchan->vc.lock, flags);
diff --git a/drivers/i2c/busses/i2c-qcom-geni.c b/drivers/i2c/busses/i2c-qcom-geni.c
index da94df466e83..36a7c0c0ff54 100644
--- a/drivers/i2c/busses/i2c-qcom-geni.c
+++ b/drivers/i2c/busses/i2c-qcom-geni.c
@@ -66,6 +66,7 @@ enum geni_i2c_err_code {
GENI_TIMEOUT,
};
+#define I2C_DMA_TX_IRQ_MASK GENMASK(12, 5)
#define DM_I2C_CB_ERR ((BIT(NACK) | BIT(BUS_PROTO) | BIT(ARB_LOST)) \
<< 5)
@@ -99,6 +100,7 @@ struct geni_i2c_dev {
struct dma_chan *rx_c;
bool gpi_mode;
bool abort_done;
+ struct gpi_i2c_result i2c_result;
};
struct geni_i2c_desc {
@@ -484,9 +486,18 @@ static int geni_i2c_tx_one_msg(struct geni_i2c_dev *gi2c, struct i2c_msg *msg,
static void i2c_gpi_cb_result(void *cb, const struct dmaengine_result *result)
{
- struct geni_i2c_dev *gi2c = cb;
-
- if (result->result != DMA_TRANS_NOERROR) {
+ struct gpi_i2c_result *i2c_res = cb;
+ struct geni_i2c_dev *gi2c = container_of(i2c_res, struct geni_i2c_dev, i2c_result);
+ u32 status;
+
+ status = FIELD_GET(I2C_DMA_TX_IRQ_MASK, i2c_res->status);
+ if (status == BIT(NACK)) {
+ geni_i2c_err(gi2c, NACK);
+ } else if (status == BIT(BUS_PROTO)) {
+ geni_i2c_err(gi2c, BUS_PROTO);
+ } else if (status == BIT(ARB_LOST)) {
+ geni_i2c_err(gi2c, ARB_LOST);
+ } else if (result->result != DMA_TRANS_NOERROR) {
dev_err(gi2c->se.dev, "DMA txn failed:%d\n", result->result);
gi2c->err = -EIO;
} else if (result->residue) {
@@ -568,7 +579,7 @@ static int geni_i2c_gpi(struct geni_i2c_dev *gi2c, struct i2c_msg *msg,
}
desc->callback_result = i2c_gpi_cb_result;
- desc->callback_param = gi2c;
+ desc->callback_param = &gi2c->i2c_result;
dmaengine_submit(desc);
*buf = dma_buf;
diff --git a/include/linux/dma/qcom-gpi-dma.h b/include/linux/dma/qcom-gpi-dma.h
index 6680dd1a43c6..f585c6a35e51 100644
--- a/include/linux/dma/qcom-gpi-dma.h
+++ b/include/linux/dma/qcom-gpi-dma.h
@@ -80,4 +80,14 @@ struct gpi_i2c_config {
bool multi_msg;
};
+/**
+ * struct gpi_i2c_result - i2c transfer status result in GSI mode
+ *
+ * @status: store txfer status value as part of callback
+ *
+ */
+struct gpi_i2c_result {
+ u32 status;
+};
+
#endif /* QCOM_GPI_DMA_H */
--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project
Powered by blists - more mailing lists