cxgb4/iw_cxgb4: display TPTE on errors

With ingress WRITE or READ RESPONSE errors, HW provides the offending
stag from the packet.  This patch adds logic to log the parsed TPTE
in this case. cxgb4 now exports a function to read a TPTE entry
from adapter memory.

Signed-off-by: Steve Wise <swise@opengridcomputing.com>
Signed-off-by: Hariprasad Shenai <hariprasad@chelsio.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Hariprasad Shenai 2014-07-14 21:34:53 +05:30 committed by David S. Miller
parent 4c2c576322
commit 031cf4769b
5 changed files with 143 additions and 11 deletions

View File

@ -241,12 +241,32 @@ static int dump_stag(int id, void *p, void *data)
struct c4iw_debugfs_data *stagd = data;
int space;
int cc;
struct fw_ri_tpte tpte;
int ret;
space = stagd->bufsize - stagd->pos - 1;
if (space == 0)
return 1;
cc = snprintf(stagd->buf + stagd->pos, space, "0x%x\n", id<<8);
ret = cxgb4_read_tpte(stagd->devp->rdev.lldi.ports[0], (u32)id<<8,
(__be32 *)&tpte);
if (ret) {
dev_err(&stagd->devp->rdev.lldi.pdev->dev,
"%s cxgb4_read_tpte err %d\n", __func__, ret);
return ret;
}
cc = snprintf(stagd->buf + stagd->pos, space,
"stag: idx 0x%x valid %d key 0x%x state %d pdid %d "
"perm 0x%x ps %d len 0x%llx va 0x%llx\n",
(u32)id<<8,
G_FW_RI_TPTE_VALID(ntohl(tpte.valid_to_pdid)),
G_FW_RI_TPTE_STAGKEY(ntohl(tpte.valid_to_pdid)),
G_FW_RI_TPTE_STAGSTATE(ntohl(tpte.valid_to_pdid)),
G_FW_RI_TPTE_PDID(ntohl(tpte.valid_to_pdid)),
G_FW_RI_TPTE_PERM(ntohl(tpte.locread_to_qpid)),
G_FW_RI_TPTE_PS(ntohl(tpte.locread_to_qpid)),
((u64)ntohl(tpte.len_hi) << 32) | ntohl(tpte.len_lo),
((u64)ntohl(tpte.va_hi) << 32) | ntohl(tpte.va_lo_fbo));
if (cc < space)
stagd->pos += cc;
return 0;
@ -259,7 +279,7 @@ static int stag_release(struct inode *inode, struct file *file)
printk(KERN_INFO "%s null stagd?\n", __func__);
return 0;
}
kfree(stagd->buf);
vfree(stagd->buf);
kfree(stagd);
return 0;
}
@ -282,8 +302,8 @@ static int stag_open(struct inode *inode, struct file *file)
idr_for_each(&stagd->devp->mmidr, count_idrs, &count);
spin_unlock_irq(&stagd->devp->lock);
stagd->bufsize = count * sizeof("0x12345678\n");
stagd->buf = kmalloc(stagd->bufsize, GFP_KERNEL);
stagd->bufsize = count * 256;
stagd->buf = vmalloc(stagd->bufsize);
if (!stagd->buf) {
ret = -ENOMEM;
goto err1;

View File

@ -35,6 +35,55 @@
#include "iw_cxgb4.h"
static void print_tpte(struct c4iw_dev *dev, u32 stag)
{
int ret;
struct fw_ri_tpte tpte;
ret = cxgb4_read_tpte(dev->rdev.lldi.ports[0], stag,
(__be32 *)&tpte);
if (ret) {
dev_err(&dev->rdev.lldi.pdev->dev,
"%s cxgb4_read_tpte err %d\n", __func__, ret);
return;
}
PDBG("stag idx 0x%x valid %d key 0x%x state %d pdid %d "
"perm 0x%x ps %d len 0x%llx va 0x%llx\n",
stag & 0xffffff00,
G_FW_RI_TPTE_VALID(ntohl(tpte.valid_to_pdid)),
G_FW_RI_TPTE_STAGKEY(ntohl(tpte.valid_to_pdid)),
G_FW_RI_TPTE_STAGSTATE(ntohl(tpte.valid_to_pdid)),
G_FW_RI_TPTE_PDID(ntohl(tpte.valid_to_pdid)),
G_FW_RI_TPTE_PERM(ntohl(tpte.locread_to_qpid)),
G_FW_RI_TPTE_PS(ntohl(tpte.locread_to_qpid)),
((u64)ntohl(tpte.len_hi) << 32) | ntohl(tpte.len_lo),
((u64)ntohl(tpte.va_hi) << 32) | ntohl(tpte.va_lo_fbo));
}
static void dump_err_cqe(struct c4iw_dev *dev, struct t4_cqe *err_cqe)
{
__be64 *p = (void *)err_cqe;
dev_err(&dev->rdev.lldi.pdev->dev,
"AE qpid %d opcode %d status 0x%x "
"type %d len 0x%x wrid.hi 0x%x wrid.lo 0x%x\n",
CQE_QPID(err_cqe), CQE_OPCODE(err_cqe),
CQE_STATUS(err_cqe), CQE_TYPE(err_cqe), ntohl(err_cqe->len),
CQE_WRID_HI(err_cqe), CQE_WRID_LOW(err_cqe));
PDBG("%016llx %016llx %016llx %016llx\n",
be64_to_cpu(p[0]), be64_to_cpu(p[1]), be64_to_cpu(p[2]),
be64_to_cpu(p[3]));
/*
* Ingress WRITE and READ_RESP errors provide
* the offending stag, so parse and log it.
*/
if (RQ_TYPE(err_cqe) && (CQE_OPCODE(err_cqe) == FW_RI_RDMA_WRITE ||
CQE_OPCODE(err_cqe) == FW_RI_READ_RESP))
print_tpte(dev, CQE_WRID_STAG(err_cqe));
}
static void post_qp_event(struct c4iw_dev *dev, struct c4iw_cq *chp,
struct c4iw_qp *qhp,
struct t4_cqe *err_cqe,
@ -44,11 +93,7 @@ static void post_qp_event(struct c4iw_dev *dev, struct c4iw_cq *chp,
struct c4iw_qp_attributes attrs;
unsigned long flag;
printk(KERN_ERR MOD "AE qpid 0x%x opcode %d status 0x%x "
"type %d wrid.hi 0x%x wrid.lo 0x%x\n",
CQE_QPID(err_cqe), CQE_OPCODE(err_cqe),
CQE_STATUS(err_cqe), CQE_TYPE(err_cqe),
CQE_WRID_HI(err_cqe), CQE_WRID_LOW(err_cqe));
dump_err_cqe(dev, err_cqe);
if (qhp->attr.state == C4IW_QP_STATE_RTS) {
attrs.next_state = C4IW_QP_STATE_TERMINATE;

View File

@ -236,8 +236,8 @@ struct t4_cqe {
#define CQE_WRID_SQ_IDX(x) ((x)->u.scqe.cidx)
/* generic accessor macros */
#define CQE_WRID_HI(x) ((x)->u.gen.wrid_hi)
#define CQE_WRID_LOW(x) ((x)->u.gen.wrid_low)
#define CQE_WRID_HI(x) (be32_to_cpu((x)->u.gen.wrid_hi))
#define CQE_WRID_LOW(x) (be32_to_cpu((x)->u.gen.wrid_low))
/* macros for flit 3 of the cqe */
#define S_CQE_GENBIT 63

View File

@ -3832,6 +3832,72 @@ void cxgb4_enable_db_coalescing(struct net_device *dev)
}
EXPORT_SYMBOL(cxgb4_enable_db_coalescing);
int cxgb4_read_tpte(struct net_device *dev, u32 stag, __be32 *tpte)
{
struct adapter *adap;
u32 offset, memtype, memaddr;
u32 edc0_size, edc1_size, mc0_size, mc1_size;
u32 edc0_end, edc1_end, mc0_end, mc1_end;
int ret;
adap = netdev2adap(dev);
offset = ((stag >> 8) * 32) + adap->vres.stag.start;
/* Figure out where the offset lands in the Memory Type/Address scheme.
* This code assumes that the memory is laid out starting at offset 0
* with no breaks as: EDC0, EDC1, MC0, MC1. All cards have both EDC0
* and EDC1. Some cards will have neither MC0 nor MC1, most cards have
* MC0, and some have both MC0 and MC1.
*/
edc0_size = EDRAM_SIZE_GET(t4_read_reg(adap, MA_EDRAM0_BAR)) << 20;
edc1_size = EDRAM_SIZE_GET(t4_read_reg(adap, MA_EDRAM1_BAR)) << 20;
mc0_size = EXT_MEM_SIZE_GET(t4_read_reg(adap, MA_EXT_MEMORY_BAR)) << 20;
edc0_end = edc0_size;
edc1_end = edc0_end + edc1_size;
mc0_end = edc1_end + mc0_size;
if (offset < edc0_end) {
memtype = MEM_EDC0;
memaddr = offset;
} else if (offset < edc1_end) {
memtype = MEM_EDC1;
memaddr = offset - edc0_end;
} else {
if (offset < mc0_end) {
memtype = MEM_MC0;
memaddr = offset - edc1_end;
} else if (is_t4(adap->params.chip)) {
/* T4 only has a single memory channel */
goto err;
} else {
mc1_size = EXT_MEM_SIZE_GET(
t4_read_reg(adap,
MA_EXT_MEMORY1_BAR)) << 20;
mc1_end = mc0_end + mc1_size;
if (offset < mc1_end) {
memtype = MEM_MC1;
memaddr = offset - mc0_end;
} else {
/* offset beyond the end of any memory */
goto err;
}
}
}
spin_lock(&adap->win0_lock);
ret = t4_memory_rw(adap, 0, memtype, memaddr, 32, tpte, T4_MEMORY_READ);
spin_unlock(&adap->win0_lock);
return ret;
err:
dev_err(adap->pdev_dev, "stag %#x, offset %#x out of range\n",
stag, offset);
return -EINVAL;
}
EXPORT_SYMBOL(cxgb4_read_tpte);
static struct pci_driver cxgb4_driver;
static void check_neigh_update(struct neighbour *neigh)

View File

@ -296,5 +296,6 @@ int cxgb4_sync_txq_pidx(struct net_device *dev, u16 qid, u16 pidx, u16 size);
int cxgb4_flush_eq_cache(struct net_device *dev);
void cxgb4_disable_db_coalescing(struct net_device *dev);
void cxgb4_enable_db_coalescing(struct net_device *dev);
int cxgb4_read_tpte(struct net_device *dev, u32 stag, __be32 *tpte);
#endif /* !__CXGB4_OFLD_H */