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 4fe56b9e6SYuval Mintz */ 5fe56b9e6SYuval Mintz 6fe56b9e6SYuval Mintz #include <linux/types.h> 7fe56b9e6SYuval Mintz #include <asm/byteorder.h> 8fe56b9e6SYuval Mintz #include <linux/delay.h> 9fe56b9e6SYuval Mintz #include <linux/errno.h> 10fe56b9e6SYuval Mintz #include <linux/kernel.h> 11fe56b9e6SYuval Mintz #include <linux/slab.h> 125529bad9STomer Tayar #include <linux/spinlock.h> 13fe56b9e6SYuval Mintz #include <linux/string.h> 140fefbfbaSSudarsana Kalluru #include <linux/etherdevice.h> 15fe56b9e6SYuval Mintz #include "qed.h" 16cac6f691SSudarsana Reddy Kalluru #include "qed_cxt.h" 1739651abdSSudarsana Reddy Kalluru #include "qed_dcbx.h" 18fe56b9e6SYuval Mintz #include "qed_hsi.h" 19fe56b9e6SYuval Mintz #include "qed_hw.h" 20fe56b9e6SYuval Mintz #include "qed_mcp.h" 21fe56b9e6SYuval Mintz #include "qed_reg_addr.h" 221408cc1fSYuval Mintz #include "qed_sriov.h" 231408cc1fSYuval Mintz 240500a70dSMichal Kalderon #define GRCBASE_MCP 0xe00000 250500a70dSMichal Kalderon 26eaa50fc5STomer Tayar #define QED_MCP_RESP_ITER_US 10 27fe56b9e6SYuval Mintz 28fe56b9e6SYuval Mintz #define QED_DRV_MB_MAX_RETRIES (500 * 1000) /* Account for 5 sec */ 29fe56b9e6SYuval Mintz #define QED_MCP_RESET_RETRIES (50 * 1000) /* Account for 500 msec */ 30fe56b9e6SYuval Mintz 31fe56b9e6SYuval Mintz #define DRV_INNER_WR(_p_hwfn, _p_ptt, _ptr, _offset, _val) \ 32fe56b9e6SYuval Mintz qed_wr(_p_hwfn, _p_ptt, (_p_hwfn->mcp_info->_ptr + _offset), \ 33fe56b9e6SYuval Mintz _val) 34fe56b9e6SYuval Mintz 35fe56b9e6SYuval Mintz #define DRV_INNER_RD(_p_hwfn, _p_ptt, _ptr, _offset) \ 36fe56b9e6SYuval Mintz qed_rd(_p_hwfn, _p_ptt, (_p_hwfn->mcp_info->_ptr + _offset)) 37fe56b9e6SYuval Mintz 38fe56b9e6SYuval Mintz #define DRV_MB_WR(_p_hwfn, _p_ptt, _field, _val) \ 39fe56b9e6SYuval Mintz DRV_INNER_WR(p_hwfn, _p_ptt, drv_mb_addr, \ 40fe56b9e6SYuval Mintz offsetof(struct public_drv_mb, _field), _val) 41fe56b9e6SYuval Mintz 42fe56b9e6SYuval Mintz #define DRV_MB_RD(_p_hwfn, _p_ptt, _field) \ 43fe56b9e6SYuval Mintz DRV_INNER_RD(_p_hwfn, _p_ptt, drv_mb_addr, \ 44fe56b9e6SYuval Mintz offsetof(struct public_drv_mb, _field)) 45fe56b9e6SYuval Mintz 46fe56b9e6SYuval Mintz #define PDA_COMP (((FW_MAJOR_VERSION) + (FW_MINOR_VERSION << 8)) << \ 47fe56b9e6SYuval Mintz DRV_ID_PDA_COMP_VER_SHIFT) 48fe56b9e6SYuval Mintz 49fe56b9e6SYuval Mintz #define MCP_BYTES_PER_MBIT_SHIFT 17 50fe56b9e6SYuval Mintz 51fe56b9e6SYuval Mintz bool qed_mcp_is_init(struct qed_hwfn *p_hwfn) 52fe56b9e6SYuval Mintz { 53fe56b9e6SYuval Mintz if (!p_hwfn->mcp_info || !p_hwfn->mcp_info->public_base) 54fe56b9e6SYuval Mintz return false; 55fe56b9e6SYuval Mintz return true; 56fe56b9e6SYuval Mintz } 57fe56b9e6SYuval Mintz 581a635e48SYuval Mintz void qed_mcp_cmd_port_init(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 59fe56b9e6SYuval Mintz { 60fe56b9e6SYuval Mintz u32 addr = SECTION_OFFSIZE_ADDR(p_hwfn->mcp_info->public_base, 61fe56b9e6SYuval Mintz PUBLIC_PORT); 62fe56b9e6SYuval Mintz u32 mfw_mb_offsize = qed_rd(p_hwfn, p_ptt, addr); 63fe56b9e6SYuval Mintz 64fe56b9e6SYuval Mintz p_hwfn->mcp_info->port_addr = SECTION_ADDR(mfw_mb_offsize, 65fe56b9e6SYuval Mintz MFW_PORT(p_hwfn)); 66fe56b9e6SYuval Mintz DP_VERBOSE(p_hwfn, QED_MSG_SP, 67fe56b9e6SYuval Mintz "port_addr = 0x%x, port_id 0x%02x\n", 68fe56b9e6SYuval Mintz p_hwfn->mcp_info->port_addr, MFW_PORT(p_hwfn)); 69fe56b9e6SYuval Mintz } 70fe56b9e6SYuval Mintz 711a635e48SYuval Mintz void qed_mcp_read_mb(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 72fe56b9e6SYuval Mintz { 73fe56b9e6SYuval Mintz u32 length = MFW_DRV_MSG_MAX_DWORDS(p_hwfn->mcp_info->mfw_mb_length); 74fe56b9e6SYuval Mintz u32 tmp, i; 75fe56b9e6SYuval Mintz 76fe56b9e6SYuval Mintz if (!p_hwfn->mcp_info->public_base) 77fe56b9e6SYuval Mintz return; 78fe56b9e6SYuval Mintz 79fe56b9e6SYuval Mintz for (i = 0; i < length; i++) { 80fe56b9e6SYuval Mintz tmp = qed_rd(p_hwfn, p_ptt, 81fe56b9e6SYuval Mintz p_hwfn->mcp_info->mfw_mb_addr + 82fe56b9e6SYuval Mintz (i << 2) + sizeof(u32)); 83fe56b9e6SYuval Mintz 84fe56b9e6SYuval Mintz /* The MB data is actually BE; Need to force it to cpu */ 85fe56b9e6SYuval Mintz ((u32 *)p_hwfn->mcp_info->mfw_mb_cur)[i] = 86fe56b9e6SYuval Mintz be32_to_cpu((__force __be32)tmp); 87fe56b9e6SYuval Mintz } 88fe56b9e6SYuval Mintz } 89fe56b9e6SYuval Mintz 904ed1eea8STomer Tayar struct qed_mcp_cmd_elem { 914ed1eea8STomer Tayar struct list_head list; 924ed1eea8STomer Tayar struct qed_mcp_mb_params *p_mb_params; 934ed1eea8STomer Tayar u16 expected_seq_num; 944ed1eea8STomer Tayar bool b_is_completed; 954ed1eea8STomer Tayar }; 964ed1eea8STomer Tayar 974ed1eea8STomer Tayar /* Must be called while cmd_lock is acquired */ 984ed1eea8STomer Tayar static struct qed_mcp_cmd_elem * 994ed1eea8STomer Tayar qed_mcp_cmd_add_elem(struct qed_hwfn *p_hwfn, 1004ed1eea8STomer Tayar struct qed_mcp_mb_params *p_mb_params, 1014ed1eea8STomer Tayar u16 expected_seq_num) 1024ed1eea8STomer Tayar { 1034ed1eea8STomer Tayar struct qed_mcp_cmd_elem *p_cmd_elem = NULL; 1044ed1eea8STomer Tayar 1054ed1eea8STomer Tayar p_cmd_elem = kzalloc(sizeof(*p_cmd_elem), GFP_ATOMIC); 1064ed1eea8STomer Tayar if (!p_cmd_elem) 1074ed1eea8STomer Tayar goto out; 1084ed1eea8STomer Tayar 1094ed1eea8STomer Tayar p_cmd_elem->p_mb_params = p_mb_params; 1104ed1eea8STomer Tayar p_cmd_elem->expected_seq_num = expected_seq_num; 1114ed1eea8STomer Tayar list_add(&p_cmd_elem->list, &p_hwfn->mcp_info->cmd_list); 1124ed1eea8STomer Tayar out: 1134ed1eea8STomer Tayar return p_cmd_elem; 1144ed1eea8STomer Tayar } 1154ed1eea8STomer Tayar 1164ed1eea8STomer Tayar /* Must be called while cmd_lock is acquired */ 1174ed1eea8STomer Tayar static void qed_mcp_cmd_del_elem(struct qed_hwfn *p_hwfn, 1184ed1eea8STomer Tayar struct qed_mcp_cmd_elem *p_cmd_elem) 1194ed1eea8STomer Tayar { 1204ed1eea8STomer Tayar list_del(&p_cmd_elem->list); 1214ed1eea8STomer Tayar kfree(p_cmd_elem); 1224ed1eea8STomer Tayar } 1234ed1eea8STomer Tayar 1244ed1eea8STomer Tayar /* Must be called while cmd_lock is acquired */ 1254ed1eea8STomer Tayar static struct qed_mcp_cmd_elem *qed_mcp_cmd_get_elem(struct qed_hwfn *p_hwfn, 1264ed1eea8STomer Tayar u16 seq_num) 1274ed1eea8STomer Tayar { 1284ed1eea8STomer Tayar struct qed_mcp_cmd_elem *p_cmd_elem = NULL; 1294ed1eea8STomer Tayar 1304ed1eea8STomer Tayar list_for_each_entry(p_cmd_elem, &p_hwfn->mcp_info->cmd_list, list) { 1314ed1eea8STomer Tayar if (p_cmd_elem->expected_seq_num == seq_num) 1324ed1eea8STomer Tayar return p_cmd_elem; 1334ed1eea8STomer Tayar } 1344ed1eea8STomer Tayar 1354ed1eea8STomer Tayar return NULL; 1364ed1eea8STomer Tayar } 1374ed1eea8STomer Tayar 138fe56b9e6SYuval Mintz int qed_mcp_free(struct qed_hwfn *p_hwfn) 139fe56b9e6SYuval Mintz { 140fe56b9e6SYuval Mintz if (p_hwfn->mcp_info) { 1414ed1eea8STomer Tayar struct qed_mcp_cmd_elem *p_cmd_elem, *p_tmp; 1424ed1eea8STomer Tayar 143fe56b9e6SYuval Mintz kfree(p_hwfn->mcp_info->mfw_mb_cur); 144fe56b9e6SYuval Mintz kfree(p_hwfn->mcp_info->mfw_mb_shadow); 1454ed1eea8STomer Tayar 1464ed1eea8STomer Tayar spin_lock_bh(&p_hwfn->mcp_info->cmd_lock); 1474ed1eea8STomer Tayar list_for_each_entry_safe(p_cmd_elem, 1484ed1eea8STomer Tayar p_tmp, 1494ed1eea8STomer Tayar &p_hwfn->mcp_info->cmd_list, list) { 1504ed1eea8STomer Tayar qed_mcp_cmd_del_elem(p_hwfn, p_cmd_elem); 151fe56b9e6SYuval Mintz } 1524ed1eea8STomer Tayar spin_unlock_bh(&p_hwfn->mcp_info->cmd_lock); 1534ed1eea8STomer Tayar } 1544ed1eea8STomer Tayar 155fe56b9e6SYuval Mintz kfree(p_hwfn->mcp_info); 1563587cb87STomer Tayar p_hwfn->mcp_info = NULL; 157fe56b9e6SYuval Mintz 158fe56b9e6SYuval Mintz return 0; 159fe56b9e6SYuval Mintz } 160fe56b9e6SYuval Mintz 161f00d25f3STomer Tayar /* Maximum of 1 sec to wait for the SHMEM ready indication */ 162f00d25f3STomer Tayar #define QED_MCP_SHMEM_RDY_MAX_RETRIES 20 163f00d25f3STomer Tayar #define QED_MCP_SHMEM_RDY_ITER_MS 50 164f00d25f3STomer Tayar 1651a635e48SYuval Mintz static int qed_load_mcp_offsets(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 166fe56b9e6SYuval Mintz { 167fe56b9e6SYuval Mintz struct qed_mcp_info *p_info = p_hwfn->mcp_info; 168f00d25f3STomer Tayar u8 cnt = QED_MCP_SHMEM_RDY_MAX_RETRIES; 169f00d25f3STomer Tayar u8 msec = QED_MCP_SHMEM_RDY_ITER_MS; 170fe56b9e6SYuval Mintz u32 drv_mb_offsize, mfw_mb_offsize; 171fe56b9e6SYuval Mintz u32 mcp_pf_id = MCP_PF_ID(p_hwfn); 172fe56b9e6SYuval Mintz 173fe56b9e6SYuval Mintz p_info->public_base = qed_rd(p_hwfn, p_ptt, MISC_REG_SHARED_MEM_ADDR); 174f00d25f3STomer Tayar if (!p_info->public_base) { 175f00d25f3STomer Tayar DP_NOTICE(p_hwfn, 176f00d25f3STomer Tayar "The address of the MCP scratch-pad is not configured\n"); 177f00d25f3STomer Tayar return -EINVAL; 178f00d25f3STomer Tayar } 179fe56b9e6SYuval Mintz 180fe56b9e6SYuval Mintz p_info->public_base |= GRCBASE_MCP; 181fe56b9e6SYuval Mintz 182f00d25f3STomer Tayar /* Get the MFW MB address and number of supported messages */ 183f00d25f3STomer Tayar mfw_mb_offsize = qed_rd(p_hwfn, p_ptt, 184f00d25f3STomer Tayar SECTION_OFFSIZE_ADDR(p_info->public_base, 185f00d25f3STomer Tayar PUBLIC_MFW_MB)); 186f00d25f3STomer Tayar p_info->mfw_mb_addr = SECTION_ADDR(mfw_mb_offsize, mcp_pf_id); 187f00d25f3STomer Tayar p_info->mfw_mb_length = (u16)qed_rd(p_hwfn, p_ptt, 188f00d25f3STomer Tayar p_info->mfw_mb_addr + 189f00d25f3STomer Tayar offsetof(struct public_mfw_mb, 190f00d25f3STomer Tayar sup_msgs)); 191f00d25f3STomer Tayar 192f00d25f3STomer Tayar /* The driver can notify that there was an MCP reset, and might read the 193f00d25f3STomer Tayar * SHMEM values before the MFW has completed initializing them. 194f00d25f3STomer Tayar * To avoid this, the "sup_msgs" field in the MFW mailbox is used as a 195f00d25f3STomer Tayar * data ready indication. 196f00d25f3STomer Tayar */ 197f00d25f3STomer Tayar while (!p_info->mfw_mb_length && --cnt) { 198f00d25f3STomer Tayar msleep(msec); 199f00d25f3STomer Tayar p_info->mfw_mb_length = 200f00d25f3STomer Tayar (u16)qed_rd(p_hwfn, p_ptt, 201f00d25f3STomer Tayar p_info->mfw_mb_addr + 202f00d25f3STomer Tayar offsetof(struct public_mfw_mb, sup_msgs)); 203f00d25f3STomer Tayar } 204f00d25f3STomer Tayar 205f00d25f3STomer Tayar if (!cnt) { 206f00d25f3STomer Tayar DP_NOTICE(p_hwfn, 207f00d25f3STomer Tayar "Failed to get the SHMEM ready notification after %d msec\n", 208f00d25f3STomer Tayar QED_MCP_SHMEM_RDY_MAX_RETRIES * msec); 209f00d25f3STomer Tayar return -EBUSY; 210f00d25f3STomer Tayar } 211f00d25f3STomer Tayar 212fe56b9e6SYuval Mintz /* Calculate the driver and MFW mailbox address */ 213fe56b9e6SYuval Mintz drv_mb_offsize = qed_rd(p_hwfn, p_ptt, 214fe56b9e6SYuval Mintz SECTION_OFFSIZE_ADDR(p_info->public_base, 215fe56b9e6SYuval Mintz PUBLIC_DRV_MB)); 216fe56b9e6SYuval Mintz p_info->drv_mb_addr = SECTION_ADDR(drv_mb_offsize, mcp_pf_id); 217fe56b9e6SYuval Mintz DP_VERBOSE(p_hwfn, QED_MSG_SP, 218fe56b9e6SYuval Mintz "drv_mb_offsiz = 0x%x, drv_mb_addr = 0x%x mcp_pf_id = 0x%x\n", 219fe56b9e6SYuval Mintz drv_mb_offsize, p_info->drv_mb_addr, mcp_pf_id); 220fe56b9e6SYuval Mintz 221fe56b9e6SYuval Mintz /* Get the current driver mailbox sequence before sending 222fe56b9e6SYuval Mintz * the first command 223fe56b9e6SYuval Mintz */ 224fe56b9e6SYuval Mintz p_info->drv_mb_seq = DRV_MB_RD(p_hwfn, p_ptt, drv_mb_header) & 225fe56b9e6SYuval Mintz DRV_MSG_SEQ_NUMBER_MASK; 226fe56b9e6SYuval Mintz 227fe56b9e6SYuval Mintz /* Get current FW pulse sequence */ 228fe56b9e6SYuval Mintz p_info->drv_pulse_seq = DRV_MB_RD(p_hwfn, p_ptt, drv_pulse_mb) & 229fe56b9e6SYuval Mintz DRV_PULSE_SEQ_MASK; 230fe56b9e6SYuval Mintz 2314ed1eea8STomer Tayar p_info->mcp_hist = qed_rd(p_hwfn, p_ptt, MISCS_REG_GENERIC_POR_0); 232fe56b9e6SYuval Mintz 233fe56b9e6SYuval Mintz return 0; 234fe56b9e6SYuval Mintz } 235fe56b9e6SYuval Mintz 2361a635e48SYuval Mintz int qed_mcp_cmd_init(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 237fe56b9e6SYuval Mintz { 238fe56b9e6SYuval Mintz struct qed_mcp_info *p_info; 239fe56b9e6SYuval Mintz u32 size; 240fe56b9e6SYuval Mintz 241fe56b9e6SYuval Mintz /* Allocate mcp_info structure */ 24260fffb3bSYuval Mintz p_hwfn->mcp_info = kzalloc(sizeof(*p_hwfn->mcp_info), GFP_KERNEL); 243fe56b9e6SYuval Mintz if (!p_hwfn->mcp_info) 244fe56b9e6SYuval Mintz goto err; 245fe56b9e6SYuval Mintz p_info = p_hwfn->mcp_info; 246fe56b9e6SYuval Mintz 2474ed1eea8STomer Tayar /* Initialize the MFW spinlock */ 2484ed1eea8STomer Tayar spin_lock_init(&p_info->cmd_lock); 2494ed1eea8STomer Tayar spin_lock_init(&p_info->link_lock); 2504ed1eea8STomer Tayar 2514ed1eea8STomer Tayar INIT_LIST_HEAD(&p_info->cmd_list); 2524ed1eea8STomer Tayar 253fe56b9e6SYuval Mintz if (qed_load_mcp_offsets(p_hwfn, p_ptt) != 0) { 254fe56b9e6SYuval Mintz DP_NOTICE(p_hwfn, "MCP is not initialized\n"); 255fe56b9e6SYuval Mintz /* Do not free mcp_info here, since public_base indicate that 256fe56b9e6SYuval Mintz * the MCP is not initialized 257fe56b9e6SYuval Mintz */ 258fe56b9e6SYuval Mintz return 0; 259fe56b9e6SYuval Mintz } 260fe56b9e6SYuval Mintz 261fe56b9e6SYuval Mintz size = MFW_DRV_MSG_MAX_DWORDS(p_info->mfw_mb_length) * sizeof(u32); 26260fffb3bSYuval Mintz p_info->mfw_mb_cur = kzalloc(size, GFP_KERNEL); 26383aeb933SYuval Mintz p_info->mfw_mb_shadow = kzalloc(size, GFP_KERNEL); 264eb2a6b80SChristophe Jaillet if (!p_info->mfw_mb_cur || !p_info->mfw_mb_shadow) 265fe56b9e6SYuval Mintz goto err; 266fe56b9e6SYuval Mintz 267fe56b9e6SYuval Mintz return 0; 268fe56b9e6SYuval Mintz 269fe56b9e6SYuval Mintz err: 270fe56b9e6SYuval Mintz qed_mcp_free(p_hwfn); 271fe56b9e6SYuval Mintz return -ENOMEM; 272fe56b9e6SYuval Mintz } 273fe56b9e6SYuval Mintz 2744ed1eea8STomer Tayar static void qed_mcp_reread_offsets(struct qed_hwfn *p_hwfn, 2754ed1eea8STomer Tayar struct qed_ptt *p_ptt) 2765529bad9STomer Tayar { 2774ed1eea8STomer Tayar u32 generic_por_0 = qed_rd(p_hwfn, p_ptt, MISCS_REG_GENERIC_POR_0); 2785529bad9STomer Tayar 2794ed1eea8STomer Tayar /* Use MCP history register to check if MCP reset occurred between init 2804ed1eea8STomer Tayar * time and now. 2815529bad9STomer Tayar */ 2824ed1eea8STomer Tayar if (p_hwfn->mcp_info->mcp_hist != generic_por_0) { 2834ed1eea8STomer Tayar DP_VERBOSE(p_hwfn, 2844ed1eea8STomer Tayar QED_MSG_SP, 2854ed1eea8STomer Tayar "Rereading MCP offsets [mcp_hist 0x%08x, generic_por_0 0x%08x]\n", 2864ed1eea8STomer Tayar p_hwfn->mcp_info->mcp_hist, generic_por_0); 2875529bad9STomer Tayar 2884ed1eea8STomer Tayar qed_load_mcp_offsets(p_hwfn, p_ptt); 2894ed1eea8STomer Tayar qed_mcp_cmd_port_init(p_hwfn, p_ptt); 2905529bad9STomer Tayar } 2915529bad9STomer Tayar } 2925529bad9STomer Tayar 2931a635e48SYuval Mintz int qed_mcp_reset(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 294fe56b9e6SYuval Mintz { 295eaa50fc5STomer Tayar u32 org_mcp_reset_seq, seq, delay = QED_MCP_RESP_ITER_US, cnt = 0; 296fe56b9e6SYuval Mintz int rc = 0; 297fe56b9e6SYuval Mintz 298b310974eSTomer Tayar if (p_hwfn->mcp_info->b_block_cmd) { 299b310974eSTomer Tayar DP_NOTICE(p_hwfn, 300b310974eSTomer Tayar "The MFW is not responsive. Avoid sending MCP_RESET mailbox command.\n"); 301b310974eSTomer Tayar return -EBUSY; 302b310974eSTomer Tayar } 303b310974eSTomer Tayar 3044ed1eea8STomer Tayar /* Ensure that only a single thread is accessing the mailbox */ 3054ed1eea8STomer Tayar spin_lock_bh(&p_hwfn->mcp_info->cmd_lock); 3064ed1eea8STomer Tayar 3074ed1eea8STomer Tayar org_mcp_reset_seq = qed_rd(p_hwfn, p_ptt, MISCS_REG_GENERIC_POR_0); 3085529bad9STomer Tayar 309fe56b9e6SYuval Mintz /* Set drv command along with the updated sequence */ 3104ed1eea8STomer Tayar qed_mcp_reread_offsets(p_hwfn, p_ptt); 3114ed1eea8STomer Tayar seq = ++p_hwfn->mcp_info->drv_mb_seq; 3124ed1eea8STomer Tayar DRV_MB_WR(p_hwfn, p_ptt, drv_mb_header, (DRV_MSG_CODE_MCP_RESET | seq)); 313fe56b9e6SYuval Mintz 314fe56b9e6SYuval Mintz do { 315fe56b9e6SYuval Mintz /* Wait for MFW response */ 316fe56b9e6SYuval Mintz udelay(delay); 317fe56b9e6SYuval Mintz /* Give the FW up to 500 second (50*1000*10usec) */ 318fe56b9e6SYuval Mintz } while ((org_mcp_reset_seq == qed_rd(p_hwfn, p_ptt, 319fe56b9e6SYuval Mintz MISCS_REG_GENERIC_POR_0)) && 320fe56b9e6SYuval Mintz (cnt++ < QED_MCP_RESET_RETRIES)); 321fe56b9e6SYuval Mintz 322fe56b9e6SYuval Mintz if (org_mcp_reset_seq != 323fe56b9e6SYuval Mintz qed_rd(p_hwfn, p_ptt, MISCS_REG_GENERIC_POR_0)) { 324fe56b9e6SYuval Mintz DP_VERBOSE(p_hwfn, QED_MSG_SP, 325fe56b9e6SYuval Mintz "MCP was reset after %d usec\n", cnt * delay); 326fe56b9e6SYuval Mintz } else { 327fe56b9e6SYuval Mintz DP_ERR(p_hwfn, "Failed to reset MCP\n"); 328fe56b9e6SYuval Mintz rc = -EAGAIN; 329fe56b9e6SYuval Mintz } 330fe56b9e6SYuval Mintz 3314ed1eea8STomer Tayar spin_unlock_bh(&p_hwfn->mcp_info->cmd_lock); 3325529bad9STomer Tayar 333fe56b9e6SYuval Mintz return rc; 334fe56b9e6SYuval Mintz } 335fe56b9e6SYuval Mintz 3364ed1eea8STomer Tayar /* Must be called while cmd_lock is acquired */ 3374ed1eea8STomer Tayar static bool qed_mcp_has_pending_cmd(struct qed_hwfn *p_hwfn) 338fe56b9e6SYuval Mintz { 3394ed1eea8STomer Tayar struct qed_mcp_cmd_elem *p_cmd_elem; 3404ed1eea8STomer Tayar 3414ed1eea8STomer Tayar /* There is at most one pending command at a certain time, and if it 3424ed1eea8STomer Tayar * exists - it is placed at the HEAD of the list. 3434ed1eea8STomer Tayar */ 3444ed1eea8STomer Tayar if (!list_empty(&p_hwfn->mcp_info->cmd_list)) { 3454ed1eea8STomer Tayar p_cmd_elem = list_first_entry(&p_hwfn->mcp_info->cmd_list, 3464ed1eea8STomer Tayar struct qed_mcp_cmd_elem, list); 3474ed1eea8STomer Tayar return !p_cmd_elem->b_is_completed; 3484ed1eea8STomer Tayar } 3494ed1eea8STomer Tayar 3504ed1eea8STomer Tayar return false; 3514ed1eea8STomer Tayar } 3524ed1eea8STomer Tayar 3534ed1eea8STomer Tayar /* Must be called while cmd_lock is acquired */ 3544ed1eea8STomer Tayar static int 3554ed1eea8STomer Tayar qed_mcp_update_pending_cmd(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 3564ed1eea8STomer Tayar { 3574ed1eea8STomer Tayar struct qed_mcp_mb_params *p_mb_params; 3584ed1eea8STomer Tayar struct qed_mcp_cmd_elem *p_cmd_elem; 3594ed1eea8STomer Tayar u32 mcp_resp; 3604ed1eea8STomer Tayar u16 seq_num; 3614ed1eea8STomer Tayar 3624ed1eea8STomer Tayar mcp_resp = DRV_MB_RD(p_hwfn, p_ptt, fw_mb_header); 3634ed1eea8STomer Tayar seq_num = (u16)(mcp_resp & FW_MSG_SEQ_NUMBER_MASK); 3644ed1eea8STomer Tayar 3654ed1eea8STomer Tayar /* Return if no new non-handled response has been received */ 3664ed1eea8STomer Tayar if (seq_num != p_hwfn->mcp_info->drv_mb_seq) 3674ed1eea8STomer Tayar return -EAGAIN; 3684ed1eea8STomer Tayar 3694ed1eea8STomer Tayar p_cmd_elem = qed_mcp_cmd_get_elem(p_hwfn, seq_num); 3704ed1eea8STomer Tayar if (!p_cmd_elem) { 3714ed1eea8STomer Tayar DP_ERR(p_hwfn, 3724ed1eea8STomer Tayar "Failed to find a pending mailbox cmd that expects sequence number %d\n", 3734ed1eea8STomer Tayar seq_num); 3744ed1eea8STomer Tayar return -EINVAL; 3754ed1eea8STomer Tayar } 3764ed1eea8STomer Tayar 3774ed1eea8STomer Tayar p_mb_params = p_cmd_elem->p_mb_params; 3784ed1eea8STomer Tayar 3794ed1eea8STomer Tayar /* Get the MFW response along with the sequence number */ 3804ed1eea8STomer Tayar p_mb_params->mcp_resp = mcp_resp; 3814ed1eea8STomer Tayar 3824ed1eea8STomer Tayar /* Get the MFW param */ 3834ed1eea8STomer Tayar p_mb_params->mcp_param = DRV_MB_RD(p_hwfn, p_ptt, fw_mb_param); 3844ed1eea8STomer Tayar 3854ed1eea8STomer Tayar /* Get the union data */ 3862f67af8cSTomer Tayar if (p_mb_params->p_data_dst != NULL && p_mb_params->data_dst_size) { 3874ed1eea8STomer Tayar u32 union_data_addr = p_hwfn->mcp_info->drv_mb_addr + 3884ed1eea8STomer Tayar offsetof(struct public_drv_mb, 3894ed1eea8STomer Tayar union_data); 3904ed1eea8STomer Tayar qed_memcpy_from(p_hwfn, p_ptt, p_mb_params->p_data_dst, 3912f67af8cSTomer Tayar union_data_addr, p_mb_params->data_dst_size); 3924ed1eea8STomer Tayar } 3934ed1eea8STomer Tayar 3944ed1eea8STomer Tayar p_cmd_elem->b_is_completed = true; 3954ed1eea8STomer Tayar 3964ed1eea8STomer Tayar return 0; 3974ed1eea8STomer Tayar } 3984ed1eea8STomer Tayar 3994ed1eea8STomer Tayar /* Must be called while cmd_lock is acquired */ 4004ed1eea8STomer Tayar static void __qed_mcp_cmd_and_union(struct qed_hwfn *p_hwfn, 4014ed1eea8STomer Tayar struct qed_ptt *p_ptt, 4024ed1eea8STomer Tayar struct qed_mcp_mb_params *p_mb_params, 4034ed1eea8STomer Tayar u16 seq_num) 4044ed1eea8STomer Tayar { 4054ed1eea8STomer Tayar union drv_union_data union_data; 4064ed1eea8STomer Tayar u32 union_data_addr; 4074ed1eea8STomer Tayar 4084ed1eea8STomer Tayar /* Set the union data */ 4094ed1eea8STomer Tayar union_data_addr = p_hwfn->mcp_info->drv_mb_addr + 4104ed1eea8STomer Tayar offsetof(struct public_drv_mb, union_data); 4114ed1eea8STomer Tayar memset(&union_data, 0, sizeof(union_data)); 4122f67af8cSTomer Tayar if (p_mb_params->p_data_src != NULL && p_mb_params->data_src_size) 4134ed1eea8STomer Tayar memcpy(&union_data, p_mb_params->p_data_src, 4142f67af8cSTomer Tayar p_mb_params->data_src_size); 4154ed1eea8STomer Tayar qed_memcpy_to(p_hwfn, p_ptt, union_data_addr, &union_data, 4164ed1eea8STomer Tayar sizeof(union_data)); 4174ed1eea8STomer Tayar 4184ed1eea8STomer Tayar /* Set the drv param */ 4194ed1eea8STomer Tayar DRV_MB_WR(p_hwfn, p_ptt, drv_mb_param, p_mb_params->param); 4204ed1eea8STomer Tayar 4214ed1eea8STomer Tayar /* Set the drv command along with the sequence number */ 4224ed1eea8STomer Tayar DRV_MB_WR(p_hwfn, p_ptt, drv_mb_header, (p_mb_params->cmd | seq_num)); 4234ed1eea8STomer Tayar 4244ed1eea8STomer Tayar DP_VERBOSE(p_hwfn, QED_MSG_SP, 4254ed1eea8STomer Tayar "MFW mailbox: command 0x%08x param 0x%08x\n", 4264ed1eea8STomer Tayar (p_mb_params->cmd | seq_num), p_mb_params->param); 4274ed1eea8STomer Tayar } 4284ed1eea8STomer Tayar 429b310974eSTomer Tayar static void qed_mcp_cmd_set_blocking(struct qed_hwfn *p_hwfn, bool block_cmd) 430b310974eSTomer Tayar { 431b310974eSTomer Tayar p_hwfn->mcp_info->b_block_cmd = block_cmd; 432b310974eSTomer Tayar 433b310974eSTomer Tayar DP_INFO(p_hwfn, "%s sending of mailbox commands to the MFW\n", 434b310974eSTomer Tayar block_cmd ? "Block" : "Unblock"); 435b310974eSTomer Tayar } 436b310974eSTomer Tayar 437b310974eSTomer Tayar static void qed_mcp_print_cpu_info(struct qed_hwfn *p_hwfn, 438b310974eSTomer Tayar struct qed_ptt *p_ptt) 439b310974eSTomer Tayar { 440b310974eSTomer Tayar u32 cpu_mode, cpu_state, cpu_pc_0, cpu_pc_1, cpu_pc_2; 441b310974eSTomer Tayar u32 delay = QED_MCP_RESP_ITER_US; 442b310974eSTomer Tayar 443b310974eSTomer Tayar cpu_mode = qed_rd(p_hwfn, p_ptt, MCP_REG_CPU_MODE); 444b310974eSTomer Tayar cpu_state = qed_rd(p_hwfn, p_ptt, MCP_REG_CPU_STATE); 445b310974eSTomer Tayar cpu_pc_0 = qed_rd(p_hwfn, p_ptt, MCP_REG_CPU_PROGRAM_COUNTER); 446b310974eSTomer Tayar udelay(delay); 447b310974eSTomer Tayar cpu_pc_1 = qed_rd(p_hwfn, p_ptt, MCP_REG_CPU_PROGRAM_COUNTER); 448b310974eSTomer Tayar udelay(delay); 449b310974eSTomer Tayar cpu_pc_2 = qed_rd(p_hwfn, p_ptt, MCP_REG_CPU_PROGRAM_COUNTER); 450b310974eSTomer Tayar 451b310974eSTomer Tayar DP_NOTICE(p_hwfn, 452b310974eSTomer Tayar "MCP CPU info: mode 0x%08x, state 0x%08x, pc {0x%08x, 0x%08x, 0x%08x}\n", 453b310974eSTomer Tayar cpu_mode, cpu_state, cpu_pc_0, cpu_pc_1, cpu_pc_2); 454b310974eSTomer Tayar } 455b310974eSTomer Tayar 4564ed1eea8STomer Tayar static int 4574ed1eea8STomer Tayar _qed_mcp_cmd_and_union(struct qed_hwfn *p_hwfn, 4584ed1eea8STomer Tayar struct qed_ptt *p_ptt, 4594ed1eea8STomer Tayar struct qed_mcp_mb_params *p_mb_params, 460eaa50fc5STomer Tayar u32 max_retries, u32 usecs) 4614ed1eea8STomer Tayar { 462eaa50fc5STomer Tayar u32 cnt = 0, msecs = DIV_ROUND_UP(usecs, 1000); 4634ed1eea8STomer Tayar struct qed_mcp_cmd_elem *p_cmd_elem; 4644ed1eea8STomer Tayar u16 seq_num; 465fe56b9e6SYuval Mintz int rc = 0; 466fe56b9e6SYuval Mintz 4674ed1eea8STomer Tayar /* Wait until the mailbox is non-occupied */ 468fe56b9e6SYuval Mintz do { 4694ed1eea8STomer Tayar /* Exit the loop if there is no pending command, or if the 4704ed1eea8STomer Tayar * pending command is completed during this iteration. 4714ed1eea8STomer Tayar * The spinlock stays locked until the command is sent. 4724ed1eea8STomer Tayar */ 4734ed1eea8STomer Tayar 4744ed1eea8STomer Tayar spin_lock_bh(&p_hwfn->mcp_info->cmd_lock); 4754ed1eea8STomer Tayar 4764ed1eea8STomer Tayar if (!qed_mcp_has_pending_cmd(p_hwfn)) 4774ed1eea8STomer Tayar break; 4784ed1eea8STomer Tayar 4794ed1eea8STomer Tayar rc = qed_mcp_update_pending_cmd(p_hwfn, p_ptt); 4804ed1eea8STomer Tayar if (!rc) 4814ed1eea8STomer Tayar break; 4824ed1eea8STomer Tayar else if (rc != -EAGAIN) 4834ed1eea8STomer Tayar goto err; 4844ed1eea8STomer Tayar 4854ed1eea8STomer Tayar spin_unlock_bh(&p_hwfn->mcp_info->cmd_lock); 486eaa50fc5STomer Tayar 487eaa50fc5STomer Tayar if (QED_MB_FLAGS_IS_SET(p_mb_params, CAN_SLEEP)) 488eaa50fc5STomer Tayar msleep(msecs); 489eaa50fc5STomer Tayar else 490eaa50fc5STomer Tayar udelay(usecs); 4914ed1eea8STomer Tayar } while (++cnt < max_retries); 492fe56b9e6SYuval Mintz 4934ed1eea8STomer Tayar if (cnt >= max_retries) { 4944ed1eea8STomer Tayar DP_NOTICE(p_hwfn, 4954ed1eea8STomer Tayar "The MFW mailbox is occupied by an uncompleted command. Failed to send command 0x%08x [param 0x%08x].\n", 4964ed1eea8STomer Tayar p_mb_params->cmd, p_mb_params->param); 4974ed1eea8STomer Tayar return -EAGAIN; 498fe56b9e6SYuval Mintz } 4994ed1eea8STomer Tayar 5004ed1eea8STomer Tayar /* Send the mailbox command */ 5014ed1eea8STomer Tayar qed_mcp_reread_offsets(p_hwfn, p_ptt); 5024ed1eea8STomer Tayar seq_num = ++p_hwfn->mcp_info->drv_mb_seq; 5034ed1eea8STomer Tayar p_cmd_elem = qed_mcp_cmd_add_elem(p_hwfn, p_mb_params, seq_num); 504c8004600SDan Carpenter if (!p_cmd_elem) { 505c8004600SDan Carpenter rc = -ENOMEM; 5064ed1eea8STomer Tayar goto err; 507c8004600SDan Carpenter } 5084ed1eea8STomer Tayar 5094ed1eea8STomer Tayar __qed_mcp_cmd_and_union(p_hwfn, p_ptt, p_mb_params, seq_num); 5104ed1eea8STomer Tayar spin_unlock_bh(&p_hwfn->mcp_info->cmd_lock); 5114ed1eea8STomer Tayar 5124ed1eea8STomer Tayar /* Wait for the MFW response */ 5134ed1eea8STomer Tayar do { 5144ed1eea8STomer Tayar /* Exit the loop if the command is already completed, or if the 5154ed1eea8STomer Tayar * command is completed during this iteration. 5164ed1eea8STomer Tayar * The spinlock stays locked until the list element is removed. 5174ed1eea8STomer Tayar */ 5184ed1eea8STomer Tayar 519eaa50fc5STomer Tayar if (QED_MB_FLAGS_IS_SET(p_mb_params, CAN_SLEEP)) 520eaa50fc5STomer Tayar msleep(msecs); 521eaa50fc5STomer Tayar else 522eaa50fc5STomer Tayar udelay(usecs); 523eaa50fc5STomer Tayar 5244ed1eea8STomer Tayar spin_lock_bh(&p_hwfn->mcp_info->cmd_lock); 5254ed1eea8STomer Tayar 5264ed1eea8STomer Tayar if (p_cmd_elem->b_is_completed) 5274ed1eea8STomer Tayar break; 5284ed1eea8STomer Tayar 5294ed1eea8STomer Tayar rc = qed_mcp_update_pending_cmd(p_hwfn, p_ptt); 5304ed1eea8STomer Tayar if (!rc) 5314ed1eea8STomer Tayar break; 5324ed1eea8STomer Tayar else if (rc != -EAGAIN) 5334ed1eea8STomer Tayar goto err; 5344ed1eea8STomer Tayar 5354ed1eea8STomer Tayar spin_unlock_bh(&p_hwfn->mcp_info->cmd_lock); 5364ed1eea8STomer Tayar } while (++cnt < max_retries); 5374ed1eea8STomer Tayar 5384ed1eea8STomer Tayar if (cnt >= max_retries) { 5394ed1eea8STomer Tayar DP_NOTICE(p_hwfn, 5404ed1eea8STomer Tayar "The MFW failed to respond to command 0x%08x [param 0x%08x].\n", 5414ed1eea8STomer Tayar p_mb_params->cmd, p_mb_params->param); 542b310974eSTomer Tayar qed_mcp_print_cpu_info(p_hwfn, p_ptt); 5434ed1eea8STomer Tayar 5444ed1eea8STomer Tayar spin_lock_bh(&p_hwfn->mcp_info->cmd_lock); 5454ed1eea8STomer Tayar qed_mcp_cmd_del_elem(p_hwfn, p_cmd_elem); 5464ed1eea8STomer Tayar spin_unlock_bh(&p_hwfn->mcp_info->cmd_lock); 5474ed1eea8STomer Tayar 548b310974eSTomer Tayar if (!QED_MB_FLAGS_IS_SET(p_mb_params, AVOID_BLOCK)) 549b310974eSTomer Tayar qed_mcp_cmd_set_blocking(p_hwfn, true); 550b310974eSTomer Tayar 5512ec276d5SIgor Russkikh qed_hw_err_notify(p_hwfn, p_ptt, 5522ec276d5SIgor Russkikh QED_HW_ERR_MFW_RESP_FAIL, NULL); 5534ed1eea8STomer Tayar return -EAGAIN; 5544ed1eea8STomer Tayar } 5554ed1eea8STomer Tayar 5564ed1eea8STomer Tayar qed_mcp_cmd_del_elem(p_hwfn, p_cmd_elem); 5574ed1eea8STomer Tayar spin_unlock_bh(&p_hwfn->mcp_info->cmd_lock); 5584ed1eea8STomer Tayar 5594ed1eea8STomer Tayar DP_VERBOSE(p_hwfn, 5604ed1eea8STomer Tayar QED_MSG_SP, 5614ed1eea8STomer Tayar "MFW mailbox: response 0x%08x param 0x%08x [after %d.%03d ms]\n", 5624ed1eea8STomer Tayar p_mb_params->mcp_resp, 5634ed1eea8STomer Tayar p_mb_params->mcp_param, 564eaa50fc5STomer Tayar (cnt * usecs) / 1000, (cnt * usecs) % 1000); 5654ed1eea8STomer Tayar 5664ed1eea8STomer Tayar /* Clear the sequence number from the MFW response */ 5674ed1eea8STomer Tayar p_mb_params->mcp_resp &= FW_MSG_CODE_MASK; 5684ed1eea8STomer Tayar 5694ed1eea8STomer Tayar return 0; 5704ed1eea8STomer Tayar 5714ed1eea8STomer Tayar err: 5724ed1eea8STomer Tayar spin_unlock_bh(&p_hwfn->mcp_info->cmd_lock); 573fe56b9e6SYuval Mintz return rc; 574fe56b9e6SYuval Mintz } 575fe56b9e6SYuval Mintz 5765529bad9STomer Tayar static int qed_mcp_cmd_and_union(struct qed_hwfn *p_hwfn, 577fe56b9e6SYuval Mintz struct qed_ptt *p_ptt, 5785529bad9STomer Tayar struct qed_mcp_mb_params *p_mb_params) 579fe56b9e6SYuval Mintz { 5802f67af8cSTomer Tayar size_t union_data_size = sizeof(union drv_union_data); 5814ed1eea8STomer Tayar u32 max_retries = QED_DRV_MB_MAX_RETRIES; 582eaa50fc5STomer Tayar u32 usecs = QED_MCP_RESP_ITER_US; 583fe56b9e6SYuval Mintz 584fe56b9e6SYuval Mintz /* MCP not initialized */ 585fe56b9e6SYuval Mintz if (!qed_mcp_is_init(p_hwfn)) { 586fe56b9e6SYuval Mintz DP_NOTICE(p_hwfn, "MFW is not initialized!\n"); 587fe56b9e6SYuval Mintz return -EBUSY; 588fe56b9e6SYuval Mintz } 589fe56b9e6SYuval Mintz 590b310974eSTomer Tayar if (p_hwfn->mcp_info->b_block_cmd) { 591b310974eSTomer Tayar DP_NOTICE(p_hwfn, 592b310974eSTomer Tayar "The MFW is not responsive. Avoid sending mailbox command 0x%08x [param 0x%08x].\n", 593b310974eSTomer Tayar p_mb_params->cmd, p_mb_params->param); 594b310974eSTomer Tayar return -EBUSY; 595b310974eSTomer Tayar } 596b310974eSTomer Tayar 5972f67af8cSTomer Tayar if (p_mb_params->data_src_size > union_data_size || 5982f67af8cSTomer Tayar p_mb_params->data_dst_size > union_data_size) { 5992f67af8cSTomer Tayar DP_ERR(p_hwfn, 6002f67af8cSTomer Tayar "The provided size is larger than the union data size [src_size %u, dst_size %u, union_data_size %zu]\n", 6012f67af8cSTomer Tayar p_mb_params->data_src_size, 6022f67af8cSTomer Tayar p_mb_params->data_dst_size, union_data_size); 6032f67af8cSTomer Tayar return -EINVAL; 6042f67af8cSTomer Tayar } 6052f67af8cSTomer Tayar 606eaa50fc5STomer Tayar if (QED_MB_FLAGS_IS_SET(p_mb_params, CAN_SLEEP)) { 607eaa50fc5STomer Tayar max_retries = DIV_ROUND_UP(max_retries, 1000); 608eaa50fc5STomer Tayar usecs *= 1000; 609eaa50fc5STomer Tayar } 610eaa50fc5STomer Tayar 6114ed1eea8STomer Tayar return _qed_mcp_cmd_and_union(p_hwfn, p_ptt, p_mb_params, max_retries, 612eaa50fc5STomer Tayar usecs); 613fe56b9e6SYuval Mintz } 614fe56b9e6SYuval Mintz 6155529bad9STomer Tayar int qed_mcp_cmd(struct qed_hwfn *p_hwfn, 6165529bad9STomer Tayar struct qed_ptt *p_ptt, 6175529bad9STomer Tayar u32 cmd, 6185529bad9STomer Tayar u32 param, 6195529bad9STomer Tayar u32 *o_mcp_resp, 6205529bad9STomer Tayar u32 *o_mcp_param) 621fe56b9e6SYuval Mintz { 6225529bad9STomer Tayar struct qed_mcp_mb_params mb_params; 6235529bad9STomer Tayar int rc; 624fe56b9e6SYuval Mintz 6255529bad9STomer Tayar memset(&mb_params, 0, sizeof(mb_params)); 6265529bad9STomer Tayar mb_params.cmd = cmd; 6275529bad9STomer Tayar mb_params.param = param; 62814d39648SMintz, Yuval 6295529bad9STomer Tayar rc = qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 6305529bad9STomer Tayar if (rc) 6315529bad9STomer Tayar return rc; 6325529bad9STomer Tayar 6335529bad9STomer Tayar *o_mcp_resp = mb_params.mcp_resp; 6345529bad9STomer Tayar *o_mcp_param = mb_params.mcp_param; 6355529bad9STomer Tayar 6365529bad9STomer Tayar return 0; 637fe56b9e6SYuval Mintz } 638fe56b9e6SYuval Mintz 639bf774d14SYueHaibing static int 640bf774d14SYueHaibing qed_mcp_nvm_wr_cmd(struct qed_hwfn *p_hwfn, 64162e4d438SSudarsana Reddy Kalluru struct qed_ptt *p_ptt, 64262e4d438SSudarsana Reddy Kalluru u32 cmd, 64362e4d438SSudarsana Reddy Kalluru u32 param, 64462e4d438SSudarsana Reddy Kalluru u32 *o_mcp_resp, 64562e4d438SSudarsana Reddy Kalluru u32 *o_mcp_param, u32 i_txn_size, u32 *i_buf) 64662e4d438SSudarsana Reddy Kalluru { 64762e4d438SSudarsana Reddy Kalluru struct qed_mcp_mb_params mb_params; 64862e4d438SSudarsana Reddy Kalluru int rc; 64962e4d438SSudarsana Reddy Kalluru 65062e4d438SSudarsana Reddy Kalluru memset(&mb_params, 0, sizeof(mb_params)); 65162e4d438SSudarsana Reddy Kalluru mb_params.cmd = cmd; 65262e4d438SSudarsana Reddy Kalluru mb_params.param = param; 65362e4d438SSudarsana Reddy Kalluru mb_params.p_data_src = i_buf; 65462e4d438SSudarsana Reddy Kalluru mb_params.data_src_size = (u8)i_txn_size; 65562e4d438SSudarsana Reddy Kalluru rc = qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 65662e4d438SSudarsana Reddy Kalluru if (rc) 65762e4d438SSudarsana Reddy Kalluru return rc; 65862e4d438SSudarsana Reddy Kalluru 65962e4d438SSudarsana Reddy Kalluru *o_mcp_resp = mb_params.mcp_resp; 66062e4d438SSudarsana Reddy Kalluru *o_mcp_param = mb_params.mcp_param; 66162e4d438SSudarsana Reddy Kalluru 6625e7ba042SDenis Bolotin /* nvm_info needs to be updated */ 6635e7ba042SDenis Bolotin p_hwfn->nvm_info.valid = false; 6645e7ba042SDenis Bolotin 66562e4d438SSudarsana Reddy Kalluru return 0; 66662e4d438SSudarsana Reddy Kalluru } 66762e4d438SSudarsana Reddy Kalluru 6684102426fSTomer Tayar int qed_mcp_nvm_rd_cmd(struct qed_hwfn *p_hwfn, 6694102426fSTomer Tayar struct qed_ptt *p_ptt, 6704102426fSTomer Tayar u32 cmd, 6714102426fSTomer Tayar u32 param, 6724102426fSTomer Tayar u32 *o_mcp_resp, 6734102426fSTomer Tayar u32 *o_mcp_param, u32 *o_txn_size, u32 *o_buf) 6744102426fSTomer Tayar { 6754102426fSTomer Tayar struct qed_mcp_mb_params mb_params; 6762f67af8cSTomer Tayar u8 raw_data[MCP_DRV_NVM_BUF_LEN]; 6774102426fSTomer Tayar int rc; 6784102426fSTomer Tayar 6794102426fSTomer Tayar memset(&mb_params, 0, sizeof(mb_params)); 6804102426fSTomer Tayar mb_params.cmd = cmd; 6814102426fSTomer Tayar mb_params.param = param; 6822f67af8cSTomer Tayar mb_params.p_data_dst = raw_data; 6832f67af8cSTomer Tayar 6842f67af8cSTomer Tayar /* Use the maximal value since the actual one is part of the response */ 6852f67af8cSTomer Tayar mb_params.data_dst_size = MCP_DRV_NVM_BUF_LEN; 6862f67af8cSTomer Tayar 6874102426fSTomer Tayar rc = qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 6884102426fSTomer Tayar if (rc) 6894102426fSTomer Tayar return rc; 6904102426fSTomer Tayar 6914102426fSTomer Tayar *o_mcp_resp = mb_params.mcp_resp; 6924102426fSTomer Tayar *o_mcp_param = mb_params.mcp_param; 6934102426fSTomer Tayar 6944102426fSTomer Tayar *o_txn_size = *o_mcp_param; 6952f67af8cSTomer Tayar memcpy(o_buf, raw_data, *o_txn_size); 6964102426fSTomer Tayar 6974102426fSTomer Tayar return 0; 6984102426fSTomer Tayar } 6994102426fSTomer Tayar 7005d24bcf1STomer Tayar static bool 7015d24bcf1STomer Tayar qed_mcp_can_force_load(u8 drv_role, 7025d24bcf1STomer Tayar u8 exist_drv_role, 7035d24bcf1STomer Tayar enum qed_override_force_load override_force_load) 704fe56b9e6SYuval Mintz { 7055d24bcf1STomer Tayar bool can_force_load = false; 7065d24bcf1STomer Tayar 7075d24bcf1STomer Tayar switch (override_force_load) { 7085d24bcf1STomer Tayar case QED_OVERRIDE_FORCE_LOAD_ALWAYS: 7095d24bcf1STomer Tayar can_force_load = true; 7105d24bcf1STomer Tayar break; 7115d24bcf1STomer Tayar case QED_OVERRIDE_FORCE_LOAD_NEVER: 7125d24bcf1STomer Tayar can_force_load = false; 7135d24bcf1STomer Tayar break; 7145d24bcf1STomer Tayar default: 7155d24bcf1STomer Tayar can_force_load = (drv_role == DRV_ROLE_OS && 7165d24bcf1STomer Tayar exist_drv_role == DRV_ROLE_PREBOOT) || 7175d24bcf1STomer Tayar (drv_role == DRV_ROLE_KDUMP && 7185d24bcf1STomer Tayar exist_drv_role == DRV_ROLE_OS); 7195d24bcf1STomer Tayar break; 7205d24bcf1STomer Tayar } 7215d24bcf1STomer Tayar 7225d24bcf1STomer Tayar return can_force_load; 7235d24bcf1STomer Tayar } 7245d24bcf1STomer Tayar 7255d24bcf1STomer Tayar static int qed_mcp_cancel_load_req(struct qed_hwfn *p_hwfn, 7265d24bcf1STomer Tayar struct qed_ptt *p_ptt) 7275d24bcf1STomer Tayar { 7285d24bcf1STomer Tayar u32 resp = 0, param = 0; 729fe56b9e6SYuval Mintz int rc; 730fe56b9e6SYuval Mintz 7315d24bcf1STomer Tayar rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_CANCEL_LOAD_REQ, 0, 7325d24bcf1STomer Tayar &resp, ¶m); 7335d24bcf1STomer Tayar if (rc) 7345d24bcf1STomer Tayar DP_NOTICE(p_hwfn, 7355d24bcf1STomer Tayar "Failed to send cancel load request, rc = %d\n", rc); 736fe56b9e6SYuval Mintz 737fe56b9e6SYuval Mintz return rc; 738fe56b9e6SYuval Mintz } 739fe56b9e6SYuval Mintz 7405d24bcf1STomer Tayar #define CONFIG_QEDE_BITMAP_IDX BIT(0) 7415d24bcf1STomer Tayar #define CONFIG_QED_SRIOV_BITMAP_IDX BIT(1) 7425d24bcf1STomer Tayar #define CONFIG_QEDR_BITMAP_IDX BIT(2) 7435d24bcf1STomer Tayar #define CONFIG_QEDF_BITMAP_IDX BIT(4) 7445d24bcf1STomer Tayar #define CONFIG_QEDI_BITMAP_IDX BIT(5) 7455d24bcf1STomer Tayar #define CONFIG_QED_LL2_BITMAP_IDX BIT(6) 7465529bad9STomer Tayar 7475d24bcf1STomer Tayar static u32 qed_get_config_bitmap(void) 7485d24bcf1STomer Tayar { 7495d24bcf1STomer Tayar u32 config_bitmap = 0x0; 7505d24bcf1STomer Tayar 7515d24bcf1STomer Tayar if (IS_ENABLED(CONFIG_QEDE)) 7525d24bcf1STomer Tayar config_bitmap |= CONFIG_QEDE_BITMAP_IDX; 7535d24bcf1STomer Tayar 7545d24bcf1STomer Tayar if (IS_ENABLED(CONFIG_QED_SRIOV)) 7555d24bcf1STomer Tayar config_bitmap |= CONFIG_QED_SRIOV_BITMAP_IDX; 7565d24bcf1STomer Tayar 7575d24bcf1STomer Tayar if (IS_ENABLED(CONFIG_QED_RDMA)) 7585d24bcf1STomer Tayar config_bitmap |= CONFIG_QEDR_BITMAP_IDX; 7595d24bcf1STomer Tayar 7605d24bcf1STomer Tayar if (IS_ENABLED(CONFIG_QED_FCOE)) 7615d24bcf1STomer Tayar config_bitmap |= CONFIG_QEDF_BITMAP_IDX; 7625d24bcf1STomer Tayar 7635d24bcf1STomer Tayar if (IS_ENABLED(CONFIG_QED_ISCSI)) 7645d24bcf1STomer Tayar config_bitmap |= CONFIG_QEDI_BITMAP_IDX; 7655d24bcf1STomer Tayar 7665d24bcf1STomer Tayar if (IS_ENABLED(CONFIG_QED_LL2)) 7675d24bcf1STomer Tayar config_bitmap |= CONFIG_QED_LL2_BITMAP_IDX; 7685d24bcf1STomer Tayar 7695d24bcf1STomer Tayar return config_bitmap; 7705d24bcf1STomer Tayar } 7715d24bcf1STomer Tayar 7725d24bcf1STomer Tayar struct qed_load_req_in_params { 7735d24bcf1STomer Tayar u8 hsi_ver; 7745d24bcf1STomer Tayar #define QED_LOAD_REQ_HSI_VER_DEFAULT 0 7755d24bcf1STomer Tayar #define QED_LOAD_REQ_HSI_VER_1 1 7765d24bcf1STomer Tayar u32 drv_ver_0; 7775d24bcf1STomer Tayar u32 drv_ver_1; 7785d24bcf1STomer Tayar u32 fw_ver; 7795d24bcf1STomer Tayar u8 drv_role; 7805d24bcf1STomer Tayar u8 timeout_val; 7815d24bcf1STomer Tayar u8 force_cmd; 7825d24bcf1STomer Tayar bool avoid_eng_reset; 7835d24bcf1STomer Tayar }; 7845d24bcf1STomer Tayar 7855d24bcf1STomer Tayar struct qed_load_req_out_params { 7865d24bcf1STomer Tayar u32 load_code; 7875d24bcf1STomer Tayar u32 exist_drv_ver_0; 7885d24bcf1STomer Tayar u32 exist_drv_ver_1; 7895d24bcf1STomer Tayar u32 exist_fw_ver; 7905d24bcf1STomer Tayar u8 exist_drv_role; 7915d24bcf1STomer Tayar u8 mfw_hsi_ver; 7925d24bcf1STomer Tayar bool drv_exists; 7935d24bcf1STomer Tayar }; 7945d24bcf1STomer Tayar 7955d24bcf1STomer Tayar static int 7965d24bcf1STomer Tayar __qed_mcp_load_req(struct qed_hwfn *p_hwfn, 7975d24bcf1STomer Tayar struct qed_ptt *p_ptt, 7985d24bcf1STomer Tayar struct qed_load_req_in_params *p_in_params, 7995d24bcf1STomer Tayar struct qed_load_req_out_params *p_out_params) 8005d24bcf1STomer Tayar { 8015d24bcf1STomer Tayar struct qed_mcp_mb_params mb_params; 8025d24bcf1STomer Tayar struct load_req_stc load_req; 8035d24bcf1STomer Tayar struct load_rsp_stc load_rsp; 8045d24bcf1STomer Tayar u32 hsi_ver; 8055d24bcf1STomer Tayar int rc; 8065d24bcf1STomer Tayar 8075d24bcf1STomer Tayar memset(&load_req, 0, sizeof(load_req)); 8085d24bcf1STomer Tayar load_req.drv_ver_0 = p_in_params->drv_ver_0; 8095d24bcf1STomer Tayar load_req.drv_ver_1 = p_in_params->drv_ver_1; 8105d24bcf1STomer Tayar load_req.fw_ver = p_in_params->fw_ver; 8115d24bcf1STomer Tayar QED_MFW_SET_FIELD(load_req.misc0, LOAD_REQ_ROLE, p_in_params->drv_role); 8125d24bcf1STomer Tayar QED_MFW_SET_FIELD(load_req.misc0, LOAD_REQ_LOCK_TO, 8135d24bcf1STomer Tayar p_in_params->timeout_val); 8145d24bcf1STomer Tayar QED_MFW_SET_FIELD(load_req.misc0, LOAD_REQ_FORCE, 8155d24bcf1STomer Tayar p_in_params->force_cmd); 8165d24bcf1STomer Tayar QED_MFW_SET_FIELD(load_req.misc0, LOAD_REQ_FLAGS0, 8175d24bcf1STomer Tayar p_in_params->avoid_eng_reset); 8185d24bcf1STomer Tayar 8195d24bcf1STomer Tayar hsi_ver = (p_in_params->hsi_ver == QED_LOAD_REQ_HSI_VER_DEFAULT) ? 8205d24bcf1STomer Tayar DRV_ID_MCP_HSI_VER_CURRENT : 8215d24bcf1STomer Tayar (p_in_params->hsi_ver << DRV_ID_MCP_HSI_VER_SHIFT); 8225d24bcf1STomer Tayar 8235d24bcf1STomer Tayar memset(&mb_params, 0, sizeof(mb_params)); 8245d24bcf1STomer Tayar mb_params.cmd = DRV_MSG_CODE_LOAD_REQ; 8255d24bcf1STomer Tayar mb_params.param = PDA_COMP | hsi_ver | p_hwfn->cdev->drv_type; 8265d24bcf1STomer Tayar mb_params.p_data_src = &load_req; 8275d24bcf1STomer Tayar mb_params.data_src_size = sizeof(load_req); 8285d24bcf1STomer Tayar mb_params.p_data_dst = &load_rsp; 8295d24bcf1STomer Tayar mb_params.data_dst_size = sizeof(load_rsp); 830b310974eSTomer Tayar mb_params.flags = QED_MB_FLAG_CAN_SLEEP | QED_MB_FLAG_AVOID_BLOCK; 8315d24bcf1STomer Tayar 8325d24bcf1STomer Tayar DP_VERBOSE(p_hwfn, QED_MSG_SP, 8335d24bcf1STomer Tayar "Load Request: param 0x%08x [init_hw %d, drv_type %d, hsi_ver %d, pda 0x%04x]\n", 8345d24bcf1STomer Tayar mb_params.param, 8355d24bcf1STomer Tayar QED_MFW_GET_FIELD(mb_params.param, DRV_ID_DRV_INIT_HW), 8365d24bcf1STomer Tayar QED_MFW_GET_FIELD(mb_params.param, DRV_ID_DRV_TYPE), 8375d24bcf1STomer Tayar QED_MFW_GET_FIELD(mb_params.param, DRV_ID_MCP_HSI_VER), 8385d24bcf1STomer Tayar QED_MFW_GET_FIELD(mb_params.param, DRV_ID_PDA_COMP_VER)); 8395d24bcf1STomer Tayar 8405d24bcf1STomer Tayar if (p_in_params->hsi_ver != QED_LOAD_REQ_HSI_VER_1) { 8415d24bcf1STomer Tayar DP_VERBOSE(p_hwfn, QED_MSG_SP, 8425d24bcf1STomer 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", 8435d24bcf1STomer Tayar load_req.drv_ver_0, 8445d24bcf1STomer Tayar load_req.drv_ver_1, 8455d24bcf1STomer Tayar load_req.fw_ver, 8465d24bcf1STomer Tayar load_req.misc0, 8475d24bcf1STomer Tayar QED_MFW_GET_FIELD(load_req.misc0, LOAD_REQ_ROLE), 8485d24bcf1STomer Tayar QED_MFW_GET_FIELD(load_req.misc0, 8495d24bcf1STomer Tayar LOAD_REQ_LOCK_TO), 8505d24bcf1STomer Tayar QED_MFW_GET_FIELD(load_req.misc0, LOAD_REQ_FORCE), 8515d24bcf1STomer Tayar QED_MFW_GET_FIELD(load_req.misc0, LOAD_REQ_FLAGS0)); 8525d24bcf1STomer Tayar } 8535d24bcf1STomer Tayar 8545d24bcf1STomer Tayar rc = qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 8555d24bcf1STomer Tayar if (rc) { 8565d24bcf1STomer Tayar DP_NOTICE(p_hwfn, "Failed to send load request, rc = %d\n", rc); 8575d24bcf1STomer Tayar return rc; 8585d24bcf1STomer Tayar } 8595d24bcf1STomer Tayar 8605d24bcf1STomer Tayar DP_VERBOSE(p_hwfn, QED_MSG_SP, 8615d24bcf1STomer Tayar "Load Response: resp 0x%08x\n", mb_params.mcp_resp); 8625d24bcf1STomer Tayar p_out_params->load_code = mb_params.mcp_resp; 8635d24bcf1STomer Tayar 8645d24bcf1STomer Tayar if (p_in_params->hsi_ver != QED_LOAD_REQ_HSI_VER_1 && 8655d24bcf1STomer Tayar p_out_params->load_code != FW_MSG_CODE_DRV_LOAD_REFUSED_HSI_1) { 8665d24bcf1STomer Tayar DP_VERBOSE(p_hwfn, 8675d24bcf1STomer Tayar QED_MSG_SP, 8685d24bcf1STomer 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", 8695d24bcf1STomer Tayar load_rsp.drv_ver_0, 8705d24bcf1STomer Tayar load_rsp.drv_ver_1, 8715d24bcf1STomer Tayar load_rsp.fw_ver, 8725d24bcf1STomer Tayar load_rsp.misc0, 8735d24bcf1STomer Tayar QED_MFW_GET_FIELD(load_rsp.misc0, LOAD_RSP_ROLE), 8745d24bcf1STomer Tayar QED_MFW_GET_FIELD(load_rsp.misc0, LOAD_RSP_HSI), 8755d24bcf1STomer Tayar QED_MFW_GET_FIELD(load_rsp.misc0, LOAD_RSP_FLAGS0)); 8765d24bcf1STomer Tayar 8775d24bcf1STomer Tayar p_out_params->exist_drv_ver_0 = load_rsp.drv_ver_0; 8785d24bcf1STomer Tayar p_out_params->exist_drv_ver_1 = load_rsp.drv_ver_1; 8795d24bcf1STomer Tayar p_out_params->exist_fw_ver = load_rsp.fw_ver; 8805d24bcf1STomer Tayar p_out_params->exist_drv_role = 8815d24bcf1STomer Tayar QED_MFW_GET_FIELD(load_rsp.misc0, LOAD_RSP_ROLE); 8825d24bcf1STomer Tayar p_out_params->mfw_hsi_ver = 8835d24bcf1STomer Tayar QED_MFW_GET_FIELD(load_rsp.misc0, LOAD_RSP_HSI); 8845d24bcf1STomer Tayar p_out_params->drv_exists = 8855d24bcf1STomer Tayar QED_MFW_GET_FIELD(load_rsp.misc0, LOAD_RSP_FLAGS0) & 8865d24bcf1STomer Tayar LOAD_RSP_FLAGS0_DRV_EXISTS; 8875d24bcf1STomer Tayar } 8885d24bcf1STomer Tayar 8895d24bcf1STomer Tayar return 0; 8905d24bcf1STomer Tayar } 8915d24bcf1STomer Tayar 8925d24bcf1STomer Tayar static int eocre_get_mfw_drv_role(struct qed_hwfn *p_hwfn, 8935d24bcf1STomer Tayar enum qed_drv_role drv_role, 8945d24bcf1STomer Tayar u8 *p_mfw_drv_role) 8955d24bcf1STomer Tayar { 8965d24bcf1STomer Tayar switch (drv_role) { 8975d24bcf1STomer Tayar case QED_DRV_ROLE_OS: 8985d24bcf1STomer Tayar *p_mfw_drv_role = DRV_ROLE_OS; 8995d24bcf1STomer Tayar break; 9005d24bcf1STomer Tayar case QED_DRV_ROLE_KDUMP: 9015d24bcf1STomer Tayar *p_mfw_drv_role = DRV_ROLE_KDUMP; 9025d24bcf1STomer Tayar break; 9035d24bcf1STomer Tayar default: 9045d24bcf1STomer Tayar DP_ERR(p_hwfn, "Unexpected driver role %d\n", drv_role); 9055d24bcf1STomer Tayar return -EINVAL; 9065d24bcf1STomer Tayar } 9075d24bcf1STomer Tayar 9085d24bcf1STomer Tayar return 0; 9095d24bcf1STomer Tayar } 9105d24bcf1STomer Tayar 9115d24bcf1STomer Tayar enum qed_load_req_force { 9125d24bcf1STomer Tayar QED_LOAD_REQ_FORCE_NONE, 9135d24bcf1STomer Tayar QED_LOAD_REQ_FORCE_PF, 9145d24bcf1STomer Tayar QED_LOAD_REQ_FORCE_ALL, 9155d24bcf1STomer Tayar }; 9165d24bcf1STomer Tayar 9175d24bcf1STomer Tayar static void qed_get_mfw_force_cmd(struct qed_hwfn *p_hwfn, 9185d24bcf1STomer Tayar 9195d24bcf1STomer Tayar enum qed_load_req_force force_cmd, 9205d24bcf1STomer Tayar u8 *p_mfw_force_cmd) 9215d24bcf1STomer Tayar { 9225d24bcf1STomer Tayar switch (force_cmd) { 9235d24bcf1STomer Tayar case QED_LOAD_REQ_FORCE_NONE: 9245d24bcf1STomer Tayar *p_mfw_force_cmd = LOAD_REQ_FORCE_NONE; 9255d24bcf1STomer Tayar break; 9265d24bcf1STomer Tayar case QED_LOAD_REQ_FORCE_PF: 9275d24bcf1STomer Tayar *p_mfw_force_cmd = LOAD_REQ_FORCE_PF; 9285d24bcf1STomer Tayar break; 9295d24bcf1STomer Tayar case QED_LOAD_REQ_FORCE_ALL: 9305d24bcf1STomer Tayar *p_mfw_force_cmd = LOAD_REQ_FORCE_ALL; 9315d24bcf1STomer Tayar break; 9325d24bcf1STomer Tayar } 9335d24bcf1STomer Tayar } 9345d24bcf1STomer Tayar 9355d24bcf1STomer Tayar int qed_mcp_load_req(struct qed_hwfn *p_hwfn, 9365d24bcf1STomer Tayar struct qed_ptt *p_ptt, 9375d24bcf1STomer Tayar struct qed_load_req_params *p_params) 9385d24bcf1STomer Tayar { 9395d24bcf1STomer Tayar struct qed_load_req_out_params out_params; 9405d24bcf1STomer Tayar struct qed_load_req_in_params in_params; 9415d24bcf1STomer Tayar u8 mfw_drv_role, mfw_force_cmd; 9425d24bcf1STomer Tayar int rc; 9435d24bcf1STomer Tayar 9445d24bcf1STomer Tayar memset(&in_params, 0, sizeof(in_params)); 9455d24bcf1STomer Tayar in_params.hsi_ver = QED_LOAD_REQ_HSI_VER_DEFAULT; 9465d24bcf1STomer Tayar in_params.drv_ver_0 = QED_VERSION; 9475d24bcf1STomer Tayar in_params.drv_ver_1 = qed_get_config_bitmap(); 9485d24bcf1STomer Tayar in_params.fw_ver = STORM_FW_VERSION; 9495d24bcf1STomer Tayar rc = eocre_get_mfw_drv_role(p_hwfn, p_params->drv_role, &mfw_drv_role); 9505d24bcf1STomer Tayar if (rc) 9515d24bcf1STomer Tayar return rc; 9525d24bcf1STomer Tayar 9535d24bcf1STomer Tayar in_params.drv_role = mfw_drv_role; 9545d24bcf1STomer Tayar in_params.timeout_val = p_params->timeout_val; 9555d24bcf1STomer Tayar qed_get_mfw_force_cmd(p_hwfn, 9565d24bcf1STomer Tayar QED_LOAD_REQ_FORCE_NONE, &mfw_force_cmd); 9575d24bcf1STomer Tayar 9585d24bcf1STomer Tayar in_params.force_cmd = mfw_force_cmd; 9595d24bcf1STomer Tayar in_params.avoid_eng_reset = p_params->avoid_eng_reset; 9605d24bcf1STomer Tayar 9615d24bcf1STomer Tayar memset(&out_params, 0, sizeof(out_params)); 9625d24bcf1STomer Tayar rc = __qed_mcp_load_req(p_hwfn, p_ptt, &in_params, &out_params); 9635d24bcf1STomer Tayar if (rc) 9645d24bcf1STomer Tayar return rc; 9655d24bcf1STomer Tayar 9665d24bcf1STomer Tayar /* First handle cases where another load request should/might be sent: 9675d24bcf1STomer Tayar * - MFW expects the old interface [HSI version = 1] 9685d24bcf1STomer Tayar * - MFW responds that a force load request is required 969fe56b9e6SYuval Mintz */ 9705d24bcf1STomer Tayar if (out_params.load_code == FW_MSG_CODE_DRV_LOAD_REFUSED_HSI_1) { 9715d24bcf1STomer Tayar DP_INFO(p_hwfn, 9725d24bcf1STomer Tayar "MFW refused a load request due to HSI > 1. Resending with HSI = 1\n"); 9735d24bcf1STomer Tayar 9745d24bcf1STomer Tayar in_params.hsi_ver = QED_LOAD_REQ_HSI_VER_1; 9755d24bcf1STomer Tayar memset(&out_params, 0, sizeof(out_params)); 9765d24bcf1STomer Tayar rc = __qed_mcp_load_req(p_hwfn, p_ptt, &in_params, &out_params); 9775d24bcf1STomer Tayar if (rc) 9785d24bcf1STomer Tayar return rc; 9795d24bcf1STomer Tayar } else if (out_params.load_code == 9805d24bcf1STomer Tayar FW_MSG_CODE_DRV_LOAD_REFUSED_REQUIRES_FORCE) { 9815d24bcf1STomer Tayar if (qed_mcp_can_force_load(in_params.drv_role, 9825d24bcf1STomer Tayar out_params.exist_drv_role, 9835d24bcf1STomer Tayar p_params->override_force_load)) { 9845d24bcf1STomer Tayar DP_INFO(p_hwfn, 9855d24bcf1STomer 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", 9865d24bcf1STomer Tayar in_params.drv_role, in_params.fw_ver, 9875d24bcf1STomer Tayar in_params.drv_ver_0, in_params.drv_ver_1, 9885d24bcf1STomer Tayar out_params.exist_drv_role, 9895d24bcf1STomer Tayar out_params.exist_fw_ver, 9905d24bcf1STomer Tayar out_params.exist_drv_ver_0, 9915d24bcf1STomer Tayar out_params.exist_drv_ver_1); 9925d24bcf1STomer Tayar 9935d24bcf1STomer Tayar qed_get_mfw_force_cmd(p_hwfn, 9945d24bcf1STomer Tayar QED_LOAD_REQ_FORCE_ALL, 9955d24bcf1STomer Tayar &mfw_force_cmd); 9965d24bcf1STomer Tayar 9975d24bcf1STomer Tayar in_params.force_cmd = mfw_force_cmd; 9985d24bcf1STomer Tayar memset(&out_params, 0, sizeof(out_params)); 9995d24bcf1STomer Tayar rc = __qed_mcp_load_req(p_hwfn, p_ptt, &in_params, 10005d24bcf1STomer Tayar &out_params); 10015d24bcf1STomer Tayar if (rc) 10025d24bcf1STomer Tayar return rc; 10035d24bcf1STomer Tayar } else { 10045d24bcf1STomer Tayar DP_NOTICE(p_hwfn, 10055d24bcf1STomer 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", 10065d24bcf1STomer Tayar in_params.drv_role, in_params.fw_ver, 10075d24bcf1STomer Tayar in_params.drv_ver_0, in_params.drv_ver_1, 10085d24bcf1STomer Tayar out_params.exist_drv_role, 10095d24bcf1STomer Tayar out_params.exist_fw_ver, 10105d24bcf1STomer Tayar out_params.exist_drv_ver_0, 10115d24bcf1STomer Tayar out_params.exist_drv_ver_1); 10125d24bcf1STomer Tayar DP_NOTICE(p_hwfn, 10135d24bcf1STomer Tayar "Avoid sending a force load request to prevent disruption of active PFs\n"); 10145d24bcf1STomer Tayar 10155d24bcf1STomer Tayar qed_mcp_cancel_load_req(p_hwfn, p_ptt); 1016fe56b9e6SYuval Mintz return -EBUSY; 1017fe56b9e6SYuval Mintz } 10185d24bcf1STomer Tayar } 10195d24bcf1STomer Tayar 10205d24bcf1STomer Tayar /* Now handle the other types of responses. 10215d24bcf1STomer Tayar * The "REFUSED_HSI_1" and "REFUSED_REQUIRES_FORCE" responses are not 10225d24bcf1STomer Tayar * expected here after the additional revised load requests were sent. 10235d24bcf1STomer Tayar */ 10245d24bcf1STomer Tayar switch (out_params.load_code) { 10255d24bcf1STomer Tayar case FW_MSG_CODE_DRV_LOAD_ENGINE: 10265d24bcf1STomer Tayar case FW_MSG_CODE_DRV_LOAD_PORT: 10275d24bcf1STomer Tayar case FW_MSG_CODE_DRV_LOAD_FUNCTION: 10285d24bcf1STomer Tayar if (out_params.mfw_hsi_ver != QED_LOAD_REQ_HSI_VER_1 && 10295d24bcf1STomer Tayar out_params.drv_exists) { 10305d24bcf1STomer Tayar /* The role and fw/driver version match, but the PF is 10315d24bcf1STomer Tayar * already loaded and has not been unloaded gracefully. 10325d24bcf1STomer Tayar */ 10335d24bcf1STomer Tayar DP_NOTICE(p_hwfn, 10345d24bcf1STomer Tayar "PF is already loaded\n"); 10355d24bcf1STomer Tayar return -EINVAL; 10365d24bcf1STomer Tayar } 10375d24bcf1STomer Tayar break; 10385d24bcf1STomer Tayar default: 10395d24bcf1STomer Tayar DP_NOTICE(p_hwfn, 10405d24bcf1STomer Tayar "Unexpected refusal to load request [resp 0x%08x]. Aborting.\n", 10415d24bcf1STomer Tayar out_params.load_code); 10425d24bcf1STomer Tayar return -EBUSY; 10435d24bcf1STomer Tayar } 10445d24bcf1STomer Tayar 10455d24bcf1STomer Tayar p_params->load_code = out_params.load_code; 1046fe56b9e6SYuval Mintz 1047fe56b9e6SYuval Mintz return 0; 1048fe56b9e6SYuval Mintz } 1049fe56b9e6SYuval Mintz 1050666db486STomer Tayar int qed_mcp_load_done(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 1051666db486STomer Tayar { 1052666db486STomer Tayar u32 resp = 0, param = 0; 1053666db486STomer Tayar int rc; 1054666db486STomer Tayar 1055666db486STomer Tayar rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_LOAD_DONE, 0, &resp, 1056666db486STomer Tayar ¶m); 1057666db486STomer Tayar if (rc) { 1058666db486STomer Tayar DP_NOTICE(p_hwfn, 1059666db486STomer Tayar "Failed to send a LOAD_DONE command, rc = %d\n", rc); 1060666db486STomer Tayar return rc; 1061666db486STomer Tayar } 1062666db486STomer Tayar 1063666db486STomer Tayar /* Check if there is a DID mismatch between nvm-cfg/efuse */ 1064666db486STomer Tayar if (param & FW_MB_PARAM_LOAD_DONE_DID_EFUSE_ERROR) 1065666db486STomer Tayar DP_NOTICE(p_hwfn, 1066666db486STomer Tayar "warning: device configuration is not supported on this board type. The device may not function as expected.\n"); 1067666db486STomer Tayar 1068666db486STomer Tayar return 0; 1069666db486STomer Tayar } 1070666db486STomer Tayar 10711226337aSTomer Tayar int qed_mcp_unload_req(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 10721226337aSTomer Tayar { 1073eaa50fc5STomer Tayar struct qed_mcp_mb_params mb_params; 1074eaa50fc5STomer Tayar u32 wol_param; 10751226337aSTomer Tayar 10761226337aSTomer Tayar switch (p_hwfn->cdev->wol_config) { 10771226337aSTomer Tayar case QED_OV_WOL_DISABLED: 10781226337aSTomer Tayar wol_param = DRV_MB_PARAM_UNLOAD_WOL_DISABLED; 10791226337aSTomer Tayar break; 10801226337aSTomer Tayar case QED_OV_WOL_ENABLED: 10811226337aSTomer Tayar wol_param = DRV_MB_PARAM_UNLOAD_WOL_ENABLED; 10821226337aSTomer Tayar break; 10831226337aSTomer Tayar default: 10841226337aSTomer Tayar DP_NOTICE(p_hwfn, 10851226337aSTomer Tayar "Unknown WoL configuration %02x\n", 10861226337aSTomer Tayar p_hwfn->cdev->wol_config); 10871226337aSTomer Tayar /* Fallthrough */ 10881226337aSTomer Tayar case QED_OV_WOL_DEFAULT: 10891226337aSTomer Tayar wol_param = DRV_MB_PARAM_UNLOAD_WOL_MCP; 10901226337aSTomer Tayar } 10911226337aSTomer Tayar 1092eaa50fc5STomer Tayar memset(&mb_params, 0, sizeof(mb_params)); 1093eaa50fc5STomer Tayar mb_params.cmd = DRV_MSG_CODE_UNLOAD_REQ; 1094eaa50fc5STomer Tayar mb_params.param = wol_param; 1095b310974eSTomer Tayar mb_params.flags = QED_MB_FLAG_CAN_SLEEP | QED_MB_FLAG_AVOID_BLOCK; 1096eaa50fc5STomer Tayar 1097eaa50fc5STomer Tayar return qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 10981226337aSTomer Tayar } 10991226337aSTomer Tayar 11001226337aSTomer Tayar int qed_mcp_unload_done(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 11011226337aSTomer Tayar { 11021226337aSTomer Tayar struct qed_mcp_mb_params mb_params; 11031226337aSTomer Tayar struct mcp_mac wol_mac; 11041226337aSTomer Tayar 11051226337aSTomer Tayar memset(&mb_params, 0, sizeof(mb_params)); 11061226337aSTomer Tayar mb_params.cmd = DRV_MSG_CODE_UNLOAD_DONE; 11071226337aSTomer Tayar 11081226337aSTomer Tayar /* Set the primary MAC if WoL is enabled */ 11091226337aSTomer Tayar if (p_hwfn->cdev->wol_config == QED_OV_WOL_ENABLED) { 11101226337aSTomer Tayar u8 *p_mac = p_hwfn->cdev->wol_mac; 11111226337aSTomer Tayar 11121226337aSTomer Tayar memset(&wol_mac, 0, sizeof(wol_mac)); 11131226337aSTomer Tayar wol_mac.mac_upper = p_mac[0] << 8 | p_mac[1]; 11141226337aSTomer Tayar wol_mac.mac_lower = p_mac[2] << 24 | p_mac[3] << 16 | 11151226337aSTomer Tayar p_mac[4] << 8 | p_mac[5]; 11161226337aSTomer Tayar 11171226337aSTomer Tayar DP_VERBOSE(p_hwfn, 11181226337aSTomer Tayar (QED_MSG_SP | NETIF_MSG_IFDOWN), 11191226337aSTomer Tayar "Setting WoL MAC: %pM --> [%08x,%08x]\n", 11201226337aSTomer Tayar p_mac, wol_mac.mac_upper, wol_mac.mac_lower); 11211226337aSTomer Tayar 11221226337aSTomer Tayar mb_params.p_data_src = &wol_mac; 11231226337aSTomer Tayar mb_params.data_src_size = sizeof(wol_mac); 11241226337aSTomer Tayar } 11251226337aSTomer Tayar 11261226337aSTomer Tayar return qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 11271226337aSTomer Tayar } 11281226337aSTomer Tayar 11290b55e27dSYuval Mintz static void qed_mcp_handle_vf_flr(struct qed_hwfn *p_hwfn, 11300b55e27dSYuval Mintz struct qed_ptt *p_ptt) 11310b55e27dSYuval Mintz { 11320b55e27dSYuval Mintz u32 addr = SECTION_OFFSIZE_ADDR(p_hwfn->mcp_info->public_base, 11330b55e27dSYuval Mintz PUBLIC_PATH); 11340b55e27dSYuval Mintz u32 mfw_path_offsize = qed_rd(p_hwfn, p_ptt, addr); 11350b55e27dSYuval Mintz u32 path_addr = SECTION_ADDR(mfw_path_offsize, 11360b55e27dSYuval Mintz QED_PATH_ID(p_hwfn)); 11370b55e27dSYuval Mintz u32 disabled_vfs[VF_MAX_STATIC / 32]; 11380b55e27dSYuval Mintz int i; 11390b55e27dSYuval Mintz 11400b55e27dSYuval Mintz DP_VERBOSE(p_hwfn, 11410b55e27dSYuval Mintz QED_MSG_SP, 11420b55e27dSYuval Mintz "Reading Disabled VF information from [offset %08x], path_addr %08x\n", 11430b55e27dSYuval Mintz mfw_path_offsize, path_addr); 11440b55e27dSYuval Mintz 11450b55e27dSYuval Mintz for (i = 0; i < (VF_MAX_STATIC / 32); i++) { 11460b55e27dSYuval Mintz disabled_vfs[i] = qed_rd(p_hwfn, p_ptt, 11470b55e27dSYuval Mintz path_addr + 11480b55e27dSYuval Mintz offsetof(struct public_path, 11490b55e27dSYuval Mintz mcp_vf_disabled) + 11500b55e27dSYuval Mintz sizeof(u32) * i); 11510b55e27dSYuval Mintz DP_VERBOSE(p_hwfn, (QED_MSG_SP | QED_MSG_IOV), 11520b55e27dSYuval Mintz "FLR-ed VFs [%08x,...,%08x] - %08x\n", 11530b55e27dSYuval Mintz i * 32, (i + 1) * 32 - 1, disabled_vfs[i]); 11540b55e27dSYuval Mintz } 11550b55e27dSYuval Mintz 11560b55e27dSYuval Mintz if (qed_iov_mark_vf_flr(p_hwfn, disabled_vfs)) 11570b55e27dSYuval Mintz qed_schedule_iov(p_hwfn, QED_IOV_WQ_FLR_FLAG); 11580b55e27dSYuval Mintz } 11590b55e27dSYuval Mintz 11600b55e27dSYuval Mintz int qed_mcp_ack_vf_flr(struct qed_hwfn *p_hwfn, 11610b55e27dSYuval Mintz struct qed_ptt *p_ptt, u32 *vfs_to_ack) 11620b55e27dSYuval Mintz { 11630b55e27dSYuval Mintz u32 addr = SECTION_OFFSIZE_ADDR(p_hwfn->mcp_info->public_base, 11640b55e27dSYuval Mintz PUBLIC_FUNC); 11650b55e27dSYuval Mintz u32 mfw_func_offsize = qed_rd(p_hwfn, p_ptt, addr); 11660b55e27dSYuval Mintz u32 func_addr = SECTION_ADDR(mfw_func_offsize, 11670b55e27dSYuval Mintz MCP_PF_ID(p_hwfn)); 11680b55e27dSYuval Mintz struct qed_mcp_mb_params mb_params; 11690b55e27dSYuval Mintz int rc; 11700b55e27dSYuval Mintz int i; 11710b55e27dSYuval Mintz 11720b55e27dSYuval Mintz for (i = 0; i < (VF_MAX_STATIC / 32); i++) 11730b55e27dSYuval Mintz DP_VERBOSE(p_hwfn, (QED_MSG_SP | QED_MSG_IOV), 11740b55e27dSYuval Mintz "Acking VFs [%08x,...,%08x] - %08x\n", 11750b55e27dSYuval Mintz i * 32, (i + 1) * 32 - 1, vfs_to_ack[i]); 11760b55e27dSYuval Mintz 11770b55e27dSYuval Mintz memset(&mb_params, 0, sizeof(mb_params)); 11780b55e27dSYuval Mintz mb_params.cmd = DRV_MSG_CODE_VF_DISABLED_DONE; 11792f67af8cSTomer Tayar mb_params.p_data_src = vfs_to_ack; 11802f67af8cSTomer Tayar mb_params.data_src_size = VF_MAX_STATIC / 8; 11810b55e27dSYuval Mintz rc = qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 11820b55e27dSYuval Mintz if (rc) { 11830b55e27dSYuval Mintz DP_NOTICE(p_hwfn, "Failed to pass ACK for VF flr to MFW\n"); 11840b55e27dSYuval Mintz return -EBUSY; 11850b55e27dSYuval Mintz } 11860b55e27dSYuval Mintz 11870b55e27dSYuval Mintz /* Clear the ACK bits */ 11880b55e27dSYuval Mintz for (i = 0; i < (VF_MAX_STATIC / 32); i++) 11890b55e27dSYuval Mintz qed_wr(p_hwfn, p_ptt, 11900b55e27dSYuval Mintz func_addr + 11910b55e27dSYuval Mintz offsetof(struct public_func, drv_ack_vf_disabled) + 11920b55e27dSYuval Mintz i * sizeof(u32), 0); 11930b55e27dSYuval Mintz 11940b55e27dSYuval Mintz return rc; 11950b55e27dSYuval Mintz } 11960b55e27dSYuval Mintz 1197334c03b5SZvi Nachmani static void qed_mcp_handle_transceiver_change(struct qed_hwfn *p_hwfn, 1198334c03b5SZvi Nachmani struct qed_ptt *p_ptt) 1199334c03b5SZvi Nachmani { 1200334c03b5SZvi Nachmani u32 transceiver_state; 1201334c03b5SZvi Nachmani 1202334c03b5SZvi Nachmani transceiver_state = qed_rd(p_hwfn, p_ptt, 1203334c03b5SZvi Nachmani p_hwfn->mcp_info->port_addr + 1204334c03b5SZvi Nachmani offsetof(struct public_port, 1205334c03b5SZvi Nachmani transceiver_data)); 1206334c03b5SZvi Nachmani 1207334c03b5SZvi Nachmani DP_VERBOSE(p_hwfn, 1208334c03b5SZvi Nachmani (NETIF_MSG_HW | QED_MSG_SP), 1209334c03b5SZvi Nachmani "Received transceiver state update [0x%08x] from mfw [Addr 0x%x]\n", 1210334c03b5SZvi Nachmani transceiver_state, 1211334c03b5SZvi Nachmani (u32)(p_hwfn->mcp_info->port_addr + 12121a635e48SYuval Mintz offsetof(struct public_port, transceiver_data))); 1213334c03b5SZvi Nachmani 1214334c03b5SZvi Nachmani transceiver_state = GET_FIELD(transceiver_state, 1215351a4dedSYuval Mintz ETH_TRANSCEIVER_STATE); 1216334c03b5SZvi Nachmani 1217351a4dedSYuval Mintz if (transceiver_state == ETH_TRANSCEIVER_STATE_PRESENT) 1218334c03b5SZvi Nachmani DP_NOTICE(p_hwfn, "Transceiver is present.\n"); 1219334c03b5SZvi Nachmani else 1220334c03b5SZvi Nachmani DP_NOTICE(p_hwfn, "Transceiver is unplugged.\n"); 1221334c03b5SZvi Nachmani } 1222334c03b5SZvi Nachmani 1223645874e5SSudarsana Reddy Kalluru static void qed_mcp_read_eee_config(struct qed_hwfn *p_hwfn, 1224645874e5SSudarsana Reddy Kalluru struct qed_ptt *p_ptt, 1225645874e5SSudarsana Reddy Kalluru struct qed_mcp_link_state *p_link) 1226645874e5SSudarsana Reddy Kalluru { 1227645874e5SSudarsana Reddy Kalluru u32 eee_status, val; 1228645874e5SSudarsana Reddy Kalluru 1229645874e5SSudarsana Reddy Kalluru p_link->eee_adv_caps = 0; 1230645874e5SSudarsana Reddy Kalluru p_link->eee_lp_adv_caps = 0; 1231645874e5SSudarsana Reddy Kalluru eee_status = qed_rd(p_hwfn, 1232645874e5SSudarsana Reddy Kalluru p_ptt, 1233645874e5SSudarsana Reddy Kalluru p_hwfn->mcp_info->port_addr + 1234645874e5SSudarsana Reddy Kalluru offsetof(struct public_port, eee_status)); 1235645874e5SSudarsana Reddy Kalluru p_link->eee_active = !!(eee_status & EEE_ACTIVE_BIT); 1236645874e5SSudarsana Reddy Kalluru val = (eee_status & EEE_LD_ADV_STATUS_MASK) >> EEE_LD_ADV_STATUS_OFFSET; 1237645874e5SSudarsana Reddy Kalluru if (val & EEE_1G_ADV) 1238645874e5SSudarsana Reddy Kalluru p_link->eee_adv_caps |= QED_EEE_1G_ADV; 1239645874e5SSudarsana Reddy Kalluru if (val & EEE_10G_ADV) 1240645874e5SSudarsana Reddy Kalluru p_link->eee_adv_caps |= QED_EEE_10G_ADV; 1241645874e5SSudarsana Reddy Kalluru val = (eee_status & EEE_LP_ADV_STATUS_MASK) >> EEE_LP_ADV_STATUS_OFFSET; 1242645874e5SSudarsana Reddy Kalluru if (val & EEE_1G_ADV) 1243645874e5SSudarsana Reddy Kalluru p_link->eee_lp_adv_caps |= QED_EEE_1G_ADV; 1244645874e5SSudarsana Reddy Kalluru if (val & EEE_10G_ADV) 1245645874e5SSudarsana Reddy Kalluru p_link->eee_lp_adv_caps |= QED_EEE_10G_ADV; 1246645874e5SSudarsana Reddy Kalluru } 1247645874e5SSudarsana Reddy Kalluru 1248e40a826aSSudarsana Reddy Kalluru static u32 qed_mcp_get_shmem_func(struct qed_hwfn *p_hwfn, 1249e40a826aSSudarsana Reddy Kalluru struct qed_ptt *p_ptt, 1250e40a826aSSudarsana Reddy Kalluru struct public_func *p_data, int pfid) 1251e40a826aSSudarsana Reddy Kalluru { 1252e40a826aSSudarsana Reddy Kalluru u32 addr = SECTION_OFFSIZE_ADDR(p_hwfn->mcp_info->public_base, 1253e40a826aSSudarsana Reddy Kalluru PUBLIC_FUNC); 1254e40a826aSSudarsana Reddy Kalluru u32 mfw_path_offsize = qed_rd(p_hwfn, p_ptt, addr); 1255e40a826aSSudarsana Reddy Kalluru u32 func_addr; 1256e40a826aSSudarsana Reddy Kalluru u32 i, size; 1257e40a826aSSudarsana Reddy Kalluru 1258e40a826aSSudarsana Reddy Kalluru func_addr = SECTION_ADDR(mfw_path_offsize, pfid); 1259e40a826aSSudarsana Reddy Kalluru memset(p_data, 0, sizeof(*p_data)); 1260e40a826aSSudarsana Reddy Kalluru 1261e40a826aSSudarsana Reddy Kalluru size = min_t(u32, sizeof(*p_data), QED_SECTION_SIZE(mfw_path_offsize)); 1262e40a826aSSudarsana Reddy Kalluru for (i = 0; i < size / sizeof(u32); i++) 1263e40a826aSSudarsana Reddy Kalluru ((u32 *)p_data)[i] = qed_rd(p_hwfn, p_ptt, 1264e40a826aSSudarsana Reddy Kalluru func_addr + (i << 2)); 1265e40a826aSSudarsana Reddy Kalluru return size; 1266e40a826aSSudarsana Reddy Kalluru } 1267e40a826aSSudarsana Reddy Kalluru 1268e40a826aSSudarsana Reddy Kalluru static void qed_read_pf_bandwidth(struct qed_hwfn *p_hwfn, 1269e40a826aSSudarsana Reddy Kalluru struct public_func *p_shmem_info) 1270e40a826aSSudarsana Reddy Kalluru { 1271e40a826aSSudarsana Reddy Kalluru struct qed_mcp_function_info *p_info; 1272e40a826aSSudarsana Reddy Kalluru 1273e40a826aSSudarsana Reddy Kalluru p_info = &p_hwfn->mcp_info->func_info; 1274e40a826aSSudarsana Reddy Kalluru 1275e40a826aSSudarsana Reddy Kalluru p_info->bandwidth_min = QED_MFW_GET_FIELD(p_shmem_info->config, 1276e40a826aSSudarsana Reddy Kalluru FUNC_MF_CFG_MIN_BW); 1277e40a826aSSudarsana Reddy Kalluru if (p_info->bandwidth_min < 1 || p_info->bandwidth_min > 100) { 1278e40a826aSSudarsana Reddy Kalluru DP_INFO(p_hwfn, 1279e40a826aSSudarsana Reddy Kalluru "bandwidth minimum out of bounds [%02x]. Set to 1\n", 1280e40a826aSSudarsana Reddy Kalluru p_info->bandwidth_min); 1281e40a826aSSudarsana Reddy Kalluru p_info->bandwidth_min = 1; 1282e40a826aSSudarsana Reddy Kalluru } 1283e40a826aSSudarsana Reddy Kalluru 1284e40a826aSSudarsana Reddy Kalluru p_info->bandwidth_max = QED_MFW_GET_FIELD(p_shmem_info->config, 1285e40a826aSSudarsana Reddy Kalluru FUNC_MF_CFG_MAX_BW); 1286e40a826aSSudarsana Reddy Kalluru if (p_info->bandwidth_max < 1 || p_info->bandwidth_max > 100) { 1287e40a826aSSudarsana Reddy Kalluru DP_INFO(p_hwfn, 1288e40a826aSSudarsana Reddy Kalluru "bandwidth maximum out of bounds [%02x]. Set to 100\n", 1289e40a826aSSudarsana Reddy Kalluru p_info->bandwidth_max); 1290e40a826aSSudarsana Reddy Kalluru p_info->bandwidth_max = 100; 1291e40a826aSSudarsana Reddy Kalluru } 1292e40a826aSSudarsana Reddy Kalluru } 1293e40a826aSSudarsana Reddy Kalluru 1294cc875c2eSYuval Mintz static void qed_mcp_handle_link_change(struct qed_hwfn *p_hwfn, 12951a635e48SYuval Mintz struct qed_ptt *p_ptt, bool b_reset) 1296cc875c2eSYuval Mintz { 1297cc875c2eSYuval Mintz struct qed_mcp_link_state *p_link; 1298a64b02d5SManish Chopra u8 max_bw, min_bw; 1299cc875c2eSYuval Mintz u32 status = 0; 1300cc875c2eSYuval Mintz 130165ed2ffdSMintz, Yuval /* Prevent SW/attentions from doing this at the same time */ 130265ed2ffdSMintz, Yuval spin_lock_bh(&p_hwfn->mcp_info->link_lock); 130365ed2ffdSMintz, Yuval 1304cc875c2eSYuval Mintz p_link = &p_hwfn->mcp_info->link_output; 1305cc875c2eSYuval Mintz memset(p_link, 0, sizeof(*p_link)); 1306cc875c2eSYuval Mintz if (!b_reset) { 1307cc875c2eSYuval Mintz status = qed_rd(p_hwfn, p_ptt, 1308cc875c2eSYuval Mintz p_hwfn->mcp_info->port_addr + 1309cc875c2eSYuval Mintz offsetof(struct public_port, link_status)); 1310cc875c2eSYuval Mintz DP_VERBOSE(p_hwfn, (NETIF_MSG_LINK | QED_MSG_SP), 1311cc875c2eSYuval Mintz "Received link update [0x%08x] from mfw [Addr 0x%x]\n", 1312cc875c2eSYuval Mintz status, 1313cc875c2eSYuval Mintz (u32)(p_hwfn->mcp_info->port_addr + 13141a635e48SYuval Mintz offsetof(struct public_port, link_status))); 1315cc875c2eSYuval Mintz } else { 1316cc875c2eSYuval Mintz DP_VERBOSE(p_hwfn, NETIF_MSG_LINK, 1317cc875c2eSYuval Mintz "Resetting link indications\n"); 131865ed2ffdSMintz, Yuval goto out; 1319cc875c2eSYuval Mintz } 1320cc875c2eSYuval Mintz 1321e40a826aSSudarsana Reddy Kalluru if (p_hwfn->b_drv_link_init) { 1322e40a826aSSudarsana Reddy Kalluru /* Link indication with modern MFW arrives as per-PF 1323e40a826aSSudarsana Reddy Kalluru * indication. 1324e40a826aSSudarsana Reddy Kalluru */ 1325e40a826aSSudarsana Reddy Kalluru if (p_hwfn->mcp_info->capabilities & 1326e40a826aSSudarsana Reddy Kalluru FW_MB_PARAM_FEATURE_SUPPORT_VLINK) { 1327e40a826aSSudarsana Reddy Kalluru struct public_func shmem_info; 1328e40a826aSSudarsana Reddy Kalluru 1329e40a826aSSudarsana Reddy Kalluru qed_mcp_get_shmem_func(p_hwfn, p_ptt, &shmem_info, 1330e40a826aSSudarsana Reddy Kalluru MCP_PF_ID(p_hwfn)); 1331e40a826aSSudarsana Reddy Kalluru p_link->link_up = !!(shmem_info.status & 1332e40a826aSSudarsana Reddy Kalluru FUNC_STATUS_VIRTUAL_LINK_UP); 1333e40a826aSSudarsana Reddy Kalluru qed_read_pf_bandwidth(p_hwfn, &shmem_info); 1334e40a826aSSudarsana Reddy Kalluru DP_VERBOSE(p_hwfn, NETIF_MSG_LINK, 1335e40a826aSSudarsana Reddy Kalluru "Virtual link_up = %d\n", p_link->link_up); 1336e40a826aSSudarsana Reddy Kalluru } else { 1337cc875c2eSYuval Mintz p_link->link_up = !!(status & LINK_STATUS_LINK_UP); 1338e40a826aSSudarsana Reddy Kalluru DP_VERBOSE(p_hwfn, NETIF_MSG_LINK, 1339e40a826aSSudarsana Reddy Kalluru "Physical link_up = %d\n", p_link->link_up); 1340e40a826aSSudarsana Reddy Kalluru } 1341e40a826aSSudarsana Reddy Kalluru } else { 1342fc916ff2SSudarsana Reddy Kalluru p_link->link_up = false; 1343e40a826aSSudarsana Reddy Kalluru } 1344cc875c2eSYuval Mintz 1345cc875c2eSYuval Mintz p_link->full_duplex = true; 1346cc875c2eSYuval Mintz switch ((status & LINK_STATUS_SPEED_AND_DUPLEX_MASK)) { 1347cc875c2eSYuval Mintz case LINK_STATUS_SPEED_AND_DUPLEX_100G: 1348cc875c2eSYuval Mintz p_link->speed = 100000; 1349cc875c2eSYuval Mintz break; 1350cc875c2eSYuval Mintz case LINK_STATUS_SPEED_AND_DUPLEX_50G: 1351cc875c2eSYuval Mintz p_link->speed = 50000; 1352cc875c2eSYuval Mintz break; 1353cc875c2eSYuval Mintz case LINK_STATUS_SPEED_AND_DUPLEX_40G: 1354cc875c2eSYuval Mintz p_link->speed = 40000; 1355cc875c2eSYuval Mintz break; 1356cc875c2eSYuval Mintz case LINK_STATUS_SPEED_AND_DUPLEX_25G: 1357cc875c2eSYuval Mintz p_link->speed = 25000; 1358cc875c2eSYuval Mintz break; 1359cc875c2eSYuval Mintz case LINK_STATUS_SPEED_AND_DUPLEX_20G: 1360cc875c2eSYuval Mintz p_link->speed = 20000; 1361cc875c2eSYuval Mintz break; 1362cc875c2eSYuval Mintz case LINK_STATUS_SPEED_AND_DUPLEX_10G: 1363cc875c2eSYuval Mintz p_link->speed = 10000; 1364cc875c2eSYuval Mintz break; 1365cc875c2eSYuval Mintz case LINK_STATUS_SPEED_AND_DUPLEX_1000THD: 1366cc875c2eSYuval Mintz p_link->full_duplex = false; 1367cc875c2eSYuval Mintz /* Fall-through */ 1368cc875c2eSYuval Mintz case LINK_STATUS_SPEED_AND_DUPLEX_1000TFD: 1369cc875c2eSYuval Mintz p_link->speed = 1000; 1370cc875c2eSYuval Mintz break; 1371cc875c2eSYuval Mintz default: 1372cc875c2eSYuval Mintz p_link->speed = 0; 137358874c7bSSudarsana Reddy Kalluru p_link->link_up = 0; 1374cc875c2eSYuval Mintz } 1375cc875c2eSYuval Mintz 13764b01e519SManish Chopra if (p_link->link_up && p_link->speed) 13774b01e519SManish Chopra p_link->line_speed = p_link->speed; 13784b01e519SManish Chopra else 13794b01e519SManish Chopra p_link->line_speed = 0; 13804b01e519SManish Chopra 13814b01e519SManish Chopra max_bw = p_hwfn->mcp_info->func_info.bandwidth_max; 1382a64b02d5SManish Chopra min_bw = p_hwfn->mcp_info->func_info.bandwidth_min; 13834b01e519SManish Chopra 1384a64b02d5SManish Chopra /* Max bandwidth configuration */ 13854b01e519SManish Chopra __qed_configure_pf_max_bandwidth(p_hwfn, p_ptt, p_link, max_bw); 1386cc875c2eSYuval Mintz 1387a64b02d5SManish Chopra /* Min bandwidth configuration */ 1388a64b02d5SManish Chopra __qed_configure_pf_min_bandwidth(p_hwfn, p_ptt, p_link, min_bw); 13896f437d43SMintz, Yuval qed_configure_vp_wfq_on_link_change(p_hwfn->cdev, p_ptt, 13906f437d43SMintz, Yuval p_link->min_pf_rate); 1391a64b02d5SManish Chopra 1392cc875c2eSYuval Mintz p_link->an = !!(status & LINK_STATUS_AUTO_NEGOTIATE_ENABLED); 1393cc875c2eSYuval Mintz p_link->an_complete = !!(status & 1394cc875c2eSYuval Mintz LINK_STATUS_AUTO_NEGOTIATE_COMPLETE); 1395cc875c2eSYuval Mintz p_link->parallel_detection = !!(status & 1396cc875c2eSYuval Mintz LINK_STATUS_PARALLEL_DETECTION_USED); 1397cc875c2eSYuval Mintz p_link->pfc_enabled = !!(status & LINK_STATUS_PFC_ENABLED); 1398cc875c2eSYuval Mintz 1399cc875c2eSYuval Mintz p_link->partner_adv_speed |= 1400cc875c2eSYuval Mintz (status & LINK_STATUS_LINK_PARTNER_1000TFD_CAPABLE) ? 1401cc875c2eSYuval Mintz QED_LINK_PARTNER_SPEED_1G_FD : 0; 1402cc875c2eSYuval Mintz p_link->partner_adv_speed |= 1403cc875c2eSYuval Mintz (status & LINK_STATUS_LINK_PARTNER_1000THD_CAPABLE) ? 1404cc875c2eSYuval Mintz QED_LINK_PARTNER_SPEED_1G_HD : 0; 1405cc875c2eSYuval Mintz p_link->partner_adv_speed |= 1406cc875c2eSYuval Mintz (status & LINK_STATUS_LINK_PARTNER_10G_CAPABLE) ? 1407cc875c2eSYuval Mintz QED_LINK_PARTNER_SPEED_10G : 0; 1408cc875c2eSYuval Mintz p_link->partner_adv_speed |= 1409cc875c2eSYuval Mintz (status & LINK_STATUS_LINK_PARTNER_20G_CAPABLE) ? 1410cc875c2eSYuval Mintz QED_LINK_PARTNER_SPEED_20G : 0; 1411cc875c2eSYuval Mintz p_link->partner_adv_speed |= 1412054c67d1SSudarsana Reddy Kalluru (status & LINK_STATUS_LINK_PARTNER_25G_CAPABLE) ? 1413054c67d1SSudarsana Reddy Kalluru QED_LINK_PARTNER_SPEED_25G : 0; 1414054c67d1SSudarsana Reddy Kalluru p_link->partner_adv_speed |= 1415cc875c2eSYuval Mintz (status & LINK_STATUS_LINK_PARTNER_40G_CAPABLE) ? 1416cc875c2eSYuval Mintz QED_LINK_PARTNER_SPEED_40G : 0; 1417cc875c2eSYuval Mintz p_link->partner_adv_speed |= 1418cc875c2eSYuval Mintz (status & LINK_STATUS_LINK_PARTNER_50G_CAPABLE) ? 1419cc875c2eSYuval Mintz QED_LINK_PARTNER_SPEED_50G : 0; 1420cc875c2eSYuval Mintz p_link->partner_adv_speed |= 1421cc875c2eSYuval Mintz (status & LINK_STATUS_LINK_PARTNER_100G_CAPABLE) ? 1422cc875c2eSYuval Mintz QED_LINK_PARTNER_SPEED_100G : 0; 1423cc875c2eSYuval Mintz 1424cc875c2eSYuval Mintz p_link->partner_tx_flow_ctrl_en = 1425cc875c2eSYuval Mintz !!(status & LINK_STATUS_TX_FLOW_CONTROL_ENABLED); 1426cc875c2eSYuval Mintz p_link->partner_rx_flow_ctrl_en = 1427cc875c2eSYuval Mintz !!(status & LINK_STATUS_RX_FLOW_CONTROL_ENABLED); 1428cc875c2eSYuval Mintz 1429cc875c2eSYuval Mintz switch (status & LINK_STATUS_LINK_PARTNER_FLOW_CONTROL_MASK) { 1430cc875c2eSYuval Mintz case LINK_STATUS_LINK_PARTNER_SYMMETRIC_PAUSE: 1431cc875c2eSYuval Mintz p_link->partner_adv_pause = QED_LINK_PARTNER_SYMMETRIC_PAUSE; 1432cc875c2eSYuval Mintz break; 1433cc875c2eSYuval Mintz case LINK_STATUS_LINK_PARTNER_ASYMMETRIC_PAUSE: 1434cc875c2eSYuval Mintz p_link->partner_adv_pause = QED_LINK_PARTNER_ASYMMETRIC_PAUSE; 1435cc875c2eSYuval Mintz break; 1436cc875c2eSYuval Mintz case LINK_STATUS_LINK_PARTNER_BOTH_PAUSE: 1437cc875c2eSYuval Mintz p_link->partner_adv_pause = QED_LINK_PARTNER_BOTH_PAUSE; 1438cc875c2eSYuval Mintz break; 1439cc875c2eSYuval Mintz default: 1440cc875c2eSYuval Mintz p_link->partner_adv_pause = 0; 1441cc875c2eSYuval Mintz } 1442cc875c2eSYuval Mintz 1443cc875c2eSYuval Mintz p_link->sfp_tx_fault = !!(status & LINK_STATUS_SFP_TX_FAULT); 1444cc875c2eSYuval Mintz 1445645874e5SSudarsana Reddy Kalluru if (p_hwfn->mcp_info->capabilities & FW_MB_PARAM_FEATURE_SUPPORT_EEE) 1446645874e5SSudarsana Reddy Kalluru qed_mcp_read_eee_config(p_hwfn, p_ptt, p_link); 1447645874e5SSudarsana Reddy Kalluru 1448706d0891SRahul Verma qed_link_update(p_hwfn, p_ptt); 144965ed2ffdSMintz, Yuval out: 145065ed2ffdSMintz, Yuval spin_unlock_bh(&p_hwfn->mcp_info->link_lock); 1451cc875c2eSYuval Mintz } 1452cc875c2eSYuval Mintz 1453351a4dedSYuval Mintz int qed_mcp_set_link(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, bool b_up) 1454cc875c2eSYuval Mintz { 1455cc875c2eSYuval Mintz struct qed_mcp_link_params *params = &p_hwfn->mcp_info->link_input; 14565529bad9STomer Tayar struct qed_mcp_mb_params mb_params; 14572f67af8cSTomer Tayar struct eth_phy_cfg phy_cfg; 1458cc875c2eSYuval Mintz int rc = 0; 14595529bad9STomer Tayar u32 cmd; 1460cc875c2eSYuval Mintz 1461cc875c2eSYuval Mintz /* Set the shmem configuration according to params */ 14622f67af8cSTomer Tayar memset(&phy_cfg, 0, sizeof(phy_cfg)); 1463cc875c2eSYuval Mintz cmd = b_up ? DRV_MSG_CODE_INIT_PHY : DRV_MSG_CODE_LINK_RESET; 1464cc875c2eSYuval Mintz if (!params->speed.autoneg) 14652f67af8cSTomer Tayar phy_cfg.speed = params->speed.forced_speed; 14662f67af8cSTomer Tayar phy_cfg.pause |= (params->pause.autoneg) ? ETH_PAUSE_AUTONEG : 0; 14672f67af8cSTomer Tayar phy_cfg.pause |= (params->pause.forced_rx) ? ETH_PAUSE_RX : 0; 14682f67af8cSTomer Tayar phy_cfg.pause |= (params->pause.forced_tx) ? ETH_PAUSE_TX : 0; 14692f67af8cSTomer Tayar phy_cfg.adv_speed = params->speed.advertised_speeds; 14702f67af8cSTomer Tayar phy_cfg.loopback_mode = params->loopback_mode; 14714ad95a93SSudarsana Reddy Kalluru 14724ad95a93SSudarsana Reddy Kalluru /* There are MFWs that share this capability regardless of whether 14734ad95a93SSudarsana Reddy Kalluru * this is feasible or not. And given that at the very least adv_caps 14744ad95a93SSudarsana Reddy Kalluru * would be set internally by qed, we want to make sure LFA would 14754ad95a93SSudarsana Reddy Kalluru * still work. 14764ad95a93SSudarsana Reddy Kalluru */ 14774ad95a93SSudarsana Reddy Kalluru if ((p_hwfn->mcp_info->capabilities & 14784ad95a93SSudarsana Reddy Kalluru FW_MB_PARAM_FEATURE_SUPPORT_EEE) && params->eee.enable) { 1479645874e5SSudarsana Reddy Kalluru phy_cfg.eee_cfg |= EEE_CFG_EEE_ENABLED; 1480645874e5SSudarsana Reddy Kalluru if (params->eee.tx_lpi_enable) 1481645874e5SSudarsana Reddy Kalluru phy_cfg.eee_cfg |= EEE_CFG_TX_LPI; 1482645874e5SSudarsana Reddy Kalluru if (params->eee.adv_caps & QED_EEE_1G_ADV) 1483645874e5SSudarsana Reddy Kalluru phy_cfg.eee_cfg |= EEE_CFG_ADV_SPEED_1G; 1484645874e5SSudarsana Reddy Kalluru if (params->eee.adv_caps & QED_EEE_10G_ADV) 1485645874e5SSudarsana Reddy Kalluru phy_cfg.eee_cfg |= EEE_CFG_ADV_SPEED_10G; 1486645874e5SSudarsana Reddy Kalluru phy_cfg.eee_cfg |= (params->eee.tx_lpi_timer << 1487645874e5SSudarsana Reddy Kalluru EEE_TX_TIMER_USEC_OFFSET) & 1488645874e5SSudarsana Reddy Kalluru EEE_TX_TIMER_USEC_MASK; 1489645874e5SSudarsana Reddy Kalluru } 1490cc875c2eSYuval Mintz 1491fc916ff2SSudarsana Reddy Kalluru p_hwfn->b_drv_link_init = b_up; 1492fc916ff2SSudarsana Reddy Kalluru 1493cc875c2eSYuval Mintz if (b_up) { 1494cc875c2eSYuval Mintz DP_VERBOSE(p_hwfn, NETIF_MSG_LINK, 1495cc875c2eSYuval Mintz "Configuring Link: Speed 0x%08x, Pause 0x%08x, adv_speed 0x%08x, loopback 0x%08x, features 0x%08x\n", 14962f67af8cSTomer Tayar phy_cfg.speed, 14972f67af8cSTomer Tayar phy_cfg.pause, 14982f67af8cSTomer Tayar phy_cfg.adv_speed, 14992f67af8cSTomer Tayar phy_cfg.loopback_mode, 15002f67af8cSTomer Tayar phy_cfg.feature_config_flags); 1501cc875c2eSYuval Mintz } else { 1502cc875c2eSYuval Mintz DP_VERBOSE(p_hwfn, NETIF_MSG_LINK, 1503cc875c2eSYuval Mintz "Resetting link\n"); 1504cc875c2eSYuval Mintz } 1505cc875c2eSYuval Mintz 15065529bad9STomer Tayar memset(&mb_params, 0, sizeof(mb_params)); 15075529bad9STomer Tayar mb_params.cmd = cmd; 15082f67af8cSTomer Tayar mb_params.p_data_src = &phy_cfg; 15092f67af8cSTomer Tayar mb_params.data_src_size = sizeof(phy_cfg); 15105529bad9STomer Tayar rc = qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 1511cc875c2eSYuval Mintz 1512cc875c2eSYuval Mintz /* if mcp fails to respond we must abort */ 1513cc875c2eSYuval Mintz if (rc) { 1514cc875c2eSYuval Mintz DP_ERR(p_hwfn, "MCP response failure, aborting\n"); 1515cc875c2eSYuval Mintz return rc; 1516cc875c2eSYuval Mintz } 1517cc875c2eSYuval Mintz 151865ed2ffdSMintz, Yuval /* Mimic link-change attention, done for several reasons: 151965ed2ffdSMintz, Yuval * - On reset, there's no guarantee MFW would trigger 152065ed2ffdSMintz, Yuval * an attention. 152165ed2ffdSMintz, Yuval * - On initialization, older MFWs might not indicate link change 152265ed2ffdSMintz, Yuval * during LFA, so we'll never get an UP indication. 152365ed2ffdSMintz, Yuval */ 152465ed2ffdSMintz, Yuval qed_mcp_handle_link_change(p_hwfn, p_ptt, !b_up); 1525cc875c2eSYuval Mintz 1526cc875c2eSYuval Mintz return 0; 1527cc875c2eSYuval Mintz } 1528cc875c2eSYuval Mintz 152964515dc8STomer Tayar u32 qed_get_process_kill_counter(struct qed_hwfn *p_hwfn, 153064515dc8STomer Tayar struct qed_ptt *p_ptt) 153164515dc8STomer Tayar { 153264515dc8STomer Tayar u32 path_offsize_addr, path_offsize, path_addr, proc_kill_cnt; 153364515dc8STomer Tayar 153464515dc8STomer Tayar if (IS_VF(p_hwfn->cdev)) 153564515dc8STomer Tayar return -EINVAL; 153664515dc8STomer Tayar 153764515dc8STomer Tayar path_offsize_addr = SECTION_OFFSIZE_ADDR(p_hwfn->mcp_info->public_base, 153864515dc8STomer Tayar PUBLIC_PATH); 153964515dc8STomer Tayar path_offsize = qed_rd(p_hwfn, p_ptt, path_offsize_addr); 154064515dc8STomer Tayar path_addr = SECTION_ADDR(path_offsize, QED_PATH_ID(p_hwfn)); 154164515dc8STomer Tayar 154264515dc8STomer Tayar proc_kill_cnt = qed_rd(p_hwfn, p_ptt, 154364515dc8STomer Tayar path_addr + 154464515dc8STomer Tayar offsetof(struct public_path, process_kill)) & 154564515dc8STomer Tayar PROCESS_KILL_COUNTER_MASK; 154664515dc8STomer Tayar 154764515dc8STomer Tayar return proc_kill_cnt; 154864515dc8STomer Tayar } 154964515dc8STomer Tayar 155064515dc8STomer Tayar static void qed_mcp_handle_process_kill(struct qed_hwfn *p_hwfn, 155164515dc8STomer Tayar struct qed_ptt *p_ptt) 155264515dc8STomer Tayar { 155364515dc8STomer Tayar struct qed_dev *cdev = p_hwfn->cdev; 155464515dc8STomer Tayar u32 proc_kill_cnt; 155564515dc8STomer Tayar 155664515dc8STomer Tayar /* Prevent possible attentions/interrupts during the recovery handling 155764515dc8STomer Tayar * and till its load phase, during which they will be re-enabled. 155864515dc8STomer Tayar */ 155964515dc8STomer Tayar qed_int_igu_disable_int(p_hwfn, p_ptt); 156064515dc8STomer Tayar 156164515dc8STomer Tayar DP_NOTICE(p_hwfn, "Received a process kill indication\n"); 156264515dc8STomer Tayar 156364515dc8STomer Tayar /* The following operations should be done once, and thus in CMT mode 156464515dc8STomer Tayar * are carried out by only the first HW function. 156564515dc8STomer Tayar */ 156664515dc8STomer Tayar if (p_hwfn != QED_LEADING_HWFN(cdev)) 156764515dc8STomer Tayar return; 156864515dc8STomer Tayar 156964515dc8STomer Tayar if (cdev->recov_in_prog) { 157064515dc8STomer Tayar DP_NOTICE(p_hwfn, 157164515dc8STomer Tayar "Ignoring the indication since a recovery process is already in progress\n"); 157264515dc8STomer Tayar return; 157364515dc8STomer Tayar } 157464515dc8STomer Tayar 157564515dc8STomer Tayar cdev->recov_in_prog = true; 157664515dc8STomer Tayar 157764515dc8STomer Tayar proc_kill_cnt = qed_get_process_kill_counter(p_hwfn, p_ptt); 157864515dc8STomer Tayar DP_NOTICE(p_hwfn, "Process kill counter: %d\n", proc_kill_cnt); 157964515dc8STomer Tayar 158064515dc8STomer Tayar qed_schedule_recovery_handler(p_hwfn); 158164515dc8STomer Tayar } 158264515dc8STomer Tayar 15836c754246SSudarsana Reddy Kalluru static void qed_mcp_send_protocol_stats(struct qed_hwfn *p_hwfn, 15846c754246SSudarsana Reddy Kalluru struct qed_ptt *p_ptt, 15856c754246SSudarsana Reddy Kalluru enum MFW_DRV_MSG_TYPE type) 15866c754246SSudarsana Reddy Kalluru { 15876c754246SSudarsana Reddy Kalluru enum qed_mcp_protocol_type stats_type; 15886c754246SSudarsana Reddy Kalluru union qed_mcp_protocol_stats stats; 15896c754246SSudarsana Reddy Kalluru struct qed_mcp_mb_params mb_params; 15906c754246SSudarsana Reddy Kalluru u32 hsi_param; 15916c754246SSudarsana Reddy Kalluru 15926c754246SSudarsana Reddy Kalluru switch (type) { 15936c754246SSudarsana Reddy Kalluru case MFW_DRV_MSG_GET_LAN_STATS: 15946c754246SSudarsana Reddy Kalluru stats_type = QED_MCP_LAN_STATS; 15956c754246SSudarsana Reddy Kalluru hsi_param = DRV_MSG_CODE_STATS_TYPE_LAN; 15966c754246SSudarsana Reddy Kalluru break; 15976c754246SSudarsana Reddy Kalluru case MFW_DRV_MSG_GET_FCOE_STATS: 15986c754246SSudarsana Reddy Kalluru stats_type = QED_MCP_FCOE_STATS; 15996c754246SSudarsana Reddy Kalluru hsi_param = DRV_MSG_CODE_STATS_TYPE_FCOE; 16006c754246SSudarsana Reddy Kalluru break; 16016c754246SSudarsana Reddy Kalluru case MFW_DRV_MSG_GET_ISCSI_STATS: 16026c754246SSudarsana Reddy Kalluru stats_type = QED_MCP_ISCSI_STATS; 16036c754246SSudarsana Reddy Kalluru hsi_param = DRV_MSG_CODE_STATS_TYPE_ISCSI; 16046c754246SSudarsana Reddy Kalluru break; 16056c754246SSudarsana Reddy Kalluru case MFW_DRV_MSG_GET_RDMA_STATS: 16066c754246SSudarsana Reddy Kalluru stats_type = QED_MCP_RDMA_STATS; 16076c754246SSudarsana Reddy Kalluru hsi_param = DRV_MSG_CODE_STATS_TYPE_RDMA; 16086c754246SSudarsana Reddy Kalluru break; 16096c754246SSudarsana Reddy Kalluru default: 16106c754246SSudarsana Reddy Kalluru DP_NOTICE(p_hwfn, "Invalid protocol type %d\n", type); 16116c754246SSudarsana Reddy Kalluru return; 16126c754246SSudarsana Reddy Kalluru } 16136c754246SSudarsana Reddy Kalluru 16146c754246SSudarsana Reddy Kalluru qed_get_protocol_stats(p_hwfn->cdev, stats_type, &stats); 16156c754246SSudarsana Reddy Kalluru 16166c754246SSudarsana Reddy Kalluru memset(&mb_params, 0, sizeof(mb_params)); 16176c754246SSudarsana Reddy Kalluru mb_params.cmd = DRV_MSG_CODE_GET_STATS; 16186c754246SSudarsana Reddy Kalluru mb_params.param = hsi_param; 16192f67af8cSTomer Tayar mb_params.p_data_src = &stats; 16202f67af8cSTomer Tayar mb_params.data_src_size = sizeof(stats); 16216c754246SSudarsana Reddy Kalluru qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 16226c754246SSudarsana Reddy Kalluru } 16236c754246SSudarsana Reddy Kalluru 16241a635e48SYuval Mintz static void qed_mcp_update_bw(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 16254b01e519SManish Chopra { 16264b01e519SManish Chopra struct qed_mcp_function_info *p_info; 16274b01e519SManish Chopra struct public_func shmem_info; 16284b01e519SManish Chopra u32 resp = 0, param = 0; 16294b01e519SManish Chopra 16301a635e48SYuval Mintz qed_mcp_get_shmem_func(p_hwfn, p_ptt, &shmem_info, MCP_PF_ID(p_hwfn)); 16314b01e519SManish Chopra 16324b01e519SManish Chopra qed_read_pf_bandwidth(p_hwfn, &shmem_info); 16334b01e519SManish Chopra 16344b01e519SManish Chopra p_info = &p_hwfn->mcp_info->func_info; 16354b01e519SManish Chopra 1636a64b02d5SManish Chopra qed_configure_pf_min_bandwidth(p_hwfn->cdev, p_info->bandwidth_min); 16374b01e519SManish Chopra qed_configure_pf_max_bandwidth(p_hwfn->cdev, p_info->bandwidth_max); 16384b01e519SManish Chopra 16394b01e519SManish Chopra /* Acknowledge the MFW */ 16404b01e519SManish Chopra qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_BW_UPDATE_ACK, 0, &resp, 16414b01e519SManish Chopra ¶m); 16424b01e519SManish Chopra } 16434b01e519SManish Chopra 16442a351fd9SMintz, Yuval static void qed_mcp_update_stag(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 16452a351fd9SMintz, Yuval { 16462a351fd9SMintz, Yuval struct public_func shmem_info; 16472a351fd9SMintz, Yuval u32 resp = 0, param = 0; 16482a351fd9SMintz, Yuval 16492a351fd9SMintz, Yuval qed_mcp_get_shmem_func(p_hwfn, p_ptt, &shmem_info, MCP_PF_ID(p_hwfn)); 16502a351fd9SMintz, Yuval 16512a351fd9SMintz, Yuval p_hwfn->mcp_info->func_info.ovlan = (u16)shmem_info.ovlan_stag & 16522a351fd9SMintz, Yuval FUNC_MF_CFG_OV_STAG_MASK; 16532a351fd9SMintz, Yuval p_hwfn->hw_info.ovlan = p_hwfn->mcp_info->func_info.ovlan; 16547e3e375cSSudarsana Reddy Kalluru if (test_bit(QED_MF_OVLAN_CLSS, &p_hwfn->cdev->mf_bits)) { 16557e3e375cSSudarsana Reddy Kalluru if (p_hwfn->hw_info.ovlan != QED_MCP_VLAN_UNSET) { 16567e3e375cSSudarsana Reddy Kalluru qed_wr(p_hwfn, p_ptt, NIG_REG_LLH_FUNC_TAG_VALUE, 16577e3e375cSSudarsana Reddy Kalluru p_hwfn->hw_info.ovlan); 16587e3e375cSSudarsana Reddy Kalluru qed_wr(p_hwfn, p_ptt, NIG_REG_LLH_FUNC_TAG_EN, 1); 16597e3e375cSSudarsana Reddy Kalluru 16607e3e375cSSudarsana Reddy Kalluru /* Configure DB to add external vlan to EDPM packets */ 16617e3e375cSSudarsana Reddy Kalluru qed_wr(p_hwfn, p_ptt, DORQ_REG_TAG1_OVRD_MODE, 1); 16627e3e375cSSudarsana Reddy Kalluru qed_wr(p_hwfn, p_ptt, DORQ_REG_PF_EXT_VID_BB_K2, 16637e3e375cSSudarsana Reddy Kalluru p_hwfn->hw_info.ovlan); 16647e3e375cSSudarsana Reddy Kalluru } else { 16657e3e375cSSudarsana Reddy Kalluru qed_wr(p_hwfn, p_ptt, NIG_REG_LLH_FUNC_TAG_EN, 0); 16667e3e375cSSudarsana Reddy Kalluru qed_wr(p_hwfn, p_ptt, NIG_REG_LLH_FUNC_TAG_VALUE, 0); 16677e3e375cSSudarsana Reddy Kalluru qed_wr(p_hwfn, p_ptt, DORQ_REG_TAG1_OVRD_MODE, 0); 16687e3e375cSSudarsana Reddy Kalluru qed_wr(p_hwfn, p_ptt, DORQ_REG_PF_EXT_VID_BB_K2, 0); 16697e3e375cSSudarsana Reddy Kalluru } 16707e3e375cSSudarsana Reddy Kalluru 16712a351fd9SMintz, Yuval qed_sp_pf_update_stag(p_hwfn); 16722a351fd9SMintz, Yuval } 16732a351fd9SMintz, Yuval 16747e3e375cSSudarsana Reddy Kalluru DP_VERBOSE(p_hwfn, QED_MSG_SP, "ovlan = %d hw_mode = 0x%x\n", 16757e3e375cSSudarsana Reddy Kalluru p_hwfn->mcp_info->func_info.ovlan, p_hwfn->hw_info.hw_mode); 16767e3e375cSSudarsana Reddy Kalluru 16772a351fd9SMintz, Yuval /* Acknowledge the MFW */ 16782a351fd9SMintz, Yuval qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_S_TAG_UPDATE_ACK, 0, 16792a351fd9SMintz, Yuval &resp, ¶m); 16802a351fd9SMintz, Yuval } 16812a351fd9SMintz, Yuval 16823e99c211SIgor Russkikh static void qed_mcp_handle_fan_failure(struct qed_hwfn *p_hwfn, 16833e99c211SIgor Russkikh struct qed_ptt *p_ptt) 16843e99c211SIgor Russkikh { 16853e99c211SIgor Russkikh /* A single notification should be sent to upper driver in CMT mode */ 16863e99c211SIgor Russkikh if (p_hwfn != QED_LEADING_HWFN(p_hwfn->cdev)) 16873e99c211SIgor Russkikh return; 16883e99c211SIgor Russkikh 16893e99c211SIgor Russkikh qed_hw_err_notify(p_hwfn, p_ptt, QED_HW_ERR_FAN_FAIL, 16903e99c211SIgor Russkikh "Fan failure was detected on the network interface card and it's going to be shut down.\n"); 16913e99c211SIgor Russkikh } 16923e99c211SIgor Russkikh 1693ebf64bf4SIgor Russkikh struct qed_mdump_cmd_params { 1694ebf64bf4SIgor Russkikh u32 cmd; 1695ebf64bf4SIgor Russkikh void *p_data_src; 1696ebf64bf4SIgor Russkikh u8 data_src_size; 1697ebf64bf4SIgor Russkikh void *p_data_dst; 1698ebf64bf4SIgor Russkikh u8 data_dst_size; 1699ebf64bf4SIgor Russkikh u32 mcp_resp; 1700ebf64bf4SIgor Russkikh }; 1701ebf64bf4SIgor Russkikh 1702ebf64bf4SIgor Russkikh static int 1703ebf64bf4SIgor Russkikh qed_mcp_mdump_cmd(struct qed_hwfn *p_hwfn, 1704ebf64bf4SIgor Russkikh struct qed_ptt *p_ptt, 1705ebf64bf4SIgor Russkikh struct qed_mdump_cmd_params *p_mdump_cmd_params) 1706ebf64bf4SIgor Russkikh { 1707ebf64bf4SIgor Russkikh struct qed_mcp_mb_params mb_params; 1708ebf64bf4SIgor Russkikh int rc; 1709ebf64bf4SIgor Russkikh 1710ebf64bf4SIgor Russkikh memset(&mb_params, 0, sizeof(mb_params)); 1711ebf64bf4SIgor Russkikh mb_params.cmd = DRV_MSG_CODE_MDUMP_CMD; 1712ebf64bf4SIgor Russkikh mb_params.param = p_mdump_cmd_params->cmd; 1713ebf64bf4SIgor Russkikh mb_params.p_data_src = p_mdump_cmd_params->p_data_src; 1714ebf64bf4SIgor Russkikh mb_params.data_src_size = p_mdump_cmd_params->data_src_size; 1715ebf64bf4SIgor Russkikh mb_params.p_data_dst = p_mdump_cmd_params->p_data_dst; 1716ebf64bf4SIgor Russkikh mb_params.data_dst_size = p_mdump_cmd_params->data_dst_size; 1717ebf64bf4SIgor Russkikh rc = qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 1718ebf64bf4SIgor Russkikh if (rc) 1719ebf64bf4SIgor Russkikh return rc; 1720ebf64bf4SIgor Russkikh 1721ebf64bf4SIgor Russkikh p_mdump_cmd_params->mcp_resp = mb_params.mcp_resp; 1722ebf64bf4SIgor Russkikh 1723ebf64bf4SIgor Russkikh if (p_mdump_cmd_params->mcp_resp == FW_MSG_CODE_MDUMP_INVALID_CMD) { 1724ebf64bf4SIgor Russkikh DP_INFO(p_hwfn, 1725ebf64bf4SIgor Russkikh "The mdump sub command is unsupported by the MFW [mdump_cmd 0x%x]\n", 1726ebf64bf4SIgor Russkikh p_mdump_cmd_params->cmd); 1727ebf64bf4SIgor Russkikh rc = -EOPNOTSUPP; 1728ebf64bf4SIgor Russkikh } else if (p_mdump_cmd_params->mcp_resp == FW_MSG_CODE_UNSUPPORTED) { 1729ebf64bf4SIgor Russkikh DP_INFO(p_hwfn, 1730ebf64bf4SIgor Russkikh "The mdump command is not supported by the MFW\n"); 1731ebf64bf4SIgor Russkikh rc = -EOPNOTSUPP; 1732ebf64bf4SIgor Russkikh } 1733ebf64bf4SIgor Russkikh 1734ebf64bf4SIgor Russkikh return rc; 1735ebf64bf4SIgor Russkikh } 1736ebf64bf4SIgor Russkikh 1737ebf64bf4SIgor Russkikh static int qed_mcp_mdump_ack(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 1738ebf64bf4SIgor Russkikh { 1739ebf64bf4SIgor Russkikh struct qed_mdump_cmd_params mdump_cmd_params; 1740ebf64bf4SIgor Russkikh 1741ebf64bf4SIgor Russkikh memset(&mdump_cmd_params, 0, sizeof(mdump_cmd_params)); 1742ebf64bf4SIgor Russkikh mdump_cmd_params.cmd = DRV_MSG_CODE_MDUMP_ACK; 1743ebf64bf4SIgor Russkikh 1744ebf64bf4SIgor Russkikh return qed_mcp_mdump_cmd(p_hwfn, p_ptt, &mdump_cmd_params); 1745ebf64bf4SIgor Russkikh } 1746ebf64bf4SIgor Russkikh 1747ebf64bf4SIgor Russkikh int 1748ebf64bf4SIgor Russkikh qed_mcp_mdump_get_retain(struct qed_hwfn *p_hwfn, 1749ebf64bf4SIgor Russkikh struct qed_ptt *p_ptt, 1750ebf64bf4SIgor Russkikh struct mdump_retain_data_stc *p_mdump_retain) 1751ebf64bf4SIgor Russkikh { 1752ebf64bf4SIgor Russkikh struct qed_mdump_cmd_params mdump_cmd_params; 1753ebf64bf4SIgor Russkikh int rc; 1754ebf64bf4SIgor Russkikh 1755ebf64bf4SIgor Russkikh memset(&mdump_cmd_params, 0, sizeof(mdump_cmd_params)); 1756ebf64bf4SIgor Russkikh mdump_cmd_params.cmd = DRV_MSG_CODE_MDUMP_GET_RETAIN; 1757ebf64bf4SIgor Russkikh mdump_cmd_params.p_data_dst = p_mdump_retain; 1758ebf64bf4SIgor Russkikh mdump_cmd_params.data_dst_size = sizeof(*p_mdump_retain); 1759ebf64bf4SIgor Russkikh 1760ebf64bf4SIgor Russkikh rc = qed_mcp_mdump_cmd(p_hwfn, p_ptt, &mdump_cmd_params); 1761ebf64bf4SIgor Russkikh if (rc) 1762ebf64bf4SIgor Russkikh return rc; 1763ebf64bf4SIgor Russkikh 1764ebf64bf4SIgor Russkikh if (mdump_cmd_params.mcp_resp != FW_MSG_CODE_OK) { 1765ebf64bf4SIgor Russkikh DP_INFO(p_hwfn, 1766ebf64bf4SIgor Russkikh "Failed to get the mdump retained data [mcp_resp 0x%x]\n", 1767ebf64bf4SIgor Russkikh mdump_cmd_params.mcp_resp); 1768ebf64bf4SIgor Russkikh return -EINVAL; 1769ebf64bf4SIgor Russkikh } 1770ebf64bf4SIgor Russkikh 1771ebf64bf4SIgor Russkikh return 0; 1772ebf64bf4SIgor Russkikh } 1773ebf64bf4SIgor Russkikh 1774ebf64bf4SIgor Russkikh static void qed_mcp_handle_critical_error(struct qed_hwfn *p_hwfn, 1775ebf64bf4SIgor Russkikh struct qed_ptt *p_ptt) 1776ebf64bf4SIgor Russkikh { 1777ebf64bf4SIgor Russkikh struct mdump_retain_data_stc mdump_retain; 1778ebf64bf4SIgor Russkikh int rc; 1779ebf64bf4SIgor Russkikh 1780ebf64bf4SIgor Russkikh /* In CMT mode - no need for more than a single acknowledgment to the 1781ebf64bf4SIgor Russkikh * MFW, and no more than a single notification to the upper driver. 1782ebf64bf4SIgor Russkikh */ 1783ebf64bf4SIgor Russkikh if (p_hwfn != QED_LEADING_HWFN(p_hwfn->cdev)) 1784ebf64bf4SIgor Russkikh return; 1785ebf64bf4SIgor Russkikh 1786ebf64bf4SIgor Russkikh rc = qed_mcp_mdump_get_retain(p_hwfn, p_ptt, &mdump_retain); 1787ebf64bf4SIgor Russkikh if (rc == 0 && mdump_retain.valid) 1788ebf64bf4SIgor Russkikh DP_NOTICE(p_hwfn, 1789ebf64bf4SIgor Russkikh "The MFW notified that a critical error occurred in the device [epoch 0x%08x, pf 0x%x, status 0x%08x]\n", 1790ebf64bf4SIgor Russkikh mdump_retain.epoch, 1791ebf64bf4SIgor Russkikh mdump_retain.pf, mdump_retain.status); 1792ebf64bf4SIgor Russkikh else 1793ebf64bf4SIgor Russkikh DP_NOTICE(p_hwfn, 1794ebf64bf4SIgor Russkikh "The MFW notified that a critical error occurred in the device\n"); 1795ebf64bf4SIgor Russkikh 1796ebf64bf4SIgor Russkikh DP_NOTICE(p_hwfn, 1797ebf64bf4SIgor Russkikh "Acknowledging the notification to not allow the MFW crash dump [driver debug data collection is preferable]\n"); 1798ebf64bf4SIgor Russkikh qed_mcp_mdump_ack(p_hwfn, p_ptt); 1799ebf64bf4SIgor Russkikh 1800ebf64bf4SIgor Russkikh qed_hw_err_notify(p_hwfn, p_ptt, QED_HW_ERR_HW_ATTN, NULL); 1801ebf64bf4SIgor Russkikh } 1802ebf64bf4SIgor Russkikh 1803cac6f691SSudarsana Reddy Kalluru void qed_mcp_read_ufp_config(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 1804cac6f691SSudarsana Reddy Kalluru { 1805cac6f691SSudarsana Reddy Kalluru struct public_func shmem_info; 1806cac6f691SSudarsana Reddy Kalluru u32 port_cfg, val; 1807cac6f691SSudarsana Reddy Kalluru 1808cac6f691SSudarsana Reddy Kalluru if (!test_bit(QED_MF_UFP_SPECIFIC, &p_hwfn->cdev->mf_bits)) 1809cac6f691SSudarsana Reddy Kalluru return; 1810cac6f691SSudarsana Reddy Kalluru 1811cac6f691SSudarsana Reddy Kalluru memset(&p_hwfn->ufp_info, 0, sizeof(p_hwfn->ufp_info)); 1812cac6f691SSudarsana Reddy Kalluru port_cfg = qed_rd(p_hwfn, p_ptt, p_hwfn->mcp_info->port_addr + 1813cac6f691SSudarsana Reddy Kalluru offsetof(struct public_port, oem_cfg_port)); 1814cac6f691SSudarsana Reddy Kalluru val = (port_cfg & OEM_CFG_CHANNEL_TYPE_MASK) >> 1815cac6f691SSudarsana Reddy Kalluru OEM_CFG_CHANNEL_TYPE_OFFSET; 1816cac6f691SSudarsana Reddy Kalluru if (val != OEM_CFG_CHANNEL_TYPE_STAGGED) 1817ec036eb9SSudarsana Reddy Kalluru DP_NOTICE(p_hwfn, 1818ec036eb9SSudarsana Reddy Kalluru "Incorrect UFP Channel type %d port_id 0x%02x\n", 1819ec036eb9SSudarsana Reddy Kalluru val, MFW_PORT(p_hwfn)); 1820cac6f691SSudarsana Reddy Kalluru 1821cac6f691SSudarsana Reddy Kalluru val = (port_cfg & OEM_CFG_SCHED_TYPE_MASK) >> OEM_CFG_SCHED_TYPE_OFFSET; 1822cac6f691SSudarsana Reddy Kalluru if (val == OEM_CFG_SCHED_TYPE_ETS) { 1823cac6f691SSudarsana Reddy Kalluru p_hwfn->ufp_info.mode = QED_UFP_MODE_ETS; 1824cac6f691SSudarsana Reddy Kalluru } else if (val == OEM_CFG_SCHED_TYPE_VNIC_BW) { 1825cac6f691SSudarsana Reddy Kalluru p_hwfn->ufp_info.mode = QED_UFP_MODE_VNIC_BW; 1826cac6f691SSudarsana Reddy Kalluru } else { 1827cac6f691SSudarsana Reddy Kalluru p_hwfn->ufp_info.mode = QED_UFP_MODE_UNKNOWN; 1828ec036eb9SSudarsana Reddy Kalluru DP_NOTICE(p_hwfn, 1829ec036eb9SSudarsana Reddy Kalluru "Unknown UFP scheduling mode %d port_id 0x%02x\n", 1830ec036eb9SSudarsana Reddy Kalluru val, MFW_PORT(p_hwfn)); 1831cac6f691SSudarsana Reddy Kalluru } 1832cac6f691SSudarsana Reddy Kalluru 1833cac6f691SSudarsana Reddy Kalluru qed_mcp_get_shmem_func(p_hwfn, p_ptt, &shmem_info, MCP_PF_ID(p_hwfn)); 1834b5fabb08SSudarsana Reddy Kalluru val = (shmem_info.oem_cfg_func & OEM_CFG_FUNC_TC_MASK) >> 1835b5fabb08SSudarsana Reddy Kalluru OEM_CFG_FUNC_TC_OFFSET; 1836cac6f691SSudarsana Reddy Kalluru p_hwfn->ufp_info.tc = (u8)val; 1837b5fabb08SSudarsana Reddy Kalluru val = (shmem_info.oem_cfg_func & OEM_CFG_FUNC_HOST_PRI_CTRL_MASK) >> 1838cac6f691SSudarsana Reddy Kalluru OEM_CFG_FUNC_HOST_PRI_CTRL_OFFSET; 1839cac6f691SSudarsana Reddy Kalluru if (val == OEM_CFG_FUNC_HOST_PRI_CTRL_VNIC) { 1840cac6f691SSudarsana Reddy Kalluru p_hwfn->ufp_info.pri_type = QED_UFP_PRI_VNIC; 1841cac6f691SSudarsana Reddy Kalluru } else if (val == OEM_CFG_FUNC_HOST_PRI_CTRL_OS) { 1842cac6f691SSudarsana Reddy Kalluru p_hwfn->ufp_info.pri_type = QED_UFP_PRI_OS; 1843cac6f691SSudarsana Reddy Kalluru } else { 1844cac6f691SSudarsana Reddy Kalluru p_hwfn->ufp_info.pri_type = QED_UFP_PRI_UNKNOWN; 1845ec036eb9SSudarsana Reddy Kalluru DP_NOTICE(p_hwfn, 1846ec036eb9SSudarsana Reddy Kalluru "Unknown Host priority control %d port_id 0x%02x\n", 1847ec036eb9SSudarsana Reddy Kalluru val, MFW_PORT(p_hwfn)); 1848cac6f691SSudarsana Reddy Kalluru } 1849cac6f691SSudarsana Reddy Kalluru 1850cac6f691SSudarsana Reddy Kalluru DP_NOTICE(p_hwfn, 1851ec036eb9SSudarsana Reddy Kalluru "UFP shmem config: mode = %d tc = %d pri_type = %d port_id 0x%02x\n", 1852ec036eb9SSudarsana Reddy Kalluru p_hwfn->ufp_info.mode, p_hwfn->ufp_info.tc, 1853ec036eb9SSudarsana Reddy Kalluru p_hwfn->ufp_info.pri_type, MFW_PORT(p_hwfn)); 1854cac6f691SSudarsana Reddy Kalluru } 1855cac6f691SSudarsana Reddy Kalluru 1856cac6f691SSudarsana Reddy Kalluru static int 1857cac6f691SSudarsana Reddy Kalluru qed_mcp_handle_ufp_event(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 1858cac6f691SSudarsana Reddy Kalluru { 1859cac6f691SSudarsana Reddy Kalluru qed_mcp_read_ufp_config(p_hwfn, p_ptt); 1860cac6f691SSudarsana Reddy Kalluru 1861cac6f691SSudarsana Reddy Kalluru if (p_hwfn->ufp_info.mode == QED_UFP_MODE_VNIC_BW) { 1862cac6f691SSudarsana Reddy Kalluru p_hwfn->qm_info.ooo_tc = p_hwfn->ufp_info.tc; 1863c4259ddaSDenis Bolotin qed_hw_info_set_offload_tc(&p_hwfn->hw_info, 1864c4259ddaSDenis Bolotin p_hwfn->ufp_info.tc); 1865cac6f691SSudarsana Reddy Kalluru 1866cac6f691SSudarsana Reddy Kalluru qed_qm_reconf(p_hwfn, p_ptt); 1867cac6f691SSudarsana Reddy Kalluru } else if (p_hwfn->ufp_info.mode == QED_UFP_MODE_ETS) { 1868cac6f691SSudarsana Reddy Kalluru /* Merge UFP TC with the dcbx TC data */ 1869cac6f691SSudarsana Reddy Kalluru qed_dcbx_mib_update_event(p_hwfn, p_ptt, 1870cac6f691SSudarsana Reddy Kalluru QED_DCBX_OPERATIONAL_MIB); 1871cac6f691SSudarsana Reddy Kalluru } else { 1872cac6f691SSudarsana Reddy Kalluru DP_ERR(p_hwfn, "Invalid sched type, discard the UFP config\n"); 1873cac6f691SSudarsana Reddy Kalluru return -EINVAL; 1874cac6f691SSudarsana Reddy Kalluru } 1875cac6f691SSudarsana Reddy Kalluru 1876cac6f691SSudarsana Reddy Kalluru /* update storm FW with negotiation results */ 1877cac6f691SSudarsana Reddy Kalluru qed_sp_pf_update_ufp(p_hwfn); 1878cac6f691SSudarsana Reddy Kalluru 1879cac6f691SSudarsana Reddy Kalluru /* update stag pcp value */ 1880cac6f691SSudarsana Reddy Kalluru qed_sp_pf_update_stag(p_hwfn); 1881cac6f691SSudarsana Reddy Kalluru 1882cac6f691SSudarsana Reddy Kalluru return 0; 1883cac6f691SSudarsana Reddy Kalluru } 1884cac6f691SSudarsana Reddy Kalluru 1885cc875c2eSYuval Mintz int qed_mcp_handle_events(struct qed_hwfn *p_hwfn, 1886cc875c2eSYuval Mintz struct qed_ptt *p_ptt) 1887cc875c2eSYuval Mintz { 1888cc875c2eSYuval Mintz struct qed_mcp_info *info = p_hwfn->mcp_info; 1889cc875c2eSYuval Mintz int rc = 0; 1890cc875c2eSYuval Mintz bool found = false; 1891cc875c2eSYuval Mintz u16 i; 1892cc875c2eSYuval Mintz 1893cc875c2eSYuval Mintz DP_VERBOSE(p_hwfn, QED_MSG_SP, "Received message from MFW\n"); 1894cc875c2eSYuval Mintz 1895cc875c2eSYuval Mintz /* Read Messages from MFW */ 1896cc875c2eSYuval Mintz qed_mcp_read_mb(p_hwfn, p_ptt); 1897cc875c2eSYuval Mintz 1898cc875c2eSYuval Mintz /* Compare current messages to old ones */ 1899cc875c2eSYuval Mintz for (i = 0; i < info->mfw_mb_length; i++) { 1900cc875c2eSYuval Mintz if (info->mfw_mb_cur[i] == info->mfw_mb_shadow[i]) 1901cc875c2eSYuval Mintz continue; 1902cc875c2eSYuval Mintz 1903cc875c2eSYuval Mintz found = true; 1904cc875c2eSYuval Mintz 1905cc875c2eSYuval Mintz DP_VERBOSE(p_hwfn, NETIF_MSG_LINK, 1906cc875c2eSYuval Mintz "Msg [%d] - old CMD 0x%02x, new CMD 0x%02x\n", 1907cc875c2eSYuval Mintz i, info->mfw_mb_shadow[i], info->mfw_mb_cur[i]); 1908cc875c2eSYuval Mintz 1909cc875c2eSYuval Mintz switch (i) { 1910cc875c2eSYuval Mintz case MFW_DRV_MSG_LINK_CHANGE: 1911cc875c2eSYuval Mintz qed_mcp_handle_link_change(p_hwfn, p_ptt, false); 1912cc875c2eSYuval Mintz break; 19130b55e27dSYuval Mintz case MFW_DRV_MSG_VF_DISABLED: 19140b55e27dSYuval Mintz qed_mcp_handle_vf_flr(p_hwfn, p_ptt); 19150b55e27dSYuval Mintz break; 191639651abdSSudarsana Reddy Kalluru case MFW_DRV_MSG_LLDP_DATA_UPDATED: 191739651abdSSudarsana Reddy Kalluru qed_dcbx_mib_update_event(p_hwfn, p_ptt, 191839651abdSSudarsana Reddy Kalluru QED_DCBX_REMOTE_LLDP_MIB); 191939651abdSSudarsana Reddy Kalluru break; 192039651abdSSudarsana Reddy Kalluru case MFW_DRV_MSG_DCBX_REMOTE_MIB_UPDATED: 192139651abdSSudarsana Reddy Kalluru qed_dcbx_mib_update_event(p_hwfn, p_ptt, 192239651abdSSudarsana Reddy Kalluru QED_DCBX_REMOTE_MIB); 192339651abdSSudarsana Reddy Kalluru break; 192439651abdSSudarsana Reddy Kalluru case MFW_DRV_MSG_DCBX_OPERATIONAL_MIB_UPDATED: 192539651abdSSudarsana Reddy Kalluru qed_dcbx_mib_update_event(p_hwfn, p_ptt, 192639651abdSSudarsana Reddy Kalluru QED_DCBX_OPERATIONAL_MIB); 192739651abdSSudarsana Reddy Kalluru break; 1928cac6f691SSudarsana Reddy Kalluru case MFW_DRV_MSG_OEM_CFG_UPDATE: 1929cac6f691SSudarsana Reddy Kalluru qed_mcp_handle_ufp_event(p_hwfn, p_ptt); 1930cac6f691SSudarsana Reddy Kalluru break; 1931334c03b5SZvi Nachmani case MFW_DRV_MSG_TRANSCEIVER_STATE_CHANGE: 1932334c03b5SZvi Nachmani qed_mcp_handle_transceiver_change(p_hwfn, p_ptt); 1933334c03b5SZvi Nachmani break; 193464515dc8STomer Tayar case MFW_DRV_MSG_ERROR_RECOVERY: 193564515dc8STomer Tayar qed_mcp_handle_process_kill(p_hwfn, p_ptt); 193664515dc8STomer Tayar break; 19376c754246SSudarsana Reddy Kalluru case MFW_DRV_MSG_GET_LAN_STATS: 19386c754246SSudarsana Reddy Kalluru case MFW_DRV_MSG_GET_FCOE_STATS: 19396c754246SSudarsana Reddy Kalluru case MFW_DRV_MSG_GET_ISCSI_STATS: 19406c754246SSudarsana Reddy Kalluru case MFW_DRV_MSG_GET_RDMA_STATS: 19416c754246SSudarsana Reddy Kalluru qed_mcp_send_protocol_stats(p_hwfn, p_ptt, i); 19426c754246SSudarsana Reddy Kalluru break; 19434b01e519SManish Chopra case MFW_DRV_MSG_BW_UPDATE: 19444b01e519SManish Chopra qed_mcp_update_bw(p_hwfn, p_ptt); 19454b01e519SManish Chopra break; 19462a351fd9SMintz, Yuval case MFW_DRV_MSG_S_TAG_UPDATE: 19472a351fd9SMintz, Yuval qed_mcp_update_stag(p_hwfn, p_ptt); 19482a351fd9SMintz, Yuval break; 19493e99c211SIgor Russkikh case MFW_DRV_MSG_FAILURE_DETECTED: 19503e99c211SIgor Russkikh qed_mcp_handle_fan_failure(p_hwfn, p_ptt); 19513e99c211SIgor Russkikh break; 1952ebf64bf4SIgor Russkikh case MFW_DRV_MSG_CRITICAL_ERROR_OCCURRED: 1953ebf64bf4SIgor Russkikh qed_mcp_handle_critical_error(p_hwfn, p_ptt); 1954ebf64bf4SIgor Russkikh break; 195559ccf86fSSudarsana Reddy Kalluru case MFW_DRV_MSG_GET_TLV_REQ: 195659ccf86fSSudarsana Reddy Kalluru qed_mfw_tlv_req(p_hwfn); 19572a351fd9SMintz, Yuval break; 1958cc875c2eSYuval Mintz default: 195939815944SMintz, Yuval DP_INFO(p_hwfn, "Unimplemented MFW message %d\n", i); 1960cc875c2eSYuval Mintz rc = -EINVAL; 1961cc875c2eSYuval Mintz } 1962cc875c2eSYuval Mintz } 1963cc875c2eSYuval Mintz 1964cc875c2eSYuval Mintz /* ACK everything */ 1965cc875c2eSYuval Mintz for (i = 0; i < MFW_DRV_MSG_MAX_DWORDS(info->mfw_mb_length); i++) { 1966cc875c2eSYuval Mintz __be32 val = cpu_to_be32(((u32 *)info->mfw_mb_cur)[i]); 1967cc875c2eSYuval Mintz 1968cc875c2eSYuval Mintz /* MFW expect answer in BE, so we force write in that format */ 1969cc875c2eSYuval Mintz qed_wr(p_hwfn, p_ptt, 1970cc875c2eSYuval Mintz info->mfw_mb_addr + sizeof(u32) + 1971cc875c2eSYuval Mintz MFW_DRV_MSG_MAX_DWORDS(info->mfw_mb_length) * 1972cc875c2eSYuval Mintz sizeof(u32) + i * sizeof(u32), 1973cc875c2eSYuval Mintz (__force u32)val); 1974cc875c2eSYuval Mintz } 1975cc875c2eSYuval Mintz 1976cc875c2eSYuval Mintz if (!found) { 1977cc875c2eSYuval Mintz DP_NOTICE(p_hwfn, 1978cc875c2eSYuval Mintz "Received an MFW message indication but no new message!\n"); 1979cc875c2eSYuval Mintz rc = -EINVAL; 1980cc875c2eSYuval Mintz } 1981cc875c2eSYuval Mintz 1982cc875c2eSYuval Mintz /* Copy the new mfw messages into the shadow */ 1983cc875c2eSYuval Mintz memcpy(info->mfw_mb_shadow, info->mfw_mb_cur, info->mfw_mb_length); 1984cc875c2eSYuval Mintz 1985cc875c2eSYuval Mintz return rc; 1986cc875c2eSYuval Mintz } 1987cc875c2eSYuval Mintz 19881408cc1fSYuval Mintz int qed_mcp_get_mfw_ver(struct qed_hwfn *p_hwfn, 19891408cc1fSYuval Mintz struct qed_ptt *p_ptt, 19901408cc1fSYuval Mintz u32 *p_mfw_ver, u32 *p_running_bundle_id) 1991fe56b9e6SYuval Mintz { 1992fe56b9e6SYuval Mintz u32 global_offsize; 1993fe56b9e6SYuval Mintz 19941408cc1fSYuval Mintz if (IS_VF(p_hwfn->cdev)) { 19951408cc1fSYuval Mintz if (p_hwfn->vf_iov_info) { 19961408cc1fSYuval Mintz struct pfvf_acquire_resp_tlv *p_resp; 19971408cc1fSYuval Mintz 19981408cc1fSYuval Mintz p_resp = &p_hwfn->vf_iov_info->acquire_resp; 19991408cc1fSYuval Mintz *p_mfw_ver = p_resp->pfdev_info.mfw_ver; 20001408cc1fSYuval Mintz return 0; 20011408cc1fSYuval Mintz } else { 20021408cc1fSYuval Mintz DP_VERBOSE(p_hwfn, 20031408cc1fSYuval Mintz QED_MSG_IOV, 20041408cc1fSYuval Mintz "VF requested MFW version prior to ACQUIRE\n"); 20051408cc1fSYuval Mintz return -EINVAL; 20061408cc1fSYuval Mintz } 20071408cc1fSYuval Mintz } 2008fe56b9e6SYuval Mintz 2009fe56b9e6SYuval Mintz global_offsize = qed_rd(p_hwfn, p_ptt, 20101408cc1fSYuval Mintz SECTION_OFFSIZE_ADDR(p_hwfn-> 20111408cc1fSYuval Mintz mcp_info->public_base, 2012fe56b9e6SYuval Mintz PUBLIC_GLOBAL)); 20131408cc1fSYuval Mintz *p_mfw_ver = 20141408cc1fSYuval Mintz qed_rd(p_hwfn, p_ptt, 20151408cc1fSYuval Mintz SECTION_ADDR(global_offsize, 20161408cc1fSYuval Mintz 0) + offsetof(struct public_global, mfw_ver)); 2017fe56b9e6SYuval Mintz 20181408cc1fSYuval Mintz if (p_running_bundle_id != NULL) { 20191408cc1fSYuval Mintz *p_running_bundle_id = qed_rd(p_hwfn, p_ptt, 20201408cc1fSYuval Mintz SECTION_ADDR(global_offsize, 0) + 20211408cc1fSYuval Mintz offsetof(struct public_global, 20221408cc1fSYuval Mintz running_bundle_id)); 20231408cc1fSYuval Mintz } 2024fe56b9e6SYuval Mintz 2025fe56b9e6SYuval Mintz return 0; 2026fe56b9e6SYuval Mintz } 2027fe56b9e6SYuval Mintz 2028ae33666aSTomer Tayar int qed_mcp_get_mbi_ver(struct qed_hwfn *p_hwfn, 2029ae33666aSTomer Tayar struct qed_ptt *p_ptt, u32 *p_mbi_ver) 2030ae33666aSTomer Tayar { 2031ae33666aSTomer Tayar u32 nvm_cfg_addr, nvm_cfg1_offset, mbi_ver_addr; 2032ae33666aSTomer Tayar 2033ae33666aSTomer Tayar if (IS_VF(p_hwfn->cdev)) 2034ae33666aSTomer Tayar return -EINVAL; 2035ae33666aSTomer Tayar 2036ae33666aSTomer Tayar /* Read the address of the nvm_cfg */ 2037ae33666aSTomer Tayar nvm_cfg_addr = qed_rd(p_hwfn, p_ptt, MISC_REG_GEN_PURP_CR0); 2038ae33666aSTomer Tayar if (!nvm_cfg_addr) { 2039ae33666aSTomer Tayar DP_NOTICE(p_hwfn, "Shared memory not initialized\n"); 2040ae33666aSTomer Tayar return -EINVAL; 2041ae33666aSTomer Tayar } 2042ae33666aSTomer Tayar 2043ae33666aSTomer Tayar /* Read the offset of nvm_cfg1 */ 2044ae33666aSTomer Tayar nvm_cfg1_offset = qed_rd(p_hwfn, p_ptt, nvm_cfg_addr + 4); 2045ae33666aSTomer Tayar 2046ae33666aSTomer Tayar mbi_ver_addr = MCP_REG_SCRATCH + nvm_cfg1_offset + 2047ae33666aSTomer Tayar offsetof(struct nvm_cfg1, glob) + 2048ae33666aSTomer Tayar offsetof(struct nvm_cfg1_glob, mbi_version); 2049ae33666aSTomer Tayar *p_mbi_ver = qed_rd(p_hwfn, p_ptt, 2050ae33666aSTomer Tayar mbi_ver_addr) & 2051ae33666aSTomer Tayar (NVM_CFG1_GLOB_MBI_VERSION_0_MASK | 2052ae33666aSTomer Tayar NVM_CFG1_GLOB_MBI_VERSION_1_MASK | 2053ae33666aSTomer Tayar NVM_CFG1_GLOB_MBI_VERSION_2_MASK); 2054ae33666aSTomer Tayar 2055ae33666aSTomer Tayar return 0; 2056ae33666aSTomer Tayar } 2057ae33666aSTomer Tayar 2058706d0891SRahul Verma int qed_mcp_get_media_type(struct qed_hwfn *p_hwfn, 2059706d0891SRahul Verma struct qed_ptt *p_ptt, u32 *p_media_type) 2060cc875c2eSYuval Mintz { 2061c56a8be7SRahul Verma *p_media_type = MEDIA_UNSPECIFIED; 2062c56a8be7SRahul Verma 2063706d0891SRahul Verma if (IS_VF(p_hwfn->cdev)) 20641408cc1fSYuval Mintz return -EINVAL; 20651408cc1fSYuval Mintz 2066cc875c2eSYuval Mintz if (!qed_mcp_is_init(p_hwfn)) { 2067cc875c2eSYuval Mintz DP_NOTICE(p_hwfn, "MFW is not initialized!\n"); 2068cc875c2eSYuval Mintz return -EBUSY; 2069cc875c2eSYuval Mintz } 2070cc875c2eSYuval Mintz 2071706d0891SRahul Verma if (!p_ptt) { 2072cc875c2eSYuval Mintz *p_media_type = MEDIA_UNSPECIFIED; 2073706d0891SRahul Verma return -EINVAL; 2074706d0891SRahul Verma } 2075cc875c2eSYuval Mintz 2076706d0891SRahul Verma *p_media_type = qed_rd(p_hwfn, p_ptt, 2077706d0891SRahul Verma p_hwfn->mcp_info->port_addr + 2078706d0891SRahul Verma offsetof(struct public_port, 2079706d0891SRahul Verma media_type)); 2080cc875c2eSYuval Mintz 2081cc875c2eSYuval Mintz return 0; 2082cc875c2eSYuval Mintz } 2083cc875c2eSYuval Mintz 2084c56a8be7SRahul Verma int qed_mcp_get_transceiver_data(struct qed_hwfn *p_hwfn, 2085c56a8be7SRahul Verma struct qed_ptt *p_ptt, 2086c56a8be7SRahul Verma u32 *p_transceiver_state, 2087c56a8be7SRahul Verma u32 *p_transceiver_type) 2088c56a8be7SRahul Verma { 2089c56a8be7SRahul Verma u32 transceiver_info; 2090c56a8be7SRahul Verma 209168203a67SRahul Verma *p_transceiver_type = ETH_TRANSCEIVER_TYPE_NONE; 209268203a67SRahul Verma *p_transceiver_state = ETH_TRANSCEIVER_STATE_UPDATING; 209368203a67SRahul Verma 2094c56a8be7SRahul Verma if (IS_VF(p_hwfn->cdev)) 2095c56a8be7SRahul Verma return -EINVAL; 2096c56a8be7SRahul Verma 2097c56a8be7SRahul Verma if (!qed_mcp_is_init(p_hwfn)) { 2098c56a8be7SRahul Verma DP_NOTICE(p_hwfn, "MFW is not initialized!\n"); 2099c56a8be7SRahul Verma return -EBUSY; 2100c56a8be7SRahul Verma } 2101c56a8be7SRahul Verma 2102c56a8be7SRahul Verma transceiver_info = qed_rd(p_hwfn, p_ptt, 2103c56a8be7SRahul Verma p_hwfn->mcp_info->port_addr + 2104c56a8be7SRahul Verma offsetof(struct public_port, 2105c56a8be7SRahul Verma transceiver_data)); 2106c56a8be7SRahul Verma 2107c56a8be7SRahul Verma *p_transceiver_state = (transceiver_info & 2108c56a8be7SRahul Verma ETH_TRANSCEIVER_STATE_MASK) >> 2109c56a8be7SRahul Verma ETH_TRANSCEIVER_STATE_OFFSET; 2110c56a8be7SRahul Verma 2111c56a8be7SRahul Verma if (*p_transceiver_state == ETH_TRANSCEIVER_STATE_PRESENT) 2112c56a8be7SRahul Verma *p_transceiver_type = (transceiver_info & 2113c56a8be7SRahul Verma ETH_TRANSCEIVER_TYPE_MASK) >> 2114c56a8be7SRahul Verma ETH_TRANSCEIVER_TYPE_OFFSET; 2115c56a8be7SRahul Verma else 2116c56a8be7SRahul Verma *p_transceiver_type = ETH_TRANSCEIVER_TYPE_UNKNOWN; 2117c56a8be7SRahul Verma 2118c56a8be7SRahul Verma return 0; 2119c56a8be7SRahul Verma } 2120c56a8be7SRahul Verma static bool qed_is_transceiver_ready(u32 transceiver_state, 2121c56a8be7SRahul Verma u32 transceiver_type) 2122c56a8be7SRahul Verma { 2123c56a8be7SRahul Verma if ((transceiver_state & ETH_TRANSCEIVER_STATE_PRESENT) && 2124c56a8be7SRahul Verma ((transceiver_state & ETH_TRANSCEIVER_STATE_UPDATING) == 0x0) && 2125c56a8be7SRahul Verma (transceiver_type != ETH_TRANSCEIVER_TYPE_NONE)) 2126c56a8be7SRahul Verma return true; 2127c56a8be7SRahul Verma 2128c56a8be7SRahul Verma return false; 2129c56a8be7SRahul Verma } 2130c56a8be7SRahul Verma 2131c56a8be7SRahul Verma int qed_mcp_trans_speed_mask(struct qed_hwfn *p_hwfn, 2132c56a8be7SRahul Verma struct qed_ptt *p_ptt, u32 *p_speed_mask) 2133c56a8be7SRahul Verma { 2134c56a8be7SRahul Verma u32 transceiver_type, transceiver_state; 213592619210SArnd Bergmann int ret; 2136c56a8be7SRahul Verma 213792619210SArnd Bergmann ret = qed_mcp_get_transceiver_data(p_hwfn, p_ptt, &transceiver_state, 2138c56a8be7SRahul Verma &transceiver_type); 213992619210SArnd Bergmann if (ret) 214092619210SArnd Bergmann return ret; 2141c56a8be7SRahul Verma 2142c56a8be7SRahul Verma if (qed_is_transceiver_ready(transceiver_state, transceiver_type) == 2143c56a8be7SRahul Verma false) 2144c56a8be7SRahul Verma return -EINVAL; 2145c56a8be7SRahul Verma 2146c56a8be7SRahul Verma switch (transceiver_type) { 2147c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_1G_LX: 2148c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_1G_SX: 2149c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_1G_PCC: 2150c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_1G_ACC: 2151c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_1000BASET: 2152c56a8be7SRahul Verma *p_speed_mask = NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G; 2153c56a8be7SRahul Verma break; 2154c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_10G_SR: 2155c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_10G_LR: 2156c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_10G_LRM: 2157c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_10G_ER: 2158c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_10G_PCC: 2159c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_10G_ACC: 2160c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_4x10G: 2161c56a8be7SRahul Verma *p_speed_mask = NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G; 2162c56a8be7SRahul Verma break; 2163c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_40G_LR4: 2164c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_40G_SR4: 2165c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_MULTI_RATE_10G_40G_SR: 2166c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_MULTI_RATE_10G_40G_LR: 2167c56a8be7SRahul Verma *p_speed_mask = NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_40G | 2168c56a8be7SRahul Verma NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G; 2169c56a8be7SRahul Verma break; 2170c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_100G_AOC: 2171c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_100G_SR4: 2172c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_100G_LR4: 2173c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_100G_ER4: 2174c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_100G_ACC: 2175c56a8be7SRahul Verma *p_speed_mask = 2176c56a8be7SRahul Verma NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_BB_100G | 2177c56a8be7SRahul Verma NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_25G; 2178c56a8be7SRahul Verma break; 2179c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_25G_SR: 2180c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_25G_LR: 2181c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_25G_AOC: 2182c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_25G_ACC_S: 2183c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_25G_ACC_M: 2184c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_25G_ACC_L: 2185c56a8be7SRahul Verma *p_speed_mask = NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_25G; 2186c56a8be7SRahul Verma break; 2187c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_25G_CA_N: 2188c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_25G_CA_S: 2189c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_25G_CA_L: 2190c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_4x25G_CR: 2191c56a8be7SRahul Verma *p_speed_mask = NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_25G | 2192c56a8be7SRahul Verma NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G | 2193c56a8be7SRahul Verma NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G; 2194c56a8be7SRahul Verma break; 2195c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_40G_CR4: 2196c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_MULTI_RATE_10G_40G_CR: 2197c56a8be7SRahul Verma *p_speed_mask = NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_40G | 2198c56a8be7SRahul Verma NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G | 2199c56a8be7SRahul Verma NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G; 2200c56a8be7SRahul Verma break; 2201c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_100G_CR4: 2202c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_MULTI_RATE_40G_100G_CR: 2203c56a8be7SRahul Verma *p_speed_mask = 2204c56a8be7SRahul Verma NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_BB_100G | 2205c56a8be7SRahul Verma NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_50G | 2206c56a8be7SRahul Verma NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_40G | 2207c56a8be7SRahul Verma NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_25G | 2208c56a8be7SRahul Verma NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_20G | 2209c56a8be7SRahul Verma NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G | 2210c56a8be7SRahul Verma NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G; 2211c56a8be7SRahul Verma break; 2212c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_MULTI_RATE_40G_100G_SR: 2213c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_MULTI_RATE_40G_100G_LR: 2214c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_MULTI_RATE_40G_100G_AOC: 2215c56a8be7SRahul Verma *p_speed_mask = 2216c56a8be7SRahul Verma NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_BB_100G | 2217c56a8be7SRahul Verma NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_40G | 2218c56a8be7SRahul Verma NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_25G | 2219c56a8be7SRahul Verma NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G; 2220c56a8be7SRahul Verma break; 2221c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_XLPPI: 2222c56a8be7SRahul Verma *p_speed_mask = NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_40G; 2223c56a8be7SRahul Verma break; 2224c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_10G_BASET: 2225c56a8be7SRahul Verma *p_speed_mask = NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G | 2226c56a8be7SRahul Verma NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G; 2227c56a8be7SRahul Verma break; 2228c56a8be7SRahul Verma default: 22291107a674SColin Ian King DP_INFO(p_hwfn, "Unknown transceiver type 0x%x\n", 2230c56a8be7SRahul Verma transceiver_type); 2231c56a8be7SRahul Verma *p_speed_mask = 0xff; 2232c56a8be7SRahul Verma break; 2233c56a8be7SRahul Verma } 2234c56a8be7SRahul Verma 2235c56a8be7SRahul Verma return 0; 2236c56a8be7SRahul Verma } 2237c56a8be7SRahul Verma 2238c56a8be7SRahul Verma int qed_mcp_get_board_config(struct qed_hwfn *p_hwfn, 2239c56a8be7SRahul Verma struct qed_ptt *p_ptt, u32 *p_board_config) 2240c56a8be7SRahul Verma { 2241c56a8be7SRahul Verma u32 nvm_cfg_addr, nvm_cfg1_offset, port_cfg_addr; 2242c56a8be7SRahul Verma 2243c56a8be7SRahul Verma if (IS_VF(p_hwfn->cdev)) 2244c56a8be7SRahul Verma return -EINVAL; 2245c56a8be7SRahul Verma 2246c56a8be7SRahul Verma if (!qed_mcp_is_init(p_hwfn)) { 2247c56a8be7SRahul Verma DP_NOTICE(p_hwfn, "MFW is not initialized!\n"); 2248c56a8be7SRahul Verma return -EBUSY; 2249c56a8be7SRahul Verma } 2250c56a8be7SRahul Verma if (!p_ptt) { 2251c56a8be7SRahul Verma *p_board_config = NVM_CFG1_PORT_PORT_TYPE_UNDEFINED; 2252c56a8be7SRahul Verma return -EINVAL; 2253c56a8be7SRahul Verma } 2254c56a8be7SRahul Verma 2255c56a8be7SRahul Verma nvm_cfg_addr = qed_rd(p_hwfn, p_ptt, MISC_REG_GEN_PURP_CR0); 2256c56a8be7SRahul Verma nvm_cfg1_offset = qed_rd(p_hwfn, p_ptt, nvm_cfg_addr + 4); 2257c56a8be7SRahul Verma port_cfg_addr = MCP_REG_SCRATCH + nvm_cfg1_offset + 2258c56a8be7SRahul Verma offsetof(struct nvm_cfg1, port[MFW_PORT(p_hwfn)]); 2259c56a8be7SRahul Verma *p_board_config = qed_rd(p_hwfn, p_ptt, 2260c56a8be7SRahul Verma port_cfg_addr + 2261c56a8be7SRahul Verma offsetof(struct nvm_cfg1_port, 2262c56a8be7SRahul Verma board_cfg)); 2263c56a8be7SRahul Verma 2264c56a8be7SRahul Verma return 0; 2265c56a8be7SRahul Verma } 2266c56a8be7SRahul Verma 22676927e826SMintz, Yuval /* Old MFW has a global configuration for all PFs regarding RDMA support */ 22686927e826SMintz, Yuval static void 22696927e826SMintz, Yuval qed_mcp_get_shmem_proto_legacy(struct qed_hwfn *p_hwfn, 22706927e826SMintz, Yuval enum qed_pci_personality *p_proto) 22716927e826SMintz, Yuval { 22726927e826SMintz, Yuval /* There wasn't ever a legacy MFW that published iwarp. 22736927e826SMintz, Yuval * So at this point, this is either plain l2 or RoCE. 22746927e826SMintz, Yuval */ 22756927e826SMintz, Yuval if (test_bit(QED_DEV_CAP_ROCE, &p_hwfn->hw_info.device_capabilities)) 22766927e826SMintz, Yuval *p_proto = QED_PCI_ETH_ROCE; 22776927e826SMintz, Yuval else 22786927e826SMintz, Yuval *p_proto = QED_PCI_ETH; 22796927e826SMintz, Yuval 22806927e826SMintz, Yuval DP_VERBOSE(p_hwfn, NETIF_MSG_IFUP, 22816927e826SMintz, Yuval "According to Legacy capabilities, L2 personality is %08x\n", 22826927e826SMintz, Yuval (u32) *p_proto); 22836927e826SMintz, Yuval } 22846927e826SMintz, Yuval 22856927e826SMintz, Yuval static int 22866927e826SMintz, Yuval qed_mcp_get_shmem_proto_mfw(struct qed_hwfn *p_hwfn, 22876927e826SMintz, Yuval struct qed_ptt *p_ptt, 22886927e826SMintz, Yuval enum qed_pci_personality *p_proto) 22896927e826SMintz, Yuval { 22906927e826SMintz, Yuval u32 resp = 0, param = 0; 22916927e826SMintz, Yuval int rc; 22926927e826SMintz, Yuval 22936927e826SMintz, Yuval rc = qed_mcp_cmd(p_hwfn, p_ptt, 22946927e826SMintz, Yuval DRV_MSG_CODE_GET_PF_RDMA_PROTOCOL, 0, &resp, ¶m); 22956927e826SMintz, Yuval if (rc) 22966927e826SMintz, Yuval return rc; 22976927e826SMintz, Yuval if (resp != FW_MSG_CODE_OK) { 22986927e826SMintz, Yuval DP_VERBOSE(p_hwfn, NETIF_MSG_IFUP, 22996927e826SMintz, Yuval "MFW lacks support for command; Returns %08x\n", 23006927e826SMintz, Yuval resp); 23016927e826SMintz, Yuval return -EINVAL; 23026927e826SMintz, Yuval } 23036927e826SMintz, Yuval 23046927e826SMintz, Yuval switch (param) { 23056927e826SMintz, Yuval case FW_MB_PARAM_GET_PF_RDMA_NONE: 23066927e826SMintz, Yuval *p_proto = QED_PCI_ETH; 23076927e826SMintz, Yuval break; 23086927e826SMintz, Yuval case FW_MB_PARAM_GET_PF_RDMA_ROCE: 23096927e826SMintz, Yuval *p_proto = QED_PCI_ETH_ROCE; 23106927e826SMintz, Yuval break; 23116927e826SMintz, Yuval case FW_MB_PARAM_GET_PF_RDMA_IWARP: 2312e0a8f9deSMichal Kalderon *p_proto = QED_PCI_ETH_IWARP; 2313e0a8f9deSMichal Kalderon break; 2314e0a8f9deSMichal Kalderon case FW_MB_PARAM_GET_PF_RDMA_BOTH: 2315e0a8f9deSMichal Kalderon *p_proto = QED_PCI_ETH_RDMA; 2316e0a8f9deSMichal Kalderon break; 23176927e826SMintz, Yuval default: 23186927e826SMintz, Yuval DP_NOTICE(p_hwfn, 23196927e826SMintz, Yuval "MFW answers GET_PF_RDMA_PROTOCOL but param is %08x\n", 23206927e826SMintz, Yuval param); 23216927e826SMintz, Yuval return -EINVAL; 23226927e826SMintz, Yuval } 23236927e826SMintz, Yuval 23246927e826SMintz, Yuval DP_VERBOSE(p_hwfn, 23256927e826SMintz, Yuval NETIF_MSG_IFUP, 23266927e826SMintz, Yuval "According to capabilities, L2 personality is %08x [resp %08x param %08x]\n", 23276927e826SMintz, Yuval (u32) *p_proto, resp, param); 23286927e826SMintz, Yuval return 0; 23296927e826SMintz, Yuval } 23306927e826SMintz, Yuval 2331fe56b9e6SYuval Mintz static int 2332fe56b9e6SYuval Mintz qed_mcp_get_shmem_proto(struct qed_hwfn *p_hwfn, 2333fe56b9e6SYuval Mintz struct public_func *p_info, 23346927e826SMintz, Yuval struct qed_ptt *p_ptt, 2335fe56b9e6SYuval Mintz enum qed_pci_personality *p_proto) 2336fe56b9e6SYuval Mintz { 2337fe56b9e6SYuval Mintz int rc = 0; 2338fe56b9e6SYuval Mintz 2339fe56b9e6SYuval Mintz switch (p_info->config & FUNC_MF_CFG_PROTOCOL_MASK) { 2340fe56b9e6SYuval Mintz case FUNC_MF_CFG_PROTOCOL_ETHERNET: 23411fe582ecSRam Amrani if (!IS_ENABLED(CONFIG_QED_RDMA)) 23421fe582ecSRam Amrani *p_proto = QED_PCI_ETH; 23431fe582ecSRam Amrani else if (qed_mcp_get_shmem_proto_mfw(p_hwfn, p_ptt, p_proto)) 23446927e826SMintz, Yuval qed_mcp_get_shmem_proto_legacy(p_hwfn, p_proto); 2345fe56b9e6SYuval Mintz break; 2346c5ac9319SYuval Mintz case FUNC_MF_CFG_PROTOCOL_ISCSI: 2347c5ac9319SYuval Mintz *p_proto = QED_PCI_ISCSI; 2348c5ac9319SYuval Mintz break; 23491e128c81SArun Easi case FUNC_MF_CFG_PROTOCOL_FCOE: 23501e128c81SArun Easi *p_proto = QED_PCI_FCOE; 23511e128c81SArun Easi break; 2352c5ac9319SYuval Mintz case FUNC_MF_CFG_PROTOCOL_ROCE: 2353c5ac9319SYuval Mintz DP_NOTICE(p_hwfn, "RoCE personality is not a valid value!\n"); 23546927e826SMintz, Yuval /* Fallthrough */ 2355fe56b9e6SYuval Mintz default: 2356fe56b9e6SYuval Mintz rc = -EINVAL; 2357fe56b9e6SYuval Mintz } 2358fe56b9e6SYuval Mintz 2359fe56b9e6SYuval Mintz return rc; 2360fe56b9e6SYuval Mintz } 2361fe56b9e6SYuval Mintz 2362fe56b9e6SYuval Mintz int qed_mcp_fill_shmem_func_info(struct qed_hwfn *p_hwfn, 2363fe56b9e6SYuval Mintz struct qed_ptt *p_ptt) 2364fe56b9e6SYuval Mintz { 2365fe56b9e6SYuval Mintz struct qed_mcp_function_info *info; 2366fe56b9e6SYuval Mintz struct public_func shmem_info; 2367fe56b9e6SYuval Mintz 23681a635e48SYuval Mintz qed_mcp_get_shmem_func(p_hwfn, p_ptt, &shmem_info, MCP_PF_ID(p_hwfn)); 2369fe56b9e6SYuval Mintz info = &p_hwfn->mcp_info->func_info; 2370fe56b9e6SYuval Mintz 2371fe56b9e6SYuval Mintz info->pause_on_host = (shmem_info.config & 2372fe56b9e6SYuval Mintz FUNC_MF_CFG_PAUSE_ON_HOST_RING) ? 1 : 0; 2373fe56b9e6SYuval Mintz 23746927e826SMintz, Yuval if (qed_mcp_get_shmem_proto(p_hwfn, &shmem_info, p_ptt, 23756927e826SMintz, Yuval &info->protocol)) { 2376fe56b9e6SYuval Mintz DP_ERR(p_hwfn, "Unknown personality %08x\n", 2377fe56b9e6SYuval Mintz (u32)(shmem_info.config & FUNC_MF_CFG_PROTOCOL_MASK)); 2378fe56b9e6SYuval Mintz return -EINVAL; 2379fe56b9e6SYuval Mintz } 2380fe56b9e6SYuval Mintz 23814b01e519SManish Chopra qed_read_pf_bandwidth(p_hwfn, &shmem_info); 2382fe56b9e6SYuval Mintz 2383fe56b9e6SYuval Mintz if (shmem_info.mac_upper || shmem_info.mac_lower) { 2384fe56b9e6SYuval Mintz info->mac[0] = (u8)(shmem_info.mac_upper >> 8); 2385fe56b9e6SYuval Mintz info->mac[1] = (u8)(shmem_info.mac_upper); 2386fe56b9e6SYuval Mintz info->mac[2] = (u8)(shmem_info.mac_lower >> 24); 2387fe56b9e6SYuval Mintz info->mac[3] = (u8)(shmem_info.mac_lower >> 16); 2388fe56b9e6SYuval Mintz info->mac[4] = (u8)(shmem_info.mac_lower >> 8); 2389fe56b9e6SYuval Mintz info->mac[5] = (u8)(shmem_info.mac_lower); 239014d39648SMintz, Yuval 239114d39648SMintz, Yuval /* Store primary MAC for later possible WoL */ 239214d39648SMintz, Yuval memcpy(&p_hwfn->cdev->wol_mac, info->mac, ETH_ALEN); 2393fe56b9e6SYuval Mintz } else { 2394fe56b9e6SYuval Mintz DP_NOTICE(p_hwfn, "MAC is 0 in shmem\n"); 2395fe56b9e6SYuval Mintz } 2396fe56b9e6SYuval Mintz 239757796759SMintz, Yuval info->wwn_port = (u64)shmem_info.fcoe_wwn_port_name_lower | 239857796759SMintz, Yuval (((u64)shmem_info.fcoe_wwn_port_name_upper) << 32); 239957796759SMintz, Yuval info->wwn_node = (u64)shmem_info.fcoe_wwn_node_name_lower | 240057796759SMintz, Yuval (((u64)shmem_info.fcoe_wwn_node_name_upper) << 32); 2401fe56b9e6SYuval Mintz 2402fe56b9e6SYuval Mintz info->ovlan = (u16)(shmem_info.ovlan_stag & FUNC_MF_CFG_OV_STAG_MASK); 2403fe56b9e6SYuval Mintz 24040fefbfbaSSudarsana Kalluru info->mtu = (u16)shmem_info.mtu_size; 24050fefbfbaSSudarsana Kalluru 240614d39648SMintz, Yuval p_hwfn->hw_info.b_wol_support = QED_WOL_SUPPORT_NONE; 240714d39648SMintz, Yuval p_hwfn->cdev->wol_config = (u8)QED_OV_WOL_DEFAULT; 240814d39648SMintz, Yuval if (qed_mcp_is_init(p_hwfn)) { 240914d39648SMintz, Yuval u32 resp = 0, param = 0; 241014d39648SMintz, Yuval int rc; 241114d39648SMintz, Yuval 241214d39648SMintz, Yuval rc = qed_mcp_cmd(p_hwfn, p_ptt, 241314d39648SMintz, Yuval DRV_MSG_CODE_OS_WOL, 0, &resp, ¶m); 241414d39648SMintz, Yuval if (rc) 241514d39648SMintz, Yuval return rc; 241614d39648SMintz, Yuval if (resp == FW_MSG_CODE_OS_WOL_SUPPORTED) 241714d39648SMintz, Yuval p_hwfn->hw_info.b_wol_support = QED_WOL_SUPPORT_PME; 241814d39648SMintz, Yuval } 241914d39648SMintz, Yuval 2420fe56b9e6SYuval Mintz DP_VERBOSE(p_hwfn, (QED_MSG_SP | NETIF_MSG_IFUP), 242114d39648SMintz, Yuval "Read configuration from shmem: pause_on_host %02x protocol %02x BW [%02x - %02x] MAC %02x:%02x:%02x:%02x:%02x:%02x wwn port %llx node %llx ovlan %04x wol %02x\n", 2422fe56b9e6SYuval Mintz info->pause_on_host, info->protocol, 2423fe56b9e6SYuval Mintz info->bandwidth_min, info->bandwidth_max, 2424fe56b9e6SYuval Mintz info->mac[0], info->mac[1], info->mac[2], 2425fe56b9e6SYuval Mintz info->mac[3], info->mac[4], info->mac[5], 242614d39648SMintz, Yuval info->wwn_port, info->wwn_node, 242714d39648SMintz, Yuval info->ovlan, (u8)p_hwfn->hw_info.b_wol_support); 2428fe56b9e6SYuval Mintz 2429fe56b9e6SYuval Mintz return 0; 2430fe56b9e6SYuval Mintz } 2431fe56b9e6SYuval Mintz 2432cc875c2eSYuval Mintz struct qed_mcp_link_params 2433cc875c2eSYuval Mintz *qed_mcp_get_link_params(struct qed_hwfn *p_hwfn) 2434cc875c2eSYuval Mintz { 2435cc875c2eSYuval Mintz if (!p_hwfn || !p_hwfn->mcp_info) 2436cc875c2eSYuval Mintz return NULL; 2437cc875c2eSYuval Mintz return &p_hwfn->mcp_info->link_input; 2438cc875c2eSYuval Mintz } 2439cc875c2eSYuval Mintz 2440cc875c2eSYuval Mintz struct qed_mcp_link_state 2441cc875c2eSYuval Mintz *qed_mcp_get_link_state(struct qed_hwfn *p_hwfn) 2442cc875c2eSYuval Mintz { 2443cc875c2eSYuval Mintz if (!p_hwfn || !p_hwfn->mcp_info) 2444cc875c2eSYuval Mintz return NULL; 2445cc875c2eSYuval Mintz return &p_hwfn->mcp_info->link_output; 2446cc875c2eSYuval Mintz } 2447cc875c2eSYuval Mintz 2448cc875c2eSYuval Mintz struct qed_mcp_link_capabilities 2449cc875c2eSYuval Mintz *qed_mcp_get_link_capabilities(struct qed_hwfn *p_hwfn) 2450cc875c2eSYuval Mintz { 2451cc875c2eSYuval Mintz if (!p_hwfn || !p_hwfn->mcp_info) 2452cc875c2eSYuval Mintz return NULL; 2453cc875c2eSYuval Mintz return &p_hwfn->mcp_info->link_capabilities; 2454cc875c2eSYuval Mintz } 2455cc875c2eSYuval Mintz 24561a635e48SYuval Mintz int qed_mcp_drain(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 2457fe56b9e6SYuval Mintz { 2458fe56b9e6SYuval Mintz u32 resp = 0, param = 0; 2459fe56b9e6SYuval Mintz int rc; 2460fe56b9e6SYuval Mintz 2461fe56b9e6SYuval Mintz rc = qed_mcp_cmd(p_hwfn, p_ptt, 24621a635e48SYuval Mintz DRV_MSG_CODE_NIG_DRAIN, 1000, &resp, ¶m); 2463fe56b9e6SYuval Mintz 2464fe56b9e6SYuval Mintz /* Wait for the drain to complete before returning */ 24658f60bafeSYuval Mintz msleep(1020); 2466fe56b9e6SYuval Mintz 2467fe56b9e6SYuval Mintz return rc; 2468fe56b9e6SYuval Mintz } 2469fe56b9e6SYuval Mintz 2470cee4d264SManish Chopra int qed_mcp_get_flash_size(struct qed_hwfn *p_hwfn, 24711a635e48SYuval Mintz struct qed_ptt *p_ptt, u32 *p_flash_size) 2472cee4d264SManish Chopra { 2473cee4d264SManish Chopra u32 flash_size; 2474cee4d264SManish Chopra 24751408cc1fSYuval Mintz if (IS_VF(p_hwfn->cdev)) 24761408cc1fSYuval Mintz return -EINVAL; 24771408cc1fSYuval Mintz 2478cee4d264SManish Chopra flash_size = qed_rd(p_hwfn, p_ptt, MCP_REG_NVM_CFG4); 2479cee4d264SManish Chopra flash_size = (flash_size & MCP_REG_NVM_CFG4_FLASH_SIZE) >> 2480cee4d264SManish Chopra MCP_REG_NVM_CFG4_FLASH_SIZE_SHIFT; 2481cee4d264SManish Chopra flash_size = (1 << (flash_size + MCP_BYTES_PER_MBIT_SHIFT)); 2482cee4d264SManish Chopra 2483cee4d264SManish Chopra *p_flash_size = flash_size; 2484cee4d264SManish Chopra 2485cee4d264SManish Chopra return 0; 2486cee4d264SManish Chopra } 2487cee4d264SManish Chopra 248864515dc8STomer Tayar int qed_start_recovery_process(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 248964515dc8STomer Tayar { 249064515dc8STomer Tayar struct qed_dev *cdev = p_hwfn->cdev; 249164515dc8STomer Tayar 249264515dc8STomer Tayar if (cdev->recov_in_prog) { 249364515dc8STomer Tayar DP_NOTICE(p_hwfn, 249464515dc8STomer Tayar "Avoid triggering a recovery since such a process is already in progress\n"); 249564515dc8STomer Tayar return -EAGAIN; 249664515dc8STomer Tayar } 249764515dc8STomer Tayar 249864515dc8STomer Tayar DP_NOTICE(p_hwfn, "Triggering a recovery process\n"); 249964515dc8STomer Tayar qed_wr(p_hwfn, p_ptt, MISC_REG_AEU_GENERAL_ATTN_35, 0x1); 250064515dc8STomer Tayar 250164515dc8STomer Tayar return 0; 250264515dc8STomer Tayar } 250364515dc8STomer Tayar 250464515dc8STomer Tayar #define QED_RECOVERY_PROLOG_SLEEP_MS 100 250564515dc8STomer Tayar 250664515dc8STomer Tayar int qed_recovery_prolog(struct qed_dev *cdev) 250764515dc8STomer Tayar { 250864515dc8STomer Tayar struct qed_hwfn *p_hwfn = QED_LEADING_HWFN(cdev); 250964515dc8STomer Tayar struct qed_ptt *p_ptt = p_hwfn->p_main_ptt; 251064515dc8STomer Tayar int rc; 251164515dc8STomer Tayar 251264515dc8STomer Tayar /* Allow ongoing PCIe transactions to complete */ 251364515dc8STomer Tayar msleep(QED_RECOVERY_PROLOG_SLEEP_MS); 251464515dc8STomer Tayar 251564515dc8STomer Tayar /* Clear the PF's internal FID_enable in the PXP */ 251664515dc8STomer Tayar rc = qed_pglueb_set_pfid_enable(p_hwfn, p_ptt, false); 251764515dc8STomer Tayar if (rc) 251864515dc8STomer Tayar DP_NOTICE(p_hwfn, 251964515dc8STomer Tayar "qed_pglueb_set_pfid_enable() failed. rc = %d.\n", 252064515dc8STomer Tayar rc); 252164515dc8STomer Tayar 252264515dc8STomer Tayar return rc; 252364515dc8STomer Tayar } 252464515dc8STomer Tayar 252588072fd4SMintz, Yuval static int 252688072fd4SMintz, Yuval qed_mcp_config_vf_msix_bb(struct qed_hwfn *p_hwfn, 25271408cc1fSYuval Mintz struct qed_ptt *p_ptt, u8 vf_id, u8 num) 25281408cc1fSYuval Mintz { 25291408cc1fSYuval Mintz u32 resp = 0, param = 0, rc_param = 0; 25301408cc1fSYuval Mintz int rc; 25311408cc1fSYuval Mintz 25321408cc1fSYuval Mintz /* Only Leader can configure MSIX, and need to take CMT into account */ 25331408cc1fSYuval Mintz if (!IS_LEAD_HWFN(p_hwfn)) 25341408cc1fSYuval Mintz return 0; 25351408cc1fSYuval Mintz num *= p_hwfn->cdev->num_hwfns; 25361408cc1fSYuval Mintz 25371408cc1fSYuval Mintz param |= (vf_id << DRV_MB_PARAM_CFG_VF_MSIX_VF_ID_SHIFT) & 25381408cc1fSYuval Mintz DRV_MB_PARAM_CFG_VF_MSIX_VF_ID_MASK; 25391408cc1fSYuval Mintz param |= (num << DRV_MB_PARAM_CFG_VF_MSIX_SB_NUM_SHIFT) & 25401408cc1fSYuval Mintz DRV_MB_PARAM_CFG_VF_MSIX_SB_NUM_MASK; 25411408cc1fSYuval Mintz 25421408cc1fSYuval Mintz rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_CFG_VF_MSIX, param, 25431408cc1fSYuval Mintz &resp, &rc_param); 25441408cc1fSYuval Mintz 25451408cc1fSYuval Mintz if (resp != FW_MSG_CODE_DRV_CFG_VF_MSIX_DONE) { 25461408cc1fSYuval Mintz DP_NOTICE(p_hwfn, "VF[%d]: MFW failed to set MSI-X\n", vf_id); 25471408cc1fSYuval Mintz rc = -EINVAL; 25481408cc1fSYuval Mintz } else { 25491408cc1fSYuval Mintz DP_VERBOSE(p_hwfn, QED_MSG_IOV, 25501408cc1fSYuval Mintz "Requested 0x%02x MSI-x interrupts from VF 0x%02x\n", 25511408cc1fSYuval Mintz num, vf_id); 25521408cc1fSYuval Mintz } 25531408cc1fSYuval Mintz 25541408cc1fSYuval Mintz return rc; 25551408cc1fSYuval Mintz } 25561408cc1fSYuval Mintz 255788072fd4SMintz, Yuval static int 255888072fd4SMintz, Yuval qed_mcp_config_vf_msix_ah(struct qed_hwfn *p_hwfn, 255988072fd4SMintz, Yuval struct qed_ptt *p_ptt, u8 num) 256088072fd4SMintz, Yuval { 256188072fd4SMintz, Yuval u32 resp = 0, param = num, rc_param = 0; 256288072fd4SMintz, Yuval int rc; 256388072fd4SMintz, Yuval 256488072fd4SMintz, Yuval rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_CFG_PF_VFS_MSIX, 256588072fd4SMintz, Yuval param, &resp, &rc_param); 256688072fd4SMintz, Yuval 256788072fd4SMintz, Yuval if (resp != FW_MSG_CODE_DRV_CFG_PF_VFS_MSIX_DONE) { 256888072fd4SMintz, Yuval DP_NOTICE(p_hwfn, "MFW failed to set MSI-X for VFs\n"); 256988072fd4SMintz, Yuval rc = -EINVAL; 257088072fd4SMintz, Yuval } else { 257188072fd4SMintz, Yuval DP_VERBOSE(p_hwfn, QED_MSG_IOV, 257288072fd4SMintz, Yuval "Requested 0x%02x MSI-x interrupts for VFs\n", num); 257388072fd4SMintz, Yuval } 257488072fd4SMintz, Yuval 257588072fd4SMintz, Yuval return rc; 257688072fd4SMintz, Yuval } 257788072fd4SMintz, Yuval 257888072fd4SMintz, Yuval int qed_mcp_config_vf_msix(struct qed_hwfn *p_hwfn, 257988072fd4SMintz, Yuval struct qed_ptt *p_ptt, u8 vf_id, u8 num) 258088072fd4SMintz, Yuval { 258188072fd4SMintz, Yuval if (QED_IS_BB(p_hwfn->cdev)) 258288072fd4SMintz, Yuval return qed_mcp_config_vf_msix_bb(p_hwfn, p_ptt, vf_id, num); 258388072fd4SMintz, Yuval else 258488072fd4SMintz, Yuval return qed_mcp_config_vf_msix_ah(p_hwfn, p_ptt, num); 258588072fd4SMintz, Yuval } 258688072fd4SMintz, Yuval 2587fe56b9e6SYuval Mintz int 2588fe56b9e6SYuval Mintz qed_mcp_send_drv_version(struct qed_hwfn *p_hwfn, 2589fe56b9e6SYuval Mintz struct qed_ptt *p_ptt, 2590fe56b9e6SYuval Mintz struct qed_mcp_drv_version *p_ver) 2591fe56b9e6SYuval Mintz { 25925529bad9STomer Tayar struct qed_mcp_mb_params mb_params; 25932f67af8cSTomer Tayar struct drv_version_stc drv_version; 25945529bad9STomer Tayar __be32 val; 25955529bad9STomer Tayar u32 i; 25965529bad9STomer Tayar int rc; 2597fe56b9e6SYuval Mintz 25982f67af8cSTomer Tayar memset(&drv_version, 0, sizeof(drv_version)); 25992f67af8cSTomer Tayar drv_version.version = p_ver->version; 260067a99b70SYuval Mintz for (i = 0; i < (MCP_DRV_VER_STR_SIZE - 4) / sizeof(u32); i++) { 260167a99b70SYuval Mintz val = cpu_to_be32(*((u32 *)&p_ver->name[i * sizeof(u32)])); 26022f67af8cSTomer Tayar *(__be32 *)&drv_version.name[i * sizeof(u32)] = val; 2603fe56b9e6SYuval Mintz } 2604fe56b9e6SYuval Mintz 26055529bad9STomer Tayar memset(&mb_params, 0, sizeof(mb_params)); 26065529bad9STomer Tayar mb_params.cmd = DRV_MSG_CODE_SET_VERSION; 26072f67af8cSTomer Tayar mb_params.p_data_src = &drv_version; 26082f67af8cSTomer Tayar mb_params.data_src_size = sizeof(drv_version); 26095529bad9STomer Tayar rc = qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 26105529bad9STomer Tayar if (rc) 2611fe56b9e6SYuval Mintz DP_ERR(p_hwfn, "MCP response failure, aborting\n"); 2612fe56b9e6SYuval Mintz 26135529bad9STomer Tayar return rc; 2614fe56b9e6SYuval Mintz } 261591420b83SSudarsana Kalluru 261676271809STomer Tayar /* A maximal 100 msec waiting time for the MCP to halt */ 261776271809STomer Tayar #define QED_MCP_HALT_SLEEP_MS 10 261876271809STomer Tayar #define QED_MCP_HALT_MAX_RETRIES 10 261976271809STomer Tayar 26204102426fSTomer Tayar int qed_mcp_halt(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 26214102426fSTomer Tayar { 262276271809STomer Tayar u32 resp = 0, param = 0, cpu_state, cnt = 0; 26234102426fSTomer Tayar int rc; 26244102426fSTomer Tayar 26254102426fSTomer Tayar rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_MCP_HALT, 0, &resp, 26264102426fSTomer Tayar ¶m); 262776271809STomer Tayar if (rc) { 26284102426fSTomer Tayar DP_ERR(p_hwfn, "MCP response failure, aborting\n"); 26294102426fSTomer Tayar return rc; 26304102426fSTomer Tayar } 26314102426fSTomer Tayar 263276271809STomer Tayar do { 263376271809STomer Tayar msleep(QED_MCP_HALT_SLEEP_MS); 263476271809STomer Tayar cpu_state = qed_rd(p_hwfn, p_ptt, MCP_REG_CPU_STATE); 263576271809STomer Tayar if (cpu_state & MCP_REG_CPU_STATE_SOFT_HALTED) 263676271809STomer Tayar break; 263776271809STomer Tayar } while (++cnt < QED_MCP_HALT_MAX_RETRIES); 263876271809STomer Tayar 263976271809STomer Tayar if (cnt == QED_MCP_HALT_MAX_RETRIES) { 264076271809STomer Tayar DP_NOTICE(p_hwfn, 264176271809STomer Tayar "Failed to halt the MCP [CPU_MODE = 0x%08x, CPU_STATE = 0x%08x]\n", 264276271809STomer Tayar qed_rd(p_hwfn, p_ptt, MCP_REG_CPU_MODE), cpu_state); 264376271809STomer Tayar return -EBUSY; 264476271809STomer Tayar } 264576271809STomer Tayar 2646b310974eSTomer Tayar qed_mcp_cmd_set_blocking(p_hwfn, true); 2647b310974eSTomer Tayar 264876271809STomer Tayar return 0; 264976271809STomer Tayar } 265076271809STomer Tayar 265176271809STomer Tayar #define QED_MCP_RESUME_SLEEP_MS 10 265276271809STomer Tayar 26534102426fSTomer Tayar int qed_mcp_resume(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 26544102426fSTomer Tayar { 265576271809STomer Tayar u32 cpu_mode, cpu_state; 26564102426fSTomer Tayar 26574102426fSTomer Tayar qed_wr(p_hwfn, p_ptt, MCP_REG_CPU_STATE, 0xffffffff); 26584102426fSTomer Tayar 26594102426fSTomer Tayar cpu_mode = qed_rd(p_hwfn, p_ptt, MCP_REG_CPU_MODE); 266076271809STomer Tayar cpu_mode &= ~MCP_REG_CPU_MODE_SOFT_HALT; 266176271809STomer Tayar qed_wr(p_hwfn, p_ptt, MCP_REG_CPU_MODE, cpu_mode); 266276271809STomer Tayar msleep(QED_MCP_RESUME_SLEEP_MS); 266376271809STomer Tayar cpu_state = qed_rd(p_hwfn, p_ptt, MCP_REG_CPU_STATE); 26644102426fSTomer Tayar 266576271809STomer Tayar if (cpu_state & MCP_REG_CPU_STATE_SOFT_HALTED) { 266676271809STomer Tayar DP_NOTICE(p_hwfn, 266776271809STomer Tayar "Failed to resume the MCP [CPU_MODE = 0x%08x, CPU_STATE = 0x%08x]\n", 266876271809STomer Tayar cpu_mode, cpu_state); 266976271809STomer Tayar return -EBUSY; 267076271809STomer Tayar } 267176271809STomer Tayar 2672b310974eSTomer Tayar qed_mcp_cmd_set_blocking(p_hwfn, false); 2673b310974eSTomer Tayar 267476271809STomer Tayar return 0; 26754102426fSTomer Tayar } 26764102426fSTomer Tayar 26770fefbfbaSSudarsana Kalluru int qed_mcp_ov_update_current_config(struct qed_hwfn *p_hwfn, 26780fefbfbaSSudarsana Kalluru struct qed_ptt *p_ptt, 26790fefbfbaSSudarsana Kalluru enum qed_ov_client client) 26800fefbfbaSSudarsana Kalluru { 26810fefbfbaSSudarsana Kalluru u32 resp = 0, param = 0; 26820fefbfbaSSudarsana Kalluru u32 drv_mb_param; 26830fefbfbaSSudarsana Kalluru int rc; 26840fefbfbaSSudarsana Kalluru 26850fefbfbaSSudarsana Kalluru switch (client) { 26860fefbfbaSSudarsana Kalluru case QED_OV_CLIENT_DRV: 26870fefbfbaSSudarsana Kalluru drv_mb_param = DRV_MB_PARAM_OV_CURR_CFG_OS; 26880fefbfbaSSudarsana Kalluru break; 26890fefbfbaSSudarsana Kalluru case QED_OV_CLIENT_USER: 26900fefbfbaSSudarsana Kalluru drv_mb_param = DRV_MB_PARAM_OV_CURR_CFG_OTHER; 26910fefbfbaSSudarsana Kalluru break; 26920fefbfbaSSudarsana Kalluru case QED_OV_CLIENT_VENDOR_SPEC: 26930fefbfbaSSudarsana Kalluru drv_mb_param = DRV_MB_PARAM_OV_CURR_CFG_VENDOR_SPEC; 26940fefbfbaSSudarsana Kalluru break; 26950fefbfbaSSudarsana Kalluru default: 26960fefbfbaSSudarsana Kalluru DP_NOTICE(p_hwfn, "Invalid client type %d\n", client); 26970fefbfbaSSudarsana Kalluru return -EINVAL; 26980fefbfbaSSudarsana Kalluru } 26990fefbfbaSSudarsana Kalluru 27000fefbfbaSSudarsana Kalluru rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_OV_UPDATE_CURR_CFG, 27010fefbfbaSSudarsana Kalluru drv_mb_param, &resp, ¶m); 27020fefbfbaSSudarsana Kalluru if (rc) 27030fefbfbaSSudarsana Kalluru DP_ERR(p_hwfn, "MCP response failure, aborting\n"); 27040fefbfbaSSudarsana Kalluru 27050fefbfbaSSudarsana Kalluru return rc; 27060fefbfbaSSudarsana Kalluru } 27070fefbfbaSSudarsana Kalluru 27080fefbfbaSSudarsana Kalluru int qed_mcp_ov_update_driver_state(struct qed_hwfn *p_hwfn, 27090fefbfbaSSudarsana Kalluru struct qed_ptt *p_ptt, 27100fefbfbaSSudarsana Kalluru enum qed_ov_driver_state drv_state) 27110fefbfbaSSudarsana Kalluru { 27120fefbfbaSSudarsana Kalluru u32 resp = 0, param = 0; 27130fefbfbaSSudarsana Kalluru u32 drv_mb_param; 27140fefbfbaSSudarsana Kalluru int rc; 27150fefbfbaSSudarsana Kalluru 27160fefbfbaSSudarsana Kalluru switch (drv_state) { 27170fefbfbaSSudarsana Kalluru case QED_OV_DRIVER_STATE_NOT_LOADED: 27180fefbfbaSSudarsana Kalluru drv_mb_param = DRV_MSG_CODE_OV_UPDATE_DRIVER_STATE_NOT_LOADED; 27190fefbfbaSSudarsana Kalluru break; 27200fefbfbaSSudarsana Kalluru case QED_OV_DRIVER_STATE_DISABLED: 27210fefbfbaSSudarsana Kalluru drv_mb_param = DRV_MSG_CODE_OV_UPDATE_DRIVER_STATE_DISABLED; 27220fefbfbaSSudarsana Kalluru break; 27230fefbfbaSSudarsana Kalluru case QED_OV_DRIVER_STATE_ACTIVE: 27240fefbfbaSSudarsana Kalluru drv_mb_param = DRV_MSG_CODE_OV_UPDATE_DRIVER_STATE_ACTIVE; 27250fefbfbaSSudarsana Kalluru break; 27260fefbfbaSSudarsana Kalluru default: 27270fefbfbaSSudarsana Kalluru DP_NOTICE(p_hwfn, "Invalid driver state %d\n", drv_state); 27280fefbfbaSSudarsana Kalluru return -EINVAL; 27290fefbfbaSSudarsana Kalluru } 27300fefbfbaSSudarsana Kalluru 27310fefbfbaSSudarsana Kalluru rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_OV_UPDATE_DRIVER_STATE, 27320fefbfbaSSudarsana Kalluru drv_mb_param, &resp, ¶m); 27330fefbfbaSSudarsana Kalluru if (rc) 27340fefbfbaSSudarsana Kalluru DP_ERR(p_hwfn, "Failed to send driver state\n"); 27350fefbfbaSSudarsana Kalluru 27360fefbfbaSSudarsana Kalluru return rc; 27370fefbfbaSSudarsana Kalluru } 27380fefbfbaSSudarsana Kalluru 27390fefbfbaSSudarsana Kalluru int qed_mcp_ov_update_mtu(struct qed_hwfn *p_hwfn, 27400fefbfbaSSudarsana Kalluru struct qed_ptt *p_ptt, u16 mtu) 27410fefbfbaSSudarsana Kalluru { 27420fefbfbaSSudarsana Kalluru u32 resp = 0, param = 0; 27430fefbfbaSSudarsana Kalluru u32 drv_mb_param; 27440fefbfbaSSudarsana Kalluru int rc; 27450fefbfbaSSudarsana Kalluru 27460fefbfbaSSudarsana Kalluru drv_mb_param = (u32)mtu << DRV_MB_PARAM_OV_MTU_SIZE_SHIFT; 27470fefbfbaSSudarsana Kalluru rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_OV_UPDATE_MTU, 27480fefbfbaSSudarsana Kalluru drv_mb_param, &resp, ¶m); 27490fefbfbaSSudarsana Kalluru if (rc) 27500fefbfbaSSudarsana Kalluru DP_ERR(p_hwfn, "Failed to send mtu value, rc = %d\n", rc); 27510fefbfbaSSudarsana Kalluru 27520fefbfbaSSudarsana Kalluru return rc; 27530fefbfbaSSudarsana Kalluru } 27540fefbfbaSSudarsana Kalluru 27550fefbfbaSSudarsana Kalluru int qed_mcp_ov_update_mac(struct qed_hwfn *p_hwfn, 27560fefbfbaSSudarsana Kalluru struct qed_ptt *p_ptt, u8 *mac) 27570fefbfbaSSudarsana Kalluru { 27580fefbfbaSSudarsana Kalluru struct qed_mcp_mb_params mb_params; 275917991002SMintz, Yuval u32 mfw_mac[2]; 27600fefbfbaSSudarsana Kalluru int rc; 27610fefbfbaSSudarsana Kalluru 27620fefbfbaSSudarsana Kalluru memset(&mb_params, 0, sizeof(mb_params)); 27630fefbfbaSSudarsana Kalluru mb_params.cmd = DRV_MSG_CODE_SET_VMAC; 27640fefbfbaSSudarsana Kalluru mb_params.param = DRV_MSG_CODE_VMAC_TYPE_MAC << 27650fefbfbaSSudarsana Kalluru DRV_MSG_CODE_VMAC_TYPE_SHIFT; 27660fefbfbaSSudarsana Kalluru mb_params.param |= MCP_PF_ID(p_hwfn); 27672f67af8cSTomer Tayar 276817991002SMintz, Yuval /* MCP is BE, and on LE platforms PCI would swap access to SHMEM 276917991002SMintz, Yuval * in 32-bit granularity. 277017991002SMintz, Yuval * So the MAC has to be set in native order [and not byte order], 277117991002SMintz, Yuval * otherwise it would be read incorrectly by MFW after swap. 277217991002SMintz, Yuval */ 277317991002SMintz, Yuval mfw_mac[0] = mac[0] << 24 | mac[1] << 16 | mac[2] << 8 | mac[3]; 277417991002SMintz, Yuval mfw_mac[1] = mac[4] << 24 | mac[5] << 16; 277517991002SMintz, Yuval 277617991002SMintz, Yuval mb_params.p_data_src = (u8 *)mfw_mac; 277717991002SMintz, Yuval mb_params.data_src_size = 8; 27780fefbfbaSSudarsana Kalluru rc = qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 27790fefbfbaSSudarsana Kalluru if (rc) 27800fefbfbaSSudarsana Kalluru DP_ERR(p_hwfn, "Failed to send mac address, rc = %d\n", rc); 27810fefbfbaSSudarsana Kalluru 278214d39648SMintz, Yuval /* Store primary MAC for later possible WoL */ 278314d39648SMintz, Yuval memcpy(p_hwfn->cdev->wol_mac, mac, ETH_ALEN); 278414d39648SMintz, Yuval 27850fefbfbaSSudarsana Kalluru return rc; 27860fefbfbaSSudarsana Kalluru } 27870fefbfbaSSudarsana Kalluru 27880fefbfbaSSudarsana Kalluru int qed_mcp_ov_update_wol(struct qed_hwfn *p_hwfn, 27890fefbfbaSSudarsana Kalluru struct qed_ptt *p_ptt, enum qed_ov_wol wol) 27900fefbfbaSSudarsana Kalluru { 27910fefbfbaSSudarsana Kalluru u32 resp = 0, param = 0; 27920fefbfbaSSudarsana Kalluru u32 drv_mb_param; 27930fefbfbaSSudarsana Kalluru int rc; 27940fefbfbaSSudarsana Kalluru 279514d39648SMintz, Yuval if (p_hwfn->hw_info.b_wol_support == QED_WOL_SUPPORT_NONE) { 279614d39648SMintz, Yuval DP_VERBOSE(p_hwfn, QED_MSG_SP, 279714d39648SMintz, Yuval "Can't change WoL configuration when WoL isn't supported\n"); 279814d39648SMintz, Yuval return -EINVAL; 279914d39648SMintz, Yuval } 280014d39648SMintz, Yuval 28010fefbfbaSSudarsana Kalluru switch (wol) { 28020fefbfbaSSudarsana Kalluru case QED_OV_WOL_DEFAULT: 28030fefbfbaSSudarsana Kalluru drv_mb_param = DRV_MB_PARAM_WOL_DEFAULT; 28040fefbfbaSSudarsana Kalluru break; 28050fefbfbaSSudarsana Kalluru case QED_OV_WOL_DISABLED: 28060fefbfbaSSudarsana Kalluru drv_mb_param = DRV_MB_PARAM_WOL_DISABLED; 28070fefbfbaSSudarsana Kalluru break; 28080fefbfbaSSudarsana Kalluru case QED_OV_WOL_ENABLED: 28090fefbfbaSSudarsana Kalluru drv_mb_param = DRV_MB_PARAM_WOL_ENABLED; 28100fefbfbaSSudarsana Kalluru break; 28110fefbfbaSSudarsana Kalluru default: 28120fefbfbaSSudarsana Kalluru DP_ERR(p_hwfn, "Invalid wol state %d\n", wol); 28130fefbfbaSSudarsana Kalluru return -EINVAL; 28140fefbfbaSSudarsana Kalluru } 28150fefbfbaSSudarsana Kalluru 28160fefbfbaSSudarsana Kalluru rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_OV_UPDATE_WOL, 28170fefbfbaSSudarsana Kalluru drv_mb_param, &resp, ¶m); 28180fefbfbaSSudarsana Kalluru if (rc) 28190fefbfbaSSudarsana Kalluru DP_ERR(p_hwfn, "Failed to send wol mode, rc = %d\n", rc); 28200fefbfbaSSudarsana Kalluru 282114d39648SMintz, Yuval /* Store the WoL update for a future unload */ 282214d39648SMintz, Yuval p_hwfn->cdev->wol_config = (u8)wol; 282314d39648SMintz, Yuval 28240fefbfbaSSudarsana Kalluru return rc; 28250fefbfbaSSudarsana Kalluru } 28260fefbfbaSSudarsana Kalluru 28270fefbfbaSSudarsana Kalluru int qed_mcp_ov_update_eswitch(struct qed_hwfn *p_hwfn, 28280fefbfbaSSudarsana Kalluru struct qed_ptt *p_ptt, 28290fefbfbaSSudarsana Kalluru enum qed_ov_eswitch eswitch) 28300fefbfbaSSudarsana Kalluru { 28310fefbfbaSSudarsana Kalluru u32 resp = 0, param = 0; 28320fefbfbaSSudarsana Kalluru u32 drv_mb_param; 28330fefbfbaSSudarsana Kalluru int rc; 28340fefbfbaSSudarsana Kalluru 28350fefbfbaSSudarsana Kalluru switch (eswitch) { 28360fefbfbaSSudarsana Kalluru case QED_OV_ESWITCH_NONE: 28370fefbfbaSSudarsana Kalluru drv_mb_param = DRV_MB_PARAM_ESWITCH_MODE_NONE; 28380fefbfbaSSudarsana Kalluru break; 28390fefbfbaSSudarsana Kalluru case QED_OV_ESWITCH_VEB: 28400fefbfbaSSudarsana Kalluru drv_mb_param = DRV_MB_PARAM_ESWITCH_MODE_VEB; 28410fefbfbaSSudarsana Kalluru break; 28420fefbfbaSSudarsana Kalluru case QED_OV_ESWITCH_VEPA: 28430fefbfbaSSudarsana Kalluru drv_mb_param = DRV_MB_PARAM_ESWITCH_MODE_VEPA; 28440fefbfbaSSudarsana Kalluru break; 28450fefbfbaSSudarsana Kalluru default: 28460fefbfbaSSudarsana Kalluru DP_ERR(p_hwfn, "Invalid eswitch mode %d\n", eswitch); 28470fefbfbaSSudarsana Kalluru return -EINVAL; 28480fefbfbaSSudarsana Kalluru } 28490fefbfbaSSudarsana Kalluru 28500fefbfbaSSudarsana Kalluru rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_OV_UPDATE_ESWITCH_MODE, 28510fefbfbaSSudarsana Kalluru drv_mb_param, &resp, ¶m); 28520fefbfbaSSudarsana Kalluru if (rc) 28530fefbfbaSSudarsana Kalluru DP_ERR(p_hwfn, "Failed to send eswitch mode, rc = %d\n", rc); 28540fefbfbaSSudarsana Kalluru 28550fefbfbaSSudarsana Kalluru return rc; 28560fefbfbaSSudarsana Kalluru } 28570fefbfbaSSudarsana Kalluru 28581a635e48SYuval Mintz int qed_mcp_set_led(struct qed_hwfn *p_hwfn, 28591a635e48SYuval Mintz struct qed_ptt *p_ptt, enum qed_led_mode mode) 286091420b83SSudarsana Kalluru { 286191420b83SSudarsana Kalluru u32 resp = 0, param = 0, drv_mb_param; 286291420b83SSudarsana Kalluru int rc; 286391420b83SSudarsana Kalluru 286491420b83SSudarsana Kalluru switch (mode) { 286591420b83SSudarsana Kalluru case QED_LED_MODE_ON: 286691420b83SSudarsana Kalluru drv_mb_param = DRV_MB_PARAM_SET_LED_MODE_ON; 286791420b83SSudarsana Kalluru break; 286891420b83SSudarsana Kalluru case QED_LED_MODE_OFF: 286991420b83SSudarsana Kalluru drv_mb_param = DRV_MB_PARAM_SET_LED_MODE_OFF; 287091420b83SSudarsana Kalluru break; 287191420b83SSudarsana Kalluru case QED_LED_MODE_RESTORE: 287291420b83SSudarsana Kalluru drv_mb_param = DRV_MB_PARAM_SET_LED_MODE_OPER; 287391420b83SSudarsana Kalluru break; 287491420b83SSudarsana Kalluru default: 287591420b83SSudarsana Kalluru DP_NOTICE(p_hwfn, "Invalid LED mode %d\n", mode); 287691420b83SSudarsana Kalluru return -EINVAL; 287791420b83SSudarsana Kalluru } 287891420b83SSudarsana Kalluru 287991420b83SSudarsana Kalluru rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_SET_LED_MODE, 288091420b83SSudarsana Kalluru drv_mb_param, &resp, ¶m); 288191420b83SSudarsana Kalluru 288291420b83SSudarsana Kalluru return rc; 288391420b83SSudarsana Kalluru } 288403dc76caSSudarsana Reddy Kalluru 28854102426fSTomer Tayar int qed_mcp_mask_parities(struct qed_hwfn *p_hwfn, 28864102426fSTomer Tayar struct qed_ptt *p_ptt, u32 mask_parities) 28874102426fSTomer Tayar { 28884102426fSTomer Tayar u32 resp = 0, param = 0; 28894102426fSTomer Tayar int rc; 28904102426fSTomer Tayar 28914102426fSTomer Tayar rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_MASK_PARITIES, 28924102426fSTomer Tayar mask_parities, &resp, ¶m); 28934102426fSTomer Tayar 28944102426fSTomer Tayar if (rc) { 28954102426fSTomer Tayar DP_ERR(p_hwfn, 28964102426fSTomer Tayar "MCP response failure for mask parities, aborting\n"); 28974102426fSTomer Tayar } else if (resp != FW_MSG_CODE_OK) { 28984102426fSTomer Tayar DP_ERR(p_hwfn, 28994102426fSTomer Tayar "MCP did not acknowledge mask parity request. Old MFW?\n"); 29004102426fSTomer Tayar rc = -EINVAL; 29014102426fSTomer Tayar } 29024102426fSTomer Tayar 29034102426fSTomer Tayar return rc; 29044102426fSTomer Tayar } 29054102426fSTomer Tayar 29067a4b21b7SMintz, Yuval int qed_mcp_nvm_read(struct qed_dev *cdev, u32 addr, u8 *p_buf, u32 len) 29077a4b21b7SMintz, Yuval { 29087a4b21b7SMintz, Yuval u32 bytes_left = len, offset = 0, bytes_to_copy, read_len = 0; 29097a4b21b7SMintz, Yuval struct qed_hwfn *p_hwfn = QED_LEADING_HWFN(cdev); 29107a4b21b7SMintz, Yuval u32 resp = 0, resp_param = 0; 29117a4b21b7SMintz, Yuval struct qed_ptt *p_ptt; 29127a4b21b7SMintz, Yuval int rc = 0; 29137a4b21b7SMintz, Yuval 29147a4b21b7SMintz, Yuval p_ptt = qed_ptt_acquire(p_hwfn); 29157a4b21b7SMintz, Yuval if (!p_ptt) 29167a4b21b7SMintz, Yuval return -EBUSY; 29177a4b21b7SMintz, Yuval 29187a4b21b7SMintz, Yuval while (bytes_left > 0) { 29197a4b21b7SMintz, Yuval bytes_to_copy = min_t(u32, bytes_left, MCP_DRV_NVM_BUF_LEN); 29207a4b21b7SMintz, Yuval 29217a4b21b7SMintz, Yuval rc = qed_mcp_nvm_rd_cmd(p_hwfn, p_ptt, 29227a4b21b7SMintz, Yuval DRV_MSG_CODE_NVM_READ_NVRAM, 29237a4b21b7SMintz, Yuval addr + offset + 29247a4b21b7SMintz, Yuval (bytes_to_copy << 2925da090917STomer Tayar DRV_MB_PARAM_NVM_LEN_OFFSET), 29267a4b21b7SMintz, Yuval &resp, &resp_param, 29277a4b21b7SMintz, Yuval &read_len, 29287a4b21b7SMintz, Yuval (u32 *)(p_buf + offset)); 29297a4b21b7SMintz, Yuval 29307a4b21b7SMintz, Yuval if (rc || (resp != FW_MSG_CODE_NVM_OK)) { 29317a4b21b7SMintz, Yuval DP_NOTICE(cdev, "MCP command rc = %d\n", rc); 29327a4b21b7SMintz, Yuval break; 29337a4b21b7SMintz, Yuval } 29347a4b21b7SMintz, Yuval 29357a4b21b7SMintz, Yuval /* This can be a lengthy process, and it's possible scheduler 29367a4b21b7SMintz, Yuval * isn't preemptable. Sleep a bit to prevent CPU hogging. 29377a4b21b7SMintz, Yuval */ 29387a4b21b7SMintz, Yuval if (bytes_left % 0x1000 < 29397a4b21b7SMintz, Yuval (bytes_left - read_len) % 0x1000) 29407a4b21b7SMintz, Yuval usleep_range(1000, 2000); 29417a4b21b7SMintz, Yuval 29427a4b21b7SMintz, Yuval offset += read_len; 29437a4b21b7SMintz, Yuval bytes_left -= read_len; 29447a4b21b7SMintz, Yuval } 29457a4b21b7SMintz, Yuval 29467a4b21b7SMintz, Yuval cdev->mcp_nvm_resp = resp; 29477a4b21b7SMintz, Yuval qed_ptt_release(p_hwfn, p_ptt); 29487a4b21b7SMintz, Yuval 29497a4b21b7SMintz, Yuval return rc; 29507a4b21b7SMintz, Yuval } 29517a4b21b7SMintz, Yuval 295262e4d438SSudarsana Reddy Kalluru int qed_mcp_nvm_resp(struct qed_dev *cdev, u8 *p_buf) 295362e4d438SSudarsana Reddy Kalluru { 295462e4d438SSudarsana Reddy Kalluru struct qed_hwfn *p_hwfn = QED_LEADING_HWFN(cdev); 295562e4d438SSudarsana Reddy Kalluru struct qed_ptt *p_ptt; 295662e4d438SSudarsana Reddy Kalluru 295762e4d438SSudarsana Reddy Kalluru p_ptt = qed_ptt_acquire(p_hwfn); 295862e4d438SSudarsana Reddy Kalluru if (!p_ptt) 295962e4d438SSudarsana Reddy Kalluru return -EBUSY; 296062e4d438SSudarsana Reddy Kalluru 296162e4d438SSudarsana Reddy Kalluru memcpy(p_buf, &cdev->mcp_nvm_resp, sizeof(cdev->mcp_nvm_resp)); 296262e4d438SSudarsana Reddy Kalluru qed_ptt_release(p_hwfn, p_ptt); 296362e4d438SSudarsana Reddy Kalluru 296462e4d438SSudarsana Reddy Kalluru return 0; 296562e4d438SSudarsana Reddy Kalluru } 296662e4d438SSudarsana Reddy Kalluru 296762e4d438SSudarsana Reddy Kalluru int qed_mcp_nvm_write(struct qed_dev *cdev, 296862e4d438SSudarsana Reddy Kalluru u32 cmd, u32 addr, u8 *p_buf, u32 len) 296962e4d438SSudarsana Reddy Kalluru { 297062e4d438SSudarsana Reddy Kalluru u32 buf_idx = 0, buf_size, nvm_cmd, nvm_offset, resp = 0, param; 297162e4d438SSudarsana Reddy Kalluru struct qed_hwfn *p_hwfn = QED_LEADING_HWFN(cdev); 297262e4d438SSudarsana Reddy Kalluru struct qed_ptt *p_ptt; 297362e4d438SSudarsana Reddy Kalluru int rc = -EINVAL; 297462e4d438SSudarsana Reddy Kalluru 297562e4d438SSudarsana Reddy Kalluru p_ptt = qed_ptt_acquire(p_hwfn); 297662e4d438SSudarsana Reddy Kalluru if (!p_ptt) 297762e4d438SSudarsana Reddy Kalluru return -EBUSY; 297862e4d438SSudarsana Reddy Kalluru 297962e4d438SSudarsana Reddy Kalluru switch (cmd) { 2980057d2b19SSudarsana Reddy Kalluru case QED_PUT_FILE_BEGIN: 2981057d2b19SSudarsana Reddy Kalluru nvm_cmd = DRV_MSG_CODE_NVM_PUT_FILE_BEGIN; 2982057d2b19SSudarsana Reddy Kalluru break; 298362e4d438SSudarsana Reddy Kalluru case QED_PUT_FILE_DATA: 298462e4d438SSudarsana Reddy Kalluru nvm_cmd = DRV_MSG_CODE_NVM_PUT_FILE_DATA; 298562e4d438SSudarsana Reddy Kalluru break; 298662e4d438SSudarsana Reddy Kalluru case QED_NVM_WRITE_NVRAM: 298762e4d438SSudarsana Reddy Kalluru nvm_cmd = DRV_MSG_CODE_NVM_WRITE_NVRAM; 298862e4d438SSudarsana Reddy Kalluru break; 298962e4d438SSudarsana Reddy Kalluru default: 299062e4d438SSudarsana Reddy Kalluru DP_NOTICE(p_hwfn, "Invalid nvm write command 0x%x\n", cmd); 299162e4d438SSudarsana Reddy Kalluru rc = -EINVAL; 299262e4d438SSudarsana Reddy Kalluru goto out; 299362e4d438SSudarsana Reddy Kalluru } 299462e4d438SSudarsana Reddy Kalluru 299562e4d438SSudarsana Reddy Kalluru buf_size = min_t(u32, (len - buf_idx), MCP_DRV_NVM_BUF_LEN); 2996057d2b19SSudarsana Reddy Kalluru while (buf_idx < len) { 2997057d2b19SSudarsana Reddy Kalluru if (cmd == QED_PUT_FILE_BEGIN) 2998057d2b19SSudarsana Reddy Kalluru nvm_offset = addr; 2999057d2b19SSudarsana Reddy Kalluru else 3000057d2b19SSudarsana Reddy Kalluru nvm_offset = ((buf_size << 3001057d2b19SSudarsana Reddy Kalluru DRV_MB_PARAM_NVM_LEN_OFFSET) | addr) + 3002057d2b19SSudarsana Reddy Kalluru buf_idx; 300362e4d438SSudarsana Reddy Kalluru rc = qed_mcp_nvm_wr_cmd(p_hwfn, p_ptt, nvm_cmd, nvm_offset, 300462e4d438SSudarsana Reddy Kalluru &resp, ¶m, buf_size, 300562e4d438SSudarsana Reddy Kalluru (u32 *)&p_buf[buf_idx]); 300662e4d438SSudarsana Reddy Kalluru if (rc) { 300762e4d438SSudarsana Reddy Kalluru DP_NOTICE(cdev, "nvm write failed, rc = %d\n", rc); 300862e4d438SSudarsana Reddy Kalluru resp = FW_MSG_CODE_ERROR; 300962e4d438SSudarsana Reddy Kalluru break; 301062e4d438SSudarsana Reddy Kalluru } 301162e4d438SSudarsana Reddy Kalluru 301262e4d438SSudarsana Reddy Kalluru if (resp != FW_MSG_CODE_OK && 301362e4d438SSudarsana Reddy Kalluru resp != FW_MSG_CODE_NVM_OK && 301462e4d438SSudarsana Reddy Kalluru resp != FW_MSG_CODE_NVM_PUT_FILE_FINISH_OK) { 301562e4d438SSudarsana Reddy Kalluru DP_NOTICE(cdev, 301662e4d438SSudarsana Reddy Kalluru "nvm write failed, resp = 0x%08x\n", resp); 301762e4d438SSudarsana Reddy Kalluru rc = -EINVAL; 301862e4d438SSudarsana Reddy Kalluru break; 301962e4d438SSudarsana Reddy Kalluru } 302062e4d438SSudarsana Reddy Kalluru 302162e4d438SSudarsana Reddy Kalluru /* This can be a lengthy process, and it's possible scheduler 302262e4d438SSudarsana Reddy Kalluru * isn't pre-emptable. Sleep a bit to prevent CPU hogging. 302362e4d438SSudarsana Reddy Kalluru */ 302462e4d438SSudarsana Reddy Kalluru if (buf_idx % 0x1000 > (buf_idx + buf_size) % 0x1000) 302562e4d438SSudarsana Reddy Kalluru usleep_range(1000, 2000); 302662e4d438SSudarsana Reddy Kalluru 3027057d2b19SSudarsana Reddy Kalluru /* For MBI upgrade, MFW response includes the next buffer offset 3028057d2b19SSudarsana Reddy Kalluru * to be delivered to MFW. 3029057d2b19SSudarsana Reddy Kalluru */ 3030057d2b19SSudarsana Reddy Kalluru if (param && cmd == QED_PUT_FILE_DATA) { 3031057d2b19SSudarsana Reddy Kalluru buf_idx = QED_MFW_GET_FIELD(param, 3032057d2b19SSudarsana Reddy Kalluru FW_MB_PARAM_NVM_PUT_FILE_REQ_OFFSET); 3033057d2b19SSudarsana Reddy Kalluru buf_size = QED_MFW_GET_FIELD(param, 3034057d2b19SSudarsana Reddy Kalluru FW_MB_PARAM_NVM_PUT_FILE_REQ_SIZE); 3035057d2b19SSudarsana Reddy Kalluru } else { 303662e4d438SSudarsana Reddy Kalluru buf_idx += buf_size; 3037057d2b19SSudarsana Reddy Kalluru buf_size = min_t(u32, (len - buf_idx), 3038057d2b19SSudarsana Reddy Kalluru MCP_DRV_NVM_BUF_LEN); 3039057d2b19SSudarsana Reddy Kalluru } 304062e4d438SSudarsana Reddy Kalluru } 304162e4d438SSudarsana Reddy Kalluru 304262e4d438SSudarsana Reddy Kalluru cdev->mcp_nvm_resp = resp; 304362e4d438SSudarsana Reddy Kalluru out: 304462e4d438SSudarsana Reddy Kalluru qed_ptt_release(p_hwfn, p_ptt); 304562e4d438SSudarsana Reddy Kalluru 304662e4d438SSudarsana Reddy Kalluru return rc; 304762e4d438SSudarsana Reddy Kalluru } 304862e4d438SSudarsana Reddy Kalluru 3049b51dab46SSudarsana Reddy Kalluru int qed_mcp_phy_sfp_read(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, 3050b51dab46SSudarsana Reddy Kalluru u32 port, u32 addr, u32 offset, u32 len, u8 *p_buf) 3051b51dab46SSudarsana Reddy Kalluru { 3052b51dab46SSudarsana Reddy Kalluru u32 bytes_left, bytes_to_copy, buf_size, nvm_offset = 0; 3053b51dab46SSudarsana Reddy Kalluru u32 resp, param; 3054b51dab46SSudarsana Reddy Kalluru int rc; 3055b51dab46SSudarsana Reddy Kalluru 3056b51dab46SSudarsana Reddy Kalluru nvm_offset |= (port << DRV_MB_PARAM_TRANSCEIVER_PORT_OFFSET) & 3057b51dab46SSudarsana Reddy Kalluru DRV_MB_PARAM_TRANSCEIVER_PORT_MASK; 3058b51dab46SSudarsana Reddy Kalluru nvm_offset |= (addr << DRV_MB_PARAM_TRANSCEIVER_I2C_ADDRESS_OFFSET) & 3059b51dab46SSudarsana Reddy Kalluru DRV_MB_PARAM_TRANSCEIVER_I2C_ADDRESS_MASK; 3060b51dab46SSudarsana Reddy Kalluru 3061b51dab46SSudarsana Reddy Kalluru addr = offset; 3062b51dab46SSudarsana Reddy Kalluru offset = 0; 3063b51dab46SSudarsana Reddy Kalluru bytes_left = len; 3064b51dab46SSudarsana Reddy Kalluru while (bytes_left > 0) { 3065b51dab46SSudarsana Reddy Kalluru bytes_to_copy = min_t(u32, bytes_left, 3066b51dab46SSudarsana Reddy Kalluru MAX_I2C_TRANSACTION_SIZE); 3067b51dab46SSudarsana Reddy Kalluru nvm_offset &= (DRV_MB_PARAM_TRANSCEIVER_I2C_ADDRESS_MASK | 3068b51dab46SSudarsana Reddy Kalluru DRV_MB_PARAM_TRANSCEIVER_PORT_MASK); 3069b51dab46SSudarsana Reddy Kalluru nvm_offset |= ((addr + offset) << 3070b51dab46SSudarsana Reddy Kalluru DRV_MB_PARAM_TRANSCEIVER_OFFSET_OFFSET) & 3071b51dab46SSudarsana Reddy Kalluru DRV_MB_PARAM_TRANSCEIVER_OFFSET_MASK; 3072b51dab46SSudarsana Reddy Kalluru nvm_offset |= (bytes_to_copy << 3073b51dab46SSudarsana Reddy Kalluru DRV_MB_PARAM_TRANSCEIVER_SIZE_OFFSET) & 3074b51dab46SSudarsana Reddy Kalluru DRV_MB_PARAM_TRANSCEIVER_SIZE_MASK; 3075b51dab46SSudarsana Reddy Kalluru rc = qed_mcp_nvm_rd_cmd(p_hwfn, p_ptt, 3076b51dab46SSudarsana Reddy Kalluru DRV_MSG_CODE_TRANSCEIVER_READ, 3077b51dab46SSudarsana Reddy Kalluru nvm_offset, &resp, ¶m, &buf_size, 3078b51dab46SSudarsana Reddy Kalluru (u32 *)(p_buf + offset)); 3079b51dab46SSudarsana Reddy Kalluru if (rc) { 3080b51dab46SSudarsana Reddy Kalluru DP_NOTICE(p_hwfn, 3081b51dab46SSudarsana Reddy Kalluru "Failed to send a transceiver read command to the MFW. rc = %d.\n", 3082b51dab46SSudarsana Reddy Kalluru rc); 3083b51dab46SSudarsana Reddy Kalluru return rc; 3084b51dab46SSudarsana Reddy Kalluru } 3085b51dab46SSudarsana Reddy Kalluru 3086b51dab46SSudarsana Reddy Kalluru if (resp == FW_MSG_CODE_TRANSCEIVER_NOT_PRESENT) 3087b51dab46SSudarsana Reddy Kalluru return -ENODEV; 3088b51dab46SSudarsana Reddy Kalluru else if (resp != FW_MSG_CODE_TRANSCEIVER_DIAG_OK) 3089b51dab46SSudarsana Reddy Kalluru return -EINVAL; 3090b51dab46SSudarsana Reddy Kalluru 3091b51dab46SSudarsana Reddy Kalluru offset += buf_size; 3092b51dab46SSudarsana Reddy Kalluru bytes_left -= buf_size; 3093b51dab46SSudarsana Reddy Kalluru } 3094b51dab46SSudarsana Reddy Kalluru 3095b51dab46SSudarsana Reddy Kalluru return 0; 3096b51dab46SSudarsana Reddy Kalluru } 3097b51dab46SSudarsana Reddy Kalluru 309803dc76caSSudarsana Reddy Kalluru int qed_mcp_bist_register_test(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 309903dc76caSSudarsana Reddy Kalluru { 310003dc76caSSudarsana Reddy Kalluru u32 drv_mb_param = 0, rsp, param; 310103dc76caSSudarsana Reddy Kalluru int rc = 0; 310203dc76caSSudarsana Reddy Kalluru 310303dc76caSSudarsana Reddy Kalluru drv_mb_param = (DRV_MB_PARAM_BIST_REGISTER_TEST << 310403dc76caSSudarsana Reddy Kalluru DRV_MB_PARAM_BIST_TEST_INDEX_SHIFT); 310503dc76caSSudarsana Reddy Kalluru 310603dc76caSSudarsana Reddy Kalluru rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_BIST_TEST, 310703dc76caSSudarsana Reddy Kalluru drv_mb_param, &rsp, ¶m); 310803dc76caSSudarsana Reddy Kalluru 310903dc76caSSudarsana Reddy Kalluru if (rc) 311003dc76caSSudarsana Reddy Kalluru return rc; 311103dc76caSSudarsana Reddy Kalluru 311203dc76caSSudarsana Reddy Kalluru if (((rsp & FW_MSG_CODE_MASK) != FW_MSG_CODE_OK) || 311303dc76caSSudarsana Reddy Kalluru (param != DRV_MB_PARAM_BIST_RC_PASSED)) 311403dc76caSSudarsana Reddy Kalluru rc = -EAGAIN; 311503dc76caSSudarsana Reddy Kalluru 311603dc76caSSudarsana Reddy Kalluru return rc; 311703dc76caSSudarsana Reddy Kalluru } 311803dc76caSSudarsana Reddy Kalluru 311903dc76caSSudarsana Reddy Kalluru int qed_mcp_bist_clock_test(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 312003dc76caSSudarsana Reddy Kalluru { 312103dc76caSSudarsana Reddy Kalluru u32 drv_mb_param, rsp, param; 312203dc76caSSudarsana Reddy Kalluru int rc = 0; 312303dc76caSSudarsana Reddy Kalluru 312403dc76caSSudarsana Reddy Kalluru drv_mb_param = (DRV_MB_PARAM_BIST_CLOCK_TEST << 312503dc76caSSudarsana Reddy Kalluru DRV_MB_PARAM_BIST_TEST_INDEX_SHIFT); 312603dc76caSSudarsana Reddy Kalluru 312703dc76caSSudarsana Reddy Kalluru rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_BIST_TEST, 312803dc76caSSudarsana Reddy Kalluru drv_mb_param, &rsp, ¶m); 312903dc76caSSudarsana Reddy Kalluru 313003dc76caSSudarsana Reddy Kalluru if (rc) 313103dc76caSSudarsana Reddy Kalluru return rc; 313203dc76caSSudarsana Reddy Kalluru 313303dc76caSSudarsana Reddy Kalluru if (((rsp & FW_MSG_CODE_MASK) != FW_MSG_CODE_OK) || 313403dc76caSSudarsana Reddy Kalluru (param != DRV_MB_PARAM_BIST_RC_PASSED)) 313503dc76caSSudarsana Reddy Kalluru rc = -EAGAIN; 313603dc76caSSudarsana Reddy Kalluru 313703dc76caSSudarsana Reddy Kalluru return rc; 313803dc76caSSudarsana Reddy Kalluru } 31397a4b21b7SMintz, Yuval 314043645ce0SSudarsana Reddy Kalluru int qed_mcp_bist_nvm_get_num_images(struct qed_hwfn *p_hwfn, 31417a4b21b7SMintz, Yuval struct qed_ptt *p_ptt, 31427a4b21b7SMintz, Yuval u32 *num_images) 31437a4b21b7SMintz, Yuval { 31447a4b21b7SMintz, Yuval u32 drv_mb_param = 0, rsp; 31457a4b21b7SMintz, Yuval int rc = 0; 31467a4b21b7SMintz, Yuval 31477a4b21b7SMintz, Yuval drv_mb_param = (DRV_MB_PARAM_BIST_NVM_TEST_NUM_IMAGES << 31487a4b21b7SMintz, Yuval DRV_MB_PARAM_BIST_TEST_INDEX_SHIFT); 31497a4b21b7SMintz, Yuval 31507a4b21b7SMintz, Yuval rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_BIST_TEST, 31517a4b21b7SMintz, Yuval drv_mb_param, &rsp, num_images); 31527a4b21b7SMintz, Yuval if (rc) 31537a4b21b7SMintz, Yuval return rc; 31547a4b21b7SMintz, Yuval 31557a4b21b7SMintz, Yuval if (((rsp & FW_MSG_CODE_MASK) != FW_MSG_CODE_OK)) 31567a4b21b7SMintz, Yuval rc = -EINVAL; 31577a4b21b7SMintz, Yuval 31587a4b21b7SMintz, Yuval return rc; 31597a4b21b7SMintz, Yuval } 31607a4b21b7SMintz, Yuval 316143645ce0SSudarsana Reddy Kalluru int qed_mcp_bist_nvm_get_image_att(struct qed_hwfn *p_hwfn, 31627a4b21b7SMintz, Yuval struct qed_ptt *p_ptt, 31637a4b21b7SMintz, Yuval struct bist_nvm_image_att *p_image_att, 31647a4b21b7SMintz, Yuval u32 image_index) 31657a4b21b7SMintz, Yuval { 31667a4b21b7SMintz, Yuval u32 buf_size = 0, param, resp = 0, resp_param = 0; 31677a4b21b7SMintz, Yuval int rc; 31687a4b21b7SMintz, Yuval 31697a4b21b7SMintz, Yuval param = DRV_MB_PARAM_BIST_NVM_TEST_IMAGE_BY_INDEX << 31707a4b21b7SMintz, Yuval DRV_MB_PARAM_BIST_TEST_INDEX_SHIFT; 31717a4b21b7SMintz, Yuval param |= image_index << DRV_MB_PARAM_BIST_TEST_IMAGE_INDEX_SHIFT; 31727a4b21b7SMintz, Yuval 31737a4b21b7SMintz, Yuval rc = qed_mcp_nvm_rd_cmd(p_hwfn, p_ptt, 31747a4b21b7SMintz, Yuval DRV_MSG_CODE_BIST_TEST, param, 31757a4b21b7SMintz, Yuval &resp, &resp_param, 31767a4b21b7SMintz, Yuval &buf_size, 31777a4b21b7SMintz, Yuval (u32 *)p_image_att); 31787a4b21b7SMintz, Yuval if (rc) 31797a4b21b7SMintz, Yuval return rc; 31807a4b21b7SMintz, Yuval 31817a4b21b7SMintz, Yuval if (((resp & FW_MSG_CODE_MASK) != FW_MSG_CODE_OK) || 31827a4b21b7SMintz, Yuval (p_image_att->return_code != 1)) 31837a4b21b7SMintz, Yuval rc = -EINVAL; 31847a4b21b7SMintz, Yuval 31857a4b21b7SMintz, Yuval return rc; 31867a4b21b7SMintz, Yuval } 31872edbff8dSTomer Tayar 318843645ce0SSudarsana Reddy Kalluru int qed_mcp_nvm_info_populate(struct qed_hwfn *p_hwfn) 318943645ce0SSudarsana Reddy Kalluru { 31905e7ba042SDenis Bolotin struct qed_nvm_image_info nvm_info; 319143645ce0SSudarsana Reddy Kalluru struct qed_ptt *p_ptt; 319243645ce0SSudarsana Reddy Kalluru int rc; 319343645ce0SSudarsana Reddy Kalluru u32 i; 319443645ce0SSudarsana Reddy Kalluru 31955e7ba042SDenis Bolotin if (p_hwfn->nvm_info.valid) 31965e7ba042SDenis Bolotin return 0; 31975e7ba042SDenis Bolotin 319843645ce0SSudarsana Reddy Kalluru p_ptt = qed_ptt_acquire(p_hwfn); 319943645ce0SSudarsana Reddy Kalluru if (!p_ptt) { 320043645ce0SSudarsana Reddy Kalluru DP_ERR(p_hwfn, "failed to acquire ptt\n"); 320143645ce0SSudarsana Reddy Kalluru return -EBUSY; 320243645ce0SSudarsana Reddy Kalluru } 320343645ce0SSudarsana Reddy Kalluru 320443645ce0SSudarsana Reddy Kalluru /* Acquire from MFW the amount of available images */ 32055e7ba042SDenis Bolotin nvm_info.num_images = 0; 320643645ce0SSudarsana Reddy Kalluru rc = qed_mcp_bist_nvm_get_num_images(p_hwfn, 32075e7ba042SDenis Bolotin p_ptt, &nvm_info.num_images); 320843645ce0SSudarsana Reddy Kalluru if (rc == -EOPNOTSUPP) { 320943645ce0SSudarsana Reddy Kalluru DP_INFO(p_hwfn, "DRV_MSG_CODE_BIST_TEST is not supported\n"); 321043645ce0SSudarsana Reddy Kalluru goto out; 32115e7ba042SDenis Bolotin } else if (rc || !nvm_info.num_images) { 321243645ce0SSudarsana Reddy Kalluru DP_ERR(p_hwfn, "Failed getting number of images\n"); 321343645ce0SSudarsana Reddy Kalluru goto err0; 321443645ce0SSudarsana Reddy Kalluru } 321543645ce0SSudarsana Reddy Kalluru 32165e7ba042SDenis Bolotin nvm_info.image_att = kmalloc_array(nvm_info.num_images, 321743645ce0SSudarsana Reddy Kalluru sizeof(struct bist_nvm_image_att), 321843645ce0SSudarsana Reddy Kalluru GFP_KERNEL); 32195e7ba042SDenis Bolotin if (!nvm_info.image_att) { 322043645ce0SSudarsana Reddy Kalluru rc = -ENOMEM; 322143645ce0SSudarsana Reddy Kalluru goto err0; 322243645ce0SSudarsana Reddy Kalluru } 322343645ce0SSudarsana Reddy Kalluru 322443645ce0SSudarsana Reddy Kalluru /* Iterate over images and get their attributes */ 32255e7ba042SDenis Bolotin for (i = 0; i < nvm_info.num_images; i++) { 322643645ce0SSudarsana Reddy Kalluru rc = qed_mcp_bist_nvm_get_image_att(p_hwfn, p_ptt, 32275e7ba042SDenis Bolotin &nvm_info.image_att[i], i); 322843645ce0SSudarsana Reddy Kalluru if (rc) { 322943645ce0SSudarsana Reddy Kalluru DP_ERR(p_hwfn, 323043645ce0SSudarsana Reddy Kalluru "Failed getting image index %d attributes\n", i); 323143645ce0SSudarsana Reddy Kalluru goto err1; 323243645ce0SSudarsana Reddy Kalluru } 323343645ce0SSudarsana Reddy Kalluru 323443645ce0SSudarsana Reddy Kalluru DP_VERBOSE(p_hwfn, QED_MSG_SP, "image index %d, size %x\n", i, 32355e7ba042SDenis Bolotin nvm_info.image_att[i].len); 323643645ce0SSudarsana Reddy Kalluru } 323743645ce0SSudarsana Reddy Kalluru out: 32385e7ba042SDenis Bolotin /* Update hwfn's nvm_info */ 32395e7ba042SDenis Bolotin if (nvm_info.num_images) { 32405e7ba042SDenis Bolotin p_hwfn->nvm_info.num_images = nvm_info.num_images; 32415e7ba042SDenis Bolotin kfree(p_hwfn->nvm_info.image_att); 32425e7ba042SDenis Bolotin p_hwfn->nvm_info.image_att = nvm_info.image_att; 32435e7ba042SDenis Bolotin p_hwfn->nvm_info.valid = true; 32445e7ba042SDenis Bolotin } 32455e7ba042SDenis Bolotin 324643645ce0SSudarsana Reddy Kalluru qed_ptt_release(p_hwfn, p_ptt); 324743645ce0SSudarsana Reddy Kalluru return 0; 324843645ce0SSudarsana Reddy Kalluru 324943645ce0SSudarsana Reddy Kalluru err1: 32505e7ba042SDenis Bolotin kfree(nvm_info.image_att); 325143645ce0SSudarsana Reddy Kalluru err0: 325243645ce0SSudarsana Reddy Kalluru qed_ptt_release(p_hwfn, p_ptt); 325343645ce0SSudarsana Reddy Kalluru return rc; 325443645ce0SSudarsana Reddy Kalluru } 325543645ce0SSudarsana Reddy Kalluru 32561ac4329aSDenis Bolotin int 325720675b37SMintz, Yuval qed_mcp_get_nvm_image_att(struct qed_hwfn *p_hwfn, 325820675b37SMintz, Yuval enum qed_nvm_images image_id, 325920675b37SMintz, Yuval struct qed_nvm_image_att *p_image_att) 326020675b37SMintz, Yuval { 326120675b37SMintz, Yuval enum nvm_image_type type; 326243645ce0SSudarsana Reddy Kalluru u32 i; 326320675b37SMintz, Yuval 326420675b37SMintz, Yuval /* Translate image_id into MFW definitions */ 326520675b37SMintz, Yuval switch (image_id) { 326620675b37SMintz, Yuval case QED_NVM_IMAGE_ISCSI_CFG: 326720675b37SMintz, Yuval type = NVM_TYPE_ISCSI_CFG; 326820675b37SMintz, Yuval break; 326920675b37SMintz, Yuval case QED_NVM_IMAGE_FCOE_CFG: 327020675b37SMintz, Yuval type = NVM_TYPE_FCOE_CFG; 327120675b37SMintz, Yuval break; 32728a52bbabSMichal Kalderon case QED_NVM_IMAGE_MDUMP: 32738a52bbabSMichal Kalderon type = NVM_TYPE_MDUMP; 32748a52bbabSMichal Kalderon break; 32751ac4329aSDenis Bolotin case QED_NVM_IMAGE_NVM_CFG1: 32761ac4329aSDenis Bolotin type = NVM_TYPE_NVM_CFG1; 32771ac4329aSDenis Bolotin break; 32781ac4329aSDenis Bolotin case QED_NVM_IMAGE_DEFAULT_CFG: 32791ac4329aSDenis Bolotin type = NVM_TYPE_DEFAULT_CFG; 32801ac4329aSDenis Bolotin break; 32811ac4329aSDenis Bolotin case QED_NVM_IMAGE_NVM_META: 32821ac4329aSDenis Bolotin type = NVM_TYPE_META; 32831ac4329aSDenis Bolotin break; 328420675b37SMintz, Yuval default: 328520675b37SMintz, Yuval DP_NOTICE(p_hwfn, "Unknown request of image_id %08x\n", 328620675b37SMintz, Yuval image_id); 328720675b37SMintz, Yuval return -EINVAL; 328820675b37SMintz, Yuval } 328920675b37SMintz, Yuval 32905e7ba042SDenis Bolotin qed_mcp_nvm_info_populate(p_hwfn); 329143645ce0SSudarsana Reddy Kalluru for (i = 0; i < p_hwfn->nvm_info.num_images; i++) 329243645ce0SSudarsana Reddy Kalluru if (type == p_hwfn->nvm_info.image_att[i].image_type) 329320675b37SMintz, Yuval break; 329443645ce0SSudarsana Reddy Kalluru if (i == p_hwfn->nvm_info.num_images) { 329520675b37SMintz, Yuval DP_VERBOSE(p_hwfn, QED_MSG_STORAGE, 329620675b37SMintz, Yuval "Failed to find nvram image of type %08x\n", 329720675b37SMintz, Yuval image_id); 329843645ce0SSudarsana Reddy Kalluru return -ENOENT; 329920675b37SMintz, Yuval } 330020675b37SMintz, Yuval 330143645ce0SSudarsana Reddy Kalluru p_image_att->start_addr = p_hwfn->nvm_info.image_att[i].nvm_start_addr; 330243645ce0SSudarsana Reddy Kalluru p_image_att->length = p_hwfn->nvm_info.image_att[i].len; 330320675b37SMintz, Yuval 330420675b37SMintz, Yuval return 0; 330520675b37SMintz, Yuval } 330620675b37SMintz, Yuval 330720675b37SMintz, Yuval int qed_mcp_get_nvm_image(struct qed_hwfn *p_hwfn, 330820675b37SMintz, Yuval enum qed_nvm_images image_id, 330920675b37SMintz, Yuval u8 *p_buffer, u32 buffer_len) 331020675b37SMintz, Yuval { 331120675b37SMintz, Yuval struct qed_nvm_image_att image_att; 331220675b37SMintz, Yuval int rc; 331320675b37SMintz, Yuval 331420675b37SMintz, Yuval memset(p_buffer, 0, buffer_len); 331520675b37SMintz, Yuval 3316b60bfdfeSDenis Bolotin rc = qed_mcp_get_nvm_image_att(p_hwfn, image_id, &image_att); 331720675b37SMintz, Yuval if (rc) 331820675b37SMintz, Yuval return rc; 331920675b37SMintz, Yuval 332020675b37SMintz, Yuval /* Validate sizes - both the image's and the supplied buffer's */ 332120675b37SMintz, Yuval if (image_att.length <= 4) { 332220675b37SMintz, Yuval DP_VERBOSE(p_hwfn, QED_MSG_STORAGE, 332320675b37SMintz, Yuval "Image [%d] is too small - only %d bytes\n", 332420675b37SMintz, Yuval image_id, image_att.length); 332520675b37SMintz, Yuval return -EINVAL; 332620675b37SMintz, Yuval } 332720675b37SMintz, Yuval 332820675b37SMintz, Yuval if (image_att.length > buffer_len) { 332920675b37SMintz, Yuval DP_VERBOSE(p_hwfn, 333020675b37SMintz, Yuval QED_MSG_STORAGE, 333120675b37SMintz, Yuval "Image [%d] is too big - %08x bytes where only %08x are available\n", 333220675b37SMintz, Yuval image_id, image_att.length, buffer_len); 333320675b37SMintz, Yuval return -ENOMEM; 333420675b37SMintz, Yuval } 333520675b37SMintz, Yuval 333620675b37SMintz, Yuval return qed_mcp_nvm_read(p_hwfn->cdev, image_att.start_addr, 333720675b37SMintz, Yuval p_buffer, image_att.length); 333820675b37SMintz, Yuval } 333920675b37SMintz, Yuval 33409c8517c4STomer Tayar static enum resource_id_enum qed_mcp_get_mfw_res_id(enum qed_resources res_id) 33419c8517c4STomer Tayar { 33429c8517c4STomer Tayar enum resource_id_enum mfw_res_id = RESOURCE_NUM_INVALID; 33439c8517c4STomer Tayar 33449c8517c4STomer Tayar switch (res_id) { 33459c8517c4STomer Tayar case QED_SB: 33469c8517c4STomer Tayar mfw_res_id = RESOURCE_NUM_SB_E; 33479c8517c4STomer Tayar break; 33489c8517c4STomer Tayar case QED_L2_QUEUE: 33499c8517c4STomer Tayar mfw_res_id = RESOURCE_NUM_L2_QUEUE_E; 33509c8517c4STomer Tayar break; 33519c8517c4STomer Tayar case QED_VPORT: 33529c8517c4STomer Tayar mfw_res_id = RESOURCE_NUM_VPORT_E; 33539c8517c4STomer Tayar break; 33549c8517c4STomer Tayar case QED_RSS_ENG: 33559c8517c4STomer Tayar mfw_res_id = RESOURCE_NUM_RSS_ENGINES_E; 33569c8517c4STomer Tayar break; 33579c8517c4STomer Tayar case QED_PQ: 33589c8517c4STomer Tayar mfw_res_id = RESOURCE_NUM_PQ_E; 33599c8517c4STomer Tayar break; 33609c8517c4STomer Tayar case QED_RL: 33619c8517c4STomer Tayar mfw_res_id = RESOURCE_NUM_RL_E; 33629c8517c4STomer Tayar break; 33639c8517c4STomer Tayar case QED_MAC: 33649c8517c4STomer Tayar case QED_VLAN: 33659c8517c4STomer Tayar /* Each VFC resource can accommodate both a MAC and a VLAN */ 33669c8517c4STomer Tayar mfw_res_id = RESOURCE_VFC_FILTER_E; 33679c8517c4STomer Tayar break; 33689c8517c4STomer Tayar case QED_ILT: 33699c8517c4STomer Tayar mfw_res_id = RESOURCE_ILT_E; 33709c8517c4STomer Tayar break; 3371997af5dfSMichal Kalderon case QED_LL2_RAM_QUEUE: 33729c8517c4STomer Tayar mfw_res_id = RESOURCE_LL2_QUEUE_E; 33739c8517c4STomer Tayar break; 3374997af5dfSMichal Kalderon case QED_LL2_CTX_QUEUE: 3375997af5dfSMichal Kalderon mfw_res_id = RESOURCE_LL2_CQS_E; 3376997af5dfSMichal Kalderon break; 33779c8517c4STomer Tayar case QED_RDMA_CNQ_RAM: 33789c8517c4STomer Tayar case QED_CMDQS_CQS: 33799c8517c4STomer Tayar /* CNQ/CMDQS are the same resource */ 33809c8517c4STomer Tayar mfw_res_id = RESOURCE_CQS_E; 33819c8517c4STomer Tayar break; 33829c8517c4STomer Tayar case QED_RDMA_STATS_QUEUE: 33839c8517c4STomer Tayar mfw_res_id = RESOURCE_RDMA_STATS_QUEUE_E; 33849c8517c4STomer Tayar break; 33859c8517c4STomer Tayar case QED_BDQ: 33869c8517c4STomer Tayar mfw_res_id = RESOURCE_BDQ_E; 33879c8517c4STomer Tayar break; 33889c8517c4STomer Tayar default: 33899c8517c4STomer Tayar break; 33909c8517c4STomer Tayar } 33919c8517c4STomer Tayar 33929c8517c4STomer Tayar return mfw_res_id; 33939c8517c4STomer Tayar } 33949c8517c4STomer Tayar 33959c8517c4STomer Tayar #define QED_RESC_ALLOC_VERSION_MAJOR 2 33962edbff8dSTomer Tayar #define QED_RESC_ALLOC_VERSION_MINOR 0 33972edbff8dSTomer Tayar #define QED_RESC_ALLOC_VERSION \ 33982edbff8dSTomer Tayar ((QED_RESC_ALLOC_VERSION_MAJOR << \ 33992edbff8dSTomer Tayar DRV_MB_PARAM_RESOURCE_ALLOC_VERSION_MAJOR_SHIFT) | \ 34002edbff8dSTomer Tayar (QED_RESC_ALLOC_VERSION_MINOR << \ 34012edbff8dSTomer Tayar DRV_MB_PARAM_RESOURCE_ALLOC_VERSION_MINOR_SHIFT)) 34029c8517c4STomer Tayar 34039c8517c4STomer Tayar struct qed_resc_alloc_in_params { 34049c8517c4STomer Tayar u32 cmd; 34059c8517c4STomer Tayar enum qed_resources res_id; 34069c8517c4STomer Tayar u32 resc_max_val; 34079c8517c4STomer Tayar }; 34089c8517c4STomer Tayar 34099c8517c4STomer Tayar struct qed_resc_alloc_out_params { 34109c8517c4STomer Tayar u32 mcp_resp; 34119c8517c4STomer Tayar u32 mcp_param; 34129c8517c4STomer Tayar u32 resc_num; 34139c8517c4STomer Tayar u32 resc_start; 34149c8517c4STomer Tayar u32 vf_resc_num; 34159c8517c4STomer Tayar u32 vf_resc_start; 34169c8517c4STomer Tayar u32 flags; 34179c8517c4STomer Tayar }; 34189c8517c4STomer Tayar 34199c8517c4STomer Tayar static int 34209c8517c4STomer Tayar qed_mcp_resc_allocation_msg(struct qed_hwfn *p_hwfn, 34212edbff8dSTomer Tayar struct qed_ptt *p_ptt, 34229c8517c4STomer Tayar struct qed_resc_alloc_in_params *p_in_params, 34239c8517c4STomer Tayar struct qed_resc_alloc_out_params *p_out_params) 34242edbff8dSTomer Tayar { 34252edbff8dSTomer Tayar struct qed_mcp_mb_params mb_params; 34269c8517c4STomer Tayar struct resource_info mfw_resc_info; 34272edbff8dSTomer Tayar int rc; 34282edbff8dSTomer Tayar 34299c8517c4STomer Tayar memset(&mfw_resc_info, 0, sizeof(mfw_resc_info)); 3430bb480242SMintz, Yuval 34319c8517c4STomer Tayar mfw_resc_info.res_id = qed_mcp_get_mfw_res_id(p_in_params->res_id); 34329c8517c4STomer Tayar if (mfw_resc_info.res_id == RESOURCE_NUM_INVALID) { 34339c8517c4STomer Tayar DP_ERR(p_hwfn, 34349c8517c4STomer Tayar "Failed to match resource %d [%s] with the MFW resources\n", 34359c8517c4STomer Tayar p_in_params->res_id, 34369c8517c4STomer Tayar qed_hw_get_resc_name(p_in_params->res_id)); 34379c8517c4STomer Tayar return -EINVAL; 34389c8517c4STomer Tayar } 34399c8517c4STomer Tayar 34409c8517c4STomer Tayar switch (p_in_params->cmd) { 34419c8517c4STomer Tayar case DRV_MSG_SET_RESOURCE_VALUE_MSG: 34429c8517c4STomer Tayar mfw_resc_info.size = p_in_params->resc_max_val; 34439c8517c4STomer Tayar /* Fallthrough */ 34449c8517c4STomer Tayar case DRV_MSG_GET_RESOURCE_ALLOC_MSG: 34459c8517c4STomer Tayar break; 34469c8517c4STomer Tayar default: 34479c8517c4STomer Tayar DP_ERR(p_hwfn, "Unexpected resource alloc command [0x%08x]\n", 34489c8517c4STomer Tayar p_in_params->cmd); 34499c8517c4STomer Tayar return -EINVAL; 34509c8517c4STomer Tayar } 34519c8517c4STomer Tayar 34529c8517c4STomer Tayar memset(&mb_params, 0, sizeof(mb_params)); 34539c8517c4STomer Tayar mb_params.cmd = p_in_params->cmd; 34549c8517c4STomer Tayar mb_params.param = QED_RESC_ALLOC_VERSION; 34559c8517c4STomer Tayar mb_params.p_data_src = &mfw_resc_info; 34569c8517c4STomer Tayar mb_params.data_src_size = sizeof(mfw_resc_info); 34579c8517c4STomer Tayar mb_params.p_data_dst = mb_params.p_data_src; 34589c8517c4STomer Tayar mb_params.data_dst_size = mb_params.data_src_size; 34599c8517c4STomer Tayar 34609c8517c4STomer Tayar DP_VERBOSE(p_hwfn, 34619c8517c4STomer Tayar QED_MSG_SP, 34629c8517c4STomer Tayar "Resource message request: cmd 0x%08x, res_id %d [%s], hsi_version %d.%d, val 0x%x\n", 34639c8517c4STomer Tayar p_in_params->cmd, 34649c8517c4STomer Tayar p_in_params->res_id, 34659c8517c4STomer Tayar qed_hw_get_resc_name(p_in_params->res_id), 34669c8517c4STomer Tayar QED_MFW_GET_FIELD(mb_params.param, 34679c8517c4STomer Tayar DRV_MB_PARAM_RESOURCE_ALLOC_VERSION_MAJOR), 34689c8517c4STomer Tayar QED_MFW_GET_FIELD(mb_params.param, 34699c8517c4STomer Tayar DRV_MB_PARAM_RESOURCE_ALLOC_VERSION_MINOR), 34709c8517c4STomer Tayar p_in_params->resc_max_val); 34719c8517c4STomer Tayar 34722edbff8dSTomer Tayar rc = qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 34732edbff8dSTomer Tayar if (rc) 34742edbff8dSTomer Tayar return rc; 34752edbff8dSTomer Tayar 34769c8517c4STomer Tayar p_out_params->mcp_resp = mb_params.mcp_resp; 34779c8517c4STomer Tayar p_out_params->mcp_param = mb_params.mcp_param; 34789c8517c4STomer Tayar p_out_params->resc_num = mfw_resc_info.size; 34799c8517c4STomer Tayar p_out_params->resc_start = mfw_resc_info.offset; 34809c8517c4STomer Tayar p_out_params->vf_resc_num = mfw_resc_info.vf_size; 34819c8517c4STomer Tayar p_out_params->vf_resc_start = mfw_resc_info.vf_offset; 34829c8517c4STomer Tayar p_out_params->flags = mfw_resc_info.flags; 34832edbff8dSTomer Tayar 34842edbff8dSTomer Tayar DP_VERBOSE(p_hwfn, 34852edbff8dSTomer Tayar QED_MSG_SP, 34869c8517c4STomer 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", 34879c8517c4STomer Tayar QED_MFW_GET_FIELD(p_out_params->mcp_param, 34889c8517c4STomer Tayar FW_MB_PARAM_RESOURCE_ALLOC_VERSION_MAJOR), 34899c8517c4STomer Tayar QED_MFW_GET_FIELD(p_out_params->mcp_param, 34909c8517c4STomer Tayar FW_MB_PARAM_RESOURCE_ALLOC_VERSION_MINOR), 34919c8517c4STomer Tayar p_out_params->resc_num, 34929c8517c4STomer Tayar p_out_params->resc_start, 34939c8517c4STomer Tayar p_out_params->vf_resc_num, 34949c8517c4STomer Tayar p_out_params->vf_resc_start, p_out_params->flags); 34959c8517c4STomer Tayar 34969c8517c4STomer Tayar return 0; 34979c8517c4STomer Tayar } 34989c8517c4STomer Tayar 34999c8517c4STomer Tayar int 35009c8517c4STomer Tayar qed_mcp_set_resc_max_val(struct qed_hwfn *p_hwfn, 35019c8517c4STomer Tayar struct qed_ptt *p_ptt, 35029c8517c4STomer Tayar enum qed_resources res_id, 35039c8517c4STomer Tayar u32 resc_max_val, u32 *p_mcp_resp) 35049c8517c4STomer Tayar { 35059c8517c4STomer Tayar struct qed_resc_alloc_out_params out_params; 35069c8517c4STomer Tayar struct qed_resc_alloc_in_params in_params; 35079c8517c4STomer Tayar int rc; 35089c8517c4STomer Tayar 35099c8517c4STomer Tayar memset(&in_params, 0, sizeof(in_params)); 35109c8517c4STomer Tayar in_params.cmd = DRV_MSG_SET_RESOURCE_VALUE_MSG; 35119c8517c4STomer Tayar in_params.res_id = res_id; 35129c8517c4STomer Tayar in_params.resc_max_val = resc_max_val; 35139c8517c4STomer Tayar memset(&out_params, 0, sizeof(out_params)); 35149c8517c4STomer Tayar rc = qed_mcp_resc_allocation_msg(p_hwfn, p_ptt, &in_params, 35159c8517c4STomer Tayar &out_params); 35169c8517c4STomer Tayar if (rc) 35179c8517c4STomer Tayar return rc; 35189c8517c4STomer Tayar 35199c8517c4STomer Tayar *p_mcp_resp = out_params.mcp_resp; 35209c8517c4STomer Tayar 35219c8517c4STomer Tayar return 0; 35229c8517c4STomer Tayar } 35239c8517c4STomer Tayar 35249c8517c4STomer Tayar int 35259c8517c4STomer Tayar qed_mcp_get_resc_info(struct qed_hwfn *p_hwfn, 35269c8517c4STomer Tayar struct qed_ptt *p_ptt, 35279c8517c4STomer Tayar enum qed_resources res_id, 35289c8517c4STomer Tayar u32 *p_mcp_resp, u32 *p_resc_num, u32 *p_resc_start) 35299c8517c4STomer Tayar { 35309c8517c4STomer Tayar struct qed_resc_alloc_out_params out_params; 35319c8517c4STomer Tayar struct qed_resc_alloc_in_params in_params; 35329c8517c4STomer Tayar int rc; 35339c8517c4STomer Tayar 35349c8517c4STomer Tayar memset(&in_params, 0, sizeof(in_params)); 35359c8517c4STomer Tayar in_params.cmd = DRV_MSG_GET_RESOURCE_ALLOC_MSG; 35369c8517c4STomer Tayar in_params.res_id = res_id; 35379c8517c4STomer Tayar memset(&out_params, 0, sizeof(out_params)); 35389c8517c4STomer Tayar rc = qed_mcp_resc_allocation_msg(p_hwfn, p_ptt, &in_params, 35399c8517c4STomer Tayar &out_params); 35409c8517c4STomer Tayar if (rc) 35419c8517c4STomer Tayar return rc; 35429c8517c4STomer Tayar 35439c8517c4STomer Tayar *p_mcp_resp = out_params.mcp_resp; 35449c8517c4STomer Tayar 35459c8517c4STomer Tayar if (*p_mcp_resp == FW_MSG_CODE_RESOURCE_ALLOC_OK) { 35469c8517c4STomer Tayar *p_resc_num = out_params.resc_num; 35479c8517c4STomer Tayar *p_resc_start = out_params.resc_start; 35489c8517c4STomer Tayar } 35492edbff8dSTomer Tayar 35502edbff8dSTomer Tayar return 0; 35512edbff8dSTomer Tayar } 355218a69e36SMintz, Yuval 355318a69e36SMintz, Yuval int qed_mcp_initiate_pf_flr(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 355418a69e36SMintz, Yuval { 355518a69e36SMintz, Yuval u32 mcp_resp, mcp_param; 355618a69e36SMintz, Yuval 355718a69e36SMintz, Yuval return qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_INITIATE_PF_FLR, 0, 355818a69e36SMintz, Yuval &mcp_resp, &mcp_param); 355918a69e36SMintz, Yuval } 356095691c9cSTomer Tayar 356195691c9cSTomer Tayar static int qed_mcp_resource_cmd(struct qed_hwfn *p_hwfn, 356295691c9cSTomer Tayar struct qed_ptt *p_ptt, 356395691c9cSTomer Tayar u32 param, u32 *p_mcp_resp, u32 *p_mcp_param) 356495691c9cSTomer Tayar { 356595691c9cSTomer Tayar int rc; 356695691c9cSTomer Tayar 356795691c9cSTomer Tayar rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_RESOURCE_CMD, param, 356895691c9cSTomer Tayar p_mcp_resp, p_mcp_param); 356995691c9cSTomer Tayar if (rc) 357095691c9cSTomer Tayar return rc; 357195691c9cSTomer Tayar 357295691c9cSTomer Tayar if (*p_mcp_resp == FW_MSG_CODE_UNSUPPORTED) { 357395691c9cSTomer Tayar DP_INFO(p_hwfn, 357495691c9cSTomer Tayar "The resource command is unsupported by the MFW\n"); 357595691c9cSTomer Tayar return -EINVAL; 357695691c9cSTomer Tayar } 357795691c9cSTomer Tayar 357895691c9cSTomer Tayar if (*p_mcp_param == RESOURCE_OPCODE_UNKNOWN_CMD) { 357995691c9cSTomer Tayar u8 opcode = QED_MFW_GET_FIELD(param, RESOURCE_CMD_REQ_OPCODE); 358095691c9cSTomer Tayar 358195691c9cSTomer Tayar DP_NOTICE(p_hwfn, 358295691c9cSTomer Tayar "The resource command is unknown to the MFW [param 0x%08x, opcode %d]\n", 358395691c9cSTomer Tayar param, opcode); 358495691c9cSTomer Tayar return -EINVAL; 358595691c9cSTomer Tayar } 358695691c9cSTomer Tayar 358795691c9cSTomer Tayar return rc; 358895691c9cSTomer Tayar } 358995691c9cSTomer Tayar 3590bf774d14SYueHaibing static int 359195691c9cSTomer Tayar __qed_mcp_resc_lock(struct qed_hwfn *p_hwfn, 359295691c9cSTomer Tayar struct qed_ptt *p_ptt, 359395691c9cSTomer Tayar struct qed_resc_lock_params *p_params) 359495691c9cSTomer Tayar { 359595691c9cSTomer Tayar u32 param = 0, mcp_resp, mcp_param; 359695691c9cSTomer Tayar u8 opcode; 359795691c9cSTomer Tayar int rc; 359895691c9cSTomer Tayar 359995691c9cSTomer Tayar switch (p_params->timeout) { 360095691c9cSTomer Tayar case QED_MCP_RESC_LOCK_TO_DEFAULT: 360195691c9cSTomer Tayar opcode = RESOURCE_OPCODE_REQ; 360295691c9cSTomer Tayar p_params->timeout = 0; 360395691c9cSTomer Tayar break; 360495691c9cSTomer Tayar case QED_MCP_RESC_LOCK_TO_NONE: 360595691c9cSTomer Tayar opcode = RESOURCE_OPCODE_REQ_WO_AGING; 360695691c9cSTomer Tayar p_params->timeout = 0; 360795691c9cSTomer Tayar break; 360895691c9cSTomer Tayar default: 360995691c9cSTomer Tayar opcode = RESOURCE_OPCODE_REQ_W_AGING; 361095691c9cSTomer Tayar break; 361195691c9cSTomer Tayar } 361295691c9cSTomer Tayar 361395691c9cSTomer Tayar QED_MFW_SET_FIELD(param, RESOURCE_CMD_REQ_RESC, p_params->resource); 361495691c9cSTomer Tayar QED_MFW_SET_FIELD(param, RESOURCE_CMD_REQ_OPCODE, opcode); 361595691c9cSTomer Tayar QED_MFW_SET_FIELD(param, RESOURCE_CMD_REQ_AGE, p_params->timeout); 361695691c9cSTomer Tayar 361795691c9cSTomer Tayar DP_VERBOSE(p_hwfn, 361895691c9cSTomer Tayar QED_MSG_SP, 361995691c9cSTomer Tayar "Resource lock request: param 0x%08x [age %d, opcode %d, resource %d]\n", 362095691c9cSTomer Tayar param, p_params->timeout, opcode, p_params->resource); 362195691c9cSTomer Tayar 362295691c9cSTomer Tayar /* Attempt to acquire the resource */ 362395691c9cSTomer Tayar rc = qed_mcp_resource_cmd(p_hwfn, p_ptt, param, &mcp_resp, &mcp_param); 362495691c9cSTomer Tayar if (rc) 362595691c9cSTomer Tayar return rc; 362695691c9cSTomer Tayar 362795691c9cSTomer Tayar /* Analyze the response */ 362895691c9cSTomer Tayar p_params->owner = QED_MFW_GET_FIELD(mcp_param, RESOURCE_CMD_RSP_OWNER); 362995691c9cSTomer Tayar opcode = QED_MFW_GET_FIELD(mcp_param, RESOURCE_CMD_RSP_OPCODE); 363095691c9cSTomer Tayar 363195691c9cSTomer Tayar DP_VERBOSE(p_hwfn, 363295691c9cSTomer Tayar QED_MSG_SP, 363395691c9cSTomer Tayar "Resource lock response: mcp_param 0x%08x [opcode %d, owner %d]\n", 363495691c9cSTomer Tayar mcp_param, opcode, p_params->owner); 363595691c9cSTomer Tayar 363695691c9cSTomer Tayar switch (opcode) { 363795691c9cSTomer Tayar case RESOURCE_OPCODE_GNT: 363895691c9cSTomer Tayar p_params->b_granted = true; 363995691c9cSTomer Tayar break; 364095691c9cSTomer Tayar case RESOURCE_OPCODE_BUSY: 364195691c9cSTomer Tayar p_params->b_granted = false; 364295691c9cSTomer Tayar break; 364395691c9cSTomer Tayar default: 364495691c9cSTomer Tayar DP_NOTICE(p_hwfn, 364595691c9cSTomer Tayar "Unexpected opcode in resource lock response [mcp_param 0x%08x, opcode %d]\n", 364695691c9cSTomer Tayar mcp_param, opcode); 364795691c9cSTomer Tayar return -EINVAL; 364895691c9cSTomer Tayar } 364995691c9cSTomer Tayar 365095691c9cSTomer Tayar return 0; 365195691c9cSTomer Tayar } 365295691c9cSTomer Tayar 365395691c9cSTomer Tayar int 365495691c9cSTomer Tayar qed_mcp_resc_lock(struct qed_hwfn *p_hwfn, 365595691c9cSTomer Tayar struct qed_ptt *p_ptt, struct qed_resc_lock_params *p_params) 365695691c9cSTomer Tayar { 365795691c9cSTomer Tayar u32 retry_cnt = 0; 365895691c9cSTomer Tayar int rc; 365995691c9cSTomer Tayar 366095691c9cSTomer Tayar do { 366195691c9cSTomer Tayar /* No need for an interval before the first iteration */ 366295691c9cSTomer Tayar if (retry_cnt) { 366395691c9cSTomer Tayar if (p_params->sleep_b4_retry) { 366495691c9cSTomer Tayar u16 retry_interval_in_ms = 366595691c9cSTomer Tayar DIV_ROUND_UP(p_params->retry_interval, 366695691c9cSTomer Tayar 1000); 366795691c9cSTomer Tayar 366895691c9cSTomer Tayar msleep(retry_interval_in_ms); 366995691c9cSTomer Tayar } else { 367095691c9cSTomer Tayar udelay(p_params->retry_interval); 367195691c9cSTomer Tayar } 367295691c9cSTomer Tayar } 367395691c9cSTomer Tayar 367495691c9cSTomer Tayar rc = __qed_mcp_resc_lock(p_hwfn, p_ptt, p_params); 367595691c9cSTomer Tayar if (rc) 367695691c9cSTomer Tayar return rc; 367795691c9cSTomer Tayar 367895691c9cSTomer Tayar if (p_params->b_granted) 367995691c9cSTomer Tayar break; 368095691c9cSTomer Tayar } while (retry_cnt++ < p_params->retry_num); 368195691c9cSTomer Tayar 368295691c9cSTomer Tayar return 0; 368395691c9cSTomer Tayar } 368495691c9cSTomer Tayar 368595691c9cSTomer Tayar int 368695691c9cSTomer Tayar qed_mcp_resc_unlock(struct qed_hwfn *p_hwfn, 368795691c9cSTomer Tayar struct qed_ptt *p_ptt, 368895691c9cSTomer Tayar struct qed_resc_unlock_params *p_params) 368995691c9cSTomer Tayar { 369095691c9cSTomer Tayar u32 param = 0, mcp_resp, mcp_param; 369195691c9cSTomer Tayar u8 opcode; 369295691c9cSTomer Tayar int rc; 369395691c9cSTomer Tayar 369495691c9cSTomer Tayar opcode = p_params->b_force ? RESOURCE_OPCODE_FORCE_RELEASE 369595691c9cSTomer Tayar : RESOURCE_OPCODE_RELEASE; 369695691c9cSTomer Tayar QED_MFW_SET_FIELD(param, RESOURCE_CMD_REQ_RESC, p_params->resource); 369795691c9cSTomer Tayar QED_MFW_SET_FIELD(param, RESOURCE_CMD_REQ_OPCODE, opcode); 369895691c9cSTomer Tayar 369995691c9cSTomer Tayar DP_VERBOSE(p_hwfn, QED_MSG_SP, 370095691c9cSTomer Tayar "Resource unlock request: param 0x%08x [opcode %d, resource %d]\n", 370195691c9cSTomer Tayar param, opcode, p_params->resource); 370295691c9cSTomer Tayar 370395691c9cSTomer Tayar /* Attempt to release the resource */ 370495691c9cSTomer Tayar rc = qed_mcp_resource_cmd(p_hwfn, p_ptt, param, &mcp_resp, &mcp_param); 370595691c9cSTomer Tayar if (rc) 370695691c9cSTomer Tayar return rc; 370795691c9cSTomer Tayar 370895691c9cSTomer Tayar /* Analyze the response */ 370995691c9cSTomer Tayar opcode = QED_MFW_GET_FIELD(mcp_param, RESOURCE_CMD_RSP_OPCODE); 371095691c9cSTomer Tayar 371195691c9cSTomer Tayar DP_VERBOSE(p_hwfn, QED_MSG_SP, 371295691c9cSTomer Tayar "Resource unlock response: mcp_param 0x%08x [opcode %d]\n", 371395691c9cSTomer Tayar mcp_param, opcode); 371495691c9cSTomer Tayar 371595691c9cSTomer Tayar switch (opcode) { 371695691c9cSTomer Tayar case RESOURCE_OPCODE_RELEASED_PREVIOUS: 371795691c9cSTomer Tayar DP_INFO(p_hwfn, 371895691c9cSTomer Tayar "Resource unlock request for an already released resource [%d]\n", 371995691c9cSTomer Tayar p_params->resource); 372095691c9cSTomer Tayar /* Fallthrough */ 372195691c9cSTomer Tayar case RESOURCE_OPCODE_RELEASED: 372295691c9cSTomer Tayar p_params->b_released = true; 372395691c9cSTomer Tayar break; 372495691c9cSTomer Tayar case RESOURCE_OPCODE_WRONG_OWNER: 372595691c9cSTomer Tayar p_params->b_released = false; 372695691c9cSTomer Tayar break; 372795691c9cSTomer Tayar default: 372895691c9cSTomer Tayar DP_NOTICE(p_hwfn, 372995691c9cSTomer Tayar "Unexpected opcode in resource unlock response [mcp_param 0x%08x, opcode %d]\n", 373095691c9cSTomer Tayar mcp_param, opcode); 373195691c9cSTomer Tayar return -EINVAL; 373295691c9cSTomer Tayar } 373395691c9cSTomer Tayar 373495691c9cSTomer Tayar return 0; 373595691c9cSTomer Tayar } 3736f470f22cSsudarsana.kalluru@cavium.com 3737f470f22cSsudarsana.kalluru@cavium.com void qed_mcp_resc_lock_default_init(struct qed_resc_lock_params *p_lock, 3738f470f22cSsudarsana.kalluru@cavium.com struct qed_resc_unlock_params *p_unlock, 3739f470f22cSsudarsana.kalluru@cavium.com enum qed_resc_lock 3740f470f22cSsudarsana.kalluru@cavium.com resource, bool b_is_permanent) 3741f470f22cSsudarsana.kalluru@cavium.com { 3742f470f22cSsudarsana.kalluru@cavium.com if (p_lock) { 3743f470f22cSsudarsana.kalluru@cavium.com memset(p_lock, 0, sizeof(*p_lock)); 3744f470f22cSsudarsana.kalluru@cavium.com 3745f470f22cSsudarsana.kalluru@cavium.com /* Permanent resources don't require aging, and there's no 3746f470f22cSsudarsana.kalluru@cavium.com * point in trying to acquire them more than once since it's 3747f470f22cSsudarsana.kalluru@cavium.com * unexpected another entity would release them. 3748f470f22cSsudarsana.kalluru@cavium.com */ 3749f470f22cSsudarsana.kalluru@cavium.com if (b_is_permanent) { 3750f470f22cSsudarsana.kalluru@cavium.com p_lock->timeout = QED_MCP_RESC_LOCK_TO_NONE; 3751f470f22cSsudarsana.kalluru@cavium.com } else { 3752f470f22cSsudarsana.kalluru@cavium.com p_lock->retry_num = QED_MCP_RESC_LOCK_RETRY_CNT_DFLT; 3753f470f22cSsudarsana.kalluru@cavium.com p_lock->retry_interval = 3754f470f22cSsudarsana.kalluru@cavium.com QED_MCP_RESC_LOCK_RETRY_VAL_DFLT; 3755f470f22cSsudarsana.kalluru@cavium.com p_lock->sleep_b4_retry = true; 3756f470f22cSsudarsana.kalluru@cavium.com } 3757f470f22cSsudarsana.kalluru@cavium.com 3758f470f22cSsudarsana.kalluru@cavium.com p_lock->resource = resource; 3759f470f22cSsudarsana.kalluru@cavium.com } 3760f470f22cSsudarsana.kalluru@cavium.com 3761f470f22cSsudarsana.kalluru@cavium.com if (p_unlock) { 3762f470f22cSsudarsana.kalluru@cavium.com memset(p_unlock, 0, sizeof(*p_unlock)); 3763f470f22cSsudarsana.kalluru@cavium.com p_unlock->resource = resource; 3764f470f22cSsudarsana.kalluru@cavium.com } 3765f470f22cSsudarsana.kalluru@cavium.com } 3766645874e5SSudarsana Reddy Kalluru 3767df9c716dSSudarsana Reddy Kalluru bool qed_mcp_is_smart_an_supported(struct qed_hwfn *p_hwfn) 3768df9c716dSSudarsana Reddy Kalluru { 3769df9c716dSSudarsana Reddy Kalluru return !!(p_hwfn->mcp_info->capabilities & 3770df9c716dSSudarsana Reddy Kalluru FW_MB_PARAM_FEATURE_SUPPORT_SMARTLINQ); 3771df9c716dSSudarsana Reddy Kalluru } 3772df9c716dSSudarsana Reddy Kalluru 3773645874e5SSudarsana Reddy Kalluru int qed_mcp_get_capabilities(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 3774645874e5SSudarsana Reddy Kalluru { 3775645874e5SSudarsana Reddy Kalluru u32 mcp_resp; 3776645874e5SSudarsana Reddy Kalluru int rc; 3777645874e5SSudarsana Reddy Kalluru 3778645874e5SSudarsana Reddy Kalluru rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_GET_MFW_FEATURE_SUPPORT, 3779645874e5SSudarsana Reddy Kalluru 0, &mcp_resp, &p_hwfn->mcp_info->capabilities); 3780645874e5SSudarsana Reddy Kalluru if (!rc) 3781645874e5SSudarsana Reddy Kalluru DP_VERBOSE(p_hwfn, (QED_MSG_SP | NETIF_MSG_PROBE), 3782645874e5SSudarsana Reddy Kalluru "MFW supported features: %08x\n", 3783645874e5SSudarsana Reddy Kalluru p_hwfn->mcp_info->capabilities); 3784645874e5SSudarsana Reddy Kalluru 3785645874e5SSudarsana Reddy Kalluru return rc; 3786645874e5SSudarsana Reddy Kalluru } 3787645874e5SSudarsana Reddy Kalluru 3788645874e5SSudarsana Reddy Kalluru int qed_mcp_set_capabilities(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 3789645874e5SSudarsana Reddy Kalluru { 3790645874e5SSudarsana Reddy Kalluru u32 mcp_resp, mcp_param, features; 3791645874e5SSudarsana Reddy Kalluru 3792e40a826aSSudarsana Reddy Kalluru features = DRV_MB_PARAM_FEATURE_SUPPORT_PORT_EEE | 3793e40a826aSSudarsana Reddy Kalluru DRV_MB_PARAM_FEATURE_SUPPORT_FUNC_VLINK; 3794645874e5SSudarsana Reddy Kalluru 3795645874e5SSudarsana Reddy Kalluru return qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_FEATURE_SUPPORT, 3796645874e5SSudarsana Reddy Kalluru features, &mcp_resp, &mcp_param); 3797645874e5SSudarsana Reddy Kalluru } 379879284adeSMichal Kalderon 379979284adeSMichal Kalderon int qed_mcp_get_engine_config(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 380079284adeSMichal Kalderon { 380179284adeSMichal Kalderon struct qed_mcp_mb_params mb_params = {0}; 380279284adeSMichal Kalderon struct qed_dev *cdev = p_hwfn->cdev; 380379284adeSMichal Kalderon u8 fir_valid, l2_valid; 380479284adeSMichal Kalderon int rc; 380579284adeSMichal Kalderon 380679284adeSMichal Kalderon mb_params.cmd = DRV_MSG_CODE_GET_ENGINE_CONFIG; 380779284adeSMichal Kalderon rc = qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 380879284adeSMichal Kalderon if (rc) 380979284adeSMichal Kalderon return rc; 381079284adeSMichal Kalderon 381179284adeSMichal Kalderon if (mb_params.mcp_resp == FW_MSG_CODE_UNSUPPORTED) { 381279284adeSMichal Kalderon DP_INFO(p_hwfn, 381379284adeSMichal Kalderon "The get_engine_config command is unsupported by the MFW\n"); 381479284adeSMichal Kalderon return -EOPNOTSUPP; 381579284adeSMichal Kalderon } 381679284adeSMichal Kalderon 381779284adeSMichal Kalderon fir_valid = QED_MFW_GET_FIELD(mb_params.mcp_param, 381879284adeSMichal Kalderon FW_MB_PARAM_ENG_CFG_FIR_AFFIN_VALID); 381979284adeSMichal Kalderon if (fir_valid) 382079284adeSMichal Kalderon cdev->fir_affin = 382179284adeSMichal Kalderon QED_MFW_GET_FIELD(mb_params.mcp_param, 382279284adeSMichal Kalderon FW_MB_PARAM_ENG_CFG_FIR_AFFIN_VALUE); 382379284adeSMichal Kalderon 382479284adeSMichal Kalderon l2_valid = QED_MFW_GET_FIELD(mb_params.mcp_param, 382579284adeSMichal Kalderon FW_MB_PARAM_ENG_CFG_L2_AFFIN_VALID); 382679284adeSMichal Kalderon if (l2_valid) 382779284adeSMichal Kalderon cdev->l2_affin_hint = 382879284adeSMichal Kalderon QED_MFW_GET_FIELD(mb_params.mcp_param, 382979284adeSMichal Kalderon FW_MB_PARAM_ENG_CFG_L2_AFFIN_VALUE); 383079284adeSMichal Kalderon 383179284adeSMichal Kalderon DP_INFO(p_hwfn, 383279284adeSMichal Kalderon "Engine affinity config: FIR={valid %hhd, value %hhd}, L2_hint={valid %hhd, value %hhd}\n", 383379284adeSMichal Kalderon fir_valid, cdev->fir_affin, l2_valid, cdev->l2_affin_hint); 383479284adeSMichal Kalderon 383579284adeSMichal Kalderon return 0; 383679284adeSMichal Kalderon } 383779284adeSMichal Kalderon 383879284adeSMichal Kalderon int qed_mcp_get_ppfid_bitmap(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 383979284adeSMichal Kalderon { 384079284adeSMichal Kalderon struct qed_mcp_mb_params mb_params = {0}; 384179284adeSMichal Kalderon struct qed_dev *cdev = p_hwfn->cdev; 384279284adeSMichal Kalderon int rc; 384379284adeSMichal Kalderon 384479284adeSMichal Kalderon mb_params.cmd = DRV_MSG_CODE_GET_PPFID_BITMAP; 384579284adeSMichal Kalderon rc = qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 384679284adeSMichal Kalderon if (rc) 384779284adeSMichal Kalderon return rc; 384879284adeSMichal Kalderon 384979284adeSMichal Kalderon if (mb_params.mcp_resp == FW_MSG_CODE_UNSUPPORTED) { 385079284adeSMichal Kalderon DP_INFO(p_hwfn, 385179284adeSMichal Kalderon "The get_ppfid_bitmap command is unsupported by the MFW\n"); 385279284adeSMichal Kalderon return -EOPNOTSUPP; 385379284adeSMichal Kalderon } 385479284adeSMichal Kalderon 385579284adeSMichal Kalderon cdev->ppfid_bitmap = QED_MFW_GET_FIELD(mb_params.mcp_param, 385679284adeSMichal Kalderon FW_MB_PARAM_PPFID_BITMAP); 385779284adeSMichal Kalderon 385879284adeSMichal Kalderon DP_VERBOSE(p_hwfn, QED_MSG_SP, "PPFID bitmap 0x%hhx\n", 385979284adeSMichal Kalderon cdev->ppfid_bitmap); 386079284adeSMichal Kalderon 386179284adeSMichal Kalderon return 0; 386279284adeSMichal Kalderon } 386338eabdf0SSudarsana Reddy Kalluru 38642d4c8495SSudarsana Reddy Kalluru int qed_mcp_nvm_get_cfg(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, 38652d4c8495SSudarsana Reddy Kalluru u16 option_id, u8 entity_id, u16 flags, u8 *p_buf, 38662d4c8495SSudarsana Reddy Kalluru u32 *p_len) 38672d4c8495SSudarsana Reddy Kalluru { 38682d4c8495SSudarsana Reddy Kalluru u32 mb_param = 0, resp, param; 38692d4c8495SSudarsana Reddy Kalluru int rc; 38702d4c8495SSudarsana Reddy Kalluru 38712d4c8495SSudarsana Reddy Kalluru QED_MFW_SET_FIELD(mb_param, DRV_MB_PARAM_NVM_CFG_OPTION_ID, option_id); 38722d4c8495SSudarsana Reddy Kalluru if (flags & QED_NVM_CFG_OPTION_INIT) 38732d4c8495SSudarsana Reddy Kalluru QED_MFW_SET_FIELD(mb_param, 38742d4c8495SSudarsana Reddy Kalluru DRV_MB_PARAM_NVM_CFG_OPTION_INIT, 1); 38752d4c8495SSudarsana Reddy Kalluru if (flags & QED_NVM_CFG_OPTION_FREE) 38762d4c8495SSudarsana Reddy Kalluru QED_MFW_SET_FIELD(mb_param, 38772d4c8495SSudarsana Reddy Kalluru DRV_MB_PARAM_NVM_CFG_OPTION_FREE, 1); 38782d4c8495SSudarsana Reddy Kalluru if (flags & QED_NVM_CFG_OPTION_ENTITY_SEL) { 38792d4c8495SSudarsana Reddy Kalluru QED_MFW_SET_FIELD(mb_param, 38802d4c8495SSudarsana Reddy Kalluru DRV_MB_PARAM_NVM_CFG_OPTION_ENTITY_SEL, 1); 38812d4c8495SSudarsana Reddy Kalluru QED_MFW_SET_FIELD(mb_param, 38822d4c8495SSudarsana Reddy Kalluru DRV_MB_PARAM_NVM_CFG_OPTION_ENTITY_ID, 38832d4c8495SSudarsana Reddy Kalluru entity_id); 38842d4c8495SSudarsana Reddy Kalluru } 38852d4c8495SSudarsana Reddy Kalluru 38862d4c8495SSudarsana Reddy Kalluru rc = qed_mcp_nvm_rd_cmd(p_hwfn, p_ptt, 38872d4c8495SSudarsana Reddy Kalluru DRV_MSG_CODE_GET_NVM_CFG_OPTION, 38882d4c8495SSudarsana Reddy Kalluru mb_param, &resp, ¶m, p_len, (u32 *)p_buf); 38892d4c8495SSudarsana Reddy Kalluru 38902d4c8495SSudarsana Reddy Kalluru return rc; 38912d4c8495SSudarsana Reddy Kalluru } 38922d4c8495SSudarsana Reddy Kalluru 389338eabdf0SSudarsana Reddy Kalluru int qed_mcp_nvm_set_cfg(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, 389438eabdf0SSudarsana Reddy Kalluru u16 option_id, u8 entity_id, u16 flags, u8 *p_buf, 389538eabdf0SSudarsana Reddy Kalluru u32 len) 389638eabdf0SSudarsana Reddy Kalluru { 389738eabdf0SSudarsana Reddy Kalluru u32 mb_param = 0, resp, param; 389838eabdf0SSudarsana Reddy Kalluru 389938eabdf0SSudarsana Reddy Kalluru QED_MFW_SET_FIELD(mb_param, DRV_MB_PARAM_NVM_CFG_OPTION_ID, option_id); 390038eabdf0SSudarsana Reddy Kalluru if (flags & QED_NVM_CFG_OPTION_ALL) 390138eabdf0SSudarsana Reddy Kalluru QED_MFW_SET_FIELD(mb_param, 390238eabdf0SSudarsana Reddy Kalluru DRV_MB_PARAM_NVM_CFG_OPTION_ALL, 1); 390338eabdf0SSudarsana Reddy Kalluru if (flags & QED_NVM_CFG_OPTION_INIT) 390438eabdf0SSudarsana Reddy Kalluru QED_MFW_SET_FIELD(mb_param, 390538eabdf0SSudarsana Reddy Kalluru DRV_MB_PARAM_NVM_CFG_OPTION_INIT, 1); 390638eabdf0SSudarsana Reddy Kalluru if (flags & QED_NVM_CFG_OPTION_COMMIT) 390738eabdf0SSudarsana Reddy Kalluru QED_MFW_SET_FIELD(mb_param, 390838eabdf0SSudarsana Reddy Kalluru DRV_MB_PARAM_NVM_CFG_OPTION_COMMIT, 1); 390938eabdf0SSudarsana Reddy Kalluru if (flags & QED_NVM_CFG_OPTION_FREE) 391038eabdf0SSudarsana Reddy Kalluru QED_MFW_SET_FIELD(mb_param, 391138eabdf0SSudarsana Reddy Kalluru DRV_MB_PARAM_NVM_CFG_OPTION_FREE, 1); 391238eabdf0SSudarsana Reddy Kalluru if (flags & QED_NVM_CFG_OPTION_ENTITY_SEL) { 391338eabdf0SSudarsana Reddy Kalluru QED_MFW_SET_FIELD(mb_param, 391438eabdf0SSudarsana Reddy Kalluru DRV_MB_PARAM_NVM_CFG_OPTION_ENTITY_SEL, 1); 391538eabdf0SSudarsana Reddy Kalluru QED_MFW_SET_FIELD(mb_param, 391638eabdf0SSudarsana Reddy Kalluru DRV_MB_PARAM_NVM_CFG_OPTION_ENTITY_ID, 391738eabdf0SSudarsana Reddy Kalluru entity_id); 391838eabdf0SSudarsana Reddy Kalluru } 391938eabdf0SSudarsana Reddy Kalluru 392038eabdf0SSudarsana Reddy Kalluru return qed_mcp_nvm_wr_cmd(p_hwfn, p_ptt, 392138eabdf0SSudarsana Reddy Kalluru DRV_MSG_CODE_SET_NVM_CFG_OPTION, 392238eabdf0SSudarsana Reddy Kalluru mb_param, &resp, ¶m, len, (u32 *)p_buf); 392338eabdf0SSudarsana Reddy Kalluru } 3924d8d6c5a7SIgor Russkikh 3925d8d6c5a7SIgor Russkikh #define QED_MCP_DBG_DATA_MAX_SIZE MCP_DRV_NVM_BUF_LEN 3926d8d6c5a7SIgor Russkikh #define QED_MCP_DBG_DATA_MAX_HEADER_SIZE sizeof(u32) 3927d8d6c5a7SIgor Russkikh #define QED_MCP_DBG_DATA_MAX_PAYLOAD_SIZE \ 3928d8d6c5a7SIgor Russkikh (QED_MCP_DBG_DATA_MAX_SIZE - QED_MCP_DBG_DATA_MAX_HEADER_SIZE) 3929d8d6c5a7SIgor Russkikh 3930d8d6c5a7SIgor Russkikh static int 3931d8d6c5a7SIgor Russkikh __qed_mcp_send_debug_data(struct qed_hwfn *p_hwfn, 3932d8d6c5a7SIgor Russkikh struct qed_ptt *p_ptt, u8 *p_buf, u8 size) 3933d8d6c5a7SIgor Russkikh { 3934d8d6c5a7SIgor Russkikh struct qed_mcp_mb_params mb_params; 3935d8d6c5a7SIgor Russkikh int rc; 3936d8d6c5a7SIgor Russkikh 3937d8d6c5a7SIgor Russkikh if (size > QED_MCP_DBG_DATA_MAX_SIZE) { 3938d8d6c5a7SIgor Russkikh DP_ERR(p_hwfn, 3939d8d6c5a7SIgor Russkikh "Debug data size is %d while it should not exceed %d\n", 3940d8d6c5a7SIgor Russkikh size, QED_MCP_DBG_DATA_MAX_SIZE); 3941d8d6c5a7SIgor Russkikh return -EINVAL; 3942d8d6c5a7SIgor Russkikh } 3943d8d6c5a7SIgor Russkikh 3944d8d6c5a7SIgor Russkikh memset(&mb_params, 0, sizeof(mb_params)); 3945d8d6c5a7SIgor Russkikh mb_params.cmd = DRV_MSG_CODE_DEBUG_DATA_SEND; 3946d8d6c5a7SIgor Russkikh SET_MFW_FIELD(mb_params.param, DRV_MSG_CODE_DEBUG_DATA_SEND_SIZE, size); 3947d8d6c5a7SIgor Russkikh mb_params.p_data_src = p_buf; 3948d8d6c5a7SIgor Russkikh mb_params.data_src_size = size; 3949d8d6c5a7SIgor Russkikh rc = qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 3950d8d6c5a7SIgor Russkikh if (rc) 3951d8d6c5a7SIgor Russkikh return rc; 3952d8d6c5a7SIgor Russkikh 3953d8d6c5a7SIgor Russkikh if (mb_params.mcp_resp == FW_MSG_CODE_UNSUPPORTED) { 3954d8d6c5a7SIgor Russkikh DP_INFO(p_hwfn, 3955d8d6c5a7SIgor Russkikh "The DEBUG_DATA_SEND command is unsupported by the MFW\n"); 3956d8d6c5a7SIgor Russkikh return -EOPNOTSUPP; 3957d8d6c5a7SIgor Russkikh } else if (mb_params.mcp_resp == (u32)FW_MSG_CODE_DEBUG_NOT_ENABLED) { 3958d8d6c5a7SIgor Russkikh DP_INFO(p_hwfn, "The DEBUG_DATA_SEND command is not enabled\n"); 3959d8d6c5a7SIgor Russkikh return -EBUSY; 3960d8d6c5a7SIgor Russkikh } else if (mb_params.mcp_resp != (u32)FW_MSG_CODE_DEBUG_DATA_SEND_OK) { 3961d8d6c5a7SIgor Russkikh DP_NOTICE(p_hwfn, 3962d8d6c5a7SIgor Russkikh "Failed to send debug data to the MFW [resp 0x%08x]\n", 3963d8d6c5a7SIgor Russkikh mb_params.mcp_resp); 3964d8d6c5a7SIgor Russkikh return -EINVAL; 3965d8d6c5a7SIgor Russkikh } 3966d8d6c5a7SIgor Russkikh 3967d8d6c5a7SIgor Russkikh return 0; 3968d8d6c5a7SIgor Russkikh } 3969d8d6c5a7SIgor Russkikh 3970d8d6c5a7SIgor Russkikh enum qed_mcp_dbg_data_type { 3971d8d6c5a7SIgor Russkikh QED_MCP_DBG_DATA_TYPE_RAW, 3972d8d6c5a7SIgor Russkikh }; 3973d8d6c5a7SIgor Russkikh 3974d8d6c5a7SIgor Russkikh /* Header format: [31:28] PFID, [27:20] flags, [19:12] type, [11:0] S/N */ 3975d8d6c5a7SIgor Russkikh #define QED_MCP_DBG_DATA_HDR_SN_OFFSET 0 3976d8d6c5a7SIgor Russkikh #define QED_MCP_DBG_DATA_HDR_SN_MASK 0x00000fff 3977d8d6c5a7SIgor Russkikh #define QED_MCP_DBG_DATA_HDR_TYPE_OFFSET 12 3978d8d6c5a7SIgor Russkikh #define QED_MCP_DBG_DATA_HDR_TYPE_MASK 0x000ff000 3979d8d6c5a7SIgor Russkikh #define QED_MCP_DBG_DATA_HDR_FLAGS_OFFSET 20 3980d8d6c5a7SIgor Russkikh #define QED_MCP_DBG_DATA_HDR_FLAGS_MASK 0x0ff00000 3981d8d6c5a7SIgor Russkikh #define QED_MCP_DBG_DATA_HDR_PF_OFFSET 28 3982d8d6c5a7SIgor Russkikh #define QED_MCP_DBG_DATA_HDR_PF_MASK 0xf0000000 3983d8d6c5a7SIgor Russkikh 3984d8d6c5a7SIgor Russkikh #define QED_MCP_DBG_DATA_HDR_FLAGS_FIRST 0x1 3985d8d6c5a7SIgor Russkikh #define QED_MCP_DBG_DATA_HDR_FLAGS_LAST 0x2 3986d8d6c5a7SIgor Russkikh 3987d8d6c5a7SIgor Russkikh static int 3988d8d6c5a7SIgor Russkikh qed_mcp_send_debug_data(struct qed_hwfn *p_hwfn, 3989d8d6c5a7SIgor Russkikh struct qed_ptt *p_ptt, 3990d8d6c5a7SIgor Russkikh enum qed_mcp_dbg_data_type type, u8 *p_buf, u32 size) 3991d8d6c5a7SIgor Russkikh { 3992d8d6c5a7SIgor Russkikh u8 raw_data[QED_MCP_DBG_DATA_MAX_SIZE], *p_tmp_buf = p_buf; 3993d8d6c5a7SIgor Russkikh u32 tmp_size = size, *p_header, *p_payload; 3994d8d6c5a7SIgor Russkikh u8 flags = 0; 3995d8d6c5a7SIgor Russkikh u16 seq; 3996d8d6c5a7SIgor Russkikh int rc; 3997d8d6c5a7SIgor Russkikh 3998d8d6c5a7SIgor Russkikh p_header = (u32 *)raw_data; 3999d8d6c5a7SIgor Russkikh p_payload = (u32 *)(raw_data + QED_MCP_DBG_DATA_MAX_HEADER_SIZE); 4000d8d6c5a7SIgor Russkikh 4001d8d6c5a7SIgor Russkikh seq = (u16)atomic_inc_return(&p_hwfn->mcp_info->dbg_data_seq); 4002d8d6c5a7SIgor Russkikh 4003d8d6c5a7SIgor Russkikh /* First chunk is marked as 'first' */ 4004d8d6c5a7SIgor Russkikh flags |= QED_MCP_DBG_DATA_HDR_FLAGS_FIRST; 4005d8d6c5a7SIgor Russkikh 4006d8d6c5a7SIgor Russkikh *p_header = 0; 4007d8d6c5a7SIgor Russkikh SET_MFW_FIELD(*p_header, QED_MCP_DBG_DATA_HDR_SN, seq); 4008d8d6c5a7SIgor Russkikh SET_MFW_FIELD(*p_header, QED_MCP_DBG_DATA_HDR_TYPE, type); 4009d8d6c5a7SIgor Russkikh SET_MFW_FIELD(*p_header, QED_MCP_DBG_DATA_HDR_FLAGS, flags); 4010d8d6c5a7SIgor Russkikh SET_MFW_FIELD(*p_header, QED_MCP_DBG_DATA_HDR_PF, p_hwfn->abs_pf_id); 4011d8d6c5a7SIgor Russkikh 4012d8d6c5a7SIgor Russkikh while (tmp_size > QED_MCP_DBG_DATA_MAX_PAYLOAD_SIZE) { 4013d8d6c5a7SIgor Russkikh memcpy(p_payload, p_tmp_buf, QED_MCP_DBG_DATA_MAX_PAYLOAD_SIZE); 4014d8d6c5a7SIgor Russkikh rc = __qed_mcp_send_debug_data(p_hwfn, p_ptt, raw_data, 4015d8d6c5a7SIgor Russkikh QED_MCP_DBG_DATA_MAX_SIZE); 4016d8d6c5a7SIgor Russkikh if (rc) 4017d8d6c5a7SIgor Russkikh return rc; 4018d8d6c5a7SIgor Russkikh 4019d8d6c5a7SIgor Russkikh /* Clear the 'first' marking after sending the first chunk */ 4020d8d6c5a7SIgor Russkikh if (p_tmp_buf == p_buf) { 4021d8d6c5a7SIgor Russkikh flags &= ~QED_MCP_DBG_DATA_HDR_FLAGS_FIRST; 4022d8d6c5a7SIgor Russkikh SET_MFW_FIELD(*p_header, QED_MCP_DBG_DATA_HDR_FLAGS, 4023d8d6c5a7SIgor Russkikh flags); 4024d8d6c5a7SIgor Russkikh } 4025d8d6c5a7SIgor Russkikh 4026d8d6c5a7SIgor Russkikh p_tmp_buf += QED_MCP_DBG_DATA_MAX_PAYLOAD_SIZE; 4027d8d6c5a7SIgor Russkikh tmp_size -= QED_MCP_DBG_DATA_MAX_PAYLOAD_SIZE; 4028d8d6c5a7SIgor Russkikh } 4029d8d6c5a7SIgor Russkikh 4030d8d6c5a7SIgor Russkikh /* Last chunk is marked as 'last' */ 4031d8d6c5a7SIgor Russkikh flags |= QED_MCP_DBG_DATA_HDR_FLAGS_LAST; 4032d8d6c5a7SIgor Russkikh SET_MFW_FIELD(*p_header, QED_MCP_DBG_DATA_HDR_FLAGS, flags); 4033d8d6c5a7SIgor Russkikh memcpy(p_payload, p_tmp_buf, tmp_size); 4034d8d6c5a7SIgor Russkikh 4035d8d6c5a7SIgor Russkikh /* Casting the left size to u8 is ok since at this point it is <= 32 */ 4036d8d6c5a7SIgor Russkikh return __qed_mcp_send_debug_data(p_hwfn, p_ptt, raw_data, 4037d8d6c5a7SIgor Russkikh (u8)(QED_MCP_DBG_DATA_MAX_HEADER_SIZE + 4038d8d6c5a7SIgor Russkikh tmp_size)); 4039d8d6c5a7SIgor Russkikh } 4040d8d6c5a7SIgor Russkikh 4041d8d6c5a7SIgor Russkikh int 4042d8d6c5a7SIgor Russkikh qed_mcp_send_raw_debug_data(struct qed_hwfn *p_hwfn, 4043d8d6c5a7SIgor Russkikh struct qed_ptt *p_ptt, u8 *p_buf, u32 size) 4044d8d6c5a7SIgor Russkikh { 4045d8d6c5a7SIgor Russkikh return qed_mcp_send_debug_data(p_hwfn, p_ptt, 4046d8d6c5a7SIgor Russkikh QED_MCP_DBG_DATA_TYPE_RAW, p_buf, size); 4047d8d6c5a7SIgor Russkikh } 4048