11f4d4ed6SAlexander Lobakin // SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) 2fe56b9e6SYuval Mintz /* QLogic qed NIC Driver 3e8f1cb50SMintz, Yuval * Copyright (c) 2015-2017 QLogic Corporation 4663eacd8SAlexander Lobakin * Copyright (c) 2019-2020 Marvell International Ltd. 5fe56b9e6SYuval Mintz */ 6fe56b9e6SYuval Mintz 7fe56b9e6SYuval Mintz #include <linux/types.h> 8fe56b9e6SYuval Mintz #include <asm/byteorder.h> 9fe56b9e6SYuval Mintz #include <linux/delay.h> 10fe56b9e6SYuval Mintz #include <linux/errno.h> 11fe56b9e6SYuval Mintz #include <linux/kernel.h> 12fe56b9e6SYuval Mintz #include <linux/slab.h> 135529bad9STomer Tayar #include <linux/spinlock.h> 14fe56b9e6SYuval Mintz #include <linux/string.h> 150fefbfbaSSudarsana Kalluru #include <linux/etherdevice.h> 16fe56b9e6SYuval Mintz #include "qed.h" 17cac6f691SSudarsana Reddy Kalluru #include "qed_cxt.h" 1839651abdSSudarsana Reddy Kalluru #include "qed_dcbx.h" 19fe56b9e6SYuval Mintz #include "qed_hsi.h" 20ee824f4bSOmkar Kulkarni #include "qed_mfw_hsi.h" 21fe56b9e6SYuval Mintz #include "qed_hw.h" 22fe56b9e6SYuval Mintz #include "qed_mcp.h" 23fe56b9e6SYuval Mintz #include "qed_reg_addr.h" 241408cc1fSYuval Mintz #include "qed_sriov.h" 251408cc1fSYuval Mintz 260500a70dSMichal Kalderon #define GRCBASE_MCP 0xe00000 270500a70dSMichal Kalderon 28eaa50fc5STomer Tayar #define QED_MCP_RESP_ITER_US 10 29fe56b9e6SYuval Mintz 30fe56b9e6SYuval Mintz #define QED_DRV_MB_MAX_RETRIES (500 * 1000) /* Account for 5 sec */ 31fe56b9e6SYuval Mintz #define QED_MCP_RESET_RETRIES (50 * 1000) /* Account for 500 msec */ 32fe56b9e6SYuval Mintz 33fe56b9e6SYuval Mintz #define DRV_INNER_WR(_p_hwfn, _p_ptt, _ptr, _offset, _val) \ 346c95dd8fSPrabhakar Kushwaha qed_wr(_p_hwfn, _p_ptt, (_p_hwfn->mcp_info->_ptr + (_offset)), \ 35fe56b9e6SYuval Mintz _val) 36fe56b9e6SYuval Mintz 37fe56b9e6SYuval Mintz #define DRV_INNER_RD(_p_hwfn, _p_ptt, _ptr, _offset) \ 386c95dd8fSPrabhakar Kushwaha qed_rd(_p_hwfn, _p_ptt, (_p_hwfn->mcp_info->_ptr + (_offset))) 39fe56b9e6SYuval Mintz 40fe56b9e6SYuval Mintz #define DRV_MB_WR(_p_hwfn, _p_ptt, _field, _val) \ 41fe56b9e6SYuval Mintz DRV_INNER_WR(p_hwfn, _p_ptt, drv_mb_addr, \ 42fe56b9e6SYuval Mintz offsetof(struct public_drv_mb, _field), _val) 43fe56b9e6SYuval Mintz 44fe56b9e6SYuval Mintz #define DRV_MB_RD(_p_hwfn, _p_ptt, _field) \ 45fe56b9e6SYuval Mintz DRV_INNER_RD(_p_hwfn, _p_ptt, drv_mb_addr, \ 46fe56b9e6SYuval Mintz offsetof(struct public_drv_mb, _field)) 47fe56b9e6SYuval Mintz 48fe56b9e6SYuval Mintz #define PDA_COMP (((FW_MAJOR_VERSION) + (FW_MINOR_VERSION << 8)) << \ 49fe56b9e6SYuval Mintz DRV_ID_PDA_COMP_VER_SHIFT) 50fe56b9e6SYuval Mintz 51fe56b9e6SYuval Mintz #define MCP_BYTES_PER_MBIT_SHIFT 17 52fe56b9e6SYuval Mintz 53fe56b9e6SYuval Mintz bool qed_mcp_is_init(struct qed_hwfn *p_hwfn) 54fe56b9e6SYuval Mintz { 55fe56b9e6SYuval Mintz if (!p_hwfn->mcp_info || !p_hwfn->mcp_info->public_base) 56fe56b9e6SYuval Mintz return false; 57fe56b9e6SYuval Mintz return true; 58fe56b9e6SYuval Mintz } 59fe56b9e6SYuval Mintz 601a635e48SYuval Mintz void qed_mcp_cmd_port_init(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 61fe56b9e6SYuval Mintz { 62fe56b9e6SYuval Mintz u32 addr = SECTION_OFFSIZE_ADDR(p_hwfn->mcp_info->public_base, 63fe56b9e6SYuval Mintz PUBLIC_PORT); 64fe56b9e6SYuval Mintz u32 mfw_mb_offsize = qed_rd(p_hwfn, p_ptt, addr); 65fe56b9e6SYuval Mintz 66fe56b9e6SYuval Mintz p_hwfn->mcp_info->port_addr = SECTION_ADDR(mfw_mb_offsize, 67fe56b9e6SYuval Mintz MFW_PORT(p_hwfn)); 68fe56b9e6SYuval Mintz DP_VERBOSE(p_hwfn, QED_MSG_SP, 69fe56b9e6SYuval Mintz "port_addr = 0x%x, port_id 0x%02x\n", 70fe56b9e6SYuval Mintz p_hwfn->mcp_info->port_addr, MFW_PORT(p_hwfn)); 71fe56b9e6SYuval Mintz } 72fe56b9e6SYuval Mintz 731a635e48SYuval Mintz void qed_mcp_read_mb(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 74fe56b9e6SYuval Mintz { 75fe56b9e6SYuval Mintz u32 length = MFW_DRV_MSG_MAX_DWORDS(p_hwfn->mcp_info->mfw_mb_length); 76fe56b9e6SYuval Mintz u32 tmp, i; 77fe56b9e6SYuval Mintz 78fe56b9e6SYuval Mintz if (!p_hwfn->mcp_info->public_base) 79fe56b9e6SYuval Mintz return; 80fe56b9e6SYuval Mintz 81fe56b9e6SYuval Mintz for (i = 0; i < length; i++) { 82fe56b9e6SYuval Mintz tmp = qed_rd(p_hwfn, p_ptt, 83fe56b9e6SYuval Mintz p_hwfn->mcp_info->mfw_mb_addr + 84fe56b9e6SYuval Mintz (i << 2) + sizeof(u32)); 85fe56b9e6SYuval Mintz 86fe56b9e6SYuval Mintz /* The MB data is actually BE; Need to force it to cpu */ 87fe56b9e6SYuval Mintz ((u32 *)p_hwfn->mcp_info->mfw_mb_cur)[i] = 88fe56b9e6SYuval Mintz be32_to_cpu((__force __be32)tmp); 89fe56b9e6SYuval Mintz } 90fe56b9e6SYuval Mintz } 91fe56b9e6SYuval Mintz 924ed1eea8STomer Tayar struct qed_mcp_cmd_elem { 934ed1eea8STomer Tayar struct list_head list; 944ed1eea8STomer Tayar struct qed_mcp_mb_params *p_mb_params; 954ed1eea8STomer Tayar u16 expected_seq_num; 964ed1eea8STomer Tayar bool b_is_completed; 974ed1eea8STomer Tayar }; 984ed1eea8STomer Tayar 994ed1eea8STomer Tayar /* Must be called while cmd_lock is acquired */ 1004ed1eea8STomer Tayar static struct qed_mcp_cmd_elem * 1014ed1eea8STomer Tayar qed_mcp_cmd_add_elem(struct qed_hwfn *p_hwfn, 1024ed1eea8STomer Tayar struct qed_mcp_mb_params *p_mb_params, 1034ed1eea8STomer Tayar u16 expected_seq_num) 1044ed1eea8STomer Tayar { 1054ed1eea8STomer Tayar struct qed_mcp_cmd_elem *p_cmd_elem = NULL; 1064ed1eea8STomer Tayar 1074ed1eea8STomer Tayar p_cmd_elem = kzalloc(sizeof(*p_cmd_elem), GFP_ATOMIC); 1084ed1eea8STomer Tayar if (!p_cmd_elem) 1094ed1eea8STomer Tayar goto out; 1104ed1eea8STomer Tayar 1114ed1eea8STomer Tayar p_cmd_elem->p_mb_params = p_mb_params; 1124ed1eea8STomer Tayar p_cmd_elem->expected_seq_num = expected_seq_num; 1134ed1eea8STomer Tayar list_add(&p_cmd_elem->list, &p_hwfn->mcp_info->cmd_list); 1144ed1eea8STomer Tayar out: 1154ed1eea8STomer Tayar return p_cmd_elem; 1164ed1eea8STomer Tayar } 1174ed1eea8STomer Tayar 1184ed1eea8STomer Tayar /* Must be called while cmd_lock is acquired */ 1194ed1eea8STomer Tayar static void qed_mcp_cmd_del_elem(struct qed_hwfn *p_hwfn, 1204ed1eea8STomer Tayar struct qed_mcp_cmd_elem *p_cmd_elem) 1214ed1eea8STomer Tayar { 1224ed1eea8STomer Tayar list_del(&p_cmd_elem->list); 1234ed1eea8STomer Tayar kfree(p_cmd_elem); 1244ed1eea8STomer Tayar } 1254ed1eea8STomer Tayar 1264ed1eea8STomer Tayar /* Must be called while cmd_lock is acquired */ 1274ed1eea8STomer Tayar static struct qed_mcp_cmd_elem *qed_mcp_cmd_get_elem(struct qed_hwfn *p_hwfn, 1284ed1eea8STomer Tayar u16 seq_num) 1294ed1eea8STomer Tayar { 1304ed1eea8STomer Tayar struct qed_mcp_cmd_elem *p_cmd_elem = NULL; 1314ed1eea8STomer Tayar 1324ed1eea8STomer Tayar list_for_each_entry(p_cmd_elem, &p_hwfn->mcp_info->cmd_list, list) { 1334ed1eea8STomer Tayar if (p_cmd_elem->expected_seq_num == seq_num) 1344ed1eea8STomer Tayar return p_cmd_elem; 1354ed1eea8STomer Tayar } 1364ed1eea8STomer Tayar 1374ed1eea8STomer Tayar return NULL; 1384ed1eea8STomer Tayar } 1394ed1eea8STomer Tayar 140fe56b9e6SYuval Mintz int qed_mcp_free(struct qed_hwfn *p_hwfn) 141fe56b9e6SYuval Mintz { 142fe56b9e6SYuval Mintz if (p_hwfn->mcp_info) { 143*ca2d5f1fSVenkata Sudheer Kumar Bhavaraju struct qed_mcp_cmd_elem *p_cmd_elem = NULL, *p_tmp; 1444ed1eea8STomer Tayar 145fe56b9e6SYuval Mintz kfree(p_hwfn->mcp_info->mfw_mb_cur); 146fe56b9e6SYuval Mintz kfree(p_hwfn->mcp_info->mfw_mb_shadow); 1474ed1eea8STomer Tayar 1484ed1eea8STomer Tayar spin_lock_bh(&p_hwfn->mcp_info->cmd_lock); 1494ed1eea8STomer Tayar list_for_each_entry_safe(p_cmd_elem, 1504ed1eea8STomer Tayar p_tmp, 1514ed1eea8STomer Tayar &p_hwfn->mcp_info->cmd_list, list) { 1524ed1eea8STomer Tayar qed_mcp_cmd_del_elem(p_hwfn, p_cmd_elem); 153fe56b9e6SYuval Mintz } 1544ed1eea8STomer Tayar spin_unlock_bh(&p_hwfn->mcp_info->cmd_lock); 1554ed1eea8STomer Tayar } 1564ed1eea8STomer Tayar 157fe56b9e6SYuval Mintz kfree(p_hwfn->mcp_info); 1583587cb87STomer Tayar p_hwfn->mcp_info = NULL; 159fe56b9e6SYuval Mintz 160fe56b9e6SYuval Mintz return 0; 161fe56b9e6SYuval Mintz } 162fe56b9e6SYuval Mintz 163f00d25f3STomer Tayar /* Maximum of 1 sec to wait for the SHMEM ready indication */ 164f00d25f3STomer Tayar #define QED_MCP_SHMEM_RDY_MAX_RETRIES 20 165f00d25f3STomer Tayar #define QED_MCP_SHMEM_RDY_ITER_MS 50 166f00d25f3STomer Tayar 1671a635e48SYuval Mintz static int qed_load_mcp_offsets(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 168fe56b9e6SYuval Mintz { 169fe56b9e6SYuval Mintz struct qed_mcp_info *p_info = p_hwfn->mcp_info; 170f00d25f3STomer Tayar u8 cnt = QED_MCP_SHMEM_RDY_MAX_RETRIES; 171f00d25f3STomer Tayar u8 msec = QED_MCP_SHMEM_RDY_ITER_MS; 172fe56b9e6SYuval Mintz u32 drv_mb_offsize, mfw_mb_offsize; 173fe56b9e6SYuval Mintz u32 mcp_pf_id = MCP_PF_ID(p_hwfn); 174fe56b9e6SYuval Mintz 175fe56b9e6SYuval Mintz p_info->public_base = qed_rd(p_hwfn, p_ptt, MISC_REG_SHARED_MEM_ADDR); 176f00d25f3STomer Tayar if (!p_info->public_base) { 177f00d25f3STomer Tayar DP_NOTICE(p_hwfn, 178f00d25f3STomer Tayar "The address of the MCP scratch-pad is not configured\n"); 179f00d25f3STomer Tayar return -EINVAL; 180f00d25f3STomer Tayar } 181fe56b9e6SYuval Mintz 182fe56b9e6SYuval Mintz p_info->public_base |= GRCBASE_MCP; 183fe56b9e6SYuval Mintz 184f00d25f3STomer Tayar /* Get the MFW MB address and number of supported messages */ 185f00d25f3STomer Tayar mfw_mb_offsize = qed_rd(p_hwfn, p_ptt, 186f00d25f3STomer Tayar SECTION_OFFSIZE_ADDR(p_info->public_base, 187f00d25f3STomer Tayar PUBLIC_MFW_MB)); 188f00d25f3STomer Tayar p_info->mfw_mb_addr = SECTION_ADDR(mfw_mb_offsize, mcp_pf_id); 189f00d25f3STomer Tayar p_info->mfw_mb_length = (u16)qed_rd(p_hwfn, p_ptt, 190f00d25f3STomer Tayar p_info->mfw_mb_addr + 191f00d25f3STomer Tayar offsetof(struct public_mfw_mb, 192f00d25f3STomer Tayar sup_msgs)); 193f00d25f3STomer Tayar 194f00d25f3STomer Tayar /* The driver can notify that there was an MCP reset, and might read the 195f00d25f3STomer Tayar * SHMEM values before the MFW has completed initializing them. 196f00d25f3STomer Tayar * To avoid this, the "sup_msgs" field in the MFW mailbox is used as a 197f00d25f3STomer Tayar * data ready indication. 198f00d25f3STomer Tayar */ 199f00d25f3STomer Tayar while (!p_info->mfw_mb_length && --cnt) { 200f00d25f3STomer Tayar msleep(msec); 201f00d25f3STomer Tayar p_info->mfw_mb_length = 202f00d25f3STomer Tayar (u16)qed_rd(p_hwfn, p_ptt, 203f00d25f3STomer Tayar p_info->mfw_mb_addr + 204f00d25f3STomer Tayar offsetof(struct public_mfw_mb, sup_msgs)); 205f00d25f3STomer Tayar } 206f00d25f3STomer Tayar 207f00d25f3STomer Tayar if (!cnt) { 208f00d25f3STomer Tayar DP_NOTICE(p_hwfn, 209f00d25f3STomer Tayar "Failed to get the SHMEM ready notification after %d msec\n", 210f00d25f3STomer Tayar QED_MCP_SHMEM_RDY_MAX_RETRIES * msec); 211f00d25f3STomer Tayar return -EBUSY; 212f00d25f3STomer Tayar } 213f00d25f3STomer Tayar 214fe56b9e6SYuval Mintz /* Calculate the driver and MFW mailbox address */ 215fe56b9e6SYuval Mintz drv_mb_offsize = qed_rd(p_hwfn, p_ptt, 216fe56b9e6SYuval Mintz SECTION_OFFSIZE_ADDR(p_info->public_base, 217fe56b9e6SYuval Mintz PUBLIC_DRV_MB)); 218fe56b9e6SYuval Mintz p_info->drv_mb_addr = SECTION_ADDR(drv_mb_offsize, mcp_pf_id); 219fe56b9e6SYuval Mintz DP_VERBOSE(p_hwfn, QED_MSG_SP, 220fe56b9e6SYuval Mintz "drv_mb_offsiz = 0x%x, drv_mb_addr = 0x%x mcp_pf_id = 0x%x\n", 221fe56b9e6SYuval Mintz drv_mb_offsize, p_info->drv_mb_addr, mcp_pf_id); 222fe56b9e6SYuval Mintz 223fe56b9e6SYuval Mintz /* Get the current driver mailbox sequence before sending 224fe56b9e6SYuval Mintz * the first command 225fe56b9e6SYuval Mintz */ 226fe56b9e6SYuval Mintz p_info->drv_mb_seq = DRV_MB_RD(p_hwfn, p_ptt, drv_mb_header) & 227fe56b9e6SYuval Mintz DRV_MSG_SEQ_NUMBER_MASK; 228fe56b9e6SYuval Mintz 229fe56b9e6SYuval Mintz /* Get current FW pulse sequence */ 230fe56b9e6SYuval Mintz p_info->drv_pulse_seq = DRV_MB_RD(p_hwfn, p_ptt, drv_pulse_mb) & 231fe56b9e6SYuval Mintz DRV_PULSE_SEQ_MASK; 232fe56b9e6SYuval Mintz 2334ed1eea8STomer Tayar p_info->mcp_hist = qed_rd(p_hwfn, p_ptt, MISCS_REG_GENERIC_POR_0); 234fe56b9e6SYuval Mintz 235fe56b9e6SYuval Mintz return 0; 236fe56b9e6SYuval Mintz } 237fe56b9e6SYuval Mintz 2381a635e48SYuval Mintz int qed_mcp_cmd_init(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 239fe56b9e6SYuval Mintz { 240fe56b9e6SYuval Mintz struct qed_mcp_info *p_info; 241fe56b9e6SYuval Mintz u32 size; 242fe56b9e6SYuval Mintz 243fe56b9e6SYuval Mintz /* Allocate mcp_info structure */ 24460fffb3bSYuval Mintz p_hwfn->mcp_info = kzalloc(sizeof(*p_hwfn->mcp_info), GFP_KERNEL); 245fe56b9e6SYuval Mintz if (!p_hwfn->mcp_info) 246fe56b9e6SYuval Mintz goto err; 247fe56b9e6SYuval Mintz p_info = p_hwfn->mcp_info; 248fe56b9e6SYuval Mintz 2494ed1eea8STomer Tayar /* Initialize the MFW spinlock */ 2504ed1eea8STomer Tayar spin_lock_init(&p_info->cmd_lock); 2514ed1eea8STomer Tayar spin_lock_init(&p_info->link_lock); 252*ca2d5f1fSVenkata Sudheer Kumar Bhavaraju spin_lock_init(&p_info->unload_lock); 2534ed1eea8STomer Tayar 2544ed1eea8STomer Tayar INIT_LIST_HEAD(&p_info->cmd_list); 2554ed1eea8STomer Tayar 256fe56b9e6SYuval Mintz if (qed_load_mcp_offsets(p_hwfn, p_ptt) != 0) { 257fe56b9e6SYuval Mintz DP_NOTICE(p_hwfn, "MCP is not initialized\n"); 258fe56b9e6SYuval Mintz /* Do not free mcp_info here, since public_base indicate that 259fe56b9e6SYuval Mintz * the MCP is not initialized 260fe56b9e6SYuval Mintz */ 261fe56b9e6SYuval Mintz return 0; 262fe56b9e6SYuval Mintz } 263fe56b9e6SYuval Mintz 264fe56b9e6SYuval Mintz size = MFW_DRV_MSG_MAX_DWORDS(p_info->mfw_mb_length) * sizeof(u32); 26560fffb3bSYuval Mintz p_info->mfw_mb_cur = kzalloc(size, GFP_KERNEL); 26683aeb933SYuval Mintz p_info->mfw_mb_shadow = kzalloc(size, GFP_KERNEL); 267eb2a6b80SChristophe Jaillet if (!p_info->mfw_mb_cur || !p_info->mfw_mb_shadow) 268fe56b9e6SYuval Mintz goto err; 269fe56b9e6SYuval Mintz 270fe56b9e6SYuval Mintz return 0; 271fe56b9e6SYuval Mintz 272fe56b9e6SYuval Mintz err: 273fe56b9e6SYuval Mintz qed_mcp_free(p_hwfn); 274fe56b9e6SYuval Mintz return -ENOMEM; 275fe56b9e6SYuval Mintz } 276fe56b9e6SYuval Mintz 2774ed1eea8STomer Tayar static void qed_mcp_reread_offsets(struct qed_hwfn *p_hwfn, 2784ed1eea8STomer Tayar struct qed_ptt *p_ptt) 2795529bad9STomer Tayar { 2804ed1eea8STomer Tayar u32 generic_por_0 = qed_rd(p_hwfn, p_ptt, MISCS_REG_GENERIC_POR_0); 2815529bad9STomer Tayar 2824ed1eea8STomer Tayar /* Use MCP history register to check if MCP reset occurred between init 2834ed1eea8STomer Tayar * time and now. 2845529bad9STomer Tayar */ 2854ed1eea8STomer Tayar if (p_hwfn->mcp_info->mcp_hist != generic_por_0) { 2864ed1eea8STomer Tayar DP_VERBOSE(p_hwfn, 2874ed1eea8STomer Tayar QED_MSG_SP, 2884ed1eea8STomer Tayar "Rereading MCP offsets [mcp_hist 0x%08x, generic_por_0 0x%08x]\n", 2894ed1eea8STomer Tayar p_hwfn->mcp_info->mcp_hist, generic_por_0); 2905529bad9STomer Tayar 2914ed1eea8STomer Tayar qed_load_mcp_offsets(p_hwfn, p_ptt); 2924ed1eea8STomer Tayar qed_mcp_cmd_port_init(p_hwfn, p_ptt); 2935529bad9STomer Tayar } 2945529bad9STomer Tayar } 2955529bad9STomer Tayar 2961a635e48SYuval Mintz int qed_mcp_reset(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 297fe56b9e6SYuval Mintz { 298eaa50fc5STomer Tayar u32 org_mcp_reset_seq, seq, delay = QED_MCP_RESP_ITER_US, cnt = 0; 299fe56b9e6SYuval Mintz int rc = 0; 300fe56b9e6SYuval Mintz 301b310974eSTomer Tayar if (p_hwfn->mcp_info->b_block_cmd) { 302b310974eSTomer Tayar DP_NOTICE(p_hwfn, 303b310974eSTomer Tayar "The MFW is not responsive. Avoid sending MCP_RESET mailbox command.\n"); 304b310974eSTomer Tayar return -EBUSY; 305b310974eSTomer Tayar } 306b310974eSTomer Tayar 3074ed1eea8STomer Tayar /* Ensure that only a single thread is accessing the mailbox */ 3084ed1eea8STomer Tayar spin_lock_bh(&p_hwfn->mcp_info->cmd_lock); 3094ed1eea8STomer Tayar 3104ed1eea8STomer Tayar org_mcp_reset_seq = qed_rd(p_hwfn, p_ptt, MISCS_REG_GENERIC_POR_0); 3115529bad9STomer Tayar 312fe56b9e6SYuval Mintz /* Set drv command along with the updated sequence */ 3134ed1eea8STomer Tayar qed_mcp_reread_offsets(p_hwfn, p_ptt); 3144ed1eea8STomer Tayar seq = ++p_hwfn->mcp_info->drv_mb_seq; 3154ed1eea8STomer Tayar DRV_MB_WR(p_hwfn, p_ptt, drv_mb_header, (DRV_MSG_CODE_MCP_RESET | seq)); 316fe56b9e6SYuval Mintz 317fe56b9e6SYuval Mintz do { 318fe56b9e6SYuval Mintz /* Wait for MFW response */ 319fe56b9e6SYuval Mintz udelay(delay); 320fe56b9e6SYuval Mintz /* Give the FW up to 500 second (50*1000*10usec) */ 321fe56b9e6SYuval Mintz } while ((org_mcp_reset_seq == qed_rd(p_hwfn, p_ptt, 322fe56b9e6SYuval Mintz MISCS_REG_GENERIC_POR_0)) && 323fe56b9e6SYuval Mintz (cnt++ < QED_MCP_RESET_RETRIES)); 324fe56b9e6SYuval Mintz 325fe56b9e6SYuval Mintz if (org_mcp_reset_seq != 326fe56b9e6SYuval Mintz qed_rd(p_hwfn, p_ptt, MISCS_REG_GENERIC_POR_0)) { 327fe56b9e6SYuval Mintz DP_VERBOSE(p_hwfn, QED_MSG_SP, 328fe56b9e6SYuval Mintz "MCP was reset after %d usec\n", cnt * delay); 329fe56b9e6SYuval Mintz } else { 330fe56b9e6SYuval Mintz DP_ERR(p_hwfn, "Failed to reset MCP\n"); 331fe56b9e6SYuval Mintz rc = -EAGAIN; 332fe56b9e6SYuval Mintz } 333fe56b9e6SYuval Mintz 3344ed1eea8STomer Tayar spin_unlock_bh(&p_hwfn->mcp_info->cmd_lock); 3355529bad9STomer Tayar 336fe56b9e6SYuval Mintz return rc; 337fe56b9e6SYuval Mintz } 338fe56b9e6SYuval Mintz 3394ed1eea8STomer Tayar /* Must be called while cmd_lock is acquired */ 3404ed1eea8STomer Tayar static bool qed_mcp_has_pending_cmd(struct qed_hwfn *p_hwfn) 341fe56b9e6SYuval Mintz { 3424ed1eea8STomer Tayar struct qed_mcp_cmd_elem *p_cmd_elem; 3434ed1eea8STomer Tayar 3444ed1eea8STomer Tayar /* There is at most one pending command at a certain time, and if it 3454ed1eea8STomer Tayar * exists - it is placed at the HEAD of the list. 3464ed1eea8STomer Tayar */ 3474ed1eea8STomer Tayar if (!list_empty(&p_hwfn->mcp_info->cmd_list)) { 3484ed1eea8STomer Tayar p_cmd_elem = list_first_entry(&p_hwfn->mcp_info->cmd_list, 3494ed1eea8STomer Tayar struct qed_mcp_cmd_elem, list); 3504ed1eea8STomer Tayar return !p_cmd_elem->b_is_completed; 3514ed1eea8STomer Tayar } 3524ed1eea8STomer Tayar 3534ed1eea8STomer Tayar return false; 3544ed1eea8STomer Tayar } 3554ed1eea8STomer Tayar 3564ed1eea8STomer Tayar /* Must be called while cmd_lock is acquired */ 3574ed1eea8STomer Tayar static int 3584ed1eea8STomer Tayar qed_mcp_update_pending_cmd(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 3594ed1eea8STomer Tayar { 3604ed1eea8STomer Tayar struct qed_mcp_mb_params *p_mb_params; 3614ed1eea8STomer Tayar struct qed_mcp_cmd_elem *p_cmd_elem; 3624ed1eea8STomer Tayar u32 mcp_resp; 3634ed1eea8STomer Tayar u16 seq_num; 3644ed1eea8STomer Tayar 3654ed1eea8STomer Tayar mcp_resp = DRV_MB_RD(p_hwfn, p_ptt, fw_mb_header); 3664ed1eea8STomer Tayar seq_num = (u16)(mcp_resp & FW_MSG_SEQ_NUMBER_MASK); 3674ed1eea8STomer Tayar 3684ed1eea8STomer Tayar /* Return if no new non-handled response has been received */ 3694ed1eea8STomer Tayar if (seq_num != p_hwfn->mcp_info->drv_mb_seq) 3704ed1eea8STomer Tayar return -EAGAIN; 3714ed1eea8STomer Tayar 3724ed1eea8STomer Tayar p_cmd_elem = qed_mcp_cmd_get_elem(p_hwfn, seq_num); 3734ed1eea8STomer Tayar if (!p_cmd_elem) { 3744ed1eea8STomer Tayar DP_ERR(p_hwfn, 3754ed1eea8STomer Tayar "Failed to find a pending mailbox cmd that expects sequence number %d\n", 3764ed1eea8STomer Tayar seq_num); 3774ed1eea8STomer Tayar return -EINVAL; 3784ed1eea8STomer Tayar } 3794ed1eea8STomer Tayar 3804ed1eea8STomer Tayar p_mb_params = p_cmd_elem->p_mb_params; 3814ed1eea8STomer Tayar 3824ed1eea8STomer Tayar /* Get the MFW response along with the sequence number */ 3834ed1eea8STomer Tayar p_mb_params->mcp_resp = mcp_resp; 3844ed1eea8STomer Tayar 3854ed1eea8STomer Tayar /* Get the MFW param */ 3864ed1eea8STomer Tayar p_mb_params->mcp_param = DRV_MB_RD(p_hwfn, p_ptt, fw_mb_param); 3874ed1eea8STomer Tayar 3884ed1eea8STomer Tayar /* Get the union data */ 3896c95dd8fSPrabhakar Kushwaha if (p_mb_params->p_data_dst && p_mb_params->data_dst_size) { 3904ed1eea8STomer Tayar u32 union_data_addr = p_hwfn->mcp_info->drv_mb_addr + 3914ed1eea8STomer Tayar offsetof(struct public_drv_mb, 3924ed1eea8STomer Tayar union_data); 3934ed1eea8STomer Tayar qed_memcpy_from(p_hwfn, p_ptt, p_mb_params->p_data_dst, 3942f67af8cSTomer Tayar union_data_addr, p_mb_params->data_dst_size); 3954ed1eea8STomer Tayar } 3964ed1eea8STomer Tayar 3974ed1eea8STomer Tayar p_cmd_elem->b_is_completed = true; 3984ed1eea8STomer Tayar 3994ed1eea8STomer Tayar return 0; 4004ed1eea8STomer Tayar } 4014ed1eea8STomer Tayar 4024ed1eea8STomer Tayar /* Must be called while cmd_lock is acquired */ 4034ed1eea8STomer Tayar static void __qed_mcp_cmd_and_union(struct qed_hwfn *p_hwfn, 4044ed1eea8STomer Tayar struct qed_ptt *p_ptt, 4054ed1eea8STomer Tayar struct qed_mcp_mb_params *p_mb_params, 4064ed1eea8STomer Tayar u16 seq_num) 4074ed1eea8STomer Tayar { 4084ed1eea8STomer Tayar union drv_union_data union_data; 4094ed1eea8STomer Tayar u32 union_data_addr; 4104ed1eea8STomer Tayar 4114ed1eea8STomer Tayar /* Set the union data */ 4124ed1eea8STomer Tayar union_data_addr = p_hwfn->mcp_info->drv_mb_addr + 4134ed1eea8STomer Tayar offsetof(struct public_drv_mb, union_data); 4144ed1eea8STomer Tayar memset(&union_data, 0, sizeof(union_data)); 4156c95dd8fSPrabhakar Kushwaha if (p_mb_params->p_data_src && p_mb_params->data_src_size) 4164ed1eea8STomer Tayar memcpy(&union_data, p_mb_params->p_data_src, 4172f67af8cSTomer Tayar p_mb_params->data_src_size); 4184ed1eea8STomer Tayar qed_memcpy_to(p_hwfn, p_ptt, union_data_addr, &union_data, 4194ed1eea8STomer Tayar sizeof(union_data)); 4204ed1eea8STomer Tayar 4214ed1eea8STomer Tayar /* Set the drv param */ 4224ed1eea8STomer Tayar DRV_MB_WR(p_hwfn, p_ptt, drv_mb_param, p_mb_params->param); 4234ed1eea8STomer Tayar 4244ed1eea8STomer Tayar /* Set the drv command along with the sequence number */ 4254ed1eea8STomer Tayar DRV_MB_WR(p_hwfn, p_ptt, drv_mb_header, (p_mb_params->cmd | seq_num)); 4264ed1eea8STomer Tayar 4274ed1eea8STomer Tayar DP_VERBOSE(p_hwfn, QED_MSG_SP, 4284ed1eea8STomer Tayar "MFW mailbox: command 0x%08x param 0x%08x\n", 4294ed1eea8STomer Tayar (p_mb_params->cmd | seq_num), p_mb_params->param); 4304ed1eea8STomer Tayar } 4314ed1eea8STomer Tayar 432b310974eSTomer Tayar static void qed_mcp_cmd_set_blocking(struct qed_hwfn *p_hwfn, bool block_cmd) 433b310974eSTomer Tayar { 434b310974eSTomer Tayar p_hwfn->mcp_info->b_block_cmd = block_cmd; 435b310974eSTomer Tayar 436b310974eSTomer Tayar DP_INFO(p_hwfn, "%s sending of mailbox commands to the MFW\n", 437b310974eSTomer Tayar block_cmd ? "Block" : "Unblock"); 438b310974eSTomer Tayar } 439b310974eSTomer Tayar 440b310974eSTomer Tayar static void qed_mcp_print_cpu_info(struct qed_hwfn *p_hwfn, 441b310974eSTomer Tayar struct qed_ptt *p_ptt) 442b310974eSTomer Tayar { 443b310974eSTomer Tayar u32 cpu_mode, cpu_state, cpu_pc_0, cpu_pc_1, cpu_pc_2; 444b310974eSTomer Tayar u32 delay = QED_MCP_RESP_ITER_US; 445b310974eSTomer Tayar 446b310974eSTomer Tayar cpu_mode = qed_rd(p_hwfn, p_ptt, MCP_REG_CPU_MODE); 447b310974eSTomer Tayar cpu_state = qed_rd(p_hwfn, p_ptt, MCP_REG_CPU_STATE); 448b310974eSTomer Tayar cpu_pc_0 = qed_rd(p_hwfn, p_ptt, MCP_REG_CPU_PROGRAM_COUNTER); 449b310974eSTomer Tayar udelay(delay); 450b310974eSTomer Tayar cpu_pc_1 = qed_rd(p_hwfn, p_ptt, MCP_REG_CPU_PROGRAM_COUNTER); 451b310974eSTomer Tayar udelay(delay); 452b310974eSTomer Tayar cpu_pc_2 = qed_rd(p_hwfn, p_ptt, MCP_REG_CPU_PROGRAM_COUNTER); 453b310974eSTomer Tayar 454b310974eSTomer Tayar DP_NOTICE(p_hwfn, 455b310974eSTomer Tayar "MCP CPU info: mode 0x%08x, state 0x%08x, pc {0x%08x, 0x%08x, 0x%08x}\n", 456b310974eSTomer Tayar cpu_mode, cpu_state, cpu_pc_0, cpu_pc_1, cpu_pc_2); 457b310974eSTomer Tayar } 458b310974eSTomer Tayar 4594ed1eea8STomer Tayar static int 4604ed1eea8STomer Tayar _qed_mcp_cmd_and_union(struct qed_hwfn *p_hwfn, 4614ed1eea8STomer Tayar struct qed_ptt *p_ptt, 4624ed1eea8STomer Tayar struct qed_mcp_mb_params *p_mb_params, 463eaa50fc5STomer Tayar u32 max_retries, u32 usecs) 4644ed1eea8STomer Tayar { 465eaa50fc5STomer Tayar u32 cnt = 0, msecs = DIV_ROUND_UP(usecs, 1000); 4664ed1eea8STomer Tayar struct qed_mcp_cmd_elem *p_cmd_elem; 4674ed1eea8STomer Tayar u16 seq_num; 468fe56b9e6SYuval Mintz int rc = 0; 469fe56b9e6SYuval Mintz 4704ed1eea8STomer Tayar /* Wait until the mailbox is non-occupied */ 471fe56b9e6SYuval Mintz do { 4724ed1eea8STomer Tayar /* Exit the loop if there is no pending command, or if the 4734ed1eea8STomer Tayar * pending command is completed during this iteration. 4744ed1eea8STomer Tayar * The spinlock stays locked until the command is sent. 4754ed1eea8STomer Tayar */ 4764ed1eea8STomer Tayar 4774ed1eea8STomer Tayar spin_lock_bh(&p_hwfn->mcp_info->cmd_lock); 4784ed1eea8STomer Tayar 4794ed1eea8STomer Tayar if (!qed_mcp_has_pending_cmd(p_hwfn)) 4804ed1eea8STomer Tayar break; 4814ed1eea8STomer Tayar 4824ed1eea8STomer Tayar rc = qed_mcp_update_pending_cmd(p_hwfn, p_ptt); 4834ed1eea8STomer Tayar if (!rc) 4844ed1eea8STomer Tayar break; 4854ed1eea8STomer Tayar else if (rc != -EAGAIN) 4864ed1eea8STomer Tayar goto err; 4874ed1eea8STomer Tayar 4884ed1eea8STomer Tayar spin_unlock_bh(&p_hwfn->mcp_info->cmd_lock); 489eaa50fc5STomer Tayar 490eaa50fc5STomer Tayar if (QED_MB_FLAGS_IS_SET(p_mb_params, CAN_SLEEP)) 491eaa50fc5STomer Tayar msleep(msecs); 492eaa50fc5STomer Tayar else 493eaa50fc5STomer Tayar udelay(usecs); 4944ed1eea8STomer Tayar } while (++cnt < max_retries); 495fe56b9e6SYuval Mintz 4964ed1eea8STomer Tayar if (cnt >= max_retries) { 4974ed1eea8STomer Tayar DP_NOTICE(p_hwfn, 4984ed1eea8STomer Tayar "The MFW mailbox is occupied by an uncompleted command. Failed to send command 0x%08x [param 0x%08x].\n", 4994ed1eea8STomer Tayar p_mb_params->cmd, p_mb_params->param); 5004ed1eea8STomer Tayar return -EAGAIN; 501fe56b9e6SYuval Mintz } 5024ed1eea8STomer Tayar 5034ed1eea8STomer Tayar /* Send the mailbox command */ 5044ed1eea8STomer Tayar qed_mcp_reread_offsets(p_hwfn, p_ptt); 5054ed1eea8STomer Tayar seq_num = ++p_hwfn->mcp_info->drv_mb_seq; 5064ed1eea8STomer Tayar p_cmd_elem = qed_mcp_cmd_add_elem(p_hwfn, p_mb_params, seq_num); 507c8004600SDan Carpenter if (!p_cmd_elem) { 508c8004600SDan Carpenter rc = -ENOMEM; 5094ed1eea8STomer Tayar goto err; 510c8004600SDan Carpenter } 5114ed1eea8STomer Tayar 5124ed1eea8STomer Tayar __qed_mcp_cmd_and_union(p_hwfn, p_ptt, p_mb_params, seq_num); 5134ed1eea8STomer Tayar spin_unlock_bh(&p_hwfn->mcp_info->cmd_lock); 5144ed1eea8STomer Tayar 5154ed1eea8STomer Tayar /* Wait for the MFW response */ 5164ed1eea8STomer Tayar do { 5174ed1eea8STomer Tayar /* Exit the loop if the command is already completed, or if the 5184ed1eea8STomer Tayar * command is completed during this iteration. 5194ed1eea8STomer Tayar * The spinlock stays locked until the list element is removed. 5204ed1eea8STomer Tayar */ 5214ed1eea8STomer Tayar 522eaa50fc5STomer Tayar if (QED_MB_FLAGS_IS_SET(p_mb_params, CAN_SLEEP)) 523eaa50fc5STomer Tayar msleep(msecs); 524eaa50fc5STomer Tayar else 525eaa50fc5STomer Tayar udelay(usecs); 526eaa50fc5STomer Tayar 5274ed1eea8STomer Tayar spin_lock_bh(&p_hwfn->mcp_info->cmd_lock); 5284ed1eea8STomer Tayar 5294ed1eea8STomer Tayar if (p_cmd_elem->b_is_completed) 5304ed1eea8STomer Tayar break; 5314ed1eea8STomer Tayar 5324ed1eea8STomer Tayar rc = qed_mcp_update_pending_cmd(p_hwfn, p_ptt); 5334ed1eea8STomer Tayar if (!rc) 5344ed1eea8STomer Tayar break; 5354ed1eea8STomer Tayar else if (rc != -EAGAIN) 5364ed1eea8STomer Tayar goto err; 5374ed1eea8STomer Tayar 5384ed1eea8STomer Tayar spin_unlock_bh(&p_hwfn->mcp_info->cmd_lock); 5394ed1eea8STomer Tayar } while (++cnt < max_retries); 5404ed1eea8STomer Tayar 5414ed1eea8STomer Tayar if (cnt >= max_retries) { 5424ed1eea8STomer Tayar DP_NOTICE(p_hwfn, 5434ed1eea8STomer Tayar "The MFW failed to respond to command 0x%08x [param 0x%08x].\n", 5444ed1eea8STomer Tayar p_mb_params->cmd, p_mb_params->param); 545b310974eSTomer Tayar qed_mcp_print_cpu_info(p_hwfn, p_ptt); 5464ed1eea8STomer Tayar 5474ed1eea8STomer Tayar spin_lock_bh(&p_hwfn->mcp_info->cmd_lock); 5484ed1eea8STomer Tayar qed_mcp_cmd_del_elem(p_hwfn, p_cmd_elem); 5494ed1eea8STomer Tayar spin_unlock_bh(&p_hwfn->mcp_info->cmd_lock); 5504ed1eea8STomer Tayar 551b310974eSTomer Tayar if (!QED_MB_FLAGS_IS_SET(p_mb_params, AVOID_BLOCK)) 552b310974eSTomer Tayar qed_mcp_cmd_set_blocking(p_hwfn, true); 553b310974eSTomer Tayar 5542ec276d5SIgor Russkikh qed_hw_err_notify(p_hwfn, p_ptt, 5552ec276d5SIgor Russkikh QED_HW_ERR_MFW_RESP_FAIL, NULL); 5564ed1eea8STomer Tayar return -EAGAIN; 5574ed1eea8STomer Tayar } 5584ed1eea8STomer Tayar 5594ed1eea8STomer Tayar qed_mcp_cmd_del_elem(p_hwfn, p_cmd_elem); 5604ed1eea8STomer Tayar spin_unlock_bh(&p_hwfn->mcp_info->cmd_lock); 5614ed1eea8STomer Tayar 5624ed1eea8STomer Tayar DP_VERBOSE(p_hwfn, 5634ed1eea8STomer Tayar QED_MSG_SP, 5644ed1eea8STomer Tayar "MFW mailbox: response 0x%08x param 0x%08x [after %d.%03d ms]\n", 5654ed1eea8STomer Tayar p_mb_params->mcp_resp, 5664ed1eea8STomer Tayar p_mb_params->mcp_param, 567eaa50fc5STomer Tayar (cnt * usecs) / 1000, (cnt * usecs) % 1000); 5684ed1eea8STomer Tayar 5694ed1eea8STomer Tayar /* Clear the sequence number from the MFW response */ 5704ed1eea8STomer Tayar p_mb_params->mcp_resp &= FW_MSG_CODE_MASK; 5714ed1eea8STomer Tayar 5724ed1eea8STomer Tayar return 0; 5734ed1eea8STomer Tayar 5744ed1eea8STomer Tayar err: 5754ed1eea8STomer Tayar spin_unlock_bh(&p_hwfn->mcp_info->cmd_lock); 576fe56b9e6SYuval Mintz return rc; 577fe56b9e6SYuval Mintz } 578fe56b9e6SYuval Mintz 5795529bad9STomer Tayar static int qed_mcp_cmd_and_union(struct qed_hwfn *p_hwfn, 580fe56b9e6SYuval Mintz struct qed_ptt *p_ptt, 5815529bad9STomer Tayar struct qed_mcp_mb_params *p_mb_params) 582fe56b9e6SYuval Mintz { 5832f67af8cSTomer Tayar size_t union_data_size = sizeof(union drv_union_data); 5844ed1eea8STomer Tayar u32 max_retries = QED_DRV_MB_MAX_RETRIES; 585eaa50fc5STomer Tayar u32 usecs = QED_MCP_RESP_ITER_US; 586fe56b9e6SYuval Mintz 587fe56b9e6SYuval Mintz /* MCP not initialized */ 588fe56b9e6SYuval Mintz if (!qed_mcp_is_init(p_hwfn)) { 589fe56b9e6SYuval Mintz DP_NOTICE(p_hwfn, "MFW is not initialized!\n"); 590fe56b9e6SYuval Mintz return -EBUSY; 591fe56b9e6SYuval Mintz } 592fe56b9e6SYuval Mintz 593b310974eSTomer Tayar if (p_hwfn->mcp_info->b_block_cmd) { 594b310974eSTomer Tayar DP_NOTICE(p_hwfn, 595b310974eSTomer Tayar "The MFW is not responsive. Avoid sending mailbox command 0x%08x [param 0x%08x].\n", 596b310974eSTomer Tayar p_mb_params->cmd, p_mb_params->param); 597b310974eSTomer Tayar return -EBUSY; 598b310974eSTomer Tayar } 599b310974eSTomer Tayar 6002f67af8cSTomer Tayar if (p_mb_params->data_src_size > union_data_size || 6012f67af8cSTomer Tayar p_mb_params->data_dst_size > union_data_size) { 6022f67af8cSTomer Tayar DP_ERR(p_hwfn, 6032f67af8cSTomer Tayar "The provided size is larger than the union data size [src_size %u, dst_size %u, union_data_size %zu]\n", 6042f67af8cSTomer Tayar p_mb_params->data_src_size, 6052f67af8cSTomer Tayar p_mb_params->data_dst_size, union_data_size); 6062f67af8cSTomer Tayar return -EINVAL; 6072f67af8cSTomer Tayar } 6082f67af8cSTomer Tayar 609eaa50fc5STomer Tayar if (QED_MB_FLAGS_IS_SET(p_mb_params, CAN_SLEEP)) { 610eaa50fc5STomer Tayar max_retries = DIV_ROUND_UP(max_retries, 1000); 611eaa50fc5STomer Tayar usecs *= 1000; 612eaa50fc5STomer Tayar } 613eaa50fc5STomer Tayar 6144ed1eea8STomer Tayar return _qed_mcp_cmd_and_union(p_hwfn, p_ptt, p_mb_params, max_retries, 615eaa50fc5STomer Tayar usecs); 616fe56b9e6SYuval Mintz } 617fe56b9e6SYuval Mintz 618ef10bd49SVenkata Sudheer Kumar Bhavaraju static int _qed_mcp_cmd(struct qed_hwfn *p_hwfn, 6195529bad9STomer Tayar struct qed_ptt *p_ptt, 6205529bad9STomer Tayar u32 cmd, 6215529bad9STomer Tayar u32 param, 6225529bad9STomer Tayar u32 *o_mcp_resp, 623ef10bd49SVenkata Sudheer Kumar Bhavaraju u32 *o_mcp_param, 624ef10bd49SVenkata Sudheer Kumar Bhavaraju bool can_sleep) 625fe56b9e6SYuval Mintz { 6265529bad9STomer Tayar struct qed_mcp_mb_params mb_params; 6275529bad9STomer Tayar int rc; 628fe56b9e6SYuval Mintz 6295529bad9STomer Tayar memset(&mb_params, 0, sizeof(mb_params)); 6305529bad9STomer Tayar mb_params.cmd = cmd; 6315529bad9STomer Tayar mb_params.param = param; 632ef10bd49SVenkata Sudheer Kumar Bhavaraju mb_params.flags = can_sleep ? QED_MB_FLAG_CAN_SLEEP : 0; 63314d39648SMintz, Yuval 6345529bad9STomer Tayar rc = qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 6355529bad9STomer Tayar if (rc) 6365529bad9STomer Tayar return rc; 6375529bad9STomer Tayar 6385529bad9STomer Tayar *o_mcp_resp = mb_params.mcp_resp; 6395529bad9STomer Tayar *o_mcp_param = mb_params.mcp_param; 6405529bad9STomer Tayar 6415529bad9STomer Tayar return 0; 642fe56b9e6SYuval Mintz } 643fe56b9e6SYuval Mintz 644ef10bd49SVenkata Sudheer Kumar Bhavaraju int qed_mcp_cmd(struct qed_hwfn *p_hwfn, 645ef10bd49SVenkata Sudheer Kumar Bhavaraju struct qed_ptt *p_ptt, 646ef10bd49SVenkata Sudheer Kumar Bhavaraju u32 cmd, 647ef10bd49SVenkata Sudheer Kumar Bhavaraju u32 param, 648ef10bd49SVenkata Sudheer Kumar Bhavaraju u32 *o_mcp_resp, 649ef10bd49SVenkata Sudheer Kumar Bhavaraju u32 *o_mcp_param) 650ef10bd49SVenkata Sudheer Kumar Bhavaraju { 651ef10bd49SVenkata Sudheer Kumar Bhavaraju return (_qed_mcp_cmd(p_hwfn, p_ptt, cmd, param, 652ef10bd49SVenkata Sudheer Kumar Bhavaraju o_mcp_resp, o_mcp_param, true)); 653ef10bd49SVenkata Sudheer Kumar Bhavaraju } 654ef10bd49SVenkata Sudheer Kumar Bhavaraju 655ef10bd49SVenkata Sudheer Kumar Bhavaraju int qed_mcp_cmd_nosleep(struct qed_hwfn *p_hwfn, 656ef10bd49SVenkata Sudheer Kumar Bhavaraju struct qed_ptt *p_ptt, 657ef10bd49SVenkata Sudheer Kumar Bhavaraju u32 cmd, 658ef10bd49SVenkata Sudheer Kumar Bhavaraju u32 param, 659ef10bd49SVenkata Sudheer Kumar Bhavaraju u32 *o_mcp_resp, 660ef10bd49SVenkata Sudheer Kumar Bhavaraju u32 *o_mcp_param) 661ef10bd49SVenkata Sudheer Kumar Bhavaraju { 662ef10bd49SVenkata Sudheer Kumar Bhavaraju return (_qed_mcp_cmd(p_hwfn, p_ptt, cmd, param, 663ef10bd49SVenkata Sudheer Kumar Bhavaraju o_mcp_resp, o_mcp_param, false)); 664ef10bd49SVenkata Sudheer Kumar Bhavaraju } 665ef10bd49SVenkata Sudheer Kumar Bhavaraju 666bf774d14SYueHaibing static int 667bf774d14SYueHaibing qed_mcp_nvm_wr_cmd(struct qed_hwfn *p_hwfn, 66862e4d438SSudarsana Reddy Kalluru struct qed_ptt *p_ptt, 66962e4d438SSudarsana Reddy Kalluru u32 cmd, 67062e4d438SSudarsana Reddy Kalluru u32 param, 67162e4d438SSudarsana Reddy Kalluru u32 *o_mcp_resp, 67262e4d438SSudarsana Reddy Kalluru u32 *o_mcp_param, u32 i_txn_size, u32 *i_buf) 67362e4d438SSudarsana Reddy Kalluru { 67462e4d438SSudarsana Reddy Kalluru struct qed_mcp_mb_params mb_params; 67562e4d438SSudarsana Reddy Kalluru int rc; 67662e4d438SSudarsana Reddy Kalluru 67762e4d438SSudarsana Reddy Kalluru memset(&mb_params, 0, sizeof(mb_params)); 67862e4d438SSudarsana Reddy Kalluru mb_params.cmd = cmd; 67962e4d438SSudarsana Reddy Kalluru mb_params.param = param; 68062e4d438SSudarsana Reddy Kalluru mb_params.p_data_src = i_buf; 68162e4d438SSudarsana Reddy Kalluru mb_params.data_src_size = (u8)i_txn_size; 68262e4d438SSudarsana Reddy Kalluru rc = qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 68362e4d438SSudarsana Reddy Kalluru if (rc) 68462e4d438SSudarsana Reddy Kalluru return rc; 68562e4d438SSudarsana Reddy Kalluru 68662e4d438SSudarsana Reddy Kalluru *o_mcp_resp = mb_params.mcp_resp; 68762e4d438SSudarsana Reddy Kalluru *o_mcp_param = mb_params.mcp_param; 68862e4d438SSudarsana Reddy Kalluru 6895e7ba042SDenis Bolotin /* nvm_info needs to be updated */ 6905e7ba042SDenis Bolotin p_hwfn->nvm_info.valid = false; 6915e7ba042SDenis Bolotin 69262e4d438SSudarsana Reddy Kalluru return 0; 69362e4d438SSudarsana Reddy Kalluru } 69462e4d438SSudarsana Reddy Kalluru 6954102426fSTomer Tayar int qed_mcp_nvm_rd_cmd(struct qed_hwfn *p_hwfn, 6964102426fSTomer Tayar struct qed_ptt *p_ptt, 6974102426fSTomer Tayar u32 cmd, 6984102426fSTomer Tayar u32 param, 6994102426fSTomer Tayar u32 *o_mcp_resp, 7006c95dd8fSPrabhakar Kushwaha u32 *o_mcp_param, 7016c95dd8fSPrabhakar Kushwaha u32 *o_txn_size, u32 *o_buf, bool b_can_sleep) 7024102426fSTomer Tayar { 7034102426fSTomer Tayar struct qed_mcp_mb_params mb_params; 7042f67af8cSTomer Tayar u8 raw_data[MCP_DRV_NVM_BUF_LEN]; 7054102426fSTomer Tayar int rc; 7064102426fSTomer Tayar 7074102426fSTomer Tayar memset(&mb_params, 0, sizeof(mb_params)); 7084102426fSTomer Tayar mb_params.cmd = cmd; 7094102426fSTomer Tayar mb_params.param = param; 7102f67af8cSTomer Tayar mb_params.p_data_dst = raw_data; 7112f67af8cSTomer Tayar 7122f67af8cSTomer Tayar /* Use the maximal value since the actual one is part of the response */ 7132f67af8cSTomer Tayar mb_params.data_dst_size = MCP_DRV_NVM_BUF_LEN; 7146c95dd8fSPrabhakar Kushwaha if (b_can_sleep) 7156c95dd8fSPrabhakar Kushwaha mb_params.flags = QED_MB_FLAG_CAN_SLEEP; 7162f67af8cSTomer Tayar 7174102426fSTomer Tayar rc = qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 7184102426fSTomer Tayar if (rc) 7194102426fSTomer Tayar return rc; 7204102426fSTomer Tayar 7214102426fSTomer Tayar *o_mcp_resp = mb_params.mcp_resp; 7224102426fSTomer Tayar *o_mcp_param = mb_params.mcp_param; 7234102426fSTomer Tayar 7244102426fSTomer Tayar *o_txn_size = *o_mcp_param; 7252f67af8cSTomer Tayar memcpy(o_buf, raw_data, *o_txn_size); 7264102426fSTomer Tayar 7274102426fSTomer Tayar return 0; 7284102426fSTomer Tayar } 7294102426fSTomer Tayar 7305d24bcf1STomer Tayar static bool 7315d24bcf1STomer Tayar qed_mcp_can_force_load(u8 drv_role, 7325d24bcf1STomer Tayar u8 exist_drv_role, 7335d24bcf1STomer Tayar enum qed_override_force_load override_force_load) 734fe56b9e6SYuval Mintz { 7355d24bcf1STomer Tayar bool can_force_load = false; 7365d24bcf1STomer Tayar 7375d24bcf1STomer Tayar switch (override_force_load) { 7385d24bcf1STomer Tayar case QED_OVERRIDE_FORCE_LOAD_ALWAYS: 7395d24bcf1STomer Tayar can_force_load = true; 7405d24bcf1STomer Tayar break; 7415d24bcf1STomer Tayar case QED_OVERRIDE_FORCE_LOAD_NEVER: 7425d24bcf1STomer Tayar can_force_load = false; 7435d24bcf1STomer Tayar break; 7445d24bcf1STomer Tayar default: 7455d24bcf1STomer Tayar can_force_load = (drv_role == DRV_ROLE_OS && 7465d24bcf1STomer Tayar exist_drv_role == DRV_ROLE_PREBOOT) || 7475d24bcf1STomer Tayar (drv_role == DRV_ROLE_KDUMP && 7485d24bcf1STomer Tayar exist_drv_role == DRV_ROLE_OS); 7495d24bcf1STomer Tayar break; 7505d24bcf1STomer Tayar } 7515d24bcf1STomer Tayar 7525d24bcf1STomer Tayar return can_force_load; 7535d24bcf1STomer Tayar } 7545d24bcf1STomer Tayar 7555d24bcf1STomer Tayar static int qed_mcp_cancel_load_req(struct qed_hwfn *p_hwfn, 7565d24bcf1STomer Tayar struct qed_ptt *p_ptt) 7575d24bcf1STomer Tayar { 7585d24bcf1STomer Tayar u32 resp = 0, param = 0; 759fe56b9e6SYuval Mintz int rc; 760fe56b9e6SYuval Mintz 7615d24bcf1STomer Tayar rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_CANCEL_LOAD_REQ, 0, 7625d24bcf1STomer Tayar &resp, ¶m); 7635d24bcf1STomer Tayar if (rc) 7645d24bcf1STomer Tayar DP_NOTICE(p_hwfn, 7655d24bcf1STomer Tayar "Failed to send cancel load request, rc = %d\n", rc); 766fe56b9e6SYuval Mintz 767fe56b9e6SYuval Mintz return rc; 768fe56b9e6SYuval Mintz } 769fe56b9e6SYuval Mintz 7705d24bcf1STomer Tayar #define CONFIG_QEDE_BITMAP_IDX BIT(0) 7715d24bcf1STomer Tayar #define CONFIG_QED_SRIOV_BITMAP_IDX BIT(1) 7725d24bcf1STomer Tayar #define CONFIG_QEDR_BITMAP_IDX BIT(2) 7735d24bcf1STomer Tayar #define CONFIG_QEDF_BITMAP_IDX BIT(4) 7745d24bcf1STomer Tayar #define CONFIG_QEDI_BITMAP_IDX BIT(5) 7755d24bcf1STomer Tayar #define CONFIG_QED_LL2_BITMAP_IDX BIT(6) 7765529bad9STomer Tayar 7775d24bcf1STomer Tayar static u32 qed_get_config_bitmap(void) 7785d24bcf1STomer Tayar { 7795d24bcf1STomer Tayar u32 config_bitmap = 0x0; 7805d24bcf1STomer Tayar 7815d24bcf1STomer Tayar if (IS_ENABLED(CONFIG_QEDE)) 7825d24bcf1STomer Tayar config_bitmap |= CONFIG_QEDE_BITMAP_IDX; 7835d24bcf1STomer Tayar 7845d24bcf1STomer Tayar if (IS_ENABLED(CONFIG_QED_SRIOV)) 7855d24bcf1STomer Tayar config_bitmap |= CONFIG_QED_SRIOV_BITMAP_IDX; 7865d24bcf1STomer Tayar 7875d24bcf1STomer Tayar if (IS_ENABLED(CONFIG_QED_RDMA)) 7885d24bcf1STomer Tayar config_bitmap |= CONFIG_QEDR_BITMAP_IDX; 7895d24bcf1STomer Tayar 7905d24bcf1STomer Tayar if (IS_ENABLED(CONFIG_QED_FCOE)) 7915d24bcf1STomer Tayar config_bitmap |= CONFIG_QEDF_BITMAP_IDX; 7925d24bcf1STomer Tayar 7935d24bcf1STomer Tayar if (IS_ENABLED(CONFIG_QED_ISCSI)) 7945d24bcf1STomer Tayar config_bitmap |= CONFIG_QEDI_BITMAP_IDX; 7955d24bcf1STomer Tayar 7965d24bcf1STomer Tayar if (IS_ENABLED(CONFIG_QED_LL2)) 7975d24bcf1STomer Tayar config_bitmap |= CONFIG_QED_LL2_BITMAP_IDX; 7985d24bcf1STomer Tayar 7995d24bcf1STomer Tayar return config_bitmap; 8005d24bcf1STomer Tayar } 8015d24bcf1STomer Tayar 8025d24bcf1STomer Tayar struct qed_load_req_in_params { 8035d24bcf1STomer Tayar u8 hsi_ver; 8045d24bcf1STomer Tayar #define QED_LOAD_REQ_HSI_VER_DEFAULT 0 8055d24bcf1STomer Tayar #define QED_LOAD_REQ_HSI_VER_1 1 8065d24bcf1STomer Tayar u32 drv_ver_0; 8075d24bcf1STomer Tayar u32 drv_ver_1; 8085d24bcf1STomer Tayar u32 fw_ver; 8095d24bcf1STomer Tayar u8 drv_role; 8105d24bcf1STomer Tayar u8 timeout_val; 8115d24bcf1STomer Tayar u8 force_cmd; 8125d24bcf1STomer Tayar bool avoid_eng_reset; 8135d24bcf1STomer Tayar }; 8145d24bcf1STomer Tayar 8155d24bcf1STomer Tayar struct qed_load_req_out_params { 8165d24bcf1STomer Tayar u32 load_code; 8175d24bcf1STomer Tayar u32 exist_drv_ver_0; 8185d24bcf1STomer Tayar u32 exist_drv_ver_1; 8195d24bcf1STomer Tayar u32 exist_fw_ver; 8205d24bcf1STomer Tayar u8 exist_drv_role; 8215d24bcf1STomer Tayar u8 mfw_hsi_ver; 8225d24bcf1STomer Tayar bool drv_exists; 8235d24bcf1STomer Tayar }; 8245d24bcf1STomer Tayar 8255d24bcf1STomer Tayar static int 8265d24bcf1STomer Tayar __qed_mcp_load_req(struct qed_hwfn *p_hwfn, 8275d24bcf1STomer Tayar struct qed_ptt *p_ptt, 8285d24bcf1STomer Tayar struct qed_load_req_in_params *p_in_params, 8295d24bcf1STomer Tayar struct qed_load_req_out_params *p_out_params) 8305d24bcf1STomer Tayar { 8315d24bcf1STomer Tayar struct qed_mcp_mb_params mb_params; 8325d24bcf1STomer Tayar struct load_req_stc load_req; 8335d24bcf1STomer Tayar struct load_rsp_stc load_rsp; 8345d24bcf1STomer Tayar u32 hsi_ver; 8355d24bcf1STomer Tayar int rc; 8365d24bcf1STomer Tayar 8375d24bcf1STomer Tayar memset(&load_req, 0, sizeof(load_req)); 8385d24bcf1STomer Tayar load_req.drv_ver_0 = p_in_params->drv_ver_0; 8395d24bcf1STomer Tayar load_req.drv_ver_1 = p_in_params->drv_ver_1; 8405d24bcf1STomer Tayar load_req.fw_ver = p_in_params->fw_ver; 8415d24bcf1STomer Tayar QED_MFW_SET_FIELD(load_req.misc0, LOAD_REQ_ROLE, p_in_params->drv_role); 8425d24bcf1STomer Tayar QED_MFW_SET_FIELD(load_req.misc0, LOAD_REQ_LOCK_TO, 8435d24bcf1STomer Tayar p_in_params->timeout_val); 8445d24bcf1STomer Tayar QED_MFW_SET_FIELD(load_req.misc0, LOAD_REQ_FORCE, 8455d24bcf1STomer Tayar p_in_params->force_cmd); 8465d24bcf1STomer Tayar QED_MFW_SET_FIELD(load_req.misc0, LOAD_REQ_FLAGS0, 8475d24bcf1STomer Tayar p_in_params->avoid_eng_reset); 8485d24bcf1STomer Tayar 8495d24bcf1STomer Tayar hsi_ver = (p_in_params->hsi_ver == QED_LOAD_REQ_HSI_VER_DEFAULT) ? 8505d24bcf1STomer Tayar DRV_ID_MCP_HSI_VER_CURRENT : 8515d24bcf1STomer Tayar (p_in_params->hsi_ver << DRV_ID_MCP_HSI_VER_SHIFT); 8525d24bcf1STomer Tayar 8535d24bcf1STomer Tayar memset(&mb_params, 0, sizeof(mb_params)); 8545d24bcf1STomer Tayar mb_params.cmd = DRV_MSG_CODE_LOAD_REQ; 8555d24bcf1STomer Tayar mb_params.param = PDA_COMP | hsi_ver | p_hwfn->cdev->drv_type; 8565d24bcf1STomer Tayar mb_params.p_data_src = &load_req; 8575d24bcf1STomer Tayar mb_params.data_src_size = sizeof(load_req); 8585d24bcf1STomer Tayar mb_params.p_data_dst = &load_rsp; 8595d24bcf1STomer Tayar mb_params.data_dst_size = sizeof(load_rsp); 860b310974eSTomer Tayar mb_params.flags = QED_MB_FLAG_CAN_SLEEP | QED_MB_FLAG_AVOID_BLOCK; 8615d24bcf1STomer Tayar 8625d24bcf1STomer Tayar DP_VERBOSE(p_hwfn, QED_MSG_SP, 8635d24bcf1STomer Tayar "Load Request: param 0x%08x [init_hw %d, drv_type %d, hsi_ver %d, pda 0x%04x]\n", 8645d24bcf1STomer Tayar mb_params.param, 8655d24bcf1STomer Tayar QED_MFW_GET_FIELD(mb_params.param, DRV_ID_DRV_INIT_HW), 8665d24bcf1STomer Tayar QED_MFW_GET_FIELD(mb_params.param, DRV_ID_DRV_TYPE), 8675d24bcf1STomer Tayar QED_MFW_GET_FIELD(mb_params.param, DRV_ID_MCP_HSI_VER), 8685d24bcf1STomer Tayar QED_MFW_GET_FIELD(mb_params.param, DRV_ID_PDA_COMP_VER)); 8695d24bcf1STomer Tayar 8705d24bcf1STomer Tayar if (p_in_params->hsi_ver != QED_LOAD_REQ_HSI_VER_1) { 8715d24bcf1STomer Tayar DP_VERBOSE(p_hwfn, QED_MSG_SP, 8725d24bcf1STomer Tayar "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", 8735d24bcf1STomer Tayar load_req.drv_ver_0, 8745d24bcf1STomer Tayar load_req.drv_ver_1, 8755d24bcf1STomer Tayar load_req.fw_ver, 8765d24bcf1STomer Tayar load_req.misc0, 8775d24bcf1STomer Tayar QED_MFW_GET_FIELD(load_req.misc0, LOAD_REQ_ROLE), 8785d24bcf1STomer Tayar QED_MFW_GET_FIELD(load_req.misc0, 8795d24bcf1STomer Tayar LOAD_REQ_LOCK_TO), 8805d24bcf1STomer Tayar QED_MFW_GET_FIELD(load_req.misc0, LOAD_REQ_FORCE), 8815d24bcf1STomer Tayar QED_MFW_GET_FIELD(load_req.misc0, LOAD_REQ_FLAGS0)); 8825d24bcf1STomer Tayar } 8835d24bcf1STomer Tayar 8845d24bcf1STomer Tayar rc = qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 8855d24bcf1STomer Tayar if (rc) { 8865d24bcf1STomer Tayar DP_NOTICE(p_hwfn, "Failed to send load request, rc = %d\n", rc); 8875d24bcf1STomer Tayar return rc; 8885d24bcf1STomer Tayar } 8895d24bcf1STomer Tayar 8905d24bcf1STomer Tayar DP_VERBOSE(p_hwfn, QED_MSG_SP, 8915d24bcf1STomer Tayar "Load Response: resp 0x%08x\n", mb_params.mcp_resp); 8925d24bcf1STomer Tayar p_out_params->load_code = mb_params.mcp_resp; 8935d24bcf1STomer Tayar 8945d24bcf1STomer Tayar if (p_in_params->hsi_ver != QED_LOAD_REQ_HSI_VER_1 && 8955d24bcf1STomer Tayar p_out_params->load_code != FW_MSG_CODE_DRV_LOAD_REFUSED_HSI_1) { 8965d24bcf1STomer Tayar DP_VERBOSE(p_hwfn, 8975d24bcf1STomer Tayar QED_MSG_SP, 8985d24bcf1STomer Tayar "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", 8995d24bcf1STomer Tayar load_rsp.drv_ver_0, 9005d24bcf1STomer Tayar load_rsp.drv_ver_1, 9015d24bcf1STomer Tayar load_rsp.fw_ver, 9025d24bcf1STomer Tayar load_rsp.misc0, 9035d24bcf1STomer Tayar QED_MFW_GET_FIELD(load_rsp.misc0, LOAD_RSP_ROLE), 9045d24bcf1STomer Tayar QED_MFW_GET_FIELD(load_rsp.misc0, LOAD_RSP_HSI), 9055d24bcf1STomer Tayar QED_MFW_GET_FIELD(load_rsp.misc0, LOAD_RSP_FLAGS0)); 9065d24bcf1STomer Tayar 9075d24bcf1STomer Tayar p_out_params->exist_drv_ver_0 = load_rsp.drv_ver_0; 9085d24bcf1STomer Tayar p_out_params->exist_drv_ver_1 = load_rsp.drv_ver_1; 9095d24bcf1STomer Tayar p_out_params->exist_fw_ver = load_rsp.fw_ver; 9105d24bcf1STomer Tayar p_out_params->exist_drv_role = 9115d24bcf1STomer Tayar QED_MFW_GET_FIELD(load_rsp.misc0, LOAD_RSP_ROLE); 9125d24bcf1STomer Tayar p_out_params->mfw_hsi_ver = 9135d24bcf1STomer Tayar QED_MFW_GET_FIELD(load_rsp.misc0, LOAD_RSP_HSI); 9145d24bcf1STomer Tayar p_out_params->drv_exists = 9155d24bcf1STomer Tayar QED_MFW_GET_FIELD(load_rsp.misc0, LOAD_RSP_FLAGS0) & 9165d24bcf1STomer Tayar LOAD_RSP_FLAGS0_DRV_EXISTS; 9175d24bcf1STomer Tayar } 9185d24bcf1STomer Tayar 9195d24bcf1STomer Tayar return 0; 9205d24bcf1STomer Tayar } 9215d24bcf1STomer Tayar 9225d24bcf1STomer Tayar static int eocre_get_mfw_drv_role(struct qed_hwfn *p_hwfn, 9235d24bcf1STomer Tayar enum qed_drv_role drv_role, 9245d24bcf1STomer Tayar u8 *p_mfw_drv_role) 9255d24bcf1STomer Tayar { 9265d24bcf1STomer Tayar switch (drv_role) { 9275d24bcf1STomer Tayar case QED_DRV_ROLE_OS: 9285d24bcf1STomer Tayar *p_mfw_drv_role = DRV_ROLE_OS; 9295d24bcf1STomer Tayar break; 9305d24bcf1STomer Tayar case QED_DRV_ROLE_KDUMP: 9315d24bcf1STomer Tayar *p_mfw_drv_role = DRV_ROLE_KDUMP; 9325d24bcf1STomer Tayar break; 9335d24bcf1STomer Tayar default: 9345d24bcf1STomer Tayar DP_ERR(p_hwfn, "Unexpected driver role %d\n", drv_role); 9355d24bcf1STomer Tayar return -EINVAL; 9365d24bcf1STomer Tayar } 9375d24bcf1STomer Tayar 9385d24bcf1STomer Tayar return 0; 9395d24bcf1STomer Tayar } 9405d24bcf1STomer Tayar 9415d24bcf1STomer Tayar enum qed_load_req_force { 9425d24bcf1STomer Tayar QED_LOAD_REQ_FORCE_NONE, 9435d24bcf1STomer Tayar QED_LOAD_REQ_FORCE_PF, 9445d24bcf1STomer Tayar QED_LOAD_REQ_FORCE_ALL, 9455d24bcf1STomer Tayar }; 9465d24bcf1STomer Tayar 9475d24bcf1STomer Tayar static void qed_get_mfw_force_cmd(struct qed_hwfn *p_hwfn, 9485d24bcf1STomer Tayar enum qed_load_req_force force_cmd, 9495d24bcf1STomer Tayar u8 *p_mfw_force_cmd) 9505d24bcf1STomer Tayar { 9515d24bcf1STomer Tayar switch (force_cmd) { 9525d24bcf1STomer Tayar case QED_LOAD_REQ_FORCE_NONE: 9535d24bcf1STomer Tayar *p_mfw_force_cmd = LOAD_REQ_FORCE_NONE; 9545d24bcf1STomer Tayar break; 9555d24bcf1STomer Tayar case QED_LOAD_REQ_FORCE_PF: 9565d24bcf1STomer Tayar *p_mfw_force_cmd = LOAD_REQ_FORCE_PF; 9575d24bcf1STomer Tayar break; 9585d24bcf1STomer Tayar case QED_LOAD_REQ_FORCE_ALL: 9595d24bcf1STomer Tayar *p_mfw_force_cmd = LOAD_REQ_FORCE_ALL; 9605d24bcf1STomer Tayar break; 9615d24bcf1STomer Tayar } 9625d24bcf1STomer Tayar } 9635d24bcf1STomer Tayar 9645d24bcf1STomer Tayar int qed_mcp_load_req(struct qed_hwfn *p_hwfn, 9655d24bcf1STomer Tayar struct qed_ptt *p_ptt, 9665d24bcf1STomer Tayar struct qed_load_req_params *p_params) 9675d24bcf1STomer Tayar { 9685d24bcf1STomer Tayar struct qed_load_req_out_params out_params; 9695d24bcf1STomer Tayar struct qed_load_req_in_params in_params; 9705d24bcf1STomer Tayar u8 mfw_drv_role, mfw_force_cmd; 9715d24bcf1STomer Tayar int rc; 9725d24bcf1STomer Tayar 9735d24bcf1STomer Tayar memset(&in_params, 0, sizeof(in_params)); 9745d24bcf1STomer Tayar in_params.hsi_ver = QED_LOAD_REQ_HSI_VER_DEFAULT; 9755d24bcf1STomer Tayar in_params.drv_ver_1 = qed_get_config_bitmap(); 9765d24bcf1STomer Tayar in_params.fw_ver = STORM_FW_VERSION; 9775d24bcf1STomer Tayar rc = eocre_get_mfw_drv_role(p_hwfn, p_params->drv_role, &mfw_drv_role); 9785d24bcf1STomer Tayar if (rc) 9795d24bcf1STomer Tayar return rc; 9805d24bcf1STomer Tayar 9815d24bcf1STomer Tayar in_params.drv_role = mfw_drv_role; 9825d24bcf1STomer Tayar in_params.timeout_val = p_params->timeout_val; 9835d24bcf1STomer Tayar qed_get_mfw_force_cmd(p_hwfn, 9845d24bcf1STomer Tayar QED_LOAD_REQ_FORCE_NONE, &mfw_force_cmd); 9855d24bcf1STomer Tayar 9865d24bcf1STomer Tayar in_params.force_cmd = mfw_force_cmd; 9875d24bcf1STomer Tayar in_params.avoid_eng_reset = p_params->avoid_eng_reset; 9885d24bcf1STomer Tayar 9895d24bcf1STomer Tayar memset(&out_params, 0, sizeof(out_params)); 9905d24bcf1STomer Tayar rc = __qed_mcp_load_req(p_hwfn, p_ptt, &in_params, &out_params); 9915d24bcf1STomer Tayar if (rc) 9925d24bcf1STomer Tayar return rc; 9935d24bcf1STomer Tayar 9945d24bcf1STomer Tayar /* First handle cases where another load request should/might be sent: 9955d24bcf1STomer Tayar * - MFW expects the old interface [HSI version = 1] 9965d24bcf1STomer Tayar * - MFW responds that a force load request is required 997fe56b9e6SYuval Mintz */ 9985d24bcf1STomer Tayar if (out_params.load_code == FW_MSG_CODE_DRV_LOAD_REFUSED_HSI_1) { 9995d24bcf1STomer Tayar DP_INFO(p_hwfn, 10005d24bcf1STomer Tayar "MFW refused a load request due to HSI > 1. Resending with HSI = 1\n"); 10015d24bcf1STomer Tayar 10025d24bcf1STomer Tayar in_params.hsi_ver = QED_LOAD_REQ_HSI_VER_1; 10035d24bcf1STomer Tayar memset(&out_params, 0, sizeof(out_params)); 10045d24bcf1STomer Tayar rc = __qed_mcp_load_req(p_hwfn, p_ptt, &in_params, &out_params); 10055d24bcf1STomer Tayar if (rc) 10065d24bcf1STomer Tayar return rc; 10075d24bcf1STomer Tayar } else if (out_params.load_code == 10085d24bcf1STomer Tayar FW_MSG_CODE_DRV_LOAD_REFUSED_REQUIRES_FORCE) { 10095d24bcf1STomer Tayar if (qed_mcp_can_force_load(in_params.drv_role, 10105d24bcf1STomer Tayar out_params.exist_drv_role, 10115d24bcf1STomer Tayar p_params->override_force_load)) { 10125d24bcf1STomer Tayar DP_INFO(p_hwfn, 10135d24bcf1STomer Tayar "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", 10145d24bcf1STomer Tayar in_params.drv_role, in_params.fw_ver, 10155d24bcf1STomer Tayar in_params.drv_ver_0, in_params.drv_ver_1, 10165d24bcf1STomer Tayar out_params.exist_drv_role, 10175d24bcf1STomer Tayar out_params.exist_fw_ver, 10185d24bcf1STomer Tayar out_params.exist_drv_ver_0, 10195d24bcf1STomer Tayar out_params.exist_drv_ver_1); 10205d24bcf1STomer Tayar 10215d24bcf1STomer Tayar qed_get_mfw_force_cmd(p_hwfn, 10225d24bcf1STomer Tayar QED_LOAD_REQ_FORCE_ALL, 10235d24bcf1STomer Tayar &mfw_force_cmd); 10245d24bcf1STomer Tayar 10255d24bcf1STomer Tayar in_params.force_cmd = mfw_force_cmd; 10265d24bcf1STomer Tayar memset(&out_params, 0, sizeof(out_params)); 10275d24bcf1STomer Tayar rc = __qed_mcp_load_req(p_hwfn, p_ptt, &in_params, 10285d24bcf1STomer Tayar &out_params); 10295d24bcf1STomer Tayar if (rc) 10305d24bcf1STomer Tayar return rc; 10315d24bcf1STomer Tayar } else { 10325d24bcf1STomer Tayar DP_NOTICE(p_hwfn, 10335d24bcf1STomer Tayar "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", 10345d24bcf1STomer Tayar in_params.drv_role, in_params.fw_ver, 10355d24bcf1STomer Tayar in_params.drv_ver_0, in_params.drv_ver_1, 10365d24bcf1STomer Tayar out_params.exist_drv_role, 10375d24bcf1STomer Tayar out_params.exist_fw_ver, 10385d24bcf1STomer Tayar out_params.exist_drv_ver_0, 10395d24bcf1STomer Tayar out_params.exist_drv_ver_1); 10405d24bcf1STomer Tayar DP_NOTICE(p_hwfn, 10415d24bcf1STomer Tayar "Avoid sending a force load request to prevent disruption of active PFs\n"); 10425d24bcf1STomer Tayar 10435d24bcf1STomer Tayar qed_mcp_cancel_load_req(p_hwfn, p_ptt); 1044fe56b9e6SYuval Mintz return -EBUSY; 1045fe56b9e6SYuval Mintz } 10465d24bcf1STomer Tayar } 10475d24bcf1STomer Tayar 10485d24bcf1STomer Tayar /* Now handle the other types of responses. 10495d24bcf1STomer Tayar * The "REFUSED_HSI_1" and "REFUSED_REQUIRES_FORCE" responses are not 10505d24bcf1STomer Tayar * expected here after the additional revised load requests were sent. 10515d24bcf1STomer Tayar */ 10525d24bcf1STomer Tayar switch (out_params.load_code) { 10535d24bcf1STomer Tayar case FW_MSG_CODE_DRV_LOAD_ENGINE: 10545d24bcf1STomer Tayar case FW_MSG_CODE_DRV_LOAD_PORT: 10555d24bcf1STomer Tayar case FW_MSG_CODE_DRV_LOAD_FUNCTION: 10565d24bcf1STomer Tayar if (out_params.mfw_hsi_ver != QED_LOAD_REQ_HSI_VER_1 && 10575d24bcf1STomer Tayar out_params.drv_exists) { 10585d24bcf1STomer Tayar /* The role and fw/driver version match, but the PF is 10595d24bcf1STomer Tayar * already loaded and has not been unloaded gracefully. 10605d24bcf1STomer Tayar */ 10615d24bcf1STomer Tayar DP_NOTICE(p_hwfn, 10625d24bcf1STomer Tayar "PF is already loaded\n"); 10635d24bcf1STomer Tayar return -EINVAL; 10645d24bcf1STomer Tayar } 10655d24bcf1STomer Tayar break; 10665d24bcf1STomer Tayar default: 10675d24bcf1STomer Tayar DP_NOTICE(p_hwfn, 10685d24bcf1STomer Tayar "Unexpected refusal to load request [resp 0x%08x]. Aborting.\n", 10695d24bcf1STomer Tayar out_params.load_code); 10705d24bcf1STomer Tayar return -EBUSY; 10715d24bcf1STomer Tayar } 10725d24bcf1STomer Tayar 10735d24bcf1STomer Tayar p_params->load_code = out_params.load_code; 1074fe56b9e6SYuval Mintz 1075fe56b9e6SYuval Mintz return 0; 1076fe56b9e6SYuval Mintz } 1077fe56b9e6SYuval Mintz 1078666db486STomer Tayar int qed_mcp_load_done(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 1079666db486STomer Tayar { 1080666db486STomer Tayar u32 resp = 0, param = 0; 1081666db486STomer Tayar int rc; 1082666db486STomer Tayar 1083666db486STomer Tayar rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_LOAD_DONE, 0, &resp, 1084666db486STomer Tayar ¶m); 1085666db486STomer Tayar if (rc) { 1086666db486STomer Tayar DP_NOTICE(p_hwfn, 1087666db486STomer Tayar "Failed to send a LOAD_DONE command, rc = %d\n", rc); 1088666db486STomer Tayar return rc; 1089666db486STomer Tayar } 1090666db486STomer Tayar 1091666db486STomer Tayar /* Check if there is a DID mismatch between nvm-cfg/efuse */ 1092666db486STomer Tayar if (param & FW_MB_PARAM_LOAD_DONE_DID_EFUSE_ERROR) 1093666db486STomer Tayar DP_NOTICE(p_hwfn, 1094666db486STomer Tayar "warning: device configuration is not supported on this board type. The device may not function as expected.\n"); 1095666db486STomer Tayar 1096666db486STomer Tayar return 0; 1097666db486STomer Tayar } 1098666db486STomer Tayar 1099*ca2d5f1fSVenkata Sudheer Kumar Bhavaraju #define MFW_COMPLETION_MAX_ITER 5000 1100*ca2d5f1fSVenkata Sudheer Kumar Bhavaraju #define MFW_COMPLETION_INTERVAL_MS 1 1101*ca2d5f1fSVenkata Sudheer Kumar Bhavaraju 11021226337aSTomer Tayar int qed_mcp_unload_req(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 11031226337aSTomer Tayar { 1104eaa50fc5STomer Tayar struct qed_mcp_mb_params mb_params; 1105*ca2d5f1fSVenkata Sudheer Kumar Bhavaraju u32 cnt = MFW_COMPLETION_MAX_ITER; 1106eaa50fc5STomer Tayar u32 wol_param; 1107*ca2d5f1fSVenkata Sudheer Kumar Bhavaraju int rc; 11081226337aSTomer Tayar 11091226337aSTomer Tayar switch (p_hwfn->cdev->wol_config) { 11101226337aSTomer Tayar case QED_OV_WOL_DISABLED: 11111226337aSTomer Tayar wol_param = DRV_MB_PARAM_UNLOAD_WOL_DISABLED; 11121226337aSTomer Tayar break; 11131226337aSTomer Tayar case QED_OV_WOL_ENABLED: 11141226337aSTomer Tayar wol_param = DRV_MB_PARAM_UNLOAD_WOL_ENABLED; 11151226337aSTomer Tayar break; 11161226337aSTomer Tayar default: 11171226337aSTomer Tayar DP_NOTICE(p_hwfn, 11181226337aSTomer Tayar "Unknown WoL configuration %02x\n", 11191226337aSTomer Tayar p_hwfn->cdev->wol_config); 1120df561f66SGustavo A. R. Silva fallthrough; 11211226337aSTomer Tayar case QED_OV_WOL_DEFAULT: 11221226337aSTomer Tayar wol_param = DRV_MB_PARAM_UNLOAD_WOL_MCP; 11231226337aSTomer Tayar } 11241226337aSTomer Tayar 1125eaa50fc5STomer Tayar memset(&mb_params, 0, sizeof(mb_params)); 1126eaa50fc5STomer Tayar mb_params.cmd = DRV_MSG_CODE_UNLOAD_REQ; 1127eaa50fc5STomer Tayar mb_params.param = wol_param; 1128b310974eSTomer Tayar mb_params.flags = QED_MB_FLAG_CAN_SLEEP | QED_MB_FLAG_AVOID_BLOCK; 1129eaa50fc5STomer Tayar 1130*ca2d5f1fSVenkata Sudheer Kumar Bhavaraju spin_lock_bh(&p_hwfn->mcp_info->unload_lock); 1131*ca2d5f1fSVenkata Sudheer Kumar Bhavaraju set_bit(QED_MCP_BYPASS_PROC_BIT, 1132*ca2d5f1fSVenkata Sudheer Kumar Bhavaraju &p_hwfn->mcp_info->mcp_handling_status); 1133*ca2d5f1fSVenkata Sudheer Kumar Bhavaraju spin_unlock_bh(&p_hwfn->mcp_info->unload_lock); 1134*ca2d5f1fSVenkata Sudheer Kumar Bhavaraju 1135*ca2d5f1fSVenkata Sudheer Kumar Bhavaraju rc = qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 1136*ca2d5f1fSVenkata Sudheer Kumar Bhavaraju 1137*ca2d5f1fSVenkata Sudheer Kumar Bhavaraju while (test_bit(QED_MCP_IN_PROCESSING_BIT, 1138*ca2d5f1fSVenkata Sudheer Kumar Bhavaraju &p_hwfn->mcp_info->mcp_handling_status) && --cnt) 1139*ca2d5f1fSVenkata Sudheer Kumar Bhavaraju msleep(MFW_COMPLETION_INTERVAL_MS); 1140*ca2d5f1fSVenkata Sudheer Kumar Bhavaraju 1141*ca2d5f1fSVenkata Sudheer Kumar Bhavaraju if (!cnt) 1142*ca2d5f1fSVenkata Sudheer Kumar Bhavaraju DP_NOTICE(p_hwfn, 1143*ca2d5f1fSVenkata Sudheer Kumar Bhavaraju "Failed to wait MFW event completion after %d msec\n", 1144*ca2d5f1fSVenkata Sudheer Kumar Bhavaraju MFW_COMPLETION_MAX_ITER * MFW_COMPLETION_INTERVAL_MS); 1145*ca2d5f1fSVenkata Sudheer Kumar Bhavaraju 1146*ca2d5f1fSVenkata Sudheer Kumar Bhavaraju return rc; 11471226337aSTomer Tayar } 11481226337aSTomer Tayar 11491226337aSTomer Tayar int qed_mcp_unload_done(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 11501226337aSTomer Tayar { 11511226337aSTomer Tayar struct qed_mcp_mb_params mb_params; 11521226337aSTomer Tayar struct mcp_mac wol_mac; 11531226337aSTomer Tayar 11541226337aSTomer Tayar memset(&mb_params, 0, sizeof(mb_params)); 11551226337aSTomer Tayar mb_params.cmd = DRV_MSG_CODE_UNLOAD_DONE; 11561226337aSTomer Tayar 11571226337aSTomer Tayar /* Set the primary MAC if WoL is enabled */ 11581226337aSTomer Tayar if (p_hwfn->cdev->wol_config == QED_OV_WOL_ENABLED) { 11591226337aSTomer Tayar u8 *p_mac = p_hwfn->cdev->wol_mac; 11601226337aSTomer Tayar 11611226337aSTomer Tayar memset(&wol_mac, 0, sizeof(wol_mac)); 11621226337aSTomer Tayar wol_mac.mac_upper = p_mac[0] << 8 | p_mac[1]; 11631226337aSTomer Tayar wol_mac.mac_lower = p_mac[2] << 24 | p_mac[3] << 16 | 11641226337aSTomer Tayar p_mac[4] << 8 | p_mac[5]; 11651226337aSTomer Tayar 11661226337aSTomer Tayar DP_VERBOSE(p_hwfn, 11671226337aSTomer Tayar (QED_MSG_SP | NETIF_MSG_IFDOWN), 11681226337aSTomer Tayar "Setting WoL MAC: %pM --> [%08x,%08x]\n", 11691226337aSTomer Tayar p_mac, wol_mac.mac_upper, wol_mac.mac_lower); 11701226337aSTomer Tayar 11711226337aSTomer Tayar mb_params.p_data_src = &wol_mac; 11721226337aSTomer Tayar mb_params.data_src_size = sizeof(wol_mac); 11731226337aSTomer Tayar } 11741226337aSTomer Tayar 11751226337aSTomer Tayar return qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 11761226337aSTomer Tayar } 11771226337aSTomer Tayar 11780b55e27dSYuval Mintz static void qed_mcp_handle_vf_flr(struct qed_hwfn *p_hwfn, 11790b55e27dSYuval Mintz struct qed_ptt *p_ptt) 11800b55e27dSYuval Mintz { 11810b55e27dSYuval Mintz u32 addr = SECTION_OFFSIZE_ADDR(p_hwfn->mcp_info->public_base, 11820b55e27dSYuval Mintz PUBLIC_PATH); 11830b55e27dSYuval Mintz u32 mfw_path_offsize = qed_rd(p_hwfn, p_ptt, addr); 11840b55e27dSYuval Mintz u32 path_addr = SECTION_ADDR(mfw_path_offsize, 11850b55e27dSYuval Mintz QED_PATH_ID(p_hwfn)); 11860b55e27dSYuval Mintz u32 disabled_vfs[VF_MAX_STATIC / 32]; 11870b55e27dSYuval Mintz int i; 11880b55e27dSYuval Mintz 11890b55e27dSYuval Mintz DP_VERBOSE(p_hwfn, 11900b55e27dSYuval Mintz QED_MSG_SP, 11910b55e27dSYuval Mintz "Reading Disabled VF information from [offset %08x], path_addr %08x\n", 11920b55e27dSYuval Mintz mfw_path_offsize, path_addr); 11930b55e27dSYuval Mintz 11940b55e27dSYuval Mintz for (i = 0; i < (VF_MAX_STATIC / 32); i++) { 11950b55e27dSYuval Mintz disabled_vfs[i] = qed_rd(p_hwfn, p_ptt, 11960b55e27dSYuval Mintz path_addr + 11970b55e27dSYuval Mintz offsetof(struct public_path, 11980b55e27dSYuval Mintz mcp_vf_disabled) + 11990b55e27dSYuval Mintz sizeof(u32) * i); 12000b55e27dSYuval Mintz DP_VERBOSE(p_hwfn, (QED_MSG_SP | QED_MSG_IOV), 12010b55e27dSYuval Mintz "FLR-ed VFs [%08x,...,%08x] - %08x\n", 12020b55e27dSYuval Mintz i * 32, (i + 1) * 32 - 1, disabled_vfs[i]); 12030b55e27dSYuval Mintz } 12040b55e27dSYuval Mintz 12050b55e27dSYuval Mintz if (qed_iov_mark_vf_flr(p_hwfn, disabled_vfs)) 12060b55e27dSYuval Mintz qed_schedule_iov(p_hwfn, QED_IOV_WQ_FLR_FLAG); 12070b55e27dSYuval Mintz } 12080b55e27dSYuval Mintz 12090b55e27dSYuval Mintz int qed_mcp_ack_vf_flr(struct qed_hwfn *p_hwfn, 12100b55e27dSYuval Mintz struct qed_ptt *p_ptt, u32 *vfs_to_ack) 12110b55e27dSYuval Mintz { 12120b55e27dSYuval Mintz u32 addr = SECTION_OFFSIZE_ADDR(p_hwfn->mcp_info->public_base, 12130b55e27dSYuval Mintz PUBLIC_FUNC); 12140b55e27dSYuval Mintz u32 mfw_func_offsize = qed_rd(p_hwfn, p_ptt, addr); 12150b55e27dSYuval Mintz u32 func_addr = SECTION_ADDR(mfw_func_offsize, 12160b55e27dSYuval Mintz MCP_PF_ID(p_hwfn)); 12170b55e27dSYuval Mintz struct qed_mcp_mb_params mb_params; 12180b55e27dSYuval Mintz int rc; 12190b55e27dSYuval Mintz int i; 12200b55e27dSYuval Mintz 12210b55e27dSYuval Mintz for (i = 0; i < (VF_MAX_STATIC / 32); i++) 12220b55e27dSYuval Mintz DP_VERBOSE(p_hwfn, (QED_MSG_SP | QED_MSG_IOV), 12230b55e27dSYuval Mintz "Acking VFs [%08x,...,%08x] - %08x\n", 12240b55e27dSYuval Mintz i * 32, (i + 1) * 32 - 1, vfs_to_ack[i]); 12250b55e27dSYuval Mintz 12260b55e27dSYuval Mintz memset(&mb_params, 0, sizeof(mb_params)); 12270b55e27dSYuval Mintz mb_params.cmd = DRV_MSG_CODE_VF_DISABLED_DONE; 12282f67af8cSTomer Tayar mb_params.p_data_src = vfs_to_ack; 12292f67af8cSTomer Tayar mb_params.data_src_size = VF_MAX_STATIC / 8; 12300b55e27dSYuval Mintz rc = qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 12310b55e27dSYuval Mintz if (rc) { 12320b55e27dSYuval Mintz DP_NOTICE(p_hwfn, "Failed to pass ACK for VF flr to MFW\n"); 12330b55e27dSYuval Mintz return -EBUSY; 12340b55e27dSYuval Mintz } 12350b55e27dSYuval Mintz 12360b55e27dSYuval Mintz /* Clear the ACK bits */ 12370b55e27dSYuval Mintz for (i = 0; i < (VF_MAX_STATIC / 32); i++) 12380b55e27dSYuval Mintz qed_wr(p_hwfn, p_ptt, 12390b55e27dSYuval Mintz func_addr + 12400b55e27dSYuval Mintz offsetof(struct public_func, drv_ack_vf_disabled) + 12410b55e27dSYuval Mintz i * sizeof(u32), 0); 12420b55e27dSYuval Mintz 12430b55e27dSYuval Mintz return rc; 12440b55e27dSYuval Mintz } 12450b55e27dSYuval Mintz 1246334c03b5SZvi Nachmani static void qed_mcp_handle_transceiver_change(struct qed_hwfn *p_hwfn, 1247334c03b5SZvi Nachmani struct qed_ptt *p_ptt) 1248334c03b5SZvi Nachmani { 1249334c03b5SZvi Nachmani u32 transceiver_state; 1250334c03b5SZvi Nachmani 1251334c03b5SZvi Nachmani transceiver_state = qed_rd(p_hwfn, p_ptt, 1252334c03b5SZvi Nachmani p_hwfn->mcp_info->port_addr + 1253334c03b5SZvi Nachmani offsetof(struct public_port, 1254334c03b5SZvi Nachmani transceiver_data)); 1255334c03b5SZvi Nachmani 1256334c03b5SZvi Nachmani DP_VERBOSE(p_hwfn, 1257334c03b5SZvi Nachmani (NETIF_MSG_HW | QED_MSG_SP), 1258334c03b5SZvi Nachmani "Received transceiver state update [0x%08x] from mfw [Addr 0x%x]\n", 1259334c03b5SZvi Nachmani transceiver_state, 1260334c03b5SZvi Nachmani (u32)(p_hwfn->mcp_info->port_addr + 12611a635e48SYuval Mintz offsetof(struct public_port, transceiver_data))); 1262334c03b5SZvi Nachmani 1263334c03b5SZvi Nachmani transceiver_state = GET_FIELD(transceiver_state, 1264351a4dedSYuval Mintz ETH_TRANSCEIVER_STATE); 1265334c03b5SZvi Nachmani 1266351a4dedSYuval Mintz if (transceiver_state == ETH_TRANSCEIVER_STATE_PRESENT) 1267334c03b5SZvi Nachmani DP_NOTICE(p_hwfn, "Transceiver is present.\n"); 1268334c03b5SZvi Nachmani else 1269334c03b5SZvi Nachmani DP_NOTICE(p_hwfn, "Transceiver is unplugged.\n"); 1270334c03b5SZvi Nachmani } 1271334c03b5SZvi Nachmani 1272645874e5SSudarsana Reddy Kalluru static void qed_mcp_read_eee_config(struct qed_hwfn *p_hwfn, 1273645874e5SSudarsana Reddy Kalluru struct qed_ptt *p_ptt, 1274645874e5SSudarsana Reddy Kalluru struct qed_mcp_link_state *p_link) 1275645874e5SSudarsana Reddy Kalluru { 1276645874e5SSudarsana Reddy Kalluru u32 eee_status, val; 1277645874e5SSudarsana Reddy Kalluru 1278645874e5SSudarsana Reddy Kalluru p_link->eee_adv_caps = 0; 1279645874e5SSudarsana Reddy Kalluru p_link->eee_lp_adv_caps = 0; 1280645874e5SSudarsana Reddy Kalluru eee_status = qed_rd(p_hwfn, 1281645874e5SSudarsana Reddy Kalluru p_ptt, 1282645874e5SSudarsana Reddy Kalluru p_hwfn->mcp_info->port_addr + 1283645874e5SSudarsana Reddy Kalluru offsetof(struct public_port, eee_status)); 1284645874e5SSudarsana Reddy Kalluru p_link->eee_active = !!(eee_status & EEE_ACTIVE_BIT); 1285645874e5SSudarsana Reddy Kalluru val = (eee_status & EEE_LD_ADV_STATUS_MASK) >> EEE_LD_ADV_STATUS_OFFSET; 1286645874e5SSudarsana Reddy Kalluru if (val & EEE_1G_ADV) 1287645874e5SSudarsana Reddy Kalluru p_link->eee_adv_caps |= QED_EEE_1G_ADV; 1288645874e5SSudarsana Reddy Kalluru if (val & EEE_10G_ADV) 1289645874e5SSudarsana Reddy Kalluru p_link->eee_adv_caps |= QED_EEE_10G_ADV; 1290645874e5SSudarsana Reddy Kalluru val = (eee_status & EEE_LP_ADV_STATUS_MASK) >> EEE_LP_ADV_STATUS_OFFSET; 1291645874e5SSudarsana Reddy Kalluru if (val & EEE_1G_ADV) 1292645874e5SSudarsana Reddy Kalluru p_link->eee_lp_adv_caps |= QED_EEE_1G_ADV; 1293645874e5SSudarsana Reddy Kalluru if (val & EEE_10G_ADV) 1294645874e5SSudarsana Reddy Kalluru p_link->eee_lp_adv_caps |= QED_EEE_10G_ADV; 1295645874e5SSudarsana Reddy Kalluru } 1296645874e5SSudarsana Reddy Kalluru 1297e40a826aSSudarsana Reddy Kalluru static u32 qed_mcp_get_shmem_func(struct qed_hwfn *p_hwfn, 1298e40a826aSSudarsana Reddy Kalluru struct qed_ptt *p_ptt, 1299e40a826aSSudarsana Reddy Kalluru struct public_func *p_data, int pfid) 1300e40a826aSSudarsana Reddy Kalluru { 1301e40a826aSSudarsana Reddy Kalluru u32 addr = SECTION_OFFSIZE_ADDR(p_hwfn->mcp_info->public_base, 1302e40a826aSSudarsana Reddy Kalluru PUBLIC_FUNC); 1303e40a826aSSudarsana Reddy Kalluru u32 mfw_path_offsize = qed_rd(p_hwfn, p_ptt, addr); 1304e40a826aSSudarsana Reddy Kalluru u32 func_addr; 1305e40a826aSSudarsana Reddy Kalluru u32 i, size; 1306e40a826aSSudarsana Reddy Kalluru 1307e40a826aSSudarsana Reddy Kalluru func_addr = SECTION_ADDR(mfw_path_offsize, pfid); 1308e40a826aSSudarsana Reddy Kalluru memset(p_data, 0, sizeof(*p_data)); 1309e40a826aSSudarsana Reddy Kalluru 1310e40a826aSSudarsana Reddy Kalluru size = min_t(u32, sizeof(*p_data), QED_SECTION_SIZE(mfw_path_offsize)); 1311e40a826aSSudarsana Reddy Kalluru for (i = 0; i < size / sizeof(u32); i++) 1312e40a826aSSudarsana Reddy Kalluru ((u32 *)p_data)[i] = qed_rd(p_hwfn, p_ptt, 1313e40a826aSSudarsana Reddy Kalluru func_addr + (i << 2)); 1314e40a826aSSudarsana Reddy Kalluru return size; 1315e40a826aSSudarsana Reddy Kalluru } 1316e40a826aSSudarsana Reddy Kalluru 1317e40a826aSSudarsana Reddy Kalluru static void qed_read_pf_bandwidth(struct qed_hwfn *p_hwfn, 1318e40a826aSSudarsana Reddy Kalluru struct public_func *p_shmem_info) 1319e40a826aSSudarsana Reddy Kalluru { 1320e40a826aSSudarsana Reddy Kalluru struct qed_mcp_function_info *p_info; 1321e40a826aSSudarsana Reddy Kalluru 1322e40a826aSSudarsana Reddy Kalluru p_info = &p_hwfn->mcp_info->func_info; 1323e40a826aSSudarsana Reddy Kalluru 1324e40a826aSSudarsana Reddy Kalluru p_info->bandwidth_min = QED_MFW_GET_FIELD(p_shmem_info->config, 1325e40a826aSSudarsana Reddy Kalluru FUNC_MF_CFG_MIN_BW); 1326e40a826aSSudarsana Reddy Kalluru if (p_info->bandwidth_min < 1 || p_info->bandwidth_min > 100) { 1327e40a826aSSudarsana Reddy Kalluru DP_INFO(p_hwfn, 1328e40a826aSSudarsana Reddy Kalluru "bandwidth minimum out of bounds [%02x]. Set to 1\n", 1329e40a826aSSudarsana Reddy Kalluru p_info->bandwidth_min); 1330e40a826aSSudarsana Reddy Kalluru p_info->bandwidth_min = 1; 1331e40a826aSSudarsana Reddy Kalluru } 1332e40a826aSSudarsana Reddy Kalluru 1333e40a826aSSudarsana Reddy Kalluru p_info->bandwidth_max = QED_MFW_GET_FIELD(p_shmem_info->config, 1334e40a826aSSudarsana Reddy Kalluru FUNC_MF_CFG_MAX_BW); 1335e40a826aSSudarsana Reddy Kalluru if (p_info->bandwidth_max < 1 || p_info->bandwidth_max > 100) { 1336e40a826aSSudarsana Reddy Kalluru DP_INFO(p_hwfn, 1337e40a826aSSudarsana Reddy Kalluru "bandwidth maximum out of bounds [%02x]. Set to 100\n", 1338e40a826aSSudarsana Reddy Kalluru p_info->bandwidth_max); 1339e40a826aSSudarsana Reddy Kalluru p_info->bandwidth_max = 100; 1340e40a826aSSudarsana Reddy Kalluru } 1341e40a826aSSudarsana Reddy Kalluru } 1342e40a826aSSudarsana Reddy Kalluru 1343cc875c2eSYuval Mintz static void qed_mcp_handle_link_change(struct qed_hwfn *p_hwfn, 13441a635e48SYuval Mintz struct qed_ptt *p_ptt, bool b_reset) 1345cc875c2eSYuval Mintz { 1346cc875c2eSYuval Mintz struct qed_mcp_link_state *p_link; 1347a64b02d5SManish Chopra u8 max_bw, min_bw; 1348cc875c2eSYuval Mintz u32 status = 0; 1349cc875c2eSYuval Mintz 135065ed2ffdSMintz, Yuval /* Prevent SW/attentions from doing this at the same time */ 135165ed2ffdSMintz, Yuval spin_lock_bh(&p_hwfn->mcp_info->link_lock); 135265ed2ffdSMintz, Yuval 1353cc875c2eSYuval Mintz p_link = &p_hwfn->mcp_info->link_output; 1354cc875c2eSYuval Mintz memset(p_link, 0, sizeof(*p_link)); 1355cc875c2eSYuval Mintz if (!b_reset) { 1356cc875c2eSYuval Mintz status = qed_rd(p_hwfn, p_ptt, 1357cc875c2eSYuval Mintz p_hwfn->mcp_info->port_addr + 1358cc875c2eSYuval Mintz offsetof(struct public_port, link_status)); 1359cc875c2eSYuval Mintz DP_VERBOSE(p_hwfn, (NETIF_MSG_LINK | QED_MSG_SP), 1360cc875c2eSYuval Mintz "Received link update [0x%08x] from mfw [Addr 0x%x]\n", 1361cc875c2eSYuval Mintz status, 1362cc875c2eSYuval Mintz (u32)(p_hwfn->mcp_info->port_addr + 13631a635e48SYuval Mintz offsetof(struct public_port, link_status))); 1364cc875c2eSYuval Mintz } else { 1365cc875c2eSYuval Mintz DP_VERBOSE(p_hwfn, NETIF_MSG_LINK, 1366cc875c2eSYuval Mintz "Resetting link indications\n"); 136765ed2ffdSMintz, Yuval goto out; 1368cc875c2eSYuval Mintz } 1369cc875c2eSYuval Mintz 1370e40a826aSSudarsana Reddy Kalluru if (p_hwfn->b_drv_link_init) { 1371e40a826aSSudarsana Reddy Kalluru /* Link indication with modern MFW arrives as per-PF 1372e40a826aSSudarsana Reddy Kalluru * indication. 1373e40a826aSSudarsana Reddy Kalluru */ 1374e40a826aSSudarsana Reddy Kalluru if (p_hwfn->mcp_info->capabilities & 1375e40a826aSSudarsana Reddy Kalluru FW_MB_PARAM_FEATURE_SUPPORT_VLINK) { 1376e40a826aSSudarsana Reddy Kalluru struct public_func shmem_info; 1377e40a826aSSudarsana Reddy Kalluru 1378e40a826aSSudarsana Reddy Kalluru qed_mcp_get_shmem_func(p_hwfn, p_ptt, &shmem_info, 1379e40a826aSSudarsana Reddy Kalluru MCP_PF_ID(p_hwfn)); 1380e40a826aSSudarsana Reddy Kalluru p_link->link_up = !!(shmem_info.status & 1381e40a826aSSudarsana Reddy Kalluru FUNC_STATUS_VIRTUAL_LINK_UP); 1382e40a826aSSudarsana Reddy Kalluru qed_read_pf_bandwidth(p_hwfn, &shmem_info); 1383e40a826aSSudarsana Reddy Kalluru DP_VERBOSE(p_hwfn, NETIF_MSG_LINK, 1384e40a826aSSudarsana Reddy Kalluru "Virtual link_up = %d\n", p_link->link_up); 1385e40a826aSSudarsana Reddy Kalluru } else { 1386cc875c2eSYuval Mintz p_link->link_up = !!(status & LINK_STATUS_LINK_UP); 1387e40a826aSSudarsana Reddy Kalluru DP_VERBOSE(p_hwfn, NETIF_MSG_LINK, 1388e40a826aSSudarsana Reddy Kalluru "Physical link_up = %d\n", p_link->link_up); 1389e40a826aSSudarsana Reddy Kalluru } 1390e40a826aSSudarsana Reddy Kalluru } else { 1391fc916ff2SSudarsana Reddy Kalluru p_link->link_up = false; 1392e40a826aSSudarsana Reddy Kalluru } 1393cc875c2eSYuval Mintz 1394cc875c2eSYuval Mintz p_link->full_duplex = true; 1395cc875c2eSYuval Mintz switch ((status & LINK_STATUS_SPEED_AND_DUPLEX_MASK)) { 1396cc875c2eSYuval Mintz case LINK_STATUS_SPEED_AND_DUPLEX_100G: 1397cc875c2eSYuval Mintz p_link->speed = 100000; 1398cc875c2eSYuval Mintz break; 1399cc875c2eSYuval Mintz case LINK_STATUS_SPEED_AND_DUPLEX_50G: 1400cc875c2eSYuval Mintz p_link->speed = 50000; 1401cc875c2eSYuval Mintz break; 1402cc875c2eSYuval Mintz case LINK_STATUS_SPEED_AND_DUPLEX_40G: 1403cc875c2eSYuval Mintz p_link->speed = 40000; 1404cc875c2eSYuval Mintz break; 1405cc875c2eSYuval Mintz case LINK_STATUS_SPEED_AND_DUPLEX_25G: 1406cc875c2eSYuval Mintz p_link->speed = 25000; 1407cc875c2eSYuval Mintz break; 1408cc875c2eSYuval Mintz case LINK_STATUS_SPEED_AND_DUPLEX_20G: 1409cc875c2eSYuval Mintz p_link->speed = 20000; 1410cc875c2eSYuval Mintz break; 1411cc875c2eSYuval Mintz case LINK_STATUS_SPEED_AND_DUPLEX_10G: 1412cc875c2eSYuval Mintz p_link->speed = 10000; 1413cc875c2eSYuval Mintz break; 1414cc875c2eSYuval Mintz case LINK_STATUS_SPEED_AND_DUPLEX_1000THD: 1415cc875c2eSYuval Mintz p_link->full_duplex = false; 1416df561f66SGustavo A. R. Silva fallthrough; 1417cc875c2eSYuval Mintz case LINK_STATUS_SPEED_AND_DUPLEX_1000TFD: 1418cc875c2eSYuval Mintz p_link->speed = 1000; 1419cc875c2eSYuval Mintz break; 1420cc875c2eSYuval Mintz default: 1421cc875c2eSYuval Mintz p_link->speed = 0; 142258874c7bSSudarsana Reddy Kalluru p_link->link_up = 0; 1423cc875c2eSYuval Mintz } 1424cc875c2eSYuval Mintz 14254b01e519SManish Chopra if (p_link->link_up && p_link->speed) 14264b01e519SManish Chopra p_link->line_speed = p_link->speed; 14274b01e519SManish Chopra else 14284b01e519SManish Chopra p_link->line_speed = 0; 14294b01e519SManish Chopra 14304b01e519SManish Chopra max_bw = p_hwfn->mcp_info->func_info.bandwidth_max; 1431a64b02d5SManish Chopra min_bw = p_hwfn->mcp_info->func_info.bandwidth_min; 14324b01e519SManish Chopra 1433a64b02d5SManish Chopra /* Max bandwidth configuration */ 14344b01e519SManish Chopra __qed_configure_pf_max_bandwidth(p_hwfn, p_ptt, p_link, max_bw); 1435cc875c2eSYuval Mintz 1436a64b02d5SManish Chopra /* Min bandwidth configuration */ 1437a64b02d5SManish Chopra __qed_configure_pf_min_bandwidth(p_hwfn, p_ptt, p_link, min_bw); 14386f437d43SMintz, Yuval qed_configure_vp_wfq_on_link_change(p_hwfn->cdev, p_ptt, 14396f437d43SMintz, Yuval p_link->min_pf_rate); 1440a64b02d5SManish Chopra 1441cc875c2eSYuval Mintz p_link->an = !!(status & LINK_STATUS_AUTO_NEGOTIATE_ENABLED); 1442cc875c2eSYuval Mintz p_link->an_complete = !!(status & 1443cc875c2eSYuval Mintz LINK_STATUS_AUTO_NEGOTIATE_COMPLETE); 1444cc875c2eSYuval Mintz p_link->parallel_detection = !!(status & 1445cc875c2eSYuval Mintz LINK_STATUS_PARALLEL_DETECTION_USED); 1446cc875c2eSYuval Mintz p_link->pfc_enabled = !!(status & LINK_STATUS_PFC_ENABLED); 1447cc875c2eSYuval Mintz 1448cc875c2eSYuval Mintz p_link->partner_adv_speed |= 1449cc875c2eSYuval Mintz (status & LINK_STATUS_LINK_PARTNER_1000TFD_CAPABLE) ? 1450cc875c2eSYuval Mintz QED_LINK_PARTNER_SPEED_1G_FD : 0; 1451cc875c2eSYuval Mintz p_link->partner_adv_speed |= 1452cc875c2eSYuval Mintz (status & LINK_STATUS_LINK_PARTNER_1000THD_CAPABLE) ? 1453cc875c2eSYuval Mintz QED_LINK_PARTNER_SPEED_1G_HD : 0; 1454cc875c2eSYuval Mintz p_link->partner_adv_speed |= 1455cc875c2eSYuval Mintz (status & LINK_STATUS_LINK_PARTNER_10G_CAPABLE) ? 1456cc875c2eSYuval Mintz QED_LINK_PARTNER_SPEED_10G : 0; 1457cc875c2eSYuval Mintz p_link->partner_adv_speed |= 1458cc875c2eSYuval Mintz (status & LINK_STATUS_LINK_PARTNER_20G_CAPABLE) ? 1459cc875c2eSYuval Mintz QED_LINK_PARTNER_SPEED_20G : 0; 1460cc875c2eSYuval Mintz p_link->partner_adv_speed |= 1461054c67d1SSudarsana Reddy Kalluru (status & LINK_STATUS_LINK_PARTNER_25G_CAPABLE) ? 1462054c67d1SSudarsana Reddy Kalluru QED_LINK_PARTNER_SPEED_25G : 0; 1463054c67d1SSudarsana Reddy Kalluru p_link->partner_adv_speed |= 1464cc875c2eSYuval Mintz (status & LINK_STATUS_LINK_PARTNER_40G_CAPABLE) ? 1465cc875c2eSYuval Mintz QED_LINK_PARTNER_SPEED_40G : 0; 1466cc875c2eSYuval Mintz p_link->partner_adv_speed |= 1467cc875c2eSYuval Mintz (status & LINK_STATUS_LINK_PARTNER_50G_CAPABLE) ? 1468cc875c2eSYuval Mintz QED_LINK_PARTNER_SPEED_50G : 0; 1469cc875c2eSYuval Mintz p_link->partner_adv_speed |= 1470cc875c2eSYuval Mintz (status & LINK_STATUS_LINK_PARTNER_100G_CAPABLE) ? 1471cc875c2eSYuval Mintz QED_LINK_PARTNER_SPEED_100G : 0; 1472cc875c2eSYuval Mintz 1473cc875c2eSYuval Mintz p_link->partner_tx_flow_ctrl_en = 1474cc875c2eSYuval Mintz !!(status & LINK_STATUS_TX_FLOW_CONTROL_ENABLED); 1475cc875c2eSYuval Mintz p_link->partner_rx_flow_ctrl_en = 1476cc875c2eSYuval Mintz !!(status & LINK_STATUS_RX_FLOW_CONTROL_ENABLED); 1477cc875c2eSYuval Mintz 1478cc875c2eSYuval Mintz switch (status & LINK_STATUS_LINK_PARTNER_FLOW_CONTROL_MASK) { 1479cc875c2eSYuval Mintz case LINK_STATUS_LINK_PARTNER_SYMMETRIC_PAUSE: 1480cc875c2eSYuval Mintz p_link->partner_adv_pause = QED_LINK_PARTNER_SYMMETRIC_PAUSE; 1481cc875c2eSYuval Mintz break; 1482cc875c2eSYuval Mintz case LINK_STATUS_LINK_PARTNER_ASYMMETRIC_PAUSE: 1483cc875c2eSYuval Mintz p_link->partner_adv_pause = QED_LINK_PARTNER_ASYMMETRIC_PAUSE; 1484cc875c2eSYuval Mintz break; 1485cc875c2eSYuval Mintz case LINK_STATUS_LINK_PARTNER_BOTH_PAUSE: 1486cc875c2eSYuval Mintz p_link->partner_adv_pause = QED_LINK_PARTNER_BOTH_PAUSE; 1487cc875c2eSYuval Mintz break; 1488cc875c2eSYuval Mintz default: 1489cc875c2eSYuval Mintz p_link->partner_adv_pause = 0; 1490cc875c2eSYuval Mintz } 1491cc875c2eSYuval Mintz 1492cc875c2eSYuval Mintz p_link->sfp_tx_fault = !!(status & LINK_STATUS_SFP_TX_FAULT); 1493cc875c2eSYuval Mintz 1494645874e5SSudarsana Reddy Kalluru if (p_hwfn->mcp_info->capabilities & FW_MB_PARAM_FEATURE_SUPPORT_EEE) 1495645874e5SSudarsana Reddy Kalluru qed_mcp_read_eee_config(p_hwfn, p_ptt, p_link); 1496645874e5SSudarsana Reddy Kalluru 1497ae7e6937SAlexander Lobakin if (p_hwfn->mcp_info->capabilities & 1498ae7e6937SAlexander Lobakin FW_MB_PARAM_FEATURE_SUPPORT_FEC_CONTROL) { 1499ae7e6937SAlexander Lobakin switch (status & LINK_STATUS_FEC_MODE_MASK) { 1500ae7e6937SAlexander Lobakin case LINK_STATUS_FEC_MODE_NONE: 1501ae7e6937SAlexander Lobakin p_link->fec_active = QED_FEC_MODE_NONE; 1502ae7e6937SAlexander Lobakin break; 1503ae7e6937SAlexander Lobakin case LINK_STATUS_FEC_MODE_FIRECODE_CL74: 1504ae7e6937SAlexander Lobakin p_link->fec_active = QED_FEC_MODE_FIRECODE; 1505ae7e6937SAlexander Lobakin break; 1506ae7e6937SAlexander Lobakin case LINK_STATUS_FEC_MODE_RS_CL91: 1507ae7e6937SAlexander Lobakin p_link->fec_active = QED_FEC_MODE_RS; 1508ae7e6937SAlexander Lobakin break; 1509ae7e6937SAlexander Lobakin default: 1510ae7e6937SAlexander Lobakin p_link->fec_active = QED_FEC_MODE_AUTO; 1511ae7e6937SAlexander Lobakin } 1512ae7e6937SAlexander Lobakin } else { 1513ae7e6937SAlexander Lobakin p_link->fec_active = QED_FEC_MODE_UNSUPPORTED; 1514ae7e6937SAlexander Lobakin } 1515ae7e6937SAlexander Lobakin 1516706d0891SRahul Verma qed_link_update(p_hwfn, p_ptt); 151765ed2ffdSMintz, Yuval out: 151865ed2ffdSMintz, Yuval spin_unlock_bh(&p_hwfn->mcp_info->link_lock); 1519cc875c2eSYuval Mintz } 1520cc875c2eSYuval Mintz 1521351a4dedSYuval Mintz int qed_mcp_set_link(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, bool b_up) 1522cc875c2eSYuval Mintz { 1523cc875c2eSYuval Mintz struct qed_mcp_link_params *params = &p_hwfn->mcp_info->link_input; 15245529bad9STomer Tayar struct qed_mcp_mb_params mb_params; 15252f67af8cSTomer Tayar struct eth_phy_cfg phy_cfg; 1526ae7e6937SAlexander Lobakin u32 cmd, fec_bit = 0; 152799785a87SAlexander Lobakin u32 val, ext_speed; 1528cc875c2eSYuval Mintz int rc = 0; 1529cc875c2eSYuval Mintz 1530cc875c2eSYuval Mintz /* Set the shmem configuration according to params */ 15312f67af8cSTomer Tayar memset(&phy_cfg, 0, sizeof(phy_cfg)); 1532cc875c2eSYuval Mintz cmd = b_up ? DRV_MSG_CODE_INIT_PHY : DRV_MSG_CODE_LINK_RESET; 1533cc875c2eSYuval Mintz if (!params->speed.autoneg) 15342f67af8cSTomer Tayar phy_cfg.speed = params->speed.forced_speed; 15352f67af8cSTomer Tayar phy_cfg.pause |= (params->pause.autoneg) ? ETH_PAUSE_AUTONEG : 0; 15362f67af8cSTomer Tayar phy_cfg.pause |= (params->pause.forced_rx) ? ETH_PAUSE_RX : 0; 15372f67af8cSTomer Tayar phy_cfg.pause |= (params->pause.forced_tx) ? ETH_PAUSE_TX : 0; 15382f67af8cSTomer Tayar phy_cfg.adv_speed = params->speed.advertised_speeds; 15392f67af8cSTomer Tayar phy_cfg.loopback_mode = params->loopback_mode; 15404ad95a93SSudarsana Reddy Kalluru 15414ad95a93SSudarsana Reddy Kalluru /* There are MFWs that share this capability regardless of whether 15424ad95a93SSudarsana Reddy Kalluru * this is feasible or not. And given that at the very least adv_caps 15434ad95a93SSudarsana Reddy Kalluru * would be set internally by qed, we want to make sure LFA would 15444ad95a93SSudarsana Reddy Kalluru * still work. 15454ad95a93SSudarsana Reddy Kalluru */ 15464ad95a93SSudarsana Reddy Kalluru if ((p_hwfn->mcp_info->capabilities & 15474ad95a93SSudarsana Reddy Kalluru FW_MB_PARAM_FEATURE_SUPPORT_EEE) && params->eee.enable) { 1548645874e5SSudarsana Reddy Kalluru phy_cfg.eee_cfg |= EEE_CFG_EEE_ENABLED; 1549645874e5SSudarsana Reddy Kalluru if (params->eee.tx_lpi_enable) 1550645874e5SSudarsana Reddy Kalluru phy_cfg.eee_cfg |= EEE_CFG_TX_LPI; 1551645874e5SSudarsana Reddy Kalluru if (params->eee.adv_caps & QED_EEE_1G_ADV) 1552645874e5SSudarsana Reddy Kalluru phy_cfg.eee_cfg |= EEE_CFG_ADV_SPEED_1G; 1553645874e5SSudarsana Reddy Kalluru if (params->eee.adv_caps & QED_EEE_10G_ADV) 1554645874e5SSudarsana Reddy Kalluru phy_cfg.eee_cfg |= EEE_CFG_ADV_SPEED_10G; 1555645874e5SSudarsana Reddy Kalluru phy_cfg.eee_cfg |= (params->eee.tx_lpi_timer << 1556645874e5SSudarsana Reddy Kalluru EEE_TX_TIMER_USEC_OFFSET) & 1557645874e5SSudarsana Reddy Kalluru EEE_TX_TIMER_USEC_MASK; 1558645874e5SSudarsana Reddy Kalluru } 1559cc875c2eSYuval Mintz 1560ae7e6937SAlexander Lobakin if (p_hwfn->mcp_info->capabilities & 1561ae7e6937SAlexander Lobakin FW_MB_PARAM_FEATURE_SUPPORT_FEC_CONTROL) { 1562ae7e6937SAlexander Lobakin if (params->fec & QED_FEC_MODE_NONE) 1563ae7e6937SAlexander Lobakin fec_bit |= FEC_FORCE_MODE_NONE; 1564ae7e6937SAlexander Lobakin else if (params->fec & QED_FEC_MODE_FIRECODE) 1565ae7e6937SAlexander Lobakin fec_bit |= FEC_FORCE_MODE_FIRECODE; 1566ae7e6937SAlexander Lobakin else if (params->fec & QED_FEC_MODE_RS) 1567ae7e6937SAlexander Lobakin fec_bit |= FEC_FORCE_MODE_RS; 1568ae7e6937SAlexander Lobakin else if (params->fec & QED_FEC_MODE_AUTO) 1569ae7e6937SAlexander Lobakin fec_bit |= FEC_FORCE_MODE_AUTO; 1570ae7e6937SAlexander Lobakin 1571ae7e6937SAlexander Lobakin SET_MFW_FIELD(phy_cfg.fec_mode, FEC_FORCE_MODE, fec_bit); 1572ae7e6937SAlexander Lobakin } 1573ae7e6937SAlexander Lobakin 157499785a87SAlexander Lobakin if (p_hwfn->mcp_info->capabilities & 157599785a87SAlexander Lobakin FW_MB_PARAM_FEATURE_SUPPORT_EXT_SPEED_FEC_CONTROL) { 157699785a87SAlexander Lobakin ext_speed = 0; 157799785a87SAlexander Lobakin if (params->ext_speed.autoneg) 1578f2a74107SPrabhakar Kushwaha ext_speed |= ETH_EXT_SPEED_NONE; 157999785a87SAlexander Lobakin 158099785a87SAlexander Lobakin val = params->ext_speed.forced_speed; 158199785a87SAlexander Lobakin if (val & QED_EXT_SPEED_1G) 158299785a87SAlexander Lobakin ext_speed |= ETH_EXT_SPEED_1G; 158399785a87SAlexander Lobakin if (val & QED_EXT_SPEED_10G) 158499785a87SAlexander Lobakin ext_speed |= ETH_EXT_SPEED_10G; 158599785a87SAlexander Lobakin if (val & QED_EXT_SPEED_25G) 158699785a87SAlexander Lobakin ext_speed |= ETH_EXT_SPEED_25G; 158799785a87SAlexander Lobakin if (val & QED_EXT_SPEED_40G) 158899785a87SAlexander Lobakin ext_speed |= ETH_EXT_SPEED_40G; 158999785a87SAlexander Lobakin if (val & QED_EXT_SPEED_50G_R) 159099785a87SAlexander Lobakin ext_speed |= ETH_EXT_SPEED_50G_BASE_R; 159199785a87SAlexander Lobakin if (val & QED_EXT_SPEED_50G_R2) 159299785a87SAlexander Lobakin ext_speed |= ETH_EXT_SPEED_50G_BASE_R2; 159399785a87SAlexander Lobakin if (val & QED_EXT_SPEED_100G_R2) 159499785a87SAlexander Lobakin ext_speed |= ETH_EXT_SPEED_100G_BASE_R2; 159599785a87SAlexander Lobakin if (val & QED_EXT_SPEED_100G_R4) 159699785a87SAlexander Lobakin ext_speed |= ETH_EXT_SPEED_100G_BASE_R4; 159799785a87SAlexander Lobakin if (val & QED_EXT_SPEED_100G_P4) 159899785a87SAlexander Lobakin ext_speed |= ETH_EXT_SPEED_100G_BASE_P4; 159999785a87SAlexander Lobakin 160099785a87SAlexander Lobakin SET_MFW_FIELD(phy_cfg.extended_speed, ETH_EXT_SPEED, 160199785a87SAlexander Lobakin ext_speed); 160299785a87SAlexander Lobakin 160399785a87SAlexander Lobakin ext_speed = 0; 160499785a87SAlexander Lobakin 160599785a87SAlexander Lobakin val = params->ext_speed.advertised_speeds; 160699785a87SAlexander Lobakin if (val & QED_EXT_SPEED_MASK_1G) 160799785a87SAlexander Lobakin ext_speed |= ETH_EXT_ADV_SPEED_1G; 160899785a87SAlexander Lobakin if (val & QED_EXT_SPEED_MASK_10G) 160999785a87SAlexander Lobakin ext_speed |= ETH_EXT_ADV_SPEED_10G; 161099785a87SAlexander Lobakin if (val & QED_EXT_SPEED_MASK_25G) 161199785a87SAlexander Lobakin ext_speed |= ETH_EXT_ADV_SPEED_25G; 161299785a87SAlexander Lobakin if (val & QED_EXT_SPEED_MASK_40G) 161399785a87SAlexander Lobakin ext_speed |= ETH_EXT_ADV_SPEED_40G; 161499785a87SAlexander Lobakin if (val & QED_EXT_SPEED_MASK_50G_R) 161599785a87SAlexander Lobakin ext_speed |= ETH_EXT_ADV_SPEED_50G_BASE_R; 161699785a87SAlexander Lobakin if (val & QED_EXT_SPEED_MASK_50G_R2) 161799785a87SAlexander Lobakin ext_speed |= ETH_EXT_ADV_SPEED_50G_BASE_R2; 161899785a87SAlexander Lobakin if (val & QED_EXT_SPEED_MASK_100G_R2) 161999785a87SAlexander Lobakin ext_speed |= ETH_EXT_ADV_SPEED_100G_BASE_R2; 162099785a87SAlexander Lobakin if (val & QED_EXT_SPEED_MASK_100G_R4) 162199785a87SAlexander Lobakin ext_speed |= ETH_EXT_ADV_SPEED_100G_BASE_R4; 162299785a87SAlexander Lobakin if (val & QED_EXT_SPEED_MASK_100G_P4) 162399785a87SAlexander Lobakin ext_speed |= ETH_EXT_ADV_SPEED_100G_BASE_P4; 162499785a87SAlexander Lobakin 162599785a87SAlexander Lobakin phy_cfg.extended_speed |= ext_speed; 162699785a87SAlexander Lobakin 162799785a87SAlexander Lobakin SET_MFW_FIELD(phy_cfg.fec_mode, FEC_EXTENDED_MODE, 162899785a87SAlexander Lobakin params->ext_fec_mode); 162999785a87SAlexander Lobakin } 163099785a87SAlexander Lobakin 1631fc916ff2SSudarsana Reddy Kalluru p_hwfn->b_drv_link_init = b_up; 1632fc916ff2SSudarsana Reddy Kalluru 1633cc875c2eSYuval Mintz if (b_up) { 1634cc875c2eSYuval Mintz DP_VERBOSE(p_hwfn, NETIF_MSG_LINK, 163599785a87SAlexander Lobakin "Configuring Link: Speed 0x%08x, Pause 0x%08x, Adv. Speed 0x%08x, Loopback 0x%08x, FEC 0x%08x, Ext. Speed 0x%08x\n", 1636ae7e6937SAlexander Lobakin phy_cfg.speed, phy_cfg.pause, phy_cfg.adv_speed, 163799785a87SAlexander Lobakin phy_cfg.loopback_mode, phy_cfg.fec_mode, 163899785a87SAlexander Lobakin phy_cfg.extended_speed); 1639cc875c2eSYuval Mintz } else { 164099785a87SAlexander Lobakin DP_VERBOSE(p_hwfn, NETIF_MSG_LINK, "Resetting link\n"); 1641cc875c2eSYuval Mintz } 1642cc875c2eSYuval Mintz 16435529bad9STomer Tayar memset(&mb_params, 0, sizeof(mb_params)); 16445529bad9STomer Tayar mb_params.cmd = cmd; 16452f67af8cSTomer Tayar mb_params.p_data_src = &phy_cfg; 16462f67af8cSTomer Tayar mb_params.data_src_size = sizeof(phy_cfg); 16475529bad9STomer Tayar rc = qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 1648cc875c2eSYuval Mintz 1649cc875c2eSYuval Mintz /* if mcp fails to respond we must abort */ 1650cc875c2eSYuval Mintz if (rc) { 1651cc875c2eSYuval Mintz DP_ERR(p_hwfn, "MCP response failure, aborting\n"); 1652cc875c2eSYuval Mintz return rc; 1653cc875c2eSYuval Mintz } 1654cc875c2eSYuval Mintz 165565ed2ffdSMintz, Yuval /* Mimic link-change attention, done for several reasons: 165665ed2ffdSMintz, Yuval * - On reset, there's no guarantee MFW would trigger 165765ed2ffdSMintz, Yuval * an attention. 165865ed2ffdSMintz, Yuval * - On initialization, older MFWs might not indicate link change 165965ed2ffdSMintz, Yuval * during LFA, so we'll never get an UP indication. 166065ed2ffdSMintz, Yuval */ 166165ed2ffdSMintz, Yuval qed_mcp_handle_link_change(p_hwfn, p_ptt, !b_up); 1662cc875c2eSYuval Mintz 1663cc875c2eSYuval Mintz return 0; 1664cc875c2eSYuval Mintz } 1665cc875c2eSYuval Mintz 166664515dc8STomer Tayar u32 qed_get_process_kill_counter(struct qed_hwfn *p_hwfn, 166764515dc8STomer Tayar struct qed_ptt *p_ptt) 166864515dc8STomer Tayar { 166964515dc8STomer Tayar u32 path_offsize_addr, path_offsize, path_addr, proc_kill_cnt; 167064515dc8STomer Tayar 167164515dc8STomer Tayar if (IS_VF(p_hwfn->cdev)) 167264515dc8STomer Tayar return -EINVAL; 167364515dc8STomer Tayar 167464515dc8STomer Tayar path_offsize_addr = SECTION_OFFSIZE_ADDR(p_hwfn->mcp_info->public_base, 167564515dc8STomer Tayar PUBLIC_PATH); 167664515dc8STomer Tayar path_offsize = qed_rd(p_hwfn, p_ptt, path_offsize_addr); 167764515dc8STomer Tayar path_addr = SECTION_ADDR(path_offsize, QED_PATH_ID(p_hwfn)); 167864515dc8STomer Tayar 167964515dc8STomer Tayar proc_kill_cnt = qed_rd(p_hwfn, p_ptt, 168064515dc8STomer Tayar path_addr + 168164515dc8STomer Tayar offsetof(struct public_path, process_kill)) & 168264515dc8STomer Tayar PROCESS_KILL_COUNTER_MASK; 168364515dc8STomer Tayar 168464515dc8STomer Tayar return proc_kill_cnt; 168564515dc8STomer Tayar } 168664515dc8STomer Tayar 168764515dc8STomer Tayar static void qed_mcp_handle_process_kill(struct qed_hwfn *p_hwfn, 168864515dc8STomer Tayar struct qed_ptt *p_ptt) 168964515dc8STomer Tayar { 169064515dc8STomer Tayar struct qed_dev *cdev = p_hwfn->cdev; 169164515dc8STomer Tayar u32 proc_kill_cnt; 169264515dc8STomer Tayar 169364515dc8STomer Tayar /* Prevent possible attentions/interrupts during the recovery handling 169464515dc8STomer Tayar * and till its load phase, during which they will be re-enabled. 169564515dc8STomer Tayar */ 169664515dc8STomer Tayar qed_int_igu_disable_int(p_hwfn, p_ptt); 169764515dc8STomer Tayar 169864515dc8STomer Tayar DP_NOTICE(p_hwfn, "Received a process kill indication\n"); 169964515dc8STomer Tayar 170064515dc8STomer Tayar /* The following operations should be done once, and thus in CMT mode 170164515dc8STomer Tayar * are carried out by only the first HW function. 170264515dc8STomer Tayar */ 170364515dc8STomer Tayar if (p_hwfn != QED_LEADING_HWFN(cdev)) 170464515dc8STomer Tayar return; 170564515dc8STomer Tayar 170664515dc8STomer Tayar if (cdev->recov_in_prog) { 170764515dc8STomer Tayar DP_NOTICE(p_hwfn, 170864515dc8STomer Tayar "Ignoring the indication since a recovery process is already in progress\n"); 170964515dc8STomer Tayar return; 171064515dc8STomer Tayar } 171164515dc8STomer Tayar 171264515dc8STomer Tayar cdev->recov_in_prog = true; 171364515dc8STomer Tayar 171464515dc8STomer Tayar proc_kill_cnt = qed_get_process_kill_counter(p_hwfn, p_ptt); 171564515dc8STomer Tayar DP_NOTICE(p_hwfn, "Process kill counter: %d\n", proc_kill_cnt); 171664515dc8STomer Tayar 171764515dc8STomer Tayar qed_schedule_recovery_handler(p_hwfn); 171864515dc8STomer Tayar } 171964515dc8STomer Tayar 17206c754246SSudarsana Reddy Kalluru static void qed_mcp_send_protocol_stats(struct qed_hwfn *p_hwfn, 17216c754246SSudarsana Reddy Kalluru struct qed_ptt *p_ptt, 17226c754246SSudarsana Reddy Kalluru enum MFW_DRV_MSG_TYPE type) 17236c754246SSudarsana Reddy Kalluru { 17246c754246SSudarsana Reddy Kalluru enum qed_mcp_protocol_type stats_type; 17256c754246SSudarsana Reddy Kalluru union qed_mcp_protocol_stats stats; 17266c754246SSudarsana Reddy Kalluru struct qed_mcp_mb_params mb_params; 17276c754246SSudarsana Reddy Kalluru u32 hsi_param; 17286c754246SSudarsana Reddy Kalluru 17296c754246SSudarsana Reddy Kalluru switch (type) { 17306c754246SSudarsana Reddy Kalluru case MFW_DRV_MSG_GET_LAN_STATS: 17316c754246SSudarsana Reddy Kalluru stats_type = QED_MCP_LAN_STATS; 17326c754246SSudarsana Reddy Kalluru hsi_param = DRV_MSG_CODE_STATS_TYPE_LAN; 17336c754246SSudarsana Reddy Kalluru break; 17346c754246SSudarsana Reddy Kalluru case MFW_DRV_MSG_GET_FCOE_STATS: 17356c754246SSudarsana Reddy Kalluru stats_type = QED_MCP_FCOE_STATS; 17366c754246SSudarsana Reddy Kalluru hsi_param = DRV_MSG_CODE_STATS_TYPE_FCOE; 17376c754246SSudarsana Reddy Kalluru break; 17386c754246SSudarsana Reddy Kalluru case MFW_DRV_MSG_GET_ISCSI_STATS: 17396c754246SSudarsana Reddy Kalluru stats_type = QED_MCP_ISCSI_STATS; 17406c754246SSudarsana Reddy Kalluru hsi_param = DRV_MSG_CODE_STATS_TYPE_ISCSI; 17416c754246SSudarsana Reddy Kalluru break; 17426c754246SSudarsana Reddy Kalluru case MFW_DRV_MSG_GET_RDMA_STATS: 17436c754246SSudarsana Reddy Kalluru stats_type = QED_MCP_RDMA_STATS; 17446c754246SSudarsana Reddy Kalluru hsi_param = DRV_MSG_CODE_STATS_TYPE_RDMA; 17456c754246SSudarsana Reddy Kalluru break; 17466c754246SSudarsana Reddy Kalluru default: 17476c754246SSudarsana Reddy Kalluru DP_NOTICE(p_hwfn, "Invalid protocol type %d\n", type); 17486c754246SSudarsana Reddy Kalluru return; 17496c754246SSudarsana Reddy Kalluru } 17506c754246SSudarsana Reddy Kalluru 17516c754246SSudarsana Reddy Kalluru qed_get_protocol_stats(p_hwfn->cdev, stats_type, &stats); 17526c754246SSudarsana Reddy Kalluru 17536c754246SSudarsana Reddy Kalluru memset(&mb_params, 0, sizeof(mb_params)); 17546c754246SSudarsana Reddy Kalluru mb_params.cmd = DRV_MSG_CODE_GET_STATS; 17556c754246SSudarsana Reddy Kalluru mb_params.param = hsi_param; 17562f67af8cSTomer Tayar mb_params.p_data_src = &stats; 17572f67af8cSTomer Tayar mb_params.data_src_size = sizeof(stats); 17586c754246SSudarsana Reddy Kalluru qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 17596c754246SSudarsana Reddy Kalluru } 17606c754246SSudarsana Reddy Kalluru 17611a635e48SYuval Mintz static void qed_mcp_update_bw(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 17624b01e519SManish Chopra { 17634b01e519SManish Chopra struct qed_mcp_function_info *p_info; 17644b01e519SManish Chopra struct public_func shmem_info; 17654b01e519SManish Chopra u32 resp = 0, param = 0; 17664b01e519SManish Chopra 17671a635e48SYuval Mintz qed_mcp_get_shmem_func(p_hwfn, p_ptt, &shmem_info, MCP_PF_ID(p_hwfn)); 17684b01e519SManish Chopra 17694b01e519SManish Chopra qed_read_pf_bandwidth(p_hwfn, &shmem_info); 17704b01e519SManish Chopra 17714b01e519SManish Chopra p_info = &p_hwfn->mcp_info->func_info; 17724b01e519SManish Chopra 1773a64b02d5SManish Chopra qed_configure_pf_min_bandwidth(p_hwfn->cdev, p_info->bandwidth_min); 17744b01e519SManish Chopra qed_configure_pf_max_bandwidth(p_hwfn->cdev, p_info->bandwidth_max); 17754b01e519SManish Chopra 17764b01e519SManish Chopra /* Acknowledge the MFW */ 1777ef10bd49SVenkata Sudheer Kumar Bhavaraju qed_mcp_cmd_nosleep(p_hwfn, p_ptt, DRV_MSG_CODE_BW_UPDATE_ACK, 0, &resp, 17784b01e519SManish Chopra ¶m); 17794b01e519SManish Chopra } 17804b01e519SManish Chopra 17812a351fd9SMintz, Yuval static void qed_mcp_update_stag(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 17822a351fd9SMintz, Yuval { 17832a351fd9SMintz, Yuval struct public_func shmem_info; 17842a351fd9SMintz, Yuval u32 resp = 0, param = 0; 17852a351fd9SMintz, Yuval 17862a351fd9SMintz, Yuval qed_mcp_get_shmem_func(p_hwfn, p_ptt, &shmem_info, MCP_PF_ID(p_hwfn)); 17872a351fd9SMintz, Yuval 17882a351fd9SMintz, Yuval p_hwfn->mcp_info->func_info.ovlan = (u16)shmem_info.ovlan_stag & 17892a351fd9SMintz, Yuval FUNC_MF_CFG_OV_STAG_MASK; 17902a351fd9SMintz, Yuval p_hwfn->hw_info.ovlan = p_hwfn->mcp_info->func_info.ovlan; 17917e3e375cSSudarsana Reddy Kalluru if (test_bit(QED_MF_OVLAN_CLSS, &p_hwfn->cdev->mf_bits)) { 17927e3e375cSSudarsana Reddy Kalluru if (p_hwfn->hw_info.ovlan != QED_MCP_VLAN_UNSET) { 17937e3e375cSSudarsana Reddy Kalluru qed_wr(p_hwfn, p_ptt, NIG_REG_LLH_FUNC_TAG_VALUE, 17947e3e375cSSudarsana Reddy Kalluru p_hwfn->hw_info.ovlan); 17957e3e375cSSudarsana Reddy Kalluru qed_wr(p_hwfn, p_ptt, NIG_REG_LLH_FUNC_TAG_EN, 1); 17967e3e375cSSudarsana Reddy Kalluru 17977e3e375cSSudarsana Reddy Kalluru /* Configure DB to add external vlan to EDPM packets */ 17987e3e375cSSudarsana Reddy Kalluru qed_wr(p_hwfn, p_ptt, DORQ_REG_TAG1_OVRD_MODE, 1); 17997e3e375cSSudarsana Reddy Kalluru qed_wr(p_hwfn, p_ptt, DORQ_REG_PF_EXT_VID_BB_K2, 18007e3e375cSSudarsana Reddy Kalluru p_hwfn->hw_info.ovlan); 18017e3e375cSSudarsana Reddy Kalluru } else { 18027e3e375cSSudarsana Reddy Kalluru qed_wr(p_hwfn, p_ptt, NIG_REG_LLH_FUNC_TAG_EN, 0); 18037e3e375cSSudarsana Reddy Kalluru qed_wr(p_hwfn, p_ptt, NIG_REG_LLH_FUNC_TAG_VALUE, 0); 18047e3e375cSSudarsana Reddy Kalluru qed_wr(p_hwfn, p_ptt, DORQ_REG_TAG1_OVRD_MODE, 0); 18057e3e375cSSudarsana Reddy Kalluru qed_wr(p_hwfn, p_ptt, DORQ_REG_PF_EXT_VID_BB_K2, 0); 18067e3e375cSSudarsana Reddy Kalluru } 18077e3e375cSSudarsana Reddy Kalluru 18082a351fd9SMintz, Yuval qed_sp_pf_update_stag(p_hwfn); 18092a351fd9SMintz, Yuval } 18102a351fd9SMintz, Yuval 18117e3e375cSSudarsana Reddy Kalluru DP_VERBOSE(p_hwfn, QED_MSG_SP, "ovlan = %d hw_mode = 0x%x\n", 18127e3e375cSSudarsana Reddy Kalluru p_hwfn->mcp_info->func_info.ovlan, p_hwfn->hw_info.hw_mode); 18137e3e375cSSudarsana Reddy Kalluru 18142a351fd9SMintz, Yuval /* Acknowledge the MFW */ 1815ef10bd49SVenkata Sudheer Kumar Bhavaraju qed_mcp_cmd_nosleep(p_hwfn, p_ptt, DRV_MSG_CODE_S_TAG_UPDATE_ACK, 0, 18162a351fd9SMintz, Yuval &resp, ¶m); 18172a351fd9SMintz, Yuval } 18182a351fd9SMintz, Yuval 18193e99c211SIgor Russkikh static void qed_mcp_handle_fan_failure(struct qed_hwfn *p_hwfn, 18203e99c211SIgor Russkikh struct qed_ptt *p_ptt) 18213e99c211SIgor Russkikh { 18223e99c211SIgor Russkikh /* A single notification should be sent to upper driver in CMT mode */ 18233e99c211SIgor Russkikh if (p_hwfn != QED_LEADING_HWFN(p_hwfn->cdev)) 18243e99c211SIgor Russkikh return; 18253e99c211SIgor Russkikh 18263e99c211SIgor Russkikh qed_hw_err_notify(p_hwfn, p_ptt, QED_HW_ERR_FAN_FAIL, 18273e99c211SIgor Russkikh "Fan failure was detected on the network interface card and it's going to be shut down.\n"); 18283e99c211SIgor Russkikh } 18293e99c211SIgor Russkikh 1830ebf64bf4SIgor Russkikh struct qed_mdump_cmd_params { 1831ebf64bf4SIgor Russkikh u32 cmd; 1832ebf64bf4SIgor Russkikh void *p_data_src; 1833ebf64bf4SIgor Russkikh u8 data_src_size; 1834ebf64bf4SIgor Russkikh void *p_data_dst; 1835ebf64bf4SIgor Russkikh u8 data_dst_size; 1836ebf64bf4SIgor Russkikh u32 mcp_resp; 1837ebf64bf4SIgor Russkikh }; 1838ebf64bf4SIgor Russkikh 1839ebf64bf4SIgor Russkikh static int 1840ebf64bf4SIgor Russkikh qed_mcp_mdump_cmd(struct qed_hwfn *p_hwfn, 1841ebf64bf4SIgor Russkikh struct qed_ptt *p_ptt, 1842ebf64bf4SIgor Russkikh struct qed_mdump_cmd_params *p_mdump_cmd_params) 1843ebf64bf4SIgor Russkikh { 1844ebf64bf4SIgor Russkikh struct qed_mcp_mb_params mb_params; 1845ebf64bf4SIgor Russkikh int rc; 1846ebf64bf4SIgor Russkikh 1847ebf64bf4SIgor Russkikh memset(&mb_params, 0, sizeof(mb_params)); 1848ebf64bf4SIgor Russkikh mb_params.cmd = DRV_MSG_CODE_MDUMP_CMD; 1849ebf64bf4SIgor Russkikh mb_params.param = p_mdump_cmd_params->cmd; 1850ebf64bf4SIgor Russkikh mb_params.p_data_src = p_mdump_cmd_params->p_data_src; 1851ebf64bf4SIgor Russkikh mb_params.data_src_size = p_mdump_cmd_params->data_src_size; 1852ebf64bf4SIgor Russkikh mb_params.p_data_dst = p_mdump_cmd_params->p_data_dst; 1853ebf64bf4SIgor Russkikh mb_params.data_dst_size = p_mdump_cmd_params->data_dst_size; 1854ebf64bf4SIgor Russkikh rc = qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 1855ebf64bf4SIgor Russkikh if (rc) 1856ebf64bf4SIgor Russkikh return rc; 1857ebf64bf4SIgor Russkikh 1858ebf64bf4SIgor Russkikh p_mdump_cmd_params->mcp_resp = mb_params.mcp_resp; 1859ebf64bf4SIgor Russkikh 1860ebf64bf4SIgor Russkikh if (p_mdump_cmd_params->mcp_resp == FW_MSG_CODE_MDUMP_INVALID_CMD) { 1861ebf64bf4SIgor Russkikh DP_INFO(p_hwfn, 1862ebf64bf4SIgor Russkikh "The mdump sub command is unsupported by the MFW [mdump_cmd 0x%x]\n", 1863ebf64bf4SIgor Russkikh p_mdump_cmd_params->cmd); 1864ebf64bf4SIgor Russkikh rc = -EOPNOTSUPP; 1865ebf64bf4SIgor Russkikh } else if (p_mdump_cmd_params->mcp_resp == FW_MSG_CODE_UNSUPPORTED) { 1866ebf64bf4SIgor Russkikh DP_INFO(p_hwfn, 1867ebf64bf4SIgor Russkikh "The mdump command is not supported by the MFW\n"); 1868ebf64bf4SIgor Russkikh rc = -EOPNOTSUPP; 1869ebf64bf4SIgor Russkikh } 1870ebf64bf4SIgor Russkikh 1871ebf64bf4SIgor Russkikh return rc; 1872ebf64bf4SIgor Russkikh } 1873ebf64bf4SIgor Russkikh 1874ebf64bf4SIgor Russkikh static int qed_mcp_mdump_ack(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 1875ebf64bf4SIgor Russkikh { 1876ebf64bf4SIgor Russkikh struct qed_mdump_cmd_params mdump_cmd_params; 1877ebf64bf4SIgor Russkikh 1878ebf64bf4SIgor Russkikh memset(&mdump_cmd_params, 0, sizeof(mdump_cmd_params)); 1879ebf64bf4SIgor Russkikh mdump_cmd_params.cmd = DRV_MSG_CODE_MDUMP_ACK; 1880ebf64bf4SIgor Russkikh 1881ebf64bf4SIgor Russkikh return qed_mcp_mdump_cmd(p_hwfn, p_ptt, &mdump_cmd_params); 1882ebf64bf4SIgor Russkikh } 1883ebf64bf4SIgor Russkikh 1884ebf64bf4SIgor Russkikh int 1885ebf64bf4SIgor Russkikh qed_mcp_mdump_get_retain(struct qed_hwfn *p_hwfn, 1886ebf64bf4SIgor Russkikh struct qed_ptt *p_ptt, 1887ebf64bf4SIgor Russkikh struct mdump_retain_data_stc *p_mdump_retain) 1888ebf64bf4SIgor Russkikh { 1889ebf64bf4SIgor Russkikh struct qed_mdump_cmd_params mdump_cmd_params; 1890ebf64bf4SIgor Russkikh int rc; 1891ebf64bf4SIgor Russkikh 1892ebf64bf4SIgor Russkikh memset(&mdump_cmd_params, 0, sizeof(mdump_cmd_params)); 1893ebf64bf4SIgor Russkikh mdump_cmd_params.cmd = DRV_MSG_CODE_MDUMP_GET_RETAIN; 1894ebf64bf4SIgor Russkikh mdump_cmd_params.p_data_dst = p_mdump_retain; 1895ebf64bf4SIgor Russkikh mdump_cmd_params.data_dst_size = sizeof(*p_mdump_retain); 1896ebf64bf4SIgor Russkikh 1897ebf64bf4SIgor Russkikh rc = qed_mcp_mdump_cmd(p_hwfn, p_ptt, &mdump_cmd_params); 1898ebf64bf4SIgor Russkikh if (rc) 1899ebf64bf4SIgor Russkikh return rc; 1900ebf64bf4SIgor Russkikh 1901ebf64bf4SIgor Russkikh if (mdump_cmd_params.mcp_resp != FW_MSG_CODE_OK) { 1902ebf64bf4SIgor Russkikh DP_INFO(p_hwfn, 1903ebf64bf4SIgor Russkikh "Failed to get the mdump retained data [mcp_resp 0x%x]\n", 1904ebf64bf4SIgor Russkikh mdump_cmd_params.mcp_resp); 1905ebf64bf4SIgor Russkikh return -EINVAL; 1906ebf64bf4SIgor Russkikh } 1907ebf64bf4SIgor Russkikh 1908ebf64bf4SIgor Russkikh return 0; 1909ebf64bf4SIgor Russkikh } 1910ebf64bf4SIgor Russkikh 1911ebf64bf4SIgor Russkikh static void qed_mcp_handle_critical_error(struct qed_hwfn *p_hwfn, 1912ebf64bf4SIgor Russkikh struct qed_ptt *p_ptt) 1913ebf64bf4SIgor Russkikh { 1914ebf64bf4SIgor Russkikh struct mdump_retain_data_stc mdump_retain; 1915ebf64bf4SIgor Russkikh int rc; 1916ebf64bf4SIgor Russkikh 1917ebf64bf4SIgor Russkikh /* In CMT mode - no need for more than a single acknowledgment to the 1918ebf64bf4SIgor Russkikh * MFW, and no more than a single notification to the upper driver. 1919ebf64bf4SIgor Russkikh */ 1920ebf64bf4SIgor Russkikh if (p_hwfn != QED_LEADING_HWFN(p_hwfn->cdev)) 1921ebf64bf4SIgor Russkikh return; 1922ebf64bf4SIgor Russkikh 1923ebf64bf4SIgor Russkikh rc = qed_mcp_mdump_get_retain(p_hwfn, p_ptt, &mdump_retain); 1924ebf64bf4SIgor Russkikh if (rc == 0 && mdump_retain.valid) 1925ebf64bf4SIgor Russkikh DP_NOTICE(p_hwfn, 1926ebf64bf4SIgor Russkikh "The MFW notified that a critical error occurred in the device [epoch 0x%08x, pf 0x%x, status 0x%08x]\n", 1927ebf64bf4SIgor Russkikh mdump_retain.epoch, 1928ebf64bf4SIgor Russkikh mdump_retain.pf, mdump_retain.status); 1929ebf64bf4SIgor Russkikh else 1930ebf64bf4SIgor Russkikh DP_NOTICE(p_hwfn, 1931ebf64bf4SIgor Russkikh "The MFW notified that a critical error occurred in the device\n"); 1932ebf64bf4SIgor Russkikh 1933ebf64bf4SIgor Russkikh DP_NOTICE(p_hwfn, 1934ebf64bf4SIgor Russkikh "Acknowledging the notification to not allow the MFW crash dump [driver debug data collection is preferable]\n"); 1935ebf64bf4SIgor Russkikh qed_mcp_mdump_ack(p_hwfn, p_ptt); 1936ebf64bf4SIgor Russkikh 1937ebf64bf4SIgor Russkikh qed_hw_err_notify(p_hwfn, p_ptt, QED_HW_ERR_HW_ATTN, NULL); 1938ebf64bf4SIgor Russkikh } 1939ebf64bf4SIgor Russkikh 1940cac6f691SSudarsana Reddy Kalluru void qed_mcp_read_ufp_config(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 1941cac6f691SSudarsana Reddy Kalluru { 1942cac6f691SSudarsana Reddy Kalluru struct public_func shmem_info; 1943cac6f691SSudarsana Reddy Kalluru u32 port_cfg, val; 1944cac6f691SSudarsana Reddy Kalluru 1945cac6f691SSudarsana Reddy Kalluru if (!test_bit(QED_MF_UFP_SPECIFIC, &p_hwfn->cdev->mf_bits)) 1946cac6f691SSudarsana Reddy Kalluru return; 1947cac6f691SSudarsana Reddy Kalluru 1948cac6f691SSudarsana Reddy Kalluru memset(&p_hwfn->ufp_info, 0, sizeof(p_hwfn->ufp_info)); 1949cac6f691SSudarsana Reddy Kalluru port_cfg = qed_rd(p_hwfn, p_ptt, p_hwfn->mcp_info->port_addr + 1950cac6f691SSudarsana Reddy Kalluru offsetof(struct public_port, oem_cfg_port)); 1951cac6f691SSudarsana Reddy Kalluru val = (port_cfg & OEM_CFG_CHANNEL_TYPE_MASK) >> 1952cac6f691SSudarsana Reddy Kalluru OEM_CFG_CHANNEL_TYPE_OFFSET; 1953cac6f691SSudarsana Reddy Kalluru if (val != OEM_CFG_CHANNEL_TYPE_STAGGED) 1954ec036eb9SSudarsana Reddy Kalluru DP_NOTICE(p_hwfn, 1955ec036eb9SSudarsana Reddy Kalluru "Incorrect UFP Channel type %d port_id 0x%02x\n", 1956ec036eb9SSudarsana Reddy Kalluru val, MFW_PORT(p_hwfn)); 1957cac6f691SSudarsana Reddy Kalluru 1958cac6f691SSudarsana Reddy Kalluru val = (port_cfg & OEM_CFG_SCHED_TYPE_MASK) >> OEM_CFG_SCHED_TYPE_OFFSET; 1959cac6f691SSudarsana Reddy Kalluru if (val == OEM_CFG_SCHED_TYPE_ETS) { 1960cac6f691SSudarsana Reddy Kalluru p_hwfn->ufp_info.mode = QED_UFP_MODE_ETS; 1961cac6f691SSudarsana Reddy Kalluru } else if (val == OEM_CFG_SCHED_TYPE_VNIC_BW) { 1962cac6f691SSudarsana Reddy Kalluru p_hwfn->ufp_info.mode = QED_UFP_MODE_VNIC_BW; 1963cac6f691SSudarsana Reddy Kalluru } else { 1964cac6f691SSudarsana Reddy Kalluru p_hwfn->ufp_info.mode = QED_UFP_MODE_UNKNOWN; 1965ec036eb9SSudarsana Reddy Kalluru DP_NOTICE(p_hwfn, 1966ec036eb9SSudarsana Reddy Kalluru "Unknown UFP scheduling mode %d port_id 0x%02x\n", 1967ec036eb9SSudarsana Reddy Kalluru val, MFW_PORT(p_hwfn)); 1968cac6f691SSudarsana Reddy Kalluru } 1969cac6f691SSudarsana Reddy Kalluru 1970cac6f691SSudarsana Reddy Kalluru qed_mcp_get_shmem_func(p_hwfn, p_ptt, &shmem_info, MCP_PF_ID(p_hwfn)); 1971b5fabb08SSudarsana Reddy Kalluru val = (shmem_info.oem_cfg_func & OEM_CFG_FUNC_TC_MASK) >> 1972b5fabb08SSudarsana Reddy Kalluru OEM_CFG_FUNC_TC_OFFSET; 1973cac6f691SSudarsana Reddy Kalluru p_hwfn->ufp_info.tc = (u8)val; 1974b5fabb08SSudarsana Reddy Kalluru val = (shmem_info.oem_cfg_func & OEM_CFG_FUNC_HOST_PRI_CTRL_MASK) >> 1975cac6f691SSudarsana Reddy Kalluru OEM_CFG_FUNC_HOST_PRI_CTRL_OFFSET; 1976cac6f691SSudarsana Reddy Kalluru if (val == OEM_CFG_FUNC_HOST_PRI_CTRL_VNIC) { 1977cac6f691SSudarsana Reddy Kalluru p_hwfn->ufp_info.pri_type = QED_UFP_PRI_VNIC; 1978cac6f691SSudarsana Reddy Kalluru } else if (val == OEM_CFG_FUNC_HOST_PRI_CTRL_OS) { 1979cac6f691SSudarsana Reddy Kalluru p_hwfn->ufp_info.pri_type = QED_UFP_PRI_OS; 1980cac6f691SSudarsana Reddy Kalluru } else { 1981cac6f691SSudarsana Reddy Kalluru p_hwfn->ufp_info.pri_type = QED_UFP_PRI_UNKNOWN; 1982ec036eb9SSudarsana Reddy Kalluru DP_NOTICE(p_hwfn, 1983ec036eb9SSudarsana Reddy Kalluru "Unknown Host priority control %d port_id 0x%02x\n", 1984ec036eb9SSudarsana Reddy Kalluru val, MFW_PORT(p_hwfn)); 1985cac6f691SSudarsana Reddy Kalluru } 1986cac6f691SSudarsana Reddy Kalluru 1987cac6f691SSudarsana Reddy Kalluru DP_NOTICE(p_hwfn, 1988ec036eb9SSudarsana Reddy Kalluru "UFP shmem config: mode = %d tc = %d pri_type = %d port_id 0x%02x\n", 1989ec036eb9SSudarsana Reddy Kalluru p_hwfn->ufp_info.mode, p_hwfn->ufp_info.tc, 1990ec036eb9SSudarsana Reddy Kalluru p_hwfn->ufp_info.pri_type, MFW_PORT(p_hwfn)); 1991cac6f691SSudarsana Reddy Kalluru } 1992cac6f691SSudarsana Reddy Kalluru 1993cac6f691SSudarsana Reddy Kalluru static int 1994cac6f691SSudarsana Reddy Kalluru qed_mcp_handle_ufp_event(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 1995cac6f691SSudarsana Reddy Kalluru { 1996cac6f691SSudarsana Reddy Kalluru qed_mcp_read_ufp_config(p_hwfn, p_ptt); 1997cac6f691SSudarsana Reddy Kalluru 1998cac6f691SSudarsana Reddy Kalluru if (p_hwfn->ufp_info.mode == QED_UFP_MODE_VNIC_BW) { 1999cac6f691SSudarsana Reddy Kalluru p_hwfn->qm_info.ooo_tc = p_hwfn->ufp_info.tc; 2000c4259ddaSDenis Bolotin qed_hw_info_set_offload_tc(&p_hwfn->hw_info, 2001c4259ddaSDenis Bolotin p_hwfn->ufp_info.tc); 2002cac6f691SSudarsana Reddy Kalluru 2003cac6f691SSudarsana Reddy Kalluru qed_qm_reconf(p_hwfn, p_ptt); 2004cac6f691SSudarsana Reddy Kalluru } else if (p_hwfn->ufp_info.mode == QED_UFP_MODE_ETS) { 2005cac6f691SSudarsana Reddy Kalluru /* Merge UFP TC with the dcbx TC data */ 2006cac6f691SSudarsana Reddy Kalluru qed_dcbx_mib_update_event(p_hwfn, p_ptt, 2007cac6f691SSudarsana Reddy Kalluru QED_DCBX_OPERATIONAL_MIB); 2008cac6f691SSudarsana Reddy Kalluru } else { 2009cac6f691SSudarsana Reddy Kalluru DP_ERR(p_hwfn, "Invalid sched type, discard the UFP config\n"); 2010cac6f691SSudarsana Reddy Kalluru return -EINVAL; 2011cac6f691SSudarsana Reddy Kalluru } 2012cac6f691SSudarsana Reddy Kalluru 2013cac6f691SSudarsana Reddy Kalluru /* update storm FW with negotiation results */ 2014cac6f691SSudarsana Reddy Kalluru qed_sp_pf_update_ufp(p_hwfn); 2015cac6f691SSudarsana Reddy Kalluru 2016cac6f691SSudarsana Reddy Kalluru /* update stag pcp value */ 2017cac6f691SSudarsana Reddy Kalluru qed_sp_pf_update_stag(p_hwfn); 2018cac6f691SSudarsana Reddy Kalluru 2019cac6f691SSudarsana Reddy Kalluru return 0; 2020cac6f691SSudarsana Reddy Kalluru } 2021cac6f691SSudarsana Reddy Kalluru 2022cc875c2eSYuval Mintz int qed_mcp_handle_events(struct qed_hwfn *p_hwfn, 2023cc875c2eSYuval Mintz struct qed_ptt *p_ptt) 2024cc875c2eSYuval Mintz { 2025cc875c2eSYuval Mintz struct qed_mcp_info *info = p_hwfn->mcp_info; 2026cc875c2eSYuval Mintz int rc = 0; 2027cc875c2eSYuval Mintz bool found = false; 2028cc875c2eSYuval Mintz u16 i; 2029cc875c2eSYuval Mintz 2030cc875c2eSYuval Mintz DP_VERBOSE(p_hwfn, QED_MSG_SP, "Received message from MFW\n"); 2031cc875c2eSYuval Mintz 2032cc875c2eSYuval Mintz /* Read Messages from MFW */ 2033cc875c2eSYuval Mintz qed_mcp_read_mb(p_hwfn, p_ptt); 2034cc875c2eSYuval Mintz 2035cc875c2eSYuval Mintz /* Compare current messages to old ones */ 2036cc875c2eSYuval Mintz for (i = 0; i < info->mfw_mb_length; i++) { 2037cc875c2eSYuval Mintz if (info->mfw_mb_cur[i] == info->mfw_mb_shadow[i]) 2038cc875c2eSYuval Mintz continue; 2039cc875c2eSYuval Mintz 2040cc875c2eSYuval Mintz found = true; 2041cc875c2eSYuval Mintz 2042cc875c2eSYuval Mintz DP_VERBOSE(p_hwfn, NETIF_MSG_LINK, 2043cc875c2eSYuval Mintz "Msg [%d] - old CMD 0x%02x, new CMD 0x%02x\n", 2044cc875c2eSYuval Mintz i, info->mfw_mb_shadow[i], info->mfw_mb_cur[i]); 2045cc875c2eSYuval Mintz 2046*ca2d5f1fSVenkata Sudheer Kumar Bhavaraju spin_lock_bh(&p_hwfn->mcp_info->unload_lock); 2047*ca2d5f1fSVenkata Sudheer Kumar Bhavaraju if (test_bit(QED_MCP_BYPASS_PROC_BIT, 2048*ca2d5f1fSVenkata Sudheer Kumar Bhavaraju &p_hwfn->mcp_info->mcp_handling_status)) { 2049*ca2d5f1fSVenkata Sudheer Kumar Bhavaraju spin_unlock_bh(&p_hwfn->mcp_info->unload_lock); 2050*ca2d5f1fSVenkata Sudheer Kumar Bhavaraju DP_INFO(p_hwfn, 2051*ca2d5f1fSVenkata Sudheer Kumar Bhavaraju "Msg [%d] is bypassed on unload flow\n", i); 2052*ca2d5f1fSVenkata Sudheer Kumar Bhavaraju continue; 2053*ca2d5f1fSVenkata Sudheer Kumar Bhavaraju } 2054*ca2d5f1fSVenkata Sudheer Kumar Bhavaraju 2055*ca2d5f1fSVenkata Sudheer Kumar Bhavaraju set_bit(QED_MCP_IN_PROCESSING_BIT, 2056*ca2d5f1fSVenkata Sudheer Kumar Bhavaraju &p_hwfn->mcp_info->mcp_handling_status); 2057*ca2d5f1fSVenkata Sudheer Kumar Bhavaraju spin_unlock_bh(&p_hwfn->mcp_info->unload_lock); 2058*ca2d5f1fSVenkata Sudheer Kumar Bhavaraju 2059cc875c2eSYuval Mintz switch (i) { 2060cc875c2eSYuval Mintz case MFW_DRV_MSG_LINK_CHANGE: 2061cc875c2eSYuval Mintz qed_mcp_handle_link_change(p_hwfn, p_ptt, false); 2062cc875c2eSYuval Mintz break; 20630b55e27dSYuval Mintz case MFW_DRV_MSG_VF_DISABLED: 20640b55e27dSYuval Mintz qed_mcp_handle_vf_flr(p_hwfn, p_ptt); 20650b55e27dSYuval Mintz break; 206639651abdSSudarsana Reddy Kalluru case MFW_DRV_MSG_LLDP_DATA_UPDATED: 206739651abdSSudarsana Reddy Kalluru qed_dcbx_mib_update_event(p_hwfn, p_ptt, 206839651abdSSudarsana Reddy Kalluru QED_DCBX_REMOTE_LLDP_MIB); 206939651abdSSudarsana Reddy Kalluru break; 207039651abdSSudarsana Reddy Kalluru case MFW_DRV_MSG_DCBX_REMOTE_MIB_UPDATED: 207139651abdSSudarsana Reddy Kalluru qed_dcbx_mib_update_event(p_hwfn, p_ptt, 207239651abdSSudarsana Reddy Kalluru QED_DCBX_REMOTE_MIB); 207339651abdSSudarsana Reddy Kalluru break; 207439651abdSSudarsana Reddy Kalluru case MFW_DRV_MSG_DCBX_OPERATIONAL_MIB_UPDATED: 207539651abdSSudarsana Reddy Kalluru qed_dcbx_mib_update_event(p_hwfn, p_ptt, 207639651abdSSudarsana Reddy Kalluru QED_DCBX_OPERATIONAL_MIB); 207739651abdSSudarsana Reddy Kalluru break; 2078cac6f691SSudarsana Reddy Kalluru case MFW_DRV_MSG_OEM_CFG_UPDATE: 2079cac6f691SSudarsana Reddy Kalluru qed_mcp_handle_ufp_event(p_hwfn, p_ptt); 2080cac6f691SSudarsana Reddy Kalluru break; 2081334c03b5SZvi Nachmani case MFW_DRV_MSG_TRANSCEIVER_STATE_CHANGE: 2082334c03b5SZvi Nachmani qed_mcp_handle_transceiver_change(p_hwfn, p_ptt); 2083334c03b5SZvi Nachmani break; 208464515dc8STomer Tayar case MFW_DRV_MSG_ERROR_RECOVERY: 208564515dc8STomer Tayar qed_mcp_handle_process_kill(p_hwfn, p_ptt); 208664515dc8STomer Tayar break; 20876c754246SSudarsana Reddy Kalluru case MFW_DRV_MSG_GET_LAN_STATS: 20886c754246SSudarsana Reddy Kalluru case MFW_DRV_MSG_GET_FCOE_STATS: 20896c754246SSudarsana Reddy Kalluru case MFW_DRV_MSG_GET_ISCSI_STATS: 20906c754246SSudarsana Reddy Kalluru case MFW_DRV_MSG_GET_RDMA_STATS: 20916c754246SSudarsana Reddy Kalluru qed_mcp_send_protocol_stats(p_hwfn, p_ptt, i); 20926c754246SSudarsana Reddy Kalluru break; 20934b01e519SManish Chopra case MFW_DRV_MSG_BW_UPDATE: 20944b01e519SManish Chopra qed_mcp_update_bw(p_hwfn, p_ptt); 20954b01e519SManish Chopra break; 20962a351fd9SMintz, Yuval case MFW_DRV_MSG_S_TAG_UPDATE: 20972a351fd9SMintz, Yuval qed_mcp_update_stag(p_hwfn, p_ptt); 20982a351fd9SMintz, Yuval break; 20993e99c211SIgor Russkikh case MFW_DRV_MSG_FAILURE_DETECTED: 21003e99c211SIgor Russkikh qed_mcp_handle_fan_failure(p_hwfn, p_ptt); 21013e99c211SIgor Russkikh break; 2102ebf64bf4SIgor Russkikh case MFW_DRV_MSG_CRITICAL_ERROR_OCCURRED: 2103ebf64bf4SIgor Russkikh qed_mcp_handle_critical_error(p_hwfn, p_ptt); 2104ebf64bf4SIgor Russkikh break; 210559ccf86fSSudarsana Reddy Kalluru case MFW_DRV_MSG_GET_TLV_REQ: 210659ccf86fSSudarsana Reddy Kalluru qed_mfw_tlv_req(p_hwfn); 21072a351fd9SMintz, Yuval break; 2108cc875c2eSYuval Mintz default: 210939815944SMintz, Yuval DP_INFO(p_hwfn, "Unimplemented MFW message %d\n", i); 2110cc875c2eSYuval Mintz rc = -EINVAL; 2111cc875c2eSYuval Mintz } 2112*ca2d5f1fSVenkata Sudheer Kumar Bhavaraju 2113*ca2d5f1fSVenkata Sudheer Kumar Bhavaraju clear_bit(QED_MCP_IN_PROCESSING_BIT, 2114*ca2d5f1fSVenkata Sudheer Kumar Bhavaraju &p_hwfn->mcp_info->mcp_handling_status); 2115cc875c2eSYuval Mintz } 2116cc875c2eSYuval Mintz 2117cc875c2eSYuval Mintz /* ACK everything */ 2118cc875c2eSYuval Mintz for (i = 0; i < MFW_DRV_MSG_MAX_DWORDS(info->mfw_mb_length); i++) { 2119cc875c2eSYuval Mintz __be32 val = cpu_to_be32(((u32 *)info->mfw_mb_cur)[i]); 2120cc875c2eSYuval Mintz 2121cc875c2eSYuval Mintz /* MFW expect answer in BE, so we force write in that format */ 2122cc875c2eSYuval Mintz qed_wr(p_hwfn, p_ptt, 2123cc875c2eSYuval Mintz info->mfw_mb_addr + sizeof(u32) + 2124cc875c2eSYuval Mintz MFW_DRV_MSG_MAX_DWORDS(info->mfw_mb_length) * 2125cc875c2eSYuval Mintz sizeof(u32) + i * sizeof(u32), 2126cc875c2eSYuval Mintz (__force u32)val); 2127cc875c2eSYuval Mintz } 2128cc875c2eSYuval Mintz 2129cc875c2eSYuval Mintz if (!found) { 2130cc875c2eSYuval Mintz DP_NOTICE(p_hwfn, 2131cc875c2eSYuval Mintz "Received an MFW message indication but no new message!\n"); 2132cc875c2eSYuval Mintz rc = -EINVAL; 2133cc875c2eSYuval Mintz } 2134cc875c2eSYuval Mintz 2135cc875c2eSYuval Mintz /* Copy the new mfw messages into the shadow */ 2136cc875c2eSYuval Mintz memcpy(info->mfw_mb_shadow, info->mfw_mb_cur, info->mfw_mb_length); 2137cc875c2eSYuval Mintz 2138cc875c2eSYuval Mintz return rc; 2139cc875c2eSYuval Mintz } 2140cc875c2eSYuval Mintz 21411408cc1fSYuval Mintz int qed_mcp_get_mfw_ver(struct qed_hwfn *p_hwfn, 21421408cc1fSYuval Mintz struct qed_ptt *p_ptt, 21431408cc1fSYuval Mintz u32 *p_mfw_ver, u32 *p_running_bundle_id) 2144fe56b9e6SYuval Mintz { 21456c95dd8fSPrabhakar Kushwaha u32 global_offsize, public_base; 2146fe56b9e6SYuval Mintz 21471408cc1fSYuval Mintz if (IS_VF(p_hwfn->cdev)) { 21481408cc1fSYuval Mintz if (p_hwfn->vf_iov_info) { 21491408cc1fSYuval Mintz struct pfvf_acquire_resp_tlv *p_resp; 21501408cc1fSYuval Mintz 21511408cc1fSYuval Mintz p_resp = &p_hwfn->vf_iov_info->acquire_resp; 21521408cc1fSYuval Mintz *p_mfw_ver = p_resp->pfdev_info.mfw_ver; 21531408cc1fSYuval Mintz return 0; 21541408cc1fSYuval Mintz } else { 21551408cc1fSYuval Mintz DP_VERBOSE(p_hwfn, 21561408cc1fSYuval Mintz QED_MSG_IOV, 21571408cc1fSYuval Mintz "VF requested MFW version prior to ACQUIRE\n"); 21581408cc1fSYuval Mintz return -EINVAL; 21591408cc1fSYuval Mintz } 21601408cc1fSYuval Mintz } 2161fe56b9e6SYuval Mintz 21626c95dd8fSPrabhakar Kushwaha public_base = p_hwfn->mcp_info->public_base; 2163fe56b9e6SYuval Mintz global_offsize = qed_rd(p_hwfn, p_ptt, 21646c95dd8fSPrabhakar Kushwaha SECTION_OFFSIZE_ADDR(public_base, 2165fe56b9e6SYuval Mintz PUBLIC_GLOBAL)); 21661408cc1fSYuval Mintz *p_mfw_ver = 21671408cc1fSYuval Mintz qed_rd(p_hwfn, p_ptt, 21681408cc1fSYuval Mintz SECTION_ADDR(global_offsize, 21691408cc1fSYuval Mintz 0) + offsetof(struct public_global, mfw_ver)); 2170fe56b9e6SYuval Mintz 21716c95dd8fSPrabhakar Kushwaha if (p_running_bundle_id) { 21721408cc1fSYuval Mintz *p_running_bundle_id = qed_rd(p_hwfn, p_ptt, 21731408cc1fSYuval Mintz SECTION_ADDR(global_offsize, 0) + 21741408cc1fSYuval Mintz offsetof(struct public_global, 21751408cc1fSYuval Mintz running_bundle_id)); 21761408cc1fSYuval Mintz } 2177fe56b9e6SYuval Mintz 2178fe56b9e6SYuval Mintz return 0; 2179fe56b9e6SYuval Mintz } 2180fe56b9e6SYuval Mintz 2181ae33666aSTomer Tayar int qed_mcp_get_mbi_ver(struct qed_hwfn *p_hwfn, 2182ae33666aSTomer Tayar struct qed_ptt *p_ptt, u32 *p_mbi_ver) 2183ae33666aSTomer Tayar { 2184ae33666aSTomer Tayar u32 nvm_cfg_addr, nvm_cfg1_offset, mbi_ver_addr; 2185ae33666aSTomer Tayar 2186ae33666aSTomer Tayar if (IS_VF(p_hwfn->cdev)) 2187ae33666aSTomer Tayar return -EINVAL; 2188ae33666aSTomer Tayar 2189ae33666aSTomer Tayar /* Read the address of the nvm_cfg */ 2190ae33666aSTomer Tayar nvm_cfg_addr = qed_rd(p_hwfn, p_ptt, MISC_REG_GEN_PURP_CR0); 2191ae33666aSTomer Tayar if (!nvm_cfg_addr) { 2192ae33666aSTomer Tayar DP_NOTICE(p_hwfn, "Shared memory not initialized\n"); 2193ae33666aSTomer Tayar return -EINVAL; 2194ae33666aSTomer Tayar } 2195ae33666aSTomer Tayar 2196ae33666aSTomer Tayar /* Read the offset of nvm_cfg1 */ 2197ae33666aSTomer Tayar nvm_cfg1_offset = qed_rd(p_hwfn, p_ptt, nvm_cfg_addr + 4); 2198ae33666aSTomer Tayar 2199ae33666aSTomer Tayar mbi_ver_addr = MCP_REG_SCRATCH + nvm_cfg1_offset + 2200ae33666aSTomer Tayar offsetof(struct nvm_cfg1, glob) + 2201ae33666aSTomer Tayar offsetof(struct nvm_cfg1_glob, mbi_version); 2202ae33666aSTomer Tayar *p_mbi_ver = qed_rd(p_hwfn, p_ptt, 2203ae33666aSTomer Tayar mbi_ver_addr) & 2204ae33666aSTomer Tayar (NVM_CFG1_GLOB_MBI_VERSION_0_MASK | 2205ae33666aSTomer Tayar NVM_CFG1_GLOB_MBI_VERSION_1_MASK | 2206ae33666aSTomer Tayar NVM_CFG1_GLOB_MBI_VERSION_2_MASK); 2207ae33666aSTomer Tayar 2208ae33666aSTomer Tayar return 0; 2209ae33666aSTomer Tayar } 2210ae33666aSTomer Tayar 2211706d0891SRahul Verma int qed_mcp_get_media_type(struct qed_hwfn *p_hwfn, 2212706d0891SRahul Verma struct qed_ptt *p_ptt, u32 *p_media_type) 2213cc875c2eSYuval Mintz { 2214c56a8be7SRahul Verma *p_media_type = MEDIA_UNSPECIFIED; 2215c56a8be7SRahul Verma 2216706d0891SRahul Verma if (IS_VF(p_hwfn->cdev)) 22171408cc1fSYuval Mintz return -EINVAL; 22181408cc1fSYuval Mintz 2219cc875c2eSYuval Mintz if (!qed_mcp_is_init(p_hwfn)) { 2220cc875c2eSYuval Mintz DP_NOTICE(p_hwfn, "MFW is not initialized!\n"); 2221cc875c2eSYuval Mintz return -EBUSY; 2222cc875c2eSYuval Mintz } 2223cc875c2eSYuval Mintz 2224706d0891SRahul Verma if (!p_ptt) { 2225cc875c2eSYuval Mintz *p_media_type = MEDIA_UNSPECIFIED; 2226706d0891SRahul Verma return -EINVAL; 2227706d0891SRahul Verma } 2228cc875c2eSYuval Mintz 2229706d0891SRahul Verma *p_media_type = qed_rd(p_hwfn, p_ptt, 2230706d0891SRahul Verma p_hwfn->mcp_info->port_addr + 2231706d0891SRahul Verma offsetof(struct public_port, 2232706d0891SRahul Verma media_type)); 2233cc875c2eSYuval Mintz 2234cc875c2eSYuval Mintz return 0; 2235cc875c2eSYuval Mintz } 2236cc875c2eSYuval Mintz 2237c56a8be7SRahul Verma int qed_mcp_get_transceiver_data(struct qed_hwfn *p_hwfn, 2238c56a8be7SRahul Verma struct qed_ptt *p_ptt, 2239c56a8be7SRahul Verma u32 *p_transceiver_state, 2240c56a8be7SRahul Verma u32 *p_transceiver_type) 2241c56a8be7SRahul Verma { 2242c56a8be7SRahul Verma u32 transceiver_info; 2243c56a8be7SRahul Verma 224468203a67SRahul Verma *p_transceiver_type = ETH_TRANSCEIVER_TYPE_NONE; 224568203a67SRahul Verma *p_transceiver_state = ETH_TRANSCEIVER_STATE_UPDATING; 224668203a67SRahul Verma 2247c56a8be7SRahul Verma if (IS_VF(p_hwfn->cdev)) 2248c56a8be7SRahul Verma return -EINVAL; 2249c56a8be7SRahul Verma 2250c56a8be7SRahul Verma if (!qed_mcp_is_init(p_hwfn)) { 2251c56a8be7SRahul Verma DP_NOTICE(p_hwfn, "MFW is not initialized!\n"); 2252c56a8be7SRahul Verma return -EBUSY; 2253c56a8be7SRahul Verma } 2254c56a8be7SRahul Verma 2255c56a8be7SRahul Verma transceiver_info = qed_rd(p_hwfn, p_ptt, 2256c56a8be7SRahul Verma p_hwfn->mcp_info->port_addr + 2257c56a8be7SRahul Verma offsetof(struct public_port, 2258c56a8be7SRahul Verma transceiver_data)); 2259c56a8be7SRahul Verma 2260c56a8be7SRahul Verma *p_transceiver_state = (transceiver_info & 2261c56a8be7SRahul Verma ETH_TRANSCEIVER_STATE_MASK) >> 2262c56a8be7SRahul Verma ETH_TRANSCEIVER_STATE_OFFSET; 2263c56a8be7SRahul Verma 2264c56a8be7SRahul Verma if (*p_transceiver_state == ETH_TRANSCEIVER_STATE_PRESENT) 2265c56a8be7SRahul Verma *p_transceiver_type = (transceiver_info & 2266c56a8be7SRahul Verma ETH_TRANSCEIVER_TYPE_MASK) >> 2267c56a8be7SRahul Verma ETH_TRANSCEIVER_TYPE_OFFSET; 2268c56a8be7SRahul Verma else 2269c56a8be7SRahul Verma *p_transceiver_type = ETH_TRANSCEIVER_TYPE_UNKNOWN; 2270c56a8be7SRahul Verma 2271c56a8be7SRahul Verma return 0; 2272c56a8be7SRahul Verma } 22736c95dd8fSPrabhakar Kushwaha 2274c56a8be7SRahul Verma static bool qed_is_transceiver_ready(u32 transceiver_state, 2275c56a8be7SRahul Verma u32 transceiver_type) 2276c56a8be7SRahul Verma { 2277c56a8be7SRahul Verma if ((transceiver_state & ETH_TRANSCEIVER_STATE_PRESENT) && 2278c56a8be7SRahul Verma ((transceiver_state & ETH_TRANSCEIVER_STATE_UPDATING) == 0x0) && 2279c56a8be7SRahul Verma (transceiver_type != ETH_TRANSCEIVER_TYPE_NONE)) 2280c56a8be7SRahul Verma return true; 2281c56a8be7SRahul Verma 2282c56a8be7SRahul Verma return false; 2283c56a8be7SRahul Verma } 2284c56a8be7SRahul Verma 2285c56a8be7SRahul Verma int qed_mcp_trans_speed_mask(struct qed_hwfn *p_hwfn, 2286c56a8be7SRahul Verma struct qed_ptt *p_ptt, u32 *p_speed_mask) 2287c56a8be7SRahul Verma { 2288c56a8be7SRahul Verma u32 transceiver_type, transceiver_state; 228992619210SArnd Bergmann int ret; 2290c56a8be7SRahul Verma 229192619210SArnd Bergmann ret = qed_mcp_get_transceiver_data(p_hwfn, p_ptt, &transceiver_state, 2292c56a8be7SRahul Verma &transceiver_type); 229392619210SArnd Bergmann if (ret) 229492619210SArnd Bergmann return ret; 2295c56a8be7SRahul Verma 2296c56a8be7SRahul Verma if (qed_is_transceiver_ready(transceiver_state, transceiver_type) == 2297c56a8be7SRahul Verma false) 2298c56a8be7SRahul Verma return -EINVAL; 2299c56a8be7SRahul Verma 2300c56a8be7SRahul Verma switch (transceiver_type) { 2301c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_1G_LX: 2302c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_1G_SX: 2303c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_1G_PCC: 2304c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_1G_ACC: 2305c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_1000BASET: 2306c56a8be7SRahul Verma *p_speed_mask = NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G; 2307c56a8be7SRahul Verma break; 2308c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_10G_SR: 2309c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_10G_LR: 2310c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_10G_LRM: 2311c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_10G_ER: 2312c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_10G_PCC: 2313c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_10G_ACC: 2314c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_4x10G: 2315c56a8be7SRahul Verma *p_speed_mask = NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G; 2316c56a8be7SRahul Verma break; 2317c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_40G_LR4: 2318c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_40G_SR4: 2319c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_MULTI_RATE_10G_40G_SR: 2320c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_MULTI_RATE_10G_40G_LR: 2321c56a8be7SRahul Verma *p_speed_mask = NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_40G | 2322c56a8be7SRahul Verma NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G; 2323c56a8be7SRahul Verma break; 2324c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_100G_AOC: 2325c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_100G_SR4: 2326c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_100G_LR4: 2327c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_100G_ER4: 2328c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_100G_ACC: 2329c56a8be7SRahul Verma *p_speed_mask = 2330c56a8be7SRahul Verma NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_BB_100G | 2331c56a8be7SRahul Verma NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_25G; 2332c56a8be7SRahul Verma break; 2333c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_25G_SR: 2334c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_25G_LR: 2335c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_25G_AOC: 2336c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_25G_ACC_S: 2337c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_25G_ACC_M: 2338c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_25G_ACC_L: 2339c56a8be7SRahul Verma *p_speed_mask = NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_25G; 2340c56a8be7SRahul Verma break; 2341c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_25G_CA_N: 2342c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_25G_CA_S: 2343c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_25G_CA_L: 2344c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_4x25G_CR: 2345c56a8be7SRahul Verma *p_speed_mask = NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_25G | 2346c56a8be7SRahul Verma NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G | 2347c56a8be7SRahul Verma NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G; 2348c56a8be7SRahul Verma break; 23499228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_MULTI_RATE_10G_25G_SR: 23509228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_MULTI_RATE_10G_25G_LR: 23519228b7c1SAlexander Lobakin *p_speed_mask = NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_25G | 23529228b7c1SAlexander Lobakin NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G; 23539228b7c1SAlexander Lobakin break; 2354c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_40G_CR4: 2355c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_MULTI_RATE_10G_40G_CR: 2356c56a8be7SRahul Verma *p_speed_mask = NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_40G | 2357c56a8be7SRahul Verma NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G | 2358c56a8be7SRahul Verma NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G; 2359c56a8be7SRahul Verma break; 2360c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_100G_CR4: 2361c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_MULTI_RATE_40G_100G_CR: 2362c56a8be7SRahul Verma *p_speed_mask = 2363c56a8be7SRahul Verma NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_BB_100G | 2364c56a8be7SRahul Verma NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_50G | 2365c56a8be7SRahul Verma NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_40G | 2366c56a8be7SRahul Verma NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_25G | 2367c56a8be7SRahul Verma NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_20G | 2368c56a8be7SRahul Verma NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G | 2369c56a8be7SRahul Verma NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G; 2370c56a8be7SRahul Verma break; 2371c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_MULTI_RATE_40G_100G_SR: 2372c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_MULTI_RATE_40G_100G_LR: 2373c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_MULTI_RATE_40G_100G_AOC: 2374c56a8be7SRahul Verma *p_speed_mask = 2375c56a8be7SRahul Verma NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_BB_100G | 2376c56a8be7SRahul Verma NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_40G | 2377c56a8be7SRahul Verma NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_25G | 2378c56a8be7SRahul Verma NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G; 2379c56a8be7SRahul Verma break; 2380c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_XLPPI: 2381c56a8be7SRahul Verma *p_speed_mask = NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_40G; 2382c56a8be7SRahul Verma break; 2383c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_10G_BASET: 23849228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_MULTI_RATE_1G_10G_SR: 23859228b7c1SAlexander Lobakin case ETH_TRANSCEIVER_TYPE_MULTI_RATE_1G_10G_LR: 2386c56a8be7SRahul Verma *p_speed_mask = NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G | 2387c56a8be7SRahul Verma NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G; 2388c56a8be7SRahul Verma break; 2389c56a8be7SRahul Verma default: 23901107a674SColin Ian King DP_INFO(p_hwfn, "Unknown transceiver type 0x%x\n", 2391c56a8be7SRahul Verma transceiver_type); 2392c56a8be7SRahul Verma *p_speed_mask = 0xff; 2393c56a8be7SRahul Verma break; 2394c56a8be7SRahul Verma } 2395c56a8be7SRahul Verma 2396c56a8be7SRahul Verma return 0; 2397c56a8be7SRahul Verma } 2398c56a8be7SRahul Verma 2399c56a8be7SRahul Verma int qed_mcp_get_board_config(struct qed_hwfn *p_hwfn, 2400c56a8be7SRahul Verma struct qed_ptt *p_ptt, u32 *p_board_config) 2401c56a8be7SRahul Verma { 2402c56a8be7SRahul Verma u32 nvm_cfg_addr, nvm_cfg1_offset, port_cfg_addr; 2403c56a8be7SRahul Verma 2404c56a8be7SRahul Verma if (IS_VF(p_hwfn->cdev)) 2405c56a8be7SRahul Verma return -EINVAL; 2406c56a8be7SRahul Verma 2407c56a8be7SRahul Verma if (!qed_mcp_is_init(p_hwfn)) { 2408c56a8be7SRahul Verma DP_NOTICE(p_hwfn, "MFW is not initialized!\n"); 2409c56a8be7SRahul Verma return -EBUSY; 2410c56a8be7SRahul Verma } 2411c56a8be7SRahul Verma if (!p_ptt) { 2412c56a8be7SRahul Verma *p_board_config = NVM_CFG1_PORT_PORT_TYPE_UNDEFINED; 2413c56a8be7SRahul Verma return -EINVAL; 2414c56a8be7SRahul Verma } 2415c56a8be7SRahul Verma 2416c56a8be7SRahul Verma nvm_cfg_addr = qed_rd(p_hwfn, p_ptt, MISC_REG_GEN_PURP_CR0); 2417c56a8be7SRahul Verma nvm_cfg1_offset = qed_rd(p_hwfn, p_ptt, nvm_cfg_addr + 4); 2418c56a8be7SRahul Verma port_cfg_addr = MCP_REG_SCRATCH + nvm_cfg1_offset + 2419c56a8be7SRahul Verma offsetof(struct nvm_cfg1, port[MFW_PORT(p_hwfn)]); 2420c56a8be7SRahul Verma *p_board_config = qed_rd(p_hwfn, p_ptt, 2421c56a8be7SRahul Verma port_cfg_addr + 2422c56a8be7SRahul Verma offsetof(struct nvm_cfg1_port, 2423c56a8be7SRahul Verma board_cfg)); 2424c56a8be7SRahul Verma 2425c56a8be7SRahul Verma return 0; 2426c56a8be7SRahul Verma } 2427c56a8be7SRahul Verma 24286927e826SMintz, Yuval /* Old MFW has a global configuration for all PFs regarding RDMA support */ 24296927e826SMintz, Yuval static void 24306927e826SMintz, Yuval qed_mcp_get_shmem_proto_legacy(struct qed_hwfn *p_hwfn, 24316927e826SMintz, Yuval enum qed_pci_personality *p_proto) 24326927e826SMintz, Yuval { 24336927e826SMintz, Yuval /* There wasn't ever a legacy MFW that published iwarp. 24346927e826SMintz, Yuval * So at this point, this is either plain l2 or RoCE. 24356927e826SMintz, Yuval */ 24366927e826SMintz, Yuval if (test_bit(QED_DEV_CAP_ROCE, &p_hwfn->hw_info.device_capabilities)) 24376927e826SMintz, Yuval *p_proto = QED_PCI_ETH_ROCE; 24386927e826SMintz, Yuval else 24396927e826SMintz, Yuval *p_proto = QED_PCI_ETH; 24406927e826SMintz, Yuval 24416927e826SMintz, Yuval DP_VERBOSE(p_hwfn, NETIF_MSG_IFUP, 24426927e826SMintz, Yuval "According to Legacy capabilities, L2 personality is %08x\n", 24436927e826SMintz, Yuval (u32)*p_proto); 24446927e826SMintz, Yuval } 24456927e826SMintz, Yuval 24466927e826SMintz, Yuval static int 24476927e826SMintz, Yuval qed_mcp_get_shmem_proto_mfw(struct qed_hwfn *p_hwfn, 24486927e826SMintz, Yuval struct qed_ptt *p_ptt, 24496927e826SMintz, Yuval enum qed_pci_personality *p_proto) 24506927e826SMintz, Yuval { 24516927e826SMintz, Yuval u32 resp = 0, param = 0; 24526927e826SMintz, Yuval int rc; 24536927e826SMintz, Yuval 24546927e826SMintz, Yuval rc = qed_mcp_cmd(p_hwfn, p_ptt, 24556927e826SMintz, Yuval DRV_MSG_CODE_GET_PF_RDMA_PROTOCOL, 0, &resp, ¶m); 24566927e826SMintz, Yuval if (rc) 24576927e826SMintz, Yuval return rc; 24586927e826SMintz, Yuval if (resp != FW_MSG_CODE_OK) { 24596927e826SMintz, Yuval DP_VERBOSE(p_hwfn, NETIF_MSG_IFUP, 24606927e826SMintz, Yuval "MFW lacks support for command; Returns %08x\n", 24616927e826SMintz, Yuval resp); 24626927e826SMintz, Yuval return -EINVAL; 24636927e826SMintz, Yuval } 24646927e826SMintz, Yuval 24656927e826SMintz, Yuval switch (param) { 24666927e826SMintz, Yuval case FW_MB_PARAM_GET_PF_RDMA_NONE: 24676927e826SMintz, Yuval *p_proto = QED_PCI_ETH; 24686927e826SMintz, Yuval break; 24696927e826SMintz, Yuval case FW_MB_PARAM_GET_PF_RDMA_ROCE: 24706927e826SMintz, Yuval *p_proto = QED_PCI_ETH_ROCE; 24716927e826SMintz, Yuval break; 24726927e826SMintz, Yuval case FW_MB_PARAM_GET_PF_RDMA_IWARP: 2473e0a8f9deSMichal Kalderon *p_proto = QED_PCI_ETH_IWARP; 2474e0a8f9deSMichal Kalderon break; 2475e0a8f9deSMichal Kalderon case FW_MB_PARAM_GET_PF_RDMA_BOTH: 2476e0a8f9deSMichal Kalderon *p_proto = QED_PCI_ETH_RDMA; 2477e0a8f9deSMichal Kalderon break; 24786927e826SMintz, Yuval default: 24796927e826SMintz, Yuval DP_NOTICE(p_hwfn, 24806927e826SMintz, Yuval "MFW answers GET_PF_RDMA_PROTOCOL but param is %08x\n", 24816927e826SMintz, Yuval param); 24826927e826SMintz, Yuval return -EINVAL; 24836927e826SMintz, Yuval } 24846927e826SMintz, Yuval 24856927e826SMintz, Yuval DP_VERBOSE(p_hwfn, 24866927e826SMintz, Yuval NETIF_MSG_IFUP, 24876927e826SMintz, Yuval "According to capabilities, L2 personality is %08x [resp %08x param %08x]\n", 24886927e826SMintz, Yuval (u32)*p_proto, resp, param); 24896927e826SMintz, Yuval return 0; 24906927e826SMintz, Yuval } 24916927e826SMintz, Yuval 2492fe56b9e6SYuval Mintz static int 2493fe56b9e6SYuval Mintz qed_mcp_get_shmem_proto(struct qed_hwfn *p_hwfn, 2494fe56b9e6SYuval Mintz struct public_func *p_info, 24956927e826SMintz, Yuval struct qed_ptt *p_ptt, 2496fe56b9e6SYuval Mintz enum qed_pci_personality *p_proto) 2497fe56b9e6SYuval Mintz { 2498fe56b9e6SYuval Mintz int rc = 0; 2499fe56b9e6SYuval Mintz 2500fe56b9e6SYuval Mintz switch (p_info->config & FUNC_MF_CFG_PROTOCOL_MASK) { 2501fe56b9e6SYuval Mintz case FUNC_MF_CFG_PROTOCOL_ETHERNET: 25021fe582ecSRam Amrani if (!IS_ENABLED(CONFIG_QED_RDMA)) 25031fe582ecSRam Amrani *p_proto = QED_PCI_ETH; 25041fe582ecSRam Amrani else if (qed_mcp_get_shmem_proto_mfw(p_hwfn, p_ptt, p_proto)) 25056927e826SMintz, Yuval qed_mcp_get_shmem_proto_legacy(p_hwfn, p_proto); 2506fe56b9e6SYuval Mintz break; 2507c5ac9319SYuval Mintz case FUNC_MF_CFG_PROTOCOL_ISCSI: 2508c5ac9319SYuval Mintz *p_proto = QED_PCI_ISCSI; 2509c5ac9319SYuval Mintz break; 25101e128c81SArun Easi case FUNC_MF_CFG_PROTOCOL_FCOE: 25111e128c81SArun Easi *p_proto = QED_PCI_FCOE; 25121e128c81SArun Easi break; 2513c5ac9319SYuval Mintz case FUNC_MF_CFG_PROTOCOL_ROCE: 2514c5ac9319SYuval Mintz DP_NOTICE(p_hwfn, "RoCE personality is not a valid value!\n"); 2515df561f66SGustavo A. R. Silva fallthrough; 2516fe56b9e6SYuval Mintz default: 2517fe56b9e6SYuval Mintz rc = -EINVAL; 2518fe56b9e6SYuval Mintz } 2519fe56b9e6SYuval Mintz 2520fe56b9e6SYuval Mintz return rc; 2521fe56b9e6SYuval Mintz } 2522fe56b9e6SYuval Mintz 2523fe56b9e6SYuval Mintz int qed_mcp_fill_shmem_func_info(struct qed_hwfn *p_hwfn, 2524fe56b9e6SYuval Mintz struct qed_ptt *p_ptt) 2525fe56b9e6SYuval Mintz { 2526fe56b9e6SYuval Mintz struct qed_mcp_function_info *info; 2527fe56b9e6SYuval Mintz struct public_func shmem_info; 2528fe56b9e6SYuval Mintz 25291a635e48SYuval Mintz qed_mcp_get_shmem_func(p_hwfn, p_ptt, &shmem_info, MCP_PF_ID(p_hwfn)); 2530fe56b9e6SYuval Mintz info = &p_hwfn->mcp_info->func_info; 2531fe56b9e6SYuval Mintz 2532fe56b9e6SYuval Mintz info->pause_on_host = (shmem_info.config & 2533fe56b9e6SYuval Mintz FUNC_MF_CFG_PAUSE_ON_HOST_RING) ? 1 : 0; 2534fe56b9e6SYuval Mintz 25356927e826SMintz, Yuval if (qed_mcp_get_shmem_proto(p_hwfn, &shmem_info, p_ptt, 25366927e826SMintz, Yuval &info->protocol)) { 2537fe56b9e6SYuval Mintz DP_ERR(p_hwfn, "Unknown personality %08x\n", 2538fe56b9e6SYuval Mintz (u32)(shmem_info.config & FUNC_MF_CFG_PROTOCOL_MASK)); 2539fe56b9e6SYuval Mintz return -EINVAL; 2540fe56b9e6SYuval Mintz } 2541fe56b9e6SYuval Mintz 25424b01e519SManish Chopra qed_read_pf_bandwidth(p_hwfn, &shmem_info); 2543fe56b9e6SYuval Mintz 2544fe56b9e6SYuval Mintz if (shmem_info.mac_upper || shmem_info.mac_lower) { 2545fe56b9e6SYuval Mintz info->mac[0] = (u8)(shmem_info.mac_upper >> 8); 2546fe56b9e6SYuval Mintz info->mac[1] = (u8)(shmem_info.mac_upper); 2547fe56b9e6SYuval Mintz info->mac[2] = (u8)(shmem_info.mac_lower >> 24); 2548fe56b9e6SYuval Mintz info->mac[3] = (u8)(shmem_info.mac_lower >> 16); 2549fe56b9e6SYuval Mintz info->mac[4] = (u8)(shmem_info.mac_lower >> 8); 2550fe56b9e6SYuval Mintz info->mac[5] = (u8)(shmem_info.mac_lower); 255114d39648SMintz, Yuval 255214d39648SMintz, Yuval /* Store primary MAC for later possible WoL */ 255314d39648SMintz, Yuval memcpy(&p_hwfn->cdev->wol_mac, info->mac, ETH_ALEN); 2554fe56b9e6SYuval Mintz } else { 2555fe56b9e6SYuval Mintz DP_NOTICE(p_hwfn, "MAC is 0 in shmem\n"); 2556fe56b9e6SYuval Mintz } 2557fe56b9e6SYuval Mintz 255857796759SMintz, Yuval info->wwn_port = (u64)shmem_info.fcoe_wwn_port_name_lower | 255957796759SMintz, Yuval (((u64)shmem_info.fcoe_wwn_port_name_upper) << 32); 256057796759SMintz, Yuval info->wwn_node = (u64)shmem_info.fcoe_wwn_node_name_lower | 256157796759SMintz, Yuval (((u64)shmem_info.fcoe_wwn_node_name_upper) << 32); 2562fe56b9e6SYuval Mintz 2563fe56b9e6SYuval Mintz info->ovlan = (u16)(shmem_info.ovlan_stag & FUNC_MF_CFG_OV_STAG_MASK); 2564fe56b9e6SYuval Mintz 25650fefbfbaSSudarsana Kalluru info->mtu = (u16)shmem_info.mtu_size; 25660fefbfbaSSudarsana Kalluru 256714d39648SMintz, Yuval p_hwfn->hw_info.b_wol_support = QED_WOL_SUPPORT_NONE; 256814d39648SMintz, Yuval p_hwfn->cdev->wol_config = (u8)QED_OV_WOL_DEFAULT; 256914d39648SMintz, Yuval if (qed_mcp_is_init(p_hwfn)) { 257014d39648SMintz, Yuval u32 resp = 0, param = 0; 257114d39648SMintz, Yuval int rc; 257214d39648SMintz, Yuval 257314d39648SMintz, Yuval rc = qed_mcp_cmd(p_hwfn, p_ptt, 257414d39648SMintz, Yuval DRV_MSG_CODE_OS_WOL, 0, &resp, ¶m); 257514d39648SMintz, Yuval if (rc) 257614d39648SMintz, Yuval return rc; 257714d39648SMintz, Yuval if (resp == FW_MSG_CODE_OS_WOL_SUPPORTED) 257814d39648SMintz, Yuval p_hwfn->hw_info.b_wol_support = QED_WOL_SUPPORT_PME; 257914d39648SMintz, Yuval } 258014d39648SMintz, Yuval 2581fe56b9e6SYuval Mintz DP_VERBOSE(p_hwfn, (QED_MSG_SP | NETIF_MSG_IFUP), 2582b03c3bacSAndy Shevchenko "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", 2583fe56b9e6SYuval Mintz info->pause_on_host, info->protocol, 2584fe56b9e6SYuval Mintz info->bandwidth_min, info->bandwidth_max, 2585b03c3bacSAndy Shevchenko info->mac, 258614d39648SMintz, Yuval info->wwn_port, info->wwn_node, 258714d39648SMintz, Yuval info->ovlan, (u8)p_hwfn->hw_info.b_wol_support); 2588fe56b9e6SYuval Mintz 2589fe56b9e6SYuval Mintz return 0; 2590fe56b9e6SYuval Mintz } 2591fe56b9e6SYuval Mintz 2592cc875c2eSYuval Mintz struct qed_mcp_link_params 2593cc875c2eSYuval Mintz *qed_mcp_get_link_params(struct qed_hwfn *p_hwfn) 2594cc875c2eSYuval Mintz { 2595cc875c2eSYuval Mintz if (!p_hwfn || !p_hwfn->mcp_info) 2596cc875c2eSYuval Mintz return NULL; 2597cc875c2eSYuval Mintz return &p_hwfn->mcp_info->link_input; 2598cc875c2eSYuval Mintz } 2599cc875c2eSYuval Mintz 2600cc875c2eSYuval Mintz struct qed_mcp_link_state 2601cc875c2eSYuval Mintz *qed_mcp_get_link_state(struct qed_hwfn *p_hwfn) 2602cc875c2eSYuval Mintz { 2603cc875c2eSYuval Mintz if (!p_hwfn || !p_hwfn->mcp_info) 2604cc875c2eSYuval Mintz return NULL; 2605cc875c2eSYuval Mintz return &p_hwfn->mcp_info->link_output; 2606cc875c2eSYuval Mintz } 2607cc875c2eSYuval Mintz 2608cc875c2eSYuval Mintz struct qed_mcp_link_capabilities 2609cc875c2eSYuval Mintz *qed_mcp_get_link_capabilities(struct qed_hwfn *p_hwfn) 2610cc875c2eSYuval Mintz { 2611cc875c2eSYuval Mintz if (!p_hwfn || !p_hwfn->mcp_info) 2612cc875c2eSYuval Mintz return NULL; 2613cc875c2eSYuval Mintz return &p_hwfn->mcp_info->link_capabilities; 2614cc875c2eSYuval Mintz } 2615cc875c2eSYuval Mintz 26161a635e48SYuval Mintz int qed_mcp_drain(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 2617fe56b9e6SYuval Mintz { 2618fe56b9e6SYuval Mintz u32 resp = 0, param = 0; 2619fe56b9e6SYuval Mintz int rc; 2620fe56b9e6SYuval Mintz 2621fe56b9e6SYuval Mintz rc = qed_mcp_cmd(p_hwfn, p_ptt, 26221a635e48SYuval Mintz DRV_MSG_CODE_NIG_DRAIN, 1000, &resp, ¶m); 2623fe56b9e6SYuval Mintz 2624fe56b9e6SYuval Mintz /* Wait for the drain to complete before returning */ 26258f60bafeSYuval Mintz msleep(1020); 2626fe56b9e6SYuval Mintz 2627fe56b9e6SYuval Mintz return rc; 2628fe56b9e6SYuval Mintz } 2629fe56b9e6SYuval Mintz 2630cee4d264SManish Chopra int qed_mcp_get_flash_size(struct qed_hwfn *p_hwfn, 26311a635e48SYuval Mintz struct qed_ptt *p_ptt, u32 *p_flash_size) 2632cee4d264SManish Chopra { 2633cee4d264SManish Chopra u32 flash_size; 2634cee4d264SManish Chopra 26351408cc1fSYuval Mintz if (IS_VF(p_hwfn->cdev)) 26361408cc1fSYuval Mintz return -EINVAL; 26371408cc1fSYuval Mintz 2638cee4d264SManish Chopra flash_size = qed_rd(p_hwfn, p_ptt, MCP_REG_NVM_CFG4); 2639cee4d264SManish Chopra flash_size = (flash_size & MCP_REG_NVM_CFG4_FLASH_SIZE) >> 2640cee4d264SManish Chopra MCP_REG_NVM_CFG4_FLASH_SIZE_SHIFT; 2641cee4d264SManish Chopra flash_size = (1 << (flash_size + MCP_BYTES_PER_MBIT_SHIFT)); 2642cee4d264SManish Chopra 2643cee4d264SManish Chopra *p_flash_size = flash_size; 2644cee4d264SManish Chopra 2645cee4d264SManish Chopra return 0; 2646cee4d264SManish Chopra } 2647cee4d264SManish Chopra 264864515dc8STomer Tayar int qed_start_recovery_process(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 264964515dc8STomer Tayar { 265064515dc8STomer Tayar struct qed_dev *cdev = p_hwfn->cdev; 265164515dc8STomer Tayar 265264515dc8STomer Tayar if (cdev->recov_in_prog) { 265364515dc8STomer Tayar DP_NOTICE(p_hwfn, 265464515dc8STomer Tayar "Avoid triggering a recovery since such a process is already in progress\n"); 265564515dc8STomer Tayar return -EAGAIN; 265664515dc8STomer Tayar } 265764515dc8STomer Tayar 265864515dc8STomer Tayar DP_NOTICE(p_hwfn, "Triggering a recovery process\n"); 265964515dc8STomer Tayar qed_wr(p_hwfn, p_ptt, MISC_REG_AEU_GENERAL_ATTN_35, 0x1); 266064515dc8STomer Tayar 266164515dc8STomer Tayar return 0; 266264515dc8STomer Tayar } 266364515dc8STomer Tayar 266464515dc8STomer Tayar #define QED_RECOVERY_PROLOG_SLEEP_MS 100 266564515dc8STomer Tayar 266664515dc8STomer Tayar int qed_recovery_prolog(struct qed_dev *cdev) 266764515dc8STomer Tayar { 266864515dc8STomer Tayar struct qed_hwfn *p_hwfn = QED_LEADING_HWFN(cdev); 266964515dc8STomer Tayar struct qed_ptt *p_ptt = p_hwfn->p_main_ptt; 267064515dc8STomer Tayar int rc; 267164515dc8STomer Tayar 267264515dc8STomer Tayar /* Allow ongoing PCIe transactions to complete */ 267364515dc8STomer Tayar msleep(QED_RECOVERY_PROLOG_SLEEP_MS); 267464515dc8STomer Tayar 267564515dc8STomer Tayar /* Clear the PF's internal FID_enable in the PXP */ 267664515dc8STomer Tayar rc = qed_pglueb_set_pfid_enable(p_hwfn, p_ptt, false); 267764515dc8STomer Tayar if (rc) 267864515dc8STomer Tayar DP_NOTICE(p_hwfn, 267964515dc8STomer Tayar "qed_pglueb_set_pfid_enable() failed. rc = %d.\n", 268064515dc8STomer Tayar rc); 268164515dc8STomer Tayar 268264515dc8STomer Tayar return rc; 268364515dc8STomer Tayar } 268464515dc8STomer Tayar 268588072fd4SMintz, Yuval static int 268688072fd4SMintz, Yuval qed_mcp_config_vf_msix_bb(struct qed_hwfn *p_hwfn, 26871408cc1fSYuval Mintz struct qed_ptt *p_ptt, u8 vf_id, u8 num) 26881408cc1fSYuval Mintz { 26891408cc1fSYuval Mintz u32 resp = 0, param = 0, rc_param = 0; 26901408cc1fSYuval Mintz int rc; 26911408cc1fSYuval Mintz 26921408cc1fSYuval Mintz /* Only Leader can configure MSIX, and need to take CMT into account */ 26931408cc1fSYuval Mintz if (!IS_LEAD_HWFN(p_hwfn)) 26941408cc1fSYuval Mintz return 0; 26951408cc1fSYuval Mintz num *= p_hwfn->cdev->num_hwfns; 26961408cc1fSYuval Mintz 26971408cc1fSYuval Mintz param |= (vf_id << DRV_MB_PARAM_CFG_VF_MSIX_VF_ID_SHIFT) & 26981408cc1fSYuval Mintz DRV_MB_PARAM_CFG_VF_MSIX_VF_ID_MASK; 26991408cc1fSYuval Mintz param |= (num << DRV_MB_PARAM_CFG_VF_MSIX_SB_NUM_SHIFT) & 27001408cc1fSYuval Mintz DRV_MB_PARAM_CFG_VF_MSIX_SB_NUM_MASK; 27011408cc1fSYuval Mintz 27021408cc1fSYuval Mintz rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_CFG_VF_MSIX, param, 27031408cc1fSYuval Mintz &resp, &rc_param); 27041408cc1fSYuval Mintz 27051408cc1fSYuval Mintz if (resp != FW_MSG_CODE_DRV_CFG_VF_MSIX_DONE) { 27061408cc1fSYuval Mintz DP_NOTICE(p_hwfn, "VF[%d]: MFW failed to set MSI-X\n", vf_id); 27071408cc1fSYuval Mintz rc = -EINVAL; 27081408cc1fSYuval Mintz } else { 27091408cc1fSYuval Mintz DP_VERBOSE(p_hwfn, QED_MSG_IOV, 27101408cc1fSYuval Mintz "Requested 0x%02x MSI-x interrupts from VF 0x%02x\n", 27111408cc1fSYuval Mintz num, vf_id); 27121408cc1fSYuval Mintz } 27131408cc1fSYuval Mintz 27141408cc1fSYuval Mintz return rc; 27151408cc1fSYuval Mintz } 27161408cc1fSYuval Mintz 271788072fd4SMintz, Yuval static int 271888072fd4SMintz, Yuval qed_mcp_config_vf_msix_ah(struct qed_hwfn *p_hwfn, 271988072fd4SMintz, Yuval struct qed_ptt *p_ptt, u8 num) 272088072fd4SMintz, Yuval { 272188072fd4SMintz, Yuval u32 resp = 0, param = num, rc_param = 0; 272288072fd4SMintz, Yuval int rc; 272388072fd4SMintz, Yuval 272488072fd4SMintz, Yuval rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_CFG_PF_VFS_MSIX, 272588072fd4SMintz, Yuval param, &resp, &rc_param); 272688072fd4SMintz, Yuval 272788072fd4SMintz, Yuval if (resp != FW_MSG_CODE_DRV_CFG_PF_VFS_MSIX_DONE) { 272888072fd4SMintz, Yuval DP_NOTICE(p_hwfn, "MFW failed to set MSI-X for VFs\n"); 272988072fd4SMintz, Yuval rc = -EINVAL; 273088072fd4SMintz, Yuval } else { 273188072fd4SMintz, Yuval DP_VERBOSE(p_hwfn, QED_MSG_IOV, 273288072fd4SMintz, Yuval "Requested 0x%02x MSI-x interrupts for VFs\n", num); 273388072fd4SMintz, Yuval } 273488072fd4SMintz, Yuval 273588072fd4SMintz, Yuval return rc; 273688072fd4SMintz, Yuval } 273788072fd4SMintz, Yuval 273888072fd4SMintz, Yuval int qed_mcp_config_vf_msix(struct qed_hwfn *p_hwfn, 273988072fd4SMintz, Yuval struct qed_ptt *p_ptt, u8 vf_id, u8 num) 274088072fd4SMintz, Yuval { 274188072fd4SMintz, Yuval if (QED_IS_BB(p_hwfn->cdev)) 274288072fd4SMintz, Yuval return qed_mcp_config_vf_msix_bb(p_hwfn, p_ptt, vf_id, num); 274388072fd4SMintz, Yuval else 274488072fd4SMintz, Yuval return qed_mcp_config_vf_msix_ah(p_hwfn, p_ptt, num); 274588072fd4SMintz, Yuval } 274688072fd4SMintz, Yuval 2747fe56b9e6SYuval Mintz int 2748fe56b9e6SYuval Mintz qed_mcp_send_drv_version(struct qed_hwfn *p_hwfn, 2749fe56b9e6SYuval Mintz struct qed_ptt *p_ptt, 2750fe56b9e6SYuval Mintz struct qed_mcp_drv_version *p_ver) 2751fe56b9e6SYuval Mintz { 27525529bad9STomer Tayar struct qed_mcp_mb_params mb_params; 27532f67af8cSTomer Tayar struct drv_version_stc drv_version; 27545529bad9STomer Tayar __be32 val; 27555529bad9STomer Tayar u32 i; 27565529bad9STomer Tayar int rc; 2757fe56b9e6SYuval Mintz 27582f67af8cSTomer Tayar memset(&drv_version, 0, sizeof(drv_version)); 27592f67af8cSTomer Tayar drv_version.version = p_ver->version; 276067a99b70SYuval Mintz for (i = 0; i < (MCP_DRV_VER_STR_SIZE - 4) / sizeof(u32); i++) { 276167a99b70SYuval Mintz val = cpu_to_be32(*((u32 *)&p_ver->name[i * sizeof(u32)])); 27622f67af8cSTomer Tayar *(__be32 *)&drv_version.name[i * sizeof(u32)] = val; 2763fe56b9e6SYuval Mintz } 2764fe56b9e6SYuval Mintz 27655529bad9STomer Tayar memset(&mb_params, 0, sizeof(mb_params)); 27665529bad9STomer Tayar mb_params.cmd = DRV_MSG_CODE_SET_VERSION; 27672f67af8cSTomer Tayar mb_params.p_data_src = &drv_version; 27682f67af8cSTomer Tayar mb_params.data_src_size = sizeof(drv_version); 27695529bad9STomer Tayar rc = qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 27705529bad9STomer Tayar if (rc) 2771fe56b9e6SYuval Mintz DP_ERR(p_hwfn, "MCP response failure, aborting\n"); 2772fe56b9e6SYuval Mintz 27735529bad9STomer Tayar return rc; 2774fe56b9e6SYuval Mintz } 277591420b83SSudarsana Kalluru 277676271809STomer Tayar /* A maximal 100 msec waiting time for the MCP to halt */ 277776271809STomer Tayar #define QED_MCP_HALT_SLEEP_MS 10 277876271809STomer Tayar #define QED_MCP_HALT_MAX_RETRIES 10 277976271809STomer Tayar 27804102426fSTomer Tayar int qed_mcp_halt(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 27814102426fSTomer Tayar { 278276271809STomer Tayar u32 resp = 0, param = 0, cpu_state, cnt = 0; 27834102426fSTomer Tayar int rc; 27844102426fSTomer Tayar 27854102426fSTomer Tayar rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_MCP_HALT, 0, &resp, 27864102426fSTomer Tayar ¶m); 278776271809STomer Tayar if (rc) { 27884102426fSTomer Tayar DP_ERR(p_hwfn, "MCP response failure, aborting\n"); 27894102426fSTomer Tayar return rc; 27904102426fSTomer Tayar } 27914102426fSTomer Tayar 279276271809STomer Tayar do { 279376271809STomer Tayar msleep(QED_MCP_HALT_SLEEP_MS); 279476271809STomer Tayar cpu_state = qed_rd(p_hwfn, p_ptt, MCP_REG_CPU_STATE); 279576271809STomer Tayar if (cpu_state & MCP_REG_CPU_STATE_SOFT_HALTED) 279676271809STomer Tayar break; 279776271809STomer Tayar } while (++cnt < QED_MCP_HALT_MAX_RETRIES); 279876271809STomer Tayar 279976271809STomer Tayar if (cnt == QED_MCP_HALT_MAX_RETRIES) { 280076271809STomer Tayar DP_NOTICE(p_hwfn, 280176271809STomer Tayar "Failed to halt the MCP [CPU_MODE = 0x%08x, CPU_STATE = 0x%08x]\n", 280276271809STomer Tayar qed_rd(p_hwfn, p_ptt, MCP_REG_CPU_MODE), cpu_state); 280376271809STomer Tayar return -EBUSY; 280476271809STomer Tayar } 280576271809STomer Tayar 2806b310974eSTomer Tayar qed_mcp_cmd_set_blocking(p_hwfn, true); 2807b310974eSTomer Tayar 280876271809STomer Tayar return 0; 280976271809STomer Tayar } 281076271809STomer Tayar 281176271809STomer Tayar #define QED_MCP_RESUME_SLEEP_MS 10 281276271809STomer Tayar 28134102426fSTomer Tayar int qed_mcp_resume(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 28144102426fSTomer Tayar { 281576271809STomer Tayar u32 cpu_mode, cpu_state; 28164102426fSTomer Tayar 28174102426fSTomer Tayar qed_wr(p_hwfn, p_ptt, MCP_REG_CPU_STATE, 0xffffffff); 28184102426fSTomer Tayar 28194102426fSTomer Tayar cpu_mode = qed_rd(p_hwfn, p_ptt, MCP_REG_CPU_MODE); 282076271809STomer Tayar cpu_mode &= ~MCP_REG_CPU_MODE_SOFT_HALT; 282176271809STomer Tayar qed_wr(p_hwfn, p_ptt, MCP_REG_CPU_MODE, cpu_mode); 282276271809STomer Tayar msleep(QED_MCP_RESUME_SLEEP_MS); 282376271809STomer Tayar cpu_state = qed_rd(p_hwfn, p_ptt, MCP_REG_CPU_STATE); 28244102426fSTomer Tayar 282576271809STomer Tayar if (cpu_state & MCP_REG_CPU_STATE_SOFT_HALTED) { 282676271809STomer Tayar DP_NOTICE(p_hwfn, 282776271809STomer Tayar "Failed to resume the MCP [CPU_MODE = 0x%08x, CPU_STATE = 0x%08x]\n", 282876271809STomer Tayar cpu_mode, cpu_state); 282976271809STomer Tayar return -EBUSY; 283076271809STomer Tayar } 283176271809STomer Tayar 2832b310974eSTomer Tayar qed_mcp_cmd_set_blocking(p_hwfn, false); 2833b310974eSTomer Tayar 283476271809STomer Tayar return 0; 28354102426fSTomer Tayar } 28364102426fSTomer Tayar 28370fefbfbaSSudarsana Kalluru int qed_mcp_ov_update_current_config(struct qed_hwfn *p_hwfn, 28380fefbfbaSSudarsana Kalluru struct qed_ptt *p_ptt, 28390fefbfbaSSudarsana Kalluru enum qed_ov_client client) 28400fefbfbaSSudarsana Kalluru { 28410fefbfbaSSudarsana Kalluru u32 resp = 0, param = 0; 28420fefbfbaSSudarsana Kalluru u32 drv_mb_param; 28430fefbfbaSSudarsana Kalluru int rc; 28440fefbfbaSSudarsana Kalluru 28450fefbfbaSSudarsana Kalluru switch (client) { 28460fefbfbaSSudarsana Kalluru case QED_OV_CLIENT_DRV: 28470fefbfbaSSudarsana Kalluru drv_mb_param = DRV_MB_PARAM_OV_CURR_CFG_OS; 28480fefbfbaSSudarsana Kalluru break; 28490fefbfbaSSudarsana Kalluru case QED_OV_CLIENT_USER: 28500fefbfbaSSudarsana Kalluru drv_mb_param = DRV_MB_PARAM_OV_CURR_CFG_OTHER; 28510fefbfbaSSudarsana Kalluru break; 28520fefbfbaSSudarsana Kalluru case QED_OV_CLIENT_VENDOR_SPEC: 28530fefbfbaSSudarsana Kalluru drv_mb_param = DRV_MB_PARAM_OV_CURR_CFG_VENDOR_SPEC; 28540fefbfbaSSudarsana Kalluru break; 28550fefbfbaSSudarsana Kalluru default: 28560fefbfbaSSudarsana Kalluru DP_NOTICE(p_hwfn, "Invalid client type %d\n", client); 28570fefbfbaSSudarsana Kalluru return -EINVAL; 28580fefbfbaSSudarsana Kalluru } 28590fefbfbaSSudarsana Kalluru 28600fefbfbaSSudarsana Kalluru rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_OV_UPDATE_CURR_CFG, 28610fefbfbaSSudarsana Kalluru drv_mb_param, &resp, ¶m); 28620fefbfbaSSudarsana Kalluru if (rc) 28630fefbfbaSSudarsana Kalluru DP_ERR(p_hwfn, "MCP response failure, aborting\n"); 28640fefbfbaSSudarsana Kalluru 28650fefbfbaSSudarsana Kalluru return rc; 28660fefbfbaSSudarsana Kalluru } 28670fefbfbaSSudarsana Kalluru 28680fefbfbaSSudarsana Kalluru int qed_mcp_ov_update_driver_state(struct qed_hwfn *p_hwfn, 28690fefbfbaSSudarsana Kalluru struct qed_ptt *p_ptt, 28700fefbfbaSSudarsana Kalluru enum qed_ov_driver_state drv_state) 28710fefbfbaSSudarsana Kalluru { 28720fefbfbaSSudarsana Kalluru u32 resp = 0, param = 0; 28730fefbfbaSSudarsana Kalluru u32 drv_mb_param; 28740fefbfbaSSudarsana Kalluru int rc; 28750fefbfbaSSudarsana Kalluru 28760fefbfbaSSudarsana Kalluru switch (drv_state) { 28770fefbfbaSSudarsana Kalluru case QED_OV_DRIVER_STATE_NOT_LOADED: 28780fefbfbaSSudarsana Kalluru drv_mb_param = DRV_MSG_CODE_OV_UPDATE_DRIVER_STATE_NOT_LOADED; 28790fefbfbaSSudarsana Kalluru break; 28800fefbfbaSSudarsana Kalluru case QED_OV_DRIVER_STATE_DISABLED: 28810fefbfbaSSudarsana Kalluru drv_mb_param = DRV_MSG_CODE_OV_UPDATE_DRIVER_STATE_DISABLED; 28820fefbfbaSSudarsana Kalluru break; 28830fefbfbaSSudarsana Kalluru case QED_OV_DRIVER_STATE_ACTIVE: 28840fefbfbaSSudarsana Kalluru drv_mb_param = DRV_MSG_CODE_OV_UPDATE_DRIVER_STATE_ACTIVE; 28850fefbfbaSSudarsana Kalluru break; 28860fefbfbaSSudarsana Kalluru default: 28870fefbfbaSSudarsana Kalluru DP_NOTICE(p_hwfn, "Invalid driver state %d\n", drv_state); 28880fefbfbaSSudarsana Kalluru return -EINVAL; 28890fefbfbaSSudarsana Kalluru } 28900fefbfbaSSudarsana Kalluru 28910fefbfbaSSudarsana Kalluru rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_OV_UPDATE_DRIVER_STATE, 28920fefbfbaSSudarsana Kalluru drv_mb_param, &resp, ¶m); 28930fefbfbaSSudarsana Kalluru if (rc) 28940fefbfbaSSudarsana Kalluru DP_ERR(p_hwfn, "Failed to send driver state\n"); 28950fefbfbaSSudarsana Kalluru 28960fefbfbaSSudarsana Kalluru return rc; 28970fefbfbaSSudarsana Kalluru } 28980fefbfbaSSudarsana Kalluru 28990fefbfbaSSudarsana Kalluru int qed_mcp_ov_update_mtu(struct qed_hwfn *p_hwfn, 29000fefbfbaSSudarsana Kalluru struct qed_ptt *p_ptt, u16 mtu) 29010fefbfbaSSudarsana Kalluru { 29020fefbfbaSSudarsana Kalluru u32 resp = 0, param = 0; 29030fefbfbaSSudarsana Kalluru u32 drv_mb_param; 29040fefbfbaSSudarsana Kalluru int rc; 29050fefbfbaSSudarsana Kalluru 29060fefbfbaSSudarsana Kalluru drv_mb_param = (u32)mtu << DRV_MB_PARAM_OV_MTU_SIZE_SHIFT; 29070fefbfbaSSudarsana Kalluru rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_OV_UPDATE_MTU, 29080fefbfbaSSudarsana Kalluru drv_mb_param, &resp, ¶m); 29090fefbfbaSSudarsana Kalluru if (rc) 29100fefbfbaSSudarsana Kalluru DP_ERR(p_hwfn, "Failed to send mtu value, rc = %d\n", rc); 29110fefbfbaSSudarsana Kalluru 29120fefbfbaSSudarsana Kalluru return rc; 29130fefbfbaSSudarsana Kalluru } 29140fefbfbaSSudarsana Kalluru 29150fefbfbaSSudarsana Kalluru int qed_mcp_ov_update_mac(struct qed_hwfn *p_hwfn, 291676660757SJakub Kicinski struct qed_ptt *p_ptt, const u8 *mac) 29170fefbfbaSSudarsana Kalluru { 29180fefbfbaSSudarsana Kalluru struct qed_mcp_mb_params mb_params; 291917991002SMintz, Yuval u32 mfw_mac[2]; 29200fefbfbaSSudarsana Kalluru int rc; 29210fefbfbaSSudarsana Kalluru 29220fefbfbaSSudarsana Kalluru memset(&mb_params, 0, sizeof(mb_params)); 29230fefbfbaSSudarsana Kalluru mb_params.cmd = DRV_MSG_CODE_SET_VMAC; 29240fefbfbaSSudarsana Kalluru mb_params.param = DRV_MSG_CODE_VMAC_TYPE_MAC << 29250fefbfbaSSudarsana Kalluru DRV_MSG_CODE_VMAC_TYPE_SHIFT; 29260fefbfbaSSudarsana Kalluru mb_params.param |= MCP_PF_ID(p_hwfn); 29272f67af8cSTomer Tayar 292817991002SMintz, Yuval /* MCP is BE, and on LE platforms PCI would swap access to SHMEM 292917991002SMintz, Yuval * in 32-bit granularity. 293017991002SMintz, Yuval * So the MAC has to be set in native order [and not byte order], 293117991002SMintz, Yuval * otherwise it would be read incorrectly by MFW after swap. 293217991002SMintz, Yuval */ 293317991002SMintz, Yuval mfw_mac[0] = mac[0] << 24 | mac[1] << 16 | mac[2] << 8 | mac[3]; 293417991002SMintz, Yuval mfw_mac[1] = mac[4] << 24 | mac[5] << 16; 293517991002SMintz, Yuval 293617991002SMintz, Yuval mb_params.p_data_src = (u8 *)mfw_mac; 293717991002SMintz, Yuval mb_params.data_src_size = 8; 29380fefbfbaSSudarsana Kalluru rc = qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 29390fefbfbaSSudarsana Kalluru if (rc) 29400fefbfbaSSudarsana Kalluru DP_ERR(p_hwfn, "Failed to send mac address, rc = %d\n", rc); 29410fefbfbaSSudarsana Kalluru 294214d39648SMintz, Yuval /* Store primary MAC for later possible WoL */ 294314d39648SMintz, Yuval memcpy(p_hwfn->cdev->wol_mac, mac, ETH_ALEN); 294414d39648SMintz, Yuval 29450fefbfbaSSudarsana Kalluru return rc; 29460fefbfbaSSudarsana Kalluru } 29470fefbfbaSSudarsana Kalluru 29480fefbfbaSSudarsana Kalluru int qed_mcp_ov_update_wol(struct qed_hwfn *p_hwfn, 29490fefbfbaSSudarsana Kalluru struct qed_ptt *p_ptt, enum qed_ov_wol wol) 29500fefbfbaSSudarsana Kalluru { 29510fefbfbaSSudarsana Kalluru u32 resp = 0, param = 0; 29520fefbfbaSSudarsana Kalluru u32 drv_mb_param; 29530fefbfbaSSudarsana Kalluru int rc; 29540fefbfbaSSudarsana Kalluru 295514d39648SMintz, Yuval if (p_hwfn->hw_info.b_wol_support == QED_WOL_SUPPORT_NONE) { 295614d39648SMintz, Yuval DP_VERBOSE(p_hwfn, QED_MSG_SP, 295714d39648SMintz, Yuval "Can't change WoL configuration when WoL isn't supported\n"); 295814d39648SMintz, Yuval return -EINVAL; 295914d39648SMintz, Yuval } 296014d39648SMintz, Yuval 29610fefbfbaSSudarsana Kalluru switch (wol) { 29620fefbfbaSSudarsana Kalluru case QED_OV_WOL_DEFAULT: 29630fefbfbaSSudarsana Kalluru drv_mb_param = DRV_MB_PARAM_WOL_DEFAULT; 29640fefbfbaSSudarsana Kalluru break; 29650fefbfbaSSudarsana Kalluru case QED_OV_WOL_DISABLED: 29660fefbfbaSSudarsana Kalluru drv_mb_param = DRV_MB_PARAM_WOL_DISABLED; 29670fefbfbaSSudarsana Kalluru break; 29680fefbfbaSSudarsana Kalluru case QED_OV_WOL_ENABLED: 29690fefbfbaSSudarsana Kalluru drv_mb_param = DRV_MB_PARAM_WOL_ENABLED; 29700fefbfbaSSudarsana Kalluru break; 29710fefbfbaSSudarsana Kalluru default: 29720fefbfbaSSudarsana Kalluru DP_ERR(p_hwfn, "Invalid wol state %d\n", wol); 29730fefbfbaSSudarsana Kalluru return -EINVAL; 29740fefbfbaSSudarsana Kalluru } 29750fefbfbaSSudarsana Kalluru 29760fefbfbaSSudarsana Kalluru rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_OV_UPDATE_WOL, 29770fefbfbaSSudarsana Kalluru drv_mb_param, &resp, ¶m); 29780fefbfbaSSudarsana Kalluru if (rc) 29790fefbfbaSSudarsana Kalluru DP_ERR(p_hwfn, "Failed to send wol mode, rc = %d\n", rc); 29800fefbfbaSSudarsana Kalluru 298114d39648SMintz, Yuval /* Store the WoL update for a future unload */ 298214d39648SMintz, Yuval p_hwfn->cdev->wol_config = (u8)wol; 298314d39648SMintz, Yuval 29840fefbfbaSSudarsana Kalluru return rc; 29850fefbfbaSSudarsana Kalluru } 29860fefbfbaSSudarsana Kalluru 29870fefbfbaSSudarsana Kalluru int qed_mcp_ov_update_eswitch(struct qed_hwfn *p_hwfn, 29880fefbfbaSSudarsana Kalluru struct qed_ptt *p_ptt, 29890fefbfbaSSudarsana Kalluru enum qed_ov_eswitch eswitch) 29900fefbfbaSSudarsana Kalluru { 29910fefbfbaSSudarsana Kalluru u32 resp = 0, param = 0; 29920fefbfbaSSudarsana Kalluru u32 drv_mb_param; 29930fefbfbaSSudarsana Kalluru int rc; 29940fefbfbaSSudarsana Kalluru 29950fefbfbaSSudarsana Kalluru switch (eswitch) { 29960fefbfbaSSudarsana Kalluru case QED_OV_ESWITCH_NONE: 29970fefbfbaSSudarsana Kalluru drv_mb_param = DRV_MB_PARAM_ESWITCH_MODE_NONE; 29980fefbfbaSSudarsana Kalluru break; 29990fefbfbaSSudarsana Kalluru case QED_OV_ESWITCH_VEB: 30000fefbfbaSSudarsana Kalluru drv_mb_param = DRV_MB_PARAM_ESWITCH_MODE_VEB; 30010fefbfbaSSudarsana Kalluru break; 30020fefbfbaSSudarsana Kalluru case QED_OV_ESWITCH_VEPA: 30030fefbfbaSSudarsana Kalluru drv_mb_param = DRV_MB_PARAM_ESWITCH_MODE_VEPA; 30040fefbfbaSSudarsana Kalluru break; 30050fefbfbaSSudarsana Kalluru default: 30060fefbfbaSSudarsana Kalluru DP_ERR(p_hwfn, "Invalid eswitch mode %d\n", eswitch); 30070fefbfbaSSudarsana Kalluru return -EINVAL; 30080fefbfbaSSudarsana Kalluru } 30090fefbfbaSSudarsana Kalluru 30100fefbfbaSSudarsana Kalluru rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_OV_UPDATE_ESWITCH_MODE, 30110fefbfbaSSudarsana Kalluru drv_mb_param, &resp, ¶m); 30120fefbfbaSSudarsana Kalluru if (rc) 30130fefbfbaSSudarsana Kalluru DP_ERR(p_hwfn, "Failed to send eswitch mode, rc = %d\n", rc); 30140fefbfbaSSudarsana Kalluru 30150fefbfbaSSudarsana Kalluru return rc; 30160fefbfbaSSudarsana Kalluru } 30170fefbfbaSSudarsana Kalluru 30181a635e48SYuval Mintz int qed_mcp_set_led(struct qed_hwfn *p_hwfn, 30191a635e48SYuval Mintz struct qed_ptt *p_ptt, enum qed_led_mode mode) 302091420b83SSudarsana Kalluru { 302191420b83SSudarsana Kalluru u32 resp = 0, param = 0, drv_mb_param; 302291420b83SSudarsana Kalluru int rc; 302391420b83SSudarsana Kalluru 302491420b83SSudarsana Kalluru switch (mode) { 302591420b83SSudarsana Kalluru case QED_LED_MODE_ON: 302691420b83SSudarsana Kalluru drv_mb_param = DRV_MB_PARAM_SET_LED_MODE_ON; 302791420b83SSudarsana Kalluru break; 302891420b83SSudarsana Kalluru case QED_LED_MODE_OFF: 302991420b83SSudarsana Kalluru drv_mb_param = DRV_MB_PARAM_SET_LED_MODE_OFF; 303091420b83SSudarsana Kalluru break; 303191420b83SSudarsana Kalluru case QED_LED_MODE_RESTORE: 303291420b83SSudarsana Kalluru drv_mb_param = DRV_MB_PARAM_SET_LED_MODE_OPER; 303391420b83SSudarsana Kalluru break; 303491420b83SSudarsana Kalluru default: 303591420b83SSudarsana Kalluru DP_NOTICE(p_hwfn, "Invalid LED mode %d\n", mode); 303691420b83SSudarsana Kalluru return -EINVAL; 303791420b83SSudarsana Kalluru } 303891420b83SSudarsana Kalluru 303991420b83SSudarsana Kalluru rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_SET_LED_MODE, 304091420b83SSudarsana Kalluru drv_mb_param, &resp, ¶m); 304191420b83SSudarsana Kalluru 304291420b83SSudarsana Kalluru return rc; 304391420b83SSudarsana Kalluru } 304403dc76caSSudarsana Reddy Kalluru 30454102426fSTomer Tayar int qed_mcp_mask_parities(struct qed_hwfn *p_hwfn, 30464102426fSTomer Tayar struct qed_ptt *p_ptt, u32 mask_parities) 30474102426fSTomer Tayar { 30484102426fSTomer Tayar u32 resp = 0, param = 0; 30494102426fSTomer Tayar int rc; 30504102426fSTomer Tayar 30514102426fSTomer Tayar rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_MASK_PARITIES, 30524102426fSTomer Tayar mask_parities, &resp, ¶m); 30534102426fSTomer Tayar 30544102426fSTomer Tayar if (rc) { 30554102426fSTomer Tayar DP_ERR(p_hwfn, 30564102426fSTomer Tayar "MCP response failure for mask parities, aborting\n"); 30574102426fSTomer Tayar } else if (resp != FW_MSG_CODE_OK) { 30584102426fSTomer Tayar DP_ERR(p_hwfn, 30594102426fSTomer Tayar "MCP did not acknowledge mask parity request. Old MFW?\n"); 30604102426fSTomer Tayar rc = -EINVAL; 30614102426fSTomer Tayar } 30624102426fSTomer Tayar 30634102426fSTomer Tayar return rc; 30644102426fSTomer Tayar } 30654102426fSTomer Tayar 30667a4b21b7SMintz, Yuval int qed_mcp_nvm_read(struct qed_dev *cdev, u32 addr, u8 *p_buf, u32 len) 30677a4b21b7SMintz, Yuval { 30687a4b21b7SMintz, Yuval u32 bytes_left = len, offset = 0, bytes_to_copy, read_len = 0; 30697a4b21b7SMintz, Yuval struct qed_hwfn *p_hwfn = QED_LEADING_HWFN(cdev); 30707a4b21b7SMintz, Yuval u32 resp = 0, resp_param = 0; 30717a4b21b7SMintz, Yuval struct qed_ptt *p_ptt; 30727a4b21b7SMintz, Yuval int rc = 0; 30737a4b21b7SMintz, Yuval 30747a4b21b7SMintz, Yuval p_ptt = qed_ptt_acquire(p_hwfn); 30757a4b21b7SMintz, Yuval if (!p_ptt) 30767a4b21b7SMintz, Yuval return -EBUSY; 30777a4b21b7SMintz, Yuval 30787a4b21b7SMintz, Yuval while (bytes_left > 0) { 30797a4b21b7SMintz, Yuval bytes_to_copy = min_t(u32, bytes_left, MCP_DRV_NVM_BUF_LEN); 30807a4b21b7SMintz, Yuval 30817a4b21b7SMintz, Yuval rc = qed_mcp_nvm_rd_cmd(p_hwfn, p_ptt, 30827a4b21b7SMintz, Yuval DRV_MSG_CODE_NVM_READ_NVRAM, 30837a4b21b7SMintz, Yuval addr + offset + 30847a4b21b7SMintz, Yuval (bytes_to_copy << 3085da090917STomer Tayar DRV_MB_PARAM_NVM_LEN_OFFSET), 30867a4b21b7SMintz, Yuval &resp, &resp_param, 30877a4b21b7SMintz, Yuval &read_len, 30886c95dd8fSPrabhakar Kushwaha (u32 *)(p_buf + offset), false); 30897a4b21b7SMintz, Yuval 30907a4b21b7SMintz, Yuval if (rc || (resp != FW_MSG_CODE_NVM_OK)) { 30917a4b21b7SMintz, Yuval DP_NOTICE(cdev, "MCP command rc = %d\n", rc); 30927a4b21b7SMintz, Yuval break; 30937a4b21b7SMintz, Yuval } 30947a4b21b7SMintz, Yuval 30957a4b21b7SMintz, Yuval /* This can be a lengthy process, and it's possible scheduler 30966c95dd8fSPrabhakar Kushwaha * isn't preemptible. Sleep a bit to prevent CPU hogging. 30977a4b21b7SMintz, Yuval */ 30987a4b21b7SMintz, Yuval if (bytes_left % 0x1000 < 30997a4b21b7SMintz, Yuval (bytes_left - read_len) % 0x1000) 31007a4b21b7SMintz, Yuval usleep_range(1000, 2000); 31017a4b21b7SMintz, Yuval 31027a4b21b7SMintz, Yuval offset += read_len; 31037a4b21b7SMintz, Yuval bytes_left -= read_len; 31047a4b21b7SMintz, Yuval } 31057a4b21b7SMintz, Yuval 31067a4b21b7SMintz, Yuval cdev->mcp_nvm_resp = resp; 31077a4b21b7SMintz, Yuval qed_ptt_release(p_hwfn, p_ptt); 31087a4b21b7SMintz, Yuval 31097a4b21b7SMintz, Yuval return rc; 31107a4b21b7SMintz, Yuval } 31117a4b21b7SMintz, Yuval 311262e4d438SSudarsana Reddy Kalluru int qed_mcp_nvm_resp(struct qed_dev *cdev, u8 *p_buf) 311362e4d438SSudarsana Reddy Kalluru { 311462e4d438SSudarsana Reddy Kalluru struct qed_hwfn *p_hwfn = QED_LEADING_HWFN(cdev); 311562e4d438SSudarsana Reddy Kalluru struct qed_ptt *p_ptt; 311662e4d438SSudarsana Reddy Kalluru 311762e4d438SSudarsana Reddy Kalluru p_ptt = qed_ptt_acquire(p_hwfn); 311862e4d438SSudarsana Reddy Kalluru if (!p_ptt) 311962e4d438SSudarsana Reddy Kalluru return -EBUSY; 312062e4d438SSudarsana Reddy Kalluru 312162e4d438SSudarsana Reddy Kalluru memcpy(p_buf, &cdev->mcp_nvm_resp, sizeof(cdev->mcp_nvm_resp)); 312262e4d438SSudarsana Reddy Kalluru qed_ptt_release(p_hwfn, p_ptt); 312362e4d438SSudarsana Reddy Kalluru 312462e4d438SSudarsana Reddy Kalluru return 0; 312562e4d438SSudarsana Reddy Kalluru } 312662e4d438SSudarsana Reddy Kalluru 312762e4d438SSudarsana Reddy Kalluru int qed_mcp_nvm_write(struct qed_dev *cdev, 312862e4d438SSudarsana Reddy Kalluru u32 cmd, u32 addr, u8 *p_buf, u32 len) 312962e4d438SSudarsana Reddy Kalluru { 313062e4d438SSudarsana Reddy Kalluru u32 buf_idx = 0, buf_size, nvm_cmd, nvm_offset, resp = 0, param; 313162e4d438SSudarsana Reddy Kalluru struct qed_hwfn *p_hwfn = QED_LEADING_HWFN(cdev); 313262e4d438SSudarsana Reddy Kalluru struct qed_ptt *p_ptt; 313362e4d438SSudarsana Reddy Kalluru int rc = -EINVAL; 313462e4d438SSudarsana Reddy Kalluru 313562e4d438SSudarsana Reddy Kalluru p_ptt = qed_ptt_acquire(p_hwfn); 313662e4d438SSudarsana Reddy Kalluru if (!p_ptt) 313762e4d438SSudarsana Reddy Kalluru return -EBUSY; 313862e4d438SSudarsana Reddy Kalluru 313962e4d438SSudarsana Reddy Kalluru switch (cmd) { 3140057d2b19SSudarsana Reddy Kalluru case QED_PUT_FILE_BEGIN: 3141057d2b19SSudarsana Reddy Kalluru nvm_cmd = DRV_MSG_CODE_NVM_PUT_FILE_BEGIN; 3142057d2b19SSudarsana Reddy Kalluru break; 314362e4d438SSudarsana Reddy Kalluru case QED_PUT_FILE_DATA: 314462e4d438SSudarsana Reddy Kalluru nvm_cmd = DRV_MSG_CODE_NVM_PUT_FILE_DATA; 314562e4d438SSudarsana Reddy Kalluru break; 314662e4d438SSudarsana Reddy Kalluru case QED_NVM_WRITE_NVRAM: 314762e4d438SSudarsana Reddy Kalluru nvm_cmd = DRV_MSG_CODE_NVM_WRITE_NVRAM; 314862e4d438SSudarsana Reddy Kalluru break; 314962e4d438SSudarsana Reddy Kalluru default: 315062e4d438SSudarsana Reddy Kalluru DP_NOTICE(p_hwfn, "Invalid nvm write command 0x%x\n", cmd); 315162e4d438SSudarsana Reddy Kalluru rc = -EINVAL; 315262e4d438SSudarsana Reddy Kalluru goto out; 315362e4d438SSudarsana Reddy Kalluru } 315462e4d438SSudarsana Reddy Kalluru 315562e4d438SSudarsana Reddy Kalluru buf_size = min_t(u32, (len - buf_idx), MCP_DRV_NVM_BUF_LEN); 3156057d2b19SSudarsana Reddy Kalluru while (buf_idx < len) { 3157057d2b19SSudarsana Reddy Kalluru if (cmd == QED_PUT_FILE_BEGIN) 3158057d2b19SSudarsana Reddy Kalluru nvm_offset = addr; 3159057d2b19SSudarsana Reddy Kalluru else 3160057d2b19SSudarsana Reddy Kalluru nvm_offset = ((buf_size << 3161057d2b19SSudarsana Reddy Kalluru DRV_MB_PARAM_NVM_LEN_OFFSET) | addr) + 3162057d2b19SSudarsana Reddy Kalluru buf_idx; 316362e4d438SSudarsana Reddy Kalluru rc = qed_mcp_nvm_wr_cmd(p_hwfn, p_ptt, nvm_cmd, nvm_offset, 316462e4d438SSudarsana Reddy Kalluru &resp, ¶m, buf_size, 316562e4d438SSudarsana Reddy Kalluru (u32 *)&p_buf[buf_idx]); 316662e4d438SSudarsana Reddy Kalluru if (rc) { 316762e4d438SSudarsana Reddy Kalluru DP_NOTICE(cdev, "nvm write failed, rc = %d\n", rc); 316862e4d438SSudarsana Reddy Kalluru resp = FW_MSG_CODE_ERROR; 316962e4d438SSudarsana Reddy Kalluru break; 317062e4d438SSudarsana Reddy Kalluru } 317162e4d438SSudarsana Reddy Kalluru 317262e4d438SSudarsana Reddy Kalluru if (resp != FW_MSG_CODE_OK && 317362e4d438SSudarsana Reddy Kalluru resp != FW_MSG_CODE_NVM_OK && 317462e4d438SSudarsana Reddy Kalluru resp != FW_MSG_CODE_NVM_PUT_FILE_FINISH_OK) { 317562e4d438SSudarsana Reddy Kalluru DP_NOTICE(cdev, 317662e4d438SSudarsana Reddy Kalluru "nvm write failed, resp = 0x%08x\n", resp); 317762e4d438SSudarsana Reddy Kalluru rc = -EINVAL; 317862e4d438SSudarsana Reddy Kalluru break; 317962e4d438SSudarsana Reddy Kalluru } 318062e4d438SSudarsana Reddy Kalluru 318162e4d438SSudarsana Reddy Kalluru /* This can be a lengthy process, and it's possible scheduler 318262e4d438SSudarsana Reddy Kalluru * isn't pre-emptable. Sleep a bit to prevent CPU hogging. 318362e4d438SSudarsana Reddy Kalluru */ 318462e4d438SSudarsana Reddy Kalluru if (buf_idx % 0x1000 > (buf_idx + buf_size) % 0x1000) 318562e4d438SSudarsana Reddy Kalluru usleep_range(1000, 2000); 318662e4d438SSudarsana Reddy Kalluru 3187057d2b19SSudarsana Reddy Kalluru /* For MBI upgrade, MFW response includes the next buffer offset 3188057d2b19SSudarsana Reddy Kalluru * to be delivered to MFW. 3189057d2b19SSudarsana Reddy Kalluru */ 3190057d2b19SSudarsana Reddy Kalluru if (param && cmd == QED_PUT_FILE_DATA) { 31916c95dd8fSPrabhakar Kushwaha buf_idx = 31926c95dd8fSPrabhakar Kushwaha QED_MFW_GET_FIELD(param, 3193057d2b19SSudarsana Reddy Kalluru FW_MB_PARAM_NVM_PUT_FILE_REQ_OFFSET); 31946c95dd8fSPrabhakar Kushwaha buf_size = 31956c95dd8fSPrabhakar Kushwaha QED_MFW_GET_FIELD(param, 3196057d2b19SSudarsana Reddy Kalluru FW_MB_PARAM_NVM_PUT_FILE_REQ_SIZE); 3197057d2b19SSudarsana Reddy Kalluru } else { 319862e4d438SSudarsana Reddy Kalluru buf_idx += buf_size; 3199057d2b19SSudarsana Reddy Kalluru buf_size = min_t(u32, (len - buf_idx), 3200057d2b19SSudarsana Reddy Kalluru MCP_DRV_NVM_BUF_LEN); 3201057d2b19SSudarsana Reddy Kalluru } 320262e4d438SSudarsana Reddy Kalluru } 320362e4d438SSudarsana Reddy Kalluru 320462e4d438SSudarsana Reddy Kalluru cdev->mcp_nvm_resp = resp; 320562e4d438SSudarsana Reddy Kalluru out: 320662e4d438SSudarsana Reddy Kalluru qed_ptt_release(p_hwfn, p_ptt); 320762e4d438SSudarsana Reddy Kalluru 320862e4d438SSudarsana Reddy Kalluru return rc; 320962e4d438SSudarsana Reddy Kalluru } 321062e4d438SSudarsana Reddy Kalluru 3211b51dab46SSudarsana Reddy Kalluru int qed_mcp_phy_sfp_read(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, 3212b51dab46SSudarsana Reddy Kalluru u32 port, u32 addr, u32 offset, u32 len, u8 *p_buf) 3213b51dab46SSudarsana Reddy Kalluru { 3214b51dab46SSudarsana Reddy Kalluru u32 bytes_left, bytes_to_copy, buf_size, nvm_offset = 0; 3215b51dab46SSudarsana Reddy Kalluru u32 resp, param; 3216b51dab46SSudarsana Reddy Kalluru int rc; 3217b51dab46SSudarsana Reddy Kalluru 3218b51dab46SSudarsana Reddy Kalluru nvm_offset |= (port << DRV_MB_PARAM_TRANSCEIVER_PORT_OFFSET) & 3219b51dab46SSudarsana Reddy Kalluru DRV_MB_PARAM_TRANSCEIVER_PORT_MASK; 3220b51dab46SSudarsana Reddy Kalluru nvm_offset |= (addr << DRV_MB_PARAM_TRANSCEIVER_I2C_ADDRESS_OFFSET) & 3221b51dab46SSudarsana Reddy Kalluru DRV_MB_PARAM_TRANSCEIVER_I2C_ADDRESS_MASK; 3222b51dab46SSudarsana Reddy Kalluru 3223b51dab46SSudarsana Reddy Kalluru addr = offset; 3224b51dab46SSudarsana Reddy Kalluru offset = 0; 3225b51dab46SSudarsana Reddy Kalluru bytes_left = len; 3226b51dab46SSudarsana Reddy Kalluru while (bytes_left > 0) { 3227b51dab46SSudarsana Reddy Kalluru bytes_to_copy = min_t(u32, bytes_left, 3228b51dab46SSudarsana Reddy Kalluru MAX_I2C_TRANSACTION_SIZE); 3229b51dab46SSudarsana Reddy Kalluru nvm_offset &= (DRV_MB_PARAM_TRANSCEIVER_I2C_ADDRESS_MASK | 3230b51dab46SSudarsana Reddy Kalluru DRV_MB_PARAM_TRANSCEIVER_PORT_MASK); 3231b51dab46SSudarsana Reddy Kalluru nvm_offset |= ((addr + offset) << 3232b51dab46SSudarsana Reddy Kalluru DRV_MB_PARAM_TRANSCEIVER_OFFSET_OFFSET) & 3233b51dab46SSudarsana Reddy Kalluru DRV_MB_PARAM_TRANSCEIVER_OFFSET_MASK; 3234b51dab46SSudarsana Reddy Kalluru nvm_offset |= (bytes_to_copy << 3235b51dab46SSudarsana Reddy Kalluru DRV_MB_PARAM_TRANSCEIVER_SIZE_OFFSET) & 3236b51dab46SSudarsana Reddy Kalluru DRV_MB_PARAM_TRANSCEIVER_SIZE_MASK; 3237b51dab46SSudarsana Reddy Kalluru rc = qed_mcp_nvm_rd_cmd(p_hwfn, p_ptt, 3238b51dab46SSudarsana Reddy Kalluru DRV_MSG_CODE_TRANSCEIVER_READ, 3239b51dab46SSudarsana Reddy Kalluru nvm_offset, &resp, ¶m, &buf_size, 32406c95dd8fSPrabhakar Kushwaha (u32 *)(p_buf + offset), true); 3241b51dab46SSudarsana Reddy Kalluru if (rc) { 3242b51dab46SSudarsana Reddy Kalluru DP_NOTICE(p_hwfn, 3243b51dab46SSudarsana Reddy Kalluru "Failed to send a transceiver read command to the MFW. rc = %d.\n", 3244b51dab46SSudarsana Reddy Kalluru rc); 3245b51dab46SSudarsana Reddy Kalluru return rc; 3246b51dab46SSudarsana Reddy Kalluru } 3247b51dab46SSudarsana Reddy Kalluru 3248b51dab46SSudarsana Reddy Kalluru if (resp == FW_MSG_CODE_TRANSCEIVER_NOT_PRESENT) 3249b51dab46SSudarsana Reddy Kalluru return -ENODEV; 3250b51dab46SSudarsana Reddy Kalluru else if (resp != FW_MSG_CODE_TRANSCEIVER_DIAG_OK) 3251b51dab46SSudarsana Reddy Kalluru return -EINVAL; 3252b51dab46SSudarsana Reddy Kalluru 3253b51dab46SSudarsana Reddy Kalluru offset += buf_size; 3254b51dab46SSudarsana Reddy Kalluru bytes_left -= buf_size; 3255b51dab46SSudarsana Reddy Kalluru } 3256b51dab46SSudarsana Reddy Kalluru 3257b51dab46SSudarsana Reddy Kalluru return 0; 3258b51dab46SSudarsana Reddy Kalluru } 3259b51dab46SSudarsana Reddy Kalluru 326003dc76caSSudarsana Reddy Kalluru int qed_mcp_bist_register_test(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 326103dc76caSSudarsana Reddy Kalluru { 326203dc76caSSudarsana Reddy Kalluru u32 drv_mb_param = 0, rsp, param; 326303dc76caSSudarsana Reddy Kalluru int rc = 0; 326403dc76caSSudarsana Reddy Kalluru 326503dc76caSSudarsana Reddy Kalluru drv_mb_param = (DRV_MB_PARAM_BIST_REGISTER_TEST << 326603dc76caSSudarsana Reddy Kalluru DRV_MB_PARAM_BIST_TEST_INDEX_SHIFT); 326703dc76caSSudarsana Reddy Kalluru 326803dc76caSSudarsana Reddy Kalluru rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_BIST_TEST, 326903dc76caSSudarsana Reddy Kalluru drv_mb_param, &rsp, ¶m); 327003dc76caSSudarsana Reddy Kalluru 327103dc76caSSudarsana Reddy Kalluru if (rc) 327203dc76caSSudarsana Reddy Kalluru return rc; 327303dc76caSSudarsana Reddy Kalluru 327403dc76caSSudarsana Reddy Kalluru if (((rsp & FW_MSG_CODE_MASK) != FW_MSG_CODE_OK) || 327503dc76caSSudarsana Reddy Kalluru (param != DRV_MB_PARAM_BIST_RC_PASSED)) 327603dc76caSSudarsana Reddy Kalluru rc = -EAGAIN; 327703dc76caSSudarsana Reddy Kalluru 327803dc76caSSudarsana Reddy Kalluru return rc; 327903dc76caSSudarsana Reddy Kalluru } 328003dc76caSSudarsana Reddy Kalluru 328103dc76caSSudarsana Reddy Kalluru int qed_mcp_bist_clock_test(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 328203dc76caSSudarsana Reddy Kalluru { 328303dc76caSSudarsana Reddy Kalluru u32 drv_mb_param, rsp, param; 328403dc76caSSudarsana Reddy Kalluru int rc = 0; 328503dc76caSSudarsana Reddy Kalluru 328603dc76caSSudarsana Reddy Kalluru drv_mb_param = (DRV_MB_PARAM_BIST_CLOCK_TEST << 328703dc76caSSudarsana Reddy Kalluru DRV_MB_PARAM_BIST_TEST_INDEX_SHIFT); 328803dc76caSSudarsana Reddy Kalluru 328903dc76caSSudarsana Reddy Kalluru rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_BIST_TEST, 329003dc76caSSudarsana Reddy Kalluru drv_mb_param, &rsp, ¶m); 329103dc76caSSudarsana Reddy Kalluru 329203dc76caSSudarsana Reddy Kalluru if (rc) 329303dc76caSSudarsana Reddy Kalluru return rc; 329403dc76caSSudarsana Reddy Kalluru 329503dc76caSSudarsana Reddy Kalluru if (((rsp & FW_MSG_CODE_MASK) != FW_MSG_CODE_OK) || 329603dc76caSSudarsana Reddy Kalluru (param != DRV_MB_PARAM_BIST_RC_PASSED)) 329703dc76caSSudarsana Reddy Kalluru rc = -EAGAIN; 329803dc76caSSudarsana Reddy Kalluru 329903dc76caSSudarsana Reddy Kalluru return rc; 330003dc76caSSudarsana Reddy Kalluru } 33017a4b21b7SMintz, Yuval 330243645ce0SSudarsana Reddy Kalluru int qed_mcp_bist_nvm_get_num_images(struct qed_hwfn *p_hwfn, 33037a4b21b7SMintz, Yuval struct qed_ptt *p_ptt, 33047a4b21b7SMintz, Yuval u32 *num_images) 33057a4b21b7SMintz, Yuval { 33067a4b21b7SMintz, Yuval u32 drv_mb_param = 0, rsp; 33077a4b21b7SMintz, Yuval int rc = 0; 33087a4b21b7SMintz, Yuval 33097a4b21b7SMintz, Yuval drv_mb_param = (DRV_MB_PARAM_BIST_NVM_TEST_NUM_IMAGES << 33107a4b21b7SMintz, Yuval DRV_MB_PARAM_BIST_TEST_INDEX_SHIFT); 33117a4b21b7SMintz, Yuval 33127a4b21b7SMintz, Yuval rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_BIST_TEST, 33137a4b21b7SMintz, Yuval drv_mb_param, &rsp, num_images); 33147a4b21b7SMintz, Yuval if (rc) 33157a4b21b7SMintz, Yuval return rc; 33167a4b21b7SMintz, Yuval 33177a4b21b7SMintz, Yuval if (((rsp & FW_MSG_CODE_MASK) != FW_MSG_CODE_OK)) 33187a4b21b7SMintz, Yuval rc = -EINVAL; 33197a4b21b7SMintz, Yuval 33207a4b21b7SMintz, Yuval return rc; 33217a4b21b7SMintz, Yuval } 33227a4b21b7SMintz, Yuval 332343645ce0SSudarsana Reddy Kalluru int qed_mcp_bist_nvm_get_image_att(struct qed_hwfn *p_hwfn, 33247a4b21b7SMintz, Yuval struct qed_ptt *p_ptt, 33257a4b21b7SMintz, Yuval struct bist_nvm_image_att *p_image_att, 33267a4b21b7SMintz, Yuval u32 image_index) 33277a4b21b7SMintz, Yuval { 33287a4b21b7SMintz, Yuval u32 buf_size = 0, param, resp = 0, resp_param = 0; 33297a4b21b7SMintz, Yuval int rc; 33307a4b21b7SMintz, Yuval 33317a4b21b7SMintz, Yuval param = DRV_MB_PARAM_BIST_NVM_TEST_IMAGE_BY_INDEX << 33327a4b21b7SMintz, Yuval DRV_MB_PARAM_BIST_TEST_INDEX_SHIFT; 33337a4b21b7SMintz, Yuval param |= image_index << DRV_MB_PARAM_BIST_TEST_IMAGE_INDEX_SHIFT; 33347a4b21b7SMintz, Yuval 33357a4b21b7SMintz, Yuval rc = qed_mcp_nvm_rd_cmd(p_hwfn, p_ptt, 33367a4b21b7SMintz, Yuval DRV_MSG_CODE_BIST_TEST, param, 33377a4b21b7SMintz, Yuval &resp, &resp_param, 33387a4b21b7SMintz, Yuval &buf_size, 33396c95dd8fSPrabhakar Kushwaha (u32 *)p_image_att, false); 33407a4b21b7SMintz, Yuval if (rc) 33417a4b21b7SMintz, Yuval return rc; 33427a4b21b7SMintz, Yuval 33437a4b21b7SMintz, Yuval if (((resp & FW_MSG_CODE_MASK) != FW_MSG_CODE_OK) || 33447a4b21b7SMintz, Yuval (p_image_att->return_code != 1)) 33457a4b21b7SMintz, Yuval rc = -EINVAL; 33467a4b21b7SMintz, Yuval 33477a4b21b7SMintz, Yuval return rc; 33487a4b21b7SMintz, Yuval } 33492edbff8dSTomer Tayar 335043645ce0SSudarsana Reddy Kalluru int qed_mcp_nvm_info_populate(struct qed_hwfn *p_hwfn) 335143645ce0SSudarsana Reddy Kalluru { 33525e7ba042SDenis Bolotin struct qed_nvm_image_info nvm_info; 335343645ce0SSudarsana Reddy Kalluru struct qed_ptt *p_ptt; 335443645ce0SSudarsana Reddy Kalluru int rc; 335543645ce0SSudarsana Reddy Kalluru u32 i; 335643645ce0SSudarsana Reddy Kalluru 33575e7ba042SDenis Bolotin if (p_hwfn->nvm_info.valid) 33585e7ba042SDenis Bolotin return 0; 33595e7ba042SDenis Bolotin 336043645ce0SSudarsana Reddy Kalluru p_ptt = qed_ptt_acquire(p_hwfn); 336143645ce0SSudarsana Reddy Kalluru if (!p_ptt) { 336243645ce0SSudarsana Reddy Kalluru DP_ERR(p_hwfn, "failed to acquire ptt\n"); 336343645ce0SSudarsana Reddy Kalluru return -EBUSY; 336443645ce0SSudarsana Reddy Kalluru } 336543645ce0SSudarsana Reddy Kalluru 336643645ce0SSudarsana Reddy Kalluru /* Acquire from MFW the amount of available images */ 33675e7ba042SDenis Bolotin nvm_info.num_images = 0; 336843645ce0SSudarsana Reddy Kalluru rc = qed_mcp_bist_nvm_get_num_images(p_hwfn, 33695e7ba042SDenis Bolotin p_ptt, &nvm_info.num_images); 337043645ce0SSudarsana Reddy Kalluru if (rc == -EOPNOTSUPP) { 337143645ce0SSudarsana Reddy Kalluru DP_INFO(p_hwfn, "DRV_MSG_CODE_BIST_TEST is not supported\n"); 337243645ce0SSudarsana Reddy Kalluru goto out; 33735e7ba042SDenis Bolotin } else if (rc || !nvm_info.num_images) { 337443645ce0SSudarsana Reddy Kalluru DP_ERR(p_hwfn, "Failed getting number of images\n"); 337543645ce0SSudarsana Reddy Kalluru goto err0; 337643645ce0SSudarsana Reddy Kalluru } 337743645ce0SSudarsana Reddy Kalluru 33785e7ba042SDenis Bolotin nvm_info.image_att = kmalloc_array(nvm_info.num_images, 337943645ce0SSudarsana Reddy Kalluru sizeof(struct bist_nvm_image_att), 338043645ce0SSudarsana Reddy Kalluru GFP_KERNEL); 33815e7ba042SDenis Bolotin if (!nvm_info.image_att) { 338243645ce0SSudarsana Reddy Kalluru rc = -ENOMEM; 338343645ce0SSudarsana Reddy Kalluru goto err0; 338443645ce0SSudarsana Reddy Kalluru } 338543645ce0SSudarsana Reddy Kalluru 338643645ce0SSudarsana Reddy Kalluru /* Iterate over images and get their attributes */ 33875e7ba042SDenis Bolotin for (i = 0; i < nvm_info.num_images; i++) { 338843645ce0SSudarsana Reddy Kalluru rc = qed_mcp_bist_nvm_get_image_att(p_hwfn, p_ptt, 33895e7ba042SDenis Bolotin &nvm_info.image_att[i], i); 339043645ce0SSudarsana Reddy Kalluru if (rc) { 339143645ce0SSudarsana Reddy Kalluru DP_ERR(p_hwfn, 339243645ce0SSudarsana Reddy Kalluru "Failed getting image index %d attributes\n", i); 339343645ce0SSudarsana Reddy Kalluru goto err1; 339443645ce0SSudarsana Reddy Kalluru } 339543645ce0SSudarsana Reddy Kalluru 339643645ce0SSudarsana Reddy Kalluru DP_VERBOSE(p_hwfn, QED_MSG_SP, "image index %d, size %x\n", i, 33975e7ba042SDenis Bolotin nvm_info.image_att[i].len); 339843645ce0SSudarsana Reddy Kalluru } 339943645ce0SSudarsana Reddy Kalluru out: 34005e7ba042SDenis Bolotin /* Update hwfn's nvm_info */ 34015e7ba042SDenis Bolotin if (nvm_info.num_images) { 34025e7ba042SDenis Bolotin p_hwfn->nvm_info.num_images = nvm_info.num_images; 34035e7ba042SDenis Bolotin kfree(p_hwfn->nvm_info.image_att); 34045e7ba042SDenis Bolotin p_hwfn->nvm_info.image_att = nvm_info.image_att; 34055e7ba042SDenis Bolotin p_hwfn->nvm_info.valid = true; 34065e7ba042SDenis Bolotin } 34075e7ba042SDenis Bolotin 340843645ce0SSudarsana Reddy Kalluru qed_ptt_release(p_hwfn, p_ptt); 340943645ce0SSudarsana Reddy Kalluru return 0; 341043645ce0SSudarsana Reddy Kalluru 341143645ce0SSudarsana Reddy Kalluru err1: 34125e7ba042SDenis Bolotin kfree(nvm_info.image_att); 341343645ce0SSudarsana Reddy Kalluru err0: 341443645ce0SSudarsana Reddy Kalluru qed_ptt_release(p_hwfn, p_ptt); 341543645ce0SSudarsana Reddy Kalluru return rc; 341643645ce0SSudarsana Reddy Kalluru } 341743645ce0SSudarsana Reddy Kalluru 341813cf8aabSSudarsana Reddy Kalluru void qed_mcp_nvm_info_free(struct qed_hwfn *p_hwfn) 341913cf8aabSSudarsana Reddy Kalluru { 342013cf8aabSSudarsana Reddy Kalluru kfree(p_hwfn->nvm_info.image_att); 342113cf8aabSSudarsana Reddy Kalluru p_hwfn->nvm_info.image_att = NULL; 342213cf8aabSSudarsana Reddy Kalluru p_hwfn->nvm_info.valid = false; 342313cf8aabSSudarsana Reddy Kalluru } 342413cf8aabSSudarsana Reddy Kalluru 34251ac4329aSDenis Bolotin int 342620675b37SMintz, Yuval qed_mcp_get_nvm_image_att(struct qed_hwfn *p_hwfn, 342720675b37SMintz, Yuval enum qed_nvm_images image_id, 342820675b37SMintz, Yuval struct qed_nvm_image_att *p_image_att) 342920675b37SMintz, Yuval { 343020675b37SMintz, Yuval enum nvm_image_type type; 343120e100f5SShai Malin int rc; 343243645ce0SSudarsana Reddy Kalluru u32 i; 343320675b37SMintz, Yuval 343420675b37SMintz, Yuval /* Translate image_id into MFW definitions */ 343520675b37SMintz, Yuval switch (image_id) { 343620675b37SMintz, Yuval case QED_NVM_IMAGE_ISCSI_CFG: 343720675b37SMintz, Yuval type = NVM_TYPE_ISCSI_CFG; 343820675b37SMintz, Yuval break; 343920675b37SMintz, Yuval case QED_NVM_IMAGE_FCOE_CFG: 344020675b37SMintz, Yuval type = NVM_TYPE_FCOE_CFG; 344120675b37SMintz, Yuval break; 34428a52bbabSMichal Kalderon case QED_NVM_IMAGE_MDUMP: 34438a52bbabSMichal Kalderon type = NVM_TYPE_MDUMP; 34448a52bbabSMichal Kalderon break; 34451ac4329aSDenis Bolotin case QED_NVM_IMAGE_NVM_CFG1: 34461ac4329aSDenis Bolotin type = NVM_TYPE_NVM_CFG1; 34471ac4329aSDenis Bolotin break; 34481ac4329aSDenis Bolotin case QED_NVM_IMAGE_DEFAULT_CFG: 34491ac4329aSDenis Bolotin type = NVM_TYPE_DEFAULT_CFG; 34501ac4329aSDenis Bolotin break; 34511ac4329aSDenis Bolotin case QED_NVM_IMAGE_NVM_META: 3452f2a74107SPrabhakar Kushwaha type = NVM_TYPE_NVM_META; 34531ac4329aSDenis Bolotin break; 345420675b37SMintz, Yuval default: 345520675b37SMintz, Yuval DP_NOTICE(p_hwfn, "Unknown request of image_id %08x\n", 345620675b37SMintz, Yuval image_id); 345720675b37SMintz, Yuval return -EINVAL; 345820675b37SMintz, Yuval } 345920675b37SMintz, Yuval 346020e100f5SShai Malin rc = qed_mcp_nvm_info_populate(p_hwfn); 346120e100f5SShai Malin if (rc) 346220e100f5SShai Malin return rc; 346320e100f5SShai Malin 346443645ce0SSudarsana Reddy Kalluru for (i = 0; i < p_hwfn->nvm_info.num_images; i++) 346543645ce0SSudarsana Reddy Kalluru if (type == p_hwfn->nvm_info.image_att[i].image_type) 346620675b37SMintz, Yuval break; 346743645ce0SSudarsana Reddy Kalluru if (i == p_hwfn->nvm_info.num_images) { 346820675b37SMintz, Yuval DP_VERBOSE(p_hwfn, QED_MSG_STORAGE, 346920675b37SMintz, Yuval "Failed to find nvram image of type %08x\n", 347020675b37SMintz, Yuval image_id); 347143645ce0SSudarsana Reddy Kalluru return -ENOENT; 347220675b37SMintz, Yuval } 347320675b37SMintz, Yuval 347443645ce0SSudarsana Reddy Kalluru p_image_att->start_addr = p_hwfn->nvm_info.image_att[i].nvm_start_addr; 347543645ce0SSudarsana Reddy Kalluru p_image_att->length = p_hwfn->nvm_info.image_att[i].len; 347620675b37SMintz, Yuval 347720675b37SMintz, Yuval return 0; 347820675b37SMintz, Yuval } 347920675b37SMintz, Yuval 348020675b37SMintz, Yuval int qed_mcp_get_nvm_image(struct qed_hwfn *p_hwfn, 348120675b37SMintz, Yuval enum qed_nvm_images image_id, 348220675b37SMintz, Yuval u8 *p_buffer, u32 buffer_len) 348320675b37SMintz, Yuval { 348420675b37SMintz, Yuval struct qed_nvm_image_att image_att; 348520675b37SMintz, Yuval int rc; 348620675b37SMintz, Yuval 348720675b37SMintz, Yuval memset(p_buffer, 0, buffer_len); 348820675b37SMintz, Yuval 3489b60bfdfeSDenis Bolotin rc = qed_mcp_get_nvm_image_att(p_hwfn, image_id, &image_att); 349020675b37SMintz, Yuval if (rc) 349120675b37SMintz, Yuval return rc; 349220675b37SMintz, Yuval 349320675b37SMintz, Yuval /* Validate sizes - both the image's and the supplied buffer's */ 349420675b37SMintz, Yuval if (image_att.length <= 4) { 349520675b37SMintz, Yuval DP_VERBOSE(p_hwfn, QED_MSG_STORAGE, 349620675b37SMintz, Yuval "Image [%d] is too small - only %d bytes\n", 349720675b37SMintz, Yuval image_id, image_att.length); 349820675b37SMintz, Yuval return -EINVAL; 349920675b37SMintz, Yuval } 350020675b37SMintz, Yuval 350120675b37SMintz, Yuval if (image_att.length > buffer_len) { 350220675b37SMintz, Yuval DP_VERBOSE(p_hwfn, 350320675b37SMintz, Yuval QED_MSG_STORAGE, 350420675b37SMintz, Yuval "Image [%d] is too big - %08x bytes where only %08x are available\n", 350520675b37SMintz, Yuval image_id, image_att.length, buffer_len); 350620675b37SMintz, Yuval return -ENOMEM; 350720675b37SMintz, Yuval } 350820675b37SMintz, Yuval 350920675b37SMintz, Yuval return qed_mcp_nvm_read(p_hwfn->cdev, image_att.start_addr, 351020675b37SMintz, Yuval p_buffer, image_att.length); 351120675b37SMintz, Yuval } 351220675b37SMintz, Yuval 35139c8517c4STomer Tayar static enum resource_id_enum qed_mcp_get_mfw_res_id(enum qed_resources res_id) 35149c8517c4STomer Tayar { 35159c8517c4STomer Tayar enum resource_id_enum mfw_res_id = RESOURCE_NUM_INVALID; 35169c8517c4STomer Tayar 35179c8517c4STomer Tayar switch (res_id) { 35189c8517c4STomer Tayar case QED_SB: 35199c8517c4STomer Tayar mfw_res_id = RESOURCE_NUM_SB_E; 35209c8517c4STomer Tayar break; 35219c8517c4STomer Tayar case QED_L2_QUEUE: 35229c8517c4STomer Tayar mfw_res_id = RESOURCE_NUM_L2_QUEUE_E; 35239c8517c4STomer Tayar break; 35249c8517c4STomer Tayar case QED_VPORT: 35259c8517c4STomer Tayar mfw_res_id = RESOURCE_NUM_VPORT_E; 35269c8517c4STomer Tayar break; 35279c8517c4STomer Tayar case QED_RSS_ENG: 35289c8517c4STomer Tayar mfw_res_id = RESOURCE_NUM_RSS_ENGINES_E; 35299c8517c4STomer Tayar break; 35309c8517c4STomer Tayar case QED_PQ: 35319c8517c4STomer Tayar mfw_res_id = RESOURCE_NUM_PQ_E; 35329c8517c4STomer Tayar break; 35339c8517c4STomer Tayar case QED_RL: 35349c8517c4STomer Tayar mfw_res_id = RESOURCE_NUM_RL_E; 35359c8517c4STomer Tayar break; 35369c8517c4STomer Tayar case QED_MAC: 35379c8517c4STomer Tayar case QED_VLAN: 35389c8517c4STomer Tayar /* Each VFC resource can accommodate both a MAC and a VLAN */ 35399c8517c4STomer Tayar mfw_res_id = RESOURCE_VFC_FILTER_E; 35409c8517c4STomer Tayar break; 35419c8517c4STomer Tayar case QED_ILT: 35429c8517c4STomer Tayar mfw_res_id = RESOURCE_ILT_E; 35439c8517c4STomer Tayar break; 3544997af5dfSMichal Kalderon case QED_LL2_RAM_QUEUE: 35459c8517c4STomer Tayar mfw_res_id = RESOURCE_LL2_QUEUE_E; 35469c8517c4STomer Tayar break; 3547997af5dfSMichal Kalderon case QED_LL2_CTX_QUEUE: 3548997af5dfSMichal Kalderon mfw_res_id = RESOURCE_LL2_CQS_E; 3549997af5dfSMichal Kalderon break; 35509c8517c4STomer Tayar case QED_RDMA_CNQ_RAM: 35519c8517c4STomer Tayar case QED_CMDQS_CQS: 35529c8517c4STomer Tayar /* CNQ/CMDQS are the same resource */ 35539c8517c4STomer Tayar mfw_res_id = RESOURCE_CQS_E; 35549c8517c4STomer Tayar break; 35559c8517c4STomer Tayar case QED_RDMA_STATS_QUEUE: 35569c8517c4STomer Tayar mfw_res_id = RESOURCE_RDMA_STATS_QUEUE_E; 35579c8517c4STomer Tayar break; 35589c8517c4STomer Tayar case QED_BDQ: 35599c8517c4STomer Tayar mfw_res_id = RESOURCE_BDQ_E; 35609c8517c4STomer Tayar break; 35619c8517c4STomer Tayar default: 35629c8517c4STomer Tayar break; 35639c8517c4STomer Tayar } 35649c8517c4STomer Tayar 35659c8517c4STomer Tayar return mfw_res_id; 35669c8517c4STomer Tayar } 35679c8517c4STomer Tayar 35689c8517c4STomer Tayar #define QED_RESC_ALLOC_VERSION_MAJOR 2 35692edbff8dSTomer Tayar #define QED_RESC_ALLOC_VERSION_MINOR 0 35702edbff8dSTomer Tayar #define QED_RESC_ALLOC_VERSION \ 35712edbff8dSTomer Tayar ((QED_RESC_ALLOC_VERSION_MAJOR << \ 35722edbff8dSTomer Tayar DRV_MB_PARAM_RESOURCE_ALLOC_VERSION_MAJOR_SHIFT) | \ 35732edbff8dSTomer Tayar (QED_RESC_ALLOC_VERSION_MINOR << \ 35742edbff8dSTomer Tayar DRV_MB_PARAM_RESOURCE_ALLOC_VERSION_MINOR_SHIFT)) 35759c8517c4STomer Tayar 35769c8517c4STomer Tayar struct qed_resc_alloc_in_params { 35779c8517c4STomer Tayar u32 cmd; 35789c8517c4STomer Tayar enum qed_resources res_id; 35799c8517c4STomer Tayar u32 resc_max_val; 35809c8517c4STomer Tayar }; 35819c8517c4STomer Tayar 35829c8517c4STomer Tayar struct qed_resc_alloc_out_params { 35839c8517c4STomer Tayar u32 mcp_resp; 35849c8517c4STomer Tayar u32 mcp_param; 35859c8517c4STomer Tayar u32 resc_num; 35869c8517c4STomer Tayar u32 resc_start; 35879c8517c4STomer Tayar u32 vf_resc_num; 35889c8517c4STomer Tayar u32 vf_resc_start; 35899c8517c4STomer Tayar u32 flags; 35909c8517c4STomer Tayar }; 35919c8517c4STomer Tayar 35929c8517c4STomer Tayar static int 35939c8517c4STomer Tayar qed_mcp_resc_allocation_msg(struct qed_hwfn *p_hwfn, 35942edbff8dSTomer Tayar struct qed_ptt *p_ptt, 35959c8517c4STomer Tayar struct qed_resc_alloc_in_params *p_in_params, 35969c8517c4STomer Tayar struct qed_resc_alloc_out_params *p_out_params) 35972edbff8dSTomer Tayar { 35982edbff8dSTomer Tayar struct qed_mcp_mb_params mb_params; 35999c8517c4STomer Tayar struct resource_info mfw_resc_info; 36002edbff8dSTomer Tayar int rc; 36012edbff8dSTomer Tayar 36029c8517c4STomer Tayar memset(&mfw_resc_info, 0, sizeof(mfw_resc_info)); 3603bb480242SMintz, Yuval 36049c8517c4STomer Tayar mfw_resc_info.res_id = qed_mcp_get_mfw_res_id(p_in_params->res_id); 36059c8517c4STomer Tayar if (mfw_resc_info.res_id == RESOURCE_NUM_INVALID) { 36069c8517c4STomer Tayar DP_ERR(p_hwfn, 36079c8517c4STomer Tayar "Failed to match resource %d [%s] with the MFW resources\n", 36089c8517c4STomer Tayar p_in_params->res_id, 36099c8517c4STomer Tayar qed_hw_get_resc_name(p_in_params->res_id)); 36109c8517c4STomer Tayar return -EINVAL; 36119c8517c4STomer Tayar } 36129c8517c4STomer Tayar 36139c8517c4STomer Tayar switch (p_in_params->cmd) { 36149c8517c4STomer Tayar case DRV_MSG_SET_RESOURCE_VALUE_MSG: 36159c8517c4STomer Tayar mfw_resc_info.size = p_in_params->resc_max_val; 3616df561f66SGustavo A. R. Silva fallthrough; 36179c8517c4STomer Tayar case DRV_MSG_GET_RESOURCE_ALLOC_MSG: 36189c8517c4STomer Tayar break; 36199c8517c4STomer Tayar default: 36209c8517c4STomer Tayar DP_ERR(p_hwfn, "Unexpected resource alloc command [0x%08x]\n", 36219c8517c4STomer Tayar p_in_params->cmd); 36229c8517c4STomer Tayar return -EINVAL; 36239c8517c4STomer Tayar } 36249c8517c4STomer Tayar 36259c8517c4STomer Tayar memset(&mb_params, 0, sizeof(mb_params)); 36269c8517c4STomer Tayar mb_params.cmd = p_in_params->cmd; 36279c8517c4STomer Tayar mb_params.param = QED_RESC_ALLOC_VERSION; 36289c8517c4STomer Tayar mb_params.p_data_src = &mfw_resc_info; 36299c8517c4STomer Tayar mb_params.data_src_size = sizeof(mfw_resc_info); 36309c8517c4STomer Tayar mb_params.p_data_dst = mb_params.p_data_src; 36319c8517c4STomer Tayar mb_params.data_dst_size = mb_params.data_src_size; 36329c8517c4STomer Tayar 36339c8517c4STomer Tayar DP_VERBOSE(p_hwfn, 36349c8517c4STomer Tayar QED_MSG_SP, 36359c8517c4STomer Tayar "Resource message request: cmd 0x%08x, res_id %d [%s], hsi_version %d.%d, val 0x%x\n", 36369c8517c4STomer Tayar p_in_params->cmd, 36379c8517c4STomer Tayar p_in_params->res_id, 36389c8517c4STomer Tayar qed_hw_get_resc_name(p_in_params->res_id), 36399c8517c4STomer Tayar QED_MFW_GET_FIELD(mb_params.param, 36409c8517c4STomer Tayar DRV_MB_PARAM_RESOURCE_ALLOC_VERSION_MAJOR), 36419c8517c4STomer Tayar QED_MFW_GET_FIELD(mb_params.param, 36429c8517c4STomer Tayar DRV_MB_PARAM_RESOURCE_ALLOC_VERSION_MINOR), 36439c8517c4STomer Tayar p_in_params->resc_max_val); 36449c8517c4STomer Tayar 36452edbff8dSTomer Tayar rc = qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 36462edbff8dSTomer Tayar if (rc) 36472edbff8dSTomer Tayar return rc; 36482edbff8dSTomer Tayar 36499c8517c4STomer Tayar p_out_params->mcp_resp = mb_params.mcp_resp; 36509c8517c4STomer Tayar p_out_params->mcp_param = mb_params.mcp_param; 36519c8517c4STomer Tayar p_out_params->resc_num = mfw_resc_info.size; 36529c8517c4STomer Tayar p_out_params->resc_start = mfw_resc_info.offset; 36539c8517c4STomer Tayar p_out_params->vf_resc_num = mfw_resc_info.vf_size; 36549c8517c4STomer Tayar p_out_params->vf_resc_start = mfw_resc_info.vf_offset; 36559c8517c4STomer Tayar p_out_params->flags = mfw_resc_info.flags; 36562edbff8dSTomer Tayar 36572edbff8dSTomer Tayar DP_VERBOSE(p_hwfn, 36582edbff8dSTomer Tayar QED_MSG_SP, 36599c8517c4STomer Tayar "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", 36609c8517c4STomer Tayar QED_MFW_GET_FIELD(p_out_params->mcp_param, 36619c8517c4STomer Tayar FW_MB_PARAM_RESOURCE_ALLOC_VERSION_MAJOR), 36629c8517c4STomer Tayar QED_MFW_GET_FIELD(p_out_params->mcp_param, 36639c8517c4STomer Tayar FW_MB_PARAM_RESOURCE_ALLOC_VERSION_MINOR), 36649c8517c4STomer Tayar p_out_params->resc_num, 36659c8517c4STomer Tayar p_out_params->resc_start, 36669c8517c4STomer Tayar p_out_params->vf_resc_num, 36679c8517c4STomer Tayar p_out_params->vf_resc_start, p_out_params->flags); 36689c8517c4STomer Tayar 36699c8517c4STomer Tayar return 0; 36709c8517c4STomer Tayar } 36719c8517c4STomer Tayar 36729c8517c4STomer Tayar int 36739c8517c4STomer Tayar qed_mcp_set_resc_max_val(struct qed_hwfn *p_hwfn, 36749c8517c4STomer Tayar struct qed_ptt *p_ptt, 36759c8517c4STomer Tayar enum qed_resources res_id, 36769c8517c4STomer Tayar u32 resc_max_val, u32 *p_mcp_resp) 36779c8517c4STomer Tayar { 36789c8517c4STomer Tayar struct qed_resc_alloc_out_params out_params; 36799c8517c4STomer Tayar struct qed_resc_alloc_in_params in_params; 36809c8517c4STomer Tayar int rc; 36819c8517c4STomer Tayar 36829c8517c4STomer Tayar memset(&in_params, 0, sizeof(in_params)); 36839c8517c4STomer Tayar in_params.cmd = DRV_MSG_SET_RESOURCE_VALUE_MSG; 36849c8517c4STomer Tayar in_params.res_id = res_id; 36859c8517c4STomer Tayar in_params.resc_max_val = resc_max_val; 36869c8517c4STomer Tayar memset(&out_params, 0, sizeof(out_params)); 36879c8517c4STomer Tayar rc = qed_mcp_resc_allocation_msg(p_hwfn, p_ptt, &in_params, 36889c8517c4STomer Tayar &out_params); 36899c8517c4STomer Tayar if (rc) 36909c8517c4STomer Tayar return rc; 36919c8517c4STomer Tayar 36929c8517c4STomer Tayar *p_mcp_resp = out_params.mcp_resp; 36939c8517c4STomer Tayar 36949c8517c4STomer Tayar return 0; 36959c8517c4STomer Tayar } 36969c8517c4STomer Tayar 36979c8517c4STomer Tayar int 36989c8517c4STomer Tayar qed_mcp_get_resc_info(struct qed_hwfn *p_hwfn, 36999c8517c4STomer Tayar struct qed_ptt *p_ptt, 37009c8517c4STomer Tayar enum qed_resources res_id, 37019c8517c4STomer Tayar u32 *p_mcp_resp, u32 *p_resc_num, u32 *p_resc_start) 37029c8517c4STomer Tayar { 37039c8517c4STomer Tayar struct qed_resc_alloc_out_params out_params; 37049c8517c4STomer Tayar struct qed_resc_alloc_in_params in_params; 37059c8517c4STomer Tayar int rc; 37069c8517c4STomer Tayar 37079c8517c4STomer Tayar memset(&in_params, 0, sizeof(in_params)); 37089c8517c4STomer Tayar in_params.cmd = DRV_MSG_GET_RESOURCE_ALLOC_MSG; 37099c8517c4STomer Tayar in_params.res_id = res_id; 37109c8517c4STomer Tayar memset(&out_params, 0, sizeof(out_params)); 37119c8517c4STomer Tayar rc = qed_mcp_resc_allocation_msg(p_hwfn, p_ptt, &in_params, 37129c8517c4STomer Tayar &out_params); 37139c8517c4STomer Tayar if (rc) 37149c8517c4STomer Tayar return rc; 37159c8517c4STomer Tayar 37169c8517c4STomer Tayar *p_mcp_resp = out_params.mcp_resp; 37179c8517c4STomer Tayar 37189c8517c4STomer Tayar if (*p_mcp_resp == FW_MSG_CODE_RESOURCE_ALLOC_OK) { 37199c8517c4STomer Tayar *p_resc_num = out_params.resc_num; 37209c8517c4STomer Tayar *p_resc_start = out_params.resc_start; 37219c8517c4STomer Tayar } 37222edbff8dSTomer Tayar 37232edbff8dSTomer Tayar return 0; 37242edbff8dSTomer Tayar } 372518a69e36SMintz, Yuval 372618a69e36SMintz, Yuval int qed_mcp_initiate_pf_flr(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 372718a69e36SMintz, Yuval { 372818a69e36SMintz, Yuval u32 mcp_resp, mcp_param; 372918a69e36SMintz, Yuval 373018a69e36SMintz, Yuval return qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_INITIATE_PF_FLR, 0, 373118a69e36SMintz, Yuval &mcp_resp, &mcp_param); 373218a69e36SMintz, Yuval } 373395691c9cSTomer Tayar 373495691c9cSTomer Tayar static int qed_mcp_resource_cmd(struct qed_hwfn *p_hwfn, 373595691c9cSTomer Tayar struct qed_ptt *p_ptt, 373695691c9cSTomer Tayar u32 param, u32 *p_mcp_resp, u32 *p_mcp_param) 373795691c9cSTomer Tayar { 373895691c9cSTomer Tayar int rc; 373995691c9cSTomer Tayar 3740ef10bd49SVenkata Sudheer Kumar Bhavaraju rc = qed_mcp_cmd_nosleep(p_hwfn, p_ptt, DRV_MSG_CODE_RESOURCE_CMD, 3741ef10bd49SVenkata Sudheer Kumar Bhavaraju param, p_mcp_resp, p_mcp_param); 374295691c9cSTomer Tayar if (rc) 374395691c9cSTomer Tayar return rc; 374495691c9cSTomer Tayar 374595691c9cSTomer Tayar if (*p_mcp_resp == FW_MSG_CODE_UNSUPPORTED) { 374695691c9cSTomer Tayar DP_INFO(p_hwfn, 374795691c9cSTomer Tayar "The resource command is unsupported by the MFW\n"); 374895691c9cSTomer Tayar return -EINVAL; 374995691c9cSTomer Tayar } 375095691c9cSTomer Tayar 375195691c9cSTomer Tayar if (*p_mcp_param == RESOURCE_OPCODE_UNKNOWN_CMD) { 375295691c9cSTomer Tayar u8 opcode = QED_MFW_GET_FIELD(param, RESOURCE_CMD_REQ_OPCODE); 375395691c9cSTomer Tayar 375495691c9cSTomer Tayar DP_NOTICE(p_hwfn, 375595691c9cSTomer Tayar "The resource command is unknown to the MFW [param 0x%08x, opcode %d]\n", 375695691c9cSTomer Tayar param, opcode); 375795691c9cSTomer Tayar return -EINVAL; 375895691c9cSTomer Tayar } 375995691c9cSTomer Tayar 376095691c9cSTomer Tayar return rc; 376195691c9cSTomer Tayar } 376295691c9cSTomer Tayar 3763bf774d14SYueHaibing static int 376495691c9cSTomer Tayar __qed_mcp_resc_lock(struct qed_hwfn *p_hwfn, 376595691c9cSTomer Tayar struct qed_ptt *p_ptt, 376695691c9cSTomer Tayar struct qed_resc_lock_params *p_params) 376795691c9cSTomer Tayar { 376895691c9cSTomer Tayar u32 param = 0, mcp_resp, mcp_param; 376995691c9cSTomer Tayar u8 opcode; 377095691c9cSTomer Tayar int rc; 377195691c9cSTomer Tayar 377295691c9cSTomer Tayar switch (p_params->timeout) { 377395691c9cSTomer Tayar case QED_MCP_RESC_LOCK_TO_DEFAULT: 377495691c9cSTomer Tayar opcode = RESOURCE_OPCODE_REQ; 377595691c9cSTomer Tayar p_params->timeout = 0; 377695691c9cSTomer Tayar break; 377795691c9cSTomer Tayar case QED_MCP_RESC_LOCK_TO_NONE: 377895691c9cSTomer Tayar opcode = RESOURCE_OPCODE_REQ_WO_AGING; 377995691c9cSTomer Tayar p_params->timeout = 0; 378095691c9cSTomer Tayar break; 378195691c9cSTomer Tayar default: 378295691c9cSTomer Tayar opcode = RESOURCE_OPCODE_REQ_W_AGING; 378395691c9cSTomer Tayar break; 378495691c9cSTomer Tayar } 378595691c9cSTomer Tayar 378695691c9cSTomer Tayar QED_MFW_SET_FIELD(param, RESOURCE_CMD_REQ_RESC, p_params->resource); 378795691c9cSTomer Tayar QED_MFW_SET_FIELD(param, RESOURCE_CMD_REQ_OPCODE, opcode); 378895691c9cSTomer Tayar QED_MFW_SET_FIELD(param, RESOURCE_CMD_REQ_AGE, p_params->timeout); 378995691c9cSTomer Tayar 379095691c9cSTomer Tayar DP_VERBOSE(p_hwfn, 379195691c9cSTomer Tayar QED_MSG_SP, 379295691c9cSTomer Tayar "Resource lock request: param 0x%08x [age %d, opcode %d, resource %d]\n", 379395691c9cSTomer Tayar param, p_params->timeout, opcode, p_params->resource); 379495691c9cSTomer Tayar 379595691c9cSTomer Tayar /* Attempt to acquire the resource */ 379695691c9cSTomer Tayar rc = qed_mcp_resource_cmd(p_hwfn, p_ptt, param, &mcp_resp, &mcp_param); 379795691c9cSTomer Tayar if (rc) 379895691c9cSTomer Tayar return rc; 379995691c9cSTomer Tayar 380095691c9cSTomer Tayar /* Analyze the response */ 380195691c9cSTomer Tayar p_params->owner = QED_MFW_GET_FIELD(mcp_param, RESOURCE_CMD_RSP_OWNER); 380295691c9cSTomer Tayar opcode = QED_MFW_GET_FIELD(mcp_param, RESOURCE_CMD_RSP_OPCODE); 380395691c9cSTomer Tayar 380495691c9cSTomer Tayar DP_VERBOSE(p_hwfn, 380595691c9cSTomer Tayar QED_MSG_SP, 380695691c9cSTomer Tayar "Resource lock response: mcp_param 0x%08x [opcode %d, owner %d]\n", 380795691c9cSTomer Tayar mcp_param, opcode, p_params->owner); 380895691c9cSTomer Tayar 380995691c9cSTomer Tayar switch (opcode) { 381095691c9cSTomer Tayar case RESOURCE_OPCODE_GNT: 381195691c9cSTomer Tayar p_params->b_granted = true; 381295691c9cSTomer Tayar break; 381395691c9cSTomer Tayar case RESOURCE_OPCODE_BUSY: 381495691c9cSTomer Tayar p_params->b_granted = false; 381595691c9cSTomer Tayar break; 381695691c9cSTomer Tayar default: 381795691c9cSTomer Tayar DP_NOTICE(p_hwfn, 381895691c9cSTomer Tayar "Unexpected opcode in resource lock response [mcp_param 0x%08x, opcode %d]\n", 381995691c9cSTomer Tayar mcp_param, opcode); 382095691c9cSTomer Tayar return -EINVAL; 382195691c9cSTomer Tayar } 382295691c9cSTomer Tayar 382395691c9cSTomer Tayar return 0; 382495691c9cSTomer Tayar } 382595691c9cSTomer Tayar 382695691c9cSTomer Tayar int 382795691c9cSTomer Tayar qed_mcp_resc_lock(struct qed_hwfn *p_hwfn, 382895691c9cSTomer Tayar struct qed_ptt *p_ptt, struct qed_resc_lock_params *p_params) 382995691c9cSTomer Tayar { 383095691c9cSTomer Tayar u32 retry_cnt = 0; 383195691c9cSTomer Tayar int rc; 383295691c9cSTomer Tayar 383395691c9cSTomer Tayar do { 383495691c9cSTomer Tayar /* No need for an interval before the first iteration */ 383595691c9cSTomer Tayar if (retry_cnt) { 383695691c9cSTomer Tayar if (p_params->sleep_b4_retry) { 383795691c9cSTomer Tayar u16 retry_interval_in_ms = 383895691c9cSTomer Tayar DIV_ROUND_UP(p_params->retry_interval, 383995691c9cSTomer Tayar 1000); 384095691c9cSTomer Tayar 384195691c9cSTomer Tayar msleep(retry_interval_in_ms); 384295691c9cSTomer Tayar } else { 384395691c9cSTomer Tayar udelay(p_params->retry_interval); 384495691c9cSTomer Tayar } 384595691c9cSTomer Tayar } 384695691c9cSTomer Tayar 384795691c9cSTomer Tayar rc = __qed_mcp_resc_lock(p_hwfn, p_ptt, p_params); 384895691c9cSTomer Tayar if (rc) 384995691c9cSTomer Tayar return rc; 385095691c9cSTomer Tayar 385195691c9cSTomer Tayar if (p_params->b_granted) 385295691c9cSTomer Tayar break; 385395691c9cSTomer Tayar } while (retry_cnt++ < p_params->retry_num); 385495691c9cSTomer Tayar 385595691c9cSTomer Tayar return 0; 385695691c9cSTomer Tayar } 385795691c9cSTomer Tayar 385895691c9cSTomer Tayar int 385995691c9cSTomer Tayar qed_mcp_resc_unlock(struct qed_hwfn *p_hwfn, 386095691c9cSTomer Tayar struct qed_ptt *p_ptt, 386195691c9cSTomer Tayar struct qed_resc_unlock_params *p_params) 386295691c9cSTomer Tayar { 386395691c9cSTomer Tayar u32 param = 0, mcp_resp, mcp_param; 386495691c9cSTomer Tayar u8 opcode; 386595691c9cSTomer Tayar int rc; 386695691c9cSTomer Tayar 386795691c9cSTomer Tayar opcode = p_params->b_force ? RESOURCE_OPCODE_FORCE_RELEASE 386895691c9cSTomer Tayar : RESOURCE_OPCODE_RELEASE; 386995691c9cSTomer Tayar QED_MFW_SET_FIELD(param, RESOURCE_CMD_REQ_RESC, p_params->resource); 387095691c9cSTomer Tayar QED_MFW_SET_FIELD(param, RESOURCE_CMD_REQ_OPCODE, opcode); 387195691c9cSTomer Tayar 387295691c9cSTomer Tayar DP_VERBOSE(p_hwfn, QED_MSG_SP, 387395691c9cSTomer Tayar "Resource unlock request: param 0x%08x [opcode %d, resource %d]\n", 387495691c9cSTomer Tayar param, opcode, p_params->resource); 387595691c9cSTomer Tayar 387695691c9cSTomer Tayar /* Attempt to release the resource */ 387795691c9cSTomer Tayar rc = qed_mcp_resource_cmd(p_hwfn, p_ptt, param, &mcp_resp, &mcp_param); 387895691c9cSTomer Tayar if (rc) 387995691c9cSTomer Tayar return rc; 388095691c9cSTomer Tayar 388195691c9cSTomer Tayar /* Analyze the response */ 388295691c9cSTomer Tayar opcode = QED_MFW_GET_FIELD(mcp_param, RESOURCE_CMD_RSP_OPCODE); 388395691c9cSTomer Tayar 388495691c9cSTomer Tayar DP_VERBOSE(p_hwfn, QED_MSG_SP, 388595691c9cSTomer Tayar "Resource unlock response: mcp_param 0x%08x [opcode %d]\n", 388695691c9cSTomer Tayar mcp_param, opcode); 388795691c9cSTomer Tayar 388895691c9cSTomer Tayar switch (opcode) { 388995691c9cSTomer Tayar case RESOURCE_OPCODE_RELEASED_PREVIOUS: 389095691c9cSTomer Tayar DP_INFO(p_hwfn, 389195691c9cSTomer Tayar "Resource unlock request for an already released resource [%d]\n", 389295691c9cSTomer Tayar p_params->resource); 3893df561f66SGustavo A. R. Silva fallthrough; 389495691c9cSTomer Tayar case RESOURCE_OPCODE_RELEASED: 389595691c9cSTomer Tayar p_params->b_released = true; 389695691c9cSTomer Tayar break; 389795691c9cSTomer Tayar case RESOURCE_OPCODE_WRONG_OWNER: 389895691c9cSTomer Tayar p_params->b_released = false; 389995691c9cSTomer Tayar break; 390095691c9cSTomer Tayar default: 390195691c9cSTomer Tayar DP_NOTICE(p_hwfn, 390295691c9cSTomer Tayar "Unexpected opcode in resource unlock response [mcp_param 0x%08x, opcode %d]\n", 390395691c9cSTomer Tayar mcp_param, opcode); 390495691c9cSTomer Tayar return -EINVAL; 390595691c9cSTomer Tayar } 390695691c9cSTomer Tayar 390795691c9cSTomer Tayar return 0; 390895691c9cSTomer Tayar } 3909f470f22cSsudarsana.kalluru@cavium.com 3910f470f22cSsudarsana.kalluru@cavium.com void qed_mcp_resc_lock_default_init(struct qed_resc_lock_params *p_lock, 3911f470f22cSsudarsana.kalluru@cavium.com struct qed_resc_unlock_params *p_unlock, 3912f470f22cSsudarsana.kalluru@cavium.com enum qed_resc_lock 3913f470f22cSsudarsana.kalluru@cavium.com resource, bool b_is_permanent) 3914f470f22cSsudarsana.kalluru@cavium.com { 3915f470f22cSsudarsana.kalluru@cavium.com if (p_lock) { 3916f470f22cSsudarsana.kalluru@cavium.com memset(p_lock, 0, sizeof(*p_lock)); 3917f470f22cSsudarsana.kalluru@cavium.com 3918f470f22cSsudarsana.kalluru@cavium.com /* Permanent resources don't require aging, and there's no 3919f470f22cSsudarsana.kalluru@cavium.com * point in trying to acquire them more than once since it's 3920f470f22cSsudarsana.kalluru@cavium.com * unexpected another entity would release them. 3921f470f22cSsudarsana.kalluru@cavium.com */ 3922f470f22cSsudarsana.kalluru@cavium.com if (b_is_permanent) { 3923f470f22cSsudarsana.kalluru@cavium.com p_lock->timeout = QED_MCP_RESC_LOCK_TO_NONE; 3924f470f22cSsudarsana.kalluru@cavium.com } else { 3925f470f22cSsudarsana.kalluru@cavium.com p_lock->retry_num = QED_MCP_RESC_LOCK_RETRY_CNT_DFLT; 3926f470f22cSsudarsana.kalluru@cavium.com p_lock->retry_interval = 3927f470f22cSsudarsana.kalluru@cavium.com QED_MCP_RESC_LOCK_RETRY_VAL_DFLT; 3928f470f22cSsudarsana.kalluru@cavium.com p_lock->sleep_b4_retry = true; 3929f470f22cSsudarsana.kalluru@cavium.com } 3930f470f22cSsudarsana.kalluru@cavium.com 3931f470f22cSsudarsana.kalluru@cavium.com p_lock->resource = resource; 3932f470f22cSsudarsana.kalluru@cavium.com } 3933f470f22cSsudarsana.kalluru@cavium.com 3934f470f22cSsudarsana.kalluru@cavium.com if (p_unlock) { 3935f470f22cSsudarsana.kalluru@cavium.com memset(p_unlock, 0, sizeof(*p_unlock)); 3936f470f22cSsudarsana.kalluru@cavium.com p_unlock->resource = resource; 3937f470f22cSsudarsana.kalluru@cavium.com } 3938f470f22cSsudarsana.kalluru@cavium.com } 3939645874e5SSudarsana Reddy Kalluru 3940df9c716dSSudarsana Reddy Kalluru bool qed_mcp_is_smart_an_supported(struct qed_hwfn *p_hwfn) 3941df9c716dSSudarsana Reddy Kalluru { 3942df9c716dSSudarsana Reddy Kalluru return !!(p_hwfn->mcp_info->capabilities & 3943df9c716dSSudarsana Reddy Kalluru FW_MB_PARAM_FEATURE_SUPPORT_SMARTLINQ); 3944df9c716dSSudarsana Reddy Kalluru } 3945df9c716dSSudarsana Reddy Kalluru 3946645874e5SSudarsana Reddy Kalluru int qed_mcp_get_capabilities(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 3947645874e5SSudarsana Reddy Kalluru { 3948645874e5SSudarsana Reddy Kalluru u32 mcp_resp; 3949645874e5SSudarsana Reddy Kalluru int rc; 3950645874e5SSudarsana Reddy Kalluru 3951645874e5SSudarsana Reddy Kalluru rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_GET_MFW_FEATURE_SUPPORT, 3952645874e5SSudarsana Reddy Kalluru 0, &mcp_resp, &p_hwfn->mcp_info->capabilities); 3953645874e5SSudarsana Reddy Kalluru if (!rc) 3954645874e5SSudarsana Reddy Kalluru DP_VERBOSE(p_hwfn, (QED_MSG_SP | NETIF_MSG_PROBE), 3955645874e5SSudarsana Reddy Kalluru "MFW supported features: %08x\n", 3956645874e5SSudarsana Reddy Kalluru p_hwfn->mcp_info->capabilities); 3957645874e5SSudarsana Reddy Kalluru 3958645874e5SSudarsana Reddy Kalluru return rc; 3959645874e5SSudarsana Reddy Kalluru } 3960645874e5SSudarsana Reddy Kalluru 3961645874e5SSudarsana Reddy Kalluru int qed_mcp_set_capabilities(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 3962645874e5SSudarsana Reddy Kalluru { 3963645874e5SSudarsana Reddy Kalluru u32 mcp_resp, mcp_param, features; 3964645874e5SSudarsana Reddy Kalluru 3965e40a826aSSudarsana Reddy Kalluru features = DRV_MB_PARAM_FEATURE_SUPPORT_PORT_EEE | 3966ae7e6937SAlexander Lobakin DRV_MB_PARAM_FEATURE_SUPPORT_FUNC_VLINK | 3967ae7e6937SAlexander Lobakin DRV_MB_PARAM_FEATURE_SUPPORT_PORT_FEC_CONTROL; 3968645874e5SSudarsana Reddy Kalluru 3969645874e5SSudarsana Reddy Kalluru return qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_FEATURE_SUPPORT, 3970645874e5SSudarsana Reddy Kalluru features, &mcp_resp, &mcp_param); 3971645874e5SSudarsana Reddy Kalluru } 397279284adeSMichal Kalderon 397379284adeSMichal Kalderon int qed_mcp_get_engine_config(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 397479284adeSMichal Kalderon { 397579284adeSMichal Kalderon struct qed_mcp_mb_params mb_params = {0}; 397679284adeSMichal Kalderon struct qed_dev *cdev = p_hwfn->cdev; 397779284adeSMichal Kalderon u8 fir_valid, l2_valid; 397879284adeSMichal Kalderon int rc; 397979284adeSMichal Kalderon 398079284adeSMichal Kalderon mb_params.cmd = DRV_MSG_CODE_GET_ENGINE_CONFIG; 398179284adeSMichal Kalderon rc = qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 398279284adeSMichal Kalderon if (rc) 398379284adeSMichal Kalderon return rc; 398479284adeSMichal Kalderon 398579284adeSMichal Kalderon if (mb_params.mcp_resp == FW_MSG_CODE_UNSUPPORTED) { 398679284adeSMichal Kalderon DP_INFO(p_hwfn, 398779284adeSMichal Kalderon "The get_engine_config command is unsupported by the MFW\n"); 398879284adeSMichal Kalderon return -EOPNOTSUPP; 398979284adeSMichal Kalderon } 399079284adeSMichal Kalderon 399179284adeSMichal Kalderon fir_valid = QED_MFW_GET_FIELD(mb_params.mcp_param, 399279284adeSMichal Kalderon FW_MB_PARAM_ENG_CFG_FIR_AFFIN_VALID); 399379284adeSMichal Kalderon if (fir_valid) 399479284adeSMichal Kalderon cdev->fir_affin = 399579284adeSMichal Kalderon QED_MFW_GET_FIELD(mb_params.mcp_param, 399679284adeSMichal Kalderon FW_MB_PARAM_ENG_CFG_FIR_AFFIN_VALUE); 399779284adeSMichal Kalderon 399879284adeSMichal Kalderon l2_valid = QED_MFW_GET_FIELD(mb_params.mcp_param, 399979284adeSMichal Kalderon FW_MB_PARAM_ENG_CFG_L2_AFFIN_VALID); 400079284adeSMichal Kalderon if (l2_valid) 400179284adeSMichal Kalderon cdev->l2_affin_hint = 400279284adeSMichal Kalderon QED_MFW_GET_FIELD(mb_params.mcp_param, 400379284adeSMichal Kalderon FW_MB_PARAM_ENG_CFG_L2_AFFIN_VALUE); 400479284adeSMichal Kalderon 400579284adeSMichal Kalderon DP_INFO(p_hwfn, 400679284adeSMichal Kalderon "Engine affinity config: FIR={valid %hhd, value %hhd}, L2_hint={valid %hhd, value %hhd}\n", 400779284adeSMichal Kalderon fir_valid, cdev->fir_affin, l2_valid, cdev->l2_affin_hint); 400879284adeSMichal Kalderon 400979284adeSMichal Kalderon return 0; 401079284adeSMichal Kalderon } 401179284adeSMichal Kalderon 401279284adeSMichal Kalderon int qed_mcp_get_ppfid_bitmap(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 401379284adeSMichal Kalderon { 401479284adeSMichal Kalderon struct qed_mcp_mb_params mb_params = {0}; 401579284adeSMichal Kalderon struct qed_dev *cdev = p_hwfn->cdev; 401679284adeSMichal Kalderon int rc; 401779284adeSMichal Kalderon 401879284adeSMichal Kalderon mb_params.cmd = DRV_MSG_CODE_GET_PPFID_BITMAP; 401979284adeSMichal Kalderon rc = qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 402079284adeSMichal Kalderon if (rc) 402179284adeSMichal Kalderon return rc; 402279284adeSMichal Kalderon 402379284adeSMichal Kalderon if (mb_params.mcp_resp == FW_MSG_CODE_UNSUPPORTED) { 402479284adeSMichal Kalderon DP_INFO(p_hwfn, 402579284adeSMichal Kalderon "The get_ppfid_bitmap command is unsupported by the MFW\n"); 402679284adeSMichal Kalderon return -EOPNOTSUPP; 402779284adeSMichal Kalderon } 402879284adeSMichal Kalderon 402979284adeSMichal Kalderon cdev->ppfid_bitmap = QED_MFW_GET_FIELD(mb_params.mcp_param, 403079284adeSMichal Kalderon FW_MB_PARAM_PPFID_BITMAP); 403179284adeSMichal Kalderon 403279284adeSMichal Kalderon DP_VERBOSE(p_hwfn, QED_MSG_SP, "PPFID bitmap 0x%hhx\n", 403379284adeSMichal Kalderon cdev->ppfid_bitmap); 403479284adeSMichal Kalderon 403579284adeSMichal Kalderon return 0; 403679284adeSMichal Kalderon } 403738eabdf0SSudarsana Reddy Kalluru 40382d4c8495SSudarsana Reddy Kalluru int qed_mcp_nvm_get_cfg(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, 40392d4c8495SSudarsana Reddy Kalluru u16 option_id, u8 entity_id, u16 flags, u8 *p_buf, 40402d4c8495SSudarsana Reddy Kalluru u32 *p_len) 40412d4c8495SSudarsana Reddy Kalluru { 40422d4c8495SSudarsana Reddy Kalluru u32 mb_param = 0, resp, param; 40432d4c8495SSudarsana Reddy Kalluru int rc; 40442d4c8495SSudarsana Reddy Kalluru 40452d4c8495SSudarsana Reddy Kalluru QED_MFW_SET_FIELD(mb_param, DRV_MB_PARAM_NVM_CFG_OPTION_ID, option_id); 40462d4c8495SSudarsana Reddy Kalluru if (flags & QED_NVM_CFG_OPTION_INIT) 40472d4c8495SSudarsana Reddy Kalluru QED_MFW_SET_FIELD(mb_param, 40482d4c8495SSudarsana Reddy Kalluru DRV_MB_PARAM_NVM_CFG_OPTION_INIT, 1); 40492d4c8495SSudarsana Reddy Kalluru if (flags & QED_NVM_CFG_OPTION_FREE) 40502d4c8495SSudarsana Reddy Kalluru QED_MFW_SET_FIELD(mb_param, 40512d4c8495SSudarsana Reddy Kalluru DRV_MB_PARAM_NVM_CFG_OPTION_FREE, 1); 40522d4c8495SSudarsana Reddy Kalluru if (flags & QED_NVM_CFG_OPTION_ENTITY_SEL) { 40532d4c8495SSudarsana Reddy Kalluru QED_MFW_SET_FIELD(mb_param, 40542d4c8495SSudarsana Reddy Kalluru DRV_MB_PARAM_NVM_CFG_OPTION_ENTITY_SEL, 1); 40552d4c8495SSudarsana Reddy Kalluru QED_MFW_SET_FIELD(mb_param, 40562d4c8495SSudarsana Reddy Kalluru DRV_MB_PARAM_NVM_CFG_OPTION_ENTITY_ID, 40572d4c8495SSudarsana Reddy Kalluru entity_id); 40582d4c8495SSudarsana Reddy Kalluru } 40592d4c8495SSudarsana Reddy Kalluru 40602d4c8495SSudarsana Reddy Kalluru rc = qed_mcp_nvm_rd_cmd(p_hwfn, p_ptt, 40612d4c8495SSudarsana Reddy Kalluru DRV_MSG_CODE_GET_NVM_CFG_OPTION, 40626c95dd8fSPrabhakar Kushwaha mb_param, &resp, ¶m, p_len, 40636c95dd8fSPrabhakar Kushwaha (u32 *)p_buf, false); 40642d4c8495SSudarsana Reddy Kalluru 40652d4c8495SSudarsana Reddy Kalluru return rc; 40662d4c8495SSudarsana Reddy Kalluru } 40672d4c8495SSudarsana Reddy Kalluru 406838eabdf0SSudarsana Reddy Kalluru int qed_mcp_nvm_set_cfg(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, 406938eabdf0SSudarsana Reddy Kalluru u16 option_id, u8 entity_id, u16 flags, u8 *p_buf, 407038eabdf0SSudarsana Reddy Kalluru u32 len) 407138eabdf0SSudarsana Reddy Kalluru { 407238eabdf0SSudarsana Reddy Kalluru u32 mb_param = 0, resp, param; 407338eabdf0SSudarsana Reddy Kalluru 407438eabdf0SSudarsana Reddy Kalluru QED_MFW_SET_FIELD(mb_param, DRV_MB_PARAM_NVM_CFG_OPTION_ID, option_id); 407538eabdf0SSudarsana Reddy Kalluru if (flags & QED_NVM_CFG_OPTION_ALL) 407638eabdf0SSudarsana Reddy Kalluru QED_MFW_SET_FIELD(mb_param, 407738eabdf0SSudarsana Reddy Kalluru DRV_MB_PARAM_NVM_CFG_OPTION_ALL, 1); 407838eabdf0SSudarsana Reddy Kalluru if (flags & QED_NVM_CFG_OPTION_INIT) 407938eabdf0SSudarsana Reddy Kalluru QED_MFW_SET_FIELD(mb_param, 408038eabdf0SSudarsana Reddy Kalluru DRV_MB_PARAM_NVM_CFG_OPTION_INIT, 1); 408138eabdf0SSudarsana Reddy Kalluru if (flags & QED_NVM_CFG_OPTION_COMMIT) 408238eabdf0SSudarsana Reddy Kalluru QED_MFW_SET_FIELD(mb_param, 408338eabdf0SSudarsana Reddy Kalluru DRV_MB_PARAM_NVM_CFG_OPTION_COMMIT, 1); 408438eabdf0SSudarsana Reddy Kalluru if (flags & QED_NVM_CFG_OPTION_FREE) 408538eabdf0SSudarsana Reddy Kalluru QED_MFW_SET_FIELD(mb_param, 408638eabdf0SSudarsana Reddy Kalluru DRV_MB_PARAM_NVM_CFG_OPTION_FREE, 1); 408738eabdf0SSudarsana Reddy Kalluru if (flags & QED_NVM_CFG_OPTION_ENTITY_SEL) { 408838eabdf0SSudarsana Reddy Kalluru QED_MFW_SET_FIELD(mb_param, 408938eabdf0SSudarsana Reddy Kalluru DRV_MB_PARAM_NVM_CFG_OPTION_ENTITY_SEL, 1); 409038eabdf0SSudarsana Reddy Kalluru QED_MFW_SET_FIELD(mb_param, 409138eabdf0SSudarsana Reddy Kalluru DRV_MB_PARAM_NVM_CFG_OPTION_ENTITY_ID, 409238eabdf0SSudarsana Reddy Kalluru entity_id); 409338eabdf0SSudarsana Reddy Kalluru } 409438eabdf0SSudarsana Reddy Kalluru 409538eabdf0SSudarsana Reddy Kalluru return qed_mcp_nvm_wr_cmd(p_hwfn, p_ptt, 409638eabdf0SSudarsana Reddy Kalluru DRV_MSG_CODE_SET_NVM_CFG_OPTION, 409738eabdf0SSudarsana Reddy Kalluru mb_param, &resp, ¶m, len, (u32 *)p_buf); 409838eabdf0SSudarsana Reddy Kalluru } 4099d8d6c5a7SIgor Russkikh 4100d8d6c5a7SIgor Russkikh #define QED_MCP_DBG_DATA_MAX_SIZE MCP_DRV_NVM_BUF_LEN 4101d8d6c5a7SIgor Russkikh #define QED_MCP_DBG_DATA_MAX_HEADER_SIZE sizeof(u32) 4102d8d6c5a7SIgor Russkikh #define QED_MCP_DBG_DATA_MAX_PAYLOAD_SIZE \ 4103d8d6c5a7SIgor Russkikh (QED_MCP_DBG_DATA_MAX_SIZE - QED_MCP_DBG_DATA_MAX_HEADER_SIZE) 4104d8d6c5a7SIgor Russkikh 4105d8d6c5a7SIgor Russkikh static int 4106d8d6c5a7SIgor Russkikh __qed_mcp_send_debug_data(struct qed_hwfn *p_hwfn, 4107d8d6c5a7SIgor Russkikh struct qed_ptt *p_ptt, u8 *p_buf, u8 size) 4108d8d6c5a7SIgor Russkikh { 4109d8d6c5a7SIgor Russkikh struct qed_mcp_mb_params mb_params; 4110d8d6c5a7SIgor Russkikh int rc; 4111d8d6c5a7SIgor Russkikh 4112d8d6c5a7SIgor Russkikh if (size > QED_MCP_DBG_DATA_MAX_SIZE) { 4113d8d6c5a7SIgor Russkikh DP_ERR(p_hwfn, 4114d8d6c5a7SIgor Russkikh "Debug data size is %d while it should not exceed %d\n", 4115d8d6c5a7SIgor Russkikh size, QED_MCP_DBG_DATA_MAX_SIZE); 4116d8d6c5a7SIgor Russkikh return -EINVAL; 4117d8d6c5a7SIgor Russkikh } 4118d8d6c5a7SIgor Russkikh 4119d8d6c5a7SIgor Russkikh memset(&mb_params, 0, sizeof(mb_params)); 4120d8d6c5a7SIgor Russkikh mb_params.cmd = DRV_MSG_CODE_DEBUG_DATA_SEND; 4121d8d6c5a7SIgor Russkikh SET_MFW_FIELD(mb_params.param, DRV_MSG_CODE_DEBUG_DATA_SEND_SIZE, size); 4122d8d6c5a7SIgor Russkikh mb_params.p_data_src = p_buf; 4123d8d6c5a7SIgor Russkikh mb_params.data_src_size = size; 4124d8d6c5a7SIgor Russkikh rc = qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 4125d8d6c5a7SIgor Russkikh if (rc) 4126d8d6c5a7SIgor Russkikh return rc; 4127d8d6c5a7SIgor Russkikh 4128d8d6c5a7SIgor Russkikh if (mb_params.mcp_resp == FW_MSG_CODE_UNSUPPORTED) { 4129d8d6c5a7SIgor Russkikh DP_INFO(p_hwfn, 4130d8d6c5a7SIgor Russkikh "The DEBUG_DATA_SEND command is unsupported by the MFW\n"); 4131d8d6c5a7SIgor Russkikh return -EOPNOTSUPP; 4132d8d6c5a7SIgor Russkikh } else if (mb_params.mcp_resp == (u32)FW_MSG_CODE_DEBUG_NOT_ENABLED) { 4133d8d6c5a7SIgor Russkikh DP_INFO(p_hwfn, "The DEBUG_DATA_SEND command is not enabled\n"); 4134d8d6c5a7SIgor Russkikh return -EBUSY; 4135d8d6c5a7SIgor Russkikh } else if (mb_params.mcp_resp != (u32)FW_MSG_CODE_DEBUG_DATA_SEND_OK) { 4136d8d6c5a7SIgor Russkikh DP_NOTICE(p_hwfn, 4137d8d6c5a7SIgor Russkikh "Failed to send debug data to the MFW [resp 0x%08x]\n", 4138d8d6c5a7SIgor Russkikh mb_params.mcp_resp); 4139d8d6c5a7SIgor Russkikh return -EINVAL; 4140d8d6c5a7SIgor Russkikh } 4141d8d6c5a7SIgor Russkikh 4142d8d6c5a7SIgor Russkikh return 0; 4143d8d6c5a7SIgor Russkikh } 4144d8d6c5a7SIgor Russkikh 4145d8d6c5a7SIgor Russkikh enum qed_mcp_dbg_data_type { 4146d8d6c5a7SIgor Russkikh QED_MCP_DBG_DATA_TYPE_RAW, 4147d8d6c5a7SIgor Russkikh }; 4148d8d6c5a7SIgor Russkikh 4149d8d6c5a7SIgor Russkikh /* Header format: [31:28] PFID, [27:20] flags, [19:12] type, [11:0] S/N */ 4150d8d6c5a7SIgor Russkikh #define QED_MCP_DBG_DATA_HDR_SN_OFFSET 0 4151d8d6c5a7SIgor Russkikh #define QED_MCP_DBG_DATA_HDR_SN_MASK 0x00000fff 4152d8d6c5a7SIgor Russkikh #define QED_MCP_DBG_DATA_HDR_TYPE_OFFSET 12 4153d8d6c5a7SIgor Russkikh #define QED_MCP_DBG_DATA_HDR_TYPE_MASK 0x000ff000 4154d8d6c5a7SIgor Russkikh #define QED_MCP_DBG_DATA_HDR_FLAGS_OFFSET 20 4155d8d6c5a7SIgor Russkikh #define QED_MCP_DBG_DATA_HDR_FLAGS_MASK 0x0ff00000 4156d8d6c5a7SIgor Russkikh #define QED_MCP_DBG_DATA_HDR_PF_OFFSET 28 4157d8d6c5a7SIgor Russkikh #define QED_MCP_DBG_DATA_HDR_PF_MASK 0xf0000000 4158d8d6c5a7SIgor Russkikh 4159d8d6c5a7SIgor Russkikh #define QED_MCP_DBG_DATA_HDR_FLAGS_FIRST 0x1 4160d8d6c5a7SIgor Russkikh #define QED_MCP_DBG_DATA_HDR_FLAGS_LAST 0x2 4161d8d6c5a7SIgor Russkikh 4162d8d6c5a7SIgor Russkikh static int 4163d8d6c5a7SIgor Russkikh qed_mcp_send_debug_data(struct qed_hwfn *p_hwfn, 4164d8d6c5a7SIgor Russkikh struct qed_ptt *p_ptt, 4165d8d6c5a7SIgor Russkikh enum qed_mcp_dbg_data_type type, u8 *p_buf, u32 size) 4166d8d6c5a7SIgor Russkikh { 4167d8d6c5a7SIgor Russkikh u8 raw_data[QED_MCP_DBG_DATA_MAX_SIZE], *p_tmp_buf = p_buf; 4168d8d6c5a7SIgor Russkikh u32 tmp_size = size, *p_header, *p_payload; 4169d8d6c5a7SIgor Russkikh u8 flags = 0; 4170d8d6c5a7SIgor Russkikh u16 seq; 4171d8d6c5a7SIgor Russkikh int rc; 4172d8d6c5a7SIgor Russkikh 4173d8d6c5a7SIgor Russkikh p_header = (u32 *)raw_data; 4174d8d6c5a7SIgor Russkikh p_payload = (u32 *)(raw_data + QED_MCP_DBG_DATA_MAX_HEADER_SIZE); 4175d8d6c5a7SIgor Russkikh 4176d8d6c5a7SIgor Russkikh seq = (u16)atomic_inc_return(&p_hwfn->mcp_info->dbg_data_seq); 4177d8d6c5a7SIgor Russkikh 4178d8d6c5a7SIgor Russkikh /* First chunk is marked as 'first' */ 4179d8d6c5a7SIgor Russkikh flags |= QED_MCP_DBG_DATA_HDR_FLAGS_FIRST; 4180d8d6c5a7SIgor Russkikh 4181d8d6c5a7SIgor Russkikh *p_header = 0; 4182d8d6c5a7SIgor Russkikh SET_MFW_FIELD(*p_header, QED_MCP_DBG_DATA_HDR_SN, seq); 4183d8d6c5a7SIgor Russkikh SET_MFW_FIELD(*p_header, QED_MCP_DBG_DATA_HDR_TYPE, type); 4184d8d6c5a7SIgor Russkikh SET_MFW_FIELD(*p_header, QED_MCP_DBG_DATA_HDR_FLAGS, flags); 4185d8d6c5a7SIgor Russkikh SET_MFW_FIELD(*p_header, QED_MCP_DBG_DATA_HDR_PF, p_hwfn->abs_pf_id); 4186d8d6c5a7SIgor Russkikh 4187d8d6c5a7SIgor Russkikh while (tmp_size > QED_MCP_DBG_DATA_MAX_PAYLOAD_SIZE) { 4188d8d6c5a7SIgor Russkikh memcpy(p_payload, p_tmp_buf, QED_MCP_DBG_DATA_MAX_PAYLOAD_SIZE); 4189d8d6c5a7SIgor Russkikh rc = __qed_mcp_send_debug_data(p_hwfn, p_ptt, raw_data, 4190d8d6c5a7SIgor Russkikh QED_MCP_DBG_DATA_MAX_SIZE); 4191d8d6c5a7SIgor Russkikh if (rc) 4192d8d6c5a7SIgor Russkikh return rc; 4193d8d6c5a7SIgor Russkikh 4194d8d6c5a7SIgor Russkikh /* Clear the 'first' marking after sending the first chunk */ 4195d8d6c5a7SIgor Russkikh if (p_tmp_buf == p_buf) { 4196d8d6c5a7SIgor Russkikh flags &= ~QED_MCP_DBG_DATA_HDR_FLAGS_FIRST; 4197d8d6c5a7SIgor Russkikh SET_MFW_FIELD(*p_header, QED_MCP_DBG_DATA_HDR_FLAGS, 4198d8d6c5a7SIgor Russkikh flags); 4199d8d6c5a7SIgor Russkikh } 4200d8d6c5a7SIgor Russkikh 4201d8d6c5a7SIgor Russkikh p_tmp_buf += QED_MCP_DBG_DATA_MAX_PAYLOAD_SIZE; 4202d8d6c5a7SIgor Russkikh tmp_size -= QED_MCP_DBG_DATA_MAX_PAYLOAD_SIZE; 4203d8d6c5a7SIgor Russkikh } 4204d8d6c5a7SIgor Russkikh 4205d8d6c5a7SIgor Russkikh /* Last chunk is marked as 'last' */ 4206d8d6c5a7SIgor Russkikh flags |= QED_MCP_DBG_DATA_HDR_FLAGS_LAST; 4207d8d6c5a7SIgor Russkikh SET_MFW_FIELD(*p_header, QED_MCP_DBG_DATA_HDR_FLAGS, flags); 4208d8d6c5a7SIgor Russkikh memcpy(p_payload, p_tmp_buf, tmp_size); 4209d8d6c5a7SIgor Russkikh 4210d8d6c5a7SIgor Russkikh /* Casting the left size to u8 is ok since at this point it is <= 32 */ 4211d8d6c5a7SIgor Russkikh return __qed_mcp_send_debug_data(p_hwfn, p_ptt, raw_data, 4212d8d6c5a7SIgor Russkikh (u8)(QED_MCP_DBG_DATA_MAX_HEADER_SIZE + 4213d8d6c5a7SIgor Russkikh tmp_size)); 4214d8d6c5a7SIgor Russkikh } 4215d8d6c5a7SIgor Russkikh 4216d8d6c5a7SIgor Russkikh int 4217d8d6c5a7SIgor Russkikh qed_mcp_send_raw_debug_data(struct qed_hwfn *p_hwfn, 4218d8d6c5a7SIgor Russkikh struct qed_ptt *p_ptt, u8 *p_buf, u32 size) 4219d8d6c5a7SIgor Russkikh { 4220d8d6c5a7SIgor Russkikh return qed_mcp_send_debug_data(p_hwfn, p_ptt, 4221d8d6c5a7SIgor Russkikh QED_MCP_DBG_DATA_TYPE_RAW, p_buf, size); 4222d8d6c5a7SIgor Russkikh } 4223823163baSManish Chopra 4224823163baSManish Chopra bool qed_mcp_is_esl_supported(struct qed_hwfn *p_hwfn) 4225823163baSManish Chopra { 4226823163baSManish Chopra return !!(p_hwfn->mcp_info->capabilities & 4227823163baSManish Chopra FW_MB_PARAM_FEATURE_SUPPORT_ENHANCED_SYS_LCK); 4228823163baSManish Chopra } 4229823163baSManish Chopra 4230823163baSManish Chopra int qed_mcp_get_esl_status(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, bool *active) 4231823163baSManish Chopra { 4232823163baSManish Chopra u32 resp = 0, param = 0; 4233823163baSManish Chopra int rc; 4234823163baSManish Chopra 4235823163baSManish Chopra rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_GET_MANAGEMENT_STATUS, 0, &resp, ¶m); 4236823163baSManish Chopra if (rc) { 4237823163baSManish Chopra DP_NOTICE(p_hwfn, "Failed to send ESL command, rc = %d\n", rc); 4238823163baSManish Chopra return rc; 4239823163baSManish Chopra } 4240823163baSManish Chopra 4241823163baSManish Chopra *active = !!(param & FW_MB_PARAM_MANAGEMENT_STATUS_LOCKDOWN_ENABLED); 4242823163baSManish Chopra 4243823163baSManish Chopra return 0; 4244823163baSManish Chopra } 4245