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