Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit cc1ec769 authored by Devesh Sharma's avatar Devesh Sharma Committed by Doug Ledford
Browse files

RDMA/bnxt_re: Fixing the Control path command and response handling



Fixing a concurrency issue with creq handling. Each caller
was given a globally managed crsq element, which was
accessed outside a lock. This could result in corruption,
if lot of applications are simultaneously issuing Control Path
commands. Now, each caller will provide its own response buffer
and the responses will be copied under a lock.
Also, Fixing the queue full condition check for the CMDQ.

As a part of these changes, the control path code is refactored
to remove the code replication in the response status checking.

Signed-off-by: default avatarDevesh Sharma <devesh.sharma@broadcom.com>
Signed-off-by: default avatarSelvin Xavier <selvin.xavier@broadcom.com>
Signed-off-by: default avatarDoug Ledford <dledford@redhat.com>
parent 79e25959
Loading
Loading
Loading
Loading
+51 −164
Original line number Diff line number Diff line
@@ -284,7 +284,7 @@ int bnxt_qplib_create_qp1(struct bnxt_qplib_res *res, struct bnxt_qplib_qp *qp)
{
	struct bnxt_qplib_rcfw *rcfw = res->rcfw;
	struct cmdq_create_qp1 req;
	struct creq_create_qp1_resp *resp;
	struct creq_create_qp1_resp resp;
	struct bnxt_qplib_pbl *pbl;
	struct bnxt_qplib_q *sq = &qp->sq;
	struct bnxt_qplib_q *rq = &qp->rq;
@@ -394,31 +394,12 @@ int bnxt_qplib_create_qp1(struct bnxt_qplib_res *res, struct bnxt_qplib_qp *qp)

	req.pd_id = cpu_to_le32(qp->pd->id);

	resp = (struct creq_create_qp1_resp *)
			bnxt_qplib_rcfw_send_message(rcfw, (void *)&req,
						     NULL, 0);
	if (!resp) {
		dev_err(&res->pdev->dev, "QPLIB: FP: CREATE_QP1 send failed");
		rc = -EINVAL;
		goto fail;
	}
	if (!bnxt_qplib_rcfw_wait_for_resp(rcfw, le16_to_cpu(req.cookie))) {
		/* Cmd timed out */
		dev_err(&rcfw->pdev->dev, "QPLIB: FP: CREATE_QP1 timed out");
		rc = -ETIMEDOUT;
		goto fail;
	}
	if (resp->status ||
	    le16_to_cpu(resp->cookie) != le16_to_cpu(req.cookie)) {
		dev_err(&rcfw->pdev->dev, "QPLIB: FP: CREATE_QP1 failed ");
		dev_err(&rcfw->pdev->dev,
			"QPLIB: with status 0x%x cmdq 0x%x resp 0x%x",
			resp->status, le16_to_cpu(req.cookie),
			le16_to_cpu(resp->cookie));
		rc = -EINVAL;
	rc = bnxt_qplib_rcfw_send_message(rcfw, (void *)&req,
					  (void *)&resp, NULL, 0);
	if (rc)
		goto fail;
	}
	qp->id = le32_to_cpu(resp->xid);

	qp->id = le32_to_cpu(resp.xid);
	qp->cur_qp_state = CMDQ_MODIFY_QP_NEW_STATE_RESET;
	sq->flush_in_progress = false;
	rq->flush_in_progress = false;
@@ -442,7 +423,7 @@ int bnxt_qplib_create_qp(struct bnxt_qplib_res *res, struct bnxt_qplib_qp *qp)
	struct bnxt_qplib_rcfw *rcfw = res->rcfw;
	struct sq_send *hw_sq_send_hdr, **hw_sq_send_ptr;
	struct cmdq_create_qp req;
	struct creq_create_qp_resp *resp;
	struct creq_create_qp_resp resp;
	struct bnxt_qplib_pbl *pbl;
	struct sq_psn_search **psn_search_ptr;
	unsigned long int psn_search, poff = 0;
@@ -627,31 +608,12 @@ int bnxt_qplib_create_qp(struct bnxt_qplib_res *res, struct bnxt_qplib_qp *qp)
	}
	req.pd_id = cpu_to_le32(qp->pd->id);

	resp = (struct creq_create_qp_resp *)
			bnxt_qplib_rcfw_send_message(rcfw, (void *)&req,
						     NULL, 0);
	if (!resp) {
		dev_err(&rcfw->pdev->dev, "QPLIB: FP: CREATE_QP send failed");
		rc = -EINVAL;
		goto fail;
	}
	if (!bnxt_qplib_rcfw_wait_for_resp(rcfw, le16_to_cpu(req.cookie))) {
		/* Cmd timed out */
		dev_err(&rcfw->pdev->dev, "QPLIB: FP: CREATE_QP timed out");
		rc = -ETIMEDOUT;
		goto fail;
	}
	if (resp->status ||
	    le16_to_cpu(resp->cookie) != le16_to_cpu(req.cookie)) {
		dev_err(&rcfw->pdev->dev, "QPLIB: FP: CREATE_QP failed ");
		dev_err(&rcfw->pdev->dev,
			"QPLIB: with status 0x%x cmdq 0x%x resp 0x%x",
			resp->status, le16_to_cpu(req.cookie),
			le16_to_cpu(resp->cookie));
		rc = -EINVAL;
	rc = bnxt_qplib_rcfw_send_message(rcfw, (void *)&req,
					  (void *)&resp, NULL, 0);
	if (rc)
		goto fail;
	}
	qp->id = le32_to_cpu(resp->xid);

	qp->id = le32_to_cpu(resp.xid);
	qp->cur_qp_state = CMDQ_MODIFY_QP_NEW_STATE_RESET;
	sq->flush_in_progress = false;
	rq->flush_in_progress = false;
@@ -769,10 +731,11 @@ int bnxt_qplib_modify_qp(struct bnxt_qplib_res *res, struct bnxt_qplib_qp *qp)
{
	struct bnxt_qplib_rcfw *rcfw = res->rcfw;
	struct cmdq_modify_qp req;
	struct creq_modify_qp_resp *resp;
	struct creq_modify_qp_resp resp;
	u16 cmd_flags = 0, pkey;
	u32 temp32[4];
	u32 bmask;
	int rc;

	RCFW_CMD_PREP(req, MODIFY_QP, cmd_flags);

@@ -862,27 +825,10 @@ int bnxt_qplib_modify_qp(struct bnxt_qplib_res *res, struct bnxt_qplib_qp *qp)

	req.vlan_pcp_vlan_dei_vlan_id = cpu_to_le16(qp->vlan_id);

	resp = (struct creq_modify_qp_resp *)
			bnxt_qplib_rcfw_send_message(rcfw, (void *)&req,
						     NULL, 0);
	if (!resp) {
		dev_err(&rcfw->pdev->dev, "QPLIB: FP: MODIFY_QP send failed");
		return -EINVAL;
	}
	if (!bnxt_qplib_rcfw_wait_for_resp(rcfw, le16_to_cpu(req.cookie))) {
		/* Cmd timed out */
		dev_err(&rcfw->pdev->dev, "QPLIB: FP: MODIFY_QP timed out");
		return -ETIMEDOUT;
	}
	if (resp->status ||
	    le16_to_cpu(resp->cookie) != le16_to_cpu(req.cookie)) {
		dev_err(&rcfw->pdev->dev, "QPLIB: FP: MODIFY_QP failed ");
		dev_err(&rcfw->pdev->dev,
			"QPLIB: with status 0x%x cmdq 0x%x resp 0x%x",
			resp->status, le16_to_cpu(req.cookie),
			le16_to_cpu(resp->cookie));
		return -EINVAL;
	}
	rc = bnxt_qplib_rcfw_send_message(rcfw, (void *)&req,
					  (void *)&resp, NULL, 0);
	if (rc)
		return rc;
	qp->cur_qp_state = qp->state;
	return 0;
}
@@ -891,37 +837,26 @@ int bnxt_qplib_query_qp(struct bnxt_qplib_res *res, struct bnxt_qplib_qp *qp)
{
	struct bnxt_qplib_rcfw *rcfw = res->rcfw;
	struct cmdq_query_qp req;
	struct creq_query_qp_resp *resp;
	struct creq_query_qp_resp resp;
	struct bnxt_qplib_rcfw_sbuf *sbuf;
	struct creq_query_qp_resp_sb *sb;
	u16 cmd_flags = 0;
	u32 temp32[4];
	int i;
	int i, rc = 0;

	RCFW_CMD_PREP(req, QUERY_QP, cmd_flags);

	sbuf = bnxt_qplib_rcfw_alloc_sbuf(rcfw, sizeof(*sb));
	if (!sbuf)
		return -ENOMEM;
	sb = sbuf->sb;

	req.qp_cid = cpu_to_le32(qp->id);
	req.resp_size = sizeof(*sb) / BNXT_QPLIB_CMDQE_UNITS;
	resp = (struct creq_query_qp_resp *)
			bnxt_qplib_rcfw_send_message(rcfw, (void *)&req,
						     (void **)&sb, 0);
	if (!resp) {
		dev_err(&rcfw->pdev->dev, "QPLIB: FP: QUERY_QP send failed");
		return -EINVAL;
	}
	if (!bnxt_qplib_rcfw_wait_for_resp(rcfw, le16_to_cpu(req.cookie))) {
		/* Cmd timed out */
		dev_err(&rcfw->pdev->dev, "QPLIB: FP: QUERY_QP timed out");
		return -ETIMEDOUT;
	}
	if (resp->status ||
	    le16_to_cpu(resp->cookie) != le16_to_cpu(req.cookie)) {
		dev_err(&rcfw->pdev->dev, "QPLIB: FP: QUERY_QP failed ");
		dev_err(&rcfw->pdev->dev,
			"QPLIB: with status 0x%x cmdq 0x%x resp 0x%x",
			resp->status, le16_to_cpu(req.cookie),
			le16_to_cpu(resp->cookie));
		return -EINVAL;
	}
	rc = bnxt_qplib_rcfw_send_message(rcfw, (void *)&req, (void *)&resp,
					  (void *)sbuf, 0);
	if (rc)
		goto bail;
	/* Extract the context from the side buffer */
	qp->state = sb->en_sqd_async_notify_state &
			CREQ_QUERY_QP_RESP_SB_STATE_MASK;
@@ -976,7 +911,9 @@ int bnxt_qplib_query_qp(struct bnxt_qplib_res *res, struct bnxt_qplib_qp *qp)
	qp->dest_qpn = le32_to_cpu(sb->dest_qp_id);
	memcpy(qp->smac, sb->src_mac, 6);
	qp->vlan_id = le16_to_cpu(sb->vlan_pcp_vlan_dei_vlan_id);
	return 0;
bail:
	bnxt_qplib_rcfw_free_sbuf(rcfw, sbuf);
	return rc;
}

static void __clean_cq(struct bnxt_qplib_cq *cq, u64 qp)
@@ -1021,34 +958,18 @@ int bnxt_qplib_destroy_qp(struct bnxt_qplib_res *res,
{
	struct bnxt_qplib_rcfw *rcfw = res->rcfw;
	struct cmdq_destroy_qp req;
	struct creq_destroy_qp_resp *resp;
	struct creq_destroy_qp_resp resp;
	unsigned long flags;
	u16 cmd_flags = 0;
	int rc;

	RCFW_CMD_PREP(req, DESTROY_QP, cmd_flags);

	req.qp_cid = cpu_to_le32(qp->id);
	resp = (struct creq_destroy_qp_resp *)
			bnxt_qplib_rcfw_send_message(rcfw, (void *)&req,
						     NULL, 0);
	if (!resp) {
		dev_err(&rcfw->pdev->dev, "QPLIB: FP: DESTROY_QP send failed");
		return -EINVAL;
	}
	if (!bnxt_qplib_rcfw_wait_for_resp(rcfw, le16_to_cpu(req.cookie))) {
		/* Cmd timed out */
		dev_err(&rcfw->pdev->dev, "QPLIB: FP: DESTROY_QP timed out");
		return -ETIMEDOUT;
	}
	if (resp->status ||
	    le16_to_cpu(resp->cookie) != le16_to_cpu(req.cookie)) {
		dev_err(&rcfw->pdev->dev, "QPLIB: FP: DESTROY_QP failed ");
		dev_err(&rcfw->pdev->dev,
			"QPLIB: with status 0x%x cmdq 0x%x resp 0x%x",
			resp->status, le16_to_cpu(req.cookie),
			le16_to_cpu(resp->cookie));
		return -EINVAL;
	}
	rc = bnxt_qplib_rcfw_send_message(rcfw, (void *)&req,
					  (void *)&resp, NULL, 0);
	if (rc)
		return rc;

	/* Must walk the associated CQs to nullified the QP ptr */
	spin_lock_irqsave(&qp->scq->hwq.lock, flags);
@@ -1483,7 +1404,7 @@ int bnxt_qplib_create_cq(struct bnxt_qplib_res *res, struct bnxt_qplib_cq *cq)
{
	struct bnxt_qplib_rcfw *rcfw = res->rcfw;
	struct cmdq_create_cq req;
	struct creq_create_cq_resp *resp;
	struct creq_create_cq_resp resp;
	struct bnxt_qplib_pbl *pbl;
	u16 cmd_flags = 0;
	int rc;
@@ -1525,30 +1446,12 @@ int bnxt_qplib_create_cq(struct bnxt_qplib_res *res, struct bnxt_qplib_cq *cq)
			(cq->cnq_hw_ring_id & CMDQ_CREATE_CQ_CNQ_ID_MASK) <<
			 CMDQ_CREATE_CQ_CNQ_ID_SFT);

	resp = (struct creq_create_cq_resp *)
			bnxt_qplib_rcfw_send_message(rcfw, (void *)&req,
						     NULL, 0);
	if (!resp) {
		dev_err(&rcfw->pdev->dev, "QPLIB: FP: CREATE_CQ send failed");
		return -EINVAL;
	}
	if (!bnxt_qplib_rcfw_wait_for_resp(rcfw, le16_to_cpu(req.cookie))) {
		/* Cmd timed out */
		dev_err(&rcfw->pdev->dev, "QPLIB: FP: CREATE_CQ timed out");
		rc = -ETIMEDOUT;
		goto fail;
	}
	if (resp->status ||
	    le16_to_cpu(resp->cookie) != le16_to_cpu(req.cookie)) {
		dev_err(&rcfw->pdev->dev, "QPLIB: FP: CREATE_CQ failed ");
		dev_err(&rcfw->pdev->dev,
			"QPLIB: with status 0x%x cmdq 0x%x resp 0x%x",
			resp->status, le16_to_cpu(req.cookie),
			le16_to_cpu(resp->cookie));
		rc = -EINVAL;
	rc = bnxt_qplib_rcfw_send_message(rcfw, (void *)&req,
					  (void *)&resp, NULL, 0);
	if (rc)
		goto fail;
	}
	cq->id = le32_to_cpu(resp->xid);

	cq->id = le32_to_cpu(resp.xid);
	cq->dbr_base = res->dpi_tbl.dbr_bar_reg_iomem;
	cq->period = BNXT_QPLIB_QUEUE_START_PERIOD;
	init_waitqueue_head(&cq->waitq);
@@ -1566,33 +1469,17 @@ int bnxt_qplib_destroy_cq(struct bnxt_qplib_res *res, struct bnxt_qplib_cq *cq)
{
	struct bnxt_qplib_rcfw *rcfw = res->rcfw;
	struct cmdq_destroy_cq req;
	struct creq_destroy_cq_resp *resp;
	struct creq_destroy_cq_resp resp;
	u16 cmd_flags = 0;
	int rc;

	RCFW_CMD_PREP(req, DESTROY_CQ, cmd_flags);

	req.cq_cid = cpu_to_le32(cq->id);
	resp = (struct creq_destroy_cq_resp *)
			bnxt_qplib_rcfw_send_message(rcfw, (void *)&req,
						     NULL, 0);
	if (!resp) {
		dev_err(&rcfw->pdev->dev, "QPLIB: FP: DESTROY_CQ send failed");
		return -EINVAL;
	}
	if (!bnxt_qplib_rcfw_wait_for_resp(rcfw, le16_to_cpu(req.cookie))) {
		/* Cmd timed out */
		dev_err(&rcfw->pdev->dev, "QPLIB: FP: DESTROY_CQ timed out");
		return -ETIMEDOUT;
	}
	if (resp->status ||
	    le16_to_cpu(resp->cookie) != le16_to_cpu(req.cookie)) {
		dev_err(&rcfw->pdev->dev, "QPLIB: FP: DESTROY_CQ failed ");
		dev_err(&rcfw->pdev->dev,
			"QPLIB: with status 0x%x cmdq 0x%x resp 0x%x",
			resp->status, le16_to_cpu(req.cookie),
			le16_to_cpu(resp->cookie));
		return -EINVAL;
	}
	rc = bnxt_qplib_rcfw_send_message(rcfw, (void *)&req,
					  (void *)&resp, NULL, 0);
	if (rc)
		return rc;
	bnxt_qplib_free_hwq(res->pdev, &cq->hwq);
	return 0;
}
+164 −150
Original line number Diff line number Diff line
@@ -39,72 +39,55 @@
#include <linux/spinlock.h>
#include <linux/pci.h>
#include <linux/prefetch.h>
#include <linux/delay.h>

#include "roce_hsi.h"
#include "qplib_res.h"
#include "qplib_rcfw.h"
static void bnxt_qplib_service_creq(unsigned long data);

/* Hardware communication channel */
int bnxt_qplib_rcfw_wait_for_resp(struct bnxt_qplib_rcfw *rcfw, u16 cookie)
static int __wait_for_resp(struct bnxt_qplib_rcfw *rcfw, u16 cookie)
{
	u16 cbit;
	int rc;

	cookie &= RCFW_MAX_COOKIE_VALUE;
	cbit = cookie % RCFW_MAX_OUTSTANDING_CMD;
	if (!test_bit(cbit, rcfw->cmdq_bitmap))
		dev_warn(&rcfw->pdev->dev,
			 "QPLIB: CMD bit %d for cookie 0x%x is not set?",
			 cbit, cookie);

	rc = wait_event_timeout(rcfw->waitq,
				!test_bit(cbit, rcfw->cmdq_bitmap),
				msecs_to_jiffies(RCFW_CMD_WAIT_TIME_MS));
	if (!rc) {
		dev_warn(&rcfw->pdev->dev,
			 "QPLIB: Bono Error: timeout %d msec, msg {0x%x}\n",
			 RCFW_CMD_WAIT_TIME_MS, cookie);
	}

	return rc;
	return rc ? 0 : -ETIMEDOUT;
};

int bnxt_qplib_rcfw_block_for_resp(struct bnxt_qplib_rcfw *rcfw, u16 cookie)
static int __block_for_resp(struct bnxt_qplib_rcfw *rcfw, u16 cookie)
{
	u32 count = -1;
	u32 count = RCFW_BLOCKED_CMD_WAIT_COUNT;
	u16 cbit;

	cookie &= RCFW_MAX_COOKIE_VALUE;
	cbit = cookie % RCFW_MAX_OUTSTANDING_CMD;
	if (!test_bit(cbit, rcfw->cmdq_bitmap))
		goto done;
	do {
		mdelay(1); /* 1m sec */
		bnxt_qplib_service_creq((unsigned long)rcfw);
	} while (test_bit(cbit, rcfw->cmdq_bitmap) && --count);
done:
	return count;
	return count ? 0 : -ETIMEDOUT;
};

void *bnxt_qplib_rcfw_send_message(struct bnxt_qplib_rcfw *rcfw,
				   struct cmdq_base *req, void **crsbe,
				   u8 is_block)
static int __send_message(struct bnxt_qplib_rcfw *rcfw, struct cmdq_base *req,
			  struct creq_base *resp, void *sb, u8 is_block)
{
	struct bnxt_qplib_crsq *crsq = &rcfw->crsq;
	struct bnxt_qplib_cmdqe *cmdqe, **cmdq_ptr;
	struct bnxt_qplib_hwq *cmdq = &rcfw->cmdq;
	struct bnxt_qplib_hwq *crsb = &rcfw->crsb;
	struct bnxt_qplib_crsqe *crsqe = NULL;
	struct bnxt_qplib_crsbe **crsb_ptr;
	struct bnxt_qplib_crsq *crsqe;
	u32 sw_prod, cmdq_prod;
	u8 retry_cnt = 0xFF;
	dma_addr_t dma_addr;
	unsigned long flags;
	u32 size, opcode;
	u16 cookie, cbit;
	int pg, idx;
	u8 *preq;

retry:
	opcode = req->opcode;
	if (!test_bit(FIRMWARE_INITIALIZED_FLAG, &rcfw->flags) &&
	    (opcode != CMDQ_BASE_OPCODE_QUERY_FUNC &&
@@ -112,63 +95,50 @@ void *bnxt_qplib_rcfw_send_message(struct bnxt_qplib_rcfw *rcfw,
		dev_err(&rcfw->pdev->dev,
			"QPLIB: RCFW not initialized, reject opcode 0x%x",
			opcode);
		return NULL;
		return -EINVAL;
	}

	if (test_bit(FIRMWARE_INITIALIZED_FLAG, &rcfw->flags) &&
	    opcode == CMDQ_BASE_OPCODE_INITIALIZE_FW) {
		dev_err(&rcfw->pdev->dev, "QPLIB: RCFW already initialized!");
		return NULL;
		return -EINVAL;
	}

	/* Cmdq are in 16-byte units, each request can consume 1 or more
	 * cmdqe
	 */
	spin_lock_irqsave(&cmdq->lock, flags);
	if (req->cmd_size > cmdq->max_elements -
	    ((HWQ_CMP(cmdq->prod, cmdq) - HWQ_CMP(cmdq->cons, cmdq)) &
	     (cmdq->max_elements - 1))) {
	if (req->cmd_size >= HWQ_FREE_SLOTS(cmdq)) {
		dev_err(&rcfw->pdev->dev, "QPLIB: RCFW: CMDQ is full!");
		spin_unlock_irqrestore(&cmdq->lock, flags);

		if (!retry_cnt--)
			return NULL;
		goto retry;
		return -EAGAIN;
	}

	retry_cnt = 0xFF;

	cookie = atomic_inc_return(&rcfw->seq_num) & RCFW_MAX_COOKIE_VALUE;
	cookie = rcfw->seq_num & RCFW_MAX_COOKIE_VALUE;
	cbit = cookie % RCFW_MAX_OUTSTANDING_CMD;
	if (is_block)
		cookie |= RCFW_CMD_IS_BLOCKING;

	set_bit(cbit, rcfw->cmdq_bitmap);
	req->cookie = cpu_to_le16(cookie);
	if (test_and_set_bit(cbit, rcfw->cmdq_bitmap)) {
		dev_err(&rcfw->pdev->dev,
			"QPLIB: RCFW MAX outstanding cmd reached!");
		atomic_dec(&rcfw->seq_num);
	crsqe = &rcfw->crsqe_tbl[cbit];
	if (crsqe->resp) {
		spin_unlock_irqrestore(&cmdq->lock, flags);
		return -EBUSY;
	}
	memset(resp, 0, sizeof(*resp));
	crsqe->resp = (struct creq_qp_event *)resp;
	crsqe->resp->cookie = req->cookie;
	crsqe->req_size = req->cmd_size;
	if (req->resp_size && sb) {
		struct bnxt_qplib_rcfw_sbuf *sbuf = sb;

		if (!retry_cnt--)
			return NULL;
		goto retry;
	}
	/* Reserve a resp buffer slot if requested */
	if (req->resp_size && crsbe) {
		spin_lock(&crsb->lock);
		sw_prod = HWQ_CMP(crsb->prod, crsb);
		crsb_ptr = (struct bnxt_qplib_crsbe **)crsb->pbl_ptr;
		*crsbe = (void *)&crsb_ptr[get_crsb_pg(sw_prod)]
					  [get_crsb_idx(sw_prod)];
		bnxt_qplib_crsb_dma_next(crsb->pbl_dma_ptr, sw_prod, &dma_addr);
		req->resp_addr = cpu_to_le64(dma_addr);
		crsb->prod++;
		spin_unlock(&crsb->lock);

		req->resp_size = (sizeof(struct bnxt_qplib_crsbe) +
				  BNXT_QPLIB_CMDQE_UNITS - 1) /
		req->resp_addr = cpu_to_le64(sbuf->dma_addr);
		req->resp_size = (sbuf->size + BNXT_QPLIB_CMDQE_UNITS - 1) /
				  BNXT_QPLIB_CMDQE_UNITS;
	}

	cmdq_ptr = (struct bnxt_qplib_cmdqe **)cmdq->pbl_ptr;
	preq = (u8 *)req;
	size = req->cmd_size * BNXT_QPLIB_CMDQE_UNITS;
@@ -190,23 +160,24 @@ void *bnxt_qplib_rcfw_send_message(struct bnxt_qplib_rcfw *rcfw,
		preq += min_t(u32, size, sizeof(*cmdqe));
		size -= min_t(u32, size, sizeof(*cmdqe));
		cmdq->prod++;
		rcfw->seq_num++;
	} while (size > 0);

	rcfw->seq_num++;

	cmdq_prod = cmdq->prod;
	if (rcfw->flags & FIRMWARE_FIRST_FLAG) {
		/* The very first doorbell write is required to set this flag
		 * which prompts the FW to reset its internal pointers
		/* The very first doorbell write
		 * is required to set this flag
		 * which prompts the FW to reset
		 * its internal pointers
		 */
		cmdq_prod |= FIRMWARE_FIRST_FLAG;
		rcfw->flags &= ~FIRMWARE_FIRST_FLAG;
	}
	sw_prod = HWQ_CMP(crsq->prod, crsq);
	crsqe = &crsq->crsq[sw_prod];
	memset(crsqe, 0, sizeof(*crsqe));
	crsq->prod++;
	crsqe->req_size = req->cmd_size;

	/* ring CMDQ DB */
	wmb();
	writel(cmdq_prod, rcfw->cmdq_bar_reg_iomem +
	       rcfw->cmdq_bar_reg_prod_off);
	writel(RCFW_CMDQ_TRIG_VAL, rcfw->cmdq_bar_reg_iomem +
@@ -214,9 +185,56 @@ void *bnxt_qplib_rcfw_send_message(struct bnxt_qplib_rcfw *rcfw,
done:
	spin_unlock_irqrestore(&cmdq->lock, flags);
	/* Return the CREQ response pointer */
	return crsqe ? &crsqe->qp_event : NULL;
	return 0;
}

int bnxt_qplib_rcfw_send_message(struct bnxt_qplib_rcfw *rcfw,
				 struct cmdq_base *req,
				 struct creq_base *resp,
				 void *sb, u8 is_block)
{
	struct creq_qp_event *evnt = (struct creq_qp_event *)resp;
	u16 cookie;
	u8 opcode, retry_cnt = 0xFF;
	int rc = 0;

	do {
		opcode = req->opcode;
		rc = __send_message(rcfw, req, resp, sb, is_block);
		cookie = le16_to_cpu(req->cookie) & RCFW_MAX_COOKIE_VALUE;
		if (!rc)
			break;

		if (!retry_cnt || (rc != -EAGAIN && rc != -EBUSY)) {
			/* send failed */
			dev_err(&rcfw->pdev->dev, "QPLIB: cmdq[%#x]=%#x send failed",
				cookie, opcode);
			return rc;
		}
		is_block ? mdelay(1) : usleep_range(500, 1000);

	} while (retry_cnt--);

	if (is_block)
		rc = __block_for_resp(rcfw, cookie);
	else
		rc = __wait_for_resp(rcfw, cookie);
	if (rc) {
		/* timed out */
		dev_err(&rcfw->pdev->dev, "QPLIB: cmdq[%#x]=%#x timedout (%d)msec",
			cookie, opcode, RCFW_CMD_WAIT_TIME_MS);
		return rc;
	}

	if (evnt->status) {
		/* failed with status */
		dev_err(&rcfw->pdev->dev, "QPLIB: cmdq[%#x]=%#x status %#x",
			cookie, opcode, evnt->status);
		rc = -EFAULT;
	}

	return rc;
}
/* Completions */
static int bnxt_qplib_process_func_event(struct bnxt_qplib_rcfw *rcfw,
					 struct creq_func_event *func_event)
@@ -260,12 +278,12 @@ static int bnxt_qplib_process_func_event(struct bnxt_qplib_rcfw *rcfw,
static int bnxt_qplib_process_qp_event(struct bnxt_qplib_rcfw *rcfw,
				       struct creq_qp_event *qp_event)
{
	struct bnxt_qplib_crsq *crsq = &rcfw->crsq;
	struct bnxt_qplib_hwq *cmdq = &rcfw->cmdq;
	struct bnxt_qplib_crsqe *crsqe;
	u16 cbit, cookie, blocked = 0;
	struct bnxt_qplib_crsq *crsqe;
	unsigned long flags;
	u32 sw_cons;
	u16 cbit, blocked = 0;
	u16 cookie;
	__le16  mcookie;

	switch (qp_event->event) {
	case CREQ_QP_EVENT_EVENT_QP_ERROR_NOTIFICATION:
@@ -275,24 +293,31 @@ static int bnxt_qplib_process_qp_event(struct bnxt_qplib_rcfw *rcfw,
	default:
		/* Command Response */
		spin_lock_irqsave(&cmdq->lock, flags);
		sw_cons = HWQ_CMP(crsq->cons, crsq);
		crsqe = &crsq->crsq[sw_cons];
		crsq->cons++;
		memcpy(&crsqe->qp_event, qp_event, sizeof(crsqe->qp_event));

		cookie = le16_to_cpu(crsqe->qp_event.cookie);
		cookie = le16_to_cpu(qp_event->cookie);
		mcookie = qp_event->cookie;
		blocked = cookie & RCFW_CMD_IS_BLOCKING;
		cookie &= RCFW_MAX_COOKIE_VALUE;
		cbit = cookie % RCFW_MAX_OUTSTANDING_CMD;
		crsqe = &rcfw->crsqe_tbl[cbit];
		if (crsqe->resp &&
		    crsqe->resp->cookie  == mcookie) {
			memcpy(crsqe->resp, qp_event, sizeof(*qp_event));
			crsqe->resp = NULL;
		} else {
			dev_err(&rcfw->pdev->dev,
				"QPLIB: CMD %s resp->cookie = %#x, evnt->cookie = %#x",
				crsqe->resp ? "mismatch" : "collision",
				crsqe->resp ? crsqe->resp->cookie : 0, mcookie);
		}
		if (!test_and_clear_bit(cbit, rcfw->cmdq_bitmap))
			dev_warn(&rcfw->pdev->dev,
				 "QPLIB: CMD bit %d was not requested", cbit);

		cmdq->cons += crsqe->req_size;
		spin_unlock_irqrestore(&cmdq->lock, flags);
		crsqe->req_size = 0;

		if (!blocked)
			wake_up(&rcfw->waitq);
		break;
		spin_unlock_irqrestore(&cmdq->lock, flags);
	}
	return 0;
}
@@ -305,12 +330,12 @@ static void bnxt_qplib_service_creq(unsigned long data)
	struct creq_base *creqe, **creq_ptr;
	u32 sw_cons, raw_cons;
	unsigned long flags;
	u32 type;
	u32 type, budget = CREQ_ENTRY_POLL_BUDGET;

	/* Service the CREQ until empty */
	/* Service the CREQ until budget is over */
	spin_lock_irqsave(&creq->lock, flags);
	raw_cons = creq->cons;
	while (1) {
	while (budget > 0) {
		sw_cons = HWQ_CMP(raw_cons, creq);
		creq_ptr = (struct creq_base **)creq->pbl_ptr;
		creqe = &creq_ptr[get_creq_pg(sw_cons)][get_creq_idx(sw_cons)];
@@ -320,15 +345,9 @@ static void bnxt_qplib_service_creq(unsigned long data)
		type = creqe->type & CREQ_BASE_TYPE_MASK;
		switch (type) {
		case CREQ_BASE_TYPE_QP_EVENT:
			if (!bnxt_qplib_process_qp_event
			    (rcfw, (struct creq_qp_event *)creqe))
			bnxt_qplib_process_qp_event
				(rcfw, (struct creq_qp_event *)creqe);
			rcfw->creq_qp_event_processed++;
			else {
				dev_warn(&rcfw->pdev->dev, "QPLIB: crsqe with");
				dev_warn(&rcfw->pdev->dev,
					 "QPLIB: type = 0x%x not handled",
					 type);
			}
			break;
		case CREQ_BASE_TYPE_FUNC_EVENT:
			if (!bnxt_qplib_process_func_event
@@ -346,7 +365,9 @@ static void bnxt_qplib_service_creq(unsigned long data)
			break;
		}
		raw_cons++;
		budget--;
	}

	if (creq->cons != raw_cons) {
		creq->cons = raw_cons;
		CREQ_DB_REARM(rcfw->creq_bar_reg_iomem, raw_cons,
@@ -375,23 +396,16 @@ static irqreturn_t bnxt_qplib_creq_irq(int irq, void *dev_instance)
/* RCFW */
int bnxt_qplib_deinit_rcfw(struct bnxt_qplib_rcfw *rcfw)
{
	struct creq_deinitialize_fw_resp *resp;
	struct cmdq_deinitialize_fw req;
	struct creq_deinitialize_fw_resp resp;
	u16 cmd_flags = 0;
	int rc;

	RCFW_CMD_PREP(req, DEINITIALIZE_FW, cmd_flags);
	resp = (struct creq_deinitialize_fw_resp *)
			bnxt_qplib_rcfw_send_message(rcfw, (void *)&req,
	rc = bnxt_qplib_rcfw_send_message(rcfw, (void *)&req, (void *)&resp,
					  NULL, 0);
	if (!resp)
		return -EINVAL;

	if (!bnxt_qplib_rcfw_wait_for_resp(rcfw, le16_to_cpu(req.cookie)))
		return -ETIMEDOUT;

	if (resp->status ||
	    le16_to_cpu(resp->cookie) != le16_to_cpu(req.cookie))
		return -EFAULT;
	if (rc)
		return rc;

	clear_bit(FIRMWARE_INITIALIZED_FLAG, &rcfw->flags);
	return 0;
@@ -417,9 +431,10 @@ static int __get_pbl_pg_idx(struct bnxt_qplib_pbl *pbl)
int bnxt_qplib_init_rcfw(struct bnxt_qplib_rcfw *rcfw,
			 struct bnxt_qplib_ctx *ctx, int is_virtfn)
{
	struct creq_initialize_fw_resp *resp;
	struct cmdq_initialize_fw req;
	struct creq_initialize_fw_resp resp;
	u16 cmd_flags = 0, level;
	int rc;

	RCFW_CMD_PREP(req, INITIALIZE_FW, cmd_flags);

@@ -482,37 +497,19 @@ int bnxt_qplib_init_rcfw(struct bnxt_qplib_rcfw *rcfw,

skip_ctx_setup:
	req.stat_ctx_id = cpu_to_le32(ctx->stats.fw_id);
	resp = (struct creq_initialize_fw_resp *)
			bnxt_qplib_rcfw_send_message(rcfw, (void *)&req,
	rc = bnxt_qplib_rcfw_send_message(rcfw, (void *)&req, (void *)&resp,
					  NULL, 0);
	if (!resp) {
		dev_err(&rcfw->pdev->dev,
			"QPLIB: RCFW: INITIALIZE_FW send failed");
		return -EINVAL;
	}
	if (!bnxt_qplib_rcfw_wait_for_resp(rcfw, le16_to_cpu(req.cookie))) {
		/* Cmd timed out */
		dev_err(&rcfw->pdev->dev,
			"QPLIB: RCFW: INITIALIZE_FW timed out");
		return -ETIMEDOUT;
	}
	if (resp->status ||
	    le16_to_cpu(resp->cookie) != le16_to_cpu(req.cookie)) {
		dev_err(&rcfw->pdev->dev,
			"QPLIB: RCFW: INITIALIZE_FW failed");
		return -EINVAL;
	}
	if (rc)
		return rc;
	set_bit(FIRMWARE_INITIALIZED_FLAG, &rcfw->flags);
	return 0;
}

void bnxt_qplib_free_rcfw_channel(struct bnxt_qplib_rcfw *rcfw)
{
	bnxt_qplib_free_hwq(rcfw->pdev, &rcfw->crsb);
	kfree(rcfw->crsq.crsq);
	kfree(rcfw->crsqe_tbl);
	bnxt_qplib_free_hwq(rcfw->pdev, &rcfw->cmdq);
	bnxt_qplib_free_hwq(rcfw->pdev, &rcfw->creq);

	rcfw->pdev = NULL;
}

@@ -539,21 +536,11 @@ int bnxt_qplib_alloc_rcfw_channel(struct pci_dev *pdev,
		goto fail;
	}

	rcfw->crsq.max_elements = rcfw->cmdq.max_elements;
	rcfw->crsq.crsq = kcalloc(rcfw->crsq.max_elements,
				  sizeof(*rcfw->crsq.crsq), GFP_KERNEL);
	if (!rcfw->crsq.crsq)
	rcfw->crsqe_tbl = kcalloc(rcfw->cmdq.max_elements,
				  sizeof(*rcfw->crsqe_tbl), GFP_KERNEL);
	if (!rcfw->crsqe_tbl)
		goto fail;

	rcfw->crsb.max_elements = BNXT_QPLIB_CRSBE_MAX_CNT;
	if (bnxt_qplib_alloc_init_hwq(rcfw->pdev, &rcfw->crsb, NULL, 0,
				      &rcfw->crsb.max_elements,
				      BNXT_QPLIB_CRSBE_UNITS, 0, PAGE_SIZE,
				      HWQ_TYPE_CTX)) {
		dev_err(&rcfw->pdev->dev,
			"QPLIB: HW channel CRSB allocation failed");
		goto fail;
	}
	return 0;

fail:
@@ -606,7 +593,7 @@ int bnxt_qplib_enable_rcfw_channel(struct pci_dev *pdev,
	int rc;

	/* General */
	atomic_set(&rcfw->seq_num, 0);
	rcfw->seq_num = 0;
	rcfw->flags = FIRMWARE_FIRST_FLAG;
	bmap_size = BITS_TO_LONGS(RCFW_MAX_OUTSTANDING_CMD *
				  sizeof(unsigned long));
@@ -636,10 +623,6 @@ int bnxt_qplib_enable_rcfw_channel(struct pci_dev *pdev,

	rcfw->cmdq_bar_reg_trig_off = RCFW_COMM_TRIG_OFFSET;

	/* CRSQ */
	rcfw->crsq.prod = 0;
	rcfw->crsq.cons = 0;

	/* CREQ */
	rcfw->creq_bar_reg = RCFW_COMM_CONS_PCI_BAR_REGION;
	res_base = pci_resource_start(pdev, rcfw->creq_bar_reg);
@@ -692,3 +675,34 @@ int bnxt_qplib_enable_rcfw_channel(struct pci_dev *pdev,
	__iowrite32_copy(rcfw->cmdq_bar_reg_iomem, &init, sizeof(init) / 4);
	return 0;
}

struct bnxt_qplib_rcfw_sbuf *bnxt_qplib_rcfw_alloc_sbuf(
		struct bnxt_qplib_rcfw *rcfw,
		u32 size)
{
	struct bnxt_qplib_rcfw_sbuf *sbuf;

	sbuf = kzalloc(sizeof(*sbuf), GFP_ATOMIC);
	if (!sbuf)
		return NULL;

	sbuf->size = size;
	sbuf->sb = dma_zalloc_coherent(&rcfw->pdev->dev, sbuf->size,
				       &sbuf->dma_addr, GFP_ATOMIC);
	if (!sbuf->sb)
		goto bail;

	return sbuf;
bail:
	kfree(sbuf);
	return NULL;
}

void bnxt_qplib_rcfw_free_sbuf(struct bnxt_qplib_rcfw *rcfw,
			       struct bnxt_qplib_rcfw_sbuf *sbuf)
{
	if (sbuf->sb)
		dma_free_coherent(&rcfw->pdev->dev, sbuf->size,
				  sbuf->sb, sbuf->dma_addr);
	kfree(sbuf);
}
+20 −41

File changed.

Preview size limit exceeded, changes collapsed.

+5 −0
Original line number Diff line number Diff line
@@ -48,6 +48,11 @@ extern const struct bnxt_qplib_gid bnxt_qplib_gid_zero;

#define HWQ_CMP(idx, hwq)	((idx) & ((hwq)->max_elements - 1))

#define HWQ_FREE_SLOTS(hwq)	(hwq->max_elements - \
				((HWQ_CMP(hwq->prod, hwq)\
				- HWQ_CMP(hwq->cons, hwq))\
				& (hwq->max_elements - 1)))

enum bnxt_qplib_hwq_type {
	HWQ_TYPE_CTX,
	HWQ_TYPE_QUEUE,
+78 −250

File changed.

Preview size limit exceeded, changes collapsed.