162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * Broadcom NetXtreme-E RoCE driver. 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright (c) 2016 - 2017, Broadcom. All rights reserved. The term 562306a36Sopenharmony_ci * Broadcom refers to Broadcom Limited and/or its subsidiaries. 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * This software is available to you under a choice of one of two 862306a36Sopenharmony_ci * licenses. You may choose to be licensed under the terms of the GNU 962306a36Sopenharmony_ci * General Public License (GPL) Version 2, available from the file 1062306a36Sopenharmony_ci * COPYING in the main directory of this source tree, or the 1162306a36Sopenharmony_ci * BSD license below: 1262306a36Sopenharmony_ci * 1362306a36Sopenharmony_ci * Redistribution and use in source and binary forms, with or without 1462306a36Sopenharmony_ci * modification, are permitted provided that the following conditions 1562306a36Sopenharmony_ci * are met: 1662306a36Sopenharmony_ci * 1762306a36Sopenharmony_ci * 1. Redistributions of source code must retain the above copyright 1862306a36Sopenharmony_ci * notice, this list of conditions and the following disclaimer. 1962306a36Sopenharmony_ci * 2. Redistributions in binary form must reproduce the above copyright 2062306a36Sopenharmony_ci * notice, this list of conditions and the following disclaimer in 2162306a36Sopenharmony_ci * the documentation and/or other materials provided with the 2262306a36Sopenharmony_ci * distribution. 2362306a36Sopenharmony_ci * 2462306a36Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' 2562306a36Sopenharmony_ci * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 2662306a36Sopenharmony_ci * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 2762306a36Sopenharmony_ci * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS 2862306a36Sopenharmony_ci * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 2962306a36Sopenharmony_ci * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 3062306a36Sopenharmony_ci * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 3162306a36Sopenharmony_ci * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 3262306a36Sopenharmony_ci * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 3362306a36Sopenharmony_ci * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 3462306a36Sopenharmony_ci * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 3562306a36Sopenharmony_ci * 3662306a36Sopenharmony_ci * Description: RDMA Controller HW interface 3762306a36Sopenharmony_ci */ 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci#define dev_fmt(fmt) "QPLIB: " fmt 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci#include <linux/interrupt.h> 4262306a36Sopenharmony_ci#include <linux/spinlock.h> 4362306a36Sopenharmony_ci#include <linux/pci.h> 4462306a36Sopenharmony_ci#include <linux/prefetch.h> 4562306a36Sopenharmony_ci#include <linux/delay.h> 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci#include "roce_hsi.h" 4862306a36Sopenharmony_ci#include "qplib_res.h" 4962306a36Sopenharmony_ci#include "qplib_rcfw.h" 5062306a36Sopenharmony_ci#include "qplib_sp.h" 5162306a36Sopenharmony_ci#include "qplib_fp.h" 5262306a36Sopenharmony_ci#include "qplib_tlv.h" 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_cistatic void bnxt_qplib_service_creq(struct tasklet_struct *t); 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci/** 5762306a36Sopenharmony_ci * bnxt_qplib_map_rc - map return type based on opcode 5862306a36Sopenharmony_ci * @opcode: roce slow path opcode 5962306a36Sopenharmony_ci * 6062306a36Sopenharmony_ci * case #1 6162306a36Sopenharmony_ci * Firmware initiated error recovery is a safe state machine and 6262306a36Sopenharmony_ci * driver can consider all the underlying rdma resources are free. 6362306a36Sopenharmony_ci * In this state, it is safe to return success for opcodes related to 6462306a36Sopenharmony_ci * destroying rdma resources (like destroy qp, destroy cq etc.). 6562306a36Sopenharmony_ci * 6662306a36Sopenharmony_ci * case #2 6762306a36Sopenharmony_ci * If driver detect potential firmware stall, it is not safe state machine 6862306a36Sopenharmony_ci * and the driver can not consider all the underlying rdma resources are 6962306a36Sopenharmony_ci * freed. 7062306a36Sopenharmony_ci * In this state, it is not safe to return success for opcodes related to 7162306a36Sopenharmony_ci * destroying rdma resources (like destroy qp, destroy cq etc.). 7262306a36Sopenharmony_ci * 7362306a36Sopenharmony_ci * Scope of this helper function is only for case #1. 7462306a36Sopenharmony_ci * 7562306a36Sopenharmony_ci * Returns: 7662306a36Sopenharmony_ci * 0 to communicate success to caller. 7762306a36Sopenharmony_ci * Non zero error code to communicate failure to caller. 7862306a36Sopenharmony_ci */ 7962306a36Sopenharmony_cistatic int bnxt_qplib_map_rc(u8 opcode) 8062306a36Sopenharmony_ci{ 8162306a36Sopenharmony_ci switch (opcode) { 8262306a36Sopenharmony_ci case CMDQ_BASE_OPCODE_DESTROY_QP: 8362306a36Sopenharmony_ci case CMDQ_BASE_OPCODE_DESTROY_SRQ: 8462306a36Sopenharmony_ci case CMDQ_BASE_OPCODE_DESTROY_CQ: 8562306a36Sopenharmony_ci case CMDQ_BASE_OPCODE_DEALLOCATE_KEY: 8662306a36Sopenharmony_ci case CMDQ_BASE_OPCODE_DEREGISTER_MR: 8762306a36Sopenharmony_ci case CMDQ_BASE_OPCODE_DELETE_GID: 8862306a36Sopenharmony_ci case CMDQ_BASE_OPCODE_DESTROY_QP1: 8962306a36Sopenharmony_ci case CMDQ_BASE_OPCODE_DESTROY_AH: 9062306a36Sopenharmony_ci case CMDQ_BASE_OPCODE_DEINITIALIZE_FW: 9162306a36Sopenharmony_ci case CMDQ_BASE_OPCODE_MODIFY_ROCE_CC: 9262306a36Sopenharmony_ci case CMDQ_BASE_OPCODE_SET_LINK_AGGR_MODE: 9362306a36Sopenharmony_ci return 0; 9462306a36Sopenharmony_ci default: 9562306a36Sopenharmony_ci return -ETIMEDOUT; 9662306a36Sopenharmony_ci } 9762306a36Sopenharmony_ci} 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci/** 10062306a36Sopenharmony_ci * bnxt_re_is_fw_stalled - Check firmware health 10162306a36Sopenharmony_ci * @rcfw: rcfw channel instance of rdev 10262306a36Sopenharmony_ci * @cookie: cookie to track the command 10362306a36Sopenharmony_ci * 10462306a36Sopenharmony_ci * If firmware has not responded any rcfw command within 10562306a36Sopenharmony_ci * rcfw->max_timeout, consider firmware as stalled. 10662306a36Sopenharmony_ci * 10762306a36Sopenharmony_ci * Returns: 10862306a36Sopenharmony_ci * 0 if firmware is responding 10962306a36Sopenharmony_ci * -ENODEV if firmware is not responding 11062306a36Sopenharmony_ci */ 11162306a36Sopenharmony_cistatic int bnxt_re_is_fw_stalled(struct bnxt_qplib_rcfw *rcfw, 11262306a36Sopenharmony_ci u16 cookie) 11362306a36Sopenharmony_ci{ 11462306a36Sopenharmony_ci struct bnxt_qplib_cmdq_ctx *cmdq; 11562306a36Sopenharmony_ci struct bnxt_qplib_crsqe *crsqe; 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci crsqe = &rcfw->crsqe_tbl[cookie]; 11862306a36Sopenharmony_ci cmdq = &rcfw->cmdq; 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci if (time_after(jiffies, cmdq->last_seen + 12162306a36Sopenharmony_ci (rcfw->max_timeout * HZ))) { 12262306a36Sopenharmony_ci dev_warn_ratelimited(&rcfw->pdev->dev, 12362306a36Sopenharmony_ci "%s: FW STALL Detected. cmdq[%#x]=%#x waited (%d > %d) msec active %d ", 12462306a36Sopenharmony_ci __func__, cookie, crsqe->opcode, 12562306a36Sopenharmony_ci jiffies_to_msecs(jiffies - cmdq->last_seen), 12662306a36Sopenharmony_ci rcfw->max_timeout * 1000, 12762306a36Sopenharmony_ci crsqe->is_in_used); 12862306a36Sopenharmony_ci return -ENODEV; 12962306a36Sopenharmony_ci } 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci return 0; 13262306a36Sopenharmony_ci} 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci/** 13562306a36Sopenharmony_ci * __wait_for_resp - Don't hold the cpu context and wait for response 13662306a36Sopenharmony_ci * @rcfw: rcfw channel instance of rdev 13762306a36Sopenharmony_ci * @cookie: cookie to track the command 13862306a36Sopenharmony_ci * 13962306a36Sopenharmony_ci * Wait for command completion in sleepable context. 14062306a36Sopenharmony_ci * 14162306a36Sopenharmony_ci * Returns: 14262306a36Sopenharmony_ci * 0 if command is completed by firmware. 14362306a36Sopenharmony_ci * Non zero error code for rest of the case. 14462306a36Sopenharmony_ci */ 14562306a36Sopenharmony_cistatic int __wait_for_resp(struct bnxt_qplib_rcfw *rcfw, u16 cookie) 14662306a36Sopenharmony_ci{ 14762306a36Sopenharmony_ci struct bnxt_qplib_cmdq_ctx *cmdq; 14862306a36Sopenharmony_ci struct bnxt_qplib_crsqe *crsqe; 14962306a36Sopenharmony_ci int ret; 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci cmdq = &rcfw->cmdq; 15262306a36Sopenharmony_ci crsqe = &rcfw->crsqe_tbl[cookie]; 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci do { 15562306a36Sopenharmony_ci if (test_bit(ERR_DEVICE_DETACHED, &cmdq->flags)) 15662306a36Sopenharmony_ci return bnxt_qplib_map_rc(crsqe->opcode); 15762306a36Sopenharmony_ci if (test_bit(FIRMWARE_STALL_DETECTED, &cmdq->flags)) 15862306a36Sopenharmony_ci return -ETIMEDOUT; 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci wait_event_timeout(cmdq->waitq, 16162306a36Sopenharmony_ci !crsqe->is_in_used || 16262306a36Sopenharmony_ci test_bit(ERR_DEVICE_DETACHED, &cmdq->flags), 16362306a36Sopenharmony_ci msecs_to_jiffies(rcfw->max_timeout * 1000)); 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci if (!crsqe->is_in_used) 16662306a36Sopenharmony_ci return 0; 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci bnxt_qplib_service_creq(&rcfw->creq.creq_tasklet); 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci if (!crsqe->is_in_used) 17162306a36Sopenharmony_ci return 0; 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci ret = bnxt_re_is_fw_stalled(rcfw, cookie); 17462306a36Sopenharmony_ci if (ret) 17562306a36Sopenharmony_ci return ret; 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci } while (true); 17862306a36Sopenharmony_ci}; 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci/** 18162306a36Sopenharmony_ci * __block_for_resp - hold the cpu context and wait for response 18262306a36Sopenharmony_ci * @rcfw: rcfw channel instance of rdev 18362306a36Sopenharmony_ci * @cookie: cookie to track the command 18462306a36Sopenharmony_ci * 18562306a36Sopenharmony_ci * This function will hold the cpu (non-sleepable context) and 18662306a36Sopenharmony_ci * wait for command completion. Maximum holding interval is 8 second. 18762306a36Sopenharmony_ci * 18862306a36Sopenharmony_ci * Returns: 18962306a36Sopenharmony_ci * -ETIMEOUT if command is not completed in specific time interval. 19062306a36Sopenharmony_ci * 0 if command is completed by firmware. 19162306a36Sopenharmony_ci */ 19262306a36Sopenharmony_cistatic int __block_for_resp(struct bnxt_qplib_rcfw *rcfw, u16 cookie) 19362306a36Sopenharmony_ci{ 19462306a36Sopenharmony_ci struct bnxt_qplib_cmdq_ctx *cmdq = &rcfw->cmdq; 19562306a36Sopenharmony_ci struct bnxt_qplib_crsqe *crsqe; 19662306a36Sopenharmony_ci unsigned long issue_time = 0; 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci issue_time = jiffies; 19962306a36Sopenharmony_ci crsqe = &rcfw->crsqe_tbl[cookie]; 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci do { 20262306a36Sopenharmony_ci if (test_bit(ERR_DEVICE_DETACHED, &cmdq->flags)) 20362306a36Sopenharmony_ci return bnxt_qplib_map_rc(crsqe->opcode); 20462306a36Sopenharmony_ci if (test_bit(FIRMWARE_STALL_DETECTED, &cmdq->flags)) 20562306a36Sopenharmony_ci return -ETIMEDOUT; 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci udelay(1); 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci bnxt_qplib_service_creq(&rcfw->creq.creq_tasklet); 21062306a36Sopenharmony_ci if (!crsqe->is_in_used) 21162306a36Sopenharmony_ci return 0; 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci } while (time_before(jiffies, issue_time + (8 * HZ))); 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci return -ETIMEDOUT; 21662306a36Sopenharmony_ci}; 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci/* __send_message_no_waiter - get cookie and post the message. 21962306a36Sopenharmony_ci * @rcfw: rcfw channel instance of rdev 22062306a36Sopenharmony_ci * @msg: qplib message internal 22162306a36Sopenharmony_ci * 22262306a36Sopenharmony_ci * This function will just post and don't bother about completion. 22362306a36Sopenharmony_ci * Current design of this function is - 22462306a36Sopenharmony_ci * user must hold the completion queue hwq->lock. 22562306a36Sopenharmony_ci * user must have used existing completion and free the resources. 22662306a36Sopenharmony_ci * this function will not check queue full condition. 22762306a36Sopenharmony_ci * this function will explicitly set is_waiter_alive=false. 22862306a36Sopenharmony_ci * current use case is - send destroy_ah if create_ah is return 22962306a36Sopenharmony_ci * after waiter of create_ah is lost. It can be extended for other 23062306a36Sopenharmony_ci * use case as well. 23162306a36Sopenharmony_ci * 23262306a36Sopenharmony_ci * Returns: Nothing 23362306a36Sopenharmony_ci * 23462306a36Sopenharmony_ci */ 23562306a36Sopenharmony_cistatic void __send_message_no_waiter(struct bnxt_qplib_rcfw *rcfw, 23662306a36Sopenharmony_ci struct bnxt_qplib_cmdqmsg *msg) 23762306a36Sopenharmony_ci{ 23862306a36Sopenharmony_ci struct bnxt_qplib_cmdq_ctx *cmdq = &rcfw->cmdq; 23962306a36Sopenharmony_ci struct bnxt_qplib_hwq *hwq = &cmdq->hwq; 24062306a36Sopenharmony_ci struct bnxt_qplib_crsqe *crsqe; 24162306a36Sopenharmony_ci struct bnxt_qplib_cmdqe *cmdqe; 24262306a36Sopenharmony_ci u32 sw_prod, cmdq_prod; 24362306a36Sopenharmony_ci u16 cookie; 24462306a36Sopenharmony_ci u32 bsize; 24562306a36Sopenharmony_ci u8 *preq; 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci cookie = cmdq->seq_num & RCFW_MAX_COOKIE_VALUE; 24862306a36Sopenharmony_ci __set_cmdq_base_cookie(msg->req, msg->req_sz, cpu_to_le16(cookie)); 24962306a36Sopenharmony_ci crsqe = &rcfw->crsqe_tbl[cookie]; 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci /* Set cmd_size in terms of 16B slots in req. */ 25262306a36Sopenharmony_ci bsize = bnxt_qplib_set_cmd_slots(msg->req); 25362306a36Sopenharmony_ci /* GET_CMD_SIZE would return number of slots in either case of tlv 25462306a36Sopenharmony_ci * and non-tlv commands after call to bnxt_qplib_set_cmd_slots() 25562306a36Sopenharmony_ci */ 25662306a36Sopenharmony_ci crsqe->is_internal_cmd = true; 25762306a36Sopenharmony_ci crsqe->is_waiter_alive = false; 25862306a36Sopenharmony_ci crsqe->is_in_used = true; 25962306a36Sopenharmony_ci crsqe->req_size = __get_cmdq_base_cmd_size(msg->req, msg->req_sz); 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci preq = (u8 *)msg->req; 26262306a36Sopenharmony_ci do { 26362306a36Sopenharmony_ci /* Locate the next cmdq slot */ 26462306a36Sopenharmony_ci sw_prod = HWQ_CMP(hwq->prod, hwq); 26562306a36Sopenharmony_ci cmdqe = bnxt_qplib_get_qe(hwq, sw_prod, NULL); 26662306a36Sopenharmony_ci /* Copy a segment of the req cmd to the cmdq */ 26762306a36Sopenharmony_ci memset(cmdqe, 0, sizeof(*cmdqe)); 26862306a36Sopenharmony_ci memcpy(cmdqe, preq, min_t(u32, bsize, sizeof(*cmdqe))); 26962306a36Sopenharmony_ci preq += min_t(u32, bsize, sizeof(*cmdqe)); 27062306a36Sopenharmony_ci bsize -= min_t(u32, bsize, sizeof(*cmdqe)); 27162306a36Sopenharmony_ci hwq->prod++; 27262306a36Sopenharmony_ci } while (bsize > 0); 27362306a36Sopenharmony_ci cmdq->seq_num++; 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci cmdq_prod = hwq->prod; 27662306a36Sopenharmony_ci atomic_inc(&rcfw->timeout_send); 27762306a36Sopenharmony_ci /* ring CMDQ DB */ 27862306a36Sopenharmony_ci wmb(); 27962306a36Sopenharmony_ci writel(cmdq_prod, cmdq->cmdq_mbox.prod); 28062306a36Sopenharmony_ci writel(RCFW_CMDQ_TRIG_VAL, cmdq->cmdq_mbox.db); 28162306a36Sopenharmony_ci} 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_cistatic int __send_message(struct bnxt_qplib_rcfw *rcfw, 28462306a36Sopenharmony_ci struct bnxt_qplib_cmdqmsg *msg, u8 opcode) 28562306a36Sopenharmony_ci{ 28662306a36Sopenharmony_ci u32 bsize, free_slots, required_slots; 28762306a36Sopenharmony_ci struct bnxt_qplib_cmdq_ctx *cmdq; 28862306a36Sopenharmony_ci struct bnxt_qplib_crsqe *crsqe; 28962306a36Sopenharmony_ci struct bnxt_qplib_cmdqe *cmdqe; 29062306a36Sopenharmony_ci struct bnxt_qplib_hwq *hwq; 29162306a36Sopenharmony_ci u32 sw_prod, cmdq_prod; 29262306a36Sopenharmony_ci struct pci_dev *pdev; 29362306a36Sopenharmony_ci unsigned long flags; 29462306a36Sopenharmony_ci u16 cookie; 29562306a36Sopenharmony_ci u8 *preq; 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci cmdq = &rcfw->cmdq; 29862306a36Sopenharmony_ci hwq = &cmdq->hwq; 29962306a36Sopenharmony_ci pdev = rcfw->pdev; 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci /* Cmdq are in 16-byte units, each request can consume 1 or more 30262306a36Sopenharmony_ci * cmdqe 30362306a36Sopenharmony_ci */ 30462306a36Sopenharmony_ci spin_lock_irqsave(&hwq->lock, flags); 30562306a36Sopenharmony_ci required_slots = bnxt_qplib_get_cmd_slots(msg->req); 30662306a36Sopenharmony_ci free_slots = HWQ_FREE_SLOTS(hwq); 30762306a36Sopenharmony_ci cookie = cmdq->seq_num & RCFW_MAX_COOKIE_VALUE; 30862306a36Sopenharmony_ci crsqe = &rcfw->crsqe_tbl[cookie]; 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci if (required_slots >= free_slots) { 31162306a36Sopenharmony_ci dev_info_ratelimited(&pdev->dev, 31262306a36Sopenharmony_ci "CMDQ is full req/free %d/%d!", 31362306a36Sopenharmony_ci required_slots, free_slots); 31462306a36Sopenharmony_ci spin_unlock_irqrestore(&hwq->lock, flags); 31562306a36Sopenharmony_ci return -EAGAIN; 31662306a36Sopenharmony_ci } 31762306a36Sopenharmony_ci if (msg->block) 31862306a36Sopenharmony_ci cookie |= RCFW_CMD_IS_BLOCKING; 31962306a36Sopenharmony_ci __set_cmdq_base_cookie(msg->req, msg->req_sz, cpu_to_le16(cookie)); 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci bsize = bnxt_qplib_set_cmd_slots(msg->req); 32262306a36Sopenharmony_ci crsqe->free_slots = free_slots; 32362306a36Sopenharmony_ci crsqe->resp = (struct creq_qp_event *)msg->resp; 32462306a36Sopenharmony_ci crsqe->resp->cookie = cpu_to_le16(cookie); 32562306a36Sopenharmony_ci crsqe->is_internal_cmd = false; 32662306a36Sopenharmony_ci crsqe->is_waiter_alive = true; 32762306a36Sopenharmony_ci crsqe->is_in_used = true; 32862306a36Sopenharmony_ci crsqe->opcode = opcode; 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci crsqe->req_size = __get_cmdq_base_cmd_size(msg->req, msg->req_sz); 33162306a36Sopenharmony_ci if (__get_cmdq_base_resp_size(msg->req, msg->req_sz) && msg->sb) { 33262306a36Sopenharmony_ci struct bnxt_qplib_rcfw_sbuf *sbuf = msg->sb; 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci __set_cmdq_base_resp_addr(msg->req, msg->req_sz, 33562306a36Sopenharmony_ci cpu_to_le64(sbuf->dma_addr)); 33662306a36Sopenharmony_ci __set_cmdq_base_resp_size(msg->req, msg->req_sz, 33762306a36Sopenharmony_ci ALIGN(sbuf->size, 33862306a36Sopenharmony_ci BNXT_QPLIB_CMDQE_UNITS) / 33962306a36Sopenharmony_ci BNXT_QPLIB_CMDQE_UNITS); 34062306a36Sopenharmony_ci } 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci preq = (u8 *)msg->req; 34362306a36Sopenharmony_ci do { 34462306a36Sopenharmony_ci /* Locate the next cmdq slot */ 34562306a36Sopenharmony_ci sw_prod = HWQ_CMP(hwq->prod, hwq); 34662306a36Sopenharmony_ci cmdqe = bnxt_qplib_get_qe(hwq, sw_prod, NULL); 34762306a36Sopenharmony_ci /* Copy a segment of the req cmd to the cmdq */ 34862306a36Sopenharmony_ci memset(cmdqe, 0, sizeof(*cmdqe)); 34962306a36Sopenharmony_ci memcpy(cmdqe, preq, min_t(u32, bsize, sizeof(*cmdqe))); 35062306a36Sopenharmony_ci preq += min_t(u32, bsize, sizeof(*cmdqe)); 35162306a36Sopenharmony_ci bsize -= min_t(u32, bsize, sizeof(*cmdqe)); 35262306a36Sopenharmony_ci hwq->prod++; 35362306a36Sopenharmony_ci } while (bsize > 0); 35462306a36Sopenharmony_ci cmdq->seq_num++; 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci cmdq_prod = hwq->prod & 0xFFFF; 35762306a36Sopenharmony_ci if (test_bit(FIRMWARE_FIRST_FLAG, &cmdq->flags)) { 35862306a36Sopenharmony_ci /* The very first doorbell write 35962306a36Sopenharmony_ci * is required to set this flag 36062306a36Sopenharmony_ci * which prompts the FW to reset 36162306a36Sopenharmony_ci * its internal pointers 36262306a36Sopenharmony_ci */ 36362306a36Sopenharmony_ci cmdq_prod |= BIT(FIRMWARE_FIRST_FLAG); 36462306a36Sopenharmony_ci clear_bit(FIRMWARE_FIRST_FLAG, &cmdq->flags); 36562306a36Sopenharmony_ci } 36662306a36Sopenharmony_ci /* ring CMDQ DB */ 36762306a36Sopenharmony_ci wmb(); 36862306a36Sopenharmony_ci writel(cmdq_prod, cmdq->cmdq_mbox.prod); 36962306a36Sopenharmony_ci writel(RCFW_CMDQ_TRIG_VAL, cmdq->cmdq_mbox.db); 37062306a36Sopenharmony_ci spin_unlock_irqrestore(&hwq->lock, flags); 37162306a36Sopenharmony_ci /* Return the CREQ response pointer */ 37262306a36Sopenharmony_ci return 0; 37362306a36Sopenharmony_ci} 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci/** 37662306a36Sopenharmony_ci * __poll_for_resp - self poll completion for rcfw command 37762306a36Sopenharmony_ci * @rcfw: rcfw channel instance of rdev 37862306a36Sopenharmony_ci * @cookie: cookie to track the command 37962306a36Sopenharmony_ci * 38062306a36Sopenharmony_ci * It works same as __wait_for_resp except this function will 38162306a36Sopenharmony_ci * do self polling in sort interval since interrupt is disabled. 38262306a36Sopenharmony_ci * This function can not be called from non-sleepable context. 38362306a36Sopenharmony_ci * 38462306a36Sopenharmony_ci * Returns: 38562306a36Sopenharmony_ci * -ETIMEOUT if command is not completed in specific time interval. 38662306a36Sopenharmony_ci * 0 if command is completed by firmware. 38762306a36Sopenharmony_ci */ 38862306a36Sopenharmony_cistatic int __poll_for_resp(struct bnxt_qplib_rcfw *rcfw, u16 cookie) 38962306a36Sopenharmony_ci{ 39062306a36Sopenharmony_ci struct bnxt_qplib_cmdq_ctx *cmdq = &rcfw->cmdq; 39162306a36Sopenharmony_ci struct bnxt_qplib_crsqe *crsqe; 39262306a36Sopenharmony_ci unsigned long issue_time; 39362306a36Sopenharmony_ci int ret; 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci issue_time = jiffies; 39662306a36Sopenharmony_ci crsqe = &rcfw->crsqe_tbl[cookie]; 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci do { 39962306a36Sopenharmony_ci if (test_bit(ERR_DEVICE_DETACHED, &cmdq->flags)) 40062306a36Sopenharmony_ci return bnxt_qplib_map_rc(crsqe->opcode); 40162306a36Sopenharmony_ci if (test_bit(FIRMWARE_STALL_DETECTED, &cmdq->flags)) 40262306a36Sopenharmony_ci return -ETIMEDOUT; 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci usleep_range(1000, 1001); 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci bnxt_qplib_service_creq(&rcfw->creq.creq_tasklet); 40762306a36Sopenharmony_ci if (!crsqe->is_in_used) 40862306a36Sopenharmony_ci return 0; 40962306a36Sopenharmony_ci if (jiffies_to_msecs(jiffies - issue_time) > 41062306a36Sopenharmony_ci (rcfw->max_timeout * 1000)) { 41162306a36Sopenharmony_ci ret = bnxt_re_is_fw_stalled(rcfw, cookie); 41262306a36Sopenharmony_ci if (ret) 41362306a36Sopenharmony_ci return ret; 41462306a36Sopenharmony_ci } 41562306a36Sopenharmony_ci } while (true); 41662306a36Sopenharmony_ci}; 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_cistatic int __send_message_basic_sanity(struct bnxt_qplib_rcfw *rcfw, 41962306a36Sopenharmony_ci struct bnxt_qplib_cmdqmsg *msg, 42062306a36Sopenharmony_ci u8 opcode) 42162306a36Sopenharmony_ci{ 42262306a36Sopenharmony_ci struct bnxt_qplib_cmdq_ctx *cmdq; 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci cmdq = &rcfw->cmdq; 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci /* Prevent posting if f/w is not in a state to process */ 42762306a36Sopenharmony_ci if (test_bit(ERR_DEVICE_DETACHED, &rcfw->cmdq.flags)) 42862306a36Sopenharmony_ci return bnxt_qplib_map_rc(opcode); 42962306a36Sopenharmony_ci if (test_bit(FIRMWARE_STALL_DETECTED, &cmdq->flags)) 43062306a36Sopenharmony_ci return -ETIMEDOUT; 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci if (test_bit(FIRMWARE_INITIALIZED_FLAG, &cmdq->flags) && 43362306a36Sopenharmony_ci opcode == CMDQ_BASE_OPCODE_INITIALIZE_FW) { 43462306a36Sopenharmony_ci dev_err(&rcfw->pdev->dev, "QPLIB: RCFW already initialized!"); 43562306a36Sopenharmony_ci return -EINVAL; 43662306a36Sopenharmony_ci } 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci if (!test_bit(FIRMWARE_INITIALIZED_FLAG, &cmdq->flags) && 43962306a36Sopenharmony_ci (opcode != CMDQ_BASE_OPCODE_QUERY_FUNC && 44062306a36Sopenharmony_ci opcode != CMDQ_BASE_OPCODE_INITIALIZE_FW && 44162306a36Sopenharmony_ci opcode != CMDQ_BASE_OPCODE_QUERY_VERSION)) { 44262306a36Sopenharmony_ci dev_err(&rcfw->pdev->dev, 44362306a36Sopenharmony_ci "QPLIB: RCFW not initialized, reject opcode 0x%x", 44462306a36Sopenharmony_ci opcode); 44562306a36Sopenharmony_ci return -EOPNOTSUPP; 44662306a36Sopenharmony_ci } 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci return 0; 44962306a36Sopenharmony_ci} 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci/* This function will just post and do not bother about completion */ 45262306a36Sopenharmony_cistatic void __destroy_timedout_ah(struct bnxt_qplib_rcfw *rcfw, 45362306a36Sopenharmony_ci struct creq_create_ah_resp *create_ah_resp) 45462306a36Sopenharmony_ci{ 45562306a36Sopenharmony_ci struct bnxt_qplib_cmdqmsg msg = {}; 45662306a36Sopenharmony_ci struct cmdq_destroy_ah req = {}; 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci bnxt_qplib_rcfw_cmd_prep((struct cmdq_base *)&req, 45962306a36Sopenharmony_ci CMDQ_BASE_OPCODE_DESTROY_AH, 46062306a36Sopenharmony_ci sizeof(req)); 46162306a36Sopenharmony_ci req.ah_cid = create_ah_resp->xid; 46262306a36Sopenharmony_ci msg.req = (struct cmdq_base *)&req; 46362306a36Sopenharmony_ci msg.req_sz = sizeof(req); 46462306a36Sopenharmony_ci __send_message_no_waiter(rcfw, &msg); 46562306a36Sopenharmony_ci dev_info_ratelimited(&rcfw->pdev->dev, 46662306a36Sopenharmony_ci "From %s: ah_cid = %d timeout_send %d\n", 46762306a36Sopenharmony_ci __func__, req.ah_cid, 46862306a36Sopenharmony_ci atomic_read(&rcfw->timeout_send)); 46962306a36Sopenharmony_ci} 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci/** 47262306a36Sopenharmony_ci * __bnxt_qplib_rcfw_send_message - qplib interface to send 47362306a36Sopenharmony_ci * and complete rcfw command. 47462306a36Sopenharmony_ci * @rcfw: rcfw channel instance of rdev 47562306a36Sopenharmony_ci * @msg: qplib message internal 47662306a36Sopenharmony_ci * 47762306a36Sopenharmony_ci * This function does not account shadow queue depth. It will send 47862306a36Sopenharmony_ci * all the command unconditionally as long as send queue is not full. 47962306a36Sopenharmony_ci * 48062306a36Sopenharmony_ci * Returns: 48162306a36Sopenharmony_ci * 0 if command completed by firmware. 48262306a36Sopenharmony_ci * Non zero if the command is not completed by firmware. 48362306a36Sopenharmony_ci */ 48462306a36Sopenharmony_cistatic int __bnxt_qplib_rcfw_send_message(struct bnxt_qplib_rcfw *rcfw, 48562306a36Sopenharmony_ci struct bnxt_qplib_cmdqmsg *msg) 48662306a36Sopenharmony_ci{ 48762306a36Sopenharmony_ci struct creq_qp_event *evnt = (struct creq_qp_event *)msg->resp; 48862306a36Sopenharmony_ci struct bnxt_qplib_crsqe *crsqe; 48962306a36Sopenharmony_ci unsigned long flags; 49062306a36Sopenharmony_ci u16 cookie; 49162306a36Sopenharmony_ci int rc; 49262306a36Sopenharmony_ci u8 opcode; 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci opcode = __get_cmdq_base_opcode(msg->req, msg->req_sz); 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci rc = __send_message_basic_sanity(rcfw, msg, opcode); 49762306a36Sopenharmony_ci if (rc) 49862306a36Sopenharmony_ci return rc; 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci rc = __send_message(rcfw, msg, opcode); 50162306a36Sopenharmony_ci if (rc) 50262306a36Sopenharmony_ci return rc; 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci cookie = le16_to_cpu(__get_cmdq_base_cookie(msg->req, msg->req_sz)) 50562306a36Sopenharmony_ci & RCFW_MAX_COOKIE_VALUE; 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci if (msg->block) 50862306a36Sopenharmony_ci rc = __block_for_resp(rcfw, cookie); 50962306a36Sopenharmony_ci else if (atomic_read(&rcfw->rcfw_intr_enabled)) 51062306a36Sopenharmony_ci rc = __wait_for_resp(rcfw, cookie); 51162306a36Sopenharmony_ci else 51262306a36Sopenharmony_ci rc = __poll_for_resp(rcfw, cookie); 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci if (rc) { 51562306a36Sopenharmony_ci spin_lock_irqsave(&rcfw->cmdq.hwq.lock, flags); 51662306a36Sopenharmony_ci crsqe = &rcfw->crsqe_tbl[cookie]; 51762306a36Sopenharmony_ci crsqe->is_waiter_alive = false; 51862306a36Sopenharmony_ci if (rc == -ENODEV) 51962306a36Sopenharmony_ci set_bit(FIRMWARE_STALL_DETECTED, &rcfw->cmdq.flags); 52062306a36Sopenharmony_ci spin_unlock_irqrestore(&rcfw->cmdq.hwq.lock, flags); 52162306a36Sopenharmony_ci return -ETIMEDOUT; 52262306a36Sopenharmony_ci } 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci if (evnt->status) { 52562306a36Sopenharmony_ci /* failed with status */ 52662306a36Sopenharmony_ci dev_err(&rcfw->pdev->dev, "cmdq[%#x]=%#x status %#x\n", 52762306a36Sopenharmony_ci cookie, opcode, evnt->status); 52862306a36Sopenharmony_ci rc = -EFAULT; 52962306a36Sopenharmony_ci } 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci return rc; 53262306a36Sopenharmony_ci} 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci/** 53562306a36Sopenharmony_ci * bnxt_qplib_rcfw_send_message - qplib interface to send 53662306a36Sopenharmony_ci * and complete rcfw command. 53762306a36Sopenharmony_ci * @rcfw: rcfw channel instance of rdev 53862306a36Sopenharmony_ci * @msg: qplib message internal 53962306a36Sopenharmony_ci * 54062306a36Sopenharmony_ci * Driver interact with Firmware through rcfw channel/slow path in two ways. 54162306a36Sopenharmony_ci * a. Blocking rcfw command send. In this path, driver cannot hold 54262306a36Sopenharmony_ci * the context for longer period since it is holding cpu until 54362306a36Sopenharmony_ci * command is not completed. 54462306a36Sopenharmony_ci * b. Non-blocking rcfw command send. In this path, driver can hold the 54562306a36Sopenharmony_ci * context for longer period. There may be many pending command waiting 54662306a36Sopenharmony_ci * for completion because of non-blocking nature. 54762306a36Sopenharmony_ci * 54862306a36Sopenharmony_ci * Driver will use shadow queue depth. Current queue depth of 8K 54962306a36Sopenharmony_ci * (due to size of rcfw message there can be actual ~4K rcfw outstanding) 55062306a36Sopenharmony_ci * is not optimal for rcfw command processing in firmware. 55162306a36Sopenharmony_ci * 55262306a36Sopenharmony_ci * Restrict at max #RCFW_CMD_NON_BLOCKING_SHADOW_QD Non-Blocking rcfw commands. 55362306a36Sopenharmony_ci * Allow all blocking commands until there is no queue full. 55462306a36Sopenharmony_ci * 55562306a36Sopenharmony_ci * Returns: 55662306a36Sopenharmony_ci * 0 if command completed by firmware. 55762306a36Sopenharmony_ci * Non zero if the command is not completed by firmware. 55862306a36Sopenharmony_ci */ 55962306a36Sopenharmony_ciint bnxt_qplib_rcfw_send_message(struct bnxt_qplib_rcfw *rcfw, 56062306a36Sopenharmony_ci struct bnxt_qplib_cmdqmsg *msg) 56162306a36Sopenharmony_ci{ 56262306a36Sopenharmony_ci int ret; 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci if (!msg->block) { 56562306a36Sopenharmony_ci down(&rcfw->rcfw_inflight); 56662306a36Sopenharmony_ci ret = __bnxt_qplib_rcfw_send_message(rcfw, msg); 56762306a36Sopenharmony_ci up(&rcfw->rcfw_inflight); 56862306a36Sopenharmony_ci } else { 56962306a36Sopenharmony_ci ret = __bnxt_qplib_rcfw_send_message(rcfw, msg); 57062306a36Sopenharmony_ci } 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci return ret; 57362306a36Sopenharmony_ci} 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci/* Completions */ 57662306a36Sopenharmony_cistatic int bnxt_qplib_process_func_event(struct bnxt_qplib_rcfw *rcfw, 57762306a36Sopenharmony_ci struct creq_func_event *func_event) 57862306a36Sopenharmony_ci{ 57962306a36Sopenharmony_ci int rc; 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci switch (func_event->event) { 58262306a36Sopenharmony_ci case CREQ_FUNC_EVENT_EVENT_TX_WQE_ERROR: 58362306a36Sopenharmony_ci break; 58462306a36Sopenharmony_ci case CREQ_FUNC_EVENT_EVENT_TX_DATA_ERROR: 58562306a36Sopenharmony_ci break; 58662306a36Sopenharmony_ci case CREQ_FUNC_EVENT_EVENT_RX_WQE_ERROR: 58762306a36Sopenharmony_ci break; 58862306a36Sopenharmony_ci case CREQ_FUNC_EVENT_EVENT_RX_DATA_ERROR: 58962306a36Sopenharmony_ci break; 59062306a36Sopenharmony_ci case CREQ_FUNC_EVENT_EVENT_CQ_ERROR: 59162306a36Sopenharmony_ci break; 59262306a36Sopenharmony_ci case CREQ_FUNC_EVENT_EVENT_TQM_ERROR: 59362306a36Sopenharmony_ci break; 59462306a36Sopenharmony_ci case CREQ_FUNC_EVENT_EVENT_CFCQ_ERROR: 59562306a36Sopenharmony_ci break; 59662306a36Sopenharmony_ci case CREQ_FUNC_EVENT_EVENT_CFCS_ERROR: 59762306a36Sopenharmony_ci /* SRQ ctx error, call srq_handler?? 59862306a36Sopenharmony_ci * But there's no SRQ handle! 59962306a36Sopenharmony_ci */ 60062306a36Sopenharmony_ci break; 60162306a36Sopenharmony_ci case CREQ_FUNC_EVENT_EVENT_CFCC_ERROR: 60262306a36Sopenharmony_ci break; 60362306a36Sopenharmony_ci case CREQ_FUNC_EVENT_EVENT_CFCM_ERROR: 60462306a36Sopenharmony_ci break; 60562306a36Sopenharmony_ci case CREQ_FUNC_EVENT_EVENT_TIM_ERROR: 60662306a36Sopenharmony_ci break; 60762306a36Sopenharmony_ci case CREQ_FUNC_EVENT_EVENT_VF_COMM_REQUEST: 60862306a36Sopenharmony_ci break; 60962306a36Sopenharmony_ci case CREQ_FUNC_EVENT_EVENT_RESOURCE_EXHAUSTED: 61062306a36Sopenharmony_ci break; 61162306a36Sopenharmony_ci default: 61262306a36Sopenharmony_ci return -EINVAL; 61362306a36Sopenharmony_ci } 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci rc = rcfw->creq.aeq_handler(rcfw, (void *)func_event, NULL); 61662306a36Sopenharmony_ci return rc; 61762306a36Sopenharmony_ci} 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_cistatic int bnxt_qplib_process_qp_event(struct bnxt_qplib_rcfw *rcfw, 62062306a36Sopenharmony_ci struct creq_qp_event *qp_event, 62162306a36Sopenharmony_ci u32 *num_wait) 62262306a36Sopenharmony_ci{ 62362306a36Sopenharmony_ci struct creq_qp_error_notification *err_event; 62462306a36Sopenharmony_ci struct bnxt_qplib_hwq *hwq = &rcfw->cmdq.hwq; 62562306a36Sopenharmony_ci struct bnxt_qplib_crsqe *crsqe; 62662306a36Sopenharmony_ci u32 qp_id, tbl_indx, req_size; 62762306a36Sopenharmony_ci struct bnxt_qplib_qp *qp; 62862306a36Sopenharmony_ci u16 cookie, blocked = 0; 62962306a36Sopenharmony_ci bool is_waiter_alive; 63062306a36Sopenharmony_ci struct pci_dev *pdev; 63162306a36Sopenharmony_ci unsigned long flags; 63262306a36Sopenharmony_ci u32 wait_cmds = 0; 63362306a36Sopenharmony_ci int rc = 0; 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci pdev = rcfw->pdev; 63662306a36Sopenharmony_ci switch (qp_event->event) { 63762306a36Sopenharmony_ci case CREQ_QP_EVENT_EVENT_QP_ERROR_NOTIFICATION: 63862306a36Sopenharmony_ci err_event = (struct creq_qp_error_notification *)qp_event; 63962306a36Sopenharmony_ci qp_id = le32_to_cpu(err_event->xid); 64062306a36Sopenharmony_ci tbl_indx = map_qp_id_to_tbl_indx(qp_id, rcfw); 64162306a36Sopenharmony_ci qp = rcfw->qp_tbl[tbl_indx].qp_handle; 64262306a36Sopenharmony_ci dev_dbg(&pdev->dev, "Received QP error notification\n"); 64362306a36Sopenharmony_ci dev_dbg(&pdev->dev, 64462306a36Sopenharmony_ci "qpid 0x%x, req_err=0x%x, resp_err=0x%x\n", 64562306a36Sopenharmony_ci qp_id, err_event->req_err_state_reason, 64662306a36Sopenharmony_ci err_event->res_err_state_reason); 64762306a36Sopenharmony_ci if (!qp) 64862306a36Sopenharmony_ci break; 64962306a36Sopenharmony_ci bnxt_qplib_mark_qp_error(qp); 65062306a36Sopenharmony_ci rc = rcfw->creq.aeq_handler(rcfw, qp_event, qp); 65162306a36Sopenharmony_ci break; 65262306a36Sopenharmony_ci default: 65362306a36Sopenharmony_ci /* 65462306a36Sopenharmony_ci * Command Response 65562306a36Sopenharmony_ci * cmdq->lock needs to be acquired to synchronie 65662306a36Sopenharmony_ci * the command send and completion reaping. This function 65762306a36Sopenharmony_ci * is always called with creq->lock held. Using 65862306a36Sopenharmony_ci * the nested variant of spin_lock. 65962306a36Sopenharmony_ci * 66062306a36Sopenharmony_ci */ 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_ci spin_lock_irqsave_nested(&hwq->lock, flags, 66362306a36Sopenharmony_ci SINGLE_DEPTH_NESTING); 66462306a36Sopenharmony_ci cookie = le16_to_cpu(qp_event->cookie); 66562306a36Sopenharmony_ci blocked = cookie & RCFW_CMD_IS_BLOCKING; 66662306a36Sopenharmony_ci cookie &= RCFW_MAX_COOKIE_VALUE; 66762306a36Sopenharmony_ci crsqe = &rcfw->crsqe_tbl[cookie]; 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_ci if (WARN_ONCE(test_bit(FIRMWARE_STALL_DETECTED, 67062306a36Sopenharmony_ci &rcfw->cmdq.flags), 67162306a36Sopenharmony_ci "QPLIB: Unreponsive rcfw channel detected.!!")) { 67262306a36Sopenharmony_ci dev_info(&pdev->dev, 67362306a36Sopenharmony_ci "rcfw timedout: cookie = %#x, free_slots = %d", 67462306a36Sopenharmony_ci cookie, crsqe->free_slots); 67562306a36Sopenharmony_ci spin_unlock_irqrestore(&hwq->lock, flags); 67662306a36Sopenharmony_ci return rc; 67762306a36Sopenharmony_ci } 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_ci if (crsqe->is_internal_cmd && !qp_event->status) 68062306a36Sopenharmony_ci atomic_dec(&rcfw->timeout_send); 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_ci if (crsqe->is_waiter_alive) { 68362306a36Sopenharmony_ci if (crsqe->resp) { 68462306a36Sopenharmony_ci memcpy(crsqe->resp, qp_event, sizeof(*qp_event)); 68562306a36Sopenharmony_ci /* Insert write memory barrier to ensure that 68662306a36Sopenharmony_ci * response data is copied before clearing the 68762306a36Sopenharmony_ci * flags 68862306a36Sopenharmony_ci */ 68962306a36Sopenharmony_ci smp_wmb(); 69062306a36Sopenharmony_ci } 69162306a36Sopenharmony_ci if (!blocked) 69262306a36Sopenharmony_ci wait_cmds++; 69362306a36Sopenharmony_ci } 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_ci req_size = crsqe->req_size; 69662306a36Sopenharmony_ci is_waiter_alive = crsqe->is_waiter_alive; 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_ci crsqe->req_size = 0; 69962306a36Sopenharmony_ci if (!is_waiter_alive) 70062306a36Sopenharmony_ci crsqe->resp = NULL; 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_ci crsqe->is_in_used = false; 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_ci hwq->cons += req_size; 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ci /* This is a case to handle below scenario - 70762306a36Sopenharmony_ci * Create AH is completed successfully by firmware, 70862306a36Sopenharmony_ci * but completion took more time and driver already lost 70962306a36Sopenharmony_ci * the context of create_ah from caller. 71062306a36Sopenharmony_ci * We have already return failure for create_ah verbs, 71162306a36Sopenharmony_ci * so let's destroy the same address vector since it is 71262306a36Sopenharmony_ci * no more used in stack. We don't care about completion 71362306a36Sopenharmony_ci * in __send_message_no_waiter. 71462306a36Sopenharmony_ci * If destroy_ah is failued by firmware, there will be AH 71562306a36Sopenharmony_ci * resource leak and relatively not critical + unlikely 71662306a36Sopenharmony_ci * scenario. Current design is not to handle such case. 71762306a36Sopenharmony_ci */ 71862306a36Sopenharmony_ci if (!is_waiter_alive && !qp_event->status && 71962306a36Sopenharmony_ci qp_event->event == CREQ_QP_EVENT_EVENT_CREATE_AH) 72062306a36Sopenharmony_ci __destroy_timedout_ah(rcfw, 72162306a36Sopenharmony_ci (struct creq_create_ah_resp *) 72262306a36Sopenharmony_ci qp_event); 72362306a36Sopenharmony_ci spin_unlock_irqrestore(&hwq->lock, flags); 72462306a36Sopenharmony_ci } 72562306a36Sopenharmony_ci *num_wait += wait_cmds; 72662306a36Sopenharmony_ci return rc; 72762306a36Sopenharmony_ci} 72862306a36Sopenharmony_ci 72962306a36Sopenharmony_ci/* SP - CREQ Completion handlers */ 73062306a36Sopenharmony_cistatic void bnxt_qplib_service_creq(struct tasklet_struct *t) 73162306a36Sopenharmony_ci{ 73262306a36Sopenharmony_ci struct bnxt_qplib_rcfw *rcfw = from_tasklet(rcfw, t, creq.creq_tasklet); 73362306a36Sopenharmony_ci struct bnxt_qplib_creq_ctx *creq = &rcfw->creq; 73462306a36Sopenharmony_ci u32 type, budget = CREQ_ENTRY_POLL_BUDGET; 73562306a36Sopenharmony_ci struct bnxt_qplib_hwq *hwq = &creq->hwq; 73662306a36Sopenharmony_ci struct creq_base *creqe; 73762306a36Sopenharmony_ci u32 sw_cons, raw_cons; 73862306a36Sopenharmony_ci unsigned long flags; 73962306a36Sopenharmony_ci u32 num_wakeup = 0; 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_ci /* Service the CREQ until budget is over */ 74262306a36Sopenharmony_ci spin_lock_irqsave(&hwq->lock, flags); 74362306a36Sopenharmony_ci raw_cons = hwq->cons; 74462306a36Sopenharmony_ci while (budget > 0) { 74562306a36Sopenharmony_ci sw_cons = HWQ_CMP(raw_cons, hwq); 74662306a36Sopenharmony_ci creqe = bnxt_qplib_get_qe(hwq, sw_cons, NULL); 74762306a36Sopenharmony_ci if (!CREQ_CMP_VALID(creqe, raw_cons, hwq->max_elements)) 74862306a36Sopenharmony_ci break; 74962306a36Sopenharmony_ci /* The valid test of the entry must be done first before 75062306a36Sopenharmony_ci * reading any further. 75162306a36Sopenharmony_ci */ 75262306a36Sopenharmony_ci dma_rmb(); 75362306a36Sopenharmony_ci rcfw->cmdq.last_seen = jiffies; 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_ci type = creqe->type & CREQ_BASE_TYPE_MASK; 75662306a36Sopenharmony_ci switch (type) { 75762306a36Sopenharmony_ci case CREQ_BASE_TYPE_QP_EVENT: 75862306a36Sopenharmony_ci bnxt_qplib_process_qp_event 75962306a36Sopenharmony_ci (rcfw, (struct creq_qp_event *)creqe, 76062306a36Sopenharmony_ci &num_wakeup); 76162306a36Sopenharmony_ci creq->stats.creq_qp_event_processed++; 76262306a36Sopenharmony_ci break; 76362306a36Sopenharmony_ci case CREQ_BASE_TYPE_FUNC_EVENT: 76462306a36Sopenharmony_ci if (!bnxt_qplib_process_func_event 76562306a36Sopenharmony_ci (rcfw, (struct creq_func_event *)creqe)) 76662306a36Sopenharmony_ci creq->stats.creq_func_event_processed++; 76762306a36Sopenharmony_ci else 76862306a36Sopenharmony_ci dev_warn(&rcfw->pdev->dev, 76962306a36Sopenharmony_ci "aeqe:%#x Not handled\n", type); 77062306a36Sopenharmony_ci break; 77162306a36Sopenharmony_ci default: 77262306a36Sopenharmony_ci if (type != ASYNC_EVENT_CMPL_TYPE_HWRM_ASYNC_EVENT) 77362306a36Sopenharmony_ci dev_warn(&rcfw->pdev->dev, 77462306a36Sopenharmony_ci "creqe with event 0x%x not handled\n", 77562306a36Sopenharmony_ci type); 77662306a36Sopenharmony_ci break; 77762306a36Sopenharmony_ci } 77862306a36Sopenharmony_ci raw_cons++; 77962306a36Sopenharmony_ci budget--; 78062306a36Sopenharmony_ci } 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_ci if (hwq->cons != raw_cons) { 78362306a36Sopenharmony_ci hwq->cons = raw_cons; 78462306a36Sopenharmony_ci bnxt_qplib_ring_nq_db(&creq->creq_db.dbinfo, 78562306a36Sopenharmony_ci rcfw->res->cctx, true); 78662306a36Sopenharmony_ci } 78762306a36Sopenharmony_ci spin_unlock_irqrestore(&hwq->lock, flags); 78862306a36Sopenharmony_ci if (num_wakeup) 78962306a36Sopenharmony_ci wake_up_nr(&rcfw->cmdq.waitq, num_wakeup); 79062306a36Sopenharmony_ci} 79162306a36Sopenharmony_ci 79262306a36Sopenharmony_cistatic irqreturn_t bnxt_qplib_creq_irq(int irq, void *dev_instance) 79362306a36Sopenharmony_ci{ 79462306a36Sopenharmony_ci struct bnxt_qplib_rcfw *rcfw = dev_instance; 79562306a36Sopenharmony_ci struct bnxt_qplib_creq_ctx *creq; 79662306a36Sopenharmony_ci struct bnxt_qplib_hwq *hwq; 79762306a36Sopenharmony_ci u32 sw_cons; 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_ci creq = &rcfw->creq; 80062306a36Sopenharmony_ci hwq = &creq->hwq; 80162306a36Sopenharmony_ci /* Prefetch the CREQ element */ 80262306a36Sopenharmony_ci sw_cons = HWQ_CMP(hwq->cons, hwq); 80362306a36Sopenharmony_ci prefetch(bnxt_qplib_get_qe(hwq, sw_cons, NULL)); 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_ci tasklet_schedule(&creq->creq_tasklet); 80662306a36Sopenharmony_ci 80762306a36Sopenharmony_ci return IRQ_HANDLED; 80862306a36Sopenharmony_ci} 80962306a36Sopenharmony_ci 81062306a36Sopenharmony_ci/* RCFW */ 81162306a36Sopenharmony_ciint bnxt_qplib_deinit_rcfw(struct bnxt_qplib_rcfw *rcfw) 81262306a36Sopenharmony_ci{ 81362306a36Sopenharmony_ci struct creq_deinitialize_fw_resp resp = {}; 81462306a36Sopenharmony_ci struct cmdq_deinitialize_fw req = {}; 81562306a36Sopenharmony_ci struct bnxt_qplib_cmdqmsg msg = {}; 81662306a36Sopenharmony_ci int rc; 81762306a36Sopenharmony_ci 81862306a36Sopenharmony_ci bnxt_qplib_rcfw_cmd_prep((struct cmdq_base *)&req, 81962306a36Sopenharmony_ci CMDQ_BASE_OPCODE_DEINITIALIZE_FW, 82062306a36Sopenharmony_ci sizeof(req)); 82162306a36Sopenharmony_ci bnxt_qplib_fill_cmdqmsg(&msg, &req, &resp, NULL, 82262306a36Sopenharmony_ci sizeof(req), sizeof(resp), 0); 82362306a36Sopenharmony_ci rc = bnxt_qplib_rcfw_send_message(rcfw, &msg); 82462306a36Sopenharmony_ci if (rc) 82562306a36Sopenharmony_ci return rc; 82662306a36Sopenharmony_ci 82762306a36Sopenharmony_ci clear_bit(FIRMWARE_INITIALIZED_FLAG, &rcfw->cmdq.flags); 82862306a36Sopenharmony_ci return 0; 82962306a36Sopenharmony_ci} 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_ciint bnxt_qplib_init_rcfw(struct bnxt_qplib_rcfw *rcfw, 83262306a36Sopenharmony_ci struct bnxt_qplib_ctx *ctx, int is_virtfn) 83362306a36Sopenharmony_ci{ 83462306a36Sopenharmony_ci struct creq_initialize_fw_resp resp = {}; 83562306a36Sopenharmony_ci struct cmdq_initialize_fw req = {}; 83662306a36Sopenharmony_ci struct bnxt_qplib_cmdqmsg msg = {}; 83762306a36Sopenharmony_ci u8 pgsz, lvl; 83862306a36Sopenharmony_ci int rc; 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_ci bnxt_qplib_rcfw_cmd_prep((struct cmdq_base *)&req, 84162306a36Sopenharmony_ci CMDQ_BASE_OPCODE_INITIALIZE_FW, 84262306a36Sopenharmony_ci sizeof(req)); 84362306a36Sopenharmony_ci /* Supply (log-base-2-of-host-page-size - base-page-shift) 84462306a36Sopenharmony_ci * to bono to adjust the doorbell page sizes. 84562306a36Sopenharmony_ci */ 84662306a36Sopenharmony_ci req.log2_dbr_pg_size = cpu_to_le16(PAGE_SHIFT - 84762306a36Sopenharmony_ci RCFW_DBR_BASE_PAGE_SHIFT); 84862306a36Sopenharmony_ci /* 84962306a36Sopenharmony_ci * Gen P5 devices doesn't require this allocation 85062306a36Sopenharmony_ci * as the L2 driver does the same for RoCE also. 85162306a36Sopenharmony_ci * Also, VFs need not setup the HW context area, PF 85262306a36Sopenharmony_ci * shall setup this area for VF. Skipping the 85362306a36Sopenharmony_ci * HW programming 85462306a36Sopenharmony_ci */ 85562306a36Sopenharmony_ci if (is_virtfn) 85662306a36Sopenharmony_ci goto skip_ctx_setup; 85762306a36Sopenharmony_ci if (bnxt_qplib_is_chip_gen_p5(rcfw->res->cctx)) 85862306a36Sopenharmony_ci goto config_vf_res; 85962306a36Sopenharmony_ci 86062306a36Sopenharmony_ci lvl = ctx->qpc_tbl.level; 86162306a36Sopenharmony_ci pgsz = bnxt_qplib_base_pg_size(&ctx->qpc_tbl); 86262306a36Sopenharmony_ci req.qpc_pg_size_qpc_lvl = (pgsz << CMDQ_INITIALIZE_FW_QPC_PG_SIZE_SFT) | 86362306a36Sopenharmony_ci lvl; 86462306a36Sopenharmony_ci lvl = ctx->mrw_tbl.level; 86562306a36Sopenharmony_ci pgsz = bnxt_qplib_base_pg_size(&ctx->mrw_tbl); 86662306a36Sopenharmony_ci req.mrw_pg_size_mrw_lvl = (pgsz << CMDQ_INITIALIZE_FW_QPC_PG_SIZE_SFT) | 86762306a36Sopenharmony_ci lvl; 86862306a36Sopenharmony_ci lvl = ctx->srqc_tbl.level; 86962306a36Sopenharmony_ci pgsz = bnxt_qplib_base_pg_size(&ctx->srqc_tbl); 87062306a36Sopenharmony_ci req.srq_pg_size_srq_lvl = (pgsz << CMDQ_INITIALIZE_FW_QPC_PG_SIZE_SFT) | 87162306a36Sopenharmony_ci lvl; 87262306a36Sopenharmony_ci lvl = ctx->cq_tbl.level; 87362306a36Sopenharmony_ci pgsz = bnxt_qplib_base_pg_size(&ctx->cq_tbl); 87462306a36Sopenharmony_ci req.cq_pg_size_cq_lvl = (pgsz << CMDQ_INITIALIZE_FW_QPC_PG_SIZE_SFT) | 87562306a36Sopenharmony_ci lvl; 87662306a36Sopenharmony_ci lvl = ctx->tim_tbl.level; 87762306a36Sopenharmony_ci pgsz = bnxt_qplib_base_pg_size(&ctx->tim_tbl); 87862306a36Sopenharmony_ci req.tim_pg_size_tim_lvl = (pgsz << CMDQ_INITIALIZE_FW_QPC_PG_SIZE_SFT) | 87962306a36Sopenharmony_ci lvl; 88062306a36Sopenharmony_ci lvl = ctx->tqm_ctx.pde.level; 88162306a36Sopenharmony_ci pgsz = bnxt_qplib_base_pg_size(&ctx->tqm_ctx.pde); 88262306a36Sopenharmony_ci req.tqm_pg_size_tqm_lvl = (pgsz << CMDQ_INITIALIZE_FW_QPC_PG_SIZE_SFT) | 88362306a36Sopenharmony_ci lvl; 88462306a36Sopenharmony_ci req.qpc_page_dir = 88562306a36Sopenharmony_ci cpu_to_le64(ctx->qpc_tbl.pbl[PBL_LVL_0].pg_map_arr[0]); 88662306a36Sopenharmony_ci req.mrw_page_dir = 88762306a36Sopenharmony_ci cpu_to_le64(ctx->mrw_tbl.pbl[PBL_LVL_0].pg_map_arr[0]); 88862306a36Sopenharmony_ci req.srq_page_dir = 88962306a36Sopenharmony_ci cpu_to_le64(ctx->srqc_tbl.pbl[PBL_LVL_0].pg_map_arr[0]); 89062306a36Sopenharmony_ci req.cq_page_dir = 89162306a36Sopenharmony_ci cpu_to_le64(ctx->cq_tbl.pbl[PBL_LVL_0].pg_map_arr[0]); 89262306a36Sopenharmony_ci req.tim_page_dir = 89362306a36Sopenharmony_ci cpu_to_le64(ctx->tim_tbl.pbl[PBL_LVL_0].pg_map_arr[0]); 89462306a36Sopenharmony_ci req.tqm_page_dir = 89562306a36Sopenharmony_ci cpu_to_le64(ctx->tqm_ctx.pde.pbl[PBL_LVL_0].pg_map_arr[0]); 89662306a36Sopenharmony_ci 89762306a36Sopenharmony_ci req.number_of_qp = cpu_to_le32(ctx->qpc_tbl.max_elements); 89862306a36Sopenharmony_ci req.number_of_mrw = cpu_to_le32(ctx->mrw_tbl.max_elements); 89962306a36Sopenharmony_ci req.number_of_srq = cpu_to_le32(ctx->srqc_tbl.max_elements); 90062306a36Sopenharmony_ci req.number_of_cq = cpu_to_le32(ctx->cq_tbl.max_elements); 90162306a36Sopenharmony_ci 90262306a36Sopenharmony_ciconfig_vf_res: 90362306a36Sopenharmony_ci req.max_qp_per_vf = cpu_to_le32(ctx->vf_res.max_qp_per_vf); 90462306a36Sopenharmony_ci req.max_mrw_per_vf = cpu_to_le32(ctx->vf_res.max_mrw_per_vf); 90562306a36Sopenharmony_ci req.max_srq_per_vf = cpu_to_le32(ctx->vf_res.max_srq_per_vf); 90662306a36Sopenharmony_ci req.max_cq_per_vf = cpu_to_le32(ctx->vf_res.max_cq_per_vf); 90762306a36Sopenharmony_ci req.max_gid_per_vf = cpu_to_le32(ctx->vf_res.max_gid_per_vf); 90862306a36Sopenharmony_ci 90962306a36Sopenharmony_ciskip_ctx_setup: 91062306a36Sopenharmony_ci req.stat_ctx_id = cpu_to_le32(ctx->stats.fw_id); 91162306a36Sopenharmony_ci bnxt_qplib_fill_cmdqmsg(&msg, &req, &resp, NULL, sizeof(req), sizeof(resp), 0); 91262306a36Sopenharmony_ci rc = bnxt_qplib_rcfw_send_message(rcfw, &msg); 91362306a36Sopenharmony_ci if (rc) 91462306a36Sopenharmony_ci return rc; 91562306a36Sopenharmony_ci set_bit(FIRMWARE_INITIALIZED_FLAG, &rcfw->cmdq.flags); 91662306a36Sopenharmony_ci return 0; 91762306a36Sopenharmony_ci} 91862306a36Sopenharmony_ci 91962306a36Sopenharmony_civoid bnxt_qplib_free_rcfw_channel(struct bnxt_qplib_rcfw *rcfw) 92062306a36Sopenharmony_ci{ 92162306a36Sopenharmony_ci kfree(rcfw->qp_tbl); 92262306a36Sopenharmony_ci kfree(rcfw->crsqe_tbl); 92362306a36Sopenharmony_ci bnxt_qplib_free_hwq(rcfw->res, &rcfw->cmdq.hwq); 92462306a36Sopenharmony_ci bnxt_qplib_free_hwq(rcfw->res, &rcfw->creq.hwq); 92562306a36Sopenharmony_ci rcfw->pdev = NULL; 92662306a36Sopenharmony_ci} 92762306a36Sopenharmony_ci 92862306a36Sopenharmony_ciint bnxt_qplib_alloc_rcfw_channel(struct bnxt_qplib_res *res, 92962306a36Sopenharmony_ci struct bnxt_qplib_rcfw *rcfw, 93062306a36Sopenharmony_ci struct bnxt_qplib_ctx *ctx, 93162306a36Sopenharmony_ci int qp_tbl_sz) 93262306a36Sopenharmony_ci{ 93362306a36Sopenharmony_ci struct bnxt_qplib_hwq_attr hwq_attr = {}; 93462306a36Sopenharmony_ci struct bnxt_qplib_sg_info sginfo = {}; 93562306a36Sopenharmony_ci struct bnxt_qplib_cmdq_ctx *cmdq; 93662306a36Sopenharmony_ci struct bnxt_qplib_creq_ctx *creq; 93762306a36Sopenharmony_ci 93862306a36Sopenharmony_ci rcfw->pdev = res->pdev; 93962306a36Sopenharmony_ci cmdq = &rcfw->cmdq; 94062306a36Sopenharmony_ci creq = &rcfw->creq; 94162306a36Sopenharmony_ci rcfw->res = res; 94262306a36Sopenharmony_ci 94362306a36Sopenharmony_ci sginfo.pgsize = PAGE_SIZE; 94462306a36Sopenharmony_ci sginfo.pgshft = PAGE_SHIFT; 94562306a36Sopenharmony_ci 94662306a36Sopenharmony_ci hwq_attr.sginfo = &sginfo; 94762306a36Sopenharmony_ci hwq_attr.res = rcfw->res; 94862306a36Sopenharmony_ci hwq_attr.depth = BNXT_QPLIB_CREQE_MAX_CNT; 94962306a36Sopenharmony_ci hwq_attr.stride = BNXT_QPLIB_CREQE_UNITS; 95062306a36Sopenharmony_ci hwq_attr.type = bnxt_qplib_get_hwq_type(res); 95162306a36Sopenharmony_ci 95262306a36Sopenharmony_ci if (bnxt_qplib_alloc_init_hwq(&creq->hwq, &hwq_attr)) { 95362306a36Sopenharmony_ci dev_err(&rcfw->pdev->dev, 95462306a36Sopenharmony_ci "HW channel CREQ allocation failed\n"); 95562306a36Sopenharmony_ci goto fail; 95662306a36Sopenharmony_ci } 95762306a36Sopenharmony_ci 95862306a36Sopenharmony_ci rcfw->cmdq_depth = BNXT_QPLIB_CMDQE_MAX_CNT; 95962306a36Sopenharmony_ci 96062306a36Sopenharmony_ci sginfo.pgsize = bnxt_qplib_cmdqe_page_size(rcfw->cmdq_depth); 96162306a36Sopenharmony_ci hwq_attr.depth = rcfw->cmdq_depth & 0x7FFFFFFF; 96262306a36Sopenharmony_ci hwq_attr.stride = BNXT_QPLIB_CMDQE_UNITS; 96362306a36Sopenharmony_ci hwq_attr.type = HWQ_TYPE_CTX; 96462306a36Sopenharmony_ci if (bnxt_qplib_alloc_init_hwq(&cmdq->hwq, &hwq_attr)) { 96562306a36Sopenharmony_ci dev_err(&rcfw->pdev->dev, 96662306a36Sopenharmony_ci "HW channel CMDQ allocation failed\n"); 96762306a36Sopenharmony_ci goto fail; 96862306a36Sopenharmony_ci } 96962306a36Sopenharmony_ci 97062306a36Sopenharmony_ci rcfw->crsqe_tbl = kcalloc(cmdq->hwq.max_elements, 97162306a36Sopenharmony_ci sizeof(*rcfw->crsqe_tbl), GFP_KERNEL); 97262306a36Sopenharmony_ci if (!rcfw->crsqe_tbl) 97362306a36Sopenharmony_ci goto fail; 97462306a36Sopenharmony_ci 97562306a36Sopenharmony_ci /* Allocate one extra to hold the QP1 entries */ 97662306a36Sopenharmony_ci rcfw->qp_tbl_size = qp_tbl_sz + 1; 97762306a36Sopenharmony_ci rcfw->qp_tbl = kcalloc(rcfw->qp_tbl_size, sizeof(struct bnxt_qplib_qp_node), 97862306a36Sopenharmony_ci GFP_KERNEL); 97962306a36Sopenharmony_ci if (!rcfw->qp_tbl) 98062306a36Sopenharmony_ci goto fail; 98162306a36Sopenharmony_ci 98262306a36Sopenharmony_ci rcfw->max_timeout = res->cctx->hwrm_cmd_max_timeout; 98362306a36Sopenharmony_ci 98462306a36Sopenharmony_ci return 0; 98562306a36Sopenharmony_ci 98662306a36Sopenharmony_cifail: 98762306a36Sopenharmony_ci bnxt_qplib_free_rcfw_channel(rcfw); 98862306a36Sopenharmony_ci return -ENOMEM; 98962306a36Sopenharmony_ci} 99062306a36Sopenharmony_ci 99162306a36Sopenharmony_civoid bnxt_qplib_rcfw_stop_irq(struct bnxt_qplib_rcfw *rcfw, bool kill) 99262306a36Sopenharmony_ci{ 99362306a36Sopenharmony_ci struct bnxt_qplib_creq_ctx *creq; 99462306a36Sopenharmony_ci 99562306a36Sopenharmony_ci creq = &rcfw->creq; 99662306a36Sopenharmony_ci 99762306a36Sopenharmony_ci if (!creq->requested) 99862306a36Sopenharmony_ci return; 99962306a36Sopenharmony_ci 100062306a36Sopenharmony_ci creq->requested = false; 100162306a36Sopenharmony_ci /* Mask h/w interrupts */ 100262306a36Sopenharmony_ci bnxt_qplib_ring_nq_db(&creq->creq_db.dbinfo, rcfw->res->cctx, false); 100362306a36Sopenharmony_ci /* Sync with last running IRQ-handler */ 100462306a36Sopenharmony_ci synchronize_irq(creq->msix_vec); 100562306a36Sopenharmony_ci free_irq(creq->msix_vec, rcfw); 100662306a36Sopenharmony_ci kfree(creq->irq_name); 100762306a36Sopenharmony_ci creq->irq_name = NULL; 100862306a36Sopenharmony_ci atomic_set(&rcfw->rcfw_intr_enabled, 0); 100962306a36Sopenharmony_ci if (kill) 101062306a36Sopenharmony_ci tasklet_kill(&creq->creq_tasklet); 101162306a36Sopenharmony_ci tasklet_disable(&creq->creq_tasklet); 101262306a36Sopenharmony_ci} 101362306a36Sopenharmony_ci 101462306a36Sopenharmony_civoid bnxt_qplib_disable_rcfw_channel(struct bnxt_qplib_rcfw *rcfw) 101562306a36Sopenharmony_ci{ 101662306a36Sopenharmony_ci struct bnxt_qplib_creq_ctx *creq; 101762306a36Sopenharmony_ci struct bnxt_qplib_cmdq_ctx *cmdq; 101862306a36Sopenharmony_ci 101962306a36Sopenharmony_ci creq = &rcfw->creq; 102062306a36Sopenharmony_ci cmdq = &rcfw->cmdq; 102162306a36Sopenharmony_ci /* Make sure the HW channel is stopped! */ 102262306a36Sopenharmony_ci bnxt_qplib_rcfw_stop_irq(rcfw, true); 102362306a36Sopenharmony_ci 102462306a36Sopenharmony_ci iounmap(cmdq->cmdq_mbox.reg.bar_reg); 102562306a36Sopenharmony_ci iounmap(creq->creq_db.reg.bar_reg); 102662306a36Sopenharmony_ci 102762306a36Sopenharmony_ci cmdq->cmdq_mbox.reg.bar_reg = NULL; 102862306a36Sopenharmony_ci creq->creq_db.reg.bar_reg = NULL; 102962306a36Sopenharmony_ci creq->aeq_handler = NULL; 103062306a36Sopenharmony_ci creq->msix_vec = 0; 103162306a36Sopenharmony_ci} 103262306a36Sopenharmony_ci 103362306a36Sopenharmony_ciint bnxt_qplib_rcfw_start_irq(struct bnxt_qplib_rcfw *rcfw, int msix_vector, 103462306a36Sopenharmony_ci bool need_init) 103562306a36Sopenharmony_ci{ 103662306a36Sopenharmony_ci struct bnxt_qplib_creq_ctx *creq; 103762306a36Sopenharmony_ci struct bnxt_qplib_res *res; 103862306a36Sopenharmony_ci int rc; 103962306a36Sopenharmony_ci 104062306a36Sopenharmony_ci creq = &rcfw->creq; 104162306a36Sopenharmony_ci res = rcfw->res; 104262306a36Sopenharmony_ci 104362306a36Sopenharmony_ci if (creq->requested) 104462306a36Sopenharmony_ci return -EFAULT; 104562306a36Sopenharmony_ci 104662306a36Sopenharmony_ci creq->msix_vec = msix_vector; 104762306a36Sopenharmony_ci if (need_init) 104862306a36Sopenharmony_ci tasklet_setup(&creq->creq_tasklet, bnxt_qplib_service_creq); 104962306a36Sopenharmony_ci else 105062306a36Sopenharmony_ci tasklet_enable(&creq->creq_tasklet); 105162306a36Sopenharmony_ci 105262306a36Sopenharmony_ci creq->irq_name = kasprintf(GFP_KERNEL, "bnxt_re-creq@pci:%s", 105362306a36Sopenharmony_ci pci_name(res->pdev)); 105462306a36Sopenharmony_ci if (!creq->irq_name) 105562306a36Sopenharmony_ci return -ENOMEM; 105662306a36Sopenharmony_ci rc = request_irq(creq->msix_vec, bnxt_qplib_creq_irq, 0, 105762306a36Sopenharmony_ci creq->irq_name, rcfw); 105862306a36Sopenharmony_ci if (rc) { 105962306a36Sopenharmony_ci kfree(creq->irq_name); 106062306a36Sopenharmony_ci creq->irq_name = NULL; 106162306a36Sopenharmony_ci tasklet_disable(&creq->creq_tasklet); 106262306a36Sopenharmony_ci return rc; 106362306a36Sopenharmony_ci } 106462306a36Sopenharmony_ci creq->requested = true; 106562306a36Sopenharmony_ci 106662306a36Sopenharmony_ci bnxt_qplib_ring_nq_db(&creq->creq_db.dbinfo, res->cctx, true); 106762306a36Sopenharmony_ci atomic_inc(&rcfw->rcfw_intr_enabled); 106862306a36Sopenharmony_ci 106962306a36Sopenharmony_ci return 0; 107062306a36Sopenharmony_ci} 107162306a36Sopenharmony_ci 107262306a36Sopenharmony_cistatic int bnxt_qplib_map_cmdq_mbox(struct bnxt_qplib_rcfw *rcfw) 107362306a36Sopenharmony_ci{ 107462306a36Sopenharmony_ci struct bnxt_qplib_cmdq_mbox *mbox; 107562306a36Sopenharmony_ci resource_size_t bar_reg; 107662306a36Sopenharmony_ci struct pci_dev *pdev; 107762306a36Sopenharmony_ci 107862306a36Sopenharmony_ci pdev = rcfw->pdev; 107962306a36Sopenharmony_ci mbox = &rcfw->cmdq.cmdq_mbox; 108062306a36Sopenharmony_ci 108162306a36Sopenharmony_ci mbox->reg.bar_id = RCFW_COMM_PCI_BAR_REGION; 108262306a36Sopenharmony_ci mbox->reg.len = RCFW_COMM_SIZE; 108362306a36Sopenharmony_ci mbox->reg.bar_base = pci_resource_start(pdev, mbox->reg.bar_id); 108462306a36Sopenharmony_ci if (!mbox->reg.bar_base) { 108562306a36Sopenharmony_ci dev_err(&pdev->dev, 108662306a36Sopenharmony_ci "QPLIB: CMDQ BAR region %d resc start is 0!\n", 108762306a36Sopenharmony_ci mbox->reg.bar_id); 108862306a36Sopenharmony_ci return -ENOMEM; 108962306a36Sopenharmony_ci } 109062306a36Sopenharmony_ci 109162306a36Sopenharmony_ci bar_reg = mbox->reg.bar_base + RCFW_COMM_BASE_OFFSET; 109262306a36Sopenharmony_ci mbox->reg.len = RCFW_COMM_SIZE; 109362306a36Sopenharmony_ci mbox->reg.bar_reg = ioremap(bar_reg, mbox->reg.len); 109462306a36Sopenharmony_ci if (!mbox->reg.bar_reg) { 109562306a36Sopenharmony_ci dev_err(&pdev->dev, 109662306a36Sopenharmony_ci "QPLIB: CMDQ BAR region %d mapping failed\n", 109762306a36Sopenharmony_ci mbox->reg.bar_id); 109862306a36Sopenharmony_ci return -ENOMEM; 109962306a36Sopenharmony_ci } 110062306a36Sopenharmony_ci 110162306a36Sopenharmony_ci mbox->prod = (void __iomem *)(mbox->reg.bar_reg + 110262306a36Sopenharmony_ci RCFW_PF_VF_COMM_PROD_OFFSET); 110362306a36Sopenharmony_ci mbox->db = (void __iomem *)(mbox->reg.bar_reg + RCFW_COMM_TRIG_OFFSET); 110462306a36Sopenharmony_ci return 0; 110562306a36Sopenharmony_ci} 110662306a36Sopenharmony_ci 110762306a36Sopenharmony_cistatic int bnxt_qplib_map_creq_db(struct bnxt_qplib_rcfw *rcfw, u32 reg_offt) 110862306a36Sopenharmony_ci{ 110962306a36Sopenharmony_ci struct bnxt_qplib_creq_db *creq_db; 111062306a36Sopenharmony_ci resource_size_t bar_reg; 111162306a36Sopenharmony_ci struct pci_dev *pdev; 111262306a36Sopenharmony_ci 111362306a36Sopenharmony_ci pdev = rcfw->pdev; 111462306a36Sopenharmony_ci creq_db = &rcfw->creq.creq_db; 111562306a36Sopenharmony_ci 111662306a36Sopenharmony_ci creq_db->reg.bar_id = RCFW_COMM_CONS_PCI_BAR_REGION; 111762306a36Sopenharmony_ci creq_db->reg.bar_base = pci_resource_start(pdev, creq_db->reg.bar_id); 111862306a36Sopenharmony_ci if (!creq_db->reg.bar_id) 111962306a36Sopenharmony_ci dev_err(&pdev->dev, 112062306a36Sopenharmony_ci "QPLIB: CREQ BAR region %d resc start is 0!", 112162306a36Sopenharmony_ci creq_db->reg.bar_id); 112262306a36Sopenharmony_ci 112362306a36Sopenharmony_ci bar_reg = creq_db->reg.bar_base + reg_offt; 112462306a36Sopenharmony_ci /* Unconditionally map 8 bytes to support 57500 series */ 112562306a36Sopenharmony_ci creq_db->reg.len = 8; 112662306a36Sopenharmony_ci creq_db->reg.bar_reg = ioremap(bar_reg, creq_db->reg.len); 112762306a36Sopenharmony_ci if (!creq_db->reg.bar_reg) { 112862306a36Sopenharmony_ci dev_err(&pdev->dev, 112962306a36Sopenharmony_ci "QPLIB: CREQ BAR region %d mapping failed", 113062306a36Sopenharmony_ci creq_db->reg.bar_id); 113162306a36Sopenharmony_ci return -ENOMEM; 113262306a36Sopenharmony_ci } 113362306a36Sopenharmony_ci creq_db->dbinfo.db = creq_db->reg.bar_reg; 113462306a36Sopenharmony_ci creq_db->dbinfo.hwq = &rcfw->creq.hwq; 113562306a36Sopenharmony_ci creq_db->dbinfo.xid = rcfw->creq.ring_id; 113662306a36Sopenharmony_ci return 0; 113762306a36Sopenharmony_ci} 113862306a36Sopenharmony_ci 113962306a36Sopenharmony_cistatic void bnxt_qplib_start_rcfw(struct bnxt_qplib_rcfw *rcfw) 114062306a36Sopenharmony_ci{ 114162306a36Sopenharmony_ci struct bnxt_qplib_cmdq_ctx *cmdq; 114262306a36Sopenharmony_ci struct bnxt_qplib_creq_ctx *creq; 114362306a36Sopenharmony_ci struct bnxt_qplib_cmdq_mbox *mbox; 114462306a36Sopenharmony_ci struct cmdq_init init = {0}; 114562306a36Sopenharmony_ci 114662306a36Sopenharmony_ci cmdq = &rcfw->cmdq; 114762306a36Sopenharmony_ci creq = &rcfw->creq; 114862306a36Sopenharmony_ci mbox = &cmdq->cmdq_mbox; 114962306a36Sopenharmony_ci 115062306a36Sopenharmony_ci init.cmdq_pbl = cpu_to_le64(cmdq->hwq.pbl[PBL_LVL_0].pg_map_arr[0]); 115162306a36Sopenharmony_ci init.cmdq_size_cmdq_lvl = 115262306a36Sopenharmony_ci cpu_to_le16(((rcfw->cmdq_depth << 115362306a36Sopenharmony_ci CMDQ_INIT_CMDQ_SIZE_SFT) & 115462306a36Sopenharmony_ci CMDQ_INIT_CMDQ_SIZE_MASK) | 115562306a36Sopenharmony_ci ((cmdq->hwq.level << 115662306a36Sopenharmony_ci CMDQ_INIT_CMDQ_LVL_SFT) & 115762306a36Sopenharmony_ci CMDQ_INIT_CMDQ_LVL_MASK)); 115862306a36Sopenharmony_ci init.creq_ring_id = cpu_to_le16(creq->ring_id); 115962306a36Sopenharmony_ci /* Write to the Bono mailbox register */ 116062306a36Sopenharmony_ci __iowrite32_copy(mbox->reg.bar_reg, &init, sizeof(init) / 4); 116162306a36Sopenharmony_ci} 116262306a36Sopenharmony_ci 116362306a36Sopenharmony_ciint bnxt_qplib_enable_rcfw_channel(struct bnxt_qplib_rcfw *rcfw, 116462306a36Sopenharmony_ci int msix_vector, 116562306a36Sopenharmony_ci int cp_bar_reg_off, 116662306a36Sopenharmony_ci aeq_handler_t aeq_handler) 116762306a36Sopenharmony_ci{ 116862306a36Sopenharmony_ci struct bnxt_qplib_cmdq_ctx *cmdq; 116962306a36Sopenharmony_ci struct bnxt_qplib_creq_ctx *creq; 117062306a36Sopenharmony_ci int rc; 117162306a36Sopenharmony_ci 117262306a36Sopenharmony_ci cmdq = &rcfw->cmdq; 117362306a36Sopenharmony_ci creq = &rcfw->creq; 117462306a36Sopenharmony_ci 117562306a36Sopenharmony_ci /* Clear to defaults */ 117662306a36Sopenharmony_ci 117762306a36Sopenharmony_ci cmdq->seq_num = 0; 117862306a36Sopenharmony_ci set_bit(FIRMWARE_FIRST_FLAG, &cmdq->flags); 117962306a36Sopenharmony_ci init_waitqueue_head(&cmdq->waitq); 118062306a36Sopenharmony_ci 118162306a36Sopenharmony_ci creq->stats.creq_qp_event_processed = 0; 118262306a36Sopenharmony_ci creq->stats.creq_func_event_processed = 0; 118362306a36Sopenharmony_ci creq->aeq_handler = aeq_handler; 118462306a36Sopenharmony_ci 118562306a36Sopenharmony_ci rc = bnxt_qplib_map_cmdq_mbox(rcfw); 118662306a36Sopenharmony_ci if (rc) 118762306a36Sopenharmony_ci return rc; 118862306a36Sopenharmony_ci 118962306a36Sopenharmony_ci rc = bnxt_qplib_map_creq_db(rcfw, cp_bar_reg_off); 119062306a36Sopenharmony_ci if (rc) 119162306a36Sopenharmony_ci return rc; 119262306a36Sopenharmony_ci 119362306a36Sopenharmony_ci rc = bnxt_qplib_rcfw_start_irq(rcfw, msix_vector, true); 119462306a36Sopenharmony_ci if (rc) { 119562306a36Sopenharmony_ci dev_err(&rcfw->pdev->dev, 119662306a36Sopenharmony_ci "Failed to request IRQ for CREQ rc = 0x%x\n", rc); 119762306a36Sopenharmony_ci bnxt_qplib_disable_rcfw_channel(rcfw); 119862306a36Sopenharmony_ci return rc; 119962306a36Sopenharmony_ci } 120062306a36Sopenharmony_ci 120162306a36Sopenharmony_ci sema_init(&rcfw->rcfw_inflight, RCFW_CMD_NON_BLOCKING_SHADOW_QD); 120262306a36Sopenharmony_ci bnxt_qplib_start_rcfw(rcfw); 120362306a36Sopenharmony_ci 120462306a36Sopenharmony_ci return 0; 120562306a36Sopenharmony_ci} 1206