diff options
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/ethernet/chelsio/cxgb4/cudbg_entity.h | 1 | ||||
-rw-r--r-- | drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c | 218 | ||||
-rw-r--r-- | drivers/net/ethernet/chelsio/cxgb4/cxgb4.h | 2 | ||||
-rw-r--r-- | drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | 2 | ||||
-rw-r--r-- | drivers/net/ethernet/chelsio/cxgb4/t4_hw.c | 7 | ||||
-rw-r--r-- | drivers/net/ethernet/chelsio/cxgb4/t4_hw.h | 4 |
6 files changed, 210 insertions, 24 deletions
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cudbg_entity.h b/drivers/net/ethernet/chelsio/cxgb4/cudbg_entity.h index 1e1719526e76..075916044980 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cudbg_entity.h +++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_entity.h @@ -185,6 +185,7 @@ struct cudbg_tid_info_region_rev1 { u32 reserved[16]; }; +#define CUDBG_LOWMEM_MAX_CTXT_QIDS 256 #define CUDBG_MAX_FL_QIDS 1024 struct cudbg_ch_cntxt { diff --git a/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c b/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c index 2e3cf36347a2..38866f3f45ac 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cudbg_lib.c @@ -1594,22 +1594,108 @@ int cudbg_collect_tid(struct cudbg_init *pdbg_init, return rc; } -int cudbg_dump_context_size(struct adapter *padap) +static int cudbg_sge_ctxt_check_valid(u32 *buf, int type) +{ + int index, bit, bit_pos = 0; + + switch (type) { + case CTXT_EGRESS: + bit_pos = 176; + break; + case CTXT_INGRESS: + bit_pos = 141; + break; + case CTXT_FLM: + bit_pos = 89; + break; + } + index = bit_pos / 32; + bit = bit_pos % 32; + return buf[index] & (1U << bit); +} + +static int cudbg_get_ctxt_region_info(struct adapter *padap, + struct cudbg_region_info *ctx_info, + u8 *mem_type) { - u32 value, size; + struct cudbg_mem_desc mem_desc; + struct cudbg_meminfo meminfo; + u32 i, j, value, found; u8 flq; + int rc; + + rc = cudbg_fill_meminfo(padap, &meminfo); + if (rc) + return rc; + + /* Get EGRESS and INGRESS context region size */ + for (i = CTXT_EGRESS; i <= CTXT_INGRESS; i++) { + found = 0; + memset(&mem_desc, 0, sizeof(struct cudbg_mem_desc)); + for (j = 0; j < ARRAY_SIZE(meminfo.avail); j++) { + rc = cudbg_get_mem_region(padap, &meminfo, j, + cudbg_region[i], + &mem_desc); + if (!rc) { + found = 1; + rc = cudbg_get_mem_relative(padap, &meminfo, j, + &mem_desc.base, + &mem_desc.limit); + if (rc) { + ctx_info[i].exist = false; + break; + } + ctx_info[i].exist = true; + ctx_info[i].start = mem_desc.base; + ctx_info[i].end = mem_desc.limit; + mem_type[i] = j; + break; + } + } + if (!found) + ctx_info[i].exist = false; + } + /* Get FLM and CNM max qid. */ value = t4_read_reg(padap, SGE_FLM_CFG_A); /* Get number of data freelist queues */ flq = HDRSTARTFLQ_G(value); - size = CUDBG_MAX_FL_QIDS >> flq; + ctx_info[CTXT_FLM].exist = true; + ctx_info[CTXT_FLM].end = (CUDBG_MAX_FL_QIDS >> flq) * SGE_CTXT_SIZE; - /* Add extra space for congestion manager contexts. - * The number of CONM contexts are same as number of freelist + /* The number of CONM contexts are same as number of freelist * queues. */ - size += size; + ctx_info[CTXT_CNM].exist = true; + ctx_info[CTXT_CNM].end = ctx_info[CTXT_FLM].end; + + return 0; +} + +int cudbg_dump_context_size(struct adapter *padap) +{ + struct cudbg_region_info region_info[CTXT_CNM + 1] = { {0} }; + u8 mem_type[CTXT_INGRESS + 1] = { 0 }; + u32 i, size = 0; + int rc; + + /* Get max valid qid for each type of queue */ + rc = cudbg_get_ctxt_region_info(padap, region_info, mem_type); + if (rc) + return rc; + + for (i = 0; i < CTXT_CNM; i++) { + if (!region_info[i].exist) { + if (i == CTXT_EGRESS || i == CTXT_INGRESS) + size += CUDBG_LOWMEM_MAX_CTXT_QIDS * + SGE_CTXT_SIZE; + continue; + } + + size += (region_info[i].end - region_info[i].start + 1) / + SGE_CTXT_SIZE; + } return size * sizeof(struct cudbg_ch_cntxt); } @@ -1632,16 +1718,54 @@ static void cudbg_read_sge_ctxt(struct cudbg_init *pdbg_init, u32 cid, t4_sge_ctxt_rd_bd(padap, cid, ctype, data); } +static void cudbg_get_sge_ctxt_fw(struct cudbg_init *pdbg_init, u32 max_qid, + u8 ctxt_type, + struct cudbg_ch_cntxt **out_buff) +{ + struct cudbg_ch_cntxt *buff = *out_buff; + int rc; + u32 j; + + for (j = 0; j < max_qid; j++) { + cudbg_read_sge_ctxt(pdbg_init, j, ctxt_type, buff->data); + rc = cudbg_sge_ctxt_check_valid(buff->data, ctxt_type); + if (!rc) + continue; + + buff->cntxt_type = ctxt_type; + buff->cntxt_id = j; + buff++; + if (ctxt_type == CTXT_FLM) { + cudbg_read_sge_ctxt(pdbg_init, j, CTXT_CNM, buff->data); + buff->cntxt_type = CTXT_CNM; + buff->cntxt_id = j; + buff++; + } + } + + *out_buff = buff; +} + int cudbg_collect_dump_context(struct cudbg_init *pdbg_init, struct cudbg_buffer *dbg_buff, struct cudbg_error *cudbg_err) { + struct cudbg_region_info region_info[CTXT_CNM + 1] = { {0} }; struct adapter *padap = pdbg_init->adap; + u32 j, size, max_ctx_size, max_ctx_qid; + u8 mem_type[CTXT_INGRESS + 1] = { 0 }; struct cudbg_buffer temp_buff = { 0 }; struct cudbg_ch_cntxt *buff; - u32 size, i = 0; + u64 *dst_off, *src_off; + u8 *ctx_buf; + u8 i, k; int rc; + /* Get max valid qid for each type of queue */ + rc = cudbg_get_ctxt_region_info(padap, region_info, mem_type); + if (rc) + return rc; + rc = cudbg_dump_context_size(padap); if (rc <= 0) return CUDBG_STATUS_ENTITY_NOT_FOUND; @@ -1651,23 +1775,79 @@ int cudbg_collect_dump_context(struct cudbg_init *pdbg_init, if (rc) return rc; + /* Get buffer with enough space to read the biggest context + * region in memory. + */ + max_ctx_size = max(region_info[CTXT_EGRESS].end - + region_info[CTXT_EGRESS].start + 1, + region_info[CTXT_INGRESS].end - + region_info[CTXT_INGRESS].start + 1); + + ctx_buf = kvzalloc(max_ctx_size, GFP_KERNEL); + if (!ctx_buf) { + cudbg_put_buff(&temp_buff, dbg_buff); + return -ENOMEM; + } + buff = (struct cudbg_ch_cntxt *)temp_buff.data; - while (size > 0) { - buff->cntxt_type = CTXT_FLM; - buff->cntxt_id = i; - cudbg_read_sge_ctxt(pdbg_init, i, CTXT_FLM, buff->data); - buff++; - size -= sizeof(struct cudbg_ch_cntxt); - buff->cntxt_type = CTXT_CNM; - buff->cntxt_id = i; - cudbg_read_sge_ctxt(pdbg_init, i, CTXT_CNM, buff->data); - buff++; - size -= sizeof(struct cudbg_ch_cntxt); + /* Collect EGRESS and INGRESS context data. + * In case of failures, fallback to collecting via FW or + * backdoor access. + */ + for (i = CTXT_EGRESS; i <= CTXT_INGRESS; i++) { + if (!region_info[i].exist) { + max_ctx_qid = CUDBG_LOWMEM_MAX_CTXT_QIDS; + cudbg_get_sge_ctxt_fw(pdbg_init, max_ctx_qid, i, + &buff); + continue; + } - i++; + max_ctx_size = region_info[i].end - region_info[i].start + 1; + max_ctx_qid = max_ctx_size / SGE_CTXT_SIZE; + + t4_sge_ctxt_flush(padap, padap->mbox, i); + rc = t4_memory_rw(padap, MEMWIN_NIC, mem_type[i], + region_info[i].start, max_ctx_size, + (__be32 *)ctx_buf, 1); + if (rc) { + max_ctx_qid = CUDBG_LOWMEM_MAX_CTXT_QIDS; + cudbg_get_sge_ctxt_fw(pdbg_init, max_ctx_qid, i, + &buff); + continue; + } + + for (j = 0; j < max_ctx_qid; j++) { + src_off = (u64 *)(ctx_buf + j * SGE_CTXT_SIZE); + dst_off = (u64 *)buff->data; + + /* The data is stored in 64-bit cpu order. Convert it + * to big endian before parsing. + */ + for (k = 0; k < SGE_CTXT_SIZE / sizeof(u64); k++) + dst_off[k] = cpu_to_be64(src_off[k]); + + rc = cudbg_sge_ctxt_check_valid(buff->data, i); + if (!rc) + continue; + + buff->cntxt_type = i; + buff->cntxt_id = j; + buff++; + } } + kvfree(ctx_buf); + + /* Collect FREELIST and CONGESTION MANAGER contexts */ + max_ctx_size = region_info[CTXT_FLM].end - + region_info[CTXT_FLM].start + 1; + max_ctx_qid = max_ctx_size / SGE_CTXT_SIZE; + /* Since FLM and CONM are 1-to-1 mapped, the below function + * will fetch both FLM and CONM contexts. + */ + cudbg_get_sge_ctxt_fw(pdbg_init, max_ctx_qid, CTXT_FLM, &buff); + cudbg_write_and_release_buff(&temp_buff, dbg_buff); return rc; } diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h index e680beed9030..97dc3efeb234 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h @@ -1654,7 +1654,7 @@ int t4_ctrl_eq_free(struct adapter *adap, unsigned int mbox, unsigned int pf, unsigned int vf, unsigned int eqid); int t4_ofld_eq_free(struct adapter *adap, unsigned int mbox, unsigned int pf, unsigned int vf, unsigned int eqid); -int t4_sge_ctxt_flush(struct adapter *adap, unsigned int mbox); +int t4_sge_ctxt_flush(struct adapter *adap, unsigned int mbox, int ctxt_type); void t4_handle_get_port_info(struct port_info *pi, const __be64 *rpl); int t4_update_port_info(struct port_info *pi); int t4_get_link_params(struct port_info *pi, unsigned int *link_okp, diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c index 6f900ffe25cc..87ac1e4dafc1 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c @@ -1673,7 +1673,7 @@ int cxgb4_flush_eq_cache(struct net_device *dev) { struct adapter *adap = netdev2adap(dev); - return t4_sge_ctxt_flush(adap, adap->mbox); + return t4_sge_ctxt_flush(adap, adap->mbox, CTXT_EGRESS); } EXPORT_SYMBOL(cxgb4_flush_eq_cache); diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c index ccb2798c34d1..112963defd0b 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c @@ -6530,18 +6530,21 @@ void t4_sge_decode_idma_state(struct adapter *adapter, int state) * t4_sge_ctxt_flush - flush the SGE context cache * @adap: the adapter * @mbox: mailbox to use for the FW command + * @ctx_type: Egress or Ingress * * Issues a FW command through the given mailbox to flush the * SGE context cache. */ -int t4_sge_ctxt_flush(struct adapter *adap, unsigned int mbox) +int t4_sge_ctxt_flush(struct adapter *adap, unsigned int mbox, int ctxt_type) { int ret; u32 ldst_addrspace; struct fw_ldst_cmd c; memset(&c, 0, sizeof(c)); - ldst_addrspace = FW_LDST_CMD_ADDRSPACE_V(FW_LDST_ADDRSPC_SGE_EGRC); + ldst_addrspace = FW_LDST_CMD_ADDRSPACE_V(ctxt_type == CTXT_EGRESS ? + FW_LDST_ADDRSPC_SGE_EGRC : + FW_LDST_ADDRSPC_SGE_INGC); c.op_to_addrspace = cpu_to_be32(FW_CMD_OP_V(FW_LDST_CMD) | FW_CMD_REQUEST_F | FW_CMD_READ_F | ldst_addrspace); diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.h b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.h index a964ed184356..83afb32c8491 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.h +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.h @@ -70,7 +70,9 @@ enum { /* SGE context types */ enum ctxt_type { - CTXT_FLM = 2, + CTXT_EGRESS, + CTXT_INGRESS, + CTXT_FLM, CTXT_CNM, }; |