Merge "slim_ngd: Handle invalid/timeout TX errors gracefully"

This commit is contained in:
Linux Build Service Account 2014-12-03 01:33:50 -08:00 committed by Gerrit - the friendly Code Review server
commit 0e956a7b28
3 changed files with 79 additions and 18 deletions

View file

@ -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);

View file

@ -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;
}

View file

@ -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);