/* QLogic (R)NIC Driver/Library * Copyright (c) 2015-2016 QLogic Corporation * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU * General Public License (GPL) Version 2, available from the file * COPYING in the main directory of this source tree, or the * OpenIB.org BSD license below: * * Redistribution and use in source and binary forms, with or * without modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above * copyright notice, this list of conditions and the following * disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include #include #include #include #include #include #define __PREVENT_DUMP_MEM_ARR__ #define __PREVENT_PXP_GLOBAL_WIN__ #include "qed.h" #include "qed_hsi.h" #include "qed_user_dbg_fw_funcs.h" /******************************* Data Types **********************************/ struct block_info { const char *name; enum block_id id; }; struct mcp_trace_format { u32 data; #define MCP_TRACE_FORMAT_MODULE_MASK 0x0000ffff #define MCP_TRACE_FORMAT_MODULE_SHIFT 0 #define MCP_TRACE_FORMAT_LEVEL_MASK 0x00030000 #define MCP_TRACE_FORMAT_LEVEL_SHIFT 16 #define MCP_TRACE_FORMAT_P1_SIZE_MASK 0x000c0000 #define MCP_TRACE_FORMAT_P1_SIZE_SHIFT 18 #define MCP_TRACE_FORMAT_P2_SIZE_MASK 0x00300000 #define MCP_TRACE_FORMAT_P2_SIZE_SHIFT 20 #define MCP_TRACE_FORMAT_P3_SIZE_MASK 0x00c00000 #define MCP_TRACE_FORMAT_P3_SIZE_SHIFT 22 #define MCP_TRACE_FORMAT_LEN_MASK 0xff000000 #define MCP_TRACE_FORMAT_LEN_SHIFT 24 char *format_str; }; /* Meta data structure, generated by a perl script during MFW build. therefore, * the structs mcp_trace_meta and mcp_trace_format are duplicated in the perl * script. */ struct mcp_trace_meta { u32 modules_num; char **modules; u32 formats_num; struct mcp_trace_format *formats; }; /* REG fifo element */ 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 }; /* IGU fifo element */ 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 }; /* Protection override element */ 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; }; /******************************** Constants **********************************/ #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_SHIFT - MCP_TRACE_FORMAT_P1_SIZE_SHIFT) #ifndef REG_FIFO_ELEMENT_DWORDS #define REG_FIFO_ELEMENT_DWORDS 2 #endif #define REG_FIFO_ELEMENT_ADDR_FACTOR 4 #define REG_FIFO_ELEMENT_IS_PF_VF_VAL 127 #ifndef IGU_FIFO_ELEMENT_DWORDS #define IGU_FIFO_ELEMENT_DWORDS 4 #endif #ifndef PROTECTION_OVERRIDE_ELEMENT_DWORDS #define PROTECTION_OVERRIDE_ELEMENT_DWORDS 2 #endif #define PROTECTION_OVERRIDE_ELEMENT_ADDR_FACTOR 4 #define DBG_BUS_SIGNATURE_LINE_NAME "signature" #define DBG_BUS_SIGNATURE_LINE_NUM 0 #define DBG_BUS_LATENCY_LINE_NAME "latency" #define DBG_BUS_LATENCY_LINE_NUM 1 /* Extra lines include a signature line + optional latency events line */ #ifndef NUM_DBG_LINES #define NUM_EXTRA_DBG_LINES(block_desc) (1 + \ (block_desc-> \ has_latency_events ? \ 1 : 0)) #define NUM_DBG_LINES(block_desc) (block_desc-> \ num_of_lines + \ NUM_EXTRA_DBG_LINES( \ block_desc)) #endif #define BYTES_IN_DWORD 4 /********************************* Macros ************************************/ #ifndef BYTES_TO_DWORDS #define BYTES_TO_DWORDS(bytes) ((bytes) / sizeof(u32)) #endif /***************************** Constant Arrays *******************************/ struct user_dbg_array { const u32 *ptr; u32 size_in_dwords; }; /* Debug arrays */ static struct user_dbg_array s_user_dbg_arrays[MAX_BIN_DBG_BUFFER_TYPE] = { {NULL} }; /* Storm names array */ static const char *s_storm_str[] = { "t", "m", "u", "x", "y", "p" }; /* Block names array */ static struct block_info s_block_info_arr[] = { {"grc", BLOCK_GRC}, {"miscs", BLOCK_MISCS}, {"misc", BLOCK_MISC}, {"dbu", BLOCK_DBU}, {"pglue_b", BLOCK_PGLUE_B}, {"cnig", BLOCK_CNIG}, {"cpmu", BLOCK_CPMU}, {"ncsi", BLOCK_NCSI}, {"opte", BLOCK_OPTE}, {"bmb", BLOCK_BMB}, {"pcie", BLOCK_PCIE}, {"mcp", BLOCK_MCP}, {"mcp2", BLOCK_MCP2}, {"pswhst", BLOCK_PSWHST}, {"pswhst2", BLOCK_PSWHST2}, {"pswrd", BLOCK_PSWRD}, {"pswrd2", BLOCK_PSWRD2}, {"pswwr", BLOCK_PSWWR}, {"pswwr2", BLOCK_PSWWR2}, {"pswrq", BLOCK_PSWRQ}, {"pswrq2", BLOCK_PSWRQ2}, {"pglcs", BLOCK_PGLCS}, {"ptu", BLOCK_PTU}, {"dmae", BLOCK_DMAE}, {"tcm", BLOCK_TCM}, {"mcm", BLOCK_MCM}, {"ucm", BLOCK_UCM}, {"xcm", BLOCK_XCM}, {"ycm", BLOCK_YCM}, {"pcm", BLOCK_PCM}, {"qm", BLOCK_QM}, {"tm", BLOCK_TM}, {"dorq", BLOCK_DORQ}, {"brb", BLOCK_BRB}, {"src", BLOCK_SRC}, {"prs", BLOCK_PRS}, {"tsdm", BLOCK_TSDM}, {"msdm", BLOCK_MSDM}, {"usdm", BLOCK_USDM}, {"xsdm", BLOCK_XSDM}, {"ysdm", BLOCK_YSDM}, {"psdm", BLOCK_PSDM}, {"tsem", BLOCK_TSEM}, {"msem", BLOCK_MSEM}, {"usem", BLOCK_USEM}, {"xsem", BLOCK_XSEM}, {"ysem", BLOCK_YSEM}, {"psem", BLOCK_PSEM}, {"rss", BLOCK_RSS}, {"tmld", BLOCK_TMLD}, {"muld", BLOCK_MULD}, {"yuld", BLOCK_YULD}, {"xyld", BLOCK_XYLD}, {"ptld", BLOCK_PTLD}, {"ypld", BLOCK_YPLD}, {"prm", BLOCK_PRM}, {"pbf_pb1", BLOCK_PBF_PB1}, {"pbf_pb2", BLOCK_PBF_PB2}, {"rpb", BLOCK_RPB}, {"btb", BLOCK_BTB}, {"pbf", BLOCK_PBF}, {"rdif", BLOCK_RDIF}, {"tdif", BLOCK_TDIF}, {"cdu", BLOCK_CDU}, {"ccfc", BLOCK_CCFC}, {"tcfc", BLOCK_TCFC}, {"igu", BLOCK_IGU}, {"cau", BLOCK_CAU}, {"rgfs", BLOCK_RGFS}, {"rgsrc", BLOCK_RGSRC}, {"tgfs", BLOCK_TGFS}, {"tgsrc", BLOCK_TGSRC}, {"umac", BLOCK_UMAC}, {"xmac", BLOCK_XMAC}, {"dbg", BLOCK_DBG}, {"nig", BLOCK_NIG}, {"wol", BLOCK_WOL}, {"bmbn", BLOCK_BMBN}, {"ipc", BLOCK_IPC}, {"nwm", BLOCK_NWM}, {"nws", BLOCK_NWS}, {"ms", BLOCK_MS}, {"phy_pcie", BLOCK_PHY_PCIE}, {"led", BLOCK_LED}, {"avs_wrap", BLOCK_AVS_WRAP}, {"pxpreqbus", BLOCK_PXPREQBUS}, {"misc_aeu", BLOCK_MISC_AEU}, {"bar0_map", BLOCK_BAR0_MAP} }; /* Storm debug mode names array */ static const char *s_storm_mode_str[] = { /* DBG_BUS_STORM_MODE_PRINTF */ "printf", /* DBG_BUS_STORM_MODE_PRAM_ADDR */ "pram_addr", /* DBG_BUS_STORM_MODE_DRA_RW */ "dra_rw", /* DBG_BUS_STORM_MODE_DRA_W */ "dra_w", /* DBG_BUS_STORM_MODE_LD_ST_ADDR */ "ld_st_addr", /* DBG_BUS_STORM_MODE_DRA_FSM */ "dra_fsm", /* DBG_BUS_STORM_MODE_RH */ "rh", /* DBG_BUS_STORM_MODE_FOC */ "foc", /* DBG_BUS_STORM_MODE_EXT_STORE */ "ext_store" }; /* Constraint operation names array */ static const char *s_constraint_op_str[MAX_DBG_BUS_CONSTRAINT_OPS] = { /* DBG_BUS_CONSTRAINT_OP_EQ */ "eq", /* DBG_BUS_CONSTRAINT_OP_NE */ "ne", /* DBG_BUS_CONSTRAINT_OP_LT */ "lt", /* DBG_BUS_CONSTRAINT_OP_LTC */ "ltc", /* DBG_BUS_CONSTRAINT_OP_LE */ "le", /* DBG_BUS_CONSTRAINT_OP_LEC */ "lec", /* DBG_BUS_CONSTRAINT_OP_GT */ "gt", /* DBG_BUS_CONSTRAINT_OP_GTC */ "gtc", /* DBG_BUS_CONSTRAINT_OP_GE */ "ge", /* DBG_BUS_CONSTRAINT_OP_GEC */ "gec" }; /* Status string array */ static const char *s_status_str[] = { /* DBG_STATUS_OK */ "Operation completed successfully", /* DBG_STATUS_APP_VERSION_NOT_SET */ "Debug application version wasn't set", /* DBG_STATUS_UNSUPPORTED_APP_VERSION */ "Unsupported debug application version", /* DBG_STATUS_DBG_BLOCK_NOT_RESET */ "The debug block wasn't reset since the last recording", /* DBG_STATUS_INVALID_ARGS */ "Invalid arguments", /* DBG_STATUS_OUTPUT_ALREADY_SET */ "The debug output was already set", /* DBG_STATUS_INVALID_PCI_BUF_SIZE */ "Invalid PCI buffer size", /* DBG_STATUS_PCI_BUF_ALLOC_FAILED */ "PCI buffer allocation failed", /* DBG_STATUS_PCI_BUF_NOT_ALLOCATED */ "A PCI buffer wasn't allocated", /* DBG_STATUS_TOO_MANY_INPUTS */ "Too many inputs were enabled. Enabled less inputs, or set 'unifyInputs' to true", /* DBG_STATUS_INPUT_OVERLAP */ "Overlapping debug bus inputs", /* DBG_STATUS_HW_ONLY_RECORDING */ "Cannot record Storm data since the entire recording cycle is used by HW", /* DBG_STATUS_STORM_ALREADY_ENABLED */ "The Storm was already enabled", /* DBG_STATUS_STORM_NOT_ENABLED */ "The specified Storm wasn't enabled", /* DBG_STATUS_BLOCK_ALREADY_ENABLED */ "The block was already enabled", /* DBG_STATUS_BLOCK_NOT_ENABLED */ "The specified block wasn't enabled", /* DBG_STATUS_NO_INPUT_ENABLED */ "No input was enabled for recording", /* DBG_STATUS_NO_FILTER_TRIGGER_64B */ "Filters and triggers are not allowed when recording in 64b units", /* DBG_STATUS_FILTER_ALREADY_ENABLED */ "The filter was already enabled", /* DBG_STATUS_TRIGGER_ALREADY_ENABLED */ "The trigger was already enabled", /* DBG_STATUS_TRIGGER_NOT_ENABLED */ "The trigger wasn't enabled", /* DBG_STATUS_CANT_ADD_CONSTRAINT */ "A constraint can be added only after a filter was enabled or a trigger state was added", /* DBG_STATUS_TOO_MANY_TRIGGER_STATES */ "Cannot add more than 3 trigger states", /* DBG_STATUS_TOO_MANY_CONSTRAINTS */ "Cannot add more than 4 constraints per filter or trigger state", /* DBG_STATUS_RECORDING_NOT_STARTED */ "The recording wasn't started", /* DBG_STATUS_DATA_DIDNT_TRIGGER */ "A trigger was configured, but it didn't trigger", /* DBG_STATUS_NO_DATA_RECORDED */ "No data was recorded", /* DBG_STATUS_DUMP_BUF_TOO_SMALL */ "Dump buffer is too small", /* DBG_STATUS_DUMP_NOT_CHUNK_ALIGNED */ "Dumped data is not aligned to chunks", /* DBG_STATUS_UNKNOWN_CHIP */ "Unknown chip", /* DBG_STATUS_VIRT_MEM_ALLOC_FAILED */ "Failed allocating virtual memory", /* DBG_STATUS_BLOCK_IN_RESET */ "The input block is in reset", /* DBG_STATUS_INVALID_TRACE_SIGNATURE */ "Invalid MCP trace signature found in NVRAM", /* DBG_STATUS_INVALID_NVRAM_BUNDLE */ "Invalid bundle ID found in NVRAM", /* DBG_STATUS_NVRAM_GET_IMAGE_FAILED */ "Failed getting NVRAM image", /* DBG_STATUS_NON_ALIGNED_NVRAM_IMAGE */ "NVRAM image is not dword-aligned", /* DBG_STATUS_NVRAM_READ_FAILED */ "Failed reading from NVRAM", /* DBG_STATUS_IDLE_CHK_PARSE_FAILED */ "Idle check parsing failed", /* DBG_STATUS_MCP_TRACE_BAD_DATA */ "MCP Trace data is corrupt", /* DBG_STATUS_MCP_TRACE_NO_META */ "Dump doesn't contain meta data - it must be provided in image file", /* DBG_STATUS_MCP_COULD_NOT_HALT */ "Failed to halt MCP", /* DBG_STATUS_MCP_COULD_NOT_RESUME */ "Failed to resume MCP after halt", /* DBG_STATUS_RESERVED2 */ "Reserved debug status - shouldn't be returned", /* DBG_STATUS_SEMI_FIFO_NOT_EMPTY */ "Failed to empty SEMI sync FIFO", /* DBG_STATUS_IGU_FIFO_BAD_DATA */ "IGU FIFO data is corrupt", /* DBG_STATUS_MCP_COULD_NOT_MASK_PRTY */ "MCP failed to mask parities", /* DBG_STATUS_FW_ASSERTS_PARSE_FAILED */ "FW Asserts parsing failed", /* DBG_STATUS_REG_FIFO_BAD_DATA */ "GRC FIFO data is corrupt", /* DBG_STATUS_PROTECTION_OVERRIDE_BAD_DATA */ "Protection Override data is corrupt", /* DBG_STATUS_DBG_ARRAY_NOT_SET */ "Debug arrays were not set (when using binary files, dbg_set_bin_ptr must be called)", /* DBG_STATUS_FILTER_BUG */ "Debug Bus filtering requires the -unifyInputs option (due to a HW bug)", /* DBG_STATUS_NON_MATCHING_LINES */ "Non-matching debug lines - all lines must be of the same type (either 128b or 256b)", /* DBG_STATUS_INVALID_TRIGGER_DWORD_OFFSET */ "The selected trigger dword offset wasn't enabled in the recorded HW block", /* DBG_STATUS_DBG_BUS_IN_USE */ "The debug bus is in use" }; /* GRC Dump flag names array */ static const char *s_grc_param_str[] = { /* DBG_GRC_PARAM_DUMP_TSTORM */ "tstorm", /* DBG_GRC_PARAM_DUMP_MSTORM */ "mstorm", /* DBG_GRC_PARAM_DUMP_USTORM */ "ustorm", /* DBG_GRC_PARAM_DUMP_XSTORM */ "xstorm", /* DBG_GRC_PARAM_DUMP_YSTORM */ "ystorm", /* DBG_GRC_PARAM_DUMP_PSTORM */ "pstorm", /* DBG_GRC_PARAM_DUMP_REGS */ "regs", /* DBG_GRC_PARAM_DUMP_RAM */ "ram", /* DBG_GRC_PARAM_DUMP_PBUF */ "pbuf", /* DBG_GRC_PARAM_DUMP_IOR */ "ior", /* DBG_GRC_PARAM_DUMP_VFC */ "vfc", /* DBG_GRC_PARAM_DUMP_CM_CTX */ "ctx", /* DBG_GRC_PARAM_DUMP_PXP */ "pxp", /* DBG_GRC_PARAM_DUMP_RSS */ "rss", /* DBG_GRC_PARAM_DUMP_CAU */ "cau", /* DBG_GRC_PARAM_DUMP_QM */ "qm", /* DBG_GRC_PARAM_DUMP_MCP */ "mcp", /* DBG_GRC_PARAM_RESERVED */ "reserved", /* DBG_GRC_PARAM_DUMP_CFC */ "cfc", /* DBG_GRC_PARAM_DUMP_IGU */ "igu", /* DBG_GRC_PARAM_DUMP_BRB */ "brb", /* DBG_GRC_PARAM_DUMP_BTB */ "btb", /* DBG_GRC_PARAM_DUMP_BMB */ "bmb", /* DBG_GRC_PARAM_DUMP_NIG */ "nig", /* DBG_GRC_PARAM_DUMP_MULD */ "muld", /* DBG_GRC_PARAM_DUMP_PRS */ "prs", /* DBG_GRC_PARAM_DUMP_DMAE */ "dmae", /* DBG_GRC_PARAM_DUMP_TM */ "tm", /* DBG_GRC_PARAM_DUMP_SDM */ "sdm", /* DBG_GRC_PARAM_DUMP_DIF */ "dif", /* DBG_GRC_PARAM_DUMP_STATIC */ "static", /* DBG_GRC_PARAM_UNSTALL */ "unstall", /* DBG_GRC_PARAM_NUM_LCIDS */ "lcids", /* DBG_GRC_PARAM_NUM_LTIDS */ "ltids", /* DBG_GRC_PARAM_EXCLUDE_ALL */ "exclude_all", /* DBG_GRC_PARAM_CRASH */ "crash", /* DBG_GRC_PARAM_PARITY_SAFE */ "parity_safe", /* DBG_GRC_PARAM_DUMP_CM */ "cm", /* DBG_GRC_PARAM_DUMP_PHY */ "phy", /* DBG_GRC_PARAM_NO_MCP */ "nomcp", /* DBG_GRC_PARAM_NO_FW_VER */ "nofwver" }; /* Idle check severity names array */ static const char *s_idle_chk_severity_str[] = { "Error", "Error if no traffic", "Warning" }; /* MCP Trace level names array */ static const char *s_mcp_trace_level_str[] = { "ERROR", "TRACE", "DEBUG" }; /* Access type names array */ static const char *s_access_strs[] = { "read", "write" }; /* Privilege type names array */ static const char *s_privilege_strs[] = { "VF", "PDA", "HV", "UA" }; /* Protection type names array */ static const char *s_protection_strs[] = { "(default)", "(default)", "(default)", "(default)", "override VF", "override PDA", "override HV", "override UA" }; /* Master type names array */ static const char *s_master_strs[] = { "???", "pxp", "mcp", "msdm", "psdm", "ysdm", "usdm", "tsdm", "xsdm", "dbu", "dmae", "???", "???", "???", "???", "???" }; /* REG FIFO error messages array */ static const char *s_reg_fifo_error_strs[] = { "grc timeout", "address doesn't belong to any block", "reserved address in block or write to read-only address", "privilege/protection mismatch", "path isolation error" }; /* IGU FIFO sources array */ static const char *s_igu_fifo_source_strs[] = { "TSTORM", "MSTORM", "USTORM", "XSTORM", "YSTORM", "PSTORM", "PCIE", "NIG_QM_PBF", "CAU", "ATTN", "GRC", }; /* IGU FIFO error messages */ static const char *s_igu_fifo_error_strs[] = { "no error", "length error", "function disabled", "VF sent command to attnetion 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" }; /* IGU FIFO address data */ 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} }; /******************************** Variables **********************************/ /* MCP Trace meta data array - used in case the dump doesn't contain the * meta data (e.g. due to no NVRAM access). */ static struct user_dbg_array s_mcp_trace_meta_arr = { NULL, 0 }; /* Parsed MCP Trace meta data info, based on MCP trace meta array */ static struct mcp_trace_meta s_mcp_trace_meta; static bool s_mcp_trace_meta_valid = false; /* Temporary buffer, used for print size calculations */ static char s_temp_buf[MAX_MSG_LEN]; /**************************** Private Functions ******************************/ static void qed_user_static_asserts(void) { } /* Returns true if the specified string is a number, false otherwise. */ static bool qed_is_number(const char *str) { size_t i = 0, len = strlen(str); for (i = 0; i < len; i++) if (str[i] < '0' || str[i] > '9') return false; return true; } 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; } /* Reads the specified number of bytes from the specified cyclic buffer (up to * 4 bytes) and returns them as a dword value. the specified buffer offset is * updated. */ 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; /* Assume running on a LITTLE ENDIAN and the buffer is network order * (BIG ENDIAN), as high order bytes are placed in lower memory address. */ 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; } /* Reads and returns the next byte from the specified buffer. the specified * buffer offset is updated. */ static u8 qed_read_byte_from_buf(void *buf, u32 * offset) { return ((u8 *) buf)[(*offset)++]; } /* Reads and returns the next dword from the specified buffer. the specified * buffer offset is updated. */ static u32 qed_read_dword_from_buf(void *buf, u32 * offset) { u32 dword_val = *(u32 *) & ((u8 *) buf)[*offset]; *offset += 4; return dword_val; } /* Reads the next string from the specified buffer, and copies it to the * specified pointer the specified buffer offset is updated. */ 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; } /* Returns a pointer to the specified offset (in bytes) of the specified * buffer. if the specified buffer in NULL, a temporary buffer pointer is * returned. */ static char *qed_get_buf_ptr(void *buf, u32 offset) { return buf ? (char *)buf + offset : s_temp_buf; } /* Reads a param from the specified buffer. returns the number of dwords read. * if the returned str_param is NULL, the param is numeric and its value is * returned in num_param. otherwise, the param is a string and its pointer is * returned in str_param. */ 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; /* Extract param name */ *param_name = char_buf; offset += strlen(*param_name) + 1; /* Check param type */ if (*(char_buf + offset++)) { /* String param */ *param_str_val = char_buf + offset; *param_num_val = 0; offset += strlen(*param_str_val) + 1; if (offset & 0x3) offset += (4 - (offset & 0x3)); } else { /* Numeric param */ *param_str_val = NULL; if (offset & 0x3) offset += (4 - (offset & 0x3)); *param_num_val = *(u32 *) (char_buf + offset); offset += 4; } return (u32) offset / 4; } /* Reads a section header from the specified buffer. Returns the number of * dwords read. */ 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); } /* Reads section params from the specified buffer and prints them to the * results buffer. Returns the number of dwords read. */ 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; } /* Parses the idle check rules and returns the number of characters printed. * in case of parsing error, returns 0. */ static u32 qed_parse_idle_chk_dump_rules(u32 * dump_buf, u32 * dump_buf_end, u32 num_rules, bool print_fw_idle_chk, char *results_buf, u32 * num_errors, u32 * num_warnings) { /* Offset in results_buf in bytes */ u32 results_offset = 0; u32 rule_idx; u16 i, j; *num_errors = 0; *num_warnings = 0; /* Go over dumped results */ 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 *) &s_user_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 *) s_user_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; /* Skip rule header */ dump_buf += BYTES_TO_DWORDS(sizeof(*hdr)); /* Update errors/warnings count */ if (hdr->severity == IDLE_CHK_SEVERITY_ERROR || hdr->severity == IDLE_CHK_SEVERITY_ERROR_NO_TRAFFIC) (*num_errors)++; else (*num_warnings)++; /* Print rule severity: */ results_offset += sprintf(qed_get_buf_ptr(results_buf, results_offset), "%s: ", s_idle_chk_severity_str[hdr->severity]); /* Print rule message */ 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; /* Print register values */ 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); /* Skip reg header */ dump_buf += BYTES_TO_DWORDS(sizeof(*reg_hdr)); /* Skip register names until the required reg_id is * reached. */ 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"); } /* Check if end of dump buffer was exceeded */ if (dump_buf > dump_buf_end) return 0; return results_offset; } /* Parses an idle check dump buffer. If result_buf is not NULL, the idle check * results are printed to it. In any case, the required results buffer size is * assigned to parsed_results_bytes. The parsing status is returned. */ static enum dbg_status qed_parse_idle_chk_dump(u32 * dump_buf, u32 num_dumped_dwords, char *results_buf, u32 * parsed_results_bytes, u32 * num_errors, u32 * num_warnings) { const char *section_name, *param_name, *param_str_val; u32 *dump_buf_end = dump_buf + num_dumped_dwords; u32 num_section_params = 0, num_rules; /* Offset in results_buf in bytes */ u32 results_offset = 0; *parsed_results_bytes = 0; *num_errors = 0; *num_warnings = 0; if (!s_user_dbg_arrays[BIN_BUF_DBG_PARSING_STRINGS].ptr || !s_user_dbg_arrays[BIN_BUF_DBG_IDLE_CHK_PARSING_DATA].ptr) return DBG_STATUS_DBG_ARRAY_NOT_SET; /* Read global_params section */ 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; /* Print global params */ dump_buf += qed_print_section_params(dump_buf, num_section_params, results_buf, &results_offset); /* Read idle_chk section */ dump_buf += qed_read_section_hdr(dump_buf, §ion_name, &num_section_params); if (strcmp(section_name, "idle_chk") || 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_rules) { u32 rules_print_size; /* Print FW output: */ results_offset += sprintf(qed_get_buf_ptr(results_buf, results_offset), "FW_IDLE_CHECK:\n"); rules_print_size = qed_parse_idle_chk_dump_rules(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; /* Print LSI output: */ results_offset += sprintf(qed_get_buf_ptr(results_buf, results_offset), "\nLSI_IDLE_CHECK:\n"); rules_print_size = qed_parse_idle_chk_dump_rules(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; } /* Print errors/warnings count */ 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"); /* Add 1 for string NULL termination */ *parsed_results_bytes = results_offset + 1; return DBG_STATUS_OK; } /* Frees the specified MCP Trace meta data */ static void qed_mcp_trace_free_meta(struct qed_hwfn *p_hwfn, struct mcp_trace_meta *meta) { u32 i; s_mcp_trace_meta_valid = false; /* Release modules */ if (meta->modules) { for (i = 0; i < meta->modules_num; i++) kfree(meta->modules[i]); kfree(meta->modules); } /* Release formats */ if (meta->formats) { for (i = 0; i < meta->formats_num; i++) kfree(meta->formats[i].format_str); kfree(meta->formats); } } /* Allocates and fills MCP Trace meta data based on the specified meta data * dump buffer. returns debug status code. */ static enum dbg_status qed_mcp_trace_alloc_meta(struct qed_hwfn *p_hwfn, const u32 * meta_buf, struct mcp_trace_meta *meta) { u8 *meta_buf_bytes = (u8 *) meta_buf; u32 offset = 0, signature, i; /* Free the previous meta before loading a new one. */ if (s_mcp_trace_meta_valid) qed_mcp_trace_free_meta(p_hwfn, meta); memset(meta, 0, sizeof(*meta)); /* Read first signature */ signature = qed_read_dword_from_buf(meta_buf_bytes, &offset); if (signature != NVM_MAGIC_VALUE) return DBG_STATUS_INVALID_TRACE_SIGNATURE; /* Read no. of modules and allocate memory for their pointers */ meta->modules_num = qed_read_byte_from_buf(meta_buf_bytes, &offset); meta->modules = (char **)kzalloc(meta->modules_num * sizeof(char *), GFP_KERNEL); if (!meta->modules) return DBG_STATUS_VIRT_MEM_ALLOC_FAILED; /* Allocate and read all module strings */ for (i = 0; i < meta->modules_num; i++) { u8 module_len = qed_read_byte_from_buf(meta_buf_bytes, &offset); *(meta->modules + i) = (char *)kzalloc(module_len, GFP_KERNEL); if (!(*(meta->modules + i))) { /* Update number of modules to be released */ 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'; } /* Read second signature */ signature = qed_read_dword_from_buf(meta_buf_bytes, &offset); if (signature != NVM_MAGIC_VALUE) return DBG_STATUS_INVALID_TRACE_SIGNATURE; /* Read number of formats and allocate memory for all formats */ meta->formats_num = qed_read_dword_from_buf(meta_buf_bytes, &offset); meta->formats = (struct mcp_trace_format *)kzalloc(meta->formats_num * sizeof(struct mcp_trace_format), GFP_KERNEL); if (!meta->formats) return DBG_STATUS_VIRT_MEM_ALLOC_FAILED; /* Allocate and read all strings */ 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 = (format_ptr->data & MCP_TRACE_FORMAT_LEN_MASK) >> MCP_TRACE_FORMAT_LEN_SHIFT; format_ptr->format_str = (char *)kzalloc(format_len, GFP_KERNEL); if (!format_ptr->format_str) { /* Update number of modules to be released */ 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); } s_mcp_trace_meta_valid = true; return DBG_STATUS_OK; } /* Parses an MCP trace buffer. If result_buf is not NULL, the MCP Trace results * are printed to it. The parsing status is returned. * Arguments: * trace_buf - MCP trace cyclic buffer * trace_buf_size - MCP trace cyclic buffer size in bytes * data_offset - offset in bytes of the data to parse in the MCP trace cyclic * buffer. * data_size - size in bytes of data to parse. * parsed_buf - destination buffer for parsed data. * parsed_bytes - size of parsed data in bytes. */ static enum dbg_status qed_parse_mcp_trace_buf(u8 * trace_buf, u32 trace_buf_size, u32 data_offset, u32 data_size, char *parsed_buf, u32 * parsed_bytes) { enum dbg_status status; u32 param_mask, param_shift; *parsed_bytes = 0; if (!s_mcp_trace_meta_valid) return DBG_STATUS_MCP_TRACE_BAD_DATA; status = DBG_STATUS_OK; while (data_size) { u32 params[3] = { 0, 0, 0 }; struct mcp_trace_format *format_ptr; u32 header, format_idx, i; u8 format_level, format_module; 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; /* Skip message if its index doesn't exist in the meta * data. */ if (format_idx > s_mcp_trace_meta.formats_num) { u8 format_size = (u8) ((header & MFW_TRACE_PRM_SIZE_MASK) >> MFW_TRACE_PRM_SIZE_SHIFT); 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 = &s_mcp_trace_meta.formats[format_idx]; for (i = 0, param_mask = MCP_TRACE_FORMAT_P1_SIZE_MASK, param_shift = MCP_TRACE_FORMAT_P1_SIZE_SHIFT; i < MCP_TRACE_FORMAT_MAX_PARAMS; i++, param_mask <<= MCP_TRACE_FORMAT_PARAM_WIDTH, param_shift += MCP_TRACE_FORMAT_PARAM_WIDTH) { /* Extract param size (0..3) */ u8 param_size = (u8) ((format_ptr->data & param_mask) >> param_shift); /* If the param size is zero, there are no other parameters. */ if (!param_size) break; /* Size is encoded using 2 bits, where 3 is used to encode 4. */ 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) ((format_ptr->data & MCP_TRACE_FORMAT_LEVEL_MASK) >> MCP_TRACE_FORMAT_LEVEL_SHIFT); format_module = (u8) ((format_ptr->data & MCP_TRACE_FORMAT_MODULE_MASK) >> MCP_TRACE_FORMAT_MODULE_SHIFT); if (format_level >= ARRAY_SIZE(s_mcp_trace_level_str)) return DBG_STATUS_MCP_TRACE_BAD_DATA; /* Print current message to results buffer */ *parsed_bytes += sprintf(qed_get_buf_ptr(parsed_buf, *parsed_bytes), "%s %-8s: ", s_mcp_trace_level_str[format_level], s_mcp_trace_meta.modules[format_module]); *parsed_bytes += sprintf(qed_get_buf_ptr(parsed_buf, *parsed_bytes), format_ptr->format_str, params[0], params[1], params[2]); } /* Add string NULL terminator */ (*parsed_bytes)++; return status; } /* Parses an MCP Trace dump buffer. If result_buf is not NULL, the MCP Trace * results are printed to it. In any case, the required results buffer size is * assigned to parsed_bytes. The parsing status is returned. */ static enum dbg_status qed_parse_mcp_trace_dump(struct qed_hwfn *p_hwfn, u32 * dump_buf, char *parsed_buf, u32 * parsed_bytes) { const char *section_name, *param_name, *param_str_val; u32 data_size, trace_data_dwords, trace_meta_dwords; u32 offset, results_offset, parsed_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_bytes = 0; /* Read global_params section */ 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; /* Print global params */ dump_buf += qed_print_section_params(dump_buf, num_section_params, parsed_buf, &results_offset); /* Read trace_data section */ 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; /* Prepare trace info */ trace = (struct mcp_trace *)dump_buf; 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; /* Read meta_data section */ 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; /* Choose meta data buffer */ if (!trace_meta_dwords) { /* Dump doesn't include meta data */ if (!s_mcp_trace_meta_arr.ptr) return DBG_STATUS_MCP_TRACE_NO_META; meta_buf = s_mcp_trace_meta_arr.ptr; } else { /* Dump includes meta data */ meta_buf = dump_buf; } /* Allocate meta data memory */ status = qed_mcp_trace_alloc_meta(p_hwfn, meta_buf, &s_mcp_trace_meta); if (status != DBG_STATUS_OK) return status; status = qed_parse_mcp_trace_buf(trace_buf, trace->size, offset, data_size, parsed_buf ? parsed_buf + results_offset : NULL, &parsed_buf_bytes); if (status != DBG_STATUS_OK) return status; *parsed_bytes = results_offset + parsed_buf_bytes; return DBG_STATUS_OK; } /* Parses a Reg FIFO dump buffer. If result_buf is not NULL, the Reg FIFO * results are printed to it. In any case, the required results buffer size is * assigned to parsed_results_bytes. The parsing status is returned. */ 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_val, vf_val; u32 results_offset = 0; char vf_str[4]; /* Read global_params section */ 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; /* Print global params */ dump_buf += qed_print_section_params(dump_buf, num_section_params, results_buf, &results_offset); /* Read reg_fifo_data section */ 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; /* Decode elements */ for (i = 0; i < num_elements; i++) { bool err_printed = false; /* Discover if element belongs to a VF or a PF */ 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); /* Add parsed element to parsed buffer */ 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, errors: ", 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) ]); /* Print errors */ for (j = 0, err_val = GET_FIELD(elements[i].data, REG_FIFO_ELEMENT_ERROR); j < ARRAY_SIZE(s_reg_fifo_error_strs); j++, err_val >>= 1) { if (err_val & 0x1) { if (err_printed) results_offset += sprintf(qed_get_buf_ptr (results_buf, results_offset), ", "); results_offset += sprintf(qed_get_buf_ptr (results_buf, results_offset), "%s", s_reg_fifo_error_strs[j]); err_printed = true; } } results_offset += sprintf(qed_get_buf_ptr(results_buf, results_offset), "\n"); } results_offset += sprintf(qed_get_buf_ptr(results_buf, results_offset), "fifo contained %d elements", num_elements); /* Add 1 for string NULL termination */ *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; char parsed_addr_data[32]; char parsed_wr_data[256]; u8 source, err_type, i; bool is_wr_cmd, is_pf; u16 cmd_addr; u64 dword12; /* Dword12 (dword index 1 and 2) contains bits 32..95 of the * FIFO element. */ 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; /* Find address 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; /* Prepare parsed address 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'; } /* Prepare parsed write data */ if (is_wr_cmd) { u32 wr_data, prod_cons; u8 is_cleanup; 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, 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); } } } else { parsed_wr_data[0] = '\0'; } /* Add parsed element to parsed buffer */ *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; } /* Parses an IGU FIFO dump buffer. If result_buf is not NULL, the IGU FIFO * results are printed to it. In any case, the required results buffer size is * assigned to parsed_results_bytes. The parsing status is returned. */ 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; /* Read global_params section */ 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; /* Print global params */ dump_buf += qed_print_section_params(dump_buf, num_section_params, results_buf, &results_offset); /* Read igu_fifo_data section */ 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; /* Decode elements */ for (i = 0; i < num_elements; i++) if ((status = qed_parse_igu_fifo_element(&elements[i], results_buf, &results_offset)) != DBG_STATUS_OK) return status; results_offset += sprintf(qed_get_buf_ptr(results_buf, results_offset), "fifo contained %d elements", num_elements); /* Add 1 for string NULL termination */ *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; /* Read global_params section */ 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; /* Print global params */ dump_buf += qed_print_section_params(dump_buf, num_section_params, results_buf, &results_offset); /* Read protection_override_data section */ 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; /* Decode elements */ 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); /* Add 1 for string NULL termination */ *parsed_results_bytes = results_offset + 1; return DBG_STATUS_OK; } /* Parses a FW Asserts dump buffer. if result_buf is not NULL, the FW Asserts * results are printed to it. in any case, the required results buffer size is * assigned to parsed_results_bytes. the parsing status is returned. */ 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; /* Read global_params section */ 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; /* Print global params */ 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")) { /* Extract params */ 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; /* Print data */ 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; } } ; /* Add 1 for string NULL termination */ *parsed_results_bytes = results_offset + 1; return DBG_STATUS_OK; } /***************************** Public Functions *******************************/ enum dbg_status qed_dbg_user_set_bin_ptr(const u8 * const bin_ptr) { struct bin_buffer_hdr *buf_array = (struct bin_buffer_hdr *)bin_ptr; u8 buf_id; /* Convert binary data to debug arrays */ for (buf_id = 0; buf_id < MAX_BIN_DBG_BUFFER_TYPE; buf_id++) { s_user_dbg_arrays[buf_id].ptr = (u32 *) (bin_ptr + buf_array[buf_id].offset); s_user_dbg_arrays[buf_id].size_in_dwords = BYTES_TO_DWORDS(buf_array[buf_id].length); } return DBG_STATUS_OK; } enum dbg_storms qed_dbg_get_storm_id(const char *storm_name) { int name_len = storm_name ? (int)strlen(storm_name) : 0; u8 i; if (name_len > 0 && name_len <= MAX_NAME_LEN) for (i = 0; i < MAX_DBG_STORMS; i++) if (!strcmp(s_storm_str[i], storm_name)) return (enum dbg_storms)i; return MAX_DBG_STORMS; } enum block_id qed_dbg_get_block_id(const char *block_name) { int name_len = block_name ? (int)strlen(block_name) : 0; u8 i; if (name_len > 0 && name_len <= MAX_NAME_LEN) for (i = 0; i < MAX_BLOCK_ID; i++) if (!strcmp(s_block_info_arr[i].name, block_name)) return s_block_info_arr[i].id; return MAX_BLOCK_ID; } enum dbg_bus_storm_modes qed_dbg_get_storm_mode_id(const char *storm_mode_name) { int name_len = storm_mode_name ? (int)strlen(storm_mode_name) : 0; u8 i; if (name_len > 0 && name_len <= MAX_NAME_LEN) for (i = 0; i < MAX_DBG_BUS_STORM_MODES; i++) if (!strcmp(s_storm_mode_str[i], storm_mode_name)) return (enum dbg_bus_storm_modes)i; return MAX_DBG_BUS_STORM_MODES; } enum dbg_bus_constraint_ops qed_dbg_get_constraint_op_id(const char *op_name) { int name_len = op_name ? (int)strlen(op_name) : 0; u8 i; if (name_len > 0 && name_len <= MAX_NAME_LEN) for (i = 0; i < MAX_DBG_BUS_CONSTRAINT_OPS; i++) if (!strcmp(s_constraint_op_str[i], op_name)) return (enum dbg_bus_constraint_ops)i; return MAX_DBG_BUS_CONSTRAINT_OPS; } 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_grc_params qed_dbg_get_grc_param_id(const char *param_name) { int name_len = param_name ? (int)strlen(param_name) : 0; u8 i; if (name_len > 0 && name_len <= MAX_NAME_LEN) for (i = 0; i < MAX_DBG_GRC_PARAMS; i++) if (!strcmp(s_grc_param_str[i], param_name)) return (enum dbg_grc_params)i; return MAX_DBG_GRC_PARAMS; } int qed_dbg_get_dbg_bus_line(enum block_id block_id, enum chip_ids chip_id, const char *line) { const struct dbg_bus_block_user_data *block = (const struct dbg_bus_block_user_data *) &s_user_dbg_arrays[BIN_BUF_DBG_BUS_BLOCKS_USER_DATA].ptr[block_id * MAX_CHIP_IDS + chip_id]; /* Check if line is a number */ if (qed_is_number(line)) { int rc; unsigned long line_num = 0; rc = kstrtoul(line, 10, &line_num); if (rc) return -1; return ((int)line_num < NUM_DBG_LINES(block)) ? (int)line_num : -1; } else if (!strcmp(line, DBG_BUS_SIGNATURE_LINE_NAME)) { return DBG_BUS_SIGNATURE_LINE_NUM; } else if (!strcmp(line, DBG_BUS_LATENCY_LINE_NAME)) { return block-> has_latency_events ? DBG_BUS_LATENCY_LINE_NUM : -1; } else { /* Block-specific debug line string */ const u32 *block_line_names_buf; const char *parsing_str_buf; u8 line_num; block_line_names_buf = &s_user_dbg_arrays[BIN_BUF_DBG_BUS_LINE_NAME_OFFSETS].ptr [block->names_offset]; parsing_str_buf = (const char *) s_user_dbg_arrays[BIN_BUF_DBG_PARSING_STRINGS].ptr; /* Search name in debug lines array */ for (line_num = 0; line_num < block->num_of_lines; line_num++) if (!strcmp(line, &parsing_str_buf[block_line_names_buf [line_num]])) return line_num + NUM_EXTRA_DBG_LINES(block); return -1; } } enum dbg_status qed_get_idle_chk_results_buf_size(struct qed_hwfn __maybe_unused * p_hwfn, u32 * dump_buf, u32 num_dumped_dwords, u32 * results_buf_size) { u32 num_errors, num_warnings; return qed_parse_idle_chk_dump(dump_buf, num_dumped_dwords, NULL, results_buf_size, &num_errors, &num_warnings); } enum dbg_status qed_print_idle_chk_results(struct qed_hwfn __maybe_unused * 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(dump_buf, num_dumped_dwords, results_buf, &parsed_buf_size, num_errors, num_warnings); } void qed_dbg_mcp_trace_set_meta_data(u32 * data, u32 size) { s_mcp_trace_meta_arr.ptr = data; s_mcp_trace_meta_arr.size_in_dwords = size; } enum dbg_status qed_get_mcp_trace_results_buf_size(struct qed_hwfn *p_hwfn, u32 * dump_buf, u32 __maybe_unused num_dumped_dwords, u32 * results_buf_size) { return qed_parse_mcp_trace_dump(p_hwfn, dump_buf, NULL, results_buf_size); } enum dbg_status qed_print_mcp_trace_results(struct qed_hwfn *p_hwfn, u32 * dump_buf, u32 __maybe_unused num_dumped_dwords, char *results_buf) { u32 parsed_buf_size; /* Doesn't do anything, needed for compile time asserts */ qed_user_static_asserts(); return qed_parse_mcp_trace_dump(p_hwfn, dump_buf, results_buf, &parsed_buf_size); } enum dbg_status qed_print_mcp_trace_line(u8 * dump_buf, u32 num_dumped_bytes, char *results_buf) { u32 parsed_bytes; return qed_parse_mcp_trace_buf(dump_buf, num_dumped_bytes, 0, num_dumped_bytes, results_buf, &parsed_bytes); } enum dbg_status qed_get_reg_fifo_results_buf_size(struct qed_hwfn __maybe_unused * p_hwfn, u32 * dump_buf, u32 __maybe_unused 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 __maybe_unused * p_hwfn, u32 * dump_buf, u32 __maybe_unused 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 __maybe_unused * p_hwfn, u32 * dump_buf, u32 __maybe_unused 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 __maybe_unused * p_hwfn, u32 * dump_buf, u32 __maybe_unused 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 __maybe_unused * p_hwfn, u32 * dump_buf, u32 __maybe_unused 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 __maybe_unused * p_hwfn, u32 * dump_buf, u32 __maybe_unused 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 __maybe_unused * p_hwfn, u32 * dump_buf, u32 __maybe_unused 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 __maybe_unused * p_hwfn, u32 * dump_buf, u32 __maybe_unused 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; enum dbg_attn_type attn_type; const char *block_name; u8 num_regs, i, j; num_regs = GET_FIELD(results->data, DBG_ATTN_BLOCK_RESULT_NUM_REGS); attn_type = (enum dbg_attn_type)GET_FIELD(results->data, DBG_ATTN_BLOCK_RESULT_ATTN_TYPE); block_name = s_block_info_arr[results->block_id].name; if (!s_user_dbg_arrays[BIN_BUF_DBG_ATTN_INDEXES].ptr || !s_user_dbg_arrays[BIN_BUF_DBG_ATTN_NAME_OFFSETS].ptr || !s_user_dbg_arrays[BIN_BUF_DBG_PARSING_STRINGS].ptr) return DBG_STATUS_DBG_ARRAY_NOT_SET; block_attn_name_offsets = &s_user_dbg_arrays[BIN_BUF_DBG_ATTN_NAME_OFFSETS]. ptr[results->names_offset]; /* Go over registers with a non-zero attention status */ 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 *) s_user_dbg_arrays[BIN_BUF_DBG_ATTN_INDEXES]. ptr)[reg_result->block_attn_offset]; /* Go over attention status bits */ for (j = 0; j < num_reg_attn; j++) { u16 attn_idx_val = GET_FIELD(bit_mapping[j].data, DBG_ATTN_BIT_MAPPING_VAL); /* Check if bit mask should be advanced (due to unused * bits). */ if (GET_FIELD(bit_mapping[j].data, DBG_ATTN_BIT_MAPPING_IS_UNUSED_BIT_CNT)) { bit_idx += (u8) attn_idx_val; continue; } /* Check current bit index */ if (reg_result->sts_val & BIT(bit_idx)) { /* An attention bit with value=1 was found */ const char *attn_name, *attn_type_str, *masked_str; u32 attn_name_offset; u32 sts_addr; /* Find attention name */ attn_name_offset = block_attn_name_offsets[attn_idx_val]; attn_name = &((const char *) s_user_dbg_arrays [BIN_BUF_DBG_PARSING_STRINGS].ptr) [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, bit_idx, masked_str); } bit_idx++; } } return DBG_STATUS_OK; }