1316485Sdavidcs/* 2316485Sdavidcs * Copyright (c) 2017-2018 Cavium, Inc. 3316485Sdavidcs * All rights reserved. 4316485Sdavidcs * 5316485Sdavidcs * Redistribution and use in source and binary forms, with or without 6316485Sdavidcs * modification, are permitted provided that the following conditions 7316485Sdavidcs * are met: 8316485Sdavidcs * 9316485Sdavidcs * 1. Redistributions of source code must retain the above copyright 10316485Sdavidcs * notice, this list of conditions and the following disclaimer. 11316485Sdavidcs * 2. Redistributions in binary form must reproduce the above copyright 12316485Sdavidcs * notice, this list of conditions and the following disclaimer in the 13316485Sdavidcs * documentation and/or other materials provided with the distribution. 14316485Sdavidcs * 15316485Sdavidcs * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16316485Sdavidcs * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17316485Sdavidcs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18316485Sdavidcs * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 19316485Sdavidcs * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20316485Sdavidcs * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21316485Sdavidcs * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22316485Sdavidcs * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23316485Sdavidcs * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 24316485Sdavidcs * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25316485Sdavidcs * POSSIBILITY OF SUCH DAMAGE. 26316485Sdavidcs */ 27316485Sdavidcs/* 28316485Sdavidcs * File : ecore_mcp.c 29316485Sdavidcs */ 30316485Sdavidcs#include <sys/cdefs.h> 31316485Sdavidcs__FBSDID("$FreeBSD: stable/11/sys/dev/qlnx/qlnxe/ecore_mcp.c 337517 2018-08-09 01:17:35Z davidcs $"); 32316485Sdavidcs 33316485Sdavidcs#include "bcm_osal.h" 34316485Sdavidcs#include "ecore.h" 35316485Sdavidcs#include "ecore_status.h" 36316485Sdavidcs#include "nvm_map.h" 37316485Sdavidcs#include "nvm_cfg.h" 38316485Sdavidcs#include "ecore_mcp.h" 39316485Sdavidcs#include "mcp_public.h" 40316485Sdavidcs#include "reg_addr.h" 41316485Sdavidcs#include "ecore_hw.h" 42316485Sdavidcs#include "ecore_init_fw_funcs.h" 43316485Sdavidcs#include "ecore_sriov.h" 44316485Sdavidcs#include "ecore_vf.h" 45316485Sdavidcs#include "ecore_iov_api.h" 46316485Sdavidcs#include "ecore_gtt_reg_addr.h" 47316485Sdavidcs#include "ecore_iro.h" 48316485Sdavidcs#include "ecore_dcbx.h" 49320164Sdavidcs#include "ecore_sp_commands.h" 50337517Sdavidcs#include "ecore_cxt.h" 51316485Sdavidcs 52316485Sdavidcs#define CHIP_MCP_RESP_ITER_US 10 53316485Sdavidcs#define EMUL_MCP_RESP_ITER_US 1000 * 1000 54316485Sdavidcs 55316485Sdavidcs#define ECORE_DRV_MB_MAX_RETRIES (500 * 1000) /* Account for 5 sec */ 56316485Sdavidcs#define ECORE_MCP_RESET_RETRIES (50 * 1000) /* Account for 500 msec */ 57316485Sdavidcs 58316485Sdavidcs#define DRV_INNER_WR(_p_hwfn, _p_ptt, _ptr, _offset, _val) \ 59316485Sdavidcs ecore_wr(_p_hwfn, _p_ptt, (_p_hwfn->mcp_info->_ptr + _offset), \ 60316485Sdavidcs _val) 61316485Sdavidcs 62316485Sdavidcs#define DRV_INNER_RD(_p_hwfn, _p_ptt, _ptr, _offset) \ 63316485Sdavidcs ecore_rd(_p_hwfn, _p_ptt, (_p_hwfn->mcp_info->_ptr + _offset)) 64316485Sdavidcs 65316485Sdavidcs#define DRV_MB_WR(_p_hwfn, _p_ptt, _field, _val) \ 66316485Sdavidcs DRV_INNER_WR(p_hwfn, _p_ptt, drv_mb_addr, \ 67316485Sdavidcs OFFSETOF(struct public_drv_mb, _field), _val) 68316485Sdavidcs 69316485Sdavidcs#define DRV_MB_RD(_p_hwfn, _p_ptt, _field) \ 70316485Sdavidcs DRV_INNER_RD(_p_hwfn, _p_ptt, drv_mb_addr, \ 71316485Sdavidcs OFFSETOF(struct public_drv_mb, _field)) 72316485Sdavidcs 73316485Sdavidcs#define PDA_COMP (((FW_MAJOR_VERSION) + (FW_MINOR_VERSION << 8)) << \ 74320164Sdavidcs DRV_ID_PDA_COMP_VER_OFFSET) 75316485Sdavidcs 76320164Sdavidcs#define MCP_BYTES_PER_MBIT_OFFSET 17 77316485Sdavidcs 78337517Sdavidcs#ifdef _NTDDK_ 79337517Sdavidcs#pragma warning(push) 80337517Sdavidcs#pragma warning(disable : 28167) 81337517Sdavidcs#pragma warning(disable : 28123) 82337517Sdavidcs#endif 83337517Sdavidcs 84316485Sdavidcs#ifndef ASIC_ONLY 85316485Sdavidcsstatic int loaded; 86316485Sdavidcsstatic int loaded_port[MAX_NUM_PORTS] = { 0 }; 87316485Sdavidcs#endif 88316485Sdavidcs 89316485Sdavidcsbool ecore_mcp_is_init(struct ecore_hwfn *p_hwfn) 90316485Sdavidcs{ 91316485Sdavidcs if (!p_hwfn->mcp_info || !p_hwfn->mcp_info->public_base) 92316485Sdavidcs return false; 93316485Sdavidcs return true; 94316485Sdavidcs} 95316485Sdavidcs 96316485Sdavidcsvoid ecore_mcp_cmd_port_init(struct ecore_hwfn *p_hwfn, 97316485Sdavidcs struct ecore_ptt *p_ptt) 98316485Sdavidcs{ 99316485Sdavidcs u32 addr = SECTION_OFFSIZE_ADDR(p_hwfn->mcp_info->public_base, 100316485Sdavidcs PUBLIC_PORT); 101316485Sdavidcs u32 mfw_mb_offsize = ecore_rd(p_hwfn, p_ptt, addr); 102316485Sdavidcs 103316485Sdavidcs p_hwfn->mcp_info->port_addr = SECTION_ADDR(mfw_mb_offsize, 104316485Sdavidcs MFW_PORT(p_hwfn)); 105316485Sdavidcs DP_VERBOSE(p_hwfn, ECORE_MSG_SP, 106316485Sdavidcs "port_addr = 0x%x, port_id 0x%02x\n", 107316485Sdavidcs p_hwfn->mcp_info->port_addr, MFW_PORT(p_hwfn)); 108316485Sdavidcs} 109316485Sdavidcs 110316485Sdavidcsvoid ecore_mcp_read_mb(struct ecore_hwfn *p_hwfn, 111316485Sdavidcs struct ecore_ptt *p_ptt) 112316485Sdavidcs{ 113316485Sdavidcs u32 length = MFW_DRV_MSG_MAX_DWORDS(p_hwfn->mcp_info->mfw_mb_length); 114316485Sdavidcs OSAL_BE32 tmp; 115316485Sdavidcs u32 i; 116316485Sdavidcs 117316485Sdavidcs#ifndef ASIC_ONLY 118316485Sdavidcs if (CHIP_REV_IS_TEDIBEAR(p_hwfn->p_dev)) 119316485Sdavidcs return; 120316485Sdavidcs#endif 121316485Sdavidcs 122316485Sdavidcs if (!p_hwfn->mcp_info->public_base) 123316485Sdavidcs return; 124316485Sdavidcs 125316485Sdavidcs for (i = 0; i < length; i++) { 126316485Sdavidcs tmp = ecore_rd(p_hwfn, p_ptt, 127316485Sdavidcs p_hwfn->mcp_info->mfw_mb_addr + 128316485Sdavidcs (i << 2) + sizeof(u32)); 129316485Sdavidcs 130316485Sdavidcs ((u32 *)p_hwfn->mcp_info->mfw_mb_cur)[i] = 131316485Sdavidcs OSAL_BE32_TO_CPU(tmp); 132316485Sdavidcs } 133316485Sdavidcs} 134316485Sdavidcs 135320164Sdavidcsstruct ecore_mcp_cmd_elem { 136320164Sdavidcs osal_list_entry_t list; 137320164Sdavidcs struct ecore_mcp_mb_params *p_mb_params; 138320164Sdavidcs u16 expected_seq_num; 139320164Sdavidcs bool b_is_completed; 140320164Sdavidcs}; 141320164Sdavidcs 142320164Sdavidcs/* Must be called while cmd_lock is acquired */ 143320164Sdavidcsstatic struct ecore_mcp_cmd_elem * 144320164Sdavidcsecore_mcp_cmd_add_elem(struct ecore_hwfn *p_hwfn, 145320164Sdavidcs struct ecore_mcp_mb_params *p_mb_params, 146320164Sdavidcs u16 expected_seq_num) 147320164Sdavidcs{ 148320164Sdavidcs struct ecore_mcp_cmd_elem *p_cmd_elem = OSAL_NULL; 149320164Sdavidcs 150320164Sdavidcs p_cmd_elem = OSAL_ZALLOC(p_hwfn->p_dev, GFP_ATOMIC, 151320164Sdavidcs sizeof(*p_cmd_elem)); 152320164Sdavidcs if (!p_cmd_elem) { 153320164Sdavidcs DP_NOTICE(p_hwfn, false, 154320164Sdavidcs "Failed to allocate `struct ecore_mcp_cmd_elem'\n"); 155320164Sdavidcs goto out; 156320164Sdavidcs } 157320164Sdavidcs 158320164Sdavidcs p_cmd_elem->p_mb_params = p_mb_params; 159320164Sdavidcs p_cmd_elem->expected_seq_num = expected_seq_num; 160320164Sdavidcs OSAL_LIST_PUSH_HEAD(&p_cmd_elem->list, &p_hwfn->mcp_info->cmd_list); 161320164Sdavidcsout: 162320164Sdavidcs return p_cmd_elem; 163320164Sdavidcs} 164320164Sdavidcs 165320164Sdavidcs/* Must be called while cmd_lock is acquired */ 166320164Sdavidcsstatic void ecore_mcp_cmd_del_elem(struct ecore_hwfn *p_hwfn, 167320164Sdavidcs struct ecore_mcp_cmd_elem *p_cmd_elem) 168320164Sdavidcs{ 169320164Sdavidcs OSAL_LIST_REMOVE_ENTRY(&p_cmd_elem->list, &p_hwfn->mcp_info->cmd_list); 170320164Sdavidcs OSAL_FREE(p_hwfn->p_dev, p_cmd_elem); 171320164Sdavidcs} 172320164Sdavidcs 173320164Sdavidcs/* Must be called while cmd_lock is acquired */ 174320164Sdavidcsstatic struct ecore_mcp_cmd_elem * 175320164Sdavidcsecore_mcp_cmd_get_elem(struct ecore_hwfn *p_hwfn, u16 seq_num) 176320164Sdavidcs{ 177320164Sdavidcs struct ecore_mcp_cmd_elem *p_cmd_elem = OSAL_NULL; 178320164Sdavidcs 179320164Sdavidcs OSAL_LIST_FOR_EACH_ENTRY(p_cmd_elem, &p_hwfn->mcp_info->cmd_list, list, 180320164Sdavidcs struct ecore_mcp_cmd_elem) { 181320164Sdavidcs if (p_cmd_elem->expected_seq_num == seq_num) 182320164Sdavidcs return p_cmd_elem; 183320164Sdavidcs } 184320164Sdavidcs 185320164Sdavidcs return OSAL_NULL; 186320164Sdavidcs} 187320164Sdavidcs 188316485Sdavidcsenum _ecore_status_t ecore_mcp_free(struct ecore_hwfn *p_hwfn) 189316485Sdavidcs{ 190316485Sdavidcs if (p_hwfn->mcp_info) { 191320164Sdavidcs struct ecore_mcp_cmd_elem *p_cmd_elem = OSAL_NULL, *p_tmp; 192320164Sdavidcs 193316485Sdavidcs OSAL_FREE(p_hwfn->p_dev, p_hwfn->mcp_info->mfw_mb_cur); 194316485Sdavidcs OSAL_FREE(p_hwfn->p_dev, p_hwfn->mcp_info->mfw_mb_shadow); 195320164Sdavidcs 196320164Sdavidcs OSAL_SPIN_LOCK(&p_hwfn->mcp_info->cmd_lock); 197320164Sdavidcs OSAL_LIST_FOR_EACH_ENTRY_SAFE(p_cmd_elem, p_tmp, 198320164Sdavidcs &p_hwfn->mcp_info->cmd_list, list, 199320164Sdavidcs struct ecore_mcp_cmd_elem) { 200320164Sdavidcs ecore_mcp_cmd_del_elem(p_hwfn, p_cmd_elem); 201320164Sdavidcs } 202320164Sdavidcs OSAL_SPIN_UNLOCK(&p_hwfn->mcp_info->cmd_lock); 203320164Sdavidcs 204316485Sdavidcs#ifdef CONFIG_ECORE_LOCK_ALLOC 205320164Sdavidcs OSAL_SPIN_LOCK_DEALLOC(&p_hwfn->mcp_info->cmd_lock); 206316485Sdavidcs OSAL_SPIN_LOCK_DEALLOC(&p_hwfn->mcp_info->link_lock); 207316485Sdavidcs#endif 208316485Sdavidcs } 209320164Sdavidcs 210316485Sdavidcs OSAL_FREE(p_hwfn->p_dev, p_hwfn->mcp_info); 211316485Sdavidcs p_hwfn->mcp_info = OSAL_NULL; 212316485Sdavidcs 213316485Sdavidcs return ECORE_SUCCESS; 214316485Sdavidcs} 215316485Sdavidcs 216337517Sdavidcs/* Maximum of 1 sec to wait for the SHMEM ready indication */ 217337517Sdavidcs#define ECPRE_MCP_SHMEM_RDY_MAX_RETRIES 20 218337517Sdavidcs#define ECORE_MCP_SHMEM_RDY_ITER_MS 50 219337517Sdavidcs 220316485Sdavidcsenum _ecore_status_t ecore_load_mcp_offsets(struct ecore_hwfn *p_hwfn, 221316485Sdavidcs struct ecore_ptt *p_ptt) 222316485Sdavidcs{ 223316485Sdavidcs struct ecore_mcp_info *p_info = p_hwfn->mcp_info; 224337517Sdavidcs u8 cnt = ECPRE_MCP_SHMEM_RDY_MAX_RETRIES; 225337517Sdavidcs u8 msec = ECORE_MCP_SHMEM_RDY_ITER_MS; 226316485Sdavidcs u32 drv_mb_offsize, mfw_mb_offsize; 227316485Sdavidcs u32 mcp_pf_id = MCP_PF_ID(p_hwfn); 228316485Sdavidcs 229316485Sdavidcs#ifndef ASIC_ONLY 230316485Sdavidcs if (CHIP_REV_IS_EMUL(p_hwfn->p_dev)) { 231316485Sdavidcs DP_NOTICE(p_hwfn, false, "Emulation - assume no MFW\n"); 232316485Sdavidcs p_info->public_base = 0; 233316485Sdavidcs return ECORE_INVAL; 234316485Sdavidcs } 235316485Sdavidcs#endif 236316485Sdavidcs 237316485Sdavidcs p_info->public_base = ecore_rd(p_hwfn, p_ptt, MISC_REG_SHARED_MEM_ADDR); 238316485Sdavidcs if (!p_info->public_base) 239320164Sdavidcs return ECORE_INVAL; 240316485Sdavidcs 241316485Sdavidcs p_info->public_base |= GRCBASE_MCP; 242316485Sdavidcs 243337517Sdavidcs /* Get the MFW MB address and number of supported messages */ 244337517Sdavidcs mfw_mb_offsize = ecore_rd(p_hwfn, p_ptt, 245337517Sdavidcs SECTION_OFFSIZE_ADDR(p_info->public_base, 246337517Sdavidcs PUBLIC_MFW_MB)); 247337517Sdavidcs p_info->mfw_mb_addr = SECTION_ADDR(mfw_mb_offsize, mcp_pf_id); 248337517Sdavidcs p_info->mfw_mb_length = (u16)ecore_rd(p_hwfn, p_ptt, 249337517Sdavidcs p_info->mfw_mb_addr); 250337517Sdavidcs 251337517Sdavidcs /* @@@TBD: 252337517Sdavidcs * The driver can notify that there was an MCP reset, and read the SHMEM 253337517Sdavidcs * values before the MFW has completed initializing them. 254337517Sdavidcs * As a temporary solution, the "sup_msgs" field is used as a data ready 255337517Sdavidcs * indication. 256337517Sdavidcs * This should be replaced with an actual indication when it is provided 257337517Sdavidcs * by the MFW. 258337517Sdavidcs */ 259337517Sdavidcs while (!p_info->mfw_mb_length && cnt--) { 260337517Sdavidcs OSAL_MSLEEP(msec); 261337517Sdavidcs p_info->mfw_mb_length = (u16)ecore_rd(p_hwfn, p_ptt, 262337517Sdavidcs p_info->mfw_mb_addr); 263337517Sdavidcs } 264337517Sdavidcs 265337517Sdavidcs if (!cnt) { 266337517Sdavidcs DP_NOTICE(p_hwfn, false, 267337517Sdavidcs "Failed to get the SHMEM ready notification after %d msec\n", 268337517Sdavidcs ECPRE_MCP_SHMEM_RDY_MAX_RETRIES * msec); 269337517Sdavidcs return ECORE_TIMEOUT; 270337517Sdavidcs } 271337517Sdavidcs 272316485Sdavidcs /* Calculate the driver and MFW mailbox address */ 273316485Sdavidcs drv_mb_offsize = ecore_rd(p_hwfn, p_ptt, 274316485Sdavidcs SECTION_OFFSIZE_ADDR(p_info->public_base, 275316485Sdavidcs PUBLIC_DRV_MB)); 276316485Sdavidcs p_info->drv_mb_addr = SECTION_ADDR(drv_mb_offsize, mcp_pf_id); 277316485Sdavidcs DP_VERBOSE(p_hwfn, ECORE_MSG_SP, 278316485Sdavidcs "drv_mb_offsiz = 0x%x, drv_mb_addr = 0x%x mcp_pf_id = 0x%x\n", 279316485Sdavidcs drv_mb_offsize, p_info->drv_mb_addr, mcp_pf_id); 280316485Sdavidcs 281316485Sdavidcs /* Get the current driver mailbox sequence before sending 282316485Sdavidcs * the first command 283316485Sdavidcs */ 284316485Sdavidcs p_info->drv_mb_seq = DRV_MB_RD(p_hwfn, p_ptt, drv_mb_header) & 285316485Sdavidcs DRV_MSG_SEQ_NUMBER_MASK; 286316485Sdavidcs 287316485Sdavidcs /* Get current FW pulse sequence */ 288316485Sdavidcs p_info->drv_pulse_seq = DRV_MB_RD(p_hwfn, p_ptt, drv_pulse_mb) & 289316485Sdavidcs DRV_PULSE_SEQ_MASK; 290316485Sdavidcs 291320164Sdavidcs p_info->mcp_hist = ecore_rd(p_hwfn, p_ptt, MISCS_REG_GENERIC_POR_0); 292316485Sdavidcs 293316485Sdavidcs return ECORE_SUCCESS; 294316485Sdavidcs} 295316485Sdavidcs 296316485Sdavidcsenum _ecore_status_t ecore_mcp_cmd_init(struct ecore_hwfn *p_hwfn, 297316485Sdavidcs struct ecore_ptt *p_ptt) 298316485Sdavidcs{ 299316485Sdavidcs struct ecore_mcp_info *p_info; 300316485Sdavidcs u32 size; 301316485Sdavidcs 302316485Sdavidcs /* Allocate mcp_info structure */ 303316485Sdavidcs p_hwfn->mcp_info = OSAL_ZALLOC(p_hwfn->p_dev, GFP_KERNEL, 304337517Sdavidcs sizeof(*p_hwfn->mcp_info)); 305337517Sdavidcs if (!p_hwfn->mcp_info) { 306337517Sdavidcs DP_NOTICE(p_hwfn, false, "Failed to allocate mcp_info\n"); 307337517Sdavidcs return ECORE_NOMEM; 308337517Sdavidcs } 309316485Sdavidcs p_info = p_hwfn->mcp_info; 310316485Sdavidcs 311320164Sdavidcs /* Initialize the MFW spinlocks */ 312320164Sdavidcs#ifdef CONFIG_ECORE_LOCK_ALLOC 313337517Sdavidcs if (OSAL_SPIN_LOCK_ALLOC(p_hwfn, &p_info->cmd_lock)) { 314337517Sdavidcs OSAL_FREE(p_hwfn->p_dev, p_hwfn->mcp_info); 315337517Sdavidcs return ECORE_NOMEM; 316337517Sdavidcs } 317337517Sdavidcs if (OSAL_SPIN_LOCK_ALLOC(p_hwfn, &p_info->link_lock)) { 318337517Sdavidcs OSAL_SPIN_LOCK_DEALLOC(&p_info->cmd_lock); 319337517Sdavidcs OSAL_FREE(p_hwfn->p_dev, p_hwfn->mcp_info); 320337517Sdavidcs return ECORE_NOMEM; 321337517Sdavidcs } 322320164Sdavidcs#endif 323320164Sdavidcs OSAL_SPIN_LOCK_INIT(&p_info->cmd_lock); 324320164Sdavidcs OSAL_SPIN_LOCK_INIT(&p_info->link_lock); 325320164Sdavidcs 326320164Sdavidcs OSAL_LIST_INIT(&p_info->cmd_list); 327320164Sdavidcs 328316485Sdavidcs if (ecore_load_mcp_offsets(p_hwfn, p_ptt) != ECORE_SUCCESS) { 329316485Sdavidcs DP_NOTICE(p_hwfn, false, "MCP is not initialized\n"); 330316485Sdavidcs /* Do not free mcp_info here, since public_base indicate that 331316485Sdavidcs * the MCP is not initialized 332316485Sdavidcs */ 333316485Sdavidcs return ECORE_SUCCESS; 334316485Sdavidcs } 335316485Sdavidcs 336316485Sdavidcs size = MFW_DRV_MSG_MAX_DWORDS(p_info->mfw_mb_length) * sizeof(u32); 337316485Sdavidcs p_info->mfw_mb_cur = OSAL_ZALLOC(p_hwfn->p_dev, GFP_KERNEL, size); 338316485Sdavidcs p_info->mfw_mb_shadow = OSAL_ZALLOC(p_hwfn->p_dev, GFP_KERNEL, size); 339337517Sdavidcs if (p_info->mfw_mb_cur == OSAL_NULL || p_info->mfw_mb_shadow == OSAL_NULL) 340316485Sdavidcs goto err; 341316485Sdavidcs 342316485Sdavidcs return ECORE_SUCCESS; 343316485Sdavidcs 344316485Sdavidcserr: 345337517Sdavidcs DP_NOTICE(p_hwfn, false, "Failed to allocate mcp memory\n"); 346316485Sdavidcs ecore_mcp_free(p_hwfn); 347316485Sdavidcs return ECORE_NOMEM; 348316485Sdavidcs} 349316485Sdavidcs 350320164Sdavidcsstatic void ecore_mcp_reread_offsets(struct ecore_hwfn *p_hwfn, 351320164Sdavidcs struct ecore_ptt *p_ptt) 352316485Sdavidcs{ 353320164Sdavidcs u32 generic_por_0 = ecore_rd(p_hwfn, p_ptt, MISCS_REG_GENERIC_POR_0); 354316485Sdavidcs 355320164Sdavidcs /* Use MCP history register to check if MCP reset occurred between init 356320164Sdavidcs * time and now. 357316485Sdavidcs */ 358320164Sdavidcs if (p_hwfn->mcp_info->mcp_hist != generic_por_0) { 359320164Sdavidcs DP_VERBOSE(p_hwfn, ECORE_MSG_SP, 360320164Sdavidcs "Rereading MCP offsets [mcp_hist 0x%08x, generic_por_0 0x%08x]\n", 361320164Sdavidcs p_hwfn->mcp_info->mcp_hist, generic_por_0); 362316485Sdavidcs 363320164Sdavidcs ecore_load_mcp_offsets(p_hwfn, p_ptt); 364320164Sdavidcs ecore_mcp_cmd_port_init(p_hwfn, p_ptt); 365316485Sdavidcs } 366316485Sdavidcs} 367316485Sdavidcs 368316485Sdavidcsenum _ecore_status_t ecore_mcp_reset(struct ecore_hwfn *p_hwfn, 369316485Sdavidcs struct ecore_ptt *p_ptt) 370316485Sdavidcs{ 371320164Sdavidcs u32 org_mcp_reset_seq, seq, delay = CHIP_MCP_RESP_ITER_US, cnt = 0; 372316485Sdavidcs enum _ecore_status_t rc = ECORE_SUCCESS; 373316485Sdavidcs 374316485Sdavidcs#ifndef ASIC_ONLY 375316485Sdavidcs if (CHIP_REV_IS_EMUL(p_hwfn->p_dev)) 376316485Sdavidcs delay = EMUL_MCP_RESP_ITER_US; 377316485Sdavidcs#endif 378316485Sdavidcs 379320164Sdavidcs if (p_hwfn->mcp_info->b_block_cmd) { 380320164Sdavidcs DP_NOTICE(p_hwfn, false, 381320164Sdavidcs "The MFW is not responsive. Avoid sending MCP_RESET mailbox command.\n"); 382320164Sdavidcs return ECORE_ABORTED; 383320164Sdavidcs } 384316485Sdavidcs 385320164Sdavidcs /* Ensure that only a single thread is accessing the mailbox */ 386320164Sdavidcs OSAL_SPIN_LOCK(&p_hwfn->mcp_info->cmd_lock); 387320164Sdavidcs 388320164Sdavidcs org_mcp_reset_seq = ecore_rd(p_hwfn, p_ptt, MISCS_REG_GENERIC_POR_0); 389320164Sdavidcs 390316485Sdavidcs /* Set drv command along with the updated sequence */ 391320164Sdavidcs ecore_mcp_reread_offsets(p_hwfn, p_ptt); 392320164Sdavidcs seq = ++p_hwfn->mcp_info->drv_mb_seq; 393316485Sdavidcs DRV_MB_WR(p_hwfn, p_ptt, drv_mb_header, (DRV_MSG_CODE_MCP_RESET | seq)); 394316485Sdavidcs 395316485Sdavidcs do { 396316485Sdavidcs /* Wait for MFW response */ 397316485Sdavidcs OSAL_UDELAY(delay); 398316485Sdavidcs /* Give the FW up to 500 second (50*1000*10usec) */ 399316485Sdavidcs } while ((org_mcp_reset_seq == ecore_rd(p_hwfn, p_ptt, 400316485Sdavidcs MISCS_REG_GENERIC_POR_0)) && 401316485Sdavidcs (cnt++ < ECORE_MCP_RESET_RETRIES)); 402316485Sdavidcs 403316485Sdavidcs if (org_mcp_reset_seq != 404316485Sdavidcs ecore_rd(p_hwfn, p_ptt, MISCS_REG_GENERIC_POR_0)) { 405316485Sdavidcs DP_VERBOSE(p_hwfn, ECORE_MSG_SP, 406316485Sdavidcs "MCP was reset after %d usec\n", cnt * delay); 407316485Sdavidcs } else { 408316485Sdavidcs DP_ERR(p_hwfn, "Failed to reset MCP\n"); 409316485Sdavidcs rc = ECORE_AGAIN; 410316485Sdavidcs } 411316485Sdavidcs 412320164Sdavidcs OSAL_SPIN_UNLOCK(&p_hwfn->mcp_info->cmd_lock); 413316485Sdavidcs 414316485Sdavidcs return rc; 415316485Sdavidcs} 416316485Sdavidcs 417320164Sdavidcs/* Must be called while cmd_lock is acquired */ 418320164Sdavidcsstatic bool ecore_mcp_has_pending_cmd(struct ecore_hwfn *p_hwfn) 419316485Sdavidcs{ 420320164Sdavidcs struct ecore_mcp_cmd_elem *p_cmd_elem = OSAL_NULL; 421316485Sdavidcs 422320164Sdavidcs /* There is at most one pending command at a certain time, and if it 423320164Sdavidcs * exists - it is placed at the HEAD of the list. 424320164Sdavidcs */ 425320164Sdavidcs if (!OSAL_LIST_IS_EMPTY(&p_hwfn->mcp_info->cmd_list)) { 426320164Sdavidcs p_cmd_elem = OSAL_LIST_FIRST_ENTRY(&p_hwfn->mcp_info->cmd_list, 427320164Sdavidcs struct ecore_mcp_cmd_elem, 428320164Sdavidcs list); 429320164Sdavidcs return !p_cmd_elem->b_is_completed; 430320164Sdavidcs } 431316485Sdavidcs 432320164Sdavidcs return false; 433320164Sdavidcs} 434316485Sdavidcs 435320164Sdavidcs/* Must be called while cmd_lock is acquired */ 436320164Sdavidcsstatic enum _ecore_status_t 437320164Sdavidcsecore_mcp_update_pending_cmd(struct ecore_hwfn *p_hwfn, struct ecore_ptt *p_ptt) 438320164Sdavidcs{ 439320164Sdavidcs struct ecore_mcp_mb_params *p_mb_params; 440320164Sdavidcs struct ecore_mcp_cmd_elem *p_cmd_elem; 441320164Sdavidcs u32 mcp_resp; 442320164Sdavidcs u16 seq_num; 443320164Sdavidcs 444320164Sdavidcs mcp_resp = DRV_MB_RD(p_hwfn, p_ptt, fw_mb_header); 445320164Sdavidcs seq_num = (u16)(mcp_resp & FW_MSG_SEQ_NUMBER_MASK); 446320164Sdavidcs 447320164Sdavidcs /* Return if no new non-handled response has been received */ 448320164Sdavidcs if (seq_num != p_hwfn->mcp_info->drv_mb_seq) 449320164Sdavidcs return ECORE_AGAIN; 450320164Sdavidcs 451320164Sdavidcs p_cmd_elem = ecore_mcp_cmd_get_elem(p_hwfn, seq_num); 452320164Sdavidcs if (!p_cmd_elem) { 453320164Sdavidcs DP_ERR(p_hwfn, 454320164Sdavidcs "Failed to find a pending mailbox cmd that expects sequence number %d\n", 455320164Sdavidcs seq_num); 456320164Sdavidcs return ECORE_UNKNOWN_ERROR; 457316485Sdavidcs } 458316485Sdavidcs 459320164Sdavidcs p_mb_params = p_cmd_elem->p_mb_params; 460316485Sdavidcs 461320164Sdavidcs /* Get the MFW response along with the sequence number */ 462320164Sdavidcs p_mb_params->mcp_resp = mcp_resp; 463316485Sdavidcs 464320164Sdavidcs /* Get the MFW param */ 465320164Sdavidcs p_mb_params->mcp_param = DRV_MB_RD(p_hwfn, p_ptt, fw_mb_param); 466320164Sdavidcs 467320164Sdavidcs /* Get the union data */ 468320164Sdavidcs if (p_mb_params->p_data_dst != OSAL_NULL && 469320164Sdavidcs p_mb_params->data_dst_size) { 470320164Sdavidcs u32 union_data_addr = p_hwfn->mcp_info->drv_mb_addr + 471320164Sdavidcs OFFSETOF(struct public_drv_mb, 472320164Sdavidcs union_data); 473320164Sdavidcs ecore_memcpy_from(p_hwfn, p_ptt, p_mb_params->p_data_dst, 474320164Sdavidcs union_data_addr, p_mb_params->data_dst_size); 475320164Sdavidcs } 476320164Sdavidcs 477320164Sdavidcs p_cmd_elem->b_is_completed = true; 478320164Sdavidcs 479320164Sdavidcs return ECORE_SUCCESS; 480320164Sdavidcs} 481320164Sdavidcs 482320164Sdavidcs/* Must be called while cmd_lock is acquired */ 483320164Sdavidcsstatic void __ecore_mcp_cmd_and_union(struct ecore_hwfn *p_hwfn, 484320164Sdavidcs struct ecore_ptt *p_ptt, 485320164Sdavidcs struct ecore_mcp_mb_params *p_mb_params, 486320164Sdavidcs u16 seq_num) 487320164Sdavidcs{ 488320164Sdavidcs union drv_union_data union_data; 489320164Sdavidcs u32 union_data_addr; 490320164Sdavidcs 491320164Sdavidcs /* Set the union data */ 492320164Sdavidcs union_data_addr = p_hwfn->mcp_info->drv_mb_addr + 493320164Sdavidcs OFFSETOF(struct public_drv_mb, union_data); 494320164Sdavidcs OSAL_MEM_ZERO(&union_data, sizeof(union_data)); 495320164Sdavidcs if (p_mb_params->p_data_src != OSAL_NULL && p_mb_params->data_src_size) 496320164Sdavidcs OSAL_MEMCPY(&union_data, p_mb_params->p_data_src, 497320164Sdavidcs p_mb_params->data_src_size); 498320164Sdavidcs ecore_memcpy_to(p_hwfn, p_ptt, union_data_addr, &union_data, 499320164Sdavidcs sizeof(union_data)); 500320164Sdavidcs 501320164Sdavidcs /* Set the drv param */ 502320164Sdavidcs DRV_MB_WR(p_hwfn, p_ptt, drv_mb_param, p_mb_params->param); 503320164Sdavidcs 504320164Sdavidcs /* Set the drv command along with the sequence number */ 505320164Sdavidcs DRV_MB_WR(p_hwfn, p_ptt, drv_mb_header, (p_mb_params->cmd | seq_num)); 506320164Sdavidcs 507316485Sdavidcs DP_VERBOSE(p_hwfn, ECORE_MSG_SP, 508320164Sdavidcs "MFW mailbox: command 0x%08x param 0x%08x\n", 509320164Sdavidcs (p_mb_params->cmd | seq_num), p_mb_params->param); 510320164Sdavidcs} 511316485Sdavidcs 512320164Sdavidcsstatic void ecore_mcp_cmd_set_blocking(struct ecore_hwfn *p_hwfn, 513320164Sdavidcs bool block_cmd) 514320164Sdavidcs{ 515320164Sdavidcs p_hwfn->mcp_info->b_block_cmd = block_cmd; 516320164Sdavidcs 517320164Sdavidcs DP_INFO(p_hwfn, "%s sending of mailbox commands to the MFW\n", 518320164Sdavidcs block_cmd ? "Block" : "Unblock"); 519320164Sdavidcs} 520320164Sdavidcs 521320164Sdavidcsstatic void ecore_mcp_print_cpu_info(struct ecore_hwfn *p_hwfn, 522320164Sdavidcs struct ecore_ptt *p_ptt) 523320164Sdavidcs{ 524320164Sdavidcs u32 cpu_mode, cpu_state, cpu_pc_0, cpu_pc_1, cpu_pc_2; 525320164Sdavidcs 526320164Sdavidcs cpu_mode = ecore_rd(p_hwfn, p_ptt, MCP_REG_CPU_MODE); 527320164Sdavidcs cpu_state = ecore_rd(p_hwfn, p_ptt, MCP_REG_CPU_STATE); 528320164Sdavidcs cpu_pc_0 = ecore_rd(p_hwfn, p_ptt, MCP_REG_CPU_PROGRAM_COUNTER); 529320164Sdavidcs OSAL_UDELAY(CHIP_MCP_RESP_ITER_US); 530320164Sdavidcs cpu_pc_1 = ecore_rd(p_hwfn, p_ptt, MCP_REG_CPU_PROGRAM_COUNTER); 531320164Sdavidcs OSAL_UDELAY(CHIP_MCP_RESP_ITER_US); 532320164Sdavidcs cpu_pc_2 = ecore_rd(p_hwfn, p_ptt, MCP_REG_CPU_PROGRAM_COUNTER); 533320164Sdavidcs 534320164Sdavidcs DP_NOTICE(p_hwfn, false, 535320164Sdavidcs "MCP CPU info: mode 0x%08x, state 0x%08x, pc {0x%08x, 0x%08x, 0x%08x}\n", 536320164Sdavidcs cpu_mode, cpu_state, cpu_pc_0, cpu_pc_1, cpu_pc_2); 537320164Sdavidcs} 538320164Sdavidcs 539320164Sdavidcsstatic enum _ecore_status_t 540320164Sdavidcs_ecore_mcp_cmd_and_union(struct ecore_hwfn *p_hwfn, struct ecore_ptt *p_ptt, 541320164Sdavidcs struct ecore_mcp_mb_params *p_mb_params, 542337517Sdavidcs u32 max_retries, u32 usecs) 543320164Sdavidcs{ 544337517Sdavidcs u32 cnt = 0, msecs = DIV_ROUND_UP(usecs, 1000); 545320164Sdavidcs struct ecore_mcp_cmd_elem *p_cmd_elem; 546320164Sdavidcs u16 seq_num; 547320164Sdavidcs enum _ecore_status_t rc = ECORE_SUCCESS; 548320164Sdavidcs 549320164Sdavidcs /* Wait until the mailbox is non-occupied */ 550316485Sdavidcs do { 551320164Sdavidcs /* Exit the loop if there is no pending command, or if the 552320164Sdavidcs * pending command is completed during this iteration. 553320164Sdavidcs * The spinlock stays locked until the command is sent. 554320164Sdavidcs */ 555320164Sdavidcs 556320164Sdavidcs OSAL_SPIN_LOCK(&p_hwfn->mcp_info->cmd_lock); 557320164Sdavidcs 558320164Sdavidcs if (!ecore_mcp_has_pending_cmd(p_hwfn)) 559320164Sdavidcs break; 560320164Sdavidcs 561320164Sdavidcs rc = ecore_mcp_update_pending_cmd(p_hwfn, p_ptt); 562320164Sdavidcs if (rc == ECORE_SUCCESS) 563320164Sdavidcs break; 564320164Sdavidcs else if (rc != ECORE_AGAIN) 565320164Sdavidcs goto err; 566320164Sdavidcs 567320164Sdavidcs OSAL_SPIN_UNLOCK(&p_hwfn->mcp_info->cmd_lock); 568337517Sdavidcs if (ECORE_MB_FLAGS_IS_SET(p_mb_params, CAN_SLEEP)) { 569337517Sdavidcs OSAL_MSLEEP(msecs); 570337517Sdavidcs } else { 571337517Sdavidcs OSAL_UDELAY(usecs); 572337517Sdavidcs } 573337517Sdavidcs OSAL_MFW_CMD_PREEMPT(p_hwfn); 574320164Sdavidcs } while (++cnt < max_retries); 575316485Sdavidcs 576320164Sdavidcs if (cnt >= max_retries) { 577320164Sdavidcs DP_NOTICE(p_hwfn, false, 578320164Sdavidcs "The MFW mailbox is occupied by an uncompleted command. Failed to send command 0x%08x [param 0x%08x].\n", 579320164Sdavidcs p_mb_params->cmd, p_mb_params->param); 580320164Sdavidcs return ECORE_AGAIN; 581320164Sdavidcs } 582316485Sdavidcs 583320164Sdavidcs /* Send the mailbox command */ 584320164Sdavidcs ecore_mcp_reread_offsets(p_hwfn, p_ptt); 585320164Sdavidcs seq_num = ++p_hwfn->mcp_info->drv_mb_seq; 586320164Sdavidcs p_cmd_elem = ecore_mcp_cmd_add_elem(p_hwfn, p_mb_params, seq_num); 587337517Sdavidcs if (!p_cmd_elem) { 588337517Sdavidcs rc = ECORE_NOMEM; 589320164Sdavidcs goto err; 590337517Sdavidcs } 591316485Sdavidcs 592320164Sdavidcs __ecore_mcp_cmd_and_union(p_hwfn, p_ptt, p_mb_params, seq_num); 593320164Sdavidcs OSAL_SPIN_UNLOCK(&p_hwfn->mcp_info->cmd_lock); 594320164Sdavidcs 595320164Sdavidcs /* Wait for the MFW response */ 596320164Sdavidcs do { 597320164Sdavidcs /* Exit the loop if the command is already completed, or if the 598320164Sdavidcs * command is completed during this iteration. 599320164Sdavidcs * The spinlock stays locked until the list element is removed. 600320164Sdavidcs */ 601320164Sdavidcs 602337517Sdavidcs if (ECORE_MB_FLAGS_IS_SET(p_mb_params, CAN_SLEEP)) { 603337517Sdavidcs OSAL_MSLEEP(msecs); 604337517Sdavidcs } else { 605337517Sdavidcs OSAL_UDELAY(usecs); 606337517Sdavidcs } 607320164Sdavidcs OSAL_SPIN_LOCK(&p_hwfn->mcp_info->cmd_lock); 608320164Sdavidcs 609320164Sdavidcs if (p_cmd_elem->b_is_completed) 610320164Sdavidcs break; 611320164Sdavidcs 612320164Sdavidcs rc = ecore_mcp_update_pending_cmd(p_hwfn, p_ptt); 613320164Sdavidcs if (rc == ECORE_SUCCESS) 614320164Sdavidcs break; 615320164Sdavidcs else if (rc != ECORE_AGAIN) 616320164Sdavidcs goto err; 617320164Sdavidcs 618320164Sdavidcs OSAL_SPIN_UNLOCK(&p_hwfn->mcp_info->cmd_lock); 619337517Sdavidcs OSAL_MFW_CMD_PREEMPT(p_hwfn); 620320164Sdavidcs } while (++cnt < max_retries); 621320164Sdavidcs 622320164Sdavidcs if (cnt >= max_retries) { 623320164Sdavidcs DP_NOTICE(p_hwfn, false, 624320164Sdavidcs "The MFW failed to respond to command 0x%08x [param 0x%08x].\n", 625320164Sdavidcs p_mb_params->cmd, p_mb_params->param); 626320164Sdavidcs ecore_mcp_print_cpu_info(p_hwfn, p_ptt); 627320164Sdavidcs 628320164Sdavidcs OSAL_SPIN_LOCK(&p_hwfn->mcp_info->cmd_lock); 629320164Sdavidcs ecore_mcp_cmd_del_elem(p_hwfn, p_cmd_elem); 630320164Sdavidcs OSAL_SPIN_UNLOCK(&p_hwfn->mcp_info->cmd_lock); 631320164Sdavidcs 632337517Sdavidcs if (!ECORE_MB_FLAGS_IS_SET(p_mb_params, AVOID_BLOCK)) 633337517Sdavidcs ecore_mcp_cmd_set_blocking(p_hwfn, true); 634316485Sdavidcs ecore_hw_err_notify(p_hwfn, ECORE_HW_ERR_MFW_RESP_FAIL); 635320164Sdavidcs return ECORE_AGAIN; 636316485Sdavidcs } 637320164Sdavidcs 638320164Sdavidcs ecore_mcp_cmd_del_elem(p_hwfn, p_cmd_elem); 639320164Sdavidcs OSAL_SPIN_UNLOCK(&p_hwfn->mcp_info->cmd_lock); 640320164Sdavidcs 641320164Sdavidcs DP_VERBOSE(p_hwfn, ECORE_MSG_SP, 642320164Sdavidcs "MFW mailbox: response 0x%08x param 0x%08x [after %d.%03d ms]\n", 643320164Sdavidcs p_mb_params->mcp_resp, p_mb_params->mcp_param, 644337517Sdavidcs (cnt * usecs) / 1000, (cnt * usecs) % 1000); 645320164Sdavidcs 646320164Sdavidcs /* Clear the sequence number from the MFW response */ 647320164Sdavidcs p_mb_params->mcp_resp &= FW_MSG_CODE_MASK; 648320164Sdavidcs 649320164Sdavidcs return ECORE_SUCCESS; 650320164Sdavidcs 651320164Sdavidcserr: 652320164Sdavidcs OSAL_SPIN_UNLOCK(&p_hwfn->mcp_info->cmd_lock); 653316485Sdavidcs return rc; 654316485Sdavidcs} 655316485Sdavidcs 656316485Sdavidcsstatic enum _ecore_status_t ecore_mcp_cmd_and_union(struct ecore_hwfn *p_hwfn, 657316485Sdavidcs struct ecore_ptt *p_ptt, 658316485Sdavidcs struct ecore_mcp_mb_params *p_mb_params) 659316485Sdavidcs{ 660320164Sdavidcs osal_size_t union_data_size = sizeof(union drv_union_data); 661320164Sdavidcs u32 max_retries = ECORE_DRV_MB_MAX_RETRIES; 662337517Sdavidcs u32 usecs = CHIP_MCP_RESP_ITER_US; 663316485Sdavidcs 664320164Sdavidcs#ifndef ASIC_ONLY 665320164Sdavidcs if (CHIP_REV_IS_EMUL(p_hwfn->p_dev)) 666337517Sdavidcs usecs = EMUL_MCP_RESP_ITER_US; 667320164Sdavidcs /* There is a built-in delay of 100usec in each MFW response read */ 668320164Sdavidcs if (CHIP_REV_IS_FPGA(p_hwfn->p_dev)) 669320164Sdavidcs max_retries /= 10; 670320164Sdavidcs#endif 671337517Sdavidcs if (ECORE_MB_FLAGS_IS_SET(p_mb_params, CAN_SLEEP)) { 672337517Sdavidcs max_retries = DIV_ROUND_UP(max_retries, 1000); 673337517Sdavidcs usecs *= 1000; 674337517Sdavidcs } 675320164Sdavidcs 676316485Sdavidcs /* MCP not initialized */ 677316485Sdavidcs if (!ecore_mcp_is_init(p_hwfn)) { 678316485Sdavidcs DP_NOTICE(p_hwfn, true, "MFW is not initialized!\n"); 679316485Sdavidcs return ECORE_BUSY; 680316485Sdavidcs } 681316485Sdavidcs 682320164Sdavidcs if (p_mb_params->data_src_size > union_data_size || 683320164Sdavidcs p_mb_params->data_dst_size > union_data_size) { 684316485Sdavidcs DP_ERR(p_hwfn, 685316485Sdavidcs "The provided size is larger than the union data size [src_size %u, dst_size %u, union_data_size %zu]\n", 686316485Sdavidcs p_mb_params->data_src_size, p_mb_params->data_dst_size, 687320164Sdavidcs union_data_size); 688316485Sdavidcs return ECORE_INVAL; 689316485Sdavidcs } 690316485Sdavidcs 691320164Sdavidcs if (p_hwfn->mcp_info->b_block_cmd) { 692320164Sdavidcs DP_NOTICE(p_hwfn, false, 693320164Sdavidcs "The MFW is not responsive. Avoid sending mailbox command 0x%08x [param 0x%08x].\n", 694320164Sdavidcs p_mb_params->cmd, p_mb_params->param); 695320164Sdavidcs return ECORE_ABORTED; 696320164Sdavidcs } 697316485Sdavidcs 698320164Sdavidcs return _ecore_mcp_cmd_and_union(p_hwfn, p_ptt, p_mb_params, max_retries, 699337517Sdavidcs usecs); 700316485Sdavidcs} 701316485Sdavidcs 702316485Sdavidcsenum _ecore_status_t ecore_mcp_cmd(struct ecore_hwfn *p_hwfn, 703316485Sdavidcs struct ecore_ptt *p_ptt, u32 cmd, u32 param, 704316485Sdavidcs u32 *o_mcp_resp, u32 *o_mcp_param) 705316485Sdavidcs{ 706316485Sdavidcs struct ecore_mcp_mb_params mb_params; 707316485Sdavidcs enum _ecore_status_t rc; 708316485Sdavidcs 709316485Sdavidcs#ifndef ASIC_ONLY 710316485Sdavidcs if (CHIP_REV_IS_EMUL(p_hwfn->p_dev)) { 711316485Sdavidcs if (cmd == DRV_MSG_CODE_UNLOAD_REQ) { 712316485Sdavidcs loaded--; 713316485Sdavidcs loaded_port[p_hwfn->port_id]--; 714316485Sdavidcs DP_VERBOSE(p_hwfn, ECORE_MSG_SP, "Unload cnt: 0x%x\n", 715316485Sdavidcs loaded); 716316485Sdavidcs } 717316485Sdavidcs return ECORE_SUCCESS; 718316485Sdavidcs } 719316485Sdavidcs#endif 720316485Sdavidcs 721316485Sdavidcs OSAL_MEM_ZERO(&mb_params, sizeof(mb_params)); 722316485Sdavidcs mb_params.cmd = cmd; 723316485Sdavidcs mb_params.param = param; 724316485Sdavidcs rc = ecore_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 725316485Sdavidcs if (rc != ECORE_SUCCESS) 726316485Sdavidcs return rc; 727316485Sdavidcs 728316485Sdavidcs *o_mcp_resp = mb_params.mcp_resp; 729316485Sdavidcs *o_mcp_param = mb_params.mcp_param; 730316485Sdavidcs 731316485Sdavidcs return ECORE_SUCCESS; 732316485Sdavidcs} 733316485Sdavidcs 734316485Sdavidcsenum _ecore_status_t ecore_mcp_nvm_wr_cmd(struct ecore_hwfn *p_hwfn, 735316485Sdavidcs struct ecore_ptt *p_ptt, 736316485Sdavidcs u32 cmd, 737316485Sdavidcs u32 param, 738316485Sdavidcs u32 *o_mcp_resp, 739316485Sdavidcs u32 *o_mcp_param, 740316485Sdavidcs u32 i_txn_size, 741316485Sdavidcs u32 *i_buf) 742316485Sdavidcs{ 743316485Sdavidcs struct ecore_mcp_mb_params mb_params; 744316485Sdavidcs enum _ecore_status_t rc; 745316485Sdavidcs 746316485Sdavidcs OSAL_MEM_ZERO(&mb_params, sizeof(mb_params)); 747316485Sdavidcs mb_params.cmd = cmd; 748316485Sdavidcs mb_params.param = param; 749316485Sdavidcs mb_params.p_data_src = i_buf; 750316485Sdavidcs mb_params.data_src_size = (u8) i_txn_size; 751316485Sdavidcs rc = ecore_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 752316485Sdavidcs if (rc != ECORE_SUCCESS) 753316485Sdavidcs return rc; 754316485Sdavidcs 755316485Sdavidcs *o_mcp_resp = mb_params.mcp_resp; 756316485Sdavidcs *o_mcp_param = mb_params.mcp_param; 757316485Sdavidcs 758316485Sdavidcs return ECORE_SUCCESS; 759316485Sdavidcs} 760316485Sdavidcs 761316485Sdavidcsenum _ecore_status_t ecore_mcp_nvm_rd_cmd(struct ecore_hwfn *p_hwfn, 762316485Sdavidcs struct ecore_ptt *p_ptt, 763316485Sdavidcs u32 cmd, 764316485Sdavidcs u32 param, 765316485Sdavidcs u32 *o_mcp_resp, 766316485Sdavidcs u32 *o_mcp_param, 767316485Sdavidcs u32 *o_txn_size, 768316485Sdavidcs u32 *o_buf) 769316485Sdavidcs{ 770316485Sdavidcs struct ecore_mcp_mb_params mb_params; 771316485Sdavidcs u8 raw_data[MCP_DRV_NVM_BUF_LEN]; 772316485Sdavidcs enum _ecore_status_t rc; 773316485Sdavidcs 774316485Sdavidcs OSAL_MEM_ZERO(&mb_params, sizeof(mb_params)); 775316485Sdavidcs mb_params.cmd = cmd; 776316485Sdavidcs mb_params.param = param; 777316485Sdavidcs mb_params.p_data_dst = raw_data; 778316485Sdavidcs 779316485Sdavidcs /* Use the maximal value since the actual one is part of the response */ 780316485Sdavidcs mb_params.data_dst_size = MCP_DRV_NVM_BUF_LEN; 781316485Sdavidcs 782316485Sdavidcs rc = ecore_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 783316485Sdavidcs if (rc != ECORE_SUCCESS) 784316485Sdavidcs return rc; 785316485Sdavidcs 786316485Sdavidcs *o_mcp_resp = mb_params.mcp_resp; 787316485Sdavidcs *o_mcp_param = mb_params.mcp_param; 788316485Sdavidcs 789316485Sdavidcs *o_txn_size = *o_mcp_param; 790316485Sdavidcs OSAL_MEMCPY(o_buf, raw_data, *o_txn_size); 791316485Sdavidcs 792316485Sdavidcs return ECORE_SUCCESS; 793316485Sdavidcs} 794316485Sdavidcs 795316485Sdavidcs#ifndef ASIC_ONLY 796316485Sdavidcsstatic void ecore_mcp_mf_workaround(struct ecore_hwfn *p_hwfn, 797316485Sdavidcs u32 *p_load_code) 798316485Sdavidcs{ 799316485Sdavidcs static int load_phase = FW_MSG_CODE_DRV_LOAD_ENGINE; 800316485Sdavidcs 801316485Sdavidcs if (!loaded) { 802316485Sdavidcs load_phase = FW_MSG_CODE_DRV_LOAD_ENGINE; 803316485Sdavidcs } else if (!loaded_port[p_hwfn->port_id]) { 804316485Sdavidcs load_phase = FW_MSG_CODE_DRV_LOAD_PORT; 805316485Sdavidcs } else { 806316485Sdavidcs load_phase = FW_MSG_CODE_DRV_LOAD_FUNCTION; 807316485Sdavidcs } 808316485Sdavidcs 809316485Sdavidcs /* On CMT, always tell that it's engine */ 810337517Sdavidcs if (ECORE_IS_CMT(p_hwfn->p_dev)) 811316485Sdavidcs load_phase = FW_MSG_CODE_DRV_LOAD_ENGINE; 812316485Sdavidcs 813316485Sdavidcs *p_load_code = load_phase; 814316485Sdavidcs loaded++; 815316485Sdavidcs loaded_port[p_hwfn->port_id]++; 816316485Sdavidcs 817316485Sdavidcs DP_VERBOSE(p_hwfn, ECORE_MSG_SP, 818316485Sdavidcs "Load phase: %x load cnt: 0x%x port id=%d port_load=%d\n", 819316485Sdavidcs *p_load_code, loaded, p_hwfn->port_id, 820316485Sdavidcs loaded_port[p_hwfn->port_id]); 821316485Sdavidcs} 822316485Sdavidcs#endif 823316485Sdavidcs 824316485Sdavidcsstatic bool 825316485Sdavidcsecore_mcp_can_force_load(u8 drv_role, u8 exist_drv_role, 826316485Sdavidcs enum ecore_override_force_load override_force_load) 827316485Sdavidcs{ 828316485Sdavidcs bool can_force_load = false; 829316485Sdavidcs 830316485Sdavidcs switch (override_force_load) { 831316485Sdavidcs case ECORE_OVERRIDE_FORCE_LOAD_ALWAYS: 832316485Sdavidcs can_force_load = true; 833316485Sdavidcs break; 834316485Sdavidcs case ECORE_OVERRIDE_FORCE_LOAD_NEVER: 835316485Sdavidcs can_force_load = false; 836316485Sdavidcs break; 837316485Sdavidcs default: 838316485Sdavidcs can_force_load = (drv_role == DRV_ROLE_OS && 839316485Sdavidcs exist_drv_role == DRV_ROLE_PREBOOT) || 840316485Sdavidcs (drv_role == DRV_ROLE_KDUMP && 841316485Sdavidcs exist_drv_role == DRV_ROLE_OS); 842316485Sdavidcs break; 843316485Sdavidcs } 844316485Sdavidcs 845316485Sdavidcs return can_force_load; 846316485Sdavidcs} 847316485Sdavidcs 848337517Sdavidcsenum _ecore_status_t ecore_mcp_cancel_load_req(struct ecore_hwfn *p_hwfn, 849337517Sdavidcs struct ecore_ptt *p_ptt) 850316485Sdavidcs{ 851316485Sdavidcs u32 resp = 0, param = 0; 852316485Sdavidcs enum _ecore_status_t rc; 853316485Sdavidcs 854316485Sdavidcs rc = ecore_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_CANCEL_LOAD_REQ, 0, 855316485Sdavidcs &resp, ¶m); 856337517Sdavidcs if (rc != ECORE_SUCCESS) { 857316485Sdavidcs DP_NOTICE(p_hwfn, false, 858316485Sdavidcs "Failed to send cancel load request, rc = %d\n", rc); 859337517Sdavidcs return rc; 860337517Sdavidcs } 861316485Sdavidcs 862337517Sdavidcs if (resp == FW_MSG_CODE_UNSUPPORTED) { 863337517Sdavidcs DP_INFO(p_hwfn, 864337517Sdavidcs "The cancel load command is unsupported by the MFW\n"); 865337517Sdavidcs return ECORE_NOTIMPL; 866337517Sdavidcs } 867337517Sdavidcs 868337517Sdavidcs return ECORE_SUCCESS; 869316485Sdavidcs} 870316485Sdavidcs 871316485Sdavidcs#define CONFIG_ECORE_L2_BITMAP_IDX (0x1 << 0) 872316485Sdavidcs#define CONFIG_ECORE_SRIOV_BITMAP_IDX (0x1 << 1) 873316485Sdavidcs#define CONFIG_ECORE_ROCE_BITMAP_IDX (0x1 << 2) 874316485Sdavidcs#define CONFIG_ECORE_IWARP_BITMAP_IDX (0x1 << 3) 875316485Sdavidcs#define CONFIG_ECORE_FCOE_BITMAP_IDX (0x1 << 4) 876316485Sdavidcs#define CONFIG_ECORE_ISCSI_BITMAP_IDX (0x1 << 5) 877316485Sdavidcs#define CONFIG_ECORE_LL2_BITMAP_IDX (0x1 << 6) 878316485Sdavidcs 879316485Sdavidcsstatic u32 ecore_get_config_bitmap(void) 880316485Sdavidcs{ 881316485Sdavidcs u32 config_bitmap = 0x0; 882316485Sdavidcs 883316485Sdavidcs#ifdef CONFIG_ECORE_L2 884316485Sdavidcs config_bitmap |= CONFIG_ECORE_L2_BITMAP_IDX; 885316485Sdavidcs#endif 886316485Sdavidcs#ifdef CONFIG_ECORE_SRIOV 887316485Sdavidcs config_bitmap |= CONFIG_ECORE_SRIOV_BITMAP_IDX; 888316485Sdavidcs#endif 889316485Sdavidcs#ifdef CONFIG_ECORE_ROCE 890316485Sdavidcs config_bitmap |= CONFIG_ECORE_ROCE_BITMAP_IDX; 891316485Sdavidcs#endif 892316485Sdavidcs#ifdef CONFIG_ECORE_IWARP 893316485Sdavidcs config_bitmap |= CONFIG_ECORE_IWARP_BITMAP_IDX; 894316485Sdavidcs#endif 895316485Sdavidcs#ifdef CONFIG_ECORE_FCOE 896316485Sdavidcs config_bitmap |= CONFIG_ECORE_FCOE_BITMAP_IDX; 897316485Sdavidcs#endif 898316485Sdavidcs#ifdef CONFIG_ECORE_ISCSI 899316485Sdavidcs config_bitmap |= CONFIG_ECORE_ISCSI_BITMAP_IDX; 900316485Sdavidcs#endif 901316485Sdavidcs#ifdef CONFIG_ECORE_LL2 902316485Sdavidcs config_bitmap |= CONFIG_ECORE_LL2_BITMAP_IDX; 903316485Sdavidcs#endif 904316485Sdavidcs 905316485Sdavidcs return config_bitmap; 906316485Sdavidcs} 907316485Sdavidcs 908316485Sdavidcsstruct ecore_load_req_in_params { 909316485Sdavidcs u8 hsi_ver; 910316485Sdavidcs#define ECORE_LOAD_REQ_HSI_VER_DEFAULT 0 911316485Sdavidcs#define ECORE_LOAD_REQ_HSI_VER_1 1 912316485Sdavidcs u32 drv_ver_0; 913316485Sdavidcs u32 drv_ver_1; 914316485Sdavidcs u32 fw_ver; 915316485Sdavidcs u8 drv_role; 916316485Sdavidcs u8 timeout_val; 917316485Sdavidcs u8 force_cmd; 918316485Sdavidcs bool avoid_eng_reset; 919316485Sdavidcs}; 920316485Sdavidcs 921316485Sdavidcsstruct ecore_load_req_out_params { 922316485Sdavidcs u32 load_code; 923316485Sdavidcs u32 exist_drv_ver_0; 924316485Sdavidcs u32 exist_drv_ver_1; 925316485Sdavidcs u32 exist_fw_ver; 926316485Sdavidcs u8 exist_drv_role; 927316485Sdavidcs u8 mfw_hsi_ver; 928316485Sdavidcs bool drv_exists; 929316485Sdavidcs}; 930316485Sdavidcs 931316485Sdavidcsstatic enum _ecore_status_t 932316485Sdavidcs__ecore_mcp_load_req(struct ecore_hwfn *p_hwfn, struct ecore_ptt *p_ptt, 933316485Sdavidcs struct ecore_load_req_in_params *p_in_params, 934316485Sdavidcs struct ecore_load_req_out_params *p_out_params) 935316485Sdavidcs{ 936316485Sdavidcs struct ecore_mcp_mb_params mb_params; 937316485Sdavidcs struct load_req_stc load_req; 938316485Sdavidcs struct load_rsp_stc load_rsp; 939316485Sdavidcs u32 hsi_ver; 940316485Sdavidcs enum _ecore_status_t rc; 941316485Sdavidcs 942316485Sdavidcs OSAL_MEM_ZERO(&load_req, sizeof(load_req)); 943316485Sdavidcs load_req.drv_ver_0 = p_in_params->drv_ver_0; 944316485Sdavidcs load_req.drv_ver_1 = p_in_params->drv_ver_1; 945316485Sdavidcs load_req.fw_ver = p_in_params->fw_ver; 946320164Sdavidcs SET_MFW_FIELD(load_req.misc0, LOAD_REQ_ROLE, p_in_params->drv_role); 947320164Sdavidcs SET_MFW_FIELD(load_req.misc0, LOAD_REQ_LOCK_TO, 948320164Sdavidcs p_in_params->timeout_val); 949320164Sdavidcs SET_MFW_FIELD(load_req.misc0, (u64)LOAD_REQ_FORCE, p_in_params->force_cmd); 950320164Sdavidcs SET_MFW_FIELD(load_req.misc0, (u64)LOAD_REQ_FLAGS0, 951320164Sdavidcs p_in_params->avoid_eng_reset); 952316485Sdavidcs 953316485Sdavidcs hsi_ver = (p_in_params->hsi_ver == ECORE_LOAD_REQ_HSI_VER_DEFAULT) ? 954316485Sdavidcs DRV_ID_MCP_HSI_VER_CURRENT : 955320164Sdavidcs (p_in_params->hsi_ver << DRV_ID_MCP_HSI_VER_OFFSET); 956316485Sdavidcs 957316485Sdavidcs OSAL_MEM_ZERO(&mb_params, sizeof(mb_params)); 958316485Sdavidcs mb_params.cmd = DRV_MSG_CODE_LOAD_REQ; 959316485Sdavidcs mb_params.param = PDA_COMP | hsi_ver | p_hwfn->p_dev->drv_type; 960316485Sdavidcs mb_params.p_data_src = &load_req; 961316485Sdavidcs mb_params.data_src_size = sizeof(load_req); 962316485Sdavidcs mb_params.p_data_dst = &load_rsp; 963316485Sdavidcs mb_params.data_dst_size = sizeof(load_rsp); 964337517Sdavidcs mb_params.flags = ECORE_MB_FLAG_CAN_SLEEP | ECORE_MB_FLAG_AVOID_BLOCK; 965316485Sdavidcs 966316485Sdavidcs DP_VERBOSE(p_hwfn, ECORE_MSG_SP, 967316485Sdavidcs "Load Request: param 0x%08x [init_hw %d, drv_type %d, hsi_ver %d, pda 0x%04x]\n", 968316485Sdavidcs mb_params.param, 969320164Sdavidcs GET_MFW_FIELD(mb_params.param, DRV_ID_DRV_INIT_HW), 970320164Sdavidcs GET_MFW_FIELD(mb_params.param, DRV_ID_DRV_TYPE), 971320164Sdavidcs GET_MFW_FIELD(mb_params.param, DRV_ID_MCP_HSI_VER), 972320164Sdavidcs GET_MFW_FIELD(mb_params.param, DRV_ID_PDA_COMP_VER)); 973316485Sdavidcs 974316485Sdavidcs if (p_in_params->hsi_ver != ECORE_LOAD_REQ_HSI_VER_1) 975316485Sdavidcs DP_VERBOSE(p_hwfn, ECORE_MSG_SP, 976316485Sdavidcs "Load Request: drv_ver 0x%08x_0x%08x, fw_ver 0x%08x, misc0 0x%08x [role %d, timeout %d, force %d, flags0 0x%x]\n", 977316485Sdavidcs load_req.drv_ver_0, load_req.drv_ver_1, 978316485Sdavidcs load_req.fw_ver, load_req.misc0, 979320164Sdavidcs GET_MFW_FIELD(load_req.misc0, LOAD_REQ_ROLE), 980320164Sdavidcs GET_MFW_FIELD(load_req.misc0, LOAD_REQ_LOCK_TO), 981320164Sdavidcs GET_MFW_FIELD(load_req.misc0, LOAD_REQ_FORCE), 982320164Sdavidcs GET_MFW_FIELD(load_req.misc0, LOAD_REQ_FLAGS0)); 983316485Sdavidcs 984316485Sdavidcs rc = ecore_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 985316485Sdavidcs if (rc != ECORE_SUCCESS) { 986316485Sdavidcs DP_NOTICE(p_hwfn, false, 987316485Sdavidcs "Failed to send load request, rc = %d\n", rc); 988316485Sdavidcs return rc; 989316485Sdavidcs } 990316485Sdavidcs 991316485Sdavidcs DP_VERBOSE(p_hwfn, ECORE_MSG_SP, 992316485Sdavidcs "Load Response: resp 0x%08x\n", mb_params.mcp_resp); 993316485Sdavidcs p_out_params->load_code = mb_params.mcp_resp; 994316485Sdavidcs 995316485Sdavidcs if (p_in_params->hsi_ver != ECORE_LOAD_REQ_HSI_VER_1 && 996316485Sdavidcs p_out_params->load_code != FW_MSG_CODE_DRV_LOAD_REFUSED_HSI_1) { 997316485Sdavidcs DP_VERBOSE(p_hwfn, ECORE_MSG_SP, 998316485Sdavidcs "Load Response: exist_drv_ver 0x%08x_0x%08x, exist_fw_ver 0x%08x, misc0 0x%08x [exist_role %d, mfw_hsi %d, flags0 0x%x]\n", 999316485Sdavidcs load_rsp.drv_ver_0, load_rsp.drv_ver_1, 1000316485Sdavidcs load_rsp.fw_ver, load_rsp.misc0, 1001320164Sdavidcs GET_MFW_FIELD(load_rsp.misc0, LOAD_RSP_ROLE), 1002320164Sdavidcs GET_MFW_FIELD(load_rsp.misc0, LOAD_RSP_HSI), 1003320164Sdavidcs GET_MFW_FIELD(load_rsp.misc0, LOAD_RSP_FLAGS0)); 1004316485Sdavidcs 1005316485Sdavidcs p_out_params->exist_drv_ver_0 = load_rsp.drv_ver_0; 1006316485Sdavidcs p_out_params->exist_drv_ver_1 = load_rsp.drv_ver_1; 1007316485Sdavidcs p_out_params->exist_fw_ver = load_rsp.fw_ver; 1008316485Sdavidcs p_out_params->exist_drv_role = 1009320164Sdavidcs GET_MFW_FIELD(load_rsp.misc0, LOAD_RSP_ROLE); 1010316485Sdavidcs p_out_params->mfw_hsi_ver = 1011320164Sdavidcs GET_MFW_FIELD(load_rsp.misc0, LOAD_RSP_HSI); 1012316485Sdavidcs p_out_params->drv_exists = 1013320164Sdavidcs GET_MFW_FIELD(load_rsp.misc0, LOAD_RSP_FLAGS0) & 1014316485Sdavidcs LOAD_RSP_FLAGS0_DRV_EXISTS; 1015316485Sdavidcs } 1016316485Sdavidcs 1017316485Sdavidcs return ECORE_SUCCESS; 1018316485Sdavidcs} 1019316485Sdavidcs 1020320164Sdavidcsstatic void ecore_get_mfw_drv_role(enum ecore_drv_role drv_role, 1021320164Sdavidcs u8 *p_mfw_drv_role) 1022316485Sdavidcs{ 1023320164Sdavidcs switch (drv_role) { 1024316485Sdavidcs case ECORE_DRV_ROLE_OS: 1025316485Sdavidcs *p_mfw_drv_role = DRV_ROLE_OS; 1026316485Sdavidcs break; 1027316485Sdavidcs case ECORE_DRV_ROLE_KDUMP: 1028316485Sdavidcs *p_mfw_drv_role = DRV_ROLE_KDUMP; 1029316485Sdavidcs break; 1030316485Sdavidcs } 1031316485Sdavidcs} 1032316485Sdavidcs 1033316485Sdavidcsenum ecore_load_req_force { 1034316485Sdavidcs ECORE_LOAD_REQ_FORCE_NONE, 1035316485Sdavidcs ECORE_LOAD_REQ_FORCE_PF, 1036316485Sdavidcs ECORE_LOAD_REQ_FORCE_ALL, 1037316485Sdavidcs}; 1038316485Sdavidcs 1039320164Sdavidcsstatic void ecore_get_mfw_force_cmd(enum ecore_load_req_force force_cmd, 1040320164Sdavidcs u8 *p_mfw_force_cmd) 1041316485Sdavidcs{ 1042316485Sdavidcs switch (force_cmd) { 1043316485Sdavidcs case ECORE_LOAD_REQ_FORCE_NONE: 1044316485Sdavidcs *p_mfw_force_cmd = LOAD_REQ_FORCE_NONE; 1045316485Sdavidcs break; 1046316485Sdavidcs case ECORE_LOAD_REQ_FORCE_PF: 1047316485Sdavidcs *p_mfw_force_cmd = LOAD_REQ_FORCE_PF; 1048316485Sdavidcs break; 1049316485Sdavidcs case ECORE_LOAD_REQ_FORCE_ALL: 1050316485Sdavidcs *p_mfw_force_cmd = LOAD_REQ_FORCE_ALL; 1051316485Sdavidcs break; 1052316485Sdavidcs } 1053316485Sdavidcs} 1054316485Sdavidcs 1055316485Sdavidcsenum _ecore_status_t ecore_mcp_load_req(struct ecore_hwfn *p_hwfn, 1056316485Sdavidcs struct ecore_ptt *p_ptt, 1057316485Sdavidcs struct ecore_load_req_params *p_params) 1058316485Sdavidcs{ 1059316485Sdavidcs struct ecore_load_req_out_params out_params; 1060316485Sdavidcs struct ecore_load_req_in_params in_params; 1061320164Sdavidcs u8 mfw_drv_role = 0, mfw_force_cmd; 1062316485Sdavidcs enum _ecore_status_t rc; 1063316485Sdavidcs 1064316485Sdavidcs#ifndef ASIC_ONLY 1065316485Sdavidcs if (CHIP_REV_IS_EMUL(p_hwfn->p_dev)) { 1066316485Sdavidcs ecore_mcp_mf_workaround(p_hwfn, &p_params->load_code); 1067316485Sdavidcs return ECORE_SUCCESS; 1068316485Sdavidcs } 1069316485Sdavidcs#endif 1070316485Sdavidcs 1071316485Sdavidcs OSAL_MEM_ZERO(&in_params, sizeof(in_params)); 1072316485Sdavidcs in_params.hsi_ver = ECORE_LOAD_REQ_HSI_VER_DEFAULT; 1073316485Sdavidcs in_params.drv_ver_0 = ECORE_VERSION; 1074316485Sdavidcs in_params.drv_ver_1 = ecore_get_config_bitmap(); 1075316485Sdavidcs in_params.fw_ver = STORM_FW_VERSION; 1076320164Sdavidcs ecore_get_mfw_drv_role(p_params->drv_role, &mfw_drv_role); 1077316485Sdavidcs in_params.drv_role = mfw_drv_role; 1078316485Sdavidcs in_params.timeout_val = p_params->timeout_val; 1079320164Sdavidcs ecore_get_mfw_force_cmd(ECORE_LOAD_REQ_FORCE_NONE, &mfw_force_cmd); 1080316485Sdavidcs in_params.force_cmd = mfw_force_cmd; 1081316485Sdavidcs in_params.avoid_eng_reset = p_params->avoid_eng_reset; 1082316485Sdavidcs 1083316485Sdavidcs OSAL_MEM_ZERO(&out_params, sizeof(out_params)); 1084316485Sdavidcs rc = __ecore_mcp_load_req(p_hwfn, p_ptt, &in_params, &out_params); 1085316485Sdavidcs if (rc != ECORE_SUCCESS) 1086316485Sdavidcs return rc; 1087316485Sdavidcs 1088316485Sdavidcs /* First handle cases where another load request should/might be sent: 1089316485Sdavidcs * - MFW expects the old interface [HSI version = 1] 1090316485Sdavidcs * - MFW responds that a force load request is required 1091316485Sdavidcs */ 1092316485Sdavidcs if (out_params.load_code == FW_MSG_CODE_DRV_LOAD_REFUSED_HSI_1) { 1093316485Sdavidcs DP_INFO(p_hwfn, 1094316485Sdavidcs "MFW refused a load request due to HSI > 1. Resending with HSI = 1.\n"); 1095316485Sdavidcs 1096316485Sdavidcs in_params.hsi_ver = ECORE_LOAD_REQ_HSI_VER_1; 1097316485Sdavidcs OSAL_MEM_ZERO(&out_params, sizeof(out_params)); 1098316485Sdavidcs rc = __ecore_mcp_load_req(p_hwfn, p_ptt, &in_params, 1099316485Sdavidcs &out_params); 1100316485Sdavidcs if (rc != ECORE_SUCCESS) 1101316485Sdavidcs return rc; 1102316485Sdavidcs } else if (out_params.load_code == 1103316485Sdavidcs FW_MSG_CODE_DRV_LOAD_REFUSED_REQUIRES_FORCE) { 1104316485Sdavidcs if (ecore_mcp_can_force_load(in_params.drv_role, 1105316485Sdavidcs out_params.exist_drv_role, 1106316485Sdavidcs p_params->override_force_load)) { 1107316485Sdavidcs DP_INFO(p_hwfn, 1108320164Sdavidcs "A force load is required [{role, fw_ver, drv_ver}: loading={%d, 0x%08x, 0x%08x_%08x}, existing={%d, 0x%08x, 0x%08x_%08x}]\n", 1109316485Sdavidcs in_params.drv_role, in_params.fw_ver, 1110337517Sdavidcs in_params.drv_ver_0, in_params.drv_ver_1, 1111316485Sdavidcs out_params.exist_drv_role, 1112316485Sdavidcs out_params.exist_fw_ver, 1113337517Sdavidcs out_params.exist_drv_ver_0, 1114337517Sdavidcs out_params.exist_drv_ver_1); 1115316485Sdavidcs 1116320164Sdavidcs ecore_get_mfw_force_cmd(ECORE_LOAD_REQ_FORCE_ALL, 1117320164Sdavidcs &mfw_force_cmd); 1118316485Sdavidcs 1119316485Sdavidcs in_params.force_cmd = mfw_force_cmd; 1120316485Sdavidcs OSAL_MEM_ZERO(&out_params, sizeof(out_params)); 1121316485Sdavidcs rc = __ecore_mcp_load_req(p_hwfn, p_ptt, &in_params, 1122316485Sdavidcs &out_params); 1123316485Sdavidcs if (rc != ECORE_SUCCESS) 1124316485Sdavidcs return rc; 1125316485Sdavidcs } else { 1126316485Sdavidcs DP_NOTICE(p_hwfn, false, 1127320164Sdavidcs "A force load is required [{role, fw_ver, drv_ver}: loading={%d, 0x%08x, x%08x_0x%08x}, existing={%d, 0x%08x, 0x%08x_0x%08x}] - Avoid\n", 1128316485Sdavidcs in_params.drv_role, in_params.fw_ver, 1129316485Sdavidcs in_params.drv_ver_0, in_params.drv_ver_1, 1130316485Sdavidcs out_params.exist_drv_role, 1131316485Sdavidcs out_params.exist_fw_ver, 1132316485Sdavidcs out_params.exist_drv_ver_0, 1133316485Sdavidcs out_params.exist_drv_ver_1); 1134316485Sdavidcs 1135316485Sdavidcs ecore_mcp_cancel_load_req(p_hwfn, p_ptt); 1136316485Sdavidcs return ECORE_BUSY; 1137316485Sdavidcs } 1138316485Sdavidcs } 1139316485Sdavidcs 1140316485Sdavidcs /* Now handle the other types of responses. 1141316485Sdavidcs * The "REFUSED_HSI_1" and "REFUSED_REQUIRES_FORCE" responses are not 1142316485Sdavidcs * expected here after the additional revised load requests were sent. 1143316485Sdavidcs */ 1144316485Sdavidcs switch (out_params.load_code) { 1145316485Sdavidcs case FW_MSG_CODE_DRV_LOAD_ENGINE: 1146316485Sdavidcs case FW_MSG_CODE_DRV_LOAD_PORT: 1147316485Sdavidcs case FW_MSG_CODE_DRV_LOAD_FUNCTION: 1148316485Sdavidcs if (out_params.mfw_hsi_ver != ECORE_LOAD_REQ_HSI_VER_1 && 1149316485Sdavidcs out_params.drv_exists) { 1150316485Sdavidcs /* The role and fw/driver version match, but the PF is 1151316485Sdavidcs * already loaded and has not been unloaded gracefully. 1152316485Sdavidcs * This is unexpected since a quasi-FLR request was 1153316485Sdavidcs * previously sent as part of ecore_hw_prepare(). 1154316485Sdavidcs */ 1155316485Sdavidcs DP_NOTICE(p_hwfn, false, 1156316485Sdavidcs "PF is already loaded - shouldn't have got here since a quasi-FLR request was previously sent!\n"); 1157316485Sdavidcs return ECORE_INVAL; 1158316485Sdavidcs } 1159316485Sdavidcs break; 1160320164Sdavidcs default: 1161316485Sdavidcs DP_NOTICE(p_hwfn, false, 1162320164Sdavidcs "Unexpected refusal to load request [resp 0x%08x]. Aborting.\n", 1163316485Sdavidcs out_params.load_code); 1164316485Sdavidcs return ECORE_BUSY; 1165316485Sdavidcs } 1166316485Sdavidcs 1167316485Sdavidcs p_params->load_code = out_params.load_code; 1168316485Sdavidcs 1169316485Sdavidcs return ECORE_SUCCESS; 1170316485Sdavidcs} 1171316485Sdavidcs 1172337517Sdavidcsenum _ecore_status_t ecore_mcp_load_done(struct ecore_hwfn *p_hwfn, 1173337517Sdavidcs struct ecore_ptt *p_ptt) 1174337517Sdavidcs{ 1175337517Sdavidcs u32 resp = 0, param = 0; 1176337517Sdavidcs enum _ecore_status_t rc; 1177337517Sdavidcs 1178337517Sdavidcs rc = ecore_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_LOAD_DONE, 0, &resp, 1179337517Sdavidcs ¶m); 1180337517Sdavidcs if (rc != ECORE_SUCCESS) { 1181337517Sdavidcs DP_NOTICE(p_hwfn, false, 1182337517Sdavidcs "Failed to send a LOAD_DONE command, rc = %d\n", rc); 1183337517Sdavidcs return rc; 1184337517Sdavidcs } 1185337517Sdavidcs 1186337517Sdavidcs if (resp == FW_MSG_CODE_DRV_LOAD_REFUSED_REJECT) { 1187337517Sdavidcs DP_NOTICE(p_hwfn, false, 1188337517Sdavidcs "Received a LOAD_REFUSED_REJECT response from the mfw\n"); 1189337517Sdavidcs return ECORE_ABORTED; 1190337517Sdavidcs } 1191337517Sdavidcs 1192337517Sdavidcs /* Check if there is a DID mismatch between nvm-cfg/efuse */ 1193337517Sdavidcs if (param & FW_MB_PARAM_LOAD_DONE_DID_EFUSE_ERROR) 1194337517Sdavidcs DP_NOTICE(p_hwfn, false, 1195337517Sdavidcs "warning: device configuration is not supported on this board type. The device may not function as expected.\n"); 1196337517Sdavidcs 1197337517Sdavidcs return ECORE_SUCCESS; 1198337517Sdavidcs} 1199337517Sdavidcs 1200316485Sdavidcsenum _ecore_status_t ecore_mcp_unload_req(struct ecore_hwfn *p_hwfn, 1201316485Sdavidcs struct ecore_ptt *p_ptt) 1202316485Sdavidcs{ 1203337517Sdavidcs struct ecore_mcp_mb_params mb_params; 1204337517Sdavidcs u32 wol_param; 1205316485Sdavidcs 1206316485Sdavidcs switch (p_hwfn->p_dev->wol_config) { 1207316485Sdavidcs case ECORE_OV_WOL_DISABLED: 1208316485Sdavidcs wol_param = DRV_MB_PARAM_UNLOAD_WOL_DISABLED; 1209316485Sdavidcs break; 1210316485Sdavidcs case ECORE_OV_WOL_ENABLED: 1211316485Sdavidcs wol_param = DRV_MB_PARAM_UNLOAD_WOL_ENABLED; 1212316485Sdavidcs break; 1213316485Sdavidcs default: 1214316485Sdavidcs DP_NOTICE(p_hwfn, true, 1215316485Sdavidcs "Unknown WoL configuration %02x\n", 1216316485Sdavidcs p_hwfn->p_dev->wol_config); 1217316485Sdavidcs /* Fallthrough */ 1218316485Sdavidcs case ECORE_OV_WOL_DEFAULT: 1219316485Sdavidcs wol_param = DRV_MB_PARAM_UNLOAD_WOL_MCP; 1220316485Sdavidcs } 1221316485Sdavidcs 1222337517Sdavidcs OSAL_MEM_ZERO(&mb_params, sizeof(mb_params)); 1223337517Sdavidcs mb_params.cmd = DRV_MSG_CODE_UNLOAD_REQ; 1224337517Sdavidcs mb_params.param = wol_param; 1225337517Sdavidcs mb_params.flags = ECORE_MB_FLAG_CAN_SLEEP | ECORE_MB_FLAG_AVOID_BLOCK; 1226337517Sdavidcs 1227337517Sdavidcs return ecore_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 1228316485Sdavidcs} 1229316485Sdavidcs 1230316485Sdavidcsenum _ecore_status_t ecore_mcp_unload_done(struct ecore_hwfn *p_hwfn, 1231316485Sdavidcs struct ecore_ptt *p_ptt) 1232316485Sdavidcs{ 1233316485Sdavidcs struct ecore_mcp_mb_params mb_params; 1234316485Sdavidcs struct mcp_mac wol_mac; 1235316485Sdavidcs 1236316485Sdavidcs OSAL_MEM_ZERO(&mb_params, sizeof(mb_params)); 1237316485Sdavidcs mb_params.cmd = DRV_MSG_CODE_UNLOAD_DONE; 1238316485Sdavidcs 1239316485Sdavidcs /* Set the primary MAC if WoL is enabled */ 1240316485Sdavidcs if (p_hwfn->p_dev->wol_config == ECORE_OV_WOL_ENABLED) { 1241316485Sdavidcs u8 *p_mac = p_hwfn->p_dev->wol_mac; 1242316485Sdavidcs 1243316485Sdavidcs OSAL_MEM_ZERO(&wol_mac, sizeof(wol_mac)); 1244316485Sdavidcs wol_mac.mac_upper = p_mac[0] << 8 | p_mac[1]; 1245316485Sdavidcs wol_mac.mac_lower = p_mac[2] << 24 | p_mac[3] << 16 | 1246316485Sdavidcs p_mac[4] << 8 | p_mac[5]; 1247316485Sdavidcs 1248316485Sdavidcs DP_VERBOSE(p_hwfn, (ECORE_MSG_SP | ECORE_MSG_IFDOWN), 1249316485Sdavidcs "Setting WoL MAC: %02x:%02x:%02x:%02x:%02x:%02x --> [%08x,%08x]\n", 1250316485Sdavidcs p_mac[0], p_mac[1], p_mac[2], p_mac[3], p_mac[4], 1251316485Sdavidcs p_mac[5], wol_mac.mac_upper, wol_mac.mac_lower); 1252316485Sdavidcs 1253316485Sdavidcs mb_params.p_data_src = &wol_mac; 1254316485Sdavidcs mb_params.data_src_size = sizeof(wol_mac); 1255316485Sdavidcs } 1256316485Sdavidcs 1257316485Sdavidcs return ecore_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 1258316485Sdavidcs} 1259316485Sdavidcs 1260316485Sdavidcsstatic void ecore_mcp_handle_vf_flr(struct ecore_hwfn *p_hwfn, 1261316485Sdavidcs struct ecore_ptt *p_ptt) 1262316485Sdavidcs{ 1263316485Sdavidcs u32 addr = SECTION_OFFSIZE_ADDR(p_hwfn->mcp_info->public_base, 1264316485Sdavidcs PUBLIC_PATH); 1265316485Sdavidcs u32 mfw_path_offsize = ecore_rd(p_hwfn, p_ptt, addr); 1266316485Sdavidcs u32 path_addr = SECTION_ADDR(mfw_path_offsize, 1267316485Sdavidcs ECORE_PATH_ID(p_hwfn)); 1268316485Sdavidcs u32 disabled_vfs[VF_MAX_STATIC / 32]; 1269316485Sdavidcs int i; 1270316485Sdavidcs 1271316485Sdavidcs DP_VERBOSE(p_hwfn, ECORE_MSG_SP, 1272316485Sdavidcs "Reading Disabled VF information from [offset %08x], path_addr %08x\n", 1273316485Sdavidcs mfw_path_offsize, path_addr); 1274316485Sdavidcs 1275316485Sdavidcs for (i = 0; i < (VF_MAX_STATIC / 32); i++) { 1276316485Sdavidcs disabled_vfs[i] = ecore_rd(p_hwfn, p_ptt, 1277316485Sdavidcs path_addr + 1278316485Sdavidcs OFFSETOF(struct public_path, 1279316485Sdavidcs mcp_vf_disabled) + 1280316485Sdavidcs sizeof(u32) * i); 1281316485Sdavidcs DP_VERBOSE(p_hwfn, (ECORE_MSG_SP | ECORE_MSG_IOV), 1282316485Sdavidcs "FLR-ed VFs [%08x,...,%08x] - %08x\n", 1283316485Sdavidcs i * 32, (i + 1) * 32 - 1, disabled_vfs[i]); 1284316485Sdavidcs } 1285316485Sdavidcs 1286316485Sdavidcs if (ecore_iov_mark_vf_flr(p_hwfn, disabled_vfs)) 1287316485Sdavidcs OSAL_VF_FLR_UPDATE(p_hwfn); 1288316485Sdavidcs} 1289316485Sdavidcs 1290316485Sdavidcsenum _ecore_status_t ecore_mcp_ack_vf_flr(struct ecore_hwfn *p_hwfn, 1291316485Sdavidcs struct ecore_ptt *p_ptt, 1292316485Sdavidcs u32 *vfs_to_ack) 1293316485Sdavidcs{ 1294316485Sdavidcs u32 addr = SECTION_OFFSIZE_ADDR(p_hwfn->mcp_info->public_base, 1295316485Sdavidcs PUBLIC_FUNC); 1296316485Sdavidcs u32 mfw_func_offsize = ecore_rd(p_hwfn, p_ptt, addr); 1297316485Sdavidcs u32 func_addr = SECTION_ADDR(mfw_func_offsize, 1298316485Sdavidcs MCP_PF_ID(p_hwfn)); 1299316485Sdavidcs struct ecore_mcp_mb_params mb_params; 1300316485Sdavidcs enum _ecore_status_t rc; 1301316485Sdavidcs int i; 1302316485Sdavidcs 1303316485Sdavidcs for (i = 0; i < (VF_MAX_STATIC / 32); i++) 1304316485Sdavidcs DP_VERBOSE(p_hwfn, (ECORE_MSG_SP | ECORE_MSG_IOV), 1305316485Sdavidcs "Acking VFs [%08x,...,%08x] - %08x\n", 1306316485Sdavidcs i * 32, (i + 1) * 32 - 1, vfs_to_ack[i]); 1307316485Sdavidcs 1308316485Sdavidcs OSAL_MEM_ZERO(&mb_params, sizeof(mb_params)); 1309316485Sdavidcs mb_params.cmd = DRV_MSG_CODE_VF_DISABLED_DONE; 1310316485Sdavidcs mb_params.p_data_src = vfs_to_ack; 1311316485Sdavidcs mb_params.data_src_size = VF_MAX_STATIC / 8; 1312316485Sdavidcs rc = ecore_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 1313316485Sdavidcs if (rc != ECORE_SUCCESS) { 1314316485Sdavidcs DP_NOTICE(p_hwfn, false, 1315316485Sdavidcs "Failed to pass ACK for VF flr to MFW\n"); 1316316485Sdavidcs return ECORE_TIMEOUT; 1317316485Sdavidcs } 1318316485Sdavidcs 1319316485Sdavidcs /* TMP - clear the ACK bits; should be done by MFW */ 1320316485Sdavidcs for (i = 0; i < (VF_MAX_STATIC / 32); i++) 1321316485Sdavidcs ecore_wr(p_hwfn, p_ptt, 1322316485Sdavidcs func_addr + 1323316485Sdavidcs OFFSETOF(struct public_func, drv_ack_vf_disabled) + 1324316485Sdavidcs i * sizeof(u32), 0); 1325316485Sdavidcs 1326316485Sdavidcs return rc; 1327316485Sdavidcs} 1328316485Sdavidcs 1329316485Sdavidcsstatic void ecore_mcp_handle_transceiver_change(struct ecore_hwfn *p_hwfn, 1330316485Sdavidcs struct ecore_ptt *p_ptt) 1331316485Sdavidcs{ 1332316485Sdavidcs u32 transceiver_state; 1333316485Sdavidcs 1334316485Sdavidcs transceiver_state = ecore_rd(p_hwfn, p_ptt, 1335316485Sdavidcs p_hwfn->mcp_info->port_addr + 1336316485Sdavidcs OFFSETOF(struct public_port, 1337316485Sdavidcs transceiver_data)); 1338316485Sdavidcs 1339316485Sdavidcs DP_VERBOSE(p_hwfn, (ECORE_MSG_HW | ECORE_MSG_SP), 1340316485Sdavidcs "Received transceiver state update [0x%08x] from mfw [Addr 0x%x]\n", 1341316485Sdavidcs transceiver_state, (u32)(p_hwfn->mcp_info->port_addr + 1342316485Sdavidcs OFFSETOF(struct public_port, 1343316485Sdavidcs transceiver_data))); 1344316485Sdavidcs 1345320164Sdavidcs transceiver_state = GET_MFW_FIELD(transceiver_state, 1346320164Sdavidcs ETH_TRANSCEIVER_STATE); 1347316485Sdavidcs 1348316485Sdavidcs if (transceiver_state == ETH_TRANSCEIVER_STATE_PRESENT) 1349316485Sdavidcs DP_NOTICE(p_hwfn, false, "Transceiver is present.\n"); 1350316485Sdavidcs else 1351316485Sdavidcs DP_NOTICE(p_hwfn, false, "Transceiver is unplugged.\n"); 1352337517Sdavidcs 1353337517Sdavidcs OSAL_TRANSCEIVER_UPDATE(p_hwfn); 1354316485Sdavidcs} 1355316485Sdavidcs 1356316485Sdavidcsstatic void ecore_mcp_read_eee_config(struct ecore_hwfn *p_hwfn, 1357316485Sdavidcs struct ecore_ptt *p_ptt, 1358316485Sdavidcs struct ecore_mcp_link_state *p_link) 1359316485Sdavidcs{ 1360316485Sdavidcs u32 eee_status, val; 1361316485Sdavidcs 1362316485Sdavidcs p_link->eee_adv_caps = 0; 1363316485Sdavidcs p_link->eee_lp_adv_caps = 0; 1364316485Sdavidcs eee_status = ecore_rd(p_hwfn, p_ptt, p_hwfn->mcp_info->port_addr + 1365316485Sdavidcs OFFSETOF(struct public_port, eee_status)); 1366316485Sdavidcs p_link->eee_active = !!(eee_status & EEE_ACTIVE_BIT); 1367320164Sdavidcs val = (eee_status & EEE_LD_ADV_STATUS_MASK) >> EEE_LD_ADV_STATUS_OFFSET; 1368316485Sdavidcs if (val & EEE_1G_ADV) 1369316485Sdavidcs p_link->eee_adv_caps |= ECORE_EEE_1G_ADV; 1370316485Sdavidcs if (val & EEE_10G_ADV) 1371316485Sdavidcs p_link->eee_adv_caps |= ECORE_EEE_10G_ADV; 1372320164Sdavidcs val = (eee_status & EEE_LP_ADV_STATUS_MASK) >> EEE_LP_ADV_STATUS_OFFSET; 1373316485Sdavidcs if (val & EEE_1G_ADV) 1374316485Sdavidcs p_link->eee_lp_adv_caps |= ECORE_EEE_1G_ADV; 1375316485Sdavidcs if (val & EEE_10G_ADV) 1376316485Sdavidcs p_link->eee_lp_adv_caps |= ECORE_EEE_10G_ADV; 1377316485Sdavidcs} 1378316485Sdavidcs 1379337517Sdavidcsstatic u32 ecore_mcp_get_shmem_func(struct ecore_hwfn *p_hwfn, 1380337517Sdavidcs struct ecore_ptt *p_ptt, 1381337517Sdavidcs struct public_func *p_data, 1382337517Sdavidcs int pfid) 1383337517Sdavidcs{ 1384337517Sdavidcs u32 addr = SECTION_OFFSIZE_ADDR(p_hwfn->mcp_info->public_base, 1385337517Sdavidcs PUBLIC_FUNC); 1386337517Sdavidcs u32 mfw_path_offsize = ecore_rd(p_hwfn, p_ptt, addr); 1387337517Sdavidcs u32 func_addr = SECTION_ADDR(mfw_path_offsize, pfid); 1388337517Sdavidcs u32 i, size; 1389337517Sdavidcs 1390337517Sdavidcs OSAL_MEM_ZERO(p_data, sizeof(*p_data)); 1391337517Sdavidcs 1392337517Sdavidcs size = OSAL_MIN_T(u32, sizeof(*p_data), 1393337517Sdavidcs SECTION_SIZE(mfw_path_offsize)); 1394337517Sdavidcs for (i = 0; i < size / sizeof(u32); i++) 1395337517Sdavidcs ((u32 *)p_data)[i] = ecore_rd(p_hwfn, p_ptt, 1396337517Sdavidcs func_addr + (i << 2)); 1397337517Sdavidcs 1398337517Sdavidcs return size; 1399337517Sdavidcs} 1400337517Sdavidcs 1401337517Sdavidcsstatic void ecore_read_pf_bandwidth(struct ecore_hwfn *p_hwfn, 1402337517Sdavidcs struct public_func *p_shmem_info) 1403337517Sdavidcs{ 1404337517Sdavidcs struct ecore_mcp_function_info *p_info; 1405337517Sdavidcs 1406337517Sdavidcs p_info = &p_hwfn->mcp_info->func_info; 1407337517Sdavidcs 1408337517Sdavidcs /* TODO - bandwidth min/max should have valid values of 1-100, 1409337517Sdavidcs * as well as some indication that the feature is disabled. 1410337517Sdavidcs * Until MFW/qlediag enforce those limitations, Assume THERE IS ALWAYS 1411337517Sdavidcs * limit and correct value to min `1' and max `100' if limit isn't in 1412337517Sdavidcs * range. 1413337517Sdavidcs */ 1414337517Sdavidcs p_info->bandwidth_min = (p_shmem_info->config & 1415337517Sdavidcs FUNC_MF_CFG_MIN_BW_MASK) >> 1416337517Sdavidcs FUNC_MF_CFG_MIN_BW_OFFSET; 1417337517Sdavidcs if (p_info->bandwidth_min < 1 || p_info->bandwidth_min > 100) { 1418337517Sdavidcs DP_INFO(p_hwfn, 1419337517Sdavidcs "bandwidth minimum out of bounds [%02x]. Set to 1\n", 1420337517Sdavidcs p_info->bandwidth_min); 1421337517Sdavidcs p_info->bandwidth_min = 1; 1422337517Sdavidcs } 1423337517Sdavidcs 1424337517Sdavidcs p_info->bandwidth_max = (p_shmem_info->config & 1425337517Sdavidcs FUNC_MF_CFG_MAX_BW_MASK) >> 1426337517Sdavidcs FUNC_MF_CFG_MAX_BW_OFFSET; 1427337517Sdavidcs if (p_info->bandwidth_max < 1 || p_info->bandwidth_max > 100) { 1428337517Sdavidcs DP_INFO(p_hwfn, 1429337517Sdavidcs "bandwidth maximum out of bounds [%02x]. Set to 100\n", 1430337517Sdavidcs p_info->bandwidth_max); 1431337517Sdavidcs p_info->bandwidth_max = 100; 1432337517Sdavidcs } 1433337517Sdavidcs} 1434337517Sdavidcs 1435316485Sdavidcsstatic void ecore_mcp_handle_link_change(struct ecore_hwfn *p_hwfn, 1436316485Sdavidcs struct ecore_ptt *p_ptt, 1437316485Sdavidcs bool b_reset) 1438316485Sdavidcs{ 1439316485Sdavidcs struct ecore_mcp_link_state *p_link; 1440316485Sdavidcs u8 max_bw, min_bw; 1441316485Sdavidcs u32 status = 0; 1442316485Sdavidcs 1443316485Sdavidcs /* Prevent SW/attentions from doing this at the same time */ 1444316485Sdavidcs OSAL_SPIN_LOCK(&p_hwfn->mcp_info->link_lock); 1445316485Sdavidcs 1446316485Sdavidcs p_link = &p_hwfn->mcp_info->link_output; 1447316485Sdavidcs OSAL_MEMSET(p_link, 0, sizeof(*p_link)); 1448316485Sdavidcs if (!b_reset) { 1449316485Sdavidcs status = ecore_rd(p_hwfn, p_ptt, 1450316485Sdavidcs p_hwfn->mcp_info->port_addr + 1451316485Sdavidcs OFFSETOF(struct public_port, link_status)); 1452316485Sdavidcs DP_VERBOSE(p_hwfn, (ECORE_MSG_LINK | ECORE_MSG_SP), 1453316485Sdavidcs "Received link update [0x%08x] from mfw [Addr 0x%x]\n", 1454316485Sdavidcs status, (u32)(p_hwfn->mcp_info->port_addr + 1455316485Sdavidcs OFFSETOF(struct public_port, link_status))); 1456316485Sdavidcs } else { 1457316485Sdavidcs DP_VERBOSE(p_hwfn, ECORE_MSG_LINK, 1458316485Sdavidcs "Resetting link indications\n"); 1459316485Sdavidcs goto out; 1460316485Sdavidcs } 1461316485Sdavidcs 1462337517Sdavidcs if (p_hwfn->b_drv_link_init) { 1463337517Sdavidcs /* Link indication with modern MFW arrives as per-PF 1464337517Sdavidcs * indication. 1465337517Sdavidcs */ 1466337517Sdavidcs if (p_hwfn->mcp_info->capabilities & 1467337517Sdavidcs FW_MB_PARAM_FEATURE_SUPPORT_VLINK) { 1468337517Sdavidcs struct public_func shmem_info; 1469337517Sdavidcs 1470337517Sdavidcs ecore_mcp_get_shmem_func(p_hwfn, p_ptt, &shmem_info, 1471337517Sdavidcs MCP_PF_ID(p_hwfn)); 1472337517Sdavidcs p_link->link_up = !!(shmem_info.status & 1473337517Sdavidcs FUNC_STATUS_VIRTUAL_LINK_UP); 1474337517Sdavidcs ecore_read_pf_bandwidth(p_hwfn, &shmem_info); 1475337517Sdavidcs } else { 1476337517Sdavidcs p_link->link_up = !!(status & LINK_STATUS_LINK_UP); 1477337517Sdavidcs } 1478337517Sdavidcs } else { 1479316485Sdavidcs p_link->link_up = false; 1480337517Sdavidcs } 1481316485Sdavidcs 1482316485Sdavidcs p_link->full_duplex = true; 1483316485Sdavidcs switch ((status & LINK_STATUS_SPEED_AND_DUPLEX_MASK)) { 1484316485Sdavidcs case LINK_STATUS_SPEED_AND_DUPLEX_100G: 1485316485Sdavidcs p_link->speed = 100000; 1486316485Sdavidcs break; 1487316485Sdavidcs case LINK_STATUS_SPEED_AND_DUPLEX_50G: 1488316485Sdavidcs p_link->speed = 50000; 1489316485Sdavidcs break; 1490316485Sdavidcs case LINK_STATUS_SPEED_AND_DUPLEX_40G: 1491316485Sdavidcs p_link->speed = 40000; 1492316485Sdavidcs break; 1493316485Sdavidcs case LINK_STATUS_SPEED_AND_DUPLEX_25G: 1494316485Sdavidcs p_link->speed = 25000; 1495316485Sdavidcs break; 1496316485Sdavidcs case LINK_STATUS_SPEED_AND_DUPLEX_20G: 1497316485Sdavidcs p_link->speed = 20000; 1498316485Sdavidcs break; 1499316485Sdavidcs case LINK_STATUS_SPEED_AND_DUPLEX_10G: 1500316485Sdavidcs p_link->speed = 10000; 1501316485Sdavidcs break; 1502316485Sdavidcs case LINK_STATUS_SPEED_AND_DUPLEX_1000THD: 1503316485Sdavidcs p_link->full_duplex = false; 1504316485Sdavidcs /* Fall-through */ 1505316485Sdavidcs case LINK_STATUS_SPEED_AND_DUPLEX_1000TFD: 1506316485Sdavidcs p_link->speed = 1000; 1507316485Sdavidcs break; 1508316485Sdavidcs default: 1509316485Sdavidcs p_link->speed = 0; 1510337517Sdavidcs p_link->link_up = 0; 1511316485Sdavidcs } 1512316485Sdavidcs 1513316485Sdavidcs /* We never store total line speed as p_link->speed is 1514316485Sdavidcs * again changes according to bandwidth allocation. 1515316485Sdavidcs */ 1516316485Sdavidcs if (p_link->link_up && p_link->speed) 1517316485Sdavidcs p_link->line_speed = p_link->speed; 1518316485Sdavidcs else 1519316485Sdavidcs p_link->line_speed = 0; 1520316485Sdavidcs 1521316485Sdavidcs max_bw = p_hwfn->mcp_info->func_info.bandwidth_max; 1522316485Sdavidcs min_bw = p_hwfn->mcp_info->func_info.bandwidth_min; 1523316485Sdavidcs 1524316485Sdavidcs /* Max bandwidth configuration */ 1525316485Sdavidcs __ecore_configure_pf_max_bandwidth(p_hwfn, p_ptt, p_link, max_bw); 1526316485Sdavidcs 1527320164Sdavidcs /* Min bandwidth configuration */ 1528316485Sdavidcs __ecore_configure_pf_min_bandwidth(p_hwfn, p_ptt, p_link, min_bw); 1529316485Sdavidcs ecore_configure_vp_wfq_on_link_change(p_hwfn->p_dev, p_ptt, 1530316485Sdavidcs p_link->min_pf_rate); 1531316485Sdavidcs 1532316485Sdavidcs p_link->an = !!(status & LINK_STATUS_AUTO_NEGOTIATE_ENABLED); 1533316485Sdavidcs p_link->an_complete = !!(status & 1534316485Sdavidcs LINK_STATUS_AUTO_NEGOTIATE_COMPLETE); 1535316485Sdavidcs p_link->parallel_detection = !!(status & 1536316485Sdavidcs LINK_STATUS_PARALLEL_DETECTION_USED); 1537316485Sdavidcs p_link->pfc_enabled = !!(status & LINK_STATUS_PFC_ENABLED); 1538316485Sdavidcs 1539316485Sdavidcs p_link->partner_adv_speed |= 1540316485Sdavidcs (status & LINK_STATUS_LINK_PARTNER_1000TFD_CAPABLE) ? 1541316485Sdavidcs ECORE_LINK_PARTNER_SPEED_1G_FD : 0; 1542316485Sdavidcs p_link->partner_adv_speed |= 1543316485Sdavidcs (status & LINK_STATUS_LINK_PARTNER_1000THD_CAPABLE) ? 1544316485Sdavidcs ECORE_LINK_PARTNER_SPEED_1G_HD : 0; 1545316485Sdavidcs p_link->partner_adv_speed |= 1546316485Sdavidcs (status & LINK_STATUS_LINK_PARTNER_10G_CAPABLE) ? 1547316485Sdavidcs ECORE_LINK_PARTNER_SPEED_10G : 0; 1548316485Sdavidcs p_link->partner_adv_speed |= 1549316485Sdavidcs (status & LINK_STATUS_LINK_PARTNER_20G_CAPABLE) ? 1550316485Sdavidcs ECORE_LINK_PARTNER_SPEED_20G : 0; 1551316485Sdavidcs p_link->partner_adv_speed |= 1552316485Sdavidcs (status & LINK_STATUS_LINK_PARTNER_25G_CAPABLE) ? 1553316485Sdavidcs ECORE_LINK_PARTNER_SPEED_25G : 0; 1554316485Sdavidcs p_link->partner_adv_speed |= 1555316485Sdavidcs (status & LINK_STATUS_LINK_PARTNER_40G_CAPABLE) ? 1556316485Sdavidcs ECORE_LINK_PARTNER_SPEED_40G : 0; 1557316485Sdavidcs p_link->partner_adv_speed |= 1558316485Sdavidcs (status & LINK_STATUS_LINK_PARTNER_50G_CAPABLE) ? 1559316485Sdavidcs ECORE_LINK_PARTNER_SPEED_50G : 0; 1560316485Sdavidcs p_link->partner_adv_speed |= 1561316485Sdavidcs (status & LINK_STATUS_LINK_PARTNER_100G_CAPABLE) ? 1562316485Sdavidcs ECORE_LINK_PARTNER_SPEED_100G : 0; 1563316485Sdavidcs 1564316485Sdavidcs p_link->partner_tx_flow_ctrl_en = 1565316485Sdavidcs !!(status & LINK_STATUS_TX_FLOW_CONTROL_ENABLED); 1566316485Sdavidcs p_link->partner_rx_flow_ctrl_en = 1567316485Sdavidcs !!(status & LINK_STATUS_RX_FLOW_CONTROL_ENABLED); 1568316485Sdavidcs 1569316485Sdavidcs switch (status & LINK_STATUS_LINK_PARTNER_FLOW_CONTROL_MASK) { 1570316485Sdavidcs case LINK_STATUS_LINK_PARTNER_SYMMETRIC_PAUSE: 1571316485Sdavidcs p_link->partner_adv_pause = ECORE_LINK_PARTNER_SYMMETRIC_PAUSE; 1572316485Sdavidcs break; 1573316485Sdavidcs case LINK_STATUS_LINK_PARTNER_ASYMMETRIC_PAUSE: 1574316485Sdavidcs p_link->partner_adv_pause = ECORE_LINK_PARTNER_ASYMMETRIC_PAUSE; 1575316485Sdavidcs break; 1576316485Sdavidcs case LINK_STATUS_LINK_PARTNER_BOTH_PAUSE: 1577316485Sdavidcs p_link->partner_adv_pause = ECORE_LINK_PARTNER_BOTH_PAUSE; 1578316485Sdavidcs break; 1579316485Sdavidcs default: 1580316485Sdavidcs p_link->partner_adv_pause = 0; 1581316485Sdavidcs } 1582316485Sdavidcs 1583316485Sdavidcs p_link->sfp_tx_fault = !!(status & LINK_STATUS_SFP_TX_FAULT); 1584316485Sdavidcs 1585316485Sdavidcs if (p_hwfn->mcp_info->capabilities & FW_MB_PARAM_FEATURE_SUPPORT_EEE) 1586316485Sdavidcs ecore_mcp_read_eee_config(p_hwfn, p_ptt, p_link); 1587316485Sdavidcs 1588337517Sdavidcs OSAL_LINK_UPDATE(p_hwfn, p_ptt); 1589316485Sdavidcsout: 1590316485Sdavidcs OSAL_SPIN_UNLOCK(&p_hwfn->mcp_info->link_lock); 1591316485Sdavidcs} 1592316485Sdavidcs 1593316485Sdavidcsenum _ecore_status_t ecore_mcp_set_link(struct ecore_hwfn *p_hwfn, 1594316485Sdavidcs struct ecore_ptt *p_ptt, 1595316485Sdavidcs bool b_up) 1596316485Sdavidcs{ 1597316485Sdavidcs struct ecore_mcp_link_params *params = &p_hwfn->mcp_info->link_input; 1598316485Sdavidcs struct ecore_mcp_mb_params mb_params; 1599316485Sdavidcs struct eth_phy_cfg phy_cfg; 1600316485Sdavidcs enum _ecore_status_t rc = ECORE_SUCCESS; 1601316485Sdavidcs u32 cmd; 1602316485Sdavidcs 1603316485Sdavidcs#ifndef ASIC_ONLY 1604316485Sdavidcs if (CHIP_REV_IS_EMUL(p_hwfn->p_dev)) 1605316485Sdavidcs return ECORE_SUCCESS; 1606316485Sdavidcs#endif 1607316485Sdavidcs 1608316485Sdavidcs /* Set the shmem configuration according to params */ 1609316485Sdavidcs OSAL_MEM_ZERO(&phy_cfg, sizeof(phy_cfg)); 1610316485Sdavidcs cmd = b_up ? DRV_MSG_CODE_INIT_PHY : DRV_MSG_CODE_LINK_RESET; 1611316485Sdavidcs if (!params->speed.autoneg) 1612316485Sdavidcs phy_cfg.speed = params->speed.forced_speed; 1613316485Sdavidcs phy_cfg.pause |= (params->pause.autoneg) ? ETH_PAUSE_AUTONEG : 0; 1614316485Sdavidcs phy_cfg.pause |= (params->pause.forced_rx) ? ETH_PAUSE_RX : 0; 1615316485Sdavidcs phy_cfg.pause |= (params->pause.forced_tx) ? ETH_PAUSE_TX : 0; 1616316485Sdavidcs phy_cfg.adv_speed = params->speed.advertised_speeds; 1617316485Sdavidcs phy_cfg.loopback_mode = params->loopback_mode; 1618337517Sdavidcs 1619337517Sdavidcs /* There are MFWs that share this capability regardless of whether 1620337517Sdavidcs * this is feasible or not. And given that at the very least adv_caps 1621337517Sdavidcs * would be set internally by ecore, we want to make sure LFA would 1622337517Sdavidcs * still work. 1623337517Sdavidcs */ 1624337517Sdavidcs if ((p_hwfn->mcp_info->capabilities & 1625337517Sdavidcs FW_MB_PARAM_FEATURE_SUPPORT_EEE) && 1626337517Sdavidcs params->eee.enable) { 1627337517Sdavidcs phy_cfg.eee_cfg |= EEE_CFG_EEE_ENABLED; 1628316485Sdavidcs if (params->eee.tx_lpi_enable) 1629316485Sdavidcs phy_cfg.eee_cfg |= EEE_CFG_TX_LPI; 1630316485Sdavidcs if (params->eee.adv_caps & ECORE_EEE_1G_ADV) 1631316485Sdavidcs phy_cfg.eee_cfg |= EEE_CFG_ADV_SPEED_1G; 1632316485Sdavidcs if (params->eee.adv_caps & ECORE_EEE_10G_ADV) 1633316485Sdavidcs phy_cfg.eee_cfg |= EEE_CFG_ADV_SPEED_10G; 1634316485Sdavidcs phy_cfg.eee_cfg |= (params->eee.tx_lpi_timer << 1635320164Sdavidcs EEE_TX_TIMER_USEC_OFFSET) & 1636316485Sdavidcs EEE_TX_TIMER_USEC_MASK; 1637316485Sdavidcs } 1638316485Sdavidcs 1639316485Sdavidcs p_hwfn->b_drv_link_init = b_up; 1640316485Sdavidcs 1641316485Sdavidcs if (b_up) 1642316485Sdavidcs DP_VERBOSE(p_hwfn, ECORE_MSG_LINK, 1643316485Sdavidcs "Configuring Link: Speed 0x%08x, Pause 0x%08x, adv_speed 0x%08x, loopback 0x%08x\n", 1644316485Sdavidcs phy_cfg.speed, phy_cfg.pause, phy_cfg.adv_speed, 1645316485Sdavidcs phy_cfg.loopback_mode); 1646316485Sdavidcs else 1647316485Sdavidcs DP_VERBOSE(p_hwfn, ECORE_MSG_LINK, "Resetting link\n"); 1648316485Sdavidcs 1649316485Sdavidcs OSAL_MEM_ZERO(&mb_params, sizeof(mb_params)); 1650316485Sdavidcs mb_params.cmd = cmd; 1651316485Sdavidcs mb_params.p_data_src = &phy_cfg; 1652316485Sdavidcs mb_params.data_src_size = sizeof(phy_cfg); 1653316485Sdavidcs rc = ecore_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 1654316485Sdavidcs 1655316485Sdavidcs /* if mcp fails to respond we must abort */ 1656316485Sdavidcs if (rc != ECORE_SUCCESS) { 1657316485Sdavidcs DP_ERR(p_hwfn, "MCP response failure, aborting\n"); 1658316485Sdavidcs return rc; 1659316485Sdavidcs } 1660316485Sdavidcs 1661316485Sdavidcs /* Mimic link-change attention, done for several reasons: 1662316485Sdavidcs * - On reset, there's no guarantee MFW would trigger 1663316485Sdavidcs * an attention. 1664316485Sdavidcs * - On initialization, older MFWs might not indicate link change 1665316485Sdavidcs * during LFA, so we'll never get an UP indication. 1666316485Sdavidcs */ 1667316485Sdavidcs ecore_mcp_handle_link_change(p_hwfn, p_ptt, !b_up); 1668316485Sdavidcs 1669337517Sdavidcs return ECORE_SUCCESS; 1670316485Sdavidcs} 1671316485Sdavidcs 1672316485Sdavidcsu32 ecore_get_process_kill_counter(struct ecore_hwfn *p_hwfn, 1673316485Sdavidcs struct ecore_ptt *p_ptt) 1674316485Sdavidcs{ 1675316485Sdavidcs u32 path_offsize_addr, path_offsize, path_addr, proc_kill_cnt; 1676316485Sdavidcs 1677316485Sdavidcs /* TODO - Add support for VFs */ 1678316485Sdavidcs if (IS_VF(p_hwfn->p_dev)) 1679316485Sdavidcs return ECORE_INVAL; 1680316485Sdavidcs 1681316485Sdavidcs path_offsize_addr = SECTION_OFFSIZE_ADDR(p_hwfn->mcp_info->public_base, 1682316485Sdavidcs PUBLIC_PATH); 1683316485Sdavidcs path_offsize = ecore_rd(p_hwfn, p_ptt, path_offsize_addr); 1684316485Sdavidcs path_addr = SECTION_ADDR(path_offsize, ECORE_PATH_ID(p_hwfn)); 1685316485Sdavidcs 1686316485Sdavidcs proc_kill_cnt = ecore_rd(p_hwfn, p_ptt, 1687316485Sdavidcs path_addr + 1688316485Sdavidcs OFFSETOF(struct public_path, process_kill)) & 1689316485Sdavidcs PROCESS_KILL_COUNTER_MASK; 1690316485Sdavidcs 1691316485Sdavidcs return proc_kill_cnt; 1692316485Sdavidcs} 1693316485Sdavidcs 1694316485Sdavidcsstatic void ecore_mcp_handle_process_kill(struct ecore_hwfn *p_hwfn, 1695316485Sdavidcs struct ecore_ptt *p_ptt) 1696316485Sdavidcs{ 1697316485Sdavidcs struct ecore_dev *p_dev = p_hwfn->p_dev; 1698316485Sdavidcs u32 proc_kill_cnt; 1699316485Sdavidcs 1700316485Sdavidcs /* Prevent possible attentions/interrupts during the recovery handling 1701316485Sdavidcs * and till its load phase, during which they will be re-enabled. 1702316485Sdavidcs */ 1703316485Sdavidcs ecore_int_igu_disable_int(p_hwfn, p_ptt); 1704316485Sdavidcs 1705316485Sdavidcs DP_NOTICE(p_hwfn, false, "Received a process kill indication\n"); 1706316485Sdavidcs 1707316485Sdavidcs /* The following operations should be done once, and thus in CMT mode 1708316485Sdavidcs * are carried out by only the first HW function. 1709316485Sdavidcs */ 1710316485Sdavidcs if (p_hwfn != ECORE_LEADING_HWFN(p_dev)) 1711316485Sdavidcs return; 1712316485Sdavidcs 1713316485Sdavidcs if (p_dev->recov_in_prog) { 1714316485Sdavidcs DP_NOTICE(p_hwfn, false, 1715316485Sdavidcs "Ignoring the indication since a recovery process is already in progress\n"); 1716316485Sdavidcs return; 1717316485Sdavidcs } 1718316485Sdavidcs 1719316485Sdavidcs p_dev->recov_in_prog = true; 1720316485Sdavidcs 1721316485Sdavidcs proc_kill_cnt = ecore_get_process_kill_counter(p_hwfn, p_ptt); 1722316485Sdavidcs DP_NOTICE(p_hwfn, false, "Process kill counter: %d\n", proc_kill_cnt); 1723316485Sdavidcs 1724316485Sdavidcs OSAL_SCHEDULE_RECOVERY_HANDLER(p_hwfn); 1725316485Sdavidcs} 1726316485Sdavidcs 1727316485Sdavidcsstatic void ecore_mcp_send_protocol_stats(struct ecore_hwfn *p_hwfn, 1728316485Sdavidcs struct ecore_ptt *p_ptt, 1729316485Sdavidcs enum MFW_DRV_MSG_TYPE type) 1730316485Sdavidcs{ 1731316485Sdavidcs enum ecore_mcp_protocol_type stats_type; 1732316485Sdavidcs union ecore_mcp_protocol_stats stats; 1733316485Sdavidcs struct ecore_mcp_mb_params mb_params; 1734316485Sdavidcs u32 hsi_param; 1735316485Sdavidcs enum _ecore_status_t rc; 1736316485Sdavidcs 1737316485Sdavidcs switch (type) { 1738316485Sdavidcs case MFW_DRV_MSG_GET_LAN_STATS: 1739316485Sdavidcs stats_type = ECORE_MCP_LAN_STATS; 1740316485Sdavidcs hsi_param = DRV_MSG_CODE_STATS_TYPE_LAN; 1741316485Sdavidcs break; 1742316485Sdavidcs case MFW_DRV_MSG_GET_FCOE_STATS: 1743316485Sdavidcs stats_type = ECORE_MCP_FCOE_STATS; 1744316485Sdavidcs hsi_param = DRV_MSG_CODE_STATS_TYPE_FCOE; 1745316485Sdavidcs break; 1746316485Sdavidcs case MFW_DRV_MSG_GET_ISCSI_STATS: 1747316485Sdavidcs stats_type = ECORE_MCP_ISCSI_STATS; 1748316485Sdavidcs hsi_param = DRV_MSG_CODE_STATS_TYPE_ISCSI; 1749316485Sdavidcs break; 1750316485Sdavidcs case MFW_DRV_MSG_GET_RDMA_STATS: 1751316485Sdavidcs stats_type = ECORE_MCP_RDMA_STATS; 1752316485Sdavidcs hsi_param = DRV_MSG_CODE_STATS_TYPE_RDMA; 1753316485Sdavidcs break; 1754316485Sdavidcs default: 1755337517Sdavidcs DP_VERBOSE(p_hwfn, ECORE_MSG_SP, 1756337517Sdavidcs "Invalid protocol type %d\n", type); 1757316485Sdavidcs return; 1758316485Sdavidcs } 1759316485Sdavidcs 1760316485Sdavidcs OSAL_GET_PROTOCOL_STATS(p_hwfn->p_dev, stats_type, &stats); 1761316485Sdavidcs 1762316485Sdavidcs OSAL_MEM_ZERO(&mb_params, sizeof(mb_params)); 1763316485Sdavidcs mb_params.cmd = DRV_MSG_CODE_GET_STATS; 1764316485Sdavidcs mb_params.param = hsi_param; 1765316485Sdavidcs mb_params.p_data_src = &stats; 1766316485Sdavidcs mb_params.data_src_size = sizeof(stats); 1767316485Sdavidcs rc = ecore_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 1768316485Sdavidcs if (rc != ECORE_SUCCESS) 1769316485Sdavidcs DP_ERR(p_hwfn, "Failed to send protocol stats, rc = %d\n", rc); 1770316485Sdavidcs} 1771316485Sdavidcs 1772316485Sdavidcsstatic void 1773316485Sdavidcsecore_mcp_update_bw(struct ecore_hwfn *p_hwfn, struct ecore_ptt *p_ptt) 1774316485Sdavidcs{ 1775316485Sdavidcs struct ecore_mcp_function_info *p_info; 1776316485Sdavidcs struct public_func shmem_info; 1777316485Sdavidcs u32 resp = 0, param = 0; 1778316485Sdavidcs 1779337517Sdavidcs OSAL_SPIN_LOCK(&p_hwfn->mcp_info->link_lock); 1780337517Sdavidcs 1781316485Sdavidcs ecore_mcp_get_shmem_func(p_hwfn, p_ptt, &shmem_info, 1782316485Sdavidcs MCP_PF_ID(p_hwfn)); 1783316485Sdavidcs 1784316485Sdavidcs ecore_read_pf_bandwidth(p_hwfn, &shmem_info); 1785316485Sdavidcs 1786316485Sdavidcs p_info = &p_hwfn->mcp_info->func_info; 1787316485Sdavidcs 1788316485Sdavidcs ecore_configure_pf_min_bandwidth(p_hwfn->p_dev, p_info->bandwidth_min); 1789316485Sdavidcs 1790316485Sdavidcs ecore_configure_pf_max_bandwidth(p_hwfn->p_dev, p_info->bandwidth_max); 1791316485Sdavidcs 1792337517Sdavidcs OSAL_SPIN_UNLOCK(&p_hwfn->mcp_info->link_lock); 1793337517Sdavidcs 1794316485Sdavidcs /* Acknowledge the MFW */ 1795316485Sdavidcs ecore_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_BW_UPDATE_ACK, 0, &resp, 1796316485Sdavidcs ¶m); 1797316485Sdavidcs} 1798316485Sdavidcs 1799316485Sdavidcsstatic void ecore_mcp_update_stag(struct ecore_hwfn *p_hwfn, 1800316485Sdavidcs struct ecore_ptt *p_ptt) 1801316485Sdavidcs{ 1802316485Sdavidcs struct public_func shmem_info; 1803316485Sdavidcs u32 resp = 0, param = 0; 1804316485Sdavidcs 1805316485Sdavidcs ecore_mcp_get_shmem_func(p_hwfn, p_ptt, &shmem_info, 1806316485Sdavidcs MCP_PF_ID(p_hwfn)); 1807316485Sdavidcs 1808316485Sdavidcs p_hwfn->mcp_info->func_info.ovlan = (u16)shmem_info.ovlan_stag & 1809316485Sdavidcs FUNC_MF_CFG_OV_STAG_MASK; 1810316485Sdavidcs p_hwfn->hw_info.ovlan = p_hwfn->mcp_info->func_info.ovlan; 1811316485Sdavidcs if ((p_hwfn->hw_info.hw_mode & (1 << MODE_MF_SD)) && 1812320164Sdavidcs (p_hwfn->hw_info.ovlan != ECORE_MCP_VLAN_UNSET)) { 1813316485Sdavidcs ecore_wr(p_hwfn, p_ptt, 1814316485Sdavidcs NIG_REG_LLH_FUNC_TAG_VALUE, 1815316485Sdavidcs p_hwfn->hw_info.ovlan); 1816320164Sdavidcs ecore_sp_pf_update_stag(p_hwfn); 1817337517Sdavidcs /* Configure doorbell to add external vlan to EDPM packets */ 1818337517Sdavidcs ecore_wr(p_hwfn, p_ptt, DORQ_REG_TAG1_OVRD_MODE, 1); 1819337517Sdavidcs ecore_wr(p_hwfn, p_ptt, DORQ_REG_PF_EXT_VID_BB_K2, 1820337517Sdavidcs p_hwfn->hw_info.ovlan); 1821320164Sdavidcs } 1822316485Sdavidcs 1823337517Sdavidcs DP_VERBOSE(p_hwfn, ECORE_MSG_SP, "ovlan = %d hw_mode = 0x%x\n", 1824337517Sdavidcs p_hwfn->mcp_info->func_info.ovlan, p_hwfn->hw_info.hw_mode); 1825316485Sdavidcs OSAL_HW_INFO_CHANGE(p_hwfn, ECORE_HW_INFO_CHANGE_OVLAN); 1826316485Sdavidcs 1827316485Sdavidcs /* Acknowledge the MFW */ 1828316485Sdavidcs ecore_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_S_TAG_UPDATE_ACK, 0, 1829316485Sdavidcs &resp, ¶m); 1830316485Sdavidcs} 1831316485Sdavidcs 1832320164Sdavidcsstatic void ecore_mcp_handle_fan_failure(struct ecore_hwfn *p_hwfn) 1833316485Sdavidcs{ 1834316485Sdavidcs /* A single notification should be sent to upper driver in CMT mode */ 1835316485Sdavidcs if (p_hwfn != ECORE_LEADING_HWFN(p_hwfn->p_dev)) 1836316485Sdavidcs return; 1837316485Sdavidcs 1838316485Sdavidcs DP_NOTICE(p_hwfn, false, 1839316485Sdavidcs "Fan failure was detected on the network interface card and it's going to be shut down.\n"); 1840316485Sdavidcs 1841316485Sdavidcs ecore_hw_err_notify(p_hwfn, ECORE_HW_ERR_FAN_FAIL); 1842316485Sdavidcs} 1843316485Sdavidcs 1844316485Sdavidcsstruct ecore_mdump_cmd_params { 1845316485Sdavidcs u32 cmd; 1846316485Sdavidcs void *p_data_src; 1847316485Sdavidcs u8 data_src_size; 1848316485Sdavidcs void *p_data_dst; 1849316485Sdavidcs u8 data_dst_size; 1850316485Sdavidcs u32 mcp_resp; 1851316485Sdavidcs}; 1852316485Sdavidcs 1853316485Sdavidcsstatic enum _ecore_status_t 1854316485Sdavidcsecore_mcp_mdump_cmd(struct ecore_hwfn *p_hwfn, struct ecore_ptt *p_ptt, 1855316485Sdavidcs struct ecore_mdump_cmd_params *p_mdump_cmd_params) 1856316485Sdavidcs{ 1857316485Sdavidcs struct ecore_mcp_mb_params mb_params; 1858316485Sdavidcs enum _ecore_status_t rc; 1859316485Sdavidcs 1860316485Sdavidcs OSAL_MEM_ZERO(&mb_params, sizeof(mb_params)); 1861316485Sdavidcs mb_params.cmd = DRV_MSG_CODE_MDUMP_CMD; 1862316485Sdavidcs mb_params.param = p_mdump_cmd_params->cmd; 1863316485Sdavidcs mb_params.p_data_src = p_mdump_cmd_params->p_data_src; 1864316485Sdavidcs mb_params.data_src_size = p_mdump_cmd_params->data_src_size; 1865316485Sdavidcs mb_params.p_data_dst = p_mdump_cmd_params->p_data_dst; 1866316485Sdavidcs mb_params.data_dst_size = p_mdump_cmd_params->data_dst_size; 1867316485Sdavidcs rc = ecore_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 1868316485Sdavidcs if (rc != ECORE_SUCCESS) 1869316485Sdavidcs return rc; 1870316485Sdavidcs 1871316485Sdavidcs p_mdump_cmd_params->mcp_resp = mb_params.mcp_resp; 1872316485Sdavidcs 1873316485Sdavidcs if (p_mdump_cmd_params->mcp_resp == FW_MSG_CODE_MDUMP_INVALID_CMD) { 1874316485Sdavidcs DP_INFO(p_hwfn, 1875316485Sdavidcs "The mdump sub command is unsupported by the MFW [mdump_cmd 0x%x]\n", 1876316485Sdavidcs p_mdump_cmd_params->cmd); 1877316485Sdavidcs rc = ECORE_NOTIMPL; 1878316485Sdavidcs } else if (p_mdump_cmd_params->mcp_resp == FW_MSG_CODE_UNSUPPORTED) { 1879316485Sdavidcs DP_INFO(p_hwfn, 1880316485Sdavidcs "The mdump command is not supported by the MFW\n"); 1881316485Sdavidcs rc = ECORE_NOTIMPL; 1882316485Sdavidcs } 1883316485Sdavidcs 1884316485Sdavidcs return rc; 1885316485Sdavidcs} 1886316485Sdavidcs 1887316485Sdavidcsstatic enum _ecore_status_t ecore_mcp_mdump_ack(struct ecore_hwfn *p_hwfn, 1888316485Sdavidcs struct ecore_ptt *p_ptt) 1889316485Sdavidcs{ 1890316485Sdavidcs struct ecore_mdump_cmd_params mdump_cmd_params; 1891316485Sdavidcs 1892316485Sdavidcs OSAL_MEM_ZERO(&mdump_cmd_params, sizeof(mdump_cmd_params)); 1893316485Sdavidcs mdump_cmd_params.cmd = DRV_MSG_CODE_MDUMP_ACK; 1894316485Sdavidcs 1895316485Sdavidcs return ecore_mcp_mdump_cmd(p_hwfn, p_ptt, &mdump_cmd_params); 1896316485Sdavidcs} 1897316485Sdavidcs 1898316485Sdavidcsenum _ecore_status_t ecore_mcp_mdump_set_values(struct ecore_hwfn *p_hwfn, 1899316485Sdavidcs struct ecore_ptt *p_ptt, 1900316485Sdavidcs u32 epoch) 1901316485Sdavidcs{ 1902316485Sdavidcs struct ecore_mdump_cmd_params mdump_cmd_params; 1903316485Sdavidcs 1904316485Sdavidcs OSAL_MEM_ZERO(&mdump_cmd_params, sizeof(mdump_cmd_params)); 1905316485Sdavidcs mdump_cmd_params.cmd = DRV_MSG_CODE_MDUMP_SET_VALUES; 1906316485Sdavidcs mdump_cmd_params.p_data_src = &epoch; 1907316485Sdavidcs mdump_cmd_params.data_src_size = sizeof(epoch); 1908316485Sdavidcs 1909316485Sdavidcs return ecore_mcp_mdump_cmd(p_hwfn, p_ptt, &mdump_cmd_params); 1910316485Sdavidcs} 1911316485Sdavidcs 1912316485Sdavidcsenum _ecore_status_t ecore_mcp_mdump_trigger(struct ecore_hwfn *p_hwfn, 1913316485Sdavidcs struct ecore_ptt *p_ptt) 1914316485Sdavidcs{ 1915316485Sdavidcs struct ecore_mdump_cmd_params mdump_cmd_params; 1916316485Sdavidcs 1917316485Sdavidcs OSAL_MEM_ZERO(&mdump_cmd_params, sizeof(mdump_cmd_params)); 1918316485Sdavidcs mdump_cmd_params.cmd = DRV_MSG_CODE_MDUMP_TRIGGER; 1919316485Sdavidcs 1920316485Sdavidcs return ecore_mcp_mdump_cmd(p_hwfn, p_ptt, &mdump_cmd_params); 1921316485Sdavidcs} 1922316485Sdavidcs 1923316485Sdavidcsstatic enum _ecore_status_t 1924316485Sdavidcsecore_mcp_mdump_get_config(struct ecore_hwfn *p_hwfn, struct ecore_ptt *p_ptt, 1925316485Sdavidcs struct mdump_config_stc *p_mdump_config) 1926316485Sdavidcs{ 1927316485Sdavidcs struct ecore_mdump_cmd_params mdump_cmd_params; 1928316485Sdavidcs enum _ecore_status_t rc; 1929316485Sdavidcs 1930316485Sdavidcs OSAL_MEM_ZERO(&mdump_cmd_params, sizeof(mdump_cmd_params)); 1931316485Sdavidcs mdump_cmd_params.cmd = DRV_MSG_CODE_MDUMP_GET_CONFIG; 1932316485Sdavidcs mdump_cmd_params.p_data_dst = p_mdump_config; 1933316485Sdavidcs mdump_cmd_params.data_dst_size = sizeof(*p_mdump_config); 1934316485Sdavidcs 1935316485Sdavidcs rc = ecore_mcp_mdump_cmd(p_hwfn, p_ptt, &mdump_cmd_params); 1936316485Sdavidcs if (rc != ECORE_SUCCESS) 1937316485Sdavidcs return rc; 1938316485Sdavidcs 1939316485Sdavidcs if (mdump_cmd_params.mcp_resp != FW_MSG_CODE_OK) { 1940316485Sdavidcs DP_INFO(p_hwfn, 1941316485Sdavidcs "Failed to get the mdump configuration and logs info [mcp_resp 0x%x]\n", 1942316485Sdavidcs mdump_cmd_params.mcp_resp); 1943316485Sdavidcs rc = ECORE_UNKNOWN_ERROR; 1944316485Sdavidcs } 1945316485Sdavidcs 1946316485Sdavidcs return rc; 1947316485Sdavidcs} 1948316485Sdavidcs 1949316485Sdavidcsenum _ecore_status_t 1950316485Sdavidcsecore_mcp_mdump_get_info(struct ecore_hwfn *p_hwfn, struct ecore_ptt *p_ptt, 1951316485Sdavidcs struct ecore_mdump_info *p_mdump_info) 1952316485Sdavidcs{ 1953316485Sdavidcs u32 addr, global_offsize, global_addr; 1954316485Sdavidcs struct mdump_config_stc mdump_config; 1955316485Sdavidcs enum _ecore_status_t rc; 1956316485Sdavidcs 1957316485Sdavidcs OSAL_MEMSET(p_mdump_info, 0, sizeof(*p_mdump_info)); 1958316485Sdavidcs 1959316485Sdavidcs addr = SECTION_OFFSIZE_ADDR(p_hwfn->mcp_info->public_base, 1960316485Sdavidcs PUBLIC_GLOBAL); 1961316485Sdavidcs global_offsize = ecore_rd(p_hwfn, p_ptt, addr); 1962316485Sdavidcs global_addr = SECTION_ADDR(global_offsize, 0); 1963316485Sdavidcs p_mdump_info->reason = ecore_rd(p_hwfn, p_ptt, 1964316485Sdavidcs global_addr + 1965316485Sdavidcs OFFSETOF(struct public_global, 1966316485Sdavidcs mdump_reason)); 1967316485Sdavidcs 1968316485Sdavidcs if (p_mdump_info->reason) { 1969316485Sdavidcs rc = ecore_mcp_mdump_get_config(p_hwfn, p_ptt, &mdump_config); 1970316485Sdavidcs if (rc != ECORE_SUCCESS) 1971316485Sdavidcs return rc; 1972316485Sdavidcs 1973316485Sdavidcs p_mdump_info->version = mdump_config.version; 1974316485Sdavidcs p_mdump_info->config = mdump_config.config; 1975316485Sdavidcs p_mdump_info->epoch = mdump_config.epoc; 1976316485Sdavidcs p_mdump_info->num_of_logs = mdump_config.num_of_logs; 1977316485Sdavidcs p_mdump_info->valid_logs = mdump_config.valid_logs; 1978316485Sdavidcs 1979316485Sdavidcs DP_VERBOSE(p_hwfn, ECORE_MSG_SP, 1980316485Sdavidcs "MFW mdump info: reason %d, version 0x%x, config 0x%x, epoch 0x%x, num_of_logs 0x%x, valid_logs 0x%x\n", 1981316485Sdavidcs p_mdump_info->reason, p_mdump_info->version, 1982316485Sdavidcs p_mdump_info->config, p_mdump_info->epoch, 1983316485Sdavidcs p_mdump_info->num_of_logs, p_mdump_info->valid_logs); 1984316485Sdavidcs } else { 1985316485Sdavidcs DP_VERBOSE(p_hwfn, ECORE_MSG_SP, 1986316485Sdavidcs "MFW mdump info: reason %d\n", p_mdump_info->reason); 1987316485Sdavidcs } 1988316485Sdavidcs 1989316485Sdavidcs return ECORE_SUCCESS; 1990316485Sdavidcs} 1991316485Sdavidcs 1992316485Sdavidcsenum _ecore_status_t ecore_mcp_mdump_clear_logs(struct ecore_hwfn *p_hwfn, 1993316485Sdavidcs struct ecore_ptt *p_ptt) 1994316485Sdavidcs{ 1995316485Sdavidcs struct ecore_mdump_cmd_params mdump_cmd_params; 1996316485Sdavidcs 1997316485Sdavidcs OSAL_MEM_ZERO(&mdump_cmd_params, sizeof(mdump_cmd_params)); 1998316485Sdavidcs mdump_cmd_params.cmd = DRV_MSG_CODE_MDUMP_CLEAR_LOGS; 1999316485Sdavidcs 2000316485Sdavidcs return ecore_mcp_mdump_cmd(p_hwfn, p_ptt, &mdump_cmd_params); 2001316485Sdavidcs} 2002316485Sdavidcs 2003316485Sdavidcsenum _ecore_status_t 2004316485Sdavidcsecore_mcp_mdump_get_retain(struct ecore_hwfn *p_hwfn, struct ecore_ptt *p_ptt, 2005316485Sdavidcs struct ecore_mdump_retain_data *p_mdump_retain) 2006316485Sdavidcs{ 2007316485Sdavidcs struct ecore_mdump_cmd_params mdump_cmd_params; 2008316485Sdavidcs struct mdump_retain_data_stc mfw_mdump_retain; 2009316485Sdavidcs enum _ecore_status_t rc; 2010316485Sdavidcs 2011316485Sdavidcs OSAL_MEM_ZERO(&mdump_cmd_params, sizeof(mdump_cmd_params)); 2012316485Sdavidcs mdump_cmd_params.cmd = DRV_MSG_CODE_MDUMP_GET_RETAIN; 2013316485Sdavidcs mdump_cmd_params.p_data_dst = &mfw_mdump_retain; 2014316485Sdavidcs mdump_cmd_params.data_dst_size = sizeof(mfw_mdump_retain); 2015316485Sdavidcs 2016316485Sdavidcs rc = ecore_mcp_mdump_cmd(p_hwfn, p_ptt, &mdump_cmd_params); 2017316485Sdavidcs if (rc != ECORE_SUCCESS) 2018316485Sdavidcs return rc; 2019316485Sdavidcs 2020316485Sdavidcs if (mdump_cmd_params.mcp_resp != FW_MSG_CODE_OK) { 2021316485Sdavidcs DP_INFO(p_hwfn, 2022316485Sdavidcs "Failed to get the mdump retained data [mcp_resp 0x%x]\n", 2023316485Sdavidcs mdump_cmd_params.mcp_resp); 2024316485Sdavidcs return ECORE_UNKNOWN_ERROR; 2025316485Sdavidcs } 2026316485Sdavidcs 2027316485Sdavidcs p_mdump_retain->valid = mfw_mdump_retain.valid; 2028316485Sdavidcs p_mdump_retain->epoch = mfw_mdump_retain.epoch; 2029316485Sdavidcs p_mdump_retain->pf = mfw_mdump_retain.pf; 2030316485Sdavidcs p_mdump_retain->status = mfw_mdump_retain.status; 2031316485Sdavidcs 2032316485Sdavidcs return ECORE_SUCCESS; 2033316485Sdavidcs} 2034316485Sdavidcs 2035316485Sdavidcsenum _ecore_status_t ecore_mcp_mdump_clr_retain(struct ecore_hwfn *p_hwfn, 2036316485Sdavidcs struct ecore_ptt *p_ptt) 2037316485Sdavidcs{ 2038316485Sdavidcs struct ecore_mdump_cmd_params mdump_cmd_params; 2039316485Sdavidcs 2040316485Sdavidcs OSAL_MEM_ZERO(&mdump_cmd_params, sizeof(mdump_cmd_params)); 2041316485Sdavidcs mdump_cmd_params.cmd = DRV_MSG_CODE_MDUMP_CLR_RETAIN; 2042316485Sdavidcs 2043316485Sdavidcs return ecore_mcp_mdump_cmd(p_hwfn, p_ptt, &mdump_cmd_params); 2044316485Sdavidcs} 2045316485Sdavidcs 2046316485Sdavidcsstatic void ecore_mcp_handle_critical_error(struct ecore_hwfn *p_hwfn, 2047316485Sdavidcs struct ecore_ptt *p_ptt) 2048316485Sdavidcs{ 2049316485Sdavidcs struct ecore_mdump_retain_data mdump_retain; 2050316485Sdavidcs enum _ecore_status_t rc; 2051316485Sdavidcs 2052316485Sdavidcs /* In CMT mode - no need for more than a single acknowledgement to the 2053316485Sdavidcs * MFW, and no more than a single notification to the upper driver. 2054316485Sdavidcs */ 2055316485Sdavidcs if (p_hwfn != ECORE_LEADING_HWFN(p_hwfn->p_dev)) 2056316485Sdavidcs return; 2057316485Sdavidcs 2058316485Sdavidcs rc = ecore_mcp_mdump_get_retain(p_hwfn, p_ptt, &mdump_retain); 2059316485Sdavidcs if (rc == ECORE_SUCCESS && mdump_retain.valid) { 2060316485Sdavidcs DP_NOTICE(p_hwfn, false, 2061316485Sdavidcs "The MFW notified that a critical error occurred in the device [epoch 0x%08x, pf 0x%x, status 0x%08x]\n", 2062316485Sdavidcs mdump_retain.epoch, mdump_retain.pf, 2063316485Sdavidcs mdump_retain.status); 2064316485Sdavidcs } else { 2065316485Sdavidcs DP_NOTICE(p_hwfn, false, 2066316485Sdavidcs "The MFW notified that a critical error occurred in the device\n"); 2067316485Sdavidcs } 2068316485Sdavidcs 2069316485Sdavidcs if (p_hwfn->p_dev->allow_mdump) { 2070316485Sdavidcs DP_NOTICE(p_hwfn, false, 2071316485Sdavidcs "Not acknowledging the notification to allow the MFW crash dump\n"); 2072316485Sdavidcs return; 2073316485Sdavidcs } 2074316485Sdavidcs 2075316485Sdavidcs DP_NOTICE(p_hwfn, false, 2076316485Sdavidcs "Acknowledging the notification to not allow the MFW crash dump [driver debug data collection is preferable]\n"); 2077316485Sdavidcs ecore_mcp_mdump_ack(p_hwfn, p_ptt); 2078316485Sdavidcs ecore_hw_err_notify(p_hwfn, ECORE_HW_ERR_HW_ATTN); 2079316485Sdavidcs} 2080316485Sdavidcs 2081337517Sdavidcsvoid 2082337517Sdavidcsecore_mcp_read_ufp_config(struct ecore_hwfn *p_hwfn, struct ecore_ptt *p_ptt) 2083337517Sdavidcs{ 2084337517Sdavidcs struct public_func shmem_info; 2085337517Sdavidcs u32 port_cfg, val; 2086337517Sdavidcs 2087337517Sdavidcs if (!OSAL_TEST_BIT(ECORE_MF_UFP_SPECIFIC, &p_hwfn->p_dev->mf_bits)) 2088337517Sdavidcs return; 2089337517Sdavidcs 2090337517Sdavidcs OSAL_MEMSET(&p_hwfn->ufp_info, 0, sizeof(p_hwfn->ufp_info)); 2091337517Sdavidcs port_cfg = ecore_rd(p_hwfn, p_ptt, p_hwfn->mcp_info->port_addr + 2092337517Sdavidcs OFFSETOF(struct public_port, oem_cfg_port)); 2093337517Sdavidcs val = GET_MFW_FIELD(port_cfg, OEM_CFG_CHANNEL_TYPE); 2094337517Sdavidcs if (val != OEM_CFG_CHANNEL_TYPE_STAGGED) 2095337517Sdavidcs DP_NOTICE(p_hwfn, false, "Incorrect UFP Channel type %d\n", 2096337517Sdavidcs val); 2097337517Sdavidcs 2098337517Sdavidcs val = GET_MFW_FIELD(port_cfg, OEM_CFG_SCHED_TYPE); 2099337517Sdavidcs if (val == OEM_CFG_SCHED_TYPE_ETS) 2100337517Sdavidcs p_hwfn->ufp_info.mode = ECORE_UFP_MODE_ETS; 2101337517Sdavidcs else if (val == OEM_CFG_SCHED_TYPE_VNIC_BW) 2102337517Sdavidcs p_hwfn->ufp_info.mode = ECORE_UFP_MODE_VNIC_BW; 2103337517Sdavidcs else { 2104337517Sdavidcs p_hwfn->ufp_info.mode = ECORE_UFP_MODE_UNKNOWN; 2105337517Sdavidcs DP_NOTICE(p_hwfn, false, "Unknown UFP scheduling mode %d\n", 2106337517Sdavidcs val); 2107337517Sdavidcs } 2108337517Sdavidcs 2109337517Sdavidcs ecore_mcp_get_shmem_func(p_hwfn, p_ptt, &shmem_info, 2110337517Sdavidcs MCP_PF_ID(p_hwfn)); 2111337517Sdavidcs val = GET_MFW_FIELD(shmem_info.oem_cfg_func, OEM_CFG_FUNC_TC); 2112337517Sdavidcs p_hwfn->ufp_info.tc = (u8)val; 2113337517Sdavidcs val = GET_MFW_FIELD(shmem_info.oem_cfg_func, 2114337517Sdavidcs OEM_CFG_FUNC_HOST_PRI_CTRL); 2115337517Sdavidcs if (val == OEM_CFG_FUNC_HOST_PRI_CTRL_VNIC) 2116337517Sdavidcs p_hwfn->ufp_info.pri_type = ECORE_UFP_PRI_VNIC; 2117337517Sdavidcs else if (val == OEM_CFG_FUNC_HOST_PRI_CTRL_OS) 2118337517Sdavidcs p_hwfn->ufp_info.pri_type = ECORE_UFP_PRI_OS; 2119337517Sdavidcs else { 2120337517Sdavidcs p_hwfn->ufp_info.pri_type = ECORE_UFP_PRI_UNKNOWN; 2121337517Sdavidcs DP_NOTICE(p_hwfn, false, "Unknown Host priority control %d\n", 2122337517Sdavidcs val); 2123337517Sdavidcs } 2124337517Sdavidcs 2125337517Sdavidcs DP_VERBOSE(p_hwfn, ECORE_MSG_DCB, 2126337517Sdavidcs "UFP shmem config: mode = %d tc = %d pri_type = %d\n", 2127337517Sdavidcs p_hwfn->ufp_info.mode, p_hwfn->ufp_info.tc, 2128337517Sdavidcs p_hwfn->ufp_info.pri_type); 2129337517Sdavidcs} 2130337517Sdavidcs 2131337517Sdavidcsstatic enum _ecore_status_t 2132337517Sdavidcsecore_mcp_handle_ufp_event(struct ecore_hwfn *p_hwfn, struct ecore_ptt *p_ptt) 2133337517Sdavidcs{ 2134337517Sdavidcs ecore_mcp_read_ufp_config(p_hwfn, p_ptt); 2135337517Sdavidcs 2136337517Sdavidcs if (p_hwfn->ufp_info.mode == ECORE_UFP_MODE_VNIC_BW) { 2137337517Sdavidcs p_hwfn->qm_info.ooo_tc = p_hwfn->ufp_info.tc; 2138337517Sdavidcs p_hwfn->hw_info.offload_tc = p_hwfn->ufp_info.tc; 2139337517Sdavidcs 2140337517Sdavidcs ecore_qm_reconf(p_hwfn, p_ptt); 2141337517Sdavidcs } else if (p_hwfn->ufp_info.mode == ECORE_UFP_MODE_ETS) { 2142337517Sdavidcs /* Merge UFP TC with the dcbx TC data */ 2143337517Sdavidcs ecore_dcbx_mib_update_event(p_hwfn, p_ptt, 2144337517Sdavidcs ECORE_DCBX_OPERATIONAL_MIB); 2145337517Sdavidcs } else { 2146337517Sdavidcs DP_ERR(p_hwfn, "Invalid sched type, discard the UFP config\n"); 2147337517Sdavidcs return ECORE_INVAL; 2148337517Sdavidcs } 2149337517Sdavidcs 2150337517Sdavidcs /* update storm FW with negotiation results */ 2151337517Sdavidcs ecore_sp_pf_update_ufp(p_hwfn); 2152337517Sdavidcs 2153337517Sdavidcs return ECORE_SUCCESS; 2154337517Sdavidcs} 2155337517Sdavidcs 2156316485Sdavidcsenum _ecore_status_t ecore_mcp_handle_events(struct ecore_hwfn *p_hwfn, 2157316485Sdavidcs struct ecore_ptt *p_ptt) 2158316485Sdavidcs{ 2159316485Sdavidcs struct ecore_mcp_info *info = p_hwfn->mcp_info; 2160316485Sdavidcs enum _ecore_status_t rc = ECORE_SUCCESS; 2161316485Sdavidcs bool found = false; 2162316485Sdavidcs u16 i; 2163316485Sdavidcs 2164316485Sdavidcs DP_VERBOSE(p_hwfn, ECORE_MSG_SP, "Received message from MFW\n"); 2165316485Sdavidcs 2166316485Sdavidcs /* Read Messages from MFW */ 2167316485Sdavidcs ecore_mcp_read_mb(p_hwfn, p_ptt); 2168316485Sdavidcs 2169316485Sdavidcs /* Compare current messages to old ones */ 2170316485Sdavidcs for (i = 0; i < info->mfw_mb_length; i++) { 2171316485Sdavidcs if (info->mfw_mb_cur[i] == info->mfw_mb_shadow[i]) 2172316485Sdavidcs continue; 2173316485Sdavidcs 2174316485Sdavidcs found = true; 2175316485Sdavidcs 2176316485Sdavidcs DP_VERBOSE(p_hwfn, ECORE_MSG_LINK, 2177316485Sdavidcs "Msg [%d] - old CMD 0x%02x, new CMD 0x%02x\n", 2178316485Sdavidcs i, info->mfw_mb_shadow[i], info->mfw_mb_cur[i]); 2179316485Sdavidcs 2180316485Sdavidcs switch (i) { 2181316485Sdavidcs case MFW_DRV_MSG_LINK_CHANGE: 2182316485Sdavidcs ecore_mcp_handle_link_change(p_hwfn, p_ptt, false); 2183316485Sdavidcs break; 2184316485Sdavidcs case MFW_DRV_MSG_VF_DISABLED: 2185316485Sdavidcs ecore_mcp_handle_vf_flr(p_hwfn, p_ptt); 2186316485Sdavidcs break; 2187316485Sdavidcs case MFW_DRV_MSG_LLDP_DATA_UPDATED: 2188316485Sdavidcs ecore_dcbx_mib_update_event(p_hwfn, p_ptt, 2189316485Sdavidcs ECORE_DCBX_REMOTE_LLDP_MIB); 2190316485Sdavidcs break; 2191316485Sdavidcs case MFW_DRV_MSG_DCBX_REMOTE_MIB_UPDATED: 2192316485Sdavidcs ecore_dcbx_mib_update_event(p_hwfn, p_ptt, 2193316485Sdavidcs ECORE_DCBX_REMOTE_MIB); 2194316485Sdavidcs break; 2195316485Sdavidcs case MFW_DRV_MSG_DCBX_OPERATIONAL_MIB_UPDATED: 2196316485Sdavidcs ecore_dcbx_mib_update_event(p_hwfn, p_ptt, 2197316485Sdavidcs ECORE_DCBX_OPERATIONAL_MIB); 2198337517Sdavidcs /* clear the user-config cache */ 2199337517Sdavidcs OSAL_MEMSET(&p_hwfn->p_dcbx_info->set, 0, 2200337517Sdavidcs sizeof(struct ecore_dcbx_set)); 2201316485Sdavidcs break; 2202337517Sdavidcs case MFW_DRV_MSG_LLDP_RECEIVED_TLVS_UPDATED: 2203337517Sdavidcs ecore_lldp_mib_update_event(p_hwfn, p_ptt); 2204337517Sdavidcs break; 2205337517Sdavidcs case MFW_DRV_MSG_OEM_CFG_UPDATE: 2206337517Sdavidcs ecore_mcp_handle_ufp_event(p_hwfn, p_ptt); 2207337517Sdavidcs break; 2208316485Sdavidcs case MFW_DRV_MSG_TRANSCEIVER_STATE_CHANGE: 2209316485Sdavidcs ecore_mcp_handle_transceiver_change(p_hwfn, p_ptt); 2210316485Sdavidcs break; 2211316485Sdavidcs case MFW_DRV_MSG_ERROR_RECOVERY: 2212316485Sdavidcs ecore_mcp_handle_process_kill(p_hwfn, p_ptt); 2213316485Sdavidcs break; 2214316485Sdavidcs case MFW_DRV_MSG_GET_LAN_STATS: 2215316485Sdavidcs case MFW_DRV_MSG_GET_FCOE_STATS: 2216316485Sdavidcs case MFW_DRV_MSG_GET_ISCSI_STATS: 2217316485Sdavidcs case MFW_DRV_MSG_GET_RDMA_STATS: 2218316485Sdavidcs ecore_mcp_send_protocol_stats(p_hwfn, p_ptt, i); 2219316485Sdavidcs break; 2220316485Sdavidcs case MFW_DRV_MSG_BW_UPDATE: 2221316485Sdavidcs ecore_mcp_update_bw(p_hwfn, p_ptt); 2222316485Sdavidcs break; 2223316485Sdavidcs case MFW_DRV_MSG_S_TAG_UPDATE: 2224316485Sdavidcs ecore_mcp_update_stag(p_hwfn, p_ptt); 2225316485Sdavidcs break; 2226316485Sdavidcs case MFW_DRV_MSG_FAILURE_DETECTED: 2227320164Sdavidcs ecore_mcp_handle_fan_failure(p_hwfn); 2228316485Sdavidcs break; 2229316485Sdavidcs case MFW_DRV_MSG_CRITICAL_ERROR_OCCURRED: 2230316485Sdavidcs ecore_mcp_handle_critical_error(p_hwfn, p_ptt); 2231316485Sdavidcs break; 2232316485Sdavidcs case MFW_DRV_MSG_GET_TLV_REQ: 2233316485Sdavidcs OSAL_MFW_TLV_REQ(p_hwfn); 2234316485Sdavidcs break; 2235316485Sdavidcs default: 2236316485Sdavidcs DP_INFO(p_hwfn, "Unimplemented MFW message %d\n", i); 2237316485Sdavidcs rc = ECORE_INVAL; 2238316485Sdavidcs } 2239316485Sdavidcs } 2240316485Sdavidcs 2241316485Sdavidcs /* ACK everything */ 2242316485Sdavidcs for (i = 0; i < MFW_DRV_MSG_MAX_DWORDS(info->mfw_mb_length); i++) { 2243316485Sdavidcs OSAL_BE32 val = OSAL_CPU_TO_BE32(((u32 *)info->mfw_mb_cur)[i]); 2244316485Sdavidcs 2245316485Sdavidcs /* MFW expect answer in BE, so we force write in that format */ 2246316485Sdavidcs ecore_wr(p_hwfn, p_ptt, 2247316485Sdavidcs info->mfw_mb_addr + sizeof(u32) + 2248316485Sdavidcs MFW_DRV_MSG_MAX_DWORDS(info->mfw_mb_length) * 2249316485Sdavidcs sizeof(u32) + i * sizeof(u32), val); 2250316485Sdavidcs } 2251316485Sdavidcs 2252316485Sdavidcs if (!found) { 2253337517Sdavidcs DP_INFO(p_hwfn, 2254337517Sdavidcs "Received an MFW message indication but no new message!\n"); 2255316485Sdavidcs rc = ECORE_INVAL; 2256316485Sdavidcs } 2257316485Sdavidcs 2258316485Sdavidcs /* Copy the new mfw messages into the shadow */ 2259316485Sdavidcs OSAL_MEMCPY(info->mfw_mb_shadow, info->mfw_mb_cur, info->mfw_mb_length); 2260316485Sdavidcs 2261316485Sdavidcs return rc; 2262316485Sdavidcs} 2263316485Sdavidcs 2264316485Sdavidcsenum _ecore_status_t ecore_mcp_get_mfw_ver(struct ecore_hwfn *p_hwfn, 2265316485Sdavidcs struct ecore_ptt *p_ptt, 2266316485Sdavidcs u32 *p_mfw_ver, 2267316485Sdavidcs u32 *p_running_bundle_id) 2268316485Sdavidcs{ 2269316485Sdavidcs u32 global_offsize; 2270316485Sdavidcs 2271316485Sdavidcs#ifndef ASIC_ONLY 2272316485Sdavidcs if (CHIP_REV_IS_EMUL(p_hwfn->p_dev)) { 2273316485Sdavidcs DP_NOTICE(p_hwfn, false, "Emulation - can't get MFW version\n"); 2274316485Sdavidcs return ECORE_SUCCESS; 2275316485Sdavidcs } 2276316485Sdavidcs#endif 2277316485Sdavidcs 2278316485Sdavidcs if (IS_VF(p_hwfn->p_dev)) { 2279316485Sdavidcs if (p_hwfn->vf_iov_info) { 2280316485Sdavidcs struct pfvf_acquire_resp_tlv *p_resp; 2281316485Sdavidcs 2282316485Sdavidcs p_resp = &p_hwfn->vf_iov_info->acquire_resp; 2283316485Sdavidcs *p_mfw_ver = p_resp->pfdev_info.mfw_ver; 2284316485Sdavidcs return ECORE_SUCCESS; 2285316485Sdavidcs } else { 2286316485Sdavidcs DP_VERBOSE(p_hwfn, ECORE_MSG_IOV, 2287316485Sdavidcs "VF requested MFW version prior to ACQUIRE\n"); 2288316485Sdavidcs return ECORE_INVAL; 2289316485Sdavidcs } 2290316485Sdavidcs } 2291316485Sdavidcs 2292316485Sdavidcs global_offsize = ecore_rd(p_hwfn, p_ptt, 2293316485Sdavidcs SECTION_OFFSIZE_ADDR(p_hwfn->mcp_info->public_base, 2294316485Sdavidcs PUBLIC_GLOBAL)); 2295316485Sdavidcs *p_mfw_ver = ecore_rd(p_hwfn, p_ptt, 2296316485Sdavidcs SECTION_ADDR(global_offsize, 0) + 2297316485Sdavidcs OFFSETOF(struct public_global, mfw_ver)); 2298316485Sdavidcs 2299316485Sdavidcs if (p_running_bundle_id != OSAL_NULL) { 2300316485Sdavidcs *p_running_bundle_id = ecore_rd(p_hwfn, p_ptt, 2301316485Sdavidcs SECTION_ADDR(global_offsize, 0) + 2302316485Sdavidcs OFFSETOF(struct public_global, 2303316485Sdavidcs running_bundle_id)); 2304316485Sdavidcs } 2305316485Sdavidcs 2306316485Sdavidcs return ECORE_SUCCESS; 2307316485Sdavidcs} 2308316485Sdavidcs 2309316485Sdavidcsenum _ecore_status_t ecore_mcp_get_mbi_ver(struct ecore_hwfn *p_hwfn, 2310316485Sdavidcs struct ecore_ptt *p_ptt, 2311316485Sdavidcs u32 *p_mbi_ver) 2312316485Sdavidcs{ 2313316485Sdavidcs u32 nvm_cfg_addr, nvm_cfg1_offset, mbi_ver_addr; 2314316485Sdavidcs 2315316485Sdavidcs#ifndef ASIC_ONLY 2316316485Sdavidcs if (CHIP_REV_IS_EMUL(p_hwfn->p_dev)) { 2317316485Sdavidcs DP_NOTICE(p_hwfn, false, "Emulation - can't get MBI version\n"); 2318316485Sdavidcs return ECORE_SUCCESS; 2319316485Sdavidcs } 2320316485Sdavidcs#endif 2321316485Sdavidcs 2322316485Sdavidcs if (IS_VF(p_hwfn->p_dev)) 2323316485Sdavidcs return ECORE_INVAL; 2324316485Sdavidcs 2325316485Sdavidcs /* Read the address of the nvm_cfg */ 2326316485Sdavidcs nvm_cfg_addr = ecore_rd(p_hwfn, p_ptt, MISC_REG_GEN_PURP_CR0); 2327316485Sdavidcs if (!nvm_cfg_addr) { 2328316485Sdavidcs DP_NOTICE(p_hwfn, false, "Shared memory not initialized\n"); 2329316485Sdavidcs return ECORE_INVAL; 2330316485Sdavidcs } 2331316485Sdavidcs 2332316485Sdavidcs /* Read the offset of nvm_cfg1 */ 2333316485Sdavidcs nvm_cfg1_offset = ecore_rd(p_hwfn, p_ptt, nvm_cfg_addr + 4); 2334316485Sdavidcs 2335316485Sdavidcs mbi_ver_addr = MCP_REG_SCRATCH + nvm_cfg1_offset + 2336316485Sdavidcs OFFSETOF(struct nvm_cfg1, glob) + 2337316485Sdavidcs OFFSETOF(struct nvm_cfg1_glob, mbi_version); 2338316485Sdavidcs *p_mbi_ver = ecore_rd(p_hwfn, p_ptt, mbi_ver_addr) & 2339316485Sdavidcs (NVM_CFG1_GLOB_MBI_VERSION_0_MASK | 2340316485Sdavidcs NVM_CFG1_GLOB_MBI_VERSION_1_MASK | 2341316485Sdavidcs NVM_CFG1_GLOB_MBI_VERSION_2_MASK); 2342316485Sdavidcs 2343316485Sdavidcs return ECORE_SUCCESS; 2344316485Sdavidcs} 2345316485Sdavidcs 2346337517Sdavidcsenum _ecore_status_t ecore_mcp_get_media_type(struct ecore_hwfn *p_hwfn, 2347337517Sdavidcs struct ecore_ptt *p_ptt, 2348337517Sdavidcs u32 *p_media_type) 2349316485Sdavidcs{ 2350316485Sdavidcs 2351316485Sdavidcs /* TODO - Add support for VFs */ 2352337517Sdavidcs if (IS_VF(p_hwfn->p_dev)) 2353316485Sdavidcs return ECORE_INVAL; 2354316485Sdavidcs 2355316485Sdavidcs if (!ecore_mcp_is_init(p_hwfn)) { 2356337517Sdavidcs DP_NOTICE(p_hwfn, false, "MFW is not initialized!\n"); 2357316485Sdavidcs return ECORE_BUSY; 2358316485Sdavidcs } 2359337517Sdavidcs if (!p_ptt) { 2360337517Sdavidcs *p_media_type = MEDIA_UNSPECIFIED; 2361337517Sdavidcs return ECORE_INVAL; 2362337517Sdavidcs } else { 2363337517Sdavidcs *p_media_type = ecore_rd(p_hwfn, p_ptt, 2364337517Sdavidcs p_hwfn->mcp_info->port_addr + 2365337517Sdavidcs OFFSETOF(struct public_port, 2366337517Sdavidcs media_type)); 2367337517Sdavidcs } 2368316485Sdavidcs 2369337517Sdavidcs return ECORE_SUCCESS; 2370337517Sdavidcs} 2371316485Sdavidcs 2372337517Sdavidcsenum _ecore_status_t ecore_mcp_get_transceiver_data(struct ecore_hwfn *p_hwfn, 2373337517Sdavidcs struct ecore_ptt *p_ptt, 2374337517Sdavidcs u32 *p_tranceiver_type) 2375337517Sdavidcs{ 2376337517Sdavidcs /* TODO - Add support for VFs */ 2377337517Sdavidcs if (IS_VF(p_hwfn->p_dev)) 2378337517Sdavidcs return ECORE_INVAL; 2379337517Sdavidcs 2380337517Sdavidcs if (!ecore_mcp_is_init(p_hwfn)) { 2381337517Sdavidcs DP_NOTICE(p_hwfn, false, "MFW is not initialized!\n"); 2382316485Sdavidcs return ECORE_BUSY; 2383337517Sdavidcs } 2384337517Sdavidcs if (!p_ptt) { 2385337517Sdavidcs *p_tranceiver_type = ETH_TRANSCEIVER_TYPE_NONE; 2386337517Sdavidcs return ECORE_INVAL; 2387337517Sdavidcs } else { 2388337517Sdavidcs *p_tranceiver_type = ecore_rd(p_hwfn, p_ptt, 2389337517Sdavidcs p_hwfn->mcp_info->port_addr + 2390337517Sdavidcs offsetof(struct public_port, 2391337517Sdavidcs transceiver_data)); 2392337517Sdavidcs } 2393316485Sdavidcs 2394337517Sdavidcs return 0; 2395337517Sdavidcs} 2396316485Sdavidcs 2397337517Sdavidcsstatic int is_transceiver_ready(u32 transceiver_state, u32 transceiver_type) 2398337517Sdavidcs{ 2399316485Sdavidcs 2400337517Sdavidcs if ((transceiver_state & ETH_TRANSCEIVER_STATE_PRESENT) && 2401337517Sdavidcs ((transceiver_state & ETH_TRANSCEIVER_STATE_UPDATING) == 0x0) && 2402337517Sdavidcs (transceiver_type != ETH_TRANSCEIVER_TYPE_NONE)) { 2403337517Sdavidcs return 1; 2404337517Sdavidcs } 2405337517Sdavidcs 2406337517Sdavidcs return 0; 2407337517Sdavidcs} 2408337517Sdavidcs 2409337517Sdavidcsenum _ecore_status_t ecore_mcp_trans_speed_mask(struct ecore_hwfn *p_hwfn, 2410337517Sdavidcs struct ecore_ptt *p_ptt, 2411337517Sdavidcs u32 *p_speed_mask) 2412337517Sdavidcs{ 2413337517Sdavidcs u32 transceiver_data, transceiver_type, transceiver_state; 2414337517Sdavidcs 2415337517Sdavidcs ecore_mcp_get_transceiver_data(p_hwfn, p_ptt, &transceiver_data); 2416337517Sdavidcs 2417337517Sdavidcs transceiver_state = GET_MFW_FIELD(transceiver_data, 2418337517Sdavidcs ETH_TRANSCEIVER_STATE); 2419337517Sdavidcs 2420337517Sdavidcs transceiver_type = GET_MFW_FIELD(transceiver_data, 2421337517Sdavidcs ETH_TRANSCEIVER_TYPE); 2422337517Sdavidcs 2423337517Sdavidcs if (is_transceiver_ready(transceiver_state, transceiver_type) == 0) { 2424337517Sdavidcs return ECORE_INVAL; 2425337517Sdavidcs } 2426337517Sdavidcs 2427337517Sdavidcs switch (transceiver_type) { 2428337517Sdavidcs case ETH_TRANSCEIVER_TYPE_1G_LX: 2429337517Sdavidcs case ETH_TRANSCEIVER_TYPE_1G_SX: 2430337517Sdavidcs case ETH_TRANSCEIVER_TYPE_1G_PCC: 2431337517Sdavidcs case ETH_TRANSCEIVER_TYPE_1G_ACC: 2432337517Sdavidcs case ETH_TRANSCEIVER_TYPE_1000BASET: 2433337517Sdavidcs *p_speed_mask = NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G; 2434337517Sdavidcs break; 2435337517Sdavidcs 2436337517Sdavidcs case ETH_TRANSCEIVER_TYPE_10G_SR: 2437337517Sdavidcs case ETH_TRANSCEIVER_TYPE_10G_LR: 2438337517Sdavidcs case ETH_TRANSCEIVER_TYPE_10G_LRM: 2439337517Sdavidcs case ETH_TRANSCEIVER_TYPE_10G_ER: 2440337517Sdavidcs case ETH_TRANSCEIVER_TYPE_10G_PCC: 2441337517Sdavidcs case ETH_TRANSCEIVER_TYPE_10G_ACC: 2442337517Sdavidcs case ETH_TRANSCEIVER_TYPE_4x10G: 2443337517Sdavidcs *p_speed_mask = NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G; 2444337517Sdavidcs break; 2445337517Sdavidcs 2446337517Sdavidcs case ETH_TRANSCEIVER_TYPE_40G_LR4: 2447337517Sdavidcs case ETH_TRANSCEIVER_TYPE_40G_SR4: 2448337517Sdavidcs case ETH_TRANSCEIVER_TYPE_MULTI_RATE_10G_40G_SR: 2449337517Sdavidcs case ETH_TRANSCEIVER_TYPE_MULTI_RATE_10G_40G_LR: 2450337517Sdavidcs *p_speed_mask = NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_40G | 2451337517Sdavidcs NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G; 2452337517Sdavidcs break; 2453337517Sdavidcs 2454337517Sdavidcs case ETH_TRANSCEIVER_TYPE_100G_AOC: 2455337517Sdavidcs case ETH_TRANSCEIVER_TYPE_100G_SR4: 2456337517Sdavidcs case ETH_TRANSCEIVER_TYPE_100G_LR4: 2457337517Sdavidcs case ETH_TRANSCEIVER_TYPE_100G_ER4: 2458337517Sdavidcs case ETH_TRANSCEIVER_TYPE_100G_ACC: 2459337517Sdavidcs *p_speed_mask = 2460337517Sdavidcs NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_BB_100G | 2461337517Sdavidcs NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_25G; 2462337517Sdavidcs break; 2463337517Sdavidcs 2464337517Sdavidcs case ETH_TRANSCEIVER_TYPE_25G_SR: 2465337517Sdavidcs case ETH_TRANSCEIVER_TYPE_25G_LR: 2466337517Sdavidcs case ETH_TRANSCEIVER_TYPE_25G_AOC: 2467337517Sdavidcs case ETH_TRANSCEIVER_TYPE_25G_ACC_S: 2468337517Sdavidcs case ETH_TRANSCEIVER_TYPE_25G_ACC_M: 2469337517Sdavidcs case ETH_TRANSCEIVER_TYPE_25G_ACC_L: 2470337517Sdavidcs *p_speed_mask = NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_25G; 2471337517Sdavidcs break; 2472337517Sdavidcs 2473337517Sdavidcs case ETH_TRANSCEIVER_TYPE_25G_CA_N: 2474337517Sdavidcs case ETH_TRANSCEIVER_TYPE_25G_CA_S: 2475337517Sdavidcs case ETH_TRANSCEIVER_TYPE_25G_CA_L: 2476337517Sdavidcs case ETH_TRANSCEIVER_TYPE_4x25G_CR: 2477337517Sdavidcs *p_speed_mask = NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_25G | 2478337517Sdavidcs NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G | 2479337517Sdavidcs NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G; 2480337517Sdavidcs break; 2481337517Sdavidcs 2482337517Sdavidcs case ETH_TRANSCEIVER_TYPE_40G_CR4: 2483337517Sdavidcs case ETH_TRANSCEIVER_TYPE_MULTI_RATE_10G_40G_CR: 2484337517Sdavidcs *p_speed_mask = NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_40G | 2485337517Sdavidcs NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G | 2486337517Sdavidcs NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G; 2487337517Sdavidcs break; 2488337517Sdavidcs 2489337517Sdavidcs case ETH_TRANSCEIVER_TYPE_100G_CR4: 2490337517Sdavidcs case ETH_TRANSCEIVER_TYPE_MULTI_RATE_40G_100G_CR: 2491337517Sdavidcs *p_speed_mask = 2492337517Sdavidcs NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_BB_100G | 2493337517Sdavidcs NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_50G | 2494337517Sdavidcs NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_40G | 2495337517Sdavidcs NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_25G | 2496337517Sdavidcs NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_20G | 2497337517Sdavidcs NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G | 2498337517Sdavidcs NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G; 2499337517Sdavidcs break; 2500337517Sdavidcs 2501337517Sdavidcs case ETH_TRANSCEIVER_TYPE_MULTI_RATE_40G_100G_SR: 2502337517Sdavidcs case ETH_TRANSCEIVER_TYPE_MULTI_RATE_40G_100G_LR: 2503337517Sdavidcs case ETH_TRANSCEIVER_TYPE_MULTI_RATE_40G_100G_AOC: 2504337517Sdavidcs *p_speed_mask = 2505337517Sdavidcs NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_BB_100G | 2506337517Sdavidcs NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_40G | 2507337517Sdavidcs NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_25G | 2508337517Sdavidcs NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G; 2509337517Sdavidcs break; 2510337517Sdavidcs 2511337517Sdavidcs case ETH_TRANSCEIVER_TYPE_XLPPI: 2512337517Sdavidcs *p_speed_mask = NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_40G; 2513337517Sdavidcs break; 2514337517Sdavidcs 2515337517Sdavidcs case ETH_TRANSCEIVER_TYPE_10G_BASET: 2516337517Sdavidcs *p_speed_mask = NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_10G | 2517337517Sdavidcs NVM_CFG1_PORT_DRV_SPEED_CAPABILITY_MASK_1G; 2518337517Sdavidcs break; 2519337517Sdavidcs 2520337517Sdavidcs default: 2521337517Sdavidcs DP_INFO(p_hwfn, "Unknown transcevier type 0x%x\n", 2522337517Sdavidcs transceiver_type); 2523337517Sdavidcs *p_speed_mask = 0xff; 2524337517Sdavidcs break; 2525337517Sdavidcs } 2526337517Sdavidcs 2527316485Sdavidcs return ECORE_SUCCESS; 2528316485Sdavidcs} 2529316485Sdavidcs 2530337517Sdavidcsenum _ecore_status_t ecore_mcp_get_board_config(struct ecore_hwfn *p_hwfn, 2531337517Sdavidcs struct ecore_ptt *p_ptt, 2532337517Sdavidcs u32 *p_board_config) 2533337517Sdavidcs{ 2534337517Sdavidcs u32 nvm_cfg_addr, nvm_cfg1_offset, port_cfg_addr; 2535337517Sdavidcs 2536337517Sdavidcs /* TODO - Add support for VFs */ 2537337517Sdavidcs if (IS_VF(p_hwfn->p_dev)) 2538337517Sdavidcs return ECORE_INVAL; 2539337517Sdavidcs 2540337517Sdavidcs if (!ecore_mcp_is_init(p_hwfn)) { 2541337517Sdavidcs DP_NOTICE(p_hwfn, false, "MFW is not initialized!\n"); 2542337517Sdavidcs return ECORE_BUSY; 2543337517Sdavidcs } 2544337517Sdavidcs if (!p_ptt) { 2545337517Sdavidcs *p_board_config = NVM_CFG1_PORT_PORT_TYPE_UNDEFINED; 2546337517Sdavidcs return ECORE_INVAL; 2547337517Sdavidcs } else { 2548337517Sdavidcs 2549337517Sdavidcs nvm_cfg_addr = ecore_rd(p_hwfn, p_ptt, 2550337517Sdavidcs MISC_REG_GEN_PURP_CR0); 2551337517Sdavidcs nvm_cfg1_offset = ecore_rd(p_hwfn, p_ptt, 2552337517Sdavidcs nvm_cfg_addr + 4); 2553337517Sdavidcs port_cfg_addr = MCP_REG_SCRATCH + nvm_cfg1_offset + 2554337517Sdavidcs offsetof(struct nvm_cfg1, port[MFW_PORT(p_hwfn)]); 2555337517Sdavidcs *p_board_config = ecore_rd(p_hwfn, p_ptt, 2556337517Sdavidcs port_cfg_addr + 2557337517Sdavidcs offsetof(struct nvm_cfg1_port, 2558337517Sdavidcs board_cfg)); 2559337517Sdavidcs } 2560337517Sdavidcs 2561337517Sdavidcs return ECORE_SUCCESS; 2562337517Sdavidcs} 2563337517Sdavidcs 2564316485Sdavidcs/* Old MFW has a global configuration for all PFs regarding RDMA support */ 2565316485Sdavidcsstatic void 2566316485Sdavidcsecore_mcp_get_shmem_proto_legacy(struct ecore_hwfn *p_hwfn, 2567316485Sdavidcs enum ecore_pci_personality *p_proto) 2568316485Sdavidcs{ 2569316485Sdavidcs /* There wasn't ever a legacy MFW that published iwarp. 2570316485Sdavidcs * So at this point, this is either plain l2 or RoCE. 2571316485Sdavidcs */ 2572316485Sdavidcs if (OSAL_TEST_BIT(ECORE_DEV_CAP_ROCE, 2573316485Sdavidcs &p_hwfn->hw_info.device_capabilities)) 2574316485Sdavidcs *p_proto = ECORE_PCI_ETH_ROCE; 2575316485Sdavidcs else 2576316485Sdavidcs *p_proto = ECORE_PCI_ETH; 2577316485Sdavidcs 2578316485Sdavidcs DP_VERBOSE(p_hwfn, ECORE_MSG_IFUP, 2579316485Sdavidcs "According to Legacy capabilities, L2 personality is %08x\n", 2580316485Sdavidcs (u32) *p_proto); 2581316485Sdavidcs} 2582316485Sdavidcs 2583316485Sdavidcsstatic enum _ecore_status_t 2584316485Sdavidcsecore_mcp_get_shmem_proto_mfw(struct ecore_hwfn *p_hwfn, 2585316485Sdavidcs struct ecore_ptt *p_ptt, 2586316485Sdavidcs enum ecore_pci_personality *p_proto) 2587316485Sdavidcs{ 2588316485Sdavidcs u32 resp = 0, param = 0; 2589316485Sdavidcs enum _ecore_status_t rc; 2590316485Sdavidcs 2591316485Sdavidcs rc = ecore_mcp_cmd(p_hwfn, p_ptt, 2592316485Sdavidcs DRV_MSG_CODE_GET_PF_RDMA_PROTOCOL, 0, &resp, ¶m); 2593316485Sdavidcs if (rc != ECORE_SUCCESS) 2594316485Sdavidcs return rc; 2595316485Sdavidcs if (resp != FW_MSG_CODE_OK) { 2596316485Sdavidcs DP_VERBOSE(p_hwfn, ECORE_MSG_IFUP, 2597316485Sdavidcs "MFW lacks support for command; Returns %08x\n", 2598316485Sdavidcs resp); 2599316485Sdavidcs return ECORE_INVAL; 2600316485Sdavidcs } 2601316485Sdavidcs 2602316485Sdavidcs switch (param) { 2603316485Sdavidcs case FW_MB_PARAM_GET_PF_RDMA_NONE: 2604316485Sdavidcs *p_proto = ECORE_PCI_ETH; 2605316485Sdavidcs break; 2606316485Sdavidcs case FW_MB_PARAM_GET_PF_RDMA_ROCE: 2607316485Sdavidcs *p_proto = ECORE_PCI_ETH_ROCE; 2608316485Sdavidcs break; 2609316485Sdavidcs case FW_MB_PARAM_GET_PF_RDMA_IWARP: 2610316485Sdavidcs *p_proto = ECORE_PCI_ETH_IWARP; 2611316485Sdavidcs break; 2612316485Sdavidcs case FW_MB_PARAM_GET_PF_RDMA_BOTH: 2613316485Sdavidcs *p_proto = ECORE_PCI_ETH_RDMA; 2614316485Sdavidcs break; 2615316485Sdavidcs default: 2616316485Sdavidcs DP_NOTICE(p_hwfn, true, 2617316485Sdavidcs "MFW answers GET_PF_RDMA_PROTOCOL but param is %08x\n", 2618316485Sdavidcs param); 2619316485Sdavidcs return ECORE_INVAL; 2620316485Sdavidcs } 2621316485Sdavidcs 2622316485Sdavidcs DP_VERBOSE(p_hwfn, ECORE_MSG_IFUP, 2623316485Sdavidcs "According to capabilities, L2 personality is %08x [resp %08x param %08x]\n", 2624316485Sdavidcs (u32) *p_proto, resp, param); 2625316485Sdavidcs return ECORE_SUCCESS; 2626316485Sdavidcs} 2627316485Sdavidcs 2628316485Sdavidcsstatic enum _ecore_status_t 2629316485Sdavidcsecore_mcp_get_shmem_proto(struct ecore_hwfn *p_hwfn, 2630316485Sdavidcs struct public_func *p_info, 2631316485Sdavidcs struct ecore_ptt *p_ptt, 2632316485Sdavidcs enum ecore_pci_personality *p_proto) 2633316485Sdavidcs{ 2634316485Sdavidcs enum _ecore_status_t rc = ECORE_SUCCESS; 2635316485Sdavidcs 2636316485Sdavidcs switch (p_info->config & FUNC_MF_CFG_PROTOCOL_MASK) { 2637316485Sdavidcs case FUNC_MF_CFG_PROTOCOL_ETHERNET: 2638316485Sdavidcs if (ecore_mcp_get_shmem_proto_mfw(p_hwfn, p_ptt, p_proto) != 2639316485Sdavidcs ECORE_SUCCESS) 2640316485Sdavidcs ecore_mcp_get_shmem_proto_legacy(p_hwfn, p_proto); 2641316485Sdavidcs break; 2642316485Sdavidcs case FUNC_MF_CFG_PROTOCOL_ISCSI: 2643316485Sdavidcs *p_proto = ECORE_PCI_ISCSI; 2644316485Sdavidcs break; 2645316485Sdavidcs case FUNC_MF_CFG_PROTOCOL_FCOE: 2646316485Sdavidcs *p_proto = ECORE_PCI_FCOE; 2647316485Sdavidcs break; 2648316485Sdavidcs case FUNC_MF_CFG_PROTOCOL_ROCE: 2649316485Sdavidcs DP_NOTICE(p_hwfn, true, "RoCE personality is not a valid value!\n"); 2650320164Sdavidcs /* Fallthrough */ 2651316485Sdavidcs default: 2652316485Sdavidcs rc = ECORE_INVAL; 2653316485Sdavidcs } 2654316485Sdavidcs 2655316485Sdavidcs return rc; 2656316485Sdavidcs} 2657316485Sdavidcs 2658316485Sdavidcsenum _ecore_status_t ecore_mcp_fill_shmem_func_info(struct ecore_hwfn *p_hwfn, 2659316485Sdavidcs struct ecore_ptt *p_ptt) 2660316485Sdavidcs{ 2661316485Sdavidcs struct ecore_mcp_function_info *info; 2662316485Sdavidcs struct public_func shmem_info; 2663316485Sdavidcs 2664316485Sdavidcs ecore_mcp_get_shmem_func(p_hwfn, p_ptt, &shmem_info, 2665316485Sdavidcs MCP_PF_ID(p_hwfn)); 2666316485Sdavidcs info = &p_hwfn->mcp_info->func_info; 2667316485Sdavidcs 2668316485Sdavidcs info->pause_on_host = (shmem_info.config & 2669316485Sdavidcs FUNC_MF_CFG_PAUSE_ON_HOST_RING) ? 1 : 0; 2670316485Sdavidcs 2671316485Sdavidcs if (ecore_mcp_get_shmem_proto(p_hwfn, &shmem_info, p_ptt, 2672316485Sdavidcs &info->protocol)) { 2673316485Sdavidcs DP_ERR(p_hwfn, "Unknown personality %08x\n", 2674316485Sdavidcs (u32)(shmem_info.config & FUNC_MF_CFG_PROTOCOL_MASK)); 2675316485Sdavidcs return ECORE_INVAL; 2676316485Sdavidcs } 2677316485Sdavidcs 2678316485Sdavidcs ecore_read_pf_bandwidth(p_hwfn, &shmem_info); 2679316485Sdavidcs 2680316485Sdavidcs if (shmem_info.mac_upper || shmem_info.mac_lower) { 2681316485Sdavidcs info->mac[0] = (u8)(shmem_info.mac_upper >> 8); 2682316485Sdavidcs info->mac[1] = (u8)(shmem_info.mac_upper); 2683316485Sdavidcs info->mac[2] = (u8)(shmem_info.mac_lower >> 24); 2684316485Sdavidcs info->mac[3] = (u8)(shmem_info.mac_lower >> 16); 2685316485Sdavidcs info->mac[4] = (u8)(shmem_info.mac_lower >> 8); 2686316485Sdavidcs info->mac[5] = (u8)(shmem_info.mac_lower); 2687316485Sdavidcs 2688316485Sdavidcs /* Store primary MAC for later possible WoL */ 2689316485Sdavidcs OSAL_MEMCPY(&p_hwfn->p_dev->wol_mac, info->mac, ETH_ALEN); 2690316485Sdavidcs 2691316485Sdavidcs } else { 2692316485Sdavidcs /* TODO - are there protocols for which there's no MAC? */ 2693316485Sdavidcs DP_NOTICE(p_hwfn, false, "MAC is 0 in shmem\n"); 2694316485Sdavidcs } 2695316485Sdavidcs 2696316485Sdavidcs /* TODO - are these calculations true for BE machine? */ 2697320164Sdavidcs info->wwn_port = (u64)shmem_info.fcoe_wwn_port_name_lower | 2698320164Sdavidcs (((u64)shmem_info.fcoe_wwn_port_name_upper) << 32); 2699320164Sdavidcs info->wwn_node = (u64)shmem_info.fcoe_wwn_node_name_lower | 2700320164Sdavidcs (((u64)shmem_info.fcoe_wwn_node_name_upper) << 32); 2701316485Sdavidcs 2702316485Sdavidcs info->ovlan = (u16)(shmem_info.ovlan_stag & FUNC_MF_CFG_OV_STAG_MASK); 2703316485Sdavidcs 2704316485Sdavidcs info->mtu = (u16)shmem_info.mtu_size; 2705316485Sdavidcs 2706316485Sdavidcs p_hwfn->hw_info.b_wol_support = ECORE_WOL_SUPPORT_NONE; 2707320164Sdavidcs p_hwfn->p_dev->wol_config = (u8)ECORE_OV_WOL_DEFAULT; 2708316485Sdavidcs if (ecore_mcp_is_init(p_hwfn)) { 2709316485Sdavidcs u32 resp = 0, param = 0; 2710316485Sdavidcs enum _ecore_status_t rc; 2711316485Sdavidcs 2712316485Sdavidcs rc = ecore_mcp_cmd(p_hwfn, p_ptt, 2713316485Sdavidcs DRV_MSG_CODE_OS_WOL, 0, &resp, ¶m); 2714316485Sdavidcs if (rc != ECORE_SUCCESS) 2715316485Sdavidcs return rc; 2716316485Sdavidcs if (resp == FW_MSG_CODE_OS_WOL_SUPPORTED) 2717316485Sdavidcs p_hwfn->hw_info.b_wol_support = ECORE_WOL_SUPPORT_PME; 2718316485Sdavidcs } 2719316485Sdavidcs 2720316485Sdavidcs DP_VERBOSE(p_hwfn, (ECORE_MSG_SP | ECORE_MSG_IFUP), 2721316485Sdavidcs "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", 2722316485Sdavidcs info->pause_on_host, info->protocol, 2723316485Sdavidcs info->bandwidth_min, info->bandwidth_max, 2724316485Sdavidcs info->mac[0], info->mac[1], info->mac[2], 2725316485Sdavidcs info->mac[3], info->mac[4], info->mac[5], 2726316485Sdavidcs (unsigned long long)info->wwn_port, (unsigned long long)info->wwn_node, info->ovlan, 2727316485Sdavidcs (u8)p_hwfn->hw_info.b_wol_support); 2728316485Sdavidcs 2729316485Sdavidcs return ECORE_SUCCESS; 2730316485Sdavidcs} 2731316485Sdavidcs 2732316485Sdavidcsstruct ecore_mcp_link_params 2733316485Sdavidcs*ecore_mcp_get_link_params(struct ecore_hwfn *p_hwfn) 2734316485Sdavidcs{ 2735316485Sdavidcs if (!p_hwfn || !p_hwfn->mcp_info) 2736316485Sdavidcs return OSAL_NULL; 2737316485Sdavidcs return &p_hwfn->mcp_info->link_input; 2738316485Sdavidcs} 2739316485Sdavidcs 2740316485Sdavidcsstruct ecore_mcp_link_state 2741316485Sdavidcs*ecore_mcp_get_link_state(struct ecore_hwfn *p_hwfn) 2742316485Sdavidcs{ 2743316485Sdavidcs if (!p_hwfn || !p_hwfn->mcp_info) 2744316485Sdavidcs return OSAL_NULL; 2745316485Sdavidcs 2746316485Sdavidcs#ifndef ASIC_ONLY 2747316485Sdavidcs if (CHIP_REV_IS_SLOW(p_hwfn->p_dev)) { 2748316485Sdavidcs DP_INFO(p_hwfn, "Non-ASIC - always notify that link is up\n"); 2749316485Sdavidcs p_hwfn->mcp_info->link_output.link_up = true; 2750316485Sdavidcs } 2751316485Sdavidcs#endif 2752316485Sdavidcs 2753316485Sdavidcs return &p_hwfn->mcp_info->link_output; 2754316485Sdavidcs} 2755316485Sdavidcs 2756316485Sdavidcsstruct ecore_mcp_link_capabilities 2757316485Sdavidcs*ecore_mcp_get_link_capabilities(struct ecore_hwfn *p_hwfn) 2758316485Sdavidcs{ 2759316485Sdavidcs if (!p_hwfn || !p_hwfn->mcp_info) 2760316485Sdavidcs return OSAL_NULL; 2761316485Sdavidcs return &p_hwfn->mcp_info->link_capabilities; 2762316485Sdavidcs} 2763316485Sdavidcs 2764316485Sdavidcsenum _ecore_status_t ecore_mcp_drain(struct ecore_hwfn *p_hwfn, 2765316485Sdavidcs struct ecore_ptt *p_ptt) 2766316485Sdavidcs{ 2767316485Sdavidcs u32 resp = 0, param = 0; 2768316485Sdavidcs enum _ecore_status_t rc; 2769316485Sdavidcs 2770316485Sdavidcs rc = ecore_mcp_cmd(p_hwfn, p_ptt, 2771316485Sdavidcs DRV_MSG_CODE_NIG_DRAIN, 1000, 2772316485Sdavidcs &resp, ¶m); 2773316485Sdavidcs 2774316485Sdavidcs /* Wait for the drain to complete before returning */ 2775316485Sdavidcs OSAL_MSLEEP(1020); 2776316485Sdavidcs 2777316485Sdavidcs return rc; 2778316485Sdavidcs} 2779316485Sdavidcs 2780316485Sdavidcs#ifndef LINUX_REMOVE 2781316485Sdavidcsconst struct ecore_mcp_function_info 2782316485Sdavidcs*ecore_mcp_get_function_info(struct ecore_hwfn *p_hwfn) 2783316485Sdavidcs{ 2784316485Sdavidcs if (!p_hwfn || !p_hwfn->mcp_info) 2785316485Sdavidcs return OSAL_NULL; 2786316485Sdavidcs return &p_hwfn->mcp_info->func_info; 2787316485Sdavidcs} 2788316485Sdavidcs 2789316485Sdavidcsint ecore_mcp_get_personality_cnt(struct ecore_hwfn *p_hwfn, 2790316485Sdavidcs struct ecore_ptt *p_ptt, 2791316485Sdavidcs u32 personalities) 2792316485Sdavidcs{ 2793316485Sdavidcs enum ecore_pci_personality protocol = ECORE_PCI_DEFAULT; 2794316485Sdavidcs struct public_func shmem_info; 2795316485Sdavidcs int i, count = 0, num_pfs; 2796316485Sdavidcs 2797316485Sdavidcs num_pfs = NUM_OF_ENG_PFS(p_hwfn->p_dev); 2798316485Sdavidcs 2799316485Sdavidcs for (i = 0; i < num_pfs; i++) { 2800316485Sdavidcs ecore_mcp_get_shmem_func(p_hwfn, p_ptt, &shmem_info, 2801316485Sdavidcs MCP_PF_ID_BY_REL(p_hwfn, i)); 2802316485Sdavidcs if (shmem_info.config & FUNC_MF_CFG_FUNC_HIDE) 2803316485Sdavidcs continue; 2804316485Sdavidcs 2805316485Sdavidcs if (ecore_mcp_get_shmem_proto(p_hwfn, &shmem_info, p_ptt, 2806316485Sdavidcs &protocol) != 2807316485Sdavidcs ECORE_SUCCESS) 2808316485Sdavidcs continue; 2809316485Sdavidcs 2810316485Sdavidcs if ((1 << ((u32)protocol)) & personalities) 2811316485Sdavidcs count++; 2812316485Sdavidcs } 2813316485Sdavidcs 2814316485Sdavidcs return count; 2815316485Sdavidcs} 2816316485Sdavidcs#endif 2817316485Sdavidcs 2818316485Sdavidcsenum _ecore_status_t ecore_mcp_get_flash_size(struct ecore_hwfn *p_hwfn, 2819316485Sdavidcs struct ecore_ptt *p_ptt, 2820316485Sdavidcs u32 *p_flash_size) 2821316485Sdavidcs{ 2822316485Sdavidcs u32 flash_size; 2823316485Sdavidcs 2824316485Sdavidcs#ifndef ASIC_ONLY 2825316485Sdavidcs if (CHIP_REV_IS_EMUL(p_hwfn->p_dev)) { 2826316485Sdavidcs DP_NOTICE(p_hwfn, false, "Emulation - can't get flash size\n"); 2827316485Sdavidcs return ECORE_INVAL; 2828316485Sdavidcs } 2829316485Sdavidcs#endif 2830316485Sdavidcs 2831316485Sdavidcs if (IS_VF(p_hwfn->p_dev)) 2832316485Sdavidcs return ECORE_INVAL; 2833316485Sdavidcs 2834316485Sdavidcs flash_size = ecore_rd(p_hwfn, p_ptt, MCP_REG_NVM_CFG4); 2835316485Sdavidcs flash_size = (flash_size & MCP_REG_NVM_CFG4_FLASH_SIZE) >> 2836320164Sdavidcs MCP_REG_NVM_CFG4_FLASH_SIZE_SHIFT; 2837320164Sdavidcs flash_size = (1 << (flash_size + MCP_BYTES_PER_MBIT_OFFSET)); 2838316485Sdavidcs 2839316485Sdavidcs *p_flash_size = flash_size; 2840316485Sdavidcs 2841316485Sdavidcs return ECORE_SUCCESS; 2842316485Sdavidcs} 2843316485Sdavidcs 2844316485Sdavidcsenum _ecore_status_t ecore_start_recovery_process(struct ecore_hwfn *p_hwfn, 2845316485Sdavidcs struct ecore_ptt *p_ptt) 2846316485Sdavidcs{ 2847316485Sdavidcs struct ecore_dev *p_dev = p_hwfn->p_dev; 2848316485Sdavidcs 2849316485Sdavidcs if (p_dev->recov_in_prog) { 2850316485Sdavidcs DP_NOTICE(p_hwfn, false, 2851316485Sdavidcs "Avoid triggering a recovery since such a process is already in progress\n"); 2852316485Sdavidcs return ECORE_AGAIN; 2853316485Sdavidcs } 2854316485Sdavidcs 2855316485Sdavidcs DP_NOTICE(p_hwfn, false, "Triggering a recovery process\n"); 2856316485Sdavidcs ecore_wr(p_hwfn, p_ptt, MISC_REG_AEU_GENERAL_ATTN_35, 0x1); 2857316485Sdavidcs 2858316485Sdavidcs return ECORE_SUCCESS; 2859316485Sdavidcs} 2860316485Sdavidcs 2861337517Sdavidcs#define ECORE_RECOVERY_PROLOG_SLEEP_MS 100 2862337517Sdavidcs 2863337517Sdavidcsenum _ecore_status_t ecore_recovery_prolog(struct ecore_dev *p_dev) 2864337517Sdavidcs{ 2865337517Sdavidcs struct ecore_hwfn *p_hwfn = ECORE_LEADING_HWFN(p_dev); 2866337517Sdavidcs struct ecore_ptt *p_ptt = p_hwfn->p_main_ptt; 2867337517Sdavidcs enum _ecore_status_t rc; 2868337517Sdavidcs 2869337517Sdavidcs /* Allow ongoing PCIe transactions to complete */ 2870337517Sdavidcs OSAL_MSLEEP(ECORE_RECOVERY_PROLOG_SLEEP_MS); 2871337517Sdavidcs 2872337517Sdavidcs /* Clear the PF's internal FID_enable in the PXP */ 2873337517Sdavidcs rc = ecore_pglueb_set_pfid_enable(p_hwfn, p_ptt, false); 2874337517Sdavidcs if (rc != ECORE_SUCCESS) 2875337517Sdavidcs DP_NOTICE(p_hwfn, false, 2876337517Sdavidcs "ecore_pglueb_set_pfid_enable() failed. rc = %d.\n", 2877337517Sdavidcs rc); 2878337517Sdavidcs 2879337517Sdavidcs return rc; 2880337517Sdavidcs} 2881337517Sdavidcs 2882320164Sdavidcsstatic enum _ecore_status_t 2883320164Sdavidcsecore_mcp_config_vf_msix_bb(struct ecore_hwfn *p_hwfn, 2884320164Sdavidcs struct ecore_ptt *p_ptt, 2885320164Sdavidcs u8 vf_id, u8 num) 2886316485Sdavidcs{ 2887316485Sdavidcs u32 resp = 0, param = 0, rc_param = 0; 2888316485Sdavidcs enum _ecore_status_t rc; 2889316485Sdavidcs 2890316485Sdavidcs /* Only Leader can configure MSIX, and need to take CMT into account */ 2891316485Sdavidcs if (!IS_LEAD_HWFN(p_hwfn)) 2892316485Sdavidcs return ECORE_SUCCESS; 2893316485Sdavidcs num *= p_hwfn->p_dev->num_hwfns; 2894316485Sdavidcs 2895320164Sdavidcs param |= (vf_id << DRV_MB_PARAM_CFG_VF_MSIX_VF_ID_OFFSET) & 2896316485Sdavidcs DRV_MB_PARAM_CFG_VF_MSIX_VF_ID_MASK; 2897320164Sdavidcs param |= (num << DRV_MB_PARAM_CFG_VF_MSIX_SB_NUM_OFFSET) & 2898316485Sdavidcs DRV_MB_PARAM_CFG_VF_MSIX_SB_NUM_MASK; 2899316485Sdavidcs 2900316485Sdavidcs rc = ecore_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_CFG_VF_MSIX, param, 2901316485Sdavidcs &resp, &rc_param); 2902316485Sdavidcs 2903316485Sdavidcs if (resp != FW_MSG_CODE_DRV_CFG_VF_MSIX_DONE) { 2904316485Sdavidcs DP_NOTICE(p_hwfn, true, "VF[%d]: MFW failed to set MSI-X\n", 2905316485Sdavidcs vf_id); 2906316485Sdavidcs rc = ECORE_INVAL; 2907316485Sdavidcs } else { 2908316485Sdavidcs DP_VERBOSE(p_hwfn, ECORE_MSG_IOV, 2909316485Sdavidcs "Requested 0x%02x MSI-x interrupts from VF 0x%02x\n", 2910316485Sdavidcs num, vf_id); 2911316485Sdavidcs } 2912316485Sdavidcs 2913316485Sdavidcs return rc; 2914316485Sdavidcs} 2915316485Sdavidcs 2916320164Sdavidcsstatic enum _ecore_status_t 2917320164Sdavidcsecore_mcp_config_vf_msix_ah(struct ecore_hwfn *p_hwfn, 2918320164Sdavidcs struct ecore_ptt *p_ptt, 2919320164Sdavidcs u8 num) 2920320164Sdavidcs{ 2921320164Sdavidcs u32 resp = 0, param = num, rc_param = 0; 2922320164Sdavidcs enum _ecore_status_t rc; 2923320164Sdavidcs 2924320164Sdavidcs rc = ecore_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_CFG_PF_VFS_MSIX, 2925320164Sdavidcs param, &resp, &rc_param); 2926320164Sdavidcs 2927320164Sdavidcs if (resp != FW_MSG_CODE_DRV_CFG_PF_VFS_MSIX_DONE) { 2928320164Sdavidcs DP_NOTICE(p_hwfn, true, "MFW failed to set MSI-X for VFs\n"); 2929320164Sdavidcs rc = ECORE_INVAL; 2930320164Sdavidcs } else { 2931320164Sdavidcs DP_VERBOSE(p_hwfn, ECORE_MSG_IOV, 2932320164Sdavidcs "Requested 0x%02x MSI-x interrupts for VFs\n", 2933320164Sdavidcs num); 2934320164Sdavidcs } 2935320164Sdavidcs 2936320164Sdavidcs return rc; 2937320164Sdavidcs} 2938320164Sdavidcs 2939320164Sdavidcsenum _ecore_status_t ecore_mcp_config_vf_msix(struct ecore_hwfn *p_hwfn, 2940320164Sdavidcs struct ecore_ptt *p_ptt, 2941320164Sdavidcs u8 vf_id, u8 num) 2942320164Sdavidcs{ 2943320164Sdavidcs if (ECORE_IS_BB(p_hwfn->p_dev)) 2944320164Sdavidcs return ecore_mcp_config_vf_msix_bb(p_hwfn, p_ptt, vf_id, num); 2945320164Sdavidcs else 2946320164Sdavidcs return ecore_mcp_config_vf_msix_ah(p_hwfn, p_ptt, num); 2947320164Sdavidcs} 2948320164Sdavidcs 2949316485Sdavidcsenum _ecore_status_t 2950316485Sdavidcsecore_mcp_send_drv_version(struct ecore_hwfn *p_hwfn, struct ecore_ptt *p_ptt, 2951316485Sdavidcs struct ecore_mcp_drv_version *p_ver) 2952316485Sdavidcs{ 2953316485Sdavidcs struct ecore_mcp_mb_params mb_params; 2954316485Sdavidcs struct drv_version_stc drv_version; 2955316485Sdavidcs u32 num_words, i; 2956316485Sdavidcs void *p_name; 2957316485Sdavidcs OSAL_BE32 val; 2958316485Sdavidcs enum _ecore_status_t rc; 2959316485Sdavidcs 2960316485Sdavidcs#ifndef ASIC_ONLY 2961316485Sdavidcs if (CHIP_REV_IS_SLOW(p_hwfn->p_dev)) 2962316485Sdavidcs return ECORE_SUCCESS; 2963316485Sdavidcs#endif 2964316485Sdavidcs 2965316485Sdavidcs OSAL_MEM_ZERO(&drv_version, sizeof(drv_version)); 2966316485Sdavidcs drv_version.version = p_ver->version; 2967316485Sdavidcs num_words = (MCP_DRV_VER_STR_SIZE - 4) / 4; 2968316485Sdavidcs for (i = 0; i < num_words; i++) { 2969316485Sdavidcs /* The driver name is expected to be in a big-endian format */ 2970316485Sdavidcs p_name = &p_ver->name[i * sizeof(u32)]; 2971316485Sdavidcs val = OSAL_CPU_TO_BE32(*(u32 *)p_name); 2972316485Sdavidcs *(u32 *)&drv_version.name[i * sizeof(u32)] = val; 2973316485Sdavidcs } 2974316485Sdavidcs 2975316485Sdavidcs OSAL_MEM_ZERO(&mb_params, sizeof(mb_params)); 2976316485Sdavidcs mb_params.cmd = DRV_MSG_CODE_SET_VERSION; 2977316485Sdavidcs mb_params.p_data_src = &drv_version; 2978316485Sdavidcs mb_params.data_src_size = sizeof(drv_version); 2979316485Sdavidcs rc = ecore_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 2980316485Sdavidcs if (rc != ECORE_SUCCESS) 2981316485Sdavidcs DP_ERR(p_hwfn, "MCP response failure, aborting\n"); 2982316485Sdavidcs 2983316485Sdavidcs return rc; 2984316485Sdavidcs} 2985316485Sdavidcs 2986320164Sdavidcs/* A maximal 100 msec waiting time for the MCP to halt */ 2987320164Sdavidcs#define ECORE_MCP_HALT_SLEEP_MS 10 2988320164Sdavidcs#define ECORE_MCP_HALT_MAX_RETRIES 10 2989320164Sdavidcs 2990316485Sdavidcsenum _ecore_status_t ecore_mcp_halt(struct ecore_hwfn *p_hwfn, 2991316485Sdavidcs struct ecore_ptt *p_ptt) 2992316485Sdavidcs{ 2993337517Sdavidcs u32 resp = 0, param = 0, cpu_state, cnt = 0; 2994316485Sdavidcs enum _ecore_status_t rc; 2995316485Sdavidcs 2996316485Sdavidcs rc = ecore_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_MCP_HALT, 0, &resp, 2997316485Sdavidcs ¶m); 2998320164Sdavidcs if (rc != ECORE_SUCCESS) { 2999316485Sdavidcs DP_ERR(p_hwfn, "MCP response failure, aborting\n"); 3000320164Sdavidcs return rc; 3001320164Sdavidcs } 3002316485Sdavidcs 3003320164Sdavidcs do { 3004320164Sdavidcs OSAL_MSLEEP(ECORE_MCP_HALT_SLEEP_MS); 3005337517Sdavidcs cpu_state = ecore_rd(p_hwfn, p_ptt, MCP_REG_CPU_STATE); 3006337517Sdavidcs if (cpu_state & MCP_REG_CPU_STATE_SOFT_HALTED) 3007320164Sdavidcs break; 3008320164Sdavidcs } while (++cnt < ECORE_MCP_HALT_MAX_RETRIES); 3009320164Sdavidcs 3010320164Sdavidcs if (cnt == ECORE_MCP_HALT_MAX_RETRIES) { 3011320164Sdavidcs DP_NOTICE(p_hwfn, false, 3012337517Sdavidcs "Failed to halt the MCP [CPU_MODE = 0x%08x, CPU_STATE = 0x%08x]\n", 3013337517Sdavidcs ecore_rd(p_hwfn, p_ptt, MCP_REG_CPU_MODE), cpu_state); 3014320164Sdavidcs return ECORE_BUSY; 3015320164Sdavidcs } 3016320164Sdavidcs 3017320164Sdavidcs ecore_mcp_cmd_set_blocking(p_hwfn, true); 3018320164Sdavidcs 3019320164Sdavidcs return ECORE_SUCCESS; 3020316485Sdavidcs} 3021316485Sdavidcs 3022337517Sdavidcs#define ECORE_MCP_RESUME_SLEEP_MS 10 3023337517Sdavidcs 3024316485Sdavidcsenum _ecore_status_t ecore_mcp_resume(struct ecore_hwfn *p_hwfn, 3025316485Sdavidcs struct ecore_ptt *p_ptt) 3026316485Sdavidcs{ 3027337517Sdavidcs u32 cpu_mode, cpu_state; 3028316485Sdavidcs 3029316485Sdavidcs ecore_wr(p_hwfn, p_ptt, MCP_REG_CPU_STATE, 0xffffffff); 3030316485Sdavidcs 3031316485Sdavidcs cpu_mode = ecore_rd(p_hwfn, p_ptt, MCP_REG_CPU_MODE); 3032337517Sdavidcs cpu_mode &= ~MCP_REG_CPU_MODE_SOFT_HALT; 3033337517Sdavidcs ecore_wr(p_hwfn, p_ptt, MCP_REG_CPU_MODE, cpu_mode); 3034316485Sdavidcs 3035337517Sdavidcs OSAL_MSLEEP(ECORE_MCP_RESUME_SLEEP_MS); 3036337517Sdavidcs cpu_state = ecore_rd(p_hwfn, p_ptt, MCP_REG_CPU_STATE); 3037337517Sdavidcs 3038337517Sdavidcs if (cpu_state & MCP_REG_CPU_STATE_SOFT_HALTED) { 3039320164Sdavidcs DP_NOTICE(p_hwfn, false, 3040337517Sdavidcs "Failed to resume the MCP [CPU_MODE = 0x%08x, CPU_STATE = 0x%08x]\n", 3041337517Sdavidcs cpu_mode, cpu_state); 3042320164Sdavidcs return ECORE_BUSY; 3043320164Sdavidcs } 3044320164Sdavidcs 3045320164Sdavidcs ecore_mcp_cmd_set_blocking(p_hwfn, false); 3046320164Sdavidcs 3047320164Sdavidcs return ECORE_SUCCESS; 3048316485Sdavidcs} 3049316485Sdavidcs 3050316485Sdavidcsenum _ecore_status_t 3051316485Sdavidcsecore_mcp_ov_update_current_config(struct ecore_hwfn *p_hwfn, 3052316485Sdavidcs struct ecore_ptt *p_ptt, 3053316485Sdavidcs enum ecore_ov_client client) 3054316485Sdavidcs{ 3055316485Sdavidcs u32 resp = 0, param = 0; 3056316485Sdavidcs u32 drv_mb_param; 3057320164Sdavidcs enum _ecore_status_t rc; 3058316485Sdavidcs 3059316485Sdavidcs switch (client) { 3060316485Sdavidcs case ECORE_OV_CLIENT_DRV: 3061316485Sdavidcs drv_mb_param = DRV_MB_PARAM_OV_CURR_CFG_OS; 3062316485Sdavidcs break; 3063316485Sdavidcs case ECORE_OV_CLIENT_USER: 3064316485Sdavidcs drv_mb_param = DRV_MB_PARAM_OV_CURR_CFG_OTHER; 3065316485Sdavidcs break; 3066316485Sdavidcs case ECORE_OV_CLIENT_VENDOR_SPEC: 3067316485Sdavidcs drv_mb_param = DRV_MB_PARAM_OV_CURR_CFG_VENDOR_SPEC; 3068316485Sdavidcs break; 3069316485Sdavidcs default: 3070316485Sdavidcs DP_NOTICE(p_hwfn, true, 3071316485Sdavidcs "Invalid client type %d\n", client); 3072316485Sdavidcs return ECORE_INVAL; 3073316485Sdavidcs } 3074316485Sdavidcs 3075316485Sdavidcs rc = ecore_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_OV_UPDATE_CURR_CFG, 3076316485Sdavidcs drv_mb_param, &resp, ¶m); 3077316485Sdavidcs if (rc != ECORE_SUCCESS) 3078316485Sdavidcs DP_ERR(p_hwfn, "MCP response failure, aborting\n"); 3079316485Sdavidcs 3080316485Sdavidcs return rc; 3081316485Sdavidcs} 3082316485Sdavidcs 3083316485Sdavidcsenum _ecore_status_t 3084316485Sdavidcsecore_mcp_ov_update_driver_state(struct ecore_hwfn *p_hwfn, 3085316485Sdavidcs struct ecore_ptt *p_ptt, 3086316485Sdavidcs enum ecore_ov_driver_state drv_state) 3087316485Sdavidcs{ 3088316485Sdavidcs u32 resp = 0, param = 0; 3089316485Sdavidcs u32 drv_mb_param; 3090320164Sdavidcs enum _ecore_status_t rc; 3091316485Sdavidcs 3092316485Sdavidcs switch (drv_state) { 3093316485Sdavidcs case ECORE_OV_DRIVER_STATE_NOT_LOADED: 3094316485Sdavidcs drv_mb_param = DRV_MSG_CODE_OV_UPDATE_DRIVER_STATE_NOT_LOADED; 3095316485Sdavidcs break; 3096316485Sdavidcs case ECORE_OV_DRIVER_STATE_DISABLED: 3097316485Sdavidcs drv_mb_param = DRV_MSG_CODE_OV_UPDATE_DRIVER_STATE_DISABLED; 3098316485Sdavidcs break; 3099316485Sdavidcs case ECORE_OV_DRIVER_STATE_ACTIVE: 3100316485Sdavidcs drv_mb_param = DRV_MSG_CODE_OV_UPDATE_DRIVER_STATE_ACTIVE; 3101316485Sdavidcs break; 3102316485Sdavidcs default: 3103316485Sdavidcs DP_NOTICE(p_hwfn, true, 3104316485Sdavidcs "Invalid driver state %d\n", drv_state); 3105316485Sdavidcs return ECORE_INVAL; 3106316485Sdavidcs } 3107316485Sdavidcs 3108316485Sdavidcs rc = ecore_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_OV_UPDATE_DRIVER_STATE, 3109316485Sdavidcs drv_mb_param, &resp, ¶m); 3110316485Sdavidcs if (rc != ECORE_SUCCESS) 3111316485Sdavidcs DP_ERR(p_hwfn, "Failed to send driver state\n"); 3112316485Sdavidcs 3113316485Sdavidcs return rc; 3114316485Sdavidcs} 3115316485Sdavidcs 3116316485Sdavidcsenum _ecore_status_t 3117316485Sdavidcsecore_mcp_ov_get_fc_npiv(struct ecore_hwfn *p_hwfn, struct ecore_ptt *p_ptt, 3118316485Sdavidcs struct ecore_fc_npiv_tbl *p_table) 3119316485Sdavidcs{ 3120316485Sdavidcs struct dci_fc_npiv_tbl *p_npiv_table; 3121316485Sdavidcs u8 *p_buf = OSAL_NULL; 3122316485Sdavidcs u32 addr, size, i; 3123320164Sdavidcs enum _ecore_status_t rc = ECORE_SUCCESS; 3124316485Sdavidcs 3125316485Sdavidcs p_table->num_wwpn = 0; 3126316485Sdavidcs p_table->num_wwnn = 0; 3127316485Sdavidcs addr = ecore_rd(p_hwfn, p_ptt, p_hwfn->mcp_info->port_addr + 3128316485Sdavidcs OFFSETOF(struct public_port, fc_npiv_nvram_tbl_addr)); 3129316485Sdavidcs if (addr == NPIV_TBL_INVALID_ADDR) { 3130316485Sdavidcs DP_VERBOSE(p_hwfn, ECORE_MSG_SP, "NPIV table doesn't exist\n"); 3131316485Sdavidcs return rc; 3132316485Sdavidcs } 3133316485Sdavidcs 3134316485Sdavidcs size = ecore_rd(p_hwfn, p_ptt, p_hwfn->mcp_info->port_addr + 3135316485Sdavidcs OFFSETOF(struct public_port, fc_npiv_nvram_tbl_size)); 3136316485Sdavidcs if (!size) { 3137316485Sdavidcs DP_VERBOSE(p_hwfn, ECORE_MSG_SP, "NPIV table is empty\n"); 3138316485Sdavidcs return rc; 3139316485Sdavidcs } 3140316485Sdavidcs 3141316485Sdavidcs p_buf = OSAL_VZALLOC(p_hwfn->p_dev, size); 3142316485Sdavidcs if (!p_buf) { 3143316485Sdavidcs DP_ERR(p_hwfn, "Buffer allocation failed\n"); 3144316485Sdavidcs return ECORE_NOMEM; 3145316485Sdavidcs } 3146316485Sdavidcs 3147316485Sdavidcs rc = ecore_mcp_nvm_read(p_hwfn->p_dev, addr, p_buf, size); 3148316485Sdavidcs if (rc != ECORE_SUCCESS) { 3149316485Sdavidcs OSAL_VFREE(p_hwfn->p_dev, p_buf); 3150316485Sdavidcs return rc; 3151316485Sdavidcs } 3152316485Sdavidcs 3153316485Sdavidcs p_npiv_table = (struct dci_fc_npiv_tbl *)p_buf; 3154316485Sdavidcs p_table->num_wwpn = (u16)p_npiv_table->fc_npiv_cfg.num_of_npiv; 3155316485Sdavidcs p_table->num_wwnn = (u16)p_npiv_table->fc_npiv_cfg.num_of_npiv; 3156316485Sdavidcs for (i = 0; i < p_table->num_wwpn; i++) { 3157316485Sdavidcs OSAL_MEMCPY(p_table->wwpn, p_npiv_table->settings[i].npiv_wwpn, 3158316485Sdavidcs ECORE_WWN_SIZE); 3159316485Sdavidcs OSAL_MEMCPY(p_table->wwnn, p_npiv_table->settings[i].npiv_wwnn, 3160316485Sdavidcs ECORE_WWN_SIZE); 3161316485Sdavidcs } 3162316485Sdavidcs 3163316485Sdavidcs OSAL_VFREE(p_hwfn->p_dev, p_buf); 3164316485Sdavidcs 3165316485Sdavidcs return ECORE_SUCCESS; 3166316485Sdavidcs} 3167316485Sdavidcs 3168316485Sdavidcsenum _ecore_status_t 3169316485Sdavidcsecore_mcp_ov_update_mtu(struct ecore_hwfn *p_hwfn, struct ecore_ptt *p_ptt, 3170316485Sdavidcs u16 mtu) 3171316485Sdavidcs{ 3172316485Sdavidcs u32 resp = 0, param = 0; 3173316485Sdavidcs u32 drv_mb_param; 3174320164Sdavidcs enum _ecore_status_t rc; 3175316485Sdavidcs 3176320164Sdavidcs drv_mb_param = (u32)mtu << DRV_MB_PARAM_OV_MTU_SIZE_OFFSET; 3177316485Sdavidcs rc = ecore_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_OV_UPDATE_MTU, 3178316485Sdavidcs drv_mb_param, &resp, ¶m); 3179316485Sdavidcs if (rc != ECORE_SUCCESS) 3180316485Sdavidcs DP_ERR(p_hwfn, "Failed to send mtu value, rc = %d\n", rc); 3181316485Sdavidcs 3182316485Sdavidcs return rc; 3183316485Sdavidcs} 3184316485Sdavidcs 3185316485Sdavidcsenum _ecore_status_t 3186316485Sdavidcsecore_mcp_ov_update_mac(struct ecore_hwfn *p_hwfn, struct ecore_ptt *p_ptt, 3187316485Sdavidcs u8 *mac) 3188316485Sdavidcs{ 3189316485Sdavidcs struct ecore_mcp_mb_params mb_params; 3190320164Sdavidcs u32 mfw_mac[2]; 3191316485Sdavidcs enum _ecore_status_t rc; 3192316485Sdavidcs 3193316485Sdavidcs OSAL_MEM_ZERO(&mb_params, sizeof(mb_params)); 3194316485Sdavidcs mb_params.cmd = DRV_MSG_CODE_SET_VMAC; 3195316485Sdavidcs mb_params.param = DRV_MSG_CODE_VMAC_TYPE_MAC << 3196320164Sdavidcs DRV_MSG_CODE_VMAC_TYPE_OFFSET; 3197316485Sdavidcs mb_params.param |= MCP_PF_ID(p_hwfn); 3198316485Sdavidcs 3199316485Sdavidcs /* MCP is BE, and on LE platforms PCI would swap access to SHMEM 3200316485Sdavidcs * in 32-bit granularity. 3201316485Sdavidcs * So the MAC has to be set in native order [and not byte order], 3202316485Sdavidcs * otherwise it would be read incorrectly by MFW after swap. 3203316485Sdavidcs */ 3204316485Sdavidcs mfw_mac[0] = mac[0] << 24 | mac[1] << 16 | mac[2] << 8 | mac[3]; 3205316485Sdavidcs mfw_mac[1] = mac[4] << 24 | mac[5] << 16; 3206316485Sdavidcs 3207316485Sdavidcs mb_params.p_data_src = (u8 *)mfw_mac; 3208316485Sdavidcs mb_params.data_src_size = 8; 3209316485Sdavidcs rc = ecore_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 3210316485Sdavidcs if (rc != ECORE_SUCCESS) 3211316485Sdavidcs DP_ERR(p_hwfn, "Failed to send mac address, rc = %d\n", rc); 3212316485Sdavidcs 3213316485Sdavidcs /* Store primary MAC for later possible WoL */ 3214316485Sdavidcs OSAL_MEMCPY(p_hwfn->p_dev->wol_mac, mac, ETH_ALEN); 3215316485Sdavidcs 3216316485Sdavidcs return rc; 3217316485Sdavidcs} 3218316485Sdavidcs 3219316485Sdavidcsenum _ecore_status_t 3220316485Sdavidcsecore_mcp_ov_update_wol(struct ecore_hwfn *p_hwfn, struct ecore_ptt *p_ptt, 3221316485Sdavidcs enum ecore_ov_wol wol) 3222316485Sdavidcs{ 3223316485Sdavidcs u32 resp = 0, param = 0; 3224316485Sdavidcs u32 drv_mb_param; 3225320164Sdavidcs enum _ecore_status_t rc; 3226316485Sdavidcs 3227316485Sdavidcs if (p_hwfn->hw_info.b_wol_support == ECORE_WOL_SUPPORT_NONE) { 3228316485Sdavidcs DP_VERBOSE(p_hwfn, ECORE_MSG_SP, 3229316485Sdavidcs "Can't change WoL configuration when WoL isn't supported\n"); 3230316485Sdavidcs return ECORE_INVAL; 3231316485Sdavidcs } 3232316485Sdavidcs 3233316485Sdavidcs switch (wol) { 3234316485Sdavidcs case ECORE_OV_WOL_DEFAULT: 3235316485Sdavidcs drv_mb_param = DRV_MB_PARAM_WOL_DEFAULT; 3236316485Sdavidcs break; 3237316485Sdavidcs case ECORE_OV_WOL_DISABLED: 3238316485Sdavidcs drv_mb_param = DRV_MB_PARAM_WOL_DISABLED; 3239316485Sdavidcs break; 3240316485Sdavidcs case ECORE_OV_WOL_ENABLED: 3241316485Sdavidcs drv_mb_param = DRV_MB_PARAM_WOL_ENABLED; 3242316485Sdavidcs break; 3243316485Sdavidcs default: 3244316485Sdavidcs DP_ERR(p_hwfn, "Invalid wol state %d\n", wol); 3245316485Sdavidcs return ECORE_INVAL; 3246316485Sdavidcs } 3247316485Sdavidcs 3248316485Sdavidcs rc = ecore_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_OV_UPDATE_WOL, 3249316485Sdavidcs drv_mb_param, &resp, ¶m); 3250316485Sdavidcs if (rc != ECORE_SUCCESS) 3251316485Sdavidcs DP_ERR(p_hwfn, "Failed to send wol mode, rc = %d\n", rc); 3252316485Sdavidcs 3253316485Sdavidcs /* Store the WoL update for a future unload */ 3254316485Sdavidcs p_hwfn->p_dev->wol_config = (u8)wol; 3255316485Sdavidcs 3256316485Sdavidcs return rc; 3257316485Sdavidcs} 3258316485Sdavidcs 3259316485Sdavidcsenum _ecore_status_t 3260316485Sdavidcsecore_mcp_ov_update_eswitch(struct ecore_hwfn *p_hwfn, struct ecore_ptt *p_ptt, 3261316485Sdavidcs enum ecore_ov_eswitch eswitch) 3262316485Sdavidcs{ 3263316485Sdavidcs u32 resp = 0, param = 0; 3264316485Sdavidcs u32 drv_mb_param; 3265320164Sdavidcs enum _ecore_status_t rc; 3266316485Sdavidcs 3267316485Sdavidcs switch (eswitch) { 3268316485Sdavidcs case ECORE_OV_ESWITCH_NONE: 3269316485Sdavidcs drv_mb_param = DRV_MB_PARAM_ESWITCH_MODE_NONE; 3270316485Sdavidcs break; 3271316485Sdavidcs case ECORE_OV_ESWITCH_VEB: 3272316485Sdavidcs drv_mb_param = DRV_MB_PARAM_ESWITCH_MODE_VEB; 3273316485Sdavidcs break; 3274316485Sdavidcs case ECORE_OV_ESWITCH_VEPA: 3275316485Sdavidcs drv_mb_param = DRV_MB_PARAM_ESWITCH_MODE_VEPA; 3276316485Sdavidcs break; 3277316485Sdavidcs default: 3278316485Sdavidcs DP_ERR(p_hwfn, "Invalid eswitch mode %d\n", eswitch); 3279316485Sdavidcs return ECORE_INVAL; 3280316485Sdavidcs } 3281316485Sdavidcs 3282316485Sdavidcs rc = ecore_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_OV_UPDATE_ESWITCH_MODE, 3283316485Sdavidcs drv_mb_param, &resp, ¶m); 3284316485Sdavidcs if (rc != ECORE_SUCCESS) 3285316485Sdavidcs DP_ERR(p_hwfn, "Failed to send eswitch mode, rc = %d\n", rc); 3286316485Sdavidcs 3287316485Sdavidcs return rc; 3288316485Sdavidcs} 3289316485Sdavidcs 3290316485Sdavidcsenum _ecore_status_t ecore_mcp_set_led(struct ecore_hwfn *p_hwfn, 3291316485Sdavidcs struct ecore_ptt *p_ptt, 3292316485Sdavidcs enum ecore_led_mode mode) 3293316485Sdavidcs{ 3294316485Sdavidcs u32 resp = 0, param = 0, drv_mb_param; 3295316485Sdavidcs enum _ecore_status_t rc; 3296316485Sdavidcs 3297316485Sdavidcs switch (mode) { 3298316485Sdavidcs case ECORE_LED_MODE_ON: 3299316485Sdavidcs drv_mb_param = DRV_MB_PARAM_SET_LED_MODE_ON; 3300316485Sdavidcs break; 3301316485Sdavidcs case ECORE_LED_MODE_OFF: 3302316485Sdavidcs drv_mb_param = DRV_MB_PARAM_SET_LED_MODE_OFF; 3303316485Sdavidcs break; 3304316485Sdavidcs case ECORE_LED_MODE_RESTORE: 3305316485Sdavidcs drv_mb_param = DRV_MB_PARAM_SET_LED_MODE_OPER; 3306316485Sdavidcs break; 3307316485Sdavidcs default: 3308316485Sdavidcs DP_NOTICE(p_hwfn, true, "Invalid LED mode %d\n", mode); 3309316485Sdavidcs return ECORE_INVAL; 3310316485Sdavidcs } 3311316485Sdavidcs 3312316485Sdavidcs rc = ecore_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_SET_LED_MODE, 3313316485Sdavidcs drv_mb_param, &resp, ¶m); 3314316485Sdavidcs if (rc != ECORE_SUCCESS) 3315316485Sdavidcs DP_ERR(p_hwfn, "MCP response failure, aborting\n"); 3316316485Sdavidcs 3317316485Sdavidcs return rc; 3318316485Sdavidcs} 3319316485Sdavidcs 3320316485Sdavidcsenum _ecore_status_t ecore_mcp_mask_parities(struct ecore_hwfn *p_hwfn, 3321316485Sdavidcs struct ecore_ptt *p_ptt, 3322316485Sdavidcs u32 mask_parities) 3323316485Sdavidcs{ 3324320164Sdavidcs u32 resp = 0, param = 0; 3325316485Sdavidcs enum _ecore_status_t rc; 3326316485Sdavidcs 3327316485Sdavidcs rc = ecore_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_MASK_PARITIES, 3328316485Sdavidcs mask_parities, &resp, ¶m); 3329316485Sdavidcs 3330316485Sdavidcs if (rc != ECORE_SUCCESS) { 3331316485Sdavidcs DP_ERR(p_hwfn, "MCP response failure for mask parities, aborting\n"); 3332316485Sdavidcs } else if (resp != FW_MSG_CODE_OK) { 3333316485Sdavidcs DP_ERR(p_hwfn, "MCP did not acknowledge mask parity request. Old MFW?\n"); 3334316485Sdavidcs rc = ECORE_INVAL; 3335316485Sdavidcs } 3336316485Sdavidcs 3337316485Sdavidcs return rc; 3338316485Sdavidcs} 3339316485Sdavidcs 3340316485Sdavidcsenum _ecore_status_t ecore_mcp_nvm_read(struct ecore_dev *p_dev, u32 addr, 3341316485Sdavidcs u8 *p_buf, u32 len) 3342316485Sdavidcs{ 3343316485Sdavidcs struct ecore_hwfn *p_hwfn = ECORE_LEADING_HWFN(p_dev); 3344316485Sdavidcs u32 bytes_left, offset, bytes_to_copy, buf_size; 3345337517Sdavidcs u32 nvm_offset, resp = 0, param; 3346316485Sdavidcs struct ecore_ptt *p_ptt; 3347316485Sdavidcs enum _ecore_status_t rc = ECORE_SUCCESS; 3348316485Sdavidcs 3349316485Sdavidcs p_ptt = ecore_ptt_acquire(p_hwfn); 3350316485Sdavidcs if (!p_ptt) 3351316485Sdavidcs return ECORE_BUSY; 3352316485Sdavidcs 3353316485Sdavidcs bytes_left = len; 3354316485Sdavidcs offset = 0; 3355316485Sdavidcs while (bytes_left > 0) { 3356316485Sdavidcs bytes_to_copy = OSAL_MIN_T(u32, bytes_left, 3357316485Sdavidcs MCP_DRV_NVM_BUF_LEN); 3358320164Sdavidcs nvm_offset = (addr + offset) | (bytes_to_copy << 3359320164Sdavidcs DRV_MB_PARAM_NVM_LEN_OFFSET); 3360320164Sdavidcs rc = ecore_mcp_nvm_rd_cmd(p_hwfn, p_ptt, 3361320164Sdavidcs DRV_MSG_CODE_NVM_READ_NVRAM, 3362320164Sdavidcs nvm_offset, &resp, ¶m, &buf_size, 3363320164Sdavidcs (u32 *)(p_buf + offset)); 3364337517Sdavidcs if (rc != ECORE_SUCCESS) { 3365337517Sdavidcs DP_NOTICE(p_dev, false, 3366337517Sdavidcs "ecore_mcp_nvm_rd_cmd() failed, rc = %d\n", 3367337517Sdavidcs rc); 3368337517Sdavidcs resp = FW_MSG_CODE_ERROR; 3369316485Sdavidcs break; 3370316485Sdavidcs } 3371316485Sdavidcs 3372337517Sdavidcs if (resp != FW_MSG_CODE_NVM_OK) { 3373337517Sdavidcs DP_NOTICE(p_dev, false, 3374337517Sdavidcs "nvm read failed, resp = 0x%08x\n", resp); 3375337517Sdavidcs rc = ECORE_UNKNOWN_ERROR; 3376337517Sdavidcs break; 3377337517Sdavidcs } 3378337517Sdavidcs 3379316485Sdavidcs /* This can be a lengthy process, and it's possible scheduler 3380316485Sdavidcs * isn't preemptable. Sleep a bit to prevent CPU hogging. 3381316485Sdavidcs */ 3382316485Sdavidcs if (bytes_left % 0x1000 < 3383320164Sdavidcs (bytes_left - buf_size) % 0x1000) 3384316485Sdavidcs OSAL_MSLEEP(1); 3385316485Sdavidcs 3386320164Sdavidcs offset += buf_size; 3387320164Sdavidcs bytes_left -= buf_size; 3388316485Sdavidcs } 3389316485Sdavidcs 3390320164Sdavidcs p_dev->mcp_nvm_resp = resp; 3391316485Sdavidcs ecore_ptt_release(p_hwfn, p_ptt); 3392316485Sdavidcs 3393316485Sdavidcs return rc; 3394316485Sdavidcs} 3395316485Sdavidcs 3396316485Sdavidcsenum _ecore_status_t ecore_mcp_phy_read(struct ecore_dev *p_dev, u32 cmd, 3397316485Sdavidcs u32 addr, u8 *p_buf, u32 len) 3398316485Sdavidcs{ 3399316485Sdavidcs struct ecore_hwfn *p_hwfn = ECORE_LEADING_HWFN(p_dev); 3400316485Sdavidcs struct ecore_ptt *p_ptt; 3401320164Sdavidcs u32 resp, param; 3402316485Sdavidcs enum _ecore_status_t rc; 3403316485Sdavidcs 3404316485Sdavidcs p_ptt = ecore_ptt_acquire(p_hwfn); 3405316485Sdavidcs if (!p_ptt) 3406316485Sdavidcs return ECORE_BUSY; 3407316485Sdavidcs 3408320164Sdavidcs rc = ecore_mcp_nvm_rd_cmd(p_hwfn, p_ptt, 3409320164Sdavidcs (cmd == ECORE_PHY_CORE_READ) ? 3410320164Sdavidcs DRV_MSG_CODE_PHY_CORE_READ : 3411320164Sdavidcs DRV_MSG_CODE_PHY_RAW_READ, 3412320164Sdavidcs addr, &resp, ¶m, &len, (u32 *)p_buf); 3413316485Sdavidcs if (rc != ECORE_SUCCESS) 3414316485Sdavidcs DP_NOTICE(p_dev, false, "MCP command rc = %d\n", rc); 3415316485Sdavidcs 3416320164Sdavidcs p_dev->mcp_nvm_resp = resp; 3417316485Sdavidcs ecore_ptt_release(p_hwfn, p_ptt); 3418316485Sdavidcs 3419316485Sdavidcs return rc; 3420316485Sdavidcs} 3421316485Sdavidcs 3422316485Sdavidcsenum _ecore_status_t ecore_mcp_nvm_resp(struct ecore_dev *p_dev, u8 *p_buf) 3423316485Sdavidcs{ 3424316485Sdavidcs struct ecore_hwfn *p_hwfn = ECORE_LEADING_HWFN(p_dev); 3425316485Sdavidcs struct ecore_ptt *p_ptt; 3426316485Sdavidcs 3427316485Sdavidcs p_ptt = ecore_ptt_acquire(p_hwfn); 3428316485Sdavidcs if (!p_ptt) 3429316485Sdavidcs return ECORE_BUSY; 3430316485Sdavidcs 3431316485Sdavidcs OSAL_MEMCPY(p_buf, &p_dev->mcp_nvm_resp, sizeof(p_dev->mcp_nvm_resp)); 3432316485Sdavidcs ecore_ptt_release(p_hwfn, p_ptt); 3433316485Sdavidcs 3434316485Sdavidcs return ECORE_SUCCESS; 3435316485Sdavidcs} 3436316485Sdavidcs 3437316485Sdavidcsenum _ecore_status_t ecore_mcp_nvm_del_file(struct ecore_dev *p_dev, 3438316485Sdavidcs u32 addr) 3439316485Sdavidcs{ 3440316485Sdavidcs struct ecore_hwfn *p_hwfn = ECORE_LEADING_HWFN(p_dev); 3441316485Sdavidcs struct ecore_ptt *p_ptt; 3442320164Sdavidcs u32 resp, param; 3443316485Sdavidcs enum _ecore_status_t rc; 3444316485Sdavidcs 3445316485Sdavidcs p_ptt = ecore_ptt_acquire(p_hwfn); 3446316485Sdavidcs if (!p_ptt) 3447316485Sdavidcs return ECORE_BUSY; 3448320164Sdavidcs rc = ecore_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_NVM_DEL_FILE, addr, 3449320164Sdavidcs &resp, ¶m); 3450320164Sdavidcs p_dev->mcp_nvm_resp = resp; 3451316485Sdavidcs ecore_ptt_release(p_hwfn, p_ptt); 3452316485Sdavidcs 3453316485Sdavidcs return rc; 3454316485Sdavidcs} 3455316485Sdavidcs 3456316485Sdavidcsenum _ecore_status_t ecore_mcp_nvm_put_file_begin(struct ecore_dev *p_dev, 3457316485Sdavidcs u32 addr) 3458316485Sdavidcs{ 3459316485Sdavidcs struct ecore_hwfn *p_hwfn = ECORE_LEADING_HWFN(p_dev); 3460316485Sdavidcs struct ecore_ptt *p_ptt; 3461320164Sdavidcs u32 resp, param; 3462316485Sdavidcs enum _ecore_status_t rc; 3463316485Sdavidcs 3464316485Sdavidcs p_ptt = ecore_ptt_acquire(p_hwfn); 3465316485Sdavidcs if (!p_ptt) 3466316485Sdavidcs return ECORE_BUSY; 3467320164Sdavidcs rc = ecore_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_NVM_PUT_FILE_BEGIN, addr, 3468320164Sdavidcs &resp, ¶m); 3469320164Sdavidcs p_dev->mcp_nvm_resp = resp; 3470316485Sdavidcs ecore_ptt_release(p_hwfn, p_ptt); 3471316485Sdavidcs 3472316485Sdavidcs return rc; 3473316485Sdavidcs} 3474316485Sdavidcs 3475320164Sdavidcs/* rc recieves ECORE_INVAL as default parameter because 3476316485Sdavidcs * it might not enter the while loop if the len is 0 3477316485Sdavidcs */ 3478316485Sdavidcsenum _ecore_status_t ecore_mcp_nvm_write(struct ecore_dev *p_dev, u32 cmd, 3479316485Sdavidcs u32 addr, u8 *p_buf, u32 len) 3480316485Sdavidcs{ 3481337517Sdavidcs u32 buf_idx, buf_size, nvm_cmd, nvm_offset, resp = 0, param; 3482316485Sdavidcs struct ecore_hwfn *p_hwfn = ECORE_LEADING_HWFN(p_dev); 3483316485Sdavidcs enum _ecore_status_t rc = ECORE_INVAL; 3484316485Sdavidcs struct ecore_ptt *p_ptt; 3485316485Sdavidcs 3486316485Sdavidcs p_ptt = ecore_ptt_acquire(p_hwfn); 3487316485Sdavidcs if (!p_ptt) 3488316485Sdavidcs return ECORE_BUSY; 3489316485Sdavidcs 3490316485Sdavidcs switch (cmd) { 3491316485Sdavidcs case ECORE_PUT_FILE_DATA: 3492320164Sdavidcs nvm_cmd = DRV_MSG_CODE_NVM_PUT_FILE_DATA; 3493316485Sdavidcs break; 3494316485Sdavidcs case ECORE_NVM_WRITE_NVRAM: 3495320164Sdavidcs nvm_cmd = DRV_MSG_CODE_NVM_WRITE_NVRAM; 3496316485Sdavidcs break; 3497316485Sdavidcs case ECORE_EXT_PHY_FW_UPGRADE: 3498320164Sdavidcs nvm_cmd = DRV_MSG_CODE_EXT_PHY_FW_UPGRADE; 3499316485Sdavidcs break; 3500337517Sdavidcs case ECORE_ENCRYPT_PASSWORD: 3501337517Sdavidcs nvm_cmd = DRV_MSG_CODE_ENCRYPT_PASSWORD; 3502337517Sdavidcs break; 3503316485Sdavidcs default: 3504316485Sdavidcs DP_NOTICE(p_hwfn, true, "Invalid nvm write command 0x%x\n", 3505316485Sdavidcs cmd); 3506337517Sdavidcs rc = ECORE_INVAL; 3507337517Sdavidcs goto out; 3508316485Sdavidcs } 3509316485Sdavidcs 3510316485Sdavidcs buf_idx = 0; 3511316485Sdavidcs while (buf_idx < len) { 3512316485Sdavidcs buf_size = OSAL_MIN_T(u32, (len - buf_idx), 3513316485Sdavidcs MCP_DRV_NVM_BUF_LEN); 3514320164Sdavidcs nvm_offset = ((buf_size << DRV_MB_PARAM_NVM_LEN_OFFSET) | 3515320164Sdavidcs addr) + 3516320164Sdavidcs buf_idx; 3517320164Sdavidcs rc = ecore_mcp_nvm_wr_cmd(p_hwfn, p_ptt, nvm_cmd, nvm_offset, 3518320164Sdavidcs &resp, ¶m, buf_size, 3519320164Sdavidcs (u32 *)&p_buf[buf_idx]); 3520337517Sdavidcs if (rc != ECORE_SUCCESS) { 3521337517Sdavidcs DP_NOTICE(p_dev, false, 3522337517Sdavidcs "ecore_mcp_nvm_write() failed, rc = %d\n", 3523337517Sdavidcs rc); 3524337517Sdavidcs resp = FW_MSG_CODE_ERROR; 3525337517Sdavidcs break; 3526337517Sdavidcs } 3527316485Sdavidcs 3528337517Sdavidcs if (resp != FW_MSG_CODE_OK && 3529337517Sdavidcs resp != FW_MSG_CODE_NVM_OK && 3530337517Sdavidcs resp != FW_MSG_CODE_NVM_PUT_FILE_FINISH_OK) { 3531337517Sdavidcs DP_NOTICE(p_dev, false, 3532337517Sdavidcs "nvm write failed, resp = 0x%08x\n", resp); 3533337517Sdavidcs rc = ECORE_UNKNOWN_ERROR; 3534337517Sdavidcs break; 3535337517Sdavidcs } 3536337517Sdavidcs 3537316485Sdavidcs /* This can be a lengthy process, and it's possible scheduler 3538316485Sdavidcs * isn't preemptable. Sleep a bit to prevent CPU hogging. 3539316485Sdavidcs */ 3540316485Sdavidcs if (buf_idx % 0x1000 > 3541316485Sdavidcs (buf_idx + buf_size) % 0x1000) 3542316485Sdavidcs OSAL_MSLEEP(1); 3543316485Sdavidcs 3544316485Sdavidcs buf_idx += buf_size; 3545316485Sdavidcs } 3546316485Sdavidcs 3547320164Sdavidcs p_dev->mcp_nvm_resp = resp; 3548337517Sdavidcsout: 3549316485Sdavidcs ecore_ptt_release(p_hwfn, p_ptt); 3550316485Sdavidcs 3551316485Sdavidcs return rc; 3552316485Sdavidcs} 3553316485Sdavidcs 3554316485Sdavidcsenum _ecore_status_t ecore_mcp_phy_write(struct ecore_dev *p_dev, u32 cmd, 3555316485Sdavidcs u32 addr, u8 *p_buf, u32 len) 3556316485Sdavidcs{ 3557316485Sdavidcs struct ecore_hwfn *p_hwfn = ECORE_LEADING_HWFN(p_dev); 3558316485Sdavidcs struct ecore_ptt *p_ptt; 3559320164Sdavidcs u32 resp, param, nvm_cmd; 3560316485Sdavidcs enum _ecore_status_t rc; 3561316485Sdavidcs 3562316485Sdavidcs p_ptt = ecore_ptt_acquire(p_hwfn); 3563316485Sdavidcs if (!p_ptt) 3564316485Sdavidcs return ECORE_BUSY; 3565316485Sdavidcs 3566320164Sdavidcs nvm_cmd = (cmd == ECORE_PHY_CORE_WRITE) ? DRV_MSG_CODE_PHY_CORE_WRITE : 3567320164Sdavidcs DRV_MSG_CODE_PHY_RAW_WRITE; 3568320164Sdavidcs rc = ecore_mcp_nvm_wr_cmd(p_hwfn, p_ptt, nvm_cmd, addr, 3569320164Sdavidcs &resp, ¶m, len, (u32 *)p_buf); 3570316485Sdavidcs if (rc != ECORE_SUCCESS) 3571316485Sdavidcs DP_NOTICE(p_dev, false, "MCP command rc = %d\n", rc); 3572320164Sdavidcs p_dev->mcp_nvm_resp = resp; 3573316485Sdavidcs ecore_ptt_release(p_hwfn, p_ptt); 3574316485Sdavidcs 3575316485Sdavidcs return rc; 3576316485Sdavidcs} 3577316485Sdavidcs 3578316485Sdavidcsenum _ecore_status_t ecore_mcp_nvm_set_secure_mode(struct ecore_dev *p_dev, 3579316485Sdavidcs u32 addr) 3580316485Sdavidcs{ 3581316485Sdavidcs struct ecore_hwfn *p_hwfn = ECORE_LEADING_HWFN(p_dev); 3582316485Sdavidcs struct ecore_ptt *p_ptt; 3583320164Sdavidcs u32 resp, param; 3584316485Sdavidcs enum _ecore_status_t rc; 3585316485Sdavidcs 3586316485Sdavidcs p_ptt = ecore_ptt_acquire(p_hwfn); 3587316485Sdavidcs if (!p_ptt) 3588316485Sdavidcs return ECORE_BUSY; 3589316485Sdavidcs 3590320164Sdavidcs rc = ecore_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_SET_SECURE_MODE, addr, 3591320164Sdavidcs &resp, ¶m); 3592320164Sdavidcs p_dev->mcp_nvm_resp = resp; 3593316485Sdavidcs ecore_ptt_release(p_hwfn, p_ptt); 3594316485Sdavidcs 3595316485Sdavidcs return rc; 3596316485Sdavidcs} 3597316485Sdavidcs 3598316485Sdavidcsenum _ecore_status_t ecore_mcp_phy_sfp_read(struct ecore_hwfn *p_hwfn, 3599316485Sdavidcs struct ecore_ptt *p_ptt, 3600316485Sdavidcs u32 port, u32 addr, u32 offset, 3601316485Sdavidcs u32 len, u8 *p_buf) 3602316485Sdavidcs{ 3603320164Sdavidcs u32 bytes_left, bytes_to_copy, buf_size, nvm_offset; 3604320164Sdavidcs u32 resp, param; 3605316485Sdavidcs enum _ecore_status_t rc; 3606316485Sdavidcs 3607320164Sdavidcs nvm_offset = (port << DRV_MB_PARAM_TRANSCEIVER_PORT_OFFSET) | 3608320164Sdavidcs (addr << DRV_MB_PARAM_TRANSCEIVER_I2C_ADDRESS_OFFSET); 3609316485Sdavidcs addr = offset; 3610316485Sdavidcs offset = 0; 3611316485Sdavidcs bytes_left = len; 3612316485Sdavidcs while (bytes_left > 0) { 3613316485Sdavidcs bytes_to_copy = OSAL_MIN_T(u32, bytes_left, 3614316485Sdavidcs MAX_I2C_TRANSACTION_SIZE); 3615320164Sdavidcs nvm_offset &= (DRV_MB_PARAM_TRANSCEIVER_I2C_ADDRESS_MASK | 3616320164Sdavidcs DRV_MB_PARAM_TRANSCEIVER_PORT_MASK); 3617320164Sdavidcs nvm_offset |= ((addr + offset) << 3618320164Sdavidcs DRV_MB_PARAM_TRANSCEIVER_OFFSET_OFFSET); 3619320164Sdavidcs nvm_offset |= (bytes_to_copy << 3620320164Sdavidcs DRV_MB_PARAM_TRANSCEIVER_SIZE_OFFSET); 3621320164Sdavidcs rc = ecore_mcp_nvm_rd_cmd(p_hwfn, p_ptt, 3622320164Sdavidcs DRV_MSG_CODE_TRANSCEIVER_READ, 3623320164Sdavidcs nvm_offset, &resp, ¶m, &buf_size, 3624320164Sdavidcs (u32 *)(p_buf + offset)); 3625320164Sdavidcs if (rc != ECORE_SUCCESS) { 3626320164Sdavidcs DP_NOTICE(p_hwfn, false, 3627320164Sdavidcs "Failed to send a transceiver read command to the MFW. rc = %d.\n", 3628320164Sdavidcs rc); 3629320164Sdavidcs return rc; 3630320164Sdavidcs } 3631320164Sdavidcs 3632320164Sdavidcs if (resp == FW_MSG_CODE_TRANSCEIVER_NOT_PRESENT) 3633316485Sdavidcs return ECORE_NODEV; 3634320164Sdavidcs else if (resp != FW_MSG_CODE_TRANSCEIVER_DIAG_OK) 3635316485Sdavidcs return ECORE_UNKNOWN_ERROR; 3636316485Sdavidcs 3637320164Sdavidcs offset += buf_size; 3638320164Sdavidcs bytes_left -= buf_size; 3639316485Sdavidcs } 3640316485Sdavidcs 3641316485Sdavidcs return ECORE_SUCCESS; 3642316485Sdavidcs} 3643316485Sdavidcs 3644316485Sdavidcsenum _ecore_status_t ecore_mcp_phy_sfp_write(struct ecore_hwfn *p_hwfn, 3645316485Sdavidcs struct ecore_ptt *p_ptt, 3646316485Sdavidcs u32 port, u32 addr, u32 offset, 3647316485Sdavidcs u32 len, u8 *p_buf) 3648316485Sdavidcs{ 3649320164Sdavidcs u32 buf_idx, buf_size, nvm_offset, resp, param; 3650316485Sdavidcs enum _ecore_status_t rc; 3651316485Sdavidcs 3652320164Sdavidcs nvm_offset = (port << DRV_MB_PARAM_TRANSCEIVER_PORT_OFFSET) | 3653320164Sdavidcs (addr << DRV_MB_PARAM_TRANSCEIVER_I2C_ADDRESS_OFFSET); 3654316485Sdavidcs buf_idx = 0; 3655316485Sdavidcs while (buf_idx < len) { 3656316485Sdavidcs buf_size = OSAL_MIN_T(u32, (len - buf_idx), 3657316485Sdavidcs MAX_I2C_TRANSACTION_SIZE); 3658320164Sdavidcs nvm_offset &= (DRV_MB_PARAM_TRANSCEIVER_I2C_ADDRESS_MASK | 3659320164Sdavidcs DRV_MB_PARAM_TRANSCEIVER_PORT_MASK); 3660320164Sdavidcs nvm_offset |= ((offset + buf_idx) << 3661320164Sdavidcs DRV_MB_PARAM_TRANSCEIVER_OFFSET_OFFSET); 3662320164Sdavidcs nvm_offset |= (buf_size << 3663320164Sdavidcs DRV_MB_PARAM_TRANSCEIVER_SIZE_OFFSET); 3664320164Sdavidcs rc = ecore_mcp_nvm_wr_cmd(p_hwfn, p_ptt, 3665320164Sdavidcs DRV_MSG_CODE_TRANSCEIVER_WRITE, 3666320164Sdavidcs nvm_offset, &resp, ¶m, buf_size, 3667320164Sdavidcs (u32 *)&p_buf[buf_idx]); 3668320164Sdavidcs if (rc != ECORE_SUCCESS) { 3669320164Sdavidcs DP_NOTICE(p_hwfn, false, 3670320164Sdavidcs "Failed to send a transceiver write command to the MFW. rc = %d.\n", 3671320164Sdavidcs rc); 3672320164Sdavidcs return rc; 3673320164Sdavidcs } 3674320164Sdavidcs 3675320164Sdavidcs if (resp == FW_MSG_CODE_TRANSCEIVER_NOT_PRESENT) 3676316485Sdavidcs return ECORE_NODEV; 3677320164Sdavidcs else if (resp != FW_MSG_CODE_TRANSCEIVER_DIAG_OK) 3678316485Sdavidcs return ECORE_UNKNOWN_ERROR; 3679316485Sdavidcs 3680316485Sdavidcs buf_idx += buf_size; 3681316485Sdavidcs } 3682316485Sdavidcs 3683316485Sdavidcs return ECORE_SUCCESS; 3684316485Sdavidcs} 3685316485Sdavidcs 3686316485Sdavidcsenum _ecore_status_t ecore_mcp_gpio_read(struct ecore_hwfn *p_hwfn, 3687316485Sdavidcs struct ecore_ptt *p_ptt, 3688316485Sdavidcs u16 gpio, u32 *gpio_val) 3689316485Sdavidcs{ 3690316485Sdavidcs enum _ecore_status_t rc = ECORE_SUCCESS; 3691316485Sdavidcs u32 drv_mb_param = 0, rsp; 3692316485Sdavidcs 3693320164Sdavidcs drv_mb_param = (gpio << DRV_MB_PARAM_GPIO_NUMBER_OFFSET); 3694316485Sdavidcs 3695316485Sdavidcs rc = ecore_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_GPIO_READ, 3696316485Sdavidcs drv_mb_param, &rsp, gpio_val); 3697316485Sdavidcs 3698316485Sdavidcs if (rc != ECORE_SUCCESS) 3699316485Sdavidcs return rc; 3700316485Sdavidcs 3701316485Sdavidcs if ((rsp & FW_MSG_CODE_MASK) != FW_MSG_CODE_GPIO_OK) 3702316485Sdavidcs return ECORE_UNKNOWN_ERROR; 3703316485Sdavidcs 3704316485Sdavidcs return ECORE_SUCCESS; 3705316485Sdavidcs} 3706316485Sdavidcs 3707316485Sdavidcsenum _ecore_status_t ecore_mcp_gpio_write(struct ecore_hwfn *p_hwfn, 3708316485Sdavidcs struct ecore_ptt *p_ptt, 3709316485Sdavidcs u16 gpio, u16 gpio_val) 3710316485Sdavidcs{ 3711316485Sdavidcs enum _ecore_status_t rc = ECORE_SUCCESS; 3712316485Sdavidcs u32 drv_mb_param = 0, param, rsp; 3713316485Sdavidcs 3714320164Sdavidcs drv_mb_param = (gpio << DRV_MB_PARAM_GPIO_NUMBER_OFFSET) | 3715320164Sdavidcs (gpio_val << DRV_MB_PARAM_GPIO_VALUE_OFFSET); 3716316485Sdavidcs 3717316485Sdavidcs rc = ecore_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_GPIO_WRITE, 3718316485Sdavidcs drv_mb_param, &rsp, ¶m); 3719316485Sdavidcs 3720316485Sdavidcs if (rc != ECORE_SUCCESS) 3721316485Sdavidcs return rc; 3722316485Sdavidcs 3723316485Sdavidcs if ((rsp & FW_MSG_CODE_MASK) != FW_MSG_CODE_GPIO_OK) 3724316485Sdavidcs return ECORE_UNKNOWN_ERROR; 3725316485Sdavidcs 3726316485Sdavidcs return ECORE_SUCCESS; 3727316485Sdavidcs} 3728316485Sdavidcs 3729316485Sdavidcsenum _ecore_status_t ecore_mcp_gpio_info(struct ecore_hwfn *p_hwfn, 3730316485Sdavidcs struct ecore_ptt *p_ptt, 3731316485Sdavidcs u16 gpio, u32 *gpio_direction, 3732316485Sdavidcs u32 *gpio_ctrl) 3733316485Sdavidcs{ 3734316485Sdavidcs u32 drv_mb_param = 0, rsp, val = 0; 3735316485Sdavidcs enum _ecore_status_t rc = ECORE_SUCCESS; 3736316485Sdavidcs 3737320164Sdavidcs drv_mb_param = gpio << DRV_MB_PARAM_GPIO_NUMBER_OFFSET; 3738316485Sdavidcs 3739316485Sdavidcs rc = ecore_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_GPIO_INFO, 3740316485Sdavidcs drv_mb_param, &rsp, &val); 3741316485Sdavidcs if (rc != ECORE_SUCCESS) 3742316485Sdavidcs return rc; 3743316485Sdavidcs 3744316485Sdavidcs *gpio_direction = (val & DRV_MB_PARAM_GPIO_DIRECTION_MASK) >> 3745320164Sdavidcs DRV_MB_PARAM_GPIO_DIRECTION_OFFSET; 3746316485Sdavidcs *gpio_ctrl = (val & DRV_MB_PARAM_GPIO_CTRL_MASK) >> 3747320164Sdavidcs DRV_MB_PARAM_GPIO_CTRL_OFFSET; 3748316485Sdavidcs 3749316485Sdavidcs if ((rsp & FW_MSG_CODE_MASK) != FW_MSG_CODE_GPIO_OK) 3750316485Sdavidcs return ECORE_UNKNOWN_ERROR; 3751316485Sdavidcs 3752316485Sdavidcs return ECORE_SUCCESS; 3753316485Sdavidcs} 3754316485Sdavidcs 3755316485Sdavidcsenum _ecore_status_t ecore_mcp_bist_register_test(struct ecore_hwfn *p_hwfn, 3756316485Sdavidcs struct ecore_ptt *p_ptt) 3757316485Sdavidcs{ 3758316485Sdavidcs u32 drv_mb_param = 0, rsp, param; 3759316485Sdavidcs enum _ecore_status_t rc = ECORE_SUCCESS; 3760316485Sdavidcs 3761316485Sdavidcs drv_mb_param = (DRV_MB_PARAM_BIST_REGISTER_TEST << 3762320164Sdavidcs DRV_MB_PARAM_BIST_TEST_INDEX_OFFSET); 3763316485Sdavidcs 3764316485Sdavidcs rc = ecore_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_BIST_TEST, 3765316485Sdavidcs drv_mb_param, &rsp, ¶m); 3766316485Sdavidcs 3767316485Sdavidcs if (rc != ECORE_SUCCESS) 3768316485Sdavidcs return rc; 3769316485Sdavidcs 3770316485Sdavidcs if (((rsp & FW_MSG_CODE_MASK) != FW_MSG_CODE_OK) || 3771316485Sdavidcs (param != DRV_MB_PARAM_BIST_RC_PASSED)) 3772316485Sdavidcs rc = ECORE_UNKNOWN_ERROR; 3773316485Sdavidcs 3774316485Sdavidcs return rc; 3775316485Sdavidcs} 3776316485Sdavidcs 3777316485Sdavidcsenum _ecore_status_t ecore_mcp_bist_clock_test(struct ecore_hwfn *p_hwfn, 3778316485Sdavidcs struct ecore_ptt *p_ptt) 3779316485Sdavidcs{ 3780316485Sdavidcs u32 drv_mb_param, rsp, param; 3781316485Sdavidcs enum _ecore_status_t rc = ECORE_SUCCESS; 3782316485Sdavidcs 3783316485Sdavidcs drv_mb_param = (DRV_MB_PARAM_BIST_CLOCK_TEST << 3784320164Sdavidcs DRV_MB_PARAM_BIST_TEST_INDEX_OFFSET); 3785316485Sdavidcs 3786316485Sdavidcs rc = ecore_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_BIST_TEST, 3787316485Sdavidcs drv_mb_param, &rsp, ¶m); 3788316485Sdavidcs 3789316485Sdavidcs if (rc != ECORE_SUCCESS) 3790316485Sdavidcs return rc; 3791316485Sdavidcs 3792316485Sdavidcs if (((rsp & FW_MSG_CODE_MASK) != FW_MSG_CODE_OK) || 3793316485Sdavidcs (param != DRV_MB_PARAM_BIST_RC_PASSED)) 3794316485Sdavidcs rc = ECORE_UNKNOWN_ERROR; 3795316485Sdavidcs 3796316485Sdavidcs return rc; 3797316485Sdavidcs} 3798316485Sdavidcs 3799316485Sdavidcsenum _ecore_status_t ecore_mcp_bist_nvm_test_get_num_images( 3800316485Sdavidcs struct ecore_hwfn *p_hwfn, struct ecore_ptt *p_ptt, u32 *num_images) 3801316485Sdavidcs{ 3802316485Sdavidcs u32 drv_mb_param = 0, rsp; 3803316485Sdavidcs enum _ecore_status_t rc = ECORE_SUCCESS; 3804316485Sdavidcs 3805316485Sdavidcs drv_mb_param = (DRV_MB_PARAM_BIST_NVM_TEST_NUM_IMAGES << 3806320164Sdavidcs DRV_MB_PARAM_BIST_TEST_INDEX_OFFSET); 3807316485Sdavidcs 3808316485Sdavidcs rc = ecore_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_BIST_TEST, 3809316485Sdavidcs drv_mb_param, &rsp, num_images); 3810316485Sdavidcs 3811316485Sdavidcs if (rc != ECORE_SUCCESS) 3812316485Sdavidcs return rc; 3813316485Sdavidcs 3814316485Sdavidcs if (((rsp & FW_MSG_CODE_MASK) != FW_MSG_CODE_OK)) 3815316485Sdavidcs rc = ECORE_UNKNOWN_ERROR; 3816316485Sdavidcs 3817316485Sdavidcs return rc; 3818316485Sdavidcs} 3819316485Sdavidcs 3820316485Sdavidcsenum _ecore_status_t ecore_mcp_bist_nvm_test_get_image_att( 3821316485Sdavidcs struct ecore_hwfn *p_hwfn, struct ecore_ptt *p_ptt, 3822316485Sdavidcs struct bist_nvm_image_att *p_image_att, u32 image_index) 3823316485Sdavidcs{ 3824320164Sdavidcs u32 buf_size, nvm_offset, resp, param; 3825316485Sdavidcs enum _ecore_status_t rc; 3826316485Sdavidcs 3827320164Sdavidcs nvm_offset = (DRV_MB_PARAM_BIST_NVM_TEST_IMAGE_BY_INDEX << 3828320164Sdavidcs DRV_MB_PARAM_BIST_TEST_INDEX_OFFSET); 3829320164Sdavidcs nvm_offset |= (image_index << 3830320164Sdavidcs DRV_MB_PARAM_BIST_TEST_IMAGE_INDEX_OFFSET); 3831320164Sdavidcs rc = ecore_mcp_nvm_rd_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_BIST_TEST, 3832320164Sdavidcs nvm_offset, &resp, ¶m, &buf_size, 3833320164Sdavidcs (u32 *)p_image_att); 3834316485Sdavidcs if (rc != ECORE_SUCCESS) 3835316485Sdavidcs return rc; 3836316485Sdavidcs 3837320164Sdavidcs if (((resp & FW_MSG_CODE_MASK) != FW_MSG_CODE_OK) || 3838316485Sdavidcs (p_image_att->return_code != 1)) 3839316485Sdavidcs rc = ECORE_UNKNOWN_ERROR; 3840316485Sdavidcs 3841316485Sdavidcs return rc; 3842316485Sdavidcs} 3843316485Sdavidcs 3844316485Sdavidcsenum _ecore_status_t 3845316485Sdavidcsecore_mcp_get_nvm_image_att(struct ecore_hwfn *p_hwfn, struct ecore_ptt *p_ptt, 3846316485Sdavidcs enum ecore_nvm_images image_id, 3847316485Sdavidcs struct ecore_nvm_image_att *p_image_att) 3848316485Sdavidcs{ 3849316485Sdavidcs struct bist_nvm_image_att mfw_image_att; 3850316485Sdavidcs enum nvm_image_type type; 3851316485Sdavidcs u32 num_images, i; 3852316485Sdavidcs enum _ecore_status_t rc; 3853316485Sdavidcs 3854316485Sdavidcs /* Translate image_id into MFW definitions */ 3855316485Sdavidcs switch (image_id) { 3856316485Sdavidcs case ECORE_NVM_IMAGE_ISCSI_CFG: 3857316485Sdavidcs type = NVM_TYPE_ISCSI_CFG; 3858316485Sdavidcs break; 3859316485Sdavidcs case ECORE_NVM_IMAGE_FCOE_CFG: 3860316485Sdavidcs type = NVM_TYPE_FCOE_CFG; 3861316485Sdavidcs break; 3862316485Sdavidcs case ECORE_NVM_IMAGE_MDUMP: 3863316485Sdavidcs type = NVM_TYPE_MDUMP; 3864316485Sdavidcs break; 3865316485Sdavidcs default: 3866316485Sdavidcs DP_NOTICE(p_hwfn, false, "Unknown request of image_id %08x\n", 3867316485Sdavidcs image_id); 3868316485Sdavidcs return ECORE_INVAL; 3869316485Sdavidcs } 3870316485Sdavidcs 3871316485Sdavidcs /* Learn number of images, then traverse and see if one fits */ 3872316485Sdavidcs rc = ecore_mcp_bist_nvm_test_get_num_images(p_hwfn, p_ptt, &num_images); 3873316485Sdavidcs if (rc != ECORE_SUCCESS || !num_images) 3874316485Sdavidcs return ECORE_INVAL; 3875316485Sdavidcs 3876316485Sdavidcs for (i = 0; i < num_images; i++) { 3877316485Sdavidcs rc = ecore_mcp_bist_nvm_test_get_image_att(p_hwfn, p_ptt, 3878316485Sdavidcs &mfw_image_att, i); 3879316485Sdavidcs if (rc != ECORE_SUCCESS) 3880316485Sdavidcs return rc; 3881316485Sdavidcs 3882316485Sdavidcs if (type == mfw_image_att.image_type) 3883316485Sdavidcs break; 3884316485Sdavidcs } 3885316485Sdavidcs if (i == num_images) { 3886316485Sdavidcs DP_VERBOSE(p_hwfn, ECORE_MSG_STORAGE, 3887316485Sdavidcs "Failed to find nvram image of type %08x\n", 3888316485Sdavidcs image_id); 3889316485Sdavidcs return ECORE_INVAL; 3890316485Sdavidcs } 3891316485Sdavidcs 3892316485Sdavidcs p_image_att->start_addr = mfw_image_att.nvm_start_addr; 3893316485Sdavidcs p_image_att->length = mfw_image_att.len; 3894316485Sdavidcs 3895316485Sdavidcs return ECORE_SUCCESS; 3896316485Sdavidcs} 3897316485Sdavidcs 3898316485Sdavidcsenum _ecore_status_t ecore_mcp_get_nvm_image(struct ecore_hwfn *p_hwfn, 3899316485Sdavidcs struct ecore_ptt *p_ptt, 3900316485Sdavidcs enum ecore_nvm_images image_id, 3901316485Sdavidcs u8 *p_buffer, u32 buffer_len) 3902316485Sdavidcs{ 3903316485Sdavidcs struct ecore_nvm_image_att image_att; 3904316485Sdavidcs enum _ecore_status_t rc; 3905316485Sdavidcs 3906316485Sdavidcs OSAL_MEM_ZERO(p_buffer, buffer_len); 3907316485Sdavidcs 3908316485Sdavidcs rc = ecore_mcp_get_nvm_image_att(p_hwfn, p_ptt, image_id, &image_att); 3909316485Sdavidcs if (rc != ECORE_SUCCESS) 3910316485Sdavidcs return rc; 3911316485Sdavidcs 3912316485Sdavidcs /* Validate sizes - both the image's and the supplied buffer's */ 3913316485Sdavidcs if (image_att.length <= 4) { 3914316485Sdavidcs DP_VERBOSE(p_hwfn, ECORE_MSG_STORAGE, 3915316485Sdavidcs "Image [%d] is too small - only %d bytes\n", 3916316485Sdavidcs image_id, image_att.length); 3917316485Sdavidcs return ECORE_INVAL; 3918316485Sdavidcs } 3919316485Sdavidcs 3920316485Sdavidcs /* Each NVM image is suffixed by CRC; Upper-layer has no need for it */ 3921316485Sdavidcs image_att.length -= 4; 3922316485Sdavidcs 3923316485Sdavidcs if (image_att.length > buffer_len) { 3924316485Sdavidcs DP_VERBOSE(p_hwfn, ECORE_MSG_STORAGE, 3925316485Sdavidcs "Image [%d] is too big - %08x bytes where only %08x are available\n", 3926316485Sdavidcs image_id, image_att.length, buffer_len); 3927316485Sdavidcs return ECORE_NOMEM; 3928316485Sdavidcs } 3929316485Sdavidcs 3930316485Sdavidcs return ecore_mcp_nvm_read(p_hwfn->p_dev, image_att.start_addr, 3931316485Sdavidcs p_buffer, image_att.length); 3932316485Sdavidcs} 3933316485Sdavidcs 3934316485Sdavidcsenum _ecore_status_t 3935316485Sdavidcsecore_mcp_get_temperature_info(struct ecore_hwfn *p_hwfn, 3936316485Sdavidcs struct ecore_ptt *p_ptt, 3937316485Sdavidcs struct ecore_temperature_info *p_temp_info) 3938316485Sdavidcs{ 3939316485Sdavidcs struct ecore_temperature_sensor *p_temp_sensor; 3940316485Sdavidcs struct temperature_status_stc mfw_temp_info; 3941316485Sdavidcs struct ecore_mcp_mb_params mb_params; 3942316485Sdavidcs u32 val; 3943316485Sdavidcs enum _ecore_status_t rc; 3944316485Sdavidcs u8 i; 3945316485Sdavidcs 3946316485Sdavidcs OSAL_MEM_ZERO(&mb_params, sizeof(mb_params)); 3947316485Sdavidcs mb_params.cmd = DRV_MSG_CODE_GET_TEMPERATURE; 3948316485Sdavidcs mb_params.p_data_dst = &mfw_temp_info; 3949316485Sdavidcs mb_params.data_dst_size = sizeof(mfw_temp_info); 3950316485Sdavidcs rc = ecore_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 3951316485Sdavidcs if (rc != ECORE_SUCCESS) 3952316485Sdavidcs return rc; 3953316485Sdavidcs 3954316485Sdavidcs OSAL_BUILD_BUG_ON(ECORE_MAX_NUM_OF_SENSORS != MAX_NUM_OF_SENSORS); 3955316485Sdavidcs p_temp_info->num_sensors = OSAL_MIN_T(u32, mfw_temp_info.num_of_sensors, 3956316485Sdavidcs ECORE_MAX_NUM_OF_SENSORS); 3957316485Sdavidcs for (i = 0; i < p_temp_info->num_sensors; i++) { 3958316485Sdavidcs val = mfw_temp_info.sensor[i]; 3959316485Sdavidcs p_temp_sensor = &p_temp_info->sensors[i]; 3960316485Sdavidcs p_temp_sensor->sensor_location = (val & SENSOR_LOCATION_MASK) >> 3961320164Sdavidcs SENSOR_LOCATION_OFFSET; 3962316485Sdavidcs p_temp_sensor->threshold_high = (val & THRESHOLD_HIGH_MASK) >> 3963320164Sdavidcs THRESHOLD_HIGH_OFFSET; 3964316485Sdavidcs p_temp_sensor->critical = (val & CRITICAL_TEMPERATURE_MASK) >> 3965320164Sdavidcs CRITICAL_TEMPERATURE_OFFSET; 3966316485Sdavidcs p_temp_sensor->current_temp = (val & CURRENT_TEMP_MASK) >> 3967320164Sdavidcs CURRENT_TEMP_OFFSET; 3968316485Sdavidcs } 3969316485Sdavidcs 3970316485Sdavidcs return ECORE_SUCCESS; 3971316485Sdavidcs} 3972316485Sdavidcs 3973316485Sdavidcsenum _ecore_status_t ecore_mcp_get_mba_versions( 3974316485Sdavidcs struct ecore_hwfn *p_hwfn, 3975316485Sdavidcs struct ecore_ptt *p_ptt, 3976316485Sdavidcs struct ecore_mba_vers *p_mba_vers) 3977316485Sdavidcs{ 3978320164Sdavidcs u32 buf_size, resp, param; 3979316485Sdavidcs enum _ecore_status_t rc; 3980316485Sdavidcs 3981320164Sdavidcs rc = ecore_mcp_nvm_rd_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_GET_MBA_VERSION, 3982320164Sdavidcs 0, &resp, ¶m, &buf_size, 3983320164Sdavidcs &(p_mba_vers->mba_vers[0])); 3984316485Sdavidcs 3985316485Sdavidcs if (rc != ECORE_SUCCESS) 3986316485Sdavidcs return rc; 3987316485Sdavidcs 3988320164Sdavidcs if ((resp & FW_MSG_CODE_MASK) != FW_MSG_CODE_NVM_OK) 3989316485Sdavidcs rc = ECORE_UNKNOWN_ERROR; 3990316485Sdavidcs 3991316485Sdavidcs if (buf_size != MCP_DRV_NVM_BUF_LEN) 3992316485Sdavidcs rc = ECORE_UNKNOWN_ERROR; 3993316485Sdavidcs 3994316485Sdavidcs return rc; 3995316485Sdavidcs} 3996316485Sdavidcs 3997316485Sdavidcsenum _ecore_status_t ecore_mcp_mem_ecc_events(struct ecore_hwfn *p_hwfn, 3998316485Sdavidcs struct ecore_ptt *p_ptt, 3999316485Sdavidcs u64 *num_events) 4000316485Sdavidcs{ 4001337517Sdavidcs struct ecore_mcp_mb_params mb_params; 4002316485Sdavidcs 4003337517Sdavidcs OSAL_MEMSET(&mb_params, 0, sizeof(struct ecore_mcp_mb_params)); 4004337517Sdavidcs mb_params.cmd = DRV_MSG_CODE_MEM_ECC_EVENTS; 4005337517Sdavidcs mb_params.p_data_dst = (union drv_union_data *)num_events; 4006337517Sdavidcs 4007337517Sdavidcs return ecore_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 4008316485Sdavidcs} 4009316485Sdavidcs 4010316485Sdavidcsstatic enum resource_id_enum 4011316485Sdavidcsecore_mcp_get_mfw_res_id(enum ecore_resources res_id) 4012316485Sdavidcs{ 4013316485Sdavidcs enum resource_id_enum mfw_res_id = RESOURCE_NUM_INVALID; 4014316485Sdavidcs 4015316485Sdavidcs switch (res_id) { 4016316485Sdavidcs case ECORE_SB: 4017316485Sdavidcs mfw_res_id = RESOURCE_NUM_SB_E; 4018316485Sdavidcs break; 4019316485Sdavidcs case ECORE_L2_QUEUE: 4020316485Sdavidcs mfw_res_id = RESOURCE_NUM_L2_QUEUE_E; 4021316485Sdavidcs break; 4022316485Sdavidcs case ECORE_VPORT: 4023316485Sdavidcs mfw_res_id = RESOURCE_NUM_VPORT_E; 4024316485Sdavidcs break; 4025316485Sdavidcs case ECORE_RSS_ENG: 4026316485Sdavidcs mfw_res_id = RESOURCE_NUM_RSS_ENGINES_E; 4027316485Sdavidcs break; 4028316485Sdavidcs case ECORE_PQ: 4029316485Sdavidcs mfw_res_id = RESOURCE_NUM_PQ_E; 4030316485Sdavidcs break; 4031316485Sdavidcs case ECORE_RL: 4032316485Sdavidcs mfw_res_id = RESOURCE_NUM_RL_E; 4033316485Sdavidcs break; 4034316485Sdavidcs case ECORE_MAC: 4035316485Sdavidcs case ECORE_VLAN: 4036316485Sdavidcs /* Each VFC resource can accommodate both a MAC and a VLAN */ 4037316485Sdavidcs mfw_res_id = RESOURCE_VFC_FILTER_E; 4038316485Sdavidcs break; 4039316485Sdavidcs case ECORE_ILT: 4040316485Sdavidcs mfw_res_id = RESOURCE_ILT_E; 4041316485Sdavidcs break; 4042316485Sdavidcs case ECORE_LL2_QUEUE: 4043316485Sdavidcs mfw_res_id = RESOURCE_LL2_QUEUE_E; 4044316485Sdavidcs break; 4045316485Sdavidcs case ECORE_RDMA_CNQ_RAM: 4046316485Sdavidcs case ECORE_CMDQS_CQS: 4047316485Sdavidcs /* CNQ/CMDQS are the same resource */ 4048316485Sdavidcs mfw_res_id = RESOURCE_CQS_E; 4049316485Sdavidcs break; 4050316485Sdavidcs case ECORE_RDMA_STATS_QUEUE: 4051316485Sdavidcs mfw_res_id = RESOURCE_RDMA_STATS_QUEUE_E; 4052316485Sdavidcs break; 4053316485Sdavidcs case ECORE_BDQ: 4054316485Sdavidcs mfw_res_id = RESOURCE_BDQ_E; 4055316485Sdavidcs break; 4056316485Sdavidcs default: 4057316485Sdavidcs break; 4058316485Sdavidcs } 4059316485Sdavidcs 4060316485Sdavidcs return mfw_res_id; 4061316485Sdavidcs} 4062316485Sdavidcs 4063316485Sdavidcs#define ECORE_RESC_ALLOC_VERSION_MAJOR 2 4064316485Sdavidcs#define ECORE_RESC_ALLOC_VERSION_MINOR 0 4065316485Sdavidcs#define ECORE_RESC_ALLOC_VERSION \ 4066316485Sdavidcs ((ECORE_RESC_ALLOC_VERSION_MAJOR << \ 4067320164Sdavidcs DRV_MB_PARAM_RESOURCE_ALLOC_VERSION_MAJOR_OFFSET) | \ 4068316485Sdavidcs (ECORE_RESC_ALLOC_VERSION_MINOR << \ 4069320164Sdavidcs DRV_MB_PARAM_RESOURCE_ALLOC_VERSION_MINOR_OFFSET)) 4070316485Sdavidcs 4071316485Sdavidcsstruct ecore_resc_alloc_in_params { 4072316485Sdavidcs u32 cmd; 4073316485Sdavidcs enum ecore_resources res_id; 4074316485Sdavidcs u32 resc_max_val; 4075316485Sdavidcs}; 4076316485Sdavidcs 4077316485Sdavidcsstruct ecore_resc_alloc_out_params { 4078316485Sdavidcs u32 mcp_resp; 4079316485Sdavidcs u32 mcp_param; 4080316485Sdavidcs u32 resc_num; 4081316485Sdavidcs u32 resc_start; 4082316485Sdavidcs u32 vf_resc_num; 4083316485Sdavidcs u32 vf_resc_start; 4084316485Sdavidcs u32 flags; 4085316485Sdavidcs}; 4086316485Sdavidcs 4087316485Sdavidcsstatic enum _ecore_status_t 4088316485Sdavidcsecore_mcp_resc_allocation_msg(struct ecore_hwfn *p_hwfn, 4089316485Sdavidcs struct ecore_ptt *p_ptt, 4090316485Sdavidcs struct ecore_resc_alloc_in_params *p_in_params, 4091316485Sdavidcs struct ecore_resc_alloc_out_params *p_out_params) 4092316485Sdavidcs{ 4093316485Sdavidcs struct ecore_mcp_mb_params mb_params; 4094316485Sdavidcs struct resource_info mfw_resc_info; 4095316485Sdavidcs enum _ecore_status_t rc; 4096316485Sdavidcs 4097316485Sdavidcs OSAL_MEM_ZERO(&mfw_resc_info, sizeof(mfw_resc_info)); 4098316485Sdavidcs 4099316485Sdavidcs mfw_resc_info.res_id = ecore_mcp_get_mfw_res_id(p_in_params->res_id); 4100316485Sdavidcs if (mfw_resc_info.res_id == RESOURCE_NUM_INVALID) { 4101316485Sdavidcs DP_ERR(p_hwfn, 4102316485Sdavidcs "Failed to match resource %d [%s] with the MFW resources\n", 4103316485Sdavidcs p_in_params->res_id, 4104316485Sdavidcs ecore_hw_get_resc_name(p_in_params->res_id)); 4105316485Sdavidcs return ECORE_INVAL; 4106316485Sdavidcs } 4107316485Sdavidcs 4108316485Sdavidcs switch (p_in_params->cmd) { 4109316485Sdavidcs case DRV_MSG_SET_RESOURCE_VALUE_MSG: 4110316485Sdavidcs mfw_resc_info.size = p_in_params->resc_max_val; 4111316485Sdavidcs /* Fallthrough */ 4112316485Sdavidcs case DRV_MSG_GET_RESOURCE_ALLOC_MSG: 4113316485Sdavidcs break; 4114316485Sdavidcs default: 4115316485Sdavidcs DP_ERR(p_hwfn, "Unexpected resource alloc command [0x%08x]\n", 4116316485Sdavidcs p_in_params->cmd); 4117316485Sdavidcs return ECORE_INVAL; 4118316485Sdavidcs } 4119316485Sdavidcs 4120316485Sdavidcs OSAL_MEM_ZERO(&mb_params, sizeof(mb_params)); 4121316485Sdavidcs mb_params.cmd = p_in_params->cmd; 4122316485Sdavidcs mb_params.param = ECORE_RESC_ALLOC_VERSION; 4123316485Sdavidcs mb_params.p_data_src = &mfw_resc_info; 4124316485Sdavidcs mb_params.data_src_size = sizeof(mfw_resc_info); 4125316485Sdavidcs mb_params.p_data_dst = mb_params.p_data_src; 4126316485Sdavidcs mb_params.data_dst_size = mb_params.data_src_size; 4127316485Sdavidcs 4128316485Sdavidcs DP_VERBOSE(p_hwfn, ECORE_MSG_SP, 4129316485Sdavidcs "Resource message request: cmd 0x%08x, res_id %d [%s], hsi_version %d.%d, val 0x%x\n", 4130316485Sdavidcs p_in_params->cmd, p_in_params->res_id, 4131316485Sdavidcs ecore_hw_get_resc_name(p_in_params->res_id), 4132320164Sdavidcs GET_MFW_FIELD(mb_params.param, 4133320164Sdavidcs DRV_MB_PARAM_RESOURCE_ALLOC_VERSION_MAJOR), 4134320164Sdavidcs GET_MFW_FIELD(mb_params.param, 4135320164Sdavidcs DRV_MB_PARAM_RESOURCE_ALLOC_VERSION_MINOR), 4136316485Sdavidcs p_in_params->resc_max_val); 4137316485Sdavidcs 4138316485Sdavidcs rc = ecore_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 4139316485Sdavidcs if (rc != ECORE_SUCCESS) 4140316485Sdavidcs return rc; 4141316485Sdavidcs 4142316485Sdavidcs p_out_params->mcp_resp = mb_params.mcp_resp; 4143316485Sdavidcs p_out_params->mcp_param = mb_params.mcp_param; 4144316485Sdavidcs p_out_params->resc_num = mfw_resc_info.size; 4145316485Sdavidcs p_out_params->resc_start = mfw_resc_info.offset; 4146316485Sdavidcs p_out_params->vf_resc_num = mfw_resc_info.vf_size; 4147316485Sdavidcs p_out_params->vf_resc_start = mfw_resc_info.vf_offset; 4148316485Sdavidcs p_out_params->flags = mfw_resc_info.flags; 4149316485Sdavidcs 4150316485Sdavidcs DP_VERBOSE(p_hwfn, ECORE_MSG_SP, 4151316485Sdavidcs "Resource message response: mfw_hsi_version %d.%d, num 0x%x, start 0x%x, vf_num 0x%x, vf_start 0x%x, flags 0x%08x\n", 4152320164Sdavidcs GET_MFW_FIELD(p_out_params->mcp_param, 4153320164Sdavidcs FW_MB_PARAM_RESOURCE_ALLOC_VERSION_MAJOR), 4154320164Sdavidcs GET_MFW_FIELD(p_out_params->mcp_param, 4155320164Sdavidcs FW_MB_PARAM_RESOURCE_ALLOC_VERSION_MINOR), 4156316485Sdavidcs p_out_params->resc_num, p_out_params->resc_start, 4157316485Sdavidcs p_out_params->vf_resc_num, p_out_params->vf_resc_start, 4158316485Sdavidcs p_out_params->flags); 4159316485Sdavidcs 4160316485Sdavidcs return ECORE_SUCCESS; 4161316485Sdavidcs} 4162316485Sdavidcs 4163316485Sdavidcsenum _ecore_status_t 4164316485Sdavidcsecore_mcp_set_resc_max_val(struct ecore_hwfn *p_hwfn, struct ecore_ptt *p_ptt, 4165316485Sdavidcs enum ecore_resources res_id, u32 resc_max_val, 4166316485Sdavidcs u32 *p_mcp_resp) 4167316485Sdavidcs{ 4168316485Sdavidcs struct ecore_resc_alloc_out_params out_params; 4169316485Sdavidcs struct ecore_resc_alloc_in_params in_params; 4170316485Sdavidcs enum _ecore_status_t rc; 4171316485Sdavidcs 4172316485Sdavidcs OSAL_MEM_ZERO(&in_params, sizeof(in_params)); 4173316485Sdavidcs in_params.cmd = DRV_MSG_SET_RESOURCE_VALUE_MSG; 4174316485Sdavidcs in_params.res_id = res_id; 4175316485Sdavidcs in_params.resc_max_val = resc_max_val; 4176316485Sdavidcs OSAL_MEM_ZERO(&out_params, sizeof(out_params)); 4177316485Sdavidcs rc = ecore_mcp_resc_allocation_msg(p_hwfn, p_ptt, &in_params, 4178316485Sdavidcs &out_params); 4179316485Sdavidcs if (rc != ECORE_SUCCESS) 4180316485Sdavidcs return rc; 4181316485Sdavidcs 4182316485Sdavidcs *p_mcp_resp = out_params.mcp_resp; 4183316485Sdavidcs 4184316485Sdavidcs return ECORE_SUCCESS; 4185316485Sdavidcs} 4186316485Sdavidcs 4187316485Sdavidcsenum _ecore_status_t 4188316485Sdavidcsecore_mcp_get_resc_info(struct ecore_hwfn *p_hwfn, struct ecore_ptt *p_ptt, 4189316485Sdavidcs enum ecore_resources res_id, u32 *p_mcp_resp, 4190316485Sdavidcs u32 *p_resc_num, u32 *p_resc_start) 4191316485Sdavidcs{ 4192316485Sdavidcs struct ecore_resc_alloc_out_params out_params; 4193316485Sdavidcs struct ecore_resc_alloc_in_params in_params; 4194316485Sdavidcs enum _ecore_status_t rc; 4195316485Sdavidcs 4196316485Sdavidcs OSAL_MEM_ZERO(&in_params, sizeof(in_params)); 4197316485Sdavidcs in_params.cmd = DRV_MSG_GET_RESOURCE_ALLOC_MSG; 4198316485Sdavidcs in_params.res_id = res_id; 4199316485Sdavidcs OSAL_MEM_ZERO(&out_params, sizeof(out_params)); 4200316485Sdavidcs rc = ecore_mcp_resc_allocation_msg(p_hwfn, p_ptt, &in_params, 4201316485Sdavidcs &out_params); 4202316485Sdavidcs if (rc != ECORE_SUCCESS) 4203316485Sdavidcs return rc; 4204316485Sdavidcs 4205316485Sdavidcs *p_mcp_resp = out_params.mcp_resp; 4206316485Sdavidcs 4207316485Sdavidcs if (*p_mcp_resp == FW_MSG_CODE_RESOURCE_ALLOC_OK) { 4208316485Sdavidcs *p_resc_num = out_params.resc_num; 4209316485Sdavidcs *p_resc_start = out_params.resc_start; 4210316485Sdavidcs } 4211316485Sdavidcs 4212316485Sdavidcs return ECORE_SUCCESS; 4213316485Sdavidcs} 4214316485Sdavidcs 4215316485Sdavidcsenum _ecore_status_t ecore_mcp_initiate_pf_flr(struct ecore_hwfn *p_hwfn, 4216316485Sdavidcs struct ecore_ptt *p_ptt) 4217316485Sdavidcs{ 4218316485Sdavidcs u32 mcp_resp, mcp_param; 4219316485Sdavidcs 4220316485Sdavidcs return ecore_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_INITIATE_PF_FLR, 0, 4221316485Sdavidcs &mcp_resp, &mcp_param); 4222316485Sdavidcs} 4223316485Sdavidcs 4224316485Sdavidcsenum _ecore_status_t ecore_mcp_get_lldp_mac(struct ecore_hwfn *p_hwfn, 4225316485Sdavidcs struct ecore_ptt *p_ptt, 4226316485Sdavidcs u8 lldp_mac_addr[ETH_ALEN]) 4227316485Sdavidcs{ 4228316485Sdavidcs struct ecore_mcp_mb_params mb_params; 4229316485Sdavidcs struct mcp_mac lldp_mac; 4230316485Sdavidcs enum _ecore_status_t rc; 4231316485Sdavidcs 4232316485Sdavidcs OSAL_MEM_ZERO(&mb_params, sizeof(mb_params)); 4233316485Sdavidcs mb_params.cmd = DRV_MSG_CODE_GET_LLDP_MAC; 4234316485Sdavidcs mb_params.p_data_dst = &lldp_mac; 4235316485Sdavidcs mb_params.data_dst_size = sizeof(lldp_mac); 4236316485Sdavidcs rc = ecore_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 4237316485Sdavidcs if (rc != ECORE_SUCCESS) 4238316485Sdavidcs return rc; 4239316485Sdavidcs 4240316485Sdavidcs if (mb_params.mcp_resp != FW_MSG_CODE_OK) { 4241316485Sdavidcs DP_NOTICE(p_hwfn, false, 4242316485Sdavidcs "MFW lacks support for the GET_LLDP_MAC command [resp 0x%08x]\n", 4243316485Sdavidcs mb_params.mcp_resp); 4244316485Sdavidcs return ECORE_INVAL; 4245316485Sdavidcs } 4246316485Sdavidcs 4247337517Sdavidcs *(u16 *)lldp_mac_addr = OSAL_BE16_TO_CPU(*(u16 *)&lldp_mac.mac_upper); 4248337517Sdavidcs *(u32 *)(lldp_mac_addr + 2) = OSAL_BE32_TO_CPU(lldp_mac.mac_lower); 4249316485Sdavidcs 4250316485Sdavidcs DP_VERBOSE(p_hwfn, ECORE_MSG_SP, 4251316485Sdavidcs "LLDP MAC address is %02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx\n", 4252316485Sdavidcs lldp_mac_addr[0], lldp_mac_addr[1], lldp_mac_addr[2], 4253316485Sdavidcs lldp_mac_addr[3], lldp_mac_addr[4], lldp_mac_addr[5]); 4254316485Sdavidcs 4255316485Sdavidcs return ECORE_SUCCESS; 4256316485Sdavidcs} 4257316485Sdavidcs 4258316485Sdavidcsenum _ecore_status_t ecore_mcp_set_lldp_mac(struct ecore_hwfn *p_hwfn, 4259316485Sdavidcs struct ecore_ptt *p_ptt, 4260316485Sdavidcs u8 lldp_mac_addr[ETH_ALEN]) 4261316485Sdavidcs{ 4262316485Sdavidcs struct ecore_mcp_mb_params mb_params; 4263316485Sdavidcs struct mcp_mac lldp_mac; 4264316485Sdavidcs enum _ecore_status_t rc; 4265316485Sdavidcs 4266316485Sdavidcs DP_VERBOSE(p_hwfn, ECORE_MSG_SP, 4267316485Sdavidcs "Configuring LLDP MAC address to %02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx\n", 4268316485Sdavidcs lldp_mac_addr[0], lldp_mac_addr[1], lldp_mac_addr[2], 4269316485Sdavidcs lldp_mac_addr[3], lldp_mac_addr[4], lldp_mac_addr[5]); 4270316485Sdavidcs 4271316485Sdavidcs OSAL_MEM_ZERO(&lldp_mac, sizeof(lldp_mac)); 4272337517Sdavidcs lldp_mac.mac_upper = OSAL_CPU_TO_BE16(*(u16 *)lldp_mac_addr); 4273337517Sdavidcs lldp_mac.mac_lower = OSAL_CPU_TO_BE32(*(u32 *)(lldp_mac_addr + 2)); 4274316485Sdavidcs 4275316485Sdavidcs OSAL_MEM_ZERO(&mb_params, sizeof(mb_params)); 4276316485Sdavidcs mb_params.cmd = DRV_MSG_CODE_SET_LLDP_MAC; 4277316485Sdavidcs mb_params.p_data_src = &lldp_mac; 4278316485Sdavidcs mb_params.data_src_size = sizeof(lldp_mac); 4279316485Sdavidcs rc = ecore_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 4280316485Sdavidcs if (rc != ECORE_SUCCESS) 4281316485Sdavidcs return rc; 4282316485Sdavidcs 4283316485Sdavidcs if (mb_params.mcp_resp != FW_MSG_CODE_OK) { 4284316485Sdavidcs DP_NOTICE(p_hwfn, false, 4285316485Sdavidcs "MFW lacks support for the SET_LLDP_MAC command [resp 0x%08x]\n", 4286316485Sdavidcs mb_params.mcp_resp); 4287316485Sdavidcs return ECORE_INVAL; 4288316485Sdavidcs } 4289316485Sdavidcs 4290316485Sdavidcs return ECORE_SUCCESS; 4291316485Sdavidcs} 4292316485Sdavidcs 4293316485Sdavidcsstatic enum _ecore_status_t ecore_mcp_resource_cmd(struct ecore_hwfn *p_hwfn, 4294316485Sdavidcs struct ecore_ptt *p_ptt, 4295316485Sdavidcs u32 param, u32 *p_mcp_resp, 4296316485Sdavidcs u32 *p_mcp_param) 4297316485Sdavidcs{ 4298316485Sdavidcs enum _ecore_status_t rc; 4299316485Sdavidcs 4300316485Sdavidcs rc = ecore_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_RESOURCE_CMD, param, 4301316485Sdavidcs p_mcp_resp, p_mcp_param); 4302316485Sdavidcs if (rc != ECORE_SUCCESS) 4303316485Sdavidcs return rc; 4304316485Sdavidcs 4305316485Sdavidcs if (*p_mcp_resp == FW_MSG_CODE_UNSUPPORTED) { 4306316485Sdavidcs DP_INFO(p_hwfn, 4307316485Sdavidcs "The resource command is unsupported by the MFW\n"); 4308316485Sdavidcs return ECORE_NOTIMPL; 4309316485Sdavidcs } 4310316485Sdavidcs 4311316485Sdavidcs if (*p_mcp_param == RESOURCE_OPCODE_UNKNOWN_CMD) { 4312320164Sdavidcs u8 opcode = GET_MFW_FIELD(param, RESOURCE_CMD_REQ_OPCODE); 4313316485Sdavidcs 4314316485Sdavidcs DP_NOTICE(p_hwfn, false, 4315316485Sdavidcs "The resource command is unknown to the MFW [param 0x%08x, opcode %d]\n", 4316316485Sdavidcs param, opcode); 4317316485Sdavidcs return ECORE_INVAL; 4318316485Sdavidcs } 4319316485Sdavidcs 4320316485Sdavidcs return rc; 4321316485Sdavidcs} 4322316485Sdavidcs 4323316485Sdavidcsstatic enum _ecore_status_t 4324316485Sdavidcs__ecore_mcp_resc_lock(struct ecore_hwfn *p_hwfn, struct ecore_ptt *p_ptt, 4325316485Sdavidcs struct ecore_resc_lock_params *p_params) 4326316485Sdavidcs{ 4327316485Sdavidcs u32 param = 0, mcp_resp, mcp_param; 4328337517Sdavidcs u8 opcode, timeout; 4329316485Sdavidcs enum _ecore_status_t rc; 4330316485Sdavidcs 4331316485Sdavidcs switch (p_params->timeout) { 4332316485Sdavidcs case ECORE_MCP_RESC_LOCK_TO_DEFAULT: 4333316485Sdavidcs opcode = RESOURCE_OPCODE_REQ; 4334337517Sdavidcs timeout = 0; 4335316485Sdavidcs break; 4336316485Sdavidcs case ECORE_MCP_RESC_LOCK_TO_NONE: 4337316485Sdavidcs opcode = RESOURCE_OPCODE_REQ_WO_AGING; 4338337517Sdavidcs timeout = 0; 4339316485Sdavidcs break; 4340316485Sdavidcs default: 4341316485Sdavidcs opcode = RESOURCE_OPCODE_REQ_W_AGING; 4342337517Sdavidcs timeout = p_params->timeout; 4343316485Sdavidcs break; 4344316485Sdavidcs } 4345316485Sdavidcs 4346320164Sdavidcs SET_MFW_FIELD(param, RESOURCE_CMD_REQ_RESC, p_params->resource); 4347320164Sdavidcs SET_MFW_FIELD(param, RESOURCE_CMD_REQ_OPCODE, opcode); 4348337517Sdavidcs SET_MFW_FIELD(param, RESOURCE_CMD_REQ_AGE, timeout); 4349316485Sdavidcs 4350316485Sdavidcs DP_VERBOSE(p_hwfn, ECORE_MSG_SP, 4351316485Sdavidcs "Resource lock request: param 0x%08x [age %d, opcode %d, resource %d]\n", 4352337517Sdavidcs param, timeout, opcode, p_params->resource); 4353316485Sdavidcs 4354316485Sdavidcs /* Attempt to acquire the resource */ 4355316485Sdavidcs rc = ecore_mcp_resource_cmd(p_hwfn, p_ptt, param, &mcp_resp, 4356316485Sdavidcs &mcp_param); 4357316485Sdavidcs if (rc != ECORE_SUCCESS) 4358316485Sdavidcs return rc; 4359316485Sdavidcs 4360316485Sdavidcs /* Analyze the response */ 4361320164Sdavidcs p_params->owner = GET_MFW_FIELD(mcp_param, RESOURCE_CMD_RSP_OWNER); 4362320164Sdavidcs opcode = GET_MFW_FIELD(mcp_param, RESOURCE_CMD_RSP_OPCODE); 4363316485Sdavidcs 4364316485Sdavidcs DP_VERBOSE(p_hwfn, ECORE_MSG_SP, 4365316485Sdavidcs "Resource lock response: mcp_param 0x%08x [opcode %d, owner %d]\n", 4366316485Sdavidcs mcp_param, opcode, p_params->owner); 4367316485Sdavidcs 4368316485Sdavidcs switch (opcode) { 4369316485Sdavidcs case RESOURCE_OPCODE_GNT: 4370316485Sdavidcs p_params->b_granted = true; 4371316485Sdavidcs break; 4372316485Sdavidcs case RESOURCE_OPCODE_BUSY: 4373316485Sdavidcs p_params->b_granted = false; 4374316485Sdavidcs break; 4375316485Sdavidcs default: 4376316485Sdavidcs DP_NOTICE(p_hwfn, false, 4377316485Sdavidcs "Unexpected opcode in resource lock response [mcp_param 0x%08x, opcode %d]\n", 4378316485Sdavidcs mcp_param, opcode); 4379316485Sdavidcs return ECORE_INVAL; 4380316485Sdavidcs } 4381316485Sdavidcs 4382316485Sdavidcs return ECORE_SUCCESS; 4383316485Sdavidcs} 4384316485Sdavidcs 4385316485Sdavidcsenum _ecore_status_t 4386316485Sdavidcsecore_mcp_resc_lock(struct ecore_hwfn *p_hwfn, struct ecore_ptt *p_ptt, 4387316485Sdavidcs struct ecore_resc_lock_params *p_params) 4388316485Sdavidcs{ 4389316485Sdavidcs u32 retry_cnt = 0; 4390316485Sdavidcs enum _ecore_status_t rc; 4391316485Sdavidcs 4392316485Sdavidcs do { 4393316485Sdavidcs /* No need for an interval before the first iteration */ 4394316485Sdavidcs if (retry_cnt) { 4395316485Sdavidcs if (p_params->sleep_b4_retry) { 4396337517Sdavidcs u32 retry_interval_in_ms = 4397316485Sdavidcs DIV_ROUND_UP(p_params->retry_interval, 4398316485Sdavidcs 1000); 4399316485Sdavidcs 4400316485Sdavidcs OSAL_MSLEEP(retry_interval_in_ms); 4401316485Sdavidcs } else { 4402316485Sdavidcs OSAL_UDELAY(p_params->retry_interval); 4403316485Sdavidcs } 4404316485Sdavidcs } 4405316485Sdavidcs 4406316485Sdavidcs rc = __ecore_mcp_resc_lock(p_hwfn, p_ptt, p_params); 4407316485Sdavidcs if (rc != ECORE_SUCCESS) 4408316485Sdavidcs return rc; 4409316485Sdavidcs 4410316485Sdavidcs if (p_params->b_granted) 4411316485Sdavidcs break; 4412316485Sdavidcs } while (retry_cnt++ < p_params->retry_num); 4413316485Sdavidcs 4414316485Sdavidcs return ECORE_SUCCESS; 4415316485Sdavidcs} 4416316485Sdavidcs 4417316485Sdavidcsenum _ecore_status_t 4418316485Sdavidcsecore_mcp_resc_unlock(struct ecore_hwfn *p_hwfn, struct ecore_ptt *p_ptt, 4419316485Sdavidcs struct ecore_resc_unlock_params *p_params) 4420316485Sdavidcs{ 4421316485Sdavidcs u32 param = 0, mcp_resp, mcp_param; 4422316485Sdavidcs u8 opcode; 4423316485Sdavidcs enum _ecore_status_t rc; 4424316485Sdavidcs 4425316485Sdavidcs opcode = p_params->b_force ? RESOURCE_OPCODE_FORCE_RELEASE 4426316485Sdavidcs : RESOURCE_OPCODE_RELEASE; 4427320164Sdavidcs SET_MFW_FIELD(param, RESOURCE_CMD_REQ_RESC, p_params->resource); 4428320164Sdavidcs SET_MFW_FIELD(param, RESOURCE_CMD_REQ_OPCODE, opcode); 4429316485Sdavidcs 4430316485Sdavidcs DP_VERBOSE(p_hwfn, ECORE_MSG_SP, 4431316485Sdavidcs "Resource unlock request: param 0x%08x [opcode %d, resource %d]\n", 4432316485Sdavidcs param, opcode, p_params->resource); 4433316485Sdavidcs 4434316485Sdavidcs /* Attempt to release the resource */ 4435316485Sdavidcs rc = ecore_mcp_resource_cmd(p_hwfn, p_ptt, param, &mcp_resp, 4436316485Sdavidcs &mcp_param); 4437316485Sdavidcs if (rc != ECORE_SUCCESS) 4438316485Sdavidcs return rc; 4439316485Sdavidcs 4440316485Sdavidcs /* Analyze the response */ 4441320164Sdavidcs opcode = GET_MFW_FIELD(mcp_param, RESOURCE_CMD_RSP_OPCODE); 4442316485Sdavidcs 4443316485Sdavidcs DP_VERBOSE(p_hwfn, ECORE_MSG_SP, 4444316485Sdavidcs "Resource unlock response: mcp_param 0x%08x [opcode %d]\n", 4445316485Sdavidcs mcp_param, opcode); 4446316485Sdavidcs 4447316485Sdavidcs switch (opcode) { 4448316485Sdavidcs case RESOURCE_OPCODE_RELEASED_PREVIOUS: 4449316485Sdavidcs DP_INFO(p_hwfn, 4450316485Sdavidcs "Resource unlock request for an already released resource [%d]\n", 4451316485Sdavidcs p_params->resource); 4452316485Sdavidcs /* Fallthrough */ 4453316485Sdavidcs case RESOURCE_OPCODE_RELEASED: 4454316485Sdavidcs p_params->b_released = true; 4455316485Sdavidcs break; 4456316485Sdavidcs case RESOURCE_OPCODE_WRONG_OWNER: 4457316485Sdavidcs p_params->b_released = false; 4458316485Sdavidcs break; 4459316485Sdavidcs default: 4460316485Sdavidcs DP_NOTICE(p_hwfn, false, 4461316485Sdavidcs "Unexpected opcode in resource unlock response [mcp_param 0x%08x, opcode %d]\n", 4462316485Sdavidcs mcp_param, opcode); 4463316485Sdavidcs return ECORE_INVAL; 4464316485Sdavidcs } 4465316485Sdavidcs 4466316485Sdavidcs return ECORE_SUCCESS; 4467316485Sdavidcs} 4468316485Sdavidcs 4469320164Sdavidcsvoid ecore_mcp_resc_lock_default_init(struct ecore_resc_lock_params *p_lock, 4470320164Sdavidcs struct ecore_resc_unlock_params *p_unlock, 4471320164Sdavidcs enum ecore_resc_lock resource, 4472320164Sdavidcs bool b_is_permanent) 4473320164Sdavidcs{ 4474320164Sdavidcs if (p_lock != OSAL_NULL) { 4475320164Sdavidcs OSAL_MEM_ZERO(p_lock, sizeof(*p_lock)); 4476320164Sdavidcs 4477320164Sdavidcs /* Permanent resources don't require aging, and there's no 4478320164Sdavidcs * point in trying to acquire them more than once since it's 4479320164Sdavidcs * unexpected another entity would release them. 4480320164Sdavidcs */ 4481320164Sdavidcs if (b_is_permanent) { 4482320164Sdavidcs p_lock->timeout = ECORE_MCP_RESC_LOCK_TO_NONE; 4483320164Sdavidcs } else { 4484320164Sdavidcs p_lock->retry_num = ECORE_MCP_RESC_LOCK_RETRY_CNT_DFLT; 4485320164Sdavidcs p_lock->retry_interval = 4486320164Sdavidcs ECORE_MCP_RESC_LOCK_RETRY_VAL_DFLT; 4487320164Sdavidcs p_lock->sleep_b4_retry = true; 4488320164Sdavidcs } 4489320164Sdavidcs 4490320164Sdavidcs p_lock->resource = resource; 4491320164Sdavidcs } 4492320164Sdavidcs 4493320164Sdavidcs if (p_unlock != OSAL_NULL) { 4494320164Sdavidcs OSAL_MEM_ZERO(p_unlock, sizeof(*p_unlock)); 4495320164Sdavidcs p_unlock->resource = resource; 4496320164Sdavidcs } 4497320164Sdavidcs} 4498320164Sdavidcs 4499316485Sdavidcsenum _ecore_status_t 4500316485Sdavidcsecore_mcp_update_fcoe_cvid(struct ecore_hwfn *p_hwfn, struct ecore_ptt *p_ptt, 4501316485Sdavidcs u16 vlan) 4502316485Sdavidcs{ 4503316485Sdavidcs u32 resp = 0, param = 0; 4504316485Sdavidcs enum _ecore_status_t rc; 4505316485Sdavidcs 4506316485Sdavidcs rc = ecore_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_OEM_UPDATE_FCOE_CVID, 4507320164Sdavidcs (u32)vlan << DRV_MB_PARAM_FCOE_CVID_OFFSET, 4508316485Sdavidcs &resp, ¶m); 4509316485Sdavidcs if (rc != ECORE_SUCCESS) 4510316485Sdavidcs DP_ERR(p_hwfn, "Failed to update fcoe vlan, rc = %d\n", rc); 4511316485Sdavidcs 4512316485Sdavidcs return rc; 4513316485Sdavidcs} 4514316485Sdavidcs 4515316485Sdavidcsenum _ecore_status_t 4516316485Sdavidcsecore_mcp_update_fcoe_fabric_name(struct ecore_hwfn *p_hwfn, 4517316485Sdavidcs struct ecore_ptt *p_ptt, u8 *wwn) 4518316485Sdavidcs{ 4519316485Sdavidcs struct ecore_mcp_mb_params mb_params; 4520316485Sdavidcs struct mcp_wwn fabric_name; 4521316485Sdavidcs enum _ecore_status_t rc; 4522316485Sdavidcs 4523316485Sdavidcs OSAL_MEM_ZERO(&fabric_name, sizeof(fabric_name)); 4524316485Sdavidcs fabric_name.wwn_upper = *(u32 *)wwn; 4525316485Sdavidcs fabric_name.wwn_lower = *(u32 *)(wwn + 4); 4526316485Sdavidcs 4527316485Sdavidcs OSAL_MEM_ZERO(&mb_params, sizeof(mb_params)); 4528316485Sdavidcs mb_params.cmd = DRV_MSG_CODE_OEM_UPDATE_FCOE_FABRIC_NAME; 4529316485Sdavidcs mb_params.p_data_src = &fabric_name; 4530316485Sdavidcs mb_params.data_src_size = sizeof(fabric_name); 4531316485Sdavidcs rc = ecore_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 4532316485Sdavidcs if (rc != ECORE_SUCCESS) 4533316485Sdavidcs DP_ERR(p_hwfn, "Failed to update fcoe wwn, rc = %d\n", rc); 4534316485Sdavidcs 4535316485Sdavidcs return rc; 4536316485Sdavidcs} 4537316485Sdavidcs 4538316485Sdavidcsvoid ecore_mcp_wol_wr(struct ecore_hwfn *p_hwfn, struct ecore_ptt *p_ptt, 4539316485Sdavidcs u32 offset, u32 val) 4540316485Sdavidcs{ 4541316485Sdavidcs struct ecore_mcp_mb_params mb_params = {0}; 4542316485Sdavidcs enum _ecore_status_t rc = ECORE_SUCCESS; 4543316485Sdavidcs u32 dword = val; 4544316485Sdavidcs 4545316485Sdavidcs mb_params.cmd = DRV_MSG_CODE_WRITE_WOL_REG; 4546316485Sdavidcs mb_params.param = offset; 4547316485Sdavidcs mb_params.p_data_src = &dword; 4548316485Sdavidcs mb_params.data_src_size = sizeof(dword); 4549316485Sdavidcs 4550316485Sdavidcs rc = ecore_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 4551316485Sdavidcs if (rc != ECORE_SUCCESS) { 4552316485Sdavidcs DP_NOTICE(p_hwfn, false, 4553316485Sdavidcs "Failed to wol write request, rc = %d\n", rc); 4554316485Sdavidcs } 4555316485Sdavidcs 4556316485Sdavidcs if (mb_params.mcp_resp != FW_MSG_CODE_WOL_READ_WRITE_OK) { 4557316485Sdavidcs DP_NOTICE(p_hwfn, false, 4558316485Sdavidcs "Failed to write value 0x%x to offset 0x%x [mcp_resp 0x%x]\n", 4559316485Sdavidcs val, offset, mb_params.mcp_resp); 4560316485Sdavidcs rc = ECORE_UNKNOWN_ERROR; 4561316485Sdavidcs } 4562316485Sdavidcs} 4563316485Sdavidcs 4564337517Sdavidcsbool ecore_mcp_is_smart_an_supported(struct ecore_hwfn *p_hwfn) 4565337517Sdavidcs{ 4566337517Sdavidcs return !!(p_hwfn->mcp_info->capabilities & 4567337517Sdavidcs FW_MB_PARAM_FEATURE_SUPPORT_SMARTLINQ); 4568337517Sdavidcs} 4569337517Sdavidcs 4570337517Sdavidcsbool ecore_mcp_rlx_odr_supported(struct ecore_hwfn *p_hwfn) 4571337517Sdavidcs{ 4572337517Sdavidcs return !!(p_hwfn->mcp_info->capabilities & 4573337517Sdavidcs FW_MB_PARAM_FEATURE_SUPPORT_RELAXED_ORD); 4574337517Sdavidcs} 4575337517Sdavidcs 4576316485Sdavidcsenum _ecore_status_t ecore_mcp_get_capabilities(struct ecore_hwfn *p_hwfn, 4577316485Sdavidcs struct ecore_ptt *p_ptt) 4578316485Sdavidcs{ 4579316485Sdavidcs u32 mcp_resp; 4580316485Sdavidcs enum _ecore_status_t rc; 4581316485Sdavidcs 4582316485Sdavidcs rc = ecore_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_GET_MFW_FEATURE_SUPPORT, 4583316485Sdavidcs 0, &mcp_resp, &p_hwfn->mcp_info->capabilities); 4584316485Sdavidcs if (rc == ECORE_SUCCESS) 4585316485Sdavidcs DP_VERBOSE(p_hwfn, (ECORE_MSG_SP | ECORE_MSG_PROBE), 4586316485Sdavidcs "MFW supported features: %08x\n", 4587316485Sdavidcs p_hwfn->mcp_info->capabilities); 4588316485Sdavidcs 4589316485Sdavidcs return rc; 4590316485Sdavidcs} 4591316485Sdavidcs 4592316485Sdavidcsenum _ecore_status_t ecore_mcp_set_capabilities(struct ecore_hwfn *p_hwfn, 4593316485Sdavidcs struct ecore_ptt *p_ptt) 4594316485Sdavidcs{ 4595316485Sdavidcs u32 mcp_resp, mcp_param, features; 4596316485Sdavidcs 4597316485Sdavidcs features = DRV_MB_PARAM_FEATURE_SUPPORT_PORT_SMARTLINQ | 4598337517Sdavidcs DRV_MB_PARAM_FEATURE_SUPPORT_PORT_EEE | 4599337517Sdavidcs DRV_MB_PARAM_FEATURE_SUPPORT_FUNC_VLINK; 4600316485Sdavidcs 4601316485Sdavidcs return ecore_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_FEATURE_SUPPORT, 4602316485Sdavidcs features, &mcp_resp, &mcp_param); 4603316485Sdavidcs} 4604337517Sdavidcs 4605337517Sdavidcsenum _ecore_status_t 4606337517Sdavidcsecore_mcp_drv_attribute(struct ecore_hwfn *p_hwfn, struct ecore_ptt *p_ptt, 4607337517Sdavidcs struct ecore_mcp_drv_attr *p_drv_attr) 4608337517Sdavidcs{ 4609337517Sdavidcs struct attribute_cmd_write_stc attr_cmd_write; 4610337517Sdavidcs enum _attribute_commands_e mfw_attr_cmd; 4611337517Sdavidcs struct ecore_mcp_mb_params mb_params; 4612337517Sdavidcs enum _ecore_status_t rc; 4613337517Sdavidcs 4614337517Sdavidcs switch (p_drv_attr->attr_cmd) { 4615337517Sdavidcs case ECORE_MCP_DRV_ATTR_CMD_READ: 4616337517Sdavidcs mfw_attr_cmd = ATTRIBUTE_CMD_READ; 4617337517Sdavidcs break; 4618337517Sdavidcs case ECORE_MCP_DRV_ATTR_CMD_WRITE: 4619337517Sdavidcs mfw_attr_cmd = ATTRIBUTE_CMD_WRITE; 4620337517Sdavidcs break; 4621337517Sdavidcs case ECORE_MCP_DRV_ATTR_CMD_READ_CLEAR: 4622337517Sdavidcs mfw_attr_cmd = ATTRIBUTE_CMD_READ_CLEAR; 4623337517Sdavidcs break; 4624337517Sdavidcs case ECORE_MCP_DRV_ATTR_CMD_CLEAR: 4625337517Sdavidcs mfw_attr_cmd = ATTRIBUTE_CMD_CLEAR; 4626337517Sdavidcs break; 4627337517Sdavidcs default: 4628337517Sdavidcs DP_NOTICE(p_hwfn, false, "Unknown attribute command %d\n", 4629337517Sdavidcs p_drv_attr->attr_cmd); 4630337517Sdavidcs return ECORE_INVAL; 4631337517Sdavidcs } 4632337517Sdavidcs 4633337517Sdavidcs OSAL_MEM_ZERO(&mb_params, sizeof(mb_params)); 4634337517Sdavidcs mb_params.cmd = DRV_MSG_CODE_ATTRIBUTE; 4635337517Sdavidcs SET_MFW_FIELD(mb_params.param, DRV_MB_PARAM_ATTRIBUTE_KEY, 4636337517Sdavidcs p_drv_attr->attr_num); 4637337517Sdavidcs SET_MFW_FIELD(mb_params.param, DRV_MB_PARAM_ATTRIBUTE_CMD, 4638337517Sdavidcs mfw_attr_cmd); 4639337517Sdavidcs if (p_drv_attr->attr_cmd == ECORE_MCP_DRV_ATTR_CMD_WRITE) { 4640337517Sdavidcs OSAL_MEM_ZERO(&attr_cmd_write, sizeof(attr_cmd_write)); 4641337517Sdavidcs attr_cmd_write.val = p_drv_attr->val; 4642337517Sdavidcs attr_cmd_write.mask = p_drv_attr->mask; 4643337517Sdavidcs attr_cmd_write.offset = p_drv_attr->offset; 4644337517Sdavidcs 4645337517Sdavidcs mb_params.p_data_src = &attr_cmd_write; 4646337517Sdavidcs mb_params.data_src_size = sizeof(attr_cmd_write); 4647337517Sdavidcs } 4648337517Sdavidcs 4649337517Sdavidcs rc = ecore_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 4650337517Sdavidcs if (rc != ECORE_SUCCESS) 4651337517Sdavidcs return rc; 4652337517Sdavidcs 4653337517Sdavidcs if (mb_params.mcp_resp == FW_MSG_CODE_UNSUPPORTED) { 4654337517Sdavidcs DP_INFO(p_hwfn, 4655337517Sdavidcs "The attribute command is not supported by the MFW\n"); 4656337517Sdavidcs return ECORE_NOTIMPL; 4657337517Sdavidcs } else if (mb_params.mcp_resp != FW_MSG_CODE_OK) { 4658337517Sdavidcs DP_INFO(p_hwfn, 4659337517Sdavidcs "Failed to send an attribute command [mcp_resp 0x%x, attr_cmd %d, attr_num %d]\n", 4660337517Sdavidcs mb_params.mcp_resp, p_drv_attr->attr_cmd, 4661337517Sdavidcs p_drv_attr->attr_num); 4662337517Sdavidcs return ECORE_INVAL; 4663337517Sdavidcs } 4664337517Sdavidcs 4665337517Sdavidcs DP_VERBOSE(p_hwfn, ECORE_MSG_SP, 4666337517Sdavidcs "Attribute Command: cmd %d [mfw_cmd %d], num %d, in={val 0x%08x, mask 0x%08x, offset 0x%08x}, out={val 0x%08x}\n", 4667337517Sdavidcs p_drv_attr->attr_cmd, mfw_attr_cmd, p_drv_attr->attr_num, 4668337517Sdavidcs p_drv_attr->val, p_drv_attr->mask, p_drv_attr->offset, 4669337517Sdavidcs mb_params.mcp_param); 4670337517Sdavidcs 4671337517Sdavidcs if (p_drv_attr->attr_cmd == ECORE_MCP_DRV_ATTR_CMD_READ || 4672337517Sdavidcs p_drv_attr->attr_cmd == ECORE_MCP_DRV_ATTR_CMD_READ_CLEAR) 4673337517Sdavidcs p_drv_attr->val = mb_params.mcp_param; 4674337517Sdavidcs 4675337517Sdavidcs return ECORE_SUCCESS; 4676337517Sdavidcs} 4677337517Sdavidcs 4678337517Sdavidcsenum _ecore_status_t ecore_mcp_get_engine_config(struct ecore_hwfn *p_hwfn, 4679337517Sdavidcs struct ecore_ptt *p_ptt) 4680337517Sdavidcs{ 4681337517Sdavidcs struct ecore_dev *p_dev = p_hwfn->p_dev; 4682337517Sdavidcs struct ecore_mcp_mb_params mb_params; 4683337517Sdavidcs u8 fir_valid, l2_valid; 4684337517Sdavidcs enum _ecore_status_t rc; 4685337517Sdavidcs 4686337517Sdavidcs OSAL_MEM_ZERO(&mb_params, sizeof(mb_params)); 4687337517Sdavidcs mb_params.cmd = DRV_MSG_CODE_GET_ENGINE_CONFIG; 4688337517Sdavidcs rc = ecore_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 4689337517Sdavidcs if (rc != ECORE_SUCCESS) 4690337517Sdavidcs return rc; 4691337517Sdavidcs 4692337517Sdavidcs if (mb_params.mcp_resp == FW_MSG_CODE_UNSUPPORTED) { 4693337517Sdavidcs DP_INFO(p_hwfn, 4694337517Sdavidcs "The get_engine_config command is unsupported by the MFW\n"); 4695337517Sdavidcs return ECORE_NOTIMPL; 4696337517Sdavidcs } 4697337517Sdavidcs 4698337517Sdavidcs fir_valid = GET_MFW_FIELD(mb_params.mcp_param, 4699337517Sdavidcs FW_MB_PARAM_ENG_CFG_FIR_AFFIN_VALID); 4700337517Sdavidcs if (fir_valid) 4701337517Sdavidcs p_dev->fir_affin = 4702337517Sdavidcs GET_MFW_FIELD(mb_params.mcp_param, 4703337517Sdavidcs FW_MB_PARAM_ENG_CFG_FIR_AFFIN_VALUE); 4704337517Sdavidcs 4705337517Sdavidcs l2_valid = GET_MFW_FIELD(mb_params.mcp_param, 4706337517Sdavidcs FW_MB_PARAM_ENG_CFG_L2_AFFIN_VALID); 4707337517Sdavidcs if (l2_valid) 4708337517Sdavidcs p_dev->l2_affin_hint = 4709337517Sdavidcs GET_MFW_FIELD(mb_params.mcp_param, 4710337517Sdavidcs FW_MB_PARAM_ENG_CFG_L2_AFFIN_VALUE); 4711337517Sdavidcs 4712337517Sdavidcs DP_INFO(p_hwfn, 4713337517Sdavidcs "Engine affinity config: FIR={valid %hhd, value %hhd}, L2_hint={valid %hhd, value %hhd}\n", 4714337517Sdavidcs fir_valid, p_dev->fir_affin, l2_valid, p_dev->l2_affin_hint); 4715337517Sdavidcs 4716337517Sdavidcs return ECORE_SUCCESS; 4717337517Sdavidcs} 4718337517Sdavidcs 4719337517Sdavidcsenum _ecore_status_t ecore_mcp_get_ppfid_bitmap(struct ecore_hwfn *p_hwfn, 4720337517Sdavidcs struct ecore_ptt *p_ptt) 4721337517Sdavidcs{ 4722337517Sdavidcs struct ecore_dev *p_dev = p_hwfn->p_dev; 4723337517Sdavidcs struct ecore_mcp_mb_params mb_params; 4724337517Sdavidcs enum _ecore_status_t rc; 4725337517Sdavidcs 4726337517Sdavidcs OSAL_MEM_ZERO(&mb_params, sizeof(mb_params)); 4727337517Sdavidcs mb_params.cmd = DRV_MSG_CODE_GET_PPFID_BITMAP; 4728337517Sdavidcs rc = ecore_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params); 4729337517Sdavidcs if (rc != ECORE_SUCCESS) 4730337517Sdavidcs return rc; 4731337517Sdavidcs 4732337517Sdavidcs if (mb_params.mcp_resp == FW_MSG_CODE_UNSUPPORTED) { 4733337517Sdavidcs DP_INFO(p_hwfn, 4734337517Sdavidcs "The get_ppfid_bitmap command is unsupported by the MFW\n"); 4735337517Sdavidcs return ECORE_NOTIMPL; 4736337517Sdavidcs } 4737337517Sdavidcs 4738337517Sdavidcs p_dev->ppfid_bitmap = GET_MFW_FIELD(mb_params.mcp_param, 4739337517Sdavidcs FW_MB_PARAM_PPFID_BITMAP); 4740337517Sdavidcs 4741337517Sdavidcs DP_VERBOSE(p_hwfn, ECORE_MSG_SP, "PPFID bitmap 0x%hhx\n", 4742337517Sdavidcs p_dev->ppfid_bitmap); 4743337517Sdavidcs 4744337517Sdavidcs return ECORE_SUCCESS; 4745337517Sdavidcs} 4746337517Sdavidcs 4747337517Sdavidcsenum _ecore_status_t 4748337517Sdavidcsecore_mcp_ind_table_lock(struct ecore_hwfn *p_hwfn, 4749337517Sdavidcs struct ecore_ptt *p_ptt, 4750337517Sdavidcs u8 retry_num, 4751337517Sdavidcs u32 retry_interval) 4752337517Sdavidcs{ 4753337517Sdavidcs struct ecore_resc_lock_params resc_lock_params; 4754337517Sdavidcs enum _ecore_status_t rc; 4755337517Sdavidcs 4756337517Sdavidcs OSAL_MEM_ZERO(&resc_lock_params, 4757337517Sdavidcs sizeof(struct ecore_resc_lock_params)); 4758337517Sdavidcs resc_lock_params.resource = ECORE_RESC_LOCK_IND_TABLE; 4759337517Sdavidcs if (!retry_num) 4760337517Sdavidcs retry_num = ECORE_MCP_RESC_LOCK_RETRY_CNT_DFLT; 4761337517Sdavidcs resc_lock_params.retry_num = retry_num; 4762337517Sdavidcs 4763337517Sdavidcs if (!retry_interval) 4764337517Sdavidcs retry_interval = ECORE_MCP_RESC_LOCK_RETRY_VAL_DFLT; 4765337517Sdavidcs resc_lock_params.retry_interval = retry_interval; 4766337517Sdavidcs 4767337517Sdavidcs rc = ecore_mcp_resc_lock(p_hwfn, p_ptt, &resc_lock_params); 4768337517Sdavidcs if (rc == ECORE_SUCCESS && !resc_lock_params.b_granted) { 4769337517Sdavidcs DP_NOTICE(p_hwfn, false, 4770337517Sdavidcs "Failed to acquire the resource lock for IDT access\n"); 4771337517Sdavidcs return ECORE_BUSY; 4772337517Sdavidcs } 4773337517Sdavidcs return rc; 4774337517Sdavidcs} 4775337517Sdavidcs 4776337517Sdavidcsenum _ecore_status_t 4777337517Sdavidcsecore_mcp_ind_table_unlock(struct ecore_hwfn *p_hwfn, struct ecore_ptt *p_ptt) 4778337517Sdavidcs{ 4779337517Sdavidcs struct ecore_resc_unlock_params resc_unlock_params; 4780337517Sdavidcs enum _ecore_status_t rc; 4781337517Sdavidcs 4782337517Sdavidcs OSAL_MEM_ZERO(&resc_unlock_params, 4783337517Sdavidcs sizeof(struct ecore_resc_unlock_params)); 4784337517Sdavidcs resc_unlock_params.resource = ECORE_RESC_LOCK_IND_TABLE; 4785337517Sdavidcs rc = ecore_mcp_resc_unlock(p_hwfn, p_ptt, 4786337517Sdavidcs &resc_unlock_params); 4787337517Sdavidcs return rc; 4788337517Sdavidcs} 4789337517Sdavidcs#ifdef _NTDDK_ 4790337517Sdavidcs#pragma warning(pop) 4791337517Sdavidcs#endif 4792