diff --git a/drivers/dma/qcom/gpi.c b/drivers/dma/qcom/gpi.c index 695c5cbae62b..69ce2ee4e797 100644 --- a/drivers/dma/qcom/gpi.c +++ b/drivers/dma/qcom/gpi.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #include @@ -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 unlock_tre_set; }; struct gpi_desc { @@ -1447,6 +1449,22 @@ static void gpi_process_qup_notif_event(struct gpii_chan *gpii_chan, client_info->cb_param); } +/* free gpi_desc for the specified channel */ +static void gpi_free_chan_desc(struct gpii_chan *gpii_chan) +{ + struct virt_dma_desc *vd; + struct gpi_desc *gpi_desc; + unsigned long flags; + + spin_lock_irqsave(&gpii_chan->vc.lock, flags); + vd = vchan_next_desc(&gpii_chan->vc); + gpi_desc = to_gpi_desc(vd); + list_del(&vd->node); + spin_unlock_irqrestore(&gpii_chan->vc.lock, flags); + kfree(gpi_desc); + gpi_desc = NULL; +} + /* process DMA Immediate completion data events */ static void gpi_process_imed_data_event(struct gpii_chan *gpii_chan, struct immediate_data_event *imed_event) @@ -1459,6 +1477,8 @@ static void gpi_process_imed_data_event(struct gpii_chan *gpii_chan, (ch_ring->el_size * imed_event->tre_index); struct msm_gpi_dma_async_tx_cb_param *tx_cb_param; unsigned long flags; + u32 chid; + struct gpii_chan *gpii_tx_chan = &gpii->gpii_chan[GPI_TX_CHAN]; /* * If channel not active don't process event but let @@ -1496,20 +1516,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 +1531,35 @@ 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 unlock tre is present, don't send transfer callback on + * on IEOT, wait for unlock IEOB. Free the respective channel + * descriptors. + * If unlock is not present, IEOB indicates freeing the descriptor + * and IEOT indicates channel transfer completion. + */ + chid = imed_event->chid; + if (gpii->unlock_tre_set) { + if (chid == GPI_RX_CHAN) { + if (imed_event->code == MSM_GPI_TCE_EOT) + goto gpi_free_desc; + else if (imed_event->code == MSM_GPI_TCE_UNEXP_ERR) + /* + * In case of an error in a read transfer on a + * shared se, unlock tre will not be processed + * as channels go to bad state so tx desc should + * be freed manually. + */ + gpi_free_chan_desc(gpii_tx_chan); + else + return; + } else if (imed_event->code == MSM_GPI_TCE_EOT) { + return; + } + } else if (imed_event->code == MSM_GPI_TCE_EOB) { + goto gpi_free_desc; + } + 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 +1575,9 @@ 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); } - kfree(gpi_desc); + +gpi_free_desc: + gpi_free_chan_desc(gpii_chan); } /* processing transfer completion events */ @@ -1554,6 +1591,8 @@ static void gpi_process_xfer_compl_event(struct gpii_chan *gpii_chan, struct msm_gpi_dma_async_tx_cb_param *tx_cb_param; struct gpi_desc *gpi_desc; unsigned long flags; + u32 chid; + struct gpii_chan *gpii_tx_chan = &gpii->gpii_chan[GPI_TX_CHAN]; /* only process events on active channel */ if (unlikely(gpii_chan->pm_state != ACTIVE_STATE)) { @@ -1583,20 +1622,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 +1637,35 @@ static void gpi_process_xfer_compl_event(struct gpii_chan *gpii_chan, /* update must be visible to other cores */ smp_wmb(); + /* + * If unlock tre is present, don't send transfer callback on + * on IEOT, wait for unlock IEOB. Free the respective channel + * descriptors. + * If unlock is not present, IEOB indicates freeing the descriptor + * and IEOT indicates channel transfer completion. + */ + chid = compl_event->chid; + if (gpii->unlock_tre_set) { + if (chid == GPI_RX_CHAN) { + if (compl_event->code == MSM_GPI_TCE_EOT) + goto gpi_free_desc; + else if (compl_event->code == MSM_GPI_TCE_UNEXP_ERR) + /* + * In case of an error in a read transfer on a + * shared se, unlock tre will not be processed + * as channels go to bad state so tx desc should + * be freed manually. + */ + gpi_free_chan_desc(gpii_tx_chan); + else + return; + } else if (compl_event->code == MSM_GPI_TCE_EOT) { + return; + } + } else if (compl_event->code == MSM_GPI_TCE_EOB) { + goto gpi_free_desc; + } + tx_cb_param = vd->tx.callback_param; if (vd->tx.callback && tx_cb_param) { GPII_VERB(gpii, gpii_chan->chid, @@ -1623,7 +1677,10 @@ 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); } - kfree(gpi_desc); + +gpi_free_desc: + gpi_free_chan_desc(gpii_chan); + } /* process all events */ @@ -2299,6 +2356,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 +2377,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; + u32 tre_type; GPII_VERB(gpii, gpii_chan->chid, "enter\n"); @@ -2352,10 +2411,21 @@ 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 is an unlock tre */ + if (i == sg_len - 1) { + tre_type = + MSM_GPI_TRE_TYPE(((struct msm_gpi_tre *)tre)); + gpii->unlock_tre_set = + tre_type == MSM_GPI_TRE_UNLOCK ? true : 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 +2877,7 @@ static int gpi_probe(struct platform_device *pdev) return -ENOMEM; /* debug purpose */ - gpi_dev_dbg = gpi_dev; + gpi_dev_dbg[arr_idx++] = gpi_dev; gpi_dev->dev = &pdev->dev; gpi_dev->klog_lvl = DEFAULT_KLOG_LVL; @@ -3018,6 +3088,10 @@ static int gpi_remove(struct platform_device *pdev) ipc_log_context_destroy(gpii->ilctxt); } + for (i = 0; i < arr_idx; i++) + gpi_dev_dbg[i] = NULL; + arr_idx = 0; + if (gpi_dev->ilctxt) ipc_log_context_destroy(gpi_dev->ilctxt); diff --git a/drivers/i2c/busses/i2c-msm-geni.c b/drivers/i2c/busses/i2c-msm-geni.c index a71dcbbd5ec5..0d9e991b219b 100644 --- a/drivers/i2c/busses/i2c-msm-geni.c +++ b/drivers/i2c/busses/i2c-msm-geni.c @@ -21,6 +21,7 @@ #include #include #include +#include #define SE_I2C_TX_TRANS_LEN (0x26C) #define SE_I2C_RX_TRANS_LEN (0x270) @@ -73,12 +74,19 @@ #define I2C_TIMEOUT_MIN_USEC 500000 +#define MAX_SE 20 + enum i2c_se_mode { UNINITIALIZED, FIFO_SE_DMA, GSI_ONLY, }; +struct dbg_buf_ctxt { + void *virt_buf; + void *map_buf; +}; + struct geni_i2c_dev { struct device *dev; void __iomem *base; @@ -97,6 +105,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; @@ -115,9 +125,14 @@ struct geni_i2c_dev { enum i2c_se_mode se_mode; bool cmd_done; bool is_shared; + u32 dbg_num; + struct dbg_buf_ctxt *dbg_buf_ptr; bool is_le_vm; }; +static struct geni_i2c_dev *gi2c_dev_dbg[MAX_SE]; +static int arr_idx; + struct geni_i2c_err_log { int err; const char *msg; @@ -207,12 +222,6 @@ static inline void qcom_geni_i2c_calc_timeout(struct geni_i2c_dev *gi2c) static void geni_i2c_err(struct geni_i2c_dev *gi2c, int err) { - if (gi2c->cur) - GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev, - "len:%d, slv-addr:0x%x, RD/WR:%d timeout:%u\n", - gi2c->cur->len, gi2c->cur->addr, gi2c->cur->flags, - gi2c->xfer_timeout); - if (err == I2C_NACK || err == GENI_ABORT_DONE) { GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev, "%s\n", gi2c_log[err].msg); @@ -221,8 +230,6 @@ static void geni_i2c_err(struct geni_i2c_dev *gi2c, int err) GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev, "%s\n", gi2c_log[err].msg); } - GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev, "%s: se-mode:%d\n", __func__, - gi2c->se_mode); geni_se_dump_dbg_regs(&gi2c->i2c_rsc, gi2c->base, gi2c->ipcl); err_ret: gi2c->err = gi2c_log[err].err; @@ -275,7 +282,13 @@ static irqreturn_t geni_i2c_irq(int irq, void *dev) u32 dma = readl_relaxed(gi2c->base + SE_GENI_DMA_MODE_EN); struct i2c_msg *cur = gi2c->cur; - if (!cur || (m_stat & M_CMD_FAILURE_EN) || + if (!cur) { + geni_se_dump_dbg_regs(&gi2c->i2c_rsc, gi2c->base, gi2c->ipcl); + GENI_SE_ERR(gi2c->ipcl, false, gi2c->dev, "Spurious irq\n"); + goto irqret; + } + + if ((m_stat & M_CMD_FAILURE_EN) || (dm_rx_st & (DM_I2C_CB_ERR)) || (m_stat & M_CMD_CANCEL_EN) || (m_stat & M_CMD_ABORT_EN)) { @@ -302,12 +315,6 @@ static irqreturn_t geni_i2c_irq(int irq, void *dev) goto irqret; } - if (dma) { - dev_dbg(gi2c->dev, "i2c dma tx:0x%x, dma rx:0x%x\n", dm_tx_st, - dm_rx_st); - goto irqret; - } - if (((m_stat & M_RX_FIFO_WATERMARK_EN) || (m_stat & M_RX_FIFO_LAST_EN)) && (cur->flags & I2C_M_RD)) { u32 rxcnt = rx_st & RX_FIFO_WC_MSK; @@ -434,10 +441,8 @@ 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)) { - gi2c_gsi_cb_err(tx_cb, "TX"); - complete(&gi2c->xfer); - } + gi2c_gsi_cb_err(tx_cb, "TX"); + complete(&gi2c->xfer); } static void gi2c_gsi_rx_cb(void *ptr) @@ -476,6 +481,7 @@ static int geni_i2c_gsi_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], goto geni_i2c_gsi_xfer_out; } } + if (!gi2c->rx_c) { gi2c->rx_c = dma_request_slave_channel(gi2c->dev, "rx"); if (!gi2c->rx_c) { @@ -496,6 +502,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 tre: ieob set */ + 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; @@ -535,26 +558,47 @@ 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) + /* Send lock tre for first transfer in a msg */ + sg_set_buf(&gi2c->tx_sg[index++], &gi2c->lock_t, + sizeof(gi2c->lock_t)); } else { sg_init_table(gi2c->tx_sg, segs); } + /* Send cfg tre when cfg not sent already */ + 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, - 0); + /* + * For Rx Go tre: Set ieob for non-shared se and for all + * but last transfer in shared se + */ + if (!gi2c->is_shared || (gi2c->is_shared && i != num-1)) + go_t->dword[3] = MSM_GPI_I2C_GO_TRE_DWORD3(1, 0, + 0, 1, 0); + else + go_t->dword[3] = MSM_GPI_I2C_GO_TRE_DWORD3(1, 0, + 0, 0, 0); } else { + /* For Tx Go tre: ieob is not set, chain bit is set */ go_t->dword[2] = MSM_GPI_I2C_GO_TRE_DWORD2(0); go_t->dword[3] = MSM_GPI_I2C_GO_TRE_DWORD3(0, 0, 0, 0, 1); @@ -564,6 +608,8 @@ static int geni_i2c_gsi_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], sizeof(gi2c->go_t)); if (msgs[i].flags & I2C_M_RD) { + GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev, + "msg[%d].len:%d R\n", i, gi2c->cur->len); sg_init_table(&gi2c->rx_sg, 1); ret = geni_se_iommu_map_buf(rx_dev, &gi2c->rx_ph, dma_buf, msgs[i].len, @@ -576,6 +622,11 @@ static int geni_i2c_gsi_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], false); goto geni_i2c_gsi_xfer_out; + } else if (gi2c->dbg_buf_ptr) { + gi2c->dbg_buf_ptr[i].virt_buf = + (void *)dma_buf; + gi2c->dbg_buf_ptr[i].map_buf = + (void *)&gi2c->rx_ph; } gi2c->rx_t.dword[0] = MSM_GPI_DMA_W_BUFFER_TRE_DWORD0(gi2c->rx_ph); @@ -583,6 +634,7 @@ static int geni_i2c_gsi_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], MSM_GPI_DMA_W_BUFFER_TRE_DWORD1(gi2c->rx_ph); gi2c->rx_t.dword[2] = MSM_GPI_DMA_W_BUFFER_TRE_DWORD2(msgs[i].len); + /* Set ieot for all Rx/Tx DMA tres */ gi2c->rx_t.dword[3] = MSM_GPI_DMA_W_BUFFER_TRE_DWORD3(0, 0, 1, 0, 0); @@ -606,6 +658,8 @@ static int geni_i2c_gsi_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], rx_cookie = dmaengine_submit(gi2c->rx_desc); dma_async_issue_pending(gi2c->rx_c); } else { + GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev, + "msg[%d].len:%d W\n", i, gi2c->cur->len); ret = geni_se_iommu_map_buf(tx_dev, &gi2c->tx_ph, dma_buf, msgs[i].len, DMA_TO_DEVICE); @@ -617,20 +671,40 @@ static int geni_i2c_gsi_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], false); goto geni_i2c_gsi_xfer_out; + } else if (gi2c->dbg_buf_ptr) { + gi2c->dbg_buf_ptr[i].virt_buf = + (void *)dma_buf; + gi2c->dbg_buf_ptr[i].map_buf = + (void *)&gi2c->tx_ph; } + gi2c->tx_t.dword[0] = MSM_GPI_DMA_W_BUFFER_TRE_DWORD0(gi2c->tx_ph); gi2c->tx_t.dword[1] = 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) + /* + * For Tx: unlock tre is send for last transfer + * so set chain bit for last transfer DMA tre. + */ + 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) { + /* Send unlock tre at the end of last transfer */ + 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 | @@ -652,8 +726,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); + "I2C gsi xfer timeout:%u flags:%d addr:0x%x\n", + gi2c->xfer_timeout, gi2c->cur->flags, + gi2c->cur->addr); geni_se_dump_dbg_regs(&gi2c->i2c_rsc, gi2c->base, gi2c->ipcl); gi2c->err = -ETIMEDOUT; @@ -663,6 +738,10 @@ geni_i2c_err_prep_sg: dmaengine_terminate_all(gi2c->tx_c); gi2c->cfg_sent = 0; } + if (gi2c->is_shared) + /* Resend cfg tre for every new message on shared se */ + gi2c->cfg_sent = 0; + if (msgs[i].flags & I2C_M_RD) geni_se_iommu_unmap_buf(rx_dev, &gi2c->rx_ph, msgs[i].len, DMA_FROM_DEVICE); @@ -688,8 +767,15 @@ static int geni_i2c_xfer(struct i2c_adapter *adap, int i, ret = 0, timeout = 0; gi2c->err = 0; - gi2c->cur = &msgs[0]; reinit_completion(&gi2c->xfer); + + /* Client to respect system suspend */ + if (!pm_runtime_enabled(gi2c->dev)) { + GENI_SE_ERR(gi2c->ipcl, false, gi2c->dev, + "%s: System suspended\n", __func__); + return -EACCES; + } + ret = pm_runtime_get_sync(gi2c->dev); if (ret < 0) { GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev, @@ -709,14 +795,25 @@ static int geni_i2c_xfer(struct i2c_adapter *adap, } } + GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev, + "n:%d addr:0x%x\n", num, msgs[0].addr); + + gi2c->dbg_num = num; + kfree(gi2c->dbg_buf_ptr); + gi2c->dbg_buf_ptr = + kcalloc(num, sizeof(struct dbg_buf_ctxt), GFP_KERNEL); + if (!gi2c->dbg_buf_ptr) + GENI_SE_ERR(gi2c->ipcl, false, gi2c->dev, + "Buf logging pointer not available\n"); + if (gi2c->se_mode == GSI_ONLY) { ret = geni_i2c_gsi_xfer(adap, msgs, num); goto geni_i2c_txn_ret; + } else { + /* Don't set shared flag in non-GSI mode */ + gi2c->is_shared = false; } - qcom_geni_i2c_conf(gi2c, 0); - dev_dbg(gi2c->dev, "i2c xfer:num:%d, msgs:len:%d,flg:%d\n", - num, msgs[0].len, msgs[0].flags); for (i = 0; i < num; i++) { int stretch = (i < (num - 1)); u32 m_param = 0; @@ -751,9 +848,8 @@ static int geni_i2c_xfer(struct i2c_adapter *adap, } if (msgs[i].flags & I2C_M_RD) { - dev_dbg(gi2c->dev, - "READ,n:%d,i:%d len:%d, stretch:%d\n", - num, i, msgs[i].len, stretch); + GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev, + "msgs[%d].len:%d R\n", i, msgs[i].len); geni_write_reg(msgs[i].len, gi2c->base, SE_I2C_RX_TRANS_LEN); m_cmd = I2C_READ; @@ -768,12 +864,16 @@ static int geni_i2c_xfer(struct i2c_adapter *adap, mode = FIFO_MODE; ret = geni_se_select_mode(gi2c->base, mode); + } else if (gi2c->dbg_buf_ptr) { + gi2c->dbg_buf_ptr[i].virt_buf = + (void *)dma_buf; + gi2c->dbg_buf_ptr[i].map_buf = + (void *)&rx_dma; } } } else { - dev_dbg(gi2c->dev, - "WRITE:n:%d,i:%d len:%d, stretch:%d, m_param:0x%x\n", - num, i, msgs[i].len, stretch, m_param); + GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev, + "msgs[%d].len:%d W\n", i, msgs[i].len); geni_write_reg(msgs[i].len, gi2c->base, SE_I2C_TX_TRANS_LEN); m_cmd = I2C_WRITE; @@ -788,6 +888,11 @@ static int geni_i2c_xfer(struct i2c_adapter *adap, mode = FIFO_MODE; ret = geni_se_select_mode(gi2c->base, mode); + } else if (gi2c->dbg_buf_ptr) { + gi2c->dbg_buf_ptr[i].virt_buf = + (void *)dma_buf; + gi2c->dbg_buf_ptr[i].map_buf = + (void *)&tx_dma; } } if (mode == FIFO_MODE) /* Get FIFO IRQ */ @@ -798,16 +903,22 @@ static int geni_i2c_xfer(struct i2c_adapter *adap, mb(); timeout = wait_for_completion_timeout(&gi2c->xfer, gi2c->xfer_timeout); - if (!timeout) + if (!timeout) { + GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev, + "I2C xfer timeout: %d\n", gi2c->xfer_timeout); geni_i2c_err(gi2c, GENI_TIMEOUT); + } if (gi2c->err) { reinit_completion(&gi2c->xfer); gi2c->cur = NULL; geni_cancel_m_cmd(gi2c->base); timeout = wait_for_completion_timeout(&gi2c->xfer, HZ); - if (!timeout) + if (!timeout) { + GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev, + "Abort\n"); geni_abort_m_cmd(gi2c->base); + } } gi2c->cur_wr = 0; gi2c->cur_rd = 0; @@ -830,7 +941,8 @@ static int geni_i2c_xfer(struct i2c_adapter *adap, } ret = gi2c->err; if (gi2c->err) { - dev_err(gi2c->dev, "i2c error :%d\n", gi2c->err); + GENI_SE_ERR(gi2c->ipcl, true, gi2c->dev, + "i2c error :%d\n", gi2c->err); break; } } @@ -842,7 +954,8 @@ geni_i2c_txn_ret: pm_runtime_put_autosuspend(gi2c->dev); gi2c->cur = NULL; gi2c->err = 0; - dev_dbg(gi2c->dev, "i2c txn ret:%d\n", ret); + GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev, + "i2c txn ret:%d\n", ret); return ret; } @@ -868,6 +981,10 @@ static int geni_i2c_probe(struct platform_device *pdev) if (!gi2c) return -ENOMEM; + if (arr_idx < MAX_SE) + /* Debug purpose */ + gi2c_dev_dbg[arr_idx++] = gi2c; + gi2c->dev = &pdev->dev; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -1029,9 +1146,15 @@ static int geni_i2c_probe(struct platform_device *pdev) static int geni_i2c_remove(struct platform_device *pdev) { struct geni_i2c_dev *gi2c = platform_get_drvdata(pdev); + int i; pm_runtime_disable(gi2c->dev); i2c_del_adapter(&gi2c->adap); + + for (i = 0; i < arr_idx; i++) + gi2c_dev_dbg[i] = NULL; + arr_idx = 0; + if (gi2c->ipcl) ipc_log_context_destroy(gi2c->ipcl); return 0; @@ -1039,6 +1162,9 @@ static int geni_i2c_remove(struct platform_device *pdev) static int geni_i2c_resume_noirq(struct device *device) { + struct geni_i2c_dev *gi2c = dev_get_drvdata(device); + + GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev, "%s\n", __func__); return 0; } @@ -1059,6 +1185,7 @@ static int geni_i2c_runtime_suspend(struct device *dev) } else { se_geni_resources_off(&gi2c->i2c_rsc); } + GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev, "%s\n", __func__); return 0; } @@ -1070,7 +1197,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); } @@ -1096,6 +1223,7 @@ static int geni_i2c_runtime_resume(struct device *dev) if (gi2c->se_mode == FIFO_SE_DMA) enable_irq(gi2c->irq); } + GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev, "%s\n", __func__); return 0; } @@ -1113,6 +1241,8 @@ static int geni_i2c_suspend_noirq(struct device *device) return -EBUSY; } if (!pm_runtime_status_suspended(device)) { + GENI_SE_DBG(gi2c->ipcl, false, gi2c->dev, + "%s\n", __func__); geni_i2c_runtime_suspend(device); pm_runtime_disable(device); pm_runtime_set_suspended(device); diff --git a/include/linux/msm_gpi.h b/include/linux/msm_gpi.h index 2003af21919a..2e57d4387d48 100644 --- a/include/linux/msm_gpi.h +++ b/include/linux/msm_gpi.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. */ #ifndef __MSM_GPI_H_ @@ -29,6 +29,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 */ #ifdef CONFIG_ARM64 #define MSM_GPI_DMA_W_BUFFER_TRE_DWORD0(ptr) ((u32)ptr)