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 114fe56b9e6SYuval Mintz int qed_mcp_free(struct qed_hwfn *p_hwfn) 115fe56b9e6SYuval Mintz { 116fe56b9e6SYuval Mintz if (p_hwfn->mcp_info) { 117fe56b9e6SYuval Mintz kfree(p_hwfn->mcp_info->mfw_mb_cur); 118fe56b9e6SYuval Mintz kfree(p_hwfn->mcp_info->mfw_mb_shadow); 119fe56b9e6SYuval Mintz } 120fe56b9e6SYuval Mintz kfree(p_hwfn->mcp_info); 121fe56b9e6SYuval Mintz 122fe56b9e6SYuval Mintz return 0; 123fe56b9e6SYuval Mintz } 124fe56b9e6SYuval Mintz 1251a635e48SYuval Mintz static int qed_load_mcp_offsets(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 126fe56b9e6SYuval Mintz { 127fe56b9e6SYuval Mintz struct qed_mcp_info *p_info = p_hwfn->mcp_info; 128fe56b9e6SYuval Mintz u32 drv_mb_offsize, mfw_mb_offsize; 129fe56b9e6SYuval Mintz u32 mcp_pf_id = MCP_PF_ID(p_hwfn); 130fe56b9e6SYuval Mintz 131fe56b9e6SYuval Mintz p_info->public_base = qed_rd(p_hwfn, p_ptt, MISC_REG_SHARED_MEM_ADDR); 132fe56b9e6SYuval Mintz if (!p_info->public_base) 133fe56b9e6SYuval Mintz return 0; 134fe56b9e6SYuval Mintz 135fe56b9e6SYuval Mintz p_info->public_base |= GRCBASE_MCP; 136fe56b9e6SYuval Mintz 137fe56b9e6SYuval Mintz /* Calculate the driver and MFW mailbox address */ 138fe56b9e6SYuval Mintz drv_mb_offsize = qed_rd(p_hwfn, p_ptt, 139fe56b9e6SYuval Mintz SECTION_OFFSIZE_ADDR(p_info->public_base, 140fe56b9e6SYuval Mintz PUBLIC_DRV_MB)); 141fe56b9e6SYuval Mintz p_info->drv_mb_addr = SECTION_ADDR(drv_mb_offsize, mcp_pf_id); 142fe56b9e6SYuval Mintz DP_VERBOSE(p_hwfn, QED_MSG_SP, 143fe56b9e6SYuval Mintz "drv_mb_offsiz = 0x%x, drv_mb_addr = 0x%x mcp_pf_id = 0x%x\n", 144fe56b9e6SYuval Mintz drv_mb_offsize, p_info->drv_mb_addr, mcp_pf_id); 145fe56b9e6SYuval Mintz 146fe56b9e6SYuval Mintz /* Set the MFW MB address */ 147fe56b9e6SYuval Mintz mfw_mb_offsize = qed_rd(p_hwfn, p_ptt, 148fe56b9e6SYuval Mintz SECTION_OFFSIZE_ADDR(p_info->public_base, 149fe56b9e6SYuval Mintz PUBLIC_MFW_MB)); 150fe56b9e6SYuval Mintz p_info->mfw_mb_addr = SECTION_ADDR(mfw_mb_offsize, mcp_pf_id); 151fe56b9e6SYuval Mintz p_info->mfw_mb_length = (u16)qed_rd(p_hwfn, p_ptt, p_info->mfw_mb_addr); 152fe56b9e6SYuval Mintz 153fe56b9e6SYuval Mintz /* Get the current driver mailbox sequence before sending 154fe56b9e6SYuval Mintz * the first command 155fe56b9e6SYuval Mintz */ 156fe56b9e6SYuval Mintz p_info->drv_mb_seq = DRV_MB_RD(p_hwfn, p_ptt, drv_mb_header) & 157fe56b9e6SYuval Mintz DRV_MSG_SEQ_NUMBER_MASK; 158fe56b9e6SYuval Mintz 159fe56b9e6SYuval Mintz /* Get current FW pulse sequence */ 160fe56b9e6SYuval Mintz p_info->drv_pulse_seq = DRV_MB_RD(p_hwfn, p_ptt, drv_pulse_mb) & 161fe56b9e6SYuval Mintz DRV_PULSE_SEQ_MASK; 162fe56b9e6SYuval Mintz 163fe56b9e6SYuval Mintz p_info->mcp_hist = (u16)qed_rd(p_hwfn, p_ptt, MISCS_REG_GENERIC_POR_0); 164fe56b9e6SYuval Mintz 165fe56b9e6SYuval Mintz return 0; 166fe56b9e6SYuval Mintz } 167fe56b9e6SYuval Mintz 1681a635e48SYuval Mintz int qed_mcp_cmd_init(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 169fe56b9e6SYuval Mintz { 170fe56b9e6SYuval Mintz struct qed_mcp_info *p_info; 171fe56b9e6SYuval Mintz u32 size; 172fe56b9e6SYuval Mintz 173fe56b9e6SYuval Mintz /* Allocate mcp_info structure */ 17460fffb3bSYuval Mintz p_hwfn->mcp_info = kzalloc(sizeof(*p_hwfn->mcp_info), GFP_KERNEL); 175fe56b9e6SYuval Mintz if (!p_hwfn->mcp_info) 176fe56b9e6SYuval Mintz goto err; 177fe56b9e6SYuval Mintz p_info = p_hwfn->mcp_info; 178fe56b9e6SYuval Mintz 179fe56b9e6SYuval Mintz if (qed_load_mcp_offsets(p_hwfn, p_ptt) != 0) { 180fe56b9e6SYuval Mintz DP_NOTICE(p_hwfn, "MCP is not initialized\n"); 181fe56b9e6SYuval Mintz /* Do not free mcp_info here, since public_base indicate that 182fe56b9e6SYuval Mintz * the MCP is not initialized 183fe56b9e6SYuval Mintz */ 184fe56b9e6SYuval Mintz return 0; 185fe56b9e6SYuval Mintz } 186fe56b9e6SYuval Mintz 187fe56b9e6SYuval Mintz size = MFW_DRV_MSG_MAX_DWORDS(p_info->mfw_mb_length) * sizeof(u32); 18860fffb3bSYuval Mintz p_info->mfw_mb_cur = kzalloc(size, GFP_KERNEL); 18983aeb933SYuval Mintz p_info->mfw_mb_shadow = kzalloc(size, GFP_KERNEL); 190fe56b9e6SYuval Mintz if (!p_info->mfw_mb_shadow || !p_info->mfw_mb_addr) 191fe56b9e6SYuval Mintz goto err; 192fe56b9e6SYuval Mintz 1935529bad9STomer Tayar /* Initialize the MFW spinlock */ 1945529bad9STomer Tayar spin_lock_init(&p_info->lock); 195fe56b9e6SYuval Mintz 196fe56b9e6SYuval Mintz return 0; 197fe56b9e6SYuval Mintz 198fe56b9e6SYuval Mintz err: 199fe56b9e6SYuval Mintz qed_mcp_free(p_hwfn); 200fe56b9e6SYuval Mintz return -ENOMEM; 201fe56b9e6SYuval Mintz } 202fe56b9e6SYuval Mintz 2035529bad9STomer Tayar /* Locks the MFW mailbox of a PF to ensure a single access. 2045529bad9STomer Tayar * The lock is achieved in most cases by holding a spinlock, causing other 2055529bad9STomer Tayar * threads to wait till a previous access is done. 2065529bad9STomer Tayar * In some cases (currently when a [UN]LOAD_REQ commands are sent), the single 2075529bad9STomer Tayar * access is achieved by setting a blocking flag, which will fail other 2085529bad9STomer Tayar * competing contexts to send their mailboxes. 2095529bad9STomer Tayar */ 2101a635e48SYuval Mintz static int qed_mcp_mb_lock(struct qed_hwfn *p_hwfn, u32 cmd) 2115529bad9STomer Tayar { 2125529bad9STomer Tayar spin_lock_bh(&p_hwfn->mcp_info->lock); 2135529bad9STomer Tayar 2145529bad9STomer Tayar /* The spinlock shouldn't be acquired when the mailbox command is 2155529bad9STomer Tayar * [UN]LOAD_REQ, since the engine is locked by the MFW, and a parallel 2165529bad9STomer Tayar * pending [UN]LOAD_REQ command of another PF together with a spinlock 2175529bad9STomer Tayar * (i.e. interrupts are disabled) - can lead to a deadlock. 2185529bad9STomer Tayar * It is assumed that for a single PF, no other mailbox commands can be 2195529bad9STomer Tayar * sent from another context while sending LOAD_REQ, and that any 2205529bad9STomer Tayar * parallel commands to UNLOAD_REQ can be cancelled. 2215529bad9STomer Tayar */ 2225529bad9STomer Tayar if (cmd == DRV_MSG_CODE_LOAD_DONE || cmd == DRV_MSG_CODE_UNLOAD_DONE) 2235529bad9STomer Tayar p_hwfn->mcp_info->block_mb_sending = false; 2245529bad9STomer Tayar 2255529bad9STomer Tayar if (p_hwfn->mcp_info->block_mb_sending) { 2265529bad9STomer Tayar DP_NOTICE(p_hwfn, 2275529bad9STomer Tayar "Trying to send a MFW mailbox command [0x%x] in parallel to [UN]LOAD_REQ. Aborting.\n", 2285529bad9STomer Tayar cmd); 2295529bad9STomer Tayar spin_unlock_bh(&p_hwfn->mcp_info->lock); 2305529bad9STomer Tayar return -EBUSY; 2315529bad9STomer Tayar } 2325529bad9STomer Tayar 2335529bad9STomer Tayar if (cmd == DRV_MSG_CODE_LOAD_REQ || cmd == DRV_MSG_CODE_UNLOAD_REQ) { 2345529bad9STomer Tayar p_hwfn->mcp_info->block_mb_sending = true; 2355529bad9STomer Tayar spin_unlock_bh(&p_hwfn->mcp_info->lock); 2365529bad9STomer Tayar } 2375529bad9STomer Tayar 2385529bad9STomer Tayar return 0; 2395529bad9STomer Tayar } 2405529bad9STomer Tayar 2411a635e48SYuval Mintz static void qed_mcp_mb_unlock(struct qed_hwfn *p_hwfn, u32 cmd) 2425529bad9STomer Tayar { 2435529bad9STomer Tayar if (cmd != DRV_MSG_CODE_LOAD_REQ && cmd != DRV_MSG_CODE_UNLOAD_REQ) 2445529bad9STomer Tayar spin_unlock_bh(&p_hwfn->mcp_info->lock); 2455529bad9STomer Tayar } 2465529bad9STomer Tayar 2471a635e48SYuval Mintz int qed_mcp_reset(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 248fe56b9e6SYuval Mintz { 249fe56b9e6SYuval Mintz u32 seq = ++p_hwfn->mcp_info->drv_mb_seq; 250fe56b9e6SYuval Mintz u8 delay = CHIP_MCP_RESP_ITER_US; 251fe56b9e6SYuval Mintz u32 org_mcp_reset_seq, cnt = 0; 252fe56b9e6SYuval Mintz int rc = 0; 253fe56b9e6SYuval Mintz 2545529bad9STomer Tayar /* Ensure that only a single thread is accessing the mailbox at a 2555529bad9STomer Tayar * certain time. 2565529bad9STomer Tayar */ 2575529bad9STomer Tayar rc = qed_mcp_mb_lock(p_hwfn, DRV_MSG_CODE_MCP_RESET); 2585529bad9STomer Tayar if (rc != 0) 2595529bad9STomer Tayar return rc; 2605529bad9STomer Tayar 261fe56b9e6SYuval Mintz /* Set drv command along with the updated sequence */ 262fe56b9e6SYuval Mintz org_mcp_reset_seq = qed_rd(p_hwfn, p_ptt, MISCS_REG_GENERIC_POR_0); 263fe56b9e6SYuval Mintz DRV_MB_WR(p_hwfn, p_ptt, drv_mb_header, 264fe56b9e6SYuval Mintz (DRV_MSG_CODE_MCP_RESET | seq)); 265fe56b9e6SYuval Mintz 266fe56b9e6SYuval Mintz do { 267fe56b9e6SYuval Mintz /* Wait for MFW response */ 268fe56b9e6SYuval Mintz udelay(delay); 269fe56b9e6SYuval Mintz /* Give the FW up to 500 second (50*1000*10usec) */ 270fe56b9e6SYuval Mintz } while ((org_mcp_reset_seq == qed_rd(p_hwfn, p_ptt, 271fe56b9e6SYuval Mintz MISCS_REG_GENERIC_POR_0)) && 272fe56b9e6SYuval Mintz (cnt++ < QED_MCP_RESET_RETRIES)); 273fe56b9e6SYuval Mintz 274fe56b9e6SYuval Mintz if (org_mcp_reset_seq != 275fe56b9e6SYuval Mintz qed_rd(p_hwfn, p_ptt, MISCS_REG_GENERIC_POR_0)) { 276fe56b9e6SYuval Mintz DP_VERBOSE(p_hwfn, QED_MSG_SP, 277fe56b9e6SYuval Mintz "MCP was reset after %d usec\n", cnt * delay); 278fe56b9e6SYuval Mintz } else { 279fe56b9e6SYuval Mintz DP_ERR(p_hwfn, "Failed to reset MCP\n"); 280fe56b9e6SYuval Mintz rc = -EAGAIN; 281fe56b9e6SYuval Mintz } 282fe56b9e6SYuval Mintz 2835529bad9STomer Tayar qed_mcp_mb_unlock(p_hwfn, DRV_MSG_CODE_MCP_RESET); 2845529bad9STomer Tayar 285fe56b9e6SYuval Mintz return rc; 286fe56b9e6SYuval Mintz } 287fe56b9e6SYuval Mintz 288fe56b9e6SYuval Mintz static int qed_do_mcp_cmd(struct qed_hwfn *p_hwfn, 289fe56b9e6SYuval Mintz struct qed_ptt *p_ptt, 290fe56b9e6SYuval Mintz u32 cmd, 291fe56b9e6SYuval Mintz u32 param, 292fe56b9e6SYuval Mintz u32 *o_mcp_resp, 293fe56b9e6SYuval Mintz u32 *o_mcp_param) 294fe56b9e6SYuval Mintz { 295fe56b9e6SYuval Mintz u8 delay = CHIP_MCP_RESP_ITER_US; 296fe56b9e6SYuval Mintz u32 seq, cnt = 1, actual_mb_seq; 297fe56b9e6SYuval Mintz int rc = 0; 298fe56b9e6SYuval Mintz 299fe56b9e6SYuval Mintz /* Get actual driver mailbox sequence */ 300fe56b9e6SYuval Mintz actual_mb_seq = DRV_MB_RD(p_hwfn, p_ptt, drv_mb_header) & 301fe56b9e6SYuval Mintz DRV_MSG_SEQ_NUMBER_MASK; 302fe56b9e6SYuval Mintz 303fe56b9e6SYuval Mintz /* Use MCP history register to check if MCP reset occurred between 304fe56b9e6SYuval Mintz * init time and now. 305fe56b9e6SYuval Mintz */ 306fe56b9e6SYuval Mintz if (p_hwfn->mcp_info->mcp_hist != 307fe56b9e6SYuval Mintz qed_rd(p_hwfn, p_ptt, MISCS_REG_GENERIC_POR_0)) { 308fe56b9e6SYuval Mintz DP_VERBOSE(p_hwfn, QED_MSG_SP, "Rereading MCP offsets\n"); 309fe56b9e6SYuval Mintz qed_load_mcp_offsets(p_hwfn, p_ptt); 310fe56b9e6SYuval Mintz qed_mcp_cmd_port_init(p_hwfn, p_ptt); 311fe56b9e6SYuval Mintz } 312fe56b9e6SYuval Mintz seq = ++p_hwfn->mcp_info->drv_mb_seq; 313fe56b9e6SYuval Mintz 314fe56b9e6SYuval Mintz /* Set drv param */ 315fe56b9e6SYuval Mintz DRV_MB_WR(p_hwfn, p_ptt, drv_mb_param, param); 316fe56b9e6SYuval Mintz 317fe56b9e6SYuval Mintz /* Set drv command along with the updated sequence */ 318fe56b9e6SYuval Mintz DRV_MB_WR(p_hwfn, p_ptt, drv_mb_header, (cmd | seq)); 319fe56b9e6SYuval Mintz 320fe56b9e6SYuval Mintz DP_VERBOSE(p_hwfn, QED_MSG_SP, 321fe56b9e6SYuval Mintz "wrote command (%x) to MFW MB param 0x%08x\n", 322fe56b9e6SYuval Mintz (cmd | seq), param); 323fe56b9e6SYuval Mintz 324fe56b9e6SYuval Mintz do { 325fe56b9e6SYuval Mintz /* Wait for MFW response */ 326fe56b9e6SYuval Mintz udelay(delay); 327fe56b9e6SYuval Mintz *o_mcp_resp = DRV_MB_RD(p_hwfn, p_ptt, fw_mb_header); 328fe56b9e6SYuval Mintz 329fe56b9e6SYuval Mintz /* Give the FW up to 5 second (500*10ms) */ 330fe56b9e6SYuval Mintz } while ((seq != (*o_mcp_resp & FW_MSG_SEQ_NUMBER_MASK)) && 331fe56b9e6SYuval Mintz (cnt++ < QED_DRV_MB_MAX_RETRIES)); 332fe56b9e6SYuval Mintz 333fe56b9e6SYuval Mintz DP_VERBOSE(p_hwfn, QED_MSG_SP, 334fe56b9e6SYuval Mintz "[after %d ms] read (%x) seq is (%x) from FW MB\n", 335fe56b9e6SYuval Mintz cnt * delay, *o_mcp_resp, seq); 336fe56b9e6SYuval Mintz 337fe56b9e6SYuval Mintz /* Is this a reply to our command? */ 338fe56b9e6SYuval Mintz if (seq == (*o_mcp_resp & FW_MSG_SEQ_NUMBER_MASK)) { 339fe56b9e6SYuval Mintz *o_mcp_resp &= FW_MSG_CODE_MASK; 340fe56b9e6SYuval Mintz /* Get the MCP param */ 341fe56b9e6SYuval Mintz *o_mcp_param = DRV_MB_RD(p_hwfn, p_ptt, fw_mb_param); 342fe56b9e6SYuval Mintz } else { 343fe56b9e6SYuval Mintz /* FW BUG! */ 344525ef5c0SYuval Mintz DP_ERR(p_hwfn, "MFW failed to respond [cmd 0x%x param 0x%x]\n", 345525ef5c0SYuval Mintz cmd, param); 346fe56b9e6SYuval Mintz *o_mcp_resp = 0; 347fe56b9e6SYuval Mintz rc = -EAGAIN; 348fe56b9e6SYuval Mintz } 349fe56b9e6SYuval Mintz return rc; 350fe56b9e6SYuval Mintz } 351fe56b9e6SYuval Mintz 3525529bad9STomer Tayar static int qed_mcp_cmd_and_union(struct qed_hwfn *p_hwfn, 353fe56b9e6SYuval Mintz struct qed_ptt *p_ptt, 3545529bad9STomer Tayar struct qed_mcp_mb_params *p_mb_params) 355fe56b9e6SYuval Mintz { 3565529bad9STomer Tayar u32 union_data_addr; 35714d39648SMintz, Yuval 3585529bad9STomer Tayar int rc; 359fe56b9e6SYuval Mintz 360fe56b9e6SYuval Mintz /* MCP not initialized */ 361fe56b9e6SYuval Mintz if (!qed_mcp_is_init(p_hwfn)) { 362fe56b9e6SYuval Mintz DP_NOTICE(p_hwfn, "MFW is not initialized!\n"); 363fe56b9e6SYuval Mintz return -EBUSY; 364fe56b9e6SYuval Mintz } 365fe56b9e6SYuval Mintz 3665529bad9STomer Tayar union_data_addr = p_hwfn->mcp_info->drv_mb_addr + 3675529bad9STomer Tayar offsetof(struct public_drv_mb, union_data); 3685529bad9STomer Tayar 3695529bad9STomer Tayar /* Ensure that only a single thread is accessing the mailbox at a 3705529bad9STomer Tayar * certain time. 371fe56b9e6SYuval Mintz */ 3725529bad9STomer Tayar rc = qed_mcp_mb_lock(p_hwfn, p_mb_params->cmd); 3735529bad9STomer Tayar if (rc) 3745529bad9STomer Tayar return rc; 3755529bad9STomer Tayar 3765529bad9STomer Tayar if (p_mb_params->p_data_src != NULL) 3775529bad9STomer Tayar qed_memcpy_to(p_hwfn, p_ptt, union_data_addr, 3785529bad9STomer Tayar p_mb_params->p_data_src, 3795529bad9STomer Tayar sizeof(*p_mb_params->p_data_src)); 3805529bad9STomer Tayar 3815529bad9STomer Tayar rc = qed_do_mcp_cmd(p_hwfn, p_ptt, p_mb_params->cmd, 3825529bad9STomer Tayar p_mb_params->param, &p_mb_params->mcp_resp, 3835529bad9STomer Tayar &p_mb_params->mcp_param); 3845529bad9STomer Tayar 3855529bad9STomer Tayar if (p_mb_params->p_data_dst != NULL) 3865529bad9STomer Tayar qed_memcpy_from(p_hwfn, p_ptt, p_mb_params->p_data_dst, 3875529bad9STomer Tayar union_data_addr, 3885529bad9STomer Tayar sizeof(*p_mb_params->p_data_dst)); 3895529bad9STomer Tayar 3905529bad9STomer Tayar qed_mcp_mb_unlock(p_hwfn, p_mb_params->cmd); 391fe56b9e6SYuval Mintz 392fe56b9e6SYuval Mintz return rc; 393fe56b9e6SYuval Mintz } 394fe56b9e6SYuval Mintz 3955529bad9STomer Tayar int qed_mcp_cmd(struct qed_hwfn *p_hwfn, 3965529bad9STomer Tayar struct qed_ptt *p_ptt, 3975529bad9STomer Tayar u32 cmd, 3985529bad9STomer Tayar u32 param, 3995529bad9STomer Tayar u32 *o_mcp_resp, 4005529bad9STomer Tayar u32 *o_mcp_param) 401fe56b9e6SYuval Mintz { 4025529bad9STomer Tayar struct qed_mcp_mb_params mb_params; 40314d39648SMintz, Yuval union drv_union_data data_src; 4045529bad9STomer Tayar int rc; 405fe56b9e6SYuval Mintz 4065529bad9STomer Tayar memset(&mb_params, 0, sizeof(mb_params)); 40714d39648SMintz, Yuval memset(&data_src, 0, sizeof(data_src)); 4085529bad9STomer Tayar mb_params.cmd = cmd; 4095529bad9STomer Tayar mb_params.param = param; 41014d39648SMintz, Yuval 41114d39648SMintz, Yuval /* In case of UNLOAD_DONE, set the primary MAC */ 41214d39648SMintz, Yuval if ((cmd == DRV_MSG_CODE_UNLOAD_DONE) && 41314d39648SMintz, Yuval (p_hwfn->cdev->wol_config == QED_OV_WOL_ENABLED)) { 41414d39648SMintz, Yuval u8 *p_mac = p_hwfn->cdev->wol_mac; 41514d39648SMintz, Yuval 41614d39648SMintz, Yuval data_src.wol_mac.mac_upper = p_mac[0] << 8 | p_mac[1]; 41714d39648SMintz, Yuval data_src.wol_mac.mac_lower = p_mac[2] << 24 | p_mac[3] << 16 | 41814d39648SMintz, Yuval p_mac[4] << 8 | p_mac[5]; 41914d39648SMintz, Yuval 42014d39648SMintz, Yuval DP_VERBOSE(p_hwfn, 42114d39648SMintz, Yuval (QED_MSG_SP | NETIF_MSG_IFDOWN), 42214d39648SMintz, Yuval "Setting WoL MAC: %pM --> [%08x,%08x]\n", 42314d39648SMintz, Yuval p_mac, data_src.wol_mac.mac_upper, 42414d39648SMintz, Yuval data_src.wol_mac.mac_lower); 42514d39648SMintz, Yuval 42614d39648SMintz, Yuval mb_params.p_data_src = &data_src; 42714d39648SMintz, Yuval } 42814d39648SMintz, Yuval 4295529bad9STomer Tayar rc = qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 4305529bad9STomer Tayar if (rc) 4315529bad9STomer Tayar return rc; 4325529bad9STomer Tayar 4335529bad9STomer Tayar *o_mcp_resp = mb_params.mcp_resp; 4345529bad9STomer Tayar *o_mcp_param = mb_params.mcp_param; 4355529bad9STomer Tayar 4365529bad9STomer Tayar return 0; 437fe56b9e6SYuval Mintz } 438fe56b9e6SYuval Mintz 4394102426fSTomer Tayar int qed_mcp_nvm_rd_cmd(struct qed_hwfn *p_hwfn, 4404102426fSTomer Tayar struct qed_ptt *p_ptt, 4414102426fSTomer Tayar u32 cmd, 4424102426fSTomer Tayar u32 param, 4434102426fSTomer Tayar u32 *o_mcp_resp, 4444102426fSTomer Tayar u32 *o_mcp_param, u32 *o_txn_size, u32 *o_buf) 4454102426fSTomer Tayar { 4464102426fSTomer Tayar struct qed_mcp_mb_params mb_params; 4474102426fSTomer Tayar union drv_union_data union_data; 4484102426fSTomer Tayar int rc; 4494102426fSTomer Tayar 4504102426fSTomer Tayar memset(&mb_params, 0, sizeof(mb_params)); 4514102426fSTomer Tayar mb_params.cmd = cmd; 4524102426fSTomer Tayar mb_params.param = param; 4534102426fSTomer Tayar mb_params.p_data_dst = &union_data; 4544102426fSTomer Tayar rc = qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 4554102426fSTomer Tayar if (rc) 4564102426fSTomer Tayar return rc; 4574102426fSTomer Tayar 4584102426fSTomer Tayar *o_mcp_resp = mb_params.mcp_resp; 4594102426fSTomer Tayar *o_mcp_param = mb_params.mcp_param; 4604102426fSTomer Tayar 4614102426fSTomer Tayar *o_txn_size = *o_mcp_param; 4624102426fSTomer Tayar memcpy(o_buf, &union_data.raw_data, *o_txn_size); 4634102426fSTomer Tayar 4644102426fSTomer Tayar return 0; 4654102426fSTomer Tayar } 4664102426fSTomer Tayar 467fe56b9e6SYuval Mintz int qed_mcp_load_req(struct qed_hwfn *p_hwfn, 4681a635e48SYuval Mintz struct qed_ptt *p_ptt, u32 *p_load_code) 469fe56b9e6SYuval Mintz { 470fe56b9e6SYuval Mintz struct qed_dev *cdev = p_hwfn->cdev; 4715529bad9STomer Tayar struct qed_mcp_mb_params mb_params; 4725529bad9STomer Tayar union drv_union_data union_data; 473fe56b9e6SYuval Mintz int rc; 474fe56b9e6SYuval Mintz 4755529bad9STomer Tayar memset(&mb_params, 0, sizeof(mb_params)); 476fe56b9e6SYuval Mintz /* Load Request */ 4775529bad9STomer Tayar mb_params.cmd = DRV_MSG_CODE_LOAD_REQ; 4785529bad9STomer Tayar mb_params.param = PDA_COMP | DRV_ID_MCP_HSI_VER_CURRENT | 4795529bad9STomer Tayar cdev->drv_type; 4805529bad9STomer Tayar memcpy(&union_data.ver_str, cdev->ver_str, MCP_DRV_VER_STR_SIZE); 4815529bad9STomer Tayar mb_params.p_data_src = &union_data; 4825529bad9STomer Tayar rc = qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 483fe56b9e6SYuval Mintz 484fe56b9e6SYuval Mintz /* if mcp fails to respond we must abort */ 485fe56b9e6SYuval Mintz if (rc) { 486fe56b9e6SYuval Mintz DP_ERR(p_hwfn, "MCP response failure, aborting\n"); 487fe56b9e6SYuval Mintz return rc; 488fe56b9e6SYuval Mintz } 489fe56b9e6SYuval Mintz 4905529bad9STomer Tayar *p_load_code = mb_params.mcp_resp; 4915529bad9STomer Tayar 492fe56b9e6SYuval Mintz /* If MFW refused (e.g. other port is in diagnostic mode) we 493fe56b9e6SYuval Mintz * must abort. This can happen in the following cases: 494fe56b9e6SYuval Mintz * - Other port is in diagnostic mode 495fe56b9e6SYuval Mintz * - Previously loaded function on the engine is not compliant with 496fe56b9e6SYuval Mintz * the requester. 497fe56b9e6SYuval Mintz * - MFW cannot cope with the requester's DRV_MFW_HSI_VERSION. 498fe56b9e6SYuval Mintz * - 499fe56b9e6SYuval Mintz */ 500fe56b9e6SYuval Mintz if (!(*p_load_code) || 501fe56b9e6SYuval Mintz ((*p_load_code) == FW_MSG_CODE_DRV_LOAD_REFUSED_HSI) || 502fe56b9e6SYuval Mintz ((*p_load_code) == FW_MSG_CODE_DRV_LOAD_REFUSED_PDA) || 503fe56b9e6SYuval Mintz ((*p_load_code) == FW_MSG_CODE_DRV_LOAD_REFUSED_DIAG)) { 504fe56b9e6SYuval Mintz DP_ERR(p_hwfn, "MCP refused load request, aborting\n"); 505fe56b9e6SYuval Mintz return -EBUSY; 506fe56b9e6SYuval Mintz } 507fe56b9e6SYuval Mintz 508fe56b9e6SYuval Mintz return 0; 509fe56b9e6SYuval Mintz } 510fe56b9e6SYuval Mintz 5110b55e27dSYuval Mintz static void qed_mcp_handle_vf_flr(struct qed_hwfn *p_hwfn, 5120b55e27dSYuval Mintz struct qed_ptt *p_ptt) 5130b55e27dSYuval Mintz { 5140b55e27dSYuval Mintz u32 addr = SECTION_OFFSIZE_ADDR(p_hwfn->mcp_info->public_base, 5150b55e27dSYuval Mintz PUBLIC_PATH); 5160b55e27dSYuval Mintz u32 mfw_path_offsize = qed_rd(p_hwfn, p_ptt, addr); 5170b55e27dSYuval Mintz u32 path_addr = SECTION_ADDR(mfw_path_offsize, 5180b55e27dSYuval Mintz QED_PATH_ID(p_hwfn)); 5190b55e27dSYuval Mintz u32 disabled_vfs[VF_MAX_STATIC / 32]; 5200b55e27dSYuval Mintz int i; 5210b55e27dSYuval Mintz 5220b55e27dSYuval Mintz DP_VERBOSE(p_hwfn, 5230b55e27dSYuval Mintz QED_MSG_SP, 5240b55e27dSYuval Mintz "Reading Disabled VF information from [offset %08x], path_addr %08x\n", 5250b55e27dSYuval Mintz mfw_path_offsize, path_addr); 5260b55e27dSYuval Mintz 5270b55e27dSYuval Mintz for (i = 0; i < (VF_MAX_STATIC / 32); i++) { 5280b55e27dSYuval Mintz disabled_vfs[i] = qed_rd(p_hwfn, p_ptt, 5290b55e27dSYuval Mintz path_addr + 5300b55e27dSYuval Mintz offsetof(struct public_path, 5310b55e27dSYuval Mintz mcp_vf_disabled) + 5320b55e27dSYuval Mintz sizeof(u32) * i); 5330b55e27dSYuval Mintz DP_VERBOSE(p_hwfn, (QED_MSG_SP | QED_MSG_IOV), 5340b55e27dSYuval Mintz "FLR-ed VFs [%08x,...,%08x] - %08x\n", 5350b55e27dSYuval Mintz i * 32, (i + 1) * 32 - 1, disabled_vfs[i]); 5360b55e27dSYuval Mintz } 5370b55e27dSYuval Mintz 5380b55e27dSYuval Mintz if (qed_iov_mark_vf_flr(p_hwfn, disabled_vfs)) 5390b55e27dSYuval Mintz qed_schedule_iov(p_hwfn, QED_IOV_WQ_FLR_FLAG); 5400b55e27dSYuval Mintz } 5410b55e27dSYuval Mintz 5420b55e27dSYuval Mintz int qed_mcp_ack_vf_flr(struct qed_hwfn *p_hwfn, 5430b55e27dSYuval Mintz struct qed_ptt *p_ptt, u32 *vfs_to_ack) 5440b55e27dSYuval Mintz { 5450b55e27dSYuval Mintz u32 addr = SECTION_OFFSIZE_ADDR(p_hwfn->mcp_info->public_base, 5460b55e27dSYuval Mintz PUBLIC_FUNC); 5470b55e27dSYuval Mintz u32 mfw_func_offsize = qed_rd(p_hwfn, p_ptt, addr); 5480b55e27dSYuval Mintz u32 func_addr = SECTION_ADDR(mfw_func_offsize, 5490b55e27dSYuval Mintz MCP_PF_ID(p_hwfn)); 5500b55e27dSYuval Mintz struct qed_mcp_mb_params mb_params; 5510b55e27dSYuval Mintz union drv_union_data union_data; 5520b55e27dSYuval Mintz int rc; 5530b55e27dSYuval Mintz int i; 5540b55e27dSYuval Mintz 5550b55e27dSYuval Mintz for (i = 0; i < (VF_MAX_STATIC / 32); i++) 5560b55e27dSYuval Mintz DP_VERBOSE(p_hwfn, (QED_MSG_SP | QED_MSG_IOV), 5570b55e27dSYuval Mintz "Acking VFs [%08x,...,%08x] - %08x\n", 5580b55e27dSYuval Mintz i * 32, (i + 1) * 32 - 1, vfs_to_ack[i]); 5590b55e27dSYuval Mintz 5600b55e27dSYuval Mintz memset(&mb_params, 0, sizeof(mb_params)); 5610b55e27dSYuval Mintz mb_params.cmd = DRV_MSG_CODE_VF_DISABLED_DONE; 5620b55e27dSYuval Mintz memcpy(&union_data.ack_vf_disabled, vfs_to_ack, VF_MAX_STATIC / 8); 5630b55e27dSYuval Mintz mb_params.p_data_src = &union_data; 5640b55e27dSYuval Mintz rc = qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 5650b55e27dSYuval Mintz if (rc) { 5660b55e27dSYuval Mintz DP_NOTICE(p_hwfn, "Failed to pass ACK for VF flr to MFW\n"); 5670b55e27dSYuval Mintz return -EBUSY; 5680b55e27dSYuval Mintz } 5690b55e27dSYuval Mintz 5700b55e27dSYuval Mintz /* Clear the ACK bits */ 5710b55e27dSYuval Mintz for (i = 0; i < (VF_MAX_STATIC / 32); i++) 5720b55e27dSYuval Mintz qed_wr(p_hwfn, p_ptt, 5730b55e27dSYuval Mintz func_addr + 5740b55e27dSYuval Mintz offsetof(struct public_func, drv_ack_vf_disabled) + 5750b55e27dSYuval Mintz i * sizeof(u32), 0); 5760b55e27dSYuval Mintz 5770b55e27dSYuval Mintz return rc; 5780b55e27dSYuval Mintz } 5790b55e27dSYuval Mintz 580334c03b5SZvi Nachmani static void qed_mcp_handle_transceiver_change(struct qed_hwfn *p_hwfn, 581334c03b5SZvi Nachmani struct qed_ptt *p_ptt) 582334c03b5SZvi Nachmani { 583334c03b5SZvi Nachmani u32 transceiver_state; 584334c03b5SZvi Nachmani 585334c03b5SZvi Nachmani transceiver_state = qed_rd(p_hwfn, p_ptt, 586334c03b5SZvi Nachmani p_hwfn->mcp_info->port_addr + 587334c03b5SZvi Nachmani offsetof(struct public_port, 588334c03b5SZvi Nachmani transceiver_data)); 589334c03b5SZvi Nachmani 590334c03b5SZvi Nachmani DP_VERBOSE(p_hwfn, 591334c03b5SZvi Nachmani (NETIF_MSG_HW | QED_MSG_SP), 592334c03b5SZvi Nachmani "Received transceiver state update [0x%08x] from mfw [Addr 0x%x]\n", 593334c03b5SZvi Nachmani transceiver_state, 594334c03b5SZvi Nachmani (u32)(p_hwfn->mcp_info->port_addr + 5951a635e48SYuval Mintz offsetof(struct public_port, transceiver_data))); 596334c03b5SZvi Nachmani 597334c03b5SZvi Nachmani transceiver_state = GET_FIELD(transceiver_state, 598351a4dedSYuval Mintz ETH_TRANSCEIVER_STATE); 599334c03b5SZvi Nachmani 600351a4dedSYuval Mintz if (transceiver_state == ETH_TRANSCEIVER_STATE_PRESENT) 601334c03b5SZvi Nachmani DP_NOTICE(p_hwfn, "Transceiver is present.\n"); 602334c03b5SZvi Nachmani else 603334c03b5SZvi Nachmani DP_NOTICE(p_hwfn, "Transceiver is unplugged.\n"); 604334c03b5SZvi Nachmani } 605334c03b5SZvi Nachmani 606cc875c2eSYuval Mintz static void qed_mcp_handle_link_change(struct qed_hwfn *p_hwfn, 6071a635e48SYuval Mintz struct qed_ptt *p_ptt, bool b_reset) 608cc875c2eSYuval Mintz { 609cc875c2eSYuval Mintz struct qed_mcp_link_state *p_link; 610a64b02d5SManish Chopra u8 max_bw, min_bw; 611cc875c2eSYuval Mintz u32 status = 0; 612cc875c2eSYuval Mintz 613cc875c2eSYuval Mintz p_link = &p_hwfn->mcp_info->link_output; 614cc875c2eSYuval Mintz memset(p_link, 0, sizeof(*p_link)); 615cc875c2eSYuval Mintz if (!b_reset) { 616cc875c2eSYuval Mintz status = qed_rd(p_hwfn, p_ptt, 617cc875c2eSYuval Mintz p_hwfn->mcp_info->port_addr + 618cc875c2eSYuval Mintz offsetof(struct public_port, link_status)); 619cc875c2eSYuval Mintz DP_VERBOSE(p_hwfn, (NETIF_MSG_LINK | QED_MSG_SP), 620cc875c2eSYuval Mintz "Received link update [0x%08x] from mfw [Addr 0x%x]\n", 621cc875c2eSYuval Mintz status, 622cc875c2eSYuval Mintz (u32)(p_hwfn->mcp_info->port_addr + 6231a635e48SYuval Mintz offsetof(struct public_port, link_status))); 624cc875c2eSYuval Mintz } else { 625cc875c2eSYuval Mintz DP_VERBOSE(p_hwfn, NETIF_MSG_LINK, 626cc875c2eSYuval Mintz "Resetting link indications\n"); 627cc875c2eSYuval Mintz return; 628cc875c2eSYuval Mintz } 629cc875c2eSYuval Mintz 630fc916ff2SSudarsana Reddy Kalluru if (p_hwfn->b_drv_link_init) 631cc875c2eSYuval Mintz p_link->link_up = !!(status & LINK_STATUS_LINK_UP); 632fc916ff2SSudarsana Reddy Kalluru else 633fc916ff2SSudarsana Reddy Kalluru p_link->link_up = false; 634cc875c2eSYuval Mintz 635cc875c2eSYuval Mintz p_link->full_duplex = true; 636cc875c2eSYuval Mintz switch ((status & LINK_STATUS_SPEED_AND_DUPLEX_MASK)) { 637cc875c2eSYuval Mintz case LINK_STATUS_SPEED_AND_DUPLEX_100G: 638cc875c2eSYuval Mintz p_link->speed = 100000; 639cc875c2eSYuval Mintz break; 640cc875c2eSYuval Mintz case LINK_STATUS_SPEED_AND_DUPLEX_50G: 641cc875c2eSYuval Mintz p_link->speed = 50000; 642cc875c2eSYuval Mintz break; 643cc875c2eSYuval Mintz case LINK_STATUS_SPEED_AND_DUPLEX_40G: 644cc875c2eSYuval Mintz p_link->speed = 40000; 645cc875c2eSYuval Mintz break; 646cc875c2eSYuval Mintz case LINK_STATUS_SPEED_AND_DUPLEX_25G: 647cc875c2eSYuval Mintz p_link->speed = 25000; 648cc875c2eSYuval Mintz break; 649cc875c2eSYuval Mintz case LINK_STATUS_SPEED_AND_DUPLEX_20G: 650cc875c2eSYuval Mintz p_link->speed = 20000; 651cc875c2eSYuval Mintz break; 652cc875c2eSYuval Mintz case LINK_STATUS_SPEED_AND_DUPLEX_10G: 653cc875c2eSYuval Mintz p_link->speed = 10000; 654cc875c2eSYuval Mintz break; 655cc875c2eSYuval Mintz case LINK_STATUS_SPEED_AND_DUPLEX_1000THD: 656cc875c2eSYuval Mintz p_link->full_duplex = false; 657cc875c2eSYuval Mintz /* Fall-through */ 658cc875c2eSYuval Mintz case LINK_STATUS_SPEED_AND_DUPLEX_1000TFD: 659cc875c2eSYuval Mintz p_link->speed = 1000; 660cc875c2eSYuval Mintz break; 661cc875c2eSYuval Mintz default: 662cc875c2eSYuval Mintz p_link->speed = 0; 663cc875c2eSYuval Mintz } 664cc875c2eSYuval Mintz 6654b01e519SManish Chopra if (p_link->link_up && p_link->speed) 6664b01e519SManish Chopra p_link->line_speed = p_link->speed; 6674b01e519SManish Chopra else 6684b01e519SManish Chopra p_link->line_speed = 0; 6694b01e519SManish Chopra 6704b01e519SManish Chopra max_bw = p_hwfn->mcp_info->func_info.bandwidth_max; 671a64b02d5SManish Chopra min_bw = p_hwfn->mcp_info->func_info.bandwidth_min; 6724b01e519SManish Chopra 673a64b02d5SManish Chopra /* Max bandwidth configuration */ 6744b01e519SManish Chopra __qed_configure_pf_max_bandwidth(p_hwfn, p_ptt, p_link, max_bw); 675cc875c2eSYuval Mintz 676a64b02d5SManish Chopra /* Min bandwidth configuration */ 677a64b02d5SManish Chopra __qed_configure_pf_min_bandwidth(p_hwfn, p_ptt, p_link, min_bw); 678a64b02d5SManish Chopra qed_configure_vp_wfq_on_link_change(p_hwfn->cdev, p_link->min_pf_rate); 679a64b02d5SManish Chopra 680cc875c2eSYuval Mintz p_link->an = !!(status & LINK_STATUS_AUTO_NEGOTIATE_ENABLED); 681cc875c2eSYuval Mintz p_link->an_complete = !!(status & 682cc875c2eSYuval Mintz LINK_STATUS_AUTO_NEGOTIATE_COMPLETE); 683cc875c2eSYuval Mintz p_link->parallel_detection = !!(status & 684cc875c2eSYuval Mintz LINK_STATUS_PARALLEL_DETECTION_USED); 685cc875c2eSYuval Mintz p_link->pfc_enabled = !!(status & LINK_STATUS_PFC_ENABLED); 686cc875c2eSYuval Mintz 687cc875c2eSYuval Mintz p_link->partner_adv_speed |= 688cc875c2eSYuval Mintz (status & LINK_STATUS_LINK_PARTNER_1000TFD_CAPABLE) ? 689cc875c2eSYuval Mintz QED_LINK_PARTNER_SPEED_1G_FD : 0; 690cc875c2eSYuval Mintz p_link->partner_adv_speed |= 691cc875c2eSYuval Mintz (status & LINK_STATUS_LINK_PARTNER_1000THD_CAPABLE) ? 692cc875c2eSYuval Mintz QED_LINK_PARTNER_SPEED_1G_HD : 0; 693cc875c2eSYuval Mintz p_link->partner_adv_speed |= 694cc875c2eSYuval Mintz (status & LINK_STATUS_LINK_PARTNER_10G_CAPABLE) ? 695cc875c2eSYuval Mintz QED_LINK_PARTNER_SPEED_10G : 0; 696cc875c2eSYuval Mintz p_link->partner_adv_speed |= 697cc875c2eSYuval Mintz (status & LINK_STATUS_LINK_PARTNER_20G_CAPABLE) ? 698cc875c2eSYuval Mintz QED_LINK_PARTNER_SPEED_20G : 0; 699cc875c2eSYuval Mintz p_link->partner_adv_speed |= 700054c67d1SSudarsana Reddy Kalluru (status & LINK_STATUS_LINK_PARTNER_25G_CAPABLE) ? 701054c67d1SSudarsana Reddy Kalluru QED_LINK_PARTNER_SPEED_25G : 0; 702054c67d1SSudarsana Reddy Kalluru p_link->partner_adv_speed |= 703cc875c2eSYuval Mintz (status & LINK_STATUS_LINK_PARTNER_40G_CAPABLE) ? 704cc875c2eSYuval Mintz QED_LINK_PARTNER_SPEED_40G : 0; 705cc875c2eSYuval Mintz p_link->partner_adv_speed |= 706cc875c2eSYuval Mintz (status & LINK_STATUS_LINK_PARTNER_50G_CAPABLE) ? 707cc875c2eSYuval Mintz QED_LINK_PARTNER_SPEED_50G : 0; 708cc875c2eSYuval Mintz p_link->partner_adv_speed |= 709cc875c2eSYuval Mintz (status & LINK_STATUS_LINK_PARTNER_100G_CAPABLE) ? 710cc875c2eSYuval Mintz QED_LINK_PARTNER_SPEED_100G : 0; 711cc875c2eSYuval Mintz 712cc875c2eSYuval Mintz p_link->partner_tx_flow_ctrl_en = 713cc875c2eSYuval Mintz !!(status & LINK_STATUS_TX_FLOW_CONTROL_ENABLED); 714cc875c2eSYuval Mintz p_link->partner_rx_flow_ctrl_en = 715cc875c2eSYuval Mintz !!(status & LINK_STATUS_RX_FLOW_CONTROL_ENABLED); 716cc875c2eSYuval Mintz 717cc875c2eSYuval Mintz switch (status & LINK_STATUS_LINK_PARTNER_FLOW_CONTROL_MASK) { 718cc875c2eSYuval Mintz case LINK_STATUS_LINK_PARTNER_SYMMETRIC_PAUSE: 719cc875c2eSYuval Mintz p_link->partner_adv_pause = QED_LINK_PARTNER_SYMMETRIC_PAUSE; 720cc875c2eSYuval Mintz break; 721cc875c2eSYuval Mintz case LINK_STATUS_LINK_PARTNER_ASYMMETRIC_PAUSE: 722cc875c2eSYuval Mintz p_link->partner_adv_pause = QED_LINK_PARTNER_ASYMMETRIC_PAUSE; 723cc875c2eSYuval Mintz break; 724cc875c2eSYuval Mintz case LINK_STATUS_LINK_PARTNER_BOTH_PAUSE: 725cc875c2eSYuval Mintz p_link->partner_adv_pause = QED_LINK_PARTNER_BOTH_PAUSE; 726cc875c2eSYuval Mintz break; 727cc875c2eSYuval Mintz default: 728cc875c2eSYuval Mintz p_link->partner_adv_pause = 0; 729cc875c2eSYuval Mintz } 730cc875c2eSYuval Mintz 731cc875c2eSYuval Mintz p_link->sfp_tx_fault = !!(status & LINK_STATUS_SFP_TX_FAULT); 732cc875c2eSYuval Mintz 733cc875c2eSYuval Mintz qed_link_update(p_hwfn); 734cc875c2eSYuval Mintz } 735cc875c2eSYuval Mintz 736351a4dedSYuval Mintz int qed_mcp_set_link(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, bool b_up) 737cc875c2eSYuval Mintz { 738cc875c2eSYuval Mintz struct qed_mcp_link_params *params = &p_hwfn->mcp_info->link_input; 7395529bad9STomer Tayar struct qed_mcp_mb_params mb_params; 7405529bad9STomer Tayar union drv_union_data union_data; 741351a4dedSYuval Mintz struct eth_phy_cfg *phy_cfg; 742cc875c2eSYuval Mintz int rc = 0; 7435529bad9STomer Tayar u32 cmd; 744cc875c2eSYuval Mintz 745cc875c2eSYuval Mintz /* Set the shmem configuration according to params */ 7465529bad9STomer Tayar phy_cfg = &union_data.drv_phy_cfg; 7475529bad9STomer Tayar memset(phy_cfg, 0, sizeof(*phy_cfg)); 748cc875c2eSYuval Mintz cmd = b_up ? DRV_MSG_CODE_INIT_PHY : DRV_MSG_CODE_LINK_RESET; 749cc875c2eSYuval Mintz if (!params->speed.autoneg) 7505529bad9STomer Tayar phy_cfg->speed = params->speed.forced_speed; 751351a4dedSYuval Mintz phy_cfg->pause |= (params->pause.autoneg) ? ETH_PAUSE_AUTONEG : 0; 752351a4dedSYuval Mintz phy_cfg->pause |= (params->pause.forced_rx) ? ETH_PAUSE_RX : 0; 753351a4dedSYuval Mintz phy_cfg->pause |= (params->pause.forced_tx) ? ETH_PAUSE_TX : 0; 7545529bad9STomer Tayar phy_cfg->adv_speed = params->speed.advertised_speeds; 7555529bad9STomer Tayar phy_cfg->loopback_mode = params->loopback_mode; 756cc875c2eSYuval Mintz 757fc916ff2SSudarsana Reddy Kalluru p_hwfn->b_drv_link_init = b_up; 758fc916ff2SSudarsana Reddy Kalluru 759cc875c2eSYuval Mintz if (b_up) { 760cc875c2eSYuval Mintz DP_VERBOSE(p_hwfn, NETIF_MSG_LINK, 761cc875c2eSYuval Mintz "Configuring Link: Speed 0x%08x, Pause 0x%08x, adv_speed 0x%08x, loopback 0x%08x, features 0x%08x\n", 7625529bad9STomer Tayar phy_cfg->speed, 7635529bad9STomer Tayar phy_cfg->pause, 7645529bad9STomer Tayar phy_cfg->adv_speed, 7655529bad9STomer Tayar phy_cfg->loopback_mode, 7665529bad9STomer Tayar phy_cfg->feature_config_flags); 767cc875c2eSYuval Mintz } else { 768cc875c2eSYuval Mintz DP_VERBOSE(p_hwfn, NETIF_MSG_LINK, 769cc875c2eSYuval Mintz "Resetting link\n"); 770cc875c2eSYuval Mintz } 771cc875c2eSYuval Mintz 7725529bad9STomer Tayar memset(&mb_params, 0, sizeof(mb_params)); 7735529bad9STomer Tayar mb_params.cmd = cmd; 7745529bad9STomer Tayar mb_params.p_data_src = &union_data; 7755529bad9STomer Tayar rc = qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 776cc875c2eSYuval Mintz 777cc875c2eSYuval Mintz /* if mcp fails to respond we must abort */ 778cc875c2eSYuval Mintz if (rc) { 779cc875c2eSYuval Mintz DP_ERR(p_hwfn, "MCP response failure, aborting\n"); 780cc875c2eSYuval Mintz return rc; 781cc875c2eSYuval Mintz } 782cc875c2eSYuval Mintz 783cc875c2eSYuval Mintz /* Reset the link status if needed */ 784cc875c2eSYuval Mintz if (!b_up) 785cc875c2eSYuval Mintz qed_mcp_handle_link_change(p_hwfn, p_ptt, true); 786cc875c2eSYuval Mintz 787cc875c2eSYuval Mintz return 0; 788cc875c2eSYuval Mintz } 789cc875c2eSYuval Mintz 7906c754246SSudarsana Reddy Kalluru static void qed_mcp_send_protocol_stats(struct qed_hwfn *p_hwfn, 7916c754246SSudarsana Reddy Kalluru struct qed_ptt *p_ptt, 7926c754246SSudarsana Reddy Kalluru enum MFW_DRV_MSG_TYPE type) 7936c754246SSudarsana Reddy Kalluru { 7946c754246SSudarsana Reddy Kalluru enum qed_mcp_protocol_type stats_type; 7956c754246SSudarsana Reddy Kalluru union qed_mcp_protocol_stats stats; 7966c754246SSudarsana Reddy Kalluru struct qed_mcp_mb_params mb_params; 7976c754246SSudarsana Reddy Kalluru union drv_union_data union_data; 7986c754246SSudarsana Reddy Kalluru u32 hsi_param; 7996c754246SSudarsana Reddy Kalluru 8006c754246SSudarsana Reddy Kalluru switch (type) { 8016c754246SSudarsana Reddy Kalluru case MFW_DRV_MSG_GET_LAN_STATS: 8026c754246SSudarsana Reddy Kalluru stats_type = QED_MCP_LAN_STATS; 8036c754246SSudarsana Reddy Kalluru hsi_param = DRV_MSG_CODE_STATS_TYPE_LAN; 8046c754246SSudarsana Reddy Kalluru break; 8056c754246SSudarsana Reddy Kalluru case MFW_DRV_MSG_GET_FCOE_STATS: 8066c754246SSudarsana Reddy Kalluru stats_type = QED_MCP_FCOE_STATS; 8076c754246SSudarsana Reddy Kalluru hsi_param = DRV_MSG_CODE_STATS_TYPE_FCOE; 8086c754246SSudarsana Reddy Kalluru break; 8096c754246SSudarsana Reddy Kalluru case MFW_DRV_MSG_GET_ISCSI_STATS: 8106c754246SSudarsana Reddy Kalluru stats_type = QED_MCP_ISCSI_STATS; 8116c754246SSudarsana Reddy Kalluru hsi_param = DRV_MSG_CODE_STATS_TYPE_ISCSI; 8126c754246SSudarsana Reddy Kalluru break; 8136c754246SSudarsana Reddy Kalluru case MFW_DRV_MSG_GET_RDMA_STATS: 8146c754246SSudarsana Reddy Kalluru stats_type = QED_MCP_RDMA_STATS; 8156c754246SSudarsana Reddy Kalluru hsi_param = DRV_MSG_CODE_STATS_TYPE_RDMA; 8166c754246SSudarsana Reddy Kalluru break; 8176c754246SSudarsana Reddy Kalluru default: 8186c754246SSudarsana Reddy Kalluru DP_NOTICE(p_hwfn, "Invalid protocol type %d\n", type); 8196c754246SSudarsana Reddy Kalluru return; 8206c754246SSudarsana Reddy Kalluru } 8216c754246SSudarsana Reddy Kalluru 8226c754246SSudarsana Reddy Kalluru qed_get_protocol_stats(p_hwfn->cdev, stats_type, &stats); 8236c754246SSudarsana Reddy Kalluru 8246c754246SSudarsana Reddy Kalluru memset(&mb_params, 0, sizeof(mb_params)); 8256c754246SSudarsana Reddy Kalluru mb_params.cmd = DRV_MSG_CODE_GET_STATS; 8266c754246SSudarsana Reddy Kalluru mb_params.param = hsi_param; 8276c754246SSudarsana Reddy Kalluru memcpy(&union_data, &stats, sizeof(stats)); 8286c754246SSudarsana Reddy Kalluru mb_params.p_data_src = &union_data; 8296c754246SSudarsana Reddy Kalluru qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 8306c754246SSudarsana Reddy Kalluru } 8316c754246SSudarsana Reddy Kalluru 8324b01e519SManish Chopra static void qed_read_pf_bandwidth(struct qed_hwfn *p_hwfn, 8334b01e519SManish Chopra struct public_func *p_shmem_info) 8344b01e519SManish Chopra { 8354b01e519SManish Chopra struct qed_mcp_function_info *p_info; 8364b01e519SManish Chopra 8374b01e519SManish Chopra p_info = &p_hwfn->mcp_info->func_info; 8384b01e519SManish Chopra 8394b01e519SManish Chopra p_info->bandwidth_min = (p_shmem_info->config & 8404b01e519SManish Chopra FUNC_MF_CFG_MIN_BW_MASK) >> 8414b01e519SManish Chopra FUNC_MF_CFG_MIN_BW_SHIFT; 8424b01e519SManish Chopra if (p_info->bandwidth_min < 1 || p_info->bandwidth_min > 100) { 8434b01e519SManish Chopra DP_INFO(p_hwfn, 8444b01e519SManish Chopra "bandwidth minimum out of bounds [%02x]. Set to 1\n", 8454b01e519SManish Chopra p_info->bandwidth_min); 8464b01e519SManish Chopra p_info->bandwidth_min = 1; 8474b01e519SManish Chopra } 8484b01e519SManish Chopra 8494b01e519SManish Chopra p_info->bandwidth_max = (p_shmem_info->config & 8504b01e519SManish Chopra FUNC_MF_CFG_MAX_BW_MASK) >> 8514b01e519SManish Chopra FUNC_MF_CFG_MAX_BW_SHIFT; 8524b01e519SManish Chopra if (p_info->bandwidth_max < 1 || p_info->bandwidth_max > 100) { 8534b01e519SManish Chopra DP_INFO(p_hwfn, 8544b01e519SManish Chopra "bandwidth maximum out of bounds [%02x]. Set to 100\n", 8554b01e519SManish Chopra p_info->bandwidth_max); 8564b01e519SManish Chopra p_info->bandwidth_max = 100; 8574b01e519SManish Chopra } 8584b01e519SManish Chopra } 8594b01e519SManish Chopra 8604b01e519SManish Chopra static u32 qed_mcp_get_shmem_func(struct qed_hwfn *p_hwfn, 8614b01e519SManish Chopra struct qed_ptt *p_ptt, 8621a635e48SYuval Mintz struct public_func *p_data, int pfid) 8634b01e519SManish Chopra { 8644b01e519SManish Chopra u32 addr = SECTION_OFFSIZE_ADDR(p_hwfn->mcp_info->public_base, 8654b01e519SManish Chopra PUBLIC_FUNC); 8664b01e519SManish Chopra u32 mfw_path_offsize = qed_rd(p_hwfn, p_ptt, addr); 8674b01e519SManish Chopra u32 func_addr = SECTION_ADDR(mfw_path_offsize, pfid); 8684b01e519SManish Chopra u32 i, size; 8694b01e519SManish Chopra 8704b01e519SManish Chopra memset(p_data, 0, sizeof(*p_data)); 8714b01e519SManish Chopra 8721a635e48SYuval Mintz size = min_t(u32, sizeof(*p_data), QED_SECTION_SIZE(mfw_path_offsize)); 8734b01e519SManish Chopra for (i = 0; i < size / sizeof(u32); i++) 8744b01e519SManish Chopra ((u32 *)p_data)[i] = qed_rd(p_hwfn, p_ptt, 8754b01e519SManish Chopra func_addr + (i << 2)); 8764b01e519SManish Chopra return size; 8774b01e519SManish Chopra } 8784b01e519SManish Chopra 8791a635e48SYuval Mintz static void qed_mcp_update_bw(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 8804b01e519SManish Chopra { 8814b01e519SManish Chopra struct qed_mcp_function_info *p_info; 8824b01e519SManish Chopra struct public_func shmem_info; 8834b01e519SManish Chopra u32 resp = 0, param = 0; 8844b01e519SManish Chopra 8851a635e48SYuval Mintz qed_mcp_get_shmem_func(p_hwfn, p_ptt, &shmem_info, MCP_PF_ID(p_hwfn)); 8864b01e519SManish Chopra 8874b01e519SManish Chopra qed_read_pf_bandwidth(p_hwfn, &shmem_info); 8884b01e519SManish Chopra 8894b01e519SManish Chopra p_info = &p_hwfn->mcp_info->func_info; 8904b01e519SManish Chopra 891a64b02d5SManish Chopra qed_configure_pf_min_bandwidth(p_hwfn->cdev, p_info->bandwidth_min); 8924b01e519SManish Chopra qed_configure_pf_max_bandwidth(p_hwfn->cdev, p_info->bandwidth_max); 8934b01e519SManish Chopra 8944b01e519SManish Chopra /* Acknowledge the MFW */ 8954b01e519SManish Chopra qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_BW_UPDATE_ACK, 0, &resp, 8964b01e519SManish Chopra ¶m); 8974b01e519SManish Chopra } 8984b01e519SManish Chopra 899cc875c2eSYuval Mintz int qed_mcp_handle_events(struct qed_hwfn *p_hwfn, 900cc875c2eSYuval Mintz struct qed_ptt *p_ptt) 901cc875c2eSYuval Mintz { 902cc875c2eSYuval Mintz struct qed_mcp_info *info = p_hwfn->mcp_info; 903cc875c2eSYuval Mintz int rc = 0; 904cc875c2eSYuval Mintz bool found = false; 905cc875c2eSYuval Mintz u16 i; 906cc875c2eSYuval Mintz 907cc875c2eSYuval Mintz DP_VERBOSE(p_hwfn, QED_MSG_SP, "Received message from MFW\n"); 908cc875c2eSYuval Mintz 909cc875c2eSYuval Mintz /* Read Messages from MFW */ 910cc875c2eSYuval Mintz qed_mcp_read_mb(p_hwfn, p_ptt); 911cc875c2eSYuval Mintz 912cc875c2eSYuval Mintz /* Compare current messages to old ones */ 913cc875c2eSYuval Mintz for (i = 0; i < info->mfw_mb_length; i++) { 914cc875c2eSYuval Mintz if (info->mfw_mb_cur[i] == info->mfw_mb_shadow[i]) 915cc875c2eSYuval Mintz continue; 916cc875c2eSYuval Mintz 917cc875c2eSYuval Mintz found = true; 918cc875c2eSYuval Mintz 919cc875c2eSYuval Mintz DP_VERBOSE(p_hwfn, NETIF_MSG_LINK, 920cc875c2eSYuval Mintz "Msg [%d] - old CMD 0x%02x, new CMD 0x%02x\n", 921cc875c2eSYuval Mintz i, info->mfw_mb_shadow[i], info->mfw_mb_cur[i]); 922cc875c2eSYuval Mintz 923cc875c2eSYuval Mintz switch (i) { 924cc875c2eSYuval Mintz case MFW_DRV_MSG_LINK_CHANGE: 925cc875c2eSYuval Mintz qed_mcp_handle_link_change(p_hwfn, p_ptt, false); 926cc875c2eSYuval Mintz break; 9270b55e27dSYuval Mintz case MFW_DRV_MSG_VF_DISABLED: 9280b55e27dSYuval Mintz qed_mcp_handle_vf_flr(p_hwfn, p_ptt); 9290b55e27dSYuval Mintz break; 93039651abdSSudarsana Reddy Kalluru case MFW_DRV_MSG_LLDP_DATA_UPDATED: 93139651abdSSudarsana Reddy Kalluru qed_dcbx_mib_update_event(p_hwfn, p_ptt, 93239651abdSSudarsana Reddy Kalluru QED_DCBX_REMOTE_LLDP_MIB); 93339651abdSSudarsana Reddy Kalluru break; 93439651abdSSudarsana Reddy Kalluru case MFW_DRV_MSG_DCBX_REMOTE_MIB_UPDATED: 93539651abdSSudarsana Reddy Kalluru qed_dcbx_mib_update_event(p_hwfn, p_ptt, 93639651abdSSudarsana Reddy Kalluru QED_DCBX_REMOTE_MIB); 93739651abdSSudarsana Reddy Kalluru break; 93839651abdSSudarsana Reddy Kalluru case MFW_DRV_MSG_DCBX_OPERATIONAL_MIB_UPDATED: 93939651abdSSudarsana Reddy Kalluru qed_dcbx_mib_update_event(p_hwfn, p_ptt, 94039651abdSSudarsana Reddy Kalluru QED_DCBX_OPERATIONAL_MIB); 94139651abdSSudarsana Reddy Kalluru break; 942334c03b5SZvi Nachmani case MFW_DRV_MSG_TRANSCEIVER_STATE_CHANGE: 943334c03b5SZvi Nachmani qed_mcp_handle_transceiver_change(p_hwfn, p_ptt); 944334c03b5SZvi Nachmani break; 9456c754246SSudarsana Reddy Kalluru case MFW_DRV_MSG_GET_LAN_STATS: 9466c754246SSudarsana Reddy Kalluru case MFW_DRV_MSG_GET_FCOE_STATS: 9476c754246SSudarsana Reddy Kalluru case MFW_DRV_MSG_GET_ISCSI_STATS: 9486c754246SSudarsana Reddy Kalluru case MFW_DRV_MSG_GET_RDMA_STATS: 9496c754246SSudarsana Reddy Kalluru qed_mcp_send_protocol_stats(p_hwfn, p_ptt, i); 9506c754246SSudarsana Reddy Kalluru break; 9514b01e519SManish Chopra case MFW_DRV_MSG_BW_UPDATE: 9524b01e519SManish Chopra qed_mcp_update_bw(p_hwfn, p_ptt); 9534b01e519SManish Chopra break; 954cc875c2eSYuval Mintz default: 955cc875c2eSYuval Mintz DP_NOTICE(p_hwfn, "Unimplemented MFW message %d\n", i); 956cc875c2eSYuval Mintz rc = -EINVAL; 957cc875c2eSYuval Mintz } 958cc875c2eSYuval Mintz } 959cc875c2eSYuval Mintz 960cc875c2eSYuval Mintz /* ACK everything */ 961cc875c2eSYuval Mintz for (i = 0; i < MFW_DRV_MSG_MAX_DWORDS(info->mfw_mb_length); i++) { 962cc875c2eSYuval Mintz __be32 val = cpu_to_be32(((u32 *)info->mfw_mb_cur)[i]); 963cc875c2eSYuval Mintz 964cc875c2eSYuval Mintz /* MFW expect answer in BE, so we force write in that format */ 965cc875c2eSYuval Mintz qed_wr(p_hwfn, p_ptt, 966cc875c2eSYuval Mintz info->mfw_mb_addr + sizeof(u32) + 967cc875c2eSYuval Mintz MFW_DRV_MSG_MAX_DWORDS(info->mfw_mb_length) * 968cc875c2eSYuval Mintz sizeof(u32) + i * sizeof(u32), 969cc875c2eSYuval Mintz (__force u32)val); 970cc875c2eSYuval Mintz } 971cc875c2eSYuval Mintz 972cc875c2eSYuval Mintz if (!found) { 973cc875c2eSYuval Mintz DP_NOTICE(p_hwfn, 974cc875c2eSYuval Mintz "Received an MFW message indication but no new message!\n"); 975cc875c2eSYuval Mintz rc = -EINVAL; 976cc875c2eSYuval Mintz } 977cc875c2eSYuval Mintz 978cc875c2eSYuval Mintz /* Copy the new mfw messages into the shadow */ 979cc875c2eSYuval Mintz memcpy(info->mfw_mb_shadow, info->mfw_mb_cur, info->mfw_mb_length); 980cc875c2eSYuval Mintz 981cc875c2eSYuval Mintz return rc; 982cc875c2eSYuval Mintz } 983cc875c2eSYuval Mintz 9841408cc1fSYuval Mintz int qed_mcp_get_mfw_ver(struct qed_hwfn *p_hwfn, 9851408cc1fSYuval Mintz struct qed_ptt *p_ptt, 9861408cc1fSYuval Mintz u32 *p_mfw_ver, u32 *p_running_bundle_id) 987fe56b9e6SYuval Mintz { 988fe56b9e6SYuval Mintz u32 global_offsize; 989fe56b9e6SYuval Mintz 9901408cc1fSYuval Mintz if (IS_VF(p_hwfn->cdev)) { 9911408cc1fSYuval Mintz if (p_hwfn->vf_iov_info) { 9921408cc1fSYuval Mintz struct pfvf_acquire_resp_tlv *p_resp; 9931408cc1fSYuval Mintz 9941408cc1fSYuval Mintz p_resp = &p_hwfn->vf_iov_info->acquire_resp; 9951408cc1fSYuval Mintz *p_mfw_ver = p_resp->pfdev_info.mfw_ver; 9961408cc1fSYuval Mintz return 0; 9971408cc1fSYuval Mintz } else { 9981408cc1fSYuval Mintz DP_VERBOSE(p_hwfn, 9991408cc1fSYuval Mintz QED_MSG_IOV, 10001408cc1fSYuval Mintz "VF requested MFW version prior to ACQUIRE\n"); 10011408cc1fSYuval Mintz return -EINVAL; 10021408cc1fSYuval Mintz } 10031408cc1fSYuval Mintz } 1004fe56b9e6SYuval Mintz 1005fe56b9e6SYuval Mintz global_offsize = qed_rd(p_hwfn, p_ptt, 10061408cc1fSYuval Mintz SECTION_OFFSIZE_ADDR(p_hwfn-> 10071408cc1fSYuval Mintz mcp_info->public_base, 1008fe56b9e6SYuval Mintz PUBLIC_GLOBAL)); 10091408cc1fSYuval Mintz *p_mfw_ver = 10101408cc1fSYuval Mintz qed_rd(p_hwfn, p_ptt, 10111408cc1fSYuval Mintz SECTION_ADDR(global_offsize, 10121408cc1fSYuval Mintz 0) + offsetof(struct public_global, mfw_ver)); 1013fe56b9e6SYuval Mintz 10141408cc1fSYuval Mintz if (p_running_bundle_id != NULL) { 10151408cc1fSYuval Mintz *p_running_bundle_id = qed_rd(p_hwfn, p_ptt, 10161408cc1fSYuval Mintz SECTION_ADDR(global_offsize, 0) + 10171408cc1fSYuval Mintz offsetof(struct public_global, 10181408cc1fSYuval Mintz running_bundle_id)); 10191408cc1fSYuval Mintz } 1020fe56b9e6SYuval Mintz 1021fe56b9e6SYuval Mintz return 0; 1022fe56b9e6SYuval Mintz } 1023fe56b9e6SYuval Mintz 10241a635e48SYuval Mintz int qed_mcp_get_media_type(struct qed_dev *cdev, u32 *p_media_type) 1025cc875c2eSYuval Mintz { 1026cc875c2eSYuval Mintz struct qed_hwfn *p_hwfn = &cdev->hwfns[0]; 1027cc875c2eSYuval Mintz struct qed_ptt *p_ptt; 1028cc875c2eSYuval Mintz 10291408cc1fSYuval Mintz if (IS_VF(cdev)) 10301408cc1fSYuval Mintz return -EINVAL; 10311408cc1fSYuval Mintz 1032cc875c2eSYuval Mintz if (!qed_mcp_is_init(p_hwfn)) { 1033cc875c2eSYuval Mintz DP_NOTICE(p_hwfn, "MFW is not initialized!\n"); 1034cc875c2eSYuval Mintz return -EBUSY; 1035cc875c2eSYuval Mintz } 1036cc875c2eSYuval Mintz 1037cc875c2eSYuval Mintz *p_media_type = MEDIA_UNSPECIFIED; 1038cc875c2eSYuval Mintz 1039cc875c2eSYuval Mintz p_ptt = qed_ptt_acquire(p_hwfn); 1040cc875c2eSYuval Mintz if (!p_ptt) 1041cc875c2eSYuval Mintz return -EBUSY; 1042cc875c2eSYuval Mintz 1043cc875c2eSYuval Mintz *p_media_type = qed_rd(p_hwfn, p_ptt, p_hwfn->mcp_info->port_addr + 1044cc875c2eSYuval Mintz offsetof(struct public_port, media_type)); 1045cc875c2eSYuval Mintz 1046cc875c2eSYuval Mintz qed_ptt_release(p_hwfn, p_ptt); 1047cc875c2eSYuval Mintz 1048cc875c2eSYuval Mintz return 0; 1049cc875c2eSYuval Mintz } 1050cc875c2eSYuval Mintz 10516927e826SMintz, Yuval /* Old MFW has a global configuration for all PFs regarding RDMA support */ 10526927e826SMintz, Yuval static void 10536927e826SMintz, Yuval qed_mcp_get_shmem_proto_legacy(struct qed_hwfn *p_hwfn, 10546927e826SMintz, Yuval enum qed_pci_personality *p_proto) 10556927e826SMintz, Yuval { 10566927e826SMintz, Yuval /* There wasn't ever a legacy MFW that published iwarp. 10576927e826SMintz, Yuval * So at this point, this is either plain l2 or RoCE. 10586927e826SMintz, Yuval */ 10596927e826SMintz, Yuval if (test_bit(QED_DEV_CAP_ROCE, &p_hwfn->hw_info.device_capabilities)) 10606927e826SMintz, Yuval *p_proto = QED_PCI_ETH_ROCE; 10616927e826SMintz, Yuval else 10626927e826SMintz, Yuval *p_proto = QED_PCI_ETH; 10636927e826SMintz, Yuval 10646927e826SMintz, Yuval DP_VERBOSE(p_hwfn, NETIF_MSG_IFUP, 10656927e826SMintz, Yuval "According to Legacy capabilities, L2 personality is %08x\n", 10666927e826SMintz, Yuval (u32) *p_proto); 10676927e826SMintz, Yuval } 10686927e826SMintz, Yuval 10696927e826SMintz, Yuval static int 10706927e826SMintz, Yuval qed_mcp_get_shmem_proto_mfw(struct qed_hwfn *p_hwfn, 10716927e826SMintz, Yuval struct qed_ptt *p_ptt, 10726927e826SMintz, Yuval enum qed_pci_personality *p_proto) 10736927e826SMintz, Yuval { 10746927e826SMintz, Yuval u32 resp = 0, param = 0; 10756927e826SMintz, Yuval int rc; 10766927e826SMintz, Yuval 10776927e826SMintz, Yuval rc = qed_mcp_cmd(p_hwfn, p_ptt, 10786927e826SMintz, Yuval DRV_MSG_CODE_GET_PF_RDMA_PROTOCOL, 0, &resp, ¶m); 10796927e826SMintz, Yuval if (rc) 10806927e826SMintz, Yuval return rc; 10816927e826SMintz, Yuval if (resp != FW_MSG_CODE_OK) { 10826927e826SMintz, Yuval DP_VERBOSE(p_hwfn, NETIF_MSG_IFUP, 10836927e826SMintz, Yuval "MFW lacks support for command; Returns %08x\n", 10846927e826SMintz, Yuval resp); 10856927e826SMintz, Yuval return -EINVAL; 10866927e826SMintz, Yuval } 10876927e826SMintz, Yuval 10886927e826SMintz, Yuval switch (param) { 10896927e826SMintz, Yuval case FW_MB_PARAM_GET_PF_RDMA_NONE: 10906927e826SMintz, Yuval *p_proto = QED_PCI_ETH; 10916927e826SMintz, Yuval break; 10926927e826SMintz, Yuval case FW_MB_PARAM_GET_PF_RDMA_ROCE: 10936927e826SMintz, Yuval *p_proto = QED_PCI_ETH_ROCE; 10946927e826SMintz, Yuval break; 10956927e826SMintz, Yuval case FW_MB_PARAM_GET_PF_RDMA_BOTH: 10966927e826SMintz, Yuval DP_NOTICE(p_hwfn, 10976927e826SMintz, Yuval "Current day drivers don't support RoCE & iWARP. Default to RoCE-only\n"); 10986927e826SMintz, Yuval *p_proto = QED_PCI_ETH_ROCE; 10996927e826SMintz, Yuval break; 11006927e826SMintz, Yuval case FW_MB_PARAM_GET_PF_RDMA_IWARP: 11016927e826SMintz, Yuval default: 11026927e826SMintz, Yuval DP_NOTICE(p_hwfn, 11036927e826SMintz, Yuval "MFW answers GET_PF_RDMA_PROTOCOL but param is %08x\n", 11046927e826SMintz, Yuval param); 11056927e826SMintz, Yuval return -EINVAL; 11066927e826SMintz, Yuval } 11076927e826SMintz, Yuval 11086927e826SMintz, Yuval DP_VERBOSE(p_hwfn, 11096927e826SMintz, Yuval NETIF_MSG_IFUP, 11106927e826SMintz, Yuval "According to capabilities, L2 personality is %08x [resp %08x param %08x]\n", 11116927e826SMintz, Yuval (u32) *p_proto, resp, param); 11126927e826SMintz, Yuval return 0; 11136927e826SMintz, Yuval } 11146927e826SMintz, Yuval 1115fe56b9e6SYuval Mintz static int 1116fe56b9e6SYuval Mintz qed_mcp_get_shmem_proto(struct qed_hwfn *p_hwfn, 1117fe56b9e6SYuval Mintz struct public_func *p_info, 11186927e826SMintz, Yuval struct qed_ptt *p_ptt, 1119fe56b9e6SYuval Mintz enum qed_pci_personality *p_proto) 1120fe56b9e6SYuval Mintz { 1121fe56b9e6SYuval Mintz int rc = 0; 1122fe56b9e6SYuval Mintz 1123fe56b9e6SYuval Mintz switch (p_info->config & FUNC_MF_CFG_PROTOCOL_MASK) { 1124fe56b9e6SYuval Mintz case FUNC_MF_CFG_PROTOCOL_ETHERNET: 11251fe582ecSRam Amrani if (!IS_ENABLED(CONFIG_QED_RDMA)) 11261fe582ecSRam Amrani *p_proto = QED_PCI_ETH; 11271fe582ecSRam Amrani else if (qed_mcp_get_shmem_proto_mfw(p_hwfn, p_ptt, p_proto)) 11286927e826SMintz, Yuval qed_mcp_get_shmem_proto_legacy(p_hwfn, p_proto); 1129fe56b9e6SYuval Mintz break; 1130c5ac9319SYuval Mintz case FUNC_MF_CFG_PROTOCOL_ISCSI: 1131c5ac9319SYuval Mintz *p_proto = QED_PCI_ISCSI; 1132c5ac9319SYuval Mintz break; 1133c5ac9319SYuval Mintz case FUNC_MF_CFG_PROTOCOL_ROCE: 1134c5ac9319SYuval Mintz DP_NOTICE(p_hwfn, "RoCE personality is not a valid value!\n"); 11356927e826SMintz, Yuval /* Fallthrough */ 1136fe56b9e6SYuval Mintz default: 1137fe56b9e6SYuval Mintz rc = -EINVAL; 1138fe56b9e6SYuval Mintz } 1139fe56b9e6SYuval Mintz 1140fe56b9e6SYuval Mintz return rc; 1141fe56b9e6SYuval Mintz } 1142fe56b9e6SYuval Mintz 1143fe56b9e6SYuval Mintz int qed_mcp_fill_shmem_func_info(struct qed_hwfn *p_hwfn, 1144fe56b9e6SYuval Mintz struct qed_ptt *p_ptt) 1145fe56b9e6SYuval Mintz { 1146fe56b9e6SYuval Mintz struct qed_mcp_function_info *info; 1147fe56b9e6SYuval Mintz struct public_func shmem_info; 1148fe56b9e6SYuval Mintz 11491a635e48SYuval Mintz qed_mcp_get_shmem_func(p_hwfn, p_ptt, &shmem_info, MCP_PF_ID(p_hwfn)); 1150fe56b9e6SYuval Mintz info = &p_hwfn->mcp_info->func_info; 1151fe56b9e6SYuval Mintz 1152fe56b9e6SYuval Mintz info->pause_on_host = (shmem_info.config & 1153fe56b9e6SYuval Mintz FUNC_MF_CFG_PAUSE_ON_HOST_RING) ? 1 : 0; 1154fe56b9e6SYuval Mintz 11556927e826SMintz, Yuval if (qed_mcp_get_shmem_proto(p_hwfn, &shmem_info, p_ptt, 11566927e826SMintz, Yuval &info->protocol)) { 1157fe56b9e6SYuval Mintz DP_ERR(p_hwfn, "Unknown personality %08x\n", 1158fe56b9e6SYuval Mintz (u32)(shmem_info.config & FUNC_MF_CFG_PROTOCOL_MASK)); 1159fe56b9e6SYuval Mintz return -EINVAL; 1160fe56b9e6SYuval Mintz } 1161fe56b9e6SYuval Mintz 11624b01e519SManish Chopra qed_read_pf_bandwidth(p_hwfn, &shmem_info); 1163fe56b9e6SYuval Mintz 1164fe56b9e6SYuval Mintz if (shmem_info.mac_upper || shmem_info.mac_lower) { 1165fe56b9e6SYuval Mintz info->mac[0] = (u8)(shmem_info.mac_upper >> 8); 1166fe56b9e6SYuval Mintz info->mac[1] = (u8)(shmem_info.mac_upper); 1167fe56b9e6SYuval Mintz info->mac[2] = (u8)(shmem_info.mac_lower >> 24); 1168fe56b9e6SYuval Mintz info->mac[3] = (u8)(shmem_info.mac_lower >> 16); 1169fe56b9e6SYuval Mintz info->mac[4] = (u8)(shmem_info.mac_lower >> 8); 1170fe56b9e6SYuval Mintz info->mac[5] = (u8)(shmem_info.mac_lower); 117114d39648SMintz, Yuval 117214d39648SMintz, Yuval /* Store primary MAC for later possible WoL */ 117314d39648SMintz, Yuval memcpy(&p_hwfn->cdev->wol_mac, info->mac, ETH_ALEN); 1174fe56b9e6SYuval Mintz } else { 1175fe56b9e6SYuval Mintz DP_NOTICE(p_hwfn, "MAC is 0 in shmem\n"); 1176fe56b9e6SYuval Mintz } 1177fe56b9e6SYuval Mintz 1178fe56b9e6SYuval Mintz info->wwn_port = (u64)shmem_info.fcoe_wwn_port_name_upper | 1179fe56b9e6SYuval Mintz (((u64)shmem_info.fcoe_wwn_port_name_lower) << 32); 1180fe56b9e6SYuval Mintz info->wwn_node = (u64)shmem_info.fcoe_wwn_node_name_upper | 1181fe56b9e6SYuval Mintz (((u64)shmem_info.fcoe_wwn_node_name_lower) << 32); 1182fe56b9e6SYuval Mintz 1183fe56b9e6SYuval Mintz info->ovlan = (u16)(shmem_info.ovlan_stag & FUNC_MF_CFG_OV_STAG_MASK); 1184fe56b9e6SYuval Mintz 11850fefbfbaSSudarsana Kalluru info->mtu = (u16)shmem_info.mtu_size; 11860fefbfbaSSudarsana Kalluru 118714d39648SMintz, Yuval p_hwfn->hw_info.b_wol_support = QED_WOL_SUPPORT_NONE; 118814d39648SMintz, Yuval p_hwfn->cdev->wol_config = (u8)QED_OV_WOL_DEFAULT; 118914d39648SMintz, Yuval if (qed_mcp_is_init(p_hwfn)) { 119014d39648SMintz, Yuval u32 resp = 0, param = 0; 119114d39648SMintz, Yuval int rc; 119214d39648SMintz, Yuval 119314d39648SMintz, Yuval rc = qed_mcp_cmd(p_hwfn, p_ptt, 119414d39648SMintz, Yuval DRV_MSG_CODE_OS_WOL, 0, &resp, ¶m); 119514d39648SMintz, Yuval if (rc) 119614d39648SMintz, Yuval return rc; 119714d39648SMintz, Yuval if (resp == FW_MSG_CODE_OS_WOL_SUPPORTED) 119814d39648SMintz, Yuval p_hwfn->hw_info.b_wol_support = QED_WOL_SUPPORT_PME; 119914d39648SMintz, Yuval } 120014d39648SMintz, Yuval 1201fe56b9e6SYuval Mintz DP_VERBOSE(p_hwfn, (QED_MSG_SP | NETIF_MSG_IFUP), 120214d39648SMintz, 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", 1203fe56b9e6SYuval Mintz info->pause_on_host, info->protocol, 1204fe56b9e6SYuval Mintz info->bandwidth_min, info->bandwidth_max, 1205fe56b9e6SYuval Mintz info->mac[0], info->mac[1], info->mac[2], 1206fe56b9e6SYuval Mintz info->mac[3], info->mac[4], info->mac[5], 120714d39648SMintz, Yuval info->wwn_port, info->wwn_node, 120814d39648SMintz, Yuval info->ovlan, (u8)p_hwfn->hw_info.b_wol_support); 1209fe56b9e6SYuval Mintz 1210fe56b9e6SYuval Mintz return 0; 1211fe56b9e6SYuval Mintz } 1212fe56b9e6SYuval Mintz 1213cc875c2eSYuval Mintz struct qed_mcp_link_params 1214cc875c2eSYuval Mintz *qed_mcp_get_link_params(struct qed_hwfn *p_hwfn) 1215cc875c2eSYuval Mintz { 1216cc875c2eSYuval Mintz if (!p_hwfn || !p_hwfn->mcp_info) 1217cc875c2eSYuval Mintz return NULL; 1218cc875c2eSYuval Mintz return &p_hwfn->mcp_info->link_input; 1219cc875c2eSYuval Mintz } 1220cc875c2eSYuval Mintz 1221cc875c2eSYuval Mintz struct qed_mcp_link_state 1222cc875c2eSYuval Mintz *qed_mcp_get_link_state(struct qed_hwfn *p_hwfn) 1223cc875c2eSYuval Mintz { 1224cc875c2eSYuval Mintz if (!p_hwfn || !p_hwfn->mcp_info) 1225cc875c2eSYuval Mintz return NULL; 1226cc875c2eSYuval Mintz return &p_hwfn->mcp_info->link_output; 1227cc875c2eSYuval Mintz } 1228cc875c2eSYuval Mintz 1229cc875c2eSYuval Mintz struct qed_mcp_link_capabilities 1230cc875c2eSYuval Mintz *qed_mcp_get_link_capabilities(struct qed_hwfn *p_hwfn) 1231cc875c2eSYuval Mintz { 1232cc875c2eSYuval Mintz if (!p_hwfn || !p_hwfn->mcp_info) 1233cc875c2eSYuval Mintz return NULL; 1234cc875c2eSYuval Mintz return &p_hwfn->mcp_info->link_capabilities; 1235cc875c2eSYuval Mintz } 1236cc875c2eSYuval Mintz 12371a635e48SYuval Mintz int qed_mcp_drain(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 1238fe56b9e6SYuval Mintz { 1239fe56b9e6SYuval Mintz u32 resp = 0, param = 0; 1240fe56b9e6SYuval Mintz int rc; 1241fe56b9e6SYuval Mintz 1242fe56b9e6SYuval Mintz rc = qed_mcp_cmd(p_hwfn, p_ptt, 12431a635e48SYuval Mintz DRV_MSG_CODE_NIG_DRAIN, 1000, &resp, ¶m); 1244fe56b9e6SYuval Mintz 1245fe56b9e6SYuval Mintz /* Wait for the drain to complete before returning */ 12468f60bafeSYuval Mintz msleep(1020); 1247fe56b9e6SYuval Mintz 1248fe56b9e6SYuval Mintz return rc; 1249fe56b9e6SYuval Mintz } 1250fe56b9e6SYuval Mintz 1251cee4d264SManish Chopra int qed_mcp_get_flash_size(struct qed_hwfn *p_hwfn, 12521a635e48SYuval Mintz struct qed_ptt *p_ptt, u32 *p_flash_size) 1253cee4d264SManish Chopra { 1254cee4d264SManish Chopra u32 flash_size; 1255cee4d264SManish Chopra 12561408cc1fSYuval Mintz if (IS_VF(p_hwfn->cdev)) 12571408cc1fSYuval Mintz return -EINVAL; 12581408cc1fSYuval Mintz 1259cee4d264SManish Chopra flash_size = qed_rd(p_hwfn, p_ptt, MCP_REG_NVM_CFG4); 1260cee4d264SManish Chopra flash_size = (flash_size & MCP_REG_NVM_CFG4_FLASH_SIZE) >> 1261cee4d264SManish Chopra MCP_REG_NVM_CFG4_FLASH_SIZE_SHIFT; 1262cee4d264SManish Chopra flash_size = (1 << (flash_size + MCP_BYTES_PER_MBIT_SHIFT)); 1263cee4d264SManish Chopra 1264cee4d264SManish Chopra *p_flash_size = flash_size; 1265cee4d264SManish Chopra 1266cee4d264SManish Chopra return 0; 1267cee4d264SManish Chopra } 1268cee4d264SManish Chopra 12691408cc1fSYuval Mintz int qed_mcp_config_vf_msix(struct qed_hwfn *p_hwfn, 12701408cc1fSYuval Mintz struct qed_ptt *p_ptt, u8 vf_id, u8 num) 12711408cc1fSYuval Mintz { 12721408cc1fSYuval Mintz u32 resp = 0, param = 0, rc_param = 0; 12731408cc1fSYuval Mintz int rc; 12741408cc1fSYuval Mintz 12751408cc1fSYuval Mintz /* Only Leader can configure MSIX, and need to take CMT into account */ 12761408cc1fSYuval Mintz if (!IS_LEAD_HWFN(p_hwfn)) 12771408cc1fSYuval Mintz return 0; 12781408cc1fSYuval Mintz num *= p_hwfn->cdev->num_hwfns; 12791408cc1fSYuval Mintz 12801408cc1fSYuval Mintz param |= (vf_id << DRV_MB_PARAM_CFG_VF_MSIX_VF_ID_SHIFT) & 12811408cc1fSYuval Mintz DRV_MB_PARAM_CFG_VF_MSIX_VF_ID_MASK; 12821408cc1fSYuval Mintz param |= (num << DRV_MB_PARAM_CFG_VF_MSIX_SB_NUM_SHIFT) & 12831408cc1fSYuval Mintz DRV_MB_PARAM_CFG_VF_MSIX_SB_NUM_MASK; 12841408cc1fSYuval Mintz 12851408cc1fSYuval Mintz rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_CFG_VF_MSIX, param, 12861408cc1fSYuval Mintz &resp, &rc_param); 12871408cc1fSYuval Mintz 12881408cc1fSYuval Mintz if (resp != FW_MSG_CODE_DRV_CFG_VF_MSIX_DONE) { 12891408cc1fSYuval Mintz DP_NOTICE(p_hwfn, "VF[%d]: MFW failed to set MSI-X\n", vf_id); 12901408cc1fSYuval Mintz rc = -EINVAL; 12911408cc1fSYuval Mintz } else { 12921408cc1fSYuval Mintz DP_VERBOSE(p_hwfn, QED_MSG_IOV, 12931408cc1fSYuval Mintz "Requested 0x%02x MSI-x interrupts from VF 0x%02x\n", 12941408cc1fSYuval Mintz num, vf_id); 12951408cc1fSYuval Mintz } 12961408cc1fSYuval Mintz 12971408cc1fSYuval Mintz return rc; 12981408cc1fSYuval Mintz } 12991408cc1fSYuval Mintz 1300fe56b9e6SYuval Mintz int 1301fe56b9e6SYuval Mintz qed_mcp_send_drv_version(struct qed_hwfn *p_hwfn, 1302fe56b9e6SYuval Mintz struct qed_ptt *p_ptt, 1303fe56b9e6SYuval Mintz struct qed_mcp_drv_version *p_ver) 1304fe56b9e6SYuval Mintz { 13055529bad9STomer Tayar struct drv_version_stc *p_drv_version; 13065529bad9STomer Tayar struct qed_mcp_mb_params mb_params; 13075529bad9STomer Tayar union drv_union_data union_data; 13085529bad9STomer Tayar __be32 val; 13095529bad9STomer Tayar u32 i; 13105529bad9STomer Tayar int rc; 1311fe56b9e6SYuval Mintz 13125529bad9STomer Tayar p_drv_version = &union_data.drv_version; 13135529bad9STomer Tayar p_drv_version->version = p_ver->version; 13144b01e519SManish Chopra 131567a99b70SYuval Mintz for (i = 0; i < (MCP_DRV_VER_STR_SIZE - 4) / sizeof(u32); i++) { 131667a99b70SYuval Mintz val = cpu_to_be32(*((u32 *)&p_ver->name[i * sizeof(u32)])); 13174b01e519SManish Chopra *(__be32 *)&p_drv_version->name[i * sizeof(u32)] = val; 1318fe56b9e6SYuval Mintz } 1319fe56b9e6SYuval Mintz 13205529bad9STomer Tayar memset(&mb_params, 0, sizeof(mb_params)); 13215529bad9STomer Tayar mb_params.cmd = DRV_MSG_CODE_SET_VERSION; 13225529bad9STomer Tayar mb_params.p_data_src = &union_data; 13235529bad9STomer Tayar rc = qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 13245529bad9STomer Tayar if (rc) 1325fe56b9e6SYuval Mintz DP_ERR(p_hwfn, "MCP response failure, aborting\n"); 1326fe56b9e6SYuval Mintz 13275529bad9STomer Tayar return rc; 1328fe56b9e6SYuval Mintz } 132991420b83SSudarsana Kalluru 13304102426fSTomer Tayar int qed_mcp_halt(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 13314102426fSTomer Tayar { 13324102426fSTomer Tayar u32 resp = 0, param = 0; 13334102426fSTomer Tayar int rc; 13344102426fSTomer Tayar 13354102426fSTomer Tayar rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_MCP_HALT, 0, &resp, 13364102426fSTomer Tayar ¶m); 13374102426fSTomer Tayar if (rc) 13384102426fSTomer Tayar DP_ERR(p_hwfn, "MCP response failure, aborting\n"); 13394102426fSTomer Tayar 13404102426fSTomer Tayar return rc; 13414102426fSTomer Tayar } 13424102426fSTomer Tayar 13434102426fSTomer Tayar int qed_mcp_resume(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 13444102426fSTomer Tayar { 13454102426fSTomer Tayar u32 value, cpu_mode; 13464102426fSTomer Tayar 13474102426fSTomer Tayar qed_wr(p_hwfn, p_ptt, MCP_REG_CPU_STATE, 0xffffffff); 13484102426fSTomer Tayar 13494102426fSTomer Tayar value = qed_rd(p_hwfn, p_ptt, MCP_REG_CPU_MODE); 13504102426fSTomer Tayar value &= ~MCP_REG_CPU_MODE_SOFT_HALT; 13514102426fSTomer Tayar qed_wr(p_hwfn, p_ptt, MCP_REG_CPU_MODE, value); 13524102426fSTomer Tayar cpu_mode = qed_rd(p_hwfn, p_ptt, MCP_REG_CPU_MODE); 13534102426fSTomer Tayar 13544102426fSTomer Tayar return (cpu_mode & MCP_REG_CPU_MODE_SOFT_HALT) ? -EAGAIN : 0; 13554102426fSTomer Tayar } 13564102426fSTomer Tayar 13570fefbfbaSSudarsana Kalluru int qed_mcp_ov_update_current_config(struct qed_hwfn *p_hwfn, 13580fefbfbaSSudarsana Kalluru struct qed_ptt *p_ptt, 13590fefbfbaSSudarsana Kalluru enum qed_ov_client client) 13600fefbfbaSSudarsana Kalluru { 13610fefbfbaSSudarsana Kalluru u32 resp = 0, param = 0; 13620fefbfbaSSudarsana Kalluru u32 drv_mb_param; 13630fefbfbaSSudarsana Kalluru int rc; 13640fefbfbaSSudarsana Kalluru 13650fefbfbaSSudarsana Kalluru switch (client) { 13660fefbfbaSSudarsana Kalluru case QED_OV_CLIENT_DRV: 13670fefbfbaSSudarsana Kalluru drv_mb_param = DRV_MB_PARAM_OV_CURR_CFG_OS; 13680fefbfbaSSudarsana Kalluru break; 13690fefbfbaSSudarsana Kalluru case QED_OV_CLIENT_USER: 13700fefbfbaSSudarsana Kalluru drv_mb_param = DRV_MB_PARAM_OV_CURR_CFG_OTHER; 13710fefbfbaSSudarsana Kalluru break; 13720fefbfbaSSudarsana Kalluru case QED_OV_CLIENT_VENDOR_SPEC: 13730fefbfbaSSudarsana Kalluru drv_mb_param = DRV_MB_PARAM_OV_CURR_CFG_VENDOR_SPEC; 13740fefbfbaSSudarsana Kalluru break; 13750fefbfbaSSudarsana Kalluru default: 13760fefbfbaSSudarsana Kalluru DP_NOTICE(p_hwfn, "Invalid client type %d\n", client); 13770fefbfbaSSudarsana Kalluru return -EINVAL; 13780fefbfbaSSudarsana Kalluru } 13790fefbfbaSSudarsana Kalluru 13800fefbfbaSSudarsana Kalluru rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_OV_UPDATE_CURR_CFG, 13810fefbfbaSSudarsana Kalluru drv_mb_param, &resp, ¶m); 13820fefbfbaSSudarsana Kalluru if (rc) 13830fefbfbaSSudarsana Kalluru DP_ERR(p_hwfn, "MCP response failure, aborting\n"); 13840fefbfbaSSudarsana Kalluru 13850fefbfbaSSudarsana Kalluru return rc; 13860fefbfbaSSudarsana Kalluru } 13870fefbfbaSSudarsana Kalluru 13880fefbfbaSSudarsana Kalluru int qed_mcp_ov_update_driver_state(struct qed_hwfn *p_hwfn, 13890fefbfbaSSudarsana Kalluru struct qed_ptt *p_ptt, 13900fefbfbaSSudarsana Kalluru enum qed_ov_driver_state drv_state) 13910fefbfbaSSudarsana Kalluru { 13920fefbfbaSSudarsana Kalluru u32 resp = 0, param = 0; 13930fefbfbaSSudarsana Kalluru u32 drv_mb_param; 13940fefbfbaSSudarsana Kalluru int rc; 13950fefbfbaSSudarsana Kalluru 13960fefbfbaSSudarsana Kalluru switch (drv_state) { 13970fefbfbaSSudarsana Kalluru case QED_OV_DRIVER_STATE_NOT_LOADED: 13980fefbfbaSSudarsana Kalluru drv_mb_param = DRV_MSG_CODE_OV_UPDATE_DRIVER_STATE_NOT_LOADED; 13990fefbfbaSSudarsana Kalluru break; 14000fefbfbaSSudarsana Kalluru case QED_OV_DRIVER_STATE_DISABLED: 14010fefbfbaSSudarsana Kalluru drv_mb_param = DRV_MSG_CODE_OV_UPDATE_DRIVER_STATE_DISABLED; 14020fefbfbaSSudarsana Kalluru break; 14030fefbfbaSSudarsana Kalluru case QED_OV_DRIVER_STATE_ACTIVE: 14040fefbfbaSSudarsana Kalluru drv_mb_param = DRV_MSG_CODE_OV_UPDATE_DRIVER_STATE_ACTIVE; 14050fefbfbaSSudarsana Kalluru break; 14060fefbfbaSSudarsana Kalluru default: 14070fefbfbaSSudarsana Kalluru DP_NOTICE(p_hwfn, "Invalid driver state %d\n", drv_state); 14080fefbfbaSSudarsana Kalluru return -EINVAL; 14090fefbfbaSSudarsana Kalluru } 14100fefbfbaSSudarsana Kalluru 14110fefbfbaSSudarsana Kalluru rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_OV_UPDATE_DRIVER_STATE, 14120fefbfbaSSudarsana Kalluru drv_mb_param, &resp, ¶m); 14130fefbfbaSSudarsana Kalluru if (rc) 14140fefbfbaSSudarsana Kalluru DP_ERR(p_hwfn, "Failed to send driver state\n"); 14150fefbfbaSSudarsana Kalluru 14160fefbfbaSSudarsana Kalluru return rc; 14170fefbfbaSSudarsana Kalluru } 14180fefbfbaSSudarsana Kalluru 14190fefbfbaSSudarsana Kalluru int qed_mcp_ov_update_mtu(struct qed_hwfn *p_hwfn, 14200fefbfbaSSudarsana Kalluru struct qed_ptt *p_ptt, u16 mtu) 14210fefbfbaSSudarsana Kalluru { 14220fefbfbaSSudarsana Kalluru u32 resp = 0, param = 0; 14230fefbfbaSSudarsana Kalluru u32 drv_mb_param; 14240fefbfbaSSudarsana Kalluru int rc; 14250fefbfbaSSudarsana Kalluru 14260fefbfbaSSudarsana Kalluru drv_mb_param = (u32)mtu << DRV_MB_PARAM_OV_MTU_SIZE_SHIFT; 14270fefbfbaSSudarsana Kalluru rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_OV_UPDATE_MTU, 14280fefbfbaSSudarsana Kalluru drv_mb_param, &resp, ¶m); 14290fefbfbaSSudarsana Kalluru if (rc) 14300fefbfbaSSudarsana Kalluru DP_ERR(p_hwfn, "Failed to send mtu value, rc = %d\n", rc); 14310fefbfbaSSudarsana Kalluru 14320fefbfbaSSudarsana Kalluru return rc; 14330fefbfbaSSudarsana Kalluru } 14340fefbfbaSSudarsana Kalluru 14350fefbfbaSSudarsana Kalluru int qed_mcp_ov_update_mac(struct qed_hwfn *p_hwfn, 14360fefbfbaSSudarsana Kalluru struct qed_ptt *p_ptt, u8 *mac) 14370fefbfbaSSudarsana Kalluru { 14380fefbfbaSSudarsana Kalluru struct qed_mcp_mb_params mb_params; 14390fefbfbaSSudarsana Kalluru union drv_union_data union_data; 14400fefbfbaSSudarsana Kalluru int rc; 14410fefbfbaSSudarsana Kalluru 14420fefbfbaSSudarsana Kalluru memset(&mb_params, 0, sizeof(mb_params)); 14430fefbfbaSSudarsana Kalluru mb_params.cmd = DRV_MSG_CODE_SET_VMAC; 14440fefbfbaSSudarsana Kalluru mb_params.param = DRV_MSG_CODE_VMAC_TYPE_MAC << 14450fefbfbaSSudarsana Kalluru DRV_MSG_CODE_VMAC_TYPE_SHIFT; 14460fefbfbaSSudarsana Kalluru mb_params.param |= MCP_PF_ID(p_hwfn); 14470fefbfbaSSudarsana Kalluru ether_addr_copy(&union_data.raw_data[0], mac); 14480fefbfbaSSudarsana Kalluru mb_params.p_data_src = &union_data; 14490fefbfbaSSudarsana Kalluru rc = qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 14500fefbfbaSSudarsana Kalluru if (rc) 14510fefbfbaSSudarsana Kalluru DP_ERR(p_hwfn, "Failed to send mac address, rc = %d\n", rc); 14520fefbfbaSSudarsana Kalluru 145314d39648SMintz, Yuval /* Store primary MAC for later possible WoL */ 145414d39648SMintz, Yuval memcpy(p_hwfn->cdev->wol_mac, mac, ETH_ALEN); 145514d39648SMintz, Yuval 14560fefbfbaSSudarsana Kalluru return rc; 14570fefbfbaSSudarsana Kalluru } 14580fefbfbaSSudarsana Kalluru 14590fefbfbaSSudarsana Kalluru int qed_mcp_ov_update_wol(struct qed_hwfn *p_hwfn, 14600fefbfbaSSudarsana Kalluru struct qed_ptt *p_ptt, enum qed_ov_wol wol) 14610fefbfbaSSudarsana Kalluru { 14620fefbfbaSSudarsana Kalluru u32 resp = 0, param = 0; 14630fefbfbaSSudarsana Kalluru u32 drv_mb_param; 14640fefbfbaSSudarsana Kalluru int rc; 14650fefbfbaSSudarsana Kalluru 146614d39648SMintz, Yuval if (p_hwfn->hw_info.b_wol_support == QED_WOL_SUPPORT_NONE) { 146714d39648SMintz, Yuval DP_VERBOSE(p_hwfn, QED_MSG_SP, 146814d39648SMintz, Yuval "Can't change WoL configuration when WoL isn't supported\n"); 146914d39648SMintz, Yuval return -EINVAL; 147014d39648SMintz, Yuval } 147114d39648SMintz, Yuval 14720fefbfbaSSudarsana Kalluru switch (wol) { 14730fefbfbaSSudarsana Kalluru case QED_OV_WOL_DEFAULT: 14740fefbfbaSSudarsana Kalluru drv_mb_param = DRV_MB_PARAM_WOL_DEFAULT; 14750fefbfbaSSudarsana Kalluru break; 14760fefbfbaSSudarsana Kalluru case QED_OV_WOL_DISABLED: 14770fefbfbaSSudarsana Kalluru drv_mb_param = DRV_MB_PARAM_WOL_DISABLED; 14780fefbfbaSSudarsana Kalluru break; 14790fefbfbaSSudarsana Kalluru case QED_OV_WOL_ENABLED: 14800fefbfbaSSudarsana Kalluru drv_mb_param = DRV_MB_PARAM_WOL_ENABLED; 14810fefbfbaSSudarsana Kalluru break; 14820fefbfbaSSudarsana Kalluru default: 14830fefbfbaSSudarsana Kalluru DP_ERR(p_hwfn, "Invalid wol state %d\n", wol); 14840fefbfbaSSudarsana Kalluru return -EINVAL; 14850fefbfbaSSudarsana Kalluru } 14860fefbfbaSSudarsana Kalluru 14870fefbfbaSSudarsana Kalluru rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_OV_UPDATE_WOL, 14880fefbfbaSSudarsana Kalluru drv_mb_param, &resp, ¶m); 14890fefbfbaSSudarsana Kalluru if (rc) 14900fefbfbaSSudarsana Kalluru DP_ERR(p_hwfn, "Failed to send wol mode, rc = %d\n", rc); 14910fefbfbaSSudarsana Kalluru 149214d39648SMintz, Yuval /* Store the WoL update for a future unload */ 149314d39648SMintz, Yuval p_hwfn->cdev->wol_config = (u8)wol; 149414d39648SMintz, Yuval 14950fefbfbaSSudarsana Kalluru return rc; 14960fefbfbaSSudarsana Kalluru } 14970fefbfbaSSudarsana Kalluru 14980fefbfbaSSudarsana Kalluru int qed_mcp_ov_update_eswitch(struct qed_hwfn *p_hwfn, 14990fefbfbaSSudarsana Kalluru struct qed_ptt *p_ptt, 15000fefbfbaSSudarsana Kalluru enum qed_ov_eswitch eswitch) 15010fefbfbaSSudarsana Kalluru { 15020fefbfbaSSudarsana Kalluru u32 resp = 0, param = 0; 15030fefbfbaSSudarsana Kalluru u32 drv_mb_param; 15040fefbfbaSSudarsana Kalluru int rc; 15050fefbfbaSSudarsana Kalluru 15060fefbfbaSSudarsana Kalluru switch (eswitch) { 15070fefbfbaSSudarsana Kalluru case QED_OV_ESWITCH_NONE: 15080fefbfbaSSudarsana Kalluru drv_mb_param = DRV_MB_PARAM_ESWITCH_MODE_NONE; 15090fefbfbaSSudarsana Kalluru break; 15100fefbfbaSSudarsana Kalluru case QED_OV_ESWITCH_VEB: 15110fefbfbaSSudarsana Kalluru drv_mb_param = DRV_MB_PARAM_ESWITCH_MODE_VEB; 15120fefbfbaSSudarsana Kalluru break; 15130fefbfbaSSudarsana Kalluru case QED_OV_ESWITCH_VEPA: 15140fefbfbaSSudarsana Kalluru drv_mb_param = DRV_MB_PARAM_ESWITCH_MODE_VEPA; 15150fefbfbaSSudarsana Kalluru break; 15160fefbfbaSSudarsana Kalluru default: 15170fefbfbaSSudarsana Kalluru DP_ERR(p_hwfn, "Invalid eswitch mode %d\n", eswitch); 15180fefbfbaSSudarsana Kalluru return -EINVAL; 15190fefbfbaSSudarsana Kalluru } 15200fefbfbaSSudarsana Kalluru 15210fefbfbaSSudarsana Kalluru rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_OV_UPDATE_ESWITCH_MODE, 15220fefbfbaSSudarsana Kalluru drv_mb_param, &resp, ¶m); 15230fefbfbaSSudarsana Kalluru if (rc) 15240fefbfbaSSudarsana Kalluru DP_ERR(p_hwfn, "Failed to send eswitch mode, rc = %d\n", rc); 15250fefbfbaSSudarsana Kalluru 15260fefbfbaSSudarsana Kalluru return rc; 15270fefbfbaSSudarsana Kalluru } 15280fefbfbaSSudarsana Kalluru 15291a635e48SYuval Mintz int qed_mcp_set_led(struct qed_hwfn *p_hwfn, 15301a635e48SYuval Mintz struct qed_ptt *p_ptt, enum qed_led_mode mode) 153191420b83SSudarsana Kalluru { 153291420b83SSudarsana Kalluru u32 resp = 0, param = 0, drv_mb_param; 153391420b83SSudarsana Kalluru int rc; 153491420b83SSudarsana Kalluru 153591420b83SSudarsana Kalluru switch (mode) { 153691420b83SSudarsana Kalluru case QED_LED_MODE_ON: 153791420b83SSudarsana Kalluru drv_mb_param = DRV_MB_PARAM_SET_LED_MODE_ON; 153891420b83SSudarsana Kalluru break; 153991420b83SSudarsana Kalluru case QED_LED_MODE_OFF: 154091420b83SSudarsana Kalluru drv_mb_param = DRV_MB_PARAM_SET_LED_MODE_OFF; 154191420b83SSudarsana Kalluru break; 154291420b83SSudarsana Kalluru case QED_LED_MODE_RESTORE: 154391420b83SSudarsana Kalluru drv_mb_param = DRV_MB_PARAM_SET_LED_MODE_OPER; 154491420b83SSudarsana Kalluru break; 154591420b83SSudarsana Kalluru default: 154691420b83SSudarsana Kalluru DP_NOTICE(p_hwfn, "Invalid LED mode %d\n", mode); 154791420b83SSudarsana Kalluru return -EINVAL; 154891420b83SSudarsana Kalluru } 154991420b83SSudarsana Kalluru 155091420b83SSudarsana Kalluru rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_SET_LED_MODE, 155191420b83SSudarsana Kalluru drv_mb_param, &resp, ¶m); 155291420b83SSudarsana Kalluru 155391420b83SSudarsana Kalluru return rc; 155491420b83SSudarsana Kalluru } 155503dc76caSSudarsana Reddy Kalluru 15564102426fSTomer Tayar int qed_mcp_mask_parities(struct qed_hwfn *p_hwfn, 15574102426fSTomer Tayar struct qed_ptt *p_ptt, u32 mask_parities) 15584102426fSTomer Tayar { 15594102426fSTomer Tayar u32 resp = 0, param = 0; 15604102426fSTomer Tayar int rc; 15614102426fSTomer Tayar 15624102426fSTomer Tayar rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_MASK_PARITIES, 15634102426fSTomer Tayar mask_parities, &resp, ¶m); 15644102426fSTomer Tayar 15654102426fSTomer Tayar if (rc) { 15664102426fSTomer Tayar DP_ERR(p_hwfn, 15674102426fSTomer Tayar "MCP response failure for mask parities, aborting\n"); 15684102426fSTomer Tayar } else if (resp != FW_MSG_CODE_OK) { 15694102426fSTomer Tayar DP_ERR(p_hwfn, 15704102426fSTomer Tayar "MCP did not acknowledge mask parity request. Old MFW?\n"); 15714102426fSTomer Tayar rc = -EINVAL; 15724102426fSTomer Tayar } 15734102426fSTomer Tayar 15744102426fSTomer Tayar return rc; 15754102426fSTomer Tayar } 15764102426fSTomer Tayar 15777a4b21b7SMintz, Yuval int qed_mcp_nvm_read(struct qed_dev *cdev, u32 addr, u8 *p_buf, u32 len) 15787a4b21b7SMintz, Yuval { 15797a4b21b7SMintz, Yuval u32 bytes_left = len, offset = 0, bytes_to_copy, read_len = 0; 15807a4b21b7SMintz, Yuval struct qed_hwfn *p_hwfn = QED_LEADING_HWFN(cdev); 15817a4b21b7SMintz, Yuval u32 resp = 0, resp_param = 0; 15827a4b21b7SMintz, Yuval struct qed_ptt *p_ptt; 15837a4b21b7SMintz, Yuval int rc = 0; 15847a4b21b7SMintz, Yuval 15857a4b21b7SMintz, Yuval p_ptt = qed_ptt_acquire(p_hwfn); 15867a4b21b7SMintz, Yuval if (!p_ptt) 15877a4b21b7SMintz, Yuval return -EBUSY; 15887a4b21b7SMintz, Yuval 15897a4b21b7SMintz, Yuval while (bytes_left > 0) { 15907a4b21b7SMintz, Yuval bytes_to_copy = min_t(u32, bytes_left, MCP_DRV_NVM_BUF_LEN); 15917a4b21b7SMintz, Yuval 15927a4b21b7SMintz, Yuval rc = qed_mcp_nvm_rd_cmd(p_hwfn, p_ptt, 15937a4b21b7SMintz, Yuval DRV_MSG_CODE_NVM_READ_NVRAM, 15947a4b21b7SMintz, Yuval addr + offset + 15957a4b21b7SMintz, Yuval (bytes_to_copy << 15967a4b21b7SMintz, Yuval DRV_MB_PARAM_NVM_LEN_SHIFT), 15977a4b21b7SMintz, Yuval &resp, &resp_param, 15987a4b21b7SMintz, Yuval &read_len, 15997a4b21b7SMintz, Yuval (u32 *)(p_buf + offset)); 16007a4b21b7SMintz, Yuval 16017a4b21b7SMintz, Yuval if (rc || (resp != FW_MSG_CODE_NVM_OK)) { 16027a4b21b7SMintz, Yuval DP_NOTICE(cdev, "MCP command rc = %d\n", rc); 16037a4b21b7SMintz, Yuval break; 16047a4b21b7SMintz, Yuval } 16057a4b21b7SMintz, Yuval 16067a4b21b7SMintz, Yuval /* This can be a lengthy process, and it's possible scheduler 16077a4b21b7SMintz, Yuval * isn't preemptable. Sleep a bit to prevent CPU hogging. 16087a4b21b7SMintz, Yuval */ 16097a4b21b7SMintz, Yuval if (bytes_left % 0x1000 < 16107a4b21b7SMintz, Yuval (bytes_left - read_len) % 0x1000) 16117a4b21b7SMintz, Yuval usleep_range(1000, 2000); 16127a4b21b7SMintz, Yuval 16137a4b21b7SMintz, Yuval offset += read_len; 16147a4b21b7SMintz, Yuval bytes_left -= read_len; 16157a4b21b7SMintz, Yuval } 16167a4b21b7SMintz, Yuval 16177a4b21b7SMintz, Yuval cdev->mcp_nvm_resp = resp; 16187a4b21b7SMintz, Yuval qed_ptt_release(p_hwfn, p_ptt); 16197a4b21b7SMintz, Yuval 16207a4b21b7SMintz, Yuval return rc; 16217a4b21b7SMintz, Yuval } 16227a4b21b7SMintz, Yuval 162303dc76caSSudarsana Reddy Kalluru int qed_mcp_bist_register_test(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 162403dc76caSSudarsana Reddy Kalluru { 162503dc76caSSudarsana Reddy Kalluru u32 drv_mb_param = 0, rsp, param; 162603dc76caSSudarsana Reddy Kalluru int rc = 0; 162703dc76caSSudarsana Reddy Kalluru 162803dc76caSSudarsana Reddy Kalluru drv_mb_param = (DRV_MB_PARAM_BIST_REGISTER_TEST << 162903dc76caSSudarsana Reddy Kalluru DRV_MB_PARAM_BIST_TEST_INDEX_SHIFT); 163003dc76caSSudarsana Reddy Kalluru 163103dc76caSSudarsana Reddy Kalluru rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_BIST_TEST, 163203dc76caSSudarsana Reddy Kalluru drv_mb_param, &rsp, ¶m); 163303dc76caSSudarsana Reddy Kalluru 163403dc76caSSudarsana Reddy Kalluru if (rc) 163503dc76caSSudarsana Reddy Kalluru return rc; 163603dc76caSSudarsana Reddy Kalluru 163703dc76caSSudarsana Reddy Kalluru if (((rsp & FW_MSG_CODE_MASK) != FW_MSG_CODE_OK) || 163803dc76caSSudarsana Reddy Kalluru (param != DRV_MB_PARAM_BIST_RC_PASSED)) 163903dc76caSSudarsana Reddy Kalluru rc = -EAGAIN; 164003dc76caSSudarsana Reddy Kalluru 164103dc76caSSudarsana Reddy Kalluru return rc; 164203dc76caSSudarsana Reddy Kalluru } 164303dc76caSSudarsana Reddy Kalluru 164403dc76caSSudarsana Reddy Kalluru int qed_mcp_bist_clock_test(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 164503dc76caSSudarsana Reddy Kalluru { 164603dc76caSSudarsana Reddy Kalluru u32 drv_mb_param, rsp, param; 164703dc76caSSudarsana Reddy Kalluru int rc = 0; 164803dc76caSSudarsana Reddy Kalluru 164903dc76caSSudarsana Reddy Kalluru drv_mb_param = (DRV_MB_PARAM_BIST_CLOCK_TEST << 165003dc76caSSudarsana Reddy Kalluru DRV_MB_PARAM_BIST_TEST_INDEX_SHIFT); 165103dc76caSSudarsana Reddy Kalluru 165203dc76caSSudarsana Reddy Kalluru rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_BIST_TEST, 165303dc76caSSudarsana Reddy Kalluru drv_mb_param, &rsp, ¶m); 165403dc76caSSudarsana Reddy Kalluru 165503dc76caSSudarsana Reddy Kalluru if (rc) 165603dc76caSSudarsana Reddy Kalluru return rc; 165703dc76caSSudarsana Reddy Kalluru 165803dc76caSSudarsana Reddy Kalluru if (((rsp & FW_MSG_CODE_MASK) != FW_MSG_CODE_OK) || 165903dc76caSSudarsana Reddy Kalluru (param != DRV_MB_PARAM_BIST_RC_PASSED)) 166003dc76caSSudarsana Reddy Kalluru rc = -EAGAIN; 166103dc76caSSudarsana Reddy Kalluru 166203dc76caSSudarsana Reddy Kalluru return rc; 166303dc76caSSudarsana Reddy Kalluru } 16647a4b21b7SMintz, Yuval 16657a4b21b7SMintz, Yuval int qed_mcp_bist_nvm_test_get_num_images(struct qed_hwfn *p_hwfn, 16667a4b21b7SMintz, Yuval struct qed_ptt *p_ptt, 16677a4b21b7SMintz, Yuval u32 *num_images) 16687a4b21b7SMintz, Yuval { 16697a4b21b7SMintz, Yuval u32 drv_mb_param = 0, rsp; 16707a4b21b7SMintz, Yuval int rc = 0; 16717a4b21b7SMintz, Yuval 16727a4b21b7SMintz, Yuval drv_mb_param = (DRV_MB_PARAM_BIST_NVM_TEST_NUM_IMAGES << 16737a4b21b7SMintz, Yuval DRV_MB_PARAM_BIST_TEST_INDEX_SHIFT); 16747a4b21b7SMintz, Yuval 16757a4b21b7SMintz, Yuval rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_BIST_TEST, 16767a4b21b7SMintz, Yuval drv_mb_param, &rsp, num_images); 16777a4b21b7SMintz, Yuval if (rc) 16787a4b21b7SMintz, Yuval return rc; 16797a4b21b7SMintz, Yuval 16807a4b21b7SMintz, Yuval if (((rsp & FW_MSG_CODE_MASK) != FW_MSG_CODE_OK)) 16817a4b21b7SMintz, Yuval rc = -EINVAL; 16827a4b21b7SMintz, Yuval 16837a4b21b7SMintz, Yuval return rc; 16847a4b21b7SMintz, Yuval } 16857a4b21b7SMintz, Yuval 16867a4b21b7SMintz, Yuval int qed_mcp_bist_nvm_test_get_image_att(struct qed_hwfn *p_hwfn, 16877a4b21b7SMintz, Yuval struct qed_ptt *p_ptt, 16887a4b21b7SMintz, Yuval struct bist_nvm_image_att *p_image_att, 16897a4b21b7SMintz, Yuval u32 image_index) 16907a4b21b7SMintz, Yuval { 16917a4b21b7SMintz, Yuval u32 buf_size = 0, param, resp = 0, resp_param = 0; 16927a4b21b7SMintz, Yuval int rc; 16937a4b21b7SMintz, Yuval 16947a4b21b7SMintz, Yuval param = DRV_MB_PARAM_BIST_NVM_TEST_IMAGE_BY_INDEX << 16957a4b21b7SMintz, Yuval DRV_MB_PARAM_BIST_TEST_INDEX_SHIFT; 16967a4b21b7SMintz, Yuval param |= image_index << DRV_MB_PARAM_BIST_TEST_IMAGE_INDEX_SHIFT; 16977a4b21b7SMintz, Yuval 16987a4b21b7SMintz, Yuval rc = qed_mcp_nvm_rd_cmd(p_hwfn, p_ptt, 16997a4b21b7SMintz, Yuval DRV_MSG_CODE_BIST_TEST, param, 17007a4b21b7SMintz, Yuval &resp, &resp_param, 17017a4b21b7SMintz, Yuval &buf_size, 17027a4b21b7SMintz, Yuval (u32 *)p_image_att); 17037a4b21b7SMintz, Yuval if (rc) 17047a4b21b7SMintz, Yuval return rc; 17057a4b21b7SMintz, Yuval 17067a4b21b7SMintz, Yuval if (((resp & FW_MSG_CODE_MASK) != FW_MSG_CODE_OK) || 17077a4b21b7SMintz, Yuval (p_image_att->return_code != 1)) 17087a4b21b7SMintz, Yuval rc = -EINVAL; 17097a4b21b7SMintz, Yuval 17107a4b21b7SMintz, Yuval return rc; 17117a4b21b7SMintz, Yuval } 17122edbff8dSTomer Tayar 17132edbff8dSTomer Tayar #define QED_RESC_ALLOC_VERSION_MAJOR 1 17142edbff8dSTomer Tayar #define QED_RESC_ALLOC_VERSION_MINOR 0 17152edbff8dSTomer Tayar #define QED_RESC_ALLOC_VERSION \ 17162edbff8dSTomer Tayar ((QED_RESC_ALLOC_VERSION_MAJOR << \ 17172edbff8dSTomer Tayar DRV_MB_PARAM_RESOURCE_ALLOC_VERSION_MAJOR_SHIFT) | \ 17182edbff8dSTomer Tayar (QED_RESC_ALLOC_VERSION_MINOR << \ 17192edbff8dSTomer Tayar DRV_MB_PARAM_RESOURCE_ALLOC_VERSION_MINOR_SHIFT)) 17202edbff8dSTomer Tayar int qed_mcp_get_resc_info(struct qed_hwfn *p_hwfn, 17212edbff8dSTomer Tayar struct qed_ptt *p_ptt, 17222edbff8dSTomer Tayar struct resource_info *p_resc_info, 17232edbff8dSTomer Tayar u32 *p_mcp_resp, u32 *p_mcp_param) 17242edbff8dSTomer Tayar { 17252edbff8dSTomer Tayar struct qed_mcp_mb_params mb_params; 1726bb480242SMintz, Yuval union drv_union_data union_data; 17272edbff8dSTomer Tayar int rc; 17282edbff8dSTomer Tayar 17292edbff8dSTomer Tayar memset(&mb_params, 0, sizeof(mb_params)); 1730bb480242SMintz, Yuval memset(&union_data, 0, sizeof(union_data)); 17312edbff8dSTomer Tayar mb_params.cmd = DRV_MSG_GET_RESOURCE_ALLOC_MSG; 17322edbff8dSTomer Tayar mb_params.param = QED_RESC_ALLOC_VERSION; 1733bb480242SMintz, Yuval 1734bb480242SMintz, Yuval /* Need to have a sufficient large struct, as the cmd_and_union 1735bb480242SMintz, Yuval * is going to do memcpy from and to it. 1736bb480242SMintz, Yuval */ 1737bb480242SMintz, Yuval memcpy(&union_data.resource, p_resc_info, sizeof(*p_resc_info)); 1738bb480242SMintz, Yuval 1739bb480242SMintz, Yuval mb_params.p_data_src = &union_data; 1740bb480242SMintz, Yuval mb_params.p_data_dst = &union_data; 17412edbff8dSTomer Tayar rc = qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 17422edbff8dSTomer Tayar if (rc) 17432edbff8dSTomer Tayar return rc; 17442edbff8dSTomer Tayar 1745bb480242SMintz, Yuval /* Copy the data back */ 1746bb480242SMintz, Yuval memcpy(p_resc_info, &union_data.resource, sizeof(*p_resc_info)); 17472edbff8dSTomer Tayar *p_mcp_resp = mb_params.mcp_resp; 17482edbff8dSTomer Tayar *p_mcp_param = mb_params.mcp_param; 17492edbff8dSTomer Tayar 17502edbff8dSTomer Tayar DP_VERBOSE(p_hwfn, 17512edbff8dSTomer Tayar QED_MSG_SP, 17522edbff8dSTomer Tayar "MFW resource_info: version 0x%x, res_id 0x%x, size 0x%x, offset 0x%x, vf_size 0x%x, vf_offset 0x%x, flags 0x%x\n", 17532edbff8dSTomer Tayar *p_mcp_param, 17542edbff8dSTomer Tayar p_resc_info->res_id, 17552edbff8dSTomer Tayar p_resc_info->size, 17562edbff8dSTomer Tayar p_resc_info->offset, 17572edbff8dSTomer Tayar p_resc_info->vf_size, 17582edbff8dSTomer Tayar p_resc_info->vf_offset, p_resc_info->flags); 17592edbff8dSTomer Tayar 17602edbff8dSTomer Tayar return 0; 17612edbff8dSTomer Tayar } 1762