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