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