18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Broadcom NetXtreme-E RoCE driver. 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright (c) 2016 - 2017, Broadcom. All rights reserved. The term 58c2ecf20Sopenharmony_ci * Broadcom refers to Broadcom Limited and/or its subsidiaries. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * This software is available to you under a choice of one of two 88c2ecf20Sopenharmony_ci * licenses. You may choose to be licensed under the terms of the GNU 98c2ecf20Sopenharmony_ci * General Public License (GPL) Version 2, available from the file 108c2ecf20Sopenharmony_ci * COPYING in the main directory of this source tree, or the 118c2ecf20Sopenharmony_ci * BSD license below: 128c2ecf20Sopenharmony_ci * 138c2ecf20Sopenharmony_ci * Redistribution and use in source and binary forms, with or without 148c2ecf20Sopenharmony_ci * modification, are permitted provided that the following conditions 158c2ecf20Sopenharmony_ci * are met: 168c2ecf20Sopenharmony_ci * 178c2ecf20Sopenharmony_ci * 1. Redistributions of source code must retain the above copyright 188c2ecf20Sopenharmony_ci * notice, this list of conditions and the following disclaimer. 198c2ecf20Sopenharmony_ci * 2. Redistributions in binary form must reproduce the above copyright 208c2ecf20Sopenharmony_ci * notice, this list of conditions and the following disclaimer in 218c2ecf20Sopenharmony_ci * the documentation and/or other materials provided with the 228c2ecf20Sopenharmony_ci * distribution. 238c2ecf20Sopenharmony_ci * 248c2ecf20Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' 258c2ecf20Sopenharmony_ci * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 268c2ecf20Sopenharmony_ci * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 278c2ecf20Sopenharmony_ci * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS 288c2ecf20Sopenharmony_ci * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 298c2ecf20Sopenharmony_ci * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 308c2ecf20Sopenharmony_ci * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 318c2ecf20Sopenharmony_ci * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 328c2ecf20Sopenharmony_ci * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 338c2ecf20Sopenharmony_ci * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 348c2ecf20Sopenharmony_ci * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 358c2ecf20Sopenharmony_ci * 368c2ecf20Sopenharmony_ci * Description: RDMA Controller HW interface 378c2ecf20Sopenharmony_ci */ 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci#define dev_fmt(fmt) "QPLIB: " fmt 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 428c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 438c2ecf20Sopenharmony_ci#include <linux/pci.h> 448c2ecf20Sopenharmony_ci#include <linux/prefetch.h> 458c2ecf20Sopenharmony_ci#include <linux/delay.h> 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci#include "roce_hsi.h" 488c2ecf20Sopenharmony_ci#include "qplib_res.h" 498c2ecf20Sopenharmony_ci#include "qplib_rcfw.h" 508c2ecf20Sopenharmony_ci#include "qplib_sp.h" 518c2ecf20Sopenharmony_ci#include "qplib_fp.h" 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_cistatic void bnxt_qplib_service_creq(struct tasklet_struct *t); 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci/* Hardware communication channel */ 568c2ecf20Sopenharmony_cistatic int __wait_for_resp(struct bnxt_qplib_rcfw *rcfw, u16 cookie) 578c2ecf20Sopenharmony_ci{ 588c2ecf20Sopenharmony_ci struct bnxt_qplib_cmdq_ctx *cmdq; 598c2ecf20Sopenharmony_ci u16 cbit; 608c2ecf20Sopenharmony_ci int rc; 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci cmdq = &rcfw->cmdq; 638c2ecf20Sopenharmony_ci cbit = cookie % rcfw->cmdq_depth; 648c2ecf20Sopenharmony_ci rc = wait_event_timeout(cmdq->waitq, 658c2ecf20Sopenharmony_ci !test_bit(cbit, cmdq->cmdq_bitmap), 668c2ecf20Sopenharmony_ci msecs_to_jiffies(RCFW_CMD_WAIT_TIME_MS)); 678c2ecf20Sopenharmony_ci return rc ? 0 : -ETIMEDOUT; 688c2ecf20Sopenharmony_ci}; 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_cistatic int __block_for_resp(struct bnxt_qplib_rcfw *rcfw, u16 cookie) 718c2ecf20Sopenharmony_ci{ 728c2ecf20Sopenharmony_ci u32 count = RCFW_BLOCKED_CMD_WAIT_COUNT; 738c2ecf20Sopenharmony_ci struct bnxt_qplib_cmdq_ctx *cmdq; 748c2ecf20Sopenharmony_ci u16 cbit; 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci cmdq = &rcfw->cmdq; 778c2ecf20Sopenharmony_ci cbit = cookie % rcfw->cmdq_depth; 788c2ecf20Sopenharmony_ci if (!test_bit(cbit, cmdq->cmdq_bitmap)) 798c2ecf20Sopenharmony_ci goto done; 808c2ecf20Sopenharmony_ci do { 818c2ecf20Sopenharmony_ci mdelay(1); /* 1m sec */ 828c2ecf20Sopenharmony_ci bnxt_qplib_service_creq(&rcfw->creq.creq_tasklet); 838c2ecf20Sopenharmony_ci } while (test_bit(cbit, cmdq->cmdq_bitmap) && --count); 848c2ecf20Sopenharmony_cidone: 858c2ecf20Sopenharmony_ci return count ? 0 : -ETIMEDOUT; 868c2ecf20Sopenharmony_ci}; 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_cistatic int __send_message(struct bnxt_qplib_rcfw *rcfw, struct cmdq_base *req, 898c2ecf20Sopenharmony_ci struct creq_base *resp, void *sb, u8 is_block) 908c2ecf20Sopenharmony_ci{ 918c2ecf20Sopenharmony_ci struct bnxt_qplib_cmdq_ctx *cmdq = &rcfw->cmdq; 928c2ecf20Sopenharmony_ci struct bnxt_qplib_hwq *hwq = &cmdq->hwq; 938c2ecf20Sopenharmony_ci struct bnxt_qplib_crsqe *crsqe; 948c2ecf20Sopenharmony_ci struct bnxt_qplib_cmdqe *cmdqe; 958c2ecf20Sopenharmony_ci u32 sw_prod, cmdq_prod; 968c2ecf20Sopenharmony_ci struct pci_dev *pdev; 978c2ecf20Sopenharmony_ci unsigned long flags; 988c2ecf20Sopenharmony_ci u32 size, opcode; 998c2ecf20Sopenharmony_ci u16 cookie, cbit; 1008c2ecf20Sopenharmony_ci u8 *preq; 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci pdev = rcfw->pdev; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci opcode = req->opcode; 1058c2ecf20Sopenharmony_ci if (!test_bit(FIRMWARE_INITIALIZED_FLAG, &cmdq->flags) && 1068c2ecf20Sopenharmony_ci (opcode != CMDQ_BASE_OPCODE_QUERY_FUNC && 1078c2ecf20Sopenharmony_ci opcode != CMDQ_BASE_OPCODE_INITIALIZE_FW && 1088c2ecf20Sopenharmony_ci opcode != CMDQ_BASE_OPCODE_QUERY_VERSION)) { 1098c2ecf20Sopenharmony_ci dev_err(&pdev->dev, 1108c2ecf20Sopenharmony_ci "RCFW not initialized, reject opcode 0x%x\n", opcode); 1118c2ecf20Sopenharmony_ci return -EINVAL; 1128c2ecf20Sopenharmony_ci } 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci if (test_bit(FIRMWARE_INITIALIZED_FLAG, &cmdq->flags) && 1158c2ecf20Sopenharmony_ci opcode == CMDQ_BASE_OPCODE_INITIALIZE_FW) { 1168c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "RCFW already initialized!\n"); 1178c2ecf20Sopenharmony_ci return -EINVAL; 1188c2ecf20Sopenharmony_ci } 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci if (test_bit(FIRMWARE_TIMED_OUT, &cmdq->flags)) 1218c2ecf20Sopenharmony_ci return -ETIMEDOUT; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci /* Cmdq are in 16-byte units, each request can consume 1 or more 1248c2ecf20Sopenharmony_ci * cmdqe 1258c2ecf20Sopenharmony_ci */ 1268c2ecf20Sopenharmony_ci spin_lock_irqsave(&hwq->lock, flags); 1278c2ecf20Sopenharmony_ci if (req->cmd_size >= HWQ_FREE_SLOTS(hwq)) { 1288c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "RCFW: CMDQ is full!\n"); 1298c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&hwq->lock, flags); 1308c2ecf20Sopenharmony_ci return -EAGAIN; 1318c2ecf20Sopenharmony_ci } 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci cookie = cmdq->seq_num & RCFW_MAX_COOKIE_VALUE; 1358c2ecf20Sopenharmony_ci cbit = cookie % rcfw->cmdq_depth; 1368c2ecf20Sopenharmony_ci if (is_block) 1378c2ecf20Sopenharmony_ci cookie |= RCFW_CMD_IS_BLOCKING; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci set_bit(cbit, cmdq->cmdq_bitmap); 1408c2ecf20Sopenharmony_ci req->cookie = cpu_to_le16(cookie); 1418c2ecf20Sopenharmony_ci crsqe = &rcfw->crsqe_tbl[cbit]; 1428c2ecf20Sopenharmony_ci if (crsqe->resp) { 1438c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&hwq->lock, flags); 1448c2ecf20Sopenharmony_ci return -EBUSY; 1458c2ecf20Sopenharmony_ci } 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci size = req->cmd_size; 1488c2ecf20Sopenharmony_ci /* change the cmd_size to the number of 16byte cmdq unit. 1498c2ecf20Sopenharmony_ci * req->cmd_size is modified here 1508c2ecf20Sopenharmony_ci */ 1518c2ecf20Sopenharmony_ci bnxt_qplib_set_cmd_slots(req); 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci memset(resp, 0, sizeof(*resp)); 1548c2ecf20Sopenharmony_ci crsqe->resp = (struct creq_qp_event *)resp; 1558c2ecf20Sopenharmony_ci crsqe->resp->cookie = req->cookie; 1568c2ecf20Sopenharmony_ci crsqe->req_size = req->cmd_size; 1578c2ecf20Sopenharmony_ci if (req->resp_size && sb) { 1588c2ecf20Sopenharmony_ci struct bnxt_qplib_rcfw_sbuf *sbuf = sb; 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci req->resp_addr = cpu_to_le64(sbuf->dma_addr); 1618c2ecf20Sopenharmony_ci req->resp_size = (sbuf->size + BNXT_QPLIB_CMDQE_UNITS - 1) / 1628c2ecf20Sopenharmony_ci BNXT_QPLIB_CMDQE_UNITS; 1638c2ecf20Sopenharmony_ci } 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci preq = (u8 *)req; 1668c2ecf20Sopenharmony_ci do { 1678c2ecf20Sopenharmony_ci /* Locate the next cmdq slot */ 1688c2ecf20Sopenharmony_ci sw_prod = HWQ_CMP(hwq->prod, hwq); 1698c2ecf20Sopenharmony_ci cmdqe = bnxt_qplib_get_qe(hwq, sw_prod, NULL); 1708c2ecf20Sopenharmony_ci if (!cmdqe) { 1718c2ecf20Sopenharmony_ci dev_err(&pdev->dev, 1728c2ecf20Sopenharmony_ci "RCFW request failed with no cmdqe!\n"); 1738c2ecf20Sopenharmony_ci goto done; 1748c2ecf20Sopenharmony_ci } 1758c2ecf20Sopenharmony_ci /* Copy a segment of the req cmd to the cmdq */ 1768c2ecf20Sopenharmony_ci memset(cmdqe, 0, sizeof(*cmdqe)); 1778c2ecf20Sopenharmony_ci memcpy(cmdqe, preq, min_t(u32, size, sizeof(*cmdqe))); 1788c2ecf20Sopenharmony_ci preq += min_t(u32, size, sizeof(*cmdqe)); 1798c2ecf20Sopenharmony_ci size -= min_t(u32, size, sizeof(*cmdqe)); 1808c2ecf20Sopenharmony_ci hwq->prod++; 1818c2ecf20Sopenharmony_ci } while (size > 0); 1828c2ecf20Sopenharmony_ci cmdq->seq_num++; 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci cmdq_prod = hwq->prod & 0xFFFF; 1858c2ecf20Sopenharmony_ci if (test_bit(FIRMWARE_FIRST_FLAG, &cmdq->flags)) { 1868c2ecf20Sopenharmony_ci /* The very first doorbell write 1878c2ecf20Sopenharmony_ci * is required to set this flag 1888c2ecf20Sopenharmony_ci * which prompts the FW to reset 1898c2ecf20Sopenharmony_ci * its internal pointers 1908c2ecf20Sopenharmony_ci */ 1918c2ecf20Sopenharmony_ci cmdq_prod |= BIT(FIRMWARE_FIRST_FLAG); 1928c2ecf20Sopenharmony_ci clear_bit(FIRMWARE_FIRST_FLAG, &cmdq->flags); 1938c2ecf20Sopenharmony_ci } 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci /* ring CMDQ DB */ 1968c2ecf20Sopenharmony_ci wmb(); 1978c2ecf20Sopenharmony_ci writel(cmdq_prod, cmdq->cmdq_mbox.prod); 1988c2ecf20Sopenharmony_ci writel(RCFW_CMDQ_TRIG_VAL, cmdq->cmdq_mbox.db); 1998c2ecf20Sopenharmony_cidone: 2008c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&hwq->lock, flags); 2018c2ecf20Sopenharmony_ci /* Return the CREQ response pointer */ 2028c2ecf20Sopenharmony_ci return 0; 2038c2ecf20Sopenharmony_ci} 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ciint bnxt_qplib_rcfw_send_message(struct bnxt_qplib_rcfw *rcfw, 2068c2ecf20Sopenharmony_ci struct cmdq_base *req, 2078c2ecf20Sopenharmony_ci struct creq_base *resp, 2088c2ecf20Sopenharmony_ci void *sb, u8 is_block) 2098c2ecf20Sopenharmony_ci{ 2108c2ecf20Sopenharmony_ci struct creq_qp_event *evnt = (struct creq_qp_event *)resp; 2118c2ecf20Sopenharmony_ci u16 cookie; 2128c2ecf20Sopenharmony_ci u8 opcode, retry_cnt = 0xFF; 2138c2ecf20Sopenharmony_ci int rc = 0; 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci do { 2168c2ecf20Sopenharmony_ci opcode = req->opcode; 2178c2ecf20Sopenharmony_ci rc = __send_message(rcfw, req, resp, sb, is_block); 2188c2ecf20Sopenharmony_ci cookie = le16_to_cpu(req->cookie) & RCFW_MAX_COOKIE_VALUE; 2198c2ecf20Sopenharmony_ci if (!rc) 2208c2ecf20Sopenharmony_ci break; 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci if (!retry_cnt || (rc != -EAGAIN && rc != -EBUSY)) { 2238c2ecf20Sopenharmony_ci /* send failed */ 2248c2ecf20Sopenharmony_ci dev_err(&rcfw->pdev->dev, "cmdq[%#x]=%#x send failed\n", 2258c2ecf20Sopenharmony_ci cookie, opcode); 2268c2ecf20Sopenharmony_ci return rc; 2278c2ecf20Sopenharmony_ci } 2288c2ecf20Sopenharmony_ci is_block ? mdelay(1) : usleep_range(500, 1000); 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci } while (retry_cnt--); 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci if (is_block) 2338c2ecf20Sopenharmony_ci rc = __block_for_resp(rcfw, cookie); 2348c2ecf20Sopenharmony_ci else 2358c2ecf20Sopenharmony_ci rc = __wait_for_resp(rcfw, cookie); 2368c2ecf20Sopenharmony_ci if (rc) { 2378c2ecf20Sopenharmony_ci /* timed out */ 2388c2ecf20Sopenharmony_ci dev_err(&rcfw->pdev->dev, "cmdq[%#x]=%#x timedout (%d)msec\n", 2398c2ecf20Sopenharmony_ci cookie, opcode, RCFW_CMD_WAIT_TIME_MS); 2408c2ecf20Sopenharmony_ci set_bit(FIRMWARE_TIMED_OUT, &rcfw->cmdq.flags); 2418c2ecf20Sopenharmony_ci return rc; 2428c2ecf20Sopenharmony_ci } 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci if (evnt->status) { 2458c2ecf20Sopenharmony_ci /* failed with status */ 2468c2ecf20Sopenharmony_ci dev_err(&rcfw->pdev->dev, "cmdq[%#x]=%#x status %#x\n", 2478c2ecf20Sopenharmony_ci cookie, opcode, evnt->status); 2488c2ecf20Sopenharmony_ci rc = -EFAULT; 2498c2ecf20Sopenharmony_ci } 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci return rc; 2528c2ecf20Sopenharmony_ci} 2538c2ecf20Sopenharmony_ci/* Completions */ 2548c2ecf20Sopenharmony_cistatic int bnxt_qplib_process_func_event(struct bnxt_qplib_rcfw *rcfw, 2558c2ecf20Sopenharmony_ci struct creq_func_event *func_event) 2568c2ecf20Sopenharmony_ci{ 2578c2ecf20Sopenharmony_ci int rc; 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci switch (func_event->event) { 2608c2ecf20Sopenharmony_ci case CREQ_FUNC_EVENT_EVENT_TX_WQE_ERROR: 2618c2ecf20Sopenharmony_ci break; 2628c2ecf20Sopenharmony_ci case CREQ_FUNC_EVENT_EVENT_TX_DATA_ERROR: 2638c2ecf20Sopenharmony_ci break; 2648c2ecf20Sopenharmony_ci case CREQ_FUNC_EVENT_EVENT_RX_WQE_ERROR: 2658c2ecf20Sopenharmony_ci break; 2668c2ecf20Sopenharmony_ci case CREQ_FUNC_EVENT_EVENT_RX_DATA_ERROR: 2678c2ecf20Sopenharmony_ci break; 2688c2ecf20Sopenharmony_ci case CREQ_FUNC_EVENT_EVENT_CQ_ERROR: 2698c2ecf20Sopenharmony_ci break; 2708c2ecf20Sopenharmony_ci case CREQ_FUNC_EVENT_EVENT_TQM_ERROR: 2718c2ecf20Sopenharmony_ci break; 2728c2ecf20Sopenharmony_ci case CREQ_FUNC_EVENT_EVENT_CFCQ_ERROR: 2738c2ecf20Sopenharmony_ci break; 2748c2ecf20Sopenharmony_ci case CREQ_FUNC_EVENT_EVENT_CFCS_ERROR: 2758c2ecf20Sopenharmony_ci /* SRQ ctx error, call srq_handler?? 2768c2ecf20Sopenharmony_ci * But there's no SRQ handle! 2778c2ecf20Sopenharmony_ci */ 2788c2ecf20Sopenharmony_ci break; 2798c2ecf20Sopenharmony_ci case CREQ_FUNC_EVENT_EVENT_CFCC_ERROR: 2808c2ecf20Sopenharmony_ci break; 2818c2ecf20Sopenharmony_ci case CREQ_FUNC_EVENT_EVENT_CFCM_ERROR: 2828c2ecf20Sopenharmony_ci break; 2838c2ecf20Sopenharmony_ci case CREQ_FUNC_EVENT_EVENT_TIM_ERROR: 2848c2ecf20Sopenharmony_ci break; 2858c2ecf20Sopenharmony_ci case CREQ_FUNC_EVENT_EVENT_VF_COMM_REQUEST: 2868c2ecf20Sopenharmony_ci break; 2878c2ecf20Sopenharmony_ci case CREQ_FUNC_EVENT_EVENT_RESOURCE_EXHAUSTED: 2888c2ecf20Sopenharmony_ci break; 2898c2ecf20Sopenharmony_ci default: 2908c2ecf20Sopenharmony_ci return -EINVAL; 2918c2ecf20Sopenharmony_ci } 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci rc = rcfw->creq.aeq_handler(rcfw, (void *)func_event, NULL); 2948c2ecf20Sopenharmony_ci return rc; 2958c2ecf20Sopenharmony_ci} 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_cistatic int bnxt_qplib_process_qp_event(struct bnxt_qplib_rcfw *rcfw, 2988c2ecf20Sopenharmony_ci struct creq_qp_event *qp_event, 2998c2ecf20Sopenharmony_ci u32 *num_wait) 3008c2ecf20Sopenharmony_ci{ 3018c2ecf20Sopenharmony_ci struct creq_qp_error_notification *err_event; 3028c2ecf20Sopenharmony_ci struct bnxt_qplib_hwq *hwq = &rcfw->cmdq.hwq; 3038c2ecf20Sopenharmony_ci struct bnxt_qplib_crsqe *crsqe; 3048c2ecf20Sopenharmony_ci struct bnxt_qplib_qp *qp; 3058c2ecf20Sopenharmony_ci u16 cbit, blocked = 0; 3068c2ecf20Sopenharmony_ci struct pci_dev *pdev; 3078c2ecf20Sopenharmony_ci unsigned long flags; 3088c2ecf20Sopenharmony_ci u32 wait_cmds = 0; 3098c2ecf20Sopenharmony_ci __le16 mcookie; 3108c2ecf20Sopenharmony_ci u16 cookie; 3118c2ecf20Sopenharmony_ci int rc = 0; 3128c2ecf20Sopenharmony_ci u32 qp_id, tbl_indx; 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci pdev = rcfw->pdev; 3158c2ecf20Sopenharmony_ci switch (qp_event->event) { 3168c2ecf20Sopenharmony_ci case CREQ_QP_EVENT_EVENT_QP_ERROR_NOTIFICATION: 3178c2ecf20Sopenharmony_ci err_event = (struct creq_qp_error_notification *)qp_event; 3188c2ecf20Sopenharmony_ci qp_id = le32_to_cpu(err_event->xid); 3198c2ecf20Sopenharmony_ci tbl_indx = map_qp_id_to_tbl_indx(qp_id, rcfw); 3208c2ecf20Sopenharmony_ci qp = rcfw->qp_tbl[tbl_indx].qp_handle; 3218c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, "Received QP error notification\n"); 3228c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, 3238c2ecf20Sopenharmony_ci "qpid 0x%x, req_err=0x%x, resp_err=0x%x\n", 3248c2ecf20Sopenharmony_ci qp_id, err_event->req_err_state_reason, 3258c2ecf20Sopenharmony_ci err_event->res_err_state_reason); 3268c2ecf20Sopenharmony_ci if (!qp) 3278c2ecf20Sopenharmony_ci break; 3288c2ecf20Sopenharmony_ci bnxt_qplib_mark_qp_error(qp); 3298c2ecf20Sopenharmony_ci rc = rcfw->creq.aeq_handler(rcfw, qp_event, qp); 3308c2ecf20Sopenharmony_ci break; 3318c2ecf20Sopenharmony_ci default: 3328c2ecf20Sopenharmony_ci /* 3338c2ecf20Sopenharmony_ci * Command Response 3348c2ecf20Sopenharmony_ci * cmdq->lock needs to be acquired to synchronie 3358c2ecf20Sopenharmony_ci * the command send and completion reaping. This function 3368c2ecf20Sopenharmony_ci * is always called with creq->lock held. Using 3378c2ecf20Sopenharmony_ci * the nested variant of spin_lock. 3388c2ecf20Sopenharmony_ci * 3398c2ecf20Sopenharmony_ci */ 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci spin_lock_irqsave_nested(&hwq->lock, flags, 3428c2ecf20Sopenharmony_ci SINGLE_DEPTH_NESTING); 3438c2ecf20Sopenharmony_ci cookie = le16_to_cpu(qp_event->cookie); 3448c2ecf20Sopenharmony_ci mcookie = qp_event->cookie; 3458c2ecf20Sopenharmony_ci blocked = cookie & RCFW_CMD_IS_BLOCKING; 3468c2ecf20Sopenharmony_ci cookie &= RCFW_MAX_COOKIE_VALUE; 3478c2ecf20Sopenharmony_ci cbit = cookie % rcfw->cmdq_depth; 3488c2ecf20Sopenharmony_ci crsqe = &rcfw->crsqe_tbl[cbit]; 3498c2ecf20Sopenharmony_ci if (crsqe->resp && 3508c2ecf20Sopenharmony_ci crsqe->resp->cookie == mcookie) { 3518c2ecf20Sopenharmony_ci memcpy(crsqe->resp, qp_event, sizeof(*qp_event)); 3528c2ecf20Sopenharmony_ci crsqe->resp = NULL; 3538c2ecf20Sopenharmony_ci } else { 3548c2ecf20Sopenharmony_ci if (crsqe->resp && crsqe->resp->cookie) 3558c2ecf20Sopenharmony_ci dev_err(&pdev->dev, 3568c2ecf20Sopenharmony_ci "CMD %s cookie sent=%#x, recd=%#x\n", 3578c2ecf20Sopenharmony_ci crsqe->resp ? "mismatch" : "collision", 3588c2ecf20Sopenharmony_ci crsqe->resp ? crsqe->resp->cookie : 0, 3598c2ecf20Sopenharmony_ci mcookie); 3608c2ecf20Sopenharmony_ci } 3618c2ecf20Sopenharmony_ci if (!test_and_clear_bit(cbit, rcfw->cmdq.cmdq_bitmap)) 3628c2ecf20Sopenharmony_ci dev_warn(&pdev->dev, 3638c2ecf20Sopenharmony_ci "CMD bit %d was not requested\n", cbit); 3648c2ecf20Sopenharmony_ci hwq->cons += crsqe->req_size; 3658c2ecf20Sopenharmony_ci crsqe->req_size = 0; 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci if (!blocked) 3688c2ecf20Sopenharmony_ci wait_cmds++; 3698c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&hwq->lock, flags); 3708c2ecf20Sopenharmony_ci } 3718c2ecf20Sopenharmony_ci *num_wait += wait_cmds; 3728c2ecf20Sopenharmony_ci return rc; 3738c2ecf20Sopenharmony_ci} 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci/* SP - CREQ Completion handlers */ 3768c2ecf20Sopenharmony_cistatic void bnxt_qplib_service_creq(struct tasklet_struct *t) 3778c2ecf20Sopenharmony_ci{ 3788c2ecf20Sopenharmony_ci struct bnxt_qplib_rcfw *rcfw = from_tasklet(rcfw, t, creq.creq_tasklet); 3798c2ecf20Sopenharmony_ci struct bnxt_qplib_creq_ctx *creq = &rcfw->creq; 3808c2ecf20Sopenharmony_ci u32 type, budget = CREQ_ENTRY_POLL_BUDGET; 3818c2ecf20Sopenharmony_ci struct bnxt_qplib_hwq *hwq = &creq->hwq; 3828c2ecf20Sopenharmony_ci struct creq_base *creqe; 3838c2ecf20Sopenharmony_ci u32 sw_cons, raw_cons; 3848c2ecf20Sopenharmony_ci unsigned long flags; 3858c2ecf20Sopenharmony_ci u32 num_wakeup = 0; 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci /* Service the CREQ until budget is over */ 3888c2ecf20Sopenharmony_ci spin_lock_irqsave(&hwq->lock, flags); 3898c2ecf20Sopenharmony_ci raw_cons = hwq->cons; 3908c2ecf20Sopenharmony_ci while (budget > 0) { 3918c2ecf20Sopenharmony_ci sw_cons = HWQ_CMP(raw_cons, hwq); 3928c2ecf20Sopenharmony_ci creqe = bnxt_qplib_get_qe(hwq, sw_cons, NULL); 3938c2ecf20Sopenharmony_ci if (!CREQ_CMP_VALID(creqe, raw_cons, hwq->max_elements)) 3948c2ecf20Sopenharmony_ci break; 3958c2ecf20Sopenharmony_ci /* The valid test of the entry must be done first before 3968c2ecf20Sopenharmony_ci * reading any further. 3978c2ecf20Sopenharmony_ci */ 3988c2ecf20Sopenharmony_ci dma_rmb(); 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci type = creqe->type & CREQ_BASE_TYPE_MASK; 4018c2ecf20Sopenharmony_ci switch (type) { 4028c2ecf20Sopenharmony_ci case CREQ_BASE_TYPE_QP_EVENT: 4038c2ecf20Sopenharmony_ci bnxt_qplib_process_qp_event 4048c2ecf20Sopenharmony_ci (rcfw, (struct creq_qp_event *)creqe, 4058c2ecf20Sopenharmony_ci &num_wakeup); 4068c2ecf20Sopenharmony_ci creq->stats.creq_qp_event_processed++; 4078c2ecf20Sopenharmony_ci break; 4088c2ecf20Sopenharmony_ci case CREQ_BASE_TYPE_FUNC_EVENT: 4098c2ecf20Sopenharmony_ci if (!bnxt_qplib_process_func_event 4108c2ecf20Sopenharmony_ci (rcfw, (struct creq_func_event *)creqe)) 4118c2ecf20Sopenharmony_ci creq->stats.creq_func_event_processed++; 4128c2ecf20Sopenharmony_ci else 4138c2ecf20Sopenharmony_ci dev_warn(&rcfw->pdev->dev, 4148c2ecf20Sopenharmony_ci "aeqe:%#x Not handled\n", type); 4158c2ecf20Sopenharmony_ci break; 4168c2ecf20Sopenharmony_ci default: 4178c2ecf20Sopenharmony_ci if (type != ASYNC_EVENT_CMPL_TYPE_HWRM_ASYNC_EVENT) 4188c2ecf20Sopenharmony_ci dev_warn(&rcfw->pdev->dev, 4198c2ecf20Sopenharmony_ci "creqe with event 0x%x not handled\n", 4208c2ecf20Sopenharmony_ci type); 4218c2ecf20Sopenharmony_ci break; 4228c2ecf20Sopenharmony_ci } 4238c2ecf20Sopenharmony_ci raw_cons++; 4248c2ecf20Sopenharmony_ci budget--; 4258c2ecf20Sopenharmony_ci } 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci if (hwq->cons != raw_cons) { 4288c2ecf20Sopenharmony_ci hwq->cons = raw_cons; 4298c2ecf20Sopenharmony_ci bnxt_qplib_ring_nq_db(&creq->creq_db.dbinfo, 4308c2ecf20Sopenharmony_ci rcfw->res->cctx, true); 4318c2ecf20Sopenharmony_ci } 4328c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&hwq->lock, flags); 4338c2ecf20Sopenharmony_ci if (num_wakeup) 4348c2ecf20Sopenharmony_ci wake_up_nr(&rcfw->cmdq.waitq, num_wakeup); 4358c2ecf20Sopenharmony_ci} 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_cistatic irqreturn_t bnxt_qplib_creq_irq(int irq, void *dev_instance) 4388c2ecf20Sopenharmony_ci{ 4398c2ecf20Sopenharmony_ci struct bnxt_qplib_rcfw *rcfw = dev_instance; 4408c2ecf20Sopenharmony_ci struct bnxt_qplib_creq_ctx *creq; 4418c2ecf20Sopenharmony_ci struct bnxt_qplib_hwq *hwq; 4428c2ecf20Sopenharmony_ci u32 sw_cons; 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci creq = &rcfw->creq; 4458c2ecf20Sopenharmony_ci hwq = &creq->hwq; 4468c2ecf20Sopenharmony_ci /* Prefetch the CREQ element */ 4478c2ecf20Sopenharmony_ci sw_cons = HWQ_CMP(hwq->cons, hwq); 4488c2ecf20Sopenharmony_ci prefetch(bnxt_qplib_get_qe(hwq, sw_cons, NULL)); 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci tasklet_schedule(&creq->creq_tasklet); 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci return IRQ_HANDLED; 4538c2ecf20Sopenharmony_ci} 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci/* RCFW */ 4568c2ecf20Sopenharmony_ciint bnxt_qplib_deinit_rcfw(struct bnxt_qplib_rcfw *rcfw) 4578c2ecf20Sopenharmony_ci{ 4588c2ecf20Sopenharmony_ci struct cmdq_deinitialize_fw req; 4598c2ecf20Sopenharmony_ci struct creq_deinitialize_fw_resp resp; 4608c2ecf20Sopenharmony_ci u16 cmd_flags = 0; 4618c2ecf20Sopenharmony_ci int rc; 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci RCFW_CMD_PREP(req, DEINITIALIZE_FW, cmd_flags); 4648c2ecf20Sopenharmony_ci rc = bnxt_qplib_rcfw_send_message(rcfw, (void *)&req, (void *)&resp, 4658c2ecf20Sopenharmony_ci NULL, 0); 4668c2ecf20Sopenharmony_ci if (rc) 4678c2ecf20Sopenharmony_ci return rc; 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci clear_bit(FIRMWARE_INITIALIZED_FLAG, &rcfw->cmdq.flags); 4708c2ecf20Sopenharmony_ci return 0; 4718c2ecf20Sopenharmony_ci} 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ciint bnxt_qplib_init_rcfw(struct bnxt_qplib_rcfw *rcfw, 4748c2ecf20Sopenharmony_ci struct bnxt_qplib_ctx *ctx, int is_virtfn) 4758c2ecf20Sopenharmony_ci{ 4768c2ecf20Sopenharmony_ci struct creq_initialize_fw_resp resp; 4778c2ecf20Sopenharmony_ci struct cmdq_initialize_fw req; 4788c2ecf20Sopenharmony_ci u16 cmd_flags = 0; 4798c2ecf20Sopenharmony_ci u8 pgsz, lvl; 4808c2ecf20Sopenharmony_ci int rc; 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ci RCFW_CMD_PREP(req, INITIALIZE_FW, cmd_flags); 4838c2ecf20Sopenharmony_ci /* Supply (log-base-2-of-host-page-size - base-page-shift) 4848c2ecf20Sopenharmony_ci * to bono to adjust the doorbell page sizes. 4858c2ecf20Sopenharmony_ci */ 4868c2ecf20Sopenharmony_ci req.log2_dbr_pg_size = cpu_to_le16(PAGE_SHIFT - 4878c2ecf20Sopenharmony_ci RCFW_DBR_BASE_PAGE_SHIFT); 4888c2ecf20Sopenharmony_ci /* 4898c2ecf20Sopenharmony_ci * Gen P5 devices doesn't require this allocation 4908c2ecf20Sopenharmony_ci * as the L2 driver does the same for RoCE also. 4918c2ecf20Sopenharmony_ci * Also, VFs need not setup the HW context area, PF 4928c2ecf20Sopenharmony_ci * shall setup this area for VF. Skipping the 4938c2ecf20Sopenharmony_ci * HW programming 4948c2ecf20Sopenharmony_ci */ 4958c2ecf20Sopenharmony_ci if (is_virtfn) 4968c2ecf20Sopenharmony_ci goto skip_ctx_setup; 4978c2ecf20Sopenharmony_ci if (bnxt_qplib_is_chip_gen_p5(rcfw->res->cctx)) 4988c2ecf20Sopenharmony_ci goto config_vf_res; 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci lvl = ctx->qpc_tbl.level; 5018c2ecf20Sopenharmony_ci pgsz = bnxt_qplib_base_pg_size(&ctx->qpc_tbl); 5028c2ecf20Sopenharmony_ci req.qpc_pg_size_qpc_lvl = (pgsz << CMDQ_INITIALIZE_FW_QPC_PG_SIZE_SFT) | 5038c2ecf20Sopenharmony_ci lvl; 5048c2ecf20Sopenharmony_ci lvl = ctx->mrw_tbl.level; 5058c2ecf20Sopenharmony_ci pgsz = bnxt_qplib_base_pg_size(&ctx->mrw_tbl); 5068c2ecf20Sopenharmony_ci req.mrw_pg_size_mrw_lvl = (pgsz << CMDQ_INITIALIZE_FW_QPC_PG_SIZE_SFT) | 5078c2ecf20Sopenharmony_ci lvl; 5088c2ecf20Sopenharmony_ci lvl = ctx->srqc_tbl.level; 5098c2ecf20Sopenharmony_ci pgsz = bnxt_qplib_base_pg_size(&ctx->srqc_tbl); 5108c2ecf20Sopenharmony_ci req.srq_pg_size_srq_lvl = (pgsz << CMDQ_INITIALIZE_FW_QPC_PG_SIZE_SFT) | 5118c2ecf20Sopenharmony_ci lvl; 5128c2ecf20Sopenharmony_ci lvl = ctx->cq_tbl.level; 5138c2ecf20Sopenharmony_ci pgsz = bnxt_qplib_base_pg_size(&ctx->cq_tbl); 5148c2ecf20Sopenharmony_ci req.cq_pg_size_cq_lvl = (pgsz << CMDQ_INITIALIZE_FW_QPC_PG_SIZE_SFT) | 5158c2ecf20Sopenharmony_ci lvl; 5168c2ecf20Sopenharmony_ci lvl = ctx->tim_tbl.level; 5178c2ecf20Sopenharmony_ci pgsz = bnxt_qplib_base_pg_size(&ctx->tim_tbl); 5188c2ecf20Sopenharmony_ci req.tim_pg_size_tim_lvl = (pgsz << CMDQ_INITIALIZE_FW_QPC_PG_SIZE_SFT) | 5198c2ecf20Sopenharmony_ci lvl; 5208c2ecf20Sopenharmony_ci lvl = ctx->tqm_ctx.pde.level; 5218c2ecf20Sopenharmony_ci pgsz = bnxt_qplib_base_pg_size(&ctx->tqm_ctx.pde); 5228c2ecf20Sopenharmony_ci req.tqm_pg_size_tqm_lvl = (pgsz << CMDQ_INITIALIZE_FW_QPC_PG_SIZE_SFT) | 5238c2ecf20Sopenharmony_ci lvl; 5248c2ecf20Sopenharmony_ci req.qpc_page_dir = 5258c2ecf20Sopenharmony_ci cpu_to_le64(ctx->qpc_tbl.pbl[PBL_LVL_0].pg_map_arr[0]); 5268c2ecf20Sopenharmony_ci req.mrw_page_dir = 5278c2ecf20Sopenharmony_ci cpu_to_le64(ctx->mrw_tbl.pbl[PBL_LVL_0].pg_map_arr[0]); 5288c2ecf20Sopenharmony_ci req.srq_page_dir = 5298c2ecf20Sopenharmony_ci cpu_to_le64(ctx->srqc_tbl.pbl[PBL_LVL_0].pg_map_arr[0]); 5308c2ecf20Sopenharmony_ci req.cq_page_dir = 5318c2ecf20Sopenharmony_ci cpu_to_le64(ctx->cq_tbl.pbl[PBL_LVL_0].pg_map_arr[0]); 5328c2ecf20Sopenharmony_ci req.tim_page_dir = 5338c2ecf20Sopenharmony_ci cpu_to_le64(ctx->tim_tbl.pbl[PBL_LVL_0].pg_map_arr[0]); 5348c2ecf20Sopenharmony_ci req.tqm_page_dir = 5358c2ecf20Sopenharmony_ci cpu_to_le64(ctx->tqm_ctx.pde.pbl[PBL_LVL_0].pg_map_arr[0]); 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci req.number_of_qp = cpu_to_le32(ctx->qpc_tbl.max_elements); 5388c2ecf20Sopenharmony_ci req.number_of_mrw = cpu_to_le32(ctx->mrw_tbl.max_elements); 5398c2ecf20Sopenharmony_ci req.number_of_srq = cpu_to_le32(ctx->srqc_tbl.max_elements); 5408c2ecf20Sopenharmony_ci req.number_of_cq = cpu_to_le32(ctx->cq_tbl.max_elements); 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ciconfig_vf_res: 5438c2ecf20Sopenharmony_ci req.max_qp_per_vf = cpu_to_le32(ctx->vf_res.max_qp_per_vf); 5448c2ecf20Sopenharmony_ci req.max_mrw_per_vf = cpu_to_le32(ctx->vf_res.max_mrw_per_vf); 5458c2ecf20Sopenharmony_ci req.max_srq_per_vf = cpu_to_le32(ctx->vf_res.max_srq_per_vf); 5468c2ecf20Sopenharmony_ci req.max_cq_per_vf = cpu_to_le32(ctx->vf_res.max_cq_per_vf); 5478c2ecf20Sopenharmony_ci req.max_gid_per_vf = cpu_to_le32(ctx->vf_res.max_gid_per_vf); 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ciskip_ctx_setup: 5508c2ecf20Sopenharmony_ci req.stat_ctx_id = cpu_to_le32(ctx->stats.fw_id); 5518c2ecf20Sopenharmony_ci rc = bnxt_qplib_rcfw_send_message(rcfw, (void *)&req, (void *)&resp, 5528c2ecf20Sopenharmony_ci NULL, 0); 5538c2ecf20Sopenharmony_ci if (rc) 5548c2ecf20Sopenharmony_ci return rc; 5558c2ecf20Sopenharmony_ci set_bit(FIRMWARE_INITIALIZED_FLAG, &rcfw->cmdq.flags); 5568c2ecf20Sopenharmony_ci return 0; 5578c2ecf20Sopenharmony_ci} 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_civoid bnxt_qplib_free_rcfw_channel(struct bnxt_qplib_rcfw *rcfw) 5608c2ecf20Sopenharmony_ci{ 5618c2ecf20Sopenharmony_ci kfree(rcfw->cmdq.cmdq_bitmap); 5628c2ecf20Sopenharmony_ci kfree(rcfw->qp_tbl); 5638c2ecf20Sopenharmony_ci kfree(rcfw->crsqe_tbl); 5648c2ecf20Sopenharmony_ci bnxt_qplib_free_hwq(rcfw->res, &rcfw->cmdq.hwq); 5658c2ecf20Sopenharmony_ci bnxt_qplib_free_hwq(rcfw->res, &rcfw->creq.hwq); 5668c2ecf20Sopenharmony_ci rcfw->pdev = NULL; 5678c2ecf20Sopenharmony_ci} 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ciint bnxt_qplib_alloc_rcfw_channel(struct bnxt_qplib_res *res, 5708c2ecf20Sopenharmony_ci struct bnxt_qplib_rcfw *rcfw, 5718c2ecf20Sopenharmony_ci struct bnxt_qplib_ctx *ctx, 5728c2ecf20Sopenharmony_ci int qp_tbl_sz) 5738c2ecf20Sopenharmony_ci{ 5748c2ecf20Sopenharmony_ci struct bnxt_qplib_hwq_attr hwq_attr = {}; 5758c2ecf20Sopenharmony_ci struct bnxt_qplib_sg_info sginfo = {}; 5768c2ecf20Sopenharmony_ci struct bnxt_qplib_cmdq_ctx *cmdq; 5778c2ecf20Sopenharmony_ci struct bnxt_qplib_creq_ctx *creq; 5788c2ecf20Sopenharmony_ci u32 bmap_size = 0; 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci rcfw->pdev = res->pdev; 5818c2ecf20Sopenharmony_ci cmdq = &rcfw->cmdq; 5828c2ecf20Sopenharmony_ci creq = &rcfw->creq; 5838c2ecf20Sopenharmony_ci rcfw->res = res; 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_ci sginfo.pgsize = PAGE_SIZE; 5868c2ecf20Sopenharmony_ci sginfo.pgshft = PAGE_SHIFT; 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci hwq_attr.sginfo = &sginfo; 5898c2ecf20Sopenharmony_ci hwq_attr.res = rcfw->res; 5908c2ecf20Sopenharmony_ci hwq_attr.depth = BNXT_QPLIB_CREQE_MAX_CNT; 5918c2ecf20Sopenharmony_ci hwq_attr.stride = BNXT_QPLIB_CREQE_UNITS; 5928c2ecf20Sopenharmony_ci hwq_attr.type = bnxt_qplib_get_hwq_type(res); 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_ci if (bnxt_qplib_alloc_init_hwq(&creq->hwq, &hwq_attr)) { 5958c2ecf20Sopenharmony_ci dev_err(&rcfw->pdev->dev, 5968c2ecf20Sopenharmony_ci "HW channel CREQ allocation failed\n"); 5978c2ecf20Sopenharmony_ci goto fail; 5988c2ecf20Sopenharmony_ci } 5998c2ecf20Sopenharmony_ci if (ctx->hwrm_intf_ver < HWRM_VERSION_RCFW_CMDQ_DEPTH_CHECK) 6008c2ecf20Sopenharmony_ci rcfw->cmdq_depth = BNXT_QPLIB_CMDQE_MAX_CNT_256; 6018c2ecf20Sopenharmony_ci else 6028c2ecf20Sopenharmony_ci rcfw->cmdq_depth = BNXT_QPLIB_CMDQE_MAX_CNT_8192; 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ci sginfo.pgsize = bnxt_qplib_cmdqe_page_size(rcfw->cmdq_depth); 6058c2ecf20Sopenharmony_ci hwq_attr.depth = rcfw->cmdq_depth & 0x7FFFFFFF; 6068c2ecf20Sopenharmony_ci hwq_attr.stride = BNXT_QPLIB_CMDQE_UNITS; 6078c2ecf20Sopenharmony_ci hwq_attr.type = HWQ_TYPE_CTX; 6088c2ecf20Sopenharmony_ci if (bnxt_qplib_alloc_init_hwq(&cmdq->hwq, &hwq_attr)) { 6098c2ecf20Sopenharmony_ci dev_err(&rcfw->pdev->dev, 6108c2ecf20Sopenharmony_ci "HW channel CMDQ allocation failed\n"); 6118c2ecf20Sopenharmony_ci goto fail; 6128c2ecf20Sopenharmony_ci } 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci rcfw->crsqe_tbl = kcalloc(cmdq->hwq.max_elements, 6158c2ecf20Sopenharmony_ci sizeof(*rcfw->crsqe_tbl), GFP_KERNEL); 6168c2ecf20Sopenharmony_ci if (!rcfw->crsqe_tbl) 6178c2ecf20Sopenharmony_ci goto fail; 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci bmap_size = BITS_TO_LONGS(rcfw->cmdq_depth) * sizeof(unsigned long); 6208c2ecf20Sopenharmony_ci cmdq->cmdq_bitmap = kzalloc(bmap_size, GFP_KERNEL); 6218c2ecf20Sopenharmony_ci if (!cmdq->cmdq_bitmap) 6228c2ecf20Sopenharmony_ci goto fail; 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci /* Allocate one extra to hold the QP1 entries */ 6258c2ecf20Sopenharmony_ci rcfw->qp_tbl_size = qp_tbl_sz + 1; 6268c2ecf20Sopenharmony_ci rcfw->qp_tbl = kcalloc(rcfw->qp_tbl_size, sizeof(struct bnxt_qplib_qp_node), 6278c2ecf20Sopenharmony_ci GFP_KERNEL); 6288c2ecf20Sopenharmony_ci if (!rcfw->qp_tbl) 6298c2ecf20Sopenharmony_ci goto fail; 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci return 0; 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_cifail: 6348c2ecf20Sopenharmony_ci bnxt_qplib_free_rcfw_channel(rcfw); 6358c2ecf20Sopenharmony_ci return -ENOMEM; 6368c2ecf20Sopenharmony_ci} 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_civoid bnxt_qplib_rcfw_stop_irq(struct bnxt_qplib_rcfw *rcfw, bool kill) 6398c2ecf20Sopenharmony_ci{ 6408c2ecf20Sopenharmony_ci struct bnxt_qplib_creq_ctx *creq; 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_ci creq = &rcfw->creq; 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_ci if (!creq->requested) 6458c2ecf20Sopenharmony_ci return; 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ci tasklet_disable(&creq->creq_tasklet); 6488c2ecf20Sopenharmony_ci /* Mask h/w interrupts */ 6498c2ecf20Sopenharmony_ci bnxt_qplib_ring_nq_db(&creq->creq_db.dbinfo, rcfw->res->cctx, false); 6508c2ecf20Sopenharmony_ci /* Sync with last running IRQ-handler */ 6518c2ecf20Sopenharmony_ci synchronize_irq(creq->msix_vec); 6528c2ecf20Sopenharmony_ci if (kill) 6538c2ecf20Sopenharmony_ci tasklet_kill(&creq->creq_tasklet); 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_ci free_irq(creq->msix_vec, rcfw); 6568c2ecf20Sopenharmony_ci kfree(creq->irq_name); 6578c2ecf20Sopenharmony_ci creq->irq_name = NULL; 6588c2ecf20Sopenharmony_ci creq->requested = false; 6598c2ecf20Sopenharmony_ci} 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_civoid bnxt_qplib_disable_rcfw_channel(struct bnxt_qplib_rcfw *rcfw) 6628c2ecf20Sopenharmony_ci{ 6638c2ecf20Sopenharmony_ci struct bnxt_qplib_creq_ctx *creq; 6648c2ecf20Sopenharmony_ci struct bnxt_qplib_cmdq_ctx *cmdq; 6658c2ecf20Sopenharmony_ci unsigned long indx; 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_ci creq = &rcfw->creq; 6688c2ecf20Sopenharmony_ci cmdq = &rcfw->cmdq; 6698c2ecf20Sopenharmony_ci /* Make sure the HW channel is stopped! */ 6708c2ecf20Sopenharmony_ci bnxt_qplib_rcfw_stop_irq(rcfw, true); 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci iounmap(cmdq->cmdq_mbox.reg.bar_reg); 6738c2ecf20Sopenharmony_ci iounmap(creq->creq_db.reg.bar_reg); 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_ci indx = find_first_bit(cmdq->cmdq_bitmap, rcfw->cmdq_depth); 6768c2ecf20Sopenharmony_ci if (indx != rcfw->cmdq_depth) 6778c2ecf20Sopenharmony_ci dev_err(&rcfw->pdev->dev, 6788c2ecf20Sopenharmony_ci "disabling RCFW with pending cmd-bit %lx\n", indx); 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_ci cmdq->cmdq_mbox.reg.bar_reg = NULL; 6818c2ecf20Sopenharmony_ci creq->creq_db.reg.bar_reg = NULL; 6828c2ecf20Sopenharmony_ci creq->aeq_handler = NULL; 6838c2ecf20Sopenharmony_ci creq->msix_vec = 0; 6848c2ecf20Sopenharmony_ci} 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_ciint bnxt_qplib_rcfw_start_irq(struct bnxt_qplib_rcfw *rcfw, int msix_vector, 6878c2ecf20Sopenharmony_ci bool need_init) 6888c2ecf20Sopenharmony_ci{ 6898c2ecf20Sopenharmony_ci struct bnxt_qplib_creq_ctx *creq; 6908c2ecf20Sopenharmony_ci struct bnxt_qplib_res *res; 6918c2ecf20Sopenharmony_ci int rc; 6928c2ecf20Sopenharmony_ci 6938c2ecf20Sopenharmony_ci creq = &rcfw->creq; 6948c2ecf20Sopenharmony_ci res = rcfw->res; 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_ci if (creq->requested) 6978c2ecf20Sopenharmony_ci return -EFAULT; 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_ci creq->msix_vec = msix_vector; 7008c2ecf20Sopenharmony_ci if (need_init) 7018c2ecf20Sopenharmony_ci tasklet_setup(&creq->creq_tasklet, bnxt_qplib_service_creq); 7028c2ecf20Sopenharmony_ci else 7038c2ecf20Sopenharmony_ci tasklet_enable(&creq->creq_tasklet); 7048c2ecf20Sopenharmony_ci 7058c2ecf20Sopenharmony_ci creq->irq_name = kasprintf(GFP_KERNEL, "bnxt_re-creq@pci:%s", 7068c2ecf20Sopenharmony_ci pci_name(res->pdev)); 7078c2ecf20Sopenharmony_ci if (!creq->irq_name) 7088c2ecf20Sopenharmony_ci return -ENOMEM; 7098c2ecf20Sopenharmony_ci rc = request_irq(creq->msix_vec, bnxt_qplib_creq_irq, 0, 7108c2ecf20Sopenharmony_ci creq->irq_name, rcfw); 7118c2ecf20Sopenharmony_ci if (rc) { 7128c2ecf20Sopenharmony_ci kfree(creq->irq_name); 7138c2ecf20Sopenharmony_ci creq->irq_name = NULL; 7148c2ecf20Sopenharmony_ci tasklet_disable(&creq->creq_tasklet); 7158c2ecf20Sopenharmony_ci return rc; 7168c2ecf20Sopenharmony_ci } 7178c2ecf20Sopenharmony_ci creq->requested = true; 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_ci bnxt_qplib_ring_nq_db(&creq->creq_db.dbinfo, res->cctx, true); 7208c2ecf20Sopenharmony_ci 7218c2ecf20Sopenharmony_ci return 0; 7228c2ecf20Sopenharmony_ci} 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_cistatic int bnxt_qplib_map_cmdq_mbox(struct bnxt_qplib_rcfw *rcfw, bool is_vf) 7258c2ecf20Sopenharmony_ci{ 7268c2ecf20Sopenharmony_ci struct bnxt_qplib_cmdq_mbox *mbox; 7278c2ecf20Sopenharmony_ci resource_size_t bar_reg; 7288c2ecf20Sopenharmony_ci struct pci_dev *pdev; 7298c2ecf20Sopenharmony_ci u16 prod_offt; 7308c2ecf20Sopenharmony_ci int rc = 0; 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_ci pdev = rcfw->pdev; 7338c2ecf20Sopenharmony_ci mbox = &rcfw->cmdq.cmdq_mbox; 7348c2ecf20Sopenharmony_ci 7358c2ecf20Sopenharmony_ci mbox->reg.bar_id = RCFW_COMM_PCI_BAR_REGION; 7368c2ecf20Sopenharmony_ci mbox->reg.len = RCFW_COMM_SIZE; 7378c2ecf20Sopenharmony_ci mbox->reg.bar_base = pci_resource_start(pdev, mbox->reg.bar_id); 7388c2ecf20Sopenharmony_ci if (!mbox->reg.bar_base) { 7398c2ecf20Sopenharmony_ci dev_err(&pdev->dev, 7408c2ecf20Sopenharmony_ci "QPLIB: CMDQ BAR region %d resc start is 0!\n", 7418c2ecf20Sopenharmony_ci mbox->reg.bar_id); 7428c2ecf20Sopenharmony_ci return -ENOMEM; 7438c2ecf20Sopenharmony_ci } 7448c2ecf20Sopenharmony_ci 7458c2ecf20Sopenharmony_ci bar_reg = mbox->reg.bar_base + RCFW_COMM_BASE_OFFSET; 7468c2ecf20Sopenharmony_ci mbox->reg.len = RCFW_COMM_SIZE; 7478c2ecf20Sopenharmony_ci mbox->reg.bar_reg = ioremap(bar_reg, mbox->reg.len); 7488c2ecf20Sopenharmony_ci if (!mbox->reg.bar_reg) { 7498c2ecf20Sopenharmony_ci dev_err(&pdev->dev, 7508c2ecf20Sopenharmony_ci "QPLIB: CMDQ BAR region %d mapping failed\n", 7518c2ecf20Sopenharmony_ci mbox->reg.bar_id); 7528c2ecf20Sopenharmony_ci return -ENOMEM; 7538c2ecf20Sopenharmony_ci } 7548c2ecf20Sopenharmony_ci 7558c2ecf20Sopenharmony_ci prod_offt = is_vf ? RCFW_VF_COMM_PROD_OFFSET : 7568c2ecf20Sopenharmony_ci RCFW_PF_COMM_PROD_OFFSET; 7578c2ecf20Sopenharmony_ci mbox->prod = (void __iomem *)(mbox->reg.bar_reg + prod_offt); 7588c2ecf20Sopenharmony_ci mbox->db = (void __iomem *)(mbox->reg.bar_reg + RCFW_COMM_TRIG_OFFSET); 7598c2ecf20Sopenharmony_ci return rc; 7608c2ecf20Sopenharmony_ci} 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_cistatic int bnxt_qplib_map_creq_db(struct bnxt_qplib_rcfw *rcfw, u32 reg_offt) 7638c2ecf20Sopenharmony_ci{ 7648c2ecf20Sopenharmony_ci struct bnxt_qplib_creq_db *creq_db; 7658c2ecf20Sopenharmony_ci resource_size_t bar_reg; 7668c2ecf20Sopenharmony_ci struct pci_dev *pdev; 7678c2ecf20Sopenharmony_ci 7688c2ecf20Sopenharmony_ci pdev = rcfw->pdev; 7698c2ecf20Sopenharmony_ci creq_db = &rcfw->creq.creq_db; 7708c2ecf20Sopenharmony_ci 7718c2ecf20Sopenharmony_ci creq_db->reg.bar_id = RCFW_COMM_CONS_PCI_BAR_REGION; 7728c2ecf20Sopenharmony_ci creq_db->reg.bar_base = pci_resource_start(pdev, creq_db->reg.bar_id); 7738c2ecf20Sopenharmony_ci if (!creq_db->reg.bar_id) 7748c2ecf20Sopenharmony_ci dev_err(&pdev->dev, 7758c2ecf20Sopenharmony_ci "QPLIB: CREQ BAR region %d resc start is 0!", 7768c2ecf20Sopenharmony_ci creq_db->reg.bar_id); 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_ci bar_reg = creq_db->reg.bar_base + reg_offt; 7798c2ecf20Sopenharmony_ci /* Unconditionally map 8 bytes to support 57500 series */ 7808c2ecf20Sopenharmony_ci creq_db->reg.len = 8; 7818c2ecf20Sopenharmony_ci creq_db->reg.bar_reg = ioremap(bar_reg, creq_db->reg.len); 7828c2ecf20Sopenharmony_ci if (!creq_db->reg.bar_reg) { 7838c2ecf20Sopenharmony_ci dev_err(&pdev->dev, 7848c2ecf20Sopenharmony_ci "QPLIB: CREQ BAR region %d mapping failed", 7858c2ecf20Sopenharmony_ci creq_db->reg.bar_id); 7868c2ecf20Sopenharmony_ci return -ENOMEM; 7878c2ecf20Sopenharmony_ci } 7888c2ecf20Sopenharmony_ci creq_db->dbinfo.db = creq_db->reg.bar_reg; 7898c2ecf20Sopenharmony_ci creq_db->dbinfo.hwq = &rcfw->creq.hwq; 7908c2ecf20Sopenharmony_ci creq_db->dbinfo.xid = rcfw->creq.ring_id; 7918c2ecf20Sopenharmony_ci return 0; 7928c2ecf20Sopenharmony_ci} 7938c2ecf20Sopenharmony_ci 7948c2ecf20Sopenharmony_cistatic void bnxt_qplib_start_rcfw(struct bnxt_qplib_rcfw *rcfw) 7958c2ecf20Sopenharmony_ci{ 7968c2ecf20Sopenharmony_ci struct bnxt_qplib_cmdq_ctx *cmdq; 7978c2ecf20Sopenharmony_ci struct bnxt_qplib_creq_ctx *creq; 7988c2ecf20Sopenharmony_ci struct bnxt_qplib_cmdq_mbox *mbox; 7998c2ecf20Sopenharmony_ci struct cmdq_init init = {0}; 8008c2ecf20Sopenharmony_ci 8018c2ecf20Sopenharmony_ci cmdq = &rcfw->cmdq; 8028c2ecf20Sopenharmony_ci creq = &rcfw->creq; 8038c2ecf20Sopenharmony_ci mbox = &cmdq->cmdq_mbox; 8048c2ecf20Sopenharmony_ci 8058c2ecf20Sopenharmony_ci init.cmdq_pbl = cpu_to_le64(cmdq->hwq.pbl[PBL_LVL_0].pg_map_arr[0]); 8068c2ecf20Sopenharmony_ci init.cmdq_size_cmdq_lvl = 8078c2ecf20Sopenharmony_ci cpu_to_le16(((rcfw->cmdq_depth << 8088c2ecf20Sopenharmony_ci CMDQ_INIT_CMDQ_SIZE_SFT) & 8098c2ecf20Sopenharmony_ci CMDQ_INIT_CMDQ_SIZE_MASK) | 8108c2ecf20Sopenharmony_ci ((cmdq->hwq.level << 8118c2ecf20Sopenharmony_ci CMDQ_INIT_CMDQ_LVL_SFT) & 8128c2ecf20Sopenharmony_ci CMDQ_INIT_CMDQ_LVL_MASK)); 8138c2ecf20Sopenharmony_ci init.creq_ring_id = cpu_to_le16(creq->ring_id); 8148c2ecf20Sopenharmony_ci /* Write to the Bono mailbox register */ 8158c2ecf20Sopenharmony_ci __iowrite32_copy(mbox->reg.bar_reg, &init, sizeof(init) / 4); 8168c2ecf20Sopenharmony_ci} 8178c2ecf20Sopenharmony_ci 8188c2ecf20Sopenharmony_ciint bnxt_qplib_enable_rcfw_channel(struct bnxt_qplib_rcfw *rcfw, 8198c2ecf20Sopenharmony_ci int msix_vector, 8208c2ecf20Sopenharmony_ci int cp_bar_reg_off, int virt_fn, 8218c2ecf20Sopenharmony_ci aeq_handler_t aeq_handler) 8228c2ecf20Sopenharmony_ci{ 8238c2ecf20Sopenharmony_ci struct bnxt_qplib_cmdq_ctx *cmdq; 8248c2ecf20Sopenharmony_ci struct bnxt_qplib_creq_ctx *creq; 8258c2ecf20Sopenharmony_ci int rc; 8268c2ecf20Sopenharmony_ci 8278c2ecf20Sopenharmony_ci cmdq = &rcfw->cmdq; 8288c2ecf20Sopenharmony_ci creq = &rcfw->creq; 8298c2ecf20Sopenharmony_ci 8308c2ecf20Sopenharmony_ci /* Clear to defaults */ 8318c2ecf20Sopenharmony_ci 8328c2ecf20Sopenharmony_ci cmdq->seq_num = 0; 8338c2ecf20Sopenharmony_ci set_bit(FIRMWARE_FIRST_FLAG, &cmdq->flags); 8348c2ecf20Sopenharmony_ci init_waitqueue_head(&cmdq->waitq); 8358c2ecf20Sopenharmony_ci 8368c2ecf20Sopenharmony_ci creq->stats.creq_qp_event_processed = 0; 8378c2ecf20Sopenharmony_ci creq->stats.creq_func_event_processed = 0; 8388c2ecf20Sopenharmony_ci creq->aeq_handler = aeq_handler; 8398c2ecf20Sopenharmony_ci 8408c2ecf20Sopenharmony_ci rc = bnxt_qplib_map_cmdq_mbox(rcfw, virt_fn); 8418c2ecf20Sopenharmony_ci if (rc) 8428c2ecf20Sopenharmony_ci return rc; 8438c2ecf20Sopenharmony_ci 8448c2ecf20Sopenharmony_ci rc = bnxt_qplib_map_creq_db(rcfw, cp_bar_reg_off); 8458c2ecf20Sopenharmony_ci if (rc) 8468c2ecf20Sopenharmony_ci return rc; 8478c2ecf20Sopenharmony_ci 8488c2ecf20Sopenharmony_ci rc = bnxt_qplib_rcfw_start_irq(rcfw, msix_vector, true); 8498c2ecf20Sopenharmony_ci if (rc) { 8508c2ecf20Sopenharmony_ci dev_err(&rcfw->pdev->dev, 8518c2ecf20Sopenharmony_ci "Failed to request IRQ for CREQ rc = 0x%x\n", rc); 8528c2ecf20Sopenharmony_ci bnxt_qplib_disable_rcfw_channel(rcfw); 8538c2ecf20Sopenharmony_ci return rc; 8548c2ecf20Sopenharmony_ci } 8558c2ecf20Sopenharmony_ci 8568c2ecf20Sopenharmony_ci bnxt_qplib_start_rcfw(rcfw); 8578c2ecf20Sopenharmony_ci 8588c2ecf20Sopenharmony_ci return 0; 8598c2ecf20Sopenharmony_ci} 8608c2ecf20Sopenharmony_ci 8618c2ecf20Sopenharmony_cistruct bnxt_qplib_rcfw_sbuf *bnxt_qplib_rcfw_alloc_sbuf( 8628c2ecf20Sopenharmony_ci struct bnxt_qplib_rcfw *rcfw, 8638c2ecf20Sopenharmony_ci u32 size) 8648c2ecf20Sopenharmony_ci{ 8658c2ecf20Sopenharmony_ci struct bnxt_qplib_rcfw_sbuf *sbuf; 8668c2ecf20Sopenharmony_ci 8678c2ecf20Sopenharmony_ci sbuf = kzalloc(sizeof(*sbuf), GFP_ATOMIC); 8688c2ecf20Sopenharmony_ci if (!sbuf) 8698c2ecf20Sopenharmony_ci return NULL; 8708c2ecf20Sopenharmony_ci 8718c2ecf20Sopenharmony_ci sbuf->size = size; 8728c2ecf20Sopenharmony_ci sbuf->sb = dma_alloc_coherent(&rcfw->pdev->dev, sbuf->size, 8738c2ecf20Sopenharmony_ci &sbuf->dma_addr, GFP_ATOMIC); 8748c2ecf20Sopenharmony_ci if (!sbuf->sb) 8758c2ecf20Sopenharmony_ci goto bail; 8768c2ecf20Sopenharmony_ci 8778c2ecf20Sopenharmony_ci return sbuf; 8788c2ecf20Sopenharmony_cibail: 8798c2ecf20Sopenharmony_ci kfree(sbuf); 8808c2ecf20Sopenharmony_ci return NULL; 8818c2ecf20Sopenharmony_ci} 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_civoid bnxt_qplib_rcfw_free_sbuf(struct bnxt_qplib_rcfw *rcfw, 8848c2ecf20Sopenharmony_ci struct bnxt_qplib_rcfw_sbuf *sbuf) 8858c2ecf20Sopenharmony_ci{ 8868c2ecf20Sopenharmony_ci if (sbuf->sb) 8878c2ecf20Sopenharmony_ci dma_free_coherent(&rcfw->pdev->dev, sbuf->size, 8888c2ecf20Sopenharmony_ci sbuf->sb, sbuf->dma_addr); 8898c2ecf20Sopenharmony_ci kfree(sbuf); 8908c2ecf20Sopenharmony_ci} 891