1fe56b9e6SYuval Mintz /* QLogic qed NIC Driver 2e8f1cb50SMintz, Yuval * Copyright (c) 2015-2017 QLogic Corporation 3fe56b9e6SYuval Mintz * 4e8f1cb50SMintz, Yuval * This software is available to you under a choice of one of two 5e8f1cb50SMintz, Yuval * licenses. You may choose to be licensed under the terms of the GNU 6e8f1cb50SMintz, Yuval * General Public License (GPL) Version 2, available from the file 7e8f1cb50SMintz, Yuval * COPYING in the main directory of this source tree, or the 8e8f1cb50SMintz, Yuval * OpenIB.org BSD license below: 9e8f1cb50SMintz, Yuval * 10e8f1cb50SMintz, Yuval * Redistribution and use in source and binary forms, with or 11e8f1cb50SMintz, Yuval * without modification, are permitted provided that the following 12e8f1cb50SMintz, Yuval * conditions are met: 13e8f1cb50SMintz, Yuval * 14e8f1cb50SMintz, Yuval * - Redistributions of source code must retain the above 15e8f1cb50SMintz, Yuval * copyright notice, this list of conditions and the following 16e8f1cb50SMintz, Yuval * disclaimer. 17e8f1cb50SMintz, Yuval * 18e8f1cb50SMintz, Yuval * - Redistributions in binary form must reproduce the above 19e8f1cb50SMintz, Yuval * copyright notice, this list of conditions and the following 20e8f1cb50SMintz, Yuval * disclaimer in the documentation and /or other materials 21e8f1cb50SMintz, Yuval * provided with the distribution. 22e8f1cb50SMintz, Yuval * 23e8f1cb50SMintz, Yuval * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 24e8f1cb50SMintz, Yuval * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 25e8f1cb50SMintz, Yuval * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26e8f1cb50SMintz, Yuval * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 27e8f1cb50SMintz, Yuval * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 28e8f1cb50SMintz, Yuval * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 29e8f1cb50SMintz, Yuval * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 30e8f1cb50SMintz, Yuval * SOFTWARE. 31fe56b9e6SYuval Mintz */ 32fe56b9e6SYuval Mintz 33fe56b9e6SYuval Mintz #include <linux/types.h> 34fe56b9e6SYuval Mintz #include <asm/byteorder.h> 35fe56b9e6SYuval Mintz #include <linux/delay.h> 36fe56b9e6SYuval Mintz #include <linux/errno.h> 37fe56b9e6SYuval Mintz #include <linux/kernel.h> 38fe56b9e6SYuval Mintz #include <linux/slab.h> 395529bad9STomer Tayar #include <linux/spinlock.h> 40fe56b9e6SYuval Mintz #include <linux/string.h> 410fefbfbaSSudarsana Kalluru #include <linux/etherdevice.h> 42fe56b9e6SYuval Mintz #include "qed.h" 43cac6f691SSudarsana Reddy Kalluru #include "qed_cxt.h" 4439651abdSSudarsana Reddy Kalluru #include "qed_dcbx.h" 45fe56b9e6SYuval Mintz #include "qed_hsi.h" 46fe56b9e6SYuval Mintz #include "qed_hw.h" 47fe56b9e6SYuval Mintz #include "qed_mcp.h" 48fe56b9e6SYuval Mintz #include "qed_reg_addr.h" 491408cc1fSYuval Mintz #include "qed_sriov.h" 501408cc1fSYuval Mintz 510500a70dSMichal Kalderon #define GRCBASE_MCP 0xe00000 520500a70dSMichal Kalderon 53eaa50fc5STomer Tayar #define QED_MCP_RESP_ITER_US 10 54fe56b9e6SYuval Mintz 55fe56b9e6SYuval Mintz #define QED_DRV_MB_MAX_RETRIES (500 * 1000) /* Account for 5 sec */ 56fe56b9e6SYuval Mintz #define QED_MCP_RESET_RETRIES (50 * 1000) /* Account for 500 msec */ 57fe56b9e6SYuval Mintz 58fe56b9e6SYuval Mintz #define DRV_INNER_WR(_p_hwfn, _p_ptt, _ptr, _offset, _val) \ 59fe56b9e6SYuval Mintz qed_wr(_p_hwfn, _p_ptt, (_p_hwfn->mcp_info->_ptr + _offset), \ 60fe56b9e6SYuval Mintz _val) 61fe56b9e6SYuval Mintz 62fe56b9e6SYuval Mintz #define DRV_INNER_RD(_p_hwfn, _p_ptt, _ptr, _offset) \ 63fe56b9e6SYuval Mintz qed_rd(_p_hwfn, _p_ptt, (_p_hwfn->mcp_info->_ptr + _offset)) 64fe56b9e6SYuval Mintz 65fe56b9e6SYuval Mintz #define DRV_MB_WR(_p_hwfn, _p_ptt, _field, _val) \ 66fe56b9e6SYuval Mintz DRV_INNER_WR(p_hwfn, _p_ptt, drv_mb_addr, \ 67fe56b9e6SYuval Mintz offsetof(struct public_drv_mb, _field), _val) 68fe56b9e6SYuval Mintz 69fe56b9e6SYuval Mintz #define DRV_MB_RD(_p_hwfn, _p_ptt, _field) \ 70fe56b9e6SYuval Mintz DRV_INNER_RD(_p_hwfn, _p_ptt, drv_mb_addr, \ 71fe56b9e6SYuval Mintz offsetof(struct public_drv_mb, _field)) 72fe56b9e6SYuval Mintz 73fe56b9e6SYuval Mintz #define PDA_COMP (((FW_MAJOR_VERSION) + (FW_MINOR_VERSION << 8)) << \ 74fe56b9e6SYuval Mintz DRV_ID_PDA_COMP_VER_SHIFT) 75fe56b9e6SYuval Mintz 76fe56b9e6SYuval Mintz #define MCP_BYTES_PER_MBIT_SHIFT 17 77fe56b9e6SYuval Mintz 78fe56b9e6SYuval Mintz bool qed_mcp_is_init(struct qed_hwfn *p_hwfn) 79fe56b9e6SYuval Mintz { 80fe56b9e6SYuval Mintz if (!p_hwfn->mcp_info || !p_hwfn->mcp_info->public_base) 81fe56b9e6SYuval Mintz return false; 82fe56b9e6SYuval Mintz return true; 83fe56b9e6SYuval Mintz } 84fe56b9e6SYuval Mintz 851a635e48SYuval Mintz void qed_mcp_cmd_port_init(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 86fe56b9e6SYuval Mintz { 87fe56b9e6SYuval Mintz u32 addr = SECTION_OFFSIZE_ADDR(p_hwfn->mcp_info->public_base, 88fe56b9e6SYuval Mintz PUBLIC_PORT); 89fe56b9e6SYuval Mintz u32 mfw_mb_offsize = qed_rd(p_hwfn, p_ptt, addr); 90fe56b9e6SYuval Mintz 91fe56b9e6SYuval Mintz p_hwfn->mcp_info->port_addr = SECTION_ADDR(mfw_mb_offsize, 92fe56b9e6SYuval Mintz MFW_PORT(p_hwfn)); 93fe56b9e6SYuval Mintz DP_VERBOSE(p_hwfn, QED_MSG_SP, 94fe56b9e6SYuval Mintz "port_addr = 0x%x, port_id 0x%02x\n", 95fe56b9e6SYuval Mintz p_hwfn->mcp_info->port_addr, MFW_PORT(p_hwfn)); 96fe56b9e6SYuval Mintz } 97fe56b9e6SYuval Mintz 981a635e48SYuval Mintz void qed_mcp_read_mb(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 99fe56b9e6SYuval Mintz { 100fe56b9e6SYuval Mintz u32 length = MFW_DRV_MSG_MAX_DWORDS(p_hwfn->mcp_info->mfw_mb_length); 101fe56b9e6SYuval Mintz u32 tmp, i; 102fe56b9e6SYuval Mintz 103fe56b9e6SYuval Mintz if (!p_hwfn->mcp_info->public_base) 104fe56b9e6SYuval Mintz return; 105fe56b9e6SYuval Mintz 106fe56b9e6SYuval Mintz for (i = 0; i < length; i++) { 107fe56b9e6SYuval Mintz tmp = qed_rd(p_hwfn, p_ptt, 108fe56b9e6SYuval Mintz p_hwfn->mcp_info->mfw_mb_addr + 109fe56b9e6SYuval Mintz (i << 2) + sizeof(u32)); 110fe56b9e6SYuval Mintz 111fe56b9e6SYuval Mintz /* The MB data is actually BE; Need to force it to cpu */ 112fe56b9e6SYuval Mintz ((u32 *)p_hwfn->mcp_info->mfw_mb_cur)[i] = 113fe56b9e6SYuval Mintz be32_to_cpu((__force __be32)tmp); 114fe56b9e6SYuval Mintz } 115fe56b9e6SYuval Mintz } 116fe56b9e6SYuval Mintz 1174ed1eea8STomer Tayar struct qed_mcp_cmd_elem { 1184ed1eea8STomer Tayar struct list_head list; 1194ed1eea8STomer Tayar struct qed_mcp_mb_params *p_mb_params; 1204ed1eea8STomer Tayar u16 expected_seq_num; 1214ed1eea8STomer Tayar bool b_is_completed; 1224ed1eea8STomer Tayar }; 1234ed1eea8STomer Tayar 1244ed1eea8STomer Tayar /* Must be called while cmd_lock is acquired */ 1254ed1eea8STomer Tayar static struct qed_mcp_cmd_elem * 1264ed1eea8STomer Tayar qed_mcp_cmd_add_elem(struct qed_hwfn *p_hwfn, 1274ed1eea8STomer Tayar struct qed_mcp_mb_params *p_mb_params, 1284ed1eea8STomer Tayar u16 expected_seq_num) 1294ed1eea8STomer Tayar { 1304ed1eea8STomer Tayar struct qed_mcp_cmd_elem *p_cmd_elem = NULL; 1314ed1eea8STomer Tayar 1324ed1eea8STomer Tayar p_cmd_elem = kzalloc(sizeof(*p_cmd_elem), GFP_ATOMIC); 1334ed1eea8STomer Tayar if (!p_cmd_elem) 1344ed1eea8STomer Tayar goto out; 1354ed1eea8STomer Tayar 1364ed1eea8STomer Tayar p_cmd_elem->p_mb_params = p_mb_params; 1374ed1eea8STomer Tayar p_cmd_elem->expected_seq_num = expected_seq_num; 1384ed1eea8STomer Tayar list_add(&p_cmd_elem->list, &p_hwfn->mcp_info->cmd_list); 1394ed1eea8STomer Tayar out: 1404ed1eea8STomer Tayar return p_cmd_elem; 1414ed1eea8STomer Tayar } 1424ed1eea8STomer Tayar 1434ed1eea8STomer Tayar /* Must be called while cmd_lock is acquired */ 1444ed1eea8STomer Tayar static void qed_mcp_cmd_del_elem(struct qed_hwfn *p_hwfn, 1454ed1eea8STomer Tayar struct qed_mcp_cmd_elem *p_cmd_elem) 1464ed1eea8STomer Tayar { 1474ed1eea8STomer Tayar list_del(&p_cmd_elem->list); 1484ed1eea8STomer Tayar kfree(p_cmd_elem); 1494ed1eea8STomer Tayar } 1504ed1eea8STomer Tayar 1514ed1eea8STomer Tayar /* Must be called while cmd_lock is acquired */ 1524ed1eea8STomer Tayar static struct qed_mcp_cmd_elem *qed_mcp_cmd_get_elem(struct qed_hwfn *p_hwfn, 1534ed1eea8STomer Tayar u16 seq_num) 1544ed1eea8STomer Tayar { 1554ed1eea8STomer Tayar struct qed_mcp_cmd_elem *p_cmd_elem = NULL; 1564ed1eea8STomer Tayar 1574ed1eea8STomer Tayar list_for_each_entry(p_cmd_elem, &p_hwfn->mcp_info->cmd_list, list) { 1584ed1eea8STomer Tayar if (p_cmd_elem->expected_seq_num == seq_num) 1594ed1eea8STomer Tayar return p_cmd_elem; 1604ed1eea8STomer Tayar } 1614ed1eea8STomer Tayar 1624ed1eea8STomer Tayar return NULL; 1634ed1eea8STomer Tayar } 1644ed1eea8STomer Tayar 165fe56b9e6SYuval Mintz int qed_mcp_free(struct qed_hwfn *p_hwfn) 166fe56b9e6SYuval Mintz { 167fe56b9e6SYuval Mintz if (p_hwfn->mcp_info) { 1684ed1eea8STomer Tayar struct qed_mcp_cmd_elem *p_cmd_elem, *p_tmp; 1694ed1eea8STomer Tayar 170fe56b9e6SYuval Mintz kfree(p_hwfn->mcp_info->mfw_mb_cur); 171fe56b9e6SYuval Mintz kfree(p_hwfn->mcp_info->mfw_mb_shadow); 1724ed1eea8STomer Tayar 1734ed1eea8STomer Tayar spin_lock_bh(&p_hwfn->mcp_info->cmd_lock); 1744ed1eea8STomer Tayar list_for_each_entry_safe(p_cmd_elem, 1754ed1eea8STomer Tayar p_tmp, 1764ed1eea8STomer Tayar &p_hwfn->mcp_info->cmd_list, list) { 1774ed1eea8STomer Tayar qed_mcp_cmd_del_elem(p_hwfn, p_cmd_elem); 178fe56b9e6SYuval Mintz } 1794ed1eea8STomer Tayar spin_unlock_bh(&p_hwfn->mcp_info->cmd_lock); 1804ed1eea8STomer Tayar } 1814ed1eea8STomer Tayar 182fe56b9e6SYuval Mintz kfree(p_hwfn->mcp_info); 1833587cb87STomer Tayar p_hwfn->mcp_info = NULL; 184fe56b9e6SYuval Mintz 185fe56b9e6SYuval Mintz return 0; 186fe56b9e6SYuval Mintz } 187fe56b9e6SYuval Mintz 188f00d25f3STomer Tayar /* Maximum of 1 sec to wait for the SHMEM ready indication */ 189f00d25f3STomer Tayar #define QED_MCP_SHMEM_RDY_MAX_RETRIES 20 190f00d25f3STomer Tayar #define QED_MCP_SHMEM_RDY_ITER_MS 50 191f00d25f3STomer Tayar 1921a635e48SYuval Mintz static int qed_load_mcp_offsets(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 193fe56b9e6SYuval Mintz { 194fe56b9e6SYuval Mintz struct qed_mcp_info *p_info = p_hwfn->mcp_info; 195f00d25f3STomer Tayar u8 cnt = QED_MCP_SHMEM_RDY_MAX_RETRIES; 196f00d25f3STomer Tayar u8 msec = QED_MCP_SHMEM_RDY_ITER_MS; 197fe56b9e6SYuval Mintz u32 drv_mb_offsize, mfw_mb_offsize; 198fe56b9e6SYuval Mintz u32 mcp_pf_id = MCP_PF_ID(p_hwfn); 199fe56b9e6SYuval Mintz 200fe56b9e6SYuval Mintz p_info->public_base = qed_rd(p_hwfn, p_ptt, MISC_REG_SHARED_MEM_ADDR); 201f00d25f3STomer Tayar if (!p_info->public_base) { 202f00d25f3STomer Tayar DP_NOTICE(p_hwfn, 203f00d25f3STomer Tayar "The address of the MCP scratch-pad is not configured\n"); 204f00d25f3STomer Tayar return -EINVAL; 205f00d25f3STomer Tayar } 206fe56b9e6SYuval Mintz 207fe56b9e6SYuval Mintz p_info->public_base |= GRCBASE_MCP; 208fe56b9e6SYuval Mintz 209f00d25f3STomer Tayar /* Get the MFW MB address and number of supported messages */ 210f00d25f3STomer Tayar mfw_mb_offsize = qed_rd(p_hwfn, p_ptt, 211f00d25f3STomer Tayar SECTION_OFFSIZE_ADDR(p_info->public_base, 212f00d25f3STomer Tayar PUBLIC_MFW_MB)); 213f00d25f3STomer Tayar p_info->mfw_mb_addr = SECTION_ADDR(mfw_mb_offsize, mcp_pf_id); 214f00d25f3STomer Tayar p_info->mfw_mb_length = (u16)qed_rd(p_hwfn, p_ptt, 215f00d25f3STomer Tayar p_info->mfw_mb_addr + 216f00d25f3STomer Tayar offsetof(struct public_mfw_mb, 217f00d25f3STomer Tayar sup_msgs)); 218f00d25f3STomer Tayar 219f00d25f3STomer Tayar /* The driver can notify that there was an MCP reset, and might read the 220f00d25f3STomer Tayar * SHMEM values before the MFW has completed initializing them. 221f00d25f3STomer Tayar * To avoid this, the "sup_msgs" field in the MFW mailbox is used as a 222f00d25f3STomer Tayar * data ready indication. 223f00d25f3STomer Tayar */ 224f00d25f3STomer Tayar while (!p_info->mfw_mb_length && --cnt) { 225f00d25f3STomer Tayar msleep(msec); 226f00d25f3STomer Tayar p_info->mfw_mb_length = 227f00d25f3STomer Tayar (u16)qed_rd(p_hwfn, p_ptt, 228f00d25f3STomer Tayar p_info->mfw_mb_addr + 229f00d25f3STomer Tayar offsetof(struct public_mfw_mb, sup_msgs)); 230f00d25f3STomer Tayar } 231f00d25f3STomer Tayar 232f00d25f3STomer Tayar if (!cnt) { 233f00d25f3STomer Tayar DP_NOTICE(p_hwfn, 234f00d25f3STomer Tayar "Failed to get the SHMEM ready notification after %d msec\n", 235f00d25f3STomer Tayar QED_MCP_SHMEM_RDY_MAX_RETRIES * msec); 236f00d25f3STomer Tayar return -EBUSY; 237f00d25f3STomer Tayar } 238f00d25f3STomer Tayar 239fe56b9e6SYuval Mintz /* Calculate the driver and MFW mailbox address */ 240fe56b9e6SYuval Mintz drv_mb_offsize = qed_rd(p_hwfn, p_ptt, 241fe56b9e6SYuval Mintz SECTION_OFFSIZE_ADDR(p_info->public_base, 242fe56b9e6SYuval Mintz PUBLIC_DRV_MB)); 243fe56b9e6SYuval Mintz p_info->drv_mb_addr = SECTION_ADDR(drv_mb_offsize, mcp_pf_id); 244fe56b9e6SYuval Mintz DP_VERBOSE(p_hwfn, QED_MSG_SP, 245fe56b9e6SYuval Mintz "drv_mb_offsiz = 0x%x, drv_mb_addr = 0x%x mcp_pf_id = 0x%x\n", 246fe56b9e6SYuval Mintz drv_mb_offsize, p_info->drv_mb_addr, mcp_pf_id); 247fe56b9e6SYuval Mintz 248fe56b9e6SYuval Mintz /* Get the current driver mailbox sequence before sending 249fe56b9e6SYuval Mintz * the first command 250fe56b9e6SYuval Mintz */ 251fe56b9e6SYuval Mintz p_info->drv_mb_seq = DRV_MB_RD(p_hwfn, p_ptt, drv_mb_header) & 252fe56b9e6SYuval Mintz DRV_MSG_SEQ_NUMBER_MASK; 253fe56b9e6SYuval Mintz 254fe56b9e6SYuval Mintz /* Get current FW pulse sequence */ 255fe56b9e6SYuval Mintz p_info->drv_pulse_seq = DRV_MB_RD(p_hwfn, p_ptt, drv_pulse_mb) & 256fe56b9e6SYuval Mintz DRV_PULSE_SEQ_MASK; 257fe56b9e6SYuval Mintz 2584ed1eea8STomer Tayar p_info->mcp_hist = qed_rd(p_hwfn, p_ptt, MISCS_REG_GENERIC_POR_0); 259fe56b9e6SYuval Mintz 260fe56b9e6SYuval Mintz return 0; 261fe56b9e6SYuval Mintz } 262fe56b9e6SYuval Mintz 2631a635e48SYuval Mintz int qed_mcp_cmd_init(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 264fe56b9e6SYuval Mintz { 265fe56b9e6SYuval Mintz struct qed_mcp_info *p_info; 266fe56b9e6SYuval Mintz u32 size; 267fe56b9e6SYuval Mintz 268fe56b9e6SYuval Mintz /* Allocate mcp_info structure */ 26960fffb3bSYuval Mintz p_hwfn->mcp_info = kzalloc(sizeof(*p_hwfn->mcp_info), GFP_KERNEL); 270fe56b9e6SYuval Mintz if (!p_hwfn->mcp_info) 271fe56b9e6SYuval Mintz goto err; 272fe56b9e6SYuval Mintz p_info = p_hwfn->mcp_info; 273fe56b9e6SYuval Mintz 2744ed1eea8STomer Tayar /* Initialize the MFW spinlock */ 2754ed1eea8STomer Tayar spin_lock_init(&p_info->cmd_lock); 2764ed1eea8STomer Tayar spin_lock_init(&p_info->link_lock); 2774ed1eea8STomer Tayar 2784ed1eea8STomer Tayar INIT_LIST_HEAD(&p_info->cmd_list); 2794ed1eea8STomer Tayar 280fe56b9e6SYuval Mintz if (qed_load_mcp_offsets(p_hwfn, p_ptt) != 0) { 281fe56b9e6SYuval Mintz DP_NOTICE(p_hwfn, "MCP is not initialized\n"); 282fe56b9e6SYuval Mintz /* Do not free mcp_info here, since public_base indicate that 283fe56b9e6SYuval Mintz * the MCP is not initialized 284fe56b9e6SYuval Mintz */ 285fe56b9e6SYuval Mintz return 0; 286fe56b9e6SYuval Mintz } 287fe56b9e6SYuval Mintz 288fe56b9e6SYuval Mintz size = MFW_DRV_MSG_MAX_DWORDS(p_info->mfw_mb_length) * sizeof(u32); 28960fffb3bSYuval Mintz p_info->mfw_mb_cur = kzalloc(size, GFP_KERNEL); 29083aeb933SYuval Mintz p_info->mfw_mb_shadow = kzalloc(size, GFP_KERNEL); 291eb2a6b80SChristophe Jaillet if (!p_info->mfw_mb_cur || !p_info->mfw_mb_shadow) 292fe56b9e6SYuval Mintz goto err; 293fe56b9e6SYuval Mintz 294fe56b9e6SYuval Mintz return 0; 295fe56b9e6SYuval Mintz 296fe56b9e6SYuval Mintz err: 297fe56b9e6SYuval Mintz qed_mcp_free(p_hwfn); 298fe56b9e6SYuval Mintz return -ENOMEM; 299fe56b9e6SYuval Mintz } 300fe56b9e6SYuval Mintz 3014ed1eea8STomer Tayar static void qed_mcp_reread_offsets(struct qed_hwfn *p_hwfn, 3024ed1eea8STomer Tayar struct qed_ptt *p_ptt) 3035529bad9STomer Tayar { 3044ed1eea8STomer Tayar u32 generic_por_0 = qed_rd(p_hwfn, p_ptt, MISCS_REG_GENERIC_POR_0); 3055529bad9STomer Tayar 3064ed1eea8STomer Tayar /* Use MCP history register to check if MCP reset occurred between init 3074ed1eea8STomer Tayar * time and now. 3085529bad9STomer Tayar */ 3094ed1eea8STomer Tayar if (p_hwfn->mcp_info->mcp_hist != generic_por_0) { 3104ed1eea8STomer Tayar DP_VERBOSE(p_hwfn, 3114ed1eea8STomer Tayar QED_MSG_SP, 3124ed1eea8STomer Tayar "Rereading MCP offsets [mcp_hist 0x%08x, generic_por_0 0x%08x]\n", 3134ed1eea8STomer Tayar p_hwfn->mcp_info->mcp_hist, generic_por_0); 3145529bad9STomer Tayar 3154ed1eea8STomer Tayar qed_load_mcp_offsets(p_hwfn, p_ptt); 3164ed1eea8STomer Tayar qed_mcp_cmd_port_init(p_hwfn, p_ptt); 3175529bad9STomer Tayar } 3185529bad9STomer Tayar } 3195529bad9STomer Tayar 3201a635e48SYuval Mintz int qed_mcp_reset(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 321fe56b9e6SYuval Mintz { 322eaa50fc5STomer Tayar u32 org_mcp_reset_seq, seq, delay = QED_MCP_RESP_ITER_US, cnt = 0; 323fe56b9e6SYuval Mintz int rc = 0; 324fe56b9e6SYuval Mintz 325b310974eSTomer Tayar if (p_hwfn->mcp_info->b_block_cmd) { 326b310974eSTomer Tayar DP_NOTICE(p_hwfn, 327b310974eSTomer Tayar "The MFW is not responsive. Avoid sending MCP_RESET mailbox command.\n"); 328b310974eSTomer Tayar return -EBUSY; 329b310974eSTomer Tayar } 330b310974eSTomer Tayar 3314ed1eea8STomer Tayar /* Ensure that only a single thread is accessing the mailbox */ 3324ed1eea8STomer Tayar spin_lock_bh(&p_hwfn->mcp_info->cmd_lock); 3334ed1eea8STomer Tayar 3344ed1eea8STomer Tayar org_mcp_reset_seq = qed_rd(p_hwfn, p_ptt, MISCS_REG_GENERIC_POR_0); 3355529bad9STomer Tayar 336fe56b9e6SYuval Mintz /* Set drv command along with the updated sequence */ 3374ed1eea8STomer Tayar qed_mcp_reread_offsets(p_hwfn, p_ptt); 3384ed1eea8STomer Tayar seq = ++p_hwfn->mcp_info->drv_mb_seq; 3394ed1eea8STomer Tayar DRV_MB_WR(p_hwfn, p_ptt, drv_mb_header, (DRV_MSG_CODE_MCP_RESET | seq)); 340fe56b9e6SYuval Mintz 341fe56b9e6SYuval Mintz do { 342fe56b9e6SYuval Mintz /* Wait for MFW response */ 343fe56b9e6SYuval Mintz udelay(delay); 344fe56b9e6SYuval Mintz /* Give the FW up to 500 second (50*1000*10usec) */ 345fe56b9e6SYuval Mintz } while ((org_mcp_reset_seq == qed_rd(p_hwfn, p_ptt, 346fe56b9e6SYuval Mintz MISCS_REG_GENERIC_POR_0)) && 347fe56b9e6SYuval Mintz (cnt++ < QED_MCP_RESET_RETRIES)); 348fe56b9e6SYuval Mintz 349fe56b9e6SYuval Mintz if (org_mcp_reset_seq != 350fe56b9e6SYuval Mintz qed_rd(p_hwfn, p_ptt, MISCS_REG_GENERIC_POR_0)) { 351fe56b9e6SYuval Mintz DP_VERBOSE(p_hwfn, QED_MSG_SP, 352fe56b9e6SYuval Mintz "MCP was reset after %d usec\n", cnt * delay); 353fe56b9e6SYuval Mintz } else { 354fe56b9e6SYuval Mintz DP_ERR(p_hwfn, "Failed to reset MCP\n"); 355fe56b9e6SYuval Mintz rc = -EAGAIN; 356fe56b9e6SYuval Mintz } 357fe56b9e6SYuval Mintz 3584ed1eea8STomer Tayar spin_unlock_bh(&p_hwfn->mcp_info->cmd_lock); 3595529bad9STomer Tayar 360fe56b9e6SYuval Mintz return rc; 361fe56b9e6SYuval Mintz } 362fe56b9e6SYuval Mintz 3634ed1eea8STomer Tayar /* Must be called while cmd_lock is acquired */ 3644ed1eea8STomer Tayar static bool qed_mcp_has_pending_cmd(struct qed_hwfn *p_hwfn) 365fe56b9e6SYuval Mintz { 3664ed1eea8STomer Tayar struct qed_mcp_cmd_elem *p_cmd_elem; 3674ed1eea8STomer Tayar 3684ed1eea8STomer Tayar /* There is at most one pending command at a certain time, and if it 3694ed1eea8STomer Tayar * exists - it is placed at the HEAD of the list. 3704ed1eea8STomer Tayar */ 3714ed1eea8STomer Tayar if (!list_empty(&p_hwfn->mcp_info->cmd_list)) { 3724ed1eea8STomer Tayar p_cmd_elem = list_first_entry(&p_hwfn->mcp_info->cmd_list, 3734ed1eea8STomer Tayar struct qed_mcp_cmd_elem, list); 3744ed1eea8STomer Tayar return !p_cmd_elem->b_is_completed; 3754ed1eea8STomer Tayar } 3764ed1eea8STomer Tayar 3774ed1eea8STomer Tayar return false; 3784ed1eea8STomer Tayar } 3794ed1eea8STomer Tayar 3804ed1eea8STomer Tayar /* Must be called while cmd_lock is acquired */ 3814ed1eea8STomer Tayar static int 3824ed1eea8STomer Tayar qed_mcp_update_pending_cmd(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 3834ed1eea8STomer Tayar { 3844ed1eea8STomer Tayar struct qed_mcp_mb_params *p_mb_params; 3854ed1eea8STomer Tayar struct qed_mcp_cmd_elem *p_cmd_elem; 3864ed1eea8STomer Tayar u32 mcp_resp; 3874ed1eea8STomer Tayar u16 seq_num; 3884ed1eea8STomer Tayar 3894ed1eea8STomer Tayar mcp_resp = DRV_MB_RD(p_hwfn, p_ptt, fw_mb_header); 3904ed1eea8STomer Tayar seq_num = (u16)(mcp_resp & FW_MSG_SEQ_NUMBER_MASK); 3914ed1eea8STomer Tayar 3924ed1eea8STomer Tayar /* Return if no new non-handled response has been received */ 3934ed1eea8STomer Tayar if (seq_num != p_hwfn->mcp_info->drv_mb_seq) 3944ed1eea8STomer Tayar return -EAGAIN; 3954ed1eea8STomer Tayar 3964ed1eea8STomer Tayar p_cmd_elem = qed_mcp_cmd_get_elem(p_hwfn, seq_num); 3974ed1eea8STomer Tayar if (!p_cmd_elem) { 3984ed1eea8STomer Tayar DP_ERR(p_hwfn, 3994ed1eea8STomer Tayar "Failed to find a pending mailbox cmd that expects sequence number %d\n", 4004ed1eea8STomer Tayar seq_num); 4014ed1eea8STomer Tayar return -EINVAL; 4024ed1eea8STomer Tayar } 4034ed1eea8STomer Tayar 4044ed1eea8STomer Tayar p_mb_params = p_cmd_elem->p_mb_params; 4054ed1eea8STomer Tayar 4064ed1eea8STomer Tayar /* Get the MFW response along with the sequence number */ 4074ed1eea8STomer Tayar p_mb_params->mcp_resp = mcp_resp; 4084ed1eea8STomer Tayar 4094ed1eea8STomer Tayar /* Get the MFW param */ 4104ed1eea8STomer Tayar p_mb_params->mcp_param = DRV_MB_RD(p_hwfn, p_ptt, fw_mb_param); 4114ed1eea8STomer Tayar 4124ed1eea8STomer Tayar /* Get the union data */ 4132f67af8cSTomer Tayar if (p_mb_params->p_data_dst != NULL && p_mb_params->data_dst_size) { 4144ed1eea8STomer Tayar u32 union_data_addr = p_hwfn->mcp_info->drv_mb_addr + 4154ed1eea8STomer Tayar offsetof(struct public_drv_mb, 4164ed1eea8STomer Tayar union_data); 4174ed1eea8STomer Tayar qed_memcpy_from(p_hwfn, p_ptt, p_mb_params->p_data_dst, 4182f67af8cSTomer Tayar union_data_addr, p_mb_params->data_dst_size); 4194ed1eea8STomer Tayar } 4204ed1eea8STomer Tayar 4214ed1eea8STomer Tayar p_cmd_elem->b_is_completed = true; 4224ed1eea8STomer Tayar 4234ed1eea8STomer Tayar return 0; 4244ed1eea8STomer Tayar } 4254ed1eea8STomer Tayar 4264ed1eea8STomer Tayar /* Must be called while cmd_lock is acquired */ 4274ed1eea8STomer Tayar static void __qed_mcp_cmd_and_union(struct qed_hwfn *p_hwfn, 4284ed1eea8STomer Tayar struct qed_ptt *p_ptt, 4294ed1eea8STomer Tayar struct qed_mcp_mb_params *p_mb_params, 4304ed1eea8STomer Tayar u16 seq_num) 4314ed1eea8STomer Tayar { 4324ed1eea8STomer Tayar union drv_union_data union_data; 4334ed1eea8STomer Tayar u32 union_data_addr; 4344ed1eea8STomer Tayar 4354ed1eea8STomer Tayar /* Set the union data */ 4364ed1eea8STomer Tayar union_data_addr = p_hwfn->mcp_info->drv_mb_addr + 4374ed1eea8STomer Tayar offsetof(struct public_drv_mb, union_data); 4384ed1eea8STomer Tayar memset(&union_data, 0, sizeof(union_data)); 4392f67af8cSTomer Tayar if (p_mb_params->p_data_src != NULL && p_mb_params->data_src_size) 4404ed1eea8STomer Tayar memcpy(&union_data, p_mb_params->p_data_src, 4412f67af8cSTomer Tayar p_mb_params->data_src_size); 4424ed1eea8STomer Tayar qed_memcpy_to(p_hwfn, p_ptt, union_data_addr, &union_data, 4434ed1eea8STomer Tayar sizeof(union_data)); 4444ed1eea8STomer Tayar 4454ed1eea8STomer Tayar /* Set the drv param */ 4464ed1eea8STomer Tayar DRV_MB_WR(p_hwfn, p_ptt, drv_mb_param, p_mb_params->param); 4474ed1eea8STomer Tayar 4484ed1eea8STomer Tayar /* Set the drv command along with the sequence number */ 4494ed1eea8STomer Tayar DRV_MB_WR(p_hwfn, p_ptt, drv_mb_header, (p_mb_params->cmd | seq_num)); 4504ed1eea8STomer Tayar 4514ed1eea8STomer Tayar DP_VERBOSE(p_hwfn, QED_MSG_SP, 4524ed1eea8STomer Tayar "MFW mailbox: command 0x%08x param 0x%08x\n", 4534ed1eea8STomer Tayar (p_mb_params->cmd | seq_num), p_mb_params->param); 4544ed1eea8STomer Tayar } 4554ed1eea8STomer Tayar 456b310974eSTomer Tayar static void qed_mcp_cmd_set_blocking(struct qed_hwfn *p_hwfn, bool block_cmd) 457b310974eSTomer Tayar { 458b310974eSTomer Tayar p_hwfn->mcp_info->b_block_cmd = block_cmd; 459b310974eSTomer Tayar 460b310974eSTomer Tayar DP_INFO(p_hwfn, "%s sending of mailbox commands to the MFW\n", 461b310974eSTomer Tayar block_cmd ? "Block" : "Unblock"); 462b310974eSTomer Tayar } 463b310974eSTomer Tayar 464b310974eSTomer Tayar static void qed_mcp_print_cpu_info(struct qed_hwfn *p_hwfn, 465b310974eSTomer Tayar struct qed_ptt *p_ptt) 466b310974eSTomer Tayar { 467b310974eSTomer Tayar u32 cpu_mode, cpu_state, cpu_pc_0, cpu_pc_1, cpu_pc_2; 468b310974eSTomer Tayar u32 delay = QED_MCP_RESP_ITER_US; 469b310974eSTomer Tayar 470b310974eSTomer Tayar cpu_mode = qed_rd(p_hwfn, p_ptt, MCP_REG_CPU_MODE); 471b310974eSTomer Tayar cpu_state = qed_rd(p_hwfn, p_ptt, MCP_REG_CPU_STATE); 472b310974eSTomer Tayar cpu_pc_0 = qed_rd(p_hwfn, p_ptt, MCP_REG_CPU_PROGRAM_COUNTER); 473b310974eSTomer Tayar udelay(delay); 474b310974eSTomer Tayar cpu_pc_1 = qed_rd(p_hwfn, p_ptt, MCP_REG_CPU_PROGRAM_COUNTER); 475b310974eSTomer Tayar udelay(delay); 476b310974eSTomer Tayar cpu_pc_2 = qed_rd(p_hwfn, p_ptt, MCP_REG_CPU_PROGRAM_COUNTER); 477b310974eSTomer Tayar 478b310974eSTomer Tayar DP_NOTICE(p_hwfn, 479b310974eSTomer Tayar "MCP CPU info: mode 0x%08x, state 0x%08x, pc {0x%08x, 0x%08x, 0x%08x}\n", 480b310974eSTomer Tayar cpu_mode, cpu_state, cpu_pc_0, cpu_pc_1, cpu_pc_2); 481b310974eSTomer Tayar } 482b310974eSTomer Tayar 4834ed1eea8STomer Tayar static int 4844ed1eea8STomer Tayar _qed_mcp_cmd_and_union(struct qed_hwfn *p_hwfn, 4854ed1eea8STomer Tayar struct qed_ptt *p_ptt, 4864ed1eea8STomer Tayar struct qed_mcp_mb_params *p_mb_params, 487eaa50fc5STomer Tayar u32 max_retries, u32 usecs) 4884ed1eea8STomer Tayar { 489eaa50fc5STomer Tayar u32 cnt = 0, msecs = DIV_ROUND_UP(usecs, 1000); 4904ed1eea8STomer Tayar struct qed_mcp_cmd_elem *p_cmd_elem; 4914ed1eea8STomer Tayar u16 seq_num; 492fe56b9e6SYuval Mintz int rc = 0; 493fe56b9e6SYuval Mintz 4944ed1eea8STomer Tayar /* Wait until the mailbox is non-occupied */ 495fe56b9e6SYuval Mintz do { 4964ed1eea8STomer Tayar /* Exit the loop if there is no pending command, or if the 4974ed1eea8STomer Tayar * pending command is completed during this iteration. 4984ed1eea8STomer Tayar * The spinlock stays locked until the command is sent. 4994ed1eea8STomer Tayar */ 5004ed1eea8STomer Tayar 5014ed1eea8STomer Tayar spin_lock_bh(&p_hwfn->mcp_info->cmd_lock); 5024ed1eea8STomer Tayar 5034ed1eea8STomer Tayar if (!qed_mcp_has_pending_cmd(p_hwfn)) 5044ed1eea8STomer Tayar break; 5054ed1eea8STomer Tayar 5064ed1eea8STomer Tayar rc = qed_mcp_update_pending_cmd(p_hwfn, p_ptt); 5074ed1eea8STomer Tayar if (!rc) 5084ed1eea8STomer Tayar break; 5094ed1eea8STomer Tayar else if (rc != -EAGAIN) 5104ed1eea8STomer Tayar goto err; 5114ed1eea8STomer Tayar 5124ed1eea8STomer Tayar spin_unlock_bh(&p_hwfn->mcp_info->cmd_lock); 513eaa50fc5STomer Tayar 514eaa50fc5STomer Tayar if (QED_MB_FLAGS_IS_SET(p_mb_params, CAN_SLEEP)) 515eaa50fc5STomer Tayar msleep(msecs); 516eaa50fc5STomer Tayar else 517eaa50fc5STomer Tayar udelay(usecs); 5184ed1eea8STomer Tayar } while (++cnt < max_retries); 519fe56b9e6SYuval Mintz 5204ed1eea8STomer Tayar if (cnt >= max_retries) { 5214ed1eea8STomer Tayar DP_NOTICE(p_hwfn, 5224ed1eea8STomer Tayar "The MFW mailbox is occupied by an uncompleted command. Failed to send command 0x%08x [param 0x%08x].\n", 5234ed1eea8STomer Tayar p_mb_params->cmd, p_mb_params->param); 5244ed1eea8STomer Tayar return -EAGAIN; 525fe56b9e6SYuval Mintz } 5264ed1eea8STomer Tayar 5274ed1eea8STomer Tayar /* Send the mailbox command */ 5284ed1eea8STomer Tayar qed_mcp_reread_offsets(p_hwfn, p_ptt); 5294ed1eea8STomer Tayar seq_num = ++p_hwfn->mcp_info->drv_mb_seq; 5304ed1eea8STomer Tayar p_cmd_elem = qed_mcp_cmd_add_elem(p_hwfn, p_mb_params, seq_num); 531c8004600SDan Carpenter if (!p_cmd_elem) { 532c8004600SDan Carpenter rc = -ENOMEM; 5334ed1eea8STomer Tayar goto err; 534c8004600SDan Carpenter } 5354ed1eea8STomer Tayar 5364ed1eea8STomer Tayar __qed_mcp_cmd_and_union(p_hwfn, p_ptt, p_mb_params, seq_num); 5374ed1eea8STomer Tayar spin_unlock_bh(&p_hwfn->mcp_info->cmd_lock); 5384ed1eea8STomer Tayar 5394ed1eea8STomer Tayar /* Wait for the MFW response */ 5404ed1eea8STomer Tayar do { 5414ed1eea8STomer Tayar /* Exit the loop if the command is already completed, or if the 5424ed1eea8STomer Tayar * command is completed during this iteration. 5434ed1eea8STomer Tayar * The spinlock stays locked until the list element is removed. 5444ed1eea8STomer Tayar */ 5454ed1eea8STomer Tayar 546eaa50fc5STomer Tayar if (QED_MB_FLAGS_IS_SET(p_mb_params, CAN_SLEEP)) 547eaa50fc5STomer Tayar msleep(msecs); 548eaa50fc5STomer Tayar else 549eaa50fc5STomer Tayar udelay(usecs); 550eaa50fc5STomer Tayar 5514ed1eea8STomer Tayar spin_lock_bh(&p_hwfn->mcp_info->cmd_lock); 5524ed1eea8STomer Tayar 5534ed1eea8STomer Tayar if (p_cmd_elem->b_is_completed) 5544ed1eea8STomer Tayar break; 5554ed1eea8STomer Tayar 5564ed1eea8STomer Tayar rc = qed_mcp_update_pending_cmd(p_hwfn, p_ptt); 5574ed1eea8STomer Tayar if (!rc) 5584ed1eea8STomer Tayar break; 5594ed1eea8STomer Tayar else if (rc != -EAGAIN) 5604ed1eea8STomer Tayar goto err; 5614ed1eea8STomer Tayar 5624ed1eea8STomer Tayar spin_unlock_bh(&p_hwfn->mcp_info->cmd_lock); 5634ed1eea8STomer Tayar } while (++cnt < max_retries); 5644ed1eea8STomer Tayar 5654ed1eea8STomer Tayar if (cnt >= max_retries) { 5664ed1eea8STomer Tayar DP_NOTICE(p_hwfn, 5674ed1eea8STomer Tayar "The MFW failed to respond to command 0x%08x [param 0x%08x].\n", 5684ed1eea8STomer Tayar p_mb_params->cmd, p_mb_params->param); 569b310974eSTomer Tayar qed_mcp_print_cpu_info(p_hwfn, p_ptt); 5704ed1eea8STomer Tayar 5714ed1eea8STomer Tayar spin_lock_bh(&p_hwfn->mcp_info->cmd_lock); 5724ed1eea8STomer Tayar qed_mcp_cmd_del_elem(p_hwfn, p_cmd_elem); 5734ed1eea8STomer Tayar spin_unlock_bh(&p_hwfn->mcp_info->cmd_lock); 5744ed1eea8STomer Tayar 575b310974eSTomer Tayar if (!QED_MB_FLAGS_IS_SET(p_mb_params, AVOID_BLOCK)) 576b310974eSTomer Tayar qed_mcp_cmd_set_blocking(p_hwfn, true); 577b310974eSTomer Tayar 5782ec276d5SIgor Russkikh qed_hw_err_notify(p_hwfn, p_ptt, 5792ec276d5SIgor Russkikh QED_HW_ERR_MFW_RESP_FAIL, NULL); 5804ed1eea8STomer Tayar return -EAGAIN; 5814ed1eea8STomer Tayar } 5824ed1eea8STomer Tayar 5834ed1eea8STomer Tayar qed_mcp_cmd_del_elem(p_hwfn, p_cmd_elem); 5844ed1eea8STomer Tayar spin_unlock_bh(&p_hwfn->mcp_info->cmd_lock); 5854ed1eea8STomer Tayar 5864ed1eea8STomer Tayar DP_VERBOSE(p_hwfn, 5874ed1eea8STomer Tayar QED_MSG_SP, 5884ed1eea8STomer Tayar "MFW mailbox: response 0x%08x param 0x%08x [after %d.%03d ms]\n", 5894ed1eea8STomer Tayar p_mb_params->mcp_resp, 5904ed1eea8STomer Tayar p_mb_params->mcp_param, 591eaa50fc5STomer Tayar (cnt * usecs) / 1000, (cnt * usecs) % 1000); 5924ed1eea8STomer Tayar 5934ed1eea8STomer Tayar /* Clear the sequence number from the MFW response */ 5944ed1eea8STomer Tayar p_mb_params->mcp_resp &= FW_MSG_CODE_MASK; 5954ed1eea8STomer Tayar 5964ed1eea8STomer Tayar return 0; 5974ed1eea8STomer Tayar 5984ed1eea8STomer Tayar err: 5994ed1eea8STomer Tayar spin_unlock_bh(&p_hwfn->mcp_info->cmd_lock); 600fe56b9e6SYuval Mintz return rc; 601fe56b9e6SYuval Mintz } 602fe56b9e6SYuval Mintz 6035529bad9STomer Tayar static int qed_mcp_cmd_and_union(struct qed_hwfn *p_hwfn, 604fe56b9e6SYuval Mintz struct qed_ptt *p_ptt, 6055529bad9STomer Tayar struct qed_mcp_mb_params *p_mb_params) 606fe56b9e6SYuval Mintz { 6072f67af8cSTomer Tayar size_t union_data_size = sizeof(union drv_union_data); 6084ed1eea8STomer Tayar u32 max_retries = QED_DRV_MB_MAX_RETRIES; 609eaa50fc5STomer Tayar u32 usecs = QED_MCP_RESP_ITER_US; 610fe56b9e6SYuval Mintz 611fe56b9e6SYuval Mintz /* MCP not initialized */ 612fe56b9e6SYuval Mintz if (!qed_mcp_is_init(p_hwfn)) { 613fe56b9e6SYuval Mintz DP_NOTICE(p_hwfn, "MFW is not initialized!\n"); 614fe56b9e6SYuval Mintz return -EBUSY; 615fe56b9e6SYuval Mintz } 616fe56b9e6SYuval Mintz 617b310974eSTomer Tayar if (p_hwfn->mcp_info->b_block_cmd) { 618b310974eSTomer Tayar DP_NOTICE(p_hwfn, 619b310974eSTomer Tayar "The MFW is not responsive. Avoid sending mailbox command 0x%08x [param 0x%08x].\n", 620b310974eSTomer Tayar p_mb_params->cmd, p_mb_params->param); 621b310974eSTomer Tayar return -EBUSY; 622b310974eSTomer Tayar } 623b310974eSTomer Tayar 6242f67af8cSTomer Tayar if (p_mb_params->data_src_size > union_data_size || 6252f67af8cSTomer Tayar p_mb_params->data_dst_size > union_data_size) { 6262f67af8cSTomer Tayar DP_ERR(p_hwfn, 6272f67af8cSTomer Tayar "The provided size is larger than the union data size [src_size %u, dst_size %u, union_data_size %zu]\n", 6282f67af8cSTomer Tayar p_mb_params->data_src_size, 6292f67af8cSTomer Tayar p_mb_params->data_dst_size, union_data_size); 6302f67af8cSTomer Tayar return -EINVAL; 6312f67af8cSTomer Tayar } 6322f67af8cSTomer Tayar 633eaa50fc5STomer Tayar if (QED_MB_FLAGS_IS_SET(p_mb_params, CAN_SLEEP)) { 634eaa50fc5STomer Tayar max_retries = DIV_ROUND_UP(max_retries, 1000); 635eaa50fc5STomer Tayar usecs *= 1000; 636eaa50fc5STomer Tayar } 637eaa50fc5STomer Tayar 6384ed1eea8STomer Tayar return _qed_mcp_cmd_and_union(p_hwfn, p_ptt, p_mb_params, max_retries, 639eaa50fc5STomer Tayar usecs); 640fe56b9e6SYuval Mintz } 641fe56b9e6SYuval Mintz 6425529bad9STomer Tayar int qed_mcp_cmd(struct qed_hwfn *p_hwfn, 6435529bad9STomer Tayar struct qed_ptt *p_ptt, 6445529bad9STomer Tayar u32 cmd, 6455529bad9STomer Tayar u32 param, 6465529bad9STomer Tayar u32 *o_mcp_resp, 6475529bad9STomer Tayar u32 *o_mcp_param) 648fe56b9e6SYuval Mintz { 6495529bad9STomer Tayar struct qed_mcp_mb_params mb_params; 6505529bad9STomer Tayar int rc; 651fe56b9e6SYuval Mintz 6525529bad9STomer Tayar memset(&mb_params, 0, sizeof(mb_params)); 6535529bad9STomer Tayar mb_params.cmd = cmd; 6545529bad9STomer Tayar mb_params.param = param; 65514d39648SMintz, Yuval 6565529bad9STomer Tayar rc = qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 6575529bad9STomer Tayar if (rc) 6585529bad9STomer Tayar return rc; 6595529bad9STomer Tayar 6605529bad9STomer Tayar *o_mcp_resp = mb_params.mcp_resp; 6615529bad9STomer Tayar *o_mcp_param = mb_params.mcp_param; 6625529bad9STomer Tayar 6635529bad9STomer Tayar return 0; 664fe56b9e6SYuval Mintz } 665fe56b9e6SYuval Mintz 666bf774d14SYueHaibing static int 667bf774d14SYueHaibing qed_mcp_nvm_wr_cmd(struct qed_hwfn *p_hwfn, 66862e4d438SSudarsana Reddy Kalluru struct qed_ptt *p_ptt, 66962e4d438SSudarsana Reddy Kalluru u32 cmd, 67062e4d438SSudarsana Reddy Kalluru u32 param, 67162e4d438SSudarsana Reddy Kalluru u32 *o_mcp_resp, 67262e4d438SSudarsana Reddy Kalluru u32 *o_mcp_param, u32 i_txn_size, u32 *i_buf) 67362e4d438SSudarsana Reddy Kalluru { 67462e4d438SSudarsana Reddy Kalluru struct qed_mcp_mb_params mb_params; 67562e4d438SSudarsana Reddy Kalluru int rc; 67662e4d438SSudarsana Reddy Kalluru 67762e4d438SSudarsana Reddy Kalluru memset(&mb_params, 0, sizeof(mb_params)); 67862e4d438SSudarsana Reddy Kalluru mb_params.cmd = cmd; 67962e4d438SSudarsana Reddy Kalluru mb_params.param = param; 68062e4d438SSudarsana Reddy Kalluru mb_params.p_data_src = i_buf; 68162e4d438SSudarsana Reddy Kalluru mb_params.data_src_size = (u8)i_txn_size; 68262e4d438SSudarsana Reddy Kalluru rc = qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 68362e4d438SSudarsana Reddy Kalluru if (rc) 68462e4d438SSudarsana Reddy Kalluru return rc; 68562e4d438SSudarsana Reddy Kalluru 68662e4d438SSudarsana Reddy Kalluru *o_mcp_resp = mb_params.mcp_resp; 68762e4d438SSudarsana Reddy Kalluru *o_mcp_param = mb_params.mcp_param; 68862e4d438SSudarsana Reddy Kalluru 6895e7ba042SDenis Bolotin /* nvm_info needs to be updated */ 6905e7ba042SDenis Bolotin p_hwfn->nvm_info.valid = false; 6915e7ba042SDenis Bolotin 69262e4d438SSudarsana Reddy Kalluru return 0; 69362e4d438SSudarsana Reddy Kalluru } 69462e4d438SSudarsana Reddy Kalluru 6954102426fSTomer Tayar int qed_mcp_nvm_rd_cmd(struct qed_hwfn *p_hwfn, 6964102426fSTomer Tayar struct qed_ptt *p_ptt, 6974102426fSTomer Tayar u32 cmd, 6984102426fSTomer Tayar u32 param, 6994102426fSTomer Tayar u32 *o_mcp_resp, 7004102426fSTomer Tayar u32 *o_mcp_param, u32 *o_txn_size, u32 *o_buf) 7014102426fSTomer Tayar { 7024102426fSTomer Tayar struct qed_mcp_mb_params mb_params; 7032f67af8cSTomer Tayar u8 raw_data[MCP_DRV_NVM_BUF_LEN]; 7044102426fSTomer Tayar int rc; 7054102426fSTomer Tayar 7064102426fSTomer Tayar memset(&mb_params, 0, sizeof(mb_params)); 7074102426fSTomer Tayar mb_params.cmd = cmd; 7084102426fSTomer Tayar mb_params.param = param; 7092f67af8cSTomer Tayar mb_params.p_data_dst = raw_data; 7102f67af8cSTomer Tayar 7112f67af8cSTomer Tayar /* Use the maximal value since the actual one is part of the response */ 7122f67af8cSTomer Tayar mb_params.data_dst_size = MCP_DRV_NVM_BUF_LEN; 7132f67af8cSTomer Tayar 7144102426fSTomer Tayar rc = qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 7154102426fSTomer Tayar if (rc) 7164102426fSTomer Tayar return rc; 7174102426fSTomer Tayar 7184102426fSTomer Tayar *o_mcp_resp = mb_params.mcp_resp; 7194102426fSTomer Tayar *o_mcp_param = mb_params.mcp_param; 7204102426fSTomer Tayar 7214102426fSTomer Tayar *o_txn_size = *o_mcp_param; 7222f67af8cSTomer Tayar memcpy(o_buf, raw_data, *o_txn_size); 7234102426fSTomer Tayar 7244102426fSTomer Tayar return 0; 7254102426fSTomer Tayar } 7264102426fSTomer Tayar 7275d24bcf1STomer Tayar static bool 7285d24bcf1STomer Tayar qed_mcp_can_force_load(u8 drv_role, 7295d24bcf1STomer Tayar u8 exist_drv_role, 7305d24bcf1STomer Tayar enum qed_override_force_load override_force_load) 731fe56b9e6SYuval Mintz { 7325d24bcf1STomer Tayar bool can_force_load = false; 7335d24bcf1STomer Tayar 7345d24bcf1STomer Tayar switch (override_force_load) { 7355d24bcf1STomer Tayar case QED_OVERRIDE_FORCE_LOAD_ALWAYS: 7365d24bcf1STomer Tayar can_force_load = true; 7375d24bcf1STomer Tayar break; 7385d24bcf1STomer Tayar case QED_OVERRIDE_FORCE_LOAD_NEVER: 7395d24bcf1STomer Tayar can_force_load = false; 7405d24bcf1STomer Tayar break; 7415d24bcf1STomer Tayar default: 7425d24bcf1STomer Tayar can_force_load = (drv_role == DRV_ROLE_OS && 7435d24bcf1STomer Tayar exist_drv_role == DRV_ROLE_PREBOOT) || 7445d24bcf1STomer Tayar (drv_role == DRV_ROLE_KDUMP && 7455d24bcf1STomer Tayar exist_drv_role == DRV_ROLE_OS); 7465d24bcf1STomer Tayar break; 7475d24bcf1STomer Tayar } 7485d24bcf1STomer Tayar 7495d24bcf1STomer Tayar return can_force_load; 7505d24bcf1STomer Tayar } 7515d24bcf1STomer Tayar 7525d24bcf1STomer Tayar static int qed_mcp_cancel_load_req(struct qed_hwfn *p_hwfn, 7535d24bcf1STomer Tayar struct qed_ptt *p_ptt) 7545d24bcf1STomer Tayar { 7555d24bcf1STomer Tayar u32 resp = 0, param = 0; 756fe56b9e6SYuval Mintz int rc; 757fe56b9e6SYuval Mintz 7585d24bcf1STomer Tayar rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_CANCEL_LOAD_REQ, 0, 7595d24bcf1STomer Tayar &resp, ¶m); 7605d24bcf1STomer Tayar if (rc) 7615d24bcf1STomer Tayar DP_NOTICE(p_hwfn, 7625d24bcf1STomer Tayar "Failed to send cancel load request, rc = %d\n", rc); 763fe56b9e6SYuval Mintz 764fe56b9e6SYuval Mintz return rc; 765fe56b9e6SYuval Mintz } 766fe56b9e6SYuval Mintz 7675d24bcf1STomer Tayar #define CONFIG_QEDE_BITMAP_IDX BIT(0) 7685d24bcf1STomer Tayar #define CONFIG_QED_SRIOV_BITMAP_IDX BIT(1) 7695d24bcf1STomer Tayar #define CONFIG_QEDR_BITMAP_IDX BIT(2) 7705d24bcf1STomer Tayar #define CONFIG_QEDF_BITMAP_IDX BIT(4) 7715d24bcf1STomer Tayar #define CONFIG_QEDI_BITMAP_IDX BIT(5) 7725d24bcf1STomer Tayar #define CONFIG_QED_LL2_BITMAP_IDX BIT(6) 7735529bad9STomer Tayar 7745d24bcf1STomer Tayar static u32 qed_get_config_bitmap(void) 7755d24bcf1STomer Tayar { 7765d24bcf1STomer Tayar u32 config_bitmap = 0x0; 7775d24bcf1STomer Tayar 7785d24bcf1STomer Tayar if (IS_ENABLED(CONFIG_QEDE)) 7795d24bcf1STomer Tayar config_bitmap |= CONFIG_QEDE_BITMAP_IDX; 7805d24bcf1STomer Tayar 7815d24bcf1STomer Tayar if (IS_ENABLED(CONFIG_QED_SRIOV)) 7825d24bcf1STomer Tayar config_bitmap |= CONFIG_QED_SRIOV_BITMAP_IDX; 7835d24bcf1STomer Tayar 7845d24bcf1STomer Tayar if (IS_ENABLED(CONFIG_QED_RDMA)) 7855d24bcf1STomer Tayar config_bitmap |= CONFIG_QEDR_BITMAP_IDX; 7865d24bcf1STomer Tayar 7875d24bcf1STomer Tayar if (IS_ENABLED(CONFIG_QED_FCOE)) 7885d24bcf1STomer Tayar config_bitmap |= CONFIG_QEDF_BITMAP_IDX; 7895d24bcf1STomer Tayar 7905d24bcf1STomer Tayar if (IS_ENABLED(CONFIG_QED_ISCSI)) 7915d24bcf1STomer Tayar config_bitmap |= CONFIG_QEDI_BITMAP_IDX; 7925d24bcf1STomer Tayar 7935d24bcf1STomer Tayar if (IS_ENABLED(CONFIG_QED_LL2)) 7945d24bcf1STomer Tayar config_bitmap |= CONFIG_QED_LL2_BITMAP_IDX; 7955d24bcf1STomer Tayar 7965d24bcf1STomer Tayar return config_bitmap; 7975d24bcf1STomer Tayar } 7985d24bcf1STomer Tayar 7995d24bcf1STomer Tayar struct qed_load_req_in_params { 8005d24bcf1STomer Tayar u8 hsi_ver; 8015d24bcf1STomer Tayar #define QED_LOAD_REQ_HSI_VER_DEFAULT 0 8025d24bcf1STomer Tayar #define QED_LOAD_REQ_HSI_VER_1 1 8035d24bcf1STomer Tayar u32 drv_ver_0; 8045d24bcf1STomer Tayar u32 drv_ver_1; 8055d24bcf1STomer Tayar u32 fw_ver; 8065d24bcf1STomer Tayar u8 drv_role; 8075d24bcf1STomer Tayar u8 timeout_val; 8085d24bcf1STomer Tayar u8 force_cmd; 8095d24bcf1STomer Tayar bool avoid_eng_reset; 8105d24bcf1STomer Tayar }; 8115d24bcf1STomer Tayar 8125d24bcf1STomer Tayar struct qed_load_req_out_params { 8135d24bcf1STomer Tayar u32 load_code; 8145d24bcf1STomer Tayar u32 exist_drv_ver_0; 8155d24bcf1STomer Tayar u32 exist_drv_ver_1; 8165d24bcf1STomer Tayar u32 exist_fw_ver; 8175d24bcf1STomer Tayar u8 exist_drv_role; 8185d24bcf1STomer Tayar u8 mfw_hsi_ver; 8195d24bcf1STomer Tayar bool drv_exists; 8205d24bcf1STomer Tayar }; 8215d24bcf1STomer Tayar 8225d24bcf1STomer Tayar static int 8235d24bcf1STomer Tayar __qed_mcp_load_req(struct qed_hwfn *p_hwfn, 8245d24bcf1STomer Tayar struct qed_ptt *p_ptt, 8255d24bcf1STomer Tayar struct qed_load_req_in_params *p_in_params, 8265d24bcf1STomer Tayar struct qed_load_req_out_params *p_out_params) 8275d24bcf1STomer Tayar { 8285d24bcf1STomer Tayar struct qed_mcp_mb_params mb_params; 8295d24bcf1STomer Tayar struct load_req_stc load_req; 8305d24bcf1STomer Tayar struct load_rsp_stc load_rsp; 8315d24bcf1STomer Tayar u32 hsi_ver; 8325d24bcf1STomer Tayar int rc; 8335d24bcf1STomer Tayar 8345d24bcf1STomer Tayar memset(&load_req, 0, sizeof(load_req)); 8355d24bcf1STomer Tayar load_req.drv_ver_0 = p_in_params->drv_ver_0; 8365d24bcf1STomer Tayar load_req.drv_ver_1 = p_in_params->drv_ver_1; 8375d24bcf1STomer Tayar load_req.fw_ver = p_in_params->fw_ver; 8385d24bcf1STomer Tayar QED_MFW_SET_FIELD(load_req.misc0, LOAD_REQ_ROLE, p_in_params->drv_role); 8395d24bcf1STomer Tayar QED_MFW_SET_FIELD(load_req.misc0, LOAD_REQ_LOCK_TO, 8405d24bcf1STomer Tayar p_in_params->timeout_val); 8415d24bcf1STomer Tayar QED_MFW_SET_FIELD(load_req.misc0, LOAD_REQ_FORCE, 8425d24bcf1STomer Tayar p_in_params->force_cmd); 8435d24bcf1STomer Tayar QED_MFW_SET_FIELD(load_req.misc0, LOAD_REQ_FLAGS0, 8445d24bcf1STomer Tayar p_in_params->avoid_eng_reset); 8455d24bcf1STomer Tayar 8465d24bcf1STomer Tayar hsi_ver = (p_in_params->hsi_ver == QED_LOAD_REQ_HSI_VER_DEFAULT) ? 8475d24bcf1STomer Tayar DRV_ID_MCP_HSI_VER_CURRENT : 8485d24bcf1STomer Tayar (p_in_params->hsi_ver << DRV_ID_MCP_HSI_VER_SHIFT); 8495d24bcf1STomer Tayar 8505d24bcf1STomer Tayar memset(&mb_params, 0, sizeof(mb_params)); 8515d24bcf1STomer Tayar mb_params.cmd = DRV_MSG_CODE_LOAD_REQ; 8525d24bcf1STomer Tayar mb_params.param = PDA_COMP | hsi_ver | p_hwfn->cdev->drv_type; 8535d24bcf1STomer Tayar mb_params.p_data_src = &load_req; 8545d24bcf1STomer Tayar mb_params.data_src_size = sizeof(load_req); 8555d24bcf1STomer Tayar mb_params.p_data_dst = &load_rsp; 8565d24bcf1STomer Tayar mb_params.data_dst_size = sizeof(load_rsp); 857b310974eSTomer Tayar mb_params.flags = QED_MB_FLAG_CAN_SLEEP | QED_MB_FLAG_AVOID_BLOCK; 8585d24bcf1STomer Tayar 8595d24bcf1STomer Tayar DP_VERBOSE(p_hwfn, QED_MSG_SP, 8605d24bcf1STomer Tayar "Load Request: param 0x%08x [init_hw %d, drv_type %d, hsi_ver %d, pda 0x%04x]\n", 8615d24bcf1STomer Tayar mb_params.param, 8625d24bcf1STomer Tayar QED_MFW_GET_FIELD(mb_params.param, DRV_ID_DRV_INIT_HW), 8635d24bcf1STomer Tayar QED_MFW_GET_FIELD(mb_params.param, DRV_ID_DRV_TYPE), 8645d24bcf1STomer Tayar QED_MFW_GET_FIELD(mb_params.param, DRV_ID_MCP_HSI_VER), 8655d24bcf1STomer Tayar QED_MFW_GET_FIELD(mb_params.param, DRV_ID_PDA_COMP_VER)); 8665d24bcf1STomer Tayar 8675d24bcf1STomer Tayar if (p_in_params->hsi_ver != QED_LOAD_REQ_HSI_VER_1) { 8685d24bcf1STomer Tayar DP_VERBOSE(p_hwfn, QED_MSG_SP, 8695d24bcf1STomer 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", 8705d24bcf1STomer Tayar load_req.drv_ver_0, 8715d24bcf1STomer Tayar load_req.drv_ver_1, 8725d24bcf1STomer Tayar load_req.fw_ver, 8735d24bcf1STomer Tayar load_req.misc0, 8745d24bcf1STomer Tayar QED_MFW_GET_FIELD(load_req.misc0, LOAD_REQ_ROLE), 8755d24bcf1STomer Tayar QED_MFW_GET_FIELD(load_req.misc0, 8765d24bcf1STomer Tayar LOAD_REQ_LOCK_TO), 8775d24bcf1STomer Tayar QED_MFW_GET_FIELD(load_req.misc0, LOAD_REQ_FORCE), 8785d24bcf1STomer Tayar QED_MFW_GET_FIELD(load_req.misc0, LOAD_REQ_FLAGS0)); 8795d24bcf1STomer Tayar } 8805d24bcf1STomer Tayar 8815d24bcf1STomer Tayar rc = qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 8825d24bcf1STomer Tayar if (rc) { 8835d24bcf1STomer Tayar DP_NOTICE(p_hwfn, "Failed to send load request, rc = %d\n", rc); 8845d24bcf1STomer Tayar return rc; 8855d24bcf1STomer Tayar } 8865d24bcf1STomer Tayar 8875d24bcf1STomer Tayar DP_VERBOSE(p_hwfn, QED_MSG_SP, 8885d24bcf1STomer Tayar "Load Response: resp 0x%08x\n", mb_params.mcp_resp); 8895d24bcf1STomer Tayar p_out_params->load_code = mb_params.mcp_resp; 8905d24bcf1STomer Tayar 8915d24bcf1STomer Tayar if (p_in_params->hsi_ver != QED_LOAD_REQ_HSI_VER_1 && 8925d24bcf1STomer Tayar p_out_params->load_code != FW_MSG_CODE_DRV_LOAD_REFUSED_HSI_1) { 8935d24bcf1STomer Tayar DP_VERBOSE(p_hwfn, 8945d24bcf1STomer Tayar QED_MSG_SP, 8955d24bcf1STomer 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", 8965d24bcf1STomer Tayar load_rsp.drv_ver_0, 8975d24bcf1STomer Tayar load_rsp.drv_ver_1, 8985d24bcf1STomer Tayar load_rsp.fw_ver, 8995d24bcf1STomer Tayar load_rsp.misc0, 9005d24bcf1STomer Tayar QED_MFW_GET_FIELD(load_rsp.misc0, LOAD_RSP_ROLE), 9015d24bcf1STomer Tayar QED_MFW_GET_FIELD(load_rsp.misc0, LOAD_RSP_HSI), 9025d24bcf1STomer Tayar QED_MFW_GET_FIELD(load_rsp.misc0, LOAD_RSP_FLAGS0)); 9035d24bcf1STomer Tayar 9045d24bcf1STomer Tayar p_out_params->exist_drv_ver_0 = load_rsp.drv_ver_0; 9055d24bcf1STomer Tayar p_out_params->exist_drv_ver_1 = load_rsp.drv_ver_1; 9065d24bcf1STomer Tayar p_out_params->exist_fw_ver = load_rsp.fw_ver; 9075d24bcf1STomer Tayar p_out_params->exist_drv_role = 9085d24bcf1STomer Tayar QED_MFW_GET_FIELD(load_rsp.misc0, LOAD_RSP_ROLE); 9095d24bcf1STomer Tayar p_out_params->mfw_hsi_ver = 9105d24bcf1STomer Tayar QED_MFW_GET_FIELD(load_rsp.misc0, LOAD_RSP_HSI); 9115d24bcf1STomer Tayar p_out_params->drv_exists = 9125d24bcf1STomer Tayar QED_MFW_GET_FIELD(load_rsp.misc0, LOAD_RSP_FLAGS0) & 9135d24bcf1STomer Tayar LOAD_RSP_FLAGS0_DRV_EXISTS; 9145d24bcf1STomer Tayar } 9155d24bcf1STomer Tayar 9165d24bcf1STomer Tayar return 0; 9175d24bcf1STomer Tayar } 9185d24bcf1STomer Tayar 9195d24bcf1STomer Tayar static int eocre_get_mfw_drv_role(struct qed_hwfn *p_hwfn, 9205d24bcf1STomer Tayar enum qed_drv_role drv_role, 9215d24bcf1STomer Tayar u8 *p_mfw_drv_role) 9225d24bcf1STomer Tayar { 9235d24bcf1STomer Tayar switch (drv_role) { 9245d24bcf1STomer Tayar case QED_DRV_ROLE_OS: 9255d24bcf1STomer Tayar *p_mfw_drv_role = DRV_ROLE_OS; 9265d24bcf1STomer Tayar break; 9275d24bcf1STomer Tayar case QED_DRV_ROLE_KDUMP: 9285d24bcf1STomer Tayar *p_mfw_drv_role = DRV_ROLE_KDUMP; 9295d24bcf1STomer Tayar break; 9305d24bcf1STomer Tayar default: 9315d24bcf1STomer Tayar DP_ERR(p_hwfn, "Unexpected driver role %d\n", drv_role); 9325d24bcf1STomer Tayar return -EINVAL; 9335d24bcf1STomer Tayar } 9345d24bcf1STomer Tayar 9355d24bcf1STomer Tayar return 0; 9365d24bcf1STomer Tayar } 9375d24bcf1STomer Tayar 9385d24bcf1STomer Tayar enum qed_load_req_force { 9395d24bcf1STomer Tayar QED_LOAD_REQ_FORCE_NONE, 9405d24bcf1STomer Tayar QED_LOAD_REQ_FORCE_PF, 9415d24bcf1STomer Tayar QED_LOAD_REQ_FORCE_ALL, 9425d24bcf1STomer Tayar }; 9435d24bcf1STomer Tayar 9445d24bcf1STomer Tayar static void qed_get_mfw_force_cmd(struct qed_hwfn *p_hwfn, 9455d24bcf1STomer Tayar 9465d24bcf1STomer Tayar enum qed_load_req_force force_cmd, 9475d24bcf1STomer Tayar u8 *p_mfw_force_cmd) 9485d24bcf1STomer Tayar { 9495d24bcf1STomer Tayar switch (force_cmd) { 9505d24bcf1STomer Tayar case QED_LOAD_REQ_FORCE_NONE: 9515d24bcf1STomer Tayar *p_mfw_force_cmd = LOAD_REQ_FORCE_NONE; 9525d24bcf1STomer Tayar break; 9535d24bcf1STomer Tayar case QED_LOAD_REQ_FORCE_PF: 9545d24bcf1STomer Tayar *p_mfw_force_cmd = LOAD_REQ_FORCE_PF; 9555d24bcf1STomer Tayar break; 9565d24bcf1STomer Tayar case QED_LOAD_REQ_FORCE_ALL: 9575d24bcf1STomer Tayar *p_mfw_force_cmd = LOAD_REQ_FORCE_ALL; 9585d24bcf1STomer Tayar break; 9595d24bcf1STomer Tayar } 9605d24bcf1STomer Tayar } 9615d24bcf1STomer Tayar 9625d24bcf1STomer Tayar int qed_mcp_load_req(struct qed_hwfn *p_hwfn, 9635d24bcf1STomer Tayar struct qed_ptt *p_ptt, 9645d24bcf1STomer Tayar struct qed_load_req_params *p_params) 9655d24bcf1STomer Tayar { 9665d24bcf1STomer Tayar struct qed_load_req_out_params out_params; 9675d24bcf1STomer Tayar struct qed_load_req_in_params in_params; 9685d24bcf1STomer Tayar u8 mfw_drv_role, mfw_force_cmd; 9695d24bcf1STomer Tayar int rc; 9705d24bcf1STomer Tayar 9715d24bcf1STomer Tayar memset(&in_params, 0, sizeof(in_params)); 9725d24bcf1STomer Tayar in_params.hsi_ver = QED_LOAD_REQ_HSI_VER_DEFAULT; 9735d24bcf1STomer Tayar in_params.drv_ver_0 = QED_VERSION; 9745d24bcf1STomer Tayar in_params.drv_ver_1 = qed_get_config_bitmap(); 9755d24bcf1STomer Tayar in_params.fw_ver = STORM_FW_VERSION; 9765d24bcf1STomer Tayar rc = eocre_get_mfw_drv_role(p_hwfn, p_params->drv_role, &mfw_drv_role); 9775d24bcf1STomer Tayar if (rc) 9785d24bcf1STomer Tayar return rc; 9795d24bcf1STomer Tayar 9805d24bcf1STomer Tayar in_params.drv_role = mfw_drv_role; 9815d24bcf1STomer Tayar in_params.timeout_val = p_params->timeout_val; 9825d24bcf1STomer Tayar qed_get_mfw_force_cmd(p_hwfn, 9835d24bcf1STomer Tayar QED_LOAD_REQ_FORCE_NONE, &mfw_force_cmd); 9845d24bcf1STomer Tayar 9855d24bcf1STomer Tayar in_params.force_cmd = mfw_force_cmd; 9865d24bcf1STomer Tayar in_params.avoid_eng_reset = p_params->avoid_eng_reset; 9875d24bcf1STomer Tayar 9885d24bcf1STomer Tayar memset(&out_params, 0, sizeof(out_params)); 9895d24bcf1STomer Tayar rc = __qed_mcp_load_req(p_hwfn, p_ptt, &in_params, &out_params); 9905d24bcf1STomer Tayar if (rc) 9915d24bcf1STomer Tayar return rc; 9925d24bcf1STomer Tayar 9935d24bcf1STomer Tayar /* First handle cases where another load request should/might be sent: 9945d24bcf1STomer Tayar * - MFW expects the old interface [HSI version = 1] 9955d24bcf1STomer Tayar * - MFW responds that a force load request is required 996fe56b9e6SYuval Mintz */ 9975d24bcf1STomer Tayar if (out_params.load_code == FW_MSG_CODE_DRV_LOAD_REFUSED_HSI_1) { 9985d24bcf1STomer Tayar DP_INFO(p_hwfn, 9995d24bcf1STomer Tayar "MFW refused a load request due to HSI > 1. Resending with HSI = 1\n"); 10005d24bcf1STomer Tayar 10015d24bcf1STomer Tayar in_params.hsi_ver = QED_LOAD_REQ_HSI_VER_1; 10025d24bcf1STomer Tayar memset(&out_params, 0, sizeof(out_params)); 10035d24bcf1STomer Tayar rc = __qed_mcp_load_req(p_hwfn, p_ptt, &in_params, &out_params); 10045d24bcf1STomer Tayar if (rc) 10055d24bcf1STomer Tayar return rc; 10065d24bcf1STomer Tayar } else if (out_params.load_code == 10075d24bcf1STomer Tayar FW_MSG_CODE_DRV_LOAD_REFUSED_REQUIRES_FORCE) { 10085d24bcf1STomer Tayar if (qed_mcp_can_force_load(in_params.drv_role, 10095d24bcf1STomer Tayar out_params.exist_drv_role, 10105d24bcf1STomer Tayar p_params->override_force_load)) { 10115d24bcf1STomer Tayar DP_INFO(p_hwfn, 10125d24bcf1STomer 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", 10135d24bcf1STomer Tayar in_params.drv_role, in_params.fw_ver, 10145d24bcf1STomer Tayar in_params.drv_ver_0, in_params.drv_ver_1, 10155d24bcf1STomer Tayar out_params.exist_drv_role, 10165d24bcf1STomer Tayar out_params.exist_fw_ver, 10175d24bcf1STomer Tayar out_params.exist_drv_ver_0, 10185d24bcf1STomer Tayar out_params.exist_drv_ver_1); 10195d24bcf1STomer Tayar 10205d24bcf1STomer Tayar qed_get_mfw_force_cmd(p_hwfn, 10215d24bcf1STomer Tayar QED_LOAD_REQ_FORCE_ALL, 10225d24bcf1STomer Tayar &mfw_force_cmd); 10235d24bcf1STomer Tayar 10245d24bcf1STomer Tayar in_params.force_cmd = mfw_force_cmd; 10255d24bcf1STomer Tayar memset(&out_params, 0, sizeof(out_params)); 10265d24bcf1STomer Tayar rc = __qed_mcp_load_req(p_hwfn, p_ptt, &in_params, 10275d24bcf1STomer Tayar &out_params); 10285d24bcf1STomer Tayar if (rc) 10295d24bcf1STomer Tayar return rc; 10305d24bcf1STomer Tayar } else { 10315d24bcf1STomer Tayar DP_NOTICE(p_hwfn, 10325d24bcf1STomer 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", 10335d24bcf1STomer Tayar in_params.drv_role, in_params.fw_ver, 10345d24bcf1STomer Tayar in_params.drv_ver_0, in_params.drv_ver_1, 10355d24bcf1STomer Tayar out_params.exist_drv_role, 10365d24bcf1STomer Tayar out_params.exist_fw_ver, 10375d24bcf1STomer Tayar out_params.exist_drv_ver_0, 10385d24bcf1STomer Tayar out_params.exist_drv_ver_1); 10395d24bcf1STomer Tayar DP_NOTICE(p_hwfn, 10405d24bcf1STomer Tayar "Avoid sending a force load request to prevent disruption of active PFs\n"); 10415d24bcf1STomer Tayar 10425d24bcf1STomer Tayar qed_mcp_cancel_load_req(p_hwfn, p_ptt); 1043fe56b9e6SYuval Mintz return -EBUSY; 1044fe56b9e6SYuval Mintz } 10455d24bcf1STomer Tayar } 10465d24bcf1STomer Tayar 10475d24bcf1STomer Tayar /* Now handle the other types of responses. 10485d24bcf1STomer Tayar * The "REFUSED_HSI_1" and "REFUSED_REQUIRES_FORCE" responses are not 10495d24bcf1STomer Tayar * expected here after the additional revised load requests were sent. 10505d24bcf1STomer Tayar */ 10515d24bcf1STomer Tayar switch (out_params.load_code) { 10525d24bcf1STomer Tayar case FW_MSG_CODE_DRV_LOAD_ENGINE: 10535d24bcf1STomer Tayar case FW_MSG_CODE_DRV_LOAD_PORT: 10545d24bcf1STomer Tayar case FW_MSG_CODE_DRV_LOAD_FUNCTION: 10555d24bcf1STomer Tayar if (out_params.mfw_hsi_ver != QED_LOAD_REQ_HSI_VER_1 && 10565d24bcf1STomer Tayar out_params.drv_exists) { 10575d24bcf1STomer Tayar /* The role and fw/driver version match, but the PF is 10585d24bcf1STomer Tayar * already loaded and has not been unloaded gracefully. 10595d24bcf1STomer Tayar */ 10605d24bcf1STomer Tayar DP_NOTICE(p_hwfn, 10615d24bcf1STomer Tayar "PF is already loaded\n"); 10625d24bcf1STomer Tayar return -EINVAL; 10635d24bcf1STomer Tayar } 10645d24bcf1STomer Tayar break; 10655d24bcf1STomer Tayar default: 10665d24bcf1STomer Tayar DP_NOTICE(p_hwfn, 10675d24bcf1STomer Tayar "Unexpected refusal to load request [resp 0x%08x]. Aborting.\n", 10685d24bcf1STomer Tayar out_params.load_code); 10695d24bcf1STomer Tayar return -EBUSY; 10705d24bcf1STomer Tayar } 10715d24bcf1STomer Tayar 10725d24bcf1STomer Tayar p_params->load_code = out_params.load_code; 1073fe56b9e6SYuval Mintz 1074fe56b9e6SYuval Mintz return 0; 1075fe56b9e6SYuval Mintz } 1076fe56b9e6SYuval Mintz 1077666db486STomer Tayar int qed_mcp_load_done(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 1078666db486STomer Tayar { 1079666db486STomer Tayar u32 resp = 0, param = 0; 1080666db486STomer Tayar int rc; 1081666db486STomer Tayar 1082666db486STomer Tayar rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_LOAD_DONE, 0, &resp, 1083666db486STomer Tayar ¶m); 1084666db486STomer Tayar if (rc) { 1085666db486STomer Tayar DP_NOTICE(p_hwfn, 1086666db486STomer Tayar "Failed to send a LOAD_DONE command, rc = %d\n", rc); 1087666db486STomer Tayar return rc; 1088666db486STomer Tayar } 1089666db486STomer Tayar 1090666db486STomer Tayar /* Check if there is a DID mismatch between nvm-cfg/efuse */ 1091666db486STomer Tayar if (param & FW_MB_PARAM_LOAD_DONE_DID_EFUSE_ERROR) 1092666db486STomer Tayar DP_NOTICE(p_hwfn, 1093666db486STomer Tayar "warning: device configuration is not supported on this board type. The device may not function as expected.\n"); 1094666db486STomer Tayar 1095666db486STomer Tayar return 0; 1096666db486STomer Tayar } 1097666db486STomer Tayar 10981226337aSTomer Tayar int qed_mcp_unload_req(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 10991226337aSTomer Tayar { 1100eaa50fc5STomer Tayar struct qed_mcp_mb_params mb_params; 1101eaa50fc5STomer Tayar u32 wol_param; 11021226337aSTomer Tayar 11031226337aSTomer Tayar switch (p_hwfn->cdev->wol_config) { 11041226337aSTomer Tayar case QED_OV_WOL_DISABLED: 11051226337aSTomer Tayar wol_param = DRV_MB_PARAM_UNLOAD_WOL_DISABLED; 11061226337aSTomer Tayar break; 11071226337aSTomer Tayar case QED_OV_WOL_ENABLED: 11081226337aSTomer Tayar wol_param = DRV_MB_PARAM_UNLOAD_WOL_ENABLED; 11091226337aSTomer Tayar break; 11101226337aSTomer Tayar default: 11111226337aSTomer Tayar DP_NOTICE(p_hwfn, 11121226337aSTomer Tayar "Unknown WoL configuration %02x\n", 11131226337aSTomer Tayar p_hwfn->cdev->wol_config); 11141226337aSTomer Tayar /* Fallthrough */ 11151226337aSTomer Tayar case QED_OV_WOL_DEFAULT: 11161226337aSTomer Tayar wol_param = DRV_MB_PARAM_UNLOAD_WOL_MCP; 11171226337aSTomer Tayar } 11181226337aSTomer Tayar 1119eaa50fc5STomer Tayar memset(&mb_params, 0, sizeof(mb_params)); 1120eaa50fc5STomer Tayar mb_params.cmd = DRV_MSG_CODE_UNLOAD_REQ; 1121eaa50fc5STomer Tayar mb_params.param = wol_param; 1122b310974eSTomer Tayar mb_params.flags = QED_MB_FLAG_CAN_SLEEP | QED_MB_FLAG_AVOID_BLOCK; 1123eaa50fc5STomer Tayar 1124eaa50fc5STomer Tayar return qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 11251226337aSTomer Tayar } 11261226337aSTomer Tayar 11271226337aSTomer Tayar int qed_mcp_unload_done(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 11281226337aSTomer Tayar { 11291226337aSTomer Tayar struct qed_mcp_mb_params mb_params; 11301226337aSTomer Tayar struct mcp_mac wol_mac; 11311226337aSTomer Tayar 11321226337aSTomer Tayar memset(&mb_params, 0, sizeof(mb_params)); 11331226337aSTomer Tayar mb_params.cmd = DRV_MSG_CODE_UNLOAD_DONE; 11341226337aSTomer Tayar 11351226337aSTomer Tayar /* Set the primary MAC if WoL is enabled */ 11361226337aSTomer Tayar if (p_hwfn->cdev->wol_config == QED_OV_WOL_ENABLED) { 11371226337aSTomer Tayar u8 *p_mac = p_hwfn->cdev->wol_mac; 11381226337aSTomer Tayar 11391226337aSTomer Tayar memset(&wol_mac, 0, sizeof(wol_mac)); 11401226337aSTomer Tayar wol_mac.mac_upper = p_mac[0] << 8 | p_mac[1]; 11411226337aSTomer Tayar wol_mac.mac_lower = p_mac[2] << 24 | p_mac[3] << 16 | 11421226337aSTomer Tayar p_mac[4] << 8 | p_mac[5]; 11431226337aSTomer Tayar 11441226337aSTomer Tayar DP_VERBOSE(p_hwfn, 11451226337aSTomer Tayar (QED_MSG_SP | NETIF_MSG_IFDOWN), 11461226337aSTomer Tayar "Setting WoL MAC: %pM --> [%08x,%08x]\n", 11471226337aSTomer Tayar p_mac, wol_mac.mac_upper, wol_mac.mac_lower); 11481226337aSTomer Tayar 11491226337aSTomer Tayar mb_params.p_data_src = &wol_mac; 11501226337aSTomer Tayar mb_params.data_src_size = sizeof(wol_mac); 11511226337aSTomer Tayar } 11521226337aSTomer Tayar 11531226337aSTomer Tayar return qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 11541226337aSTomer Tayar } 11551226337aSTomer Tayar 11560b55e27dSYuval Mintz static void qed_mcp_handle_vf_flr(struct qed_hwfn *p_hwfn, 11570b55e27dSYuval Mintz struct qed_ptt *p_ptt) 11580b55e27dSYuval Mintz { 11590b55e27dSYuval Mintz u32 addr = SECTION_OFFSIZE_ADDR(p_hwfn->mcp_info->public_base, 11600b55e27dSYuval Mintz PUBLIC_PATH); 11610b55e27dSYuval Mintz u32 mfw_path_offsize = qed_rd(p_hwfn, p_ptt, addr); 11620b55e27dSYuval Mintz u32 path_addr = SECTION_ADDR(mfw_path_offsize, 11630b55e27dSYuval Mintz QED_PATH_ID(p_hwfn)); 11640b55e27dSYuval Mintz u32 disabled_vfs[VF_MAX_STATIC / 32]; 11650b55e27dSYuval Mintz int i; 11660b55e27dSYuval Mintz 11670b55e27dSYuval Mintz DP_VERBOSE(p_hwfn, 11680b55e27dSYuval Mintz QED_MSG_SP, 11690b55e27dSYuval Mintz "Reading Disabled VF information from [offset %08x], path_addr %08x\n", 11700b55e27dSYuval Mintz mfw_path_offsize, path_addr); 11710b55e27dSYuval Mintz 11720b55e27dSYuval Mintz for (i = 0; i < (VF_MAX_STATIC / 32); i++) { 11730b55e27dSYuval Mintz disabled_vfs[i] = qed_rd(p_hwfn, p_ptt, 11740b55e27dSYuval Mintz path_addr + 11750b55e27dSYuval Mintz offsetof(struct public_path, 11760b55e27dSYuval Mintz mcp_vf_disabled) + 11770b55e27dSYuval Mintz sizeof(u32) * i); 11780b55e27dSYuval Mintz DP_VERBOSE(p_hwfn, (QED_MSG_SP | QED_MSG_IOV), 11790b55e27dSYuval Mintz "FLR-ed VFs [%08x,...,%08x] - %08x\n", 11800b55e27dSYuval Mintz i * 32, (i + 1) * 32 - 1, disabled_vfs[i]); 11810b55e27dSYuval Mintz } 11820b55e27dSYuval Mintz 11830b55e27dSYuval Mintz if (qed_iov_mark_vf_flr(p_hwfn, disabled_vfs)) 11840b55e27dSYuval Mintz qed_schedule_iov(p_hwfn, QED_IOV_WQ_FLR_FLAG); 11850b55e27dSYuval Mintz } 11860b55e27dSYuval Mintz 11870b55e27dSYuval Mintz int qed_mcp_ack_vf_flr(struct qed_hwfn *p_hwfn, 11880b55e27dSYuval Mintz struct qed_ptt *p_ptt, u32 *vfs_to_ack) 11890b55e27dSYuval Mintz { 11900b55e27dSYuval Mintz u32 addr = SECTION_OFFSIZE_ADDR(p_hwfn->mcp_info->public_base, 11910b55e27dSYuval Mintz PUBLIC_FUNC); 11920b55e27dSYuval Mintz u32 mfw_func_offsize = qed_rd(p_hwfn, p_ptt, addr); 11930b55e27dSYuval Mintz u32 func_addr = SECTION_ADDR(mfw_func_offsize, 11940b55e27dSYuval Mintz MCP_PF_ID(p_hwfn)); 11950b55e27dSYuval Mintz struct qed_mcp_mb_params mb_params; 11960b55e27dSYuval Mintz int rc; 11970b55e27dSYuval Mintz int i; 11980b55e27dSYuval Mintz 11990b55e27dSYuval Mintz for (i = 0; i < (VF_MAX_STATIC / 32); i++) 12000b55e27dSYuval Mintz DP_VERBOSE(p_hwfn, (QED_MSG_SP | QED_MSG_IOV), 12010b55e27dSYuval Mintz "Acking VFs [%08x,...,%08x] - %08x\n", 12020b55e27dSYuval Mintz i * 32, (i + 1) * 32 - 1, vfs_to_ack[i]); 12030b55e27dSYuval Mintz 12040b55e27dSYuval Mintz memset(&mb_params, 0, sizeof(mb_params)); 12050b55e27dSYuval Mintz mb_params.cmd = DRV_MSG_CODE_VF_DISABLED_DONE; 12062f67af8cSTomer Tayar mb_params.p_data_src = vfs_to_ack; 12072f67af8cSTomer Tayar mb_params.data_src_size = VF_MAX_STATIC / 8; 12080b55e27dSYuval Mintz rc = qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 12090b55e27dSYuval Mintz if (rc) { 12100b55e27dSYuval Mintz DP_NOTICE(p_hwfn, "Failed to pass ACK for VF flr to MFW\n"); 12110b55e27dSYuval Mintz return -EBUSY; 12120b55e27dSYuval Mintz } 12130b55e27dSYuval Mintz 12140b55e27dSYuval Mintz /* Clear the ACK bits */ 12150b55e27dSYuval Mintz for (i = 0; i < (VF_MAX_STATIC / 32); i++) 12160b55e27dSYuval Mintz qed_wr(p_hwfn, p_ptt, 12170b55e27dSYuval Mintz func_addr + 12180b55e27dSYuval Mintz offsetof(struct public_func, drv_ack_vf_disabled) + 12190b55e27dSYuval Mintz i * sizeof(u32), 0); 12200b55e27dSYuval Mintz 12210b55e27dSYuval Mintz return rc; 12220b55e27dSYuval Mintz } 12230b55e27dSYuval Mintz 1224334c03b5SZvi Nachmani static void qed_mcp_handle_transceiver_change(struct qed_hwfn *p_hwfn, 1225334c03b5SZvi Nachmani struct qed_ptt *p_ptt) 1226334c03b5SZvi Nachmani { 1227334c03b5SZvi Nachmani u32 transceiver_state; 1228334c03b5SZvi Nachmani 1229334c03b5SZvi Nachmani transceiver_state = qed_rd(p_hwfn, p_ptt, 1230334c03b5SZvi Nachmani p_hwfn->mcp_info->port_addr + 1231334c03b5SZvi Nachmani offsetof(struct public_port, 1232334c03b5SZvi Nachmani transceiver_data)); 1233334c03b5SZvi Nachmani 1234334c03b5SZvi Nachmani DP_VERBOSE(p_hwfn, 1235334c03b5SZvi Nachmani (NETIF_MSG_HW | QED_MSG_SP), 1236334c03b5SZvi Nachmani "Received transceiver state update [0x%08x] from mfw [Addr 0x%x]\n", 1237334c03b5SZvi Nachmani transceiver_state, 1238334c03b5SZvi Nachmani (u32)(p_hwfn->mcp_info->port_addr + 12391a635e48SYuval Mintz offsetof(struct public_port, transceiver_data))); 1240334c03b5SZvi Nachmani 1241334c03b5SZvi Nachmani transceiver_state = GET_FIELD(transceiver_state, 1242351a4dedSYuval Mintz ETH_TRANSCEIVER_STATE); 1243334c03b5SZvi Nachmani 1244351a4dedSYuval Mintz if (transceiver_state == ETH_TRANSCEIVER_STATE_PRESENT) 1245334c03b5SZvi Nachmani DP_NOTICE(p_hwfn, "Transceiver is present.\n"); 1246334c03b5SZvi Nachmani else 1247334c03b5SZvi Nachmani DP_NOTICE(p_hwfn, "Transceiver is unplugged.\n"); 1248334c03b5SZvi Nachmani } 1249334c03b5SZvi Nachmani 1250645874e5SSudarsana Reddy Kalluru static void qed_mcp_read_eee_config(struct qed_hwfn *p_hwfn, 1251645874e5SSudarsana Reddy Kalluru struct qed_ptt *p_ptt, 1252645874e5SSudarsana Reddy Kalluru struct qed_mcp_link_state *p_link) 1253645874e5SSudarsana Reddy Kalluru { 1254645874e5SSudarsana Reddy Kalluru u32 eee_status, val; 1255645874e5SSudarsana Reddy Kalluru 1256645874e5SSudarsana Reddy Kalluru p_link->eee_adv_caps = 0; 1257645874e5SSudarsana Reddy Kalluru p_link->eee_lp_adv_caps = 0; 1258645874e5SSudarsana Reddy Kalluru eee_status = qed_rd(p_hwfn, 1259645874e5SSudarsana Reddy Kalluru p_ptt, 1260645874e5SSudarsana Reddy Kalluru p_hwfn->mcp_info->port_addr + 1261645874e5SSudarsana Reddy Kalluru offsetof(struct public_port, eee_status)); 1262645874e5SSudarsana Reddy Kalluru p_link->eee_active = !!(eee_status & EEE_ACTIVE_BIT); 1263645874e5SSudarsana Reddy Kalluru val = (eee_status & EEE_LD_ADV_STATUS_MASK) >> EEE_LD_ADV_STATUS_OFFSET; 1264645874e5SSudarsana Reddy Kalluru if (val & EEE_1G_ADV) 1265645874e5SSudarsana Reddy Kalluru p_link->eee_adv_caps |= QED_EEE_1G_ADV; 1266645874e5SSudarsana Reddy Kalluru if (val & EEE_10G_ADV) 1267645874e5SSudarsana Reddy Kalluru p_link->eee_adv_caps |= QED_EEE_10G_ADV; 1268645874e5SSudarsana Reddy Kalluru val = (eee_status & EEE_LP_ADV_STATUS_MASK) >> EEE_LP_ADV_STATUS_OFFSET; 1269645874e5SSudarsana Reddy Kalluru if (val & EEE_1G_ADV) 1270645874e5SSudarsana Reddy Kalluru p_link->eee_lp_adv_caps |= QED_EEE_1G_ADV; 1271645874e5SSudarsana Reddy Kalluru if (val & EEE_10G_ADV) 1272645874e5SSudarsana Reddy Kalluru p_link->eee_lp_adv_caps |= QED_EEE_10G_ADV; 1273645874e5SSudarsana Reddy Kalluru } 1274645874e5SSudarsana Reddy Kalluru 1275e40a826aSSudarsana Reddy Kalluru static u32 qed_mcp_get_shmem_func(struct qed_hwfn *p_hwfn, 1276e40a826aSSudarsana Reddy Kalluru struct qed_ptt *p_ptt, 1277e40a826aSSudarsana Reddy Kalluru struct public_func *p_data, int pfid) 1278e40a826aSSudarsana Reddy Kalluru { 1279e40a826aSSudarsana Reddy Kalluru u32 addr = SECTION_OFFSIZE_ADDR(p_hwfn->mcp_info->public_base, 1280e40a826aSSudarsana Reddy Kalluru PUBLIC_FUNC); 1281e40a826aSSudarsana Reddy Kalluru u32 mfw_path_offsize = qed_rd(p_hwfn, p_ptt, addr); 1282e40a826aSSudarsana Reddy Kalluru u32 func_addr; 1283e40a826aSSudarsana Reddy Kalluru u32 i, size; 1284e40a826aSSudarsana Reddy Kalluru 1285e40a826aSSudarsana Reddy Kalluru func_addr = SECTION_ADDR(mfw_path_offsize, pfid); 1286e40a826aSSudarsana Reddy Kalluru memset(p_data, 0, sizeof(*p_data)); 1287e40a826aSSudarsana Reddy Kalluru 1288e40a826aSSudarsana Reddy Kalluru size = min_t(u32, sizeof(*p_data), QED_SECTION_SIZE(mfw_path_offsize)); 1289e40a826aSSudarsana Reddy Kalluru for (i = 0; i < size / sizeof(u32); i++) 1290e40a826aSSudarsana Reddy Kalluru ((u32 *)p_data)[i] = qed_rd(p_hwfn, p_ptt, 1291e40a826aSSudarsana Reddy Kalluru func_addr + (i << 2)); 1292e40a826aSSudarsana Reddy Kalluru return size; 1293e40a826aSSudarsana Reddy Kalluru } 1294e40a826aSSudarsana Reddy Kalluru 1295e40a826aSSudarsana Reddy Kalluru static void qed_read_pf_bandwidth(struct qed_hwfn *p_hwfn, 1296e40a826aSSudarsana Reddy Kalluru struct public_func *p_shmem_info) 1297e40a826aSSudarsana Reddy Kalluru { 1298e40a826aSSudarsana Reddy Kalluru struct qed_mcp_function_info *p_info; 1299e40a826aSSudarsana Reddy Kalluru 1300e40a826aSSudarsana Reddy Kalluru p_info = &p_hwfn->mcp_info->func_info; 1301e40a826aSSudarsana Reddy Kalluru 1302e40a826aSSudarsana Reddy Kalluru p_info->bandwidth_min = QED_MFW_GET_FIELD(p_shmem_info->config, 1303e40a826aSSudarsana Reddy Kalluru FUNC_MF_CFG_MIN_BW); 1304e40a826aSSudarsana Reddy Kalluru if (p_info->bandwidth_min < 1 || p_info->bandwidth_min > 100) { 1305e40a826aSSudarsana Reddy Kalluru DP_INFO(p_hwfn, 1306e40a826aSSudarsana Reddy Kalluru "bandwidth minimum out of bounds [%02x]. Set to 1\n", 1307e40a826aSSudarsana Reddy Kalluru p_info->bandwidth_min); 1308e40a826aSSudarsana Reddy Kalluru p_info->bandwidth_min = 1; 1309e40a826aSSudarsana Reddy Kalluru } 1310e40a826aSSudarsana Reddy Kalluru 1311e40a826aSSudarsana Reddy Kalluru p_info->bandwidth_max = QED_MFW_GET_FIELD(p_shmem_info->config, 1312e40a826aSSudarsana Reddy Kalluru FUNC_MF_CFG_MAX_BW); 1313e40a826aSSudarsana Reddy Kalluru if (p_info->bandwidth_max < 1 || p_info->bandwidth_max > 100) { 1314e40a826aSSudarsana Reddy Kalluru DP_INFO(p_hwfn, 1315e40a826aSSudarsana Reddy Kalluru "bandwidth maximum out of bounds [%02x]. Set to 100\n", 1316e40a826aSSudarsana Reddy Kalluru p_info->bandwidth_max); 1317e40a826aSSudarsana Reddy Kalluru p_info->bandwidth_max = 100; 1318e40a826aSSudarsana Reddy Kalluru } 1319e40a826aSSudarsana Reddy Kalluru } 1320e40a826aSSudarsana Reddy Kalluru 1321cc875c2eSYuval Mintz static void qed_mcp_handle_link_change(struct qed_hwfn *p_hwfn, 13221a635e48SYuval Mintz struct qed_ptt *p_ptt, bool b_reset) 1323cc875c2eSYuval Mintz { 1324cc875c2eSYuval Mintz struct qed_mcp_link_state *p_link; 1325a64b02d5SManish Chopra u8 max_bw, min_bw; 1326cc875c2eSYuval Mintz u32 status = 0; 1327cc875c2eSYuval Mintz 132865ed2ffdSMintz, Yuval /* Prevent SW/attentions from doing this at the same time */ 132965ed2ffdSMintz, Yuval spin_lock_bh(&p_hwfn->mcp_info->link_lock); 133065ed2ffdSMintz, Yuval 1331cc875c2eSYuval Mintz p_link = &p_hwfn->mcp_info->link_output; 1332cc875c2eSYuval Mintz memset(p_link, 0, sizeof(*p_link)); 1333cc875c2eSYuval Mintz if (!b_reset) { 1334cc875c2eSYuval Mintz status = qed_rd(p_hwfn, p_ptt, 1335cc875c2eSYuval Mintz p_hwfn->mcp_info->port_addr + 1336cc875c2eSYuval Mintz offsetof(struct public_port, link_status)); 1337cc875c2eSYuval Mintz DP_VERBOSE(p_hwfn, (NETIF_MSG_LINK | QED_MSG_SP), 1338cc875c2eSYuval Mintz "Received link update [0x%08x] from mfw [Addr 0x%x]\n", 1339cc875c2eSYuval Mintz status, 1340cc875c2eSYuval Mintz (u32)(p_hwfn->mcp_info->port_addr + 13411a635e48SYuval Mintz offsetof(struct public_port, link_status))); 1342cc875c2eSYuval Mintz } else { 1343cc875c2eSYuval Mintz DP_VERBOSE(p_hwfn, NETIF_MSG_LINK, 1344cc875c2eSYuval Mintz "Resetting link indications\n"); 134565ed2ffdSMintz, Yuval goto out; 1346cc875c2eSYuval Mintz } 1347cc875c2eSYuval Mintz 1348e40a826aSSudarsana Reddy Kalluru if (p_hwfn->b_drv_link_init) { 1349e40a826aSSudarsana Reddy Kalluru /* Link indication with modern MFW arrives as per-PF 1350e40a826aSSudarsana Reddy Kalluru * indication. 1351e40a826aSSudarsana Reddy Kalluru */ 1352e40a826aSSudarsana Reddy Kalluru if (p_hwfn->mcp_info->capabilities & 1353e40a826aSSudarsana Reddy Kalluru FW_MB_PARAM_FEATURE_SUPPORT_VLINK) { 1354e40a826aSSudarsana Reddy Kalluru struct public_func shmem_info; 1355e40a826aSSudarsana Reddy Kalluru 1356e40a826aSSudarsana Reddy Kalluru qed_mcp_get_shmem_func(p_hwfn, p_ptt, &shmem_info, 1357e40a826aSSudarsana Reddy Kalluru MCP_PF_ID(p_hwfn)); 1358e40a826aSSudarsana Reddy Kalluru p_link->link_up = !!(shmem_info.status & 1359e40a826aSSudarsana Reddy Kalluru FUNC_STATUS_VIRTUAL_LINK_UP); 1360e40a826aSSudarsana Reddy Kalluru qed_read_pf_bandwidth(p_hwfn, &shmem_info); 1361e40a826aSSudarsana Reddy Kalluru DP_VERBOSE(p_hwfn, NETIF_MSG_LINK, 1362e40a826aSSudarsana Reddy Kalluru "Virtual link_up = %d\n", p_link->link_up); 1363e40a826aSSudarsana Reddy Kalluru } else { 1364cc875c2eSYuval Mintz p_link->link_up = !!(status & LINK_STATUS_LINK_UP); 1365e40a826aSSudarsana Reddy Kalluru DP_VERBOSE(p_hwfn, NETIF_MSG_LINK, 1366e40a826aSSudarsana Reddy Kalluru "Physical link_up = %d\n", p_link->link_up); 1367e40a826aSSudarsana Reddy Kalluru } 1368e40a826aSSudarsana Reddy Kalluru } else { 1369fc916ff2SSudarsana Reddy Kalluru p_link->link_up = false; 1370e40a826aSSudarsana Reddy Kalluru } 1371cc875c2eSYuval Mintz 1372cc875c2eSYuval Mintz p_link->full_duplex = true; 1373cc875c2eSYuval Mintz switch ((status & LINK_STATUS_SPEED_AND_DUPLEX_MASK)) { 1374cc875c2eSYuval Mintz case LINK_STATUS_SPEED_AND_DUPLEX_100G: 1375cc875c2eSYuval Mintz p_link->speed = 100000; 1376cc875c2eSYuval Mintz break; 1377cc875c2eSYuval Mintz case LINK_STATUS_SPEED_AND_DUPLEX_50G: 1378cc875c2eSYuval Mintz p_link->speed = 50000; 1379cc875c2eSYuval Mintz break; 1380cc875c2eSYuval Mintz case LINK_STATUS_SPEED_AND_DUPLEX_40G: 1381cc875c2eSYuval Mintz p_link->speed = 40000; 1382cc875c2eSYuval Mintz break; 1383cc875c2eSYuval Mintz case LINK_STATUS_SPEED_AND_DUPLEX_25G: 1384cc875c2eSYuval Mintz p_link->speed = 25000; 1385cc875c2eSYuval Mintz break; 1386cc875c2eSYuval Mintz case LINK_STATUS_SPEED_AND_DUPLEX_20G: 1387cc875c2eSYuval Mintz p_link->speed = 20000; 1388cc875c2eSYuval Mintz break; 1389cc875c2eSYuval Mintz case LINK_STATUS_SPEED_AND_DUPLEX_10G: 1390cc875c2eSYuval Mintz p_link->speed = 10000; 1391cc875c2eSYuval Mintz break; 1392cc875c2eSYuval Mintz case LINK_STATUS_SPEED_AND_DUPLEX_1000THD: 1393cc875c2eSYuval Mintz p_link->full_duplex = false; 1394cc875c2eSYuval Mintz /* Fall-through */ 1395cc875c2eSYuval Mintz case LINK_STATUS_SPEED_AND_DUPLEX_1000TFD: 1396cc875c2eSYuval Mintz p_link->speed = 1000; 1397cc875c2eSYuval Mintz break; 1398cc875c2eSYuval Mintz default: 1399cc875c2eSYuval Mintz p_link->speed = 0; 140058874c7bSSudarsana Reddy Kalluru p_link->link_up = 0; 1401cc875c2eSYuval Mintz } 1402cc875c2eSYuval Mintz 14034b01e519SManish Chopra if (p_link->link_up && p_link->speed) 14044b01e519SManish Chopra p_link->line_speed = p_link->speed; 14054b01e519SManish Chopra else 14064b01e519SManish Chopra p_link->line_speed = 0; 14074b01e519SManish Chopra 14084b01e519SManish Chopra max_bw = p_hwfn->mcp_info->func_info.bandwidth_max; 1409a64b02d5SManish Chopra min_bw = p_hwfn->mcp_info->func_info.bandwidth_min; 14104b01e519SManish Chopra 1411a64b02d5SManish Chopra /* Max bandwidth configuration */ 14124b01e519SManish Chopra __qed_configure_pf_max_bandwidth(p_hwfn, p_ptt, p_link, max_bw); 1413cc875c2eSYuval Mintz 1414a64b02d5SManish Chopra /* Min bandwidth configuration */ 1415a64b02d5SManish Chopra __qed_configure_pf_min_bandwidth(p_hwfn, p_ptt, p_link, min_bw); 14166f437d43SMintz, Yuval qed_configure_vp_wfq_on_link_change(p_hwfn->cdev, p_ptt, 14176f437d43SMintz, Yuval p_link->min_pf_rate); 1418a64b02d5SManish Chopra 1419cc875c2eSYuval Mintz p_link->an = !!(status & LINK_STATUS_AUTO_NEGOTIATE_ENABLED); 1420cc875c2eSYuval Mintz p_link->an_complete = !!(status & 1421cc875c2eSYuval Mintz LINK_STATUS_AUTO_NEGOTIATE_COMPLETE); 1422cc875c2eSYuval Mintz p_link->parallel_detection = !!(status & 1423cc875c2eSYuval Mintz LINK_STATUS_PARALLEL_DETECTION_USED); 1424cc875c2eSYuval Mintz p_link->pfc_enabled = !!(status & LINK_STATUS_PFC_ENABLED); 1425cc875c2eSYuval Mintz 1426cc875c2eSYuval Mintz p_link->partner_adv_speed |= 1427cc875c2eSYuval Mintz (status & LINK_STATUS_LINK_PARTNER_1000TFD_CAPABLE) ? 1428cc875c2eSYuval Mintz QED_LINK_PARTNER_SPEED_1G_FD : 0; 1429cc875c2eSYuval Mintz p_link->partner_adv_speed |= 1430cc875c2eSYuval Mintz (status & LINK_STATUS_LINK_PARTNER_1000THD_CAPABLE) ? 1431cc875c2eSYuval Mintz QED_LINK_PARTNER_SPEED_1G_HD : 0; 1432cc875c2eSYuval Mintz p_link->partner_adv_speed |= 1433cc875c2eSYuval Mintz (status & LINK_STATUS_LINK_PARTNER_10G_CAPABLE) ? 1434cc875c2eSYuval Mintz QED_LINK_PARTNER_SPEED_10G : 0; 1435cc875c2eSYuval Mintz p_link->partner_adv_speed |= 1436cc875c2eSYuval Mintz (status & LINK_STATUS_LINK_PARTNER_20G_CAPABLE) ? 1437cc875c2eSYuval Mintz QED_LINK_PARTNER_SPEED_20G : 0; 1438cc875c2eSYuval Mintz p_link->partner_adv_speed |= 1439054c67d1SSudarsana Reddy Kalluru (status & LINK_STATUS_LINK_PARTNER_25G_CAPABLE) ? 1440054c67d1SSudarsana Reddy Kalluru QED_LINK_PARTNER_SPEED_25G : 0; 1441054c67d1SSudarsana Reddy Kalluru p_link->partner_adv_speed |= 1442cc875c2eSYuval Mintz (status & LINK_STATUS_LINK_PARTNER_40G_CAPABLE) ? 1443cc875c2eSYuval Mintz QED_LINK_PARTNER_SPEED_40G : 0; 1444cc875c2eSYuval Mintz p_link->partner_adv_speed |= 1445cc875c2eSYuval Mintz (status & LINK_STATUS_LINK_PARTNER_50G_CAPABLE) ? 1446cc875c2eSYuval Mintz QED_LINK_PARTNER_SPEED_50G : 0; 1447cc875c2eSYuval Mintz p_link->partner_adv_speed |= 1448cc875c2eSYuval Mintz (status & LINK_STATUS_LINK_PARTNER_100G_CAPABLE) ? 1449cc875c2eSYuval Mintz QED_LINK_PARTNER_SPEED_100G : 0; 1450cc875c2eSYuval Mintz 1451cc875c2eSYuval Mintz p_link->partner_tx_flow_ctrl_en = 1452cc875c2eSYuval Mintz !!(status & LINK_STATUS_TX_FLOW_CONTROL_ENABLED); 1453cc875c2eSYuval Mintz p_link->partner_rx_flow_ctrl_en = 1454cc875c2eSYuval Mintz !!(status & LINK_STATUS_RX_FLOW_CONTROL_ENABLED); 1455cc875c2eSYuval Mintz 1456cc875c2eSYuval Mintz switch (status & LINK_STATUS_LINK_PARTNER_FLOW_CONTROL_MASK) { 1457cc875c2eSYuval Mintz case LINK_STATUS_LINK_PARTNER_SYMMETRIC_PAUSE: 1458cc875c2eSYuval Mintz p_link->partner_adv_pause = QED_LINK_PARTNER_SYMMETRIC_PAUSE; 1459cc875c2eSYuval Mintz break; 1460cc875c2eSYuval Mintz case LINK_STATUS_LINK_PARTNER_ASYMMETRIC_PAUSE: 1461cc875c2eSYuval Mintz p_link->partner_adv_pause = QED_LINK_PARTNER_ASYMMETRIC_PAUSE; 1462cc875c2eSYuval Mintz break; 1463cc875c2eSYuval Mintz case LINK_STATUS_LINK_PARTNER_BOTH_PAUSE: 1464cc875c2eSYuval Mintz p_link->partner_adv_pause = QED_LINK_PARTNER_BOTH_PAUSE; 1465cc875c2eSYuval Mintz break; 1466cc875c2eSYuval Mintz default: 1467cc875c2eSYuval Mintz p_link->partner_adv_pause = 0; 1468cc875c2eSYuval Mintz } 1469cc875c2eSYuval Mintz 1470cc875c2eSYuval Mintz p_link->sfp_tx_fault = !!(status & LINK_STATUS_SFP_TX_FAULT); 1471cc875c2eSYuval Mintz 1472645874e5SSudarsana Reddy Kalluru if (p_hwfn->mcp_info->capabilities & FW_MB_PARAM_FEATURE_SUPPORT_EEE) 1473645874e5SSudarsana Reddy Kalluru qed_mcp_read_eee_config(p_hwfn, p_ptt, p_link); 1474645874e5SSudarsana Reddy Kalluru 1475706d0891SRahul Verma qed_link_update(p_hwfn, p_ptt); 147665ed2ffdSMintz, Yuval out: 147765ed2ffdSMintz, Yuval spin_unlock_bh(&p_hwfn->mcp_info->link_lock); 1478cc875c2eSYuval Mintz } 1479cc875c2eSYuval Mintz 1480351a4dedSYuval Mintz int qed_mcp_set_link(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, bool b_up) 1481cc875c2eSYuval Mintz { 1482cc875c2eSYuval Mintz struct qed_mcp_link_params *params = &p_hwfn->mcp_info->link_input; 14835529bad9STomer Tayar struct qed_mcp_mb_params mb_params; 14842f67af8cSTomer Tayar struct eth_phy_cfg phy_cfg; 1485cc875c2eSYuval Mintz int rc = 0; 14865529bad9STomer Tayar u32 cmd; 1487cc875c2eSYuval Mintz 1488cc875c2eSYuval Mintz /* Set the shmem configuration according to params */ 14892f67af8cSTomer Tayar memset(&phy_cfg, 0, sizeof(phy_cfg)); 1490cc875c2eSYuval Mintz cmd = b_up ? DRV_MSG_CODE_INIT_PHY : DRV_MSG_CODE_LINK_RESET; 1491cc875c2eSYuval Mintz if (!params->speed.autoneg) 14922f67af8cSTomer Tayar phy_cfg.speed = params->speed.forced_speed; 14932f67af8cSTomer Tayar phy_cfg.pause |= (params->pause.autoneg) ? ETH_PAUSE_AUTONEG : 0; 14942f67af8cSTomer Tayar phy_cfg.pause |= (params->pause.forced_rx) ? ETH_PAUSE_RX : 0; 14952f67af8cSTomer Tayar phy_cfg.pause |= (params->pause.forced_tx) ? ETH_PAUSE_TX : 0; 14962f67af8cSTomer Tayar phy_cfg.adv_speed = params->speed.advertised_speeds; 14972f67af8cSTomer Tayar phy_cfg.loopback_mode = params->loopback_mode; 14984ad95a93SSudarsana Reddy Kalluru 14994ad95a93SSudarsana Reddy Kalluru /* There are MFWs that share this capability regardless of whether 15004ad95a93SSudarsana Reddy Kalluru * this is feasible or not. And given that at the very least adv_caps 15014ad95a93SSudarsana Reddy Kalluru * would be set internally by qed, we want to make sure LFA would 15024ad95a93SSudarsana Reddy Kalluru * still work. 15034ad95a93SSudarsana Reddy Kalluru */ 15044ad95a93SSudarsana Reddy Kalluru if ((p_hwfn->mcp_info->capabilities & 15054ad95a93SSudarsana Reddy Kalluru FW_MB_PARAM_FEATURE_SUPPORT_EEE) && params->eee.enable) { 1506645874e5SSudarsana Reddy Kalluru phy_cfg.eee_cfg |= EEE_CFG_EEE_ENABLED; 1507645874e5SSudarsana Reddy Kalluru if (params->eee.tx_lpi_enable) 1508645874e5SSudarsana Reddy Kalluru phy_cfg.eee_cfg |= EEE_CFG_TX_LPI; 1509645874e5SSudarsana Reddy Kalluru if (params->eee.adv_caps & QED_EEE_1G_ADV) 1510645874e5SSudarsana Reddy Kalluru phy_cfg.eee_cfg |= EEE_CFG_ADV_SPEED_1G; 1511645874e5SSudarsana Reddy Kalluru if (params->eee.adv_caps & QED_EEE_10G_ADV) 1512645874e5SSudarsana Reddy Kalluru phy_cfg.eee_cfg |= EEE_CFG_ADV_SPEED_10G; 1513645874e5SSudarsana Reddy Kalluru phy_cfg.eee_cfg |= (params->eee.tx_lpi_timer << 1514645874e5SSudarsana Reddy Kalluru EEE_TX_TIMER_USEC_OFFSET) & 1515645874e5SSudarsana Reddy Kalluru EEE_TX_TIMER_USEC_MASK; 1516645874e5SSudarsana Reddy Kalluru } 1517cc875c2eSYuval Mintz 1518fc916ff2SSudarsana Reddy Kalluru p_hwfn->b_drv_link_init = b_up; 1519fc916ff2SSudarsana Reddy Kalluru 1520cc875c2eSYuval Mintz if (b_up) { 1521cc875c2eSYuval Mintz DP_VERBOSE(p_hwfn, NETIF_MSG_LINK, 1522cc875c2eSYuval Mintz "Configuring Link: Speed 0x%08x, Pause 0x%08x, adv_speed 0x%08x, loopback 0x%08x, features 0x%08x\n", 15232f67af8cSTomer Tayar phy_cfg.speed, 15242f67af8cSTomer Tayar phy_cfg.pause, 15252f67af8cSTomer Tayar phy_cfg.adv_speed, 15262f67af8cSTomer Tayar phy_cfg.loopback_mode, 15272f67af8cSTomer Tayar phy_cfg.feature_config_flags); 1528cc875c2eSYuval Mintz } else { 1529cc875c2eSYuval Mintz DP_VERBOSE(p_hwfn, NETIF_MSG_LINK, 1530cc875c2eSYuval Mintz "Resetting link\n"); 1531cc875c2eSYuval Mintz } 1532cc875c2eSYuval Mintz 15335529bad9STomer Tayar memset(&mb_params, 0, sizeof(mb_params)); 15345529bad9STomer Tayar mb_params.cmd = cmd; 15352f67af8cSTomer Tayar mb_params.p_data_src = &phy_cfg; 15362f67af8cSTomer Tayar mb_params.data_src_size = sizeof(phy_cfg); 15375529bad9STomer Tayar rc = qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 1538cc875c2eSYuval Mintz 1539cc875c2eSYuval Mintz /* if mcp fails to respond we must abort */ 1540cc875c2eSYuval Mintz if (rc) { 1541cc875c2eSYuval Mintz DP_ERR(p_hwfn, "MCP response failure, aborting\n"); 1542cc875c2eSYuval Mintz return rc; 1543cc875c2eSYuval Mintz } 1544cc875c2eSYuval Mintz 154565ed2ffdSMintz, Yuval /* Mimic link-change attention, done for several reasons: 154665ed2ffdSMintz, Yuval * - On reset, there's no guarantee MFW would trigger 154765ed2ffdSMintz, Yuval * an attention. 154865ed2ffdSMintz, Yuval * - On initialization, older MFWs might not indicate link change 154965ed2ffdSMintz, Yuval * during LFA, so we'll never get an UP indication. 155065ed2ffdSMintz, Yuval */ 155165ed2ffdSMintz, Yuval qed_mcp_handle_link_change(p_hwfn, p_ptt, !b_up); 1552cc875c2eSYuval Mintz 1553cc875c2eSYuval Mintz return 0; 1554cc875c2eSYuval Mintz } 1555cc875c2eSYuval Mintz 155664515dc8STomer Tayar u32 qed_get_process_kill_counter(struct qed_hwfn *p_hwfn, 155764515dc8STomer Tayar struct qed_ptt *p_ptt) 155864515dc8STomer Tayar { 155964515dc8STomer Tayar u32 path_offsize_addr, path_offsize, path_addr, proc_kill_cnt; 156064515dc8STomer Tayar 156164515dc8STomer Tayar if (IS_VF(p_hwfn->cdev)) 156264515dc8STomer Tayar return -EINVAL; 156364515dc8STomer Tayar 156464515dc8STomer Tayar path_offsize_addr = SECTION_OFFSIZE_ADDR(p_hwfn->mcp_info->public_base, 156564515dc8STomer Tayar PUBLIC_PATH); 156664515dc8STomer Tayar path_offsize = qed_rd(p_hwfn, p_ptt, path_offsize_addr); 156764515dc8STomer Tayar path_addr = SECTION_ADDR(path_offsize, QED_PATH_ID(p_hwfn)); 156864515dc8STomer Tayar 156964515dc8STomer Tayar proc_kill_cnt = qed_rd(p_hwfn, p_ptt, 157064515dc8STomer Tayar path_addr + 157164515dc8STomer Tayar offsetof(struct public_path, process_kill)) & 157264515dc8STomer Tayar PROCESS_KILL_COUNTER_MASK; 157364515dc8STomer Tayar 157464515dc8STomer Tayar return proc_kill_cnt; 157564515dc8STomer Tayar } 157664515dc8STomer Tayar 157764515dc8STomer Tayar static void qed_mcp_handle_process_kill(struct qed_hwfn *p_hwfn, 157864515dc8STomer Tayar struct qed_ptt *p_ptt) 157964515dc8STomer Tayar { 158064515dc8STomer Tayar struct qed_dev *cdev = p_hwfn->cdev; 158164515dc8STomer Tayar u32 proc_kill_cnt; 158264515dc8STomer Tayar 158364515dc8STomer Tayar /* Prevent possible attentions/interrupts during the recovery handling 158464515dc8STomer Tayar * and till its load phase, during which they will be re-enabled. 158564515dc8STomer Tayar */ 158664515dc8STomer Tayar qed_int_igu_disable_int(p_hwfn, p_ptt); 158764515dc8STomer Tayar 158864515dc8STomer Tayar DP_NOTICE(p_hwfn, "Received a process kill indication\n"); 158964515dc8STomer Tayar 159064515dc8STomer Tayar /* The following operations should be done once, and thus in CMT mode 159164515dc8STomer Tayar * are carried out by only the first HW function. 159264515dc8STomer Tayar */ 159364515dc8STomer Tayar if (p_hwfn != QED_LEADING_HWFN(cdev)) 159464515dc8STomer Tayar return; 159564515dc8STomer Tayar 159664515dc8STomer Tayar if (cdev->recov_in_prog) { 159764515dc8STomer Tayar DP_NOTICE(p_hwfn, 159864515dc8STomer Tayar "Ignoring the indication since a recovery process is already in progress\n"); 159964515dc8STomer Tayar return; 160064515dc8STomer Tayar } 160164515dc8STomer Tayar 160264515dc8STomer Tayar cdev->recov_in_prog = true; 160364515dc8STomer Tayar 160464515dc8STomer Tayar proc_kill_cnt = qed_get_process_kill_counter(p_hwfn, p_ptt); 160564515dc8STomer Tayar DP_NOTICE(p_hwfn, "Process kill counter: %d\n", proc_kill_cnt); 160664515dc8STomer Tayar 160764515dc8STomer Tayar qed_schedule_recovery_handler(p_hwfn); 160864515dc8STomer Tayar } 160964515dc8STomer Tayar 16106c754246SSudarsana Reddy Kalluru static void qed_mcp_send_protocol_stats(struct qed_hwfn *p_hwfn, 16116c754246SSudarsana Reddy Kalluru struct qed_ptt *p_ptt, 16126c754246SSudarsana Reddy Kalluru enum MFW_DRV_MSG_TYPE type) 16136c754246SSudarsana Reddy Kalluru { 16146c754246SSudarsana Reddy Kalluru enum qed_mcp_protocol_type stats_type; 16156c754246SSudarsana Reddy Kalluru union qed_mcp_protocol_stats stats; 16166c754246SSudarsana Reddy Kalluru struct qed_mcp_mb_params mb_params; 16176c754246SSudarsana Reddy Kalluru u32 hsi_param; 16186c754246SSudarsana Reddy Kalluru 16196c754246SSudarsana Reddy Kalluru switch (type) { 16206c754246SSudarsana Reddy Kalluru case MFW_DRV_MSG_GET_LAN_STATS: 16216c754246SSudarsana Reddy Kalluru stats_type = QED_MCP_LAN_STATS; 16226c754246SSudarsana Reddy Kalluru hsi_param = DRV_MSG_CODE_STATS_TYPE_LAN; 16236c754246SSudarsana Reddy Kalluru break; 16246c754246SSudarsana Reddy Kalluru case MFW_DRV_MSG_GET_FCOE_STATS: 16256c754246SSudarsana Reddy Kalluru stats_type = QED_MCP_FCOE_STATS; 16266c754246SSudarsana Reddy Kalluru hsi_param = DRV_MSG_CODE_STATS_TYPE_FCOE; 16276c754246SSudarsana Reddy Kalluru break; 16286c754246SSudarsana Reddy Kalluru case MFW_DRV_MSG_GET_ISCSI_STATS: 16296c754246SSudarsana Reddy Kalluru stats_type = QED_MCP_ISCSI_STATS; 16306c754246SSudarsana Reddy Kalluru hsi_param = DRV_MSG_CODE_STATS_TYPE_ISCSI; 16316c754246SSudarsana Reddy Kalluru break; 16326c754246SSudarsana Reddy Kalluru case MFW_DRV_MSG_GET_RDMA_STATS: 16336c754246SSudarsana Reddy Kalluru stats_type = QED_MCP_RDMA_STATS; 16346c754246SSudarsana Reddy Kalluru hsi_param = DRV_MSG_CODE_STATS_TYPE_RDMA; 16356c754246SSudarsana Reddy Kalluru break; 16366c754246SSudarsana Reddy Kalluru default: 16376c754246SSudarsana Reddy Kalluru DP_NOTICE(p_hwfn, "Invalid protocol type %d\n", type); 16386c754246SSudarsana Reddy Kalluru return; 16396c754246SSudarsana Reddy Kalluru } 16406c754246SSudarsana Reddy Kalluru 16416c754246SSudarsana Reddy Kalluru qed_get_protocol_stats(p_hwfn->cdev, stats_type, &stats); 16426c754246SSudarsana Reddy Kalluru 16436c754246SSudarsana Reddy Kalluru memset(&mb_params, 0, sizeof(mb_params)); 16446c754246SSudarsana Reddy Kalluru mb_params.cmd = DRV_MSG_CODE_GET_STATS; 16456c754246SSudarsana Reddy Kalluru mb_params.param = hsi_param; 16462f67af8cSTomer Tayar mb_params.p_data_src = &stats; 16472f67af8cSTomer Tayar mb_params.data_src_size = sizeof(stats); 16486c754246SSudarsana Reddy Kalluru qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 16496c754246SSudarsana Reddy Kalluru } 16506c754246SSudarsana Reddy Kalluru 16511a635e48SYuval Mintz static void qed_mcp_update_bw(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 16524b01e519SManish Chopra { 16534b01e519SManish Chopra struct qed_mcp_function_info *p_info; 16544b01e519SManish Chopra struct public_func shmem_info; 16554b01e519SManish Chopra u32 resp = 0, param = 0; 16564b01e519SManish Chopra 16571a635e48SYuval Mintz qed_mcp_get_shmem_func(p_hwfn, p_ptt, &shmem_info, MCP_PF_ID(p_hwfn)); 16584b01e519SManish Chopra 16594b01e519SManish Chopra qed_read_pf_bandwidth(p_hwfn, &shmem_info); 16604b01e519SManish Chopra 16614b01e519SManish Chopra p_info = &p_hwfn->mcp_info->func_info; 16624b01e519SManish Chopra 1663a64b02d5SManish Chopra qed_configure_pf_min_bandwidth(p_hwfn->cdev, p_info->bandwidth_min); 16644b01e519SManish Chopra qed_configure_pf_max_bandwidth(p_hwfn->cdev, p_info->bandwidth_max); 16654b01e519SManish Chopra 16664b01e519SManish Chopra /* Acknowledge the MFW */ 16674b01e519SManish Chopra qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_BW_UPDATE_ACK, 0, &resp, 16684b01e519SManish Chopra ¶m); 16694b01e519SManish Chopra } 16704b01e519SManish Chopra 16712a351fd9SMintz, Yuval static void qed_mcp_update_stag(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 16722a351fd9SMintz, Yuval { 16732a351fd9SMintz, Yuval struct public_func shmem_info; 16742a351fd9SMintz, Yuval u32 resp = 0, param = 0; 16752a351fd9SMintz, Yuval 16762a351fd9SMintz, Yuval qed_mcp_get_shmem_func(p_hwfn, p_ptt, &shmem_info, MCP_PF_ID(p_hwfn)); 16772a351fd9SMintz, Yuval 16782a351fd9SMintz, Yuval p_hwfn->mcp_info->func_info.ovlan = (u16)shmem_info.ovlan_stag & 16792a351fd9SMintz, Yuval FUNC_MF_CFG_OV_STAG_MASK; 16802a351fd9SMintz, Yuval p_hwfn->hw_info.ovlan = p_hwfn->mcp_info->func_info.ovlan; 16817e3e375cSSudarsana Reddy Kalluru if (test_bit(QED_MF_OVLAN_CLSS, &p_hwfn->cdev->mf_bits)) { 16827e3e375cSSudarsana Reddy Kalluru if (p_hwfn->hw_info.ovlan != QED_MCP_VLAN_UNSET) { 16837e3e375cSSudarsana Reddy Kalluru qed_wr(p_hwfn, p_ptt, NIG_REG_LLH_FUNC_TAG_VALUE, 16847e3e375cSSudarsana Reddy Kalluru p_hwfn->hw_info.ovlan); 16857e3e375cSSudarsana Reddy Kalluru qed_wr(p_hwfn, p_ptt, NIG_REG_LLH_FUNC_TAG_EN, 1); 16867e3e375cSSudarsana Reddy Kalluru 16877e3e375cSSudarsana Reddy Kalluru /* Configure DB to add external vlan to EDPM packets */ 16887e3e375cSSudarsana Reddy Kalluru qed_wr(p_hwfn, p_ptt, DORQ_REG_TAG1_OVRD_MODE, 1); 16897e3e375cSSudarsana Reddy Kalluru qed_wr(p_hwfn, p_ptt, DORQ_REG_PF_EXT_VID_BB_K2, 16907e3e375cSSudarsana Reddy Kalluru p_hwfn->hw_info.ovlan); 16917e3e375cSSudarsana Reddy Kalluru } else { 16927e3e375cSSudarsana Reddy Kalluru qed_wr(p_hwfn, p_ptt, NIG_REG_LLH_FUNC_TAG_EN, 0); 16937e3e375cSSudarsana Reddy Kalluru qed_wr(p_hwfn, p_ptt, NIG_REG_LLH_FUNC_TAG_VALUE, 0); 16947e3e375cSSudarsana Reddy Kalluru qed_wr(p_hwfn, p_ptt, DORQ_REG_TAG1_OVRD_MODE, 0); 16957e3e375cSSudarsana Reddy Kalluru qed_wr(p_hwfn, p_ptt, DORQ_REG_PF_EXT_VID_BB_K2, 0); 16967e3e375cSSudarsana Reddy Kalluru } 16977e3e375cSSudarsana Reddy Kalluru 16982a351fd9SMintz, Yuval qed_sp_pf_update_stag(p_hwfn); 16992a351fd9SMintz, Yuval } 17002a351fd9SMintz, Yuval 17017e3e375cSSudarsana Reddy Kalluru DP_VERBOSE(p_hwfn, QED_MSG_SP, "ovlan = %d hw_mode = 0x%x\n", 17027e3e375cSSudarsana Reddy Kalluru p_hwfn->mcp_info->func_info.ovlan, p_hwfn->hw_info.hw_mode); 17037e3e375cSSudarsana Reddy Kalluru 17042a351fd9SMintz, Yuval /* Acknowledge the MFW */ 17052a351fd9SMintz, Yuval qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_S_TAG_UPDATE_ACK, 0, 17062a351fd9SMintz, Yuval &resp, ¶m); 17072a351fd9SMintz, Yuval } 17082a351fd9SMintz, Yuval 1709cac6f691SSudarsana Reddy Kalluru void qed_mcp_read_ufp_config(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 1710cac6f691SSudarsana Reddy Kalluru { 1711cac6f691SSudarsana Reddy Kalluru struct public_func shmem_info; 1712cac6f691SSudarsana Reddy Kalluru u32 port_cfg, val; 1713cac6f691SSudarsana Reddy Kalluru 1714cac6f691SSudarsana Reddy Kalluru if (!test_bit(QED_MF_UFP_SPECIFIC, &p_hwfn->cdev->mf_bits)) 1715cac6f691SSudarsana Reddy Kalluru return; 1716cac6f691SSudarsana Reddy Kalluru 1717cac6f691SSudarsana Reddy Kalluru memset(&p_hwfn->ufp_info, 0, sizeof(p_hwfn->ufp_info)); 1718cac6f691SSudarsana Reddy Kalluru port_cfg = qed_rd(p_hwfn, p_ptt, p_hwfn->mcp_info->port_addr + 1719cac6f691SSudarsana Reddy Kalluru offsetof(struct public_port, oem_cfg_port)); 1720cac6f691SSudarsana Reddy Kalluru val = (port_cfg & OEM_CFG_CHANNEL_TYPE_MASK) >> 1721cac6f691SSudarsana Reddy Kalluru OEM_CFG_CHANNEL_TYPE_OFFSET; 1722cac6f691SSudarsana Reddy Kalluru if (val != OEM_CFG_CHANNEL_TYPE_STAGGED) 1723ec036eb9SSudarsana Reddy Kalluru DP_NOTICE(p_hwfn, 1724ec036eb9SSudarsana Reddy Kalluru "Incorrect UFP Channel type %d port_id 0x%02x\n", 1725ec036eb9SSudarsana Reddy Kalluru val, MFW_PORT(p_hwfn)); 1726cac6f691SSudarsana Reddy Kalluru 1727cac6f691SSudarsana Reddy Kalluru val = (port_cfg & OEM_CFG_SCHED_TYPE_MASK) >> OEM_CFG_SCHED_TYPE_OFFSET; 1728cac6f691SSudarsana Reddy Kalluru if (val == OEM_CFG_SCHED_TYPE_ETS) { 1729cac6f691SSudarsana Reddy Kalluru p_hwfn->ufp_info.mode = QED_UFP_MODE_ETS; 1730cac6f691SSudarsana Reddy Kalluru } else if (val == OEM_CFG_SCHED_TYPE_VNIC_BW) { 1731cac6f691SSudarsana Reddy Kalluru p_hwfn->ufp_info.mode = QED_UFP_MODE_VNIC_BW; 1732cac6f691SSudarsana Reddy Kalluru } else { 1733cac6f691SSudarsana Reddy Kalluru p_hwfn->ufp_info.mode = QED_UFP_MODE_UNKNOWN; 1734ec036eb9SSudarsana Reddy Kalluru DP_NOTICE(p_hwfn, 1735ec036eb9SSudarsana Reddy Kalluru "Unknown UFP scheduling mode %d port_id 0x%02x\n", 1736ec036eb9SSudarsana Reddy Kalluru val, MFW_PORT(p_hwfn)); 1737cac6f691SSudarsana Reddy Kalluru } 1738cac6f691SSudarsana Reddy Kalluru 1739cac6f691SSudarsana Reddy Kalluru qed_mcp_get_shmem_func(p_hwfn, p_ptt, &shmem_info, MCP_PF_ID(p_hwfn)); 1740b5fabb08SSudarsana Reddy Kalluru val = (shmem_info.oem_cfg_func & OEM_CFG_FUNC_TC_MASK) >> 1741b5fabb08SSudarsana Reddy Kalluru OEM_CFG_FUNC_TC_OFFSET; 1742cac6f691SSudarsana Reddy Kalluru p_hwfn->ufp_info.tc = (u8)val; 1743b5fabb08SSudarsana Reddy Kalluru val = (shmem_info.oem_cfg_func & OEM_CFG_FUNC_HOST_PRI_CTRL_MASK) >> 1744cac6f691SSudarsana Reddy Kalluru OEM_CFG_FUNC_HOST_PRI_CTRL_OFFSET; 1745cac6f691SSudarsana Reddy Kalluru if (val == OEM_CFG_FUNC_HOST_PRI_CTRL_VNIC) { 1746cac6f691SSudarsana Reddy Kalluru p_hwfn->ufp_info.pri_type = QED_UFP_PRI_VNIC; 1747cac6f691SSudarsana Reddy Kalluru } else if (val == OEM_CFG_FUNC_HOST_PRI_CTRL_OS) { 1748cac6f691SSudarsana Reddy Kalluru p_hwfn->ufp_info.pri_type = QED_UFP_PRI_OS; 1749cac6f691SSudarsana Reddy Kalluru } else { 1750cac6f691SSudarsana Reddy Kalluru p_hwfn->ufp_info.pri_type = QED_UFP_PRI_UNKNOWN; 1751ec036eb9SSudarsana Reddy Kalluru DP_NOTICE(p_hwfn, 1752ec036eb9SSudarsana Reddy Kalluru "Unknown Host priority control %d port_id 0x%02x\n", 1753ec036eb9SSudarsana Reddy Kalluru val, MFW_PORT(p_hwfn)); 1754cac6f691SSudarsana Reddy Kalluru } 1755cac6f691SSudarsana Reddy Kalluru 1756cac6f691SSudarsana Reddy Kalluru DP_NOTICE(p_hwfn, 1757ec036eb9SSudarsana Reddy Kalluru "UFP shmem config: mode = %d tc = %d pri_type = %d port_id 0x%02x\n", 1758ec036eb9SSudarsana Reddy Kalluru p_hwfn->ufp_info.mode, p_hwfn->ufp_info.tc, 1759ec036eb9SSudarsana Reddy Kalluru p_hwfn->ufp_info.pri_type, MFW_PORT(p_hwfn)); 1760cac6f691SSudarsana Reddy Kalluru } 1761cac6f691SSudarsana Reddy Kalluru 1762cac6f691SSudarsana Reddy Kalluru static int 1763cac6f691SSudarsana Reddy Kalluru qed_mcp_handle_ufp_event(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 1764cac6f691SSudarsana Reddy Kalluru { 1765cac6f691SSudarsana Reddy Kalluru qed_mcp_read_ufp_config(p_hwfn, p_ptt); 1766cac6f691SSudarsana Reddy Kalluru 1767cac6f691SSudarsana Reddy Kalluru if (p_hwfn->ufp_info.mode == QED_UFP_MODE_VNIC_BW) { 1768cac6f691SSudarsana Reddy Kalluru p_hwfn->qm_info.ooo_tc = p_hwfn->ufp_info.tc; 1769c4259ddaSDenis Bolotin qed_hw_info_set_offload_tc(&p_hwfn->hw_info, 1770c4259ddaSDenis Bolotin p_hwfn->ufp_info.tc); 1771cac6f691SSudarsana Reddy Kalluru 1772cac6f691SSudarsana Reddy Kalluru qed_qm_reconf(p_hwfn, p_ptt); 1773cac6f691SSudarsana Reddy Kalluru } else if (p_hwfn->ufp_info.mode == QED_UFP_MODE_ETS) { 1774cac6f691SSudarsana Reddy Kalluru /* Merge UFP TC with the dcbx TC data */ 1775cac6f691SSudarsana Reddy Kalluru qed_dcbx_mib_update_event(p_hwfn, p_ptt, 1776cac6f691SSudarsana Reddy Kalluru QED_DCBX_OPERATIONAL_MIB); 1777cac6f691SSudarsana Reddy Kalluru } else { 1778cac6f691SSudarsana Reddy Kalluru DP_ERR(p_hwfn, "Invalid sched type, discard the UFP config\n"); 1779cac6f691SSudarsana Reddy Kalluru return -EINVAL; 1780cac6f691SSudarsana Reddy Kalluru } 1781cac6f691SSudarsana Reddy Kalluru 1782cac6f691SSudarsana Reddy Kalluru /* update storm FW with negotiation results */ 1783cac6f691SSudarsana Reddy Kalluru qed_sp_pf_update_ufp(p_hwfn); 1784cac6f691SSudarsana Reddy Kalluru 1785cac6f691SSudarsana Reddy Kalluru /* update stag pcp value */ 1786cac6f691SSudarsana Reddy Kalluru qed_sp_pf_update_stag(p_hwfn); 1787cac6f691SSudarsana Reddy Kalluru 1788cac6f691SSudarsana Reddy Kalluru return 0; 1789cac6f691SSudarsana Reddy Kalluru } 1790cac6f691SSudarsana Reddy Kalluru 1791cc875c2eSYuval Mintz int qed_mcp_handle_events(struct qed_hwfn *p_hwfn, 1792cc875c2eSYuval Mintz struct qed_ptt *p_ptt) 1793cc875c2eSYuval Mintz { 1794cc875c2eSYuval Mintz struct qed_mcp_info *info = p_hwfn->mcp_info; 1795cc875c2eSYuval Mintz int rc = 0; 1796cc875c2eSYuval Mintz bool found = false; 1797cc875c2eSYuval Mintz u16 i; 1798cc875c2eSYuval Mintz 1799cc875c2eSYuval Mintz DP_VERBOSE(p_hwfn, QED_MSG_SP, "Received message from MFW\n"); 1800cc875c2eSYuval Mintz 1801cc875c2eSYuval Mintz /* Read Messages from MFW */ 1802cc875c2eSYuval Mintz qed_mcp_read_mb(p_hwfn, p_ptt); 1803cc875c2eSYuval Mintz 1804cc875c2eSYuval Mintz /* Compare current messages to old ones */ 1805cc875c2eSYuval Mintz for (i = 0; i < info->mfw_mb_length; i++) { 1806cc875c2eSYuval Mintz if (info->mfw_mb_cur[i] == info->mfw_mb_shadow[i]) 1807cc875c2eSYuval Mintz continue; 1808cc875c2eSYuval Mintz 1809cc875c2eSYuval Mintz found = true; 1810cc875c2eSYuval Mintz 1811cc875c2eSYuval Mintz DP_VERBOSE(p_hwfn, NETIF_MSG_LINK, 1812cc875c2eSYuval Mintz "Msg [%d] - old CMD 0x%02x, new CMD 0x%02x\n", 1813cc875c2eSYuval Mintz i, info->mfw_mb_shadow[i], info->mfw_mb_cur[i]); 1814cc875c2eSYuval Mintz 1815cc875c2eSYuval Mintz switch (i) { 1816cc875c2eSYuval Mintz case MFW_DRV_MSG_LINK_CHANGE: 1817cc875c2eSYuval Mintz qed_mcp_handle_link_change(p_hwfn, p_ptt, false); 1818cc875c2eSYuval Mintz break; 18190b55e27dSYuval Mintz case MFW_DRV_MSG_VF_DISABLED: 18200b55e27dSYuval Mintz qed_mcp_handle_vf_flr(p_hwfn, p_ptt); 18210b55e27dSYuval Mintz break; 182239651abdSSudarsana Reddy Kalluru case MFW_DRV_MSG_LLDP_DATA_UPDATED: 182339651abdSSudarsana Reddy Kalluru qed_dcbx_mib_update_event(p_hwfn, p_ptt, 182439651abdSSudarsana Reddy Kalluru QED_DCBX_REMOTE_LLDP_MIB); 182539651abdSSudarsana Reddy Kalluru break; 182639651abdSSudarsana Reddy Kalluru case MFW_DRV_MSG_DCBX_REMOTE_MIB_UPDATED: 182739651abdSSudarsana Reddy Kalluru qed_dcbx_mib_update_event(p_hwfn, p_ptt, 182839651abdSSudarsana Reddy Kalluru QED_DCBX_REMOTE_MIB); 182939651abdSSudarsana Reddy Kalluru break; 183039651abdSSudarsana Reddy Kalluru case MFW_DRV_MSG_DCBX_OPERATIONAL_MIB_UPDATED: 183139651abdSSudarsana Reddy Kalluru qed_dcbx_mib_update_event(p_hwfn, p_ptt, 183239651abdSSudarsana Reddy Kalluru QED_DCBX_OPERATIONAL_MIB); 183339651abdSSudarsana Reddy Kalluru break; 1834cac6f691SSudarsana Reddy Kalluru case MFW_DRV_MSG_OEM_CFG_UPDATE: 1835cac6f691SSudarsana Reddy Kalluru qed_mcp_handle_ufp_event(p_hwfn, p_ptt); 1836cac6f691SSudarsana Reddy Kalluru break; 1837334c03b5SZvi Nachmani case MFW_DRV_MSG_TRANSCEIVER_STATE_CHANGE: 1838334c03b5SZvi Nachmani qed_mcp_handle_transceiver_change(p_hwfn, p_ptt); 1839334c03b5SZvi Nachmani break; 184064515dc8STomer Tayar case MFW_DRV_MSG_ERROR_RECOVERY: 184164515dc8STomer Tayar qed_mcp_handle_process_kill(p_hwfn, p_ptt); 184264515dc8STomer Tayar break; 18436c754246SSudarsana Reddy Kalluru case MFW_DRV_MSG_GET_LAN_STATS: 18446c754246SSudarsana Reddy Kalluru case MFW_DRV_MSG_GET_FCOE_STATS: 18456c754246SSudarsana Reddy Kalluru case MFW_DRV_MSG_GET_ISCSI_STATS: 18466c754246SSudarsana Reddy Kalluru case MFW_DRV_MSG_GET_RDMA_STATS: 18476c754246SSudarsana Reddy Kalluru qed_mcp_send_protocol_stats(p_hwfn, p_ptt, i); 18486c754246SSudarsana Reddy Kalluru break; 18494b01e519SManish Chopra case MFW_DRV_MSG_BW_UPDATE: 18504b01e519SManish Chopra qed_mcp_update_bw(p_hwfn, p_ptt); 18514b01e519SManish Chopra break; 18522a351fd9SMintz, Yuval case MFW_DRV_MSG_S_TAG_UPDATE: 18532a351fd9SMintz, Yuval qed_mcp_update_stag(p_hwfn, p_ptt); 18542a351fd9SMintz, Yuval break; 185559ccf86fSSudarsana Reddy Kalluru case MFW_DRV_MSG_GET_TLV_REQ: 185659ccf86fSSudarsana Reddy Kalluru qed_mfw_tlv_req(p_hwfn); 18572a351fd9SMintz, Yuval break; 1858cc875c2eSYuval Mintz default: 185939815944SMintz, Yuval DP_INFO(p_hwfn, "Unimplemented MFW message %d\n", i); 1860cc875c2eSYuval Mintz rc = -EINVAL; 1861cc875c2eSYuval Mintz } 1862cc875c2eSYuval Mintz } 1863cc875c2eSYuval Mintz 1864cc875c2eSYuval Mintz /* ACK everything */ 1865cc875c2eSYuval Mintz for (i = 0; i < MFW_DRV_MSG_MAX_DWORDS(info->mfw_mb_length); i++) { 1866cc875c2eSYuval Mintz __be32 val = cpu_to_be32(((u32 *)info->mfw_mb_cur)[i]); 1867cc875c2eSYuval Mintz 1868cc875c2eSYuval Mintz /* MFW expect answer in BE, so we force write in that format */ 1869cc875c2eSYuval Mintz qed_wr(p_hwfn, p_ptt, 1870cc875c2eSYuval Mintz info->mfw_mb_addr + sizeof(u32) + 1871cc875c2eSYuval Mintz MFW_DRV_MSG_MAX_DWORDS(info->mfw_mb_length) * 1872cc875c2eSYuval Mintz sizeof(u32) + i * sizeof(u32), 1873cc875c2eSYuval Mintz (__force u32)val); 1874cc875c2eSYuval Mintz } 1875cc875c2eSYuval Mintz 1876cc875c2eSYuval Mintz if (!found) { 1877cc875c2eSYuval Mintz DP_NOTICE(p_hwfn, 1878cc875c2eSYuval Mintz "Received an MFW message indication but no new message!\n"); 1879cc875c2eSYuval Mintz rc = -EINVAL; 1880cc875c2eSYuval Mintz } 1881cc875c2eSYuval Mintz 1882cc875c2eSYuval Mintz /* Copy the new mfw messages into the shadow */ 1883cc875c2eSYuval Mintz memcpy(info->mfw_mb_shadow, info->mfw_mb_cur, info->mfw_mb_length); 1884cc875c2eSYuval Mintz 1885cc875c2eSYuval Mintz return rc; 1886cc875c2eSYuval Mintz } 1887cc875c2eSYuval Mintz 18881408cc1fSYuval Mintz int qed_mcp_get_mfw_ver(struct qed_hwfn *p_hwfn, 18891408cc1fSYuval Mintz struct qed_ptt *p_ptt, 18901408cc1fSYuval Mintz u32 *p_mfw_ver, u32 *p_running_bundle_id) 1891fe56b9e6SYuval Mintz { 1892fe56b9e6SYuval Mintz u32 global_offsize; 1893fe56b9e6SYuval Mintz 18941408cc1fSYuval Mintz if (IS_VF(p_hwfn->cdev)) { 18951408cc1fSYuval Mintz if (p_hwfn->vf_iov_info) { 18961408cc1fSYuval Mintz struct pfvf_acquire_resp_tlv *p_resp; 18971408cc1fSYuval Mintz 18981408cc1fSYuval Mintz p_resp = &p_hwfn->vf_iov_info->acquire_resp; 18991408cc1fSYuval Mintz *p_mfw_ver = p_resp->pfdev_info.mfw_ver; 19001408cc1fSYuval Mintz return 0; 19011408cc1fSYuval Mintz } else { 19021408cc1fSYuval Mintz DP_VERBOSE(p_hwfn, 19031408cc1fSYuval Mintz QED_MSG_IOV, 19041408cc1fSYuval Mintz "VF requested MFW version prior to ACQUIRE\n"); 19051408cc1fSYuval Mintz return -EINVAL; 19061408cc1fSYuval Mintz } 19071408cc1fSYuval Mintz } 1908fe56b9e6SYuval Mintz 1909fe56b9e6SYuval Mintz global_offsize = qed_rd(p_hwfn, p_ptt, 19101408cc1fSYuval Mintz SECTION_OFFSIZE_ADDR(p_hwfn-> 19111408cc1fSYuval Mintz mcp_info->public_base, 1912fe56b9e6SYuval Mintz PUBLIC_GLOBAL)); 19131408cc1fSYuval Mintz *p_mfw_ver = 19141408cc1fSYuval Mintz qed_rd(p_hwfn, p_ptt, 19151408cc1fSYuval Mintz SECTION_ADDR(global_offsize, 19161408cc1fSYuval Mintz 0) + offsetof(struct public_global, mfw_ver)); 1917fe56b9e6SYuval Mintz 19181408cc1fSYuval Mintz if (p_running_bundle_id != NULL) { 19191408cc1fSYuval Mintz *p_running_bundle_id = qed_rd(p_hwfn, p_ptt, 19201408cc1fSYuval Mintz SECTION_ADDR(global_offsize, 0) + 19211408cc1fSYuval Mintz offsetof(struct public_global, 19221408cc1fSYuval Mintz running_bundle_id)); 19231408cc1fSYuval Mintz } 1924fe56b9e6SYuval Mintz 1925fe56b9e6SYuval Mintz return 0; 1926fe56b9e6SYuval Mintz } 1927fe56b9e6SYuval Mintz 1928ae33666aSTomer Tayar int qed_mcp_get_mbi_ver(struct qed_hwfn *p_hwfn, 1929ae33666aSTomer Tayar struct qed_ptt *p_ptt, u32 *p_mbi_ver) 1930ae33666aSTomer Tayar { 1931ae33666aSTomer Tayar u32 nvm_cfg_addr, nvm_cfg1_offset, mbi_ver_addr; 1932ae33666aSTomer Tayar 1933ae33666aSTomer Tayar if (IS_VF(p_hwfn->cdev)) 1934ae33666aSTomer Tayar return -EINVAL; 1935ae33666aSTomer Tayar 1936ae33666aSTomer Tayar /* Read the address of the nvm_cfg */ 1937ae33666aSTomer Tayar nvm_cfg_addr = qed_rd(p_hwfn, p_ptt, MISC_REG_GEN_PURP_CR0); 1938ae33666aSTomer Tayar if (!nvm_cfg_addr) { 1939ae33666aSTomer Tayar DP_NOTICE(p_hwfn, "Shared memory not initialized\n"); 1940ae33666aSTomer Tayar return -EINVAL; 1941ae33666aSTomer Tayar } 1942ae33666aSTomer Tayar 1943ae33666aSTomer Tayar /* Read the offset of nvm_cfg1 */ 1944ae33666aSTomer Tayar nvm_cfg1_offset = qed_rd(p_hwfn, p_ptt, nvm_cfg_addr + 4); 1945ae33666aSTomer Tayar 1946ae33666aSTomer Tayar mbi_ver_addr = MCP_REG_SCRATCH + nvm_cfg1_offset + 1947ae33666aSTomer Tayar offsetof(struct nvm_cfg1, glob) + 1948ae33666aSTomer Tayar offsetof(struct nvm_cfg1_glob, mbi_version); 1949ae33666aSTomer Tayar *p_mbi_ver = qed_rd(p_hwfn, p_ptt, 1950ae33666aSTomer Tayar mbi_ver_addr) & 1951ae33666aSTomer Tayar (NVM_CFG1_GLOB_MBI_VERSION_0_MASK | 1952ae33666aSTomer Tayar NVM_CFG1_GLOB_MBI_VERSION_1_MASK | 1953ae33666aSTomer Tayar NVM_CFG1_GLOB_MBI_VERSION_2_MASK); 1954ae33666aSTomer Tayar 1955ae33666aSTomer Tayar return 0; 1956ae33666aSTomer Tayar } 1957ae33666aSTomer Tayar 1958706d0891SRahul Verma int qed_mcp_get_media_type(struct qed_hwfn *p_hwfn, 1959706d0891SRahul Verma struct qed_ptt *p_ptt, u32 *p_media_type) 1960cc875c2eSYuval Mintz { 1961c56a8be7SRahul Verma *p_media_type = MEDIA_UNSPECIFIED; 1962c56a8be7SRahul Verma 1963706d0891SRahul Verma if (IS_VF(p_hwfn->cdev)) 19641408cc1fSYuval Mintz return -EINVAL; 19651408cc1fSYuval Mintz 1966cc875c2eSYuval Mintz if (!qed_mcp_is_init(p_hwfn)) { 1967cc875c2eSYuval Mintz DP_NOTICE(p_hwfn, "MFW is not initialized!\n"); 1968cc875c2eSYuval Mintz return -EBUSY; 1969cc875c2eSYuval Mintz } 1970cc875c2eSYuval Mintz 1971706d0891SRahul Verma if (!p_ptt) { 1972cc875c2eSYuval Mintz *p_media_type = MEDIA_UNSPECIFIED; 1973706d0891SRahul Verma return -EINVAL; 1974706d0891SRahul Verma } 1975cc875c2eSYuval Mintz 1976706d0891SRahul Verma *p_media_type = qed_rd(p_hwfn, p_ptt, 1977706d0891SRahul Verma p_hwfn->mcp_info->port_addr + 1978706d0891SRahul Verma offsetof(struct public_port, 1979706d0891SRahul Verma media_type)); 1980cc875c2eSYuval Mintz 1981cc875c2eSYuval Mintz return 0; 1982cc875c2eSYuval Mintz } 1983cc875c2eSYuval Mintz 1984c56a8be7SRahul Verma int qed_mcp_get_transceiver_data(struct qed_hwfn *p_hwfn, 1985c56a8be7SRahul Verma struct qed_ptt *p_ptt, 1986c56a8be7SRahul Verma u32 *p_transceiver_state, 1987c56a8be7SRahul Verma u32 *p_transceiver_type) 1988c56a8be7SRahul Verma { 1989c56a8be7SRahul Verma u32 transceiver_info; 1990c56a8be7SRahul Verma 199168203a67SRahul Verma *p_transceiver_type = ETH_TRANSCEIVER_TYPE_NONE; 199268203a67SRahul Verma *p_transceiver_state = ETH_TRANSCEIVER_STATE_UPDATING; 199368203a67SRahul Verma 1994c56a8be7SRahul Verma if (IS_VF(p_hwfn->cdev)) 1995c56a8be7SRahul Verma return -EINVAL; 1996c56a8be7SRahul Verma 1997c56a8be7SRahul Verma if (!qed_mcp_is_init(p_hwfn)) { 1998c56a8be7SRahul Verma DP_NOTICE(p_hwfn, "MFW is not initialized!\n"); 1999c56a8be7SRahul Verma return -EBUSY; 2000c56a8be7SRahul Verma } 2001c56a8be7SRahul Verma 2002c56a8be7SRahul Verma transceiver_info = qed_rd(p_hwfn, p_ptt, 2003c56a8be7SRahul Verma p_hwfn->mcp_info->port_addr + 2004c56a8be7SRahul Verma offsetof(struct public_port, 2005c56a8be7SRahul Verma transceiver_data)); 2006c56a8be7SRahul Verma 2007c56a8be7SRahul Verma *p_transceiver_state = (transceiver_info & 2008c56a8be7SRahul Verma ETH_TRANSCEIVER_STATE_MASK) >> 2009c56a8be7SRahul Verma ETH_TRANSCEIVER_STATE_OFFSET; 2010c56a8be7SRahul Verma 2011c56a8be7SRahul Verma if (*p_transceiver_state == ETH_TRANSCEIVER_STATE_PRESENT) 2012c56a8be7SRahul Verma *p_transceiver_type = (transceiver_info & 2013c56a8be7SRahul Verma ETH_TRANSCEIVER_TYPE_MASK) >> 2014c56a8be7SRahul Verma ETH_TRANSCEIVER_TYPE_OFFSET; 2015c56a8be7SRahul Verma else 2016c56a8be7SRahul Verma *p_transceiver_type = ETH_TRANSCEIVER_TYPE_UNKNOWN; 2017c56a8be7SRahul Verma 2018c56a8be7SRahul Verma return 0; 2019c56a8be7SRahul Verma } 2020c56a8be7SRahul Verma static bool qed_is_transceiver_ready(u32 transceiver_state, 2021c56a8be7SRahul Verma u32 transceiver_type) 2022c56a8be7SRahul Verma { 2023c56a8be7SRahul Verma if ((transceiver_state & ETH_TRANSCEIVER_STATE_PRESENT) && 2024c56a8be7SRahul Verma ((transceiver_state & ETH_TRANSCEIVER_STATE_UPDATING) == 0x0) && 2025c56a8be7SRahul Verma (transceiver_type != ETH_TRANSCEIVER_TYPE_NONE)) 2026c56a8be7SRahul Verma return true; 2027c56a8be7SRahul Verma 2028c56a8be7SRahul Verma return false; 2029c56a8be7SRahul Verma } 2030c56a8be7SRahul Verma 2031c56a8be7SRahul Verma int qed_mcp_trans_speed_mask(struct qed_hwfn *p_hwfn, 2032c56a8be7SRahul Verma struct qed_ptt *p_ptt, u32 *p_speed_mask) 2033c56a8be7SRahul Verma { 2034c56a8be7SRahul Verma u32 transceiver_type, transceiver_state; 203592619210SArnd Bergmann int ret; 2036c56a8be7SRahul Verma 203792619210SArnd Bergmann ret = qed_mcp_get_transceiver_data(p_hwfn, p_ptt, &transceiver_state, 2038c56a8be7SRahul Verma &transceiver_type); 203992619210SArnd Bergmann if (ret) 204092619210SArnd Bergmann return ret; 2041c56a8be7SRahul Verma 2042c56a8be7SRahul Verma if (qed_is_transceiver_ready(transceiver_state, transceiver_type) == 2043c56a8be7SRahul Verma false) 2044c56a8be7SRahul Verma return -EINVAL; 2045c56a8be7SRahul Verma 2046c56a8be7SRahul Verma switch (transceiver_type) { 2047c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_1G_LX: 2048c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_1G_SX: 2049c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_1G_PCC: 2050c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_1G_ACC: 2051c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_1000BASET: 2052c56a8be7SRahul Verma *p_speed_mask = NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G; 2053c56a8be7SRahul Verma break; 2054c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_10G_SR: 2055c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_10G_LR: 2056c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_10G_LRM: 2057c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_10G_ER: 2058c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_10G_PCC: 2059c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_10G_ACC: 2060c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_4x10G: 2061c56a8be7SRahul Verma *p_speed_mask = NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G; 2062c56a8be7SRahul Verma break; 2063c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_40G_LR4: 2064c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_40G_SR4: 2065c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_MULTI_RATE_10G_40G_SR: 2066c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_MULTI_RATE_10G_40G_LR: 2067c56a8be7SRahul Verma *p_speed_mask = NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_40G | 2068c56a8be7SRahul Verma NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G; 2069c56a8be7SRahul Verma break; 2070c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_100G_AOC: 2071c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_100G_SR4: 2072c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_100G_LR4: 2073c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_100G_ER4: 2074c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_100G_ACC: 2075c56a8be7SRahul Verma *p_speed_mask = 2076c56a8be7SRahul Verma NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_BB_100G | 2077c56a8be7SRahul Verma NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_25G; 2078c56a8be7SRahul Verma break; 2079c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_25G_SR: 2080c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_25G_LR: 2081c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_25G_AOC: 2082c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_25G_ACC_S: 2083c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_25G_ACC_M: 2084c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_25G_ACC_L: 2085c56a8be7SRahul Verma *p_speed_mask = NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_25G; 2086c56a8be7SRahul Verma break; 2087c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_25G_CA_N: 2088c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_25G_CA_S: 2089c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_25G_CA_L: 2090c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_4x25G_CR: 2091c56a8be7SRahul Verma *p_speed_mask = NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_25G | 2092c56a8be7SRahul Verma NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G | 2093c56a8be7SRahul Verma NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G; 2094c56a8be7SRahul Verma break; 2095c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_40G_CR4: 2096c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_MULTI_RATE_10G_40G_CR: 2097c56a8be7SRahul Verma *p_speed_mask = NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_40G | 2098c56a8be7SRahul Verma NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G | 2099c56a8be7SRahul Verma NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G; 2100c56a8be7SRahul Verma break; 2101c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_100G_CR4: 2102c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_MULTI_RATE_40G_100G_CR: 2103c56a8be7SRahul Verma *p_speed_mask = 2104c56a8be7SRahul Verma NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_BB_100G | 2105c56a8be7SRahul Verma NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_50G | 2106c56a8be7SRahul Verma NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_40G | 2107c56a8be7SRahul Verma NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_25G | 2108c56a8be7SRahul Verma NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_20G | 2109c56a8be7SRahul Verma NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G | 2110c56a8be7SRahul Verma NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G; 2111c56a8be7SRahul Verma break; 2112c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_MULTI_RATE_40G_100G_SR: 2113c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_MULTI_RATE_40G_100G_LR: 2114c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_MULTI_RATE_40G_100G_AOC: 2115c56a8be7SRahul Verma *p_speed_mask = 2116c56a8be7SRahul Verma NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_BB_100G | 2117c56a8be7SRahul Verma NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_40G | 2118c56a8be7SRahul Verma NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_25G | 2119c56a8be7SRahul Verma NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G; 2120c56a8be7SRahul Verma break; 2121c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_XLPPI: 2122c56a8be7SRahul Verma *p_speed_mask = NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_40G; 2123c56a8be7SRahul Verma break; 2124c56a8be7SRahul Verma case ETH_TRANSCEIVER_TYPE_10G_BASET: 2125c56a8be7SRahul Verma *p_speed_mask = NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G | 2126c56a8be7SRahul Verma NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G; 2127c56a8be7SRahul Verma break; 2128c56a8be7SRahul Verma default: 21291107a674SColin Ian King DP_INFO(p_hwfn, "Unknown transceiver type 0x%x\n", 2130c56a8be7SRahul Verma transceiver_type); 2131c56a8be7SRahul Verma *p_speed_mask = 0xff; 2132c56a8be7SRahul Verma break; 2133c56a8be7SRahul Verma } 2134c56a8be7SRahul Verma 2135c56a8be7SRahul Verma return 0; 2136c56a8be7SRahul Verma } 2137c56a8be7SRahul Verma 2138c56a8be7SRahul Verma int qed_mcp_get_board_config(struct qed_hwfn *p_hwfn, 2139c56a8be7SRahul Verma struct qed_ptt *p_ptt, u32 *p_board_config) 2140c56a8be7SRahul Verma { 2141c56a8be7SRahul Verma u32 nvm_cfg_addr, nvm_cfg1_offset, port_cfg_addr; 2142c56a8be7SRahul Verma 2143c56a8be7SRahul Verma if (IS_VF(p_hwfn->cdev)) 2144c56a8be7SRahul Verma return -EINVAL; 2145c56a8be7SRahul Verma 2146c56a8be7SRahul Verma if (!qed_mcp_is_init(p_hwfn)) { 2147c56a8be7SRahul Verma DP_NOTICE(p_hwfn, "MFW is not initialized!\n"); 2148c56a8be7SRahul Verma return -EBUSY; 2149c56a8be7SRahul Verma } 2150c56a8be7SRahul Verma if (!p_ptt) { 2151c56a8be7SRahul Verma *p_board_config = NVM_CFG1_PORT_PORT_TYPE_UNDEFINED; 2152c56a8be7SRahul Verma return -EINVAL; 2153c56a8be7SRahul Verma } 2154c56a8be7SRahul Verma 2155c56a8be7SRahul Verma nvm_cfg_addr = qed_rd(p_hwfn, p_ptt, MISC_REG_GEN_PURP_CR0); 2156c56a8be7SRahul Verma nvm_cfg1_offset = qed_rd(p_hwfn, p_ptt, nvm_cfg_addr + 4); 2157c56a8be7SRahul Verma port_cfg_addr = MCP_REG_SCRATCH + nvm_cfg1_offset + 2158c56a8be7SRahul Verma offsetof(struct nvm_cfg1, port[MFW_PORT(p_hwfn)]); 2159c56a8be7SRahul Verma *p_board_config = qed_rd(p_hwfn, p_ptt, 2160c56a8be7SRahul Verma port_cfg_addr + 2161c56a8be7SRahul Verma offsetof(struct nvm_cfg1_port, 2162c56a8be7SRahul Verma board_cfg)); 2163c56a8be7SRahul Verma 2164c56a8be7SRahul Verma return 0; 2165c56a8be7SRahul Verma } 2166c56a8be7SRahul Verma 21676927e826SMintz, Yuval /* Old MFW has a global configuration for all PFs regarding RDMA support */ 21686927e826SMintz, Yuval static void 21696927e826SMintz, Yuval qed_mcp_get_shmem_proto_legacy(struct qed_hwfn *p_hwfn, 21706927e826SMintz, Yuval enum qed_pci_personality *p_proto) 21716927e826SMintz, Yuval { 21726927e826SMintz, Yuval /* There wasn't ever a legacy MFW that published iwarp. 21736927e826SMintz, Yuval * So at this point, this is either plain l2 or RoCE. 21746927e826SMintz, Yuval */ 21756927e826SMintz, Yuval if (test_bit(QED_DEV_CAP_ROCE, &p_hwfn->hw_info.device_capabilities)) 21766927e826SMintz, Yuval *p_proto = QED_PCI_ETH_ROCE; 21776927e826SMintz, Yuval else 21786927e826SMintz, Yuval *p_proto = QED_PCI_ETH; 21796927e826SMintz, Yuval 21806927e826SMintz, Yuval DP_VERBOSE(p_hwfn, NETIF_MSG_IFUP, 21816927e826SMintz, Yuval "According to Legacy capabilities, L2 personality is %08x\n", 21826927e826SMintz, Yuval (u32) *p_proto); 21836927e826SMintz, Yuval } 21846927e826SMintz, Yuval 21856927e826SMintz, Yuval static int 21866927e826SMintz, Yuval qed_mcp_get_shmem_proto_mfw(struct qed_hwfn *p_hwfn, 21876927e826SMintz, Yuval struct qed_ptt *p_ptt, 21886927e826SMintz, Yuval enum qed_pci_personality *p_proto) 21896927e826SMintz, Yuval { 21906927e826SMintz, Yuval u32 resp = 0, param = 0; 21916927e826SMintz, Yuval int rc; 21926927e826SMintz, Yuval 21936927e826SMintz, Yuval rc = qed_mcp_cmd(p_hwfn, p_ptt, 21946927e826SMintz, Yuval DRV_MSG_CODE_GET_PF_RDMA_PROTOCOL, 0, &resp, ¶m); 21956927e826SMintz, Yuval if (rc) 21966927e826SMintz, Yuval return rc; 21976927e826SMintz, Yuval if (resp != FW_MSG_CODE_OK) { 21986927e826SMintz, Yuval DP_VERBOSE(p_hwfn, NETIF_MSG_IFUP, 21996927e826SMintz, Yuval "MFW lacks support for command; Returns %08x\n", 22006927e826SMintz, Yuval resp); 22016927e826SMintz, Yuval return -EINVAL; 22026927e826SMintz, Yuval } 22036927e826SMintz, Yuval 22046927e826SMintz, Yuval switch (param) { 22056927e826SMintz, Yuval case FW_MB_PARAM_GET_PF_RDMA_NONE: 22066927e826SMintz, Yuval *p_proto = QED_PCI_ETH; 22076927e826SMintz, Yuval break; 22086927e826SMintz, Yuval case FW_MB_PARAM_GET_PF_RDMA_ROCE: 22096927e826SMintz, Yuval *p_proto = QED_PCI_ETH_ROCE; 22106927e826SMintz, Yuval break; 22116927e826SMintz, Yuval case FW_MB_PARAM_GET_PF_RDMA_IWARP: 2212e0a8f9deSMichal Kalderon *p_proto = QED_PCI_ETH_IWARP; 2213e0a8f9deSMichal Kalderon break; 2214e0a8f9deSMichal Kalderon case FW_MB_PARAM_GET_PF_RDMA_BOTH: 2215e0a8f9deSMichal Kalderon *p_proto = QED_PCI_ETH_RDMA; 2216e0a8f9deSMichal Kalderon break; 22176927e826SMintz, Yuval default: 22186927e826SMintz, Yuval DP_NOTICE(p_hwfn, 22196927e826SMintz, Yuval "MFW answers GET_PF_RDMA_PROTOCOL but param is %08x\n", 22206927e826SMintz, Yuval param); 22216927e826SMintz, Yuval return -EINVAL; 22226927e826SMintz, Yuval } 22236927e826SMintz, Yuval 22246927e826SMintz, Yuval DP_VERBOSE(p_hwfn, 22256927e826SMintz, Yuval NETIF_MSG_IFUP, 22266927e826SMintz, Yuval "According to capabilities, L2 personality is %08x [resp %08x param %08x]\n", 22276927e826SMintz, Yuval (u32) *p_proto, resp, param); 22286927e826SMintz, Yuval return 0; 22296927e826SMintz, Yuval } 22306927e826SMintz, Yuval 2231fe56b9e6SYuval Mintz static int 2232fe56b9e6SYuval Mintz qed_mcp_get_shmem_proto(struct qed_hwfn *p_hwfn, 2233fe56b9e6SYuval Mintz struct public_func *p_info, 22346927e826SMintz, Yuval struct qed_ptt *p_ptt, 2235fe56b9e6SYuval Mintz enum qed_pci_personality *p_proto) 2236fe56b9e6SYuval Mintz { 2237fe56b9e6SYuval Mintz int rc = 0; 2238fe56b9e6SYuval Mintz 2239fe56b9e6SYuval Mintz switch (p_info->config & FUNC_MF_CFG_PROTOCOL_MASK) { 2240fe56b9e6SYuval Mintz case FUNC_MF_CFG_PROTOCOL_ETHERNET: 22411fe582ecSRam Amrani if (!IS_ENABLED(CONFIG_QED_RDMA)) 22421fe582ecSRam Amrani *p_proto = QED_PCI_ETH; 22431fe582ecSRam Amrani else if (qed_mcp_get_shmem_proto_mfw(p_hwfn, p_ptt, p_proto)) 22446927e826SMintz, Yuval qed_mcp_get_shmem_proto_legacy(p_hwfn, p_proto); 2245fe56b9e6SYuval Mintz break; 2246c5ac9319SYuval Mintz case FUNC_MF_CFG_PROTOCOL_ISCSI: 2247c5ac9319SYuval Mintz *p_proto = QED_PCI_ISCSI; 2248c5ac9319SYuval Mintz break; 22491e128c81SArun Easi case FUNC_MF_CFG_PROTOCOL_FCOE: 22501e128c81SArun Easi *p_proto = QED_PCI_FCOE; 22511e128c81SArun Easi break; 2252c5ac9319SYuval Mintz case FUNC_MF_CFG_PROTOCOL_ROCE: 2253c5ac9319SYuval Mintz DP_NOTICE(p_hwfn, "RoCE personality is not a valid value!\n"); 22546927e826SMintz, Yuval /* Fallthrough */ 2255fe56b9e6SYuval Mintz default: 2256fe56b9e6SYuval Mintz rc = -EINVAL; 2257fe56b9e6SYuval Mintz } 2258fe56b9e6SYuval Mintz 2259fe56b9e6SYuval Mintz return rc; 2260fe56b9e6SYuval Mintz } 2261fe56b9e6SYuval Mintz 2262fe56b9e6SYuval Mintz int qed_mcp_fill_shmem_func_info(struct qed_hwfn *p_hwfn, 2263fe56b9e6SYuval Mintz struct qed_ptt *p_ptt) 2264fe56b9e6SYuval Mintz { 2265fe56b9e6SYuval Mintz struct qed_mcp_function_info *info; 2266fe56b9e6SYuval Mintz struct public_func shmem_info; 2267fe56b9e6SYuval Mintz 22681a635e48SYuval Mintz qed_mcp_get_shmem_func(p_hwfn, p_ptt, &shmem_info, MCP_PF_ID(p_hwfn)); 2269fe56b9e6SYuval Mintz info = &p_hwfn->mcp_info->func_info; 2270fe56b9e6SYuval Mintz 2271fe56b9e6SYuval Mintz info->pause_on_host = (shmem_info.config & 2272fe56b9e6SYuval Mintz FUNC_MF_CFG_PAUSE_ON_HOST_RING) ? 1 : 0; 2273fe56b9e6SYuval Mintz 22746927e826SMintz, Yuval if (qed_mcp_get_shmem_proto(p_hwfn, &shmem_info, p_ptt, 22756927e826SMintz, Yuval &info->protocol)) { 2276fe56b9e6SYuval Mintz DP_ERR(p_hwfn, "Unknown personality %08x\n", 2277fe56b9e6SYuval Mintz (u32)(shmem_info.config & FUNC_MF_CFG_PROTOCOL_MASK)); 2278fe56b9e6SYuval Mintz return -EINVAL; 2279fe56b9e6SYuval Mintz } 2280fe56b9e6SYuval Mintz 22814b01e519SManish Chopra qed_read_pf_bandwidth(p_hwfn, &shmem_info); 2282fe56b9e6SYuval Mintz 2283fe56b9e6SYuval Mintz if (shmem_info.mac_upper || shmem_info.mac_lower) { 2284fe56b9e6SYuval Mintz info->mac[0] = (u8)(shmem_info.mac_upper >> 8); 2285fe56b9e6SYuval Mintz info->mac[1] = (u8)(shmem_info.mac_upper); 2286fe56b9e6SYuval Mintz info->mac[2] = (u8)(shmem_info.mac_lower >> 24); 2287fe56b9e6SYuval Mintz info->mac[3] = (u8)(shmem_info.mac_lower >> 16); 2288fe56b9e6SYuval Mintz info->mac[4] = (u8)(shmem_info.mac_lower >> 8); 2289fe56b9e6SYuval Mintz info->mac[5] = (u8)(shmem_info.mac_lower); 229014d39648SMintz, Yuval 229114d39648SMintz, Yuval /* Store primary MAC for later possible WoL */ 229214d39648SMintz, Yuval memcpy(&p_hwfn->cdev->wol_mac, info->mac, ETH_ALEN); 2293fe56b9e6SYuval Mintz } else { 2294fe56b9e6SYuval Mintz DP_NOTICE(p_hwfn, "MAC is 0 in shmem\n"); 2295fe56b9e6SYuval Mintz } 2296fe56b9e6SYuval Mintz 229757796759SMintz, Yuval info->wwn_port = (u64)shmem_info.fcoe_wwn_port_name_lower | 229857796759SMintz, Yuval (((u64)shmem_info.fcoe_wwn_port_name_upper) << 32); 229957796759SMintz, Yuval info->wwn_node = (u64)shmem_info.fcoe_wwn_node_name_lower | 230057796759SMintz, Yuval (((u64)shmem_info.fcoe_wwn_node_name_upper) << 32); 2301fe56b9e6SYuval Mintz 2302fe56b9e6SYuval Mintz info->ovlan = (u16)(shmem_info.ovlan_stag & FUNC_MF_CFG_OV_STAG_MASK); 2303fe56b9e6SYuval Mintz 23040fefbfbaSSudarsana Kalluru info->mtu = (u16)shmem_info.mtu_size; 23050fefbfbaSSudarsana Kalluru 230614d39648SMintz, Yuval p_hwfn->hw_info.b_wol_support = QED_WOL_SUPPORT_NONE; 230714d39648SMintz, Yuval p_hwfn->cdev->wol_config = (u8)QED_OV_WOL_DEFAULT; 230814d39648SMintz, Yuval if (qed_mcp_is_init(p_hwfn)) { 230914d39648SMintz, Yuval u32 resp = 0, param = 0; 231014d39648SMintz, Yuval int rc; 231114d39648SMintz, Yuval 231214d39648SMintz, Yuval rc = qed_mcp_cmd(p_hwfn, p_ptt, 231314d39648SMintz, Yuval DRV_MSG_CODE_OS_WOL, 0, &resp, ¶m); 231414d39648SMintz, Yuval if (rc) 231514d39648SMintz, Yuval return rc; 231614d39648SMintz, Yuval if (resp == FW_MSG_CODE_OS_WOL_SUPPORTED) 231714d39648SMintz, Yuval p_hwfn->hw_info.b_wol_support = QED_WOL_SUPPORT_PME; 231814d39648SMintz, Yuval } 231914d39648SMintz, Yuval 2320fe56b9e6SYuval Mintz DP_VERBOSE(p_hwfn, (QED_MSG_SP | NETIF_MSG_IFUP), 232114d39648SMintz, 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", 2322fe56b9e6SYuval Mintz info->pause_on_host, info->protocol, 2323fe56b9e6SYuval Mintz info->bandwidth_min, info->bandwidth_max, 2324fe56b9e6SYuval Mintz info->mac[0], info->mac[1], info->mac[2], 2325fe56b9e6SYuval Mintz info->mac[3], info->mac[4], info->mac[5], 232614d39648SMintz, Yuval info->wwn_port, info->wwn_node, 232714d39648SMintz, Yuval info->ovlan, (u8)p_hwfn->hw_info.b_wol_support); 2328fe56b9e6SYuval Mintz 2329fe56b9e6SYuval Mintz return 0; 2330fe56b9e6SYuval Mintz } 2331fe56b9e6SYuval Mintz 2332cc875c2eSYuval Mintz struct qed_mcp_link_params 2333cc875c2eSYuval Mintz *qed_mcp_get_link_params(struct qed_hwfn *p_hwfn) 2334cc875c2eSYuval Mintz { 2335cc875c2eSYuval Mintz if (!p_hwfn || !p_hwfn->mcp_info) 2336cc875c2eSYuval Mintz return NULL; 2337cc875c2eSYuval Mintz return &p_hwfn->mcp_info->link_input; 2338cc875c2eSYuval Mintz } 2339cc875c2eSYuval Mintz 2340cc875c2eSYuval Mintz struct qed_mcp_link_state 2341cc875c2eSYuval Mintz *qed_mcp_get_link_state(struct qed_hwfn *p_hwfn) 2342cc875c2eSYuval Mintz { 2343cc875c2eSYuval Mintz if (!p_hwfn || !p_hwfn->mcp_info) 2344cc875c2eSYuval Mintz return NULL; 2345cc875c2eSYuval Mintz return &p_hwfn->mcp_info->link_output; 2346cc875c2eSYuval Mintz } 2347cc875c2eSYuval Mintz 2348cc875c2eSYuval Mintz struct qed_mcp_link_capabilities 2349cc875c2eSYuval Mintz *qed_mcp_get_link_capabilities(struct qed_hwfn *p_hwfn) 2350cc875c2eSYuval Mintz { 2351cc875c2eSYuval Mintz if (!p_hwfn || !p_hwfn->mcp_info) 2352cc875c2eSYuval Mintz return NULL; 2353cc875c2eSYuval Mintz return &p_hwfn->mcp_info->link_capabilities; 2354cc875c2eSYuval Mintz } 2355cc875c2eSYuval Mintz 23561a635e48SYuval Mintz int qed_mcp_drain(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 2357fe56b9e6SYuval Mintz { 2358fe56b9e6SYuval Mintz u32 resp = 0, param = 0; 2359fe56b9e6SYuval Mintz int rc; 2360fe56b9e6SYuval Mintz 2361fe56b9e6SYuval Mintz rc = qed_mcp_cmd(p_hwfn, p_ptt, 23621a635e48SYuval Mintz DRV_MSG_CODE_NIG_DRAIN, 1000, &resp, ¶m); 2363fe56b9e6SYuval Mintz 2364fe56b9e6SYuval Mintz /* Wait for the drain to complete before returning */ 23658f60bafeSYuval Mintz msleep(1020); 2366fe56b9e6SYuval Mintz 2367fe56b9e6SYuval Mintz return rc; 2368fe56b9e6SYuval Mintz } 2369fe56b9e6SYuval Mintz 2370cee4d264SManish Chopra int qed_mcp_get_flash_size(struct qed_hwfn *p_hwfn, 23711a635e48SYuval Mintz struct qed_ptt *p_ptt, u32 *p_flash_size) 2372cee4d264SManish Chopra { 2373cee4d264SManish Chopra u32 flash_size; 2374cee4d264SManish Chopra 23751408cc1fSYuval Mintz if (IS_VF(p_hwfn->cdev)) 23761408cc1fSYuval Mintz return -EINVAL; 23771408cc1fSYuval Mintz 2378cee4d264SManish Chopra flash_size = qed_rd(p_hwfn, p_ptt, MCP_REG_NVM_CFG4); 2379cee4d264SManish Chopra flash_size = (flash_size & MCP_REG_NVM_CFG4_FLASH_SIZE) >> 2380cee4d264SManish Chopra MCP_REG_NVM_CFG4_FLASH_SIZE_SHIFT; 2381cee4d264SManish Chopra flash_size = (1 << (flash_size + MCP_BYTES_PER_MBIT_SHIFT)); 2382cee4d264SManish Chopra 2383cee4d264SManish Chopra *p_flash_size = flash_size; 2384cee4d264SManish Chopra 2385cee4d264SManish Chopra return 0; 2386cee4d264SManish Chopra } 2387cee4d264SManish Chopra 238864515dc8STomer Tayar int qed_start_recovery_process(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 238964515dc8STomer Tayar { 239064515dc8STomer Tayar struct qed_dev *cdev = p_hwfn->cdev; 239164515dc8STomer Tayar 239264515dc8STomer Tayar if (cdev->recov_in_prog) { 239364515dc8STomer Tayar DP_NOTICE(p_hwfn, 239464515dc8STomer Tayar "Avoid triggering a recovery since such a process is already in progress\n"); 239564515dc8STomer Tayar return -EAGAIN; 239664515dc8STomer Tayar } 239764515dc8STomer Tayar 239864515dc8STomer Tayar DP_NOTICE(p_hwfn, "Triggering a recovery process\n"); 239964515dc8STomer Tayar qed_wr(p_hwfn, p_ptt, MISC_REG_AEU_GENERAL_ATTN_35, 0x1); 240064515dc8STomer Tayar 240164515dc8STomer Tayar return 0; 240264515dc8STomer Tayar } 240364515dc8STomer Tayar 240464515dc8STomer Tayar #define QED_RECOVERY_PROLOG_SLEEP_MS 100 240564515dc8STomer Tayar 240664515dc8STomer Tayar int qed_recovery_prolog(struct qed_dev *cdev) 240764515dc8STomer Tayar { 240864515dc8STomer Tayar struct qed_hwfn *p_hwfn = QED_LEADING_HWFN(cdev); 240964515dc8STomer Tayar struct qed_ptt *p_ptt = p_hwfn->p_main_ptt; 241064515dc8STomer Tayar int rc; 241164515dc8STomer Tayar 241264515dc8STomer Tayar /* Allow ongoing PCIe transactions to complete */ 241364515dc8STomer Tayar msleep(QED_RECOVERY_PROLOG_SLEEP_MS); 241464515dc8STomer Tayar 241564515dc8STomer Tayar /* Clear the PF's internal FID_enable in the PXP */ 241664515dc8STomer Tayar rc = qed_pglueb_set_pfid_enable(p_hwfn, p_ptt, false); 241764515dc8STomer Tayar if (rc) 241864515dc8STomer Tayar DP_NOTICE(p_hwfn, 241964515dc8STomer Tayar "qed_pglueb_set_pfid_enable() failed. rc = %d.\n", 242064515dc8STomer Tayar rc); 242164515dc8STomer Tayar 242264515dc8STomer Tayar return rc; 242364515dc8STomer Tayar } 242464515dc8STomer Tayar 242588072fd4SMintz, Yuval static int 242688072fd4SMintz, Yuval qed_mcp_config_vf_msix_bb(struct qed_hwfn *p_hwfn, 24271408cc1fSYuval Mintz struct qed_ptt *p_ptt, u8 vf_id, u8 num) 24281408cc1fSYuval Mintz { 24291408cc1fSYuval Mintz u32 resp = 0, param = 0, rc_param = 0; 24301408cc1fSYuval Mintz int rc; 24311408cc1fSYuval Mintz 24321408cc1fSYuval Mintz /* Only Leader can configure MSIX, and need to take CMT into account */ 24331408cc1fSYuval Mintz if (!IS_LEAD_HWFN(p_hwfn)) 24341408cc1fSYuval Mintz return 0; 24351408cc1fSYuval Mintz num *= p_hwfn->cdev->num_hwfns; 24361408cc1fSYuval Mintz 24371408cc1fSYuval Mintz param |= (vf_id << DRV_MB_PARAM_CFG_VF_MSIX_VF_ID_SHIFT) & 24381408cc1fSYuval Mintz DRV_MB_PARAM_CFG_VF_MSIX_VF_ID_MASK; 24391408cc1fSYuval Mintz param |= (num << DRV_MB_PARAM_CFG_VF_MSIX_SB_NUM_SHIFT) & 24401408cc1fSYuval Mintz DRV_MB_PARAM_CFG_VF_MSIX_SB_NUM_MASK; 24411408cc1fSYuval Mintz 24421408cc1fSYuval Mintz rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_CFG_VF_MSIX, param, 24431408cc1fSYuval Mintz &resp, &rc_param); 24441408cc1fSYuval Mintz 24451408cc1fSYuval Mintz if (resp != FW_MSG_CODE_DRV_CFG_VF_MSIX_DONE) { 24461408cc1fSYuval Mintz DP_NOTICE(p_hwfn, "VF[%d]: MFW failed to set MSI-X\n", vf_id); 24471408cc1fSYuval Mintz rc = -EINVAL; 24481408cc1fSYuval Mintz } else { 24491408cc1fSYuval Mintz DP_VERBOSE(p_hwfn, QED_MSG_IOV, 24501408cc1fSYuval Mintz "Requested 0x%02x MSI-x interrupts from VF 0x%02x\n", 24511408cc1fSYuval Mintz num, vf_id); 24521408cc1fSYuval Mintz } 24531408cc1fSYuval Mintz 24541408cc1fSYuval Mintz return rc; 24551408cc1fSYuval Mintz } 24561408cc1fSYuval Mintz 245788072fd4SMintz, Yuval static int 245888072fd4SMintz, Yuval qed_mcp_config_vf_msix_ah(struct qed_hwfn *p_hwfn, 245988072fd4SMintz, Yuval struct qed_ptt *p_ptt, u8 num) 246088072fd4SMintz, Yuval { 246188072fd4SMintz, Yuval u32 resp = 0, param = num, rc_param = 0; 246288072fd4SMintz, Yuval int rc; 246388072fd4SMintz, Yuval 246488072fd4SMintz, Yuval rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_CFG_PF_VFS_MSIX, 246588072fd4SMintz, Yuval param, &resp, &rc_param); 246688072fd4SMintz, Yuval 246788072fd4SMintz, Yuval if (resp != FW_MSG_CODE_DRV_CFG_PF_VFS_MSIX_DONE) { 246888072fd4SMintz, Yuval DP_NOTICE(p_hwfn, "MFW failed to set MSI-X for VFs\n"); 246988072fd4SMintz, Yuval rc = -EINVAL; 247088072fd4SMintz, Yuval } else { 247188072fd4SMintz, Yuval DP_VERBOSE(p_hwfn, QED_MSG_IOV, 247288072fd4SMintz, Yuval "Requested 0x%02x MSI-x interrupts for VFs\n", num); 247388072fd4SMintz, Yuval } 247488072fd4SMintz, Yuval 247588072fd4SMintz, Yuval return rc; 247688072fd4SMintz, Yuval } 247788072fd4SMintz, Yuval 247888072fd4SMintz, Yuval int qed_mcp_config_vf_msix(struct qed_hwfn *p_hwfn, 247988072fd4SMintz, Yuval struct qed_ptt *p_ptt, u8 vf_id, u8 num) 248088072fd4SMintz, Yuval { 248188072fd4SMintz, Yuval if (QED_IS_BB(p_hwfn->cdev)) 248288072fd4SMintz, Yuval return qed_mcp_config_vf_msix_bb(p_hwfn, p_ptt, vf_id, num); 248388072fd4SMintz, Yuval else 248488072fd4SMintz, Yuval return qed_mcp_config_vf_msix_ah(p_hwfn, p_ptt, num); 248588072fd4SMintz, Yuval } 248688072fd4SMintz, Yuval 2487fe56b9e6SYuval Mintz int 2488fe56b9e6SYuval Mintz qed_mcp_send_drv_version(struct qed_hwfn *p_hwfn, 2489fe56b9e6SYuval Mintz struct qed_ptt *p_ptt, 2490fe56b9e6SYuval Mintz struct qed_mcp_drv_version *p_ver) 2491fe56b9e6SYuval Mintz { 24925529bad9STomer Tayar struct qed_mcp_mb_params mb_params; 24932f67af8cSTomer Tayar struct drv_version_stc drv_version; 24945529bad9STomer Tayar __be32 val; 24955529bad9STomer Tayar u32 i; 24965529bad9STomer Tayar int rc; 2497fe56b9e6SYuval Mintz 24982f67af8cSTomer Tayar memset(&drv_version, 0, sizeof(drv_version)); 24992f67af8cSTomer Tayar drv_version.version = p_ver->version; 250067a99b70SYuval Mintz for (i = 0; i < (MCP_DRV_VER_STR_SIZE - 4) / sizeof(u32); i++) { 250167a99b70SYuval Mintz val = cpu_to_be32(*((u32 *)&p_ver->name[i * sizeof(u32)])); 25022f67af8cSTomer Tayar *(__be32 *)&drv_version.name[i * sizeof(u32)] = val; 2503fe56b9e6SYuval Mintz } 2504fe56b9e6SYuval Mintz 25055529bad9STomer Tayar memset(&mb_params, 0, sizeof(mb_params)); 25065529bad9STomer Tayar mb_params.cmd = DRV_MSG_CODE_SET_VERSION; 25072f67af8cSTomer Tayar mb_params.p_data_src = &drv_version; 25082f67af8cSTomer Tayar mb_params.data_src_size = sizeof(drv_version); 25095529bad9STomer Tayar rc = qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 25105529bad9STomer Tayar if (rc) 2511fe56b9e6SYuval Mintz DP_ERR(p_hwfn, "MCP response failure, aborting\n"); 2512fe56b9e6SYuval Mintz 25135529bad9STomer Tayar return rc; 2514fe56b9e6SYuval Mintz } 251591420b83SSudarsana Kalluru 251676271809STomer Tayar /* A maximal 100 msec waiting time for the MCP to halt */ 251776271809STomer Tayar #define QED_MCP_HALT_SLEEP_MS 10 251876271809STomer Tayar #define QED_MCP_HALT_MAX_RETRIES 10 251976271809STomer Tayar 25204102426fSTomer Tayar int qed_mcp_halt(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 25214102426fSTomer Tayar { 252276271809STomer Tayar u32 resp = 0, param = 0, cpu_state, cnt = 0; 25234102426fSTomer Tayar int rc; 25244102426fSTomer Tayar 25254102426fSTomer Tayar rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_MCP_HALT, 0, &resp, 25264102426fSTomer Tayar ¶m); 252776271809STomer Tayar if (rc) { 25284102426fSTomer Tayar DP_ERR(p_hwfn, "MCP response failure, aborting\n"); 25294102426fSTomer Tayar return rc; 25304102426fSTomer Tayar } 25314102426fSTomer Tayar 253276271809STomer Tayar do { 253376271809STomer Tayar msleep(QED_MCP_HALT_SLEEP_MS); 253476271809STomer Tayar cpu_state = qed_rd(p_hwfn, p_ptt, MCP_REG_CPU_STATE); 253576271809STomer Tayar if (cpu_state & MCP_REG_CPU_STATE_SOFT_HALTED) 253676271809STomer Tayar break; 253776271809STomer Tayar } while (++cnt < QED_MCP_HALT_MAX_RETRIES); 253876271809STomer Tayar 253976271809STomer Tayar if (cnt == QED_MCP_HALT_MAX_RETRIES) { 254076271809STomer Tayar DP_NOTICE(p_hwfn, 254176271809STomer Tayar "Failed to halt the MCP [CPU_MODE = 0x%08x, CPU_STATE = 0x%08x]\n", 254276271809STomer Tayar qed_rd(p_hwfn, p_ptt, MCP_REG_CPU_MODE), cpu_state); 254376271809STomer Tayar return -EBUSY; 254476271809STomer Tayar } 254576271809STomer Tayar 2546b310974eSTomer Tayar qed_mcp_cmd_set_blocking(p_hwfn, true); 2547b310974eSTomer Tayar 254876271809STomer Tayar return 0; 254976271809STomer Tayar } 255076271809STomer Tayar 255176271809STomer Tayar #define QED_MCP_RESUME_SLEEP_MS 10 255276271809STomer Tayar 25534102426fSTomer Tayar int qed_mcp_resume(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 25544102426fSTomer Tayar { 255576271809STomer Tayar u32 cpu_mode, cpu_state; 25564102426fSTomer Tayar 25574102426fSTomer Tayar qed_wr(p_hwfn, p_ptt, MCP_REG_CPU_STATE, 0xffffffff); 25584102426fSTomer Tayar 25594102426fSTomer Tayar cpu_mode = qed_rd(p_hwfn, p_ptt, MCP_REG_CPU_MODE); 256076271809STomer Tayar cpu_mode &= ~MCP_REG_CPU_MODE_SOFT_HALT; 256176271809STomer Tayar qed_wr(p_hwfn, p_ptt, MCP_REG_CPU_MODE, cpu_mode); 256276271809STomer Tayar msleep(QED_MCP_RESUME_SLEEP_MS); 256376271809STomer Tayar cpu_state = qed_rd(p_hwfn, p_ptt, MCP_REG_CPU_STATE); 25644102426fSTomer Tayar 256576271809STomer Tayar if (cpu_state & MCP_REG_CPU_STATE_SOFT_HALTED) { 256676271809STomer Tayar DP_NOTICE(p_hwfn, 256776271809STomer Tayar "Failed to resume the MCP [CPU_MODE = 0x%08x, CPU_STATE = 0x%08x]\n", 256876271809STomer Tayar cpu_mode, cpu_state); 256976271809STomer Tayar return -EBUSY; 257076271809STomer Tayar } 257176271809STomer Tayar 2572b310974eSTomer Tayar qed_mcp_cmd_set_blocking(p_hwfn, false); 2573b310974eSTomer Tayar 257476271809STomer Tayar return 0; 25754102426fSTomer Tayar } 25764102426fSTomer Tayar 25770fefbfbaSSudarsana Kalluru int qed_mcp_ov_update_current_config(struct qed_hwfn *p_hwfn, 25780fefbfbaSSudarsana Kalluru struct qed_ptt *p_ptt, 25790fefbfbaSSudarsana Kalluru enum qed_ov_client client) 25800fefbfbaSSudarsana Kalluru { 25810fefbfbaSSudarsana Kalluru u32 resp = 0, param = 0; 25820fefbfbaSSudarsana Kalluru u32 drv_mb_param; 25830fefbfbaSSudarsana Kalluru int rc; 25840fefbfbaSSudarsana Kalluru 25850fefbfbaSSudarsana Kalluru switch (client) { 25860fefbfbaSSudarsana Kalluru case QED_OV_CLIENT_DRV: 25870fefbfbaSSudarsana Kalluru drv_mb_param = DRV_MB_PARAM_OV_CURR_CFG_OS; 25880fefbfbaSSudarsana Kalluru break; 25890fefbfbaSSudarsana Kalluru case QED_OV_CLIENT_USER: 25900fefbfbaSSudarsana Kalluru drv_mb_param = DRV_MB_PARAM_OV_CURR_CFG_OTHER; 25910fefbfbaSSudarsana Kalluru break; 25920fefbfbaSSudarsana Kalluru case QED_OV_CLIENT_VENDOR_SPEC: 25930fefbfbaSSudarsana Kalluru drv_mb_param = DRV_MB_PARAM_OV_CURR_CFG_VENDOR_SPEC; 25940fefbfbaSSudarsana Kalluru break; 25950fefbfbaSSudarsana Kalluru default: 25960fefbfbaSSudarsana Kalluru DP_NOTICE(p_hwfn, "Invalid client type %d\n", client); 25970fefbfbaSSudarsana Kalluru return -EINVAL; 25980fefbfbaSSudarsana Kalluru } 25990fefbfbaSSudarsana Kalluru 26000fefbfbaSSudarsana Kalluru rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_OV_UPDATE_CURR_CFG, 26010fefbfbaSSudarsana Kalluru drv_mb_param, &resp, ¶m); 26020fefbfbaSSudarsana Kalluru if (rc) 26030fefbfbaSSudarsana Kalluru DP_ERR(p_hwfn, "MCP response failure, aborting\n"); 26040fefbfbaSSudarsana Kalluru 26050fefbfbaSSudarsana Kalluru return rc; 26060fefbfbaSSudarsana Kalluru } 26070fefbfbaSSudarsana Kalluru 26080fefbfbaSSudarsana Kalluru int qed_mcp_ov_update_driver_state(struct qed_hwfn *p_hwfn, 26090fefbfbaSSudarsana Kalluru struct qed_ptt *p_ptt, 26100fefbfbaSSudarsana Kalluru enum qed_ov_driver_state drv_state) 26110fefbfbaSSudarsana Kalluru { 26120fefbfbaSSudarsana Kalluru u32 resp = 0, param = 0; 26130fefbfbaSSudarsana Kalluru u32 drv_mb_param; 26140fefbfbaSSudarsana Kalluru int rc; 26150fefbfbaSSudarsana Kalluru 26160fefbfbaSSudarsana Kalluru switch (drv_state) { 26170fefbfbaSSudarsana Kalluru case QED_OV_DRIVER_STATE_NOT_LOADED: 26180fefbfbaSSudarsana Kalluru drv_mb_param = DRV_MSG_CODE_OV_UPDATE_DRIVER_STATE_NOT_LOADED; 26190fefbfbaSSudarsana Kalluru break; 26200fefbfbaSSudarsana Kalluru case QED_OV_DRIVER_STATE_DISABLED: 26210fefbfbaSSudarsana Kalluru drv_mb_param = DRV_MSG_CODE_OV_UPDATE_DRIVER_STATE_DISABLED; 26220fefbfbaSSudarsana Kalluru break; 26230fefbfbaSSudarsana Kalluru case QED_OV_DRIVER_STATE_ACTIVE: 26240fefbfbaSSudarsana Kalluru drv_mb_param = DRV_MSG_CODE_OV_UPDATE_DRIVER_STATE_ACTIVE; 26250fefbfbaSSudarsana Kalluru break; 26260fefbfbaSSudarsana Kalluru default: 26270fefbfbaSSudarsana Kalluru DP_NOTICE(p_hwfn, "Invalid driver state %d\n", drv_state); 26280fefbfbaSSudarsana Kalluru return -EINVAL; 26290fefbfbaSSudarsana Kalluru } 26300fefbfbaSSudarsana Kalluru 26310fefbfbaSSudarsana Kalluru rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_OV_UPDATE_DRIVER_STATE, 26320fefbfbaSSudarsana Kalluru drv_mb_param, &resp, ¶m); 26330fefbfbaSSudarsana Kalluru if (rc) 26340fefbfbaSSudarsana Kalluru DP_ERR(p_hwfn, "Failed to send driver state\n"); 26350fefbfbaSSudarsana Kalluru 26360fefbfbaSSudarsana Kalluru return rc; 26370fefbfbaSSudarsana Kalluru } 26380fefbfbaSSudarsana Kalluru 26390fefbfbaSSudarsana Kalluru int qed_mcp_ov_update_mtu(struct qed_hwfn *p_hwfn, 26400fefbfbaSSudarsana Kalluru struct qed_ptt *p_ptt, u16 mtu) 26410fefbfbaSSudarsana Kalluru { 26420fefbfbaSSudarsana Kalluru u32 resp = 0, param = 0; 26430fefbfbaSSudarsana Kalluru u32 drv_mb_param; 26440fefbfbaSSudarsana Kalluru int rc; 26450fefbfbaSSudarsana Kalluru 26460fefbfbaSSudarsana Kalluru drv_mb_param = (u32)mtu << DRV_MB_PARAM_OV_MTU_SIZE_SHIFT; 26470fefbfbaSSudarsana Kalluru rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_OV_UPDATE_MTU, 26480fefbfbaSSudarsana Kalluru drv_mb_param, &resp, ¶m); 26490fefbfbaSSudarsana Kalluru if (rc) 26500fefbfbaSSudarsana Kalluru DP_ERR(p_hwfn, "Failed to send mtu value, rc = %d\n", rc); 26510fefbfbaSSudarsana Kalluru 26520fefbfbaSSudarsana Kalluru return rc; 26530fefbfbaSSudarsana Kalluru } 26540fefbfbaSSudarsana Kalluru 26550fefbfbaSSudarsana Kalluru int qed_mcp_ov_update_mac(struct qed_hwfn *p_hwfn, 26560fefbfbaSSudarsana Kalluru struct qed_ptt *p_ptt, u8 *mac) 26570fefbfbaSSudarsana Kalluru { 26580fefbfbaSSudarsana Kalluru struct qed_mcp_mb_params mb_params; 265917991002SMintz, Yuval u32 mfw_mac[2]; 26600fefbfbaSSudarsana Kalluru int rc; 26610fefbfbaSSudarsana Kalluru 26620fefbfbaSSudarsana Kalluru memset(&mb_params, 0, sizeof(mb_params)); 26630fefbfbaSSudarsana Kalluru mb_params.cmd = DRV_MSG_CODE_SET_VMAC; 26640fefbfbaSSudarsana Kalluru mb_params.param = DRV_MSG_CODE_VMAC_TYPE_MAC << 26650fefbfbaSSudarsana Kalluru DRV_MSG_CODE_VMAC_TYPE_SHIFT; 26660fefbfbaSSudarsana Kalluru mb_params.param |= MCP_PF_ID(p_hwfn); 26672f67af8cSTomer Tayar 266817991002SMintz, Yuval /* MCP is BE, and on LE platforms PCI would swap access to SHMEM 266917991002SMintz, Yuval * in 32-bit granularity. 267017991002SMintz, Yuval * So the MAC has to be set in native order [and not byte order], 267117991002SMintz, Yuval * otherwise it would be read incorrectly by MFW after swap. 267217991002SMintz, Yuval */ 267317991002SMintz, Yuval mfw_mac[0] = mac[0] << 24 | mac[1] << 16 | mac[2] << 8 | mac[3]; 267417991002SMintz, Yuval mfw_mac[1] = mac[4] << 24 | mac[5] << 16; 267517991002SMintz, Yuval 267617991002SMintz, Yuval mb_params.p_data_src = (u8 *)mfw_mac; 267717991002SMintz, Yuval mb_params.data_src_size = 8; 26780fefbfbaSSudarsana Kalluru rc = qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 26790fefbfbaSSudarsana Kalluru if (rc) 26800fefbfbaSSudarsana Kalluru DP_ERR(p_hwfn, "Failed to send mac address, rc = %d\n", rc); 26810fefbfbaSSudarsana Kalluru 268214d39648SMintz, Yuval /* Store primary MAC for later possible WoL */ 268314d39648SMintz, Yuval memcpy(p_hwfn->cdev->wol_mac, mac, ETH_ALEN); 268414d39648SMintz, Yuval 26850fefbfbaSSudarsana Kalluru return rc; 26860fefbfbaSSudarsana Kalluru } 26870fefbfbaSSudarsana Kalluru 26880fefbfbaSSudarsana Kalluru int qed_mcp_ov_update_wol(struct qed_hwfn *p_hwfn, 26890fefbfbaSSudarsana Kalluru struct qed_ptt *p_ptt, enum qed_ov_wol wol) 26900fefbfbaSSudarsana Kalluru { 26910fefbfbaSSudarsana Kalluru u32 resp = 0, param = 0; 26920fefbfbaSSudarsana Kalluru u32 drv_mb_param; 26930fefbfbaSSudarsana Kalluru int rc; 26940fefbfbaSSudarsana Kalluru 269514d39648SMintz, Yuval if (p_hwfn->hw_info.b_wol_support == QED_WOL_SUPPORT_NONE) { 269614d39648SMintz, Yuval DP_VERBOSE(p_hwfn, QED_MSG_SP, 269714d39648SMintz, Yuval "Can't change WoL configuration when WoL isn't supported\n"); 269814d39648SMintz, Yuval return -EINVAL; 269914d39648SMintz, Yuval } 270014d39648SMintz, Yuval 27010fefbfbaSSudarsana Kalluru switch (wol) { 27020fefbfbaSSudarsana Kalluru case QED_OV_WOL_DEFAULT: 27030fefbfbaSSudarsana Kalluru drv_mb_param = DRV_MB_PARAM_WOL_DEFAULT; 27040fefbfbaSSudarsana Kalluru break; 27050fefbfbaSSudarsana Kalluru case QED_OV_WOL_DISABLED: 27060fefbfbaSSudarsana Kalluru drv_mb_param = DRV_MB_PARAM_WOL_DISABLED; 27070fefbfbaSSudarsana Kalluru break; 27080fefbfbaSSudarsana Kalluru case QED_OV_WOL_ENABLED: 27090fefbfbaSSudarsana Kalluru drv_mb_param = DRV_MB_PARAM_WOL_ENABLED; 27100fefbfbaSSudarsana Kalluru break; 27110fefbfbaSSudarsana Kalluru default: 27120fefbfbaSSudarsana Kalluru DP_ERR(p_hwfn, "Invalid wol state %d\n", wol); 27130fefbfbaSSudarsana Kalluru return -EINVAL; 27140fefbfbaSSudarsana Kalluru } 27150fefbfbaSSudarsana Kalluru 27160fefbfbaSSudarsana Kalluru rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_OV_UPDATE_WOL, 27170fefbfbaSSudarsana Kalluru drv_mb_param, &resp, ¶m); 27180fefbfbaSSudarsana Kalluru if (rc) 27190fefbfbaSSudarsana Kalluru DP_ERR(p_hwfn, "Failed to send wol mode, rc = %d\n", rc); 27200fefbfbaSSudarsana Kalluru 272114d39648SMintz, Yuval /* Store the WoL update for a future unload */ 272214d39648SMintz, Yuval p_hwfn->cdev->wol_config = (u8)wol; 272314d39648SMintz, Yuval 27240fefbfbaSSudarsana Kalluru return rc; 27250fefbfbaSSudarsana Kalluru } 27260fefbfbaSSudarsana Kalluru 27270fefbfbaSSudarsana Kalluru int qed_mcp_ov_update_eswitch(struct qed_hwfn *p_hwfn, 27280fefbfbaSSudarsana Kalluru struct qed_ptt *p_ptt, 27290fefbfbaSSudarsana Kalluru enum qed_ov_eswitch eswitch) 27300fefbfbaSSudarsana Kalluru { 27310fefbfbaSSudarsana Kalluru u32 resp = 0, param = 0; 27320fefbfbaSSudarsana Kalluru u32 drv_mb_param; 27330fefbfbaSSudarsana Kalluru int rc; 27340fefbfbaSSudarsana Kalluru 27350fefbfbaSSudarsana Kalluru switch (eswitch) { 27360fefbfbaSSudarsana Kalluru case QED_OV_ESWITCH_NONE: 27370fefbfbaSSudarsana Kalluru drv_mb_param = DRV_MB_PARAM_ESWITCH_MODE_NONE; 27380fefbfbaSSudarsana Kalluru break; 27390fefbfbaSSudarsana Kalluru case QED_OV_ESWITCH_VEB: 27400fefbfbaSSudarsana Kalluru drv_mb_param = DRV_MB_PARAM_ESWITCH_MODE_VEB; 27410fefbfbaSSudarsana Kalluru break; 27420fefbfbaSSudarsana Kalluru case QED_OV_ESWITCH_VEPA: 27430fefbfbaSSudarsana Kalluru drv_mb_param = DRV_MB_PARAM_ESWITCH_MODE_VEPA; 27440fefbfbaSSudarsana Kalluru break; 27450fefbfbaSSudarsana Kalluru default: 27460fefbfbaSSudarsana Kalluru DP_ERR(p_hwfn, "Invalid eswitch mode %d\n", eswitch); 27470fefbfbaSSudarsana Kalluru return -EINVAL; 27480fefbfbaSSudarsana Kalluru } 27490fefbfbaSSudarsana Kalluru 27500fefbfbaSSudarsana Kalluru rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_OV_UPDATE_ESWITCH_MODE, 27510fefbfbaSSudarsana Kalluru drv_mb_param, &resp, ¶m); 27520fefbfbaSSudarsana Kalluru if (rc) 27530fefbfbaSSudarsana Kalluru DP_ERR(p_hwfn, "Failed to send eswitch mode, rc = %d\n", rc); 27540fefbfbaSSudarsana Kalluru 27550fefbfbaSSudarsana Kalluru return rc; 27560fefbfbaSSudarsana Kalluru } 27570fefbfbaSSudarsana Kalluru 27581a635e48SYuval Mintz int qed_mcp_set_led(struct qed_hwfn *p_hwfn, 27591a635e48SYuval Mintz struct qed_ptt *p_ptt, enum qed_led_mode mode) 276091420b83SSudarsana Kalluru { 276191420b83SSudarsana Kalluru u32 resp = 0, param = 0, drv_mb_param; 276291420b83SSudarsana Kalluru int rc; 276391420b83SSudarsana Kalluru 276491420b83SSudarsana Kalluru switch (mode) { 276591420b83SSudarsana Kalluru case QED_LED_MODE_ON: 276691420b83SSudarsana Kalluru drv_mb_param = DRV_MB_PARAM_SET_LED_MODE_ON; 276791420b83SSudarsana Kalluru break; 276891420b83SSudarsana Kalluru case QED_LED_MODE_OFF: 276991420b83SSudarsana Kalluru drv_mb_param = DRV_MB_PARAM_SET_LED_MODE_OFF; 277091420b83SSudarsana Kalluru break; 277191420b83SSudarsana Kalluru case QED_LED_MODE_RESTORE: 277291420b83SSudarsana Kalluru drv_mb_param = DRV_MB_PARAM_SET_LED_MODE_OPER; 277391420b83SSudarsana Kalluru break; 277491420b83SSudarsana Kalluru default: 277591420b83SSudarsana Kalluru DP_NOTICE(p_hwfn, "Invalid LED mode %d\n", mode); 277691420b83SSudarsana Kalluru return -EINVAL; 277791420b83SSudarsana Kalluru } 277891420b83SSudarsana Kalluru 277991420b83SSudarsana Kalluru rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_SET_LED_MODE, 278091420b83SSudarsana Kalluru drv_mb_param, &resp, ¶m); 278191420b83SSudarsana Kalluru 278291420b83SSudarsana Kalluru return rc; 278391420b83SSudarsana Kalluru } 278403dc76caSSudarsana Reddy Kalluru 27854102426fSTomer Tayar int qed_mcp_mask_parities(struct qed_hwfn *p_hwfn, 27864102426fSTomer Tayar struct qed_ptt *p_ptt, u32 mask_parities) 27874102426fSTomer Tayar { 27884102426fSTomer Tayar u32 resp = 0, param = 0; 27894102426fSTomer Tayar int rc; 27904102426fSTomer Tayar 27914102426fSTomer Tayar rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_MASK_PARITIES, 27924102426fSTomer Tayar mask_parities, &resp, ¶m); 27934102426fSTomer Tayar 27944102426fSTomer Tayar if (rc) { 27954102426fSTomer Tayar DP_ERR(p_hwfn, 27964102426fSTomer Tayar "MCP response failure for mask parities, aborting\n"); 27974102426fSTomer Tayar } else if (resp != FW_MSG_CODE_OK) { 27984102426fSTomer Tayar DP_ERR(p_hwfn, 27994102426fSTomer Tayar "MCP did not acknowledge mask parity request. Old MFW?\n"); 28004102426fSTomer Tayar rc = -EINVAL; 28014102426fSTomer Tayar } 28024102426fSTomer Tayar 28034102426fSTomer Tayar return rc; 28044102426fSTomer Tayar } 28054102426fSTomer Tayar 28067a4b21b7SMintz, Yuval int qed_mcp_nvm_read(struct qed_dev *cdev, u32 addr, u8 *p_buf, u32 len) 28077a4b21b7SMintz, Yuval { 28087a4b21b7SMintz, Yuval u32 bytes_left = len, offset = 0, bytes_to_copy, read_len = 0; 28097a4b21b7SMintz, Yuval struct qed_hwfn *p_hwfn = QED_LEADING_HWFN(cdev); 28107a4b21b7SMintz, Yuval u32 resp = 0, resp_param = 0; 28117a4b21b7SMintz, Yuval struct qed_ptt *p_ptt; 28127a4b21b7SMintz, Yuval int rc = 0; 28137a4b21b7SMintz, Yuval 28147a4b21b7SMintz, Yuval p_ptt = qed_ptt_acquire(p_hwfn); 28157a4b21b7SMintz, Yuval if (!p_ptt) 28167a4b21b7SMintz, Yuval return -EBUSY; 28177a4b21b7SMintz, Yuval 28187a4b21b7SMintz, Yuval while (bytes_left > 0) { 28197a4b21b7SMintz, Yuval bytes_to_copy = min_t(u32, bytes_left, MCP_DRV_NVM_BUF_LEN); 28207a4b21b7SMintz, Yuval 28217a4b21b7SMintz, Yuval rc = qed_mcp_nvm_rd_cmd(p_hwfn, p_ptt, 28227a4b21b7SMintz, Yuval DRV_MSG_CODE_NVM_READ_NVRAM, 28237a4b21b7SMintz, Yuval addr + offset + 28247a4b21b7SMintz, Yuval (bytes_to_copy << 2825da090917STomer Tayar DRV_MB_PARAM_NVM_LEN_OFFSET), 28267a4b21b7SMintz, Yuval &resp, &resp_param, 28277a4b21b7SMintz, Yuval &read_len, 28287a4b21b7SMintz, Yuval (u32 *)(p_buf + offset)); 28297a4b21b7SMintz, Yuval 28307a4b21b7SMintz, Yuval if (rc || (resp != FW_MSG_CODE_NVM_OK)) { 28317a4b21b7SMintz, Yuval DP_NOTICE(cdev, "MCP command rc = %d\n", rc); 28327a4b21b7SMintz, Yuval break; 28337a4b21b7SMintz, Yuval } 28347a4b21b7SMintz, Yuval 28357a4b21b7SMintz, Yuval /* This can be a lengthy process, and it's possible scheduler 28367a4b21b7SMintz, Yuval * isn't preemptable. Sleep a bit to prevent CPU hogging. 28377a4b21b7SMintz, Yuval */ 28387a4b21b7SMintz, Yuval if (bytes_left % 0x1000 < 28397a4b21b7SMintz, Yuval (bytes_left - read_len) % 0x1000) 28407a4b21b7SMintz, Yuval usleep_range(1000, 2000); 28417a4b21b7SMintz, Yuval 28427a4b21b7SMintz, Yuval offset += read_len; 28437a4b21b7SMintz, Yuval bytes_left -= read_len; 28447a4b21b7SMintz, Yuval } 28457a4b21b7SMintz, Yuval 28467a4b21b7SMintz, Yuval cdev->mcp_nvm_resp = resp; 28477a4b21b7SMintz, Yuval qed_ptt_release(p_hwfn, p_ptt); 28487a4b21b7SMintz, Yuval 28497a4b21b7SMintz, Yuval return rc; 28507a4b21b7SMintz, Yuval } 28517a4b21b7SMintz, Yuval 285262e4d438SSudarsana Reddy Kalluru int qed_mcp_nvm_resp(struct qed_dev *cdev, u8 *p_buf) 285362e4d438SSudarsana Reddy Kalluru { 285462e4d438SSudarsana Reddy Kalluru struct qed_hwfn *p_hwfn = QED_LEADING_HWFN(cdev); 285562e4d438SSudarsana Reddy Kalluru struct qed_ptt *p_ptt; 285662e4d438SSudarsana Reddy Kalluru 285762e4d438SSudarsana Reddy Kalluru p_ptt = qed_ptt_acquire(p_hwfn); 285862e4d438SSudarsana Reddy Kalluru if (!p_ptt) 285962e4d438SSudarsana Reddy Kalluru return -EBUSY; 286062e4d438SSudarsana Reddy Kalluru 286162e4d438SSudarsana Reddy Kalluru memcpy(p_buf, &cdev->mcp_nvm_resp, sizeof(cdev->mcp_nvm_resp)); 286262e4d438SSudarsana Reddy Kalluru qed_ptt_release(p_hwfn, p_ptt); 286362e4d438SSudarsana Reddy Kalluru 286462e4d438SSudarsana Reddy Kalluru return 0; 286562e4d438SSudarsana Reddy Kalluru } 286662e4d438SSudarsana Reddy Kalluru 286762e4d438SSudarsana Reddy Kalluru int qed_mcp_nvm_write(struct qed_dev *cdev, 286862e4d438SSudarsana Reddy Kalluru u32 cmd, u32 addr, u8 *p_buf, u32 len) 286962e4d438SSudarsana Reddy Kalluru { 287062e4d438SSudarsana Reddy Kalluru u32 buf_idx = 0, buf_size, nvm_cmd, nvm_offset, resp = 0, param; 287162e4d438SSudarsana Reddy Kalluru struct qed_hwfn *p_hwfn = QED_LEADING_HWFN(cdev); 287262e4d438SSudarsana Reddy Kalluru struct qed_ptt *p_ptt; 287362e4d438SSudarsana Reddy Kalluru int rc = -EINVAL; 287462e4d438SSudarsana Reddy Kalluru 287562e4d438SSudarsana Reddy Kalluru p_ptt = qed_ptt_acquire(p_hwfn); 287662e4d438SSudarsana Reddy Kalluru if (!p_ptt) 287762e4d438SSudarsana Reddy Kalluru return -EBUSY; 287862e4d438SSudarsana Reddy Kalluru 287962e4d438SSudarsana Reddy Kalluru switch (cmd) { 2880057d2b19SSudarsana Reddy Kalluru case QED_PUT_FILE_BEGIN: 2881057d2b19SSudarsana Reddy Kalluru nvm_cmd = DRV_MSG_CODE_NVM_PUT_FILE_BEGIN; 2882057d2b19SSudarsana Reddy Kalluru break; 288362e4d438SSudarsana Reddy Kalluru case QED_PUT_FILE_DATA: 288462e4d438SSudarsana Reddy Kalluru nvm_cmd = DRV_MSG_CODE_NVM_PUT_FILE_DATA; 288562e4d438SSudarsana Reddy Kalluru break; 288662e4d438SSudarsana Reddy Kalluru case QED_NVM_WRITE_NVRAM: 288762e4d438SSudarsana Reddy Kalluru nvm_cmd = DRV_MSG_CODE_NVM_WRITE_NVRAM; 288862e4d438SSudarsana Reddy Kalluru break; 288962e4d438SSudarsana Reddy Kalluru default: 289062e4d438SSudarsana Reddy Kalluru DP_NOTICE(p_hwfn, "Invalid nvm write command 0x%x\n", cmd); 289162e4d438SSudarsana Reddy Kalluru rc = -EINVAL; 289262e4d438SSudarsana Reddy Kalluru goto out; 289362e4d438SSudarsana Reddy Kalluru } 289462e4d438SSudarsana Reddy Kalluru 289562e4d438SSudarsana Reddy Kalluru buf_size = min_t(u32, (len - buf_idx), MCP_DRV_NVM_BUF_LEN); 2896057d2b19SSudarsana Reddy Kalluru while (buf_idx < len) { 2897057d2b19SSudarsana Reddy Kalluru if (cmd == QED_PUT_FILE_BEGIN) 2898057d2b19SSudarsana Reddy Kalluru nvm_offset = addr; 2899057d2b19SSudarsana Reddy Kalluru else 2900057d2b19SSudarsana Reddy Kalluru nvm_offset = ((buf_size << 2901057d2b19SSudarsana Reddy Kalluru DRV_MB_PARAM_NVM_LEN_OFFSET) | addr) + 2902057d2b19SSudarsana Reddy Kalluru buf_idx; 290362e4d438SSudarsana Reddy Kalluru rc = qed_mcp_nvm_wr_cmd(p_hwfn, p_ptt, nvm_cmd, nvm_offset, 290462e4d438SSudarsana Reddy Kalluru &resp, ¶m, buf_size, 290562e4d438SSudarsana Reddy Kalluru (u32 *)&p_buf[buf_idx]); 290662e4d438SSudarsana Reddy Kalluru if (rc) { 290762e4d438SSudarsana Reddy Kalluru DP_NOTICE(cdev, "nvm write failed, rc = %d\n", rc); 290862e4d438SSudarsana Reddy Kalluru resp = FW_MSG_CODE_ERROR; 290962e4d438SSudarsana Reddy Kalluru break; 291062e4d438SSudarsana Reddy Kalluru } 291162e4d438SSudarsana Reddy Kalluru 291262e4d438SSudarsana Reddy Kalluru if (resp != FW_MSG_CODE_OK && 291362e4d438SSudarsana Reddy Kalluru resp != FW_MSG_CODE_NVM_OK && 291462e4d438SSudarsana Reddy Kalluru resp != FW_MSG_CODE_NVM_PUT_FILE_FINISH_OK) { 291562e4d438SSudarsana Reddy Kalluru DP_NOTICE(cdev, 291662e4d438SSudarsana Reddy Kalluru "nvm write failed, resp = 0x%08x\n", resp); 291762e4d438SSudarsana Reddy Kalluru rc = -EINVAL; 291862e4d438SSudarsana Reddy Kalluru break; 291962e4d438SSudarsana Reddy Kalluru } 292062e4d438SSudarsana Reddy Kalluru 292162e4d438SSudarsana Reddy Kalluru /* This can be a lengthy process, and it's possible scheduler 292262e4d438SSudarsana Reddy Kalluru * isn't pre-emptable. Sleep a bit to prevent CPU hogging. 292362e4d438SSudarsana Reddy Kalluru */ 292462e4d438SSudarsana Reddy Kalluru if (buf_idx % 0x1000 > (buf_idx + buf_size) % 0x1000) 292562e4d438SSudarsana Reddy Kalluru usleep_range(1000, 2000); 292662e4d438SSudarsana Reddy Kalluru 2927057d2b19SSudarsana Reddy Kalluru /* For MBI upgrade, MFW response includes the next buffer offset 2928057d2b19SSudarsana Reddy Kalluru * to be delivered to MFW. 2929057d2b19SSudarsana Reddy Kalluru */ 2930057d2b19SSudarsana Reddy Kalluru if (param && cmd == QED_PUT_FILE_DATA) { 2931057d2b19SSudarsana Reddy Kalluru buf_idx = QED_MFW_GET_FIELD(param, 2932057d2b19SSudarsana Reddy Kalluru FW_MB_PARAM_NVM_PUT_FILE_REQ_OFFSET); 2933057d2b19SSudarsana Reddy Kalluru buf_size = QED_MFW_GET_FIELD(param, 2934057d2b19SSudarsana Reddy Kalluru FW_MB_PARAM_NVM_PUT_FILE_REQ_SIZE); 2935057d2b19SSudarsana Reddy Kalluru } else { 293662e4d438SSudarsana Reddy Kalluru buf_idx += buf_size; 2937057d2b19SSudarsana Reddy Kalluru buf_size = min_t(u32, (len - buf_idx), 2938057d2b19SSudarsana Reddy Kalluru MCP_DRV_NVM_BUF_LEN); 2939057d2b19SSudarsana Reddy Kalluru } 294062e4d438SSudarsana Reddy Kalluru } 294162e4d438SSudarsana Reddy Kalluru 294262e4d438SSudarsana Reddy Kalluru cdev->mcp_nvm_resp = resp; 294362e4d438SSudarsana Reddy Kalluru out: 294462e4d438SSudarsana Reddy Kalluru qed_ptt_release(p_hwfn, p_ptt); 294562e4d438SSudarsana Reddy Kalluru 294662e4d438SSudarsana Reddy Kalluru return rc; 294762e4d438SSudarsana Reddy Kalluru } 294862e4d438SSudarsana Reddy Kalluru 2949b51dab46SSudarsana Reddy Kalluru int qed_mcp_phy_sfp_read(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, 2950b51dab46SSudarsana Reddy Kalluru u32 port, u32 addr, u32 offset, u32 len, u8 *p_buf) 2951b51dab46SSudarsana Reddy Kalluru { 2952b51dab46SSudarsana Reddy Kalluru u32 bytes_left, bytes_to_copy, buf_size, nvm_offset = 0; 2953b51dab46SSudarsana Reddy Kalluru u32 resp, param; 2954b51dab46SSudarsana Reddy Kalluru int rc; 2955b51dab46SSudarsana Reddy Kalluru 2956b51dab46SSudarsana Reddy Kalluru nvm_offset |= (port << DRV_MB_PARAM_TRANSCEIVER_PORT_OFFSET) & 2957b51dab46SSudarsana Reddy Kalluru DRV_MB_PARAM_TRANSCEIVER_PORT_MASK; 2958b51dab46SSudarsana Reddy Kalluru nvm_offset |= (addr << DRV_MB_PARAM_TRANSCEIVER_I2C_ADDRESS_OFFSET) & 2959b51dab46SSudarsana Reddy Kalluru DRV_MB_PARAM_TRANSCEIVER_I2C_ADDRESS_MASK; 2960b51dab46SSudarsana Reddy Kalluru 2961b51dab46SSudarsana Reddy Kalluru addr = offset; 2962b51dab46SSudarsana Reddy Kalluru offset = 0; 2963b51dab46SSudarsana Reddy Kalluru bytes_left = len; 2964b51dab46SSudarsana Reddy Kalluru while (bytes_left > 0) { 2965b51dab46SSudarsana Reddy Kalluru bytes_to_copy = min_t(u32, bytes_left, 2966b51dab46SSudarsana Reddy Kalluru MAX_I2C_TRANSACTION_SIZE); 2967b51dab46SSudarsana Reddy Kalluru nvm_offset &= (DRV_MB_PARAM_TRANSCEIVER_I2C_ADDRESS_MASK | 2968b51dab46SSudarsana Reddy Kalluru DRV_MB_PARAM_TRANSCEIVER_PORT_MASK); 2969b51dab46SSudarsana Reddy Kalluru nvm_offset |= ((addr + offset) << 2970b51dab46SSudarsana Reddy Kalluru DRV_MB_PARAM_TRANSCEIVER_OFFSET_OFFSET) & 2971b51dab46SSudarsana Reddy Kalluru DRV_MB_PARAM_TRANSCEIVER_OFFSET_MASK; 2972b51dab46SSudarsana Reddy Kalluru nvm_offset |= (bytes_to_copy << 2973b51dab46SSudarsana Reddy Kalluru DRV_MB_PARAM_TRANSCEIVER_SIZE_OFFSET) & 2974b51dab46SSudarsana Reddy Kalluru DRV_MB_PARAM_TRANSCEIVER_SIZE_MASK; 2975b51dab46SSudarsana Reddy Kalluru rc = qed_mcp_nvm_rd_cmd(p_hwfn, p_ptt, 2976b51dab46SSudarsana Reddy Kalluru DRV_MSG_CODE_TRANSCEIVER_READ, 2977b51dab46SSudarsana Reddy Kalluru nvm_offset, &resp, ¶m, &buf_size, 2978b51dab46SSudarsana Reddy Kalluru (u32 *)(p_buf + offset)); 2979b51dab46SSudarsana Reddy Kalluru if (rc) { 2980b51dab46SSudarsana Reddy Kalluru DP_NOTICE(p_hwfn, 2981b51dab46SSudarsana Reddy Kalluru "Failed to send a transceiver read command to the MFW. rc = %d.\n", 2982b51dab46SSudarsana Reddy Kalluru rc); 2983b51dab46SSudarsana Reddy Kalluru return rc; 2984b51dab46SSudarsana Reddy Kalluru } 2985b51dab46SSudarsana Reddy Kalluru 2986b51dab46SSudarsana Reddy Kalluru if (resp == FW_MSG_CODE_TRANSCEIVER_NOT_PRESENT) 2987b51dab46SSudarsana Reddy Kalluru return -ENODEV; 2988b51dab46SSudarsana Reddy Kalluru else if (resp != FW_MSG_CODE_TRANSCEIVER_DIAG_OK) 2989b51dab46SSudarsana Reddy Kalluru return -EINVAL; 2990b51dab46SSudarsana Reddy Kalluru 2991b51dab46SSudarsana Reddy Kalluru offset += buf_size; 2992b51dab46SSudarsana Reddy Kalluru bytes_left -= buf_size; 2993b51dab46SSudarsana Reddy Kalluru } 2994b51dab46SSudarsana Reddy Kalluru 2995b51dab46SSudarsana Reddy Kalluru return 0; 2996b51dab46SSudarsana Reddy Kalluru } 2997b51dab46SSudarsana Reddy Kalluru 299803dc76caSSudarsana Reddy Kalluru int qed_mcp_bist_register_test(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 299903dc76caSSudarsana Reddy Kalluru { 300003dc76caSSudarsana Reddy Kalluru u32 drv_mb_param = 0, rsp, param; 300103dc76caSSudarsana Reddy Kalluru int rc = 0; 300203dc76caSSudarsana Reddy Kalluru 300303dc76caSSudarsana Reddy Kalluru drv_mb_param = (DRV_MB_PARAM_BIST_REGISTER_TEST << 300403dc76caSSudarsana Reddy Kalluru DRV_MB_PARAM_BIST_TEST_INDEX_SHIFT); 300503dc76caSSudarsana Reddy Kalluru 300603dc76caSSudarsana Reddy Kalluru rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_BIST_TEST, 300703dc76caSSudarsana Reddy Kalluru drv_mb_param, &rsp, ¶m); 300803dc76caSSudarsana Reddy Kalluru 300903dc76caSSudarsana Reddy Kalluru if (rc) 301003dc76caSSudarsana Reddy Kalluru return rc; 301103dc76caSSudarsana Reddy Kalluru 301203dc76caSSudarsana Reddy Kalluru if (((rsp & FW_MSG_CODE_MASK) != FW_MSG_CODE_OK) || 301303dc76caSSudarsana Reddy Kalluru (param != DRV_MB_PARAM_BIST_RC_PASSED)) 301403dc76caSSudarsana Reddy Kalluru rc = -EAGAIN; 301503dc76caSSudarsana Reddy Kalluru 301603dc76caSSudarsana Reddy Kalluru return rc; 301703dc76caSSudarsana Reddy Kalluru } 301803dc76caSSudarsana Reddy Kalluru 301903dc76caSSudarsana Reddy Kalluru int qed_mcp_bist_clock_test(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 302003dc76caSSudarsana Reddy Kalluru { 302103dc76caSSudarsana Reddy Kalluru u32 drv_mb_param, rsp, param; 302203dc76caSSudarsana Reddy Kalluru int rc = 0; 302303dc76caSSudarsana Reddy Kalluru 302403dc76caSSudarsana Reddy Kalluru drv_mb_param = (DRV_MB_PARAM_BIST_CLOCK_TEST << 302503dc76caSSudarsana Reddy Kalluru DRV_MB_PARAM_BIST_TEST_INDEX_SHIFT); 302603dc76caSSudarsana Reddy Kalluru 302703dc76caSSudarsana Reddy Kalluru rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_BIST_TEST, 302803dc76caSSudarsana Reddy Kalluru drv_mb_param, &rsp, ¶m); 302903dc76caSSudarsana Reddy Kalluru 303003dc76caSSudarsana Reddy Kalluru if (rc) 303103dc76caSSudarsana Reddy Kalluru return rc; 303203dc76caSSudarsana Reddy Kalluru 303303dc76caSSudarsana Reddy Kalluru if (((rsp & FW_MSG_CODE_MASK) != FW_MSG_CODE_OK) || 303403dc76caSSudarsana Reddy Kalluru (param != DRV_MB_PARAM_BIST_RC_PASSED)) 303503dc76caSSudarsana Reddy Kalluru rc = -EAGAIN; 303603dc76caSSudarsana Reddy Kalluru 303703dc76caSSudarsana Reddy Kalluru return rc; 303803dc76caSSudarsana Reddy Kalluru } 30397a4b21b7SMintz, Yuval 304043645ce0SSudarsana Reddy Kalluru int qed_mcp_bist_nvm_get_num_images(struct qed_hwfn *p_hwfn, 30417a4b21b7SMintz, Yuval struct qed_ptt *p_ptt, 30427a4b21b7SMintz, Yuval u32 *num_images) 30437a4b21b7SMintz, Yuval { 30447a4b21b7SMintz, Yuval u32 drv_mb_param = 0, rsp; 30457a4b21b7SMintz, Yuval int rc = 0; 30467a4b21b7SMintz, Yuval 30477a4b21b7SMintz, Yuval drv_mb_param = (DRV_MB_PARAM_BIST_NVM_TEST_NUM_IMAGES << 30487a4b21b7SMintz, Yuval DRV_MB_PARAM_BIST_TEST_INDEX_SHIFT); 30497a4b21b7SMintz, Yuval 30507a4b21b7SMintz, Yuval rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_BIST_TEST, 30517a4b21b7SMintz, Yuval drv_mb_param, &rsp, num_images); 30527a4b21b7SMintz, Yuval if (rc) 30537a4b21b7SMintz, Yuval return rc; 30547a4b21b7SMintz, Yuval 30557a4b21b7SMintz, Yuval if (((rsp & FW_MSG_CODE_MASK) != FW_MSG_CODE_OK)) 30567a4b21b7SMintz, Yuval rc = -EINVAL; 30577a4b21b7SMintz, Yuval 30587a4b21b7SMintz, Yuval return rc; 30597a4b21b7SMintz, Yuval } 30607a4b21b7SMintz, Yuval 306143645ce0SSudarsana Reddy Kalluru int qed_mcp_bist_nvm_get_image_att(struct qed_hwfn *p_hwfn, 30627a4b21b7SMintz, Yuval struct qed_ptt *p_ptt, 30637a4b21b7SMintz, Yuval struct bist_nvm_image_att *p_image_att, 30647a4b21b7SMintz, Yuval u32 image_index) 30657a4b21b7SMintz, Yuval { 30667a4b21b7SMintz, Yuval u32 buf_size = 0, param, resp = 0, resp_param = 0; 30677a4b21b7SMintz, Yuval int rc; 30687a4b21b7SMintz, Yuval 30697a4b21b7SMintz, Yuval param = DRV_MB_PARAM_BIST_NVM_TEST_IMAGE_BY_INDEX << 30707a4b21b7SMintz, Yuval DRV_MB_PARAM_BIST_TEST_INDEX_SHIFT; 30717a4b21b7SMintz, Yuval param |= image_index << DRV_MB_PARAM_BIST_TEST_IMAGE_INDEX_SHIFT; 30727a4b21b7SMintz, Yuval 30737a4b21b7SMintz, Yuval rc = qed_mcp_nvm_rd_cmd(p_hwfn, p_ptt, 30747a4b21b7SMintz, Yuval DRV_MSG_CODE_BIST_TEST, param, 30757a4b21b7SMintz, Yuval &resp, &resp_param, 30767a4b21b7SMintz, Yuval &buf_size, 30777a4b21b7SMintz, Yuval (u32 *)p_image_att); 30787a4b21b7SMintz, Yuval if (rc) 30797a4b21b7SMintz, Yuval return rc; 30807a4b21b7SMintz, Yuval 30817a4b21b7SMintz, Yuval if (((resp & FW_MSG_CODE_MASK) != FW_MSG_CODE_OK) || 30827a4b21b7SMintz, Yuval (p_image_att->return_code != 1)) 30837a4b21b7SMintz, Yuval rc = -EINVAL; 30847a4b21b7SMintz, Yuval 30857a4b21b7SMintz, Yuval return rc; 30867a4b21b7SMintz, Yuval } 30872edbff8dSTomer Tayar 308843645ce0SSudarsana Reddy Kalluru int qed_mcp_nvm_info_populate(struct qed_hwfn *p_hwfn) 308943645ce0SSudarsana Reddy Kalluru { 30905e7ba042SDenis Bolotin struct qed_nvm_image_info nvm_info; 309143645ce0SSudarsana Reddy Kalluru struct qed_ptt *p_ptt; 309243645ce0SSudarsana Reddy Kalluru int rc; 309343645ce0SSudarsana Reddy Kalluru u32 i; 309443645ce0SSudarsana Reddy Kalluru 30955e7ba042SDenis Bolotin if (p_hwfn->nvm_info.valid) 30965e7ba042SDenis Bolotin return 0; 30975e7ba042SDenis Bolotin 309843645ce0SSudarsana Reddy Kalluru p_ptt = qed_ptt_acquire(p_hwfn); 309943645ce0SSudarsana Reddy Kalluru if (!p_ptt) { 310043645ce0SSudarsana Reddy Kalluru DP_ERR(p_hwfn, "failed to acquire ptt\n"); 310143645ce0SSudarsana Reddy Kalluru return -EBUSY; 310243645ce0SSudarsana Reddy Kalluru } 310343645ce0SSudarsana Reddy Kalluru 310443645ce0SSudarsana Reddy Kalluru /* Acquire from MFW the amount of available images */ 31055e7ba042SDenis Bolotin nvm_info.num_images = 0; 310643645ce0SSudarsana Reddy Kalluru rc = qed_mcp_bist_nvm_get_num_images(p_hwfn, 31075e7ba042SDenis Bolotin p_ptt, &nvm_info.num_images); 310843645ce0SSudarsana Reddy Kalluru if (rc == -EOPNOTSUPP) { 310943645ce0SSudarsana Reddy Kalluru DP_INFO(p_hwfn, "DRV_MSG_CODE_BIST_TEST is not supported\n"); 311043645ce0SSudarsana Reddy Kalluru goto out; 31115e7ba042SDenis Bolotin } else if (rc || !nvm_info.num_images) { 311243645ce0SSudarsana Reddy Kalluru DP_ERR(p_hwfn, "Failed getting number of images\n"); 311343645ce0SSudarsana Reddy Kalluru goto err0; 311443645ce0SSudarsana Reddy Kalluru } 311543645ce0SSudarsana Reddy Kalluru 31165e7ba042SDenis Bolotin nvm_info.image_att = kmalloc_array(nvm_info.num_images, 311743645ce0SSudarsana Reddy Kalluru sizeof(struct bist_nvm_image_att), 311843645ce0SSudarsana Reddy Kalluru GFP_KERNEL); 31195e7ba042SDenis Bolotin if (!nvm_info.image_att) { 312043645ce0SSudarsana Reddy Kalluru rc = -ENOMEM; 312143645ce0SSudarsana Reddy Kalluru goto err0; 312243645ce0SSudarsana Reddy Kalluru } 312343645ce0SSudarsana Reddy Kalluru 312443645ce0SSudarsana Reddy Kalluru /* Iterate over images and get their attributes */ 31255e7ba042SDenis Bolotin for (i = 0; i < nvm_info.num_images; i++) { 312643645ce0SSudarsana Reddy Kalluru rc = qed_mcp_bist_nvm_get_image_att(p_hwfn, p_ptt, 31275e7ba042SDenis Bolotin &nvm_info.image_att[i], i); 312843645ce0SSudarsana Reddy Kalluru if (rc) { 312943645ce0SSudarsana Reddy Kalluru DP_ERR(p_hwfn, 313043645ce0SSudarsana Reddy Kalluru "Failed getting image index %d attributes\n", i); 313143645ce0SSudarsana Reddy Kalluru goto err1; 313243645ce0SSudarsana Reddy Kalluru } 313343645ce0SSudarsana Reddy Kalluru 313443645ce0SSudarsana Reddy Kalluru DP_VERBOSE(p_hwfn, QED_MSG_SP, "image index %d, size %x\n", i, 31355e7ba042SDenis Bolotin nvm_info.image_att[i].len); 313643645ce0SSudarsana Reddy Kalluru } 313743645ce0SSudarsana Reddy Kalluru out: 31385e7ba042SDenis Bolotin /* Update hwfn's nvm_info */ 31395e7ba042SDenis Bolotin if (nvm_info.num_images) { 31405e7ba042SDenis Bolotin p_hwfn->nvm_info.num_images = nvm_info.num_images; 31415e7ba042SDenis Bolotin kfree(p_hwfn->nvm_info.image_att); 31425e7ba042SDenis Bolotin p_hwfn->nvm_info.image_att = nvm_info.image_att; 31435e7ba042SDenis Bolotin p_hwfn->nvm_info.valid = true; 31445e7ba042SDenis Bolotin } 31455e7ba042SDenis Bolotin 314643645ce0SSudarsana Reddy Kalluru qed_ptt_release(p_hwfn, p_ptt); 314743645ce0SSudarsana Reddy Kalluru return 0; 314843645ce0SSudarsana Reddy Kalluru 314943645ce0SSudarsana Reddy Kalluru err1: 31505e7ba042SDenis Bolotin kfree(nvm_info.image_att); 315143645ce0SSudarsana Reddy Kalluru err0: 315243645ce0SSudarsana Reddy Kalluru qed_ptt_release(p_hwfn, p_ptt); 315343645ce0SSudarsana Reddy Kalluru return rc; 315443645ce0SSudarsana Reddy Kalluru } 315543645ce0SSudarsana Reddy Kalluru 31561ac4329aSDenis Bolotin int 315720675b37SMintz, Yuval qed_mcp_get_nvm_image_att(struct qed_hwfn *p_hwfn, 315820675b37SMintz, Yuval enum qed_nvm_images image_id, 315920675b37SMintz, Yuval struct qed_nvm_image_att *p_image_att) 316020675b37SMintz, Yuval { 316120675b37SMintz, Yuval enum nvm_image_type type; 316243645ce0SSudarsana Reddy Kalluru u32 i; 316320675b37SMintz, Yuval 316420675b37SMintz, Yuval /* Translate image_id into MFW definitions */ 316520675b37SMintz, Yuval switch (image_id) { 316620675b37SMintz, Yuval case QED_NVM_IMAGE_ISCSI_CFG: 316720675b37SMintz, Yuval type = NVM_TYPE_ISCSI_CFG; 316820675b37SMintz, Yuval break; 316920675b37SMintz, Yuval case QED_NVM_IMAGE_FCOE_CFG: 317020675b37SMintz, Yuval type = NVM_TYPE_FCOE_CFG; 317120675b37SMintz, Yuval break; 31728a52bbabSMichal Kalderon case QED_NVM_IMAGE_MDUMP: 31738a52bbabSMichal Kalderon type = NVM_TYPE_MDUMP; 31748a52bbabSMichal Kalderon break; 31751ac4329aSDenis Bolotin case QED_NVM_IMAGE_NVM_CFG1: 31761ac4329aSDenis Bolotin type = NVM_TYPE_NVM_CFG1; 31771ac4329aSDenis Bolotin break; 31781ac4329aSDenis Bolotin case QED_NVM_IMAGE_DEFAULT_CFG: 31791ac4329aSDenis Bolotin type = NVM_TYPE_DEFAULT_CFG; 31801ac4329aSDenis Bolotin break; 31811ac4329aSDenis Bolotin case QED_NVM_IMAGE_NVM_META: 31821ac4329aSDenis Bolotin type = NVM_TYPE_META; 31831ac4329aSDenis Bolotin break; 318420675b37SMintz, Yuval default: 318520675b37SMintz, Yuval DP_NOTICE(p_hwfn, "Unknown request of image_id %08x\n", 318620675b37SMintz, Yuval image_id); 318720675b37SMintz, Yuval return -EINVAL; 318820675b37SMintz, Yuval } 318920675b37SMintz, Yuval 31905e7ba042SDenis Bolotin qed_mcp_nvm_info_populate(p_hwfn); 319143645ce0SSudarsana Reddy Kalluru for (i = 0; i < p_hwfn->nvm_info.num_images; i++) 319243645ce0SSudarsana Reddy Kalluru if (type == p_hwfn->nvm_info.image_att[i].image_type) 319320675b37SMintz, Yuval break; 319443645ce0SSudarsana Reddy Kalluru if (i == p_hwfn->nvm_info.num_images) { 319520675b37SMintz, Yuval DP_VERBOSE(p_hwfn, QED_MSG_STORAGE, 319620675b37SMintz, Yuval "Failed to find nvram image of type %08x\n", 319720675b37SMintz, Yuval image_id); 319843645ce0SSudarsana Reddy Kalluru return -ENOENT; 319920675b37SMintz, Yuval } 320020675b37SMintz, Yuval 320143645ce0SSudarsana Reddy Kalluru p_image_att->start_addr = p_hwfn->nvm_info.image_att[i].nvm_start_addr; 320243645ce0SSudarsana Reddy Kalluru p_image_att->length = p_hwfn->nvm_info.image_att[i].len; 320320675b37SMintz, Yuval 320420675b37SMintz, Yuval return 0; 320520675b37SMintz, Yuval } 320620675b37SMintz, Yuval 320720675b37SMintz, Yuval int qed_mcp_get_nvm_image(struct qed_hwfn *p_hwfn, 320820675b37SMintz, Yuval enum qed_nvm_images image_id, 320920675b37SMintz, Yuval u8 *p_buffer, u32 buffer_len) 321020675b37SMintz, Yuval { 321120675b37SMintz, Yuval struct qed_nvm_image_att image_att; 321220675b37SMintz, Yuval int rc; 321320675b37SMintz, Yuval 321420675b37SMintz, Yuval memset(p_buffer, 0, buffer_len); 321520675b37SMintz, Yuval 3216b60bfdfeSDenis Bolotin rc = qed_mcp_get_nvm_image_att(p_hwfn, image_id, &image_att); 321720675b37SMintz, Yuval if (rc) 321820675b37SMintz, Yuval return rc; 321920675b37SMintz, Yuval 322020675b37SMintz, Yuval /* Validate sizes - both the image's and the supplied buffer's */ 322120675b37SMintz, Yuval if (image_att.length <= 4) { 322220675b37SMintz, Yuval DP_VERBOSE(p_hwfn, QED_MSG_STORAGE, 322320675b37SMintz, Yuval "Image [%d] is too small - only %d bytes\n", 322420675b37SMintz, Yuval image_id, image_att.length); 322520675b37SMintz, Yuval return -EINVAL; 322620675b37SMintz, Yuval } 322720675b37SMintz, Yuval 322820675b37SMintz, Yuval if (image_att.length > buffer_len) { 322920675b37SMintz, Yuval DP_VERBOSE(p_hwfn, 323020675b37SMintz, Yuval QED_MSG_STORAGE, 323120675b37SMintz, Yuval "Image [%d] is too big - %08x bytes where only %08x are available\n", 323220675b37SMintz, Yuval image_id, image_att.length, buffer_len); 323320675b37SMintz, Yuval return -ENOMEM; 323420675b37SMintz, Yuval } 323520675b37SMintz, Yuval 323620675b37SMintz, Yuval return qed_mcp_nvm_read(p_hwfn->cdev, image_att.start_addr, 323720675b37SMintz, Yuval p_buffer, image_att.length); 323820675b37SMintz, Yuval } 323920675b37SMintz, Yuval 32409c8517c4STomer Tayar static enum resource_id_enum qed_mcp_get_mfw_res_id(enum qed_resources res_id) 32419c8517c4STomer Tayar { 32429c8517c4STomer Tayar enum resource_id_enum mfw_res_id = RESOURCE_NUM_INVALID; 32439c8517c4STomer Tayar 32449c8517c4STomer Tayar switch (res_id) { 32459c8517c4STomer Tayar case QED_SB: 32469c8517c4STomer Tayar mfw_res_id = RESOURCE_NUM_SB_E; 32479c8517c4STomer Tayar break; 32489c8517c4STomer Tayar case QED_L2_QUEUE: 32499c8517c4STomer Tayar mfw_res_id = RESOURCE_NUM_L2_QUEUE_E; 32509c8517c4STomer Tayar break; 32519c8517c4STomer Tayar case QED_VPORT: 32529c8517c4STomer Tayar mfw_res_id = RESOURCE_NUM_VPORT_E; 32539c8517c4STomer Tayar break; 32549c8517c4STomer Tayar case QED_RSS_ENG: 32559c8517c4STomer Tayar mfw_res_id = RESOURCE_NUM_RSS_ENGINES_E; 32569c8517c4STomer Tayar break; 32579c8517c4STomer Tayar case QED_PQ: 32589c8517c4STomer Tayar mfw_res_id = RESOURCE_NUM_PQ_E; 32599c8517c4STomer Tayar break; 32609c8517c4STomer Tayar case QED_RL: 32619c8517c4STomer Tayar mfw_res_id = RESOURCE_NUM_RL_E; 32629c8517c4STomer Tayar break; 32639c8517c4STomer Tayar case QED_MAC: 32649c8517c4STomer Tayar case QED_VLAN: 32659c8517c4STomer Tayar /* Each VFC resource can accommodate both a MAC and a VLAN */ 32669c8517c4STomer Tayar mfw_res_id = RESOURCE_VFC_FILTER_E; 32679c8517c4STomer Tayar break; 32689c8517c4STomer Tayar case QED_ILT: 32699c8517c4STomer Tayar mfw_res_id = RESOURCE_ILT_E; 32709c8517c4STomer Tayar break; 3271997af5dfSMichal Kalderon case QED_LL2_RAM_QUEUE: 32729c8517c4STomer Tayar mfw_res_id = RESOURCE_LL2_QUEUE_E; 32739c8517c4STomer Tayar break; 3274997af5dfSMichal Kalderon case QED_LL2_CTX_QUEUE: 3275997af5dfSMichal Kalderon mfw_res_id = RESOURCE_LL2_CQS_E; 3276997af5dfSMichal Kalderon break; 32779c8517c4STomer Tayar case QED_RDMA_CNQ_RAM: 32789c8517c4STomer Tayar case QED_CMDQS_CQS: 32799c8517c4STomer Tayar /* CNQ/CMDQS are the same resource */ 32809c8517c4STomer Tayar mfw_res_id = RESOURCE_CQS_E; 32819c8517c4STomer Tayar break; 32829c8517c4STomer Tayar case QED_RDMA_STATS_QUEUE: 32839c8517c4STomer Tayar mfw_res_id = RESOURCE_RDMA_STATS_QUEUE_E; 32849c8517c4STomer Tayar break; 32859c8517c4STomer Tayar case QED_BDQ: 32869c8517c4STomer Tayar mfw_res_id = RESOURCE_BDQ_E; 32879c8517c4STomer Tayar break; 32889c8517c4STomer Tayar default: 32899c8517c4STomer Tayar break; 32909c8517c4STomer Tayar } 32919c8517c4STomer Tayar 32929c8517c4STomer Tayar return mfw_res_id; 32939c8517c4STomer Tayar } 32949c8517c4STomer Tayar 32959c8517c4STomer Tayar #define QED_RESC_ALLOC_VERSION_MAJOR 2 32962edbff8dSTomer Tayar #define QED_RESC_ALLOC_VERSION_MINOR 0 32972edbff8dSTomer Tayar #define QED_RESC_ALLOC_VERSION \ 32982edbff8dSTomer Tayar ((QED_RESC_ALLOC_VERSION_MAJOR << \ 32992edbff8dSTomer Tayar DRV_MB_PARAM_RESOURCE_ALLOC_VERSION_MAJOR_SHIFT) | \ 33002edbff8dSTomer Tayar (QED_RESC_ALLOC_VERSION_MINOR << \ 33012edbff8dSTomer Tayar DRV_MB_PARAM_RESOURCE_ALLOC_VERSION_MINOR_SHIFT)) 33029c8517c4STomer Tayar 33039c8517c4STomer Tayar struct qed_resc_alloc_in_params { 33049c8517c4STomer Tayar u32 cmd; 33059c8517c4STomer Tayar enum qed_resources res_id; 33069c8517c4STomer Tayar u32 resc_max_val; 33079c8517c4STomer Tayar }; 33089c8517c4STomer Tayar 33099c8517c4STomer Tayar struct qed_resc_alloc_out_params { 33109c8517c4STomer Tayar u32 mcp_resp; 33119c8517c4STomer Tayar u32 mcp_param; 33129c8517c4STomer Tayar u32 resc_num; 33139c8517c4STomer Tayar u32 resc_start; 33149c8517c4STomer Tayar u32 vf_resc_num; 33159c8517c4STomer Tayar u32 vf_resc_start; 33169c8517c4STomer Tayar u32 flags; 33179c8517c4STomer Tayar }; 33189c8517c4STomer Tayar 33199c8517c4STomer Tayar static int 33209c8517c4STomer Tayar qed_mcp_resc_allocation_msg(struct qed_hwfn *p_hwfn, 33212edbff8dSTomer Tayar struct qed_ptt *p_ptt, 33229c8517c4STomer Tayar struct qed_resc_alloc_in_params *p_in_params, 33239c8517c4STomer Tayar struct qed_resc_alloc_out_params *p_out_params) 33242edbff8dSTomer Tayar { 33252edbff8dSTomer Tayar struct qed_mcp_mb_params mb_params; 33269c8517c4STomer Tayar struct resource_info mfw_resc_info; 33272edbff8dSTomer Tayar int rc; 33282edbff8dSTomer Tayar 33299c8517c4STomer Tayar memset(&mfw_resc_info, 0, sizeof(mfw_resc_info)); 3330bb480242SMintz, Yuval 33319c8517c4STomer Tayar mfw_resc_info.res_id = qed_mcp_get_mfw_res_id(p_in_params->res_id); 33329c8517c4STomer Tayar if (mfw_resc_info.res_id == RESOURCE_NUM_INVALID) { 33339c8517c4STomer Tayar DP_ERR(p_hwfn, 33349c8517c4STomer Tayar "Failed to match resource %d [%s] with the MFW resources\n", 33359c8517c4STomer Tayar p_in_params->res_id, 33369c8517c4STomer Tayar qed_hw_get_resc_name(p_in_params->res_id)); 33379c8517c4STomer Tayar return -EINVAL; 33389c8517c4STomer Tayar } 33399c8517c4STomer Tayar 33409c8517c4STomer Tayar switch (p_in_params->cmd) { 33419c8517c4STomer Tayar case DRV_MSG_SET_RESOURCE_VALUE_MSG: 33429c8517c4STomer Tayar mfw_resc_info.size = p_in_params->resc_max_val; 33439c8517c4STomer Tayar /* Fallthrough */ 33449c8517c4STomer Tayar case DRV_MSG_GET_RESOURCE_ALLOC_MSG: 33459c8517c4STomer Tayar break; 33469c8517c4STomer Tayar default: 33479c8517c4STomer Tayar DP_ERR(p_hwfn, "Unexpected resource alloc command [0x%08x]\n", 33489c8517c4STomer Tayar p_in_params->cmd); 33499c8517c4STomer Tayar return -EINVAL; 33509c8517c4STomer Tayar } 33519c8517c4STomer Tayar 33529c8517c4STomer Tayar memset(&mb_params, 0, sizeof(mb_params)); 33539c8517c4STomer Tayar mb_params.cmd = p_in_params->cmd; 33549c8517c4STomer Tayar mb_params.param = QED_RESC_ALLOC_VERSION; 33559c8517c4STomer Tayar mb_params.p_data_src = &mfw_resc_info; 33569c8517c4STomer Tayar mb_params.data_src_size = sizeof(mfw_resc_info); 33579c8517c4STomer Tayar mb_params.p_data_dst = mb_params.p_data_src; 33589c8517c4STomer Tayar mb_params.data_dst_size = mb_params.data_src_size; 33599c8517c4STomer Tayar 33609c8517c4STomer Tayar DP_VERBOSE(p_hwfn, 33619c8517c4STomer Tayar QED_MSG_SP, 33629c8517c4STomer Tayar "Resource message request: cmd 0x%08x, res_id %d [%s], hsi_version %d.%d, val 0x%x\n", 33639c8517c4STomer Tayar p_in_params->cmd, 33649c8517c4STomer Tayar p_in_params->res_id, 33659c8517c4STomer Tayar qed_hw_get_resc_name(p_in_params->res_id), 33669c8517c4STomer Tayar QED_MFW_GET_FIELD(mb_params.param, 33679c8517c4STomer Tayar DRV_MB_PARAM_RESOURCE_ALLOC_VERSION_MAJOR), 33689c8517c4STomer Tayar QED_MFW_GET_FIELD(mb_params.param, 33699c8517c4STomer Tayar DRV_MB_PARAM_RESOURCE_ALLOC_VERSION_MINOR), 33709c8517c4STomer Tayar p_in_params->resc_max_val); 33719c8517c4STomer Tayar 33722edbff8dSTomer Tayar rc = qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 33732edbff8dSTomer Tayar if (rc) 33742edbff8dSTomer Tayar return rc; 33752edbff8dSTomer Tayar 33769c8517c4STomer Tayar p_out_params->mcp_resp = mb_params.mcp_resp; 33779c8517c4STomer Tayar p_out_params->mcp_param = mb_params.mcp_param; 33789c8517c4STomer Tayar p_out_params->resc_num = mfw_resc_info.size; 33799c8517c4STomer Tayar p_out_params->resc_start = mfw_resc_info.offset; 33809c8517c4STomer Tayar p_out_params->vf_resc_num = mfw_resc_info.vf_size; 33819c8517c4STomer Tayar p_out_params->vf_resc_start = mfw_resc_info.vf_offset; 33829c8517c4STomer Tayar p_out_params->flags = mfw_resc_info.flags; 33832edbff8dSTomer Tayar 33842edbff8dSTomer Tayar DP_VERBOSE(p_hwfn, 33852edbff8dSTomer Tayar QED_MSG_SP, 33869c8517c4STomer 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", 33879c8517c4STomer Tayar QED_MFW_GET_FIELD(p_out_params->mcp_param, 33889c8517c4STomer Tayar FW_MB_PARAM_RESOURCE_ALLOC_VERSION_MAJOR), 33899c8517c4STomer Tayar QED_MFW_GET_FIELD(p_out_params->mcp_param, 33909c8517c4STomer Tayar FW_MB_PARAM_RESOURCE_ALLOC_VERSION_MINOR), 33919c8517c4STomer Tayar p_out_params->resc_num, 33929c8517c4STomer Tayar p_out_params->resc_start, 33939c8517c4STomer Tayar p_out_params->vf_resc_num, 33949c8517c4STomer Tayar p_out_params->vf_resc_start, p_out_params->flags); 33959c8517c4STomer Tayar 33969c8517c4STomer Tayar return 0; 33979c8517c4STomer Tayar } 33989c8517c4STomer Tayar 33999c8517c4STomer Tayar int 34009c8517c4STomer Tayar qed_mcp_set_resc_max_val(struct qed_hwfn *p_hwfn, 34019c8517c4STomer Tayar struct qed_ptt *p_ptt, 34029c8517c4STomer Tayar enum qed_resources res_id, 34039c8517c4STomer Tayar u32 resc_max_val, u32 *p_mcp_resp) 34049c8517c4STomer Tayar { 34059c8517c4STomer Tayar struct qed_resc_alloc_out_params out_params; 34069c8517c4STomer Tayar struct qed_resc_alloc_in_params in_params; 34079c8517c4STomer Tayar int rc; 34089c8517c4STomer Tayar 34099c8517c4STomer Tayar memset(&in_params, 0, sizeof(in_params)); 34109c8517c4STomer Tayar in_params.cmd = DRV_MSG_SET_RESOURCE_VALUE_MSG; 34119c8517c4STomer Tayar in_params.res_id = res_id; 34129c8517c4STomer Tayar in_params.resc_max_val = resc_max_val; 34139c8517c4STomer Tayar memset(&out_params, 0, sizeof(out_params)); 34149c8517c4STomer Tayar rc = qed_mcp_resc_allocation_msg(p_hwfn, p_ptt, &in_params, 34159c8517c4STomer Tayar &out_params); 34169c8517c4STomer Tayar if (rc) 34179c8517c4STomer Tayar return rc; 34189c8517c4STomer Tayar 34199c8517c4STomer Tayar *p_mcp_resp = out_params.mcp_resp; 34209c8517c4STomer Tayar 34219c8517c4STomer Tayar return 0; 34229c8517c4STomer Tayar } 34239c8517c4STomer Tayar 34249c8517c4STomer Tayar int 34259c8517c4STomer Tayar qed_mcp_get_resc_info(struct qed_hwfn *p_hwfn, 34269c8517c4STomer Tayar struct qed_ptt *p_ptt, 34279c8517c4STomer Tayar enum qed_resources res_id, 34289c8517c4STomer Tayar u32 *p_mcp_resp, u32 *p_resc_num, u32 *p_resc_start) 34299c8517c4STomer Tayar { 34309c8517c4STomer Tayar struct qed_resc_alloc_out_params out_params; 34319c8517c4STomer Tayar struct qed_resc_alloc_in_params in_params; 34329c8517c4STomer Tayar int rc; 34339c8517c4STomer Tayar 34349c8517c4STomer Tayar memset(&in_params, 0, sizeof(in_params)); 34359c8517c4STomer Tayar in_params.cmd = DRV_MSG_GET_RESOURCE_ALLOC_MSG; 34369c8517c4STomer Tayar in_params.res_id = res_id; 34379c8517c4STomer Tayar memset(&out_params, 0, sizeof(out_params)); 34389c8517c4STomer Tayar rc = qed_mcp_resc_allocation_msg(p_hwfn, p_ptt, &in_params, 34399c8517c4STomer Tayar &out_params); 34409c8517c4STomer Tayar if (rc) 34419c8517c4STomer Tayar return rc; 34429c8517c4STomer Tayar 34439c8517c4STomer Tayar *p_mcp_resp = out_params.mcp_resp; 34449c8517c4STomer Tayar 34459c8517c4STomer Tayar if (*p_mcp_resp == FW_MSG_CODE_RESOURCE_ALLOC_OK) { 34469c8517c4STomer Tayar *p_resc_num = out_params.resc_num; 34479c8517c4STomer Tayar *p_resc_start = out_params.resc_start; 34489c8517c4STomer Tayar } 34492edbff8dSTomer Tayar 34502edbff8dSTomer Tayar return 0; 34512edbff8dSTomer Tayar } 345218a69e36SMintz, Yuval 345318a69e36SMintz, Yuval int qed_mcp_initiate_pf_flr(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 345418a69e36SMintz, Yuval { 345518a69e36SMintz, Yuval u32 mcp_resp, mcp_param; 345618a69e36SMintz, Yuval 345718a69e36SMintz, Yuval return qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_INITIATE_PF_FLR, 0, 345818a69e36SMintz, Yuval &mcp_resp, &mcp_param); 345918a69e36SMintz, Yuval } 346095691c9cSTomer Tayar 346195691c9cSTomer Tayar static int qed_mcp_resource_cmd(struct qed_hwfn *p_hwfn, 346295691c9cSTomer Tayar struct qed_ptt *p_ptt, 346395691c9cSTomer Tayar u32 param, u32 *p_mcp_resp, u32 *p_mcp_param) 346495691c9cSTomer Tayar { 346595691c9cSTomer Tayar int rc; 346695691c9cSTomer Tayar 346795691c9cSTomer Tayar rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_RESOURCE_CMD, param, 346895691c9cSTomer Tayar p_mcp_resp, p_mcp_param); 346995691c9cSTomer Tayar if (rc) 347095691c9cSTomer Tayar return rc; 347195691c9cSTomer Tayar 347295691c9cSTomer Tayar if (*p_mcp_resp == FW_MSG_CODE_UNSUPPORTED) { 347395691c9cSTomer Tayar DP_INFO(p_hwfn, 347495691c9cSTomer Tayar "The resource command is unsupported by the MFW\n"); 347595691c9cSTomer Tayar return -EINVAL; 347695691c9cSTomer Tayar } 347795691c9cSTomer Tayar 347895691c9cSTomer Tayar if (*p_mcp_param == RESOURCE_OPCODE_UNKNOWN_CMD) { 347995691c9cSTomer Tayar u8 opcode = QED_MFW_GET_FIELD(param, RESOURCE_CMD_REQ_OPCODE); 348095691c9cSTomer Tayar 348195691c9cSTomer Tayar DP_NOTICE(p_hwfn, 348295691c9cSTomer Tayar "The resource command is unknown to the MFW [param 0x%08x, opcode %d]\n", 348395691c9cSTomer Tayar param, opcode); 348495691c9cSTomer Tayar return -EINVAL; 348595691c9cSTomer Tayar } 348695691c9cSTomer Tayar 348795691c9cSTomer Tayar return rc; 348895691c9cSTomer Tayar } 348995691c9cSTomer Tayar 3490bf774d14SYueHaibing static int 349195691c9cSTomer Tayar __qed_mcp_resc_lock(struct qed_hwfn *p_hwfn, 349295691c9cSTomer Tayar struct qed_ptt *p_ptt, 349395691c9cSTomer Tayar struct qed_resc_lock_params *p_params) 349495691c9cSTomer Tayar { 349595691c9cSTomer Tayar u32 param = 0, mcp_resp, mcp_param; 349695691c9cSTomer Tayar u8 opcode; 349795691c9cSTomer Tayar int rc; 349895691c9cSTomer Tayar 349995691c9cSTomer Tayar switch (p_params->timeout) { 350095691c9cSTomer Tayar case QED_MCP_RESC_LOCK_TO_DEFAULT: 350195691c9cSTomer Tayar opcode = RESOURCE_OPCODE_REQ; 350295691c9cSTomer Tayar p_params->timeout = 0; 350395691c9cSTomer Tayar break; 350495691c9cSTomer Tayar case QED_MCP_RESC_LOCK_TO_NONE: 350595691c9cSTomer Tayar opcode = RESOURCE_OPCODE_REQ_WO_AGING; 350695691c9cSTomer Tayar p_params->timeout = 0; 350795691c9cSTomer Tayar break; 350895691c9cSTomer Tayar default: 350995691c9cSTomer Tayar opcode = RESOURCE_OPCODE_REQ_W_AGING; 351095691c9cSTomer Tayar break; 351195691c9cSTomer Tayar } 351295691c9cSTomer Tayar 351395691c9cSTomer Tayar QED_MFW_SET_FIELD(param, RESOURCE_CMD_REQ_RESC, p_params->resource); 351495691c9cSTomer Tayar QED_MFW_SET_FIELD(param, RESOURCE_CMD_REQ_OPCODE, opcode); 351595691c9cSTomer Tayar QED_MFW_SET_FIELD(param, RESOURCE_CMD_REQ_AGE, p_params->timeout); 351695691c9cSTomer Tayar 351795691c9cSTomer Tayar DP_VERBOSE(p_hwfn, 351895691c9cSTomer Tayar QED_MSG_SP, 351995691c9cSTomer Tayar "Resource lock request: param 0x%08x [age %d, opcode %d, resource %d]\n", 352095691c9cSTomer Tayar param, p_params->timeout, opcode, p_params->resource); 352195691c9cSTomer Tayar 352295691c9cSTomer Tayar /* Attempt to acquire the resource */ 352395691c9cSTomer Tayar rc = qed_mcp_resource_cmd(p_hwfn, p_ptt, param, &mcp_resp, &mcp_param); 352495691c9cSTomer Tayar if (rc) 352595691c9cSTomer Tayar return rc; 352695691c9cSTomer Tayar 352795691c9cSTomer Tayar /* Analyze the response */ 352895691c9cSTomer Tayar p_params->owner = QED_MFW_GET_FIELD(mcp_param, RESOURCE_CMD_RSP_OWNER); 352995691c9cSTomer Tayar opcode = QED_MFW_GET_FIELD(mcp_param, RESOURCE_CMD_RSP_OPCODE); 353095691c9cSTomer Tayar 353195691c9cSTomer Tayar DP_VERBOSE(p_hwfn, 353295691c9cSTomer Tayar QED_MSG_SP, 353395691c9cSTomer Tayar "Resource lock response: mcp_param 0x%08x [opcode %d, owner %d]\n", 353495691c9cSTomer Tayar mcp_param, opcode, p_params->owner); 353595691c9cSTomer Tayar 353695691c9cSTomer Tayar switch (opcode) { 353795691c9cSTomer Tayar case RESOURCE_OPCODE_GNT: 353895691c9cSTomer Tayar p_params->b_granted = true; 353995691c9cSTomer Tayar break; 354095691c9cSTomer Tayar case RESOURCE_OPCODE_BUSY: 354195691c9cSTomer Tayar p_params->b_granted = false; 354295691c9cSTomer Tayar break; 354395691c9cSTomer Tayar default: 354495691c9cSTomer Tayar DP_NOTICE(p_hwfn, 354595691c9cSTomer Tayar "Unexpected opcode in resource lock response [mcp_param 0x%08x, opcode %d]\n", 354695691c9cSTomer Tayar mcp_param, opcode); 354795691c9cSTomer Tayar return -EINVAL; 354895691c9cSTomer Tayar } 354995691c9cSTomer Tayar 355095691c9cSTomer Tayar return 0; 355195691c9cSTomer Tayar } 355295691c9cSTomer Tayar 355395691c9cSTomer Tayar int 355495691c9cSTomer Tayar qed_mcp_resc_lock(struct qed_hwfn *p_hwfn, 355595691c9cSTomer Tayar struct qed_ptt *p_ptt, struct qed_resc_lock_params *p_params) 355695691c9cSTomer Tayar { 355795691c9cSTomer Tayar u32 retry_cnt = 0; 355895691c9cSTomer Tayar int rc; 355995691c9cSTomer Tayar 356095691c9cSTomer Tayar do { 356195691c9cSTomer Tayar /* No need for an interval before the first iteration */ 356295691c9cSTomer Tayar if (retry_cnt) { 356395691c9cSTomer Tayar if (p_params->sleep_b4_retry) { 356495691c9cSTomer Tayar u16 retry_interval_in_ms = 356595691c9cSTomer Tayar DIV_ROUND_UP(p_params->retry_interval, 356695691c9cSTomer Tayar 1000); 356795691c9cSTomer Tayar 356895691c9cSTomer Tayar msleep(retry_interval_in_ms); 356995691c9cSTomer Tayar } else { 357095691c9cSTomer Tayar udelay(p_params->retry_interval); 357195691c9cSTomer Tayar } 357295691c9cSTomer Tayar } 357395691c9cSTomer Tayar 357495691c9cSTomer Tayar rc = __qed_mcp_resc_lock(p_hwfn, p_ptt, p_params); 357595691c9cSTomer Tayar if (rc) 357695691c9cSTomer Tayar return rc; 357795691c9cSTomer Tayar 357895691c9cSTomer Tayar if (p_params->b_granted) 357995691c9cSTomer Tayar break; 358095691c9cSTomer Tayar } while (retry_cnt++ < p_params->retry_num); 358195691c9cSTomer Tayar 358295691c9cSTomer Tayar return 0; 358395691c9cSTomer Tayar } 358495691c9cSTomer Tayar 358595691c9cSTomer Tayar int 358695691c9cSTomer Tayar qed_mcp_resc_unlock(struct qed_hwfn *p_hwfn, 358795691c9cSTomer Tayar struct qed_ptt *p_ptt, 358895691c9cSTomer Tayar struct qed_resc_unlock_params *p_params) 358995691c9cSTomer Tayar { 359095691c9cSTomer Tayar u32 param = 0, mcp_resp, mcp_param; 359195691c9cSTomer Tayar u8 opcode; 359295691c9cSTomer Tayar int rc; 359395691c9cSTomer Tayar 359495691c9cSTomer Tayar opcode = p_params->b_force ? RESOURCE_OPCODE_FORCE_RELEASE 359595691c9cSTomer Tayar : RESOURCE_OPCODE_RELEASE; 359695691c9cSTomer Tayar QED_MFW_SET_FIELD(param, RESOURCE_CMD_REQ_RESC, p_params->resource); 359795691c9cSTomer Tayar QED_MFW_SET_FIELD(param, RESOURCE_CMD_REQ_OPCODE, opcode); 359895691c9cSTomer Tayar 359995691c9cSTomer Tayar DP_VERBOSE(p_hwfn, QED_MSG_SP, 360095691c9cSTomer Tayar "Resource unlock request: param 0x%08x [opcode %d, resource %d]\n", 360195691c9cSTomer Tayar param, opcode, p_params->resource); 360295691c9cSTomer Tayar 360395691c9cSTomer Tayar /* Attempt to release the resource */ 360495691c9cSTomer Tayar rc = qed_mcp_resource_cmd(p_hwfn, p_ptt, param, &mcp_resp, &mcp_param); 360595691c9cSTomer Tayar if (rc) 360695691c9cSTomer Tayar return rc; 360795691c9cSTomer Tayar 360895691c9cSTomer Tayar /* Analyze the response */ 360995691c9cSTomer Tayar opcode = QED_MFW_GET_FIELD(mcp_param, RESOURCE_CMD_RSP_OPCODE); 361095691c9cSTomer Tayar 361195691c9cSTomer Tayar DP_VERBOSE(p_hwfn, QED_MSG_SP, 361295691c9cSTomer Tayar "Resource unlock response: mcp_param 0x%08x [opcode %d]\n", 361395691c9cSTomer Tayar mcp_param, opcode); 361495691c9cSTomer Tayar 361595691c9cSTomer Tayar switch (opcode) { 361695691c9cSTomer Tayar case RESOURCE_OPCODE_RELEASED_PREVIOUS: 361795691c9cSTomer Tayar DP_INFO(p_hwfn, 361895691c9cSTomer Tayar "Resource unlock request for an already released resource [%d]\n", 361995691c9cSTomer Tayar p_params->resource); 362095691c9cSTomer Tayar /* Fallthrough */ 362195691c9cSTomer Tayar case RESOURCE_OPCODE_RELEASED: 362295691c9cSTomer Tayar p_params->b_released = true; 362395691c9cSTomer Tayar break; 362495691c9cSTomer Tayar case RESOURCE_OPCODE_WRONG_OWNER: 362595691c9cSTomer Tayar p_params->b_released = false; 362695691c9cSTomer Tayar break; 362795691c9cSTomer Tayar default: 362895691c9cSTomer Tayar DP_NOTICE(p_hwfn, 362995691c9cSTomer Tayar "Unexpected opcode in resource unlock response [mcp_param 0x%08x, opcode %d]\n", 363095691c9cSTomer Tayar mcp_param, opcode); 363195691c9cSTomer Tayar return -EINVAL; 363295691c9cSTomer Tayar } 363395691c9cSTomer Tayar 363495691c9cSTomer Tayar return 0; 363595691c9cSTomer Tayar } 3636f470f22cSsudarsana.kalluru@cavium.com 3637f470f22cSsudarsana.kalluru@cavium.com void qed_mcp_resc_lock_default_init(struct qed_resc_lock_params *p_lock, 3638f470f22cSsudarsana.kalluru@cavium.com struct qed_resc_unlock_params *p_unlock, 3639f470f22cSsudarsana.kalluru@cavium.com enum qed_resc_lock 3640f470f22cSsudarsana.kalluru@cavium.com resource, bool b_is_permanent) 3641f470f22cSsudarsana.kalluru@cavium.com { 3642f470f22cSsudarsana.kalluru@cavium.com if (p_lock) { 3643f470f22cSsudarsana.kalluru@cavium.com memset(p_lock, 0, sizeof(*p_lock)); 3644f470f22cSsudarsana.kalluru@cavium.com 3645f470f22cSsudarsana.kalluru@cavium.com /* Permanent resources don't require aging, and there's no 3646f470f22cSsudarsana.kalluru@cavium.com * point in trying to acquire them more than once since it's 3647f470f22cSsudarsana.kalluru@cavium.com * unexpected another entity would release them. 3648f470f22cSsudarsana.kalluru@cavium.com */ 3649f470f22cSsudarsana.kalluru@cavium.com if (b_is_permanent) { 3650f470f22cSsudarsana.kalluru@cavium.com p_lock->timeout = QED_MCP_RESC_LOCK_TO_NONE; 3651f470f22cSsudarsana.kalluru@cavium.com } else { 3652f470f22cSsudarsana.kalluru@cavium.com p_lock->retry_num = QED_MCP_RESC_LOCK_RETRY_CNT_DFLT; 3653f470f22cSsudarsana.kalluru@cavium.com p_lock->retry_interval = 3654f470f22cSsudarsana.kalluru@cavium.com QED_MCP_RESC_LOCK_RETRY_VAL_DFLT; 3655f470f22cSsudarsana.kalluru@cavium.com p_lock->sleep_b4_retry = true; 3656f470f22cSsudarsana.kalluru@cavium.com } 3657f470f22cSsudarsana.kalluru@cavium.com 3658f470f22cSsudarsana.kalluru@cavium.com p_lock->resource = resource; 3659f470f22cSsudarsana.kalluru@cavium.com } 3660f470f22cSsudarsana.kalluru@cavium.com 3661f470f22cSsudarsana.kalluru@cavium.com if (p_unlock) { 3662f470f22cSsudarsana.kalluru@cavium.com memset(p_unlock, 0, sizeof(*p_unlock)); 3663f470f22cSsudarsana.kalluru@cavium.com p_unlock->resource = resource; 3664f470f22cSsudarsana.kalluru@cavium.com } 3665f470f22cSsudarsana.kalluru@cavium.com } 3666645874e5SSudarsana Reddy Kalluru 3667df9c716dSSudarsana Reddy Kalluru bool qed_mcp_is_smart_an_supported(struct qed_hwfn *p_hwfn) 3668df9c716dSSudarsana Reddy Kalluru { 3669df9c716dSSudarsana Reddy Kalluru return !!(p_hwfn->mcp_info->capabilities & 3670df9c716dSSudarsana Reddy Kalluru FW_MB_PARAM_FEATURE_SUPPORT_SMARTLINQ); 3671df9c716dSSudarsana Reddy Kalluru } 3672df9c716dSSudarsana Reddy Kalluru 3673645874e5SSudarsana Reddy Kalluru int qed_mcp_get_capabilities(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 3674645874e5SSudarsana Reddy Kalluru { 3675645874e5SSudarsana Reddy Kalluru u32 mcp_resp; 3676645874e5SSudarsana Reddy Kalluru int rc; 3677645874e5SSudarsana Reddy Kalluru 3678645874e5SSudarsana Reddy Kalluru rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_GET_MFW_FEATURE_SUPPORT, 3679645874e5SSudarsana Reddy Kalluru 0, &mcp_resp, &p_hwfn->mcp_info->capabilities); 3680645874e5SSudarsana Reddy Kalluru if (!rc) 3681645874e5SSudarsana Reddy Kalluru DP_VERBOSE(p_hwfn, (QED_MSG_SP | NETIF_MSG_PROBE), 3682645874e5SSudarsana Reddy Kalluru "MFW supported features: %08x\n", 3683645874e5SSudarsana Reddy Kalluru p_hwfn->mcp_info->capabilities); 3684645874e5SSudarsana Reddy Kalluru 3685645874e5SSudarsana Reddy Kalluru return rc; 3686645874e5SSudarsana Reddy Kalluru } 3687645874e5SSudarsana Reddy Kalluru 3688645874e5SSudarsana Reddy Kalluru int qed_mcp_set_capabilities(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 3689645874e5SSudarsana Reddy Kalluru { 3690645874e5SSudarsana Reddy Kalluru u32 mcp_resp, mcp_param, features; 3691645874e5SSudarsana Reddy Kalluru 3692e40a826aSSudarsana Reddy Kalluru features = DRV_MB_PARAM_FEATURE_SUPPORT_PORT_EEE | 3693e40a826aSSudarsana Reddy Kalluru DRV_MB_PARAM_FEATURE_SUPPORT_FUNC_VLINK; 3694645874e5SSudarsana Reddy Kalluru 3695645874e5SSudarsana Reddy Kalluru return qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_FEATURE_SUPPORT, 3696645874e5SSudarsana Reddy Kalluru features, &mcp_resp, &mcp_param); 3697645874e5SSudarsana Reddy Kalluru } 369879284adeSMichal Kalderon 369979284adeSMichal Kalderon int qed_mcp_get_engine_config(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 370079284adeSMichal Kalderon { 370179284adeSMichal Kalderon struct qed_mcp_mb_params mb_params = {0}; 370279284adeSMichal Kalderon struct qed_dev *cdev = p_hwfn->cdev; 370379284adeSMichal Kalderon u8 fir_valid, l2_valid; 370479284adeSMichal Kalderon int rc; 370579284adeSMichal Kalderon 370679284adeSMichal Kalderon mb_params.cmd = DRV_MSG_CODE_GET_ENGINE_CONFIG; 370779284adeSMichal Kalderon rc = qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 370879284adeSMichal Kalderon if (rc) 370979284adeSMichal Kalderon return rc; 371079284adeSMichal Kalderon 371179284adeSMichal Kalderon if (mb_params.mcp_resp == FW_MSG_CODE_UNSUPPORTED) { 371279284adeSMichal Kalderon DP_INFO(p_hwfn, 371379284adeSMichal Kalderon "The get_engine_config command is unsupported by the MFW\n"); 371479284adeSMichal Kalderon return -EOPNOTSUPP; 371579284adeSMichal Kalderon } 371679284adeSMichal Kalderon 371779284adeSMichal Kalderon fir_valid = QED_MFW_GET_FIELD(mb_params.mcp_param, 371879284adeSMichal Kalderon FW_MB_PARAM_ENG_CFG_FIR_AFFIN_VALID); 371979284adeSMichal Kalderon if (fir_valid) 372079284adeSMichal Kalderon cdev->fir_affin = 372179284adeSMichal Kalderon QED_MFW_GET_FIELD(mb_params.mcp_param, 372279284adeSMichal Kalderon FW_MB_PARAM_ENG_CFG_FIR_AFFIN_VALUE); 372379284adeSMichal Kalderon 372479284adeSMichal Kalderon l2_valid = QED_MFW_GET_FIELD(mb_params.mcp_param, 372579284adeSMichal Kalderon FW_MB_PARAM_ENG_CFG_L2_AFFIN_VALID); 372679284adeSMichal Kalderon if (l2_valid) 372779284adeSMichal Kalderon cdev->l2_affin_hint = 372879284adeSMichal Kalderon QED_MFW_GET_FIELD(mb_params.mcp_param, 372979284adeSMichal Kalderon FW_MB_PARAM_ENG_CFG_L2_AFFIN_VALUE); 373079284adeSMichal Kalderon 373179284adeSMichal Kalderon DP_INFO(p_hwfn, 373279284adeSMichal Kalderon "Engine affinity config: FIR={valid %hhd, value %hhd}, L2_hint={valid %hhd, value %hhd}\n", 373379284adeSMichal Kalderon fir_valid, cdev->fir_affin, l2_valid, cdev->l2_affin_hint); 373479284adeSMichal Kalderon 373579284adeSMichal Kalderon return 0; 373679284adeSMichal Kalderon } 373779284adeSMichal Kalderon 373879284adeSMichal Kalderon int qed_mcp_get_ppfid_bitmap(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 373979284adeSMichal Kalderon { 374079284adeSMichal Kalderon struct qed_mcp_mb_params mb_params = {0}; 374179284adeSMichal Kalderon struct qed_dev *cdev = p_hwfn->cdev; 374279284adeSMichal Kalderon int rc; 374379284adeSMichal Kalderon 374479284adeSMichal Kalderon mb_params.cmd = DRV_MSG_CODE_GET_PPFID_BITMAP; 374579284adeSMichal Kalderon rc = qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 374679284adeSMichal Kalderon if (rc) 374779284adeSMichal Kalderon return rc; 374879284adeSMichal Kalderon 374979284adeSMichal Kalderon if (mb_params.mcp_resp == FW_MSG_CODE_UNSUPPORTED) { 375079284adeSMichal Kalderon DP_INFO(p_hwfn, 375179284adeSMichal Kalderon "The get_ppfid_bitmap command is unsupported by the MFW\n"); 375279284adeSMichal Kalderon return -EOPNOTSUPP; 375379284adeSMichal Kalderon } 375479284adeSMichal Kalderon 375579284adeSMichal Kalderon cdev->ppfid_bitmap = QED_MFW_GET_FIELD(mb_params.mcp_param, 375679284adeSMichal Kalderon FW_MB_PARAM_PPFID_BITMAP); 375779284adeSMichal Kalderon 375879284adeSMichal Kalderon DP_VERBOSE(p_hwfn, QED_MSG_SP, "PPFID bitmap 0x%hhx\n", 375979284adeSMichal Kalderon cdev->ppfid_bitmap); 376079284adeSMichal Kalderon 376179284adeSMichal Kalderon return 0; 376279284adeSMichal Kalderon } 376338eabdf0SSudarsana Reddy Kalluru 37642d4c8495SSudarsana Reddy Kalluru int qed_mcp_nvm_get_cfg(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, 37652d4c8495SSudarsana Reddy Kalluru u16 option_id, u8 entity_id, u16 flags, u8 *p_buf, 37662d4c8495SSudarsana Reddy Kalluru u32 *p_len) 37672d4c8495SSudarsana Reddy Kalluru { 37682d4c8495SSudarsana Reddy Kalluru u32 mb_param = 0, resp, param; 37692d4c8495SSudarsana Reddy Kalluru int rc; 37702d4c8495SSudarsana Reddy Kalluru 37712d4c8495SSudarsana Reddy Kalluru QED_MFW_SET_FIELD(mb_param, DRV_MB_PARAM_NVM_CFG_OPTION_ID, option_id); 37722d4c8495SSudarsana Reddy Kalluru if (flags & QED_NVM_CFG_OPTION_INIT) 37732d4c8495SSudarsana Reddy Kalluru QED_MFW_SET_FIELD(mb_param, 37742d4c8495SSudarsana Reddy Kalluru DRV_MB_PARAM_NVM_CFG_OPTION_INIT, 1); 37752d4c8495SSudarsana Reddy Kalluru if (flags & QED_NVM_CFG_OPTION_FREE) 37762d4c8495SSudarsana Reddy Kalluru QED_MFW_SET_FIELD(mb_param, 37772d4c8495SSudarsana Reddy Kalluru DRV_MB_PARAM_NVM_CFG_OPTION_FREE, 1); 37782d4c8495SSudarsana Reddy Kalluru if (flags & QED_NVM_CFG_OPTION_ENTITY_SEL) { 37792d4c8495SSudarsana Reddy Kalluru QED_MFW_SET_FIELD(mb_param, 37802d4c8495SSudarsana Reddy Kalluru DRV_MB_PARAM_NVM_CFG_OPTION_ENTITY_SEL, 1); 37812d4c8495SSudarsana Reddy Kalluru QED_MFW_SET_FIELD(mb_param, 37822d4c8495SSudarsana Reddy Kalluru DRV_MB_PARAM_NVM_CFG_OPTION_ENTITY_ID, 37832d4c8495SSudarsana Reddy Kalluru entity_id); 37842d4c8495SSudarsana Reddy Kalluru } 37852d4c8495SSudarsana Reddy Kalluru 37862d4c8495SSudarsana Reddy Kalluru rc = qed_mcp_nvm_rd_cmd(p_hwfn, p_ptt, 37872d4c8495SSudarsana Reddy Kalluru DRV_MSG_CODE_GET_NVM_CFG_OPTION, 37882d4c8495SSudarsana Reddy Kalluru mb_param, &resp, ¶m, p_len, (u32 *)p_buf); 37892d4c8495SSudarsana Reddy Kalluru 37902d4c8495SSudarsana Reddy Kalluru return rc; 37912d4c8495SSudarsana Reddy Kalluru } 37922d4c8495SSudarsana Reddy Kalluru 379338eabdf0SSudarsana Reddy Kalluru int qed_mcp_nvm_set_cfg(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, 379438eabdf0SSudarsana Reddy Kalluru u16 option_id, u8 entity_id, u16 flags, u8 *p_buf, 379538eabdf0SSudarsana Reddy Kalluru u32 len) 379638eabdf0SSudarsana Reddy Kalluru { 379738eabdf0SSudarsana Reddy Kalluru u32 mb_param = 0, resp, param; 379838eabdf0SSudarsana Reddy Kalluru 379938eabdf0SSudarsana Reddy Kalluru QED_MFW_SET_FIELD(mb_param, DRV_MB_PARAM_NVM_CFG_OPTION_ID, option_id); 380038eabdf0SSudarsana Reddy Kalluru if (flags & QED_NVM_CFG_OPTION_ALL) 380138eabdf0SSudarsana Reddy Kalluru QED_MFW_SET_FIELD(mb_param, 380238eabdf0SSudarsana Reddy Kalluru DRV_MB_PARAM_NVM_CFG_OPTION_ALL, 1); 380338eabdf0SSudarsana Reddy Kalluru if (flags & QED_NVM_CFG_OPTION_INIT) 380438eabdf0SSudarsana Reddy Kalluru QED_MFW_SET_FIELD(mb_param, 380538eabdf0SSudarsana Reddy Kalluru DRV_MB_PARAM_NVM_CFG_OPTION_INIT, 1); 380638eabdf0SSudarsana Reddy Kalluru if (flags & QED_NVM_CFG_OPTION_COMMIT) 380738eabdf0SSudarsana Reddy Kalluru QED_MFW_SET_FIELD(mb_param, 380838eabdf0SSudarsana Reddy Kalluru DRV_MB_PARAM_NVM_CFG_OPTION_COMMIT, 1); 380938eabdf0SSudarsana Reddy Kalluru if (flags & QED_NVM_CFG_OPTION_FREE) 381038eabdf0SSudarsana Reddy Kalluru QED_MFW_SET_FIELD(mb_param, 381138eabdf0SSudarsana Reddy Kalluru DRV_MB_PARAM_NVM_CFG_OPTION_FREE, 1); 381238eabdf0SSudarsana Reddy Kalluru if (flags & QED_NVM_CFG_OPTION_ENTITY_SEL) { 381338eabdf0SSudarsana Reddy Kalluru QED_MFW_SET_FIELD(mb_param, 381438eabdf0SSudarsana Reddy Kalluru DRV_MB_PARAM_NVM_CFG_OPTION_ENTITY_SEL, 1); 381538eabdf0SSudarsana Reddy Kalluru QED_MFW_SET_FIELD(mb_param, 381638eabdf0SSudarsana Reddy Kalluru DRV_MB_PARAM_NVM_CFG_OPTION_ENTITY_ID, 381738eabdf0SSudarsana Reddy Kalluru entity_id); 381838eabdf0SSudarsana Reddy Kalluru } 381938eabdf0SSudarsana Reddy Kalluru 382038eabdf0SSudarsana Reddy Kalluru return qed_mcp_nvm_wr_cmd(p_hwfn, p_ptt, 382138eabdf0SSudarsana Reddy Kalluru DRV_MSG_CODE_SET_NVM_CFG_OPTION, 382238eabdf0SSudarsana Reddy Kalluru mb_param, &resp, ¶m, len, (u32 *)p_buf); 382338eabdf0SSudarsana Reddy Kalluru } 3824d8d6c5a7SIgor Russkikh 3825d8d6c5a7SIgor Russkikh #define QED_MCP_DBG_DATA_MAX_SIZE MCP_DRV_NVM_BUF_LEN 3826d8d6c5a7SIgor Russkikh #define QED_MCP_DBG_DATA_MAX_HEADER_SIZE sizeof(u32) 3827d8d6c5a7SIgor Russkikh #define QED_MCP_DBG_DATA_MAX_PAYLOAD_SIZE \ 3828d8d6c5a7SIgor Russkikh (QED_MCP_DBG_DATA_MAX_SIZE - QED_MCP_DBG_DATA_MAX_HEADER_SIZE) 3829d8d6c5a7SIgor Russkikh 3830d8d6c5a7SIgor Russkikh static int 3831d8d6c5a7SIgor Russkikh __qed_mcp_send_debug_data(struct qed_hwfn *p_hwfn, 3832d8d6c5a7SIgor Russkikh struct qed_ptt *p_ptt, u8 *p_buf, u8 size) 3833d8d6c5a7SIgor Russkikh { 3834d8d6c5a7SIgor Russkikh struct qed_mcp_mb_params mb_params; 3835d8d6c5a7SIgor Russkikh int rc; 3836d8d6c5a7SIgor Russkikh 3837d8d6c5a7SIgor Russkikh if (size > QED_MCP_DBG_DATA_MAX_SIZE) { 3838d8d6c5a7SIgor Russkikh DP_ERR(p_hwfn, 3839d8d6c5a7SIgor Russkikh "Debug data size is %d while it should not exceed %d\n", 3840d8d6c5a7SIgor Russkikh size, QED_MCP_DBG_DATA_MAX_SIZE); 3841d8d6c5a7SIgor Russkikh return -EINVAL; 3842d8d6c5a7SIgor Russkikh } 3843d8d6c5a7SIgor Russkikh 3844d8d6c5a7SIgor Russkikh memset(&mb_params, 0, sizeof(mb_params)); 3845d8d6c5a7SIgor Russkikh mb_params.cmd = DRV_MSG_CODE_DEBUG_DATA_SEND; 3846d8d6c5a7SIgor Russkikh SET_MFW_FIELD(mb_params.param, DRV_MSG_CODE_DEBUG_DATA_SEND_SIZE, size); 3847d8d6c5a7SIgor Russkikh mb_params.p_data_src = p_buf; 3848d8d6c5a7SIgor Russkikh mb_params.data_src_size = size; 3849d8d6c5a7SIgor Russkikh rc = qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 3850d8d6c5a7SIgor Russkikh if (rc) 3851d8d6c5a7SIgor Russkikh return rc; 3852d8d6c5a7SIgor Russkikh 3853d8d6c5a7SIgor Russkikh if (mb_params.mcp_resp == FW_MSG_CODE_UNSUPPORTED) { 3854d8d6c5a7SIgor Russkikh DP_INFO(p_hwfn, 3855d8d6c5a7SIgor Russkikh "The DEBUG_DATA_SEND command is unsupported by the MFW\n"); 3856d8d6c5a7SIgor Russkikh return -EOPNOTSUPP; 3857d8d6c5a7SIgor Russkikh } else if (mb_params.mcp_resp == (u32)FW_MSG_CODE_DEBUG_NOT_ENABLED) { 3858d8d6c5a7SIgor Russkikh DP_INFO(p_hwfn, "The DEBUG_DATA_SEND command is not enabled\n"); 3859d8d6c5a7SIgor Russkikh return -EBUSY; 3860d8d6c5a7SIgor Russkikh } else if (mb_params.mcp_resp != (u32)FW_MSG_CODE_DEBUG_DATA_SEND_OK) { 3861d8d6c5a7SIgor Russkikh DP_NOTICE(p_hwfn, 3862d8d6c5a7SIgor Russkikh "Failed to send debug data to the MFW [resp 0x%08x]\n", 3863d8d6c5a7SIgor Russkikh mb_params.mcp_resp); 3864d8d6c5a7SIgor Russkikh return -EINVAL; 3865d8d6c5a7SIgor Russkikh } 3866d8d6c5a7SIgor Russkikh 3867d8d6c5a7SIgor Russkikh return 0; 3868d8d6c5a7SIgor Russkikh } 3869d8d6c5a7SIgor Russkikh 3870d8d6c5a7SIgor Russkikh enum qed_mcp_dbg_data_type { 3871d8d6c5a7SIgor Russkikh QED_MCP_DBG_DATA_TYPE_RAW, 3872d8d6c5a7SIgor Russkikh }; 3873d8d6c5a7SIgor Russkikh 3874d8d6c5a7SIgor Russkikh /* Header format: [31:28] PFID, [27:20] flags, [19:12] type, [11:0] S/N */ 3875d8d6c5a7SIgor Russkikh #define QED_MCP_DBG_DATA_HDR_SN_OFFSET 0 3876d8d6c5a7SIgor Russkikh #define QED_MCP_DBG_DATA_HDR_SN_MASK 0x00000fff 3877d8d6c5a7SIgor Russkikh #define QED_MCP_DBG_DATA_HDR_TYPE_OFFSET 12 3878d8d6c5a7SIgor Russkikh #define QED_MCP_DBG_DATA_HDR_TYPE_MASK 0x000ff000 3879d8d6c5a7SIgor Russkikh #define QED_MCP_DBG_DATA_HDR_FLAGS_OFFSET 20 3880d8d6c5a7SIgor Russkikh #define QED_MCP_DBG_DATA_HDR_FLAGS_MASK 0x0ff00000 3881d8d6c5a7SIgor Russkikh #define QED_MCP_DBG_DATA_HDR_PF_OFFSET 28 3882d8d6c5a7SIgor Russkikh #define QED_MCP_DBG_DATA_HDR_PF_MASK 0xf0000000 3883d8d6c5a7SIgor Russkikh 3884d8d6c5a7SIgor Russkikh #define QED_MCP_DBG_DATA_HDR_FLAGS_FIRST 0x1 3885d8d6c5a7SIgor Russkikh #define QED_MCP_DBG_DATA_HDR_FLAGS_LAST 0x2 3886d8d6c5a7SIgor Russkikh 3887d8d6c5a7SIgor Russkikh static int 3888d8d6c5a7SIgor Russkikh qed_mcp_send_debug_data(struct qed_hwfn *p_hwfn, 3889d8d6c5a7SIgor Russkikh struct qed_ptt *p_ptt, 3890d8d6c5a7SIgor Russkikh enum qed_mcp_dbg_data_type type, u8 *p_buf, u32 size) 3891d8d6c5a7SIgor Russkikh { 3892d8d6c5a7SIgor Russkikh u8 raw_data[QED_MCP_DBG_DATA_MAX_SIZE], *p_tmp_buf = p_buf; 3893d8d6c5a7SIgor Russkikh u32 tmp_size = size, *p_header, *p_payload; 3894d8d6c5a7SIgor Russkikh u8 flags = 0; 3895d8d6c5a7SIgor Russkikh u16 seq; 3896d8d6c5a7SIgor Russkikh int rc; 3897d8d6c5a7SIgor Russkikh 3898d8d6c5a7SIgor Russkikh p_header = (u32 *)raw_data; 3899d8d6c5a7SIgor Russkikh p_payload = (u32 *)(raw_data + QED_MCP_DBG_DATA_MAX_HEADER_SIZE); 3900d8d6c5a7SIgor Russkikh 3901d8d6c5a7SIgor Russkikh seq = (u16)atomic_inc_return(&p_hwfn->mcp_info->dbg_data_seq); 3902d8d6c5a7SIgor Russkikh 3903d8d6c5a7SIgor Russkikh /* First chunk is marked as 'first' */ 3904d8d6c5a7SIgor Russkikh flags |= QED_MCP_DBG_DATA_HDR_FLAGS_FIRST; 3905d8d6c5a7SIgor Russkikh 3906d8d6c5a7SIgor Russkikh *p_header = 0; 3907d8d6c5a7SIgor Russkikh SET_MFW_FIELD(*p_header, QED_MCP_DBG_DATA_HDR_SN, seq); 3908d8d6c5a7SIgor Russkikh SET_MFW_FIELD(*p_header, QED_MCP_DBG_DATA_HDR_TYPE, type); 3909d8d6c5a7SIgor Russkikh SET_MFW_FIELD(*p_header, QED_MCP_DBG_DATA_HDR_FLAGS, flags); 3910d8d6c5a7SIgor Russkikh SET_MFW_FIELD(*p_header, QED_MCP_DBG_DATA_HDR_PF, p_hwfn->abs_pf_id); 3911d8d6c5a7SIgor Russkikh 3912d8d6c5a7SIgor Russkikh while (tmp_size > QED_MCP_DBG_DATA_MAX_PAYLOAD_SIZE) { 3913d8d6c5a7SIgor Russkikh memcpy(p_payload, p_tmp_buf, QED_MCP_DBG_DATA_MAX_PAYLOAD_SIZE); 3914d8d6c5a7SIgor Russkikh rc = __qed_mcp_send_debug_data(p_hwfn, p_ptt, raw_data, 3915d8d6c5a7SIgor Russkikh QED_MCP_DBG_DATA_MAX_SIZE); 3916d8d6c5a7SIgor Russkikh if (rc) 3917d8d6c5a7SIgor Russkikh return rc; 3918d8d6c5a7SIgor Russkikh 3919d8d6c5a7SIgor Russkikh /* Clear the 'first' marking after sending the first chunk */ 3920d8d6c5a7SIgor Russkikh if (p_tmp_buf == p_buf) { 3921d8d6c5a7SIgor Russkikh flags &= ~QED_MCP_DBG_DATA_HDR_FLAGS_FIRST; 3922d8d6c5a7SIgor Russkikh SET_MFW_FIELD(*p_header, QED_MCP_DBG_DATA_HDR_FLAGS, 3923d8d6c5a7SIgor Russkikh flags); 3924d8d6c5a7SIgor Russkikh } 3925d8d6c5a7SIgor Russkikh 3926d8d6c5a7SIgor Russkikh p_tmp_buf += QED_MCP_DBG_DATA_MAX_PAYLOAD_SIZE; 3927d8d6c5a7SIgor Russkikh tmp_size -= QED_MCP_DBG_DATA_MAX_PAYLOAD_SIZE; 3928d8d6c5a7SIgor Russkikh } 3929d8d6c5a7SIgor Russkikh 3930d8d6c5a7SIgor Russkikh /* Last chunk is marked as 'last' */ 3931d8d6c5a7SIgor Russkikh flags |= QED_MCP_DBG_DATA_HDR_FLAGS_LAST; 3932d8d6c5a7SIgor Russkikh SET_MFW_FIELD(*p_header, QED_MCP_DBG_DATA_HDR_FLAGS, flags); 3933d8d6c5a7SIgor Russkikh memcpy(p_payload, p_tmp_buf, tmp_size); 3934d8d6c5a7SIgor Russkikh 3935d8d6c5a7SIgor Russkikh /* Casting the left size to u8 is ok since at this point it is <= 32 */ 3936d8d6c5a7SIgor Russkikh return __qed_mcp_send_debug_data(p_hwfn, p_ptt, raw_data, 3937d8d6c5a7SIgor Russkikh (u8)(QED_MCP_DBG_DATA_MAX_HEADER_SIZE + 3938d8d6c5a7SIgor Russkikh tmp_size)); 3939d8d6c5a7SIgor Russkikh } 3940d8d6c5a7SIgor Russkikh 3941d8d6c5a7SIgor Russkikh int 3942d8d6c5a7SIgor Russkikh qed_mcp_send_raw_debug_data(struct qed_hwfn *p_hwfn, 3943d8d6c5a7SIgor Russkikh struct qed_ptt *p_ptt, u8 *p_buf, u32 size) 3944d8d6c5a7SIgor Russkikh { 3945d8d6c5a7SIgor Russkikh return qed_mcp_send_debug_data(p_hwfn, p_ptt, 3946d8d6c5a7SIgor Russkikh QED_MCP_DBG_DATA_TYPE_RAW, p_buf, size); 3947d8d6c5a7SIgor Russkikh } 3948