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