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