#include <linux/module.h>
#include <linux/vmalloc.h>
#include <linux/crc32.h>
#include "qed.h"
#include "qed_cxt.h"
#include "qed_hsi.h"
#include "qed_dbg_hsi.h"
#include "qed_hw.h"
#include "qed_mcp.h"
#include "qed_reg_addr.h"
enum mem_groups {
MEM_GROUP_PXP_MEM,
MEM_GROUP_DMAE_MEM,
MEM_GROUP_CM_MEM,
MEM_GROUP_QM_MEM,
MEM_GROUP_DORQ_MEM,
MEM_GROUP_BRB_RAM,
MEM_GROUP_BRB_MEM,
MEM_GROUP_PRS_MEM,
MEM_GROUP_SDM_MEM,
MEM_GROUP_PBUF,
MEM_GROUP_IOR,
MEM_GROUP_RAM,
MEM_GROUP_BTB_RAM,
MEM_GROUP_RDIF_CTX,
MEM_GROUP_TDIF_CTX,
MEM_GROUP_CFC_MEM,
MEM_GROUP_CONN_CFC_MEM,
MEM_GROUP_CAU_PI,
MEM_GROUP_CAU_MEM,
MEM_GROUP_CAU_MEM_EXT,
MEM_GROUP_PXP_ILT,
MEM_GROUP_MULD_MEM,
MEM_GROUP_BTB_MEM,
MEM_GROUP_IGU_MEM,
MEM_GROUP_IGU_MSIX,
MEM_GROUP_CAU_SB,
MEM_GROUP_BMB_RAM,
MEM_GROUP_BMB_MEM,
MEM_GROUP_TM_MEM,
MEM_GROUP_TASK_CFC_MEM,
MEM_GROUPS_NUM
};
static const char * const s_mem_group_names[] = {
"PXP_MEM",
"DMAE_MEM",
"CM_MEM",
"QM_MEM",
"DORQ_MEM",
"BRB_RAM",
"BRB_MEM",
"PRS_MEM",
"SDM_MEM",
"PBUF",
"IOR",
"RAM",
"BTB_RAM",
"RDIF_CTX",
"TDIF_CTX",
"CFC_MEM",
"CONN_CFC_MEM",
"CAU_PI",
"CAU_MEM",
"CAU_MEM_EXT",
"PXP_ILT",
"MULD_MEM",
"BTB_MEM",
"IGU_MEM",
"IGU_MSIX",
"CAU_SB",
"BMB_RAM",
"BMB_MEM",
"TM_MEM",
"TASK_CFC_MEM",
};
static u32 cond5(const u32 *r, const u32 *imm)
{
return ((r[0] & imm[0]) != imm[1]) && ((r[1] & imm[2]) != imm[3]);
}
static u32 cond7(const u32 *r, const u32 *imm)
{
return ((r[0] >> imm[0]) & imm[1]) != imm[2];
}
static u32 cond6(const u32 *r, const u32 *imm)
{
return (r[0] & imm[0]) != imm[1];
}
static u32 cond9(const u32 *r, const u32 *imm)
{
return ((r[0] & imm[0]) >> imm[1]) !=
(((r[0] & imm[2]) >> imm[3]) | ((r[1] & imm[4]) << imm[5]));
}
static u32 cond10(const u32 *r, const u32 *imm)
{
return ((r[0] & imm[0]) >> imm[1]) != (r[0] & imm[2]);
}
static u32 cond4(const u32 *r, const u32 *imm)
{
return (r[0] & ~imm[0]) != imm[1];
}
static u32 cond0(const u32 *r, const u32 *imm)
{
return (r[0] & ~r[1]) != imm[0];
}
static u32 cond14(const u32 *r, const u32 *imm)
{
return (r[0] | imm[0]) != imm[1];
}
static u32 cond1(const u32 *r, const u32 *imm)
{
return r[0] != imm[0];
}
static u32 cond11(const u32 *r, const u32 *imm)
{
return r[0] != r[1] && r[2] == imm[0];
}
static u32 cond12(const u32 *r, const u32 *imm)
{
return r[0] != r[1] && r[2] > imm[0];
}
static u32 cond3(const u32 *r, const u32 *imm)
{
return r[0] != r[1];
}
static u32 cond13(const u32 *r, const u32 *imm)
{
return r[0] & imm[0];
}
static u32 cond8(const u32 *r, const u32 *imm)
{
return r[0] < (r[1] - imm[0]);
}
static u32 cond2(const u32 *r, const u32 *imm)
{
return r[0] > imm[0];
}
static u32(*cond_arr[]) (const u32 *r, const u32 *imm) = {
cond0,
cond1,
cond2,
cond3,
cond4,
cond5,
cond6,
cond7,
cond8,
cond9,
cond10,
cond11,
cond12,
cond13,
cond14,
};
#define NUM_PHYS_BLOCKS 84
#define NUM_DBG_RESET_REGS 8
enum hw_types {
HW_TYPE_ASIC,
PLATFORM_RESERVED,
PLATFORM_RESERVED2,
PLATFORM_RESERVED3,
PLATFORM_RESERVED4,
MAX_HW_TYPES
};
enum cm_ctx_types {
CM_CTX_CONN_AG,
CM_CTX_CONN_ST,
CM_CTX_TASK_AG,
CM_CTX_TASK_ST,
NUM_CM_CTX_TYPES
};
enum dbg_bus_frame_modes {
DBG_BUS_FRAME_MODE_4ST = 0,
DBG_BUS_FRAME_MODE_2ST_2HW = 1,
DBG_BUS_FRAME_MODE_1ST_3HW = 2,
DBG_BUS_FRAME_MODE_4HW = 3,
DBG_BUS_FRAME_MODE_8HW = 4,
DBG_BUS_NUM_FRAME_MODES
};
enum dbg_bus_semi_frame_modes {
DBG_BUS_SEMI_FRAME_MODE_4FAST = 0,
DBG_BUS_SEMI_FRAME_MODE_2FAST_2SLOW = 1,
DBG_BUS_SEMI_FRAME_MODE_1FAST_3SLOW = 2,
DBG_BUS_SEMI_FRAME_MODE_4SLOW = 3,
DBG_BUS_SEMI_NUM_FRAME_MODES
};
enum dbg_bus_filter_types {
DBG_BUS_FILTER_TYPE_OFF,
DBG_BUS_FILTER_TYPE_PRE,
DBG_BUS_FILTER_TYPE_POST,
DBG_BUS_FILTER_TYPE_ON
};
enum dbg_bus_pre_trigger_types {
DBG_BUS_PRE_TRIGGER_FROM_ZERO,
DBG_BUS_PRE_TRIGGER_NUM_CHUNKS,
DBG_BUS_PRE_TRIGGER_DROP
};
enum dbg_bus_post_trigger_types {
DBG_BUS_POST_TRIGGER_RECORD,
DBG_BUS_POST_TRIGGER_DROP
};
enum dbg_bus_other_engine_modes {
DBG_BUS_OTHER_ENGINE_MODE_NONE,
DBG_BUS_OTHER_ENGINE_MODE_DOUBLE_BW_TX,
DBG_BUS_OTHER_ENGINE_MODE_DOUBLE_BW_RX,
DBG_BUS_OTHER_ENGINE_MODE_CROSS_ENGINE_TX,
DBG_BUS_OTHER_ENGINE_MODE_CROSS_ENGINE_RX
};
struct framing_mode_defs {
u8 id;
u8 blocks_dword_mask;
u8 storms_dword_mask;
u8 semi_framing_mode_id;
u8 full_buf_thr;
};
struct chip_defs {
const char *name;
u8 dwords_per_cycle;
u8 num_framing_modes;
u32 num_ilt_pages;
struct framing_mode_defs *framing_modes;
};
struct hw_type_defs {
const char *name;
u32 delay_factor;
u32 dmae_thresh;
u32 log_thresh;
};
struct rbc_reset_defs {
u32 reset_reg_addr;
u32 reset_val[MAX_CHIP_IDS];
};
struct storm_defs {
char letter;
enum block_id sem_block_id;
enum dbg_bus_clients dbg_client_id[MAX_CHIP_IDS];
bool has_vfc;
u32 sem_fast_mem_addr;
u32 sem_frame_mode_addr;
u32 sem_slow_enable_addr;
u32 sem_slow_mode_addr;
u32 sem_slow_mode1_conf_addr;
u32 sem_sync_dbg_empty_addr;
u32 sem_gpre_vect_addr;
u32 cm_ctx_wr_addr;
u32 cm_ctx_rd_addr[NUM_CM_CTX_TYPES];
u32 cm_ctx_lid_sizes[MAX_CHIP_IDS][NUM_CM_CTX_TYPES];
};
struct dbg_bus_constraint_op_defs {
u8 hw_op_val;
bool is_cyclic;
};
struct storm_mode_defs {
const char *name;
bool is_fast_dbg;
u8 id_in_hw;
u32 src_disable_reg_addr;
u32 src_enable_val;
bool exists[MAX_CHIP_IDS];
};
struct grc_param_defs {
u32 default_val[MAX_CHIP_IDS];
u32 min;
u32 max;
bool is_preset;
bool is_persistent;
u32 exclude_all_preset_val;
u32 crash_preset_val[MAX_CHIP_IDS];
};
struct rss_mem_defs {
const char *mem_name;
const char *type_name;
u32 addr;
u32 entry_width;
u32 num_entries[MAX_CHIP_IDS];
};
struct vfc_ram_defs {
const char *mem_name;
const char *type_name;
u32 base_row;
u32 num_rows;
};
struct big_ram_defs {
const char *instance_name;
enum mem_groups mem_group_id;
enum mem_groups ram_mem_group_id;
enum dbg_grc_params grc_param;
u32 addr_reg_addr;
u32 data_reg_addr;
u32 is_256b_reg_addr;
u32 is_256b_bit_offset[MAX_CHIP_IDS];
u32 ram_size[MAX_CHIP_IDS];
};
struct phy_defs {
const char *phy_name;
u32 base_addr;
u32 tbus_addr_lo_addr;
u32 tbus_addr_hi_addr;
u32 tbus_data_lo_addr;
u32 tbus_data_hi_addr;
};
struct split_type_defs {
const char *name;
};
#define BYTES_IN_DWORD sizeof(u32)
#define CEIL_DWORDS(size) DIV_ROUND_UP(size, 32)
#define FIELD_BIT_OFFSET(type, field) type ## _ ## field ## _ ## OFFSET
#define FIELD_BIT_SIZE(type, field) type ## _ ## field ## _ ## SIZE
#define FIELD_DWORD_OFFSET(type, field) \
((int)(FIELD_BIT_OFFSET(type, field) / 32))
#define FIELD_DWORD_SHIFT(type, field) (FIELD_BIT_OFFSET(type, field) % 32)
#define FIELD_BIT_MASK(type, field) \
(((1 << FIELD_BIT_SIZE(type, field)) - 1) << \
FIELD_DWORD_SHIFT(type, field))
#define SET_VAR_FIELD(var, type, field, val) \
do { \
var[FIELD_DWORD_OFFSET(type, field)] &= \
(~FIELD_BIT_MASK(type, field)); \
var[FIELD_DWORD_OFFSET(type, field)] |= \
(val) << FIELD_DWORD_SHIFT(type, field); \
} while (0)
#define ARR_REG_WR(dev, ptt, addr, arr, arr_size) \
do { \
for (i = 0; i < (arr_size); i++) \
qed_wr(dev, ptt, addr, (arr)[i]); \
} while (0)
#define DWORDS_TO_BYTES(dwords) ((dwords) * BYTES_IN_DWORD)
#define BYTES_TO_DWORDS(bytes) ((bytes) / BYTES_IN_DWORD)
#define NUM_EXTRA_DBG_LINES(block) \
(GET_FIELD((block)->flags, DBG_BLOCK_CHIP_HAS_LATENCY_EVENTS) ? 2 : 1)
#define NUM_DBG_LINES(block) \
((block)->num_of_dbg_bus_lines + NUM_EXTRA_DBG_LINES(block))
#define USE_DMAE true
#define PROTECT_WIDE_BUS true
#define RAM_LINES_TO_DWORDS(lines) ((lines) * 2)
#define RAM_LINES_TO_BYTES(lines) \
DWORDS_TO_BYTES(RAM_LINES_TO_DWORDS(lines))
#define REG_DUMP_LEN_SHIFT 24
#define MEM_DUMP_ENTRY_SIZE_DWORDS \
BYTES_TO_DWORDS(sizeof(struct dbg_dump_mem))
#define IDLE_CHK_RULE_SIZE_DWORDS \
BYTES_TO_DWORDS(sizeof(struct dbg_idle_chk_rule))
#define IDLE_CHK_RESULT_HDR_DWORDS \
BYTES_TO_DWORDS(sizeof(struct dbg_idle_chk_result_hdr))
#define IDLE_CHK_RESULT_REG_HDR_DWORDS \
BYTES_TO_DWORDS(sizeof(struct dbg_idle_chk_result_reg_hdr))
#define PAGE_MEM_DESC_SIZE_DWORDS \
BYTES_TO_DWORDS(sizeof(struct phys_mem_desc))
#define IDLE_CHK_MAX_ENTRIES_SIZE 32
#define VFC_CAM_CMD_STRUCT_SIZE 64
#define VFC_CAM_CMD_ROW_OFFSET 48
#define VFC_CAM_CMD_ROW_SIZE 9
#define VFC_CAM_ADDR_STRUCT_SIZE 16
#define VFC_CAM_ADDR_OP_OFFSET 0
#define VFC_CAM_ADDR_OP_SIZE 4
#define VFC_CAM_RESP_STRUCT_SIZE 256
#define VFC_RAM_ADDR_STRUCT_SIZE 16
#define VFC_RAM_ADDR_OP_OFFSET 0
#define VFC_RAM_ADDR_OP_SIZE 2
#define VFC_RAM_ADDR_ROW_OFFSET 2
#define VFC_RAM_ADDR_ROW_SIZE 10
#define VFC_RAM_RESP_STRUCT_SIZE 256
#define VFC_CAM_CMD_DWORDS CEIL_DWORDS(VFC_CAM_CMD_STRUCT_SIZE)
#define VFC_CAM_ADDR_DWORDS CEIL_DWORDS(VFC_CAM_ADDR_STRUCT_SIZE)
#define VFC_CAM_RESP_DWORDS CEIL_DWORDS(VFC_CAM_RESP_STRUCT_SIZE)
#define VFC_RAM_CMD_DWORDS VFC_CAM_CMD_DWORDS
#define VFC_RAM_ADDR_DWORDS CEIL_DWORDS(VFC_RAM_ADDR_STRUCT_SIZE)
#define VFC_RAM_RESP_DWORDS CEIL_DWORDS(VFC_RAM_RESP_STRUCT_SIZE)
#define NUM_VFC_RAM_TYPES 4
#define VFC_CAM_NUM_ROWS 512
#define VFC_OPCODE_CAM_RD 14
#define VFC_OPCODE_RAM_RD 0
#define NUM_RSS_MEM_TYPES 5
#define NUM_BIG_RAM_TYPES 3
#define BIG_RAM_NAME_LEN 3
#define NUM_PHY_TBUS_ADDRESSES 2048
#define PHY_DUMP_SIZE_DWORDS (NUM_PHY_TBUS_ADDRESSES / 2)
#define RESET_REG_UNRESET_OFFSET 4
#define STALL_DELAY_MS 500
#define STATIC_DEBUG_LINE_DWORDS 9
#define NUM_COMMON_GLOBAL_PARAMS 10
#define MAX_RECURSION_DEPTH 10
#define FW_IMG_KUKU 0
#define FW_IMG_MAIN 1
#define FW_IMG_L2B 2
#define REG_FIFO_ELEMENT_DWORDS 2
#define REG_FIFO_DEPTH_ELEMENTS 32
#define REG_FIFO_DEPTH_DWORDS \
(REG_FIFO_ELEMENT_DWORDS * REG_FIFO_DEPTH_ELEMENTS)
#define IGU_FIFO_ELEMENT_DWORDS 4
#define IGU_FIFO_DEPTH_ELEMENTS 64
#define IGU_FIFO_DEPTH_DWORDS \
(IGU_FIFO_ELEMENT_DWORDS * IGU_FIFO_DEPTH_ELEMENTS)
#define PROTECTION_OVERRIDE_ELEMENT_DWORDS 2
#define PROTECTION_OVERRIDE_DEPTH_ELEMENTS 20
#define PROTECTION_OVERRIDE_DEPTH_DWORDS \
(PROTECTION_OVERRIDE_DEPTH_ELEMENTS * \
PROTECTION_OVERRIDE_ELEMENT_DWORDS)
#define MCP_SPAD_TRACE_OFFSIZE_ADDR \
(MCP_REG_SCRATCH + \
offsetof(struct static_init, sections[SPAD_SECTION_TRACE]))
#define MAX_SW_PLTAFORM_STR_SIZE 64
#define EMPTY_FW_VERSION_STR "???_???_???_???"
#define EMPTY_FW_IMAGE_STR "???????????????"
static struct framing_mode_defs s_framing_mode_defs[4] = {
{DBG_BUS_FRAME_MODE_4ST, 0x0, 0xf,
DBG_BUS_SEMI_FRAME_MODE_4FAST,
10},
{DBG_BUS_FRAME_MODE_4HW, 0xf, 0x0, DBG_BUS_SEMI_FRAME_MODE_4SLOW,
10},
{DBG_BUS_FRAME_MODE_2ST_2HW, 0x3, 0xc,
DBG_BUS_SEMI_FRAME_MODE_2FAST_2SLOW, 10},
{DBG_BUS_FRAME_MODE_1ST_3HW, 0x7, 0x8,
DBG_BUS_SEMI_FRAME_MODE_1FAST_3SLOW, 10}
};
static struct chip_defs s_chip_defs[MAX_CHIP_IDS] = {
{"bb", 4, DBG_BUS_NUM_FRAME_MODES, PSWRQ2_REG_ILT_MEMORY_SIZE_BB / 2,
s_framing_mode_defs},
{"ah", 4, DBG_BUS_NUM_FRAME_MODES, PSWRQ2_REG_ILT_MEMORY_SIZE_K2 / 2,
s_framing_mode_defs}
};
static struct storm_defs s_storm_defs[] = {
{'T', BLOCK_TSEM,
{DBG_BUS_CLIENT_RBCT, DBG_BUS_CLIENT_RBCT},
true,
TSEM_REG_FAST_MEMORY,
TSEM_REG_DBG_FRAME_MODE, TSEM_REG_SLOW_DBG_ACTIVE,
TSEM_REG_SLOW_DBG_MODE, TSEM_REG_DBG_MODE1_CFG,
TSEM_REG_SYNC_DBG_EMPTY, TSEM_REG_DBG_GPRE_VECT,
TCM_REG_CTX_RBC_ACCS,
{TCM_REG_AGG_CON_CTX, TCM_REG_SM_CON_CTX, TCM_REG_AGG_TASK_CTX,
TCM_REG_SM_TASK_CTX},
{{4, 16, 2, 4}, {4, 16, 2, 4}}
},
{'M', BLOCK_MSEM,
{DBG_BUS_CLIENT_RBCT, DBG_BUS_CLIENT_RBCM},
false,
MSEM_REG_FAST_MEMORY,
MSEM_REG_DBG_FRAME_MODE,
MSEM_REG_SLOW_DBG_ACTIVE,
MSEM_REG_SLOW_DBG_MODE,
MSEM_REG_DBG_MODE1_CFG,
MSEM_REG_SYNC_DBG_EMPTY,
MSEM_REG_DBG_GPRE_VECT,
MCM_REG_CTX_RBC_ACCS,
{MCM_REG_AGG_CON_CTX, MCM_REG_SM_CON_CTX, MCM_REG_AGG_TASK_CTX,
MCM_REG_SM_TASK_CTX },
{{1, 10, 2, 7}, {1, 10, 2, 7}}
},
{'U', BLOCK_USEM,
{DBG_BUS_CLIENT_RBCU, DBG_BUS_CLIENT_RBCU},
false,
USEM_REG_FAST_MEMORY,
USEM_REG_DBG_FRAME_MODE,
USEM_REG_SLOW_DBG_ACTIVE,
USEM_REG_SLOW_DBG_MODE,
USEM_REG_DBG_MODE1_CFG,
USEM_REG_SYNC_DBG_EMPTY,
USEM_REG_DBG_GPRE_VECT,
UCM_REG_CTX_RBC_ACCS,
{UCM_REG_AGG_CON_CTX, UCM_REG_SM_CON_CTX, UCM_REG_AGG_TASK_CTX,
UCM_REG_SM_TASK_CTX},
{{2, 13, 3, 3}, {2, 13, 3, 3}}
},
{'X', BLOCK_XSEM,
{DBG_BUS_CLIENT_RBCX, DBG_BUS_CLIENT_RBCX},
false,
XSEM_REG_FAST_MEMORY,
XSEM_REG_DBG_FRAME_MODE,
XSEM_REG_SLOW_DBG_ACTIVE,
XSEM_REG_SLOW_DBG_MODE,
XSEM_REG_DBG_MODE1_CFG,
XSEM_REG_SYNC_DBG_EMPTY,
XSEM_REG_DBG_GPRE_VECT,
XCM_REG_CTX_RBC_ACCS,
{XCM_REG_AGG_CON_CTX, XCM_REG_SM_CON_CTX, 0, 0},
{{9, 15, 0, 0}, {9, 15, 0, 0}}
},
{'Y', BLOCK_YSEM,
{DBG_BUS_CLIENT_RBCX, DBG_BUS_CLIENT_RBCY},
false,
YSEM_REG_FAST_MEMORY,
YSEM_REG_DBG_FRAME_MODE,
YSEM_REG_SLOW_DBG_ACTIVE,
YSEM_REG_SLOW_DBG_MODE,
YSEM_REG_DBG_MODE1_CFG,
YSEM_REG_SYNC_DBG_EMPTY,
YSEM_REG_DBG_GPRE_VECT,
YCM_REG_CTX_RBC_ACCS,
{YCM_REG_AGG_CON_CTX, YCM_REG_SM_CON_CTX, YCM_REG_AGG_TASK_CTX,
YCM_REG_SM_TASK_CTX},
{{2, 3, 2, 12}, {2, 3, 2, 12}}
},
{'P', BLOCK_PSEM,
{DBG_BUS_CLIENT_RBCS, DBG_BUS_CLIENT_RBCS},
true,
PSEM_REG_FAST_MEMORY,
PSEM_REG_DBG_FRAME_MODE,
PSEM_REG_SLOW_DBG_ACTIVE,
PSEM_REG_SLOW_DBG_MODE,
PSEM_REG_DBG_MODE1_CFG,
PSEM_REG_SYNC_DBG_EMPTY,
PSEM_REG_DBG_GPRE_VECT,
PCM_REG_CTX_RBC_ACCS,
{0, PCM_REG_SM_CON_CTX, 0, 0},
{{0, 10, 0, 0}, {0, 10, 0, 0}}
},
};
static struct hw_type_defs s_hw_type_defs[] = {
{"asic", 1, 256, 32768},
{"reserved", 0, 0, 0},
{"reserved2", 0, 0, 0},
{"reserved3", 0, 0, 0},
{"reserved4", 0, 0, 0}
};
static struct grc_param_defs s_grc_param_defs[] = {
{{1, 1}, 0, 1, false, false, 1, {1, 1}},
{{1, 1}, 0, 1, false, false, 1, {1, 1}},
{{1, 1}, 0, 1, false, false, 1, {1, 1}},
{{1, 1}, 0, 1, false, false, 1, {1, 1}},
{{1, 1}, 0, 1, false, false, 1, {1, 1}},
{{1, 1}, 0, 1, false, false, 1, {1, 1}},
{{1, 1}, 0, 1, false, false, 0, {1, 1}},
{{1, 1}, 0, 1, false, false, 0, {1, 1}},
{{1, 1}, 0, 1, false, false, 0, {1, 1}},
{{0, 0}, 0, 1, false, false, 0, {1, 1}},
{{0, 0}, 0, 1, false, false, 0, {1, 1}},
{{1, 1}, 0, 1, false, false, 0, {1, 1}},
{{1, 1}, 0, 1, false, false, 0, {1, 1}},
{{1, 1}, 0, 1, false, false, 0, {1, 1}},
{{1, 1}, 0, 1, false, false, 0, {1, 1}},
{{1, 1}, 0, 1, false, false, 0, {1, 1}},
{{1, 1}, 0, 1, false, false, 0, {1, 1}},
{{1, 1}, 0, 1, false, false, 0, {1, 1}},
{{1, 1}, 0, 1, false, false, 0, {1, 1}},
{{1, 1}, 0, 1, false, false, 0, {1, 1}},
{{0, 0}, 0, 1, false, false, 0, {1, 1}},
{{0, 0}, 0, 1, false, false, 0, {1, 1}},
{{0, 0}, 0, 1, false, false, 0, {0, 0}},
{{0, 0}, 0, 1, false, false, 0, {0, 0}},
{{1, 1}, 0, 1, false, false, 0, {1, 1}},
{{1, 1}, 0, 1, false, false, 0, {1, 1}},
{{1, 1}, 0, 1, false, false, 0, {1, 1}},
{{1, 1}, 0, 1, false, false, 0, {1, 1}},
{{1, 1}, 0, 1, false, false, 0, {1, 1}},
{{1, 1}, 0, 1, false, false, 0, {1, 1}},
{{1, 1}, 0, 1, false, false, 0, {1, 1}},
{{0, 0}, 0, 1, false, false, 0, {0, 0}},
{{0, 0}, 0, 1, false, false, 0, {0, 0}},
{{0, 0}, 1, 0xffffffff, false, true, 0, {0, 0}},
{{0, 0}, 0, 1, true, false, 0, {0, 0}},
{{0, 0}, 0, 1, true, false, 0, {0, 0}},
{{0, 0}, 0, 1, false, false, 0, {0, 0}},
{{1, 1}, 0, 1, false, false, 0, {1, 1}},
{{0, 0}, 0, 1, false, false, 0, {0, 0}},
{{0, 0}, 0, 1, false, false, 0, {0, 0}},
{{0, 0}, 0, 1, false, false, 0, {0, 0}},
{{0, 0}, 0, 1, false, false, 0, {0, 0}},
{{0, 1}, 0, 1, false, false, 0, {0, 1}},
{{1, 1}, 0, 1, false, false, 0, {0, 0}},
{{1, 1}, 0, 1, false, false, 0, {0, 0}},
{{0, 0}, 0, 1, false, false, 0, {1, 1}}
};
static struct rss_mem_defs s_rss_mem_defs[] = {
{"rss_mem_cid", "rss_cid", 0, 32,
{256, 320}},
{"rss_mem_key_msb", "rss_key", 1024, 256,
{128, 208}},
{"rss_mem_key_lsb", "rss_key", 2048, 64,
{128, 208}},
{"rss_mem_info", "rss_info", 3072, 16,
{128, 208}},
{"rss_mem_ind", "rss_ind", 4096, 16,
{16384, 26624}}
};
static struct vfc_ram_defs s_vfc_ram_defs[] = {
{"vfc_ram_tt1", "vfc_ram", 0, 512},
{"vfc_ram_mtt2", "vfc_ram", 512, 128},
{"vfc_ram_stt2", "vfc_ram", 640, 32},
{"vfc_ram_ro_vect", "vfc_ram", 672, 32}
};
static struct big_ram_defs s_big_ram_defs[] = {
{"BRB", MEM_GROUP_BRB_MEM, MEM_GROUP_BRB_RAM, DBG_GRC_PARAM_DUMP_BRB,
BRB_REG_BIG_RAM_ADDRESS, BRB_REG_BIG_RAM_DATA,
MISC_REG_BLOCK_256B_EN, {0, 0},
{153600, 180224}},
{"BTB", MEM_GROUP_BTB_MEM, MEM_GROUP_BTB_RAM, DBG_GRC_PARAM_DUMP_BTB,
BTB_REG_BIG_RAM_ADDRESS, BTB_REG_BIG_RAM_DATA,
MISC_REG_BLOCK_256B_EN, {0, 1},
{92160, 117760}},
{"BMB", MEM_GROUP_BMB_MEM, MEM_GROUP_BMB_RAM, DBG_GRC_PARAM_DUMP_BMB,
BMB_REG_BIG_RAM_ADDRESS, BMB_REG_BIG_RAM_DATA,
MISCS_REG_BLOCK_256B_EN, {0, 0},
{36864, 36864}}
};
static struct rbc_reset_defs s_rbc_reset_defs[] = {
{MISCS_REG_RESET_PL_HV,
{0x0, 0x400}},
{MISC_REG_RESET_PL_PDA_VMAIN_1,
{0x4404040, 0x4404040}},
{MISC_REG_RESET_PL_PDA_VMAIN_2,
{0x7, 0x7c00007}},
{MISC_REG_RESET_PL_PDA_VAUX,
{0x2, 0x2}},
};
static struct phy_defs s_phy_defs[] = {
{"nw_phy", NWS_REG_NWS_CMU_K2,
PHY_NW_IP_REG_PHY0_TOP_TBUS_ADDR_7_0_K2,
PHY_NW_IP_REG_PHY0_TOP_TBUS_ADDR_15_8_K2,
PHY_NW_IP_REG_PHY0_TOP_TBUS_DATA_7_0_K2,
PHY_NW_IP_REG_PHY0_TOP_TBUS_DATA_11_8_K2},
{"sgmii_phy", MS_REG_MS_CMU_K2,
PHY_SGMII_IP_REG_AHB_CMU_CSR_0_X132_K2,
PHY_SGMII_IP_REG_AHB_CMU_CSR_0_X133_K2,
PHY_SGMII_IP_REG_AHB_CMU_CSR_0_X130_K2,
PHY_SGMII_IP_REG_AHB_CMU_CSR_0_X131_K2},
{"pcie_phy0", PHY_PCIE_REG_PHY0_K2,
PHY_PCIE_IP_REG_AHB_CMU_CSR_0_X132_K2,
PHY_PCIE_IP_REG_AHB_CMU_CSR_0_X133_K2,
PHY_PCIE_IP_REG_AHB_CMU_CSR_0_X130_K2,
PHY_PCIE_IP_REG_AHB_CMU_CSR_0_X131_K2},
{"pcie_phy1", PHY_PCIE_REG_PHY1_K2,
PHY_PCIE_IP_REG_AHB_CMU_CSR_0_X132_K2,
PHY_PCIE_IP_REG_AHB_CMU_CSR_0_X133_K2,
PHY_PCIE_IP_REG_AHB_CMU_CSR_0_X130_K2,
PHY_PCIE_IP_REG_AHB_CMU_CSR_0_X131_K2},
};
static struct split_type_defs s_split_type_defs[] = {
{"eng"},
{"port"},
{"pf"},
{"port"},
{"vf"}
};
static u32 s_app_ver;
static void qed_static_asserts(void)
{
}
static u32 qed_read_unaligned_dword(u8 *buf)
{
u32 dword;
memcpy((u8 *)&dword, buf, sizeof(dword));
return dword;
}
static void qed_grc_set_param(struct qed_hwfn *p_hwfn,
enum dbg_grc_params grc_param, u32 val)
{
struct dbg_tools_data *dev_data = &p_hwfn->dbg_info;
dev_data->grc.param_val[grc_param] = val;
}
static u32 qed_grc_get_param(struct qed_hwfn *p_hwfn,
enum dbg_grc_params grc_param)
{
struct dbg_tools_data *dev_data = &p_hwfn->dbg_info;
return dev_data->grc.param_val[grc_param];
}
static void qed_dbg_grc_init_params(struct qed_hwfn *p_hwfn)
{
struct dbg_tools_data *dev_data = &p_hwfn->dbg_info;
if (!dev_data->grc.params_initialized) {
qed_dbg_grc_set_params_default(p_hwfn);
dev_data->grc.params_initialized = 1;
}
}
static void qed_set_dbg_bin_buf(struct qed_hwfn *p_hwfn,
enum bin_dbg_buffer_type buf_type,
const u32 *ptr, u32 size)
{
struct virt_mem_desc *buf = &p_hwfn->dbg_arrays[buf_type];
buf->ptr = (void *)ptr;
buf->size = size;
}
static enum dbg_status qed_dbg_dev_init(struct qed_hwfn *p_hwfn)
{
struct dbg_tools_data *dev_data = &p_hwfn->dbg_info;
u8 num_pfs = 0, max_pfs_per_port = 0;
if (dev_data->initialized)
return DBG_STATUS_OK;
if (!s_app_ver)
return DBG_STATUS_APP_VERSION_NOT_SET;
if (QED_IS_K2(p_hwfn->cdev)) {
dev_data->chip_id = CHIP_K2;
dev_data->mode_enable[MODE_K2] = 1;
dev_data->num_vfs = MAX_NUM_VFS_K2;
num_pfs = MAX_NUM_PFS_K2;
max_pfs_per_port = MAX_NUM_PFS_K2 / 2;
} else if (QED_IS_BB_B0(p_hwfn->cdev)) {
dev_data->chip_id = CHIP_BB;
dev_data->mode_enable[MODE_BB] = 1;
dev_data->num_vfs = MAX_NUM_VFS_BB;
num_pfs = MAX_NUM_PFS_BB;
max_pfs_per_port = MAX_NUM_PFS_BB;
} else {
return DBG_STATUS_UNKNOWN_CHIP;
}
dev_data->hw_type = HW_TYPE_ASIC;
dev_data->mode_enable[MODE_ASIC] = 1;
switch (p_hwfn->cdev->num_ports_in_engine) {
case 1:
dev_data->mode_enable[MODE_PORTS_PER_ENG_1] = 1;
break;
case 2:
dev_data->mode_enable[MODE_PORTS_PER_ENG_2] = 1;
break;
case 4:
dev_data->mode_enable[MODE_PORTS_PER_ENG_4] = 1;
break;
}
if (QED_IS_CMT(p_hwfn->cdev))
dev_data->mode_enable[MODE_100G] = 1;
if (dev_data->mode_enable[MODE_PORTS_PER_ENG_1] ||
dev_data->mode_enable[MODE_100G])
dev_data->num_ports = 1;
else if (dev_data->mode_enable[MODE_PORTS_PER_ENG_2])
dev_data->num_ports = 2;
else if (dev_data->mode_enable[MODE_PORTS_PER_ENG_4])
dev_data->num_ports = 4;
dev_data->num_pfs_per_port = min_t(u32,
num_pfs / dev_data->num_ports,
max_pfs_per_port);
qed_dbg_grc_init_params(p_hwfn);
dev_data->use_dmae = true;
dev_data->initialized = 1;
return DBG_STATUS_OK;
}
static const struct dbg_block *get_dbg_block(struct qed_hwfn *p_hwfn,
enum block_id block_id)
{
const struct dbg_block *dbg_block;
dbg_block = p_hwfn->dbg_arrays[BIN_BUF_DBG_BLOCKS].ptr;
return dbg_block + block_id;
}
static const struct dbg_block_chip *qed_get_dbg_block_per_chip(struct qed_hwfn
*p_hwfn,
enum block_id
block_id)
{
struct dbg_tools_data *dev_data = &p_hwfn->dbg_info;
return (const struct dbg_block_chip *)
p_hwfn->dbg_arrays[BIN_BUF_DBG_BLOCKS_CHIP_DATA].ptr +
block_id * MAX_CHIP_IDS + dev_data->chip_id;
}
static const struct dbg_reset_reg *qed_get_dbg_reset_reg(struct qed_hwfn
*p_hwfn,
u8 reset_reg_id)
{
struct dbg_tools_data *dev_data = &p_hwfn->dbg_info;
return (const struct dbg_reset_reg *)
p_hwfn->dbg_arrays[BIN_BUF_DBG_RESET_REGS].ptr +
reset_reg_id * MAX_CHIP_IDS + dev_data->chip_id;
}
static void qed_read_storm_fw_info(struct qed_hwfn *p_hwfn,
struct qed_ptt *p_ptt,
u8 storm_id, struct fw_info *fw_info)
{
struct storm_defs *storm = &s_storm_defs[storm_id];
struct fw_info_location fw_info_location;
u32 addr, i, size, *dest;
memset(&fw_info_location, 0, sizeof(fw_info_location));
memset(fw_info, 0, sizeof(*fw_info));
addr = storm->sem_fast_mem_addr + SEM_FAST_REG_INT_RAM +
DWORDS_TO_BYTES(SEM_FAST_REG_INT_RAM_SIZE) -
sizeof(fw_info_location);
dest = (u32 *)&fw_info_location;
size = BYTES_TO_DWORDS(sizeof(fw_info_location));
for (i = 0; i < size; i++, addr += BYTES_IN_DWORD)
dest[i] = qed_rd(p_hwfn, p_ptt, addr);
size = le32_to_cpu(fw_info_location.size);
if (!size || size > sizeof(*fw_info))
return;
addr = le32_to_cpu(fw_info_location.grc_addr);
dest = (u32 *)fw_info;
size = BYTES_TO_DWORDS(size);
for (i = 0; i < size; i++, addr += BYTES_IN_DWORD)
dest[i] = qed_rd(p_hwfn, p_ptt, addr);
}
static u32 qed_dump_str(char *dump_buf, bool dump, const char *str)
{
if (dump)
strcpy(dump_buf, str);
return (u32)strlen(str) + 1;
}
static u32 qed_dump_align(char *dump_buf, bool dump, u32 byte_offset)
{
u8 offset_in_dword, align_size;
offset_in_dword = (u8)(byte_offset & 0x3);
align_size = offset_in_dword ? BYTES_IN_DWORD - offset_in_dword : 0;
if (dump && align_size)
memset(dump_buf, 0, align_size);
return align_size;
}
static u32 qed_dump_str_param(u32 *dump_buf,
bool dump,
const char *param_name, const char *param_val)
{
char *char_buf = (char *)dump_buf;
u32 offset = 0;
offset += qed_dump_str(char_buf + offset, dump, param_name);
if (dump)
*(char_buf + offset) = 1;
offset++;
offset += qed_dump_str(char_buf + offset, dump, param_val);
offset += qed_dump_align(char_buf + offset, dump, offset);
return BYTES_TO_DWORDS(offset);
}
static u32 qed_dump_num_param(u32 *dump_buf,
bool dump, const char *param_name, u32 param_val)
{
char *char_buf = (char *)dump_buf;
u32 offset = 0;
offset += qed_dump_str(char_buf + offset, dump, param_name);
if (dump)
*(char_buf + offset) = 0;
offset++;
offset += qed_dump_align(char_buf + offset, dump, offset);
offset = BYTES_TO_DWORDS(offset);
if (dump)
*(dump_buf + offset) = param_val;
offset++;
return offset;
}
static u32 qed_dump_fw_ver_param(struct qed_hwfn *p_hwfn,
struct qed_ptt *p_ptt,
u32 *dump_buf, bool dump)
{
char fw_ver_str[16] = EMPTY_FW_VERSION_STR;
char fw_img_str[16] = EMPTY_FW_IMAGE_STR;
struct fw_info fw_info = { {0}, {0} };
u32 offset = 0;
if (dump && !qed_grc_get_param(p_hwfn, DBG_GRC_PARAM_NO_FW_VER)) {
qed_read_fw_info(p_hwfn, p_ptt, &fw_info);
if (snprintf(fw_ver_str, sizeof(fw_ver_str),
"%d_%d_%d_%d", fw_info.ver.num.major,
fw_info.ver.num.minor, fw_info.ver.num.rev,
fw_info.ver.num.eng) < 0)
DP_NOTICE(p_hwfn,
"Unexpected debug error: invalid FW version string\n");
switch (fw_info.ver.image_id) {
case FW_IMG_KUKU:
strcpy(fw_img_str, "kuku");
break;
case FW_IMG_MAIN:
strcpy(fw_img_str, "main");
break;
case FW_IMG_L2B:
strcpy(fw_img_str, "l2b");
break;
default:
strcpy(fw_img_str, "unknown");
break;
}
}
offset += qed_dump_str_param(dump_buf + offset,
dump, "fw-version", fw_ver_str);
offset += qed_dump_str_param(dump_buf + offset,
dump, "fw-image", fw_img_str);
offset += qed_dump_num_param(dump_buf + offset, dump, "fw-timestamp",
le32_to_cpu(fw_info.ver.timestamp));
return offset;
}
static u32 qed_dump_mfw_ver_param(struct qed_hwfn *p_hwfn,
struct qed_ptt *p_ptt,
u32 *dump_buf, bool dump)
{
char mfw_ver_str[16] = EMPTY_FW_VERSION_STR;
if (dump &&
!qed_grc_get_param(p_hwfn, DBG_GRC_PARAM_NO_FW_VER)) {
u32 global_section_offsize, global_section_addr, mfw_ver;
u32 public_data_addr, global_section_offsize_addr;
public_data_addr = qed_rd(p_hwfn,
p_ptt,
MISC_REG_SHARED_MEM_ADDR) |
MCP_REG_SCRATCH;
global_section_offsize_addr = public_data_addr +
offsetof(struct mcp_public_data,
sections) +
sizeof(offsize_t) * PUBLIC_GLOBAL;
global_section_offsize = qed_rd(p_hwfn, p_ptt,
global_section_offsize_addr);
global_section_addr =
MCP_REG_SCRATCH +
(global_section_offsize & OFFSIZE_OFFSET_MASK) * 4;
mfw_ver = qed_rd(p_hwfn, p_ptt,
global_section_addr +
offsetof(struct public_global, mfw_ver));
if (snprintf(mfw_ver_str, sizeof(mfw_ver_str), "%d_%d_%d_%d",
(u8)(mfw_ver >> 24), (u8)(mfw_ver >> 16),
(u8)(mfw_ver >> 8), (u8)mfw_ver) < 0)
DP_NOTICE(p_hwfn,
"Unexpected debug error: invalid MFW version string\n");
}
return qed_dump_str_param(dump_buf, dump, "mfw-version", mfw_ver_str);
}
static u32 qed_dump_chip_revision_param(struct qed_hwfn *p_hwfn,
struct qed_ptt *p_ptt,
u32 *dump_buf, bool dump)
{
struct dbg_tools_data *dev_data = &p_hwfn->dbg_info;
char param_str[3] = "??";
if (dev_data->hw_type == HW_TYPE_ASIC) {
u32 chip_rev, chip_metal;
chip_rev = qed_rd(p_hwfn, p_ptt, MISCS_REG_CHIP_REV);
chip_metal = qed_rd(p_hwfn, p_ptt, MISCS_REG_CHIP_METAL);
param_str[0] = 'a' + (u8)chip_rev;
param_str[1] = '0' + (u8)chip_metal;
}
return qed_dump_str_param(dump_buf, dump, "chip-revision", param_str);
}
static u32 qed_dump_section_hdr(u32 *dump_buf,
bool dump, const char *name, u32 num_params)
{
return qed_dump_num_param(dump_buf, dump, name, num_params);
}
static u32 qed_dump_common_global_params(struct qed_hwfn *p_hwfn,
struct qed_ptt *p_ptt,
u32 *dump_buf,
bool dump,
u8 num_specific_global_params)
{
struct dbg_tools_data *dev_data = &p_hwfn->dbg_info;
u32 offset = 0;
u8 num_params;
num_params = NUM_COMMON_GLOBAL_PARAMS + num_specific_global_params +
(dev_data->chip_id == CHIP_BB ? 1 : 0);
offset += qed_dump_section_hdr(dump_buf + offset,
dump, "global_params", num_params);
offset += qed_dump_fw_ver_param(p_hwfn, p_ptt, dump_buf + offset, dump);
offset += qed_dump_mfw_ver_param(p_hwfn,
p_ptt, dump_buf + offset, dump);
offset += qed_dump_chip_revision_param(p_hwfn,
p_ptt, dump_buf + offset, dump);
offset += qed_dump_num_param(dump_buf + offset,
dump, "tools-version", TOOLS_VERSION);
offset += qed_dump_str_param(dump_buf + offset,
dump,
"chip",
s_chip_defs[dev_data->chip_id].name);
offset += qed_dump_str_param(dump_buf + offset,
dump,
"platform",
s_hw_type_defs[dev_data->hw_type].name);
offset += qed_dump_num_param(dump_buf + offset,
dump, "pci-func", p_hwfn->abs_pf_id);
offset += qed_dump_num_param(dump_buf + offset,
dump, "epoch", qed_get_epoch_time());
if (dev_data->chip_id == CHIP_BB)
offset += qed_dump_num_param(dump_buf + offset,
dump, "path", QED_PATH_ID(p_hwfn));
return offset;
}
static u32 qed_dump_last_section(u32 *dump_buf, u32 offset, bool dump)
{
u32 start_offset = offset;
offset += qed_dump_section_hdr(dump_buf + offset, dump, "last", 0);
if (dump)
*(dump_buf + offset) = ~crc32(0xffffffff,
(u8 *)dump_buf,
DWORDS_TO_BYTES(offset));
offset++;
return offset - start_offset;
}
static void qed_update_blocks_reset_state(struct qed_hwfn *p_hwfn,
struct qed_ptt *p_ptt)
{
struct dbg_tools_data *dev_data = &p_hwfn->dbg_info;
u32 reg_val[NUM_DBG_RESET_REGS] = { 0 };
u8 rst_reg_id;
u32 blk_id;
for (rst_reg_id = 0; rst_reg_id < NUM_DBG_RESET_REGS; rst_reg_id++) {
const struct dbg_reset_reg *rst_reg;
bool rst_reg_removed;
u32 rst_reg_addr;
rst_reg = qed_get_dbg_reset_reg(p_hwfn, rst_reg_id);
rst_reg_removed = GET_FIELD(rst_reg->data,
DBG_RESET_REG_IS_REMOVED);
rst_reg_addr = DWORDS_TO_BYTES(GET_FIELD(rst_reg->data,
DBG_RESET_REG_ADDR));
if (!rst_reg_removed)
reg_val[rst_reg_id] = qed_rd(p_hwfn, p_ptt,
rst_reg_addr);
}
for (blk_id = 0; blk_id < NUM_PHYS_BLOCKS; blk_id++) {
const struct dbg_block_chip *blk;
bool has_rst_reg;
bool is_removed;
blk = qed_get_dbg_block_per_chip(p_hwfn, (enum block_id)blk_id);
is_removed = GET_FIELD(blk->flags, DBG_BLOCK_CHIP_IS_REMOVED);
has_rst_reg = GET_FIELD(blk->flags,
DBG_BLOCK_CHIP_HAS_RESET_REG);
if (!is_removed && has_rst_reg)
dev_data->block_in_reset[blk_id] =
!(reg_val[blk->reset_reg_id] &
BIT(blk->reset_reg_bit_offset));
}
}
static bool qed_is_mode_match_rec(struct qed_hwfn *p_hwfn,
u16 *modes_buf_offset, u8 rec_depth)
{
struct dbg_tools_data *dev_data = &p_hwfn->dbg_info;
u8 *dbg_array;
bool arg1, arg2;
u8 tree_val;
if (rec_depth > MAX_RECURSION_DEPTH) {
DP_NOTICE(p_hwfn,
"Unexpected error: is_mode_match_rec exceeded the max recursion depth. This is probably due to a corrupt init/debug buffer.\n");
return false;
}
dbg_array = p_hwfn->dbg_arrays[BIN_BUF_DBG_MODE_TREE].ptr;
tree_val = dbg_array[(*modes_buf_offset)++];
switch (tree_val) {
case INIT_MODE_OP_NOT:
return !qed_is_mode_match_rec(p_hwfn,
modes_buf_offset, rec_depth + 1);
case INIT_MODE_OP_OR:
case INIT_MODE_OP_AND:
arg1 = qed_is_mode_match_rec(p_hwfn,
modes_buf_offset, rec_depth + 1);
arg2 = qed_is_mode_match_rec(p_hwfn,
modes_buf_offset, rec_depth + 1);
return (tree_val == INIT_MODE_OP_OR) ? (arg1 ||
arg2) : (arg1 && arg2);
default:
return dev_data->mode_enable[tree_val - MAX_INIT_MODE_OPS] > 0;
}
}
static bool qed_is_mode_match(struct qed_hwfn *p_hwfn, u16 *modes_buf_offset)
{
return qed_is_mode_match_rec(p_hwfn, modes_buf_offset, 0);
}
static void qed_bus_enable_dbg_block(struct qed_hwfn *p_hwfn,
struct qed_ptt *p_ptt, bool enable)
{
qed_wr(p_hwfn, p_ptt, DBG_REG_DBG_BLOCK_ON, enable ? 1 : 0);
}
static void qed_bus_reset_dbg_block(struct qed_hwfn *p_hwfn,
struct qed_ptt *p_ptt)
{
u32 reset_reg_addr, old_reset_reg_val, new_reset_reg_val;
const struct dbg_reset_reg *reset_reg;
const struct dbg_block_chip *block;
block = qed_get_dbg_block_per_chip(p_hwfn, BLOCK_DBG);
reset_reg = qed_get_dbg_reset_reg(p_hwfn, block->reset_reg_id);
reset_reg_addr =
DWORDS_TO_BYTES(GET_FIELD(reset_reg->data, DBG_RESET_REG_ADDR));
old_reset_reg_val = qed_rd(p_hwfn, p_ptt, reset_reg_addr);
new_reset_reg_val =
old_reset_reg_val & ~BIT(block->reset_reg_bit_offset);
qed_wr(p_hwfn, p_ptt, reset_reg_addr, new_reset_reg_val);
qed_wr(p_hwfn, p_ptt, reset_reg_addr, old_reset_reg_val);
}
static void qed_bus_enable_clients(struct qed_hwfn *p_hwfn,
struct qed_ptt *p_ptt, u32 client_mask)
{
qed_wr(p_hwfn, p_ptt, DBG_REG_CLIENT_ENABLE, client_mask);
}
static void qed_bus_config_dbg_line(struct qed_hwfn *p_hwfn,
struct qed_ptt *p_ptt,
enum block_id block_id,
u8 line_id,
u8 enable_mask,
u8 right_shift,
u8 force_valid_mask, u8 force_frame_mask)
{
const struct dbg_block_chip *block =
qed_get_dbg_block_per_chip(p_hwfn, block_id);
qed_wr(p_hwfn, p_ptt, DWORDS_TO_BYTES(block->dbg_select_reg_addr),
line_id);
qed_wr(p_hwfn, p_ptt, DWORDS_TO_BYTES(block->dbg_dword_enable_reg_addr),
enable_mask);
qed_wr(p_hwfn, p_ptt, DWORDS_TO_BYTES(block->dbg_shift_reg_addr),
right_shift);
qed_wr(p_hwfn, p_ptt, DWORDS_TO_BYTES(block->dbg_force_valid_reg_addr),
force_valid_mask);
qed_wr(p_hwfn, p_ptt, DWORDS_TO_BYTES(block->dbg_force_frame_reg_addr),
force_frame_mask);
}
static void qed_bus_disable_blocks(struct qed_hwfn *p_hwfn,
struct qed_ptt *p_ptt)
{
struct dbg_tools_data *dev_data = &p_hwfn->dbg_info;
u32 block_id;
for (block_id = 0; block_id < MAX_BLOCK_ID; block_id++) {
const struct dbg_block_chip *block_per_chip =
qed_get_dbg_block_per_chip(p_hwfn,
(enum block_id)block_id);
if (GET_FIELD(block_per_chip->flags,
DBG_BLOCK_CHIP_IS_REMOVED) ||
dev_data->block_in_reset[block_id])
continue;
if (GET_FIELD(block_per_chip->flags,
DBG_BLOCK_CHIP_HAS_DBG_BUS)) {
u32 dbg_en_addr =
block_per_chip->dbg_dword_enable_reg_addr;
u16 modes_buf_offset =
GET_FIELD(block_per_chip->dbg_bus_mode.data,
DBG_MODE_HDR_MODES_BUF_OFFSET);
bool eval_mode =
GET_FIELD(block_per_chip->dbg_bus_mode.data,
DBG_MODE_HDR_EVAL_MODE) > 0;
if (!eval_mode ||
qed_is_mode_match(p_hwfn, &modes_buf_offset))
qed_wr(p_hwfn, p_ptt,
DWORDS_TO_BYTES(dbg_en_addr),
0);
}
}
}
static bool qed_grc_is_included(struct qed_hwfn *p_hwfn,
enum dbg_grc_params grc_param)
{
return qed_grc_get_param(p_hwfn, grc_param) > 0;
}
static enum dbg_storms qed_get_id_from_letter(char storm_letter)
{
u8 storm_id;
for (storm_id = 0; storm_id < MAX_DBG_STORMS; storm_id++)
if (s_storm_defs[storm_id].letter == storm_letter)
return (enum dbg_storms)storm_id;
return MAX_DBG_STORMS;
}
static bool qed_grc_is_storm_included(struct qed_hwfn *p_hwfn,
enum dbg_storms storm)
{
return qed_grc_get_param(p_hwfn, (enum dbg_grc_params)storm) > 0;
}
static bool qed_grc_is_mem_included(struct qed_hwfn *p_hwfn,
enum block_id block_id, u8 mem_group_id)
{
const struct dbg_block *block;
u8 i;
block = get_dbg_block(p_hwfn, block_id);
if (block->associated_storm_letter) {
enum dbg_storms associated_storm_id =
qed_get_id_from_letter(block->associated_storm_letter);
if (associated_storm_id == MAX_DBG_STORMS ||
!qed_grc_is_storm_included(p_hwfn, associated_storm_id))
return false;
}
for (i = 0; i < NUM_BIG_RAM_TYPES; i++) {
struct big_ram_defs *big_ram = &s_big_ram_defs[i];
if (mem_group_id == big_ram->mem_group_id ||
mem_group_id == big_ram->ram_mem_group_id)
return qed_grc_is_included(p_hwfn, big_ram->grc_param);
}
switch (mem_group_id) {
case MEM_GROUP_PXP_ILT:
case MEM_GROUP_PXP_MEM:
return qed_grc_is_included(p_hwfn, DBG_GRC_PARAM_DUMP_PXP);
case MEM_GROUP_RAM:
return qed_grc_is_included(p_hwfn, DBG_GRC_PARAM_DUMP_RAM);
case MEM_GROUP_PBUF:
return qed_grc_is_included(p_hwfn, DBG_GRC_PARAM_DUMP_PBUF);
case MEM_GROUP_CAU_MEM:
case MEM_GROUP_CAU_SB:
case MEM_GROUP_CAU_PI:
return qed_grc_is_included(p_hwfn, DBG_GRC_PARAM_DUMP_CAU);
case MEM_GROUP_CAU_MEM_EXT:
return qed_grc_is_included(p_hwfn, DBG_GRC_PARAM_DUMP_CAU_EXT);
case MEM_GROUP_QM_MEM:
return qed_grc_is_included(p_hwfn, DBG_GRC_PARAM_DUMP_QM);
case MEM_GROUP_CFC_MEM:
case MEM_GROUP_CONN_CFC_MEM:
case MEM_GROUP_TASK_CFC_MEM:
return qed_grc_is_included(p_hwfn, DBG_GRC_PARAM_DUMP_CFC) ||
qed_grc_is_included(p_hwfn, DBG_GRC_PARAM_DUMP_CM_CTX);
case MEM_GROUP_DORQ_MEM:
return qed_grc_is_included(p_hwfn, DBG_GRC_PARAM_DUMP_DORQ);
case MEM_GROUP_IGU_MEM:
case MEM_GROUP_IGU_MSIX:
return qed_grc_is_included(p_hwfn, DBG_GRC_PARAM_DUMP_IGU);
case MEM_GROUP_MULD_MEM:
return qed_grc_is_included(p_hwfn, DBG_GRC_PARAM_DUMP_MULD);
case MEM_GROUP_PRS_MEM:
return qed_grc_is_included(p_hwfn, DBG_GRC_PARAM_DUMP_PRS);
case MEM_GROUP_DMAE_MEM:
return qed_grc_is_included(p_hwfn, DBG_GRC_PARAM_DUMP_DMAE);
case MEM_GROUP_TM_MEM:
return qed_grc_is_included(p_hwfn, DBG_GRC_PARAM_DUMP_TM);
case MEM_GROUP_SDM_MEM:
return qed_grc_is_included(p_hwfn, DBG_GRC_PARAM_DUMP_SDM);
case MEM_GROUP_TDIF_CTX:
case MEM_GROUP_RDIF_CTX:
return qed_grc_is_included(p_hwfn, DBG_GRC_PARAM_DUMP_DIF);
case MEM_GROUP_CM_MEM:
return qed_grc_is_included(p_hwfn, DBG_GRC_PARAM_DUMP_CM);
case MEM_GROUP_IOR:
return qed_grc_is_included(p_hwfn, DBG_GRC_PARAM_DUMP_IOR);
default:
return true;
}
}
static void qed_grc_stall_storms(struct qed_hwfn *p_hwfn,
struct qed_ptt *p_ptt, bool stall)
{
u32 reg_addr;
u8 storm_id;
for (storm_id = 0; storm_id < MAX_DBG_STORMS; storm_id++) {
if (!qed_grc_is_storm_included(p_hwfn,
(enum dbg_storms)storm_id))
continue;
reg_addr = s_storm_defs[storm_id].sem_fast_mem_addr +
SEM_FAST_REG_STALL_0;
qed_wr(p_hwfn, p_ptt, reg_addr, stall ? 1 : 0);
}
msleep(STALL_DELAY_MS);
}
static void qed_grc_unreset_blocks(struct qed_hwfn *p_hwfn,
struct qed_ptt *p_ptt, bool rbc_only)
{
struct dbg_tools_data *dev_data = &p_hwfn->dbg_info;
u8 chip_id = dev_data->chip_id;
u32 i;
for (i = 0; i < ARRAY_SIZE(s_rbc_reset_defs); i++)
if (s_rbc_reset_defs[i].reset_val[dev_data->chip_id])
qed_wr(p_hwfn,
p_ptt,
s_rbc_reset_defs[i].reset_reg_addr +
RESET_REG_UNRESET_OFFSET,
s_rbc_reset_defs[i].reset_val[chip_id]);
if (!rbc_only) {
u32 reg_val[NUM_DBG_RESET_REGS] = { 0 };
u8 reset_reg_id;
u32 block_id;
for (block_id = 0; block_id < NUM_PHYS_BLOCKS; block_id++) {
bool is_removed, has_reset_reg, unreset_before_dump;
const struct dbg_block_chip *block;
block = qed_get_dbg_block_per_chip(p_hwfn,
(enum block_id)
block_id);
is_removed =
GET_FIELD(block->flags, DBG_BLOCK_CHIP_IS_REMOVED);
has_reset_reg =
GET_FIELD(block->flags,
DBG_BLOCK_CHIP_HAS_RESET_REG);
unreset_before_dump =
GET_FIELD(block->flags,
DBG_BLOCK_CHIP_UNRESET_BEFORE_DUMP);
if (!is_removed && has_reset_reg && unreset_before_dump)
reg_val[block->reset_reg_id] |=
BIT(block->reset_reg_bit_offset);
}
for (reset_reg_id = 0; reset_reg_id < NUM_DBG_RESET_REGS;
reset_reg_id++) {
const struct dbg_reset_reg *reset_reg;
u32 reset_reg_addr;
reset_reg = qed_get_dbg_reset_reg(p_hwfn, reset_reg_id);
if (GET_FIELD
(reset_reg->data, DBG_RESET_REG_IS_REMOVED))
continue;
if (reg_val[reset_reg_id]) {
reset_reg_addr =
GET_FIELD(reset_reg->data,
DBG_RESET_REG_ADDR);
qed_wr(p_hwfn,
p_ptt,
DWORDS_TO_BYTES(reset_reg_addr) +
RESET_REG_UNRESET_OFFSET,
reg_val[reset_reg_id]);
}
}
}
}
static const struct dbg_attn_block_type_data *
qed_get_block_attn_data(struct qed_hwfn *p_hwfn,
enum block_id block_id, enum dbg_attn_type attn_type)
{
const struct dbg_attn_block *base_attn_block_arr =
(const struct dbg_attn_block *)
p_hwfn->dbg_arrays[BIN_BUF_DBG_ATTN_BLOCKS].ptr;
return &base_attn_block_arr[block_id].per_type_data[attn_type];
}
static const struct dbg_attn_reg *
qed_get_block_attn_regs(struct qed_hwfn *p_hwfn,
enum block_id block_id, enum dbg_attn_type attn_type,
u8 *num_attn_regs)
{
const struct dbg_attn_block_type_data *block_type_data =
qed_get_block_attn_data(p_hwfn, block_id, attn_type);
*num_attn_regs = block_type_data->num_regs;
return (const struct dbg_attn_reg *)
p_hwfn->dbg_arrays[BIN_BUF_DBG_ATTN_REGS].ptr +
block_type_data->regs_offset;
}
static void qed_grc_clear_all_prty(struct qed_hwfn *p_hwfn,
struct qed_ptt *p_ptt)
{
struct dbg_tools_data *dev_data = &p_hwfn->dbg_info;
const struct dbg_attn_reg *attn_reg_arr;
u32 block_id, sts_clr_address;
u8 reg_idx, num_attn_regs;
for (block_id = 0; block_id < NUM_PHYS_BLOCKS; block_id++) {
if (dev_data->block_in_reset[block_id])
continue;
attn_reg_arr = qed_get_block_attn_regs(p_hwfn,
(enum block_id)block_id,
ATTN_TYPE_PARITY,
&num_attn_regs);
for (reg_idx = 0; reg_idx < num_attn_regs; reg_idx++) {
const struct dbg_attn_reg *reg_data =
&attn_reg_arr[reg_idx];
u16 modes_buf_offset;
bool eval_mode;
eval_mode = GET_FIELD(reg_data->mode.data,
DBG_MODE_HDR_EVAL_MODE) > 0;
modes_buf_offset =
GET_FIELD(reg_data->mode.data,
DBG_MODE_HDR_MODES_BUF_OFFSET);
sts_clr_address = reg_data->sts_clr_address;
if (!eval_mode ||
qed_is_mode_match(p_hwfn, &modes_buf_offset))
qed_rd(p_hwfn, p_ptt,
DWORDS_TO_BYTES(sts_clr_address));
}
}
}
static enum dbg_status qed_find_nvram_image(struct qed_hwfn *p_hwfn,
struct qed_ptt *p_ptt,
u32 image_type,
u32 *nvram_offset_bytes,
u32 *nvram_size_bytes,
bool b_can_sleep)
{
u32 ret_mcp_resp, ret_mcp_param, ret_txn_size;
struct mcp_file_att file_att;
int nvm_result;
nvm_result = qed_mcp_nvm_rd_cmd(p_hwfn,
p_ptt,
DRV_MSG_CODE_NVM_GET_FILE_ATT,
image_type,
&ret_mcp_resp,
&ret_mcp_param,
&ret_txn_size,
(u32 *)&file_att,
b_can_sleep);
if (nvm_result || (ret_mcp_resp & FW_MSG_CODE_MASK) !=
FW_MSG_CODE_NVM_OK)
return DBG_STATUS_NVRAM_GET_IMAGE_FAILED;
*nvram_offset_bytes = file_att.nvm_start_addr;
*nvram_size_bytes = file_att.len;
DP_VERBOSE(p_hwfn,
QED_MSG_DEBUG,
"find_nvram_image: found NVRAM image of type %d in NVRAM offset %d bytes with size %d bytes\n",
image_type, *nvram_offset_bytes, *nvram_size_bytes);
if (*nvram_size_bytes & 0x3)
return DBG_STATUS_NON_ALIGNED_NVRAM_IMAGE;
return DBG_STATUS_OK;
}
static enum dbg_status qed_nvram_read(struct qed_hwfn *p_hwfn,
struct qed_ptt *p_ptt,
u32 nvram_offset_bytes,
u32 nvram_size_bytes,
u32 *ret_buf,
bool b_can_sleep)
{
u32 ret_mcp_resp, ret_mcp_param, ret_read_size, bytes_to_copy;
s32 bytes_left = nvram_size_bytes;
u32 read_offset = 0, param = 0;
DP_VERBOSE(p_hwfn,
QED_MSG_DEBUG,
"nvram_read: reading image of size %d bytes from NVRAM\n",
nvram_size_bytes);
do {
bytes_to_copy =
(bytes_left >
MCP_DRV_NVM_BUF_LEN) ? MCP_DRV_NVM_BUF_LEN : bytes_left;
SET_MFW_FIELD(param,
DRV_MB_PARAM_NVM_OFFSET,
nvram_offset_bytes + read_offset);
SET_MFW_FIELD(param, DRV_MB_PARAM_NVM_LEN, bytes_to_copy);
if (qed_mcp_nvm_rd_cmd(p_hwfn, p_ptt,
DRV_MSG_CODE_NVM_READ_NVRAM, param,
&ret_mcp_resp,
&ret_mcp_param, &ret_read_size,
(u32 *)((u8 *)ret_buf + read_offset),
b_can_sleep))
return DBG_STATUS_NVRAM_READ_FAILED;
if ((ret_mcp_resp & FW_MSG_CODE_MASK) != FW_MSG_CODE_NVM_OK)
return DBG_STATUS_NVRAM_READ_FAILED;
read_offset += ret_read_size;
bytes_left -= ret_read_size;
} while (bytes_left > 0);
return DBG_STATUS_OK;
}
static u32 qed_grc_dump_regs_hdr(u32 *dump_buf,
bool dump,
u32 num_reg_entries,
enum init_split_types split_type,
u8 split_id, const char *reg_type_name)
{
u8 num_params = 2 +
(split_type != SPLIT_TYPE_NONE ? 1 : 0) + (reg_type_name ? 1 : 0);
u32 offset = 0;
offset += qed_dump_section_hdr(dump_buf + offset,
dump, "grc_regs", num_params);
offset += qed_dump_num_param(dump_buf + offset,
dump, "count", num_reg_entries);
offset += qed_dump_str_param(dump_buf + offset,
dump, "split",
s_split_type_defs[split_type].name);
if (split_type != SPLIT_TYPE_NONE)
offset += qed_dump_num_param(dump_buf + offset,
dump, "id", split_id);
if (reg_type_name)
offset += qed_dump_str_param(dump_buf + offset,
dump, "type", reg_type_name);
return offset;
}
void qed_read_regs(struct qed_hwfn *p_hwfn,
struct qed_ptt *p_ptt, u32 *buf, u32 addr, u32 len)
{
u32 i;
for (i = 0; i < len; i++)
buf[i] = qed_rd(p_hwfn, p_ptt, DWORDS_TO_BYTES(addr + i));
}
static u32 qed_grc_dump_addr_range(struct qed_hwfn *p_hwfn,
struct qed_ptt *p_ptt,
u32 *dump_buf,
bool dump, u32 addr, u32 len, bool wide_bus,
enum init_split_types split_type,
u8 split_id)
{
struct dbg_tools_data *dev_data = &p_hwfn->dbg_info;
u8 port_id = 0, pf_id = 0, vf_id = 0;
bool read_using_dmae = false;
u32 thresh;
u16 fid;
if (!dump)
return len;
switch (split_type) {
case SPLIT_TYPE_PORT:
port_id = split_id;
break;
case SPLIT_TYPE_PF:
pf_id = split_id;
break;
case SPLIT_TYPE_PORT_PF:
port_id = split_id / dev_data->num_pfs_per_port;
pf_id = port_id + dev_data->num_ports *
(split_id % dev_data->num_pfs_per_port);
break;
case SPLIT_TYPE_VF:
vf_id = split_id;
break;
default:
break;
}
if (dev_data->use_dmae && split_type != SPLIT_TYPE_VF &&
(len >= s_hw_type_defs[dev_data->hw_type].dmae_thresh ||
(PROTECT_WIDE_BUS && wide_bus))) {
struct qed_dmae_params dmae_params;
memset(&dmae_params, 0, sizeof(dmae_params));
SET_FIELD(dmae_params.flags, QED_DMAE_PARAMS_COMPLETION_DST, 1);
switch (split_type) {
case SPLIT_TYPE_PORT:
SET_FIELD(dmae_params.flags, QED_DMAE_PARAMS_PORT_VALID,
1);
dmae_params.port_id = port_id;
break;
case SPLIT_TYPE_PF:
SET_FIELD(dmae_params.flags,
QED_DMAE_PARAMS_SRC_PF_VALID, 1);
dmae_params.src_pfid = pf_id;
break;
case SPLIT_TYPE_PORT_PF:
SET_FIELD(dmae_params.flags, QED_DMAE_PARAMS_PORT_VALID,
1);
SET_FIELD(dmae_params.flags,
QED_DMAE_PARAMS_SRC_PF_VALID, 1);
dmae_params.port_id = port_id;
dmae_params.src_pfid = pf_id;
break;
default:
break;
}
read_using_dmae = !qed_dmae_grc2host(p_hwfn,
p_ptt,
DWORDS_TO_BYTES(addr),
(u64)(uintptr_t)(dump_buf),
len, &dmae_params);
if (!read_using_dmae) {
dev_data->use_dmae = 0;
DP_VERBOSE(p_hwfn,
QED_MSG_DEBUG,
"Failed reading from chip using DMAE, using GRC instead\n");
}
}
if (read_using_dmae)
goto print_log;
if (split_type != dev_data->pretend.split_type ||
split_id != dev_data->pretend.split_id) {
switch (split_type) {
case SPLIT_TYPE_PORT:
qed_port_pretend(p_hwfn, p_ptt, port_id);
break;
case SPLIT_TYPE_PF:
fid = FIELD_VALUE(PXP_PRETEND_CONCRETE_FID_PFID,
pf_id);
qed_fid_pretend(p_hwfn, p_ptt, fid);
break;
case SPLIT_TYPE_PORT_PF:
fid = FIELD_VALUE(PXP_PRETEND_CONCRETE_FID_PFID,
pf_id);
qed_port_fid_pretend(p_hwfn, p_ptt, port_id, fid);
break;
case SPLIT_TYPE_VF:
fid = FIELD_VALUE(PXP_PRETEND_CONCRETE_FID_VFVALID, 1)
| FIELD_VALUE(PXP_PRETEND_CONCRETE_FID_VFID,
vf_id);
qed_fid_pretend(p_hwfn, p_ptt, fid);
break;
default:
break;
}
dev_data->pretend.split_type = (u8)split_type;
dev_data->pretend.split_id = split_id;
}
qed_read_regs(p_hwfn, p_ptt, dump_buf, addr, len);
print_log:
dev_data->num_regs_read += len;
thresh = s_hw_type_defs[dev_data->hw_type].log_thresh;
if ((dev_data->num_regs_read / thresh) >
((dev_data->num_regs_read - len) / thresh))
DP_VERBOSE(p_hwfn,
QED_MSG_DEBUG,
"Dumped %d registers...\n", dev_data->num_regs_read);
return len;
}
static u32 qed_grc_dump_reg_entry_hdr(u32 *dump_buf,
bool dump, u32 addr, u32 len)
{
if (dump)
*dump_buf = addr | (len << REG_DUMP_LEN_SHIFT);
return 1;
}
static u32 qed_grc_dump_reg_entry(struct qed_hwfn *p_hwfn,
struct qed_ptt *p_ptt,
u32 *dump_buf,
bool dump, u32 addr, u32 len, bool wide_bus,
enum init_split_types split_type, u8 split_id)
{
u32 offset = 0;
offset += qed_grc_dump_reg_entry_hdr(dump_buf, dump, addr, len);
offset += qed_grc_dump_addr_range(p_hwfn,
p_ptt,
dump_buf + offset,
dump, addr, len, wide_bus,
split_type, split_id);
return offset;
}
static u32 qed_grc_dump_reg_entry_skip(struct qed_hwfn *p_hwfn,
struct qed_ptt *p_ptt,
u32 *dump_buf,
bool dump,
u32 addr,
u32 total_len,
u32 read_len, u32 skip_len)
{
u32 offset = 0, reg_offset = 0;
offset += qed_grc_dump_reg_entry_hdr(dump_buf, dump, addr, total_len);
if (!dump)
return offset + total_len;
while (reg_offset < total_len) {
u32 curr_len = min_t(u32, read_len, total_len - reg_offset);
offset += qed_grc_dump_addr_range(p_hwfn,
p_ptt,
dump_buf + offset,
dump, addr, curr_len, false,
SPLIT_TYPE_NONE, 0);
reg_offset += curr_len;
addr += curr_len;
if (reg_offset < total_len) {
curr_len = min_t(u32, skip_len, total_len - skip_len);
memset(dump_buf + offset, 0, DWORDS_TO_BYTES(curr_len));
offset += curr_len;
reg_offset += curr_len;
addr += curr_len;
}
}
return offset;
}
static u32 qed_grc_dump_regs_entries(struct qed_hwfn *p_hwfn,
struct qed_ptt *p_ptt,
struct virt_mem_desc input_regs_arr,
u32 *dump_buf,
bool dump,
enum init_split_types split_type,
u8 split_id,
bool block_enable[MAX_BLOCK_ID],
u32 *num_dumped_reg_entries)
{
u32 i, offset = 0, input_offset = 0;
bool mode_match = true;
*num_dumped_reg_entries = 0;
while (input_offset < BYTES_TO_DWORDS(input_regs_arr.size)) {
const struct dbg_dump_cond_hdr *cond_hdr =
(const struct dbg_dump_cond_hdr *)
input_regs_arr.ptr + input_offset++;
u16 modes_buf_offset;
bool eval_mode;
eval_mode = GET_FIELD(cond_hdr->mode.data,
DBG_MODE_HDR_EVAL_MODE) > 0;
if (eval_mode) {
modes_buf_offset =
GET_FIELD(cond_hdr->mode.data,
DBG_MODE_HDR_MODES_BUF_OFFSET);
mode_match = qed_is_mode_match(p_hwfn,
&modes_buf_offset);
}
if (!mode_match || !block_enable[cond_hdr->block_id]) {
input_offset += cond_hdr->data_size;
continue;
}
for (i = 0; i < cond_hdr->data_size; i++, input_offset++) {
const struct dbg_dump_reg *reg =
(const struct dbg_dump_reg *)
input_regs_arr.ptr + input_offset;
u32 addr, len;
bool wide_bus;
addr = GET_FIELD(reg->data, DBG_DUMP_REG_ADDRESS);
len = GET_FIELD(reg->data, DBG_DUMP_REG_LENGTH);
wide_bus = GET_FIELD(reg->data, DBG_DUMP_REG_WIDE_BUS);
offset += qed_grc_dump_reg_entry(p_hwfn,
p_ptt,
dump_buf + offset,
dump,
addr,
len,
wide_bus,
split_type, split_id);
(*num_dumped_reg_entries)++;
}
}
return offset;
}
static u32 qed_grc_dump_split_data(struct qed_hwfn *p_hwfn,
struct qed_ptt *p_ptt,
struct virt_mem_desc input_regs_arr,
u32 *dump_buf,
bool dump,
bool block_enable[MAX_BLOCK_ID],
enum init_split_types split_type,
u8 split_id, const char *reg_type_name)
{
struct dbg_tools_data *dev_data = &p_hwfn->dbg_info;
enum init_split_types hdr_split_type = split_type;
u32 num_dumped_reg_entries, offset;
u8 hdr_split_id = split_id;
if (split_type == SPLIT_TYPE_PORT_PF) {
hdr_split_type = SPLIT_TYPE_PORT;
hdr_split_id = split_id / dev_data->num_pfs_per_port;
}
offset = qed_grc_dump_regs_hdr(dump_buf,
false,
0,
hdr_split_type,
hdr_split_id, reg_type_name);
offset += qed_grc_dump_regs_entries(p_hwfn,
p_ptt,
input_regs_arr,
dump_buf + offset,
dump,
split_type,
split_id,
block_enable,
&num_dumped_reg_entries);
if (dump && num_dumped_reg_entries > 0)
qed_grc_dump_regs_hdr(dump_buf,
dump,
num_dumped_reg_entries,
hdr_split_type,
hdr_split_id, reg_type_name);
return num_dumped_reg_entries > 0 ? offset : 0;
}
static u32 qed_grc_dump_registers(struct qed_hwfn *p_hwfn,
struct qed_ptt *p_ptt,
u32 *dump_buf,
bool dump,
bool block_enable[MAX_BLOCK_ID],
const char *reg_type_name)
{
struct virt_mem_desc *dbg_buf =
&p_hwfn->dbg_arrays[BIN_BUF_DBG_DUMP_REG];
struct dbg_tools_data *dev_data = &p_hwfn->dbg_info;
u32 offset = 0, input_offset = 0;
while (input_offset < BYTES_TO_DWORDS(dbg_buf->size)) {
const struct dbg_dump_split_hdr *split_hdr;
struct virt_mem_desc curr_input_regs_arr;
enum init_split_types split_type;
u16 split_count = 0;
u32 split_data_size;
u8 split_id;
split_hdr =
(const struct dbg_dump_split_hdr *)
dbg_buf->ptr + input_offset++;
split_type =
GET_FIELD(split_hdr->hdr,
DBG_DUMP_SPLIT_HDR_SPLIT_TYPE_ID);
split_data_size = GET_FIELD(split_hdr->hdr,
DBG_DUMP_SPLIT_HDR_DATA_SIZE);
curr_input_regs_arr.ptr =
(u32 *)p_hwfn->dbg_arrays[BIN_BUF_DBG_DUMP_REG].ptr +
input_offset;
curr_input_regs_arr.size = DWORDS_TO_BYTES(split_data_size);
switch (split_type) {
case SPLIT_TYPE_NONE:
split_count = 1;
break;
case SPLIT_TYPE_PORT:
split_count = dev_data->num_ports;
break;
case SPLIT_TYPE_PF:
case SPLIT_TYPE_PORT_PF:
split_count = dev_data->num_ports *
dev_data->num_pfs_per_port;
break;
case SPLIT_TYPE_VF:
split_count = dev_data->num_vfs;
break;
default:
return 0;
}
for (split_id = 0; split_id < split_count; split_id++)
offset += qed_grc_dump_split_data(p_hwfn, p_ptt,
curr_input_regs_arr,
dump_buf + offset,
dump, block_enable,
split_type,
split_id,
reg_type_name);
input_offset += split_data_size;
}
if (dump) {
qed_fid_pretend(p_hwfn, p_ptt,
FIELD_VALUE(PXP_PRETEND_CONCRETE_FID_PFID,
p_hwfn->rel_pf_id));
dev_data->pretend.split_type = SPLIT_TYPE_NONE;
dev_data->pretend.split_id = 0;
}
return offset;
}
static u32 qed_grc_dump_reset_regs(struct qed_hwfn *p_hwfn,
struct qed_ptt *p_ptt,
u32 *dump_buf, bool dump)
{
u32 offset = 0, num_regs = 0;
u8 reset_reg_id;
offset += qed_grc_dump_regs_hdr(dump_buf,
false,
0, SPLIT_TYPE_NONE, 0, "RESET_REGS");
for (reset_reg_id = 0; reset_reg_id < NUM_DBG_RESET_REGS;
reset_reg_id++) {
const struct dbg_reset_reg *reset_reg;
u32 reset_reg_addr;
reset_reg = qed_get_dbg_reset_reg(p_hwfn, reset_reg_id);
if (GET_FIELD(reset_reg->data, DBG_RESET_REG_IS_REMOVED))
continue;
reset_reg_addr = GET_FIELD(reset_reg->data, DBG_RESET_REG_ADDR);
offset += qed_grc_dump_reg_entry(p_hwfn,
p_ptt,
dump_buf + offset,
dump,
reset_reg_addr,
1, false, SPLIT_TYPE_NONE, 0);
num_regs++;
}
if (dump)
qed_grc_dump_regs_hdr(dump_buf,
true, num_regs, SPLIT_TYPE_NONE,
0, "RESET_REGS");
return offset;
}
static u32 qed_grc_dump_modified_regs(struct qed_hwfn *p_hwfn,
struct qed_ptt *p_ptt,
u32 *dump_buf, bool dump)
{
struct dbg_tools_data *dev_data = &p_hwfn->dbg_info;
u32 block_id, offset = 0, stall_regs_offset;
const struct dbg_attn_reg *attn_reg_arr;
u8 storm_id, reg_idx, num_attn_regs;
u32 num_reg_entries = 0;
offset += qed_grc_dump_regs_hdr(dump_buf,
false,
0, SPLIT_TYPE_NONE, 0, "ATTN_REGS");
for (block_id = 0; block_id < NUM_PHYS_BLOCKS; block_id++) {
if (dev_data->block_in_reset[block_id] && dump)
continue;
attn_reg_arr = qed_get_block_attn_regs(p_hwfn,
(enum block_id)block_id,
ATTN_TYPE_PARITY,
&num_attn_regs);
for (reg_idx = 0; reg_idx < num_attn_regs; reg_idx++) {
const struct dbg_attn_reg *reg_data =
&attn_reg_arr[reg_idx];
u16 modes_buf_offset;
bool eval_mode;
u32 addr;
eval_mode = GET_FIELD(reg_data->mode.data,
DBG_MODE_HDR_EVAL_MODE) > 0;
modes_buf_offset =
GET_FIELD(reg_data->mode.data,
DBG_MODE_HDR_MODES_BUF_OFFSET);
if (eval_mode &&
!qed_is_mode_match(p_hwfn, &modes_buf_offset))
continue;
addr = reg_data->mask_address;
offset += qed_grc_dump_reg_entry(p_hwfn,
p_ptt,
dump_buf + offset,
dump,
addr,
1, false,
SPLIT_TYPE_NONE, 0);
addr = GET_FIELD(reg_data->data,
DBG_ATTN_REG_STS_ADDRESS);
offset += qed_grc_dump_reg_entry(p_hwfn,
p_ptt,
dump_buf + offset,
dump,
addr,
1, false,
SPLIT_TYPE_NONE, 0);
num_reg_entries += 2;
}
}
if (dump)
qed_grc_dump_regs_hdr(dump_buf,
true,
num_reg_entries,
SPLIT_TYPE_NONE, 0, "ATTN_REGS");
stall_regs_offset = offset;
offset += qed_grc_dump_regs_hdr(dump_buf,
false, 0, SPLIT_TYPE_NONE, 0, "REGS");
for (storm_id = 0, num_reg_entries = 0; storm_id < MAX_DBG_STORMS;
storm_id++) {
struct storm_defs *storm = &s_storm_defs[storm_id];
u32 addr;
if (dev_data->block_in_reset[storm->sem_block_id] && dump)
continue;
addr =
BYTES_TO_DWORDS(storm->sem_fast_mem_addr +
SEM_FAST_REG_STALLED);
offset += qed_grc_dump_reg_entry(p_hwfn,
p_ptt,
dump_buf + offset,
dump,
addr,
1,
false, SPLIT_TYPE_NONE, 0);
num_reg_entries++;
}
if (dump)
qed_grc_dump_regs_hdr(dump_buf + stall_regs_offset,
true,
num_reg_entries,
SPLIT_TYPE_NONE, 0, "REGS");
return offset;
}
static u32 qed_grc_dump_special_regs(struct qed_hwfn *p_hwfn,
struct qed_ptt *p_ptt,
u32 *dump_buf, bool dump)
{
u32 offset = 0, addr;
offset += qed_grc_dump_regs_hdr(dump_buf,
dump, 2, SPLIT_TYPE_NONE, 0, "REGS");
addr = BYTES_TO_DWORDS(RDIF_REG_DEBUG_ERROR_INFO);
offset += qed_grc_dump_reg_entry_skip(p_hwfn,
p_ptt,
dump_buf + offset,
dump,
addr,
RDIF_REG_DEBUG_ERROR_INFO_SIZE,
7,
1);
addr = BYTES_TO_DWORDS(TDIF_REG_DEBUG_ERROR_INFO);
offset +=
qed_grc_dump_reg_entry_skip(p_hwfn,
p_ptt,
dump_buf + offset,
dump,
addr,
TDIF_REG_DEBUG_ERROR_INFO_SIZE,
7,
1);
return offset;
}
static u32 qed_grc_dump_mem_hdr(struct qed_hwfn *p_hwfn,
u32 *dump_buf,
bool dump,
const char *name,
u32 addr,
u32 len,
u32 bit_width,
bool packed,
const char *mem_group, char storm_letter)
{
u8 num_params = 3;
u32 offset = 0;
char buf[64];
if (!len)
DP_NOTICE(p_hwfn,
"Unexpected GRC Dump error: dumped memory size must be non-zero\n");
if (bit_width)
num_params++;
if (packed)
num_params++;
offset += qed_dump_section_hdr(dump_buf + offset,
dump, "grc_mem", num_params);
if (name) {
if (storm_letter) {
strcpy(buf, "?STORM_");
buf[0] = storm_letter;
strcpy(buf + strlen(buf), name);
} else {
strcpy(buf, name);
}
offset += qed_dump_str_param(dump_buf + offset,
dump, "name", buf);
} else {
u32 addr_in_bytes = DWORDS_TO_BYTES(addr);
offset += qed_dump_num_param(dump_buf + offset,
dump, "addr", addr_in_bytes);
}
offset += qed_dump_num_param(dump_buf + offset, dump, "len", len);
if (bit_width)
offset += qed_dump_num_param(dump_buf + offset,
dump, "width", bit_width);
if (packed)
offset += qed_dump_num_param(dump_buf + offset,
dump, "packed", 1);
if (storm_letter) {
strcpy(buf, "?STORM_");
buf[0] = storm_letter;
strcpy(buf + strlen(buf), mem_group);
} else {
strcpy(buf, mem_group);
}
offset += qed_dump_str_param(dump_buf + offset, dump, "type", buf);
return offset;
}
static u32 qed_grc_dump_mem(struct qed_hwfn *p_hwfn,
struct qed_ptt *p_ptt,
u32 *dump_buf,
bool dump,
const char *name,
u32 addr,
u32 len,
bool wide_bus,
u32 bit_width,
bool packed,
const char *mem_group, char storm_letter)
{
u32 offset = 0;
offset += qed_grc_dump_mem_hdr(p_hwfn,
dump_buf + offset,
dump,
name,
addr,
len,
bit_width,
packed, mem_group, storm_letter);
offset += qed_grc_dump_addr_range(p_hwfn,
p_ptt,
dump_buf + offset,
dump, addr, len, wide_bus,
SPLIT_TYPE_NONE, 0);
return offset;
}
static u32 qed_grc_dump_mem_entries(struct qed_hwfn *p_hwfn,
struct qed_ptt *p_ptt,
struct virt_mem_desc input_mems_arr,
u32 *dump_buf, bool dump)
{
u32 i, offset = 0, input_offset = 0;
bool mode_match = true;
while (input_offset < BYTES_TO_DWORDS(input_mems_arr.size)) {
const struct dbg_dump_cond_hdr *cond_hdr;
u16 modes_buf_offset;
u32 num_entries;
bool eval_mode;
cond_hdr =
(const struct dbg_dump_cond_hdr *)input_mems_arr.ptr +
input_offset++;
num_entries = cond_hdr->data_size / MEM_DUMP_ENTRY_SIZE_DWORDS;
eval_mode = GET_FIELD(cond_hdr->mode.data,
DBG_MODE_HDR_EVAL_MODE) > 0;
if (eval_mode) {
modes_buf_offset =
GET_FIELD(cond_hdr->mode.data,
DBG_MODE_HDR_MODES_BUF_OFFSET);
mode_match = qed_is_mode_match(p_hwfn,
&modes_buf_offset);
}
if (!mode_match) {
input_offset += cond_hdr->data_size;
continue;
}
for (i = 0; i < num_entries;
i++, input_offset += MEM_DUMP_ENTRY_SIZE_DWORDS) {
const struct dbg_dump_mem *mem =
(const struct dbg_dump_mem *)((u32 *)
input_mems_arr.ptr
+ input_offset);
const struct dbg_block *block;
char storm_letter = 0;
u32 mem_addr, mem_len;
bool mem_wide_bus;
u8 mem_group_id;
mem_group_id = GET_FIELD(mem->dword0,
DBG_DUMP_MEM_MEM_GROUP_ID);
if (mem_group_id >= MEM_GROUPS_NUM) {
DP_NOTICE(p_hwfn, "Invalid mem_group_id\n");
return 0;
}
if (!qed_grc_is_mem_included(p_hwfn,
(enum block_id)
cond_hdr->block_id,
mem_group_id))
continue;
mem_addr = GET_FIELD(mem->dword0, DBG_DUMP_MEM_ADDRESS);
mem_len = GET_FIELD(mem->dword1, DBG_DUMP_MEM_LENGTH);
mem_wide_bus = GET_FIELD(mem->dword1,
DBG_DUMP_MEM_WIDE_BUS);
block = get_dbg_block(p_hwfn,
cond_hdr->block_id);
if (block->associated_storm_letter)
storm_letter = block->associated_storm_letter;
offset += qed_grc_dump_mem(p_hwfn,
p_ptt,
dump_buf + offset,
dump,
NULL,
mem_addr,
mem_len,
mem_wide_bus,
0,
false,
s_mem_group_names[mem_group_id],
storm_letter);
}
}
return offset;
}
static u32 qed_grc_dump_memories(struct qed_hwfn *p_hwfn,
struct qed_ptt *p_ptt,
u32 *dump_buf, bool dump)
{
struct virt_mem_desc *dbg_buf =
&p_hwfn->dbg_arrays[BIN_BUF_DBG_DUMP_MEM];
u32 offset = 0, input_offset = 0;
while (input_offset < BYTES_TO_DWORDS(dbg_buf->size)) {
const struct dbg_dump_split_hdr *split_hdr;
struct virt_mem_desc curr_input_mems_arr;
enum init_split_types split_type;
u32 split_data_size;
split_hdr =
(const struct dbg_dump_split_hdr *)dbg_buf->ptr +
input_offset++;
split_type = GET_FIELD(split_hdr->hdr,
DBG_DUMP_SPLIT_HDR_SPLIT_TYPE_ID);
split_data_size = GET_FIELD(split_hdr->hdr,
DBG_DUMP_SPLIT_HDR_DATA_SIZE);
curr_input_mems_arr.ptr = (u32 *)dbg_buf->ptr + input_offset;
curr_input_mems_arr.size = DWORDS_TO_BYTES(split_data_size);
if (split_type == SPLIT_TYPE_NONE)
offset += qed_grc_dump_mem_entries(p_hwfn,
p_ptt,
curr_input_mems_arr,
dump_buf + offset,
dump);
else
DP_NOTICE(p_hwfn,
"Dumping split memories is currently not supported\n");
input_offset += split_data_size;
}
return offset;
}
static u32 qed_grc_dump_ctx_data(struct qed_hwfn *p_hwfn,
struct qed_ptt *p_ptt,
u32 *dump_buf,
bool dump,
const char *name,
u32 num_lids,
enum cm_ctx_types ctx_type, u8 storm_id)
{
struct dbg_tools_data *dev_data = &p_hwfn->dbg_info;
struct storm_defs *storm = &s_storm_defs[storm_id];
u32 i, lid, lid_size, total_size;
u32 rd_reg_addr, offset = 0;
lid_size = storm->cm_ctx_lid_sizes[dev_data->chip_id][ctx_type] * 4;
if (!lid_size)
return 0;
total_size = num_lids * lid_size;
offset += qed_grc_dump_mem_hdr(p_hwfn,
dump_buf + offset,
dump,
name,
0,
total_size,
lid_size * 32,
false, name, storm->letter);
if (!dump)
return offset + total_size;
rd_reg_addr = BYTES_TO_DWORDS(storm->cm_ctx_rd_addr[ctx_type]);
for (lid = 0; lid < num_lids; lid++) {
for (i = 0; i < lid_size; i++) {
qed_wr(p_hwfn,
p_ptt, storm->cm_ctx_wr_addr, (i << 9) | lid);
offset += qed_grc_dump_addr_range(p_hwfn,
p_ptt,
dump_buf + offset,
dump,
rd_reg_addr,
1,
false,
SPLIT_TYPE_NONE, 0);
}
}
return offset;
}
static u32 qed_grc_dump_ctx(struct qed_hwfn *p_hwfn,
struct qed_ptt *p_ptt, u32 *dump_buf, bool dump)
{
u32 offset = 0;
u8 storm_id;
for (storm_id = 0; storm_id < MAX_DBG_STORMS; storm_id++) {
if (!qed_grc_is_storm_included(p_hwfn,
(enum dbg_storms)storm_id))
continue;
offset += qed_grc_dump_ctx_data(p_hwfn,
p_ptt,
dump_buf + offset,
dump,
"CONN_AG_CTX",
NUM_OF_LCIDS,
CM_CTX_CONN_AG, storm_id);
offset += qed_grc_dump_ctx_data(p_hwfn,
p_ptt,
dump_buf + offset,
dump,
"CONN_ST_CTX",
NUM_OF_LCIDS,
CM_CTX_CONN_ST, storm_id);
offset += qed_grc_dump_ctx_data(p_hwfn,
p_ptt,
dump_buf + offset,
dump,
"TASK_AG_CTX",
NUM_OF_LTIDS,
CM_CTX_TASK_AG, storm_id);
offset += qed_grc_dump_ctx_data(p_hwfn,
p_ptt,
dump_buf + offset,
dump,
"TASK_ST_CTX",
NUM_OF_LTIDS,
CM_CTX_TASK_ST, storm_id);
}
return offset;
}
#define VFC_STATUS_RESP_READY_BIT 0
#define VFC_STATUS_BUSY_BIT 1
#define VFC_STATUS_SENDING_CMD_BIT 2
#define VFC_POLLING_DELAY_MS 1
#define VFC_POLLING_COUNT 20
static u32 qed_grc_dump_read_from_vfc(struct qed_hwfn *p_hwfn,
struct qed_ptt *p_ptt,
struct storm_defs *storm,
u32 *cmd_data,
u32 cmd_size,
u32 *addr_data,
u32 addr_size,
u32 resp_size, u32 *dump_buf)
{
struct dbg_tools_data *dev_data = &p_hwfn->dbg_info;
u32 vfc_status, polling_ms, polling_count = 0, i;
u32 reg_addr, sem_base;
bool is_ready = false;
sem_base = storm->sem_fast_mem_addr;
polling_ms = VFC_POLLING_DELAY_MS *
s_hw_type_defs[dev_data->hw_type].delay_factor;
ARR_REG_WR(p_hwfn,
p_ptt,
sem_base + SEM_FAST_REG_VFC_DATA_WR,
cmd_data, cmd_size);
ARR_REG_WR(p_hwfn,
p_ptt,
sem_base + SEM_FAST_REG_VFC_ADDR,
addr_data, addr_size);
for (i = 0; i < resp_size; i++) {
do {
reg_addr = sem_base + SEM_FAST_REG_VFC_STATUS;
qed_grc_dump_addr_range(p_hwfn,
p_ptt,
&vfc_status,
true,
BYTES_TO_DWORDS(reg_addr),
1,
false, SPLIT_TYPE_NONE, 0);
is_ready = vfc_status & BIT(VFC_STATUS_RESP_READY_BIT);
if (!is_ready) {
if (polling_count++ == VFC_POLLING_COUNT)
return 0;
msleep(polling_ms);
}
} while (!is_ready);
reg_addr = sem_base + SEM_FAST_REG_VFC_DATA_RD;
qed_grc_dump_addr_range(p_hwfn,
p_ptt,
dump_buf + i,
true,
BYTES_TO_DWORDS(reg_addr),
1, false, SPLIT_TYPE_NONE, 0);
}
return resp_size;
}
static u32 qed_grc_dump_vfc_cam(struct qed_hwfn *p_hwfn,
struct qed_ptt *p_ptt,
u32 *dump_buf, bool dump, u8 storm_id)
{
u32 total_size = VFC_CAM_NUM_ROWS * VFC_CAM_RESP_DWORDS;
struct storm_defs *storm = &s_storm_defs[storm_id];
u32 cam_addr[VFC_CAM_ADDR_DWORDS] = { 0 };
u32 cam_cmd[VFC_CAM_CMD_DWORDS] = { 0 };
u32 row, offset = 0;
offset += qed_grc_dump_mem_hdr(p_hwfn,
dump_buf + offset,
dump,
"vfc_cam",
0,
total_size,
256,
false, "vfc_cam", storm->letter);
if (!dump)
return offset + total_size;
SET_VAR_FIELD(cam_addr, VFC_CAM_ADDR, OP, VFC_OPCODE_CAM_RD);
for (row = 0; row < VFC_CAM_NUM_ROWS; row++) {
SET_VAR_FIELD(cam_cmd, VFC_CAM_CMD, ROW, row);
offset += qed_grc_dump_read_from_vfc(p_hwfn,
p_ptt,
storm,
cam_cmd,
VFC_CAM_CMD_DWORDS,
cam_addr,
VFC_CAM_ADDR_DWORDS,
VFC_CAM_RESP_DWORDS,
dump_buf + offset);
}
return offset;
}
static u32 qed_grc_dump_vfc_ram(struct qed_hwfn *p_hwfn,
struct qed_ptt *p_ptt,
u32 *dump_buf,
bool dump,
u8 storm_id, struct vfc_ram_defs *ram_defs)
{
u32 total_size = ram_defs->num_rows * VFC_RAM_RESP_DWORDS;
struct storm_defs *storm = &s_storm_defs[storm_id];
u32 ram_addr[VFC_RAM_ADDR_DWORDS] = { 0 };
u32 ram_cmd[VFC_RAM_CMD_DWORDS] = { 0 };
u32 row, offset = 0;
offset += qed_grc_dump_mem_hdr(p_hwfn,
dump_buf + offset,
dump,
ram_defs->mem_name,
0,
total_size,
256,
false,
ram_defs->type_name,
storm->letter);
if (!dump)
return offset + total_size;
SET_VAR_FIELD(ram_addr, VFC_RAM_ADDR, OP, VFC_OPCODE_RAM_RD);
for (row = ram_defs->base_row;
row < ram_defs->base_row + ram_defs->num_rows; row++) {
SET_VAR_FIELD(ram_addr, VFC_RAM_ADDR, ROW, row);
offset += qed_grc_dump_read_from_vfc(p_hwfn,
p_ptt,
storm,
ram_cmd,
VFC_RAM_CMD_DWORDS,
ram_addr,
VFC_RAM_ADDR_DWORDS,
VFC_RAM_RESP_DWORDS,
dump_buf + offset);
}
return offset;
}
static u32 qed_grc_dump_vfc(struct qed_hwfn *p_hwfn,
struct qed_ptt *p_ptt, u32 *dump_buf, bool dump)
{
u8 storm_id, i;
u32 offset = 0;
for (storm_id = 0; storm_id < MAX_DBG_STORMS; storm_id++) {
if (!qed_grc_is_storm_included(p_hwfn,
(enum dbg_storms)storm_id) ||
!s_storm_defs[storm_id].has_vfc)
continue;
offset += qed_grc_dump_vfc_cam(p_hwfn,
p_ptt,
dump_buf + offset,
dump, storm_id);
for (i = 0; i < NUM_VFC_RAM_TYPES; i++)
offset += qed_grc_dump_vfc_ram(p_hwfn,
p_ptt,
dump_buf + offset,
dump,
storm_id,
&s_vfc_ram_defs[i]);
}
return offset;
}
static u32 qed_grc_dump_rss(struct qed_hwfn *p_hwfn,
struct qed_ptt *p_ptt, u32 *dump_buf, bool dump)
{
struct dbg_tools_data *dev_data = &p_hwfn->dbg_info;
u32 offset = 0;
u8 rss_mem_id;
for (rss_mem_id = 0; rss_mem_id < NUM_RSS_MEM_TYPES; rss_mem_id++) {
u32 rss_addr, num_entries, total_dwords;
struct rss_mem_defs *rss_defs;
u32 addr, num_dwords_to_read;
bool packed;
rss_defs = &s_rss_mem_defs[rss_mem_id];
rss_addr = rss_defs->addr;
num_entries = rss_defs->num_entries[dev_data->chip_id];
total_dwords = (num_entries * rss_defs->entry_width) / 32;
packed = (rss_defs->entry_width == 16);
offset += qed_grc_dump_mem_hdr(p_hwfn,
dump_buf + offset,
dump,
rss_defs->mem_name,
0,
total_dwords,
rss_defs->entry_width,
packed,
rss_defs->type_name, 0);
if (!dump) {
offset += total_dwords;
continue;
}
addr = BYTES_TO_DWORDS(RSS_REG_RSS_RAM_DATA);
while (total_dwords) {
num_dwords_to_read = min_t(u32,
RSS_REG_RSS_RAM_DATA_SIZE,
total_dwords);
qed_wr(p_hwfn, p_ptt, RSS_REG_RSS_RAM_ADDR, rss_addr);
offset += qed_grc_dump_addr_range(p_hwfn,
p_ptt,
dump_buf + offset,
dump,
addr,
num_dwords_to_read,
false,
SPLIT_TYPE_NONE, 0);
total_dwords -= num_dwords_to_read;
rss_addr++;
}
}
return offset;
}
static u32 qed_grc_dump_big_ram(struct qed_hwfn *p_hwfn,
struct qed_ptt *p_ptt,
u32 *dump_buf, bool dump, u8 big_ram_id)
{
struct dbg_tools_data *dev_data = &p_hwfn->dbg_info;
u32 block_size, ram_size, offset = 0, reg_val, i;
char mem_name[12] = "???_BIG_RAM";
char type_name[8] = "???_RAM";
struct big_ram_defs *big_ram;
big_ram = &s_big_ram_defs[big_ram_id];
ram_size = big_ram->ram_size[dev_data->chip_id];
reg_val = qed_rd(p_hwfn, p_ptt, big_ram->is_256b_reg_addr);
block_size = reg_val &
BIT(big_ram->is_256b_bit_offset[dev_data->chip_id]) ? 256
: 128;
strncpy(type_name, big_ram->instance_name, BIG_RAM_NAME_LEN);
strncpy(mem_name, big_ram->instance_name, BIG_RAM_NAME_LEN);
offset += qed_grc_dump_mem_hdr(p_hwfn,
dump_buf + offset,
dump,
mem_name,
0,
ram_size,
block_size * 8,
false, type_name, 0);
if (!dump)
return offset + ram_size;
for (i = 0; i < DIV_ROUND_UP(ram_size, BRB_REG_BIG_RAM_DATA_SIZE);
i++) {
u32 addr, len;
qed_wr(p_hwfn, p_ptt, big_ram->addr_reg_addr, i);
addr = BYTES_TO_DWORDS(big_ram->data_reg_addr);
len = BRB_REG_BIG_RAM_DATA_SIZE;
offset += qed_grc_dump_addr_range(p_hwfn,
p_ptt,
dump_buf + offset,
dump,
addr,
len,
false, SPLIT_TYPE_NONE, 0);
}
return offset;
}
static u32 qed_grc_dump_mcp(struct qed_hwfn *p_hwfn,
struct qed_ptt *p_ptt, u32 *dump_buf, bool dump)
{
bool block_enable[MAX_BLOCK_ID] = { 0 };
u32 offset = 0, addr;
bool halted = false;
if (dump && !qed_grc_get_param(p_hwfn, DBG_GRC_PARAM_NO_MCP)) {
halted = !qed_mcp_halt(p_hwfn, p_ptt);
if (!halted)
DP_NOTICE(p_hwfn, "MCP halt failed!\n");
}
offset += qed_grc_dump_mem(p_hwfn,
p_ptt,
dump_buf + offset,
dump,
NULL,
BYTES_TO_DWORDS(MCP_REG_SCRATCH),
MCP_REG_SCRATCH_SIZE,
false, 0, false, "MCP", 0);
offset += qed_grc_dump_mem(p_hwfn,
p_ptt,
dump_buf + offset,
dump,
NULL,
BYTES_TO_DWORDS(MCP_REG_CPU_REG_FILE),
MCP_REG_CPU_REG_FILE_SIZE,
false, 0, false, "MCP", 0);
block_enable[BLOCK_MCP] = true;
offset += qed_grc_dump_registers(p_hwfn,
p_ptt,
dump_buf + offset,
dump, block_enable, "MCP");
offset += qed_grc_dump_regs_hdr(dump_buf + offset,
dump, 1, SPLIT_TYPE_NONE, 0,
"MCP");
addr = BYTES_TO_DWORDS(MISC_REG_SHARED_MEM_ADDR);
offset += qed_grc_dump_reg_entry(p_hwfn,
p_ptt,
dump_buf + offset,
dump,
addr,
1,
false, SPLIT_TYPE_NONE, 0);
if (halted && qed_mcp_resume(p_hwfn, p_ptt))
DP_NOTICE(p_hwfn, "Failed to resume MCP after halt!\n");
return offset;
}
static u32 qed_grc_dump_phy(struct qed_hwfn *p_hwfn,
struct qed_ptt *p_ptt, u32 *dump_buf, bool dump)
{
u32 offset = 0, tbus_lo_offset, tbus_hi_offset;
char mem_name[32];
u8 phy_id;
for (phy_id = 0; phy_id < ARRAY_SIZE(s_phy_defs); phy_id++) {
u32 addr_lo_addr, addr_hi_addr, data_lo_addr, data_hi_addr;
struct phy_defs *phy_defs;
u8 *bytes_buf;
phy_defs = &s_phy_defs[phy_id];
addr_lo_addr = phy_defs->base_addr +
phy_defs->tbus_addr_lo_addr;
addr_hi_addr = phy_defs->base_addr +
phy_defs->tbus_addr_hi_addr;
data_lo_addr = phy_defs->base_addr +
phy_defs->tbus_data_lo_addr;
data_hi_addr = phy_defs->base_addr +
phy_defs->tbus_data_hi_addr;
if (snprintf(mem_name, sizeof(mem_name), "tbus_%s",
phy_defs->phy_name) < 0)
DP_NOTICE(p_hwfn,
"Unexpected debug error: invalid PHY memory name\n");
offset += qed_grc_dump_mem_hdr(p_hwfn,
dump_buf + offset,
dump,
mem_name,
0,
PHY_DUMP_SIZE_DWORDS,
16, true, mem_name, 0);
if (!dump) {
offset += PHY_DUMP_SIZE_DWORDS;
continue;
}
bytes_buf = (u8 *)(dump_buf + offset);
for (tbus_hi_offset = 0;
tbus_hi_offset < (NUM_PHY_TBUS_ADDRESSES >> 8);
tbus_hi_offset++) {
qed_wr(p_hwfn, p_ptt, addr_hi_addr, tbus_hi_offset);
for (tbus_lo_offset = 0; tbus_lo_offset < 256;
tbus_lo_offset++) {
qed_wr(p_hwfn,
p_ptt, addr_lo_addr, tbus_lo_offset);
*(bytes_buf++) = (u8)qed_rd(p_hwfn,
p_ptt,
data_lo_addr);
*(bytes_buf++) = (u8)qed_rd(p_hwfn,
p_ptt,
data_hi_addr);
}
}
offset += PHY_DUMP_SIZE_DWORDS;
}
return offset;
}
static u32 qed_grc_dump_mcp_hw_dump(struct qed_hwfn *p_hwfn,
struct qed_ptt *p_ptt,
u32 *dump_buf, bool dump)
{
u32 hw_dump_offset_bytes = 0, hw_dump_size_bytes = 0;
u32 hw_dump_size_dwords = 0, offset = 0;
enum dbg_status status;
status = qed_find_nvram_image(p_hwfn,
p_ptt,
NVM_TYPE_HW_DUMP_OUT,
&hw_dump_offset_bytes,
&hw_dump_size_bytes,
false);
if (status != DBG_STATUS_OK)
return 0;
hw_dump_size_dwords = BYTES_TO_DWORDS(hw_dump_size_bytes);
offset += qed_dump_section_hdr(dump_buf + offset,
dump, "mcp_hw_dump", 1);
offset += qed_dump_num_param(dump_buf + offset,
dump, "size", hw_dump_size_dwords);
if (dump && hw_dump_size_dwords) {
status = qed_nvram_read(p_hwfn,
p_ptt,
hw_dump_offset_bytes,
hw_dump_size_bytes,
dump_buf + offset,
false);
if (status != DBG_STATUS_OK) {
DP_NOTICE(p_hwfn,
"Failed to read MCP HW Dump image from NVRAM\n");
return 0;
}
}
offset += hw_dump_size_dwords;
return offset;
}
static u32 qed_grc_dump_static_debug(struct qed_hwfn *p_hwfn,
struct qed_ptt *p_ptt,
u32 *dump_buf, bool dump)
{
struct dbg_tools_data *dev_data = &p_hwfn->dbg_info;
u32 block_id, line_id, offset = 0, addr, len;
if (dump && qed_rd(p_hwfn, p_ptt, DBG_REG_DBG_BLOCK_ON))
return 0;
if (dump) {
qed_bus_disable_blocks(p_hwfn, p_ptt);
qed_bus_reset_dbg_block(p_hwfn, p_ptt);
qed_wr(p_hwfn,
p_ptt, DBG_REG_FRAMING_MODE, DBG_BUS_FRAME_MODE_8HW);
qed_wr(p_hwfn,
p_ptt, DBG_REG_DEBUG_TARGET, DBG_BUS_TARGET_ID_INT_BUF);
qed_wr(p_hwfn, p_ptt, DBG_REG_FULL_MODE, 1);
qed_bus_enable_dbg_block(p_hwfn, p_ptt, true);
}
for (block_id = 0; block_id < MAX_BLOCK_ID; block_id++) {
const struct dbg_block_chip *block_per_chip;
const struct dbg_block *block;
bool is_removed, has_dbg_bus;
u16 modes_buf_offset;
u32 block_dwords;
block_per_chip =
qed_get_dbg_block_per_chip(p_hwfn, (enum block_id)block_id);
is_removed = GET_FIELD(block_per_chip->flags,
DBG_BLOCK_CHIP_IS_REMOVED);
has_dbg_bus = GET_FIELD(block_per_chip->flags,
DBG_BLOCK_CHIP_HAS_DBG_BUS);
if (!is_removed && has_dbg_bus &&
GET_FIELD(block_per_chip->dbg_bus_mode.data,
DBG_MODE_HDR_EVAL_MODE) > 0) {
modes_buf_offset =
GET_FIELD(block_per_chip->dbg_bus_mode.data,
DBG_MODE_HDR_MODES_BUF_OFFSET);
if (!qed_is_mode_match(p_hwfn, &modes_buf_offset))
has_dbg_bus = false;
}
if (is_removed || !has_dbg_bus)
continue;
block_dwords = NUM_DBG_LINES(block_per_chip) *
STATIC_DEBUG_LINE_DWORDS;
block = get_dbg_block(p_hwfn, (enum block_id)block_id);
offset += qed_grc_dump_mem_hdr(p_hwfn,
dump_buf + offset,
dump,
block->name,
0,
block_dwords,
32, false, "STATIC", 0);
if (!dump) {
offset += block_dwords;
continue;
}
if (dev_data->block_in_reset[block_id]) {
memset(dump_buf + offset, 0,
DWORDS_TO_BYTES(block_dwords));
offset += block_dwords;
continue;
}
qed_bus_enable_clients(p_hwfn,
p_ptt,
BIT(block_per_chip->dbg_client_id));
addr = BYTES_TO_DWORDS(DBG_REG_CALENDAR_OUT_DATA);
len = STATIC_DEBUG_LINE_DWORDS;
for (line_id = 0; line_id < (u32)NUM_DBG_LINES(block_per_chip);
line_id++) {
qed_bus_config_dbg_line(p_hwfn,
p_ptt,
(enum block_id)block_id,
(u8)line_id, 0xf, 0, 0, 0);
offset += qed_grc_dump_addr_range(p_hwfn,
p_ptt,
dump_buf + offset,
dump,
addr,
len,
true, SPLIT_TYPE_NONE,
0);
}
qed_bus_enable_clients(p_hwfn, p_ptt, 0);
qed_bus_config_dbg_line(p_hwfn, p_ptt,
(enum block_id)block_id, 0, 0, 0, 0, 0);
}
if (dump) {
qed_bus_enable_dbg_block(p_hwfn, p_ptt, false);
qed_bus_enable_clients(p_hwfn, p_ptt, 0);
}
return offset;
}
static enum dbg_status qed_grc_dump(struct qed_hwfn *p_hwfn,
struct qed_ptt *p_ptt,
u32 *dump_buf,
bool dump, u32 *num_dumped_dwords)
{
struct dbg_tools_data *dev_data = &p_hwfn->dbg_info;
bool parities_masked = false;
u32 dwords_read, offset = 0;
u8 i;
*num_dumped_dwords = 0;
dev_data->num_regs_read = 0;
if (dump)
qed_update_blocks_reset_state(p_hwfn, p_ptt);
offset += qed_dump_common_global_params(p_hwfn,
p_ptt,
dump_buf + offset, dump, 4);
offset += qed_dump_str_param(dump_buf + offset,
dump, "dump-type", "grc-dump");
offset += qed_dump_num_param(dump_buf + offset,
dump,
"num-lcids",
NUM_OF_LCIDS);
offset += qed_dump_num_param(dump_buf + offset,
dump,
"num-ltids",
NUM_OF_LTIDS);
offset += qed_dump_num_param(dump_buf + offset,
dump, "num-ports", dev_data->num_ports);
if (qed_grc_is_included(p_hwfn, DBG_GRC_PARAM_DUMP_REGS))
offset += qed_grc_dump_reset_regs(p_hwfn,
p_ptt,
dump_buf + offset, dump);
if (dump) {
qed_grc_unreset_blocks(p_hwfn, p_ptt, false);
qed_update_blocks_reset_state(p_hwfn, p_ptt);
}
if (dump &&
!qed_grc_get_param(p_hwfn, DBG_GRC_PARAM_NO_MCP)) {
parities_masked = !qed_mcp_mask_parities(p_hwfn, p_ptt, 1);
if (!parities_masked) {
DP_NOTICE(p_hwfn,
"Failed to mask parities using MFW\n");
if (qed_grc_get_param
(p_hwfn, DBG_GRC_PARAM_PARITY_SAFE))
return DBG_STATUS_MCP_COULD_NOT_MASK_PRTY;
}
}
if (qed_grc_is_included(p_hwfn, DBG_GRC_PARAM_DUMP_REGS))
offset += qed_grc_dump_modified_regs(p_hwfn,
p_ptt,
dump_buf + offset, dump);
if (dump &&
(qed_grc_is_included(p_hwfn,
DBG_GRC_PARAM_DUMP_IOR) ||
qed_grc_is_included(p_hwfn, DBG_GRC_PARAM_DUMP_VFC)))
qed_grc_stall_storms(p_hwfn, p_ptt, true);
if (qed_grc_is_included(p_hwfn, DBG_GRC_PARAM_DUMP_REGS)) {
bool block_enable[MAX_BLOCK_ID];
for (i = 0; i < MAX_BLOCK_ID; i++)
block_enable[i] = true;
block_enable[BLOCK_MCP] = false;
offset += qed_grc_dump_registers(p_hwfn,
p_ptt,
dump_buf +
offset,
dump,
block_enable, NULL);
offset += qed_grc_dump_special_regs(p_hwfn,
p_ptt,
dump_buf + offset, dump);
}
offset += qed_grc_dump_memories(p_hwfn, p_ptt, dump_buf + offset, dump);
if (qed_grc_is_included(p_hwfn, DBG_GRC_PARAM_DUMP_MCP))
offset += qed_grc_dump_mcp(p_hwfn,
p_ptt, dump_buf + offset, dump);
if (qed_grc_is_included(p_hwfn, DBG_GRC_PARAM_DUMP_CM_CTX))
offset += qed_grc_dump_ctx(p_hwfn,
p_ptt, dump_buf + offset, dump);
if (qed_grc_is_included(p_hwfn, DBG_GRC_PARAM_DUMP_RSS))
offset += qed_grc_dump_rss(p_hwfn,
p_ptt, dump_buf + offset, dump);
for (i = 0; i < NUM_BIG_RAM_TYPES; i++)
if (qed_grc_is_included(p_hwfn, s_big_ram_defs[i].grc_param))
offset += qed_grc_dump_big_ram(p_hwfn,
p_ptt,
dump_buf + offset,
dump, i);
if (qed_grc_is_included(p_hwfn, DBG_GRC_PARAM_DUMP_VFC)) {
dwords_read = qed_grc_dump_vfc(p_hwfn,
p_ptt, dump_buf + offset, dump);
offset += dwords_read;
if (!dwords_read)
return DBG_STATUS_VFC_READ_ERROR;
}
if (qed_grc_is_included(p_hwfn,
DBG_GRC_PARAM_DUMP_PHY) && dev_data->chip_id ==
CHIP_K2 && dev_data->hw_type == HW_TYPE_ASIC)
offset += qed_grc_dump_phy(p_hwfn,
p_ptt, dump_buf + offset, dump);
if (qed_grc_is_included(p_hwfn, DBG_GRC_PARAM_DUMP_MCP_HW_DUMP) &&
!qed_grc_get_param(p_hwfn, DBG_GRC_PARAM_NO_MCP) && 1)
offset += qed_grc_dump_mcp_hw_dump(p_hwfn,
p_ptt,
dump_buf + offset, dump);
if (qed_grc_is_included(p_hwfn,
DBG_GRC_PARAM_DUMP_STATIC) &&
(!dump || dev_data->bus.state == DBG_BUS_STATE_IDLE))
offset += qed_grc_dump_static_debug(p_hwfn,
p_ptt,
dump_buf + offset, dump);
offset += qed_dump_last_section(dump_buf, offset, dump);
if (dump) {
if (qed_grc_get_param(p_hwfn, DBG_GRC_PARAM_UNSTALL))
qed_grc_stall_storms(p_hwfn, p_ptt, false);
qed_grc_clear_all_prty(p_hwfn, p_ptt);
if (parities_masked)
qed_mcp_mask_parities(p_hwfn, p_ptt, 0);
}
*num_dumped_dwords = offset;
return DBG_STATUS_OK;
}
static u32 qed_idle_chk_dump_failure(struct qed_hwfn *p_hwfn,
struct qed_ptt *p_ptt,
u32 *dump_buf,
bool dump,
u16 rule_id,
const struct dbg_idle_chk_rule *rule,
u16 fail_entry_id, u32 *cond_reg_values)
{
struct dbg_tools_data *dev_data = &p_hwfn->dbg_info;
const struct dbg_idle_chk_cond_reg *cond_regs;
const struct dbg_idle_chk_info_reg *info_regs;
u32 i, next_reg_offset = 0, offset = 0;
struct dbg_idle_chk_result_hdr *hdr;
const union dbg_idle_chk_reg *regs;
u8 reg_id;
hdr = (struct dbg_idle_chk_result_hdr *)dump_buf;
regs = (const union dbg_idle_chk_reg *)
p_hwfn->dbg_arrays[BIN_BUF_DBG_IDLE_CHK_REGS].ptr +
rule->reg_offset;
cond_regs = ®s[0].cond_reg;
info_regs = ®s[rule->num_cond_regs].info_reg;
if (dump) {
memset(hdr, 0, sizeof(*hdr));
hdr->rule_id = rule_id;
hdr->mem_entry_id = fail_entry_id;
hdr->severity = rule->severity;
hdr->num_dumped_cond_regs = rule->num_cond_regs;
}
offset += IDLE_CHK_RESULT_HDR_DWORDS;
for (reg_id = 0; reg_id < rule->num_cond_regs; reg_id++) {
const struct dbg_idle_chk_cond_reg *reg = &cond_regs[reg_id];
struct dbg_idle_chk_result_reg_hdr *reg_hdr;
reg_hdr =
(struct dbg_idle_chk_result_reg_hdr *)(dump_buf + offset);
if (!dump) {
offset += IDLE_CHK_RESULT_REG_HDR_DWORDS +
reg->entry_size;
continue;
}
offset += IDLE_CHK_RESULT_REG_HDR_DWORDS;
memset(reg_hdr, 0, sizeof(*reg_hdr));
reg_hdr->start_entry = reg->start_entry;
reg_hdr->size = reg->entry_size;
SET_FIELD(reg_hdr->data,
DBG_IDLE_CHK_RESULT_REG_HDR_IS_MEM,
reg->num_entries > 1 || reg->start_entry > 0 ? 1 : 0);
SET_FIELD(reg_hdr->data,
DBG_IDLE_CHK_RESULT_REG_HDR_REG_ID, reg_id);
for (i = 0; i < reg_hdr->size; i++, next_reg_offset++, offset++)
dump_buf[offset] = cond_reg_values[next_reg_offset];
}
for (reg_id = 0; reg_id < rule->num_info_regs; reg_id++) {
const struct dbg_idle_chk_info_reg *reg = &info_regs[reg_id];
u32 block_id;
if (!dump) {
offset += IDLE_CHK_RESULT_REG_HDR_DWORDS + reg->size;
continue;
}
block_id = GET_FIELD(reg->data, DBG_IDLE_CHK_INFO_REG_BLOCK_ID);
if (block_id >= MAX_BLOCK_ID) {
DP_NOTICE(p_hwfn, "Invalid block_id\n");
return 0;
}
if (!dev_data->block_in_reset[block_id]) {
struct dbg_idle_chk_result_reg_hdr *reg_hdr;
bool wide_bus, eval_mode, mode_match = true;
u16 modes_buf_offset;
u32 addr;
reg_hdr = (struct dbg_idle_chk_result_reg_hdr *)
(dump_buf + offset);
eval_mode = GET_FIELD(reg->mode.data,
DBG_MODE_HDR_EVAL_MODE) > 0;
if (eval_mode) {
modes_buf_offset =
GET_FIELD(reg->mode.data,
DBG_MODE_HDR_MODES_BUF_OFFSET);
mode_match =
qed_is_mode_match(p_hwfn,
&modes_buf_offset);
}
if (!mode_match)
continue;
addr = GET_FIELD(reg->data,
DBG_IDLE_CHK_INFO_REG_ADDRESS);
wide_bus = GET_FIELD(reg->data,
DBG_IDLE_CHK_INFO_REG_WIDE_BUS);
offset += IDLE_CHK_RESULT_REG_HDR_DWORDS;
hdr->num_dumped_info_regs++;
memset(reg_hdr, 0, sizeof(*reg_hdr));
reg_hdr->size = reg->size;
SET_FIELD(reg_hdr->data,
DBG_IDLE_CHK_RESULT_REG_HDR_REG_ID,
rule->num_cond_regs + reg_id);
offset += qed_grc_dump_addr_range(p_hwfn,
p_ptt,
dump_buf + offset,
dump,
addr,
reg->size, wide_bus,
SPLIT_TYPE_NONE, 0);
}
}
return offset;
}
static u32
qed_idle_chk_dump_rule_entries(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt,
u32 *dump_buf, bool dump,
const struct dbg_idle_chk_rule *input_rules,
u32 num_input_rules, u32 *num_failing_rules)
{
struct dbg_tools_data *dev_data = &p_hwfn->dbg_info;
u32 cond_reg_values[IDLE_CHK_MAX_ENTRIES_SIZE];
u32 i, offset = 0;
u16 entry_id;
u8 reg_id;
*num_failing_rules = 0;
for (i = 0; i < num_input_rules; i++) {
const struct dbg_idle_chk_cond_reg *cond_regs;
const struct dbg_idle_chk_rule *rule;
const union dbg_idle_chk_reg *regs;
u16 num_reg_entries = 1;
bool check_rule = true;
const u32 *imm_values;
rule = &input_rules[i];
regs = (const union dbg_idle_chk_reg *)
p_hwfn->dbg_arrays[BIN_BUF_DBG_IDLE_CHK_REGS].ptr +
rule->reg_offset;
cond_regs = ®s[0].cond_reg;
imm_values =
(u32 *)p_hwfn->dbg_arrays[BIN_BUF_DBG_IDLE_CHK_IMMS].ptr +
rule->imm_offset;
for (reg_id = 0; reg_id < rule->num_cond_regs && check_rule;
reg_id++) {
u32 block_id =
GET_FIELD(cond_regs[reg_id].data,
DBG_IDLE_CHK_COND_REG_BLOCK_ID);
if (block_id >= MAX_BLOCK_ID) {
DP_NOTICE(p_hwfn, "Invalid block_id\n");
return 0;
}
check_rule = !dev_data->block_in_reset[block_id];
if (cond_regs[reg_id].num_entries > num_reg_entries)
num_reg_entries = cond_regs[reg_id].num_entries;
}
if (!check_rule && dump)
continue;
if (!dump) {
u32 entry_dump_size =
qed_idle_chk_dump_failure(p_hwfn,
p_ptt,
dump_buf + offset,
false,
rule->rule_id,
rule,
0,
NULL);
offset += num_reg_entries * entry_dump_size;
(*num_failing_rules) += num_reg_entries;
continue;
}
for (entry_id = 0; entry_id < num_reg_entries; entry_id++) {
u32 next_reg_offset = 0;
for (reg_id = 0; reg_id < rule->num_cond_regs;
reg_id++) {
const struct dbg_idle_chk_cond_reg *reg =
&cond_regs[reg_id];
u32 padded_entry_size, addr;
bool wide_bus;
addr = GET_FIELD(reg->data,
DBG_IDLE_CHK_COND_REG_ADDRESS);
wide_bus =
GET_FIELD(reg->data,
DBG_IDLE_CHK_COND_REG_WIDE_BUS);
if (reg->num_entries > 1 ||
reg->start_entry > 0) {
padded_entry_size =
reg->entry_size > 1 ?
roundup_pow_of_two(reg->entry_size) :
1;
addr += (reg->start_entry + entry_id) *
padded_entry_size;
}
if (next_reg_offset + reg->entry_size >=
IDLE_CHK_MAX_ENTRIES_SIZE) {
DP_NOTICE(p_hwfn,
"idle check registers entry is too large\n");
return 0;
}
next_reg_offset +=
qed_grc_dump_addr_range(p_hwfn, p_ptt,
cond_reg_values +
next_reg_offset,
dump, addr,
reg->entry_size,
wide_bus,
SPLIT_TYPE_NONE, 0);
}
if ((*cond_arr[rule->cond_id]) (cond_reg_values,
imm_values)) {
offset += qed_idle_chk_dump_failure(p_hwfn,
p_ptt,
dump_buf + offset,
dump,
rule->rule_id,
rule,
entry_id,
cond_reg_values);
(*num_failing_rules)++;
}
}
}
return offset;
}
static u32 qed_idle_chk_dump(struct qed_hwfn *p_hwfn,
struct qed_ptt *p_ptt, u32 *dump_buf, bool dump)
{
struct virt_mem_desc *dbg_buf =
&p_hwfn->dbg_arrays[BIN_BUF_DBG_IDLE_CHK_RULES];
u32 num_failing_rules_offset, offset = 0,
input_offset = 0, num_failing_rules = 0;
offset += qed_dump_common_global_params(p_hwfn,
p_ptt,
dump_buf + offset, dump, 1);
offset += qed_dump_str_param(dump_buf + offset,
dump, "dump-type", "idle-chk");
offset += qed_dump_section_hdr(dump_buf + offset, dump, "idle_chk", 1);
num_failing_rules_offset = offset;
offset += qed_dump_num_param(dump_buf + offset, dump, "num_rules", 0);
while (input_offset < BYTES_TO_DWORDS(dbg_buf->size)) {
const struct dbg_idle_chk_cond_hdr *cond_hdr =
(const struct dbg_idle_chk_cond_hdr *)dbg_buf->ptr +
input_offset++;
bool eval_mode, mode_match = true;
u32 curr_failing_rules;
u16 modes_buf_offset;
eval_mode = GET_FIELD(cond_hdr->mode.data,
DBG_MODE_HDR_EVAL_MODE) > 0;
if (eval_mode) {
modes_buf_offset =
GET_FIELD(cond_hdr->mode.data,
DBG_MODE_HDR_MODES_BUF_OFFSET);
mode_match = qed_is_mode_match(p_hwfn,
&modes_buf_offset);
}
if (mode_match) {
const struct dbg_idle_chk_rule *rule =
(const struct dbg_idle_chk_rule *)((u32 *)
dbg_buf->ptr
+ input_offset);
u32 num_input_rules =
cond_hdr->data_size / IDLE_CHK_RULE_SIZE_DWORDS;
offset +=
qed_idle_chk_dump_rule_entries(p_hwfn,
p_ptt,
dump_buf +
offset,
dump,
rule,
num_input_rules,
&curr_failing_rules);
num_failing_rules += curr_failing_rules;
}
input_offset += cond_hdr->data_size;
}
if (dump)
qed_dump_num_param(dump_buf + num_failing_rules_offset,
dump, "num_rules", num_failing_rules);
offset += qed_dump_last_section(dump_buf, offset, dump);
return offset;
}
static enum dbg_status qed_mcp_trace_get_data_info(struct qed_hwfn *p_hwfn,
struct qed_ptt *p_ptt,
u32 *trace_data_grc_addr,
u32 *trace_data_size)
{
u32 spad_trace_offsize, signature;
spad_trace_offsize = qed_rd(p_hwfn, p_ptt, MCP_SPAD_TRACE_OFFSIZE_ADDR);
*trace_data_grc_addr =
MCP_REG_SCRATCH + SECTION_OFFSET(spad_trace_offsize);
signature = qed_rd(p_hwfn, p_ptt,
*trace_data_grc_addr +
offsetof(struct mcp_trace, signature));
if (signature != MFW_TRACE_SIGNATURE)
return DBG_STATUS_INVALID_TRACE_SIGNATURE;
*trace_data_size = qed_rd(p_hwfn,
p_ptt,
*trace_data_grc_addr +
offsetof(struct mcp_trace, size));
return DBG_STATUS_OK;
}
static enum dbg_status qed_mcp_trace_get_meta_info(struct qed_hwfn *p_hwfn,
struct qed_ptt *p_ptt,
u32 trace_data_size_bytes,
u32 *running_bundle_id,
u32 *trace_meta_offset,
u32 *trace_meta_size)
{
u32 spad_trace_offsize, nvram_image_type, running_mfw_addr;
spad_trace_offsize = qed_rd(p_hwfn, p_ptt, MCP_SPAD_TRACE_OFFSIZE_ADDR);
running_mfw_addr =
MCP_REG_SCRATCH + SECTION_OFFSET(spad_trace_offsize) +
QED_SECTION_SIZE(spad_trace_offsize) + trace_data_size_bytes;
*running_bundle_id = qed_rd(p_hwfn, p_ptt, running_mfw_addr);
if (*running_bundle_id > 1)
return DBG_STATUS_INVALID_NVRAM_BUNDLE;
nvram_image_type =
(*running_bundle_id ==
DIR_ID_1) ? NVM_TYPE_MFW_TRACE1 : NVM_TYPE_MFW_TRACE2;
return qed_find_nvram_image(p_hwfn,
p_ptt,
nvram_image_type,
trace_meta_offset,
trace_meta_size,
true);
}
static enum dbg_status qed_mcp_trace_read_meta(struct qed_hwfn *p_hwfn,
struct qed_ptt *p_ptt,
u32 nvram_offset_in_bytes,
u32 size_in_bytes, u32 *buf)
{
u8 modules_num, module_len, i, *byte_buf = (u8 *)buf;
enum dbg_status status;
u32 signature;
status = qed_nvram_read(p_hwfn,
p_ptt,
nvram_offset_in_bytes,
size_in_bytes,
buf,
true);
if (status != DBG_STATUS_OK)
return status;
signature = qed_read_unaligned_dword(byte_buf);
byte_buf += sizeof(signature);
if (signature != NVM_MAGIC_VALUE)
return DBG_STATUS_INVALID_TRACE_SIGNATURE;
modules_num = *(byte_buf++);
for (i = 0; i < modules_num; i++) {
module_len = *(byte_buf++);
byte_buf += module_len;
}
signature = qed_read_unaligned_dword(byte_buf);
byte_buf += sizeof(signature);
if (signature != NVM_MAGIC_VALUE)
return DBG_STATUS_INVALID_TRACE_SIGNATURE;
return DBG_STATUS_OK;
}
static enum dbg_status qed_mcp_trace_dump(struct qed_hwfn *p_hwfn,
struct qed_ptt *p_ptt,
u32 *dump_buf,
bool dump, u32 *num_dumped_dwords)
{
u32 trace_data_grc_addr, trace_data_size_bytes, trace_data_size_dwords;
u32 trace_meta_size_dwords = 0, running_bundle_id, offset = 0;
u32 trace_meta_offset_bytes = 0, trace_meta_size_bytes = 0;
enum dbg_status status;
int halted = 0;
bool use_mfw;
*num_dumped_dwords = 0;
use_mfw = !qed_grc_get_param(p_hwfn, DBG_GRC_PARAM_NO_MCP);
status = qed_mcp_trace_get_data_info(p_hwfn,
p_ptt,
&trace_data_grc_addr,
&trace_data_size_bytes);
if (status != DBG_STATUS_OK)
return status;
offset += qed_dump_common_global_params(p_hwfn,
p_ptt,
dump_buf + offset, dump, 1);
offset += qed_dump_str_param(dump_buf + offset,
dump, "dump-type", "mcp-trace");
if (dump && use_mfw) {
halted = !qed_mcp_halt(p_hwfn, p_ptt);
if (!halted)
DP_NOTICE(p_hwfn, "MCP halt failed!\n");
}
trace_data_size_dwords =
DIV_ROUND_UP(trace_data_size_bytes + sizeof(struct mcp_trace),
BYTES_IN_DWORD);
offset += qed_dump_section_hdr(dump_buf + offset,
dump, "mcp_trace_data", 1);
offset += qed_dump_num_param(dump_buf + offset,
dump, "size", trace_data_size_dwords);
offset += qed_grc_dump_addr_range(p_hwfn,
p_ptt,
dump_buf + offset,
dump,
BYTES_TO_DWORDS(trace_data_grc_addr),
trace_data_size_dwords, false,
SPLIT_TYPE_NONE, 0);
if (halted && qed_mcp_resume(p_hwfn, p_ptt))
DP_NOTICE(p_hwfn, "Failed to resume MCP after halt!\n");
offset += qed_dump_section_hdr(dump_buf + offset,
dump, "mcp_trace_meta", 1);
trace_meta_size_bytes =
qed_grc_get_param(p_hwfn, DBG_GRC_PARAM_MCP_TRACE_META_SIZE);
if ((!trace_meta_size_bytes || dump) && use_mfw)
status = qed_mcp_trace_get_meta_info(p_hwfn,
p_ptt,
trace_data_size_bytes,
&running_bundle_id,
&trace_meta_offset_bytes,
&trace_meta_size_bytes);
if (status == DBG_STATUS_OK)
trace_meta_size_dwords = BYTES_TO_DWORDS(trace_meta_size_bytes);
offset += qed_dump_num_param(dump_buf + offset,
dump, "size", trace_meta_size_dwords);
if (dump && trace_meta_size_dwords)
status = qed_mcp_trace_read_meta(p_hwfn,
p_ptt,
trace_meta_offset_bytes,
trace_meta_size_bytes,
dump_buf + offset);
if (status == DBG_STATUS_OK)
offset += trace_meta_size_dwords;
offset += qed_dump_last_section(dump_buf, offset, dump);
*num_dumped_dwords = offset;
return use_mfw ? status : DBG_STATUS_NVRAM_GET_IMAGE_FAILED;
}
static enum dbg_status qed_reg_fifo_dump(struct qed_hwfn *p_hwfn,
struct qed_ptt *p_ptt,
u32 *dump_buf,
bool dump, u32 *num_dumped_dwords)
{
u32 dwords_read, size_param_offset, offset = 0, addr, len;
bool fifo_has_data;
*num_dumped_dwords = 0;
offset += qed_dump_common_global_params(p_hwfn,
p_ptt,
dump_buf + offset, dump, 1);
offset += qed_dump_str_param(dump_buf + offset,
dump, "dump-type", "reg-fifo");
offset += qed_dump_section_hdr(dump_buf + offset,
dump, "reg_fifo_data", 1);
size_param_offset = offset;
offset += qed_dump_num_param(dump_buf + offset, dump, "size", 0);
if (!dump) {
offset += REG_FIFO_DEPTH_DWORDS;
goto out;
}
fifo_has_data = qed_rd(p_hwfn, p_ptt,
GRC_REG_TRACE_FIFO_VALID_DATA) > 0;
addr = BYTES_TO_DWORDS(GRC_REG_TRACE_FIFO);
len = REG_FIFO_ELEMENT_DWORDS;
for (dwords_read = 0;
fifo_has_data && dwords_read < REG_FIFO_DEPTH_DWORDS;
dwords_read += REG_FIFO_ELEMENT_DWORDS) {
offset += qed_grc_dump_addr_range(p_hwfn,
p_ptt,
dump_buf + offset,
true,
addr,
len,
true, SPLIT_TYPE_NONE,
0);
fifo_has_data = qed_rd(p_hwfn, p_ptt,
GRC_REG_TRACE_FIFO_VALID_DATA) > 0;
}
qed_dump_num_param(dump_buf + size_param_offset, dump, "size",
dwords_read);
out:
offset += qed_dump_last_section(dump_buf, offset, dump);
*num_dumped_dwords = offset;
return DBG_STATUS_OK;
}
static enum dbg_status qed_igu_fifo_dump(struct qed_hwfn *p_hwfn,
struct qed_ptt *p_ptt,
u32 *dump_buf,
bool dump, u32 *num_dumped_dwords)
{
u32 dwords_read, size_param_offset, offset = 0, addr, len;
bool fifo_has_data;
*num_dumped_dwords = 0;
offset += qed_dump_common_global_params(p_hwfn,
p_ptt,
dump_buf + offset, dump, 1);
offset += qed_dump_str_param(dump_buf + offset,
dump, "dump-type", "igu-fifo");
offset += qed_dump_section_hdr(dump_buf + offset,
dump, "igu_fifo_data", 1);
size_param_offset = offset;
offset += qed_dump_num_param(dump_buf + offset, dump, "size", 0);
if (!dump) {
offset += IGU_FIFO_DEPTH_DWORDS;
goto out;
}
fifo_has_data = qed_rd(p_hwfn, p_ptt,
IGU_REG_ERROR_HANDLING_DATA_VALID) > 0;
addr = BYTES_TO_DWORDS(IGU_REG_ERROR_HANDLING_MEMORY);
len = IGU_FIFO_ELEMENT_DWORDS;
for (dwords_read = 0;
fifo_has_data && dwords_read < IGU_FIFO_DEPTH_DWORDS;
dwords_read += IGU_FIFO_ELEMENT_DWORDS) {
offset += qed_grc_dump_addr_range(p_hwfn,
p_ptt,
dump_buf + offset,
true,
addr,
len,
true, SPLIT_TYPE_NONE,
0);
fifo_has_data = qed_rd(p_hwfn, p_ptt,
IGU_REG_ERROR_HANDLING_DATA_VALID) > 0;
}
qed_dump_num_param(dump_buf + size_param_offset, dump, "size",
dwords_read);
out:
offset += qed_dump_last_section(dump_buf, offset, dump);
*num_dumped_dwords = offset;
return DBG_STATUS_OK;
}
static enum dbg_status qed_protection_override_dump(struct qed_hwfn *p_hwfn,
struct qed_ptt *p_ptt,
u32 *dump_buf,
bool dump,
u32 *num_dumped_dwords)
{
u32 size_param_offset, override_window_dwords, offset = 0, addr;
*num_dumped_dwords = 0;
offset += qed_dump_common_global_params(p_hwfn,
p_ptt,
dump_buf + offset, dump, 1);
offset += qed_dump_str_param(dump_buf + offset,
dump, "dump-type", "protection-override");
offset += qed_dump_section_hdr(dump_buf + offset,
dump, "protection_override_data", 1);
size_param_offset = offset;
offset += qed_dump_num_param(dump_buf + offset, dump, "size", 0);
if (!dump) {
offset += PROTECTION_OVERRIDE_DEPTH_DWORDS;
goto out;
}
override_window_dwords =
qed_rd(p_hwfn, p_ptt, GRC_REG_NUMBER_VALID_OVERRIDE_WINDOW) *
PROTECTION_OVERRIDE_ELEMENT_DWORDS;
if (override_window_dwords) {
addr = BYTES_TO_DWORDS(GRC_REG_PROTECTION_OVERRIDE_WINDOW);
offset += qed_grc_dump_addr_range(p_hwfn,
p_ptt,
dump_buf + offset,
true,
addr,
override_window_dwords,
true, SPLIT_TYPE_NONE, 0);
qed_dump_num_param(dump_buf + size_param_offset, dump, "size",
override_window_dwords);
}
out:
offset += qed_dump_last_section(dump_buf, offset, dump);
*num_dumped_dwords = offset;
return DBG_STATUS_OK;
}
static u32 qed_fw_asserts_dump(struct qed_hwfn *p_hwfn,
struct qed_ptt *p_ptt, u32 *dump_buf, bool dump)
{
struct dbg_tools_data *dev_data = &p_hwfn->dbg_info;
struct fw_asserts_ram_section *asserts;
char storm_letter_str[2] = "?";
struct fw_info fw_info;
u32 offset = 0;
u8 storm_id;
offset += qed_dump_common_global_params(p_hwfn,
p_ptt,
dump_buf + offset, dump, 1);
offset += qed_dump_str_param(dump_buf + offset,
dump, "dump-type", "fw-asserts");
for (storm_id = 0; storm_id < MAX_DBG_STORMS; storm_id++) {
u32 fw_asserts_section_addr, next_list_idx_addr, next_list_idx;
struct storm_defs *storm = &s_storm_defs[storm_id];
u32 last_list_idx, addr;
if (dev_data->block_in_reset[storm->sem_block_id])
continue;
qed_read_storm_fw_info(p_hwfn, p_ptt, storm_id, &fw_info);
asserts = &fw_info.fw_asserts_section;
storm_letter_str[0] = storm->letter;
offset += qed_dump_section_hdr(dump_buf + offset,
dump, "fw_asserts", 2);
offset += qed_dump_str_param(dump_buf + offset,
dump, "storm", storm_letter_str);
offset += qed_dump_num_param(dump_buf + offset,
dump,
"size",
asserts->list_element_dword_size);
if (!dump) {
offset += asserts->list_element_dword_size;
continue;
}
addr = le16_to_cpu(asserts->section_ram_line_offset);
fw_asserts_section_addr = storm->sem_fast_mem_addr +
SEM_FAST_REG_INT_RAM +
RAM_LINES_TO_BYTES(addr);
next_list_idx_addr = fw_asserts_section_addr +
DWORDS_TO_BYTES(asserts->list_next_index_dword_offset);
next_list_idx = qed_rd(p_hwfn, p_ptt, next_list_idx_addr);
last_list_idx = (next_list_idx > 0 ?
next_list_idx :
asserts->list_num_elements) - 1;
addr = BYTES_TO_DWORDS(fw_asserts_section_addr) +
asserts->list_dword_offset +
last_list_idx * asserts->list_element_dword_size;
offset +=
qed_grc_dump_addr_range(p_hwfn, p_ptt,
dump_buf + offset,
dump, addr,
asserts->list_element_dword_size,
false, SPLIT_TYPE_NONE, 0);
}
offset += qed_dump_last_section(dump_buf, offset, dump);
return offset;
}
static u32 qed_ilt_dump_pages_range(u32 *dump_buf, u32 *given_offset,
bool *dump, u32 start_page_id,
u32 num_pages,
struct phys_mem_desc *ilt_pages,
bool dump_page_ids, u32 buf_size_in_dwords,
u32 *given_actual_dump_size_in_dwords)
{
u32 actual_dump_size_in_dwords = *given_actual_dump_size_in_dwords;
u32 page_id, end_page_id, offset = *given_offset;
struct phys_mem_desc *mem_desc = NULL;
bool continue_dump = *dump;
u32 partial_page_size = 0;
if (num_pages == 0)
return offset;
end_page_id = start_page_id + num_pages - 1;
for (page_id = start_page_id; page_id <= end_page_id; page_id++) {
mem_desc = &ilt_pages[page_id];
if (!ilt_pages[page_id].virt_addr)
continue;
if (dump_page_ids) {
if ((continue_dump) &&
(offset + 1 > buf_size_in_dwords)) {
continue_dump = false;
actual_dump_size_in_dwords = offset;
}
if (continue_dump)
*(dump_buf + offset) = page_id;
offset++;
} else {
if ((continue_dump) &&
(offset + BYTES_TO_DWORDS(mem_desc->size) >
buf_size_in_dwords)) {
if (offset + BYTES_TO_DWORDS(mem_desc->size) >
buf_size_in_dwords) {
partial_page_size =
buf_size_in_dwords - offset;
memcpy(dump_buf + offset,
mem_desc->virt_addr,
partial_page_size);
continue_dump = false;
actual_dump_size_in_dwords =
offset + partial_page_size;
}
}
if (continue_dump)
memcpy(dump_buf + offset,
mem_desc->virt_addr, mem_desc->size);
offset += BYTES_TO_DWORDS(mem_desc->size);
}
}
*dump = continue_dump;
*given_offset = offset;
*given_actual_dump_size_in_dwords = actual_dump_size_in_dwords;
return offset;
}
static u32 qed_ilt_dump_pages_section(struct qed_hwfn *p_hwfn,
u32 *dump_buf,
u32 *given_offset,
bool *dump,
u32 valid_conn_pf_pages,
u32 valid_conn_vf_pages,
struct phys_mem_desc *ilt_pages,
bool dump_page_ids,
u32 buf_size_in_dwords,
u32 *given_actual_dump_size_in_dwords)
{
struct qed_ilt_client_cfg *clients = p_hwfn->p_cxt_mngr->clients;
u32 pf_start_line, start_page_id, offset = *given_offset;
u32 cdut_pf_init_pages, cdut_vf_init_pages;
u32 cdut_pf_work_pages, cdut_vf_work_pages;
u32 base_data_offset, size_param_offset;
u32 src_pages;
u32 section_header_and_param_size;
u32 cdut_pf_pages, cdut_vf_pages;
u32 actual_dump_size_in_dwords;
bool continue_dump = *dump;
bool update_size = *dump;
const char *section_name;
u32 i;
actual_dump_size_in_dwords = *given_actual_dump_size_in_dwords;
section_name = dump_page_ids ? "ilt_page_ids" : "ilt_page_mem";
cdut_pf_init_pages = qed_get_cdut_num_pf_init_pages(p_hwfn);
cdut_vf_init_pages = qed_get_cdut_num_vf_init_pages(p_hwfn);
cdut_pf_work_pages = qed_get_cdut_num_pf_work_pages(p_hwfn);
cdut_vf_work_pages = qed_get_cdut_num_vf_work_pages(p_hwfn);
cdut_pf_pages = cdut_pf_init_pages + cdut_pf_work_pages;
cdut_vf_pages = cdut_vf_init_pages + cdut_vf_work_pages;
pf_start_line = p_hwfn->p_cxt_mngr->pf_start_line;
section_header_and_param_size = qed_dump_section_hdr(NULL,
false,
section_name,
1) +
qed_dump_num_param(NULL, false, "size", 0);
if ((continue_dump) &&
(offset + section_header_and_param_size > buf_size_in_dwords)) {
continue_dump = false;
update_size = false;
actual_dump_size_in_dwords = offset;
}
offset += qed_dump_section_hdr(dump_buf + offset,
continue_dump, section_name, 1);
size_param_offset = offset;
offset += qed_dump_num_param(dump_buf + offset,
continue_dump, "size", 0);
base_data_offset = offset;
if (qed_grc_get_param(p_hwfn, DBG_GRC_PARAM_DUMP_ILT_CDUC)) {
start_page_id = clients[ILT_CLI_CDUC].first.val - pf_start_line;
qed_ilt_dump_pages_range(dump_buf, &offset, &continue_dump,
start_page_id, valid_conn_pf_pages,
ilt_pages, dump_page_ids,
buf_size_in_dwords,
&actual_dump_size_in_dwords);
start_page_id += clients[ILT_CLI_CDUC].pf_total_lines;
for (i = 0; i < p_hwfn->p_cxt_mngr->vf_count;
i++, start_page_id += clients[ILT_CLI_CDUC].vf_total_lines)
qed_ilt_dump_pages_range(dump_buf, &offset,
&continue_dump, start_page_id,
valid_conn_vf_pages,
ilt_pages, dump_page_ids,
buf_size_in_dwords,
&actual_dump_size_in_dwords);
}
if (qed_grc_get_param(p_hwfn, DBG_GRC_PARAM_DUMP_ILT_CDUT)) {
start_page_id = clients[ILT_CLI_CDUT].first.val +
cdut_pf_init_pages - pf_start_line;
qed_ilt_dump_pages_range(dump_buf, &offset, &continue_dump,
start_page_id, cdut_pf_work_pages,
ilt_pages, dump_page_ids,
buf_size_in_dwords,
&actual_dump_size_in_dwords);
start_page_id = clients[ILT_CLI_CDUT].first.val +
cdut_pf_pages + cdut_vf_init_pages - pf_start_line;
for (i = 0; i < p_hwfn->p_cxt_mngr->vf_count;
i++, start_page_id += cdut_vf_pages)
qed_ilt_dump_pages_range(dump_buf, &offset,
&continue_dump, start_page_id,
cdut_vf_work_pages, ilt_pages,
dump_page_ids,
buf_size_in_dwords,
&actual_dump_size_in_dwords);
}
if (clients[ILT_CLI_SRC].active) {
start_page_id = clients[ILT_CLI_SRC].first.val - pf_start_line;
src_pages = clients[ILT_CLI_SRC].last.val -
clients[ILT_CLI_SRC].first.val + 1;
qed_ilt_dump_pages_range(dump_buf, &offset, &continue_dump,
start_page_id, src_pages, ilt_pages,
dump_page_ids, buf_size_in_dwords,
&actual_dump_size_in_dwords);
}
if (update_size) {
u32 section_size = (*dump == continue_dump) ?
offset - base_data_offset :
actual_dump_size_in_dwords - base_data_offset;
if (section_size > 0)
qed_dump_num_param(dump_buf + size_param_offset,
*dump, "size", section_size);
else if ((section_size == 0) && (*dump != continue_dump))
actual_dump_size_in_dwords -=
section_header_and_param_size;
}
*dump = continue_dump;
*given_offset = offset;
*given_actual_dump_size_in_dwords = actual_dump_size_in_dwords;
return offset;
}
static u32
qed_ilt_dump_dump_common_global_params(struct qed_hwfn *p_hwfn,
struct qed_ptt *p_ptt,
u32 *dump_buf,
bool dump,
u32 cduc_page_size,
u32 conn_ctx_size,
u32 cdut_page_size,
u32 *full_dump_size_param_offset,
u32 *actual_dump_size_param_offset)
{
struct qed_ilt_client_cfg *clients = p_hwfn->p_cxt_mngr->clients;
u32 offset = 0;
offset += qed_dump_common_global_params(p_hwfn, p_ptt,
dump_buf + offset,
dump, 30);
offset += qed_dump_str_param(dump_buf + offset,
dump,
"dump-type", "ilt-dump");
offset += qed_dump_num_param(dump_buf + offset,
dump,
"cduc-page-size",
cduc_page_size);
offset += qed_dump_num_param(dump_buf + offset,
dump,
"cduc-first-page-id",
clients[ILT_CLI_CDUC].first.val);
offset += qed_dump_num_param(dump_buf + offset,
dump,
"cduc-last-page-id",
clients[ILT_CLI_CDUC].last.val);
offset += qed_dump_num_param(dump_buf + offset,
dump,
"cduc-num-pf-pages",
clients[ILT_CLI_CDUC].pf_total_lines);
offset += qed_dump_num_param(dump_buf + offset,
dump,
"cduc-num-vf-pages",
clients[ILT_CLI_CDUC].vf_total_lines);
offset += qed_dump_num_param(dump_buf + offset,
dump,
"max-conn-ctx-size",
conn_ctx_size);
offset += qed_dump_num_param(dump_buf + offset,
dump,
"cdut-page-size",
cdut_page_size);
offset += qed_dump_num_param(dump_buf + offset,
dump,
"cdut-first-page-id",
clients[ILT_CLI_CDUT].first.val);
offset += qed_dump_num_param(dump_buf + offset,
dump,
"cdut-last-page-id",
clients[ILT_CLI_CDUT].last.val);
offset += qed_dump_num_param(dump_buf + offset,
dump,
"cdut-num-pf-init-pages",
qed_get_cdut_num_pf_init_pages(p_hwfn));
offset += qed_dump_num_param(dump_buf + offset,
dump,
"cdut-num-vf-init-pages",
qed_get_cdut_num_vf_init_pages(p_hwfn));
offset += qed_dump_num_param(dump_buf + offset,
dump,
"cdut-num-pf-work-pages",
qed_get_cdut_num_pf_work_pages(p_hwfn));
offset += qed_dump_num_param(dump_buf + offset,
dump,
"cdut-num-vf-work-pages",
qed_get_cdut_num_vf_work_pages(p_hwfn));
offset += qed_dump_num_param(dump_buf + offset,
dump,
"max-task-ctx-size",
p_hwfn->p_cxt_mngr->task_ctx_size);
offset += qed_dump_num_param(dump_buf + offset,
dump,
"first-vf-id-in-pf",
p_hwfn->p_cxt_mngr->first_vf_in_pf);
offset += qed_dump_num_param(dump_buf + offset,
dump,
"num-vfs-in-pf",
p_hwfn->p_cxt_mngr->vf_count);
offset += qed_dump_num_param(dump_buf + offset,
dump,
"ptr-size-bytes",
sizeof(void *));
offset += qed_dump_num_param(dump_buf + offset,
dump,
"pf-start-line",
p_hwfn->p_cxt_mngr->pf_start_line);
offset += qed_dump_num_param(dump_buf + offset,
dump,
"page-mem-desc-size-dwords",
PAGE_MEM_DESC_SIZE_DWORDS);
offset += qed_dump_num_param(dump_buf + offset,
dump,
"ilt-shadow-size",
p_hwfn->p_cxt_mngr->ilt_shadow_size);
*full_dump_size_param_offset = offset;
offset += qed_dump_num_param(dump_buf + offset,
dump, "dump-size-full", 0);
*actual_dump_size_param_offset = offset;
offset += qed_dump_num_param(dump_buf + offset,
dump,
"dump-size-actual", 0);
offset += qed_dump_num_param(dump_buf + offset,
dump,
"iscsi_task_pages",
p_hwfn->p_cxt_mngr->iscsi_task_pages);
offset += qed_dump_num_param(dump_buf + offset,
dump,
"fcoe_task_pages",
p_hwfn->p_cxt_mngr->fcoe_task_pages);
offset += qed_dump_num_param(dump_buf + offset,
dump,
"roce_task_pages",
p_hwfn->p_cxt_mngr->roce_task_pages);
offset += qed_dump_num_param(dump_buf + offset,
dump,
"eth_task_pages",
p_hwfn->p_cxt_mngr->eth_task_pages);
offset += qed_dump_num_param(dump_buf + offset,
dump,
"src-first-page-id",
clients[ILT_CLI_SRC].first.val);
offset += qed_dump_num_param(dump_buf + offset,
dump,
"src-last-page-id",
clients[ILT_CLI_SRC].last.val);
offset += qed_dump_num_param(dump_buf + offset,
dump,
"src-is-active",
clients[ILT_CLI_SRC].active);
return offset;
}
static u32 qed_ilt_dump_dump_num_pf_cids(struct qed_hwfn *p_hwfn,
u32 *dump_buf,
bool dump, u32 *valid_conn_pf_cids)
{
u32 num_pf_cids = 0;
u32 offset = 0;
u8 conn_type;
offset += qed_dump_section_hdr(dump_buf + offset,
dump, "num_pf_cids_per_conn_type", 1);
offset += qed_dump_num_param(dump_buf + offset,
dump, "size", NUM_OF_CONNECTION_TYPES);
for (conn_type = 0, *valid_conn_pf_cids = 0;
conn_type < NUM_OF_CONNECTION_TYPES; conn_type++, offset++) {
num_pf_cids = p_hwfn->p_cxt_mngr->conn_cfg[conn_type].cid_count;
if (dump)
*(dump_buf + offset) = num_pf_cids;
*valid_conn_pf_cids += num_pf_cids;
}
return offset;
}
static u32 qed_ilt_dump_dump_num_vf_cids(struct qed_hwfn *p_hwfn,
u32 *dump_buf,
bool dump, u32 *valid_conn_vf_cids)
{
u32 num_vf_cids = 0;
u32 offset = 0;
u8 conn_type;
offset += qed_dump_section_hdr(dump_buf + offset, dump,
"num_vf_cids_per_conn_type", 1);
offset += qed_dump_num_param(dump_buf + offset,
dump, "size", NUM_OF_CONNECTION_TYPES);
for (conn_type = 0, *valid_conn_vf_cids = 0;
conn_type < NUM_OF_CONNECTION_TYPES; conn_type++, offset++) {
num_vf_cids =
p_hwfn->p_cxt_mngr->conn_cfg[conn_type].cids_per_vf;
if (dump)
*(dump_buf + offset) = num_vf_cids;
*valid_conn_vf_cids += num_vf_cids;
}
return offset;
}
static u32 qed_ilt_dump(struct qed_hwfn *p_hwfn,
struct qed_ptt *p_ptt,
u32 *dump_buf, u32 buf_size_in_dwords, bool dump)
{
#if ((!defined VMWARE) && (!defined UEFI))
struct qed_ilt_client_cfg *clients = p_hwfn->p_cxt_mngr->clients;
#endif
u32 valid_conn_vf_cids = 0,
valid_conn_vf_pages, offset = 0, real_dumped_size = 0;
u32 valid_conn_pf_cids = 0, valid_conn_pf_pages, num_pages;
u32 num_cids_per_page, conn_ctx_size;
u32 cduc_page_size, cdut_page_size;
u32 actual_dump_size_in_dwords = 0;
struct phys_mem_desc *ilt_pages;
u32 actul_dump_off = 0;
u32 last_section_size;
u32 full_dump_off = 0;
u32 section_size = 0;
bool continue_dump;
u32 page_id;
last_section_size = qed_dump_last_section(NULL, 0, false);
cduc_page_size = 1 <<
(clients[ILT_CLI_CDUC].p_size.val + PXP_ILT_PAGE_SIZE_NUM_BITS_MIN);
cdut_page_size = 1 <<
(clients[ILT_CLI_CDUT].p_size.val + PXP_ILT_PAGE_SIZE_NUM_BITS_MIN);
conn_ctx_size = p_hwfn->p_cxt_mngr->conn_ctx_size;
num_cids_per_page = (int)(cduc_page_size / conn_ctx_size);
ilt_pages = p_hwfn->p_cxt_mngr->ilt_shadow;
continue_dump = dump;
if (dump) {
if (buf_size_in_dwords >= last_section_size) {
buf_size_in_dwords -= last_section_size;
} else {
continue_dump = false;
actual_dump_size_in_dwords = offset;
}
}
if (continue_dump) {
section_size =
qed_ilt_dump_dump_common_global_params(p_hwfn,
p_ptt,
NULL,
false,
cduc_page_size,
conn_ctx_size,
cdut_page_size,
&full_dump_off,
&actul_dump_off);
if (offset + section_size > buf_size_in_dwords) {
continue_dump = false;
actual_dump_size_in_dwords = offset;
}
}
offset += qed_ilt_dump_dump_common_global_params(p_hwfn,
p_ptt,
dump_buf + offset,
continue_dump,
cduc_page_size,
conn_ctx_size,
cdut_page_size,
&full_dump_off,
&actul_dump_off);
if (continue_dump) {
section_size =
qed_ilt_dump_dump_num_pf_cids(p_hwfn,
NULL,
false,
&valid_conn_pf_cids);
if (offset + section_size > buf_size_in_dwords) {
continue_dump = false;
actual_dump_size_in_dwords = offset;
}
}
offset += qed_ilt_dump_dump_num_pf_cids(p_hwfn,
dump_buf + offset,
continue_dump,
&valid_conn_pf_cids);
if (continue_dump) {
section_size =
qed_ilt_dump_dump_num_vf_cids(p_hwfn,
NULL,
false,
&valid_conn_vf_cids);
if (offset + section_size > buf_size_in_dwords) {
continue_dump = false;
actual_dump_size_in_dwords = offset;
}
}
offset += qed_ilt_dump_dump_num_vf_cids(p_hwfn,
dump_buf + offset,
continue_dump,
&valid_conn_vf_cids);
num_pages = p_hwfn->p_cxt_mngr->ilt_shadow_size;
if (continue_dump) {
section_size = qed_dump_section_hdr(NULL,
false,
"ilt_page_desc",
1) +
qed_dump_num_param(NULL,
false,
"size",
num_pages * PAGE_MEM_DESC_SIZE_DWORDS);
if (offset + section_size > buf_size_in_dwords) {
continue_dump = false;
actual_dump_size_in_dwords = offset;
}
}
offset += qed_dump_section_hdr(dump_buf + offset,
continue_dump, "ilt_page_desc", 1);
offset += qed_dump_num_param(dump_buf + offset,
continue_dump,
"size",
num_pages * PAGE_MEM_DESC_SIZE_DWORDS);
if (continue_dump) {
for (page_id = 0; page_id < num_pages;
page_id++, offset += PAGE_MEM_DESC_SIZE_DWORDS) {
if (continue_dump &&
(offset + PAGE_MEM_DESC_SIZE_DWORDS <=
buf_size_in_dwords)) {
memcpy(dump_buf + offset,
&ilt_pages[page_id],
DWORDS_TO_BYTES
(PAGE_MEM_DESC_SIZE_DWORDS));
} else {
if (continue_dump) {
continue_dump = false;
actual_dump_size_in_dwords = offset;
}
}
}
} else {
offset += num_pages * PAGE_MEM_DESC_SIZE_DWORDS;
}
valid_conn_pf_pages = DIV_ROUND_UP(valid_conn_pf_cids,
num_cids_per_page);
valid_conn_vf_pages = DIV_ROUND_UP(valid_conn_vf_cids,
num_cids_per_page);
qed_ilt_dump_pages_section(p_hwfn, dump_buf, &offset, &continue_dump,
valid_conn_pf_pages, valid_conn_vf_pages,
ilt_pages, true, buf_size_in_dwords,
&actual_dump_size_in_dwords);
qed_ilt_dump_pages_section(p_hwfn, dump_buf, &offset, &continue_dump,
valid_conn_pf_pages, valid_conn_vf_pages,
ilt_pages, false, buf_size_in_dwords,
&actual_dump_size_in_dwords);
real_dumped_size =
(continue_dump == dump) ? offset : actual_dump_size_in_dwords;
qed_dump_num_param(dump_buf + full_dump_off, dump,
"full-dump-size", offset + last_section_size);
qed_dump_num_param(dump_buf + actul_dump_off,
dump,
"actual-dump-size",
real_dumped_size + last_section_size);
real_dumped_size += qed_dump_last_section(dump_buf,
real_dumped_size, dump);
return real_dumped_size;
}
enum dbg_status qed_dbg_set_bin_ptr(struct qed_hwfn *p_hwfn,
const u8 * const bin_ptr)
{
struct bin_buffer_hdr *buf_hdrs = (struct bin_buffer_hdr *)bin_ptr;
u8 buf_id;
for (buf_id = 0; buf_id < MAX_BIN_DBG_BUFFER_TYPE; buf_id++)
qed_set_dbg_bin_buf(p_hwfn,
buf_id,
(u32 *)(bin_ptr + buf_hdrs[buf_id].offset),
buf_hdrs[buf_id].length);
return DBG_STATUS_OK;
}
static enum dbg_status qed_dbg_set_app_ver(u32 ver)
{
if (ver < TOOLS_VERSION)
return DBG_STATUS_UNSUPPORTED_APP_VERSION;
s_app_ver = ver;
return DBG_STATUS_OK;
}
bool qed_read_fw_info(struct qed_hwfn *p_hwfn,
struct qed_ptt *p_ptt, struct fw_info *fw_info)
{
struct dbg_tools_data *dev_data = &p_hwfn->dbg_info;
u8 storm_id;
for (storm_id = 0; storm_id < MAX_DBG_STORMS; storm_id++) {
struct storm_defs *storm = &s_storm_defs[storm_id];
if (dev_data->block_in_reset[storm->sem_block_id])
continue;
qed_read_storm_fw_info(p_hwfn, p_ptt, storm_id, fw_info);
return true;
}
return false;
}
enum dbg_status qed_dbg_grc_config(struct qed_hwfn *p_hwfn,
enum dbg_grc_params grc_param, u32 val)
{
struct dbg_tools_data *dev_data = &p_hwfn->dbg_info;
enum dbg_status status;
int i;
DP_VERBOSE(p_hwfn,
QED_MSG_DEBUG,
"dbg_grc_config: paramId = %d, val = %d\n", grc_param, val);
status = qed_dbg_dev_init(p_hwfn);
if (status != DBG_STATUS_OK)
return status;
qed_dbg_grc_init_params(p_hwfn);
if (grc_param >= MAX_DBG_GRC_PARAMS)
return DBG_STATUS_INVALID_ARGS;
if (val < s_grc_param_defs[grc_param].min ||
val > s_grc_param_defs[grc_param].max)
return DBG_STATUS_INVALID_ARGS;
if (s_grc_param_defs[grc_param].is_preset) {
if (!val)
return DBG_STATUS_INVALID_ARGS;
for (i = 0; i < MAX_DBG_GRC_PARAMS; i++) {
struct grc_param_defs *defs = &s_grc_param_defs[i];
u32 preset_val;
if (defs->is_persistent)
continue;
if (grc_param == DBG_GRC_PARAM_EXCLUDE_ALL)
preset_val =
defs->exclude_all_preset_val;
else if (grc_param == DBG_GRC_PARAM_CRASH)
preset_val =
defs->crash_preset_val[dev_data->chip_id];
else
return DBG_STATUS_INVALID_ARGS;
qed_grc_set_param(p_hwfn, i, preset_val);
}
} else {
qed_grc_set_param(p_hwfn, grc_param, val);
}
return DBG_STATUS_OK;
}
void qed_dbg_grc_set_params_default(struct qed_hwfn *p_hwfn)
{
struct dbg_tools_data *dev_data = &p_hwfn->dbg_info;
u32 i;
for (i = 0; i < MAX_DBG_GRC_PARAMS; i++)
if (!s_grc_param_defs[i].is_persistent)
dev_data->grc.param_val[i] =
s_grc_param_defs[i].default_val[dev_data->chip_id];
}
enum dbg_status qed_dbg_grc_get_dump_buf_size(struct qed_hwfn *p_hwfn,
struct qed_ptt *p_ptt,
u32 *buf_size)
{
enum dbg_status status = qed_dbg_dev_init(p_hwfn);
*buf_size = 0;
if (status != DBG_STATUS_OK)
return status;
if (!p_hwfn->dbg_arrays[BIN_BUF_DBG_MODE_TREE].ptr ||
!p_hwfn->dbg_arrays[BIN_BUF_DBG_DUMP_REG].ptr ||
!p_hwfn->dbg_arrays[BIN_BUF_DBG_DUMP_MEM].ptr ||
!p_hwfn->dbg_arrays[BIN_BUF_DBG_ATTN_BLOCKS].ptr ||
!p_hwfn->dbg_arrays[BIN_BUF_DBG_ATTN_REGS].ptr)
return DBG_STATUS_DBG_ARRAY_NOT_SET;
return qed_grc_dump(p_hwfn, p_ptt, NULL, false, buf_size);
}
enum dbg_status qed_dbg_grc_dump(struct qed_hwfn *p_hwfn,
struct qed_ptt *p_ptt,
u32 *dump_buf,
u32 buf_size_in_dwords,
u32 *num_dumped_dwords)
{
u32 needed_buf_size_in_dwords;
enum dbg_status status;
*num_dumped_dwords = 0;
status = qed_dbg_grc_get_dump_buf_size(p_hwfn,
p_ptt,
&needed_buf_size_in_dwords);
if (status != DBG_STATUS_OK)
return status;
if (buf_size_in_dwords < needed_buf_size_in_dwords)
return DBG_STATUS_DUMP_BUF_TOO_SMALL;
qed_static_asserts();
status = qed_grc_dump(p_hwfn, p_ptt, dump_buf, true, num_dumped_dwords);
qed_dbg_grc_set_params_default(p_hwfn);
return status;
}
enum dbg_status qed_dbg_idle_chk_get_dump_buf_size(struct qed_hwfn *p_hwfn,
struct qed_ptt *p_ptt,
u32 *buf_size)
{
struct dbg_tools_data *dev_data = &p_hwfn->dbg_info;
struct idle_chk_data *idle_chk = &dev_data->idle_chk;
enum dbg_status status;
*buf_size = 0;
status = qed_dbg_dev_init(p_hwfn);
if (status != DBG_STATUS_OK)
return status;
if (!p_hwfn->dbg_arrays[BIN_BUF_DBG_MODE_TREE].ptr ||
!p_hwfn->dbg_arrays[BIN_BUF_DBG_IDLE_CHK_REGS].ptr ||
!p_hwfn->dbg_arrays[BIN_BUF_DBG_IDLE_CHK_IMMS].ptr ||
!p_hwfn->dbg_arrays[BIN_BUF_DBG_IDLE_CHK_RULES].ptr)
return DBG_STATUS_DBG_ARRAY_NOT_SET;
if (!idle_chk->buf_size_set) {
idle_chk->buf_size = qed_idle_chk_dump(p_hwfn,
p_ptt, NULL, false);
idle_chk->buf_size_set = true;
}
*buf_size = idle_chk->buf_size;
return DBG_STATUS_OK;
}
enum dbg_status qed_dbg_idle_chk_dump(struct qed_hwfn *p_hwfn,
struct qed_ptt *p_ptt,
u32 *dump_buf,
u32 buf_size_in_dwords,
u32 *num_dumped_dwords)
{
u32 needed_buf_size_in_dwords;
enum dbg_status status;
*num_dumped_dwords = 0;
status = qed_dbg_idle_chk_get_dump_buf_size(p_hwfn,
p_ptt,
&needed_buf_size_in_dwords);
if (status != DBG_STATUS_OK)
return status;
if (buf_size_in_dwords < needed_buf_size_in_dwords)
return DBG_STATUS_DUMP_BUF_TOO_SMALL;
qed_grc_unreset_blocks(p_hwfn, p_ptt, true);
qed_update_blocks_reset_state(p_hwfn, p_ptt);
*num_dumped_dwords = qed_idle_chk_dump(p_hwfn, p_ptt, dump_buf, true);
qed_dbg_grc_set_params_default(p_hwfn);
return DBG_STATUS_OK;
}
enum dbg_status qed_dbg_mcp_trace_get_dump_buf_size(struct qed_hwfn *p_hwfn,
struct qed_ptt *p_ptt,
u32 *buf_size)
{
enum dbg_status status = qed_dbg_dev_init(p_hwfn);
*buf_size = 0;
if (status != DBG_STATUS_OK)
return status;
return qed_mcp_trace_dump(p_hwfn, p_ptt, NULL, false, buf_size);
}
enum dbg_status qed_dbg_mcp_trace_dump(struct qed_hwfn *p_hwfn,
struct qed_ptt *p_ptt,
u32 *dump_buf,
u32 buf_size_in_dwords,
u32 *num_dumped_dwords)
{
u32 needed_buf_size_in_dwords;
enum dbg_status status;
status =
qed_dbg_mcp_trace_get_dump_buf_size(p_hwfn,
p_ptt,
&needed_buf_size_in_dwords);
if (status != DBG_STATUS_OK && status !=
DBG_STATUS_NVRAM_GET_IMAGE_FAILED)
return status;
if (buf_size_in_dwords < needed_buf_size_in_dwords)
return DBG_STATUS_DUMP_BUF_TOO_SMALL;
qed_update_blocks_reset_state(p_hwfn, p_ptt);
status = qed_mcp_trace_dump(p_hwfn,
p_ptt, dump_buf, true, num_dumped_dwords);
qed_dbg_grc_set_params_default(p_hwfn);
return status;
}
enum dbg_status qed_dbg_reg_fifo_get_dump_buf_size(struct qed_hwfn *p_hwfn,
struct qed_ptt *p_ptt,
u32 *buf_size)
{
enum dbg_status status = qed_dbg_dev_init(p_hwfn);
*buf_size = 0;
if (status != DBG_STATUS_OK)
return status;
return qed_reg_fifo_dump(p_hwfn, p_ptt, NULL, false, buf_size);
}
enum dbg_status qed_dbg_reg_fifo_dump(struct qed_hwfn *p_hwfn,
struct qed_ptt *p_ptt,
u32 *dump_buf,
u32 buf_size_in_dwords,
u32 *num_dumped_dwords)
{
u32 needed_buf_size_in_dwords;
enum dbg_status status;
*num_dumped_dwords = 0;
status = qed_dbg_reg_fifo_get_dump_buf_size(p_hwfn,
p_ptt,
&needed_buf_size_in_dwords);
if (status != DBG_STATUS_OK)
return status;
if (buf_size_in_dwords < needed_buf_size_in_dwords)
return DBG_STATUS_DUMP_BUF_TOO_SMALL;
qed_update_blocks_reset_state(p_hwfn, p_ptt);
status = qed_reg_fifo_dump(p_hwfn,
p_ptt, dump_buf, true, num_dumped_dwords);
qed_dbg_grc_set_params_default(p_hwfn);
return status;
}
enum dbg_status qed_dbg_igu_fifo_get_dump_buf_size(struct qed_hwfn *p_hwfn,
struct qed_ptt *p_ptt,
u32 *buf_size)
{
enum dbg_status status = qed_dbg_dev_init(p_hwfn);
*buf_size = 0;
if (status != DBG_STATUS_OK)
return status;
return qed_igu_fifo_dump(p_hwfn, p_ptt, NULL, false, buf_size);
}
enum dbg_status qed_dbg_igu_fifo_dump(struct qed_hwfn *p_hwfn,
struct qed_ptt *p_ptt,
u32 *dump_buf,
u32 buf_size_in_dwords,
u32 *num_dumped_dwords)
{
u32 needed_buf_size_in_dwords;
enum dbg_status status;
*num_dumped_dwords = 0;
status = qed_dbg_igu_fifo_get_dump_buf_size(p_hwfn,
p_ptt,
&needed_buf_size_in_dwords);
if (status != DBG_STATUS_OK)
return status;
if (buf_size_in_dwords < needed_buf_size_in_dwords)
return DBG_STATUS_DUMP_BUF_TOO_SMALL;
qed_update_blocks_reset_state(p_hwfn, p_ptt);
status = qed_igu_fifo_dump(p_hwfn,
p_ptt, dump_buf, true, num_dumped_dwords);
qed_dbg_grc_set_params_default(p_hwfn);
return status;
}
enum dbg_status
qed_dbg_protection_override_get_dump_buf_size(struct qed_hwfn *p_hwfn,
struct qed_ptt *p_ptt,
u32 *buf_size)
{
enum dbg_status status = qed_dbg_dev_init(p_hwfn);
*buf_size = 0;
if (status != DBG_STATUS_OK)
return status;
return qed_protection_override_dump(p_hwfn,
p_ptt, NULL, false, buf_size);
}
enum dbg_status qed_dbg_protection_override_dump(struct qed_hwfn *p_hwfn,
struct qed_ptt *p_ptt,
u32 *dump_buf,
u32 buf_size_in_dwords,
u32 *num_dumped_dwords)
{
u32 needed_buf_size_in_dwords, *p_size = &needed_buf_size_in_dwords;
enum dbg_status status;
*num_dumped_dwords = 0;
status =
qed_dbg_protection_override_get_dump_buf_size(p_hwfn,
p_ptt,
p_size);
if (status != DBG_STATUS_OK)
return status;
if (buf_size_in_dwords < needed_buf_size_in_dwords)
return DBG_STATUS_DUMP_BUF_TOO_SMALL;
qed_update_blocks_reset_state(p_hwfn, p_ptt);
status = qed_protection_override_dump(p_hwfn,
p_ptt,
dump_buf,
true, num_dumped_dwords);
qed_dbg_grc_set_params_default(p_hwfn);
return status;
}
enum dbg_status qed_dbg_fw_asserts_get_dump_buf_size(struct qed_hwfn *p_hwfn,
struct qed_ptt *p_ptt,
u32 *buf_size)
{
enum dbg_status status = qed_dbg_dev_init(p_hwfn);
*buf_size = 0;
if (status != DBG_STATUS_OK)
return status;
qed_update_blocks_reset_state(p_hwfn, p_ptt);
*buf_size = qed_fw_asserts_dump(p_hwfn, p_ptt, NULL, false);
return DBG_STATUS_OK;
}
enum dbg_status qed_dbg_fw_asserts_dump(struct qed_hwfn *p_hwfn,
struct qed_ptt *p_ptt,
u32 *dump_buf,
u32 buf_size_in_dwords,
u32 *num_dumped_dwords)
{
u32 needed_buf_size_in_dwords, *p_size = &needed_buf_size_in_dwords;
enum dbg_status status;
*num_dumped_dwords = 0;
status =
qed_dbg_fw_asserts_get_dump_buf_size(p_hwfn,
p_ptt,
p_size);
if (status != DBG_STATUS_OK)
return status;
if (buf_size_in_dwords < needed_buf_size_in_dwords)
return DBG_STATUS_DUMP_BUF_TOO_SMALL;
*num_dumped_dwords = qed_fw_asserts_dump(p_hwfn, p_ptt, dump_buf, true);
qed_dbg_grc_set_params_default(p_hwfn);
return DBG_STATUS_OK;
}
static enum dbg_status qed_dbg_ilt_get_dump_buf_size(struct qed_hwfn *p_hwfn,
struct qed_ptt *p_ptt,
u32 *buf_size)
{
enum dbg_status status = qed_dbg_dev_init(p_hwfn);
*buf_size = 0;
if (status != DBG_STATUS_OK)
return status;
*buf_size = qed_ilt_dump(p_hwfn, p_ptt, NULL, 0, false);
return DBG_STATUS_OK;
}
static enum dbg_status qed_dbg_ilt_dump(struct qed_hwfn *p_hwfn,
struct qed_ptt *p_ptt,
u32 *dump_buf,
u32 buf_size_in_dwords,
u32 *num_dumped_dwords)
{
*num_dumped_dwords = qed_ilt_dump(p_hwfn,
p_ptt,
dump_buf, buf_size_in_dwords, true);
qed_dbg_grc_set_params_default(p_hwfn);
return DBG_STATUS_OK;
}
enum dbg_status qed_dbg_read_attn(struct qed_hwfn *p_hwfn,
struct qed_ptt *p_ptt,
enum block_id block_id,
enum dbg_attn_type attn_type,
bool clear_status,
struct dbg_attn_block_result *results)
{
enum dbg_status status = qed_dbg_dev_init(p_hwfn);
u8 reg_idx, num_attn_regs, num_result_regs = 0;
const struct dbg_attn_reg *attn_reg_arr;
if (status != DBG_STATUS_OK)
return status;
if (!p_hwfn->dbg_arrays[BIN_BUF_DBG_MODE_TREE].ptr ||
!p_hwfn->dbg_arrays[BIN_BUF_DBG_ATTN_BLOCKS].ptr ||
!p_hwfn->dbg_arrays[BIN_BUF_DBG_ATTN_REGS].ptr)
return DBG_STATUS_DBG_ARRAY_NOT_SET;
attn_reg_arr = qed_get_block_attn_regs(p_hwfn,
block_id,
attn_type, &num_attn_regs);
for (reg_idx = 0; reg_idx < num_attn_regs; reg_idx++) {
const struct dbg_attn_reg *reg_data = &attn_reg_arr[reg_idx];
struct dbg_attn_reg_result *reg_result;
u32 sts_addr, sts_val;
u16 modes_buf_offset;
bool eval_mode;
eval_mode = GET_FIELD(reg_data->mode.data,
DBG_MODE_HDR_EVAL_MODE) > 0;
modes_buf_offset = GET_FIELD(reg_data->mode.data,
DBG_MODE_HDR_MODES_BUF_OFFSET);
if (eval_mode && !qed_is_mode_match(p_hwfn, &modes_buf_offset))
continue;
sts_addr = DWORDS_TO_BYTES(clear_status ?
reg_data->sts_clr_address :
GET_FIELD(reg_data->data,
DBG_ATTN_REG_STS_ADDRESS));
sts_val = qed_rd(p_hwfn, p_ptt, sts_addr);
if (!sts_val)
continue;
reg_result = &results->reg_results[num_result_regs];
SET_FIELD(reg_result->data,
DBG_ATTN_REG_RESULT_STS_ADDRESS, sts_addr);
SET_FIELD(reg_result->data,
DBG_ATTN_REG_RESULT_NUM_REG_ATTN,
GET_FIELD(reg_data->data, DBG_ATTN_REG_NUM_REG_ATTN));
reg_result->block_attn_offset = reg_data->block_attn_offset;
reg_result->sts_val = sts_val;
reg_result->mask_val = qed_rd(p_hwfn,
p_ptt,
DWORDS_TO_BYTES
(reg_data->mask_address));
num_result_regs++;
}
results->block_id = (u8)block_id;
results->names_offset =
qed_get_block_attn_data(p_hwfn, block_id, attn_type)->names_offset;
SET_FIELD(results->data, DBG_ATTN_BLOCK_RESULT_ATTN_TYPE, attn_type);
SET_FIELD(results->data,
DBG_ATTN_BLOCK_RESULT_NUM_REGS, num_result_regs);
return DBG_STATUS_OK;
}
struct reg_fifo_element {
u64 data;
#define REG_FIFO_ELEMENT_ADDRESS_SHIFT 0
#define REG_FIFO_ELEMENT_ADDRESS_MASK 0x7fffff
#define REG_FIFO_ELEMENT_ACCESS_SHIFT 23
#define REG_FIFO_ELEMENT_ACCESS_MASK 0x1
#define REG_FIFO_ELEMENT_PF_SHIFT 24
#define REG_FIFO_ELEMENT_PF_MASK 0xf
#define REG_FIFO_ELEMENT_VF_SHIFT 28
#define REG_FIFO_ELEMENT_VF_MASK 0xff
#define REG_FIFO_ELEMENT_PORT_SHIFT 36
#define REG_FIFO_ELEMENT_PORT_MASK 0x3
#define REG_FIFO_ELEMENT_PRIVILEGE_SHIFT 38
#define REG_FIFO_ELEMENT_PRIVILEGE_MASK 0x3
#define REG_FIFO_ELEMENT_PROTECTION_SHIFT 40
#define REG_FIFO_ELEMENT_PROTECTION_MASK 0x7
#define REG_FIFO_ELEMENT_MASTER_SHIFT 43
#define REG_FIFO_ELEMENT_MASTER_MASK 0xf
#define REG_FIFO_ELEMENT_ERROR_SHIFT 47
#define REG_FIFO_ELEMENT_ERROR_MASK 0x1f
};
struct reg_fifo_err {
u32 err_code;
const char *err_msg;
};
struct igu_fifo_element {
u32 dword0;
#define IGU_FIFO_ELEMENT_DWORD0_FID_SHIFT 0
#define IGU_FIFO_ELEMENT_DWORD0_FID_MASK 0xff
#define IGU_FIFO_ELEMENT_DWORD0_IS_PF_SHIFT 8
#define IGU_FIFO_ELEMENT_DWORD0_IS_PF_MASK 0x1
#define IGU_FIFO_ELEMENT_DWORD0_SOURCE_SHIFT 9
#define IGU_FIFO_ELEMENT_DWORD0_SOURCE_MASK 0xf
#define IGU_FIFO_ELEMENT_DWORD0_ERR_TYPE_SHIFT 13
#define IGU_FIFO_ELEMENT_DWORD0_ERR_TYPE_MASK 0xf
#define IGU_FIFO_ELEMENT_DWORD0_CMD_ADDR_SHIFT 17
#define IGU_FIFO_ELEMENT_DWORD0_CMD_ADDR_MASK 0x7fff
u32 dword1;
u32 dword2;
#define IGU_FIFO_ELEMENT_DWORD12_IS_WR_CMD_SHIFT 0
#define IGU_FIFO_ELEMENT_DWORD12_IS_WR_CMD_MASK 0x1
#define IGU_FIFO_ELEMENT_DWORD12_WR_DATA_SHIFT 1
#define IGU_FIFO_ELEMENT_DWORD12_WR_DATA_MASK 0xffffffff
u32 reserved;
};
struct igu_fifo_wr_data {
u32 data;
#define IGU_FIFO_WR_DATA_PROD_CONS_SHIFT 0
#define IGU_FIFO_WR_DATA_PROD_CONS_MASK 0xffffff
#define IGU_FIFO_WR_DATA_UPDATE_FLAG_SHIFT 24
#define IGU_FIFO_WR_DATA_UPDATE_FLAG_MASK 0x1
#define IGU_FIFO_WR_DATA_EN_DIS_INT_FOR_SB_SHIFT 25
#define IGU_FIFO_WR_DATA_EN_DIS_INT_FOR_SB_MASK 0x3
#define IGU_FIFO_WR_DATA_SEGMENT_SHIFT 27
#define IGU_FIFO_WR_DATA_SEGMENT_MASK 0x1
#define IGU_FIFO_WR_DATA_TIMER_MASK_SHIFT 28
#define IGU_FIFO_WR_DATA_TIMER_MASK_MASK 0x1
#define IGU_FIFO_WR_DATA_CMD_TYPE_SHIFT 31
#define IGU_FIFO_WR_DATA_CMD_TYPE_MASK 0x1
};
struct igu_fifo_cleanup_wr_data {
u32 data;
#define IGU_FIFO_CLEANUP_WR_DATA_RESERVED_SHIFT 0
#define IGU_FIFO_CLEANUP_WR_DATA_RESERVED_MASK 0x7ffffff
#define IGU_FIFO_CLEANUP_WR_DATA_CLEANUP_VAL_SHIFT 27
#define IGU_FIFO_CLEANUP_WR_DATA_CLEANUP_VAL_MASK 0x1
#define IGU_FIFO_CLEANUP_WR_DATA_CLEANUP_TYPE_SHIFT 28
#define IGU_FIFO_CLEANUP_WR_DATA_CLEANUP_TYPE_MASK 0x7
#define IGU_FIFO_CLEANUP_WR_DATA_CMD_TYPE_SHIFT 31
#define IGU_FIFO_CLEANUP_WR_DATA_CMD_TYPE_MASK 0x1
};
struct protection_override_element {
u64 data;
#define PROTECTION_OVERRIDE_ELEMENT_ADDRESS_SHIFT 0
#define PROTECTION_OVERRIDE_ELEMENT_ADDRESS_MASK 0x7fffff
#define PROTECTION_OVERRIDE_ELEMENT_WINDOW_SIZE_SHIFT 23
#define PROTECTION_OVERRIDE_ELEMENT_WINDOW_SIZE_MASK 0xffffff
#define PROTECTION_OVERRIDE_ELEMENT_READ_SHIFT 47
#define PROTECTION_OVERRIDE_ELEMENT_READ_MASK 0x1
#define PROTECTION_OVERRIDE_ELEMENT_WRITE_SHIFT 48
#define PROTECTION_OVERRIDE_ELEMENT_WRITE_MASK 0x1
#define PROTECTION_OVERRIDE_ELEMENT_READ_PROTECTION_SHIFT 49
#define PROTECTION_OVERRIDE_ELEMENT_READ_PROTECTION_MASK 0x7
#define PROTECTION_OVERRIDE_ELEMENT_WRITE_PROTECTION_SHIFT 52
#define PROTECTION_OVERRIDE_ELEMENT_WRITE_PROTECTION_MASK 0x7
};
enum igu_fifo_sources {
IGU_SRC_PXP0,
IGU_SRC_PXP1,
IGU_SRC_PXP2,
IGU_SRC_PXP3,
IGU_SRC_PXP4,
IGU_SRC_PXP5,
IGU_SRC_PXP6,
IGU_SRC_PXP7,
IGU_SRC_CAU,
IGU_SRC_ATTN,
IGU_SRC_GRC
};
enum igu_fifo_addr_types {
IGU_ADDR_TYPE_MSIX_MEM,
IGU_ADDR_TYPE_WRITE_PBA,
IGU_ADDR_TYPE_WRITE_INT_ACK,
IGU_ADDR_TYPE_WRITE_ATTN_BITS,
IGU_ADDR_TYPE_READ_INT,
IGU_ADDR_TYPE_WRITE_PROD_UPDATE,
IGU_ADDR_TYPE_RESERVED
};
struct igu_fifo_addr_data {
u16 start_addr;
u16 end_addr;
char *desc;
char *vf_desc;
enum igu_fifo_addr_types type;
};
#define MAX_MSG_LEN 1024
#define MCP_TRACE_MAX_MODULE_LEN 8
#define MCP_TRACE_FORMAT_MAX_PARAMS 3
#define MCP_TRACE_FORMAT_PARAM_WIDTH \
(MCP_TRACE_FORMAT_P2_SIZE_OFFSET - MCP_TRACE_FORMAT_P1_SIZE_OFFSET)
#define REG_FIFO_ELEMENT_ADDR_FACTOR 4
#define REG_FIFO_ELEMENT_IS_PF_VF_VAL 127
#define PROTECTION_OVERRIDE_ELEMENT_ADDR_FACTOR 4
static const char * const s_status_str[] = {
"Operation completed successfully",
"Debug application version wasn't set",
"Unsupported debug application version",
"The debug block wasn't reset since the last recording",
"Invalid arguments",
"The debug output was already set",
"Invalid PCI buffer size",
"PCI buffer allocation failed",
"A PCI buffer wasn't allocated",
"The filter/trigger constraint dword offsets are not enabled for recording",
"No matching framing mode",
"Error reading from VFC",
"The Storm was already enabled",
"The specified Storm wasn't enabled",
"The block was already enabled",
"The specified block wasn't enabled",
"No input was enabled for recording",
"Filters and triggers are not allowed in E4 256-bit mode",
"The filter was already enabled",
"The trigger was already enabled",
"The trigger wasn't enabled",
"A constraint can be added only after a filter was enabled or a trigger state was added",
"Cannot add more than 3 trigger states",
"Cannot add more than 4 constraints per filter or trigger state",
"The recording wasn't started",
"A trigger was configured, but it didn't trigger",
"No data was recorded",
"Dump buffer is too small",
"Dumped data is not aligned to chunks",
"Unknown chip",
"Failed allocating virtual memory",
"The input block is in reset",
"Invalid MCP trace signature found in NVRAM",
"Invalid bundle ID found in NVRAM",
"Failed getting NVRAM image",
"NVRAM image is not dword-aligned",
"Failed reading from NVRAM",
"Idle check parsing failed",
"MCP Trace data is corrupt",
"Dump doesn't contain meta data - it must be provided in image file",
"Failed to halt MCP",
"Failed to resume MCP after halt",
"",
"Failed to empty SEMI sync FIFO",
"IGU FIFO data is corrupt",
"MCP failed to mask parities",
"FW Asserts parsing failed",
"GRC FIFO data is corrupt",
"Protection Override data is corrupt",
"Debug arrays were not set (when using binary files, dbg_set_bin_ptr must be called)",
"",
"Non-matching debug lines - in E4, all lines must be of the same type (either 128b or 256b)",
"Insufficient HW IDs. Try to record less Storms/blocks",
"The debug bus is in use",
"The storm debug mode is not supported in the current chip",
"Other engine is supported only in BB",
"The configured filter mode requires a single Storm/block input",
"The configured filter mode requires that all the constraints of a single trigger state will be defined on a single Storm/block input",
"When triggering on Storm data, the Storm to trigger on must be specified",
"Failed to request MDUMP2 Offsize",
"Expected CRC (part of the MDUMP2 data) is different than the calculated CRC over that data",
"Invalid Signature found at start of MDUMP2",
"Invalid Log Size of MDUMP2",
"Invalid Log Header of MDUMP2",
"Invalid Log Data of MDUMP2",
"Could not extract number of ports from regval buf of MDUMP2",
"Could not extract MFW (link) status from regval buf of MDUMP2",
"Could not display linkdump of MDUMP2",
"Could not read PHY CFG of MDUMP2",
"Could not read PLL Mode of MDUMP2",
"Could not read TSCF/TSCE Lane Regs of MDUMP2",
"Could not allocate MDUMP2 reg-val internal buffer"
};
static const char * const s_idle_chk_severity_str[] = {
"Error",
"Error if no traffic",
"Warning"
};
static const char * const s_mcp_trace_level_str[] = {
"ERROR",
"TRACE",
"DEBUG"
};
static const char * const s_access_strs[] = {
"read",
"write"
};
static const char * const s_privilege_strs[] = {
"VF",
"PDA",
"HV",
"UA"
};
static const char * const s_protection_strs[] = {
"(default)",
"(default)",
"(default)",
"(default)",
"override VF",
"override PDA",
"override HV",
"override UA"
};
static const char * const s_master_strs[] = {
"???",
"pxp",
"mcp",
"msdm",
"psdm",
"ysdm",
"usdm",
"tsdm",
"xsdm",
"dbu",
"dmae",
"jdap",
"???",
"???",
"???",
"???"
};
static struct reg_fifo_err s_reg_fifo_errors[] = {
{1, "grc timeout"},
{2, "address doesn't belong to any block"},
{4, "reserved address in block or write to read-only address"},
{8, "privilege/protection mismatch"},
{16, "path isolation error"},
{17, "RSL error"}
};
static const char * const s_igu_fifo_source_strs[] = {
"TSTORM",
"MSTORM",
"USTORM",
"XSTORM",
"YSTORM",
"PSTORM",
"PCIE",
"NIG_QM_PBF",
"CAU",
"ATTN",
"GRC",
};
static const char * const s_igu_fifo_error_strs[] = {
"no error",
"length error",
"function disabled",
"VF sent command to attention address",
"host sent prod update command",
"read of during interrupt register while in MIMD mode",
"access to PXP BAR reserved address",
"producer update command to attention index",
"unknown error",
"SB index not valid",
"SB relative index and FID not found",
"FID not match",
"command with error flag asserted (PCI error or CAU discard)",
"VF sent cleanup and RF cleanup is disabled",
"cleanup command on type bigger than 4"
};
static const struct igu_fifo_addr_data s_igu_fifo_addr_data[] = {
{0x0, 0x101, "MSI-X Memory", NULL,
IGU_ADDR_TYPE_MSIX_MEM},
{0x102, 0x1ff, "reserved", NULL,
IGU_ADDR_TYPE_RESERVED},
{0x200, 0x200, "Write PBA[0:63]", NULL,
IGU_ADDR_TYPE_WRITE_PBA},
{0x201, 0x201, "Write PBA[64:127]", "reserved",
IGU_ADDR_TYPE_WRITE_PBA},
{0x202, 0x202, "Write PBA[128]", "reserved",
IGU_ADDR_TYPE_WRITE_PBA},
{0x203, 0x3ff, "reserved", NULL,
IGU_ADDR_TYPE_RESERVED},
{0x400, 0x5ef, "Write interrupt acknowledgment", NULL,
IGU_ADDR_TYPE_WRITE_INT_ACK},
{0x5f0, 0x5f0, "Attention bits update", NULL,
IGU_ADDR_TYPE_WRITE_ATTN_BITS},
{0x5f1, 0x5f1, "Attention bits set", NULL,
IGU_ADDR_TYPE_WRITE_ATTN_BITS},
{0x5f2, 0x5f2, "Attention bits clear", NULL,
IGU_ADDR_TYPE_WRITE_ATTN_BITS},
{0x5f3, 0x5f3, "Read interrupt 0:63 with mask", NULL,
IGU_ADDR_TYPE_READ_INT},
{0x5f4, 0x5f4, "Read interrupt 0:31 with mask", NULL,
IGU_ADDR_TYPE_READ_INT},
{0x5f5, 0x5f5, "Read interrupt 32:63 with mask", NULL,
IGU_ADDR_TYPE_READ_INT},
{0x5f6, 0x5f6, "Read interrupt 0:63 without mask", NULL,
IGU_ADDR_TYPE_READ_INT},
{0x5f7, 0x5ff, "reserved", NULL,
IGU_ADDR_TYPE_RESERVED},
{0x600, 0x7ff, "Producer update", NULL,
IGU_ADDR_TYPE_WRITE_PROD_UPDATE}
};
static char s_temp_buf[MAX_MSG_LEN];
static void qed_user_static_asserts(void)
{
}
static u32 qed_cyclic_add(u32 a, u32 b, u32 size)
{
return (a + b) % size;
}
static u32 qed_cyclic_sub(u32 a, u32 b, u32 size)
{
return (size + a - b) % size;
}
static u32 qed_read_from_cyclic_buf(void *buf,
u32 *offset,
u32 buf_size, u8 num_bytes_to_read)
{
u8 i, *val_ptr, *bytes_buf = (u8 *)buf;
u32 val = 0;
val_ptr = (u8 *)&val;
for (i = 0; i < num_bytes_to_read; i++) {
val_ptr[i] = bytes_buf[*offset];
*offset = qed_cyclic_add(*offset, 1, buf_size);
}
return val;
}
static u8 qed_read_byte_from_buf(void *buf, u32 *offset)
{
return ((u8 *)buf)[(*offset)++];
}
static u32 qed_read_dword_from_buf(void *buf, u32 *offset)
{
u32 dword_val = *(u32 *)&((u8 *)buf)[*offset];
*offset += 4;
return dword_val;
}
static void qed_read_str_from_buf(void *buf, u32 *offset, u32 size, char *dest)
{
const char *source_str = &((const char *)buf)[*offset];
strncpy(dest, source_str, size);
dest[size - 1] = '\0';
*offset += size;
}
static char *qed_get_buf_ptr(void *buf, u32 offset)
{
return buf ? (char *)buf + offset : s_temp_buf;
}
static u32 qed_read_param(u32 *dump_buf,
const char **param_name,
const char **param_str_val, u32 *param_num_val)
{
char *char_buf = (char *)dump_buf;
size_t offset = 0;
*param_name = char_buf;
offset += strlen(*param_name) + 1;
if (*(char_buf + offset++)) {
*param_str_val = char_buf + offset;
*param_num_val = 0;
offset += strlen(*param_str_val) + 1;
if (offset & 0x3)
offset += (4 - (offset & 0x3));
} else {
*param_str_val = NULL;
if (offset & 0x3)
offset += (4 - (offset & 0x3));
*param_num_val = *(u32 *)(char_buf + offset);
offset += 4;
}
return (u32)offset / 4;
}
static u32 qed_read_section_hdr(u32 *dump_buf,
const char **section_name,
u32 *num_section_params)
{
const char *param_str_val;
return qed_read_param(dump_buf,
section_name, ¶m_str_val, num_section_params);
}
static u32 qed_print_section_params(u32 *dump_buf,
u32 num_section_params,
char *results_buf, u32 *num_chars_printed)
{
u32 i, dump_offset = 0, results_offset = 0;
for (i = 0; i < num_section_params; i++) {
const char *param_name, *param_str_val;
u32 param_num_val = 0;
dump_offset += qed_read_param(dump_buf + dump_offset,
¶m_name,
¶m_str_val, ¶m_num_val);
if (param_str_val)
results_offset +=
sprintf(qed_get_buf_ptr(results_buf,
results_offset),
"%s: %s\n", param_name, param_str_val);
else if (strcmp(param_name, "fw-timestamp"))
results_offset +=
sprintf(qed_get_buf_ptr(results_buf,
results_offset),
"%s: %d\n", param_name, param_num_val);
}
results_offset += sprintf(qed_get_buf_ptr(results_buf, results_offset),
"\n");
*num_chars_printed = results_offset;
return dump_offset;
}
static const char *qed_dbg_get_block_name(struct qed_hwfn *p_hwfn,
enum block_id block_id)
{
const struct dbg_block_user *block =
(const struct dbg_block_user *)
p_hwfn->dbg_arrays[BIN_BUF_DBG_BLOCKS_USER_DATA].ptr + block_id;
return (const char *)block->name;
}
static struct dbg_tools_user_data *qed_dbg_get_user_data(struct qed_hwfn
*p_hwfn)
{
return (struct dbg_tools_user_data *)p_hwfn->dbg_user_info;
}
static u32 qed_parse_idle_chk_dump_rules(struct qed_hwfn *p_hwfn,
u32 *dump_buf,
u32 *dump_buf_end,
u32 num_rules,
bool print_fw_idle_chk,
char *results_buf,
u32 *num_errors, u32 *num_warnings)
{
u32 results_offset = 0;
u32 rule_idx;
u16 i, j;
*num_errors = 0;
*num_warnings = 0;
for (rule_idx = 0; rule_idx < num_rules && dump_buf < dump_buf_end;
rule_idx++) {
const struct dbg_idle_chk_rule_parsing_data *rule_parsing_data;
struct dbg_idle_chk_result_hdr *hdr;
const char *parsing_str, *lsi_msg;
u32 parsing_str_offset;
bool has_fw_msg;
u8 curr_reg_id;
hdr = (struct dbg_idle_chk_result_hdr *)dump_buf;
rule_parsing_data =
(const struct dbg_idle_chk_rule_parsing_data *)
p_hwfn->dbg_arrays[BIN_BUF_DBG_IDLE_CHK_PARSING_DATA].ptr +
hdr->rule_id;
parsing_str_offset =
GET_FIELD(rule_parsing_data->data,
DBG_IDLE_CHK_RULE_PARSING_DATA_STR_OFFSET);
has_fw_msg =
GET_FIELD(rule_parsing_data->data,
DBG_IDLE_CHK_RULE_PARSING_DATA_HAS_FW_MSG) > 0;
parsing_str = (const char *)
p_hwfn->dbg_arrays[BIN_BUF_DBG_PARSING_STRINGS].ptr +
parsing_str_offset;
lsi_msg = parsing_str;
curr_reg_id = 0;
if (hdr->severity >= MAX_DBG_IDLE_CHK_SEVERITY_TYPES)
return 0;
dump_buf += BYTES_TO_DWORDS(sizeof(*hdr));
if (hdr->severity == IDLE_CHK_SEVERITY_ERROR ||
hdr->severity == IDLE_CHK_SEVERITY_ERROR_NO_TRAFFIC)
(*num_errors)++;
else
(*num_warnings)++;
results_offset +=
sprintf(qed_get_buf_ptr(results_buf,
results_offset), "%s: ",
s_idle_chk_severity_str[hdr->severity]);
if (has_fw_msg)
parsing_str += strlen(parsing_str) + 1;
results_offset +=
sprintf(qed_get_buf_ptr(results_buf,
results_offset), "%s.",
has_fw_msg &&
print_fw_idle_chk ? parsing_str : lsi_msg);
parsing_str += strlen(parsing_str) + 1;
results_offset +=
sprintf(qed_get_buf_ptr(results_buf,
results_offset), " Registers:");
for (i = 0;
i < hdr->num_dumped_cond_regs + hdr->num_dumped_info_regs;
i++) {
struct dbg_idle_chk_result_reg_hdr *reg_hdr;
bool is_mem;
u8 reg_id;
reg_hdr =
(struct dbg_idle_chk_result_reg_hdr *)dump_buf;
is_mem = GET_FIELD(reg_hdr->data,
DBG_IDLE_CHK_RESULT_REG_HDR_IS_MEM);
reg_id = GET_FIELD(reg_hdr->data,
DBG_IDLE_CHK_RESULT_REG_HDR_REG_ID);
dump_buf += BYTES_TO_DWORDS(sizeof(*reg_hdr));
for (; reg_id > curr_reg_id; curr_reg_id++)
parsing_str += strlen(parsing_str) + 1;
results_offset +=
sprintf(qed_get_buf_ptr(results_buf,
results_offset), " %s",
parsing_str);
if (i < hdr->num_dumped_cond_regs && is_mem)
results_offset +=
sprintf(qed_get_buf_ptr(results_buf,
results_offset),
"[%d]", hdr->mem_entry_id +
reg_hdr->start_entry);
results_offset +=
sprintf(qed_get_buf_ptr(results_buf,
results_offset), "=");
for (j = 0; j < reg_hdr->size; j++, dump_buf++) {
results_offset +=
sprintf(qed_get_buf_ptr(results_buf,
results_offset),
"0x%x", *dump_buf);
if (j < reg_hdr->size - 1)
results_offset +=
sprintf(qed_get_buf_ptr
(results_buf,
results_offset), ",");
}
}
results_offset +=
sprintf(qed_get_buf_ptr(results_buf, results_offset), "\n");
}
if (dump_buf > dump_buf_end)
return 0;
return results_offset;
}
static enum dbg_status qed_parse_idle_chk_dump(struct qed_hwfn *p_hwfn,
u32 *dump_buf,
u32 num_dumped_dwords,
char *results_buf,
u32 *parsed_results_bytes,
u32 *num_errors,
u32 *num_warnings)
{
u32 num_section_params = 0, num_rules, num_rules_not_dumped;
const char *section_name, *param_name, *param_str_val;
u32 *dump_buf_end = dump_buf + num_dumped_dwords;
u32 results_offset = 0;
*parsed_results_bytes = 0;
*num_errors = 0;
*num_warnings = 0;
if (!p_hwfn->dbg_arrays[BIN_BUF_DBG_PARSING_STRINGS].ptr ||
!p_hwfn->dbg_arrays[BIN_BUF_DBG_IDLE_CHK_PARSING_DATA].ptr)
return DBG_STATUS_DBG_ARRAY_NOT_SET;
dump_buf += qed_read_section_hdr(dump_buf,
§ion_name, &num_section_params);
if (strcmp(section_name, "global_params"))
return DBG_STATUS_IDLE_CHK_PARSE_FAILED;
dump_buf += qed_print_section_params(dump_buf,
num_section_params,
results_buf, &results_offset);
dump_buf += qed_read_section_hdr(dump_buf,
§ion_name, &num_section_params);
if (strcmp(section_name, "idle_chk") ||
(num_section_params != 2 && num_section_params != 1))
return DBG_STATUS_IDLE_CHK_PARSE_FAILED;
dump_buf += qed_read_param(dump_buf,
¶m_name, ¶m_str_val, &num_rules);
if (strcmp(param_name, "num_rules"))
return DBG_STATUS_IDLE_CHK_PARSE_FAILED;
if (num_section_params > 1) {
dump_buf += qed_read_param(dump_buf,
¶m_name,
¶m_str_val,
&num_rules_not_dumped);
if (strcmp(param_name, "num_rules_not_dumped"))
return DBG_STATUS_IDLE_CHK_PARSE_FAILED;
} else {
num_rules_not_dumped = 0;
}
if (num_rules) {
u32 rules_print_size;
results_offset +=
sprintf(qed_get_buf_ptr(results_buf,
results_offset),
"FW_IDLE_CHECK:\n");
rules_print_size =
qed_parse_idle_chk_dump_rules(p_hwfn,
dump_buf,
dump_buf_end,
num_rules,
true,
results_buf ?
results_buf +
results_offset :
NULL,
num_errors,
num_warnings);
results_offset += rules_print_size;
if (!rules_print_size)
return DBG_STATUS_IDLE_CHK_PARSE_FAILED;
results_offset +=
sprintf(qed_get_buf_ptr(results_buf,
results_offset),
"\nLSI_IDLE_CHECK:\n");
rules_print_size =
qed_parse_idle_chk_dump_rules(p_hwfn,
dump_buf,
dump_buf_end,
num_rules,
false,
results_buf ?
results_buf +
results_offset :
NULL,
num_errors,
num_warnings);
results_offset += rules_print_size;
if (!rules_print_size)
return DBG_STATUS_IDLE_CHK_PARSE_FAILED;
}
if (*num_errors)
results_offset +=
sprintf(qed_get_buf_ptr(results_buf,
results_offset),
"\nIdle Check failed!!! (with %d errors and %d warnings)\n",
*num_errors, *num_warnings);
else if (*num_warnings)
results_offset +=
sprintf(qed_get_buf_ptr(results_buf,
results_offset),
"\nIdle Check completed successfully (with %d warnings)\n",
*num_warnings);
else
results_offset +=
sprintf(qed_get_buf_ptr(results_buf,
results_offset),
"\nIdle Check completed successfully\n");
if (num_rules_not_dumped)
results_offset +=
sprintf(qed_get_buf_ptr(results_buf,
results_offset),
"\nIdle Check Partially dumped : num_rules_not_dumped = %d\n",
num_rules_not_dumped);
*parsed_results_bytes = results_offset + 1;
return DBG_STATUS_OK;
}
static enum dbg_status
qed_mcp_trace_alloc_meta_data(struct qed_hwfn *p_hwfn,
const u32 *meta_buf)
{
struct dbg_tools_user_data *dev_user_data;
u32 offset = 0, signature, i;
struct mcp_trace_meta *meta;
u8 *meta_buf_bytes;
dev_user_data = qed_dbg_get_user_data(p_hwfn);
meta = &dev_user_data->mcp_trace_meta;
meta_buf_bytes = (u8 *)meta_buf;
if (meta->is_allocated)
qed_mcp_trace_free_meta_data(p_hwfn);
memset(meta, 0, sizeof(*meta));
signature = qed_read_dword_from_buf(meta_buf_bytes, &offset);
if (signature != NVM_MAGIC_VALUE)
return DBG_STATUS_INVALID_TRACE_SIGNATURE;
meta->modules_num = qed_read_byte_from_buf(meta_buf_bytes, &offset);
meta->modules = kcalloc(meta->modules_num, sizeof(char *),
GFP_KERNEL);
if (!meta->modules)
return DBG_STATUS_VIRT_MEM_ALLOC_FAILED;
for (i = 0; i < meta->modules_num; i++) {
u8 module_len = qed_read_byte_from_buf(meta_buf_bytes, &offset);
*(meta->modules + i) = kzalloc(module_len, GFP_KERNEL);
if (!(*(meta->modules + i))) {
meta->modules_num = i ? i - 1 : 0;
return DBG_STATUS_VIRT_MEM_ALLOC_FAILED;
}
qed_read_str_from_buf(meta_buf_bytes, &offset, module_len,
*(meta->modules + i));
if (module_len > MCP_TRACE_MAX_MODULE_LEN)
(*(meta->modules + i))[MCP_TRACE_MAX_MODULE_LEN] = '\0';
}
signature = qed_read_dword_from_buf(meta_buf_bytes, &offset);
if (signature != NVM_MAGIC_VALUE)
return DBG_STATUS_INVALID_TRACE_SIGNATURE;
meta->formats_num = qed_read_dword_from_buf(meta_buf_bytes, &offset);
meta->formats = kcalloc(meta->formats_num,
sizeof(struct mcp_trace_format),
GFP_KERNEL);
if (!meta->formats)
return DBG_STATUS_VIRT_MEM_ALLOC_FAILED;
for (i = 0; i < meta->formats_num; i++) {
struct mcp_trace_format *format_ptr = &meta->formats[i];
u8 format_len;
format_ptr->data = qed_read_dword_from_buf(meta_buf_bytes,
&offset);
format_len = GET_MFW_FIELD(format_ptr->data,
MCP_TRACE_FORMAT_LEN);
format_ptr->format_str = kzalloc(format_len, GFP_KERNEL);
if (!format_ptr->format_str) {
meta->formats_num = i ? i - 1 : 0;
return DBG_STATUS_VIRT_MEM_ALLOC_FAILED;
}
qed_read_str_from_buf(meta_buf_bytes,
&offset,
format_len, format_ptr->format_str);
}
meta->is_allocated = true;
return DBG_STATUS_OK;
}
static enum dbg_status qed_parse_mcp_trace_buf(struct qed_hwfn *p_hwfn,
u8 *trace_buf,
u32 trace_buf_size,
u32 data_offset,
u32 data_size,
char *parsed_buf,
u32 *parsed_results_bytes)
{
struct dbg_tools_user_data *dev_user_data;
struct mcp_trace_meta *meta;
u32 param_mask, param_shift;
enum dbg_status status;
dev_user_data = qed_dbg_get_user_data(p_hwfn);
meta = &dev_user_data->mcp_trace_meta;
*parsed_results_bytes = 0;
if (!meta->is_allocated)
return DBG_STATUS_MCP_TRACE_BAD_DATA;
status = DBG_STATUS_OK;
while (data_size) {
struct mcp_trace_format *format_ptr;
u8 format_level, format_module;
u32 params[3] = { 0, 0, 0 };
u32 header, format_idx, i;
if (data_size < MFW_TRACE_ENTRY_SIZE)
return DBG_STATUS_MCP_TRACE_BAD_DATA;
header = qed_read_from_cyclic_buf(trace_buf,
&data_offset,
trace_buf_size,
MFW_TRACE_ENTRY_SIZE);
data_size -= MFW_TRACE_ENTRY_SIZE;
format_idx = header & MFW_TRACE_EVENTID_MASK;
if (format_idx >= meta->formats_num) {
u8 format_size = (u8)GET_MFW_FIELD(header,
MFW_TRACE_PRM_SIZE);
if (data_size < format_size)
return DBG_STATUS_MCP_TRACE_BAD_DATA;
data_offset = qed_cyclic_add(data_offset,
format_size,
trace_buf_size);
data_size -= format_size;
continue;
}
format_ptr = &meta->formats[format_idx];
for (i = 0,
param_mask = MCP_TRACE_FORMAT_P1_SIZE_MASK, param_shift =
MCP_TRACE_FORMAT_P1_SIZE_OFFSET;
i < MCP_TRACE_FORMAT_MAX_PARAMS;
i++, param_mask <<= MCP_TRACE_FORMAT_PARAM_WIDTH,
param_shift += MCP_TRACE_FORMAT_PARAM_WIDTH) {
u8 param_size = (u8)((format_ptr->data & param_mask) >>
param_shift);
if (!param_size)
break;
if (param_size == 3)
param_size = 4;
if (data_size < param_size)
return DBG_STATUS_MCP_TRACE_BAD_DATA;
params[i] = qed_read_from_cyclic_buf(trace_buf,
&data_offset,
trace_buf_size,
param_size);
data_size -= param_size;
}
format_level = (u8)GET_MFW_FIELD(format_ptr->data,
MCP_TRACE_FORMAT_LEVEL);
format_module = (u8)GET_MFW_FIELD(format_ptr->data,
MCP_TRACE_FORMAT_MODULE);
if (format_level >= ARRAY_SIZE(s_mcp_trace_level_str))
return DBG_STATUS_MCP_TRACE_BAD_DATA;
*parsed_results_bytes +=
sprintf(qed_get_buf_ptr(parsed_buf,
*parsed_results_bytes),
"%s %-8s: ",
s_mcp_trace_level_str[format_level],
meta->modules[format_module]);
*parsed_results_bytes +=
sprintf(qed_get_buf_ptr(parsed_buf, *parsed_results_bytes),
format_ptr->format_str,
params[0], params[1], params[2]);
}
(*parsed_results_bytes)++;
return status;
}
static enum dbg_status qed_parse_mcp_trace_dump(struct qed_hwfn *p_hwfn,
u32 *dump_buf,
char *results_buf,
u32 *parsed_results_bytes,
bool free_meta_data)
{
const char *section_name, *param_name, *param_str_val;
u32 data_size, trace_data_dwords, trace_meta_dwords;
u32 offset, results_offset, results_buf_bytes;
u32 param_num_val, num_section_params;
struct mcp_trace *trace;
enum dbg_status status;
const u32 *meta_buf;
u8 *trace_buf;
*parsed_results_bytes = 0;
dump_buf += qed_read_section_hdr(dump_buf,
§ion_name, &num_section_params);
if (strcmp(section_name, "global_params"))
return DBG_STATUS_MCP_TRACE_BAD_DATA;
dump_buf += qed_print_section_params(dump_buf,
num_section_params,
results_buf, &results_offset);
dump_buf += qed_read_section_hdr(dump_buf,
§ion_name, &num_section_params);
if (strcmp(section_name, "mcp_trace_data") || num_section_params != 1)
return DBG_STATUS_MCP_TRACE_BAD_DATA;
dump_buf += qed_read_param(dump_buf,
¶m_name, ¶m_str_val, ¶m_num_val);
if (strcmp(param_name, "size"))
return DBG_STATUS_MCP_TRACE_BAD_DATA;
trace_data_dwords = param_num_val;
trace = (struct mcp_trace *)dump_buf;
if (trace->signature != MFW_TRACE_SIGNATURE || !trace->size)
return DBG_STATUS_MCP_TRACE_BAD_DATA;
trace_buf = (u8 *)dump_buf + sizeof(*trace);
offset = trace->trace_oldest;
data_size = qed_cyclic_sub(trace->trace_prod, offset, trace->size);
dump_buf += trace_data_dwords;
dump_buf += qed_read_section_hdr(dump_buf,
§ion_name, &num_section_params);
if (strcmp(section_name, "mcp_trace_meta"))
return DBG_STATUS_MCP_TRACE_BAD_DATA;
dump_buf += qed_read_param(dump_buf,
¶m_name, ¶m_str_val, ¶m_num_val);
if (strcmp(param_name, "size"))
return DBG_STATUS_MCP_TRACE_BAD_DATA;
trace_meta_dwords = param_num_val;
if (!trace_meta_dwords) {
struct dbg_tools_user_data *dev_user_data =
qed_dbg_get_user_data(p_hwfn);
if (!dev_user_data->mcp_trace_user_meta_buf)
return DBG_STATUS_MCP_TRACE_NO_META;
meta_buf = dev_user_data->mcp_trace_user_meta_buf;
} else {
meta_buf = dump_buf;
}
status = qed_mcp_trace_alloc_meta_data(p_hwfn, meta_buf);
if (status != DBG_STATUS_OK)
return status;
status = qed_parse_mcp_trace_buf(p_hwfn,
trace_buf,
trace->size,
offset,
data_size,
results_buf ?
results_buf + results_offset :
NULL,
&results_buf_bytes);
if (status != DBG_STATUS_OK)
return status;
if (free_meta_data)
qed_mcp_trace_free_meta_data(p_hwfn);
*parsed_results_bytes = results_offset + results_buf_bytes;
return DBG_STATUS_OK;
}
static enum dbg_status qed_parse_reg_fifo_dump(u32 *dump_buf,
char *results_buf,
u32 *parsed_results_bytes)
{
const char *section_name, *param_name, *param_str_val;
u32 param_num_val, num_section_params, num_elements;
struct reg_fifo_element *elements;
u8 i, j, err_code, vf_val;
u32 results_offset = 0;
char vf_str[4];
dump_buf += qed_read_section_hdr(dump_buf,
§ion_name, &num_section_params);
if (strcmp(section_name, "global_params"))
return DBG_STATUS_REG_FIFO_BAD_DATA;
dump_buf += qed_print_section_params(dump_buf,
num_section_params,
results_buf, &results_offset);
dump_buf += qed_read_section_hdr(dump_buf,
§ion_name, &num_section_params);
if (strcmp(section_name, "reg_fifo_data"))
return DBG_STATUS_REG_FIFO_BAD_DATA;
dump_buf += qed_read_param(dump_buf,
¶m_name, ¶m_str_val, ¶m_num_val);
if (strcmp(param_name, "size"))
return DBG_STATUS_REG_FIFO_BAD_DATA;
if (param_num_val % REG_FIFO_ELEMENT_DWORDS)
return DBG_STATUS_REG_FIFO_BAD_DATA;
num_elements = param_num_val / REG_FIFO_ELEMENT_DWORDS;
elements = (struct reg_fifo_element *)dump_buf;
for (i = 0; i < num_elements; i++) {
const char *err_msg = NULL;
vf_val = GET_FIELD(elements[i].data, REG_FIFO_ELEMENT_VF);
if (vf_val == REG_FIFO_ELEMENT_IS_PF_VF_VAL)
sprintf(vf_str, "%s", "N/A");
else
sprintf(vf_str, "%d", vf_val);
err_code = GET_FIELD(elements[i].data, REG_FIFO_ELEMENT_ERROR);
for (j = 0; j < ARRAY_SIZE(s_reg_fifo_errors) && !err_msg; j++)
if (err_code == s_reg_fifo_errors[j].err_code)
err_msg = s_reg_fifo_errors[j].err_msg;
results_offset +=
sprintf(qed_get_buf_ptr(results_buf,
results_offset),
"raw: 0x%016llx, address: 0x%07x, access: %-5s, pf: %2d, vf: %s, port: %d, privilege: %-3s, protection: %-12s, master: %-4s, error: %s\n",
elements[i].data,
(u32)GET_FIELD(elements[i].data,
REG_FIFO_ELEMENT_ADDRESS) *
REG_FIFO_ELEMENT_ADDR_FACTOR,
s_access_strs[GET_FIELD(elements[i].data,
REG_FIFO_ELEMENT_ACCESS)],
(u32)GET_FIELD(elements[i].data,
REG_FIFO_ELEMENT_PF),
vf_str,
(u32)GET_FIELD(elements[i].data,
REG_FIFO_ELEMENT_PORT),
s_privilege_strs[GET_FIELD(elements[i].data,
REG_FIFO_ELEMENT_PRIVILEGE)],
s_protection_strs[GET_FIELD(elements[i].data,
REG_FIFO_ELEMENT_PROTECTION)],
s_master_strs[GET_FIELD(elements[i].data,
REG_FIFO_ELEMENT_MASTER)],
err_msg ? err_msg : "unknown error code");
}
results_offset += sprintf(qed_get_buf_ptr(results_buf,
results_offset),
"fifo contained %d elements", num_elements);
*parsed_results_bytes = results_offset + 1;
return DBG_STATUS_OK;
}
static enum dbg_status qed_parse_igu_fifo_element(struct igu_fifo_element
*element, char
*results_buf,
u32 *results_offset)
{
const struct igu_fifo_addr_data *found_addr = NULL;
u8 source, err_type, i, is_cleanup;
char parsed_addr_data[32];
char parsed_wr_data[256];
u32 wr_data, prod_cons;
bool is_wr_cmd, is_pf;
u16 cmd_addr;
u64 dword12;
dword12 = ((u64)element->dword2 << 32) | element->dword1;
is_wr_cmd = GET_FIELD(dword12, IGU_FIFO_ELEMENT_DWORD12_IS_WR_CMD);
is_pf = GET_FIELD(element->dword0, IGU_FIFO_ELEMENT_DWORD0_IS_PF);
cmd_addr = GET_FIELD(element->dword0, IGU_FIFO_ELEMENT_DWORD0_CMD_ADDR);
source = GET_FIELD(element->dword0, IGU_FIFO_ELEMENT_DWORD0_SOURCE);
err_type = GET_FIELD(element->dword0, IGU_FIFO_ELEMENT_DWORD0_ERR_TYPE);
if (source >= ARRAY_SIZE(s_igu_fifo_source_strs))
return DBG_STATUS_IGU_FIFO_BAD_DATA;
if (err_type >= ARRAY_SIZE(s_igu_fifo_error_strs))
return DBG_STATUS_IGU_FIFO_BAD_DATA;
for (i = 0; i < ARRAY_SIZE(s_igu_fifo_addr_data) && !found_addr; i++) {
const struct igu_fifo_addr_data *curr_addr =
&s_igu_fifo_addr_data[i];
if (cmd_addr >= curr_addr->start_addr && cmd_addr <=
curr_addr->end_addr)
found_addr = curr_addr;
}
if (!found_addr)
return DBG_STATUS_IGU_FIFO_BAD_DATA;
switch (found_addr->type) {
case IGU_ADDR_TYPE_MSIX_MEM:
sprintf(parsed_addr_data, " vector_num = 0x%x", cmd_addr / 2);
break;
case IGU_ADDR_TYPE_WRITE_INT_ACK:
case IGU_ADDR_TYPE_WRITE_PROD_UPDATE:
sprintf(parsed_addr_data,
" SB = 0x%x", cmd_addr - found_addr->start_addr);
break;
default:
parsed_addr_data[0] = '\0';
}
if (!is_wr_cmd) {
parsed_wr_data[0] = '\0';
goto out;
}
wr_data = GET_FIELD(dword12, IGU_FIFO_ELEMENT_DWORD12_WR_DATA);
prod_cons = GET_FIELD(wr_data, IGU_FIFO_WR_DATA_PROD_CONS);
is_cleanup = GET_FIELD(wr_data, IGU_FIFO_WR_DATA_CMD_TYPE);
if (source == IGU_SRC_ATTN) {
sprintf(parsed_wr_data, "prod: 0x%x, ", prod_cons);
} else {
if (is_cleanup) {
u8 cleanup_val, cleanup_type;
cleanup_val =
GET_FIELD(wr_data,
IGU_FIFO_CLEANUP_WR_DATA_CLEANUP_VAL);
cleanup_type =
GET_FIELD(wr_data,
IGU_FIFO_CLEANUP_WR_DATA_CLEANUP_TYPE);
sprintf(parsed_wr_data,
"cmd_type: cleanup, cleanup_val: %s, cleanup_type : %d, ",
cleanup_val ? "set" : "clear",
cleanup_type);
} else {
u8 update_flag, en_dis_int_for_sb, segment;
u8 timer_mask;
update_flag = GET_FIELD(wr_data,
IGU_FIFO_WR_DATA_UPDATE_FLAG);
en_dis_int_for_sb =
GET_FIELD(wr_data,
IGU_FIFO_WR_DATA_EN_DIS_INT_FOR_SB);
segment = GET_FIELD(wr_data,
IGU_FIFO_WR_DATA_SEGMENT);
timer_mask = GET_FIELD(wr_data,
IGU_FIFO_WR_DATA_TIMER_MASK);
sprintf(parsed_wr_data,
"cmd_type: prod/cons update, prod/cons: 0x%x, update_flag: %s, en_dis_int_for_sb : %s, segment : %s, timer_mask = %d, ",
prod_cons,
update_flag ? "update" : "nop",
en_dis_int_for_sb ?
(en_dis_int_for_sb == 1 ? "disable" : "nop") :
"enable",
segment ? "attn" : "regular",
timer_mask);
}
}
out:
*results_offset += sprintf(qed_get_buf_ptr(results_buf,
*results_offset),
"raw: 0x%01x%08x%08x, %s: %d, source : %s, type : %s, cmd_addr : 0x%x(%s%s), %serror: %s\n",
element->dword2, element->dword1,
element->dword0,
is_pf ? "pf" : "vf",
GET_FIELD(element->dword0,
IGU_FIFO_ELEMENT_DWORD0_FID),
s_igu_fifo_source_strs[source],
is_wr_cmd ? "wr" : "rd",
cmd_addr,
(!is_pf && found_addr->vf_desc)
? found_addr->vf_desc
: found_addr->desc,
parsed_addr_data,
parsed_wr_data,
s_igu_fifo_error_strs[err_type]);
return DBG_STATUS_OK;
}
static enum dbg_status qed_parse_igu_fifo_dump(u32 *dump_buf,
char *results_buf,
u32 *parsed_results_bytes)
{
const char *section_name, *param_name, *param_str_val;
u32 param_num_val, num_section_params, num_elements;
struct igu_fifo_element *elements;
enum dbg_status status;
u32 results_offset = 0;
u8 i;
dump_buf += qed_read_section_hdr(dump_buf,
§ion_name, &num_section_params);
if (strcmp(section_name, "global_params"))
return DBG_STATUS_IGU_FIFO_BAD_DATA;
dump_buf += qed_print_section_params(dump_buf,
num_section_params,
results_buf, &results_offset);
dump_buf += qed_read_section_hdr(dump_buf,
§ion_name, &num_section_params);
if (strcmp(section_name, "igu_fifo_data"))
return DBG_STATUS_IGU_FIFO_BAD_DATA;
dump_buf += qed_read_param(dump_buf,
¶m_name, ¶m_str_val, ¶m_num_val);
if (strcmp(param_name, "size"))
return DBG_STATUS_IGU_FIFO_BAD_DATA;
if (param_num_val % IGU_FIFO_ELEMENT_DWORDS)
return DBG_STATUS_IGU_FIFO_BAD_DATA;
num_elements = param_num_val / IGU_FIFO_ELEMENT_DWORDS;
elements = (struct igu_fifo_element *)dump_buf;
for (i = 0; i < num_elements; i++) {
status = qed_parse_igu_fifo_element(&elements[i],
results_buf,
&results_offset);
if (status != DBG_STATUS_OK)
return status;
}
results_offset += sprintf(qed_get_buf_ptr(results_buf,
results_offset),
"fifo contained %d elements", num_elements);
*parsed_results_bytes = results_offset + 1;
return DBG_STATUS_OK;
}
static enum dbg_status
qed_parse_protection_override_dump(u32 *dump_buf,
char *results_buf,
u32 *parsed_results_bytes)
{
const char *section_name, *param_name, *param_str_val;
u32 param_num_val, num_section_params, num_elements;
struct protection_override_element *elements;
u32 results_offset = 0;
u8 i;
dump_buf += qed_read_section_hdr(dump_buf,
§ion_name, &num_section_params);
if (strcmp(section_name, "global_params"))
return DBG_STATUS_PROTECTION_OVERRIDE_BAD_DATA;
dump_buf += qed_print_section_params(dump_buf,
num_section_params,
results_buf, &results_offset);
dump_buf += qed_read_section_hdr(dump_buf,
§ion_name, &num_section_params);
if (strcmp(section_name, "protection_override_data"))
return DBG_STATUS_PROTECTION_OVERRIDE_BAD_DATA;
dump_buf += qed_read_param(dump_buf,
¶m_name, ¶m_str_val, ¶m_num_val);
if (strcmp(param_name, "size"))
return DBG_STATUS_PROTECTION_OVERRIDE_BAD_DATA;
if (param_num_val % PROTECTION_OVERRIDE_ELEMENT_DWORDS)
return DBG_STATUS_PROTECTION_OVERRIDE_BAD_DATA;
num_elements = param_num_val / PROTECTION_OVERRIDE_ELEMENT_DWORDS;
elements = (struct protection_override_element *)dump_buf;
for (i = 0; i < num_elements; i++) {
u32 address = GET_FIELD(elements[i].data,
PROTECTION_OVERRIDE_ELEMENT_ADDRESS) *
PROTECTION_OVERRIDE_ELEMENT_ADDR_FACTOR;
results_offset +=
sprintf(qed_get_buf_ptr(results_buf,
results_offset),
"window %2d, address: 0x%07x, size: %7d regs, read: %d, write: %d, read protection: %-12s, write protection: %-12s\n",
i, address,
(u32)GET_FIELD(elements[i].data,
PROTECTION_OVERRIDE_ELEMENT_WINDOW_SIZE),
(u32)GET_FIELD(elements[i].data,
PROTECTION_OVERRIDE_ELEMENT_READ),
(u32)GET_FIELD(elements[i].data,
PROTECTION_OVERRIDE_ELEMENT_WRITE),
s_protection_strs[GET_FIELD(elements[i].data,
PROTECTION_OVERRIDE_ELEMENT_READ_PROTECTION)],
s_protection_strs[GET_FIELD(elements[i].data,
PROTECTION_OVERRIDE_ELEMENT_WRITE_PROTECTION)]);
}
results_offset += sprintf(qed_get_buf_ptr(results_buf,
results_offset),
"protection override contained %d elements",
num_elements);
*parsed_results_bytes = results_offset + 1;
return DBG_STATUS_OK;
}
static enum dbg_status qed_parse_fw_asserts_dump(u32 *dump_buf,
char *results_buf,
u32 *parsed_results_bytes)
{
u32 num_section_params, param_num_val, i, results_offset = 0;
const char *param_name, *param_str_val, *section_name;
bool last_section_found = false;
*parsed_results_bytes = 0;
dump_buf += qed_read_section_hdr(dump_buf,
§ion_name, &num_section_params);
if (strcmp(section_name, "global_params"))
return DBG_STATUS_FW_ASSERTS_PARSE_FAILED;
dump_buf += qed_print_section_params(dump_buf,
num_section_params,
results_buf, &results_offset);
while (!last_section_found) {
dump_buf += qed_read_section_hdr(dump_buf,
§ion_name,
&num_section_params);
if (!strcmp(section_name, "fw_asserts")) {
const char *storm_letter = NULL;
u32 storm_dump_size = 0;
for (i = 0; i < num_section_params; i++) {
dump_buf += qed_read_param(dump_buf,
¶m_name,
¶m_str_val,
¶m_num_val);
if (!strcmp(param_name, "storm"))
storm_letter = param_str_val;
else if (!strcmp(param_name, "size"))
storm_dump_size = param_num_val;
else
return
DBG_STATUS_FW_ASSERTS_PARSE_FAILED;
}
if (!storm_letter || !storm_dump_size)
return DBG_STATUS_FW_ASSERTS_PARSE_FAILED;
results_offset +=
sprintf(qed_get_buf_ptr(results_buf,
results_offset),
"\n%sSTORM_ASSERT: size=%d\n",
storm_letter, storm_dump_size);
for (i = 0; i < storm_dump_size; i++, dump_buf++)
results_offset +=
sprintf(qed_get_buf_ptr(results_buf,
results_offset),
"%08x\n", *dump_buf);
} else if (!strcmp(section_name, "last")) {
last_section_found = true;
} else {
return DBG_STATUS_FW_ASSERTS_PARSE_FAILED;
}
}
*parsed_results_bytes = results_offset + 1;
return DBG_STATUS_OK;
}
enum dbg_status qed_dbg_user_set_bin_ptr(struct qed_hwfn *p_hwfn,
const u8 * const bin_ptr)
{
struct bin_buffer_hdr *buf_hdrs = (struct bin_buffer_hdr *)bin_ptr;
u8 buf_id;
for (buf_id = 0; buf_id < MAX_BIN_DBG_BUFFER_TYPE; buf_id++)
qed_set_dbg_bin_buf(p_hwfn,
(enum bin_dbg_buffer_type)buf_id,
(u32 *)(bin_ptr + buf_hdrs[buf_id].offset),
buf_hdrs[buf_id].length);
return DBG_STATUS_OK;
}
enum dbg_status qed_dbg_alloc_user_data(struct qed_hwfn *p_hwfn,
void **user_data_ptr)
{
*user_data_ptr = kzalloc(sizeof(struct dbg_tools_user_data),
GFP_KERNEL);
if (!(*user_data_ptr))
return DBG_STATUS_VIRT_MEM_ALLOC_FAILED;
return DBG_STATUS_OK;
}
const char *qed_dbg_get_status_str(enum dbg_status status)
{
return (status <
MAX_DBG_STATUS) ? s_status_str[status] : "Invalid debug status";
}
enum dbg_status qed_get_idle_chk_results_buf_size(struct qed_hwfn *p_hwfn,
u32 *dump_buf,
u32 num_dumped_dwords,
u32 *results_buf_size)
{
u32 num_errors, num_warnings;
return qed_parse_idle_chk_dump(p_hwfn,
dump_buf,
num_dumped_dwords,
NULL,
results_buf_size,
&num_errors, &num_warnings);
}
enum dbg_status qed_print_idle_chk_results(struct qed_hwfn *p_hwfn,
u32 *dump_buf,
u32 num_dumped_dwords,
char *results_buf,
u32 *num_errors,
u32 *num_warnings)
{
u32 parsed_buf_size;
return qed_parse_idle_chk_dump(p_hwfn,
dump_buf,
num_dumped_dwords,
results_buf,
&parsed_buf_size,
num_errors, num_warnings);
}
void qed_dbg_mcp_trace_set_meta_data(struct qed_hwfn *p_hwfn,
const u32 *meta_buf)
{
struct dbg_tools_user_data *dev_user_data =
qed_dbg_get_user_data(p_hwfn);
dev_user_data->mcp_trace_user_meta_buf = meta_buf;
}
enum dbg_status qed_get_mcp_trace_results_buf_size(struct qed_hwfn *p_hwfn,
u32 *dump_buf,
u32 num_dumped_dwords,
u32 *results_buf_size)
{
return qed_parse_mcp_trace_dump(p_hwfn,
dump_buf, NULL, results_buf_size, true);
}
enum dbg_status qed_print_mcp_trace_results(struct qed_hwfn *p_hwfn,
u32 *dump_buf,
u32 num_dumped_dwords,
char *results_buf)
{
u32 parsed_buf_size;
qed_user_static_asserts();
return qed_parse_mcp_trace_dump(p_hwfn,
dump_buf,
results_buf, &parsed_buf_size, true);
}
enum dbg_status qed_print_mcp_trace_results_cont(struct qed_hwfn *p_hwfn,
u32 *dump_buf,
char *results_buf)
{
u32 parsed_buf_size;
return qed_parse_mcp_trace_dump(p_hwfn, dump_buf, results_buf,
&parsed_buf_size, false);
}
enum dbg_status qed_print_mcp_trace_line(struct qed_hwfn *p_hwfn,
u8 *dump_buf,
u32 num_dumped_bytes,
char *results_buf)
{
u32 parsed_results_bytes;
return qed_parse_mcp_trace_buf(p_hwfn,
dump_buf,
num_dumped_bytes,
0,
num_dumped_bytes,
results_buf, &parsed_results_bytes);
}
void qed_mcp_trace_free_meta_data(struct qed_hwfn *p_hwfn)
{
struct dbg_tools_user_data *dev_user_data;
struct mcp_trace_meta *meta;
u32 i;
dev_user_data = qed_dbg_get_user_data(p_hwfn);
meta = &dev_user_data->mcp_trace_meta;
if (!meta->is_allocated)
return;
if (meta->modules) {
for (i = 0; i < meta->modules_num; i++)
kfree(meta->modules[i]);
kfree(meta->modules);
}
if (meta->formats) {
for (i = 0; i < meta->formats_num; i++)
kfree(meta->formats[i].format_str);
kfree(meta->formats);
}
meta->is_allocated = false;
}
enum dbg_status qed_get_reg_fifo_results_buf_size(struct qed_hwfn *p_hwfn,
u32 *dump_buf,
u32 num_dumped_dwords,
u32 *results_buf_size)
{
return qed_parse_reg_fifo_dump(dump_buf, NULL, results_buf_size);
}
enum dbg_status qed_print_reg_fifo_results(struct qed_hwfn *p_hwfn,
u32 *dump_buf,
u32 num_dumped_dwords,
char *results_buf)
{
u32 parsed_buf_size;
return qed_parse_reg_fifo_dump(dump_buf, results_buf, &parsed_buf_size);
}
enum dbg_status qed_get_igu_fifo_results_buf_size(struct qed_hwfn *p_hwfn,
u32 *dump_buf,
u32 num_dumped_dwords,
u32 *results_buf_size)
{
return qed_parse_igu_fifo_dump(dump_buf, NULL, results_buf_size);
}
enum dbg_status qed_print_igu_fifo_results(struct qed_hwfn *p_hwfn,
u32 *dump_buf,
u32 num_dumped_dwords,
char *results_buf)
{
u32 parsed_buf_size;
return qed_parse_igu_fifo_dump(dump_buf, results_buf, &parsed_buf_size);
}
enum dbg_status
qed_get_protection_override_results_buf_size(struct qed_hwfn *p_hwfn,
u32 *dump_buf,
u32 num_dumped_dwords,
u32 *results_buf_size)
{
return qed_parse_protection_override_dump(dump_buf,
NULL, results_buf_size);
}
enum dbg_status qed_print_protection_override_results(struct qed_hwfn *p_hwfn,
u32 *dump_buf,
u32 num_dumped_dwords,
char *results_buf)
{
u32 parsed_buf_size;
return qed_parse_protection_override_dump(dump_buf,
results_buf,
&parsed_buf_size);
}
enum dbg_status qed_get_fw_asserts_results_buf_size(struct qed_hwfn *p_hwfn,
u32 *dump_buf,
u32 num_dumped_dwords,
u32 *results_buf_size)
{
return qed_parse_fw_asserts_dump(dump_buf, NULL, results_buf_size);
}
enum dbg_status qed_print_fw_asserts_results(struct qed_hwfn *p_hwfn,
u32 *dump_buf,
u32 num_dumped_dwords,
char *results_buf)
{
u32 parsed_buf_size;
return qed_parse_fw_asserts_dump(dump_buf,
results_buf, &parsed_buf_size);
}
enum dbg_status qed_dbg_parse_attn(struct qed_hwfn *p_hwfn,
struct dbg_attn_block_result *results)
{
const u32 *block_attn_name_offsets;
const char *attn_name_base;
const char *block_name;
enum dbg_attn_type attn_type;
u8 num_regs, i, j;
num_regs = GET_FIELD(results->data, DBG_ATTN_BLOCK_RESULT_NUM_REGS);
attn_type = GET_FIELD(results->data, DBG_ATTN_BLOCK_RESULT_ATTN_TYPE);
block_name = qed_dbg_get_block_name(p_hwfn, results->block_id);
if (!block_name)
return DBG_STATUS_INVALID_ARGS;
if (!p_hwfn->dbg_arrays[BIN_BUF_DBG_ATTN_INDEXES].ptr ||
!p_hwfn->dbg_arrays[BIN_BUF_DBG_ATTN_NAME_OFFSETS].ptr ||
!p_hwfn->dbg_arrays[BIN_BUF_DBG_PARSING_STRINGS].ptr)
return DBG_STATUS_DBG_ARRAY_NOT_SET;
block_attn_name_offsets =
(u32 *)p_hwfn->dbg_arrays[BIN_BUF_DBG_ATTN_NAME_OFFSETS].ptr +
results->names_offset;
attn_name_base = p_hwfn->dbg_arrays[BIN_BUF_DBG_PARSING_STRINGS].ptr;
for (i = 0; i < num_regs; i++) {
struct dbg_attn_bit_mapping *bit_mapping;
struct dbg_attn_reg_result *reg_result;
u8 num_reg_attn, bit_idx = 0;
reg_result = &results->reg_results[i];
num_reg_attn = GET_FIELD(reg_result->data,
DBG_ATTN_REG_RESULT_NUM_REG_ATTN);
bit_mapping = (struct dbg_attn_bit_mapping *)
p_hwfn->dbg_arrays[BIN_BUF_DBG_ATTN_INDEXES].ptr +
reg_result->block_attn_offset;
for (j = 0; j < num_reg_attn; j++) {
u16 attn_idx_val = GET_FIELD(bit_mapping[j].data,
DBG_ATTN_BIT_MAPPING_VAL);
const char *attn_name, *attn_type_str, *masked_str;
u32 attn_name_offset;
u32 sts_addr;
if (GET_FIELD(bit_mapping[j].data,
DBG_ATTN_BIT_MAPPING_IS_UNUSED_BIT_CNT)) {
bit_idx += (u8)attn_idx_val;
continue;
}
if (reg_result->sts_val & BIT(bit_idx)) {
attn_name_offset =
block_attn_name_offsets[attn_idx_val];
attn_name = attn_name_base + attn_name_offset;
attn_type_str =
(attn_type ==
ATTN_TYPE_INTERRUPT ? "Interrupt" :
"Parity");
masked_str = reg_result->mask_val &
BIT(bit_idx) ?
" [masked]" : "";
sts_addr =
GET_FIELD(reg_result->data,
DBG_ATTN_REG_RESULT_STS_ADDRESS);
DP_NOTICE(p_hwfn,
"%s (%s) : %s [address 0x%08x, bit %d]%s\n",
block_name, attn_type_str, attn_name,
sts_addr * 4, bit_idx, masked_str);
}
bit_idx++;
}
}
return DBG_STATUS_OK;
}
static enum dbg_status
qed_print_idle_chk_results_wrapper(struct qed_hwfn *p_hwfn,
u32 *dump_buf,
u32 num_dumped_dwords,
char *results_buf)
{
u32 num_errors, num_warnnings;
return qed_print_idle_chk_results(p_hwfn, dump_buf, num_dumped_dwords,
results_buf, &num_errors,
&num_warnnings);
}
static DEFINE_MUTEX(qed_dbg_lock);
#define MAX_PHY_RESULT_BUFFER 9000
#define GRC_NUM_STR_FUNCS 2
#define IDLE_CHK_NUM_STR_FUNCS 1
#define MCP_TRACE_NUM_STR_FUNCS 1
#define REG_FIFO_NUM_STR_FUNCS 1
#define IGU_FIFO_NUM_STR_FUNCS 1
#define PROTECTION_OVERRIDE_NUM_STR_FUNCS 1
#define FW_ASSERTS_NUM_STR_FUNCS 1
#define ILT_NUM_STR_FUNCS 1
#define PHY_NUM_STR_FUNCS 20
static struct {
char *name;
u32 num_funcs;
enum dbg_status (*get_size)(struct qed_hwfn *p_hwfn,
struct qed_ptt *p_ptt, u32 *size);
enum dbg_status (*perform_dump)(struct qed_hwfn *p_hwfn,
struct qed_ptt *p_ptt, u32 *dump_buf,
u32 buf_size, u32 *dumped_dwords);
enum dbg_status (*print_results)(struct qed_hwfn *p_hwfn,
u32 *dump_buf, u32 num_dumped_dwords,
char *results_buf);
enum dbg_status (*results_buf_size)(struct qed_hwfn *p_hwfn,
u32 *dump_buf,
u32 num_dumped_dwords,
u32 *results_buf_size);
const struct qed_func_lookup *hsi_func_lookup;
} qed_features_lookup[] = {
{
"grc", GRC_NUM_STR_FUNCS, qed_dbg_grc_get_dump_buf_size,
qed_dbg_grc_dump, NULL, NULL, NULL}, {
"idle_chk", IDLE_CHK_NUM_STR_FUNCS,
qed_dbg_idle_chk_get_dump_buf_size,
qed_dbg_idle_chk_dump,
qed_print_idle_chk_results_wrapper,
qed_get_idle_chk_results_buf_size,
NULL}, {
"mcp_trace", MCP_TRACE_NUM_STR_FUNCS,
qed_dbg_mcp_trace_get_dump_buf_size,
qed_dbg_mcp_trace_dump, qed_print_mcp_trace_results,
qed_get_mcp_trace_results_buf_size,
NULL}, {
"reg_fifo", REG_FIFO_NUM_STR_FUNCS,
qed_dbg_reg_fifo_get_dump_buf_size,
qed_dbg_reg_fifo_dump, qed_print_reg_fifo_results,
qed_get_reg_fifo_results_buf_size,
NULL}, {
"igu_fifo", IGU_FIFO_NUM_STR_FUNCS,
qed_dbg_igu_fifo_get_dump_buf_size,
qed_dbg_igu_fifo_dump, qed_print_igu_fifo_results,
qed_get_igu_fifo_results_buf_size,
NULL}, {
"protection_override", PROTECTION_OVERRIDE_NUM_STR_FUNCS,
qed_dbg_protection_override_get_dump_buf_size,
qed_dbg_protection_override_dump,
qed_print_protection_override_results,
qed_get_protection_override_results_buf_size,
NULL}, {
"fw_asserts", FW_ASSERTS_NUM_STR_FUNCS,
qed_dbg_fw_asserts_get_dump_buf_size,
qed_dbg_fw_asserts_dump,
qed_print_fw_asserts_results,
qed_get_fw_asserts_results_buf_size,
NULL}, {
"ilt", ILT_NUM_STR_FUNCS, qed_dbg_ilt_get_dump_buf_size,
qed_dbg_ilt_dump, NULL, NULL, NULL},};
static void qed_dbg_print_feature(u8 *p_text_buf, u32 text_size)
{
u32 i, precision = 80;
if (!p_text_buf)
return;
pr_notice("\n%.*s", precision, p_text_buf);
for (i = precision; i < text_size; i += precision)
pr_cont("%.*s", precision, p_text_buf + i);
pr_cont("\n");
}
#define QED_RESULTS_BUF_MIN_SIZE 16
static enum dbg_status format_feature(struct qed_hwfn *p_hwfn,
enum qed_dbg_features feature_idx)
{
struct qed_dbg_feature *feature =
&p_hwfn->cdev->dbg_features[feature_idx];
u32 txt_size_bytes, null_char_pos, i;
u32 *dbuf, dwords;
enum dbg_status rc;
char *text_buf;
if (!qed_features_lookup[feature_idx].results_buf_size)
return DBG_STATUS_OK;
dbuf = (u32 *)feature->dump_buf;
dwords = feature->dumped_dwords;
rc = qed_features_lookup[feature_idx].results_buf_size(p_hwfn,
dbuf,
dwords,
&txt_size_bytes);
if (rc != DBG_STATUS_OK)
return rc;
null_char_pos = txt_size_bytes - 1;
txt_size_bytes = (txt_size_bytes + 3) & ~0x3;
if (txt_size_bytes < QED_RESULTS_BUF_MIN_SIZE) {
DP_NOTICE(p_hwfn->cdev,
"formatted size of feature was too small %d. Aborting\n",
txt_size_bytes);
return DBG_STATUS_INVALID_ARGS;
}
text_buf = vzalloc(txt_size_bytes);
if (!text_buf) {
DP_NOTICE(p_hwfn->cdev,
"failed to allocate text buffer. Aborting\n");
return DBG_STATUS_VIRT_MEM_ALLOC_FAILED;
}
rc = qed_features_lookup[feature_idx].print_results(p_hwfn,
dbuf,
dwords,
text_buf);
if (rc != DBG_STATUS_OK) {
vfree(text_buf);
return rc;
}
for (i = null_char_pos; i < txt_size_bytes; i++)
text_buf[i] = '\n';
if (p_hwfn->cdev->print_dbg_data)
qed_dbg_print_feature(text_buf, txt_size_bytes);
if (p_hwfn->cdev->dbg_bin_dump) {
vfree(text_buf);
return rc;
}
vfree(feature->dump_buf);
feature->dump_buf = text_buf;
feature->buf_size = txt_size_bytes;
feature->dumped_dwords = txt_size_bytes / 4;
return rc;
}
#define MAX_DBG_FEATURE_SIZE_DWORDS 0x3FFFFFFF
static enum dbg_status qed_dbg_dump(struct qed_hwfn *p_hwfn,
struct qed_ptt *p_ptt,
enum qed_dbg_features feature_idx)
{
struct qed_dbg_feature *feature =
&p_hwfn->cdev->dbg_features[feature_idx];
u32 buf_size_dwords, *dbuf, *dwords;
enum dbg_status rc;
DP_NOTICE(p_hwfn->cdev, "Collecting a debug feature [\"%s\"]\n",
qed_features_lookup[feature_idx].name);
if (feature->dump_buf) {
vfree(feature->dump_buf);
feature->dump_buf = NULL;
}
rc = qed_features_lookup[feature_idx].get_size(p_hwfn, p_ptt,
&buf_size_dwords);
if (rc != DBG_STATUS_OK && rc != DBG_STATUS_NVRAM_GET_IMAGE_FAILED)
return rc;
if (buf_size_dwords > MAX_DBG_FEATURE_SIZE_DWORDS) {
feature->buf_size = 0;
DP_NOTICE(p_hwfn->cdev,
"Debug feature [\"%s\"] size (0x%x dwords) exceeds maximum size (0x%x dwords)\n",
qed_features_lookup[feature_idx].name,
buf_size_dwords, MAX_DBG_FEATURE_SIZE_DWORDS);
return DBG_STATUS_OK;
}
feature->buf_size = buf_size_dwords * sizeof(u32);
feature->dump_buf = vmalloc(feature->buf_size);
if (!feature->dump_buf)
return DBG_STATUS_VIRT_MEM_ALLOC_FAILED;
dbuf = (u32 *)feature->dump_buf;
dwords = &feature->dumped_dwords;
rc = qed_features_lookup[feature_idx].perform_dump(p_hwfn, p_ptt,
dbuf,
feature->buf_size /
sizeof(u32),
dwords);
if (rc == DBG_STATUS_NVRAM_GET_IMAGE_FAILED)
return DBG_STATUS_OK;
if (rc != DBG_STATUS_OK)
return rc;
rc = format_feature(p_hwfn, feature_idx);
return rc;
}
int qed_dbg_grc(struct qed_dev *cdev, void *buffer, u32 *num_dumped_bytes)
{
return qed_dbg_feature(cdev, buffer, DBG_FEATURE_GRC, num_dumped_bytes);
}
int qed_dbg_grc_size(struct qed_dev *cdev)
{
return qed_dbg_feature_size(cdev, DBG_FEATURE_GRC);
}
int qed_dbg_idle_chk(struct qed_dev *cdev, void *buffer, u32 *num_dumped_bytes)
{
return qed_dbg_feature(cdev, buffer, DBG_FEATURE_IDLE_CHK,
num_dumped_bytes);
}
int qed_dbg_idle_chk_size(struct qed_dev *cdev)
{
return qed_dbg_feature_size(cdev, DBG_FEATURE_IDLE_CHK);
}
int qed_dbg_reg_fifo(struct qed_dev *cdev, void *buffer, u32 *num_dumped_bytes)
{
return qed_dbg_feature(cdev, buffer, DBG_FEATURE_REG_FIFO,
num_dumped_bytes);
}
int qed_dbg_reg_fifo_size(struct qed_dev *cdev)
{
return qed_dbg_feature_size(cdev, DBG_FEATURE_REG_FIFO);
}
int qed_dbg_igu_fifo(struct qed_dev *cdev, void *buffer, u32 *num_dumped_bytes)
{
return qed_dbg_feature(cdev, buffer, DBG_FEATURE_IGU_FIFO,
num_dumped_bytes);
}
int qed_dbg_igu_fifo_size(struct qed_dev *cdev)
{
return qed_dbg_feature_size(cdev, DBG_FEATURE_IGU_FIFO);
}
static int qed_dbg_nvm_image_length(struct qed_hwfn *p_hwfn,
enum qed_nvm_images image_id, u32 *length)
{
struct qed_nvm_image_att image_att;
int rc;
*length = 0;
rc = qed_mcp_get_nvm_image_att(p_hwfn, image_id, &image_att);
if (rc)
return rc;
*length = image_att.length;
return rc;
}
static int qed_dbg_nvm_image(struct qed_dev *cdev, void *buffer,
u32 *num_dumped_bytes,
enum qed_nvm_images image_id)
{
struct qed_hwfn *p_hwfn =
&cdev->hwfns[cdev->engine_for_debug];
u32 len_rounded;
int rc;
*num_dumped_bytes = 0;
rc = qed_dbg_nvm_image_length(p_hwfn, image_id, &len_rounded);
if (rc)
return rc;
DP_NOTICE(p_hwfn->cdev,
"Collecting a debug feature [\"nvram image %d\"]\n",
image_id);
len_rounded = roundup(len_rounded, sizeof(u32));
rc = qed_mcp_get_nvm_image(p_hwfn, image_id, buffer, len_rounded);
if (rc)
return rc;
if (image_id != QED_NVM_IMAGE_NVM_META)
cpu_to_be32_array((__force __be32 *)buffer,
(const u32 *)buffer,
len_rounded / sizeof(u32));
*num_dumped_bytes = len_rounded;
return rc;
}
int qed_dbg_protection_override(struct qed_dev *cdev, void *buffer,
u32 *num_dumped_bytes)
{
return qed_dbg_feature(cdev, buffer, DBG_FEATURE_PROTECTION_OVERRIDE,
num_dumped_bytes);
}
int qed_dbg_protection_override_size(struct qed_dev *cdev)
{
return qed_dbg_feature_size(cdev, DBG_FEATURE_PROTECTION_OVERRIDE);
}
int qed_dbg_fw_asserts(struct qed_dev *cdev, void *buffer,
u32 *num_dumped_bytes)
{
return qed_dbg_feature(cdev, buffer, DBG_FEATURE_FW_ASSERTS,
num_dumped_bytes);
}
int qed_dbg_fw_asserts_size(struct qed_dev *cdev)
{
return qed_dbg_feature_size(cdev, DBG_FEATURE_FW_ASSERTS);
}
int qed_dbg_ilt(struct qed_dev *cdev, void *buffer, u32 *num_dumped_bytes)
{
return qed_dbg_feature(cdev, buffer, DBG_FEATURE_ILT, num_dumped_bytes);
}
int qed_dbg_ilt_size(struct qed_dev *cdev)
{
return qed_dbg_feature_size(cdev, DBG_FEATURE_ILT);
}
int qed_dbg_mcp_trace(struct qed_dev *cdev, void *buffer,
u32 *num_dumped_bytes)
{
return qed_dbg_feature(cdev, buffer, DBG_FEATURE_MCP_TRACE,
num_dumped_bytes);
}
int qed_dbg_mcp_trace_size(struct qed_dev *cdev)
{
return qed_dbg_feature_size(cdev, DBG_FEATURE_MCP_TRACE);
}
#define REGDUMP_HEADER_SIZE sizeof(u32)
#define REGDUMP_HEADER_SIZE_SHIFT 0
#define REGDUMP_HEADER_SIZE_MASK 0xffffff
#define REGDUMP_HEADER_FEATURE_SHIFT 24
#define REGDUMP_HEADER_FEATURE_MASK 0x1f
#define REGDUMP_HEADER_BIN_DUMP_SHIFT 29
#define REGDUMP_HEADER_BIN_DUMP_MASK 0x1
#define REGDUMP_HEADER_OMIT_ENGINE_SHIFT 30
#define REGDUMP_HEADER_OMIT_ENGINE_MASK 0x1
#define REGDUMP_HEADER_ENGINE_SHIFT 31
#define REGDUMP_HEADER_ENGINE_MASK 0x1
#define REGDUMP_MAX_SIZE 0x1000000
#define ILT_DUMP_MAX_SIZE (1024 * 1024 * 15)
enum debug_print_features {
OLD_MODE = 0,
IDLE_CHK = 1,
GRC_DUMP = 2,
MCP_TRACE = 3,
REG_FIFO = 4,
PROTECTION_OVERRIDE = 5,
IGU_FIFO = 6,
PHY = 7,
FW_ASSERTS = 8,
NVM_CFG1 = 9,
DEFAULT_CFG = 10,
NVM_META = 11,
MDUMP = 12,
ILT_DUMP = 13,
};
static u32 qed_calc_regdump_header(struct qed_dev *cdev,
enum debug_print_features feature,
int engine, u32 feature_size,
u8 omit_engine, u8 dbg_bin_dump)
{
u32 res = 0;
SET_FIELD(res, REGDUMP_HEADER_SIZE, feature_size);
if (res != feature_size)
DP_NOTICE(cdev,
"Feature %d is too large (size 0x%x) and will corrupt the dump\n",
feature, feature_size);
SET_FIELD(res, REGDUMP_HEADER_FEATURE, feature);
SET_FIELD(res, REGDUMP_HEADER_BIN_DUMP, dbg_bin_dump);
SET_FIELD(res, REGDUMP_HEADER_OMIT_ENGINE, omit_engine);
SET_FIELD(res, REGDUMP_HEADER_ENGINE, engine);
return res;
}
int qed_dbg_all_data(struct qed_dev *cdev, void *buffer)
{
u8 cur_engine, omit_engine = 0, org_engine;
struct qed_hwfn *p_hwfn = &cdev->hwfns[cdev->engine_for_debug];
struct dbg_tools_data *dev_data = &p_hwfn->dbg_info;
int grc_params[MAX_DBG_GRC_PARAMS], rc, i;
u32 offset = 0, feature_size;
for (i = 0; i < MAX_DBG_GRC_PARAMS; i++)
grc_params[i] = dev_data->grc.param_val[i];
if (!QED_IS_CMT(cdev))
omit_engine = 1;
cdev->dbg_bin_dump = 1;
mutex_lock(&qed_dbg_lock);
org_engine = qed_get_debug_engine(cdev);
for (cur_engine = 0; cur_engine < cdev->num_hwfns; cur_engine++) {
DP_VERBOSE(cdev, QED_MSG_DEBUG,
"obtaining idle_chk and grcdump for current engine\n");
qed_set_debug_engine(cdev, cur_engine);
rc = qed_dbg_idle_chk(cdev, (u8 *)buffer + offset +
REGDUMP_HEADER_SIZE, &feature_size);
if (!rc) {
*(u32 *)((u8 *)buffer + offset) =
qed_calc_regdump_header(cdev, IDLE_CHK,
cur_engine,
feature_size,
omit_engine,
cdev->dbg_bin_dump);
offset += (feature_size + REGDUMP_HEADER_SIZE);
} else {
DP_ERR(cdev, "qed_dbg_idle_chk failed. rc = %d\n", rc);
}
rc = qed_dbg_idle_chk(cdev, (u8 *)buffer + offset +
REGDUMP_HEADER_SIZE, &feature_size);
if (!rc) {
*(u32 *)((u8 *)buffer + offset) =
qed_calc_regdump_header(cdev, IDLE_CHK,
cur_engine,
feature_size,
omit_engine,
cdev->dbg_bin_dump);
offset += (feature_size + REGDUMP_HEADER_SIZE);
} else {
DP_ERR(cdev, "qed_dbg_idle_chk failed. rc = %d\n", rc);
}
rc = qed_dbg_reg_fifo(cdev, (u8 *)buffer + offset +
REGDUMP_HEADER_SIZE, &feature_size);
if (!rc) {
*(u32 *)((u8 *)buffer + offset) =
qed_calc_regdump_header(cdev, REG_FIFO,
cur_engine,
feature_size,
omit_engine,
cdev->dbg_bin_dump);
offset += (feature_size + REGDUMP_HEADER_SIZE);
} else {
DP_ERR(cdev, "qed_dbg_reg_fifo failed. rc = %d\n", rc);
}
rc = qed_dbg_igu_fifo(cdev, (u8 *)buffer + offset +
REGDUMP_HEADER_SIZE, &feature_size);
if (!rc) {
*(u32 *)((u8 *)buffer + offset) =
qed_calc_regdump_header(cdev, IGU_FIFO,
cur_engine,
feature_size,
omit_engine,
cdev->dbg_bin_dump);
offset += (feature_size + REGDUMP_HEADER_SIZE);
} else {
DP_ERR(cdev, "qed_dbg_igu_fifo failed. rc = %d", rc);
}
rc = qed_dbg_protection_override(cdev, (u8 *)buffer + offset +
REGDUMP_HEADER_SIZE,
&feature_size);
if (!rc) {
*(u32 *)((u8 *)buffer + offset) =
qed_calc_regdump_header(cdev,
PROTECTION_OVERRIDE,
cur_engine,
feature_size,
omit_engine,
cdev->dbg_bin_dump);
offset += (feature_size + REGDUMP_HEADER_SIZE);
} else {
DP_ERR(cdev,
"qed_dbg_protection_override failed. rc = %d\n",
rc);
}
rc = qed_dbg_fw_asserts(cdev, (u8 *)buffer + offset +
REGDUMP_HEADER_SIZE, &feature_size);
if (!rc) {
*(u32 *)((u8 *)buffer + offset) =
qed_calc_regdump_header(cdev, FW_ASSERTS,
cur_engine,
feature_size,
omit_engine,
cdev->dbg_bin_dump);
offset += (feature_size + REGDUMP_HEADER_SIZE);
} else {
DP_ERR(cdev, "qed_dbg_fw_asserts failed. rc = %d\n",
rc);
}
feature_size = qed_dbg_ilt_size(cdev);
if (!cdev->disable_ilt_dump && feature_size <
ILT_DUMP_MAX_SIZE) {
rc = qed_dbg_ilt(cdev, (u8 *)buffer + offset +
REGDUMP_HEADER_SIZE, &feature_size);
if (!rc) {
*(u32 *)((u8 *)buffer + offset) =
qed_calc_regdump_header(cdev, ILT_DUMP,
cur_engine,
feature_size,
omit_engine,
cdev->dbg_bin_dump);
offset += (feature_size + REGDUMP_HEADER_SIZE);
} else {
DP_ERR(cdev, "qed_dbg_ilt failed. rc = %d\n",
rc);
}
}
for (i = 0; i < MAX_DBG_GRC_PARAMS; i++)
dev_data->grc.param_val[i] = grc_params[i];
rc = qed_dbg_grc(cdev, (u8 *)buffer + offset +
REGDUMP_HEADER_SIZE, &feature_size);
if (!rc) {
*(u32 *)((u8 *)buffer + offset) =
qed_calc_regdump_header(cdev, GRC_DUMP,
cur_engine,
feature_size,
omit_engine,
cdev->dbg_bin_dump);
offset += (feature_size + REGDUMP_HEADER_SIZE);
} else {
DP_ERR(cdev, "qed_dbg_grc failed. rc = %d", rc);
}
}
qed_set_debug_engine(cdev, org_engine);
rc = qed_dbg_mcp_trace(cdev, (u8 *)buffer + offset +
REGDUMP_HEADER_SIZE, &feature_size);
if (!rc) {
*(u32 *)((u8 *)buffer + offset) =
qed_calc_regdump_header(cdev, MCP_TRACE, cur_engine,
feature_size, omit_engine,
cdev->dbg_bin_dump);
offset += (feature_size + REGDUMP_HEADER_SIZE);
} else {
DP_ERR(cdev, "qed_dbg_mcp_trace failed. rc = %d\n", rc);
}
rc = qed_dbg_nvm_image(cdev,
(u8 *)buffer + offset +
REGDUMP_HEADER_SIZE, &feature_size,
QED_NVM_IMAGE_NVM_CFG1);
if (!rc) {
*(u32 *)((u8 *)buffer + offset) =
qed_calc_regdump_header(cdev, NVM_CFG1, cur_engine,
feature_size, omit_engine,
cdev->dbg_bin_dump);
offset += (feature_size + REGDUMP_HEADER_SIZE);
} else if (rc != -ENOENT) {
DP_ERR(cdev,
"qed_dbg_nvm_image failed for image %d (%s), rc = %d\n",
QED_NVM_IMAGE_NVM_CFG1, "QED_NVM_IMAGE_NVM_CFG1",
rc);
}
rc = qed_dbg_nvm_image(cdev,
(u8 *)buffer + offset +
REGDUMP_HEADER_SIZE, &feature_size,
QED_NVM_IMAGE_DEFAULT_CFG);
if (!rc) {
*(u32 *)((u8 *)buffer + offset) =
qed_calc_regdump_header(cdev, DEFAULT_CFG,
cur_engine, feature_size,
omit_engine,
cdev->dbg_bin_dump);
offset += (feature_size + REGDUMP_HEADER_SIZE);
} else if (rc != -ENOENT) {
DP_ERR(cdev,
"qed_dbg_nvm_image failed for image %d (%s), rc = %d\n",
QED_NVM_IMAGE_DEFAULT_CFG,
"QED_NVM_IMAGE_DEFAULT_CFG", rc);
}
rc = qed_dbg_nvm_image(cdev,
(u8 *)buffer + offset +
REGDUMP_HEADER_SIZE, &feature_size,
QED_NVM_IMAGE_NVM_META);
if (!rc) {
*(u32 *)((u8 *)buffer + offset) =
qed_calc_regdump_header(cdev, NVM_META, cur_engine,
feature_size, omit_engine,
cdev->dbg_bin_dump);
offset += (feature_size + REGDUMP_HEADER_SIZE);
} else if (rc != -ENOENT) {
DP_ERR(cdev,
"qed_dbg_nvm_image failed for image %d (%s), rc = %d\n",
QED_NVM_IMAGE_NVM_META, "QED_NVM_IMAGE_NVM_META",
rc);
}
rc = qed_dbg_nvm_image(cdev, (u8 *)buffer + offset +
REGDUMP_HEADER_SIZE, &feature_size,
QED_NVM_IMAGE_MDUMP);
if (!rc) {
*(u32 *)((u8 *)buffer + offset) =
qed_calc_regdump_header(cdev, MDUMP, cur_engine,
feature_size, omit_engine,
cdev->dbg_bin_dump);
offset += (feature_size + REGDUMP_HEADER_SIZE);
} else if (rc != -ENOENT) {
DP_ERR(cdev,
"qed_dbg_nvm_image failed for image %d (%s), rc = %d\n",
QED_NVM_IMAGE_MDUMP, "QED_NVM_IMAGE_MDUMP", rc);
}
mutex_unlock(&qed_dbg_lock);
cdev->dbg_bin_dump = 0;
return 0;
}
int qed_dbg_all_data_size(struct qed_dev *cdev)
{
u32 regs_len = 0, image_len = 0, ilt_len = 0, total_ilt_len = 0;
struct qed_hwfn *p_hwfn = &cdev->hwfns[cdev->engine_for_debug];
u8 cur_engine, org_engine;
cdev->disable_ilt_dump = false;
org_engine = qed_get_debug_engine(cdev);
for (cur_engine = 0; cur_engine < cdev->num_hwfns; cur_engine++) {
DP_VERBOSE(cdev, QED_MSG_DEBUG,
"calculating idle_chk and grcdump register length for current engine\n");
qed_set_debug_engine(cdev, cur_engine);
regs_len += REGDUMP_HEADER_SIZE + qed_dbg_idle_chk_size(cdev) +
REGDUMP_HEADER_SIZE + qed_dbg_idle_chk_size(cdev) +
REGDUMP_HEADER_SIZE + qed_dbg_grc_size(cdev) +
REGDUMP_HEADER_SIZE + qed_dbg_reg_fifo_size(cdev) +
REGDUMP_HEADER_SIZE + qed_dbg_igu_fifo_size(cdev) +
REGDUMP_HEADER_SIZE +
qed_dbg_protection_override_size(cdev) +
REGDUMP_HEADER_SIZE + qed_dbg_fw_asserts_size(cdev);
ilt_len = REGDUMP_HEADER_SIZE + qed_dbg_ilt_size(cdev);
if (ilt_len < ILT_DUMP_MAX_SIZE) {
total_ilt_len += ilt_len;
regs_len += ilt_len;
}
}
qed_set_debug_engine(cdev, org_engine);
regs_len += REGDUMP_HEADER_SIZE + qed_dbg_mcp_trace_size(cdev) +
REGDUMP_HEADER_SIZE + qed_dbg_phy_size(cdev);
qed_dbg_nvm_image_length(p_hwfn, QED_NVM_IMAGE_NVM_CFG1, &image_len);
if (image_len)
regs_len += REGDUMP_HEADER_SIZE + image_len;
qed_dbg_nvm_image_length(p_hwfn, QED_NVM_IMAGE_DEFAULT_CFG, &image_len);
if (image_len)
regs_len += REGDUMP_HEADER_SIZE + image_len;
qed_dbg_nvm_image_length(p_hwfn, QED_NVM_IMAGE_NVM_META, &image_len);
if (image_len)
regs_len += REGDUMP_HEADER_SIZE + image_len;
qed_dbg_nvm_image_length(p_hwfn, QED_NVM_IMAGE_MDUMP, &image_len);
if (image_len)
regs_len += REGDUMP_HEADER_SIZE + image_len;
if (regs_len > REGDUMP_MAX_SIZE) {
DP_VERBOSE(cdev, QED_MSG_DEBUG,
"Dump exceeds max size 0x%x, disable ILT dump\n",
REGDUMP_MAX_SIZE);
cdev->disable_ilt_dump = true;
regs_len -= total_ilt_len;
}
return regs_len;
}
int qed_dbg_feature(struct qed_dev *cdev, void *buffer,
enum qed_dbg_features feature, u32 *num_dumped_bytes)
{
struct qed_dbg_feature *qed_feature = &cdev->dbg_features[feature];
struct qed_hwfn *p_hwfn = &cdev->hwfns[cdev->engine_for_debug];
enum dbg_status dbg_rc;
struct qed_ptt *p_ptt;
int rc = 0;
p_ptt = qed_ptt_acquire(p_hwfn);
if (!p_ptt)
return -EINVAL;
dbg_rc = qed_dbg_dump(p_hwfn, p_ptt, feature);
if (dbg_rc != DBG_STATUS_OK) {
DP_VERBOSE(cdev, QED_MSG_DEBUG, "%s\n",
qed_dbg_get_status_str(dbg_rc));
*num_dumped_bytes = 0;
rc = -EINVAL;
goto out;
}
DP_VERBOSE(cdev, QED_MSG_DEBUG,
"copying debugfs feature to external buffer\n");
memcpy(buffer, qed_feature->dump_buf, qed_feature->buf_size);
*num_dumped_bytes = cdev->dbg_features[feature].dumped_dwords *
4;
out:
qed_ptt_release(p_hwfn, p_ptt);
return rc;
}
int qed_dbg_feature_size(struct qed_dev *cdev, enum qed_dbg_features feature)
{
struct qed_dbg_feature *qed_feature = &cdev->dbg_features[feature];
struct qed_hwfn *p_hwfn = &cdev->hwfns[cdev->engine_for_debug];
struct qed_ptt *p_ptt = qed_ptt_acquire(p_hwfn);
u32 buf_size_dwords;
enum dbg_status rc;
if (!p_ptt)
return -EINVAL;
rc = qed_features_lookup[feature].get_size(p_hwfn, p_ptt,
&buf_size_dwords);
if (rc != DBG_STATUS_OK)
buf_size_dwords = 0;
if (buf_size_dwords > MAX_DBG_FEATURE_SIZE_DWORDS)
buf_size_dwords = 0;
qed_ptt_release(p_hwfn, p_ptt);
qed_feature->buf_size = buf_size_dwords * sizeof(u32);
return qed_feature->buf_size;
}
int qed_dbg_phy_size(struct qed_dev *cdev)
{
return MAX_PHY_RESULT_BUFFER * (1 + qed_device_num_ports(cdev));
}
u8 qed_get_debug_engine(struct qed_dev *cdev)
{
return cdev->engine_for_debug;
}
void qed_set_debug_engine(struct qed_dev *cdev, int engine_number)
{
DP_VERBOSE(cdev, QED_MSG_DEBUG, "set debug engine to %d\n",
engine_number);
cdev->engine_for_debug = engine_number;
}
void qed_dbg_pf_init(struct qed_dev *cdev)
{
const u8 *dbg_values = NULL;
int i;
qed_dbg_set_app_ver(TOOLS_VERSION);
dbg_values = cdev->firmware->data + *(u32 *)cdev->firmware->data;
for_each_hwfn(cdev, i) {
qed_dbg_set_bin_ptr(&cdev->hwfns[i], dbg_values);
qed_dbg_user_set_bin_ptr(&cdev->hwfns[i], dbg_values);
}
cdev->engine_for_debug = 0;
}
void qed_dbg_pf_exit(struct qed_dev *cdev)
{
struct qed_dbg_feature *feature = NULL;
enum qed_dbg_features feature_idx;
for (feature_idx = 0; feature_idx < DBG_FEATURE_NUM; feature_idx++) {
feature = &cdev->dbg_features[feature_idx];
if (feature->dump_buf) {
vfree(feature->dump_buf);
feature->dump_buf = NULL;
}
}
}