xref: /linux/drivers/infiniband/hw/bng_re/bng_fw.c (revision 53c6ee7d7f68a0679f8ddc703338aa2550d24a17)
153310b69SSiva Reddy Kallam // SPDX-License-Identifier: GPL-2.0
253310b69SSiva Reddy Kallam // Copyright (c) 2025 Broadcom.
353310b69SSiva Reddy Kallam #include <linux/pci.h>
453310b69SSiva Reddy Kallam 
54f830cd8SSiva Reddy Kallam #include "roce_hsi.h"
653310b69SSiva Reddy Kallam #include "bng_res.h"
753310b69SSiva Reddy Kallam #include "bng_fw.h"
853310b69SSiva Reddy Kallam 
9*53c6ee7dSSiva Reddy Kallam /**
10*53c6ee7dSSiva Reddy Kallam  * bng_re_map_rc  -  map return type based on opcode
11*53c6ee7dSSiva Reddy Kallam  * @opcode:  roce slow path opcode
12*53c6ee7dSSiva Reddy Kallam  *
13*53c6ee7dSSiva Reddy Kallam  * case #1
14*53c6ee7dSSiva Reddy Kallam  * Firmware initiated error recovery is a safe state machine and
15*53c6ee7dSSiva Reddy Kallam  * driver can consider all the underlying rdma resources are free.
16*53c6ee7dSSiva Reddy Kallam  * In this state, it is safe to return success for opcodes related to
17*53c6ee7dSSiva Reddy Kallam  * destroying rdma resources (like destroy qp, destroy cq etc.).
18*53c6ee7dSSiva Reddy Kallam  *
19*53c6ee7dSSiva Reddy Kallam  * case #2
20*53c6ee7dSSiva Reddy Kallam  * If driver detect potential firmware stall, it is not safe state machine
21*53c6ee7dSSiva Reddy Kallam  * and the driver can not consider all the underlying rdma resources are
22*53c6ee7dSSiva Reddy Kallam  * freed.
23*53c6ee7dSSiva Reddy Kallam  * In this state, it is not safe to return success for opcodes related to
24*53c6ee7dSSiva Reddy Kallam  * destroying rdma resources (like destroy qp, destroy cq etc.).
25*53c6ee7dSSiva Reddy Kallam  *
26*53c6ee7dSSiva Reddy Kallam  * Scope of this helper function is only for case #1.
27*53c6ee7dSSiva Reddy Kallam  *
28*53c6ee7dSSiva Reddy Kallam  * Returns:
29*53c6ee7dSSiva Reddy Kallam  * 0 to communicate success to caller.
30*53c6ee7dSSiva Reddy Kallam  * Non zero error code to communicate failure to caller.
31*53c6ee7dSSiva Reddy Kallam  */
32*53c6ee7dSSiva Reddy Kallam static int bng_re_map_rc(u8 opcode)
33*53c6ee7dSSiva Reddy Kallam {
34*53c6ee7dSSiva Reddy Kallam 	switch (opcode) {
35*53c6ee7dSSiva Reddy Kallam 	case CMDQ_BASE_OPCODE_DESTROY_QP:
36*53c6ee7dSSiva Reddy Kallam 	case CMDQ_BASE_OPCODE_DESTROY_SRQ:
37*53c6ee7dSSiva Reddy Kallam 	case CMDQ_BASE_OPCODE_DESTROY_CQ:
38*53c6ee7dSSiva Reddy Kallam 	case CMDQ_BASE_OPCODE_DEALLOCATE_KEY:
39*53c6ee7dSSiva Reddy Kallam 	case CMDQ_BASE_OPCODE_DEREGISTER_MR:
40*53c6ee7dSSiva Reddy Kallam 	case CMDQ_BASE_OPCODE_DELETE_GID:
41*53c6ee7dSSiva Reddy Kallam 	case CMDQ_BASE_OPCODE_DESTROY_QP1:
42*53c6ee7dSSiva Reddy Kallam 	case CMDQ_BASE_OPCODE_DESTROY_AH:
43*53c6ee7dSSiva Reddy Kallam 	case CMDQ_BASE_OPCODE_DEINITIALIZE_FW:
44*53c6ee7dSSiva Reddy Kallam 	case CMDQ_BASE_OPCODE_MODIFY_ROCE_CC:
45*53c6ee7dSSiva Reddy Kallam 	case CMDQ_BASE_OPCODE_SET_LINK_AGGR_MODE:
46*53c6ee7dSSiva Reddy Kallam 		return 0;
47*53c6ee7dSSiva Reddy Kallam 	default:
48*53c6ee7dSSiva Reddy Kallam 		return -ETIMEDOUT;
49*53c6ee7dSSiva Reddy Kallam 	}
50*53c6ee7dSSiva Reddy Kallam }
51*53c6ee7dSSiva Reddy Kallam 
5253310b69SSiva Reddy Kallam void bng_re_free_rcfw_channel(struct bng_re_rcfw *rcfw)
5353310b69SSiva Reddy Kallam {
5453310b69SSiva Reddy Kallam 	kfree(rcfw->crsqe_tbl);
5553310b69SSiva Reddy Kallam 	bng_re_free_hwq(rcfw->res, &rcfw->cmdq.hwq);
5653310b69SSiva Reddy Kallam 	bng_re_free_hwq(rcfw->res, &rcfw->creq.hwq);
5753310b69SSiva Reddy Kallam 	rcfw->pdev = NULL;
5853310b69SSiva Reddy Kallam }
5953310b69SSiva Reddy Kallam 
6053310b69SSiva Reddy Kallam int bng_re_alloc_fw_channel(struct bng_re_res *res,
6153310b69SSiva Reddy Kallam 			    struct bng_re_rcfw *rcfw)
6253310b69SSiva Reddy Kallam {
6353310b69SSiva Reddy Kallam 	struct bng_re_hwq_attr hwq_attr = {};
6453310b69SSiva Reddy Kallam 	struct bng_re_sg_info sginfo = {};
6553310b69SSiva Reddy Kallam 	struct bng_re_cmdq_ctx *cmdq;
6653310b69SSiva Reddy Kallam 	struct bng_re_creq_ctx *creq;
6753310b69SSiva Reddy Kallam 
6853310b69SSiva Reddy Kallam 	rcfw->pdev = res->pdev;
6953310b69SSiva Reddy Kallam 	cmdq = &rcfw->cmdq;
7053310b69SSiva Reddy Kallam 	creq = &rcfw->creq;
7153310b69SSiva Reddy Kallam 	rcfw->res = res;
7253310b69SSiva Reddy Kallam 
7353310b69SSiva Reddy Kallam 	sginfo.pgsize = PAGE_SIZE;
7453310b69SSiva Reddy Kallam 	sginfo.pgshft = PAGE_SHIFT;
7553310b69SSiva Reddy Kallam 
7653310b69SSiva Reddy Kallam 	hwq_attr.sginfo = &sginfo;
7753310b69SSiva Reddy Kallam 	hwq_attr.res = rcfw->res;
7853310b69SSiva Reddy Kallam 	hwq_attr.depth = BNG_FW_CREQE_MAX_CNT;
7953310b69SSiva Reddy Kallam 	hwq_attr.stride = BNG_FW_CREQE_UNITS;
8053310b69SSiva Reddy Kallam 	hwq_attr.type = BNG_HWQ_TYPE_QUEUE;
8153310b69SSiva Reddy Kallam 
8253310b69SSiva Reddy Kallam 	if (bng_re_alloc_init_hwq(&creq->hwq, &hwq_attr)) {
8353310b69SSiva Reddy Kallam 		dev_err(&rcfw->pdev->dev,
8453310b69SSiva Reddy Kallam 			"HW channel CREQ allocation failed\n");
8553310b69SSiva Reddy Kallam 		goto fail;
8653310b69SSiva Reddy Kallam 	}
8753310b69SSiva Reddy Kallam 
8853310b69SSiva Reddy Kallam 	rcfw->cmdq_depth = BNG_FW_CMDQE_MAX_CNT;
8953310b69SSiva Reddy Kallam 
9053310b69SSiva Reddy Kallam 	sginfo.pgsize = bng_fw_cmdqe_page_size(rcfw->cmdq_depth);
9153310b69SSiva Reddy Kallam 	hwq_attr.depth = rcfw->cmdq_depth & 0x7FFFFFFF;
9253310b69SSiva Reddy Kallam 	hwq_attr.stride = BNG_FW_CMDQE_UNITS;
9353310b69SSiva Reddy Kallam 	hwq_attr.type = BNG_HWQ_TYPE_CTX;
9453310b69SSiva Reddy Kallam 	if (bng_re_alloc_init_hwq(&cmdq->hwq, &hwq_attr)) {
9553310b69SSiva Reddy Kallam 		dev_err(&rcfw->pdev->dev,
9653310b69SSiva Reddy Kallam 			"HW channel CMDQ allocation failed\n");
9753310b69SSiva Reddy Kallam 		goto fail;
9853310b69SSiva Reddy Kallam 	}
9953310b69SSiva Reddy Kallam 
10053310b69SSiva Reddy Kallam 	rcfw->crsqe_tbl = kcalloc(cmdq->hwq.max_elements,
10153310b69SSiva Reddy Kallam 				  sizeof(*rcfw->crsqe_tbl), GFP_KERNEL);
10253310b69SSiva Reddy Kallam 	if (!rcfw->crsqe_tbl)
10353310b69SSiva Reddy Kallam 		goto fail;
10453310b69SSiva Reddy Kallam 
10553310b69SSiva Reddy Kallam 	spin_lock_init(&rcfw->tbl_lock);
10653310b69SSiva Reddy Kallam 
10753310b69SSiva Reddy Kallam 	rcfw->max_timeout = res->cctx->hwrm_cmd_max_timeout;
10853310b69SSiva Reddy Kallam 	return 0;
10953310b69SSiva Reddy Kallam 
11053310b69SSiva Reddy Kallam fail:
11153310b69SSiva Reddy Kallam 	bng_re_free_rcfw_channel(rcfw);
11253310b69SSiva Reddy Kallam 	return -ENOMEM;
11353310b69SSiva Reddy Kallam }
1144f830cd8SSiva Reddy Kallam 
1154f830cd8SSiva Reddy Kallam static int bng_re_process_qp_event(struct bng_re_rcfw *rcfw,
1164f830cd8SSiva Reddy Kallam 				   struct creq_qp_event *qp_event,
1174f830cd8SSiva Reddy Kallam 				   u32 *num_wait)
1184f830cd8SSiva Reddy Kallam {
1194f830cd8SSiva Reddy Kallam 	struct bng_re_hwq *hwq = &rcfw->cmdq.hwq;
1204f830cd8SSiva Reddy Kallam 	struct bng_re_crsqe *crsqe;
1214f830cd8SSiva Reddy Kallam 	u32 req_size;
1224f830cd8SSiva Reddy Kallam 	u16 cookie;
1234f830cd8SSiva Reddy Kallam 	bool is_waiter_alive;
1244f830cd8SSiva Reddy Kallam 	struct pci_dev *pdev;
1254f830cd8SSiva Reddy Kallam 	u32 wait_cmds = 0;
1264f830cd8SSiva Reddy Kallam 	int rc = 0;
1274f830cd8SSiva Reddy Kallam 
1284f830cd8SSiva Reddy Kallam 	pdev = rcfw->pdev;
1294f830cd8SSiva Reddy Kallam 	switch (qp_event->event) {
1304f830cd8SSiva Reddy Kallam 	case CREQ_QP_EVENT_EVENT_QP_ERROR_NOTIFICATION:
1314f830cd8SSiva Reddy Kallam 		dev_err(&pdev->dev, "Received QP error notification\n");
1324f830cd8SSiva Reddy Kallam 		break;
1334f830cd8SSiva Reddy Kallam 	default:
1344f830cd8SSiva Reddy Kallam 		/*
1354f830cd8SSiva Reddy Kallam 		 * Command Response
1364f830cd8SSiva Reddy Kallam 		 * cmdq->lock needs to be acquired to synchronie
1374f830cd8SSiva Reddy Kallam 		 * the command send and completion reaping. This function
1384f830cd8SSiva Reddy Kallam 		 * is always called with creq->lock held. Using
1394f830cd8SSiva Reddy Kallam 		 * the nested variant of spin_lock.
1404f830cd8SSiva Reddy Kallam 		 *
1414f830cd8SSiva Reddy Kallam 		 */
1424f830cd8SSiva Reddy Kallam 
1434f830cd8SSiva Reddy Kallam 		spin_lock_nested(&hwq->lock, SINGLE_DEPTH_NESTING);
1444f830cd8SSiva Reddy Kallam 		cookie = le16_to_cpu(qp_event->cookie);
1454f830cd8SSiva Reddy Kallam 		cookie &= BNG_FW_MAX_COOKIE_VALUE;
1464f830cd8SSiva Reddy Kallam 		crsqe = &rcfw->crsqe_tbl[cookie];
1474f830cd8SSiva Reddy Kallam 
1484f830cd8SSiva Reddy Kallam 		if (WARN_ONCE(test_bit(FIRMWARE_STALL_DETECTED,
1494f830cd8SSiva Reddy Kallam 				       &rcfw->cmdq.flags),
1504f830cd8SSiva Reddy Kallam 		    "Unreponsive rcfw channel detected.!!")) {
1514f830cd8SSiva Reddy Kallam 			dev_info(&pdev->dev,
1524f830cd8SSiva Reddy Kallam 				 "rcfw timedout: cookie = %#x, free_slots = %d",
1534f830cd8SSiva Reddy Kallam 				 cookie, crsqe->free_slots);
1544f830cd8SSiva Reddy Kallam 			spin_unlock(&hwq->lock);
1554f830cd8SSiva Reddy Kallam 			return rc;
1564f830cd8SSiva Reddy Kallam 		}
1574f830cd8SSiva Reddy Kallam 
1584f830cd8SSiva Reddy Kallam 		if (crsqe->is_waiter_alive) {
1594f830cd8SSiva Reddy Kallam 			if (crsqe->resp) {
1604f830cd8SSiva Reddy Kallam 				memcpy(crsqe->resp, qp_event, sizeof(*qp_event));
1614f830cd8SSiva Reddy Kallam 				/* Insert write memory barrier to ensure that
1624f830cd8SSiva Reddy Kallam 				 * response data is copied before clearing the
1634f830cd8SSiva Reddy Kallam 				 * flags
1644f830cd8SSiva Reddy Kallam 				 */
1654f830cd8SSiva Reddy Kallam 				smp_wmb();
1664f830cd8SSiva Reddy Kallam 			}
1674f830cd8SSiva Reddy Kallam 		}
1684f830cd8SSiva Reddy Kallam 
1694f830cd8SSiva Reddy Kallam 		wait_cmds++;
1704f830cd8SSiva Reddy Kallam 
1714f830cd8SSiva Reddy Kallam 		req_size = crsqe->req_size;
1724f830cd8SSiva Reddy Kallam 		is_waiter_alive = crsqe->is_waiter_alive;
1734f830cd8SSiva Reddy Kallam 
1744f830cd8SSiva Reddy Kallam 		crsqe->req_size = 0;
1754f830cd8SSiva Reddy Kallam 		if (!is_waiter_alive)
1764f830cd8SSiva Reddy Kallam 			crsqe->resp = NULL;
1774f830cd8SSiva Reddy Kallam 
1784f830cd8SSiva Reddy Kallam 		crsqe->is_in_used = false;
1794f830cd8SSiva Reddy Kallam 
1804f830cd8SSiva Reddy Kallam 		hwq->cons += req_size;
1814f830cd8SSiva Reddy Kallam 
1824f830cd8SSiva Reddy Kallam 		spin_unlock(&hwq->lock);
1834f830cd8SSiva Reddy Kallam 	}
1844f830cd8SSiva Reddy Kallam 	*num_wait += wait_cmds;
1854f830cd8SSiva Reddy Kallam 	return rc;
1864f830cd8SSiva Reddy Kallam }
1874f830cd8SSiva Reddy Kallam 
1884f830cd8SSiva Reddy Kallam /* function events */
1894f830cd8SSiva Reddy Kallam static int bng_re_process_func_event(struct bng_re_rcfw *rcfw,
1904f830cd8SSiva Reddy Kallam 				     struct creq_func_event *func_event)
1914f830cd8SSiva Reddy Kallam {
1924f830cd8SSiva Reddy Kallam 	switch (func_event->event) {
1934f830cd8SSiva Reddy Kallam 	case CREQ_FUNC_EVENT_EVENT_TX_WQE_ERROR:
1944f830cd8SSiva Reddy Kallam 	case CREQ_FUNC_EVENT_EVENT_TX_DATA_ERROR:
1954f830cd8SSiva Reddy Kallam 	case CREQ_FUNC_EVENT_EVENT_RX_WQE_ERROR:
1964f830cd8SSiva Reddy Kallam 	case CREQ_FUNC_EVENT_EVENT_RX_DATA_ERROR:
1974f830cd8SSiva Reddy Kallam 	case CREQ_FUNC_EVENT_EVENT_CQ_ERROR:
1984f830cd8SSiva Reddy Kallam 	case CREQ_FUNC_EVENT_EVENT_TQM_ERROR:
1994f830cd8SSiva Reddy Kallam 	case CREQ_FUNC_EVENT_EVENT_CFCQ_ERROR:
2004f830cd8SSiva Reddy Kallam 	case CREQ_FUNC_EVENT_EVENT_CFCS_ERROR:
2014f830cd8SSiva Reddy Kallam 	case CREQ_FUNC_EVENT_EVENT_CFCC_ERROR:
2024f830cd8SSiva Reddy Kallam 	case CREQ_FUNC_EVENT_EVENT_CFCM_ERROR:
2034f830cd8SSiva Reddy Kallam 	case CREQ_FUNC_EVENT_EVENT_TIM_ERROR:
2044f830cd8SSiva Reddy Kallam 	case CREQ_FUNC_EVENT_EVENT_VF_COMM_REQUEST:
2054f830cd8SSiva Reddy Kallam 	case CREQ_FUNC_EVENT_EVENT_RESOURCE_EXHAUSTED:
2064f830cd8SSiva Reddy Kallam 		break;
2074f830cd8SSiva Reddy Kallam 	default:
2084f830cd8SSiva Reddy Kallam 		return -EINVAL;
2094f830cd8SSiva Reddy Kallam 	}
2104f830cd8SSiva Reddy Kallam 
2114f830cd8SSiva Reddy Kallam 	return 0;
2124f830cd8SSiva Reddy Kallam }
2134f830cd8SSiva Reddy Kallam 
2144f830cd8SSiva Reddy Kallam /* CREQ Completion handlers */
2154f830cd8SSiva Reddy Kallam static void bng_re_service_creq(struct tasklet_struct *t)
2164f830cd8SSiva Reddy Kallam {
2174f830cd8SSiva Reddy Kallam 	struct bng_re_rcfw *rcfw = from_tasklet(rcfw, t, creq.creq_tasklet);
2184f830cd8SSiva Reddy Kallam 	struct bng_re_creq_ctx *creq = &rcfw->creq;
2194f830cd8SSiva Reddy Kallam 	u32 type, budget = BNG_FW_CREQ_ENTRY_POLL_BUDGET;
2204f830cd8SSiva Reddy Kallam 	struct bng_re_hwq *hwq = &creq->hwq;
2214f830cd8SSiva Reddy Kallam 	struct creq_base *creqe;
2224f830cd8SSiva Reddy Kallam 	u32 num_wakeup = 0;
2234f830cd8SSiva Reddy Kallam 	u32 hw_polled = 0;
2244f830cd8SSiva Reddy Kallam 
2254f830cd8SSiva Reddy Kallam 	/* Service the CREQ until budget is over */
2264f830cd8SSiva Reddy Kallam 	spin_lock_bh(&hwq->lock);
2274f830cd8SSiva Reddy Kallam 	while (budget > 0) {
2284f830cd8SSiva Reddy Kallam 		creqe = bng_re_get_qe(hwq, hwq->cons, NULL);
2294f830cd8SSiva Reddy Kallam 		if (!BNG_FW_CREQ_CMP_VALID(creqe, creq->creq_db.dbinfo.flags))
2304f830cd8SSiva Reddy Kallam 			break;
2314f830cd8SSiva Reddy Kallam 		/* The valid test of the entry must be done first before
2324f830cd8SSiva Reddy Kallam 		 * reading any further.
2334f830cd8SSiva Reddy Kallam 		 */
2344f830cd8SSiva Reddy Kallam 		dma_rmb();
2354f830cd8SSiva Reddy Kallam 
2364f830cd8SSiva Reddy Kallam 		type = creqe->type & CREQ_BASE_TYPE_MASK;
2374f830cd8SSiva Reddy Kallam 		switch (type) {
2384f830cd8SSiva Reddy Kallam 		case CREQ_BASE_TYPE_QP_EVENT:
2394f830cd8SSiva Reddy Kallam 			bng_re_process_qp_event
2404f830cd8SSiva Reddy Kallam 				(rcfw, (struct creq_qp_event *)creqe,
2414f830cd8SSiva Reddy Kallam 				 &num_wakeup);
2424f830cd8SSiva Reddy Kallam 			creq->stats.creq_qp_event_processed++;
2434f830cd8SSiva Reddy Kallam 			break;
2444f830cd8SSiva Reddy Kallam 		case CREQ_BASE_TYPE_FUNC_EVENT:
2454f830cd8SSiva Reddy Kallam 			if (!bng_re_process_func_event
2464f830cd8SSiva Reddy Kallam 			    (rcfw, (struct creq_func_event *)creqe))
2474f830cd8SSiva Reddy Kallam 				creq->stats.creq_func_event_processed++;
2484f830cd8SSiva Reddy Kallam 			else
2494f830cd8SSiva Reddy Kallam 				dev_warn(&rcfw->pdev->dev,
2504f830cd8SSiva Reddy Kallam 					 "aeqe:%#x Not handled\n", type);
2514f830cd8SSiva Reddy Kallam 			break;
2524f830cd8SSiva Reddy Kallam 		default:
2534f830cd8SSiva Reddy Kallam 			if (type != ASYNC_EVENT_CMPL_TYPE_HWRM_ASYNC_EVENT)
2544f830cd8SSiva Reddy Kallam 				dev_warn(&rcfw->pdev->dev,
2554f830cd8SSiva Reddy Kallam 					 "creqe with event 0x%x not handled\n",
2564f830cd8SSiva Reddy Kallam 					 type);
2574f830cd8SSiva Reddy Kallam 			break;
2584f830cd8SSiva Reddy Kallam 		}
2594f830cd8SSiva Reddy Kallam 		budget--;
2604f830cd8SSiva Reddy Kallam 		hw_polled++;
2614f830cd8SSiva Reddy Kallam 		bng_re_hwq_incr_cons(hwq->max_elements, &hwq->cons,
2624f830cd8SSiva Reddy Kallam 				     1, &creq->creq_db.dbinfo.flags);
2634f830cd8SSiva Reddy Kallam 	}
2644f830cd8SSiva Reddy Kallam 
2654f830cd8SSiva Reddy Kallam 	if (hw_polled)
2664f830cd8SSiva Reddy Kallam 		bng_re_ring_nq_db(&creq->creq_db.dbinfo,
2674f830cd8SSiva Reddy Kallam 				  rcfw->res->cctx, true);
2684f830cd8SSiva Reddy Kallam 	spin_unlock_bh(&hwq->lock);
2694f830cd8SSiva Reddy Kallam 	if (num_wakeup)
2704f830cd8SSiva Reddy Kallam 		wake_up_nr(&rcfw->cmdq.waitq, num_wakeup);
2714f830cd8SSiva Reddy Kallam }
2724f830cd8SSiva Reddy Kallam 
273*53c6ee7dSSiva Reddy Kallam static int __send_message_basic_sanity(struct bng_re_rcfw *rcfw,
274*53c6ee7dSSiva Reddy Kallam 				       struct bng_re_cmdqmsg *msg,
275*53c6ee7dSSiva Reddy Kallam 				       u8 opcode)
276*53c6ee7dSSiva Reddy Kallam {
277*53c6ee7dSSiva Reddy Kallam 	struct bng_re_cmdq_ctx *cmdq;
278*53c6ee7dSSiva Reddy Kallam 
279*53c6ee7dSSiva Reddy Kallam 	cmdq = &rcfw->cmdq;
280*53c6ee7dSSiva Reddy Kallam 
281*53c6ee7dSSiva Reddy Kallam 	if (test_bit(FIRMWARE_STALL_DETECTED, &cmdq->flags))
282*53c6ee7dSSiva Reddy Kallam 		return -ETIMEDOUT;
283*53c6ee7dSSiva Reddy Kallam 
284*53c6ee7dSSiva Reddy Kallam 	if (test_bit(FIRMWARE_INITIALIZED_FLAG, &cmdq->flags) &&
285*53c6ee7dSSiva Reddy Kallam 	    opcode == CMDQ_BASE_OPCODE_INITIALIZE_FW) {
286*53c6ee7dSSiva Reddy Kallam 		dev_err(&rcfw->pdev->dev, "RCFW already initialized!");
287*53c6ee7dSSiva Reddy Kallam 		return -EINVAL;
288*53c6ee7dSSiva Reddy Kallam 	}
289*53c6ee7dSSiva Reddy Kallam 
290*53c6ee7dSSiva Reddy Kallam 	if (!test_bit(FIRMWARE_INITIALIZED_FLAG, &cmdq->flags) &&
291*53c6ee7dSSiva Reddy Kallam 	    (opcode != CMDQ_BASE_OPCODE_QUERY_FUNC &&
292*53c6ee7dSSiva Reddy Kallam 	     opcode != CMDQ_BASE_OPCODE_INITIALIZE_FW &&
293*53c6ee7dSSiva Reddy Kallam 	     opcode != CMDQ_BASE_OPCODE_QUERY_VERSION)) {
294*53c6ee7dSSiva Reddy Kallam 		dev_err(&rcfw->pdev->dev,
295*53c6ee7dSSiva Reddy Kallam 			"RCFW not initialized, reject opcode 0x%x",
296*53c6ee7dSSiva Reddy Kallam 			opcode);
297*53c6ee7dSSiva Reddy Kallam 		return -EOPNOTSUPP;
298*53c6ee7dSSiva Reddy Kallam 	}
299*53c6ee7dSSiva Reddy Kallam 
300*53c6ee7dSSiva Reddy Kallam 	return 0;
301*53c6ee7dSSiva Reddy Kallam }
302*53c6ee7dSSiva Reddy Kallam 
303*53c6ee7dSSiva Reddy Kallam static int __send_message(struct bng_re_rcfw *rcfw,
304*53c6ee7dSSiva Reddy Kallam 			  struct bng_re_cmdqmsg *msg, u8 opcode)
305*53c6ee7dSSiva Reddy Kallam {
306*53c6ee7dSSiva Reddy Kallam 	u32 bsize, free_slots, required_slots;
307*53c6ee7dSSiva Reddy Kallam 	struct bng_re_cmdq_ctx *cmdq;
308*53c6ee7dSSiva Reddy Kallam 	struct bng_re_crsqe *crsqe;
309*53c6ee7dSSiva Reddy Kallam 	struct bng_fw_cmdqe *cmdqe;
310*53c6ee7dSSiva Reddy Kallam 	struct bng_re_hwq *hwq;
311*53c6ee7dSSiva Reddy Kallam 	u32 sw_prod, cmdq_prod;
312*53c6ee7dSSiva Reddy Kallam 	struct pci_dev *pdev;
313*53c6ee7dSSiva Reddy Kallam 	u16 cookie;
314*53c6ee7dSSiva Reddy Kallam 	u8 *preq;
315*53c6ee7dSSiva Reddy Kallam 
316*53c6ee7dSSiva Reddy Kallam 	cmdq = &rcfw->cmdq;
317*53c6ee7dSSiva Reddy Kallam 	hwq = &cmdq->hwq;
318*53c6ee7dSSiva Reddy Kallam 	pdev = rcfw->pdev;
319*53c6ee7dSSiva Reddy Kallam 
320*53c6ee7dSSiva Reddy Kallam 	/* Cmdq are in 16-byte units, each request can consume 1 or more
321*53c6ee7dSSiva Reddy Kallam 	 * cmdqe
322*53c6ee7dSSiva Reddy Kallam 	 */
323*53c6ee7dSSiva Reddy Kallam 	spin_lock_bh(&hwq->lock);
324*53c6ee7dSSiva Reddy Kallam 	required_slots = bng_re_get_cmd_slots(msg->req);
325*53c6ee7dSSiva Reddy Kallam 	free_slots = HWQ_FREE_SLOTS(hwq);
326*53c6ee7dSSiva Reddy Kallam 	cookie = cmdq->seq_num & BNG_FW_MAX_COOKIE_VALUE;
327*53c6ee7dSSiva Reddy Kallam 	crsqe = &rcfw->crsqe_tbl[cookie];
328*53c6ee7dSSiva Reddy Kallam 
329*53c6ee7dSSiva Reddy Kallam 	if (required_slots >= free_slots) {
330*53c6ee7dSSiva Reddy Kallam 		dev_info_ratelimited(&pdev->dev,
331*53c6ee7dSSiva Reddy Kallam 				     "CMDQ is full req/free %d/%d!",
332*53c6ee7dSSiva Reddy Kallam 				     required_slots, free_slots);
333*53c6ee7dSSiva Reddy Kallam 		spin_unlock_bh(&hwq->lock);
334*53c6ee7dSSiva Reddy Kallam 		return -EAGAIN;
335*53c6ee7dSSiva Reddy Kallam 	}
336*53c6ee7dSSiva Reddy Kallam 	__set_cmdq_base_cookie(msg->req, msg->req_sz, cpu_to_le16(cookie));
337*53c6ee7dSSiva Reddy Kallam 
338*53c6ee7dSSiva Reddy Kallam 	bsize = bng_re_set_cmd_slots(msg->req);
339*53c6ee7dSSiva Reddy Kallam 	crsqe->free_slots = free_slots;
340*53c6ee7dSSiva Reddy Kallam 	crsqe->resp = (struct creq_qp_event *)msg->resp;
341*53c6ee7dSSiva Reddy Kallam 	crsqe->is_waiter_alive = true;
342*53c6ee7dSSiva Reddy Kallam 	crsqe->is_in_used = true;
343*53c6ee7dSSiva Reddy Kallam 	crsqe->opcode = opcode;
344*53c6ee7dSSiva Reddy Kallam 
345*53c6ee7dSSiva Reddy Kallam 	crsqe->req_size = __get_cmdq_base_cmd_size(msg->req, msg->req_sz);
346*53c6ee7dSSiva Reddy Kallam 	if (__get_cmdq_base_resp_size(msg->req, msg->req_sz) && msg->sb) {
347*53c6ee7dSSiva Reddy Kallam 		struct bng_re_rcfw_sbuf *sbuf = msg->sb;
348*53c6ee7dSSiva Reddy Kallam 
349*53c6ee7dSSiva Reddy Kallam 		__set_cmdq_base_resp_addr(msg->req, msg->req_sz,
350*53c6ee7dSSiva Reddy Kallam 					  cpu_to_le64(sbuf->dma_addr));
351*53c6ee7dSSiva Reddy Kallam 		__set_cmdq_base_resp_size(msg->req, msg->req_sz,
352*53c6ee7dSSiva Reddy Kallam 					  ALIGN(sbuf->size,
353*53c6ee7dSSiva Reddy Kallam 						BNG_FW_CMDQE_UNITS) /
354*53c6ee7dSSiva Reddy Kallam 						BNG_FW_CMDQE_UNITS);
355*53c6ee7dSSiva Reddy Kallam 	}
356*53c6ee7dSSiva Reddy Kallam 
357*53c6ee7dSSiva Reddy Kallam 	preq = (u8 *)msg->req;
358*53c6ee7dSSiva Reddy Kallam 	do {
359*53c6ee7dSSiva Reddy Kallam 		/* Locate the next cmdq slot */
360*53c6ee7dSSiva Reddy Kallam 		sw_prod = HWQ_CMP(hwq->prod, hwq);
361*53c6ee7dSSiva Reddy Kallam 		cmdqe = bng_re_get_qe(hwq, sw_prod, NULL);
362*53c6ee7dSSiva Reddy Kallam 		/* Copy a segment of the req cmd to the cmdq */
363*53c6ee7dSSiva Reddy Kallam 		memset(cmdqe, 0, sizeof(*cmdqe));
364*53c6ee7dSSiva Reddy Kallam 		memcpy(cmdqe, preq, min_t(u32, bsize, sizeof(*cmdqe)));
365*53c6ee7dSSiva Reddy Kallam 		preq += min_t(u32, bsize, sizeof(*cmdqe));
366*53c6ee7dSSiva Reddy Kallam 		bsize -= min_t(u32, bsize, sizeof(*cmdqe));
367*53c6ee7dSSiva Reddy Kallam 		hwq->prod++;
368*53c6ee7dSSiva Reddy Kallam 	} while (bsize > 0);
369*53c6ee7dSSiva Reddy Kallam 	cmdq->seq_num++;
370*53c6ee7dSSiva Reddy Kallam 
371*53c6ee7dSSiva Reddy Kallam 	cmdq_prod = hwq->prod & 0xFFFF;
372*53c6ee7dSSiva Reddy Kallam 	if (test_bit(FIRMWARE_FIRST_FLAG, &cmdq->flags)) {
373*53c6ee7dSSiva Reddy Kallam 		/* The very first doorbell write
374*53c6ee7dSSiva Reddy Kallam 		 * is required to set this flag
375*53c6ee7dSSiva Reddy Kallam 		 * which prompts the FW to reset
376*53c6ee7dSSiva Reddy Kallam 		 * its internal pointers
377*53c6ee7dSSiva Reddy Kallam 		 */
378*53c6ee7dSSiva Reddy Kallam 		cmdq_prod |= BIT(FIRMWARE_FIRST_FLAG);
379*53c6ee7dSSiva Reddy Kallam 		clear_bit(FIRMWARE_FIRST_FLAG, &cmdq->flags);
380*53c6ee7dSSiva Reddy Kallam 	}
381*53c6ee7dSSiva Reddy Kallam 	/* ring CMDQ DB */
382*53c6ee7dSSiva Reddy Kallam 	wmb();
383*53c6ee7dSSiva Reddy Kallam 	writel(cmdq_prod, cmdq->cmdq_mbox.prod);
384*53c6ee7dSSiva Reddy Kallam 	writel(BNG_FW_CMDQ_TRIG_VAL, cmdq->cmdq_mbox.db);
385*53c6ee7dSSiva Reddy Kallam 	spin_unlock_bh(&hwq->lock);
386*53c6ee7dSSiva Reddy Kallam 	/* Return the CREQ response pointer */
387*53c6ee7dSSiva Reddy Kallam 	return 0;
388*53c6ee7dSSiva Reddy Kallam }
389*53c6ee7dSSiva Reddy Kallam 
390*53c6ee7dSSiva Reddy Kallam /**
391*53c6ee7dSSiva Reddy Kallam  * __wait_for_resp   -	Don't hold the cpu context and wait for response
392*53c6ee7dSSiva Reddy Kallam  * @rcfw:    rcfw channel instance of rdev
393*53c6ee7dSSiva Reddy Kallam  * @cookie:  cookie to track the command
394*53c6ee7dSSiva Reddy Kallam  *
395*53c6ee7dSSiva Reddy Kallam  * Wait for command completion in sleepable context.
396*53c6ee7dSSiva Reddy Kallam  *
397*53c6ee7dSSiva Reddy Kallam  * Returns:
398*53c6ee7dSSiva Reddy Kallam  * 0 if command is completed by firmware.
399*53c6ee7dSSiva Reddy Kallam  * Non zero error code for rest of the case.
400*53c6ee7dSSiva Reddy Kallam  */
401*53c6ee7dSSiva Reddy Kallam static int __wait_for_resp(struct bng_re_rcfw *rcfw, u16 cookie)
402*53c6ee7dSSiva Reddy Kallam {
403*53c6ee7dSSiva Reddy Kallam 	struct bng_re_cmdq_ctx *cmdq;
404*53c6ee7dSSiva Reddy Kallam 	struct bng_re_crsqe *crsqe;
405*53c6ee7dSSiva Reddy Kallam 
406*53c6ee7dSSiva Reddy Kallam 	cmdq = &rcfw->cmdq;
407*53c6ee7dSSiva Reddy Kallam 	crsqe = &rcfw->crsqe_tbl[cookie];
408*53c6ee7dSSiva Reddy Kallam 
409*53c6ee7dSSiva Reddy Kallam 	do {
410*53c6ee7dSSiva Reddy Kallam 		wait_event_timeout(cmdq->waitq,
411*53c6ee7dSSiva Reddy Kallam 				   !crsqe->is_in_used,
412*53c6ee7dSSiva Reddy Kallam 				   secs_to_jiffies(rcfw->max_timeout));
413*53c6ee7dSSiva Reddy Kallam 
414*53c6ee7dSSiva Reddy Kallam 		if (!crsqe->is_in_used)
415*53c6ee7dSSiva Reddy Kallam 			return 0;
416*53c6ee7dSSiva Reddy Kallam 
417*53c6ee7dSSiva Reddy Kallam 		bng_re_service_creq(&rcfw->creq.creq_tasklet);
418*53c6ee7dSSiva Reddy Kallam 
419*53c6ee7dSSiva Reddy Kallam 		if (!crsqe->is_in_used)
420*53c6ee7dSSiva Reddy Kallam 			return 0;
421*53c6ee7dSSiva Reddy Kallam 	} while (true);
422*53c6ee7dSSiva Reddy Kallam };
423*53c6ee7dSSiva Reddy Kallam 
424*53c6ee7dSSiva Reddy Kallam /**
425*53c6ee7dSSiva Reddy Kallam  * bng_re_rcfw_send_message   -	interface to send
426*53c6ee7dSSiva Reddy Kallam  * and complete rcfw command.
427*53c6ee7dSSiva Reddy Kallam  * @rcfw:   rcfw channel instance of rdev
428*53c6ee7dSSiva Reddy Kallam  * @msg:    message to send
429*53c6ee7dSSiva Reddy Kallam  *
430*53c6ee7dSSiva Reddy Kallam  * This function does not account shadow queue depth. It will send
431*53c6ee7dSSiva Reddy Kallam  * all the command unconditionally as long as send queue is not full.
432*53c6ee7dSSiva Reddy Kallam  *
433*53c6ee7dSSiva Reddy Kallam  * Returns:
434*53c6ee7dSSiva Reddy Kallam  * 0 if command completed by firmware.
435*53c6ee7dSSiva Reddy Kallam  * Non zero if the command is not completed by firmware.
436*53c6ee7dSSiva Reddy Kallam  */
437*53c6ee7dSSiva Reddy Kallam int bng_re_rcfw_send_message(struct bng_re_rcfw *rcfw,
438*53c6ee7dSSiva Reddy Kallam 			     struct bng_re_cmdqmsg *msg)
439*53c6ee7dSSiva Reddy Kallam {
440*53c6ee7dSSiva Reddy Kallam 	struct creq_qp_event *evnt = (struct creq_qp_event *)msg->resp;
441*53c6ee7dSSiva Reddy Kallam 	struct bng_re_crsqe *crsqe;
442*53c6ee7dSSiva Reddy Kallam 	u16 cookie;
443*53c6ee7dSSiva Reddy Kallam 	int rc;
444*53c6ee7dSSiva Reddy Kallam 	u8 opcode;
445*53c6ee7dSSiva Reddy Kallam 
446*53c6ee7dSSiva Reddy Kallam 	opcode = __get_cmdq_base_opcode(msg->req, msg->req_sz);
447*53c6ee7dSSiva Reddy Kallam 
448*53c6ee7dSSiva Reddy Kallam 	rc = __send_message_basic_sanity(rcfw, msg, opcode);
449*53c6ee7dSSiva Reddy Kallam 	if (rc)
450*53c6ee7dSSiva Reddy Kallam 		return rc == -ENXIO ? bng_re_map_rc(opcode) : rc;
451*53c6ee7dSSiva Reddy Kallam 
452*53c6ee7dSSiva Reddy Kallam 	rc = __send_message(rcfw, msg, opcode);
453*53c6ee7dSSiva Reddy Kallam 	if (rc)
454*53c6ee7dSSiva Reddy Kallam 		return rc;
455*53c6ee7dSSiva Reddy Kallam 
456*53c6ee7dSSiva Reddy Kallam 	cookie = le16_to_cpu(__get_cmdq_base_cookie(msg->req, msg->req_sz))
457*53c6ee7dSSiva Reddy Kallam 				& BNG_FW_MAX_COOKIE_VALUE;
458*53c6ee7dSSiva Reddy Kallam 
459*53c6ee7dSSiva Reddy Kallam 	rc = __wait_for_resp(rcfw, cookie);
460*53c6ee7dSSiva Reddy Kallam 
461*53c6ee7dSSiva Reddy Kallam 	if (rc) {
462*53c6ee7dSSiva Reddy Kallam 		spin_lock_bh(&rcfw->cmdq.hwq.lock);
463*53c6ee7dSSiva Reddy Kallam 		crsqe = &rcfw->crsqe_tbl[cookie];
464*53c6ee7dSSiva Reddy Kallam 		crsqe->is_waiter_alive = false;
465*53c6ee7dSSiva Reddy Kallam 		if (rc == -ENODEV)
466*53c6ee7dSSiva Reddy Kallam 			set_bit(FIRMWARE_STALL_DETECTED, &rcfw->cmdq.flags);
467*53c6ee7dSSiva Reddy Kallam 		spin_unlock_bh(&rcfw->cmdq.hwq.lock);
468*53c6ee7dSSiva Reddy Kallam 		return -ETIMEDOUT;
469*53c6ee7dSSiva Reddy Kallam 	}
470*53c6ee7dSSiva Reddy Kallam 
471*53c6ee7dSSiva Reddy Kallam 	if (evnt->status) {
472*53c6ee7dSSiva Reddy Kallam 		/* failed with status */
473*53c6ee7dSSiva Reddy Kallam 		dev_err(&rcfw->pdev->dev, "cmdq[%#x]=%#x status %#x\n",
474*53c6ee7dSSiva Reddy Kallam 			cookie, opcode, evnt->status);
475*53c6ee7dSSiva Reddy Kallam 		rc = -EIO;
476*53c6ee7dSSiva Reddy Kallam 	}
477*53c6ee7dSSiva Reddy Kallam 
478*53c6ee7dSSiva Reddy Kallam 	return rc;
479*53c6ee7dSSiva Reddy Kallam }
480*53c6ee7dSSiva Reddy Kallam 
4814f830cd8SSiva Reddy Kallam static int bng_re_map_cmdq_mbox(struct bng_re_rcfw *rcfw)
4824f830cd8SSiva Reddy Kallam {
4834f830cd8SSiva Reddy Kallam 	struct bng_re_cmdq_mbox *mbox;
4844f830cd8SSiva Reddy Kallam 	resource_size_t bar_reg;
4854f830cd8SSiva Reddy Kallam 	struct pci_dev *pdev;
4864f830cd8SSiva Reddy Kallam 
4874f830cd8SSiva Reddy Kallam 	pdev = rcfw->pdev;
4884f830cd8SSiva Reddy Kallam 	mbox = &rcfw->cmdq.cmdq_mbox;
4894f830cd8SSiva Reddy Kallam 
4904f830cd8SSiva Reddy Kallam 	mbox->reg.bar_id = BNG_FW_COMM_PCI_BAR_REGION;
4914f830cd8SSiva Reddy Kallam 	mbox->reg.len = BNG_FW_COMM_SIZE;
4924f830cd8SSiva Reddy Kallam 	mbox->reg.bar_base = pci_resource_start(pdev, mbox->reg.bar_id);
4934f830cd8SSiva Reddy Kallam 	if (!mbox->reg.bar_base) {
4944f830cd8SSiva Reddy Kallam 		dev_err(&pdev->dev,
4954f830cd8SSiva Reddy Kallam 			"CMDQ BAR region %d resc start is 0!\n",
4964f830cd8SSiva Reddy Kallam 			mbox->reg.bar_id);
4974f830cd8SSiva Reddy Kallam 		return -ENOMEM;
4984f830cd8SSiva Reddy Kallam 	}
4994f830cd8SSiva Reddy Kallam 
5004f830cd8SSiva Reddy Kallam 	bar_reg = mbox->reg.bar_base + BNG_FW_COMM_BASE_OFFSET;
5014f830cd8SSiva Reddy Kallam 	mbox->reg.len = BNG_FW_COMM_SIZE;
5024f830cd8SSiva Reddy Kallam 	mbox->reg.bar_reg = ioremap(bar_reg, mbox->reg.len);
5034f830cd8SSiva Reddy Kallam 	if (!mbox->reg.bar_reg) {
5044f830cd8SSiva Reddy Kallam 		dev_err(&pdev->dev,
5054f830cd8SSiva Reddy Kallam 			"CMDQ BAR region %d mapping failed\n",
5064f830cd8SSiva Reddy Kallam 			mbox->reg.bar_id);
5074f830cd8SSiva Reddy Kallam 		return -ENOMEM;
5084f830cd8SSiva Reddy Kallam 	}
5094f830cd8SSiva Reddy Kallam 
5104f830cd8SSiva Reddy Kallam 	mbox->prod = (void  __iomem *)(mbox->reg.bar_reg +
5114f830cd8SSiva Reddy Kallam 			BNG_FW_PF_VF_COMM_PROD_OFFSET);
5124f830cd8SSiva Reddy Kallam 	mbox->db = (void __iomem *)(mbox->reg.bar_reg + BNG_FW_COMM_TRIG_OFFSET);
5134f830cd8SSiva Reddy Kallam 	return 0;
5144f830cd8SSiva Reddy Kallam }
5154f830cd8SSiva Reddy Kallam 
5164f830cd8SSiva Reddy Kallam static irqreturn_t bng_re_creq_irq(int irq, void *dev_instance)
5174f830cd8SSiva Reddy Kallam {
5184f830cd8SSiva Reddy Kallam 	struct bng_re_rcfw *rcfw = dev_instance;
5194f830cd8SSiva Reddy Kallam 	struct bng_re_creq_ctx *creq;
5204f830cd8SSiva Reddy Kallam 	struct bng_re_hwq *hwq;
5214f830cd8SSiva Reddy Kallam 	u32 sw_cons;
5224f830cd8SSiva Reddy Kallam 
5234f830cd8SSiva Reddy Kallam 	creq = &rcfw->creq;
5244f830cd8SSiva Reddy Kallam 	hwq = &creq->hwq;
5254f830cd8SSiva Reddy Kallam 	/* Prefetch the CREQ element */
5264f830cd8SSiva Reddy Kallam 	sw_cons = HWQ_CMP(hwq->cons, hwq);
5274f830cd8SSiva Reddy Kallam 	prefetch(bng_re_get_qe(hwq, sw_cons, NULL));
5284f830cd8SSiva Reddy Kallam 
5294f830cd8SSiva Reddy Kallam 	tasklet_schedule(&creq->creq_tasklet);
5304f830cd8SSiva Reddy Kallam 	return IRQ_HANDLED;
5314f830cd8SSiva Reddy Kallam }
5324f830cd8SSiva Reddy Kallam 
5334f830cd8SSiva Reddy Kallam int bng_re_rcfw_start_irq(struct bng_re_rcfw *rcfw, int msix_vector,
5344f830cd8SSiva Reddy Kallam 			  bool need_init)
5354f830cd8SSiva Reddy Kallam {
5364f830cd8SSiva Reddy Kallam 	struct bng_re_creq_ctx *creq;
5374f830cd8SSiva Reddy Kallam 	struct bng_re_res *res;
5384f830cd8SSiva Reddy Kallam 	int rc;
5394f830cd8SSiva Reddy Kallam 
5404f830cd8SSiva Reddy Kallam 	creq = &rcfw->creq;
5414f830cd8SSiva Reddy Kallam 	res = rcfw->res;
5424f830cd8SSiva Reddy Kallam 
5434f830cd8SSiva Reddy Kallam 	if (creq->irq_handler_avail)
5444f830cd8SSiva Reddy Kallam 		return -EFAULT;
5454f830cd8SSiva Reddy Kallam 
5464f830cd8SSiva Reddy Kallam 	creq->msix_vec = msix_vector;
5474f830cd8SSiva Reddy Kallam 	if (need_init)
5484f830cd8SSiva Reddy Kallam 		tasklet_setup(&creq->creq_tasklet, bng_re_service_creq);
5494f830cd8SSiva Reddy Kallam 	else
5504f830cd8SSiva Reddy Kallam 		tasklet_enable(&creq->creq_tasklet);
5514f830cd8SSiva Reddy Kallam 
5524f830cd8SSiva Reddy Kallam 	creq->irq_name = kasprintf(GFP_KERNEL, "bng_re-creq@pci:%s",
5534f830cd8SSiva Reddy Kallam 				   pci_name(res->pdev));
5544f830cd8SSiva Reddy Kallam 	if (!creq->irq_name)
5554f830cd8SSiva Reddy Kallam 		return -ENOMEM;
5564f830cd8SSiva Reddy Kallam 	rc = request_irq(creq->msix_vec, bng_re_creq_irq, 0,
5574f830cd8SSiva Reddy Kallam 			 creq->irq_name, rcfw);
5584f830cd8SSiva Reddy Kallam 	if (rc) {
5594f830cd8SSiva Reddy Kallam 		kfree(creq->irq_name);
5604f830cd8SSiva Reddy Kallam 		creq->irq_name = NULL;
5614f830cd8SSiva Reddy Kallam 		tasklet_disable(&creq->creq_tasklet);
5624f830cd8SSiva Reddy Kallam 		return rc;
5634f830cd8SSiva Reddy Kallam 	}
5644f830cd8SSiva Reddy Kallam 	creq->irq_handler_avail = true;
5654f830cd8SSiva Reddy Kallam 
5664f830cd8SSiva Reddy Kallam 	bng_re_ring_nq_db(&creq->creq_db.dbinfo, res->cctx, true);
5674f830cd8SSiva Reddy Kallam 	atomic_inc(&rcfw->rcfw_intr_enabled);
5684f830cd8SSiva Reddy Kallam 
5694f830cd8SSiva Reddy Kallam 	return 0;
5704f830cd8SSiva Reddy Kallam }
5714f830cd8SSiva Reddy Kallam 
5724f830cd8SSiva Reddy Kallam static int bng_re_map_creq_db(struct bng_re_rcfw *rcfw, u32 reg_offt)
5734f830cd8SSiva Reddy Kallam {
5744f830cd8SSiva Reddy Kallam 	struct bng_re_creq_db *creq_db;
5754f830cd8SSiva Reddy Kallam 	resource_size_t bar_reg;
5764f830cd8SSiva Reddy Kallam 	struct pci_dev *pdev;
5774f830cd8SSiva Reddy Kallam 
5784f830cd8SSiva Reddy Kallam 	pdev = rcfw->pdev;
5794f830cd8SSiva Reddy Kallam 	creq_db = &rcfw->creq.creq_db;
5804f830cd8SSiva Reddy Kallam 
5814f830cd8SSiva Reddy Kallam 	creq_db->dbinfo.flags = 0;
5824f830cd8SSiva Reddy Kallam 	creq_db->reg.bar_id = BNG_FW_COMM_CONS_PCI_BAR_REGION;
5834f830cd8SSiva Reddy Kallam 	creq_db->reg.bar_base = pci_resource_start(pdev, creq_db->reg.bar_id);
5844f830cd8SSiva Reddy Kallam 	if (!creq_db->reg.bar_id)
5854f830cd8SSiva Reddy Kallam 		dev_err(&pdev->dev,
5864f830cd8SSiva Reddy Kallam 			"CREQ BAR region %d resc start is 0!",
5874f830cd8SSiva Reddy Kallam 			creq_db->reg.bar_id);
5884f830cd8SSiva Reddy Kallam 
5894f830cd8SSiva Reddy Kallam 	bar_reg = creq_db->reg.bar_base + reg_offt;
5904f830cd8SSiva Reddy Kallam 
5914f830cd8SSiva Reddy Kallam 	creq_db->reg.len = BNG_FW_CREQ_DB_LEN;
5924f830cd8SSiva Reddy Kallam 	creq_db->reg.bar_reg = ioremap(bar_reg, creq_db->reg.len);
5934f830cd8SSiva Reddy Kallam 	if (!creq_db->reg.bar_reg) {
5944f830cd8SSiva Reddy Kallam 		dev_err(&pdev->dev,
5954f830cd8SSiva Reddy Kallam 			"CREQ BAR region %d mapping failed",
5964f830cd8SSiva Reddy Kallam 			creq_db->reg.bar_id);
5974f830cd8SSiva Reddy Kallam 		return -ENOMEM;
5984f830cd8SSiva Reddy Kallam 	}
5994f830cd8SSiva Reddy Kallam 	creq_db->dbinfo.db = creq_db->reg.bar_reg;
6004f830cd8SSiva Reddy Kallam 	creq_db->dbinfo.hwq = &rcfw->creq.hwq;
6014f830cd8SSiva Reddy Kallam 	creq_db->dbinfo.xid = rcfw->creq.ring_id;
6024f830cd8SSiva Reddy Kallam 	return 0;
6034f830cd8SSiva Reddy Kallam }
6044f830cd8SSiva Reddy Kallam 
6054f830cd8SSiva Reddy Kallam void bng_re_rcfw_stop_irq(struct bng_re_rcfw *rcfw, bool kill)
6064f830cd8SSiva Reddy Kallam {
6074f830cd8SSiva Reddy Kallam 	struct bng_re_creq_ctx *creq;
6084f830cd8SSiva Reddy Kallam 
6094f830cd8SSiva Reddy Kallam 	creq = &rcfw->creq;
6104f830cd8SSiva Reddy Kallam 
6114f830cd8SSiva Reddy Kallam 	if (!creq->irq_handler_avail)
6124f830cd8SSiva Reddy Kallam 		return;
6134f830cd8SSiva Reddy Kallam 
6144f830cd8SSiva Reddy Kallam 	creq->irq_handler_avail = false;
6154f830cd8SSiva Reddy Kallam 	/* Mask h/w interrupts */
6164f830cd8SSiva Reddy Kallam 	bng_re_ring_nq_db(&creq->creq_db.dbinfo, rcfw->res->cctx, false);
6174f830cd8SSiva Reddy Kallam 	/* Sync with last running IRQ-handler */
6184f830cd8SSiva Reddy Kallam 	synchronize_irq(creq->msix_vec);
6194f830cd8SSiva Reddy Kallam 	free_irq(creq->msix_vec, rcfw);
6204f830cd8SSiva Reddy Kallam 	kfree(creq->irq_name);
6214f830cd8SSiva Reddy Kallam 	creq->irq_name = NULL;
6224f830cd8SSiva Reddy Kallam 	atomic_set(&rcfw->rcfw_intr_enabled, 0);
6234f830cd8SSiva Reddy Kallam 	if (kill)
6244f830cd8SSiva Reddy Kallam 		tasklet_kill(&creq->creq_tasklet);
6254f830cd8SSiva Reddy Kallam 	tasklet_disable(&creq->creq_tasklet);
6264f830cd8SSiva Reddy Kallam }
6274f830cd8SSiva Reddy Kallam 
6284f830cd8SSiva Reddy Kallam void bng_re_disable_rcfw_channel(struct bng_re_rcfw *rcfw)
6294f830cd8SSiva Reddy Kallam {
6304f830cd8SSiva Reddy Kallam 	struct bng_re_creq_ctx *creq;
6314f830cd8SSiva Reddy Kallam 	struct bng_re_cmdq_ctx *cmdq;
6324f830cd8SSiva Reddy Kallam 
6334f830cd8SSiva Reddy Kallam 	creq = &rcfw->creq;
6344f830cd8SSiva Reddy Kallam 	cmdq = &rcfw->cmdq;
6354f830cd8SSiva Reddy Kallam 	/* Make sure the HW channel is stopped! */
6364f830cd8SSiva Reddy Kallam 	bng_re_rcfw_stop_irq(rcfw, true);
6374f830cd8SSiva Reddy Kallam 
6384f830cd8SSiva Reddy Kallam 	iounmap(cmdq->cmdq_mbox.reg.bar_reg);
6394f830cd8SSiva Reddy Kallam 	iounmap(creq->creq_db.reg.bar_reg);
6404f830cd8SSiva Reddy Kallam 
6414f830cd8SSiva Reddy Kallam 	cmdq->cmdq_mbox.reg.bar_reg = NULL;
6424f830cd8SSiva Reddy Kallam 	creq->creq_db.reg.bar_reg = NULL;
6434f830cd8SSiva Reddy Kallam 	creq->msix_vec = 0;
6444f830cd8SSiva Reddy Kallam }
6454f830cd8SSiva Reddy Kallam 
646*53c6ee7dSSiva Reddy Kallam static void bng_re_start_rcfw(struct bng_re_rcfw *rcfw)
647*53c6ee7dSSiva Reddy Kallam {
648*53c6ee7dSSiva Reddy Kallam 	struct bng_re_cmdq_ctx *cmdq;
649*53c6ee7dSSiva Reddy Kallam 	struct bng_re_creq_ctx *creq;
650*53c6ee7dSSiva Reddy Kallam 	struct bng_re_cmdq_mbox *mbox;
651*53c6ee7dSSiva Reddy Kallam 	struct cmdq_init init = {0};
652*53c6ee7dSSiva Reddy Kallam 
653*53c6ee7dSSiva Reddy Kallam 	cmdq = &rcfw->cmdq;
654*53c6ee7dSSiva Reddy Kallam 	creq = &rcfw->creq;
655*53c6ee7dSSiva Reddy Kallam 	mbox = &cmdq->cmdq_mbox;
656*53c6ee7dSSiva Reddy Kallam 
657*53c6ee7dSSiva Reddy Kallam 	init.cmdq_pbl = cpu_to_le64(cmdq->hwq.pbl[BNG_PBL_LVL_0].pg_map_arr[0]);
658*53c6ee7dSSiva Reddy Kallam 	init.cmdq_size_cmdq_lvl =
659*53c6ee7dSSiva Reddy Kallam 			cpu_to_le16(((rcfw->cmdq_depth <<
660*53c6ee7dSSiva Reddy Kallam 				      CMDQ_INIT_CMDQ_SIZE_SFT) &
661*53c6ee7dSSiva Reddy Kallam 				    CMDQ_INIT_CMDQ_SIZE_MASK) |
662*53c6ee7dSSiva Reddy Kallam 				    ((cmdq->hwq.level <<
663*53c6ee7dSSiva Reddy Kallam 				      CMDQ_INIT_CMDQ_LVL_SFT) &
664*53c6ee7dSSiva Reddy Kallam 				    CMDQ_INIT_CMDQ_LVL_MASK));
665*53c6ee7dSSiva Reddy Kallam 	init.creq_ring_id = cpu_to_le16(creq->ring_id);
666*53c6ee7dSSiva Reddy Kallam 	/* Write to the mailbox register */
667*53c6ee7dSSiva Reddy Kallam 	__iowrite32_copy(mbox->reg.bar_reg, &init, sizeof(init) / 4);
668*53c6ee7dSSiva Reddy Kallam }
669*53c6ee7dSSiva Reddy Kallam 
6704f830cd8SSiva Reddy Kallam int bng_re_enable_fw_channel(struct bng_re_rcfw *rcfw,
6714f830cd8SSiva Reddy Kallam 			     int msix_vector,
6724f830cd8SSiva Reddy Kallam 			     int cp_bar_reg_off)
6734f830cd8SSiva Reddy Kallam {
6744f830cd8SSiva Reddy Kallam 	struct bng_re_cmdq_ctx *cmdq;
6754f830cd8SSiva Reddy Kallam 	int rc;
6764f830cd8SSiva Reddy Kallam 
6774f830cd8SSiva Reddy Kallam 	cmdq = &rcfw->cmdq;
6784f830cd8SSiva Reddy Kallam 
6794f830cd8SSiva Reddy Kallam 	/* Assign defaults */
6804f830cd8SSiva Reddy Kallam 	cmdq->seq_num = 0;
6814f830cd8SSiva Reddy Kallam 	set_bit(FIRMWARE_FIRST_FLAG, &cmdq->flags);
6824f830cd8SSiva Reddy Kallam 	init_waitqueue_head(&cmdq->waitq);
6834f830cd8SSiva Reddy Kallam 
6844f830cd8SSiva Reddy Kallam 	rc = bng_re_map_cmdq_mbox(rcfw);
6854f830cd8SSiva Reddy Kallam 	if (rc)
6864f830cd8SSiva Reddy Kallam 		return rc;
6874f830cd8SSiva Reddy Kallam 
6884f830cd8SSiva Reddy Kallam 	rc = bng_re_map_creq_db(rcfw, cp_bar_reg_off);
6894f830cd8SSiva Reddy Kallam 	if (rc)
6904f830cd8SSiva Reddy Kallam 		return rc;
6914f830cd8SSiva Reddy Kallam 
6924f830cd8SSiva Reddy Kallam 	rc = bng_re_rcfw_start_irq(rcfw, msix_vector, true);
6934f830cd8SSiva Reddy Kallam 	if (rc) {
6944f830cd8SSiva Reddy Kallam 		dev_err(&rcfw->pdev->dev,
6954f830cd8SSiva Reddy Kallam 			"Failed to request IRQ for CREQ rc = 0x%x\n", rc);
6964f830cd8SSiva Reddy Kallam 		bng_re_disable_rcfw_channel(rcfw);
6974f830cd8SSiva Reddy Kallam 		return rc;
6984f830cd8SSiva Reddy Kallam 	}
6994f830cd8SSiva Reddy Kallam 
700*53c6ee7dSSiva Reddy Kallam 	bng_re_start_rcfw(rcfw);
7014f830cd8SSiva Reddy Kallam 	return 0;
7024f830cd8SSiva Reddy Kallam }
703