freebsd-skq/sys/dev/cxgbe/cudbg/cudbg_lib.c
Navdeep Parhar 8ee789e9fa cxgbe(4): Fix unsafe mailbox access in cudbg.
MFC after:	1 week
Sponsored by:	Chelsio Communications
2017-11-21 01:18:58 +00:00

4455 lines
110 KiB
C

/*-
* Copyright (c) 2017 Chelsio Communications, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/types.h>
#include <sys/param.h>
#include "common/common.h"
#include "common/t4_regs.h"
#include "cudbg.h"
#include "cudbg_lib_common.h"
#include "cudbg_lib.h"
#include "cudbg_entity.h"
#define BUFFER_WARN_LIMIT 10000000
struct large_entity large_entity_list[] = {
{CUDBG_EDC0, 0, 0},
{CUDBG_EDC1, 0 , 0},
{CUDBG_MC0, 0, 0},
{CUDBG_MC1, 0, 0}
};
static int is_fw_attached(struct cudbg_init *pdbg_init)
{
return (pdbg_init->adap->flags & FW_OK);
}
/* This function will add additional padding bytes into debug_buffer to make it
* 4 byte aligned.*/
static void align_debug_buffer(struct cudbg_buffer *dbg_buff,
struct cudbg_entity_hdr *entity_hdr)
{
u8 zero_buf[4] = {0};
u8 padding, remain;
remain = (dbg_buff->offset - entity_hdr->start_offset) % 4;
padding = 4 - remain;
if (remain) {
memcpy(((u8 *) dbg_buff->data) + dbg_buff->offset, &zero_buf,
padding);
dbg_buff->offset += padding;
entity_hdr->num_pad = padding;
}
entity_hdr->size = dbg_buff->offset - entity_hdr->start_offset;
}
static void read_sge_ctxt(struct cudbg_init *pdbg_init, u32 cid,
enum ctxt_type ctype, u32 *data)
{
struct adapter *padap = pdbg_init->adap;
int rc = -1;
if (is_fw_attached(pdbg_init)) {
rc = begin_synchronized_op(padap, NULL, SLEEP_OK | INTR_OK,
"t4cudf");
if (rc != 0)
goto out;
rc = t4_sge_ctxt_rd(padap, padap->mbox, cid, ctype,
data);
end_synchronized_op(padap, 0);
}
out:
if (rc)
t4_sge_ctxt_rd_bd(padap, cid, ctype, data);
}
static int get_next_ext_entity_hdr(void *outbuf, u32 *ext_size,
struct cudbg_buffer *dbg_buff,
struct cudbg_entity_hdr **entity_hdr)
{
struct cudbg_hdr *cudbg_hdr = (struct cudbg_hdr *)outbuf;
int rc = 0;
u32 ext_offset = cudbg_hdr->data_len;
*ext_size = 0;
if (dbg_buff->size - dbg_buff->offset <=
sizeof(struct cudbg_entity_hdr)) {
rc = CUDBG_STATUS_BUFFER_SHORT;
goto err;
}
*entity_hdr = (struct cudbg_entity_hdr *)
((char *)outbuf + cudbg_hdr->data_len);
/* Find the last extended entity header */
while ((*entity_hdr)->size) {
ext_offset += sizeof(struct cudbg_entity_hdr) +
(*entity_hdr)->size;
*ext_size += (*entity_hdr)->size +
sizeof(struct cudbg_entity_hdr);
if (dbg_buff->size - dbg_buff->offset + *ext_size <=
sizeof(struct cudbg_entity_hdr)) {
rc = CUDBG_STATUS_BUFFER_SHORT;
goto err;
}
if (ext_offset != (*entity_hdr)->next_ext_offset) {
ext_offset -= sizeof(struct cudbg_entity_hdr) +
(*entity_hdr)->size;
break;
}
(*entity_hdr)->next_ext_offset = *ext_size;
*entity_hdr = (struct cudbg_entity_hdr *)
((char *)outbuf +
ext_offset);
}
/* update the data offset */
dbg_buff->offset = ext_offset;
err:
return rc;
}
static int wr_entity_to_flash(void *handle, struct cudbg_buffer *dbg_buff,
u32 cur_entity_data_offset,
u32 cur_entity_size,
int entity_nu, u32 ext_size)
{
struct cudbg_private *priv = handle;
struct cudbg_init *cudbg_init = &priv->dbg_init;
struct cudbg_flash_sec_info *sec_info = &priv->sec_info;
u64 timestamp;
u32 cur_entity_hdr_offset = sizeof(struct cudbg_hdr);
u32 remain_flash_size;
u32 flash_data_offset;
u32 data_hdr_size;
int rc = -1;
data_hdr_size = CUDBG_MAX_ENTITY * sizeof(struct cudbg_entity_hdr) +
sizeof(struct cudbg_hdr);
flash_data_offset = (FLASH_CUDBG_NSECS *
(sizeof(struct cudbg_flash_hdr) +
data_hdr_size)) +
(cur_entity_data_offset - data_hdr_size);
if (flash_data_offset > CUDBG_FLASH_SIZE) {
update_skip_size(sec_info, cur_entity_size);
if (cudbg_init->verbose)
cudbg_init->print("Large entity skipping...\n");
return rc;
}
remain_flash_size = CUDBG_FLASH_SIZE - flash_data_offset;
if (cur_entity_size > remain_flash_size) {
update_skip_size(sec_info, cur_entity_size);
if (cudbg_init->verbose)
cudbg_init->print("Large entity skipping...\n");
} else {
timestamp = 0;
cur_entity_hdr_offset +=
(sizeof(struct cudbg_entity_hdr) *
(entity_nu - 1));
rc = cudbg_write_flash(handle, timestamp, dbg_buff,
cur_entity_data_offset,
cur_entity_hdr_offset,
cur_entity_size,
ext_size);
if (rc == CUDBG_STATUS_FLASH_FULL && cudbg_init->verbose)
cudbg_init->print("\n\tFLASH is full... "
"can not write in flash more\n\n");
}
return rc;
}
int cudbg_collect(void *handle, void *outbuf, u32 *outbuf_size)
{
struct cudbg_entity_hdr *entity_hdr = NULL;
struct cudbg_entity_hdr *ext_entity_hdr = NULL;
struct cudbg_hdr *cudbg_hdr;
struct cudbg_buffer dbg_buff;
struct cudbg_error cudbg_err = {0};
int large_entity_code;
u8 *dbg_bitmap = ((struct cudbg_private *)handle)->dbg_init.dbg_bitmap;
struct cudbg_init *cudbg_init =
&(((struct cudbg_private *)handle)->dbg_init);
struct adapter *padap = cudbg_init->adap;
u32 total_size, remaining_buf_size;
u32 ext_size = 0;
int index, bit, i, rc = -1;
int all;
bool flag_ext = 0;
reset_skip_entity();
dbg_buff.data = outbuf;
dbg_buff.size = *outbuf_size;
dbg_buff.offset = 0;
cudbg_hdr = (struct cudbg_hdr *)dbg_buff.data;
cudbg_hdr->signature = CUDBG_SIGNATURE;
cudbg_hdr->hdr_len = sizeof(struct cudbg_hdr);
cudbg_hdr->major_ver = CUDBG_MAJOR_VERSION;
cudbg_hdr->minor_ver = CUDBG_MINOR_VERSION;
cudbg_hdr->max_entities = CUDBG_MAX_ENTITY;
cudbg_hdr->chip_ver = padap->params.chipid;
if (cudbg_hdr->data_len)
flag_ext = 1;
if (cudbg_init->use_flash) {
#ifndef notyet
rc = t4_get_flash_params(padap);
if (rc) {
if (cudbg_init->verbose)
cudbg_init->print("\nGet flash params failed.\n\n");
cudbg_init->use_flash = 0;
}
#endif
#ifdef notyet
/* Timestamp is mandatory. If it is not passed then disable
* flash support
*/
if (!cudbg_init->dbg_params[CUDBG_TIMESTAMP_PARAM].u.time) {
if (cudbg_init->verbose)
cudbg_init->print("\nTimestamp param missing,"
"so ignoring flash write request\n\n");
cudbg_init->use_flash = 0;
}
#endif
}
if (sizeof(struct cudbg_entity_hdr) * CUDBG_MAX_ENTITY >
dbg_buff.size) {
rc = CUDBG_STATUS_SMALL_BUFF;
total_size = cudbg_hdr->hdr_len;
goto err;
}
/* If ext flag is set then move the offset to the end of the buf
* so that we can add ext entities
*/
if (flag_ext) {
ext_entity_hdr = (struct cudbg_entity_hdr *)
((char *)outbuf + cudbg_hdr->hdr_len +
(sizeof(struct cudbg_entity_hdr) *
(CUDBG_EXT_ENTITY - 1)));
ext_entity_hdr->start_offset = cudbg_hdr->data_len;
ext_entity_hdr->entity_type = CUDBG_EXT_ENTITY;
ext_entity_hdr->size = 0;
dbg_buff.offset = cudbg_hdr->data_len;
} else {
dbg_buff.offset += cudbg_hdr->hdr_len; /* move 24 bytes*/
dbg_buff.offset += CUDBG_MAX_ENTITY *
sizeof(struct cudbg_entity_hdr);
}
total_size = dbg_buff.offset;
all = dbg_bitmap[0] & (1 << CUDBG_ALL);
/*sort(large_entity_list);*/
for (i = 1; i < CUDBG_MAX_ENTITY; i++) {
index = i / 8;
bit = i % 8;
if (entity_list[i].bit == CUDBG_EXT_ENTITY)
continue;
if (all || (dbg_bitmap[index] & (1 << bit))) {
if (!flag_ext) {
rc = get_entity_hdr(outbuf, i, dbg_buff.size,
&entity_hdr);
if (rc)
cudbg_hdr->hdr_flags = rc;
} else {
rc = get_next_ext_entity_hdr(outbuf, &ext_size,
&dbg_buff,
&entity_hdr);
if (rc)
goto err;
/* move the offset after the ext header */
dbg_buff.offset +=
sizeof(struct cudbg_entity_hdr);
}
entity_hdr->entity_type = i;
entity_hdr->start_offset = dbg_buff.offset;
/* process each entity by calling process_entity fp */
remaining_buf_size = dbg_buff.size - dbg_buff.offset;
if ((remaining_buf_size <= BUFFER_WARN_LIMIT) &&
is_large_entity(i)) {
if (cudbg_init->verbose)
cudbg_init->print("Skipping %s\n",
entity_list[i].name);
skip_entity(i);
continue;
} else {
/* If fw_attach is 0, then skip entities which
* communicates with firmware
*/
if (!is_fw_attached(cudbg_init) &&
(entity_list[i].flag &
(1 << ENTITY_FLAG_FW_NO_ATTACH))) {
if (cudbg_init->verbose)
cudbg_init->print("Skipping %s entity,"\
"because fw_attach "\
"is 0\n",
entity_list[i].name);
continue;
}
if (cudbg_init->verbose)
cudbg_init->print("collecting debug entity: "\
"%s\n", entity_list[i].name);
memset(&cudbg_err, 0,
sizeof(struct cudbg_error));
rc = process_entity[i-1](cudbg_init, &dbg_buff,
&cudbg_err);
}
if (rc) {
entity_hdr->size = 0;
dbg_buff.offset = entity_hdr->start_offset;
} else
align_debug_buffer(&dbg_buff, entity_hdr);
if (cudbg_err.sys_err)
rc = CUDBG_SYSTEM_ERROR;
entity_hdr->hdr_flags = rc;
entity_hdr->sys_err = cudbg_err.sys_err;
entity_hdr->sys_warn = cudbg_err.sys_warn;
/* We don't want to include ext entity size in global
* header
*/
if (!flag_ext)
total_size += entity_hdr->size;
cudbg_hdr->data_len = total_size;
*outbuf_size = total_size;
/* consider the size of the ext entity header and data
* also
*/
if (flag_ext) {
ext_size += (sizeof(struct cudbg_entity_hdr) +
entity_hdr->size);
entity_hdr->start_offset -= cudbg_hdr->data_len;
ext_entity_hdr->size = ext_size;
entity_hdr->next_ext_offset = ext_size;
entity_hdr->flag |= CUDBG_EXT_DATA_VALID;
}
if (cudbg_init->use_flash) {
if (flag_ext) {
wr_entity_to_flash(handle,
&dbg_buff,
ext_entity_hdr->
start_offset,
entity_hdr->
size,
CUDBG_EXT_ENTITY,
ext_size);
}
else
wr_entity_to_flash(handle,
&dbg_buff,
entity_hdr->\
start_offset,
entity_hdr->size,
i, ext_size);
}
}
}
for (i = 0; i < sizeof(large_entity_list) / sizeof(struct large_entity);
i++) {
large_entity_code = large_entity_list[i].entity_code;
if (large_entity_list[i].skip_flag) {
if (!flag_ext) {
rc = get_entity_hdr(outbuf, large_entity_code,
dbg_buff.size, &entity_hdr);
if (rc)
cudbg_hdr->hdr_flags = rc;
} else {
rc = get_next_ext_entity_hdr(outbuf, &ext_size,
&dbg_buff,
&entity_hdr);
if (rc)
goto err;
dbg_buff.offset +=
sizeof(struct cudbg_entity_hdr);
}
/* If fw_attach is 0, then skip entities which
* communicates with firmware
*/
if (!is_fw_attached(cudbg_init) &&
(entity_list[large_entity_code].flag &
(1 << ENTITY_FLAG_FW_NO_ATTACH))) {
if (cudbg_init->verbose)
cudbg_init->print("Skipping %s entity,"\
"because fw_attach "\
"is 0\n",
entity_list[large_entity_code]
.name);
continue;
}
entity_hdr->entity_type = large_entity_code;
entity_hdr->start_offset = dbg_buff.offset;
if (cudbg_init->verbose)
cudbg_init->print("Re-trying debug entity: %s\n",
entity_list[large_entity_code].name);
memset(&cudbg_err, 0, sizeof(struct cudbg_error));
rc = process_entity[large_entity_code - 1](cudbg_init,
&dbg_buff,
&cudbg_err);
if (rc) {
entity_hdr->size = 0;
dbg_buff.offset = entity_hdr->start_offset;
} else
align_debug_buffer(&dbg_buff, entity_hdr);
if (cudbg_err.sys_err)
rc = CUDBG_SYSTEM_ERROR;
entity_hdr->hdr_flags = rc;
entity_hdr->sys_err = cudbg_err.sys_err;
entity_hdr->sys_warn = cudbg_err.sys_warn;
/* We don't want to include ext entity size in global
* header
*/
if (!flag_ext)
total_size += entity_hdr->size;
cudbg_hdr->data_len = total_size;
*outbuf_size = total_size;
/* consider the size of the ext entity header and
* data also
*/
if (flag_ext) {
ext_size += (sizeof(struct cudbg_entity_hdr) +
entity_hdr->size);
entity_hdr->start_offset -=
cudbg_hdr->data_len;
ext_entity_hdr->size = ext_size;
entity_hdr->flag |= CUDBG_EXT_DATA_VALID;
}
if (cudbg_init->use_flash) {
if (flag_ext)
wr_entity_to_flash(handle,
&dbg_buff,
ext_entity_hdr->
start_offset,
entity_hdr->size,
CUDBG_EXT_ENTITY,
ext_size);
else
wr_entity_to_flash(handle,
&dbg_buff,
entity_hdr->
start_offset,
entity_hdr->
size,
large_entity_list[i].
entity_code,
ext_size);
}
}
}
cudbg_hdr->data_len = total_size;
*outbuf_size = total_size;
if (flag_ext)
*outbuf_size += ext_size;
return 0;
err:
return rc;
}
void reset_skip_entity(void)
{
int i;
for (i = 0; i < ARRAY_SIZE(large_entity_list); i++)
large_entity_list[i].skip_flag = 0;
}
void skip_entity(int entity_code)
{
int i;
for (i = 0; i < sizeof(large_entity_list) / sizeof(struct large_entity);
i++) {
if (large_entity_list[i].entity_code == entity_code)
large_entity_list[i].skip_flag = 1;
}
}
int is_large_entity(int entity_code)
{
int i;
for (i = 0; i < sizeof(large_entity_list) / sizeof(struct large_entity);
i++) {
if (large_entity_list[i].entity_code == entity_code)
return 1;
}
return 0;
}
int get_entity_hdr(void *outbuf, int i, u32 size,
struct cudbg_entity_hdr **entity_hdr)
{
int rc = 0;
struct cudbg_hdr *cudbg_hdr = (struct cudbg_hdr *)outbuf;
if (cudbg_hdr->hdr_len + (sizeof(struct cudbg_entity_hdr)*i) > size)
return CUDBG_STATUS_SMALL_BUFF;
*entity_hdr = (struct cudbg_entity_hdr *)
((char *)outbuf+cudbg_hdr->hdr_len +
(sizeof(struct cudbg_entity_hdr)*(i-1)));
return rc;
}
static int collect_rss(struct cudbg_init *pdbg_init,
struct cudbg_buffer *dbg_buff,
struct cudbg_error *cudbg_err)
{
struct adapter *padap = pdbg_init->adap;
struct cudbg_buffer scratch_buff;
u32 size;
int rc = 0;
size = RSS_NENTRIES * sizeof(u16);
rc = get_scratch_buff(dbg_buff, size, &scratch_buff);
if (rc)
goto err;
rc = t4_read_rss(padap, (u16 *)scratch_buff.data);
if (rc) {
if (pdbg_init->verbose)
pdbg_init->print("%s(), t4_read_rss failed!, rc: %d\n",
__func__, rc);
cudbg_err->sys_err = rc;
goto err1;
}
rc = write_compression_hdr(&scratch_buff, dbg_buff);
if (rc)
goto err1;
rc = compress_buff(&scratch_buff, dbg_buff);
err1:
release_scratch_buff(&scratch_buff, dbg_buff);
err:
return rc;
}
static int collect_sw_state(struct cudbg_init *pdbg_init,
struct cudbg_buffer *dbg_buff,
struct cudbg_error *cudbg_err)
{
struct adapter *padap = pdbg_init->adap;
struct cudbg_buffer scratch_buff;
struct sw_state *swstate;
u32 size;
int rc = 0;
size = sizeof(struct sw_state);
rc = get_scratch_buff(dbg_buff, size, &scratch_buff);
if (rc)
goto err;
swstate = (struct sw_state *) scratch_buff.data;
swstate->fw_state = t4_read_reg(padap, A_PCIE_FW);
snprintf(swstate->caller_string, sizeof(swstate->caller_string), "%s",
"FreeBSD");
swstate->os_type = 0;
rc = write_compression_hdr(&scratch_buff, dbg_buff);
if (rc)
goto err1;
rc = compress_buff(&scratch_buff, dbg_buff);
err1:
release_scratch_buff(&scratch_buff, dbg_buff);
err:
return rc;
}
static int collect_ddp_stats(struct cudbg_init *pdbg_init,
struct cudbg_buffer *dbg_buff,
struct cudbg_error *cudbg_err)
{
struct adapter *padap = pdbg_init->adap;
struct cudbg_buffer scratch_buff;
struct tp_usm_stats *tp_usm_stats_buff;
u32 size;
int rc = 0;
size = sizeof(struct tp_usm_stats);
rc = get_scratch_buff(dbg_buff, size, &scratch_buff);
if (rc)
goto err;
tp_usm_stats_buff = (struct tp_usm_stats *) scratch_buff.data;
/* spin_lock(&padap->stats_lock); TODO*/
t4_get_usm_stats(padap, tp_usm_stats_buff, 1);
/* spin_unlock(&padap->stats_lock); TODO*/
rc = write_compression_hdr(&scratch_buff, dbg_buff);
if (rc)
goto err1;
rc = compress_buff(&scratch_buff, dbg_buff);
err1:
release_scratch_buff(&scratch_buff, dbg_buff);
err:
return rc;
}
static int collect_ulptx_la(struct cudbg_init *pdbg_init,
struct cudbg_buffer *dbg_buff,
struct cudbg_error *cudbg_err)
{
struct adapter *padap = pdbg_init->adap;
struct cudbg_buffer scratch_buff;
struct struct_ulptx_la *ulptx_la_buff;
u32 size, i, j;
int rc = 0;
size = sizeof(struct struct_ulptx_la);
rc = get_scratch_buff(dbg_buff, size, &scratch_buff);
if (rc)
goto err;
ulptx_la_buff = (struct struct_ulptx_la *) scratch_buff.data;
for (i = 0; i < CUDBG_NUM_ULPTX; i++) {
ulptx_la_buff->rdptr[i] = t4_read_reg(padap,
A_ULP_TX_LA_RDPTR_0 +
0x10 * i);
ulptx_la_buff->wrptr[i] = t4_read_reg(padap,
A_ULP_TX_LA_WRPTR_0 +
0x10 * i);
ulptx_la_buff->rddata[i] = t4_read_reg(padap,
A_ULP_TX_LA_RDDATA_0 +
0x10 * i);
for (j = 0; j < CUDBG_NUM_ULPTX_READ; j++) {
ulptx_la_buff->rd_data[i][j] =
t4_read_reg(padap,
A_ULP_TX_LA_RDDATA_0 + 0x10 * i);
}
}
rc = write_compression_hdr(&scratch_buff, dbg_buff);
if (rc)
goto err1;
rc = compress_buff(&scratch_buff, dbg_buff);
err1:
release_scratch_buff(&scratch_buff, dbg_buff);
err:
return rc;
}
static int collect_ulprx_la(struct cudbg_init *pdbg_init,
struct cudbg_buffer *dbg_buff,
struct cudbg_error *cudbg_err)
{
struct adapter *padap = pdbg_init->adap;
struct cudbg_buffer scratch_buff;
struct struct_ulprx_la *ulprx_la_buff;
u32 size;
int rc = 0;
size = sizeof(struct struct_ulprx_la);
rc = get_scratch_buff(dbg_buff, size, &scratch_buff);
if (rc)
goto err;
ulprx_la_buff = (struct struct_ulprx_la *) scratch_buff.data;
t4_ulprx_read_la(padap, (u32 *)ulprx_la_buff->data);
ulprx_la_buff->size = ULPRX_LA_SIZE;
rc = write_compression_hdr(&scratch_buff, dbg_buff);
if (rc)
goto err1;
rc = compress_buff(&scratch_buff, dbg_buff);
err1:
release_scratch_buff(&scratch_buff, dbg_buff);
err:
return rc;
}
static int collect_cpl_stats(struct cudbg_init *pdbg_init,
struct cudbg_buffer *dbg_buff,
struct cudbg_error *cudbg_err)
{
struct adapter *padap = pdbg_init->adap;
struct cudbg_buffer scratch_buff;
struct struct_tp_cpl_stats *tp_cpl_stats_buff;
u32 size;
int rc = 0;
size = sizeof(struct struct_tp_cpl_stats);
rc = get_scratch_buff(dbg_buff, size, &scratch_buff);
if (rc)
goto err;
tp_cpl_stats_buff = (struct struct_tp_cpl_stats *) scratch_buff.data;
tp_cpl_stats_buff->nchan = padap->chip_params->nchan;
/* spin_lock(&padap->stats_lock); TODO*/
t4_tp_get_cpl_stats(padap, &tp_cpl_stats_buff->stats, 1);
/* spin_unlock(&padap->stats_lock); TODO*/
rc = write_compression_hdr(&scratch_buff, dbg_buff);
if (rc)
goto err1;
rc = compress_buff(&scratch_buff, dbg_buff);
err1:
release_scratch_buff(&scratch_buff, dbg_buff);
err:
return rc;
}
static int collect_wc_stats(struct cudbg_init *pdbg_init,
struct cudbg_buffer *dbg_buff,
struct cudbg_error *cudbg_err)
{
struct adapter *padap = pdbg_init->adap;
struct cudbg_buffer scratch_buff;
struct struct_wc_stats *wc_stats_buff;
u32 val1;
u32 val2;
u32 size;
int rc = 0;
size = sizeof(struct struct_wc_stats);
rc = get_scratch_buff(dbg_buff, size, &scratch_buff);
if (rc)
goto err;
wc_stats_buff = (struct struct_wc_stats *) scratch_buff.data;
if (!is_t4(padap)) {
val1 = t4_read_reg(padap, A_SGE_STAT_TOTAL);
val2 = t4_read_reg(padap, A_SGE_STAT_MATCH);
wc_stats_buff->wr_cl_success = val1 - val2;
wc_stats_buff->wr_cl_fail = val2;
} else {
wc_stats_buff->wr_cl_success = 0;
wc_stats_buff->wr_cl_fail = 0;
}
rc = write_compression_hdr(&scratch_buff, dbg_buff);
if (rc)
goto err1;
rc = compress_buff(&scratch_buff, dbg_buff);
err1:
release_scratch_buff(&scratch_buff, dbg_buff);
err:
return rc;
}
static int mem_desc_cmp(const void *a, const void *b)
{
return ((const struct struct_mem_desc *)a)->base -
((const struct struct_mem_desc *)b)->base;
}
static int fill_meminfo(struct adapter *padap,
struct struct_meminfo *meminfo_buff)
{
struct struct_mem_desc *md;
u32 size, lo, hi;
u32 used, alloc;
int n, i, rc = 0;
size = sizeof(struct struct_meminfo);
memset(meminfo_buff->avail, 0,
ARRAY_SIZE(meminfo_buff->avail) *
sizeof(struct struct_mem_desc));
memset(meminfo_buff->mem, 0,
(ARRAY_SIZE(region) + 3) * sizeof(struct struct_mem_desc));
md = meminfo_buff->mem;
for (i = 0; i < ARRAY_SIZE(meminfo_buff->mem); i++) {
meminfo_buff->mem[i].limit = 0;
meminfo_buff->mem[i].idx = i;
}
i = 0;
lo = t4_read_reg(padap, A_MA_TARGET_MEM_ENABLE);
if (lo & F_EDRAM0_ENABLE) {
hi = t4_read_reg(padap, A_MA_EDRAM0_BAR);
meminfo_buff->avail[i].base = G_EDRAM0_BASE(hi) << 20;
meminfo_buff->avail[i].limit = meminfo_buff->avail[i].base +
(G_EDRAM0_SIZE(hi) << 20);
meminfo_buff->avail[i].idx = 0;
i++;
}
if (lo & F_EDRAM1_ENABLE) {
hi = t4_read_reg(padap, A_MA_EDRAM1_BAR);
meminfo_buff->avail[i].base = G_EDRAM1_BASE(hi) << 20;
meminfo_buff->avail[i].limit = meminfo_buff->avail[i].base +
(G_EDRAM1_SIZE(hi) << 20);
meminfo_buff->avail[i].idx = 1;
i++;
}
if (is_t5(padap)) {
if (lo & F_EXT_MEM0_ENABLE) {
hi = t4_read_reg(padap, A_MA_EXT_MEMORY0_BAR);
meminfo_buff->avail[i].base = G_EXT_MEM_BASE(hi) << 20;
meminfo_buff->avail[i].limit =
meminfo_buff->avail[i].base +
(G_EXT_MEM_SIZE(hi) << 20);
meminfo_buff->avail[i].idx = 3;
i++;
}
if (lo & F_EXT_MEM1_ENABLE) {
hi = t4_read_reg(padap, A_MA_EXT_MEMORY1_BAR);
meminfo_buff->avail[i].base = G_EXT_MEM1_BASE(hi) << 20;
meminfo_buff->avail[i].limit =
meminfo_buff->avail[i].base +
(G_EXT_MEM1_SIZE(hi) << 20);
meminfo_buff->avail[i].idx = 4;
i++;
}
} else if (is_t6(padap)) {
if (lo & F_EXT_MEM_ENABLE) {
hi = t4_read_reg(padap, A_MA_EXT_MEMORY_BAR);
meminfo_buff->avail[i].base = G_EXT_MEM_BASE(hi) << 20;
meminfo_buff->avail[i].limit =
meminfo_buff->avail[i].base +
(G_EXT_MEM_SIZE(hi) << 20);
meminfo_buff->avail[i].idx = 2;
i++;
}
}
if (!i) { /* no memory available */
rc = CUDBG_STATUS_ENTITY_NOT_FOUND;
goto err;
}
meminfo_buff->avail_c = i;
qsort(meminfo_buff->avail, i, sizeof(struct struct_mem_desc),
mem_desc_cmp);
(md++)->base = t4_read_reg(padap, A_SGE_DBQ_CTXT_BADDR);
(md++)->base = t4_read_reg(padap, A_SGE_IMSG_CTXT_BADDR);
(md++)->base = t4_read_reg(padap, A_SGE_FLM_CACHE_BADDR);
(md++)->base = t4_read_reg(padap, A_TP_CMM_TCB_BASE);
(md++)->base = t4_read_reg(padap, A_TP_CMM_MM_BASE);
(md++)->base = t4_read_reg(padap, A_TP_CMM_TIMER_BASE);
(md++)->base = t4_read_reg(padap, A_TP_CMM_MM_RX_FLST_BASE);
(md++)->base = t4_read_reg(padap, A_TP_CMM_MM_TX_FLST_BASE);
(md++)->base = t4_read_reg(padap, A_TP_CMM_MM_PS_FLST_BASE);
/* the next few have explicit upper bounds */
md->base = t4_read_reg(padap, A_TP_PMM_TX_BASE);
md->limit = md->base - 1 +
t4_read_reg(padap,
A_TP_PMM_TX_PAGE_SIZE) *
G_PMTXMAXPAGE(t4_read_reg(padap,
A_TP_PMM_TX_MAX_PAGE)
);
md++;
md->base = t4_read_reg(padap, A_TP_PMM_RX_BASE);
md->limit = md->base - 1 +
t4_read_reg(padap,
A_TP_PMM_RX_PAGE_SIZE) *
G_PMRXMAXPAGE(t4_read_reg(padap,
A_TP_PMM_RX_MAX_PAGE)
);
md++;
if (t4_read_reg(padap, A_LE_DB_CONFIG) & F_HASHEN) {
if (chip_id(padap) <= CHELSIO_T5) {
hi = t4_read_reg(padap, A_LE_DB_TID_HASHBASE) / 4;
md->base = t4_read_reg(padap, A_LE_DB_HASH_TID_BASE);
} else {
hi = t4_read_reg(padap, A_LE_DB_HASH_TID_BASE);
md->base = t4_read_reg(padap,
A_LE_DB_HASH_TBL_BASE_ADDR);
}
md->limit = 0;
} else {
md->base = 0;
md->idx = ARRAY_SIZE(region); /* hide it */
}
md++;
#define ulp_region(reg) \
{\
md->base = t4_read_reg(padap, A_ULP_ ## reg ## _LLIMIT);\
(md++)->limit = t4_read_reg(padap, A_ULP_ ## reg ## _ULIMIT);\
}
ulp_region(RX_ISCSI);
ulp_region(RX_TDDP);
ulp_region(TX_TPT);
ulp_region(RX_STAG);
ulp_region(RX_RQ);
ulp_region(RX_RQUDP);
ulp_region(RX_PBL);
ulp_region(TX_PBL);
#undef ulp_region
md->base = 0;
md->idx = ARRAY_SIZE(region);
if (!is_t4(padap)) {
u32 sge_ctrl = t4_read_reg(padap, A_SGE_CONTROL2);
u32 fifo_size = t4_read_reg(padap, A_SGE_DBVFIFO_SIZE);
if (is_t5(padap)) {
if (sge_ctrl & F_VFIFO_ENABLE)
size = G_DBVFIFO_SIZE(fifo_size);
} else
size = G_T6_DBVFIFO_SIZE(fifo_size);
if (size) {
md->base = G_BASEADDR(t4_read_reg(padap,
A_SGE_DBVFIFO_BADDR));
md->limit = md->base + (size << 2) - 1;
}
}
md++;
md->base = t4_read_reg(padap, A_ULP_RX_CTX_BASE);
md->limit = 0;
md++;
md->base = t4_read_reg(padap, A_ULP_TX_ERR_TABLE_BASE);
md->limit = 0;
md++;
#ifndef __NO_DRIVER_OCQ_SUPPORT__
/*md->base = padap->vres.ocq.start;*/
/*if (adap->vres.ocq.size)*/
/* md->limit = md->base + adap->vres.ocq.size - 1;*/
/*else*/
md->idx = ARRAY_SIZE(region); /* hide it */
md++;
#endif
/* add any address-space holes, there can be up to 3 */
for (n = 0; n < i - 1; n++)
if (meminfo_buff->avail[n].limit <
meminfo_buff->avail[n + 1].base)
(md++)->base = meminfo_buff->avail[n].limit;
if (meminfo_buff->avail[n].limit)
(md++)->base = meminfo_buff->avail[n].limit;
n = (int) (md - meminfo_buff->mem);
meminfo_buff->mem_c = n;
qsort(meminfo_buff->mem, n, sizeof(struct struct_mem_desc),
mem_desc_cmp);
lo = t4_read_reg(padap, A_CIM_SDRAM_BASE_ADDR);
hi = t4_read_reg(padap, A_CIM_SDRAM_ADDR_SIZE) + lo - 1;
meminfo_buff->up_ram_lo = lo;
meminfo_buff->up_ram_hi = hi;
lo = t4_read_reg(padap, A_CIM_EXTMEM2_BASE_ADDR);
hi = t4_read_reg(padap, A_CIM_EXTMEM2_ADDR_SIZE) + lo - 1;
meminfo_buff->up_extmem2_lo = lo;
meminfo_buff->up_extmem2_hi = hi;
lo = t4_read_reg(padap, A_TP_PMM_RX_MAX_PAGE);
meminfo_buff->rx_pages_data[0] = G_PMRXMAXPAGE(lo);
meminfo_buff->rx_pages_data[1] =
t4_read_reg(padap, A_TP_PMM_RX_PAGE_SIZE) >> 10;
meminfo_buff->rx_pages_data[2] = (lo & F_PMRXNUMCHN) ? 2 : 1 ;
lo = t4_read_reg(padap, A_TP_PMM_TX_MAX_PAGE);
hi = t4_read_reg(padap, A_TP_PMM_TX_PAGE_SIZE);
meminfo_buff->tx_pages_data[0] = G_PMTXMAXPAGE(lo);
meminfo_buff->tx_pages_data[1] =
hi >= (1 << 20) ? (hi >> 20) : (hi >> 10);
meminfo_buff->tx_pages_data[2] =
hi >= (1 << 20) ? 'M' : 'K';
meminfo_buff->tx_pages_data[3] = 1 << G_PMTXNUMCHN(lo);
for (i = 0; i < 4; i++) {
if (chip_id(padap) > CHELSIO_T5)
lo = t4_read_reg(padap,
A_MPS_RX_MAC_BG_PG_CNT0 + i * 4);
else
lo = t4_read_reg(padap, A_MPS_RX_PG_RSV0 + i * 4);
if (is_t5(padap)) {
used = G_T5_USED(lo);
alloc = G_T5_ALLOC(lo);
} else {
used = G_USED(lo);
alloc = G_ALLOC(lo);
}
meminfo_buff->port_used[i] = used;
meminfo_buff->port_alloc[i] = alloc;
}
for (i = 0; i < padap->chip_params->nchan; i++) {
if (chip_id(padap) > CHELSIO_T5)
lo = t4_read_reg(padap,
A_MPS_RX_LPBK_BG_PG_CNT0 + i * 4);
else
lo = t4_read_reg(padap, A_MPS_RX_PG_RSV4 + i * 4);
if (is_t5(padap)) {
used = G_T5_USED(lo);
alloc = G_T5_ALLOC(lo);
} else {
used = G_USED(lo);
alloc = G_ALLOC(lo);
}
meminfo_buff->loopback_used[i] = used;
meminfo_buff->loopback_alloc[i] = alloc;
}
err:
return rc;
}
static int collect_meminfo(struct cudbg_init *pdbg_init,
struct cudbg_buffer *dbg_buff,
struct cudbg_error *cudbg_err)
{
struct adapter *padap = pdbg_init->adap;
struct cudbg_buffer scratch_buff;
struct struct_meminfo *meminfo_buff;
int rc = 0;
u32 size;
size = sizeof(struct struct_meminfo);
rc = get_scratch_buff(dbg_buff, size, &scratch_buff);
if (rc)
goto err;
meminfo_buff = (struct struct_meminfo *)scratch_buff.data;
rc = fill_meminfo(padap, meminfo_buff);
if (rc)
goto err;
rc = write_compression_hdr(&scratch_buff, dbg_buff);
if (rc)
goto err1;
rc = compress_buff(&scratch_buff, dbg_buff);
err1:
release_scratch_buff(&scratch_buff, dbg_buff);
err:
return rc;
}
static int collect_lb_stats(struct cudbg_init *pdbg_init,
struct cudbg_buffer *dbg_buff,
struct cudbg_error *cudbg_err)
{
struct adapter *padap = pdbg_init->adap;
struct cudbg_buffer scratch_buff;
struct lb_port_stats *tmp_stats;
struct struct_lb_stats *lb_stats_buff;
u32 i, n, size;
int rc = 0;
rc = padap->params.nports;
if (rc < 0)
goto err;
n = rc;
size = sizeof(struct struct_lb_stats) +
n * sizeof(struct lb_port_stats);
rc = get_scratch_buff(dbg_buff, size, &scratch_buff);
if (rc)
goto err;
lb_stats_buff = (struct struct_lb_stats *) scratch_buff.data;
lb_stats_buff->nchan = n;
tmp_stats = lb_stats_buff->s;
for (i = 0; i < n; i += 2, tmp_stats += 2) {
t4_get_lb_stats(padap, i, tmp_stats);
t4_get_lb_stats(padap, i + 1, tmp_stats+1);
}
rc = write_compression_hdr(&scratch_buff, dbg_buff);
if (rc)
goto err1;
rc = compress_buff(&scratch_buff, dbg_buff);
err1:
release_scratch_buff(&scratch_buff, dbg_buff);
err:
return rc;
}
static int collect_rdma_stats(struct cudbg_init *pdbg_init,
struct cudbg_buffer *dbg_buff,
struct cudbg_error *cudbg_er)
{
struct adapter *padap = pdbg_init->adap;
struct cudbg_buffer scratch_buff;
struct tp_rdma_stats *rdma_stats_buff;
u32 size;
int rc = 0;
size = sizeof(struct tp_rdma_stats);
rc = get_scratch_buff(dbg_buff, size, &scratch_buff);
if (rc)
goto err;
rdma_stats_buff = (struct tp_rdma_stats *) scratch_buff.data;
/* spin_lock(&padap->stats_lock); TODO*/
t4_tp_get_rdma_stats(padap, rdma_stats_buff, 1);
/* spin_unlock(&padap->stats_lock); TODO*/
rc = write_compression_hdr(&scratch_buff, dbg_buff);
if (rc)
goto err1;
rc = compress_buff(&scratch_buff, dbg_buff);
err1:
release_scratch_buff(&scratch_buff, dbg_buff);
err:
return rc;
}
static int collect_clk_info(struct cudbg_init *pdbg_init,
struct cudbg_buffer *dbg_buff,
struct cudbg_error *cudbg_err)
{
struct cudbg_buffer scratch_buff;
struct adapter *padap = pdbg_init->adap;
struct struct_clk_info *clk_info_buff;
u64 tp_tick_us;
int size;
int rc = 0;
if (!padap->params.vpd.cclk) {
rc = CUDBG_STATUS_CCLK_NOT_DEFINED;
goto err;
}
size = sizeof(struct struct_clk_info);
rc = get_scratch_buff(dbg_buff, size, &scratch_buff);
if (rc)
goto err;
clk_info_buff = (struct struct_clk_info *) scratch_buff.data;
clk_info_buff->cclk_ps = 1000000000 / padap->params.vpd.cclk; /* in ps
*/
clk_info_buff->res = t4_read_reg(padap, A_TP_TIMER_RESOLUTION);
clk_info_buff->tre = G_TIMERRESOLUTION(clk_info_buff->res);
clk_info_buff->dack_re = G_DELAYEDACKRESOLUTION(clk_info_buff->res);
tp_tick_us = (clk_info_buff->cclk_ps << clk_info_buff->tre) / 1000000;
/* in us */
clk_info_buff->dack_timer = ((clk_info_buff->cclk_ps <<
clk_info_buff->dack_re) / 1000000) *
t4_read_reg(padap, A_TP_DACK_TIMER);
clk_info_buff->retransmit_min =
tp_tick_us * t4_read_reg(padap, A_TP_RXT_MIN);
clk_info_buff->retransmit_max =
tp_tick_us * t4_read_reg(padap, A_TP_RXT_MAX);
clk_info_buff->persist_timer_min =
tp_tick_us * t4_read_reg(padap, A_TP_PERS_MIN);
clk_info_buff->persist_timer_max =
tp_tick_us * t4_read_reg(padap, A_TP_PERS_MAX);
clk_info_buff->keepalive_idle_timer =
tp_tick_us * t4_read_reg(padap, A_TP_KEEP_IDLE);
clk_info_buff->keepalive_interval =
tp_tick_us * t4_read_reg(padap, A_TP_KEEP_INTVL);
clk_info_buff->initial_srtt =
tp_tick_us * G_INITSRTT(t4_read_reg(padap, A_TP_INIT_SRTT));
clk_info_buff->finwait2_timer =
tp_tick_us * t4_read_reg(padap, A_TP_FINWAIT2_TIMER);
rc = write_compression_hdr(&scratch_buff, dbg_buff);
if (rc)
goto err1;
rc = compress_buff(&scratch_buff, dbg_buff);
err1:
release_scratch_buff(&scratch_buff, dbg_buff);
err:
return rc;
}
static int collect_macstats(struct cudbg_init *pdbg_init,
struct cudbg_buffer *dbg_buff,
struct cudbg_error *cudbg_err)
{
struct adapter *padap = pdbg_init->adap;
struct cudbg_buffer scratch_buff;
struct struct_mac_stats_rev1 *mac_stats_buff;
u32 i, n, size;
int rc = 0;
rc = padap->params.nports;
if (rc < 0)
goto err;
n = rc;
size = sizeof(struct struct_mac_stats_rev1);
rc = get_scratch_buff(dbg_buff, size, &scratch_buff);
if (rc)
goto err;
mac_stats_buff = (struct struct_mac_stats_rev1 *) scratch_buff.data;
mac_stats_buff->ver_hdr.signature = CUDBG_ENTITY_SIGNATURE;
mac_stats_buff->ver_hdr.revision = CUDBG_MAC_STATS_REV;
mac_stats_buff->ver_hdr.size = sizeof(struct struct_mac_stats_rev1) -
sizeof(struct cudbg_ver_hdr);
mac_stats_buff->port_count = n;
for (i = 0; i < mac_stats_buff->port_count; i++)
t4_get_port_stats(padap, i, &mac_stats_buff->stats[i]);
rc = write_compression_hdr(&scratch_buff, dbg_buff);
if (rc)
goto err1;
rc = compress_buff(&scratch_buff, dbg_buff);
err1:
release_scratch_buff(&scratch_buff, dbg_buff);
err:
return rc;
}
static int collect_cim_pif_la(struct cudbg_init *pdbg_init,
struct cudbg_buffer *dbg_buff,
struct cudbg_error *cudbg_err)
{
struct adapter *padap = pdbg_init->adap;
struct cudbg_buffer scratch_buff;
struct cim_pif_la *cim_pif_la_buff;
u32 size;
int rc = 0;
size = sizeof(struct cim_pif_la) +
2 * CIM_PIFLA_SIZE * 6 * sizeof(u32);
rc = get_scratch_buff(dbg_buff, size, &scratch_buff);
if (rc)
goto err;
cim_pif_la_buff = (struct cim_pif_la *) scratch_buff.data;
cim_pif_la_buff->size = CIM_PIFLA_SIZE;
t4_cim_read_pif_la(padap, (u32 *)cim_pif_la_buff->data,
(u32 *)cim_pif_la_buff->data + 6 * CIM_PIFLA_SIZE,
NULL, NULL);
rc = write_compression_hdr(&scratch_buff, dbg_buff);
if (rc)
goto err1;
rc = compress_buff(&scratch_buff, dbg_buff);
err1:
release_scratch_buff(&scratch_buff, dbg_buff);
err:
return rc;
}
static int collect_tp_la(struct cudbg_init *pdbg_init,
struct cudbg_buffer *dbg_buff,
struct cudbg_error *cudbg_err)
{
struct adapter *padap = pdbg_init->adap;
struct cudbg_buffer scratch_buff;
struct struct_tp_la *tp_la_buff;
u32 size;
int rc = 0;
size = sizeof(struct struct_tp_la) + TPLA_SIZE * sizeof(u64);
rc = get_scratch_buff(dbg_buff, size, &scratch_buff);
if (rc)
goto err;
tp_la_buff = (struct struct_tp_la *) scratch_buff.data;
tp_la_buff->mode = G_DBGLAMODE(t4_read_reg(padap, A_TP_DBG_LA_CONFIG));
t4_tp_read_la(padap, (u64 *)tp_la_buff->data, NULL);
rc = write_compression_hdr(&scratch_buff, dbg_buff);
if (rc)
goto err1;
rc = compress_buff(&scratch_buff, dbg_buff);
err1:
release_scratch_buff(&scratch_buff, dbg_buff);
err:
return rc;
}
static int collect_fcoe_stats(struct cudbg_init *pdbg_init,
struct cudbg_buffer *dbg_buff,
struct cudbg_error *cudbg_err)
{
struct adapter *padap = pdbg_init->adap;
struct cudbg_buffer scratch_buff;
struct struct_tp_fcoe_stats *tp_fcoe_stats_buff;
u32 size;
int rc = 0;
size = sizeof(struct struct_tp_fcoe_stats);
rc = get_scratch_buff(dbg_buff, size, &scratch_buff);
if (rc)
goto err;
tp_fcoe_stats_buff = (struct struct_tp_fcoe_stats *) scratch_buff.data;
/* spin_lock(&padap->stats_lock); TODO*/
t4_get_fcoe_stats(padap, 0, &tp_fcoe_stats_buff->stats[0], 1);
t4_get_fcoe_stats(padap, 1, &tp_fcoe_stats_buff->stats[1], 1);
if (padap->chip_params->nchan == NCHAN) {
t4_get_fcoe_stats(padap, 2, &tp_fcoe_stats_buff->stats[2], 1);
t4_get_fcoe_stats(padap, 3, &tp_fcoe_stats_buff->stats[3], 1);
}
/* spin_unlock(&padap->stats_lock); TODO*/
rc = write_compression_hdr(&scratch_buff, dbg_buff);
if (rc)
goto err1;
rc = compress_buff(&scratch_buff, dbg_buff);
err1:
release_scratch_buff(&scratch_buff, dbg_buff);
err:
return rc;
}
static int collect_tp_err_stats(struct cudbg_init *pdbg_init,
struct cudbg_buffer *dbg_buff,
struct cudbg_error *cudbg_err)
{
struct adapter *padap = pdbg_init->adap;
struct cudbg_buffer scratch_buff;
struct struct_tp_err_stats *tp_err_stats_buff;
u32 size;
int rc = 0;
size = sizeof(struct struct_tp_err_stats);
rc = get_scratch_buff(dbg_buff, size, &scratch_buff);
if (rc)
goto err;
tp_err_stats_buff = (struct struct_tp_err_stats *) scratch_buff.data;
/* spin_lock(&padap->stats_lock); TODO*/
t4_tp_get_err_stats(padap, &tp_err_stats_buff->stats, 1);
/* spin_unlock(&padap->stats_lock); TODO*/
tp_err_stats_buff->nchan = padap->chip_params->nchan;
rc = write_compression_hdr(&scratch_buff, dbg_buff);
if (rc)
goto err1;
rc = compress_buff(&scratch_buff, dbg_buff);
err1:
release_scratch_buff(&scratch_buff, dbg_buff);
err:
return rc;
}
static int collect_tcp_stats(struct cudbg_init *pdbg_init,
struct cudbg_buffer *dbg_buff,
struct cudbg_error *cudbg_err)
{
struct adapter *padap = pdbg_init->adap;
struct cudbg_buffer scratch_buff;
struct struct_tcp_stats *tcp_stats_buff;
u32 size;
int rc = 0;
size = sizeof(struct struct_tcp_stats);
rc = get_scratch_buff(dbg_buff, size, &scratch_buff);
if (rc)
goto err;
tcp_stats_buff = (struct struct_tcp_stats *) scratch_buff.data;
/* spin_lock(&padap->stats_lock); TODO*/
t4_tp_get_tcp_stats(padap, &tcp_stats_buff->v4, &tcp_stats_buff->v6, 1);
/* spin_unlock(&padap->stats_lock); TODO*/
rc = write_compression_hdr(&scratch_buff, dbg_buff);
if (rc)
goto err1;
rc = compress_buff(&scratch_buff, dbg_buff);
err1:
release_scratch_buff(&scratch_buff, dbg_buff);
err:
return rc;
}
static int collect_hw_sched(struct cudbg_init *pdbg_init,
struct cudbg_buffer *dbg_buff,
struct cudbg_error *cudbg_err)
{
struct adapter *padap = pdbg_init->adap;
struct cudbg_buffer scratch_buff;
struct struct_hw_sched *hw_sched_buff;
u32 size;
int i, rc = 0;
if (!padap->params.vpd.cclk) {
rc = CUDBG_STATUS_CCLK_NOT_DEFINED;
goto err;
}
size = sizeof(struct struct_hw_sched);
rc = get_scratch_buff(dbg_buff, size, &scratch_buff);
if (rc)
goto err;
hw_sched_buff = (struct struct_hw_sched *) scratch_buff.data;
hw_sched_buff->map = t4_read_reg(padap, A_TP_TX_MOD_QUEUE_REQ_MAP);
hw_sched_buff->mode = G_TIMERMODE(t4_read_reg(padap, A_TP_MOD_CONFIG));
t4_read_pace_tbl(padap, hw_sched_buff->pace_tab);
for (i = 0; i < NTX_SCHED; ++i) {
t4_get_tx_sched(padap, i, &hw_sched_buff->kbps[i],
&hw_sched_buff->ipg[i], 1);
}
rc = write_compression_hdr(&scratch_buff, dbg_buff);
if (rc)
goto err1;
rc = compress_buff(&scratch_buff, dbg_buff);
err1:
release_scratch_buff(&scratch_buff, dbg_buff);
err:
return rc;
}
static int collect_pm_stats(struct cudbg_init *pdbg_init,
struct cudbg_buffer *dbg_buff,
struct cudbg_error *cudbg_err)
{
struct adapter *padap = pdbg_init->adap;
struct cudbg_buffer scratch_buff;
struct struct_pm_stats *pm_stats_buff;
u32 size;
int rc = 0;
size = sizeof(struct struct_pm_stats);
rc = get_scratch_buff(dbg_buff, size, &scratch_buff);
if (rc)
goto err;
pm_stats_buff = (struct struct_pm_stats *) scratch_buff.data;
t4_pmtx_get_stats(padap, pm_stats_buff->tx_cnt, pm_stats_buff->tx_cyc);
t4_pmrx_get_stats(padap, pm_stats_buff->rx_cnt, pm_stats_buff->rx_cyc);
rc = write_compression_hdr(&scratch_buff, dbg_buff);
if (rc)
goto err1;
rc = compress_buff(&scratch_buff, dbg_buff);
err1:
release_scratch_buff(&scratch_buff, dbg_buff);
err:
return rc;
}
static int collect_path_mtu(struct cudbg_init *pdbg_init,
struct cudbg_buffer *dbg_buff,
struct cudbg_error *cudbg_err)
{
struct adapter *padap = pdbg_init->adap;
struct cudbg_buffer scratch_buff;
u32 size;
int rc = 0;
size = NMTUS * sizeof(u16);
rc = get_scratch_buff(dbg_buff, size, &scratch_buff);
if (rc)
goto err;
t4_read_mtu_tbl(padap, (u16 *)scratch_buff.data, NULL);
rc = write_compression_hdr(&scratch_buff, dbg_buff);
if (rc)
goto err1;
rc = compress_buff(&scratch_buff, dbg_buff);
err1:
release_scratch_buff(&scratch_buff, dbg_buff);
err:
return rc;
}
static int collect_rss_key(struct cudbg_init *pdbg_init,
struct cudbg_buffer *dbg_buff,
struct cudbg_error *cudbg_err)
{
struct adapter *padap = pdbg_init->adap;
struct cudbg_buffer scratch_buff;
u32 size;
int rc = 0;
size = 10 * sizeof(u32);
rc = get_scratch_buff(dbg_buff, size, &scratch_buff);
if (rc)
goto err;
t4_read_rss_key(padap, (u32 *)scratch_buff.data, 1);
rc = write_compression_hdr(&scratch_buff, dbg_buff);
if (rc)
goto err1;
rc = compress_buff(&scratch_buff, dbg_buff);
err1:
release_scratch_buff(&scratch_buff, dbg_buff);
err:
return rc;
}
static int collect_rss_config(struct cudbg_init *pdbg_init,
struct cudbg_buffer *dbg_buff,
struct cudbg_error *cudbg_err)
{
struct adapter *padap = pdbg_init->adap;
struct cudbg_buffer scratch_buff;
struct rss_config *rss_conf;
int rc;
u32 size;
size = sizeof(struct rss_config);
rc = get_scratch_buff(dbg_buff, size, &scratch_buff);
if (rc)
goto err;
rss_conf = (struct rss_config *)scratch_buff.data;
rss_conf->tp_rssconf = t4_read_reg(padap, A_TP_RSS_CONFIG);
rss_conf->tp_rssconf_tnl = t4_read_reg(padap, A_TP_RSS_CONFIG_TNL);
rss_conf->tp_rssconf_ofd = t4_read_reg(padap, A_TP_RSS_CONFIG_OFD);
rss_conf->tp_rssconf_syn = t4_read_reg(padap, A_TP_RSS_CONFIG_SYN);
rss_conf->tp_rssconf_vrt = t4_read_reg(padap, A_TP_RSS_CONFIG_VRT);
rss_conf->tp_rssconf_cng = t4_read_reg(padap, A_TP_RSS_CONFIG_CNG);
rss_conf->chip = padap->params.chipid;
rc = write_compression_hdr(&scratch_buff, dbg_buff);
if (rc)
goto err1;
rc = compress_buff(&scratch_buff, dbg_buff);
err1:
release_scratch_buff(&scratch_buff, dbg_buff);
err:
return rc;
}
static int collect_rss_vf_config(struct cudbg_init *pdbg_init,
struct cudbg_buffer *dbg_buff,
struct cudbg_error *cudbg_err)
{
struct adapter *padap = pdbg_init->adap;
struct cudbg_buffer scratch_buff;
struct rss_vf_conf *vfconf;
int vf, rc, vf_count;
u32 size;
vf_count = padap->chip_params->vfcount;
size = vf_count * sizeof(*vfconf);
rc = get_scratch_buff(dbg_buff, size, &scratch_buff);
if (rc)
goto err;
vfconf = (struct rss_vf_conf *)scratch_buff.data;
for (vf = 0; vf < vf_count; vf++) {
t4_read_rss_vf_config(padap, vf, &vfconf[vf].rss_vf_vfl,
&vfconf[vf].rss_vf_vfh, 1);
}
rc = write_compression_hdr(&scratch_buff, dbg_buff);
if (rc)
goto err1;
rc = compress_buff(&scratch_buff, dbg_buff);
err1:
release_scratch_buff(&scratch_buff, dbg_buff);
err:
return rc;
}
static int collect_rss_pf_config(struct cudbg_init *pdbg_init,
struct cudbg_buffer *dbg_buff,
struct cudbg_error *cudbg_err)
{
struct cudbg_buffer scratch_buff;
struct rss_pf_conf *pfconf;
struct adapter *padap = pdbg_init->adap;
u32 rss_pf_map, rss_pf_mask, size;
int pf, rc;
size = 8 * sizeof(*pfconf);
rc = get_scratch_buff(dbg_buff, size, &scratch_buff);
if (rc)
goto err;
pfconf = (struct rss_pf_conf *)scratch_buff.data;
rss_pf_map = t4_read_rss_pf_map(padap, 1);
rss_pf_mask = t4_read_rss_pf_mask(padap, 1);
for (pf = 0; pf < 8; pf++) {
pfconf[pf].rss_pf_map = rss_pf_map;
pfconf[pf].rss_pf_mask = rss_pf_mask;
/* no return val */
t4_read_rss_pf_config(padap, pf, &pfconf[pf].rss_pf_config, 1);
}
rc = write_compression_hdr(&scratch_buff, dbg_buff);
if (rc)
goto err1;
rc = compress_buff(&scratch_buff, dbg_buff);
err1:
release_scratch_buff(&scratch_buff, dbg_buff);
err:
return rc;
}
static int check_valid(u32 *buf, int type)
{
int index;
int bit;
int 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);
}
/**
* Get EGRESS, INGRESS, FLM, and CNM max qid.
*
* For EGRESS and INGRESS, do the following calculation.
* max_qid = (DBQ/IMSG context region size in bytes) /
* (size of context in bytes).
*
* For FLM, do the following calculation.
* max_qid = (FLM cache region size in bytes) /
* ((number of pointers cached in EDRAM) * 8 (bytes per pointer)).
*
* There's a 1-to-1 mapping between FLM and CNM if there's no header splitting
* enabled; i.e., max CNM qid is equal to max FLM qid. However, if header
* splitting is enabled, then max CNM qid is half of max FLM qid.
*/
static int get_max_ctxt_qid(struct adapter *padap,
struct struct_meminfo *meminfo,
u32 *max_ctx_qid, u8 nelem)
{
u32 i, idx, found = 0;
if (nelem != (CTXT_CNM + 1))
return -EINVAL;
for (i = 0; i < meminfo->mem_c; i++) {
if (meminfo->mem[i].idx >= ARRAY_SIZE(region))
continue; /* skip holes */
idx = meminfo->mem[i].idx;
/* Get DBQ, IMSG, and FLM context region size */
if (idx <= CTXT_FLM) {
if (!(meminfo->mem[i].limit))
meminfo->mem[i].limit =
i < meminfo->mem_c - 1 ?
meminfo->mem[i + 1].base - 1 : ~0;
if (idx < CTXT_FLM) {
/* Get EGRESS and INGRESS max qid. */
max_ctx_qid[idx] = (meminfo->mem[i].limit -
meminfo->mem[i].base + 1) /
CUDBG_CTXT_SIZE_BYTES;
found++;
} else {
/* Get FLM and CNM max qid. */
u32 value, edram_ptr_count;
u8 bytes_per_ptr = 8;
u8 nohdr;
value = t4_read_reg(padap, A_SGE_FLM_CFG);
/* Check if header splitting is enabled. */
nohdr = (value >> S_NOHDR) & 1U;
/* Get the number of pointers in EDRAM per
* qid in units of 32.
*/
edram_ptr_count = 32 *
(1U << G_EDRAMPTRCNT(value));
/* EDRAMPTRCNT value of 3 is reserved.
* So don't exceed 128.
*/
if (edram_ptr_count > 128)
edram_ptr_count = 128;
max_ctx_qid[idx] = (meminfo->mem[i].limit -
meminfo->mem[i].base + 1) /
(edram_ptr_count *
bytes_per_ptr);
found++;
/* CNM has 1-to-1 mapping with FLM.
* However, if header splitting is enabled,
* then max CNM qid is half of max FLM qid.
*/
max_ctx_qid[CTXT_CNM] = nohdr ?
max_ctx_qid[idx] :
max_ctx_qid[idx] >> 1;
/* One more increment for CNM */
found++;
}
}
if (found == nelem)
break;
}
/* Sanity check. Ensure the values are within known max. */
max_ctx_qid[CTXT_EGRESS] = min_t(u32, max_ctx_qid[CTXT_EGRESS],
M_CTXTQID);
max_ctx_qid[CTXT_INGRESS] = min_t(u32, max_ctx_qid[CTXT_INGRESS],
CUDBG_MAX_INGRESS_QIDS);
max_ctx_qid[CTXT_FLM] = min_t(u32, max_ctx_qid[CTXT_FLM],
CUDBG_MAX_FL_QIDS);
max_ctx_qid[CTXT_CNM] = min_t(u32, max_ctx_qid[CTXT_CNM],
CUDBG_MAX_CNM_QIDS);
return 0;
}
static int collect_dump_context(struct cudbg_init *pdbg_init,
struct cudbg_buffer *dbg_buff,
struct cudbg_error *cudbg_err)
{
struct cudbg_buffer scratch_buff;
struct cudbg_buffer temp_buff;
struct adapter *padap = pdbg_init->adap;
u32 size = 0, next_offset = 0, total_size = 0;
struct cudbg_ch_cntxt *buff = NULL;
struct struct_meminfo meminfo;
int bytes = 0;
int rc = 0;
u32 i, j;
u32 max_ctx_qid[CTXT_CNM + 1];
bool limit_qid = false;
u32 qid_count = 0;
rc = fill_meminfo(padap, &meminfo);
if (rc)
goto err;
/* Get max valid qid for each type of queue */
rc = get_max_ctxt_qid(padap, &meminfo, max_ctx_qid, CTXT_CNM + 1);
if (rc)
goto err;
/* There are four types of queues. Collect context upto max
* qid of each type of queue.
*/
for (i = CTXT_EGRESS; i <= CTXT_CNM; i++)
size += sizeof(struct cudbg_ch_cntxt) * max_ctx_qid[i];
rc = get_scratch_buff(dbg_buff, size, &scratch_buff);
if (rc == CUDBG_STATUS_NO_SCRATCH_MEM) {
/* Not enough scratch Memory available.
* Collect context of at least CUDBG_LOWMEM_MAX_CTXT_QIDS
* for each queue type.
*/
size = 0;
for (i = CTXT_EGRESS; i <= CTXT_CNM; i++)
size += sizeof(struct cudbg_ch_cntxt) *
CUDBG_LOWMEM_MAX_CTXT_QIDS;
limit_qid = true;
rc = get_scratch_buff(dbg_buff, size, &scratch_buff);
if (rc)
goto err;
}
buff = (struct cudbg_ch_cntxt *)scratch_buff.data;
/* Collect context data */
for (i = CTXT_EGRESS; i <= CTXT_FLM; i++) {
qid_count = 0;
for (j = 0; j < max_ctx_qid[i]; j++) {
read_sge_ctxt(pdbg_init, j, i, buff->data);
rc = check_valid(buff->data, i);
if (rc) {
buff->cntxt_type = i;
buff->cntxt_id = j;
buff++;
total_size += sizeof(struct cudbg_ch_cntxt);
if (i == CTXT_FLM) {
read_sge_ctxt(pdbg_init, j, CTXT_CNM,
buff->data);
buff->cntxt_type = CTXT_CNM;
buff->cntxt_id = j;
buff++;
total_size +=
sizeof(struct cudbg_ch_cntxt);
}
qid_count++;
}
/* If there's not enough space to collect more qids,
* then bail and move on to next queue type.
*/
if (limit_qid &&
qid_count >= CUDBG_LOWMEM_MAX_CTXT_QIDS)
break;
}
}
scratch_buff.size = total_size;
rc = write_compression_hdr(&scratch_buff, dbg_buff);
if (rc)
goto err1;
/* Splitting buffer and writing in terms of CUDBG_CHUNK_SIZE */
while (total_size > 0) {
bytes = min_t(unsigned long, (unsigned long)total_size,
(unsigned long)CUDBG_CHUNK_SIZE);
temp_buff.size = bytes;
temp_buff.data = (void *)((char *)scratch_buff.data +
next_offset);
rc = compress_buff(&temp_buff, dbg_buff);
if (rc)
goto err1;
total_size -= bytes;
next_offset += bytes;
}
err1:
scratch_buff.size = size;
release_scratch_buff(&scratch_buff, dbg_buff);
err:
return rc;
}
static int collect_fw_devlog(struct cudbg_init *pdbg_init,
struct cudbg_buffer *dbg_buff,
struct cudbg_error *cudbg_err)
{
#ifdef notyet
struct adapter *padap = pdbg_init->adap;
struct devlog_params *dparams = &padap->params.devlog;
struct cudbg_param *params = NULL;
struct cudbg_buffer scratch_buff;
u32 offset;
int rc = 0, i;
rc = t4_init_devlog_params(padap, 1);
if (rc < 0) {
pdbg_init->print("%s(), t4_init_devlog_params failed!, rc: "\
"%d\n", __func__, rc);
for (i = 0; i < pdbg_init->dbg_params_cnt; i++) {
if (pdbg_init->dbg_params[i].param_type ==
CUDBG_DEVLOG_PARAM) {
params = &pdbg_init->dbg_params[i];
break;
}
}
if (params) {
dparams->memtype = params->u.devlog_param.memtype;
dparams->start = params->u.devlog_param.start;
dparams->size = params->u.devlog_param.size;
} else {
cudbg_err->sys_err = rc;
goto err;
}
}
rc = get_scratch_buff(dbg_buff, dparams->size, &scratch_buff);
if (rc)
goto err;
/* Collect FW devlog */
if (dparams->start != 0) {
offset = scratch_buff.offset;
rc = t4_memory_rw(padap, padap->params.drv_memwin,
dparams->memtype, dparams->start,
dparams->size,
(__be32 *)((char *)scratch_buff.data +
offset), 1);
if (rc) {
pdbg_init->print("%s(), t4_memory_rw failed!, rc: "\
"%d\n", __func__, rc);
cudbg_err->sys_err = rc;
goto err1;
}
}
rc = write_compression_hdr(&scratch_buff, dbg_buff);
if (rc)
goto err1;
rc = compress_buff(&scratch_buff, dbg_buff);
err1:
release_scratch_buff(&scratch_buff, dbg_buff);
err:
return rc;
#endif
return (EDOOFUS);
}
/* CIM OBQ */
static int collect_cim_obq_ulp0(struct cudbg_init *pdbg_init,
struct cudbg_buffer *dbg_buff,
struct cudbg_error *cudbg_err)
{
int rc = 0, qid = 0;
rc = read_cim_obq(pdbg_init, dbg_buff, cudbg_err, qid);
return rc;
}
static int collect_cim_obq_ulp1(struct cudbg_init *pdbg_init,
struct cudbg_buffer *dbg_buff,
struct cudbg_error *cudbg_err)
{
int rc = 0, qid = 1;
rc = read_cim_obq(pdbg_init, dbg_buff, cudbg_err, qid);
return rc;
}
static int collect_cim_obq_ulp2(struct cudbg_init *pdbg_init,
struct cudbg_buffer *dbg_buff,
struct cudbg_error *cudbg_err)
{
int rc = 0, qid = 2;
rc = read_cim_obq(pdbg_init, dbg_buff, cudbg_err, qid);
return rc;
}
static int collect_cim_obq_ulp3(struct cudbg_init *pdbg_init,
struct cudbg_buffer *dbg_buff,
struct cudbg_error *cudbg_err)
{
int rc = 0, qid = 3;
rc = read_cim_obq(pdbg_init, dbg_buff, cudbg_err, qid);
return rc;
}
static int collect_cim_obq_sge(struct cudbg_init *pdbg_init,
struct cudbg_buffer *dbg_buff,
struct cudbg_error *cudbg_err)
{
int rc = 0, qid = 4;
rc = read_cim_obq(pdbg_init, dbg_buff, cudbg_err, qid);
return rc;
}
static int collect_cim_obq_ncsi(struct cudbg_init *pdbg_init,
struct cudbg_buffer *dbg_buff,
struct cudbg_error *cudbg_err)
{
int rc = 0, qid = 5;
rc = read_cim_obq(pdbg_init, dbg_buff, cudbg_err, qid);
return rc;
}
static int collect_obq_sge_rx_q0(struct cudbg_init *pdbg_init,
struct cudbg_buffer *dbg_buff,
struct cudbg_error *cudbg_err)
{
int rc = 0, qid = 6;
rc = read_cim_obq(pdbg_init, dbg_buff, cudbg_err, qid);
return rc;
}
static int collect_obq_sge_rx_q1(struct cudbg_init *pdbg_init,
struct cudbg_buffer *dbg_buff,
struct cudbg_error *cudbg_err)
{
int rc = 0, qid = 7;
rc = read_cim_obq(pdbg_init, dbg_buff, cudbg_err, qid);
return rc;
}
static int read_cim_obq(struct cudbg_init *pdbg_init,
struct cudbg_buffer *dbg_buff,
struct cudbg_error *cudbg_err, int qid)
{
struct cudbg_buffer scratch_buff;
struct adapter *padap = pdbg_init->adap;
u32 qsize;
int rc;
int no_of_read_words;
/* collect CIM OBQ */
qsize = 6 * CIM_OBQ_SIZE * 4 * sizeof(u32);
rc = get_scratch_buff(dbg_buff, qsize, &scratch_buff);
if (rc)
goto err;
/* t4_read_cim_obq will return no. of read words or error */
no_of_read_words = t4_read_cim_obq(padap, qid,
(u32 *)((u32 *)scratch_buff.data +
scratch_buff.offset), qsize);
/* no_of_read_words is less than or equal to 0 means error */
if (no_of_read_words <= 0) {
if (no_of_read_words == 0)
rc = CUDBG_SYSTEM_ERROR;
else
rc = no_of_read_words;
if (pdbg_init->verbose)
pdbg_init->print("%s: t4_read_cim_obq failed (%d)\n",
__func__, rc);
cudbg_err->sys_err = rc;
goto err1;
}
scratch_buff.size = no_of_read_words * 4;
rc = write_compression_hdr(&scratch_buff, dbg_buff);
if (rc)
goto err1;
rc = compress_buff(&scratch_buff, dbg_buff);
if (rc)
goto err1;
err1:
release_scratch_buff(&scratch_buff, dbg_buff);
err:
return rc;
}
/* CIM IBQ */
static int collect_cim_ibq_tp0(struct cudbg_init *pdbg_init,
struct cudbg_buffer *dbg_buff,
struct cudbg_error *cudbg_err)
{
int rc = 0, qid = 0;
rc = read_cim_ibq(pdbg_init, dbg_buff, cudbg_err, qid);
return rc;
}
static int collect_cim_ibq_tp1(struct cudbg_init *pdbg_init,
struct cudbg_buffer *dbg_buff,
struct cudbg_error *cudbg_err)
{
int rc = 0, qid = 1;
rc = read_cim_ibq(pdbg_init, dbg_buff, cudbg_err, qid);
return rc;
}
static int collect_cim_ibq_ulp(struct cudbg_init *pdbg_init,
struct cudbg_buffer *dbg_buff,
struct cudbg_error *cudbg_err)
{
int rc = 0, qid = 2;
rc = read_cim_ibq(pdbg_init, dbg_buff, cudbg_err, qid);
return rc;
}
static int collect_cim_ibq_sge0(struct cudbg_init *pdbg_init,
struct cudbg_buffer *dbg_buff,
struct cudbg_error *cudbg_err)
{
int rc = 0, qid = 3;
rc = read_cim_ibq(pdbg_init, dbg_buff, cudbg_err, qid);
return rc;
}
static int collect_cim_ibq_sge1(struct cudbg_init *pdbg_init,
struct cudbg_buffer *dbg_buff,
struct cudbg_error *cudbg_err)
{
int rc = 0, qid = 4;
rc = read_cim_ibq(pdbg_init, dbg_buff, cudbg_err, qid);
return rc;
}
static int collect_cim_ibq_ncsi(struct cudbg_init *pdbg_init,
struct cudbg_buffer *dbg_buff,
struct cudbg_error *cudbg_err)
{
int rc, qid = 5;
rc = read_cim_ibq(pdbg_init, dbg_buff, cudbg_err, qid);
return rc;
}
static int read_cim_ibq(struct cudbg_init *pdbg_init,
struct cudbg_buffer *dbg_buff,
struct cudbg_error *cudbg_err, int qid)
{
struct adapter *padap = pdbg_init->adap;
struct cudbg_buffer scratch_buff;
u32 qsize;
int rc;
int no_of_read_words;
/* collect CIM IBQ */
qsize = CIM_IBQ_SIZE * 4 * sizeof(u32);
rc = get_scratch_buff(dbg_buff, qsize, &scratch_buff);
if (rc)
goto err;
/* t4_read_cim_ibq will return no. of read words or error */
no_of_read_words = t4_read_cim_ibq(padap, qid,
(u32 *)((u32 *)scratch_buff.data +
scratch_buff.offset), qsize);
/* no_of_read_words is less than or equal to 0 means error */
if (no_of_read_words <= 0) {
if (no_of_read_words == 0)
rc = CUDBG_SYSTEM_ERROR;
else
rc = no_of_read_words;
if (pdbg_init->verbose)
pdbg_init->print("%s: t4_read_cim_ibq failed (%d)\n",
__func__, rc);
cudbg_err->sys_err = rc;
goto err1;
}
rc = write_compression_hdr(&scratch_buff, dbg_buff);
if (rc)
goto err1;
rc = compress_buff(&scratch_buff, dbg_buff);
if (rc)
goto err1;
err1:
release_scratch_buff(&scratch_buff, dbg_buff);
err:
return rc;
}
static int collect_cim_ma_la(struct cudbg_init *pdbg_init,
struct cudbg_buffer *dbg_buff,
struct cudbg_error *cudbg_err)
{
struct cudbg_buffer scratch_buff;
struct adapter *padap = pdbg_init->adap;
u32 rc = 0;
/* collect CIM MA LA */
scratch_buff.size = 2 * CIM_MALA_SIZE * 5 * sizeof(u32);
rc = get_scratch_buff(dbg_buff, scratch_buff.size, &scratch_buff);
if (rc)
goto err;
/* no return */
t4_cim_read_ma_la(padap,
(u32 *) ((char *)scratch_buff.data +
scratch_buff.offset),
(u32 *) ((char *)scratch_buff.data +
scratch_buff.offset + 5 * CIM_MALA_SIZE));
rc = write_compression_hdr(&scratch_buff, dbg_buff);
if (rc)
goto err1;
rc = compress_buff(&scratch_buff, dbg_buff);
err1:
release_scratch_buff(&scratch_buff, dbg_buff);
err:
return rc;
}
static int collect_cim_la(struct cudbg_init *pdbg_init,
struct cudbg_buffer *dbg_buff,
struct cudbg_error *cudbg_err)
{
struct cudbg_buffer scratch_buff;
struct adapter *padap = pdbg_init->adap;
int rc;
u32 cfg = 0;
int size;
/* collect CIM LA */
if (is_t6(padap)) {
size = padap->params.cim_la_size / 10 + 1;
size *= 11 * sizeof(u32);
} else {
size = padap->params.cim_la_size / 8;
size *= 8 * sizeof(u32);
}
size += sizeof(cfg);
rc = get_scratch_buff(dbg_buff, size, &scratch_buff);
if (rc)
goto err;
rc = t4_cim_read(padap, A_UP_UP_DBG_LA_CFG, 1, &cfg);
if (rc) {
if (pdbg_init->verbose)
pdbg_init->print("%s: t4_cim_read failed (%d)\n",
__func__, rc);
cudbg_err->sys_err = rc;
goto err1;
}
memcpy((char *)scratch_buff.data + scratch_buff.offset, &cfg,
sizeof(cfg));
rc = t4_cim_read_la(padap,
(u32 *) ((char *)scratch_buff.data +
scratch_buff.offset + sizeof(cfg)), NULL);
if (rc < 0) {
if (pdbg_init->verbose)
pdbg_init->print("%s: t4_cim_read_la failed (%d)\n",
__func__, rc);
cudbg_err->sys_err = rc;
goto err1;
}
rc = write_compression_hdr(&scratch_buff, dbg_buff);
if (rc)
goto err1;
rc = compress_buff(&scratch_buff, dbg_buff);
if (rc)
goto err1;
err1:
release_scratch_buff(&scratch_buff, dbg_buff);
err:
return rc;
}
static int collect_cim_qcfg(struct cudbg_init *pdbg_init,
struct cudbg_buffer *dbg_buff,
struct cudbg_error *cudbg_err)
{
struct cudbg_buffer scratch_buff;
struct adapter *padap = pdbg_init->adap;
u32 offset;
int cim_num_obq, rc = 0;
struct struct_cim_qcfg *cim_qcfg_data = NULL;
rc = get_scratch_buff(dbg_buff, sizeof(struct struct_cim_qcfg),
&scratch_buff);
if (rc)
goto err;
offset = scratch_buff.offset;
cim_num_obq = is_t4(padap) ? CIM_NUM_OBQ : CIM_NUM_OBQ_T5;
cim_qcfg_data =
(struct struct_cim_qcfg *)((u8 *)((char *)scratch_buff.data +
offset));
rc = t4_cim_read(padap, A_UP_IBQ_0_RDADDR,
ARRAY_SIZE(cim_qcfg_data->stat), cim_qcfg_data->stat);
if (rc) {
if (pdbg_init->verbose)
pdbg_init->print("%s: t4_cim_read IBQ_0_RDADDR failed (%d)\n",
__func__, rc);
cudbg_err->sys_err = rc;
goto err1;
}
rc = t4_cim_read(padap, A_UP_OBQ_0_REALADDR,
ARRAY_SIZE(cim_qcfg_data->obq_wr),
cim_qcfg_data->obq_wr);
if (rc) {
if (pdbg_init->verbose)
pdbg_init->print("%s: t4_cim_read OBQ_0_REALADDR failed (%d)\n",
__func__, rc);
cudbg_err->sys_err = rc;
goto err1;
}
/* no return val */
t4_read_cimq_cfg(padap,
cim_qcfg_data->base,
cim_qcfg_data->size,
cim_qcfg_data->thres);
rc = write_compression_hdr(&scratch_buff, dbg_buff);
if (rc)
goto err1;
rc = compress_buff(&scratch_buff, dbg_buff);
if (rc)
goto err1;
err1:
release_scratch_buff(&scratch_buff, dbg_buff);
err:
return rc;
}
/**
* Fetch the TX/RX payload regions start and end.
*
* @padap (IN): adapter handle.
* @mem_type (IN): EDC0, EDC1, MC/MC0/MC1.
* @mem_tot_len (IN): total length of @mem_type memory region to read.
* @payload_type (IN): TX or RX Payload.
* @reg_info (OUT): store the payload region info.
*
* Fetch the TX/RX payload region information from meminfo.
* However, reading from the @mem_type region starts at 0 and not
* from whatever base info is stored in meminfo. Hence, if the
* payload region exists, then calculate the payload region
* start and end wrt 0 and @mem_tot_len, respectively, and set
* @reg_info->exist to true. Otherwise, set @reg_info->exist to false.
*/
#ifdef notyet
static int get_payload_range(struct adapter *padap, u8 mem_type,
unsigned long mem_tot_len, u8 payload_type,
struct struct_region_info *reg_info)
{
struct struct_meminfo meminfo;
struct struct_mem_desc mem_region;
struct struct_mem_desc payload;
u32 i, idx, found = 0;
u8 mc_type;
int rc;
/* Get meminfo of all regions */
rc = fill_meminfo(padap, &meminfo);
if (rc)
return rc;
/* Extract the specified TX or RX Payload region range */
memset(&payload, 0, sizeof(struct struct_mem_desc));
for (i = 0; i < meminfo.mem_c; i++) {
if (meminfo.mem[i].idx >= ARRAY_SIZE(region))
continue; /* skip holes */
idx = meminfo.mem[i].idx;
/* Get TX or RX Payload region start and end */
if (idx == payload_type) {
if (!(meminfo.mem[i].limit))
meminfo.mem[i].limit =
i < meminfo.mem_c - 1 ?
meminfo.mem[i + 1].base - 1 : ~0;
memcpy(&payload, &meminfo.mem[i], sizeof(payload));
found = 1;
break;
}
}
/* If TX or RX Payload region is not found return error. */
if (!found)
return -EINVAL;
if (mem_type < MEM_MC) {
memcpy(&mem_region, &meminfo.avail[mem_type],
sizeof(mem_region));
} else {
/* Check if both MC0 and MC1 exist by checking if a
* base address for the specified @mem_type exists.
* If a base address exists, then there is MC1 and
* hence use the base address stored at index 3.
* Otherwise, use the base address stored at index 2.
*/
mc_type = meminfo.avail[mem_type].base ?
mem_type : mem_type - 1;
memcpy(&mem_region, &meminfo.avail[mc_type],
sizeof(mem_region));
}
/* Check if payload region exists in current memory */
if (payload.base < mem_region.base && payload.limit < mem_region.base) {
reg_info->exist = false;
return 0;
}
/* Get Payload region start and end with respect to 0 and
* mem_tot_len, respectively. This is because reading from the
* memory region starts at 0 and not at base info stored in meminfo.
*/
if (payload.base < mem_region.limit) {
reg_info->exist = true;
if (payload.base >= mem_region.base)
reg_info->start = payload.base - mem_region.base;
else
reg_info->start = 0;
if (payload.limit < mem_region.limit)
reg_info->end = payload.limit - mem_region.base;
else
reg_info->end = mem_tot_len;
}
return 0;
}
#endif
static int read_fw_mem(struct cudbg_init *pdbg_init,
struct cudbg_buffer *dbg_buff, u8 mem_type,
unsigned long tot_len, struct cudbg_error *cudbg_err)
{
#ifdef notyet
struct cudbg_buffer scratch_buff;
struct adapter *padap = pdbg_init->adap;
unsigned long bytes_read = 0;
unsigned long bytes_left;
unsigned long bytes;
int rc;
struct struct_region_info payload[2]; /* TX and RX Payload Region */
u16 get_payload_flag;
u8 i;
get_payload_flag =
pdbg_init->dbg_params[CUDBG_GET_PAYLOAD_PARAM].param_type;
/* If explicitly asked to get TX/RX Payload data,
* then don't zero out the payload data. Otherwise,
* zero out the payload data.
*/
if (!get_payload_flag) {
u8 region_index[2];
u8 j = 0;
/* Find the index of TX and RX Payload regions in meminfo */
for (i = 0; i < ARRAY_SIZE(region); i++) {
if (!strcmp(region[i], "Tx payload:") ||
!strcmp(region[i], "Rx payload:")) {
region_index[j] = i;
j++;
if (j == 2)
break;
}
}
/* Get TX/RX Payload region range if they exist */
memset(payload, 0, ARRAY_SIZE(payload) * sizeof(payload[0]));
for (i = 0; i < ARRAY_SIZE(payload); i++) {
rc = get_payload_range(padap, mem_type, tot_len,
region_index[i],
&payload[i]);
if (rc)
goto err;
if (payload[i].exist) {
/* Align start and end to avoid wrap around */
payload[i].start =
roundup(payload[i].start,
CUDBG_CHUNK_SIZE);
payload[i].end =
rounddown(payload[i].end,
CUDBG_CHUNK_SIZE);
}
}
}
bytes_left = tot_len;
scratch_buff.size = tot_len;
rc = write_compression_hdr(&scratch_buff, dbg_buff);
if (rc)
goto err;
while (bytes_left > 0) {
bytes = min_t(unsigned long, bytes_left, (unsigned long)CUDBG_CHUNK_SIZE);
rc = get_scratch_buff(dbg_buff, bytes, &scratch_buff);
if (rc) {
rc = CUDBG_STATUS_NO_SCRATCH_MEM;
goto err;
}
if (!get_payload_flag) {
for (i = 0; i < ARRAY_SIZE(payload); i++) {
if (payload[i].exist &&
bytes_read >= payload[i].start &&
(bytes_read + bytes) <= payload[i].end) {
memset(scratch_buff.data, 0, bytes);
/* TX and RX Payload regions
* can't overlap.
*/
goto skip_read;
}
}
}
/* Read from file */
/*fread(scratch_buff.data, 1, Bytes, in);*/
rc = t4_memory_rw(padap, MEMWIN_NIC, mem_type, bytes_read,
bytes, (__be32 *)(scratch_buff.data), 1);
if (rc) {
if (pdbg_init->verbose)
pdbg_init->print("%s: t4_memory_rw failed (%d)",
__func__, rc);
cudbg_err->sys_err = rc;
goto err1;
}
skip_read:
rc = compress_buff(&scratch_buff, dbg_buff);
if (rc)
goto err1;
bytes_left -= bytes;
bytes_read += bytes;
release_scratch_buff(&scratch_buff, dbg_buff);
}
err1:
if (rc)
release_scratch_buff(&scratch_buff, dbg_buff);
err:
return rc;
#endif
return (EDOOFUS);
}
static void collect_mem_info(struct cudbg_init *pdbg_init,
struct card_mem *mem_info)
{
struct adapter *padap = pdbg_init->adap;
u32 value;
int t4 = 0;
if (is_t4(padap))
t4 = 1;
if (t4) {
value = t4_read_reg(padap, A_MA_EXT_MEMORY_BAR);
value = G_EXT_MEM_SIZE(value);
mem_info->size_mc0 = (u16)value; /* size in MB */
value = t4_read_reg(padap, A_MA_TARGET_MEM_ENABLE);
if (value & F_EXT_MEM_ENABLE)
mem_info->mem_flag |= (1 << MC0_FLAG); /* set mc0 flag
bit */
} else {
value = t4_read_reg(padap, A_MA_EXT_MEMORY0_BAR);
value = G_EXT_MEM0_SIZE(value);
mem_info->size_mc0 = (u16)value;
value = t4_read_reg(padap, A_MA_EXT_MEMORY1_BAR);
value = G_EXT_MEM1_SIZE(value);
mem_info->size_mc1 = (u16)value;
value = t4_read_reg(padap, A_MA_TARGET_MEM_ENABLE);
if (value & F_EXT_MEM0_ENABLE)
mem_info->mem_flag |= (1 << MC0_FLAG);
if (value & F_EXT_MEM1_ENABLE)
mem_info->mem_flag |= (1 << MC1_FLAG);
}
value = t4_read_reg(padap, A_MA_EDRAM0_BAR);
value = G_EDRAM0_SIZE(value);
mem_info->size_edc0 = (u16)value;
value = t4_read_reg(padap, A_MA_EDRAM1_BAR);
value = G_EDRAM1_SIZE(value);
mem_info->size_edc1 = (u16)value;
value = t4_read_reg(padap, A_MA_TARGET_MEM_ENABLE);
if (value & F_EDRAM0_ENABLE)
mem_info->mem_flag |= (1 << EDC0_FLAG);
if (value & F_EDRAM1_ENABLE)
mem_info->mem_flag |= (1 << EDC1_FLAG);
}
static void cudbg_t4_fwcache(struct cudbg_init *pdbg_init,
struct cudbg_error *cudbg_err)
{
struct adapter *padap = pdbg_init->adap;
int rc;
if (is_fw_attached(pdbg_init)) {
/* Flush uP dcache before reading edcX/mcX */
rc = begin_synchronized_op(padap, NULL, SLEEP_OK | INTR_OK,
"t4cudl");
if (rc == 0) {
rc = t4_fwcache(padap, FW_PARAM_DEV_FWCACHE_FLUSH);
end_synchronized_op(padap, 0);
}
if (rc) {
if (pdbg_init->verbose)
pdbg_init->print("%s: t4_fwcache failed (%d)\n",
__func__, rc);
cudbg_err->sys_warn = rc;
}
}
}
static int collect_edc0_meminfo(struct cudbg_init *pdbg_init,
struct cudbg_buffer *dbg_buff,
struct cudbg_error *cudbg_err)
{
struct card_mem mem_info = {0};
unsigned long edc0_size;
int rc;
cudbg_t4_fwcache(pdbg_init, cudbg_err);
collect_mem_info(pdbg_init, &mem_info);
if (mem_info.mem_flag & (1 << EDC0_FLAG)) {
edc0_size = (((unsigned long)mem_info.size_edc0) * 1024 * 1024);
rc = read_fw_mem(pdbg_init, dbg_buff, MEM_EDC0,
edc0_size, cudbg_err);
if (rc)
goto err;
} else {
rc = CUDBG_STATUS_ENTITY_NOT_FOUND;
if (pdbg_init->verbose)
pdbg_init->print("%s(), collect_mem_info failed!, %s\n",
__func__, err_msg[-rc]);
goto err;
}
err:
return rc;
}
static int collect_edc1_meminfo(struct cudbg_init *pdbg_init,
struct cudbg_buffer *dbg_buff,
struct cudbg_error *cudbg_err)
{
struct card_mem mem_info = {0};
unsigned long edc1_size;
int rc;
cudbg_t4_fwcache(pdbg_init, cudbg_err);
collect_mem_info(pdbg_init, &mem_info);
if (mem_info.mem_flag & (1 << EDC1_FLAG)) {
edc1_size = (((unsigned long)mem_info.size_edc1) * 1024 * 1024);
rc = read_fw_mem(pdbg_init, dbg_buff, MEM_EDC1,
edc1_size, cudbg_err);
if (rc)
goto err;
} else {
rc = CUDBG_STATUS_ENTITY_NOT_FOUND;
if (pdbg_init->verbose)
pdbg_init->print("%s(), collect_mem_info failed!, %s\n",
__func__, err_msg[-rc]);
goto err;
}
err:
return rc;
}
static int collect_mc0_meminfo(struct cudbg_init *pdbg_init,
struct cudbg_buffer *dbg_buff,
struct cudbg_error *cudbg_err)
{
struct card_mem mem_info = {0};
unsigned long mc0_size;
int rc;
cudbg_t4_fwcache(pdbg_init, cudbg_err);
collect_mem_info(pdbg_init, &mem_info);
if (mem_info.mem_flag & (1 << MC0_FLAG)) {
mc0_size = (((unsigned long)mem_info.size_mc0) * 1024 * 1024);
rc = read_fw_mem(pdbg_init, dbg_buff, MEM_MC0,
mc0_size, cudbg_err);
if (rc)
goto err;
} else {
rc = CUDBG_STATUS_ENTITY_NOT_FOUND;
if (pdbg_init->verbose)
pdbg_init->print("%s(), collect_mem_info failed!, %s\n",
__func__, err_msg[-rc]);
goto err;
}
err:
return rc;
}
static int collect_mc1_meminfo(struct cudbg_init *pdbg_init,
struct cudbg_buffer *dbg_buff,
struct cudbg_error *cudbg_err)
{
struct card_mem mem_info = {0};
unsigned long mc1_size;
int rc;
cudbg_t4_fwcache(pdbg_init, cudbg_err);
collect_mem_info(pdbg_init, &mem_info);
if (mem_info.mem_flag & (1 << MC1_FLAG)) {
mc1_size = (((unsigned long)mem_info.size_mc1) * 1024 * 1024);
rc = read_fw_mem(pdbg_init, dbg_buff, MEM_MC1,
mc1_size, cudbg_err);
if (rc)
goto err;
} else {
rc = CUDBG_STATUS_ENTITY_NOT_FOUND;
if (pdbg_init->verbose)
pdbg_init->print("%s(), collect_mem_info failed!, %s\n",
__func__, err_msg[-rc]);
goto err;
}
err:
return rc;
}
static int collect_reg_dump(struct cudbg_init *pdbg_init,
struct cudbg_buffer *dbg_buff,
struct cudbg_error *cudbg_err)
{
struct cudbg_buffer scratch_buff;
struct cudbg_buffer tmp_scratch_buff;
struct adapter *padap = pdbg_init->adap;
unsigned long bytes_read = 0;
unsigned long bytes_left;
u32 buf_size = 0, bytes = 0;
int rc = 0;
if (is_t4(padap))
buf_size = T4_REGMAP_SIZE ;/*+ sizeof(unsigned int);*/
else if (is_t5(padap) || is_t6(padap))
buf_size = T5_REGMAP_SIZE;
scratch_buff.size = buf_size;
tmp_scratch_buff = scratch_buff;
rc = get_scratch_buff(dbg_buff, scratch_buff.size, &scratch_buff);
if (rc)
goto err;
/* no return */
t4_get_regs(padap, (void *)scratch_buff.data, scratch_buff.size);
bytes_left = scratch_buff.size;
rc = write_compression_hdr(&scratch_buff, dbg_buff);
if (rc)
goto err1;
while (bytes_left > 0) {
tmp_scratch_buff.data =
((char *)scratch_buff.data) + bytes_read;
bytes = min_t(unsigned long, bytes_left, (unsigned long)CUDBG_CHUNK_SIZE);
tmp_scratch_buff.size = bytes;
compress_buff(&tmp_scratch_buff, dbg_buff);
bytes_left -= bytes;
bytes_read += bytes;
}
err1:
release_scratch_buff(&scratch_buff, dbg_buff);
err:
return rc;
}
static int collect_cctrl(struct cudbg_init *pdbg_init,
struct cudbg_buffer *dbg_buff,
struct cudbg_error *cudbg_err)
{
struct cudbg_buffer scratch_buff;
struct adapter *padap = pdbg_init->adap;
u32 size;
int rc;
size = sizeof(u16) * NMTUS * NCCTRL_WIN;
scratch_buff.size = size;
rc = get_scratch_buff(dbg_buff, scratch_buff.size, &scratch_buff);
if (rc)
goto err;
t4_read_cong_tbl(padap, (void *)scratch_buff.data);
rc = write_compression_hdr(&scratch_buff, dbg_buff);
if (rc)
goto err1;
rc = compress_buff(&scratch_buff, dbg_buff);
err1:
release_scratch_buff(&scratch_buff, dbg_buff);
err:
return rc;
}
static int check_busy_bit(struct adapter *padap)
{
u32 val;
u32 busy = 1;
int i = 0;
int retry = 10;
int status = 0;
while (busy & (1 < retry)) {
val = t4_read_reg(padap, A_CIM_HOST_ACC_CTRL);
busy = (0 != (val & CUDBG_CIM_BUSY_BIT));
i++;
}
if (busy)
status = -1;
return status;
}
static int cim_ha_rreg(struct adapter *padap, u32 addr, u32 *val)
{
int rc = 0;
/* write register address into the A_CIM_HOST_ACC_CTRL */
t4_write_reg(padap, A_CIM_HOST_ACC_CTRL, addr);
/* Poll HOSTBUSY */
rc = check_busy_bit(padap);
if (rc)
goto err;
/* Read value from A_CIM_HOST_ACC_DATA */
*val = t4_read_reg(padap, A_CIM_HOST_ACC_DATA);
err:
return rc;
}
static int dump_up_cim(struct adapter *padap, struct cudbg_init *pdbg_init,
struct ireg_field *up_cim_reg, u32 *buff)
{
u32 i;
int rc = 0;
for (i = 0; i < up_cim_reg->ireg_offset_range; i++) {
rc = cim_ha_rreg(padap,
up_cim_reg->ireg_local_offset + (i * 4),
buff);
if (rc) {
if (pdbg_init->verbose)
pdbg_init->print("BUSY timeout reading"
"CIM_HOST_ACC_CTRL\n");
goto err;
}
buff++;
}
err:
return rc;
}
static int collect_up_cim_indirect(struct cudbg_init *pdbg_init,
struct cudbg_buffer *dbg_buff,
struct cudbg_error *cudbg_err)
{
struct cudbg_buffer scratch_buff;
struct adapter *padap = pdbg_init->adap;
struct ireg_buf *up_cim;
u32 size;
int i, rc, n;
n = sizeof(t5_up_cim_reg_array) / (4 * sizeof(u32));
size = sizeof(struct ireg_buf) * n;
scratch_buff.size = size;
rc = get_scratch_buff(dbg_buff, scratch_buff.size, &scratch_buff);
if (rc)
goto err;
up_cim = (struct ireg_buf *)scratch_buff.data;
for (i = 0; i < n; i++) {
struct ireg_field *up_cim_reg = &up_cim->tp_pio;
u32 *buff = up_cim->outbuf;
if (is_t5(padap)) {
up_cim_reg->ireg_addr = t5_up_cim_reg_array[i][0];
up_cim_reg->ireg_data = t5_up_cim_reg_array[i][1];
up_cim_reg->ireg_local_offset =
t5_up_cim_reg_array[i][2];
up_cim_reg->ireg_offset_range =
t5_up_cim_reg_array[i][3];
} else if (is_t6(padap)) {
up_cim_reg->ireg_addr = t6_up_cim_reg_array[i][0];
up_cim_reg->ireg_data = t6_up_cim_reg_array[i][1];
up_cim_reg->ireg_local_offset =
t6_up_cim_reg_array[i][2];
up_cim_reg->ireg_offset_range =
t6_up_cim_reg_array[i][3];
}
rc = dump_up_cim(padap, pdbg_init, up_cim_reg, buff);
up_cim++;
}
rc = write_compression_hdr(&scratch_buff, dbg_buff);
if (rc)
goto err1;
rc = compress_buff(&scratch_buff, dbg_buff);
err1:
release_scratch_buff(&scratch_buff, dbg_buff);
err:
return rc;
}
static int collect_mbox_log(struct cudbg_init *pdbg_init,
struct cudbg_buffer *dbg_buff,
struct cudbg_error *cudbg_err)
{
#ifdef notyet
struct cudbg_buffer scratch_buff;
struct cudbg_mbox_log *mboxlog = NULL;
struct mbox_cmd_log *log = NULL;
struct mbox_cmd *entry;
u64 flit;
u32 size;
unsigned int entry_idx;
int i, k, rc;
u16 mbox_cmds;
if (pdbg_init->dbg_params[CUDBG_MBOX_LOG_PARAM].u.mboxlog_param.log) {
log = pdbg_init->dbg_params[CUDBG_MBOX_LOG_PARAM].u.
mboxlog_param.log;
mbox_cmds = pdbg_init->dbg_params[CUDBG_MBOX_LOG_PARAM].u.
mboxlog_param.mbox_cmds;
} else {
if (pdbg_init->verbose)
pdbg_init->print("Mbox log is not requested\n");
return CUDBG_STATUS_ENTITY_NOT_REQUESTED;
}
size = sizeof(struct cudbg_mbox_log) * mbox_cmds;
scratch_buff.size = size;
rc = get_scratch_buff(dbg_buff, scratch_buff.size, &scratch_buff);
if (rc)
goto err;
mboxlog = (struct cudbg_mbox_log *)scratch_buff.data;
for (k = 0; k < mbox_cmds; k++) {
entry_idx = log->cursor + k;
if (entry_idx >= log->size)
entry_idx -= log->size;
entry = mbox_cmd_log_entry(log, entry_idx);
/* skip over unused entries */
if (entry->timestamp == 0)
continue;
memcpy(&mboxlog->entry, entry, sizeof(struct mbox_cmd));
for (i = 0; i < MBOX_LEN / 8; i++) {
flit = entry->cmd[i];
mboxlog->hi[i] = (u32)(flit >> 32);
mboxlog->lo[i] = (u32)flit;
}
mboxlog++;
}
rc = write_compression_hdr(&scratch_buff, dbg_buff);
if (rc)
goto err1;
rc = compress_buff(&scratch_buff, dbg_buff);
err1:
release_scratch_buff(&scratch_buff, dbg_buff);
err:
return rc;
#endif
return (EDOOFUS);
}
static int collect_pbt_tables(struct cudbg_init *pdbg_init,
struct cudbg_buffer *dbg_buff,
struct cudbg_error *cudbg_err)
{
struct cudbg_buffer scratch_buff;
struct adapter *padap = pdbg_init->adap;
struct cudbg_pbt_tables *pbt = NULL;
u32 size;
u32 addr;
int i, rc;
size = sizeof(struct cudbg_pbt_tables);
scratch_buff.size = size;
rc = get_scratch_buff(dbg_buff, scratch_buff.size, &scratch_buff);
if (rc)
goto err;
pbt = (struct cudbg_pbt_tables *)scratch_buff.data;
/* PBT dynamic entries */
addr = CUDBG_CHAC_PBT_ADDR;
for (i = 0; i < CUDBG_PBT_DYNAMIC_ENTRIES; i++) {
rc = cim_ha_rreg(padap, addr + (i * 4), &pbt->pbt_dynamic[i]);
if (rc) {
if (pdbg_init->verbose)
pdbg_init->print("BUSY timeout reading"
"CIM_HOST_ACC_CTRL\n");
goto err1;
}
}
/* PBT static entries */
/* static entries start when bit 6 is set */
addr = CUDBG_CHAC_PBT_ADDR + (1 << 6);
for (i = 0; i < CUDBG_PBT_STATIC_ENTRIES; i++) {
rc = cim_ha_rreg(padap, addr + (i * 4), &pbt->pbt_static[i]);
if (rc) {
if (pdbg_init->verbose)
pdbg_init->print("BUSY timeout reading"
"CIM_HOST_ACC_CTRL\n");
goto err1;
}
}
/* LRF entries */
addr = CUDBG_CHAC_PBT_LRF;
for (i = 0; i < CUDBG_LRF_ENTRIES; i++) {
rc = cim_ha_rreg(padap, addr + (i * 4), &pbt->lrf_table[i]);
if (rc) {
if (pdbg_init->verbose)
pdbg_init->print("BUSY timeout reading"
"CIM_HOST_ACC_CTRL\n");
goto err1;
}
}
/* PBT data entries */
addr = CUDBG_CHAC_PBT_DATA;
for (i = 0; i < CUDBG_PBT_DATA_ENTRIES; i++) {
rc = cim_ha_rreg(padap, addr + (i * 4), &pbt->pbt_data[i]);
if (rc) {
if (pdbg_init->verbose)
pdbg_init->print("BUSY timeout reading"
"CIM_HOST_ACC_CTRL\n");
goto err1;
}
}
rc = write_compression_hdr(&scratch_buff, dbg_buff);
if (rc)
goto err1;
rc = compress_buff(&scratch_buff, dbg_buff);
err1:
release_scratch_buff(&scratch_buff, dbg_buff);
err:
return rc;
}
static int collect_pm_indirect(struct cudbg_init *pdbg_init,
struct cudbg_buffer *dbg_buff,
struct cudbg_error *cudbg_err)
{
struct cudbg_buffer scratch_buff;
struct adapter *padap = pdbg_init->adap;
struct ireg_buf *ch_pm;
u32 size;
int i, rc, n;
n = sizeof(t5_pm_rx_array) / (4 * sizeof(u32));
size = sizeof(struct ireg_buf) * n * 2;
scratch_buff.size = size;
rc = get_scratch_buff(dbg_buff, scratch_buff.size, &scratch_buff);
if (rc)
goto err;
ch_pm = (struct ireg_buf *)scratch_buff.data;
/*PM_RX*/
for (i = 0; i < n; i++) {
struct ireg_field *pm_pio = &ch_pm->tp_pio;
u32 *buff = ch_pm->outbuf;
pm_pio->ireg_addr = t5_pm_rx_array[i][0];
pm_pio->ireg_data = t5_pm_rx_array[i][1];
pm_pio->ireg_local_offset = t5_pm_rx_array[i][2];
pm_pio->ireg_offset_range = t5_pm_rx_array[i][3];
t4_read_indirect(padap,
pm_pio->ireg_addr,
pm_pio->ireg_data,
buff,
pm_pio->ireg_offset_range,
pm_pio->ireg_local_offset);
ch_pm++;
}
/*PM_Tx*/
n = sizeof(t5_pm_tx_array) / (4 * sizeof(u32));
for (i = 0; i < n; i++) {
struct ireg_field *pm_pio = &ch_pm->tp_pio;
u32 *buff = ch_pm->outbuf;
pm_pio->ireg_addr = t5_pm_tx_array[i][0];
pm_pio->ireg_data = t5_pm_tx_array[i][1];
pm_pio->ireg_local_offset = t5_pm_tx_array[i][2];
pm_pio->ireg_offset_range = t5_pm_tx_array[i][3];
t4_read_indirect(padap,
pm_pio->ireg_addr,
pm_pio->ireg_data,
buff,
pm_pio->ireg_offset_range,
pm_pio->ireg_local_offset);
ch_pm++;
}
rc = write_compression_hdr(&scratch_buff, dbg_buff);
if (rc)
goto err1;
rc = compress_buff(&scratch_buff, dbg_buff);
err1:
release_scratch_buff(&scratch_buff, dbg_buff);
err:
return rc;
}
static int collect_tid(struct cudbg_init *pdbg_init,
struct cudbg_buffer *dbg_buff,
struct cudbg_error *cudbg_err)
{
struct cudbg_buffer scratch_buff;
struct adapter *padap = pdbg_init->adap;
struct tid_info_region *tid;
struct tid_info_region_rev1 *tid1;
u32 para[7], val[7];
u32 mbox, pf;
int rc;
scratch_buff.size = sizeof(struct tid_info_region_rev1);
rc = get_scratch_buff(dbg_buff, scratch_buff.size, &scratch_buff);
if (rc)
goto err;
#define FW_PARAM_DEV_A(param) \
(V_FW_PARAMS_MNEM(FW_PARAMS_MNEM_DEV) | \
V_FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_DEV_##param))
#define FW_PARAM_PFVF_A(param) \
(V_FW_PARAMS_MNEM(FW_PARAMS_MNEM_PFVF) | \
V_FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_PFVF_##param)| \
V_FW_PARAMS_PARAM_Y(0) | \
V_FW_PARAMS_PARAM_Z(0))
#define MAX_ATIDS_A 8192U
tid1 = (struct tid_info_region_rev1 *)scratch_buff.data;
tid = &(tid1->tid);
tid1->ver_hdr.signature = CUDBG_ENTITY_SIGNATURE;
tid1->ver_hdr.revision = CUDBG_TID_INFO_REV;
tid1->ver_hdr.size = sizeof(struct tid_info_region_rev1) -
sizeof(struct cudbg_ver_hdr);
if (is_t5(padap)) {
tid->hash_base = t4_read_reg(padap, A_LE_DB_TID_HASHBASE);
tid1->tid_start = 0;
} else if (is_t6(padap)) {
tid->hash_base = t4_read_reg(padap, A_T6_LE_DB_HASH_TID_BASE);
tid1->tid_start = t4_read_reg(padap, A_LE_DB_ACTIVE_TABLE_START_INDEX);
}
tid->le_db_conf = t4_read_reg(padap, A_LE_DB_CONFIG);
para[0] = FW_PARAM_PFVF_A(FILTER_START);
para[1] = FW_PARAM_PFVF_A(FILTER_END);
para[2] = FW_PARAM_PFVF_A(ACTIVE_FILTER_START);
para[3] = FW_PARAM_PFVF_A(ACTIVE_FILTER_END);
para[4] = FW_PARAM_DEV_A(NTID);
para[5] = FW_PARAM_PFVF_A(SERVER_START);
para[6] = FW_PARAM_PFVF_A(SERVER_END);
rc = begin_synchronized_op(padap, NULL, SLEEP_OK | INTR_OK, "t4cudq");
if (rc)
goto err;
mbox = padap->mbox;
pf = padap->pf;
rc = t4_query_params(padap, mbox, pf, 0, 7, para, val);
if (rc < 0) {
if (rc == -FW_EPERM) {
/* It looks like we don't have permission to use
* padap->mbox.
*
* Try mbox 4. If it works, we'll continue to
* collect the rest of tid info from mbox 4.
* Else, quit trying to collect tid info.
*/
mbox = 4;
pf = 4;
rc = t4_query_params(padap, mbox, pf, 0, 7, para, val);
if (rc < 0) {
cudbg_err->sys_err = rc;
goto err1;
}
} else {
cudbg_err->sys_err = rc;
goto err1;
}
}
tid->ftid_base = val[0];
tid->nftids = val[1] - val[0] + 1;
/*active filter region*/
if (val[2] != val[3]) {
#ifdef notyet
tid->flags |= FW_OFLD_CONN;
#endif
tid->aftid_base = val[2];
tid->aftid_end = val[3];
}
tid->ntids = val[4];
tid->natids = min_t(u32, tid->ntids / 2, MAX_ATIDS_A);
tid->stid_base = val[5];
tid->nstids = val[6] - val[5] + 1;
if (chip_id(padap) >= CHELSIO_T6) {
para[0] = FW_PARAM_PFVF_A(HPFILTER_START);
para[1] = FW_PARAM_PFVF_A(HPFILTER_END);
rc = t4_query_params(padap, mbox, pf, 0, 2, para, val);
if (rc < 0) {
cudbg_err->sys_err = rc;
goto err1;
}
tid->hpftid_base = val[0];
tid->nhpftids = val[1] - val[0] + 1;
}
if (chip_id(padap) <= CHELSIO_T5) {
tid->sb = t4_read_reg(padap, A_LE_DB_SERVER_INDEX) / 4;
tid->hash_base /= 4;
} else
tid->sb = t4_read_reg(padap, A_LE_DB_SRVR_START_INDEX);
/*UO context range*/
para[0] = FW_PARAM_PFVF_A(ETHOFLD_START);
para[1] = FW_PARAM_PFVF_A(ETHOFLD_END);
rc = t4_query_params(padap, mbox, pf, 0, 2, para, val);
if (rc < 0) {
cudbg_err->sys_err = rc;
goto err1;
}
if (val[0] != val[1]) {
tid->uotid_base = val[0];
tid->nuotids = val[1] - val[0] + 1;
}
tid->IP_users = t4_read_reg(padap, A_LE_DB_ACT_CNT_IPV4);
tid->IPv6_users = t4_read_reg(padap, A_LE_DB_ACT_CNT_IPV6);
#undef FW_PARAM_PFVF_A
#undef FW_PARAM_DEV_A
#undef MAX_ATIDS_A
rc = write_compression_hdr(&scratch_buff, dbg_buff);
if (rc)
goto err1;
rc = compress_buff(&scratch_buff, dbg_buff);
err1:
end_synchronized_op(padap, 0);
release_scratch_buff(&scratch_buff, dbg_buff);
err:
return rc;
}
static int collect_tx_rate(struct cudbg_init *pdbg_init,
struct cudbg_buffer *dbg_buff,
struct cudbg_error *cudbg_err)
{
struct cudbg_buffer scratch_buff;
struct adapter *padap = pdbg_init->adap;
struct tx_rate *tx_rate;
u32 size;
int rc;
size = sizeof(struct tx_rate);
scratch_buff.size = size;
rc = get_scratch_buff(dbg_buff, scratch_buff.size, &scratch_buff);
if (rc)
goto err;
tx_rate = (struct tx_rate *)scratch_buff.data;
t4_get_chan_txrate(padap, tx_rate->nrate, tx_rate->orate);
tx_rate->nchan = padap->chip_params->nchan;
rc = write_compression_hdr(&scratch_buff, dbg_buff);
if (rc)
goto err1;
rc = compress_buff(&scratch_buff, dbg_buff);
err1:
release_scratch_buff(&scratch_buff, dbg_buff);
err:
return rc;
}
static inline void cudbg_tcamxy2valmask(u64 x, u64 y, u8 *addr, u64 *mask)
{
*mask = x | y;
y = (__force u64)cpu_to_be64(y);
memcpy(addr, (char *)&y + 2, ETH_ALEN);
}
static void mps_rpl_backdoor(struct adapter *padap, struct fw_ldst_mps_rplc *mps_rplc)
{
if (is_t5(padap)) {
mps_rplc->rplc255_224 = htonl(t4_read_reg(padap,
A_MPS_VF_RPLCT_MAP3));
mps_rplc->rplc223_192 = htonl(t4_read_reg(padap,
A_MPS_VF_RPLCT_MAP2));
mps_rplc->rplc191_160 = htonl(t4_read_reg(padap,
A_MPS_VF_RPLCT_MAP1));
mps_rplc->rplc159_128 = htonl(t4_read_reg(padap,
A_MPS_VF_RPLCT_MAP0));
} else {
mps_rplc->rplc255_224 = htonl(t4_read_reg(padap,
A_MPS_VF_RPLCT_MAP7));
mps_rplc->rplc223_192 = htonl(t4_read_reg(padap,
A_MPS_VF_RPLCT_MAP6));
mps_rplc->rplc191_160 = htonl(t4_read_reg(padap,
A_MPS_VF_RPLCT_MAP5));
mps_rplc->rplc159_128 = htonl(t4_read_reg(padap,
A_MPS_VF_RPLCT_MAP4));
}
mps_rplc->rplc127_96 = htonl(t4_read_reg(padap, A_MPS_VF_RPLCT_MAP3));
mps_rplc->rplc95_64 = htonl(t4_read_reg(padap, A_MPS_VF_RPLCT_MAP2));
mps_rplc->rplc63_32 = htonl(t4_read_reg(padap, A_MPS_VF_RPLCT_MAP1));
mps_rplc->rplc31_0 = htonl(t4_read_reg(padap, A_MPS_VF_RPLCT_MAP0));
}
static int collect_mps_tcam(struct cudbg_init *pdbg_init,
struct cudbg_buffer *dbg_buff,
struct cudbg_error *cudbg_err)
{
struct cudbg_buffer scratch_buff;
struct adapter *padap = pdbg_init->adap;
struct cudbg_mps_tcam *tcam = NULL;
u32 size = 0, i, n, total_size = 0;
u32 ctl, data2;
u64 tcamy, tcamx, val;
int rc;
n = padap->chip_params->mps_tcam_size;
size = sizeof(struct cudbg_mps_tcam) * n;
scratch_buff.size = size;
rc = get_scratch_buff(dbg_buff, scratch_buff.size, &scratch_buff);
if (rc)
goto err;
memset(scratch_buff.data, 0, size);
tcam = (struct cudbg_mps_tcam *)scratch_buff.data;
for (i = 0; i < n; i++) {
if (chip_id(padap) >= CHELSIO_T6) {
/* CtlReqID - 1: use Host Driver Requester ID
* CtlCmdType - 0: Read, 1: Write
* CtlTcamSel - 0: TCAM0, 1: TCAM1
* CtlXYBitSel- 0: Y bit, 1: X bit
*/
/* Read tcamy */
ctl = (V_CTLREQID(1) |
V_CTLCMDTYPE(0) | V_CTLXYBITSEL(0));
if (i < 256)
ctl |= V_CTLTCAMINDEX(i) | V_CTLTCAMSEL(0);
else
ctl |= V_CTLTCAMINDEX(i - 256) |
V_CTLTCAMSEL(1);
t4_write_reg(padap, A_MPS_CLS_TCAM_DATA2_CTL, ctl);
val = t4_read_reg(padap, A_MPS_CLS_TCAM_RDATA1_REQ_ID1);
tcamy = G_DMACH(val) << 32;
tcamy |= t4_read_reg(padap, A_MPS_CLS_TCAM_RDATA0_REQ_ID1);
data2 = t4_read_reg(padap, A_MPS_CLS_TCAM_RDATA2_REQ_ID1);
tcam->lookup_type = G_DATALKPTYPE(data2);
/* 0 - Outer header, 1 - Inner header
* [71:48] bit locations are overloaded for
* outer vs. inner lookup types.
*/
if (tcam->lookup_type &&
(tcam->lookup_type != M_DATALKPTYPE)) {
/* Inner header VNI */
tcam->vniy = ((data2 & F_DATAVIDH2) << 23) |
(G_DATAVIDH1(data2) << 16) |
G_VIDL(val);
tcam->dip_hit = data2 & F_DATADIPHIT;
} else {
tcam->vlan_vld = data2 & F_DATAVIDH2;
tcam->ivlan = G_VIDL(val);
}
tcam->port_num = G_DATAPORTNUM(data2);
/* Read tcamx. Change the control param */
ctl |= V_CTLXYBITSEL(1);
t4_write_reg(padap, A_MPS_CLS_TCAM_DATA2_CTL, ctl);
val = t4_read_reg(padap, A_MPS_CLS_TCAM_RDATA1_REQ_ID1);
tcamx = G_DMACH(val) << 32;
tcamx |= t4_read_reg(padap, A_MPS_CLS_TCAM_RDATA0_REQ_ID1);
data2 = t4_read_reg(padap, A_MPS_CLS_TCAM_RDATA2_REQ_ID1);
if (tcam->lookup_type &&
(tcam->lookup_type != M_DATALKPTYPE)) {
/* Inner header VNI mask */
tcam->vnix = ((data2 & F_DATAVIDH2) << 23) |
(G_DATAVIDH1(data2) << 16) |
G_VIDL(val);
}
} else {
tcamy = t4_read_reg64(padap, MPS_CLS_TCAM_Y_L(i));
tcamx = t4_read_reg64(padap, MPS_CLS_TCAM_X_L(i));
}
if (tcamx & tcamy)
continue;
tcam->cls_lo = t4_read_reg(padap, MPS_CLS_SRAM_L(i));
tcam->cls_hi = t4_read_reg(padap, MPS_CLS_SRAM_H(i));
if (is_t5(padap))
tcam->repli = (tcam->cls_lo & F_REPLICATE);
else if (is_t6(padap))
tcam->repli = (tcam->cls_lo & F_T6_REPLICATE);
if (tcam->repli) {
struct fw_ldst_cmd ldst_cmd;
struct fw_ldst_mps_rplc mps_rplc;
memset(&ldst_cmd, 0, sizeof(ldst_cmd));
ldst_cmd.op_to_addrspace =
htonl(V_FW_CMD_OP(FW_LDST_CMD) |
F_FW_CMD_REQUEST |
F_FW_CMD_READ |
V_FW_LDST_CMD_ADDRSPACE(
FW_LDST_ADDRSPC_MPS));
ldst_cmd.cycles_to_len16 = htonl(FW_LEN16(ldst_cmd));
ldst_cmd.u.mps.rplc.fid_idx =
htons(V_FW_LDST_CMD_FID(FW_LDST_MPS_RPLC) |
V_FW_LDST_CMD_IDX(i));
rc = begin_synchronized_op(padap, NULL,
SLEEP_OK | INTR_OK, "t4cudm");
if (rc == 0) {
rc = t4_wr_mbox(padap, padap->mbox, &ldst_cmd,
sizeof(ldst_cmd), &ldst_cmd);
end_synchronized_op(padap, 0);
}
if (rc)
mps_rpl_backdoor(padap, &mps_rplc);
else
mps_rplc = ldst_cmd.u.mps.rplc;
tcam->rplc[0] = ntohl(mps_rplc.rplc31_0);
tcam->rplc[1] = ntohl(mps_rplc.rplc63_32);
tcam->rplc[2] = ntohl(mps_rplc.rplc95_64);
tcam->rplc[3] = ntohl(mps_rplc.rplc127_96);
if (padap->chip_params->mps_rplc_size >
CUDBG_MAX_RPLC_SIZE) {
tcam->rplc[4] = ntohl(mps_rplc.rplc159_128);
tcam->rplc[5] = ntohl(mps_rplc.rplc191_160);
tcam->rplc[6] = ntohl(mps_rplc.rplc223_192);
tcam->rplc[7] = ntohl(mps_rplc.rplc255_224);
}
}
cudbg_tcamxy2valmask(tcamx, tcamy, tcam->addr, &tcam->mask);
tcam->idx = i;
tcam->rplc_size = padap->chip_params->mps_rplc_size;
total_size += sizeof(struct cudbg_mps_tcam);
tcam++;
}
if (total_size == 0) {
rc = CUDBG_SYSTEM_ERROR;
goto err1;
}
scratch_buff.size = total_size;
rc = write_compression_hdr(&scratch_buff, dbg_buff);
if (rc)
goto err1;
rc = compress_buff(&scratch_buff, dbg_buff);
err1:
scratch_buff.size = size;
release_scratch_buff(&scratch_buff, dbg_buff);
err:
return rc;
}
static int collect_pcie_config(struct cudbg_init *pdbg_init,
struct cudbg_buffer *dbg_buff,
struct cudbg_error *cudbg_err)
{
struct cudbg_buffer scratch_buff;
struct adapter *padap = pdbg_init->adap;
u32 size, *value, j;
int i, rc, n;
size = sizeof(u32) * NUM_PCIE_CONFIG_REGS;
n = sizeof(t5_pcie_config_array) / (2 * sizeof(u32));
scratch_buff.size = size;
rc = get_scratch_buff(dbg_buff, scratch_buff.size, &scratch_buff);
if (rc)
goto err;
value = (u32 *)scratch_buff.data;
for (i = 0; i < n; i++) {
for (j = t5_pcie_config_array[i][0];
j <= t5_pcie_config_array[i][1]; j += 4) {
*value++ = t4_hw_pci_read_cfg4(padap, j);
}
}
rc = write_compression_hdr(&scratch_buff, dbg_buff);
if (rc)
goto err1;
rc = compress_buff(&scratch_buff, dbg_buff);
err1:
release_scratch_buff(&scratch_buff, dbg_buff);
err:
return rc;
}
static int cudbg_read_tid(struct cudbg_init *pdbg_init, u32 tid,
struct cudbg_tid_data *tid_data)
{
int i, cmd_retry = 8;
struct adapter *padap = pdbg_init->adap;
u32 val;
/* Fill REQ_DATA regs with 0's */
for (i = 0; i < CUDBG_NUM_REQ_REGS; i++)
t4_write_reg(padap, A_LE_DB_DBGI_REQ_DATA + (i << 2), 0);
/* Write DBIG command */
val = (0x4 << S_DBGICMD) | tid;
t4_write_reg(padap, A_LE_DB_DBGI_REQ_TCAM_CMD, val);
tid_data->dbig_cmd = val;
val = 0;
val |= 1 << S_DBGICMDSTRT;
val |= 1; /* LE mode */
t4_write_reg(padap, A_LE_DB_DBGI_CONFIG, val);
tid_data->dbig_conf = val;
/* Poll the DBGICMDBUSY bit */
val = 1;
while (val) {
val = t4_read_reg(padap, A_LE_DB_DBGI_CONFIG);
val = (val >> S_DBGICMDBUSY) & 1;
cmd_retry--;
if (!cmd_retry) {
if (pdbg_init->verbose)
pdbg_init->print("%s(): Timeout waiting for non-busy\n",
__func__);
return CUDBG_SYSTEM_ERROR;
}
}
/* Check RESP status */
val = 0;
val = t4_read_reg(padap, A_LE_DB_DBGI_RSP_STATUS);
tid_data->dbig_rsp_stat = val;
if (!(val & 1)) {
if (pdbg_init->verbose)
pdbg_init->print("%s(): DBGI command failed\n", __func__);
return CUDBG_SYSTEM_ERROR;
}
/* Read RESP data */
for (i = 0; i < CUDBG_NUM_REQ_REGS; i++)
tid_data->data[i] = t4_read_reg(padap,
A_LE_DB_DBGI_RSP_DATA +
(i << 2));
tid_data->tid = tid;
return 0;
}
static int collect_le_tcam(struct cudbg_init *pdbg_init,
struct cudbg_buffer *dbg_buff,
struct cudbg_error *cudbg_err)
{
struct cudbg_buffer scratch_buff;
struct adapter *padap = pdbg_init->adap;
struct cudbg_tcam tcam_region = {0};
struct cudbg_tid_data *tid_data = NULL;
u32 value, bytes = 0, bytes_left = 0;
u32 i;
int rc, size;
/* Get the LE regions */
value = t4_read_reg(padap, A_LE_DB_TID_HASHBASE); /* Get hash base
index */
tcam_region.tid_hash_base = value;
/* Get routing table index */
value = t4_read_reg(padap, A_LE_DB_ROUTING_TABLE_INDEX);
tcam_region.routing_start = value;
/*Get clip table index */
value = t4_read_reg(padap, A_LE_DB_CLIP_TABLE_INDEX);
tcam_region.clip_start = value;
/* Get filter table index */
value = t4_read_reg(padap, A_LE_DB_FILTER_TABLE_INDEX);
tcam_region.filter_start = value;
/* Get server table index */
value = t4_read_reg(padap, A_LE_DB_SERVER_INDEX);
tcam_region.server_start = value;
/* Check whether hash is enabled and calculate the max tids */
value = t4_read_reg(padap, A_LE_DB_CONFIG);
if ((value >> S_HASHEN) & 1) {
value = t4_read_reg(padap, A_LE_DB_HASH_CONFIG);
if (chip_id(padap) > CHELSIO_T5)
tcam_region.max_tid = (value & 0xFFFFF) +
tcam_region.tid_hash_base;
else { /* for T5 */
value = G_HASHTIDSIZE(value);
value = 1 << value;
tcam_region.max_tid = value +
tcam_region.tid_hash_base;
}
} else /* hash not enabled */
tcam_region.max_tid = CUDBG_MAX_TCAM_TID;
size = sizeof(struct cudbg_tid_data) * tcam_region.max_tid;
size += sizeof(struct cudbg_tcam);
scratch_buff.size = size;
rc = write_compression_hdr(&scratch_buff, dbg_buff);
if (rc)
goto err;
rc = get_scratch_buff(dbg_buff, CUDBG_CHUNK_SIZE, &scratch_buff);
if (rc)
goto err;
memcpy(scratch_buff.data, &tcam_region, sizeof(struct cudbg_tcam));
tid_data = (struct cudbg_tid_data *)(((struct cudbg_tcam *)
scratch_buff.data) + 1);
bytes_left = CUDBG_CHUNK_SIZE - sizeof(struct cudbg_tcam);
bytes = sizeof(struct cudbg_tcam);
/* read all tid */
for (i = 0; i < tcam_region.max_tid; i++) {
if (bytes_left < sizeof(struct cudbg_tid_data)) {
scratch_buff.size = bytes;
rc = compress_buff(&scratch_buff, dbg_buff);
if (rc)
goto err1;
scratch_buff.size = CUDBG_CHUNK_SIZE;
release_scratch_buff(&scratch_buff, dbg_buff);
/* new alloc */
rc = get_scratch_buff(dbg_buff, CUDBG_CHUNK_SIZE,
&scratch_buff);
if (rc)
goto err;
tid_data = (struct cudbg_tid_data *)(scratch_buff.data);
bytes_left = CUDBG_CHUNK_SIZE;
bytes = 0;
}
rc = cudbg_read_tid(pdbg_init, i, tid_data);
if (rc) {
cudbg_err->sys_err = rc;
goto err1;
}
tid_data++;
bytes_left -= sizeof(struct cudbg_tid_data);
bytes += sizeof(struct cudbg_tid_data);
}
if (bytes) {
scratch_buff.size = bytes;
rc = compress_buff(&scratch_buff, dbg_buff);
}
err1:
scratch_buff.size = CUDBG_CHUNK_SIZE;
release_scratch_buff(&scratch_buff, dbg_buff);
err:
return rc;
}
static int collect_ma_indirect(struct cudbg_init *pdbg_init,
struct cudbg_buffer *dbg_buff,
struct cudbg_error *cudbg_err)
{
struct cudbg_buffer scratch_buff;
struct adapter *padap = pdbg_init->adap;
struct ireg_buf *ma_indr = NULL;
u32 size, j;
int i, rc, n;
if (chip_id(padap) < CHELSIO_T6) {
if (pdbg_init->verbose)
pdbg_init->print("MA indirect available only in T6\n");
rc = CUDBG_STATUS_ENTITY_NOT_FOUND;
goto err;
}
n = sizeof(t6_ma_ireg_array) / (4 * sizeof(u32));
size = sizeof(struct ireg_buf) * n * 2;
scratch_buff.size = size;
rc = get_scratch_buff(dbg_buff, scratch_buff.size, &scratch_buff);
if (rc)
goto err;
ma_indr = (struct ireg_buf *)scratch_buff.data;
for (i = 0; i < n; i++) {
struct ireg_field *ma_fli = &ma_indr->tp_pio;
u32 *buff = ma_indr->outbuf;
ma_fli->ireg_addr = t6_ma_ireg_array[i][0];
ma_fli->ireg_data = t6_ma_ireg_array[i][1];
ma_fli->ireg_local_offset = t6_ma_ireg_array[i][2];
ma_fli->ireg_offset_range = t6_ma_ireg_array[i][3];
t4_read_indirect(padap, ma_fli->ireg_addr, ma_fli->ireg_data,
buff, ma_fli->ireg_offset_range,
ma_fli->ireg_local_offset);
ma_indr++;
}
n = sizeof(t6_ma_ireg_array2) / (4 * sizeof(u32));
for (i = 0; i < n; i++) {
struct ireg_field *ma_fli = &ma_indr->tp_pio;
u32 *buff = ma_indr->outbuf;
ma_fli->ireg_addr = t6_ma_ireg_array2[i][0];
ma_fli->ireg_data = t6_ma_ireg_array2[i][1];
ma_fli->ireg_local_offset = t6_ma_ireg_array2[i][2];
for (j = 0; j < t6_ma_ireg_array2[i][3]; j++) {
t4_read_indirect(padap, ma_fli->ireg_addr,
ma_fli->ireg_data, buff, 1,
ma_fli->ireg_local_offset);
buff++;
ma_fli->ireg_local_offset += 0x20;
}
ma_indr++;
}
rc = write_compression_hdr(&scratch_buff, dbg_buff);
if (rc)
goto err1;
rc = compress_buff(&scratch_buff, dbg_buff);
err1:
release_scratch_buff(&scratch_buff, dbg_buff);
err:
return rc;
}
static int collect_hma_indirect(struct cudbg_init *pdbg_init,
struct cudbg_buffer *dbg_buff,
struct cudbg_error *cudbg_err)
{
struct cudbg_buffer scratch_buff;
struct adapter *padap = pdbg_init->adap;
struct ireg_buf *hma_indr = NULL;
u32 size;
int i, rc, n;
if (chip_id(padap) < CHELSIO_T6) {
if (pdbg_init->verbose)
pdbg_init->print("HMA indirect available only in T6\n");
rc = CUDBG_STATUS_ENTITY_NOT_FOUND;
goto err;
}
n = sizeof(t6_hma_ireg_array) / (4 * sizeof(u32));
size = sizeof(struct ireg_buf) * n;
scratch_buff.size = size;
rc = get_scratch_buff(dbg_buff, scratch_buff.size, &scratch_buff);
if (rc)
goto err;
hma_indr = (struct ireg_buf *)scratch_buff.data;
for (i = 0; i < n; i++) {
struct ireg_field *hma_fli = &hma_indr->tp_pio;
u32 *buff = hma_indr->outbuf;
hma_fli->ireg_addr = t6_hma_ireg_array[i][0];
hma_fli->ireg_data = t6_hma_ireg_array[i][1];
hma_fli->ireg_local_offset = t6_hma_ireg_array[i][2];
hma_fli->ireg_offset_range = t6_hma_ireg_array[i][3];
t4_read_indirect(padap, hma_fli->ireg_addr, hma_fli->ireg_data,
buff, hma_fli->ireg_offset_range,
hma_fli->ireg_local_offset);
hma_indr++;
}
rc = write_compression_hdr(&scratch_buff, dbg_buff);
if (rc)
goto err1;
rc = compress_buff(&scratch_buff, dbg_buff);
err1:
release_scratch_buff(&scratch_buff, dbg_buff);
err:
return rc;
}
static int collect_pcie_indirect(struct cudbg_init *pdbg_init,
struct cudbg_buffer *dbg_buff,
struct cudbg_error *cudbg_err)
{
struct cudbg_buffer scratch_buff;
struct adapter *padap = pdbg_init->adap;
struct ireg_buf *ch_pcie;
u32 size;
int i, rc, n;
n = sizeof(t5_pcie_pdbg_array) / (4 * sizeof(u32));
size = sizeof(struct ireg_buf) * n * 2;
scratch_buff.size = size;
rc = get_scratch_buff(dbg_buff, scratch_buff.size, &scratch_buff);
if (rc)
goto err;
ch_pcie = (struct ireg_buf *)scratch_buff.data;
/*PCIE_PDBG*/
for (i = 0; i < n; i++) {
struct ireg_field *pcie_pio = &ch_pcie->tp_pio;
u32 *buff = ch_pcie->outbuf;
pcie_pio->ireg_addr = t5_pcie_pdbg_array[i][0];
pcie_pio->ireg_data = t5_pcie_pdbg_array[i][1];
pcie_pio->ireg_local_offset = t5_pcie_pdbg_array[i][2];
pcie_pio->ireg_offset_range = t5_pcie_pdbg_array[i][3];
t4_read_indirect(padap,
pcie_pio->ireg_addr,
pcie_pio->ireg_data,
buff,
pcie_pio->ireg_offset_range,
pcie_pio->ireg_local_offset);
ch_pcie++;
}
/*PCIE_CDBG*/
n = sizeof(t5_pcie_cdbg_array) / (4 * sizeof(u32));
for (i = 0; i < n; i++) {
struct ireg_field *pcie_pio = &ch_pcie->tp_pio;
u32 *buff = ch_pcie->outbuf;
pcie_pio->ireg_addr = t5_pcie_cdbg_array[i][0];
pcie_pio->ireg_data = t5_pcie_cdbg_array[i][1];
pcie_pio->ireg_local_offset = t5_pcie_cdbg_array[i][2];
pcie_pio->ireg_offset_range = t5_pcie_cdbg_array[i][3];
t4_read_indirect(padap,
pcie_pio->ireg_addr,
pcie_pio->ireg_data,
buff,
pcie_pio->ireg_offset_range,
pcie_pio->ireg_local_offset);
ch_pcie++;
}
rc = write_compression_hdr(&scratch_buff, dbg_buff);
if (rc)
goto err1;
rc = compress_buff(&scratch_buff, dbg_buff);
err1:
release_scratch_buff(&scratch_buff, dbg_buff);
err:
return rc;
}
static int collect_tp_indirect(struct cudbg_init *pdbg_init,
struct cudbg_buffer *dbg_buff,
struct cudbg_error *cudbg_err)
{
struct cudbg_buffer scratch_buff;
struct adapter *padap = pdbg_init->adap;
struct ireg_buf *ch_tp_pio;
u32 size;
int i, rc, n = 0;
if (is_t5(padap))
n = sizeof(t5_tp_pio_array) / (4 * sizeof(u32));
else if (is_t6(padap))
n = sizeof(t6_tp_pio_array) / (4 * sizeof(u32));
size = sizeof(struct ireg_buf) * n * 3;
scratch_buff.size = size;
rc = get_scratch_buff(dbg_buff, scratch_buff.size, &scratch_buff);
if (rc)
goto err;
ch_tp_pio = (struct ireg_buf *)scratch_buff.data;
/* TP_PIO*/
for (i = 0; i < n; i++) {
struct ireg_field *tp_pio = &ch_tp_pio->tp_pio;
u32 *buff = ch_tp_pio->outbuf;
if (is_t5(padap)) {
tp_pio->ireg_addr = t5_tp_pio_array[i][0];
tp_pio->ireg_data = t5_tp_pio_array[i][1];
tp_pio->ireg_local_offset = t5_tp_pio_array[i][2];
tp_pio->ireg_offset_range = t5_tp_pio_array[i][3];
} else if (is_t6(padap)) {
tp_pio->ireg_addr = t6_tp_pio_array[i][0];
tp_pio->ireg_data = t6_tp_pio_array[i][1];
tp_pio->ireg_local_offset = t6_tp_pio_array[i][2];
tp_pio->ireg_offset_range = t6_tp_pio_array[i][3];
}
t4_tp_pio_read(padap, buff, tp_pio->ireg_offset_range,
tp_pio->ireg_local_offset, true);
ch_tp_pio++;
}
/* TP_TM_PIO*/
if (is_t5(padap))
n = sizeof(t5_tp_tm_pio_array) / (4 * sizeof(u32));
else if (is_t6(padap))
n = sizeof(t6_tp_tm_pio_array) / (4 * sizeof(u32));
for (i = 0; i < n; i++) {
struct ireg_field *tp_pio = &ch_tp_pio->tp_pio;
u32 *buff = ch_tp_pio->outbuf;
if (is_t5(padap)) {
tp_pio->ireg_addr = t5_tp_tm_pio_array[i][0];
tp_pio->ireg_data = t5_tp_tm_pio_array[i][1];
tp_pio->ireg_local_offset = t5_tp_tm_pio_array[i][2];
tp_pio->ireg_offset_range = t5_tp_tm_pio_array[i][3];
} else if (is_t6(padap)) {
tp_pio->ireg_addr = t6_tp_tm_pio_array[i][0];
tp_pio->ireg_data = t6_tp_tm_pio_array[i][1];
tp_pio->ireg_local_offset = t6_tp_tm_pio_array[i][2];
tp_pio->ireg_offset_range = t6_tp_tm_pio_array[i][3];
}
t4_tp_tm_pio_read(padap, buff, tp_pio->ireg_offset_range,
tp_pio->ireg_local_offset, true);
ch_tp_pio++;
}
/* TP_MIB_INDEX*/
if (is_t5(padap))
n = sizeof(t5_tp_mib_index_array) / (4 * sizeof(u32));
else if (is_t6(padap))
n = sizeof(t6_tp_mib_index_array) / (4 * sizeof(u32));
for (i = 0; i < n ; i++) {
struct ireg_field *tp_pio = &ch_tp_pio->tp_pio;
u32 *buff = ch_tp_pio->outbuf;
if (is_t5(padap)) {
tp_pio->ireg_addr = t5_tp_mib_index_array[i][0];
tp_pio->ireg_data = t5_tp_mib_index_array[i][1];
tp_pio->ireg_local_offset =
t5_tp_mib_index_array[i][2];
tp_pio->ireg_offset_range =
t5_tp_mib_index_array[i][3];
} else if (is_t6(padap)) {
tp_pio->ireg_addr = t6_tp_mib_index_array[i][0];
tp_pio->ireg_data = t6_tp_mib_index_array[i][1];
tp_pio->ireg_local_offset =
t6_tp_mib_index_array[i][2];
tp_pio->ireg_offset_range =
t6_tp_mib_index_array[i][3];
}
t4_tp_mib_read(padap, buff, tp_pio->ireg_offset_range,
tp_pio->ireg_local_offset, true);
ch_tp_pio++;
}
rc = write_compression_hdr(&scratch_buff, dbg_buff);
if (rc)
goto err1;
rc = compress_buff(&scratch_buff, dbg_buff);
err1:
release_scratch_buff(&scratch_buff, dbg_buff);
err:
return rc;
}
static int collect_sge_indirect(struct cudbg_init *pdbg_init,
struct cudbg_buffer *dbg_buff,
struct cudbg_error *cudbg_err)
{
struct cudbg_buffer scratch_buff;
struct adapter *padap = pdbg_init->adap;
struct ireg_buf *ch_sge_dbg;
u32 size;
int i, rc;
size = sizeof(struct ireg_buf) * 2;
scratch_buff.size = size;
rc = get_scratch_buff(dbg_buff, scratch_buff.size, &scratch_buff);
if (rc)
goto err;
ch_sge_dbg = (struct ireg_buf *)scratch_buff.data;
for (i = 0; i < 2; i++) {
struct ireg_field *sge_pio = &ch_sge_dbg->tp_pio;
u32 *buff = ch_sge_dbg->outbuf;
sge_pio->ireg_addr = t5_sge_dbg_index_array[i][0];
sge_pio->ireg_data = t5_sge_dbg_index_array[i][1];
sge_pio->ireg_local_offset = t5_sge_dbg_index_array[i][2];
sge_pio->ireg_offset_range = t5_sge_dbg_index_array[i][3];
t4_read_indirect(padap,
sge_pio->ireg_addr,
sge_pio->ireg_data,
buff,
sge_pio->ireg_offset_range,
sge_pio->ireg_local_offset);
ch_sge_dbg++;
}
rc = write_compression_hdr(&scratch_buff, dbg_buff);
if (rc)
goto err1;
rc = compress_buff(&scratch_buff, dbg_buff);
err1:
release_scratch_buff(&scratch_buff, dbg_buff);
err:
return rc;
}
static int collect_full(struct cudbg_init *pdbg_init,
struct cudbg_buffer *dbg_buff,
struct cudbg_error *cudbg_err)
{
struct cudbg_buffer scratch_buff;
struct adapter *padap = pdbg_init->adap;
u32 reg_addr, reg_data, reg_local_offset, reg_offset_range;
u32 *sp;
int rc;
int nreg = 0;
/* Collect Registers:
* TP_DBG_SCHED_TX (0x7e40 + 0x6a),
* TP_DBG_SCHED_RX (0x7e40 + 0x6b),
* TP_DBG_CSIDE_INT (0x7e40 + 0x23f),
* TP_DBG_ESIDE_INT (0x7e40 + 0x148),
* PCIE_CDEBUG_INDEX[AppData0] (0x5a10 + 2),
* PCIE_CDEBUG_INDEX[AppData1] (0x5a10 + 3) This is for T6
* SGE_DEBUG_DATA_HIGH_INDEX_10 (0x12a8)
**/
if (is_t5(padap))
nreg = 6;
else if (is_t6(padap))
nreg = 7;
scratch_buff.size = nreg * sizeof(u32);
rc = get_scratch_buff(dbg_buff, scratch_buff.size, &scratch_buff);
if (rc)
goto err;
sp = (u32 *)scratch_buff.data;
/* TP_DBG_SCHED_TX */
reg_local_offset = t5_tp_pio_array[3][2] + 0xa;
reg_offset_range = 1;
t4_tp_pio_read(padap, sp, reg_offset_range, reg_local_offset, true);
sp++;
/* TP_DBG_SCHED_RX */
reg_local_offset = t5_tp_pio_array[3][2] + 0xb;
reg_offset_range = 1;
t4_tp_pio_read(padap, sp, reg_offset_range, reg_local_offset, true);
sp++;
/* TP_DBG_CSIDE_INT */
reg_local_offset = t5_tp_pio_array[9][2] + 0xf;
reg_offset_range = 1;
t4_tp_pio_read(padap, sp, reg_offset_range, reg_local_offset, true);
sp++;
/* TP_DBG_ESIDE_INT */
reg_local_offset = t5_tp_pio_array[8][2] + 3;
reg_offset_range = 1;
t4_tp_pio_read(padap, sp, reg_offset_range, reg_local_offset, true);
sp++;
/* PCIE_CDEBUG_INDEX[AppData0] */
reg_addr = t5_pcie_cdbg_array[0][0];
reg_data = t5_pcie_cdbg_array[0][1];
reg_local_offset = t5_pcie_cdbg_array[0][2] + 2;
reg_offset_range = 1;
t4_read_indirect(padap, reg_addr, reg_data, sp, reg_offset_range,
reg_local_offset);
sp++;
if (is_t6(padap)) {
/* PCIE_CDEBUG_INDEX[AppData1] */
reg_addr = t5_pcie_cdbg_array[0][0];
reg_data = t5_pcie_cdbg_array[0][1];
reg_local_offset = t5_pcie_cdbg_array[0][2] + 3;
reg_offset_range = 1;
t4_read_indirect(padap, reg_addr, reg_data, sp,
reg_offset_range, reg_local_offset);
sp++;
}
/* SGE_DEBUG_DATA_HIGH_INDEX_10 */
*sp = t4_read_reg(padap, A_SGE_DEBUG_DATA_HIGH_INDEX_10);
rc = write_compression_hdr(&scratch_buff, dbg_buff);
if (rc)
goto err1;
rc = compress_buff(&scratch_buff, dbg_buff);
err1:
release_scratch_buff(&scratch_buff, dbg_buff);
err:
return rc;
}
static int collect_vpd_data(struct cudbg_init *pdbg_init,
struct cudbg_buffer *dbg_buff,
struct cudbg_error *cudbg_err)
{
#ifdef notyet
struct cudbg_buffer scratch_buff;
struct adapter *padap = pdbg_init->adap;
struct struct_vpd_data *vpd_data;
char vpd_ver[4];
u32 fw_vers;
u32 size;
int rc;
size = sizeof(struct struct_vpd_data);
scratch_buff.size = size;
rc = get_scratch_buff(dbg_buff, scratch_buff.size, &scratch_buff);
if (rc)
goto err;
vpd_data = (struct struct_vpd_data *)scratch_buff.data;
if (is_t5(padap)) {
read_vpd_reg(padap, SN_REG_ADDR, SN_MAX_LEN, vpd_data->sn);
read_vpd_reg(padap, BN_REG_ADDR, BN_MAX_LEN, vpd_data->bn);
read_vpd_reg(padap, NA_REG_ADDR, NA_MAX_LEN, vpd_data->na);
read_vpd_reg(padap, MN_REG_ADDR, MN_MAX_LEN, vpd_data->mn);
} else if (is_t6(padap)) {
read_vpd_reg(padap, SN_T6_ADDR, SN_MAX_LEN, vpd_data->sn);
read_vpd_reg(padap, BN_T6_ADDR, BN_MAX_LEN, vpd_data->bn);
read_vpd_reg(padap, NA_T6_ADDR, NA_MAX_LEN, vpd_data->na);
read_vpd_reg(padap, MN_T6_ADDR, MN_MAX_LEN, vpd_data->mn);
}
if (is_fw_attached(pdbg_init)) {
rc = t4_get_scfg_version(padap, &vpd_data->scfg_vers);
} else {
rc = 1;
}
if (rc) {
/* Now trying with backdoor mechanism */
rc = read_vpd_reg(padap, SCFG_VER_ADDR, SCFG_VER_LEN,
(u8 *)&vpd_data->scfg_vers);
if (rc)
goto err1;
}
if (is_fw_attached(pdbg_init)) {
rc = t4_get_vpd_version(padap, &vpd_data->vpd_vers);
} else {
rc = 1;
}
if (rc) {
/* Now trying with backdoor mechanism */
rc = read_vpd_reg(padap, VPD_VER_ADDR, VPD_VER_LEN,
(u8 *)vpd_ver);
if (rc)
goto err1;
/* read_vpd_reg return string of stored hex
* converting hex string to char string
* vpd version is 2 bytes only */
sprintf(vpd_ver, "%c%c\n", vpd_ver[0], vpd_ver[1]);
vpd_data->vpd_vers = simple_strtoul(vpd_ver, NULL, 16);
}
/* Get FW version if it's not already filled in */
fw_vers = padap->params.fw_vers;
if (!fw_vers) {
rc = t4_get_fw_version(padap, &fw_vers);
if (rc)
goto err1;
}
vpd_data->fw_major = G_FW_HDR_FW_VER_MAJOR(fw_vers);
vpd_data->fw_minor = G_FW_HDR_FW_VER_MINOR(fw_vers);
vpd_data->fw_micro = G_FW_HDR_FW_VER_MICRO(fw_vers);
vpd_data->fw_build = G_FW_HDR_FW_VER_BUILD(fw_vers);
rc = write_compression_hdr(&scratch_buff, dbg_buff);
if (rc)
goto err1;
rc = compress_buff(&scratch_buff, dbg_buff);
err1:
release_scratch_buff(&scratch_buff, dbg_buff);
err:
return rc;
#endif
return (EDOOFUS);
}