From 22cec88da571b681322a4caea76bb1b978deaa3e Mon Sep 17 00:00:00 2001 From: Vipin Deep Kaur Date: Mon, 4 Nov 2019 11:51:03 +0530 Subject: [PATCH] i2c: i2c-qcom-geni: Add lock and unlock tre support in I2C GSI mode Add lock and unlock tre support in I2C GSI mode for shared se so that none of the concurrent GPIIs will be able to perform any transfer while SE is exclusively locked by a GPII. Change-Id: Iacf489f1cda55c85464651120e0c5e39278221ac Signed-off-by: Vipin Deep Kaur --- drivers/dma/qcom/gpi.c | 70 ++++++++++++++++-------------- drivers/dma/qcom/msm_gpi_mmio.h | 4 ++ drivers/i2c/busses/i2c-qcom-geni.c | 69 +++++++++++++++++++++++------ drivers/spi/spi-geni-qcom.c | 2 +- include/linux/msm_gpi.h | 16 +++++++ 5 files changed, 114 insertions(+), 47 deletions(-) diff --git a/drivers/dma/qcom/gpi.c b/drivers/dma/qcom/gpi.c index c23b191790f9..8401e7d14f67 100644 --- a/drivers/dma/qcom/gpi.c +++ b/drivers/dma/qcom/gpi.c @@ -447,7 +447,8 @@ struct gpi_dev { struct dentry *dentry; }; -static struct gpi_dev *gpi_dev_dbg; +static struct gpi_dev *gpi_dev_dbg[5]; +static int arr_idx; struct reg_info { char *name; @@ -581,6 +582,7 @@ struct gpii { struct gpi_reg_table dbg_reg_table; bool reg_table_dump; u32 dbg_gpi_irq_cnt; + bool ieob_set; }; struct gpi_desc { @@ -1496,20 +1498,6 @@ static void gpi_process_imed_data_event(struct gpii_chan *gpii_chan, return; } gpi_desc = to_gpi_desc(vd); - - /* Event TR RP gen. don't match descriptor TR */ - if (gpi_desc->wp != tre) { - spin_unlock_irqrestore(&gpii_chan->vc.lock, flags); - GPII_ERR(gpii, gpii_chan->chid, - "EOT/EOB received for wrong TRE 0x%0llx != 0x%0llx\n", - to_physical(ch_ring, gpi_desc->wp), - to_physical(ch_ring, tre)); - gpi_generate_cb_event(gpii_chan, MSM_GPI_QUP_EOT_DESC_MISMATCH, - __LINE__); - return; - } - - list_del(&vd->node); spin_unlock_irqrestore(&gpii_chan->vc.lock, flags); @@ -1525,6 +1513,9 @@ static void gpi_process_imed_data_event(struct gpii_chan *gpii_chan, /* make sure rp updates are immediately visible to all cores */ smp_wmb(); + if (imed_event->code == MSM_GPI_TCE_EOT && gpii->ieob_set) + return; + tx_cb_param = vd->tx.callback_param; if (vd->tx.callback && tx_cb_param) { struct msm_gpi_tre *imed_tre = &tx_cb_param->imed_tre; @@ -1540,7 +1531,12 @@ static void gpi_process_imed_data_event(struct gpii_chan *gpii_chan, tx_cb_param->status = imed_event->status; vd->tx.callback(tx_cb_param); } + + spin_lock_irqsave(&gpii_chan->vc.lock, flags); + list_del(&vd->node); + spin_unlock_irqrestore(&gpii_chan->vc.lock, flags); kfree(gpi_desc); + gpi_desc = NULL; } /* processing transfer completion events */ @@ -1583,20 +1579,6 @@ static void gpi_process_xfer_compl_event(struct gpii_chan *gpii_chan, } gpi_desc = to_gpi_desc(vd); - - /* TRE Event generated didn't match descriptor's TRE */ - if (gpi_desc->wp != ev_rp) { - spin_unlock_irqrestore(&gpii_chan->vc.lock, flags); - GPII_ERR(gpii, gpii_chan->chid, - "EOT\EOB received for wrong TRE 0x%0llx != 0x%0llx\n", - to_physical(ch_ring, gpi_desc->wp), - to_physical(ch_ring, ev_rp)); - gpi_generate_cb_event(gpii_chan, MSM_GPI_QUP_EOT_DESC_MISMATCH, - __LINE__); - return; - } - - list_del(&vd->node); spin_unlock_irqrestore(&gpii_chan->vc.lock, flags); @@ -1612,6 +1594,9 @@ static void gpi_process_xfer_compl_event(struct gpii_chan *gpii_chan, /* update must be visible to other cores */ smp_wmb(); + if (compl_event->code == MSM_GPI_TCE_EOT && gpii->ieob_set) + return; + tx_cb_param = vd->tx.callback_param; if (vd->tx.callback && tx_cb_param) { GPII_VERB(gpii, gpii_chan->chid, @@ -1623,7 +1608,13 @@ static void gpi_process_xfer_compl_event(struct gpii_chan *gpii_chan, tx_cb_param->status = compl_event->status; vd->tx.callback(tx_cb_param); } + + spin_lock_irqsave(&gpii_chan->vc.lock, flags); + list_del(&vd->node); + spin_unlock_irqrestore(&gpii_chan->vc.lock, flags); kfree(gpi_desc); + gpi_desc = NULL; + } /* process all events */ @@ -2299,6 +2290,7 @@ void gpi_desc_free(struct virt_dma_desc *vd) struct gpi_desc *gpi_desc = to_gpi_desc(vd); kfree(gpi_desc); + gpi_desc = NULL; } /* copy tre into transfer ring */ @@ -2319,6 +2311,7 @@ struct dma_async_tx_descriptor *gpi_prep_slave_sg(struct dma_chan *chan, void *tre, *wp = NULL; const gfp_t gfp = GFP_ATOMIC; struct gpi_desc *gpi_desc; + gpii->ieob_set = false; GPII_VERB(gpii, gpii_chan->chid, "enter\n"); @@ -2352,10 +2345,22 @@ struct dma_async_tx_descriptor *gpi_prep_slave_sg(struct dma_chan *chan, } /* copy each tre into transfer ring */ - for_each_sg(sgl, sg, sg_len, i) - for (j = 0, tre = sg_virt(sg); j < sg->length; + for_each_sg(sgl, sg, sg_len, i) { + tre = sg_virt(sg); + + /* Check if last tre has ieob set */ + if (i == sg_len - 1) { + if ((((struct msm_gpi_tre *)tre)->dword[3] & + GPI_IEOB_BMSK) >> GPI_IEOB_BMSK_SHIFT) + gpii->ieob_set = true; + else + gpii->ieob_set = false; + } + + for (j = 0; j < sg->length; j += ch_ring->el_size, tre += ch_ring->el_size) gpi_queue_xfer(gpii, gpii_chan, tre, &wp); + } /* set up the descriptor */ gpi_desc->db = ch_ring->wp; @@ -2807,7 +2812,8 @@ static int gpi_probe(struct platform_device *pdev) return -ENOMEM; /* debug purpose */ - gpi_dev_dbg = gpi_dev; + gpi_dev_dbg[arr_idx] = gpi_dev; + arr_idx++; gpi_dev->dev = &pdev->dev; gpi_dev->klog_lvl = DEFAULT_KLOG_LVL; diff --git a/drivers/dma/qcom/msm_gpi_mmio.h b/drivers/dma/qcom/msm_gpi_mmio.h index 46ed27e3ed92..74a390b21dab 100644 --- a/drivers/dma/qcom/msm_gpi_mmio.h +++ b/drivers/dma/qcom/msm_gpi_mmio.h @@ -228,3 +228,7 @@ enum CNTXT_OFFS { #define GPI_DEBUG_QSB_LOG_1 (0x5068) #define GPI_DEBUG_QSB_LOG_2 (0x506C) #define GPI_DEBUG_QSB_LOG_LAST_MISC_ID(n) (0x5070 + (0x4*n)) + +/* IEOB bit set */ +#define GPI_IEOB_BMSK (0x100) +#define GPI_IEOB_BMSK_SHIFT (8) diff --git a/drivers/i2c/busses/i2c-qcom-geni.c b/drivers/i2c/busses/i2c-qcom-geni.c index 3cd43f53d6ca..07bb152d09ad 100644 --- a/drivers/i2c/busses/i2c-qcom-geni.c +++ b/drivers/i2c/busses/i2c-qcom-geni.c @@ -98,6 +98,8 @@ struct geni_i2c_dev { int clk_fld_idx; struct dma_chan *tx_c; struct dma_chan *rx_c; + struct msm_gpi_tre lock_t; + struct msm_gpi_tre unlock_t; struct msm_gpi_tre cfg0_t; struct msm_gpi_tre go_t; struct msm_gpi_tre tx_t; @@ -370,9 +372,9 @@ static void gi2c_ev_cb(struct dma_chan *ch, struct msm_gpi_cb const *cb_str, } if (cb_str->cb_event != MSM_GPI_QUP_NOTIFY) GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev, - "GSI QN err:0x%x, status:0x%x, err:%d\n", - cb_str->error_log.error_code, - m_stat, cb_str->cb_event); + "GSI QN err:0x%x, status:0x%x, err:%d slv_addr: 0x%x R/W: %d\n", + cb_str->error_log.error_code, m_stat, + cb_str->cb_event, gi2c->cur->addr, gi2c->cur->flags); } static void gi2c_gsi_cb_err(struct msm_gpi_dma_async_tx_cb_param *cb, @@ -398,7 +400,9 @@ static void gi2c_gsi_tx_cb(void *ptr) struct msm_gpi_dma_async_tx_cb_param *tx_cb = ptr; struct geni_i2c_dev *gi2c = tx_cb->userdata; - if (!(gi2c->cur->flags & I2C_M_RD)) { + if (tx_cb->completion_code == MSM_GPI_TCE_EOB) { + complete(&gi2c->xfer); + } else if (!(gi2c->cur->flags & I2C_M_RD)) { gi2c_gsi_cb_err(tx_cb, "TX"); complete(&gi2c->xfer); } @@ -460,6 +464,23 @@ static int geni_i2c_gsi_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], } } + if (gi2c->is_shared) { + struct msm_gpi_tre *lock_t = &gi2c->lock_t; + struct msm_gpi_tre *unlock_t = &gi2c->unlock_t; + + /* lock */ + lock_t->dword[0] = MSM_GPI_LOCK_TRE_DWORD0; + lock_t->dword[1] = MSM_GPI_LOCK_TRE_DWORD1; + lock_t->dword[2] = MSM_GPI_LOCK_TRE_DWORD2; + lock_t->dword[3] = MSM_GPI_LOCK_TRE_DWORD3(0, 0, 0, 0, 1); + + /* unlock */ + unlock_t->dword[0] = MSM_GPI_UNLOCK_TRE_DWORD0; + unlock_t->dword[1] = MSM_GPI_UNLOCK_TRE_DWORD1; + unlock_t->dword[2] = MSM_GPI_UNLOCK_TRE_DWORD2; + unlock_t->dword[3] = MSM_GPI_UNLOCK_TRE_DWORD3(0, 0, 0, 1, 0); + } + if (!gi2c->cfg_sent) { struct geni_i2c_clk_fld *itr = geni_i2c_clk_map + gi2c->clk_fld_idx; @@ -499,24 +520,34 @@ static int geni_i2c_gsi_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], } qcom_geni_i2c_calc_timeout(gi2c); - if (!gi2c->cfg_sent) { + + if (!gi2c->cfg_sent) segs++; + if (gi2c->is_shared && (i == 0 || i == num-1)) { + segs++; + if (num == 1) + segs++; sg_init_table(gi2c->tx_sg, segs); - sg_set_buf(gi2c->tx_sg, &gi2c->cfg0_t, - sizeof(gi2c->cfg0_t)); - gi2c->cfg_sent = 1; - index++; + if (i == 0) + sg_set_buf(&gi2c->tx_sg[index++], &gi2c->lock_t, + sizeof(gi2c->lock_t)); } else { sg_init_table(gi2c->tx_sg, segs); } + if (!gi2c->cfg_sent) { + sg_set_buf(&gi2c->tx_sg[index++], &gi2c->cfg0_t, + sizeof(gi2c->cfg0_t)); + gi2c->cfg_sent = 1; + } + go_t->dword[0] = MSM_GPI_I2C_GO_TRE_DWORD0((stretch << 2), msgs[i].addr, op); go_t->dword[1] = MSM_GPI_I2C_GO_TRE_DWORD1; if (msgs[i].flags & I2C_M_RD) { go_t->dword[2] = MSM_GPI_I2C_GO_TRE_DWORD2(msgs[i].len); - go_t->dword[3] = MSM_GPI_I2C_GO_TRE_DWORD3(1, 0, 0, 1, + go_t->dword[3] = MSM_GPI_I2C_GO_TRE_DWORD3(1, 0, 0, 0, 0); } else { go_t->dword[2] = MSM_GPI_I2C_GO_TRE_DWORD2(0); @@ -588,13 +619,22 @@ static int geni_i2c_gsi_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], MSM_GPI_DMA_W_BUFFER_TRE_DWORD1(gi2c->tx_ph); gi2c->tx_t.dword[2] = MSM_GPI_DMA_W_BUFFER_TRE_DWORD2(msgs[i].len); - gi2c->tx_t.dword[3] = + if (gi2c->is_shared && i == num-1) + gi2c->tx_t.dword[3] = + MSM_GPI_DMA_W_BUFFER_TRE_DWORD3(0, 0, 1, 0, 1); + else + gi2c->tx_t.dword[3] = MSM_GPI_DMA_W_BUFFER_TRE_DWORD3(0, 0, 1, 0, 0); sg_set_buf(&gi2c->tx_sg[index++], &gi2c->tx_t, sizeof(gi2c->tx_t)); } + if (gi2c->is_shared && i == num-1) { + sg_set_buf(&gi2c->tx_sg[index++], + &gi2c->unlock_t, sizeof(gi2c->unlock_t)); + } + gi2c->tx_desc = dmaengine_prep_slave_sg(gi2c->tx_c, gi2c->tx_sg, segs, DMA_MEM_TO_DEV, (DMA_PREP_INTERRUPT | @@ -616,8 +656,9 @@ static int geni_i2c_gsi_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], gi2c->xfer_timeout); if (!timeout) { GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev, - "GSI Txn timed out: %u len: %d\n", - gi2c->xfer_timeout, gi2c->cur->len); + "GSI Txn timed out: %u len: %d slv:addr: 0x%x R/W: %d\n", + gi2c->xfer_timeout, gi2c->cur->len, + gi2c->cur->addr, gi2c->cur->flags); geni_se_dump_dbg_regs(&gi2c->i2c_rsc, gi2c->base, gi2c->ipcl); gi2c->err = -ETIMEDOUT; @@ -1001,7 +1042,7 @@ static int geni_i2c_runtime_resume(struct device *dev) if (!gi2c->ipcl) { char ipc_name[I2C_NAME_SIZE]; - snprintf(ipc_name, I2C_NAME_SIZE, "i2c-%d", gi2c->adap.nr); + snprintf(ipc_name, I2C_NAME_SIZE, "%s", dev_name(gi2c->dev)); gi2c->ipcl = ipc_log_context_create(2, ipc_name, 0); } diff --git a/drivers/spi/spi-geni-qcom.c b/drivers/spi/spi-geni-qcom.c index e704a96cce74..373e5f00ec01 100644 --- a/drivers/spi/spi-geni-qcom.c +++ b/drivers/spi/spi-geni-qcom.c @@ -397,7 +397,7 @@ static struct msm_gpi_tre *setup_go_tre(int cmd, int cs, int rx_len, int flags, if (cmd == SPI_RX_ONLY) { eot = 0; chain = 0; - eob = 1; + eob = 0; } else { eot = 0; chain = 1; diff --git a/include/linux/msm_gpi.h b/include/linux/msm_gpi.h index 09d94f49ee0b..6925c97ae28f 100644 --- a/include/linux/msm_gpi.h +++ b/include/linux/msm_gpi.h @@ -27,6 +27,22 @@ enum msm_gpi_tre_type { #define MSM_GPI_TRE_TYPE(tre) ((tre->dword[3] >> 16) & 0xFF) +/* Lock TRE */ +#define MSM_GPI_LOCK_TRE_DWORD0 (0) +#define MSM_GPI_LOCK_TRE_DWORD1 (0) +#define MSM_GPI_LOCK_TRE_DWORD2 (0) +#define MSM_GPI_LOCK_TRE_DWORD3(link_rx, bei, ieot, ieob, ch) \ + ((0x3 << 20) | (0x0 << 16) | (link_rx << 11) | (bei << 10) | \ + (ieot << 9) | (ieob << 8) | ch) + +/* Unlock TRE */ +#define MSM_GPI_UNLOCK_TRE_DWORD0 (0) +#define MSM_GPI_UNLOCK_TRE_DWORD1 (0) +#define MSM_GPI_UNLOCK_TRE_DWORD2 (0) +#define MSM_GPI_UNLOCK_TRE_DWORD3(link_rx, bei, ieot, ieob, ch) \ + ((0x3 << 20) | (0x1 << 16) | (link_rx << 11) | (bei << 10) | \ + (ieot << 9) | (ieob << 8) | ch) + /* DMA w. Buffer TRE */ #define MSM_GPI_DMA_W_BUFFER_TRE_DWORD0(ptr) ((u32)ptr) #define MSM_GPI_DMA_W_BUFFER_TRE_DWORD1(ptr) ((u32)(ptr >> 32))