xref: /linux/drivers/infiniband/hw/bng_re/bng_fw.c (revision 155c9971fa88a6655431476f024566fcd9ddcdb6)
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"
804e031ffSSiva Reddy Kallam #include "bng_sp.h"
953310b69SSiva Reddy Kallam 
1053c6ee7dSSiva Reddy Kallam /**
1153c6ee7dSSiva Reddy Kallam  * bng_re_map_rc  -  map return type based on opcode
1253c6ee7dSSiva Reddy Kallam  * @opcode:  roce slow path opcode
1353c6ee7dSSiva Reddy Kallam  *
1453c6ee7dSSiva Reddy Kallam  * case #1
1553c6ee7dSSiva Reddy Kallam  * Firmware initiated error recovery is a safe state machine and
1653c6ee7dSSiva Reddy Kallam  * driver can consider all the underlying rdma resources are free.
1753c6ee7dSSiva Reddy Kallam  * In this state, it is safe to return success for opcodes related to
1853c6ee7dSSiva Reddy Kallam  * destroying rdma resources (like destroy qp, destroy cq etc.).
1953c6ee7dSSiva Reddy Kallam  *
2053c6ee7dSSiva Reddy Kallam  * case #2
2153c6ee7dSSiva Reddy Kallam  * If driver detect potential firmware stall, it is not safe state machine
2253c6ee7dSSiva Reddy Kallam  * and the driver can not consider all the underlying rdma resources are
2353c6ee7dSSiva Reddy Kallam  * freed.
2453c6ee7dSSiva Reddy Kallam  * In this state, it is not safe to return success for opcodes related to
2553c6ee7dSSiva Reddy Kallam  * destroying rdma resources (like destroy qp, destroy cq etc.).
2653c6ee7dSSiva Reddy Kallam  *
2753c6ee7dSSiva Reddy Kallam  * Scope of this helper function is only for case #1.
2853c6ee7dSSiva Reddy Kallam  *
2953c6ee7dSSiva Reddy Kallam  * Returns:
3053c6ee7dSSiva Reddy Kallam  * 0 to communicate success to caller.
3153c6ee7dSSiva Reddy Kallam  * Non zero error code to communicate failure to caller.
3253c6ee7dSSiva Reddy Kallam  */
3353c6ee7dSSiva Reddy Kallam static int bng_re_map_rc(u8 opcode)
3453c6ee7dSSiva Reddy Kallam {
3553c6ee7dSSiva Reddy Kallam 	switch (opcode) {
3653c6ee7dSSiva Reddy Kallam 	case CMDQ_BASE_OPCODE_DESTROY_QP:
3753c6ee7dSSiva Reddy Kallam 	case CMDQ_BASE_OPCODE_DESTROY_SRQ:
3853c6ee7dSSiva Reddy Kallam 	case CMDQ_BASE_OPCODE_DESTROY_CQ:
3953c6ee7dSSiva Reddy Kallam 	case CMDQ_BASE_OPCODE_DEALLOCATE_KEY:
4053c6ee7dSSiva Reddy Kallam 	case CMDQ_BASE_OPCODE_DEREGISTER_MR:
4153c6ee7dSSiva Reddy Kallam 	case CMDQ_BASE_OPCODE_DELETE_GID:
4253c6ee7dSSiva Reddy Kallam 	case CMDQ_BASE_OPCODE_DESTROY_QP1:
4353c6ee7dSSiva Reddy Kallam 	case CMDQ_BASE_OPCODE_DESTROY_AH:
4453c6ee7dSSiva Reddy Kallam 	case CMDQ_BASE_OPCODE_DEINITIALIZE_FW:
4553c6ee7dSSiva Reddy Kallam 	case CMDQ_BASE_OPCODE_MODIFY_ROCE_CC:
4653c6ee7dSSiva Reddy Kallam 	case CMDQ_BASE_OPCODE_SET_LINK_AGGR_MODE:
4753c6ee7dSSiva Reddy Kallam 		return 0;
4853c6ee7dSSiva Reddy Kallam 	default:
4953c6ee7dSSiva Reddy Kallam 		return -ETIMEDOUT;
5053c6ee7dSSiva Reddy Kallam 	}
5153c6ee7dSSiva Reddy Kallam }
5253c6ee7dSSiva Reddy Kallam 
5353310b69SSiva Reddy Kallam void bng_re_free_rcfw_channel(struct bng_re_rcfw *rcfw)
5453310b69SSiva Reddy Kallam {
5553310b69SSiva Reddy Kallam 	kfree(rcfw->crsqe_tbl);
5653310b69SSiva Reddy Kallam 	bng_re_free_hwq(rcfw->res, &rcfw->cmdq.hwq);
5753310b69SSiva Reddy Kallam 	bng_re_free_hwq(rcfw->res, &rcfw->creq.hwq);
5853310b69SSiva Reddy Kallam 	rcfw->pdev = NULL;
5953310b69SSiva Reddy Kallam }
6053310b69SSiva Reddy Kallam 
6153310b69SSiva Reddy Kallam int bng_re_alloc_fw_channel(struct bng_re_res *res,
6253310b69SSiva Reddy Kallam 			    struct bng_re_rcfw *rcfw)
6353310b69SSiva Reddy Kallam {
6453310b69SSiva Reddy Kallam 	struct bng_re_hwq_attr hwq_attr = {};
6553310b69SSiva Reddy Kallam 	struct bng_re_sg_info sginfo = {};
6653310b69SSiva Reddy Kallam 	struct bng_re_cmdq_ctx *cmdq;
6753310b69SSiva Reddy Kallam 	struct bng_re_creq_ctx *creq;
6853310b69SSiva Reddy Kallam 
6953310b69SSiva Reddy Kallam 	rcfw->pdev = res->pdev;
7053310b69SSiva Reddy Kallam 	cmdq = &rcfw->cmdq;
7153310b69SSiva Reddy Kallam 	creq = &rcfw->creq;
7253310b69SSiva Reddy Kallam 	rcfw->res = res;
7353310b69SSiva Reddy Kallam 
7453310b69SSiva Reddy Kallam 	sginfo.pgsize = PAGE_SIZE;
7553310b69SSiva Reddy Kallam 	sginfo.pgshft = PAGE_SHIFT;
7653310b69SSiva Reddy Kallam 
7753310b69SSiva Reddy Kallam 	hwq_attr.sginfo = &sginfo;
7853310b69SSiva Reddy Kallam 	hwq_attr.res = rcfw->res;
7953310b69SSiva Reddy Kallam 	hwq_attr.depth = BNG_FW_CREQE_MAX_CNT;
8053310b69SSiva Reddy Kallam 	hwq_attr.stride = BNG_FW_CREQE_UNITS;
8153310b69SSiva Reddy Kallam 	hwq_attr.type = BNG_HWQ_TYPE_QUEUE;
8253310b69SSiva Reddy Kallam 
8353310b69SSiva Reddy Kallam 	if (bng_re_alloc_init_hwq(&creq->hwq, &hwq_attr)) {
8453310b69SSiva Reddy Kallam 		dev_err(&rcfw->pdev->dev,
8553310b69SSiva Reddy Kallam 			"HW channel CREQ allocation failed\n");
8653310b69SSiva Reddy Kallam 		goto fail;
8753310b69SSiva Reddy Kallam 	}
8853310b69SSiva Reddy Kallam 
8953310b69SSiva Reddy Kallam 	rcfw->cmdq_depth = BNG_FW_CMDQE_MAX_CNT;
9053310b69SSiva Reddy Kallam 
9153310b69SSiva Reddy Kallam 	sginfo.pgsize = bng_fw_cmdqe_page_size(rcfw->cmdq_depth);
9253310b69SSiva Reddy Kallam 	hwq_attr.depth = rcfw->cmdq_depth & 0x7FFFFFFF;
9353310b69SSiva Reddy Kallam 	hwq_attr.stride = BNG_FW_CMDQE_UNITS;
9453310b69SSiva Reddy Kallam 	hwq_attr.type = BNG_HWQ_TYPE_CTX;
9553310b69SSiva Reddy Kallam 	if (bng_re_alloc_init_hwq(&cmdq->hwq, &hwq_attr)) {
9653310b69SSiva Reddy Kallam 		dev_err(&rcfw->pdev->dev,
9753310b69SSiva Reddy Kallam 			"HW channel CMDQ allocation failed\n");
9853310b69SSiva Reddy Kallam 		goto fail;
9953310b69SSiva Reddy Kallam 	}
10053310b69SSiva Reddy Kallam 
10153310b69SSiva Reddy Kallam 	rcfw->crsqe_tbl = kcalloc(cmdq->hwq.max_elements,
10253310b69SSiva Reddy Kallam 				  sizeof(*rcfw->crsqe_tbl), GFP_KERNEL);
10353310b69SSiva Reddy Kallam 	if (!rcfw->crsqe_tbl)
10453310b69SSiva Reddy Kallam 		goto fail;
10553310b69SSiva Reddy Kallam 
10653310b69SSiva Reddy Kallam 	spin_lock_init(&rcfw->tbl_lock);
10753310b69SSiva Reddy Kallam 
10853310b69SSiva Reddy Kallam 	rcfw->max_timeout = res->cctx->hwrm_cmd_max_timeout;
10953310b69SSiva Reddy Kallam 	return 0;
11053310b69SSiva Reddy Kallam 
11153310b69SSiva Reddy Kallam fail:
11253310b69SSiva Reddy Kallam 	bng_re_free_rcfw_channel(rcfw);
11353310b69SSiva Reddy Kallam 	return -ENOMEM;
11453310b69SSiva Reddy Kallam }
1154f830cd8SSiva Reddy Kallam 
1164f830cd8SSiva Reddy Kallam static int bng_re_process_qp_event(struct bng_re_rcfw *rcfw,
1174f830cd8SSiva Reddy Kallam 				   struct creq_qp_event *qp_event,
1184f830cd8SSiva Reddy Kallam 				   u32 *num_wait)
1194f830cd8SSiva Reddy Kallam {
1204f830cd8SSiva Reddy Kallam 	struct bng_re_hwq *hwq = &rcfw->cmdq.hwq;
1214f830cd8SSiva Reddy Kallam 	struct bng_re_crsqe *crsqe;
1224f830cd8SSiva Reddy Kallam 	u32 req_size;
1234f830cd8SSiva Reddy Kallam 	u16 cookie;
1244f830cd8SSiva Reddy Kallam 	bool is_waiter_alive;
1254f830cd8SSiva Reddy Kallam 	struct pci_dev *pdev;
1264f830cd8SSiva Reddy Kallam 	u32 wait_cmds = 0;
1274f830cd8SSiva Reddy Kallam 	int rc = 0;
1284f830cd8SSiva Reddy Kallam 
1294f830cd8SSiva Reddy Kallam 	pdev = rcfw->pdev;
1304f830cd8SSiva Reddy Kallam 	switch (qp_event->event) {
1314f830cd8SSiva Reddy Kallam 	case CREQ_QP_EVENT_EVENT_QP_ERROR_NOTIFICATION:
1324f830cd8SSiva Reddy Kallam 		dev_err(&pdev->dev, "Received QP error notification\n");
1334f830cd8SSiva Reddy Kallam 		break;
1344f830cd8SSiva Reddy Kallam 	default:
1354f830cd8SSiva Reddy Kallam 		/*
1364f830cd8SSiva Reddy Kallam 		 * Command Response
1374f830cd8SSiva Reddy Kallam 		 * cmdq->lock needs to be acquired to synchronie
1384f830cd8SSiva Reddy Kallam 		 * the command send and completion reaping. This function
1394f830cd8SSiva Reddy Kallam 		 * is always called with creq->lock held. Using
1404f830cd8SSiva Reddy Kallam 		 * the nested variant of spin_lock.
1414f830cd8SSiva Reddy Kallam 		 *
1424f830cd8SSiva Reddy Kallam 		 */
1434f830cd8SSiva Reddy Kallam 
1444f830cd8SSiva Reddy Kallam 		spin_lock_nested(&hwq->lock, SINGLE_DEPTH_NESTING);
1454f830cd8SSiva Reddy Kallam 		cookie = le16_to_cpu(qp_event->cookie);
1464f830cd8SSiva Reddy Kallam 		cookie &= BNG_FW_MAX_COOKIE_VALUE;
1474f830cd8SSiva Reddy Kallam 		crsqe = &rcfw->crsqe_tbl[cookie];
1484f830cd8SSiva Reddy Kallam 
1494f830cd8SSiva Reddy Kallam 		if (WARN_ONCE(test_bit(FIRMWARE_STALL_DETECTED,
1504f830cd8SSiva Reddy Kallam 				       &rcfw->cmdq.flags),
1514f830cd8SSiva Reddy Kallam 		    "Unreponsive rcfw channel detected.!!")) {
1524f830cd8SSiva Reddy Kallam 			dev_info(&pdev->dev,
1534f830cd8SSiva Reddy Kallam 				 "rcfw timedout: cookie = %#x, free_slots = %d",
1544f830cd8SSiva Reddy Kallam 				 cookie, crsqe->free_slots);
1554f830cd8SSiva Reddy Kallam 			spin_unlock(&hwq->lock);
1564f830cd8SSiva Reddy Kallam 			return rc;
1574f830cd8SSiva Reddy Kallam 		}
1584f830cd8SSiva Reddy Kallam 
1594f830cd8SSiva Reddy Kallam 		if (crsqe->is_waiter_alive) {
1604f830cd8SSiva Reddy Kallam 			if (crsqe->resp) {
1614f830cd8SSiva Reddy Kallam 				memcpy(crsqe->resp, qp_event, sizeof(*qp_event));
1624f830cd8SSiva Reddy Kallam 				/* Insert write memory barrier to ensure that
1634f830cd8SSiva Reddy Kallam 				 * response data is copied before clearing the
1644f830cd8SSiva Reddy Kallam 				 * flags
1654f830cd8SSiva Reddy Kallam 				 */
1664f830cd8SSiva Reddy Kallam 				smp_wmb();
1674f830cd8SSiva Reddy Kallam 			}
1684f830cd8SSiva Reddy Kallam 		}
1694f830cd8SSiva Reddy Kallam 
1704f830cd8SSiva Reddy Kallam 		wait_cmds++;
1714f830cd8SSiva Reddy Kallam 
1724f830cd8SSiva Reddy Kallam 		req_size = crsqe->req_size;
1734f830cd8SSiva Reddy Kallam 		is_waiter_alive = crsqe->is_waiter_alive;
1744f830cd8SSiva Reddy Kallam 
1754f830cd8SSiva Reddy Kallam 		crsqe->req_size = 0;
1764f830cd8SSiva Reddy Kallam 		if (!is_waiter_alive)
1774f830cd8SSiva Reddy Kallam 			crsqe->resp = NULL;
1784f830cd8SSiva Reddy Kallam 
1794f830cd8SSiva Reddy Kallam 		crsqe->is_in_used = false;
1804f830cd8SSiva Reddy Kallam 
1814f830cd8SSiva Reddy Kallam 		hwq->cons += req_size;
1824f830cd8SSiva Reddy Kallam 
1834f830cd8SSiva Reddy Kallam 		spin_unlock(&hwq->lock);
1844f830cd8SSiva Reddy Kallam 	}
1854f830cd8SSiva Reddy Kallam 	*num_wait += wait_cmds;
1864f830cd8SSiva Reddy Kallam 	return rc;
1874f830cd8SSiva Reddy Kallam }
1884f830cd8SSiva Reddy Kallam 
1894f830cd8SSiva Reddy Kallam /* function events */
1904f830cd8SSiva Reddy Kallam static int bng_re_process_func_event(struct bng_re_rcfw *rcfw,
1914f830cd8SSiva Reddy Kallam 				     struct creq_func_event *func_event)
1924f830cd8SSiva Reddy Kallam {
1934f830cd8SSiva Reddy Kallam 	switch (func_event->event) {
1944f830cd8SSiva Reddy Kallam 	case CREQ_FUNC_EVENT_EVENT_TX_WQE_ERROR:
1954f830cd8SSiva Reddy Kallam 	case CREQ_FUNC_EVENT_EVENT_TX_DATA_ERROR:
1964f830cd8SSiva Reddy Kallam 	case CREQ_FUNC_EVENT_EVENT_RX_WQE_ERROR:
1974f830cd8SSiva Reddy Kallam 	case CREQ_FUNC_EVENT_EVENT_RX_DATA_ERROR:
1984f830cd8SSiva Reddy Kallam 	case CREQ_FUNC_EVENT_EVENT_CQ_ERROR:
1994f830cd8SSiva Reddy Kallam 	case CREQ_FUNC_EVENT_EVENT_TQM_ERROR:
2004f830cd8SSiva Reddy Kallam 	case CREQ_FUNC_EVENT_EVENT_CFCQ_ERROR:
2014f830cd8SSiva Reddy Kallam 	case CREQ_FUNC_EVENT_EVENT_CFCS_ERROR:
2024f830cd8SSiva Reddy Kallam 	case CREQ_FUNC_EVENT_EVENT_CFCC_ERROR:
2034f830cd8SSiva Reddy Kallam 	case CREQ_FUNC_EVENT_EVENT_CFCM_ERROR:
2044f830cd8SSiva Reddy Kallam 	case CREQ_FUNC_EVENT_EVENT_TIM_ERROR:
2054f830cd8SSiva Reddy Kallam 	case CREQ_FUNC_EVENT_EVENT_VF_COMM_REQUEST:
2064f830cd8SSiva Reddy Kallam 	case CREQ_FUNC_EVENT_EVENT_RESOURCE_EXHAUSTED:
2074f830cd8SSiva Reddy Kallam 		break;
2084f830cd8SSiva Reddy Kallam 	default:
2094f830cd8SSiva Reddy Kallam 		return -EINVAL;
2104f830cd8SSiva Reddy Kallam 	}
2114f830cd8SSiva Reddy Kallam 
2124f830cd8SSiva Reddy Kallam 	return 0;
2134f830cd8SSiva Reddy Kallam }
2144f830cd8SSiva Reddy Kallam 
2154f830cd8SSiva Reddy Kallam /* CREQ Completion handlers */
2164f830cd8SSiva Reddy Kallam static void bng_re_service_creq(struct tasklet_struct *t)
2174f830cd8SSiva Reddy Kallam {
2184f830cd8SSiva Reddy Kallam 	struct bng_re_rcfw *rcfw = from_tasklet(rcfw, t, creq.creq_tasklet);
2194f830cd8SSiva Reddy Kallam 	struct bng_re_creq_ctx *creq = &rcfw->creq;
2204f830cd8SSiva Reddy Kallam 	u32 type, budget = BNG_FW_CREQ_ENTRY_POLL_BUDGET;
2214f830cd8SSiva Reddy Kallam 	struct bng_re_hwq *hwq = &creq->hwq;
2224f830cd8SSiva Reddy Kallam 	struct creq_base *creqe;
2234f830cd8SSiva Reddy Kallam 	u32 num_wakeup = 0;
2244f830cd8SSiva Reddy Kallam 	u32 hw_polled = 0;
2254f830cd8SSiva Reddy Kallam 
2264f830cd8SSiva Reddy Kallam 	/* Service the CREQ until budget is over */
2274f830cd8SSiva Reddy Kallam 	spin_lock_bh(&hwq->lock);
2284f830cd8SSiva Reddy Kallam 	while (budget > 0) {
2294f830cd8SSiva Reddy Kallam 		creqe = bng_re_get_qe(hwq, hwq->cons, NULL);
2304f830cd8SSiva Reddy Kallam 		if (!BNG_FW_CREQ_CMP_VALID(creqe, creq->creq_db.dbinfo.flags))
2314f830cd8SSiva Reddy Kallam 			break;
2324f830cd8SSiva Reddy Kallam 		/* The valid test of the entry must be done first before
2334f830cd8SSiva Reddy Kallam 		 * reading any further.
2344f830cd8SSiva Reddy Kallam 		 */
2354f830cd8SSiva Reddy Kallam 		dma_rmb();
2364f830cd8SSiva Reddy Kallam 
2374f830cd8SSiva Reddy Kallam 		type = creqe->type & CREQ_BASE_TYPE_MASK;
2384f830cd8SSiva Reddy Kallam 		switch (type) {
2394f830cd8SSiva Reddy Kallam 		case CREQ_BASE_TYPE_QP_EVENT:
2404f830cd8SSiva Reddy Kallam 			bng_re_process_qp_event
2414f830cd8SSiva Reddy Kallam 				(rcfw, (struct creq_qp_event *)creqe,
2424f830cd8SSiva Reddy Kallam 				 &num_wakeup);
2434f830cd8SSiva Reddy Kallam 			creq->stats.creq_qp_event_processed++;
2444f830cd8SSiva Reddy Kallam 			break;
2454f830cd8SSiva Reddy Kallam 		case CREQ_BASE_TYPE_FUNC_EVENT:
2464f830cd8SSiva Reddy Kallam 			if (!bng_re_process_func_event
2474f830cd8SSiva Reddy Kallam 			    (rcfw, (struct creq_func_event *)creqe))
2484f830cd8SSiva Reddy Kallam 				creq->stats.creq_func_event_processed++;
2494f830cd8SSiva Reddy Kallam 			else
2504f830cd8SSiva Reddy Kallam 				dev_warn(&rcfw->pdev->dev,
2514f830cd8SSiva Reddy Kallam 					 "aeqe:%#x Not handled\n", type);
2524f830cd8SSiva Reddy Kallam 			break;
2534f830cd8SSiva Reddy Kallam 		default:
2544f830cd8SSiva Reddy Kallam 			if (type != ASYNC_EVENT_CMPL_TYPE_HWRM_ASYNC_EVENT)
2554f830cd8SSiva Reddy Kallam 				dev_warn(&rcfw->pdev->dev,
2564f830cd8SSiva Reddy Kallam 					 "creqe with event 0x%x not handled\n",
2574f830cd8SSiva Reddy Kallam 					 type);
2584f830cd8SSiva Reddy Kallam 			break;
2594f830cd8SSiva Reddy Kallam 		}
2604f830cd8SSiva Reddy Kallam 		budget--;
2614f830cd8SSiva Reddy Kallam 		hw_polled++;
2624f830cd8SSiva Reddy Kallam 		bng_re_hwq_incr_cons(hwq->max_elements, &hwq->cons,
2634f830cd8SSiva Reddy Kallam 				     1, &creq->creq_db.dbinfo.flags);
2644f830cd8SSiva Reddy Kallam 	}
2654f830cd8SSiva Reddy Kallam 
2664f830cd8SSiva Reddy Kallam 	if (hw_polled)
2674f830cd8SSiva Reddy Kallam 		bng_re_ring_nq_db(&creq->creq_db.dbinfo,
2684f830cd8SSiva Reddy Kallam 				  rcfw->res->cctx, true);
2694f830cd8SSiva Reddy Kallam 	spin_unlock_bh(&hwq->lock);
2704f830cd8SSiva Reddy Kallam 	if (num_wakeup)
2714f830cd8SSiva Reddy Kallam 		wake_up_nr(&rcfw->cmdq.waitq, num_wakeup);
2724f830cd8SSiva Reddy Kallam }
2734f830cd8SSiva Reddy Kallam 
27453c6ee7dSSiva Reddy Kallam static int __send_message_basic_sanity(struct bng_re_rcfw *rcfw,
27553c6ee7dSSiva Reddy Kallam 				       struct bng_re_cmdqmsg *msg,
27653c6ee7dSSiva Reddy Kallam 				       u8 opcode)
27753c6ee7dSSiva Reddy Kallam {
27853c6ee7dSSiva Reddy Kallam 	struct bng_re_cmdq_ctx *cmdq;
27953c6ee7dSSiva Reddy Kallam 
28053c6ee7dSSiva Reddy Kallam 	cmdq = &rcfw->cmdq;
28153c6ee7dSSiva Reddy Kallam 
28253c6ee7dSSiva Reddy Kallam 	if (test_bit(FIRMWARE_STALL_DETECTED, &cmdq->flags))
28353c6ee7dSSiva Reddy Kallam 		return -ETIMEDOUT;
28453c6ee7dSSiva Reddy Kallam 
28553c6ee7dSSiva Reddy Kallam 	if (test_bit(FIRMWARE_INITIALIZED_FLAG, &cmdq->flags) &&
28653c6ee7dSSiva Reddy Kallam 	    opcode == CMDQ_BASE_OPCODE_INITIALIZE_FW) {
28753c6ee7dSSiva Reddy Kallam 		dev_err(&rcfw->pdev->dev, "RCFW already initialized!");
28853c6ee7dSSiva Reddy Kallam 		return -EINVAL;
28953c6ee7dSSiva Reddy Kallam 	}
29053c6ee7dSSiva Reddy Kallam 
29153c6ee7dSSiva Reddy Kallam 	if (!test_bit(FIRMWARE_INITIALIZED_FLAG, &cmdq->flags) &&
29253c6ee7dSSiva Reddy Kallam 	    (opcode != CMDQ_BASE_OPCODE_QUERY_FUNC &&
29353c6ee7dSSiva Reddy Kallam 	     opcode != CMDQ_BASE_OPCODE_INITIALIZE_FW &&
29453c6ee7dSSiva Reddy Kallam 	     opcode != CMDQ_BASE_OPCODE_QUERY_VERSION)) {
29553c6ee7dSSiva Reddy Kallam 		dev_err(&rcfw->pdev->dev,
29653c6ee7dSSiva Reddy Kallam 			"RCFW not initialized, reject opcode 0x%x",
29753c6ee7dSSiva Reddy Kallam 			opcode);
29853c6ee7dSSiva Reddy Kallam 		return -EOPNOTSUPP;
29953c6ee7dSSiva Reddy Kallam 	}
30053c6ee7dSSiva Reddy Kallam 
30153c6ee7dSSiva Reddy Kallam 	return 0;
30253c6ee7dSSiva Reddy Kallam }
30353c6ee7dSSiva Reddy Kallam 
30453c6ee7dSSiva Reddy Kallam static int __send_message(struct bng_re_rcfw *rcfw,
30553c6ee7dSSiva Reddy Kallam 			  struct bng_re_cmdqmsg *msg, u8 opcode)
30653c6ee7dSSiva Reddy Kallam {
30753c6ee7dSSiva Reddy Kallam 	u32 bsize, free_slots, required_slots;
30853c6ee7dSSiva Reddy Kallam 	struct bng_re_cmdq_ctx *cmdq;
30953c6ee7dSSiva Reddy Kallam 	struct bng_re_crsqe *crsqe;
31053c6ee7dSSiva Reddy Kallam 	struct bng_fw_cmdqe *cmdqe;
31153c6ee7dSSiva Reddy Kallam 	struct bng_re_hwq *hwq;
31253c6ee7dSSiva Reddy Kallam 	u32 sw_prod, cmdq_prod;
31353c6ee7dSSiva Reddy Kallam 	struct pci_dev *pdev;
31453c6ee7dSSiva Reddy Kallam 	u16 cookie;
31553c6ee7dSSiva Reddy Kallam 	u8 *preq;
31653c6ee7dSSiva Reddy Kallam 
31753c6ee7dSSiva Reddy Kallam 	cmdq = &rcfw->cmdq;
31853c6ee7dSSiva Reddy Kallam 	hwq = &cmdq->hwq;
31953c6ee7dSSiva Reddy Kallam 	pdev = rcfw->pdev;
32053c6ee7dSSiva Reddy Kallam 
32153c6ee7dSSiva Reddy Kallam 	/* Cmdq are in 16-byte units, each request can consume 1 or more
32253c6ee7dSSiva Reddy Kallam 	 * cmdqe
32353c6ee7dSSiva Reddy Kallam 	 */
32453c6ee7dSSiva Reddy Kallam 	spin_lock_bh(&hwq->lock);
32553c6ee7dSSiva Reddy Kallam 	required_slots = bng_re_get_cmd_slots(msg->req);
32653c6ee7dSSiva Reddy Kallam 	free_slots = HWQ_FREE_SLOTS(hwq);
32753c6ee7dSSiva Reddy Kallam 	cookie = cmdq->seq_num & BNG_FW_MAX_COOKIE_VALUE;
32853c6ee7dSSiva Reddy Kallam 	crsqe = &rcfw->crsqe_tbl[cookie];
32953c6ee7dSSiva Reddy Kallam 
33053c6ee7dSSiva Reddy Kallam 	if (required_slots >= free_slots) {
33153c6ee7dSSiva Reddy Kallam 		dev_info_ratelimited(&pdev->dev,
33253c6ee7dSSiva Reddy Kallam 				     "CMDQ is full req/free %d/%d!",
33353c6ee7dSSiva Reddy Kallam 				     required_slots, free_slots);
33453c6ee7dSSiva Reddy Kallam 		spin_unlock_bh(&hwq->lock);
33553c6ee7dSSiva Reddy Kallam 		return -EAGAIN;
33653c6ee7dSSiva Reddy Kallam 	}
33753c6ee7dSSiva Reddy Kallam 	__set_cmdq_base_cookie(msg->req, msg->req_sz, cpu_to_le16(cookie));
33853c6ee7dSSiva Reddy Kallam 
33953c6ee7dSSiva Reddy Kallam 	bsize = bng_re_set_cmd_slots(msg->req);
34053c6ee7dSSiva Reddy Kallam 	crsqe->free_slots = free_slots;
34153c6ee7dSSiva Reddy Kallam 	crsqe->resp = (struct creq_qp_event *)msg->resp;
34253c6ee7dSSiva Reddy Kallam 	crsqe->is_waiter_alive = true;
34353c6ee7dSSiva Reddy Kallam 	crsqe->is_in_used = true;
34453c6ee7dSSiva Reddy Kallam 	crsqe->opcode = opcode;
34553c6ee7dSSiva Reddy Kallam 
34653c6ee7dSSiva Reddy Kallam 	crsqe->req_size = __get_cmdq_base_cmd_size(msg->req, msg->req_sz);
34753c6ee7dSSiva Reddy Kallam 	if (__get_cmdq_base_resp_size(msg->req, msg->req_sz) && msg->sb) {
34853c6ee7dSSiva Reddy Kallam 		struct bng_re_rcfw_sbuf *sbuf = msg->sb;
34953c6ee7dSSiva Reddy Kallam 
35053c6ee7dSSiva Reddy Kallam 		__set_cmdq_base_resp_addr(msg->req, msg->req_sz,
35153c6ee7dSSiva Reddy Kallam 					  cpu_to_le64(sbuf->dma_addr));
35253c6ee7dSSiva Reddy Kallam 		__set_cmdq_base_resp_size(msg->req, msg->req_sz,
35353c6ee7dSSiva Reddy Kallam 					  ALIGN(sbuf->size,
35453c6ee7dSSiva Reddy Kallam 						BNG_FW_CMDQE_UNITS) /
35553c6ee7dSSiva Reddy Kallam 						BNG_FW_CMDQE_UNITS);
35653c6ee7dSSiva Reddy Kallam 	}
35753c6ee7dSSiva Reddy Kallam 
35853c6ee7dSSiva Reddy Kallam 	preq = (u8 *)msg->req;
35953c6ee7dSSiva Reddy Kallam 	do {
36053c6ee7dSSiva Reddy Kallam 		/* Locate the next cmdq slot */
36153c6ee7dSSiva Reddy Kallam 		sw_prod = HWQ_CMP(hwq->prod, hwq);
36253c6ee7dSSiva Reddy Kallam 		cmdqe = bng_re_get_qe(hwq, sw_prod, NULL);
36353c6ee7dSSiva Reddy Kallam 		/* Copy a segment of the req cmd to the cmdq */
36453c6ee7dSSiva Reddy Kallam 		memset(cmdqe, 0, sizeof(*cmdqe));
36553c6ee7dSSiva Reddy Kallam 		memcpy(cmdqe, preq, min_t(u32, bsize, sizeof(*cmdqe)));
36653c6ee7dSSiva Reddy Kallam 		preq += min_t(u32, bsize, sizeof(*cmdqe));
36753c6ee7dSSiva Reddy Kallam 		bsize -= min_t(u32, bsize, sizeof(*cmdqe));
36853c6ee7dSSiva Reddy Kallam 		hwq->prod++;
36953c6ee7dSSiva Reddy Kallam 	} while (bsize > 0);
37053c6ee7dSSiva Reddy Kallam 	cmdq->seq_num++;
37153c6ee7dSSiva Reddy Kallam 
37253c6ee7dSSiva Reddy Kallam 	cmdq_prod = hwq->prod & 0xFFFF;
37353c6ee7dSSiva Reddy Kallam 	if (test_bit(FIRMWARE_FIRST_FLAG, &cmdq->flags)) {
37453c6ee7dSSiva Reddy Kallam 		/* The very first doorbell write
37553c6ee7dSSiva Reddy Kallam 		 * is required to set this flag
37653c6ee7dSSiva Reddy Kallam 		 * which prompts the FW to reset
37753c6ee7dSSiva Reddy Kallam 		 * its internal pointers
37853c6ee7dSSiva Reddy Kallam 		 */
37953c6ee7dSSiva Reddy Kallam 		cmdq_prod |= BIT(FIRMWARE_FIRST_FLAG);
38053c6ee7dSSiva Reddy Kallam 		clear_bit(FIRMWARE_FIRST_FLAG, &cmdq->flags);
38153c6ee7dSSiva Reddy Kallam 	}
38253c6ee7dSSiva Reddy Kallam 	/* ring CMDQ DB */
38353c6ee7dSSiva Reddy Kallam 	wmb();
38453c6ee7dSSiva Reddy Kallam 	writel(cmdq_prod, cmdq->cmdq_mbox.prod);
38553c6ee7dSSiva Reddy Kallam 	writel(BNG_FW_CMDQ_TRIG_VAL, cmdq->cmdq_mbox.db);
38653c6ee7dSSiva Reddy Kallam 	spin_unlock_bh(&hwq->lock);
38753c6ee7dSSiva Reddy Kallam 	/* Return the CREQ response pointer */
38853c6ee7dSSiva Reddy Kallam 	return 0;
38953c6ee7dSSiva Reddy Kallam }
39053c6ee7dSSiva Reddy Kallam 
39153c6ee7dSSiva Reddy Kallam /**
39253c6ee7dSSiva Reddy Kallam  * __wait_for_resp   -	Don't hold the cpu context and wait for response
39353c6ee7dSSiva Reddy Kallam  * @rcfw:    rcfw channel instance of rdev
39453c6ee7dSSiva Reddy Kallam  * @cookie:  cookie to track the command
39553c6ee7dSSiva Reddy Kallam  *
39653c6ee7dSSiva Reddy Kallam  * Wait for command completion in sleepable context.
39753c6ee7dSSiva Reddy Kallam  *
39853c6ee7dSSiva Reddy Kallam  * Returns:
39953c6ee7dSSiva Reddy Kallam  * 0 if command is completed by firmware.
40053c6ee7dSSiva Reddy Kallam  * Non zero error code for rest of the case.
40153c6ee7dSSiva Reddy Kallam  */
40253c6ee7dSSiva Reddy Kallam static int __wait_for_resp(struct bng_re_rcfw *rcfw, u16 cookie)
40353c6ee7dSSiva Reddy Kallam {
40453c6ee7dSSiva Reddy Kallam 	struct bng_re_cmdq_ctx *cmdq;
40553c6ee7dSSiva Reddy Kallam 	struct bng_re_crsqe *crsqe;
40653c6ee7dSSiva Reddy Kallam 
40753c6ee7dSSiva Reddy Kallam 	cmdq = &rcfw->cmdq;
40853c6ee7dSSiva Reddy Kallam 	crsqe = &rcfw->crsqe_tbl[cookie];
40953c6ee7dSSiva Reddy Kallam 
41053c6ee7dSSiva Reddy Kallam 	do {
41153c6ee7dSSiva Reddy Kallam 		wait_event_timeout(cmdq->waitq,
41253c6ee7dSSiva Reddy Kallam 				   !crsqe->is_in_used,
41353c6ee7dSSiva Reddy Kallam 				   secs_to_jiffies(rcfw->max_timeout));
41453c6ee7dSSiva Reddy Kallam 
41553c6ee7dSSiva Reddy Kallam 		if (!crsqe->is_in_used)
41653c6ee7dSSiva Reddy Kallam 			return 0;
41753c6ee7dSSiva Reddy Kallam 
41853c6ee7dSSiva Reddy Kallam 		bng_re_service_creq(&rcfw->creq.creq_tasklet);
41953c6ee7dSSiva Reddy Kallam 
42053c6ee7dSSiva Reddy Kallam 		if (!crsqe->is_in_used)
42153c6ee7dSSiva Reddy Kallam 			return 0;
42253c6ee7dSSiva Reddy Kallam 	} while (true);
42353c6ee7dSSiva Reddy Kallam };
42453c6ee7dSSiva Reddy Kallam 
42553c6ee7dSSiva Reddy Kallam /**
42653c6ee7dSSiva Reddy Kallam  * bng_re_rcfw_send_message   -	interface to send
42753c6ee7dSSiva Reddy Kallam  * and complete rcfw command.
42853c6ee7dSSiva Reddy Kallam  * @rcfw:   rcfw channel instance of rdev
42953c6ee7dSSiva Reddy Kallam  * @msg:    message to send
43053c6ee7dSSiva Reddy Kallam  *
43153c6ee7dSSiva Reddy Kallam  * This function does not account shadow queue depth. It will send
43253c6ee7dSSiva Reddy Kallam  * all the command unconditionally as long as send queue is not full.
43353c6ee7dSSiva Reddy Kallam  *
43453c6ee7dSSiva Reddy Kallam  * Returns:
43553c6ee7dSSiva Reddy Kallam  * 0 if command completed by firmware.
43653c6ee7dSSiva Reddy Kallam  * Non zero if the command is not completed by firmware.
43753c6ee7dSSiva Reddy Kallam  */
43853c6ee7dSSiva Reddy Kallam int bng_re_rcfw_send_message(struct bng_re_rcfw *rcfw,
43953c6ee7dSSiva Reddy Kallam 			     struct bng_re_cmdqmsg *msg)
44053c6ee7dSSiva Reddy Kallam {
44153c6ee7dSSiva Reddy Kallam 	struct creq_qp_event *evnt = (struct creq_qp_event *)msg->resp;
44253c6ee7dSSiva Reddy Kallam 	struct bng_re_crsqe *crsqe;
44353c6ee7dSSiva Reddy Kallam 	u16 cookie;
44453c6ee7dSSiva Reddy Kallam 	int rc;
44553c6ee7dSSiva Reddy Kallam 	u8 opcode;
44653c6ee7dSSiva Reddy Kallam 
44753c6ee7dSSiva Reddy Kallam 	opcode = __get_cmdq_base_opcode(msg->req, msg->req_sz);
44853c6ee7dSSiva Reddy Kallam 
44953c6ee7dSSiva Reddy Kallam 	rc = __send_message_basic_sanity(rcfw, msg, opcode);
45053c6ee7dSSiva Reddy Kallam 	if (rc)
45153c6ee7dSSiva Reddy Kallam 		return rc == -ENXIO ? bng_re_map_rc(opcode) : rc;
45253c6ee7dSSiva Reddy Kallam 
45353c6ee7dSSiva Reddy Kallam 	rc = __send_message(rcfw, msg, opcode);
45453c6ee7dSSiva Reddy Kallam 	if (rc)
45553c6ee7dSSiva Reddy Kallam 		return rc;
45653c6ee7dSSiva Reddy Kallam 
45753c6ee7dSSiva Reddy Kallam 	cookie = le16_to_cpu(__get_cmdq_base_cookie(msg->req, msg->req_sz))
45853c6ee7dSSiva Reddy Kallam 				& BNG_FW_MAX_COOKIE_VALUE;
45953c6ee7dSSiva Reddy Kallam 
46053c6ee7dSSiva Reddy Kallam 	rc = __wait_for_resp(rcfw, cookie);
46153c6ee7dSSiva Reddy Kallam 
46253c6ee7dSSiva Reddy Kallam 	if (rc) {
46353c6ee7dSSiva Reddy Kallam 		spin_lock_bh(&rcfw->cmdq.hwq.lock);
46453c6ee7dSSiva Reddy Kallam 		crsqe = &rcfw->crsqe_tbl[cookie];
46553c6ee7dSSiva Reddy Kallam 		crsqe->is_waiter_alive = false;
46653c6ee7dSSiva Reddy Kallam 		if (rc == -ENODEV)
46753c6ee7dSSiva Reddy Kallam 			set_bit(FIRMWARE_STALL_DETECTED, &rcfw->cmdq.flags);
46853c6ee7dSSiva Reddy Kallam 		spin_unlock_bh(&rcfw->cmdq.hwq.lock);
46953c6ee7dSSiva Reddy Kallam 		return -ETIMEDOUT;
47053c6ee7dSSiva Reddy Kallam 	}
47153c6ee7dSSiva Reddy Kallam 
47253c6ee7dSSiva Reddy Kallam 	if (evnt->status) {
47353c6ee7dSSiva Reddy Kallam 		/* failed with status */
47453c6ee7dSSiva Reddy Kallam 		dev_err(&rcfw->pdev->dev, "cmdq[%#x]=%#x status %#x\n",
47553c6ee7dSSiva Reddy Kallam 			cookie, opcode, evnt->status);
47653c6ee7dSSiva Reddy Kallam 		rc = -EIO;
47753c6ee7dSSiva Reddy Kallam 	}
47853c6ee7dSSiva Reddy Kallam 
47953c6ee7dSSiva Reddy Kallam 	return rc;
48053c6ee7dSSiva Reddy Kallam }
48153c6ee7dSSiva Reddy Kallam 
4824f830cd8SSiva Reddy Kallam static int bng_re_map_cmdq_mbox(struct bng_re_rcfw *rcfw)
4834f830cd8SSiva Reddy Kallam {
4844f830cd8SSiva Reddy Kallam 	struct bng_re_cmdq_mbox *mbox;
4854f830cd8SSiva Reddy Kallam 	resource_size_t bar_reg;
4864f830cd8SSiva Reddy Kallam 	struct pci_dev *pdev;
4874f830cd8SSiva Reddy Kallam 
4884f830cd8SSiva Reddy Kallam 	pdev = rcfw->pdev;
4894f830cd8SSiva Reddy Kallam 	mbox = &rcfw->cmdq.cmdq_mbox;
4904f830cd8SSiva Reddy Kallam 
4914f830cd8SSiva Reddy Kallam 	mbox->reg.bar_id = BNG_FW_COMM_PCI_BAR_REGION;
4924f830cd8SSiva Reddy Kallam 	mbox->reg.len = BNG_FW_COMM_SIZE;
4934f830cd8SSiva Reddy Kallam 	mbox->reg.bar_base = pci_resource_start(pdev, mbox->reg.bar_id);
4944f830cd8SSiva Reddy Kallam 	if (!mbox->reg.bar_base) {
4954f830cd8SSiva Reddy Kallam 		dev_err(&pdev->dev,
4964f830cd8SSiva Reddy Kallam 			"CMDQ BAR region %d resc start is 0!\n",
4974f830cd8SSiva Reddy Kallam 			mbox->reg.bar_id);
4984f830cd8SSiva Reddy Kallam 		return -ENOMEM;
4994f830cd8SSiva Reddy Kallam 	}
5004f830cd8SSiva Reddy Kallam 
5014f830cd8SSiva Reddy Kallam 	bar_reg = mbox->reg.bar_base + BNG_FW_COMM_BASE_OFFSET;
5024f830cd8SSiva Reddy Kallam 	mbox->reg.len = BNG_FW_COMM_SIZE;
5034f830cd8SSiva Reddy Kallam 	mbox->reg.bar_reg = ioremap(bar_reg, mbox->reg.len);
5044f830cd8SSiva Reddy Kallam 	if (!mbox->reg.bar_reg) {
5054f830cd8SSiva Reddy Kallam 		dev_err(&pdev->dev,
5064f830cd8SSiva Reddy Kallam 			"CMDQ BAR region %d mapping failed\n",
5074f830cd8SSiva Reddy Kallam 			mbox->reg.bar_id);
5084f830cd8SSiva Reddy Kallam 		return -ENOMEM;
5094f830cd8SSiva Reddy Kallam 	}
5104f830cd8SSiva Reddy Kallam 
5114f830cd8SSiva Reddy Kallam 	mbox->prod = (void  __iomem *)(mbox->reg.bar_reg +
5124f830cd8SSiva Reddy Kallam 			BNG_FW_PF_VF_COMM_PROD_OFFSET);
5134f830cd8SSiva Reddy Kallam 	mbox->db = (void __iomem *)(mbox->reg.bar_reg + BNG_FW_COMM_TRIG_OFFSET);
5144f830cd8SSiva Reddy Kallam 	return 0;
5154f830cd8SSiva Reddy Kallam }
5164f830cd8SSiva Reddy Kallam 
5174f830cd8SSiva Reddy Kallam static irqreturn_t bng_re_creq_irq(int irq, void *dev_instance)
5184f830cd8SSiva Reddy Kallam {
5194f830cd8SSiva Reddy Kallam 	struct bng_re_rcfw *rcfw = dev_instance;
5204f830cd8SSiva Reddy Kallam 	struct bng_re_creq_ctx *creq;
5214f830cd8SSiva Reddy Kallam 	struct bng_re_hwq *hwq;
5224f830cd8SSiva Reddy Kallam 	u32 sw_cons;
5234f830cd8SSiva Reddy Kallam 
5244f830cd8SSiva Reddy Kallam 	creq = &rcfw->creq;
5254f830cd8SSiva Reddy Kallam 	hwq = &creq->hwq;
5264f830cd8SSiva Reddy Kallam 	/* Prefetch the CREQ element */
5274f830cd8SSiva Reddy Kallam 	sw_cons = HWQ_CMP(hwq->cons, hwq);
528*155c9971SLeon Romanovsky 	bng_re_get_qe(hwq, sw_cons, NULL);
5294f830cd8SSiva Reddy Kallam 
5304f830cd8SSiva Reddy Kallam 	tasklet_schedule(&creq->creq_tasklet);
5314f830cd8SSiva Reddy Kallam 	return IRQ_HANDLED;
5324f830cd8SSiva Reddy Kallam }
5334f830cd8SSiva Reddy Kallam 
5344f830cd8SSiva Reddy Kallam int bng_re_rcfw_start_irq(struct bng_re_rcfw *rcfw, int msix_vector,
5354f830cd8SSiva Reddy Kallam 			  bool need_init)
5364f830cd8SSiva Reddy Kallam {
5374f830cd8SSiva Reddy Kallam 	struct bng_re_creq_ctx *creq;
5384f830cd8SSiva Reddy Kallam 	struct bng_re_res *res;
5394f830cd8SSiva Reddy Kallam 	int rc;
5404f830cd8SSiva Reddy Kallam 
5414f830cd8SSiva Reddy Kallam 	creq = &rcfw->creq;
5424f830cd8SSiva Reddy Kallam 	res = rcfw->res;
5434f830cd8SSiva Reddy Kallam 
5444f830cd8SSiva Reddy Kallam 	if (creq->irq_handler_avail)
5454f830cd8SSiva Reddy Kallam 		return -EFAULT;
5464f830cd8SSiva Reddy Kallam 
5474f830cd8SSiva Reddy Kallam 	creq->msix_vec = msix_vector;
5484f830cd8SSiva Reddy Kallam 	if (need_init)
5494f830cd8SSiva Reddy Kallam 		tasklet_setup(&creq->creq_tasklet, bng_re_service_creq);
5504f830cd8SSiva Reddy Kallam 	else
5514f830cd8SSiva Reddy Kallam 		tasklet_enable(&creq->creq_tasklet);
5524f830cd8SSiva Reddy Kallam 
5534f830cd8SSiva Reddy Kallam 	creq->irq_name = kasprintf(GFP_KERNEL, "bng_re-creq@pci:%s",
5544f830cd8SSiva Reddy Kallam 				   pci_name(res->pdev));
5554f830cd8SSiva Reddy Kallam 	if (!creq->irq_name)
5564f830cd8SSiva Reddy Kallam 		return -ENOMEM;
5574f830cd8SSiva Reddy Kallam 	rc = request_irq(creq->msix_vec, bng_re_creq_irq, 0,
5584f830cd8SSiva Reddy Kallam 			 creq->irq_name, rcfw);
5594f830cd8SSiva Reddy Kallam 	if (rc) {
5604f830cd8SSiva Reddy Kallam 		kfree(creq->irq_name);
5614f830cd8SSiva Reddy Kallam 		creq->irq_name = NULL;
5624f830cd8SSiva Reddy Kallam 		tasklet_disable(&creq->creq_tasklet);
5634f830cd8SSiva Reddy Kallam 		return rc;
5644f830cd8SSiva Reddy Kallam 	}
5654f830cd8SSiva Reddy Kallam 	creq->irq_handler_avail = true;
5664f830cd8SSiva Reddy Kallam 
5674f830cd8SSiva Reddy Kallam 	bng_re_ring_nq_db(&creq->creq_db.dbinfo, res->cctx, true);
5684f830cd8SSiva Reddy Kallam 	atomic_inc(&rcfw->rcfw_intr_enabled);
5694f830cd8SSiva Reddy Kallam 
5704f830cd8SSiva Reddy Kallam 	return 0;
5714f830cd8SSiva Reddy Kallam }
5724f830cd8SSiva Reddy Kallam 
5734f830cd8SSiva Reddy Kallam static int bng_re_map_creq_db(struct bng_re_rcfw *rcfw, u32 reg_offt)
5744f830cd8SSiva Reddy Kallam {
5754f830cd8SSiva Reddy Kallam 	struct bng_re_creq_db *creq_db;
5764f830cd8SSiva Reddy Kallam 	resource_size_t bar_reg;
5774f830cd8SSiva Reddy Kallam 	struct pci_dev *pdev;
5784f830cd8SSiva Reddy Kallam 
5794f830cd8SSiva Reddy Kallam 	pdev = rcfw->pdev;
5804f830cd8SSiva Reddy Kallam 	creq_db = &rcfw->creq.creq_db;
5814f830cd8SSiva Reddy Kallam 
5824f830cd8SSiva Reddy Kallam 	creq_db->dbinfo.flags = 0;
5834f830cd8SSiva Reddy Kallam 	creq_db->reg.bar_id = BNG_FW_COMM_CONS_PCI_BAR_REGION;
5844f830cd8SSiva Reddy Kallam 	creq_db->reg.bar_base = pci_resource_start(pdev, creq_db->reg.bar_id);
5854f830cd8SSiva Reddy Kallam 	if (!creq_db->reg.bar_id)
5864f830cd8SSiva Reddy Kallam 		dev_err(&pdev->dev,
5874f830cd8SSiva Reddy Kallam 			"CREQ BAR region %d resc start is 0!",
5884f830cd8SSiva Reddy Kallam 			creq_db->reg.bar_id);
5894f830cd8SSiva Reddy Kallam 
5904f830cd8SSiva Reddy Kallam 	bar_reg = creq_db->reg.bar_base + reg_offt;
5914f830cd8SSiva Reddy Kallam 
5924f830cd8SSiva Reddy Kallam 	creq_db->reg.len = BNG_FW_CREQ_DB_LEN;
5934f830cd8SSiva Reddy Kallam 	creq_db->reg.bar_reg = ioremap(bar_reg, creq_db->reg.len);
5944f830cd8SSiva Reddy Kallam 	if (!creq_db->reg.bar_reg) {
5954f830cd8SSiva Reddy Kallam 		dev_err(&pdev->dev,
5964f830cd8SSiva Reddy Kallam 			"CREQ BAR region %d mapping failed",
5974f830cd8SSiva Reddy Kallam 			creq_db->reg.bar_id);
5984f830cd8SSiva Reddy Kallam 		return -ENOMEM;
5994f830cd8SSiva Reddy Kallam 	}
6004f830cd8SSiva Reddy Kallam 	creq_db->dbinfo.db = creq_db->reg.bar_reg;
6014f830cd8SSiva Reddy Kallam 	creq_db->dbinfo.hwq = &rcfw->creq.hwq;
6024f830cd8SSiva Reddy Kallam 	creq_db->dbinfo.xid = rcfw->creq.ring_id;
6034f830cd8SSiva Reddy Kallam 	return 0;
6044f830cd8SSiva Reddy Kallam }
6054f830cd8SSiva Reddy Kallam 
6064f830cd8SSiva Reddy Kallam void bng_re_rcfw_stop_irq(struct bng_re_rcfw *rcfw, bool kill)
6074f830cd8SSiva Reddy Kallam {
6084f830cd8SSiva Reddy Kallam 	struct bng_re_creq_ctx *creq;
6094f830cd8SSiva Reddy Kallam 
6104f830cd8SSiva Reddy Kallam 	creq = &rcfw->creq;
6114f830cd8SSiva Reddy Kallam 
6124f830cd8SSiva Reddy Kallam 	if (!creq->irq_handler_avail)
6134f830cd8SSiva Reddy Kallam 		return;
6144f830cd8SSiva Reddy Kallam 
6154f830cd8SSiva Reddy Kallam 	creq->irq_handler_avail = false;
6164f830cd8SSiva Reddy Kallam 	/* Mask h/w interrupts */
6174f830cd8SSiva Reddy Kallam 	bng_re_ring_nq_db(&creq->creq_db.dbinfo, rcfw->res->cctx, false);
6184f830cd8SSiva Reddy Kallam 	/* Sync with last running IRQ-handler */
6194f830cd8SSiva Reddy Kallam 	synchronize_irq(creq->msix_vec);
6204f830cd8SSiva Reddy Kallam 	free_irq(creq->msix_vec, rcfw);
6214f830cd8SSiva Reddy Kallam 	kfree(creq->irq_name);
6224f830cd8SSiva Reddy Kallam 	creq->irq_name = NULL;
6234f830cd8SSiva Reddy Kallam 	atomic_set(&rcfw->rcfw_intr_enabled, 0);
6244f830cd8SSiva Reddy Kallam 	if (kill)
6254f830cd8SSiva Reddy Kallam 		tasklet_kill(&creq->creq_tasklet);
6264f830cd8SSiva Reddy Kallam 	tasklet_disable(&creq->creq_tasklet);
6274f830cd8SSiva Reddy Kallam }
6284f830cd8SSiva Reddy Kallam 
6294f830cd8SSiva Reddy Kallam void bng_re_disable_rcfw_channel(struct bng_re_rcfw *rcfw)
6304f830cd8SSiva Reddy Kallam {
6314f830cd8SSiva Reddy Kallam 	struct bng_re_creq_ctx *creq;
6324f830cd8SSiva Reddy Kallam 	struct bng_re_cmdq_ctx *cmdq;
6334f830cd8SSiva Reddy Kallam 
6344f830cd8SSiva Reddy Kallam 	creq = &rcfw->creq;
6354f830cd8SSiva Reddy Kallam 	cmdq = &rcfw->cmdq;
6364f830cd8SSiva Reddy Kallam 	/* Make sure the HW channel is stopped! */
6374f830cd8SSiva Reddy Kallam 	bng_re_rcfw_stop_irq(rcfw, true);
6384f830cd8SSiva Reddy Kallam 
6394f830cd8SSiva Reddy Kallam 	iounmap(cmdq->cmdq_mbox.reg.bar_reg);
6404f830cd8SSiva Reddy Kallam 	iounmap(creq->creq_db.reg.bar_reg);
6414f830cd8SSiva Reddy Kallam 
6424f830cd8SSiva Reddy Kallam 	cmdq->cmdq_mbox.reg.bar_reg = NULL;
6434f830cd8SSiva Reddy Kallam 	creq->creq_db.reg.bar_reg = NULL;
6444f830cd8SSiva Reddy Kallam 	creq->msix_vec = 0;
6454f830cd8SSiva Reddy Kallam }
6464f830cd8SSiva Reddy Kallam 
64753c6ee7dSSiva Reddy Kallam static void bng_re_start_rcfw(struct bng_re_rcfw *rcfw)
64853c6ee7dSSiva Reddy Kallam {
64953c6ee7dSSiva Reddy Kallam 	struct bng_re_cmdq_ctx *cmdq;
65053c6ee7dSSiva Reddy Kallam 	struct bng_re_creq_ctx *creq;
65153c6ee7dSSiva Reddy Kallam 	struct bng_re_cmdq_mbox *mbox;
65253c6ee7dSSiva Reddy Kallam 	struct cmdq_init init = {0};
65353c6ee7dSSiva Reddy Kallam 
65453c6ee7dSSiva Reddy Kallam 	cmdq = &rcfw->cmdq;
65553c6ee7dSSiva Reddy Kallam 	creq = &rcfw->creq;
65653c6ee7dSSiva Reddy Kallam 	mbox = &cmdq->cmdq_mbox;
65753c6ee7dSSiva Reddy Kallam 
65853c6ee7dSSiva Reddy Kallam 	init.cmdq_pbl = cpu_to_le64(cmdq->hwq.pbl[BNG_PBL_LVL_0].pg_map_arr[0]);
65953c6ee7dSSiva Reddy Kallam 	init.cmdq_size_cmdq_lvl =
66053c6ee7dSSiva Reddy Kallam 			cpu_to_le16(((rcfw->cmdq_depth <<
66153c6ee7dSSiva Reddy Kallam 				      CMDQ_INIT_CMDQ_SIZE_SFT) &
66253c6ee7dSSiva Reddy Kallam 				    CMDQ_INIT_CMDQ_SIZE_MASK) |
66353c6ee7dSSiva Reddy Kallam 				    ((cmdq->hwq.level <<
66453c6ee7dSSiva Reddy Kallam 				      CMDQ_INIT_CMDQ_LVL_SFT) &
66553c6ee7dSSiva Reddy Kallam 				    CMDQ_INIT_CMDQ_LVL_MASK));
66653c6ee7dSSiva Reddy Kallam 	init.creq_ring_id = cpu_to_le16(creq->ring_id);
66753c6ee7dSSiva Reddy Kallam 	/* Write to the mailbox register */
66853c6ee7dSSiva Reddy Kallam 	__iowrite32_copy(mbox->reg.bar_reg, &init, sizeof(init) / 4);
66953c6ee7dSSiva Reddy Kallam }
67053c6ee7dSSiva Reddy Kallam 
6714f830cd8SSiva Reddy Kallam int bng_re_enable_fw_channel(struct bng_re_rcfw *rcfw,
6724f830cd8SSiva Reddy Kallam 			     int msix_vector,
6734f830cd8SSiva Reddy Kallam 			     int cp_bar_reg_off)
6744f830cd8SSiva Reddy Kallam {
6754f830cd8SSiva Reddy Kallam 	struct bng_re_cmdq_ctx *cmdq;
6764f830cd8SSiva Reddy Kallam 	int rc;
6774f830cd8SSiva Reddy Kallam 
6784f830cd8SSiva Reddy Kallam 	cmdq = &rcfw->cmdq;
6794f830cd8SSiva Reddy Kallam 
6804f830cd8SSiva Reddy Kallam 	/* Assign defaults */
6814f830cd8SSiva Reddy Kallam 	cmdq->seq_num = 0;
6824f830cd8SSiva Reddy Kallam 	set_bit(FIRMWARE_FIRST_FLAG, &cmdq->flags);
6834f830cd8SSiva Reddy Kallam 	init_waitqueue_head(&cmdq->waitq);
6844f830cd8SSiva Reddy Kallam 
6854f830cd8SSiva Reddy Kallam 	rc = bng_re_map_cmdq_mbox(rcfw);
6864f830cd8SSiva Reddy Kallam 	if (rc)
6874f830cd8SSiva Reddy Kallam 		return rc;
6884f830cd8SSiva Reddy Kallam 
6894f830cd8SSiva Reddy Kallam 	rc = bng_re_map_creq_db(rcfw, cp_bar_reg_off);
6904f830cd8SSiva Reddy Kallam 	if (rc)
6914f830cd8SSiva Reddy Kallam 		return rc;
6924f830cd8SSiva Reddy Kallam 
6934f830cd8SSiva Reddy Kallam 	rc = bng_re_rcfw_start_irq(rcfw, msix_vector, true);
6944f830cd8SSiva Reddy Kallam 	if (rc) {
6954f830cd8SSiva Reddy Kallam 		dev_err(&rcfw->pdev->dev,
6964f830cd8SSiva Reddy Kallam 			"Failed to request IRQ for CREQ rc = 0x%x\n", rc);
6974f830cd8SSiva Reddy Kallam 		bng_re_disable_rcfw_channel(rcfw);
6984f830cd8SSiva Reddy Kallam 		return rc;
6994f830cd8SSiva Reddy Kallam 	}
7004f830cd8SSiva Reddy Kallam 
70153c6ee7dSSiva Reddy Kallam 	bng_re_start_rcfw(rcfw);
7024f830cd8SSiva Reddy Kallam 	return 0;
7034f830cd8SSiva Reddy Kallam }
70404e031ffSSiva Reddy Kallam 
70504e031ffSSiva Reddy Kallam int bng_re_deinit_rcfw(struct bng_re_rcfw *rcfw)
70604e031ffSSiva Reddy Kallam {
70704e031ffSSiva Reddy Kallam 	struct creq_deinitialize_fw_resp resp = {};
70804e031ffSSiva Reddy Kallam 	struct cmdq_deinitialize_fw req = {};
70904e031ffSSiva Reddy Kallam 	struct bng_re_cmdqmsg msg = {};
71004e031ffSSiva Reddy Kallam 	int rc;
71104e031ffSSiva Reddy Kallam 
71204e031ffSSiva Reddy Kallam 	bng_re_rcfw_cmd_prep((struct cmdq_base *)&req,
71304e031ffSSiva Reddy Kallam 			     CMDQ_BASE_OPCODE_DEINITIALIZE_FW,
71404e031ffSSiva Reddy Kallam 			     sizeof(req));
71504e031ffSSiva Reddy Kallam 	bng_re_fill_cmdqmsg(&msg, &req, &resp, NULL,
71604e031ffSSiva Reddy Kallam 			    sizeof(req), sizeof(resp), 0);
71704e031ffSSiva Reddy Kallam 	rc = bng_re_rcfw_send_message(rcfw, &msg);
71804e031ffSSiva Reddy Kallam 	if (rc)
71904e031ffSSiva Reddy Kallam 		return rc;
72004e031ffSSiva Reddy Kallam 
72104e031ffSSiva Reddy Kallam 	clear_bit(FIRMWARE_INITIALIZED_FLAG, &rcfw->cmdq.flags);
72204e031ffSSiva Reddy Kallam 	return 0;
72304e031ffSSiva Reddy Kallam }
72404e031ffSSiva Reddy Kallam static inline bool _is_hw_retx_supported(u16 dev_cap_flags)
72504e031ffSSiva Reddy Kallam {
72604e031ffSSiva Reddy Kallam 	return dev_cap_flags &
72704e031ffSSiva Reddy Kallam 		(CREQ_QUERY_FUNC_RESP_SB_HW_REQUESTER_RETX_ENABLED |
72804e031ffSSiva Reddy Kallam 		 CREQ_QUERY_FUNC_RESP_SB_HW_RESPONDER_RETX_ENABLED);
72904e031ffSSiva Reddy Kallam }
73004e031ffSSiva Reddy Kallam 
73104e031ffSSiva Reddy Kallam #define BNG_RE_HW_RETX(a) _is_hw_retx_supported((a))
73204e031ffSSiva Reddy Kallam static inline bool _is_optimize_modify_qp_supported(u16 dev_cap_ext_flags2)
73304e031ffSSiva Reddy Kallam {
73404e031ffSSiva Reddy Kallam 	return dev_cap_ext_flags2 &
73504e031ffSSiva Reddy Kallam 	       CREQ_QUERY_FUNC_RESP_SB_OPTIMIZE_MODIFY_QP_SUPPORTED;
73604e031ffSSiva Reddy Kallam }
73704e031ffSSiva Reddy Kallam 
73804e031ffSSiva Reddy Kallam int bng_re_init_rcfw(struct bng_re_rcfw *rcfw,
73904e031ffSSiva Reddy Kallam 		     struct bng_re_stats *stats_ctx)
74004e031ffSSiva Reddy Kallam {
74104e031ffSSiva Reddy Kallam 	struct creq_initialize_fw_resp resp = {};
74204e031ffSSiva Reddy Kallam 	struct cmdq_initialize_fw req = {};
74304e031ffSSiva Reddy Kallam 	struct bng_re_cmdqmsg msg = {};
74404e031ffSSiva Reddy Kallam 	int rc;
74504e031ffSSiva Reddy Kallam 	u16 flags = 0;
74604e031ffSSiva Reddy Kallam 
74704e031ffSSiva Reddy Kallam 	bng_re_rcfw_cmd_prep((struct cmdq_base *)&req,
74804e031ffSSiva Reddy Kallam 			     CMDQ_BASE_OPCODE_INITIALIZE_FW,
74904e031ffSSiva Reddy Kallam 			     sizeof(req));
75004e031ffSSiva Reddy Kallam 	/* Supply (log-base-2-of-host-page-size - base-page-shift)
75104e031ffSSiva Reddy Kallam 	 * to bono to adjust the doorbell page sizes.
75204e031ffSSiva Reddy Kallam 	 */
75304e031ffSSiva Reddy Kallam 	req.log2_dbr_pg_size = cpu_to_le16(PAGE_SHIFT -
75404e031ffSSiva Reddy Kallam 					   BNG_FW_DBR_BASE_PAGE_SHIFT);
75504e031ffSSiva Reddy Kallam 	if (BNG_RE_HW_RETX(rcfw->res->dattr->dev_cap_flags))
75604e031ffSSiva Reddy Kallam 		flags |= CMDQ_INITIALIZE_FW_FLAGS_HW_REQUESTER_RETX_SUPPORTED;
75704e031ffSSiva Reddy Kallam 	if (_is_optimize_modify_qp_supported(rcfw->res->dattr->dev_cap_flags2))
75804e031ffSSiva Reddy Kallam 		flags |= CMDQ_INITIALIZE_FW_FLAGS_OPTIMIZE_MODIFY_QP_SUPPORTED;
75904e031ffSSiva Reddy Kallam 	req.flags |= cpu_to_le16(flags);
76004e031ffSSiva Reddy Kallam 	req.stat_ctx_id = cpu_to_le32(stats_ctx->fw_id);
76104e031ffSSiva Reddy Kallam 	bng_re_fill_cmdqmsg(&msg, &req, &resp, NULL, sizeof(req), sizeof(resp), 0);
76204e031ffSSiva Reddy Kallam 	rc = bng_re_rcfw_send_message(rcfw, &msg);
76304e031ffSSiva Reddy Kallam 	if (rc)
76404e031ffSSiva Reddy Kallam 		return rc;
76504e031ffSSiva Reddy Kallam 	set_bit(FIRMWARE_INITIALIZED_FLAG, &rcfw->cmdq.flags);
76604e031ffSSiva Reddy Kallam 	return 0;
76704e031ffSSiva Reddy Kallam }
768