18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) 28c2ecf20Sopenharmony_ci/* QLogic qed NIC Driver 38c2ecf20Sopenharmony_ci * Copyright (c) 2015-2017 QLogic Corporation 48c2ecf20Sopenharmony_ci * Copyright (c) 2019-2020 Marvell International Ltd. 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include <linux/types.h> 88c2ecf20Sopenharmony_ci#include <asm/byteorder.h> 98c2ecf20Sopenharmony_ci#include <linux/delay.h> 108c2ecf20Sopenharmony_ci#include <linux/errno.h> 118c2ecf20Sopenharmony_ci#include <linux/kernel.h> 128c2ecf20Sopenharmony_ci#include <linux/slab.h> 138c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 148c2ecf20Sopenharmony_ci#include <linux/string.h> 158c2ecf20Sopenharmony_ci#include <linux/etherdevice.h> 168c2ecf20Sopenharmony_ci#include "qed.h" 178c2ecf20Sopenharmony_ci#include "qed_cxt.h" 188c2ecf20Sopenharmony_ci#include "qed_dcbx.h" 198c2ecf20Sopenharmony_ci#include "qed_hsi.h" 208c2ecf20Sopenharmony_ci#include "qed_hw.h" 218c2ecf20Sopenharmony_ci#include "qed_mcp.h" 228c2ecf20Sopenharmony_ci#include "qed_reg_addr.h" 238c2ecf20Sopenharmony_ci#include "qed_sriov.h" 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#define GRCBASE_MCP 0xe00000 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci#define QED_MCP_RESP_ITER_US 10 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci#define QED_DRV_MB_MAX_RETRIES (500 * 1000) /* Account for 5 sec */ 308c2ecf20Sopenharmony_ci#define QED_MCP_RESET_RETRIES (50 * 1000) /* Account for 500 msec */ 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci#define DRV_INNER_WR(_p_hwfn, _p_ptt, _ptr, _offset, _val) \ 338c2ecf20Sopenharmony_ci qed_wr(_p_hwfn, _p_ptt, (_p_hwfn->mcp_info->_ptr + _offset), \ 348c2ecf20Sopenharmony_ci _val) 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci#define DRV_INNER_RD(_p_hwfn, _p_ptt, _ptr, _offset) \ 378c2ecf20Sopenharmony_ci qed_rd(_p_hwfn, _p_ptt, (_p_hwfn->mcp_info->_ptr + _offset)) 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci#define DRV_MB_WR(_p_hwfn, _p_ptt, _field, _val) \ 408c2ecf20Sopenharmony_ci DRV_INNER_WR(p_hwfn, _p_ptt, drv_mb_addr, \ 418c2ecf20Sopenharmony_ci offsetof(struct public_drv_mb, _field), _val) 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci#define DRV_MB_RD(_p_hwfn, _p_ptt, _field) \ 448c2ecf20Sopenharmony_ci DRV_INNER_RD(_p_hwfn, _p_ptt, drv_mb_addr, \ 458c2ecf20Sopenharmony_ci offsetof(struct public_drv_mb, _field)) 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci#define PDA_COMP (((FW_MAJOR_VERSION) + (FW_MINOR_VERSION << 8)) << \ 488c2ecf20Sopenharmony_ci DRV_ID_PDA_COMP_VER_SHIFT) 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci#define MCP_BYTES_PER_MBIT_SHIFT 17 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_cibool qed_mcp_is_init(struct qed_hwfn *p_hwfn) 538c2ecf20Sopenharmony_ci{ 548c2ecf20Sopenharmony_ci if (!p_hwfn->mcp_info || !p_hwfn->mcp_info->public_base) 558c2ecf20Sopenharmony_ci return false; 568c2ecf20Sopenharmony_ci return true; 578c2ecf20Sopenharmony_ci} 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_civoid qed_mcp_cmd_port_init(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 608c2ecf20Sopenharmony_ci{ 618c2ecf20Sopenharmony_ci u32 addr = SECTION_OFFSIZE_ADDR(p_hwfn->mcp_info->public_base, 628c2ecf20Sopenharmony_ci PUBLIC_PORT); 638c2ecf20Sopenharmony_ci u32 mfw_mb_offsize = qed_rd(p_hwfn, p_ptt, addr); 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci p_hwfn->mcp_info->port_addr = SECTION_ADDR(mfw_mb_offsize, 668c2ecf20Sopenharmony_ci MFW_PORT(p_hwfn)); 678c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, QED_MSG_SP, 688c2ecf20Sopenharmony_ci "port_addr = 0x%x, port_id 0x%02x\n", 698c2ecf20Sopenharmony_ci p_hwfn->mcp_info->port_addr, MFW_PORT(p_hwfn)); 708c2ecf20Sopenharmony_ci} 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_civoid qed_mcp_read_mb(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 738c2ecf20Sopenharmony_ci{ 748c2ecf20Sopenharmony_ci u32 length = MFW_DRV_MSG_MAX_DWORDS(p_hwfn->mcp_info->mfw_mb_length); 758c2ecf20Sopenharmony_ci u32 tmp, i; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci if (!p_hwfn->mcp_info->public_base) 788c2ecf20Sopenharmony_ci return; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci for (i = 0; i < length; i++) { 818c2ecf20Sopenharmony_ci tmp = qed_rd(p_hwfn, p_ptt, 828c2ecf20Sopenharmony_ci p_hwfn->mcp_info->mfw_mb_addr + 838c2ecf20Sopenharmony_ci (i << 2) + sizeof(u32)); 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci /* The MB data is actually BE; Need to force it to cpu */ 868c2ecf20Sopenharmony_ci ((u32 *)p_hwfn->mcp_info->mfw_mb_cur)[i] = 878c2ecf20Sopenharmony_ci be32_to_cpu((__force __be32)tmp); 888c2ecf20Sopenharmony_ci } 898c2ecf20Sopenharmony_ci} 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_cistruct qed_mcp_cmd_elem { 928c2ecf20Sopenharmony_ci struct list_head list; 938c2ecf20Sopenharmony_ci struct qed_mcp_mb_params *p_mb_params; 948c2ecf20Sopenharmony_ci u16 expected_seq_num; 958c2ecf20Sopenharmony_ci bool b_is_completed; 968c2ecf20Sopenharmony_ci}; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci/* Must be called while cmd_lock is acquired */ 998c2ecf20Sopenharmony_cistatic struct qed_mcp_cmd_elem * 1008c2ecf20Sopenharmony_ciqed_mcp_cmd_add_elem(struct qed_hwfn *p_hwfn, 1018c2ecf20Sopenharmony_ci struct qed_mcp_mb_params *p_mb_params, 1028c2ecf20Sopenharmony_ci u16 expected_seq_num) 1038c2ecf20Sopenharmony_ci{ 1048c2ecf20Sopenharmony_ci struct qed_mcp_cmd_elem *p_cmd_elem = NULL; 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci p_cmd_elem = kzalloc(sizeof(*p_cmd_elem), GFP_ATOMIC); 1078c2ecf20Sopenharmony_ci if (!p_cmd_elem) 1088c2ecf20Sopenharmony_ci goto out; 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci p_cmd_elem->p_mb_params = p_mb_params; 1118c2ecf20Sopenharmony_ci p_cmd_elem->expected_seq_num = expected_seq_num; 1128c2ecf20Sopenharmony_ci list_add(&p_cmd_elem->list, &p_hwfn->mcp_info->cmd_list); 1138c2ecf20Sopenharmony_ciout: 1148c2ecf20Sopenharmony_ci return p_cmd_elem; 1158c2ecf20Sopenharmony_ci} 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci/* Must be called while cmd_lock is acquired */ 1188c2ecf20Sopenharmony_cistatic void qed_mcp_cmd_del_elem(struct qed_hwfn *p_hwfn, 1198c2ecf20Sopenharmony_ci struct qed_mcp_cmd_elem *p_cmd_elem) 1208c2ecf20Sopenharmony_ci{ 1218c2ecf20Sopenharmony_ci list_del(&p_cmd_elem->list); 1228c2ecf20Sopenharmony_ci kfree(p_cmd_elem); 1238c2ecf20Sopenharmony_ci} 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci/* Must be called while cmd_lock is acquired */ 1268c2ecf20Sopenharmony_cistatic struct qed_mcp_cmd_elem *qed_mcp_cmd_get_elem(struct qed_hwfn *p_hwfn, 1278c2ecf20Sopenharmony_ci u16 seq_num) 1288c2ecf20Sopenharmony_ci{ 1298c2ecf20Sopenharmony_ci struct qed_mcp_cmd_elem *p_cmd_elem = NULL; 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci list_for_each_entry(p_cmd_elem, &p_hwfn->mcp_info->cmd_list, list) { 1328c2ecf20Sopenharmony_ci if (p_cmd_elem->expected_seq_num == seq_num) 1338c2ecf20Sopenharmony_ci return p_cmd_elem; 1348c2ecf20Sopenharmony_ci } 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci return NULL; 1378c2ecf20Sopenharmony_ci} 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ciint qed_mcp_free(struct qed_hwfn *p_hwfn) 1408c2ecf20Sopenharmony_ci{ 1418c2ecf20Sopenharmony_ci if (p_hwfn->mcp_info) { 1428c2ecf20Sopenharmony_ci struct qed_mcp_cmd_elem *p_cmd_elem, *p_tmp; 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci kfree(p_hwfn->mcp_info->mfw_mb_cur); 1458c2ecf20Sopenharmony_ci kfree(p_hwfn->mcp_info->mfw_mb_shadow); 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci spin_lock_bh(&p_hwfn->mcp_info->cmd_lock); 1488c2ecf20Sopenharmony_ci list_for_each_entry_safe(p_cmd_elem, 1498c2ecf20Sopenharmony_ci p_tmp, 1508c2ecf20Sopenharmony_ci &p_hwfn->mcp_info->cmd_list, list) { 1518c2ecf20Sopenharmony_ci qed_mcp_cmd_del_elem(p_hwfn, p_cmd_elem); 1528c2ecf20Sopenharmony_ci } 1538c2ecf20Sopenharmony_ci spin_unlock_bh(&p_hwfn->mcp_info->cmd_lock); 1548c2ecf20Sopenharmony_ci } 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci kfree(p_hwfn->mcp_info); 1578c2ecf20Sopenharmony_ci p_hwfn->mcp_info = NULL; 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci return 0; 1608c2ecf20Sopenharmony_ci} 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci/* Maximum of 1 sec to wait for the SHMEM ready indication */ 1638c2ecf20Sopenharmony_ci#define QED_MCP_SHMEM_RDY_MAX_RETRIES 20 1648c2ecf20Sopenharmony_ci#define QED_MCP_SHMEM_RDY_ITER_MS 50 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_cistatic int qed_load_mcp_offsets(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 1678c2ecf20Sopenharmony_ci{ 1688c2ecf20Sopenharmony_ci struct qed_mcp_info *p_info = p_hwfn->mcp_info; 1698c2ecf20Sopenharmony_ci u8 cnt = QED_MCP_SHMEM_RDY_MAX_RETRIES; 1708c2ecf20Sopenharmony_ci u8 msec = QED_MCP_SHMEM_RDY_ITER_MS; 1718c2ecf20Sopenharmony_ci u32 drv_mb_offsize, mfw_mb_offsize; 1728c2ecf20Sopenharmony_ci u32 mcp_pf_id = MCP_PF_ID(p_hwfn); 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci p_info->public_base = qed_rd(p_hwfn, p_ptt, MISC_REG_SHARED_MEM_ADDR); 1758c2ecf20Sopenharmony_ci if (!p_info->public_base) { 1768c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, 1778c2ecf20Sopenharmony_ci "The address of the MCP scratch-pad is not configured\n"); 1788c2ecf20Sopenharmony_ci return -EINVAL; 1798c2ecf20Sopenharmony_ci } 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci p_info->public_base |= GRCBASE_MCP; 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci /* Get the MFW MB address and number of supported messages */ 1848c2ecf20Sopenharmony_ci mfw_mb_offsize = qed_rd(p_hwfn, p_ptt, 1858c2ecf20Sopenharmony_ci SECTION_OFFSIZE_ADDR(p_info->public_base, 1868c2ecf20Sopenharmony_ci PUBLIC_MFW_MB)); 1878c2ecf20Sopenharmony_ci p_info->mfw_mb_addr = SECTION_ADDR(mfw_mb_offsize, mcp_pf_id); 1888c2ecf20Sopenharmony_ci p_info->mfw_mb_length = (u16)qed_rd(p_hwfn, p_ptt, 1898c2ecf20Sopenharmony_ci p_info->mfw_mb_addr + 1908c2ecf20Sopenharmony_ci offsetof(struct public_mfw_mb, 1918c2ecf20Sopenharmony_ci sup_msgs)); 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci /* The driver can notify that there was an MCP reset, and might read the 1948c2ecf20Sopenharmony_ci * SHMEM values before the MFW has completed initializing them. 1958c2ecf20Sopenharmony_ci * To avoid this, the "sup_msgs" field in the MFW mailbox is used as a 1968c2ecf20Sopenharmony_ci * data ready indication. 1978c2ecf20Sopenharmony_ci */ 1988c2ecf20Sopenharmony_ci while (!p_info->mfw_mb_length && --cnt) { 1998c2ecf20Sopenharmony_ci msleep(msec); 2008c2ecf20Sopenharmony_ci p_info->mfw_mb_length = 2018c2ecf20Sopenharmony_ci (u16)qed_rd(p_hwfn, p_ptt, 2028c2ecf20Sopenharmony_ci p_info->mfw_mb_addr + 2038c2ecf20Sopenharmony_ci offsetof(struct public_mfw_mb, sup_msgs)); 2048c2ecf20Sopenharmony_ci } 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci if (!cnt) { 2078c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, 2088c2ecf20Sopenharmony_ci "Failed to get the SHMEM ready notification after %d msec\n", 2098c2ecf20Sopenharmony_ci QED_MCP_SHMEM_RDY_MAX_RETRIES * msec); 2108c2ecf20Sopenharmony_ci return -EBUSY; 2118c2ecf20Sopenharmony_ci } 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci /* Calculate the driver and MFW mailbox address */ 2148c2ecf20Sopenharmony_ci drv_mb_offsize = qed_rd(p_hwfn, p_ptt, 2158c2ecf20Sopenharmony_ci SECTION_OFFSIZE_ADDR(p_info->public_base, 2168c2ecf20Sopenharmony_ci PUBLIC_DRV_MB)); 2178c2ecf20Sopenharmony_ci p_info->drv_mb_addr = SECTION_ADDR(drv_mb_offsize, mcp_pf_id); 2188c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, QED_MSG_SP, 2198c2ecf20Sopenharmony_ci "drv_mb_offsiz = 0x%x, drv_mb_addr = 0x%x mcp_pf_id = 0x%x\n", 2208c2ecf20Sopenharmony_ci drv_mb_offsize, p_info->drv_mb_addr, mcp_pf_id); 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci /* Get the current driver mailbox sequence before sending 2238c2ecf20Sopenharmony_ci * the first command 2248c2ecf20Sopenharmony_ci */ 2258c2ecf20Sopenharmony_ci p_info->drv_mb_seq = DRV_MB_RD(p_hwfn, p_ptt, drv_mb_header) & 2268c2ecf20Sopenharmony_ci DRV_MSG_SEQ_NUMBER_MASK; 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci /* Get current FW pulse sequence */ 2298c2ecf20Sopenharmony_ci p_info->drv_pulse_seq = DRV_MB_RD(p_hwfn, p_ptt, drv_pulse_mb) & 2308c2ecf20Sopenharmony_ci DRV_PULSE_SEQ_MASK; 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci p_info->mcp_hist = qed_rd(p_hwfn, p_ptt, MISCS_REG_GENERIC_POR_0); 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci return 0; 2358c2ecf20Sopenharmony_ci} 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ciint qed_mcp_cmd_init(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 2388c2ecf20Sopenharmony_ci{ 2398c2ecf20Sopenharmony_ci struct qed_mcp_info *p_info; 2408c2ecf20Sopenharmony_ci u32 size; 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci /* Allocate mcp_info structure */ 2438c2ecf20Sopenharmony_ci p_hwfn->mcp_info = kzalloc(sizeof(*p_hwfn->mcp_info), GFP_KERNEL); 2448c2ecf20Sopenharmony_ci if (!p_hwfn->mcp_info) 2458c2ecf20Sopenharmony_ci goto err; 2468c2ecf20Sopenharmony_ci p_info = p_hwfn->mcp_info; 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci /* Initialize the MFW spinlock */ 2498c2ecf20Sopenharmony_ci spin_lock_init(&p_info->cmd_lock); 2508c2ecf20Sopenharmony_ci spin_lock_init(&p_info->link_lock); 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&p_info->cmd_list); 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci if (qed_load_mcp_offsets(p_hwfn, p_ptt) != 0) { 2558c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, "MCP is not initialized\n"); 2568c2ecf20Sopenharmony_ci /* Do not free mcp_info here, since public_base indicate that 2578c2ecf20Sopenharmony_ci * the MCP is not initialized 2588c2ecf20Sopenharmony_ci */ 2598c2ecf20Sopenharmony_ci return 0; 2608c2ecf20Sopenharmony_ci } 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci size = MFW_DRV_MSG_MAX_DWORDS(p_info->mfw_mb_length) * sizeof(u32); 2638c2ecf20Sopenharmony_ci p_info->mfw_mb_cur = kzalloc(size, GFP_KERNEL); 2648c2ecf20Sopenharmony_ci p_info->mfw_mb_shadow = kzalloc(size, GFP_KERNEL); 2658c2ecf20Sopenharmony_ci if (!p_info->mfw_mb_cur || !p_info->mfw_mb_shadow) 2668c2ecf20Sopenharmony_ci goto err; 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci return 0; 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_cierr: 2718c2ecf20Sopenharmony_ci qed_mcp_free(p_hwfn); 2728c2ecf20Sopenharmony_ci return -ENOMEM; 2738c2ecf20Sopenharmony_ci} 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_cistatic void qed_mcp_reread_offsets(struct qed_hwfn *p_hwfn, 2768c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt) 2778c2ecf20Sopenharmony_ci{ 2788c2ecf20Sopenharmony_ci u32 generic_por_0 = qed_rd(p_hwfn, p_ptt, MISCS_REG_GENERIC_POR_0); 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci /* Use MCP history register to check if MCP reset occurred between init 2818c2ecf20Sopenharmony_ci * time and now. 2828c2ecf20Sopenharmony_ci */ 2838c2ecf20Sopenharmony_ci if (p_hwfn->mcp_info->mcp_hist != generic_por_0) { 2848c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, 2858c2ecf20Sopenharmony_ci QED_MSG_SP, 2868c2ecf20Sopenharmony_ci "Rereading MCP offsets [mcp_hist 0x%08x, generic_por_0 0x%08x]\n", 2878c2ecf20Sopenharmony_ci p_hwfn->mcp_info->mcp_hist, generic_por_0); 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci qed_load_mcp_offsets(p_hwfn, p_ptt); 2908c2ecf20Sopenharmony_ci qed_mcp_cmd_port_init(p_hwfn, p_ptt); 2918c2ecf20Sopenharmony_ci } 2928c2ecf20Sopenharmony_ci} 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ciint qed_mcp_reset(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 2958c2ecf20Sopenharmony_ci{ 2968c2ecf20Sopenharmony_ci u32 org_mcp_reset_seq, seq, delay = QED_MCP_RESP_ITER_US, cnt = 0; 2978c2ecf20Sopenharmony_ci int rc = 0; 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci if (p_hwfn->mcp_info->b_block_cmd) { 3008c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, 3018c2ecf20Sopenharmony_ci "The MFW is not responsive. Avoid sending MCP_RESET mailbox command.\n"); 3028c2ecf20Sopenharmony_ci return -EBUSY; 3038c2ecf20Sopenharmony_ci } 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci /* Ensure that only a single thread is accessing the mailbox */ 3068c2ecf20Sopenharmony_ci spin_lock_bh(&p_hwfn->mcp_info->cmd_lock); 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci org_mcp_reset_seq = qed_rd(p_hwfn, p_ptt, MISCS_REG_GENERIC_POR_0); 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci /* Set drv command along with the updated sequence */ 3118c2ecf20Sopenharmony_ci qed_mcp_reread_offsets(p_hwfn, p_ptt); 3128c2ecf20Sopenharmony_ci seq = ++p_hwfn->mcp_info->drv_mb_seq; 3138c2ecf20Sopenharmony_ci DRV_MB_WR(p_hwfn, p_ptt, drv_mb_header, (DRV_MSG_CODE_MCP_RESET | seq)); 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci do { 3168c2ecf20Sopenharmony_ci /* Wait for MFW response */ 3178c2ecf20Sopenharmony_ci udelay(delay); 3188c2ecf20Sopenharmony_ci /* Give the FW up to 500 second (50*1000*10usec) */ 3198c2ecf20Sopenharmony_ci } while ((org_mcp_reset_seq == qed_rd(p_hwfn, p_ptt, 3208c2ecf20Sopenharmony_ci MISCS_REG_GENERIC_POR_0)) && 3218c2ecf20Sopenharmony_ci (cnt++ < QED_MCP_RESET_RETRIES)); 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci if (org_mcp_reset_seq != 3248c2ecf20Sopenharmony_ci qed_rd(p_hwfn, p_ptt, MISCS_REG_GENERIC_POR_0)) { 3258c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, QED_MSG_SP, 3268c2ecf20Sopenharmony_ci "MCP was reset after %d usec\n", cnt * delay); 3278c2ecf20Sopenharmony_ci } else { 3288c2ecf20Sopenharmony_ci DP_ERR(p_hwfn, "Failed to reset MCP\n"); 3298c2ecf20Sopenharmony_ci rc = -EAGAIN; 3308c2ecf20Sopenharmony_ci } 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci spin_unlock_bh(&p_hwfn->mcp_info->cmd_lock); 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci return rc; 3358c2ecf20Sopenharmony_ci} 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci/* Must be called while cmd_lock is acquired */ 3388c2ecf20Sopenharmony_cistatic bool qed_mcp_has_pending_cmd(struct qed_hwfn *p_hwfn) 3398c2ecf20Sopenharmony_ci{ 3408c2ecf20Sopenharmony_ci struct qed_mcp_cmd_elem *p_cmd_elem; 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci /* There is at most one pending command at a certain time, and if it 3438c2ecf20Sopenharmony_ci * exists - it is placed at the HEAD of the list. 3448c2ecf20Sopenharmony_ci */ 3458c2ecf20Sopenharmony_ci if (!list_empty(&p_hwfn->mcp_info->cmd_list)) { 3468c2ecf20Sopenharmony_ci p_cmd_elem = list_first_entry(&p_hwfn->mcp_info->cmd_list, 3478c2ecf20Sopenharmony_ci struct qed_mcp_cmd_elem, list); 3488c2ecf20Sopenharmony_ci return !p_cmd_elem->b_is_completed; 3498c2ecf20Sopenharmony_ci } 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci return false; 3528c2ecf20Sopenharmony_ci} 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci/* Must be called while cmd_lock is acquired */ 3558c2ecf20Sopenharmony_cistatic int 3568c2ecf20Sopenharmony_ciqed_mcp_update_pending_cmd(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 3578c2ecf20Sopenharmony_ci{ 3588c2ecf20Sopenharmony_ci struct qed_mcp_mb_params *p_mb_params; 3598c2ecf20Sopenharmony_ci struct qed_mcp_cmd_elem *p_cmd_elem; 3608c2ecf20Sopenharmony_ci u32 mcp_resp; 3618c2ecf20Sopenharmony_ci u16 seq_num; 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci mcp_resp = DRV_MB_RD(p_hwfn, p_ptt, fw_mb_header); 3648c2ecf20Sopenharmony_ci seq_num = (u16)(mcp_resp & FW_MSG_SEQ_NUMBER_MASK); 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci /* Return if no new non-handled response has been received */ 3678c2ecf20Sopenharmony_ci if (seq_num != p_hwfn->mcp_info->drv_mb_seq) 3688c2ecf20Sopenharmony_ci return -EAGAIN; 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci p_cmd_elem = qed_mcp_cmd_get_elem(p_hwfn, seq_num); 3718c2ecf20Sopenharmony_ci if (!p_cmd_elem) { 3728c2ecf20Sopenharmony_ci DP_ERR(p_hwfn, 3738c2ecf20Sopenharmony_ci "Failed to find a pending mailbox cmd that expects sequence number %d\n", 3748c2ecf20Sopenharmony_ci seq_num); 3758c2ecf20Sopenharmony_ci return -EINVAL; 3768c2ecf20Sopenharmony_ci } 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci p_mb_params = p_cmd_elem->p_mb_params; 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci /* Get the MFW response along with the sequence number */ 3818c2ecf20Sopenharmony_ci p_mb_params->mcp_resp = mcp_resp; 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci /* Get the MFW param */ 3848c2ecf20Sopenharmony_ci p_mb_params->mcp_param = DRV_MB_RD(p_hwfn, p_ptt, fw_mb_param); 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci /* Get the union data */ 3878c2ecf20Sopenharmony_ci if (p_mb_params->p_data_dst != NULL && p_mb_params->data_dst_size) { 3888c2ecf20Sopenharmony_ci u32 union_data_addr = p_hwfn->mcp_info->drv_mb_addr + 3898c2ecf20Sopenharmony_ci offsetof(struct public_drv_mb, 3908c2ecf20Sopenharmony_ci union_data); 3918c2ecf20Sopenharmony_ci qed_memcpy_from(p_hwfn, p_ptt, p_mb_params->p_data_dst, 3928c2ecf20Sopenharmony_ci union_data_addr, p_mb_params->data_dst_size); 3938c2ecf20Sopenharmony_ci } 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci p_cmd_elem->b_is_completed = true; 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci return 0; 3988c2ecf20Sopenharmony_ci} 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci/* Must be called while cmd_lock is acquired */ 4018c2ecf20Sopenharmony_cistatic void __qed_mcp_cmd_and_union(struct qed_hwfn *p_hwfn, 4028c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt, 4038c2ecf20Sopenharmony_ci struct qed_mcp_mb_params *p_mb_params, 4048c2ecf20Sopenharmony_ci u16 seq_num) 4058c2ecf20Sopenharmony_ci{ 4068c2ecf20Sopenharmony_ci union drv_union_data union_data; 4078c2ecf20Sopenharmony_ci u32 union_data_addr; 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci /* Set the union data */ 4108c2ecf20Sopenharmony_ci union_data_addr = p_hwfn->mcp_info->drv_mb_addr + 4118c2ecf20Sopenharmony_ci offsetof(struct public_drv_mb, union_data); 4128c2ecf20Sopenharmony_ci memset(&union_data, 0, sizeof(union_data)); 4138c2ecf20Sopenharmony_ci if (p_mb_params->p_data_src != NULL && p_mb_params->data_src_size) 4148c2ecf20Sopenharmony_ci memcpy(&union_data, p_mb_params->p_data_src, 4158c2ecf20Sopenharmony_ci p_mb_params->data_src_size); 4168c2ecf20Sopenharmony_ci qed_memcpy_to(p_hwfn, p_ptt, union_data_addr, &union_data, 4178c2ecf20Sopenharmony_ci sizeof(union_data)); 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci /* Set the drv param */ 4208c2ecf20Sopenharmony_ci DRV_MB_WR(p_hwfn, p_ptt, drv_mb_param, p_mb_params->param); 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci /* Set the drv command along with the sequence number */ 4238c2ecf20Sopenharmony_ci DRV_MB_WR(p_hwfn, p_ptt, drv_mb_header, (p_mb_params->cmd | seq_num)); 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, QED_MSG_SP, 4268c2ecf20Sopenharmony_ci "MFW mailbox: command 0x%08x param 0x%08x\n", 4278c2ecf20Sopenharmony_ci (p_mb_params->cmd | seq_num), p_mb_params->param); 4288c2ecf20Sopenharmony_ci} 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_cistatic void qed_mcp_cmd_set_blocking(struct qed_hwfn *p_hwfn, bool block_cmd) 4318c2ecf20Sopenharmony_ci{ 4328c2ecf20Sopenharmony_ci p_hwfn->mcp_info->b_block_cmd = block_cmd; 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci DP_INFO(p_hwfn, "%s sending of mailbox commands to the MFW\n", 4358c2ecf20Sopenharmony_ci block_cmd ? "Block" : "Unblock"); 4368c2ecf20Sopenharmony_ci} 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_cistatic void qed_mcp_print_cpu_info(struct qed_hwfn *p_hwfn, 4398c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt) 4408c2ecf20Sopenharmony_ci{ 4418c2ecf20Sopenharmony_ci u32 cpu_mode, cpu_state, cpu_pc_0, cpu_pc_1, cpu_pc_2; 4428c2ecf20Sopenharmony_ci u32 delay = QED_MCP_RESP_ITER_US; 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci cpu_mode = qed_rd(p_hwfn, p_ptt, MCP_REG_CPU_MODE); 4458c2ecf20Sopenharmony_ci cpu_state = qed_rd(p_hwfn, p_ptt, MCP_REG_CPU_STATE); 4468c2ecf20Sopenharmony_ci cpu_pc_0 = qed_rd(p_hwfn, p_ptt, MCP_REG_CPU_PROGRAM_COUNTER); 4478c2ecf20Sopenharmony_ci udelay(delay); 4488c2ecf20Sopenharmony_ci cpu_pc_1 = qed_rd(p_hwfn, p_ptt, MCP_REG_CPU_PROGRAM_COUNTER); 4498c2ecf20Sopenharmony_ci udelay(delay); 4508c2ecf20Sopenharmony_ci cpu_pc_2 = qed_rd(p_hwfn, p_ptt, MCP_REG_CPU_PROGRAM_COUNTER); 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, 4538c2ecf20Sopenharmony_ci "MCP CPU info: mode 0x%08x, state 0x%08x, pc {0x%08x, 0x%08x, 0x%08x}\n", 4548c2ecf20Sopenharmony_ci cpu_mode, cpu_state, cpu_pc_0, cpu_pc_1, cpu_pc_2); 4558c2ecf20Sopenharmony_ci} 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_cistatic int 4588c2ecf20Sopenharmony_ci_qed_mcp_cmd_and_union(struct qed_hwfn *p_hwfn, 4598c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt, 4608c2ecf20Sopenharmony_ci struct qed_mcp_mb_params *p_mb_params, 4618c2ecf20Sopenharmony_ci u32 max_retries, u32 usecs) 4628c2ecf20Sopenharmony_ci{ 4638c2ecf20Sopenharmony_ci u32 cnt = 0, msecs = DIV_ROUND_UP(usecs, 1000); 4648c2ecf20Sopenharmony_ci struct qed_mcp_cmd_elem *p_cmd_elem; 4658c2ecf20Sopenharmony_ci u16 seq_num; 4668c2ecf20Sopenharmony_ci int rc = 0; 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci /* Wait until the mailbox is non-occupied */ 4698c2ecf20Sopenharmony_ci do { 4708c2ecf20Sopenharmony_ci /* Exit the loop if there is no pending command, or if the 4718c2ecf20Sopenharmony_ci * pending command is completed during this iteration. 4728c2ecf20Sopenharmony_ci * The spinlock stays locked until the command is sent. 4738c2ecf20Sopenharmony_ci */ 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci spin_lock_bh(&p_hwfn->mcp_info->cmd_lock); 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci if (!qed_mcp_has_pending_cmd(p_hwfn)) { 4788c2ecf20Sopenharmony_ci spin_unlock_bh(&p_hwfn->mcp_info->cmd_lock); 4798c2ecf20Sopenharmony_ci break; 4808c2ecf20Sopenharmony_ci } 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ci rc = qed_mcp_update_pending_cmd(p_hwfn, p_ptt); 4838c2ecf20Sopenharmony_ci if (!rc) { 4848c2ecf20Sopenharmony_ci spin_unlock_bh(&p_hwfn->mcp_info->cmd_lock); 4858c2ecf20Sopenharmony_ci break; 4868c2ecf20Sopenharmony_ci } else if (rc != -EAGAIN) { 4878c2ecf20Sopenharmony_ci goto err; 4888c2ecf20Sopenharmony_ci } 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci spin_unlock_bh(&p_hwfn->mcp_info->cmd_lock); 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci if (QED_MB_FLAGS_IS_SET(p_mb_params, CAN_SLEEP)) 4938c2ecf20Sopenharmony_ci msleep(msecs); 4948c2ecf20Sopenharmony_ci else 4958c2ecf20Sopenharmony_ci udelay(usecs); 4968c2ecf20Sopenharmony_ci } while (++cnt < max_retries); 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci if (cnt >= max_retries) { 4998c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, 5008c2ecf20Sopenharmony_ci "The MFW mailbox is occupied by an uncompleted command. Failed to send command 0x%08x [param 0x%08x].\n", 5018c2ecf20Sopenharmony_ci p_mb_params->cmd, p_mb_params->param); 5028c2ecf20Sopenharmony_ci return -EAGAIN; 5038c2ecf20Sopenharmony_ci } 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci spin_lock_bh(&p_hwfn->mcp_info->cmd_lock); 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci /* Send the mailbox command */ 5088c2ecf20Sopenharmony_ci qed_mcp_reread_offsets(p_hwfn, p_ptt); 5098c2ecf20Sopenharmony_ci seq_num = ++p_hwfn->mcp_info->drv_mb_seq; 5108c2ecf20Sopenharmony_ci p_cmd_elem = qed_mcp_cmd_add_elem(p_hwfn, p_mb_params, seq_num); 5118c2ecf20Sopenharmony_ci if (!p_cmd_elem) { 5128c2ecf20Sopenharmony_ci rc = -ENOMEM; 5138c2ecf20Sopenharmony_ci goto err; 5148c2ecf20Sopenharmony_ci } 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci __qed_mcp_cmd_and_union(p_hwfn, p_ptt, p_mb_params, seq_num); 5178c2ecf20Sopenharmony_ci spin_unlock_bh(&p_hwfn->mcp_info->cmd_lock); 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci /* Wait for the MFW response */ 5208c2ecf20Sopenharmony_ci do { 5218c2ecf20Sopenharmony_ci /* Exit the loop if the command is already completed, or if the 5228c2ecf20Sopenharmony_ci * command is completed during this iteration. 5238c2ecf20Sopenharmony_ci * The spinlock stays locked until the list element is removed. 5248c2ecf20Sopenharmony_ci */ 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci if (QED_MB_FLAGS_IS_SET(p_mb_params, CAN_SLEEP)) 5278c2ecf20Sopenharmony_ci msleep(msecs); 5288c2ecf20Sopenharmony_ci else 5298c2ecf20Sopenharmony_ci udelay(usecs); 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci spin_lock_bh(&p_hwfn->mcp_info->cmd_lock); 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci if (p_cmd_elem->b_is_completed) { 5348c2ecf20Sopenharmony_ci spin_unlock_bh(&p_hwfn->mcp_info->cmd_lock); 5358c2ecf20Sopenharmony_ci break; 5368c2ecf20Sopenharmony_ci } 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci rc = qed_mcp_update_pending_cmd(p_hwfn, p_ptt); 5398c2ecf20Sopenharmony_ci if (!rc) { 5408c2ecf20Sopenharmony_ci spin_unlock_bh(&p_hwfn->mcp_info->cmd_lock); 5418c2ecf20Sopenharmony_ci break; 5428c2ecf20Sopenharmony_ci } else if (rc != -EAGAIN) { 5438c2ecf20Sopenharmony_ci goto err; 5448c2ecf20Sopenharmony_ci } 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci spin_unlock_bh(&p_hwfn->mcp_info->cmd_lock); 5478c2ecf20Sopenharmony_ci } while (++cnt < max_retries); 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci if (cnt >= max_retries) { 5508c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, 5518c2ecf20Sopenharmony_ci "The MFW failed to respond to command 0x%08x [param 0x%08x].\n", 5528c2ecf20Sopenharmony_ci p_mb_params->cmd, p_mb_params->param); 5538c2ecf20Sopenharmony_ci qed_mcp_print_cpu_info(p_hwfn, p_ptt); 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci spin_lock_bh(&p_hwfn->mcp_info->cmd_lock); 5568c2ecf20Sopenharmony_ci qed_mcp_cmd_del_elem(p_hwfn, p_cmd_elem); 5578c2ecf20Sopenharmony_ci spin_unlock_bh(&p_hwfn->mcp_info->cmd_lock); 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ci if (!QED_MB_FLAGS_IS_SET(p_mb_params, AVOID_BLOCK)) 5608c2ecf20Sopenharmony_ci qed_mcp_cmd_set_blocking(p_hwfn, true); 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ci qed_hw_err_notify(p_hwfn, p_ptt, 5638c2ecf20Sopenharmony_ci QED_HW_ERR_MFW_RESP_FAIL, NULL); 5648c2ecf20Sopenharmony_ci return -EAGAIN; 5658c2ecf20Sopenharmony_ci } 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci spin_lock_bh(&p_hwfn->mcp_info->cmd_lock); 5688c2ecf20Sopenharmony_ci qed_mcp_cmd_del_elem(p_hwfn, p_cmd_elem); 5698c2ecf20Sopenharmony_ci spin_unlock_bh(&p_hwfn->mcp_info->cmd_lock); 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, 5728c2ecf20Sopenharmony_ci QED_MSG_SP, 5738c2ecf20Sopenharmony_ci "MFW mailbox: response 0x%08x param 0x%08x [after %d.%03d ms]\n", 5748c2ecf20Sopenharmony_ci p_mb_params->mcp_resp, 5758c2ecf20Sopenharmony_ci p_mb_params->mcp_param, 5768c2ecf20Sopenharmony_ci (cnt * usecs) / 1000, (cnt * usecs) % 1000); 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci /* Clear the sequence number from the MFW response */ 5798c2ecf20Sopenharmony_ci p_mb_params->mcp_resp &= FW_MSG_CODE_MASK; 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_ci return 0; 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_cierr: 5848c2ecf20Sopenharmony_ci spin_unlock_bh(&p_hwfn->mcp_info->cmd_lock); 5858c2ecf20Sopenharmony_ci return rc; 5868c2ecf20Sopenharmony_ci} 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_cistatic int qed_mcp_cmd_and_union(struct qed_hwfn *p_hwfn, 5898c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt, 5908c2ecf20Sopenharmony_ci struct qed_mcp_mb_params *p_mb_params) 5918c2ecf20Sopenharmony_ci{ 5928c2ecf20Sopenharmony_ci size_t union_data_size = sizeof(union drv_union_data); 5938c2ecf20Sopenharmony_ci u32 max_retries = QED_DRV_MB_MAX_RETRIES; 5948c2ecf20Sopenharmony_ci u32 usecs = QED_MCP_RESP_ITER_US; 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci /* MCP not initialized */ 5978c2ecf20Sopenharmony_ci if (!qed_mcp_is_init(p_hwfn)) { 5988c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, "MFW is not initialized!\n"); 5998c2ecf20Sopenharmony_ci return -EBUSY; 6008c2ecf20Sopenharmony_ci } 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_ci if (p_hwfn->mcp_info->b_block_cmd) { 6038c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, 6048c2ecf20Sopenharmony_ci "The MFW is not responsive. Avoid sending mailbox command 0x%08x [param 0x%08x].\n", 6058c2ecf20Sopenharmony_ci p_mb_params->cmd, p_mb_params->param); 6068c2ecf20Sopenharmony_ci return -EBUSY; 6078c2ecf20Sopenharmony_ci } 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci if (p_mb_params->data_src_size > union_data_size || 6108c2ecf20Sopenharmony_ci p_mb_params->data_dst_size > union_data_size) { 6118c2ecf20Sopenharmony_ci DP_ERR(p_hwfn, 6128c2ecf20Sopenharmony_ci "The provided size is larger than the union data size [src_size %u, dst_size %u, union_data_size %zu]\n", 6138c2ecf20Sopenharmony_ci p_mb_params->data_src_size, 6148c2ecf20Sopenharmony_ci p_mb_params->data_dst_size, union_data_size); 6158c2ecf20Sopenharmony_ci return -EINVAL; 6168c2ecf20Sopenharmony_ci } 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_ci if (QED_MB_FLAGS_IS_SET(p_mb_params, CAN_SLEEP)) { 6198c2ecf20Sopenharmony_ci max_retries = DIV_ROUND_UP(max_retries, 1000); 6208c2ecf20Sopenharmony_ci usecs *= 1000; 6218c2ecf20Sopenharmony_ci } 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_ci return _qed_mcp_cmd_and_union(p_hwfn, p_ptt, p_mb_params, max_retries, 6248c2ecf20Sopenharmony_ci usecs); 6258c2ecf20Sopenharmony_ci} 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ciint qed_mcp_cmd(struct qed_hwfn *p_hwfn, 6288c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt, 6298c2ecf20Sopenharmony_ci u32 cmd, 6308c2ecf20Sopenharmony_ci u32 param, 6318c2ecf20Sopenharmony_ci u32 *o_mcp_resp, 6328c2ecf20Sopenharmony_ci u32 *o_mcp_param) 6338c2ecf20Sopenharmony_ci{ 6348c2ecf20Sopenharmony_ci struct qed_mcp_mb_params mb_params; 6358c2ecf20Sopenharmony_ci int rc; 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_ci memset(&mb_params, 0, sizeof(mb_params)); 6388c2ecf20Sopenharmony_ci mb_params.cmd = cmd; 6398c2ecf20Sopenharmony_ci mb_params.param = param; 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_ci rc = qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 6428c2ecf20Sopenharmony_ci if (rc) 6438c2ecf20Sopenharmony_ci return rc; 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci *o_mcp_resp = mb_params.mcp_resp; 6468c2ecf20Sopenharmony_ci *o_mcp_param = mb_params.mcp_param; 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ci return 0; 6498c2ecf20Sopenharmony_ci} 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_cistatic int 6528c2ecf20Sopenharmony_ciqed_mcp_nvm_wr_cmd(struct qed_hwfn *p_hwfn, 6538c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt, 6548c2ecf20Sopenharmony_ci u32 cmd, 6558c2ecf20Sopenharmony_ci u32 param, 6568c2ecf20Sopenharmony_ci u32 *o_mcp_resp, 6578c2ecf20Sopenharmony_ci u32 *o_mcp_param, u32 i_txn_size, u32 *i_buf) 6588c2ecf20Sopenharmony_ci{ 6598c2ecf20Sopenharmony_ci struct qed_mcp_mb_params mb_params; 6608c2ecf20Sopenharmony_ci int rc; 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_ci memset(&mb_params, 0, sizeof(mb_params)); 6638c2ecf20Sopenharmony_ci mb_params.cmd = cmd; 6648c2ecf20Sopenharmony_ci mb_params.param = param; 6658c2ecf20Sopenharmony_ci mb_params.p_data_src = i_buf; 6668c2ecf20Sopenharmony_ci mb_params.data_src_size = (u8)i_txn_size; 6678c2ecf20Sopenharmony_ci rc = qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 6688c2ecf20Sopenharmony_ci if (rc) 6698c2ecf20Sopenharmony_ci return rc; 6708c2ecf20Sopenharmony_ci 6718c2ecf20Sopenharmony_ci *o_mcp_resp = mb_params.mcp_resp; 6728c2ecf20Sopenharmony_ci *o_mcp_param = mb_params.mcp_param; 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_ci /* nvm_info needs to be updated */ 6758c2ecf20Sopenharmony_ci p_hwfn->nvm_info.valid = false; 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_ci return 0; 6788c2ecf20Sopenharmony_ci} 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_ciint qed_mcp_nvm_rd_cmd(struct qed_hwfn *p_hwfn, 6818c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt, 6828c2ecf20Sopenharmony_ci u32 cmd, 6838c2ecf20Sopenharmony_ci u32 param, 6848c2ecf20Sopenharmony_ci u32 *o_mcp_resp, 6858c2ecf20Sopenharmony_ci u32 *o_mcp_param, u32 *o_txn_size, u32 *o_buf) 6868c2ecf20Sopenharmony_ci{ 6878c2ecf20Sopenharmony_ci struct qed_mcp_mb_params mb_params; 6888c2ecf20Sopenharmony_ci u8 raw_data[MCP_DRV_NVM_BUF_LEN]; 6898c2ecf20Sopenharmony_ci int rc; 6908c2ecf20Sopenharmony_ci 6918c2ecf20Sopenharmony_ci memset(&mb_params, 0, sizeof(mb_params)); 6928c2ecf20Sopenharmony_ci mb_params.cmd = cmd; 6938c2ecf20Sopenharmony_ci mb_params.param = param; 6948c2ecf20Sopenharmony_ci mb_params.p_data_dst = raw_data; 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_ci /* Use the maximal value since the actual one is part of the response */ 6978c2ecf20Sopenharmony_ci mb_params.data_dst_size = MCP_DRV_NVM_BUF_LEN; 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_ci rc = qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 7008c2ecf20Sopenharmony_ci if (rc) 7018c2ecf20Sopenharmony_ci return rc; 7028c2ecf20Sopenharmony_ci 7038c2ecf20Sopenharmony_ci *o_mcp_resp = mb_params.mcp_resp; 7048c2ecf20Sopenharmony_ci *o_mcp_param = mb_params.mcp_param; 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_ci *o_txn_size = *o_mcp_param; 7078c2ecf20Sopenharmony_ci memcpy(o_buf, raw_data, *o_txn_size); 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_ci return 0; 7108c2ecf20Sopenharmony_ci} 7118c2ecf20Sopenharmony_ci 7128c2ecf20Sopenharmony_cistatic bool 7138c2ecf20Sopenharmony_ciqed_mcp_can_force_load(u8 drv_role, 7148c2ecf20Sopenharmony_ci u8 exist_drv_role, 7158c2ecf20Sopenharmony_ci enum qed_override_force_load override_force_load) 7168c2ecf20Sopenharmony_ci{ 7178c2ecf20Sopenharmony_ci bool can_force_load = false; 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_ci switch (override_force_load) { 7208c2ecf20Sopenharmony_ci case QED_OVERRIDE_FORCE_LOAD_ALWAYS: 7218c2ecf20Sopenharmony_ci can_force_load = true; 7228c2ecf20Sopenharmony_ci break; 7238c2ecf20Sopenharmony_ci case QED_OVERRIDE_FORCE_LOAD_NEVER: 7248c2ecf20Sopenharmony_ci can_force_load = false; 7258c2ecf20Sopenharmony_ci break; 7268c2ecf20Sopenharmony_ci default: 7278c2ecf20Sopenharmony_ci can_force_load = (drv_role == DRV_ROLE_OS && 7288c2ecf20Sopenharmony_ci exist_drv_role == DRV_ROLE_PREBOOT) || 7298c2ecf20Sopenharmony_ci (drv_role == DRV_ROLE_KDUMP && 7308c2ecf20Sopenharmony_ci exist_drv_role == DRV_ROLE_OS); 7318c2ecf20Sopenharmony_ci break; 7328c2ecf20Sopenharmony_ci } 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_ci return can_force_load; 7358c2ecf20Sopenharmony_ci} 7368c2ecf20Sopenharmony_ci 7378c2ecf20Sopenharmony_cistatic int qed_mcp_cancel_load_req(struct qed_hwfn *p_hwfn, 7388c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt) 7398c2ecf20Sopenharmony_ci{ 7408c2ecf20Sopenharmony_ci u32 resp = 0, param = 0; 7418c2ecf20Sopenharmony_ci int rc; 7428c2ecf20Sopenharmony_ci 7438c2ecf20Sopenharmony_ci rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_CANCEL_LOAD_REQ, 0, 7448c2ecf20Sopenharmony_ci &resp, ¶m); 7458c2ecf20Sopenharmony_ci if (rc) 7468c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, 7478c2ecf20Sopenharmony_ci "Failed to send cancel load request, rc = %d\n", rc); 7488c2ecf20Sopenharmony_ci 7498c2ecf20Sopenharmony_ci return rc; 7508c2ecf20Sopenharmony_ci} 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_ci#define CONFIG_QEDE_BITMAP_IDX BIT(0) 7538c2ecf20Sopenharmony_ci#define CONFIG_QED_SRIOV_BITMAP_IDX BIT(1) 7548c2ecf20Sopenharmony_ci#define CONFIG_QEDR_BITMAP_IDX BIT(2) 7558c2ecf20Sopenharmony_ci#define CONFIG_QEDF_BITMAP_IDX BIT(4) 7568c2ecf20Sopenharmony_ci#define CONFIG_QEDI_BITMAP_IDX BIT(5) 7578c2ecf20Sopenharmony_ci#define CONFIG_QED_LL2_BITMAP_IDX BIT(6) 7588c2ecf20Sopenharmony_ci 7598c2ecf20Sopenharmony_cistatic u32 qed_get_config_bitmap(void) 7608c2ecf20Sopenharmony_ci{ 7618c2ecf20Sopenharmony_ci u32 config_bitmap = 0x0; 7628c2ecf20Sopenharmony_ci 7638c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_QEDE)) 7648c2ecf20Sopenharmony_ci config_bitmap |= CONFIG_QEDE_BITMAP_IDX; 7658c2ecf20Sopenharmony_ci 7668c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_QED_SRIOV)) 7678c2ecf20Sopenharmony_ci config_bitmap |= CONFIG_QED_SRIOV_BITMAP_IDX; 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_QED_RDMA)) 7708c2ecf20Sopenharmony_ci config_bitmap |= CONFIG_QEDR_BITMAP_IDX; 7718c2ecf20Sopenharmony_ci 7728c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_QED_FCOE)) 7738c2ecf20Sopenharmony_ci config_bitmap |= CONFIG_QEDF_BITMAP_IDX; 7748c2ecf20Sopenharmony_ci 7758c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_QED_ISCSI)) 7768c2ecf20Sopenharmony_ci config_bitmap |= CONFIG_QEDI_BITMAP_IDX; 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_QED_LL2)) 7798c2ecf20Sopenharmony_ci config_bitmap |= CONFIG_QED_LL2_BITMAP_IDX; 7808c2ecf20Sopenharmony_ci 7818c2ecf20Sopenharmony_ci return config_bitmap; 7828c2ecf20Sopenharmony_ci} 7838c2ecf20Sopenharmony_ci 7848c2ecf20Sopenharmony_cistruct qed_load_req_in_params { 7858c2ecf20Sopenharmony_ci u8 hsi_ver; 7868c2ecf20Sopenharmony_ci#define QED_LOAD_REQ_HSI_VER_DEFAULT 0 7878c2ecf20Sopenharmony_ci#define QED_LOAD_REQ_HSI_VER_1 1 7888c2ecf20Sopenharmony_ci u32 drv_ver_0; 7898c2ecf20Sopenharmony_ci u32 drv_ver_1; 7908c2ecf20Sopenharmony_ci u32 fw_ver; 7918c2ecf20Sopenharmony_ci u8 drv_role; 7928c2ecf20Sopenharmony_ci u8 timeout_val; 7938c2ecf20Sopenharmony_ci u8 force_cmd; 7948c2ecf20Sopenharmony_ci bool avoid_eng_reset; 7958c2ecf20Sopenharmony_ci}; 7968c2ecf20Sopenharmony_ci 7978c2ecf20Sopenharmony_cistruct qed_load_req_out_params { 7988c2ecf20Sopenharmony_ci u32 load_code; 7998c2ecf20Sopenharmony_ci u32 exist_drv_ver_0; 8008c2ecf20Sopenharmony_ci u32 exist_drv_ver_1; 8018c2ecf20Sopenharmony_ci u32 exist_fw_ver; 8028c2ecf20Sopenharmony_ci u8 exist_drv_role; 8038c2ecf20Sopenharmony_ci u8 mfw_hsi_ver; 8048c2ecf20Sopenharmony_ci bool drv_exists; 8058c2ecf20Sopenharmony_ci}; 8068c2ecf20Sopenharmony_ci 8078c2ecf20Sopenharmony_cistatic int 8088c2ecf20Sopenharmony_ci__qed_mcp_load_req(struct qed_hwfn *p_hwfn, 8098c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt, 8108c2ecf20Sopenharmony_ci struct qed_load_req_in_params *p_in_params, 8118c2ecf20Sopenharmony_ci struct qed_load_req_out_params *p_out_params) 8128c2ecf20Sopenharmony_ci{ 8138c2ecf20Sopenharmony_ci struct qed_mcp_mb_params mb_params; 8148c2ecf20Sopenharmony_ci struct load_req_stc load_req; 8158c2ecf20Sopenharmony_ci struct load_rsp_stc load_rsp; 8168c2ecf20Sopenharmony_ci u32 hsi_ver; 8178c2ecf20Sopenharmony_ci int rc; 8188c2ecf20Sopenharmony_ci 8198c2ecf20Sopenharmony_ci memset(&load_req, 0, sizeof(load_req)); 8208c2ecf20Sopenharmony_ci load_req.drv_ver_0 = p_in_params->drv_ver_0; 8218c2ecf20Sopenharmony_ci load_req.drv_ver_1 = p_in_params->drv_ver_1; 8228c2ecf20Sopenharmony_ci load_req.fw_ver = p_in_params->fw_ver; 8238c2ecf20Sopenharmony_ci QED_MFW_SET_FIELD(load_req.misc0, LOAD_REQ_ROLE, p_in_params->drv_role); 8248c2ecf20Sopenharmony_ci QED_MFW_SET_FIELD(load_req.misc0, LOAD_REQ_LOCK_TO, 8258c2ecf20Sopenharmony_ci p_in_params->timeout_val); 8268c2ecf20Sopenharmony_ci QED_MFW_SET_FIELD(load_req.misc0, LOAD_REQ_FORCE, 8278c2ecf20Sopenharmony_ci p_in_params->force_cmd); 8288c2ecf20Sopenharmony_ci QED_MFW_SET_FIELD(load_req.misc0, LOAD_REQ_FLAGS0, 8298c2ecf20Sopenharmony_ci p_in_params->avoid_eng_reset); 8308c2ecf20Sopenharmony_ci 8318c2ecf20Sopenharmony_ci hsi_ver = (p_in_params->hsi_ver == QED_LOAD_REQ_HSI_VER_DEFAULT) ? 8328c2ecf20Sopenharmony_ci DRV_ID_MCP_HSI_VER_CURRENT : 8338c2ecf20Sopenharmony_ci (p_in_params->hsi_ver << DRV_ID_MCP_HSI_VER_SHIFT); 8348c2ecf20Sopenharmony_ci 8358c2ecf20Sopenharmony_ci memset(&mb_params, 0, sizeof(mb_params)); 8368c2ecf20Sopenharmony_ci mb_params.cmd = DRV_MSG_CODE_LOAD_REQ; 8378c2ecf20Sopenharmony_ci mb_params.param = PDA_COMP | hsi_ver | p_hwfn->cdev->drv_type; 8388c2ecf20Sopenharmony_ci mb_params.p_data_src = &load_req; 8398c2ecf20Sopenharmony_ci mb_params.data_src_size = sizeof(load_req); 8408c2ecf20Sopenharmony_ci mb_params.p_data_dst = &load_rsp; 8418c2ecf20Sopenharmony_ci mb_params.data_dst_size = sizeof(load_rsp); 8428c2ecf20Sopenharmony_ci mb_params.flags = QED_MB_FLAG_CAN_SLEEP | QED_MB_FLAG_AVOID_BLOCK; 8438c2ecf20Sopenharmony_ci 8448c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, QED_MSG_SP, 8458c2ecf20Sopenharmony_ci "Load Request: param 0x%08x [init_hw %d, drv_type %d, hsi_ver %d, pda 0x%04x]\n", 8468c2ecf20Sopenharmony_ci mb_params.param, 8478c2ecf20Sopenharmony_ci QED_MFW_GET_FIELD(mb_params.param, DRV_ID_DRV_INIT_HW), 8488c2ecf20Sopenharmony_ci QED_MFW_GET_FIELD(mb_params.param, DRV_ID_DRV_TYPE), 8498c2ecf20Sopenharmony_ci QED_MFW_GET_FIELD(mb_params.param, DRV_ID_MCP_HSI_VER), 8508c2ecf20Sopenharmony_ci QED_MFW_GET_FIELD(mb_params.param, DRV_ID_PDA_COMP_VER)); 8518c2ecf20Sopenharmony_ci 8528c2ecf20Sopenharmony_ci if (p_in_params->hsi_ver != QED_LOAD_REQ_HSI_VER_1) { 8538c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, QED_MSG_SP, 8548c2ecf20Sopenharmony_ci "Load Request: drv_ver 0x%08x_0x%08x, fw_ver 0x%08x, misc0 0x%08x [role %d, timeout %d, force %d, flags0 0x%x]\n", 8558c2ecf20Sopenharmony_ci load_req.drv_ver_0, 8568c2ecf20Sopenharmony_ci load_req.drv_ver_1, 8578c2ecf20Sopenharmony_ci load_req.fw_ver, 8588c2ecf20Sopenharmony_ci load_req.misc0, 8598c2ecf20Sopenharmony_ci QED_MFW_GET_FIELD(load_req.misc0, LOAD_REQ_ROLE), 8608c2ecf20Sopenharmony_ci QED_MFW_GET_FIELD(load_req.misc0, 8618c2ecf20Sopenharmony_ci LOAD_REQ_LOCK_TO), 8628c2ecf20Sopenharmony_ci QED_MFW_GET_FIELD(load_req.misc0, LOAD_REQ_FORCE), 8638c2ecf20Sopenharmony_ci QED_MFW_GET_FIELD(load_req.misc0, LOAD_REQ_FLAGS0)); 8648c2ecf20Sopenharmony_ci } 8658c2ecf20Sopenharmony_ci 8668c2ecf20Sopenharmony_ci rc = qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 8678c2ecf20Sopenharmony_ci if (rc) { 8688c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, "Failed to send load request, rc = %d\n", rc); 8698c2ecf20Sopenharmony_ci return rc; 8708c2ecf20Sopenharmony_ci } 8718c2ecf20Sopenharmony_ci 8728c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, QED_MSG_SP, 8738c2ecf20Sopenharmony_ci "Load Response: resp 0x%08x\n", mb_params.mcp_resp); 8748c2ecf20Sopenharmony_ci p_out_params->load_code = mb_params.mcp_resp; 8758c2ecf20Sopenharmony_ci 8768c2ecf20Sopenharmony_ci if (p_in_params->hsi_ver != QED_LOAD_REQ_HSI_VER_1 && 8778c2ecf20Sopenharmony_ci p_out_params->load_code != FW_MSG_CODE_DRV_LOAD_REFUSED_HSI_1) { 8788c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, 8798c2ecf20Sopenharmony_ci QED_MSG_SP, 8808c2ecf20Sopenharmony_ci "Load Response: exist_drv_ver 0x%08x_0x%08x, exist_fw_ver 0x%08x, misc0 0x%08x [exist_role %d, mfw_hsi %d, flags0 0x%x]\n", 8818c2ecf20Sopenharmony_ci load_rsp.drv_ver_0, 8828c2ecf20Sopenharmony_ci load_rsp.drv_ver_1, 8838c2ecf20Sopenharmony_ci load_rsp.fw_ver, 8848c2ecf20Sopenharmony_ci load_rsp.misc0, 8858c2ecf20Sopenharmony_ci QED_MFW_GET_FIELD(load_rsp.misc0, LOAD_RSP_ROLE), 8868c2ecf20Sopenharmony_ci QED_MFW_GET_FIELD(load_rsp.misc0, LOAD_RSP_HSI), 8878c2ecf20Sopenharmony_ci QED_MFW_GET_FIELD(load_rsp.misc0, LOAD_RSP_FLAGS0)); 8888c2ecf20Sopenharmony_ci 8898c2ecf20Sopenharmony_ci p_out_params->exist_drv_ver_0 = load_rsp.drv_ver_0; 8908c2ecf20Sopenharmony_ci p_out_params->exist_drv_ver_1 = load_rsp.drv_ver_1; 8918c2ecf20Sopenharmony_ci p_out_params->exist_fw_ver = load_rsp.fw_ver; 8928c2ecf20Sopenharmony_ci p_out_params->exist_drv_role = 8938c2ecf20Sopenharmony_ci QED_MFW_GET_FIELD(load_rsp.misc0, LOAD_RSP_ROLE); 8948c2ecf20Sopenharmony_ci p_out_params->mfw_hsi_ver = 8958c2ecf20Sopenharmony_ci QED_MFW_GET_FIELD(load_rsp.misc0, LOAD_RSP_HSI); 8968c2ecf20Sopenharmony_ci p_out_params->drv_exists = 8978c2ecf20Sopenharmony_ci QED_MFW_GET_FIELD(load_rsp.misc0, LOAD_RSP_FLAGS0) & 8988c2ecf20Sopenharmony_ci LOAD_RSP_FLAGS0_DRV_EXISTS; 8998c2ecf20Sopenharmony_ci } 9008c2ecf20Sopenharmony_ci 9018c2ecf20Sopenharmony_ci return 0; 9028c2ecf20Sopenharmony_ci} 9038c2ecf20Sopenharmony_ci 9048c2ecf20Sopenharmony_cistatic int eocre_get_mfw_drv_role(struct qed_hwfn *p_hwfn, 9058c2ecf20Sopenharmony_ci enum qed_drv_role drv_role, 9068c2ecf20Sopenharmony_ci u8 *p_mfw_drv_role) 9078c2ecf20Sopenharmony_ci{ 9088c2ecf20Sopenharmony_ci switch (drv_role) { 9098c2ecf20Sopenharmony_ci case QED_DRV_ROLE_OS: 9108c2ecf20Sopenharmony_ci *p_mfw_drv_role = DRV_ROLE_OS; 9118c2ecf20Sopenharmony_ci break; 9128c2ecf20Sopenharmony_ci case QED_DRV_ROLE_KDUMP: 9138c2ecf20Sopenharmony_ci *p_mfw_drv_role = DRV_ROLE_KDUMP; 9148c2ecf20Sopenharmony_ci break; 9158c2ecf20Sopenharmony_ci default: 9168c2ecf20Sopenharmony_ci DP_ERR(p_hwfn, "Unexpected driver role %d\n", drv_role); 9178c2ecf20Sopenharmony_ci return -EINVAL; 9188c2ecf20Sopenharmony_ci } 9198c2ecf20Sopenharmony_ci 9208c2ecf20Sopenharmony_ci return 0; 9218c2ecf20Sopenharmony_ci} 9228c2ecf20Sopenharmony_ci 9238c2ecf20Sopenharmony_cienum qed_load_req_force { 9248c2ecf20Sopenharmony_ci QED_LOAD_REQ_FORCE_NONE, 9258c2ecf20Sopenharmony_ci QED_LOAD_REQ_FORCE_PF, 9268c2ecf20Sopenharmony_ci QED_LOAD_REQ_FORCE_ALL, 9278c2ecf20Sopenharmony_ci}; 9288c2ecf20Sopenharmony_ci 9298c2ecf20Sopenharmony_cistatic void qed_get_mfw_force_cmd(struct qed_hwfn *p_hwfn, 9308c2ecf20Sopenharmony_ci 9318c2ecf20Sopenharmony_ci enum qed_load_req_force force_cmd, 9328c2ecf20Sopenharmony_ci u8 *p_mfw_force_cmd) 9338c2ecf20Sopenharmony_ci{ 9348c2ecf20Sopenharmony_ci switch (force_cmd) { 9358c2ecf20Sopenharmony_ci case QED_LOAD_REQ_FORCE_NONE: 9368c2ecf20Sopenharmony_ci *p_mfw_force_cmd = LOAD_REQ_FORCE_NONE; 9378c2ecf20Sopenharmony_ci break; 9388c2ecf20Sopenharmony_ci case QED_LOAD_REQ_FORCE_PF: 9398c2ecf20Sopenharmony_ci *p_mfw_force_cmd = LOAD_REQ_FORCE_PF; 9408c2ecf20Sopenharmony_ci break; 9418c2ecf20Sopenharmony_ci case QED_LOAD_REQ_FORCE_ALL: 9428c2ecf20Sopenharmony_ci *p_mfw_force_cmd = LOAD_REQ_FORCE_ALL; 9438c2ecf20Sopenharmony_ci break; 9448c2ecf20Sopenharmony_ci } 9458c2ecf20Sopenharmony_ci} 9468c2ecf20Sopenharmony_ci 9478c2ecf20Sopenharmony_ciint qed_mcp_load_req(struct qed_hwfn *p_hwfn, 9488c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt, 9498c2ecf20Sopenharmony_ci struct qed_load_req_params *p_params) 9508c2ecf20Sopenharmony_ci{ 9518c2ecf20Sopenharmony_ci struct qed_load_req_out_params out_params; 9528c2ecf20Sopenharmony_ci struct qed_load_req_in_params in_params; 9538c2ecf20Sopenharmony_ci u8 mfw_drv_role, mfw_force_cmd; 9548c2ecf20Sopenharmony_ci int rc; 9558c2ecf20Sopenharmony_ci 9568c2ecf20Sopenharmony_ci memset(&in_params, 0, sizeof(in_params)); 9578c2ecf20Sopenharmony_ci in_params.hsi_ver = QED_LOAD_REQ_HSI_VER_DEFAULT; 9588c2ecf20Sopenharmony_ci in_params.drv_ver_0 = QED_VERSION; 9598c2ecf20Sopenharmony_ci in_params.drv_ver_1 = qed_get_config_bitmap(); 9608c2ecf20Sopenharmony_ci in_params.fw_ver = STORM_FW_VERSION; 9618c2ecf20Sopenharmony_ci rc = eocre_get_mfw_drv_role(p_hwfn, p_params->drv_role, &mfw_drv_role); 9628c2ecf20Sopenharmony_ci if (rc) 9638c2ecf20Sopenharmony_ci return rc; 9648c2ecf20Sopenharmony_ci 9658c2ecf20Sopenharmony_ci in_params.drv_role = mfw_drv_role; 9668c2ecf20Sopenharmony_ci in_params.timeout_val = p_params->timeout_val; 9678c2ecf20Sopenharmony_ci qed_get_mfw_force_cmd(p_hwfn, 9688c2ecf20Sopenharmony_ci QED_LOAD_REQ_FORCE_NONE, &mfw_force_cmd); 9698c2ecf20Sopenharmony_ci 9708c2ecf20Sopenharmony_ci in_params.force_cmd = mfw_force_cmd; 9718c2ecf20Sopenharmony_ci in_params.avoid_eng_reset = p_params->avoid_eng_reset; 9728c2ecf20Sopenharmony_ci 9738c2ecf20Sopenharmony_ci memset(&out_params, 0, sizeof(out_params)); 9748c2ecf20Sopenharmony_ci rc = __qed_mcp_load_req(p_hwfn, p_ptt, &in_params, &out_params); 9758c2ecf20Sopenharmony_ci if (rc) 9768c2ecf20Sopenharmony_ci return rc; 9778c2ecf20Sopenharmony_ci 9788c2ecf20Sopenharmony_ci /* First handle cases where another load request should/might be sent: 9798c2ecf20Sopenharmony_ci * - MFW expects the old interface [HSI version = 1] 9808c2ecf20Sopenharmony_ci * - MFW responds that a force load request is required 9818c2ecf20Sopenharmony_ci */ 9828c2ecf20Sopenharmony_ci if (out_params.load_code == FW_MSG_CODE_DRV_LOAD_REFUSED_HSI_1) { 9838c2ecf20Sopenharmony_ci DP_INFO(p_hwfn, 9848c2ecf20Sopenharmony_ci "MFW refused a load request due to HSI > 1. Resending with HSI = 1\n"); 9858c2ecf20Sopenharmony_ci 9868c2ecf20Sopenharmony_ci in_params.hsi_ver = QED_LOAD_REQ_HSI_VER_1; 9878c2ecf20Sopenharmony_ci memset(&out_params, 0, sizeof(out_params)); 9888c2ecf20Sopenharmony_ci rc = __qed_mcp_load_req(p_hwfn, p_ptt, &in_params, &out_params); 9898c2ecf20Sopenharmony_ci if (rc) 9908c2ecf20Sopenharmony_ci return rc; 9918c2ecf20Sopenharmony_ci } else if (out_params.load_code == 9928c2ecf20Sopenharmony_ci FW_MSG_CODE_DRV_LOAD_REFUSED_REQUIRES_FORCE) { 9938c2ecf20Sopenharmony_ci if (qed_mcp_can_force_load(in_params.drv_role, 9948c2ecf20Sopenharmony_ci out_params.exist_drv_role, 9958c2ecf20Sopenharmony_ci p_params->override_force_load)) { 9968c2ecf20Sopenharmony_ci DP_INFO(p_hwfn, 9978c2ecf20Sopenharmony_ci "A force load is required [{role, fw_ver, drv_ver}: loading={%d, 0x%08x, x%08x_0x%08x}, existing={%d, 0x%08x, 0x%08x_0x%08x}]\n", 9988c2ecf20Sopenharmony_ci in_params.drv_role, in_params.fw_ver, 9998c2ecf20Sopenharmony_ci in_params.drv_ver_0, in_params.drv_ver_1, 10008c2ecf20Sopenharmony_ci out_params.exist_drv_role, 10018c2ecf20Sopenharmony_ci out_params.exist_fw_ver, 10028c2ecf20Sopenharmony_ci out_params.exist_drv_ver_0, 10038c2ecf20Sopenharmony_ci out_params.exist_drv_ver_1); 10048c2ecf20Sopenharmony_ci 10058c2ecf20Sopenharmony_ci qed_get_mfw_force_cmd(p_hwfn, 10068c2ecf20Sopenharmony_ci QED_LOAD_REQ_FORCE_ALL, 10078c2ecf20Sopenharmony_ci &mfw_force_cmd); 10088c2ecf20Sopenharmony_ci 10098c2ecf20Sopenharmony_ci in_params.force_cmd = mfw_force_cmd; 10108c2ecf20Sopenharmony_ci memset(&out_params, 0, sizeof(out_params)); 10118c2ecf20Sopenharmony_ci rc = __qed_mcp_load_req(p_hwfn, p_ptt, &in_params, 10128c2ecf20Sopenharmony_ci &out_params); 10138c2ecf20Sopenharmony_ci if (rc) 10148c2ecf20Sopenharmony_ci return rc; 10158c2ecf20Sopenharmony_ci } else { 10168c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, 10178c2ecf20Sopenharmony_ci "A force load is required [{role, fw_ver, drv_ver}: loading={%d, 0x%08x, x%08x_0x%08x}, existing={%d, 0x%08x, 0x%08x_0x%08x}] - Avoid\n", 10188c2ecf20Sopenharmony_ci in_params.drv_role, in_params.fw_ver, 10198c2ecf20Sopenharmony_ci in_params.drv_ver_0, in_params.drv_ver_1, 10208c2ecf20Sopenharmony_ci out_params.exist_drv_role, 10218c2ecf20Sopenharmony_ci out_params.exist_fw_ver, 10228c2ecf20Sopenharmony_ci out_params.exist_drv_ver_0, 10238c2ecf20Sopenharmony_ci out_params.exist_drv_ver_1); 10248c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, 10258c2ecf20Sopenharmony_ci "Avoid sending a force load request to prevent disruption of active PFs\n"); 10268c2ecf20Sopenharmony_ci 10278c2ecf20Sopenharmony_ci qed_mcp_cancel_load_req(p_hwfn, p_ptt); 10288c2ecf20Sopenharmony_ci return -EBUSY; 10298c2ecf20Sopenharmony_ci } 10308c2ecf20Sopenharmony_ci } 10318c2ecf20Sopenharmony_ci 10328c2ecf20Sopenharmony_ci /* Now handle the other types of responses. 10338c2ecf20Sopenharmony_ci * The "REFUSED_HSI_1" and "REFUSED_REQUIRES_FORCE" responses are not 10348c2ecf20Sopenharmony_ci * expected here after the additional revised load requests were sent. 10358c2ecf20Sopenharmony_ci */ 10368c2ecf20Sopenharmony_ci switch (out_params.load_code) { 10378c2ecf20Sopenharmony_ci case FW_MSG_CODE_DRV_LOAD_ENGINE: 10388c2ecf20Sopenharmony_ci case FW_MSG_CODE_DRV_LOAD_PORT: 10398c2ecf20Sopenharmony_ci case FW_MSG_CODE_DRV_LOAD_FUNCTION: 10408c2ecf20Sopenharmony_ci if (out_params.mfw_hsi_ver != QED_LOAD_REQ_HSI_VER_1 && 10418c2ecf20Sopenharmony_ci out_params.drv_exists) { 10428c2ecf20Sopenharmony_ci /* The role and fw/driver version match, but the PF is 10438c2ecf20Sopenharmony_ci * already loaded and has not been unloaded gracefully. 10448c2ecf20Sopenharmony_ci */ 10458c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, 10468c2ecf20Sopenharmony_ci "PF is already loaded\n"); 10478c2ecf20Sopenharmony_ci return -EINVAL; 10488c2ecf20Sopenharmony_ci } 10498c2ecf20Sopenharmony_ci break; 10508c2ecf20Sopenharmony_ci default: 10518c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, 10528c2ecf20Sopenharmony_ci "Unexpected refusal to load request [resp 0x%08x]. Aborting.\n", 10538c2ecf20Sopenharmony_ci out_params.load_code); 10548c2ecf20Sopenharmony_ci return -EBUSY; 10558c2ecf20Sopenharmony_ci } 10568c2ecf20Sopenharmony_ci 10578c2ecf20Sopenharmony_ci p_params->load_code = out_params.load_code; 10588c2ecf20Sopenharmony_ci 10598c2ecf20Sopenharmony_ci return 0; 10608c2ecf20Sopenharmony_ci} 10618c2ecf20Sopenharmony_ci 10628c2ecf20Sopenharmony_ciint qed_mcp_load_done(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 10638c2ecf20Sopenharmony_ci{ 10648c2ecf20Sopenharmony_ci u32 resp = 0, param = 0; 10658c2ecf20Sopenharmony_ci int rc; 10668c2ecf20Sopenharmony_ci 10678c2ecf20Sopenharmony_ci rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_LOAD_DONE, 0, &resp, 10688c2ecf20Sopenharmony_ci ¶m); 10698c2ecf20Sopenharmony_ci if (rc) { 10708c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, 10718c2ecf20Sopenharmony_ci "Failed to send a LOAD_DONE command, rc = %d\n", rc); 10728c2ecf20Sopenharmony_ci return rc; 10738c2ecf20Sopenharmony_ci } 10748c2ecf20Sopenharmony_ci 10758c2ecf20Sopenharmony_ci /* Check if there is a DID mismatch between nvm-cfg/efuse */ 10768c2ecf20Sopenharmony_ci if (param & FW_MB_PARAM_LOAD_DONE_DID_EFUSE_ERROR) 10778c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, 10788c2ecf20Sopenharmony_ci "warning: device configuration is not supported on this board type. The device may not function as expected.\n"); 10798c2ecf20Sopenharmony_ci 10808c2ecf20Sopenharmony_ci return 0; 10818c2ecf20Sopenharmony_ci} 10828c2ecf20Sopenharmony_ci 10838c2ecf20Sopenharmony_ciint qed_mcp_unload_req(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 10848c2ecf20Sopenharmony_ci{ 10858c2ecf20Sopenharmony_ci struct qed_mcp_mb_params mb_params; 10868c2ecf20Sopenharmony_ci u32 wol_param; 10878c2ecf20Sopenharmony_ci 10888c2ecf20Sopenharmony_ci switch (p_hwfn->cdev->wol_config) { 10898c2ecf20Sopenharmony_ci case QED_OV_WOL_DISABLED: 10908c2ecf20Sopenharmony_ci wol_param = DRV_MB_PARAM_UNLOAD_WOL_DISABLED; 10918c2ecf20Sopenharmony_ci break; 10928c2ecf20Sopenharmony_ci case QED_OV_WOL_ENABLED: 10938c2ecf20Sopenharmony_ci wol_param = DRV_MB_PARAM_UNLOAD_WOL_ENABLED; 10948c2ecf20Sopenharmony_ci break; 10958c2ecf20Sopenharmony_ci default: 10968c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, 10978c2ecf20Sopenharmony_ci "Unknown WoL configuration %02x\n", 10988c2ecf20Sopenharmony_ci p_hwfn->cdev->wol_config); 10998c2ecf20Sopenharmony_ci fallthrough; 11008c2ecf20Sopenharmony_ci case QED_OV_WOL_DEFAULT: 11018c2ecf20Sopenharmony_ci wol_param = DRV_MB_PARAM_UNLOAD_WOL_MCP; 11028c2ecf20Sopenharmony_ci } 11038c2ecf20Sopenharmony_ci 11048c2ecf20Sopenharmony_ci memset(&mb_params, 0, sizeof(mb_params)); 11058c2ecf20Sopenharmony_ci mb_params.cmd = DRV_MSG_CODE_UNLOAD_REQ; 11068c2ecf20Sopenharmony_ci mb_params.param = wol_param; 11078c2ecf20Sopenharmony_ci mb_params.flags = QED_MB_FLAG_CAN_SLEEP | QED_MB_FLAG_AVOID_BLOCK; 11088c2ecf20Sopenharmony_ci 11098c2ecf20Sopenharmony_ci return qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 11108c2ecf20Sopenharmony_ci} 11118c2ecf20Sopenharmony_ci 11128c2ecf20Sopenharmony_ciint qed_mcp_unload_done(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 11138c2ecf20Sopenharmony_ci{ 11148c2ecf20Sopenharmony_ci struct qed_mcp_mb_params mb_params; 11158c2ecf20Sopenharmony_ci struct mcp_mac wol_mac; 11168c2ecf20Sopenharmony_ci 11178c2ecf20Sopenharmony_ci memset(&mb_params, 0, sizeof(mb_params)); 11188c2ecf20Sopenharmony_ci mb_params.cmd = DRV_MSG_CODE_UNLOAD_DONE; 11198c2ecf20Sopenharmony_ci 11208c2ecf20Sopenharmony_ci /* Set the primary MAC if WoL is enabled */ 11218c2ecf20Sopenharmony_ci if (p_hwfn->cdev->wol_config == QED_OV_WOL_ENABLED) { 11228c2ecf20Sopenharmony_ci u8 *p_mac = p_hwfn->cdev->wol_mac; 11238c2ecf20Sopenharmony_ci 11248c2ecf20Sopenharmony_ci memset(&wol_mac, 0, sizeof(wol_mac)); 11258c2ecf20Sopenharmony_ci wol_mac.mac_upper = p_mac[0] << 8 | p_mac[1]; 11268c2ecf20Sopenharmony_ci wol_mac.mac_lower = p_mac[2] << 24 | p_mac[3] << 16 | 11278c2ecf20Sopenharmony_ci p_mac[4] << 8 | p_mac[5]; 11288c2ecf20Sopenharmony_ci 11298c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, 11308c2ecf20Sopenharmony_ci (QED_MSG_SP | NETIF_MSG_IFDOWN), 11318c2ecf20Sopenharmony_ci "Setting WoL MAC: %pM --> [%08x,%08x]\n", 11328c2ecf20Sopenharmony_ci p_mac, wol_mac.mac_upper, wol_mac.mac_lower); 11338c2ecf20Sopenharmony_ci 11348c2ecf20Sopenharmony_ci mb_params.p_data_src = &wol_mac; 11358c2ecf20Sopenharmony_ci mb_params.data_src_size = sizeof(wol_mac); 11368c2ecf20Sopenharmony_ci } 11378c2ecf20Sopenharmony_ci 11388c2ecf20Sopenharmony_ci return qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 11398c2ecf20Sopenharmony_ci} 11408c2ecf20Sopenharmony_ci 11418c2ecf20Sopenharmony_cistatic void qed_mcp_handle_vf_flr(struct qed_hwfn *p_hwfn, 11428c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt) 11438c2ecf20Sopenharmony_ci{ 11448c2ecf20Sopenharmony_ci u32 addr = SECTION_OFFSIZE_ADDR(p_hwfn->mcp_info->public_base, 11458c2ecf20Sopenharmony_ci PUBLIC_PATH); 11468c2ecf20Sopenharmony_ci u32 mfw_path_offsize = qed_rd(p_hwfn, p_ptt, addr); 11478c2ecf20Sopenharmony_ci u32 path_addr = SECTION_ADDR(mfw_path_offsize, 11488c2ecf20Sopenharmony_ci QED_PATH_ID(p_hwfn)); 11498c2ecf20Sopenharmony_ci u32 disabled_vfs[VF_MAX_STATIC / 32]; 11508c2ecf20Sopenharmony_ci int i; 11518c2ecf20Sopenharmony_ci 11528c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, 11538c2ecf20Sopenharmony_ci QED_MSG_SP, 11548c2ecf20Sopenharmony_ci "Reading Disabled VF information from [offset %08x], path_addr %08x\n", 11558c2ecf20Sopenharmony_ci mfw_path_offsize, path_addr); 11568c2ecf20Sopenharmony_ci 11578c2ecf20Sopenharmony_ci for (i = 0; i < (VF_MAX_STATIC / 32); i++) { 11588c2ecf20Sopenharmony_ci disabled_vfs[i] = qed_rd(p_hwfn, p_ptt, 11598c2ecf20Sopenharmony_ci path_addr + 11608c2ecf20Sopenharmony_ci offsetof(struct public_path, 11618c2ecf20Sopenharmony_ci mcp_vf_disabled) + 11628c2ecf20Sopenharmony_ci sizeof(u32) * i); 11638c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, (QED_MSG_SP | QED_MSG_IOV), 11648c2ecf20Sopenharmony_ci "FLR-ed VFs [%08x,...,%08x] - %08x\n", 11658c2ecf20Sopenharmony_ci i * 32, (i + 1) * 32 - 1, disabled_vfs[i]); 11668c2ecf20Sopenharmony_ci } 11678c2ecf20Sopenharmony_ci 11688c2ecf20Sopenharmony_ci if (qed_iov_mark_vf_flr(p_hwfn, disabled_vfs)) 11698c2ecf20Sopenharmony_ci qed_schedule_iov(p_hwfn, QED_IOV_WQ_FLR_FLAG); 11708c2ecf20Sopenharmony_ci} 11718c2ecf20Sopenharmony_ci 11728c2ecf20Sopenharmony_ciint qed_mcp_ack_vf_flr(struct qed_hwfn *p_hwfn, 11738c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt, u32 *vfs_to_ack) 11748c2ecf20Sopenharmony_ci{ 11758c2ecf20Sopenharmony_ci u32 addr = SECTION_OFFSIZE_ADDR(p_hwfn->mcp_info->public_base, 11768c2ecf20Sopenharmony_ci PUBLIC_FUNC); 11778c2ecf20Sopenharmony_ci u32 mfw_func_offsize = qed_rd(p_hwfn, p_ptt, addr); 11788c2ecf20Sopenharmony_ci u32 func_addr = SECTION_ADDR(mfw_func_offsize, 11798c2ecf20Sopenharmony_ci MCP_PF_ID(p_hwfn)); 11808c2ecf20Sopenharmony_ci struct qed_mcp_mb_params mb_params; 11818c2ecf20Sopenharmony_ci int rc; 11828c2ecf20Sopenharmony_ci int i; 11838c2ecf20Sopenharmony_ci 11848c2ecf20Sopenharmony_ci for (i = 0; i < (VF_MAX_STATIC / 32); i++) 11858c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, (QED_MSG_SP | QED_MSG_IOV), 11868c2ecf20Sopenharmony_ci "Acking VFs [%08x,...,%08x] - %08x\n", 11878c2ecf20Sopenharmony_ci i * 32, (i + 1) * 32 - 1, vfs_to_ack[i]); 11888c2ecf20Sopenharmony_ci 11898c2ecf20Sopenharmony_ci memset(&mb_params, 0, sizeof(mb_params)); 11908c2ecf20Sopenharmony_ci mb_params.cmd = DRV_MSG_CODE_VF_DISABLED_DONE; 11918c2ecf20Sopenharmony_ci mb_params.p_data_src = vfs_to_ack; 11928c2ecf20Sopenharmony_ci mb_params.data_src_size = VF_MAX_STATIC / 8; 11938c2ecf20Sopenharmony_ci rc = qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 11948c2ecf20Sopenharmony_ci if (rc) { 11958c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, "Failed to pass ACK for VF flr to MFW\n"); 11968c2ecf20Sopenharmony_ci return -EBUSY; 11978c2ecf20Sopenharmony_ci } 11988c2ecf20Sopenharmony_ci 11998c2ecf20Sopenharmony_ci /* Clear the ACK bits */ 12008c2ecf20Sopenharmony_ci for (i = 0; i < (VF_MAX_STATIC / 32); i++) 12018c2ecf20Sopenharmony_ci qed_wr(p_hwfn, p_ptt, 12028c2ecf20Sopenharmony_ci func_addr + 12038c2ecf20Sopenharmony_ci offsetof(struct public_func, drv_ack_vf_disabled) + 12048c2ecf20Sopenharmony_ci i * sizeof(u32), 0); 12058c2ecf20Sopenharmony_ci 12068c2ecf20Sopenharmony_ci return rc; 12078c2ecf20Sopenharmony_ci} 12088c2ecf20Sopenharmony_ci 12098c2ecf20Sopenharmony_cistatic void qed_mcp_handle_transceiver_change(struct qed_hwfn *p_hwfn, 12108c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt) 12118c2ecf20Sopenharmony_ci{ 12128c2ecf20Sopenharmony_ci u32 transceiver_state; 12138c2ecf20Sopenharmony_ci 12148c2ecf20Sopenharmony_ci transceiver_state = qed_rd(p_hwfn, p_ptt, 12158c2ecf20Sopenharmony_ci p_hwfn->mcp_info->port_addr + 12168c2ecf20Sopenharmony_ci offsetof(struct public_port, 12178c2ecf20Sopenharmony_ci transceiver_data)); 12188c2ecf20Sopenharmony_ci 12198c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, 12208c2ecf20Sopenharmony_ci (NETIF_MSG_HW | QED_MSG_SP), 12218c2ecf20Sopenharmony_ci "Received transceiver state update [0x%08x] from mfw [Addr 0x%x]\n", 12228c2ecf20Sopenharmony_ci transceiver_state, 12238c2ecf20Sopenharmony_ci (u32)(p_hwfn->mcp_info->port_addr + 12248c2ecf20Sopenharmony_ci offsetof(struct public_port, transceiver_data))); 12258c2ecf20Sopenharmony_ci 12268c2ecf20Sopenharmony_ci transceiver_state = GET_FIELD(transceiver_state, 12278c2ecf20Sopenharmony_ci ETH_TRANSCEIVER_STATE); 12288c2ecf20Sopenharmony_ci 12298c2ecf20Sopenharmony_ci if (transceiver_state == ETH_TRANSCEIVER_STATE_PRESENT) 12308c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, "Transceiver is present.\n"); 12318c2ecf20Sopenharmony_ci else 12328c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, "Transceiver is unplugged.\n"); 12338c2ecf20Sopenharmony_ci} 12348c2ecf20Sopenharmony_ci 12358c2ecf20Sopenharmony_cistatic void qed_mcp_read_eee_config(struct qed_hwfn *p_hwfn, 12368c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt, 12378c2ecf20Sopenharmony_ci struct qed_mcp_link_state *p_link) 12388c2ecf20Sopenharmony_ci{ 12398c2ecf20Sopenharmony_ci u32 eee_status, val; 12408c2ecf20Sopenharmony_ci 12418c2ecf20Sopenharmony_ci p_link->eee_adv_caps = 0; 12428c2ecf20Sopenharmony_ci p_link->eee_lp_adv_caps = 0; 12438c2ecf20Sopenharmony_ci eee_status = qed_rd(p_hwfn, 12448c2ecf20Sopenharmony_ci p_ptt, 12458c2ecf20Sopenharmony_ci p_hwfn->mcp_info->port_addr + 12468c2ecf20Sopenharmony_ci offsetof(struct public_port, eee_status)); 12478c2ecf20Sopenharmony_ci p_link->eee_active = !!(eee_status & EEE_ACTIVE_BIT); 12488c2ecf20Sopenharmony_ci val = (eee_status & EEE_LD_ADV_STATUS_MASK) >> EEE_LD_ADV_STATUS_OFFSET; 12498c2ecf20Sopenharmony_ci if (val & EEE_1G_ADV) 12508c2ecf20Sopenharmony_ci p_link->eee_adv_caps |= QED_EEE_1G_ADV; 12518c2ecf20Sopenharmony_ci if (val & EEE_10G_ADV) 12528c2ecf20Sopenharmony_ci p_link->eee_adv_caps |= QED_EEE_10G_ADV; 12538c2ecf20Sopenharmony_ci val = (eee_status & EEE_LP_ADV_STATUS_MASK) >> EEE_LP_ADV_STATUS_OFFSET; 12548c2ecf20Sopenharmony_ci if (val & EEE_1G_ADV) 12558c2ecf20Sopenharmony_ci p_link->eee_lp_adv_caps |= QED_EEE_1G_ADV; 12568c2ecf20Sopenharmony_ci if (val & EEE_10G_ADV) 12578c2ecf20Sopenharmony_ci p_link->eee_lp_adv_caps |= QED_EEE_10G_ADV; 12588c2ecf20Sopenharmony_ci} 12598c2ecf20Sopenharmony_ci 12608c2ecf20Sopenharmony_cistatic u32 qed_mcp_get_shmem_func(struct qed_hwfn *p_hwfn, 12618c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt, 12628c2ecf20Sopenharmony_ci struct public_func *p_data, int pfid) 12638c2ecf20Sopenharmony_ci{ 12648c2ecf20Sopenharmony_ci u32 addr = SECTION_OFFSIZE_ADDR(p_hwfn->mcp_info->public_base, 12658c2ecf20Sopenharmony_ci PUBLIC_FUNC); 12668c2ecf20Sopenharmony_ci u32 mfw_path_offsize = qed_rd(p_hwfn, p_ptt, addr); 12678c2ecf20Sopenharmony_ci u32 func_addr; 12688c2ecf20Sopenharmony_ci u32 i, size; 12698c2ecf20Sopenharmony_ci 12708c2ecf20Sopenharmony_ci func_addr = SECTION_ADDR(mfw_path_offsize, pfid); 12718c2ecf20Sopenharmony_ci memset(p_data, 0, sizeof(*p_data)); 12728c2ecf20Sopenharmony_ci 12738c2ecf20Sopenharmony_ci size = min_t(u32, sizeof(*p_data), QED_SECTION_SIZE(mfw_path_offsize)); 12748c2ecf20Sopenharmony_ci for (i = 0; i < size / sizeof(u32); i++) 12758c2ecf20Sopenharmony_ci ((u32 *)p_data)[i] = qed_rd(p_hwfn, p_ptt, 12768c2ecf20Sopenharmony_ci func_addr + (i << 2)); 12778c2ecf20Sopenharmony_ci return size; 12788c2ecf20Sopenharmony_ci} 12798c2ecf20Sopenharmony_ci 12808c2ecf20Sopenharmony_cistatic void qed_read_pf_bandwidth(struct qed_hwfn *p_hwfn, 12818c2ecf20Sopenharmony_ci struct public_func *p_shmem_info) 12828c2ecf20Sopenharmony_ci{ 12838c2ecf20Sopenharmony_ci struct qed_mcp_function_info *p_info; 12848c2ecf20Sopenharmony_ci 12858c2ecf20Sopenharmony_ci p_info = &p_hwfn->mcp_info->func_info; 12868c2ecf20Sopenharmony_ci 12878c2ecf20Sopenharmony_ci p_info->bandwidth_min = QED_MFW_GET_FIELD(p_shmem_info->config, 12888c2ecf20Sopenharmony_ci FUNC_MF_CFG_MIN_BW); 12898c2ecf20Sopenharmony_ci if (p_info->bandwidth_min < 1 || p_info->bandwidth_min > 100) { 12908c2ecf20Sopenharmony_ci DP_INFO(p_hwfn, 12918c2ecf20Sopenharmony_ci "bandwidth minimum out of bounds [%02x]. Set to 1\n", 12928c2ecf20Sopenharmony_ci p_info->bandwidth_min); 12938c2ecf20Sopenharmony_ci p_info->bandwidth_min = 1; 12948c2ecf20Sopenharmony_ci } 12958c2ecf20Sopenharmony_ci 12968c2ecf20Sopenharmony_ci p_info->bandwidth_max = QED_MFW_GET_FIELD(p_shmem_info->config, 12978c2ecf20Sopenharmony_ci FUNC_MF_CFG_MAX_BW); 12988c2ecf20Sopenharmony_ci if (p_info->bandwidth_max < 1 || p_info->bandwidth_max > 100) { 12998c2ecf20Sopenharmony_ci DP_INFO(p_hwfn, 13008c2ecf20Sopenharmony_ci "bandwidth maximum out of bounds [%02x]. Set to 100\n", 13018c2ecf20Sopenharmony_ci p_info->bandwidth_max); 13028c2ecf20Sopenharmony_ci p_info->bandwidth_max = 100; 13038c2ecf20Sopenharmony_ci } 13048c2ecf20Sopenharmony_ci} 13058c2ecf20Sopenharmony_ci 13068c2ecf20Sopenharmony_cistatic void qed_mcp_handle_link_change(struct qed_hwfn *p_hwfn, 13078c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt, bool b_reset) 13088c2ecf20Sopenharmony_ci{ 13098c2ecf20Sopenharmony_ci struct qed_mcp_link_state *p_link; 13108c2ecf20Sopenharmony_ci u8 max_bw, min_bw; 13118c2ecf20Sopenharmony_ci u32 status = 0; 13128c2ecf20Sopenharmony_ci 13138c2ecf20Sopenharmony_ci /* Prevent SW/attentions from doing this at the same time */ 13148c2ecf20Sopenharmony_ci spin_lock_bh(&p_hwfn->mcp_info->link_lock); 13158c2ecf20Sopenharmony_ci 13168c2ecf20Sopenharmony_ci p_link = &p_hwfn->mcp_info->link_output; 13178c2ecf20Sopenharmony_ci memset(p_link, 0, sizeof(*p_link)); 13188c2ecf20Sopenharmony_ci if (!b_reset) { 13198c2ecf20Sopenharmony_ci status = qed_rd(p_hwfn, p_ptt, 13208c2ecf20Sopenharmony_ci p_hwfn->mcp_info->port_addr + 13218c2ecf20Sopenharmony_ci offsetof(struct public_port, link_status)); 13228c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, (NETIF_MSG_LINK | QED_MSG_SP), 13238c2ecf20Sopenharmony_ci "Received link update [0x%08x] from mfw [Addr 0x%x]\n", 13248c2ecf20Sopenharmony_ci status, 13258c2ecf20Sopenharmony_ci (u32)(p_hwfn->mcp_info->port_addr + 13268c2ecf20Sopenharmony_ci offsetof(struct public_port, link_status))); 13278c2ecf20Sopenharmony_ci } else { 13288c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, NETIF_MSG_LINK, 13298c2ecf20Sopenharmony_ci "Resetting link indications\n"); 13308c2ecf20Sopenharmony_ci goto out; 13318c2ecf20Sopenharmony_ci } 13328c2ecf20Sopenharmony_ci 13338c2ecf20Sopenharmony_ci if (p_hwfn->b_drv_link_init) { 13348c2ecf20Sopenharmony_ci /* Link indication with modern MFW arrives as per-PF 13358c2ecf20Sopenharmony_ci * indication. 13368c2ecf20Sopenharmony_ci */ 13378c2ecf20Sopenharmony_ci if (p_hwfn->mcp_info->capabilities & 13388c2ecf20Sopenharmony_ci FW_MB_PARAM_FEATURE_SUPPORT_VLINK) { 13398c2ecf20Sopenharmony_ci struct public_func shmem_info; 13408c2ecf20Sopenharmony_ci 13418c2ecf20Sopenharmony_ci qed_mcp_get_shmem_func(p_hwfn, p_ptt, &shmem_info, 13428c2ecf20Sopenharmony_ci MCP_PF_ID(p_hwfn)); 13438c2ecf20Sopenharmony_ci p_link->link_up = !!(shmem_info.status & 13448c2ecf20Sopenharmony_ci FUNC_STATUS_VIRTUAL_LINK_UP); 13458c2ecf20Sopenharmony_ci qed_read_pf_bandwidth(p_hwfn, &shmem_info); 13468c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, NETIF_MSG_LINK, 13478c2ecf20Sopenharmony_ci "Virtual link_up = %d\n", p_link->link_up); 13488c2ecf20Sopenharmony_ci } else { 13498c2ecf20Sopenharmony_ci p_link->link_up = !!(status & LINK_STATUS_LINK_UP); 13508c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, NETIF_MSG_LINK, 13518c2ecf20Sopenharmony_ci "Physical link_up = %d\n", p_link->link_up); 13528c2ecf20Sopenharmony_ci } 13538c2ecf20Sopenharmony_ci } else { 13548c2ecf20Sopenharmony_ci p_link->link_up = false; 13558c2ecf20Sopenharmony_ci } 13568c2ecf20Sopenharmony_ci 13578c2ecf20Sopenharmony_ci p_link->full_duplex = true; 13588c2ecf20Sopenharmony_ci switch ((status & LINK_STATUS_SPEED_AND_DUPLEX_MASK)) { 13598c2ecf20Sopenharmony_ci case LINK_STATUS_SPEED_AND_DUPLEX_100G: 13608c2ecf20Sopenharmony_ci p_link->speed = 100000; 13618c2ecf20Sopenharmony_ci break; 13628c2ecf20Sopenharmony_ci case LINK_STATUS_SPEED_AND_DUPLEX_50G: 13638c2ecf20Sopenharmony_ci p_link->speed = 50000; 13648c2ecf20Sopenharmony_ci break; 13658c2ecf20Sopenharmony_ci case LINK_STATUS_SPEED_AND_DUPLEX_40G: 13668c2ecf20Sopenharmony_ci p_link->speed = 40000; 13678c2ecf20Sopenharmony_ci break; 13688c2ecf20Sopenharmony_ci case LINK_STATUS_SPEED_AND_DUPLEX_25G: 13698c2ecf20Sopenharmony_ci p_link->speed = 25000; 13708c2ecf20Sopenharmony_ci break; 13718c2ecf20Sopenharmony_ci case LINK_STATUS_SPEED_AND_DUPLEX_20G: 13728c2ecf20Sopenharmony_ci p_link->speed = 20000; 13738c2ecf20Sopenharmony_ci break; 13748c2ecf20Sopenharmony_ci case LINK_STATUS_SPEED_AND_DUPLEX_10G: 13758c2ecf20Sopenharmony_ci p_link->speed = 10000; 13768c2ecf20Sopenharmony_ci break; 13778c2ecf20Sopenharmony_ci case LINK_STATUS_SPEED_AND_DUPLEX_1000THD: 13788c2ecf20Sopenharmony_ci p_link->full_duplex = false; 13798c2ecf20Sopenharmony_ci fallthrough; 13808c2ecf20Sopenharmony_ci case LINK_STATUS_SPEED_AND_DUPLEX_1000TFD: 13818c2ecf20Sopenharmony_ci p_link->speed = 1000; 13828c2ecf20Sopenharmony_ci break; 13838c2ecf20Sopenharmony_ci default: 13848c2ecf20Sopenharmony_ci p_link->speed = 0; 13858c2ecf20Sopenharmony_ci p_link->link_up = 0; 13868c2ecf20Sopenharmony_ci } 13878c2ecf20Sopenharmony_ci 13888c2ecf20Sopenharmony_ci if (p_link->link_up && p_link->speed) 13898c2ecf20Sopenharmony_ci p_link->line_speed = p_link->speed; 13908c2ecf20Sopenharmony_ci else 13918c2ecf20Sopenharmony_ci p_link->line_speed = 0; 13928c2ecf20Sopenharmony_ci 13938c2ecf20Sopenharmony_ci max_bw = p_hwfn->mcp_info->func_info.bandwidth_max; 13948c2ecf20Sopenharmony_ci min_bw = p_hwfn->mcp_info->func_info.bandwidth_min; 13958c2ecf20Sopenharmony_ci 13968c2ecf20Sopenharmony_ci /* Max bandwidth configuration */ 13978c2ecf20Sopenharmony_ci __qed_configure_pf_max_bandwidth(p_hwfn, p_ptt, p_link, max_bw); 13988c2ecf20Sopenharmony_ci 13998c2ecf20Sopenharmony_ci /* Min bandwidth configuration */ 14008c2ecf20Sopenharmony_ci __qed_configure_pf_min_bandwidth(p_hwfn, p_ptt, p_link, min_bw); 14018c2ecf20Sopenharmony_ci qed_configure_vp_wfq_on_link_change(p_hwfn->cdev, p_ptt, 14028c2ecf20Sopenharmony_ci p_link->min_pf_rate); 14038c2ecf20Sopenharmony_ci 14048c2ecf20Sopenharmony_ci p_link->an = !!(status & LINK_STATUS_AUTO_NEGOTIATE_ENABLED); 14058c2ecf20Sopenharmony_ci p_link->an_complete = !!(status & 14068c2ecf20Sopenharmony_ci LINK_STATUS_AUTO_NEGOTIATE_COMPLETE); 14078c2ecf20Sopenharmony_ci p_link->parallel_detection = !!(status & 14088c2ecf20Sopenharmony_ci LINK_STATUS_PARALLEL_DETECTION_USED); 14098c2ecf20Sopenharmony_ci p_link->pfc_enabled = !!(status & LINK_STATUS_PFC_ENABLED); 14108c2ecf20Sopenharmony_ci 14118c2ecf20Sopenharmony_ci p_link->partner_adv_speed |= 14128c2ecf20Sopenharmony_ci (status & LINK_STATUS_LINK_PARTNER_1000TFD_CAPABLE) ? 14138c2ecf20Sopenharmony_ci QED_LINK_PARTNER_SPEED_1G_FD : 0; 14148c2ecf20Sopenharmony_ci p_link->partner_adv_speed |= 14158c2ecf20Sopenharmony_ci (status & LINK_STATUS_LINK_PARTNER_1000THD_CAPABLE) ? 14168c2ecf20Sopenharmony_ci QED_LINK_PARTNER_SPEED_1G_HD : 0; 14178c2ecf20Sopenharmony_ci p_link->partner_adv_speed |= 14188c2ecf20Sopenharmony_ci (status & LINK_STATUS_LINK_PARTNER_10G_CAPABLE) ? 14198c2ecf20Sopenharmony_ci QED_LINK_PARTNER_SPEED_10G : 0; 14208c2ecf20Sopenharmony_ci p_link->partner_adv_speed |= 14218c2ecf20Sopenharmony_ci (status & LINK_STATUS_LINK_PARTNER_20G_CAPABLE) ? 14228c2ecf20Sopenharmony_ci QED_LINK_PARTNER_SPEED_20G : 0; 14238c2ecf20Sopenharmony_ci p_link->partner_adv_speed |= 14248c2ecf20Sopenharmony_ci (status & LINK_STATUS_LINK_PARTNER_25G_CAPABLE) ? 14258c2ecf20Sopenharmony_ci QED_LINK_PARTNER_SPEED_25G : 0; 14268c2ecf20Sopenharmony_ci p_link->partner_adv_speed |= 14278c2ecf20Sopenharmony_ci (status & LINK_STATUS_LINK_PARTNER_40G_CAPABLE) ? 14288c2ecf20Sopenharmony_ci QED_LINK_PARTNER_SPEED_40G : 0; 14298c2ecf20Sopenharmony_ci p_link->partner_adv_speed |= 14308c2ecf20Sopenharmony_ci (status & LINK_STATUS_LINK_PARTNER_50G_CAPABLE) ? 14318c2ecf20Sopenharmony_ci QED_LINK_PARTNER_SPEED_50G : 0; 14328c2ecf20Sopenharmony_ci p_link->partner_adv_speed |= 14338c2ecf20Sopenharmony_ci (status & LINK_STATUS_LINK_PARTNER_100G_CAPABLE) ? 14348c2ecf20Sopenharmony_ci QED_LINK_PARTNER_SPEED_100G : 0; 14358c2ecf20Sopenharmony_ci 14368c2ecf20Sopenharmony_ci p_link->partner_tx_flow_ctrl_en = 14378c2ecf20Sopenharmony_ci !!(status & LINK_STATUS_TX_FLOW_CONTROL_ENABLED); 14388c2ecf20Sopenharmony_ci p_link->partner_rx_flow_ctrl_en = 14398c2ecf20Sopenharmony_ci !!(status & LINK_STATUS_RX_FLOW_CONTROL_ENABLED); 14408c2ecf20Sopenharmony_ci 14418c2ecf20Sopenharmony_ci switch (status & LINK_STATUS_LINK_PARTNER_FLOW_CONTROL_MASK) { 14428c2ecf20Sopenharmony_ci case LINK_STATUS_LINK_PARTNER_SYMMETRIC_PAUSE: 14438c2ecf20Sopenharmony_ci p_link->partner_adv_pause = QED_LINK_PARTNER_SYMMETRIC_PAUSE; 14448c2ecf20Sopenharmony_ci break; 14458c2ecf20Sopenharmony_ci case LINK_STATUS_LINK_PARTNER_ASYMMETRIC_PAUSE: 14468c2ecf20Sopenharmony_ci p_link->partner_adv_pause = QED_LINK_PARTNER_ASYMMETRIC_PAUSE; 14478c2ecf20Sopenharmony_ci break; 14488c2ecf20Sopenharmony_ci case LINK_STATUS_LINK_PARTNER_BOTH_PAUSE: 14498c2ecf20Sopenharmony_ci p_link->partner_adv_pause = QED_LINK_PARTNER_BOTH_PAUSE; 14508c2ecf20Sopenharmony_ci break; 14518c2ecf20Sopenharmony_ci default: 14528c2ecf20Sopenharmony_ci p_link->partner_adv_pause = 0; 14538c2ecf20Sopenharmony_ci } 14548c2ecf20Sopenharmony_ci 14558c2ecf20Sopenharmony_ci p_link->sfp_tx_fault = !!(status & LINK_STATUS_SFP_TX_FAULT); 14568c2ecf20Sopenharmony_ci 14578c2ecf20Sopenharmony_ci if (p_hwfn->mcp_info->capabilities & FW_MB_PARAM_FEATURE_SUPPORT_EEE) 14588c2ecf20Sopenharmony_ci qed_mcp_read_eee_config(p_hwfn, p_ptt, p_link); 14598c2ecf20Sopenharmony_ci 14608c2ecf20Sopenharmony_ci if (p_hwfn->mcp_info->capabilities & 14618c2ecf20Sopenharmony_ci FW_MB_PARAM_FEATURE_SUPPORT_FEC_CONTROL) { 14628c2ecf20Sopenharmony_ci switch (status & LINK_STATUS_FEC_MODE_MASK) { 14638c2ecf20Sopenharmony_ci case LINK_STATUS_FEC_MODE_NONE: 14648c2ecf20Sopenharmony_ci p_link->fec_active = QED_FEC_MODE_NONE; 14658c2ecf20Sopenharmony_ci break; 14668c2ecf20Sopenharmony_ci case LINK_STATUS_FEC_MODE_FIRECODE_CL74: 14678c2ecf20Sopenharmony_ci p_link->fec_active = QED_FEC_MODE_FIRECODE; 14688c2ecf20Sopenharmony_ci break; 14698c2ecf20Sopenharmony_ci case LINK_STATUS_FEC_MODE_RS_CL91: 14708c2ecf20Sopenharmony_ci p_link->fec_active = QED_FEC_MODE_RS; 14718c2ecf20Sopenharmony_ci break; 14728c2ecf20Sopenharmony_ci default: 14738c2ecf20Sopenharmony_ci p_link->fec_active = QED_FEC_MODE_AUTO; 14748c2ecf20Sopenharmony_ci } 14758c2ecf20Sopenharmony_ci } else { 14768c2ecf20Sopenharmony_ci p_link->fec_active = QED_FEC_MODE_UNSUPPORTED; 14778c2ecf20Sopenharmony_ci } 14788c2ecf20Sopenharmony_ci 14798c2ecf20Sopenharmony_ci qed_link_update(p_hwfn, p_ptt); 14808c2ecf20Sopenharmony_ciout: 14818c2ecf20Sopenharmony_ci spin_unlock_bh(&p_hwfn->mcp_info->link_lock); 14828c2ecf20Sopenharmony_ci} 14838c2ecf20Sopenharmony_ci 14848c2ecf20Sopenharmony_ciint qed_mcp_set_link(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, bool b_up) 14858c2ecf20Sopenharmony_ci{ 14868c2ecf20Sopenharmony_ci struct qed_mcp_link_params *params = &p_hwfn->mcp_info->link_input; 14878c2ecf20Sopenharmony_ci struct qed_mcp_mb_params mb_params; 14888c2ecf20Sopenharmony_ci struct eth_phy_cfg phy_cfg; 14898c2ecf20Sopenharmony_ci u32 cmd, fec_bit = 0; 14908c2ecf20Sopenharmony_ci u32 val, ext_speed; 14918c2ecf20Sopenharmony_ci int rc = 0; 14928c2ecf20Sopenharmony_ci 14938c2ecf20Sopenharmony_ci /* Set the shmem configuration according to params */ 14948c2ecf20Sopenharmony_ci memset(&phy_cfg, 0, sizeof(phy_cfg)); 14958c2ecf20Sopenharmony_ci cmd = b_up ? DRV_MSG_CODE_INIT_PHY : DRV_MSG_CODE_LINK_RESET; 14968c2ecf20Sopenharmony_ci if (!params->speed.autoneg) 14978c2ecf20Sopenharmony_ci phy_cfg.speed = params->speed.forced_speed; 14988c2ecf20Sopenharmony_ci phy_cfg.pause |= (params->pause.autoneg) ? ETH_PAUSE_AUTONEG : 0; 14998c2ecf20Sopenharmony_ci phy_cfg.pause |= (params->pause.forced_rx) ? ETH_PAUSE_RX : 0; 15008c2ecf20Sopenharmony_ci phy_cfg.pause |= (params->pause.forced_tx) ? ETH_PAUSE_TX : 0; 15018c2ecf20Sopenharmony_ci phy_cfg.adv_speed = params->speed.advertised_speeds; 15028c2ecf20Sopenharmony_ci phy_cfg.loopback_mode = params->loopback_mode; 15038c2ecf20Sopenharmony_ci 15048c2ecf20Sopenharmony_ci /* There are MFWs that share this capability regardless of whether 15058c2ecf20Sopenharmony_ci * this is feasible or not. And given that at the very least adv_caps 15068c2ecf20Sopenharmony_ci * would be set internally by qed, we want to make sure LFA would 15078c2ecf20Sopenharmony_ci * still work. 15088c2ecf20Sopenharmony_ci */ 15098c2ecf20Sopenharmony_ci if ((p_hwfn->mcp_info->capabilities & 15108c2ecf20Sopenharmony_ci FW_MB_PARAM_FEATURE_SUPPORT_EEE) && params->eee.enable) { 15118c2ecf20Sopenharmony_ci phy_cfg.eee_cfg |= EEE_CFG_EEE_ENABLED; 15128c2ecf20Sopenharmony_ci if (params->eee.tx_lpi_enable) 15138c2ecf20Sopenharmony_ci phy_cfg.eee_cfg |= EEE_CFG_TX_LPI; 15148c2ecf20Sopenharmony_ci if (params->eee.adv_caps & QED_EEE_1G_ADV) 15158c2ecf20Sopenharmony_ci phy_cfg.eee_cfg |= EEE_CFG_ADV_SPEED_1G; 15168c2ecf20Sopenharmony_ci if (params->eee.adv_caps & QED_EEE_10G_ADV) 15178c2ecf20Sopenharmony_ci phy_cfg.eee_cfg |= EEE_CFG_ADV_SPEED_10G; 15188c2ecf20Sopenharmony_ci phy_cfg.eee_cfg |= (params->eee.tx_lpi_timer << 15198c2ecf20Sopenharmony_ci EEE_TX_TIMER_USEC_OFFSET) & 15208c2ecf20Sopenharmony_ci EEE_TX_TIMER_USEC_MASK; 15218c2ecf20Sopenharmony_ci } 15228c2ecf20Sopenharmony_ci 15238c2ecf20Sopenharmony_ci if (p_hwfn->mcp_info->capabilities & 15248c2ecf20Sopenharmony_ci FW_MB_PARAM_FEATURE_SUPPORT_FEC_CONTROL) { 15258c2ecf20Sopenharmony_ci if (params->fec & QED_FEC_MODE_NONE) 15268c2ecf20Sopenharmony_ci fec_bit |= FEC_FORCE_MODE_NONE; 15278c2ecf20Sopenharmony_ci else if (params->fec & QED_FEC_MODE_FIRECODE) 15288c2ecf20Sopenharmony_ci fec_bit |= FEC_FORCE_MODE_FIRECODE; 15298c2ecf20Sopenharmony_ci else if (params->fec & QED_FEC_MODE_RS) 15308c2ecf20Sopenharmony_ci fec_bit |= FEC_FORCE_MODE_RS; 15318c2ecf20Sopenharmony_ci else if (params->fec & QED_FEC_MODE_AUTO) 15328c2ecf20Sopenharmony_ci fec_bit |= FEC_FORCE_MODE_AUTO; 15338c2ecf20Sopenharmony_ci 15348c2ecf20Sopenharmony_ci SET_MFW_FIELD(phy_cfg.fec_mode, FEC_FORCE_MODE, fec_bit); 15358c2ecf20Sopenharmony_ci } 15368c2ecf20Sopenharmony_ci 15378c2ecf20Sopenharmony_ci if (p_hwfn->mcp_info->capabilities & 15388c2ecf20Sopenharmony_ci FW_MB_PARAM_FEATURE_SUPPORT_EXT_SPEED_FEC_CONTROL) { 15398c2ecf20Sopenharmony_ci ext_speed = 0; 15408c2ecf20Sopenharmony_ci if (params->ext_speed.autoneg) 15418c2ecf20Sopenharmony_ci ext_speed |= ETH_EXT_SPEED_AN; 15428c2ecf20Sopenharmony_ci 15438c2ecf20Sopenharmony_ci val = params->ext_speed.forced_speed; 15448c2ecf20Sopenharmony_ci if (val & QED_EXT_SPEED_1G) 15458c2ecf20Sopenharmony_ci ext_speed |= ETH_EXT_SPEED_1G; 15468c2ecf20Sopenharmony_ci if (val & QED_EXT_SPEED_10G) 15478c2ecf20Sopenharmony_ci ext_speed |= ETH_EXT_SPEED_10G; 15488c2ecf20Sopenharmony_ci if (val & QED_EXT_SPEED_20G) 15498c2ecf20Sopenharmony_ci ext_speed |= ETH_EXT_SPEED_20G; 15508c2ecf20Sopenharmony_ci if (val & QED_EXT_SPEED_25G) 15518c2ecf20Sopenharmony_ci ext_speed |= ETH_EXT_SPEED_25G; 15528c2ecf20Sopenharmony_ci if (val & QED_EXT_SPEED_40G) 15538c2ecf20Sopenharmony_ci ext_speed |= ETH_EXT_SPEED_40G; 15548c2ecf20Sopenharmony_ci if (val & QED_EXT_SPEED_50G_R) 15558c2ecf20Sopenharmony_ci ext_speed |= ETH_EXT_SPEED_50G_BASE_R; 15568c2ecf20Sopenharmony_ci if (val & QED_EXT_SPEED_50G_R2) 15578c2ecf20Sopenharmony_ci ext_speed |= ETH_EXT_SPEED_50G_BASE_R2; 15588c2ecf20Sopenharmony_ci if (val & QED_EXT_SPEED_100G_R2) 15598c2ecf20Sopenharmony_ci ext_speed |= ETH_EXT_SPEED_100G_BASE_R2; 15608c2ecf20Sopenharmony_ci if (val & QED_EXT_SPEED_100G_R4) 15618c2ecf20Sopenharmony_ci ext_speed |= ETH_EXT_SPEED_100G_BASE_R4; 15628c2ecf20Sopenharmony_ci if (val & QED_EXT_SPEED_100G_P4) 15638c2ecf20Sopenharmony_ci ext_speed |= ETH_EXT_SPEED_100G_BASE_P4; 15648c2ecf20Sopenharmony_ci 15658c2ecf20Sopenharmony_ci SET_MFW_FIELD(phy_cfg.extended_speed, ETH_EXT_SPEED, 15668c2ecf20Sopenharmony_ci ext_speed); 15678c2ecf20Sopenharmony_ci 15688c2ecf20Sopenharmony_ci ext_speed = 0; 15698c2ecf20Sopenharmony_ci 15708c2ecf20Sopenharmony_ci val = params->ext_speed.advertised_speeds; 15718c2ecf20Sopenharmony_ci if (val & QED_EXT_SPEED_MASK_1G) 15728c2ecf20Sopenharmony_ci ext_speed |= ETH_EXT_ADV_SPEED_1G; 15738c2ecf20Sopenharmony_ci if (val & QED_EXT_SPEED_MASK_10G) 15748c2ecf20Sopenharmony_ci ext_speed |= ETH_EXT_ADV_SPEED_10G; 15758c2ecf20Sopenharmony_ci if (val & QED_EXT_SPEED_MASK_20G) 15768c2ecf20Sopenharmony_ci ext_speed |= ETH_EXT_ADV_SPEED_20G; 15778c2ecf20Sopenharmony_ci if (val & QED_EXT_SPEED_MASK_25G) 15788c2ecf20Sopenharmony_ci ext_speed |= ETH_EXT_ADV_SPEED_25G; 15798c2ecf20Sopenharmony_ci if (val & QED_EXT_SPEED_MASK_40G) 15808c2ecf20Sopenharmony_ci ext_speed |= ETH_EXT_ADV_SPEED_40G; 15818c2ecf20Sopenharmony_ci if (val & QED_EXT_SPEED_MASK_50G_R) 15828c2ecf20Sopenharmony_ci ext_speed |= ETH_EXT_ADV_SPEED_50G_BASE_R; 15838c2ecf20Sopenharmony_ci if (val & QED_EXT_SPEED_MASK_50G_R2) 15848c2ecf20Sopenharmony_ci ext_speed |= ETH_EXT_ADV_SPEED_50G_BASE_R2; 15858c2ecf20Sopenharmony_ci if (val & QED_EXT_SPEED_MASK_100G_R2) 15868c2ecf20Sopenharmony_ci ext_speed |= ETH_EXT_ADV_SPEED_100G_BASE_R2; 15878c2ecf20Sopenharmony_ci if (val & QED_EXT_SPEED_MASK_100G_R4) 15888c2ecf20Sopenharmony_ci ext_speed |= ETH_EXT_ADV_SPEED_100G_BASE_R4; 15898c2ecf20Sopenharmony_ci if (val & QED_EXT_SPEED_MASK_100G_P4) 15908c2ecf20Sopenharmony_ci ext_speed |= ETH_EXT_ADV_SPEED_100G_BASE_P4; 15918c2ecf20Sopenharmony_ci 15928c2ecf20Sopenharmony_ci phy_cfg.extended_speed |= ext_speed; 15938c2ecf20Sopenharmony_ci 15948c2ecf20Sopenharmony_ci SET_MFW_FIELD(phy_cfg.fec_mode, FEC_EXTENDED_MODE, 15958c2ecf20Sopenharmony_ci params->ext_fec_mode); 15968c2ecf20Sopenharmony_ci } 15978c2ecf20Sopenharmony_ci 15988c2ecf20Sopenharmony_ci p_hwfn->b_drv_link_init = b_up; 15998c2ecf20Sopenharmony_ci 16008c2ecf20Sopenharmony_ci if (b_up) { 16018c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, NETIF_MSG_LINK, 16028c2ecf20Sopenharmony_ci "Configuring Link: Speed 0x%08x, Pause 0x%08x, Adv. Speed 0x%08x, Loopback 0x%08x, FEC 0x%08x, Ext. Speed 0x%08x\n", 16038c2ecf20Sopenharmony_ci phy_cfg.speed, phy_cfg.pause, phy_cfg.adv_speed, 16048c2ecf20Sopenharmony_ci phy_cfg.loopback_mode, phy_cfg.fec_mode, 16058c2ecf20Sopenharmony_ci phy_cfg.extended_speed); 16068c2ecf20Sopenharmony_ci } else { 16078c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, NETIF_MSG_LINK, "Resetting link\n"); 16088c2ecf20Sopenharmony_ci } 16098c2ecf20Sopenharmony_ci 16108c2ecf20Sopenharmony_ci memset(&mb_params, 0, sizeof(mb_params)); 16118c2ecf20Sopenharmony_ci mb_params.cmd = cmd; 16128c2ecf20Sopenharmony_ci mb_params.p_data_src = &phy_cfg; 16138c2ecf20Sopenharmony_ci mb_params.data_src_size = sizeof(phy_cfg); 16148c2ecf20Sopenharmony_ci rc = qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 16158c2ecf20Sopenharmony_ci 16168c2ecf20Sopenharmony_ci /* if mcp fails to respond we must abort */ 16178c2ecf20Sopenharmony_ci if (rc) { 16188c2ecf20Sopenharmony_ci DP_ERR(p_hwfn, "MCP response failure, aborting\n"); 16198c2ecf20Sopenharmony_ci return rc; 16208c2ecf20Sopenharmony_ci } 16218c2ecf20Sopenharmony_ci 16228c2ecf20Sopenharmony_ci /* Mimic link-change attention, done for several reasons: 16238c2ecf20Sopenharmony_ci * - On reset, there's no guarantee MFW would trigger 16248c2ecf20Sopenharmony_ci * an attention. 16258c2ecf20Sopenharmony_ci * - On initialization, older MFWs might not indicate link change 16268c2ecf20Sopenharmony_ci * during LFA, so we'll never get an UP indication. 16278c2ecf20Sopenharmony_ci */ 16288c2ecf20Sopenharmony_ci qed_mcp_handle_link_change(p_hwfn, p_ptt, !b_up); 16298c2ecf20Sopenharmony_ci 16308c2ecf20Sopenharmony_ci return 0; 16318c2ecf20Sopenharmony_ci} 16328c2ecf20Sopenharmony_ci 16338c2ecf20Sopenharmony_ciu32 qed_get_process_kill_counter(struct qed_hwfn *p_hwfn, 16348c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt) 16358c2ecf20Sopenharmony_ci{ 16368c2ecf20Sopenharmony_ci u32 path_offsize_addr, path_offsize, path_addr, proc_kill_cnt; 16378c2ecf20Sopenharmony_ci 16388c2ecf20Sopenharmony_ci if (IS_VF(p_hwfn->cdev)) 16398c2ecf20Sopenharmony_ci return -EINVAL; 16408c2ecf20Sopenharmony_ci 16418c2ecf20Sopenharmony_ci path_offsize_addr = SECTION_OFFSIZE_ADDR(p_hwfn->mcp_info->public_base, 16428c2ecf20Sopenharmony_ci PUBLIC_PATH); 16438c2ecf20Sopenharmony_ci path_offsize = qed_rd(p_hwfn, p_ptt, path_offsize_addr); 16448c2ecf20Sopenharmony_ci path_addr = SECTION_ADDR(path_offsize, QED_PATH_ID(p_hwfn)); 16458c2ecf20Sopenharmony_ci 16468c2ecf20Sopenharmony_ci proc_kill_cnt = qed_rd(p_hwfn, p_ptt, 16478c2ecf20Sopenharmony_ci path_addr + 16488c2ecf20Sopenharmony_ci offsetof(struct public_path, process_kill)) & 16498c2ecf20Sopenharmony_ci PROCESS_KILL_COUNTER_MASK; 16508c2ecf20Sopenharmony_ci 16518c2ecf20Sopenharmony_ci return proc_kill_cnt; 16528c2ecf20Sopenharmony_ci} 16538c2ecf20Sopenharmony_ci 16548c2ecf20Sopenharmony_cistatic void qed_mcp_handle_process_kill(struct qed_hwfn *p_hwfn, 16558c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt) 16568c2ecf20Sopenharmony_ci{ 16578c2ecf20Sopenharmony_ci struct qed_dev *cdev = p_hwfn->cdev; 16588c2ecf20Sopenharmony_ci u32 proc_kill_cnt; 16598c2ecf20Sopenharmony_ci 16608c2ecf20Sopenharmony_ci /* Prevent possible attentions/interrupts during the recovery handling 16618c2ecf20Sopenharmony_ci * and till its load phase, during which they will be re-enabled. 16628c2ecf20Sopenharmony_ci */ 16638c2ecf20Sopenharmony_ci qed_int_igu_disable_int(p_hwfn, p_ptt); 16648c2ecf20Sopenharmony_ci 16658c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, "Received a process kill indication\n"); 16668c2ecf20Sopenharmony_ci 16678c2ecf20Sopenharmony_ci /* The following operations should be done once, and thus in CMT mode 16688c2ecf20Sopenharmony_ci * are carried out by only the first HW function. 16698c2ecf20Sopenharmony_ci */ 16708c2ecf20Sopenharmony_ci if (p_hwfn != QED_LEADING_HWFN(cdev)) 16718c2ecf20Sopenharmony_ci return; 16728c2ecf20Sopenharmony_ci 16738c2ecf20Sopenharmony_ci if (cdev->recov_in_prog) { 16748c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, 16758c2ecf20Sopenharmony_ci "Ignoring the indication since a recovery process is already in progress\n"); 16768c2ecf20Sopenharmony_ci return; 16778c2ecf20Sopenharmony_ci } 16788c2ecf20Sopenharmony_ci 16798c2ecf20Sopenharmony_ci cdev->recov_in_prog = true; 16808c2ecf20Sopenharmony_ci 16818c2ecf20Sopenharmony_ci proc_kill_cnt = qed_get_process_kill_counter(p_hwfn, p_ptt); 16828c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, "Process kill counter: %d\n", proc_kill_cnt); 16838c2ecf20Sopenharmony_ci 16848c2ecf20Sopenharmony_ci qed_schedule_recovery_handler(p_hwfn); 16858c2ecf20Sopenharmony_ci} 16868c2ecf20Sopenharmony_ci 16878c2ecf20Sopenharmony_cistatic void qed_mcp_send_protocol_stats(struct qed_hwfn *p_hwfn, 16888c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt, 16898c2ecf20Sopenharmony_ci enum MFW_DRV_MSG_TYPE type) 16908c2ecf20Sopenharmony_ci{ 16918c2ecf20Sopenharmony_ci enum qed_mcp_protocol_type stats_type; 16928c2ecf20Sopenharmony_ci union qed_mcp_protocol_stats stats; 16938c2ecf20Sopenharmony_ci struct qed_mcp_mb_params mb_params; 16948c2ecf20Sopenharmony_ci u32 hsi_param; 16958c2ecf20Sopenharmony_ci 16968c2ecf20Sopenharmony_ci switch (type) { 16978c2ecf20Sopenharmony_ci case MFW_DRV_MSG_GET_LAN_STATS: 16988c2ecf20Sopenharmony_ci stats_type = QED_MCP_LAN_STATS; 16998c2ecf20Sopenharmony_ci hsi_param = DRV_MSG_CODE_STATS_TYPE_LAN; 17008c2ecf20Sopenharmony_ci break; 17018c2ecf20Sopenharmony_ci case MFW_DRV_MSG_GET_FCOE_STATS: 17028c2ecf20Sopenharmony_ci stats_type = QED_MCP_FCOE_STATS; 17038c2ecf20Sopenharmony_ci hsi_param = DRV_MSG_CODE_STATS_TYPE_FCOE; 17048c2ecf20Sopenharmony_ci break; 17058c2ecf20Sopenharmony_ci case MFW_DRV_MSG_GET_ISCSI_STATS: 17068c2ecf20Sopenharmony_ci stats_type = QED_MCP_ISCSI_STATS; 17078c2ecf20Sopenharmony_ci hsi_param = DRV_MSG_CODE_STATS_TYPE_ISCSI; 17088c2ecf20Sopenharmony_ci break; 17098c2ecf20Sopenharmony_ci case MFW_DRV_MSG_GET_RDMA_STATS: 17108c2ecf20Sopenharmony_ci stats_type = QED_MCP_RDMA_STATS; 17118c2ecf20Sopenharmony_ci hsi_param = DRV_MSG_CODE_STATS_TYPE_RDMA; 17128c2ecf20Sopenharmony_ci break; 17138c2ecf20Sopenharmony_ci default: 17148c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, "Invalid protocol type %d\n", type); 17158c2ecf20Sopenharmony_ci return; 17168c2ecf20Sopenharmony_ci } 17178c2ecf20Sopenharmony_ci 17188c2ecf20Sopenharmony_ci qed_get_protocol_stats(p_hwfn->cdev, stats_type, &stats); 17198c2ecf20Sopenharmony_ci 17208c2ecf20Sopenharmony_ci memset(&mb_params, 0, sizeof(mb_params)); 17218c2ecf20Sopenharmony_ci mb_params.cmd = DRV_MSG_CODE_GET_STATS; 17228c2ecf20Sopenharmony_ci mb_params.param = hsi_param; 17238c2ecf20Sopenharmony_ci mb_params.p_data_src = &stats; 17248c2ecf20Sopenharmony_ci mb_params.data_src_size = sizeof(stats); 17258c2ecf20Sopenharmony_ci qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 17268c2ecf20Sopenharmony_ci} 17278c2ecf20Sopenharmony_ci 17288c2ecf20Sopenharmony_cistatic void qed_mcp_update_bw(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 17298c2ecf20Sopenharmony_ci{ 17308c2ecf20Sopenharmony_ci struct qed_mcp_function_info *p_info; 17318c2ecf20Sopenharmony_ci struct public_func shmem_info; 17328c2ecf20Sopenharmony_ci u32 resp = 0, param = 0; 17338c2ecf20Sopenharmony_ci 17348c2ecf20Sopenharmony_ci qed_mcp_get_shmem_func(p_hwfn, p_ptt, &shmem_info, MCP_PF_ID(p_hwfn)); 17358c2ecf20Sopenharmony_ci 17368c2ecf20Sopenharmony_ci qed_read_pf_bandwidth(p_hwfn, &shmem_info); 17378c2ecf20Sopenharmony_ci 17388c2ecf20Sopenharmony_ci p_info = &p_hwfn->mcp_info->func_info; 17398c2ecf20Sopenharmony_ci 17408c2ecf20Sopenharmony_ci qed_configure_pf_min_bandwidth(p_hwfn->cdev, p_info->bandwidth_min); 17418c2ecf20Sopenharmony_ci qed_configure_pf_max_bandwidth(p_hwfn->cdev, p_info->bandwidth_max); 17428c2ecf20Sopenharmony_ci 17438c2ecf20Sopenharmony_ci /* Acknowledge the MFW */ 17448c2ecf20Sopenharmony_ci qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_BW_UPDATE_ACK, 0, &resp, 17458c2ecf20Sopenharmony_ci ¶m); 17468c2ecf20Sopenharmony_ci} 17478c2ecf20Sopenharmony_ci 17488c2ecf20Sopenharmony_cistatic void qed_mcp_update_stag(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 17498c2ecf20Sopenharmony_ci{ 17508c2ecf20Sopenharmony_ci struct public_func shmem_info; 17518c2ecf20Sopenharmony_ci u32 resp = 0, param = 0; 17528c2ecf20Sopenharmony_ci 17538c2ecf20Sopenharmony_ci qed_mcp_get_shmem_func(p_hwfn, p_ptt, &shmem_info, MCP_PF_ID(p_hwfn)); 17548c2ecf20Sopenharmony_ci 17558c2ecf20Sopenharmony_ci p_hwfn->mcp_info->func_info.ovlan = (u16)shmem_info.ovlan_stag & 17568c2ecf20Sopenharmony_ci FUNC_MF_CFG_OV_STAG_MASK; 17578c2ecf20Sopenharmony_ci p_hwfn->hw_info.ovlan = p_hwfn->mcp_info->func_info.ovlan; 17588c2ecf20Sopenharmony_ci if (test_bit(QED_MF_OVLAN_CLSS, &p_hwfn->cdev->mf_bits)) { 17598c2ecf20Sopenharmony_ci if (p_hwfn->hw_info.ovlan != QED_MCP_VLAN_UNSET) { 17608c2ecf20Sopenharmony_ci qed_wr(p_hwfn, p_ptt, NIG_REG_LLH_FUNC_TAG_VALUE, 17618c2ecf20Sopenharmony_ci p_hwfn->hw_info.ovlan); 17628c2ecf20Sopenharmony_ci qed_wr(p_hwfn, p_ptt, NIG_REG_LLH_FUNC_TAG_EN, 1); 17638c2ecf20Sopenharmony_ci 17648c2ecf20Sopenharmony_ci /* Configure DB to add external vlan to EDPM packets */ 17658c2ecf20Sopenharmony_ci qed_wr(p_hwfn, p_ptt, DORQ_REG_TAG1_OVRD_MODE, 1); 17668c2ecf20Sopenharmony_ci qed_wr(p_hwfn, p_ptt, DORQ_REG_PF_EXT_VID_BB_K2, 17678c2ecf20Sopenharmony_ci p_hwfn->hw_info.ovlan); 17688c2ecf20Sopenharmony_ci } else { 17698c2ecf20Sopenharmony_ci qed_wr(p_hwfn, p_ptt, NIG_REG_LLH_FUNC_TAG_EN, 0); 17708c2ecf20Sopenharmony_ci qed_wr(p_hwfn, p_ptt, NIG_REG_LLH_FUNC_TAG_VALUE, 0); 17718c2ecf20Sopenharmony_ci qed_wr(p_hwfn, p_ptt, DORQ_REG_TAG1_OVRD_MODE, 0); 17728c2ecf20Sopenharmony_ci qed_wr(p_hwfn, p_ptt, DORQ_REG_PF_EXT_VID_BB_K2, 0); 17738c2ecf20Sopenharmony_ci } 17748c2ecf20Sopenharmony_ci 17758c2ecf20Sopenharmony_ci qed_sp_pf_update_stag(p_hwfn); 17768c2ecf20Sopenharmony_ci } 17778c2ecf20Sopenharmony_ci 17788c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, QED_MSG_SP, "ovlan = %d hw_mode = 0x%x\n", 17798c2ecf20Sopenharmony_ci p_hwfn->mcp_info->func_info.ovlan, p_hwfn->hw_info.hw_mode); 17808c2ecf20Sopenharmony_ci 17818c2ecf20Sopenharmony_ci /* Acknowledge the MFW */ 17828c2ecf20Sopenharmony_ci qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_S_TAG_UPDATE_ACK, 0, 17838c2ecf20Sopenharmony_ci &resp, ¶m); 17848c2ecf20Sopenharmony_ci} 17858c2ecf20Sopenharmony_ci 17868c2ecf20Sopenharmony_cistatic void qed_mcp_handle_fan_failure(struct qed_hwfn *p_hwfn, 17878c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt) 17888c2ecf20Sopenharmony_ci{ 17898c2ecf20Sopenharmony_ci /* A single notification should be sent to upper driver in CMT mode */ 17908c2ecf20Sopenharmony_ci if (p_hwfn != QED_LEADING_HWFN(p_hwfn->cdev)) 17918c2ecf20Sopenharmony_ci return; 17928c2ecf20Sopenharmony_ci 17938c2ecf20Sopenharmony_ci qed_hw_err_notify(p_hwfn, p_ptt, QED_HW_ERR_FAN_FAIL, 17948c2ecf20Sopenharmony_ci "Fan failure was detected on the network interface card and it's going to be shut down.\n"); 17958c2ecf20Sopenharmony_ci} 17968c2ecf20Sopenharmony_ci 17978c2ecf20Sopenharmony_cistruct qed_mdump_cmd_params { 17988c2ecf20Sopenharmony_ci u32 cmd; 17998c2ecf20Sopenharmony_ci void *p_data_src; 18008c2ecf20Sopenharmony_ci u8 data_src_size; 18018c2ecf20Sopenharmony_ci void *p_data_dst; 18028c2ecf20Sopenharmony_ci u8 data_dst_size; 18038c2ecf20Sopenharmony_ci u32 mcp_resp; 18048c2ecf20Sopenharmony_ci}; 18058c2ecf20Sopenharmony_ci 18068c2ecf20Sopenharmony_cistatic int 18078c2ecf20Sopenharmony_ciqed_mcp_mdump_cmd(struct qed_hwfn *p_hwfn, 18088c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt, 18098c2ecf20Sopenharmony_ci struct qed_mdump_cmd_params *p_mdump_cmd_params) 18108c2ecf20Sopenharmony_ci{ 18118c2ecf20Sopenharmony_ci struct qed_mcp_mb_params mb_params; 18128c2ecf20Sopenharmony_ci int rc; 18138c2ecf20Sopenharmony_ci 18148c2ecf20Sopenharmony_ci memset(&mb_params, 0, sizeof(mb_params)); 18158c2ecf20Sopenharmony_ci mb_params.cmd = DRV_MSG_CODE_MDUMP_CMD; 18168c2ecf20Sopenharmony_ci mb_params.param = p_mdump_cmd_params->cmd; 18178c2ecf20Sopenharmony_ci mb_params.p_data_src = p_mdump_cmd_params->p_data_src; 18188c2ecf20Sopenharmony_ci mb_params.data_src_size = p_mdump_cmd_params->data_src_size; 18198c2ecf20Sopenharmony_ci mb_params.p_data_dst = p_mdump_cmd_params->p_data_dst; 18208c2ecf20Sopenharmony_ci mb_params.data_dst_size = p_mdump_cmd_params->data_dst_size; 18218c2ecf20Sopenharmony_ci rc = qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 18228c2ecf20Sopenharmony_ci if (rc) 18238c2ecf20Sopenharmony_ci return rc; 18248c2ecf20Sopenharmony_ci 18258c2ecf20Sopenharmony_ci p_mdump_cmd_params->mcp_resp = mb_params.mcp_resp; 18268c2ecf20Sopenharmony_ci 18278c2ecf20Sopenharmony_ci if (p_mdump_cmd_params->mcp_resp == FW_MSG_CODE_MDUMP_INVALID_CMD) { 18288c2ecf20Sopenharmony_ci DP_INFO(p_hwfn, 18298c2ecf20Sopenharmony_ci "The mdump sub command is unsupported by the MFW [mdump_cmd 0x%x]\n", 18308c2ecf20Sopenharmony_ci p_mdump_cmd_params->cmd); 18318c2ecf20Sopenharmony_ci rc = -EOPNOTSUPP; 18328c2ecf20Sopenharmony_ci } else if (p_mdump_cmd_params->mcp_resp == FW_MSG_CODE_UNSUPPORTED) { 18338c2ecf20Sopenharmony_ci DP_INFO(p_hwfn, 18348c2ecf20Sopenharmony_ci "The mdump command is not supported by the MFW\n"); 18358c2ecf20Sopenharmony_ci rc = -EOPNOTSUPP; 18368c2ecf20Sopenharmony_ci } 18378c2ecf20Sopenharmony_ci 18388c2ecf20Sopenharmony_ci return rc; 18398c2ecf20Sopenharmony_ci} 18408c2ecf20Sopenharmony_ci 18418c2ecf20Sopenharmony_cistatic int qed_mcp_mdump_ack(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 18428c2ecf20Sopenharmony_ci{ 18438c2ecf20Sopenharmony_ci struct qed_mdump_cmd_params mdump_cmd_params; 18448c2ecf20Sopenharmony_ci 18458c2ecf20Sopenharmony_ci memset(&mdump_cmd_params, 0, sizeof(mdump_cmd_params)); 18468c2ecf20Sopenharmony_ci mdump_cmd_params.cmd = DRV_MSG_CODE_MDUMP_ACK; 18478c2ecf20Sopenharmony_ci 18488c2ecf20Sopenharmony_ci return qed_mcp_mdump_cmd(p_hwfn, p_ptt, &mdump_cmd_params); 18498c2ecf20Sopenharmony_ci} 18508c2ecf20Sopenharmony_ci 18518c2ecf20Sopenharmony_ciint 18528c2ecf20Sopenharmony_ciqed_mcp_mdump_get_retain(struct qed_hwfn *p_hwfn, 18538c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt, 18548c2ecf20Sopenharmony_ci struct mdump_retain_data_stc *p_mdump_retain) 18558c2ecf20Sopenharmony_ci{ 18568c2ecf20Sopenharmony_ci struct qed_mdump_cmd_params mdump_cmd_params; 18578c2ecf20Sopenharmony_ci int rc; 18588c2ecf20Sopenharmony_ci 18598c2ecf20Sopenharmony_ci memset(&mdump_cmd_params, 0, sizeof(mdump_cmd_params)); 18608c2ecf20Sopenharmony_ci mdump_cmd_params.cmd = DRV_MSG_CODE_MDUMP_GET_RETAIN; 18618c2ecf20Sopenharmony_ci mdump_cmd_params.p_data_dst = p_mdump_retain; 18628c2ecf20Sopenharmony_ci mdump_cmd_params.data_dst_size = sizeof(*p_mdump_retain); 18638c2ecf20Sopenharmony_ci 18648c2ecf20Sopenharmony_ci rc = qed_mcp_mdump_cmd(p_hwfn, p_ptt, &mdump_cmd_params); 18658c2ecf20Sopenharmony_ci if (rc) 18668c2ecf20Sopenharmony_ci return rc; 18678c2ecf20Sopenharmony_ci 18688c2ecf20Sopenharmony_ci if (mdump_cmd_params.mcp_resp != FW_MSG_CODE_OK) { 18698c2ecf20Sopenharmony_ci DP_INFO(p_hwfn, 18708c2ecf20Sopenharmony_ci "Failed to get the mdump retained data [mcp_resp 0x%x]\n", 18718c2ecf20Sopenharmony_ci mdump_cmd_params.mcp_resp); 18728c2ecf20Sopenharmony_ci return -EINVAL; 18738c2ecf20Sopenharmony_ci } 18748c2ecf20Sopenharmony_ci 18758c2ecf20Sopenharmony_ci return 0; 18768c2ecf20Sopenharmony_ci} 18778c2ecf20Sopenharmony_ci 18788c2ecf20Sopenharmony_cistatic void qed_mcp_handle_critical_error(struct qed_hwfn *p_hwfn, 18798c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt) 18808c2ecf20Sopenharmony_ci{ 18818c2ecf20Sopenharmony_ci struct mdump_retain_data_stc mdump_retain; 18828c2ecf20Sopenharmony_ci int rc; 18838c2ecf20Sopenharmony_ci 18848c2ecf20Sopenharmony_ci /* In CMT mode - no need for more than a single acknowledgment to the 18858c2ecf20Sopenharmony_ci * MFW, and no more than a single notification to the upper driver. 18868c2ecf20Sopenharmony_ci */ 18878c2ecf20Sopenharmony_ci if (p_hwfn != QED_LEADING_HWFN(p_hwfn->cdev)) 18888c2ecf20Sopenharmony_ci return; 18898c2ecf20Sopenharmony_ci 18908c2ecf20Sopenharmony_ci rc = qed_mcp_mdump_get_retain(p_hwfn, p_ptt, &mdump_retain); 18918c2ecf20Sopenharmony_ci if (rc == 0 && mdump_retain.valid) 18928c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, 18938c2ecf20Sopenharmony_ci "The MFW notified that a critical error occurred in the device [epoch 0x%08x, pf 0x%x, status 0x%08x]\n", 18948c2ecf20Sopenharmony_ci mdump_retain.epoch, 18958c2ecf20Sopenharmony_ci mdump_retain.pf, mdump_retain.status); 18968c2ecf20Sopenharmony_ci else 18978c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, 18988c2ecf20Sopenharmony_ci "The MFW notified that a critical error occurred in the device\n"); 18998c2ecf20Sopenharmony_ci 19008c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, 19018c2ecf20Sopenharmony_ci "Acknowledging the notification to not allow the MFW crash dump [driver debug data collection is preferable]\n"); 19028c2ecf20Sopenharmony_ci qed_mcp_mdump_ack(p_hwfn, p_ptt); 19038c2ecf20Sopenharmony_ci 19048c2ecf20Sopenharmony_ci qed_hw_err_notify(p_hwfn, p_ptt, QED_HW_ERR_HW_ATTN, NULL); 19058c2ecf20Sopenharmony_ci} 19068c2ecf20Sopenharmony_ci 19078c2ecf20Sopenharmony_civoid qed_mcp_read_ufp_config(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 19088c2ecf20Sopenharmony_ci{ 19098c2ecf20Sopenharmony_ci struct public_func shmem_info; 19108c2ecf20Sopenharmony_ci u32 port_cfg, val; 19118c2ecf20Sopenharmony_ci 19128c2ecf20Sopenharmony_ci if (!test_bit(QED_MF_UFP_SPECIFIC, &p_hwfn->cdev->mf_bits)) 19138c2ecf20Sopenharmony_ci return; 19148c2ecf20Sopenharmony_ci 19158c2ecf20Sopenharmony_ci memset(&p_hwfn->ufp_info, 0, sizeof(p_hwfn->ufp_info)); 19168c2ecf20Sopenharmony_ci port_cfg = qed_rd(p_hwfn, p_ptt, p_hwfn->mcp_info->port_addr + 19178c2ecf20Sopenharmony_ci offsetof(struct public_port, oem_cfg_port)); 19188c2ecf20Sopenharmony_ci val = (port_cfg & OEM_CFG_CHANNEL_TYPE_MASK) >> 19198c2ecf20Sopenharmony_ci OEM_CFG_CHANNEL_TYPE_OFFSET; 19208c2ecf20Sopenharmony_ci if (val != OEM_CFG_CHANNEL_TYPE_STAGGED) 19218c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, 19228c2ecf20Sopenharmony_ci "Incorrect UFP Channel type %d port_id 0x%02x\n", 19238c2ecf20Sopenharmony_ci val, MFW_PORT(p_hwfn)); 19248c2ecf20Sopenharmony_ci 19258c2ecf20Sopenharmony_ci val = (port_cfg & OEM_CFG_SCHED_TYPE_MASK) >> OEM_CFG_SCHED_TYPE_OFFSET; 19268c2ecf20Sopenharmony_ci if (val == OEM_CFG_SCHED_TYPE_ETS) { 19278c2ecf20Sopenharmony_ci p_hwfn->ufp_info.mode = QED_UFP_MODE_ETS; 19288c2ecf20Sopenharmony_ci } else if (val == OEM_CFG_SCHED_TYPE_VNIC_BW) { 19298c2ecf20Sopenharmony_ci p_hwfn->ufp_info.mode = QED_UFP_MODE_VNIC_BW; 19308c2ecf20Sopenharmony_ci } else { 19318c2ecf20Sopenharmony_ci p_hwfn->ufp_info.mode = QED_UFP_MODE_UNKNOWN; 19328c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, 19338c2ecf20Sopenharmony_ci "Unknown UFP scheduling mode %d port_id 0x%02x\n", 19348c2ecf20Sopenharmony_ci val, MFW_PORT(p_hwfn)); 19358c2ecf20Sopenharmony_ci } 19368c2ecf20Sopenharmony_ci 19378c2ecf20Sopenharmony_ci qed_mcp_get_shmem_func(p_hwfn, p_ptt, &shmem_info, MCP_PF_ID(p_hwfn)); 19388c2ecf20Sopenharmony_ci val = (shmem_info.oem_cfg_func & OEM_CFG_FUNC_TC_MASK) >> 19398c2ecf20Sopenharmony_ci OEM_CFG_FUNC_TC_OFFSET; 19408c2ecf20Sopenharmony_ci p_hwfn->ufp_info.tc = (u8)val; 19418c2ecf20Sopenharmony_ci val = (shmem_info.oem_cfg_func & OEM_CFG_FUNC_HOST_PRI_CTRL_MASK) >> 19428c2ecf20Sopenharmony_ci OEM_CFG_FUNC_HOST_PRI_CTRL_OFFSET; 19438c2ecf20Sopenharmony_ci if (val == OEM_CFG_FUNC_HOST_PRI_CTRL_VNIC) { 19448c2ecf20Sopenharmony_ci p_hwfn->ufp_info.pri_type = QED_UFP_PRI_VNIC; 19458c2ecf20Sopenharmony_ci } else if (val == OEM_CFG_FUNC_HOST_PRI_CTRL_OS) { 19468c2ecf20Sopenharmony_ci p_hwfn->ufp_info.pri_type = QED_UFP_PRI_OS; 19478c2ecf20Sopenharmony_ci } else { 19488c2ecf20Sopenharmony_ci p_hwfn->ufp_info.pri_type = QED_UFP_PRI_UNKNOWN; 19498c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, 19508c2ecf20Sopenharmony_ci "Unknown Host priority control %d port_id 0x%02x\n", 19518c2ecf20Sopenharmony_ci val, MFW_PORT(p_hwfn)); 19528c2ecf20Sopenharmony_ci } 19538c2ecf20Sopenharmony_ci 19548c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, 19558c2ecf20Sopenharmony_ci "UFP shmem config: mode = %d tc = %d pri_type = %d port_id 0x%02x\n", 19568c2ecf20Sopenharmony_ci p_hwfn->ufp_info.mode, p_hwfn->ufp_info.tc, 19578c2ecf20Sopenharmony_ci p_hwfn->ufp_info.pri_type, MFW_PORT(p_hwfn)); 19588c2ecf20Sopenharmony_ci} 19598c2ecf20Sopenharmony_ci 19608c2ecf20Sopenharmony_cistatic int 19618c2ecf20Sopenharmony_ciqed_mcp_handle_ufp_event(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 19628c2ecf20Sopenharmony_ci{ 19638c2ecf20Sopenharmony_ci qed_mcp_read_ufp_config(p_hwfn, p_ptt); 19648c2ecf20Sopenharmony_ci 19658c2ecf20Sopenharmony_ci if (p_hwfn->ufp_info.mode == QED_UFP_MODE_VNIC_BW) { 19668c2ecf20Sopenharmony_ci p_hwfn->qm_info.ooo_tc = p_hwfn->ufp_info.tc; 19678c2ecf20Sopenharmony_ci qed_hw_info_set_offload_tc(&p_hwfn->hw_info, 19688c2ecf20Sopenharmony_ci p_hwfn->ufp_info.tc); 19698c2ecf20Sopenharmony_ci 19708c2ecf20Sopenharmony_ci qed_qm_reconf(p_hwfn, p_ptt); 19718c2ecf20Sopenharmony_ci } else if (p_hwfn->ufp_info.mode == QED_UFP_MODE_ETS) { 19728c2ecf20Sopenharmony_ci /* Merge UFP TC with the dcbx TC data */ 19738c2ecf20Sopenharmony_ci qed_dcbx_mib_update_event(p_hwfn, p_ptt, 19748c2ecf20Sopenharmony_ci QED_DCBX_OPERATIONAL_MIB); 19758c2ecf20Sopenharmony_ci } else { 19768c2ecf20Sopenharmony_ci DP_ERR(p_hwfn, "Invalid sched type, discard the UFP config\n"); 19778c2ecf20Sopenharmony_ci return -EINVAL; 19788c2ecf20Sopenharmony_ci } 19798c2ecf20Sopenharmony_ci 19808c2ecf20Sopenharmony_ci /* update storm FW with negotiation results */ 19818c2ecf20Sopenharmony_ci qed_sp_pf_update_ufp(p_hwfn); 19828c2ecf20Sopenharmony_ci 19838c2ecf20Sopenharmony_ci /* update stag pcp value */ 19848c2ecf20Sopenharmony_ci qed_sp_pf_update_stag(p_hwfn); 19858c2ecf20Sopenharmony_ci 19868c2ecf20Sopenharmony_ci return 0; 19878c2ecf20Sopenharmony_ci} 19888c2ecf20Sopenharmony_ci 19898c2ecf20Sopenharmony_ciint qed_mcp_handle_events(struct qed_hwfn *p_hwfn, 19908c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt) 19918c2ecf20Sopenharmony_ci{ 19928c2ecf20Sopenharmony_ci struct qed_mcp_info *info = p_hwfn->mcp_info; 19938c2ecf20Sopenharmony_ci int rc = 0; 19948c2ecf20Sopenharmony_ci bool found = false; 19958c2ecf20Sopenharmony_ci u16 i; 19968c2ecf20Sopenharmony_ci 19978c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, QED_MSG_SP, "Received message from MFW\n"); 19988c2ecf20Sopenharmony_ci 19998c2ecf20Sopenharmony_ci /* Read Messages from MFW */ 20008c2ecf20Sopenharmony_ci qed_mcp_read_mb(p_hwfn, p_ptt); 20018c2ecf20Sopenharmony_ci 20028c2ecf20Sopenharmony_ci /* Compare current messages to old ones */ 20038c2ecf20Sopenharmony_ci for (i = 0; i < info->mfw_mb_length; i++) { 20048c2ecf20Sopenharmony_ci if (info->mfw_mb_cur[i] == info->mfw_mb_shadow[i]) 20058c2ecf20Sopenharmony_ci continue; 20068c2ecf20Sopenharmony_ci 20078c2ecf20Sopenharmony_ci found = true; 20088c2ecf20Sopenharmony_ci 20098c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, NETIF_MSG_LINK, 20108c2ecf20Sopenharmony_ci "Msg [%d] - old CMD 0x%02x, new CMD 0x%02x\n", 20118c2ecf20Sopenharmony_ci i, info->mfw_mb_shadow[i], info->mfw_mb_cur[i]); 20128c2ecf20Sopenharmony_ci 20138c2ecf20Sopenharmony_ci switch (i) { 20148c2ecf20Sopenharmony_ci case MFW_DRV_MSG_LINK_CHANGE: 20158c2ecf20Sopenharmony_ci qed_mcp_handle_link_change(p_hwfn, p_ptt, false); 20168c2ecf20Sopenharmony_ci break; 20178c2ecf20Sopenharmony_ci case MFW_DRV_MSG_VF_DISABLED: 20188c2ecf20Sopenharmony_ci qed_mcp_handle_vf_flr(p_hwfn, p_ptt); 20198c2ecf20Sopenharmony_ci break; 20208c2ecf20Sopenharmony_ci case MFW_DRV_MSG_LLDP_DATA_UPDATED: 20218c2ecf20Sopenharmony_ci qed_dcbx_mib_update_event(p_hwfn, p_ptt, 20228c2ecf20Sopenharmony_ci QED_DCBX_REMOTE_LLDP_MIB); 20238c2ecf20Sopenharmony_ci break; 20248c2ecf20Sopenharmony_ci case MFW_DRV_MSG_DCBX_REMOTE_MIB_UPDATED: 20258c2ecf20Sopenharmony_ci qed_dcbx_mib_update_event(p_hwfn, p_ptt, 20268c2ecf20Sopenharmony_ci QED_DCBX_REMOTE_MIB); 20278c2ecf20Sopenharmony_ci break; 20288c2ecf20Sopenharmony_ci case MFW_DRV_MSG_DCBX_OPERATIONAL_MIB_UPDATED: 20298c2ecf20Sopenharmony_ci qed_dcbx_mib_update_event(p_hwfn, p_ptt, 20308c2ecf20Sopenharmony_ci QED_DCBX_OPERATIONAL_MIB); 20318c2ecf20Sopenharmony_ci break; 20328c2ecf20Sopenharmony_ci case MFW_DRV_MSG_OEM_CFG_UPDATE: 20338c2ecf20Sopenharmony_ci qed_mcp_handle_ufp_event(p_hwfn, p_ptt); 20348c2ecf20Sopenharmony_ci break; 20358c2ecf20Sopenharmony_ci case MFW_DRV_MSG_TRANSCEIVER_STATE_CHANGE: 20368c2ecf20Sopenharmony_ci qed_mcp_handle_transceiver_change(p_hwfn, p_ptt); 20378c2ecf20Sopenharmony_ci break; 20388c2ecf20Sopenharmony_ci case MFW_DRV_MSG_ERROR_RECOVERY: 20398c2ecf20Sopenharmony_ci qed_mcp_handle_process_kill(p_hwfn, p_ptt); 20408c2ecf20Sopenharmony_ci break; 20418c2ecf20Sopenharmony_ci case MFW_DRV_MSG_GET_LAN_STATS: 20428c2ecf20Sopenharmony_ci case MFW_DRV_MSG_GET_FCOE_STATS: 20438c2ecf20Sopenharmony_ci case MFW_DRV_MSG_GET_ISCSI_STATS: 20448c2ecf20Sopenharmony_ci case MFW_DRV_MSG_GET_RDMA_STATS: 20458c2ecf20Sopenharmony_ci qed_mcp_send_protocol_stats(p_hwfn, p_ptt, i); 20468c2ecf20Sopenharmony_ci break; 20478c2ecf20Sopenharmony_ci case MFW_DRV_MSG_BW_UPDATE: 20488c2ecf20Sopenharmony_ci qed_mcp_update_bw(p_hwfn, p_ptt); 20498c2ecf20Sopenharmony_ci break; 20508c2ecf20Sopenharmony_ci case MFW_DRV_MSG_S_TAG_UPDATE: 20518c2ecf20Sopenharmony_ci qed_mcp_update_stag(p_hwfn, p_ptt); 20528c2ecf20Sopenharmony_ci break; 20538c2ecf20Sopenharmony_ci case MFW_DRV_MSG_FAILURE_DETECTED: 20548c2ecf20Sopenharmony_ci qed_mcp_handle_fan_failure(p_hwfn, p_ptt); 20558c2ecf20Sopenharmony_ci break; 20568c2ecf20Sopenharmony_ci case MFW_DRV_MSG_CRITICAL_ERROR_OCCURRED: 20578c2ecf20Sopenharmony_ci qed_mcp_handle_critical_error(p_hwfn, p_ptt); 20588c2ecf20Sopenharmony_ci break; 20598c2ecf20Sopenharmony_ci case MFW_DRV_MSG_GET_TLV_REQ: 20608c2ecf20Sopenharmony_ci qed_mfw_tlv_req(p_hwfn); 20618c2ecf20Sopenharmony_ci break; 20628c2ecf20Sopenharmony_ci default: 20638c2ecf20Sopenharmony_ci DP_INFO(p_hwfn, "Unimplemented MFW message %d\n", i); 20648c2ecf20Sopenharmony_ci rc = -EINVAL; 20658c2ecf20Sopenharmony_ci } 20668c2ecf20Sopenharmony_ci } 20678c2ecf20Sopenharmony_ci 20688c2ecf20Sopenharmony_ci /* ACK everything */ 20698c2ecf20Sopenharmony_ci for (i = 0; i < MFW_DRV_MSG_MAX_DWORDS(info->mfw_mb_length); i++) { 20708c2ecf20Sopenharmony_ci __be32 val = cpu_to_be32(((u32 *)info->mfw_mb_cur)[i]); 20718c2ecf20Sopenharmony_ci 20728c2ecf20Sopenharmony_ci /* MFW expect answer in BE, so we force write in that format */ 20738c2ecf20Sopenharmony_ci qed_wr(p_hwfn, p_ptt, 20748c2ecf20Sopenharmony_ci info->mfw_mb_addr + sizeof(u32) + 20758c2ecf20Sopenharmony_ci MFW_DRV_MSG_MAX_DWORDS(info->mfw_mb_length) * 20768c2ecf20Sopenharmony_ci sizeof(u32) + i * sizeof(u32), 20778c2ecf20Sopenharmony_ci (__force u32)val); 20788c2ecf20Sopenharmony_ci } 20798c2ecf20Sopenharmony_ci 20808c2ecf20Sopenharmony_ci if (!found) { 20818c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, 20828c2ecf20Sopenharmony_ci "Received an MFW message indication but no new message!\n"); 20838c2ecf20Sopenharmony_ci rc = -EINVAL; 20848c2ecf20Sopenharmony_ci } 20858c2ecf20Sopenharmony_ci 20868c2ecf20Sopenharmony_ci /* Copy the new mfw messages into the shadow */ 20878c2ecf20Sopenharmony_ci memcpy(info->mfw_mb_shadow, info->mfw_mb_cur, info->mfw_mb_length); 20888c2ecf20Sopenharmony_ci 20898c2ecf20Sopenharmony_ci return rc; 20908c2ecf20Sopenharmony_ci} 20918c2ecf20Sopenharmony_ci 20928c2ecf20Sopenharmony_ciint qed_mcp_get_mfw_ver(struct qed_hwfn *p_hwfn, 20938c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt, 20948c2ecf20Sopenharmony_ci u32 *p_mfw_ver, u32 *p_running_bundle_id) 20958c2ecf20Sopenharmony_ci{ 20968c2ecf20Sopenharmony_ci u32 global_offsize; 20978c2ecf20Sopenharmony_ci 20988c2ecf20Sopenharmony_ci if (IS_VF(p_hwfn->cdev)) { 20998c2ecf20Sopenharmony_ci if (p_hwfn->vf_iov_info) { 21008c2ecf20Sopenharmony_ci struct pfvf_acquire_resp_tlv *p_resp; 21018c2ecf20Sopenharmony_ci 21028c2ecf20Sopenharmony_ci p_resp = &p_hwfn->vf_iov_info->acquire_resp; 21038c2ecf20Sopenharmony_ci *p_mfw_ver = p_resp->pfdev_info.mfw_ver; 21048c2ecf20Sopenharmony_ci return 0; 21058c2ecf20Sopenharmony_ci } else { 21068c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, 21078c2ecf20Sopenharmony_ci QED_MSG_IOV, 21088c2ecf20Sopenharmony_ci "VF requested MFW version prior to ACQUIRE\n"); 21098c2ecf20Sopenharmony_ci return -EINVAL; 21108c2ecf20Sopenharmony_ci } 21118c2ecf20Sopenharmony_ci } 21128c2ecf20Sopenharmony_ci 21138c2ecf20Sopenharmony_ci global_offsize = qed_rd(p_hwfn, p_ptt, 21148c2ecf20Sopenharmony_ci SECTION_OFFSIZE_ADDR(p_hwfn-> 21158c2ecf20Sopenharmony_ci mcp_info->public_base, 21168c2ecf20Sopenharmony_ci PUBLIC_GLOBAL)); 21178c2ecf20Sopenharmony_ci *p_mfw_ver = 21188c2ecf20Sopenharmony_ci qed_rd(p_hwfn, p_ptt, 21198c2ecf20Sopenharmony_ci SECTION_ADDR(global_offsize, 21208c2ecf20Sopenharmony_ci 0) + offsetof(struct public_global, mfw_ver)); 21218c2ecf20Sopenharmony_ci 21228c2ecf20Sopenharmony_ci if (p_running_bundle_id != NULL) { 21238c2ecf20Sopenharmony_ci *p_running_bundle_id = qed_rd(p_hwfn, p_ptt, 21248c2ecf20Sopenharmony_ci SECTION_ADDR(global_offsize, 0) + 21258c2ecf20Sopenharmony_ci offsetof(struct public_global, 21268c2ecf20Sopenharmony_ci running_bundle_id)); 21278c2ecf20Sopenharmony_ci } 21288c2ecf20Sopenharmony_ci 21298c2ecf20Sopenharmony_ci return 0; 21308c2ecf20Sopenharmony_ci} 21318c2ecf20Sopenharmony_ci 21328c2ecf20Sopenharmony_ciint qed_mcp_get_mbi_ver(struct qed_hwfn *p_hwfn, 21338c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt, u32 *p_mbi_ver) 21348c2ecf20Sopenharmony_ci{ 21358c2ecf20Sopenharmony_ci u32 nvm_cfg_addr, nvm_cfg1_offset, mbi_ver_addr; 21368c2ecf20Sopenharmony_ci 21378c2ecf20Sopenharmony_ci if (IS_VF(p_hwfn->cdev)) 21388c2ecf20Sopenharmony_ci return -EINVAL; 21398c2ecf20Sopenharmony_ci 21408c2ecf20Sopenharmony_ci /* Read the address of the nvm_cfg */ 21418c2ecf20Sopenharmony_ci nvm_cfg_addr = qed_rd(p_hwfn, p_ptt, MISC_REG_GEN_PURP_CR0); 21428c2ecf20Sopenharmony_ci if (!nvm_cfg_addr) { 21438c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, "Shared memory not initialized\n"); 21448c2ecf20Sopenharmony_ci return -EINVAL; 21458c2ecf20Sopenharmony_ci } 21468c2ecf20Sopenharmony_ci 21478c2ecf20Sopenharmony_ci /* Read the offset of nvm_cfg1 */ 21488c2ecf20Sopenharmony_ci nvm_cfg1_offset = qed_rd(p_hwfn, p_ptt, nvm_cfg_addr + 4); 21498c2ecf20Sopenharmony_ci 21508c2ecf20Sopenharmony_ci mbi_ver_addr = MCP_REG_SCRATCH + nvm_cfg1_offset + 21518c2ecf20Sopenharmony_ci offsetof(struct nvm_cfg1, glob) + 21528c2ecf20Sopenharmony_ci offsetof(struct nvm_cfg1_glob, mbi_version); 21538c2ecf20Sopenharmony_ci *p_mbi_ver = qed_rd(p_hwfn, p_ptt, 21548c2ecf20Sopenharmony_ci mbi_ver_addr) & 21558c2ecf20Sopenharmony_ci (NVM_CFG1_GLOB_MBI_VERSION_0_MASK | 21568c2ecf20Sopenharmony_ci NVM_CFG1_GLOB_MBI_VERSION_1_MASK | 21578c2ecf20Sopenharmony_ci NVM_CFG1_GLOB_MBI_VERSION_2_MASK); 21588c2ecf20Sopenharmony_ci 21598c2ecf20Sopenharmony_ci return 0; 21608c2ecf20Sopenharmony_ci} 21618c2ecf20Sopenharmony_ci 21628c2ecf20Sopenharmony_ciint qed_mcp_get_media_type(struct qed_hwfn *p_hwfn, 21638c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt, u32 *p_media_type) 21648c2ecf20Sopenharmony_ci{ 21658c2ecf20Sopenharmony_ci *p_media_type = MEDIA_UNSPECIFIED; 21668c2ecf20Sopenharmony_ci 21678c2ecf20Sopenharmony_ci if (IS_VF(p_hwfn->cdev)) 21688c2ecf20Sopenharmony_ci return -EINVAL; 21698c2ecf20Sopenharmony_ci 21708c2ecf20Sopenharmony_ci if (!qed_mcp_is_init(p_hwfn)) { 21718c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, "MFW is not initialized!\n"); 21728c2ecf20Sopenharmony_ci return -EBUSY; 21738c2ecf20Sopenharmony_ci } 21748c2ecf20Sopenharmony_ci 21758c2ecf20Sopenharmony_ci if (!p_ptt) { 21768c2ecf20Sopenharmony_ci *p_media_type = MEDIA_UNSPECIFIED; 21778c2ecf20Sopenharmony_ci return -EINVAL; 21788c2ecf20Sopenharmony_ci } 21798c2ecf20Sopenharmony_ci 21808c2ecf20Sopenharmony_ci *p_media_type = qed_rd(p_hwfn, p_ptt, 21818c2ecf20Sopenharmony_ci p_hwfn->mcp_info->port_addr + 21828c2ecf20Sopenharmony_ci offsetof(struct public_port, 21838c2ecf20Sopenharmony_ci media_type)); 21848c2ecf20Sopenharmony_ci 21858c2ecf20Sopenharmony_ci return 0; 21868c2ecf20Sopenharmony_ci} 21878c2ecf20Sopenharmony_ci 21888c2ecf20Sopenharmony_ciint qed_mcp_get_transceiver_data(struct qed_hwfn *p_hwfn, 21898c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt, 21908c2ecf20Sopenharmony_ci u32 *p_transceiver_state, 21918c2ecf20Sopenharmony_ci u32 *p_transceiver_type) 21928c2ecf20Sopenharmony_ci{ 21938c2ecf20Sopenharmony_ci u32 transceiver_info; 21948c2ecf20Sopenharmony_ci 21958c2ecf20Sopenharmony_ci *p_transceiver_type = ETH_TRANSCEIVER_TYPE_NONE; 21968c2ecf20Sopenharmony_ci *p_transceiver_state = ETH_TRANSCEIVER_STATE_UPDATING; 21978c2ecf20Sopenharmony_ci 21988c2ecf20Sopenharmony_ci if (IS_VF(p_hwfn->cdev)) 21998c2ecf20Sopenharmony_ci return -EINVAL; 22008c2ecf20Sopenharmony_ci 22018c2ecf20Sopenharmony_ci if (!qed_mcp_is_init(p_hwfn)) { 22028c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, "MFW is not initialized!\n"); 22038c2ecf20Sopenharmony_ci return -EBUSY; 22048c2ecf20Sopenharmony_ci } 22058c2ecf20Sopenharmony_ci 22068c2ecf20Sopenharmony_ci transceiver_info = qed_rd(p_hwfn, p_ptt, 22078c2ecf20Sopenharmony_ci p_hwfn->mcp_info->port_addr + 22088c2ecf20Sopenharmony_ci offsetof(struct public_port, 22098c2ecf20Sopenharmony_ci transceiver_data)); 22108c2ecf20Sopenharmony_ci 22118c2ecf20Sopenharmony_ci *p_transceiver_state = (transceiver_info & 22128c2ecf20Sopenharmony_ci ETH_TRANSCEIVER_STATE_MASK) >> 22138c2ecf20Sopenharmony_ci ETH_TRANSCEIVER_STATE_OFFSET; 22148c2ecf20Sopenharmony_ci 22158c2ecf20Sopenharmony_ci if (*p_transceiver_state == ETH_TRANSCEIVER_STATE_PRESENT) 22168c2ecf20Sopenharmony_ci *p_transceiver_type = (transceiver_info & 22178c2ecf20Sopenharmony_ci ETH_TRANSCEIVER_TYPE_MASK) >> 22188c2ecf20Sopenharmony_ci ETH_TRANSCEIVER_TYPE_OFFSET; 22198c2ecf20Sopenharmony_ci else 22208c2ecf20Sopenharmony_ci *p_transceiver_type = ETH_TRANSCEIVER_TYPE_UNKNOWN; 22218c2ecf20Sopenharmony_ci 22228c2ecf20Sopenharmony_ci return 0; 22238c2ecf20Sopenharmony_ci} 22248c2ecf20Sopenharmony_cistatic bool qed_is_transceiver_ready(u32 transceiver_state, 22258c2ecf20Sopenharmony_ci u32 transceiver_type) 22268c2ecf20Sopenharmony_ci{ 22278c2ecf20Sopenharmony_ci if ((transceiver_state & ETH_TRANSCEIVER_STATE_PRESENT) && 22288c2ecf20Sopenharmony_ci ((transceiver_state & ETH_TRANSCEIVER_STATE_UPDATING) == 0x0) && 22298c2ecf20Sopenharmony_ci (transceiver_type != ETH_TRANSCEIVER_TYPE_NONE)) 22308c2ecf20Sopenharmony_ci return true; 22318c2ecf20Sopenharmony_ci 22328c2ecf20Sopenharmony_ci return false; 22338c2ecf20Sopenharmony_ci} 22348c2ecf20Sopenharmony_ci 22358c2ecf20Sopenharmony_ciint qed_mcp_trans_speed_mask(struct qed_hwfn *p_hwfn, 22368c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt, u32 *p_speed_mask) 22378c2ecf20Sopenharmony_ci{ 22388c2ecf20Sopenharmony_ci u32 transceiver_type, transceiver_state; 22398c2ecf20Sopenharmony_ci int ret; 22408c2ecf20Sopenharmony_ci 22418c2ecf20Sopenharmony_ci ret = qed_mcp_get_transceiver_data(p_hwfn, p_ptt, &transceiver_state, 22428c2ecf20Sopenharmony_ci &transceiver_type); 22438c2ecf20Sopenharmony_ci if (ret) 22448c2ecf20Sopenharmony_ci return ret; 22458c2ecf20Sopenharmony_ci 22468c2ecf20Sopenharmony_ci if (qed_is_transceiver_ready(transceiver_state, transceiver_type) == 22478c2ecf20Sopenharmony_ci false) 22488c2ecf20Sopenharmony_ci return -EINVAL; 22498c2ecf20Sopenharmony_ci 22508c2ecf20Sopenharmony_ci switch (transceiver_type) { 22518c2ecf20Sopenharmony_ci case ETH_TRANSCEIVER_TYPE_1G_LX: 22528c2ecf20Sopenharmony_ci case ETH_TRANSCEIVER_TYPE_1G_SX: 22538c2ecf20Sopenharmony_ci case ETH_TRANSCEIVER_TYPE_1G_PCC: 22548c2ecf20Sopenharmony_ci case ETH_TRANSCEIVER_TYPE_1G_ACC: 22558c2ecf20Sopenharmony_ci case ETH_TRANSCEIVER_TYPE_1000BASET: 22568c2ecf20Sopenharmony_ci *p_speed_mask = NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G; 22578c2ecf20Sopenharmony_ci break; 22588c2ecf20Sopenharmony_ci case ETH_TRANSCEIVER_TYPE_10G_SR: 22598c2ecf20Sopenharmony_ci case ETH_TRANSCEIVER_TYPE_10G_LR: 22608c2ecf20Sopenharmony_ci case ETH_TRANSCEIVER_TYPE_10G_LRM: 22618c2ecf20Sopenharmony_ci case ETH_TRANSCEIVER_TYPE_10G_ER: 22628c2ecf20Sopenharmony_ci case ETH_TRANSCEIVER_TYPE_10G_PCC: 22638c2ecf20Sopenharmony_ci case ETH_TRANSCEIVER_TYPE_10G_ACC: 22648c2ecf20Sopenharmony_ci case ETH_TRANSCEIVER_TYPE_4x10G: 22658c2ecf20Sopenharmony_ci *p_speed_mask = NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G; 22668c2ecf20Sopenharmony_ci break; 22678c2ecf20Sopenharmony_ci case ETH_TRANSCEIVER_TYPE_40G_LR4: 22688c2ecf20Sopenharmony_ci case ETH_TRANSCEIVER_TYPE_40G_SR4: 22698c2ecf20Sopenharmony_ci case ETH_TRANSCEIVER_TYPE_MULTI_RATE_10G_40G_SR: 22708c2ecf20Sopenharmony_ci case ETH_TRANSCEIVER_TYPE_MULTI_RATE_10G_40G_LR: 22718c2ecf20Sopenharmony_ci *p_speed_mask = NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_40G | 22728c2ecf20Sopenharmony_ci NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G; 22738c2ecf20Sopenharmony_ci break; 22748c2ecf20Sopenharmony_ci case ETH_TRANSCEIVER_TYPE_100G_AOC: 22758c2ecf20Sopenharmony_ci case ETH_TRANSCEIVER_TYPE_100G_SR4: 22768c2ecf20Sopenharmony_ci case ETH_TRANSCEIVER_TYPE_100G_LR4: 22778c2ecf20Sopenharmony_ci case ETH_TRANSCEIVER_TYPE_100G_ER4: 22788c2ecf20Sopenharmony_ci case ETH_TRANSCEIVER_TYPE_100G_ACC: 22798c2ecf20Sopenharmony_ci *p_speed_mask = 22808c2ecf20Sopenharmony_ci NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_BB_100G | 22818c2ecf20Sopenharmony_ci NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_25G; 22828c2ecf20Sopenharmony_ci break; 22838c2ecf20Sopenharmony_ci case ETH_TRANSCEIVER_TYPE_25G_SR: 22848c2ecf20Sopenharmony_ci case ETH_TRANSCEIVER_TYPE_25G_LR: 22858c2ecf20Sopenharmony_ci case ETH_TRANSCEIVER_TYPE_25G_AOC: 22868c2ecf20Sopenharmony_ci case ETH_TRANSCEIVER_TYPE_25G_ACC_S: 22878c2ecf20Sopenharmony_ci case ETH_TRANSCEIVER_TYPE_25G_ACC_M: 22888c2ecf20Sopenharmony_ci case ETH_TRANSCEIVER_TYPE_25G_ACC_L: 22898c2ecf20Sopenharmony_ci *p_speed_mask = NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_25G; 22908c2ecf20Sopenharmony_ci break; 22918c2ecf20Sopenharmony_ci case ETH_TRANSCEIVER_TYPE_25G_CA_N: 22928c2ecf20Sopenharmony_ci case ETH_TRANSCEIVER_TYPE_25G_CA_S: 22938c2ecf20Sopenharmony_ci case ETH_TRANSCEIVER_TYPE_25G_CA_L: 22948c2ecf20Sopenharmony_ci case ETH_TRANSCEIVER_TYPE_4x25G_CR: 22958c2ecf20Sopenharmony_ci *p_speed_mask = NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_25G | 22968c2ecf20Sopenharmony_ci NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G | 22978c2ecf20Sopenharmony_ci NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G; 22988c2ecf20Sopenharmony_ci break; 22998c2ecf20Sopenharmony_ci case ETH_TRANSCEIVER_TYPE_MULTI_RATE_10G_25G_SR: 23008c2ecf20Sopenharmony_ci case ETH_TRANSCEIVER_TYPE_MULTI_RATE_10G_25G_LR: 23018c2ecf20Sopenharmony_ci *p_speed_mask = NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_25G | 23028c2ecf20Sopenharmony_ci NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G; 23038c2ecf20Sopenharmony_ci break; 23048c2ecf20Sopenharmony_ci case ETH_TRANSCEIVER_TYPE_40G_CR4: 23058c2ecf20Sopenharmony_ci case ETH_TRANSCEIVER_TYPE_MULTI_RATE_10G_40G_CR: 23068c2ecf20Sopenharmony_ci *p_speed_mask = NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_40G | 23078c2ecf20Sopenharmony_ci NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G | 23088c2ecf20Sopenharmony_ci NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G; 23098c2ecf20Sopenharmony_ci break; 23108c2ecf20Sopenharmony_ci case ETH_TRANSCEIVER_TYPE_100G_CR4: 23118c2ecf20Sopenharmony_ci case ETH_TRANSCEIVER_TYPE_MULTI_RATE_40G_100G_CR: 23128c2ecf20Sopenharmony_ci *p_speed_mask = 23138c2ecf20Sopenharmony_ci NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_BB_100G | 23148c2ecf20Sopenharmony_ci NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_50G | 23158c2ecf20Sopenharmony_ci NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_40G | 23168c2ecf20Sopenharmony_ci NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_25G | 23178c2ecf20Sopenharmony_ci NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_20G | 23188c2ecf20Sopenharmony_ci NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G | 23198c2ecf20Sopenharmony_ci NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G; 23208c2ecf20Sopenharmony_ci break; 23218c2ecf20Sopenharmony_ci case ETH_TRANSCEIVER_TYPE_MULTI_RATE_40G_100G_SR: 23228c2ecf20Sopenharmony_ci case ETH_TRANSCEIVER_TYPE_MULTI_RATE_40G_100G_LR: 23238c2ecf20Sopenharmony_ci case ETH_TRANSCEIVER_TYPE_MULTI_RATE_40G_100G_AOC: 23248c2ecf20Sopenharmony_ci *p_speed_mask = 23258c2ecf20Sopenharmony_ci NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_BB_100G | 23268c2ecf20Sopenharmony_ci NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_40G | 23278c2ecf20Sopenharmony_ci NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_25G | 23288c2ecf20Sopenharmony_ci NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G; 23298c2ecf20Sopenharmony_ci break; 23308c2ecf20Sopenharmony_ci case ETH_TRANSCEIVER_TYPE_XLPPI: 23318c2ecf20Sopenharmony_ci *p_speed_mask = NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_40G; 23328c2ecf20Sopenharmony_ci break; 23338c2ecf20Sopenharmony_ci case ETH_TRANSCEIVER_TYPE_10G_BASET: 23348c2ecf20Sopenharmony_ci case ETH_TRANSCEIVER_TYPE_MULTI_RATE_1G_10G_SR: 23358c2ecf20Sopenharmony_ci case ETH_TRANSCEIVER_TYPE_MULTI_RATE_1G_10G_LR: 23368c2ecf20Sopenharmony_ci *p_speed_mask = NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G | 23378c2ecf20Sopenharmony_ci NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G; 23388c2ecf20Sopenharmony_ci break; 23398c2ecf20Sopenharmony_ci default: 23408c2ecf20Sopenharmony_ci DP_INFO(p_hwfn, "Unknown transceiver type 0x%x\n", 23418c2ecf20Sopenharmony_ci transceiver_type); 23428c2ecf20Sopenharmony_ci *p_speed_mask = 0xff; 23438c2ecf20Sopenharmony_ci break; 23448c2ecf20Sopenharmony_ci } 23458c2ecf20Sopenharmony_ci 23468c2ecf20Sopenharmony_ci return 0; 23478c2ecf20Sopenharmony_ci} 23488c2ecf20Sopenharmony_ci 23498c2ecf20Sopenharmony_ciint qed_mcp_get_board_config(struct qed_hwfn *p_hwfn, 23508c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt, u32 *p_board_config) 23518c2ecf20Sopenharmony_ci{ 23528c2ecf20Sopenharmony_ci u32 nvm_cfg_addr, nvm_cfg1_offset, port_cfg_addr; 23538c2ecf20Sopenharmony_ci 23548c2ecf20Sopenharmony_ci if (IS_VF(p_hwfn->cdev)) 23558c2ecf20Sopenharmony_ci return -EINVAL; 23568c2ecf20Sopenharmony_ci 23578c2ecf20Sopenharmony_ci if (!qed_mcp_is_init(p_hwfn)) { 23588c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, "MFW is not initialized!\n"); 23598c2ecf20Sopenharmony_ci return -EBUSY; 23608c2ecf20Sopenharmony_ci } 23618c2ecf20Sopenharmony_ci if (!p_ptt) { 23628c2ecf20Sopenharmony_ci *p_board_config = NVM_CFG1_PORT_PORT_TYPE_UNDEFINED; 23638c2ecf20Sopenharmony_ci return -EINVAL; 23648c2ecf20Sopenharmony_ci } 23658c2ecf20Sopenharmony_ci 23668c2ecf20Sopenharmony_ci nvm_cfg_addr = qed_rd(p_hwfn, p_ptt, MISC_REG_GEN_PURP_CR0); 23678c2ecf20Sopenharmony_ci nvm_cfg1_offset = qed_rd(p_hwfn, p_ptt, nvm_cfg_addr + 4); 23688c2ecf20Sopenharmony_ci port_cfg_addr = MCP_REG_SCRATCH + nvm_cfg1_offset + 23698c2ecf20Sopenharmony_ci offsetof(struct nvm_cfg1, port[MFW_PORT(p_hwfn)]); 23708c2ecf20Sopenharmony_ci *p_board_config = qed_rd(p_hwfn, p_ptt, 23718c2ecf20Sopenharmony_ci port_cfg_addr + 23728c2ecf20Sopenharmony_ci offsetof(struct nvm_cfg1_port, 23738c2ecf20Sopenharmony_ci board_cfg)); 23748c2ecf20Sopenharmony_ci 23758c2ecf20Sopenharmony_ci return 0; 23768c2ecf20Sopenharmony_ci} 23778c2ecf20Sopenharmony_ci 23788c2ecf20Sopenharmony_ci/* Old MFW has a global configuration for all PFs regarding RDMA support */ 23798c2ecf20Sopenharmony_cistatic void 23808c2ecf20Sopenharmony_ciqed_mcp_get_shmem_proto_legacy(struct qed_hwfn *p_hwfn, 23818c2ecf20Sopenharmony_ci enum qed_pci_personality *p_proto) 23828c2ecf20Sopenharmony_ci{ 23838c2ecf20Sopenharmony_ci /* There wasn't ever a legacy MFW that published iwarp. 23848c2ecf20Sopenharmony_ci * So at this point, this is either plain l2 or RoCE. 23858c2ecf20Sopenharmony_ci */ 23868c2ecf20Sopenharmony_ci if (test_bit(QED_DEV_CAP_ROCE, &p_hwfn->hw_info.device_capabilities)) 23878c2ecf20Sopenharmony_ci *p_proto = QED_PCI_ETH_ROCE; 23888c2ecf20Sopenharmony_ci else 23898c2ecf20Sopenharmony_ci *p_proto = QED_PCI_ETH; 23908c2ecf20Sopenharmony_ci 23918c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, NETIF_MSG_IFUP, 23928c2ecf20Sopenharmony_ci "According to Legacy capabilities, L2 personality is %08x\n", 23938c2ecf20Sopenharmony_ci (u32) *p_proto); 23948c2ecf20Sopenharmony_ci} 23958c2ecf20Sopenharmony_ci 23968c2ecf20Sopenharmony_cistatic int 23978c2ecf20Sopenharmony_ciqed_mcp_get_shmem_proto_mfw(struct qed_hwfn *p_hwfn, 23988c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt, 23998c2ecf20Sopenharmony_ci enum qed_pci_personality *p_proto) 24008c2ecf20Sopenharmony_ci{ 24018c2ecf20Sopenharmony_ci u32 resp = 0, param = 0; 24028c2ecf20Sopenharmony_ci int rc; 24038c2ecf20Sopenharmony_ci 24048c2ecf20Sopenharmony_ci rc = qed_mcp_cmd(p_hwfn, p_ptt, 24058c2ecf20Sopenharmony_ci DRV_MSG_CODE_GET_PF_RDMA_PROTOCOL, 0, &resp, ¶m); 24068c2ecf20Sopenharmony_ci if (rc) 24078c2ecf20Sopenharmony_ci return rc; 24088c2ecf20Sopenharmony_ci if (resp != FW_MSG_CODE_OK) { 24098c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, NETIF_MSG_IFUP, 24108c2ecf20Sopenharmony_ci "MFW lacks support for command; Returns %08x\n", 24118c2ecf20Sopenharmony_ci resp); 24128c2ecf20Sopenharmony_ci return -EINVAL; 24138c2ecf20Sopenharmony_ci } 24148c2ecf20Sopenharmony_ci 24158c2ecf20Sopenharmony_ci switch (param) { 24168c2ecf20Sopenharmony_ci case FW_MB_PARAM_GET_PF_RDMA_NONE: 24178c2ecf20Sopenharmony_ci *p_proto = QED_PCI_ETH; 24188c2ecf20Sopenharmony_ci break; 24198c2ecf20Sopenharmony_ci case FW_MB_PARAM_GET_PF_RDMA_ROCE: 24208c2ecf20Sopenharmony_ci *p_proto = QED_PCI_ETH_ROCE; 24218c2ecf20Sopenharmony_ci break; 24228c2ecf20Sopenharmony_ci case FW_MB_PARAM_GET_PF_RDMA_IWARP: 24238c2ecf20Sopenharmony_ci *p_proto = QED_PCI_ETH_IWARP; 24248c2ecf20Sopenharmony_ci break; 24258c2ecf20Sopenharmony_ci case FW_MB_PARAM_GET_PF_RDMA_BOTH: 24268c2ecf20Sopenharmony_ci *p_proto = QED_PCI_ETH_RDMA; 24278c2ecf20Sopenharmony_ci break; 24288c2ecf20Sopenharmony_ci default: 24298c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, 24308c2ecf20Sopenharmony_ci "MFW answers GET_PF_RDMA_PROTOCOL but param is %08x\n", 24318c2ecf20Sopenharmony_ci param); 24328c2ecf20Sopenharmony_ci return -EINVAL; 24338c2ecf20Sopenharmony_ci } 24348c2ecf20Sopenharmony_ci 24358c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, 24368c2ecf20Sopenharmony_ci NETIF_MSG_IFUP, 24378c2ecf20Sopenharmony_ci "According to capabilities, L2 personality is %08x [resp %08x param %08x]\n", 24388c2ecf20Sopenharmony_ci (u32) *p_proto, resp, param); 24398c2ecf20Sopenharmony_ci return 0; 24408c2ecf20Sopenharmony_ci} 24418c2ecf20Sopenharmony_ci 24428c2ecf20Sopenharmony_cistatic int 24438c2ecf20Sopenharmony_ciqed_mcp_get_shmem_proto(struct qed_hwfn *p_hwfn, 24448c2ecf20Sopenharmony_ci struct public_func *p_info, 24458c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt, 24468c2ecf20Sopenharmony_ci enum qed_pci_personality *p_proto) 24478c2ecf20Sopenharmony_ci{ 24488c2ecf20Sopenharmony_ci int rc = 0; 24498c2ecf20Sopenharmony_ci 24508c2ecf20Sopenharmony_ci switch (p_info->config & FUNC_MF_CFG_PROTOCOL_MASK) { 24518c2ecf20Sopenharmony_ci case FUNC_MF_CFG_PROTOCOL_ETHERNET: 24528c2ecf20Sopenharmony_ci if (!IS_ENABLED(CONFIG_QED_RDMA)) 24538c2ecf20Sopenharmony_ci *p_proto = QED_PCI_ETH; 24548c2ecf20Sopenharmony_ci else if (qed_mcp_get_shmem_proto_mfw(p_hwfn, p_ptt, p_proto)) 24558c2ecf20Sopenharmony_ci qed_mcp_get_shmem_proto_legacy(p_hwfn, p_proto); 24568c2ecf20Sopenharmony_ci break; 24578c2ecf20Sopenharmony_ci case FUNC_MF_CFG_PROTOCOL_ISCSI: 24588c2ecf20Sopenharmony_ci *p_proto = QED_PCI_ISCSI; 24598c2ecf20Sopenharmony_ci break; 24608c2ecf20Sopenharmony_ci case FUNC_MF_CFG_PROTOCOL_FCOE: 24618c2ecf20Sopenharmony_ci *p_proto = QED_PCI_FCOE; 24628c2ecf20Sopenharmony_ci break; 24638c2ecf20Sopenharmony_ci case FUNC_MF_CFG_PROTOCOL_ROCE: 24648c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, "RoCE personality is not a valid value!\n"); 24658c2ecf20Sopenharmony_ci fallthrough; 24668c2ecf20Sopenharmony_ci default: 24678c2ecf20Sopenharmony_ci rc = -EINVAL; 24688c2ecf20Sopenharmony_ci } 24698c2ecf20Sopenharmony_ci 24708c2ecf20Sopenharmony_ci return rc; 24718c2ecf20Sopenharmony_ci} 24728c2ecf20Sopenharmony_ci 24738c2ecf20Sopenharmony_ciint qed_mcp_fill_shmem_func_info(struct qed_hwfn *p_hwfn, 24748c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt) 24758c2ecf20Sopenharmony_ci{ 24768c2ecf20Sopenharmony_ci struct qed_mcp_function_info *info; 24778c2ecf20Sopenharmony_ci struct public_func shmem_info; 24788c2ecf20Sopenharmony_ci 24798c2ecf20Sopenharmony_ci qed_mcp_get_shmem_func(p_hwfn, p_ptt, &shmem_info, MCP_PF_ID(p_hwfn)); 24808c2ecf20Sopenharmony_ci info = &p_hwfn->mcp_info->func_info; 24818c2ecf20Sopenharmony_ci 24828c2ecf20Sopenharmony_ci info->pause_on_host = (shmem_info.config & 24838c2ecf20Sopenharmony_ci FUNC_MF_CFG_PAUSE_ON_HOST_RING) ? 1 : 0; 24848c2ecf20Sopenharmony_ci 24858c2ecf20Sopenharmony_ci if (qed_mcp_get_shmem_proto(p_hwfn, &shmem_info, p_ptt, 24868c2ecf20Sopenharmony_ci &info->protocol)) { 24878c2ecf20Sopenharmony_ci DP_ERR(p_hwfn, "Unknown personality %08x\n", 24888c2ecf20Sopenharmony_ci (u32)(shmem_info.config & FUNC_MF_CFG_PROTOCOL_MASK)); 24898c2ecf20Sopenharmony_ci return -EINVAL; 24908c2ecf20Sopenharmony_ci } 24918c2ecf20Sopenharmony_ci 24928c2ecf20Sopenharmony_ci qed_read_pf_bandwidth(p_hwfn, &shmem_info); 24938c2ecf20Sopenharmony_ci 24948c2ecf20Sopenharmony_ci if (shmem_info.mac_upper || shmem_info.mac_lower) { 24958c2ecf20Sopenharmony_ci info->mac[0] = (u8)(shmem_info.mac_upper >> 8); 24968c2ecf20Sopenharmony_ci info->mac[1] = (u8)(shmem_info.mac_upper); 24978c2ecf20Sopenharmony_ci info->mac[2] = (u8)(shmem_info.mac_lower >> 24); 24988c2ecf20Sopenharmony_ci info->mac[3] = (u8)(shmem_info.mac_lower >> 16); 24998c2ecf20Sopenharmony_ci info->mac[4] = (u8)(shmem_info.mac_lower >> 8); 25008c2ecf20Sopenharmony_ci info->mac[5] = (u8)(shmem_info.mac_lower); 25018c2ecf20Sopenharmony_ci 25028c2ecf20Sopenharmony_ci /* Store primary MAC for later possible WoL */ 25038c2ecf20Sopenharmony_ci memcpy(&p_hwfn->cdev->wol_mac, info->mac, ETH_ALEN); 25048c2ecf20Sopenharmony_ci } else { 25058c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, "MAC is 0 in shmem\n"); 25068c2ecf20Sopenharmony_ci } 25078c2ecf20Sopenharmony_ci 25088c2ecf20Sopenharmony_ci info->wwn_port = (u64)shmem_info.fcoe_wwn_port_name_lower | 25098c2ecf20Sopenharmony_ci (((u64)shmem_info.fcoe_wwn_port_name_upper) << 32); 25108c2ecf20Sopenharmony_ci info->wwn_node = (u64)shmem_info.fcoe_wwn_node_name_lower | 25118c2ecf20Sopenharmony_ci (((u64)shmem_info.fcoe_wwn_node_name_upper) << 32); 25128c2ecf20Sopenharmony_ci 25138c2ecf20Sopenharmony_ci info->ovlan = (u16)(shmem_info.ovlan_stag & FUNC_MF_CFG_OV_STAG_MASK); 25148c2ecf20Sopenharmony_ci 25158c2ecf20Sopenharmony_ci info->mtu = (u16)shmem_info.mtu_size; 25168c2ecf20Sopenharmony_ci 25178c2ecf20Sopenharmony_ci p_hwfn->hw_info.b_wol_support = QED_WOL_SUPPORT_NONE; 25188c2ecf20Sopenharmony_ci p_hwfn->cdev->wol_config = (u8)QED_OV_WOL_DEFAULT; 25198c2ecf20Sopenharmony_ci if (qed_mcp_is_init(p_hwfn)) { 25208c2ecf20Sopenharmony_ci u32 resp = 0, param = 0; 25218c2ecf20Sopenharmony_ci int rc; 25228c2ecf20Sopenharmony_ci 25238c2ecf20Sopenharmony_ci rc = qed_mcp_cmd(p_hwfn, p_ptt, 25248c2ecf20Sopenharmony_ci DRV_MSG_CODE_OS_WOL, 0, &resp, ¶m); 25258c2ecf20Sopenharmony_ci if (rc) 25268c2ecf20Sopenharmony_ci return rc; 25278c2ecf20Sopenharmony_ci if (resp == FW_MSG_CODE_OS_WOL_SUPPORTED) 25288c2ecf20Sopenharmony_ci p_hwfn->hw_info.b_wol_support = QED_WOL_SUPPORT_PME; 25298c2ecf20Sopenharmony_ci } 25308c2ecf20Sopenharmony_ci 25318c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, (QED_MSG_SP | NETIF_MSG_IFUP), 25328c2ecf20Sopenharmony_ci "Read configuration from shmem: pause_on_host %02x protocol %02x BW [%02x - %02x] MAC %pM wwn port %llx node %llx ovlan %04x wol %02x\n", 25338c2ecf20Sopenharmony_ci info->pause_on_host, info->protocol, 25348c2ecf20Sopenharmony_ci info->bandwidth_min, info->bandwidth_max, 25358c2ecf20Sopenharmony_ci info->mac, 25368c2ecf20Sopenharmony_ci info->wwn_port, info->wwn_node, 25378c2ecf20Sopenharmony_ci info->ovlan, (u8)p_hwfn->hw_info.b_wol_support); 25388c2ecf20Sopenharmony_ci 25398c2ecf20Sopenharmony_ci return 0; 25408c2ecf20Sopenharmony_ci} 25418c2ecf20Sopenharmony_ci 25428c2ecf20Sopenharmony_cistruct qed_mcp_link_params 25438c2ecf20Sopenharmony_ci*qed_mcp_get_link_params(struct qed_hwfn *p_hwfn) 25448c2ecf20Sopenharmony_ci{ 25458c2ecf20Sopenharmony_ci if (!p_hwfn || !p_hwfn->mcp_info) 25468c2ecf20Sopenharmony_ci return NULL; 25478c2ecf20Sopenharmony_ci return &p_hwfn->mcp_info->link_input; 25488c2ecf20Sopenharmony_ci} 25498c2ecf20Sopenharmony_ci 25508c2ecf20Sopenharmony_cistruct qed_mcp_link_state 25518c2ecf20Sopenharmony_ci*qed_mcp_get_link_state(struct qed_hwfn *p_hwfn) 25528c2ecf20Sopenharmony_ci{ 25538c2ecf20Sopenharmony_ci if (!p_hwfn || !p_hwfn->mcp_info) 25548c2ecf20Sopenharmony_ci return NULL; 25558c2ecf20Sopenharmony_ci return &p_hwfn->mcp_info->link_output; 25568c2ecf20Sopenharmony_ci} 25578c2ecf20Sopenharmony_ci 25588c2ecf20Sopenharmony_cistruct qed_mcp_link_capabilities 25598c2ecf20Sopenharmony_ci*qed_mcp_get_link_capabilities(struct qed_hwfn *p_hwfn) 25608c2ecf20Sopenharmony_ci{ 25618c2ecf20Sopenharmony_ci if (!p_hwfn || !p_hwfn->mcp_info) 25628c2ecf20Sopenharmony_ci return NULL; 25638c2ecf20Sopenharmony_ci return &p_hwfn->mcp_info->link_capabilities; 25648c2ecf20Sopenharmony_ci} 25658c2ecf20Sopenharmony_ci 25668c2ecf20Sopenharmony_ciint qed_mcp_drain(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 25678c2ecf20Sopenharmony_ci{ 25688c2ecf20Sopenharmony_ci u32 resp = 0, param = 0; 25698c2ecf20Sopenharmony_ci int rc; 25708c2ecf20Sopenharmony_ci 25718c2ecf20Sopenharmony_ci rc = qed_mcp_cmd(p_hwfn, p_ptt, 25728c2ecf20Sopenharmony_ci DRV_MSG_CODE_NIG_DRAIN, 1000, &resp, ¶m); 25738c2ecf20Sopenharmony_ci 25748c2ecf20Sopenharmony_ci /* Wait for the drain to complete before returning */ 25758c2ecf20Sopenharmony_ci msleep(1020); 25768c2ecf20Sopenharmony_ci 25778c2ecf20Sopenharmony_ci return rc; 25788c2ecf20Sopenharmony_ci} 25798c2ecf20Sopenharmony_ci 25808c2ecf20Sopenharmony_ciint qed_mcp_get_flash_size(struct qed_hwfn *p_hwfn, 25818c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt, u32 *p_flash_size) 25828c2ecf20Sopenharmony_ci{ 25838c2ecf20Sopenharmony_ci u32 flash_size; 25848c2ecf20Sopenharmony_ci 25858c2ecf20Sopenharmony_ci if (IS_VF(p_hwfn->cdev)) 25868c2ecf20Sopenharmony_ci return -EINVAL; 25878c2ecf20Sopenharmony_ci 25888c2ecf20Sopenharmony_ci flash_size = qed_rd(p_hwfn, p_ptt, MCP_REG_NVM_CFG4); 25898c2ecf20Sopenharmony_ci flash_size = (flash_size & MCP_REG_NVM_CFG4_FLASH_SIZE) >> 25908c2ecf20Sopenharmony_ci MCP_REG_NVM_CFG4_FLASH_SIZE_SHIFT; 25918c2ecf20Sopenharmony_ci flash_size = (1 << (flash_size + MCP_BYTES_PER_MBIT_SHIFT)); 25928c2ecf20Sopenharmony_ci 25938c2ecf20Sopenharmony_ci *p_flash_size = flash_size; 25948c2ecf20Sopenharmony_ci 25958c2ecf20Sopenharmony_ci return 0; 25968c2ecf20Sopenharmony_ci} 25978c2ecf20Sopenharmony_ci 25988c2ecf20Sopenharmony_ciint qed_start_recovery_process(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 25998c2ecf20Sopenharmony_ci{ 26008c2ecf20Sopenharmony_ci struct qed_dev *cdev = p_hwfn->cdev; 26018c2ecf20Sopenharmony_ci 26028c2ecf20Sopenharmony_ci if (cdev->recov_in_prog) { 26038c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, 26048c2ecf20Sopenharmony_ci "Avoid triggering a recovery since such a process is already in progress\n"); 26058c2ecf20Sopenharmony_ci return -EAGAIN; 26068c2ecf20Sopenharmony_ci } 26078c2ecf20Sopenharmony_ci 26088c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, "Triggering a recovery process\n"); 26098c2ecf20Sopenharmony_ci qed_wr(p_hwfn, p_ptt, MISC_REG_AEU_GENERAL_ATTN_35, 0x1); 26108c2ecf20Sopenharmony_ci 26118c2ecf20Sopenharmony_ci return 0; 26128c2ecf20Sopenharmony_ci} 26138c2ecf20Sopenharmony_ci 26148c2ecf20Sopenharmony_ci#define QED_RECOVERY_PROLOG_SLEEP_MS 100 26158c2ecf20Sopenharmony_ci 26168c2ecf20Sopenharmony_ciint qed_recovery_prolog(struct qed_dev *cdev) 26178c2ecf20Sopenharmony_ci{ 26188c2ecf20Sopenharmony_ci struct qed_hwfn *p_hwfn = QED_LEADING_HWFN(cdev); 26198c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt = p_hwfn->p_main_ptt; 26208c2ecf20Sopenharmony_ci int rc; 26218c2ecf20Sopenharmony_ci 26228c2ecf20Sopenharmony_ci /* Allow ongoing PCIe transactions to complete */ 26238c2ecf20Sopenharmony_ci msleep(QED_RECOVERY_PROLOG_SLEEP_MS); 26248c2ecf20Sopenharmony_ci 26258c2ecf20Sopenharmony_ci /* Clear the PF's internal FID_enable in the PXP */ 26268c2ecf20Sopenharmony_ci rc = qed_pglueb_set_pfid_enable(p_hwfn, p_ptt, false); 26278c2ecf20Sopenharmony_ci if (rc) 26288c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, 26298c2ecf20Sopenharmony_ci "qed_pglueb_set_pfid_enable() failed. rc = %d.\n", 26308c2ecf20Sopenharmony_ci rc); 26318c2ecf20Sopenharmony_ci 26328c2ecf20Sopenharmony_ci return rc; 26338c2ecf20Sopenharmony_ci} 26348c2ecf20Sopenharmony_ci 26358c2ecf20Sopenharmony_cistatic int 26368c2ecf20Sopenharmony_ciqed_mcp_config_vf_msix_bb(struct qed_hwfn *p_hwfn, 26378c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt, u8 vf_id, u8 num) 26388c2ecf20Sopenharmony_ci{ 26398c2ecf20Sopenharmony_ci u32 resp = 0, param = 0, rc_param = 0; 26408c2ecf20Sopenharmony_ci int rc; 26418c2ecf20Sopenharmony_ci 26428c2ecf20Sopenharmony_ci /* Only Leader can configure MSIX, and need to take CMT into account */ 26438c2ecf20Sopenharmony_ci if (!IS_LEAD_HWFN(p_hwfn)) 26448c2ecf20Sopenharmony_ci return 0; 26458c2ecf20Sopenharmony_ci num *= p_hwfn->cdev->num_hwfns; 26468c2ecf20Sopenharmony_ci 26478c2ecf20Sopenharmony_ci param |= (vf_id << DRV_MB_PARAM_CFG_VF_MSIX_VF_ID_SHIFT) & 26488c2ecf20Sopenharmony_ci DRV_MB_PARAM_CFG_VF_MSIX_VF_ID_MASK; 26498c2ecf20Sopenharmony_ci param |= (num << DRV_MB_PARAM_CFG_VF_MSIX_SB_NUM_SHIFT) & 26508c2ecf20Sopenharmony_ci DRV_MB_PARAM_CFG_VF_MSIX_SB_NUM_MASK; 26518c2ecf20Sopenharmony_ci 26528c2ecf20Sopenharmony_ci rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_CFG_VF_MSIX, param, 26538c2ecf20Sopenharmony_ci &resp, &rc_param); 26548c2ecf20Sopenharmony_ci 26558c2ecf20Sopenharmony_ci if (resp != FW_MSG_CODE_DRV_CFG_VF_MSIX_DONE) { 26568c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, "VF[%d]: MFW failed to set MSI-X\n", vf_id); 26578c2ecf20Sopenharmony_ci rc = -EINVAL; 26588c2ecf20Sopenharmony_ci } else { 26598c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, QED_MSG_IOV, 26608c2ecf20Sopenharmony_ci "Requested 0x%02x MSI-x interrupts from VF 0x%02x\n", 26618c2ecf20Sopenharmony_ci num, vf_id); 26628c2ecf20Sopenharmony_ci } 26638c2ecf20Sopenharmony_ci 26648c2ecf20Sopenharmony_ci return rc; 26658c2ecf20Sopenharmony_ci} 26668c2ecf20Sopenharmony_ci 26678c2ecf20Sopenharmony_cistatic int 26688c2ecf20Sopenharmony_ciqed_mcp_config_vf_msix_ah(struct qed_hwfn *p_hwfn, 26698c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt, u8 num) 26708c2ecf20Sopenharmony_ci{ 26718c2ecf20Sopenharmony_ci u32 resp = 0, param = num, rc_param = 0; 26728c2ecf20Sopenharmony_ci int rc; 26738c2ecf20Sopenharmony_ci 26748c2ecf20Sopenharmony_ci rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_CFG_PF_VFS_MSIX, 26758c2ecf20Sopenharmony_ci param, &resp, &rc_param); 26768c2ecf20Sopenharmony_ci 26778c2ecf20Sopenharmony_ci if (resp != FW_MSG_CODE_DRV_CFG_PF_VFS_MSIX_DONE) { 26788c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, "MFW failed to set MSI-X for VFs\n"); 26798c2ecf20Sopenharmony_ci rc = -EINVAL; 26808c2ecf20Sopenharmony_ci } else { 26818c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, QED_MSG_IOV, 26828c2ecf20Sopenharmony_ci "Requested 0x%02x MSI-x interrupts for VFs\n", num); 26838c2ecf20Sopenharmony_ci } 26848c2ecf20Sopenharmony_ci 26858c2ecf20Sopenharmony_ci return rc; 26868c2ecf20Sopenharmony_ci} 26878c2ecf20Sopenharmony_ci 26888c2ecf20Sopenharmony_ciint qed_mcp_config_vf_msix(struct qed_hwfn *p_hwfn, 26898c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt, u8 vf_id, u8 num) 26908c2ecf20Sopenharmony_ci{ 26918c2ecf20Sopenharmony_ci if (QED_IS_BB(p_hwfn->cdev)) 26928c2ecf20Sopenharmony_ci return qed_mcp_config_vf_msix_bb(p_hwfn, p_ptt, vf_id, num); 26938c2ecf20Sopenharmony_ci else 26948c2ecf20Sopenharmony_ci return qed_mcp_config_vf_msix_ah(p_hwfn, p_ptt, num); 26958c2ecf20Sopenharmony_ci} 26968c2ecf20Sopenharmony_ci 26978c2ecf20Sopenharmony_ciint 26988c2ecf20Sopenharmony_ciqed_mcp_send_drv_version(struct qed_hwfn *p_hwfn, 26998c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt, 27008c2ecf20Sopenharmony_ci struct qed_mcp_drv_version *p_ver) 27018c2ecf20Sopenharmony_ci{ 27028c2ecf20Sopenharmony_ci struct qed_mcp_mb_params mb_params; 27038c2ecf20Sopenharmony_ci struct drv_version_stc drv_version; 27048c2ecf20Sopenharmony_ci __be32 val; 27058c2ecf20Sopenharmony_ci u32 i; 27068c2ecf20Sopenharmony_ci int rc; 27078c2ecf20Sopenharmony_ci 27088c2ecf20Sopenharmony_ci memset(&drv_version, 0, sizeof(drv_version)); 27098c2ecf20Sopenharmony_ci drv_version.version = p_ver->version; 27108c2ecf20Sopenharmony_ci for (i = 0; i < (MCP_DRV_VER_STR_SIZE - 4) / sizeof(u32); i++) { 27118c2ecf20Sopenharmony_ci val = cpu_to_be32(*((u32 *)&p_ver->name[i * sizeof(u32)])); 27128c2ecf20Sopenharmony_ci *(__be32 *)&drv_version.name[i * sizeof(u32)] = val; 27138c2ecf20Sopenharmony_ci } 27148c2ecf20Sopenharmony_ci 27158c2ecf20Sopenharmony_ci memset(&mb_params, 0, sizeof(mb_params)); 27168c2ecf20Sopenharmony_ci mb_params.cmd = DRV_MSG_CODE_SET_VERSION; 27178c2ecf20Sopenharmony_ci mb_params.p_data_src = &drv_version; 27188c2ecf20Sopenharmony_ci mb_params.data_src_size = sizeof(drv_version); 27198c2ecf20Sopenharmony_ci rc = qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 27208c2ecf20Sopenharmony_ci if (rc) 27218c2ecf20Sopenharmony_ci DP_ERR(p_hwfn, "MCP response failure, aborting\n"); 27228c2ecf20Sopenharmony_ci 27238c2ecf20Sopenharmony_ci return rc; 27248c2ecf20Sopenharmony_ci} 27258c2ecf20Sopenharmony_ci 27268c2ecf20Sopenharmony_ci/* A maximal 100 msec waiting time for the MCP to halt */ 27278c2ecf20Sopenharmony_ci#define QED_MCP_HALT_SLEEP_MS 10 27288c2ecf20Sopenharmony_ci#define QED_MCP_HALT_MAX_RETRIES 10 27298c2ecf20Sopenharmony_ci 27308c2ecf20Sopenharmony_ciint qed_mcp_halt(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 27318c2ecf20Sopenharmony_ci{ 27328c2ecf20Sopenharmony_ci u32 resp = 0, param = 0, cpu_state, cnt = 0; 27338c2ecf20Sopenharmony_ci int rc; 27348c2ecf20Sopenharmony_ci 27358c2ecf20Sopenharmony_ci rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_MCP_HALT, 0, &resp, 27368c2ecf20Sopenharmony_ci ¶m); 27378c2ecf20Sopenharmony_ci if (rc) { 27388c2ecf20Sopenharmony_ci DP_ERR(p_hwfn, "MCP response failure, aborting\n"); 27398c2ecf20Sopenharmony_ci return rc; 27408c2ecf20Sopenharmony_ci } 27418c2ecf20Sopenharmony_ci 27428c2ecf20Sopenharmony_ci do { 27438c2ecf20Sopenharmony_ci msleep(QED_MCP_HALT_SLEEP_MS); 27448c2ecf20Sopenharmony_ci cpu_state = qed_rd(p_hwfn, p_ptt, MCP_REG_CPU_STATE); 27458c2ecf20Sopenharmony_ci if (cpu_state & MCP_REG_CPU_STATE_SOFT_HALTED) 27468c2ecf20Sopenharmony_ci break; 27478c2ecf20Sopenharmony_ci } while (++cnt < QED_MCP_HALT_MAX_RETRIES); 27488c2ecf20Sopenharmony_ci 27498c2ecf20Sopenharmony_ci if (cnt == QED_MCP_HALT_MAX_RETRIES) { 27508c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, 27518c2ecf20Sopenharmony_ci "Failed to halt the MCP [CPU_MODE = 0x%08x, CPU_STATE = 0x%08x]\n", 27528c2ecf20Sopenharmony_ci qed_rd(p_hwfn, p_ptt, MCP_REG_CPU_MODE), cpu_state); 27538c2ecf20Sopenharmony_ci return -EBUSY; 27548c2ecf20Sopenharmony_ci } 27558c2ecf20Sopenharmony_ci 27568c2ecf20Sopenharmony_ci qed_mcp_cmd_set_blocking(p_hwfn, true); 27578c2ecf20Sopenharmony_ci 27588c2ecf20Sopenharmony_ci return 0; 27598c2ecf20Sopenharmony_ci} 27608c2ecf20Sopenharmony_ci 27618c2ecf20Sopenharmony_ci#define QED_MCP_RESUME_SLEEP_MS 10 27628c2ecf20Sopenharmony_ci 27638c2ecf20Sopenharmony_ciint qed_mcp_resume(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 27648c2ecf20Sopenharmony_ci{ 27658c2ecf20Sopenharmony_ci u32 cpu_mode, cpu_state; 27668c2ecf20Sopenharmony_ci 27678c2ecf20Sopenharmony_ci qed_wr(p_hwfn, p_ptt, MCP_REG_CPU_STATE, 0xffffffff); 27688c2ecf20Sopenharmony_ci 27698c2ecf20Sopenharmony_ci cpu_mode = qed_rd(p_hwfn, p_ptt, MCP_REG_CPU_MODE); 27708c2ecf20Sopenharmony_ci cpu_mode &= ~MCP_REG_CPU_MODE_SOFT_HALT; 27718c2ecf20Sopenharmony_ci qed_wr(p_hwfn, p_ptt, MCP_REG_CPU_MODE, cpu_mode); 27728c2ecf20Sopenharmony_ci msleep(QED_MCP_RESUME_SLEEP_MS); 27738c2ecf20Sopenharmony_ci cpu_state = qed_rd(p_hwfn, p_ptt, MCP_REG_CPU_STATE); 27748c2ecf20Sopenharmony_ci 27758c2ecf20Sopenharmony_ci if (cpu_state & MCP_REG_CPU_STATE_SOFT_HALTED) { 27768c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, 27778c2ecf20Sopenharmony_ci "Failed to resume the MCP [CPU_MODE = 0x%08x, CPU_STATE = 0x%08x]\n", 27788c2ecf20Sopenharmony_ci cpu_mode, cpu_state); 27798c2ecf20Sopenharmony_ci return -EBUSY; 27808c2ecf20Sopenharmony_ci } 27818c2ecf20Sopenharmony_ci 27828c2ecf20Sopenharmony_ci qed_mcp_cmd_set_blocking(p_hwfn, false); 27838c2ecf20Sopenharmony_ci 27848c2ecf20Sopenharmony_ci return 0; 27858c2ecf20Sopenharmony_ci} 27868c2ecf20Sopenharmony_ci 27878c2ecf20Sopenharmony_ciint qed_mcp_ov_update_current_config(struct qed_hwfn *p_hwfn, 27888c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt, 27898c2ecf20Sopenharmony_ci enum qed_ov_client client) 27908c2ecf20Sopenharmony_ci{ 27918c2ecf20Sopenharmony_ci u32 resp = 0, param = 0; 27928c2ecf20Sopenharmony_ci u32 drv_mb_param; 27938c2ecf20Sopenharmony_ci int rc; 27948c2ecf20Sopenharmony_ci 27958c2ecf20Sopenharmony_ci switch (client) { 27968c2ecf20Sopenharmony_ci case QED_OV_CLIENT_DRV: 27978c2ecf20Sopenharmony_ci drv_mb_param = DRV_MB_PARAM_OV_CURR_CFG_OS; 27988c2ecf20Sopenharmony_ci break; 27998c2ecf20Sopenharmony_ci case QED_OV_CLIENT_USER: 28008c2ecf20Sopenharmony_ci drv_mb_param = DRV_MB_PARAM_OV_CURR_CFG_OTHER; 28018c2ecf20Sopenharmony_ci break; 28028c2ecf20Sopenharmony_ci case QED_OV_CLIENT_VENDOR_SPEC: 28038c2ecf20Sopenharmony_ci drv_mb_param = DRV_MB_PARAM_OV_CURR_CFG_VENDOR_SPEC; 28048c2ecf20Sopenharmony_ci break; 28058c2ecf20Sopenharmony_ci default: 28068c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, "Invalid client type %d\n", client); 28078c2ecf20Sopenharmony_ci return -EINVAL; 28088c2ecf20Sopenharmony_ci } 28098c2ecf20Sopenharmony_ci 28108c2ecf20Sopenharmony_ci rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_OV_UPDATE_CURR_CFG, 28118c2ecf20Sopenharmony_ci drv_mb_param, &resp, ¶m); 28128c2ecf20Sopenharmony_ci if (rc) 28138c2ecf20Sopenharmony_ci DP_ERR(p_hwfn, "MCP response failure, aborting\n"); 28148c2ecf20Sopenharmony_ci 28158c2ecf20Sopenharmony_ci return rc; 28168c2ecf20Sopenharmony_ci} 28178c2ecf20Sopenharmony_ci 28188c2ecf20Sopenharmony_ciint qed_mcp_ov_update_driver_state(struct qed_hwfn *p_hwfn, 28198c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt, 28208c2ecf20Sopenharmony_ci enum qed_ov_driver_state drv_state) 28218c2ecf20Sopenharmony_ci{ 28228c2ecf20Sopenharmony_ci u32 resp = 0, param = 0; 28238c2ecf20Sopenharmony_ci u32 drv_mb_param; 28248c2ecf20Sopenharmony_ci int rc; 28258c2ecf20Sopenharmony_ci 28268c2ecf20Sopenharmony_ci switch (drv_state) { 28278c2ecf20Sopenharmony_ci case QED_OV_DRIVER_STATE_NOT_LOADED: 28288c2ecf20Sopenharmony_ci drv_mb_param = DRV_MSG_CODE_OV_UPDATE_DRIVER_STATE_NOT_LOADED; 28298c2ecf20Sopenharmony_ci break; 28308c2ecf20Sopenharmony_ci case QED_OV_DRIVER_STATE_DISABLED: 28318c2ecf20Sopenharmony_ci drv_mb_param = DRV_MSG_CODE_OV_UPDATE_DRIVER_STATE_DISABLED; 28328c2ecf20Sopenharmony_ci break; 28338c2ecf20Sopenharmony_ci case QED_OV_DRIVER_STATE_ACTIVE: 28348c2ecf20Sopenharmony_ci drv_mb_param = DRV_MSG_CODE_OV_UPDATE_DRIVER_STATE_ACTIVE; 28358c2ecf20Sopenharmony_ci break; 28368c2ecf20Sopenharmony_ci default: 28378c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, "Invalid driver state %d\n", drv_state); 28388c2ecf20Sopenharmony_ci return -EINVAL; 28398c2ecf20Sopenharmony_ci } 28408c2ecf20Sopenharmony_ci 28418c2ecf20Sopenharmony_ci rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_OV_UPDATE_DRIVER_STATE, 28428c2ecf20Sopenharmony_ci drv_mb_param, &resp, ¶m); 28438c2ecf20Sopenharmony_ci if (rc) 28448c2ecf20Sopenharmony_ci DP_ERR(p_hwfn, "Failed to send driver state\n"); 28458c2ecf20Sopenharmony_ci 28468c2ecf20Sopenharmony_ci return rc; 28478c2ecf20Sopenharmony_ci} 28488c2ecf20Sopenharmony_ci 28498c2ecf20Sopenharmony_ciint qed_mcp_ov_update_mtu(struct qed_hwfn *p_hwfn, 28508c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt, u16 mtu) 28518c2ecf20Sopenharmony_ci{ 28528c2ecf20Sopenharmony_ci u32 resp = 0, param = 0; 28538c2ecf20Sopenharmony_ci u32 drv_mb_param; 28548c2ecf20Sopenharmony_ci int rc; 28558c2ecf20Sopenharmony_ci 28568c2ecf20Sopenharmony_ci drv_mb_param = (u32)mtu << DRV_MB_PARAM_OV_MTU_SIZE_SHIFT; 28578c2ecf20Sopenharmony_ci rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_OV_UPDATE_MTU, 28588c2ecf20Sopenharmony_ci drv_mb_param, &resp, ¶m); 28598c2ecf20Sopenharmony_ci if (rc) 28608c2ecf20Sopenharmony_ci DP_ERR(p_hwfn, "Failed to send mtu value, rc = %d\n", rc); 28618c2ecf20Sopenharmony_ci 28628c2ecf20Sopenharmony_ci return rc; 28638c2ecf20Sopenharmony_ci} 28648c2ecf20Sopenharmony_ci 28658c2ecf20Sopenharmony_ciint qed_mcp_ov_update_mac(struct qed_hwfn *p_hwfn, 28668c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt, u8 *mac) 28678c2ecf20Sopenharmony_ci{ 28688c2ecf20Sopenharmony_ci struct qed_mcp_mb_params mb_params; 28698c2ecf20Sopenharmony_ci u32 mfw_mac[2]; 28708c2ecf20Sopenharmony_ci int rc; 28718c2ecf20Sopenharmony_ci 28728c2ecf20Sopenharmony_ci memset(&mb_params, 0, sizeof(mb_params)); 28738c2ecf20Sopenharmony_ci mb_params.cmd = DRV_MSG_CODE_SET_VMAC; 28748c2ecf20Sopenharmony_ci mb_params.param = DRV_MSG_CODE_VMAC_TYPE_MAC << 28758c2ecf20Sopenharmony_ci DRV_MSG_CODE_VMAC_TYPE_SHIFT; 28768c2ecf20Sopenharmony_ci mb_params.param |= MCP_PF_ID(p_hwfn); 28778c2ecf20Sopenharmony_ci 28788c2ecf20Sopenharmony_ci /* MCP is BE, and on LE platforms PCI would swap access to SHMEM 28798c2ecf20Sopenharmony_ci * in 32-bit granularity. 28808c2ecf20Sopenharmony_ci * So the MAC has to be set in native order [and not byte order], 28818c2ecf20Sopenharmony_ci * otherwise it would be read incorrectly by MFW after swap. 28828c2ecf20Sopenharmony_ci */ 28838c2ecf20Sopenharmony_ci mfw_mac[0] = mac[0] << 24 | mac[1] << 16 | mac[2] << 8 | mac[3]; 28848c2ecf20Sopenharmony_ci mfw_mac[1] = mac[4] << 24 | mac[5] << 16; 28858c2ecf20Sopenharmony_ci 28868c2ecf20Sopenharmony_ci mb_params.p_data_src = (u8 *)mfw_mac; 28878c2ecf20Sopenharmony_ci mb_params.data_src_size = 8; 28888c2ecf20Sopenharmony_ci rc = qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 28898c2ecf20Sopenharmony_ci if (rc) 28908c2ecf20Sopenharmony_ci DP_ERR(p_hwfn, "Failed to send mac address, rc = %d\n", rc); 28918c2ecf20Sopenharmony_ci 28928c2ecf20Sopenharmony_ci /* Store primary MAC for later possible WoL */ 28938c2ecf20Sopenharmony_ci memcpy(p_hwfn->cdev->wol_mac, mac, ETH_ALEN); 28948c2ecf20Sopenharmony_ci 28958c2ecf20Sopenharmony_ci return rc; 28968c2ecf20Sopenharmony_ci} 28978c2ecf20Sopenharmony_ci 28988c2ecf20Sopenharmony_ciint qed_mcp_ov_update_wol(struct qed_hwfn *p_hwfn, 28998c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt, enum qed_ov_wol wol) 29008c2ecf20Sopenharmony_ci{ 29018c2ecf20Sopenharmony_ci u32 resp = 0, param = 0; 29028c2ecf20Sopenharmony_ci u32 drv_mb_param; 29038c2ecf20Sopenharmony_ci int rc; 29048c2ecf20Sopenharmony_ci 29058c2ecf20Sopenharmony_ci if (p_hwfn->hw_info.b_wol_support == QED_WOL_SUPPORT_NONE) { 29068c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, QED_MSG_SP, 29078c2ecf20Sopenharmony_ci "Can't change WoL configuration when WoL isn't supported\n"); 29088c2ecf20Sopenharmony_ci return -EINVAL; 29098c2ecf20Sopenharmony_ci } 29108c2ecf20Sopenharmony_ci 29118c2ecf20Sopenharmony_ci switch (wol) { 29128c2ecf20Sopenharmony_ci case QED_OV_WOL_DEFAULT: 29138c2ecf20Sopenharmony_ci drv_mb_param = DRV_MB_PARAM_WOL_DEFAULT; 29148c2ecf20Sopenharmony_ci break; 29158c2ecf20Sopenharmony_ci case QED_OV_WOL_DISABLED: 29168c2ecf20Sopenharmony_ci drv_mb_param = DRV_MB_PARAM_WOL_DISABLED; 29178c2ecf20Sopenharmony_ci break; 29188c2ecf20Sopenharmony_ci case QED_OV_WOL_ENABLED: 29198c2ecf20Sopenharmony_ci drv_mb_param = DRV_MB_PARAM_WOL_ENABLED; 29208c2ecf20Sopenharmony_ci break; 29218c2ecf20Sopenharmony_ci default: 29228c2ecf20Sopenharmony_ci DP_ERR(p_hwfn, "Invalid wol state %d\n", wol); 29238c2ecf20Sopenharmony_ci return -EINVAL; 29248c2ecf20Sopenharmony_ci } 29258c2ecf20Sopenharmony_ci 29268c2ecf20Sopenharmony_ci rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_OV_UPDATE_WOL, 29278c2ecf20Sopenharmony_ci drv_mb_param, &resp, ¶m); 29288c2ecf20Sopenharmony_ci if (rc) 29298c2ecf20Sopenharmony_ci DP_ERR(p_hwfn, "Failed to send wol mode, rc = %d\n", rc); 29308c2ecf20Sopenharmony_ci 29318c2ecf20Sopenharmony_ci /* Store the WoL update for a future unload */ 29328c2ecf20Sopenharmony_ci p_hwfn->cdev->wol_config = (u8)wol; 29338c2ecf20Sopenharmony_ci 29348c2ecf20Sopenharmony_ci return rc; 29358c2ecf20Sopenharmony_ci} 29368c2ecf20Sopenharmony_ci 29378c2ecf20Sopenharmony_ciint qed_mcp_ov_update_eswitch(struct qed_hwfn *p_hwfn, 29388c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt, 29398c2ecf20Sopenharmony_ci enum qed_ov_eswitch eswitch) 29408c2ecf20Sopenharmony_ci{ 29418c2ecf20Sopenharmony_ci u32 resp = 0, param = 0; 29428c2ecf20Sopenharmony_ci u32 drv_mb_param; 29438c2ecf20Sopenharmony_ci int rc; 29448c2ecf20Sopenharmony_ci 29458c2ecf20Sopenharmony_ci switch (eswitch) { 29468c2ecf20Sopenharmony_ci case QED_OV_ESWITCH_NONE: 29478c2ecf20Sopenharmony_ci drv_mb_param = DRV_MB_PARAM_ESWITCH_MODE_NONE; 29488c2ecf20Sopenharmony_ci break; 29498c2ecf20Sopenharmony_ci case QED_OV_ESWITCH_VEB: 29508c2ecf20Sopenharmony_ci drv_mb_param = DRV_MB_PARAM_ESWITCH_MODE_VEB; 29518c2ecf20Sopenharmony_ci break; 29528c2ecf20Sopenharmony_ci case QED_OV_ESWITCH_VEPA: 29538c2ecf20Sopenharmony_ci drv_mb_param = DRV_MB_PARAM_ESWITCH_MODE_VEPA; 29548c2ecf20Sopenharmony_ci break; 29558c2ecf20Sopenharmony_ci default: 29568c2ecf20Sopenharmony_ci DP_ERR(p_hwfn, "Invalid eswitch mode %d\n", eswitch); 29578c2ecf20Sopenharmony_ci return -EINVAL; 29588c2ecf20Sopenharmony_ci } 29598c2ecf20Sopenharmony_ci 29608c2ecf20Sopenharmony_ci rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_OV_UPDATE_ESWITCH_MODE, 29618c2ecf20Sopenharmony_ci drv_mb_param, &resp, ¶m); 29628c2ecf20Sopenharmony_ci if (rc) 29638c2ecf20Sopenharmony_ci DP_ERR(p_hwfn, "Failed to send eswitch mode, rc = %d\n", rc); 29648c2ecf20Sopenharmony_ci 29658c2ecf20Sopenharmony_ci return rc; 29668c2ecf20Sopenharmony_ci} 29678c2ecf20Sopenharmony_ci 29688c2ecf20Sopenharmony_ciint qed_mcp_set_led(struct qed_hwfn *p_hwfn, 29698c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt, enum qed_led_mode mode) 29708c2ecf20Sopenharmony_ci{ 29718c2ecf20Sopenharmony_ci u32 resp = 0, param = 0, drv_mb_param; 29728c2ecf20Sopenharmony_ci int rc; 29738c2ecf20Sopenharmony_ci 29748c2ecf20Sopenharmony_ci switch (mode) { 29758c2ecf20Sopenharmony_ci case QED_LED_MODE_ON: 29768c2ecf20Sopenharmony_ci drv_mb_param = DRV_MB_PARAM_SET_LED_MODE_ON; 29778c2ecf20Sopenharmony_ci break; 29788c2ecf20Sopenharmony_ci case QED_LED_MODE_OFF: 29798c2ecf20Sopenharmony_ci drv_mb_param = DRV_MB_PARAM_SET_LED_MODE_OFF; 29808c2ecf20Sopenharmony_ci break; 29818c2ecf20Sopenharmony_ci case QED_LED_MODE_RESTORE: 29828c2ecf20Sopenharmony_ci drv_mb_param = DRV_MB_PARAM_SET_LED_MODE_OPER; 29838c2ecf20Sopenharmony_ci break; 29848c2ecf20Sopenharmony_ci default: 29858c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, "Invalid LED mode %d\n", mode); 29868c2ecf20Sopenharmony_ci return -EINVAL; 29878c2ecf20Sopenharmony_ci } 29888c2ecf20Sopenharmony_ci 29898c2ecf20Sopenharmony_ci rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_SET_LED_MODE, 29908c2ecf20Sopenharmony_ci drv_mb_param, &resp, ¶m); 29918c2ecf20Sopenharmony_ci 29928c2ecf20Sopenharmony_ci return rc; 29938c2ecf20Sopenharmony_ci} 29948c2ecf20Sopenharmony_ci 29958c2ecf20Sopenharmony_ciint qed_mcp_mask_parities(struct qed_hwfn *p_hwfn, 29968c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt, u32 mask_parities) 29978c2ecf20Sopenharmony_ci{ 29988c2ecf20Sopenharmony_ci u32 resp = 0, param = 0; 29998c2ecf20Sopenharmony_ci int rc; 30008c2ecf20Sopenharmony_ci 30018c2ecf20Sopenharmony_ci rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_MASK_PARITIES, 30028c2ecf20Sopenharmony_ci mask_parities, &resp, ¶m); 30038c2ecf20Sopenharmony_ci 30048c2ecf20Sopenharmony_ci if (rc) { 30058c2ecf20Sopenharmony_ci DP_ERR(p_hwfn, 30068c2ecf20Sopenharmony_ci "MCP response failure for mask parities, aborting\n"); 30078c2ecf20Sopenharmony_ci } else if (resp != FW_MSG_CODE_OK) { 30088c2ecf20Sopenharmony_ci DP_ERR(p_hwfn, 30098c2ecf20Sopenharmony_ci "MCP did not acknowledge mask parity request. Old MFW?\n"); 30108c2ecf20Sopenharmony_ci rc = -EINVAL; 30118c2ecf20Sopenharmony_ci } 30128c2ecf20Sopenharmony_ci 30138c2ecf20Sopenharmony_ci return rc; 30148c2ecf20Sopenharmony_ci} 30158c2ecf20Sopenharmony_ci 30168c2ecf20Sopenharmony_ciint qed_mcp_nvm_read(struct qed_dev *cdev, u32 addr, u8 *p_buf, u32 len) 30178c2ecf20Sopenharmony_ci{ 30188c2ecf20Sopenharmony_ci u32 bytes_left = len, offset = 0, bytes_to_copy, read_len = 0; 30198c2ecf20Sopenharmony_ci struct qed_hwfn *p_hwfn = QED_LEADING_HWFN(cdev); 30208c2ecf20Sopenharmony_ci u32 resp = 0, resp_param = 0; 30218c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt; 30228c2ecf20Sopenharmony_ci int rc = 0; 30238c2ecf20Sopenharmony_ci 30248c2ecf20Sopenharmony_ci p_ptt = qed_ptt_acquire(p_hwfn); 30258c2ecf20Sopenharmony_ci if (!p_ptt) 30268c2ecf20Sopenharmony_ci return -EBUSY; 30278c2ecf20Sopenharmony_ci 30288c2ecf20Sopenharmony_ci while (bytes_left > 0) { 30298c2ecf20Sopenharmony_ci bytes_to_copy = min_t(u32, bytes_left, MCP_DRV_NVM_BUF_LEN); 30308c2ecf20Sopenharmony_ci 30318c2ecf20Sopenharmony_ci rc = qed_mcp_nvm_rd_cmd(p_hwfn, p_ptt, 30328c2ecf20Sopenharmony_ci DRV_MSG_CODE_NVM_READ_NVRAM, 30338c2ecf20Sopenharmony_ci addr + offset + 30348c2ecf20Sopenharmony_ci (bytes_to_copy << 30358c2ecf20Sopenharmony_ci DRV_MB_PARAM_NVM_LEN_OFFSET), 30368c2ecf20Sopenharmony_ci &resp, &resp_param, 30378c2ecf20Sopenharmony_ci &read_len, 30388c2ecf20Sopenharmony_ci (u32 *)(p_buf + offset)); 30398c2ecf20Sopenharmony_ci 30408c2ecf20Sopenharmony_ci if (rc || (resp != FW_MSG_CODE_NVM_OK)) { 30418c2ecf20Sopenharmony_ci DP_NOTICE(cdev, "MCP command rc = %d\n", rc); 30428c2ecf20Sopenharmony_ci break; 30438c2ecf20Sopenharmony_ci } 30448c2ecf20Sopenharmony_ci 30458c2ecf20Sopenharmony_ci /* This can be a lengthy process, and it's possible scheduler 30468c2ecf20Sopenharmony_ci * isn't preemptable. Sleep a bit to prevent CPU hogging. 30478c2ecf20Sopenharmony_ci */ 30488c2ecf20Sopenharmony_ci if (bytes_left % 0x1000 < 30498c2ecf20Sopenharmony_ci (bytes_left - read_len) % 0x1000) 30508c2ecf20Sopenharmony_ci usleep_range(1000, 2000); 30518c2ecf20Sopenharmony_ci 30528c2ecf20Sopenharmony_ci offset += read_len; 30538c2ecf20Sopenharmony_ci bytes_left -= read_len; 30548c2ecf20Sopenharmony_ci } 30558c2ecf20Sopenharmony_ci 30568c2ecf20Sopenharmony_ci cdev->mcp_nvm_resp = resp; 30578c2ecf20Sopenharmony_ci qed_ptt_release(p_hwfn, p_ptt); 30588c2ecf20Sopenharmony_ci 30598c2ecf20Sopenharmony_ci return rc; 30608c2ecf20Sopenharmony_ci} 30618c2ecf20Sopenharmony_ci 30628c2ecf20Sopenharmony_ciint qed_mcp_nvm_resp(struct qed_dev *cdev, u8 *p_buf) 30638c2ecf20Sopenharmony_ci{ 30648c2ecf20Sopenharmony_ci struct qed_hwfn *p_hwfn = QED_LEADING_HWFN(cdev); 30658c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt; 30668c2ecf20Sopenharmony_ci 30678c2ecf20Sopenharmony_ci p_ptt = qed_ptt_acquire(p_hwfn); 30688c2ecf20Sopenharmony_ci if (!p_ptt) 30698c2ecf20Sopenharmony_ci return -EBUSY; 30708c2ecf20Sopenharmony_ci 30718c2ecf20Sopenharmony_ci memcpy(p_buf, &cdev->mcp_nvm_resp, sizeof(cdev->mcp_nvm_resp)); 30728c2ecf20Sopenharmony_ci qed_ptt_release(p_hwfn, p_ptt); 30738c2ecf20Sopenharmony_ci 30748c2ecf20Sopenharmony_ci return 0; 30758c2ecf20Sopenharmony_ci} 30768c2ecf20Sopenharmony_ci 30778c2ecf20Sopenharmony_ciint qed_mcp_nvm_write(struct qed_dev *cdev, 30788c2ecf20Sopenharmony_ci u32 cmd, u32 addr, u8 *p_buf, u32 len) 30798c2ecf20Sopenharmony_ci{ 30808c2ecf20Sopenharmony_ci u32 buf_idx = 0, buf_size, nvm_cmd, nvm_offset, resp = 0, param; 30818c2ecf20Sopenharmony_ci struct qed_hwfn *p_hwfn = QED_LEADING_HWFN(cdev); 30828c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt; 30838c2ecf20Sopenharmony_ci int rc = -EINVAL; 30848c2ecf20Sopenharmony_ci 30858c2ecf20Sopenharmony_ci p_ptt = qed_ptt_acquire(p_hwfn); 30868c2ecf20Sopenharmony_ci if (!p_ptt) 30878c2ecf20Sopenharmony_ci return -EBUSY; 30888c2ecf20Sopenharmony_ci 30898c2ecf20Sopenharmony_ci switch (cmd) { 30908c2ecf20Sopenharmony_ci case QED_PUT_FILE_BEGIN: 30918c2ecf20Sopenharmony_ci nvm_cmd = DRV_MSG_CODE_NVM_PUT_FILE_BEGIN; 30928c2ecf20Sopenharmony_ci break; 30938c2ecf20Sopenharmony_ci case QED_PUT_FILE_DATA: 30948c2ecf20Sopenharmony_ci nvm_cmd = DRV_MSG_CODE_NVM_PUT_FILE_DATA; 30958c2ecf20Sopenharmony_ci break; 30968c2ecf20Sopenharmony_ci case QED_NVM_WRITE_NVRAM: 30978c2ecf20Sopenharmony_ci nvm_cmd = DRV_MSG_CODE_NVM_WRITE_NVRAM; 30988c2ecf20Sopenharmony_ci break; 30998c2ecf20Sopenharmony_ci default: 31008c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, "Invalid nvm write command 0x%x\n", cmd); 31018c2ecf20Sopenharmony_ci rc = -EINVAL; 31028c2ecf20Sopenharmony_ci goto out; 31038c2ecf20Sopenharmony_ci } 31048c2ecf20Sopenharmony_ci 31058c2ecf20Sopenharmony_ci buf_size = min_t(u32, (len - buf_idx), MCP_DRV_NVM_BUF_LEN); 31068c2ecf20Sopenharmony_ci while (buf_idx < len) { 31078c2ecf20Sopenharmony_ci if (cmd == QED_PUT_FILE_BEGIN) 31088c2ecf20Sopenharmony_ci nvm_offset = addr; 31098c2ecf20Sopenharmony_ci else 31108c2ecf20Sopenharmony_ci nvm_offset = ((buf_size << 31118c2ecf20Sopenharmony_ci DRV_MB_PARAM_NVM_LEN_OFFSET) | addr) + 31128c2ecf20Sopenharmony_ci buf_idx; 31138c2ecf20Sopenharmony_ci rc = qed_mcp_nvm_wr_cmd(p_hwfn, p_ptt, nvm_cmd, nvm_offset, 31148c2ecf20Sopenharmony_ci &resp, ¶m, buf_size, 31158c2ecf20Sopenharmony_ci (u32 *)&p_buf[buf_idx]); 31168c2ecf20Sopenharmony_ci if (rc) { 31178c2ecf20Sopenharmony_ci DP_NOTICE(cdev, "nvm write failed, rc = %d\n", rc); 31188c2ecf20Sopenharmony_ci resp = FW_MSG_CODE_ERROR; 31198c2ecf20Sopenharmony_ci break; 31208c2ecf20Sopenharmony_ci } 31218c2ecf20Sopenharmony_ci 31228c2ecf20Sopenharmony_ci if (resp != FW_MSG_CODE_OK && 31238c2ecf20Sopenharmony_ci resp != FW_MSG_CODE_NVM_OK && 31248c2ecf20Sopenharmony_ci resp != FW_MSG_CODE_NVM_PUT_FILE_FINISH_OK) { 31258c2ecf20Sopenharmony_ci DP_NOTICE(cdev, 31268c2ecf20Sopenharmony_ci "nvm write failed, resp = 0x%08x\n", resp); 31278c2ecf20Sopenharmony_ci rc = -EINVAL; 31288c2ecf20Sopenharmony_ci break; 31298c2ecf20Sopenharmony_ci } 31308c2ecf20Sopenharmony_ci 31318c2ecf20Sopenharmony_ci /* This can be a lengthy process, and it's possible scheduler 31328c2ecf20Sopenharmony_ci * isn't pre-emptable. Sleep a bit to prevent CPU hogging. 31338c2ecf20Sopenharmony_ci */ 31348c2ecf20Sopenharmony_ci if (buf_idx % 0x1000 > (buf_idx + buf_size) % 0x1000) 31358c2ecf20Sopenharmony_ci usleep_range(1000, 2000); 31368c2ecf20Sopenharmony_ci 31378c2ecf20Sopenharmony_ci /* For MBI upgrade, MFW response includes the next buffer offset 31388c2ecf20Sopenharmony_ci * to be delivered to MFW. 31398c2ecf20Sopenharmony_ci */ 31408c2ecf20Sopenharmony_ci if (param && cmd == QED_PUT_FILE_DATA) { 31418c2ecf20Sopenharmony_ci buf_idx = QED_MFW_GET_FIELD(param, 31428c2ecf20Sopenharmony_ci FW_MB_PARAM_NVM_PUT_FILE_REQ_OFFSET); 31438c2ecf20Sopenharmony_ci buf_size = QED_MFW_GET_FIELD(param, 31448c2ecf20Sopenharmony_ci FW_MB_PARAM_NVM_PUT_FILE_REQ_SIZE); 31458c2ecf20Sopenharmony_ci } else { 31468c2ecf20Sopenharmony_ci buf_idx += buf_size; 31478c2ecf20Sopenharmony_ci buf_size = min_t(u32, (len - buf_idx), 31488c2ecf20Sopenharmony_ci MCP_DRV_NVM_BUF_LEN); 31498c2ecf20Sopenharmony_ci } 31508c2ecf20Sopenharmony_ci } 31518c2ecf20Sopenharmony_ci 31528c2ecf20Sopenharmony_ci cdev->mcp_nvm_resp = resp; 31538c2ecf20Sopenharmony_ciout: 31548c2ecf20Sopenharmony_ci qed_ptt_release(p_hwfn, p_ptt); 31558c2ecf20Sopenharmony_ci 31568c2ecf20Sopenharmony_ci return rc; 31578c2ecf20Sopenharmony_ci} 31588c2ecf20Sopenharmony_ci 31598c2ecf20Sopenharmony_ciint qed_mcp_phy_sfp_read(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, 31608c2ecf20Sopenharmony_ci u32 port, u32 addr, u32 offset, u32 len, u8 *p_buf) 31618c2ecf20Sopenharmony_ci{ 31628c2ecf20Sopenharmony_ci u32 bytes_left, bytes_to_copy, buf_size, nvm_offset = 0; 31638c2ecf20Sopenharmony_ci u32 resp, param; 31648c2ecf20Sopenharmony_ci int rc; 31658c2ecf20Sopenharmony_ci 31668c2ecf20Sopenharmony_ci nvm_offset |= (port << DRV_MB_PARAM_TRANSCEIVER_PORT_OFFSET) & 31678c2ecf20Sopenharmony_ci DRV_MB_PARAM_TRANSCEIVER_PORT_MASK; 31688c2ecf20Sopenharmony_ci nvm_offset |= (addr << DRV_MB_PARAM_TRANSCEIVER_I2C_ADDRESS_OFFSET) & 31698c2ecf20Sopenharmony_ci DRV_MB_PARAM_TRANSCEIVER_I2C_ADDRESS_MASK; 31708c2ecf20Sopenharmony_ci 31718c2ecf20Sopenharmony_ci addr = offset; 31728c2ecf20Sopenharmony_ci offset = 0; 31738c2ecf20Sopenharmony_ci bytes_left = len; 31748c2ecf20Sopenharmony_ci while (bytes_left > 0) { 31758c2ecf20Sopenharmony_ci bytes_to_copy = min_t(u32, bytes_left, 31768c2ecf20Sopenharmony_ci MAX_I2C_TRANSACTION_SIZE); 31778c2ecf20Sopenharmony_ci nvm_offset &= (DRV_MB_PARAM_TRANSCEIVER_I2C_ADDRESS_MASK | 31788c2ecf20Sopenharmony_ci DRV_MB_PARAM_TRANSCEIVER_PORT_MASK); 31798c2ecf20Sopenharmony_ci nvm_offset |= ((addr + offset) << 31808c2ecf20Sopenharmony_ci DRV_MB_PARAM_TRANSCEIVER_OFFSET_OFFSET) & 31818c2ecf20Sopenharmony_ci DRV_MB_PARAM_TRANSCEIVER_OFFSET_MASK; 31828c2ecf20Sopenharmony_ci nvm_offset |= (bytes_to_copy << 31838c2ecf20Sopenharmony_ci DRV_MB_PARAM_TRANSCEIVER_SIZE_OFFSET) & 31848c2ecf20Sopenharmony_ci DRV_MB_PARAM_TRANSCEIVER_SIZE_MASK; 31858c2ecf20Sopenharmony_ci rc = qed_mcp_nvm_rd_cmd(p_hwfn, p_ptt, 31868c2ecf20Sopenharmony_ci DRV_MSG_CODE_TRANSCEIVER_READ, 31878c2ecf20Sopenharmony_ci nvm_offset, &resp, ¶m, &buf_size, 31888c2ecf20Sopenharmony_ci (u32 *)(p_buf + offset)); 31898c2ecf20Sopenharmony_ci if (rc) { 31908c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, 31918c2ecf20Sopenharmony_ci "Failed to send a transceiver read command to the MFW. rc = %d.\n", 31928c2ecf20Sopenharmony_ci rc); 31938c2ecf20Sopenharmony_ci return rc; 31948c2ecf20Sopenharmony_ci } 31958c2ecf20Sopenharmony_ci 31968c2ecf20Sopenharmony_ci if (resp == FW_MSG_CODE_TRANSCEIVER_NOT_PRESENT) 31978c2ecf20Sopenharmony_ci return -ENODEV; 31988c2ecf20Sopenharmony_ci else if (resp != FW_MSG_CODE_TRANSCEIVER_DIAG_OK) 31998c2ecf20Sopenharmony_ci return -EINVAL; 32008c2ecf20Sopenharmony_ci 32018c2ecf20Sopenharmony_ci offset += buf_size; 32028c2ecf20Sopenharmony_ci bytes_left -= buf_size; 32038c2ecf20Sopenharmony_ci } 32048c2ecf20Sopenharmony_ci 32058c2ecf20Sopenharmony_ci return 0; 32068c2ecf20Sopenharmony_ci} 32078c2ecf20Sopenharmony_ci 32088c2ecf20Sopenharmony_ciint qed_mcp_bist_register_test(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 32098c2ecf20Sopenharmony_ci{ 32108c2ecf20Sopenharmony_ci u32 drv_mb_param = 0, rsp, param; 32118c2ecf20Sopenharmony_ci int rc = 0; 32128c2ecf20Sopenharmony_ci 32138c2ecf20Sopenharmony_ci drv_mb_param = (DRV_MB_PARAM_BIST_REGISTER_TEST << 32148c2ecf20Sopenharmony_ci DRV_MB_PARAM_BIST_TEST_INDEX_SHIFT); 32158c2ecf20Sopenharmony_ci 32168c2ecf20Sopenharmony_ci rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_BIST_TEST, 32178c2ecf20Sopenharmony_ci drv_mb_param, &rsp, ¶m); 32188c2ecf20Sopenharmony_ci 32198c2ecf20Sopenharmony_ci if (rc) 32208c2ecf20Sopenharmony_ci return rc; 32218c2ecf20Sopenharmony_ci 32228c2ecf20Sopenharmony_ci if (((rsp & FW_MSG_CODE_MASK) != FW_MSG_CODE_OK) || 32238c2ecf20Sopenharmony_ci (param != DRV_MB_PARAM_BIST_RC_PASSED)) 32248c2ecf20Sopenharmony_ci rc = -EAGAIN; 32258c2ecf20Sopenharmony_ci 32268c2ecf20Sopenharmony_ci return rc; 32278c2ecf20Sopenharmony_ci} 32288c2ecf20Sopenharmony_ci 32298c2ecf20Sopenharmony_ciint qed_mcp_bist_clock_test(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 32308c2ecf20Sopenharmony_ci{ 32318c2ecf20Sopenharmony_ci u32 drv_mb_param, rsp, param; 32328c2ecf20Sopenharmony_ci int rc = 0; 32338c2ecf20Sopenharmony_ci 32348c2ecf20Sopenharmony_ci drv_mb_param = (DRV_MB_PARAM_BIST_CLOCK_TEST << 32358c2ecf20Sopenharmony_ci DRV_MB_PARAM_BIST_TEST_INDEX_SHIFT); 32368c2ecf20Sopenharmony_ci 32378c2ecf20Sopenharmony_ci rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_BIST_TEST, 32388c2ecf20Sopenharmony_ci drv_mb_param, &rsp, ¶m); 32398c2ecf20Sopenharmony_ci 32408c2ecf20Sopenharmony_ci if (rc) 32418c2ecf20Sopenharmony_ci return rc; 32428c2ecf20Sopenharmony_ci 32438c2ecf20Sopenharmony_ci if (((rsp & FW_MSG_CODE_MASK) != FW_MSG_CODE_OK) || 32448c2ecf20Sopenharmony_ci (param != DRV_MB_PARAM_BIST_RC_PASSED)) 32458c2ecf20Sopenharmony_ci rc = -EAGAIN; 32468c2ecf20Sopenharmony_ci 32478c2ecf20Sopenharmony_ci return rc; 32488c2ecf20Sopenharmony_ci} 32498c2ecf20Sopenharmony_ci 32508c2ecf20Sopenharmony_ciint qed_mcp_bist_nvm_get_num_images(struct qed_hwfn *p_hwfn, 32518c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt, 32528c2ecf20Sopenharmony_ci u32 *num_images) 32538c2ecf20Sopenharmony_ci{ 32548c2ecf20Sopenharmony_ci u32 drv_mb_param = 0, rsp; 32558c2ecf20Sopenharmony_ci int rc = 0; 32568c2ecf20Sopenharmony_ci 32578c2ecf20Sopenharmony_ci drv_mb_param = (DRV_MB_PARAM_BIST_NVM_TEST_NUM_IMAGES << 32588c2ecf20Sopenharmony_ci DRV_MB_PARAM_BIST_TEST_INDEX_SHIFT); 32598c2ecf20Sopenharmony_ci 32608c2ecf20Sopenharmony_ci rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_BIST_TEST, 32618c2ecf20Sopenharmony_ci drv_mb_param, &rsp, num_images); 32628c2ecf20Sopenharmony_ci if (rc) 32638c2ecf20Sopenharmony_ci return rc; 32648c2ecf20Sopenharmony_ci 32658c2ecf20Sopenharmony_ci if (((rsp & FW_MSG_CODE_MASK) != FW_MSG_CODE_OK)) 32668c2ecf20Sopenharmony_ci rc = -EINVAL; 32678c2ecf20Sopenharmony_ci 32688c2ecf20Sopenharmony_ci return rc; 32698c2ecf20Sopenharmony_ci} 32708c2ecf20Sopenharmony_ci 32718c2ecf20Sopenharmony_ciint qed_mcp_bist_nvm_get_image_att(struct qed_hwfn *p_hwfn, 32728c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt, 32738c2ecf20Sopenharmony_ci struct bist_nvm_image_att *p_image_att, 32748c2ecf20Sopenharmony_ci u32 image_index) 32758c2ecf20Sopenharmony_ci{ 32768c2ecf20Sopenharmony_ci u32 buf_size = 0, param, resp = 0, resp_param = 0; 32778c2ecf20Sopenharmony_ci int rc; 32788c2ecf20Sopenharmony_ci 32798c2ecf20Sopenharmony_ci param = DRV_MB_PARAM_BIST_NVM_TEST_IMAGE_BY_INDEX << 32808c2ecf20Sopenharmony_ci DRV_MB_PARAM_BIST_TEST_INDEX_SHIFT; 32818c2ecf20Sopenharmony_ci param |= image_index << DRV_MB_PARAM_BIST_TEST_IMAGE_INDEX_SHIFT; 32828c2ecf20Sopenharmony_ci 32838c2ecf20Sopenharmony_ci rc = qed_mcp_nvm_rd_cmd(p_hwfn, p_ptt, 32848c2ecf20Sopenharmony_ci DRV_MSG_CODE_BIST_TEST, param, 32858c2ecf20Sopenharmony_ci &resp, &resp_param, 32868c2ecf20Sopenharmony_ci &buf_size, 32878c2ecf20Sopenharmony_ci (u32 *)p_image_att); 32888c2ecf20Sopenharmony_ci if (rc) 32898c2ecf20Sopenharmony_ci return rc; 32908c2ecf20Sopenharmony_ci 32918c2ecf20Sopenharmony_ci if (((resp & FW_MSG_CODE_MASK) != FW_MSG_CODE_OK) || 32928c2ecf20Sopenharmony_ci (p_image_att->return_code != 1)) 32938c2ecf20Sopenharmony_ci rc = -EINVAL; 32948c2ecf20Sopenharmony_ci 32958c2ecf20Sopenharmony_ci return rc; 32968c2ecf20Sopenharmony_ci} 32978c2ecf20Sopenharmony_ci 32988c2ecf20Sopenharmony_ciint qed_mcp_nvm_info_populate(struct qed_hwfn *p_hwfn) 32998c2ecf20Sopenharmony_ci{ 33008c2ecf20Sopenharmony_ci struct qed_nvm_image_info nvm_info; 33018c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt; 33028c2ecf20Sopenharmony_ci int rc; 33038c2ecf20Sopenharmony_ci u32 i; 33048c2ecf20Sopenharmony_ci 33058c2ecf20Sopenharmony_ci if (p_hwfn->nvm_info.valid) 33068c2ecf20Sopenharmony_ci return 0; 33078c2ecf20Sopenharmony_ci 33088c2ecf20Sopenharmony_ci p_ptt = qed_ptt_acquire(p_hwfn); 33098c2ecf20Sopenharmony_ci if (!p_ptt) { 33108c2ecf20Sopenharmony_ci DP_ERR(p_hwfn, "failed to acquire ptt\n"); 33118c2ecf20Sopenharmony_ci return -EBUSY; 33128c2ecf20Sopenharmony_ci } 33138c2ecf20Sopenharmony_ci 33148c2ecf20Sopenharmony_ci /* Acquire from MFW the amount of available images */ 33158c2ecf20Sopenharmony_ci nvm_info.num_images = 0; 33168c2ecf20Sopenharmony_ci rc = qed_mcp_bist_nvm_get_num_images(p_hwfn, 33178c2ecf20Sopenharmony_ci p_ptt, &nvm_info.num_images); 33188c2ecf20Sopenharmony_ci if (rc == -EOPNOTSUPP) { 33198c2ecf20Sopenharmony_ci DP_INFO(p_hwfn, "DRV_MSG_CODE_BIST_TEST is not supported\n"); 33208c2ecf20Sopenharmony_ci goto out; 33218c2ecf20Sopenharmony_ci } else if (rc || !nvm_info.num_images) { 33228c2ecf20Sopenharmony_ci DP_ERR(p_hwfn, "Failed getting number of images\n"); 33238c2ecf20Sopenharmony_ci goto err0; 33248c2ecf20Sopenharmony_ci } 33258c2ecf20Sopenharmony_ci 33268c2ecf20Sopenharmony_ci nvm_info.image_att = kmalloc_array(nvm_info.num_images, 33278c2ecf20Sopenharmony_ci sizeof(struct bist_nvm_image_att), 33288c2ecf20Sopenharmony_ci GFP_KERNEL); 33298c2ecf20Sopenharmony_ci if (!nvm_info.image_att) { 33308c2ecf20Sopenharmony_ci rc = -ENOMEM; 33318c2ecf20Sopenharmony_ci goto err0; 33328c2ecf20Sopenharmony_ci } 33338c2ecf20Sopenharmony_ci 33348c2ecf20Sopenharmony_ci /* Iterate over images and get their attributes */ 33358c2ecf20Sopenharmony_ci for (i = 0; i < nvm_info.num_images; i++) { 33368c2ecf20Sopenharmony_ci rc = qed_mcp_bist_nvm_get_image_att(p_hwfn, p_ptt, 33378c2ecf20Sopenharmony_ci &nvm_info.image_att[i], i); 33388c2ecf20Sopenharmony_ci if (rc) { 33398c2ecf20Sopenharmony_ci DP_ERR(p_hwfn, 33408c2ecf20Sopenharmony_ci "Failed getting image index %d attributes\n", i); 33418c2ecf20Sopenharmony_ci goto err1; 33428c2ecf20Sopenharmony_ci } 33438c2ecf20Sopenharmony_ci 33448c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, QED_MSG_SP, "image index %d, size %x\n", i, 33458c2ecf20Sopenharmony_ci nvm_info.image_att[i].len); 33468c2ecf20Sopenharmony_ci } 33478c2ecf20Sopenharmony_ciout: 33488c2ecf20Sopenharmony_ci /* Update hwfn's nvm_info */ 33498c2ecf20Sopenharmony_ci if (nvm_info.num_images) { 33508c2ecf20Sopenharmony_ci p_hwfn->nvm_info.num_images = nvm_info.num_images; 33518c2ecf20Sopenharmony_ci kfree(p_hwfn->nvm_info.image_att); 33528c2ecf20Sopenharmony_ci p_hwfn->nvm_info.image_att = nvm_info.image_att; 33538c2ecf20Sopenharmony_ci p_hwfn->nvm_info.valid = true; 33548c2ecf20Sopenharmony_ci } 33558c2ecf20Sopenharmony_ci 33568c2ecf20Sopenharmony_ci qed_ptt_release(p_hwfn, p_ptt); 33578c2ecf20Sopenharmony_ci return 0; 33588c2ecf20Sopenharmony_ci 33598c2ecf20Sopenharmony_cierr1: 33608c2ecf20Sopenharmony_ci kfree(nvm_info.image_att); 33618c2ecf20Sopenharmony_cierr0: 33628c2ecf20Sopenharmony_ci qed_ptt_release(p_hwfn, p_ptt); 33638c2ecf20Sopenharmony_ci return rc; 33648c2ecf20Sopenharmony_ci} 33658c2ecf20Sopenharmony_ci 33668c2ecf20Sopenharmony_civoid qed_mcp_nvm_info_free(struct qed_hwfn *p_hwfn) 33678c2ecf20Sopenharmony_ci{ 33688c2ecf20Sopenharmony_ci kfree(p_hwfn->nvm_info.image_att); 33698c2ecf20Sopenharmony_ci p_hwfn->nvm_info.image_att = NULL; 33708c2ecf20Sopenharmony_ci p_hwfn->nvm_info.valid = false; 33718c2ecf20Sopenharmony_ci} 33728c2ecf20Sopenharmony_ci 33738c2ecf20Sopenharmony_ciint 33748c2ecf20Sopenharmony_ciqed_mcp_get_nvm_image_att(struct qed_hwfn *p_hwfn, 33758c2ecf20Sopenharmony_ci enum qed_nvm_images image_id, 33768c2ecf20Sopenharmony_ci struct qed_nvm_image_att *p_image_att) 33778c2ecf20Sopenharmony_ci{ 33788c2ecf20Sopenharmony_ci enum nvm_image_type type; 33798c2ecf20Sopenharmony_ci int rc; 33808c2ecf20Sopenharmony_ci u32 i; 33818c2ecf20Sopenharmony_ci 33828c2ecf20Sopenharmony_ci /* Translate image_id into MFW definitions */ 33838c2ecf20Sopenharmony_ci switch (image_id) { 33848c2ecf20Sopenharmony_ci case QED_NVM_IMAGE_ISCSI_CFG: 33858c2ecf20Sopenharmony_ci type = NVM_TYPE_ISCSI_CFG; 33868c2ecf20Sopenharmony_ci break; 33878c2ecf20Sopenharmony_ci case QED_NVM_IMAGE_FCOE_CFG: 33888c2ecf20Sopenharmony_ci type = NVM_TYPE_FCOE_CFG; 33898c2ecf20Sopenharmony_ci break; 33908c2ecf20Sopenharmony_ci case QED_NVM_IMAGE_MDUMP: 33918c2ecf20Sopenharmony_ci type = NVM_TYPE_MDUMP; 33928c2ecf20Sopenharmony_ci break; 33938c2ecf20Sopenharmony_ci case QED_NVM_IMAGE_NVM_CFG1: 33948c2ecf20Sopenharmony_ci type = NVM_TYPE_NVM_CFG1; 33958c2ecf20Sopenharmony_ci break; 33968c2ecf20Sopenharmony_ci case QED_NVM_IMAGE_DEFAULT_CFG: 33978c2ecf20Sopenharmony_ci type = NVM_TYPE_DEFAULT_CFG; 33988c2ecf20Sopenharmony_ci break; 33998c2ecf20Sopenharmony_ci case QED_NVM_IMAGE_NVM_META: 34008c2ecf20Sopenharmony_ci type = NVM_TYPE_META; 34018c2ecf20Sopenharmony_ci break; 34028c2ecf20Sopenharmony_ci default: 34038c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, "Unknown request of image_id %08x\n", 34048c2ecf20Sopenharmony_ci image_id); 34058c2ecf20Sopenharmony_ci return -EINVAL; 34068c2ecf20Sopenharmony_ci } 34078c2ecf20Sopenharmony_ci 34088c2ecf20Sopenharmony_ci rc = qed_mcp_nvm_info_populate(p_hwfn); 34098c2ecf20Sopenharmony_ci if (rc) 34108c2ecf20Sopenharmony_ci return rc; 34118c2ecf20Sopenharmony_ci 34128c2ecf20Sopenharmony_ci for (i = 0; i < p_hwfn->nvm_info.num_images; i++) 34138c2ecf20Sopenharmony_ci if (type == p_hwfn->nvm_info.image_att[i].image_type) 34148c2ecf20Sopenharmony_ci break; 34158c2ecf20Sopenharmony_ci if (i == p_hwfn->nvm_info.num_images) { 34168c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, QED_MSG_STORAGE, 34178c2ecf20Sopenharmony_ci "Failed to find nvram image of type %08x\n", 34188c2ecf20Sopenharmony_ci image_id); 34198c2ecf20Sopenharmony_ci return -ENOENT; 34208c2ecf20Sopenharmony_ci } 34218c2ecf20Sopenharmony_ci 34228c2ecf20Sopenharmony_ci p_image_att->start_addr = p_hwfn->nvm_info.image_att[i].nvm_start_addr; 34238c2ecf20Sopenharmony_ci p_image_att->length = p_hwfn->nvm_info.image_att[i].len; 34248c2ecf20Sopenharmony_ci 34258c2ecf20Sopenharmony_ci return 0; 34268c2ecf20Sopenharmony_ci} 34278c2ecf20Sopenharmony_ci 34288c2ecf20Sopenharmony_ciint qed_mcp_get_nvm_image(struct qed_hwfn *p_hwfn, 34298c2ecf20Sopenharmony_ci enum qed_nvm_images image_id, 34308c2ecf20Sopenharmony_ci u8 *p_buffer, u32 buffer_len) 34318c2ecf20Sopenharmony_ci{ 34328c2ecf20Sopenharmony_ci struct qed_nvm_image_att image_att; 34338c2ecf20Sopenharmony_ci int rc; 34348c2ecf20Sopenharmony_ci 34358c2ecf20Sopenharmony_ci memset(p_buffer, 0, buffer_len); 34368c2ecf20Sopenharmony_ci 34378c2ecf20Sopenharmony_ci rc = qed_mcp_get_nvm_image_att(p_hwfn, image_id, &image_att); 34388c2ecf20Sopenharmony_ci if (rc) 34398c2ecf20Sopenharmony_ci return rc; 34408c2ecf20Sopenharmony_ci 34418c2ecf20Sopenharmony_ci /* Validate sizes - both the image's and the supplied buffer's */ 34428c2ecf20Sopenharmony_ci if (image_att.length <= 4) { 34438c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, QED_MSG_STORAGE, 34448c2ecf20Sopenharmony_ci "Image [%d] is too small - only %d bytes\n", 34458c2ecf20Sopenharmony_ci image_id, image_att.length); 34468c2ecf20Sopenharmony_ci return -EINVAL; 34478c2ecf20Sopenharmony_ci } 34488c2ecf20Sopenharmony_ci 34498c2ecf20Sopenharmony_ci if (image_att.length > buffer_len) { 34508c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, 34518c2ecf20Sopenharmony_ci QED_MSG_STORAGE, 34528c2ecf20Sopenharmony_ci "Image [%d] is too big - %08x bytes where only %08x are available\n", 34538c2ecf20Sopenharmony_ci image_id, image_att.length, buffer_len); 34548c2ecf20Sopenharmony_ci return -ENOMEM; 34558c2ecf20Sopenharmony_ci } 34568c2ecf20Sopenharmony_ci 34578c2ecf20Sopenharmony_ci return qed_mcp_nvm_read(p_hwfn->cdev, image_att.start_addr, 34588c2ecf20Sopenharmony_ci p_buffer, image_att.length); 34598c2ecf20Sopenharmony_ci} 34608c2ecf20Sopenharmony_ci 34618c2ecf20Sopenharmony_cistatic enum resource_id_enum qed_mcp_get_mfw_res_id(enum qed_resources res_id) 34628c2ecf20Sopenharmony_ci{ 34638c2ecf20Sopenharmony_ci enum resource_id_enum mfw_res_id = RESOURCE_NUM_INVALID; 34648c2ecf20Sopenharmony_ci 34658c2ecf20Sopenharmony_ci switch (res_id) { 34668c2ecf20Sopenharmony_ci case QED_SB: 34678c2ecf20Sopenharmony_ci mfw_res_id = RESOURCE_NUM_SB_E; 34688c2ecf20Sopenharmony_ci break; 34698c2ecf20Sopenharmony_ci case QED_L2_QUEUE: 34708c2ecf20Sopenharmony_ci mfw_res_id = RESOURCE_NUM_L2_QUEUE_E; 34718c2ecf20Sopenharmony_ci break; 34728c2ecf20Sopenharmony_ci case QED_VPORT: 34738c2ecf20Sopenharmony_ci mfw_res_id = RESOURCE_NUM_VPORT_E; 34748c2ecf20Sopenharmony_ci break; 34758c2ecf20Sopenharmony_ci case QED_RSS_ENG: 34768c2ecf20Sopenharmony_ci mfw_res_id = RESOURCE_NUM_RSS_ENGINES_E; 34778c2ecf20Sopenharmony_ci break; 34788c2ecf20Sopenharmony_ci case QED_PQ: 34798c2ecf20Sopenharmony_ci mfw_res_id = RESOURCE_NUM_PQ_E; 34808c2ecf20Sopenharmony_ci break; 34818c2ecf20Sopenharmony_ci case QED_RL: 34828c2ecf20Sopenharmony_ci mfw_res_id = RESOURCE_NUM_RL_E; 34838c2ecf20Sopenharmony_ci break; 34848c2ecf20Sopenharmony_ci case QED_MAC: 34858c2ecf20Sopenharmony_ci case QED_VLAN: 34868c2ecf20Sopenharmony_ci /* Each VFC resource can accommodate both a MAC and a VLAN */ 34878c2ecf20Sopenharmony_ci mfw_res_id = RESOURCE_VFC_FILTER_E; 34888c2ecf20Sopenharmony_ci break; 34898c2ecf20Sopenharmony_ci case QED_ILT: 34908c2ecf20Sopenharmony_ci mfw_res_id = RESOURCE_ILT_E; 34918c2ecf20Sopenharmony_ci break; 34928c2ecf20Sopenharmony_ci case QED_LL2_RAM_QUEUE: 34938c2ecf20Sopenharmony_ci mfw_res_id = RESOURCE_LL2_QUEUE_E; 34948c2ecf20Sopenharmony_ci break; 34958c2ecf20Sopenharmony_ci case QED_LL2_CTX_QUEUE: 34968c2ecf20Sopenharmony_ci mfw_res_id = RESOURCE_LL2_CQS_E; 34978c2ecf20Sopenharmony_ci break; 34988c2ecf20Sopenharmony_ci case QED_RDMA_CNQ_RAM: 34998c2ecf20Sopenharmony_ci case QED_CMDQS_CQS: 35008c2ecf20Sopenharmony_ci /* CNQ/CMDQS are the same resource */ 35018c2ecf20Sopenharmony_ci mfw_res_id = RESOURCE_CQS_E; 35028c2ecf20Sopenharmony_ci break; 35038c2ecf20Sopenharmony_ci case QED_RDMA_STATS_QUEUE: 35048c2ecf20Sopenharmony_ci mfw_res_id = RESOURCE_RDMA_STATS_QUEUE_E; 35058c2ecf20Sopenharmony_ci break; 35068c2ecf20Sopenharmony_ci case QED_BDQ: 35078c2ecf20Sopenharmony_ci mfw_res_id = RESOURCE_BDQ_E; 35088c2ecf20Sopenharmony_ci break; 35098c2ecf20Sopenharmony_ci default: 35108c2ecf20Sopenharmony_ci break; 35118c2ecf20Sopenharmony_ci } 35128c2ecf20Sopenharmony_ci 35138c2ecf20Sopenharmony_ci return mfw_res_id; 35148c2ecf20Sopenharmony_ci} 35158c2ecf20Sopenharmony_ci 35168c2ecf20Sopenharmony_ci#define QED_RESC_ALLOC_VERSION_MAJOR 2 35178c2ecf20Sopenharmony_ci#define QED_RESC_ALLOC_VERSION_MINOR 0 35188c2ecf20Sopenharmony_ci#define QED_RESC_ALLOC_VERSION \ 35198c2ecf20Sopenharmony_ci ((QED_RESC_ALLOC_VERSION_MAJOR << \ 35208c2ecf20Sopenharmony_ci DRV_MB_PARAM_RESOURCE_ALLOC_VERSION_MAJOR_SHIFT) | \ 35218c2ecf20Sopenharmony_ci (QED_RESC_ALLOC_VERSION_MINOR << \ 35228c2ecf20Sopenharmony_ci DRV_MB_PARAM_RESOURCE_ALLOC_VERSION_MINOR_SHIFT)) 35238c2ecf20Sopenharmony_ci 35248c2ecf20Sopenharmony_cistruct qed_resc_alloc_in_params { 35258c2ecf20Sopenharmony_ci u32 cmd; 35268c2ecf20Sopenharmony_ci enum qed_resources res_id; 35278c2ecf20Sopenharmony_ci u32 resc_max_val; 35288c2ecf20Sopenharmony_ci}; 35298c2ecf20Sopenharmony_ci 35308c2ecf20Sopenharmony_cistruct qed_resc_alloc_out_params { 35318c2ecf20Sopenharmony_ci u32 mcp_resp; 35328c2ecf20Sopenharmony_ci u32 mcp_param; 35338c2ecf20Sopenharmony_ci u32 resc_num; 35348c2ecf20Sopenharmony_ci u32 resc_start; 35358c2ecf20Sopenharmony_ci u32 vf_resc_num; 35368c2ecf20Sopenharmony_ci u32 vf_resc_start; 35378c2ecf20Sopenharmony_ci u32 flags; 35388c2ecf20Sopenharmony_ci}; 35398c2ecf20Sopenharmony_ci 35408c2ecf20Sopenharmony_cistatic int 35418c2ecf20Sopenharmony_ciqed_mcp_resc_allocation_msg(struct qed_hwfn *p_hwfn, 35428c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt, 35438c2ecf20Sopenharmony_ci struct qed_resc_alloc_in_params *p_in_params, 35448c2ecf20Sopenharmony_ci struct qed_resc_alloc_out_params *p_out_params) 35458c2ecf20Sopenharmony_ci{ 35468c2ecf20Sopenharmony_ci struct qed_mcp_mb_params mb_params; 35478c2ecf20Sopenharmony_ci struct resource_info mfw_resc_info; 35488c2ecf20Sopenharmony_ci int rc; 35498c2ecf20Sopenharmony_ci 35508c2ecf20Sopenharmony_ci memset(&mfw_resc_info, 0, sizeof(mfw_resc_info)); 35518c2ecf20Sopenharmony_ci 35528c2ecf20Sopenharmony_ci mfw_resc_info.res_id = qed_mcp_get_mfw_res_id(p_in_params->res_id); 35538c2ecf20Sopenharmony_ci if (mfw_resc_info.res_id == RESOURCE_NUM_INVALID) { 35548c2ecf20Sopenharmony_ci DP_ERR(p_hwfn, 35558c2ecf20Sopenharmony_ci "Failed to match resource %d [%s] with the MFW resources\n", 35568c2ecf20Sopenharmony_ci p_in_params->res_id, 35578c2ecf20Sopenharmony_ci qed_hw_get_resc_name(p_in_params->res_id)); 35588c2ecf20Sopenharmony_ci return -EINVAL; 35598c2ecf20Sopenharmony_ci } 35608c2ecf20Sopenharmony_ci 35618c2ecf20Sopenharmony_ci switch (p_in_params->cmd) { 35628c2ecf20Sopenharmony_ci case DRV_MSG_SET_RESOURCE_VALUE_MSG: 35638c2ecf20Sopenharmony_ci mfw_resc_info.size = p_in_params->resc_max_val; 35648c2ecf20Sopenharmony_ci fallthrough; 35658c2ecf20Sopenharmony_ci case DRV_MSG_GET_RESOURCE_ALLOC_MSG: 35668c2ecf20Sopenharmony_ci break; 35678c2ecf20Sopenharmony_ci default: 35688c2ecf20Sopenharmony_ci DP_ERR(p_hwfn, "Unexpected resource alloc command [0x%08x]\n", 35698c2ecf20Sopenharmony_ci p_in_params->cmd); 35708c2ecf20Sopenharmony_ci return -EINVAL; 35718c2ecf20Sopenharmony_ci } 35728c2ecf20Sopenharmony_ci 35738c2ecf20Sopenharmony_ci memset(&mb_params, 0, sizeof(mb_params)); 35748c2ecf20Sopenharmony_ci mb_params.cmd = p_in_params->cmd; 35758c2ecf20Sopenharmony_ci mb_params.param = QED_RESC_ALLOC_VERSION; 35768c2ecf20Sopenharmony_ci mb_params.p_data_src = &mfw_resc_info; 35778c2ecf20Sopenharmony_ci mb_params.data_src_size = sizeof(mfw_resc_info); 35788c2ecf20Sopenharmony_ci mb_params.p_data_dst = mb_params.p_data_src; 35798c2ecf20Sopenharmony_ci mb_params.data_dst_size = mb_params.data_src_size; 35808c2ecf20Sopenharmony_ci 35818c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, 35828c2ecf20Sopenharmony_ci QED_MSG_SP, 35838c2ecf20Sopenharmony_ci "Resource message request: cmd 0x%08x, res_id %d [%s], hsi_version %d.%d, val 0x%x\n", 35848c2ecf20Sopenharmony_ci p_in_params->cmd, 35858c2ecf20Sopenharmony_ci p_in_params->res_id, 35868c2ecf20Sopenharmony_ci qed_hw_get_resc_name(p_in_params->res_id), 35878c2ecf20Sopenharmony_ci QED_MFW_GET_FIELD(mb_params.param, 35888c2ecf20Sopenharmony_ci DRV_MB_PARAM_RESOURCE_ALLOC_VERSION_MAJOR), 35898c2ecf20Sopenharmony_ci QED_MFW_GET_FIELD(mb_params.param, 35908c2ecf20Sopenharmony_ci DRV_MB_PARAM_RESOURCE_ALLOC_VERSION_MINOR), 35918c2ecf20Sopenharmony_ci p_in_params->resc_max_val); 35928c2ecf20Sopenharmony_ci 35938c2ecf20Sopenharmony_ci rc = qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 35948c2ecf20Sopenharmony_ci if (rc) 35958c2ecf20Sopenharmony_ci return rc; 35968c2ecf20Sopenharmony_ci 35978c2ecf20Sopenharmony_ci p_out_params->mcp_resp = mb_params.mcp_resp; 35988c2ecf20Sopenharmony_ci p_out_params->mcp_param = mb_params.mcp_param; 35998c2ecf20Sopenharmony_ci p_out_params->resc_num = mfw_resc_info.size; 36008c2ecf20Sopenharmony_ci p_out_params->resc_start = mfw_resc_info.offset; 36018c2ecf20Sopenharmony_ci p_out_params->vf_resc_num = mfw_resc_info.vf_size; 36028c2ecf20Sopenharmony_ci p_out_params->vf_resc_start = mfw_resc_info.vf_offset; 36038c2ecf20Sopenharmony_ci p_out_params->flags = mfw_resc_info.flags; 36048c2ecf20Sopenharmony_ci 36058c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, 36068c2ecf20Sopenharmony_ci QED_MSG_SP, 36078c2ecf20Sopenharmony_ci "Resource message response: mfw_hsi_version %d.%d, num 0x%x, start 0x%x, vf_num 0x%x, vf_start 0x%x, flags 0x%08x\n", 36088c2ecf20Sopenharmony_ci QED_MFW_GET_FIELD(p_out_params->mcp_param, 36098c2ecf20Sopenharmony_ci FW_MB_PARAM_RESOURCE_ALLOC_VERSION_MAJOR), 36108c2ecf20Sopenharmony_ci QED_MFW_GET_FIELD(p_out_params->mcp_param, 36118c2ecf20Sopenharmony_ci FW_MB_PARAM_RESOURCE_ALLOC_VERSION_MINOR), 36128c2ecf20Sopenharmony_ci p_out_params->resc_num, 36138c2ecf20Sopenharmony_ci p_out_params->resc_start, 36148c2ecf20Sopenharmony_ci p_out_params->vf_resc_num, 36158c2ecf20Sopenharmony_ci p_out_params->vf_resc_start, p_out_params->flags); 36168c2ecf20Sopenharmony_ci 36178c2ecf20Sopenharmony_ci return 0; 36188c2ecf20Sopenharmony_ci} 36198c2ecf20Sopenharmony_ci 36208c2ecf20Sopenharmony_ciint 36218c2ecf20Sopenharmony_ciqed_mcp_set_resc_max_val(struct qed_hwfn *p_hwfn, 36228c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt, 36238c2ecf20Sopenharmony_ci enum qed_resources res_id, 36248c2ecf20Sopenharmony_ci u32 resc_max_val, u32 *p_mcp_resp) 36258c2ecf20Sopenharmony_ci{ 36268c2ecf20Sopenharmony_ci struct qed_resc_alloc_out_params out_params; 36278c2ecf20Sopenharmony_ci struct qed_resc_alloc_in_params in_params; 36288c2ecf20Sopenharmony_ci int rc; 36298c2ecf20Sopenharmony_ci 36308c2ecf20Sopenharmony_ci memset(&in_params, 0, sizeof(in_params)); 36318c2ecf20Sopenharmony_ci in_params.cmd = DRV_MSG_SET_RESOURCE_VALUE_MSG; 36328c2ecf20Sopenharmony_ci in_params.res_id = res_id; 36338c2ecf20Sopenharmony_ci in_params.resc_max_val = resc_max_val; 36348c2ecf20Sopenharmony_ci memset(&out_params, 0, sizeof(out_params)); 36358c2ecf20Sopenharmony_ci rc = qed_mcp_resc_allocation_msg(p_hwfn, p_ptt, &in_params, 36368c2ecf20Sopenharmony_ci &out_params); 36378c2ecf20Sopenharmony_ci if (rc) 36388c2ecf20Sopenharmony_ci return rc; 36398c2ecf20Sopenharmony_ci 36408c2ecf20Sopenharmony_ci *p_mcp_resp = out_params.mcp_resp; 36418c2ecf20Sopenharmony_ci 36428c2ecf20Sopenharmony_ci return 0; 36438c2ecf20Sopenharmony_ci} 36448c2ecf20Sopenharmony_ci 36458c2ecf20Sopenharmony_ciint 36468c2ecf20Sopenharmony_ciqed_mcp_get_resc_info(struct qed_hwfn *p_hwfn, 36478c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt, 36488c2ecf20Sopenharmony_ci enum qed_resources res_id, 36498c2ecf20Sopenharmony_ci u32 *p_mcp_resp, u32 *p_resc_num, u32 *p_resc_start) 36508c2ecf20Sopenharmony_ci{ 36518c2ecf20Sopenharmony_ci struct qed_resc_alloc_out_params out_params; 36528c2ecf20Sopenharmony_ci struct qed_resc_alloc_in_params in_params; 36538c2ecf20Sopenharmony_ci int rc; 36548c2ecf20Sopenharmony_ci 36558c2ecf20Sopenharmony_ci memset(&in_params, 0, sizeof(in_params)); 36568c2ecf20Sopenharmony_ci in_params.cmd = DRV_MSG_GET_RESOURCE_ALLOC_MSG; 36578c2ecf20Sopenharmony_ci in_params.res_id = res_id; 36588c2ecf20Sopenharmony_ci memset(&out_params, 0, sizeof(out_params)); 36598c2ecf20Sopenharmony_ci rc = qed_mcp_resc_allocation_msg(p_hwfn, p_ptt, &in_params, 36608c2ecf20Sopenharmony_ci &out_params); 36618c2ecf20Sopenharmony_ci if (rc) 36628c2ecf20Sopenharmony_ci return rc; 36638c2ecf20Sopenharmony_ci 36648c2ecf20Sopenharmony_ci *p_mcp_resp = out_params.mcp_resp; 36658c2ecf20Sopenharmony_ci 36668c2ecf20Sopenharmony_ci if (*p_mcp_resp == FW_MSG_CODE_RESOURCE_ALLOC_OK) { 36678c2ecf20Sopenharmony_ci *p_resc_num = out_params.resc_num; 36688c2ecf20Sopenharmony_ci *p_resc_start = out_params.resc_start; 36698c2ecf20Sopenharmony_ci } 36708c2ecf20Sopenharmony_ci 36718c2ecf20Sopenharmony_ci return 0; 36728c2ecf20Sopenharmony_ci} 36738c2ecf20Sopenharmony_ci 36748c2ecf20Sopenharmony_ciint qed_mcp_initiate_pf_flr(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 36758c2ecf20Sopenharmony_ci{ 36768c2ecf20Sopenharmony_ci u32 mcp_resp, mcp_param; 36778c2ecf20Sopenharmony_ci 36788c2ecf20Sopenharmony_ci return qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_INITIATE_PF_FLR, 0, 36798c2ecf20Sopenharmony_ci &mcp_resp, &mcp_param); 36808c2ecf20Sopenharmony_ci} 36818c2ecf20Sopenharmony_ci 36828c2ecf20Sopenharmony_cistatic int qed_mcp_resource_cmd(struct qed_hwfn *p_hwfn, 36838c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt, 36848c2ecf20Sopenharmony_ci u32 param, u32 *p_mcp_resp, u32 *p_mcp_param) 36858c2ecf20Sopenharmony_ci{ 36868c2ecf20Sopenharmony_ci int rc; 36878c2ecf20Sopenharmony_ci 36888c2ecf20Sopenharmony_ci rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_RESOURCE_CMD, param, 36898c2ecf20Sopenharmony_ci p_mcp_resp, p_mcp_param); 36908c2ecf20Sopenharmony_ci if (rc) 36918c2ecf20Sopenharmony_ci return rc; 36928c2ecf20Sopenharmony_ci 36938c2ecf20Sopenharmony_ci if (*p_mcp_resp == FW_MSG_CODE_UNSUPPORTED) { 36948c2ecf20Sopenharmony_ci DP_INFO(p_hwfn, 36958c2ecf20Sopenharmony_ci "The resource command is unsupported by the MFW\n"); 36968c2ecf20Sopenharmony_ci return -EINVAL; 36978c2ecf20Sopenharmony_ci } 36988c2ecf20Sopenharmony_ci 36998c2ecf20Sopenharmony_ci if (*p_mcp_param == RESOURCE_OPCODE_UNKNOWN_CMD) { 37008c2ecf20Sopenharmony_ci u8 opcode = QED_MFW_GET_FIELD(param, RESOURCE_CMD_REQ_OPCODE); 37018c2ecf20Sopenharmony_ci 37028c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, 37038c2ecf20Sopenharmony_ci "The resource command is unknown to the MFW [param 0x%08x, opcode %d]\n", 37048c2ecf20Sopenharmony_ci param, opcode); 37058c2ecf20Sopenharmony_ci return -EINVAL; 37068c2ecf20Sopenharmony_ci } 37078c2ecf20Sopenharmony_ci 37088c2ecf20Sopenharmony_ci return rc; 37098c2ecf20Sopenharmony_ci} 37108c2ecf20Sopenharmony_ci 37118c2ecf20Sopenharmony_cistatic int 37128c2ecf20Sopenharmony_ci__qed_mcp_resc_lock(struct qed_hwfn *p_hwfn, 37138c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt, 37148c2ecf20Sopenharmony_ci struct qed_resc_lock_params *p_params) 37158c2ecf20Sopenharmony_ci{ 37168c2ecf20Sopenharmony_ci u32 param = 0, mcp_resp, mcp_param; 37178c2ecf20Sopenharmony_ci u8 opcode; 37188c2ecf20Sopenharmony_ci int rc; 37198c2ecf20Sopenharmony_ci 37208c2ecf20Sopenharmony_ci switch (p_params->timeout) { 37218c2ecf20Sopenharmony_ci case QED_MCP_RESC_LOCK_TO_DEFAULT: 37228c2ecf20Sopenharmony_ci opcode = RESOURCE_OPCODE_REQ; 37238c2ecf20Sopenharmony_ci p_params->timeout = 0; 37248c2ecf20Sopenharmony_ci break; 37258c2ecf20Sopenharmony_ci case QED_MCP_RESC_LOCK_TO_NONE: 37268c2ecf20Sopenharmony_ci opcode = RESOURCE_OPCODE_REQ_WO_AGING; 37278c2ecf20Sopenharmony_ci p_params->timeout = 0; 37288c2ecf20Sopenharmony_ci break; 37298c2ecf20Sopenharmony_ci default: 37308c2ecf20Sopenharmony_ci opcode = RESOURCE_OPCODE_REQ_W_AGING; 37318c2ecf20Sopenharmony_ci break; 37328c2ecf20Sopenharmony_ci } 37338c2ecf20Sopenharmony_ci 37348c2ecf20Sopenharmony_ci QED_MFW_SET_FIELD(param, RESOURCE_CMD_REQ_RESC, p_params->resource); 37358c2ecf20Sopenharmony_ci QED_MFW_SET_FIELD(param, RESOURCE_CMD_REQ_OPCODE, opcode); 37368c2ecf20Sopenharmony_ci QED_MFW_SET_FIELD(param, RESOURCE_CMD_REQ_AGE, p_params->timeout); 37378c2ecf20Sopenharmony_ci 37388c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, 37398c2ecf20Sopenharmony_ci QED_MSG_SP, 37408c2ecf20Sopenharmony_ci "Resource lock request: param 0x%08x [age %d, opcode %d, resource %d]\n", 37418c2ecf20Sopenharmony_ci param, p_params->timeout, opcode, p_params->resource); 37428c2ecf20Sopenharmony_ci 37438c2ecf20Sopenharmony_ci /* Attempt to acquire the resource */ 37448c2ecf20Sopenharmony_ci rc = qed_mcp_resource_cmd(p_hwfn, p_ptt, param, &mcp_resp, &mcp_param); 37458c2ecf20Sopenharmony_ci if (rc) 37468c2ecf20Sopenharmony_ci return rc; 37478c2ecf20Sopenharmony_ci 37488c2ecf20Sopenharmony_ci /* Analyze the response */ 37498c2ecf20Sopenharmony_ci p_params->owner = QED_MFW_GET_FIELD(mcp_param, RESOURCE_CMD_RSP_OWNER); 37508c2ecf20Sopenharmony_ci opcode = QED_MFW_GET_FIELD(mcp_param, RESOURCE_CMD_RSP_OPCODE); 37518c2ecf20Sopenharmony_ci 37528c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, 37538c2ecf20Sopenharmony_ci QED_MSG_SP, 37548c2ecf20Sopenharmony_ci "Resource lock response: mcp_param 0x%08x [opcode %d, owner %d]\n", 37558c2ecf20Sopenharmony_ci mcp_param, opcode, p_params->owner); 37568c2ecf20Sopenharmony_ci 37578c2ecf20Sopenharmony_ci switch (opcode) { 37588c2ecf20Sopenharmony_ci case RESOURCE_OPCODE_GNT: 37598c2ecf20Sopenharmony_ci p_params->b_granted = true; 37608c2ecf20Sopenharmony_ci break; 37618c2ecf20Sopenharmony_ci case RESOURCE_OPCODE_BUSY: 37628c2ecf20Sopenharmony_ci p_params->b_granted = false; 37638c2ecf20Sopenharmony_ci break; 37648c2ecf20Sopenharmony_ci default: 37658c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, 37668c2ecf20Sopenharmony_ci "Unexpected opcode in resource lock response [mcp_param 0x%08x, opcode %d]\n", 37678c2ecf20Sopenharmony_ci mcp_param, opcode); 37688c2ecf20Sopenharmony_ci return -EINVAL; 37698c2ecf20Sopenharmony_ci } 37708c2ecf20Sopenharmony_ci 37718c2ecf20Sopenharmony_ci return 0; 37728c2ecf20Sopenharmony_ci} 37738c2ecf20Sopenharmony_ci 37748c2ecf20Sopenharmony_ciint 37758c2ecf20Sopenharmony_ciqed_mcp_resc_lock(struct qed_hwfn *p_hwfn, 37768c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt, struct qed_resc_lock_params *p_params) 37778c2ecf20Sopenharmony_ci{ 37788c2ecf20Sopenharmony_ci u32 retry_cnt = 0; 37798c2ecf20Sopenharmony_ci int rc; 37808c2ecf20Sopenharmony_ci 37818c2ecf20Sopenharmony_ci do { 37828c2ecf20Sopenharmony_ci /* No need for an interval before the first iteration */ 37838c2ecf20Sopenharmony_ci if (retry_cnt) { 37848c2ecf20Sopenharmony_ci if (p_params->sleep_b4_retry) { 37858c2ecf20Sopenharmony_ci u16 retry_interval_in_ms = 37868c2ecf20Sopenharmony_ci DIV_ROUND_UP(p_params->retry_interval, 37878c2ecf20Sopenharmony_ci 1000); 37888c2ecf20Sopenharmony_ci 37898c2ecf20Sopenharmony_ci msleep(retry_interval_in_ms); 37908c2ecf20Sopenharmony_ci } else { 37918c2ecf20Sopenharmony_ci udelay(p_params->retry_interval); 37928c2ecf20Sopenharmony_ci } 37938c2ecf20Sopenharmony_ci } 37948c2ecf20Sopenharmony_ci 37958c2ecf20Sopenharmony_ci rc = __qed_mcp_resc_lock(p_hwfn, p_ptt, p_params); 37968c2ecf20Sopenharmony_ci if (rc) 37978c2ecf20Sopenharmony_ci return rc; 37988c2ecf20Sopenharmony_ci 37998c2ecf20Sopenharmony_ci if (p_params->b_granted) 38008c2ecf20Sopenharmony_ci break; 38018c2ecf20Sopenharmony_ci } while (retry_cnt++ < p_params->retry_num); 38028c2ecf20Sopenharmony_ci 38038c2ecf20Sopenharmony_ci return 0; 38048c2ecf20Sopenharmony_ci} 38058c2ecf20Sopenharmony_ci 38068c2ecf20Sopenharmony_ciint 38078c2ecf20Sopenharmony_ciqed_mcp_resc_unlock(struct qed_hwfn *p_hwfn, 38088c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt, 38098c2ecf20Sopenharmony_ci struct qed_resc_unlock_params *p_params) 38108c2ecf20Sopenharmony_ci{ 38118c2ecf20Sopenharmony_ci u32 param = 0, mcp_resp, mcp_param; 38128c2ecf20Sopenharmony_ci u8 opcode; 38138c2ecf20Sopenharmony_ci int rc; 38148c2ecf20Sopenharmony_ci 38158c2ecf20Sopenharmony_ci opcode = p_params->b_force ? RESOURCE_OPCODE_FORCE_RELEASE 38168c2ecf20Sopenharmony_ci : RESOURCE_OPCODE_RELEASE; 38178c2ecf20Sopenharmony_ci QED_MFW_SET_FIELD(param, RESOURCE_CMD_REQ_RESC, p_params->resource); 38188c2ecf20Sopenharmony_ci QED_MFW_SET_FIELD(param, RESOURCE_CMD_REQ_OPCODE, opcode); 38198c2ecf20Sopenharmony_ci 38208c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, QED_MSG_SP, 38218c2ecf20Sopenharmony_ci "Resource unlock request: param 0x%08x [opcode %d, resource %d]\n", 38228c2ecf20Sopenharmony_ci param, opcode, p_params->resource); 38238c2ecf20Sopenharmony_ci 38248c2ecf20Sopenharmony_ci /* Attempt to release the resource */ 38258c2ecf20Sopenharmony_ci rc = qed_mcp_resource_cmd(p_hwfn, p_ptt, param, &mcp_resp, &mcp_param); 38268c2ecf20Sopenharmony_ci if (rc) 38278c2ecf20Sopenharmony_ci return rc; 38288c2ecf20Sopenharmony_ci 38298c2ecf20Sopenharmony_ci /* Analyze the response */ 38308c2ecf20Sopenharmony_ci opcode = QED_MFW_GET_FIELD(mcp_param, RESOURCE_CMD_RSP_OPCODE); 38318c2ecf20Sopenharmony_ci 38328c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, QED_MSG_SP, 38338c2ecf20Sopenharmony_ci "Resource unlock response: mcp_param 0x%08x [opcode %d]\n", 38348c2ecf20Sopenharmony_ci mcp_param, opcode); 38358c2ecf20Sopenharmony_ci 38368c2ecf20Sopenharmony_ci switch (opcode) { 38378c2ecf20Sopenharmony_ci case RESOURCE_OPCODE_RELEASED_PREVIOUS: 38388c2ecf20Sopenharmony_ci DP_INFO(p_hwfn, 38398c2ecf20Sopenharmony_ci "Resource unlock request for an already released resource [%d]\n", 38408c2ecf20Sopenharmony_ci p_params->resource); 38418c2ecf20Sopenharmony_ci fallthrough; 38428c2ecf20Sopenharmony_ci case RESOURCE_OPCODE_RELEASED: 38438c2ecf20Sopenharmony_ci p_params->b_released = true; 38448c2ecf20Sopenharmony_ci break; 38458c2ecf20Sopenharmony_ci case RESOURCE_OPCODE_WRONG_OWNER: 38468c2ecf20Sopenharmony_ci p_params->b_released = false; 38478c2ecf20Sopenharmony_ci break; 38488c2ecf20Sopenharmony_ci default: 38498c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, 38508c2ecf20Sopenharmony_ci "Unexpected opcode in resource unlock response [mcp_param 0x%08x, opcode %d]\n", 38518c2ecf20Sopenharmony_ci mcp_param, opcode); 38528c2ecf20Sopenharmony_ci return -EINVAL; 38538c2ecf20Sopenharmony_ci } 38548c2ecf20Sopenharmony_ci 38558c2ecf20Sopenharmony_ci return 0; 38568c2ecf20Sopenharmony_ci} 38578c2ecf20Sopenharmony_ci 38588c2ecf20Sopenharmony_civoid qed_mcp_resc_lock_default_init(struct qed_resc_lock_params *p_lock, 38598c2ecf20Sopenharmony_ci struct qed_resc_unlock_params *p_unlock, 38608c2ecf20Sopenharmony_ci enum qed_resc_lock 38618c2ecf20Sopenharmony_ci resource, bool b_is_permanent) 38628c2ecf20Sopenharmony_ci{ 38638c2ecf20Sopenharmony_ci if (p_lock) { 38648c2ecf20Sopenharmony_ci memset(p_lock, 0, sizeof(*p_lock)); 38658c2ecf20Sopenharmony_ci 38668c2ecf20Sopenharmony_ci /* Permanent resources don't require aging, and there's no 38678c2ecf20Sopenharmony_ci * point in trying to acquire them more than once since it's 38688c2ecf20Sopenharmony_ci * unexpected another entity would release them. 38698c2ecf20Sopenharmony_ci */ 38708c2ecf20Sopenharmony_ci if (b_is_permanent) { 38718c2ecf20Sopenharmony_ci p_lock->timeout = QED_MCP_RESC_LOCK_TO_NONE; 38728c2ecf20Sopenharmony_ci } else { 38738c2ecf20Sopenharmony_ci p_lock->retry_num = QED_MCP_RESC_LOCK_RETRY_CNT_DFLT; 38748c2ecf20Sopenharmony_ci p_lock->retry_interval = 38758c2ecf20Sopenharmony_ci QED_MCP_RESC_LOCK_RETRY_VAL_DFLT; 38768c2ecf20Sopenharmony_ci p_lock->sleep_b4_retry = true; 38778c2ecf20Sopenharmony_ci } 38788c2ecf20Sopenharmony_ci 38798c2ecf20Sopenharmony_ci p_lock->resource = resource; 38808c2ecf20Sopenharmony_ci } 38818c2ecf20Sopenharmony_ci 38828c2ecf20Sopenharmony_ci if (p_unlock) { 38838c2ecf20Sopenharmony_ci memset(p_unlock, 0, sizeof(*p_unlock)); 38848c2ecf20Sopenharmony_ci p_unlock->resource = resource; 38858c2ecf20Sopenharmony_ci } 38868c2ecf20Sopenharmony_ci} 38878c2ecf20Sopenharmony_ci 38888c2ecf20Sopenharmony_cibool qed_mcp_is_smart_an_supported(struct qed_hwfn *p_hwfn) 38898c2ecf20Sopenharmony_ci{ 38908c2ecf20Sopenharmony_ci return !!(p_hwfn->mcp_info->capabilities & 38918c2ecf20Sopenharmony_ci FW_MB_PARAM_FEATURE_SUPPORT_SMARTLINQ); 38928c2ecf20Sopenharmony_ci} 38938c2ecf20Sopenharmony_ci 38948c2ecf20Sopenharmony_ciint qed_mcp_get_capabilities(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 38958c2ecf20Sopenharmony_ci{ 38968c2ecf20Sopenharmony_ci u32 mcp_resp; 38978c2ecf20Sopenharmony_ci int rc; 38988c2ecf20Sopenharmony_ci 38998c2ecf20Sopenharmony_ci rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_GET_MFW_FEATURE_SUPPORT, 39008c2ecf20Sopenharmony_ci 0, &mcp_resp, &p_hwfn->mcp_info->capabilities); 39018c2ecf20Sopenharmony_ci if (!rc) 39028c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, (QED_MSG_SP | NETIF_MSG_PROBE), 39038c2ecf20Sopenharmony_ci "MFW supported features: %08x\n", 39048c2ecf20Sopenharmony_ci p_hwfn->mcp_info->capabilities); 39058c2ecf20Sopenharmony_ci 39068c2ecf20Sopenharmony_ci return rc; 39078c2ecf20Sopenharmony_ci} 39088c2ecf20Sopenharmony_ci 39098c2ecf20Sopenharmony_ciint qed_mcp_set_capabilities(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 39108c2ecf20Sopenharmony_ci{ 39118c2ecf20Sopenharmony_ci u32 mcp_resp, mcp_param, features; 39128c2ecf20Sopenharmony_ci 39138c2ecf20Sopenharmony_ci features = DRV_MB_PARAM_FEATURE_SUPPORT_PORT_EEE | 39148c2ecf20Sopenharmony_ci DRV_MB_PARAM_FEATURE_SUPPORT_FUNC_VLINK | 39158c2ecf20Sopenharmony_ci DRV_MB_PARAM_FEATURE_SUPPORT_PORT_FEC_CONTROL; 39168c2ecf20Sopenharmony_ci 39178c2ecf20Sopenharmony_ci if (QED_IS_E5(p_hwfn->cdev)) 39188c2ecf20Sopenharmony_ci features |= 39198c2ecf20Sopenharmony_ci DRV_MB_PARAM_FEATURE_SUPPORT_PORT_EXT_SPEED_FEC_CONTROL; 39208c2ecf20Sopenharmony_ci 39218c2ecf20Sopenharmony_ci return qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_FEATURE_SUPPORT, 39228c2ecf20Sopenharmony_ci features, &mcp_resp, &mcp_param); 39238c2ecf20Sopenharmony_ci} 39248c2ecf20Sopenharmony_ci 39258c2ecf20Sopenharmony_ciint qed_mcp_get_engine_config(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 39268c2ecf20Sopenharmony_ci{ 39278c2ecf20Sopenharmony_ci struct qed_mcp_mb_params mb_params = {0}; 39288c2ecf20Sopenharmony_ci struct qed_dev *cdev = p_hwfn->cdev; 39298c2ecf20Sopenharmony_ci u8 fir_valid, l2_valid; 39308c2ecf20Sopenharmony_ci int rc; 39318c2ecf20Sopenharmony_ci 39328c2ecf20Sopenharmony_ci mb_params.cmd = DRV_MSG_CODE_GET_ENGINE_CONFIG; 39338c2ecf20Sopenharmony_ci rc = qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 39348c2ecf20Sopenharmony_ci if (rc) 39358c2ecf20Sopenharmony_ci return rc; 39368c2ecf20Sopenharmony_ci 39378c2ecf20Sopenharmony_ci if (mb_params.mcp_resp == FW_MSG_CODE_UNSUPPORTED) { 39388c2ecf20Sopenharmony_ci DP_INFO(p_hwfn, 39398c2ecf20Sopenharmony_ci "The get_engine_config command is unsupported by the MFW\n"); 39408c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 39418c2ecf20Sopenharmony_ci } 39428c2ecf20Sopenharmony_ci 39438c2ecf20Sopenharmony_ci fir_valid = QED_MFW_GET_FIELD(mb_params.mcp_param, 39448c2ecf20Sopenharmony_ci FW_MB_PARAM_ENG_CFG_FIR_AFFIN_VALID); 39458c2ecf20Sopenharmony_ci if (fir_valid) 39468c2ecf20Sopenharmony_ci cdev->fir_affin = 39478c2ecf20Sopenharmony_ci QED_MFW_GET_FIELD(mb_params.mcp_param, 39488c2ecf20Sopenharmony_ci FW_MB_PARAM_ENG_CFG_FIR_AFFIN_VALUE); 39498c2ecf20Sopenharmony_ci 39508c2ecf20Sopenharmony_ci l2_valid = QED_MFW_GET_FIELD(mb_params.mcp_param, 39518c2ecf20Sopenharmony_ci FW_MB_PARAM_ENG_CFG_L2_AFFIN_VALID); 39528c2ecf20Sopenharmony_ci if (l2_valid) 39538c2ecf20Sopenharmony_ci cdev->l2_affin_hint = 39548c2ecf20Sopenharmony_ci QED_MFW_GET_FIELD(mb_params.mcp_param, 39558c2ecf20Sopenharmony_ci FW_MB_PARAM_ENG_CFG_L2_AFFIN_VALUE); 39568c2ecf20Sopenharmony_ci 39578c2ecf20Sopenharmony_ci DP_INFO(p_hwfn, 39588c2ecf20Sopenharmony_ci "Engine affinity config: FIR={valid %hhd, value %hhd}, L2_hint={valid %hhd, value %hhd}\n", 39598c2ecf20Sopenharmony_ci fir_valid, cdev->fir_affin, l2_valid, cdev->l2_affin_hint); 39608c2ecf20Sopenharmony_ci 39618c2ecf20Sopenharmony_ci return 0; 39628c2ecf20Sopenharmony_ci} 39638c2ecf20Sopenharmony_ci 39648c2ecf20Sopenharmony_ciint qed_mcp_get_ppfid_bitmap(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 39658c2ecf20Sopenharmony_ci{ 39668c2ecf20Sopenharmony_ci struct qed_mcp_mb_params mb_params = {0}; 39678c2ecf20Sopenharmony_ci struct qed_dev *cdev = p_hwfn->cdev; 39688c2ecf20Sopenharmony_ci int rc; 39698c2ecf20Sopenharmony_ci 39708c2ecf20Sopenharmony_ci mb_params.cmd = DRV_MSG_CODE_GET_PPFID_BITMAP; 39718c2ecf20Sopenharmony_ci rc = qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 39728c2ecf20Sopenharmony_ci if (rc) 39738c2ecf20Sopenharmony_ci return rc; 39748c2ecf20Sopenharmony_ci 39758c2ecf20Sopenharmony_ci if (mb_params.mcp_resp == FW_MSG_CODE_UNSUPPORTED) { 39768c2ecf20Sopenharmony_ci DP_INFO(p_hwfn, 39778c2ecf20Sopenharmony_ci "The get_ppfid_bitmap command is unsupported by the MFW\n"); 39788c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 39798c2ecf20Sopenharmony_ci } 39808c2ecf20Sopenharmony_ci 39818c2ecf20Sopenharmony_ci cdev->ppfid_bitmap = QED_MFW_GET_FIELD(mb_params.mcp_param, 39828c2ecf20Sopenharmony_ci FW_MB_PARAM_PPFID_BITMAP); 39838c2ecf20Sopenharmony_ci 39848c2ecf20Sopenharmony_ci DP_VERBOSE(p_hwfn, QED_MSG_SP, "PPFID bitmap 0x%hhx\n", 39858c2ecf20Sopenharmony_ci cdev->ppfid_bitmap); 39868c2ecf20Sopenharmony_ci 39878c2ecf20Sopenharmony_ci return 0; 39888c2ecf20Sopenharmony_ci} 39898c2ecf20Sopenharmony_ci 39908c2ecf20Sopenharmony_ciint qed_mcp_nvm_get_cfg(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, 39918c2ecf20Sopenharmony_ci u16 option_id, u8 entity_id, u16 flags, u8 *p_buf, 39928c2ecf20Sopenharmony_ci u32 *p_len) 39938c2ecf20Sopenharmony_ci{ 39948c2ecf20Sopenharmony_ci u32 mb_param = 0, resp, param; 39958c2ecf20Sopenharmony_ci int rc; 39968c2ecf20Sopenharmony_ci 39978c2ecf20Sopenharmony_ci QED_MFW_SET_FIELD(mb_param, DRV_MB_PARAM_NVM_CFG_OPTION_ID, option_id); 39988c2ecf20Sopenharmony_ci if (flags & QED_NVM_CFG_OPTION_INIT) 39998c2ecf20Sopenharmony_ci QED_MFW_SET_FIELD(mb_param, 40008c2ecf20Sopenharmony_ci DRV_MB_PARAM_NVM_CFG_OPTION_INIT, 1); 40018c2ecf20Sopenharmony_ci if (flags & QED_NVM_CFG_OPTION_FREE) 40028c2ecf20Sopenharmony_ci QED_MFW_SET_FIELD(mb_param, 40038c2ecf20Sopenharmony_ci DRV_MB_PARAM_NVM_CFG_OPTION_FREE, 1); 40048c2ecf20Sopenharmony_ci if (flags & QED_NVM_CFG_OPTION_ENTITY_SEL) { 40058c2ecf20Sopenharmony_ci QED_MFW_SET_FIELD(mb_param, 40068c2ecf20Sopenharmony_ci DRV_MB_PARAM_NVM_CFG_OPTION_ENTITY_SEL, 1); 40078c2ecf20Sopenharmony_ci QED_MFW_SET_FIELD(mb_param, 40088c2ecf20Sopenharmony_ci DRV_MB_PARAM_NVM_CFG_OPTION_ENTITY_ID, 40098c2ecf20Sopenharmony_ci entity_id); 40108c2ecf20Sopenharmony_ci } 40118c2ecf20Sopenharmony_ci 40128c2ecf20Sopenharmony_ci rc = qed_mcp_nvm_rd_cmd(p_hwfn, p_ptt, 40138c2ecf20Sopenharmony_ci DRV_MSG_CODE_GET_NVM_CFG_OPTION, 40148c2ecf20Sopenharmony_ci mb_param, &resp, ¶m, p_len, (u32 *)p_buf); 40158c2ecf20Sopenharmony_ci 40168c2ecf20Sopenharmony_ci return rc; 40178c2ecf20Sopenharmony_ci} 40188c2ecf20Sopenharmony_ci 40198c2ecf20Sopenharmony_ciint qed_mcp_nvm_set_cfg(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, 40208c2ecf20Sopenharmony_ci u16 option_id, u8 entity_id, u16 flags, u8 *p_buf, 40218c2ecf20Sopenharmony_ci u32 len) 40228c2ecf20Sopenharmony_ci{ 40238c2ecf20Sopenharmony_ci u32 mb_param = 0, resp, param; 40248c2ecf20Sopenharmony_ci 40258c2ecf20Sopenharmony_ci QED_MFW_SET_FIELD(mb_param, DRV_MB_PARAM_NVM_CFG_OPTION_ID, option_id); 40268c2ecf20Sopenharmony_ci if (flags & QED_NVM_CFG_OPTION_ALL) 40278c2ecf20Sopenharmony_ci QED_MFW_SET_FIELD(mb_param, 40288c2ecf20Sopenharmony_ci DRV_MB_PARAM_NVM_CFG_OPTION_ALL, 1); 40298c2ecf20Sopenharmony_ci if (flags & QED_NVM_CFG_OPTION_INIT) 40308c2ecf20Sopenharmony_ci QED_MFW_SET_FIELD(mb_param, 40318c2ecf20Sopenharmony_ci DRV_MB_PARAM_NVM_CFG_OPTION_INIT, 1); 40328c2ecf20Sopenharmony_ci if (flags & QED_NVM_CFG_OPTION_COMMIT) 40338c2ecf20Sopenharmony_ci QED_MFW_SET_FIELD(mb_param, 40348c2ecf20Sopenharmony_ci DRV_MB_PARAM_NVM_CFG_OPTION_COMMIT, 1); 40358c2ecf20Sopenharmony_ci if (flags & QED_NVM_CFG_OPTION_FREE) 40368c2ecf20Sopenharmony_ci QED_MFW_SET_FIELD(mb_param, 40378c2ecf20Sopenharmony_ci DRV_MB_PARAM_NVM_CFG_OPTION_FREE, 1); 40388c2ecf20Sopenharmony_ci if (flags & QED_NVM_CFG_OPTION_ENTITY_SEL) { 40398c2ecf20Sopenharmony_ci QED_MFW_SET_FIELD(mb_param, 40408c2ecf20Sopenharmony_ci DRV_MB_PARAM_NVM_CFG_OPTION_ENTITY_SEL, 1); 40418c2ecf20Sopenharmony_ci QED_MFW_SET_FIELD(mb_param, 40428c2ecf20Sopenharmony_ci DRV_MB_PARAM_NVM_CFG_OPTION_ENTITY_ID, 40438c2ecf20Sopenharmony_ci entity_id); 40448c2ecf20Sopenharmony_ci } 40458c2ecf20Sopenharmony_ci 40468c2ecf20Sopenharmony_ci return qed_mcp_nvm_wr_cmd(p_hwfn, p_ptt, 40478c2ecf20Sopenharmony_ci DRV_MSG_CODE_SET_NVM_CFG_OPTION, 40488c2ecf20Sopenharmony_ci mb_param, &resp, ¶m, len, (u32 *)p_buf); 40498c2ecf20Sopenharmony_ci} 40508c2ecf20Sopenharmony_ci 40518c2ecf20Sopenharmony_ci#define QED_MCP_DBG_DATA_MAX_SIZE MCP_DRV_NVM_BUF_LEN 40528c2ecf20Sopenharmony_ci#define QED_MCP_DBG_DATA_MAX_HEADER_SIZE sizeof(u32) 40538c2ecf20Sopenharmony_ci#define QED_MCP_DBG_DATA_MAX_PAYLOAD_SIZE \ 40548c2ecf20Sopenharmony_ci (QED_MCP_DBG_DATA_MAX_SIZE - QED_MCP_DBG_DATA_MAX_HEADER_SIZE) 40558c2ecf20Sopenharmony_ci 40568c2ecf20Sopenharmony_cistatic int 40578c2ecf20Sopenharmony_ci__qed_mcp_send_debug_data(struct qed_hwfn *p_hwfn, 40588c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt, u8 *p_buf, u8 size) 40598c2ecf20Sopenharmony_ci{ 40608c2ecf20Sopenharmony_ci struct qed_mcp_mb_params mb_params; 40618c2ecf20Sopenharmony_ci int rc; 40628c2ecf20Sopenharmony_ci 40638c2ecf20Sopenharmony_ci if (size > QED_MCP_DBG_DATA_MAX_SIZE) { 40648c2ecf20Sopenharmony_ci DP_ERR(p_hwfn, 40658c2ecf20Sopenharmony_ci "Debug data size is %d while it should not exceed %d\n", 40668c2ecf20Sopenharmony_ci size, QED_MCP_DBG_DATA_MAX_SIZE); 40678c2ecf20Sopenharmony_ci return -EINVAL; 40688c2ecf20Sopenharmony_ci } 40698c2ecf20Sopenharmony_ci 40708c2ecf20Sopenharmony_ci memset(&mb_params, 0, sizeof(mb_params)); 40718c2ecf20Sopenharmony_ci mb_params.cmd = DRV_MSG_CODE_DEBUG_DATA_SEND; 40728c2ecf20Sopenharmony_ci SET_MFW_FIELD(mb_params.param, DRV_MSG_CODE_DEBUG_DATA_SEND_SIZE, size); 40738c2ecf20Sopenharmony_ci mb_params.p_data_src = p_buf; 40748c2ecf20Sopenharmony_ci mb_params.data_src_size = size; 40758c2ecf20Sopenharmony_ci rc = qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 40768c2ecf20Sopenharmony_ci if (rc) 40778c2ecf20Sopenharmony_ci return rc; 40788c2ecf20Sopenharmony_ci 40798c2ecf20Sopenharmony_ci if (mb_params.mcp_resp == FW_MSG_CODE_UNSUPPORTED) { 40808c2ecf20Sopenharmony_ci DP_INFO(p_hwfn, 40818c2ecf20Sopenharmony_ci "The DEBUG_DATA_SEND command is unsupported by the MFW\n"); 40828c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 40838c2ecf20Sopenharmony_ci } else if (mb_params.mcp_resp == (u32)FW_MSG_CODE_DEBUG_NOT_ENABLED) { 40848c2ecf20Sopenharmony_ci DP_INFO(p_hwfn, "The DEBUG_DATA_SEND command is not enabled\n"); 40858c2ecf20Sopenharmony_ci return -EBUSY; 40868c2ecf20Sopenharmony_ci } else if (mb_params.mcp_resp != (u32)FW_MSG_CODE_DEBUG_DATA_SEND_OK) { 40878c2ecf20Sopenharmony_ci DP_NOTICE(p_hwfn, 40888c2ecf20Sopenharmony_ci "Failed to send debug data to the MFW [resp 0x%08x]\n", 40898c2ecf20Sopenharmony_ci mb_params.mcp_resp); 40908c2ecf20Sopenharmony_ci return -EINVAL; 40918c2ecf20Sopenharmony_ci } 40928c2ecf20Sopenharmony_ci 40938c2ecf20Sopenharmony_ci return 0; 40948c2ecf20Sopenharmony_ci} 40958c2ecf20Sopenharmony_ci 40968c2ecf20Sopenharmony_cienum qed_mcp_dbg_data_type { 40978c2ecf20Sopenharmony_ci QED_MCP_DBG_DATA_TYPE_RAW, 40988c2ecf20Sopenharmony_ci}; 40998c2ecf20Sopenharmony_ci 41008c2ecf20Sopenharmony_ci/* Header format: [31:28] PFID, [27:20] flags, [19:12] type, [11:0] S/N */ 41018c2ecf20Sopenharmony_ci#define QED_MCP_DBG_DATA_HDR_SN_OFFSET 0 41028c2ecf20Sopenharmony_ci#define QED_MCP_DBG_DATA_HDR_SN_MASK 0x00000fff 41038c2ecf20Sopenharmony_ci#define QED_MCP_DBG_DATA_HDR_TYPE_OFFSET 12 41048c2ecf20Sopenharmony_ci#define QED_MCP_DBG_DATA_HDR_TYPE_MASK 0x000ff000 41058c2ecf20Sopenharmony_ci#define QED_MCP_DBG_DATA_HDR_FLAGS_OFFSET 20 41068c2ecf20Sopenharmony_ci#define QED_MCP_DBG_DATA_HDR_FLAGS_MASK 0x0ff00000 41078c2ecf20Sopenharmony_ci#define QED_MCP_DBG_DATA_HDR_PF_OFFSET 28 41088c2ecf20Sopenharmony_ci#define QED_MCP_DBG_DATA_HDR_PF_MASK 0xf0000000 41098c2ecf20Sopenharmony_ci 41108c2ecf20Sopenharmony_ci#define QED_MCP_DBG_DATA_HDR_FLAGS_FIRST 0x1 41118c2ecf20Sopenharmony_ci#define QED_MCP_DBG_DATA_HDR_FLAGS_LAST 0x2 41128c2ecf20Sopenharmony_ci 41138c2ecf20Sopenharmony_cistatic int 41148c2ecf20Sopenharmony_ciqed_mcp_send_debug_data(struct qed_hwfn *p_hwfn, 41158c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt, 41168c2ecf20Sopenharmony_ci enum qed_mcp_dbg_data_type type, u8 *p_buf, u32 size) 41178c2ecf20Sopenharmony_ci{ 41188c2ecf20Sopenharmony_ci u8 raw_data[QED_MCP_DBG_DATA_MAX_SIZE], *p_tmp_buf = p_buf; 41198c2ecf20Sopenharmony_ci u32 tmp_size = size, *p_header, *p_payload; 41208c2ecf20Sopenharmony_ci u8 flags = 0; 41218c2ecf20Sopenharmony_ci u16 seq; 41228c2ecf20Sopenharmony_ci int rc; 41238c2ecf20Sopenharmony_ci 41248c2ecf20Sopenharmony_ci p_header = (u32 *)raw_data; 41258c2ecf20Sopenharmony_ci p_payload = (u32 *)(raw_data + QED_MCP_DBG_DATA_MAX_HEADER_SIZE); 41268c2ecf20Sopenharmony_ci 41278c2ecf20Sopenharmony_ci seq = (u16)atomic_inc_return(&p_hwfn->mcp_info->dbg_data_seq); 41288c2ecf20Sopenharmony_ci 41298c2ecf20Sopenharmony_ci /* First chunk is marked as 'first' */ 41308c2ecf20Sopenharmony_ci flags |= QED_MCP_DBG_DATA_HDR_FLAGS_FIRST; 41318c2ecf20Sopenharmony_ci 41328c2ecf20Sopenharmony_ci *p_header = 0; 41338c2ecf20Sopenharmony_ci SET_MFW_FIELD(*p_header, QED_MCP_DBG_DATA_HDR_SN, seq); 41348c2ecf20Sopenharmony_ci SET_MFW_FIELD(*p_header, QED_MCP_DBG_DATA_HDR_TYPE, type); 41358c2ecf20Sopenharmony_ci SET_MFW_FIELD(*p_header, QED_MCP_DBG_DATA_HDR_FLAGS, flags); 41368c2ecf20Sopenharmony_ci SET_MFW_FIELD(*p_header, QED_MCP_DBG_DATA_HDR_PF, p_hwfn->abs_pf_id); 41378c2ecf20Sopenharmony_ci 41388c2ecf20Sopenharmony_ci while (tmp_size > QED_MCP_DBG_DATA_MAX_PAYLOAD_SIZE) { 41398c2ecf20Sopenharmony_ci memcpy(p_payload, p_tmp_buf, QED_MCP_DBG_DATA_MAX_PAYLOAD_SIZE); 41408c2ecf20Sopenharmony_ci rc = __qed_mcp_send_debug_data(p_hwfn, p_ptt, raw_data, 41418c2ecf20Sopenharmony_ci QED_MCP_DBG_DATA_MAX_SIZE); 41428c2ecf20Sopenharmony_ci if (rc) 41438c2ecf20Sopenharmony_ci return rc; 41448c2ecf20Sopenharmony_ci 41458c2ecf20Sopenharmony_ci /* Clear the 'first' marking after sending the first chunk */ 41468c2ecf20Sopenharmony_ci if (p_tmp_buf == p_buf) { 41478c2ecf20Sopenharmony_ci flags &= ~QED_MCP_DBG_DATA_HDR_FLAGS_FIRST; 41488c2ecf20Sopenharmony_ci SET_MFW_FIELD(*p_header, QED_MCP_DBG_DATA_HDR_FLAGS, 41498c2ecf20Sopenharmony_ci flags); 41508c2ecf20Sopenharmony_ci } 41518c2ecf20Sopenharmony_ci 41528c2ecf20Sopenharmony_ci p_tmp_buf += QED_MCP_DBG_DATA_MAX_PAYLOAD_SIZE; 41538c2ecf20Sopenharmony_ci tmp_size -= QED_MCP_DBG_DATA_MAX_PAYLOAD_SIZE; 41548c2ecf20Sopenharmony_ci } 41558c2ecf20Sopenharmony_ci 41568c2ecf20Sopenharmony_ci /* Last chunk is marked as 'last' */ 41578c2ecf20Sopenharmony_ci flags |= QED_MCP_DBG_DATA_HDR_FLAGS_LAST; 41588c2ecf20Sopenharmony_ci SET_MFW_FIELD(*p_header, QED_MCP_DBG_DATA_HDR_FLAGS, flags); 41598c2ecf20Sopenharmony_ci memcpy(p_payload, p_tmp_buf, tmp_size); 41608c2ecf20Sopenharmony_ci 41618c2ecf20Sopenharmony_ci /* Casting the left size to u8 is ok since at this point it is <= 32 */ 41628c2ecf20Sopenharmony_ci return __qed_mcp_send_debug_data(p_hwfn, p_ptt, raw_data, 41638c2ecf20Sopenharmony_ci (u8)(QED_MCP_DBG_DATA_MAX_HEADER_SIZE + 41648c2ecf20Sopenharmony_ci tmp_size)); 41658c2ecf20Sopenharmony_ci} 41668c2ecf20Sopenharmony_ci 41678c2ecf20Sopenharmony_ciint 41688c2ecf20Sopenharmony_ciqed_mcp_send_raw_debug_data(struct qed_hwfn *p_hwfn, 41698c2ecf20Sopenharmony_ci struct qed_ptt *p_ptt, u8 *p_buf, u32 size) 41708c2ecf20Sopenharmony_ci{ 41718c2ecf20Sopenharmony_ci return qed_mcp_send_debug_data(p_hwfn, p_ptt, 41728c2ecf20Sopenharmony_ci QED_MCP_DBG_DATA_TYPE_RAW, p_buf, size); 41738c2ecf20Sopenharmony_ci} 4174