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" 4339651abdSSudarsana Reddy Kalluru #include "qed_dcbx.h" 44fe56b9e6SYuval Mintz #include "qed_hsi.h" 45fe56b9e6SYuval Mintz #include "qed_hw.h" 46fe56b9e6SYuval Mintz #include "qed_mcp.h" 47fe56b9e6SYuval Mintz #include "qed_reg_addr.h" 481408cc1fSYuval Mintz #include "qed_sriov.h" 491408cc1fSYuval Mintz 50fe56b9e6SYuval Mintz #define CHIP_MCP_RESP_ITER_US 10 51fe56b9e6SYuval Mintz 52fe56b9e6SYuval Mintz #define QED_DRV_MB_MAX_RETRIES (500 * 1000) /* Account for 5 sec */ 53fe56b9e6SYuval Mintz #define QED_MCP_RESET_RETRIES (50 * 1000) /* Account for 500 msec */ 54fe56b9e6SYuval Mintz 55fe56b9e6SYuval Mintz #define DRV_INNER_WR(_p_hwfn, _p_ptt, _ptr, _offset, _val) \ 56fe56b9e6SYuval Mintz qed_wr(_p_hwfn, _p_ptt, (_p_hwfn->mcp_info->_ptr + _offset), \ 57fe56b9e6SYuval Mintz _val) 58fe56b9e6SYuval Mintz 59fe56b9e6SYuval Mintz #define DRV_INNER_RD(_p_hwfn, _p_ptt, _ptr, _offset) \ 60fe56b9e6SYuval Mintz qed_rd(_p_hwfn, _p_ptt, (_p_hwfn->mcp_info->_ptr + _offset)) 61fe56b9e6SYuval Mintz 62fe56b9e6SYuval Mintz #define DRV_MB_WR(_p_hwfn, _p_ptt, _field, _val) \ 63fe56b9e6SYuval Mintz DRV_INNER_WR(p_hwfn, _p_ptt, drv_mb_addr, \ 64fe56b9e6SYuval Mintz offsetof(struct public_drv_mb, _field), _val) 65fe56b9e6SYuval Mintz 66fe56b9e6SYuval Mintz #define DRV_MB_RD(_p_hwfn, _p_ptt, _field) \ 67fe56b9e6SYuval Mintz DRV_INNER_RD(_p_hwfn, _p_ptt, drv_mb_addr, \ 68fe56b9e6SYuval Mintz offsetof(struct public_drv_mb, _field)) 69fe56b9e6SYuval Mintz 70fe56b9e6SYuval Mintz #define PDA_COMP (((FW_MAJOR_VERSION) + (FW_MINOR_VERSION << 8)) << \ 71fe56b9e6SYuval Mintz DRV_ID_PDA_COMP_VER_SHIFT) 72fe56b9e6SYuval Mintz 73fe56b9e6SYuval Mintz #define MCP_BYTES_PER_MBIT_SHIFT 17 74fe56b9e6SYuval Mintz 75fe56b9e6SYuval Mintz bool qed_mcp_is_init(struct qed_hwfn *p_hwfn) 76fe56b9e6SYuval Mintz { 77fe56b9e6SYuval Mintz if (!p_hwfn->mcp_info || !p_hwfn->mcp_info->public_base) 78fe56b9e6SYuval Mintz return false; 79fe56b9e6SYuval Mintz return true; 80fe56b9e6SYuval Mintz } 81fe56b9e6SYuval Mintz 821a635e48SYuval Mintz void qed_mcp_cmd_port_init(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 83fe56b9e6SYuval Mintz { 84fe56b9e6SYuval Mintz u32 addr = SECTION_OFFSIZE_ADDR(p_hwfn->mcp_info->public_base, 85fe56b9e6SYuval Mintz PUBLIC_PORT); 86fe56b9e6SYuval Mintz u32 mfw_mb_offsize = qed_rd(p_hwfn, p_ptt, addr); 87fe56b9e6SYuval Mintz 88fe56b9e6SYuval Mintz p_hwfn->mcp_info->port_addr = SECTION_ADDR(mfw_mb_offsize, 89fe56b9e6SYuval Mintz MFW_PORT(p_hwfn)); 90fe56b9e6SYuval Mintz DP_VERBOSE(p_hwfn, QED_MSG_SP, 91fe56b9e6SYuval Mintz "port_addr = 0x%x, port_id 0x%02x\n", 92fe56b9e6SYuval Mintz p_hwfn->mcp_info->port_addr, MFW_PORT(p_hwfn)); 93fe56b9e6SYuval Mintz } 94fe56b9e6SYuval Mintz 951a635e48SYuval Mintz void qed_mcp_read_mb(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 96fe56b9e6SYuval Mintz { 97fe56b9e6SYuval Mintz u32 length = MFW_DRV_MSG_MAX_DWORDS(p_hwfn->mcp_info->mfw_mb_length); 98fe56b9e6SYuval Mintz u32 tmp, i; 99fe56b9e6SYuval Mintz 100fe56b9e6SYuval Mintz if (!p_hwfn->mcp_info->public_base) 101fe56b9e6SYuval Mintz return; 102fe56b9e6SYuval Mintz 103fe56b9e6SYuval Mintz for (i = 0; i < length; i++) { 104fe56b9e6SYuval Mintz tmp = qed_rd(p_hwfn, p_ptt, 105fe56b9e6SYuval Mintz p_hwfn->mcp_info->mfw_mb_addr + 106fe56b9e6SYuval Mintz (i << 2) + sizeof(u32)); 107fe56b9e6SYuval Mintz 108fe56b9e6SYuval Mintz /* The MB data is actually BE; Need to force it to cpu */ 109fe56b9e6SYuval Mintz ((u32 *)p_hwfn->mcp_info->mfw_mb_cur)[i] = 110fe56b9e6SYuval Mintz be32_to_cpu((__force __be32)tmp); 111fe56b9e6SYuval Mintz } 112fe56b9e6SYuval Mintz } 113fe56b9e6SYuval Mintz 1144ed1eea8STomer Tayar struct qed_mcp_cmd_elem { 1154ed1eea8STomer Tayar struct list_head list; 1164ed1eea8STomer Tayar struct qed_mcp_mb_params *p_mb_params; 1174ed1eea8STomer Tayar u16 expected_seq_num; 1184ed1eea8STomer Tayar bool b_is_completed; 1194ed1eea8STomer Tayar }; 1204ed1eea8STomer Tayar 1214ed1eea8STomer Tayar /* Must be called while cmd_lock is acquired */ 1224ed1eea8STomer Tayar static struct qed_mcp_cmd_elem * 1234ed1eea8STomer Tayar qed_mcp_cmd_add_elem(struct qed_hwfn *p_hwfn, 1244ed1eea8STomer Tayar struct qed_mcp_mb_params *p_mb_params, 1254ed1eea8STomer Tayar u16 expected_seq_num) 1264ed1eea8STomer Tayar { 1274ed1eea8STomer Tayar struct qed_mcp_cmd_elem *p_cmd_elem = NULL; 1284ed1eea8STomer Tayar 1294ed1eea8STomer Tayar p_cmd_elem = kzalloc(sizeof(*p_cmd_elem), GFP_ATOMIC); 1304ed1eea8STomer Tayar if (!p_cmd_elem) 1314ed1eea8STomer Tayar goto out; 1324ed1eea8STomer Tayar 1334ed1eea8STomer Tayar p_cmd_elem->p_mb_params = p_mb_params; 1344ed1eea8STomer Tayar p_cmd_elem->expected_seq_num = expected_seq_num; 1354ed1eea8STomer Tayar list_add(&p_cmd_elem->list, &p_hwfn->mcp_info->cmd_list); 1364ed1eea8STomer Tayar out: 1374ed1eea8STomer Tayar return p_cmd_elem; 1384ed1eea8STomer Tayar } 1394ed1eea8STomer Tayar 1404ed1eea8STomer Tayar /* Must be called while cmd_lock is acquired */ 1414ed1eea8STomer Tayar static void qed_mcp_cmd_del_elem(struct qed_hwfn *p_hwfn, 1424ed1eea8STomer Tayar struct qed_mcp_cmd_elem *p_cmd_elem) 1434ed1eea8STomer Tayar { 1444ed1eea8STomer Tayar list_del(&p_cmd_elem->list); 1454ed1eea8STomer Tayar kfree(p_cmd_elem); 1464ed1eea8STomer Tayar } 1474ed1eea8STomer Tayar 1484ed1eea8STomer Tayar /* Must be called while cmd_lock is acquired */ 1494ed1eea8STomer Tayar static struct qed_mcp_cmd_elem *qed_mcp_cmd_get_elem(struct qed_hwfn *p_hwfn, 1504ed1eea8STomer Tayar u16 seq_num) 1514ed1eea8STomer Tayar { 1524ed1eea8STomer Tayar struct qed_mcp_cmd_elem *p_cmd_elem = NULL; 1534ed1eea8STomer Tayar 1544ed1eea8STomer Tayar list_for_each_entry(p_cmd_elem, &p_hwfn->mcp_info->cmd_list, list) { 1554ed1eea8STomer Tayar if (p_cmd_elem->expected_seq_num == seq_num) 1564ed1eea8STomer Tayar return p_cmd_elem; 1574ed1eea8STomer Tayar } 1584ed1eea8STomer Tayar 1594ed1eea8STomer Tayar return NULL; 1604ed1eea8STomer Tayar } 1614ed1eea8STomer Tayar 162fe56b9e6SYuval Mintz int qed_mcp_free(struct qed_hwfn *p_hwfn) 163fe56b9e6SYuval Mintz { 164fe56b9e6SYuval Mintz if (p_hwfn->mcp_info) { 1654ed1eea8STomer Tayar struct qed_mcp_cmd_elem *p_cmd_elem, *p_tmp; 1664ed1eea8STomer Tayar 167fe56b9e6SYuval Mintz kfree(p_hwfn->mcp_info->mfw_mb_cur); 168fe56b9e6SYuval Mintz kfree(p_hwfn->mcp_info->mfw_mb_shadow); 1694ed1eea8STomer Tayar 1704ed1eea8STomer Tayar spin_lock_bh(&p_hwfn->mcp_info->cmd_lock); 1714ed1eea8STomer Tayar list_for_each_entry_safe(p_cmd_elem, 1724ed1eea8STomer Tayar p_tmp, 1734ed1eea8STomer Tayar &p_hwfn->mcp_info->cmd_list, list) { 1744ed1eea8STomer Tayar qed_mcp_cmd_del_elem(p_hwfn, p_cmd_elem); 175fe56b9e6SYuval Mintz } 1764ed1eea8STomer Tayar spin_unlock_bh(&p_hwfn->mcp_info->cmd_lock); 1774ed1eea8STomer Tayar } 1784ed1eea8STomer Tayar 179fe56b9e6SYuval Mintz kfree(p_hwfn->mcp_info); 1803587cb87STomer Tayar p_hwfn->mcp_info = NULL; 181fe56b9e6SYuval Mintz 182fe56b9e6SYuval Mintz return 0; 183fe56b9e6SYuval Mintz } 184fe56b9e6SYuval Mintz 1851a635e48SYuval Mintz static int qed_load_mcp_offsets(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 186fe56b9e6SYuval Mintz { 187fe56b9e6SYuval Mintz struct qed_mcp_info *p_info = p_hwfn->mcp_info; 188fe56b9e6SYuval Mintz u32 drv_mb_offsize, mfw_mb_offsize; 189fe56b9e6SYuval Mintz u32 mcp_pf_id = MCP_PF_ID(p_hwfn); 190fe56b9e6SYuval Mintz 191fe56b9e6SYuval Mintz p_info->public_base = qed_rd(p_hwfn, p_ptt, MISC_REG_SHARED_MEM_ADDR); 192fe56b9e6SYuval Mintz if (!p_info->public_base) 193fe56b9e6SYuval Mintz return 0; 194fe56b9e6SYuval Mintz 195fe56b9e6SYuval Mintz p_info->public_base |= GRCBASE_MCP; 196fe56b9e6SYuval Mintz 197fe56b9e6SYuval Mintz /* Calculate the driver and MFW mailbox address */ 198fe56b9e6SYuval Mintz drv_mb_offsize = qed_rd(p_hwfn, p_ptt, 199fe56b9e6SYuval Mintz SECTION_OFFSIZE_ADDR(p_info->public_base, 200fe56b9e6SYuval Mintz PUBLIC_DRV_MB)); 201fe56b9e6SYuval Mintz p_info->drv_mb_addr = SECTION_ADDR(drv_mb_offsize, mcp_pf_id); 202fe56b9e6SYuval Mintz DP_VERBOSE(p_hwfn, QED_MSG_SP, 203fe56b9e6SYuval Mintz "drv_mb_offsiz = 0x%x, drv_mb_addr = 0x%x mcp_pf_id = 0x%x\n", 204fe56b9e6SYuval Mintz drv_mb_offsize, p_info->drv_mb_addr, mcp_pf_id); 205fe56b9e6SYuval Mintz 206fe56b9e6SYuval Mintz /* Set the MFW MB address */ 207fe56b9e6SYuval Mintz mfw_mb_offsize = qed_rd(p_hwfn, p_ptt, 208fe56b9e6SYuval Mintz SECTION_OFFSIZE_ADDR(p_info->public_base, 209fe56b9e6SYuval Mintz PUBLIC_MFW_MB)); 210fe56b9e6SYuval Mintz p_info->mfw_mb_addr = SECTION_ADDR(mfw_mb_offsize, mcp_pf_id); 211fe56b9e6SYuval Mintz p_info->mfw_mb_length = (u16)qed_rd(p_hwfn, p_ptt, p_info->mfw_mb_addr); 212fe56b9e6SYuval Mintz 213fe56b9e6SYuval Mintz /* Get the current driver mailbox sequence before sending 214fe56b9e6SYuval Mintz * the first command 215fe56b9e6SYuval Mintz */ 216fe56b9e6SYuval Mintz p_info->drv_mb_seq = DRV_MB_RD(p_hwfn, p_ptt, drv_mb_header) & 217fe56b9e6SYuval Mintz DRV_MSG_SEQ_NUMBER_MASK; 218fe56b9e6SYuval Mintz 219fe56b9e6SYuval Mintz /* Get current FW pulse sequence */ 220fe56b9e6SYuval Mintz p_info->drv_pulse_seq = DRV_MB_RD(p_hwfn, p_ptt, drv_pulse_mb) & 221fe56b9e6SYuval Mintz DRV_PULSE_SEQ_MASK; 222fe56b9e6SYuval Mintz 2234ed1eea8STomer Tayar p_info->mcp_hist = qed_rd(p_hwfn, p_ptt, MISCS_REG_GENERIC_POR_0); 224fe56b9e6SYuval Mintz 225fe56b9e6SYuval Mintz return 0; 226fe56b9e6SYuval Mintz } 227fe56b9e6SYuval Mintz 2281a635e48SYuval Mintz int qed_mcp_cmd_init(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 229fe56b9e6SYuval Mintz { 230fe56b9e6SYuval Mintz struct qed_mcp_info *p_info; 231fe56b9e6SYuval Mintz u32 size; 232fe56b9e6SYuval Mintz 233fe56b9e6SYuval Mintz /* Allocate mcp_info structure */ 23460fffb3bSYuval Mintz p_hwfn->mcp_info = kzalloc(sizeof(*p_hwfn->mcp_info), GFP_KERNEL); 235fe56b9e6SYuval Mintz if (!p_hwfn->mcp_info) 236fe56b9e6SYuval Mintz goto err; 237fe56b9e6SYuval Mintz p_info = p_hwfn->mcp_info; 238fe56b9e6SYuval Mintz 2394ed1eea8STomer Tayar /* Initialize the MFW spinlock */ 2404ed1eea8STomer Tayar spin_lock_init(&p_info->cmd_lock); 2414ed1eea8STomer Tayar spin_lock_init(&p_info->link_lock); 2424ed1eea8STomer Tayar 2434ed1eea8STomer Tayar INIT_LIST_HEAD(&p_info->cmd_list); 2444ed1eea8STomer Tayar 245fe56b9e6SYuval Mintz if (qed_load_mcp_offsets(p_hwfn, p_ptt) != 0) { 246fe56b9e6SYuval Mintz DP_NOTICE(p_hwfn, "MCP is not initialized\n"); 247fe56b9e6SYuval Mintz /* Do not free mcp_info here, since public_base indicate that 248fe56b9e6SYuval Mintz * the MCP is not initialized 249fe56b9e6SYuval Mintz */ 250fe56b9e6SYuval Mintz return 0; 251fe56b9e6SYuval Mintz } 252fe56b9e6SYuval Mintz 253fe56b9e6SYuval Mintz size = MFW_DRV_MSG_MAX_DWORDS(p_info->mfw_mb_length) * sizeof(u32); 25460fffb3bSYuval Mintz p_info->mfw_mb_cur = kzalloc(size, GFP_KERNEL); 25583aeb933SYuval Mintz p_info->mfw_mb_shadow = kzalloc(size, GFP_KERNEL); 256fe56b9e6SYuval Mintz if (!p_info->mfw_mb_shadow || !p_info->mfw_mb_addr) 257fe56b9e6SYuval Mintz goto err; 258fe56b9e6SYuval Mintz 259fe56b9e6SYuval Mintz return 0; 260fe56b9e6SYuval Mintz 261fe56b9e6SYuval Mintz err: 262fe56b9e6SYuval Mintz qed_mcp_free(p_hwfn); 263fe56b9e6SYuval Mintz return -ENOMEM; 264fe56b9e6SYuval Mintz } 265fe56b9e6SYuval Mintz 2664ed1eea8STomer Tayar static void qed_mcp_reread_offsets(struct qed_hwfn *p_hwfn, 2674ed1eea8STomer Tayar struct qed_ptt *p_ptt) 2685529bad9STomer Tayar { 2694ed1eea8STomer Tayar u32 generic_por_0 = qed_rd(p_hwfn, p_ptt, MISCS_REG_GENERIC_POR_0); 2705529bad9STomer Tayar 2714ed1eea8STomer Tayar /* Use MCP history register to check if MCP reset occurred between init 2724ed1eea8STomer Tayar * time and now. 2735529bad9STomer Tayar */ 2744ed1eea8STomer Tayar if (p_hwfn->mcp_info->mcp_hist != generic_por_0) { 2754ed1eea8STomer Tayar DP_VERBOSE(p_hwfn, 2764ed1eea8STomer Tayar QED_MSG_SP, 2774ed1eea8STomer Tayar "Rereading MCP offsets [mcp_hist 0x%08x, generic_por_0 0x%08x]\n", 2784ed1eea8STomer Tayar p_hwfn->mcp_info->mcp_hist, generic_por_0); 2795529bad9STomer Tayar 2804ed1eea8STomer Tayar qed_load_mcp_offsets(p_hwfn, p_ptt); 2814ed1eea8STomer Tayar qed_mcp_cmd_port_init(p_hwfn, p_ptt); 2825529bad9STomer Tayar } 2835529bad9STomer Tayar } 2845529bad9STomer Tayar 2851a635e48SYuval Mintz int qed_mcp_reset(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 286fe56b9e6SYuval Mintz { 2874ed1eea8STomer Tayar u32 org_mcp_reset_seq, seq, delay = CHIP_MCP_RESP_ITER_US, cnt = 0; 288fe56b9e6SYuval Mintz int rc = 0; 289fe56b9e6SYuval Mintz 2904ed1eea8STomer Tayar /* Ensure that only a single thread is accessing the mailbox */ 2914ed1eea8STomer Tayar spin_lock_bh(&p_hwfn->mcp_info->cmd_lock); 2924ed1eea8STomer Tayar 2934ed1eea8STomer Tayar org_mcp_reset_seq = qed_rd(p_hwfn, p_ptt, MISCS_REG_GENERIC_POR_0); 2945529bad9STomer Tayar 295fe56b9e6SYuval Mintz /* Set drv command along with the updated sequence */ 2964ed1eea8STomer Tayar qed_mcp_reread_offsets(p_hwfn, p_ptt); 2974ed1eea8STomer Tayar seq = ++p_hwfn->mcp_info->drv_mb_seq; 2984ed1eea8STomer Tayar DRV_MB_WR(p_hwfn, p_ptt, drv_mb_header, (DRV_MSG_CODE_MCP_RESET | seq)); 299fe56b9e6SYuval Mintz 300fe56b9e6SYuval Mintz do { 301fe56b9e6SYuval Mintz /* Wait for MFW response */ 302fe56b9e6SYuval Mintz udelay(delay); 303fe56b9e6SYuval Mintz /* Give the FW up to 500 second (50*1000*10usec) */ 304fe56b9e6SYuval Mintz } while ((org_mcp_reset_seq == qed_rd(p_hwfn, p_ptt, 305fe56b9e6SYuval Mintz MISCS_REG_GENERIC_POR_0)) && 306fe56b9e6SYuval Mintz (cnt++ < QED_MCP_RESET_RETRIES)); 307fe56b9e6SYuval Mintz 308fe56b9e6SYuval Mintz if (org_mcp_reset_seq != 309fe56b9e6SYuval Mintz qed_rd(p_hwfn, p_ptt, MISCS_REG_GENERIC_POR_0)) { 310fe56b9e6SYuval Mintz DP_VERBOSE(p_hwfn, QED_MSG_SP, 311fe56b9e6SYuval Mintz "MCP was reset after %d usec\n", cnt * delay); 312fe56b9e6SYuval Mintz } else { 313fe56b9e6SYuval Mintz DP_ERR(p_hwfn, "Failed to reset MCP\n"); 314fe56b9e6SYuval Mintz rc = -EAGAIN; 315fe56b9e6SYuval Mintz } 316fe56b9e6SYuval Mintz 3174ed1eea8STomer Tayar spin_unlock_bh(&p_hwfn->mcp_info->cmd_lock); 3185529bad9STomer Tayar 319fe56b9e6SYuval Mintz return rc; 320fe56b9e6SYuval Mintz } 321fe56b9e6SYuval Mintz 3224ed1eea8STomer Tayar /* Must be called while cmd_lock is acquired */ 3234ed1eea8STomer Tayar static bool qed_mcp_has_pending_cmd(struct qed_hwfn *p_hwfn) 324fe56b9e6SYuval Mintz { 3254ed1eea8STomer Tayar struct qed_mcp_cmd_elem *p_cmd_elem; 3264ed1eea8STomer Tayar 3274ed1eea8STomer Tayar /* There is at most one pending command at a certain time, and if it 3284ed1eea8STomer Tayar * exists - it is placed at the HEAD of the list. 3294ed1eea8STomer Tayar */ 3304ed1eea8STomer Tayar if (!list_empty(&p_hwfn->mcp_info->cmd_list)) { 3314ed1eea8STomer Tayar p_cmd_elem = list_first_entry(&p_hwfn->mcp_info->cmd_list, 3324ed1eea8STomer Tayar struct qed_mcp_cmd_elem, list); 3334ed1eea8STomer Tayar return !p_cmd_elem->b_is_completed; 3344ed1eea8STomer Tayar } 3354ed1eea8STomer Tayar 3364ed1eea8STomer Tayar return false; 3374ed1eea8STomer Tayar } 3384ed1eea8STomer Tayar 3394ed1eea8STomer Tayar /* Must be called while cmd_lock is acquired */ 3404ed1eea8STomer Tayar static int 3414ed1eea8STomer Tayar qed_mcp_update_pending_cmd(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 3424ed1eea8STomer Tayar { 3434ed1eea8STomer Tayar struct qed_mcp_mb_params *p_mb_params; 3444ed1eea8STomer Tayar struct qed_mcp_cmd_elem *p_cmd_elem; 3454ed1eea8STomer Tayar u32 mcp_resp; 3464ed1eea8STomer Tayar u16 seq_num; 3474ed1eea8STomer Tayar 3484ed1eea8STomer Tayar mcp_resp = DRV_MB_RD(p_hwfn, p_ptt, fw_mb_header); 3494ed1eea8STomer Tayar seq_num = (u16)(mcp_resp & FW_MSG_SEQ_NUMBER_MASK); 3504ed1eea8STomer Tayar 3514ed1eea8STomer Tayar /* Return if no new non-handled response has been received */ 3524ed1eea8STomer Tayar if (seq_num != p_hwfn->mcp_info->drv_mb_seq) 3534ed1eea8STomer Tayar return -EAGAIN; 3544ed1eea8STomer Tayar 3554ed1eea8STomer Tayar p_cmd_elem = qed_mcp_cmd_get_elem(p_hwfn, seq_num); 3564ed1eea8STomer Tayar if (!p_cmd_elem) { 3574ed1eea8STomer Tayar DP_ERR(p_hwfn, 3584ed1eea8STomer Tayar "Failed to find a pending mailbox cmd that expects sequence number %d\n", 3594ed1eea8STomer Tayar seq_num); 3604ed1eea8STomer Tayar return -EINVAL; 3614ed1eea8STomer Tayar } 3624ed1eea8STomer Tayar 3634ed1eea8STomer Tayar p_mb_params = p_cmd_elem->p_mb_params; 3644ed1eea8STomer Tayar 3654ed1eea8STomer Tayar /* Get the MFW response along with the sequence number */ 3664ed1eea8STomer Tayar p_mb_params->mcp_resp = mcp_resp; 3674ed1eea8STomer Tayar 3684ed1eea8STomer Tayar /* Get the MFW param */ 3694ed1eea8STomer Tayar p_mb_params->mcp_param = DRV_MB_RD(p_hwfn, p_ptt, fw_mb_param); 3704ed1eea8STomer Tayar 3714ed1eea8STomer Tayar /* Get the union data */ 3722f67af8cSTomer Tayar if (p_mb_params->p_data_dst != NULL && p_mb_params->data_dst_size) { 3734ed1eea8STomer Tayar u32 union_data_addr = p_hwfn->mcp_info->drv_mb_addr + 3744ed1eea8STomer Tayar offsetof(struct public_drv_mb, 3754ed1eea8STomer Tayar union_data); 3764ed1eea8STomer Tayar qed_memcpy_from(p_hwfn, p_ptt, p_mb_params->p_data_dst, 3772f67af8cSTomer Tayar union_data_addr, p_mb_params->data_dst_size); 3784ed1eea8STomer Tayar } 3794ed1eea8STomer Tayar 3804ed1eea8STomer Tayar p_cmd_elem->b_is_completed = true; 3814ed1eea8STomer Tayar 3824ed1eea8STomer Tayar return 0; 3834ed1eea8STomer Tayar } 3844ed1eea8STomer Tayar 3854ed1eea8STomer Tayar /* Must be called while cmd_lock is acquired */ 3864ed1eea8STomer Tayar static void __qed_mcp_cmd_and_union(struct qed_hwfn *p_hwfn, 3874ed1eea8STomer Tayar struct qed_ptt *p_ptt, 3884ed1eea8STomer Tayar struct qed_mcp_mb_params *p_mb_params, 3894ed1eea8STomer Tayar u16 seq_num) 3904ed1eea8STomer Tayar { 3914ed1eea8STomer Tayar union drv_union_data union_data; 3924ed1eea8STomer Tayar u32 union_data_addr; 3934ed1eea8STomer Tayar 3944ed1eea8STomer Tayar /* Set the union data */ 3954ed1eea8STomer Tayar union_data_addr = p_hwfn->mcp_info->drv_mb_addr + 3964ed1eea8STomer Tayar offsetof(struct public_drv_mb, union_data); 3974ed1eea8STomer Tayar memset(&union_data, 0, sizeof(union_data)); 3982f67af8cSTomer Tayar if (p_mb_params->p_data_src != NULL && p_mb_params->data_src_size) 3994ed1eea8STomer Tayar memcpy(&union_data, p_mb_params->p_data_src, 4002f67af8cSTomer Tayar p_mb_params->data_src_size); 4014ed1eea8STomer Tayar qed_memcpy_to(p_hwfn, p_ptt, union_data_addr, &union_data, 4024ed1eea8STomer Tayar sizeof(union_data)); 4034ed1eea8STomer Tayar 4044ed1eea8STomer Tayar /* Set the drv param */ 4054ed1eea8STomer Tayar DRV_MB_WR(p_hwfn, p_ptt, drv_mb_param, p_mb_params->param); 4064ed1eea8STomer Tayar 4074ed1eea8STomer Tayar /* Set the drv command along with the sequence number */ 4084ed1eea8STomer Tayar DRV_MB_WR(p_hwfn, p_ptt, drv_mb_header, (p_mb_params->cmd | seq_num)); 4094ed1eea8STomer Tayar 4104ed1eea8STomer Tayar DP_VERBOSE(p_hwfn, QED_MSG_SP, 4114ed1eea8STomer Tayar "MFW mailbox: command 0x%08x param 0x%08x\n", 4124ed1eea8STomer Tayar (p_mb_params->cmd | seq_num), p_mb_params->param); 4134ed1eea8STomer Tayar } 4144ed1eea8STomer Tayar 4154ed1eea8STomer Tayar static int 4164ed1eea8STomer Tayar _qed_mcp_cmd_and_union(struct qed_hwfn *p_hwfn, 4174ed1eea8STomer Tayar struct qed_ptt *p_ptt, 4184ed1eea8STomer Tayar struct qed_mcp_mb_params *p_mb_params, 4194ed1eea8STomer Tayar u32 max_retries, u32 delay) 4204ed1eea8STomer Tayar { 4214ed1eea8STomer Tayar struct qed_mcp_cmd_elem *p_cmd_elem; 4224ed1eea8STomer Tayar u32 cnt = 0; 4234ed1eea8STomer Tayar u16 seq_num; 424fe56b9e6SYuval Mintz int rc = 0; 425fe56b9e6SYuval Mintz 4264ed1eea8STomer Tayar /* Wait until the mailbox is non-occupied */ 427fe56b9e6SYuval Mintz do { 4284ed1eea8STomer Tayar /* Exit the loop if there is no pending command, or if the 4294ed1eea8STomer Tayar * pending command is completed during this iteration. 4304ed1eea8STomer Tayar * The spinlock stays locked until the command is sent. 4314ed1eea8STomer Tayar */ 4324ed1eea8STomer Tayar 4334ed1eea8STomer Tayar spin_lock_bh(&p_hwfn->mcp_info->cmd_lock); 4344ed1eea8STomer Tayar 4354ed1eea8STomer Tayar if (!qed_mcp_has_pending_cmd(p_hwfn)) 4364ed1eea8STomer Tayar break; 4374ed1eea8STomer Tayar 4384ed1eea8STomer Tayar rc = qed_mcp_update_pending_cmd(p_hwfn, p_ptt); 4394ed1eea8STomer Tayar if (!rc) 4404ed1eea8STomer Tayar break; 4414ed1eea8STomer Tayar else if (rc != -EAGAIN) 4424ed1eea8STomer Tayar goto err; 4434ed1eea8STomer Tayar 4444ed1eea8STomer Tayar spin_unlock_bh(&p_hwfn->mcp_info->cmd_lock); 445fe56b9e6SYuval Mintz udelay(delay); 4464ed1eea8STomer Tayar } while (++cnt < max_retries); 447fe56b9e6SYuval Mintz 4484ed1eea8STomer Tayar if (cnt >= max_retries) { 4494ed1eea8STomer Tayar DP_NOTICE(p_hwfn, 4504ed1eea8STomer Tayar "The MFW mailbox is occupied by an uncompleted command. Failed to send command 0x%08x [param 0x%08x].\n", 4514ed1eea8STomer Tayar p_mb_params->cmd, p_mb_params->param); 4524ed1eea8STomer Tayar return -EAGAIN; 453fe56b9e6SYuval Mintz } 4544ed1eea8STomer Tayar 4554ed1eea8STomer Tayar /* Send the mailbox command */ 4564ed1eea8STomer Tayar qed_mcp_reread_offsets(p_hwfn, p_ptt); 4574ed1eea8STomer Tayar seq_num = ++p_hwfn->mcp_info->drv_mb_seq; 4584ed1eea8STomer Tayar p_cmd_elem = qed_mcp_cmd_add_elem(p_hwfn, p_mb_params, seq_num); 459c8004600SDan Carpenter if (!p_cmd_elem) { 460c8004600SDan Carpenter rc = -ENOMEM; 4614ed1eea8STomer Tayar goto err; 462c8004600SDan Carpenter } 4634ed1eea8STomer Tayar 4644ed1eea8STomer Tayar __qed_mcp_cmd_and_union(p_hwfn, p_ptt, p_mb_params, seq_num); 4654ed1eea8STomer Tayar spin_unlock_bh(&p_hwfn->mcp_info->cmd_lock); 4664ed1eea8STomer Tayar 4674ed1eea8STomer Tayar /* Wait for the MFW response */ 4684ed1eea8STomer Tayar do { 4694ed1eea8STomer Tayar /* Exit the loop if the command is already completed, or if the 4704ed1eea8STomer Tayar * command is completed during this iteration. 4714ed1eea8STomer Tayar * The spinlock stays locked until the list element is removed. 4724ed1eea8STomer Tayar */ 4734ed1eea8STomer Tayar 4744ed1eea8STomer Tayar udelay(delay); 4754ed1eea8STomer Tayar spin_lock_bh(&p_hwfn->mcp_info->cmd_lock); 4764ed1eea8STomer Tayar 4774ed1eea8STomer Tayar if (p_cmd_elem->b_is_completed) 4784ed1eea8STomer Tayar break; 4794ed1eea8STomer Tayar 4804ed1eea8STomer Tayar rc = qed_mcp_update_pending_cmd(p_hwfn, p_ptt); 4814ed1eea8STomer Tayar if (!rc) 4824ed1eea8STomer Tayar break; 4834ed1eea8STomer Tayar else if (rc != -EAGAIN) 4844ed1eea8STomer Tayar goto err; 4854ed1eea8STomer Tayar 4864ed1eea8STomer Tayar spin_unlock_bh(&p_hwfn->mcp_info->cmd_lock); 4874ed1eea8STomer Tayar } while (++cnt < max_retries); 4884ed1eea8STomer Tayar 4894ed1eea8STomer Tayar if (cnt >= max_retries) { 4904ed1eea8STomer Tayar DP_NOTICE(p_hwfn, 4914ed1eea8STomer Tayar "The MFW failed to respond to command 0x%08x [param 0x%08x].\n", 4924ed1eea8STomer Tayar p_mb_params->cmd, p_mb_params->param); 4934ed1eea8STomer Tayar 4944ed1eea8STomer Tayar spin_lock_bh(&p_hwfn->mcp_info->cmd_lock); 4954ed1eea8STomer Tayar qed_mcp_cmd_del_elem(p_hwfn, p_cmd_elem); 4964ed1eea8STomer Tayar spin_unlock_bh(&p_hwfn->mcp_info->cmd_lock); 4974ed1eea8STomer Tayar 4984ed1eea8STomer Tayar return -EAGAIN; 4994ed1eea8STomer Tayar } 5004ed1eea8STomer Tayar 5014ed1eea8STomer Tayar qed_mcp_cmd_del_elem(p_hwfn, p_cmd_elem); 5024ed1eea8STomer Tayar spin_unlock_bh(&p_hwfn->mcp_info->cmd_lock); 5034ed1eea8STomer Tayar 5044ed1eea8STomer Tayar DP_VERBOSE(p_hwfn, 5054ed1eea8STomer Tayar QED_MSG_SP, 5064ed1eea8STomer Tayar "MFW mailbox: response 0x%08x param 0x%08x [after %d.%03d ms]\n", 5074ed1eea8STomer Tayar p_mb_params->mcp_resp, 5084ed1eea8STomer Tayar p_mb_params->mcp_param, 5094ed1eea8STomer Tayar (cnt * delay) / 1000, (cnt * delay) % 1000); 5104ed1eea8STomer Tayar 5114ed1eea8STomer Tayar /* Clear the sequence number from the MFW response */ 5124ed1eea8STomer Tayar p_mb_params->mcp_resp &= FW_MSG_CODE_MASK; 5134ed1eea8STomer Tayar 5144ed1eea8STomer Tayar return 0; 5154ed1eea8STomer Tayar 5164ed1eea8STomer Tayar err: 5174ed1eea8STomer Tayar spin_unlock_bh(&p_hwfn->mcp_info->cmd_lock); 518fe56b9e6SYuval Mintz return rc; 519fe56b9e6SYuval Mintz } 520fe56b9e6SYuval Mintz 5215529bad9STomer Tayar static int qed_mcp_cmd_and_union(struct qed_hwfn *p_hwfn, 522fe56b9e6SYuval Mintz struct qed_ptt *p_ptt, 5235529bad9STomer Tayar struct qed_mcp_mb_params *p_mb_params) 524fe56b9e6SYuval Mintz { 5252f67af8cSTomer Tayar size_t union_data_size = sizeof(union drv_union_data); 5264ed1eea8STomer Tayar u32 max_retries = QED_DRV_MB_MAX_RETRIES; 5274ed1eea8STomer Tayar u32 delay = CHIP_MCP_RESP_ITER_US; 528fe56b9e6SYuval Mintz 529fe56b9e6SYuval Mintz /* MCP not initialized */ 530fe56b9e6SYuval Mintz if (!qed_mcp_is_init(p_hwfn)) { 531fe56b9e6SYuval Mintz DP_NOTICE(p_hwfn, "MFW is not initialized!\n"); 532fe56b9e6SYuval Mintz return -EBUSY; 533fe56b9e6SYuval Mintz } 534fe56b9e6SYuval Mintz 5352f67af8cSTomer Tayar if (p_mb_params->data_src_size > union_data_size || 5362f67af8cSTomer Tayar p_mb_params->data_dst_size > union_data_size) { 5372f67af8cSTomer Tayar DP_ERR(p_hwfn, 5382f67af8cSTomer Tayar "The provided size is larger than the union data size [src_size %u, dst_size %u, union_data_size %zu]\n", 5392f67af8cSTomer Tayar p_mb_params->data_src_size, 5402f67af8cSTomer Tayar p_mb_params->data_dst_size, union_data_size); 5412f67af8cSTomer Tayar return -EINVAL; 5422f67af8cSTomer Tayar } 5432f67af8cSTomer Tayar 5444ed1eea8STomer Tayar return _qed_mcp_cmd_and_union(p_hwfn, p_ptt, p_mb_params, max_retries, 5454ed1eea8STomer Tayar delay); 546fe56b9e6SYuval Mintz } 547fe56b9e6SYuval Mintz 5485529bad9STomer Tayar int qed_mcp_cmd(struct qed_hwfn *p_hwfn, 5495529bad9STomer Tayar struct qed_ptt *p_ptt, 5505529bad9STomer Tayar u32 cmd, 5515529bad9STomer Tayar u32 param, 5525529bad9STomer Tayar u32 *o_mcp_resp, 5535529bad9STomer Tayar u32 *o_mcp_param) 554fe56b9e6SYuval Mintz { 5555529bad9STomer Tayar struct qed_mcp_mb_params mb_params; 5565529bad9STomer Tayar int rc; 557fe56b9e6SYuval Mintz 5585529bad9STomer Tayar memset(&mb_params, 0, sizeof(mb_params)); 5595529bad9STomer Tayar mb_params.cmd = cmd; 5605529bad9STomer Tayar mb_params.param = param; 56114d39648SMintz, Yuval 5625529bad9STomer Tayar rc = qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 5635529bad9STomer Tayar if (rc) 5645529bad9STomer Tayar return rc; 5655529bad9STomer Tayar 5665529bad9STomer Tayar *o_mcp_resp = mb_params.mcp_resp; 5675529bad9STomer Tayar *o_mcp_param = mb_params.mcp_param; 5685529bad9STomer Tayar 5695529bad9STomer Tayar return 0; 570fe56b9e6SYuval Mintz } 571fe56b9e6SYuval Mintz 5724102426fSTomer Tayar int qed_mcp_nvm_rd_cmd(struct qed_hwfn *p_hwfn, 5734102426fSTomer Tayar struct qed_ptt *p_ptt, 5744102426fSTomer Tayar u32 cmd, 5754102426fSTomer Tayar u32 param, 5764102426fSTomer Tayar u32 *o_mcp_resp, 5774102426fSTomer Tayar u32 *o_mcp_param, u32 *o_txn_size, u32 *o_buf) 5784102426fSTomer Tayar { 5794102426fSTomer Tayar struct qed_mcp_mb_params mb_params; 5802f67af8cSTomer Tayar u8 raw_data[MCP_DRV_NVM_BUF_LEN]; 5814102426fSTomer Tayar int rc; 5824102426fSTomer Tayar 5834102426fSTomer Tayar memset(&mb_params, 0, sizeof(mb_params)); 5844102426fSTomer Tayar mb_params.cmd = cmd; 5854102426fSTomer Tayar mb_params.param = param; 5862f67af8cSTomer Tayar mb_params.p_data_dst = raw_data; 5872f67af8cSTomer Tayar 5882f67af8cSTomer Tayar /* Use the maximal value since the actual one is part of the response */ 5892f67af8cSTomer Tayar mb_params.data_dst_size = MCP_DRV_NVM_BUF_LEN; 5902f67af8cSTomer Tayar 5914102426fSTomer Tayar rc = qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 5924102426fSTomer Tayar if (rc) 5934102426fSTomer Tayar return rc; 5944102426fSTomer Tayar 5954102426fSTomer Tayar *o_mcp_resp = mb_params.mcp_resp; 5964102426fSTomer Tayar *o_mcp_param = mb_params.mcp_param; 5974102426fSTomer Tayar 5984102426fSTomer Tayar *o_txn_size = *o_mcp_param; 5992f67af8cSTomer Tayar memcpy(o_buf, raw_data, *o_txn_size); 6004102426fSTomer Tayar 6014102426fSTomer Tayar return 0; 6024102426fSTomer Tayar } 6034102426fSTomer Tayar 6045d24bcf1STomer Tayar static bool 6055d24bcf1STomer Tayar qed_mcp_can_force_load(u8 drv_role, 6065d24bcf1STomer Tayar u8 exist_drv_role, 6075d24bcf1STomer Tayar enum qed_override_force_load override_force_load) 608fe56b9e6SYuval Mintz { 6095d24bcf1STomer Tayar bool can_force_load = false; 6105d24bcf1STomer Tayar 6115d24bcf1STomer Tayar switch (override_force_load) { 6125d24bcf1STomer Tayar case QED_OVERRIDE_FORCE_LOAD_ALWAYS: 6135d24bcf1STomer Tayar can_force_load = true; 6145d24bcf1STomer Tayar break; 6155d24bcf1STomer Tayar case QED_OVERRIDE_FORCE_LOAD_NEVER: 6165d24bcf1STomer Tayar can_force_load = false; 6175d24bcf1STomer Tayar break; 6185d24bcf1STomer Tayar default: 6195d24bcf1STomer Tayar can_force_load = (drv_role == DRV_ROLE_OS && 6205d24bcf1STomer Tayar exist_drv_role == DRV_ROLE_PREBOOT) || 6215d24bcf1STomer Tayar (drv_role == DRV_ROLE_KDUMP && 6225d24bcf1STomer Tayar exist_drv_role == DRV_ROLE_OS); 6235d24bcf1STomer Tayar break; 6245d24bcf1STomer Tayar } 6255d24bcf1STomer Tayar 6265d24bcf1STomer Tayar return can_force_load; 6275d24bcf1STomer Tayar } 6285d24bcf1STomer Tayar 6295d24bcf1STomer Tayar static int qed_mcp_cancel_load_req(struct qed_hwfn *p_hwfn, 6305d24bcf1STomer Tayar struct qed_ptt *p_ptt) 6315d24bcf1STomer Tayar { 6325d24bcf1STomer Tayar u32 resp = 0, param = 0; 633fe56b9e6SYuval Mintz int rc; 634fe56b9e6SYuval Mintz 6355d24bcf1STomer Tayar rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_CANCEL_LOAD_REQ, 0, 6365d24bcf1STomer Tayar &resp, ¶m); 6375d24bcf1STomer Tayar if (rc) 6385d24bcf1STomer Tayar DP_NOTICE(p_hwfn, 6395d24bcf1STomer Tayar "Failed to send cancel load request, rc = %d\n", rc); 640fe56b9e6SYuval Mintz 641fe56b9e6SYuval Mintz return rc; 642fe56b9e6SYuval Mintz } 643fe56b9e6SYuval Mintz 6445d24bcf1STomer Tayar #define CONFIG_QEDE_BITMAP_IDX BIT(0) 6455d24bcf1STomer Tayar #define CONFIG_QED_SRIOV_BITMAP_IDX BIT(1) 6465d24bcf1STomer Tayar #define CONFIG_QEDR_BITMAP_IDX BIT(2) 6475d24bcf1STomer Tayar #define CONFIG_QEDF_BITMAP_IDX BIT(4) 6485d24bcf1STomer Tayar #define CONFIG_QEDI_BITMAP_IDX BIT(5) 6495d24bcf1STomer Tayar #define CONFIG_QED_LL2_BITMAP_IDX BIT(6) 6505529bad9STomer Tayar 6515d24bcf1STomer Tayar static u32 qed_get_config_bitmap(void) 6525d24bcf1STomer Tayar { 6535d24bcf1STomer Tayar u32 config_bitmap = 0x0; 6545d24bcf1STomer Tayar 6555d24bcf1STomer Tayar if (IS_ENABLED(CONFIG_QEDE)) 6565d24bcf1STomer Tayar config_bitmap |= CONFIG_QEDE_BITMAP_IDX; 6575d24bcf1STomer Tayar 6585d24bcf1STomer Tayar if (IS_ENABLED(CONFIG_QED_SRIOV)) 6595d24bcf1STomer Tayar config_bitmap |= CONFIG_QED_SRIOV_BITMAP_IDX; 6605d24bcf1STomer Tayar 6615d24bcf1STomer Tayar if (IS_ENABLED(CONFIG_QED_RDMA)) 6625d24bcf1STomer Tayar config_bitmap |= CONFIG_QEDR_BITMAP_IDX; 6635d24bcf1STomer Tayar 6645d24bcf1STomer Tayar if (IS_ENABLED(CONFIG_QED_FCOE)) 6655d24bcf1STomer Tayar config_bitmap |= CONFIG_QEDF_BITMAP_IDX; 6665d24bcf1STomer Tayar 6675d24bcf1STomer Tayar if (IS_ENABLED(CONFIG_QED_ISCSI)) 6685d24bcf1STomer Tayar config_bitmap |= CONFIG_QEDI_BITMAP_IDX; 6695d24bcf1STomer Tayar 6705d24bcf1STomer Tayar if (IS_ENABLED(CONFIG_QED_LL2)) 6715d24bcf1STomer Tayar config_bitmap |= CONFIG_QED_LL2_BITMAP_IDX; 6725d24bcf1STomer Tayar 6735d24bcf1STomer Tayar return config_bitmap; 6745d24bcf1STomer Tayar } 6755d24bcf1STomer Tayar 6765d24bcf1STomer Tayar struct qed_load_req_in_params { 6775d24bcf1STomer Tayar u8 hsi_ver; 6785d24bcf1STomer Tayar #define QED_LOAD_REQ_HSI_VER_DEFAULT 0 6795d24bcf1STomer Tayar #define QED_LOAD_REQ_HSI_VER_1 1 6805d24bcf1STomer Tayar u32 drv_ver_0; 6815d24bcf1STomer Tayar u32 drv_ver_1; 6825d24bcf1STomer Tayar u32 fw_ver; 6835d24bcf1STomer Tayar u8 drv_role; 6845d24bcf1STomer Tayar u8 timeout_val; 6855d24bcf1STomer Tayar u8 force_cmd; 6865d24bcf1STomer Tayar bool avoid_eng_reset; 6875d24bcf1STomer Tayar }; 6885d24bcf1STomer Tayar 6895d24bcf1STomer Tayar struct qed_load_req_out_params { 6905d24bcf1STomer Tayar u32 load_code; 6915d24bcf1STomer Tayar u32 exist_drv_ver_0; 6925d24bcf1STomer Tayar u32 exist_drv_ver_1; 6935d24bcf1STomer Tayar u32 exist_fw_ver; 6945d24bcf1STomer Tayar u8 exist_drv_role; 6955d24bcf1STomer Tayar u8 mfw_hsi_ver; 6965d24bcf1STomer Tayar bool drv_exists; 6975d24bcf1STomer Tayar }; 6985d24bcf1STomer Tayar 6995d24bcf1STomer Tayar static int 7005d24bcf1STomer Tayar __qed_mcp_load_req(struct qed_hwfn *p_hwfn, 7015d24bcf1STomer Tayar struct qed_ptt *p_ptt, 7025d24bcf1STomer Tayar struct qed_load_req_in_params *p_in_params, 7035d24bcf1STomer Tayar struct qed_load_req_out_params *p_out_params) 7045d24bcf1STomer Tayar { 7055d24bcf1STomer Tayar struct qed_mcp_mb_params mb_params; 7065d24bcf1STomer Tayar struct load_req_stc load_req; 7075d24bcf1STomer Tayar struct load_rsp_stc load_rsp; 7085d24bcf1STomer Tayar u32 hsi_ver; 7095d24bcf1STomer Tayar int rc; 7105d24bcf1STomer Tayar 7115d24bcf1STomer Tayar memset(&load_req, 0, sizeof(load_req)); 7125d24bcf1STomer Tayar load_req.drv_ver_0 = p_in_params->drv_ver_0; 7135d24bcf1STomer Tayar load_req.drv_ver_1 = p_in_params->drv_ver_1; 7145d24bcf1STomer Tayar load_req.fw_ver = p_in_params->fw_ver; 7155d24bcf1STomer Tayar QED_MFW_SET_FIELD(load_req.misc0, LOAD_REQ_ROLE, p_in_params->drv_role); 7165d24bcf1STomer Tayar QED_MFW_SET_FIELD(load_req.misc0, LOAD_REQ_LOCK_TO, 7175d24bcf1STomer Tayar p_in_params->timeout_val); 7185d24bcf1STomer Tayar QED_MFW_SET_FIELD(load_req.misc0, LOAD_REQ_FORCE, 7195d24bcf1STomer Tayar p_in_params->force_cmd); 7205d24bcf1STomer Tayar QED_MFW_SET_FIELD(load_req.misc0, LOAD_REQ_FLAGS0, 7215d24bcf1STomer Tayar p_in_params->avoid_eng_reset); 7225d24bcf1STomer Tayar 7235d24bcf1STomer Tayar hsi_ver = (p_in_params->hsi_ver == QED_LOAD_REQ_HSI_VER_DEFAULT) ? 7245d24bcf1STomer Tayar DRV_ID_MCP_HSI_VER_CURRENT : 7255d24bcf1STomer Tayar (p_in_params->hsi_ver << DRV_ID_MCP_HSI_VER_SHIFT); 7265d24bcf1STomer Tayar 7275d24bcf1STomer Tayar memset(&mb_params, 0, sizeof(mb_params)); 7285d24bcf1STomer Tayar mb_params.cmd = DRV_MSG_CODE_LOAD_REQ; 7295d24bcf1STomer Tayar mb_params.param = PDA_COMP | hsi_ver | p_hwfn->cdev->drv_type; 7305d24bcf1STomer Tayar mb_params.p_data_src = &load_req; 7315d24bcf1STomer Tayar mb_params.data_src_size = sizeof(load_req); 7325d24bcf1STomer Tayar mb_params.p_data_dst = &load_rsp; 7335d24bcf1STomer Tayar mb_params.data_dst_size = sizeof(load_rsp); 7345d24bcf1STomer Tayar 7355d24bcf1STomer Tayar DP_VERBOSE(p_hwfn, QED_MSG_SP, 7365d24bcf1STomer Tayar "Load Request: param 0x%08x [init_hw %d, drv_type %d, hsi_ver %d, pda 0x%04x]\n", 7375d24bcf1STomer Tayar mb_params.param, 7385d24bcf1STomer Tayar QED_MFW_GET_FIELD(mb_params.param, DRV_ID_DRV_INIT_HW), 7395d24bcf1STomer Tayar QED_MFW_GET_FIELD(mb_params.param, DRV_ID_DRV_TYPE), 7405d24bcf1STomer Tayar QED_MFW_GET_FIELD(mb_params.param, DRV_ID_MCP_HSI_VER), 7415d24bcf1STomer Tayar QED_MFW_GET_FIELD(mb_params.param, DRV_ID_PDA_COMP_VER)); 7425d24bcf1STomer Tayar 7435d24bcf1STomer Tayar if (p_in_params->hsi_ver != QED_LOAD_REQ_HSI_VER_1) { 7445d24bcf1STomer Tayar DP_VERBOSE(p_hwfn, QED_MSG_SP, 7455d24bcf1STomer 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", 7465d24bcf1STomer Tayar load_req.drv_ver_0, 7475d24bcf1STomer Tayar load_req.drv_ver_1, 7485d24bcf1STomer Tayar load_req.fw_ver, 7495d24bcf1STomer Tayar load_req.misc0, 7505d24bcf1STomer Tayar QED_MFW_GET_FIELD(load_req.misc0, LOAD_REQ_ROLE), 7515d24bcf1STomer Tayar QED_MFW_GET_FIELD(load_req.misc0, 7525d24bcf1STomer Tayar LOAD_REQ_LOCK_TO), 7535d24bcf1STomer Tayar QED_MFW_GET_FIELD(load_req.misc0, LOAD_REQ_FORCE), 7545d24bcf1STomer Tayar QED_MFW_GET_FIELD(load_req.misc0, LOAD_REQ_FLAGS0)); 7555d24bcf1STomer Tayar } 7565d24bcf1STomer Tayar 7575d24bcf1STomer Tayar rc = qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 7585d24bcf1STomer Tayar if (rc) { 7595d24bcf1STomer Tayar DP_NOTICE(p_hwfn, "Failed to send load request, rc = %d\n", rc); 7605d24bcf1STomer Tayar return rc; 7615d24bcf1STomer Tayar } 7625d24bcf1STomer Tayar 7635d24bcf1STomer Tayar DP_VERBOSE(p_hwfn, QED_MSG_SP, 7645d24bcf1STomer Tayar "Load Response: resp 0x%08x\n", mb_params.mcp_resp); 7655d24bcf1STomer Tayar p_out_params->load_code = mb_params.mcp_resp; 7665d24bcf1STomer Tayar 7675d24bcf1STomer Tayar if (p_in_params->hsi_ver != QED_LOAD_REQ_HSI_VER_1 && 7685d24bcf1STomer Tayar p_out_params->load_code != FW_MSG_CODE_DRV_LOAD_REFUSED_HSI_1) { 7695d24bcf1STomer Tayar DP_VERBOSE(p_hwfn, 7705d24bcf1STomer Tayar QED_MSG_SP, 7715d24bcf1STomer 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", 7725d24bcf1STomer Tayar load_rsp.drv_ver_0, 7735d24bcf1STomer Tayar load_rsp.drv_ver_1, 7745d24bcf1STomer Tayar load_rsp.fw_ver, 7755d24bcf1STomer Tayar load_rsp.misc0, 7765d24bcf1STomer Tayar QED_MFW_GET_FIELD(load_rsp.misc0, LOAD_RSP_ROLE), 7775d24bcf1STomer Tayar QED_MFW_GET_FIELD(load_rsp.misc0, LOAD_RSP_HSI), 7785d24bcf1STomer Tayar QED_MFW_GET_FIELD(load_rsp.misc0, LOAD_RSP_FLAGS0)); 7795d24bcf1STomer Tayar 7805d24bcf1STomer Tayar p_out_params->exist_drv_ver_0 = load_rsp.drv_ver_0; 7815d24bcf1STomer Tayar p_out_params->exist_drv_ver_1 = load_rsp.drv_ver_1; 7825d24bcf1STomer Tayar p_out_params->exist_fw_ver = load_rsp.fw_ver; 7835d24bcf1STomer Tayar p_out_params->exist_drv_role = 7845d24bcf1STomer Tayar QED_MFW_GET_FIELD(load_rsp.misc0, LOAD_RSP_ROLE); 7855d24bcf1STomer Tayar p_out_params->mfw_hsi_ver = 7865d24bcf1STomer Tayar QED_MFW_GET_FIELD(load_rsp.misc0, LOAD_RSP_HSI); 7875d24bcf1STomer Tayar p_out_params->drv_exists = 7885d24bcf1STomer Tayar QED_MFW_GET_FIELD(load_rsp.misc0, LOAD_RSP_FLAGS0) & 7895d24bcf1STomer Tayar LOAD_RSP_FLAGS0_DRV_EXISTS; 7905d24bcf1STomer Tayar } 7915d24bcf1STomer Tayar 7925d24bcf1STomer Tayar return 0; 7935d24bcf1STomer Tayar } 7945d24bcf1STomer Tayar 7955d24bcf1STomer Tayar static int eocre_get_mfw_drv_role(struct qed_hwfn *p_hwfn, 7965d24bcf1STomer Tayar enum qed_drv_role drv_role, 7975d24bcf1STomer Tayar u8 *p_mfw_drv_role) 7985d24bcf1STomer Tayar { 7995d24bcf1STomer Tayar switch (drv_role) { 8005d24bcf1STomer Tayar case QED_DRV_ROLE_OS: 8015d24bcf1STomer Tayar *p_mfw_drv_role = DRV_ROLE_OS; 8025d24bcf1STomer Tayar break; 8035d24bcf1STomer Tayar case QED_DRV_ROLE_KDUMP: 8045d24bcf1STomer Tayar *p_mfw_drv_role = DRV_ROLE_KDUMP; 8055d24bcf1STomer Tayar break; 8065d24bcf1STomer Tayar default: 8075d24bcf1STomer Tayar DP_ERR(p_hwfn, "Unexpected driver role %d\n", drv_role); 8085d24bcf1STomer Tayar return -EINVAL; 8095d24bcf1STomer Tayar } 8105d24bcf1STomer Tayar 8115d24bcf1STomer Tayar return 0; 8125d24bcf1STomer Tayar } 8135d24bcf1STomer Tayar 8145d24bcf1STomer Tayar enum qed_load_req_force { 8155d24bcf1STomer Tayar QED_LOAD_REQ_FORCE_NONE, 8165d24bcf1STomer Tayar QED_LOAD_REQ_FORCE_PF, 8175d24bcf1STomer Tayar QED_LOAD_REQ_FORCE_ALL, 8185d24bcf1STomer Tayar }; 8195d24bcf1STomer Tayar 8205d24bcf1STomer Tayar static void qed_get_mfw_force_cmd(struct qed_hwfn *p_hwfn, 8215d24bcf1STomer Tayar 8225d24bcf1STomer Tayar enum qed_load_req_force force_cmd, 8235d24bcf1STomer Tayar u8 *p_mfw_force_cmd) 8245d24bcf1STomer Tayar { 8255d24bcf1STomer Tayar switch (force_cmd) { 8265d24bcf1STomer Tayar case QED_LOAD_REQ_FORCE_NONE: 8275d24bcf1STomer Tayar *p_mfw_force_cmd = LOAD_REQ_FORCE_NONE; 8285d24bcf1STomer Tayar break; 8295d24bcf1STomer Tayar case QED_LOAD_REQ_FORCE_PF: 8305d24bcf1STomer Tayar *p_mfw_force_cmd = LOAD_REQ_FORCE_PF; 8315d24bcf1STomer Tayar break; 8325d24bcf1STomer Tayar case QED_LOAD_REQ_FORCE_ALL: 8335d24bcf1STomer Tayar *p_mfw_force_cmd = LOAD_REQ_FORCE_ALL; 8345d24bcf1STomer Tayar break; 8355d24bcf1STomer Tayar } 8365d24bcf1STomer Tayar } 8375d24bcf1STomer Tayar 8385d24bcf1STomer Tayar int qed_mcp_load_req(struct qed_hwfn *p_hwfn, 8395d24bcf1STomer Tayar struct qed_ptt *p_ptt, 8405d24bcf1STomer Tayar struct qed_load_req_params *p_params) 8415d24bcf1STomer Tayar { 8425d24bcf1STomer Tayar struct qed_load_req_out_params out_params; 8435d24bcf1STomer Tayar struct qed_load_req_in_params in_params; 8445d24bcf1STomer Tayar u8 mfw_drv_role, mfw_force_cmd; 8455d24bcf1STomer Tayar int rc; 8465d24bcf1STomer Tayar 8475d24bcf1STomer Tayar memset(&in_params, 0, sizeof(in_params)); 8485d24bcf1STomer Tayar in_params.hsi_ver = QED_LOAD_REQ_HSI_VER_DEFAULT; 8495d24bcf1STomer Tayar in_params.drv_ver_0 = QED_VERSION; 8505d24bcf1STomer Tayar in_params.drv_ver_1 = qed_get_config_bitmap(); 8515d24bcf1STomer Tayar in_params.fw_ver = STORM_FW_VERSION; 8525d24bcf1STomer Tayar rc = eocre_get_mfw_drv_role(p_hwfn, p_params->drv_role, &mfw_drv_role); 8535d24bcf1STomer Tayar if (rc) 8545d24bcf1STomer Tayar return rc; 8555d24bcf1STomer Tayar 8565d24bcf1STomer Tayar in_params.drv_role = mfw_drv_role; 8575d24bcf1STomer Tayar in_params.timeout_val = p_params->timeout_val; 8585d24bcf1STomer Tayar qed_get_mfw_force_cmd(p_hwfn, 8595d24bcf1STomer Tayar QED_LOAD_REQ_FORCE_NONE, &mfw_force_cmd); 8605d24bcf1STomer Tayar 8615d24bcf1STomer Tayar in_params.force_cmd = mfw_force_cmd; 8625d24bcf1STomer Tayar in_params.avoid_eng_reset = p_params->avoid_eng_reset; 8635d24bcf1STomer Tayar 8645d24bcf1STomer Tayar memset(&out_params, 0, sizeof(out_params)); 8655d24bcf1STomer Tayar rc = __qed_mcp_load_req(p_hwfn, p_ptt, &in_params, &out_params); 8665d24bcf1STomer Tayar if (rc) 8675d24bcf1STomer Tayar return rc; 8685d24bcf1STomer Tayar 8695d24bcf1STomer Tayar /* First handle cases where another load request should/might be sent: 8705d24bcf1STomer Tayar * - MFW expects the old interface [HSI version = 1] 8715d24bcf1STomer Tayar * - MFW responds that a force load request is required 872fe56b9e6SYuval Mintz */ 8735d24bcf1STomer Tayar if (out_params.load_code == FW_MSG_CODE_DRV_LOAD_REFUSED_HSI_1) { 8745d24bcf1STomer Tayar DP_INFO(p_hwfn, 8755d24bcf1STomer Tayar "MFW refused a load request due to HSI > 1. Resending with HSI = 1\n"); 8765d24bcf1STomer Tayar 8775d24bcf1STomer Tayar in_params.hsi_ver = QED_LOAD_REQ_HSI_VER_1; 8785d24bcf1STomer Tayar memset(&out_params, 0, sizeof(out_params)); 8795d24bcf1STomer Tayar rc = __qed_mcp_load_req(p_hwfn, p_ptt, &in_params, &out_params); 8805d24bcf1STomer Tayar if (rc) 8815d24bcf1STomer Tayar return rc; 8825d24bcf1STomer Tayar } else if (out_params.load_code == 8835d24bcf1STomer Tayar FW_MSG_CODE_DRV_LOAD_REFUSED_REQUIRES_FORCE) { 8845d24bcf1STomer Tayar if (qed_mcp_can_force_load(in_params.drv_role, 8855d24bcf1STomer Tayar out_params.exist_drv_role, 8865d24bcf1STomer Tayar p_params->override_force_load)) { 8875d24bcf1STomer Tayar DP_INFO(p_hwfn, 8885d24bcf1STomer 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", 8895d24bcf1STomer Tayar in_params.drv_role, in_params.fw_ver, 8905d24bcf1STomer Tayar in_params.drv_ver_0, in_params.drv_ver_1, 8915d24bcf1STomer Tayar out_params.exist_drv_role, 8925d24bcf1STomer Tayar out_params.exist_fw_ver, 8935d24bcf1STomer Tayar out_params.exist_drv_ver_0, 8945d24bcf1STomer Tayar out_params.exist_drv_ver_1); 8955d24bcf1STomer Tayar 8965d24bcf1STomer Tayar qed_get_mfw_force_cmd(p_hwfn, 8975d24bcf1STomer Tayar QED_LOAD_REQ_FORCE_ALL, 8985d24bcf1STomer Tayar &mfw_force_cmd); 8995d24bcf1STomer Tayar 9005d24bcf1STomer Tayar in_params.force_cmd = mfw_force_cmd; 9015d24bcf1STomer Tayar memset(&out_params, 0, sizeof(out_params)); 9025d24bcf1STomer Tayar rc = __qed_mcp_load_req(p_hwfn, p_ptt, &in_params, 9035d24bcf1STomer Tayar &out_params); 9045d24bcf1STomer Tayar if (rc) 9055d24bcf1STomer Tayar return rc; 9065d24bcf1STomer Tayar } else { 9075d24bcf1STomer Tayar DP_NOTICE(p_hwfn, 9085d24bcf1STomer 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", 9095d24bcf1STomer Tayar in_params.drv_role, in_params.fw_ver, 9105d24bcf1STomer Tayar in_params.drv_ver_0, in_params.drv_ver_1, 9115d24bcf1STomer Tayar out_params.exist_drv_role, 9125d24bcf1STomer Tayar out_params.exist_fw_ver, 9135d24bcf1STomer Tayar out_params.exist_drv_ver_0, 9145d24bcf1STomer Tayar out_params.exist_drv_ver_1); 9155d24bcf1STomer Tayar DP_NOTICE(p_hwfn, 9165d24bcf1STomer Tayar "Avoid sending a force load request to prevent disruption of active PFs\n"); 9175d24bcf1STomer Tayar 9185d24bcf1STomer Tayar qed_mcp_cancel_load_req(p_hwfn, p_ptt); 919fe56b9e6SYuval Mintz return -EBUSY; 920fe56b9e6SYuval Mintz } 9215d24bcf1STomer Tayar } 9225d24bcf1STomer Tayar 9235d24bcf1STomer Tayar /* Now handle the other types of responses. 9245d24bcf1STomer Tayar * The "REFUSED_HSI_1" and "REFUSED_REQUIRES_FORCE" responses are not 9255d24bcf1STomer Tayar * expected here after the additional revised load requests were sent. 9265d24bcf1STomer Tayar */ 9275d24bcf1STomer Tayar switch (out_params.load_code) { 9285d24bcf1STomer Tayar case FW_MSG_CODE_DRV_LOAD_ENGINE: 9295d24bcf1STomer Tayar case FW_MSG_CODE_DRV_LOAD_PORT: 9305d24bcf1STomer Tayar case FW_MSG_CODE_DRV_LOAD_FUNCTION: 9315d24bcf1STomer Tayar if (out_params.mfw_hsi_ver != QED_LOAD_REQ_HSI_VER_1 && 9325d24bcf1STomer Tayar out_params.drv_exists) { 9335d24bcf1STomer Tayar /* The role and fw/driver version match, but the PF is 9345d24bcf1STomer Tayar * already loaded and has not been unloaded gracefully. 9355d24bcf1STomer Tayar */ 9365d24bcf1STomer Tayar DP_NOTICE(p_hwfn, 9375d24bcf1STomer Tayar "PF is already loaded\n"); 9385d24bcf1STomer Tayar return -EINVAL; 9395d24bcf1STomer Tayar } 9405d24bcf1STomer Tayar break; 9415d24bcf1STomer Tayar default: 9425d24bcf1STomer Tayar DP_NOTICE(p_hwfn, 9435d24bcf1STomer Tayar "Unexpected refusal to load request [resp 0x%08x]. Aborting.\n", 9445d24bcf1STomer Tayar out_params.load_code); 9455d24bcf1STomer Tayar return -EBUSY; 9465d24bcf1STomer Tayar } 9475d24bcf1STomer Tayar 9485d24bcf1STomer Tayar p_params->load_code = out_params.load_code; 949fe56b9e6SYuval Mintz 950fe56b9e6SYuval Mintz return 0; 951fe56b9e6SYuval Mintz } 952fe56b9e6SYuval Mintz 9531226337aSTomer Tayar int qed_mcp_unload_req(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 9541226337aSTomer Tayar { 9551226337aSTomer Tayar u32 wol_param, mcp_resp, mcp_param; 9561226337aSTomer Tayar 9571226337aSTomer Tayar switch (p_hwfn->cdev->wol_config) { 9581226337aSTomer Tayar case QED_OV_WOL_DISABLED: 9591226337aSTomer Tayar wol_param = DRV_MB_PARAM_UNLOAD_WOL_DISABLED; 9601226337aSTomer Tayar break; 9611226337aSTomer Tayar case QED_OV_WOL_ENABLED: 9621226337aSTomer Tayar wol_param = DRV_MB_PARAM_UNLOAD_WOL_ENABLED; 9631226337aSTomer Tayar break; 9641226337aSTomer Tayar default: 9651226337aSTomer Tayar DP_NOTICE(p_hwfn, 9661226337aSTomer Tayar "Unknown WoL configuration %02x\n", 9671226337aSTomer Tayar p_hwfn->cdev->wol_config); 9681226337aSTomer Tayar /* Fallthrough */ 9691226337aSTomer Tayar case QED_OV_WOL_DEFAULT: 9701226337aSTomer Tayar wol_param = DRV_MB_PARAM_UNLOAD_WOL_MCP; 9711226337aSTomer Tayar } 9721226337aSTomer Tayar 9731226337aSTomer Tayar return qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_UNLOAD_REQ, wol_param, 9741226337aSTomer Tayar &mcp_resp, &mcp_param); 9751226337aSTomer Tayar } 9761226337aSTomer Tayar 9771226337aSTomer Tayar int qed_mcp_unload_done(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 9781226337aSTomer Tayar { 9791226337aSTomer Tayar struct qed_mcp_mb_params mb_params; 9801226337aSTomer Tayar struct mcp_mac wol_mac; 9811226337aSTomer Tayar 9821226337aSTomer Tayar memset(&mb_params, 0, sizeof(mb_params)); 9831226337aSTomer Tayar mb_params.cmd = DRV_MSG_CODE_UNLOAD_DONE; 9841226337aSTomer Tayar 9851226337aSTomer Tayar /* Set the primary MAC if WoL is enabled */ 9861226337aSTomer Tayar if (p_hwfn->cdev->wol_config == QED_OV_WOL_ENABLED) { 9871226337aSTomer Tayar u8 *p_mac = p_hwfn->cdev->wol_mac; 9881226337aSTomer Tayar 9891226337aSTomer Tayar memset(&wol_mac, 0, sizeof(wol_mac)); 9901226337aSTomer Tayar wol_mac.mac_upper = p_mac[0] << 8 | p_mac[1]; 9911226337aSTomer Tayar wol_mac.mac_lower = p_mac[2] << 24 | p_mac[3] << 16 | 9921226337aSTomer Tayar p_mac[4] << 8 | p_mac[5]; 9931226337aSTomer Tayar 9941226337aSTomer Tayar DP_VERBOSE(p_hwfn, 9951226337aSTomer Tayar (QED_MSG_SP | NETIF_MSG_IFDOWN), 9961226337aSTomer Tayar "Setting WoL MAC: %pM --> [%08x,%08x]\n", 9971226337aSTomer Tayar p_mac, wol_mac.mac_upper, wol_mac.mac_lower); 9981226337aSTomer Tayar 9991226337aSTomer Tayar mb_params.p_data_src = &wol_mac; 10001226337aSTomer Tayar mb_params.data_src_size = sizeof(wol_mac); 10011226337aSTomer Tayar } 10021226337aSTomer Tayar 10031226337aSTomer Tayar return qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 10041226337aSTomer Tayar } 10051226337aSTomer Tayar 10060b55e27dSYuval Mintz static void qed_mcp_handle_vf_flr(struct qed_hwfn *p_hwfn, 10070b55e27dSYuval Mintz struct qed_ptt *p_ptt) 10080b55e27dSYuval Mintz { 10090b55e27dSYuval Mintz u32 addr = SECTION_OFFSIZE_ADDR(p_hwfn->mcp_info->public_base, 10100b55e27dSYuval Mintz PUBLIC_PATH); 10110b55e27dSYuval Mintz u32 mfw_path_offsize = qed_rd(p_hwfn, p_ptt, addr); 10120b55e27dSYuval Mintz u32 path_addr = SECTION_ADDR(mfw_path_offsize, 10130b55e27dSYuval Mintz QED_PATH_ID(p_hwfn)); 10140b55e27dSYuval Mintz u32 disabled_vfs[VF_MAX_STATIC / 32]; 10150b55e27dSYuval Mintz int i; 10160b55e27dSYuval Mintz 10170b55e27dSYuval Mintz DP_VERBOSE(p_hwfn, 10180b55e27dSYuval Mintz QED_MSG_SP, 10190b55e27dSYuval Mintz "Reading Disabled VF information from [offset %08x], path_addr %08x\n", 10200b55e27dSYuval Mintz mfw_path_offsize, path_addr); 10210b55e27dSYuval Mintz 10220b55e27dSYuval Mintz for (i = 0; i < (VF_MAX_STATIC / 32); i++) { 10230b55e27dSYuval Mintz disabled_vfs[i] = qed_rd(p_hwfn, p_ptt, 10240b55e27dSYuval Mintz path_addr + 10250b55e27dSYuval Mintz offsetof(struct public_path, 10260b55e27dSYuval Mintz mcp_vf_disabled) + 10270b55e27dSYuval Mintz sizeof(u32) * i); 10280b55e27dSYuval Mintz DP_VERBOSE(p_hwfn, (QED_MSG_SP | QED_MSG_IOV), 10290b55e27dSYuval Mintz "FLR-ed VFs [%08x,...,%08x] - %08x\n", 10300b55e27dSYuval Mintz i * 32, (i + 1) * 32 - 1, disabled_vfs[i]); 10310b55e27dSYuval Mintz } 10320b55e27dSYuval Mintz 10330b55e27dSYuval Mintz if (qed_iov_mark_vf_flr(p_hwfn, disabled_vfs)) 10340b55e27dSYuval Mintz qed_schedule_iov(p_hwfn, QED_IOV_WQ_FLR_FLAG); 10350b55e27dSYuval Mintz } 10360b55e27dSYuval Mintz 10370b55e27dSYuval Mintz int qed_mcp_ack_vf_flr(struct qed_hwfn *p_hwfn, 10380b55e27dSYuval Mintz struct qed_ptt *p_ptt, u32 *vfs_to_ack) 10390b55e27dSYuval Mintz { 10400b55e27dSYuval Mintz u32 addr = SECTION_OFFSIZE_ADDR(p_hwfn->mcp_info->public_base, 10410b55e27dSYuval Mintz PUBLIC_FUNC); 10420b55e27dSYuval Mintz u32 mfw_func_offsize = qed_rd(p_hwfn, p_ptt, addr); 10430b55e27dSYuval Mintz u32 func_addr = SECTION_ADDR(mfw_func_offsize, 10440b55e27dSYuval Mintz MCP_PF_ID(p_hwfn)); 10450b55e27dSYuval Mintz struct qed_mcp_mb_params mb_params; 10460b55e27dSYuval Mintz int rc; 10470b55e27dSYuval Mintz int i; 10480b55e27dSYuval Mintz 10490b55e27dSYuval Mintz for (i = 0; i < (VF_MAX_STATIC / 32); i++) 10500b55e27dSYuval Mintz DP_VERBOSE(p_hwfn, (QED_MSG_SP | QED_MSG_IOV), 10510b55e27dSYuval Mintz "Acking VFs [%08x,...,%08x] - %08x\n", 10520b55e27dSYuval Mintz i * 32, (i + 1) * 32 - 1, vfs_to_ack[i]); 10530b55e27dSYuval Mintz 10540b55e27dSYuval Mintz memset(&mb_params, 0, sizeof(mb_params)); 10550b55e27dSYuval Mintz mb_params.cmd = DRV_MSG_CODE_VF_DISABLED_DONE; 10562f67af8cSTomer Tayar mb_params.p_data_src = vfs_to_ack; 10572f67af8cSTomer Tayar mb_params.data_src_size = VF_MAX_STATIC / 8; 10580b55e27dSYuval Mintz rc = qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 10590b55e27dSYuval Mintz if (rc) { 10600b55e27dSYuval Mintz DP_NOTICE(p_hwfn, "Failed to pass ACK for VF flr to MFW\n"); 10610b55e27dSYuval Mintz return -EBUSY; 10620b55e27dSYuval Mintz } 10630b55e27dSYuval Mintz 10640b55e27dSYuval Mintz /* Clear the ACK bits */ 10650b55e27dSYuval Mintz for (i = 0; i < (VF_MAX_STATIC / 32); i++) 10660b55e27dSYuval Mintz qed_wr(p_hwfn, p_ptt, 10670b55e27dSYuval Mintz func_addr + 10680b55e27dSYuval Mintz offsetof(struct public_func, drv_ack_vf_disabled) + 10690b55e27dSYuval Mintz i * sizeof(u32), 0); 10700b55e27dSYuval Mintz 10710b55e27dSYuval Mintz return rc; 10720b55e27dSYuval Mintz } 10730b55e27dSYuval Mintz 1074334c03b5SZvi Nachmani static void qed_mcp_handle_transceiver_change(struct qed_hwfn *p_hwfn, 1075334c03b5SZvi Nachmani struct qed_ptt *p_ptt) 1076334c03b5SZvi Nachmani { 1077334c03b5SZvi Nachmani u32 transceiver_state; 1078334c03b5SZvi Nachmani 1079334c03b5SZvi Nachmani transceiver_state = qed_rd(p_hwfn, p_ptt, 1080334c03b5SZvi Nachmani p_hwfn->mcp_info->port_addr + 1081334c03b5SZvi Nachmani offsetof(struct public_port, 1082334c03b5SZvi Nachmani transceiver_data)); 1083334c03b5SZvi Nachmani 1084334c03b5SZvi Nachmani DP_VERBOSE(p_hwfn, 1085334c03b5SZvi Nachmani (NETIF_MSG_HW | QED_MSG_SP), 1086334c03b5SZvi Nachmani "Received transceiver state update [0x%08x] from mfw [Addr 0x%x]\n", 1087334c03b5SZvi Nachmani transceiver_state, 1088334c03b5SZvi Nachmani (u32)(p_hwfn->mcp_info->port_addr + 10891a635e48SYuval Mintz offsetof(struct public_port, transceiver_data))); 1090334c03b5SZvi Nachmani 1091334c03b5SZvi Nachmani transceiver_state = GET_FIELD(transceiver_state, 1092351a4dedSYuval Mintz ETH_TRANSCEIVER_STATE); 1093334c03b5SZvi Nachmani 1094351a4dedSYuval Mintz if (transceiver_state == ETH_TRANSCEIVER_STATE_PRESENT) 1095334c03b5SZvi Nachmani DP_NOTICE(p_hwfn, "Transceiver is present.\n"); 1096334c03b5SZvi Nachmani else 1097334c03b5SZvi Nachmani DP_NOTICE(p_hwfn, "Transceiver is unplugged.\n"); 1098334c03b5SZvi Nachmani } 1099334c03b5SZvi Nachmani 1100cc875c2eSYuval Mintz static void qed_mcp_handle_link_change(struct qed_hwfn *p_hwfn, 11011a635e48SYuval Mintz struct qed_ptt *p_ptt, bool b_reset) 1102cc875c2eSYuval Mintz { 1103cc875c2eSYuval Mintz struct qed_mcp_link_state *p_link; 1104a64b02d5SManish Chopra u8 max_bw, min_bw; 1105cc875c2eSYuval Mintz u32 status = 0; 1106cc875c2eSYuval Mintz 110765ed2ffdSMintz, Yuval /* Prevent SW/attentions from doing this at the same time */ 110865ed2ffdSMintz, Yuval spin_lock_bh(&p_hwfn->mcp_info->link_lock); 110965ed2ffdSMintz, Yuval 1110cc875c2eSYuval Mintz p_link = &p_hwfn->mcp_info->link_output; 1111cc875c2eSYuval Mintz memset(p_link, 0, sizeof(*p_link)); 1112cc875c2eSYuval Mintz if (!b_reset) { 1113cc875c2eSYuval Mintz status = qed_rd(p_hwfn, p_ptt, 1114cc875c2eSYuval Mintz p_hwfn->mcp_info->port_addr + 1115cc875c2eSYuval Mintz offsetof(struct public_port, link_status)); 1116cc875c2eSYuval Mintz DP_VERBOSE(p_hwfn, (NETIF_MSG_LINK | QED_MSG_SP), 1117cc875c2eSYuval Mintz "Received link update [0x%08x] from mfw [Addr 0x%x]\n", 1118cc875c2eSYuval Mintz status, 1119cc875c2eSYuval Mintz (u32)(p_hwfn->mcp_info->port_addr + 11201a635e48SYuval Mintz offsetof(struct public_port, link_status))); 1121cc875c2eSYuval Mintz } else { 1122cc875c2eSYuval Mintz DP_VERBOSE(p_hwfn, NETIF_MSG_LINK, 1123cc875c2eSYuval Mintz "Resetting link indications\n"); 112465ed2ffdSMintz, Yuval goto out; 1125cc875c2eSYuval Mintz } 1126cc875c2eSYuval Mintz 1127fc916ff2SSudarsana Reddy Kalluru if (p_hwfn->b_drv_link_init) 1128cc875c2eSYuval Mintz p_link->link_up = !!(status & LINK_STATUS_LINK_UP); 1129fc916ff2SSudarsana Reddy Kalluru else 1130fc916ff2SSudarsana Reddy Kalluru p_link->link_up = false; 1131cc875c2eSYuval Mintz 1132cc875c2eSYuval Mintz p_link->full_duplex = true; 1133cc875c2eSYuval Mintz switch ((status & LINK_STATUS_SPEED_AND_DUPLEX_MASK)) { 1134cc875c2eSYuval Mintz case LINK_STATUS_SPEED_AND_DUPLEX_100G: 1135cc875c2eSYuval Mintz p_link->speed = 100000; 1136cc875c2eSYuval Mintz break; 1137cc875c2eSYuval Mintz case LINK_STATUS_SPEED_AND_DUPLEX_50G: 1138cc875c2eSYuval Mintz p_link->speed = 50000; 1139cc875c2eSYuval Mintz break; 1140cc875c2eSYuval Mintz case LINK_STATUS_SPEED_AND_DUPLEX_40G: 1141cc875c2eSYuval Mintz p_link->speed = 40000; 1142cc875c2eSYuval Mintz break; 1143cc875c2eSYuval Mintz case LINK_STATUS_SPEED_AND_DUPLEX_25G: 1144cc875c2eSYuval Mintz p_link->speed = 25000; 1145cc875c2eSYuval Mintz break; 1146cc875c2eSYuval Mintz case LINK_STATUS_SPEED_AND_DUPLEX_20G: 1147cc875c2eSYuval Mintz p_link->speed = 20000; 1148cc875c2eSYuval Mintz break; 1149cc875c2eSYuval Mintz case LINK_STATUS_SPEED_AND_DUPLEX_10G: 1150cc875c2eSYuval Mintz p_link->speed = 10000; 1151cc875c2eSYuval Mintz break; 1152cc875c2eSYuval Mintz case LINK_STATUS_SPEED_AND_DUPLEX_1000THD: 1153cc875c2eSYuval Mintz p_link->full_duplex = false; 1154cc875c2eSYuval Mintz /* Fall-through */ 1155cc875c2eSYuval Mintz case LINK_STATUS_SPEED_AND_DUPLEX_1000TFD: 1156cc875c2eSYuval Mintz p_link->speed = 1000; 1157cc875c2eSYuval Mintz break; 1158cc875c2eSYuval Mintz default: 1159cc875c2eSYuval Mintz p_link->speed = 0; 1160cc875c2eSYuval Mintz } 1161cc875c2eSYuval Mintz 11624b01e519SManish Chopra if (p_link->link_up && p_link->speed) 11634b01e519SManish Chopra p_link->line_speed = p_link->speed; 11644b01e519SManish Chopra else 11654b01e519SManish Chopra p_link->line_speed = 0; 11664b01e519SManish Chopra 11674b01e519SManish Chopra max_bw = p_hwfn->mcp_info->func_info.bandwidth_max; 1168a64b02d5SManish Chopra min_bw = p_hwfn->mcp_info->func_info.bandwidth_min; 11694b01e519SManish Chopra 1170a64b02d5SManish Chopra /* Max bandwidth configuration */ 11714b01e519SManish Chopra __qed_configure_pf_max_bandwidth(p_hwfn, p_ptt, p_link, max_bw); 1172cc875c2eSYuval Mintz 1173a64b02d5SManish Chopra /* Min bandwidth configuration */ 1174a64b02d5SManish Chopra __qed_configure_pf_min_bandwidth(p_hwfn, p_ptt, p_link, min_bw); 11756f437d43SMintz, Yuval qed_configure_vp_wfq_on_link_change(p_hwfn->cdev, p_ptt, 11766f437d43SMintz, Yuval p_link->min_pf_rate); 1177a64b02d5SManish Chopra 1178cc875c2eSYuval Mintz p_link->an = !!(status & LINK_STATUS_AUTO_NEGOTIATE_ENABLED); 1179cc875c2eSYuval Mintz p_link->an_complete = !!(status & 1180cc875c2eSYuval Mintz LINK_STATUS_AUTO_NEGOTIATE_COMPLETE); 1181cc875c2eSYuval Mintz p_link->parallel_detection = !!(status & 1182cc875c2eSYuval Mintz LINK_STATUS_PARALLEL_DETECTION_USED); 1183cc875c2eSYuval Mintz p_link->pfc_enabled = !!(status & LINK_STATUS_PFC_ENABLED); 1184cc875c2eSYuval Mintz 1185cc875c2eSYuval Mintz p_link->partner_adv_speed |= 1186cc875c2eSYuval Mintz (status & LINK_STATUS_LINK_PARTNER_1000TFD_CAPABLE) ? 1187cc875c2eSYuval Mintz QED_LINK_PARTNER_SPEED_1G_FD : 0; 1188cc875c2eSYuval Mintz p_link->partner_adv_speed |= 1189cc875c2eSYuval Mintz (status & LINK_STATUS_LINK_PARTNER_1000THD_CAPABLE) ? 1190cc875c2eSYuval Mintz QED_LINK_PARTNER_SPEED_1G_HD : 0; 1191cc875c2eSYuval Mintz p_link->partner_adv_speed |= 1192cc875c2eSYuval Mintz (status & LINK_STATUS_LINK_PARTNER_10G_CAPABLE) ? 1193cc875c2eSYuval Mintz QED_LINK_PARTNER_SPEED_10G : 0; 1194cc875c2eSYuval Mintz p_link->partner_adv_speed |= 1195cc875c2eSYuval Mintz (status & LINK_STATUS_LINK_PARTNER_20G_CAPABLE) ? 1196cc875c2eSYuval Mintz QED_LINK_PARTNER_SPEED_20G : 0; 1197cc875c2eSYuval Mintz p_link->partner_adv_speed |= 1198054c67d1SSudarsana Reddy Kalluru (status & LINK_STATUS_LINK_PARTNER_25G_CAPABLE) ? 1199054c67d1SSudarsana Reddy Kalluru QED_LINK_PARTNER_SPEED_25G : 0; 1200054c67d1SSudarsana Reddy Kalluru p_link->partner_adv_speed |= 1201cc875c2eSYuval Mintz (status & LINK_STATUS_LINK_PARTNER_40G_CAPABLE) ? 1202cc875c2eSYuval Mintz QED_LINK_PARTNER_SPEED_40G : 0; 1203cc875c2eSYuval Mintz p_link->partner_adv_speed |= 1204cc875c2eSYuval Mintz (status & LINK_STATUS_LINK_PARTNER_50G_CAPABLE) ? 1205cc875c2eSYuval Mintz QED_LINK_PARTNER_SPEED_50G : 0; 1206cc875c2eSYuval Mintz p_link->partner_adv_speed |= 1207cc875c2eSYuval Mintz (status & LINK_STATUS_LINK_PARTNER_100G_CAPABLE) ? 1208cc875c2eSYuval Mintz QED_LINK_PARTNER_SPEED_100G : 0; 1209cc875c2eSYuval Mintz 1210cc875c2eSYuval Mintz p_link->partner_tx_flow_ctrl_en = 1211cc875c2eSYuval Mintz !!(status & LINK_STATUS_TX_FLOW_CONTROL_ENABLED); 1212cc875c2eSYuval Mintz p_link->partner_rx_flow_ctrl_en = 1213cc875c2eSYuval Mintz !!(status & LINK_STATUS_RX_FLOW_CONTROL_ENABLED); 1214cc875c2eSYuval Mintz 1215cc875c2eSYuval Mintz switch (status & LINK_STATUS_LINK_PARTNER_FLOW_CONTROL_MASK) { 1216cc875c2eSYuval Mintz case LINK_STATUS_LINK_PARTNER_SYMMETRIC_PAUSE: 1217cc875c2eSYuval Mintz p_link->partner_adv_pause = QED_LINK_PARTNER_SYMMETRIC_PAUSE; 1218cc875c2eSYuval Mintz break; 1219cc875c2eSYuval Mintz case LINK_STATUS_LINK_PARTNER_ASYMMETRIC_PAUSE: 1220cc875c2eSYuval Mintz p_link->partner_adv_pause = QED_LINK_PARTNER_ASYMMETRIC_PAUSE; 1221cc875c2eSYuval Mintz break; 1222cc875c2eSYuval Mintz case LINK_STATUS_LINK_PARTNER_BOTH_PAUSE: 1223cc875c2eSYuval Mintz p_link->partner_adv_pause = QED_LINK_PARTNER_BOTH_PAUSE; 1224cc875c2eSYuval Mintz break; 1225cc875c2eSYuval Mintz default: 1226cc875c2eSYuval Mintz p_link->partner_adv_pause = 0; 1227cc875c2eSYuval Mintz } 1228cc875c2eSYuval Mintz 1229cc875c2eSYuval Mintz p_link->sfp_tx_fault = !!(status & LINK_STATUS_SFP_TX_FAULT); 1230cc875c2eSYuval Mintz 1231cc875c2eSYuval Mintz qed_link_update(p_hwfn); 123265ed2ffdSMintz, Yuval out: 123365ed2ffdSMintz, Yuval spin_unlock_bh(&p_hwfn->mcp_info->link_lock); 1234cc875c2eSYuval Mintz } 1235cc875c2eSYuval Mintz 1236351a4dedSYuval Mintz int qed_mcp_set_link(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, bool b_up) 1237cc875c2eSYuval Mintz { 1238cc875c2eSYuval Mintz struct qed_mcp_link_params *params = &p_hwfn->mcp_info->link_input; 12395529bad9STomer Tayar struct qed_mcp_mb_params mb_params; 12402f67af8cSTomer Tayar struct eth_phy_cfg phy_cfg; 1241cc875c2eSYuval Mintz int rc = 0; 12425529bad9STomer Tayar u32 cmd; 1243cc875c2eSYuval Mintz 1244cc875c2eSYuval Mintz /* Set the shmem configuration according to params */ 12452f67af8cSTomer Tayar memset(&phy_cfg, 0, sizeof(phy_cfg)); 1246cc875c2eSYuval Mintz cmd = b_up ? DRV_MSG_CODE_INIT_PHY : DRV_MSG_CODE_LINK_RESET; 1247cc875c2eSYuval Mintz if (!params->speed.autoneg) 12482f67af8cSTomer Tayar phy_cfg.speed = params->speed.forced_speed; 12492f67af8cSTomer Tayar phy_cfg.pause |= (params->pause.autoneg) ? ETH_PAUSE_AUTONEG : 0; 12502f67af8cSTomer Tayar phy_cfg.pause |= (params->pause.forced_rx) ? ETH_PAUSE_RX : 0; 12512f67af8cSTomer Tayar phy_cfg.pause |= (params->pause.forced_tx) ? ETH_PAUSE_TX : 0; 12522f67af8cSTomer Tayar phy_cfg.adv_speed = params->speed.advertised_speeds; 12532f67af8cSTomer Tayar phy_cfg.loopback_mode = params->loopback_mode; 1254cc875c2eSYuval Mintz 1255fc916ff2SSudarsana Reddy Kalluru p_hwfn->b_drv_link_init = b_up; 1256fc916ff2SSudarsana Reddy Kalluru 1257cc875c2eSYuval Mintz if (b_up) { 1258cc875c2eSYuval Mintz DP_VERBOSE(p_hwfn, NETIF_MSG_LINK, 1259cc875c2eSYuval Mintz "Configuring Link: Speed 0x%08x, Pause 0x%08x, adv_speed 0x%08x, loopback 0x%08x, features 0x%08x\n", 12602f67af8cSTomer Tayar phy_cfg.speed, 12612f67af8cSTomer Tayar phy_cfg.pause, 12622f67af8cSTomer Tayar phy_cfg.adv_speed, 12632f67af8cSTomer Tayar phy_cfg.loopback_mode, 12642f67af8cSTomer Tayar phy_cfg.feature_config_flags); 1265cc875c2eSYuval Mintz } else { 1266cc875c2eSYuval Mintz DP_VERBOSE(p_hwfn, NETIF_MSG_LINK, 1267cc875c2eSYuval Mintz "Resetting link\n"); 1268cc875c2eSYuval Mintz } 1269cc875c2eSYuval Mintz 12705529bad9STomer Tayar memset(&mb_params, 0, sizeof(mb_params)); 12715529bad9STomer Tayar mb_params.cmd = cmd; 12722f67af8cSTomer Tayar mb_params.p_data_src = &phy_cfg; 12732f67af8cSTomer Tayar mb_params.data_src_size = sizeof(phy_cfg); 12745529bad9STomer Tayar rc = qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 1275cc875c2eSYuval Mintz 1276cc875c2eSYuval Mintz /* if mcp fails to respond we must abort */ 1277cc875c2eSYuval Mintz if (rc) { 1278cc875c2eSYuval Mintz DP_ERR(p_hwfn, "MCP response failure, aborting\n"); 1279cc875c2eSYuval Mintz return rc; 1280cc875c2eSYuval Mintz } 1281cc875c2eSYuval Mintz 128265ed2ffdSMintz, Yuval /* Mimic link-change attention, done for several reasons: 128365ed2ffdSMintz, Yuval * - On reset, there's no guarantee MFW would trigger 128465ed2ffdSMintz, Yuval * an attention. 128565ed2ffdSMintz, Yuval * - On initialization, older MFWs might not indicate link change 128665ed2ffdSMintz, Yuval * during LFA, so we'll never get an UP indication. 128765ed2ffdSMintz, Yuval */ 128865ed2ffdSMintz, Yuval qed_mcp_handle_link_change(p_hwfn, p_ptt, !b_up); 1289cc875c2eSYuval Mintz 1290cc875c2eSYuval Mintz return 0; 1291cc875c2eSYuval Mintz } 1292cc875c2eSYuval Mintz 12936c754246SSudarsana Reddy Kalluru static void qed_mcp_send_protocol_stats(struct qed_hwfn *p_hwfn, 12946c754246SSudarsana Reddy Kalluru struct qed_ptt *p_ptt, 12956c754246SSudarsana Reddy Kalluru enum MFW_DRV_MSG_TYPE type) 12966c754246SSudarsana Reddy Kalluru { 12976c754246SSudarsana Reddy Kalluru enum qed_mcp_protocol_type stats_type; 12986c754246SSudarsana Reddy Kalluru union qed_mcp_protocol_stats stats; 12996c754246SSudarsana Reddy Kalluru struct qed_mcp_mb_params mb_params; 13006c754246SSudarsana Reddy Kalluru u32 hsi_param; 13016c754246SSudarsana Reddy Kalluru 13026c754246SSudarsana Reddy Kalluru switch (type) { 13036c754246SSudarsana Reddy Kalluru case MFW_DRV_MSG_GET_LAN_STATS: 13046c754246SSudarsana Reddy Kalluru stats_type = QED_MCP_LAN_STATS; 13056c754246SSudarsana Reddy Kalluru hsi_param = DRV_MSG_CODE_STATS_TYPE_LAN; 13066c754246SSudarsana Reddy Kalluru break; 13076c754246SSudarsana Reddy Kalluru case MFW_DRV_MSG_GET_FCOE_STATS: 13086c754246SSudarsana Reddy Kalluru stats_type = QED_MCP_FCOE_STATS; 13096c754246SSudarsana Reddy Kalluru hsi_param = DRV_MSG_CODE_STATS_TYPE_FCOE; 13106c754246SSudarsana Reddy Kalluru break; 13116c754246SSudarsana Reddy Kalluru case MFW_DRV_MSG_GET_ISCSI_STATS: 13126c754246SSudarsana Reddy Kalluru stats_type = QED_MCP_ISCSI_STATS; 13136c754246SSudarsana Reddy Kalluru hsi_param = DRV_MSG_CODE_STATS_TYPE_ISCSI; 13146c754246SSudarsana Reddy Kalluru break; 13156c754246SSudarsana Reddy Kalluru case MFW_DRV_MSG_GET_RDMA_STATS: 13166c754246SSudarsana Reddy Kalluru stats_type = QED_MCP_RDMA_STATS; 13176c754246SSudarsana Reddy Kalluru hsi_param = DRV_MSG_CODE_STATS_TYPE_RDMA; 13186c754246SSudarsana Reddy Kalluru break; 13196c754246SSudarsana Reddy Kalluru default: 13206c754246SSudarsana Reddy Kalluru DP_NOTICE(p_hwfn, "Invalid protocol type %d\n", type); 13216c754246SSudarsana Reddy Kalluru return; 13226c754246SSudarsana Reddy Kalluru } 13236c754246SSudarsana Reddy Kalluru 13246c754246SSudarsana Reddy Kalluru qed_get_protocol_stats(p_hwfn->cdev, stats_type, &stats); 13256c754246SSudarsana Reddy Kalluru 13266c754246SSudarsana Reddy Kalluru memset(&mb_params, 0, sizeof(mb_params)); 13276c754246SSudarsana Reddy Kalluru mb_params.cmd = DRV_MSG_CODE_GET_STATS; 13286c754246SSudarsana Reddy Kalluru mb_params.param = hsi_param; 13292f67af8cSTomer Tayar mb_params.p_data_src = &stats; 13302f67af8cSTomer Tayar mb_params.data_src_size = sizeof(stats); 13316c754246SSudarsana Reddy Kalluru qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 13326c754246SSudarsana Reddy Kalluru } 13336c754246SSudarsana Reddy Kalluru 13344b01e519SManish Chopra static void qed_read_pf_bandwidth(struct qed_hwfn *p_hwfn, 13354b01e519SManish Chopra struct public_func *p_shmem_info) 13364b01e519SManish Chopra { 13374b01e519SManish Chopra struct qed_mcp_function_info *p_info; 13384b01e519SManish Chopra 13394b01e519SManish Chopra p_info = &p_hwfn->mcp_info->func_info; 13404b01e519SManish Chopra 13414b01e519SManish Chopra p_info->bandwidth_min = (p_shmem_info->config & 13424b01e519SManish Chopra FUNC_MF_CFG_MIN_BW_MASK) >> 13434b01e519SManish Chopra FUNC_MF_CFG_MIN_BW_SHIFT; 13444b01e519SManish Chopra if (p_info->bandwidth_min < 1 || p_info->bandwidth_min > 100) { 13454b01e519SManish Chopra DP_INFO(p_hwfn, 13464b01e519SManish Chopra "bandwidth minimum out of bounds [%02x]. Set to 1\n", 13474b01e519SManish Chopra p_info->bandwidth_min); 13484b01e519SManish Chopra p_info->bandwidth_min = 1; 13494b01e519SManish Chopra } 13504b01e519SManish Chopra 13514b01e519SManish Chopra p_info->bandwidth_max = (p_shmem_info->config & 13524b01e519SManish Chopra FUNC_MF_CFG_MAX_BW_MASK) >> 13534b01e519SManish Chopra FUNC_MF_CFG_MAX_BW_SHIFT; 13544b01e519SManish Chopra if (p_info->bandwidth_max < 1 || p_info->bandwidth_max > 100) { 13554b01e519SManish Chopra DP_INFO(p_hwfn, 13564b01e519SManish Chopra "bandwidth maximum out of bounds [%02x]. Set to 100\n", 13574b01e519SManish Chopra p_info->bandwidth_max); 13584b01e519SManish Chopra p_info->bandwidth_max = 100; 13594b01e519SManish Chopra } 13604b01e519SManish Chopra } 13614b01e519SManish Chopra 13624b01e519SManish Chopra static u32 qed_mcp_get_shmem_func(struct qed_hwfn *p_hwfn, 13634b01e519SManish Chopra struct qed_ptt *p_ptt, 13641a635e48SYuval Mintz struct public_func *p_data, int pfid) 13654b01e519SManish Chopra { 13664b01e519SManish Chopra u32 addr = SECTION_OFFSIZE_ADDR(p_hwfn->mcp_info->public_base, 13674b01e519SManish Chopra PUBLIC_FUNC); 13684b01e519SManish Chopra u32 mfw_path_offsize = qed_rd(p_hwfn, p_ptt, addr); 13694b01e519SManish Chopra u32 func_addr = SECTION_ADDR(mfw_path_offsize, pfid); 13704b01e519SManish Chopra u32 i, size; 13714b01e519SManish Chopra 13724b01e519SManish Chopra memset(p_data, 0, sizeof(*p_data)); 13734b01e519SManish Chopra 13741a635e48SYuval Mintz size = min_t(u32, sizeof(*p_data), QED_SECTION_SIZE(mfw_path_offsize)); 13754b01e519SManish Chopra for (i = 0; i < size / sizeof(u32); i++) 13764b01e519SManish Chopra ((u32 *)p_data)[i] = qed_rd(p_hwfn, p_ptt, 13774b01e519SManish Chopra func_addr + (i << 2)); 13784b01e519SManish Chopra return size; 13794b01e519SManish Chopra } 13804b01e519SManish Chopra 13811a635e48SYuval Mintz static void qed_mcp_update_bw(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 13824b01e519SManish Chopra { 13834b01e519SManish Chopra struct qed_mcp_function_info *p_info; 13844b01e519SManish Chopra struct public_func shmem_info; 13854b01e519SManish Chopra u32 resp = 0, param = 0; 13864b01e519SManish Chopra 13871a635e48SYuval Mintz qed_mcp_get_shmem_func(p_hwfn, p_ptt, &shmem_info, MCP_PF_ID(p_hwfn)); 13884b01e519SManish Chopra 13894b01e519SManish Chopra qed_read_pf_bandwidth(p_hwfn, &shmem_info); 13904b01e519SManish Chopra 13914b01e519SManish Chopra p_info = &p_hwfn->mcp_info->func_info; 13924b01e519SManish Chopra 1393a64b02d5SManish Chopra qed_configure_pf_min_bandwidth(p_hwfn->cdev, p_info->bandwidth_min); 13944b01e519SManish Chopra qed_configure_pf_max_bandwidth(p_hwfn->cdev, p_info->bandwidth_max); 13954b01e519SManish Chopra 13964b01e519SManish Chopra /* Acknowledge the MFW */ 13974b01e519SManish Chopra qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_BW_UPDATE_ACK, 0, &resp, 13984b01e519SManish Chopra ¶m); 13994b01e519SManish Chopra } 14004b01e519SManish Chopra 14012a351fd9SMintz, Yuval static void qed_mcp_update_stag(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 14022a351fd9SMintz, Yuval { 14032a351fd9SMintz, Yuval struct public_func shmem_info; 14042a351fd9SMintz, Yuval u32 resp = 0, param = 0; 14052a351fd9SMintz, Yuval 14062a351fd9SMintz, Yuval qed_mcp_get_shmem_func(p_hwfn, p_ptt, &shmem_info, MCP_PF_ID(p_hwfn)); 14072a351fd9SMintz, Yuval 14082a351fd9SMintz, Yuval p_hwfn->mcp_info->func_info.ovlan = (u16)shmem_info.ovlan_stag & 14092a351fd9SMintz, Yuval FUNC_MF_CFG_OV_STAG_MASK; 14102a351fd9SMintz, Yuval p_hwfn->hw_info.ovlan = p_hwfn->mcp_info->func_info.ovlan; 14112a351fd9SMintz, Yuval if ((p_hwfn->hw_info.hw_mode & BIT(MODE_MF_SD)) && 14122a351fd9SMintz, Yuval (p_hwfn->hw_info.ovlan != QED_MCP_VLAN_UNSET)) { 14132a351fd9SMintz, Yuval qed_wr(p_hwfn, p_ptt, 14142a351fd9SMintz, Yuval NIG_REG_LLH_FUNC_TAG_VALUE, p_hwfn->hw_info.ovlan); 14152a351fd9SMintz, Yuval qed_sp_pf_update_stag(p_hwfn); 14162a351fd9SMintz, Yuval } 14172a351fd9SMintz, Yuval 14182a351fd9SMintz, Yuval /* Acknowledge the MFW */ 14192a351fd9SMintz, Yuval qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_S_TAG_UPDATE_ACK, 0, 14202a351fd9SMintz, Yuval &resp, ¶m); 14212a351fd9SMintz, Yuval } 14222a351fd9SMintz, Yuval 1423cc875c2eSYuval Mintz int qed_mcp_handle_events(struct qed_hwfn *p_hwfn, 1424cc875c2eSYuval Mintz struct qed_ptt *p_ptt) 1425cc875c2eSYuval Mintz { 1426cc875c2eSYuval Mintz struct qed_mcp_info *info = p_hwfn->mcp_info; 1427cc875c2eSYuval Mintz int rc = 0; 1428cc875c2eSYuval Mintz bool found = false; 1429cc875c2eSYuval Mintz u16 i; 1430cc875c2eSYuval Mintz 1431cc875c2eSYuval Mintz DP_VERBOSE(p_hwfn, QED_MSG_SP, "Received message from MFW\n"); 1432cc875c2eSYuval Mintz 1433cc875c2eSYuval Mintz /* Read Messages from MFW */ 1434cc875c2eSYuval Mintz qed_mcp_read_mb(p_hwfn, p_ptt); 1435cc875c2eSYuval Mintz 1436cc875c2eSYuval Mintz /* Compare current messages to old ones */ 1437cc875c2eSYuval Mintz for (i = 0; i < info->mfw_mb_length; i++) { 1438cc875c2eSYuval Mintz if (info->mfw_mb_cur[i] == info->mfw_mb_shadow[i]) 1439cc875c2eSYuval Mintz continue; 1440cc875c2eSYuval Mintz 1441cc875c2eSYuval Mintz found = true; 1442cc875c2eSYuval Mintz 1443cc875c2eSYuval Mintz DP_VERBOSE(p_hwfn, NETIF_MSG_LINK, 1444cc875c2eSYuval Mintz "Msg [%d] - old CMD 0x%02x, new CMD 0x%02x\n", 1445cc875c2eSYuval Mintz i, info->mfw_mb_shadow[i], info->mfw_mb_cur[i]); 1446cc875c2eSYuval Mintz 1447cc875c2eSYuval Mintz switch (i) { 1448cc875c2eSYuval Mintz case MFW_DRV_MSG_LINK_CHANGE: 1449cc875c2eSYuval Mintz qed_mcp_handle_link_change(p_hwfn, p_ptt, false); 1450cc875c2eSYuval Mintz break; 14510b55e27dSYuval Mintz case MFW_DRV_MSG_VF_DISABLED: 14520b55e27dSYuval Mintz qed_mcp_handle_vf_flr(p_hwfn, p_ptt); 14530b55e27dSYuval Mintz break; 145439651abdSSudarsana Reddy Kalluru case MFW_DRV_MSG_LLDP_DATA_UPDATED: 145539651abdSSudarsana Reddy Kalluru qed_dcbx_mib_update_event(p_hwfn, p_ptt, 145639651abdSSudarsana Reddy Kalluru QED_DCBX_REMOTE_LLDP_MIB); 145739651abdSSudarsana Reddy Kalluru break; 145839651abdSSudarsana Reddy Kalluru case MFW_DRV_MSG_DCBX_REMOTE_MIB_UPDATED: 145939651abdSSudarsana Reddy Kalluru qed_dcbx_mib_update_event(p_hwfn, p_ptt, 146039651abdSSudarsana Reddy Kalluru QED_DCBX_REMOTE_MIB); 146139651abdSSudarsana Reddy Kalluru break; 146239651abdSSudarsana Reddy Kalluru case MFW_DRV_MSG_DCBX_OPERATIONAL_MIB_UPDATED: 146339651abdSSudarsana Reddy Kalluru qed_dcbx_mib_update_event(p_hwfn, p_ptt, 146439651abdSSudarsana Reddy Kalluru QED_DCBX_OPERATIONAL_MIB); 146539651abdSSudarsana Reddy Kalluru break; 1466334c03b5SZvi Nachmani case MFW_DRV_MSG_TRANSCEIVER_STATE_CHANGE: 1467334c03b5SZvi Nachmani qed_mcp_handle_transceiver_change(p_hwfn, p_ptt); 1468334c03b5SZvi Nachmani break; 14696c754246SSudarsana Reddy Kalluru case MFW_DRV_MSG_GET_LAN_STATS: 14706c754246SSudarsana Reddy Kalluru case MFW_DRV_MSG_GET_FCOE_STATS: 14716c754246SSudarsana Reddy Kalluru case MFW_DRV_MSG_GET_ISCSI_STATS: 14726c754246SSudarsana Reddy Kalluru case MFW_DRV_MSG_GET_RDMA_STATS: 14736c754246SSudarsana Reddy Kalluru qed_mcp_send_protocol_stats(p_hwfn, p_ptt, i); 14746c754246SSudarsana Reddy Kalluru break; 14754b01e519SManish Chopra case MFW_DRV_MSG_BW_UPDATE: 14764b01e519SManish Chopra qed_mcp_update_bw(p_hwfn, p_ptt); 14774b01e519SManish Chopra break; 14782a351fd9SMintz, Yuval case MFW_DRV_MSG_S_TAG_UPDATE: 14792a351fd9SMintz, Yuval qed_mcp_update_stag(p_hwfn, p_ptt); 14802a351fd9SMintz, Yuval break; 14812a351fd9SMintz, Yuval break; 1482cc875c2eSYuval Mintz default: 148339815944SMintz, Yuval DP_INFO(p_hwfn, "Unimplemented MFW message %d\n", i); 1484cc875c2eSYuval Mintz rc = -EINVAL; 1485cc875c2eSYuval Mintz } 1486cc875c2eSYuval Mintz } 1487cc875c2eSYuval Mintz 1488cc875c2eSYuval Mintz /* ACK everything */ 1489cc875c2eSYuval Mintz for (i = 0; i < MFW_DRV_MSG_MAX_DWORDS(info->mfw_mb_length); i++) { 1490cc875c2eSYuval Mintz __be32 val = cpu_to_be32(((u32 *)info->mfw_mb_cur)[i]); 1491cc875c2eSYuval Mintz 1492cc875c2eSYuval Mintz /* MFW expect answer in BE, so we force write in that format */ 1493cc875c2eSYuval Mintz qed_wr(p_hwfn, p_ptt, 1494cc875c2eSYuval Mintz info->mfw_mb_addr + sizeof(u32) + 1495cc875c2eSYuval Mintz MFW_DRV_MSG_MAX_DWORDS(info->mfw_mb_length) * 1496cc875c2eSYuval Mintz sizeof(u32) + i * sizeof(u32), 1497cc875c2eSYuval Mintz (__force u32)val); 1498cc875c2eSYuval Mintz } 1499cc875c2eSYuval Mintz 1500cc875c2eSYuval Mintz if (!found) { 1501cc875c2eSYuval Mintz DP_NOTICE(p_hwfn, 1502cc875c2eSYuval Mintz "Received an MFW message indication but no new message!\n"); 1503cc875c2eSYuval Mintz rc = -EINVAL; 1504cc875c2eSYuval Mintz } 1505cc875c2eSYuval Mintz 1506cc875c2eSYuval Mintz /* Copy the new mfw messages into the shadow */ 1507cc875c2eSYuval Mintz memcpy(info->mfw_mb_shadow, info->mfw_mb_cur, info->mfw_mb_length); 1508cc875c2eSYuval Mintz 1509cc875c2eSYuval Mintz return rc; 1510cc875c2eSYuval Mintz } 1511cc875c2eSYuval Mintz 15121408cc1fSYuval Mintz int qed_mcp_get_mfw_ver(struct qed_hwfn *p_hwfn, 15131408cc1fSYuval Mintz struct qed_ptt *p_ptt, 15141408cc1fSYuval Mintz u32 *p_mfw_ver, u32 *p_running_bundle_id) 1515fe56b9e6SYuval Mintz { 1516fe56b9e6SYuval Mintz u32 global_offsize; 1517fe56b9e6SYuval Mintz 15181408cc1fSYuval Mintz if (IS_VF(p_hwfn->cdev)) { 15191408cc1fSYuval Mintz if (p_hwfn->vf_iov_info) { 15201408cc1fSYuval Mintz struct pfvf_acquire_resp_tlv *p_resp; 15211408cc1fSYuval Mintz 15221408cc1fSYuval Mintz p_resp = &p_hwfn->vf_iov_info->acquire_resp; 15231408cc1fSYuval Mintz *p_mfw_ver = p_resp->pfdev_info.mfw_ver; 15241408cc1fSYuval Mintz return 0; 15251408cc1fSYuval Mintz } else { 15261408cc1fSYuval Mintz DP_VERBOSE(p_hwfn, 15271408cc1fSYuval Mintz QED_MSG_IOV, 15281408cc1fSYuval Mintz "VF requested MFW version prior to ACQUIRE\n"); 15291408cc1fSYuval Mintz return -EINVAL; 15301408cc1fSYuval Mintz } 15311408cc1fSYuval Mintz } 1532fe56b9e6SYuval Mintz 1533fe56b9e6SYuval Mintz global_offsize = qed_rd(p_hwfn, p_ptt, 15341408cc1fSYuval Mintz SECTION_OFFSIZE_ADDR(p_hwfn-> 15351408cc1fSYuval Mintz mcp_info->public_base, 1536fe56b9e6SYuval Mintz PUBLIC_GLOBAL)); 15371408cc1fSYuval Mintz *p_mfw_ver = 15381408cc1fSYuval Mintz qed_rd(p_hwfn, p_ptt, 15391408cc1fSYuval Mintz SECTION_ADDR(global_offsize, 15401408cc1fSYuval Mintz 0) + offsetof(struct public_global, mfw_ver)); 1541fe56b9e6SYuval Mintz 15421408cc1fSYuval Mintz if (p_running_bundle_id != NULL) { 15431408cc1fSYuval Mintz *p_running_bundle_id = qed_rd(p_hwfn, p_ptt, 15441408cc1fSYuval Mintz SECTION_ADDR(global_offsize, 0) + 15451408cc1fSYuval Mintz offsetof(struct public_global, 15461408cc1fSYuval Mintz running_bundle_id)); 15471408cc1fSYuval Mintz } 1548fe56b9e6SYuval Mintz 1549fe56b9e6SYuval Mintz return 0; 1550fe56b9e6SYuval Mintz } 1551fe56b9e6SYuval Mintz 1552ae33666aSTomer Tayar int qed_mcp_get_mbi_ver(struct qed_hwfn *p_hwfn, 1553ae33666aSTomer Tayar struct qed_ptt *p_ptt, u32 *p_mbi_ver) 1554ae33666aSTomer Tayar { 1555ae33666aSTomer Tayar u32 nvm_cfg_addr, nvm_cfg1_offset, mbi_ver_addr; 1556ae33666aSTomer Tayar 1557ae33666aSTomer Tayar if (IS_VF(p_hwfn->cdev)) 1558ae33666aSTomer Tayar return -EINVAL; 1559ae33666aSTomer Tayar 1560ae33666aSTomer Tayar /* Read the address of the nvm_cfg */ 1561ae33666aSTomer Tayar nvm_cfg_addr = qed_rd(p_hwfn, p_ptt, MISC_REG_GEN_PURP_CR0); 1562ae33666aSTomer Tayar if (!nvm_cfg_addr) { 1563ae33666aSTomer Tayar DP_NOTICE(p_hwfn, "Shared memory not initialized\n"); 1564ae33666aSTomer Tayar return -EINVAL; 1565ae33666aSTomer Tayar } 1566ae33666aSTomer Tayar 1567ae33666aSTomer Tayar /* Read the offset of nvm_cfg1 */ 1568ae33666aSTomer Tayar nvm_cfg1_offset = qed_rd(p_hwfn, p_ptt, nvm_cfg_addr + 4); 1569ae33666aSTomer Tayar 1570ae33666aSTomer Tayar mbi_ver_addr = MCP_REG_SCRATCH + nvm_cfg1_offset + 1571ae33666aSTomer Tayar offsetof(struct nvm_cfg1, glob) + 1572ae33666aSTomer Tayar offsetof(struct nvm_cfg1_glob, mbi_version); 1573ae33666aSTomer Tayar *p_mbi_ver = qed_rd(p_hwfn, p_ptt, 1574ae33666aSTomer Tayar mbi_ver_addr) & 1575ae33666aSTomer Tayar (NVM_CFG1_GLOB_MBI_VERSION_0_MASK | 1576ae33666aSTomer Tayar NVM_CFG1_GLOB_MBI_VERSION_1_MASK | 1577ae33666aSTomer Tayar NVM_CFG1_GLOB_MBI_VERSION_2_MASK); 1578ae33666aSTomer Tayar 1579ae33666aSTomer Tayar return 0; 1580ae33666aSTomer Tayar } 1581ae33666aSTomer Tayar 15821a635e48SYuval Mintz int qed_mcp_get_media_type(struct qed_dev *cdev, u32 *p_media_type) 1583cc875c2eSYuval Mintz { 1584cc875c2eSYuval Mintz struct qed_hwfn *p_hwfn = &cdev->hwfns[0]; 1585cc875c2eSYuval Mintz struct qed_ptt *p_ptt; 1586cc875c2eSYuval Mintz 15871408cc1fSYuval Mintz if (IS_VF(cdev)) 15881408cc1fSYuval Mintz return -EINVAL; 15891408cc1fSYuval Mintz 1590cc875c2eSYuval Mintz if (!qed_mcp_is_init(p_hwfn)) { 1591cc875c2eSYuval Mintz DP_NOTICE(p_hwfn, "MFW is not initialized!\n"); 1592cc875c2eSYuval Mintz return -EBUSY; 1593cc875c2eSYuval Mintz } 1594cc875c2eSYuval Mintz 1595cc875c2eSYuval Mintz *p_media_type = MEDIA_UNSPECIFIED; 1596cc875c2eSYuval Mintz 1597cc875c2eSYuval Mintz p_ptt = qed_ptt_acquire(p_hwfn); 1598cc875c2eSYuval Mintz if (!p_ptt) 1599cc875c2eSYuval Mintz return -EBUSY; 1600cc875c2eSYuval Mintz 1601cc875c2eSYuval Mintz *p_media_type = qed_rd(p_hwfn, p_ptt, p_hwfn->mcp_info->port_addr + 1602cc875c2eSYuval Mintz offsetof(struct public_port, media_type)); 1603cc875c2eSYuval Mintz 1604cc875c2eSYuval Mintz qed_ptt_release(p_hwfn, p_ptt); 1605cc875c2eSYuval Mintz 1606cc875c2eSYuval Mintz return 0; 1607cc875c2eSYuval Mintz } 1608cc875c2eSYuval Mintz 16096927e826SMintz, Yuval /* Old MFW has a global configuration for all PFs regarding RDMA support */ 16106927e826SMintz, Yuval static void 16116927e826SMintz, Yuval qed_mcp_get_shmem_proto_legacy(struct qed_hwfn *p_hwfn, 16126927e826SMintz, Yuval enum qed_pci_personality *p_proto) 16136927e826SMintz, Yuval { 16146927e826SMintz, Yuval /* There wasn't ever a legacy MFW that published iwarp. 16156927e826SMintz, Yuval * So at this point, this is either plain l2 or RoCE. 16166927e826SMintz, Yuval */ 16176927e826SMintz, Yuval if (test_bit(QED_DEV_CAP_ROCE, &p_hwfn->hw_info.device_capabilities)) 16186927e826SMintz, Yuval *p_proto = QED_PCI_ETH_ROCE; 16196927e826SMintz, Yuval else 16206927e826SMintz, Yuval *p_proto = QED_PCI_ETH; 16216927e826SMintz, Yuval 16226927e826SMintz, Yuval DP_VERBOSE(p_hwfn, NETIF_MSG_IFUP, 16236927e826SMintz, Yuval "According to Legacy capabilities, L2 personality is %08x\n", 16246927e826SMintz, Yuval (u32) *p_proto); 16256927e826SMintz, Yuval } 16266927e826SMintz, Yuval 16276927e826SMintz, Yuval static int 16286927e826SMintz, Yuval qed_mcp_get_shmem_proto_mfw(struct qed_hwfn *p_hwfn, 16296927e826SMintz, Yuval struct qed_ptt *p_ptt, 16306927e826SMintz, Yuval enum qed_pci_personality *p_proto) 16316927e826SMintz, Yuval { 16326927e826SMintz, Yuval u32 resp = 0, param = 0; 16336927e826SMintz, Yuval int rc; 16346927e826SMintz, Yuval 16356927e826SMintz, Yuval rc = qed_mcp_cmd(p_hwfn, p_ptt, 16366927e826SMintz, Yuval DRV_MSG_CODE_GET_PF_RDMA_PROTOCOL, 0, &resp, ¶m); 16376927e826SMintz, Yuval if (rc) 16386927e826SMintz, Yuval return rc; 16396927e826SMintz, Yuval if (resp != FW_MSG_CODE_OK) { 16406927e826SMintz, Yuval DP_VERBOSE(p_hwfn, NETIF_MSG_IFUP, 16416927e826SMintz, Yuval "MFW lacks support for command; Returns %08x\n", 16426927e826SMintz, Yuval resp); 16436927e826SMintz, Yuval return -EINVAL; 16446927e826SMintz, Yuval } 16456927e826SMintz, Yuval 16466927e826SMintz, Yuval switch (param) { 16476927e826SMintz, Yuval case FW_MB_PARAM_GET_PF_RDMA_NONE: 16486927e826SMintz, Yuval *p_proto = QED_PCI_ETH; 16496927e826SMintz, Yuval break; 16506927e826SMintz, Yuval case FW_MB_PARAM_GET_PF_RDMA_ROCE: 16516927e826SMintz, Yuval *p_proto = QED_PCI_ETH_ROCE; 16526927e826SMintz, Yuval break; 16536927e826SMintz, Yuval case FW_MB_PARAM_GET_PF_RDMA_BOTH: 16546927e826SMintz, Yuval DP_NOTICE(p_hwfn, 16556927e826SMintz, Yuval "Current day drivers don't support RoCE & iWARP. Default to RoCE-only\n"); 16566927e826SMintz, Yuval *p_proto = QED_PCI_ETH_ROCE; 16576927e826SMintz, Yuval break; 16586927e826SMintz, Yuval case FW_MB_PARAM_GET_PF_RDMA_IWARP: 16596927e826SMintz, Yuval default: 16606927e826SMintz, Yuval DP_NOTICE(p_hwfn, 16616927e826SMintz, Yuval "MFW answers GET_PF_RDMA_PROTOCOL but param is %08x\n", 16626927e826SMintz, Yuval param); 16636927e826SMintz, Yuval return -EINVAL; 16646927e826SMintz, Yuval } 16656927e826SMintz, Yuval 16666927e826SMintz, Yuval DP_VERBOSE(p_hwfn, 16676927e826SMintz, Yuval NETIF_MSG_IFUP, 16686927e826SMintz, Yuval "According to capabilities, L2 personality is %08x [resp %08x param %08x]\n", 16696927e826SMintz, Yuval (u32) *p_proto, resp, param); 16706927e826SMintz, Yuval return 0; 16716927e826SMintz, Yuval } 16726927e826SMintz, Yuval 1673fe56b9e6SYuval Mintz static int 1674fe56b9e6SYuval Mintz qed_mcp_get_shmem_proto(struct qed_hwfn *p_hwfn, 1675fe56b9e6SYuval Mintz struct public_func *p_info, 16766927e826SMintz, Yuval struct qed_ptt *p_ptt, 1677fe56b9e6SYuval Mintz enum qed_pci_personality *p_proto) 1678fe56b9e6SYuval Mintz { 1679fe56b9e6SYuval Mintz int rc = 0; 1680fe56b9e6SYuval Mintz 1681fe56b9e6SYuval Mintz switch (p_info->config & FUNC_MF_CFG_PROTOCOL_MASK) { 1682fe56b9e6SYuval Mintz case FUNC_MF_CFG_PROTOCOL_ETHERNET: 16831fe582ecSRam Amrani if (!IS_ENABLED(CONFIG_QED_RDMA)) 16841fe582ecSRam Amrani *p_proto = QED_PCI_ETH; 16851fe582ecSRam Amrani else if (qed_mcp_get_shmem_proto_mfw(p_hwfn, p_ptt, p_proto)) 16866927e826SMintz, Yuval qed_mcp_get_shmem_proto_legacy(p_hwfn, p_proto); 1687fe56b9e6SYuval Mintz break; 1688c5ac9319SYuval Mintz case FUNC_MF_CFG_PROTOCOL_ISCSI: 1689c5ac9319SYuval Mintz *p_proto = QED_PCI_ISCSI; 1690c5ac9319SYuval Mintz break; 16911e128c81SArun Easi case FUNC_MF_CFG_PROTOCOL_FCOE: 16921e128c81SArun Easi *p_proto = QED_PCI_FCOE; 16931e128c81SArun Easi break; 1694c5ac9319SYuval Mintz case FUNC_MF_CFG_PROTOCOL_ROCE: 1695c5ac9319SYuval Mintz DP_NOTICE(p_hwfn, "RoCE personality is not a valid value!\n"); 16966927e826SMintz, Yuval /* Fallthrough */ 1697fe56b9e6SYuval Mintz default: 1698fe56b9e6SYuval Mintz rc = -EINVAL; 1699fe56b9e6SYuval Mintz } 1700fe56b9e6SYuval Mintz 1701fe56b9e6SYuval Mintz return rc; 1702fe56b9e6SYuval Mintz } 1703fe56b9e6SYuval Mintz 1704fe56b9e6SYuval Mintz int qed_mcp_fill_shmem_func_info(struct qed_hwfn *p_hwfn, 1705fe56b9e6SYuval Mintz struct qed_ptt *p_ptt) 1706fe56b9e6SYuval Mintz { 1707fe56b9e6SYuval Mintz struct qed_mcp_function_info *info; 1708fe56b9e6SYuval Mintz struct public_func shmem_info; 1709fe56b9e6SYuval Mintz 17101a635e48SYuval Mintz qed_mcp_get_shmem_func(p_hwfn, p_ptt, &shmem_info, MCP_PF_ID(p_hwfn)); 1711fe56b9e6SYuval Mintz info = &p_hwfn->mcp_info->func_info; 1712fe56b9e6SYuval Mintz 1713fe56b9e6SYuval Mintz info->pause_on_host = (shmem_info.config & 1714fe56b9e6SYuval Mintz FUNC_MF_CFG_PAUSE_ON_HOST_RING) ? 1 : 0; 1715fe56b9e6SYuval Mintz 17166927e826SMintz, Yuval if (qed_mcp_get_shmem_proto(p_hwfn, &shmem_info, p_ptt, 17176927e826SMintz, Yuval &info->protocol)) { 1718fe56b9e6SYuval Mintz DP_ERR(p_hwfn, "Unknown personality %08x\n", 1719fe56b9e6SYuval Mintz (u32)(shmem_info.config & FUNC_MF_CFG_PROTOCOL_MASK)); 1720fe56b9e6SYuval Mintz return -EINVAL; 1721fe56b9e6SYuval Mintz } 1722fe56b9e6SYuval Mintz 17234b01e519SManish Chopra qed_read_pf_bandwidth(p_hwfn, &shmem_info); 1724fe56b9e6SYuval Mintz 1725fe56b9e6SYuval Mintz if (shmem_info.mac_upper || shmem_info.mac_lower) { 1726fe56b9e6SYuval Mintz info->mac[0] = (u8)(shmem_info.mac_upper >> 8); 1727fe56b9e6SYuval Mintz info->mac[1] = (u8)(shmem_info.mac_upper); 1728fe56b9e6SYuval Mintz info->mac[2] = (u8)(shmem_info.mac_lower >> 24); 1729fe56b9e6SYuval Mintz info->mac[3] = (u8)(shmem_info.mac_lower >> 16); 1730fe56b9e6SYuval Mintz info->mac[4] = (u8)(shmem_info.mac_lower >> 8); 1731fe56b9e6SYuval Mintz info->mac[5] = (u8)(shmem_info.mac_lower); 173214d39648SMintz, Yuval 173314d39648SMintz, Yuval /* Store primary MAC for later possible WoL */ 173414d39648SMintz, Yuval memcpy(&p_hwfn->cdev->wol_mac, info->mac, ETH_ALEN); 1735fe56b9e6SYuval Mintz } else { 1736fe56b9e6SYuval Mintz DP_NOTICE(p_hwfn, "MAC is 0 in shmem\n"); 1737fe56b9e6SYuval Mintz } 1738fe56b9e6SYuval Mintz 173957796759SMintz, Yuval info->wwn_port = (u64)shmem_info.fcoe_wwn_port_name_lower | 174057796759SMintz, Yuval (((u64)shmem_info.fcoe_wwn_port_name_upper) << 32); 174157796759SMintz, Yuval info->wwn_node = (u64)shmem_info.fcoe_wwn_node_name_lower | 174257796759SMintz, Yuval (((u64)shmem_info.fcoe_wwn_node_name_upper) << 32); 1743fe56b9e6SYuval Mintz 1744fe56b9e6SYuval Mintz info->ovlan = (u16)(shmem_info.ovlan_stag & FUNC_MF_CFG_OV_STAG_MASK); 1745fe56b9e6SYuval Mintz 17460fefbfbaSSudarsana Kalluru info->mtu = (u16)shmem_info.mtu_size; 17470fefbfbaSSudarsana Kalluru 174814d39648SMintz, Yuval p_hwfn->hw_info.b_wol_support = QED_WOL_SUPPORT_NONE; 174914d39648SMintz, Yuval p_hwfn->cdev->wol_config = (u8)QED_OV_WOL_DEFAULT; 175014d39648SMintz, Yuval if (qed_mcp_is_init(p_hwfn)) { 175114d39648SMintz, Yuval u32 resp = 0, param = 0; 175214d39648SMintz, Yuval int rc; 175314d39648SMintz, Yuval 175414d39648SMintz, Yuval rc = qed_mcp_cmd(p_hwfn, p_ptt, 175514d39648SMintz, Yuval DRV_MSG_CODE_OS_WOL, 0, &resp, ¶m); 175614d39648SMintz, Yuval if (rc) 175714d39648SMintz, Yuval return rc; 175814d39648SMintz, Yuval if (resp == FW_MSG_CODE_OS_WOL_SUPPORTED) 175914d39648SMintz, Yuval p_hwfn->hw_info.b_wol_support = QED_WOL_SUPPORT_PME; 176014d39648SMintz, Yuval } 176114d39648SMintz, Yuval 1762fe56b9e6SYuval Mintz DP_VERBOSE(p_hwfn, (QED_MSG_SP | NETIF_MSG_IFUP), 176314d39648SMintz, 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", 1764fe56b9e6SYuval Mintz info->pause_on_host, info->protocol, 1765fe56b9e6SYuval Mintz info->bandwidth_min, info->bandwidth_max, 1766fe56b9e6SYuval Mintz info->mac[0], info->mac[1], info->mac[2], 1767fe56b9e6SYuval Mintz info->mac[3], info->mac[4], info->mac[5], 176814d39648SMintz, Yuval info->wwn_port, info->wwn_node, 176914d39648SMintz, Yuval info->ovlan, (u8)p_hwfn->hw_info.b_wol_support); 1770fe56b9e6SYuval Mintz 1771fe56b9e6SYuval Mintz return 0; 1772fe56b9e6SYuval Mintz } 1773fe56b9e6SYuval Mintz 1774cc875c2eSYuval Mintz struct qed_mcp_link_params 1775cc875c2eSYuval Mintz *qed_mcp_get_link_params(struct qed_hwfn *p_hwfn) 1776cc875c2eSYuval Mintz { 1777cc875c2eSYuval Mintz if (!p_hwfn || !p_hwfn->mcp_info) 1778cc875c2eSYuval Mintz return NULL; 1779cc875c2eSYuval Mintz return &p_hwfn->mcp_info->link_input; 1780cc875c2eSYuval Mintz } 1781cc875c2eSYuval Mintz 1782cc875c2eSYuval Mintz struct qed_mcp_link_state 1783cc875c2eSYuval Mintz *qed_mcp_get_link_state(struct qed_hwfn *p_hwfn) 1784cc875c2eSYuval Mintz { 1785cc875c2eSYuval Mintz if (!p_hwfn || !p_hwfn->mcp_info) 1786cc875c2eSYuval Mintz return NULL; 1787cc875c2eSYuval Mintz return &p_hwfn->mcp_info->link_output; 1788cc875c2eSYuval Mintz } 1789cc875c2eSYuval Mintz 1790cc875c2eSYuval Mintz struct qed_mcp_link_capabilities 1791cc875c2eSYuval Mintz *qed_mcp_get_link_capabilities(struct qed_hwfn *p_hwfn) 1792cc875c2eSYuval Mintz { 1793cc875c2eSYuval Mintz if (!p_hwfn || !p_hwfn->mcp_info) 1794cc875c2eSYuval Mintz return NULL; 1795cc875c2eSYuval Mintz return &p_hwfn->mcp_info->link_capabilities; 1796cc875c2eSYuval Mintz } 1797cc875c2eSYuval Mintz 17981a635e48SYuval Mintz int qed_mcp_drain(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 1799fe56b9e6SYuval Mintz { 1800fe56b9e6SYuval Mintz u32 resp = 0, param = 0; 1801fe56b9e6SYuval Mintz int rc; 1802fe56b9e6SYuval Mintz 1803fe56b9e6SYuval Mintz rc = qed_mcp_cmd(p_hwfn, p_ptt, 18041a635e48SYuval Mintz DRV_MSG_CODE_NIG_DRAIN, 1000, &resp, ¶m); 1805fe56b9e6SYuval Mintz 1806fe56b9e6SYuval Mintz /* Wait for the drain to complete before returning */ 18078f60bafeSYuval Mintz msleep(1020); 1808fe56b9e6SYuval Mintz 1809fe56b9e6SYuval Mintz return rc; 1810fe56b9e6SYuval Mintz } 1811fe56b9e6SYuval Mintz 1812cee4d264SManish Chopra int qed_mcp_get_flash_size(struct qed_hwfn *p_hwfn, 18131a635e48SYuval Mintz struct qed_ptt *p_ptt, u32 *p_flash_size) 1814cee4d264SManish Chopra { 1815cee4d264SManish Chopra u32 flash_size; 1816cee4d264SManish Chopra 18171408cc1fSYuval Mintz if (IS_VF(p_hwfn->cdev)) 18181408cc1fSYuval Mintz return -EINVAL; 18191408cc1fSYuval Mintz 1820cee4d264SManish Chopra flash_size = qed_rd(p_hwfn, p_ptt, MCP_REG_NVM_CFG4); 1821cee4d264SManish Chopra flash_size = (flash_size & MCP_REG_NVM_CFG4_FLASH_SIZE) >> 1822cee4d264SManish Chopra MCP_REG_NVM_CFG4_FLASH_SIZE_SHIFT; 1823cee4d264SManish Chopra flash_size = (1 << (flash_size + MCP_BYTES_PER_MBIT_SHIFT)); 1824cee4d264SManish Chopra 1825cee4d264SManish Chopra *p_flash_size = flash_size; 1826cee4d264SManish Chopra 1827cee4d264SManish Chopra return 0; 1828cee4d264SManish Chopra } 1829cee4d264SManish Chopra 183088072fd4SMintz, Yuval static int 183188072fd4SMintz, Yuval qed_mcp_config_vf_msix_bb(struct qed_hwfn *p_hwfn, 18321408cc1fSYuval Mintz struct qed_ptt *p_ptt, u8 vf_id, u8 num) 18331408cc1fSYuval Mintz { 18341408cc1fSYuval Mintz u32 resp = 0, param = 0, rc_param = 0; 18351408cc1fSYuval Mintz int rc; 18361408cc1fSYuval Mintz 18371408cc1fSYuval Mintz /* Only Leader can configure MSIX, and need to take CMT into account */ 18381408cc1fSYuval Mintz if (!IS_LEAD_HWFN(p_hwfn)) 18391408cc1fSYuval Mintz return 0; 18401408cc1fSYuval Mintz num *= p_hwfn->cdev->num_hwfns; 18411408cc1fSYuval Mintz 18421408cc1fSYuval Mintz param |= (vf_id << DRV_MB_PARAM_CFG_VF_MSIX_VF_ID_SHIFT) & 18431408cc1fSYuval Mintz DRV_MB_PARAM_CFG_VF_MSIX_VF_ID_MASK; 18441408cc1fSYuval Mintz param |= (num << DRV_MB_PARAM_CFG_VF_MSIX_SB_NUM_SHIFT) & 18451408cc1fSYuval Mintz DRV_MB_PARAM_CFG_VF_MSIX_SB_NUM_MASK; 18461408cc1fSYuval Mintz 18471408cc1fSYuval Mintz rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_CFG_VF_MSIX, param, 18481408cc1fSYuval Mintz &resp, &rc_param); 18491408cc1fSYuval Mintz 18501408cc1fSYuval Mintz if (resp != FW_MSG_CODE_DRV_CFG_VF_MSIX_DONE) { 18511408cc1fSYuval Mintz DP_NOTICE(p_hwfn, "VF[%d]: MFW failed to set MSI-X\n", vf_id); 18521408cc1fSYuval Mintz rc = -EINVAL; 18531408cc1fSYuval Mintz } else { 18541408cc1fSYuval Mintz DP_VERBOSE(p_hwfn, QED_MSG_IOV, 18551408cc1fSYuval Mintz "Requested 0x%02x MSI-x interrupts from VF 0x%02x\n", 18561408cc1fSYuval Mintz num, vf_id); 18571408cc1fSYuval Mintz } 18581408cc1fSYuval Mintz 18591408cc1fSYuval Mintz return rc; 18601408cc1fSYuval Mintz } 18611408cc1fSYuval Mintz 186288072fd4SMintz, Yuval static int 186388072fd4SMintz, Yuval qed_mcp_config_vf_msix_ah(struct qed_hwfn *p_hwfn, 186488072fd4SMintz, Yuval struct qed_ptt *p_ptt, u8 num) 186588072fd4SMintz, Yuval { 186688072fd4SMintz, Yuval u32 resp = 0, param = num, rc_param = 0; 186788072fd4SMintz, Yuval int rc; 186888072fd4SMintz, Yuval 186988072fd4SMintz, Yuval rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_CFG_PF_VFS_MSIX, 187088072fd4SMintz, Yuval param, &resp, &rc_param); 187188072fd4SMintz, Yuval 187288072fd4SMintz, Yuval if (resp != FW_MSG_CODE_DRV_CFG_PF_VFS_MSIX_DONE) { 187388072fd4SMintz, Yuval DP_NOTICE(p_hwfn, "MFW failed to set MSI-X for VFs\n"); 187488072fd4SMintz, Yuval rc = -EINVAL; 187588072fd4SMintz, Yuval } else { 187688072fd4SMintz, Yuval DP_VERBOSE(p_hwfn, QED_MSG_IOV, 187788072fd4SMintz, Yuval "Requested 0x%02x MSI-x interrupts for VFs\n", num); 187888072fd4SMintz, Yuval } 187988072fd4SMintz, Yuval 188088072fd4SMintz, Yuval return rc; 188188072fd4SMintz, Yuval } 188288072fd4SMintz, Yuval 188388072fd4SMintz, Yuval int qed_mcp_config_vf_msix(struct qed_hwfn *p_hwfn, 188488072fd4SMintz, Yuval struct qed_ptt *p_ptt, u8 vf_id, u8 num) 188588072fd4SMintz, Yuval { 188688072fd4SMintz, Yuval if (QED_IS_BB(p_hwfn->cdev)) 188788072fd4SMintz, Yuval return qed_mcp_config_vf_msix_bb(p_hwfn, p_ptt, vf_id, num); 188888072fd4SMintz, Yuval else 188988072fd4SMintz, Yuval return qed_mcp_config_vf_msix_ah(p_hwfn, p_ptt, num); 189088072fd4SMintz, Yuval } 189188072fd4SMintz, Yuval 1892fe56b9e6SYuval Mintz int 1893fe56b9e6SYuval Mintz qed_mcp_send_drv_version(struct qed_hwfn *p_hwfn, 1894fe56b9e6SYuval Mintz struct qed_ptt *p_ptt, 1895fe56b9e6SYuval Mintz struct qed_mcp_drv_version *p_ver) 1896fe56b9e6SYuval Mintz { 18975529bad9STomer Tayar struct qed_mcp_mb_params mb_params; 18982f67af8cSTomer Tayar struct drv_version_stc drv_version; 18995529bad9STomer Tayar __be32 val; 19005529bad9STomer Tayar u32 i; 19015529bad9STomer Tayar int rc; 1902fe56b9e6SYuval Mintz 19032f67af8cSTomer Tayar memset(&drv_version, 0, sizeof(drv_version)); 19042f67af8cSTomer Tayar drv_version.version = p_ver->version; 190567a99b70SYuval Mintz for (i = 0; i < (MCP_DRV_VER_STR_SIZE - 4) / sizeof(u32); i++) { 190667a99b70SYuval Mintz val = cpu_to_be32(*((u32 *)&p_ver->name[i * sizeof(u32)])); 19072f67af8cSTomer Tayar *(__be32 *)&drv_version.name[i * sizeof(u32)] = val; 1908fe56b9e6SYuval Mintz } 1909fe56b9e6SYuval Mintz 19105529bad9STomer Tayar memset(&mb_params, 0, sizeof(mb_params)); 19115529bad9STomer Tayar mb_params.cmd = DRV_MSG_CODE_SET_VERSION; 19122f67af8cSTomer Tayar mb_params.p_data_src = &drv_version; 19132f67af8cSTomer Tayar mb_params.data_src_size = sizeof(drv_version); 19145529bad9STomer Tayar rc = qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 19155529bad9STomer Tayar if (rc) 1916fe56b9e6SYuval Mintz DP_ERR(p_hwfn, "MCP response failure, aborting\n"); 1917fe56b9e6SYuval Mintz 19185529bad9STomer Tayar return rc; 1919fe56b9e6SYuval Mintz } 192091420b83SSudarsana Kalluru 19214102426fSTomer Tayar int qed_mcp_halt(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 19224102426fSTomer Tayar { 19234102426fSTomer Tayar u32 resp = 0, param = 0; 19244102426fSTomer Tayar int rc; 19254102426fSTomer Tayar 19264102426fSTomer Tayar rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_MCP_HALT, 0, &resp, 19274102426fSTomer Tayar ¶m); 19284102426fSTomer Tayar if (rc) 19294102426fSTomer Tayar DP_ERR(p_hwfn, "MCP response failure, aborting\n"); 19304102426fSTomer Tayar 19314102426fSTomer Tayar return rc; 19324102426fSTomer Tayar } 19334102426fSTomer Tayar 19344102426fSTomer Tayar int qed_mcp_resume(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 19354102426fSTomer Tayar { 19364102426fSTomer Tayar u32 value, cpu_mode; 19374102426fSTomer Tayar 19384102426fSTomer Tayar qed_wr(p_hwfn, p_ptt, MCP_REG_CPU_STATE, 0xffffffff); 19394102426fSTomer Tayar 19404102426fSTomer Tayar value = qed_rd(p_hwfn, p_ptt, MCP_REG_CPU_MODE); 19414102426fSTomer Tayar value &= ~MCP_REG_CPU_MODE_SOFT_HALT; 19424102426fSTomer Tayar qed_wr(p_hwfn, p_ptt, MCP_REG_CPU_MODE, value); 19434102426fSTomer Tayar cpu_mode = qed_rd(p_hwfn, p_ptt, MCP_REG_CPU_MODE); 19444102426fSTomer Tayar 19454102426fSTomer Tayar return (cpu_mode & MCP_REG_CPU_MODE_SOFT_HALT) ? -EAGAIN : 0; 19464102426fSTomer Tayar } 19474102426fSTomer Tayar 19480fefbfbaSSudarsana Kalluru int qed_mcp_ov_update_current_config(struct qed_hwfn *p_hwfn, 19490fefbfbaSSudarsana Kalluru struct qed_ptt *p_ptt, 19500fefbfbaSSudarsana Kalluru enum qed_ov_client client) 19510fefbfbaSSudarsana Kalluru { 19520fefbfbaSSudarsana Kalluru u32 resp = 0, param = 0; 19530fefbfbaSSudarsana Kalluru u32 drv_mb_param; 19540fefbfbaSSudarsana Kalluru int rc; 19550fefbfbaSSudarsana Kalluru 19560fefbfbaSSudarsana Kalluru switch (client) { 19570fefbfbaSSudarsana Kalluru case QED_OV_CLIENT_DRV: 19580fefbfbaSSudarsana Kalluru drv_mb_param = DRV_MB_PARAM_OV_CURR_CFG_OS; 19590fefbfbaSSudarsana Kalluru break; 19600fefbfbaSSudarsana Kalluru case QED_OV_CLIENT_USER: 19610fefbfbaSSudarsana Kalluru drv_mb_param = DRV_MB_PARAM_OV_CURR_CFG_OTHER; 19620fefbfbaSSudarsana Kalluru break; 19630fefbfbaSSudarsana Kalluru case QED_OV_CLIENT_VENDOR_SPEC: 19640fefbfbaSSudarsana Kalluru drv_mb_param = DRV_MB_PARAM_OV_CURR_CFG_VENDOR_SPEC; 19650fefbfbaSSudarsana Kalluru break; 19660fefbfbaSSudarsana Kalluru default: 19670fefbfbaSSudarsana Kalluru DP_NOTICE(p_hwfn, "Invalid client type %d\n", client); 19680fefbfbaSSudarsana Kalluru return -EINVAL; 19690fefbfbaSSudarsana Kalluru } 19700fefbfbaSSudarsana Kalluru 19710fefbfbaSSudarsana Kalluru rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_OV_UPDATE_CURR_CFG, 19720fefbfbaSSudarsana Kalluru drv_mb_param, &resp, ¶m); 19730fefbfbaSSudarsana Kalluru if (rc) 19740fefbfbaSSudarsana Kalluru DP_ERR(p_hwfn, "MCP response failure, aborting\n"); 19750fefbfbaSSudarsana Kalluru 19760fefbfbaSSudarsana Kalluru return rc; 19770fefbfbaSSudarsana Kalluru } 19780fefbfbaSSudarsana Kalluru 19790fefbfbaSSudarsana Kalluru int qed_mcp_ov_update_driver_state(struct qed_hwfn *p_hwfn, 19800fefbfbaSSudarsana Kalluru struct qed_ptt *p_ptt, 19810fefbfbaSSudarsana Kalluru enum qed_ov_driver_state drv_state) 19820fefbfbaSSudarsana Kalluru { 19830fefbfbaSSudarsana Kalluru u32 resp = 0, param = 0; 19840fefbfbaSSudarsana Kalluru u32 drv_mb_param; 19850fefbfbaSSudarsana Kalluru int rc; 19860fefbfbaSSudarsana Kalluru 19870fefbfbaSSudarsana Kalluru switch (drv_state) { 19880fefbfbaSSudarsana Kalluru case QED_OV_DRIVER_STATE_NOT_LOADED: 19890fefbfbaSSudarsana Kalluru drv_mb_param = DRV_MSG_CODE_OV_UPDATE_DRIVER_STATE_NOT_LOADED; 19900fefbfbaSSudarsana Kalluru break; 19910fefbfbaSSudarsana Kalluru case QED_OV_DRIVER_STATE_DISABLED: 19920fefbfbaSSudarsana Kalluru drv_mb_param = DRV_MSG_CODE_OV_UPDATE_DRIVER_STATE_DISABLED; 19930fefbfbaSSudarsana Kalluru break; 19940fefbfbaSSudarsana Kalluru case QED_OV_DRIVER_STATE_ACTIVE: 19950fefbfbaSSudarsana Kalluru drv_mb_param = DRV_MSG_CODE_OV_UPDATE_DRIVER_STATE_ACTIVE; 19960fefbfbaSSudarsana Kalluru break; 19970fefbfbaSSudarsana Kalluru default: 19980fefbfbaSSudarsana Kalluru DP_NOTICE(p_hwfn, "Invalid driver state %d\n", drv_state); 19990fefbfbaSSudarsana Kalluru return -EINVAL; 20000fefbfbaSSudarsana Kalluru } 20010fefbfbaSSudarsana Kalluru 20020fefbfbaSSudarsana Kalluru rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_OV_UPDATE_DRIVER_STATE, 20030fefbfbaSSudarsana Kalluru drv_mb_param, &resp, ¶m); 20040fefbfbaSSudarsana Kalluru if (rc) 20050fefbfbaSSudarsana Kalluru DP_ERR(p_hwfn, "Failed to send driver state\n"); 20060fefbfbaSSudarsana Kalluru 20070fefbfbaSSudarsana Kalluru return rc; 20080fefbfbaSSudarsana Kalluru } 20090fefbfbaSSudarsana Kalluru 20100fefbfbaSSudarsana Kalluru int qed_mcp_ov_update_mtu(struct qed_hwfn *p_hwfn, 20110fefbfbaSSudarsana Kalluru struct qed_ptt *p_ptt, u16 mtu) 20120fefbfbaSSudarsana Kalluru { 20130fefbfbaSSudarsana Kalluru u32 resp = 0, param = 0; 20140fefbfbaSSudarsana Kalluru u32 drv_mb_param; 20150fefbfbaSSudarsana Kalluru int rc; 20160fefbfbaSSudarsana Kalluru 20170fefbfbaSSudarsana Kalluru drv_mb_param = (u32)mtu << DRV_MB_PARAM_OV_MTU_SIZE_SHIFT; 20180fefbfbaSSudarsana Kalluru rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_OV_UPDATE_MTU, 20190fefbfbaSSudarsana Kalluru drv_mb_param, &resp, ¶m); 20200fefbfbaSSudarsana Kalluru if (rc) 20210fefbfbaSSudarsana Kalluru DP_ERR(p_hwfn, "Failed to send mtu value, rc = %d\n", rc); 20220fefbfbaSSudarsana Kalluru 20230fefbfbaSSudarsana Kalluru return rc; 20240fefbfbaSSudarsana Kalluru } 20250fefbfbaSSudarsana Kalluru 20260fefbfbaSSudarsana Kalluru int qed_mcp_ov_update_mac(struct qed_hwfn *p_hwfn, 20270fefbfbaSSudarsana Kalluru struct qed_ptt *p_ptt, u8 *mac) 20280fefbfbaSSudarsana Kalluru { 20290fefbfbaSSudarsana Kalluru struct qed_mcp_mb_params mb_params; 203017991002SMintz, Yuval u32 mfw_mac[2]; 20310fefbfbaSSudarsana Kalluru int rc; 20320fefbfbaSSudarsana Kalluru 20330fefbfbaSSudarsana Kalluru memset(&mb_params, 0, sizeof(mb_params)); 20340fefbfbaSSudarsana Kalluru mb_params.cmd = DRV_MSG_CODE_SET_VMAC; 20350fefbfbaSSudarsana Kalluru mb_params.param = DRV_MSG_CODE_VMAC_TYPE_MAC << 20360fefbfbaSSudarsana Kalluru DRV_MSG_CODE_VMAC_TYPE_SHIFT; 20370fefbfbaSSudarsana Kalluru mb_params.param |= MCP_PF_ID(p_hwfn); 20382f67af8cSTomer Tayar 203917991002SMintz, Yuval /* MCP is BE, and on LE platforms PCI would swap access to SHMEM 204017991002SMintz, Yuval * in 32-bit granularity. 204117991002SMintz, Yuval * So the MAC has to be set in native order [and not byte order], 204217991002SMintz, Yuval * otherwise it would be read incorrectly by MFW after swap. 204317991002SMintz, Yuval */ 204417991002SMintz, Yuval mfw_mac[0] = mac[0] << 24 | mac[1] << 16 | mac[2] << 8 | mac[3]; 204517991002SMintz, Yuval mfw_mac[1] = mac[4] << 24 | mac[5] << 16; 204617991002SMintz, Yuval 204717991002SMintz, Yuval mb_params.p_data_src = (u8 *)mfw_mac; 204817991002SMintz, Yuval mb_params.data_src_size = 8; 20490fefbfbaSSudarsana Kalluru rc = qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 20500fefbfbaSSudarsana Kalluru if (rc) 20510fefbfbaSSudarsana Kalluru DP_ERR(p_hwfn, "Failed to send mac address, rc = %d\n", rc); 20520fefbfbaSSudarsana Kalluru 205314d39648SMintz, Yuval /* Store primary MAC for later possible WoL */ 205414d39648SMintz, Yuval memcpy(p_hwfn->cdev->wol_mac, mac, ETH_ALEN); 205514d39648SMintz, Yuval 20560fefbfbaSSudarsana Kalluru return rc; 20570fefbfbaSSudarsana Kalluru } 20580fefbfbaSSudarsana Kalluru 20590fefbfbaSSudarsana Kalluru int qed_mcp_ov_update_wol(struct qed_hwfn *p_hwfn, 20600fefbfbaSSudarsana Kalluru struct qed_ptt *p_ptt, enum qed_ov_wol wol) 20610fefbfbaSSudarsana Kalluru { 20620fefbfbaSSudarsana Kalluru u32 resp = 0, param = 0; 20630fefbfbaSSudarsana Kalluru u32 drv_mb_param; 20640fefbfbaSSudarsana Kalluru int rc; 20650fefbfbaSSudarsana Kalluru 206614d39648SMintz, Yuval if (p_hwfn->hw_info.b_wol_support == QED_WOL_SUPPORT_NONE) { 206714d39648SMintz, Yuval DP_VERBOSE(p_hwfn, QED_MSG_SP, 206814d39648SMintz, Yuval "Can't change WoL configuration when WoL isn't supported\n"); 206914d39648SMintz, Yuval return -EINVAL; 207014d39648SMintz, Yuval } 207114d39648SMintz, Yuval 20720fefbfbaSSudarsana Kalluru switch (wol) { 20730fefbfbaSSudarsana Kalluru case QED_OV_WOL_DEFAULT: 20740fefbfbaSSudarsana Kalluru drv_mb_param = DRV_MB_PARAM_WOL_DEFAULT; 20750fefbfbaSSudarsana Kalluru break; 20760fefbfbaSSudarsana Kalluru case QED_OV_WOL_DISABLED: 20770fefbfbaSSudarsana Kalluru drv_mb_param = DRV_MB_PARAM_WOL_DISABLED; 20780fefbfbaSSudarsana Kalluru break; 20790fefbfbaSSudarsana Kalluru case QED_OV_WOL_ENABLED: 20800fefbfbaSSudarsana Kalluru drv_mb_param = DRV_MB_PARAM_WOL_ENABLED; 20810fefbfbaSSudarsana Kalluru break; 20820fefbfbaSSudarsana Kalluru default: 20830fefbfbaSSudarsana Kalluru DP_ERR(p_hwfn, "Invalid wol state %d\n", wol); 20840fefbfbaSSudarsana Kalluru return -EINVAL; 20850fefbfbaSSudarsana Kalluru } 20860fefbfbaSSudarsana Kalluru 20870fefbfbaSSudarsana Kalluru rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_OV_UPDATE_WOL, 20880fefbfbaSSudarsana Kalluru drv_mb_param, &resp, ¶m); 20890fefbfbaSSudarsana Kalluru if (rc) 20900fefbfbaSSudarsana Kalluru DP_ERR(p_hwfn, "Failed to send wol mode, rc = %d\n", rc); 20910fefbfbaSSudarsana Kalluru 209214d39648SMintz, Yuval /* Store the WoL update for a future unload */ 209314d39648SMintz, Yuval p_hwfn->cdev->wol_config = (u8)wol; 209414d39648SMintz, Yuval 20950fefbfbaSSudarsana Kalluru return rc; 20960fefbfbaSSudarsana Kalluru } 20970fefbfbaSSudarsana Kalluru 20980fefbfbaSSudarsana Kalluru int qed_mcp_ov_update_eswitch(struct qed_hwfn *p_hwfn, 20990fefbfbaSSudarsana Kalluru struct qed_ptt *p_ptt, 21000fefbfbaSSudarsana Kalluru enum qed_ov_eswitch eswitch) 21010fefbfbaSSudarsana Kalluru { 21020fefbfbaSSudarsana Kalluru u32 resp = 0, param = 0; 21030fefbfbaSSudarsana Kalluru u32 drv_mb_param; 21040fefbfbaSSudarsana Kalluru int rc; 21050fefbfbaSSudarsana Kalluru 21060fefbfbaSSudarsana Kalluru switch (eswitch) { 21070fefbfbaSSudarsana Kalluru case QED_OV_ESWITCH_NONE: 21080fefbfbaSSudarsana Kalluru drv_mb_param = DRV_MB_PARAM_ESWITCH_MODE_NONE; 21090fefbfbaSSudarsana Kalluru break; 21100fefbfbaSSudarsana Kalluru case QED_OV_ESWITCH_VEB: 21110fefbfbaSSudarsana Kalluru drv_mb_param = DRV_MB_PARAM_ESWITCH_MODE_VEB; 21120fefbfbaSSudarsana Kalluru break; 21130fefbfbaSSudarsana Kalluru case QED_OV_ESWITCH_VEPA: 21140fefbfbaSSudarsana Kalluru drv_mb_param = DRV_MB_PARAM_ESWITCH_MODE_VEPA; 21150fefbfbaSSudarsana Kalluru break; 21160fefbfbaSSudarsana Kalluru default: 21170fefbfbaSSudarsana Kalluru DP_ERR(p_hwfn, "Invalid eswitch mode %d\n", eswitch); 21180fefbfbaSSudarsana Kalluru return -EINVAL; 21190fefbfbaSSudarsana Kalluru } 21200fefbfbaSSudarsana Kalluru 21210fefbfbaSSudarsana Kalluru rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_OV_UPDATE_ESWITCH_MODE, 21220fefbfbaSSudarsana Kalluru drv_mb_param, &resp, ¶m); 21230fefbfbaSSudarsana Kalluru if (rc) 21240fefbfbaSSudarsana Kalluru DP_ERR(p_hwfn, "Failed to send eswitch mode, rc = %d\n", rc); 21250fefbfbaSSudarsana Kalluru 21260fefbfbaSSudarsana Kalluru return rc; 21270fefbfbaSSudarsana Kalluru } 21280fefbfbaSSudarsana Kalluru 21291a635e48SYuval Mintz int qed_mcp_set_led(struct qed_hwfn *p_hwfn, 21301a635e48SYuval Mintz struct qed_ptt *p_ptt, enum qed_led_mode mode) 213191420b83SSudarsana Kalluru { 213291420b83SSudarsana Kalluru u32 resp = 0, param = 0, drv_mb_param; 213391420b83SSudarsana Kalluru int rc; 213491420b83SSudarsana Kalluru 213591420b83SSudarsana Kalluru switch (mode) { 213691420b83SSudarsana Kalluru case QED_LED_MODE_ON: 213791420b83SSudarsana Kalluru drv_mb_param = DRV_MB_PARAM_SET_LED_MODE_ON; 213891420b83SSudarsana Kalluru break; 213991420b83SSudarsana Kalluru case QED_LED_MODE_OFF: 214091420b83SSudarsana Kalluru drv_mb_param = DRV_MB_PARAM_SET_LED_MODE_OFF; 214191420b83SSudarsana Kalluru break; 214291420b83SSudarsana Kalluru case QED_LED_MODE_RESTORE: 214391420b83SSudarsana Kalluru drv_mb_param = DRV_MB_PARAM_SET_LED_MODE_OPER; 214491420b83SSudarsana Kalluru break; 214591420b83SSudarsana Kalluru default: 214691420b83SSudarsana Kalluru DP_NOTICE(p_hwfn, "Invalid LED mode %d\n", mode); 214791420b83SSudarsana Kalluru return -EINVAL; 214891420b83SSudarsana Kalluru } 214991420b83SSudarsana Kalluru 215091420b83SSudarsana Kalluru rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_SET_LED_MODE, 215191420b83SSudarsana Kalluru drv_mb_param, &resp, ¶m); 215291420b83SSudarsana Kalluru 215391420b83SSudarsana Kalluru return rc; 215491420b83SSudarsana Kalluru } 215503dc76caSSudarsana Reddy Kalluru 21564102426fSTomer Tayar int qed_mcp_mask_parities(struct qed_hwfn *p_hwfn, 21574102426fSTomer Tayar struct qed_ptt *p_ptt, u32 mask_parities) 21584102426fSTomer Tayar { 21594102426fSTomer Tayar u32 resp = 0, param = 0; 21604102426fSTomer Tayar int rc; 21614102426fSTomer Tayar 21624102426fSTomer Tayar rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_MASK_PARITIES, 21634102426fSTomer Tayar mask_parities, &resp, ¶m); 21644102426fSTomer Tayar 21654102426fSTomer Tayar if (rc) { 21664102426fSTomer Tayar DP_ERR(p_hwfn, 21674102426fSTomer Tayar "MCP response failure for mask parities, aborting\n"); 21684102426fSTomer Tayar } else if (resp != FW_MSG_CODE_OK) { 21694102426fSTomer Tayar DP_ERR(p_hwfn, 21704102426fSTomer Tayar "MCP did not acknowledge mask parity request. Old MFW?\n"); 21714102426fSTomer Tayar rc = -EINVAL; 21724102426fSTomer Tayar } 21734102426fSTomer Tayar 21744102426fSTomer Tayar return rc; 21754102426fSTomer Tayar } 21764102426fSTomer Tayar 21777a4b21b7SMintz, Yuval int qed_mcp_nvm_read(struct qed_dev *cdev, u32 addr, u8 *p_buf, u32 len) 21787a4b21b7SMintz, Yuval { 21797a4b21b7SMintz, Yuval u32 bytes_left = len, offset = 0, bytes_to_copy, read_len = 0; 21807a4b21b7SMintz, Yuval struct qed_hwfn *p_hwfn = QED_LEADING_HWFN(cdev); 21817a4b21b7SMintz, Yuval u32 resp = 0, resp_param = 0; 21827a4b21b7SMintz, Yuval struct qed_ptt *p_ptt; 21837a4b21b7SMintz, Yuval int rc = 0; 21847a4b21b7SMintz, Yuval 21857a4b21b7SMintz, Yuval p_ptt = qed_ptt_acquire(p_hwfn); 21867a4b21b7SMintz, Yuval if (!p_ptt) 21877a4b21b7SMintz, Yuval return -EBUSY; 21887a4b21b7SMintz, Yuval 21897a4b21b7SMintz, Yuval while (bytes_left > 0) { 21907a4b21b7SMintz, Yuval bytes_to_copy = min_t(u32, bytes_left, MCP_DRV_NVM_BUF_LEN); 21917a4b21b7SMintz, Yuval 21927a4b21b7SMintz, Yuval rc = qed_mcp_nvm_rd_cmd(p_hwfn, p_ptt, 21937a4b21b7SMintz, Yuval DRV_MSG_CODE_NVM_READ_NVRAM, 21947a4b21b7SMintz, Yuval addr + offset + 21957a4b21b7SMintz, Yuval (bytes_to_copy << 21967a4b21b7SMintz, Yuval DRV_MB_PARAM_NVM_LEN_SHIFT), 21977a4b21b7SMintz, Yuval &resp, &resp_param, 21987a4b21b7SMintz, Yuval &read_len, 21997a4b21b7SMintz, Yuval (u32 *)(p_buf + offset)); 22007a4b21b7SMintz, Yuval 22017a4b21b7SMintz, Yuval if (rc || (resp != FW_MSG_CODE_NVM_OK)) { 22027a4b21b7SMintz, Yuval DP_NOTICE(cdev, "MCP command rc = %d\n", rc); 22037a4b21b7SMintz, Yuval break; 22047a4b21b7SMintz, Yuval } 22057a4b21b7SMintz, Yuval 22067a4b21b7SMintz, Yuval /* This can be a lengthy process, and it's possible scheduler 22077a4b21b7SMintz, Yuval * isn't preemptable. Sleep a bit to prevent CPU hogging. 22087a4b21b7SMintz, Yuval */ 22097a4b21b7SMintz, Yuval if (bytes_left % 0x1000 < 22107a4b21b7SMintz, Yuval (bytes_left - read_len) % 0x1000) 22117a4b21b7SMintz, Yuval usleep_range(1000, 2000); 22127a4b21b7SMintz, Yuval 22137a4b21b7SMintz, Yuval offset += read_len; 22147a4b21b7SMintz, Yuval bytes_left -= read_len; 22157a4b21b7SMintz, Yuval } 22167a4b21b7SMintz, Yuval 22177a4b21b7SMintz, Yuval cdev->mcp_nvm_resp = resp; 22187a4b21b7SMintz, Yuval qed_ptt_release(p_hwfn, p_ptt); 22197a4b21b7SMintz, Yuval 22207a4b21b7SMintz, Yuval return rc; 22217a4b21b7SMintz, Yuval } 22227a4b21b7SMintz, Yuval 222303dc76caSSudarsana Reddy Kalluru int qed_mcp_bist_register_test(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 222403dc76caSSudarsana Reddy Kalluru { 222503dc76caSSudarsana Reddy Kalluru u32 drv_mb_param = 0, rsp, param; 222603dc76caSSudarsana Reddy Kalluru int rc = 0; 222703dc76caSSudarsana Reddy Kalluru 222803dc76caSSudarsana Reddy Kalluru drv_mb_param = (DRV_MB_PARAM_BIST_REGISTER_TEST << 222903dc76caSSudarsana Reddy Kalluru DRV_MB_PARAM_BIST_TEST_INDEX_SHIFT); 223003dc76caSSudarsana Reddy Kalluru 223103dc76caSSudarsana Reddy Kalluru rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_BIST_TEST, 223203dc76caSSudarsana Reddy Kalluru drv_mb_param, &rsp, ¶m); 223303dc76caSSudarsana Reddy Kalluru 223403dc76caSSudarsana Reddy Kalluru if (rc) 223503dc76caSSudarsana Reddy Kalluru return rc; 223603dc76caSSudarsana Reddy Kalluru 223703dc76caSSudarsana Reddy Kalluru if (((rsp & FW_MSG_CODE_MASK) != FW_MSG_CODE_OK) || 223803dc76caSSudarsana Reddy Kalluru (param != DRV_MB_PARAM_BIST_RC_PASSED)) 223903dc76caSSudarsana Reddy Kalluru rc = -EAGAIN; 224003dc76caSSudarsana Reddy Kalluru 224103dc76caSSudarsana Reddy Kalluru return rc; 224203dc76caSSudarsana Reddy Kalluru } 224303dc76caSSudarsana Reddy Kalluru 224403dc76caSSudarsana Reddy Kalluru int qed_mcp_bist_clock_test(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 224503dc76caSSudarsana Reddy Kalluru { 224603dc76caSSudarsana Reddy Kalluru u32 drv_mb_param, rsp, param; 224703dc76caSSudarsana Reddy Kalluru int rc = 0; 224803dc76caSSudarsana Reddy Kalluru 224903dc76caSSudarsana Reddy Kalluru drv_mb_param = (DRV_MB_PARAM_BIST_CLOCK_TEST << 225003dc76caSSudarsana Reddy Kalluru DRV_MB_PARAM_BIST_TEST_INDEX_SHIFT); 225103dc76caSSudarsana Reddy Kalluru 225203dc76caSSudarsana Reddy Kalluru rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_BIST_TEST, 225303dc76caSSudarsana Reddy Kalluru drv_mb_param, &rsp, ¶m); 225403dc76caSSudarsana Reddy Kalluru 225503dc76caSSudarsana Reddy Kalluru if (rc) 225603dc76caSSudarsana Reddy Kalluru return rc; 225703dc76caSSudarsana Reddy Kalluru 225803dc76caSSudarsana Reddy Kalluru if (((rsp & FW_MSG_CODE_MASK) != FW_MSG_CODE_OK) || 225903dc76caSSudarsana Reddy Kalluru (param != DRV_MB_PARAM_BIST_RC_PASSED)) 226003dc76caSSudarsana Reddy Kalluru rc = -EAGAIN; 226103dc76caSSudarsana Reddy Kalluru 226203dc76caSSudarsana Reddy Kalluru return rc; 226303dc76caSSudarsana Reddy Kalluru } 22647a4b21b7SMintz, Yuval 22657a4b21b7SMintz, Yuval int qed_mcp_bist_nvm_test_get_num_images(struct qed_hwfn *p_hwfn, 22667a4b21b7SMintz, Yuval struct qed_ptt *p_ptt, 22677a4b21b7SMintz, Yuval u32 *num_images) 22687a4b21b7SMintz, Yuval { 22697a4b21b7SMintz, Yuval u32 drv_mb_param = 0, rsp; 22707a4b21b7SMintz, Yuval int rc = 0; 22717a4b21b7SMintz, Yuval 22727a4b21b7SMintz, Yuval drv_mb_param = (DRV_MB_PARAM_BIST_NVM_TEST_NUM_IMAGES << 22737a4b21b7SMintz, Yuval DRV_MB_PARAM_BIST_TEST_INDEX_SHIFT); 22747a4b21b7SMintz, Yuval 22757a4b21b7SMintz, Yuval rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_BIST_TEST, 22767a4b21b7SMintz, Yuval drv_mb_param, &rsp, num_images); 22777a4b21b7SMintz, Yuval if (rc) 22787a4b21b7SMintz, Yuval return rc; 22797a4b21b7SMintz, Yuval 22807a4b21b7SMintz, Yuval if (((rsp & FW_MSG_CODE_MASK) != FW_MSG_CODE_OK)) 22817a4b21b7SMintz, Yuval rc = -EINVAL; 22827a4b21b7SMintz, Yuval 22837a4b21b7SMintz, Yuval return rc; 22847a4b21b7SMintz, Yuval } 22857a4b21b7SMintz, Yuval 22867a4b21b7SMintz, Yuval int qed_mcp_bist_nvm_test_get_image_att(struct qed_hwfn *p_hwfn, 22877a4b21b7SMintz, Yuval struct qed_ptt *p_ptt, 22887a4b21b7SMintz, Yuval struct bist_nvm_image_att *p_image_att, 22897a4b21b7SMintz, Yuval u32 image_index) 22907a4b21b7SMintz, Yuval { 22917a4b21b7SMintz, Yuval u32 buf_size = 0, param, resp = 0, resp_param = 0; 22927a4b21b7SMintz, Yuval int rc; 22937a4b21b7SMintz, Yuval 22947a4b21b7SMintz, Yuval param = DRV_MB_PARAM_BIST_NVM_TEST_IMAGE_BY_INDEX << 22957a4b21b7SMintz, Yuval DRV_MB_PARAM_BIST_TEST_INDEX_SHIFT; 22967a4b21b7SMintz, Yuval param |= image_index << DRV_MB_PARAM_BIST_TEST_IMAGE_INDEX_SHIFT; 22977a4b21b7SMintz, Yuval 22987a4b21b7SMintz, Yuval rc = qed_mcp_nvm_rd_cmd(p_hwfn, p_ptt, 22997a4b21b7SMintz, Yuval DRV_MSG_CODE_BIST_TEST, param, 23007a4b21b7SMintz, Yuval &resp, &resp_param, 23017a4b21b7SMintz, Yuval &buf_size, 23027a4b21b7SMintz, Yuval (u32 *)p_image_att); 23037a4b21b7SMintz, Yuval if (rc) 23047a4b21b7SMintz, Yuval return rc; 23057a4b21b7SMintz, Yuval 23067a4b21b7SMintz, Yuval if (((resp & FW_MSG_CODE_MASK) != FW_MSG_CODE_OK) || 23077a4b21b7SMintz, Yuval (p_image_att->return_code != 1)) 23087a4b21b7SMintz, Yuval rc = -EINVAL; 23097a4b21b7SMintz, Yuval 23107a4b21b7SMintz, Yuval return rc; 23117a4b21b7SMintz, Yuval } 23122edbff8dSTomer Tayar 231320675b37SMintz, Yuval static int 231420675b37SMintz, Yuval qed_mcp_get_nvm_image_att(struct qed_hwfn *p_hwfn, 231520675b37SMintz, Yuval struct qed_ptt *p_ptt, 231620675b37SMintz, Yuval enum qed_nvm_images image_id, 231720675b37SMintz, Yuval struct qed_nvm_image_att *p_image_att) 231820675b37SMintz, Yuval { 231920675b37SMintz, Yuval struct bist_nvm_image_att mfw_image_att; 232020675b37SMintz, Yuval enum nvm_image_type type; 232120675b37SMintz, Yuval u32 num_images, i; 232220675b37SMintz, Yuval int rc; 232320675b37SMintz, Yuval 232420675b37SMintz, Yuval /* Translate image_id into MFW definitions */ 232520675b37SMintz, Yuval switch (image_id) { 232620675b37SMintz, Yuval case QED_NVM_IMAGE_ISCSI_CFG: 232720675b37SMintz, Yuval type = NVM_TYPE_ISCSI_CFG; 232820675b37SMintz, Yuval break; 232920675b37SMintz, Yuval case QED_NVM_IMAGE_FCOE_CFG: 233020675b37SMintz, Yuval type = NVM_TYPE_FCOE_CFG; 233120675b37SMintz, Yuval break; 233220675b37SMintz, Yuval default: 233320675b37SMintz, Yuval DP_NOTICE(p_hwfn, "Unknown request of image_id %08x\n", 233420675b37SMintz, Yuval image_id); 233520675b37SMintz, Yuval return -EINVAL; 233620675b37SMintz, Yuval } 233720675b37SMintz, Yuval 233820675b37SMintz, Yuval /* Learn number of images, then traverse and see if one fits */ 233920675b37SMintz, Yuval rc = qed_mcp_bist_nvm_test_get_num_images(p_hwfn, p_ptt, &num_images); 234020675b37SMintz, Yuval if (rc || !num_images) 234120675b37SMintz, Yuval return -EINVAL; 234220675b37SMintz, Yuval 234320675b37SMintz, Yuval for (i = 0; i < num_images; i++) { 234420675b37SMintz, Yuval rc = qed_mcp_bist_nvm_test_get_image_att(p_hwfn, p_ptt, 234520675b37SMintz, Yuval &mfw_image_att, i); 234620675b37SMintz, Yuval if (rc) 234720675b37SMintz, Yuval return rc; 234820675b37SMintz, Yuval 234920675b37SMintz, Yuval if (type == mfw_image_att.image_type) 235020675b37SMintz, Yuval break; 235120675b37SMintz, Yuval } 235220675b37SMintz, Yuval if (i == num_images) { 235320675b37SMintz, Yuval DP_VERBOSE(p_hwfn, QED_MSG_STORAGE, 235420675b37SMintz, Yuval "Failed to find nvram image of type %08x\n", 235520675b37SMintz, Yuval image_id); 235620675b37SMintz, Yuval return -EINVAL; 235720675b37SMintz, Yuval } 235820675b37SMintz, Yuval 235920675b37SMintz, Yuval p_image_att->start_addr = mfw_image_att.nvm_start_addr; 236020675b37SMintz, Yuval p_image_att->length = mfw_image_att.len; 236120675b37SMintz, Yuval 236220675b37SMintz, Yuval return 0; 236320675b37SMintz, Yuval } 236420675b37SMintz, Yuval 236520675b37SMintz, Yuval int qed_mcp_get_nvm_image(struct qed_hwfn *p_hwfn, 236620675b37SMintz, Yuval struct qed_ptt *p_ptt, 236720675b37SMintz, Yuval enum qed_nvm_images image_id, 236820675b37SMintz, Yuval u8 *p_buffer, u32 buffer_len) 236920675b37SMintz, Yuval { 237020675b37SMintz, Yuval struct qed_nvm_image_att image_att; 237120675b37SMintz, Yuval int rc; 237220675b37SMintz, Yuval 237320675b37SMintz, Yuval memset(p_buffer, 0, buffer_len); 237420675b37SMintz, Yuval 237520675b37SMintz, Yuval rc = qed_mcp_get_nvm_image_att(p_hwfn, p_ptt, image_id, &image_att); 237620675b37SMintz, Yuval if (rc) 237720675b37SMintz, Yuval return rc; 237820675b37SMintz, Yuval 237920675b37SMintz, Yuval /* Validate sizes - both the image's and the supplied buffer's */ 238020675b37SMintz, Yuval if (image_att.length <= 4) { 238120675b37SMintz, Yuval DP_VERBOSE(p_hwfn, QED_MSG_STORAGE, 238220675b37SMintz, Yuval "Image [%d] is too small - only %d bytes\n", 238320675b37SMintz, Yuval image_id, image_att.length); 238420675b37SMintz, Yuval return -EINVAL; 238520675b37SMintz, Yuval } 238620675b37SMintz, Yuval 238720675b37SMintz, Yuval /* Each NVM image is suffixed by CRC; Upper-layer has no need for it */ 238820675b37SMintz, Yuval image_att.length -= 4; 238920675b37SMintz, Yuval 239020675b37SMintz, Yuval if (image_att.length > buffer_len) { 239120675b37SMintz, Yuval DP_VERBOSE(p_hwfn, 239220675b37SMintz, Yuval QED_MSG_STORAGE, 239320675b37SMintz, Yuval "Image [%d] is too big - %08x bytes where only %08x are available\n", 239420675b37SMintz, Yuval image_id, image_att.length, buffer_len); 239520675b37SMintz, Yuval return -ENOMEM; 239620675b37SMintz, Yuval } 239720675b37SMintz, Yuval 239820675b37SMintz, Yuval return qed_mcp_nvm_read(p_hwfn->cdev, image_att.start_addr, 239920675b37SMintz, Yuval p_buffer, image_att.length); 240020675b37SMintz, Yuval } 240120675b37SMintz, Yuval 24029c8517c4STomer Tayar static enum resource_id_enum qed_mcp_get_mfw_res_id(enum qed_resources res_id) 24039c8517c4STomer Tayar { 24049c8517c4STomer Tayar enum resource_id_enum mfw_res_id = RESOURCE_NUM_INVALID; 24059c8517c4STomer Tayar 24069c8517c4STomer Tayar switch (res_id) { 24079c8517c4STomer Tayar case QED_SB: 24089c8517c4STomer Tayar mfw_res_id = RESOURCE_NUM_SB_E; 24099c8517c4STomer Tayar break; 24109c8517c4STomer Tayar case QED_L2_QUEUE: 24119c8517c4STomer Tayar mfw_res_id = RESOURCE_NUM_L2_QUEUE_E; 24129c8517c4STomer Tayar break; 24139c8517c4STomer Tayar case QED_VPORT: 24149c8517c4STomer Tayar mfw_res_id = RESOURCE_NUM_VPORT_E; 24159c8517c4STomer Tayar break; 24169c8517c4STomer Tayar case QED_RSS_ENG: 24179c8517c4STomer Tayar mfw_res_id = RESOURCE_NUM_RSS_ENGINES_E; 24189c8517c4STomer Tayar break; 24199c8517c4STomer Tayar case QED_PQ: 24209c8517c4STomer Tayar mfw_res_id = RESOURCE_NUM_PQ_E; 24219c8517c4STomer Tayar break; 24229c8517c4STomer Tayar case QED_RL: 24239c8517c4STomer Tayar mfw_res_id = RESOURCE_NUM_RL_E; 24249c8517c4STomer Tayar break; 24259c8517c4STomer Tayar case QED_MAC: 24269c8517c4STomer Tayar case QED_VLAN: 24279c8517c4STomer Tayar /* Each VFC resource can accommodate both a MAC and a VLAN */ 24289c8517c4STomer Tayar mfw_res_id = RESOURCE_VFC_FILTER_E; 24299c8517c4STomer Tayar break; 24309c8517c4STomer Tayar case QED_ILT: 24319c8517c4STomer Tayar mfw_res_id = RESOURCE_ILT_E; 24329c8517c4STomer Tayar break; 24339c8517c4STomer Tayar case QED_LL2_QUEUE: 24349c8517c4STomer Tayar mfw_res_id = RESOURCE_LL2_QUEUE_E; 24359c8517c4STomer Tayar break; 24369c8517c4STomer Tayar case QED_RDMA_CNQ_RAM: 24379c8517c4STomer Tayar case QED_CMDQS_CQS: 24389c8517c4STomer Tayar /* CNQ/CMDQS are the same resource */ 24399c8517c4STomer Tayar mfw_res_id = RESOURCE_CQS_E; 24409c8517c4STomer Tayar break; 24419c8517c4STomer Tayar case QED_RDMA_STATS_QUEUE: 24429c8517c4STomer Tayar mfw_res_id = RESOURCE_RDMA_STATS_QUEUE_E; 24439c8517c4STomer Tayar break; 24449c8517c4STomer Tayar case QED_BDQ: 24459c8517c4STomer Tayar mfw_res_id = RESOURCE_BDQ_E; 24469c8517c4STomer Tayar break; 24479c8517c4STomer Tayar default: 24489c8517c4STomer Tayar break; 24499c8517c4STomer Tayar } 24509c8517c4STomer Tayar 24519c8517c4STomer Tayar return mfw_res_id; 24529c8517c4STomer Tayar } 24539c8517c4STomer Tayar 24549c8517c4STomer Tayar #define QED_RESC_ALLOC_VERSION_MAJOR 2 24552edbff8dSTomer Tayar #define QED_RESC_ALLOC_VERSION_MINOR 0 24562edbff8dSTomer Tayar #define QED_RESC_ALLOC_VERSION \ 24572edbff8dSTomer Tayar ((QED_RESC_ALLOC_VERSION_MAJOR << \ 24582edbff8dSTomer Tayar DRV_MB_PARAM_RESOURCE_ALLOC_VERSION_MAJOR_SHIFT) | \ 24592edbff8dSTomer Tayar (QED_RESC_ALLOC_VERSION_MINOR << \ 24602edbff8dSTomer Tayar DRV_MB_PARAM_RESOURCE_ALLOC_VERSION_MINOR_SHIFT)) 24619c8517c4STomer Tayar 24629c8517c4STomer Tayar struct qed_resc_alloc_in_params { 24639c8517c4STomer Tayar u32 cmd; 24649c8517c4STomer Tayar enum qed_resources res_id; 24659c8517c4STomer Tayar u32 resc_max_val; 24669c8517c4STomer Tayar }; 24679c8517c4STomer Tayar 24689c8517c4STomer Tayar struct qed_resc_alloc_out_params { 24699c8517c4STomer Tayar u32 mcp_resp; 24709c8517c4STomer Tayar u32 mcp_param; 24719c8517c4STomer Tayar u32 resc_num; 24729c8517c4STomer Tayar u32 resc_start; 24739c8517c4STomer Tayar u32 vf_resc_num; 24749c8517c4STomer Tayar u32 vf_resc_start; 24759c8517c4STomer Tayar u32 flags; 24769c8517c4STomer Tayar }; 24779c8517c4STomer Tayar 24789c8517c4STomer Tayar static int 24799c8517c4STomer Tayar qed_mcp_resc_allocation_msg(struct qed_hwfn *p_hwfn, 24802edbff8dSTomer Tayar struct qed_ptt *p_ptt, 24819c8517c4STomer Tayar struct qed_resc_alloc_in_params *p_in_params, 24829c8517c4STomer Tayar struct qed_resc_alloc_out_params *p_out_params) 24832edbff8dSTomer Tayar { 24842edbff8dSTomer Tayar struct qed_mcp_mb_params mb_params; 24859c8517c4STomer Tayar struct resource_info mfw_resc_info; 24862edbff8dSTomer Tayar int rc; 24872edbff8dSTomer Tayar 24889c8517c4STomer Tayar memset(&mfw_resc_info, 0, sizeof(mfw_resc_info)); 2489bb480242SMintz, Yuval 24909c8517c4STomer Tayar mfw_resc_info.res_id = qed_mcp_get_mfw_res_id(p_in_params->res_id); 24919c8517c4STomer Tayar if (mfw_resc_info.res_id == RESOURCE_NUM_INVALID) { 24929c8517c4STomer Tayar DP_ERR(p_hwfn, 24939c8517c4STomer Tayar "Failed to match resource %d [%s] with the MFW resources\n", 24949c8517c4STomer Tayar p_in_params->res_id, 24959c8517c4STomer Tayar qed_hw_get_resc_name(p_in_params->res_id)); 24969c8517c4STomer Tayar return -EINVAL; 24979c8517c4STomer Tayar } 24989c8517c4STomer Tayar 24999c8517c4STomer Tayar switch (p_in_params->cmd) { 25009c8517c4STomer Tayar case DRV_MSG_SET_RESOURCE_VALUE_MSG: 25019c8517c4STomer Tayar mfw_resc_info.size = p_in_params->resc_max_val; 25029c8517c4STomer Tayar /* Fallthrough */ 25039c8517c4STomer Tayar case DRV_MSG_GET_RESOURCE_ALLOC_MSG: 25049c8517c4STomer Tayar break; 25059c8517c4STomer Tayar default: 25069c8517c4STomer Tayar DP_ERR(p_hwfn, "Unexpected resource alloc command [0x%08x]\n", 25079c8517c4STomer Tayar p_in_params->cmd); 25089c8517c4STomer Tayar return -EINVAL; 25099c8517c4STomer Tayar } 25109c8517c4STomer Tayar 25119c8517c4STomer Tayar memset(&mb_params, 0, sizeof(mb_params)); 25129c8517c4STomer Tayar mb_params.cmd = p_in_params->cmd; 25139c8517c4STomer Tayar mb_params.param = QED_RESC_ALLOC_VERSION; 25149c8517c4STomer Tayar mb_params.p_data_src = &mfw_resc_info; 25159c8517c4STomer Tayar mb_params.data_src_size = sizeof(mfw_resc_info); 25169c8517c4STomer Tayar mb_params.p_data_dst = mb_params.p_data_src; 25179c8517c4STomer Tayar mb_params.data_dst_size = mb_params.data_src_size; 25189c8517c4STomer Tayar 25199c8517c4STomer Tayar DP_VERBOSE(p_hwfn, 25209c8517c4STomer Tayar QED_MSG_SP, 25219c8517c4STomer Tayar "Resource message request: cmd 0x%08x, res_id %d [%s], hsi_version %d.%d, val 0x%x\n", 25229c8517c4STomer Tayar p_in_params->cmd, 25239c8517c4STomer Tayar p_in_params->res_id, 25249c8517c4STomer Tayar qed_hw_get_resc_name(p_in_params->res_id), 25259c8517c4STomer Tayar QED_MFW_GET_FIELD(mb_params.param, 25269c8517c4STomer Tayar DRV_MB_PARAM_RESOURCE_ALLOC_VERSION_MAJOR), 25279c8517c4STomer Tayar QED_MFW_GET_FIELD(mb_params.param, 25289c8517c4STomer Tayar DRV_MB_PARAM_RESOURCE_ALLOC_VERSION_MINOR), 25299c8517c4STomer Tayar p_in_params->resc_max_val); 25309c8517c4STomer Tayar 25312edbff8dSTomer Tayar rc = qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 25322edbff8dSTomer Tayar if (rc) 25332edbff8dSTomer Tayar return rc; 25342edbff8dSTomer Tayar 25359c8517c4STomer Tayar p_out_params->mcp_resp = mb_params.mcp_resp; 25369c8517c4STomer Tayar p_out_params->mcp_param = mb_params.mcp_param; 25379c8517c4STomer Tayar p_out_params->resc_num = mfw_resc_info.size; 25389c8517c4STomer Tayar p_out_params->resc_start = mfw_resc_info.offset; 25399c8517c4STomer Tayar p_out_params->vf_resc_num = mfw_resc_info.vf_size; 25409c8517c4STomer Tayar p_out_params->vf_resc_start = mfw_resc_info.vf_offset; 25419c8517c4STomer Tayar p_out_params->flags = mfw_resc_info.flags; 25422edbff8dSTomer Tayar 25432edbff8dSTomer Tayar DP_VERBOSE(p_hwfn, 25442edbff8dSTomer Tayar QED_MSG_SP, 25459c8517c4STomer 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", 25469c8517c4STomer Tayar QED_MFW_GET_FIELD(p_out_params->mcp_param, 25479c8517c4STomer Tayar FW_MB_PARAM_RESOURCE_ALLOC_VERSION_MAJOR), 25489c8517c4STomer Tayar QED_MFW_GET_FIELD(p_out_params->mcp_param, 25499c8517c4STomer Tayar FW_MB_PARAM_RESOURCE_ALLOC_VERSION_MINOR), 25509c8517c4STomer Tayar p_out_params->resc_num, 25519c8517c4STomer Tayar p_out_params->resc_start, 25529c8517c4STomer Tayar p_out_params->vf_resc_num, 25539c8517c4STomer Tayar p_out_params->vf_resc_start, p_out_params->flags); 25549c8517c4STomer Tayar 25559c8517c4STomer Tayar return 0; 25569c8517c4STomer Tayar } 25579c8517c4STomer Tayar 25589c8517c4STomer Tayar int 25599c8517c4STomer Tayar qed_mcp_set_resc_max_val(struct qed_hwfn *p_hwfn, 25609c8517c4STomer Tayar struct qed_ptt *p_ptt, 25619c8517c4STomer Tayar enum qed_resources res_id, 25629c8517c4STomer Tayar u32 resc_max_val, u32 *p_mcp_resp) 25639c8517c4STomer Tayar { 25649c8517c4STomer Tayar struct qed_resc_alloc_out_params out_params; 25659c8517c4STomer Tayar struct qed_resc_alloc_in_params in_params; 25669c8517c4STomer Tayar int rc; 25679c8517c4STomer Tayar 25689c8517c4STomer Tayar memset(&in_params, 0, sizeof(in_params)); 25699c8517c4STomer Tayar in_params.cmd = DRV_MSG_SET_RESOURCE_VALUE_MSG; 25709c8517c4STomer Tayar in_params.res_id = res_id; 25719c8517c4STomer Tayar in_params.resc_max_val = resc_max_val; 25729c8517c4STomer Tayar memset(&out_params, 0, sizeof(out_params)); 25739c8517c4STomer Tayar rc = qed_mcp_resc_allocation_msg(p_hwfn, p_ptt, &in_params, 25749c8517c4STomer Tayar &out_params); 25759c8517c4STomer Tayar if (rc) 25769c8517c4STomer Tayar return rc; 25779c8517c4STomer Tayar 25789c8517c4STomer Tayar *p_mcp_resp = out_params.mcp_resp; 25799c8517c4STomer Tayar 25809c8517c4STomer Tayar return 0; 25819c8517c4STomer Tayar } 25829c8517c4STomer Tayar 25839c8517c4STomer Tayar int 25849c8517c4STomer Tayar qed_mcp_get_resc_info(struct qed_hwfn *p_hwfn, 25859c8517c4STomer Tayar struct qed_ptt *p_ptt, 25869c8517c4STomer Tayar enum qed_resources res_id, 25879c8517c4STomer Tayar u32 *p_mcp_resp, u32 *p_resc_num, u32 *p_resc_start) 25889c8517c4STomer Tayar { 25899c8517c4STomer Tayar struct qed_resc_alloc_out_params out_params; 25909c8517c4STomer Tayar struct qed_resc_alloc_in_params in_params; 25919c8517c4STomer Tayar int rc; 25929c8517c4STomer Tayar 25939c8517c4STomer Tayar memset(&in_params, 0, sizeof(in_params)); 25949c8517c4STomer Tayar in_params.cmd = DRV_MSG_GET_RESOURCE_ALLOC_MSG; 25959c8517c4STomer Tayar in_params.res_id = res_id; 25969c8517c4STomer Tayar memset(&out_params, 0, sizeof(out_params)); 25979c8517c4STomer Tayar rc = qed_mcp_resc_allocation_msg(p_hwfn, p_ptt, &in_params, 25989c8517c4STomer Tayar &out_params); 25999c8517c4STomer Tayar if (rc) 26009c8517c4STomer Tayar return rc; 26019c8517c4STomer Tayar 26029c8517c4STomer Tayar *p_mcp_resp = out_params.mcp_resp; 26039c8517c4STomer Tayar 26049c8517c4STomer Tayar if (*p_mcp_resp == FW_MSG_CODE_RESOURCE_ALLOC_OK) { 26059c8517c4STomer Tayar *p_resc_num = out_params.resc_num; 26069c8517c4STomer Tayar *p_resc_start = out_params.resc_start; 26079c8517c4STomer Tayar } 26082edbff8dSTomer Tayar 26092edbff8dSTomer Tayar return 0; 26102edbff8dSTomer Tayar } 261118a69e36SMintz, Yuval 261218a69e36SMintz, Yuval int qed_mcp_initiate_pf_flr(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 261318a69e36SMintz, Yuval { 261418a69e36SMintz, Yuval u32 mcp_resp, mcp_param; 261518a69e36SMintz, Yuval 261618a69e36SMintz, Yuval return qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_INITIATE_PF_FLR, 0, 261718a69e36SMintz, Yuval &mcp_resp, &mcp_param); 261818a69e36SMintz, Yuval } 261995691c9cSTomer Tayar 262095691c9cSTomer Tayar static int qed_mcp_resource_cmd(struct qed_hwfn *p_hwfn, 262195691c9cSTomer Tayar struct qed_ptt *p_ptt, 262295691c9cSTomer Tayar u32 param, u32 *p_mcp_resp, u32 *p_mcp_param) 262395691c9cSTomer Tayar { 262495691c9cSTomer Tayar int rc; 262595691c9cSTomer Tayar 262695691c9cSTomer Tayar rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_RESOURCE_CMD, param, 262795691c9cSTomer Tayar p_mcp_resp, p_mcp_param); 262895691c9cSTomer Tayar if (rc) 262995691c9cSTomer Tayar return rc; 263095691c9cSTomer Tayar 263195691c9cSTomer Tayar if (*p_mcp_resp == FW_MSG_CODE_UNSUPPORTED) { 263295691c9cSTomer Tayar DP_INFO(p_hwfn, 263395691c9cSTomer Tayar "The resource command is unsupported by the MFW\n"); 263495691c9cSTomer Tayar return -EINVAL; 263595691c9cSTomer Tayar } 263695691c9cSTomer Tayar 263795691c9cSTomer Tayar if (*p_mcp_param == RESOURCE_OPCODE_UNKNOWN_CMD) { 263895691c9cSTomer Tayar u8 opcode = QED_MFW_GET_FIELD(param, RESOURCE_CMD_REQ_OPCODE); 263995691c9cSTomer Tayar 264095691c9cSTomer Tayar DP_NOTICE(p_hwfn, 264195691c9cSTomer Tayar "The resource command is unknown to the MFW [param 0x%08x, opcode %d]\n", 264295691c9cSTomer Tayar param, opcode); 264395691c9cSTomer Tayar return -EINVAL; 264495691c9cSTomer Tayar } 264595691c9cSTomer Tayar 264695691c9cSTomer Tayar return rc; 264795691c9cSTomer Tayar } 264895691c9cSTomer Tayar 264995691c9cSTomer Tayar int 265095691c9cSTomer Tayar __qed_mcp_resc_lock(struct qed_hwfn *p_hwfn, 265195691c9cSTomer Tayar struct qed_ptt *p_ptt, 265295691c9cSTomer Tayar struct qed_resc_lock_params *p_params) 265395691c9cSTomer Tayar { 265495691c9cSTomer Tayar u32 param = 0, mcp_resp, mcp_param; 265595691c9cSTomer Tayar u8 opcode; 265695691c9cSTomer Tayar int rc; 265795691c9cSTomer Tayar 265895691c9cSTomer Tayar switch (p_params->timeout) { 265995691c9cSTomer Tayar case QED_MCP_RESC_LOCK_TO_DEFAULT: 266095691c9cSTomer Tayar opcode = RESOURCE_OPCODE_REQ; 266195691c9cSTomer Tayar p_params->timeout = 0; 266295691c9cSTomer Tayar break; 266395691c9cSTomer Tayar case QED_MCP_RESC_LOCK_TO_NONE: 266495691c9cSTomer Tayar opcode = RESOURCE_OPCODE_REQ_WO_AGING; 266595691c9cSTomer Tayar p_params->timeout = 0; 266695691c9cSTomer Tayar break; 266795691c9cSTomer Tayar default: 266895691c9cSTomer Tayar opcode = RESOURCE_OPCODE_REQ_W_AGING; 266995691c9cSTomer Tayar break; 267095691c9cSTomer Tayar } 267195691c9cSTomer Tayar 267295691c9cSTomer Tayar QED_MFW_SET_FIELD(param, RESOURCE_CMD_REQ_RESC, p_params->resource); 267395691c9cSTomer Tayar QED_MFW_SET_FIELD(param, RESOURCE_CMD_REQ_OPCODE, opcode); 267495691c9cSTomer Tayar QED_MFW_SET_FIELD(param, RESOURCE_CMD_REQ_AGE, p_params->timeout); 267595691c9cSTomer Tayar 267695691c9cSTomer Tayar DP_VERBOSE(p_hwfn, 267795691c9cSTomer Tayar QED_MSG_SP, 267895691c9cSTomer Tayar "Resource lock request: param 0x%08x [age %d, opcode %d, resource %d]\n", 267995691c9cSTomer Tayar param, p_params->timeout, opcode, p_params->resource); 268095691c9cSTomer Tayar 268195691c9cSTomer Tayar /* Attempt to acquire the resource */ 268295691c9cSTomer Tayar rc = qed_mcp_resource_cmd(p_hwfn, p_ptt, param, &mcp_resp, &mcp_param); 268395691c9cSTomer Tayar if (rc) 268495691c9cSTomer Tayar return rc; 268595691c9cSTomer Tayar 268695691c9cSTomer Tayar /* Analyze the response */ 268795691c9cSTomer Tayar p_params->owner = QED_MFW_GET_FIELD(mcp_param, RESOURCE_CMD_RSP_OWNER); 268895691c9cSTomer Tayar opcode = QED_MFW_GET_FIELD(mcp_param, RESOURCE_CMD_RSP_OPCODE); 268995691c9cSTomer Tayar 269095691c9cSTomer Tayar DP_VERBOSE(p_hwfn, 269195691c9cSTomer Tayar QED_MSG_SP, 269295691c9cSTomer Tayar "Resource lock response: mcp_param 0x%08x [opcode %d, owner %d]\n", 269395691c9cSTomer Tayar mcp_param, opcode, p_params->owner); 269495691c9cSTomer Tayar 269595691c9cSTomer Tayar switch (opcode) { 269695691c9cSTomer Tayar case RESOURCE_OPCODE_GNT: 269795691c9cSTomer Tayar p_params->b_granted = true; 269895691c9cSTomer Tayar break; 269995691c9cSTomer Tayar case RESOURCE_OPCODE_BUSY: 270095691c9cSTomer Tayar p_params->b_granted = false; 270195691c9cSTomer Tayar break; 270295691c9cSTomer Tayar default: 270395691c9cSTomer Tayar DP_NOTICE(p_hwfn, 270495691c9cSTomer Tayar "Unexpected opcode in resource lock response [mcp_param 0x%08x, opcode %d]\n", 270595691c9cSTomer Tayar mcp_param, opcode); 270695691c9cSTomer Tayar return -EINVAL; 270795691c9cSTomer Tayar } 270895691c9cSTomer Tayar 270995691c9cSTomer Tayar return 0; 271095691c9cSTomer Tayar } 271195691c9cSTomer Tayar 271295691c9cSTomer Tayar int 271395691c9cSTomer Tayar qed_mcp_resc_lock(struct qed_hwfn *p_hwfn, 271495691c9cSTomer Tayar struct qed_ptt *p_ptt, struct qed_resc_lock_params *p_params) 271595691c9cSTomer Tayar { 271695691c9cSTomer Tayar u32 retry_cnt = 0; 271795691c9cSTomer Tayar int rc; 271895691c9cSTomer Tayar 271995691c9cSTomer Tayar do { 272095691c9cSTomer Tayar /* No need for an interval before the first iteration */ 272195691c9cSTomer Tayar if (retry_cnt) { 272295691c9cSTomer Tayar if (p_params->sleep_b4_retry) { 272395691c9cSTomer Tayar u16 retry_interval_in_ms = 272495691c9cSTomer Tayar DIV_ROUND_UP(p_params->retry_interval, 272595691c9cSTomer Tayar 1000); 272695691c9cSTomer Tayar 272795691c9cSTomer Tayar msleep(retry_interval_in_ms); 272895691c9cSTomer Tayar } else { 272995691c9cSTomer Tayar udelay(p_params->retry_interval); 273095691c9cSTomer Tayar } 273195691c9cSTomer Tayar } 273295691c9cSTomer Tayar 273395691c9cSTomer Tayar rc = __qed_mcp_resc_lock(p_hwfn, p_ptt, p_params); 273495691c9cSTomer Tayar if (rc) 273595691c9cSTomer Tayar return rc; 273695691c9cSTomer Tayar 273795691c9cSTomer Tayar if (p_params->b_granted) 273895691c9cSTomer Tayar break; 273995691c9cSTomer Tayar } while (retry_cnt++ < p_params->retry_num); 274095691c9cSTomer Tayar 274195691c9cSTomer Tayar return 0; 274295691c9cSTomer Tayar } 274395691c9cSTomer Tayar 274495691c9cSTomer Tayar int 274595691c9cSTomer Tayar qed_mcp_resc_unlock(struct qed_hwfn *p_hwfn, 274695691c9cSTomer Tayar struct qed_ptt *p_ptt, 274795691c9cSTomer Tayar struct qed_resc_unlock_params *p_params) 274895691c9cSTomer Tayar { 274995691c9cSTomer Tayar u32 param = 0, mcp_resp, mcp_param; 275095691c9cSTomer Tayar u8 opcode; 275195691c9cSTomer Tayar int rc; 275295691c9cSTomer Tayar 275395691c9cSTomer Tayar opcode = p_params->b_force ? RESOURCE_OPCODE_FORCE_RELEASE 275495691c9cSTomer Tayar : RESOURCE_OPCODE_RELEASE; 275595691c9cSTomer Tayar QED_MFW_SET_FIELD(param, RESOURCE_CMD_REQ_RESC, p_params->resource); 275695691c9cSTomer Tayar QED_MFW_SET_FIELD(param, RESOURCE_CMD_REQ_OPCODE, opcode); 275795691c9cSTomer Tayar 275895691c9cSTomer Tayar DP_VERBOSE(p_hwfn, QED_MSG_SP, 275995691c9cSTomer Tayar "Resource unlock request: param 0x%08x [opcode %d, resource %d]\n", 276095691c9cSTomer Tayar param, opcode, p_params->resource); 276195691c9cSTomer Tayar 276295691c9cSTomer Tayar /* Attempt to release the resource */ 276395691c9cSTomer Tayar rc = qed_mcp_resource_cmd(p_hwfn, p_ptt, param, &mcp_resp, &mcp_param); 276495691c9cSTomer Tayar if (rc) 276595691c9cSTomer Tayar return rc; 276695691c9cSTomer Tayar 276795691c9cSTomer Tayar /* Analyze the response */ 276895691c9cSTomer Tayar opcode = QED_MFW_GET_FIELD(mcp_param, RESOURCE_CMD_RSP_OPCODE); 276995691c9cSTomer Tayar 277095691c9cSTomer Tayar DP_VERBOSE(p_hwfn, QED_MSG_SP, 277195691c9cSTomer Tayar "Resource unlock response: mcp_param 0x%08x [opcode %d]\n", 277295691c9cSTomer Tayar mcp_param, opcode); 277395691c9cSTomer Tayar 277495691c9cSTomer Tayar switch (opcode) { 277595691c9cSTomer Tayar case RESOURCE_OPCODE_RELEASED_PREVIOUS: 277695691c9cSTomer Tayar DP_INFO(p_hwfn, 277795691c9cSTomer Tayar "Resource unlock request for an already released resource [%d]\n", 277895691c9cSTomer Tayar p_params->resource); 277995691c9cSTomer Tayar /* Fallthrough */ 278095691c9cSTomer Tayar case RESOURCE_OPCODE_RELEASED: 278195691c9cSTomer Tayar p_params->b_released = true; 278295691c9cSTomer Tayar break; 278395691c9cSTomer Tayar case RESOURCE_OPCODE_WRONG_OWNER: 278495691c9cSTomer Tayar p_params->b_released = false; 278595691c9cSTomer Tayar break; 278695691c9cSTomer Tayar default: 278795691c9cSTomer Tayar DP_NOTICE(p_hwfn, 278895691c9cSTomer Tayar "Unexpected opcode in resource unlock response [mcp_param 0x%08x, opcode %d]\n", 278995691c9cSTomer Tayar mcp_param, opcode); 279095691c9cSTomer Tayar return -EINVAL; 279195691c9cSTomer Tayar } 279295691c9cSTomer Tayar 279395691c9cSTomer Tayar return 0; 279495691c9cSTomer Tayar } 2795f470f22cSsudarsana.kalluru@cavium.com 2796f470f22cSsudarsana.kalluru@cavium.com void qed_mcp_resc_lock_default_init(struct qed_resc_lock_params *p_lock, 2797f470f22cSsudarsana.kalluru@cavium.com struct qed_resc_unlock_params *p_unlock, 2798f470f22cSsudarsana.kalluru@cavium.com enum qed_resc_lock 2799f470f22cSsudarsana.kalluru@cavium.com resource, bool b_is_permanent) 2800f470f22cSsudarsana.kalluru@cavium.com { 2801f470f22cSsudarsana.kalluru@cavium.com if (p_lock) { 2802f470f22cSsudarsana.kalluru@cavium.com memset(p_lock, 0, sizeof(*p_lock)); 2803f470f22cSsudarsana.kalluru@cavium.com 2804f470f22cSsudarsana.kalluru@cavium.com /* Permanent resources don't require aging, and there's no 2805f470f22cSsudarsana.kalluru@cavium.com * point in trying to acquire them more than once since it's 2806f470f22cSsudarsana.kalluru@cavium.com * unexpected another entity would release them. 2807f470f22cSsudarsana.kalluru@cavium.com */ 2808f470f22cSsudarsana.kalluru@cavium.com if (b_is_permanent) { 2809f470f22cSsudarsana.kalluru@cavium.com p_lock->timeout = QED_MCP_RESC_LOCK_TO_NONE; 2810f470f22cSsudarsana.kalluru@cavium.com } else { 2811f470f22cSsudarsana.kalluru@cavium.com p_lock->retry_num = QED_MCP_RESC_LOCK_RETRY_CNT_DFLT; 2812f470f22cSsudarsana.kalluru@cavium.com p_lock->retry_interval = 2813f470f22cSsudarsana.kalluru@cavium.com QED_MCP_RESC_LOCK_RETRY_VAL_DFLT; 2814f470f22cSsudarsana.kalluru@cavium.com p_lock->sleep_b4_retry = true; 2815f470f22cSsudarsana.kalluru@cavium.com } 2816f470f22cSsudarsana.kalluru@cavium.com 2817f470f22cSsudarsana.kalluru@cavium.com p_lock->resource = resource; 2818f470f22cSsudarsana.kalluru@cavium.com } 2819f470f22cSsudarsana.kalluru@cavium.com 2820f470f22cSsudarsana.kalluru@cavium.com if (p_unlock) { 2821f470f22cSsudarsana.kalluru@cavium.com memset(p_unlock, 0, sizeof(*p_unlock)); 2822f470f22cSsudarsana.kalluru@cavium.com p_unlock->resource = resource; 2823f470f22cSsudarsana.kalluru@cavium.com } 2824f470f22cSsudarsana.kalluru@cavium.com } 2825