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); 19565ed2ffdSMintz, Yuval spin_lock_init(&p_info->link_lock); 196fe56b9e6SYuval Mintz 197fe56b9e6SYuval Mintz return 0; 198fe56b9e6SYuval Mintz 199fe56b9e6SYuval Mintz err: 200fe56b9e6SYuval Mintz qed_mcp_free(p_hwfn); 201fe56b9e6SYuval Mintz return -ENOMEM; 202fe56b9e6SYuval Mintz } 203fe56b9e6SYuval Mintz 2045529bad9STomer Tayar /* Locks the MFW mailbox of a PF to ensure a single access. 2055529bad9STomer Tayar * The lock is achieved in most cases by holding a spinlock, causing other 2065529bad9STomer Tayar * threads to wait till a previous access is done. 2075529bad9STomer Tayar * In some cases (currently when a [UN]LOAD_REQ commands are sent), the single 2085529bad9STomer Tayar * access is achieved by setting a blocking flag, which will fail other 2095529bad9STomer Tayar * competing contexts to send their mailboxes. 2105529bad9STomer Tayar */ 2111a635e48SYuval Mintz static int qed_mcp_mb_lock(struct qed_hwfn *p_hwfn, u32 cmd) 2125529bad9STomer Tayar { 2135529bad9STomer Tayar spin_lock_bh(&p_hwfn->mcp_info->lock); 2145529bad9STomer Tayar 2155529bad9STomer Tayar /* The spinlock shouldn't be acquired when the mailbox command is 2165529bad9STomer Tayar * [UN]LOAD_REQ, since the engine is locked by the MFW, and a parallel 2175529bad9STomer Tayar * pending [UN]LOAD_REQ command of another PF together with a spinlock 2185529bad9STomer Tayar * (i.e. interrupts are disabled) - can lead to a deadlock. 2195529bad9STomer Tayar * It is assumed that for a single PF, no other mailbox commands can be 2205529bad9STomer Tayar * sent from another context while sending LOAD_REQ, and that any 2215529bad9STomer Tayar * parallel commands to UNLOAD_REQ can be cancelled. 2225529bad9STomer Tayar */ 2235529bad9STomer Tayar if (cmd == DRV_MSG_CODE_LOAD_DONE || cmd == DRV_MSG_CODE_UNLOAD_DONE) 2245529bad9STomer Tayar p_hwfn->mcp_info->block_mb_sending = false; 2255529bad9STomer Tayar 2265529bad9STomer Tayar if (p_hwfn->mcp_info->block_mb_sending) { 2275529bad9STomer Tayar DP_NOTICE(p_hwfn, 2285529bad9STomer Tayar "Trying to send a MFW mailbox command [0x%x] in parallel to [UN]LOAD_REQ. Aborting.\n", 2295529bad9STomer Tayar cmd); 2305529bad9STomer Tayar spin_unlock_bh(&p_hwfn->mcp_info->lock); 2315529bad9STomer Tayar return -EBUSY; 2325529bad9STomer Tayar } 2335529bad9STomer Tayar 2345529bad9STomer Tayar if (cmd == DRV_MSG_CODE_LOAD_REQ || cmd == DRV_MSG_CODE_UNLOAD_REQ) { 2355529bad9STomer Tayar p_hwfn->mcp_info->block_mb_sending = true; 2365529bad9STomer Tayar spin_unlock_bh(&p_hwfn->mcp_info->lock); 2375529bad9STomer Tayar } 2385529bad9STomer Tayar 2395529bad9STomer Tayar return 0; 2405529bad9STomer Tayar } 2415529bad9STomer Tayar 2421a635e48SYuval Mintz static void qed_mcp_mb_unlock(struct qed_hwfn *p_hwfn, u32 cmd) 2435529bad9STomer Tayar { 2445529bad9STomer Tayar if (cmd != DRV_MSG_CODE_LOAD_REQ && cmd != DRV_MSG_CODE_UNLOAD_REQ) 2455529bad9STomer Tayar spin_unlock_bh(&p_hwfn->mcp_info->lock); 2465529bad9STomer Tayar } 2475529bad9STomer Tayar 2481a635e48SYuval Mintz int qed_mcp_reset(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 249fe56b9e6SYuval Mintz { 250fe56b9e6SYuval Mintz u32 seq = ++p_hwfn->mcp_info->drv_mb_seq; 251fe56b9e6SYuval Mintz u8 delay = CHIP_MCP_RESP_ITER_US; 252fe56b9e6SYuval Mintz u32 org_mcp_reset_seq, cnt = 0; 253fe56b9e6SYuval Mintz int rc = 0; 254fe56b9e6SYuval Mintz 2555529bad9STomer Tayar /* Ensure that only a single thread is accessing the mailbox at a 2565529bad9STomer Tayar * certain time. 2575529bad9STomer Tayar */ 2585529bad9STomer Tayar rc = qed_mcp_mb_lock(p_hwfn, DRV_MSG_CODE_MCP_RESET); 2595529bad9STomer Tayar if (rc != 0) 2605529bad9STomer Tayar return rc; 2615529bad9STomer Tayar 262fe56b9e6SYuval Mintz /* Set drv command along with the updated sequence */ 263fe56b9e6SYuval Mintz org_mcp_reset_seq = qed_rd(p_hwfn, p_ptt, MISCS_REG_GENERIC_POR_0); 264fe56b9e6SYuval Mintz DRV_MB_WR(p_hwfn, p_ptt, drv_mb_header, 265fe56b9e6SYuval Mintz (DRV_MSG_CODE_MCP_RESET | seq)); 266fe56b9e6SYuval Mintz 267fe56b9e6SYuval Mintz do { 268fe56b9e6SYuval Mintz /* Wait for MFW response */ 269fe56b9e6SYuval Mintz udelay(delay); 270fe56b9e6SYuval Mintz /* Give the FW up to 500 second (50*1000*10usec) */ 271fe56b9e6SYuval Mintz } while ((org_mcp_reset_seq == qed_rd(p_hwfn, p_ptt, 272fe56b9e6SYuval Mintz MISCS_REG_GENERIC_POR_0)) && 273fe56b9e6SYuval Mintz (cnt++ < QED_MCP_RESET_RETRIES)); 274fe56b9e6SYuval Mintz 275fe56b9e6SYuval Mintz if (org_mcp_reset_seq != 276fe56b9e6SYuval Mintz qed_rd(p_hwfn, p_ptt, MISCS_REG_GENERIC_POR_0)) { 277fe56b9e6SYuval Mintz DP_VERBOSE(p_hwfn, QED_MSG_SP, 278fe56b9e6SYuval Mintz "MCP was reset after %d usec\n", cnt * delay); 279fe56b9e6SYuval Mintz } else { 280fe56b9e6SYuval Mintz DP_ERR(p_hwfn, "Failed to reset MCP\n"); 281fe56b9e6SYuval Mintz rc = -EAGAIN; 282fe56b9e6SYuval Mintz } 283fe56b9e6SYuval Mintz 2845529bad9STomer Tayar qed_mcp_mb_unlock(p_hwfn, DRV_MSG_CODE_MCP_RESET); 2855529bad9STomer Tayar 286fe56b9e6SYuval Mintz return rc; 287fe56b9e6SYuval Mintz } 288fe56b9e6SYuval Mintz 289fe56b9e6SYuval Mintz static int qed_do_mcp_cmd(struct qed_hwfn *p_hwfn, 290fe56b9e6SYuval Mintz struct qed_ptt *p_ptt, 291fe56b9e6SYuval Mintz u32 cmd, 292fe56b9e6SYuval Mintz u32 param, 293fe56b9e6SYuval Mintz u32 *o_mcp_resp, 294fe56b9e6SYuval Mintz u32 *o_mcp_param) 295fe56b9e6SYuval Mintz { 296fe56b9e6SYuval Mintz u8 delay = CHIP_MCP_RESP_ITER_US; 297fe56b9e6SYuval Mintz u32 seq, cnt = 1, actual_mb_seq; 298fe56b9e6SYuval Mintz int rc = 0; 299fe56b9e6SYuval Mintz 300fe56b9e6SYuval Mintz /* Get actual driver mailbox sequence */ 301fe56b9e6SYuval Mintz actual_mb_seq = DRV_MB_RD(p_hwfn, p_ptt, drv_mb_header) & 302fe56b9e6SYuval Mintz DRV_MSG_SEQ_NUMBER_MASK; 303fe56b9e6SYuval Mintz 304fe56b9e6SYuval Mintz /* Use MCP history register to check if MCP reset occurred between 305fe56b9e6SYuval Mintz * init time and now. 306fe56b9e6SYuval Mintz */ 307fe56b9e6SYuval Mintz if (p_hwfn->mcp_info->mcp_hist != 308fe56b9e6SYuval Mintz qed_rd(p_hwfn, p_ptt, MISCS_REG_GENERIC_POR_0)) { 309fe56b9e6SYuval Mintz DP_VERBOSE(p_hwfn, QED_MSG_SP, "Rereading MCP offsets\n"); 310fe56b9e6SYuval Mintz qed_load_mcp_offsets(p_hwfn, p_ptt); 311fe56b9e6SYuval Mintz qed_mcp_cmd_port_init(p_hwfn, p_ptt); 312fe56b9e6SYuval Mintz } 313fe56b9e6SYuval Mintz seq = ++p_hwfn->mcp_info->drv_mb_seq; 314fe56b9e6SYuval Mintz 315fe56b9e6SYuval Mintz /* Set drv param */ 316fe56b9e6SYuval Mintz DRV_MB_WR(p_hwfn, p_ptt, drv_mb_param, param); 317fe56b9e6SYuval Mintz 318fe56b9e6SYuval Mintz /* Set drv command along with the updated sequence */ 319fe56b9e6SYuval Mintz DRV_MB_WR(p_hwfn, p_ptt, drv_mb_header, (cmd | seq)); 320fe56b9e6SYuval Mintz 321fe56b9e6SYuval Mintz DP_VERBOSE(p_hwfn, QED_MSG_SP, 322fe56b9e6SYuval Mintz "wrote command (%x) to MFW MB param 0x%08x\n", 323fe56b9e6SYuval Mintz (cmd | seq), param); 324fe56b9e6SYuval Mintz 325fe56b9e6SYuval Mintz do { 326fe56b9e6SYuval Mintz /* Wait for MFW response */ 327fe56b9e6SYuval Mintz udelay(delay); 328fe56b9e6SYuval Mintz *o_mcp_resp = DRV_MB_RD(p_hwfn, p_ptt, fw_mb_header); 329fe56b9e6SYuval Mintz 330fe56b9e6SYuval Mintz /* Give the FW up to 5 second (500*10ms) */ 331fe56b9e6SYuval Mintz } while ((seq != (*o_mcp_resp & FW_MSG_SEQ_NUMBER_MASK)) && 332fe56b9e6SYuval Mintz (cnt++ < QED_DRV_MB_MAX_RETRIES)); 333fe56b9e6SYuval Mintz 334fe56b9e6SYuval Mintz DP_VERBOSE(p_hwfn, QED_MSG_SP, 335fe56b9e6SYuval Mintz "[after %d ms] read (%x) seq is (%x) from FW MB\n", 336fe56b9e6SYuval Mintz cnt * delay, *o_mcp_resp, seq); 337fe56b9e6SYuval Mintz 338fe56b9e6SYuval Mintz /* Is this a reply to our command? */ 339fe56b9e6SYuval Mintz if (seq == (*o_mcp_resp & FW_MSG_SEQ_NUMBER_MASK)) { 340fe56b9e6SYuval Mintz *o_mcp_resp &= FW_MSG_CODE_MASK; 341fe56b9e6SYuval Mintz /* Get the MCP param */ 342fe56b9e6SYuval Mintz *o_mcp_param = DRV_MB_RD(p_hwfn, p_ptt, fw_mb_param); 343fe56b9e6SYuval Mintz } else { 344fe56b9e6SYuval Mintz /* FW BUG! */ 345525ef5c0SYuval Mintz DP_ERR(p_hwfn, "MFW failed to respond [cmd 0x%x param 0x%x]\n", 346525ef5c0SYuval Mintz cmd, param); 347fe56b9e6SYuval Mintz *o_mcp_resp = 0; 348fe56b9e6SYuval Mintz rc = -EAGAIN; 349fe56b9e6SYuval Mintz } 350fe56b9e6SYuval Mintz return rc; 351fe56b9e6SYuval Mintz } 352fe56b9e6SYuval Mintz 3535529bad9STomer Tayar static int qed_mcp_cmd_and_union(struct qed_hwfn *p_hwfn, 354fe56b9e6SYuval Mintz struct qed_ptt *p_ptt, 3555529bad9STomer Tayar struct qed_mcp_mb_params *p_mb_params) 356fe56b9e6SYuval Mintz { 3575529bad9STomer Tayar u32 union_data_addr; 35814d39648SMintz, Yuval 3595529bad9STomer Tayar int rc; 360fe56b9e6SYuval Mintz 361fe56b9e6SYuval Mintz /* MCP not initialized */ 362fe56b9e6SYuval Mintz if (!qed_mcp_is_init(p_hwfn)) { 363fe56b9e6SYuval Mintz DP_NOTICE(p_hwfn, "MFW is not initialized!\n"); 364fe56b9e6SYuval Mintz return -EBUSY; 365fe56b9e6SYuval Mintz } 366fe56b9e6SYuval Mintz 3675529bad9STomer Tayar union_data_addr = p_hwfn->mcp_info->drv_mb_addr + 3685529bad9STomer Tayar offsetof(struct public_drv_mb, union_data); 3695529bad9STomer Tayar 3705529bad9STomer Tayar /* Ensure that only a single thread is accessing the mailbox at a 3715529bad9STomer Tayar * certain time. 372fe56b9e6SYuval Mintz */ 3735529bad9STomer Tayar rc = qed_mcp_mb_lock(p_hwfn, p_mb_params->cmd); 3745529bad9STomer Tayar if (rc) 3755529bad9STomer Tayar return rc; 3765529bad9STomer Tayar 3775529bad9STomer Tayar if (p_mb_params->p_data_src != NULL) 3785529bad9STomer Tayar qed_memcpy_to(p_hwfn, p_ptt, union_data_addr, 3795529bad9STomer Tayar p_mb_params->p_data_src, 3805529bad9STomer Tayar sizeof(*p_mb_params->p_data_src)); 3815529bad9STomer Tayar 3825529bad9STomer Tayar rc = qed_do_mcp_cmd(p_hwfn, p_ptt, p_mb_params->cmd, 3835529bad9STomer Tayar p_mb_params->param, &p_mb_params->mcp_resp, 3845529bad9STomer Tayar &p_mb_params->mcp_param); 3855529bad9STomer Tayar 3865529bad9STomer Tayar if (p_mb_params->p_data_dst != NULL) 3875529bad9STomer Tayar qed_memcpy_from(p_hwfn, p_ptt, p_mb_params->p_data_dst, 3885529bad9STomer Tayar union_data_addr, 3895529bad9STomer Tayar sizeof(*p_mb_params->p_data_dst)); 3905529bad9STomer Tayar 3915529bad9STomer Tayar qed_mcp_mb_unlock(p_hwfn, p_mb_params->cmd); 392fe56b9e6SYuval Mintz 393fe56b9e6SYuval Mintz return rc; 394fe56b9e6SYuval Mintz } 395fe56b9e6SYuval Mintz 3965529bad9STomer Tayar int qed_mcp_cmd(struct qed_hwfn *p_hwfn, 3975529bad9STomer Tayar struct qed_ptt *p_ptt, 3985529bad9STomer Tayar u32 cmd, 3995529bad9STomer Tayar u32 param, 4005529bad9STomer Tayar u32 *o_mcp_resp, 4015529bad9STomer Tayar u32 *o_mcp_param) 402fe56b9e6SYuval Mintz { 4035529bad9STomer Tayar struct qed_mcp_mb_params mb_params; 40414d39648SMintz, Yuval union drv_union_data data_src; 4055529bad9STomer Tayar int rc; 406fe56b9e6SYuval Mintz 4075529bad9STomer Tayar memset(&mb_params, 0, sizeof(mb_params)); 40814d39648SMintz, Yuval memset(&data_src, 0, sizeof(data_src)); 4095529bad9STomer Tayar mb_params.cmd = cmd; 4105529bad9STomer Tayar mb_params.param = param; 41114d39648SMintz, Yuval 41214d39648SMintz, Yuval /* In case of UNLOAD_DONE, set the primary MAC */ 41314d39648SMintz, Yuval if ((cmd == DRV_MSG_CODE_UNLOAD_DONE) && 41414d39648SMintz, Yuval (p_hwfn->cdev->wol_config == QED_OV_WOL_ENABLED)) { 41514d39648SMintz, Yuval u8 *p_mac = p_hwfn->cdev->wol_mac; 41614d39648SMintz, Yuval 41714d39648SMintz, Yuval data_src.wol_mac.mac_upper = p_mac[0] << 8 | p_mac[1]; 41814d39648SMintz, Yuval data_src.wol_mac.mac_lower = p_mac[2] << 24 | p_mac[3] << 16 | 41914d39648SMintz, Yuval p_mac[4] << 8 | p_mac[5]; 42014d39648SMintz, Yuval 42114d39648SMintz, Yuval DP_VERBOSE(p_hwfn, 42214d39648SMintz, Yuval (QED_MSG_SP | NETIF_MSG_IFDOWN), 42314d39648SMintz, Yuval "Setting WoL MAC: %pM --> [%08x,%08x]\n", 42414d39648SMintz, Yuval p_mac, data_src.wol_mac.mac_upper, 42514d39648SMintz, Yuval data_src.wol_mac.mac_lower); 42614d39648SMintz, Yuval 42714d39648SMintz, Yuval mb_params.p_data_src = &data_src; 42814d39648SMintz, Yuval } 42914d39648SMintz, Yuval 4305529bad9STomer Tayar rc = qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 4315529bad9STomer Tayar if (rc) 4325529bad9STomer Tayar return rc; 4335529bad9STomer Tayar 4345529bad9STomer Tayar *o_mcp_resp = mb_params.mcp_resp; 4355529bad9STomer Tayar *o_mcp_param = mb_params.mcp_param; 4365529bad9STomer Tayar 4375529bad9STomer Tayar return 0; 438fe56b9e6SYuval Mintz } 439fe56b9e6SYuval Mintz 4404102426fSTomer Tayar int qed_mcp_nvm_rd_cmd(struct qed_hwfn *p_hwfn, 4414102426fSTomer Tayar struct qed_ptt *p_ptt, 4424102426fSTomer Tayar u32 cmd, 4434102426fSTomer Tayar u32 param, 4444102426fSTomer Tayar u32 *o_mcp_resp, 4454102426fSTomer Tayar u32 *o_mcp_param, u32 *o_txn_size, u32 *o_buf) 4464102426fSTomer Tayar { 4474102426fSTomer Tayar struct qed_mcp_mb_params mb_params; 4484102426fSTomer Tayar union drv_union_data union_data; 4494102426fSTomer Tayar int rc; 4504102426fSTomer Tayar 4514102426fSTomer Tayar memset(&mb_params, 0, sizeof(mb_params)); 4524102426fSTomer Tayar mb_params.cmd = cmd; 4534102426fSTomer Tayar mb_params.param = param; 4544102426fSTomer Tayar mb_params.p_data_dst = &union_data; 4554102426fSTomer Tayar rc = qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 4564102426fSTomer Tayar if (rc) 4574102426fSTomer Tayar return rc; 4584102426fSTomer Tayar 4594102426fSTomer Tayar *o_mcp_resp = mb_params.mcp_resp; 4604102426fSTomer Tayar *o_mcp_param = mb_params.mcp_param; 4614102426fSTomer Tayar 4624102426fSTomer Tayar *o_txn_size = *o_mcp_param; 4634102426fSTomer Tayar memcpy(o_buf, &union_data.raw_data, *o_txn_size); 4644102426fSTomer Tayar 4654102426fSTomer Tayar return 0; 4664102426fSTomer Tayar } 4674102426fSTomer Tayar 468fe56b9e6SYuval Mintz int qed_mcp_load_req(struct qed_hwfn *p_hwfn, 4691a635e48SYuval Mintz struct qed_ptt *p_ptt, u32 *p_load_code) 470fe56b9e6SYuval Mintz { 471fe56b9e6SYuval Mintz struct qed_dev *cdev = p_hwfn->cdev; 4725529bad9STomer Tayar struct qed_mcp_mb_params mb_params; 4735529bad9STomer Tayar union drv_union_data union_data; 474fe56b9e6SYuval Mintz int rc; 475fe56b9e6SYuval Mintz 4765529bad9STomer Tayar memset(&mb_params, 0, sizeof(mb_params)); 477fe56b9e6SYuval Mintz /* Load Request */ 4785529bad9STomer Tayar mb_params.cmd = DRV_MSG_CODE_LOAD_REQ; 4795529bad9STomer Tayar mb_params.param = PDA_COMP | DRV_ID_MCP_HSI_VER_CURRENT | 4805529bad9STomer Tayar cdev->drv_type; 4815529bad9STomer Tayar memcpy(&union_data.ver_str, cdev->ver_str, MCP_DRV_VER_STR_SIZE); 4825529bad9STomer Tayar mb_params.p_data_src = &union_data; 4835529bad9STomer Tayar rc = qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 484fe56b9e6SYuval Mintz 485fe56b9e6SYuval Mintz /* if mcp fails to respond we must abort */ 486fe56b9e6SYuval Mintz if (rc) { 487fe56b9e6SYuval Mintz DP_ERR(p_hwfn, "MCP response failure, aborting\n"); 488fe56b9e6SYuval Mintz return rc; 489fe56b9e6SYuval Mintz } 490fe56b9e6SYuval Mintz 4915529bad9STomer Tayar *p_load_code = mb_params.mcp_resp; 4925529bad9STomer Tayar 493fe56b9e6SYuval Mintz /* If MFW refused (e.g. other port is in diagnostic mode) we 494fe56b9e6SYuval Mintz * must abort. This can happen in the following cases: 495fe56b9e6SYuval Mintz * - Other port is in diagnostic mode 496fe56b9e6SYuval Mintz * - Previously loaded function on the engine is not compliant with 497fe56b9e6SYuval Mintz * the requester. 498fe56b9e6SYuval Mintz * - MFW cannot cope with the requester's DRV_MFW_HSI_VERSION. 499fe56b9e6SYuval Mintz * - 500fe56b9e6SYuval Mintz */ 501fe56b9e6SYuval Mintz if (!(*p_load_code) || 502fe56b9e6SYuval Mintz ((*p_load_code) == FW_MSG_CODE_DRV_LOAD_REFUSED_HSI) || 503fe56b9e6SYuval Mintz ((*p_load_code) == FW_MSG_CODE_DRV_LOAD_REFUSED_PDA) || 504fe56b9e6SYuval Mintz ((*p_load_code) == FW_MSG_CODE_DRV_LOAD_REFUSED_DIAG)) { 505fe56b9e6SYuval Mintz DP_ERR(p_hwfn, "MCP refused load request, aborting\n"); 506fe56b9e6SYuval Mintz return -EBUSY; 507fe56b9e6SYuval Mintz } 508fe56b9e6SYuval Mintz 509fe56b9e6SYuval Mintz return 0; 510fe56b9e6SYuval Mintz } 511fe56b9e6SYuval Mintz 5120b55e27dSYuval Mintz static void qed_mcp_handle_vf_flr(struct qed_hwfn *p_hwfn, 5130b55e27dSYuval Mintz struct qed_ptt *p_ptt) 5140b55e27dSYuval Mintz { 5150b55e27dSYuval Mintz u32 addr = SECTION_OFFSIZE_ADDR(p_hwfn->mcp_info->public_base, 5160b55e27dSYuval Mintz PUBLIC_PATH); 5170b55e27dSYuval Mintz u32 mfw_path_offsize = qed_rd(p_hwfn, p_ptt, addr); 5180b55e27dSYuval Mintz u32 path_addr = SECTION_ADDR(mfw_path_offsize, 5190b55e27dSYuval Mintz QED_PATH_ID(p_hwfn)); 5200b55e27dSYuval Mintz u32 disabled_vfs[VF_MAX_STATIC / 32]; 5210b55e27dSYuval Mintz int i; 5220b55e27dSYuval Mintz 5230b55e27dSYuval Mintz DP_VERBOSE(p_hwfn, 5240b55e27dSYuval Mintz QED_MSG_SP, 5250b55e27dSYuval Mintz "Reading Disabled VF information from [offset %08x], path_addr %08x\n", 5260b55e27dSYuval Mintz mfw_path_offsize, path_addr); 5270b55e27dSYuval Mintz 5280b55e27dSYuval Mintz for (i = 0; i < (VF_MAX_STATIC / 32); i++) { 5290b55e27dSYuval Mintz disabled_vfs[i] = qed_rd(p_hwfn, p_ptt, 5300b55e27dSYuval Mintz path_addr + 5310b55e27dSYuval Mintz offsetof(struct public_path, 5320b55e27dSYuval Mintz mcp_vf_disabled) + 5330b55e27dSYuval Mintz sizeof(u32) * i); 5340b55e27dSYuval Mintz DP_VERBOSE(p_hwfn, (QED_MSG_SP | QED_MSG_IOV), 5350b55e27dSYuval Mintz "FLR-ed VFs [%08x,...,%08x] - %08x\n", 5360b55e27dSYuval Mintz i * 32, (i + 1) * 32 - 1, disabled_vfs[i]); 5370b55e27dSYuval Mintz } 5380b55e27dSYuval Mintz 5390b55e27dSYuval Mintz if (qed_iov_mark_vf_flr(p_hwfn, disabled_vfs)) 5400b55e27dSYuval Mintz qed_schedule_iov(p_hwfn, QED_IOV_WQ_FLR_FLAG); 5410b55e27dSYuval Mintz } 5420b55e27dSYuval Mintz 5430b55e27dSYuval Mintz int qed_mcp_ack_vf_flr(struct qed_hwfn *p_hwfn, 5440b55e27dSYuval Mintz struct qed_ptt *p_ptt, u32 *vfs_to_ack) 5450b55e27dSYuval Mintz { 5460b55e27dSYuval Mintz u32 addr = SECTION_OFFSIZE_ADDR(p_hwfn->mcp_info->public_base, 5470b55e27dSYuval Mintz PUBLIC_FUNC); 5480b55e27dSYuval Mintz u32 mfw_func_offsize = qed_rd(p_hwfn, p_ptt, addr); 5490b55e27dSYuval Mintz u32 func_addr = SECTION_ADDR(mfw_func_offsize, 5500b55e27dSYuval Mintz MCP_PF_ID(p_hwfn)); 5510b55e27dSYuval Mintz struct qed_mcp_mb_params mb_params; 5520b55e27dSYuval Mintz union drv_union_data union_data; 5530b55e27dSYuval Mintz int rc; 5540b55e27dSYuval Mintz int i; 5550b55e27dSYuval Mintz 5560b55e27dSYuval Mintz for (i = 0; i < (VF_MAX_STATIC / 32); i++) 5570b55e27dSYuval Mintz DP_VERBOSE(p_hwfn, (QED_MSG_SP | QED_MSG_IOV), 5580b55e27dSYuval Mintz "Acking VFs [%08x,...,%08x] - %08x\n", 5590b55e27dSYuval Mintz i * 32, (i + 1) * 32 - 1, vfs_to_ack[i]); 5600b55e27dSYuval Mintz 5610b55e27dSYuval Mintz memset(&mb_params, 0, sizeof(mb_params)); 5620b55e27dSYuval Mintz mb_params.cmd = DRV_MSG_CODE_VF_DISABLED_DONE; 5630b55e27dSYuval Mintz memcpy(&union_data.ack_vf_disabled, vfs_to_ack, VF_MAX_STATIC / 8); 5640b55e27dSYuval Mintz mb_params.p_data_src = &union_data; 5650b55e27dSYuval Mintz rc = qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 5660b55e27dSYuval Mintz if (rc) { 5670b55e27dSYuval Mintz DP_NOTICE(p_hwfn, "Failed to pass ACK for VF flr to MFW\n"); 5680b55e27dSYuval Mintz return -EBUSY; 5690b55e27dSYuval Mintz } 5700b55e27dSYuval Mintz 5710b55e27dSYuval Mintz /* Clear the ACK bits */ 5720b55e27dSYuval Mintz for (i = 0; i < (VF_MAX_STATIC / 32); i++) 5730b55e27dSYuval Mintz qed_wr(p_hwfn, p_ptt, 5740b55e27dSYuval Mintz func_addr + 5750b55e27dSYuval Mintz offsetof(struct public_func, drv_ack_vf_disabled) + 5760b55e27dSYuval Mintz i * sizeof(u32), 0); 5770b55e27dSYuval Mintz 5780b55e27dSYuval Mintz return rc; 5790b55e27dSYuval Mintz } 5800b55e27dSYuval Mintz 581334c03b5SZvi Nachmani static void qed_mcp_handle_transceiver_change(struct qed_hwfn *p_hwfn, 582334c03b5SZvi Nachmani struct qed_ptt *p_ptt) 583334c03b5SZvi Nachmani { 584334c03b5SZvi Nachmani u32 transceiver_state; 585334c03b5SZvi Nachmani 586334c03b5SZvi Nachmani transceiver_state = qed_rd(p_hwfn, p_ptt, 587334c03b5SZvi Nachmani p_hwfn->mcp_info->port_addr + 588334c03b5SZvi Nachmani offsetof(struct public_port, 589334c03b5SZvi Nachmani transceiver_data)); 590334c03b5SZvi Nachmani 591334c03b5SZvi Nachmani DP_VERBOSE(p_hwfn, 592334c03b5SZvi Nachmani (NETIF_MSG_HW | QED_MSG_SP), 593334c03b5SZvi Nachmani "Received transceiver state update [0x%08x] from mfw [Addr 0x%x]\n", 594334c03b5SZvi Nachmani transceiver_state, 595334c03b5SZvi Nachmani (u32)(p_hwfn->mcp_info->port_addr + 5961a635e48SYuval Mintz offsetof(struct public_port, transceiver_data))); 597334c03b5SZvi Nachmani 598334c03b5SZvi Nachmani transceiver_state = GET_FIELD(transceiver_state, 599351a4dedSYuval Mintz ETH_TRANSCEIVER_STATE); 600334c03b5SZvi Nachmani 601351a4dedSYuval Mintz if (transceiver_state == ETH_TRANSCEIVER_STATE_PRESENT) 602334c03b5SZvi Nachmani DP_NOTICE(p_hwfn, "Transceiver is present.\n"); 603334c03b5SZvi Nachmani else 604334c03b5SZvi Nachmani DP_NOTICE(p_hwfn, "Transceiver is unplugged.\n"); 605334c03b5SZvi Nachmani } 606334c03b5SZvi Nachmani 607cc875c2eSYuval Mintz static void qed_mcp_handle_link_change(struct qed_hwfn *p_hwfn, 6081a635e48SYuval Mintz struct qed_ptt *p_ptt, bool b_reset) 609cc875c2eSYuval Mintz { 610cc875c2eSYuval Mintz struct qed_mcp_link_state *p_link; 611a64b02d5SManish Chopra u8 max_bw, min_bw; 612cc875c2eSYuval Mintz u32 status = 0; 613cc875c2eSYuval Mintz 61465ed2ffdSMintz, Yuval /* Prevent SW/attentions from doing this at the same time */ 61565ed2ffdSMintz, Yuval spin_lock_bh(&p_hwfn->mcp_info->link_lock); 61665ed2ffdSMintz, Yuval 617cc875c2eSYuval Mintz p_link = &p_hwfn->mcp_info->link_output; 618cc875c2eSYuval Mintz memset(p_link, 0, sizeof(*p_link)); 619cc875c2eSYuval Mintz if (!b_reset) { 620cc875c2eSYuval Mintz status = qed_rd(p_hwfn, p_ptt, 621cc875c2eSYuval Mintz p_hwfn->mcp_info->port_addr + 622cc875c2eSYuval Mintz offsetof(struct public_port, link_status)); 623cc875c2eSYuval Mintz DP_VERBOSE(p_hwfn, (NETIF_MSG_LINK | QED_MSG_SP), 624cc875c2eSYuval Mintz "Received link update [0x%08x] from mfw [Addr 0x%x]\n", 625cc875c2eSYuval Mintz status, 626cc875c2eSYuval Mintz (u32)(p_hwfn->mcp_info->port_addr + 6271a635e48SYuval Mintz offsetof(struct public_port, link_status))); 628cc875c2eSYuval Mintz } else { 629cc875c2eSYuval Mintz DP_VERBOSE(p_hwfn, NETIF_MSG_LINK, 630cc875c2eSYuval Mintz "Resetting link indications\n"); 63165ed2ffdSMintz, Yuval goto out; 632cc875c2eSYuval Mintz } 633cc875c2eSYuval Mintz 634fc916ff2SSudarsana Reddy Kalluru if (p_hwfn->b_drv_link_init) 635cc875c2eSYuval Mintz p_link->link_up = !!(status & LINK_STATUS_LINK_UP); 636fc916ff2SSudarsana Reddy Kalluru else 637fc916ff2SSudarsana Reddy Kalluru p_link->link_up = false; 638cc875c2eSYuval Mintz 639cc875c2eSYuval Mintz p_link->full_duplex = true; 640cc875c2eSYuval Mintz switch ((status & LINK_STATUS_SPEED_AND_DUPLEX_MASK)) { 641cc875c2eSYuval Mintz case LINK_STATUS_SPEED_AND_DUPLEX_100G: 642cc875c2eSYuval Mintz p_link->speed = 100000; 643cc875c2eSYuval Mintz break; 644cc875c2eSYuval Mintz case LINK_STATUS_SPEED_AND_DUPLEX_50G: 645cc875c2eSYuval Mintz p_link->speed = 50000; 646cc875c2eSYuval Mintz break; 647cc875c2eSYuval Mintz case LINK_STATUS_SPEED_AND_DUPLEX_40G: 648cc875c2eSYuval Mintz p_link->speed = 40000; 649cc875c2eSYuval Mintz break; 650cc875c2eSYuval Mintz case LINK_STATUS_SPEED_AND_DUPLEX_25G: 651cc875c2eSYuval Mintz p_link->speed = 25000; 652cc875c2eSYuval Mintz break; 653cc875c2eSYuval Mintz case LINK_STATUS_SPEED_AND_DUPLEX_20G: 654cc875c2eSYuval Mintz p_link->speed = 20000; 655cc875c2eSYuval Mintz break; 656cc875c2eSYuval Mintz case LINK_STATUS_SPEED_AND_DUPLEX_10G: 657cc875c2eSYuval Mintz p_link->speed = 10000; 658cc875c2eSYuval Mintz break; 659cc875c2eSYuval Mintz case LINK_STATUS_SPEED_AND_DUPLEX_1000THD: 660cc875c2eSYuval Mintz p_link->full_duplex = false; 661cc875c2eSYuval Mintz /* Fall-through */ 662cc875c2eSYuval Mintz case LINK_STATUS_SPEED_AND_DUPLEX_1000TFD: 663cc875c2eSYuval Mintz p_link->speed = 1000; 664cc875c2eSYuval Mintz break; 665cc875c2eSYuval Mintz default: 666cc875c2eSYuval Mintz p_link->speed = 0; 667cc875c2eSYuval Mintz } 668cc875c2eSYuval Mintz 6694b01e519SManish Chopra if (p_link->link_up && p_link->speed) 6704b01e519SManish Chopra p_link->line_speed = p_link->speed; 6714b01e519SManish Chopra else 6724b01e519SManish Chopra p_link->line_speed = 0; 6734b01e519SManish Chopra 6744b01e519SManish Chopra max_bw = p_hwfn->mcp_info->func_info.bandwidth_max; 675a64b02d5SManish Chopra min_bw = p_hwfn->mcp_info->func_info.bandwidth_min; 6764b01e519SManish Chopra 677a64b02d5SManish Chopra /* Max bandwidth configuration */ 6784b01e519SManish Chopra __qed_configure_pf_max_bandwidth(p_hwfn, p_ptt, p_link, max_bw); 679cc875c2eSYuval Mintz 680a64b02d5SManish Chopra /* Min bandwidth configuration */ 681a64b02d5SManish Chopra __qed_configure_pf_min_bandwidth(p_hwfn, p_ptt, p_link, min_bw); 682a64b02d5SManish Chopra qed_configure_vp_wfq_on_link_change(p_hwfn->cdev, p_link->min_pf_rate); 683a64b02d5SManish Chopra 684cc875c2eSYuval Mintz p_link->an = !!(status & LINK_STATUS_AUTO_NEGOTIATE_ENABLED); 685cc875c2eSYuval Mintz p_link->an_complete = !!(status & 686cc875c2eSYuval Mintz LINK_STATUS_AUTO_NEGOTIATE_COMPLETE); 687cc875c2eSYuval Mintz p_link->parallel_detection = !!(status & 688cc875c2eSYuval Mintz LINK_STATUS_PARALLEL_DETECTION_USED); 689cc875c2eSYuval Mintz p_link->pfc_enabled = !!(status & LINK_STATUS_PFC_ENABLED); 690cc875c2eSYuval Mintz 691cc875c2eSYuval Mintz p_link->partner_adv_speed |= 692cc875c2eSYuval Mintz (status & LINK_STATUS_LINK_PARTNER_1000TFD_CAPABLE) ? 693cc875c2eSYuval Mintz QED_LINK_PARTNER_SPEED_1G_FD : 0; 694cc875c2eSYuval Mintz p_link->partner_adv_speed |= 695cc875c2eSYuval Mintz (status & LINK_STATUS_LINK_PARTNER_1000THD_CAPABLE) ? 696cc875c2eSYuval Mintz QED_LINK_PARTNER_SPEED_1G_HD : 0; 697cc875c2eSYuval Mintz p_link->partner_adv_speed |= 698cc875c2eSYuval Mintz (status & LINK_STATUS_LINK_PARTNER_10G_CAPABLE) ? 699cc875c2eSYuval Mintz QED_LINK_PARTNER_SPEED_10G : 0; 700cc875c2eSYuval Mintz p_link->partner_adv_speed |= 701cc875c2eSYuval Mintz (status & LINK_STATUS_LINK_PARTNER_20G_CAPABLE) ? 702cc875c2eSYuval Mintz QED_LINK_PARTNER_SPEED_20G : 0; 703cc875c2eSYuval Mintz p_link->partner_adv_speed |= 704054c67d1SSudarsana Reddy Kalluru (status & LINK_STATUS_LINK_PARTNER_25G_CAPABLE) ? 705054c67d1SSudarsana Reddy Kalluru QED_LINK_PARTNER_SPEED_25G : 0; 706054c67d1SSudarsana Reddy Kalluru p_link->partner_adv_speed |= 707cc875c2eSYuval Mintz (status & LINK_STATUS_LINK_PARTNER_40G_CAPABLE) ? 708cc875c2eSYuval Mintz QED_LINK_PARTNER_SPEED_40G : 0; 709cc875c2eSYuval Mintz p_link->partner_adv_speed |= 710cc875c2eSYuval Mintz (status & LINK_STATUS_LINK_PARTNER_50G_CAPABLE) ? 711cc875c2eSYuval Mintz QED_LINK_PARTNER_SPEED_50G : 0; 712cc875c2eSYuval Mintz p_link->partner_adv_speed |= 713cc875c2eSYuval Mintz (status & LINK_STATUS_LINK_PARTNER_100G_CAPABLE) ? 714cc875c2eSYuval Mintz QED_LINK_PARTNER_SPEED_100G : 0; 715cc875c2eSYuval Mintz 716cc875c2eSYuval Mintz p_link->partner_tx_flow_ctrl_en = 717cc875c2eSYuval Mintz !!(status & LINK_STATUS_TX_FLOW_CONTROL_ENABLED); 718cc875c2eSYuval Mintz p_link->partner_rx_flow_ctrl_en = 719cc875c2eSYuval Mintz !!(status & LINK_STATUS_RX_FLOW_CONTROL_ENABLED); 720cc875c2eSYuval Mintz 721cc875c2eSYuval Mintz switch (status & LINK_STATUS_LINK_PARTNER_FLOW_CONTROL_MASK) { 722cc875c2eSYuval Mintz case LINK_STATUS_LINK_PARTNER_SYMMETRIC_PAUSE: 723cc875c2eSYuval Mintz p_link->partner_adv_pause = QED_LINK_PARTNER_SYMMETRIC_PAUSE; 724cc875c2eSYuval Mintz break; 725cc875c2eSYuval Mintz case LINK_STATUS_LINK_PARTNER_ASYMMETRIC_PAUSE: 726cc875c2eSYuval Mintz p_link->partner_adv_pause = QED_LINK_PARTNER_ASYMMETRIC_PAUSE; 727cc875c2eSYuval Mintz break; 728cc875c2eSYuval Mintz case LINK_STATUS_LINK_PARTNER_BOTH_PAUSE: 729cc875c2eSYuval Mintz p_link->partner_adv_pause = QED_LINK_PARTNER_BOTH_PAUSE; 730cc875c2eSYuval Mintz break; 731cc875c2eSYuval Mintz default: 732cc875c2eSYuval Mintz p_link->partner_adv_pause = 0; 733cc875c2eSYuval Mintz } 734cc875c2eSYuval Mintz 735cc875c2eSYuval Mintz p_link->sfp_tx_fault = !!(status & LINK_STATUS_SFP_TX_FAULT); 736cc875c2eSYuval Mintz 737cc875c2eSYuval Mintz qed_link_update(p_hwfn); 73865ed2ffdSMintz, Yuval out: 73965ed2ffdSMintz, Yuval spin_unlock_bh(&p_hwfn->mcp_info->link_lock); 740cc875c2eSYuval Mintz } 741cc875c2eSYuval Mintz 742351a4dedSYuval Mintz int qed_mcp_set_link(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt, bool b_up) 743cc875c2eSYuval Mintz { 744cc875c2eSYuval Mintz struct qed_mcp_link_params *params = &p_hwfn->mcp_info->link_input; 7455529bad9STomer Tayar struct qed_mcp_mb_params mb_params; 7465529bad9STomer Tayar union drv_union_data union_data; 747351a4dedSYuval Mintz struct eth_phy_cfg *phy_cfg; 748cc875c2eSYuval Mintz int rc = 0; 7495529bad9STomer Tayar u32 cmd; 750cc875c2eSYuval Mintz 751cc875c2eSYuval Mintz /* Set the shmem configuration according to params */ 7525529bad9STomer Tayar phy_cfg = &union_data.drv_phy_cfg; 7535529bad9STomer Tayar memset(phy_cfg, 0, sizeof(*phy_cfg)); 754cc875c2eSYuval Mintz cmd = b_up ? DRV_MSG_CODE_INIT_PHY : DRV_MSG_CODE_LINK_RESET; 755cc875c2eSYuval Mintz if (!params->speed.autoneg) 7565529bad9STomer Tayar phy_cfg->speed = params->speed.forced_speed; 757351a4dedSYuval Mintz phy_cfg->pause |= (params->pause.autoneg) ? ETH_PAUSE_AUTONEG : 0; 758351a4dedSYuval Mintz phy_cfg->pause |= (params->pause.forced_rx) ? ETH_PAUSE_RX : 0; 759351a4dedSYuval Mintz phy_cfg->pause |= (params->pause.forced_tx) ? ETH_PAUSE_TX : 0; 7605529bad9STomer Tayar phy_cfg->adv_speed = params->speed.advertised_speeds; 7615529bad9STomer Tayar phy_cfg->loopback_mode = params->loopback_mode; 762cc875c2eSYuval Mintz 763fc916ff2SSudarsana Reddy Kalluru p_hwfn->b_drv_link_init = b_up; 764fc916ff2SSudarsana Reddy Kalluru 765cc875c2eSYuval Mintz if (b_up) { 766cc875c2eSYuval Mintz DP_VERBOSE(p_hwfn, NETIF_MSG_LINK, 767cc875c2eSYuval Mintz "Configuring Link: Speed 0x%08x, Pause 0x%08x, adv_speed 0x%08x, loopback 0x%08x, features 0x%08x\n", 7685529bad9STomer Tayar phy_cfg->speed, 7695529bad9STomer Tayar phy_cfg->pause, 7705529bad9STomer Tayar phy_cfg->adv_speed, 7715529bad9STomer Tayar phy_cfg->loopback_mode, 7725529bad9STomer Tayar phy_cfg->feature_config_flags); 773cc875c2eSYuval Mintz } else { 774cc875c2eSYuval Mintz DP_VERBOSE(p_hwfn, NETIF_MSG_LINK, 775cc875c2eSYuval Mintz "Resetting link\n"); 776cc875c2eSYuval Mintz } 777cc875c2eSYuval Mintz 7785529bad9STomer Tayar memset(&mb_params, 0, sizeof(mb_params)); 7795529bad9STomer Tayar mb_params.cmd = cmd; 7805529bad9STomer Tayar mb_params.p_data_src = &union_data; 7815529bad9STomer Tayar rc = qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 782cc875c2eSYuval Mintz 783cc875c2eSYuval Mintz /* if mcp fails to respond we must abort */ 784cc875c2eSYuval Mintz if (rc) { 785cc875c2eSYuval Mintz DP_ERR(p_hwfn, "MCP response failure, aborting\n"); 786cc875c2eSYuval Mintz return rc; 787cc875c2eSYuval Mintz } 788cc875c2eSYuval Mintz 78965ed2ffdSMintz, Yuval /* Mimic link-change attention, done for several reasons: 79065ed2ffdSMintz, Yuval * - On reset, there's no guarantee MFW would trigger 79165ed2ffdSMintz, Yuval * an attention. 79265ed2ffdSMintz, Yuval * - On initialization, older MFWs might not indicate link change 79365ed2ffdSMintz, Yuval * during LFA, so we'll never get an UP indication. 79465ed2ffdSMintz, Yuval */ 79565ed2ffdSMintz, Yuval qed_mcp_handle_link_change(p_hwfn, p_ptt, !b_up); 796cc875c2eSYuval Mintz 797cc875c2eSYuval Mintz return 0; 798cc875c2eSYuval Mintz } 799cc875c2eSYuval Mintz 8006c754246SSudarsana Reddy Kalluru static void qed_mcp_send_protocol_stats(struct qed_hwfn *p_hwfn, 8016c754246SSudarsana Reddy Kalluru struct qed_ptt *p_ptt, 8026c754246SSudarsana Reddy Kalluru enum MFW_DRV_MSG_TYPE type) 8036c754246SSudarsana Reddy Kalluru { 8046c754246SSudarsana Reddy Kalluru enum qed_mcp_protocol_type stats_type; 8056c754246SSudarsana Reddy Kalluru union qed_mcp_protocol_stats stats; 8066c754246SSudarsana Reddy Kalluru struct qed_mcp_mb_params mb_params; 8076c754246SSudarsana Reddy Kalluru union drv_union_data union_data; 8086c754246SSudarsana Reddy Kalluru u32 hsi_param; 8096c754246SSudarsana Reddy Kalluru 8106c754246SSudarsana Reddy Kalluru switch (type) { 8116c754246SSudarsana Reddy Kalluru case MFW_DRV_MSG_GET_LAN_STATS: 8126c754246SSudarsana Reddy Kalluru stats_type = QED_MCP_LAN_STATS; 8136c754246SSudarsana Reddy Kalluru hsi_param = DRV_MSG_CODE_STATS_TYPE_LAN; 8146c754246SSudarsana Reddy Kalluru break; 8156c754246SSudarsana Reddy Kalluru case MFW_DRV_MSG_GET_FCOE_STATS: 8166c754246SSudarsana Reddy Kalluru stats_type = QED_MCP_FCOE_STATS; 8176c754246SSudarsana Reddy Kalluru hsi_param = DRV_MSG_CODE_STATS_TYPE_FCOE; 8186c754246SSudarsana Reddy Kalluru break; 8196c754246SSudarsana Reddy Kalluru case MFW_DRV_MSG_GET_ISCSI_STATS: 8206c754246SSudarsana Reddy Kalluru stats_type = QED_MCP_ISCSI_STATS; 8216c754246SSudarsana Reddy Kalluru hsi_param = DRV_MSG_CODE_STATS_TYPE_ISCSI; 8226c754246SSudarsana Reddy Kalluru break; 8236c754246SSudarsana Reddy Kalluru case MFW_DRV_MSG_GET_RDMA_STATS: 8246c754246SSudarsana Reddy Kalluru stats_type = QED_MCP_RDMA_STATS; 8256c754246SSudarsana Reddy Kalluru hsi_param = DRV_MSG_CODE_STATS_TYPE_RDMA; 8266c754246SSudarsana Reddy Kalluru break; 8276c754246SSudarsana Reddy Kalluru default: 8286c754246SSudarsana Reddy Kalluru DP_NOTICE(p_hwfn, "Invalid protocol type %d\n", type); 8296c754246SSudarsana Reddy Kalluru return; 8306c754246SSudarsana Reddy Kalluru } 8316c754246SSudarsana Reddy Kalluru 8326c754246SSudarsana Reddy Kalluru qed_get_protocol_stats(p_hwfn->cdev, stats_type, &stats); 8336c754246SSudarsana Reddy Kalluru 8346c754246SSudarsana Reddy Kalluru memset(&mb_params, 0, sizeof(mb_params)); 8356c754246SSudarsana Reddy Kalluru mb_params.cmd = DRV_MSG_CODE_GET_STATS; 8366c754246SSudarsana Reddy Kalluru mb_params.param = hsi_param; 8376c754246SSudarsana Reddy Kalluru memcpy(&union_data, &stats, sizeof(stats)); 8386c754246SSudarsana Reddy Kalluru mb_params.p_data_src = &union_data; 8396c754246SSudarsana Reddy Kalluru qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 8406c754246SSudarsana Reddy Kalluru } 8416c754246SSudarsana Reddy Kalluru 8424b01e519SManish Chopra static void qed_read_pf_bandwidth(struct qed_hwfn *p_hwfn, 8434b01e519SManish Chopra struct public_func *p_shmem_info) 8444b01e519SManish Chopra { 8454b01e519SManish Chopra struct qed_mcp_function_info *p_info; 8464b01e519SManish Chopra 8474b01e519SManish Chopra p_info = &p_hwfn->mcp_info->func_info; 8484b01e519SManish Chopra 8494b01e519SManish Chopra p_info->bandwidth_min = (p_shmem_info->config & 8504b01e519SManish Chopra FUNC_MF_CFG_MIN_BW_MASK) >> 8514b01e519SManish Chopra FUNC_MF_CFG_MIN_BW_SHIFT; 8524b01e519SManish Chopra if (p_info->bandwidth_min < 1 || p_info->bandwidth_min > 100) { 8534b01e519SManish Chopra DP_INFO(p_hwfn, 8544b01e519SManish Chopra "bandwidth minimum out of bounds [%02x]. Set to 1\n", 8554b01e519SManish Chopra p_info->bandwidth_min); 8564b01e519SManish Chopra p_info->bandwidth_min = 1; 8574b01e519SManish Chopra } 8584b01e519SManish Chopra 8594b01e519SManish Chopra p_info->bandwidth_max = (p_shmem_info->config & 8604b01e519SManish Chopra FUNC_MF_CFG_MAX_BW_MASK) >> 8614b01e519SManish Chopra FUNC_MF_CFG_MAX_BW_SHIFT; 8624b01e519SManish Chopra if (p_info->bandwidth_max < 1 || p_info->bandwidth_max > 100) { 8634b01e519SManish Chopra DP_INFO(p_hwfn, 8644b01e519SManish Chopra "bandwidth maximum out of bounds [%02x]. Set to 100\n", 8654b01e519SManish Chopra p_info->bandwidth_max); 8664b01e519SManish Chopra p_info->bandwidth_max = 100; 8674b01e519SManish Chopra } 8684b01e519SManish Chopra } 8694b01e519SManish Chopra 8704b01e519SManish Chopra static u32 qed_mcp_get_shmem_func(struct qed_hwfn *p_hwfn, 8714b01e519SManish Chopra struct qed_ptt *p_ptt, 8721a635e48SYuval Mintz struct public_func *p_data, int pfid) 8734b01e519SManish Chopra { 8744b01e519SManish Chopra u32 addr = SECTION_OFFSIZE_ADDR(p_hwfn->mcp_info->public_base, 8754b01e519SManish Chopra PUBLIC_FUNC); 8764b01e519SManish Chopra u32 mfw_path_offsize = qed_rd(p_hwfn, p_ptt, addr); 8774b01e519SManish Chopra u32 func_addr = SECTION_ADDR(mfw_path_offsize, pfid); 8784b01e519SManish Chopra u32 i, size; 8794b01e519SManish Chopra 8804b01e519SManish Chopra memset(p_data, 0, sizeof(*p_data)); 8814b01e519SManish Chopra 8821a635e48SYuval Mintz size = min_t(u32, sizeof(*p_data), QED_SECTION_SIZE(mfw_path_offsize)); 8834b01e519SManish Chopra for (i = 0; i < size / sizeof(u32); i++) 8844b01e519SManish Chopra ((u32 *)p_data)[i] = qed_rd(p_hwfn, p_ptt, 8854b01e519SManish Chopra func_addr + (i << 2)); 8864b01e519SManish Chopra return size; 8874b01e519SManish Chopra } 8884b01e519SManish Chopra 8891a635e48SYuval Mintz static void qed_mcp_update_bw(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 8904b01e519SManish Chopra { 8914b01e519SManish Chopra struct qed_mcp_function_info *p_info; 8924b01e519SManish Chopra struct public_func shmem_info; 8934b01e519SManish Chopra u32 resp = 0, param = 0; 8944b01e519SManish Chopra 8951a635e48SYuval Mintz qed_mcp_get_shmem_func(p_hwfn, p_ptt, &shmem_info, MCP_PF_ID(p_hwfn)); 8964b01e519SManish Chopra 8974b01e519SManish Chopra qed_read_pf_bandwidth(p_hwfn, &shmem_info); 8984b01e519SManish Chopra 8994b01e519SManish Chopra p_info = &p_hwfn->mcp_info->func_info; 9004b01e519SManish Chopra 901a64b02d5SManish Chopra qed_configure_pf_min_bandwidth(p_hwfn->cdev, p_info->bandwidth_min); 9024b01e519SManish Chopra qed_configure_pf_max_bandwidth(p_hwfn->cdev, p_info->bandwidth_max); 9034b01e519SManish Chopra 9044b01e519SManish Chopra /* Acknowledge the MFW */ 9054b01e519SManish Chopra qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_BW_UPDATE_ACK, 0, &resp, 9064b01e519SManish Chopra ¶m); 9074b01e519SManish Chopra } 9084b01e519SManish Chopra 909cc875c2eSYuval Mintz int qed_mcp_handle_events(struct qed_hwfn *p_hwfn, 910cc875c2eSYuval Mintz struct qed_ptt *p_ptt) 911cc875c2eSYuval Mintz { 912cc875c2eSYuval Mintz struct qed_mcp_info *info = p_hwfn->mcp_info; 913cc875c2eSYuval Mintz int rc = 0; 914cc875c2eSYuval Mintz bool found = false; 915cc875c2eSYuval Mintz u16 i; 916cc875c2eSYuval Mintz 917cc875c2eSYuval Mintz DP_VERBOSE(p_hwfn, QED_MSG_SP, "Received message from MFW\n"); 918cc875c2eSYuval Mintz 919cc875c2eSYuval Mintz /* Read Messages from MFW */ 920cc875c2eSYuval Mintz qed_mcp_read_mb(p_hwfn, p_ptt); 921cc875c2eSYuval Mintz 922cc875c2eSYuval Mintz /* Compare current messages to old ones */ 923cc875c2eSYuval Mintz for (i = 0; i < info->mfw_mb_length; i++) { 924cc875c2eSYuval Mintz if (info->mfw_mb_cur[i] == info->mfw_mb_shadow[i]) 925cc875c2eSYuval Mintz continue; 926cc875c2eSYuval Mintz 927cc875c2eSYuval Mintz found = true; 928cc875c2eSYuval Mintz 929cc875c2eSYuval Mintz DP_VERBOSE(p_hwfn, NETIF_MSG_LINK, 930cc875c2eSYuval Mintz "Msg [%d] - old CMD 0x%02x, new CMD 0x%02x\n", 931cc875c2eSYuval Mintz i, info->mfw_mb_shadow[i], info->mfw_mb_cur[i]); 932cc875c2eSYuval Mintz 933cc875c2eSYuval Mintz switch (i) { 934cc875c2eSYuval Mintz case MFW_DRV_MSG_LINK_CHANGE: 935cc875c2eSYuval Mintz qed_mcp_handle_link_change(p_hwfn, p_ptt, false); 936cc875c2eSYuval Mintz break; 9370b55e27dSYuval Mintz case MFW_DRV_MSG_VF_DISABLED: 9380b55e27dSYuval Mintz qed_mcp_handle_vf_flr(p_hwfn, p_ptt); 9390b55e27dSYuval Mintz break; 94039651abdSSudarsana Reddy Kalluru case MFW_DRV_MSG_LLDP_DATA_UPDATED: 94139651abdSSudarsana Reddy Kalluru qed_dcbx_mib_update_event(p_hwfn, p_ptt, 94239651abdSSudarsana Reddy Kalluru QED_DCBX_REMOTE_LLDP_MIB); 94339651abdSSudarsana Reddy Kalluru break; 94439651abdSSudarsana Reddy Kalluru case MFW_DRV_MSG_DCBX_REMOTE_MIB_UPDATED: 94539651abdSSudarsana Reddy Kalluru qed_dcbx_mib_update_event(p_hwfn, p_ptt, 94639651abdSSudarsana Reddy Kalluru QED_DCBX_REMOTE_MIB); 94739651abdSSudarsana Reddy Kalluru break; 94839651abdSSudarsana Reddy Kalluru case MFW_DRV_MSG_DCBX_OPERATIONAL_MIB_UPDATED: 94939651abdSSudarsana Reddy Kalluru qed_dcbx_mib_update_event(p_hwfn, p_ptt, 95039651abdSSudarsana Reddy Kalluru QED_DCBX_OPERATIONAL_MIB); 95139651abdSSudarsana Reddy Kalluru break; 952334c03b5SZvi Nachmani case MFW_DRV_MSG_TRANSCEIVER_STATE_CHANGE: 953334c03b5SZvi Nachmani qed_mcp_handle_transceiver_change(p_hwfn, p_ptt); 954334c03b5SZvi Nachmani break; 9556c754246SSudarsana Reddy Kalluru case MFW_DRV_MSG_GET_LAN_STATS: 9566c754246SSudarsana Reddy Kalluru case MFW_DRV_MSG_GET_FCOE_STATS: 9576c754246SSudarsana Reddy Kalluru case MFW_DRV_MSG_GET_ISCSI_STATS: 9586c754246SSudarsana Reddy Kalluru case MFW_DRV_MSG_GET_RDMA_STATS: 9596c754246SSudarsana Reddy Kalluru qed_mcp_send_protocol_stats(p_hwfn, p_ptt, i); 9606c754246SSudarsana Reddy Kalluru break; 9614b01e519SManish Chopra case MFW_DRV_MSG_BW_UPDATE: 9624b01e519SManish Chopra qed_mcp_update_bw(p_hwfn, p_ptt); 9634b01e519SManish Chopra break; 964cc875c2eSYuval Mintz default: 965cc875c2eSYuval Mintz DP_NOTICE(p_hwfn, "Unimplemented MFW message %d\n", i); 966cc875c2eSYuval Mintz rc = -EINVAL; 967cc875c2eSYuval Mintz } 968cc875c2eSYuval Mintz } 969cc875c2eSYuval Mintz 970cc875c2eSYuval Mintz /* ACK everything */ 971cc875c2eSYuval Mintz for (i = 0; i < MFW_DRV_MSG_MAX_DWORDS(info->mfw_mb_length); i++) { 972cc875c2eSYuval Mintz __be32 val = cpu_to_be32(((u32 *)info->mfw_mb_cur)[i]); 973cc875c2eSYuval Mintz 974cc875c2eSYuval Mintz /* MFW expect answer in BE, so we force write in that format */ 975cc875c2eSYuval Mintz qed_wr(p_hwfn, p_ptt, 976cc875c2eSYuval Mintz info->mfw_mb_addr + sizeof(u32) + 977cc875c2eSYuval Mintz MFW_DRV_MSG_MAX_DWORDS(info->mfw_mb_length) * 978cc875c2eSYuval Mintz sizeof(u32) + i * sizeof(u32), 979cc875c2eSYuval Mintz (__force u32)val); 980cc875c2eSYuval Mintz } 981cc875c2eSYuval Mintz 982cc875c2eSYuval Mintz if (!found) { 983cc875c2eSYuval Mintz DP_NOTICE(p_hwfn, 984cc875c2eSYuval Mintz "Received an MFW message indication but no new message!\n"); 985cc875c2eSYuval Mintz rc = -EINVAL; 986cc875c2eSYuval Mintz } 987cc875c2eSYuval Mintz 988cc875c2eSYuval Mintz /* Copy the new mfw messages into the shadow */ 989cc875c2eSYuval Mintz memcpy(info->mfw_mb_shadow, info->mfw_mb_cur, info->mfw_mb_length); 990cc875c2eSYuval Mintz 991cc875c2eSYuval Mintz return rc; 992cc875c2eSYuval Mintz } 993cc875c2eSYuval Mintz 9941408cc1fSYuval Mintz int qed_mcp_get_mfw_ver(struct qed_hwfn *p_hwfn, 9951408cc1fSYuval Mintz struct qed_ptt *p_ptt, 9961408cc1fSYuval Mintz u32 *p_mfw_ver, u32 *p_running_bundle_id) 997fe56b9e6SYuval Mintz { 998fe56b9e6SYuval Mintz u32 global_offsize; 999fe56b9e6SYuval Mintz 10001408cc1fSYuval Mintz if (IS_VF(p_hwfn->cdev)) { 10011408cc1fSYuval Mintz if (p_hwfn->vf_iov_info) { 10021408cc1fSYuval Mintz struct pfvf_acquire_resp_tlv *p_resp; 10031408cc1fSYuval Mintz 10041408cc1fSYuval Mintz p_resp = &p_hwfn->vf_iov_info->acquire_resp; 10051408cc1fSYuval Mintz *p_mfw_ver = p_resp->pfdev_info.mfw_ver; 10061408cc1fSYuval Mintz return 0; 10071408cc1fSYuval Mintz } else { 10081408cc1fSYuval Mintz DP_VERBOSE(p_hwfn, 10091408cc1fSYuval Mintz QED_MSG_IOV, 10101408cc1fSYuval Mintz "VF requested MFW version prior to ACQUIRE\n"); 10111408cc1fSYuval Mintz return -EINVAL; 10121408cc1fSYuval Mintz } 10131408cc1fSYuval Mintz } 1014fe56b9e6SYuval Mintz 1015fe56b9e6SYuval Mintz global_offsize = qed_rd(p_hwfn, p_ptt, 10161408cc1fSYuval Mintz SECTION_OFFSIZE_ADDR(p_hwfn-> 10171408cc1fSYuval Mintz mcp_info->public_base, 1018fe56b9e6SYuval Mintz PUBLIC_GLOBAL)); 10191408cc1fSYuval Mintz *p_mfw_ver = 10201408cc1fSYuval Mintz qed_rd(p_hwfn, p_ptt, 10211408cc1fSYuval Mintz SECTION_ADDR(global_offsize, 10221408cc1fSYuval Mintz 0) + offsetof(struct public_global, mfw_ver)); 1023fe56b9e6SYuval Mintz 10241408cc1fSYuval Mintz if (p_running_bundle_id != NULL) { 10251408cc1fSYuval Mintz *p_running_bundle_id = qed_rd(p_hwfn, p_ptt, 10261408cc1fSYuval Mintz SECTION_ADDR(global_offsize, 0) + 10271408cc1fSYuval Mintz offsetof(struct public_global, 10281408cc1fSYuval Mintz running_bundle_id)); 10291408cc1fSYuval Mintz } 1030fe56b9e6SYuval Mintz 1031fe56b9e6SYuval Mintz return 0; 1032fe56b9e6SYuval Mintz } 1033fe56b9e6SYuval Mintz 10341a635e48SYuval Mintz int qed_mcp_get_media_type(struct qed_dev *cdev, u32 *p_media_type) 1035cc875c2eSYuval Mintz { 1036cc875c2eSYuval Mintz struct qed_hwfn *p_hwfn = &cdev->hwfns[0]; 1037cc875c2eSYuval Mintz struct qed_ptt *p_ptt; 1038cc875c2eSYuval Mintz 10391408cc1fSYuval Mintz if (IS_VF(cdev)) 10401408cc1fSYuval Mintz return -EINVAL; 10411408cc1fSYuval Mintz 1042cc875c2eSYuval Mintz if (!qed_mcp_is_init(p_hwfn)) { 1043cc875c2eSYuval Mintz DP_NOTICE(p_hwfn, "MFW is not initialized!\n"); 1044cc875c2eSYuval Mintz return -EBUSY; 1045cc875c2eSYuval Mintz } 1046cc875c2eSYuval Mintz 1047cc875c2eSYuval Mintz *p_media_type = MEDIA_UNSPECIFIED; 1048cc875c2eSYuval Mintz 1049cc875c2eSYuval Mintz p_ptt = qed_ptt_acquire(p_hwfn); 1050cc875c2eSYuval Mintz if (!p_ptt) 1051cc875c2eSYuval Mintz return -EBUSY; 1052cc875c2eSYuval Mintz 1053cc875c2eSYuval Mintz *p_media_type = qed_rd(p_hwfn, p_ptt, p_hwfn->mcp_info->port_addr + 1054cc875c2eSYuval Mintz offsetof(struct public_port, media_type)); 1055cc875c2eSYuval Mintz 1056cc875c2eSYuval Mintz qed_ptt_release(p_hwfn, p_ptt); 1057cc875c2eSYuval Mintz 1058cc875c2eSYuval Mintz return 0; 1059cc875c2eSYuval Mintz } 1060cc875c2eSYuval Mintz 10616927e826SMintz, Yuval /* Old MFW has a global configuration for all PFs regarding RDMA support */ 10626927e826SMintz, Yuval static void 10636927e826SMintz, Yuval qed_mcp_get_shmem_proto_legacy(struct qed_hwfn *p_hwfn, 10646927e826SMintz, Yuval enum qed_pci_personality *p_proto) 10656927e826SMintz, Yuval { 10666927e826SMintz, Yuval /* There wasn't ever a legacy MFW that published iwarp. 10676927e826SMintz, Yuval * So at this point, this is either plain l2 or RoCE. 10686927e826SMintz, Yuval */ 10696927e826SMintz, Yuval if (test_bit(QED_DEV_CAP_ROCE, &p_hwfn->hw_info.device_capabilities)) 10706927e826SMintz, Yuval *p_proto = QED_PCI_ETH_ROCE; 10716927e826SMintz, Yuval else 10726927e826SMintz, Yuval *p_proto = QED_PCI_ETH; 10736927e826SMintz, Yuval 10746927e826SMintz, Yuval DP_VERBOSE(p_hwfn, NETIF_MSG_IFUP, 10756927e826SMintz, Yuval "According to Legacy capabilities, L2 personality is %08x\n", 10766927e826SMintz, Yuval (u32) *p_proto); 10776927e826SMintz, Yuval } 10786927e826SMintz, Yuval 10796927e826SMintz, Yuval static int 10806927e826SMintz, Yuval qed_mcp_get_shmem_proto_mfw(struct qed_hwfn *p_hwfn, 10816927e826SMintz, Yuval struct qed_ptt *p_ptt, 10826927e826SMintz, Yuval enum qed_pci_personality *p_proto) 10836927e826SMintz, Yuval { 10846927e826SMintz, Yuval u32 resp = 0, param = 0; 10856927e826SMintz, Yuval int rc; 10866927e826SMintz, Yuval 10876927e826SMintz, Yuval rc = qed_mcp_cmd(p_hwfn, p_ptt, 10886927e826SMintz, Yuval DRV_MSG_CODE_GET_PF_RDMA_PROTOCOL, 0, &resp, ¶m); 10896927e826SMintz, Yuval if (rc) 10906927e826SMintz, Yuval return rc; 10916927e826SMintz, Yuval if (resp != FW_MSG_CODE_OK) { 10926927e826SMintz, Yuval DP_VERBOSE(p_hwfn, NETIF_MSG_IFUP, 10936927e826SMintz, Yuval "MFW lacks support for command; Returns %08x\n", 10946927e826SMintz, Yuval resp); 10956927e826SMintz, Yuval return -EINVAL; 10966927e826SMintz, Yuval } 10976927e826SMintz, Yuval 10986927e826SMintz, Yuval switch (param) { 10996927e826SMintz, Yuval case FW_MB_PARAM_GET_PF_RDMA_NONE: 11006927e826SMintz, Yuval *p_proto = QED_PCI_ETH; 11016927e826SMintz, Yuval break; 11026927e826SMintz, Yuval case FW_MB_PARAM_GET_PF_RDMA_ROCE: 11036927e826SMintz, Yuval *p_proto = QED_PCI_ETH_ROCE; 11046927e826SMintz, Yuval break; 11056927e826SMintz, Yuval case FW_MB_PARAM_GET_PF_RDMA_BOTH: 11066927e826SMintz, Yuval DP_NOTICE(p_hwfn, 11076927e826SMintz, Yuval "Current day drivers don't support RoCE & iWARP. Default to RoCE-only\n"); 11086927e826SMintz, Yuval *p_proto = QED_PCI_ETH_ROCE; 11096927e826SMintz, Yuval break; 11106927e826SMintz, Yuval case FW_MB_PARAM_GET_PF_RDMA_IWARP: 11116927e826SMintz, Yuval default: 11126927e826SMintz, Yuval DP_NOTICE(p_hwfn, 11136927e826SMintz, Yuval "MFW answers GET_PF_RDMA_PROTOCOL but param is %08x\n", 11146927e826SMintz, Yuval param); 11156927e826SMintz, Yuval return -EINVAL; 11166927e826SMintz, Yuval } 11176927e826SMintz, Yuval 11186927e826SMintz, Yuval DP_VERBOSE(p_hwfn, 11196927e826SMintz, Yuval NETIF_MSG_IFUP, 11206927e826SMintz, Yuval "According to capabilities, L2 personality is %08x [resp %08x param %08x]\n", 11216927e826SMintz, Yuval (u32) *p_proto, resp, param); 11226927e826SMintz, Yuval return 0; 11236927e826SMintz, Yuval } 11246927e826SMintz, Yuval 1125fe56b9e6SYuval Mintz static int 1126fe56b9e6SYuval Mintz qed_mcp_get_shmem_proto(struct qed_hwfn *p_hwfn, 1127fe56b9e6SYuval Mintz struct public_func *p_info, 11286927e826SMintz, Yuval struct qed_ptt *p_ptt, 1129fe56b9e6SYuval Mintz enum qed_pci_personality *p_proto) 1130fe56b9e6SYuval Mintz { 1131fe56b9e6SYuval Mintz int rc = 0; 1132fe56b9e6SYuval Mintz 1133fe56b9e6SYuval Mintz switch (p_info->config & FUNC_MF_CFG_PROTOCOL_MASK) { 1134fe56b9e6SYuval Mintz case FUNC_MF_CFG_PROTOCOL_ETHERNET: 11351fe582ecSRam Amrani if (!IS_ENABLED(CONFIG_QED_RDMA)) 11361fe582ecSRam Amrani *p_proto = QED_PCI_ETH; 11371fe582ecSRam Amrani else if (qed_mcp_get_shmem_proto_mfw(p_hwfn, p_ptt, p_proto)) 11386927e826SMintz, Yuval qed_mcp_get_shmem_proto_legacy(p_hwfn, p_proto); 1139fe56b9e6SYuval Mintz break; 1140c5ac9319SYuval Mintz case FUNC_MF_CFG_PROTOCOL_ISCSI: 1141c5ac9319SYuval Mintz *p_proto = QED_PCI_ISCSI; 1142c5ac9319SYuval Mintz break; 11431e128c81SArun Easi case FUNC_MF_CFG_PROTOCOL_FCOE: 11441e128c81SArun Easi *p_proto = QED_PCI_FCOE; 11451e128c81SArun Easi break; 1146c5ac9319SYuval Mintz case FUNC_MF_CFG_PROTOCOL_ROCE: 1147c5ac9319SYuval Mintz DP_NOTICE(p_hwfn, "RoCE personality is not a valid value!\n"); 11486927e826SMintz, Yuval /* Fallthrough */ 1149fe56b9e6SYuval Mintz default: 1150fe56b9e6SYuval Mintz rc = -EINVAL; 1151fe56b9e6SYuval Mintz } 1152fe56b9e6SYuval Mintz 1153fe56b9e6SYuval Mintz return rc; 1154fe56b9e6SYuval Mintz } 1155fe56b9e6SYuval Mintz 1156fe56b9e6SYuval Mintz int qed_mcp_fill_shmem_func_info(struct qed_hwfn *p_hwfn, 1157fe56b9e6SYuval Mintz struct qed_ptt *p_ptt) 1158fe56b9e6SYuval Mintz { 1159fe56b9e6SYuval Mintz struct qed_mcp_function_info *info; 1160fe56b9e6SYuval Mintz struct public_func shmem_info; 1161fe56b9e6SYuval Mintz 11621a635e48SYuval Mintz qed_mcp_get_shmem_func(p_hwfn, p_ptt, &shmem_info, MCP_PF_ID(p_hwfn)); 1163fe56b9e6SYuval Mintz info = &p_hwfn->mcp_info->func_info; 1164fe56b9e6SYuval Mintz 1165fe56b9e6SYuval Mintz info->pause_on_host = (shmem_info.config & 1166fe56b9e6SYuval Mintz FUNC_MF_CFG_PAUSE_ON_HOST_RING) ? 1 : 0; 1167fe56b9e6SYuval Mintz 11686927e826SMintz, Yuval if (qed_mcp_get_shmem_proto(p_hwfn, &shmem_info, p_ptt, 11696927e826SMintz, Yuval &info->protocol)) { 1170fe56b9e6SYuval Mintz DP_ERR(p_hwfn, "Unknown personality %08x\n", 1171fe56b9e6SYuval Mintz (u32)(shmem_info.config & FUNC_MF_CFG_PROTOCOL_MASK)); 1172fe56b9e6SYuval Mintz return -EINVAL; 1173fe56b9e6SYuval Mintz } 1174fe56b9e6SYuval Mintz 11754b01e519SManish Chopra qed_read_pf_bandwidth(p_hwfn, &shmem_info); 1176fe56b9e6SYuval Mintz 1177fe56b9e6SYuval Mintz if (shmem_info.mac_upper || shmem_info.mac_lower) { 1178fe56b9e6SYuval Mintz info->mac[0] = (u8)(shmem_info.mac_upper >> 8); 1179fe56b9e6SYuval Mintz info->mac[1] = (u8)(shmem_info.mac_upper); 1180fe56b9e6SYuval Mintz info->mac[2] = (u8)(shmem_info.mac_lower >> 24); 1181fe56b9e6SYuval Mintz info->mac[3] = (u8)(shmem_info.mac_lower >> 16); 1182fe56b9e6SYuval Mintz info->mac[4] = (u8)(shmem_info.mac_lower >> 8); 1183fe56b9e6SYuval Mintz info->mac[5] = (u8)(shmem_info.mac_lower); 118414d39648SMintz, Yuval 118514d39648SMintz, Yuval /* Store primary MAC for later possible WoL */ 118614d39648SMintz, Yuval memcpy(&p_hwfn->cdev->wol_mac, info->mac, ETH_ALEN); 1187fe56b9e6SYuval Mintz } else { 1188fe56b9e6SYuval Mintz DP_NOTICE(p_hwfn, "MAC is 0 in shmem\n"); 1189fe56b9e6SYuval Mintz } 1190fe56b9e6SYuval Mintz 1191fe56b9e6SYuval Mintz info->wwn_port = (u64)shmem_info.fcoe_wwn_port_name_upper | 1192fe56b9e6SYuval Mintz (((u64)shmem_info.fcoe_wwn_port_name_lower) << 32); 1193fe56b9e6SYuval Mintz info->wwn_node = (u64)shmem_info.fcoe_wwn_node_name_upper | 1194fe56b9e6SYuval Mintz (((u64)shmem_info.fcoe_wwn_node_name_lower) << 32); 1195fe56b9e6SYuval Mintz 1196fe56b9e6SYuval Mintz info->ovlan = (u16)(shmem_info.ovlan_stag & FUNC_MF_CFG_OV_STAG_MASK); 1197fe56b9e6SYuval Mintz 11980fefbfbaSSudarsana Kalluru info->mtu = (u16)shmem_info.mtu_size; 11990fefbfbaSSudarsana Kalluru 120014d39648SMintz, Yuval p_hwfn->hw_info.b_wol_support = QED_WOL_SUPPORT_NONE; 120114d39648SMintz, Yuval p_hwfn->cdev->wol_config = (u8)QED_OV_WOL_DEFAULT; 120214d39648SMintz, Yuval if (qed_mcp_is_init(p_hwfn)) { 120314d39648SMintz, Yuval u32 resp = 0, param = 0; 120414d39648SMintz, Yuval int rc; 120514d39648SMintz, Yuval 120614d39648SMintz, Yuval rc = qed_mcp_cmd(p_hwfn, p_ptt, 120714d39648SMintz, Yuval DRV_MSG_CODE_OS_WOL, 0, &resp, ¶m); 120814d39648SMintz, Yuval if (rc) 120914d39648SMintz, Yuval return rc; 121014d39648SMintz, Yuval if (resp == FW_MSG_CODE_OS_WOL_SUPPORTED) 121114d39648SMintz, Yuval p_hwfn->hw_info.b_wol_support = QED_WOL_SUPPORT_PME; 121214d39648SMintz, Yuval } 121314d39648SMintz, Yuval 1214fe56b9e6SYuval Mintz DP_VERBOSE(p_hwfn, (QED_MSG_SP | NETIF_MSG_IFUP), 121514d39648SMintz, 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", 1216fe56b9e6SYuval Mintz info->pause_on_host, info->protocol, 1217fe56b9e6SYuval Mintz info->bandwidth_min, info->bandwidth_max, 1218fe56b9e6SYuval Mintz info->mac[0], info->mac[1], info->mac[2], 1219fe56b9e6SYuval Mintz info->mac[3], info->mac[4], info->mac[5], 122014d39648SMintz, Yuval info->wwn_port, info->wwn_node, 122114d39648SMintz, Yuval info->ovlan, (u8)p_hwfn->hw_info.b_wol_support); 1222fe56b9e6SYuval Mintz 1223fe56b9e6SYuval Mintz return 0; 1224fe56b9e6SYuval Mintz } 1225fe56b9e6SYuval Mintz 1226cc875c2eSYuval Mintz struct qed_mcp_link_params 1227cc875c2eSYuval Mintz *qed_mcp_get_link_params(struct qed_hwfn *p_hwfn) 1228cc875c2eSYuval Mintz { 1229cc875c2eSYuval Mintz if (!p_hwfn || !p_hwfn->mcp_info) 1230cc875c2eSYuval Mintz return NULL; 1231cc875c2eSYuval Mintz return &p_hwfn->mcp_info->link_input; 1232cc875c2eSYuval Mintz } 1233cc875c2eSYuval Mintz 1234cc875c2eSYuval Mintz struct qed_mcp_link_state 1235cc875c2eSYuval Mintz *qed_mcp_get_link_state(struct qed_hwfn *p_hwfn) 1236cc875c2eSYuval Mintz { 1237cc875c2eSYuval Mintz if (!p_hwfn || !p_hwfn->mcp_info) 1238cc875c2eSYuval Mintz return NULL; 1239cc875c2eSYuval Mintz return &p_hwfn->mcp_info->link_output; 1240cc875c2eSYuval Mintz } 1241cc875c2eSYuval Mintz 1242cc875c2eSYuval Mintz struct qed_mcp_link_capabilities 1243cc875c2eSYuval Mintz *qed_mcp_get_link_capabilities(struct qed_hwfn *p_hwfn) 1244cc875c2eSYuval Mintz { 1245cc875c2eSYuval Mintz if (!p_hwfn || !p_hwfn->mcp_info) 1246cc875c2eSYuval Mintz return NULL; 1247cc875c2eSYuval Mintz return &p_hwfn->mcp_info->link_capabilities; 1248cc875c2eSYuval Mintz } 1249cc875c2eSYuval Mintz 12501a635e48SYuval Mintz int qed_mcp_drain(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 1251fe56b9e6SYuval Mintz { 1252fe56b9e6SYuval Mintz u32 resp = 0, param = 0; 1253fe56b9e6SYuval Mintz int rc; 1254fe56b9e6SYuval Mintz 1255fe56b9e6SYuval Mintz rc = qed_mcp_cmd(p_hwfn, p_ptt, 12561a635e48SYuval Mintz DRV_MSG_CODE_NIG_DRAIN, 1000, &resp, ¶m); 1257fe56b9e6SYuval Mintz 1258fe56b9e6SYuval Mintz /* Wait for the drain to complete before returning */ 12598f60bafeSYuval Mintz msleep(1020); 1260fe56b9e6SYuval Mintz 1261fe56b9e6SYuval Mintz return rc; 1262fe56b9e6SYuval Mintz } 1263fe56b9e6SYuval Mintz 1264cee4d264SManish Chopra int qed_mcp_get_flash_size(struct qed_hwfn *p_hwfn, 12651a635e48SYuval Mintz struct qed_ptt *p_ptt, u32 *p_flash_size) 1266cee4d264SManish Chopra { 1267cee4d264SManish Chopra u32 flash_size; 1268cee4d264SManish Chopra 12691408cc1fSYuval Mintz if (IS_VF(p_hwfn->cdev)) 12701408cc1fSYuval Mintz return -EINVAL; 12711408cc1fSYuval Mintz 1272cee4d264SManish Chopra flash_size = qed_rd(p_hwfn, p_ptt, MCP_REG_NVM_CFG4); 1273cee4d264SManish Chopra flash_size = (flash_size & MCP_REG_NVM_CFG4_FLASH_SIZE) >> 1274cee4d264SManish Chopra MCP_REG_NVM_CFG4_FLASH_SIZE_SHIFT; 1275cee4d264SManish Chopra flash_size = (1 << (flash_size + MCP_BYTES_PER_MBIT_SHIFT)); 1276cee4d264SManish Chopra 1277cee4d264SManish Chopra *p_flash_size = flash_size; 1278cee4d264SManish Chopra 1279cee4d264SManish Chopra return 0; 1280cee4d264SManish Chopra } 1281cee4d264SManish Chopra 12821408cc1fSYuval Mintz int qed_mcp_config_vf_msix(struct qed_hwfn *p_hwfn, 12831408cc1fSYuval Mintz struct qed_ptt *p_ptt, u8 vf_id, u8 num) 12841408cc1fSYuval Mintz { 12851408cc1fSYuval Mintz u32 resp = 0, param = 0, rc_param = 0; 12861408cc1fSYuval Mintz int rc; 12871408cc1fSYuval Mintz 12881408cc1fSYuval Mintz /* Only Leader can configure MSIX, and need to take CMT into account */ 12891408cc1fSYuval Mintz if (!IS_LEAD_HWFN(p_hwfn)) 12901408cc1fSYuval Mintz return 0; 12911408cc1fSYuval Mintz num *= p_hwfn->cdev->num_hwfns; 12921408cc1fSYuval Mintz 12931408cc1fSYuval Mintz param |= (vf_id << DRV_MB_PARAM_CFG_VF_MSIX_VF_ID_SHIFT) & 12941408cc1fSYuval Mintz DRV_MB_PARAM_CFG_VF_MSIX_VF_ID_MASK; 12951408cc1fSYuval Mintz param |= (num << DRV_MB_PARAM_CFG_VF_MSIX_SB_NUM_SHIFT) & 12961408cc1fSYuval Mintz DRV_MB_PARAM_CFG_VF_MSIX_SB_NUM_MASK; 12971408cc1fSYuval Mintz 12981408cc1fSYuval Mintz rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_CFG_VF_MSIX, param, 12991408cc1fSYuval Mintz &resp, &rc_param); 13001408cc1fSYuval Mintz 13011408cc1fSYuval Mintz if (resp != FW_MSG_CODE_DRV_CFG_VF_MSIX_DONE) { 13021408cc1fSYuval Mintz DP_NOTICE(p_hwfn, "VF[%d]: MFW failed to set MSI-X\n", vf_id); 13031408cc1fSYuval Mintz rc = -EINVAL; 13041408cc1fSYuval Mintz } else { 13051408cc1fSYuval Mintz DP_VERBOSE(p_hwfn, QED_MSG_IOV, 13061408cc1fSYuval Mintz "Requested 0x%02x MSI-x interrupts from VF 0x%02x\n", 13071408cc1fSYuval Mintz num, vf_id); 13081408cc1fSYuval Mintz } 13091408cc1fSYuval Mintz 13101408cc1fSYuval Mintz return rc; 13111408cc1fSYuval Mintz } 13121408cc1fSYuval Mintz 1313fe56b9e6SYuval Mintz int 1314fe56b9e6SYuval Mintz qed_mcp_send_drv_version(struct qed_hwfn *p_hwfn, 1315fe56b9e6SYuval Mintz struct qed_ptt *p_ptt, 1316fe56b9e6SYuval Mintz struct qed_mcp_drv_version *p_ver) 1317fe56b9e6SYuval Mintz { 13185529bad9STomer Tayar struct drv_version_stc *p_drv_version; 13195529bad9STomer Tayar struct qed_mcp_mb_params mb_params; 13205529bad9STomer Tayar union drv_union_data union_data; 13215529bad9STomer Tayar __be32 val; 13225529bad9STomer Tayar u32 i; 13235529bad9STomer Tayar int rc; 1324fe56b9e6SYuval Mintz 13255529bad9STomer Tayar p_drv_version = &union_data.drv_version; 13265529bad9STomer Tayar p_drv_version->version = p_ver->version; 13274b01e519SManish Chopra 132867a99b70SYuval Mintz for (i = 0; i < (MCP_DRV_VER_STR_SIZE - 4) / sizeof(u32); i++) { 132967a99b70SYuval Mintz val = cpu_to_be32(*((u32 *)&p_ver->name[i * sizeof(u32)])); 13304b01e519SManish Chopra *(__be32 *)&p_drv_version->name[i * sizeof(u32)] = val; 1331fe56b9e6SYuval Mintz } 1332fe56b9e6SYuval Mintz 13335529bad9STomer Tayar memset(&mb_params, 0, sizeof(mb_params)); 13345529bad9STomer Tayar mb_params.cmd = DRV_MSG_CODE_SET_VERSION; 13355529bad9STomer Tayar mb_params.p_data_src = &union_data; 13365529bad9STomer Tayar rc = qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 13375529bad9STomer Tayar if (rc) 1338fe56b9e6SYuval Mintz DP_ERR(p_hwfn, "MCP response failure, aborting\n"); 1339fe56b9e6SYuval Mintz 13405529bad9STomer Tayar return rc; 1341fe56b9e6SYuval Mintz } 134291420b83SSudarsana Kalluru 13434102426fSTomer Tayar int qed_mcp_halt(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 13444102426fSTomer Tayar { 13454102426fSTomer Tayar u32 resp = 0, param = 0; 13464102426fSTomer Tayar int rc; 13474102426fSTomer Tayar 13484102426fSTomer Tayar rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_MCP_HALT, 0, &resp, 13494102426fSTomer Tayar ¶m); 13504102426fSTomer Tayar if (rc) 13514102426fSTomer Tayar DP_ERR(p_hwfn, "MCP response failure, aborting\n"); 13524102426fSTomer Tayar 13534102426fSTomer Tayar return rc; 13544102426fSTomer Tayar } 13554102426fSTomer Tayar 13564102426fSTomer Tayar int qed_mcp_resume(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 13574102426fSTomer Tayar { 13584102426fSTomer Tayar u32 value, cpu_mode; 13594102426fSTomer Tayar 13604102426fSTomer Tayar qed_wr(p_hwfn, p_ptt, MCP_REG_CPU_STATE, 0xffffffff); 13614102426fSTomer Tayar 13624102426fSTomer Tayar value = qed_rd(p_hwfn, p_ptt, MCP_REG_CPU_MODE); 13634102426fSTomer Tayar value &= ~MCP_REG_CPU_MODE_SOFT_HALT; 13644102426fSTomer Tayar qed_wr(p_hwfn, p_ptt, MCP_REG_CPU_MODE, value); 13654102426fSTomer Tayar cpu_mode = qed_rd(p_hwfn, p_ptt, MCP_REG_CPU_MODE); 13664102426fSTomer Tayar 13674102426fSTomer Tayar return (cpu_mode & MCP_REG_CPU_MODE_SOFT_HALT) ? -EAGAIN : 0; 13684102426fSTomer Tayar } 13694102426fSTomer Tayar 13700fefbfbaSSudarsana Kalluru int qed_mcp_ov_update_current_config(struct qed_hwfn *p_hwfn, 13710fefbfbaSSudarsana Kalluru struct qed_ptt *p_ptt, 13720fefbfbaSSudarsana Kalluru enum qed_ov_client client) 13730fefbfbaSSudarsana Kalluru { 13740fefbfbaSSudarsana Kalluru u32 resp = 0, param = 0; 13750fefbfbaSSudarsana Kalluru u32 drv_mb_param; 13760fefbfbaSSudarsana Kalluru int rc; 13770fefbfbaSSudarsana Kalluru 13780fefbfbaSSudarsana Kalluru switch (client) { 13790fefbfbaSSudarsana Kalluru case QED_OV_CLIENT_DRV: 13800fefbfbaSSudarsana Kalluru drv_mb_param = DRV_MB_PARAM_OV_CURR_CFG_OS; 13810fefbfbaSSudarsana Kalluru break; 13820fefbfbaSSudarsana Kalluru case QED_OV_CLIENT_USER: 13830fefbfbaSSudarsana Kalluru drv_mb_param = DRV_MB_PARAM_OV_CURR_CFG_OTHER; 13840fefbfbaSSudarsana Kalluru break; 13850fefbfbaSSudarsana Kalluru case QED_OV_CLIENT_VENDOR_SPEC: 13860fefbfbaSSudarsana Kalluru drv_mb_param = DRV_MB_PARAM_OV_CURR_CFG_VENDOR_SPEC; 13870fefbfbaSSudarsana Kalluru break; 13880fefbfbaSSudarsana Kalluru default: 13890fefbfbaSSudarsana Kalluru DP_NOTICE(p_hwfn, "Invalid client type %d\n", client); 13900fefbfbaSSudarsana Kalluru return -EINVAL; 13910fefbfbaSSudarsana Kalluru } 13920fefbfbaSSudarsana Kalluru 13930fefbfbaSSudarsana Kalluru rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_OV_UPDATE_CURR_CFG, 13940fefbfbaSSudarsana Kalluru drv_mb_param, &resp, ¶m); 13950fefbfbaSSudarsana Kalluru if (rc) 13960fefbfbaSSudarsana Kalluru DP_ERR(p_hwfn, "MCP response failure, aborting\n"); 13970fefbfbaSSudarsana Kalluru 13980fefbfbaSSudarsana Kalluru return rc; 13990fefbfbaSSudarsana Kalluru } 14000fefbfbaSSudarsana Kalluru 14010fefbfbaSSudarsana Kalluru int qed_mcp_ov_update_driver_state(struct qed_hwfn *p_hwfn, 14020fefbfbaSSudarsana Kalluru struct qed_ptt *p_ptt, 14030fefbfbaSSudarsana Kalluru enum qed_ov_driver_state drv_state) 14040fefbfbaSSudarsana Kalluru { 14050fefbfbaSSudarsana Kalluru u32 resp = 0, param = 0; 14060fefbfbaSSudarsana Kalluru u32 drv_mb_param; 14070fefbfbaSSudarsana Kalluru int rc; 14080fefbfbaSSudarsana Kalluru 14090fefbfbaSSudarsana Kalluru switch (drv_state) { 14100fefbfbaSSudarsana Kalluru case QED_OV_DRIVER_STATE_NOT_LOADED: 14110fefbfbaSSudarsana Kalluru drv_mb_param = DRV_MSG_CODE_OV_UPDATE_DRIVER_STATE_NOT_LOADED; 14120fefbfbaSSudarsana Kalluru break; 14130fefbfbaSSudarsana Kalluru case QED_OV_DRIVER_STATE_DISABLED: 14140fefbfbaSSudarsana Kalluru drv_mb_param = DRV_MSG_CODE_OV_UPDATE_DRIVER_STATE_DISABLED; 14150fefbfbaSSudarsana Kalluru break; 14160fefbfbaSSudarsana Kalluru case QED_OV_DRIVER_STATE_ACTIVE: 14170fefbfbaSSudarsana Kalluru drv_mb_param = DRV_MSG_CODE_OV_UPDATE_DRIVER_STATE_ACTIVE; 14180fefbfbaSSudarsana Kalluru break; 14190fefbfbaSSudarsana Kalluru default: 14200fefbfbaSSudarsana Kalluru DP_NOTICE(p_hwfn, "Invalid driver state %d\n", drv_state); 14210fefbfbaSSudarsana Kalluru return -EINVAL; 14220fefbfbaSSudarsana Kalluru } 14230fefbfbaSSudarsana Kalluru 14240fefbfbaSSudarsana Kalluru rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_OV_UPDATE_DRIVER_STATE, 14250fefbfbaSSudarsana Kalluru drv_mb_param, &resp, ¶m); 14260fefbfbaSSudarsana Kalluru if (rc) 14270fefbfbaSSudarsana Kalluru DP_ERR(p_hwfn, "Failed to send driver state\n"); 14280fefbfbaSSudarsana Kalluru 14290fefbfbaSSudarsana Kalluru return rc; 14300fefbfbaSSudarsana Kalluru } 14310fefbfbaSSudarsana Kalluru 14320fefbfbaSSudarsana Kalluru int qed_mcp_ov_update_mtu(struct qed_hwfn *p_hwfn, 14330fefbfbaSSudarsana Kalluru struct qed_ptt *p_ptt, u16 mtu) 14340fefbfbaSSudarsana Kalluru { 14350fefbfbaSSudarsana Kalluru u32 resp = 0, param = 0; 14360fefbfbaSSudarsana Kalluru u32 drv_mb_param; 14370fefbfbaSSudarsana Kalluru int rc; 14380fefbfbaSSudarsana Kalluru 14390fefbfbaSSudarsana Kalluru drv_mb_param = (u32)mtu << DRV_MB_PARAM_OV_MTU_SIZE_SHIFT; 14400fefbfbaSSudarsana Kalluru rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_OV_UPDATE_MTU, 14410fefbfbaSSudarsana Kalluru drv_mb_param, &resp, ¶m); 14420fefbfbaSSudarsana Kalluru if (rc) 14430fefbfbaSSudarsana Kalluru DP_ERR(p_hwfn, "Failed to send mtu value, rc = %d\n", rc); 14440fefbfbaSSudarsana Kalluru 14450fefbfbaSSudarsana Kalluru return rc; 14460fefbfbaSSudarsana Kalluru } 14470fefbfbaSSudarsana Kalluru 14480fefbfbaSSudarsana Kalluru int qed_mcp_ov_update_mac(struct qed_hwfn *p_hwfn, 14490fefbfbaSSudarsana Kalluru struct qed_ptt *p_ptt, u8 *mac) 14500fefbfbaSSudarsana Kalluru { 14510fefbfbaSSudarsana Kalluru struct qed_mcp_mb_params mb_params; 14520fefbfbaSSudarsana Kalluru union drv_union_data union_data; 14530fefbfbaSSudarsana Kalluru int rc; 14540fefbfbaSSudarsana Kalluru 14550fefbfbaSSudarsana Kalluru memset(&mb_params, 0, sizeof(mb_params)); 14560fefbfbaSSudarsana Kalluru mb_params.cmd = DRV_MSG_CODE_SET_VMAC; 14570fefbfbaSSudarsana Kalluru mb_params.param = DRV_MSG_CODE_VMAC_TYPE_MAC << 14580fefbfbaSSudarsana Kalluru DRV_MSG_CODE_VMAC_TYPE_SHIFT; 14590fefbfbaSSudarsana Kalluru mb_params.param |= MCP_PF_ID(p_hwfn); 14600fefbfbaSSudarsana Kalluru ether_addr_copy(&union_data.raw_data[0], mac); 14610fefbfbaSSudarsana Kalluru mb_params.p_data_src = &union_data; 14620fefbfbaSSudarsana Kalluru rc = qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 14630fefbfbaSSudarsana Kalluru if (rc) 14640fefbfbaSSudarsana Kalluru DP_ERR(p_hwfn, "Failed to send mac address, rc = %d\n", rc); 14650fefbfbaSSudarsana Kalluru 146614d39648SMintz, Yuval /* Store primary MAC for later possible WoL */ 146714d39648SMintz, Yuval memcpy(p_hwfn->cdev->wol_mac, mac, ETH_ALEN); 146814d39648SMintz, Yuval 14690fefbfbaSSudarsana Kalluru return rc; 14700fefbfbaSSudarsana Kalluru } 14710fefbfbaSSudarsana Kalluru 14720fefbfbaSSudarsana Kalluru int qed_mcp_ov_update_wol(struct qed_hwfn *p_hwfn, 14730fefbfbaSSudarsana Kalluru struct qed_ptt *p_ptt, enum qed_ov_wol wol) 14740fefbfbaSSudarsana Kalluru { 14750fefbfbaSSudarsana Kalluru u32 resp = 0, param = 0; 14760fefbfbaSSudarsana Kalluru u32 drv_mb_param; 14770fefbfbaSSudarsana Kalluru int rc; 14780fefbfbaSSudarsana Kalluru 147914d39648SMintz, Yuval if (p_hwfn->hw_info.b_wol_support == QED_WOL_SUPPORT_NONE) { 148014d39648SMintz, Yuval DP_VERBOSE(p_hwfn, QED_MSG_SP, 148114d39648SMintz, Yuval "Can't change WoL configuration when WoL isn't supported\n"); 148214d39648SMintz, Yuval return -EINVAL; 148314d39648SMintz, Yuval } 148414d39648SMintz, Yuval 14850fefbfbaSSudarsana Kalluru switch (wol) { 14860fefbfbaSSudarsana Kalluru case QED_OV_WOL_DEFAULT: 14870fefbfbaSSudarsana Kalluru drv_mb_param = DRV_MB_PARAM_WOL_DEFAULT; 14880fefbfbaSSudarsana Kalluru break; 14890fefbfbaSSudarsana Kalluru case QED_OV_WOL_DISABLED: 14900fefbfbaSSudarsana Kalluru drv_mb_param = DRV_MB_PARAM_WOL_DISABLED; 14910fefbfbaSSudarsana Kalluru break; 14920fefbfbaSSudarsana Kalluru case QED_OV_WOL_ENABLED: 14930fefbfbaSSudarsana Kalluru drv_mb_param = DRV_MB_PARAM_WOL_ENABLED; 14940fefbfbaSSudarsana Kalluru break; 14950fefbfbaSSudarsana Kalluru default: 14960fefbfbaSSudarsana Kalluru DP_ERR(p_hwfn, "Invalid wol state %d\n", wol); 14970fefbfbaSSudarsana Kalluru return -EINVAL; 14980fefbfbaSSudarsana Kalluru } 14990fefbfbaSSudarsana Kalluru 15000fefbfbaSSudarsana Kalluru rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_OV_UPDATE_WOL, 15010fefbfbaSSudarsana Kalluru drv_mb_param, &resp, ¶m); 15020fefbfbaSSudarsana Kalluru if (rc) 15030fefbfbaSSudarsana Kalluru DP_ERR(p_hwfn, "Failed to send wol mode, rc = %d\n", rc); 15040fefbfbaSSudarsana Kalluru 150514d39648SMintz, Yuval /* Store the WoL update for a future unload */ 150614d39648SMintz, Yuval p_hwfn->cdev->wol_config = (u8)wol; 150714d39648SMintz, Yuval 15080fefbfbaSSudarsana Kalluru return rc; 15090fefbfbaSSudarsana Kalluru } 15100fefbfbaSSudarsana Kalluru 15110fefbfbaSSudarsana Kalluru int qed_mcp_ov_update_eswitch(struct qed_hwfn *p_hwfn, 15120fefbfbaSSudarsana Kalluru struct qed_ptt *p_ptt, 15130fefbfbaSSudarsana Kalluru enum qed_ov_eswitch eswitch) 15140fefbfbaSSudarsana Kalluru { 15150fefbfbaSSudarsana Kalluru u32 resp = 0, param = 0; 15160fefbfbaSSudarsana Kalluru u32 drv_mb_param; 15170fefbfbaSSudarsana Kalluru int rc; 15180fefbfbaSSudarsana Kalluru 15190fefbfbaSSudarsana Kalluru switch (eswitch) { 15200fefbfbaSSudarsana Kalluru case QED_OV_ESWITCH_NONE: 15210fefbfbaSSudarsana Kalluru drv_mb_param = DRV_MB_PARAM_ESWITCH_MODE_NONE; 15220fefbfbaSSudarsana Kalluru break; 15230fefbfbaSSudarsana Kalluru case QED_OV_ESWITCH_VEB: 15240fefbfbaSSudarsana Kalluru drv_mb_param = DRV_MB_PARAM_ESWITCH_MODE_VEB; 15250fefbfbaSSudarsana Kalluru break; 15260fefbfbaSSudarsana Kalluru case QED_OV_ESWITCH_VEPA: 15270fefbfbaSSudarsana Kalluru drv_mb_param = DRV_MB_PARAM_ESWITCH_MODE_VEPA; 15280fefbfbaSSudarsana Kalluru break; 15290fefbfbaSSudarsana Kalluru default: 15300fefbfbaSSudarsana Kalluru DP_ERR(p_hwfn, "Invalid eswitch mode %d\n", eswitch); 15310fefbfbaSSudarsana Kalluru return -EINVAL; 15320fefbfbaSSudarsana Kalluru } 15330fefbfbaSSudarsana Kalluru 15340fefbfbaSSudarsana Kalluru rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_OV_UPDATE_ESWITCH_MODE, 15350fefbfbaSSudarsana Kalluru drv_mb_param, &resp, ¶m); 15360fefbfbaSSudarsana Kalluru if (rc) 15370fefbfbaSSudarsana Kalluru DP_ERR(p_hwfn, "Failed to send eswitch mode, rc = %d\n", rc); 15380fefbfbaSSudarsana Kalluru 15390fefbfbaSSudarsana Kalluru return rc; 15400fefbfbaSSudarsana Kalluru } 15410fefbfbaSSudarsana Kalluru 15421a635e48SYuval Mintz int qed_mcp_set_led(struct qed_hwfn *p_hwfn, 15431a635e48SYuval Mintz struct qed_ptt *p_ptt, enum qed_led_mode mode) 154491420b83SSudarsana Kalluru { 154591420b83SSudarsana Kalluru u32 resp = 0, param = 0, drv_mb_param; 154691420b83SSudarsana Kalluru int rc; 154791420b83SSudarsana Kalluru 154891420b83SSudarsana Kalluru switch (mode) { 154991420b83SSudarsana Kalluru case QED_LED_MODE_ON: 155091420b83SSudarsana Kalluru drv_mb_param = DRV_MB_PARAM_SET_LED_MODE_ON; 155191420b83SSudarsana Kalluru break; 155291420b83SSudarsana Kalluru case QED_LED_MODE_OFF: 155391420b83SSudarsana Kalluru drv_mb_param = DRV_MB_PARAM_SET_LED_MODE_OFF; 155491420b83SSudarsana Kalluru break; 155591420b83SSudarsana Kalluru case QED_LED_MODE_RESTORE: 155691420b83SSudarsana Kalluru drv_mb_param = DRV_MB_PARAM_SET_LED_MODE_OPER; 155791420b83SSudarsana Kalluru break; 155891420b83SSudarsana Kalluru default: 155991420b83SSudarsana Kalluru DP_NOTICE(p_hwfn, "Invalid LED mode %d\n", mode); 156091420b83SSudarsana Kalluru return -EINVAL; 156191420b83SSudarsana Kalluru } 156291420b83SSudarsana Kalluru 156391420b83SSudarsana Kalluru rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_SET_LED_MODE, 156491420b83SSudarsana Kalluru drv_mb_param, &resp, ¶m); 156591420b83SSudarsana Kalluru 156691420b83SSudarsana Kalluru return rc; 156791420b83SSudarsana Kalluru } 156803dc76caSSudarsana Reddy Kalluru 15694102426fSTomer Tayar int qed_mcp_mask_parities(struct qed_hwfn *p_hwfn, 15704102426fSTomer Tayar struct qed_ptt *p_ptt, u32 mask_parities) 15714102426fSTomer Tayar { 15724102426fSTomer Tayar u32 resp = 0, param = 0; 15734102426fSTomer Tayar int rc; 15744102426fSTomer Tayar 15754102426fSTomer Tayar rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_MASK_PARITIES, 15764102426fSTomer Tayar mask_parities, &resp, ¶m); 15774102426fSTomer Tayar 15784102426fSTomer Tayar if (rc) { 15794102426fSTomer Tayar DP_ERR(p_hwfn, 15804102426fSTomer Tayar "MCP response failure for mask parities, aborting\n"); 15814102426fSTomer Tayar } else if (resp != FW_MSG_CODE_OK) { 15824102426fSTomer Tayar DP_ERR(p_hwfn, 15834102426fSTomer Tayar "MCP did not acknowledge mask parity request. Old MFW?\n"); 15844102426fSTomer Tayar rc = -EINVAL; 15854102426fSTomer Tayar } 15864102426fSTomer Tayar 15874102426fSTomer Tayar return rc; 15884102426fSTomer Tayar } 15894102426fSTomer Tayar 15907a4b21b7SMintz, Yuval int qed_mcp_nvm_read(struct qed_dev *cdev, u32 addr, u8 *p_buf, u32 len) 15917a4b21b7SMintz, Yuval { 15927a4b21b7SMintz, Yuval u32 bytes_left = len, offset = 0, bytes_to_copy, read_len = 0; 15937a4b21b7SMintz, Yuval struct qed_hwfn *p_hwfn = QED_LEADING_HWFN(cdev); 15947a4b21b7SMintz, Yuval u32 resp = 0, resp_param = 0; 15957a4b21b7SMintz, Yuval struct qed_ptt *p_ptt; 15967a4b21b7SMintz, Yuval int rc = 0; 15977a4b21b7SMintz, Yuval 15987a4b21b7SMintz, Yuval p_ptt = qed_ptt_acquire(p_hwfn); 15997a4b21b7SMintz, Yuval if (!p_ptt) 16007a4b21b7SMintz, Yuval return -EBUSY; 16017a4b21b7SMintz, Yuval 16027a4b21b7SMintz, Yuval while (bytes_left > 0) { 16037a4b21b7SMintz, Yuval bytes_to_copy = min_t(u32, bytes_left, MCP_DRV_NVM_BUF_LEN); 16047a4b21b7SMintz, Yuval 16057a4b21b7SMintz, Yuval rc = qed_mcp_nvm_rd_cmd(p_hwfn, p_ptt, 16067a4b21b7SMintz, Yuval DRV_MSG_CODE_NVM_READ_NVRAM, 16077a4b21b7SMintz, Yuval addr + offset + 16087a4b21b7SMintz, Yuval (bytes_to_copy << 16097a4b21b7SMintz, Yuval DRV_MB_PARAM_NVM_LEN_SHIFT), 16107a4b21b7SMintz, Yuval &resp, &resp_param, 16117a4b21b7SMintz, Yuval &read_len, 16127a4b21b7SMintz, Yuval (u32 *)(p_buf + offset)); 16137a4b21b7SMintz, Yuval 16147a4b21b7SMintz, Yuval if (rc || (resp != FW_MSG_CODE_NVM_OK)) { 16157a4b21b7SMintz, Yuval DP_NOTICE(cdev, "MCP command rc = %d\n", rc); 16167a4b21b7SMintz, Yuval break; 16177a4b21b7SMintz, Yuval } 16187a4b21b7SMintz, Yuval 16197a4b21b7SMintz, Yuval /* This can be a lengthy process, and it's possible scheduler 16207a4b21b7SMintz, Yuval * isn't preemptable. Sleep a bit to prevent CPU hogging. 16217a4b21b7SMintz, Yuval */ 16227a4b21b7SMintz, Yuval if (bytes_left % 0x1000 < 16237a4b21b7SMintz, Yuval (bytes_left - read_len) % 0x1000) 16247a4b21b7SMintz, Yuval usleep_range(1000, 2000); 16257a4b21b7SMintz, Yuval 16267a4b21b7SMintz, Yuval offset += read_len; 16277a4b21b7SMintz, Yuval bytes_left -= read_len; 16287a4b21b7SMintz, Yuval } 16297a4b21b7SMintz, Yuval 16307a4b21b7SMintz, Yuval cdev->mcp_nvm_resp = resp; 16317a4b21b7SMintz, Yuval qed_ptt_release(p_hwfn, p_ptt); 16327a4b21b7SMintz, Yuval 16337a4b21b7SMintz, Yuval return rc; 16347a4b21b7SMintz, Yuval } 16357a4b21b7SMintz, Yuval 163603dc76caSSudarsana Reddy Kalluru int qed_mcp_bist_register_test(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 163703dc76caSSudarsana Reddy Kalluru { 163803dc76caSSudarsana Reddy Kalluru u32 drv_mb_param = 0, rsp, param; 163903dc76caSSudarsana Reddy Kalluru int rc = 0; 164003dc76caSSudarsana Reddy Kalluru 164103dc76caSSudarsana Reddy Kalluru drv_mb_param = (DRV_MB_PARAM_BIST_REGISTER_TEST << 164203dc76caSSudarsana Reddy Kalluru DRV_MB_PARAM_BIST_TEST_INDEX_SHIFT); 164303dc76caSSudarsana Reddy Kalluru 164403dc76caSSudarsana Reddy Kalluru rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_BIST_TEST, 164503dc76caSSudarsana Reddy Kalluru drv_mb_param, &rsp, ¶m); 164603dc76caSSudarsana Reddy Kalluru 164703dc76caSSudarsana Reddy Kalluru if (rc) 164803dc76caSSudarsana Reddy Kalluru return rc; 164903dc76caSSudarsana Reddy Kalluru 165003dc76caSSudarsana Reddy Kalluru if (((rsp & FW_MSG_CODE_MASK) != FW_MSG_CODE_OK) || 165103dc76caSSudarsana Reddy Kalluru (param != DRV_MB_PARAM_BIST_RC_PASSED)) 165203dc76caSSudarsana Reddy Kalluru rc = -EAGAIN; 165303dc76caSSudarsana Reddy Kalluru 165403dc76caSSudarsana Reddy Kalluru return rc; 165503dc76caSSudarsana Reddy Kalluru } 165603dc76caSSudarsana Reddy Kalluru 165703dc76caSSudarsana Reddy Kalluru int qed_mcp_bist_clock_test(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt) 165803dc76caSSudarsana Reddy Kalluru { 165903dc76caSSudarsana Reddy Kalluru u32 drv_mb_param, rsp, param; 166003dc76caSSudarsana Reddy Kalluru int rc = 0; 166103dc76caSSudarsana Reddy Kalluru 166203dc76caSSudarsana Reddy Kalluru drv_mb_param = (DRV_MB_PARAM_BIST_CLOCK_TEST << 166303dc76caSSudarsana Reddy Kalluru DRV_MB_PARAM_BIST_TEST_INDEX_SHIFT); 166403dc76caSSudarsana Reddy Kalluru 166503dc76caSSudarsana Reddy Kalluru rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_BIST_TEST, 166603dc76caSSudarsana Reddy Kalluru drv_mb_param, &rsp, ¶m); 166703dc76caSSudarsana Reddy Kalluru 166803dc76caSSudarsana Reddy Kalluru if (rc) 166903dc76caSSudarsana Reddy Kalluru return rc; 167003dc76caSSudarsana Reddy Kalluru 167103dc76caSSudarsana Reddy Kalluru if (((rsp & FW_MSG_CODE_MASK) != FW_MSG_CODE_OK) || 167203dc76caSSudarsana Reddy Kalluru (param != DRV_MB_PARAM_BIST_RC_PASSED)) 167303dc76caSSudarsana Reddy Kalluru rc = -EAGAIN; 167403dc76caSSudarsana Reddy Kalluru 167503dc76caSSudarsana Reddy Kalluru return rc; 167603dc76caSSudarsana Reddy Kalluru } 16777a4b21b7SMintz, Yuval 16787a4b21b7SMintz, Yuval int qed_mcp_bist_nvm_test_get_num_images(struct qed_hwfn *p_hwfn, 16797a4b21b7SMintz, Yuval struct qed_ptt *p_ptt, 16807a4b21b7SMintz, Yuval u32 *num_images) 16817a4b21b7SMintz, Yuval { 16827a4b21b7SMintz, Yuval u32 drv_mb_param = 0, rsp; 16837a4b21b7SMintz, Yuval int rc = 0; 16847a4b21b7SMintz, Yuval 16857a4b21b7SMintz, Yuval drv_mb_param = (DRV_MB_PARAM_BIST_NVM_TEST_NUM_IMAGES << 16867a4b21b7SMintz, Yuval DRV_MB_PARAM_BIST_TEST_INDEX_SHIFT); 16877a4b21b7SMintz, Yuval 16887a4b21b7SMintz, Yuval rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_BIST_TEST, 16897a4b21b7SMintz, Yuval drv_mb_param, &rsp, num_images); 16907a4b21b7SMintz, Yuval if (rc) 16917a4b21b7SMintz, Yuval return rc; 16927a4b21b7SMintz, Yuval 16937a4b21b7SMintz, Yuval if (((rsp & FW_MSG_CODE_MASK) != FW_MSG_CODE_OK)) 16947a4b21b7SMintz, Yuval rc = -EINVAL; 16957a4b21b7SMintz, Yuval 16967a4b21b7SMintz, Yuval return rc; 16977a4b21b7SMintz, Yuval } 16987a4b21b7SMintz, Yuval 16997a4b21b7SMintz, Yuval int qed_mcp_bist_nvm_test_get_image_att(struct qed_hwfn *p_hwfn, 17007a4b21b7SMintz, Yuval struct qed_ptt *p_ptt, 17017a4b21b7SMintz, Yuval struct bist_nvm_image_att *p_image_att, 17027a4b21b7SMintz, Yuval u32 image_index) 17037a4b21b7SMintz, Yuval { 17047a4b21b7SMintz, Yuval u32 buf_size = 0, param, resp = 0, resp_param = 0; 17057a4b21b7SMintz, Yuval int rc; 17067a4b21b7SMintz, Yuval 17077a4b21b7SMintz, Yuval param = DRV_MB_PARAM_BIST_NVM_TEST_IMAGE_BY_INDEX << 17087a4b21b7SMintz, Yuval DRV_MB_PARAM_BIST_TEST_INDEX_SHIFT; 17097a4b21b7SMintz, Yuval param |= image_index << DRV_MB_PARAM_BIST_TEST_IMAGE_INDEX_SHIFT; 17107a4b21b7SMintz, Yuval 17117a4b21b7SMintz, Yuval rc = qed_mcp_nvm_rd_cmd(p_hwfn, p_ptt, 17127a4b21b7SMintz, Yuval DRV_MSG_CODE_BIST_TEST, param, 17137a4b21b7SMintz, Yuval &resp, &resp_param, 17147a4b21b7SMintz, Yuval &buf_size, 17157a4b21b7SMintz, Yuval (u32 *)p_image_att); 17167a4b21b7SMintz, Yuval if (rc) 17177a4b21b7SMintz, Yuval return rc; 17187a4b21b7SMintz, Yuval 17197a4b21b7SMintz, Yuval if (((resp & FW_MSG_CODE_MASK) != FW_MSG_CODE_OK) || 17207a4b21b7SMintz, Yuval (p_image_att->return_code != 1)) 17217a4b21b7SMintz, Yuval rc = -EINVAL; 17227a4b21b7SMintz, Yuval 17237a4b21b7SMintz, Yuval return rc; 17247a4b21b7SMintz, Yuval } 17252edbff8dSTomer Tayar 17262edbff8dSTomer Tayar #define QED_RESC_ALLOC_VERSION_MAJOR 1 17272edbff8dSTomer Tayar #define QED_RESC_ALLOC_VERSION_MINOR 0 17282edbff8dSTomer Tayar #define QED_RESC_ALLOC_VERSION \ 17292edbff8dSTomer Tayar ((QED_RESC_ALLOC_VERSION_MAJOR << \ 17302edbff8dSTomer Tayar DRV_MB_PARAM_RESOURCE_ALLOC_VERSION_MAJOR_SHIFT) | \ 17312edbff8dSTomer Tayar (QED_RESC_ALLOC_VERSION_MINOR << \ 17322edbff8dSTomer Tayar DRV_MB_PARAM_RESOURCE_ALLOC_VERSION_MINOR_SHIFT)) 17332edbff8dSTomer Tayar int qed_mcp_get_resc_info(struct qed_hwfn *p_hwfn, 17342edbff8dSTomer Tayar struct qed_ptt *p_ptt, 17352edbff8dSTomer Tayar struct resource_info *p_resc_info, 17362edbff8dSTomer Tayar u32 *p_mcp_resp, u32 *p_mcp_param) 17372edbff8dSTomer Tayar { 17382edbff8dSTomer Tayar struct qed_mcp_mb_params mb_params; 1739bb480242SMintz, Yuval union drv_union_data union_data; 17402edbff8dSTomer Tayar int rc; 17412edbff8dSTomer Tayar 17422edbff8dSTomer Tayar memset(&mb_params, 0, sizeof(mb_params)); 1743bb480242SMintz, Yuval memset(&union_data, 0, sizeof(union_data)); 17442edbff8dSTomer Tayar mb_params.cmd = DRV_MSG_GET_RESOURCE_ALLOC_MSG; 17452edbff8dSTomer Tayar mb_params.param = QED_RESC_ALLOC_VERSION; 1746bb480242SMintz, Yuval 1747bb480242SMintz, Yuval /* Need to have a sufficient large struct, as the cmd_and_union 1748bb480242SMintz, Yuval * is going to do memcpy from and to it. 1749bb480242SMintz, Yuval */ 1750bb480242SMintz, Yuval memcpy(&union_data.resource, p_resc_info, sizeof(*p_resc_info)); 1751bb480242SMintz, Yuval 1752bb480242SMintz, Yuval mb_params.p_data_src = &union_data; 1753bb480242SMintz, Yuval mb_params.p_data_dst = &union_data; 17542edbff8dSTomer Tayar rc = qed_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 17552edbff8dSTomer Tayar if (rc) 17562edbff8dSTomer Tayar return rc; 17572edbff8dSTomer Tayar 1758bb480242SMintz, Yuval /* Copy the data back */ 1759bb480242SMintz, Yuval memcpy(p_resc_info, &union_data.resource, sizeof(*p_resc_info)); 17602edbff8dSTomer Tayar *p_mcp_resp = mb_params.mcp_resp; 17612edbff8dSTomer Tayar *p_mcp_param = mb_params.mcp_param; 17622edbff8dSTomer Tayar 17632edbff8dSTomer Tayar DP_VERBOSE(p_hwfn, 17642edbff8dSTomer Tayar QED_MSG_SP, 17652edbff8dSTomer 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", 17662edbff8dSTomer Tayar *p_mcp_param, 17672edbff8dSTomer Tayar p_resc_info->res_id, 17682edbff8dSTomer Tayar p_resc_info->size, 17692edbff8dSTomer Tayar p_resc_info->offset, 17702edbff8dSTomer Tayar p_resc_info->vf_size, 17712edbff8dSTomer Tayar p_resc_info->vf_offset, p_resc_info->flags); 17722edbff8dSTomer Tayar 17732edbff8dSTomer Tayar return 0; 17742edbff8dSTomer Tayar } 1775