On 13-03-24, 10:56, Mukesh Kumar Savaliya wrote: > 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. > > Co-developed-by: Viken Dadhaniya <quic_vdadhani@xxxxxxxxxxx> > Signed-off-by: Viken Dadhaniya <quic_vdadhani@xxxxxxxxxxx> > Signed-off-by: Mukesh Kumar Savaliya <quic_msavaliy@xxxxxxxxxxx> > Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@xxxxxxxxxx> > --- > v3 -> v4: > - Included bitfield.h to fix compilation issue for x86 arch. > - Removed Fixes tag as this is not fixing any crash. > - Added Reviewed-by tag. > > 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 | 20 ++++++++++++++++---- > include/linux/dma/qcom-gpi-dma.h | 10 ++++++++++ > 3 files changed, 37 insertions(+), 5 deletions(-) Urgh, why do we have i2c and dma changes in single patch? I dont think they would be dependent > > 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); This is generic, why should this be i2c specific... we should set generic status value > + } 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..11dcfcf13d8b 100644 > --- a/drivers/i2c/busses/i2c-qcom-geni.c > +++ b/drivers/i2c/busses/i2c-qcom-geni.c > @@ -2,6 +2,7 @@ > // Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. > > #include <linux/acpi.h> > +#include <linux/bitfield.h> > #include <linux/clk.h> > #include <linux/dmaengine.h> > #include <linux/dma-mapping.h> > @@ -66,6 +67,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 +101,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 +487,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 +580,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 -- ~Vinod