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 
3614b24e2bSVaishali Kulkarni #include "bcm_osal.h"
3714b24e2bSVaishali Kulkarni #include "reg_addr.h"
3814b24e2bSVaishali Kulkarni #include "ecore_gtt_reg_addr.h"
3914b24e2bSVaishali Kulkarni #include "ecore_hsi_common.h"
4014b24e2bSVaishali Kulkarni #include "ecore.h"
4114b24e2bSVaishali Kulkarni #include "ecore_sp_api.h"
4214b24e2bSVaishali Kulkarni #include "ecore_spq.h"
4314b24e2bSVaishali Kulkarni #include "ecore_iro.h"
4414b24e2bSVaishali Kulkarni #include "ecore_init_fw_funcs.h"
4514b24e2bSVaishali Kulkarni #include "ecore_cxt.h"
4614b24e2bSVaishali Kulkarni #include "ecore_int.h"
4714b24e2bSVaishali Kulkarni #include "ecore_dev_api.h"
4814b24e2bSVaishali Kulkarni #include "ecore_mcp.h"
4914b24e2bSVaishali Kulkarni #ifdef CONFIG_ECORE_ROCE
5014b24e2bSVaishali Kulkarni #include "ecore_roce.h"
5114b24e2bSVaishali Kulkarni #endif
5214b24e2bSVaishali Kulkarni #include "ecore_hw.h"
5314b24e2bSVaishali Kulkarni #include "ecore_sriov.h"
5414b24e2bSVaishali Kulkarni #ifdef CONFIG_ECORE_ISCSI
5514b24e2bSVaishali Kulkarni #include "ecore_iscsi.h"
5614b24e2bSVaishali Kulkarni #include "ecore_ooo.h"
5714b24e2bSVaishali Kulkarni #endif
5814b24e2bSVaishali Kulkarni 
5914b24e2bSVaishali Kulkarni /***************************************************************************
6014b24e2bSVaishali Kulkarni  * Structures & Definitions
6114b24e2bSVaishali Kulkarni  ***************************************************************************/
6214b24e2bSVaishali Kulkarni 
6314b24e2bSVaishali Kulkarni #define SPQ_HIGH_PRI_RESERVE_DEFAULT	(1)
6414b24e2bSVaishali Kulkarni 
6514b24e2bSVaishali Kulkarni #define SPQ_BLOCK_DELAY_MAX_ITER	(10)
6614b24e2bSVaishali Kulkarni #define SPQ_BLOCK_DELAY_US		(10)
6714b24e2bSVaishali Kulkarni #define SPQ_BLOCK_SLEEP_MAX_ITER	(1000)
6814b24e2bSVaishali Kulkarni #define SPQ_BLOCK_SLEEP_MS		(5)
6914b24e2bSVaishali Kulkarni 
7014b24e2bSVaishali Kulkarni #ifndef REMOVE_DBG
7114b24e2bSVaishali Kulkarni /***************************************************************************
7214b24e2bSVaishali Kulkarni  * Debug [iSCSI] tool
7314b24e2bSVaishali Kulkarni  ***************************************************************************/
ecore_iscsi_eq_dump(struct ecore_hwfn * p_hwfn,struct event_ring_entry * p_eqe)7414b24e2bSVaishali Kulkarni static void ecore_iscsi_eq_dump(struct ecore_hwfn *p_hwfn,
7514b24e2bSVaishali Kulkarni 				struct event_ring_entry *p_eqe)
7614b24e2bSVaishali Kulkarni {
7714b24e2bSVaishali Kulkarni 	if (p_eqe->opcode >= MAX_ISCSI_EQE_OPCODE) {
7814b24e2bSVaishali Kulkarni 		DP_NOTICE(p_hwfn, false, "Unknown iSCSI EQ: %x\n",
7914b24e2bSVaishali Kulkarni 			  p_eqe->opcode);
8014b24e2bSVaishali Kulkarni 	}
8114b24e2bSVaishali Kulkarni 
8214b24e2bSVaishali Kulkarni 	switch (p_eqe->opcode) {
8314b24e2bSVaishali Kulkarni 	case ISCSI_EVENT_TYPE_INIT_FUNC:
8414b24e2bSVaishali Kulkarni 	case ISCSI_EVENT_TYPE_DESTROY_FUNC:
8514b24e2bSVaishali Kulkarni 		/* NOPE */
8614b24e2bSVaishali Kulkarni 		break;
8714b24e2bSVaishali Kulkarni 	case ISCSI_EVENT_TYPE_OFFLOAD_CONN:
8814b24e2bSVaishali Kulkarni 	case ISCSI_EVENT_TYPE_TERMINATE_CONN:
8914b24e2bSVaishali Kulkarni 		DP_VERBOSE(p_hwfn, ECORE_MSG_STORAGE,
9014b24e2bSVaishali Kulkarni 			   "iSCSI EQE: Port %x, Op %x, echo %x, FWret %x, CID %x, ConnID %x, ERR %x\n",
9114b24e2bSVaishali Kulkarni 			   p_hwfn->port_id, p_eqe->opcode,
9214b24e2bSVaishali Kulkarni 			   OSAL_LE16_TO_CPU(p_eqe->echo),
9314b24e2bSVaishali Kulkarni 			   p_eqe->fw_return_code,
9414b24e2bSVaishali Kulkarni 			   OSAL_LE32_TO_CPU(p_eqe->data.iscsi_info.cid),
9514b24e2bSVaishali Kulkarni 			   OSAL_LE16_TO_CPU(p_eqe->data.iscsi_info.conn_id),
9614b24e2bSVaishali Kulkarni 			   p_eqe->data.iscsi_info.error_code);
9714b24e2bSVaishali Kulkarni 		break;
9814b24e2bSVaishali Kulkarni 	case ISCSI_EVENT_TYPE_UPDATE_CONN:
9914b24e2bSVaishali Kulkarni 	case ISCSI_EVENT_TYPE_CLEAR_SQ:
10014b24e2bSVaishali Kulkarni 	case ISCSI_EVENT_TYPE_ASYN_CONNECT_COMPLETE:
10114b24e2bSVaishali Kulkarni 	case ISCSI_EVENT_TYPE_ASYN_TERMINATE_DONE:
10214b24e2bSVaishali Kulkarni 	case ISCSI_EVENT_TYPE_ASYN_ABORT_RCVD:
10314b24e2bSVaishali Kulkarni 	case ISCSI_EVENT_TYPE_ASYN_CLOSE_RCVD:
10414b24e2bSVaishali Kulkarni 	case ISCSI_EVENT_TYPE_ASYN_SYN_RCVD:
10514b24e2bSVaishali Kulkarni 	case ISCSI_EVENT_TYPE_ASYN_MAX_RT_TIME:
10614b24e2bSVaishali Kulkarni 	case ISCSI_EVENT_TYPE_ASYN_MAX_RT_CNT:
10714b24e2bSVaishali Kulkarni 	case ISCSI_EVENT_TYPE_ASYN_MAX_KA_PROBES_CNT:
10814b24e2bSVaishali Kulkarni 	case ISCSI_EVENT_TYPE_ASYN_FIN_WAIT2:
10914b24e2bSVaishali Kulkarni 	case ISCSI_EVENT_TYPE_ISCSI_CONN_ERROR:
11014b24e2bSVaishali Kulkarni 	case ISCSI_EVENT_TYPE_TCP_CONN_ERROR:
11114b24e2bSVaishali Kulkarni 	default:
11214b24e2bSVaishali Kulkarni 		/* NOPE */
11314b24e2bSVaishali Kulkarni 		break;
11414b24e2bSVaishali Kulkarni 	}
11514b24e2bSVaishali Kulkarni }
11614b24e2bSVaishali Kulkarni #endif
11714b24e2bSVaishali Kulkarni 
11814b24e2bSVaishali Kulkarni /***************************************************************************
11914b24e2bSVaishali Kulkarni  * Blocking Imp. (BLOCK/EBLOCK mode)
12014b24e2bSVaishali Kulkarni  ***************************************************************************/
ecore_spq_blocking_cb(struct ecore_hwfn * p_hwfn,void * cookie,union event_ring_data * data,u8 fw_return_code)12114b24e2bSVaishali Kulkarni static void ecore_spq_blocking_cb(struct ecore_hwfn *p_hwfn,
12214b24e2bSVaishali Kulkarni 					void                  *cookie,
12314b24e2bSVaishali Kulkarni 					union event_ring_data *data,
12414b24e2bSVaishali Kulkarni 					u8                    fw_return_code)
12514b24e2bSVaishali Kulkarni {
12614b24e2bSVaishali Kulkarni 	struct ecore_spq_comp_done *comp_done;
12714b24e2bSVaishali Kulkarni 
12814b24e2bSVaishali Kulkarni 	comp_done = (struct ecore_spq_comp_done *)cookie;
12914b24e2bSVaishali Kulkarni 
13014b24e2bSVaishali Kulkarni 	comp_done->done = 0x1;
13114b24e2bSVaishali Kulkarni 	comp_done->fw_return_code = fw_return_code;
13214b24e2bSVaishali Kulkarni 
13314b24e2bSVaishali Kulkarni 	/* make update visible to waiting thread */
13414b24e2bSVaishali Kulkarni 	OSAL_SMP_WMB(p_hwfn->p_dev);
13514b24e2bSVaishali Kulkarni }
13614b24e2bSVaishali Kulkarni 
__ecore_spq_block(struct ecore_hwfn * p_hwfn,struct ecore_spq_entry * p_ent,u8 * p_fw_ret,bool sleep_between_iter)13714b24e2bSVaishali Kulkarni static enum _ecore_status_t __ecore_spq_block(struct ecore_hwfn *p_hwfn,
13814b24e2bSVaishali Kulkarni 					      struct ecore_spq_entry *p_ent,
13914b24e2bSVaishali Kulkarni 					      u8 *p_fw_ret,
14014b24e2bSVaishali Kulkarni 					      bool sleep_between_iter)
14114b24e2bSVaishali Kulkarni {
14214b24e2bSVaishali Kulkarni 	struct ecore_spq_comp_done *comp_done;
14314b24e2bSVaishali Kulkarni 	u32 iter_cnt;
14414b24e2bSVaishali Kulkarni 
14514b24e2bSVaishali Kulkarni 	comp_done = (struct ecore_spq_comp_done *)p_ent->comp_cb.cookie;
14614b24e2bSVaishali Kulkarni 	iter_cnt = sleep_between_iter ? SPQ_BLOCK_SLEEP_MAX_ITER
14714b24e2bSVaishali Kulkarni 				      : SPQ_BLOCK_DELAY_MAX_ITER;
14814b24e2bSVaishali Kulkarni 
14914b24e2bSVaishali Kulkarni 	while (iter_cnt--) {
15014b24e2bSVaishali Kulkarni 		OSAL_POLL_MODE_DPC(p_hwfn);
15114b24e2bSVaishali Kulkarni 		OSAL_SMP_RMB(p_hwfn->p_dev);
15214b24e2bSVaishali Kulkarni 		if (comp_done->done == 1) {
15314b24e2bSVaishali Kulkarni 			if (p_fw_ret)
15414b24e2bSVaishali Kulkarni 				*p_fw_ret = comp_done->fw_return_code;
15514b24e2bSVaishali Kulkarni 			return ECORE_SUCCESS;
15614b24e2bSVaishali Kulkarni 		}
15714b24e2bSVaishali Kulkarni 
15814b24e2bSVaishali Kulkarni 		if (sleep_between_iter)
15914b24e2bSVaishali Kulkarni 			OSAL_MSLEEP(SPQ_BLOCK_SLEEP_MS);
16014b24e2bSVaishali Kulkarni 		else
16114b24e2bSVaishali Kulkarni 			OSAL_UDELAY(SPQ_BLOCK_DELAY_US);
16214b24e2bSVaishali Kulkarni 	}
16314b24e2bSVaishali Kulkarni 
16414b24e2bSVaishali Kulkarni 	return ECORE_TIMEOUT;
16514b24e2bSVaishali Kulkarni }
16614b24e2bSVaishali Kulkarni 
ecore_spq_block(struct ecore_hwfn * p_hwfn,struct ecore_spq_entry * p_ent,u8 * p_fw_ret,bool skip_quick_poll)16714b24e2bSVaishali Kulkarni static enum _ecore_status_t ecore_spq_block(struct ecore_hwfn *p_hwfn,
16814b24e2bSVaishali Kulkarni 					    struct ecore_spq_entry *p_ent,
16914b24e2bSVaishali Kulkarni 					    u8 *p_fw_ret, bool skip_quick_poll)
17014b24e2bSVaishali Kulkarni {
17114b24e2bSVaishali Kulkarni 	struct ecore_spq_comp_done *comp_done;
17214b24e2bSVaishali Kulkarni 	enum _ecore_status_t rc;
17314b24e2bSVaishali Kulkarni 
17414b24e2bSVaishali Kulkarni 	/* A relatively short polling period w/o sleeping, to allow the FW to
17514b24e2bSVaishali Kulkarni 	 * complete the ramrod and thus possibly to avoid the following sleeps.
17614b24e2bSVaishali Kulkarni 	 */
17714b24e2bSVaishali Kulkarni 	if (!skip_quick_poll) {
17814b24e2bSVaishali Kulkarni 		rc = __ecore_spq_block(p_hwfn, p_ent, p_fw_ret, false);
17914b24e2bSVaishali Kulkarni 		if (rc == ECORE_SUCCESS)
18014b24e2bSVaishali Kulkarni 			return ECORE_SUCCESS;
18114b24e2bSVaishali Kulkarni 	}
18214b24e2bSVaishali Kulkarni 
18314b24e2bSVaishali Kulkarni 	/* Move to polling with a sleeping period between iterations */
18414b24e2bSVaishali Kulkarni 	rc = __ecore_spq_block(p_hwfn, p_ent, p_fw_ret, true);
18514b24e2bSVaishali Kulkarni 	if (rc == ECORE_SUCCESS)
18614b24e2bSVaishali Kulkarni 		return ECORE_SUCCESS;
18714b24e2bSVaishali Kulkarni 
18814b24e2bSVaishali Kulkarni 	DP_INFO(p_hwfn, "Ramrod is stuck, requesting MCP drain\n");
18914b24e2bSVaishali Kulkarni 	rc = ecore_mcp_drain(p_hwfn, p_hwfn->p_main_ptt);
19014b24e2bSVaishali Kulkarni 	if (rc != ECORE_SUCCESS) {
19114b24e2bSVaishali Kulkarni 		DP_NOTICE(p_hwfn, true, "MCP drain failed\n");
19214b24e2bSVaishali Kulkarni 		goto err;
19314b24e2bSVaishali Kulkarni 	}
19414b24e2bSVaishali Kulkarni 
19514b24e2bSVaishali Kulkarni 	/* Retry after drain */
19614b24e2bSVaishali Kulkarni 	rc = __ecore_spq_block(p_hwfn, p_ent, p_fw_ret, true);
19714b24e2bSVaishali Kulkarni 	if (rc == ECORE_SUCCESS)
19814b24e2bSVaishali Kulkarni 		return ECORE_SUCCESS;
19914b24e2bSVaishali Kulkarni 
20014b24e2bSVaishali Kulkarni 	comp_done = (struct ecore_spq_comp_done *)p_ent->comp_cb.cookie;
20114b24e2bSVaishali Kulkarni 	if (comp_done->done == 1) {
20214b24e2bSVaishali Kulkarni 		if (p_fw_ret)
20314b24e2bSVaishali Kulkarni 			*p_fw_ret = comp_done->fw_return_code;
20414b24e2bSVaishali Kulkarni 		return ECORE_SUCCESS;
20514b24e2bSVaishali Kulkarni 	}
20614b24e2bSVaishali Kulkarni err:
20714b24e2bSVaishali Kulkarni 	DP_NOTICE(p_hwfn, true,
20814b24e2bSVaishali Kulkarni 		  "Ramrod is stuck [CID %08x cmd %02x protocol %02x echo %04x]\n",
20914b24e2bSVaishali Kulkarni 		  OSAL_LE32_TO_CPU(p_ent->elem.hdr.cid),
21014b24e2bSVaishali Kulkarni 		  p_ent->elem.hdr.cmd_id, p_ent->elem.hdr.protocol_id,
21114b24e2bSVaishali Kulkarni 		  OSAL_LE16_TO_CPU(p_ent->elem.hdr.echo));
21214b24e2bSVaishali Kulkarni 
21314b24e2bSVaishali Kulkarni 	ecore_hw_err_notify(p_hwfn, ECORE_HW_ERR_RAMROD_FAIL);
21414b24e2bSVaishali Kulkarni 
21514b24e2bSVaishali Kulkarni 	return ECORE_BUSY;
21614b24e2bSVaishali Kulkarni }
21714b24e2bSVaishali Kulkarni 
21814b24e2bSVaishali Kulkarni /***************************************************************************
21914b24e2bSVaishali Kulkarni  * SPQ entries inner API
22014b24e2bSVaishali Kulkarni  ***************************************************************************/
ecore_spq_fill_entry(struct ecore_hwfn * p_hwfn,struct ecore_spq_entry * p_ent)22114b24e2bSVaishali Kulkarni static enum _ecore_status_t ecore_spq_fill_entry(struct ecore_hwfn *p_hwfn,
22214b24e2bSVaishali Kulkarni 						 struct ecore_spq_entry *p_ent)
22314b24e2bSVaishali Kulkarni {
22414b24e2bSVaishali Kulkarni 	p_ent->flags = 0;
22514b24e2bSVaishali Kulkarni 
22614b24e2bSVaishali Kulkarni 	switch (p_ent->comp_mode) {
22714b24e2bSVaishali Kulkarni 	case ECORE_SPQ_MODE_EBLOCK:
22814b24e2bSVaishali Kulkarni 	case ECORE_SPQ_MODE_BLOCK:
22914b24e2bSVaishali Kulkarni 		p_ent->comp_cb.function = ecore_spq_blocking_cb;
23014b24e2bSVaishali Kulkarni 		break;
23114b24e2bSVaishali Kulkarni 	case ECORE_SPQ_MODE_CB:
23214b24e2bSVaishali Kulkarni 		break;
23314b24e2bSVaishali Kulkarni 	default:
23414b24e2bSVaishali Kulkarni 		DP_NOTICE(p_hwfn, true, "Unknown SPQE completion mode %d\n",
23514b24e2bSVaishali Kulkarni 			  p_ent->comp_mode);
23614b24e2bSVaishali Kulkarni 		return ECORE_INVAL;
23714b24e2bSVaishali Kulkarni 	}
23814b24e2bSVaishali Kulkarni 
23914b24e2bSVaishali Kulkarni 	DP_VERBOSE(p_hwfn, ECORE_MSG_SPQ,
24014b24e2bSVaishali Kulkarni 		   "Ramrod header: [CID 0x%08x CMD 0x%02x protocol 0x%02x] Data pointer: [%08x:%08x] Completion Mode: %s\n",
24114b24e2bSVaishali Kulkarni 		   p_ent->elem.hdr.cid, p_ent->elem.hdr.cmd_id,
24214b24e2bSVaishali Kulkarni 		   p_ent->elem.hdr.protocol_id,
24314b24e2bSVaishali Kulkarni 		   p_ent->elem.data_ptr.hi, p_ent->elem.data_ptr.lo,
24414b24e2bSVaishali Kulkarni 		   D_TRINE(p_ent->comp_mode, ECORE_SPQ_MODE_EBLOCK,
24514b24e2bSVaishali Kulkarni 			   ECORE_SPQ_MODE_BLOCK, "MODE_EBLOCK", "MODE_BLOCK",
24614b24e2bSVaishali Kulkarni 			   "MODE_CB"));
24714b24e2bSVaishali Kulkarni 
24814b24e2bSVaishali Kulkarni 	return ECORE_SUCCESS;
24914b24e2bSVaishali Kulkarni }
25014b24e2bSVaishali Kulkarni 
25114b24e2bSVaishali Kulkarni /***************************************************************************
25214b24e2bSVaishali Kulkarni  * HSI access
25314b24e2bSVaishali Kulkarni  ***************************************************************************/
ecore_spq_hw_initialize(struct ecore_hwfn * p_hwfn,struct ecore_spq * p_spq)25414b24e2bSVaishali Kulkarni static void ecore_spq_hw_initialize(struct ecore_hwfn *p_hwfn,
25514b24e2bSVaishali Kulkarni 				    struct ecore_spq  *p_spq)
25614b24e2bSVaishali Kulkarni {
25714b24e2bSVaishali Kulkarni 	struct ecore_cxt_info cxt_info;
25814b24e2bSVaishali Kulkarni 	struct core_conn_context *p_cxt;
25914b24e2bSVaishali Kulkarni 	enum _ecore_status_t rc;
26014b24e2bSVaishali Kulkarni 	u16 physical_q;
26114b24e2bSVaishali Kulkarni 
26214b24e2bSVaishali Kulkarni 	cxt_info.iid = p_spq->cid;
26314b24e2bSVaishali Kulkarni 
26414b24e2bSVaishali Kulkarni 	rc = ecore_cxt_get_cid_info(p_hwfn, &cxt_info);
26514b24e2bSVaishali Kulkarni 
26614b24e2bSVaishali Kulkarni 	if (rc < 0) {
26714b24e2bSVaishali Kulkarni 		DP_NOTICE(p_hwfn, true, "Cannot find context info for cid=%d\n",
26814b24e2bSVaishali Kulkarni 			  p_spq->cid);
26914b24e2bSVaishali Kulkarni 		return;
27014b24e2bSVaishali Kulkarni 	}
27114b24e2bSVaishali Kulkarni 
27214b24e2bSVaishali Kulkarni 	p_cxt = cxt_info.p_cxt;
27314b24e2bSVaishali Kulkarni 
27414b24e2bSVaishali Kulkarni 	/* @@@TBD we zero the context until we have ilt_reset implemented. */
27514b24e2bSVaishali Kulkarni 	OSAL_MEM_ZERO(p_cxt, sizeof(*p_cxt));
27614b24e2bSVaishali Kulkarni 
27714b24e2bSVaishali Kulkarni 	if (ECORE_IS_BB(p_hwfn->p_dev) || ECORE_IS_AH(p_hwfn->p_dev)) {
27814b24e2bSVaishali Kulkarni 		SET_FIELD(p_cxt->xstorm_ag_context.flags10,
27914b24e2bSVaishali Kulkarni 			  E4_XSTORM_CORE_CONN_AG_CTX_DQ_CF_EN, 1);
28014b24e2bSVaishali Kulkarni 		SET_FIELD(p_cxt->xstorm_ag_context.flags1,
28114b24e2bSVaishali Kulkarni 			  E4_XSTORM_CORE_CONN_AG_CTX_DQ_CF_ACTIVE, 1);
28214b24e2bSVaishali Kulkarni 		/*SET_FIELD(p_cxt->xstorm_ag_context.flags10,
28314b24e2bSVaishali Kulkarni 			  E4_XSTORM_CORE_CONN_AG_CTX_SLOW_PATH_EN, 1);*/
28414b24e2bSVaishali Kulkarni 		SET_FIELD(p_cxt->xstorm_ag_context.flags9,
28514b24e2bSVaishali Kulkarni 			  E4_XSTORM_CORE_CONN_AG_CTX_CONSOLID_PROD_CF_EN, 1);
28614b24e2bSVaishali Kulkarni 	} else { /* E5 */
28714b24e2bSVaishali Kulkarni 		ECORE_E5_MISSING_CODE;
28814b24e2bSVaishali Kulkarni 	}
28914b24e2bSVaishali Kulkarni 
29014b24e2bSVaishali Kulkarni 	/* CDU validation - FIXME currently disabled */
29114b24e2bSVaishali Kulkarni 
29214b24e2bSVaishali Kulkarni 	/* QM physical queue */
29314b24e2bSVaishali Kulkarni 	physical_q = ecore_get_cm_pq_idx(p_hwfn, PQ_FLAGS_LB);
29414b24e2bSVaishali Kulkarni 	p_cxt->xstorm_ag_context.physical_q0 = OSAL_CPU_TO_LE16(physical_q);
29514b24e2bSVaishali Kulkarni 
29614b24e2bSVaishali Kulkarni 	p_cxt->xstorm_st_context.spq_base_lo =
29714b24e2bSVaishali Kulkarni 		DMA_LO_LE(p_spq->chain.p_phys_addr);
29814b24e2bSVaishali Kulkarni 	p_cxt->xstorm_st_context.spq_base_hi =
29914b24e2bSVaishali Kulkarni 		DMA_HI_LE(p_spq->chain.p_phys_addr);
30014b24e2bSVaishali Kulkarni 
30114b24e2bSVaishali Kulkarni 	DMA_REGPAIR_LE(p_cxt->xstorm_st_context.consolid_base_addr,
30214b24e2bSVaishali Kulkarni 		       p_hwfn->p_consq->chain.p_phys_addr);
30314b24e2bSVaishali Kulkarni }
30414b24e2bSVaishali Kulkarni 
ecore_spq_hw_post(struct ecore_hwfn * p_hwfn,struct ecore_spq * p_spq,struct ecore_spq_entry * p_ent)30514b24e2bSVaishali Kulkarni static enum _ecore_status_t ecore_spq_hw_post(struct ecore_hwfn		*p_hwfn,
30614b24e2bSVaishali Kulkarni 					      struct ecore_spq		*p_spq,
30714b24e2bSVaishali Kulkarni 					      struct ecore_spq_entry	*p_ent)
30814b24e2bSVaishali Kulkarni {
30914b24e2bSVaishali Kulkarni 	struct ecore_chain *p_chain = &p_hwfn->p_spq->chain;
31014b24e2bSVaishali Kulkarni 	u16 echo = ecore_chain_get_prod_idx(p_chain);
31114b24e2bSVaishali Kulkarni 	struct slow_path_element *elem;
31214b24e2bSVaishali Kulkarni 	struct core_db_data db;
31314b24e2bSVaishali Kulkarni 
31414b24e2bSVaishali Kulkarni 	p_ent->elem.hdr.echo = OSAL_CPU_TO_LE16(echo);
31514b24e2bSVaishali Kulkarni 	elem = ecore_chain_produce(p_chain);
31614b24e2bSVaishali Kulkarni 	if (!elem) {
31714b24e2bSVaishali Kulkarni 		DP_NOTICE(p_hwfn, true, "Failed to produce from SPQ chain\n");
31814b24e2bSVaishali Kulkarni 		return ECORE_INVAL;
31914b24e2bSVaishali Kulkarni 	}
32014b24e2bSVaishali Kulkarni 
32114b24e2bSVaishali Kulkarni 	*elem = p_ent->elem; /* struct assignment */
32214b24e2bSVaishali Kulkarni 
32314b24e2bSVaishali Kulkarni 	/* send a doorbell on the slow hwfn session */
32414b24e2bSVaishali Kulkarni 	OSAL_MEMSET(&db, 0, sizeof(db));
32514b24e2bSVaishali Kulkarni 	SET_FIELD(db.params, CORE_DB_DATA_DEST, DB_DEST_XCM);
32614b24e2bSVaishali Kulkarni 	SET_FIELD(db.params, CORE_DB_DATA_AGG_CMD, DB_AGG_CMD_SET);
32714b24e2bSVaishali Kulkarni 	SET_FIELD(db.params, CORE_DB_DATA_AGG_VAL_SEL, DQ_XCM_CORE_SPQ_PROD_CMD);
32814b24e2bSVaishali Kulkarni 	db.agg_flags = DQ_XCM_CORE_DQ_CF_CMD;
32914b24e2bSVaishali Kulkarni 	db.spq_prod = OSAL_CPU_TO_LE16(ecore_chain_get_prod_idx(p_chain));
33014b24e2bSVaishali Kulkarni 
33114b24e2bSVaishali Kulkarni 	/* make sure the SPQE is updated before the doorbell */
33214b24e2bSVaishali Kulkarni 	OSAL_WMB(p_hwfn->p_dev);
33314b24e2bSVaishali Kulkarni 
33414b24e2bSVaishali Kulkarni 	DOORBELL(p_hwfn, DB_ADDR(p_spq->cid, DQ_DEMS_LEGACY), *(u32 *)&db);
33514b24e2bSVaishali Kulkarni 
33614b24e2bSVaishali Kulkarni 	/* make sure doorbell is rang */
33714b24e2bSVaishali Kulkarni 	OSAL_WMB(p_hwfn->p_dev);
33814b24e2bSVaishali Kulkarni 
33914b24e2bSVaishali Kulkarni 	DP_VERBOSE(p_hwfn, ECORE_MSG_SPQ,
34014b24e2bSVaishali Kulkarni 		   "Doorbelled [0x%08x, CID 0x%08x] with Flags: %02x agg_params: %02x, prod: %04x\n",
34114b24e2bSVaishali Kulkarni 		   DB_ADDR(p_spq->cid, DQ_DEMS_LEGACY), p_spq->cid, db.params,
34214b24e2bSVaishali Kulkarni 		   db.agg_flags, ecore_chain_get_prod_idx(p_chain));
34314b24e2bSVaishali Kulkarni 
34414b24e2bSVaishali Kulkarni 	return ECORE_SUCCESS;
34514b24e2bSVaishali Kulkarni }
34614b24e2bSVaishali Kulkarni 
34714b24e2bSVaishali Kulkarni /***************************************************************************
34814b24e2bSVaishali Kulkarni  * Asynchronous events
34914b24e2bSVaishali Kulkarni  ***************************************************************************/
35014b24e2bSVaishali Kulkarni 
35114b24e2bSVaishali Kulkarni static enum _ecore_status_t
ecore_async_event_completion(struct ecore_hwfn * p_hwfn,struct event_ring_entry * p_eqe)35214b24e2bSVaishali Kulkarni ecore_async_event_completion(struct ecore_hwfn *p_hwfn,
35314b24e2bSVaishali Kulkarni 			     struct event_ring_entry *p_eqe)
35414b24e2bSVaishali Kulkarni {
35514b24e2bSVaishali Kulkarni 	switch (p_eqe->protocol_id) {
35614b24e2bSVaishali Kulkarni #ifdef CONFIG_ECORE_ROCE
35714b24e2bSVaishali Kulkarni 	case PROTOCOLID_ROCE:
35814b24e2bSVaishali Kulkarni 	{
35914b24e2bSVaishali Kulkarni 		ecore_roce_async_event(p_hwfn,
36014b24e2bSVaishali Kulkarni 				       p_eqe->opcode,
36114b24e2bSVaishali Kulkarni 				       &p_eqe->data.rdma_data);
36214b24e2bSVaishali Kulkarni 		return ECORE_SUCCESS;
36314b24e2bSVaishali Kulkarni 	}
36414b24e2bSVaishali Kulkarni #ifdef CONFIG_ECORE_IWARP
36514b24e2bSVaishali Kulkarni 	case PROTOCOLID_IWARP:
36614b24e2bSVaishali Kulkarni 	{
36714b24e2bSVaishali Kulkarni 		ecore_iwarp_async_event(p_hwfn,
36814b24e2bSVaishali Kulkarni 					p_eqe->opcode,
36914b24e2bSVaishali Kulkarni 					&p_eqe->data.rdma_data.async_handle,
37014b24e2bSVaishali Kulkarni 					p_eqe->fw_return_code);
37114b24e2bSVaishali Kulkarni 		return ECORE_SUCCESS;
37214b24e2bSVaishali Kulkarni 	}
37314b24e2bSVaishali Kulkarni #endif
37414b24e2bSVaishali Kulkarni #endif
37514b24e2bSVaishali Kulkarni 	case PROTOCOLID_COMMON:
37614b24e2bSVaishali Kulkarni 		return ecore_sriov_eqe_event(p_hwfn,
37714b24e2bSVaishali Kulkarni 					     p_eqe->opcode,
37814b24e2bSVaishali Kulkarni 					     p_eqe->echo,
37914b24e2bSVaishali Kulkarni 					     &p_eqe->data);
38014b24e2bSVaishali Kulkarni #ifdef CONFIG_ECORE_ISCSI
38114b24e2bSVaishali Kulkarni 	case PROTOCOLID_ISCSI:
38214b24e2bSVaishali Kulkarni 		if (p_hwfn->p_iscsi_info->event_cb != OSAL_NULL) {
38314b24e2bSVaishali Kulkarni 			struct ecore_iscsi_info *p_iscsi = p_hwfn->p_iscsi_info;
38414b24e2bSVaishali Kulkarni 
38514b24e2bSVaishali Kulkarni 			return p_iscsi->event_cb(p_iscsi->event_context,
38614b24e2bSVaishali Kulkarni 						 p_eqe->opcode, &p_eqe->data);
38714b24e2bSVaishali Kulkarni 		} else {
38814b24e2bSVaishali Kulkarni 			DP_NOTICE(p_hwfn,
38914b24e2bSVaishali Kulkarni 				 false, "iSCSI async completion is not set\n");
39014b24e2bSVaishali Kulkarni 			return ECORE_NOTIMPL;
39114b24e2bSVaishali Kulkarni 		}
39214b24e2bSVaishali Kulkarni #endif
39314b24e2bSVaishali Kulkarni 	default:
39414b24e2bSVaishali Kulkarni 		DP_NOTICE(p_hwfn,
39514b24e2bSVaishali Kulkarni 			 true, "Unknown Async completion for protocol: %d\n",
39614b24e2bSVaishali Kulkarni 			 p_eqe->protocol_id);
39714b24e2bSVaishali Kulkarni 		return ECORE_INVAL;
39814b24e2bSVaishali Kulkarni 	}
39914b24e2bSVaishali Kulkarni }
40014b24e2bSVaishali Kulkarni 
40114b24e2bSVaishali Kulkarni /***************************************************************************
40214b24e2bSVaishali Kulkarni  * EQ API
40314b24e2bSVaishali Kulkarni  ***************************************************************************/
ecore_eq_prod_update(struct ecore_hwfn * p_hwfn,u16 prod)40414b24e2bSVaishali Kulkarni void ecore_eq_prod_update(struct ecore_hwfn	*p_hwfn,
40514b24e2bSVaishali Kulkarni 			  u16			prod)
40614b24e2bSVaishali Kulkarni {
40714b24e2bSVaishali Kulkarni 	u32 addr = GTT_BAR0_MAP_REG_USDM_RAM +
40814b24e2bSVaishali Kulkarni 		USTORM_EQE_CONS_OFFSET(p_hwfn->rel_pf_id);
40914b24e2bSVaishali Kulkarni 
41014b24e2bSVaishali Kulkarni 	REG_WR16(p_hwfn, addr, prod);
41114b24e2bSVaishali Kulkarni 
41214b24e2bSVaishali Kulkarni 	/* keep prod updates ordered */
41314b24e2bSVaishali Kulkarni 	OSAL_MMIOWB(p_hwfn->p_dev);
41414b24e2bSVaishali Kulkarni }
41514b24e2bSVaishali Kulkarni 
ecore_eq_completion(struct ecore_hwfn * p_hwfn,void * cookie)41614b24e2bSVaishali Kulkarni enum _ecore_status_t ecore_eq_completion(struct ecore_hwfn	*p_hwfn,
41714b24e2bSVaishali Kulkarni 					 void                   *cookie)
41814b24e2bSVaishali Kulkarni 
41914b24e2bSVaishali Kulkarni {
42014b24e2bSVaishali Kulkarni 	struct ecore_eq    *p_eq    = cookie;
42114b24e2bSVaishali Kulkarni 	struct ecore_chain *p_chain = &p_eq->chain;
42214b24e2bSVaishali Kulkarni 	enum _ecore_status_t rc = 0;
42314b24e2bSVaishali Kulkarni 
42414b24e2bSVaishali Kulkarni 	/* take a snapshot of the FW consumer */
42514b24e2bSVaishali Kulkarni 	u16 fw_cons_idx = OSAL_LE16_TO_CPU(*p_eq->p_fw_cons);
42614b24e2bSVaishali Kulkarni 
42714b24e2bSVaishali Kulkarni 	DP_VERBOSE(p_hwfn, ECORE_MSG_SPQ, "fw_cons_idx %x\n", fw_cons_idx);
42814b24e2bSVaishali Kulkarni 
42914b24e2bSVaishali Kulkarni 	/* Need to guarantee the fw_cons index we use points to a usuable
43014b24e2bSVaishali Kulkarni 	 * element (to comply with our chain), so our macros would comply
43114b24e2bSVaishali Kulkarni 	 */
43214b24e2bSVaishali Kulkarni 	if ((fw_cons_idx & ecore_chain_get_usable_per_page(p_chain)) ==
43314b24e2bSVaishali Kulkarni 	    ecore_chain_get_usable_per_page(p_chain)) {
43414b24e2bSVaishali Kulkarni 		fw_cons_idx += ecore_chain_get_unusable_per_page(p_chain);
43514b24e2bSVaishali Kulkarni 	}
43614b24e2bSVaishali Kulkarni 
43714b24e2bSVaishali Kulkarni 	/* Complete current segment of eq entries */
43814b24e2bSVaishali Kulkarni 	while (fw_cons_idx != ecore_chain_get_cons_idx(p_chain)) {
43914b24e2bSVaishali Kulkarni 		struct event_ring_entry *p_eqe = ecore_chain_consume(p_chain);
44014b24e2bSVaishali Kulkarni 		if (!p_eqe) {
44114b24e2bSVaishali Kulkarni 			rc = ECORE_INVAL;
44214b24e2bSVaishali Kulkarni 			break;
44314b24e2bSVaishali Kulkarni 		}
44414b24e2bSVaishali Kulkarni 
44514b24e2bSVaishali Kulkarni 		DP_VERBOSE(p_hwfn,
44614b24e2bSVaishali Kulkarni 			   ECORE_MSG_SPQ,
44714b24e2bSVaishali Kulkarni 			   "op %x prot %x res0 %x echo %x fwret %x flags %x\n",
44814b24e2bSVaishali Kulkarni 			   p_eqe->opcode,	     /* Event Opcode */
44914b24e2bSVaishali Kulkarni 			   p_eqe->protocol_id,	     /* Event Protocol ID */
45014b24e2bSVaishali Kulkarni 			   p_eqe->reserved0,	     /* Reserved */
45114b24e2bSVaishali Kulkarni 			   OSAL_LE16_TO_CPU(p_eqe->echo),/* Echo value from
45214b24e2bSVaishali Kulkarni 							ramrod data on the host
45314b24e2bSVaishali Kulkarni 						      */
45414b24e2bSVaishali Kulkarni 			   p_eqe->fw_return_code,    /* FW return code for SP
45514b24e2bSVaishali Kulkarni 							ramrods
45614b24e2bSVaishali Kulkarni 						      */
45714b24e2bSVaishali Kulkarni 			   p_eqe->flags);
45814b24e2bSVaishali Kulkarni #ifndef REMOVE_DBG
45914b24e2bSVaishali Kulkarni 		if (p_eqe->protocol_id == PROTOCOLID_ISCSI)
46014b24e2bSVaishali Kulkarni 			ecore_iscsi_eq_dump(p_hwfn, p_eqe);
46114b24e2bSVaishali Kulkarni #endif
46214b24e2bSVaishali Kulkarni 
46314b24e2bSVaishali Kulkarni 		if (GET_FIELD(p_eqe->flags, EVENT_RING_ENTRY_ASYNC)) {
46414b24e2bSVaishali Kulkarni 			if (ecore_async_event_completion(p_hwfn, p_eqe))
46514b24e2bSVaishali Kulkarni 				rc = ECORE_INVAL;
46614b24e2bSVaishali Kulkarni 		} else if (ecore_spq_completion(p_hwfn,
46714b24e2bSVaishali Kulkarni 						p_eqe->echo,
46814b24e2bSVaishali Kulkarni 						p_eqe->fw_return_code,
46914b24e2bSVaishali Kulkarni 						&p_eqe->data)) {
47014b24e2bSVaishali Kulkarni 			rc = ECORE_INVAL;
47114b24e2bSVaishali Kulkarni 		}
47214b24e2bSVaishali Kulkarni 
47314b24e2bSVaishali Kulkarni 		ecore_chain_recycle_consumed(p_chain);
47414b24e2bSVaishali Kulkarni 	}
47514b24e2bSVaishali Kulkarni 
47614b24e2bSVaishali Kulkarni 	ecore_eq_prod_update(p_hwfn, ecore_chain_get_prod_idx(p_chain));
47714b24e2bSVaishali Kulkarni 
47814b24e2bSVaishali Kulkarni 	return rc;
47914b24e2bSVaishali Kulkarni }
48014b24e2bSVaishali Kulkarni 
ecore_eq_alloc(struct ecore_hwfn * p_hwfn,u16 num_elem)48114b24e2bSVaishali Kulkarni enum _ecore_status_t ecore_eq_alloc(struct ecore_hwfn *p_hwfn, u16 num_elem)
48214b24e2bSVaishali Kulkarni {
48314b24e2bSVaishali Kulkarni 	struct ecore_eq	*p_eq;
48414b24e2bSVaishali Kulkarni 
48514b24e2bSVaishali Kulkarni 	/* Allocate EQ struct */
48614b24e2bSVaishali Kulkarni 	p_eq = OSAL_ZALLOC(p_hwfn->p_dev, GFP_KERNEL, sizeof(*p_eq));
48714b24e2bSVaishali Kulkarni 	if (!p_eq) {
48814b24e2bSVaishali Kulkarni 		DP_NOTICE(p_hwfn, true,
48914b24e2bSVaishali Kulkarni 			  "Failed to allocate `struct ecore_eq'\n");
49014b24e2bSVaishali Kulkarni 		return ECORE_NOMEM;
49114b24e2bSVaishali Kulkarni 	}
49214b24e2bSVaishali Kulkarni 
49314b24e2bSVaishali Kulkarni 	/* Allocate and initialize EQ chain*/
49414b24e2bSVaishali Kulkarni 	if (ecore_chain_alloc(p_hwfn->p_dev,
49514b24e2bSVaishali Kulkarni 			      ECORE_CHAIN_USE_TO_PRODUCE,
49614b24e2bSVaishali Kulkarni 			      ECORE_CHAIN_MODE_PBL,
49714b24e2bSVaishali Kulkarni 			      ECORE_CHAIN_CNT_TYPE_U16,
49814b24e2bSVaishali Kulkarni 			      num_elem,
49914b24e2bSVaishali Kulkarni 			      sizeof(union event_ring_element),
50014b24e2bSVaishali Kulkarni 			      &p_eq->chain, OSAL_NULL) != ECORE_SUCCESS) {
50114b24e2bSVaishali Kulkarni 		DP_NOTICE(p_hwfn, true, "Failed to allocate eq chain\n");
50214b24e2bSVaishali Kulkarni 		goto eq_allocate_fail;
50314b24e2bSVaishali Kulkarni 	}
50414b24e2bSVaishali Kulkarni 
50514b24e2bSVaishali Kulkarni 	/* register EQ completion on the SP SB */
50614b24e2bSVaishali Kulkarni 	ecore_int_register_cb(p_hwfn, ecore_eq_completion,
50714b24e2bSVaishali Kulkarni 			      p_eq, &p_eq->eq_sb_index, &p_eq->p_fw_cons);
50814b24e2bSVaishali Kulkarni 
50914b24e2bSVaishali Kulkarni 	p_hwfn->p_eq = p_eq;
51014b24e2bSVaishali Kulkarni 	return ECORE_SUCCESS;
51114b24e2bSVaishali Kulkarni 
51214b24e2bSVaishali Kulkarni eq_allocate_fail:
51314b24e2bSVaishali Kulkarni 	OSAL_FREE(p_hwfn->p_dev, p_eq);
51414b24e2bSVaishali Kulkarni 	return ECORE_NOMEM;
51514b24e2bSVaishali Kulkarni }
51614b24e2bSVaishali Kulkarni 
ecore_eq_setup(struct ecore_hwfn * p_hwfn)51714b24e2bSVaishali Kulkarni void ecore_eq_setup(struct ecore_hwfn *p_hwfn)
51814b24e2bSVaishali Kulkarni {
51914b24e2bSVaishali Kulkarni 	ecore_chain_reset(&p_hwfn->p_eq->chain);
52014b24e2bSVaishali Kulkarni }
52114b24e2bSVaishali Kulkarni 
ecore_eq_free(struct ecore_hwfn * p_hwfn)52214b24e2bSVaishali Kulkarni void ecore_eq_free(struct ecore_hwfn *p_hwfn)
52314b24e2bSVaishali Kulkarni {
52414b24e2bSVaishali Kulkarni 	if (!p_hwfn->p_eq)
52514b24e2bSVaishali Kulkarni 		return;
52614b24e2bSVaishali Kulkarni 
52714b24e2bSVaishali Kulkarni 	ecore_chain_free(p_hwfn->p_dev, &p_hwfn->p_eq->chain);
52814b24e2bSVaishali Kulkarni 
52914b24e2bSVaishali Kulkarni 	OSAL_FREE(p_hwfn->p_dev, p_hwfn->p_eq);
53014b24e2bSVaishali Kulkarni 	p_hwfn->p_eq = OSAL_NULL;
53114b24e2bSVaishali Kulkarni }
53214b24e2bSVaishali Kulkarni 
53314b24e2bSVaishali Kulkarni /***************************************************************************
53414b24e2bSVaishali Kulkarni * CQE API - manipulate EQ functionallity
53514b24e2bSVaishali Kulkarni ***************************************************************************/
ecore_cqe_completion(struct ecore_hwfn * p_hwfn,struct eth_slow_path_rx_cqe * cqe,enum protocol_type protocol)53614b24e2bSVaishali Kulkarni static enum _ecore_status_t ecore_cqe_completion(struct ecore_hwfn *p_hwfn,
53714b24e2bSVaishali Kulkarni 						 struct eth_slow_path_rx_cqe *cqe,
53814b24e2bSVaishali Kulkarni 						 enum protocol_type protocol)
53914b24e2bSVaishali Kulkarni {
54014b24e2bSVaishali Kulkarni 	if (IS_VF(p_hwfn->p_dev))
54114b24e2bSVaishali Kulkarni 		return OSAL_VF_CQE_COMPLETION(p_hwfn, cqe, protocol);
54214b24e2bSVaishali Kulkarni 
54314b24e2bSVaishali Kulkarni 	/* @@@tmp - it's possible we'll eventually want to handle some
54414b24e2bSVaishali Kulkarni 	 * actual commands that can arrive here, but for now this is only
54514b24e2bSVaishali Kulkarni 	 * used to complete the ramrod using the echo value on the cqe
54614b24e2bSVaishali Kulkarni 	 */
54714b24e2bSVaishali Kulkarni 	return ecore_spq_completion(p_hwfn, cqe->echo, 0, OSAL_NULL);
54814b24e2bSVaishali Kulkarni }
54914b24e2bSVaishali Kulkarni 
ecore_eth_cqe_completion(struct ecore_hwfn * p_hwfn,struct eth_slow_path_rx_cqe * cqe)55014b24e2bSVaishali Kulkarni enum _ecore_status_t ecore_eth_cqe_completion(struct ecore_hwfn *p_hwfn,
55114b24e2bSVaishali Kulkarni 					      struct eth_slow_path_rx_cqe *cqe)
55214b24e2bSVaishali Kulkarni {
55314b24e2bSVaishali Kulkarni 	enum _ecore_status_t rc;
55414b24e2bSVaishali Kulkarni 
55514b24e2bSVaishali Kulkarni 	rc = ecore_cqe_completion(p_hwfn, cqe, PROTOCOLID_ETH);
55614b24e2bSVaishali Kulkarni 	if (rc) {
55714b24e2bSVaishali Kulkarni 		DP_NOTICE(p_hwfn, true,
55814b24e2bSVaishali Kulkarni 			  "Failed to handle RXQ CQE [cmd 0x%02x]\n",
55914b24e2bSVaishali Kulkarni 			  cqe->ramrod_cmd_id);
56014b24e2bSVaishali Kulkarni 	}
56114b24e2bSVaishali Kulkarni 
56214b24e2bSVaishali Kulkarni 	return rc;
56314b24e2bSVaishali Kulkarni }
56414b24e2bSVaishali Kulkarni 
56514b24e2bSVaishali Kulkarni /***************************************************************************
56614b24e2bSVaishali Kulkarni  * Slow hwfn Queue (spq)
56714b24e2bSVaishali Kulkarni  ***************************************************************************/
ecore_spq_setup(struct ecore_hwfn * p_hwfn)56814b24e2bSVaishali Kulkarni void ecore_spq_setup(struct ecore_hwfn *p_hwfn)
56914b24e2bSVaishali Kulkarni {
57014b24e2bSVaishali Kulkarni 	struct ecore_spq *p_spq = p_hwfn->p_spq;
57114b24e2bSVaishali Kulkarni 	struct ecore_spq_entry *p_virt = OSAL_NULL;
57214b24e2bSVaishali Kulkarni 	dma_addr_t p_phys = 0;
57314b24e2bSVaishali Kulkarni 	u32 i, capacity;
57414b24e2bSVaishali Kulkarni 
57514b24e2bSVaishali Kulkarni 	OSAL_LIST_INIT(&p_spq->pending);
57614b24e2bSVaishali Kulkarni 	OSAL_LIST_INIT(&p_spq->completion_pending);
57714b24e2bSVaishali Kulkarni 	OSAL_LIST_INIT(&p_spq->free_pool);
57814b24e2bSVaishali Kulkarni 	OSAL_LIST_INIT(&p_spq->unlimited_pending);
57914b24e2bSVaishali Kulkarni 	OSAL_SPIN_LOCK_INIT(&p_spq->lock);
58014b24e2bSVaishali Kulkarni 
58114b24e2bSVaishali Kulkarni 	/* SPQ empty pool */
582*04443fdeSToomas Soome 	p_phys = p_spq->p_phys + offsetof(struct ecore_spq_entry, ramrod);
58314b24e2bSVaishali Kulkarni 	p_virt = p_spq->p_virt;
58414b24e2bSVaishali Kulkarni 
58514b24e2bSVaishali Kulkarni 	capacity = ecore_chain_get_capacity(&p_spq->chain);
58614b24e2bSVaishali Kulkarni 	for (i = 0; i < capacity; i++) {
58714b24e2bSVaishali Kulkarni 		DMA_REGPAIR_LE(p_virt->elem.data_ptr, p_phys);
58814b24e2bSVaishali Kulkarni 
58914b24e2bSVaishali Kulkarni 		OSAL_LIST_PUSH_TAIL(&p_virt->list, &p_spq->free_pool);
59014b24e2bSVaishali Kulkarni 
59114b24e2bSVaishali Kulkarni 		p_virt++;
59214b24e2bSVaishali Kulkarni 		p_phys += sizeof(struct ecore_spq_entry);
59314b24e2bSVaishali Kulkarni 	}
59414b24e2bSVaishali Kulkarni 
59514b24e2bSVaishali Kulkarni 	/* Statistics */
59614b24e2bSVaishali Kulkarni 	p_spq->normal_count		= 0;
59714b24e2bSVaishali Kulkarni 	p_spq->comp_count		= 0;
59814b24e2bSVaishali Kulkarni 	p_spq->comp_sent_count		= 0;
59914b24e2bSVaishali Kulkarni 	p_spq->unlimited_pending_count	= 0;
60014b24e2bSVaishali Kulkarni 
60114b24e2bSVaishali Kulkarni 	OSAL_MEM_ZERO(p_spq->p_comp_bitmap,
60214b24e2bSVaishali Kulkarni 		      SPQ_COMP_BMAP_SIZE * sizeof(unsigned long));
60314b24e2bSVaishali Kulkarni 	p_spq->comp_bitmap_idx = 0;
60414b24e2bSVaishali Kulkarni 
60514b24e2bSVaishali Kulkarni 	/* SPQ cid, cannot fail */
60614b24e2bSVaishali Kulkarni 	ecore_cxt_acquire_cid(p_hwfn, PROTOCOLID_CORE, &p_spq->cid);
60714b24e2bSVaishali Kulkarni 	ecore_spq_hw_initialize(p_hwfn, p_spq);
60814b24e2bSVaishali Kulkarni 
60914b24e2bSVaishali Kulkarni 	/* reset the chain itself */
61014b24e2bSVaishali Kulkarni 	ecore_chain_reset(&p_spq->chain);
61114b24e2bSVaishali Kulkarni }
61214b24e2bSVaishali Kulkarni 
ecore_spq_alloc(struct ecore_hwfn * p_hwfn)61314b24e2bSVaishali Kulkarni enum _ecore_status_t ecore_spq_alloc(struct ecore_hwfn *p_hwfn)
61414b24e2bSVaishali Kulkarni {
61514b24e2bSVaishali Kulkarni 	struct ecore_spq_entry *p_virt = OSAL_NULL;
61614b24e2bSVaishali Kulkarni 	struct ecore_spq *p_spq = OSAL_NULL;
61714b24e2bSVaishali Kulkarni 	dma_addr_t p_phys = 0;
61814b24e2bSVaishali Kulkarni 	u32 capacity;
61914b24e2bSVaishali Kulkarni 
62014b24e2bSVaishali Kulkarni 	/* SPQ struct */
62114b24e2bSVaishali Kulkarni 	p_spq =
62214b24e2bSVaishali Kulkarni 	    OSAL_ZALLOC(p_hwfn->p_dev, GFP_KERNEL, sizeof(struct ecore_spq));
62314b24e2bSVaishali Kulkarni 	if (!p_spq) {
62414b24e2bSVaishali Kulkarni 		DP_NOTICE(p_hwfn, true, "Failed to allocate `struct ecore_spq'\n");
62514b24e2bSVaishali Kulkarni 		return ECORE_NOMEM;
62614b24e2bSVaishali Kulkarni 	}
62714b24e2bSVaishali Kulkarni 
62814b24e2bSVaishali Kulkarni 	/* SPQ ring  */
62914b24e2bSVaishali Kulkarni 	if (ecore_chain_alloc(p_hwfn->p_dev,
63014b24e2bSVaishali Kulkarni 			      ECORE_CHAIN_USE_TO_PRODUCE,
63114b24e2bSVaishali Kulkarni 			      ECORE_CHAIN_MODE_SINGLE,
63214b24e2bSVaishali Kulkarni 			      ECORE_CHAIN_CNT_TYPE_U16,
63314b24e2bSVaishali Kulkarni 			      0, /* N/A when the mode is SINGLE */
63414b24e2bSVaishali Kulkarni 			      sizeof(struct slow_path_element),
63514b24e2bSVaishali Kulkarni 			      &p_spq->chain, OSAL_NULL)) {
63614b24e2bSVaishali Kulkarni 		DP_NOTICE(p_hwfn, true, "Failed to allocate spq chain\n");
63714b24e2bSVaishali Kulkarni 		goto spq_allocate_fail;
63814b24e2bSVaishali Kulkarni 	}
63914b24e2bSVaishali Kulkarni 
64014b24e2bSVaishali Kulkarni 	/* allocate and fill the SPQ elements (incl. ramrod data list) */
64114b24e2bSVaishali Kulkarni 	capacity = ecore_chain_get_capacity(&p_spq->chain);
64214b24e2bSVaishali Kulkarni 	p_virt = OSAL_DMA_ALLOC_COHERENT(p_hwfn->p_dev, &p_phys,
64314b24e2bSVaishali Kulkarni 					 capacity *
64414b24e2bSVaishali Kulkarni 					 sizeof(struct ecore_spq_entry));
64514b24e2bSVaishali Kulkarni 	if (!p_virt) {
64614b24e2bSVaishali Kulkarni 		goto spq_allocate_fail;
64714b24e2bSVaishali Kulkarni 	}
64814b24e2bSVaishali Kulkarni 
64914b24e2bSVaishali Kulkarni 	p_spq->p_virt = p_virt;
65014b24e2bSVaishali Kulkarni 	p_spq->p_phys = p_phys;
65114b24e2bSVaishali Kulkarni 
65214b24e2bSVaishali Kulkarni 	OSAL_SPIN_LOCK_ALLOC(p_hwfn, &p_spq->lock);
65314b24e2bSVaishali Kulkarni 
65414b24e2bSVaishali Kulkarni 	p_hwfn->p_spq = p_spq;
65514b24e2bSVaishali Kulkarni 	return ECORE_SUCCESS;
65614b24e2bSVaishali Kulkarni 
65714b24e2bSVaishali Kulkarni spq_allocate_fail:
65814b24e2bSVaishali Kulkarni 	ecore_chain_free(p_hwfn->p_dev, &p_spq->chain);
65914b24e2bSVaishali Kulkarni 	OSAL_FREE(p_hwfn->p_dev, p_spq);
66014b24e2bSVaishali Kulkarni 	return ECORE_NOMEM;
66114b24e2bSVaishali Kulkarni }
66214b24e2bSVaishali Kulkarni 
ecore_spq_free(struct ecore_hwfn * p_hwfn)66314b24e2bSVaishali Kulkarni void ecore_spq_free(struct ecore_hwfn *p_hwfn)
66414b24e2bSVaishali Kulkarni {
66514b24e2bSVaishali Kulkarni 	struct ecore_spq *p_spq = p_hwfn->p_spq;
66614b24e2bSVaishali Kulkarni 	u32 capacity;
66714b24e2bSVaishali Kulkarni 
66814b24e2bSVaishali Kulkarni 	if (!p_spq)
66914b24e2bSVaishali Kulkarni 		return;
67014b24e2bSVaishali Kulkarni 
67114b24e2bSVaishali Kulkarni 	if (p_spq->p_virt) {
67214b24e2bSVaishali Kulkarni 		capacity = ecore_chain_get_capacity(&p_spq->chain);
67314b24e2bSVaishali Kulkarni 		OSAL_DMA_FREE_COHERENT(p_hwfn->p_dev,
67414b24e2bSVaishali Kulkarni 				       p_spq->p_virt,
67514b24e2bSVaishali Kulkarni 				       p_spq->p_phys,
67614b24e2bSVaishali Kulkarni 				       capacity *
67714b24e2bSVaishali Kulkarni 				       sizeof(struct ecore_spq_entry));
67814b24e2bSVaishali Kulkarni 	}
67914b24e2bSVaishali Kulkarni 
68014b24e2bSVaishali Kulkarni 	ecore_chain_free(p_hwfn->p_dev, &p_spq->chain);
68114b24e2bSVaishali Kulkarni 	OSAL_SPIN_LOCK_DEALLOC(&p_spq->lock);
68214b24e2bSVaishali Kulkarni 
68314b24e2bSVaishali Kulkarni 	OSAL_FREE(p_hwfn->p_dev, p_spq);
68414b24e2bSVaishali Kulkarni 	p_hwfn->p_spq = OSAL_NULL;
68514b24e2bSVaishali Kulkarni }
68614b24e2bSVaishali Kulkarni 
ecore_spq_get_entry(struct ecore_hwfn * p_hwfn,struct ecore_spq_entry ** pp_ent)68714b24e2bSVaishali Kulkarni enum _ecore_status_t ecore_spq_get_entry(struct ecore_hwfn *p_hwfn,
68814b24e2bSVaishali Kulkarni 					 struct ecore_spq_entry **pp_ent)
68914b24e2bSVaishali Kulkarni {
69014b24e2bSVaishali Kulkarni 	struct ecore_spq *p_spq = p_hwfn->p_spq;
69114b24e2bSVaishali Kulkarni 	struct ecore_spq_entry *p_ent = OSAL_NULL;
69214b24e2bSVaishali Kulkarni 	enum _ecore_status_t rc = ECORE_SUCCESS;
69314b24e2bSVaishali Kulkarni 
69414b24e2bSVaishali Kulkarni 	OSAL_SPIN_LOCK(&p_spq->lock);
69514b24e2bSVaishali Kulkarni 
69614b24e2bSVaishali Kulkarni 	if (OSAL_LIST_IS_EMPTY(&p_spq->free_pool)) {
69714b24e2bSVaishali Kulkarni 
69814b24e2bSVaishali Kulkarni 		p_ent = OSAL_ZALLOC(p_hwfn->p_dev, GFP_ATOMIC, sizeof(*p_ent));
69914b24e2bSVaishali Kulkarni 		if (!p_ent) {
70014b24e2bSVaishali Kulkarni 			DP_NOTICE(p_hwfn, true, "Failed to allocate an SPQ entry for a pending ramrod\n");
70114b24e2bSVaishali Kulkarni 			rc = ECORE_NOMEM;
70214b24e2bSVaishali Kulkarni 			goto out_unlock;
70314b24e2bSVaishali Kulkarni 		}
70414b24e2bSVaishali Kulkarni 		p_ent->queue = &p_spq->unlimited_pending;
70514b24e2bSVaishali Kulkarni 	} else {
70614b24e2bSVaishali Kulkarni 		p_ent = OSAL_LIST_FIRST_ENTRY(&p_spq->free_pool,
70714b24e2bSVaishali Kulkarni 					      struct ecore_spq_entry,
70814b24e2bSVaishali Kulkarni 					      list);
70914b24e2bSVaishali Kulkarni 		OSAL_LIST_REMOVE_ENTRY(&p_ent->list, &p_spq->free_pool);
71014b24e2bSVaishali Kulkarni 		p_ent->queue = &p_spq->pending;
71114b24e2bSVaishali Kulkarni 	}
71214b24e2bSVaishali Kulkarni 
71314b24e2bSVaishali Kulkarni 	*pp_ent = p_ent;
71414b24e2bSVaishali Kulkarni 
71514b24e2bSVaishali Kulkarni out_unlock:
71614b24e2bSVaishali Kulkarni 	OSAL_SPIN_UNLOCK(&p_spq->lock);
71714b24e2bSVaishali Kulkarni 	return rc;
71814b24e2bSVaishali Kulkarni }
71914b24e2bSVaishali Kulkarni 
72014b24e2bSVaishali Kulkarni /* Locked variant; Should be called while the SPQ lock is taken */
__ecore_spq_return_entry(struct ecore_hwfn * p_hwfn,struct ecore_spq_entry * p_ent)72114b24e2bSVaishali Kulkarni static void __ecore_spq_return_entry(struct ecore_hwfn *p_hwfn,
72214b24e2bSVaishali Kulkarni 			      struct ecore_spq_entry *p_ent)
72314b24e2bSVaishali Kulkarni {
72414b24e2bSVaishali Kulkarni 	OSAL_LIST_PUSH_TAIL(&p_ent->list, &p_hwfn->p_spq->free_pool);
72514b24e2bSVaishali Kulkarni }
72614b24e2bSVaishali Kulkarni 
ecore_spq_return_entry(struct ecore_hwfn * p_hwfn,struct ecore_spq_entry * p_ent)72714b24e2bSVaishali Kulkarni void ecore_spq_return_entry(struct ecore_hwfn *p_hwfn,
72814b24e2bSVaishali Kulkarni 			    struct ecore_spq_entry *p_ent)
72914b24e2bSVaishali Kulkarni {
73014b24e2bSVaishali Kulkarni 	OSAL_SPIN_LOCK(&p_hwfn->p_spq->lock);
73114b24e2bSVaishali Kulkarni 	__ecore_spq_return_entry(p_hwfn, p_ent);
73214b24e2bSVaishali Kulkarni 	OSAL_SPIN_UNLOCK(&p_hwfn->p_spq->lock);
73314b24e2bSVaishali Kulkarni }
73414b24e2bSVaishali Kulkarni 
73514b24e2bSVaishali Kulkarni /**
73614b24e2bSVaishali Kulkarni  * @brief ecore_spq_add_entry - adds a new entry to the pending
73714b24e2bSVaishali Kulkarni  *        list. Should be used while lock is being held.
73814b24e2bSVaishali Kulkarni  *
73914b24e2bSVaishali Kulkarni  * Addes an entry to the pending list is there is room (en empty
74014b24e2bSVaishali Kulkarni  * element is avaliable in the free_pool), or else places the
74114b24e2bSVaishali Kulkarni  * entry in the unlimited_pending pool.
74214b24e2bSVaishali Kulkarni  *
74314b24e2bSVaishali Kulkarni  * @param p_hwfn
74414b24e2bSVaishali Kulkarni  * @param p_ent
74514b24e2bSVaishali Kulkarni  * @param priority
74614b24e2bSVaishali Kulkarni  *
74714b24e2bSVaishali Kulkarni  * @return enum _ecore_status_t
74814b24e2bSVaishali Kulkarni  */
ecore_spq_add_entry(struct ecore_hwfn * p_hwfn,struct ecore_spq_entry * p_ent,enum spq_priority priority)74914b24e2bSVaishali Kulkarni static enum _ecore_status_t ecore_spq_add_entry(struct ecore_hwfn *p_hwfn,
75014b24e2bSVaishali Kulkarni 						struct ecore_spq_entry *p_ent,
75114b24e2bSVaishali Kulkarni 						enum spq_priority priority)
75214b24e2bSVaishali Kulkarni {
75314b24e2bSVaishali Kulkarni 	struct ecore_spq	*p_spq	= p_hwfn->p_spq;
75414b24e2bSVaishali Kulkarni 
75514b24e2bSVaishali Kulkarni 	if (p_ent->queue == &p_spq->unlimited_pending) {
75614b24e2bSVaishali Kulkarni 		if (OSAL_LIST_IS_EMPTY(&p_spq->free_pool)) {
75714b24e2bSVaishali Kulkarni 
75814b24e2bSVaishali Kulkarni 			OSAL_LIST_PUSH_TAIL(&p_ent->list,
75914b24e2bSVaishali Kulkarni 					    &p_spq->unlimited_pending);
76014b24e2bSVaishali Kulkarni 			p_spq->unlimited_pending_count++;
76114b24e2bSVaishali Kulkarni 
76214b24e2bSVaishali Kulkarni 			return ECORE_SUCCESS;
76314b24e2bSVaishali Kulkarni 
76414b24e2bSVaishali Kulkarni 		} else {
76514b24e2bSVaishali Kulkarni 			struct ecore_spq_entry *p_en2;
76614b24e2bSVaishali Kulkarni 
76714b24e2bSVaishali Kulkarni 			p_en2 = OSAL_LIST_FIRST_ENTRY(&p_spq->free_pool,
76814b24e2bSVaishali Kulkarni 						     struct ecore_spq_entry,
76914b24e2bSVaishali Kulkarni 						     list);
77014b24e2bSVaishali Kulkarni 			OSAL_LIST_REMOVE_ENTRY(&p_en2->list, &p_spq->free_pool);
77114b24e2bSVaishali Kulkarni 
77214b24e2bSVaishali Kulkarni 			/* Copy the ring element physical pointer to the new
77314b24e2bSVaishali Kulkarni 			 * entry, since we are about to override the entire ring
77414b24e2bSVaishali Kulkarni 			 * entry and don't want to lose the pointer.
77514b24e2bSVaishali Kulkarni 			 */
77614b24e2bSVaishali Kulkarni 			p_ent->elem.data_ptr = p_en2->elem.data_ptr;
77714b24e2bSVaishali Kulkarni 
77814b24e2bSVaishali Kulkarni 			*p_en2 = *p_ent;
77914b24e2bSVaishali Kulkarni 
78014b24e2bSVaishali Kulkarni 			/* EBLOCK responsible to free the allocated p_ent */
78114b24e2bSVaishali Kulkarni 			if (p_ent->comp_mode != ECORE_SPQ_MODE_EBLOCK)
78214b24e2bSVaishali Kulkarni 				OSAL_FREE(p_hwfn->p_dev, p_ent);
78314b24e2bSVaishali Kulkarni 
78414b24e2bSVaishali Kulkarni 			p_ent = p_en2;
78514b24e2bSVaishali Kulkarni 		}
78614b24e2bSVaishali Kulkarni 	}
78714b24e2bSVaishali Kulkarni 
78814b24e2bSVaishali Kulkarni 	/* entry is to be placed in 'pending' queue */
78914b24e2bSVaishali Kulkarni 	switch (priority) {
79014b24e2bSVaishali Kulkarni 	case ECORE_SPQ_PRIORITY_NORMAL:
79114b24e2bSVaishali Kulkarni 		OSAL_LIST_PUSH_TAIL(&p_ent->list, &p_spq->pending);
79214b24e2bSVaishali Kulkarni 		p_spq->normal_count++;
79314b24e2bSVaishali Kulkarni 		break;
79414b24e2bSVaishali Kulkarni 	case ECORE_SPQ_PRIORITY_HIGH:
79514b24e2bSVaishali Kulkarni 		OSAL_LIST_PUSH_HEAD(&p_ent->list, &p_spq->pending);
79614b24e2bSVaishali Kulkarni 		p_spq->high_count++;
79714b24e2bSVaishali Kulkarni 		break;
79814b24e2bSVaishali Kulkarni 	default:
79914b24e2bSVaishali Kulkarni 		return ECORE_INVAL;
80014b24e2bSVaishali Kulkarni 	}
80114b24e2bSVaishali Kulkarni 
80214b24e2bSVaishali Kulkarni 	return ECORE_SUCCESS;
80314b24e2bSVaishali Kulkarni }
80414b24e2bSVaishali Kulkarni 
80514b24e2bSVaishali Kulkarni /***************************************************************************
80614b24e2bSVaishali Kulkarni  * Accessor
80714b24e2bSVaishali Kulkarni  ***************************************************************************/
80814b24e2bSVaishali Kulkarni 
ecore_spq_get_cid(struct ecore_hwfn * p_hwfn)80914b24e2bSVaishali Kulkarni u32 ecore_spq_get_cid(struct ecore_hwfn *p_hwfn)
81014b24e2bSVaishali Kulkarni {
81114b24e2bSVaishali Kulkarni 	if (!p_hwfn->p_spq) {
81214b24e2bSVaishali Kulkarni 		return 0xffffffff;	/* illegal */
81314b24e2bSVaishali Kulkarni 	}
81414b24e2bSVaishali Kulkarni 	return p_hwfn->p_spq->cid;
81514b24e2bSVaishali Kulkarni }
81614b24e2bSVaishali Kulkarni 
81714b24e2bSVaishali Kulkarni /***************************************************************************
81814b24e2bSVaishali Kulkarni  * Posting new Ramrods
81914b24e2bSVaishali Kulkarni  ***************************************************************************/
82014b24e2bSVaishali Kulkarni 
ecore_spq_post_list(struct ecore_hwfn * p_hwfn,osal_list_t * head,u32 keep_reserve)82114b24e2bSVaishali Kulkarni static enum _ecore_status_t ecore_spq_post_list(struct ecore_hwfn *p_hwfn,
82214b24e2bSVaishali Kulkarni 						osal_list_t	  *head,
82314b24e2bSVaishali Kulkarni 						u32		  keep_reserve)
82414b24e2bSVaishali Kulkarni {
82514b24e2bSVaishali Kulkarni 	struct ecore_spq	*p_spq = p_hwfn->p_spq;
82614b24e2bSVaishali Kulkarni 	enum _ecore_status_t	rc;
82714b24e2bSVaishali Kulkarni 
82814b24e2bSVaishali Kulkarni 	/* TODO - implementation might be wasteful; will always keep room
82914b24e2bSVaishali Kulkarni 	 * for an additional high priority ramrod (even if one is already
83014b24e2bSVaishali Kulkarni 	 * pending FW)
83114b24e2bSVaishali Kulkarni 	 */
83214b24e2bSVaishali Kulkarni 	while (ecore_chain_get_elem_left(&p_spq->chain) > keep_reserve &&
83314b24e2bSVaishali Kulkarni 	       !OSAL_LIST_IS_EMPTY(head)) {
83414b24e2bSVaishali Kulkarni 		struct ecore_spq_entry  *p_ent =
83514b24e2bSVaishali Kulkarni 		    OSAL_LIST_FIRST_ENTRY(head, struct ecore_spq_entry, list);
83614b24e2bSVaishali Kulkarni 		if (p_ent != OSAL_NULL) {
83714b24e2bSVaishali Kulkarni #if defined(_NTDDK_)
83814b24e2bSVaishali Kulkarni #pragma warning(suppress : 6011 28182)
83914b24e2bSVaishali Kulkarni #endif
84014b24e2bSVaishali Kulkarni 			OSAL_LIST_REMOVE_ENTRY(&p_ent->list, head);
84114b24e2bSVaishali Kulkarni 			OSAL_LIST_PUSH_TAIL(&p_ent->list, &p_spq->completion_pending);
84214b24e2bSVaishali Kulkarni 			p_spq->comp_sent_count++;
84314b24e2bSVaishali Kulkarni 
84414b24e2bSVaishali Kulkarni 			rc = ecore_spq_hw_post(p_hwfn, p_spq, p_ent);
84514b24e2bSVaishali Kulkarni 			if (rc) {
84614b24e2bSVaishali Kulkarni 				OSAL_LIST_REMOVE_ENTRY(&p_ent->list,
84714b24e2bSVaishali Kulkarni 									&p_spq->completion_pending);
84814b24e2bSVaishali Kulkarni 				__ecore_spq_return_entry(p_hwfn, p_ent);
84914b24e2bSVaishali Kulkarni 				return rc;
85014b24e2bSVaishali Kulkarni 			}
85114b24e2bSVaishali Kulkarni 		}
85214b24e2bSVaishali Kulkarni 	}
85314b24e2bSVaishali Kulkarni 
85414b24e2bSVaishali Kulkarni 	return ECORE_SUCCESS;
85514b24e2bSVaishali Kulkarni }
85614b24e2bSVaishali Kulkarni 
ecore_spq_pend_post(struct ecore_hwfn * p_hwfn)85714b24e2bSVaishali Kulkarni static enum _ecore_status_t ecore_spq_pend_post(struct ecore_hwfn *p_hwfn)
85814b24e2bSVaishali Kulkarni {
85914b24e2bSVaishali Kulkarni 	struct ecore_spq *p_spq = p_hwfn->p_spq;
86014b24e2bSVaishali Kulkarni 	struct ecore_spq_entry *p_ent = OSAL_NULL;
86114b24e2bSVaishali Kulkarni 
86214b24e2bSVaishali Kulkarni 	while (!OSAL_LIST_IS_EMPTY(&p_spq->free_pool))
86314b24e2bSVaishali Kulkarni 	{
86414b24e2bSVaishali Kulkarni 		if (OSAL_LIST_IS_EMPTY(&p_spq->unlimited_pending))
86514b24e2bSVaishali Kulkarni 			break;
86614b24e2bSVaishali Kulkarni 
86714b24e2bSVaishali Kulkarni 		p_ent = OSAL_LIST_FIRST_ENTRY(&p_spq->unlimited_pending,
86814b24e2bSVaishali Kulkarni 					      struct ecore_spq_entry,
86914b24e2bSVaishali Kulkarni 					      list);
87014b24e2bSVaishali Kulkarni 		if (!p_ent)
87114b24e2bSVaishali Kulkarni 			return ECORE_INVAL;
87214b24e2bSVaishali Kulkarni 
87314b24e2bSVaishali Kulkarni #if defined(_NTDDK_)
87414b24e2bSVaishali Kulkarni #pragma warning(suppress : 6011)
87514b24e2bSVaishali Kulkarni #endif
87614b24e2bSVaishali Kulkarni 		OSAL_LIST_REMOVE_ENTRY(&p_ent->list, &p_spq->unlimited_pending);
87714b24e2bSVaishali Kulkarni 
87814b24e2bSVaishali Kulkarni 		ecore_spq_add_entry(p_hwfn, p_ent, p_ent->priority);
87914b24e2bSVaishali Kulkarni 	}
88014b24e2bSVaishali Kulkarni 
88114b24e2bSVaishali Kulkarni 	return ecore_spq_post_list(p_hwfn, &p_spq->pending,
88214b24e2bSVaishali Kulkarni 				   SPQ_HIGH_PRI_RESERVE_DEFAULT);
88314b24e2bSVaishali Kulkarni }
88414b24e2bSVaishali Kulkarni 
ecore_spq_post(struct ecore_hwfn * p_hwfn,struct ecore_spq_entry * p_ent,u8 * fw_return_code)88514b24e2bSVaishali Kulkarni enum _ecore_status_t ecore_spq_post(struct ecore_hwfn		*p_hwfn,
88614b24e2bSVaishali Kulkarni 				    struct ecore_spq_entry	*p_ent,
88714b24e2bSVaishali Kulkarni 				    u8                          *fw_return_code)
88814b24e2bSVaishali Kulkarni {
88914b24e2bSVaishali Kulkarni 	enum _ecore_status_t	rc = ECORE_SUCCESS;
89014b24e2bSVaishali Kulkarni 	struct ecore_spq	*p_spq = p_hwfn ? p_hwfn->p_spq : OSAL_NULL;
89114b24e2bSVaishali Kulkarni 	bool			b_ret_ent = true;
89214b24e2bSVaishali Kulkarni 
89314b24e2bSVaishali Kulkarni 	if (!p_hwfn)
89414b24e2bSVaishali Kulkarni 		return ECORE_INVAL;
89514b24e2bSVaishali Kulkarni 
89614b24e2bSVaishali Kulkarni 	if (!p_ent) {
89714b24e2bSVaishali Kulkarni 		DP_NOTICE(p_hwfn, true, "Got a NULL pointer\n");
89814b24e2bSVaishali Kulkarni 		return ECORE_INVAL;
89914b24e2bSVaishali Kulkarni 	}
90014b24e2bSVaishali Kulkarni 
90114b24e2bSVaishali Kulkarni 	if (p_hwfn->p_dev->recov_in_prog) {
90214b24e2bSVaishali Kulkarni 		DP_VERBOSE(p_hwfn, ECORE_MSG_SPQ,
90314b24e2bSVaishali Kulkarni 			   "Recovery is in progress -> skip spq post [cmd %02x protocol %02x]\n",
90414b24e2bSVaishali Kulkarni 			   p_ent->elem.hdr.cmd_id, p_ent->elem.hdr.protocol_id);
90514b24e2bSVaishali Kulkarni 		/* Return success to let the flows to be completed successfully
90614b24e2bSVaishali Kulkarni 		 * w/o any error handling.
90714b24e2bSVaishali Kulkarni 		 */
90814b24e2bSVaishali Kulkarni 		return ECORE_SUCCESS;
90914b24e2bSVaishali Kulkarni 	}
91014b24e2bSVaishali Kulkarni 
91114b24e2bSVaishali Kulkarni 	OSAL_SPIN_LOCK(&p_spq->lock);
91214b24e2bSVaishali Kulkarni 
91314b24e2bSVaishali Kulkarni 	/* Complete the entry */
91414b24e2bSVaishali Kulkarni 	rc = ecore_spq_fill_entry(p_hwfn, p_ent);
91514b24e2bSVaishali Kulkarni 
91614b24e2bSVaishali Kulkarni 	/* Check return value after LOCK is taken for cleaner error flow */
91714b24e2bSVaishali Kulkarni 	if (rc)
91814b24e2bSVaishali Kulkarni 		goto spq_post_fail;
91914b24e2bSVaishali Kulkarni 
92014b24e2bSVaishali Kulkarni 	/* Add the request to the pending queue */
92114b24e2bSVaishali Kulkarni 	rc = ecore_spq_add_entry(p_hwfn, p_ent, p_ent->priority);
92214b24e2bSVaishali Kulkarni 	if (rc)
92314b24e2bSVaishali Kulkarni 		goto spq_post_fail;
92414b24e2bSVaishali Kulkarni 
92514b24e2bSVaishali Kulkarni 	rc = ecore_spq_pend_post(p_hwfn);
92614b24e2bSVaishali Kulkarni 	if (rc) {
92714b24e2bSVaishali Kulkarni 		/* Since it's possible that pending failed for a different
92814b24e2bSVaishali Kulkarni 		 * entry [altough unlikely], the failed entry was already
92914b24e2bSVaishali Kulkarni 		 * dealt with; No need to return it here.
93014b24e2bSVaishali Kulkarni 		 */
93114b24e2bSVaishali Kulkarni 		b_ret_ent = false;
93214b24e2bSVaishali Kulkarni 		goto spq_post_fail;
93314b24e2bSVaishali Kulkarni 	}
93414b24e2bSVaishali Kulkarni 
93514b24e2bSVaishali Kulkarni 	OSAL_SPIN_UNLOCK(&p_spq->lock);
93614b24e2bSVaishali Kulkarni 
93714b24e2bSVaishali Kulkarni 	if (p_ent->comp_mode == ECORE_SPQ_MODE_EBLOCK) {
93814b24e2bSVaishali Kulkarni 		/* For entries in ECORE BLOCK mode, the completion code cannot
93914b24e2bSVaishali Kulkarni 		 * perform the neccessary cleanup - if it did, we couldn't
94014b24e2bSVaishali Kulkarni 		 * access p_ent here to see whether it's successful or not.
94114b24e2bSVaishali Kulkarni 		 * Thus, after gaining the answer - perform the cleanup here.
94214b24e2bSVaishali Kulkarni 		 */
94314b24e2bSVaishali Kulkarni 		rc = ecore_spq_block(p_hwfn, p_ent, fw_return_code,
94414b24e2bSVaishali Kulkarni 				     p_ent->queue == &p_spq->unlimited_pending);
94514b24e2bSVaishali Kulkarni 
94614b24e2bSVaishali Kulkarni 		if (p_ent->queue == &p_spq->unlimited_pending) {
94714b24e2bSVaishali Kulkarni 			/* This is an allocated p_ent which does not need to
94814b24e2bSVaishali Kulkarni 			 * return to pool.
94914b24e2bSVaishali Kulkarni 			 */
95014b24e2bSVaishali Kulkarni 			OSAL_FREE(p_hwfn->p_dev, p_ent);
95114b24e2bSVaishali Kulkarni 
95214b24e2bSVaishali Kulkarni 			/* TBD: handle error flow and remove p_ent from
95314b24e2bSVaishali Kulkarni 			 * completion pending
95414b24e2bSVaishali Kulkarni 			 */
95514b24e2bSVaishali Kulkarni 			return rc;
95614b24e2bSVaishali Kulkarni 		}
95714b24e2bSVaishali Kulkarni 
95814b24e2bSVaishali Kulkarni 		if (rc)
95914b24e2bSVaishali Kulkarni 			goto spq_post_fail2;
96014b24e2bSVaishali Kulkarni 
96114b24e2bSVaishali Kulkarni 		/* return to pool */
96214b24e2bSVaishali Kulkarni 		ecore_spq_return_entry(p_hwfn, p_ent);
96314b24e2bSVaishali Kulkarni 	}
96414b24e2bSVaishali Kulkarni 	return rc;
96514b24e2bSVaishali Kulkarni 
96614b24e2bSVaishali Kulkarni spq_post_fail2:
96714b24e2bSVaishali Kulkarni 	OSAL_SPIN_LOCK(&p_spq->lock);
96814b24e2bSVaishali Kulkarni 	OSAL_LIST_REMOVE_ENTRY(&p_ent->list, &p_spq->completion_pending);
96914b24e2bSVaishali Kulkarni 	ecore_chain_return_produced(&p_spq->chain);
97014b24e2bSVaishali Kulkarni 
97114b24e2bSVaishali Kulkarni spq_post_fail:
97214b24e2bSVaishali Kulkarni 	/* return to the free pool */
97314b24e2bSVaishali Kulkarni 	if (b_ret_ent)
97414b24e2bSVaishali Kulkarni 		__ecore_spq_return_entry(p_hwfn, p_ent);
97514b24e2bSVaishali Kulkarni 	OSAL_SPIN_UNLOCK(&p_spq->lock);
97614b24e2bSVaishali Kulkarni 
97714b24e2bSVaishali Kulkarni 	return rc;
97814b24e2bSVaishali Kulkarni }
97914b24e2bSVaishali Kulkarni 
ecore_spq_completion(struct ecore_hwfn * p_hwfn,__le16 echo,u8 fw_return_code,union event_ring_data * p_data)98014b24e2bSVaishali Kulkarni enum _ecore_status_t ecore_spq_completion(struct ecore_hwfn *p_hwfn,
98114b24e2bSVaishali Kulkarni 					  __le16 echo,
98214b24e2bSVaishali Kulkarni 					  u8 fw_return_code,
98314b24e2bSVaishali Kulkarni 					  union event_ring_data	*p_data)
98414b24e2bSVaishali Kulkarni {
98514b24e2bSVaishali Kulkarni 	struct ecore_spq	*p_spq;
98614b24e2bSVaishali Kulkarni 	struct ecore_spq_entry	*p_ent = OSAL_NULL;
98714b24e2bSVaishali Kulkarni 	struct ecore_spq_entry	*tmp;
98814b24e2bSVaishali Kulkarni 	struct ecore_spq_entry	*found = OSAL_NULL;
98914b24e2bSVaishali Kulkarni 	enum _ecore_status_t	rc;
99014b24e2bSVaishali Kulkarni 
99114b24e2bSVaishali Kulkarni 	if (!p_hwfn) {
99214b24e2bSVaishali Kulkarni 		return ECORE_INVAL;
99314b24e2bSVaishali Kulkarni 	}
99414b24e2bSVaishali Kulkarni 
99514b24e2bSVaishali Kulkarni 	p_spq = p_hwfn->p_spq;
99614b24e2bSVaishali Kulkarni 	if (!p_spq) {
99714b24e2bSVaishali Kulkarni 		return ECORE_INVAL;
99814b24e2bSVaishali Kulkarni 	}
99914b24e2bSVaishali Kulkarni 
100014b24e2bSVaishali Kulkarni 	OSAL_SPIN_LOCK(&p_spq->lock);
100114b24e2bSVaishali Kulkarni 	OSAL_LIST_FOR_EACH_ENTRY_SAFE(p_ent,
100214b24e2bSVaishali Kulkarni 				      tmp,
100314b24e2bSVaishali Kulkarni 				      &p_spq->completion_pending,
100414b24e2bSVaishali Kulkarni 				      list,
100514b24e2bSVaishali Kulkarni 				      struct ecore_spq_entry) {
100614b24e2bSVaishali Kulkarni 
100714b24e2bSVaishali Kulkarni 		if (p_ent->elem.hdr.echo == echo) {
100814b24e2bSVaishali Kulkarni 			OSAL_LIST_REMOVE_ENTRY(&p_ent->list,
100914b24e2bSVaishali Kulkarni 					       &p_spq->completion_pending);
101014b24e2bSVaishali Kulkarni 
101114b24e2bSVaishali Kulkarni 			/* Avoid overriding of SPQ entries when getting
101214b24e2bSVaishali Kulkarni 			 * out-of-order completions, by marking the completions
101314b24e2bSVaishali Kulkarni 			 * in a bitmap and increasing the chain consumer only
101414b24e2bSVaishali Kulkarni 			 * for the first successive completed entries.
101514b24e2bSVaishali Kulkarni 			 */
101614b24e2bSVaishali Kulkarni 			SPQ_COMP_BMAP_SET_BIT(p_spq, echo);
101714b24e2bSVaishali Kulkarni 			while (SPQ_COMP_BMAP_TEST_BIT(p_spq,
101814b24e2bSVaishali Kulkarni 						      p_spq->comp_bitmap_idx)) {
101914b24e2bSVaishali Kulkarni 				SPQ_COMP_BMAP_CLEAR_BIT(p_spq,
102014b24e2bSVaishali Kulkarni 							p_spq->comp_bitmap_idx);
102114b24e2bSVaishali Kulkarni 				p_spq->comp_bitmap_idx++;
102214b24e2bSVaishali Kulkarni 				ecore_chain_return_produced(&p_spq->chain);
102314b24e2bSVaishali Kulkarni 			}
102414b24e2bSVaishali Kulkarni 
102514b24e2bSVaishali Kulkarni 			p_spq->comp_count++;
102614b24e2bSVaishali Kulkarni 			found = p_ent;
102714b24e2bSVaishali Kulkarni 			break;
102814b24e2bSVaishali Kulkarni 		}
102914b24e2bSVaishali Kulkarni 
103014b24e2bSVaishali Kulkarni 		/* This is debug and should be relatively uncommon - depends
103114b24e2bSVaishali Kulkarni 		 * on scenarios which have mutliple per-PF sent ramrods.
103214b24e2bSVaishali Kulkarni 		 */
103314b24e2bSVaishali Kulkarni 		DP_VERBOSE(p_hwfn, ECORE_MSG_SPQ,
103414b24e2bSVaishali Kulkarni 			   "Got completion for echo %04x - doesn't match echo %04x in completion pending list\n",
103514b24e2bSVaishali Kulkarni 			   OSAL_LE16_TO_CPU(echo),
103614b24e2bSVaishali Kulkarni 			   OSAL_LE16_TO_CPU(p_ent->elem.hdr.echo));
103714b24e2bSVaishali Kulkarni 	}
103814b24e2bSVaishali Kulkarni 
103914b24e2bSVaishali Kulkarni 	/* Release lock before callback, as callback may post
104014b24e2bSVaishali Kulkarni 	 * an additional ramrod.
104114b24e2bSVaishali Kulkarni 	 */
104214b24e2bSVaishali Kulkarni 	OSAL_SPIN_UNLOCK(&p_spq->lock);
104314b24e2bSVaishali Kulkarni 
104414b24e2bSVaishali Kulkarni 	if (!found) {
104514b24e2bSVaishali Kulkarni 		DP_NOTICE(p_hwfn, true,
104614b24e2bSVaishali Kulkarni 			  "Failed to find an entry this EQE [echo %04x] completes\n",
104714b24e2bSVaishali Kulkarni 			  OSAL_LE16_TO_CPU(echo));
104814b24e2bSVaishali Kulkarni 		return ECORE_EXISTS;
104914b24e2bSVaishali Kulkarni 	}
105014b24e2bSVaishali Kulkarni 
105114b24e2bSVaishali Kulkarni 	DP_VERBOSE(p_hwfn, ECORE_MSG_SPQ,
105214b24e2bSVaishali Kulkarni 		   "Complete EQE [echo %04x]: func %p cookie %p)\n",
105314b24e2bSVaishali Kulkarni 		   OSAL_LE16_TO_CPU(echo),
105414b24e2bSVaishali Kulkarni 		   p_ent->comp_cb.function, p_ent->comp_cb.cookie);
105514b24e2bSVaishali Kulkarni 	if (found->comp_cb.function)
105614b24e2bSVaishali Kulkarni 		found->comp_cb.function(p_hwfn, found->comp_cb.cookie, p_data,
105714b24e2bSVaishali Kulkarni 					fw_return_code);
105814b24e2bSVaishali Kulkarni 	else
105914b24e2bSVaishali Kulkarni 		DP_VERBOSE(p_hwfn, ECORE_MSG_SPQ, "Got a completion without a callback function\n");
106014b24e2bSVaishali Kulkarni 
106114b24e2bSVaishali Kulkarni 	if ((found->comp_mode != ECORE_SPQ_MODE_EBLOCK) ||
106214b24e2bSVaishali Kulkarni 	    (found->queue == &p_spq->unlimited_pending))
106314b24e2bSVaishali Kulkarni 		/* EBLOCK  is responsible for returning its own entry into the
106414b24e2bSVaishali Kulkarni 		 * free list, unless it originally added the entry into the
106514b24e2bSVaishali Kulkarni 		 * unlimited pending list.
106614b24e2bSVaishali Kulkarni 		 */
106714b24e2bSVaishali Kulkarni 		ecore_spq_return_entry(p_hwfn, found);
106814b24e2bSVaishali Kulkarni 
106914b24e2bSVaishali Kulkarni 	/* Attempt to post pending requests */
107014b24e2bSVaishali Kulkarni 	OSAL_SPIN_LOCK(&p_spq->lock);
107114b24e2bSVaishali Kulkarni 	rc = ecore_spq_pend_post(p_hwfn);
107214b24e2bSVaishali Kulkarni 	OSAL_SPIN_UNLOCK(&p_spq->lock);
107314b24e2bSVaishali Kulkarni 
107414b24e2bSVaishali Kulkarni 	return rc;
107514b24e2bSVaishali Kulkarni }
107614b24e2bSVaishali Kulkarni 
ecore_consq_alloc(struct ecore_hwfn * p_hwfn)107714b24e2bSVaishali Kulkarni enum _ecore_status_t ecore_consq_alloc(struct ecore_hwfn *p_hwfn)
107814b24e2bSVaishali Kulkarni {
107914b24e2bSVaishali Kulkarni 	struct ecore_consq *p_consq;
108014b24e2bSVaishali Kulkarni 
108114b24e2bSVaishali Kulkarni 	/* Allocate ConsQ struct */
108214b24e2bSVaishali Kulkarni 	p_consq = OSAL_ZALLOC(p_hwfn->p_dev, GFP_KERNEL, sizeof(*p_consq));
108314b24e2bSVaishali Kulkarni 	if (!p_consq) {
108414b24e2bSVaishali Kulkarni 		DP_NOTICE(p_hwfn, true,
108514b24e2bSVaishali Kulkarni 			  "Failed to allocate `struct ecore_consq'\n");
108614b24e2bSVaishali Kulkarni 		return ECORE_NOMEM;
108714b24e2bSVaishali Kulkarni 	}
108814b24e2bSVaishali Kulkarni 
108914b24e2bSVaishali Kulkarni 	/* Allocate and initialize EQ chain*/
109014b24e2bSVaishali Kulkarni 	if (ecore_chain_alloc(p_hwfn->p_dev,
109114b24e2bSVaishali Kulkarni 			      ECORE_CHAIN_USE_TO_PRODUCE,
109214b24e2bSVaishali Kulkarni 			      ECORE_CHAIN_MODE_PBL,
109314b24e2bSVaishali Kulkarni 			      ECORE_CHAIN_CNT_TYPE_U16,
109414b24e2bSVaishali Kulkarni 			      ECORE_CHAIN_PAGE_SIZE/0x80,
109514b24e2bSVaishali Kulkarni 			      0x80,
109614b24e2bSVaishali Kulkarni 			      &p_consq->chain, OSAL_NULL) != ECORE_SUCCESS) {
109714b24e2bSVaishali Kulkarni 		DP_NOTICE(p_hwfn, true, "Failed to allocate consq chain");
109814b24e2bSVaishali Kulkarni 		goto consq_allocate_fail;
109914b24e2bSVaishali Kulkarni 	}
110014b24e2bSVaishali Kulkarni 
110114b24e2bSVaishali Kulkarni 	p_hwfn->p_consq = p_consq;
110214b24e2bSVaishali Kulkarni 	return ECORE_SUCCESS;
110314b24e2bSVaishali Kulkarni 
110414b24e2bSVaishali Kulkarni consq_allocate_fail:
110514b24e2bSVaishali Kulkarni 	OSAL_FREE(p_hwfn->p_dev, p_consq);
110614b24e2bSVaishali Kulkarni 	return ECORE_NOMEM;
110714b24e2bSVaishali Kulkarni }
110814b24e2bSVaishali Kulkarni 
ecore_consq_setup(struct ecore_hwfn * p_hwfn)110914b24e2bSVaishali Kulkarni void ecore_consq_setup(struct ecore_hwfn *p_hwfn)
111014b24e2bSVaishali Kulkarni {
111114b24e2bSVaishali Kulkarni 	ecore_chain_reset(&p_hwfn->p_consq->chain);
111214b24e2bSVaishali Kulkarni }
111314b24e2bSVaishali Kulkarni 
ecore_consq_free(struct ecore_hwfn * p_hwfn)111414b24e2bSVaishali Kulkarni void ecore_consq_free(struct ecore_hwfn *p_hwfn)
111514b24e2bSVaishali Kulkarni {
111614b24e2bSVaishali Kulkarni 	if (!p_hwfn->p_consq)
111714b24e2bSVaishali Kulkarni 		return;
111814b24e2bSVaishali Kulkarni 
111914b24e2bSVaishali Kulkarni 	ecore_chain_free(p_hwfn->p_dev, &p_hwfn->p_consq->chain);
112014b24e2bSVaishali Kulkarni 
112114b24e2bSVaishali Kulkarni 	OSAL_FREE(p_hwfn->p_dev, p_hwfn->p_consq);
112214b24e2bSVaishali Kulkarni 	p_hwfn->p_consq = OSAL_NULL;
112314b24e2bSVaishali Kulkarni }
112414b24e2bSVaishali Kulkarni 
1125