xref: /dpdk/drivers/net/qede/base/ecore_spq.c (revision 5018f1fc5f18d517c672559d4cc74784a579e037)
13126df22SRasesh Mody /* SPDX-License-Identifier: BSD-3-Clause
29adde217SRasesh Mody  * Copyright (c) 2016 - 2018 Cavium Inc.
3ec94dbc5SRasesh Mody  * All rights reserved.
49adde217SRasesh Mody  * www.cavium.com
5ec94dbc5SRasesh Mody  */
6ec94dbc5SRasesh Mody 
7ec94dbc5SRasesh Mody #include "bcm_osal.h"
8ec94dbc5SRasesh Mody #include "reg_addr.h"
9ec94dbc5SRasesh Mody #include "ecore_gtt_reg_addr.h"
10ec94dbc5SRasesh Mody #include "ecore_hsi_common.h"
11ec94dbc5SRasesh Mody #include "ecore.h"
12ec94dbc5SRasesh Mody #include "ecore_sp_api.h"
13ec94dbc5SRasesh Mody #include "ecore_spq.h"
14ec94dbc5SRasesh Mody #include "ecore_iro.h"
15ec94dbc5SRasesh Mody #include "ecore_init_fw_funcs.h"
16ec94dbc5SRasesh Mody #include "ecore_cxt.h"
17ec94dbc5SRasesh Mody #include "ecore_int.h"
18ec94dbc5SRasesh Mody #include "ecore_dev_api.h"
19ec94dbc5SRasesh Mody #include "ecore_mcp.h"
20ec94dbc5SRasesh Mody #include "ecore_hw.h"
2186a2265eSRasesh Mody #include "ecore_sriov.h"
22ec94dbc5SRasesh Mody 
23ec94dbc5SRasesh Mody /***************************************************************************
24ec94dbc5SRasesh Mody  * Structures & Definitions
25ec94dbc5SRasesh Mody  ***************************************************************************/
26ec94dbc5SRasesh Mody 
27ec94dbc5SRasesh Mody #define SPQ_HIGH_PRI_RESERVE_DEFAULT	(1)
2822d07d93SRasesh Mody 
2922d07d93SRasesh Mody #define SPQ_BLOCK_DELAY_MAX_ITER	(10)
3022d07d93SRasesh Mody #define SPQ_BLOCK_DELAY_US		(10)
312d52085eSRasesh Mody #define SPQ_BLOCK_SLEEP_MAX_ITER	(200)
3222d07d93SRasesh Mody #define SPQ_BLOCK_SLEEP_MS		(5)
33ec94dbc5SRasesh Mody 
34ec94dbc5SRasesh Mody /***************************************************************************
35ec94dbc5SRasesh Mody  * Blocking Imp. (BLOCK/EBLOCK mode)
36ec94dbc5SRasesh Mody  ***************************************************************************/
ecore_spq_blocking_cb(struct ecore_hwfn * p_hwfn,void * cookie,union event_ring_data OSAL_UNUSED * data,u8 fw_return_code)3730ecf673SRasesh Mody static void ecore_spq_blocking_cb(struct ecore_hwfn *p_hwfn, void *cookie,
3830ecf673SRasesh Mody 				  union event_ring_data OSAL_UNUSED * data,
39ec94dbc5SRasesh Mody 				  u8 fw_return_code)
40ec94dbc5SRasesh Mody {
41ec94dbc5SRasesh Mody 	struct ecore_spq_comp_done *comp_done;
42ec94dbc5SRasesh Mody 
43ec94dbc5SRasesh Mody 	comp_done = (struct ecore_spq_comp_done *)cookie;
44ec94dbc5SRasesh Mody 
45ec94dbc5SRasesh Mody 	comp_done->done = 0x1;
46ec94dbc5SRasesh Mody 	comp_done->fw_return_code = fw_return_code;
47ec94dbc5SRasesh Mody 
48ec94dbc5SRasesh Mody 	/* make update visible to waiting thread */
49ec94dbc5SRasesh Mody 	OSAL_SMP_WMB(p_hwfn->p_dev);
50ec94dbc5SRasesh Mody }
51ec94dbc5SRasesh Mody 
__ecore_spq_block(struct ecore_hwfn * p_hwfn,struct ecore_spq_entry * p_ent,u8 * p_fw_ret,bool sleep_between_iter)5222d07d93SRasesh Mody static enum _ecore_status_t __ecore_spq_block(struct ecore_hwfn *p_hwfn,
5322d07d93SRasesh Mody 					      struct ecore_spq_entry *p_ent,
5422d07d93SRasesh Mody 					      u8 *p_fw_ret,
5522d07d93SRasesh Mody 					      bool sleep_between_iter)
5622d07d93SRasesh Mody {
5722d07d93SRasesh Mody 	struct ecore_spq_comp_done *comp_done;
5822d07d93SRasesh Mody 	u32 iter_cnt;
5922d07d93SRasesh Mody 
6022d07d93SRasesh Mody 	comp_done = (struct ecore_spq_comp_done *)p_ent->comp_cb.cookie;
612d52085eSRasesh Mody 	iter_cnt = sleep_between_iter ? p_hwfn->p_spq->block_sleep_max_iter
6222d07d93SRasesh Mody 				      : SPQ_BLOCK_DELAY_MAX_ITER;
632d52085eSRasesh Mody #ifndef ASIC_ONLY
642d52085eSRasesh Mody 	if (CHIP_REV_IS_EMUL(p_hwfn->p_dev) && sleep_between_iter)
652d52085eSRasesh Mody 		iter_cnt *= 5;
662d52085eSRasesh Mody #endif
6722d07d93SRasesh Mody 
6822d07d93SRasesh Mody 	while (iter_cnt--) {
6922d07d93SRasesh Mody 		OSAL_POLL_MODE_DPC(p_hwfn);
7022d07d93SRasesh Mody 		OSAL_SMP_RMB(p_hwfn->p_dev);
7122d07d93SRasesh Mody 		if (comp_done->done == 1) {
7222d07d93SRasesh Mody 			if (p_fw_ret)
7322d07d93SRasesh Mody 				*p_fw_ret = comp_done->fw_return_code;
7422d07d93SRasesh Mody 			return ECORE_SUCCESS;
7522d07d93SRasesh Mody 		}
7622d07d93SRasesh Mody 
7722d07d93SRasesh Mody 		if (sleep_between_iter)
7822d07d93SRasesh Mody 			OSAL_MSLEEP(SPQ_BLOCK_SLEEP_MS);
7922d07d93SRasesh Mody 		else
8022d07d93SRasesh Mody 			OSAL_UDELAY(SPQ_BLOCK_DELAY_US);
8122d07d93SRasesh Mody 	}
8222d07d93SRasesh Mody 
8322d07d93SRasesh Mody 	return ECORE_TIMEOUT;
8422d07d93SRasesh Mody }
8522d07d93SRasesh Mody 
ecore_spq_block(struct ecore_hwfn * p_hwfn,struct ecore_spq_entry * p_ent,u8 * p_fw_ret,bool skip_quick_poll)86ec94dbc5SRasesh Mody static enum _ecore_status_t ecore_spq_block(struct ecore_hwfn *p_hwfn,
87ec94dbc5SRasesh Mody 					    struct ecore_spq_entry *p_ent,
8822d07d93SRasesh Mody 					    u8 *p_fw_ret, bool skip_quick_poll)
89ec94dbc5SRasesh Mody {
90ec94dbc5SRasesh Mody 	struct ecore_spq_comp_done *comp_done;
91739a5b2fSRasesh Mody 	struct ecore_ptt *p_ptt;
92ec94dbc5SRasesh Mody 	enum _ecore_status_t rc;
93ec94dbc5SRasesh Mody 
9422d07d93SRasesh Mody 	/* A relatively short polling period w/o sleeping, to allow the FW to
9522d07d93SRasesh Mody 	 * complete the ramrod and thus possibly to avoid the following sleeps.
9622d07d93SRasesh Mody 	 */
9722d07d93SRasesh Mody 	if (!skip_quick_poll) {
9822d07d93SRasesh Mody 		rc = __ecore_spq_block(p_hwfn, p_ent, p_fw_ret, false);
9922d07d93SRasesh Mody 		if (rc == ECORE_SUCCESS)
100ec94dbc5SRasesh Mody 			return ECORE_SUCCESS;
101ec94dbc5SRasesh Mody 	}
10222d07d93SRasesh Mody 
10322d07d93SRasesh Mody 	/* Move to polling with a sleeping period between iterations */
10422d07d93SRasesh Mody 	rc = __ecore_spq_block(p_hwfn, p_ent, p_fw_ret, true);
10522d07d93SRasesh Mody 	if (rc == ECORE_SUCCESS)
10622d07d93SRasesh Mody 		return ECORE_SUCCESS;
107ec94dbc5SRasesh Mody 
108739a5b2fSRasesh Mody 	p_ptt = ecore_ptt_acquire(p_hwfn);
109739a5b2fSRasesh Mody 	if (!p_ptt)
110739a5b2fSRasesh Mody 		return ECORE_AGAIN;
111739a5b2fSRasesh Mody 
112ec94dbc5SRasesh Mody 	DP_INFO(p_hwfn, "Ramrod is stuck, requesting MCP drain\n");
113739a5b2fSRasesh Mody 	rc = ecore_mcp_drain(p_hwfn, p_ptt);
114739a5b2fSRasesh Mody 	ecore_ptt_release(p_hwfn, p_ptt);
11522d07d93SRasesh Mody 	if (rc != ECORE_SUCCESS) {
116ec94dbc5SRasesh Mody 		DP_NOTICE(p_hwfn, true, "MCP drain failed\n");
11722d07d93SRasesh Mody 		goto err;
11822d07d93SRasesh Mody 	}
119ec94dbc5SRasesh Mody 
120ec94dbc5SRasesh Mody 	/* Retry after drain */
12122d07d93SRasesh Mody 	rc = __ecore_spq_block(p_hwfn, p_ent, p_fw_ret, true);
12222d07d93SRasesh Mody 	if (rc == ECORE_SUCCESS)
12322d07d93SRasesh Mody 		return ECORE_SUCCESS;
12422d07d93SRasesh Mody 
12522d07d93SRasesh Mody 	comp_done = (struct ecore_spq_comp_done *)p_ent->comp_cb.cookie;
126ec94dbc5SRasesh Mody 	if (comp_done->done == 1) {
127ec94dbc5SRasesh Mody 		if (p_fw_ret)
128ec94dbc5SRasesh Mody 			*p_fw_ret = comp_done->fw_return_code;
129ec94dbc5SRasesh Mody 		return ECORE_SUCCESS;
130ec94dbc5SRasesh Mody 	}
13122d07d93SRasesh Mody err:
132ec94dbc5SRasesh Mody 	DP_NOTICE(p_hwfn, true,
133ec94dbc5SRasesh Mody 		  "Ramrod is stuck [CID %08x cmd %02x proto %02x echo %04x]\n",
134ec94dbc5SRasesh Mody 		  OSAL_LE32_TO_CPU(p_ent->elem.hdr.cid),
135ec94dbc5SRasesh Mody 		  p_ent->elem.hdr.cmd_id, p_ent->elem.hdr.protocol_id,
136ec94dbc5SRasesh Mody 		  OSAL_LE16_TO_CPU(p_ent->elem.hdr.echo));
137ec94dbc5SRasesh Mody 
138ec94dbc5SRasesh Mody 	ecore_hw_err_notify(p_hwfn, ECORE_HW_ERR_RAMROD_FAIL);
139ec94dbc5SRasesh Mody 
140ec94dbc5SRasesh Mody 	return ECORE_BUSY;
141ec94dbc5SRasesh Mody }
142ec94dbc5SRasesh Mody 
ecore_set_spq_block_timeout(struct ecore_hwfn * p_hwfn,u32 spq_timeout_ms)1432d52085eSRasesh Mody void ecore_set_spq_block_timeout(struct ecore_hwfn *p_hwfn,
1442d52085eSRasesh Mody 				 u32 spq_timeout_ms)
1452d52085eSRasesh Mody {
1462d52085eSRasesh Mody 	p_hwfn->p_spq->block_sleep_max_iter = spq_timeout_ms ?
1472d52085eSRasesh Mody 		spq_timeout_ms / SPQ_BLOCK_SLEEP_MS :
1482d52085eSRasesh Mody 		SPQ_BLOCK_SLEEP_MAX_ITER;
1492d52085eSRasesh Mody }
1502d52085eSRasesh Mody 
151ec94dbc5SRasesh Mody /***************************************************************************
152ec94dbc5SRasesh Mody  * SPQ entries inner API
153ec94dbc5SRasesh Mody  ***************************************************************************/
154ec94dbc5SRasesh Mody static enum _ecore_status_t
ecore_spq_fill_entry(struct ecore_hwfn * p_hwfn,struct ecore_spq_entry * p_ent)155ec94dbc5SRasesh Mody ecore_spq_fill_entry(struct ecore_hwfn *p_hwfn, struct ecore_spq_entry *p_ent)
156ec94dbc5SRasesh Mody {
157ec94dbc5SRasesh Mody 	p_ent->flags = 0;
158ec94dbc5SRasesh Mody 
159ec94dbc5SRasesh Mody 	switch (p_ent->comp_mode) {
160ec94dbc5SRasesh Mody 	case ECORE_SPQ_MODE_EBLOCK:
161ec94dbc5SRasesh Mody 	case ECORE_SPQ_MODE_BLOCK:
162ec94dbc5SRasesh Mody 		p_ent->comp_cb.function = ecore_spq_blocking_cb;
163ec94dbc5SRasesh Mody 		break;
164ec94dbc5SRasesh Mody 	case ECORE_SPQ_MODE_CB:
165ec94dbc5SRasesh Mody 		break;
166ec94dbc5SRasesh Mody 	default:
167ec94dbc5SRasesh Mody 		DP_NOTICE(p_hwfn, true, "Unknown SPQE completion mode %d\n",
168ec94dbc5SRasesh Mody 			  p_ent->comp_mode);
169ec94dbc5SRasesh Mody 		return ECORE_INVAL;
170ec94dbc5SRasesh Mody 	}
171ec94dbc5SRasesh Mody 
172ec94dbc5SRasesh Mody 	DP_VERBOSE(p_hwfn, ECORE_MSG_SPQ,
173ec94dbc5SRasesh Mody 		   "Ramrod header: [CID 0x%08x CMD 0x%02x protocol 0x%02x]"
174ec94dbc5SRasesh Mody 		   " Data pointer: [%08x:%08x] Completion Mode: %s\n",
175ec94dbc5SRasesh Mody 		   p_ent->elem.hdr.cid, p_ent->elem.hdr.cmd_id,
176ec94dbc5SRasesh Mody 		   p_ent->elem.hdr.protocol_id,
177ec94dbc5SRasesh Mody 		   p_ent->elem.data_ptr.hi, p_ent->elem.data_ptr.lo,
178ec94dbc5SRasesh Mody 		   D_TRINE(p_ent->comp_mode, ECORE_SPQ_MODE_EBLOCK,
179ec94dbc5SRasesh Mody 			   ECORE_SPQ_MODE_BLOCK, "MODE_EBLOCK", "MODE_BLOCK",
180ec94dbc5SRasesh Mody 			   "MODE_CB"));
181ec94dbc5SRasesh Mody 
182ec94dbc5SRasesh Mody 	return ECORE_SUCCESS;
183ec94dbc5SRasesh Mody }
184ec94dbc5SRasesh Mody 
185ec94dbc5SRasesh Mody /***************************************************************************
186ec94dbc5SRasesh Mody  * HSI access
187ec94dbc5SRasesh Mody  ***************************************************************************/
1883b307c55SRasesh Mody 
1893b307c55SRasesh Mody #define XSTORM_CORE_CONN_AG_CTX_DQ_CF_EN_MASK			0x1
1903b307c55SRasesh Mody #define XSTORM_CORE_CONN_AG_CTX_DQ_CF_EN_SHIFT			0
1913b307c55SRasesh Mody #define XSTORM_CORE_CONN_AG_CTX_DQ_CF_ACTIVE_MASK		0x1
1923b307c55SRasesh Mody #define XSTORM_CORE_CONN_AG_CTX_DQ_CF_ACTIVE_SHIFT		7
1933b307c55SRasesh Mody #define XSTORM_CORE_CONN_AG_CTX_SLOW_PATH_EN_MASK		0x1
1943b307c55SRasesh Mody #define XSTORM_CORE_CONN_AG_CTX_SLOW_PATH_EN_SHIFT		4
1953b307c55SRasesh Mody #define XSTORM_CORE_CONN_AG_CTX_CONSOLID_PROD_CF_EN_MASK	0x1
1963b307c55SRasesh Mody #define XSTORM_CORE_CONN_AG_CTX_CONSOLID_PROD_CF_EN_SHIFT	6
1973b307c55SRasesh Mody 
ecore_spq_hw_initialize(struct ecore_hwfn * p_hwfn,struct ecore_spq * p_spq)198ec94dbc5SRasesh Mody static void ecore_spq_hw_initialize(struct ecore_hwfn *p_hwfn,
199ec94dbc5SRasesh Mody 				    struct ecore_spq *p_spq)
200ec94dbc5SRasesh Mody {
2013b307c55SRasesh Mody 	__le32 *p_spq_base_lo, *p_spq_base_hi;
2023b307c55SRasesh Mody 	struct regpair *p_consolid_base_addr;
2033b307c55SRasesh Mody 	u8 *p_flags1, *p_flags9, *p_flags10;
20452fa735cSRasesh Mody 	struct core_conn_context *p_cxt;
205c68f27a2SRasesh Mody 	struct ecore_cxt_info cxt_info;
2063b307c55SRasesh Mody 	u32 core_conn_context_size;
2073b307c55SRasesh Mody 	__le16 *p_physical_q0;
2085ef41193SRasesh Mody 	u16 physical_q;
209c68f27a2SRasesh Mody 	enum _ecore_status_t rc;
210ec94dbc5SRasesh Mody 
211ec94dbc5SRasesh Mody 	cxt_info.iid = p_spq->cid;
212ec94dbc5SRasesh Mody 
213ec94dbc5SRasesh Mody 	rc = ecore_cxt_get_cid_info(p_hwfn, &cxt_info);
214ec94dbc5SRasesh Mody 
2153b307c55SRasesh Mody 	if (rc != ECORE_SUCCESS) {
2169455b556SRasesh Mody 		DP_NOTICE(p_hwfn, true, "Cannot find context info for cid=%d\n",
217ec94dbc5SRasesh Mody 			  p_spq->cid);
218ec94dbc5SRasesh Mody 		return;
219ec94dbc5SRasesh Mody 	}
220ec94dbc5SRasesh Mody 
221ec94dbc5SRasesh Mody 	p_cxt = cxt_info.p_cxt;
2223b307c55SRasesh Mody 	core_conn_context_size = sizeof(*p_cxt);
2233b307c55SRasesh Mody 	p_flags1 = &p_cxt->xstorm_ag_context.flags1;
2243b307c55SRasesh Mody 	p_flags9 = &p_cxt->xstorm_ag_context.flags9;
2253b307c55SRasesh Mody 	p_flags10 = &p_cxt->xstorm_ag_context.flags10;
2263b307c55SRasesh Mody 	p_physical_q0 = &p_cxt->xstorm_ag_context.physical_q0;
2273b307c55SRasesh Mody 	p_spq_base_lo = &p_cxt->xstorm_st_context.spq_base_lo;
2283b307c55SRasesh Mody 	p_spq_base_hi = &p_cxt->xstorm_st_context.spq_base_hi;
2293b307c55SRasesh Mody 	p_consolid_base_addr = &p_cxt->xstorm_st_context.consolid_base_addr;
230ec94dbc5SRasesh Mody 
23139f0eb3bSRasesh Mody 	/* @@@TBD we zero the context until we have ilt_reset implemented. */
2323b307c55SRasesh Mody 	OSAL_MEM_ZERO(p_cxt, core_conn_context_size);
23339f0eb3bSRasesh Mody 
2343b307c55SRasesh Mody 	SET_FIELD(*p_flags10, XSTORM_CORE_CONN_AG_CTX_DQ_CF_EN, 1);
2353b307c55SRasesh Mody 	SET_FIELD(*p_flags1, XSTORM_CORE_CONN_AG_CTX_DQ_CF_ACTIVE, 1);
2363b307c55SRasesh Mody 	SET_FIELD(*p_flags9, XSTORM_CORE_CONN_AG_CTX_CONSOLID_PROD_CF_EN, 1);
237ec94dbc5SRasesh Mody 
238ec94dbc5SRasesh Mody 	/* CDU validation - FIXME currently disabled */
239ec94dbc5SRasesh Mody 
240ec94dbc5SRasesh Mody 	/* QM physical queue */
2415ef41193SRasesh Mody 	physical_q = ecore_get_cm_pq_idx(p_hwfn, PQ_FLAGS_LB);
2423b307c55SRasesh Mody 	*p_physical_q0 = OSAL_CPU_TO_LE16(physical_q);
243ec94dbc5SRasesh Mody 
2443b307c55SRasesh Mody 	*p_spq_base_lo = DMA_LO_LE(p_spq->chain.p_phys_addr);
2453b307c55SRasesh Mody 	*p_spq_base_hi = DMA_HI_LE(p_spq->chain.p_phys_addr);
246ec94dbc5SRasesh Mody 
2473b307c55SRasesh Mody 	DMA_REGPAIR_LE(*p_consolid_base_addr,
24822d07d93SRasesh Mody 		       p_hwfn->p_consq->chain.p_phys_addr);
249ec94dbc5SRasesh Mody }
250ec94dbc5SRasesh Mody 
ecore_spq_hw_post(struct ecore_hwfn * p_hwfn,struct ecore_spq * p_spq,struct ecore_spq_entry * p_ent)251ec94dbc5SRasesh Mody static enum _ecore_status_t ecore_spq_hw_post(struct ecore_hwfn *p_hwfn,
252ec94dbc5SRasesh Mody 					      struct ecore_spq *p_spq,
253ec94dbc5SRasesh Mody 					      struct ecore_spq_entry *p_ent)
254ec94dbc5SRasesh Mody {
255ec94dbc5SRasesh Mody 	struct ecore_chain *p_chain = &p_hwfn->p_spq->chain;
256e916697fSRasesh Mody 	struct core_db_data *p_db_data = &p_spq->db_data;
257ec94dbc5SRasesh Mody 	u16 echo = ecore_chain_get_prod_idx(p_chain);
258ec94dbc5SRasesh Mody 	struct slow_path_element *elem;
259ec94dbc5SRasesh Mody 
260ec94dbc5SRasesh Mody 	p_ent->elem.hdr.echo = OSAL_CPU_TO_LE16(echo);
261ec94dbc5SRasesh Mody 	elem = ecore_chain_produce(p_chain);
262ec94dbc5SRasesh Mody 	if (!elem) {
263ec94dbc5SRasesh Mody 		DP_NOTICE(p_hwfn, true, "Failed to produce from SPQ chain\n");
264ec94dbc5SRasesh Mody 		return ECORE_INVAL;
265ec94dbc5SRasesh Mody 	}
266ec94dbc5SRasesh Mody 
267e916697fSRasesh Mody 	*elem = p_ent->elem;	/* Struct assignment */
268ec94dbc5SRasesh Mody 
269e916697fSRasesh Mody 	p_db_data->spq_prod =
270e916697fSRasesh Mody 		OSAL_CPU_TO_LE16(ecore_chain_get_prod_idx(p_chain));
271ec94dbc5SRasesh Mody 
272e916697fSRasesh Mody 	/* Make sure the SPQE is updated before the doorbell */
27322d07d93SRasesh Mody 	OSAL_WMB(p_hwfn->p_dev);
274ec94dbc5SRasesh Mody 
275e916697fSRasesh Mody 	DOORBELL(p_hwfn, p_spq->db_addr_offset, *(u32 *)p_db_data);
276ec94dbc5SRasesh Mody 
277e916697fSRasesh Mody 	/* Make sure doorbell is rang */
27822d07d93SRasesh Mody 	OSAL_WMB(p_hwfn->p_dev);
279ec94dbc5SRasesh Mody 
280ec94dbc5SRasesh Mody 	DP_VERBOSE(p_hwfn, ECORE_MSG_SPQ,
281ec94dbc5SRasesh Mody 		   "Doorbelled [0x%08x, CID 0x%08x] with Flags: %02x"
282ec94dbc5SRasesh Mody 		   " agg_params: %02x, prod: %04x\n",
283e916697fSRasesh Mody 		   p_spq->db_addr_offset, p_spq->cid, p_db_data->params,
284e916697fSRasesh Mody 		   p_db_data->agg_flags, ecore_chain_get_prod_idx(p_chain));
285ec94dbc5SRasesh Mody 
286ec94dbc5SRasesh Mody 	return ECORE_SUCCESS;
287ec94dbc5SRasesh Mody }
288ec94dbc5SRasesh Mody 
289ec94dbc5SRasesh Mody /***************************************************************************
290ec94dbc5SRasesh Mody  * Asynchronous events
291ec94dbc5SRasesh Mody  ***************************************************************************/
292ec94dbc5SRasesh Mody 
293ec94dbc5SRasesh Mody static enum _ecore_status_t
ecore_async_event_completion(struct ecore_hwfn * p_hwfn,struct event_ring_entry * p_eqe)294ec94dbc5SRasesh Mody ecore_async_event_completion(struct ecore_hwfn *p_hwfn,
295ec94dbc5SRasesh Mody 			     struct event_ring_entry *p_eqe)
296ec94dbc5SRasesh Mody {
2977f474588SRasesh Mody 	ecore_spq_async_comp_cb cb;
2989ed26bc7SRasesh Mody 	enum _ecore_status_t rc;
2997f474588SRasesh Mody 
300cbc23596SRasesh Mody 	if (p_eqe->protocol_id >= MAX_PROTOCOL_TYPE) {
301cbc23596SRasesh Mody 		DP_ERR(p_hwfn, "Wrong protocol: %d\n", p_eqe->protocol_id);
3027f474588SRasesh Mody 		return ECORE_INVAL;
303cbc23596SRasesh Mody 	}
3047f474588SRasesh Mody 
3057f474588SRasesh Mody 	cb = p_hwfn->p_spq->async_comp_cb[p_eqe->protocol_id];
3069ed26bc7SRasesh Mody 	if (!cb) {
307ec94dbc5SRasesh Mody 		DP_NOTICE(p_hwfn,
308ec94dbc5SRasesh Mody 			  true, "Unknown Async completion for protocol: %d\n",
309ec94dbc5SRasesh Mody 			  p_eqe->protocol_id);
310ec94dbc5SRasesh Mody 		return ECORE_INVAL;
311ec94dbc5SRasesh Mody 	}
3129ed26bc7SRasesh Mody 
3139ed26bc7SRasesh Mody 	rc = cb(p_hwfn, p_eqe->opcode, p_eqe->echo,
3149ed26bc7SRasesh Mody 		&p_eqe->data, p_eqe->fw_return_code);
3159ed26bc7SRasesh Mody 	if (rc != ECORE_SUCCESS)
3169ed26bc7SRasesh Mody 		DP_NOTICE(p_hwfn, true,
3179ed26bc7SRasesh Mody 			  "Async completion callback failed, rc = %d [opcode %x, echo %x, fw_return_code %x]",
3189ed26bc7SRasesh Mody 			  rc, p_eqe->opcode, p_eqe->echo,
3199ed26bc7SRasesh Mody 			  p_eqe->fw_return_code);
3209ed26bc7SRasesh Mody 
3219ed26bc7SRasesh Mody 	return rc;
322ec94dbc5SRasesh Mody }
323ec94dbc5SRasesh Mody 
3247f474588SRasesh Mody enum _ecore_status_t
ecore_spq_register_async_cb(struct ecore_hwfn * p_hwfn,enum protocol_type protocol_id,ecore_spq_async_comp_cb cb)3257f474588SRasesh Mody ecore_spq_register_async_cb(struct ecore_hwfn *p_hwfn,
3267f474588SRasesh Mody 			    enum protocol_type protocol_id,
3277f474588SRasesh Mody 			    ecore_spq_async_comp_cb cb)
3287f474588SRasesh Mody {
3297f474588SRasesh Mody 	if (!p_hwfn->p_spq || (protocol_id >= MAX_PROTOCOL_TYPE))
3307f474588SRasesh Mody 		return ECORE_INVAL;
3317f474588SRasesh Mody 
3327f474588SRasesh Mody 	p_hwfn->p_spq->async_comp_cb[protocol_id] = cb;
3337f474588SRasesh Mody 	return ECORE_SUCCESS;
3347f474588SRasesh Mody }
3357f474588SRasesh Mody 
3367f474588SRasesh Mody void
ecore_spq_unregister_async_cb(struct ecore_hwfn * p_hwfn,enum protocol_type protocol_id)3377f474588SRasesh Mody ecore_spq_unregister_async_cb(struct ecore_hwfn *p_hwfn,
3387f474588SRasesh Mody 			      enum protocol_type protocol_id)
3397f474588SRasesh Mody {
3407f474588SRasesh Mody 	if (!p_hwfn->p_spq || (protocol_id >= MAX_PROTOCOL_TYPE))
3417f474588SRasesh Mody 		return;
3427f474588SRasesh Mody 
3437f474588SRasesh Mody 	p_hwfn->p_spq->async_comp_cb[protocol_id] = OSAL_NULL;
3447f474588SRasesh Mody }
3457f474588SRasesh Mody 
346ec94dbc5SRasesh Mody /***************************************************************************
347ec94dbc5SRasesh Mody  * EQ API
348ec94dbc5SRasesh Mody  ***************************************************************************/
ecore_eq_prod_update(struct ecore_hwfn * p_hwfn,u16 prod)349ec94dbc5SRasesh Mody void ecore_eq_prod_update(struct ecore_hwfn *p_hwfn, u16 prod)
350ec94dbc5SRasesh Mody {
351ec94dbc5SRasesh Mody 	u32 addr = GTT_BAR0_MAP_REG_USDM_RAM +
352ec94dbc5SRasesh Mody 	    USTORM_EQE_CONS_OFFSET(p_hwfn->rel_pf_id);
353ec94dbc5SRasesh Mody 
354ec94dbc5SRasesh Mody 	REG_WR16(p_hwfn, addr, prod);
355ec94dbc5SRasesh Mody 
356ec94dbc5SRasesh Mody 	/* keep prod updates ordered */
357ec94dbc5SRasesh Mody 	OSAL_MMIOWB(p_hwfn->p_dev);
358ec94dbc5SRasesh Mody }
359ec94dbc5SRasesh Mody 
ecore_eq_completion(struct ecore_hwfn * p_hwfn,void * cookie)360ec94dbc5SRasesh Mody enum _ecore_status_t ecore_eq_completion(struct ecore_hwfn *p_hwfn,
361ec94dbc5SRasesh Mody 					 void *cookie)
362ec94dbc5SRasesh Mody {
363ec94dbc5SRasesh Mody 	struct ecore_eq *p_eq = cookie;
364ec94dbc5SRasesh Mody 	struct ecore_chain *p_chain = &p_eq->chain;
365cbc23596SRasesh Mody 	u16 fw_cons_idx             = 0;
3669ed26bc7SRasesh Mody 	enum _ecore_status_t rc = ECORE_SUCCESS;
367ec94dbc5SRasesh Mody 
368cbc23596SRasesh Mody 	if (!p_hwfn->p_spq) {
369cbc23596SRasesh Mody 		DP_ERR(p_hwfn, "Unexpected NULL p_spq\n");
370cbc23596SRasesh Mody 		return ECORE_INVAL;
371cbc23596SRasesh Mody 	}
372cbc23596SRasesh Mody 
373ec94dbc5SRasesh Mody 	/* take a snapshot of the FW consumer */
374cbc23596SRasesh Mody 	fw_cons_idx = OSAL_LE16_TO_CPU(*p_eq->p_fw_cons);
375ec94dbc5SRasesh Mody 
376ec94dbc5SRasesh Mody 	DP_VERBOSE(p_hwfn, ECORE_MSG_SPQ, "fw_cons_idx %x\n", fw_cons_idx);
377ec94dbc5SRasesh Mody 
378ec94dbc5SRasesh Mody 	/* Need to guarantee the fw_cons index we use points to a usuable
379ec94dbc5SRasesh Mody 	 * element (to comply with our chain), so our macros would comply
380ec94dbc5SRasesh Mody 	 */
381ec94dbc5SRasesh Mody 	if ((fw_cons_idx & ecore_chain_get_usable_per_page(p_chain)) ==
382ec94dbc5SRasesh Mody 	    ecore_chain_get_usable_per_page(p_chain)) {
383ec94dbc5SRasesh Mody 		fw_cons_idx += ecore_chain_get_unusable_per_page(p_chain);
384ec94dbc5SRasesh Mody 	}
385ec94dbc5SRasesh Mody 
386ec94dbc5SRasesh Mody 	/* Complete current segment of eq entries */
387ec94dbc5SRasesh Mody 	while (fw_cons_idx != ecore_chain_get_cons_idx(p_chain)) {
388ec94dbc5SRasesh Mody 		struct event_ring_entry *p_eqe = ecore_chain_consume(p_chain);
389ec94dbc5SRasesh Mody 		if (!p_eqe) {
3909ed26bc7SRasesh Mody 			DP_ERR(p_hwfn,
3919ed26bc7SRasesh Mody 			       "Unexpected NULL chain consumer entry\n");
392ec94dbc5SRasesh Mody 			break;
393ec94dbc5SRasesh Mody 		}
394ec94dbc5SRasesh Mody 
395ec94dbc5SRasesh Mody 		DP_VERBOSE(p_hwfn, ECORE_MSG_SPQ,
39622d07d93SRasesh Mody 			   "op %x prot %x res0 %x echo %x fwret %x flags %x\n",
39722d07d93SRasesh Mody 			   p_eqe->opcode,	     /* Event Opcode */
398ec94dbc5SRasesh Mody 			   p_eqe->protocol_id,	/* Event Protocol ID */
399ec94dbc5SRasesh Mody 			   p_eqe->reserved0,	/* Reserved */
40022d07d93SRasesh Mody 			   /* Echo value from ramrod data on the host */
401ec94dbc5SRasesh Mody 			   OSAL_LE16_TO_CPU(p_eqe->echo),
402ec94dbc5SRasesh Mody 			   p_eqe->fw_return_code,    /* FW return code for SP
403ec94dbc5SRasesh Mody 						      * ramrods
404ec94dbc5SRasesh Mody 						      */
405ec94dbc5SRasesh Mody 			   p_eqe->flags);
406ec94dbc5SRasesh Mody 
4079ed26bc7SRasesh Mody 		if (GET_FIELD(p_eqe->flags, EVENT_RING_ENTRY_ASYNC))
4089ed26bc7SRasesh Mody 			ecore_async_event_completion(p_hwfn, p_eqe);
4099ed26bc7SRasesh Mody 		else
4109ed26bc7SRasesh Mody 			ecore_spq_completion(p_hwfn,
411ec94dbc5SRasesh Mody 					     p_eqe->echo,
412ec94dbc5SRasesh Mody 					     p_eqe->fw_return_code,
4139ed26bc7SRasesh Mody 					     &p_eqe->data);
414ec94dbc5SRasesh Mody 
415ec94dbc5SRasesh Mody 		ecore_chain_recycle_consumed(p_chain);
416ec94dbc5SRasesh Mody 	}
417ec94dbc5SRasesh Mody 
418ec94dbc5SRasesh Mody 	ecore_eq_prod_update(p_hwfn, ecore_chain_get_prod_idx(p_chain));
419ec94dbc5SRasesh Mody 
420ec94dbc5SRasesh Mody 	return rc;
421ec94dbc5SRasesh Mody }
422ec94dbc5SRasesh Mody 
ecore_eq_alloc(struct ecore_hwfn * p_hwfn,u16 num_elem)423d411a2b5SRasesh Mody enum _ecore_status_t ecore_eq_alloc(struct ecore_hwfn *p_hwfn, u16 num_elem)
424ec94dbc5SRasesh Mody {
425ec94dbc5SRasesh Mody 	struct ecore_eq *p_eq;
426ec94dbc5SRasesh Mody 
427ec94dbc5SRasesh Mody 	/* Allocate EQ struct */
42822d07d93SRasesh Mody 	p_eq = OSAL_ZALLOC(p_hwfn->p_dev, GFP_KERNEL, sizeof(*p_eq));
429ec94dbc5SRasesh Mody 	if (!p_eq) {
43098abf84eSRasesh Mody 		DP_NOTICE(p_hwfn, false,
431ec94dbc5SRasesh Mody 			  "Failed to allocate `struct ecore_eq'\n");
432d411a2b5SRasesh Mody 		return ECORE_NOMEM;
433ec94dbc5SRasesh Mody 	}
434ec94dbc5SRasesh Mody 
435ec94dbc5SRasesh Mody 	/* Allocate and initialize EQ chain*/
436ec94dbc5SRasesh Mody 	if (ecore_chain_alloc(p_hwfn->p_dev,
437ec94dbc5SRasesh Mody 			      ECORE_CHAIN_USE_TO_PRODUCE,
438ec94dbc5SRasesh Mody 			      ECORE_CHAIN_MODE_PBL,
439ec94dbc5SRasesh Mody 			      ECORE_CHAIN_CNT_TYPE_U16,
440ec94dbc5SRasesh Mody 			      num_elem,
441fe96c1e8SRasesh Mody 			      sizeof(union event_ring_element),
442d411a2b5SRasesh Mody 			      &p_eq->chain, OSAL_NULL) != ECORE_SUCCESS) {
44398abf84eSRasesh Mody 		DP_NOTICE(p_hwfn, false, "Failed to allocate eq chain\n");
444ec94dbc5SRasesh Mody 		goto eq_allocate_fail;
445ec94dbc5SRasesh Mody 	}
446ec94dbc5SRasesh Mody 
447ec94dbc5SRasesh Mody 	/* register EQ completion on the SP SB */
448ababb520SRasesh Mody 	ecore_int_register_cb(p_hwfn, ecore_eq_completion,
449ec94dbc5SRasesh Mody 			      p_eq, &p_eq->eq_sb_index, &p_eq->p_fw_cons);
450ec94dbc5SRasesh Mody 
451d411a2b5SRasesh Mody 	p_hwfn->p_eq = p_eq;
452d411a2b5SRasesh Mody 	return ECORE_SUCCESS;
453ec94dbc5SRasesh Mody 
454ec94dbc5SRasesh Mody eq_allocate_fail:
455ec94dbc5SRasesh Mody 	OSAL_FREE(p_hwfn->p_dev, p_eq);
456d411a2b5SRasesh Mody 	return ECORE_NOMEM;
457d411a2b5SRasesh Mody }
458d411a2b5SRasesh Mody 
ecore_eq_setup(struct ecore_hwfn * p_hwfn)459d411a2b5SRasesh Mody void ecore_eq_setup(struct ecore_hwfn *p_hwfn)
460d411a2b5SRasesh Mody {
461d411a2b5SRasesh Mody 	ecore_chain_reset(&p_hwfn->p_eq->chain);
462d411a2b5SRasesh Mody }
463d411a2b5SRasesh Mody 
ecore_eq_free(struct ecore_hwfn * p_hwfn)464d411a2b5SRasesh Mody void ecore_eq_free(struct ecore_hwfn *p_hwfn)
465d411a2b5SRasesh Mody {
466d411a2b5SRasesh Mody 	if (!p_hwfn->p_eq)
467d411a2b5SRasesh Mody 		return;
468d411a2b5SRasesh Mody 
469d411a2b5SRasesh Mody 	ecore_chain_free(p_hwfn->p_dev, &p_hwfn->p_eq->chain);
470d411a2b5SRasesh Mody 
471d411a2b5SRasesh Mody 	OSAL_FREE(p_hwfn->p_dev, p_hwfn->p_eq);
472d411a2b5SRasesh Mody 	p_hwfn->p_eq = OSAL_NULL;
473ec94dbc5SRasesh Mody }
474ec94dbc5SRasesh Mody 
475ec94dbc5SRasesh Mody /***************************************************************************
476ec94dbc5SRasesh Mody * CQE API - manipulate EQ functionality
477ec94dbc5SRasesh Mody ***************************************************************************/
ecore_cqe_completion(struct ecore_hwfn * p_hwfn,struct eth_slow_path_rx_cqe * cqe,enum protocol_type protocol)478ec94dbc5SRasesh Mody static enum _ecore_status_t ecore_cqe_completion(struct ecore_hwfn *p_hwfn,
479ec94dbc5SRasesh Mody 						 struct eth_slow_path_rx_cqe
480ec94dbc5SRasesh Mody 						 *cqe,
481ec94dbc5SRasesh Mody 						 enum protocol_type protocol)
482ec94dbc5SRasesh Mody {
48386a2265eSRasesh Mody 	if (IS_VF(p_hwfn->p_dev))
48486a2265eSRasesh Mody 		return OSAL_VF_CQE_COMPLETION(p_hwfn, cqe, protocol);
48586a2265eSRasesh Mody 
486ec94dbc5SRasesh Mody 	/* @@@tmp - it's possible we'll eventually want to handle some
487ec94dbc5SRasesh Mody 	 * actual commands that can arrive here, but for now this is only
488ec94dbc5SRasesh Mody 	 * used to complete the ramrod using the echo value on the cqe
489ec94dbc5SRasesh Mody 	 */
490ec94dbc5SRasesh Mody 	return ecore_spq_completion(p_hwfn, cqe->echo, 0, OSAL_NULL);
491ec94dbc5SRasesh Mody }
492ec94dbc5SRasesh Mody 
ecore_eth_cqe_completion(struct ecore_hwfn * p_hwfn,struct eth_slow_path_rx_cqe * cqe)493ec94dbc5SRasesh Mody enum _ecore_status_t ecore_eth_cqe_completion(struct ecore_hwfn *p_hwfn,
494ec94dbc5SRasesh Mody 					      struct eth_slow_path_rx_cqe *cqe)
495ec94dbc5SRasesh Mody {
496ec94dbc5SRasesh Mody 	enum _ecore_status_t rc;
497ec94dbc5SRasesh Mody 
498ec94dbc5SRasesh Mody 	rc = ecore_cqe_completion(p_hwfn, cqe, PROTOCOLID_ETH);
499ec94dbc5SRasesh Mody 	if (rc) {
500ec94dbc5SRasesh Mody 		DP_NOTICE(p_hwfn, true,
501ec94dbc5SRasesh Mody 			  "Failed to handle RXQ CQE [cmd 0x%02x]\n",
502ec94dbc5SRasesh Mody 			  cqe->ramrod_cmd_id);
503ec94dbc5SRasesh Mody 	}
504ec94dbc5SRasesh Mody 
505ec94dbc5SRasesh Mody 	return rc;
506ec94dbc5SRasesh Mody }
507ec94dbc5SRasesh Mody 
508ec94dbc5SRasesh Mody /***************************************************************************
509ec94dbc5SRasesh Mody  * Slow hwfn Queue (spq)
510ec94dbc5SRasesh Mody  ***************************************************************************/
ecore_spq_setup(struct ecore_hwfn * p_hwfn)511ec94dbc5SRasesh Mody void ecore_spq_setup(struct ecore_hwfn *p_hwfn)
512ec94dbc5SRasesh Mody {
513ec94dbc5SRasesh Mody 	struct ecore_spq *p_spq = p_hwfn->p_spq;
5149455b556SRasesh Mody 	struct ecore_spq_entry *p_virt = OSAL_NULL;
515e916697fSRasesh Mody 	struct core_db_data *p_db_data;
516e916697fSRasesh Mody 	void OSAL_IOMEM *db_addr;
517ec94dbc5SRasesh Mody 	dma_addr_t p_phys = 0;
518ec94dbc5SRasesh Mody 	u32 i, capacity;
519e916697fSRasesh Mody 	enum _ecore_status_t rc;
520ec94dbc5SRasesh Mody 
521ec94dbc5SRasesh Mody 	OSAL_LIST_INIT(&p_spq->pending);
522ec94dbc5SRasesh Mody 	OSAL_LIST_INIT(&p_spq->completion_pending);
523ec94dbc5SRasesh Mody 	OSAL_LIST_INIT(&p_spq->free_pool);
524ec94dbc5SRasesh Mody 	OSAL_LIST_INIT(&p_spq->unlimited_pending);
525ec94dbc5SRasesh Mody 	OSAL_SPIN_LOCK_INIT(&p_spq->lock);
526ec94dbc5SRasesh Mody 
527ec94dbc5SRasesh Mody 	/* SPQ empty pool */
528ec94dbc5SRasesh Mody 	p_phys = p_spq->p_phys + OFFSETOF(struct ecore_spq_entry, ramrod);
529ec94dbc5SRasesh Mody 	p_virt = p_spq->p_virt;
530ec94dbc5SRasesh Mody 
531ec94dbc5SRasesh Mody 	capacity = ecore_chain_get_capacity(&p_spq->chain);
532ec94dbc5SRasesh Mody 	for (i = 0; i < capacity; i++) {
53322d07d93SRasesh Mody 		DMA_REGPAIR_LE(p_virt->elem.data_ptr, p_phys);
534ec94dbc5SRasesh Mody 
535ec94dbc5SRasesh Mody 		OSAL_LIST_PUSH_TAIL(&p_virt->list, &p_spq->free_pool);
536ec94dbc5SRasesh Mody 
537ec94dbc5SRasesh Mody 		p_virt++;
538ec94dbc5SRasesh Mody 		p_phys += sizeof(struct ecore_spq_entry);
539ec94dbc5SRasesh Mody 	}
540ec94dbc5SRasesh Mody 
541ec94dbc5SRasesh Mody 	/* Statistics */
542ec94dbc5SRasesh Mody 	p_spq->normal_count = 0;
543ec94dbc5SRasesh Mody 	p_spq->comp_count = 0;
544ec94dbc5SRasesh Mody 	p_spq->comp_sent_count = 0;
545ec94dbc5SRasesh Mody 	p_spq->unlimited_pending_count = 0;
546ec94dbc5SRasesh Mody 
547ec94dbc5SRasesh Mody 	OSAL_MEM_ZERO(p_spq->p_comp_bitmap,
548ec94dbc5SRasesh Mody 		      SPQ_COMP_BMAP_SIZE * sizeof(unsigned long));
549ec94dbc5SRasesh Mody 	p_spq->comp_bitmap_idx = 0;
550ec94dbc5SRasesh Mody 
551ec94dbc5SRasesh Mody 	/* SPQ cid, cannot fail */
552ec94dbc5SRasesh Mody 	ecore_cxt_acquire_cid(p_hwfn, PROTOCOLID_CORE, &p_spq->cid);
553ec94dbc5SRasesh Mody 	ecore_spq_hw_initialize(p_hwfn, p_spq);
554ec94dbc5SRasesh Mody 
555ec94dbc5SRasesh Mody 	/* reset the chain itself */
556ec94dbc5SRasesh Mody 	ecore_chain_reset(&p_spq->chain);
557e916697fSRasesh Mody 
558e916697fSRasesh Mody 	/* Initialize the address/data of the SPQ doorbell */
559e916697fSRasesh Mody 	p_spq->db_addr_offset = DB_ADDR(p_spq->cid, DQ_DEMS_LEGACY);
560e916697fSRasesh Mody 	p_db_data = &p_spq->db_data;
561e916697fSRasesh Mody 	OSAL_MEM_ZERO(p_db_data, sizeof(*p_db_data));
562e916697fSRasesh Mody 	SET_FIELD(p_db_data->params, CORE_DB_DATA_DEST, DB_DEST_XCM);
563e916697fSRasesh Mody 	SET_FIELD(p_db_data->params, CORE_DB_DATA_AGG_CMD, DB_AGG_CMD_MAX);
564e916697fSRasesh Mody 	SET_FIELD(p_db_data->params, CORE_DB_DATA_AGG_VAL_SEL,
565e916697fSRasesh Mody 		  DQ_XCM_CORE_SPQ_PROD_CMD);
566e916697fSRasesh Mody 	p_db_data->agg_flags = DQ_XCM_CORE_DQ_CF_CMD;
567e916697fSRasesh Mody 
568e916697fSRasesh Mody 	/* Register the SPQ doorbell with the doorbell recovery mechanism */
569e916697fSRasesh Mody 	db_addr = (void *)((u8 *)p_hwfn->doorbells + p_spq->db_addr_offset);
570e916697fSRasesh Mody 	rc = ecore_db_recovery_add(p_hwfn->p_dev, db_addr, &p_spq->db_data,
571e916697fSRasesh Mody 				   DB_REC_WIDTH_32B, DB_REC_KERNEL);
572e916697fSRasesh Mody 	if (rc != ECORE_SUCCESS)
573e916697fSRasesh Mody 		DP_INFO(p_hwfn,
574e916697fSRasesh Mody 			"Failed to register the SPQ doorbell with the doorbell recovery mechanism\n");
575ec94dbc5SRasesh Mody }
576ec94dbc5SRasesh Mody 
ecore_spq_alloc(struct ecore_hwfn * p_hwfn)577ec94dbc5SRasesh Mody enum _ecore_status_t ecore_spq_alloc(struct ecore_hwfn *p_hwfn)
578ec94dbc5SRasesh Mody {
579ec94dbc5SRasesh Mody 	struct ecore_spq_entry *p_virt = OSAL_NULL;
580ec94dbc5SRasesh Mody 	struct ecore_spq *p_spq = OSAL_NULL;
581ec94dbc5SRasesh Mody 	dma_addr_t p_phys = 0;
582ec94dbc5SRasesh Mody 	u32 capacity;
583ec94dbc5SRasesh Mody 
584ec94dbc5SRasesh Mody 	/* SPQ struct */
585ec94dbc5SRasesh Mody 	p_spq =
586ec94dbc5SRasesh Mody 	    OSAL_ZALLOC(p_hwfn->p_dev, GFP_KERNEL, sizeof(struct ecore_spq));
587ec94dbc5SRasesh Mody 	if (!p_spq) {
58898abf84eSRasesh Mody 		DP_NOTICE(p_hwfn, false, "Failed to allocate `struct ecore_spq'\n");
589ec94dbc5SRasesh Mody 		return ECORE_NOMEM;
590ec94dbc5SRasesh Mody 	}
591ec94dbc5SRasesh Mody 
592ec94dbc5SRasesh Mody 	/* SPQ ring  */
593fe96c1e8SRasesh Mody 	if (ecore_chain_alloc(p_hwfn->p_dev,
594fe96c1e8SRasesh Mody 			      ECORE_CHAIN_USE_TO_PRODUCE,
595fe96c1e8SRasesh Mody 			      ECORE_CHAIN_MODE_SINGLE,
596fe96c1e8SRasesh Mody 			      ECORE_CHAIN_CNT_TYPE_U16,
597fe96c1e8SRasesh Mody 			      0, /* N/A when the mode is SINGLE */
598fe96c1e8SRasesh Mody 			      sizeof(struct slow_path_element),
599fe96c1e8SRasesh Mody 			      &p_spq->chain, OSAL_NULL)) {
60098abf84eSRasesh Mody 		DP_NOTICE(p_hwfn, false, "Failed to allocate spq chain\n");
601ec94dbc5SRasesh Mody 		goto spq_allocate_fail;
602ec94dbc5SRasesh Mody 	}
603ec94dbc5SRasesh Mody 
604ec94dbc5SRasesh Mody 	/* allocate and fill the SPQ elements (incl. ramrod data list) */
605ec94dbc5SRasesh Mody 	capacity = ecore_chain_get_capacity(&p_spq->chain);
606ec94dbc5SRasesh Mody 	p_virt = OSAL_DMA_ALLOC_COHERENT(p_hwfn->p_dev, &p_phys,
607ec94dbc5SRasesh Mody 					 capacity *
608ec94dbc5SRasesh Mody 					 sizeof(struct ecore_spq_entry));
609ec94dbc5SRasesh Mody 	if (!p_virt)
610ec94dbc5SRasesh Mody 		goto spq_allocate_fail;
611ec94dbc5SRasesh Mody 
612ec94dbc5SRasesh Mody 	p_spq->p_virt = p_virt;
613ec94dbc5SRasesh Mody 	p_spq->p_phys = p_phys;
614ec94dbc5SRasesh Mody 
61522c99696SRasesh Mody #ifdef CONFIG_ECORE_LOCK_ALLOC
61698abf84eSRasesh Mody 	if (OSAL_SPIN_LOCK_ALLOC(p_hwfn, &p_spq->lock))
61798abf84eSRasesh Mody 		goto spq_allocate_fail;
61822c99696SRasesh Mody #endif
619ec94dbc5SRasesh Mody 
620ec94dbc5SRasesh Mody 	p_hwfn->p_spq = p_spq;
621ec94dbc5SRasesh Mody 	return ECORE_SUCCESS;
622ec94dbc5SRasesh Mody 
623ec94dbc5SRasesh Mody spq_allocate_fail:
624ec94dbc5SRasesh Mody 	ecore_chain_free(p_hwfn->p_dev, &p_spq->chain);
625ec94dbc5SRasesh Mody 	OSAL_FREE(p_hwfn->p_dev, p_spq);
626ec94dbc5SRasesh Mody 	return ECORE_NOMEM;
627ec94dbc5SRasesh Mody }
628ec94dbc5SRasesh Mody 
ecore_spq_free(struct ecore_hwfn * p_hwfn)629ec94dbc5SRasesh Mody void ecore_spq_free(struct ecore_hwfn *p_hwfn)
630ec94dbc5SRasesh Mody {
631ec94dbc5SRasesh Mody 	struct ecore_spq *p_spq = p_hwfn->p_spq;
632e916697fSRasesh Mody 	void OSAL_IOMEM *db_addr;
633ec94dbc5SRasesh Mody 	u32 capacity;
634ec94dbc5SRasesh Mody 
635ec94dbc5SRasesh Mody 	if (!p_spq)
636ec94dbc5SRasesh Mody 		return;
637ec94dbc5SRasesh Mody 
638e916697fSRasesh Mody 	/* Delete the SPQ doorbell from the doorbell recovery mechanism */
639e916697fSRasesh Mody 	db_addr = (void *)((u8 *)p_hwfn->doorbells + p_spq->db_addr_offset);
640e916697fSRasesh Mody 	ecore_db_recovery_del(p_hwfn->p_dev, db_addr, &p_spq->db_data);
641e916697fSRasesh Mody 
642ec94dbc5SRasesh Mody 	if (p_spq->p_virt) {
643ec94dbc5SRasesh Mody 		capacity = ecore_chain_get_capacity(&p_spq->chain);
644ec94dbc5SRasesh Mody 		OSAL_DMA_FREE_COHERENT(p_hwfn->p_dev,
645ec94dbc5SRasesh Mody 				       p_spq->p_virt,
646ec94dbc5SRasesh Mody 				       p_spq->p_phys,
647ec94dbc5SRasesh Mody 				       capacity *
648ec94dbc5SRasesh Mody 				       sizeof(struct ecore_spq_entry));
649ec94dbc5SRasesh Mody 	}
650ec94dbc5SRasesh Mody 
651ec94dbc5SRasesh Mody 	ecore_chain_free(p_hwfn->p_dev, &p_spq->chain);
65222c99696SRasesh Mody #ifdef CONFIG_ECORE_LOCK_ALLOC
653ec94dbc5SRasesh Mody 	OSAL_SPIN_LOCK_DEALLOC(&p_spq->lock);
65422c99696SRasesh Mody #endif
65522c99696SRasesh Mody 
656ec94dbc5SRasesh Mody 	OSAL_FREE(p_hwfn->p_dev, p_spq);
657ec94dbc5SRasesh Mody }
658ec94dbc5SRasesh Mody 
659ec94dbc5SRasesh Mody enum _ecore_status_t
ecore_spq_get_entry(struct ecore_hwfn * p_hwfn,struct ecore_spq_entry ** pp_ent)660ec94dbc5SRasesh Mody ecore_spq_get_entry(struct ecore_hwfn *p_hwfn, struct ecore_spq_entry **pp_ent)
661ec94dbc5SRasesh Mody {
662ec94dbc5SRasesh Mody 	struct ecore_spq *p_spq = p_hwfn->p_spq;
663ec94dbc5SRasesh Mody 	struct ecore_spq_entry *p_ent = OSAL_NULL;
66422d07d93SRasesh Mody 	enum _ecore_status_t rc = ECORE_SUCCESS;
665ec94dbc5SRasesh Mody 
666ec94dbc5SRasesh Mody 	OSAL_SPIN_LOCK(&p_spq->lock);
667ec94dbc5SRasesh Mody 
668ec94dbc5SRasesh Mody 	if (OSAL_LIST_IS_EMPTY(&p_spq->free_pool)) {
66922d07d93SRasesh Mody 		p_ent = OSAL_ZALLOC(p_hwfn->p_dev, GFP_ATOMIC, sizeof(*p_ent));
670ec94dbc5SRasesh Mody 		if (!p_ent) {
67198abf84eSRasesh Mody 			DP_NOTICE(p_hwfn, false, "Failed to allocate an SPQ entry for a pending ramrod\n");
67222d07d93SRasesh Mody 			rc = ECORE_NOMEM;
67322d07d93SRasesh Mody 			goto out_unlock;
674ec94dbc5SRasesh Mody 		}
675ec94dbc5SRasesh Mody 		p_ent->queue = &p_spq->unlimited_pending;
676ec94dbc5SRasesh Mody 	} else {
677ec94dbc5SRasesh Mody 		p_ent = OSAL_LIST_FIRST_ENTRY(&p_spq->free_pool,
678ec94dbc5SRasesh Mody 					      struct ecore_spq_entry, list);
679ec94dbc5SRasesh Mody 		OSAL_LIST_REMOVE_ENTRY(&p_ent->list, &p_spq->free_pool);
680ec94dbc5SRasesh Mody 		p_ent->queue = &p_spq->pending;
681ec94dbc5SRasesh Mody 	}
682ec94dbc5SRasesh Mody 
683ec94dbc5SRasesh Mody 	*pp_ent = p_ent;
684ec94dbc5SRasesh Mody 
68522d07d93SRasesh Mody out_unlock:
686ec94dbc5SRasesh Mody 	OSAL_SPIN_UNLOCK(&p_spq->lock);
68722d07d93SRasesh Mody 	return rc;
688ec94dbc5SRasesh Mody }
689ec94dbc5SRasesh Mody 
690ec94dbc5SRasesh Mody /* 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)691ec94dbc5SRasesh Mody static void __ecore_spq_return_entry(struct ecore_hwfn *p_hwfn,
692ec94dbc5SRasesh Mody 				     struct ecore_spq_entry *p_ent)
693ec94dbc5SRasesh Mody {
694ec94dbc5SRasesh Mody 	OSAL_LIST_PUSH_TAIL(&p_ent->list, &p_hwfn->p_spq->free_pool);
695ec94dbc5SRasesh Mody }
696ec94dbc5SRasesh Mody 
ecore_spq_return_entry(struct ecore_hwfn * p_hwfn,struct ecore_spq_entry * p_ent)697ec94dbc5SRasesh Mody void ecore_spq_return_entry(struct ecore_hwfn *p_hwfn,
698ec94dbc5SRasesh Mody 			    struct ecore_spq_entry *p_ent)
699ec94dbc5SRasesh Mody {
700ec94dbc5SRasesh Mody 	OSAL_SPIN_LOCK(&p_hwfn->p_spq->lock);
701ec94dbc5SRasesh Mody 	__ecore_spq_return_entry(p_hwfn, p_ent);
702ec94dbc5SRasesh Mody 	OSAL_SPIN_UNLOCK(&p_hwfn->p_spq->lock);
703ec94dbc5SRasesh Mody }
704ec94dbc5SRasesh Mody 
705ec94dbc5SRasesh Mody /**
706ec94dbc5SRasesh Mody  * @brief ecore_spq_add_entry - adds a new entry to the pending
707ec94dbc5SRasesh Mody  *        list. Should be used while lock is being held.
708ec94dbc5SRasesh Mody  *
709ec94dbc5SRasesh Mody  * Addes an entry to the pending list is there is room (en empty
710ec94dbc5SRasesh Mody  * element is available in the free_pool), or else places the
711ec94dbc5SRasesh Mody  * entry in the unlimited_pending pool.
712ec94dbc5SRasesh Mody  *
713ec94dbc5SRasesh Mody  * @param p_hwfn
714ec94dbc5SRasesh Mody  * @param p_ent
715ec94dbc5SRasesh Mody  * @param priority
716ec94dbc5SRasesh Mody  *
717ec94dbc5SRasesh Mody  * @return enum _ecore_status_t
718ec94dbc5SRasesh Mody  */
719ec94dbc5SRasesh Mody static enum _ecore_status_t
ecore_spq_add_entry(struct ecore_hwfn * p_hwfn,struct ecore_spq_entry * p_ent,enum spq_priority priority)720ec94dbc5SRasesh Mody ecore_spq_add_entry(struct ecore_hwfn *p_hwfn,
721ec94dbc5SRasesh Mody 		    struct ecore_spq_entry *p_ent, enum spq_priority priority)
722ec94dbc5SRasesh Mody {
723ec94dbc5SRasesh Mody 	struct ecore_spq *p_spq = p_hwfn->p_spq;
724ec94dbc5SRasesh Mody 
725ec94dbc5SRasesh Mody 	if (p_ent->queue == &p_spq->unlimited_pending) {
726ec94dbc5SRasesh Mody 		if (OSAL_LIST_IS_EMPTY(&p_spq->free_pool)) {
727ec94dbc5SRasesh Mody 			OSAL_LIST_PUSH_TAIL(&p_ent->list,
728ec94dbc5SRasesh Mody 					    &p_spq->unlimited_pending);
729ec94dbc5SRasesh Mody 			p_spq->unlimited_pending_count++;
730ec94dbc5SRasesh Mody 
731ec94dbc5SRasesh Mody 			return ECORE_SUCCESS;
73222d07d93SRasesh Mody 
733d2e7d931SRasesh Mody 		} else {
734ec94dbc5SRasesh Mody 			struct ecore_spq_entry *p_en2;
735ec94dbc5SRasesh Mody 
736ec94dbc5SRasesh Mody 			p_en2 = OSAL_LIST_FIRST_ENTRY(&p_spq->free_pool,
737ec94dbc5SRasesh Mody 						     struct ecore_spq_entry,
738ec94dbc5SRasesh Mody 						     list);
739ec94dbc5SRasesh Mody 			OSAL_LIST_REMOVE_ENTRY(&p_en2->list, &p_spq->free_pool);
740ec94dbc5SRasesh Mody 
741ec94dbc5SRasesh Mody 			/* Copy the ring element physical pointer to the new
742ec94dbc5SRasesh Mody 			 * entry, since we are about to override the entire ring
743ec94dbc5SRasesh Mody 			 * entry and don't want to lose the pointer.
744ec94dbc5SRasesh Mody 			 */
745ec94dbc5SRasesh Mody 			p_ent->elem.data_ptr = p_en2->elem.data_ptr;
746ec94dbc5SRasesh Mody 
747ec94dbc5SRasesh Mody 			*p_en2 = *p_ent;
748ec94dbc5SRasesh Mody 
74922d07d93SRasesh Mody 			/* EBLOCK responsible to free the allocated p_ent */
75022d07d93SRasesh Mody 			if (p_ent->comp_mode != ECORE_SPQ_MODE_EBLOCK)
751ec94dbc5SRasesh Mody 				OSAL_FREE(p_hwfn->p_dev, p_ent);
752ec94dbc5SRasesh Mody 
753ec94dbc5SRasesh Mody 			p_ent = p_en2;
754ec94dbc5SRasesh Mody 		}
755d2e7d931SRasesh Mody 	}
756ec94dbc5SRasesh Mody 
757ec94dbc5SRasesh Mody 	/* entry is to be placed in 'pending' queue */
758ec94dbc5SRasesh Mody 	switch (priority) {
759ec94dbc5SRasesh Mody 	case ECORE_SPQ_PRIORITY_NORMAL:
760ec94dbc5SRasesh Mody 		OSAL_LIST_PUSH_TAIL(&p_ent->list, &p_spq->pending);
761ec94dbc5SRasesh Mody 		p_spq->normal_count++;
762ec94dbc5SRasesh Mody 		break;
763ec94dbc5SRasesh Mody 	case ECORE_SPQ_PRIORITY_HIGH:
764ec94dbc5SRasesh Mody 		OSAL_LIST_PUSH_HEAD(&p_ent->list, &p_spq->pending);
765ec94dbc5SRasesh Mody 		p_spq->high_count++;
766ec94dbc5SRasesh Mody 		break;
767ec94dbc5SRasesh Mody 	default:
768ec94dbc5SRasesh Mody 		return ECORE_INVAL;
769ec94dbc5SRasesh Mody 	}
770ec94dbc5SRasesh Mody 
771ec94dbc5SRasesh Mody 	return ECORE_SUCCESS;
772ec94dbc5SRasesh Mody }
773ec94dbc5SRasesh Mody 
774ec94dbc5SRasesh Mody /***************************************************************************
775ec94dbc5SRasesh Mody  * Accessor
776ec94dbc5SRasesh Mody  ***************************************************************************/
777ec94dbc5SRasesh Mody 
ecore_spq_get_cid(struct ecore_hwfn * p_hwfn)778ec94dbc5SRasesh Mody u32 ecore_spq_get_cid(struct ecore_hwfn *p_hwfn)
779ec94dbc5SRasesh Mody {
780ec94dbc5SRasesh Mody 	if (!p_hwfn->p_spq)
781ec94dbc5SRasesh Mody 		return 0xffffffff;	/* illegal */
782ec94dbc5SRasesh Mody 	return p_hwfn->p_spq->cid;
783ec94dbc5SRasesh Mody }
784ec94dbc5SRasesh Mody 
785ec94dbc5SRasesh Mody /***************************************************************************
786ec94dbc5SRasesh Mody  * Posting new Ramrods
787ec94dbc5SRasesh Mody  ***************************************************************************/
788ec94dbc5SRasesh Mody 
ecore_spq_post_list(struct ecore_hwfn * p_hwfn,osal_list_t * head,u32 keep_reserve)789ec94dbc5SRasesh Mody static enum _ecore_status_t ecore_spq_post_list(struct ecore_hwfn *p_hwfn,
790ec94dbc5SRasesh Mody 						osal_list_t *head,
791ec94dbc5SRasesh Mody 						u32 keep_reserve)
792ec94dbc5SRasesh Mody {
793ec94dbc5SRasesh Mody 	struct ecore_spq *p_spq = p_hwfn->p_spq;
794ec94dbc5SRasesh Mody 	enum _ecore_status_t rc;
795ec94dbc5SRasesh Mody 
796ec94dbc5SRasesh Mody 	/* TODO - implementation might be wasteful; will always keep room
797ec94dbc5SRasesh Mody 	 * for an additional high priority ramrod (even if one is already
798ec94dbc5SRasesh Mody 	 * pending FW)
799ec94dbc5SRasesh Mody 	 */
800ec94dbc5SRasesh Mody 	while (ecore_chain_get_elem_left(&p_spq->chain) > keep_reserve &&
801ec94dbc5SRasesh Mody 	       !OSAL_LIST_IS_EMPTY(head)) {
802ec94dbc5SRasesh Mody 		struct ecore_spq_entry *p_ent =
803ec94dbc5SRasesh Mody 		    OSAL_LIST_FIRST_ENTRY(head, struct ecore_spq_entry, list);
80422d07d93SRasesh Mody 		if (p_ent != OSAL_NULL) {
80522d07d93SRasesh Mody #if defined(_NTDDK_)
80622d07d93SRasesh Mody #pragma warning(suppress : 6011 28182)
80722d07d93SRasesh Mody #endif
808ec94dbc5SRasesh Mody 			OSAL_LIST_REMOVE_ENTRY(&p_ent->list, head);
80922d07d93SRasesh Mody 			OSAL_LIST_PUSH_TAIL(&p_ent->list,
81022d07d93SRasesh Mody 					    &p_spq->completion_pending);
811ec94dbc5SRasesh Mody 			p_spq->comp_sent_count++;
812ec94dbc5SRasesh Mody 
813ec94dbc5SRasesh Mody 			rc = ecore_spq_hw_post(p_hwfn, p_spq, p_ent);
814ec94dbc5SRasesh Mody 			if (rc) {
815ec94dbc5SRasesh Mody 				OSAL_LIST_REMOVE_ENTRY(&p_ent->list,
816ec94dbc5SRasesh Mody 						    &p_spq->completion_pending);
817ec94dbc5SRasesh Mody 				__ecore_spq_return_entry(p_hwfn, p_ent);
818ec94dbc5SRasesh Mody 				return rc;
819ec94dbc5SRasesh Mody 			}
820ec94dbc5SRasesh Mody 		}
82122d07d93SRasesh Mody 	}
822ec94dbc5SRasesh Mody 
823ec94dbc5SRasesh Mody 	return ECORE_SUCCESS;
824ec94dbc5SRasesh Mody }
825ec94dbc5SRasesh Mody 
ecore_spq_pend_post(struct ecore_hwfn * p_hwfn)826ec94dbc5SRasesh Mody static enum _ecore_status_t ecore_spq_pend_post(struct ecore_hwfn *p_hwfn)
827ec94dbc5SRasesh Mody {
828ec94dbc5SRasesh Mody 	struct ecore_spq *p_spq = p_hwfn->p_spq;
829ec94dbc5SRasesh Mody 	struct ecore_spq_entry *p_ent = OSAL_NULL;
830ec94dbc5SRasesh Mody 
831ec94dbc5SRasesh Mody 	while (!OSAL_LIST_IS_EMPTY(&p_spq->free_pool)) {
832ec94dbc5SRasesh Mody 		if (OSAL_LIST_IS_EMPTY(&p_spq->unlimited_pending))
833ec94dbc5SRasesh Mody 			break;
834ec94dbc5SRasesh Mody 
835ec94dbc5SRasesh Mody 		p_ent = OSAL_LIST_FIRST_ENTRY(&p_spq->unlimited_pending,
836ec94dbc5SRasesh Mody 					      struct ecore_spq_entry, list);
837ec94dbc5SRasesh Mody 		if (!p_ent)
838ec94dbc5SRasesh Mody 			return ECORE_INVAL;
839ec94dbc5SRasesh Mody 
84022d07d93SRasesh Mody #if defined(_NTDDK_)
84122d07d93SRasesh Mody #pragma warning(suppress : 6011)
84222d07d93SRasesh Mody #endif
843ec94dbc5SRasesh Mody 		OSAL_LIST_REMOVE_ENTRY(&p_ent->list, &p_spq->unlimited_pending);
844ec94dbc5SRasesh Mody 
845ec94dbc5SRasesh Mody 		ecore_spq_add_entry(p_hwfn, p_ent, p_ent->priority);
846ec94dbc5SRasesh Mody 	}
847ec94dbc5SRasesh Mody 
84822d07d93SRasesh Mody 	return ecore_spq_post_list(p_hwfn,
849ec94dbc5SRasesh Mody 				 &p_spq->pending, SPQ_HIGH_PRI_RESERVE_DEFAULT);
850ec94dbc5SRasesh Mody }
851ec94dbc5SRasesh Mody 
ecore_spq_post(struct ecore_hwfn * p_hwfn,struct ecore_spq_entry * p_ent,u8 * fw_return_code)852ec94dbc5SRasesh Mody enum _ecore_status_t ecore_spq_post(struct ecore_hwfn *p_hwfn,
853ec94dbc5SRasesh Mody 				    struct ecore_spq_entry *p_ent,
854ec94dbc5SRasesh Mody 				    u8 *fw_return_code)
855ec94dbc5SRasesh Mody {
856ec94dbc5SRasesh Mody 	enum _ecore_status_t rc = ECORE_SUCCESS;
857ec94dbc5SRasesh Mody 	struct ecore_spq *p_spq = p_hwfn ? p_hwfn->p_spq : OSAL_NULL;
858ec94dbc5SRasesh Mody 	bool b_ret_ent = true;
859ec94dbc5SRasesh Mody 
860ec94dbc5SRasesh Mody 	if (!p_hwfn)
861ec94dbc5SRasesh Mody 		return ECORE_INVAL;
862ec94dbc5SRasesh Mody 
863ec94dbc5SRasesh Mody 	if (!p_ent) {
864ec94dbc5SRasesh Mody 		DP_NOTICE(p_hwfn, true, "Got a NULL pointer\n");
865ec94dbc5SRasesh Mody 		return ECORE_INVAL;
866ec94dbc5SRasesh Mody 	}
867ec94dbc5SRasesh Mody 
868ec94dbc5SRasesh Mody 	if (p_hwfn->p_dev->recov_in_prog) {
869ec94dbc5SRasesh Mody 		DP_VERBOSE(p_hwfn, ECORE_MSG_SPQ,
870ec94dbc5SRasesh Mody 			   "Recovery is in progress -> skip spq post"
8719455b556SRasesh Mody 			   " [cmd %02x protocol %02x]\n",
872ec94dbc5SRasesh Mody 			   p_ent->elem.hdr.cmd_id, p_ent->elem.hdr.protocol_id);
873ec94dbc5SRasesh Mody 		/* Return success to let the flows to be completed successfully
874ec94dbc5SRasesh Mody 		 * w/o any error handling.
875ec94dbc5SRasesh Mody 		 */
876ec94dbc5SRasesh Mody 		return ECORE_SUCCESS;
877ec94dbc5SRasesh Mody 	}
878ec94dbc5SRasesh Mody 
879ec94dbc5SRasesh Mody 	OSAL_SPIN_LOCK(&p_spq->lock);
880ec94dbc5SRasesh Mody 
881ec94dbc5SRasesh Mody 	/* Complete the entry */
882ec94dbc5SRasesh Mody 	rc = ecore_spq_fill_entry(p_hwfn, p_ent);
883ec94dbc5SRasesh Mody 
884ec94dbc5SRasesh Mody 	/* Check return value after LOCK is taken for cleaner error flow */
885ec94dbc5SRasesh Mody 	if (rc)
886ec94dbc5SRasesh Mody 		goto spq_post_fail;
887ec94dbc5SRasesh Mody 
888ec94dbc5SRasesh Mody 	/* Add the request to the pending queue */
889ec94dbc5SRasesh Mody 	rc = ecore_spq_add_entry(p_hwfn, p_ent, p_ent->priority);
890ec94dbc5SRasesh Mody 	if (rc)
891ec94dbc5SRasesh Mody 		goto spq_post_fail;
892ec94dbc5SRasesh Mody 
893ec94dbc5SRasesh Mody 	rc = ecore_spq_pend_post(p_hwfn);
894ec94dbc5SRasesh Mody 	if (rc) {
895ec94dbc5SRasesh Mody 		/* Since it's possible that pending failed for a different
896ec94dbc5SRasesh Mody 		 * entry [although unlikely], the failed entry was already
897ec94dbc5SRasesh Mody 		 * dealt with; No need to return it here.
898ec94dbc5SRasesh Mody 		 */
899ec94dbc5SRasesh Mody 		b_ret_ent = false;
900ec94dbc5SRasesh Mody 		goto spq_post_fail;
901ec94dbc5SRasesh Mody 	}
902ec94dbc5SRasesh Mody 
903ec94dbc5SRasesh Mody 	OSAL_SPIN_UNLOCK(&p_spq->lock);
904ec94dbc5SRasesh Mody 
905ec94dbc5SRasesh Mody 	if (p_ent->comp_mode == ECORE_SPQ_MODE_EBLOCK) {
906ec94dbc5SRasesh Mody 		/* For entries in ECORE BLOCK mode, the completion code cannot
907ec94dbc5SRasesh Mody 		 * perform the necessary cleanup - if it did, we couldn't
908ec94dbc5SRasesh Mody 		 * access p_ent here to see whether it's successful or not.
909ec94dbc5SRasesh Mody 		 * Thus, after gaining the answer perform the cleanup here.
910ec94dbc5SRasesh Mody 		 */
91122d07d93SRasesh Mody 		rc = ecore_spq_block(p_hwfn, p_ent, fw_return_code,
91222d07d93SRasesh Mody 				     p_ent->queue == &p_spq->unlimited_pending);
91322d07d93SRasesh Mody 
91422d07d93SRasesh Mody 		if (p_ent->queue == &p_spq->unlimited_pending) {
91522d07d93SRasesh Mody 			/* This is an allocated p_ent which does not need to
91622d07d93SRasesh Mody 			 * return to pool.
91722d07d93SRasesh Mody 			 */
91822d07d93SRasesh Mody 			OSAL_FREE(p_hwfn->p_dev, p_ent);
91922d07d93SRasesh Mody 
92022d07d93SRasesh Mody 			/* TBD: handle error flow and remove p_ent from
92122d07d93SRasesh Mody 			 * completion pending
92222d07d93SRasesh Mody 			 */
92322d07d93SRasesh Mody 			return rc;
92422d07d93SRasesh Mody 		}
92522d07d93SRasesh Mody 
926ec94dbc5SRasesh Mody 		if (rc)
927ec94dbc5SRasesh Mody 			goto spq_post_fail2;
928ec94dbc5SRasesh Mody 
929ec94dbc5SRasesh Mody 		/* return to pool */
930ec94dbc5SRasesh Mody 		ecore_spq_return_entry(p_hwfn, p_ent);
931ec94dbc5SRasesh Mody 	}
932ec94dbc5SRasesh Mody 	return rc;
933ec94dbc5SRasesh Mody 
934ec94dbc5SRasesh Mody spq_post_fail2:
935ec94dbc5SRasesh Mody 	OSAL_SPIN_LOCK(&p_spq->lock);
936ec94dbc5SRasesh Mody 	OSAL_LIST_REMOVE_ENTRY(&p_ent->list, &p_spq->completion_pending);
937ec94dbc5SRasesh Mody 	ecore_chain_return_produced(&p_spq->chain);
938ec94dbc5SRasesh Mody 
939ec94dbc5SRasesh Mody spq_post_fail:
940ec94dbc5SRasesh Mody 	/* return to the free pool */
941ec94dbc5SRasesh Mody 	if (b_ret_ent)
942ec94dbc5SRasesh Mody 		__ecore_spq_return_entry(p_hwfn, p_ent);
943ec94dbc5SRasesh Mody 	OSAL_SPIN_UNLOCK(&p_spq->lock);
944ec94dbc5SRasesh Mody 
945ec94dbc5SRasesh Mody 	return rc;
946ec94dbc5SRasesh Mody }
947ec94dbc5SRasesh Mody 
ecore_spq_completion(struct ecore_hwfn * p_hwfn,__le16 echo,u8 fw_return_code,union event_ring_data * p_data)948ec94dbc5SRasesh Mody enum _ecore_status_t ecore_spq_completion(struct ecore_hwfn *p_hwfn,
949ec94dbc5SRasesh Mody 					  __le16 echo,
950ec94dbc5SRasesh Mody 					  u8 fw_return_code,
951ec94dbc5SRasesh Mody 					  union event_ring_data *p_data)
952ec94dbc5SRasesh Mody {
953ec94dbc5SRasesh Mody 	struct ecore_spq *p_spq;
954ec94dbc5SRasesh Mody 	struct ecore_spq_entry *p_ent = OSAL_NULL;
955ec94dbc5SRasesh Mody 	struct ecore_spq_entry *tmp;
956ec94dbc5SRasesh Mody 	struct ecore_spq_entry *found = OSAL_NULL;
957ec94dbc5SRasesh Mody 	enum _ecore_status_t rc;
958ec94dbc5SRasesh Mody 
959ec94dbc5SRasesh Mody 	p_spq = p_hwfn->p_spq;
9609ed26bc7SRasesh Mody 	if (!p_spq) {
9619ed26bc7SRasesh Mody 		DP_ERR(p_hwfn, "Unexpected NULL p_spq\n");
962ec94dbc5SRasesh Mody 		return ECORE_INVAL;
9639ed26bc7SRasesh Mody 	}
964ec94dbc5SRasesh Mody 
965ec94dbc5SRasesh Mody 	OSAL_SPIN_LOCK(&p_spq->lock);
966ec94dbc5SRasesh Mody 	OSAL_LIST_FOR_EACH_ENTRY_SAFE(p_ent,
967ec94dbc5SRasesh Mody 				      tmp,
968ec94dbc5SRasesh Mody 				      &p_spq->completion_pending,
969ec94dbc5SRasesh Mody 				      list, struct ecore_spq_entry) {
970ec94dbc5SRasesh Mody 		if (p_ent->elem.hdr.echo == echo) {
971ec94dbc5SRasesh Mody 			OSAL_LIST_REMOVE_ENTRY(&p_ent->list,
972ec94dbc5SRasesh Mody 					       &p_spq->completion_pending);
973ec94dbc5SRasesh Mody 
974ec94dbc5SRasesh Mody 			/* Avoid overriding of SPQ entries when getting
975ec94dbc5SRasesh Mody 			 * out-of-order completions, by marking the completions
976ec94dbc5SRasesh Mody 			 * in a bitmap and increasing the chain consumer only
977ec94dbc5SRasesh Mody 			 * for the first successive completed entries.
978ec94dbc5SRasesh Mody 			 */
979ec94dbc5SRasesh Mody 			SPQ_COMP_BMAP_SET_BIT(p_spq, echo);
980*5018f1fcSJoyce Kong 			while (SPQ_COMP_BMAP_GET_BIT(p_spq,
981ec94dbc5SRasesh Mody 						      p_spq->comp_bitmap_idx)) {
982ec94dbc5SRasesh Mody 				SPQ_COMP_BMAP_CLEAR_BIT(p_spq,
983ec94dbc5SRasesh Mody 							p_spq->comp_bitmap_idx);
984ec94dbc5SRasesh Mody 				p_spq->comp_bitmap_idx++;
985ec94dbc5SRasesh Mody 				ecore_chain_return_produced(&p_spq->chain);
986ec94dbc5SRasesh Mody 			}
987ec94dbc5SRasesh Mody 
988ec94dbc5SRasesh Mody 			p_spq->comp_count++;
989ec94dbc5SRasesh Mody 			found = p_ent;
990ec94dbc5SRasesh Mody 			break;
991ec94dbc5SRasesh Mody 		}
992ec94dbc5SRasesh Mody 
993ec94dbc5SRasesh Mody 		/* This is debug and should be relatively uncommon - depends
994ec94dbc5SRasesh Mody 		 * on scenarios which have mutliple per-PF sent ramrods.
995ec94dbc5SRasesh Mody 		 */
996ec94dbc5SRasesh Mody 		DP_VERBOSE(p_hwfn, ECORE_MSG_SPQ,
997ec94dbc5SRasesh Mody 			   "Got completion for echo %04x - doesn't match"
998ec94dbc5SRasesh Mody 			   " echo %04x in completion pending list\n",
999ec94dbc5SRasesh Mody 			   OSAL_LE16_TO_CPU(echo),
1000ec94dbc5SRasesh Mody 			   OSAL_LE16_TO_CPU(p_ent->elem.hdr.echo));
1001ec94dbc5SRasesh Mody 	}
1002ec94dbc5SRasesh Mody 
1003ec94dbc5SRasesh Mody 	/* Release lock before callback, as callback may post
1004ec94dbc5SRasesh Mody 	 * an additional ramrod.
1005ec94dbc5SRasesh Mody 	 */
1006ec94dbc5SRasesh Mody 	OSAL_SPIN_UNLOCK(&p_spq->lock);
1007ec94dbc5SRasesh Mody 
1008ec94dbc5SRasesh Mody 	if (!found) {
1009ec94dbc5SRasesh Mody 		DP_NOTICE(p_hwfn, true,
1010ec94dbc5SRasesh Mody 			  "Failed to find an entry this"
1011ec94dbc5SRasesh Mody 			  " EQE [echo %04x] completes\n",
1012ec94dbc5SRasesh Mody 			  OSAL_LE16_TO_CPU(echo));
1013ec94dbc5SRasesh Mody 		return ECORE_EXISTS;
1014ec94dbc5SRasesh Mody 	}
1015ec94dbc5SRasesh Mody 
1016ec94dbc5SRasesh Mody 	DP_VERBOSE(p_hwfn, ECORE_MSG_SPQ,
1017ec94dbc5SRasesh Mody 		   "Complete EQE [echo %04x]: func %p cookie %p)\n",
1018ec94dbc5SRasesh Mody 		   OSAL_LE16_TO_CPU(echo),
1019ec94dbc5SRasesh Mody 		   p_ent->comp_cb.function, p_ent->comp_cb.cookie);
1020ec94dbc5SRasesh Mody 	if (found->comp_cb.function)
1021ec94dbc5SRasesh Mody 		found->comp_cb.function(p_hwfn, found->comp_cb.cookie, p_data,
1022ec94dbc5SRasesh Mody 					fw_return_code);
1023869c47d0SRasesh Mody 	else
1024869c47d0SRasesh Mody 		DP_VERBOSE(p_hwfn, ECORE_MSG_SPQ,
1025869c47d0SRasesh Mody 			   "Got a completion without a callback function\n");
1026ec94dbc5SRasesh Mody 
102722d07d93SRasesh Mody 	if ((found->comp_mode != ECORE_SPQ_MODE_EBLOCK) ||
102822d07d93SRasesh Mody 	    (found->queue == &p_spq->unlimited_pending))
102922d07d93SRasesh Mody 		/* EBLOCK  is responsible for returning its own entry into the
103022d07d93SRasesh Mody 		 * free list, unless it originally added the entry into the
103122d07d93SRasesh Mody 		 * unlimited pending list.
103222d07d93SRasesh Mody 		 */
1033ec94dbc5SRasesh Mody 		ecore_spq_return_entry(p_hwfn, found);
1034ec94dbc5SRasesh Mody 
1035ec94dbc5SRasesh Mody 	/* Attempt to post pending requests */
1036ec94dbc5SRasesh Mody 	OSAL_SPIN_LOCK(&p_spq->lock);
1037ec94dbc5SRasesh Mody 	rc = ecore_spq_pend_post(p_hwfn);
1038ec94dbc5SRasesh Mody 	OSAL_SPIN_UNLOCK(&p_spq->lock);
1039ec94dbc5SRasesh Mody 
1040ec94dbc5SRasesh Mody 	return rc;
1041ec94dbc5SRasesh Mody }
1042ec94dbc5SRasesh Mody 
ecore_consq_alloc(struct ecore_hwfn * p_hwfn)1043d411a2b5SRasesh Mody enum _ecore_status_t ecore_consq_alloc(struct ecore_hwfn *p_hwfn)
1044ec94dbc5SRasesh Mody {
1045ec94dbc5SRasesh Mody 	struct ecore_consq *p_consq;
1046ec94dbc5SRasesh Mody 
1047ec94dbc5SRasesh Mody 	/* Allocate ConsQ struct */
1048ec94dbc5SRasesh Mody 	p_consq =
104922d07d93SRasesh Mody 	    OSAL_ZALLOC(p_hwfn->p_dev, GFP_KERNEL, sizeof(*p_consq));
1050ec94dbc5SRasesh Mody 	if (!p_consq) {
105198abf84eSRasesh Mody 		DP_NOTICE(p_hwfn, false,
1052ec94dbc5SRasesh Mody 			  "Failed to allocate `struct ecore_consq'\n");
1053d411a2b5SRasesh Mody 		return ECORE_NOMEM;
1054ec94dbc5SRasesh Mody 	}
1055ec94dbc5SRasesh Mody 
1056ec94dbc5SRasesh Mody 	/* Allocate and initialize EQ chain */
1057ec94dbc5SRasesh Mody 	if (ecore_chain_alloc(p_hwfn->p_dev,
1058ec94dbc5SRasesh Mody 			      ECORE_CHAIN_USE_TO_PRODUCE,
1059ec94dbc5SRasesh Mody 			      ECORE_CHAIN_MODE_PBL,
1060ec94dbc5SRasesh Mody 			      ECORE_CHAIN_CNT_TYPE_U16,
1061ec94dbc5SRasesh Mody 			      ECORE_CHAIN_PAGE_SIZE / 0x80,
1062fe96c1e8SRasesh Mody 			      0x80,
1063d411a2b5SRasesh Mody 			      &p_consq->chain, OSAL_NULL) != ECORE_SUCCESS) {
106498abf84eSRasesh Mody 		DP_NOTICE(p_hwfn, false, "Failed to allocate consq chain");
1065ec94dbc5SRasesh Mody 		goto consq_allocate_fail;
1066ec94dbc5SRasesh Mody 	}
1067ec94dbc5SRasesh Mody 
1068d411a2b5SRasesh Mody 	p_hwfn->p_consq = p_consq;
1069d411a2b5SRasesh Mody 	return ECORE_SUCCESS;
1070ec94dbc5SRasesh Mody 
1071ec94dbc5SRasesh Mody consq_allocate_fail:
1072ec94dbc5SRasesh Mody 	OSAL_FREE(p_hwfn->p_dev, p_consq);
1073d411a2b5SRasesh Mody 	return ECORE_NOMEM;
1074d411a2b5SRasesh Mody }
1075d411a2b5SRasesh Mody 
ecore_consq_setup(struct ecore_hwfn * p_hwfn)1076d411a2b5SRasesh Mody void ecore_consq_setup(struct ecore_hwfn *p_hwfn)
1077d411a2b5SRasesh Mody {
1078d411a2b5SRasesh Mody 	ecore_chain_reset(&p_hwfn->p_consq->chain);
1079d411a2b5SRasesh Mody }
1080d411a2b5SRasesh Mody 
ecore_consq_free(struct ecore_hwfn * p_hwfn)1081d411a2b5SRasesh Mody void ecore_consq_free(struct ecore_hwfn *p_hwfn)
1082d411a2b5SRasesh Mody {
1083d411a2b5SRasesh Mody 	if (!p_hwfn->p_consq)
1084d411a2b5SRasesh Mody 		return;
1085d411a2b5SRasesh Mody 
1086d411a2b5SRasesh Mody 	ecore_chain_free(p_hwfn->p_dev, &p_hwfn->p_consq->chain);
1087d411a2b5SRasesh Mody 	OSAL_FREE(p_hwfn->p_dev, p_hwfn->p_consq);
1088ec94dbc5SRasesh Mody }
1089