i3c: i3c-master-qcom-geni: Fix DMA and FIFO mode timeout scenario
This change primarily fixes timeout issue observed during command send as part of read and write operations. This will do proper cleanup of the GENI in command timeout with cancel and abort operations while waiting for the done event. Change-Id: Icd1a546fd6f54046640910e2d1225da855b2ea42 Signed-off-by: Mukesh Kumar Savaliya <msavaliy@codeaurora.org>
This commit is contained in:
@@ -580,6 +580,26 @@ static irqreturn_t geni_i3c_ibi_irq(int irq, void *dev)
|
|||||||
return IRQ_HANDLED;
|
return IRQ_HANDLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void geni_i3c_handle_err(struct geni_i3c_dev *gi3c, u32 status)
|
||||||
|
{
|
||||||
|
if (status & M_GP_IRQ_0_EN)
|
||||||
|
geni_i3c_err(gi3c, RD_TERM);
|
||||||
|
if (status & M_GP_IRQ_1_EN)
|
||||||
|
geni_i3c_err(gi3c, NACK);
|
||||||
|
if (status & M_GP_IRQ_2_EN)
|
||||||
|
geni_i3c_err(gi3c, CRC_ERR);
|
||||||
|
if (status & M_GP_IRQ_3_EN)
|
||||||
|
geni_i3c_err(gi3c, BUS_PROTO);
|
||||||
|
if (status & M_GP_IRQ_4_EN)
|
||||||
|
geni_i3c_err(gi3c, NACK_7E);
|
||||||
|
if (status & M_CMD_OVERRUN_EN)
|
||||||
|
geni_i3c_err(gi3c, GENI_OVERRUN);
|
||||||
|
if (status & M_ILLEGAL_CMD_EN)
|
||||||
|
geni_i3c_err(gi3c, GENI_ILLEGAL_CMD);
|
||||||
|
if (status & M_CMD_ABORT_EN)
|
||||||
|
geni_i3c_err(gi3c, GENI_ABORT_DONE);
|
||||||
|
}
|
||||||
|
|
||||||
static irqreturn_t geni_i3c_irq(int irq, void *dev)
|
static irqreturn_t geni_i3c_irq(int irq, void *dev)
|
||||||
{
|
{
|
||||||
struct geni_i3c_dev *gi3c = dev;
|
struct geni_i3c_dev *gi3c = dev;
|
||||||
@@ -597,24 +617,8 @@ static irqreturn_t geni_i3c_irq(int irq, void *dev)
|
|||||||
dm_rx_st = readl_relaxed(gi3c->se.base + SE_DMA_RX_IRQ_STAT);
|
dm_rx_st = readl_relaxed(gi3c->se.base + SE_DMA_RX_IRQ_STAT);
|
||||||
dma = readl_relaxed(gi3c->se.base + SE_GENI_DMA_MODE_EN);
|
dma = readl_relaxed(gi3c->se.base + SE_GENI_DMA_MODE_EN);
|
||||||
|
|
||||||
if ((m_stat & SE_I3C_ERR) ||
|
if ((m_stat & SE_I3C_ERR) || (dm_rx_st & DM_I3C_CB_ERR)) {
|
||||||
(dm_rx_st & DM_I3C_CB_ERR)) {
|
geni_i3c_handle_err(gi3c, m_stat);
|
||||||
if (m_stat & M_GP_IRQ_0_EN)
|
|
||||||
geni_i3c_err(gi3c, RD_TERM);
|
|
||||||
if (m_stat & M_GP_IRQ_1_EN)
|
|
||||||
geni_i3c_err(gi3c, NACK);
|
|
||||||
if (m_stat & M_GP_IRQ_2_EN)
|
|
||||||
geni_i3c_err(gi3c, CRC_ERR);
|
|
||||||
if (m_stat & M_GP_IRQ_3_EN)
|
|
||||||
geni_i3c_err(gi3c, BUS_PROTO);
|
|
||||||
if (m_stat & M_GP_IRQ_4_EN)
|
|
||||||
geni_i3c_err(gi3c, NACK_7E);
|
|
||||||
if (m_stat & M_CMD_OVERRUN_EN)
|
|
||||||
geni_i3c_err(gi3c, GENI_OVERRUN);
|
|
||||||
if (m_stat & M_ILLEGAL_CMD_EN)
|
|
||||||
geni_i3c_err(gi3c, GENI_ILLEGAL_CMD);
|
|
||||||
if (m_stat & M_CMD_ABORT_EN)
|
|
||||||
geni_i3c_err(gi3c, GENI_ABORT_DONE);
|
|
||||||
|
|
||||||
/* Disable the TX Watermark interrupt to stop TX */
|
/* Disable the TX Watermark interrupt to stop TX */
|
||||||
if (!dma)
|
if (!dma)
|
||||||
@@ -688,8 +692,11 @@ static irqreturn_t geni_i3c_irq(int irq, void *dev)
|
|||||||
complete(&gi3c->done);
|
complete(&gi3c->done);
|
||||||
} else if ((dm_tx_st & TX_DMA_DONE) ||
|
} else if ((dm_tx_st & TX_DMA_DONE) ||
|
||||||
(dm_rx_st & RX_DMA_DONE) ||
|
(dm_rx_st & RX_DMA_DONE) ||
|
||||||
(dm_rx_st & RX_RESET_DONE))
|
(dm_rx_st & RX_RESET_DONE) ||
|
||||||
|
(dm_tx_st & TX_RESET_DONE)) {
|
||||||
|
|
||||||
complete(&gi3c->done);
|
complete(&gi3c->done);
|
||||||
|
}
|
||||||
|
|
||||||
spin_unlock_irqrestore(&gi3c->spinlock, flags);
|
spin_unlock_irqrestore(&gi3c->spinlock, flags);
|
||||||
return IRQ_HANDLED;
|
return IRQ_HANDLED;
|
||||||
@@ -792,18 +799,37 @@ static int _i3c_geni_execute_command
|
|||||||
|
|
||||||
GENI_SE_ERR(gi3c->ipcl, true, gi3c->se.dev,
|
GENI_SE_ERR(gi3c->ipcl, true, gi3c->se.dev,
|
||||||
"got wait_for_completion timeout\n");
|
"got wait_for_completion timeout\n");
|
||||||
spin_lock_irqsave(&gi3c->spinlock, flags);
|
|
||||||
geni_i3c_err(gi3c, GENI_TIMEOUT);
|
geni_i3c_err(gi3c, GENI_TIMEOUT);
|
||||||
gi3c->cur_buf = NULL;
|
gi3c->cur_buf = NULL;
|
||||||
gi3c->cur_len = gi3c->cur_idx = 0;
|
gi3c->cur_len = gi3c->cur_idx = 0;
|
||||||
gi3c->cur_rnw = 0;
|
gi3c->cur_rnw = 0;
|
||||||
|
|
||||||
|
reinit_completion(&gi3c->done);
|
||||||
|
|
||||||
|
spin_lock_irqsave(&gi3c->spinlock, flags);
|
||||||
|
geni_cancel_m_cmd(gi3c->se.base);
|
||||||
|
spin_unlock_irqrestore(&gi3c->spinlock, flags);
|
||||||
|
|
||||||
|
time_remaining = wait_for_completion_timeout(&gi3c->done, HZ);
|
||||||
|
if (!time_remaining) {
|
||||||
|
GENI_SE_ERR(gi3c->ipcl, true, gi3c->se.dev,
|
||||||
|
"%s:Cancel cmd failed : Aborting\n", __func__);
|
||||||
|
|
||||||
|
reinit_completion(&gi3c->done);
|
||||||
|
spin_lock_irqsave(&gi3c->spinlock, flags);
|
||||||
geni_abort_m_cmd(gi3c->se.base);
|
geni_abort_m_cmd(gi3c->se.base);
|
||||||
spin_unlock_irqrestore(&gi3c->spinlock, flags);
|
spin_unlock_irqrestore(&gi3c->spinlock, flags);
|
||||||
time_remaining = wait_for_completion_timeout(&gi3c->done,
|
time_remaining =
|
||||||
XFER_TIMEOUT);
|
wait_for_completion_timeout(&gi3c->done, XFER_TIMEOUT);
|
||||||
|
if (!time_remaining)
|
||||||
|
GENI_SE_ERR(gi3c->ipcl, true, gi3c->se.dev,
|
||||||
|
"%s:Abort Failed\n", __func__);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (xfer->mode == SE_DMA) {
|
if (xfer->mode == SE_DMA) {
|
||||||
if (gi3c->err) {
|
if (gi3c->err) {
|
||||||
|
reinit_completion(&gi3c->done);
|
||||||
if (rnw == READ_TRANSACTION)
|
if (rnw == READ_TRANSACTION)
|
||||||
writel_relaxed(1, gi3c->se.base +
|
writel_relaxed(1, gi3c->se.base +
|
||||||
SE_DMA_RX_FSM_RST);
|
SE_DMA_RX_FSM_RST);
|
||||||
|
|||||||
Reference in New Issue
Block a user