/* 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. */ #define __PREVENT_DUMP_MEM_ARR__ #define __PREVENT_PXP_GLOBAL_WIN__ #define __PREVENT_COND_ARR__ #include "qed.h" #ifdef CONFIG_DEBUG_FS #include #include #include #include #include #include #include #include #include #include #include #include #include "qed_phy_api.h" #include "qed_hsi.h" #include "qed_compat.h" #include "qed_hw.h" #include "qed_dev_api.h" #include "qed_dcbx.h" #include "qed_chain.h" #include "qed_sp.h" /*#include "qed_user_dbg_fw_funcs.h"*/ #ifndef QED_UPSTREAM /* ! QED_UPSTREAM */ #include "qed_tests.h" #endif #include "qed_mcp.h" static uint dbg_send_uevent = 1; module_param(dbg_send_uevent, uint, S_IRUGO); MODULE_PARM_DESC(dbg_send_uevent, " Send a uevent upon saving all debug data to internal buffer (0 do-not-send; 1 send (default))"); static char dbg_data_path[QED_DBG_DATA_PATH_MAX_SIZE]; module_param_string(dbg_data_path, dbg_data_path, sizeof(dbg_data_path), S_IRUGO); MODULE_PARM_DESC(dbg_data_path, " Path for debug data files.\n" "\t\tA non-empty path enables saving auto-collected debug data to file. No uevent will be sent in this case."); static struct dentry *qed_dbg_root; #define MAX_PHY_RESULT_BUFFER 9000 /******************************** Feature Meta data section ************************************/ #define BUS_NUM_STR_FUNCS 16 #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 #ifndef QED_UPSTREAM /* ! QED_UPSTREAM */ #define TESTS_NUM_STR_FUNCS 66 #endif #define PHY_NUM_STR_FUNCS 20 struct qed_func_lookup { const char *key; int (*str_func) (struct qed_hwfn * p_hwfn, struct qed_ptt * p_ptt, char *params_string); }; /* lookup tables for finding the correct hsi function from user command */ const static struct qed_func_lookup qed_bus_hsi_func_lookup[] = { {"reset", qed_str_bus_reset}, {"set_pci_output", qed_str_bus_set_pci_output}, {"set_nw_output", qed_str_bus_set_nw_output}, {"enable_block", qed_str_bus_enable_block}, {"enable_storm", qed_str_bus_enable_storm}, {"enable_timestamp", qed_str_bus_enable_timestamp}, {"add_eid_range_sem_filter", qed_str_bus_add_eid_range_sem_filter}, {"add_eid_mask_sem_filter", qed_str_bus_add_eid_mask_sem_filter}, {"add_cid_sem_filter", qed_str_bus_add_cid_sem_filter}, {"enable_filter", qed_str_bus_enable_filter}, {"enable_trigger", qed_str_bus_enable_trigger}, {"add_trigger_state", qed_str_bus_add_trigger_state}, {"add_constraint", qed_str_bus_add_constraint}, {"start", qed_str_bus_start}, {"stop", qed_str_bus_stop}, {"dump", qed_str_bus_dump}, }; const static struct qed_func_lookup qed_grc_hsi_func_lookup[] = { {"config", qed_str_grc_config}, {"dump", qed_str_grc_dump}, }; const static struct qed_func_lookup qed_idle_chk_hsi_func_lookup[] = { {"dump", qed_str_idle_chk_dump}, }; const static struct qed_func_lookup qed_mcp_trace_hsi_func_lookup[] = { {"dump", qed_str_mcp_trace_dump}, }; const static struct qed_func_lookup qed_reg_fifo_hsi_func_lookup[] = { {"dump", qed_str_reg_fifo_dump}, }; const static struct qed_func_lookup qed_igu_fifo_hsi_func_lookup[] = { {"dump", qed_str_igu_fifo_dump}, }; const static struct qed_func_lookup qed_protection_override_hsi_func_lookup[] = { {"dump", qed_str_protection_override_dump}, }; const static struct qed_func_lookup qed_fw_asserts_hsi_func_lookup[] = { {"dump", qed_str_fw_asserts_dump}, }; #ifndef QED_UPSTREAM /* ! QED_UPSTREAM */ const static struct qed_func_lookup qed_tests_func_lookup[] = { {"qm_reconf", qed_str_qm_reconf_test}, {"ets", qed_str_ets_test}, {"phony_dcbx", qed_str_phony_dcbx_test}, {"mcp_halt", qed_str_mcp_halt_test}, {"mcp_resume", qed_str_mcp_resume_test}, {"mcp_mask_parities", qed_str_mcp_mask_parities_test}, {"mcp_unmask_parities", qed_str_mcp_unmask_parities_test}, {"test", qed_str_test_test}, {"coal_vf", qed_str_coal_vf_test}, {"gen_process_kill", qed_str_gen_process_kill_test}, {"gen_system_kill", qed_str_gen_system_kill_test}, {"trigger_recovery", qed_str_trigger_recovery_test}, {"msix_vector_mask", qed_str_msix_vector_mask_test}, {"msix_mask", qed_str_msix_mask_test}, {"msix_disable", qed_str_msix_disable_test}, {"config_obff_fsm", qed_str_config_obff_fsm_test}, {"dump_obff_stats", qed_str_dump_obff_stats_test}, {"set_obff_state", qed_str_set_obff_state_test}, {"ramrod_flood", qed_str_ramrod_flood_test}, {"gen_fan_failure", qed_str_gen_fan_failure_test}, {"bist_register", qed_str_bist_register_test}, {"bist_clock", qed_str_bist_clock_test}, {"bist_nvm", qed_str_bist_nvm_test}, {"get_temperature", qed_str_get_temperature_test}, {"get_mba_versions", qed_str_get_mba_versions_test}, {"mcp_resc_lock", qed_str_mcp_resc_lock_test}, {"mcp_resc_unlock", qed_str_mcp_resc_unlock_test}, {"read_dpm_register", qed_str_read_dpm_register_test}, {"iwarp_tcp_cids_weight", qed_str_iwarp_tcp_cids_weight_test}, {"iwarp_ep_free_list", qed_str_iwarp_ep_free_list_test}, {"iwarp_ep_active_list", qed_str_iwarp_ep_active_list_test}, {"iwarp_create_listen", qed_str_iwarp_create_listen_test}, {"iwarp_remove_listen", qed_str_iwarp_remove_listen_test}, {"iwarp_listeners", qed_str_iwarp_listeners_test}, {"rdma_query_stats", qed_str_rdma_query_stats_test}, {"db_recovery_dp", qed_str_db_recovery_dp_test}, {"db_recovery_execute", qed_str_db_recovery_execute_test}, {"dscp_pfc_enable", qed_str_dscp_pfc_enable_test}, {"dscp_pfc_get", qed_str_dscp_pfc_get_test}, {"dscp_pfc_set", qed_str_dscp_pfc_set_test}, {"dcbx_set_mode", qed_str_dcbx_set_mode_test}, {"dcbx_get_mode", qed_str_dcbx_get_mode_test}, {"dcbx_get_pfc", qed_str_dcbx_get_pfc_test}, {"dcbx_set_pfc", qed_str_dcbx_set_pfc_test}, {"dcbx_get_pri_to_tc", qed_str_dcbx_get_pri_to_tc_test}, {"dcbx_set_pri_to_tc", qed_str_dcbx_set_pri_to_tc_test}, {"dcbx_get_tc_bw", qed_str_dcbx_get_tc_bw_test}, {"dcbx_get_tc_tsa", qed_str_dcbx_get_tc_tsa_test}, {"dcbx_set_tc_bw_tsa", qed_str_dcbx_set_tc_bw_tsa_test}, {"dcbx_get_app", qed_str_dcbx_get_app_test}, {"dcbx_set_app", qed_str_dcbx_set_app_test}, {"rdma_glob_vlan_pri_en", qed_str_rdma_glob_vlan_pri_en_test}, {"rdma_glob_vlan_pri", qed_str_rdma_glob_vlan_pri_test}, {"rdma_glob_ecn_en", qed_str_rdma_glob_ecn_en_test}, {"rdma_glob_ecn", qed_str_rdma_glob_ecn_test}, {"rdma_glob_dscp_en", qed_str_rdma_glob_dscp_en_test}, {"rdma_glob_dscp", qed_str_rdma_glob_dscp_test}, {"gen_hw_err", qed_str_gen_hw_err_test}, {"set_dev_access", qed_str_set_dev_access_test}, {"reg_read", qed_str_reg_read_test}, {"reg_write", qed_str_reg_write_test}, {"dump_llh", qed_str_dump_llh_test}, {"pq_group_count", qed_str_pq_group_count_test}, {"pq_group_set_pq_port", qed_str_pq_group_set_pq_port_test}, {"rdma_bond_slave", qed_str_rdma_bond_slave_test}, {"link_down", qed_str_link_down_test}, }; #endif const static struct qed_func_lookup qed_phy_func_lookup[] = { {"core_write", qed_str_phy_core_write}, {"core_read", qed_str_phy_core_read}, {"raw_write", qed_str_phy_raw_write}, {"raw_read", qed_str_phy_raw_read}, {"mac_stat", qed_str_phy_mac_stat}, {"info", qed_str_phy_info}, {"sfp_write", qed_str_phy_sfp_write}, {"sfp_read", qed_str_phy_sfp_read}, {"sfp_decode", qed_str_phy_sfp_decode}, {"sfp_get_inserted", qed_str_phy_sfp_get_inserted}, {"sfp_get_txdisable", qed_str_phy_sfp_get_txdisable}, {"sfp_set_txdisable", qed_str_phy_sfp_set_txdisable}, {"sfp_get_txreset", qed_str_phy_sfp_get_txreset}, {"sfp_get_rxlos", qed_str_phy_sfp_get_rxlos}, {"sfp_get_eeprom", qed_str_phy_sfp_get_eeprom}, {"gpio_write", qed_str_phy_gpio_write}, {"gpio_read", qed_str_phy_gpio_read}, {"gpio_info", qed_str_phy_gpio_info}, {"extphy_read", qed_str_phy_extphy_read}, {"extphy_write", qed_str_phy_extphy_write}, }; /* wrapper for unifying the idle_chk and mcp_trace api */ 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); } /* feature meta data lookup table */ 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[] = { { "bus", BUS_NUM_STR_FUNCS, qed_dbg_bus_get_dump_buf_size, qed_dbg_bus_dump, NULL, NULL, qed_bus_hsi_func_lookup}, { "grc", GRC_NUM_STR_FUNCS, qed_dbg_grc_get_dump_buf_size, qed_dbg_grc_dump, NULL, NULL, qed_grc_hsi_func_lookup}, { "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, qed_idle_chk_hsi_func_lookup}, { "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, qed_mcp_trace_hsi_func_lookup}, { "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, qed_reg_fifo_hsi_func_lookup}, { "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, qed_igu_fifo_hsi_func_lookup}, { "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, qed_protection_override_hsi_func_lookup}, { "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, qed_fw_asserts_hsi_func_lookup},}; #ifndef QED_UPSTREAM /* ! QED_UPSTREAM */ static const char *tests_list = "qm_reconf\n" "ets\n" "phony_dcbx\n" "mcp_halt\n" "mcp_resume\n" "mcp_mask_parities\n" "mcp_unmask_parities\n" "test\n" "coal_vf\n" "gen_process_kill\n" "gen_system_kill\n" "trigger_recovery\n" "msix_vector_mask\n" "msix_mask\n" "msix_disable\n" "config_obff_fsm\n" "dump_obff_stats\n" "set_obff_state\n" "ramrod_flood\n" "gen_fan_failure\n" "bist_register\n" "bist_clock\n" "bist_nvm\n" "get_temperature\n" "get_mba_versions\n" "mcp_resc_lock\n" "mcp_resc_unlock\n" "read_dpm_register\n" "iwarp_tcp_cids_weight\n" "iwarp_ep_free_list\n" "iwarp_ep_active_list\n" "iwarp_create_listen\n" "iwarp_remove_listen\n" "iwarp_listeners\n" "rdma_query_stats\n" "db_recovery_dp\n" "db_recovery_execute\n" "dscp_pfc_enable\n" "dscp_pfc_get\n" "dscp_pfc_set\n" "dcbx_set_mode\n" "dcbx_get_mode\n" "dcbx_get_pfc\n" "dcbx_set_pfc\n" "dcbx_get_pri_to_tc\n" "dcbx_set_pri_to_tc\n" "dcbx_get_tc_bw\n" "dcbx_get_tc_tsa\n" "dcbx_set_tc_bw_tsa\n" "dcbx_get_app\n" "dcbx_set_app\n" "rdma_glob_vlan_pri_en\n" "rdma_glob_vlan_pri\n" "rdma_glob_ecn_en\n" "rdma_glob_ecn\n" "rdma_glob_dscp_en\n" "rdma_glob_dscp\n" "gen_hw_err\n" "set_dev_access\n" "reg_read\n" "reg_write\n" "dump_llh\n" "pq_group_count\n" "pq_group_set_pq_port\n" "rdma_bond_slave\n" "link_down\n"; #endif static const char *phy_list = "core_write\n" "core_read\n" "raw_write\n" "raw_read\n" "mac_stat\n" "info\n" "sfp_write\n" "sfp_read\n" "sfp_decode\n" "sfp_get_inserted\n" "sfp_get_txdisable\n" "sfp_set_txdisable\n" "sfp_get_txreset\n" "sfp_get_rxlos\n" "sfp_get_eeprom\n" "gpio_write\n" "gpio_read\n" "gpio_info\n" "extphy_read\n" "extphy_write\n"; #define ENGINE_NUM_STR_FUNCS 1 const static struct qed_func_lookup qed_engine_func_lookup[] = { {"engine", qed_str_engine}, }; /******************************** end of Feature meta data section *****************************/ 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 /* generic function for decoding debug feature info. */ 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 text_size_bytes, null_char_pos, i; enum dbg_status rc; char *text_buf; /* check if feature supports formatting capability */ if (qed_features_lookup[feature_idx].results_buf_size == NULL) return DBG_STATUS_OK; /* obtain size of formatted output */ rc = qed_features_lookup[feature_idx].results_buf_size(p_hwfn, (u32 *) feature-> dump_buf, feature-> dumped_dwords, &text_size_bytes); if (rc != DBG_STATUS_OK) return rc; /* Make sure that the allocated size is a multiple of dword (4 bytes) */ null_char_pos = text_size_bytes - 1; text_size_bytes = (text_size_bytes + 3) & ~0x3; if (text_size_bytes < QED_RESULTS_BUF_MIN_SIZE) { DP_NOTICE(p_hwfn->cdev, "formatted size of feature was too small %d. Aborting\n", text_size_bytes); return DBG_STATUS_INVALID_ARGS; } /* allocate temp text buf */ text_buf = vzalloc(text_size_bytes); if (!text_buf) { DP_NOTICE(p_hwfn->cdev, "failed to allocate text buffer. Aborting\n"); return DBG_STATUS_VIRT_MEM_ALLOC_FAILED; } /* decode feature opcodes to string on temp buf */ rc = qed_features_lookup[feature_idx].print_results(p_hwfn, (u32 *) feature-> dump_buf, feature-> dumped_dwords, text_buf); if (rc != DBG_STATUS_OK) { vfree(text_buf); return rc; } /* Replace the original null character with a '\n' character. * The bytes that were added as a result of the dword alignment are also * padded with '\n' characters. */ for (i = null_char_pos; i < text_size_bytes; i++) text_buf[i] = '\n'; /* dump printable feature to log */ if (p_hwfn->cdev->print_dbg_data) qed_dbg_print_feature(text_buf, text_size_bytes); /* free the old dump_buf and point the dump_buf to the newly allocagted and formatted text buffer */ vfree(feature->dump_buf); feature->dump_buf = text_buf; feature->buf_size = text_size_bytes; feature->dumped_dwords = text_size_bytes / 4; return rc; } /* generic function for performing the dump of a debug feature. */ 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; enum dbg_status rc; DP_NOTICE(p_hwfn->cdev, "Collecting a debug feature [\"%s\"]\n", qed_features_lookup[feature_idx].name); /* dump_buf was already allocated need to free (this can happen if dump was called but file was never read). * We can't use the buffer as is since size may have changed */ if (feature->dump_buf) { vfree(feature->dump_buf); feature->dump_buf = NULL; } /* get buffer size from hsi, allocate accordingly, and perform the dump */ 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; 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; rc = qed_features_lookup[feature_idx].perform_dump(p_hwfn, p_ptt, (u32 *) feature-> dump_buf, feature->buf_size / sizeof(u32), &feature-> dumped_dwords); /* if mcp is stuck we get DBG_STATUS_NVRAM_GET_IMAGE_FAILED error. * In this case the buffer holds valid binary data, but we wont able * to parse it (since parsing relies on data in NVRAM which is only * accessible when MFW is responsive). skip the formatting but return * success so that binary data is provided. */ if (rc == DBG_STATUS_NVRAM_GET_IMAGE_FAILED) return DBG_STATUS_OK; if (rc != DBG_STATUS_OK) return rc; /* format output */ rc = format_feature(p_hwfn, feature_idx); return rc; } /* postconfig globals */ static void *postconfig_buf; static int postconfig_bytes; /* phy globals */ char *p_phy_result_buf; /******************************** wrappers ************************************/ /*** wrapper for invoking qed_dbg_bus_reset according to string parameter ***/ int qed_str_bus_reset(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, char *params_string) { u32 one_shot_en; u8 force_hw_dwords; u32 unify_inputs; u32 grc_input_en; int args_num = 4; if (args_num != sscanf(params_string, "%i %hhi %i %i ", &one_shot_en, &force_hw_dwords, &unify_inputs, &grc_input_en)) return DBG_STATUS_INVALID_ARGS; return qed_dbg_bus_reset(p_hwfn, p_ptt, one_shot_en, force_hw_dwords, unify_inputs, grc_input_en); } /*** wrapper for invoking qed_dbg_bus_set_pci_output according to string parameter ***/ int qed_str_bus_set_pci_output(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, char *params_string) { u16 buf_size_kb; int args_num = 1; if (args_num != sscanf(params_string, "%hi ", &buf_size_kb)) return DBG_STATUS_INVALID_ARGS; return qed_dbg_bus_set_pci_output(p_hwfn, p_ptt, buf_size_kb); } /*** wrapper for invoking qed_dbg_bus_set_nw_output according to string parameter ***/ int qed_str_bus_set_nw_output(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, char *params_string) { u8 port_id; u32 dest_addr_lo32; u16 dest_addr_hi16; u16 data_limit_size_kb; u32 send_to_other_engine; u32 rcv_from_other_engine; int args_num = 6; if (args_num != sscanf(params_string, "%hhi %i %hi %hi %i %i ", &port_id, &dest_addr_lo32, &dest_addr_hi16, &data_limit_size_kb, &send_to_other_engine, &rcv_from_other_engine)) return DBG_STATUS_INVALID_ARGS; return qed_dbg_bus_set_nw_output(p_hwfn, p_ptt, port_id, dest_addr_lo32, dest_addr_hi16, data_limit_size_kb, send_to_other_engine, rcv_from_other_engine); } /*** wrapper for invoking qed_dbg_bus_enable_block according to string parameter ***/ int qed_str_bus_enable_block(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, char *params_string) { char block[MAX_NAME_LEN]; u8 line_num; u8 cycle_en; u8 right_shift; u8 force_valid; u8 force_frame; char line[64]; int args_num = 6; if (args_num != sscanf(params_string, "%s %s %hhi %hhi %hhi %hhi", block, line, &cycle_en, &right_shift, &force_valid, &force_frame)) return DBG_STATUS_INVALID_ARGS; line_num = qed_dbg_get_dbg_bus_line(qed_dbg_get_block_id(block), qed_dbg_get_chip_id(p_hwfn), line); return qed_dbg_bus_enable_block(p_hwfn, qed_dbg_get_block_id(block), line_num, cycle_en, right_shift, force_valid, force_frame); } /*** wrapper for invoking qed_dbg_bus_enable_storm according to string parameter ***/ int qed_str_bus_enable_storm(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, char *params_string) { char storm[MAX_NAME_LEN]; char storm_mode[MAX_NAME_LEN]; int args_num = 2; if (args_num != sscanf(params_string, "%s %s ", storm, storm_mode)) return DBG_STATUS_INVALID_ARGS; return qed_dbg_bus_enable_storm(p_hwfn, qed_dbg_get_storm_id(storm), qed_dbg_get_storm_mode_id(storm_mode)); } /*** wrapper for invoking qed_dbg_bus_enable_timestamp according to string parameter ***/ int qed_str_bus_enable_timestamp(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, char *params_string) { u8 valid_en; u8 frame_en; u32 tick_len; int args_num = 3; if (args_num != sscanf(params_string, "%hhi %hhi %i ", &valid_en, &frame_en, &tick_len)) return DBG_STATUS_INVALID_ARGS; return qed_dbg_bus_enable_timestamp(p_hwfn, p_ptt, valid_en, frame_en, tick_len); } /*** wrapper for invoking qed_dbg_bus_add_eid_range_sem_filter according to string parameter ***/ int qed_str_bus_add_eid_range_sem_filter(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, char *params_string) { char storm[MAX_NAME_LEN]; u8 min_eid; u8 max_eid; int args_num = 3; if (args_num != sscanf(params_string, "%s %hhi %hhi ", storm, &min_eid, &max_eid)) return DBG_STATUS_INVALID_ARGS; return qed_dbg_bus_add_eid_range_sem_filter(p_hwfn, qed_dbg_get_storm_id(storm), min_eid, max_eid); } /*** wrapper for invoking qed_dbg_bus_add_eid_mask_sem_filter according to string parameter ***/ int qed_str_bus_add_eid_mask_sem_filter(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, char *params_string) { char storm[MAX_NAME_LEN]; u8 eid_val; u8 eid_mask; int args_num = 3; if (args_num != sscanf(params_string, "%s %hhi %hhi ", storm, &eid_val, &eid_mask)) return DBG_STATUS_INVALID_ARGS; return qed_dbg_bus_add_eid_mask_sem_filter(p_hwfn, qed_dbg_get_storm_id(storm), eid_val, eid_mask); } /*** wrapper for invoking qed_dbg_bus_add_cid_sem_filter according to string parameter ***/ int qed_str_bus_add_cid_sem_filter(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, char *params_string) { char storm[MAX_NAME_LEN]; u32 cid; int args_num = 2; if (args_num != sscanf(params_string, "%s %i ", storm, &cid)) return DBG_STATUS_INVALID_ARGS; return qed_dbg_bus_add_cid_sem_filter(p_hwfn, qed_dbg_get_storm_id(storm), cid); } /*** wrapper for invoking qed_dbg_bus_enable_filter according to string parameter ***/ int qed_str_bus_enable_filter(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, char *params_string) { char block[MAX_NAME_LEN]; u8 const_msg_len; int args_num = 2; if (args_num != sscanf(params_string, "%s %hhi ", block, &const_msg_len)) return DBG_STATUS_INVALID_ARGS; return qed_dbg_bus_enable_filter(p_hwfn, p_ptt, qed_dbg_get_block_id(block), const_msg_len); } /*** wrapper for invoking qed_dbg_bus_enable_trigger according to string parameter ***/ int qed_str_bus_enable_trigger(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, char *params_string) { u32 rec_pre_trigger; u8 pre_chunks; u32 rec_post_trigger; u32 post_cycles; u32 filter_pre_trigger; u32 filter_post_trigger; int args_num = 6; if (args_num != sscanf(params_string, "%i %hhi %i %i %i %i ", &rec_pre_trigger, &pre_chunks, &rec_post_trigger, &post_cycles, &filter_pre_trigger, &filter_post_trigger)) return DBG_STATUS_INVALID_ARGS; return qed_dbg_bus_enable_trigger(p_hwfn, p_ptt, rec_pre_trigger, pre_chunks, rec_post_trigger, post_cycles, filter_pre_trigger, filter_post_trigger); } /*** wrapper for invoking qed_dbg_bus_add_trigger_state according to string parameter ***/ int qed_str_bus_add_trigger_state(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, char *params_string) { char block[MAX_NAME_LEN]; u8 const_msg_len; u16 count_to_next; int args_num = 3; if (args_num != sscanf(params_string, "%s %hhi %hi ", block, &const_msg_len, &count_to_next)) return DBG_STATUS_INVALID_ARGS; return qed_dbg_bus_add_trigger_state(p_hwfn, p_ptt, qed_dbg_get_block_id(block), const_msg_len, count_to_next); } /*** wrapper for invoking qed_dbg_bus_add_constraint according to string parameter ***/ int qed_str_bus_add_constraint(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, char *params_string) { char constraint_op[MAX_NAME_LEN]; u32 data; u32 data_mask; u32 compare_frame; u8 frame_bit; u8 cycle_offset; u8 dword_offset_in_cycle; u32 is_mandatory; int args_num = 8; if (args_num != sscanf(params_string, "%s %i %i %i %hhi %hhi %hhi %i ", constraint_op, &data, &data_mask, &compare_frame, &frame_bit, &cycle_offset, &dword_offset_in_cycle, &is_mandatory)) return DBG_STATUS_INVALID_ARGS; return qed_dbg_bus_add_constraint(p_hwfn, p_ptt, qed_dbg_get_constraint_op_id (constraint_op), data, data_mask, compare_frame, frame_bit, cycle_offset, dword_offset_in_cycle, is_mandatory); } /*** wrapper for invoking qed_dbg_bus_start according to string parameter ***/ int qed_str_bus_start(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, char *params_string) { p_hwfn->cdev->recording_active = true; return qed_dbg_bus_start(p_hwfn, p_ptt); } /*** wrapper for invoking qed_dbg_bus_stop according to string parameter ***/ int qed_str_bus_stop(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, char *params_string) { return qed_dbg_bus_stop(p_hwfn, p_ptt); } /*** wrapper for invoking qed_dbg_bus_dump according to string parameter ***/ int qed_str_bus_dump(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, char *params_string) { p_hwfn->cdev->recording_active = false; return qed_dbg_dump(p_hwfn, p_ptt, DBG_FEATURE_BUS); } /*** wrapper for invoking qed_dbg_grc_config according to string parameter ***/ int qed_str_grc_config(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, char *params_string) { char grc_param[MAX_NAME_LEN]; u32 val; int args_num = 2; if (args_num != sscanf(params_string, "%s %i ", grc_param, &val)) return DBG_STATUS_INVALID_ARGS; return qed_dbg_grc_config(p_hwfn, qed_dbg_get_grc_param_id(grc_param), val); } /*** wrapper for invoking qed_dbg_grc_dump according to string parameter ***/ int qed_str_grc_dump(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, char *params_string) { return qed_dbg_dump(p_hwfn, p_ptt, DBG_FEATURE_GRC); } /*** wrapper for invoking qed_dbg_idle_chk_dump according to string parameter ***/ int qed_str_idle_chk_dump(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, char *params_string) { return qed_dbg_dump(p_hwfn, p_ptt, DBG_FEATURE_IDLE_CHK); } /*** wrapper for invoking qed_dbg_mcp_trace_dump according to string parameter ***/ int qed_str_mcp_trace_dump(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, char *params_string) { return qed_dbg_dump(p_hwfn, p_ptt, DBG_FEATURE_MCP_TRACE); } /*** wrapper for invoking qed_dbg_reg_fifo_dump according to string parameter ***/ int qed_str_reg_fifo_dump(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, char *params_string) { return qed_dbg_dump(p_hwfn, p_ptt, DBG_FEATURE_REG_FIFO); } /*** wrapper for invoking qed_dbg_igu_fifo_dump according to string parameter ***/ int qed_str_igu_fifo_dump(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, char *params_string) { return qed_dbg_dump(p_hwfn, p_ptt, DBG_FEATURE_IGU_FIFO); } /*** wrapper for invoking qed_dbg_protection_override_dump according to string parameter ***/ int qed_str_protection_override_dump(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, char *params_string) { return qed_dbg_dump(p_hwfn, p_ptt, DBG_FEATURE_PROTECTION_OVERRIDE); } /*** wrapper for invoking qed_dbg_fw_asserts_dump according to string parameter ***/ int qed_str_fw_asserts_dump(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, char *params_string) { return qed_dbg_dump(p_hwfn, p_ptt, DBG_FEATURE_FW_ASSERTS); } #ifndef QED_UPSTREAM /* ! QED_UPSTREAM */ /*** wrapper for invoking qed_qm_reconf_test according to string parameter ***/ int qed_str_qm_reconf_test(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, char *params_string) { return qed_qm_reconf_test(p_hwfn, p_ptt); } /*** wrapper for invoking qed_ets_test according to string parameter ***/ int qed_str_ets_test(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, char *params_string) { return qed_ets_test(p_hwfn, p_ptt); } /*** wrapper for invoking qed_phony_dcbx_test according to string parameter ***/ int qed_str_phony_dcbx_test(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, char *params_string) { return qed_phony_dcbx_test(p_hwfn, p_ptt); } /*** wrapper for invoking qed_mcp_halt_test according to string parameter ***/ int qed_str_mcp_halt_test(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, char *params_string) { return qed_mcp_halt_test(p_hwfn, p_ptt); } /*** wrapper for invoking qed_mcp_resume_test according to string parameter ***/ int qed_str_mcp_resume_test(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, char *params_string) { return qed_mcp_resume_test(p_hwfn, p_ptt); } /*** wrapper for invoking qed_mcp_mask_parities_test according to string parameter ***/ int qed_str_mcp_mask_parities_test(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, char *params_string) { return qed_mcp_mask_parities_test(p_hwfn, p_ptt); } /*** wrapper for invoking qed_mcp_unmask_parities_test according to string parameter ***/ int qed_str_mcp_unmask_parities_test(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, char *params_string) { return qed_mcp_unmask_parities_test(p_hwfn, p_ptt); } /*** wrapper for invoking qed_test_test according to string parameter ***/ int qed_str_test_test(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, char *params_string) { u32 rc; int args_num = 1; if (args_num != sscanf(params_string, "%i ", &rc)) return DBG_STATUS_INVALID_ARGS; return qed_test_test(p_hwfn, p_ptt, rc); } /*** wrapper for invoking qed_coal_vf_test according to string parameter ***/ int qed_str_coal_vf_test(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, char *params_string) { u16 rx_coal; u16 tx_coal; u16 vf_id; int args_num = 3; if (args_num != sscanf(params_string, "%hi %hi %hi ", &rx_coal, &tx_coal, &vf_id)) return DBG_STATUS_INVALID_ARGS; return qed_coal_vf_test(p_hwfn, p_ptt, rx_coal, tx_coal, vf_id); } /*** wrapper for invoking qed_gen_process_kill_test according to string parameter ***/ int qed_str_gen_process_kill_test(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, char *params_string) { u8 is_common_block; int args_num = 1; if (args_num != sscanf(params_string, "%hhi ", &is_common_block)) return DBG_STATUS_INVALID_ARGS; return qed_gen_process_kill_test(p_hwfn, p_ptt, is_common_block); } /*** wrapper for invoking qed_gen_system_kill_test according to string parameter ***/ int qed_str_gen_system_kill_test(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, char *params_string) { return qed_gen_system_kill_test(p_hwfn, p_ptt); } /*** wrapper for invoking qed_trigger_recovery_test according to string parameter ***/ int qed_str_trigger_recovery_test(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, char *params_string) { return qed_trigger_recovery_test(p_hwfn, p_ptt); } /*** wrapper for invoking qed_msix_vector_mask_test according to string parameter ***/ int qed_str_msix_vector_mask_test(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, char *params_string) { u8 vector; u8 b_mask; int args_num = 2; if (args_num != sscanf(params_string, "%hhi %hhi ", &vector, &b_mask)) return DBG_STATUS_INVALID_ARGS; return qed_msix_vector_mask_test(p_hwfn, p_ptt, vector, b_mask); } /*** wrapper for invoking qed_msix_mask_test according to string parameter ***/ int qed_str_msix_mask_test(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, char *params_string) { u8 b_mask; int args_num = 1; if (args_num != sscanf(params_string, "%hhi ", &b_mask)) return DBG_STATUS_INVALID_ARGS; return qed_msix_mask_test(p_hwfn, p_ptt, b_mask); } /*** wrapper for invoking qed_msix_disable_test according to string parameter ***/ int qed_str_msix_disable_test(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, char *params_string) { u8 b_disable; int args_num = 1; if (args_num != sscanf(params_string, "%hhi ", &b_disable)) return DBG_STATUS_INVALID_ARGS; return qed_msix_disable_test(p_hwfn, p_ptt, b_disable); } /*** wrapper for invoking qed_config_obff_fsm_test according to string parameter ***/ int qed_str_config_obff_fsm_test(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, char *params_string) { return qed_config_obff_fsm_test(p_hwfn, p_ptt); } /*** wrapper for invoking qed_dump_obff_stats_test according to string parameter ***/ int qed_str_dump_obff_stats_test(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, char *params_string) { return qed_dump_obff_stats_test(p_hwfn, p_ptt); } /*** wrapper for invoking qed_set_obff_state_test according to string parameter ***/ int qed_str_set_obff_state_test(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, char *params_string) { u8 state; int args_num = 1; if (args_num != sscanf(params_string, "%hhi ", &state)) return DBG_STATUS_INVALID_ARGS; return qed_set_obff_state_test(p_hwfn, p_ptt, state); } /*** wrapper for invoking qed_ramrod_flood_test according to string parameter ***/ int qed_str_ramrod_flood_test(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, char *params_string) { u32 ramrod_amount; int args_num = 1; if (args_num != sscanf(params_string, "%i ", &ramrod_amount)) return DBG_STATUS_INVALID_ARGS; return qed_ramrod_flood_test(p_hwfn, p_ptt, ramrod_amount); } /*** wrapper for invoking qed_gen_fan_failure_test according to string parameter ***/ int qed_str_gen_fan_failure_test(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, char *params_string) { u8 is_over_temp; int args_num = 1; if (args_num != sscanf(params_string, "%hhi ", &is_over_temp)) return DBG_STATUS_INVALID_ARGS; return qed_gen_fan_failure_test(p_hwfn, p_ptt, is_over_temp); } /*** wrapper for invoking qed_bist_register_test according to string parameter ***/ int qed_str_bist_register_test(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, char *params_string) { return qed_bist_register_test(p_hwfn, p_ptt); } /*** wrapper for invoking qed_bist_clock_test according to string parameter ***/ int qed_str_bist_clock_test(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, char *params_string) { return qed_bist_clock_test(p_hwfn, p_ptt); } /*** wrapper for invoking qed_bist_nvm_test according to string parameter ***/ int qed_str_bist_nvm_test(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, char *params_string) { return qed_bist_nvm_test(p_hwfn, p_ptt); } /*** wrapper for invoking qed_get_temperature_test according to string parameter ***/ int qed_str_get_temperature_test(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, char *params_string) { return qed_get_temperature_test(p_hwfn, p_ptt); } /*** wrapper for invoking qed_get_mba_versions_test according to string parameter ***/ int qed_str_get_mba_versions_test(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, char *params_string) { return qed_get_mba_versions_test(p_hwfn, p_ptt); } /*** wrapper for invoking qed_mcp_resc_lock_test according to string parameter ***/ int qed_str_mcp_resc_lock_test(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, char *params_string) { u8 resource; u8 timeout; int args_num = 2; if (args_num != sscanf(params_string, "%hhi %hhi ", &resource, &timeout)) return DBG_STATUS_INVALID_ARGS; return qed_mcp_resc_lock_test(p_hwfn, p_ptt, resource, timeout); } /*** wrapper for invoking qed_mcp_resc_unlock_test according to string parameter ***/ int qed_str_mcp_resc_unlock_test(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, char *params_string) { u8 resource; u8 force; int args_num = 2; if (args_num != sscanf(params_string, "%hhi %hhi ", &resource, &force)) return DBG_STATUS_INVALID_ARGS; return qed_mcp_resc_unlock_test(p_hwfn, p_ptt, resource, force); } /*** wrapper for invoking qed_read_dpm_register_test according to string parameter ***/ int qed_str_read_dpm_register_test(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, char *params_string) { u32 hw_addr; int args_num = 1; if (args_num != sscanf(params_string, "%i ", &hw_addr)) return DBG_STATUS_INVALID_ARGS; return qed_read_dpm_register_test(p_hwfn, p_ptt, hw_addr); } /*** wrapper for invoking qed_iwarp_tcp_cids_weight_test according to string parameter ***/ int qed_str_iwarp_tcp_cids_weight_test(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, char *params_string) { return qed_iwarp_tcp_cids_weight_test(p_hwfn, p_ptt); } /*** wrapper for invoking qed_iwarp_ep_free_list_test according to string parameter ***/ int qed_str_iwarp_ep_free_list_test(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, char *params_string) { return qed_iwarp_ep_free_list_test(p_hwfn, p_ptt); } /*** wrapper for invoking qed_iwarp_ep_active_list_test according to string parameter ***/ int qed_str_iwarp_ep_active_list_test(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, char *params_string) { return qed_iwarp_ep_active_list_test(p_hwfn, p_ptt); } /*** wrapper for invoking qed_iwarp_create_listen_test according to string parameter ***/ int qed_str_iwarp_create_listen_test(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, char *params_string) { u32 ip_addr; u32 port; int args_num = 2; if (args_num != sscanf(params_string, "%i %i ", &ip_addr, &port)) return DBG_STATUS_INVALID_ARGS; return qed_iwarp_create_listen_test(p_hwfn, p_ptt, ip_addr, port); } /*** wrapper for invoking qed_iwarp_remove_listen_test according to string parameter ***/ int qed_str_iwarp_remove_listen_test(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, char *params_string) { u32 handle_hi; u32 handle_lo; int args_num = 2; if (args_num != sscanf(params_string, "%i %i ", &handle_hi, &handle_lo)) return DBG_STATUS_INVALID_ARGS; return qed_iwarp_remove_listen_test(p_hwfn, p_ptt, handle_hi, handle_lo); } /*** wrapper for invoking qed_iwarp_listeners_test according to string parameter ***/ int qed_str_iwarp_listeners_test(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, char *params_string) { return qed_iwarp_listeners_test(p_hwfn, p_ptt); } /*** wrapper for invoking qed_rdma_query_stats_test according to string parameter ***/ int qed_str_rdma_query_stats_test(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, char *params_string) { return qed_rdma_query_stats_test(p_hwfn, p_ptt); } /*** wrapper for invoking qed_db_recovery_dp_test according to string parameter ***/ int qed_str_db_recovery_dp_test(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, char *params_string) { return qed_db_recovery_dp_test(p_hwfn, p_ptt); } /*** wrapper for invoking qed_db_recovery_execute_test according to string parameter ***/ int qed_str_db_recovery_execute_test(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, char *params_string) { u8 is_dry_run; int args_num = 1; if (args_num != sscanf(params_string, "%hhi ", &is_dry_run)) return DBG_STATUS_INVALID_ARGS; return qed_db_recovery_execute_test(p_hwfn, p_ptt, is_dry_run); } /*** wrapper for invoking qed_dscp_pfc_enable_test according to string parameter ***/ int qed_str_dscp_pfc_enable_test(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, char *params_string) { u8 enable; int args_num = 1; if (args_num != sscanf(params_string, "%hhi ", &enable)) return DBG_STATUS_INVALID_ARGS; return qed_dscp_pfc_enable_test(p_hwfn, p_ptt, enable); } /*** wrapper for invoking qed_dscp_pfc_get_test according to string parameter ***/ int qed_str_dscp_pfc_get_test(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, char *params_string) { u8 index; int args_num = 1; if (args_num != sscanf(params_string, "%hhi ", &index)) return DBG_STATUS_INVALID_ARGS; return qed_dscp_pfc_get_test(p_hwfn, p_ptt, index); } /*** wrapper for invoking qed_dscp_pfc_set_test according to string parameter ***/ int qed_str_dscp_pfc_set_test(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, char *params_string) { u8 index; u8 pri_val; int args_num = 2; if (args_num != sscanf(params_string, "%hhi %hhi ", &index, &pri_val)) return DBG_STATUS_INVALID_ARGS; return qed_dscp_pfc_set_test(p_hwfn, p_ptt, index, pri_val); } /*** wrapper for invoking qed_dcbx_set_mode_test according to string parameter ***/ int qed_str_dcbx_set_mode_test(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, char *params_string) { u8 mode; int args_num = 1; if (args_num != sscanf(params_string, "%hhi ", &mode)) return DBG_STATUS_INVALID_ARGS; return qed_dcbx_set_mode_test(p_hwfn, p_ptt, mode); } /*** wrapper for invoking qed_dcbx_get_mode_test according to string parameter ***/ int qed_str_dcbx_get_mode_test(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, char *params_string) { return qed_dcbx_get_mode_test(p_hwfn, p_ptt); } /*** wrapper for invoking qed_dcbx_get_pfc_test according to string parameter ***/ int qed_str_dcbx_get_pfc_test(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, char *params_string) { u8 priority; int args_num = 1; if (args_num != sscanf(params_string, "%hhi ", &priority)) return DBG_STATUS_INVALID_ARGS; return qed_dcbx_get_pfc_test(p_hwfn, p_ptt, priority); } /*** wrapper for invoking qed_dcbx_set_pfc_test according to string parameter ***/ int qed_str_dcbx_set_pfc_test(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, char *params_string) { u8 priority; u8 enable; int args_num = 2; if (args_num != sscanf(params_string, "%hhi %hhi ", &priority, &enable)) return DBG_STATUS_INVALID_ARGS; return qed_dcbx_set_pfc_test(p_hwfn, p_ptt, priority, enable); } /*** wrapper for invoking qed_dcbx_get_pri_to_tc_test according to string parameter ***/ int qed_str_dcbx_get_pri_to_tc_test(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, char *params_string) { u8 pri; int args_num = 1; if (args_num != sscanf(params_string, "%hhi ", &pri)) return DBG_STATUS_INVALID_ARGS; return qed_dcbx_get_pri_to_tc_test(p_hwfn, p_ptt, pri); } /*** wrapper for invoking qed_dcbx_set_pri_to_tc_test according to string parameter ***/ int qed_str_dcbx_set_pri_to_tc_test(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, char *params_string) { u8 pri; u8 tc; int args_num = 2; if (args_num != sscanf(params_string, "%hhi %hhi ", &pri, &tc)) return DBG_STATUS_INVALID_ARGS; return qed_dcbx_set_pri_to_tc_test(p_hwfn, p_ptt, pri, tc); } /*** wrapper for invoking qed_dcbx_get_tc_bw_test according to string parameter ***/ int qed_str_dcbx_get_tc_bw_test(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, char *params_string) { u8 tc; int args_num = 1; if (args_num != sscanf(params_string, "%hhi ", &tc)) return DBG_STATUS_INVALID_ARGS; return qed_dcbx_get_tc_bw_test(p_hwfn, p_ptt, tc); } /*** wrapper for invoking qed_dcbx_get_tc_tsa_test according to string parameter ***/ int qed_str_dcbx_get_tc_tsa_test(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, char *params_string) { u8 tc; int args_num = 1; if (args_num != sscanf(params_string, "%hhi ", &tc)) return DBG_STATUS_INVALID_ARGS; return qed_dcbx_get_tc_tsa_test(p_hwfn, p_ptt, tc); } /*** wrapper for invoking qed_dcbx_set_tc_bw_tsa_test according to string parameter ***/ int qed_str_dcbx_set_tc_bw_tsa_test(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, char *params_string) { u8 tc; u8 bw_pct; u8 tsa_type; int args_num = 3; if (args_num != sscanf(params_string, "%hhi %hhi %hhi ", &tc, &bw_pct, &tsa_type)) return DBG_STATUS_INVALID_ARGS; return qed_dcbx_set_tc_bw_tsa_test(p_hwfn, p_ptt, tc, bw_pct, tsa_type); } /*** wrapper for invoking qed_dcbx_get_app_test according to string parameter ***/ int qed_str_dcbx_get_app_test(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, char *params_string) { u8 idtype; u16 idval; int args_num = 2; if (args_num != sscanf(params_string, "%hhi %hi ", &idtype, &idval)) return DBG_STATUS_INVALID_ARGS; return qed_dcbx_get_app_test(p_hwfn, p_ptt, idtype, idval); } /*** wrapper for invoking qed_dcbx_set_app_test according to string parameter ***/ int qed_str_dcbx_set_app_test(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, char *params_string) { u8 idtype; u16 idval; u8 pri; int args_num = 3; if (args_num != sscanf(params_string, "%hhi %hi %hhi ", &idtype, &idval, &pri)) return DBG_STATUS_INVALID_ARGS; return qed_dcbx_set_app_test(p_hwfn, p_ptt, idtype, idval, pri); } /*** wrapper for invoking qed_rdma_glob_vlan_pri_en_test according to string parameter ***/ int qed_str_rdma_glob_vlan_pri_en_test(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, char *params_string) { u8 pri_en_val; int args_num = 1; if (args_num != sscanf(params_string, "%hhi ", &pri_en_val)) return DBG_STATUS_INVALID_ARGS; return qed_rdma_glob_vlan_pri_en_test(p_hwfn, p_ptt, pri_en_val); } /*** wrapper for invoking qed_rdma_glob_vlan_pri_test according to string parameter ***/ int qed_str_rdma_glob_vlan_pri_test(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, char *params_string) { u8 pri_val; int args_num = 1; if (args_num != sscanf(params_string, "%hhi ", &pri_val)) return DBG_STATUS_INVALID_ARGS; return qed_rdma_glob_vlan_pri_test(p_hwfn, p_ptt, pri_val); } /*** wrapper for invoking qed_rdma_glob_ecn_en_test according to string parameter ***/ int qed_str_rdma_glob_ecn_en_test(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, char *params_string) { u8 ecn_en_val; int args_num = 1; if (args_num != sscanf(params_string, "%hhi ", &ecn_en_val)) return DBG_STATUS_INVALID_ARGS; return qed_rdma_glob_ecn_en_test(p_hwfn, p_ptt, ecn_en_val); } /*** wrapper for invoking qed_rdma_glob_ecn_test according to string parameter ***/ int qed_str_rdma_glob_ecn_test(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, char *params_string) { u8 ecn_val; int args_num = 1; if (args_num != sscanf(params_string, "%hhi ", &ecn_val)) return DBG_STATUS_INVALID_ARGS; return qed_rdma_glob_ecn_test(p_hwfn, p_ptt, ecn_val); } /*** wrapper for invoking qed_rdma_glob_dscp_en_test according to string parameter ***/ int qed_str_rdma_glob_dscp_en_test(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, char *params_string) { u8 dscp_en_val; int args_num = 1; if (args_num != sscanf(params_string, "%hhi ", &dscp_en_val)) return DBG_STATUS_INVALID_ARGS; return qed_rdma_glob_dscp_en_test(p_hwfn, p_ptt, dscp_en_val); } /*** wrapper for invoking qed_rdma_glob_dscp_test according to string parameter ***/ int qed_str_rdma_glob_dscp_test(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, char *params_string) { u8 dscp_val; int args_num = 1; if (args_num != sscanf(params_string, "%hhi ", &dscp_val)) return DBG_STATUS_INVALID_ARGS; return qed_rdma_glob_dscp_test(p_hwfn, p_ptt, dscp_val); } /*** wrapper for invoking qed_gen_hw_err_test according to string parameter ***/ int qed_str_gen_hw_err_test(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, char *params_string) { u8 hw_err_type; int args_num = 1; if (args_num != sscanf(params_string, "%hhi ", &hw_err_type)) return DBG_STATUS_INVALID_ARGS; return qed_gen_hw_err_test(p_hwfn, p_ptt, hw_err_type); } /*** wrapper for invoking qed_set_dev_access_test according to string parameter ***/ int qed_str_set_dev_access_test(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, char *params_string) { u8 enable; int args_num = 1; if (args_num != sscanf(params_string, "%hhi ", &enable)) return DBG_STATUS_INVALID_ARGS; return qed_set_dev_access_test(p_hwfn, p_ptt, enable); } /*** wrapper for invoking qed_reg_read_test according to string parameter ***/ int qed_str_reg_read_test(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, char *params_string) { u32 addr; int args_num = 1; if (args_num != sscanf(params_string, "%i ", &addr)) return DBG_STATUS_INVALID_ARGS; return qed_reg_read_test(p_hwfn, p_ptt, addr); } /*** wrapper for invoking qed_reg_write_test according to string parameter ***/ int qed_str_reg_write_test(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, char *params_string) { u32 addr; u32 value; int args_num = 2; if (args_num != sscanf(params_string, "%i %i ", &addr, &value)) return DBG_STATUS_INVALID_ARGS; return qed_reg_write_test(p_hwfn, p_ptt, addr, value); } /*** wrapper for invoking qed_dump_llh_test according to string parameter ***/ int qed_str_dump_llh_test(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, char *params_string) { return qed_dump_llh_test(p_hwfn, p_ptt); } /*** wrapper for invoking qed_pq_group_count_test according to string parameter ***/ int qed_str_pq_group_count_test(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, char *params_string) { u8 count; int args_num = 1; if (args_num != sscanf(params_string, "%hhi ", &count)) return DBG_STATUS_INVALID_ARGS; return qed_pq_group_count_test(p_hwfn, p_ptt, count); } /*** wrapper for invoking qed_pq_group_set_pq_port_test according to string parameter ***/ int qed_str_pq_group_set_pq_port_test(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, char *params_string) { u16 idx; u8 port; u8 tc; int args_num = 3; if (args_num != sscanf(params_string, "%hi %hhi %hhi ", &idx, &port, &tc)) return DBG_STATUS_INVALID_ARGS; return qed_pq_group_set_pq_port_test(p_hwfn, p_ptt, idx, port, tc); } /*** wrapper for invoking qed_rdma_bond_slave_test according to string parameter ***/ int qed_str_rdma_bond_slave_test(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, char *params_string) { u8 slave_ppfid; u8 master_pfid; int args_num = 2; if (args_num != sscanf(params_string, "%hhi %hhi ", &slave_ppfid, &master_pfid)) return DBG_STATUS_INVALID_ARGS; return qed_rdma_bond_slave_test(p_hwfn, p_ptt, slave_ppfid, master_pfid); } /*** wrapper for invoking qed_link_down_test according to string parameter ***/ int qed_str_link_down_test(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, char *params_string) { u8 link_up; int args_num = 1; if (args_num != sscanf(params_string, "%hhi ", &link_up)) return DBG_STATUS_INVALID_ARGS; return qed_link_down_test(p_hwfn, p_ptt, link_up); } #endif /*** wrapper for invoking qed_phy_core_write according to string parameter ***/ int qed_str_phy_core_write(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, char *params_string) { u32 port; u32 addr; u32 data_lo; u32 data_hi; int args_num = 4; if (args_num != sscanf(params_string, "%i %i %i %i ", &port, &addr, &data_lo, &data_hi)) return DBG_STATUS_INVALID_ARGS; return qed_phy_core_write(p_hwfn, port, addr, data_lo, data_hi, p_phy_result_buf); } /*** wrapper for invoking qed_phy_core_read according to string parameter ***/ int qed_str_phy_core_read(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, char *params_string) { u32 port; u32 addr; int args_num = 2; if (args_num != sscanf(params_string, "%i %i ", &port, &addr)) return DBG_STATUS_INVALID_ARGS; return qed_phy_core_read(p_hwfn, port, addr, p_phy_result_buf); } /*** wrapper for invoking qed_phy_raw_write according to string parameter ***/ int qed_str_phy_raw_write(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, char *params_string) { u32 port; u32 lane; u32 addr; u32 data_lo; u32 data_hi; int args_num = 5; if (args_num != sscanf(params_string, "%i %i %i %i %i ", &port, &lane, &addr, &data_lo, &data_hi)) return DBG_STATUS_INVALID_ARGS; return qed_phy_raw_write(p_hwfn, port, lane, addr, data_lo, data_hi, p_phy_result_buf); } /*** wrapper for invoking qed_phy_raw_read according to string parameter ***/ int qed_str_phy_raw_read(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, char *params_string) { u32 port; u32 lane; u32 addr; int args_num = 3; if (args_num != sscanf(params_string, "%i %i %i ", &port, &lane, &addr)) return DBG_STATUS_INVALID_ARGS; return qed_phy_raw_read(p_hwfn, port, lane, addr, p_phy_result_buf); } /*** wrapper for invoking qed_phy_mac_stat according to string parameter ***/ int qed_str_phy_mac_stat(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, char *params_string) { u32 port; int args_num = 1; if (args_num != sscanf(params_string, "%i ", &port)) return DBG_STATUS_INVALID_ARGS; return qed_phy_mac_stat(p_hwfn, p_ptt, port, p_phy_result_buf); } /*** wrapper for invoking qed_phy_info according to string parameter ***/ int qed_str_phy_info(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, char *params_string) { return qed_phy_info(p_hwfn, p_ptt, p_phy_result_buf); } /*** wrapper for invoking qed_phy_sfp_write according to string parameter ***/ int qed_str_phy_sfp_write(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, char *params_string) { u32 port; u32 addr; u32 offset; u32 size; u32 val; int args_num = 5; if (args_num != sscanf(params_string, "%i %i %i %i %i ", &port, &addr, &offset, &size, &val)) return DBG_STATUS_INVALID_ARGS; return qed_phy_sfp_write(p_hwfn, p_ptt, port, addr, offset, size, val, p_phy_result_buf); } /*** wrapper for invoking qed_phy_sfp_read according to string parameter ***/ int qed_str_phy_sfp_read(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, char *params_string) { u32 port; u32 addr; u32 offset; u32 size; int args_num = 4; if (args_num != sscanf(params_string, "%i %i %i %i ", &port, &addr, &offset, &size)) return DBG_STATUS_INVALID_ARGS; return qed_phy_sfp_read(p_hwfn, p_ptt, port, addr, offset, size, p_phy_result_buf); } /*** wrapper for invoking qed_phy_sfp_decode according to string parameter ***/ int qed_str_phy_sfp_decode(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, char *params_string) { u32 port; int args_num = 1; if (args_num != sscanf(params_string, "%i ", &port)) return DBG_STATUS_INVALID_ARGS; return qed_phy_sfp_decode(p_hwfn, p_ptt, port, p_phy_result_buf); } /*** wrapper for invoking qed_phy_sfp_get_inserted according to string parameter ***/ int qed_str_phy_sfp_get_inserted(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, char *params_string) { u32 port; int args_num = 1; if (args_num != sscanf(params_string, "%i ", &port)) return DBG_STATUS_INVALID_ARGS; return qed_phy_sfp_get_inserted(p_hwfn, p_ptt, port, p_phy_result_buf); } /*** wrapper for invoking qed_phy_sfp_get_txdisable according to string parameter ***/ int qed_str_phy_sfp_get_txdisable(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, char *params_string) { u32 port; int args_num = 1; if (args_num != sscanf(params_string, "%i ", &port)) return DBG_STATUS_INVALID_ARGS; return qed_phy_sfp_get_txdisable(p_hwfn, p_ptt, port, p_phy_result_buf); } /*** wrapper for invoking qed_phy_sfp_set_txdisable according to string parameter ***/ int qed_str_phy_sfp_set_txdisable(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, char *params_string) { u32 port; u8 txdisable; int args_num = 2; if (args_num != sscanf(params_string, "%i %hhi ", &port, &txdisable)) return DBG_STATUS_INVALID_ARGS; return qed_phy_sfp_set_txdisable(p_hwfn, p_ptt, port, txdisable, p_phy_result_buf); } /*** wrapper for invoking qed_phy_sfp_get_txreset according to string parameter ***/ int qed_str_phy_sfp_get_txreset(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, char *params_string) { u32 port; int args_num = 1; if (args_num != sscanf(params_string, "%i ", &port)) return DBG_STATUS_INVALID_ARGS; return qed_phy_sfp_get_txreset(p_hwfn, p_ptt, port, p_phy_result_buf); } /*** wrapper for invoking qed_phy_sfp_get_rxlos according to string parameter ***/ int qed_str_phy_sfp_get_rxlos(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, char *params_string) { u32 port; int args_num = 1; if (args_num != sscanf(params_string, "%i ", &port)) return DBG_STATUS_INVALID_ARGS; return qed_phy_sfp_get_rxlos(p_hwfn, p_ptt, port, p_phy_result_buf); } /*** wrapper for invoking qed_phy_sfp_get_eeprom according to string parameter ***/ int qed_str_phy_sfp_get_eeprom(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, char *params_string) { u32 port; int args_num = 1; if (args_num != sscanf(params_string, "%i ", &port)) return DBG_STATUS_INVALID_ARGS; return qed_phy_sfp_get_eeprom(p_hwfn, p_ptt, port, p_phy_result_buf); } /*** wrapper for invoking qed_phy_gpio_write according to string parameter ***/ int qed_str_phy_gpio_write(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, char *params_string) { u16 gpio; u16 gpio_val; int args_num = 2; if (args_num != sscanf(params_string, "%hi %hi ", &gpio, &gpio_val)) return DBG_STATUS_INVALID_ARGS; return qed_phy_gpio_write(p_hwfn, p_ptt, gpio, gpio_val, p_phy_result_buf); } /*** wrapper for invoking qed_phy_gpio_read according to string parameter ***/ int qed_str_phy_gpio_read(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, char *params_string) { u16 gpio; int args_num = 1; if (args_num != sscanf(params_string, "%hi ", &gpio)) return DBG_STATUS_INVALID_ARGS; return qed_phy_gpio_read(p_hwfn, p_ptt, gpio, p_phy_result_buf); } /*** wrapper for invoking qed_phy_gpio_info according to string parameter ***/ int qed_str_phy_gpio_info(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, char *params_string) { u16 gpio; int args_num = 1; if (args_num != sscanf(params_string, "%hi ", &gpio)) return DBG_STATUS_INVALID_ARGS; return qed_phy_gpio_info(p_hwfn, p_ptt, gpio, p_phy_result_buf); } /*** wrapper for invoking qed_phy_extphy_read according to string parameter ***/ int qed_str_phy_extphy_read(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, char *params_string) { u16 port; u16 devad; u16 reg; int args_num = 3; if (args_num != sscanf(params_string, "%hi %hi %hi ", &port, &devad, ®)) return DBG_STATUS_INVALID_ARGS; return qed_phy_extphy_read(p_hwfn, p_ptt, port, devad, reg, p_phy_result_buf); } /*** wrapper for invoking qed_phy_extphy_write according to string parameter ***/ int qed_str_phy_extphy_write(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, char *params_string) { u16 port; u16 devad; u16 reg; u16 val; int args_num = 4; if (args_num != sscanf(params_string, "%hi %hi %hi %hi ", &port, &devad, ®, &val)) return DBG_STATUS_INVALID_ARGS; return qed_phy_extphy_write(p_hwfn, p_ptt, port, devad, reg, val, p_phy_result_buf); } /*** wrapper for invoking qed_engine according to string parameter ***/ int qed_str_engine(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, char *params_string) { u8 engine_for_debug; int args_num = 1; /* convert string to int */ if (args_num != sscanf(params_string, "%hhd", &engine_for_debug)) return DBG_STATUS_INVALID_ARGS; /* check if the input is valid */ if ((engine_for_debug != 0) && (engine_for_debug != 1)) { DP_NOTICE(p_hwfn->cdev, "error! input must be 0 or 1!\n"); return DBG_STATUS_INVALID_ARGS; } /* check if the engine that trying to set exists */ /* if trying to set engine 1 and there is one engine it's wrong */ if (engine_for_debug == p_hwfn->cdev->num_hwfns) { DP_NOTICE(p_hwfn->cdev, "error! you are trying to set engine that doesn't exist\n"); return DBG_STATUS_INVALID_ARGS; } /* change the debug bus engine */ p_hwfn->cdev->engine_for_debug = engine_for_debug; return DBG_STATUS_OK; } /************************ end of wrappers section *****************************/ 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); } int qed_dbg_phy(struct qed_dev *cdev, void *buffer, u32 * num_dumped_bytes) { struct qed_hwfn *p_hwfn = &cdev->hwfns[cdev->engine_for_debug]; struct qed_ptt *p_ptt; int i, num_ports, rc; DP_NOTICE(p_hwfn->cdev, "Collecting a debug feature [\"phy_dump\"]\n"); /* acquire ptt */ p_ptt = qed_ptt_acquire(p_hwfn); if (!p_ptt) return -EINVAL; /* get phy info */ rc = qed_phy_info(p_hwfn, p_ptt, buffer); if (!rc) { *num_dumped_bytes = strlen(buffer); /* run through all ports and get phy mac_stat */ num_ports = qed_device_num_ports(cdev); for (i = 0; i < num_ports; i++) { rc = qed_phy_mac_stat(p_hwfn, p_ptt, i, buffer + *num_dumped_bytes); if (rc) break; *num_dumped_bytes += strlen(buffer + *num_dumped_bytes); } } qed_ptt_release(p_hwfn, p_ptt); return rc; } int qed_dbg_phy_size(struct qed_dev *cdev) { /* return max size of phy info and * phy mac_stat multiplied by the number of ports */ return MAX_PHY_RESULT_BUFFER * (1 + qed_device_num_ports(cdev)); } 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_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) { #ifndef ASIC_ONLY if (CHIP_REV_IS_EMUL(cdev)) return 0; #endif return qed_dbg_feature_size(cdev, DBG_FEATURE_MCP_TRACE); } /* defines the amount of bytes allocated for recording the length of * debugfs feature buffer @@@TBD duplicate of qede.h */ #define REGDUMP_HEADER_SIZE sizeof(u32) #define REGDUMP_HEADER_FEATURE_SHIFT 24 #define REGDUMP_HEADER_ENGINE_SHIFT 31 #define REGDUMP_HEADER_OMIT_ENGINE_SHIFT 30 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, }; static u32 qed_calc_regdump_header(enum debug_print_features feature, int engine, u32 feature_size, u8 omit_engine) { /* insert the engine, feature and mode inside the header and combine it with feature size */ return (feature_size | (feature << REGDUMP_HEADER_FEATURE_SHIFT) | (omit_engine << REGDUMP_HEADER_OMIT_ENGINE_SHIFT) | (engine << REGDUMP_HEADER_ENGINE_SHIFT)); } static void qed_dbg_all_data_free_buf(struct qed_dev *cdev) { vfree(cdev->p_dbg_data_buf); cdev->p_dbg_data_buf = NULL; } int qed_dbg_all_data(struct qed_dev *cdev, void *buffer) { u8 cur_engine, omit_engine = 0, org_engine; u32 offset = 0, feature_size; int rc; /* Use a previously saved buffer if exists */ if (cdev->p_dbg_data_buf) { DP_NOTICE(cdev, "Using a debug data buffer that was previously obtained and saved\n"); memcpy(buffer, cdev->p_dbg_data_buf, cdev->dbg_data_buf_size); qed_dbg_all_data_free_buf(cdev); return 0; } if (!QED_IS_CMT(cdev)) omit_engine = 1; org_engine = qed_get_debug_engine(cdev); for (cur_engine = 0; cur_engine < cdev->num_hwfns; cur_engine++) { /* collect idle_chks and grcDump for each hw function */ DP_VERBOSE(cdev, QED_MSG_DEBUG, "obtaining idle_chk and grcdump for current engine\n"); qed_set_debug_engine(cdev, cur_engine); /* first idle_chk */ rc = qed_dbg_idle_chk(cdev, (u8 *) buffer + offset + REGDUMP_HEADER_SIZE, &feature_size); if (!rc) { *(u32 *) ((u8 *) buffer + offset) = qed_calc_regdump_header(IDLE_CHK, cur_engine, feature_size, omit_engine); offset += (feature_size + REGDUMP_HEADER_SIZE); } else { DP_ERR(cdev, "qed_dbg_idle_chk failed. rc = %d\n", rc); } /* second idle_chk */ rc = qed_dbg_idle_chk(cdev, (u8 *) buffer + offset + REGDUMP_HEADER_SIZE, &feature_size); if (!rc) { *(u32 *) ((u8 *) buffer + offset) = qed_calc_regdump_header(IDLE_CHK, cur_engine, feature_size, omit_engine); offset += (feature_size + REGDUMP_HEADER_SIZE); } else { DP_ERR(cdev, "qed_dbg_idle_chk failed. rc = %d\n", rc); } /* reg_fifo dump */ rc = qed_dbg_reg_fifo(cdev, (u8 *) buffer + offset + REGDUMP_HEADER_SIZE, &feature_size); if (!rc) { *(u32 *) ((u8 *) buffer + offset) = qed_calc_regdump_header(REG_FIFO, cur_engine, feature_size, omit_engine); offset += (feature_size + REGDUMP_HEADER_SIZE); } else { DP_ERR(cdev, "qed_dbg_reg_fifo failed. rc = %d\n", rc); } /* igu_fifo dump */ rc = qed_dbg_igu_fifo(cdev, (u8 *) buffer + offset + REGDUMP_HEADER_SIZE, &feature_size); if (!rc) { *(u32 *) ((u8 *) buffer + offset) = qed_calc_regdump_header(IGU_FIFO, cur_engine, feature_size, omit_engine); offset += (feature_size + REGDUMP_HEADER_SIZE); } else { DP_ERR(cdev, "qed_dbg_igu_fifo failed. rc = %d", rc); } /* protection_override dump */ rc = qed_dbg_protection_override(cdev, (u8 *) buffer + offset + REGDUMP_HEADER_SIZE, &feature_size); if (!rc) { *(u32 *) ((u8 *) buffer + offset) = qed_calc_regdump_header(PROTECTION_OVERRIDE, cur_engine, feature_size, omit_engine); offset += (feature_size + REGDUMP_HEADER_SIZE); } else { DP_ERR(cdev, "qed_dbg_protection_override failed. rc = %d\n", rc); } /* fw_asserts dump */ rc = qed_dbg_fw_asserts(cdev, (u8 *) buffer + offset + REGDUMP_HEADER_SIZE, &feature_size); if (!rc) { *(u32 *) ((u8 *) buffer + offset) = qed_calc_regdump_header(FW_ASSERTS, cur_engine, feature_size, omit_engine); offset += (feature_size + REGDUMP_HEADER_SIZE); } else { DP_ERR(cdev, "qed_dbg_fw_asserts failed. rc = %d\n", rc); } /* grc dump - must be last because when mcp stuck it will * clutter idle_chk, reg_fifo, ... */ rc = qed_dbg_grc(cdev, (u8 *) buffer + offset + REGDUMP_HEADER_SIZE, &feature_size); if (!rc) { *(u32 *) ((u8 *) buffer + offset) = qed_calc_regdump_header(GRC_DUMP, cur_engine, feature_size, omit_engine); offset += (feature_size + REGDUMP_HEADER_SIZE); } else { DP_ERR(cdev, "qed_dbg_grc failed. rc = %d", rc); } } qed_set_debug_engine(cdev, org_engine); /* phy dump */ rc = qed_dbg_phy(cdev, (u8 *) buffer + offset + REGDUMP_HEADER_SIZE, &feature_size); if (!rc) { *(u32 *) ((u8 *) buffer + offset) = qed_calc_regdump_header(PHY, cur_engine, feature_size, omit_engine); offset += (feature_size + REGDUMP_HEADER_SIZE); } else { DP_ERR(cdev, "qed_dbg_phy failed. rc = %d", rc); } /* mcp_trace */ rc = qed_dbg_mcp_trace(cdev, (u8 *) buffer + offset + REGDUMP_HEADER_SIZE, &feature_size); if (!rc) { *(u32 *) ((u8 *) buffer + offset) = qed_calc_regdump_header(MCP_TRACE, cur_engine, feature_size, omit_engine); offset += (feature_size + REGDUMP_HEADER_SIZE); } else { DP_ERR(cdev, "qed_dbg_mcp_trace failed. rc = %d\n", rc); } return 0; } int qed_dbg_all_data_size(struct qed_dev *cdev) { u8 cur_engine, org_engine; u32 regs_len = 0; /* Use a previously saved buffer size if exists */ if (cdev->p_dbg_data_buf) return cdev->dbg_data_buf_size; org_engine = qed_get_debug_engine(cdev); for (cur_engine = 0; cur_engine < cdev->num_hwfns; cur_engine++) { /* engine specific */ 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); } qed_set_debug_engine(cdev, org_engine); /* engine common */ regs_len += REGDUMP_HEADER_SIZE + qed_dbg_mcp_trace_size(cdev) + REGDUMP_HEADER_SIZE + qed_dbg_phy_size(cdev); return regs_len; } static struct file *qed_file_open(const char *filename, int flags, umode_t mode, long *err) { struct file *filp = NULL; mm_segment_t old_fs; old_fs = get_fs(); set_fs(get_ds()); filp = filp_open(filename, flags, mode); set_fs(old_fs); if (IS_ERR(filp)) { *err = PTR_ERR(filp); return NULL; } return filp; } static int qed_file_close(struct file *file) { return filp_close(file, NULL); } static ssize_t qed_file_write(struct file *file, const char *buf, size_t count, loff_t * pos) { #ifdef _HAS_KERNEL_WRITE_V2 /* QED_UPSTREAM */ return kernel_write(file, buf, count, pos); #else mm_segment_t old_fs; ssize_t res; old_fs = get_fs(); set_fs(get_ds()); /* The cast to a user pointer is valid due to the set_fs() */ res = vfs_write(file, (__force const char __user *)buf, count, pos); set_fs(old_fs); return res; #endif } static int qed_file_sync(struct file *file) { #ifdef _HAS_VFS_FSYNC_V2 /* QED_UPSTREAM */ return vfs_fsync(file, 0); #else return vfs_fsync(file, file->f_path.dentry, 0); #endif } static int qed_dbg_save_to_file(struct qed_dev *cdev) { size_t size = strlen(cdev->dbg_data_path); int rc = 0, fclose_rc = 0; struct file *filp = NULL; struct timespec now; struct tm tm_val; ssize_t ret = 0; loff_t pos = 0; long err = 0; getnstimeofday(&now); time_to_tm(now.tv_sec, 0, &tm_val); snprintf(cdev->dbg_data_path + size, QED_DBG_DATA_FILE_NAME_SIZE, "/qed_dump_%02d-%02d-%02ld_%02d-%02d-%02d.bin", tm_val.tm_mon + 1, (int)tm_val.tm_mday, 1900 + tm_val.tm_year, tm_val.tm_hour, tm_val.tm_min, tm_val.tm_sec); filp = qed_file_open(cdev->dbg_data_path, O_RDWR | O_CREAT, 0600, &err); if (!filp) { DP_NOTICE(cdev, "Failed to open \"%s\" for saving debug data [err %ld]\n", cdev->dbg_data_path, err); return -EFAULT; } ret = qed_file_write(filp, cdev->p_dbg_data_buf, cdev->dbg_data_buf_size, &pos); if (ret < 0) { DP_NOTICE(cdev, "Failed to write debug data to \"%s\"\n", cdev->dbg_data_path); rc = (int)ret; goto out; } if (pos != cdev->dbg_data_buf_size) { DP_NOTICE(cdev, "Failed to write all debug data to \"%s\" [written %lld, dbg_data_buf_size %d]\n", cdev->dbg_data_path, pos, cdev->dbg_data_buf_size); rc = -EAGAIN; goto out; } rc = qed_file_sync(filp); if (rc) DP_NOTICE(cdev, "Failed to write back data for \"%s\" to disk\n", cdev->dbg_data_path); out: fclose_rc = qed_file_close(filp); if (fclose_rc) { DP_NOTICE(cdev, "Failed to close \"%s\"\n", cdev->dbg_data_path); /* The code of the first error should be returned */ rc = !rc ? fclose_rc : rc; } if (!rc) { DP_NOTICE(cdev, "Saved qed debug data at \"%s\"\n", cdev->dbg_data_path); qed_dbg_all_data_free_buf(cdev); } /* Remove the file name from the path */ cdev->dbg_data_path[size] = '\0'; return rc; } static void qed_dbg_send_uevent(struct qed_dev *cdev) { struct device *dev = &cdev->pdev->dev; char bdf[64]; char *envp_ext[] = { bdf, NULL }; int rc; snprintf(bdf, sizeof(bdf), "QED_DEBUGFS_BDF_DIR=%02x:%02x.%01x", cdev->pdev->bus->number, PCI_SLOT(cdev->pdev->devfn), PCI_FUNC(cdev->pdev->devfn)); rc = kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp_ext); if (rc) DP_NOTICE(cdev, "Failed to send a uevent\n"); } static int __qed_dbg_save_all_data(struct qed_dev *cdev) { u32 dbg_data_buf_size; u8 *p_dbg_data_buf; int rc; dbg_data_buf_size = qed_dbg_all_data_size(cdev); p_dbg_data_buf = vzalloc(dbg_data_buf_size); if (!p_dbg_data_buf) { DP_NOTICE(cdev, "Failed to allocate memory for a debug data buffer\n"); return -ENOMEM; } rc = qed_dbg_all_data(cdev, p_dbg_data_buf); if (rc) { DP_NOTICE(cdev, "Failed to obtain debug data\n"); vfree(p_dbg_data_buf); return rc; } cdev->p_dbg_data_buf = p_dbg_data_buf; cdev->dbg_data_buf_size = dbg_data_buf_size; return 0; } void qed_dbg_save_all_data(struct qed_dev *cdev, bool print_dbg_data) { bool curr_print_flag = cdev->print_dbg_data; int rc; qed_dbg_all_data_free_buf(cdev); cdev->print_dbg_data = print_dbg_data; rc = __qed_dbg_save_all_data(cdev); if (rc) goto out; /* The udev mechanism is not needed if directly saving to file */ if (cdev->b_dump_dbg_data) rc = qed_dbg_save_to_file(cdev); else if (dbg_send_uevent) qed_dbg_send_uevent(cdev); out: cdev->print_dbg_data = curr_print_flag; } int qed_dbg_feature(struct qed_dev *cdev, void *buffer, enum qed_dbg_features feature, u32 * num_dumped_bytes) { struct qed_ptt *p_ptt; enum dbg_status dbg_rc; int rc = 0; struct qed_hwfn *p_hwfn = &cdev->hwfns[cdev->engine_for_debug]; struct qed_dbg_feature *qed_feature = &cdev->dbg_features[feature]; /* acquire ptt */ p_ptt = qed_ptt_acquire(p_hwfn); if (!p_ptt) return -EINVAL; /* get dump */ 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; } /* function for external module to obtain feature dump size */ int qed_dbg_feature_size(struct qed_dev *cdev, enum qed_dbg_features feature) { struct qed_hwfn *p_hwfn = &cdev->hwfns[cdev->engine_for_debug]; struct qed_dbg_feature *qed_feature = &cdev->dbg_features[feature]; 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; qed_ptt_release(p_hwfn, p_ptt); qed_feature->buf_size = buf_size_dwords * sizeof(u32); return qed_feature->buf_size; } static ssize_t qed_dbg_cmd_read_inner(struct file *filp, char __user * buffer, size_t count, loff_t * ppos, u8 * dump_buf, int dumped_bytes) { int bytes_not_copied, len; /*pr_info("qed_dbg_cmd_read called. qed_dumped_bytes %d, *ppos %d\n", dumped_bytes, (u32)*ppos); */ /* if there is nothing further to dump, no point to continue */ if (*ppos == dumped_bytes) return 0; /* data availability sanity */ if (*ppos > dumped_bytes || !dumped_bytes || !dump_buf) { pr_err("no data in dump buffer\n"); return 0; } len = min_t(int, count, dumped_bytes - *ppos); /* copy dump data to the user */ bytes_not_copied = copy_to_user(buffer, &dump_buf[*ppos], len); if (bytes_not_copied < 0) { pr_err("failed to copy all bytes: bytes_not_copied %d\n", bytes_not_copied); return bytes_not_copied; } *ppos += len; return len; } /* Generic function for supplying debug data of a feature to the user */ static ssize_t qed_dbg_cmd_read(struct file *filp, char __user * buffer, size_t count, loff_t * ppos, enum qed_dbg_features feature_idx) { struct qed_dbg_feature *feature; struct qed_dev *cdev; int dumped_bytes; cdev = (struct qed_dev *)filp->private_data; feature = &cdev->dbg_features[feature_idx]; dumped_bytes = feature->dumped_dwords * sizeof(u32); return qed_dbg_cmd_read_inner(filp, buffer, count, ppos, (void *)feature->dump_buf, dumped_bytes); } /* qed_dbg_cmd_write - write into cmd datum */ static ssize_t qed_dbg_cmd_write(struct file *filp, const char __user * buffer, size_t count, loff_t * ppos, const struct qed_func_lookup *lookup, int num_funcs, bool from_user, bool is_hsi, bool is_tests) { struct qed_dev *cdev = (struct qed_dev *)filp->private_data; struct qed_hwfn *p_hwfn = &cdev->hwfns[cdev->engine_for_debug]; struct qed_ptt *p_ptt = qed_ptt_acquire(p_hwfn); int bytes_not_copied, func_idx; enum dbg_status rc = 100; char *cmd_buf; u8 cmd_len; if (!p_ptt) return 0; DP_VERBOSE(cdev, QED_MSG_DEBUG, "qed_dbg_cmd_write called: count %zu\n", count); /* don't allow partial writes */ if (*ppos != 0) { qed_ptt_release(p_hwfn, p_ptt); return 0; } /* prep command buffer */ if (!from_user) /* +1 to include the \n */ cmd_len = strchr(buffer, '\n') - buffer + 1; else /* strnlen_user() includes the null terminator */ cmd_len = strnlen_user(buffer, MAX_ARG_STRLEN) - 1; cmd_buf = kzalloc(cmd_len, GFP_KERNEL); if (!cmd_buf) { qed_ptt_release(p_hwfn, p_ptt); return count; } if (!from_user) { memcpy(cmd_buf, buffer, cmd_len); } else { /* copy user data to command buffer and perform sanity */ bytes_not_copied = copy_from_user(cmd_buf, buffer, cmd_len); if (bytes_not_copied < 0) { kfree(cmd_buf); qed_ptt_release(p_hwfn, p_ptt); return bytes_not_copied; } if (bytes_not_copied > 0) return count; /* Fix cmd_len to be the size of the string till the first * occurrence of \n (inclusively), since a multiple-line input * should be processed line by line. */ cmd_len = strchr(cmd_buf, '\n') - cmd_buf + 1; } /* Replace the closing \n character with a null terminator */ cmd_buf[cmd_len - 1] = '\0'; /* scan lookup table keys for a match to command buffer first arg */ for (func_idx = 0; func_idx < num_funcs; func_idx++) { int keylen = strlen(lookup[func_idx].key); /* use strncmp rather than strcmp since we only want to find a * matching prefix, not the entire string. */ if (strncmp(lookup[func_idx].key, cmd_buf, keylen) == 0) { DP_VERBOSE(cdev, QED_MSG_DEBUG, "matched %s to cmd_buf %s\n", lookup[func_idx].key, cmd_buf); rc = (lookup[func_idx].str_func) (p_hwfn, p_ptt, cmd_buf + keylen); break; } } /* if command string was not found in the lookup table then log error and do nothing */ if (func_idx == num_funcs) DP_NOTICE(cdev, "unknown command: %s\n", cmd_buf); /* for hsi function, test result code and print status if error */ if (is_hsi && rc != DBG_STATUS_OK) DP_NOTICE(cdev, "hsi func returned status %s\n", qed_dbg_get_status_str(rc)); /* for test function, store result */ if (!is_hsi) { memset(cdev->test_result, 0, sizeof(cdev->test_result)); snprintf(cdev->test_result, QED_TEST_RESULT_LENGTH, "%d\n", rc); cdev->test_result_available = true; } kfree(cmd_buf); cmd_buf = NULL; qed_ptt_release(p_hwfn, p_ptt); return cmd_len; } /********************** file operations section *******************************/ /* read file op for the bus feature */ static ssize_t qed_dbg_bus_cmd_read(struct file *filp, char __user * buffer, size_t count, loff_t * ppos) { return qed_dbg_cmd_read(filp, buffer, count, ppos, DBG_FEATURE_BUS); } /* write file op for the bus feature */ static ssize_t qed_dbg_bus_cmd_write(struct file *filp, const char __user * buffer, size_t count, loff_t * ppos) { return qed_dbg_cmd_write(filp, buffer, count, ppos, qed_features_lookup[DBG_FEATURE_BUS]. hsi_func_lookup, qed_features_lookup[DBG_FEATURE_BUS].num_funcs, true /* from user */ , true /* hsi function */ , false /* not tests function */ ); } /* read file op for the grc feature */ static ssize_t qed_dbg_grc_cmd_read(struct file *filp, char __user * buffer, size_t count, loff_t * ppos) { return qed_dbg_cmd_read(filp, buffer, count, ppos, DBG_FEATURE_GRC); } /* write file op for the grc feature */ static ssize_t qed_dbg_grc_cmd_write(struct file *filp, const char __user * buffer, size_t count, loff_t * ppos) { return qed_dbg_cmd_write(filp, buffer, count, ppos, qed_features_lookup[DBG_FEATURE_GRC]. hsi_func_lookup, qed_features_lookup[DBG_FEATURE_GRC].num_funcs, true /* from user */ , true /* hsi function */ , false /* not tests function */ ); } /* read file op for the idle_chk feature */ static ssize_t qed_dbg_idle_chk_cmd_read(struct file *filp, char __user * buffer, size_t count, loff_t * ppos) { return qed_dbg_cmd_read(filp, buffer, count, ppos, DBG_FEATURE_IDLE_CHK); } /* write file op for the idle_chk feature */ static ssize_t qed_dbg_idle_chk_cmd_write(struct file *filp, const char __user * buffer, size_t count, loff_t * ppos) { return qed_dbg_cmd_write(filp, buffer, count, ppos, qed_features_lookup[DBG_FEATURE_IDLE_CHK]. hsi_func_lookup, qed_features_lookup[DBG_FEATURE_IDLE_CHK]. num_funcs, true /* from user */ , true /* hsi function */ , false /* not tests function */ ); } /* read file op for the mcp_trace feature */ static ssize_t qed_dbg_mcp_trace_cmd_read(struct file *filp, char __user * buffer, size_t count, loff_t * ppos) { return qed_dbg_cmd_read(filp, buffer, count, ppos, DBG_FEATURE_MCP_TRACE); } /* write file op for the mcp_trace feature */ static ssize_t qed_dbg_mcp_trace_cmd_write(struct file *filp, const char __user * buffer, size_t count, loff_t * ppos) { return qed_dbg_cmd_write(filp, buffer, count, ppos, qed_features_lookup[DBG_FEATURE_MCP_TRACE]. hsi_func_lookup, qed_features_lookup[DBG_FEATURE_MCP_TRACE]. num_funcs, true /* from user */ , true /* hsi function */ , false /* not tests function */ ); } /* read file op for the reg_fifo feature */ static ssize_t qed_dbg_reg_fifo_cmd_read(struct file *filp, char __user * buffer, size_t count, loff_t * ppos) { return qed_dbg_cmd_read(filp, buffer, count, ppos, DBG_FEATURE_REG_FIFO); } /* write file op for the reg_fifo feature */ static ssize_t qed_dbg_reg_fifo_cmd_write(struct file *filp, const char __user * buffer, size_t count, loff_t * ppos) { return qed_dbg_cmd_write(filp, buffer, count, ppos, qed_features_lookup[DBG_FEATURE_REG_FIFO]. hsi_func_lookup, qed_features_lookup[DBG_FEATURE_REG_FIFO]. num_funcs, true /* from user */ , true /* hsi function */ , false /* not tests function */ ); } /* read file op for the igu_fifo feature */ static ssize_t qed_dbg_igu_fifo_cmd_read(struct file *filp, char __user * buffer, size_t count, loff_t * ppos) { return qed_dbg_cmd_read(filp, buffer, count, ppos, DBG_FEATURE_IGU_FIFO); } /* write file op for the igu_fifo feature */ static ssize_t qed_dbg_igu_fifo_cmd_write(struct file *filp, const char __user * buffer, size_t count, loff_t * ppos) { return qed_dbg_cmd_write(filp, buffer, count, ppos, qed_features_lookup[DBG_FEATURE_IGU_FIFO]. hsi_func_lookup, qed_features_lookup[DBG_FEATURE_IGU_FIFO]. num_funcs, true /* from user */ , true /* hsi function */ , false /* not tests function */ ); } /* read file op for the protection_override feature */ static ssize_t qed_dbg_protection_override_cmd_read(struct file *filp, char __user * buffer, size_t count, loff_t * ppos) { return qed_dbg_cmd_read(filp, buffer, count, ppos, DBG_FEATURE_PROTECTION_OVERRIDE); } /* write file op for the protection_override feature */ static ssize_t qed_dbg_protection_override_cmd_write(struct file *filp, const char __user * buffer, size_t count, loff_t * ppos) { return qed_dbg_cmd_write(filp, buffer, count, ppos, qed_features_lookup [DBG_FEATURE_PROTECTION_OVERRIDE]. hsi_func_lookup, qed_features_lookup [DBG_FEATURE_PROTECTION_OVERRIDE].num_funcs, true /* from user */ , true /* hsi function */ , false /* not tests function */ ); } /* read file op for the fw_asserts feature */ static ssize_t qed_dbg_fw_asserts_cmd_read(struct file *filp, char __user * buffer, size_t count, loff_t * ppos) { return qed_dbg_cmd_read(filp, buffer, count, ppos, DBG_FEATURE_FW_ASSERTS); } /* write file op for the fw_asserts feature */ static ssize_t qed_dbg_fw_asserts_cmd_write(struct file *filp, const char __user * buffer, size_t count, loff_t * ppos) { return qed_dbg_cmd_write(filp, buffer, count, ppos, qed_features_lookup[DBG_FEATURE_FW_ASSERTS]. hsi_func_lookup, qed_features_lookup[DBG_FEATURE_FW_ASSERTS]. num_funcs, true /* from user */ , true /* hsi function */ , false /* not tests function */ ); } /*** prepare file operations structures for debug features ***/ #define qed_debugfs_fileops(feature) \ { \ .owner = THIS_MODULE, \ .open = simple_open, \ .read = qed_dbg_##feature##_cmd_read, \ .write = qed_dbg_##feature##_cmd_write \ } static const struct file_operations qed_feature_fops[DBG_FEATURE_NUM] = { qed_debugfs_fileops(bus), qed_debugfs_fileops(grc), qed_debugfs_fileops(idle_chk), qed_debugfs_fileops(mcp_trace), qed_debugfs_fileops(reg_fifo), qed_debugfs_fileops(igu_fifo), qed_debugfs_fileops(protection_override), qed_debugfs_fileops(fw_asserts), }; /********************** end of file opreation section *************************/ /* list element that contains the preconfig commands for the debug bus */ struct preconfig_struct { struct list_head list_entry; char *buffer; size_t count; loff_t *ppos; }; /* pool of the preconfig struct that holds the preconfig list */ struct preconfig_struct_pool { struct list_head preconfig_list; } preconfig_pool; u8 preconfig_engine = 0; 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; } /* frees preconfig list */ void free_preconfig(void) { struct preconfig_struct tmp_preconfig; struct preconfig_struct *p_preconfig; struct preconfig_struct *tmp; p_preconfig = &tmp_preconfig; /* free all list elements in preconfig pool */ list_for_each_entry_safe(p_preconfig, tmp, &preconfig_pool.preconfig_list, list_entry) { kfree(p_preconfig->buffer); list_del(&p_preconfig->list_entry); kfree(p_preconfig); } } /* free post config info */ void free_postconfig(void) { kfree(postconfig_buf); postconfig_bytes = 0; } /* allocate new preconfig list element * copy __user buffer into the buffer in the new element */ static ssize_t qed_dbg_preconfig_cmd_write(struct file *filp, const char __user * buffer, size_t count, loff_t * ppos) { /* prepare list element */ struct preconfig_struct *p_preconfig = kmalloc(sizeof(*p_preconfig), GFP_KERNEL); int bytes_not_copied; u8 preconfig_len; if (!p_preconfig) { pr_notice("allocating p_preconfig failed\n"); goto err0; } /* strnlen_user() includes the null terminator */ preconfig_len = strnlen_user(buffer, MAX_ARG_STRLEN) - 1; /* allocate buffer for command string */ p_preconfig->buffer = kzalloc(preconfig_len, GFP_KERNEL); if (!p_preconfig->buffer) { pr_notice("allocating p_preconfig->buffer failed\n"); goto err1; } /* populate list element */ bytes_not_copied = copy_from_user(p_preconfig->buffer, buffer, preconfig_len); if (bytes_not_copied != 0) { pr_notice("copy from user failed\n"); goto err2; } /* Fix preconfig_len to be the size of the string till the first * occurrence of \n (inclusively), since a multiple-line input should be * processed line by line. */ preconfig_len = strchr(p_preconfig->buffer, '\n') - p_preconfig->buffer + 1; p_preconfig->count = preconfig_len; p_preconfig->ppos = ppos; /* add element to list */ list_add_tail(&p_preconfig->list_entry, &preconfig_pool.preconfig_list); return preconfig_len; err2: kfree(p_preconfig->buffer); err1: kfree(p_preconfig); err0: pr_notice ("due to the error that occurred debugbus preconfig will not work\n"); return count; } /* prints the buffer from preconfig list */ static ssize_t qed_dbg_preconfig_cmd_read(struct file *filp, char __user * buffer, size_t count, loff_t * ppos) { struct preconfig_struct tmp_preconfig; struct preconfig_struct *p_preconfig; struct preconfig_struct *tmp; int traversed_bytes = 0; int bytes_not_copied; int bytes_copied; size_t len = 0; p_preconfig = &tmp_preconfig; /* traverses the preconfig list elements and prints the buffers */ list_for_each_entry_safe(p_preconfig, tmp, &(preconfig_pool.preconfig_list), list_entry) { /* does this element contain new bytes? */ if (traversed_bytes + p_preconfig->count > *ppos) { int local_ppos = *ppos - traversed_bytes; len = p_preconfig->count - local_ppos; bytes_not_copied = copy_to_user(buffer, &p_preconfig->buffer[local_ppos], len); if (bytes_not_copied) pr_notice ("failed to copy all bytes, bytes not copied: %d\n", bytes_not_copied); bytes_copied = len - bytes_not_copied; *ppos += bytes_copied; return bytes_copied; } traversed_bytes += p_preconfig->count; } return 0; } static ssize_t qed_dbg_preconfig_engine_cmd_write(struct file *filp, const char __user * buffer, size_t count, loff_t * ppos) { int bytes_not_copied; char *cmd_buf; u8 cmd_len, tmp; /* don't allow partial writes */ if (*ppos != 0) return 0; /* strnlen_user() includes the null terminator */ cmd_len = strnlen_user(buffer, MAX_ARG_STRLEN) - 1; /* allocate buffer for command string */ cmd_buf = kzalloc(cmd_len, GFP_KERNEL); if (!cmd_buf) return count; /* copy user data to command buffer and perform sanity */ bytes_not_copied = copy_from_user(cmd_buf, buffer, cmd_len); if (bytes_not_copied < 0) { kfree(cmd_buf); return bytes_not_copied; } if (bytes_not_copied > 0) { kfree(cmd_buf); return count; } /* Fix cmd_len to be the size of the string till the first occurrence of * \n (inclusively). */ cmd_len = strchr(cmd_buf, '\n') - cmd_buf + 1; /* Replace the closing \n character with a null terminator */ cmd_buf[cmd_len - 1] = '\0'; /* scan user input into preconfig engine */ sscanf(cmd_buf, "%hhi", &tmp); /* sanitize */ if (tmp > 1) pr_err("illegal value for preconfig engine %d\n", tmp); else preconfig_engine = tmp; kfree(cmd_buf); cmd_buf = NULL; return cmd_len; } static ssize_t qed_dbg_char_cmd_read(char __user * buffer, size_t count, loff_t * ppos, char *source) { int bytes_not_copied, len; char data[3]; snprintf(data, sizeof(char) + 2, "%hhd\n", *source); /* +2 for /n and /0 */ len = sizeof(data); /* avoid reading beyond available data */ len = min_t(int, count, len - *ppos); /* copy data to the user */ bytes_not_copied = copy_to_user(buffer, data + *ppos, len); /* notify user of problems */ if (bytes_not_copied < 0) { pr_err("failed to copy all bytes: bytes_not_copied %d\n", bytes_not_copied); return bytes_not_copied; } *ppos += len; return len; } static ssize_t qed_dbg_preconfig_engine_cmd_read(struct file *filp, char __user * buffer, size_t count, loff_t * ppos) { return qed_dbg_char_cmd_read(buffer, count, ppos, &preconfig_engine); } /* curently no functionality for writing into the postconfig node */ static ssize_t qed_dbg_postconfig_cmd_write(struct file *filp, const char __user * buffer, size_t count, loff_t * ppos) { return 0; } static ssize_t qed_dbg_postconfig_cmd_read(struct file *filp, char __user * buffer, size_t count, loff_t * ppos) { return qed_dbg_cmd_read_inner(filp, buffer, count, ppos, postconfig_buf, postconfig_bytes); } static void qed_chain_info_init(struct qed_dev *cdev, int start_index, bool print_metadata) { cdev->chain_info.current_index = start_index; cdev->chain_info.b_key_entered = true; cdev->chain_info.print_metadata = print_metadata; cdev->chain_info.final_index = cdev->chain_info.chain->capacity; } static ssize_t qed_dbg_chain_print_cmd_write(struct file *filp, const char __user * buffer, size_t count, loff_t * ppos) { struct qed_dev *cdev = (struct qed_dev *)filp->private_data; struct qed_hwfn *p_hwfn = &cdev->hwfns[cdev->engine_for_debug]; char *buf; int len; buf = kmalloc(count + 1, GFP_ATOMIC); /* +1 for '\0' */ if (!buf) { pr_notice("allocating buffer failed\n"); goto error; } len = simple_write_to_buffer(buf, count, ppos, buffer, count); if (len < 0) { pr_notice("copy from user failed\n"); goto error; } buf[len] = '\0'; if (!strncmp(buf, "eq", 2)) { cdev->chain_info.chain = &p_hwfn->p_eq->chain; qed_chain_info_init(cdev, 0, true); } if (!strncmp(buf, "spq", 3)) { cdev->chain_info.chain = &p_hwfn->p_spq->chain; qed_chain_info_init(cdev, 0, true); } kfree(buf); return len; error: kfree(buf); pr_notice("due to the error that occurred chain print will not work\n"); return count; } /* EXAMPLE FOR USING YOUR OWN ELEMENT AND METADATA PRINT FUNCTIONS */ int qed_chain_print_element(struct qed_chain *p_chain, void *p_element, char *buffer) { /* this will be a service function for the per chain print element function */ int pos = 0, length, elem_size = p_chain->elem_size; /* print element byte by byte */ while (elem_size > 0) { length = sprintf(buffer + pos, " %02x", *(u8 *) p_element); if (length < 0) { pr_notice("Failed to copy data to buffer\n"); return length; } pos += length; elem_size--; p_element++; } length = sprintf(buffer + pos, "\n"); if (length < 0) { pr_notice("Failed to copy data to buffer\n"); return length; } pos += length; return pos; } int qed_chain_print_metadata(struct qed_chain *p_chain, char *buffer) { int pos = 0, length; length = sprintf(buffer, "prod 0x%x [%03d], cons 0x%x [%03d]\n", qed_chain_get_prod_idx(p_chain), qed_chain_get_prod_idx(p_chain) & 0xff, qed_chain_get_cons_idx(p_chain), qed_chain_get_cons_idx(p_chain) & 0xff); if (length < 0) { pr_notice("Failed to copy Metadata to buffer\n"); return length; } pos += length; length = sprintf(buffer + pos, "Chain capacity: %d, Chain size: %d\n", p_chain->capacity, p_chain->size); if (length < 0) { pr_notice("Failed to copy Metadata to buffer\n"); return length; } pos += length; return pos; } /* END OF EXAMPLE */ #define CHAIN_PRINT_DONE 200 static ssize_t qed_dbg_chain_print_cmd_read(struct file *filp, char __user * buffer, size_t count, loff_t * ppos) { struct qed_dev *cdev = (struct qed_dev *)filp->private_data; int len = 0, rc = 0; char *buf; char key_list[] = "spq\neq\n"; /* check if the user entered a key, if not print the list of the keys */ if (!cdev->chain_info.b_key_entered) { len = simple_read_from_buffer(buffer, count, ppos, key_list, strlen(key_list)); } else { buf = kmalloc(sizeof(char) * count, GFP_KERNEL); if (!buf) { pr_notice("allocating buffer failed\n"); return 0; } /* example for calling chain print with function pointers */ rc = qed_chain_print(cdev->chain_info.chain, buf, count, &cdev->chain_info.current_index, cdev->chain_info.final_index, cdev->chain_info.print_metadata, qed_chain_print_element, qed_chain_print_metadata); /* example for calling chain print without function pointers */ /*rc = qed_chain_print(cdev->chain_info.chain, buf, count, &cdev->chain_info.current_index, cdev->chain_info.final_index, cdev->chain_info.print_metadata, NULL, NULL); */ if (rc < 0) { pr_notice("printing chain to buffer failed\n"); return 0; } len = simple_read_from_buffer(buffer, count, ppos, buf, strlen(buf)); cdev->chain_info.print_metadata = false; kfree(buf); if (rc == CHAIN_PRINT_DONE) *ppos -= len; else cdev->chain_info.b_key_entered = false; } return len; } /* copies the buffer from preconfig list to debug bus * occurs only if preconfig list exists * the function is called after device is brought out of reset */ void qed_copy_preconfig_to_bus(struct qed_dev *cdev, u8 init_engine) { struct preconfig_struct tmp_preconfig; struct preconfig_struct *p_preconfig; struct preconfig_struct *tmp; struct file filp; loff_t temp = 0; ssize_t len; /* copy to debug bus only if the engine being initialized matches the one indicated * in the preconfig command */ if (init_engine != preconfig_engine) return; else qed_set_debug_engine(cdev, preconfig_engine); filp.private_data = (void *)cdev; p_preconfig = &tmp_preconfig; if (!list_empty(&preconfig_pool.preconfig_list)) { /* traverses the preconfig list elements and the buffer to qed_dbg_cmd_write */ list_for_each_entry_safe(p_preconfig, tmp, &(preconfig_pool.preconfig_list), list_entry) { len = strlen(p_preconfig->buffer); qed_dbg_cmd_write(&filp, p_preconfig->buffer, len, &temp, qed_bus_hsi_func_lookup, BUS_NUM_STR_FUNCS, false /*not from user */ , false /*not an dbg hsi function */ , false /*not an tests function */ ); } free_preconfig(); } } /* postconfig buf is used to copy the data from a running debug bus recording * when driver is being removed, or probe flow fails, since the data will be * unattainable otherwise. */ int qed_copy_bus_to_postconfig(struct qed_dev *cdev, u8 down_engine) { int rc; /* check if there is an active recording in this PF */ if (!cdev->recording_active) return 0; /* check that the recording is for this engine */ if (down_engine != qed_get_debug_engine(cdev)) return 0; /* allocate the postconfig buffer acording to active recording size */ postconfig_bytes = qed_dbg_feature_size(cdev, DBG_FEATURE_BUS); if (postconfig_bytes < 0) return postconfig_bytes; postconfig_buf = kzalloc(postconfig_bytes, GFP_KERNEL); if (!postconfig_buf) { DP_ERR(cdev, "postconfig buf allocation failed\n"); postconfig_bytes = 0; return -ENOMEM; } /* copy recorded data to postconfig buffer */ rc = qed_dbg_feature(cdev, postconfig_buf, DBG_FEATURE_BUS, &postconfig_bytes); cdev->recording_active = false; return rc; } #ifndef QED_UPSTREAM /* ! QED_UPSTREAM */ static ssize_t qed_dbg_tests_cmd_write(struct file *filp, const char __user * buffer, size_t count, loff_t * ppos) { return qed_dbg_cmd_write(filp, buffer, count, ppos, qed_tests_func_lookup, TESTS_NUM_STR_FUNCS, true /* from user */ , false /* not an dbg hsi function */ , true /* tests function */ ); } #endif /* function services tests and phy read command */ static ssize_t qed_dbg_external_cmd_read(struct file *filp, char __user * buffer, size_t count, loff_t * ppos, char *data, int len) { struct qed_dev *cdev = (struct qed_dev *)filp->private_data; int bytes_not_copied; /* avoid reading beyond available data */ len = min_t(int, count, len - *ppos); /* copy data to the user */ bytes_not_copied = copy_to_user(buffer, data + *ppos, len); /* notify user of problems */ if (bytes_not_copied < 0) { DP_NOTICE(cdev, "failed to copy all bytes: bytes_not_copied %d\n", bytes_not_copied); return bytes_not_copied; } /* mark result as unavailable */ if (len == 0) cdev->test_result_available = false; *ppos += len; return len; } #ifndef QED_UPSTREAM /* ! QED_UPSTREAM */ static ssize_t qed_dbg_tests_cmd_read(struct file *filp, char __user * buffer, size_t count, loff_t * ppos) { struct qed_dev *cdev = (struct qed_dev *)filp->private_data; int len, return_len; char *data; /* if test result is available return it. Otherwise print out available tests */ if (cdev->test_result_available) { data = (char *)&cdev->test_result; len = sizeof(cdev->test_result); } else { data = (char *)tests_list; len = strlen(tests_list); } return_len = qed_dbg_external_cmd_read(filp, buffer, count, ppos, data, len); return return_len; } #endif static ssize_t qed_dbg_phy_cmd_write(struct file *filp, const char __user * buffer, size_t count, loff_t * ppos) { if (p_phy_result_buf == NULL) p_phy_result_buf = kzalloc(sizeof(char) * MAX_PHY_RESULT_BUFFER, GFP_KERNEL); return qed_dbg_cmd_write(filp, buffer, count, ppos, qed_phy_func_lookup, PHY_NUM_STR_FUNCS, true /* from user */ , false /* not a dbg hsi function */ , false /* not a tests function */ ); return 0; } /* prints the buffer from phy list */ static ssize_t qed_dbg_phy_cmd_read(struct file *filp, char __user * buffer, size_t count, loff_t * ppos) { int len, return_len; char *data; /* if test result is available return it. Otherwise print out available phy commands */ if (p_phy_result_buf != NULL) { data = p_phy_result_buf; len = strlen(p_phy_result_buf); } else { data = (char *)phy_list; len = strlen(phy_list); } return_len = qed_dbg_external_cmd_read(filp, buffer, count, ppos, data, len); if (return_len == 0) { kfree(p_phy_result_buf); p_phy_result_buf = NULL; } return return_len; } static ssize_t qed_dbg_engine_cmd_write(struct file *filp, const char __user * buffer, size_t count, loff_t * ppos) { return qed_dbg_cmd_write(filp, buffer, count, ppos, qed_engine_func_lookup, ENGINE_NUM_STR_FUNCS, true /* from user */ , true /* dbg hsi function */ , false /* not a tests function */ ); } static ssize_t qed_dbg_engine_cmd_read(struct file *filp, char __user * buffer, size_t count, loff_t * ppos) { struct qed_dev *cdev = (struct qed_dev *)filp->private_data; return qed_dbg_char_cmd_read(buffer, count, ppos, &cdev->engine_for_debug); } static void qed_dbg_mdump_free_buf(struct qed_dev *cdev) { kfree(cdev->dbg_mdump.buf); cdev->dbg_mdump.buf = NULL; cdev->dbg_mdump.buf_size = 0; } #define QED_DBG_MDUMP_STATUS_LENGTH 32 static int qed_dbg_mdump_get_status(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) { struct qed_dev *cdev = p_hwfn->cdev; struct qed_mdump_info mdump_info; int rc; qed_dbg_mdump_free_buf(cdev); cdev->dbg_mdump.buf = kzalloc(QED_DBG_MDUMP_STATUS_LENGTH, GFP_KERNEL); if (!cdev->dbg_mdump.buf) { DP_NOTICE(cdev, "Failed to allocate buffer\n"); return -ENOMEM; } rc = qed_mcp_mdump_get_info(p_hwfn, p_ptt, &mdump_info); if (rc) { qed_dbg_mdump_free_buf(cdev); return rc; } cdev->dbg_mdump.buf_size = QED_DBG_MDUMP_STATUS_LENGTH; snprintf(cdev->dbg_mdump.buf, QED_DBG_MDUMP_STATUS_LENGTH, "num_of_logs: %d\n", mdump_info.num_of_logs); return 0; } static int qed_dbg_mdump_get_image(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) { struct qed_dev *cdev = p_hwfn->cdev; struct qed_nvm_image_att image_att; u32 len_rounded, i; __be32 val; int rc; qed_dbg_mdump_free_buf(cdev); rc = qed_mcp_get_nvm_image_att(p_hwfn, p_ptt, QED_NVM_IMAGE_MDUMP, &image_att); if (rc) return rc; /* Rounding the image length up to sizeof(u32) saves the need to handle * residues when we call later to cpu_to_be32(). */ len_rounded = roundup(image_att.length, sizeof(u32)); cdev->dbg_mdump.buf = kzalloc(len_rounded, GFP_KERNEL); if (!cdev->dbg_mdump.buf) { DP_NOTICE(cdev, "Failed to allocate buffer\n"); return -ENOMEM; } rc = qed_mcp_get_nvm_image(p_hwfn, p_ptt, QED_NVM_IMAGE_MDUMP, cdev->dbg_mdump.buf, len_rounded); if (rc) { qed_dbg_mdump_free_buf(cdev); return rc; } /* The parsing tool expects the image to be in a big-endian foramt */ for (i = 0; i < len_rounded; i += 4) { val = cpu_to_be32(*(u32 *) & cdev->dbg_mdump.buf[i]); *(u32 *) & cdev->dbg_mdump.buf[i] = val; } cdev->dbg_mdump.buf_size = len_rounded; return 0; } #define QED_DBG_MDUMP_RETAIN_LENGTH 64 static int qed_dbg_mdump_get_retain(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) { struct qed_mdump_retain_data mdump_retain; struct qed_dev *cdev = p_hwfn->cdev; int rc; qed_dbg_mdump_free_buf(cdev); cdev->dbg_mdump.buf = kzalloc(QED_DBG_MDUMP_RETAIN_LENGTH, GFP_KERNEL); if (!cdev->dbg_mdump.buf) { DP_NOTICE(cdev, "Failed to allocate buffer\n"); return -ENOMEM; } rc = qed_mcp_mdump_get_retain(p_hwfn, p_ptt, &mdump_retain); if (rc) { qed_dbg_mdump_free_buf(cdev); return rc; } cdev->dbg_mdump.buf_size = QED_DBG_MDUMP_RETAIN_LENGTH; snprintf(cdev->dbg_mdump.buf, QED_DBG_MDUMP_RETAIN_LENGTH, "valid 0x%x, epoch 0x%08x, pf 0x%x, status 0x%08x\n", mdump_retain.valid, mdump_retain.epoch, mdump_retain.pf, mdump_retain.status); return 0; } static int qed_str_mdump_status(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, char *params_string) { int rc = qed_dbg_mdump_get_status(p_hwfn, p_ptt); if (!rc) p_hwfn->cdev->dbg_mdump.cmd = QED_DBG_MDUMP_CMD_STATUS; return rc; } static int qed_str_mdump_trigger(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, char *params_string) { int rc = qed_mcp_mdump_trigger(p_hwfn, p_ptt); if (!rc) p_hwfn->cdev->dbg_mdump.cmd = QED_DBG_MDUMP_CMD_TRIGGER; return rc; } static int qed_str_mdump_dump(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, char *params_string) { int rc = qed_dbg_mdump_get_image(p_hwfn, p_ptt); if (!rc) p_hwfn->cdev->dbg_mdump.cmd = QED_DBG_MDUMP_CMD_DUMP; return rc; } static int qed_str_mdump_clear(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, char *params_string) { int rc = qed_mcp_mdump_clear_logs(p_hwfn, p_ptt); if (!rc) p_hwfn->cdev->dbg_mdump.cmd = QED_DBG_MDUMP_CMD_CLEAR; return rc; } static int qed_str_mdump_get_retain(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, char *params_string) { int rc = qed_dbg_mdump_get_retain(p_hwfn, p_ptt); if (!rc) p_hwfn->cdev->dbg_mdump.cmd = QED_DBG_MDUMP_CMD_GET_RETAIN; return rc; } static int qed_str_mdump_clr_retain(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, char *params_string) { int rc = qed_mcp_mdump_clr_retain(p_hwfn, p_ptt); if (!rc) p_hwfn->cdev->dbg_mdump.cmd = QED_DBG_MDUMP_CMD_CLR_RETAIN; return rc; } const static struct qed_func_lookup qed_mdump_func_lookup[] = { {"status", qed_str_mdump_status}, {"trigger", qed_str_mdump_trigger}, {"dump", qed_str_mdump_dump}, {"clear", qed_str_mdump_clear}, {"get_retain", qed_str_mdump_get_retain}, {"clr_retain", qed_str_mdump_clr_retain}, }; static ssize_t qed_dbg_mdump_cmd_write(struct file *filp, const char __user * buffer, size_t count, loff_t * ppos) { struct qed_dev *cdev = (struct qed_dev *)filp->private_data; int num_funcs = sizeof(qed_mdump_func_lookup) / sizeof(qed_mdump_func_lookup[0]); cdev->dbg_mdump.cmd = QED_DBG_MDUMP_CMD_NONE; return qed_dbg_cmd_write(filp, buffer, count, ppos, qed_mdump_func_lookup, num_funcs, true, /* from user */ false, /* not a dbg hsi function */ false); /* not a tests function */ } static ssize_t qed_dbg_mdump_cmd_read(struct file *filp, char __user * buffer, size_t count, loff_t * ppos) { struct qed_dev *cdev = (struct qed_dev *)filp->private_data; char key_list[] = "status\ntrigger\ndump\nclear\nget_retain\nclr_retain\n"; int len = 0; switch (cdev->dbg_mdump.cmd) { case QED_DBG_MDUMP_CMD_NONE: /* If no key was given - print the list of the valid keys */ len = simple_read_from_buffer(buffer, count, ppos, key_list, strlen(key_list)); break; case QED_DBG_MDUMP_CMD_STATUS: case QED_DBG_MDUMP_CMD_DUMP: case QED_DBG_MDUMP_CMD_GET_RETAIN: len = simple_read_from_buffer(buffer, count, ppos, cdev->dbg_mdump.buf, cdev->dbg_mdump.buf_size); if (!len) { cdev->dbg_mdump.cmd = QED_DBG_MDUMP_CMD_NONE; qed_dbg_mdump_free_buf(cdev); } break; default: /* Do nothing for other mdump keys */ cdev->dbg_mdump.cmd = QED_DBG_MDUMP_CMD_NONE; break; } return len; } static int qed_str_all_data_dump(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, char *params_string) { struct qed_dev *cdev = p_hwfn->cdev; int rc; /* Use a previously saved buffer if exists */ if (cdev->p_dbg_data_buf) return 0; rc = __qed_dbg_save_all_data(cdev); return rc; } const static struct qed_func_lookup qed_all_data_func_lookup[] = { {"dump", qed_str_all_data_dump}, }; static ssize_t qed_dbg_all_data_cmd_write(struct file *filp, const char __user * buffer, size_t count, loff_t * ppos) { int num_funcs = sizeof(qed_all_data_func_lookup) / sizeof(qed_all_data_func_lookup[0]); return qed_dbg_cmd_write(filp, buffer, count, ppos, qed_all_data_func_lookup, num_funcs, true, /* from user */ false, /* not a dbg hsi function */ false); /* not a tests function */ } static ssize_t qed_dbg_all_data_cmd_read(struct file *filp, char __user * buffer, size_t count, loff_t * ppos) { struct qed_dev *cdev = (struct qed_dev *)filp->private_data; int len = 0; if (!cdev->p_dbg_data_buf) { DP_NOTICE(cdev, "No data in the debug data buffer\n"); return 0; } len = simple_read_from_buffer(buffer, count, ppos, cdev->p_dbg_data_buf, cdev->dbg_data_buf_size); if (!len) qed_dbg_all_data_free_buf(cdev); return len; } static const struct file_operations preconfig_fops = qed_debugfs_fileops(preconfig); static const struct file_operations preconfig_engine_fops = qed_debugfs_fileops(preconfig_engine); static const struct file_operations chain_print_fops = qed_debugfs_fileops(chain_print); static const struct file_operations postconfig_fops = qed_debugfs_fileops(postconfig); #ifndef QED_UPSTREAM /* ! QED_UPSTREAM */ static const struct file_operations tests_fops = qed_debugfs_fileops(tests); #endif /* ; */ static const struct file_operations engine_fops = qed_debugfs_fileops(engine); static const struct file_operations phy_fops = qed_debugfs_fileops(phy); static const struct file_operations mdump_fops = qed_debugfs_fileops(mdump); static const struct file_operations all_data_fops = qed_debugfs_fileops(all_data); /** * qed_dbg_pf_init - setup the debugfs file for the pf * @pf: the pf that is starting up **/ void qed_dbg_pf_init(struct qed_dev *cdev) { char pf_dirname[9]; /* e.g. 00:04:00 +1 null termination */ enum qed_dbg_features feature_idx; struct dentry *file_dentry = NULL; const u8 *dbg_values; size_t size; /* Sync ver with debugbus qed code */ qed_dbg_set_app_ver(TOOLS_VERSION); /* Debug values are after init values. * The offset is the first dword of the file. */ dbg_values = cdev->firmware->data + *(u32 *) cdev->firmware->data; qed_dbg_set_bin_ptr(dbg_values); qed_dbg_user_set_bin_ptr(dbg_values); /* Set the hwfn to be 0 as default */ cdev->engine_for_debug = 0; if (!qed_dbg_root) return; /* Create pf dir */ sprintf(pf_dirname, "%02x:%02x.%01x", cdev->pdev->bus->number, PCI_SLOT(cdev->pdev->devfn), PCI_FUNC(cdev->pdev->devfn)); cdev->bdf_dentry = debugfs_create_dir(pf_dirname, qed_dbg_root); if (!cdev->bdf_dentry) { pr_notice("debugfs entry %s creation failed\n", pf_dirname); return; } /* Create debug features debugfs files */ for (feature_idx = 0; feature_idx < DBG_FEATURE_NUM; feature_idx++) { const struct file_operations *fops; char *name; DP_VERBOSE(cdev, QED_MSG_DEBUG, "Creating debugfs node for %s\n", qed_features_lookup[feature_idx].name); name = qed_features_lookup[feature_idx].name; fops = &qed_feature_fops[feature_idx]; file_dentry = debugfs_create_file(name, 0600, cdev->bdf_dentry, cdev, fops); if (!file_dentry) DP_NOTICE(cdev, "debugfs entry %s creation failed\n", name); } #ifndef QED_UPSTREAM /* ! QED_UPSTREAM */ /* Create tests debugfs node */ DP_VERBOSE(cdev, QED_MSG_DEBUG, "Creating debugfs tests node\n"); file_dentry = debugfs_create_file("tests", 0600, cdev->bdf_dentry, cdev, &tests_fops); if (!file_dentry) DP_NOTICE(cdev, "debugfs tests entry creation failed\n"); #endif /* Create engine debugfs node */ DP_VERBOSE(cdev, QED_MSG_DEBUG, "creating debugfs engine node\n"); file_dentry = debugfs_create_file("engine", 0600, cdev->bdf_dentry, cdev, &engine_fops); if (!file_dentry) DP_NOTICE(cdev, "debugfs entry engine creation failed\n"); /* Create phy debugfs node */ DP_VERBOSE(cdev, QED_MSG_DEBUG, "creating debugfs PHY node\n"); file_dentry = debugfs_create_file("phy", 0600, cdev->bdf_dentry, cdev, &phy_fops); if (!file_dentry) DP_NOTICE(cdev, "debugfs entry PHY creation failed\n"); /* Create chain_print file under qed */ DP_VERBOSE(cdev, QED_MSG_DEBUG, "creating debugfs Chain Print node\n"); file_dentry = debugfs_create_file("chain_print", 0600, cdev->bdf_dentry, cdev, &chain_print_fops); if (!file_dentry) DP_NOTICE(cdev, "debugfs entry Chain Print creation failed\n"); /* Create mdump file under qed */ DP_VERBOSE(cdev, QED_MSG_DEBUG, "creating debugfs mdump node\n"); file_dentry = debugfs_create_file("mdump", 0600, cdev->bdf_dentry, cdev, &mdump_fops); if (!file_dentry) DP_NOTICE(cdev, "debugfs entry mdump creation failed\n"); /* Create all_data file under qed */ DP_VERBOSE(cdev, QED_MSG_DEBUG, "creating debugfs all_data node\n"); file_dentry = debugfs_create_file("all_data", 0600, cdev->bdf_dentry, cdev, &all_data_fops); if (!file_dentry) DP_NOTICE(cdev, "debugfs entry all_data creation failed\n"); /* Enable/disable the saving of auto-collected debug data to file */ size = strnlen(dbg_data_path, QED_DBG_DATA_PATH_MAX_SIZE); cdev->b_dump_dbg_data = ! !size; if (cdev->b_dump_dbg_data) strncpy(cdev->dbg_data_path, dbg_data_path, QED_DBG_DATA_PATH_MAX_SIZE); return; } /** * qed_dbg_pf_exit - clear out the pf's debugfs entries * @pf: the pf that is stopping **/ void qed_dbg_pf_exit(struct qed_dev *cdev) { struct qed_dbg_feature *feature = NULL; enum qed_dbg_features feature_idx; /* remove debugfs entries of this PF */ DP_VERBOSE(cdev, QED_MSG_DEBUG, "removing debugfs entry of PF %d\n", cdev->hwfns[0].abs_pf_id); debugfs_remove_recursive(cdev->bdf_dentry); cdev->bdf_dentry = NULL; /* debug features' buffers may be allocated if debug feature was used but dump wasn't called */ 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; } } /* The mdump buffer may be allocated if a command was writtetn w/o a * following read. */ qed_dbg_mdump_free_buf(cdev); /* free a previously saved buffer if exists */ vfree(cdev->p_dbg_data_buf); cdev->p_dbg_data_buf = NULL; } /** * qed_init - start up debugfs for the driver **/ void qed_dbg_init(void) { struct dentry *file_dentry = NULL; pr_notice("creating debugfs root node\n"); INIT_LIST_HEAD(&preconfig_pool.preconfig_list); /* Create qed dir in root of debugfs. NULL means debugfs root. */ qed_dbg_root = debugfs_create_dir("qed", NULL); if (!qed_dbg_root) { pr_notice("init of debugfs failed\n"); return; } /* Create preconfig file under qed */ file_dentry = debugfs_create_file("preconfig", 0600, qed_dbg_root, NULL, &preconfig_fops); if (!file_dentry) { pr_notice("debugfs entry preconfig creation failed\n"); free_preconfig(); } /* Create preconfig engine file under qed */ file_dentry = debugfs_create_file("preconfig_engine", 0600, qed_dbg_root, NULL, &preconfig_engine_fops); if (!file_dentry) pr_notice("debugfs entry preconfig engine creation failed\n"); /* Create postconfig file under qed */ file_dentry = debugfs_create_file("postconfig", 0600, qed_dbg_root, NULL, &postconfig_fops); if (!file_dentry) pr_notice("debugfs entry postconfig creation failed\n"); } /** * qed_dbg_exit - clean out the driver's debugfs entries **/ void qed_dbg_exit(void) { pr_notice("destroying debugfs root entry\n"); /* remove preconfig list */ free_preconfig(); /* free postconfig info */ free_postconfig(); /* remove qed dir in root of debugfs */ debugfs_remove_recursive(qed_dbg_root); qed_dbg_root = NULL; } #else /* CONFIG_DEBUG_FS */ void qed_dbg_pf_init(struct qed_dev *cdev) { } void qed_dbg_pf_exit(struct qed_dev *cdev) { } void qed_dbg_init(void) { } void qed_dbg_exit(void) { } void qed_copy_preconfig_to_bus(struct qed_dev *cdev, u8 init_engine) { } int qed_copy_bus_to_postconfig(struct qed_dev *cdev, u8 down_engine) { return 0; } u8 qed_get_debug_engine(struct qed_dev * cdev) { return 0; } #endif /* CONFIG_DEBUG_FS */