mirror of
https://github.com/team-infusion-developers/android_kernel_samsung_msm8976.git
synced 2024-09-21 03:43:03 +00:00
slim_ngd: Handle invalid/timeout TX errors gracefully
Invalid transactions can cause timeout or NACK TX errors. Clear completion object reference for pending TX messages and print TX BAM pipe descriptors and status registers for such transactions. TX timeouts during connect/disconnect port error conditions should clear completion object reference for acklowledgement receipt to avoid referring to stale completion object later. Change-Id: I81018df8cab59b43753c46c8a49a5066b794fda6 Signed-off-by: Sagar Dharia <sdharia@codeaurora.org>
This commit is contained in:
parent
ed198ed6c2
commit
bc4c3bf0bf
|
@ -95,19 +95,22 @@ static irqreturn_t ngd_slim_interrupt(int irq, void *d)
|
|||
(stat & NGD_INT_MSG_TX_INVAL) || (stat & NGD_INT_DEV_ERR) ||
|
||||
(stat & NGD_INT_TX_NACKED_2)) {
|
||||
writel_relaxed(stat, ngd + NGD_INT_CLR);
|
||||
dev->err = -EIO;
|
||||
if (stat & NGD_INT_MSG_TX_INVAL)
|
||||
dev->err = -EINVAL;
|
||||
else
|
||||
dev->err = -EIO;
|
||||
|
||||
SLIM_WARN(dev, "NGD interrupt error:0x%x, err:%d\n", stat,
|
||||
dev->err);
|
||||
/* Guarantee that error interrupts are cleared */
|
||||
mb();
|
||||
msm_slim_manage_tx_msgq(dev, false, NULL);
|
||||
msm_slim_manage_tx_msgq(dev, false, NULL, dev->err);
|
||||
|
||||
} else if (stat & NGD_INT_TX_MSG_SENT) {
|
||||
writel_relaxed(NGD_INT_TX_MSG_SENT, ngd + NGD_INT_CLR);
|
||||
/* Make sure interrupt is cleared */
|
||||
mb();
|
||||
msm_slim_manage_tx_msgq(dev, false, NULL);
|
||||
msm_slim_manage_tx_msgq(dev, false, NULL, 0);
|
||||
}
|
||||
if (stat & NGD_INT_RX_MSG_RCVD) {
|
||||
u32 rx_buf[10];
|
||||
|
@ -475,6 +478,13 @@ static int ngd_xfer_msg(struct slim_controller *ctrl, struct slim_msg_txn *txn)
|
|||
}
|
||||
txn->rl--;
|
||||
|
||||
if (txn->len > SLIM_MSGQ_BUF_LEN || txn->rl > SLIM_MSGQ_BUF_LEN) {
|
||||
SLIM_WARN(dev, "msg exeeds HW lim:%d, rl:%d, mc:0x%x, mt:0x%x",
|
||||
txn->len, txn->rl, txn->mc, txn->mt);
|
||||
ret = -EDQUOT;
|
||||
goto ngd_xfer_err;
|
||||
}
|
||||
|
||||
if (txn->mt == SLIM_MSG_MT_CORE && txn->comp &&
|
||||
dev->use_tx_msgqs == MSM_MSGQ_ENABLED &&
|
||||
(txn_mc != SLIM_MSG_MC_REQUEST_INFORMATION &&
|
||||
|
@ -567,9 +577,26 @@ static int ngd_xfer_msg(struct slim_controller *ctrl, struct slim_msg_txn *txn)
|
|||
ret = msm_send_msg_buf(dev, pbuf, txn->rl,
|
||||
NGD_BASE(dev->ctrl.nr, dev->ver) + NGD_TX_MSG);
|
||||
if (!ret && sync_wr) {
|
||||
int i;
|
||||
int timeout = wait_for_completion_timeout(&tx_sent, HZ);
|
||||
if (!timeout) {
|
||||
if (!timeout && dev->use_tx_msgqs == MSM_MSGQ_ENABLED) {
|
||||
struct msm_slim_endp *endpoint = &dev->tx_msgq;
|
||||
struct sps_mem_buffer *mem = &endpoint->buf;
|
||||
u32 idx = (u32) (((u8 *)pbuf - (u8 *)mem->base) /
|
||||
SLIM_MSGQ_BUF_LEN);
|
||||
phys_addr_t addr = mem->phys_base +
|
||||
(idx * SLIM_MSGQ_BUF_LEN);
|
||||
ret = -ETIMEDOUT;
|
||||
SLIM_WARN(dev, "timeout, BAM desc_idx:%d, phys:%llx",
|
||||
idx, (u64)addr);
|
||||
for (i = 0; i < (SLIM_MSGQ_BUF_LEN >> 2) ; i++)
|
||||
SLIM_WARN(dev, "timeout:bam-desc[%d]:0x%x",
|
||||
i, *(pbuf + i));
|
||||
if (idx < MSM_TX_BUFS)
|
||||
dev->wr_comp[idx] = NULL;
|
||||
/* print BAM debug info for TX pipe */
|
||||
sps_get_bam_debug_info(dev->bam.hdl, 93,
|
||||
SPS_BAM_PIPE(4), 0, 2);
|
||||
/*
|
||||
* disconnect/recoonect pipe so that subsequent
|
||||
* transactions don't timeout due to unavailable
|
||||
|
@ -580,6 +607,12 @@ static int ngd_xfer_msg(struct slim_controller *ctrl, struct slim_msg_txn *txn)
|
|||
&dev->use_tx_msgqs);
|
||||
msm_slim_connect_endp(dev, &dev->tx_msgq, NULL);
|
||||
}
|
||||
} else if (!timeout) {
|
||||
ret = -ETIMEDOUT;
|
||||
SLIM_WARN(dev, "timeout non-BAM TX,len:%d", txn->rl);
|
||||
for (i = 0; i < (SLIM_MSGQ_BUF_LEN >> 2) ; i++)
|
||||
SLIM_WARN(dev, "timeout:txbuf[%d]:0x%x", i,
|
||||
dev->tx_buf[i]);
|
||||
} else {
|
||||
ret = dev->err;
|
||||
}
|
||||
|
@ -599,22 +632,27 @@ static int ngd_xfer_msg(struct slim_controller *ctrl, struct slim_msg_txn *txn)
|
|||
|
||||
SLIM_WARN(dev, "conf:0x%x,stat:0x%x,rxmsgq:0x%x\n",
|
||||
conf, stat, rx_msgq);
|
||||
SLIM_WARN(dev, "int_stat:0x%x,int_en:0x%x,int_cll:0x%x\n",
|
||||
SLIM_ERR(dev, "int_stat:0x%x,int_en:0x%x,int_cll:0x%x\n",
|
||||
int_stat, int_en, int_clr);
|
||||
} else if (txn_mt == SLIM_MSG_MT_DEST_REFERRED_USER &&
|
||||
}
|
||||
|
||||
if (txn_mt == SLIM_MSG_MT_DEST_REFERRED_USER &&
|
||||
(txn_mc == SLIM_USR_MC_CONNECT_SRC ||
|
||||
txn_mc == SLIM_USR_MC_CONNECT_SINK ||
|
||||
txn_mc == SLIM_USR_MC_DISCONNECT_PORT)) {
|
||||
int timeout;
|
||||
mutex_unlock(&dev->tx_lock);
|
||||
msm_slim_put_ctrl(dev);
|
||||
timeout = wait_for_completion_timeout(txn->comp, HZ);
|
||||
if (!timeout)
|
||||
ret = -ETIMEDOUT;
|
||||
else
|
||||
ret = txn->ec;
|
||||
if (!ret) {
|
||||
timeout = wait_for_completion_timeout(txn->comp, HZ);
|
||||
/* remote side did not acknowledge */
|
||||
if (!timeout)
|
||||
ret = -EREMOTEIO;
|
||||
else
|
||||
ret = txn->ec;
|
||||
}
|
||||
if (ret) {
|
||||
SLIM_INFO(dev,
|
||||
SLIM_ERR(dev,
|
||||
"connect/disconnect:0x%x,tid:%d err:%d\n",
|
||||
txn->mc, txn->tid, ret);
|
||||
mutex_lock(&ctrl->m_ctrl);
|
||||
|
|
|
@ -417,7 +417,7 @@ static int msm_slim_post_tx_msgq(struct msm_slim_ctrl *dev, u8 *buf, int len)
|
|||
return ret;
|
||||
}
|
||||
|
||||
void msm_slim_tx_msg_return(struct msm_slim_ctrl *dev)
|
||||
void msm_slim_tx_msg_return(struct msm_slim_ctrl *dev, int err)
|
||||
{
|
||||
struct msm_slim_endp *endpoint = &dev->tx_msgq;
|
||||
struct sps_mem_buffer *mem = &endpoint->buf;
|
||||
|
@ -446,6 +446,25 @@ void msm_slim_tx_msg_return(struct msm_slim_ctrl *dev)
|
|||
struct completion *comp = dev->wr_comp[idx];
|
||||
dev->wr_comp[idx] = NULL;
|
||||
complete(comp);
|
||||
} else if (idx >= MSM_TX_BUFS) {
|
||||
SLIM_ERR(dev, "BUF out of bounds:base:0x%llx, io:0x%x",
|
||||
(u64)mem->phys_base, iovec.addr);
|
||||
/* print BAM debug info for TX pipe */
|
||||
sps_get_bam_debug_info(dev->bam.hdl, 93,
|
||||
SPS_BAM_PIPE(4), 0, 2);
|
||||
continue;
|
||||
}
|
||||
if (err) {
|
||||
int i;
|
||||
u32 *addr = (u32 *)mem->base +
|
||||
(idx * (SLIM_MSGQ_BUF_LEN >> 2));
|
||||
/* print the descriptor that resulted in error */
|
||||
for (i = 0; i < (SLIM_MSGQ_BUF_LEN >> 2); i++)
|
||||
SLIM_WARN(dev, "err desc[%d]:0x%x", i, addr[i]);
|
||||
/* print BAM debug info for TX pipe for invalid TX */
|
||||
if (err == -EINVAL)
|
||||
sps_get_bam_debug_info(dev->bam.hdl, 93,
|
||||
SPS_BAM_PIPE(4), 0, 2);
|
||||
}
|
||||
/* reclaim all packets that were delivered out of order */
|
||||
if (idx != dev->tx_head)
|
||||
|
@ -477,7 +496,7 @@ static u32 *msm_slim_modify_tx_buf(struct msm_slim_ctrl *dev,
|
|||
return retbuf;
|
||||
}
|
||||
u32 *msm_slim_manage_tx_msgq(struct msm_slim_ctrl *dev, bool getbuf,
|
||||
struct completion *comp)
|
||||
struct completion *comp, int err)
|
||||
{
|
||||
int ret = 0;
|
||||
int retries = 0;
|
||||
|
@ -485,7 +504,7 @@ u32 *msm_slim_manage_tx_msgq(struct msm_slim_ctrl *dev, bool getbuf,
|
|||
|
||||
mutex_lock(&dev->tx_buf_lock);
|
||||
if (!getbuf) {
|
||||
msm_slim_tx_msg_return(dev);
|
||||
msm_slim_tx_msg_return(dev, err);
|
||||
mutex_unlock(&dev->tx_buf_lock);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -497,7 +516,7 @@ u32 *msm_slim_manage_tx_msgq(struct msm_slim_ctrl *dev, bool getbuf,
|
|||
}
|
||||
|
||||
do {
|
||||
msm_slim_tx_msg_return(dev);
|
||||
msm_slim_tx_msg_return(dev, err);
|
||||
retbuf = msm_slim_modify_tx_buf(dev, comp);
|
||||
if (!retbuf)
|
||||
ret = -EAGAIN;
|
||||
|
@ -551,7 +570,7 @@ u32 *msm_get_msg_buf(struct msm_slim_ctrl *dev, int len,
|
|||
return dev->tx_buf;
|
||||
}
|
||||
|
||||
return msm_slim_manage_tx_msgq(dev, true, comp);
|
||||
return msm_slim_manage_tx_msgq(dev, true, comp, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -701,8 +720,12 @@ int msm_slim_connect_endp(struct msm_slim_ctrl *dev,
|
|||
}
|
||||
dev->use_rx_msgqs = MSM_MSGQ_ENABLED;
|
||||
} else {
|
||||
mutex_lock(&dev->tx_buf_lock);
|
||||
dev->tx_tail = 0;
|
||||
dev->tx_head = 0;
|
||||
for (i = 0; i < MSM_TX_BUFS; i++)
|
||||
dev->wr_comp[i] = NULL;
|
||||
mutex_unlock(&dev->tx_buf_lock);
|
||||
dev->use_tx_msgqs = MSM_MSGQ_ENABLED;
|
||||
}
|
||||
|
||||
|
|
|
@ -379,7 +379,7 @@ int msm_send_msg_buf(struct msm_slim_ctrl *dev, u32 *buf, u8 len, u32 tx_reg);
|
|||
u32 *msm_get_msg_buf(struct msm_slim_ctrl *dev, int len,
|
||||
struct completion *comp);
|
||||
u32 *msm_slim_manage_tx_msgq(struct msm_slim_ctrl *dev, bool getbuf,
|
||||
struct completion *comp);
|
||||
struct completion *comp, int err);
|
||||
int msm_slim_rx_msgq_get(struct msm_slim_ctrl *dev, u32 *data, int offset);
|
||||
int msm_slim_sps_init(struct msm_slim_ctrl *dev, struct resource *bam_mem,
|
||||
u32 pipe_reg, bool remote);
|
||||
|
|
Loading…
Reference in a new issue