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 <vkaur@codeaurora.org>
This commit is contained in:
parent
a18d61730a
commit
22cec88da5
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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))
|
||||
|
Loading…
Reference in New Issue
Block a user