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 */
bng_re_map_rc(u8 opcode)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
bng_re_free_rcfw_channel(struct bng_re_rcfw * rcfw)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
bng_re_alloc_fw_channel(struct bng_re_res * res,struct bng_re_rcfw * rcfw)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
bng_re_process_qp_event(struct bng_re_rcfw * rcfw,struct creq_qp_event * qp_event,u32 * num_wait)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 */
bng_re_process_func_event(struct bng_re_rcfw * rcfw,struct creq_func_event * func_event)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 */
bng_re_service_creq(struct tasklet_struct * t)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
__send_message_basic_sanity(struct bng_re_rcfw * rcfw,struct bng_re_cmdqmsg * msg,u8 opcode)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
__send_message(struct bng_re_rcfw * rcfw,struct bng_re_cmdqmsg * msg,u8 opcode)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 */
__wait_for_resp(struct bng_re_rcfw * rcfw,u16 cookie)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 */
bng_re_rcfw_send_message(struct bng_re_rcfw * rcfw,struct bng_re_cmdqmsg * msg)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
bng_re_map_cmdq_mbox(struct bng_re_rcfw * rcfw)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
bng_re_creq_irq(int irq,void * dev_instance)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
bng_re_rcfw_start_irq(struct bng_re_rcfw * rcfw,int msix_vector,bool need_init)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
bng_re_map_creq_db(struct bng_re_rcfw * rcfw,u32 reg_offt)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
bng_re_rcfw_stop_irq(struct bng_re_rcfw * rcfw,bool kill)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
bng_re_disable_rcfw_channel(struct bng_re_rcfw * rcfw)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
bng_re_start_rcfw(struct bng_re_rcfw * rcfw)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
bng_re_enable_fw_channel(struct bng_re_rcfw * rcfw,int msix_vector,int cp_bar_reg_off)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
bng_re_deinit_rcfw(struct bng_re_rcfw * rcfw)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 }
_is_hw_retx_supported(u16 dev_cap_flags)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))
_is_optimize_modify_qp_supported(u16 dev_cap_ext_flags2)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
bng_re_init_rcfw(struct bng_re_rcfw * rcfw,struct bng_re_stats * stats_ctx)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