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 51eaa50fc5STomer Tayar #define QED_MCP_RESP_ITER_US 10 52fe56b9e6SYuval Mintz 53fe56b9e6SYuval Mintz #define QED_DRV_MB_MAX_RETRIES (500 * 1000) /* Account for 5 sec */ 54fe56b9e6SYuval Mintz #define QED_MCP_RESET_RETRIES (50 * 1000) /* Account for 500 msec */ 55fe56b9e6SYuval Mintz 56fe56b9e6SYuval Mintz #define DRV_INNER_WR(_p_hwfn, _p_ptt, _ptr, _offset, _val) \ 57fe56b9e6SYuval Mintz qed_wr(_p_hwfn, _p_ptt, (_p_hwfn->mcp_info->_ptr + _offset), \ 58fe56b9e6SYuval Mintz _val) 59fe56b9e6SYuval Mintz 60fe56b9e6SYuval Mintz #define DRV_INNER_RD(_p_hwfn, _p_ptt, _ptr, _offset) \ 61fe56b9e6SYuval Mintz qed_rd(_p_hwfn, _p_ptt, (_p_hwfn->mcp_info->_ptr + _offset)) 62fe56b9e6SYuval Mintz 63fe56b9e6SYuval Mintz #define DRV_MB_WR(_p_hwfn, _p_ptt, _field, _val) \ 64fe56b9e6SYuval Mintz DRV_INNER_WR(p_hwfn, _p_ptt, drv_mb_addr, \ 65fe56b9e6SYuval Mintz offsetof(struct public_drv_mb, _field), _val) 66fe56b9e6SYuval Mintz 67fe56b9e6SYuval Mintz #define DRV_MB_RD(_p_hwfn, _p_ptt, _field) \ 68fe56b9e6SYuval Mintz DRV_INNER_RD(_p_hwfn, _p_ptt, drv_mb_addr, \ 69fe56b9e6SYuval Mintz offsetof(struct public_drv_mb, _field)) 70fe56b9e6SYuval Mintz 71fe56b9e6SYuval Mintz #define PDA_COMP (((FW_MAJOR_VERSION) + (FW_MINOR_VERSION << 8)) << \ 72fe56b9e6SYuval Mintz DRV_ID_PDA_COMP_VER_SHIFT) 73fe56b9e6SYuval Mintz 74fe56b9e6SYuval Mintz #define MCP_BYTES_PER_MBIT_SHIFT 17 75fe56b9e6SYuval Mintz 76fe56b9e6SYuval Mintz bool qed_mcp_is_init(struct qed_hwfn *p_hwfn) 77fe56b9e6SYuval Mintz { 78fe56b9e6SYuval Mintz if (!p_hwfn->mcp_info || !p_hwfn->mcp_info->public_base) 79fe56b9e6SYuval Mintz return false; 80fe56b9e6SYuval Mintz return true; 81fe56b9e6SYuval Mintz } 82fe56b9e6SYuval Mintz 831a635e48SYuval Mintz void qed_mcp_cmd_port_init(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 84fe56b9e6SYuval Mintz { 85fe56b9e6SYuval Mintz u32 addr = SECTION_OFFSIZE_ADDR(p_hwfn->mcp_info->public_base, 86fe56b9e6SYuval Mintz PUBLIC_PORT); 87fe56b9e6SYuval Mintz u32 mfw_mb_offsize = qed_rd(p_hwfn, p_ptt, addr); 88fe56b9e6SYuval Mintz 89fe56b9e6SYuval Mintz p_hwfn->mcp_info->port_addr = SECTION_ADDR(mfw_mb_offsize, 90fe56b9e6SYuval Mintz MFW_PORT(p_hwfn)); 91fe56b9e6SYuval Mintz DP_VERBOSE(p_hwfn, QED_MSG_SP, 92fe56b9e6SYuval Mintz "port_addr = 0x%x, port_id 0x%02x\n", 93fe56b9e6SYuval Mintz p_hwfn->mcp_info->port_addr, MFW_PORT(p_hwfn)); 94fe56b9e6SYuval Mintz } 95fe56b9e6SYuval Mintz 961a635e48SYuval Mintz void qed_mcp_read_mb(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 97fe56b9e6SYuval Mintz { 98fe56b9e6SYuval Mintz u32 length = MFW_DRV_MSG_MAX_DWORDS(p_hwfn->mcp_info->mfw_mb_length); 99fe56b9e6SYuval Mintz u32 tmp, i; 100fe56b9e6SYuval Mintz 101fe56b9e6SYuval Mintz if (!p_hwfn->mcp_info->public_base) 102fe56b9e6SYuval Mintz return; 103fe56b9e6SYuval Mintz 104fe56b9e6SYuval Mintz for (i = 0; i < length; i++) { 105fe56b9e6SYuval Mintz tmp = qed_rd(p_hwfn, p_ptt, 106fe56b9e6SYuval Mintz p_hwfn->mcp_info->mfw_mb_addr + 107fe56b9e6SYuval Mintz (i << 2) + sizeof(u32)); 108fe56b9e6SYuval Mintz 109fe56b9e6SYuval Mintz /* The MB data is actually BE; Need to force it to cpu */ 110fe56b9e6SYuval Mintz ((u32 *)p_hwfn->mcp_info->mfw_mb_cur)[i] = 111fe56b9e6SYuval Mintz be32_to_cpu((__force __be32)tmp); 112fe56b9e6SYuval Mintz } 113fe56b9e6SYuval Mintz } 114fe56b9e6SYuval Mintz 1154ed1eea8STomer Tayar struct qed_mcp_cmd_elem { 1164ed1eea8STomer Tayar struct list_head list; 1174ed1eea8STomer Tayar struct qed_mcp_mb_params *p_mb_params; 1184ed1eea8STomer Tayar u16 expected_seq_num; 1194ed1eea8STomer Tayar bool b_is_completed; 1204ed1eea8STomer Tayar }; 1214ed1eea8STomer Tayar 1224ed1eea8STomer Tayar /* Must be called while cmd_lock is acquired */ 1234ed1eea8STomer Tayar static struct qed_mcp_cmd_elem * 1244ed1eea8STomer Tayar qed_mcp_cmd_add_elem(struct qed_hwfn *p_hwfn, 1254ed1eea8STomer Tayar struct qed_mcp_mb_params *p_mb_params, 1264ed1eea8STomer Tayar u16 expected_seq_num) 1274ed1eea8STomer Tayar { 1284ed1eea8STomer Tayar struct qed_mcp_cmd_elem *p_cmd_elem = NULL; 1294ed1eea8STomer Tayar 1304ed1eea8STomer Tayar p_cmd_elem = kzalloc(sizeof(*p_cmd_elem), GFP_ATOMIC); 1314ed1eea8STomer Tayar if (!p_cmd_elem) 1324ed1eea8STomer Tayar goto out; 1334ed1eea8STomer Tayar 1344ed1eea8STomer Tayar p_cmd_elem->p_mb_params = p_mb_params; 1354ed1eea8STomer Tayar p_cmd_elem->expected_seq_num = expected_seq_num; 1364ed1eea8STomer Tayar list_add(&p_cmd_elem->list, &p_hwfn->mcp_info->cmd_list); 1374ed1eea8STomer Tayar out: 1384ed1eea8STomer Tayar return p_cmd_elem; 1394ed1eea8STomer Tayar } 1404ed1eea8STomer Tayar 1414ed1eea8STomer Tayar /* Must be called while cmd_lock is acquired */ 1424ed1eea8STomer Tayar static void qed_mcp_cmd_del_elem(struct qed_hwfn *p_hwfn, 1434ed1eea8STomer Tayar struct qed_mcp_cmd_elem *p_cmd_elem) 1444ed1eea8STomer Tayar { 1454ed1eea8STomer Tayar list_del(&p_cmd_elem->list); 1464ed1eea8STomer Tayar kfree(p_cmd_elem); 1474ed1eea8STomer Tayar } 1484ed1eea8STomer Tayar 1494ed1eea8STomer Tayar /* Must be called while cmd_lock is acquired */ 1504ed1eea8STomer Tayar static struct qed_mcp_cmd_elem *qed_mcp_cmd_get_elem(struct qed_hwfn *p_hwfn, 1514ed1eea8STomer Tayar u16 seq_num) 1524ed1eea8STomer Tayar { 1534ed1eea8STomer Tayar struct qed_mcp_cmd_elem *p_cmd_elem = NULL; 1544ed1eea8STomer Tayar 1554ed1eea8STomer Tayar list_for_each_entry(p_cmd_elem, &p_hwfn->mcp_info->cmd_list, list) { 1564ed1eea8STomer Tayar if (p_cmd_elem->expected_seq_num == seq_num) 1574ed1eea8STomer Tayar return p_cmd_elem; 1584ed1eea8STomer Tayar } 1594ed1eea8STomer Tayar 1604ed1eea8STomer Tayar return NULL; 1614ed1eea8STomer Tayar } 1624ed1eea8STomer Tayar 163fe56b9e6SYuval Mintz int qed_mcp_free(struct qed_hwfn *p_hwfn) 164fe56b9e6SYuval Mintz { 165fe56b9e6SYuval Mintz if (p_hwfn->mcp_info) { 1664ed1eea8STomer Tayar struct qed_mcp_cmd_elem *p_cmd_elem, *p_tmp; 1674ed1eea8STomer Tayar 168fe56b9e6SYuval Mintz kfree(p_hwfn->mcp_info->mfw_mb_cur); 169fe56b9e6SYuval Mintz kfree(p_hwfn->mcp_info->mfw_mb_shadow); 1704ed1eea8STomer Tayar 1714ed1eea8STomer Tayar spin_lock_bh(&p_hwfn->mcp_info->cmd_lock); 1724ed1eea8STomer Tayar list_for_each_entry_safe(p_cmd_elem, 1734ed1eea8STomer Tayar p_tmp, 1744ed1eea8STomer Tayar &p_hwfn->mcp_info->cmd_list, list) { 1754ed1eea8STomer Tayar qed_mcp_cmd_del_elem(p_hwfn, p_cmd_elem); 176fe56b9e6SYuval Mintz } 1774ed1eea8STomer Tayar spin_unlock_bh(&p_hwfn->mcp_info->cmd_lock); 1784ed1eea8STomer Tayar } 1794ed1eea8STomer Tayar 180fe56b9e6SYuval Mintz kfree(p_hwfn->mcp_info); 1813587cb87STomer Tayar p_hwfn->mcp_info = NULL; 182fe56b9e6SYuval Mintz 183fe56b9e6SYuval Mintz return 0; 184fe56b9e6SYuval Mintz } 185fe56b9e6SYuval Mintz 186f00d25f3STomer Tayar /* Maximum of 1 sec to wait for the SHMEM ready indication */ 187f00d25f3STomer Tayar #define QED_MCP_SHMEM_RDY_MAX_RETRIES 20 188f00d25f3STomer Tayar #define QED_MCP_SHMEM_RDY_ITER_MS 50 189f00d25f3STomer Tayar 1901a635e48SYuval Mintz static int qed_load_mcp_offsets(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 191fe56b9e6SYuval Mintz { 192fe56b9e6SYuval Mintz struct qed_mcp_info *p_info = p_hwfn->mcp_info; 193f00d25f3STomer Tayar u8 cnt = QED_MCP_SHMEM_RDY_MAX_RETRIES; 194f00d25f3STomer Tayar u8 msec = QED_MCP_SHMEM_RDY_ITER_MS; 195fe56b9e6SYuval Mintz u32 drv_mb_offsize, mfw_mb_offsize; 196fe56b9e6SYuval Mintz u32 mcp_pf_id = MCP_PF_ID(p_hwfn); 197fe56b9e6SYuval Mintz 198fe56b9e6SYuval Mintz p_info->public_base = qed_rd(p_hwfn, p_ptt, MISC_REG_SHARED_MEM_ADDR); 199f00d25f3STomer Tayar if (!p_info->public_base) { 200f00d25f3STomer Tayar DP_NOTICE(p_hwfn, 201f00d25f3STomer Tayar "The address of the MCP scratch-pad is not configured\n"); 202f00d25f3STomer Tayar return -EINVAL; 203f00d25f3STomer Tayar } 204fe56b9e6SYuval Mintz 205fe56b9e6SYuval Mintz p_info->public_base |= GRCBASE_MCP; 206fe56b9e6SYuval Mintz 207f00d25f3STomer Tayar /* Get the MFW MB address and number of supported messages */ 208f00d25f3STomer Tayar mfw_mb_offsize = qed_rd(p_hwfn, p_ptt, 209f00d25f3STomer Tayar SECTION_OFFSIZE_ADDR(p_info->public_base, 210f00d25f3STomer Tayar PUBLIC_MFW_MB)); 211f00d25f3STomer Tayar p_info->mfw_mb_addr = SECTION_ADDR(mfw_mb_offsize, mcp_pf_id); 212f00d25f3STomer Tayar p_info->mfw_mb_length = (u16)qed_rd(p_hwfn, p_ptt, 213f00d25f3STomer Tayar p_info->mfw_mb_addr + 214f00d25f3STomer Tayar offsetof(struct public_mfw_mb, 215f00d25f3STomer Tayar sup_msgs)); 216f00d25f3STomer Tayar 217f00d25f3STomer Tayar /* The driver can notify that there was an MCP reset, and might read the 218f00d25f3STomer Tayar * SHMEM values before the MFW has completed initializing them. 219f00d25f3STomer Tayar * To avoid this, the "sup_msgs" field in the MFW mailbox is used as a 220f00d25f3STomer Tayar * data ready indication. 221f00d25f3STomer Tayar */ 222f00d25f3STomer Tayar while (!p_info->mfw_mb_length && --cnt) { 223f00d25f3STomer Tayar msleep(msec); 224f00d25f3STomer Tayar p_info->mfw_mb_length = 225f00d25f3STomer Tayar (u16)qed_rd(p_hwfn, p_ptt, 226f00d25f3STomer Tayar p_info->mfw_mb_addr + 227f00d25f3STomer Tayar offsetof(struct public_mfw_mb, sup_msgs)); 228f00d25f3STomer Tayar } 229f00d25f3STomer Tayar 230f00d25f3STomer Tayar if (!cnt) { 231f00d25f3STomer Tayar DP_NOTICE(p_hwfn, 232f00d25f3STomer Tayar "Failed to get the SHMEM ready notification after %d msec\n", 233f00d25f3STomer Tayar QED_MCP_SHMEM_RDY_MAX_RETRIES * msec); 234f00d25f3STomer Tayar return -EBUSY; 235f00d25f3STomer Tayar } 236f00d25f3STomer Tayar 237fe56b9e6SYuval Mintz /* Calculate the driver and MFW mailbox address */ 238fe56b9e6SYuval Mintz drv_mb_offsize = qed_rd(p_hwfn, p_ptt, 239fe56b9e6SYuval Mintz SECTION_OFFSIZE_ADDR(p_info->public_base, 240fe56b9e6SYuval Mintz PUBLIC_DRV_MB)); 241fe56b9e6SYuval Mintz p_info->drv_mb_addr = SECTION_ADDR(drv_mb_offsize, mcp_pf_id); 242fe56b9e6SYuval Mintz DP_VERBOSE(p_hwfn, QED_MSG_SP, 243fe56b9e6SYuval Mintz "drv_mb_offsiz = 0x%x, drv_mb_addr = 0x%x mcp_pf_id = 0x%x\n", 244fe56b9e6SYuval Mintz drv_mb_offsize, p_info->drv_mb_addr, mcp_pf_id); 245fe56b9e6SYuval Mintz 246fe56b9e6SYuval Mintz /* Get the current driver mailbox sequence before sending 247fe56b9e6SYuval Mintz * the first command 248fe56b9e6SYuval Mintz */ 249fe56b9e6SYuval Mintz p_info->drv_mb_seq = DRV_MB_RD(p_hwfn, p_ptt, drv_mb_header) & 250fe56b9e6SYuval Mintz DRV_MSG_SEQ_NUMBER_MASK; 251fe56b9e6SYuval Mintz 252fe56b9e6SYuval Mintz /* Get current FW pulse sequence */ 253fe56b9e6SYuval Mintz p_info->drv_pulse_seq = DRV_MB_RD(p_hwfn, p_ptt, drv_pulse_mb) & 254fe56b9e6SYuval Mintz DRV_PULSE_SEQ_MASK; 255fe56b9e6SYuval Mintz 2564ed1eea8STomer Tayar p_info->mcp_hist = qed_rd(p_hwfn, p_ptt, MISCS_REG_GENERIC_POR_0); 257fe56b9e6SYuval Mintz 258fe56b9e6SYuval Mintz return 0; 259fe56b9e6SYuval Mintz } 260fe56b9e6SYuval Mintz 2611a635e48SYuval Mintz int qed_mcp_cmd_init(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 262fe56b9e6SYuval Mintz { 263fe56b9e6SYuval Mintz struct qed_mcp_info *p_info; 264fe56b9e6SYuval Mintz u32 size; 265fe56b9e6SYuval Mintz 266fe56b9e6SYuval Mintz /* Allocate mcp_info structure */ 26760fffb3bSYuval Mintz p_hwfn->mcp_info = kzalloc(sizeof(*p_hwfn->mcp_info), GFP_KERNEL); 268fe56b9e6SYuval Mintz if (!p_hwfn->mcp_info) 269fe56b9e6SYuval Mintz goto err; 270fe56b9e6SYuval Mintz p_info = p_hwfn->mcp_info; 271fe56b9e6SYuval Mintz 2724ed1eea8STomer Tayar /* Initialize the MFW spinlock */ 2734ed1eea8STomer Tayar spin_lock_init(&p_info->cmd_lock); 2744ed1eea8STomer Tayar spin_lock_init(&p_info->link_lock); 2754ed1eea8STomer Tayar 2764ed1eea8STomer Tayar INIT_LIST_HEAD(&p_info->cmd_list); 2774ed1eea8STomer Tayar 278fe56b9e6SYuval Mintz if (qed_load_mcp_offsets(p_hwfn, p_ptt) != 0) { 279fe56b9e6SYuval Mintz DP_NOTICE(p_hwfn, "MCP is not initialized\n"); 280fe56b9e6SYuval Mintz /* Do not free mcp_info here, since public_base indicate that 281fe56b9e6SYuval Mintz * the MCP is not initialized 282fe56b9e6SYuval Mintz */ 283fe56b9e6SYuval Mintz return 0; 284fe56b9e6SYuval Mintz } 285fe56b9e6SYuval Mintz 286fe56b9e6SYuval Mintz size = MFW_DRV_MSG_MAX_DWORDS(p_info->mfw_mb_length) * sizeof(u32); 28760fffb3bSYuval Mintz p_info->mfw_mb_cur = kzalloc(size, GFP_KERNEL); 28883aeb933SYuval Mintz p_info->mfw_mb_shadow = kzalloc(size, GFP_KERNEL); 289eb2a6b80SChristophe Jaillet if (!p_info->mfw_mb_cur || !p_info->mfw_mb_shadow) 290fe56b9e6SYuval Mintz goto err; 291fe56b9e6SYuval Mintz 292fe56b9e6SYuval Mintz return 0; 293fe56b9e6SYuval Mintz 294fe56b9e6SYuval Mintz err: 295fe56b9e6SYuval Mintz qed_mcp_free(p_hwfn); 296fe56b9e6SYuval Mintz return -ENOMEM; 297fe56b9e6SYuval Mintz } 298fe56b9e6SYuval Mintz 2994ed1eea8STomer Tayar static void qed_mcp_reread_offsets(struct qed_hwfn *p_hwfn, 3004ed1eea8STomer Tayar struct qed_ptt *p_ptt) 3015529bad9STomer Tayar { 3024ed1eea8STomer Tayar u32 generic_por_0 = qed_rd(p_hwfn, p_ptt, MISCS_REG_GENERIC_POR_0); 3035529bad9STomer Tayar 3044ed1eea8STomer Tayar /* Use MCP history register to check if MCP reset occurred between init 3054ed1eea8STomer Tayar * time and now. 3065529bad9STomer Tayar */ 3074ed1eea8STomer Tayar if (p_hwfn->mcp_info->mcp_hist != generic_por_0) { 3084ed1eea8STomer Tayar DP_VERBOSE(p_hwfn, 3094ed1eea8STomer Tayar QED_MSG_SP, 3104ed1eea8STomer Tayar "Rereading MCP offsets [mcp_hist 0x%08x, generic_por_0 0x%08x]\n", 3114ed1eea8STomer Tayar p_hwfn->mcp_info->mcp_hist, generic_por_0); 3125529bad9STomer Tayar 3134ed1eea8STomer Tayar qed_load_mcp_offsets(p_hwfn, p_ptt); 3144ed1eea8STomer Tayar qed_mcp_cmd_port_init(p_hwfn, p_ptt); 3155529bad9STomer Tayar } 3165529bad9STomer Tayar } 3175529bad9STomer Tayar 3181a635e48SYuval Mintz int qed_mcp_reset(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 319fe56b9e6SYuval Mintz { 320eaa50fc5STomer Tayar u32 org_mcp_reset_seq, seq, delay = QED_MCP_RESP_ITER_US, cnt = 0; 321fe56b9e6SYuval Mintz int rc = 0; 322fe56b9e6SYuval Mintz 323b310974eSTomer Tayar if (p_hwfn->mcp_info->b_block_cmd) { 324b310974eSTomer Tayar DP_NOTICE(p_hwfn, 325b310974eSTomer Tayar "The MFW is not responsive. Avoid sending MCP_RESET mailbox command.\n"); 326b310974eSTomer Tayar return -EBUSY; 327b310974eSTomer Tayar } 328b310974eSTomer Tayar 3294ed1eea8STomer Tayar /* Ensure that only a single thread is accessing the mailbox */ 3304ed1eea8STomer Tayar spin_lock_bh(&p_hwfn->mcp_info->cmd_lock); 3314ed1eea8STomer Tayar 3324ed1eea8STomer Tayar org_mcp_reset_seq = qed_rd(p_hwfn, p_ptt, MISCS_REG_GENERIC_POR_0); 3335529bad9STomer Tayar 334fe56b9e6SYuval Mintz /* Set drv command along with the updated sequence */ 3354ed1eea8STomer Tayar qed_mcp_reread_offsets(p_hwfn, p_ptt); 3364ed1eea8STomer Tayar seq = ++p_hwfn->mcp_info->drv_mb_seq; 3374ed1eea8STomer Tayar DRV_MB_WR(p_hwfn, p_ptt, drv_mb_header, (DRV_MSG_CODE_MCP_RESET | seq)); 338fe56b9e6SYuval Mintz 339fe56b9e6SYuval Mintz do { 340fe56b9e6SYuval Mintz /* Wait for MFW response */ 341fe56b9e6SYuval Mintz udelay(delay); 342fe56b9e6SYuval Mintz /* Give the FW up to 500 second (50*1000*10usec) */ 343fe56b9e6SYuval Mintz } while ((org_mcp_reset_seq == qed_rd(p_hwfn, p_ptt, 344fe56b9e6SYuval Mintz MISCS_REG_GENERIC_POR_0)) && 345fe56b9e6SYuval Mintz (cnt++ < QED_MCP_RESET_RETRIES)); 346fe56b9e6SYuval Mintz 347fe56b9e6SYuval Mintz if (org_mcp_reset_seq != 348fe56b9e6SYuval Mintz qed_rd(p_hwfn, p_ptt, MISCS_REG_GENERIC_POR_0)) { 349fe56b9e6SYuval Mintz DP_VERBOSE(p_hwfn, QED_MSG_SP, 350fe56b9e6SYuval Mintz "MCP was reset after %d usec\n", cnt * delay); 351fe56b9e6SYuval Mintz } else { 352fe56b9e6SYuval Mintz DP_ERR(p_hwfn, "Failed to reset MCP\n"); 353fe56b9e6SYuval Mintz rc = -EAGAIN; 354fe56b9e6SYuval Mintz } 355fe56b9e6SYuval Mintz 3564ed1eea8STomer Tayar spin_unlock_bh(&p_hwfn->mcp_info->cmd_lock); 3575529bad9STomer Tayar 358fe56b9e6SYuval Mintz return rc; 359fe56b9e6SYuval Mintz } 360fe56b9e6SYuval Mintz 3614ed1eea8STomer Tayar /* Must be called while cmd_lock is acquired */ 3624ed1eea8STomer Tayar static bool qed_mcp_has_pending_cmd(struct qed_hwfn *p_hwfn) 363fe56b9e6SYuval Mintz { 3644ed1eea8STomer Tayar struct qed_mcp_cmd_elem *p_cmd_elem; 3654ed1eea8STomer Tayar 3664ed1eea8STomer Tayar /* There is at most one pending command at a certain time, and if it 3674ed1eea8STomer Tayar * exists - it is placed at the HEAD of the list. 3684ed1eea8STomer Tayar */ 3694ed1eea8STomer Tayar if (!list_empty(&p_hwfn->mcp_info->cmd_list)) { 3704ed1eea8STomer Tayar p_cmd_elem = list_first_entry(&p_hwfn->mcp_info->cmd_list, 3714ed1eea8STomer Tayar struct qed_mcp_cmd_elem, list); 3724ed1eea8STomer Tayar return !p_cmd_elem->b_is_completed; 3734ed1eea8STomer Tayar } 3744ed1eea8STomer Tayar 3754ed1eea8STomer Tayar return false; 3764ed1eea8STomer Tayar } 3774ed1eea8STomer Tayar 3784ed1eea8STomer Tayar /* Must be called while cmd_lock is acquired */ 3794ed1eea8STomer Tayar static int 3804ed1eea8STomer Tayar qed_mcp_update_pending_cmd(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 3814ed1eea8STomer Tayar { 3824ed1eea8STomer Tayar struct qed_mcp_mb_params *p_mb_params; 3834ed1eea8STomer Tayar struct qed_mcp_cmd_elem *p_cmd_elem; 3844ed1eea8STomer Tayar u32 mcp_resp; 3854ed1eea8STomer Tayar u16 seq_num; 3864ed1eea8STomer Tayar 3874ed1eea8STomer Tayar mcp_resp = DRV_MB_RD(p_hwfn, p_ptt, fw_mb_header); 3884ed1eea8STomer Tayar seq_num = (u16)(mcp_resp & FW_MSG_SEQ_NUMBER_MASK); 3894ed1eea8STomer Tayar 3904ed1eea8STomer Tayar /* Return if no new non-handled response has been received */ 3914ed1eea8STomer Tayar if (seq_num != p_hwfn->mcp_info->drv_mb_seq) 3924ed1eea8STomer Tayar return -EAGAIN; 3934ed1eea8STomer Tayar 3944ed1eea8STomer Tayar p_cmd_elem = qed_mcp_cmd_get_elem(p_hwfn, seq_num); 3954ed1eea8STomer Tayar if (!p_cmd_elem) { 3964ed1eea8STomer Tayar DP_ERR(p_hwfn, 3974ed1eea8STomer Tayar "Failed to find a pending mailbox cmd that expects sequence number %d\n", 3984ed1eea8STomer Tayar seq_num); 3994ed1eea8STomer Tayar return -EINVAL; 4004ed1eea8STomer Tayar } 4014ed1eea8STomer Tayar 4024ed1eea8STomer Tayar p_mb_params = p_cmd_elem->p_mb_params; 4034ed1eea8STomer Tayar 4044ed1eea8STomer Tayar /* Get the MFW response along with the sequence number */ 4054ed1eea8STomer Tayar p_mb_params->mcp_resp = mcp_resp; 4064ed1eea8STomer Tayar 4074ed1eea8STomer Tayar /* Get the MFW param */ 4084ed1eea8STomer Tayar p_mb_params->mcp_param = DRV_MB_RD(p_hwfn, p_ptt, fw_mb_param); 4094ed1eea8STomer Tayar 4104ed1eea8STomer Tayar /* Get the union data */ 4112f67af8cSTomer Tayar if (p_mb_params->p_data_dst != NULL && p_mb_params->data_dst_size) { 4124ed1eea8STomer Tayar u32 union_data_addr = p_hwfn->mcp_info->drv_mb_addr + 4134ed1eea8STomer Tayar offsetof(struct public_drv_mb, 4144ed1eea8STomer Tayar union_data); 4154ed1eea8STomer Tayar qed_memcpy_from(p_hwfn, p_ptt, p_mb_params->p_data_dst, 4162f67af8cSTomer Tayar union_data_addr, p_mb_params->data_dst_size); 4174ed1eea8STomer Tayar } 4184ed1eea8STomer Tayar 4194ed1eea8STomer Tayar p_cmd_elem->b_is_completed = true; 4204ed1eea8STomer Tayar 4214ed1eea8STomer Tayar return 0; 4224ed1eea8STomer Tayar } 4234ed1eea8STomer Tayar 4244ed1eea8STomer Tayar /* Must be called while cmd_lock is acquired */ 4254ed1eea8STomer Tayar static void __qed_mcp_cmd_and_union(struct qed_hwfn *p_hwfn, 4264ed1eea8STomer Tayar struct qed_ptt *p_ptt, 4274ed1eea8STomer Tayar struct qed_mcp_mb_params *p_mb_params, 4284ed1eea8STomer Tayar u16 seq_num) 4294ed1eea8STomer Tayar { 4304ed1eea8STomer Tayar union drv_union_data union_data; 4314ed1eea8STomer Tayar u32 union_data_addr; 4324ed1eea8STomer Tayar 4334ed1eea8STomer Tayar /* Set the union data */ 4344ed1eea8STomer Tayar union_data_addr = p_hwfn->mcp_info->drv_mb_addr + 4354ed1eea8STomer Tayar offsetof(struct public_drv_mb, union_data); 4364ed1eea8STomer Tayar memset(&union_data, 0, sizeof(union_data)); 4372f67af8cSTomer Tayar if (p_mb_params->p_data_src != NULL && p_mb_params->data_src_size) 4384ed1eea8STomer Tayar memcpy(&union_data, p_mb_params->p_data_src, 4392f67af8cSTomer Tayar p_mb_params->data_src_size); 4404ed1eea8STomer Tayar qed_memcpy_to(p_hwfn, p_ptt, union_data_addr, &union_data, 4414ed1eea8STomer Tayar sizeof(union_data)); 4424ed1eea8STomer Tayar 4434ed1eea8STomer Tayar /* Set the drv param */ 4444ed1eea8STomer Tayar DRV_MB_WR(p_hwfn, p_ptt, drv_mb_param, p_mb_params->param); 4454ed1eea8STomer Tayar 4464ed1eea8STomer Tayar /* Set the drv command along with the sequence number */ 4474ed1eea8STomer Tayar DRV_MB_WR(p_hwfn, p_ptt, drv_mb_header, (p_mb_params->cmd | seq_num)); 4484ed1eea8STomer Tayar 4494ed1eea8STomer Tayar DP_VERBOSE(p_hwfn, QED_MSG_SP, 4504ed1eea8STomer Tayar "MFW mailbox: command 0x%08x param 0x%08x\n", 4514ed1eea8STomer Tayar (p_mb_params->cmd | seq_num), p_mb_params->param); 4524ed1eea8STomer Tayar } 4534ed1eea8STomer Tayar 454b310974eSTomer Tayar static void qed_mcp_cmd_set_blocking(struct qed_hwfn *p_hwfn, bool block_cmd) 455b310974eSTomer Tayar { 456b310974eSTomer Tayar p_hwfn->mcp_info->b_block_cmd = block_cmd; 457b310974eSTomer Tayar 458b310974eSTomer Tayar DP_INFO(p_hwfn, "%s sending of mailbox commands to the MFW\n", 459b310974eSTomer Tayar block_cmd ? "Block" : "Unblock"); 460b310974eSTomer Tayar } 461b310974eSTomer Tayar 462b310974eSTomer Tayar static void qed_mcp_print_cpu_info(struct qed_hwfn *p_hwfn, 463b310974eSTomer Tayar struct qed_ptt *p_ptt) 464b310974eSTomer Tayar { 465b310974eSTomer Tayar u32 cpu_mode, cpu_state, cpu_pc_0, cpu_pc_1, cpu_pc_2; 466b310974eSTomer Tayar u32 delay = QED_MCP_RESP_ITER_US; 467b310974eSTomer Tayar 468b310974eSTomer Tayar cpu_mode = qed_rd(p_hwfn, p_ptt, MCP_REG_CPU_MODE); 469b310974eSTomer Tayar cpu_state = qed_rd(p_hwfn, p_ptt, MCP_REG_CPU_STATE); 470b310974eSTomer Tayar cpu_pc_0 = qed_rd(p_hwfn, p_ptt, MCP_REG_CPU_PROGRAM_COUNTER); 471b310974eSTomer Tayar udelay(delay); 472b310974eSTomer Tayar cpu_pc_1 = qed_rd(p_hwfn, p_ptt, MCP_REG_CPU_PROGRAM_COUNTER); 473b310974eSTomer Tayar udelay(delay); 474b310974eSTomer Tayar cpu_pc_2 = qed_rd(p_hwfn, p_ptt, MCP_REG_CPU_PROGRAM_COUNTER); 475b310974eSTomer Tayar 476b310974eSTomer Tayar DP_NOTICE(p_hwfn, 477b310974eSTomer Tayar "MCP CPU info: mode 0x%08x, state 0x%08x, pc {0x%08x, 0x%08x, 0x%08x}\n", 478b310974eSTomer Tayar cpu_mode, cpu_state, cpu_pc_0, cpu_pc_1, cpu_pc_2); 479b310974eSTomer Tayar } 480b310974eSTomer Tayar 4814ed1eea8STomer Tayar static int 4824ed1eea8STomer Tayar _qed_mcp_cmd_and_union(struct qed_hwfn *p_hwfn, 4834ed1eea8STomer Tayar struct qed_ptt *p_ptt, 4844ed1eea8STomer Tayar struct qed_mcp_mb_params *p_mb_params, 485eaa50fc5STomer Tayar u32 max_retries, u32 usecs) 4864ed1eea8STomer Tayar { 487eaa50fc5STomer Tayar u32 cnt = 0, msecs = DIV_ROUND_UP(usecs, 1000); 4884ed1eea8STomer Tayar struct qed_mcp_cmd_elem *p_cmd_elem; 4894ed1eea8STomer Tayar u16 seq_num; 490fe56b9e6SYuval Mintz int rc = 0; 491fe56b9e6SYuval Mintz 4924ed1eea8STomer Tayar /* Wait until the mailbox is non-occupied */ 493fe56b9e6SYuval Mintz do { 4944ed1eea8STomer Tayar /* Exit the loop if there is no pending command, or if the 4954ed1eea8STomer Tayar * pending command is completed during this iteration. 4964ed1eea8STomer Tayar * The spinlock stays locked until the command is sent. 4974ed1eea8STomer Tayar */ 4984ed1eea8STomer Tayar 4994ed1eea8STomer Tayar spin_lock_bh(&p_hwfn->mcp_info->cmd_lock); 5004ed1eea8STomer Tayar 5014ed1eea8STomer Tayar if (!qed_mcp_has_pending_cmd(p_hwfn)) 5024ed1eea8STomer Tayar break; 5034ed1eea8STomer Tayar 5044ed1eea8STomer Tayar rc = qed_mcp_update_pending_cmd(p_hwfn, p_ptt); 5054ed1eea8STomer Tayar if (!rc) 5064ed1eea8STomer Tayar break; 5074ed1eea8STomer Tayar else if (rc != -EAGAIN) 5084ed1eea8STomer Tayar goto err; 5094ed1eea8STomer Tayar 5104ed1eea8STomer Tayar spin_unlock_bh(&p_hwfn->mcp_info->cmd_lock); 511eaa50fc5STomer Tayar 512eaa50fc5STomer Tayar if (QED_MB_FLAGS_IS_SET(p_mb_params, CAN_SLEEP)) 513eaa50fc5STomer Tayar msleep(msecs); 514eaa50fc5STomer Tayar else 515eaa50fc5STomer Tayar udelay(usecs); 5164ed1eea8STomer Tayar } while (++cnt < max_retries); 517fe56b9e6SYuval Mintz 5184ed1eea8STomer Tayar if (cnt >= max_retries) { 5194ed1eea8STomer Tayar DP_NOTICE(p_hwfn, 5204ed1eea8STomer Tayar "The MFW mailbox is occupied by an uncompleted command. Failed to send command 0x%08x [param 0x%08x].\n", 5214ed1eea8STomer Tayar p_mb_params->cmd, p_mb_params->param); 5224ed1eea8STomer Tayar return -EAGAIN; 523fe56b9e6SYuval Mintz } 5244ed1eea8STomer Tayar 5254ed1eea8STomer Tayar /* Send the mailbox command */ 5264ed1eea8STomer Tayar qed_mcp_reread_offsets(p_hwfn, p_ptt); 5274ed1eea8STomer Tayar seq_num = ++p_hwfn->mcp_info->drv_mb_seq; 5284ed1eea8STomer Tayar p_cmd_elem = qed_mcp_cmd_add_elem(p_hwfn, p_mb_params, seq_num); 529c8004600SDan Carpenter if (!p_cmd_elem) { 530c8004600SDan Carpenter rc = -ENOMEM; 5314ed1eea8STomer Tayar goto err; 532c8004600SDan Carpenter } 5334ed1eea8STomer Tayar 5344ed1eea8STomer Tayar __qed_mcp_cmd_and_union(p_hwfn, p_ptt, p_mb_params, seq_num); 5354ed1eea8STomer Tayar spin_unlock_bh(&p_hwfn->mcp_info->cmd_lock); 5364ed1eea8STomer Tayar 5374ed1eea8STomer Tayar /* Wait for the MFW response */ 5384ed1eea8STomer Tayar do { 5394ed1eea8STomer Tayar /* Exit the loop if the command is already completed, or if the 5404ed1eea8STomer Tayar * command is completed during this iteration. 5414ed1eea8STomer Tayar * The spinlock stays locked until the list element is removed. 5424ed1eea8STomer Tayar */ 5434ed1eea8STomer Tayar 544eaa50fc5STomer Tayar if (QED_MB_FLAGS_IS_SET(p_mb_params, CAN_SLEEP)) 545eaa50fc5STomer Tayar msleep(msecs); 546eaa50fc5STomer Tayar else 547eaa50fc5STomer Tayar udelay(usecs); 548eaa50fc5STomer Tayar 5494ed1eea8STomer Tayar spin_lock_bh(&p_hwfn->mcp_info->cmd_lock); 5504ed1eea8STomer Tayar 5514ed1eea8STomer Tayar if (p_cmd_elem->b_is_completed) 5524ed1eea8STomer Tayar break; 5534ed1eea8STomer Tayar 5544ed1eea8STomer Tayar rc = qed_mcp_update_pending_cmd(p_hwfn, p_ptt); 5554ed1eea8STomer Tayar if (!rc) 5564ed1eea8STomer Tayar break; 5574ed1eea8STomer Tayar else if (rc != -EAGAIN) 5584ed1eea8STomer Tayar goto err; 5594ed1eea8STomer Tayar 5604ed1eea8STomer Tayar spin_unlock_bh(&p_hwfn->mcp_info->cmd_lock); 5614ed1eea8STomer Tayar } while (++cnt < max_retries); 5624ed1eea8STomer Tayar 5634ed1eea8STomer Tayar if (cnt >= max_retries) { 5644ed1eea8STomer Tayar DP_NOTICE(p_hwfn, 5654ed1eea8STomer Tayar "The MFW failed to respond to command 0x%08x [param 0x%08x].\n", 5664ed1eea8STomer Tayar p_mb_params->cmd, p_mb_params->param); 567b310974eSTomer Tayar qed_mcp_print_cpu_info(p_hwfn, p_ptt); 5684ed1eea8STomer Tayar 5694ed1eea8STomer Tayar spin_lock_bh(&p_hwfn->mcp_info->cmd_lock); 5704ed1eea8STomer Tayar qed_mcp_cmd_del_elem(p_hwfn, p_cmd_elem); 5714ed1eea8STomer Tayar spin_unlock_bh(&p_hwfn->mcp_info->cmd_lock); 5724ed1eea8STomer Tayar 573b310974eSTomer Tayar if (!QED_MB_FLAGS_IS_SET(p_mb_params, AVOID_BLOCK)) 574b310974eSTomer Tayar qed_mcp_cmd_set_blocking(p_hwfn, true); 575b310974eSTomer Tayar 5764ed1eea8STomer Tayar return -EAGAIN; 5774ed1eea8STomer Tayar } 5784ed1eea8STomer Tayar 5794ed1eea8STomer Tayar qed_mcp_cmd_del_elem(p_hwfn, p_cmd_elem); 5804ed1eea8STomer Tayar spin_unlock_bh(&p_hwfn->mcp_info->cmd_lock); 5814ed1eea8STomer Tayar 5824ed1eea8STomer Tayar DP_VERBOSE(p_hwfn, 5834ed1eea8STomer Tayar QED_MSG_SP, 5844ed1eea8STomer Tayar "MFW mailbox: response 0x%08x param 0x%08x [after %d.%03d ms]\n", 5854ed1eea8STomer Tayar p_mb_params->mcp_resp, 5864ed1eea8STomer Tayar p_mb_params->mcp_param, 587eaa50fc5STomer Tayar (cnt * usecs) / 1000, (cnt * usecs) % 1000); 5884ed1eea8STomer Tayar 5894ed1eea8STomer Tayar /* Clear the sequence number from the MFW response */ 5904ed1eea8STomer Tayar p_mb_params->mcp_resp &= FW_MSG_CODE_MASK; 5914ed1eea8STomer Tayar 5924ed1eea8STomer Tayar return 0; 5934ed1eea8STomer Tayar 5944ed1eea8STomer Tayar err: 5954ed1eea8STomer Tayar spin_unlock_bh(&p_hwfn->mcp_info->cmd_lock); 596fe56b9e6SYuval Mintz return rc; 597fe56b9e6SYuval Mintz } 598fe56b9e6SYuval Mintz 5995529bad9STomer Tayar static int qed_mcp_cmd_and_union(struct qed_hwfn *p_hwfn, 600fe56b9e6SYuval Mintz struct qed_ptt *p_ptt, 6015529bad9STomer Tayar struct qed_mcp_mb_params *p_mb_params) 602fe56b9e6SYuval Mintz { 6032f67af8cSTomer Tayar size_t union_data_size = sizeof(union drv_union_data); 6044ed1eea8STomer Tayar u32 max_retries = QED_DRV_MB_MAX_RETRIES; 605eaa50fc5STomer Tayar u32 usecs = QED_MCP_RESP_ITER_US; 606fe56b9e6SYuval Mintz 607fe56b9e6SYuval Mintz /* MCP not initialized */ 608fe56b9e6SYuval Mintz if (!qed_mcp_is_init(p_hwfn)) { 609fe56b9e6SYuval Mintz DP_NOTICE(p_hwfn, "MFW is not initialized!\n"); 610fe56b9e6SYuval Mintz return -EBUSY; 611fe56b9e6SYuval Mintz } 612fe56b9e6SYuval Mintz 613b310974eSTomer Tayar if (p_hwfn->mcp_info->b_block_cmd) { 614b310974eSTomer Tayar DP_NOTICE(p_hwfn, 615b310974eSTomer Tayar "The MFW is not responsive. Avoid sending mailbox command 0x%08x [param 0x%08x].\n", 616b310974eSTomer Tayar p_mb_params->cmd, p_mb_params->param); 617b310974eSTomer Tayar return -EBUSY; 618b310974eSTomer Tayar } 619b310974eSTomer Tayar 6202f67af8cSTomer Tayar if (p_mb_params->data_src_size > union_data_size || 6212f67af8cSTomer Tayar p_mb_params->data_dst_size > union_data_size) { 6222f67af8cSTomer Tayar DP_ERR(p_hwfn, 6232f67af8cSTomer Tayar "The provided size is larger than the union data size [src_size %u, dst_size %u, union_data_size %zu]\n", 6242f67af8cSTomer Tayar p_mb_params->data_src_size, 6252f67af8cSTomer Tayar p_mb_params->data_dst_size, union_data_size); 6262f67af8cSTomer Tayar return -EINVAL; 6272f67af8cSTomer Tayar } 6282f67af8cSTomer Tayar 629eaa50fc5STomer Tayar if (QED_MB_FLAGS_IS_SET(p_mb_params, CAN_SLEEP)) { 630eaa50fc5STomer Tayar max_retries = DIV_ROUND_UP(max_retries, 1000); 631eaa50fc5STomer Tayar usecs *= 1000; 632eaa50fc5STomer Tayar } 633eaa50fc5STomer Tayar 6344ed1eea8STomer Tayar return _qed_mcp_cmd_and_union(p_hwfn, p_ptt, p_mb_params, max_retries, 635eaa50fc5STomer Tayar usecs); 636fe56b9e6SYuval Mintz } 637fe56b9e6SYuval Mintz 6385529bad9STomer Tayar int qed_mcp_cmd(struct qed_hwfn *p_hwfn, 6395529bad9STomer Tayar struct qed_ptt *p_ptt, 6405529bad9STomer Tayar u32 cmd, 6415529bad9STomer Tayar u32 param, 6425529bad9STomer Tayar u32 *o_mcp_resp, 6435529bad9STomer Tayar u32 *o_mcp_param) 644fe56b9e6SYuval Mintz { 6455529bad9STomer Tayar struct qed_mcp_mb_params mb_params; 6465529bad9STomer Tayar int rc; 647fe56b9e6SYuval Mintz 6485529bad9STomer Tayar memset(&mb_params, 0, sizeof(mb_params)); 6495529bad9STomer Tayar mb_params.cmd = cmd; 6505529bad9STomer Tayar mb_params.param = param; 65114d39648SMintz, Yuval 6525529bad9STomer Tayar rc = qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 6535529bad9STomer Tayar if (rc) 6545529bad9STomer Tayar return rc; 6555529bad9STomer Tayar 6565529bad9STomer Tayar *o_mcp_resp = mb_params.mcp_resp; 6575529bad9STomer Tayar *o_mcp_param = mb_params.mcp_param; 6585529bad9STomer Tayar 6595529bad9STomer Tayar return 0; 660fe56b9e6SYuval Mintz } 661fe56b9e6SYuval Mintz 662bf774d14SYueHaibing static int 663bf774d14SYueHaibing qed_mcp_nvm_wr_cmd(struct qed_hwfn *p_hwfn, 66462e4d438SSudarsana Reddy Kalluru struct qed_ptt *p_ptt, 66562e4d438SSudarsana Reddy Kalluru u32 cmd, 66662e4d438SSudarsana Reddy Kalluru u32 param, 66762e4d438SSudarsana Reddy Kalluru u32 *o_mcp_resp, 66862e4d438SSudarsana Reddy Kalluru u32 *o_mcp_param, u32 i_txn_size, u32 *i_buf) 66962e4d438SSudarsana Reddy Kalluru { 67062e4d438SSudarsana Reddy Kalluru struct qed_mcp_mb_params mb_params; 67162e4d438SSudarsana Reddy Kalluru int rc; 67262e4d438SSudarsana Reddy Kalluru 67362e4d438SSudarsana Reddy Kalluru memset(&mb_params, 0, sizeof(mb_params)); 67462e4d438SSudarsana Reddy Kalluru mb_params.cmd = cmd; 67562e4d438SSudarsana Reddy Kalluru mb_params.param = param; 67662e4d438SSudarsana Reddy Kalluru mb_params.p_data_src = i_buf; 67762e4d438SSudarsana Reddy Kalluru mb_params.data_src_size = (u8)i_txn_size; 67862e4d438SSudarsana Reddy Kalluru rc = qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 67962e4d438SSudarsana Reddy Kalluru if (rc) 68062e4d438SSudarsana Reddy Kalluru return rc; 68162e4d438SSudarsana Reddy Kalluru 68262e4d438SSudarsana Reddy Kalluru *o_mcp_resp = mb_params.mcp_resp; 68362e4d438SSudarsana Reddy Kalluru *o_mcp_param = mb_params.mcp_param; 68462e4d438SSudarsana Reddy Kalluru 6855e7ba042SDenis Bolotin /* nvm_info needs to be updated */ 6865e7ba042SDenis Bolotin p_hwfn->nvm_info.valid = false; 6875e7ba042SDenis Bolotin 68862e4d438SSudarsana Reddy Kalluru return 0; 68962e4d438SSudarsana Reddy Kalluru } 69062e4d438SSudarsana Reddy Kalluru 6914102426fSTomer Tayar int qed_mcp_nvm_rd_cmd(struct qed_hwfn *p_hwfn, 6924102426fSTomer Tayar struct qed_ptt *p_ptt, 6934102426fSTomer Tayar u32 cmd, 6944102426fSTomer Tayar u32 param, 6954102426fSTomer Tayar u32 *o_mcp_resp, 6964102426fSTomer Tayar u32 *o_mcp_param, u32 *o_txn_size, u32 *o_buf) 6974102426fSTomer Tayar { 6984102426fSTomer Tayar struct qed_mcp_mb_params mb_params; 6992f67af8cSTomer Tayar u8 raw_data[MCP_DRV_NVM_BUF_LEN]; 7004102426fSTomer Tayar int rc; 7014102426fSTomer Tayar 7024102426fSTomer Tayar memset(&mb_params, 0, sizeof(mb_params)); 7034102426fSTomer Tayar mb_params.cmd = cmd; 7044102426fSTomer Tayar mb_params.param = param; 7052f67af8cSTomer Tayar mb_params.p_data_dst = raw_data; 7062f67af8cSTomer Tayar 7072f67af8cSTomer Tayar /* Use the maximal value since the actual one is part of the response */ 7082f67af8cSTomer Tayar mb_params.data_dst_size = MCP_DRV_NVM_BUF_LEN; 7092f67af8cSTomer Tayar 7104102426fSTomer Tayar rc = qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 7114102426fSTomer Tayar if (rc) 7124102426fSTomer Tayar return rc; 7134102426fSTomer Tayar 7144102426fSTomer Tayar *o_mcp_resp = mb_params.mcp_resp; 7154102426fSTomer Tayar *o_mcp_param = mb_params.mcp_param; 7164102426fSTomer Tayar 7174102426fSTomer Tayar *o_txn_size = *o_mcp_param; 7182f67af8cSTomer Tayar memcpy(o_buf, raw_data, *o_txn_size); 7194102426fSTomer Tayar 7204102426fSTomer Tayar return 0; 7214102426fSTomer Tayar } 7224102426fSTomer Tayar 7235d24bcf1STomer Tayar static bool 7245d24bcf1STomer Tayar qed_mcp_can_force_load(u8 drv_role, 7255d24bcf1STomer Tayar u8 exist_drv_role, 7265d24bcf1STomer Tayar enum qed_override_force_load override_force_load) 727fe56b9e6SYuval Mintz { 7285d24bcf1STomer Tayar bool can_force_load = false; 7295d24bcf1STomer Tayar 7305d24bcf1STomer Tayar switch (override_force_load) { 7315d24bcf1STomer Tayar case QED_OVERRIDE_FORCE_LOAD_ALWAYS: 7325d24bcf1STomer Tayar can_force_load = true; 7335d24bcf1STomer Tayar break; 7345d24bcf1STomer Tayar case QED_OVERRIDE_FORCE_LOAD_NEVER: 7355d24bcf1STomer Tayar can_force_load = false; 7365d24bcf1STomer Tayar break; 7375d24bcf1STomer Tayar default: 7385d24bcf1STomer Tayar can_force_load = (drv_role == DRV_ROLE_OS && 7395d24bcf1STomer Tayar exist_drv_role == DRV_ROLE_PREBOOT) || 7405d24bcf1STomer Tayar (drv_role == DRV_ROLE_KDUMP && 7415d24bcf1STomer Tayar exist_drv_role == DRV_ROLE_OS); 7425d24bcf1STomer Tayar break; 7435d24bcf1STomer Tayar } 7445d24bcf1STomer Tayar 7455d24bcf1STomer Tayar return can_force_load; 7465d24bcf1STomer Tayar } 7475d24bcf1STomer Tayar 7485d24bcf1STomer Tayar static int qed_mcp_cancel_load_req(struct qed_hwfn *p_hwfn, 7495d24bcf1STomer Tayar struct qed_ptt *p_ptt) 7505d24bcf1STomer Tayar { 7515d24bcf1STomer Tayar u32 resp = 0, param = 0; 752fe56b9e6SYuval Mintz int rc; 753fe56b9e6SYuval Mintz 7545d24bcf1STomer Tayar rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_CANCEL_LOAD_REQ, 0, 7555d24bcf1STomer Tayar &resp, ¶m); 7565d24bcf1STomer Tayar if (rc) 7575d24bcf1STomer Tayar DP_NOTICE(p_hwfn, 7585d24bcf1STomer Tayar "Failed to send cancel load request, rc = %d\n", rc); 759fe56b9e6SYuval Mintz 760fe56b9e6SYuval Mintz return rc; 761fe56b9e6SYuval Mintz } 762fe56b9e6SYuval Mintz 7635d24bcf1STomer Tayar #define CONFIG_QEDE_BITMAP_IDX BIT(0) 7645d24bcf1STomer Tayar #define CONFIG_QED_SRIOV_BITMAP_IDX BIT(1) 7655d24bcf1STomer Tayar #define CONFIG_QEDR_BITMAP_IDX BIT(2) 7665d24bcf1STomer Tayar #define CONFIG_QEDF_BITMAP_IDX BIT(4) 7675d24bcf1STomer Tayar #define CONFIG_QEDI_BITMAP_IDX BIT(5) 7685d24bcf1STomer Tayar #define CONFIG_QED_LL2_BITMAP_IDX BIT(6) 7695529bad9STomer Tayar 7705d24bcf1STomer Tayar static u32 qed_get_config_bitmap(void) 7715d24bcf1STomer Tayar { 7725d24bcf1STomer Tayar u32 config_bitmap = 0x0; 7735d24bcf1STomer Tayar 7745d24bcf1STomer Tayar if (IS_ENABLED(CONFIG_QEDE)) 7755d24bcf1STomer Tayar config_bitmap |= CONFIG_QEDE_BITMAP_IDX; 7765d24bcf1STomer Tayar 7775d24bcf1STomer Tayar if (IS_ENABLED(CONFIG_QED_SRIOV)) 7785d24bcf1STomer Tayar config_bitmap |= CONFIG_QED_SRIOV_BITMAP_IDX; 7795d24bcf1STomer Tayar 7805d24bcf1STomer Tayar if (IS_ENABLED(CONFIG_QED_RDMA)) 7815d24bcf1STomer Tayar config_bitmap |= CONFIG_QEDR_BITMAP_IDX; 7825d24bcf1STomer Tayar 7835d24bcf1STomer Tayar if (IS_ENABLED(CONFIG_QED_FCOE)) 7845d24bcf1STomer Tayar config_bitmap |= CONFIG_QEDF_BITMAP_IDX; 7855d24bcf1STomer Tayar 7865d24bcf1STomer Tayar if (IS_ENABLED(CONFIG_QED_ISCSI)) 7875d24bcf1STomer Tayar config_bitmap |= CONFIG_QEDI_BITMAP_IDX; 7885d24bcf1STomer Tayar 7895d24bcf1STomer Tayar if (IS_ENABLED(CONFIG_QED_LL2)) 7905d24bcf1STomer Tayar config_bitmap |= CONFIG_QED_LL2_BITMAP_IDX; 7915d24bcf1STomer Tayar 7925d24bcf1STomer Tayar return config_bitmap; 7935d24bcf1STomer Tayar } 7945d24bcf1STomer Tayar 7955d24bcf1STomer Tayar struct qed_load_req_in_params { 7965d24bcf1STomer Tayar u8 hsi_ver; 7975d24bcf1STomer Tayar #define QED_LOAD_REQ_HSI_VER_DEFAULT 0 7985d24bcf1STomer Tayar #define QED_LOAD_REQ_HSI_VER_1 1 7995d24bcf1STomer Tayar u32 drv_ver_0; 8005d24bcf1STomer Tayar u32 drv_ver_1; 8015d24bcf1STomer Tayar u32 fw_ver; 8025d24bcf1STomer Tayar u8 drv_role; 8035d24bcf1STomer Tayar u8 timeout_val; 8045d24bcf1STomer Tayar u8 force_cmd; 8055d24bcf1STomer Tayar bool avoid_eng_reset; 8065d24bcf1STomer Tayar }; 8075d24bcf1STomer Tayar 8085d24bcf1STomer Tayar struct qed_load_req_out_params { 8095d24bcf1STomer Tayar u32 load_code; 8105d24bcf1STomer Tayar u32 exist_drv_ver_0; 8115d24bcf1STomer Tayar u32 exist_drv_ver_1; 8125d24bcf1STomer Tayar u32 exist_fw_ver; 8135d24bcf1STomer Tayar u8 exist_drv_role; 8145d24bcf1STomer Tayar u8 mfw_hsi_ver; 8155d24bcf1STomer Tayar bool drv_exists; 8165d24bcf1STomer Tayar }; 8175d24bcf1STomer Tayar 8185d24bcf1STomer Tayar static int 8195d24bcf1STomer Tayar __qed_mcp_load_req(struct qed_hwfn *p_hwfn, 8205d24bcf1STomer Tayar struct qed_ptt *p_ptt, 8215d24bcf1STomer Tayar struct qed_load_req_in_params *p_in_params, 8225d24bcf1STomer Tayar struct qed_load_req_out_params *p_out_params) 8235d24bcf1STomer Tayar { 8245d24bcf1STomer Tayar struct qed_mcp_mb_params mb_params; 8255d24bcf1STomer Tayar struct load_req_stc load_req; 8265d24bcf1STomer Tayar struct load_rsp_stc load_rsp; 8275d24bcf1STomer Tayar u32 hsi_ver; 8285d24bcf1STomer Tayar int rc; 8295d24bcf1STomer Tayar 8305d24bcf1STomer Tayar memset(&load_req, 0, sizeof(load_req)); 8315d24bcf1STomer Tayar load_req.drv_ver_0 = p_in_params->drv_ver_0; 8325d24bcf1STomer Tayar load_req.drv_ver_1 = p_in_params->drv_ver_1; 8335d24bcf1STomer Tayar load_req.fw_ver = p_in_params->fw_ver; 8345d24bcf1STomer Tayar QED_MFW_SET_FIELD(load_req.misc0, LOAD_REQ_ROLE, p_in_params->drv_role); 8355d24bcf1STomer Tayar QED_MFW_SET_FIELD(load_req.misc0, LOAD_REQ_LOCK_TO, 8365d24bcf1STomer Tayar p_in_params->timeout_val); 8375d24bcf1STomer Tayar QED_MFW_SET_FIELD(load_req.misc0, LOAD_REQ_FORCE, 8385d24bcf1STomer Tayar p_in_params->force_cmd); 8395d24bcf1STomer Tayar QED_MFW_SET_FIELD(load_req.misc0, LOAD_REQ_FLAGS0, 8405d24bcf1STomer Tayar p_in_params->avoid_eng_reset); 8415d24bcf1STomer Tayar 8425d24bcf1STomer Tayar hsi_ver = (p_in_params->hsi_ver == QED_LOAD_REQ_HSI_VER_DEFAULT) ? 8435d24bcf1STomer Tayar DRV_ID_MCP_HSI_VER_CURRENT : 8445d24bcf1STomer Tayar (p_in_params->hsi_ver << DRV_ID_MCP_HSI_VER_SHIFT); 8455d24bcf1STomer Tayar 8465d24bcf1STomer Tayar memset(&mb_params, 0, sizeof(mb_params)); 8475d24bcf1STomer Tayar mb_params.cmd = DRV_MSG_CODE_LOAD_REQ; 8485d24bcf1STomer Tayar mb_params.param = PDA_COMP | hsi_ver | p_hwfn->cdev->drv_type; 8495d24bcf1STomer Tayar mb_params.p_data_src = &load_req; 8505d24bcf1STomer Tayar mb_params.data_src_size = sizeof(load_req); 8515d24bcf1STomer Tayar mb_params.p_data_dst = &load_rsp; 8525d24bcf1STomer Tayar mb_params.data_dst_size = sizeof(load_rsp); 853b310974eSTomer Tayar mb_params.flags = QED_MB_FLAG_CAN_SLEEP | QED_MB_FLAG_AVOID_BLOCK; 8545d24bcf1STomer Tayar 8555d24bcf1STomer Tayar DP_VERBOSE(p_hwfn, QED_MSG_SP, 8565d24bcf1STomer Tayar "Load Request: param 0x%08x [init_hw %d, drv_type %d, hsi_ver %d, pda 0x%04x]\n", 8575d24bcf1STomer Tayar mb_params.param, 8585d24bcf1STomer Tayar QED_MFW_GET_FIELD(mb_params.param, DRV_ID_DRV_INIT_HW), 8595d24bcf1STomer Tayar QED_MFW_GET_FIELD(mb_params.param, DRV_ID_DRV_TYPE), 8605d24bcf1STomer Tayar QED_MFW_GET_FIELD(mb_params.param, DRV_ID_MCP_HSI_VER), 8615d24bcf1STomer Tayar QED_MFW_GET_FIELD(mb_params.param, DRV_ID_PDA_COMP_VER)); 8625d24bcf1STomer Tayar 8635d24bcf1STomer Tayar if (p_in_params->hsi_ver != QED_LOAD_REQ_HSI_VER_1) { 8645d24bcf1STomer Tayar DP_VERBOSE(p_hwfn, QED_MSG_SP, 8655d24bcf1STomer 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", 8665d24bcf1STomer Tayar load_req.drv_ver_0, 8675d24bcf1STomer Tayar load_req.drv_ver_1, 8685d24bcf1STomer Tayar load_req.fw_ver, 8695d24bcf1STomer Tayar load_req.misc0, 8705d24bcf1STomer Tayar QED_MFW_GET_FIELD(load_req.misc0, LOAD_REQ_ROLE), 8715d24bcf1STomer Tayar QED_MFW_GET_FIELD(load_req.misc0, 8725d24bcf1STomer Tayar LOAD_REQ_LOCK_TO), 8735d24bcf1STomer Tayar QED_MFW_GET_FIELD(load_req.misc0, LOAD_REQ_FORCE), 8745d24bcf1STomer Tayar QED_MFW_GET_FIELD(load_req.misc0, LOAD_REQ_FLAGS0)); 8755d24bcf1STomer Tayar } 8765d24bcf1STomer Tayar 8775d24bcf1STomer Tayar rc = qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 8785d24bcf1STomer Tayar if (rc) { 8795d24bcf1STomer Tayar DP_NOTICE(p_hwfn, "Failed to send load request, rc = %d\n", rc); 8805d24bcf1STomer Tayar return rc; 8815d24bcf1STomer Tayar } 8825d24bcf1STomer Tayar 8835d24bcf1STomer Tayar DP_VERBOSE(p_hwfn, QED_MSG_SP, 8845d24bcf1STomer Tayar "Load Response: resp 0x%08x\n", mb_params.mcp_resp); 8855d24bcf1STomer Tayar p_out_params->load_code = mb_params.mcp_resp; 8865d24bcf1STomer Tayar 8875d24bcf1STomer Tayar if (p_in_params->hsi_ver != QED_LOAD_REQ_HSI_VER_1 && 8885d24bcf1STomer Tayar p_out_params->load_code != FW_MSG_CODE_DRV_LOAD_REFUSED_HSI_1) { 8895d24bcf1STomer Tayar DP_VERBOSE(p_hwfn, 8905d24bcf1STomer Tayar QED_MSG_SP, 8915d24bcf1STomer 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", 8925d24bcf1STomer Tayar load_rsp.drv_ver_0, 8935d24bcf1STomer Tayar load_rsp.drv_ver_1, 8945d24bcf1STomer Tayar load_rsp.fw_ver, 8955d24bcf1STomer Tayar load_rsp.misc0, 8965d24bcf1STomer Tayar QED_MFW_GET_FIELD(load_rsp.misc0, LOAD_RSP_ROLE), 8975d24bcf1STomer Tayar QED_MFW_GET_FIELD(load_rsp.misc0, LOAD_RSP_HSI), 8985d24bcf1STomer Tayar QED_MFW_GET_FIELD(load_rsp.misc0, LOAD_RSP_FLAGS0)); 8995d24bcf1STomer Tayar 9005d24bcf1STomer Tayar p_out_params->exist_drv_ver_0 = load_rsp.drv_ver_0; 9015d24bcf1STomer Tayar p_out_params->exist_drv_ver_1 = load_rsp.drv_ver_1; 9025d24bcf1STomer Tayar p_out_params->exist_fw_ver = load_rsp.fw_ver; 9035d24bcf1STomer Tayar p_out_params->exist_drv_role = 9045d24bcf1STomer Tayar QED_MFW_GET_FIELD(load_rsp.misc0, LOAD_RSP_ROLE); 9055d24bcf1STomer Tayar p_out_params->mfw_hsi_ver = 9065d24bcf1STomer Tayar QED_MFW_GET_FIELD(load_rsp.misc0, LOAD_RSP_HSI); 9075d24bcf1STomer Tayar p_out_params->drv_exists = 9085d24bcf1STomer Tayar QED_MFW_GET_FIELD(load_rsp.misc0, LOAD_RSP_FLAGS0) & 9095d24bcf1STomer Tayar LOAD_RSP_FLAGS0_DRV_EXISTS; 9105d24bcf1STomer Tayar } 9115d24bcf1STomer Tayar 9125d24bcf1STomer Tayar return 0; 9135d24bcf1STomer Tayar } 9145d24bcf1STomer Tayar 9155d24bcf1STomer Tayar static int eocre_get_mfw_drv_role(struct qed_hwfn *p_hwfn, 9165d24bcf1STomer Tayar enum qed_drv_role drv_role, 9175d24bcf1STomer Tayar u8 *p_mfw_drv_role) 9185d24bcf1STomer Tayar { 9195d24bcf1STomer Tayar switch (drv_role) { 9205d24bcf1STomer Tayar case QED_DRV_ROLE_OS: 9215d24bcf1STomer Tayar *p_mfw_drv_role = DRV_ROLE_OS; 9225d24bcf1STomer Tayar break; 9235d24bcf1STomer Tayar case QED_DRV_ROLE_KDUMP: 9245d24bcf1STomer Tayar *p_mfw_drv_role = DRV_ROLE_KDUMP; 9255d24bcf1STomer Tayar break; 9265d24bcf1STomer Tayar default: 9275d24bcf1STomer Tayar DP_ERR(p_hwfn, "Unexpected driver role %d\n", drv_role); 9285d24bcf1STomer Tayar return -EINVAL; 9295d24bcf1STomer Tayar } 9305d24bcf1STomer Tayar 9315d24bcf1STomer Tayar return 0; 9325d24bcf1STomer Tayar } 9335d24bcf1STomer Tayar 9345d24bcf1STomer Tayar enum qed_load_req_force { 9355d24bcf1STomer Tayar QED_LOAD_REQ_FORCE_NONE, 9365d24bcf1STomer Tayar QED_LOAD_REQ_FORCE_PF, 9375d24bcf1STomer Tayar QED_LOAD_REQ_FORCE_ALL, 9385d24bcf1STomer Tayar }; 9395d24bcf1STomer Tayar 9405d24bcf1STomer Tayar static void qed_get_mfw_force_cmd(struct qed_hwfn *p_hwfn, 9415d24bcf1STomer Tayar 9425d24bcf1STomer Tayar enum qed_load_req_force force_cmd, 9435d24bcf1STomer Tayar u8 *p_mfw_force_cmd) 9445d24bcf1STomer Tayar { 9455d24bcf1STomer Tayar switch (force_cmd) { 9465d24bcf1STomer Tayar case QED_LOAD_REQ_FORCE_NONE: 9475d24bcf1STomer Tayar *p_mfw_force_cmd = LOAD_REQ_FORCE_NONE; 9485d24bcf1STomer Tayar break; 9495d24bcf1STomer Tayar case QED_LOAD_REQ_FORCE_PF: 9505d24bcf1STomer Tayar *p_mfw_force_cmd = LOAD_REQ_FORCE_PF; 9515d24bcf1STomer Tayar break; 9525d24bcf1STomer Tayar case QED_LOAD_REQ_FORCE_ALL: 9535d24bcf1STomer Tayar *p_mfw_force_cmd = LOAD_REQ_FORCE_ALL; 9545d24bcf1STomer Tayar break; 9555d24bcf1STomer Tayar } 9565d24bcf1STomer Tayar } 9575d24bcf1STomer Tayar 9585d24bcf1STomer Tayar int qed_mcp_load_req(struct qed_hwfn *p_hwfn, 9595d24bcf1STomer Tayar struct qed_ptt *p_ptt, 9605d24bcf1STomer Tayar struct qed_load_req_params *p_params) 9615d24bcf1STomer Tayar { 9625d24bcf1STomer Tayar struct qed_load_req_out_params out_params; 9635d24bcf1STomer Tayar struct qed_load_req_in_params in_params; 9645d24bcf1STomer Tayar u8 mfw_drv_role, mfw_force_cmd; 9655d24bcf1STomer Tayar int rc; 9665d24bcf1STomer Tayar 9675d24bcf1STomer Tayar memset(&in_params, 0, sizeof(in_params)); 9685d24bcf1STomer Tayar in_params.hsi_ver = QED_LOAD_REQ_HSI_VER_DEFAULT; 9695d24bcf1STomer Tayar in_params.drv_ver_0 = QED_VERSION; 9705d24bcf1STomer Tayar in_params.drv_ver_1 = qed_get_config_bitmap(); 9715d24bcf1STomer Tayar in_params.fw_ver = STORM_FW_VERSION; 9725d24bcf1STomer Tayar rc = eocre_get_mfw_drv_role(p_hwfn, p_params->drv_role, &mfw_drv_role); 9735d24bcf1STomer Tayar if (rc) 9745d24bcf1STomer Tayar return rc; 9755d24bcf1STomer Tayar 9765d24bcf1STomer Tayar in_params.drv_role = mfw_drv_role; 9775d24bcf1STomer Tayar in_params.timeout_val = p_params->timeout_val; 9785d24bcf1STomer Tayar qed_get_mfw_force_cmd(p_hwfn, 9795d24bcf1STomer Tayar QED_LOAD_REQ_FORCE_NONE, &mfw_force_cmd); 9805d24bcf1STomer Tayar 9815d24bcf1STomer Tayar in_params.force_cmd = mfw_force_cmd; 9825d24bcf1STomer Tayar in_params.avoid_eng_reset = p_params->avoid_eng_reset; 9835d24bcf1STomer Tayar 9845d24bcf1STomer Tayar memset(&out_params, 0, sizeof(out_params)); 9855d24bcf1STomer Tayar rc = __qed_mcp_load_req(p_hwfn, p_ptt, &in_params, &out_params); 9865d24bcf1STomer Tayar if (rc) 9875d24bcf1STomer Tayar return rc; 9885d24bcf1STomer Tayar 9895d24bcf1STomer Tayar /* First handle cases where another load request should/might be sent: 9905d24bcf1STomer Tayar * - MFW expects the old interface [HSI version = 1] 9915d24bcf1STomer Tayar * - MFW responds that a force load request is required 992fe56b9e6SYuval Mintz */ 9935d24bcf1STomer Tayar if (out_params.load_code == FW_MSG_CODE_DRV_LOAD_REFUSED_HSI_1) { 9945d24bcf1STomer Tayar DP_INFO(p_hwfn, 9955d24bcf1STomer Tayar "MFW refused a load request due to HSI > 1. Resending with HSI = 1\n"); 9965d24bcf1STomer Tayar 9975d24bcf1STomer Tayar in_params.hsi_ver = QED_LOAD_REQ_HSI_VER_1; 9985d24bcf1STomer Tayar memset(&out_params, 0, sizeof(out_params)); 9995d24bcf1STomer Tayar rc = __qed_mcp_load_req(p_hwfn, p_ptt, &in_params, &out_params); 10005d24bcf1STomer Tayar if (rc) 10015d24bcf1STomer Tayar return rc; 10025d24bcf1STomer Tayar } else if (out_params.load_code == 10035d24bcf1STomer Tayar FW_MSG_CODE_DRV_LOAD_REFUSED_REQUIRES_FORCE) { 10045d24bcf1STomer Tayar if (qed_mcp_can_force_load(in_params.drv_role, 10055d24bcf1STomer Tayar out_params.exist_drv_role, 10065d24bcf1STomer Tayar p_params->override_force_load)) { 10075d24bcf1STomer Tayar DP_INFO(p_hwfn, 10085d24bcf1STomer 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", 10095d24bcf1STomer Tayar in_params.drv_role, in_params.fw_ver, 10105d24bcf1STomer Tayar in_params.drv_ver_0, in_params.drv_ver_1, 10115d24bcf1STomer Tayar out_params.exist_drv_role, 10125d24bcf1STomer Tayar out_params.exist_fw_ver, 10135d24bcf1STomer Tayar out_params.exist_drv_ver_0, 10145d24bcf1STomer Tayar out_params.exist_drv_ver_1); 10155d24bcf1STomer Tayar 10165d24bcf1STomer Tayar qed_get_mfw_force_cmd(p_hwfn, 10175d24bcf1STomer Tayar QED_LOAD_REQ_FORCE_ALL, 10185d24bcf1STomer Tayar &mfw_force_cmd); 10195d24bcf1STomer Tayar 10205d24bcf1STomer Tayar in_params.force_cmd = mfw_force_cmd; 10215d24bcf1STomer Tayar memset(&out_params, 0, sizeof(out_params)); 10225d24bcf1STomer Tayar rc = __qed_mcp_load_req(p_hwfn, p_ptt, &in_params, 10235d24bcf1STomer Tayar &out_params); 10245d24bcf1STomer Tayar if (rc) 10255d24bcf1STomer Tayar return rc; 10265d24bcf1STomer Tayar } else { 10275d24bcf1STomer Tayar DP_NOTICE(p_hwfn, 10285d24bcf1STomer 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", 10295d24bcf1STomer Tayar in_params.drv_role, in_params.fw_ver, 10305d24bcf1STomer Tayar in_params.drv_ver_0, in_params.drv_ver_1, 10315d24bcf1STomer Tayar out_params.exist_drv_role, 10325d24bcf1STomer Tayar out_params.exist_fw_ver, 10335d24bcf1STomer Tayar out_params.exist_drv_ver_0, 10345d24bcf1STomer Tayar out_params.exist_drv_ver_1); 10355d24bcf1STomer Tayar DP_NOTICE(p_hwfn, 10365d24bcf1STomer Tayar "Avoid sending a force load request to prevent disruption of active PFs\n"); 10375d24bcf1STomer Tayar 10385d24bcf1STomer Tayar qed_mcp_cancel_load_req(p_hwfn, p_ptt); 1039fe56b9e6SYuval Mintz return -EBUSY; 1040fe56b9e6SYuval Mintz } 10415d24bcf1STomer Tayar } 10425d24bcf1STomer Tayar 10435d24bcf1STomer Tayar /* Now handle the other types of responses. 10445d24bcf1STomer Tayar * The "REFUSED_HSI_1" and "REFUSED_REQUIRES_FORCE" responses are not 10455d24bcf1STomer Tayar * expected here after the additional revised load requests were sent. 10465d24bcf1STomer Tayar */ 10475d24bcf1STomer Tayar switch (out_params.load_code) { 10485d24bcf1STomer Tayar case FW_MSG_CODE_DRV_LOAD_ENGINE: 10495d24bcf1STomer Tayar case FW_MSG_CODE_DRV_LOAD_PORT: 10505d24bcf1STomer Tayar case FW_MSG_CODE_DRV_LOAD_FUNCTION: 10515d24bcf1STomer Tayar if (out_params.mfw_hsi_ver != QED_LOAD_REQ_HSI_VER_1 && 10525d24bcf1STomer Tayar out_params.drv_exists) { 10535d24bcf1STomer Tayar /* The role and fw/driver version match, but the PF is 10545d24bcf1STomer Tayar * already loaded and has not been unloaded gracefully. 10555d24bcf1STomer Tayar */ 10565d24bcf1STomer Tayar DP_NOTICE(p_hwfn, 10575d24bcf1STomer Tayar "PF is already loaded\n"); 10585d24bcf1STomer Tayar return -EINVAL; 10595d24bcf1STomer Tayar } 10605d24bcf1STomer Tayar break; 10615d24bcf1STomer Tayar default: 10625d24bcf1STomer Tayar DP_NOTICE(p_hwfn, 10635d24bcf1STomer Tayar "Unexpected refusal to load request [resp 0x%08x]. Aborting.\n", 10645d24bcf1STomer Tayar out_params.load_code); 10655d24bcf1STomer Tayar return -EBUSY; 10665d24bcf1STomer Tayar } 10675d24bcf1STomer Tayar 10685d24bcf1STomer Tayar p_params->load_code = out_params.load_code; 1069fe56b9e6SYuval Mintz 1070fe56b9e6SYuval Mintz return 0; 1071fe56b9e6SYuval Mintz } 1072fe56b9e6SYuval Mintz 10731226337aSTomer Tayar int qed_mcp_unload_req(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 10741226337aSTomer Tayar { 1075eaa50fc5STomer Tayar struct qed_mcp_mb_params mb_params; 1076eaa50fc5STomer Tayar u32 wol_param; 10771226337aSTomer Tayar 10781226337aSTomer Tayar switch (p_hwfn->cdev->wol_config) { 10791226337aSTomer Tayar case QED_OV_WOL_DISABLED: 10801226337aSTomer Tayar wol_param = DRV_MB_PARAM_UNLOAD_WOL_DISABLED; 10811226337aSTomer Tayar break; 10821226337aSTomer Tayar case QED_OV_WOL_ENABLED: 10831226337aSTomer Tayar wol_param = DRV_MB_PARAM_UNLOAD_WOL_ENABLED; 10841226337aSTomer Tayar break; 10851226337aSTomer Tayar default: 10861226337aSTomer Tayar DP_NOTICE(p_hwfn, 10871226337aSTomer Tayar "Unknown WoL configuration %02x\n", 10881226337aSTomer Tayar p_hwfn->cdev->wol_config); 10891226337aSTomer Tayar /* Fallthrough */ 10901226337aSTomer Tayar case QED_OV_WOL_DEFAULT: 10911226337aSTomer Tayar wol_param = DRV_MB_PARAM_UNLOAD_WOL_MCP; 10921226337aSTomer Tayar } 10931226337aSTomer Tayar 1094eaa50fc5STomer Tayar memset(&mb_params, 0, sizeof(mb_params)); 1095eaa50fc5STomer Tayar mb_params.cmd = DRV_MSG_CODE_UNLOAD_REQ; 1096eaa50fc5STomer Tayar mb_params.param = wol_param; 1097b310974eSTomer Tayar mb_params.flags = QED_MB_FLAG_CAN_SLEEP | QED_MB_FLAG_AVOID_BLOCK; 1098eaa50fc5STomer Tayar 1099eaa50fc5STomer Tayar return qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 11001226337aSTomer Tayar } 11011226337aSTomer Tayar 11021226337aSTomer Tayar int qed_mcp_unload_done(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 11031226337aSTomer Tayar { 11041226337aSTomer Tayar struct qed_mcp_mb_params mb_params; 11051226337aSTomer Tayar struct mcp_mac wol_mac; 11061226337aSTomer Tayar 11071226337aSTomer Tayar memset(&mb_params, 0, sizeof(mb_params)); 11081226337aSTomer Tayar mb_params.cmd = DRV_MSG_CODE_UNLOAD_DONE; 11091226337aSTomer Tayar 11101226337aSTomer Tayar /* Set the primary MAC if WoL is enabled */ 11111226337aSTomer Tayar if (p_hwfn->cdev->wol_config == QED_OV_WOL_ENABLED) { 11121226337aSTomer Tayar u8 *p_mac = p_hwfn->cdev->wol_mac; 11131226337aSTomer Tayar 11141226337aSTomer Tayar memset(&wol_mac, 0, sizeof(wol_mac)); 11151226337aSTomer Tayar wol_mac.mac_upper = p_mac[0] << 8 | p_mac[1]; 11161226337aSTomer Tayar wol_mac.mac_lower = p_mac[2] << 24 | p_mac[3] << 16 | 11171226337aSTomer Tayar p_mac[4] << 8 | p_mac[5]; 11181226337aSTomer Tayar 11191226337aSTomer Tayar DP_VERBOSE(p_hwfn, 11201226337aSTomer Tayar (QED_MSG_SP | NETIF_MSG_IFDOWN), 11211226337aSTomer Tayar "Setting WoL MAC: %pM --> [%08x,%08x]\n", 11221226337aSTomer Tayar p_mac, wol_mac.mac_upper, wol_mac.mac_lower); 11231226337aSTomer Tayar 11241226337aSTomer Tayar mb_params.p_data_src = &wol_mac; 11251226337aSTomer Tayar mb_params.data_src_size = sizeof(wol_mac); 11261226337aSTomer Tayar } 11271226337aSTomer Tayar 11281226337aSTomer Tayar return qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 11291226337aSTomer Tayar } 11301226337aSTomer Tayar 11310b55e27dSYuval Mintz static void qed_mcp_handle_vf_flr(struct qed_hwfn *p_hwfn, 11320b55e27dSYuval Mintz struct qed_ptt *p_ptt) 11330b55e27dSYuval Mintz { 11340b55e27dSYuval Mintz u32 addr = SECTION_OFFSIZE_ADDR(p_hwfn->mcp_info->public_base, 11350b55e27dSYuval Mintz PUBLIC_PATH); 11360b55e27dSYuval Mintz u32 mfw_path_offsize = qed_rd(p_hwfn, p_ptt, addr); 11370b55e27dSYuval Mintz u32 path_addr = SECTION_ADDR(mfw_path_offsize, 11380b55e27dSYuval Mintz QED_PATH_ID(p_hwfn)); 11390b55e27dSYuval Mintz u32 disabled_vfs[VF_MAX_STATIC / 32]; 11400b55e27dSYuval Mintz int i; 11410b55e27dSYuval Mintz 11420b55e27dSYuval Mintz DP_VERBOSE(p_hwfn, 11430b55e27dSYuval Mintz QED_MSG_SP, 11440b55e27dSYuval Mintz "Reading Disabled VF information from [offset %08x], path_addr %08x\n", 11450b55e27dSYuval Mintz mfw_path_offsize, path_addr); 11460b55e27dSYuval Mintz 11470b55e27dSYuval Mintz for (i = 0; i < (VF_MAX_STATIC / 32); i++) { 11480b55e27dSYuval Mintz disabled_vfs[i] = qed_rd(p_hwfn, p_ptt, 11490b55e27dSYuval Mintz path_addr + 11500b55e27dSYuval Mintz offsetof(struct public_path, 11510b55e27dSYuval Mintz mcp_vf_disabled) + 11520b55e27dSYuval Mintz sizeof(u32) * i); 11530b55e27dSYuval Mintz DP_VERBOSE(p_hwfn, (QED_MSG_SP | QED_MSG_IOV), 11540b55e27dSYuval Mintz "FLR-ed VFs [%08x,...,%08x] - %08x\n", 11550b55e27dSYuval Mintz i * 32, (i + 1) * 32 - 1, disabled_vfs[i]); 11560b55e27dSYuval Mintz } 11570b55e27dSYuval Mintz 11580b55e27dSYuval Mintz if (qed_iov_mark_vf_flr(p_hwfn, disabled_vfs)) 11590b55e27dSYuval Mintz qed_schedule_iov(p_hwfn, QED_IOV_WQ_FLR_FLAG); 11600b55e27dSYuval Mintz } 11610b55e27dSYuval Mintz 11620b55e27dSYuval Mintz int qed_mcp_ack_vf_flr(struct qed_hwfn *p_hwfn, 11630b55e27dSYuval Mintz struct qed_ptt *p_ptt, u32 *vfs_to_ack) 11640b55e27dSYuval Mintz { 11650b55e27dSYuval Mintz u32 addr = SECTION_OFFSIZE_ADDR(p_hwfn->mcp_info->public_base, 11660b55e27dSYuval Mintz PUBLIC_FUNC); 11670b55e27dSYuval Mintz u32 mfw_func_offsize = qed_rd(p_hwfn, p_ptt, addr); 11680b55e27dSYuval Mintz u32 func_addr = SECTION_ADDR(mfw_func_offsize, 11690b55e27dSYuval Mintz MCP_PF_ID(p_hwfn)); 11700b55e27dSYuval Mintz struct qed_mcp_mb_params mb_params; 11710b55e27dSYuval Mintz int rc; 11720b55e27dSYuval Mintz int i; 11730b55e27dSYuval Mintz 11740b55e27dSYuval Mintz for (i = 0; i < (VF_MAX_STATIC / 32); i++) 11750b55e27dSYuval Mintz DP_VERBOSE(p_hwfn, (QED_MSG_SP | QED_MSG_IOV), 11760b55e27dSYuval Mintz "Acking VFs [%08x,...,%08x] - %08x\n", 11770b55e27dSYuval Mintz i * 32, (i + 1) * 32 - 1, vfs_to_ack[i]); 11780b55e27dSYuval Mintz 11790b55e27dSYuval Mintz memset(&mb_params, 0, sizeof(mb_params)); 11800b55e27dSYuval Mintz mb_params.cmd = DRV_MSG_CODE_VF_DISABLED_DONE; 11812f67af8cSTomer Tayar mb_params.p_data_src = vfs_to_ack; 11822f67af8cSTomer Tayar mb_params.data_src_size = VF_MAX_STATIC / 8; 11830b55e27dSYuval Mintz rc = qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 11840b55e27dSYuval Mintz if (rc) { 11850b55e27dSYuval Mintz DP_NOTICE(p_hwfn, "Failed to pass ACK for VF flr to MFW\n"); 11860b55e27dSYuval Mintz return -EBUSY; 11870b55e27dSYuval Mintz } 11880b55e27dSYuval Mintz 11890b55e27dSYuval Mintz /* Clear the ACK bits */ 11900b55e27dSYuval Mintz for (i = 0; i < (VF_MAX_STATIC / 32); i++) 11910b55e27dSYuval Mintz qed_wr(p_hwfn, p_ptt, 11920b55e27dSYuval Mintz func_addr + 11930b55e27dSYuval Mintz offsetof(struct public_func, drv_ack_vf_disabled) + 11940b55e27dSYuval Mintz i * sizeof(u32), 0); 11950b55e27dSYuval Mintz 11960b55e27dSYuval Mintz return rc; 11970b55e27dSYuval Mintz } 11980b55e27dSYuval Mintz 1199334c03b5SZvi Nachmani static void qed_mcp_handle_transceiver_change(struct qed_hwfn *p_hwfn, 1200334c03b5SZvi Nachmani struct qed_ptt *p_ptt) 1201334c03b5SZvi Nachmani { 1202334c03b5SZvi Nachmani u32 transceiver_state; 1203334c03b5SZvi Nachmani 1204334c03b5SZvi Nachmani transceiver_state = qed_rd(p_hwfn, p_ptt, 1205334c03b5SZvi Nachmani p_hwfn->mcp_info->port_addr + 1206334c03b5SZvi Nachmani offsetof(struct public_port, 1207334c03b5SZvi Nachmani transceiver_data)); 1208334c03b5SZvi Nachmani 1209334c03b5SZvi Nachmani DP_VERBOSE(p_hwfn, 1210334c03b5SZvi Nachmani (NETIF_MSG_HW | QED_MSG_SP), 1211334c03b5SZvi Nachmani "Received transceiver state update [0x%08x] from mfw [Addr 0x%x]\n", 1212334c03b5SZvi Nachmani transceiver_state, 1213334c03b5SZvi Nachmani (u32)(p_hwfn->mcp_info->port_addr + 12141a635e48SYuval Mintz offsetof(struct public_port, transceiver_data))); 1215334c03b5SZvi Nachmani 1216334c03b5SZvi Nachmani transceiver_state = GET_FIELD(transceiver_state, 1217351a4dedSYuval Mintz ETH_TRANSCEIVER_STATE); 1218334c03b5SZvi Nachmani 1219351a4dedSYuval Mintz if (transceiver_state == ETH_TRANSCEIVER_STATE_PRESENT) 1220334c03b5SZvi Nachmani DP_NOTICE(p_hwfn, "Transceiver is present.\n"); 1221334c03b5SZvi Nachmani else 1222334c03b5SZvi Nachmani DP_NOTICE(p_hwfn, "Transceiver is unplugged.\n"); 1223334c03b5SZvi Nachmani } 1224334c03b5SZvi Nachmani 1225645874e5SSudarsana Reddy Kalluru static void qed_mcp_read_eee_config(struct qed_hwfn *p_hwfn, 1226645874e5SSudarsana Reddy Kalluru struct qed_ptt *p_ptt, 1227645874e5SSudarsana Reddy Kalluru struct qed_mcp_link_state *p_link) 1228645874e5SSudarsana Reddy Kalluru { 1229645874e5SSudarsana Reddy Kalluru u32 eee_status, val; 1230645874e5SSudarsana Reddy Kalluru 1231645874e5SSudarsana Reddy Kalluru p_link->eee_adv_caps = 0; 1232645874e5SSudarsana Reddy Kalluru p_link->eee_lp_adv_caps = 0; 1233645874e5SSudarsana Reddy Kalluru eee_status = qed_rd(p_hwfn, 1234645874e5SSudarsana Reddy Kalluru p_ptt, 1235645874e5SSudarsana Reddy Kalluru p_hwfn->mcp_info->port_addr + 1236645874e5SSudarsana Reddy Kalluru offsetof(struct public_port, eee_status)); 1237645874e5SSudarsana Reddy Kalluru p_link->eee_active = !!(eee_status & EEE_ACTIVE_BIT); 1238645874e5SSudarsana Reddy Kalluru val = (eee_status & EEE_LD_ADV_STATUS_MASK) >> EEE_LD_ADV_STATUS_OFFSET; 1239645874e5SSudarsana Reddy Kalluru if (val & EEE_1G_ADV) 1240645874e5SSudarsana Reddy Kalluru p_link->eee_adv_caps |= QED_EEE_1G_ADV; 1241645874e5SSudarsana Reddy Kalluru if (val & EEE_10G_ADV) 1242645874e5SSudarsana Reddy Kalluru p_link->eee_adv_caps |= QED_EEE_10G_ADV; 1243645874e5SSudarsana Reddy Kalluru val = (eee_status & EEE_LP_ADV_STATUS_MASK) >> EEE_LP_ADV_STATUS_OFFSET; 1244645874e5SSudarsana Reddy Kalluru if (val & EEE_1G_ADV) 1245645874e5SSudarsana Reddy Kalluru p_link->eee_lp_adv_caps |= QED_EEE_1G_ADV; 1246645874e5SSudarsana Reddy Kalluru if (val & EEE_10G_ADV) 1247645874e5SSudarsana Reddy Kalluru p_link->eee_lp_adv_caps |= QED_EEE_10G_ADV; 1248645874e5SSudarsana Reddy Kalluru } 1249645874e5SSudarsana Reddy Kalluru 1250e40a826aSSudarsana Reddy Kalluru static u32 qed_mcp_get_shmem_func(struct qed_hwfn *p_hwfn, 1251e40a826aSSudarsana Reddy Kalluru struct qed_ptt *p_ptt, 1252e40a826aSSudarsana Reddy Kalluru struct public_func *p_data, int pfid) 1253e40a826aSSudarsana Reddy Kalluru { 1254e40a826aSSudarsana Reddy Kalluru u32 addr = SECTION_OFFSIZE_ADDR(p_hwfn->mcp_info->public_base, 1255e40a826aSSudarsana Reddy Kalluru PUBLIC_FUNC); 1256e40a826aSSudarsana Reddy Kalluru u32 mfw_path_offsize = qed_rd(p_hwfn, p_ptt, addr); 1257e40a826aSSudarsana Reddy Kalluru u32 func_addr; 1258e40a826aSSudarsana Reddy Kalluru u32 i, size; 1259e40a826aSSudarsana Reddy Kalluru 1260e40a826aSSudarsana Reddy Kalluru func_addr = SECTION_ADDR(mfw_path_offsize, pfid); 1261e40a826aSSudarsana Reddy Kalluru memset(p_data, 0, sizeof(*p_data)); 1262e40a826aSSudarsana Reddy Kalluru 1263e40a826aSSudarsana Reddy Kalluru size = min_t(u32, sizeof(*p_data), QED_SECTION_SIZE(mfw_path_offsize)); 1264e40a826aSSudarsana Reddy Kalluru for (i = 0; i < size / sizeof(u32); i++) 1265e40a826aSSudarsana Reddy Kalluru ((u32 *)p_data)[i] = qed_rd(p_hwfn, p_ptt, 1266e40a826aSSudarsana Reddy Kalluru func_addr + (i << 2)); 1267e40a826aSSudarsana Reddy Kalluru return size; 1268e40a826aSSudarsana Reddy Kalluru } 1269e40a826aSSudarsana Reddy Kalluru 1270e40a826aSSudarsana Reddy Kalluru static void qed_read_pf_bandwidth(struct qed_hwfn *p_hwfn, 1271e40a826aSSudarsana Reddy Kalluru struct public_func *p_shmem_info) 1272e40a826aSSudarsana Reddy Kalluru { 1273e40a826aSSudarsana Reddy Kalluru struct qed_mcp_function_info *p_info; 1274e40a826aSSudarsana Reddy Kalluru 1275e40a826aSSudarsana Reddy Kalluru p_info = &p_hwfn->mcp_info->func_info; 1276e40a826aSSudarsana Reddy Kalluru 1277e40a826aSSudarsana Reddy Kalluru p_info->bandwidth_min = QED_MFW_GET_FIELD(p_shmem_info->config, 1278e40a826aSSudarsana Reddy Kalluru FUNC_MF_CFG_MIN_BW); 1279e40a826aSSudarsana Reddy Kalluru if (p_info->bandwidth_min < 1 || p_info->bandwidth_min > 100) { 1280e40a826aSSudarsana Reddy Kalluru DP_INFO(p_hwfn, 1281e40a826aSSudarsana Reddy Kalluru "bandwidth minimum out of bounds [%02x]. Set to 1\n", 1282e40a826aSSudarsana Reddy Kalluru p_info->bandwidth_min); 1283e40a826aSSudarsana Reddy Kalluru p_info->bandwidth_min = 1; 1284e40a826aSSudarsana Reddy Kalluru } 1285e40a826aSSudarsana Reddy Kalluru 1286e40a826aSSudarsana Reddy Kalluru p_info->bandwidth_max = QED_MFW_GET_FIELD(p_shmem_info->config, 1287e40a826aSSudarsana Reddy Kalluru FUNC_MF_CFG_MAX_BW); 1288e40a826aSSudarsana Reddy Kalluru if (p_info->bandwidth_max < 1 || p_info->bandwidth_max > 100) { 1289e40a826aSSudarsana Reddy Kalluru DP_INFO(p_hwfn, 1290e40a826aSSudarsana Reddy Kalluru "bandwidth maximum out of bounds [%02x]. Set to 100\n", 1291e40a826aSSudarsana Reddy Kalluru p_info->bandwidth_max); 1292e40a826aSSudarsana Reddy Kalluru p_info->bandwidth_max = 100; 1293e40a826aSSudarsana Reddy Kalluru } 1294e40a826aSSudarsana Reddy Kalluru } 1295e40a826aSSudarsana Reddy Kalluru 1296cc875c2eSYuval Mintz static void qed_mcp_handle_link_change(struct qed_hwfn *p_hwfn, 12971a635e48SYuval Mintz struct qed_ptt *p_ptt, bool b_reset) 1298cc875c2eSYuval Mintz { 1299cc875c2eSYuval Mintz struct qed_mcp_link_state *p_link; 1300a64b02d5SManish Chopra u8 max_bw, min_bw; 1301cc875c2eSYuval Mintz u32 status = 0; 1302cc875c2eSYuval Mintz 130365ed2ffdSMintz, Yuval /* Prevent SW/attentions from doing this at the same time */ 130465ed2ffdSMintz, Yuval spin_lock_bh(&p_hwfn->mcp_info->link_lock); 130565ed2ffdSMintz, Yuval 1306cc875c2eSYuval Mintz p_link = &p_hwfn->mcp_info->link_output; 1307cc875c2eSYuval Mintz memset(p_link, 0, sizeof(*p_link)); 1308cc875c2eSYuval Mintz if (!b_reset) { 1309cc875c2eSYuval Mintz status = qed_rd(p_hwfn, p_ptt, 1310cc875c2eSYuval Mintz p_hwfn->mcp_info->port_addr + 1311cc875c2eSYuval Mintz offsetof(struct public_port, link_status)); 1312cc875c2eSYuval Mintz DP_VERBOSE(p_hwfn, (NETIF_MSG_LINK | QED_MSG_SP), 1313cc875c2eSYuval Mintz "Received link update [0x%08x] from mfw [Addr 0x%x]\n", 1314cc875c2eSYuval Mintz status, 1315cc875c2eSYuval Mintz (u32)(p_hwfn->mcp_info->port_addr + 13161a635e48SYuval Mintz offsetof(struct public_port, link_status))); 1317cc875c2eSYuval Mintz } else { 1318cc875c2eSYuval Mintz DP_VERBOSE(p_hwfn, NETIF_MSG_LINK, 1319cc875c2eSYuval Mintz "Resetting link indications\n"); 132065ed2ffdSMintz, Yuval goto out; 1321cc875c2eSYuval Mintz } 1322cc875c2eSYuval Mintz 1323e40a826aSSudarsana Reddy Kalluru if (p_hwfn->b_drv_link_init) { 1324e40a826aSSudarsana Reddy Kalluru /* Link indication with modern MFW arrives as per-PF 1325e40a826aSSudarsana Reddy Kalluru * indication. 1326e40a826aSSudarsana Reddy Kalluru */ 1327e40a826aSSudarsana Reddy Kalluru if (p_hwfn->mcp_info->capabilities & 1328e40a826aSSudarsana Reddy Kalluru FW_MB_PARAM_FEATURE_SUPPORT_VLINK) { 1329e40a826aSSudarsana Reddy Kalluru struct public_func shmem_info; 1330e40a826aSSudarsana Reddy Kalluru 1331e40a826aSSudarsana Reddy Kalluru qed_mcp_get_shmem_func(p_hwfn, p_ptt, &shmem_info, 1332e40a826aSSudarsana Reddy Kalluru MCP_PF_ID(p_hwfn)); 1333e40a826aSSudarsana Reddy Kalluru p_link->link_up = !!(shmem_info.status & 1334e40a826aSSudarsana Reddy Kalluru FUNC_STATUS_VIRTUAL_LINK_UP); 1335e40a826aSSudarsana Reddy Kalluru qed_read_pf_bandwidth(p_hwfn, &shmem_info); 1336e40a826aSSudarsana Reddy Kalluru DP_VERBOSE(p_hwfn, NETIF_MSG_LINK, 1337e40a826aSSudarsana Reddy Kalluru "Virtual link_up = %d\n", p_link->link_up); 1338e40a826aSSudarsana Reddy Kalluru } else { 1339cc875c2eSYuval Mintz p_link->link_up = !!(status & LINK_STATUS_LINK_UP); 1340e40a826aSSudarsana Reddy Kalluru DP_VERBOSE(p_hwfn, NETIF_MSG_LINK, 1341e40a826aSSudarsana Reddy Kalluru "Physical link_up = %d\n", p_link->link_up); 1342e40a826aSSudarsana Reddy Kalluru } 1343e40a826aSSudarsana Reddy Kalluru } else { 1344fc916ff2SSudarsana Reddy Kalluru p_link->link_up = false; 1345e40a826aSSudarsana Reddy Kalluru } 1346cc875c2eSYuval Mintz 1347cc875c2eSYuval Mintz p_link->full_duplex = true; 1348cc875c2eSYuval Mintz switch ((status & LINK_STATUS_SPEED_AND_DUPLEX_MASK)) { 1349cc875c2eSYuval Mintz case LINK_STATUS_SPEED_AND_DUPLEX_100G: 1350cc875c2eSYuval Mintz p_link->speed = 100000; 1351cc875c2eSYuval Mintz break; 1352cc875c2eSYuval Mintz case LINK_STATUS_SPEED_AND_DUPLEX_50G: 1353cc875c2eSYuval Mintz p_link->speed = 50000; 1354cc875c2eSYuval Mintz break; 1355cc875c2eSYuval Mintz case LINK_STATUS_SPEED_AND_DUPLEX_40G: 1356cc875c2eSYuval Mintz p_link->speed = 40000; 1357cc875c2eSYuval Mintz break; 1358cc875c2eSYuval Mintz case LINK_STATUS_SPEED_AND_DUPLEX_25G: 1359cc875c2eSYuval Mintz p_link->speed = 25000; 1360cc875c2eSYuval Mintz break; 1361cc875c2eSYuval Mintz case LINK_STATUS_SPEED_AND_DUPLEX_20G: 1362cc875c2eSYuval Mintz p_link->speed = 20000; 1363cc875c2eSYuval Mintz break; 1364cc875c2eSYuval Mintz case LINK_STATUS_SPEED_AND_DUPLEX_10G: 1365cc875c2eSYuval Mintz p_link->speed = 10000; 1366cc875c2eSYuval Mintz break; 1367cc875c2eSYuval Mintz case LINK_STATUS_SPEED_AND_DUPLEX_1000THD: 1368cc875c2eSYuval Mintz p_link->full_duplex = false; 1369cc875c2eSYuval Mintz /* Fall-through */ 1370cc875c2eSYuval Mintz case LINK_STATUS_SPEED_AND_DUPLEX_1000TFD: 1371cc875c2eSYuval Mintz p_link->speed = 1000; 1372cc875c2eSYuval Mintz break; 1373cc875c2eSYuval Mintz default: 1374cc875c2eSYuval Mintz p_link->speed = 0; 137558874c7bSSudarsana Reddy Kalluru p_link->link_up = 0; 1376cc875c2eSYuval Mintz } 1377cc875c2eSYuval Mintz 13784b01e519SManish Chopra if (p_link->link_up && p_link->speed) 13794b01e519SManish Chopra p_link->line_speed = p_link->speed; 13804b01e519SManish Chopra else 13814b01e519SManish Chopra p_link->line_speed = 0; 13824b01e519SManish Chopra 13834b01e519SManish Chopra max_bw = p_hwfn->mcp_info->func_info.bandwidth_max; 1384a64b02d5SManish Chopra min_bw = p_hwfn->mcp_info->func_info.bandwidth_min; 13854b01e519SManish Chopra 1386a64b02d5SManish Chopra /* Max bandwidth configuration */ 13874b01e519SManish Chopra __qed_configure_pf_max_bandwidth(p_hwfn, p_ptt, p_link, max_bw); 1388cc875c2eSYuval Mintz 1389a64b02d5SManish Chopra /* Min bandwidth configuration */ 1390a64b02d5SManish Chopra __qed_configure_pf_min_bandwidth(p_hwfn, p_ptt, p_link, min_bw); 13916f437d43SMintz, Yuval qed_configure_vp_wfq_on_link_change(p_hwfn->cdev, p_ptt, 13926f437d43SMintz, Yuval p_link->min_pf_rate); 1393a64b02d5SManish Chopra 1394cc875c2eSYuval Mintz p_link->an = !!(status & LINK_STATUS_AUTO_NEGOTIATE_ENABLED); 1395cc875c2eSYuval Mintz p_link->an_complete = !!(status & 1396cc875c2eSYuval Mintz LINK_STATUS_AUTO_NEGOTIATE_COMPLETE); 1397cc875c2eSYuval Mintz p_link->parallel_detection = !!(status & 1398cc875c2eSYuval Mintz LINK_STATUS_PARALLEL_DETECTION_USED); 1399cc875c2eSYuval Mintz p_link->pfc_enabled = !!(status & LINK_STATUS_PFC_ENABLED); 1400cc875c2eSYuval Mintz 1401cc875c2eSYuval Mintz p_link->partner_adv_speed |= 1402cc875c2eSYuval Mintz (status & LINK_STATUS_LINK_PARTNER_1000TFD_CAPABLE) ? 1403cc875c2eSYuval Mintz QED_LINK_PARTNER_SPEED_1G_FD : 0; 1404cc875c2eSYuval Mintz p_link->partner_adv_speed |= 1405cc875c2eSYuval Mintz (status & LINK_STATUS_LINK_PARTNER_1000THD_CAPABLE) ? 1406cc875c2eSYuval Mintz QED_LINK_PARTNER_SPEED_1G_HD : 0; 1407cc875c2eSYuval Mintz p_link->partner_adv_speed |= 1408cc875c2eSYuval Mintz (status & LINK_STATUS_LINK_PARTNER_10G_CAPABLE) ? 1409cc875c2eSYuval Mintz QED_LINK_PARTNER_SPEED_10G : 0; 1410cc875c2eSYuval Mintz p_link->partner_adv_speed |= 1411cc875c2eSYuval Mintz (status & LINK_STATUS_LINK_PARTNER_20G_CAPABLE) ? 1412cc875c2eSYuval Mintz QED_LINK_PARTNER_SPEED_20G : 0; 1413cc875c2eSYuval Mintz p_link->partner_adv_speed |= 1414054c67d1SSudarsana Reddy Kalluru (status & LINK_STATUS_LINK_PARTNER_25G_CAPABLE) ? 1415054c67d1SSudarsana Reddy Kalluru QED_LINK_PARTNER_SPEED_25G : 0; 1416054c67d1SSudarsana Reddy Kalluru p_link->partner_adv_speed |= 1417cc875c2eSYuval Mintz (status & LINK_STATUS_LINK_PARTNER_40G_CAPABLE) ? 1418cc875c2eSYuval Mintz QED_LINK_PARTNER_SPEED_40G : 0; 1419cc875c2eSYuval Mintz p_link->partner_adv_speed |= 1420cc875c2eSYuval Mintz (status & LINK_STATUS_LINK_PARTNER_50G_CAPABLE) ? 1421cc875c2eSYuval Mintz QED_LINK_PARTNER_SPEED_50G : 0; 1422cc875c2eSYuval Mintz p_link->partner_adv_speed |= 1423cc875c2eSYuval Mintz (status & LINK_STATUS_LINK_PARTNER_100G_CAPABLE) ? 1424cc875c2eSYuval Mintz QED_LINK_PARTNER_SPEED_100G : 0; 1425cc875c2eSYuval Mintz 1426cc875c2eSYuval Mintz p_link->partner_tx_flow_ctrl_en = 1427cc875c2eSYuval Mintz !!(status & LINK_STATUS_TX_FLOW_CONTROL_ENABLED); 1428cc875c2eSYuval Mintz p_link->partner_rx_flow_ctrl_en = 1429cc875c2eSYuval Mintz !!(status & LINK_STATUS_RX_FLOW_CONTROL_ENABLED); 1430cc875c2eSYuval Mintz 1431cc875c2eSYuval Mintz switch (status & LINK_STATUS_LINK_PARTNER_FLOW_CONTROL_MASK) { 1432cc875c2eSYuval Mintz case LINK_STATUS_LINK_PARTNER_SYMMETRIC_PAUSE: 1433cc875c2eSYuval Mintz p_link->partner_adv_pause = QED_LINK_PARTNER_SYMMETRIC_PAUSE; 1434cc875c2eSYuval Mintz break; 1435cc875c2eSYuval Mintz case LINK_STATUS_LINK_PARTNER_ASYMMETRIC_PAUSE: 1436cc875c2eSYuval Mintz p_link->partner_adv_pause = QED_LINK_PARTNER_ASYMMETRIC_PAUSE; 1437cc875c2eSYuval Mintz break; 1438cc875c2eSYuval Mintz case LINK_STATUS_LINK_PARTNER_BOTH_PAUSE: 1439cc875c2eSYuval Mintz p_link->partner_adv_pause = QED_LINK_PARTNER_BOTH_PAUSE; 1440cc875c2eSYuval Mintz break; 1441cc875c2eSYuval Mintz default: 1442cc875c2eSYuval Mintz p_link->partner_adv_pause = 0; 1443cc875c2eSYuval Mintz } 1444cc875c2eSYuval Mintz 1445cc875c2eSYuval Mintz p_link->sfp_tx_fault = !!(status & LINK_STATUS_SFP_TX_FAULT); 1446cc875c2eSYuval Mintz 1447645874e5SSudarsana Reddy Kalluru if (p_hwfn->mcp_info->capabilities & FW_MB_PARAM_FEATURE_SUPPORT_EEE) 1448645874e5SSudarsana Reddy Kalluru qed_mcp_read_eee_config(p_hwfn, p_ptt, p_link); 1449645874e5SSudarsana Reddy Kalluru 1450706d0891SRahul Verma qed_link_update(p_hwfn, p_ptt); 145165ed2ffdSMintz, Yuval out: 145265ed2ffdSMintz, Yuval spin_unlock_bh(&p_hwfn->mcp_info->link_lock); 1453cc875c2eSYuval Mintz } 1454cc875c2eSYuval Mintz 1455351a4dedSYuval Mintz int qed_mcp_set_link(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, bool b_up) 1456cc875c2eSYuval Mintz { 1457cc875c2eSYuval Mintz struct qed_mcp_link_params *params = &p_hwfn->mcp_info->link_input; 14585529bad9STomer Tayar struct qed_mcp_mb_params mb_params; 14592f67af8cSTomer Tayar struct eth_phy_cfg phy_cfg; 1460cc875c2eSYuval Mintz int rc = 0; 14615529bad9STomer Tayar u32 cmd; 1462cc875c2eSYuval Mintz 1463cc875c2eSYuval Mintz /* Set the shmem configuration according to params */ 14642f67af8cSTomer Tayar memset(&phy_cfg, 0, sizeof(phy_cfg)); 1465cc875c2eSYuval Mintz cmd = b_up ? DRV_MSG_CODE_INIT_PHY : DRV_MSG_CODE_LINK_RESET; 1466cc875c2eSYuval Mintz if (!params->speed.autoneg) 14672f67af8cSTomer Tayar phy_cfg.speed = params->speed.forced_speed; 14682f67af8cSTomer Tayar phy_cfg.pause |= (params->pause.autoneg) ? ETH_PAUSE_AUTONEG : 0; 14692f67af8cSTomer Tayar phy_cfg.pause |= (params->pause.forced_rx) ? ETH_PAUSE_RX : 0; 14702f67af8cSTomer Tayar phy_cfg.pause |= (params->pause.forced_tx) ? ETH_PAUSE_TX : 0; 14712f67af8cSTomer Tayar phy_cfg.adv_speed = params->speed.advertised_speeds; 14722f67af8cSTomer Tayar phy_cfg.loopback_mode = params->loopback_mode; 14734ad95a93SSudarsana Reddy Kalluru 14744ad95a93SSudarsana Reddy Kalluru /* There are MFWs that share this capability regardless of whether 14754ad95a93SSudarsana Reddy Kalluru * this is feasible or not. And given that at the very least adv_caps 14764ad95a93SSudarsana Reddy Kalluru * would be set internally by qed, we want to make sure LFA would 14774ad95a93SSudarsana Reddy Kalluru * still work. 14784ad95a93SSudarsana Reddy Kalluru */ 14794ad95a93SSudarsana Reddy Kalluru if ((p_hwfn->mcp_info->capabilities & 14804ad95a93SSudarsana Reddy Kalluru FW_MB_PARAM_FEATURE_SUPPORT_EEE) && params->eee.enable) { 1481645874e5SSudarsana Reddy Kalluru phy_cfg.eee_cfg |= EEE_CFG_EEE_ENABLED; 1482645874e5SSudarsana Reddy Kalluru if (params->eee.tx_lpi_enable) 1483645874e5SSudarsana Reddy Kalluru phy_cfg.eee_cfg |= EEE_CFG_TX_LPI; 1484645874e5SSudarsana Reddy Kalluru if (params->eee.adv_caps & QED_EEE_1G_ADV) 1485645874e5SSudarsana Reddy Kalluru phy_cfg.eee_cfg |= EEE_CFG_ADV_SPEED_1G; 1486645874e5SSudarsana Reddy Kalluru if (params->eee.adv_caps & QED_EEE_10G_ADV) 1487645874e5SSudarsana Reddy Kalluru phy_cfg.eee_cfg |= EEE_CFG_ADV_SPEED_10G; 1488645874e5SSudarsana Reddy Kalluru phy_cfg.eee_cfg |= (params->eee.tx_lpi_timer << 1489645874e5SSudarsana Reddy Kalluru EEE_TX_TIMER_USEC_OFFSET) & 1490645874e5SSudarsana Reddy Kalluru EEE_TX_TIMER_USEC_MASK; 1491645874e5SSudarsana Reddy Kalluru } 1492cc875c2eSYuval Mintz 1493fc916ff2SSudarsana Reddy Kalluru p_hwfn->b_drv_link_init = b_up; 1494fc916ff2SSudarsana Reddy Kalluru 1495cc875c2eSYuval Mintz if (b_up) { 1496cc875c2eSYuval Mintz DP_VERBOSE(p_hwfn, NETIF_MSG_LINK, 1497cc875c2eSYuval Mintz "Configuring Link: Speed 0x%08x, Pause 0x%08x, adv_speed 0x%08x, loopback 0x%08x, features 0x%08x\n", 14982f67af8cSTomer Tayar phy_cfg.speed, 14992f67af8cSTomer Tayar phy_cfg.pause, 15002f67af8cSTomer Tayar phy_cfg.adv_speed, 15012f67af8cSTomer Tayar phy_cfg.loopback_mode, 15022f67af8cSTomer Tayar phy_cfg.feature_config_flags); 1503cc875c2eSYuval Mintz } else { 1504cc875c2eSYuval Mintz DP_VERBOSE(p_hwfn, NETIF_MSG_LINK, 1505cc875c2eSYuval Mintz "Resetting link\n"); 1506cc875c2eSYuval Mintz } 1507cc875c2eSYuval Mintz 15085529bad9STomer Tayar memset(&mb_params, 0, sizeof(mb_params)); 15095529bad9STomer Tayar mb_params.cmd = cmd; 15102f67af8cSTomer Tayar mb_params.p_data_src = &phy_cfg; 15112f67af8cSTomer Tayar mb_params.data_src_size = sizeof(phy_cfg); 15125529bad9STomer Tayar rc = qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 1513cc875c2eSYuval Mintz 1514cc875c2eSYuval Mintz /* if mcp fails to respond we must abort */ 1515cc875c2eSYuval Mintz if (rc) { 1516cc875c2eSYuval Mintz DP_ERR(p_hwfn, "MCP response failure, aborting\n"); 1517cc875c2eSYuval Mintz return rc; 1518cc875c2eSYuval Mintz } 1519cc875c2eSYuval Mintz 152065ed2ffdSMintz, Yuval /* Mimic link-change attention, done for several reasons: 152165ed2ffdSMintz, Yuval * - On reset, there's no guarantee MFW would trigger 152265ed2ffdSMintz, Yuval * an attention. 152365ed2ffdSMintz, Yuval * - On initialization, older MFWs might not indicate link change 152465ed2ffdSMintz, Yuval * during LFA, so we'll never get an UP indication. 152565ed2ffdSMintz, Yuval */ 152665ed2ffdSMintz, Yuval qed_mcp_handle_link_change(p_hwfn, p_ptt, !b_up); 1527cc875c2eSYuval Mintz 1528cc875c2eSYuval Mintz return 0; 1529cc875c2eSYuval Mintz } 1530cc875c2eSYuval Mintz 15316c754246SSudarsana Reddy Kalluru static void qed_mcp_send_protocol_stats(struct qed_hwfn *p_hwfn, 15326c754246SSudarsana Reddy Kalluru struct qed_ptt *p_ptt, 15336c754246SSudarsana Reddy Kalluru enum MFW_DRV_MSG_TYPE type) 15346c754246SSudarsana Reddy Kalluru { 15356c754246SSudarsana Reddy Kalluru enum qed_mcp_protocol_type stats_type; 15366c754246SSudarsana Reddy Kalluru union qed_mcp_protocol_stats stats; 15376c754246SSudarsana Reddy Kalluru struct qed_mcp_mb_params mb_params; 15386c754246SSudarsana Reddy Kalluru u32 hsi_param; 15396c754246SSudarsana Reddy Kalluru 15406c754246SSudarsana Reddy Kalluru switch (type) { 15416c754246SSudarsana Reddy Kalluru case MFW_DRV_MSG_GET_LAN_STATS: 15426c754246SSudarsana Reddy Kalluru stats_type = QED_MCP_LAN_STATS; 15436c754246SSudarsana Reddy Kalluru hsi_param = DRV_MSG_CODE_STATS_TYPE_LAN; 15446c754246SSudarsana Reddy Kalluru break; 15456c754246SSudarsana Reddy Kalluru case MFW_DRV_MSG_GET_FCOE_STATS: 15466c754246SSudarsana Reddy Kalluru stats_type = QED_MCP_FCOE_STATS; 15476c754246SSudarsana Reddy Kalluru hsi_param = DRV_MSG_CODE_STATS_TYPE_FCOE; 15486c754246SSudarsana Reddy Kalluru break; 15496c754246SSudarsana Reddy Kalluru case MFW_DRV_MSG_GET_ISCSI_STATS: 15506c754246SSudarsana Reddy Kalluru stats_type = QED_MCP_ISCSI_STATS; 15516c754246SSudarsana Reddy Kalluru hsi_param = DRV_MSG_CODE_STATS_TYPE_ISCSI; 15526c754246SSudarsana Reddy Kalluru break; 15536c754246SSudarsana Reddy Kalluru case MFW_DRV_MSG_GET_RDMA_STATS: 15546c754246SSudarsana Reddy Kalluru stats_type = QED_MCP_RDMA_STATS; 15556c754246SSudarsana Reddy Kalluru hsi_param = DRV_MSG_CODE_STATS_TYPE_RDMA; 15566c754246SSudarsana Reddy Kalluru break; 15576c754246SSudarsana Reddy Kalluru default: 15586c754246SSudarsana Reddy Kalluru DP_NOTICE(p_hwfn, "Invalid protocol type %d\n", type); 15596c754246SSudarsana Reddy Kalluru return; 15606c754246SSudarsana Reddy Kalluru } 15616c754246SSudarsana Reddy Kalluru 15626c754246SSudarsana Reddy Kalluru qed_get_protocol_stats(p_hwfn->cdev, stats_type, &stats); 15636c754246SSudarsana Reddy Kalluru 15646c754246SSudarsana Reddy Kalluru memset(&mb_params, 0, sizeof(mb_params)); 15656c754246SSudarsana Reddy Kalluru mb_params.cmd = DRV_MSG_CODE_GET_STATS; 15666c754246SSudarsana Reddy Kalluru mb_params.param = hsi_param; 15672f67af8cSTomer Tayar mb_params.p_data_src = &stats; 15682f67af8cSTomer Tayar mb_params.data_src_size = sizeof(stats); 15696c754246SSudarsana Reddy Kalluru qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 15706c754246SSudarsana Reddy Kalluru } 15716c754246SSudarsana Reddy Kalluru 15721a635e48SYuval Mintz static void qed_mcp_update_bw(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 15734b01e519SManish Chopra { 15744b01e519SManish Chopra struct qed_mcp_function_info *p_info; 15754b01e519SManish Chopra struct public_func shmem_info; 15764b01e519SManish Chopra u32 resp = 0, param = 0; 15774b01e519SManish Chopra 15781a635e48SYuval Mintz qed_mcp_get_shmem_func(p_hwfn, p_ptt, &shmem_info, MCP_PF_ID(p_hwfn)); 15794b01e519SManish Chopra 15804b01e519SManish Chopra qed_read_pf_bandwidth(p_hwfn, &shmem_info); 15814b01e519SManish Chopra 15824b01e519SManish Chopra p_info = &p_hwfn->mcp_info->func_info; 15834b01e519SManish Chopra 1584a64b02d5SManish Chopra qed_configure_pf_min_bandwidth(p_hwfn->cdev, p_info->bandwidth_min); 15854b01e519SManish Chopra qed_configure_pf_max_bandwidth(p_hwfn->cdev, p_info->bandwidth_max); 15864b01e519SManish Chopra 15874b01e519SManish Chopra /* Acknowledge the MFW */ 15884b01e519SManish Chopra qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_BW_UPDATE_ACK, 0, &resp, 15894b01e519SManish Chopra ¶m); 15904b01e519SManish Chopra } 15914b01e519SManish Chopra 15922a351fd9SMintz, Yuval static void qed_mcp_update_stag(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 15932a351fd9SMintz, Yuval { 15942a351fd9SMintz, Yuval struct public_func shmem_info; 15952a351fd9SMintz, Yuval u32 resp = 0, param = 0; 15962a351fd9SMintz, Yuval 15972a351fd9SMintz, Yuval qed_mcp_get_shmem_func(p_hwfn, p_ptt, &shmem_info, MCP_PF_ID(p_hwfn)); 15982a351fd9SMintz, Yuval 15992a351fd9SMintz, Yuval p_hwfn->mcp_info->func_info.ovlan = (u16)shmem_info.ovlan_stag & 16002a351fd9SMintz, Yuval FUNC_MF_CFG_OV_STAG_MASK; 16012a351fd9SMintz, Yuval p_hwfn->hw_info.ovlan = p_hwfn->mcp_info->func_info.ovlan; 16027e3e375cSSudarsana Reddy Kalluru if (test_bit(QED_MF_OVLAN_CLSS, &p_hwfn->cdev->mf_bits)) { 16037e3e375cSSudarsana Reddy Kalluru if (p_hwfn->hw_info.ovlan != QED_MCP_VLAN_UNSET) { 16047e3e375cSSudarsana Reddy Kalluru qed_wr(p_hwfn, p_ptt, NIG_REG_LLH_FUNC_TAG_VALUE, 16057e3e375cSSudarsana Reddy Kalluru p_hwfn->hw_info.ovlan); 16067e3e375cSSudarsana Reddy Kalluru qed_wr(p_hwfn, p_ptt, NIG_REG_LLH_FUNC_TAG_EN, 1); 16077e3e375cSSudarsana Reddy Kalluru 16087e3e375cSSudarsana Reddy Kalluru /* Configure DB to add external vlan to EDPM packets */ 16097e3e375cSSudarsana Reddy Kalluru qed_wr(p_hwfn, p_ptt, DORQ_REG_TAG1_OVRD_MODE, 1); 16107e3e375cSSudarsana Reddy Kalluru qed_wr(p_hwfn, p_ptt, DORQ_REG_PF_EXT_VID_BB_K2, 16117e3e375cSSudarsana Reddy Kalluru p_hwfn->hw_info.ovlan); 16127e3e375cSSudarsana Reddy Kalluru } else { 16137e3e375cSSudarsana Reddy Kalluru qed_wr(p_hwfn, p_ptt, NIG_REG_LLH_FUNC_TAG_EN, 0); 16147e3e375cSSudarsana Reddy Kalluru qed_wr(p_hwfn, p_ptt, NIG_REG_LLH_FUNC_TAG_VALUE, 0); 16157e3e375cSSudarsana Reddy Kalluru qed_wr(p_hwfn, p_ptt, DORQ_REG_TAG1_OVRD_MODE, 0); 16167e3e375cSSudarsana Reddy Kalluru qed_wr(p_hwfn, p_ptt, DORQ_REG_PF_EXT_VID_BB_K2, 0); 16177e3e375cSSudarsana Reddy Kalluru } 16187e3e375cSSudarsana Reddy Kalluru 16192a351fd9SMintz, Yuval qed_sp_pf_update_stag(p_hwfn); 16202a351fd9SMintz, Yuval } 16212a351fd9SMintz, Yuval 16227e3e375cSSudarsana Reddy Kalluru DP_VERBOSE(p_hwfn, QED_MSG_SP, "ovlan = %d hw_mode = 0x%x\n", 16237e3e375cSSudarsana Reddy Kalluru p_hwfn->mcp_info->func_info.ovlan, p_hwfn->hw_info.hw_mode); 16247e3e375cSSudarsana Reddy Kalluru 16252a351fd9SMintz, Yuval /* Acknowledge the MFW */ 16262a351fd9SMintz, Yuval qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_S_TAG_UPDATE_ACK, 0, 16272a351fd9SMintz, Yuval &resp, ¶m); 16282a351fd9SMintz, Yuval } 16292a351fd9SMintz, Yuval 1630cac6f691SSudarsana Reddy Kalluru void qed_mcp_read_ufp_config(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 1631cac6f691SSudarsana Reddy Kalluru { 1632cac6f691SSudarsana Reddy Kalluru struct public_func shmem_info; 1633cac6f691SSudarsana Reddy Kalluru u32 port_cfg, val; 1634cac6f691SSudarsana Reddy Kalluru 1635cac6f691SSudarsana Reddy Kalluru if (!test_bit(QED_MF_UFP_SPECIFIC, &p_hwfn->cdev->mf_bits)) 1636cac6f691SSudarsana Reddy Kalluru return; 1637cac6f691SSudarsana Reddy Kalluru 1638cac6f691SSudarsana Reddy Kalluru memset(&p_hwfn->ufp_info, 0, sizeof(p_hwfn->ufp_info)); 1639cac6f691SSudarsana Reddy Kalluru port_cfg = qed_rd(p_hwfn, p_ptt, p_hwfn->mcp_info->port_addr + 1640cac6f691SSudarsana Reddy Kalluru offsetof(struct public_port, oem_cfg_port)); 1641cac6f691SSudarsana Reddy Kalluru val = (port_cfg & OEM_CFG_CHANNEL_TYPE_MASK) >> 1642cac6f691SSudarsana Reddy Kalluru OEM_CFG_CHANNEL_TYPE_OFFSET; 1643cac6f691SSudarsana Reddy Kalluru if (val != OEM_CFG_CHANNEL_TYPE_STAGGED) 1644cac6f691SSudarsana Reddy Kalluru DP_NOTICE(p_hwfn, "Incorrect UFP Channel type %d\n", val); 1645cac6f691SSudarsana Reddy Kalluru 1646cac6f691SSudarsana Reddy Kalluru val = (port_cfg & OEM_CFG_SCHED_TYPE_MASK) >> OEM_CFG_SCHED_TYPE_OFFSET; 1647cac6f691SSudarsana Reddy Kalluru if (val == OEM_CFG_SCHED_TYPE_ETS) { 1648cac6f691SSudarsana Reddy Kalluru p_hwfn->ufp_info.mode = QED_UFP_MODE_ETS; 1649cac6f691SSudarsana Reddy Kalluru } else if (val == OEM_CFG_SCHED_TYPE_VNIC_BW) { 1650cac6f691SSudarsana Reddy Kalluru p_hwfn->ufp_info.mode = QED_UFP_MODE_VNIC_BW; 1651cac6f691SSudarsana Reddy Kalluru } else { 1652cac6f691SSudarsana Reddy Kalluru p_hwfn->ufp_info.mode = QED_UFP_MODE_UNKNOWN; 1653cac6f691SSudarsana Reddy Kalluru DP_NOTICE(p_hwfn, "Unknown UFP scheduling mode %d\n", val); 1654cac6f691SSudarsana Reddy Kalluru } 1655cac6f691SSudarsana Reddy Kalluru 1656cac6f691SSudarsana Reddy Kalluru qed_mcp_get_shmem_func(p_hwfn, p_ptt, &shmem_info, MCP_PF_ID(p_hwfn)); 1657b5fabb08SSudarsana Reddy Kalluru val = (shmem_info.oem_cfg_func & OEM_CFG_FUNC_TC_MASK) >> 1658b5fabb08SSudarsana Reddy Kalluru OEM_CFG_FUNC_TC_OFFSET; 1659cac6f691SSudarsana Reddy Kalluru p_hwfn->ufp_info.tc = (u8)val; 1660b5fabb08SSudarsana Reddy Kalluru val = (shmem_info.oem_cfg_func & OEM_CFG_FUNC_HOST_PRI_CTRL_MASK) >> 1661cac6f691SSudarsana Reddy Kalluru OEM_CFG_FUNC_HOST_PRI_CTRL_OFFSET; 1662cac6f691SSudarsana Reddy Kalluru if (val == OEM_CFG_FUNC_HOST_PRI_CTRL_VNIC) { 1663cac6f691SSudarsana Reddy Kalluru p_hwfn->ufp_info.pri_type = QED_UFP_PRI_VNIC; 1664cac6f691SSudarsana Reddy Kalluru } else if (val == OEM_CFG_FUNC_HOST_PRI_CTRL_OS) { 1665cac6f691SSudarsana Reddy Kalluru p_hwfn->ufp_info.pri_type = QED_UFP_PRI_OS; 1666cac6f691SSudarsana Reddy Kalluru } else { 1667cac6f691SSudarsana Reddy Kalluru p_hwfn->ufp_info.pri_type = QED_UFP_PRI_UNKNOWN; 1668cac6f691SSudarsana Reddy Kalluru DP_NOTICE(p_hwfn, "Unknown Host priority control %d\n", val); 1669cac6f691SSudarsana Reddy Kalluru } 1670cac6f691SSudarsana Reddy Kalluru 1671cac6f691SSudarsana Reddy Kalluru DP_NOTICE(p_hwfn, 1672cac6f691SSudarsana Reddy Kalluru "UFP shmem config: mode = %d tc = %d pri_type = %d\n", 1673cac6f691SSudarsana Reddy Kalluru p_hwfn->ufp_info.mode, 1674cac6f691SSudarsana Reddy Kalluru p_hwfn->ufp_info.tc, p_hwfn->ufp_info.pri_type); 1675cac6f691SSudarsana Reddy Kalluru } 1676cac6f691SSudarsana Reddy Kalluru 1677cac6f691SSudarsana Reddy Kalluru static int 1678cac6f691SSudarsana Reddy Kalluru qed_mcp_handle_ufp_event(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 1679cac6f691SSudarsana Reddy Kalluru { 1680cac6f691SSudarsana Reddy Kalluru qed_mcp_read_ufp_config(p_hwfn, p_ptt); 1681cac6f691SSudarsana Reddy Kalluru 1682cac6f691SSudarsana Reddy Kalluru if (p_hwfn->ufp_info.mode == QED_UFP_MODE_VNIC_BW) { 1683cac6f691SSudarsana Reddy Kalluru p_hwfn->qm_info.ooo_tc = p_hwfn->ufp_info.tc; 1684c4259ddaSDenis Bolotin qed_hw_info_set_offload_tc(&p_hwfn->hw_info, 1685c4259ddaSDenis Bolotin p_hwfn->ufp_info.tc); 1686cac6f691SSudarsana Reddy Kalluru 1687cac6f691SSudarsana Reddy Kalluru qed_qm_reconf(p_hwfn, p_ptt); 1688cac6f691SSudarsana Reddy Kalluru } else if (p_hwfn->ufp_info.mode == QED_UFP_MODE_ETS) { 1689cac6f691SSudarsana Reddy Kalluru /* Merge UFP TC with the dcbx TC data */ 1690cac6f691SSudarsana Reddy Kalluru qed_dcbx_mib_update_event(p_hwfn, p_ptt, 1691cac6f691SSudarsana Reddy Kalluru QED_DCBX_OPERATIONAL_MIB); 1692cac6f691SSudarsana Reddy Kalluru } else { 1693cac6f691SSudarsana Reddy Kalluru DP_ERR(p_hwfn, "Invalid sched type, discard the UFP config\n"); 1694cac6f691SSudarsana Reddy Kalluru return -EINVAL; 1695cac6f691SSudarsana Reddy Kalluru } 1696cac6f691SSudarsana Reddy Kalluru 1697cac6f691SSudarsana Reddy Kalluru /* update storm FW with negotiation results */ 1698cac6f691SSudarsana Reddy Kalluru qed_sp_pf_update_ufp(p_hwfn); 1699cac6f691SSudarsana Reddy Kalluru 1700cac6f691SSudarsana Reddy Kalluru /* update stag pcp value */ 1701cac6f691SSudarsana Reddy Kalluru qed_sp_pf_update_stag(p_hwfn); 1702cac6f691SSudarsana Reddy Kalluru 1703cac6f691SSudarsana Reddy Kalluru return 0; 1704cac6f691SSudarsana Reddy Kalluru } 1705cac6f691SSudarsana Reddy Kalluru 1706cc875c2eSYuval Mintz int qed_mcp_handle_events(struct qed_hwfn *p_hwfn, 1707cc875c2eSYuval Mintz struct qed_ptt *p_ptt) 1708cc875c2eSYuval Mintz { 1709cc875c2eSYuval Mintz struct qed_mcp_info *info = p_hwfn->mcp_info; 1710cc875c2eSYuval Mintz int rc = 0; 1711cc875c2eSYuval Mintz bool found = false; 1712cc875c2eSYuval Mintz u16 i; 1713cc875c2eSYuval Mintz 1714cc875c2eSYuval Mintz DP_VERBOSE(p_hwfn, QED_MSG_SP, "Received message from MFW\n"); 1715cc875c2eSYuval Mintz 1716cc875c2eSYuval Mintz /* Read Messages from MFW */ 1717cc875c2eSYuval Mintz qed_mcp_read_mb(p_hwfn, p_ptt); 1718cc875c2eSYuval Mintz 1719cc875c2eSYuval Mintz /* Compare current messages to old ones */ 1720cc875c2eSYuval Mintz for (i = 0; i < info->mfw_mb_length; i++) { 1721cc875c2eSYuval Mintz if (info->mfw_mb_cur[i] == info->mfw_mb_shadow[i]) 1722cc875c2eSYuval Mintz continue; 1723cc875c2eSYuval Mintz 1724cc875c2eSYuval Mintz found = true; 1725cc875c2eSYuval Mintz 1726cc875c2eSYuval Mintz DP_VERBOSE(p_hwfn, NETIF_MSG_LINK, 1727cc875c2eSYuval Mintz "Msg [%d] - old CMD 0x%02x, new CMD 0x%02x\n", 1728cc875c2eSYuval Mintz i, info->mfw_mb_shadow[i], info->mfw_mb_cur[i]); 1729cc875c2eSYuval Mintz 1730cc875c2eSYuval Mintz switch (i) { 1731cc875c2eSYuval Mintz case MFW_DRV_MSG_LINK_CHANGE: 1732cc875c2eSYuval Mintz qed_mcp_handle_link_change(p_hwfn, p_ptt, false); 1733cc875c2eSYuval Mintz break; 17340b55e27dSYuval Mintz case MFW_DRV_MSG_VF_DISABLED: 17350b55e27dSYuval Mintz qed_mcp_handle_vf_flr(p_hwfn, p_ptt); 17360b55e27dSYuval Mintz break; 173739651abdSSudarsana Reddy Kalluru case MFW_DRV_MSG_LLDP_DATA_UPDATED: 173839651abdSSudarsana Reddy Kalluru qed_dcbx_mib_update_event(p_hwfn, p_ptt, 173939651abdSSudarsana Reddy Kalluru QED_DCBX_REMOTE_LLDP_MIB); 174039651abdSSudarsana Reddy Kalluru break; 174139651abdSSudarsana Reddy Kalluru case MFW_DRV_MSG_DCBX_REMOTE_MIB_UPDATED: 174239651abdSSudarsana Reddy Kalluru qed_dcbx_mib_update_event(p_hwfn, p_ptt, 174339651abdSSudarsana Reddy Kalluru QED_DCBX_REMOTE_MIB); 174439651abdSSudarsana Reddy Kalluru break; 174539651abdSSudarsana Reddy Kalluru case MFW_DRV_MSG_DCBX_OPERATIONAL_MIB_UPDATED: 174639651abdSSudarsana Reddy Kalluru qed_dcbx_mib_update_event(p_hwfn, p_ptt, 174739651abdSSudarsana Reddy Kalluru QED_DCBX_OPERATIONAL_MIB); 174839651abdSSudarsana Reddy Kalluru break; 1749cac6f691SSudarsana Reddy Kalluru case MFW_DRV_MSG_OEM_CFG_UPDATE: 1750cac6f691SSudarsana Reddy Kalluru qed_mcp_handle_ufp_event(p_hwfn, p_ptt); 1751cac6f691SSudarsana Reddy Kalluru break; 1752334c03b5SZvi Nachmani case MFW_DRV_MSG_TRANSCEIVER_STATE_CHANGE: 1753334c03b5SZvi Nachmani qed_mcp_handle_transceiver_change(p_hwfn, p_ptt); 1754334c03b5SZvi Nachmani break; 17556c754246SSudarsana Reddy Kalluru case MFW_DRV_MSG_GET_LAN_STATS: 17566c754246SSudarsana Reddy Kalluru case MFW_DRV_MSG_GET_FCOE_STATS: 17576c754246SSudarsana Reddy Kalluru case MFW_DRV_MSG_GET_ISCSI_STATS: 17586c754246SSudarsana Reddy Kalluru case MFW_DRV_MSG_GET_RDMA_STATS: 17596c754246SSudarsana Reddy Kalluru qed_mcp_send_protocol_stats(p_hwfn, p_ptt, i); 17606c754246SSudarsana Reddy Kalluru break; 17614b01e519SManish Chopra case MFW_DRV_MSG_BW_UPDATE: 17624b01e519SManish Chopra qed_mcp_update_bw(p_hwfn, p_ptt); 17634b01e519SManish Chopra break; 17642a351fd9SMintz, Yuval case MFW_DRV_MSG_S_TAG_UPDATE: 17652a351fd9SMintz, Yuval qed_mcp_update_stag(p_hwfn, p_ptt); 17662a351fd9SMintz, Yuval break; 176759ccf86fSSudarsana Reddy Kalluru case MFW_DRV_MSG_GET_TLV_REQ: 176859ccf86fSSudarsana Reddy Kalluru qed_mfw_tlv_req(p_hwfn); 17692a351fd9SMintz, Yuval break; 1770cc875c2eSYuval Mintz default: 177139815944SMintz, Yuval DP_INFO(p_hwfn, "Unimplemented MFW message %d\n", i); 1772cc875c2eSYuval Mintz rc = -EINVAL; 1773cc875c2eSYuval Mintz } 1774cc875c2eSYuval Mintz } 1775cc875c2eSYuval Mintz 1776cc875c2eSYuval Mintz /* ACK everything */ 1777cc875c2eSYuval Mintz for (i = 0; i < MFW_DRV_MSG_MAX_DWORDS(info->mfw_mb_length); i++) { 1778cc875c2eSYuval Mintz __be32 val = cpu_to_be32(((u32 *)info->mfw_mb_cur)[i]); 1779cc875c2eSYuval Mintz 1780cc875c2eSYuval Mintz /* MFW expect answer in BE, so we force write in that format */ 1781cc875c2eSYuval Mintz qed_wr(p_hwfn, p_ptt, 1782cc875c2eSYuval Mintz info->mfw_mb_addr + sizeof(u32) + 1783cc875c2eSYuval Mintz MFW_DRV_MSG_MAX_DWORDS(info->mfw_mb_length) * 1784cc875c2eSYuval Mintz sizeof(u32) + i * sizeof(u32), 1785cc875c2eSYuval Mintz (__force u32)val); 1786cc875c2eSYuval Mintz } 1787cc875c2eSYuval Mintz 1788cc875c2eSYuval Mintz if (!found) { 1789cc875c2eSYuval Mintz DP_NOTICE(p_hwfn, 1790cc875c2eSYuval Mintz "Received an MFW message indication but no new message!\n"); 1791cc875c2eSYuval Mintz rc = -EINVAL; 1792cc875c2eSYuval Mintz } 1793cc875c2eSYuval Mintz 1794cc875c2eSYuval Mintz /* Copy the new mfw messages into the shadow */ 1795cc875c2eSYuval Mintz memcpy(info->mfw_mb_shadow, info->mfw_mb_cur, info->mfw_mb_length); 1796cc875c2eSYuval Mintz 1797cc875c2eSYuval Mintz return rc; 1798cc875c2eSYuval Mintz } 1799cc875c2eSYuval Mintz 18001408cc1fSYuval Mintz int qed_mcp_get_mfw_ver(struct qed_hwfn *p_hwfn, 18011408cc1fSYuval Mintz struct qed_ptt *p_ptt, 18021408cc1fSYuval Mintz u32 *p_mfw_ver, u32 *p_running_bundle_id) 1803fe56b9e6SYuval Mintz { 1804fe56b9e6SYuval Mintz u32 global_offsize; 1805fe56b9e6SYuval Mintz 18061408cc1fSYuval Mintz if (IS_VF(p_hwfn->cdev)) { 18071408cc1fSYuval Mintz if (p_hwfn->vf_iov_info) { 18081408cc1fSYuval Mintz struct pfvf_acquire_resp_tlv *p_resp; 18091408cc1fSYuval Mintz 18101408cc1fSYuval Mintz p_resp = &p_hwfn->vf_iov_info->acquire_resp; 18111408cc1fSYuval Mintz *p_mfw_ver = p_resp->pfdev_info.mfw_ver; 18121408cc1fSYuval Mintz return 0; 18131408cc1fSYuval Mintz } else { 18141408cc1fSYuval Mintz DP_VERBOSE(p_hwfn, 18151408cc1fSYuval Mintz QED_MSG_IOV, 18161408cc1fSYuval Mintz "VF requested MFW version prior to ACQUIRE\n"); 18171408cc1fSYuval Mintz return -EINVAL; 18181408cc1fSYuval Mintz } 18191408cc1fSYuval Mintz } 1820fe56b9e6SYuval Mintz 1821fe56b9e6SYuval Mintz global_offsize = qed_rd(p_hwfn, p_ptt, 18221408cc1fSYuval Mintz SECTION_OFFSIZE_ADDR(p_hwfn-> 18231408cc1fSYuval Mintz mcp_info->public_base, 1824fe56b9e6SYuval Mintz PUBLIC_GLOBAL)); 18251408cc1fSYuval Mintz *p_mfw_ver = 18261408cc1fSYuval Mintz qed_rd(p_hwfn, p_ptt, 18271408cc1fSYuval Mintz SECTION_ADDR(global_offsize, 18281408cc1fSYuval Mintz 0) + offsetof(struct public_global, mfw_ver)); 1829fe56b9e6SYuval Mintz 18301408cc1fSYuval Mintz if (p_running_bundle_id != NULL) { 18311408cc1fSYuval Mintz *p_running_bundle_id = qed_rd(p_hwfn, p_ptt, 18321408cc1fSYuval Mintz SECTION_ADDR(global_offsize, 0) + 18331408cc1fSYuval Mintz offsetof(struct public_global, 18341408cc1fSYuval Mintz running_bundle_id)); 18351408cc1fSYuval Mintz } 1836fe56b9e6SYuval Mintz 1837fe56b9e6SYuval Mintz return 0; 1838fe56b9e6SYuval Mintz } 1839fe56b9e6SYuval Mintz 1840ae33666aSTomer Tayar int qed_mcp_get_mbi_ver(struct qed_hwfn *p_hwfn, 1841ae33666aSTomer Tayar struct qed_ptt *p_ptt, u32 *p_mbi_ver) 1842ae33666aSTomer Tayar { 1843ae33666aSTomer Tayar u32 nvm_cfg_addr, nvm_cfg1_offset, mbi_ver_addr; 1844ae33666aSTomer Tayar 1845ae33666aSTomer Tayar if (IS_VF(p_hwfn->cdev)) 1846ae33666aSTomer Tayar return -EINVAL; 1847ae33666aSTomer Tayar 1848ae33666aSTomer Tayar /* Read the address of the nvm_cfg */ 1849ae33666aSTomer Tayar nvm_cfg_addr = qed_rd(p_hwfn, p_ptt, MISC_REG_GEN_PURP_CR0); 1850ae33666aSTomer Tayar if (!nvm_cfg_addr) { 1851ae33666aSTomer Tayar DP_NOTICE(p_hwfn, "Shared memory not initialized\n"); 1852ae33666aSTomer Tayar return -EINVAL; 1853ae33666aSTomer Tayar } 1854ae33666aSTomer Tayar 1855ae33666aSTomer Tayar /* Read the offset of nvm_cfg1 */ 1856ae33666aSTomer Tayar nvm_cfg1_offset = qed_rd(p_hwfn, p_ptt, nvm_cfg_addr + 4); 1857ae33666aSTomer Tayar 1858ae33666aSTomer Tayar mbi_ver_addr = MCP_REG_SCRATCH + nvm_cfg1_offset + 1859ae33666aSTomer Tayar offsetof(struct nvm_cfg1, glob) + 1860ae33666aSTomer Tayar offsetof(struct nvm_cfg1_glob, mbi_version); 1861ae33666aSTomer Tayar *p_mbi_ver = qed_rd(p_hwfn, p_ptt, 1862ae33666aSTomer Tayar mbi_ver_addr) & 1863ae33666aSTomer Tayar (NVM_CFG1_GLOB_MBI_VERSION_0_MASK | 1864ae33666aSTomer Tayar NVM_CFG1_GLOB_MBI_VERSION_1_MASK | 1865ae33666aSTomer Tayar NVM_CFG1_GLOB_MBI_VERSION_2_MASK); 1866ae33666aSTomer Tayar 1867ae33666aSTomer Tayar return 0; 1868ae33666aSTomer Tayar } 1869ae33666aSTomer Tayar 1870706d0891SRahul Verma int qed_mcp_get_media_type(struct qed_hwfn *p_hwfn, 1871706d0891SRahul Verma struct qed_ptt *p_ptt, u32 *p_media_type) 1872cc875c2eSYuval Mintz { 1873706d0891SRahul Verma if (IS_VF(p_hwfn->cdev)) 18741408cc1fSYuval Mintz return -EINVAL; 18751408cc1fSYuval Mintz 1876cc875c2eSYuval Mintz if (!qed_mcp_is_init(p_hwfn)) { 1877cc875c2eSYuval Mintz DP_NOTICE(p_hwfn, "MFW is not initialized!\n"); 1878cc875c2eSYuval Mintz return -EBUSY; 1879cc875c2eSYuval Mintz } 1880cc875c2eSYuval Mintz 1881706d0891SRahul Verma if (!p_ptt) { 1882cc875c2eSYuval Mintz *p_media_type = MEDIA_UNSPECIFIED; 1883706d0891SRahul Verma return -EINVAL; 1884706d0891SRahul Verma } 1885cc875c2eSYuval Mintz 1886706d0891SRahul Verma *p_media_type = qed_rd(p_hwfn, p_ptt, 1887706d0891SRahul Verma p_hwfn->mcp_info->port_addr + 1888706d0891SRahul Verma offsetof(struct public_port, 1889706d0891SRahul Verma media_type)); 1890cc875c2eSYuval Mintz 1891cc875c2eSYuval Mintz return 0; 1892cc875c2eSYuval Mintz } 1893cc875c2eSYuval Mintz 18946927e826SMintz, Yuval /* Old MFW has a global configuration for all PFs regarding RDMA support */ 18956927e826SMintz, Yuval static void 18966927e826SMintz, Yuval qed_mcp_get_shmem_proto_legacy(struct qed_hwfn *p_hwfn, 18976927e826SMintz, Yuval enum qed_pci_personality *p_proto) 18986927e826SMintz, Yuval { 18996927e826SMintz, Yuval /* There wasn't ever a legacy MFW that published iwarp. 19006927e826SMintz, Yuval * So at this point, this is either plain l2 or RoCE. 19016927e826SMintz, Yuval */ 19026927e826SMintz, Yuval if (test_bit(QED_DEV_CAP_ROCE, &p_hwfn->hw_info.device_capabilities)) 19036927e826SMintz, Yuval *p_proto = QED_PCI_ETH_ROCE; 19046927e826SMintz, Yuval else 19056927e826SMintz, Yuval *p_proto = QED_PCI_ETH; 19066927e826SMintz, Yuval 19076927e826SMintz, Yuval DP_VERBOSE(p_hwfn, NETIF_MSG_IFUP, 19086927e826SMintz, Yuval "According to Legacy capabilities, L2 personality is %08x\n", 19096927e826SMintz, Yuval (u32) *p_proto); 19106927e826SMintz, Yuval } 19116927e826SMintz, Yuval 19126927e826SMintz, Yuval static int 19136927e826SMintz, Yuval qed_mcp_get_shmem_proto_mfw(struct qed_hwfn *p_hwfn, 19146927e826SMintz, Yuval struct qed_ptt *p_ptt, 19156927e826SMintz, Yuval enum qed_pci_personality *p_proto) 19166927e826SMintz, Yuval { 19176927e826SMintz, Yuval u32 resp = 0, param = 0; 19186927e826SMintz, Yuval int rc; 19196927e826SMintz, Yuval 19206927e826SMintz, Yuval rc = qed_mcp_cmd(p_hwfn, p_ptt, 19216927e826SMintz, Yuval DRV_MSG_CODE_GET_PF_RDMA_PROTOCOL, 0, &resp, ¶m); 19226927e826SMintz, Yuval if (rc) 19236927e826SMintz, Yuval return rc; 19246927e826SMintz, Yuval if (resp != FW_MSG_CODE_OK) { 19256927e826SMintz, Yuval DP_VERBOSE(p_hwfn, NETIF_MSG_IFUP, 19266927e826SMintz, Yuval "MFW lacks support for command; Returns %08x\n", 19276927e826SMintz, Yuval resp); 19286927e826SMintz, Yuval return -EINVAL; 19296927e826SMintz, Yuval } 19306927e826SMintz, Yuval 19316927e826SMintz, Yuval switch (param) { 19326927e826SMintz, Yuval case FW_MB_PARAM_GET_PF_RDMA_NONE: 19336927e826SMintz, Yuval *p_proto = QED_PCI_ETH; 19346927e826SMintz, Yuval break; 19356927e826SMintz, Yuval case FW_MB_PARAM_GET_PF_RDMA_ROCE: 19366927e826SMintz, Yuval *p_proto = QED_PCI_ETH_ROCE; 19376927e826SMintz, Yuval break; 19386927e826SMintz, Yuval case FW_MB_PARAM_GET_PF_RDMA_IWARP: 1939e0a8f9deSMichal Kalderon *p_proto = QED_PCI_ETH_IWARP; 1940e0a8f9deSMichal Kalderon break; 1941e0a8f9deSMichal Kalderon case FW_MB_PARAM_GET_PF_RDMA_BOTH: 1942e0a8f9deSMichal Kalderon *p_proto = QED_PCI_ETH_RDMA; 1943e0a8f9deSMichal Kalderon break; 19446927e826SMintz, Yuval default: 19456927e826SMintz, Yuval DP_NOTICE(p_hwfn, 19466927e826SMintz, Yuval "MFW answers GET_PF_RDMA_PROTOCOL but param is %08x\n", 19476927e826SMintz, Yuval param); 19486927e826SMintz, Yuval return -EINVAL; 19496927e826SMintz, Yuval } 19506927e826SMintz, Yuval 19516927e826SMintz, Yuval DP_VERBOSE(p_hwfn, 19526927e826SMintz, Yuval NETIF_MSG_IFUP, 19536927e826SMintz, Yuval "According to capabilities, L2 personality is %08x [resp %08x param %08x]\n", 19546927e826SMintz, Yuval (u32) *p_proto, resp, param); 19556927e826SMintz, Yuval return 0; 19566927e826SMintz, Yuval } 19576927e826SMintz, Yuval 1958fe56b9e6SYuval Mintz static int 1959fe56b9e6SYuval Mintz qed_mcp_get_shmem_proto(struct qed_hwfn *p_hwfn, 1960fe56b9e6SYuval Mintz struct public_func *p_info, 19616927e826SMintz, Yuval struct qed_ptt *p_ptt, 1962fe56b9e6SYuval Mintz enum qed_pci_personality *p_proto) 1963fe56b9e6SYuval Mintz { 1964fe56b9e6SYuval Mintz int rc = 0; 1965fe56b9e6SYuval Mintz 1966fe56b9e6SYuval Mintz switch (p_info->config & FUNC_MF_CFG_PROTOCOL_MASK) { 1967fe56b9e6SYuval Mintz case FUNC_MF_CFG_PROTOCOL_ETHERNET: 19681fe582ecSRam Amrani if (!IS_ENABLED(CONFIG_QED_RDMA)) 19691fe582ecSRam Amrani *p_proto = QED_PCI_ETH; 19701fe582ecSRam Amrani else if (qed_mcp_get_shmem_proto_mfw(p_hwfn, p_ptt, p_proto)) 19716927e826SMintz, Yuval qed_mcp_get_shmem_proto_legacy(p_hwfn, p_proto); 1972fe56b9e6SYuval Mintz break; 1973c5ac9319SYuval Mintz case FUNC_MF_CFG_PROTOCOL_ISCSI: 1974c5ac9319SYuval Mintz *p_proto = QED_PCI_ISCSI; 1975c5ac9319SYuval Mintz break; 19761e128c81SArun Easi case FUNC_MF_CFG_PROTOCOL_FCOE: 19771e128c81SArun Easi *p_proto = QED_PCI_FCOE; 19781e128c81SArun Easi break; 1979c5ac9319SYuval Mintz case FUNC_MF_CFG_PROTOCOL_ROCE: 1980c5ac9319SYuval Mintz DP_NOTICE(p_hwfn, "RoCE personality is not a valid value!\n"); 19816927e826SMintz, Yuval /* Fallthrough */ 1982fe56b9e6SYuval Mintz default: 1983fe56b9e6SYuval Mintz rc = -EINVAL; 1984fe56b9e6SYuval Mintz } 1985fe56b9e6SYuval Mintz 1986fe56b9e6SYuval Mintz return rc; 1987fe56b9e6SYuval Mintz } 1988fe56b9e6SYuval Mintz 1989fe56b9e6SYuval Mintz int qed_mcp_fill_shmem_func_info(struct qed_hwfn *p_hwfn, 1990fe56b9e6SYuval Mintz struct qed_ptt *p_ptt) 1991fe56b9e6SYuval Mintz { 1992fe56b9e6SYuval Mintz struct qed_mcp_function_info *info; 1993fe56b9e6SYuval Mintz struct public_func shmem_info; 1994fe56b9e6SYuval Mintz 19951a635e48SYuval Mintz qed_mcp_get_shmem_func(p_hwfn, p_ptt, &shmem_info, MCP_PF_ID(p_hwfn)); 1996fe56b9e6SYuval Mintz info = &p_hwfn->mcp_info->func_info; 1997fe56b9e6SYuval Mintz 1998fe56b9e6SYuval Mintz info->pause_on_host = (shmem_info.config & 1999fe56b9e6SYuval Mintz FUNC_MF_CFG_PAUSE_ON_HOST_RING) ? 1 : 0; 2000fe56b9e6SYuval Mintz 20016927e826SMintz, Yuval if (qed_mcp_get_shmem_proto(p_hwfn, &shmem_info, p_ptt, 20026927e826SMintz, Yuval &info->protocol)) { 2003fe56b9e6SYuval Mintz DP_ERR(p_hwfn, "Unknown personality %08x\n", 2004fe56b9e6SYuval Mintz (u32)(shmem_info.config & FUNC_MF_CFG_PROTOCOL_MASK)); 2005fe56b9e6SYuval Mintz return -EINVAL; 2006fe56b9e6SYuval Mintz } 2007fe56b9e6SYuval Mintz 20084b01e519SManish Chopra qed_read_pf_bandwidth(p_hwfn, &shmem_info); 2009fe56b9e6SYuval Mintz 2010fe56b9e6SYuval Mintz if (shmem_info.mac_upper || shmem_info.mac_lower) { 2011fe56b9e6SYuval Mintz info->mac[0] = (u8)(shmem_info.mac_upper >> 8); 2012fe56b9e6SYuval Mintz info->mac[1] = (u8)(shmem_info.mac_upper); 2013fe56b9e6SYuval Mintz info->mac[2] = (u8)(shmem_info.mac_lower >> 24); 2014fe56b9e6SYuval Mintz info->mac[3] = (u8)(shmem_info.mac_lower >> 16); 2015fe56b9e6SYuval Mintz info->mac[4] = (u8)(shmem_info.mac_lower >> 8); 2016fe56b9e6SYuval Mintz info->mac[5] = (u8)(shmem_info.mac_lower); 201714d39648SMintz, Yuval 201814d39648SMintz, Yuval /* Store primary MAC for later possible WoL */ 201914d39648SMintz, Yuval memcpy(&p_hwfn->cdev->wol_mac, info->mac, ETH_ALEN); 2020fe56b9e6SYuval Mintz } else { 2021fe56b9e6SYuval Mintz DP_NOTICE(p_hwfn, "MAC is 0 in shmem\n"); 2022fe56b9e6SYuval Mintz } 2023fe56b9e6SYuval Mintz 202457796759SMintz, Yuval info->wwn_port = (u64)shmem_info.fcoe_wwn_port_name_lower | 202557796759SMintz, Yuval (((u64)shmem_info.fcoe_wwn_port_name_upper) << 32); 202657796759SMintz, Yuval info->wwn_node = (u64)shmem_info.fcoe_wwn_node_name_lower | 202757796759SMintz, Yuval (((u64)shmem_info.fcoe_wwn_node_name_upper) << 32); 2028fe56b9e6SYuval Mintz 2029fe56b9e6SYuval Mintz info->ovlan = (u16)(shmem_info.ovlan_stag & FUNC_MF_CFG_OV_STAG_MASK); 2030fe56b9e6SYuval Mintz 20310fefbfbaSSudarsana Kalluru info->mtu = (u16)shmem_info.mtu_size; 20320fefbfbaSSudarsana Kalluru 203314d39648SMintz, Yuval p_hwfn->hw_info.b_wol_support = QED_WOL_SUPPORT_NONE; 203414d39648SMintz, Yuval p_hwfn->cdev->wol_config = (u8)QED_OV_WOL_DEFAULT; 203514d39648SMintz, Yuval if (qed_mcp_is_init(p_hwfn)) { 203614d39648SMintz, Yuval u32 resp = 0, param = 0; 203714d39648SMintz, Yuval int rc; 203814d39648SMintz, Yuval 203914d39648SMintz, Yuval rc = qed_mcp_cmd(p_hwfn, p_ptt, 204014d39648SMintz, Yuval DRV_MSG_CODE_OS_WOL, 0, &resp, ¶m); 204114d39648SMintz, Yuval if (rc) 204214d39648SMintz, Yuval return rc; 204314d39648SMintz, Yuval if (resp == FW_MSG_CODE_OS_WOL_SUPPORTED) 204414d39648SMintz, Yuval p_hwfn->hw_info.b_wol_support = QED_WOL_SUPPORT_PME; 204514d39648SMintz, Yuval } 204614d39648SMintz, Yuval 2047fe56b9e6SYuval Mintz DP_VERBOSE(p_hwfn, (QED_MSG_SP | NETIF_MSG_IFUP), 204814d39648SMintz, 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", 2049fe56b9e6SYuval Mintz info->pause_on_host, info->protocol, 2050fe56b9e6SYuval Mintz info->bandwidth_min, info->bandwidth_max, 2051fe56b9e6SYuval Mintz info->mac[0], info->mac[1], info->mac[2], 2052fe56b9e6SYuval Mintz info->mac[3], info->mac[4], info->mac[5], 205314d39648SMintz, Yuval info->wwn_port, info->wwn_node, 205414d39648SMintz, Yuval info->ovlan, (u8)p_hwfn->hw_info.b_wol_support); 2055fe56b9e6SYuval Mintz 2056fe56b9e6SYuval Mintz return 0; 2057fe56b9e6SYuval Mintz } 2058fe56b9e6SYuval Mintz 2059cc875c2eSYuval Mintz struct qed_mcp_link_params 2060cc875c2eSYuval Mintz *qed_mcp_get_link_params(struct qed_hwfn *p_hwfn) 2061cc875c2eSYuval Mintz { 2062cc875c2eSYuval Mintz if (!p_hwfn || !p_hwfn->mcp_info) 2063cc875c2eSYuval Mintz return NULL; 2064cc875c2eSYuval Mintz return &p_hwfn->mcp_info->link_input; 2065cc875c2eSYuval Mintz } 2066cc875c2eSYuval Mintz 2067cc875c2eSYuval Mintz struct qed_mcp_link_state 2068cc875c2eSYuval Mintz *qed_mcp_get_link_state(struct qed_hwfn *p_hwfn) 2069cc875c2eSYuval Mintz { 2070cc875c2eSYuval Mintz if (!p_hwfn || !p_hwfn->mcp_info) 2071cc875c2eSYuval Mintz return NULL; 2072cc875c2eSYuval Mintz return &p_hwfn->mcp_info->link_output; 2073cc875c2eSYuval Mintz } 2074cc875c2eSYuval Mintz 2075cc875c2eSYuval Mintz struct qed_mcp_link_capabilities 2076cc875c2eSYuval Mintz *qed_mcp_get_link_capabilities(struct qed_hwfn *p_hwfn) 2077cc875c2eSYuval Mintz { 2078cc875c2eSYuval Mintz if (!p_hwfn || !p_hwfn->mcp_info) 2079cc875c2eSYuval Mintz return NULL; 2080cc875c2eSYuval Mintz return &p_hwfn->mcp_info->link_capabilities; 2081cc875c2eSYuval Mintz } 2082cc875c2eSYuval Mintz 20831a635e48SYuval Mintz int qed_mcp_drain(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 2084fe56b9e6SYuval Mintz { 2085fe56b9e6SYuval Mintz u32 resp = 0, param = 0; 2086fe56b9e6SYuval Mintz int rc; 2087fe56b9e6SYuval Mintz 2088fe56b9e6SYuval Mintz rc = qed_mcp_cmd(p_hwfn, p_ptt, 20891a635e48SYuval Mintz DRV_MSG_CODE_NIG_DRAIN, 1000, &resp, ¶m); 2090fe56b9e6SYuval Mintz 2091fe56b9e6SYuval Mintz /* Wait for the drain to complete before returning */ 20928f60bafeSYuval Mintz msleep(1020); 2093fe56b9e6SYuval Mintz 2094fe56b9e6SYuval Mintz return rc; 2095fe56b9e6SYuval Mintz } 2096fe56b9e6SYuval Mintz 2097cee4d264SManish Chopra int qed_mcp_get_flash_size(struct qed_hwfn *p_hwfn, 20981a635e48SYuval Mintz struct qed_ptt *p_ptt, u32 *p_flash_size) 2099cee4d264SManish Chopra { 2100cee4d264SManish Chopra u32 flash_size; 2101cee4d264SManish Chopra 21021408cc1fSYuval Mintz if (IS_VF(p_hwfn->cdev)) 21031408cc1fSYuval Mintz return -EINVAL; 21041408cc1fSYuval Mintz 2105cee4d264SManish Chopra flash_size = qed_rd(p_hwfn, p_ptt, MCP_REG_NVM_CFG4); 2106cee4d264SManish Chopra flash_size = (flash_size & MCP_REG_NVM_CFG4_FLASH_SIZE) >> 2107cee4d264SManish Chopra MCP_REG_NVM_CFG4_FLASH_SIZE_SHIFT; 2108cee4d264SManish Chopra flash_size = (1 << (flash_size + MCP_BYTES_PER_MBIT_SHIFT)); 2109cee4d264SManish Chopra 2110cee4d264SManish Chopra *p_flash_size = flash_size; 2111cee4d264SManish Chopra 2112cee4d264SManish Chopra return 0; 2113cee4d264SManish Chopra } 2114cee4d264SManish Chopra 211588072fd4SMintz, Yuval static int 211688072fd4SMintz, Yuval qed_mcp_config_vf_msix_bb(struct qed_hwfn *p_hwfn, 21171408cc1fSYuval Mintz struct qed_ptt *p_ptt, u8 vf_id, u8 num) 21181408cc1fSYuval Mintz { 21191408cc1fSYuval Mintz u32 resp = 0, param = 0, rc_param = 0; 21201408cc1fSYuval Mintz int rc; 21211408cc1fSYuval Mintz 21221408cc1fSYuval Mintz /* Only Leader can configure MSIX, and need to take CMT into account */ 21231408cc1fSYuval Mintz if (!IS_LEAD_HWFN(p_hwfn)) 21241408cc1fSYuval Mintz return 0; 21251408cc1fSYuval Mintz num *= p_hwfn->cdev->num_hwfns; 21261408cc1fSYuval Mintz 21271408cc1fSYuval Mintz param |= (vf_id << DRV_MB_PARAM_CFG_VF_MSIX_VF_ID_SHIFT) & 21281408cc1fSYuval Mintz DRV_MB_PARAM_CFG_VF_MSIX_VF_ID_MASK; 21291408cc1fSYuval Mintz param |= (num << DRV_MB_PARAM_CFG_VF_MSIX_SB_NUM_SHIFT) & 21301408cc1fSYuval Mintz DRV_MB_PARAM_CFG_VF_MSIX_SB_NUM_MASK; 21311408cc1fSYuval Mintz 21321408cc1fSYuval Mintz rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_CFG_VF_MSIX, param, 21331408cc1fSYuval Mintz &resp, &rc_param); 21341408cc1fSYuval Mintz 21351408cc1fSYuval Mintz if (resp != FW_MSG_CODE_DRV_CFG_VF_MSIX_DONE) { 21361408cc1fSYuval Mintz DP_NOTICE(p_hwfn, "VF[%d]: MFW failed to set MSI-X\n", vf_id); 21371408cc1fSYuval Mintz rc = -EINVAL; 21381408cc1fSYuval Mintz } else { 21391408cc1fSYuval Mintz DP_VERBOSE(p_hwfn, QED_MSG_IOV, 21401408cc1fSYuval Mintz "Requested 0x%02x MSI-x interrupts from VF 0x%02x\n", 21411408cc1fSYuval Mintz num, vf_id); 21421408cc1fSYuval Mintz } 21431408cc1fSYuval Mintz 21441408cc1fSYuval Mintz return rc; 21451408cc1fSYuval Mintz } 21461408cc1fSYuval Mintz 214788072fd4SMintz, Yuval static int 214888072fd4SMintz, Yuval qed_mcp_config_vf_msix_ah(struct qed_hwfn *p_hwfn, 214988072fd4SMintz, Yuval struct qed_ptt *p_ptt, u8 num) 215088072fd4SMintz, Yuval { 215188072fd4SMintz, Yuval u32 resp = 0, param = num, rc_param = 0; 215288072fd4SMintz, Yuval int rc; 215388072fd4SMintz, Yuval 215488072fd4SMintz, Yuval rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_CFG_PF_VFS_MSIX, 215588072fd4SMintz, Yuval param, &resp, &rc_param); 215688072fd4SMintz, Yuval 215788072fd4SMintz, Yuval if (resp != FW_MSG_CODE_DRV_CFG_PF_VFS_MSIX_DONE) { 215888072fd4SMintz, Yuval DP_NOTICE(p_hwfn, "MFW failed to set MSI-X for VFs\n"); 215988072fd4SMintz, Yuval rc = -EINVAL; 216088072fd4SMintz, Yuval } else { 216188072fd4SMintz, Yuval DP_VERBOSE(p_hwfn, QED_MSG_IOV, 216288072fd4SMintz, Yuval "Requested 0x%02x MSI-x interrupts for VFs\n", num); 216388072fd4SMintz, Yuval } 216488072fd4SMintz, Yuval 216588072fd4SMintz, Yuval return rc; 216688072fd4SMintz, Yuval } 216788072fd4SMintz, Yuval 216888072fd4SMintz, Yuval int qed_mcp_config_vf_msix(struct qed_hwfn *p_hwfn, 216988072fd4SMintz, Yuval struct qed_ptt *p_ptt, u8 vf_id, u8 num) 217088072fd4SMintz, Yuval { 217188072fd4SMintz, Yuval if (QED_IS_BB(p_hwfn->cdev)) 217288072fd4SMintz, Yuval return qed_mcp_config_vf_msix_bb(p_hwfn, p_ptt, vf_id, num); 217388072fd4SMintz, Yuval else 217488072fd4SMintz, Yuval return qed_mcp_config_vf_msix_ah(p_hwfn, p_ptt, num); 217588072fd4SMintz, Yuval } 217688072fd4SMintz, Yuval 2177fe56b9e6SYuval Mintz int 2178fe56b9e6SYuval Mintz qed_mcp_send_drv_version(struct qed_hwfn *p_hwfn, 2179fe56b9e6SYuval Mintz struct qed_ptt *p_ptt, 2180fe56b9e6SYuval Mintz struct qed_mcp_drv_version *p_ver) 2181fe56b9e6SYuval Mintz { 21825529bad9STomer Tayar struct qed_mcp_mb_params mb_params; 21832f67af8cSTomer Tayar struct drv_version_stc drv_version; 21845529bad9STomer Tayar __be32 val; 21855529bad9STomer Tayar u32 i; 21865529bad9STomer Tayar int rc; 2187fe56b9e6SYuval Mintz 21882f67af8cSTomer Tayar memset(&drv_version, 0, sizeof(drv_version)); 21892f67af8cSTomer Tayar drv_version.version = p_ver->version; 219067a99b70SYuval Mintz for (i = 0; i < (MCP_DRV_VER_STR_SIZE - 4) / sizeof(u32); i++) { 219167a99b70SYuval Mintz val = cpu_to_be32(*((u32 *)&p_ver->name[i * sizeof(u32)])); 21922f67af8cSTomer Tayar *(__be32 *)&drv_version.name[i * sizeof(u32)] = val; 2193fe56b9e6SYuval Mintz } 2194fe56b9e6SYuval Mintz 21955529bad9STomer Tayar memset(&mb_params, 0, sizeof(mb_params)); 21965529bad9STomer Tayar mb_params.cmd = DRV_MSG_CODE_SET_VERSION; 21972f67af8cSTomer Tayar mb_params.p_data_src = &drv_version; 21982f67af8cSTomer Tayar mb_params.data_src_size = sizeof(drv_version); 21995529bad9STomer Tayar rc = qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 22005529bad9STomer Tayar if (rc) 2201fe56b9e6SYuval Mintz DP_ERR(p_hwfn, "MCP response failure, aborting\n"); 2202fe56b9e6SYuval Mintz 22035529bad9STomer Tayar return rc; 2204fe56b9e6SYuval Mintz } 220591420b83SSudarsana Kalluru 220676271809STomer Tayar /* A maximal 100 msec waiting time for the MCP to halt */ 220776271809STomer Tayar #define QED_MCP_HALT_SLEEP_MS 10 220876271809STomer Tayar #define QED_MCP_HALT_MAX_RETRIES 10 220976271809STomer Tayar 22104102426fSTomer Tayar int qed_mcp_halt(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 22114102426fSTomer Tayar { 221276271809STomer Tayar u32 resp = 0, param = 0, cpu_state, cnt = 0; 22134102426fSTomer Tayar int rc; 22144102426fSTomer Tayar 22154102426fSTomer Tayar rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_MCP_HALT, 0, &resp, 22164102426fSTomer Tayar ¶m); 221776271809STomer Tayar if (rc) { 22184102426fSTomer Tayar DP_ERR(p_hwfn, "MCP response failure, aborting\n"); 22194102426fSTomer Tayar return rc; 22204102426fSTomer Tayar } 22214102426fSTomer Tayar 222276271809STomer Tayar do { 222376271809STomer Tayar msleep(QED_MCP_HALT_SLEEP_MS); 222476271809STomer Tayar cpu_state = qed_rd(p_hwfn, p_ptt, MCP_REG_CPU_STATE); 222576271809STomer Tayar if (cpu_state & MCP_REG_CPU_STATE_SOFT_HALTED) 222676271809STomer Tayar break; 222776271809STomer Tayar } while (++cnt < QED_MCP_HALT_MAX_RETRIES); 222876271809STomer Tayar 222976271809STomer Tayar if (cnt == QED_MCP_HALT_MAX_RETRIES) { 223076271809STomer Tayar DP_NOTICE(p_hwfn, 223176271809STomer Tayar "Failed to halt the MCP [CPU_MODE = 0x%08x, CPU_STATE = 0x%08x]\n", 223276271809STomer Tayar qed_rd(p_hwfn, p_ptt, MCP_REG_CPU_MODE), cpu_state); 223376271809STomer Tayar return -EBUSY; 223476271809STomer Tayar } 223576271809STomer Tayar 2236b310974eSTomer Tayar qed_mcp_cmd_set_blocking(p_hwfn, true); 2237b310974eSTomer Tayar 223876271809STomer Tayar return 0; 223976271809STomer Tayar } 224076271809STomer Tayar 224176271809STomer Tayar #define QED_MCP_RESUME_SLEEP_MS 10 224276271809STomer Tayar 22434102426fSTomer Tayar int qed_mcp_resume(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 22444102426fSTomer Tayar { 224576271809STomer Tayar u32 cpu_mode, cpu_state; 22464102426fSTomer Tayar 22474102426fSTomer Tayar qed_wr(p_hwfn, p_ptt, MCP_REG_CPU_STATE, 0xffffffff); 22484102426fSTomer Tayar 22494102426fSTomer Tayar cpu_mode = qed_rd(p_hwfn, p_ptt, MCP_REG_CPU_MODE); 225076271809STomer Tayar cpu_mode &= ~MCP_REG_CPU_MODE_SOFT_HALT; 225176271809STomer Tayar qed_wr(p_hwfn, p_ptt, MCP_REG_CPU_MODE, cpu_mode); 225276271809STomer Tayar msleep(QED_MCP_RESUME_SLEEP_MS); 225376271809STomer Tayar cpu_state = qed_rd(p_hwfn, p_ptt, MCP_REG_CPU_STATE); 22544102426fSTomer Tayar 225576271809STomer Tayar if (cpu_state & MCP_REG_CPU_STATE_SOFT_HALTED) { 225676271809STomer Tayar DP_NOTICE(p_hwfn, 225776271809STomer Tayar "Failed to resume the MCP [CPU_MODE = 0x%08x, CPU_STATE = 0x%08x]\n", 225876271809STomer Tayar cpu_mode, cpu_state); 225976271809STomer Tayar return -EBUSY; 226076271809STomer Tayar } 226176271809STomer Tayar 2262b310974eSTomer Tayar qed_mcp_cmd_set_blocking(p_hwfn, false); 2263b310974eSTomer Tayar 226476271809STomer Tayar return 0; 22654102426fSTomer Tayar } 22664102426fSTomer Tayar 22670fefbfbaSSudarsana Kalluru int qed_mcp_ov_update_current_config(struct qed_hwfn *p_hwfn, 22680fefbfbaSSudarsana Kalluru struct qed_ptt *p_ptt, 22690fefbfbaSSudarsana Kalluru enum qed_ov_client client) 22700fefbfbaSSudarsana Kalluru { 22710fefbfbaSSudarsana Kalluru u32 resp = 0, param = 0; 22720fefbfbaSSudarsana Kalluru u32 drv_mb_param; 22730fefbfbaSSudarsana Kalluru int rc; 22740fefbfbaSSudarsana Kalluru 22750fefbfbaSSudarsana Kalluru switch (client) { 22760fefbfbaSSudarsana Kalluru case QED_OV_CLIENT_DRV: 22770fefbfbaSSudarsana Kalluru drv_mb_param = DRV_MB_PARAM_OV_CURR_CFG_OS; 22780fefbfbaSSudarsana Kalluru break; 22790fefbfbaSSudarsana Kalluru case QED_OV_CLIENT_USER: 22800fefbfbaSSudarsana Kalluru drv_mb_param = DRV_MB_PARAM_OV_CURR_CFG_OTHER; 22810fefbfbaSSudarsana Kalluru break; 22820fefbfbaSSudarsana Kalluru case QED_OV_CLIENT_VENDOR_SPEC: 22830fefbfbaSSudarsana Kalluru drv_mb_param = DRV_MB_PARAM_OV_CURR_CFG_VENDOR_SPEC; 22840fefbfbaSSudarsana Kalluru break; 22850fefbfbaSSudarsana Kalluru default: 22860fefbfbaSSudarsana Kalluru DP_NOTICE(p_hwfn, "Invalid client type %d\n", client); 22870fefbfbaSSudarsana Kalluru return -EINVAL; 22880fefbfbaSSudarsana Kalluru } 22890fefbfbaSSudarsana Kalluru 22900fefbfbaSSudarsana Kalluru rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_OV_UPDATE_CURR_CFG, 22910fefbfbaSSudarsana Kalluru drv_mb_param, &resp, ¶m); 22920fefbfbaSSudarsana Kalluru if (rc) 22930fefbfbaSSudarsana Kalluru DP_ERR(p_hwfn, "MCP response failure, aborting\n"); 22940fefbfbaSSudarsana Kalluru 22950fefbfbaSSudarsana Kalluru return rc; 22960fefbfbaSSudarsana Kalluru } 22970fefbfbaSSudarsana Kalluru 22980fefbfbaSSudarsana Kalluru int qed_mcp_ov_update_driver_state(struct qed_hwfn *p_hwfn, 22990fefbfbaSSudarsana Kalluru struct qed_ptt *p_ptt, 23000fefbfbaSSudarsana Kalluru enum qed_ov_driver_state drv_state) 23010fefbfbaSSudarsana Kalluru { 23020fefbfbaSSudarsana Kalluru u32 resp = 0, param = 0; 23030fefbfbaSSudarsana Kalluru u32 drv_mb_param; 23040fefbfbaSSudarsana Kalluru int rc; 23050fefbfbaSSudarsana Kalluru 23060fefbfbaSSudarsana Kalluru switch (drv_state) { 23070fefbfbaSSudarsana Kalluru case QED_OV_DRIVER_STATE_NOT_LOADED: 23080fefbfbaSSudarsana Kalluru drv_mb_param = DRV_MSG_CODE_OV_UPDATE_DRIVER_STATE_NOT_LOADED; 23090fefbfbaSSudarsana Kalluru break; 23100fefbfbaSSudarsana Kalluru case QED_OV_DRIVER_STATE_DISABLED: 23110fefbfbaSSudarsana Kalluru drv_mb_param = DRV_MSG_CODE_OV_UPDATE_DRIVER_STATE_DISABLED; 23120fefbfbaSSudarsana Kalluru break; 23130fefbfbaSSudarsana Kalluru case QED_OV_DRIVER_STATE_ACTIVE: 23140fefbfbaSSudarsana Kalluru drv_mb_param = DRV_MSG_CODE_OV_UPDATE_DRIVER_STATE_ACTIVE; 23150fefbfbaSSudarsana Kalluru break; 23160fefbfbaSSudarsana Kalluru default: 23170fefbfbaSSudarsana Kalluru DP_NOTICE(p_hwfn, "Invalid driver state %d\n", drv_state); 23180fefbfbaSSudarsana Kalluru return -EINVAL; 23190fefbfbaSSudarsana Kalluru } 23200fefbfbaSSudarsana Kalluru 23210fefbfbaSSudarsana Kalluru rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_OV_UPDATE_DRIVER_STATE, 23220fefbfbaSSudarsana Kalluru drv_mb_param, &resp, ¶m); 23230fefbfbaSSudarsana Kalluru if (rc) 23240fefbfbaSSudarsana Kalluru DP_ERR(p_hwfn, "Failed to send driver state\n"); 23250fefbfbaSSudarsana Kalluru 23260fefbfbaSSudarsana Kalluru return rc; 23270fefbfbaSSudarsana Kalluru } 23280fefbfbaSSudarsana Kalluru 23290fefbfbaSSudarsana Kalluru int qed_mcp_ov_update_mtu(struct qed_hwfn *p_hwfn, 23300fefbfbaSSudarsana Kalluru struct qed_ptt *p_ptt, u16 mtu) 23310fefbfbaSSudarsana Kalluru { 23320fefbfbaSSudarsana Kalluru u32 resp = 0, param = 0; 23330fefbfbaSSudarsana Kalluru u32 drv_mb_param; 23340fefbfbaSSudarsana Kalluru int rc; 23350fefbfbaSSudarsana Kalluru 23360fefbfbaSSudarsana Kalluru drv_mb_param = (u32)mtu << DRV_MB_PARAM_OV_MTU_SIZE_SHIFT; 23370fefbfbaSSudarsana Kalluru rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_OV_UPDATE_MTU, 23380fefbfbaSSudarsana Kalluru drv_mb_param, &resp, ¶m); 23390fefbfbaSSudarsana Kalluru if (rc) 23400fefbfbaSSudarsana Kalluru DP_ERR(p_hwfn, "Failed to send mtu value, rc = %d\n", rc); 23410fefbfbaSSudarsana Kalluru 23420fefbfbaSSudarsana Kalluru return rc; 23430fefbfbaSSudarsana Kalluru } 23440fefbfbaSSudarsana Kalluru 23450fefbfbaSSudarsana Kalluru int qed_mcp_ov_update_mac(struct qed_hwfn *p_hwfn, 23460fefbfbaSSudarsana Kalluru struct qed_ptt *p_ptt, u8 *mac) 23470fefbfbaSSudarsana Kalluru { 23480fefbfbaSSudarsana Kalluru struct qed_mcp_mb_params mb_params; 234917991002SMintz, Yuval u32 mfw_mac[2]; 23500fefbfbaSSudarsana Kalluru int rc; 23510fefbfbaSSudarsana Kalluru 23520fefbfbaSSudarsana Kalluru memset(&mb_params, 0, sizeof(mb_params)); 23530fefbfbaSSudarsana Kalluru mb_params.cmd = DRV_MSG_CODE_SET_VMAC; 23540fefbfbaSSudarsana Kalluru mb_params.param = DRV_MSG_CODE_VMAC_TYPE_MAC << 23550fefbfbaSSudarsana Kalluru DRV_MSG_CODE_VMAC_TYPE_SHIFT; 23560fefbfbaSSudarsana Kalluru mb_params.param |= MCP_PF_ID(p_hwfn); 23572f67af8cSTomer Tayar 235817991002SMintz, Yuval /* MCP is BE, and on LE platforms PCI would swap access to SHMEM 235917991002SMintz, Yuval * in 32-bit granularity. 236017991002SMintz, Yuval * So the MAC has to be set in native order [and not byte order], 236117991002SMintz, Yuval * otherwise it would be read incorrectly by MFW after swap. 236217991002SMintz, Yuval */ 236317991002SMintz, Yuval mfw_mac[0] = mac[0] << 24 | mac[1] << 16 | mac[2] << 8 | mac[3]; 236417991002SMintz, Yuval mfw_mac[1] = mac[4] << 24 | mac[5] << 16; 236517991002SMintz, Yuval 236617991002SMintz, Yuval mb_params.p_data_src = (u8 *)mfw_mac; 236717991002SMintz, Yuval mb_params.data_src_size = 8; 23680fefbfbaSSudarsana Kalluru rc = qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 23690fefbfbaSSudarsana Kalluru if (rc) 23700fefbfbaSSudarsana Kalluru DP_ERR(p_hwfn, "Failed to send mac address, rc = %d\n", rc); 23710fefbfbaSSudarsana Kalluru 237214d39648SMintz, Yuval /* Store primary MAC for later possible WoL */ 237314d39648SMintz, Yuval memcpy(p_hwfn->cdev->wol_mac, mac, ETH_ALEN); 237414d39648SMintz, Yuval 23750fefbfbaSSudarsana Kalluru return rc; 23760fefbfbaSSudarsana Kalluru } 23770fefbfbaSSudarsana Kalluru 23780fefbfbaSSudarsana Kalluru int qed_mcp_ov_update_wol(struct qed_hwfn *p_hwfn, 23790fefbfbaSSudarsana Kalluru struct qed_ptt *p_ptt, enum qed_ov_wol wol) 23800fefbfbaSSudarsana Kalluru { 23810fefbfbaSSudarsana Kalluru u32 resp = 0, param = 0; 23820fefbfbaSSudarsana Kalluru u32 drv_mb_param; 23830fefbfbaSSudarsana Kalluru int rc; 23840fefbfbaSSudarsana Kalluru 238514d39648SMintz, Yuval if (p_hwfn->hw_info.b_wol_support == QED_WOL_SUPPORT_NONE) { 238614d39648SMintz, Yuval DP_VERBOSE(p_hwfn, QED_MSG_SP, 238714d39648SMintz, Yuval "Can't change WoL configuration when WoL isn't supported\n"); 238814d39648SMintz, Yuval return -EINVAL; 238914d39648SMintz, Yuval } 239014d39648SMintz, Yuval 23910fefbfbaSSudarsana Kalluru switch (wol) { 23920fefbfbaSSudarsana Kalluru case QED_OV_WOL_DEFAULT: 23930fefbfbaSSudarsana Kalluru drv_mb_param = DRV_MB_PARAM_WOL_DEFAULT; 23940fefbfbaSSudarsana Kalluru break; 23950fefbfbaSSudarsana Kalluru case QED_OV_WOL_DISABLED: 23960fefbfbaSSudarsana Kalluru drv_mb_param = DRV_MB_PARAM_WOL_DISABLED; 23970fefbfbaSSudarsana Kalluru break; 23980fefbfbaSSudarsana Kalluru case QED_OV_WOL_ENABLED: 23990fefbfbaSSudarsana Kalluru drv_mb_param = DRV_MB_PARAM_WOL_ENABLED; 24000fefbfbaSSudarsana Kalluru break; 24010fefbfbaSSudarsana Kalluru default: 24020fefbfbaSSudarsana Kalluru DP_ERR(p_hwfn, "Invalid wol state %d\n", wol); 24030fefbfbaSSudarsana Kalluru return -EINVAL; 24040fefbfbaSSudarsana Kalluru } 24050fefbfbaSSudarsana Kalluru 24060fefbfbaSSudarsana Kalluru rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_OV_UPDATE_WOL, 24070fefbfbaSSudarsana Kalluru drv_mb_param, &resp, ¶m); 24080fefbfbaSSudarsana Kalluru if (rc) 24090fefbfbaSSudarsana Kalluru DP_ERR(p_hwfn, "Failed to send wol mode, rc = %d\n", rc); 24100fefbfbaSSudarsana Kalluru 241114d39648SMintz, Yuval /* Store the WoL update for a future unload */ 241214d39648SMintz, Yuval p_hwfn->cdev->wol_config = (u8)wol; 241314d39648SMintz, Yuval 24140fefbfbaSSudarsana Kalluru return rc; 24150fefbfbaSSudarsana Kalluru } 24160fefbfbaSSudarsana Kalluru 24170fefbfbaSSudarsana Kalluru int qed_mcp_ov_update_eswitch(struct qed_hwfn *p_hwfn, 24180fefbfbaSSudarsana Kalluru struct qed_ptt *p_ptt, 24190fefbfbaSSudarsana Kalluru enum qed_ov_eswitch eswitch) 24200fefbfbaSSudarsana Kalluru { 24210fefbfbaSSudarsana Kalluru u32 resp = 0, param = 0; 24220fefbfbaSSudarsana Kalluru u32 drv_mb_param; 24230fefbfbaSSudarsana Kalluru int rc; 24240fefbfbaSSudarsana Kalluru 24250fefbfbaSSudarsana Kalluru switch (eswitch) { 24260fefbfbaSSudarsana Kalluru case QED_OV_ESWITCH_NONE: 24270fefbfbaSSudarsana Kalluru drv_mb_param = DRV_MB_PARAM_ESWITCH_MODE_NONE; 24280fefbfbaSSudarsana Kalluru break; 24290fefbfbaSSudarsana Kalluru case QED_OV_ESWITCH_VEB: 24300fefbfbaSSudarsana Kalluru drv_mb_param = DRV_MB_PARAM_ESWITCH_MODE_VEB; 24310fefbfbaSSudarsana Kalluru break; 24320fefbfbaSSudarsana Kalluru case QED_OV_ESWITCH_VEPA: 24330fefbfbaSSudarsana Kalluru drv_mb_param = DRV_MB_PARAM_ESWITCH_MODE_VEPA; 24340fefbfbaSSudarsana Kalluru break; 24350fefbfbaSSudarsana Kalluru default: 24360fefbfbaSSudarsana Kalluru DP_ERR(p_hwfn, "Invalid eswitch mode %d\n", eswitch); 24370fefbfbaSSudarsana Kalluru return -EINVAL; 24380fefbfbaSSudarsana Kalluru } 24390fefbfbaSSudarsana Kalluru 24400fefbfbaSSudarsana Kalluru rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_OV_UPDATE_ESWITCH_MODE, 24410fefbfbaSSudarsana Kalluru drv_mb_param, &resp, ¶m); 24420fefbfbaSSudarsana Kalluru if (rc) 24430fefbfbaSSudarsana Kalluru DP_ERR(p_hwfn, "Failed to send eswitch mode, rc = %d\n", rc); 24440fefbfbaSSudarsana Kalluru 24450fefbfbaSSudarsana Kalluru return rc; 24460fefbfbaSSudarsana Kalluru } 24470fefbfbaSSudarsana Kalluru 24481a635e48SYuval Mintz int qed_mcp_set_led(struct qed_hwfn *p_hwfn, 24491a635e48SYuval Mintz struct qed_ptt *p_ptt, enum qed_led_mode mode) 245091420b83SSudarsana Kalluru { 245191420b83SSudarsana Kalluru u32 resp = 0, param = 0, drv_mb_param; 245291420b83SSudarsana Kalluru int rc; 245391420b83SSudarsana Kalluru 245491420b83SSudarsana Kalluru switch (mode) { 245591420b83SSudarsana Kalluru case QED_LED_MODE_ON: 245691420b83SSudarsana Kalluru drv_mb_param = DRV_MB_PARAM_SET_LED_MODE_ON; 245791420b83SSudarsana Kalluru break; 245891420b83SSudarsana Kalluru case QED_LED_MODE_OFF: 245991420b83SSudarsana Kalluru drv_mb_param = DRV_MB_PARAM_SET_LED_MODE_OFF; 246091420b83SSudarsana Kalluru break; 246191420b83SSudarsana Kalluru case QED_LED_MODE_RESTORE: 246291420b83SSudarsana Kalluru drv_mb_param = DRV_MB_PARAM_SET_LED_MODE_OPER; 246391420b83SSudarsana Kalluru break; 246491420b83SSudarsana Kalluru default: 246591420b83SSudarsana Kalluru DP_NOTICE(p_hwfn, "Invalid LED mode %d\n", mode); 246691420b83SSudarsana Kalluru return -EINVAL; 246791420b83SSudarsana Kalluru } 246891420b83SSudarsana Kalluru 246991420b83SSudarsana Kalluru rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_SET_LED_MODE, 247091420b83SSudarsana Kalluru drv_mb_param, &resp, ¶m); 247191420b83SSudarsana Kalluru 247291420b83SSudarsana Kalluru return rc; 247391420b83SSudarsana Kalluru } 247403dc76caSSudarsana Reddy Kalluru 24754102426fSTomer Tayar int qed_mcp_mask_parities(struct qed_hwfn *p_hwfn, 24764102426fSTomer Tayar struct qed_ptt *p_ptt, u32 mask_parities) 24774102426fSTomer Tayar { 24784102426fSTomer Tayar u32 resp = 0, param = 0; 24794102426fSTomer Tayar int rc; 24804102426fSTomer Tayar 24814102426fSTomer Tayar rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_MASK_PARITIES, 24824102426fSTomer Tayar mask_parities, &resp, ¶m); 24834102426fSTomer Tayar 24844102426fSTomer Tayar if (rc) { 24854102426fSTomer Tayar DP_ERR(p_hwfn, 24864102426fSTomer Tayar "MCP response failure for mask parities, aborting\n"); 24874102426fSTomer Tayar } else if (resp != FW_MSG_CODE_OK) { 24884102426fSTomer Tayar DP_ERR(p_hwfn, 24894102426fSTomer Tayar "MCP did not acknowledge mask parity request. Old MFW?\n"); 24904102426fSTomer Tayar rc = -EINVAL; 24914102426fSTomer Tayar } 24924102426fSTomer Tayar 24934102426fSTomer Tayar return rc; 24944102426fSTomer Tayar } 24954102426fSTomer Tayar 24967a4b21b7SMintz, Yuval int qed_mcp_nvm_read(struct qed_dev *cdev, u32 addr, u8 *p_buf, u32 len) 24977a4b21b7SMintz, Yuval { 24987a4b21b7SMintz, Yuval u32 bytes_left = len, offset = 0, bytes_to_copy, read_len = 0; 24997a4b21b7SMintz, Yuval struct qed_hwfn *p_hwfn = QED_LEADING_HWFN(cdev); 25007a4b21b7SMintz, Yuval u32 resp = 0, resp_param = 0; 25017a4b21b7SMintz, Yuval struct qed_ptt *p_ptt; 25027a4b21b7SMintz, Yuval int rc = 0; 25037a4b21b7SMintz, Yuval 25047a4b21b7SMintz, Yuval p_ptt = qed_ptt_acquire(p_hwfn); 25057a4b21b7SMintz, Yuval if (!p_ptt) 25067a4b21b7SMintz, Yuval return -EBUSY; 25077a4b21b7SMintz, Yuval 25087a4b21b7SMintz, Yuval while (bytes_left > 0) { 25097a4b21b7SMintz, Yuval bytes_to_copy = min_t(u32, bytes_left, MCP_DRV_NVM_BUF_LEN); 25107a4b21b7SMintz, Yuval 25117a4b21b7SMintz, Yuval rc = qed_mcp_nvm_rd_cmd(p_hwfn, p_ptt, 25127a4b21b7SMintz, Yuval DRV_MSG_CODE_NVM_READ_NVRAM, 25137a4b21b7SMintz, Yuval addr + offset + 25147a4b21b7SMintz, Yuval (bytes_to_copy << 2515da090917STomer Tayar DRV_MB_PARAM_NVM_LEN_OFFSET), 25167a4b21b7SMintz, Yuval &resp, &resp_param, 25177a4b21b7SMintz, Yuval &read_len, 25187a4b21b7SMintz, Yuval (u32 *)(p_buf + offset)); 25197a4b21b7SMintz, Yuval 25207a4b21b7SMintz, Yuval if (rc || (resp != FW_MSG_CODE_NVM_OK)) { 25217a4b21b7SMintz, Yuval DP_NOTICE(cdev, "MCP command rc = %d\n", rc); 25227a4b21b7SMintz, Yuval break; 25237a4b21b7SMintz, Yuval } 25247a4b21b7SMintz, Yuval 25257a4b21b7SMintz, Yuval /* This can be a lengthy process, and it's possible scheduler 25267a4b21b7SMintz, Yuval * isn't preemptable. Sleep a bit to prevent CPU hogging. 25277a4b21b7SMintz, Yuval */ 25287a4b21b7SMintz, Yuval if (bytes_left % 0x1000 < 25297a4b21b7SMintz, Yuval (bytes_left - read_len) % 0x1000) 25307a4b21b7SMintz, Yuval usleep_range(1000, 2000); 25317a4b21b7SMintz, Yuval 25327a4b21b7SMintz, Yuval offset += read_len; 25337a4b21b7SMintz, Yuval bytes_left -= read_len; 25347a4b21b7SMintz, Yuval } 25357a4b21b7SMintz, Yuval 25367a4b21b7SMintz, Yuval cdev->mcp_nvm_resp = resp; 25377a4b21b7SMintz, Yuval qed_ptt_release(p_hwfn, p_ptt); 25387a4b21b7SMintz, Yuval 25397a4b21b7SMintz, Yuval return rc; 25407a4b21b7SMintz, Yuval } 25417a4b21b7SMintz, Yuval 254262e4d438SSudarsana Reddy Kalluru int qed_mcp_nvm_resp(struct qed_dev *cdev, u8 *p_buf) 254362e4d438SSudarsana Reddy Kalluru { 254462e4d438SSudarsana Reddy Kalluru struct qed_hwfn *p_hwfn = QED_LEADING_HWFN(cdev); 254562e4d438SSudarsana Reddy Kalluru struct qed_ptt *p_ptt; 254662e4d438SSudarsana Reddy Kalluru 254762e4d438SSudarsana Reddy Kalluru p_ptt = qed_ptt_acquire(p_hwfn); 254862e4d438SSudarsana Reddy Kalluru if (!p_ptt) 254962e4d438SSudarsana Reddy Kalluru return -EBUSY; 255062e4d438SSudarsana Reddy Kalluru 255162e4d438SSudarsana Reddy Kalluru memcpy(p_buf, &cdev->mcp_nvm_resp, sizeof(cdev->mcp_nvm_resp)); 255262e4d438SSudarsana Reddy Kalluru qed_ptt_release(p_hwfn, p_ptt); 255362e4d438SSudarsana Reddy Kalluru 255462e4d438SSudarsana Reddy Kalluru return 0; 255562e4d438SSudarsana Reddy Kalluru } 255662e4d438SSudarsana Reddy Kalluru 255762e4d438SSudarsana Reddy Kalluru int qed_mcp_nvm_put_file_begin(struct qed_dev *cdev, u32 addr) 255862e4d438SSudarsana Reddy Kalluru { 255962e4d438SSudarsana Reddy Kalluru struct qed_hwfn *p_hwfn = QED_LEADING_HWFN(cdev); 256062e4d438SSudarsana Reddy Kalluru struct qed_ptt *p_ptt; 256162e4d438SSudarsana Reddy Kalluru u32 resp, param; 256262e4d438SSudarsana Reddy Kalluru int rc; 256362e4d438SSudarsana Reddy Kalluru 256462e4d438SSudarsana Reddy Kalluru p_ptt = qed_ptt_acquire(p_hwfn); 256562e4d438SSudarsana Reddy Kalluru if (!p_ptt) 256662e4d438SSudarsana Reddy Kalluru return -EBUSY; 256762e4d438SSudarsana Reddy Kalluru rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_NVM_PUT_FILE_BEGIN, addr, 256862e4d438SSudarsana Reddy Kalluru &resp, ¶m); 256962e4d438SSudarsana Reddy Kalluru cdev->mcp_nvm_resp = resp; 257062e4d438SSudarsana Reddy Kalluru qed_ptt_release(p_hwfn, p_ptt); 257162e4d438SSudarsana Reddy Kalluru 257262e4d438SSudarsana Reddy Kalluru return rc; 257362e4d438SSudarsana Reddy Kalluru } 257462e4d438SSudarsana Reddy Kalluru 257562e4d438SSudarsana Reddy Kalluru int qed_mcp_nvm_write(struct qed_dev *cdev, 257662e4d438SSudarsana Reddy Kalluru u32 cmd, u32 addr, u8 *p_buf, u32 len) 257762e4d438SSudarsana Reddy Kalluru { 257862e4d438SSudarsana Reddy Kalluru u32 buf_idx = 0, buf_size, nvm_cmd, nvm_offset, resp = 0, param; 257962e4d438SSudarsana Reddy Kalluru struct qed_hwfn *p_hwfn = QED_LEADING_HWFN(cdev); 258062e4d438SSudarsana Reddy Kalluru struct qed_ptt *p_ptt; 258162e4d438SSudarsana Reddy Kalluru int rc = -EINVAL; 258262e4d438SSudarsana Reddy Kalluru 258362e4d438SSudarsana Reddy Kalluru p_ptt = qed_ptt_acquire(p_hwfn); 258462e4d438SSudarsana Reddy Kalluru if (!p_ptt) 258562e4d438SSudarsana Reddy Kalluru return -EBUSY; 258662e4d438SSudarsana Reddy Kalluru 258762e4d438SSudarsana Reddy Kalluru switch (cmd) { 258862e4d438SSudarsana Reddy Kalluru case QED_PUT_FILE_DATA: 258962e4d438SSudarsana Reddy Kalluru nvm_cmd = DRV_MSG_CODE_NVM_PUT_FILE_DATA; 259062e4d438SSudarsana Reddy Kalluru break; 259162e4d438SSudarsana Reddy Kalluru case QED_NVM_WRITE_NVRAM: 259262e4d438SSudarsana Reddy Kalluru nvm_cmd = DRV_MSG_CODE_NVM_WRITE_NVRAM; 259362e4d438SSudarsana Reddy Kalluru break; 259462e4d438SSudarsana Reddy Kalluru default: 259562e4d438SSudarsana Reddy Kalluru DP_NOTICE(p_hwfn, "Invalid nvm write command 0x%x\n", cmd); 259662e4d438SSudarsana Reddy Kalluru rc = -EINVAL; 259762e4d438SSudarsana Reddy Kalluru goto out; 259862e4d438SSudarsana Reddy Kalluru } 259962e4d438SSudarsana Reddy Kalluru 260062e4d438SSudarsana Reddy Kalluru while (buf_idx < len) { 260162e4d438SSudarsana Reddy Kalluru buf_size = min_t(u32, (len - buf_idx), MCP_DRV_NVM_BUF_LEN); 260262e4d438SSudarsana Reddy Kalluru nvm_offset = ((buf_size << DRV_MB_PARAM_NVM_LEN_OFFSET) | 260362e4d438SSudarsana Reddy Kalluru addr) + buf_idx; 260462e4d438SSudarsana Reddy Kalluru rc = qed_mcp_nvm_wr_cmd(p_hwfn, p_ptt, nvm_cmd, nvm_offset, 260562e4d438SSudarsana Reddy Kalluru &resp, ¶m, buf_size, 260662e4d438SSudarsana Reddy Kalluru (u32 *)&p_buf[buf_idx]); 260762e4d438SSudarsana Reddy Kalluru if (rc) { 260862e4d438SSudarsana Reddy Kalluru DP_NOTICE(cdev, "nvm write failed, rc = %d\n", rc); 260962e4d438SSudarsana Reddy Kalluru resp = FW_MSG_CODE_ERROR; 261062e4d438SSudarsana Reddy Kalluru break; 261162e4d438SSudarsana Reddy Kalluru } 261262e4d438SSudarsana Reddy Kalluru 261362e4d438SSudarsana Reddy Kalluru if (resp != FW_MSG_CODE_OK && 261462e4d438SSudarsana Reddy Kalluru resp != FW_MSG_CODE_NVM_OK && 261562e4d438SSudarsana Reddy Kalluru resp != FW_MSG_CODE_NVM_PUT_FILE_FINISH_OK) { 261662e4d438SSudarsana Reddy Kalluru DP_NOTICE(cdev, 261762e4d438SSudarsana Reddy Kalluru "nvm write failed, resp = 0x%08x\n", resp); 261862e4d438SSudarsana Reddy Kalluru rc = -EINVAL; 261962e4d438SSudarsana Reddy Kalluru break; 262062e4d438SSudarsana Reddy Kalluru } 262162e4d438SSudarsana Reddy Kalluru 262262e4d438SSudarsana Reddy Kalluru /* This can be a lengthy process, and it's possible scheduler 262362e4d438SSudarsana Reddy Kalluru * isn't pre-emptable. Sleep a bit to prevent CPU hogging. 262462e4d438SSudarsana Reddy Kalluru */ 262562e4d438SSudarsana Reddy Kalluru if (buf_idx % 0x1000 > (buf_idx + buf_size) % 0x1000) 262662e4d438SSudarsana Reddy Kalluru usleep_range(1000, 2000); 262762e4d438SSudarsana Reddy Kalluru 262862e4d438SSudarsana Reddy Kalluru buf_idx += buf_size; 262962e4d438SSudarsana Reddy Kalluru } 263062e4d438SSudarsana Reddy Kalluru 263162e4d438SSudarsana Reddy Kalluru cdev->mcp_nvm_resp = resp; 263262e4d438SSudarsana Reddy Kalluru out: 263362e4d438SSudarsana Reddy Kalluru qed_ptt_release(p_hwfn, p_ptt); 263462e4d438SSudarsana Reddy Kalluru 263562e4d438SSudarsana Reddy Kalluru return rc; 263662e4d438SSudarsana Reddy Kalluru } 263762e4d438SSudarsana Reddy Kalluru 2638b51dab46SSudarsana Reddy Kalluru int qed_mcp_phy_sfp_read(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, 2639b51dab46SSudarsana Reddy Kalluru u32 port, u32 addr, u32 offset, u32 len, u8 *p_buf) 2640b51dab46SSudarsana Reddy Kalluru { 2641b51dab46SSudarsana Reddy Kalluru u32 bytes_left, bytes_to_copy, buf_size, nvm_offset = 0; 2642b51dab46SSudarsana Reddy Kalluru u32 resp, param; 2643b51dab46SSudarsana Reddy Kalluru int rc; 2644b51dab46SSudarsana Reddy Kalluru 2645b51dab46SSudarsana Reddy Kalluru nvm_offset |= (port << DRV_MB_PARAM_TRANSCEIVER_PORT_OFFSET) & 2646b51dab46SSudarsana Reddy Kalluru DRV_MB_PARAM_TRANSCEIVER_PORT_MASK; 2647b51dab46SSudarsana Reddy Kalluru nvm_offset |= (addr << DRV_MB_PARAM_TRANSCEIVER_I2C_ADDRESS_OFFSET) & 2648b51dab46SSudarsana Reddy Kalluru DRV_MB_PARAM_TRANSCEIVER_I2C_ADDRESS_MASK; 2649b51dab46SSudarsana Reddy Kalluru 2650b51dab46SSudarsana Reddy Kalluru addr = offset; 2651b51dab46SSudarsana Reddy Kalluru offset = 0; 2652b51dab46SSudarsana Reddy Kalluru bytes_left = len; 2653b51dab46SSudarsana Reddy Kalluru while (bytes_left > 0) { 2654b51dab46SSudarsana Reddy Kalluru bytes_to_copy = min_t(u32, bytes_left, 2655b51dab46SSudarsana Reddy Kalluru MAX_I2C_TRANSACTION_SIZE); 2656b51dab46SSudarsana Reddy Kalluru nvm_offset &= (DRV_MB_PARAM_TRANSCEIVER_I2C_ADDRESS_MASK | 2657b51dab46SSudarsana Reddy Kalluru DRV_MB_PARAM_TRANSCEIVER_PORT_MASK); 2658b51dab46SSudarsana Reddy Kalluru nvm_offset |= ((addr + offset) << 2659b51dab46SSudarsana Reddy Kalluru DRV_MB_PARAM_TRANSCEIVER_OFFSET_OFFSET) & 2660b51dab46SSudarsana Reddy Kalluru DRV_MB_PARAM_TRANSCEIVER_OFFSET_MASK; 2661b51dab46SSudarsana Reddy Kalluru nvm_offset |= (bytes_to_copy << 2662b51dab46SSudarsana Reddy Kalluru DRV_MB_PARAM_TRANSCEIVER_SIZE_OFFSET) & 2663b51dab46SSudarsana Reddy Kalluru DRV_MB_PARAM_TRANSCEIVER_SIZE_MASK; 2664b51dab46SSudarsana Reddy Kalluru rc = qed_mcp_nvm_rd_cmd(p_hwfn, p_ptt, 2665b51dab46SSudarsana Reddy Kalluru DRV_MSG_CODE_TRANSCEIVER_READ, 2666b51dab46SSudarsana Reddy Kalluru nvm_offset, &resp, ¶m, &buf_size, 2667b51dab46SSudarsana Reddy Kalluru (u32 *)(p_buf + offset)); 2668b51dab46SSudarsana Reddy Kalluru if (rc) { 2669b51dab46SSudarsana Reddy Kalluru DP_NOTICE(p_hwfn, 2670b51dab46SSudarsana Reddy Kalluru "Failed to send a transceiver read command to the MFW. rc = %d.\n", 2671b51dab46SSudarsana Reddy Kalluru rc); 2672b51dab46SSudarsana Reddy Kalluru return rc; 2673b51dab46SSudarsana Reddy Kalluru } 2674b51dab46SSudarsana Reddy Kalluru 2675b51dab46SSudarsana Reddy Kalluru if (resp == FW_MSG_CODE_TRANSCEIVER_NOT_PRESENT) 2676b51dab46SSudarsana Reddy Kalluru return -ENODEV; 2677b51dab46SSudarsana Reddy Kalluru else if (resp != FW_MSG_CODE_TRANSCEIVER_DIAG_OK) 2678b51dab46SSudarsana Reddy Kalluru return -EINVAL; 2679b51dab46SSudarsana Reddy Kalluru 2680b51dab46SSudarsana Reddy Kalluru offset += buf_size; 2681b51dab46SSudarsana Reddy Kalluru bytes_left -= buf_size; 2682b51dab46SSudarsana Reddy Kalluru } 2683b51dab46SSudarsana Reddy Kalluru 2684b51dab46SSudarsana Reddy Kalluru return 0; 2685b51dab46SSudarsana Reddy Kalluru } 2686b51dab46SSudarsana Reddy Kalluru 268703dc76caSSudarsana Reddy Kalluru int qed_mcp_bist_register_test(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 268803dc76caSSudarsana Reddy Kalluru { 268903dc76caSSudarsana Reddy Kalluru u32 drv_mb_param = 0, rsp, param; 269003dc76caSSudarsana Reddy Kalluru int rc = 0; 269103dc76caSSudarsana Reddy Kalluru 269203dc76caSSudarsana Reddy Kalluru drv_mb_param = (DRV_MB_PARAM_BIST_REGISTER_TEST << 269303dc76caSSudarsana Reddy Kalluru DRV_MB_PARAM_BIST_TEST_INDEX_SHIFT); 269403dc76caSSudarsana Reddy Kalluru 269503dc76caSSudarsana Reddy Kalluru rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_BIST_TEST, 269603dc76caSSudarsana Reddy Kalluru drv_mb_param, &rsp, ¶m); 269703dc76caSSudarsana Reddy Kalluru 269803dc76caSSudarsana Reddy Kalluru if (rc) 269903dc76caSSudarsana Reddy Kalluru return rc; 270003dc76caSSudarsana Reddy Kalluru 270103dc76caSSudarsana Reddy Kalluru if (((rsp & FW_MSG_CODE_MASK) != FW_MSG_CODE_OK) || 270203dc76caSSudarsana Reddy Kalluru (param != DRV_MB_PARAM_BIST_RC_PASSED)) 270303dc76caSSudarsana Reddy Kalluru rc = -EAGAIN; 270403dc76caSSudarsana Reddy Kalluru 270503dc76caSSudarsana Reddy Kalluru return rc; 270603dc76caSSudarsana Reddy Kalluru } 270703dc76caSSudarsana Reddy Kalluru 270803dc76caSSudarsana Reddy Kalluru int qed_mcp_bist_clock_test(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 270903dc76caSSudarsana Reddy Kalluru { 271003dc76caSSudarsana Reddy Kalluru u32 drv_mb_param, rsp, param; 271103dc76caSSudarsana Reddy Kalluru int rc = 0; 271203dc76caSSudarsana Reddy Kalluru 271303dc76caSSudarsana Reddy Kalluru drv_mb_param = (DRV_MB_PARAM_BIST_CLOCK_TEST << 271403dc76caSSudarsana Reddy Kalluru DRV_MB_PARAM_BIST_TEST_INDEX_SHIFT); 271503dc76caSSudarsana Reddy Kalluru 271603dc76caSSudarsana Reddy Kalluru rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_BIST_TEST, 271703dc76caSSudarsana Reddy Kalluru drv_mb_param, &rsp, ¶m); 271803dc76caSSudarsana Reddy Kalluru 271903dc76caSSudarsana Reddy Kalluru if (rc) 272003dc76caSSudarsana Reddy Kalluru return rc; 272103dc76caSSudarsana Reddy Kalluru 272203dc76caSSudarsana Reddy Kalluru if (((rsp & FW_MSG_CODE_MASK) != FW_MSG_CODE_OK) || 272303dc76caSSudarsana Reddy Kalluru (param != DRV_MB_PARAM_BIST_RC_PASSED)) 272403dc76caSSudarsana Reddy Kalluru rc = -EAGAIN; 272503dc76caSSudarsana Reddy Kalluru 272603dc76caSSudarsana Reddy Kalluru return rc; 272703dc76caSSudarsana Reddy Kalluru } 27287a4b21b7SMintz, Yuval 272943645ce0SSudarsana Reddy Kalluru int qed_mcp_bist_nvm_get_num_images(struct qed_hwfn *p_hwfn, 27307a4b21b7SMintz, Yuval struct qed_ptt *p_ptt, 27317a4b21b7SMintz, Yuval u32 *num_images) 27327a4b21b7SMintz, Yuval { 27337a4b21b7SMintz, Yuval u32 drv_mb_param = 0, rsp; 27347a4b21b7SMintz, Yuval int rc = 0; 27357a4b21b7SMintz, Yuval 27367a4b21b7SMintz, Yuval drv_mb_param = (DRV_MB_PARAM_BIST_NVM_TEST_NUM_IMAGES << 27377a4b21b7SMintz, Yuval DRV_MB_PARAM_BIST_TEST_INDEX_SHIFT); 27387a4b21b7SMintz, Yuval 27397a4b21b7SMintz, Yuval rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_BIST_TEST, 27407a4b21b7SMintz, Yuval drv_mb_param, &rsp, num_images); 27417a4b21b7SMintz, Yuval if (rc) 27427a4b21b7SMintz, Yuval return rc; 27437a4b21b7SMintz, Yuval 27447a4b21b7SMintz, Yuval if (((rsp & FW_MSG_CODE_MASK) != FW_MSG_CODE_OK)) 27457a4b21b7SMintz, Yuval rc = -EINVAL; 27467a4b21b7SMintz, Yuval 27477a4b21b7SMintz, Yuval return rc; 27487a4b21b7SMintz, Yuval } 27497a4b21b7SMintz, Yuval 275043645ce0SSudarsana Reddy Kalluru int qed_mcp_bist_nvm_get_image_att(struct qed_hwfn *p_hwfn, 27517a4b21b7SMintz, Yuval struct qed_ptt *p_ptt, 27527a4b21b7SMintz, Yuval struct bist_nvm_image_att *p_image_att, 27537a4b21b7SMintz, Yuval u32 image_index) 27547a4b21b7SMintz, Yuval { 27557a4b21b7SMintz, Yuval u32 buf_size = 0, param, resp = 0, resp_param = 0; 27567a4b21b7SMintz, Yuval int rc; 27577a4b21b7SMintz, Yuval 27587a4b21b7SMintz, Yuval param = DRV_MB_PARAM_BIST_NVM_TEST_IMAGE_BY_INDEX << 27597a4b21b7SMintz, Yuval DRV_MB_PARAM_BIST_TEST_INDEX_SHIFT; 27607a4b21b7SMintz, Yuval param |= image_index << DRV_MB_PARAM_BIST_TEST_IMAGE_INDEX_SHIFT; 27617a4b21b7SMintz, Yuval 27627a4b21b7SMintz, Yuval rc = qed_mcp_nvm_rd_cmd(p_hwfn, p_ptt, 27637a4b21b7SMintz, Yuval DRV_MSG_CODE_BIST_TEST, param, 27647a4b21b7SMintz, Yuval &resp, &resp_param, 27657a4b21b7SMintz, Yuval &buf_size, 27667a4b21b7SMintz, Yuval (u32 *)p_image_att); 27677a4b21b7SMintz, Yuval if (rc) 27687a4b21b7SMintz, Yuval return rc; 27697a4b21b7SMintz, Yuval 27707a4b21b7SMintz, Yuval if (((resp & FW_MSG_CODE_MASK) != FW_MSG_CODE_OK) || 27717a4b21b7SMintz, Yuval (p_image_att->return_code != 1)) 27727a4b21b7SMintz, Yuval rc = -EINVAL; 27737a4b21b7SMintz, Yuval 27747a4b21b7SMintz, Yuval return rc; 27757a4b21b7SMintz, Yuval } 27762edbff8dSTomer Tayar 277743645ce0SSudarsana Reddy Kalluru int qed_mcp_nvm_info_populate(struct qed_hwfn *p_hwfn) 277843645ce0SSudarsana Reddy Kalluru { 27795e7ba042SDenis Bolotin struct qed_nvm_image_info nvm_info; 278043645ce0SSudarsana Reddy Kalluru struct qed_ptt *p_ptt; 278143645ce0SSudarsana Reddy Kalluru int rc; 278243645ce0SSudarsana Reddy Kalluru u32 i; 278343645ce0SSudarsana Reddy Kalluru 27845e7ba042SDenis Bolotin if (p_hwfn->nvm_info.valid) 27855e7ba042SDenis Bolotin return 0; 27865e7ba042SDenis Bolotin 278743645ce0SSudarsana Reddy Kalluru p_ptt = qed_ptt_acquire(p_hwfn); 278843645ce0SSudarsana Reddy Kalluru if (!p_ptt) { 278943645ce0SSudarsana Reddy Kalluru DP_ERR(p_hwfn, "failed to acquire ptt\n"); 279043645ce0SSudarsana Reddy Kalluru return -EBUSY; 279143645ce0SSudarsana Reddy Kalluru } 279243645ce0SSudarsana Reddy Kalluru 279343645ce0SSudarsana Reddy Kalluru /* Acquire from MFW the amount of available images */ 27945e7ba042SDenis Bolotin nvm_info.num_images = 0; 279543645ce0SSudarsana Reddy Kalluru rc = qed_mcp_bist_nvm_get_num_images(p_hwfn, 27965e7ba042SDenis Bolotin p_ptt, &nvm_info.num_images); 279743645ce0SSudarsana Reddy Kalluru if (rc == -EOPNOTSUPP) { 279843645ce0SSudarsana Reddy Kalluru DP_INFO(p_hwfn, "DRV_MSG_CODE_BIST_TEST is not supported\n"); 279943645ce0SSudarsana Reddy Kalluru goto out; 28005e7ba042SDenis Bolotin } else if (rc || !nvm_info.num_images) { 280143645ce0SSudarsana Reddy Kalluru DP_ERR(p_hwfn, "Failed getting number of images\n"); 280243645ce0SSudarsana Reddy Kalluru goto err0; 280343645ce0SSudarsana Reddy Kalluru } 280443645ce0SSudarsana Reddy Kalluru 28055e7ba042SDenis Bolotin nvm_info.image_att = kmalloc_array(nvm_info.num_images, 280643645ce0SSudarsana Reddy Kalluru sizeof(struct bist_nvm_image_att), 280743645ce0SSudarsana Reddy Kalluru GFP_KERNEL); 28085e7ba042SDenis Bolotin if (!nvm_info.image_att) { 280943645ce0SSudarsana Reddy Kalluru rc = -ENOMEM; 281043645ce0SSudarsana Reddy Kalluru goto err0; 281143645ce0SSudarsana Reddy Kalluru } 281243645ce0SSudarsana Reddy Kalluru 281343645ce0SSudarsana Reddy Kalluru /* Iterate over images and get their attributes */ 28145e7ba042SDenis Bolotin for (i = 0; i < nvm_info.num_images; i++) { 281543645ce0SSudarsana Reddy Kalluru rc = qed_mcp_bist_nvm_get_image_att(p_hwfn, p_ptt, 28165e7ba042SDenis Bolotin &nvm_info.image_att[i], i); 281743645ce0SSudarsana Reddy Kalluru if (rc) { 281843645ce0SSudarsana Reddy Kalluru DP_ERR(p_hwfn, 281943645ce0SSudarsana Reddy Kalluru "Failed getting image index %d attributes\n", i); 282043645ce0SSudarsana Reddy Kalluru goto err1; 282143645ce0SSudarsana Reddy Kalluru } 282243645ce0SSudarsana Reddy Kalluru 282343645ce0SSudarsana Reddy Kalluru DP_VERBOSE(p_hwfn, QED_MSG_SP, "image index %d, size %x\n", i, 28245e7ba042SDenis Bolotin nvm_info.image_att[i].len); 282543645ce0SSudarsana Reddy Kalluru } 282643645ce0SSudarsana Reddy Kalluru out: 28275e7ba042SDenis Bolotin /* Update hwfn's nvm_info */ 28285e7ba042SDenis Bolotin if (nvm_info.num_images) { 28295e7ba042SDenis Bolotin p_hwfn->nvm_info.num_images = nvm_info.num_images; 28305e7ba042SDenis Bolotin kfree(p_hwfn->nvm_info.image_att); 28315e7ba042SDenis Bolotin p_hwfn->nvm_info.image_att = nvm_info.image_att; 28325e7ba042SDenis Bolotin p_hwfn->nvm_info.valid = true; 28335e7ba042SDenis Bolotin } 28345e7ba042SDenis Bolotin 283543645ce0SSudarsana Reddy Kalluru qed_ptt_release(p_hwfn, p_ptt); 283643645ce0SSudarsana Reddy Kalluru return 0; 283743645ce0SSudarsana Reddy Kalluru 283843645ce0SSudarsana Reddy Kalluru err1: 28395e7ba042SDenis Bolotin kfree(nvm_info.image_att); 284043645ce0SSudarsana Reddy Kalluru err0: 284143645ce0SSudarsana Reddy Kalluru qed_ptt_release(p_hwfn, p_ptt); 284243645ce0SSudarsana Reddy Kalluru return rc; 284343645ce0SSudarsana Reddy Kalluru } 284443645ce0SSudarsana Reddy Kalluru 28451ac4329aSDenis Bolotin int 284620675b37SMintz, Yuval qed_mcp_get_nvm_image_att(struct qed_hwfn *p_hwfn, 284720675b37SMintz, Yuval enum qed_nvm_images image_id, 284820675b37SMintz, Yuval struct qed_nvm_image_att *p_image_att) 284920675b37SMintz, Yuval { 285020675b37SMintz, Yuval enum nvm_image_type type; 285143645ce0SSudarsana Reddy Kalluru u32 i; 285220675b37SMintz, Yuval 285320675b37SMintz, Yuval /* Translate image_id into MFW definitions */ 285420675b37SMintz, Yuval switch (image_id) { 285520675b37SMintz, Yuval case QED_NVM_IMAGE_ISCSI_CFG: 285620675b37SMintz, Yuval type = NVM_TYPE_ISCSI_CFG; 285720675b37SMintz, Yuval break; 285820675b37SMintz, Yuval case QED_NVM_IMAGE_FCOE_CFG: 285920675b37SMintz, Yuval type = NVM_TYPE_FCOE_CFG; 286020675b37SMintz, Yuval break; 28611ac4329aSDenis Bolotin case QED_NVM_IMAGE_NVM_CFG1: 28621ac4329aSDenis Bolotin type = NVM_TYPE_NVM_CFG1; 28631ac4329aSDenis Bolotin break; 28641ac4329aSDenis Bolotin case QED_NVM_IMAGE_DEFAULT_CFG: 28651ac4329aSDenis Bolotin type = NVM_TYPE_DEFAULT_CFG; 28661ac4329aSDenis Bolotin break; 28671ac4329aSDenis Bolotin case QED_NVM_IMAGE_NVM_META: 28681ac4329aSDenis Bolotin type = NVM_TYPE_META; 28691ac4329aSDenis Bolotin break; 287020675b37SMintz, Yuval default: 287120675b37SMintz, Yuval DP_NOTICE(p_hwfn, "Unknown request of image_id %08x\n", 287220675b37SMintz, Yuval image_id); 287320675b37SMintz, Yuval return -EINVAL; 287420675b37SMintz, Yuval } 287520675b37SMintz, Yuval 28765e7ba042SDenis Bolotin qed_mcp_nvm_info_populate(p_hwfn); 287743645ce0SSudarsana Reddy Kalluru for (i = 0; i < p_hwfn->nvm_info.num_images; i++) 287843645ce0SSudarsana Reddy Kalluru if (type == p_hwfn->nvm_info.image_att[i].image_type) 287920675b37SMintz, Yuval break; 288043645ce0SSudarsana Reddy Kalluru if (i == p_hwfn->nvm_info.num_images) { 288120675b37SMintz, Yuval DP_VERBOSE(p_hwfn, QED_MSG_STORAGE, 288220675b37SMintz, Yuval "Failed to find nvram image of type %08x\n", 288320675b37SMintz, Yuval image_id); 288443645ce0SSudarsana Reddy Kalluru return -ENOENT; 288520675b37SMintz, Yuval } 288620675b37SMintz, Yuval 288743645ce0SSudarsana Reddy Kalluru p_image_att->start_addr = p_hwfn->nvm_info.image_att[i].nvm_start_addr; 288843645ce0SSudarsana Reddy Kalluru p_image_att->length = p_hwfn->nvm_info.image_att[i].len; 288920675b37SMintz, Yuval 289020675b37SMintz, Yuval return 0; 289120675b37SMintz, Yuval } 289220675b37SMintz, Yuval 289320675b37SMintz, Yuval int qed_mcp_get_nvm_image(struct qed_hwfn *p_hwfn, 289420675b37SMintz, Yuval enum qed_nvm_images image_id, 289520675b37SMintz, Yuval u8 *p_buffer, u32 buffer_len) 289620675b37SMintz, Yuval { 289720675b37SMintz, Yuval struct qed_nvm_image_att image_att; 289820675b37SMintz, Yuval int rc; 289920675b37SMintz, Yuval 290020675b37SMintz, Yuval memset(p_buffer, 0, buffer_len); 290120675b37SMintz, Yuval 2902b60bfdfeSDenis Bolotin rc = qed_mcp_get_nvm_image_att(p_hwfn, image_id, &image_att); 290320675b37SMintz, Yuval if (rc) 290420675b37SMintz, Yuval return rc; 290520675b37SMintz, Yuval 290620675b37SMintz, Yuval /* Validate sizes - both the image's and the supplied buffer's */ 290720675b37SMintz, Yuval if (image_att.length <= 4) { 290820675b37SMintz, Yuval DP_VERBOSE(p_hwfn, QED_MSG_STORAGE, 290920675b37SMintz, Yuval "Image [%d] is too small - only %d bytes\n", 291020675b37SMintz, Yuval image_id, image_att.length); 291120675b37SMintz, Yuval return -EINVAL; 291220675b37SMintz, Yuval } 291320675b37SMintz, Yuval 291420675b37SMintz, Yuval if (image_att.length > buffer_len) { 291520675b37SMintz, Yuval DP_VERBOSE(p_hwfn, 291620675b37SMintz, Yuval QED_MSG_STORAGE, 291720675b37SMintz, Yuval "Image [%d] is too big - %08x bytes where only %08x are available\n", 291820675b37SMintz, Yuval image_id, image_att.length, buffer_len); 291920675b37SMintz, Yuval return -ENOMEM; 292020675b37SMintz, Yuval } 292120675b37SMintz, Yuval 292220675b37SMintz, Yuval return qed_mcp_nvm_read(p_hwfn->cdev, image_att.start_addr, 292320675b37SMintz, Yuval p_buffer, image_att.length); 292420675b37SMintz, Yuval } 292520675b37SMintz, Yuval 29269c8517c4STomer Tayar static enum resource_id_enum qed_mcp_get_mfw_res_id(enum qed_resources res_id) 29279c8517c4STomer Tayar { 29289c8517c4STomer Tayar enum resource_id_enum mfw_res_id = RESOURCE_NUM_INVALID; 29299c8517c4STomer Tayar 29309c8517c4STomer Tayar switch (res_id) { 29319c8517c4STomer Tayar case QED_SB: 29329c8517c4STomer Tayar mfw_res_id = RESOURCE_NUM_SB_E; 29339c8517c4STomer Tayar break; 29349c8517c4STomer Tayar case QED_L2_QUEUE: 29359c8517c4STomer Tayar mfw_res_id = RESOURCE_NUM_L2_QUEUE_E; 29369c8517c4STomer Tayar break; 29379c8517c4STomer Tayar case QED_VPORT: 29389c8517c4STomer Tayar mfw_res_id = RESOURCE_NUM_VPORT_E; 29399c8517c4STomer Tayar break; 29409c8517c4STomer Tayar case QED_RSS_ENG: 29419c8517c4STomer Tayar mfw_res_id = RESOURCE_NUM_RSS_ENGINES_E; 29429c8517c4STomer Tayar break; 29439c8517c4STomer Tayar case QED_PQ: 29449c8517c4STomer Tayar mfw_res_id = RESOURCE_NUM_PQ_E; 29459c8517c4STomer Tayar break; 29469c8517c4STomer Tayar case QED_RL: 29479c8517c4STomer Tayar mfw_res_id = RESOURCE_NUM_RL_E; 29489c8517c4STomer Tayar break; 29499c8517c4STomer Tayar case QED_MAC: 29509c8517c4STomer Tayar case QED_VLAN: 29519c8517c4STomer Tayar /* Each VFC resource can accommodate both a MAC and a VLAN */ 29529c8517c4STomer Tayar mfw_res_id = RESOURCE_VFC_FILTER_E; 29539c8517c4STomer Tayar break; 29549c8517c4STomer Tayar case QED_ILT: 29559c8517c4STomer Tayar mfw_res_id = RESOURCE_ILT_E; 29569c8517c4STomer Tayar break; 29579c8517c4STomer Tayar case QED_LL2_QUEUE: 29589c8517c4STomer Tayar mfw_res_id = RESOURCE_LL2_QUEUE_E; 29599c8517c4STomer Tayar break; 29609c8517c4STomer Tayar case QED_RDMA_CNQ_RAM: 29619c8517c4STomer Tayar case QED_CMDQS_CQS: 29629c8517c4STomer Tayar /* CNQ/CMDQS are the same resource */ 29639c8517c4STomer Tayar mfw_res_id = RESOURCE_CQS_E; 29649c8517c4STomer Tayar break; 29659c8517c4STomer Tayar case QED_RDMA_STATS_QUEUE: 29669c8517c4STomer Tayar mfw_res_id = RESOURCE_RDMA_STATS_QUEUE_E; 29679c8517c4STomer Tayar break; 29689c8517c4STomer Tayar case QED_BDQ: 29699c8517c4STomer Tayar mfw_res_id = RESOURCE_BDQ_E; 29709c8517c4STomer Tayar break; 29719c8517c4STomer Tayar default: 29729c8517c4STomer Tayar break; 29739c8517c4STomer Tayar } 29749c8517c4STomer Tayar 29759c8517c4STomer Tayar return mfw_res_id; 29769c8517c4STomer Tayar } 29779c8517c4STomer Tayar 29789c8517c4STomer Tayar #define QED_RESC_ALLOC_VERSION_MAJOR 2 29792edbff8dSTomer Tayar #define QED_RESC_ALLOC_VERSION_MINOR 0 29802edbff8dSTomer Tayar #define QED_RESC_ALLOC_VERSION \ 29812edbff8dSTomer Tayar ((QED_RESC_ALLOC_VERSION_MAJOR << \ 29822edbff8dSTomer Tayar DRV_MB_PARAM_RESOURCE_ALLOC_VERSION_MAJOR_SHIFT) | \ 29832edbff8dSTomer Tayar (QED_RESC_ALLOC_VERSION_MINOR << \ 29842edbff8dSTomer Tayar DRV_MB_PARAM_RESOURCE_ALLOC_VERSION_MINOR_SHIFT)) 29859c8517c4STomer Tayar 29869c8517c4STomer Tayar struct qed_resc_alloc_in_params { 29879c8517c4STomer Tayar u32 cmd; 29889c8517c4STomer Tayar enum qed_resources res_id; 29899c8517c4STomer Tayar u32 resc_max_val; 29909c8517c4STomer Tayar }; 29919c8517c4STomer Tayar 29929c8517c4STomer Tayar struct qed_resc_alloc_out_params { 29939c8517c4STomer Tayar u32 mcp_resp; 29949c8517c4STomer Tayar u32 mcp_param; 29959c8517c4STomer Tayar u32 resc_num; 29969c8517c4STomer Tayar u32 resc_start; 29979c8517c4STomer Tayar u32 vf_resc_num; 29989c8517c4STomer Tayar u32 vf_resc_start; 29999c8517c4STomer Tayar u32 flags; 30009c8517c4STomer Tayar }; 30019c8517c4STomer Tayar 30029c8517c4STomer Tayar static int 30039c8517c4STomer Tayar qed_mcp_resc_allocation_msg(struct qed_hwfn *p_hwfn, 30042edbff8dSTomer Tayar struct qed_ptt *p_ptt, 30059c8517c4STomer Tayar struct qed_resc_alloc_in_params *p_in_params, 30069c8517c4STomer Tayar struct qed_resc_alloc_out_params *p_out_params) 30072edbff8dSTomer Tayar { 30082edbff8dSTomer Tayar struct qed_mcp_mb_params mb_params; 30099c8517c4STomer Tayar struct resource_info mfw_resc_info; 30102edbff8dSTomer Tayar int rc; 30112edbff8dSTomer Tayar 30129c8517c4STomer Tayar memset(&mfw_resc_info, 0, sizeof(mfw_resc_info)); 3013bb480242SMintz, Yuval 30149c8517c4STomer Tayar mfw_resc_info.res_id = qed_mcp_get_mfw_res_id(p_in_params->res_id); 30159c8517c4STomer Tayar if (mfw_resc_info.res_id == RESOURCE_NUM_INVALID) { 30169c8517c4STomer Tayar DP_ERR(p_hwfn, 30179c8517c4STomer Tayar "Failed to match resource %d [%s] with the MFW resources\n", 30189c8517c4STomer Tayar p_in_params->res_id, 30199c8517c4STomer Tayar qed_hw_get_resc_name(p_in_params->res_id)); 30209c8517c4STomer Tayar return -EINVAL; 30219c8517c4STomer Tayar } 30229c8517c4STomer Tayar 30239c8517c4STomer Tayar switch (p_in_params->cmd) { 30249c8517c4STomer Tayar case DRV_MSG_SET_RESOURCE_VALUE_MSG: 30259c8517c4STomer Tayar mfw_resc_info.size = p_in_params->resc_max_val; 30269c8517c4STomer Tayar /* Fallthrough */ 30279c8517c4STomer Tayar case DRV_MSG_GET_RESOURCE_ALLOC_MSG: 30289c8517c4STomer Tayar break; 30299c8517c4STomer Tayar default: 30309c8517c4STomer Tayar DP_ERR(p_hwfn, "Unexpected resource alloc command [0x%08x]\n", 30319c8517c4STomer Tayar p_in_params->cmd); 30329c8517c4STomer Tayar return -EINVAL; 30339c8517c4STomer Tayar } 30349c8517c4STomer Tayar 30359c8517c4STomer Tayar memset(&mb_params, 0, sizeof(mb_params)); 30369c8517c4STomer Tayar mb_params.cmd = p_in_params->cmd; 30379c8517c4STomer Tayar mb_params.param = QED_RESC_ALLOC_VERSION; 30389c8517c4STomer Tayar mb_params.p_data_src = &mfw_resc_info; 30399c8517c4STomer Tayar mb_params.data_src_size = sizeof(mfw_resc_info); 30409c8517c4STomer Tayar mb_params.p_data_dst = mb_params.p_data_src; 30419c8517c4STomer Tayar mb_params.data_dst_size = mb_params.data_src_size; 30429c8517c4STomer Tayar 30439c8517c4STomer Tayar DP_VERBOSE(p_hwfn, 30449c8517c4STomer Tayar QED_MSG_SP, 30459c8517c4STomer Tayar "Resource message request: cmd 0x%08x, res_id %d [%s], hsi_version %d.%d, val 0x%x\n", 30469c8517c4STomer Tayar p_in_params->cmd, 30479c8517c4STomer Tayar p_in_params->res_id, 30489c8517c4STomer Tayar qed_hw_get_resc_name(p_in_params->res_id), 30499c8517c4STomer Tayar QED_MFW_GET_FIELD(mb_params.param, 30509c8517c4STomer Tayar DRV_MB_PARAM_RESOURCE_ALLOC_VERSION_MAJOR), 30519c8517c4STomer Tayar QED_MFW_GET_FIELD(mb_params.param, 30529c8517c4STomer Tayar DRV_MB_PARAM_RESOURCE_ALLOC_VERSION_MINOR), 30539c8517c4STomer Tayar p_in_params->resc_max_val); 30549c8517c4STomer Tayar 30552edbff8dSTomer Tayar rc = qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 30562edbff8dSTomer Tayar if (rc) 30572edbff8dSTomer Tayar return rc; 30582edbff8dSTomer Tayar 30599c8517c4STomer Tayar p_out_params->mcp_resp = mb_params.mcp_resp; 30609c8517c4STomer Tayar p_out_params->mcp_param = mb_params.mcp_param; 30619c8517c4STomer Tayar p_out_params->resc_num = mfw_resc_info.size; 30629c8517c4STomer Tayar p_out_params->resc_start = mfw_resc_info.offset; 30639c8517c4STomer Tayar p_out_params->vf_resc_num = mfw_resc_info.vf_size; 30649c8517c4STomer Tayar p_out_params->vf_resc_start = mfw_resc_info.vf_offset; 30659c8517c4STomer Tayar p_out_params->flags = mfw_resc_info.flags; 30662edbff8dSTomer Tayar 30672edbff8dSTomer Tayar DP_VERBOSE(p_hwfn, 30682edbff8dSTomer Tayar QED_MSG_SP, 30699c8517c4STomer 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", 30709c8517c4STomer Tayar QED_MFW_GET_FIELD(p_out_params->mcp_param, 30719c8517c4STomer Tayar FW_MB_PARAM_RESOURCE_ALLOC_VERSION_MAJOR), 30729c8517c4STomer Tayar QED_MFW_GET_FIELD(p_out_params->mcp_param, 30739c8517c4STomer Tayar FW_MB_PARAM_RESOURCE_ALLOC_VERSION_MINOR), 30749c8517c4STomer Tayar p_out_params->resc_num, 30759c8517c4STomer Tayar p_out_params->resc_start, 30769c8517c4STomer Tayar p_out_params->vf_resc_num, 30779c8517c4STomer Tayar p_out_params->vf_resc_start, p_out_params->flags); 30789c8517c4STomer Tayar 30799c8517c4STomer Tayar return 0; 30809c8517c4STomer Tayar } 30819c8517c4STomer Tayar 30829c8517c4STomer Tayar int 30839c8517c4STomer Tayar qed_mcp_set_resc_max_val(struct qed_hwfn *p_hwfn, 30849c8517c4STomer Tayar struct qed_ptt *p_ptt, 30859c8517c4STomer Tayar enum qed_resources res_id, 30869c8517c4STomer Tayar u32 resc_max_val, u32 *p_mcp_resp) 30879c8517c4STomer Tayar { 30889c8517c4STomer Tayar struct qed_resc_alloc_out_params out_params; 30899c8517c4STomer Tayar struct qed_resc_alloc_in_params in_params; 30909c8517c4STomer Tayar int rc; 30919c8517c4STomer Tayar 30929c8517c4STomer Tayar memset(&in_params, 0, sizeof(in_params)); 30939c8517c4STomer Tayar in_params.cmd = DRV_MSG_SET_RESOURCE_VALUE_MSG; 30949c8517c4STomer Tayar in_params.res_id = res_id; 30959c8517c4STomer Tayar in_params.resc_max_val = resc_max_val; 30969c8517c4STomer Tayar memset(&out_params, 0, sizeof(out_params)); 30979c8517c4STomer Tayar rc = qed_mcp_resc_allocation_msg(p_hwfn, p_ptt, &in_params, 30989c8517c4STomer Tayar &out_params); 30999c8517c4STomer Tayar if (rc) 31009c8517c4STomer Tayar return rc; 31019c8517c4STomer Tayar 31029c8517c4STomer Tayar *p_mcp_resp = out_params.mcp_resp; 31039c8517c4STomer Tayar 31049c8517c4STomer Tayar return 0; 31059c8517c4STomer Tayar } 31069c8517c4STomer Tayar 31079c8517c4STomer Tayar int 31089c8517c4STomer Tayar qed_mcp_get_resc_info(struct qed_hwfn *p_hwfn, 31099c8517c4STomer Tayar struct qed_ptt *p_ptt, 31109c8517c4STomer Tayar enum qed_resources res_id, 31119c8517c4STomer Tayar u32 *p_mcp_resp, u32 *p_resc_num, u32 *p_resc_start) 31129c8517c4STomer Tayar { 31139c8517c4STomer Tayar struct qed_resc_alloc_out_params out_params; 31149c8517c4STomer Tayar struct qed_resc_alloc_in_params in_params; 31159c8517c4STomer Tayar int rc; 31169c8517c4STomer Tayar 31179c8517c4STomer Tayar memset(&in_params, 0, sizeof(in_params)); 31189c8517c4STomer Tayar in_params.cmd = DRV_MSG_GET_RESOURCE_ALLOC_MSG; 31199c8517c4STomer Tayar in_params.res_id = res_id; 31209c8517c4STomer Tayar memset(&out_params, 0, sizeof(out_params)); 31219c8517c4STomer Tayar rc = qed_mcp_resc_allocation_msg(p_hwfn, p_ptt, &in_params, 31229c8517c4STomer Tayar &out_params); 31239c8517c4STomer Tayar if (rc) 31249c8517c4STomer Tayar return rc; 31259c8517c4STomer Tayar 31269c8517c4STomer Tayar *p_mcp_resp = out_params.mcp_resp; 31279c8517c4STomer Tayar 31289c8517c4STomer Tayar if (*p_mcp_resp == FW_MSG_CODE_RESOURCE_ALLOC_OK) { 31299c8517c4STomer Tayar *p_resc_num = out_params.resc_num; 31309c8517c4STomer Tayar *p_resc_start = out_params.resc_start; 31319c8517c4STomer Tayar } 31322edbff8dSTomer Tayar 31332edbff8dSTomer Tayar return 0; 31342edbff8dSTomer Tayar } 313518a69e36SMintz, Yuval 313618a69e36SMintz, Yuval int qed_mcp_initiate_pf_flr(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 313718a69e36SMintz, Yuval { 313818a69e36SMintz, Yuval u32 mcp_resp, mcp_param; 313918a69e36SMintz, Yuval 314018a69e36SMintz, Yuval return qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_INITIATE_PF_FLR, 0, 314118a69e36SMintz, Yuval &mcp_resp, &mcp_param); 314218a69e36SMintz, Yuval } 314395691c9cSTomer Tayar 314495691c9cSTomer Tayar static int qed_mcp_resource_cmd(struct qed_hwfn *p_hwfn, 314595691c9cSTomer Tayar struct qed_ptt *p_ptt, 314695691c9cSTomer Tayar u32 param, u32 *p_mcp_resp, u32 *p_mcp_param) 314795691c9cSTomer Tayar { 314895691c9cSTomer Tayar int rc; 314995691c9cSTomer Tayar 315095691c9cSTomer Tayar rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_RESOURCE_CMD, param, 315195691c9cSTomer Tayar p_mcp_resp, p_mcp_param); 315295691c9cSTomer Tayar if (rc) 315395691c9cSTomer Tayar return rc; 315495691c9cSTomer Tayar 315595691c9cSTomer Tayar if (*p_mcp_resp == FW_MSG_CODE_UNSUPPORTED) { 315695691c9cSTomer Tayar DP_INFO(p_hwfn, 315795691c9cSTomer Tayar "The resource command is unsupported by the MFW\n"); 315895691c9cSTomer Tayar return -EINVAL; 315995691c9cSTomer Tayar } 316095691c9cSTomer Tayar 316195691c9cSTomer Tayar if (*p_mcp_param == RESOURCE_OPCODE_UNKNOWN_CMD) { 316295691c9cSTomer Tayar u8 opcode = QED_MFW_GET_FIELD(param, RESOURCE_CMD_REQ_OPCODE); 316395691c9cSTomer Tayar 316495691c9cSTomer Tayar DP_NOTICE(p_hwfn, 316595691c9cSTomer Tayar "The resource command is unknown to the MFW [param 0x%08x, opcode %d]\n", 316695691c9cSTomer Tayar param, opcode); 316795691c9cSTomer Tayar return -EINVAL; 316895691c9cSTomer Tayar } 316995691c9cSTomer Tayar 317095691c9cSTomer Tayar return rc; 317195691c9cSTomer Tayar } 317295691c9cSTomer Tayar 3173bf774d14SYueHaibing static int 317495691c9cSTomer Tayar __qed_mcp_resc_lock(struct qed_hwfn *p_hwfn, 317595691c9cSTomer Tayar struct qed_ptt *p_ptt, 317695691c9cSTomer Tayar struct qed_resc_lock_params *p_params) 317795691c9cSTomer Tayar { 317895691c9cSTomer Tayar u32 param = 0, mcp_resp, mcp_param; 317995691c9cSTomer Tayar u8 opcode; 318095691c9cSTomer Tayar int rc; 318195691c9cSTomer Tayar 318295691c9cSTomer Tayar switch (p_params->timeout) { 318395691c9cSTomer Tayar case QED_MCP_RESC_LOCK_TO_DEFAULT: 318495691c9cSTomer Tayar opcode = RESOURCE_OPCODE_REQ; 318595691c9cSTomer Tayar p_params->timeout = 0; 318695691c9cSTomer Tayar break; 318795691c9cSTomer Tayar case QED_MCP_RESC_LOCK_TO_NONE: 318895691c9cSTomer Tayar opcode = RESOURCE_OPCODE_REQ_WO_AGING; 318995691c9cSTomer Tayar p_params->timeout = 0; 319095691c9cSTomer Tayar break; 319195691c9cSTomer Tayar default: 319295691c9cSTomer Tayar opcode = RESOURCE_OPCODE_REQ_W_AGING; 319395691c9cSTomer Tayar break; 319495691c9cSTomer Tayar } 319595691c9cSTomer Tayar 319695691c9cSTomer Tayar QED_MFW_SET_FIELD(param, RESOURCE_CMD_REQ_RESC, p_params->resource); 319795691c9cSTomer Tayar QED_MFW_SET_FIELD(param, RESOURCE_CMD_REQ_OPCODE, opcode); 319895691c9cSTomer Tayar QED_MFW_SET_FIELD(param, RESOURCE_CMD_REQ_AGE, p_params->timeout); 319995691c9cSTomer Tayar 320095691c9cSTomer Tayar DP_VERBOSE(p_hwfn, 320195691c9cSTomer Tayar QED_MSG_SP, 320295691c9cSTomer Tayar "Resource lock request: param 0x%08x [age %d, opcode %d, resource %d]\n", 320395691c9cSTomer Tayar param, p_params->timeout, opcode, p_params->resource); 320495691c9cSTomer Tayar 320595691c9cSTomer Tayar /* Attempt to acquire the resource */ 320695691c9cSTomer Tayar rc = qed_mcp_resource_cmd(p_hwfn, p_ptt, param, &mcp_resp, &mcp_param); 320795691c9cSTomer Tayar if (rc) 320895691c9cSTomer Tayar return rc; 320995691c9cSTomer Tayar 321095691c9cSTomer Tayar /* Analyze the response */ 321195691c9cSTomer Tayar p_params->owner = QED_MFW_GET_FIELD(mcp_param, RESOURCE_CMD_RSP_OWNER); 321295691c9cSTomer Tayar opcode = QED_MFW_GET_FIELD(mcp_param, RESOURCE_CMD_RSP_OPCODE); 321395691c9cSTomer Tayar 321495691c9cSTomer Tayar DP_VERBOSE(p_hwfn, 321595691c9cSTomer Tayar QED_MSG_SP, 321695691c9cSTomer Tayar "Resource lock response: mcp_param 0x%08x [opcode %d, owner %d]\n", 321795691c9cSTomer Tayar mcp_param, opcode, p_params->owner); 321895691c9cSTomer Tayar 321995691c9cSTomer Tayar switch (opcode) { 322095691c9cSTomer Tayar case RESOURCE_OPCODE_GNT: 322195691c9cSTomer Tayar p_params->b_granted = true; 322295691c9cSTomer Tayar break; 322395691c9cSTomer Tayar case RESOURCE_OPCODE_BUSY: 322495691c9cSTomer Tayar p_params->b_granted = false; 322595691c9cSTomer Tayar break; 322695691c9cSTomer Tayar default: 322795691c9cSTomer Tayar DP_NOTICE(p_hwfn, 322895691c9cSTomer Tayar "Unexpected opcode in resource lock response [mcp_param 0x%08x, opcode %d]\n", 322995691c9cSTomer Tayar mcp_param, opcode); 323095691c9cSTomer Tayar return -EINVAL; 323195691c9cSTomer Tayar } 323295691c9cSTomer Tayar 323395691c9cSTomer Tayar return 0; 323495691c9cSTomer Tayar } 323595691c9cSTomer Tayar 323695691c9cSTomer Tayar int 323795691c9cSTomer Tayar qed_mcp_resc_lock(struct qed_hwfn *p_hwfn, 323895691c9cSTomer Tayar struct qed_ptt *p_ptt, struct qed_resc_lock_params *p_params) 323995691c9cSTomer Tayar { 324095691c9cSTomer Tayar u32 retry_cnt = 0; 324195691c9cSTomer Tayar int rc; 324295691c9cSTomer Tayar 324395691c9cSTomer Tayar do { 324495691c9cSTomer Tayar /* No need for an interval before the first iteration */ 324595691c9cSTomer Tayar if (retry_cnt) { 324695691c9cSTomer Tayar if (p_params->sleep_b4_retry) { 324795691c9cSTomer Tayar u16 retry_interval_in_ms = 324895691c9cSTomer Tayar DIV_ROUND_UP(p_params->retry_interval, 324995691c9cSTomer Tayar 1000); 325095691c9cSTomer Tayar 325195691c9cSTomer Tayar msleep(retry_interval_in_ms); 325295691c9cSTomer Tayar } else { 325395691c9cSTomer Tayar udelay(p_params->retry_interval); 325495691c9cSTomer Tayar } 325595691c9cSTomer Tayar } 325695691c9cSTomer Tayar 325795691c9cSTomer Tayar rc = __qed_mcp_resc_lock(p_hwfn, p_ptt, p_params); 325895691c9cSTomer Tayar if (rc) 325995691c9cSTomer Tayar return rc; 326095691c9cSTomer Tayar 326195691c9cSTomer Tayar if (p_params->b_granted) 326295691c9cSTomer Tayar break; 326395691c9cSTomer Tayar } while (retry_cnt++ < p_params->retry_num); 326495691c9cSTomer Tayar 326595691c9cSTomer Tayar return 0; 326695691c9cSTomer Tayar } 326795691c9cSTomer Tayar 326895691c9cSTomer Tayar int 326995691c9cSTomer Tayar qed_mcp_resc_unlock(struct qed_hwfn *p_hwfn, 327095691c9cSTomer Tayar struct qed_ptt *p_ptt, 327195691c9cSTomer Tayar struct qed_resc_unlock_params *p_params) 327295691c9cSTomer Tayar { 327395691c9cSTomer Tayar u32 param = 0, mcp_resp, mcp_param; 327495691c9cSTomer Tayar u8 opcode; 327595691c9cSTomer Tayar int rc; 327695691c9cSTomer Tayar 327795691c9cSTomer Tayar opcode = p_params->b_force ? RESOURCE_OPCODE_FORCE_RELEASE 327895691c9cSTomer Tayar : RESOURCE_OPCODE_RELEASE; 327995691c9cSTomer Tayar QED_MFW_SET_FIELD(param, RESOURCE_CMD_REQ_RESC, p_params->resource); 328095691c9cSTomer Tayar QED_MFW_SET_FIELD(param, RESOURCE_CMD_REQ_OPCODE, opcode); 328195691c9cSTomer Tayar 328295691c9cSTomer Tayar DP_VERBOSE(p_hwfn, QED_MSG_SP, 328395691c9cSTomer Tayar "Resource unlock request: param 0x%08x [opcode %d, resource %d]\n", 328495691c9cSTomer Tayar param, opcode, p_params->resource); 328595691c9cSTomer Tayar 328695691c9cSTomer Tayar /* Attempt to release the resource */ 328795691c9cSTomer Tayar rc = qed_mcp_resource_cmd(p_hwfn, p_ptt, param, &mcp_resp, &mcp_param); 328895691c9cSTomer Tayar if (rc) 328995691c9cSTomer Tayar return rc; 329095691c9cSTomer Tayar 329195691c9cSTomer Tayar /* Analyze the response */ 329295691c9cSTomer Tayar opcode = QED_MFW_GET_FIELD(mcp_param, RESOURCE_CMD_RSP_OPCODE); 329395691c9cSTomer Tayar 329495691c9cSTomer Tayar DP_VERBOSE(p_hwfn, QED_MSG_SP, 329595691c9cSTomer Tayar "Resource unlock response: mcp_param 0x%08x [opcode %d]\n", 329695691c9cSTomer Tayar mcp_param, opcode); 329795691c9cSTomer Tayar 329895691c9cSTomer Tayar switch (opcode) { 329995691c9cSTomer Tayar case RESOURCE_OPCODE_RELEASED_PREVIOUS: 330095691c9cSTomer Tayar DP_INFO(p_hwfn, 330195691c9cSTomer Tayar "Resource unlock request for an already released resource [%d]\n", 330295691c9cSTomer Tayar p_params->resource); 330395691c9cSTomer Tayar /* Fallthrough */ 330495691c9cSTomer Tayar case RESOURCE_OPCODE_RELEASED: 330595691c9cSTomer Tayar p_params->b_released = true; 330695691c9cSTomer Tayar break; 330795691c9cSTomer Tayar case RESOURCE_OPCODE_WRONG_OWNER: 330895691c9cSTomer Tayar p_params->b_released = false; 330995691c9cSTomer Tayar break; 331095691c9cSTomer Tayar default: 331195691c9cSTomer Tayar DP_NOTICE(p_hwfn, 331295691c9cSTomer Tayar "Unexpected opcode in resource unlock response [mcp_param 0x%08x, opcode %d]\n", 331395691c9cSTomer Tayar mcp_param, opcode); 331495691c9cSTomer Tayar return -EINVAL; 331595691c9cSTomer Tayar } 331695691c9cSTomer Tayar 331795691c9cSTomer Tayar return 0; 331895691c9cSTomer Tayar } 3319f470f22cSsudarsana.kalluru@cavium.com 3320f470f22cSsudarsana.kalluru@cavium.com void qed_mcp_resc_lock_default_init(struct qed_resc_lock_params *p_lock, 3321f470f22cSsudarsana.kalluru@cavium.com struct qed_resc_unlock_params *p_unlock, 3322f470f22cSsudarsana.kalluru@cavium.com enum qed_resc_lock 3323f470f22cSsudarsana.kalluru@cavium.com resource, bool b_is_permanent) 3324f470f22cSsudarsana.kalluru@cavium.com { 3325f470f22cSsudarsana.kalluru@cavium.com if (p_lock) { 3326f470f22cSsudarsana.kalluru@cavium.com memset(p_lock, 0, sizeof(*p_lock)); 3327f470f22cSsudarsana.kalluru@cavium.com 3328f470f22cSsudarsana.kalluru@cavium.com /* Permanent resources don't require aging, and there's no 3329f470f22cSsudarsana.kalluru@cavium.com * point in trying to acquire them more than once since it's 3330f470f22cSsudarsana.kalluru@cavium.com * unexpected another entity would release them. 3331f470f22cSsudarsana.kalluru@cavium.com */ 3332f470f22cSsudarsana.kalluru@cavium.com if (b_is_permanent) { 3333f470f22cSsudarsana.kalluru@cavium.com p_lock->timeout = QED_MCP_RESC_LOCK_TO_NONE; 3334f470f22cSsudarsana.kalluru@cavium.com } else { 3335f470f22cSsudarsana.kalluru@cavium.com p_lock->retry_num = QED_MCP_RESC_LOCK_RETRY_CNT_DFLT; 3336f470f22cSsudarsana.kalluru@cavium.com p_lock->retry_interval = 3337f470f22cSsudarsana.kalluru@cavium.com QED_MCP_RESC_LOCK_RETRY_VAL_DFLT; 3338f470f22cSsudarsana.kalluru@cavium.com p_lock->sleep_b4_retry = true; 3339f470f22cSsudarsana.kalluru@cavium.com } 3340f470f22cSsudarsana.kalluru@cavium.com 3341f470f22cSsudarsana.kalluru@cavium.com p_lock->resource = resource; 3342f470f22cSsudarsana.kalluru@cavium.com } 3343f470f22cSsudarsana.kalluru@cavium.com 3344f470f22cSsudarsana.kalluru@cavium.com if (p_unlock) { 3345f470f22cSsudarsana.kalluru@cavium.com memset(p_unlock, 0, sizeof(*p_unlock)); 3346f470f22cSsudarsana.kalluru@cavium.com p_unlock->resource = resource; 3347f470f22cSsudarsana.kalluru@cavium.com } 3348f470f22cSsudarsana.kalluru@cavium.com } 3349645874e5SSudarsana Reddy Kalluru 3350645874e5SSudarsana Reddy Kalluru int qed_mcp_get_capabilities(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 3351645874e5SSudarsana Reddy Kalluru { 3352645874e5SSudarsana Reddy Kalluru u32 mcp_resp; 3353645874e5SSudarsana Reddy Kalluru int rc; 3354645874e5SSudarsana Reddy Kalluru 3355645874e5SSudarsana Reddy Kalluru rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_GET_MFW_FEATURE_SUPPORT, 3356645874e5SSudarsana Reddy Kalluru 0, &mcp_resp, &p_hwfn->mcp_info->capabilities); 3357645874e5SSudarsana Reddy Kalluru if (!rc) 3358645874e5SSudarsana Reddy Kalluru DP_VERBOSE(p_hwfn, (QED_MSG_SP | NETIF_MSG_PROBE), 3359645874e5SSudarsana Reddy Kalluru "MFW supported features: %08x\n", 3360645874e5SSudarsana Reddy Kalluru p_hwfn->mcp_info->capabilities); 3361645874e5SSudarsana Reddy Kalluru 3362645874e5SSudarsana Reddy Kalluru return rc; 3363645874e5SSudarsana Reddy Kalluru } 3364645874e5SSudarsana Reddy Kalluru 3365645874e5SSudarsana Reddy Kalluru int qed_mcp_set_capabilities(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 3366645874e5SSudarsana Reddy Kalluru { 3367645874e5SSudarsana Reddy Kalluru u32 mcp_resp, mcp_param, features; 3368645874e5SSudarsana Reddy Kalluru 3369e40a826aSSudarsana Reddy Kalluru features = DRV_MB_PARAM_FEATURE_SUPPORT_PORT_EEE | 3370e40a826aSSudarsana Reddy Kalluru DRV_MB_PARAM_FEATURE_SUPPORT_FUNC_VLINK; 3371645874e5SSudarsana Reddy Kalluru 3372645874e5SSudarsana Reddy Kalluru return qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_FEATURE_SUPPORT, 3373645874e5SSudarsana Reddy Kalluru features, &mcp_resp, &mcp_param); 3374645874e5SSudarsana Reddy Kalluru } 3375