From 052480e3e5042375b1eaf4d2a00085651c458c5d Mon Sep 17 00:00:00 2001 From: Mukesh Kumar Savaliya Date: Mon, 11 Oct 2021 15:17:30 +0530 Subject: [PATCH] i2c: i2c-msm-geni: WAR to halt cancel if IOS not in good state This change halts cancel command operation if IOS lines not in good state for i2c due to Power or slave side issue. Perform cancel once IO lines comes to good state. Till that i2c transfer will not be servied. This is a workaround fix if the abort is failing after cancel and never recovers. Change-Id: Icca5904d0d3df7432b948343ef9396cb25d93cd0 Signed-off-by: Mukesh Kumar Savaliya --- drivers/i2c/busses/i2c-msm-geni.c | 84 +++++++++++++++++++++++++------ 1 file changed, 69 insertions(+), 15 deletions(-) diff --git a/drivers/i2c/busses/i2c-msm-geni.c b/drivers/i2c/busses/i2c-msm-geni.c index d1c7af60c50f..21b2dcfd8a6d 100644 --- a/drivers/i2c/busses/i2c-msm-geni.c +++ b/drivers/i2c/busses/i2c-msm-geni.c @@ -134,6 +134,7 @@ struct geni_i2c_dev { bool first_resume; bool gpi_reset; bool disable_dma_mode; + bool prev_cancel_pending; //Halt cancel till IOS in good state }; static struct geni_i2c_dev *gi2c_dev_dbg[MAX_SE]; @@ -241,10 +242,45 @@ err_ret: gi2c->err = gi2c_log[err].err; } -static int geni_i2c_prepare(struct geni_i2c_dev *gi2c) +static int do_pending_cancel(struct geni_i2c_dev *gi2c) { + int timeout = 0; u32 geni_ios = 0; + geni_ios = geni_read_reg_nolog(gi2c->base, SE_GENI_IOS); + if ((geni_ios & 0x3) != 0x3) { + GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev, + "%s: Can't do pending cancel, IOS bad state: 0x%x\n", + __func__, geni_ios); + return -EINVAL; + } + + if (gi2c->se_mode == GSI_ONLY) { + dmaengine_terminate_all(gi2c->tx_c); + gi2c->cfg_sent = 0; + } else { + reinit_completion(&gi2c->xfer); + geni_cancel_m_cmd(gi2c->base); + timeout = wait_for_completion_timeout(&gi2c->xfer, HZ); + if (!timeout) { + GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev, + "%s:Pending Cancel failed\n", __func__); + reinit_completion(&gi2c->xfer); + geni_abort_m_cmd(gi2c->base); + timeout = wait_for_completion_timeout(&gi2c->xfer, HZ); + if (!timeout) + GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev, + "%s:Abort failed\n", __func__); + } + } + gi2c->prev_cancel_pending = false; + GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev, + "%s: Pending Cancel done\n", __func__); + return timeout; +} + +static int geni_i2c_prepare(struct geni_i2c_dev *gi2c) +{ if (gi2c->se_mode == UNINITIALIZED) { int proto = get_se_proto(gi2c->base); u32 se_mode; @@ -256,16 +292,6 @@ static int geni_i2c_prepare(struct geni_i2c_dev *gi2c) return -ENXIO; } - geni_ios = geni_read_reg_nolog(gi2c->base, SE_GENI_IOS); - if ((geni_ios & 0x3) != 0x3) { //SCL:b'1, SDA:b'0 - GENI_SE_DBG(gi2c->ipcl, true, gi2c->dev, - "IO lines not in good state, Check power to slave\n"); - - if (!gi2c->is_le_vm) - se_geni_resources_off(&gi2c->i2c_rsc); - return -ENXIO; - } - se_mode = readl_relaxed(gi2c->base + GENI_IF_FIFO_DISABLE_RO); if (se_mode) { @@ -933,6 +959,8 @@ static int geni_i2c_gsi_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], timeout = wait_for_completion_timeout(&gi2c->xfer, gi2c->xfer_timeout); if (!timeout) { + u32 geni_ios = 0; + GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev, "I2C gsi xfer timeout:%u flags:%d addr:0x%x\n", gi2c->xfer_timeout, gi2c->cur->flags, @@ -940,6 +968,15 @@ static int geni_i2c_gsi_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], geni_se_dump_dbg_regs(&gi2c->i2c_rsc, gi2c->base, gi2c->ipcl); gi2c->err = -ETIMEDOUT; + + /* WAR: Set flag to mark cancel pending if IOS stuck */ + geni_ios = geni_read_reg_nolog(gi2c->base, SE_GENI_IOS); + if ((geni_ios & 0x3) != 0x3) { //SCL:b'1, SDA:b'0 + GENI_SE_DBG(gi2c->ipcl, true, gi2c->dev, + "%s: IO lines not in good state\n", __func__); + gi2c->prev_cancel_pending = true; + goto geni_i2c_gsi_cancel_pending; + } } geni_i2c_err_prep_sg: if (gi2c->err) { @@ -962,6 +999,7 @@ geni_i2c_err_prep_sg: /* Resend cfg tre for every new message on shared se */ gi2c->cfg_sent = 0; +geni_i2c_gsi_cancel_pending: if (msgs[i].flags & I2C_M_RD) geni_se_iommu_unmap_buf(rx_dev, &gi2c->rx_ph, msgs[i].len, DMA_FROM_DEVICE); @@ -1007,6 +1045,13 @@ static int geni_i2c_xfer(struct i2c_adapter *adap, } } + // WAR : Complete previous pending cancel cmd + if (gi2c->prev_cancel_pending) { + ret = do_pending_cancel(gi2c); + if (ret) + return ret; //Don't perform xfer is cancel failed + } + GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev, "n:%d addr:0x%x\n", num, msgs[0].addr); @@ -1124,9 +1169,20 @@ static int geni_i2c_xfer(struct i2c_adapter *adap, timeout = wait_for_completion_timeout(&gi2c->xfer, gi2c->xfer_timeout); if (!timeout) { + u32 geni_ios = 0; + GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev, "I2C xfer timeout: %d\n", gi2c->xfer_timeout); geni_i2c_err(gi2c, GENI_TIMEOUT); + + /* WAR: Set flag to mark cancel pending if IOS bad */ + geni_ios = geni_read_reg_nolog(gi2c->base, SE_GENI_IOS); + if ((geni_ios & 0x3) != 0x3) { //SCL:b'1, SDA:b'0 + GENI_SE_DBG(gi2c->ipcl, true, gi2c->dev, + "%s: IO lines not in good state\n", __func__); + gi2c->prev_cancel_pending = true; + goto geni_i2c_txn_ret; + } } if (gi2c->err) { @@ -1453,19 +1509,17 @@ static int geni_i2c_runtime_resume(struct device *dev) if (!gi2c->is_le_vm) { /* Do not control clk/gpio/icb for LE-VM */ ret = se_geni_resources_on(&gi2c->i2c_rsc); - if (ret) return ret; ret = geni_i2c_prepare(gi2c); if (ret) { - dev_err(gi2c->dev, "I2C prepare failed\n"); + dev_err(gi2c->dev, "I2C prepare failed: %d\n", ret); return ret; } if (gi2c->se_mode == FIFO_SE_DMA) enable_irq(gi2c->irq); - } else if (!gi2c->first_resume) { /* * For first resume call in le, do nothing, and in @@ -1475,7 +1529,7 @@ static int geni_i2c_runtime_resume(struct device *dev) */ ret = geni_i2c_prepare(gi2c); if (ret) { - dev_err(gi2c->dev, "I2C prepare failed\n"); + dev_err(gi2c->dev, "I2C prepare failed:%d\n", ret); return ret; }