114b24e2bSVaishali Kulkarni /*
214b24e2bSVaishali Kulkarni * CDDL HEADER START
314b24e2bSVaishali Kulkarni *
414b24e2bSVaishali Kulkarni * The contents of this file are subject to the terms of the
514b24e2bSVaishali Kulkarni * Common Development and Distribution License, v.1,  (the "License").
614b24e2bSVaishali Kulkarni * You may not use this file except in compliance with the License.
714b24e2bSVaishali Kulkarni *
814b24e2bSVaishali Kulkarni * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
914b24e2bSVaishali Kulkarni * or http://opensource.org/licenses/CDDL-1.0.
1014b24e2bSVaishali Kulkarni * See the License for the specific language governing permissions
1114b24e2bSVaishali Kulkarni * and limitations under the License.
1214b24e2bSVaishali Kulkarni *
1314b24e2bSVaishali Kulkarni * When distributing Covered Code, include this CDDL HEADER in each
1414b24e2bSVaishali Kulkarni * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1514b24e2bSVaishali Kulkarni * If applicable, add the following below this CDDL HEADER, with the
1614b24e2bSVaishali Kulkarni * fields enclosed by brackets "[]" replaced with your own identifying
1714b24e2bSVaishali Kulkarni * information: Portions Copyright [yyyy] [name of copyright owner]
1814b24e2bSVaishali Kulkarni *
1914b24e2bSVaishali Kulkarni * CDDL HEADER END
2014b24e2bSVaishali Kulkarni */
2114b24e2bSVaishali Kulkarni 
2214b24e2bSVaishali Kulkarni /*
2314b24e2bSVaishali Kulkarni * Copyright 2014-2017 Cavium, Inc.
2414b24e2bSVaishali Kulkarni * The contents of this file are subject to the terms of the Common Development
2514b24e2bSVaishali Kulkarni * and Distribution License, v.1,  (the "License").
2614b24e2bSVaishali Kulkarni 
2714b24e2bSVaishali Kulkarni * You may not use this file except in compliance with the License.
2814b24e2bSVaishali Kulkarni 
2914b24e2bSVaishali Kulkarni * You can obtain a copy of the License at available
3014b24e2bSVaishali Kulkarni * at http://opensource.org/licenses/CDDL-1.0
3114b24e2bSVaishali Kulkarni 
3214b24e2bSVaishali Kulkarni * See the License for the specific language governing permissions and
3314b24e2bSVaishali Kulkarni * limitations under the License.
3414b24e2bSVaishali Kulkarni */
3514b24e2bSVaishali Kulkarni 
36b68ddc76SJohn Levon /*
37b68ddc76SJohn Levon  * Copyright 2018 Joyent, Inc.
38b68ddc76SJohn Levon  */
39b68ddc76SJohn Levon 
4014b24e2bSVaishali Kulkarni #include "bcm_osal.h"
4114b24e2bSVaishali Kulkarni #include "ecore.h"
4214b24e2bSVaishali Kulkarni #include "ecore_status.h"
4314b24e2bSVaishali Kulkarni #include "nvm_map.h"
4414b24e2bSVaishali Kulkarni #include "nvm_cfg.h"
4514b24e2bSVaishali Kulkarni #include "ecore_mcp.h"
4614b24e2bSVaishali Kulkarni #include "mcp_public.h"
4714b24e2bSVaishali Kulkarni #include "reg_addr.h"
4814b24e2bSVaishali Kulkarni #include "ecore_hw.h"
4914b24e2bSVaishali Kulkarni #include "ecore_init_fw_funcs.h"
5014b24e2bSVaishali Kulkarni #include "ecore_sriov.h"
5114b24e2bSVaishali Kulkarni #include "ecore_vf.h"
5214b24e2bSVaishali Kulkarni #include "ecore_iov_api.h"
5314b24e2bSVaishali Kulkarni #include "ecore_gtt_reg_addr.h"
5414b24e2bSVaishali Kulkarni #include "ecore_iro.h"
5514b24e2bSVaishali Kulkarni #include "ecore_dcbx.h"
5614b24e2bSVaishali Kulkarni #include "ecore_sp_commands.h"
5714b24e2bSVaishali Kulkarni 
5814b24e2bSVaishali Kulkarni #define CHIP_MCP_RESP_ITER_US 10
5914b24e2bSVaishali Kulkarni #define EMUL_MCP_RESP_ITER_US 1000 * 1000
6014b24e2bSVaishali Kulkarni 
6114b24e2bSVaishali Kulkarni #define ECORE_DRV_MB_MAX_RETRIES	(500 * 1000) /* Account for 5 sec */
6214b24e2bSVaishali Kulkarni #define ECORE_MCP_RESET_RETRIES		(50 * 1000) /* Account for 500 msec */
6314b24e2bSVaishali Kulkarni 
6414b24e2bSVaishali Kulkarni #define DRV_INNER_WR(_p_hwfn, _p_ptt, _ptr, _offset, _val) \
6514b24e2bSVaishali Kulkarni 	ecore_wr(_p_hwfn, _p_ptt, (_p_hwfn->mcp_info->_ptr + _offset), \
6614b24e2bSVaishali Kulkarni 		 _val)
6714b24e2bSVaishali Kulkarni 
6814b24e2bSVaishali Kulkarni #define DRV_INNER_RD(_p_hwfn, _p_ptt, _ptr, _offset) \
6914b24e2bSVaishali Kulkarni 	ecore_rd(_p_hwfn, _p_ptt, (_p_hwfn->mcp_info->_ptr + _offset))
7014b24e2bSVaishali Kulkarni 
7114b24e2bSVaishali Kulkarni #define DRV_MB_WR(_p_hwfn, _p_ptt, _field, _val) \
7214b24e2bSVaishali Kulkarni 	DRV_INNER_WR(p_hwfn, _p_ptt, drv_mb_addr, \
73*04443fdeSToomas Soome 		     offsetof(struct public_drv_mb, _field), _val)
7414b24e2bSVaishali Kulkarni 
7514b24e2bSVaishali Kulkarni #define DRV_MB_RD(_p_hwfn, _p_ptt, _field) \
7614b24e2bSVaishali Kulkarni 	DRV_INNER_RD(_p_hwfn, _p_ptt, drv_mb_addr, \
77*04443fdeSToomas Soome 		     offsetof(struct public_drv_mb, _field))
7814b24e2bSVaishali Kulkarni 
7914b24e2bSVaishali Kulkarni #define PDA_COMP (((FW_MAJOR_VERSION) + (FW_MINOR_VERSION << 8)) << \
8014b24e2bSVaishali Kulkarni 	DRV_ID_PDA_COMP_VER_SHIFT)
8114b24e2bSVaishali Kulkarni 
8214b24e2bSVaishali Kulkarni #define MCP_BYTES_PER_MBIT_SHIFT 17
8314b24e2bSVaishali Kulkarni 
8414b24e2bSVaishali Kulkarni #ifndef ASIC_ONLY
8514b24e2bSVaishali Kulkarni static int loaded;
8614b24e2bSVaishali Kulkarni static int loaded_port[MAX_NUM_PORTS] = { 0 };
8714b24e2bSVaishali Kulkarni #endif
8814b24e2bSVaishali Kulkarni 
ecore_mcp_is_init(struct ecore_hwfn * p_hwfn)8914b24e2bSVaishali Kulkarni bool ecore_mcp_is_init(struct ecore_hwfn *p_hwfn)
9014b24e2bSVaishali Kulkarni {
9114b24e2bSVaishali Kulkarni 	if (!p_hwfn->mcp_info || !p_hwfn->mcp_info->public_base)
9214b24e2bSVaishali Kulkarni 		return false;
9314b24e2bSVaishali Kulkarni 	return true;
9414b24e2bSVaishali Kulkarni }
9514b24e2bSVaishali Kulkarni 
ecore_mcp_cmd_port_init(struct ecore_hwfn * p_hwfn,struct ecore_ptt * p_ptt)9614b24e2bSVaishali Kulkarni void ecore_mcp_cmd_port_init(struct ecore_hwfn *p_hwfn,
9714b24e2bSVaishali Kulkarni 			     struct ecore_ptt *p_ptt)
9814b24e2bSVaishali Kulkarni {
9914b24e2bSVaishali Kulkarni 	u32 addr = SECTION_OFFSIZE_ADDR(p_hwfn->mcp_info->public_base,
10014b24e2bSVaishali Kulkarni 					PUBLIC_PORT);
10114b24e2bSVaishali Kulkarni 	u32 mfw_mb_offsize = ecore_rd(p_hwfn, p_ptt, addr);
10214b24e2bSVaishali Kulkarni 
10314b24e2bSVaishali Kulkarni 	p_hwfn->mcp_info->port_addr = SECTION_ADDR(mfw_mb_offsize,
10414b24e2bSVaishali Kulkarni 						   MFW_PORT(p_hwfn));
10514b24e2bSVaishali Kulkarni 	DP_VERBOSE(p_hwfn, ECORE_MSG_SP,
10614b24e2bSVaishali Kulkarni 		   "port_addr = 0x%x, port_id 0x%02x\n",
10714b24e2bSVaishali Kulkarni 		   p_hwfn->mcp_info->port_addr, MFW_PORT(p_hwfn));
10814b24e2bSVaishali Kulkarni }
10914b24e2bSVaishali Kulkarni 
ecore_mcp_read_mb(struct ecore_hwfn * p_hwfn,struct ecore_ptt * p_ptt)11014b24e2bSVaishali Kulkarni void ecore_mcp_read_mb(struct ecore_hwfn *p_hwfn,
11114b24e2bSVaishali Kulkarni 		       struct ecore_ptt *p_ptt)
11214b24e2bSVaishali Kulkarni {
11314b24e2bSVaishali Kulkarni 	u32 length = MFW_DRV_MSG_MAX_DWORDS(p_hwfn->mcp_info->mfw_mb_length);
11414b24e2bSVaishali Kulkarni 	OSAL_BE32 tmp;
11514b24e2bSVaishali Kulkarni 	u32 i;
11614b24e2bSVaishali Kulkarni 
11714b24e2bSVaishali Kulkarni #ifndef ASIC_ONLY
11814b24e2bSVaishali Kulkarni 	if (CHIP_REV_IS_TEDIBEAR(p_hwfn->p_dev))
11914b24e2bSVaishali Kulkarni 		return;
12014b24e2bSVaishali Kulkarni #endif
12114b24e2bSVaishali Kulkarni 
12214b24e2bSVaishali Kulkarni 	if (!p_hwfn->mcp_info->public_base)
12314b24e2bSVaishali Kulkarni 		return;
12414b24e2bSVaishali Kulkarni 
12514b24e2bSVaishali Kulkarni 	for (i = 0; i < length; i++) {
12614b24e2bSVaishali Kulkarni 		tmp = ecore_rd(p_hwfn, p_ptt,
12714b24e2bSVaishali Kulkarni 			       p_hwfn->mcp_info->mfw_mb_addr +
12814b24e2bSVaishali Kulkarni 			       (i << 2) + sizeof(u32));
12914b24e2bSVaishali Kulkarni 
13014b24e2bSVaishali Kulkarni 		((u32 *)p_hwfn->mcp_info->mfw_mb_cur)[i] =
13114b24e2bSVaishali Kulkarni 						OSAL_BE32_TO_CPU(tmp);
13214b24e2bSVaishali Kulkarni 	}
13314b24e2bSVaishali Kulkarni }
13414b24e2bSVaishali Kulkarni 
ecore_mcp_free(struct ecore_hwfn * p_hwfn)13514b24e2bSVaishali Kulkarni enum _ecore_status_t ecore_mcp_free(struct ecore_hwfn *p_hwfn)
13614b24e2bSVaishali Kulkarni {
13714b24e2bSVaishali Kulkarni 	if (p_hwfn->mcp_info) {
13814b24e2bSVaishali Kulkarni 		OSAL_FREE(p_hwfn->p_dev, p_hwfn->mcp_info->mfw_mb_cur);
13914b24e2bSVaishali Kulkarni 		OSAL_FREE(p_hwfn->p_dev, p_hwfn->mcp_info->mfw_mb_shadow);
14014b24e2bSVaishali Kulkarni #ifdef CONFIG_ECORE_LOCK_ALLOC
14114b24e2bSVaishali Kulkarni 		OSAL_SPIN_LOCK_DEALLOC(&p_hwfn->mcp_info->lock);
14214b24e2bSVaishali Kulkarni 		OSAL_SPIN_LOCK_DEALLOC(&p_hwfn->mcp_info->link_lock);
14314b24e2bSVaishali Kulkarni #endif
14414b24e2bSVaishali Kulkarni 	}
14514b24e2bSVaishali Kulkarni 	OSAL_FREE(p_hwfn->p_dev, p_hwfn->mcp_info);
14614b24e2bSVaishali Kulkarni 	p_hwfn->mcp_info = OSAL_NULL;
14714b24e2bSVaishali Kulkarni 
14814b24e2bSVaishali Kulkarni 	return ECORE_SUCCESS;
14914b24e2bSVaishali Kulkarni }
15014b24e2bSVaishali Kulkarni 
ecore_load_mcp_offsets(struct ecore_hwfn * p_hwfn,struct ecore_ptt * p_ptt)15114b24e2bSVaishali Kulkarni enum _ecore_status_t ecore_load_mcp_offsets(struct ecore_hwfn *p_hwfn,
15214b24e2bSVaishali Kulkarni 					    struct ecore_ptt *p_ptt)
15314b24e2bSVaishali Kulkarni {
15414b24e2bSVaishali Kulkarni 	struct ecore_mcp_info *p_info = p_hwfn->mcp_info;
15514b24e2bSVaishali Kulkarni 	u32 drv_mb_offsize, mfw_mb_offsize;
15614b24e2bSVaishali Kulkarni 	u32 mcp_pf_id = MCP_PF_ID(p_hwfn);
15714b24e2bSVaishali Kulkarni 
15814b24e2bSVaishali Kulkarni #ifndef ASIC_ONLY
15914b24e2bSVaishali Kulkarni 	if (CHIP_REV_IS_EMUL(p_hwfn->p_dev)) {
16014b24e2bSVaishali Kulkarni 		DP_NOTICE(p_hwfn, false, "Emulation - assume no MFW\n");
16114b24e2bSVaishali Kulkarni 		p_info->public_base = 0;
16214b24e2bSVaishali Kulkarni 		return ECORE_INVAL;
16314b24e2bSVaishali Kulkarni 	}
16414b24e2bSVaishali Kulkarni #endif
16514b24e2bSVaishali Kulkarni 
16614b24e2bSVaishali Kulkarni 	p_info->public_base = ecore_rd(p_hwfn, p_ptt, MISC_REG_SHARED_MEM_ADDR);
16714b24e2bSVaishali Kulkarni 	if (!p_info->public_base)
16814b24e2bSVaishali Kulkarni 			return ECORE_INVAL;
16914b24e2bSVaishali Kulkarni 
17014b24e2bSVaishali Kulkarni 	p_info->public_base |= GRCBASE_MCP;
17114b24e2bSVaishali Kulkarni 
17214b24e2bSVaishali Kulkarni 	/* Calculate the driver and MFW mailbox address */
17314b24e2bSVaishali Kulkarni 	drv_mb_offsize = ecore_rd(p_hwfn, p_ptt,
17414b24e2bSVaishali Kulkarni 				  SECTION_OFFSIZE_ADDR(p_info->public_base,
17514b24e2bSVaishali Kulkarni 						       PUBLIC_DRV_MB));
17614b24e2bSVaishali Kulkarni 	p_info->drv_mb_addr = SECTION_ADDR(drv_mb_offsize, mcp_pf_id);
17714b24e2bSVaishali Kulkarni 	DP_VERBOSE(p_hwfn, ECORE_MSG_SP,
17814b24e2bSVaishali Kulkarni 		   "drv_mb_offsiz = 0x%x, drv_mb_addr = 0x%x mcp_pf_id = 0x%x\n",
17914b24e2bSVaishali Kulkarni 		   drv_mb_offsize, p_info->drv_mb_addr, mcp_pf_id);
18014b24e2bSVaishali Kulkarni 
18114b24e2bSVaishali Kulkarni 	/* Set the MFW MB address */
18214b24e2bSVaishali Kulkarni 	mfw_mb_offsize = ecore_rd(p_hwfn, p_ptt,
18314b24e2bSVaishali Kulkarni 				  SECTION_OFFSIZE_ADDR(p_info->public_base,
18414b24e2bSVaishali Kulkarni 				  PUBLIC_MFW_MB));
18514b24e2bSVaishali Kulkarni 	p_info->mfw_mb_addr = SECTION_ADDR(mfw_mb_offsize, mcp_pf_id);
18614b24e2bSVaishali Kulkarni 	p_info->mfw_mb_length = (u16)ecore_rd(p_hwfn, p_ptt,
18714b24e2bSVaishali Kulkarni 					      p_info->mfw_mb_addr);
18814b24e2bSVaishali Kulkarni 
18914b24e2bSVaishali Kulkarni 	/* Get the current driver mailbox sequence before sending
19014b24e2bSVaishali Kulkarni 	 * the first command
19114b24e2bSVaishali Kulkarni 	 */
19214b24e2bSVaishali Kulkarni 	p_info->drv_mb_seq = DRV_MB_RD(p_hwfn, p_ptt, drv_mb_header) &
19314b24e2bSVaishali Kulkarni 				       DRV_MSG_SEQ_NUMBER_MASK;
19414b24e2bSVaishali Kulkarni 
19514b24e2bSVaishali Kulkarni 	/* Get current FW pulse sequence */
19614b24e2bSVaishali Kulkarni 	p_info->drv_pulse_seq = DRV_MB_RD(p_hwfn, p_ptt, drv_pulse_mb) &
19714b24e2bSVaishali Kulkarni 				DRV_PULSE_SEQ_MASK;
19814b24e2bSVaishali Kulkarni 
19914b24e2bSVaishali Kulkarni 	p_info->mcp_hist = (u16)ecore_rd(p_hwfn, p_ptt,
20014b24e2bSVaishali Kulkarni 					 MISCS_REG_GENERIC_POR_0);
20114b24e2bSVaishali Kulkarni 
20214b24e2bSVaishali Kulkarni 	return ECORE_SUCCESS;
20314b24e2bSVaishali Kulkarni }
20414b24e2bSVaishali Kulkarni 
ecore_mcp_cmd_init(struct ecore_hwfn * p_hwfn,struct ecore_ptt * p_ptt)20514b24e2bSVaishali Kulkarni enum _ecore_status_t ecore_mcp_cmd_init(struct ecore_hwfn *p_hwfn,
20614b24e2bSVaishali Kulkarni 					struct ecore_ptt *p_ptt)
20714b24e2bSVaishali Kulkarni {
20814b24e2bSVaishali Kulkarni 	struct ecore_mcp_info *p_info;
20914b24e2bSVaishali Kulkarni 	u32 size;
21014b24e2bSVaishali Kulkarni 
21114b24e2bSVaishali Kulkarni 	/* Allocate mcp_info structure */
21214b24e2bSVaishali Kulkarni 	p_hwfn->mcp_info = OSAL_ZALLOC(p_hwfn->p_dev, GFP_KERNEL,
21314b24e2bSVaishali Kulkarni 				       sizeof(*p_hwfn->mcp_info));
21414b24e2bSVaishali Kulkarni 	if (!p_hwfn->mcp_info)
21514b24e2bSVaishali Kulkarni 		goto err;
21614b24e2bSVaishali Kulkarni 	p_info = p_hwfn->mcp_info;
21714b24e2bSVaishali Kulkarni 
21814b24e2bSVaishali Kulkarni 	if (ecore_load_mcp_offsets(p_hwfn, p_ptt) != ECORE_SUCCESS) {
21914b24e2bSVaishali Kulkarni 		DP_NOTICE(p_hwfn, false, "MCP is not initialized\n");
22014b24e2bSVaishali Kulkarni 		/* Do not free mcp_info here, since public_base indicate that
22114b24e2bSVaishali Kulkarni 		 * the MCP is not initialized
22214b24e2bSVaishali Kulkarni 		 */
22314b24e2bSVaishali Kulkarni 		return ECORE_SUCCESS;
22414b24e2bSVaishali Kulkarni 	}
22514b24e2bSVaishali Kulkarni 
22614b24e2bSVaishali Kulkarni 	size = MFW_DRV_MSG_MAX_DWORDS(p_info->mfw_mb_length) * sizeof(u32);
22714b24e2bSVaishali Kulkarni 	p_info->mfw_mb_cur = OSAL_ZALLOC(p_hwfn->p_dev, GFP_KERNEL, size);
22814b24e2bSVaishali Kulkarni 	p_info->mfw_mb_shadow = OSAL_ZALLOC(p_hwfn->p_dev, GFP_KERNEL, size);
22914b24e2bSVaishali Kulkarni 	if (!p_info->mfw_mb_shadow || !p_info->mfw_mb_addr)
23014b24e2bSVaishali Kulkarni 		goto err;
23114b24e2bSVaishali Kulkarni 
23214b24e2bSVaishali Kulkarni 	/* Initialize the MFW spinlock */
23314b24e2bSVaishali Kulkarni #ifdef CONFIG_ECORE_LOCK_ALLOC
23414b24e2bSVaishali Kulkarni 	OSAL_SPIN_LOCK_ALLOC(p_hwfn, &p_info->lock);
23514b24e2bSVaishali Kulkarni 	OSAL_SPIN_LOCK_ALLOC(p_hwfn, &p_info->link_lock);
23614b24e2bSVaishali Kulkarni #endif
23714b24e2bSVaishali Kulkarni 	OSAL_SPIN_LOCK_INIT(&p_info->lock);
23814b24e2bSVaishali Kulkarni 	OSAL_SPIN_LOCK_INIT(&p_info->link_lock);
23914b24e2bSVaishali Kulkarni 
24014b24e2bSVaishali Kulkarni 	return ECORE_SUCCESS;
24114b24e2bSVaishali Kulkarni 
24214b24e2bSVaishali Kulkarni err:
24314b24e2bSVaishali Kulkarni 	DP_NOTICE(p_hwfn, true, "Failed to allocate mcp memory\n");
24414b24e2bSVaishali Kulkarni 	ecore_mcp_free(p_hwfn);
24514b24e2bSVaishali Kulkarni 	return ECORE_NOMEM;
24614b24e2bSVaishali Kulkarni 
24714b24e2bSVaishali Kulkarni }
24814b24e2bSVaishali Kulkarni 
24914b24e2bSVaishali Kulkarni /* Locks the MFW mailbox of a PF to ensure a single access.
25014b24e2bSVaishali Kulkarni  * The lock is achieved in most cases by holding a spinlock, causing other
25114b24e2bSVaishali Kulkarni  * threads to wait till a previous access is done.
25214b24e2bSVaishali Kulkarni  * In some cases (currently when a [UN]LOAD_REQ commands are sent), the single
25314b24e2bSVaishali Kulkarni  * access is achieved by setting a blocking flag, which will fail other
25414b24e2bSVaishali Kulkarni  * competing contexts to send their mailboxes.
25514b24e2bSVaishali Kulkarni  */
ecore_mcp_mb_lock(struct ecore_hwfn * p_hwfn,u32 cmd)25614b24e2bSVaishali Kulkarni static enum _ecore_status_t ecore_mcp_mb_lock(struct ecore_hwfn *p_hwfn,
25714b24e2bSVaishali Kulkarni 					      u32 cmd)
25814b24e2bSVaishali Kulkarni {
25914b24e2bSVaishali Kulkarni 	OSAL_SPIN_LOCK(&p_hwfn->mcp_info->lock);
26014b24e2bSVaishali Kulkarni 
26114b24e2bSVaishali Kulkarni 	/* The spinlock shouldn't be acquired when the mailbox command is
26214b24e2bSVaishali Kulkarni 	 * [UN]LOAD_REQ, since the engine is locked by the MFW, and a parallel
26314b24e2bSVaishali Kulkarni 	 * pending [UN]LOAD_REQ command of another PF together with a spinlock
26414b24e2bSVaishali Kulkarni 	 * (i.e. interrupts are disabled) - can lead to a deadlock.
26514b24e2bSVaishali Kulkarni 	 * It is assumed that for a single PF, no other mailbox commands can be
26614b24e2bSVaishali Kulkarni 	 * sent from another context while sending LOAD_REQ, and that any
26714b24e2bSVaishali Kulkarni 	 * parallel commands to UNLOAD_REQ can be cancelled.
26814b24e2bSVaishali Kulkarni 	 */
26914b24e2bSVaishali Kulkarni 	if (cmd == DRV_MSG_CODE_LOAD_DONE || cmd == DRV_MSG_CODE_UNLOAD_DONE)
27014b24e2bSVaishali Kulkarni 		p_hwfn->mcp_info->block_mb_sending = false;
27114b24e2bSVaishali Kulkarni 
27214b24e2bSVaishali Kulkarni 	/* There's at least a single command that is sent by ecore during the
27314b24e2bSVaishali Kulkarni 	 * load sequence [expectation of MFW].
27414b24e2bSVaishali Kulkarni 	 */
27514b24e2bSVaishali Kulkarni 	if ((p_hwfn->mcp_info->block_mb_sending) &&
27614b24e2bSVaishali Kulkarni 	    (cmd != DRV_MSG_CODE_FEATURE_SUPPORT)) {
27714b24e2bSVaishali Kulkarni 		DP_NOTICE(p_hwfn, false,
27814b24e2bSVaishali Kulkarni 			  "Trying to send a MFW mailbox command [0x%x] in parallel to [UN]LOAD_REQ. Aborting.\n",
27914b24e2bSVaishali Kulkarni 			  cmd);
28014b24e2bSVaishali Kulkarni 		OSAL_SPIN_UNLOCK(&p_hwfn->mcp_info->lock);
28114b24e2bSVaishali Kulkarni 		return ECORE_BUSY;
28214b24e2bSVaishali Kulkarni 	}
28314b24e2bSVaishali Kulkarni 
28414b24e2bSVaishali Kulkarni 	if (cmd == DRV_MSG_CODE_LOAD_REQ || cmd == DRV_MSG_CODE_UNLOAD_REQ) {
28514b24e2bSVaishali Kulkarni 		p_hwfn->mcp_info->block_mb_sending = true;
28614b24e2bSVaishali Kulkarni 		OSAL_SPIN_UNLOCK(&p_hwfn->mcp_info->lock);
28714b24e2bSVaishali Kulkarni 	}
28814b24e2bSVaishali Kulkarni 
28914b24e2bSVaishali Kulkarni 	return ECORE_SUCCESS;
29014b24e2bSVaishali Kulkarni }
29114b24e2bSVaishali Kulkarni 
ecore_mcp_mb_unlock(struct ecore_hwfn * p_hwfn,u32 cmd)29214b24e2bSVaishali Kulkarni static void ecore_mcp_mb_unlock(struct ecore_hwfn *p_hwfn, u32 cmd)
29314b24e2bSVaishali Kulkarni {
29414b24e2bSVaishali Kulkarni 	if (cmd != DRV_MSG_CODE_LOAD_REQ && cmd != DRV_MSG_CODE_UNLOAD_REQ)
29514b24e2bSVaishali Kulkarni 		OSAL_SPIN_UNLOCK(&p_hwfn->mcp_info->lock);
29614b24e2bSVaishali Kulkarni }
29714b24e2bSVaishali Kulkarni 
ecore_mcp_reset(struct ecore_hwfn * p_hwfn,struct ecore_ptt * p_ptt)29814b24e2bSVaishali Kulkarni enum _ecore_status_t ecore_mcp_reset(struct ecore_hwfn *p_hwfn,
29914b24e2bSVaishali Kulkarni 				     struct ecore_ptt *p_ptt)
30014b24e2bSVaishali Kulkarni {
30114b24e2bSVaishali Kulkarni 	u32 seq = ++p_hwfn->mcp_info->drv_mb_seq;
30214b24e2bSVaishali Kulkarni 	u32 delay = CHIP_MCP_RESP_ITER_US;
30314b24e2bSVaishali Kulkarni 	u32 org_mcp_reset_seq, cnt = 0;
30414b24e2bSVaishali Kulkarni 	enum _ecore_status_t rc = ECORE_SUCCESS;
30514b24e2bSVaishali Kulkarni 
30614b24e2bSVaishali Kulkarni #ifndef ASIC_ONLY
30714b24e2bSVaishali Kulkarni 	if (CHIP_REV_IS_EMUL(p_hwfn->p_dev))
30814b24e2bSVaishali Kulkarni 		delay = EMUL_MCP_RESP_ITER_US;
30914b24e2bSVaishali Kulkarni #endif
31014b24e2bSVaishali Kulkarni 
31114b24e2bSVaishali Kulkarni 	/* Ensure that only a single thread is accessing the mailbox at a
31214b24e2bSVaishali Kulkarni 	 * certain time.
31314b24e2bSVaishali Kulkarni 	 */
31414b24e2bSVaishali Kulkarni 	rc = ecore_mcp_mb_lock(p_hwfn, DRV_MSG_CODE_MCP_RESET);
31514b24e2bSVaishali Kulkarni 	if (rc != ECORE_SUCCESS)
31614b24e2bSVaishali Kulkarni 		return rc;
31714b24e2bSVaishali Kulkarni 
31814b24e2bSVaishali Kulkarni 	/* Set drv command along with the updated sequence */
31914b24e2bSVaishali Kulkarni 	org_mcp_reset_seq = ecore_rd(p_hwfn, p_ptt, MISCS_REG_GENERIC_POR_0);
32014b24e2bSVaishali Kulkarni 	DRV_MB_WR(p_hwfn, p_ptt, drv_mb_header, (DRV_MSG_CODE_MCP_RESET | seq));
32114b24e2bSVaishali Kulkarni 
32214b24e2bSVaishali Kulkarni 	do {
32314b24e2bSVaishali Kulkarni 		/* Wait for MFW response */
32414b24e2bSVaishali Kulkarni 		OSAL_UDELAY(delay);
32514b24e2bSVaishali Kulkarni 		/* Give the FW up to 500 second (50*1000*10usec) */
32614b24e2bSVaishali Kulkarni 	} while ((org_mcp_reset_seq == ecore_rd(p_hwfn, p_ptt,
32714b24e2bSVaishali Kulkarni 						MISCS_REG_GENERIC_POR_0)) &&
32814b24e2bSVaishali Kulkarni 		 (cnt++ < ECORE_MCP_RESET_RETRIES));
32914b24e2bSVaishali Kulkarni 
33014b24e2bSVaishali Kulkarni 	if (org_mcp_reset_seq !=
33114b24e2bSVaishali Kulkarni 	    ecore_rd(p_hwfn, p_ptt, MISCS_REG_GENERIC_POR_0)) {
33214b24e2bSVaishali Kulkarni 		DP_VERBOSE(p_hwfn, ECORE_MSG_SP,
33314b24e2bSVaishali Kulkarni 			   "MCP was reset after %d usec\n", cnt * delay);
33414b24e2bSVaishali Kulkarni 	} else {
33514b24e2bSVaishali Kulkarni 		DP_ERR(p_hwfn, "Failed to reset MCP\n");
33614b24e2bSVaishali Kulkarni 		rc = ECORE_AGAIN;
33714b24e2bSVaishali Kulkarni 	}
33814b24e2bSVaishali Kulkarni 
33914b24e2bSVaishali Kulkarni 	ecore_mcp_mb_unlock(p_hwfn, DRV_MSG_CODE_MCP_RESET);
34014b24e2bSVaishali Kulkarni 
34114b24e2bSVaishali Kulkarni 	return rc;
34214b24e2bSVaishali Kulkarni }
34314b24e2bSVaishali Kulkarni 
ecore_mcp_print_cpu_info(struct ecore_hwfn * p_hwfn,struct ecore_ptt * p_ptt)34414b24e2bSVaishali Kulkarni void ecore_mcp_print_cpu_info(struct ecore_hwfn *p_hwfn,
34514b24e2bSVaishali Kulkarni 			      struct ecore_ptt *p_ptt)
34614b24e2bSVaishali Kulkarni {
34714b24e2bSVaishali Kulkarni 	u32 cpu_mode, cpu_state, cpu_pc_0, cpu_pc_1, cpu_pc_2;
34814b24e2bSVaishali Kulkarni 
34914b24e2bSVaishali Kulkarni 	cpu_mode = ecore_rd(p_hwfn, p_ptt, MCP_REG_CPU_MODE);
35014b24e2bSVaishali Kulkarni 	cpu_state = ecore_rd(p_hwfn, p_ptt, MCP_REG_CPU_STATE);
35114b24e2bSVaishali Kulkarni 	cpu_pc_0 = ecore_rd(p_hwfn, p_ptt, MCP_REG_CPU_PROGRAM_COUNTER);
35214b24e2bSVaishali Kulkarni 	OSAL_UDELAY(CHIP_MCP_RESP_ITER_US);
35314b24e2bSVaishali Kulkarni 	cpu_pc_1 = ecore_rd(p_hwfn, p_ptt, MCP_REG_CPU_PROGRAM_COUNTER);
35414b24e2bSVaishali Kulkarni 	OSAL_UDELAY(CHIP_MCP_RESP_ITER_US);
35514b24e2bSVaishali Kulkarni 	cpu_pc_2 = ecore_rd(p_hwfn, p_ptt, MCP_REG_CPU_PROGRAM_COUNTER);
35614b24e2bSVaishali Kulkarni 
35714b24e2bSVaishali Kulkarni 	DP_NOTICE(p_hwfn, false,
35814b24e2bSVaishali Kulkarni 		  "MCP CPU info: mode 0x%08x, state 0x%08x, pc {0x%08x, 0x%08x, 0x%08x}\n",
35914b24e2bSVaishali Kulkarni 		  cpu_mode, cpu_state, cpu_pc_0, cpu_pc_1, cpu_pc_2);
36014b24e2bSVaishali Kulkarni }
36114b24e2bSVaishali Kulkarni 
ecore_do_mcp_cmd(struct ecore_hwfn * p_hwfn,struct ecore_ptt * p_ptt,u32 cmd,u32 param,u32 * o_mcp_resp,u32 * o_mcp_param)36214b24e2bSVaishali Kulkarni static enum _ecore_status_t ecore_do_mcp_cmd(struct ecore_hwfn *p_hwfn,
36314b24e2bSVaishali Kulkarni 					     struct ecore_ptt *p_ptt,
36414b24e2bSVaishali Kulkarni 					     u32 cmd, u32 param,
36514b24e2bSVaishali Kulkarni 					     u32 *o_mcp_resp, u32 *o_mcp_param)
36614b24e2bSVaishali Kulkarni {
36714b24e2bSVaishali Kulkarni 	u32 delay = CHIP_MCP_RESP_ITER_US;
36814b24e2bSVaishali Kulkarni 	u32 max_retries = ECORE_DRV_MB_MAX_RETRIES;
369b68ddc76SJohn Levon 	u32 seq, cnt = 1, actual_mb_seq __unused;
37014b24e2bSVaishali Kulkarni 	enum _ecore_status_t rc = ECORE_SUCCESS;
37114b24e2bSVaishali Kulkarni 
37214b24e2bSVaishali Kulkarni #ifndef ASIC_ONLY
37314b24e2bSVaishali Kulkarni 	if (CHIP_REV_IS_EMUL(p_hwfn->p_dev))
37414b24e2bSVaishali Kulkarni 		delay = EMUL_MCP_RESP_ITER_US;
37514b24e2bSVaishali Kulkarni 	/* There is a built-in delay of 100usec in each MFW response read */
37614b24e2bSVaishali Kulkarni 	if (CHIP_REV_IS_FPGA(p_hwfn->p_dev))
37714b24e2bSVaishali Kulkarni 		max_retries /= 10;
37814b24e2bSVaishali Kulkarni #endif
37914b24e2bSVaishali Kulkarni 
38014b24e2bSVaishali Kulkarni 	/* Get actual driver mailbox sequence */
38114b24e2bSVaishali Kulkarni 	actual_mb_seq = DRV_MB_RD(p_hwfn, p_ptt, drv_mb_header) &
38214b24e2bSVaishali Kulkarni 			DRV_MSG_SEQ_NUMBER_MASK;
38314b24e2bSVaishali Kulkarni 
38414b24e2bSVaishali Kulkarni 	/* Use MCP history register to check if MCP reset occurred between
38514b24e2bSVaishali Kulkarni 	 * init time and now.
38614b24e2bSVaishali Kulkarni 	 */
38714b24e2bSVaishali Kulkarni 	if (p_hwfn->mcp_info->mcp_hist !=
38814b24e2bSVaishali Kulkarni 	    ecore_rd(p_hwfn, p_ptt, MISCS_REG_GENERIC_POR_0)) {
38914b24e2bSVaishali Kulkarni 		DP_VERBOSE(p_hwfn, ECORE_MSG_SP, "Rereading MCP offsets\n");
39014b24e2bSVaishali Kulkarni 		ecore_load_mcp_offsets(p_hwfn, p_ptt);
39114b24e2bSVaishali Kulkarni 		ecore_mcp_cmd_port_init(p_hwfn, p_ptt);
39214b24e2bSVaishali Kulkarni 	}
39314b24e2bSVaishali Kulkarni 	seq = ++p_hwfn->mcp_info->drv_mb_seq;
39414b24e2bSVaishali Kulkarni 
39514b24e2bSVaishali Kulkarni 	/* Set drv param */
39614b24e2bSVaishali Kulkarni 	DRV_MB_WR(p_hwfn, p_ptt, drv_mb_param, param);
39714b24e2bSVaishali Kulkarni 
39814b24e2bSVaishali Kulkarni 	/* Set drv command along with the updated sequence */
39914b24e2bSVaishali Kulkarni 	DRV_MB_WR(p_hwfn, p_ptt, drv_mb_header, (cmd | seq));
40014b24e2bSVaishali Kulkarni 
40114b24e2bSVaishali Kulkarni 	DP_VERBOSE(p_hwfn, ECORE_MSG_SP,
40214b24e2bSVaishali Kulkarni 		   "wrote command (%x) to MFW MB param 0x%08x\n",
40314b24e2bSVaishali Kulkarni 		   (cmd | seq), param);
40414b24e2bSVaishali Kulkarni 
40514b24e2bSVaishali Kulkarni 	do {
40614b24e2bSVaishali Kulkarni 		/* Wait for MFW response */
40714b24e2bSVaishali Kulkarni 		OSAL_UDELAY(delay);
40814b24e2bSVaishali Kulkarni 		*o_mcp_resp = DRV_MB_RD(p_hwfn, p_ptt, fw_mb_header);
40914b24e2bSVaishali Kulkarni 
41014b24e2bSVaishali Kulkarni 		/* Give the FW up to 5 second (500*10ms) */
41114b24e2bSVaishali Kulkarni 	} while ((seq != (*o_mcp_resp & FW_MSG_SEQ_NUMBER_MASK)) &&
41214b24e2bSVaishali Kulkarni 		 (cnt++ < max_retries));
41314b24e2bSVaishali Kulkarni 
41414b24e2bSVaishali Kulkarni 	DP_VERBOSE(p_hwfn, ECORE_MSG_SP,
41514b24e2bSVaishali Kulkarni 		   "[after %d ms] read (%x) seq is (%x) from FW MB\n",
41614b24e2bSVaishali Kulkarni 		   cnt * delay, *o_mcp_resp, seq);
41714b24e2bSVaishali Kulkarni 
41814b24e2bSVaishali Kulkarni 	/* Is this a reply to our command? */
41914b24e2bSVaishali Kulkarni 	if (seq == (*o_mcp_resp & FW_MSG_SEQ_NUMBER_MASK)) {
42014b24e2bSVaishali Kulkarni 		*o_mcp_resp &= FW_MSG_CODE_MASK;
42114b24e2bSVaishali Kulkarni 		/* Get the MCP param */
42214b24e2bSVaishali Kulkarni 		*o_mcp_param = DRV_MB_RD(p_hwfn, p_ptt, fw_mb_param);
42314b24e2bSVaishali Kulkarni 	} else {
42414b24e2bSVaishali Kulkarni 		/* FW BUG! */
42514b24e2bSVaishali Kulkarni 		DP_ERR(p_hwfn, "MFW failed to respond [cmd 0x%x param 0x%x]\n",
42614b24e2bSVaishali Kulkarni 		       cmd, param);
42714b24e2bSVaishali Kulkarni 		ecore_mcp_print_cpu_info(p_hwfn, p_ptt);
42814b24e2bSVaishali Kulkarni 		*o_mcp_resp = 0;
42914b24e2bSVaishali Kulkarni 		rc = ECORE_AGAIN;
43014b24e2bSVaishali Kulkarni 		ecore_hw_err_notify(p_hwfn, ECORE_HW_ERR_MFW_RESP_FAIL);
43114b24e2bSVaishali Kulkarni 	}
43214b24e2bSVaishali Kulkarni 	return rc;
43314b24e2bSVaishali Kulkarni }
43414b24e2bSVaishali Kulkarni 
ecore_mcp_cmd_and_union(struct ecore_hwfn * p_hwfn,struct ecore_ptt * p_ptt,struct ecore_mcp_mb_params * p_mb_params)43514b24e2bSVaishali Kulkarni static enum _ecore_status_t ecore_mcp_cmd_and_union(struct ecore_hwfn *p_hwfn,
43614b24e2bSVaishali Kulkarni 						    struct ecore_ptt *p_ptt,
43714b24e2bSVaishali Kulkarni 						    struct ecore_mcp_mb_params *p_mb_params)
43814b24e2bSVaishali Kulkarni {
43914b24e2bSVaishali Kulkarni 	union drv_union_data union_data;
44014b24e2bSVaishali Kulkarni 	u32 union_data_addr;
44114b24e2bSVaishali Kulkarni 	enum _ecore_status_t rc;
44214b24e2bSVaishali Kulkarni 
44314b24e2bSVaishali Kulkarni 	/* MCP not initialized */
44414b24e2bSVaishali Kulkarni 	if (!ecore_mcp_is_init(p_hwfn)) {
44514b24e2bSVaishali Kulkarni 		DP_NOTICE(p_hwfn, true, "MFW is not initialized!\n");
44614b24e2bSVaishali Kulkarni 		return ECORE_BUSY;
44714b24e2bSVaishali Kulkarni 	}
44814b24e2bSVaishali Kulkarni 
44914b24e2bSVaishali Kulkarni 	if (p_mb_params->data_src_size > sizeof(union_data) ||
45014b24e2bSVaishali Kulkarni 	    p_mb_params->data_dst_size > sizeof(union_data)) {
45114b24e2bSVaishali Kulkarni 		DP_ERR(p_hwfn,
45214b24e2bSVaishali Kulkarni 		       "The provided size is larger than the union data size [src_size %u, dst_size %u, union_data_size %zu]\n",
45314b24e2bSVaishali Kulkarni 		       p_mb_params->data_src_size, p_mb_params->data_dst_size,
45414b24e2bSVaishali Kulkarni 		       sizeof(union_data));
45514b24e2bSVaishali Kulkarni 		return ECORE_INVAL;
45614b24e2bSVaishali Kulkarni 	}
45714b24e2bSVaishali Kulkarni 
45814b24e2bSVaishali Kulkarni 	union_data_addr = p_hwfn->mcp_info->drv_mb_addr +
459*04443fdeSToomas Soome 			  offsetof(struct public_drv_mb, union_data);
46014b24e2bSVaishali Kulkarni 
46114b24e2bSVaishali Kulkarni 	/* Ensure that only a single thread is accessing the mailbox at a
46214b24e2bSVaishali Kulkarni 	 * certain time.
46314b24e2bSVaishali Kulkarni 	 */
46414b24e2bSVaishali Kulkarni 	rc = ecore_mcp_mb_lock(p_hwfn, p_mb_params->cmd);
46514b24e2bSVaishali Kulkarni 	if (rc != ECORE_SUCCESS)
46614b24e2bSVaishali Kulkarni 		return rc;
46714b24e2bSVaishali Kulkarni 
46814b24e2bSVaishali Kulkarni 	OSAL_MEM_ZERO(&union_data, sizeof(union_data));
46914b24e2bSVaishali Kulkarni 	if (p_mb_params->p_data_src != OSAL_NULL && p_mb_params->data_src_size)
47014b24e2bSVaishali Kulkarni 		OSAL_MEMCPY(&union_data, p_mb_params->p_data_src,
47114b24e2bSVaishali Kulkarni 			    p_mb_params->data_src_size);
47214b24e2bSVaishali Kulkarni 	ecore_memcpy_to(p_hwfn, p_ptt, union_data_addr, &union_data,
47314b24e2bSVaishali Kulkarni 			sizeof(union_data));
47414b24e2bSVaishali Kulkarni 
47514b24e2bSVaishali Kulkarni 	rc = ecore_do_mcp_cmd(p_hwfn, p_ptt, p_mb_params->cmd,
47614b24e2bSVaishali Kulkarni 			      p_mb_params->param, &p_mb_params->mcp_resp,
47714b24e2bSVaishali Kulkarni 			      &p_mb_params->mcp_param);
47814b24e2bSVaishali Kulkarni 
47914b24e2bSVaishali Kulkarni 	if (p_mb_params->p_data_dst != OSAL_NULL &&
48014b24e2bSVaishali Kulkarni 	    p_mb_params->data_dst_size)
48114b24e2bSVaishali Kulkarni 		ecore_memcpy_from(p_hwfn, p_ptt, p_mb_params->p_data_dst,
48214b24e2bSVaishali Kulkarni 				  union_data_addr, p_mb_params->data_dst_size);
48314b24e2bSVaishali Kulkarni 
48414b24e2bSVaishali Kulkarni 	ecore_mcp_mb_unlock(p_hwfn, p_mb_params->cmd);
48514b24e2bSVaishali Kulkarni 
48614b24e2bSVaishali Kulkarni 	return rc;
48714b24e2bSVaishali Kulkarni }
48814b24e2bSVaishali Kulkarni 
ecore_mcp_cmd(struct ecore_hwfn * p_hwfn,struct ecore_ptt * p_ptt,u32 cmd,u32 param,u32 * o_mcp_resp,u32 * o_mcp_param)48914b24e2bSVaishali Kulkarni enum _ecore_status_t ecore_mcp_cmd(struct ecore_hwfn *p_hwfn,
49014b24e2bSVaishali Kulkarni 				   struct ecore_ptt *p_ptt, u32 cmd, u32 param,
49114b24e2bSVaishali Kulkarni 				   u32 *o_mcp_resp, u32 *o_mcp_param)
49214b24e2bSVaishali Kulkarni {
49314b24e2bSVaishali Kulkarni 	struct ecore_mcp_mb_params mb_params;
49414b24e2bSVaishali Kulkarni 	enum _ecore_status_t rc;
49514b24e2bSVaishali Kulkarni 
49614b24e2bSVaishali Kulkarni #ifndef ASIC_ONLY
49714b24e2bSVaishali Kulkarni 	if (CHIP_REV_IS_EMUL(p_hwfn->p_dev)) {
49814b24e2bSVaishali Kulkarni 		if (cmd == DRV_MSG_CODE_UNLOAD_REQ) {
49914b24e2bSVaishali Kulkarni 			loaded--;
50014b24e2bSVaishali Kulkarni 			loaded_port[p_hwfn->port_id]--;
50114b24e2bSVaishali Kulkarni 			DP_VERBOSE(p_hwfn, ECORE_MSG_SP, "Unload cnt: 0x%x\n",
50214b24e2bSVaishali Kulkarni 				   loaded);
50314b24e2bSVaishali Kulkarni 		}
50414b24e2bSVaishali Kulkarni 		return ECORE_SUCCESS;
50514b24e2bSVaishali Kulkarni 	}
50614b24e2bSVaishali Kulkarni #endif
50714b24e2bSVaishali Kulkarni 
50814b24e2bSVaishali Kulkarni 	OSAL_MEM_ZERO(&mb_params, sizeof(mb_params));
50914b24e2bSVaishali Kulkarni 	mb_params.cmd = cmd;
51014b24e2bSVaishali Kulkarni 	mb_params.param = param;
51114b24e2bSVaishali Kulkarni 	rc = ecore_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params);
51214b24e2bSVaishali Kulkarni 	if (rc != ECORE_SUCCESS)
51314b24e2bSVaishali Kulkarni 		return rc;
51414b24e2bSVaishali Kulkarni 
51514b24e2bSVaishali Kulkarni 	*o_mcp_resp = mb_params.mcp_resp;
51614b24e2bSVaishali Kulkarni 	*o_mcp_param = mb_params.mcp_param;
51714b24e2bSVaishali Kulkarni 
51814b24e2bSVaishali Kulkarni 	return ECORE_SUCCESS;
51914b24e2bSVaishali Kulkarni }
52014b24e2bSVaishali Kulkarni 
ecore_mcp_nvm_wr_cmd(struct ecore_hwfn * p_hwfn,struct ecore_ptt * p_ptt,u32 cmd,u32 param,u32 * o_mcp_resp,u32 * o_mcp_param,u32 i_txn_size,u32 * i_buf)52114b24e2bSVaishali Kulkarni enum _ecore_status_t ecore_mcp_nvm_wr_cmd(struct ecore_hwfn *p_hwfn,
52214b24e2bSVaishali Kulkarni 					  struct ecore_ptt *p_ptt,
52314b24e2bSVaishali Kulkarni 					  u32 cmd,
52414b24e2bSVaishali Kulkarni 					  u32 param,
52514b24e2bSVaishali Kulkarni 					  u32 *o_mcp_resp,
52614b24e2bSVaishali Kulkarni 					  u32 *o_mcp_param,
52714b24e2bSVaishali Kulkarni 					  u32 i_txn_size,
52814b24e2bSVaishali Kulkarni 					  u32 *i_buf)
52914b24e2bSVaishali Kulkarni {
53014b24e2bSVaishali Kulkarni 	struct ecore_mcp_mb_params mb_params;
53114b24e2bSVaishali Kulkarni 	enum _ecore_status_t rc;
53214b24e2bSVaishali Kulkarni 
53314b24e2bSVaishali Kulkarni 	OSAL_MEM_ZERO(&mb_params, sizeof(mb_params));
53414b24e2bSVaishali Kulkarni 	mb_params.cmd = cmd;
53514b24e2bSVaishali Kulkarni 	mb_params.param = param;
53614b24e2bSVaishali Kulkarni 	mb_params.p_data_src = i_buf;
53714b24e2bSVaishali Kulkarni 	mb_params.data_src_size = (u8) i_txn_size;
53814b24e2bSVaishali Kulkarni 	rc = ecore_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params);
53914b24e2bSVaishali Kulkarni 	if (rc != ECORE_SUCCESS)
54014b24e2bSVaishali Kulkarni 		return rc;
54114b24e2bSVaishali Kulkarni 
54214b24e2bSVaishali Kulkarni 	*o_mcp_resp = mb_params.mcp_resp;
54314b24e2bSVaishali Kulkarni 	*o_mcp_param = mb_params.mcp_param;
54414b24e2bSVaishali Kulkarni 
54514b24e2bSVaishali Kulkarni 	return ECORE_SUCCESS;
54614b24e2bSVaishali Kulkarni }
54714b24e2bSVaishali Kulkarni 
ecore_mcp_nvm_rd_cmd(struct ecore_hwfn * p_hwfn,struct ecore_ptt * p_ptt,u32 cmd,u32 param,u32 * o_mcp_resp,u32 * o_mcp_param,u32 * o_txn_size,u32 * o_buf)54814b24e2bSVaishali Kulkarni enum _ecore_status_t ecore_mcp_nvm_rd_cmd(struct ecore_hwfn *p_hwfn,
54914b24e2bSVaishali Kulkarni 					  struct ecore_ptt *p_ptt,
55014b24e2bSVaishali Kulkarni 					  u32 cmd,
55114b24e2bSVaishali Kulkarni 					  u32 param,
55214b24e2bSVaishali Kulkarni 					  u32 *o_mcp_resp,
55314b24e2bSVaishali Kulkarni 					  u32 *o_mcp_param,
55414b24e2bSVaishali Kulkarni 					  u32 *o_txn_size,
55514b24e2bSVaishali Kulkarni 					  u32 *o_buf)
55614b24e2bSVaishali Kulkarni {
55714b24e2bSVaishali Kulkarni 	struct ecore_mcp_mb_params mb_params;
55814b24e2bSVaishali Kulkarni 	u8 raw_data[MCP_DRV_NVM_BUF_LEN];
55914b24e2bSVaishali Kulkarni 	enum _ecore_status_t rc;
56014b24e2bSVaishali Kulkarni 
56114b24e2bSVaishali Kulkarni 	OSAL_MEM_ZERO(&mb_params, sizeof(mb_params));
56214b24e2bSVaishali Kulkarni 	mb_params.cmd = cmd;
56314b24e2bSVaishali Kulkarni 	mb_params.param = param;
56414b24e2bSVaishali Kulkarni 	mb_params.p_data_dst = raw_data;
56514b24e2bSVaishali Kulkarni 
56614b24e2bSVaishali Kulkarni 	/* Use the maximal value since the actual one is part of the response */
56714b24e2bSVaishali Kulkarni 	mb_params.data_dst_size = MCP_DRV_NVM_BUF_LEN;
56814b24e2bSVaishali Kulkarni 
56914b24e2bSVaishali Kulkarni 	rc = ecore_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params);
57014b24e2bSVaishali Kulkarni 	if (rc != ECORE_SUCCESS)
57114b24e2bSVaishali Kulkarni 		return rc;
57214b24e2bSVaishali Kulkarni 
57314b24e2bSVaishali Kulkarni 	*o_mcp_resp = mb_params.mcp_resp;
57414b24e2bSVaishali Kulkarni 	*o_mcp_param = mb_params.mcp_param;
57514b24e2bSVaishali Kulkarni 
57614b24e2bSVaishali Kulkarni 	*o_txn_size = *o_mcp_param;
57714b24e2bSVaishali Kulkarni 	OSAL_MEMCPY(o_buf, raw_data, *o_txn_size);
57814b24e2bSVaishali Kulkarni 
57914b24e2bSVaishali Kulkarni 	return ECORE_SUCCESS;
58014b24e2bSVaishali Kulkarni }
58114b24e2bSVaishali Kulkarni 
58214b24e2bSVaishali Kulkarni #ifndef ASIC_ONLY
ecore_mcp_mf_workaround(struct ecore_hwfn * p_hwfn,u32 * p_load_code)58314b24e2bSVaishali Kulkarni static void ecore_mcp_mf_workaround(struct ecore_hwfn *p_hwfn,
58414b24e2bSVaishali Kulkarni 				    u32 *p_load_code)
58514b24e2bSVaishali Kulkarni {
58614b24e2bSVaishali Kulkarni 	static int load_phase = FW_MSG_CODE_DRV_LOAD_ENGINE;
58714b24e2bSVaishali Kulkarni 
58814b24e2bSVaishali Kulkarni 	if (!loaded) {
58914b24e2bSVaishali Kulkarni 		load_phase = FW_MSG_CODE_DRV_LOAD_ENGINE;
59014b24e2bSVaishali Kulkarni 	} else if (!loaded_port[p_hwfn->port_id]) {
59114b24e2bSVaishali Kulkarni 		load_phase = FW_MSG_CODE_DRV_LOAD_PORT;
59214b24e2bSVaishali Kulkarni 	} else {
59314b24e2bSVaishali Kulkarni 		load_phase = FW_MSG_CODE_DRV_LOAD_FUNCTION;
59414b24e2bSVaishali Kulkarni 	}
59514b24e2bSVaishali Kulkarni 
59614b24e2bSVaishali Kulkarni 	/* On CMT, always tell that it's engine */
59714b24e2bSVaishali Kulkarni 	if (p_hwfn->p_dev->num_hwfns > 1)
59814b24e2bSVaishali Kulkarni 		load_phase = FW_MSG_CODE_DRV_LOAD_ENGINE;
59914b24e2bSVaishali Kulkarni 
60014b24e2bSVaishali Kulkarni 	*p_load_code = load_phase;
60114b24e2bSVaishali Kulkarni 	loaded++;
60214b24e2bSVaishali Kulkarni 	loaded_port[p_hwfn->port_id]++;
60314b24e2bSVaishali Kulkarni 
60414b24e2bSVaishali Kulkarni 	DP_VERBOSE(p_hwfn, ECORE_MSG_SP,
60514b24e2bSVaishali Kulkarni 		   "Load phase: %x load cnt: 0x%x port id=%d port_load=%d\n",
60614b24e2bSVaishali Kulkarni 		   *p_load_code, loaded, p_hwfn->port_id,
60714b24e2bSVaishali Kulkarni 		   loaded_port[p_hwfn->port_id]);
60814b24e2bSVaishali Kulkarni }
60914b24e2bSVaishali Kulkarni #endif
61014b24e2bSVaishali Kulkarni 
61114b24e2bSVaishali Kulkarni static bool
ecore_mcp_can_force_load(u8 drv_role,u8 exist_drv_role,enum ecore_override_force_load override_force_load)61214b24e2bSVaishali Kulkarni ecore_mcp_can_force_load(u8 drv_role, u8 exist_drv_role,
61314b24e2bSVaishali Kulkarni 			 enum ecore_override_force_load override_force_load)
61414b24e2bSVaishali Kulkarni {
61514b24e2bSVaishali Kulkarni 	bool can_force_load = false;
61614b24e2bSVaishali Kulkarni 
61714b24e2bSVaishali Kulkarni 	switch (override_force_load) {
61814b24e2bSVaishali Kulkarni 	case ECORE_OVERRIDE_FORCE_LOAD_ALWAYS:
61914b24e2bSVaishali Kulkarni 		can_force_load = true;
62014b24e2bSVaishali Kulkarni 		break;
62114b24e2bSVaishali Kulkarni 	case ECORE_OVERRIDE_FORCE_LOAD_NEVER:
62214b24e2bSVaishali Kulkarni 		can_force_load = false;
62314b24e2bSVaishali Kulkarni 		break;
62414b24e2bSVaishali Kulkarni 	default:
62514b24e2bSVaishali Kulkarni 		can_force_load = (drv_role == DRV_ROLE_OS &&
62614b24e2bSVaishali Kulkarni 				  exist_drv_role == DRV_ROLE_PREBOOT) ||
62714b24e2bSVaishali Kulkarni 				 (drv_role == DRV_ROLE_KDUMP &&
62814b24e2bSVaishali Kulkarni 				  exist_drv_role == DRV_ROLE_OS);
62914b24e2bSVaishali Kulkarni 		break;
63014b24e2bSVaishali Kulkarni 	}
63114b24e2bSVaishali Kulkarni 
63214b24e2bSVaishali Kulkarni 	return can_force_load;
63314b24e2bSVaishali Kulkarni }
63414b24e2bSVaishali Kulkarni 
ecore_mcp_cancel_load_req(struct ecore_hwfn * p_hwfn,struct ecore_ptt * p_ptt)63514b24e2bSVaishali Kulkarni static enum _ecore_status_t ecore_mcp_cancel_load_req(struct ecore_hwfn *p_hwfn,
63614b24e2bSVaishali Kulkarni 						      struct ecore_ptt *p_ptt)
63714b24e2bSVaishali Kulkarni {
63814b24e2bSVaishali Kulkarni 	u32 resp = 0, param = 0;
63914b24e2bSVaishali Kulkarni 	enum _ecore_status_t rc;
64014b24e2bSVaishali Kulkarni 
64114b24e2bSVaishali Kulkarni 	rc = ecore_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_CANCEL_LOAD_REQ, 0,
64214b24e2bSVaishali Kulkarni 			   &resp, &param);
64314b24e2bSVaishali Kulkarni 	if (rc != ECORE_SUCCESS)
64414b24e2bSVaishali Kulkarni 		DP_NOTICE(p_hwfn, false,
64514b24e2bSVaishali Kulkarni 			  "Failed to send cancel load request, rc = %d\n", rc);
64614b24e2bSVaishali Kulkarni 
64714b24e2bSVaishali Kulkarni 	return rc;
64814b24e2bSVaishali Kulkarni }
64914b24e2bSVaishali Kulkarni 
65014b24e2bSVaishali Kulkarni #define CONFIG_ECORE_L2_BITMAP_IDX	(0x1 << 0)
65114b24e2bSVaishali Kulkarni #define CONFIG_ECORE_SRIOV_BITMAP_IDX	(0x1 << 1)
65214b24e2bSVaishali Kulkarni #define CONFIG_ECORE_ROCE_BITMAP_IDX	(0x1 << 2)
65314b24e2bSVaishali Kulkarni #define CONFIG_ECORE_IWARP_BITMAP_IDX	(0x1 << 3)
65414b24e2bSVaishali Kulkarni #define CONFIG_ECORE_FCOE_BITMAP_IDX	(0x1 << 4)
65514b24e2bSVaishali Kulkarni #define CONFIG_ECORE_ISCSI_BITMAP_IDX	(0x1 << 5)
65614b24e2bSVaishali Kulkarni #define CONFIG_ECORE_LL2_BITMAP_IDX	(0x1 << 6)
65714b24e2bSVaishali Kulkarni 
ecore_get_config_bitmap(void)65814b24e2bSVaishali Kulkarni static u32 ecore_get_config_bitmap(void)
65914b24e2bSVaishali Kulkarni {
66014b24e2bSVaishali Kulkarni 	u32 config_bitmap = 0x0;
66114b24e2bSVaishali Kulkarni 
66214b24e2bSVaishali Kulkarni #ifdef CONFIG_ECORE_L2
66314b24e2bSVaishali Kulkarni 	config_bitmap |= CONFIG_ECORE_L2_BITMAP_IDX;
66414b24e2bSVaishali Kulkarni #endif
66514b24e2bSVaishali Kulkarni #ifdef CONFIG_ECORE_SRIOV
66614b24e2bSVaishali Kulkarni 	config_bitmap |= CONFIG_ECORE_SRIOV_BITMAP_IDX;
66714b24e2bSVaishali Kulkarni #endif
66814b24e2bSVaishali Kulkarni #ifdef CONFIG_ECORE_ROCE
66914b24e2bSVaishali Kulkarni 	config_bitmap |= CONFIG_ECORE_ROCE_BITMAP_IDX;
67014b24e2bSVaishali Kulkarni #endif
67114b24e2bSVaishali Kulkarni #ifdef CONFIG_ECORE_IWARP
67214b24e2bSVaishali Kulkarni 	config_bitmap |= CONFIG_ECORE_IWARP_BITMAP_IDX;
67314b24e2bSVaishali Kulkarni #endif
67414b24e2bSVaishali Kulkarni #ifdef CONFIG_ECORE_FCOE
67514b24e2bSVaishali Kulkarni 	config_bitmap |= CONFIG_ECORE_FCOE_BITMAP_IDX;
67614b24e2bSVaishali Kulkarni #endif
67714b24e2bSVaishali Kulkarni #ifdef CONFIG_ECORE_ISCSI
67814b24e2bSVaishali Kulkarni 	config_bitmap |= CONFIG_ECORE_ISCSI_BITMAP_IDX;
67914b24e2bSVaishali Kulkarni #endif
68014b24e2bSVaishali Kulkarni #ifdef CONFIG_ECORE_LL2
68114b24e2bSVaishali Kulkarni 	config_bitmap |= CONFIG_ECORE_LL2_BITMAP_IDX;
68214b24e2bSVaishali Kulkarni #endif
68314b24e2bSVaishali Kulkarni 
68414b24e2bSVaishali Kulkarni 	return config_bitmap;
68514b24e2bSVaishali Kulkarni }
68614b24e2bSVaishali Kulkarni 
68714b24e2bSVaishali Kulkarni struct ecore_load_req_in_params {
68814b24e2bSVaishali Kulkarni 	u8 hsi_ver;
68914b24e2bSVaishali Kulkarni #define ECORE_LOAD_REQ_HSI_VER_DEFAULT	0
69014b24e2bSVaishali Kulkarni #define ECORE_LOAD_REQ_HSI_VER_1	1
69114b24e2bSVaishali Kulkarni 	u32 drv_ver_0;
69214b24e2bSVaishali Kulkarni 	u32 drv_ver_1;
69314b24e2bSVaishali Kulkarni 	u32 fw_ver;
69414b24e2bSVaishali Kulkarni 	u8 drv_role;
69514b24e2bSVaishali Kulkarni 	u8 timeout_val;
69614b24e2bSVaishali Kulkarni 	u8 force_cmd;
69714b24e2bSVaishali Kulkarni 	bool avoid_eng_reset;
69814b24e2bSVaishali Kulkarni };
69914b24e2bSVaishali Kulkarni 
70014b24e2bSVaishali Kulkarni struct ecore_load_req_out_params {
70114b24e2bSVaishali Kulkarni 	u32 load_code;
70214b24e2bSVaishali Kulkarni 	u32 exist_drv_ver_0;
70314b24e2bSVaishali Kulkarni 	u32 exist_drv_ver_1;
70414b24e2bSVaishali Kulkarni 	u32 exist_fw_ver;
70514b24e2bSVaishali Kulkarni 	u8 exist_drv_role;
70614b24e2bSVaishali Kulkarni 	u8 mfw_hsi_ver;
70714b24e2bSVaishali Kulkarni 	bool drv_exists;
70814b24e2bSVaishali Kulkarni };
70914b24e2bSVaishali Kulkarni 
71014b24e2bSVaishali Kulkarni static enum _ecore_status_t
__ecore_mcp_load_req(struct ecore_hwfn * p_hwfn,struct ecore_ptt * p_ptt,struct ecore_load_req_in_params * p_in_params,struct ecore_load_req_out_params * p_out_params)71114b24e2bSVaishali Kulkarni __ecore_mcp_load_req(struct ecore_hwfn *p_hwfn, struct ecore_ptt *p_ptt,
71214b24e2bSVaishali Kulkarni 		     struct ecore_load_req_in_params *p_in_params,
71314b24e2bSVaishali Kulkarni 		     struct ecore_load_req_out_params *p_out_params)
71414b24e2bSVaishali Kulkarni {
71514b24e2bSVaishali Kulkarni 	struct ecore_mcp_mb_params mb_params;
71614b24e2bSVaishali Kulkarni 	struct load_req_stc load_req;
71714b24e2bSVaishali Kulkarni 	struct load_rsp_stc load_rsp;
71814b24e2bSVaishali Kulkarni 	u32 hsi_ver;
71914b24e2bSVaishali Kulkarni 	enum _ecore_status_t rc;
72014b24e2bSVaishali Kulkarni 
72114b24e2bSVaishali Kulkarni 	OSAL_MEM_ZERO(&load_req, sizeof(load_req));
72214b24e2bSVaishali Kulkarni 	load_req.drv_ver_0 = p_in_params->drv_ver_0;
72314b24e2bSVaishali Kulkarni 	load_req.drv_ver_1 = p_in_params->drv_ver_1;
72414b24e2bSVaishali Kulkarni 	load_req.fw_ver = p_in_params->fw_ver;
72514b24e2bSVaishali Kulkarni 	ECORE_MFW_SET_FIELD(load_req.misc0, LOAD_REQ_ROLE,
72614b24e2bSVaishali Kulkarni 			    p_in_params->drv_role);
72714b24e2bSVaishali Kulkarni 	ECORE_MFW_SET_FIELD(load_req.misc0, LOAD_REQ_LOCK_TO,
72814b24e2bSVaishali Kulkarni 			    p_in_params->timeout_val);
72914b24e2bSVaishali Kulkarni 	ECORE_MFW_SET_FIELD(load_req.misc0, LOAD_REQ_FORCE,
73014b24e2bSVaishali Kulkarni 			    p_in_params->force_cmd);
73114b24e2bSVaishali Kulkarni 	ECORE_MFW_SET_FIELD(load_req.misc0, LOAD_REQ_FLAGS0,
73214b24e2bSVaishali Kulkarni 			    p_in_params->avoid_eng_reset);
73314b24e2bSVaishali Kulkarni 
73414b24e2bSVaishali Kulkarni 	hsi_ver = (p_in_params->hsi_ver == ECORE_LOAD_REQ_HSI_VER_DEFAULT) ?
73514b24e2bSVaishali Kulkarni 		  DRV_ID_MCP_HSI_VER_CURRENT :
73614b24e2bSVaishali Kulkarni 		  (p_in_params->hsi_ver << DRV_ID_MCP_HSI_VER_SHIFT);
73714b24e2bSVaishali Kulkarni 
73814b24e2bSVaishali Kulkarni 	OSAL_MEM_ZERO(&mb_params, sizeof(mb_params));
73914b24e2bSVaishali Kulkarni 	mb_params.cmd = DRV_MSG_CODE_LOAD_REQ;
74014b24e2bSVaishali Kulkarni 	mb_params.param = PDA_COMP | hsi_ver | p_hwfn->p_dev->drv_type;
74114b24e2bSVaishali Kulkarni 	mb_params.p_data_src = &load_req;
74214b24e2bSVaishali Kulkarni 	mb_params.data_src_size = sizeof(load_req);
74314b24e2bSVaishali Kulkarni 	mb_params.p_data_dst = &load_rsp;
74414b24e2bSVaishali Kulkarni 	mb_params.data_dst_size = sizeof(load_rsp);
74514b24e2bSVaishali Kulkarni 
74614b24e2bSVaishali Kulkarni 	DP_VERBOSE(p_hwfn, ECORE_MSG_SP,
74714b24e2bSVaishali Kulkarni 		   "Load Request: param 0x%08x [init_hw %d, drv_type %d, hsi_ver %d, pda 0x%04x]\n",
74814b24e2bSVaishali Kulkarni 		   mb_params.param,
74914b24e2bSVaishali Kulkarni 		   ECORE_MFW_GET_FIELD(mb_params.param, DRV_ID_DRV_INIT_HW),
75014b24e2bSVaishali Kulkarni 		   ECORE_MFW_GET_FIELD(mb_params.param, DRV_ID_DRV_TYPE),
75114b24e2bSVaishali Kulkarni 		   ECORE_MFW_GET_FIELD(mb_params.param, DRV_ID_MCP_HSI_VER),
75214b24e2bSVaishali Kulkarni 		   ECORE_MFW_GET_FIELD(mb_params.param, DRV_ID_PDA_COMP_VER));
75314b24e2bSVaishali Kulkarni 
75414b24e2bSVaishali Kulkarni 	if (p_in_params->hsi_ver != ECORE_LOAD_REQ_HSI_VER_1)
75514b24e2bSVaishali Kulkarni 		DP_VERBOSE(p_hwfn, ECORE_MSG_SP,
75614b24e2bSVaishali Kulkarni 			   "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",
75714b24e2bSVaishali Kulkarni 			   load_req.drv_ver_0, load_req.drv_ver_1,
75814b24e2bSVaishali Kulkarni 			   load_req.fw_ver, load_req.misc0,
75914b24e2bSVaishali Kulkarni 			   ECORE_MFW_GET_FIELD(load_req.misc0, LOAD_REQ_ROLE),
76014b24e2bSVaishali Kulkarni 			   ECORE_MFW_GET_FIELD(load_req.misc0,
76114b24e2bSVaishali Kulkarni 					       LOAD_REQ_LOCK_TO),
76214b24e2bSVaishali Kulkarni 			   ECORE_MFW_GET_FIELD(load_req.misc0, LOAD_REQ_FORCE),
763