All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH for-next 00/13] RDMA/bnxt_re: Misc fixes for bnxt_re
@ 2017-06-21 17:18 Selvin Xavier
       [not found] ` <1498065504-27902-1-git-send-email-selvin.xavier-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>
  0 siblings, 1 reply; 17+ messages in thread
From: Selvin Xavier @ 2017-06-21 17:18 UTC (permalink / raw)
  To: dledford-H+wXaHxf7aLQT0dZR+AlfA
  Cc: linux-rdma-u79uwXL29TY76Z2rM5mHXA, Selvin Xavier

This patch series includes the bug fixes for bnxt_re.

Patches 1 - 8 in this series are the backlog from the previously
submitted series -
https://www.spinics.net/lists/linux-rdma/msg50984.htm (6 out of the
the 14 patches from the above series got merged into 4.12-rc).
Theise patches are already reviewed by the community.

Patches 9-13 are new patches posted for review.

Doug,
Please review this and consider applying all 13 patches in the 4.13
merge cycle.

Thanks,
Selvin Xavier

Devesh Sharma (3):
  RDMA/bnxt_re: Free doorbell page index (DPI) during dealloc ucontext
  RDMA/bnxt_re: Enable atomics only if host bios supports
  RDMA/bnxt_re: Fix return value of poll routine

Eddie Wai (1):
  RDMA/bnxt_re: Fixed the max_rd_atomic support for initiator and
    destination QP

Kalesh AP (1):
  RDMA/bnxt_re: Add vlan tag for untagged RoCE traffic when PFC is
    configured

Selvin Xavier (5):
  RDMA/bnxt_re: Do not free the ctx_tbl entry if delete GID fails
  RDMA/bnxt_re: Report supported value to IB stack in query_device
  RDMA/bnxt_re: Allow posting when QPs are in error
  RDMA/bnxt_re: Report MISSED_EVENTS in req_notify_cq
  RDMA/bnxt_re: Fix the value reported for local ack delay

Somnath Kotur (3):
  RDMA/bnxt_re: Fix race between netdev register and unregister events
  RDMA/bnxt_re: Fix WQE Size posted to HW to prevent it from throwing
    error
  RDMA/bnxt_re: Specify RDMA component when allocating stats context

 drivers/infiniband/hw/bnxt_re/bnxt_re.h    |  22 +-
 drivers/infiniband/hw/bnxt_re/ib_verbs.c   | 158 ++++++-----
 drivers/infiniband/hw/bnxt_re/ib_verbs.h   |   3 +-
 drivers/infiniband/hw/bnxt_re/main.c       |  96 ++++++-
 drivers/infiniband/hw/bnxt_re/qplib_fp.c   | 440 +++++++++++++++++++++++------
 drivers/infiniband/hw/bnxt_re/qplib_fp.h   |  23 +-
 drivers/infiniband/hw/bnxt_re/qplib_rcfw.c |  10 +-
 drivers/infiniband/hw/bnxt_re/qplib_rcfw.h |  10 +-
 drivers/infiniband/hw/bnxt_re/qplib_res.c  |  10 +
 drivers/infiniband/hw/bnxt_re/qplib_res.h  |   2 +
 drivers/infiniband/hw/bnxt_re/qplib_sp.c   |  93 ++++--
 drivers/infiniband/hw/bnxt_re/qplib_sp.h   |   5 +
 drivers/infiniband/hw/bnxt_re/roce_hsi.h   |   4 +-
 13 files changed, 687 insertions(+), 189 deletions(-)

-- 
2.5.5

--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 17+ messages in thread

* [PATCH for-next 01/13] RDMA/bnxt_re: Fix race between netdev register and unregister events
       [not found] ` <1498065504-27902-1-git-send-email-selvin.xavier-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>
@ 2017-06-21 17:18   ` Selvin Xavier
  2017-06-21 17:18   ` [PATCH for-next 02/13] RDMA/bnxt_re: Free doorbell page index (DPI) during dealloc ucontext Selvin Xavier
                     ` (11 subsequent siblings)
  12 siblings, 0 replies; 17+ messages in thread
From: Selvin Xavier @ 2017-06-21 17:18 UTC (permalink / raw)
  To: dledford-H+wXaHxf7aLQT0dZR+AlfA
  Cc: linux-rdma-u79uwXL29TY76Z2rM5mHXA, Somnath Kotur,
	Sriharsha Basavapatna, Selvin Xavier

From: Somnath Kotur <somnath.kotur-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>

Upon receipt of the NETDEV_REGISTER event from the netdev notifier
chain, the IB stack registration is spawned off to a workqueue
since that also requires an rtnl lock.
There could be 2 kinds of races between the NETDEV_REGISTER and the
NETDEV_UNREGISTER event handling.
a)The NETDEV_UNREGISTER event is received in rapid succession after
the NETDEV_REGISTER event even before the work queue got a chance
to run
b)The NETDEV_UNREGISTER event is received while the workqueue that
handles registration with the IB stack is still in progress.
Handle both the races with a bit flag that is set as part of the
NETDEV_REGISTER event just before the work item is queued and cleared
in the workqueue after the registration with the IB stack is complete.
Use a barrier to ensure the bit is cleared only after the IB stack
registration code is completed.

Removes the link speed query from the query_port as it causes
deadlock while trying to acquire rtnl_lock. Now querying the
speed from the nedev event itself.

Also, added a code to wait for resources(like CQ) to be freed by the
ULPs, during driver unload

Signed-off-by: Somnath Kotur <somnath.kotur-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>
Signed-off-by: Sriharsha Basavapatna <sriharsha.basavapatna-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>
Signed-off-by: Selvin Xavier <selvin.xavier-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>
---
 drivers/infiniband/hw/bnxt_re/bnxt_re.h  | 13 +++++++----
 drivers/infiniband/hw/bnxt_re/ib_verbs.c | 21 +++--------------
 drivers/infiniband/hw/bnxt_re/main.c     | 39 ++++++++++++++++++++++++++++++++
 3 files changed, 50 insertions(+), 23 deletions(-)

diff --git a/drivers/infiniband/hw/bnxt_re/bnxt_re.h b/drivers/infiniband/hw/bnxt_re/bnxt_re.h
index 0877283..12950ec 100644
--- a/drivers/infiniband/hw/bnxt_re/bnxt_re.h
+++ b/drivers/infiniband/hw/bnxt_re/bnxt_re.h
@@ -84,11 +84,13 @@ struct bnxt_re_dev {
 	struct ib_device		ibdev;
 	struct list_head		list;
 	unsigned long			flags;
-#define BNXT_RE_FLAG_NETDEV_REGISTERED	0
-#define BNXT_RE_FLAG_IBDEV_REGISTERED	1
-#define BNXT_RE_FLAG_GOT_MSIX		2
-#define BNXT_RE_FLAG_RCFW_CHANNEL_EN	8
-#define BNXT_RE_FLAG_QOS_WORK_REG	16
+#define BNXT_RE_FLAG_NETDEV_REGISTERED         0
+#define BNXT_RE_FLAG_IBDEV_REGISTERED          1
+#define BNXT_RE_FLAG_GOT_MSIX                  2
+#define BNXT_RE_FLAG_RCFW_CHANNEL_EN           4
+#define BNXT_RE_FLAG_QOS_WORK_REG              5
+#define BNXT_RE_FLAG_NETDEV_REG_IN_PROG        6
+
 	struct net_device		*netdev;
 	unsigned int			version, major, minor;
 	struct bnxt_en_dev		*en_dev;
@@ -131,6 +133,7 @@ struct bnxt_re_dev {
 	struct bnxt_re_qp		*qp1_sqp;
 	struct bnxt_re_ah		*sqp_ah;
 	struct bnxt_re_sqp_entries sqp_tbl[1024];
+	u32 espeed;
 };
 
 #define to_bnxt_re_dev(ptr, member)	\
diff --git a/drivers/infiniband/hw/bnxt_re/ib_verbs.c b/drivers/infiniband/hw/bnxt_re/ib_verbs.c
index c7bd683..fa388f2 100644
--- a/drivers/infiniband/hw/bnxt_re/ib_verbs.c
+++ b/drivers/infiniband/hw/bnxt_re/ib_verbs.c
@@ -223,20 +223,8 @@ int bnxt_re_modify_device(struct ib_device *ibdev,
 	return 0;
 }
 
-static void __to_ib_speed_width(struct net_device *netdev, u8 *speed, u8 *width)
+static void __to_ib_speed_width(u32 espeed, u8 *speed, u8 *width)
 {
-	struct ethtool_link_ksettings lksettings;
-	u32 espeed;
-
-	if (netdev->ethtool_ops && netdev->ethtool_ops->get_link_ksettings) {
-		memset(&lksettings, 0, sizeof(lksettings));
-		rtnl_lock();
-		netdev->ethtool_ops->get_link_ksettings(netdev, &lksettings);
-		rtnl_unlock();
-		espeed = lksettings.base.speed;
-	} else {
-		espeed = SPEED_UNKNOWN;
-	}
 	switch (espeed) {
 	case SPEED_1000:
 		*speed = IB_SPEED_SDR;
@@ -303,12 +291,9 @@ int bnxt_re_query_port(struct ib_device *ibdev, u8 port_num,
 	port_attr->sm_sl = 0;
 	port_attr->subnet_timeout = 0;
 	port_attr->init_type_reply = 0;
-	/* call the underlying netdev's ethtool hooks to query speed settings
-	 * for which we acquire rtnl_lock _only_ if it's registered with
-	 * IB stack to avoid race in the NETDEV_UNREG path
-	 */
+
 	if (test_bit(BNXT_RE_FLAG_IBDEV_REGISTERED, &rdev->flags))
-		__to_ib_speed_width(rdev->netdev, &port_attr->active_speed,
+		__to_ib_speed_width(rdev->espeed, &port_attr->active_speed,
 				    &port_attr->active_width);
 	return 0;
 }
diff --git a/drivers/infiniband/hw/bnxt_re/main.c b/drivers/infiniband/hw/bnxt_re/main.c
index 1fce5e7..91b5208 100644
--- a/drivers/infiniband/hw/bnxt_re/main.c
+++ b/drivers/infiniband/hw/bnxt_re/main.c
@@ -48,6 +48,8 @@
 #include <net/ipv6.h>
 #include <net/addrconf.h>
 #include <linux/if_ether.h>
+#include <linux/atomic.h>
+#include <asm/barrier.h>
 
 #include <rdma/ib_verbs.h>
 #include <rdma/ib_user_verbs.h>
@@ -922,6 +924,10 @@ static void bnxt_re_ib_unreg(struct bnxt_re_dev *rdev, bool lock_wait)
 	if (test_and_clear_bit(BNXT_RE_FLAG_QOS_WORK_REG, &rdev->flags))
 		cancel_delayed_work(&rdev->worker);
 
+	/* Wait for ULPs to release references */
+	while (atomic_read(&rdev->cq_count))
+		usleep_range(500, 1000);
+
 	bnxt_re_cleanup_res(rdev);
 	bnxt_re_free_res(rdev, lock_wait);
 
@@ -1148,6 +1154,22 @@ static void bnxt_re_remove_one(struct bnxt_re_dev *rdev)
 	pci_dev_put(rdev->en_dev->pdev);
 }
 
+static void bnxt_re_get_link_speed(struct bnxt_re_dev *rdev)
+{
+	struct ethtool_link_ksettings lksettings;
+	struct net_device *netdev = rdev->netdev;
+
+	if (netdev->ethtool_ops && netdev->ethtool_ops->get_link_ksettings) {
+		memset(&lksettings, 0, sizeof(lksettings));
+		if (rtnl_trylock()) {
+			netdev->ethtool_ops->get_link_ksettings(netdev,
+								&lksettings);
+			rdev->espeed = lksettings.base.speed;
+			rtnl_unlock();
+		}
+	}
+}
+
 /* Handle all deferred netevents tasks */
 static void bnxt_re_task(struct work_struct *work)
 {
@@ -1165,6 +1187,10 @@ static void bnxt_re_task(struct work_struct *work)
 	switch (re_work->event) {
 	case NETDEV_REGISTER:
 		rc = bnxt_re_ib_reg(rdev);
+		/* Use memory barrier to sync the rdev->flags */
+		smp_mb();
+		clear_bit(BNXT_RE_FLAG_NETDEV_REG_IN_PROG,
+			  &rdev->flags);
 		if (rc)
 			dev_err(rdev_to_dev(rdev),
 				"Failed to register with IB: %#x", rc);
@@ -1182,6 +1208,7 @@ static void bnxt_re_task(struct work_struct *work)
 		else if (netif_carrier_ok(rdev->netdev))
 			bnxt_re_dispatch_event(&rdev->ibdev, NULL, 1,
 					       IB_EVENT_PORT_ACTIVE);
+		bnxt_re_get_link_speed(rdev);
 		break;
 	default:
 		break;
@@ -1240,10 +1267,22 @@ static int bnxt_re_netdev_event(struct notifier_block *notifier,
 			break;
 		}
 		bnxt_re_init_one(rdev);
+		/*
+		 *  Query the link speed at the time of registration.
+		 *  Already in rtnl_lock context
+		 */
+		bnxt_re_get_link_speed(rdev);
+
+		set_bit(BNXT_RE_FLAG_NETDEV_REG_IN_PROG, &rdev->flags);
 		sch_work = true;
 		break;
 
 	case NETDEV_UNREGISTER:
+		/* netdev notifier will call NETDEV_UNREGISTER again later since
+		 * we are still holding the reference to the netdev
+		 */
+		if (test_bit(BNXT_RE_FLAG_NETDEV_REG_IN_PROG, &rdev->flags))
+			goto exit;
 		bnxt_re_ib_unreg(rdev, false);
 		bnxt_re_remove_one(rdev);
 		bnxt_re_dev_unreg(rdev);
-- 
2.5.5

--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH for-next 02/13] RDMA/bnxt_re: Free doorbell page index (DPI) during dealloc ucontext
       [not found] ` <1498065504-27902-1-git-send-email-selvin.xavier-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>
  2017-06-21 17:18   ` [PATCH for-next 01/13] RDMA/bnxt_re: Fix race between netdev register and unregister events Selvin Xavier
@ 2017-06-21 17:18   ` Selvin Xavier
  2017-06-21 17:18   ` [PATCH for-next 03/13] RDMA/bnxt_re: Fix WQE Size posted to HW to prevent it from throwing error Selvin Xavier
                     ` (10 subsequent siblings)
  12 siblings, 0 replies; 17+ messages in thread
From: Selvin Xavier @ 2017-06-21 17:18 UTC (permalink / raw)
  To: dledford-H+wXaHxf7aLQT0dZR+AlfA
  Cc: linux-rdma-u79uwXL29TY76Z2rM5mHXA, Devesh Sharma, Selvin Xavier

From: Devesh Sharma <devesh.sharma-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>

The driver must free the DPI during the dealloc_ucontext
instead of freeing it during dealloc_pd. However, the DPI
allocation scheme remains unchanged.

Signed-off-by: Devesh Sharma <devesh.sharma-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>
Signed-off-by: Selvin Xavier <selvin.xavier-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>
---
 drivers/infiniband/hw/bnxt_re/ib_verbs.c | 58 ++++++++++++++++----------------
 drivers/infiniband/hw/bnxt_re/ib_verbs.h |  3 +-
 2 files changed, 30 insertions(+), 31 deletions(-)

diff --git a/drivers/infiniband/hw/bnxt_re/ib_verbs.c b/drivers/infiniband/hw/bnxt_re/ib_verbs.c
index fa388f2..2fa5967 100644
--- a/drivers/infiniband/hw/bnxt_re/ib_verbs.c
+++ b/drivers/infiniband/hw/bnxt_re/ib_verbs.c
@@ -597,30 +597,13 @@ int bnxt_re_dealloc_pd(struct ib_pd *ib_pd)
 	int rc;
 
 	bnxt_re_destroy_fence_mr(pd);
-	if (ib_pd->uobject && pd->dpi.dbr) {
-		struct ib_ucontext *ib_uctx = ib_pd->uobject->context;
-		struct bnxt_re_ucontext *ucntx;
 
-		/* Free DPI only if this is the first PD allocated by the
-		 * application and mark the context dpi as NULL
-		 */
-		ucntx = container_of(ib_uctx, struct bnxt_re_ucontext, ib_uctx);
-
-		rc = bnxt_qplib_dealloc_dpi(&rdev->qplib_res,
-					    &rdev->qplib_res.dpi_tbl,
-					    &pd->dpi);
+	if (pd->qplib_pd.id) {
+		rc = bnxt_qplib_dealloc_pd(&rdev->qplib_res,
+					   &rdev->qplib_res.pd_tbl,
+					   &pd->qplib_pd);
 		if (rc)
-			dev_err(rdev_to_dev(rdev), "Failed to deallocate HW DPI");
-			/* Don't fail, continue*/
-		ucntx->dpi = NULL;
-	}
-
-	rc = bnxt_qplib_dealloc_pd(&rdev->qplib_res,
-				   &rdev->qplib_res.pd_tbl,
-				   &pd->qplib_pd);
-	if (rc) {
-		dev_err(rdev_to_dev(rdev), "Failed to deallocate HW PD");
-		return rc;
+			dev_err(rdev_to_dev(rdev), "Failed to deallocate HW PD");
 	}
 
 	kfree(pd);
@@ -652,23 +635,22 @@ struct ib_pd *bnxt_re_alloc_pd(struct ib_device *ibdev,
 	if (udata) {
 		struct bnxt_re_pd_resp resp;
 
-		if (!ucntx->dpi) {
+		if (!ucntx->dpi.dbr) {
 			/* Allocate DPI in alloc_pd to avoid failing of
 			 * ibv_devinfo and family of application when DPIs
 			 * are depleted.
 			 */
 			if (bnxt_qplib_alloc_dpi(&rdev->qplib_res.dpi_tbl,
-						 &pd->dpi, ucntx)) {
+						 &ucntx->dpi, ucntx)) {
 				rc = -ENOMEM;
 				goto dbfail;
 			}
-			ucntx->dpi = &pd->dpi;
 		}
 
 		resp.pdid = pd->qplib_pd.id;
 		/* Still allow mapping this DBR to the new user PD. */
-		resp.dpi = ucntx->dpi->dpi;
-		resp.dbr = (u64)ucntx->dpi->umdbr;
+		resp.dpi = ucntx->dpi.dpi;
+		resp.dbr = (u64)ucntx->dpi.umdbr;
 
 		rc = ib_copy_to_udata(udata, &resp, sizeof(resp));
 		if (rc) {
@@ -945,7 +927,7 @@ static int bnxt_re_init_user_qp(struct bnxt_re_dev *rdev, struct bnxt_re_pd *pd,
 		qplib_qp->rq.nmap = umem->nmap;
 	}
 
-	qplib_qp->dpi = cntx->dpi;
+	qplib_qp->dpi = &cntx->dpi;
 	return 0;
 rqfail:
 	ib_umem_release(qp->sumem);
@@ -2388,7 +2370,7 @@ struct ib_cq *bnxt_re_create_cq(struct ib_device *ibdev,
 		}
 		cq->qplib_cq.sghead = cq->umem->sg_head.sgl;
 		cq->qplib_cq.nmap = cq->umem->nmap;
-		cq->qplib_cq.dpi = uctx->dpi;
+		cq->qplib_cq.dpi = &uctx->dpi;
 	} else {
 		cq->max_cql = min_t(u32, entries, MAX_CQL_PER_POLL);
 		cq->cql = kcalloc(cq->max_cql, sizeof(struct bnxt_qplib_cqe),
@@ -3373,8 +3355,26 @@ int bnxt_re_dealloc_ucontext(struct ib_ucontext *ib_uctx)
 	struct bnxt_re_ucontext *uctx = container_of(ib_uctx,
 						   struct bnxt_re_ucontext,
 						   ib_uctx);
+
+	struct bnxt_re_dev *rdev = uctx->rdev;
+	int rc = 0;
+
 	if (uctx->shpg)
 		free_page((unsigned long)uctx->shpg);
+
+	if (uctx->dpi.dbr) {
+		/* Free DPI only if this is the first PD allocated by the
+		 * application and mark the context dpi as NULL
+		 */
+		rc = bnxt_qplib_dealloc_dpi(&rdev->qplib_res,
+					    &rdev->qplib_res.dpi_tbl,
+					    &uctx->dpi);
+		if (rc)
+			dev_err(rdev_to_dev(rdev), "Deallocte HW DPI failed!");
+			/* Don't fail, continue*/
+		uctx->dpi.dbr = NULL;
+	}
+
 	kfree(uctx);
 	return 0;
 }
diff --git a/drivers/infiniband/hw/bnxt_re/ib_verbs.h b/drivers/infiniband/hw/bnxt_re/ib_verbs.h
index 6c160f6..a0bb7e3 100644
--- a/drivers/infiniband/hw/bnxt_re/ib_verbs.h
+++ b/drivers/infiniband/hw/bnxt_re/ib_verbs.h
@@ -59,7 +59,6 @@ struct bnxt_re_pd {
 	struct bnxt_re_dev	*rdev;
 	struct ib_pd		ib_pd;
 	struct bnxt_qplib_pd	qplib_pd;
-	struct bnxt_qplib_dpi	dpi;
 	struct bnxt_re_fence_data fence;
 };
 
@@ -127,7 +126,7 @@ struct bnxt_re_mw {
 struct bnxt_re_ucontext {
 	struct bnxt_re_dev	*rdev;
 	struct ib_ucontext	ib_uctx;
-	struct bnxt_qplib_dpi	*dpi;
+	struct bnxt_qplib_dpi	dpi;
 	void			*shpg;
 	spinlock_t		sh_lock;	/* protect shpg */
 };
-- 
2.5.5

--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH for-next 03/13] RDMA/bnxt_re: Fix WQE Size posted to HW to prevent it from throwing error
       [not found] ` <1498065504-27902-1-git-send-email-selvin.xavier-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>
  2017-06-21 17:18   ` [PATCH for-next 01/13] RDMA/bnxt_re: Fix race between netdev register and unregister events Selvin Xavier
  2017-06-21 17:18   ` [PATCH for-next 02/13] RDMA/bnxt_re: Free doorbell page index (DPI) during dealloc ucontext Selvin Xavier
@ 2017-06-21 17:18   ` Selvin Xavier
  2017-06-21 17:18   ` [PATCH for-next 04/13] RDMA/bnxt_re: Add vlan tag for untagged RoCE traffic when PFC is configured Selvin Xavier
                     ` (9 subsequent siblings)
  12 siblings, 0 replies; 17+ messages in thread
From: Selvin Xavier @ 2017-06-21 17:18 UTC (permalink / raw)
  To: dledford-H+wXaHxf7aLQT0dZR+AlfA
  Cc: linux-rdma-u79uwXL29TY76Z2rM5mHXA, Somnath Kotur, Selvin Xavier

From: Somnath Kotur <somnath.kotur-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>

Posting WQE size of 2 results in a WQE_FORMAT_ERROR
thrown by the HW as it requires host to supply WQE Size with room
for atleast one SGE so that the resulting WQE size be atleast 3.

Signed-off-by: Somnath Kotur <somnath.kotur-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>
Signed-off-by: Selvin Xavier <selvin.xavier-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>
---
 drivers/infiniband/hw/bnxt_re/qplib_fp.c | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/drivers/infiniband/hw/bnxt_re/qplib_fp.c b/drivers/infiniband/hw/bnxt_re/qplib_fp.c
index f05500bc..8ef39df 100644
--- a/drivers/infiniband/hw/bnxt_re/qplib_fp.c
+++ b/drivers/infiniband/hw/bnxt_re/qplib_fp.c
@@ -1128,6 +1128,11 @@ int bnxt_qplib_post_send(struct bnxt_qplib_qp *qp,
 		}
 		/* Each SGE entry = 1 WQE size16 */
 		wqe_size16 = wqe->num_sge;
+		/* HW requires wqe size has room for atleast one SGE even if
+		 * none was supplied by ULP
+		 */
+		if (!wqe->num_sge)
+			wqe_size16++;
 	}
 
 	/* Specifics */
@@ -1364,6 +1369,11 @@ int bnxt_qplib_post_recv(struct bnxt_qplib_qp *qp,
 	rqe->flags = wqe->flags;
 	rqe->wqe_size = wqe->num_sge +
 			((offsetof(typeof(*rqe), data) + 15) >> 4);
+	/* HW requires wqe size has room for atleast one SGE even if none
+	 * was supplied by ULP
+	 */
+	if (!wqe->num_sge)
+		rqe->wqe_size++;
 
 	/* Supply the rqe->wr_id index to the wr_id_tbl for now */
 	rqe->wr_id[0] = cpu_to_le32(sw_prod);
-- 
2.5.5

--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH for-next 04/13] RDMA/bnxt_re: Add vlan tag for untagged RoCE traffic when PFC is configured
       [not found] ` <1498065504-27902-1-git-send-email-selvin.xavier-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>
                     ` (2 preceding siblings ...)
  2017-06-21 17:18   ` [PATCH for-next 03/13] RDMA/bnxt_re: Fix WQE Size posted to HW to prevent it from throwing error Selvin Xavier
@ 2017-06-21 17:18   ` Selvin Xavier
  2017-06-21 17:18   ` [PATCH for-next 05/13] RDMA/bnxt_re: Do not free the ctx_tbl entry if delete GID fails Selvin Xavier
                     ` (8 subsequent siblings)
  12 siblings, 0 replies; 17+ messages in thread
From: Selvin Xavier @ 2017-06-21 17:18 UTC (permalink / raw)
  To: dledford-H+wXaHxf7aLQT0dZR+AlfA
  Cc: linux-rdma-u79uwXL29TY76Z2rM5mHXA, Kalesh AP, Selvin Xavier

From: Kalesh AP <kalesh-anakkur.purayil-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>

Current implementation does not program vlan header insertion
in RoCE packet if no vlan is configured. Firmware does not add
prority when there is no vlan tag in the packet. Modify the code
to insert vlan header when PFC is enabled on the interface.

Signed-off-by: Kalesh AP <kalesh-anakkur.purayil-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>
Signed-off-by: Selvin Xavier <selvin.xavier-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>
Reviewed-by: Leon Romanovsky <leonro-VPRAkNaXOzVWk0Htik3J/w@public.gmane.org>
---
 drivers/infiniband/hw/bnxt_re/main.c      | 53 ++++++++++++++++++---
 drivers/infiniband/hw/bnxt_re/qplib_res.c | 10 ++++
 drivers/infiniband/hw/bnxt_re/qplib_res.h |  2 +
 drivers/infiniband/hw/bnxt_re/qplib_sp.c  | 77 ++++++++++++++++++++++++-------
 drivers/infiniband/hw/bnxt_re/qplib_sp.h  |  2 +
 drivers/infiniband/hw/bnxt_re/roce_hsi.h  |  4 +-
 6 files changed, 124 insertions(+), 24 deletions(-)

diff --git a/drivers/infiniband/hw/bnxt_re/main.c b/drivers/infiniband/hw/bnxt_re/main.c
index 91b5208..df4d1df 100644
--- a/drivers/infiniband/hw/bnxt_re/main.c
+++ b/drivers/infiniband/hw/bnxt_re/main.c
@@ -836,6 +836,42 @@ static void bnxt_re_dev_stop(struct bnxt_re_dev *rdev)
 	mutex_unlock(&rdev->qp_lock);
 }
 
+static int bnxt_re_update_gid(struct bnxt_re_dev *rdev)
+{
+	struct bnxt_qplib_sgid_tbl *sgid_tbl = &rdev->qplib_res.sgid_tbl;
+	struct bnxt_qplib_gid gid;
+	u16 gid_idx, index;
+	int rc = 0;
+
+	if (!test_bit(BNXT_RE_FLAG_IBDEV_REGISTERED, &rdev->flags))
+		return 0;
+
+	if (!sgid_tbl) {
+		dev_err(rdev_to_dev(rdev), "QPLIB: SGID table not allocated");
+		return -EINVAL;
+	}
+
+	for (index = 0; index < sgid_tbl->active; index++) {
+		gid_idx = sgid_tbl->hw_id[index];
+
+		if (!memcmp(&sgid_tbl->tbl[index], &bnxt_qplib_gid_zero,
+			    sizeof(bnxt_qplib_gid_zero)))
+			continue;
+		/* need to modify the VLAN enable setting of non VLAN GID only
+		 * as setting is done for VLAN GID while adding GID
+		 */
+		if (sgid_tbl->vlan[index])
+			continue;
+
+		memcpy(&gid, &sgid_tbl->tbl[index], sizeof(gid));
+
+		rc = bnxt_qplib_update_sgid(sgid_tbl, &gid, gid_idx,
+					    rdev->qplib_res.netdev->dev_addr);
+	}
+
+	return rc;
+}
+
 static u32 bnxt_re_get_priority_mask(struct bnxt_re_dev *rdev)
 {
 	u32 prio_map = 0, tmp_map = 0;
@@ -855,8 +891,6 @@ static u32 bnxt_re_get_priority_mask(struct bnxt_re_dev *rdev)
 	tmp_map = dcb_ieee_getapp_mask(netdev, &app);
 	prio_map |= tmp_map;
 
-	if (!prio_map)
-		prio_map = -EFAULT;
 	return prio_map;
 }
 
@@ -882,10 +916,7 @@ static int bnxt_re_setup_qos(struct bnxt_re_dev *rdev)
 	int rc;
 
 	/* Get priority for roce */
-	rc = bnxt_re_get_priority_mask(rdev);
-	if (rc < 0)
-		return rc;
-	prio_map = (u8)rc;
+	prio_map = bnxt_re_get_priority_mask(rdev);
 
 	if (prio_map == rdev->cur_prio_map)
 		return 0;
@@ -907,6 +938,16 @@ static int bnxt_re_setup_qos(struct bnxt_re_dev *rdev)
 		return rc;
 	}
 
+	/* Actual priorities are not programmed as they are already
+	 * done by L2 driver; just enable or disable priority vlan tagging
+	 */
+	if ((prio_map == 0 && rdev->qplib_res.prio) ||
+	    (prio_map != 0 && !rdev->qplib_res.prio)) {
+		rdev->qplib_res.prio = prio_map ? true : false;
+
+		bnxt_re_update_gid(rdev);
+	}
+
 	return 0;
 }
 
diff --git a/drivers/infiniband/hw/bnxt_re/qplib_res.c b/drivers/infiniband/hw/bnxt_re/qplib_res.c
index 62447b3..4e10170 100644
--- a/drivers/infiniband/hw/bnxt_re/qplib_res.c
+++ b/drivers/infiniband/hw/bnxt_re/qplib_res.c
@@ -468,9 +468,11 @@ static void bnxt_qplib_free_sgid_tbl(struct bnxt_qplib_res *res,
 	kfree(sgid_tbl->tbl);
 	kfree(sgid_tbl->hw_id);
 	kfree(sgid_tbl->ctx);
+	kfree(sgid_tbl->vlan);
 	sgid_tbl->tbl = NULL;
 	sgid_tbl->hw_id = NULL;
 	sgid_tbl->ctx = NULL;
+	sgid_tbl->vlan = NULL;
 	sgid_tbl->max = 0;
 	sgid_tbl->active = 0;
 }
@@ -491,8 +493,15 @@ static int bnxt_qplib_alloc_sgid_tbl(struct bnxt_qplib_res *res,
 	if (!sgid_tbl->ctx)
 		goto out_free2;
 
+	sgid_tbl->vlan = kcalloc(max, sizeof(u8), GFP_KERNEL);
+	if (!sgid_tbl->vlan)
+		goto out_free3;
+
 	sgid_tbl->max = max;
 	return 0;
+out_free3:
+	kfree(sgid_tbl->ctx);
+	sgid_tbl->ctx = NULL;
 out_free2:
 	kfree(sgid_tbl->hw_id);
 	sgid_tbl->hw_id = NULL;
@@ -514,6 +523,7 @@ static void bnxt_qplib_cleanup_sgid_tbl(struct bnxt_qplib_res *res,
 	}
 	memset(sgid_tbl->tbl, 0, sizeof(struct bnxt_qplib_gid) * sgid_tbl->max);
 	memset(sgid_tbl->hw_id, -1, sizeof(u16) * sgid_tbl->max);
+	memset(sgid_tbl->vlan, 0, sizeof(u8) * sgid_tbl->max);
 	sgid_tbl->active = 0;
 }
 
diff --git a/drivers/infiniband/hw/bnxt_re/qplib_res.h b/drivers/infiniband/hw/bnxt_re/qplib_res.h
index 2e48555..e872075 100644
--- a/drivers/infiniband/hw/bnxt_re/qplib_res.h
+++ b/drivers/infiniband/hw/bnxt_re/qplib_res.h
@@ -116,6 +116,7 @@ struct bnxt_qplib_sgid_tbl {
 	u16				max;
 	u16				active;
 	void				*ctx;
+	u8				*vlan;
 };
 
 struct bnxt_qplib_pkey_tbl {
@@ -188,6 +189,7 @@ struct bnxt_qplib_res {
 	struct bnxt_qplib_sgid_tbl	sgid_tbl;
 	struct bnxt_qplib_pkey_tbl	pkey_tbl;
 	struct bnxt_qplib_dpi_tbl	dpi_tbl;
+	bool				prio;
 };
 
 #define to_bnxt_qplib(ptr, type, member)	\
diff --git a/drivers/infiniband/hw/bnxt_re/qplib_sp.c b/drivers/infiniband/hw/bnxt_re/qplib_sp.c
index fde18cf..5a633b4 100644
--- a/drivers/infiniband/hw/bnxt_re/qplib_sp.c
+++ b/drivers/infiniband/hw/bnxt_re/qplib_sp.c
@@ -197,6 +197,7 @@ int bnxt_qplib_del_sgid(struct bnxt_qplib_sgid_tbl *sgid_tbl,
 	}
 	memcpy(&sgid_tbl->tbl[index], &bnxt_qplib_gid_zero,
 	       sizeof(bnxt_qplib_gid_zero));
+	sgid_tbl->vlan[index] = 0;
 	sgid_tbl->active--;
 	dev_dbg(&res->pdev->dev,
 		"QPLIB: SGID deleted hw_id[0x%x] = 0x%x active = 0x%x",
@@ -249,28 +250,32 @@ int bnxt_qplib_add_sgid(struct bnxt_qplib_sgid_tbl *sgid_tbl,
 		struct cmdq_add_gid req;
 		struct creq_add_gid_resp resp;
 		u16 cmd_flags = 0;
-		u32 temp32[4];
-		u16 temp16[3];
 		int rc;
 
 		RCFW_CMD_PREP(req, ADD_GID, cmd_flags);
 
-		memcpy(temp32, gid->data, sizeof(struct bnxt_qplib_gid));
-		req.gid[0] = cpu_to_be32(temp32[3]);
-		req.gid[1] = cpu_to_be32(temp32[2]);
-		req.gid[2] = cpu_to_be32(temp32[1]);
-		req.gid[3] = cpu_to_be32(temp32[0]);
-		if (vlan_id != 0xFFFF)
-			req.vlan = cpu_to_le16((vlan_id &
-					CMDQ_ADD_GID_VLAN_VLAN_ID_MASK) |
-					CMDQ_ADD_GID_VLAN_TPID_TPID_8100 |
-					CMDQ_ADD_GID_VLAN_VLAN_EN);
+		req.gid[0] = cpu_to_be32(((u32 *)gid->data)[3]);
+		req.gid[1] = cpu_to_be32(((u32 *)gid->data)[2]);
+		req.gid[2] = cpu_to_be32(((u32 *)gid->data)[1]);
+		req.gid[3] = cpu_to_be32(((u32 *)gid->data)[0]);
+		/*
+		 * driver should ensure that all RoCE traffic is always VLAN
+		 * tagged if RoCE traffic is running on non-zero VLAN ID or
+		 * RoCE traffic is running on non-zero Priority.
+		 */
+		if ((vlan_id != 0xFFFF) || res->prio) {
+			if (vlan_id != 0xFFFF)
+				req.vlan = cpu_to_le16
+				(vlan_id & CMDQ_ADD_GID_VLAN_VLAN_ID_MASK);
+			req.vlan |= cpu_to_le16
+					(CMDQ_ADD_GID_VLAN_TPID_TPID_8100 |
+					 CMDQ_ADD_GID_VLAN_VLAN_EN);
+		}
 
 		/* MAC in network format */
-		memcpy(temp16, smac, 6);
-		req.src_mac[0] = cpu_to_be16(temp16[0]);
-		req.src_mac[1] = cpu_to_be16(temp16[1]);
-		req.src_mac[2] = cpu_to_be16(temp16[2]);
+		req.src_mac[0] = cpu_to_be16(((u16 *)smac)[0]);
+		req.src_mac[1] = cpu_to_be16(((u16 *)smac)[1]);
+		req.src_mac[2] = cpu_to_be16(((u16 *)smac)[2]);
 
 		rc = bnxt_qplib_rcfw_send_message(rcfw, (void *)&req,
 						  (void *)&resp, NULL, 0);
@@ -281,6 +286,9 @@ int bnxt_qplib_add_sgid(struct bnxt_qplib_sgid_tbl *sgid_tbl,
 	/* Add GID to the sgid_tbl */
 	memcpy(&sgid_tbl->tbl[free_idx], gid, sizeof(*gid));
 	sgid_tbl->active++;
+	if (vlan_id != 0xFFFF)
+		sgid_tbl->vlan[free_idx] = 1;
+
 	dev_dbg(&res->pdev->dev,
 		"QPLIB: SGID added hw_id[0x%x] = 0x%x active = 0x%x",
 		 free_idx, sgid_tbl->hw_id[free_idx], sgid_tbl->active);
@@ -290,6 +298,43 @@ int bnxt_qplib_add_sgid(struct bnxt_qplib_sgid_tbl *sgid_tbl,
 	return 0;
 }
 
+int bnxt_qplib_update_sgid(struct bnxt_qplib_sgid_tbl *sgid_tbl,
+			   struct bnxt_qplib_gid *gid, u16 gid_idx,
+			   u8 *smac)
+{
+	struct bnxt_qplib_res *res = to_bnxt_qplib(sgid_tbl,
+						   struct bnxt_qplib_res,
+						   sgid_tbl);
+	struct bnxt_qplib_rcfw *rcfw = res->rcfw;
+	struct creq_modify_gid_resp resp;
+	struct cmdq_modify_gid req;
+	int rc;
+	u16 cmd_flags = 0;
+
+	RCFW_CMD_PREP(req, MODIFY_GID, cmd_flags);
+
+	req.gid[0] = cpu_to_be32(((u32 *)gid->data)[3]);
+	req.gid[1] = cpu_to_be32(((u32 *)gid->data)[2]);
+	req.gid[2] = cpu_to_be32(((u32 *)gid->data)[1]);
+	req.gid[3] = cpu_to_be32(((u32 *)gid->data)[0]);
+	if (res->prio) {
+		req.vlan |= cpu_to_le16
+			(CMDQ_ADD_GID_VLAN_TPID_TPID_8100 |
+			 CMDQ_ADD_GID_VLAN_VLAN_EN);
+	}
+
+	/* MAC in network format */
+	req.src_mac[0] = cpu_to_be16(((u16 *)smac)[0]);
+	req.src_mac[1] = cpu_to_be16(((u16 *)smac)[1]);
+	req.src_mac[2] = cpu_to_be16(((u16 *)smac)[2]);
+
+	req.gid_index = cpu_to_le16(gid_idx);
+
+	rc = bnxt_qplib_rcfw_send_message(rcfw, (void *)&req,
+					  (void *)&resp, NULL, 0);
+	return rc;
+}
+
 /* pkeys */
 int bnxt_qplib_get_pkey(struct bnxt_qplib_res *res,
 			struct bnxt_qplib_pkey_tbl *pkey_tbl, u16 index,
diff --git a/drivers/infiniband/hw/bnxt_re/qplib_sp.h b/drivers/infiniband/hw/bnxt_re/qplib_sp.h
index a543f95..e3a3ed9 100644
--- a/drivers/infiniband/hw/bnxt_re/qplib_sp.h
+++ b/drivers/infiniband/hw/bnxt_re/qplib_sp.h
@@ -132,6 +132,8 @@ int bnxt_qplib_del_sgid(struct bnxt_qplib_sgid_tbl *sgid_tbl,
 int bnxt_qplib_add_sgid(struct bnxt_qplib_sgid_tbl *sgid_tbl,
 			struct bnxt_qplib_gid *gid, u8 *mac, u16 vlan_id,
 			bool update, u32 *index);
+int bnxt_qplib_update_sgid(struct bnxt_qplib_sgid_tbl *sgid_tbl,
+			   struct bnxt_qplib_gid *gid, u16 gid_idx, u8 *smac);
 int bnxt_qplib_get_pkey(struct bnxt_qplib_res *res,
 			struct bnxt_qplib_pkey_tbl *pkey_tbl, u16 index,
 			u16 *pkey);
diff --git a/drivers/infiniband/hw/bnxt_re/roce_hsi.h b/drivers/infiniband/hw/bnxt_re/roce_hsi.h
index fc23477..eeb55b2 100644
--- a/drivers/infiniband/hw/bnxt_re/roce_hsi.h
+++ b/drivers/infiniband/hw/bnxt_re/roce_hsi.h
@@ -1473,8 +1473,8 @@ struct cmdq_modify_gid {
 	u8 resp_size;
 	u8 reserved8;
 	__le64 resp_addr;
-	__le32 gid[4];
-	__le16 src_mac[3];
+	__be32 gid[4];
+	__be16 src_mac[3];
 	__le16 vlan;
 	#define CMDQ_MODIFY_GID_VLAN_VLAN_ID_MASK		    0xfffUL
 	#define CMDQ_MODIFY_GID_VLAN_VLAN_ID_SFT		    0
-- 
2.5.5

--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH for-next 05/13] RDMA/bnxt_re: Do not free the ctx_tbl entry if delete GID fails
       [not found] ` <1498065504-27902-1-git-send-email-selvin.xavier-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>
                     ` (3 preceding siblings ...)
  2017-06-21 17:18   ` [PATCH for-next 04/13] RDMA/bnxt_re: Add vlan tag for untagged RoCE traffic when PFC is configured Selvin Xavier
@ 2017-06-21 17:18   ` Selvin Xavier
  2017-06-21 17:18   ` [PATCH for-next 06/13] RDMA/bnxt_re: Report supported value to IB stack in query_device Selvin Xavier
                     ` (7 subsequent siblings)
  12 siblings, 0 replies; 17+ messages in thread
From: Selvin Xavier @ 2017-06-21 17:18 UTC (permalink / raw)
  To: dledford-H+wXaHxf7aLQT0dZR+AlfA
  Cc: linux-rdma-u79uwXL29TY76Z2rM5mHXA, Selvin Xavier, Kalesh AP

This fix is added only to avoid system crash in some a
specific scenario. When bnxt_re driver is loaded and if
user tries to change interface mac address, delete GID
fails because QP1 is still associated with existing MAC
(default GID). If the above command fails GID tables are
not modified in the h/w or driver, but the GID context memory
is freed. Now, if the user changes the mac back to the original
value, another add_gid comes to the driver where the driver
reports that the GID is already present in its table
and tries to access the context which was already freed.

So, in this case, in order to  avoid NULL pointer de-reference,
this patch removes the context memory free  if delete_gid fails
and the same context memory is re-used in new add_gid.
Memory cleanup will be taken care during driver unload, while
deleting the GID table.

Signed-off-by: Kalesh AP <kalesh-anakkur.purayil-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>
Signed-off-by: Selvin Xavier <selvin.xavier-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>
---
 drivers/infiniband/hw/bnxt_re/ib_verbs.c | 16 +++++++++-------
 1 file changed, 9 insertions(+), 7 deletions(-)

diff --git a/drivers/infiniband/hw/bnxt_re/ib_verbs.c b/drivers/infiniband/hw/bnxt_re/ib_verbs.c
index 2fa5967..7c9685a 100644
--- a/drivers/infiniband/hw/bnxt_re/ib_verbs.c
+++ b/drivers/infiniband/hw/bnxt_re/ib_verbs.c
@@ -375,15 +375,17 @@ int bnxt_re_del_gid(struct ib_device *ibdev, u8 port_num,
 			return -EINVAL;
 		ctx->refcnt--;
 		if (!ctx->refcnt) {
-			rc = bnxt_qplib_del_sgid
-					(sgid_tbl,
-					 &sgid_tbl->tbl[ctx->idx], true);
-			if (rc)
+			rc = bnxt_qplib_del_sgid(sgid_tbl,
+						 &sgid_tbl->tbl[ctx->idx],
+						 true);
+			if (rc) {
 				dev_err(rdev_to_dev(rdev),
 					"Failed to remove GID: %#x", rc);
-			ctx_tbl = sgid_tbl->ctx;
-			ctx_tbl[ctx->idx] = NULL;
-			kfree(ctx);
+			} else {
+				ctx_tbl = sgid_tbl->ctx;
+				ctx_tbl[ctx->idx] = NULL;
+				kfree(ctx);
+			}
 		}
 	} else {
 		return -EINVAL;
-- 
2.5.5

--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH for-next 06/13] RDMA/bnxt_re: Report supported value to IB stack in query_device
       [not found] ` <1498065504-27902-1-git-send-email-selvin.xavier-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>
                     ` (4 preceding siblings ...)
  2017-06-21 17:18   ` [PATCH for-next 05/13] RDMA/bnxt_re: Do not free the ctx_tbl entry if delete GID fails Selvin Xavier
@ 2017-06-21 17:18   ` Selvin Xavier
  2017-06-21 17:18   ` [PATCH for-next 07/13] RDMA/bnxt_re: Fixed the max_rd_atomic support for initiator and destination QP Selvin Xavier
                     ` (6 subsequent siblings)
  12 siblings, 0 replies; 17+ messages in thread
From: Selvin Xavier @ 2017-06-21 17:18 UTC (permalink / raw)
  To: dledford-H+wXaHxf7aLQT0dZR+AlfA
  Cc: linux-rdma-u79uwXL29TY76Z2rM5mHXA, Selvin Xavier

 - Report supported value for max_mr_size to IB stack in query_device.
   Also, check and log if MR size requested by application in
   reg_user_mr() is greater than value currently supported by driver.
 - Report only 4K page size support for now
 - Fix Max_QP value returned by ibv_devinfo -vv.
   In case of PF, FW reserves 129 QPs for creating QP1s of VFs
   and PF. So the max_qp value reported by FW for PF doesn'tt include
   the QP1. Fixing this issue by adding 1 with the value reported
   by FW.

Signed-off-by: Selvin Xavier <selvin.xavier-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>
---
 drivers/infiniband/hw/bnxt_re/bnxt_re.h  |  2 ++
 drivers/infiniband/hw/bnxt_re/ib_verbs.c | 12 ++++++++----
 drivers/infiniband/hw/bnxt_re/qplib_sp.c |  2 ++
 3 files changed, 12 insertions(+), 4 deletions(-)

diff --git a/drivers/infiniband/hw/bnxt_re/bnxt_re.h b/drivers/infiniband/hw/bnxt_re/bnxt_re.h
index 12950ec..30bff05 100644
--- a/drivers/infiniband/hw/bnxt_re/bnxt_re.h
+++ b/drivers/infiniband/hw/bnxt_re/bnxt_re.h
@@ -51,6 +51,8 @@
 #define BNXT_RE_PAGE_SIZE_8M		BIT(23)
 #define BNXT_RE_PAGE_SIZE_1G		BIT(30)
 
+#define BNXT_RE_MAX_MR_SIZE		BIT(30)
+
 #define BNXT_RE_MAX_QPC_COUNT		(64 * 1024)
 #define BNXT_RE_MAX_MRW_COUNT		(64 * 1024)
 #define BNXT_RE_MAX_SRQC_COUNT		(64 * 1024)
diff --git a/drivers/infiniband/hw/bnxt_re/ib_verbs.c b/drivers/infiniband/hw/bnxt_re/ib_verbs.c
index 7c9685a..aa96b2c 100644
--- a/drivers/infiniband/hw/bnxt_re/ib_verbs.c
+++ b/drivers/infiniband/hw/bnxt_re/ib_verbs.c
@@ -145,10 +145,8 @@ int bnxt_re_query_device(struct ib_device *ibdev,
 	ib_attr->fw_ver = (u64)(unsigned long)(dev_attr->fw_ver);
 	bnxt_qplib_get_guid(rdev->netdev->dev_addr,
 			    (u8 *)&ib_attr->sys_image_guid);
-	ib_attr->max_mr_size = ~0ull;
-	ib_attr->page_size_cap = BNXT_RE_PAGE_SIZE_4K | BNXT_RE_PAGE_SIZE_8K |
-				 BNXT_RE_PAGE_SIZE_64K | BNXT_RE_PAGE_SIZE_2M |
-				 BNXT_RE_PAGE_SIZE_8M | BNXT_RE_PAGE_SIZE_1G;
+	ib_attr->max_mr_size = BNXT_RE_MAX_MR_SIZE;
+	ib_attr->page_size_cap = BNXT_RE_PAGE_SIZE_4K;
 
 	ib_attr->vendor_id = rdev->en_dev->pdev->vendor;
 	ib_attr->vendor_part_id = rdev->en_dev->pdev->device;
@@ -3214,6 +3212,12 @@ struct ib_mr *bnxt_re_reg_user_mr(struct ib_pd *ib_pd, u64 start, u64 length,
 	struct scatterlist *sg;
 	int entry;
 
+	if (length > BNXT_RE_MAX_MR_SIZE) {
+		dev_err(rdev_to_dev(rdev), "MR Size: %lld > Max supported:%ld\n",
+			length, BNXT_RE_MAX_MR_SIZE);
+		return ERR_PTR(-ENOMEM);
+	}
+
 	mr = kzalloc(sizeof(*mr), GFP_KERNEL);
 	if (!mr)
 		return ERR_PTR(-ENOMEM);
diff --git a/drivers/infiniband/hw/bnxt_re/qplib_sp.c b/drivers/infiniband/hw/bnxt_re/qplib_sp.c
index 5a633b4..33c04a0 100644
--- a/drivers/infiniband/hw/bnxt_re/qplib_sp.c
+++ b/drivers/infiniband/hw/bnxt_re/qplib_sp.c
@@ -81,6 +81,8 @@ int bnxt_qplib_get_dev_attr(struct bnxt_qplib_rcfw *rcfw,
 
 	/* Extract the context from the side buffer */
 	attr->max_qp = le32_to_cpu(sb->max_qp);
+	/* max_qp value reported by FW for PF doesn't include the QP1 for PF */
+	attr->max_qp += 1;
 	attr->max_qp_rd_atom =
 		sb->max_qp_rd_atom > BNXT_QPLIB_MAX_OUT_RD_ATOM ?
 		BNXT_QPLIB_MAX_OUT_RD_ATOM : sb->max_qp_rd_atom;
-- 
2.5.5

--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH for-next 07/13] RDMA/bnxt_re: Fixed the max_rd_atomic support for initiator and destination QP
       [not found] ` <1498065504-27902-1-git-send-email-selvin.xavier-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>
                     ` (5 preceding siblings ...)
  2017-06-21 17:18   ` [PATCH for-next 06/13] RDMA/bnxt_re: Report supported value to IB stack in query_device Selvin Xavier
@ 2017-06-21 17:18   ` Selvin Xavier
  2017-06-21 17:18   ` [PATCH for-next 08/13] RDMA/bnxt_re: Specify RDMA component when allocating stats context Selvin Xavier
                     ` (5 subsequent siblings)
  12 siblings, 0 replies; 17+ messages in thread
From: Selvin Xavier @ 2017-06-21 17:18 UTC (permalink / raw)
  To: dledford-H+wXaHxf7aLQT0dZR+AlfA
  Cc: linux-rdma-u79uwXL29TY76Z2rM5mHXA, Eddie Wai, Selvin Xavier

From: Eddie Wai <eddie.wai-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>

There's a couple of bugs in the support of max_rd_atomic and
max_dest_rd_atomic. In the modify_qp, if the requested max_rd_atomic,
which is the ORRQ size, is greater than what the chip can support,
then we have to cap the request to chip max as we can't have the HW
overflow the ORRQ. Capping the max_rd_atomic support internally is okay
to do as the remaining read/atomic WRs will still be sitting in the SQ.
However, for the max_dest_rd_atomic, the driver has to error out as
this dictates the IRRQ size and we can't control what the remote
side sends.

Signed-off-by: Eddie Wai <eddie.wai-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>
Signed-off-by: Selvin Xavier <selvin.xavier-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>
---
 drivers/infiniband/hw/bnxt_re/ib_verbs.c | 15 +++++++++++++--
 1 file changed, 13 insertions(+), 2 deletions(-)

diff --git a/drivers/infiniband/hw/bnxt_re/ib_verbs.c b/drivers/infiniband/hw/bnxt_re/ib_verbs.c
index aa96b2c..6629727 100644
--- a/drivers/infiniband/hw/bnxt_re/ib_verbs.c
+++ b/drivers/infiniband/hw/bnxt_re/ib_verbs.c
@@ -172,7 +172,7 @@ int bnxt_re_query_device(struct ib_device *ibdev,
 	ib_attr->max_mr = dev_attr->max_mr;
 	ib_attr->max_pd = dev_attr->max_pd;
 	ib_attr->max_qp_rd_atom = dev_attr->max_qp_rd_atom;
-	ib_attr->max_qp_init_rd_atom = dev_attr->max_qp_rd_atom;
+	ib_attr->max_qp_init_rd_atom = dev_attr->max_qp_init_rd_atom;
 	ib_attr->atomic_cap = IB_ATOMIC_HCA;
 	ib_attr->masked_atomic_cap = IB_ATOMIC_HCA;
 
@@ -1497,13 +1497,24 @@ int bnxt_re_modify_qp(struct ib_qp *ib_qp, struct ib_qp_attr *qp_attr,
 	if (qp_attr_mask & IB_QP_MAX_QP_RD_ATOMIC) {
 		qp->qplib_qp.modify_flags |=
 				CMDQ_MODIFY_QP_MODIFY_MASK_MAX_RD_ATOMIC;
-		qp->qplib_qp.max_rd_atomic = qp_attr->max_rd_atomic;
+		/* Cap the max_rd_atomic to device max */
+		qp->qplib_qp.max_rd_atomic = min_t(u32, qp_attr->max_rd_atomic,
+						   dev_attr->max_qp_rd_atom);
 	}
 	if (qp_attr_mask & IB_QP_SQ_PSN) {
 		qp->qplib_qp.modify_flags |= CMDQ_MODIFY_QP_MODIFY_MASK_SQ_PSN;
 		qp->qplib_qp.sq.psn = qp_attr->sq_psn;
 	}
 	if (qp_attr_mask & IB_QP_MAX_DEST_RD_ATOMIC) {
+		if (qp_attr->max_dest_rd_atomic >
+		    dev_attr->max_qp_init_rd_atom) {
+			dev_err(rdev_to_dev(rdev),
+				"max_dest_rd_atomic requested%d is > dev_max%d",
+				qp_attr->max_dest_rd_atomic,
+				dev_attr->max_qp_init_rd_atom);
+			return -EINVAL;
+		}
+
 		qp->qplib_qp.modify_flags |=
 				CMDQ_MODIFY_QP_MODIFY_MASK_MAX_DEST_RD_ATOMIC;
 		qp->qplib_qp.max_dest_rd_atomic = qp_attr->max_dest_rd_atomic;
-- 
2.5.5

--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH for-next 08/13] RDMA/bnxt_re: Specify RDMA component when allocating stats context
       [not found] ` <1498065504-27902-1-git-send-email-selvin.xavier-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>
                     ` (6 preceding siblings ...)
  2017-06-21 17:18   ` [PATCH for-next 07/13] RDMA/bnxt_re: Fixed the max_rd_atomic support for initiator and destination QP Selvin Xavier
@ 2017-06-21 17:18   ` Selvin Xavier
  2017-06-21 17:18   ` [PATCH for-next 09/13] RDMA/bnxt_re: Allow posting when QPs are in error Selvin Xavier
                     ` (4 subsequent siblings)
  12 siblings, 0 replies; 17+ messages in thread
From: Selvin Xavier @ 2017-06-21 17:18 UTC (permalink / raw)
  To: dledford-H+wXaHxf7aLQT0dZR+AlfA
  Cc: linux-rdma-u79uwXL29TY76Z2rM5mHXA, Somnath Kotur, Selvin Xavier

From: Somnath Kotur <somnath.kotur-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>

Starting FW version 20.6.47, firmware is keeping separate statistics
for L2 and RDMA. However, driver needs to specify RDMA or not when
allocating stat_ctx.

Signed-off-by: Selvin Xavier <selvin.xavier-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>
---
 drivers/infiniband/hw/bnxt_re/main.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/infiniband/hw/bnxt_re/main.c b/drivers/infiniband/hw/bnxt_re/main.c
index df4d1df..c067b9c 100644
--- a/drivers/infiniband/hw/bnxt_re/main.c
+++ b/drivers/infiniband/hw/bnxt_re/main.c
@@ -335,6 +335,7 @@ static int bnxt_re_net_stats_ctx_alloc(struct bnxt_re_dev *rdev,
 	bnxt_re_init_hwrm_hdr(rdev, (void *)&req, HWRM_STAT_CTX_ALLOC, -1, -1);
 	req.update_period_ms = cpu_to_le32(1000);
 	req.stats_dma_addr = cpu_to_le64(dma_map);
+	req.stat_ctx_flags = STAT_CTX_ALLOC_REQ_STAT_CTX_FLAGS_ROCE;
 	bnxt_re_fill_fw_msg(&fw_msg, (void *)&req, sizeof(req), (void *)&resp,
 			    sizeof(resp), DFLT_HWRM_CMD_TIMEOUT);
 	rc = en_dev->en_ops->bnxt_send_fw_msg(en_dev, BNXT_ROCE_ULP, &fw_msg);
-- 
2.5.5

--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH for-next 09/13] RDMA/bnxt_re: Allow posting when QPs are in error
       [not found] ` <1498065504-27902-1-git-send-email-selvin.xavier-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>
                     ` (7 preceding siblings ...)
  2017-06-21 17:18   ` [PATCH for-next 08/13] RDMA/bnxt_re: Specify RDMA component when allocating stats context Selvin Xavier
@ 2017-06-21 17:18   ` Selvin Xavier
       [not found]     ` <1498065504-27902-10-git-send-email-selvin.xavier-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>
  2017-06-21 17:18   ` [PATCH for-next 10/13] RDMA/bnxt_re: Enable atomics only if host bios supports Selvin Xavier
                     ` (3 subsequent siblings)
  12 siblings, 1 reply; 17+ messages in thread
From: Selvin Xavier @ 2017-06-21 17:18 UTC (permalink / raw)
  To: dledford-H+wXaHxf7aLQT0dZR+AlfA
  Cc: linux-rdma-u79uwXL29TY76Z2rM5mHXA, Selvin Xavier, Sriharsha Basavapatna

This  patch allows driver to post send and receive
requests on QPs which are in  error state.

Instead of flushing the QP in the context of polling
error CQEs, the QPs will be added to a flush list
maintained per CQ. QP state is moved to error.
QP is added to flush list if the user moves it
to error state using modify_qp also. After polling the HW
CQ in poll_cq routine, this flush list is traversed
and driver completes work requests each QP in the flush
list, till the budget expires. The QP is moved out of
flush list during QP destroy or during modify_QP to RESET.

When ULPs post Work Requests while QP is in error state,
driver will store the ULP data and then increments the
QP producer s/w index, without ringing doorbell. It then
schedules a worker to invoke the CQ handler since the
interrupts wont be generated from the HW for this request.

Signed-off-by: Sriharsha Basavapatna <sriharsha.basavapatna-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>
Signed-off-by: Selvin Xavier <selvin.xavier-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>
---
 drivers/infiniband/hw/bnxt_re/ib_verbs.c   |  22 ++
 drivers/infiniband/hw/bnxt_re/main.c       |   3 +-
 drivers/infiniband/hw/bnxt_re/qplib_fp.c   | 411 ++++++++++++++++++++++-------
 drivers/infiniband/hw/bnxt_re/qplib_fp.h   |  22 +-
 drivers/infiniband/hw/bnxt_re/qplib_rcfw.c |  10 +-
 drivers/infiniband/hw/bnxt_re/qplib_rcfw.h |  10 +-
 6 files changed, 383 insertions(+), 95 deletions(-)

diff --git a/drivers/infiniband/hw/bnxt_re/ib_verbs.c b/drivers/infiniband/hw/bnxt_re/ib_verbs.c
index 6629727..e7d667f 100644
--- a/drivers/infiniband/hw/bnxt_re/ib_verbs.c
+++ b/drivers/infiniband/hw/bnxt_re/ib_verbs.c
@@ -829,6 +829,7 @@ int bnxt_re_destroy_qp(struct ib_qp *ib_qp)
 	struct bnxt_re_dev *rdev = qp->rdev;
 	int rc;
 
+	bnxt_qplib_del_flush_qp(&qp->qplib_qp);
 	rc = bnxt_qplib_destroy_qp(&rdev->qplib_res, &qp->qplib_qp);
 	if (rc) {
 		dev_err(rdev_to_dev(rdev), "Failed to destroy HW QP");
@@ -843,6 +844,7 @@ int bnxt_re_destroy_qp(struct ib_qp *ib_qp)
 			return rc;
 		}
 
+		bnxt_qplib_del_flush_qp(&qp->qplib_qp);
 		rc = bnxt_qplib_destroy_qp(&rdev->qplib_res,
 					   &rdev->qp1_sqp->qplib_qp);
 		if (rc) {
@@ -1387,6 +1389,21 @@ int bnxt_re_modify_qp(struct ib_qp *ib_qp, struct ib_qp_attr *qp_attr,
 		}
 		qp->qplib_qp.modify_flags |= CMDQ_MODIFY_QP_MODIFY_MASK_STATE;
 		qp->qplib_qp.state = __from_ib_qp_state(qp_attr->qp_state);
+
+		if (!qp->sumem &&
+		    qp->qplib_qp.state == CMDQ_MODIFY_QP_NEW_STATE_ERR) {
+			dev_dbg(rdev_to_dev(rdev),
+				"Move QP = %p to flush list\n",
+				qp);
+			bnxt_qplib_add_flush_qp(&qp->qplib_qp);
+		}
+		if (!qp->sumem &&
+		    qp->qplib_qp.state == CMDQ_MODIFY_QP_NEW_STATE_RESET) {
+			dev_dbg(rdev_to_dev(rdev),
+				"Move QP = %p out of flush list\n",
+				qp);
+			bnxt_qplib_del_flush_qp(&qp->qplib_qp);
+		}
 	}
 	if (qp_attr_mask & IB_QP_EN_SQD_ASYNC_NOTIFY) {
 		qp->qplib_qp.modify_flags |=
@@ -2397,6 +2414,7 @@ struct ib_cq *bnxt_re_create_cq(struct ib_device *ibdev,
 	}
 	cq->qplib_cq.max_wqe = entries;
 	cq->qplib_cq.cnq_hw_ring_id = rdev->nq.ring_id;
+	cq->qplib_cq.nq	= &rdev->nq;
 
 	rc = bnxt_qplib_create_cq(&rdev->qplib_res, &cq->qplib_cq);
 	if (rc) {
@@ -2903,6 +2921,10 @@ int bnxt_re_poll_cq(struct ib_cq *ib_cq, int num_entries, struct ib_wc *wc)
 					sq->send_phantom = false;
 			}
 		}
+		if (ncqe < budget)
+			ncqe += bnxt_qplib_process_flush_list(&cq->qplib_cq,
+							      cqe + ncqe,
+							      budget - ncqe);
 
 		if (!ncqe)
 			break;
diff --git a/drivers/infiniband/hw/bnxt_re/main.c b/drivers/infiniband/hw/bnxt_re/main.c
index c067b9c..ec9fc0b 100644
--- a/drivers/infiniband/hw/bnxt_re/main.c
+++ b/drivers/infiniband/hw/bnxt_re/main.c
@@ -1045,7 +1045,8 @@ static int bnxt_re_ib_reg(struct bnxt_re_dev *rdev)
 	/* Establish RCFW Communication Channel to initialize the context
 	 * memory for the function and all child VFs
 	 */
-	rc = bnxt_qplib_alloc_rcfw_channel(rdev->en_dev->pdev, &rdev->rcfw);
+	rc = bnxt_qplib_alloc_rcfw_channel(rdev->en_dev->pdev, &rdev->rcfw,
+					   BNXT_RE_MAX_QPC_COUNT);
 	if (rc)
 		goto fail;
 
diff --git a/drivers/infiniband/hw/bnxt_re/qplib_fp.c b/drivers/infiniband/hw/bnxt_re/qplib_fp.c
index 8ef39df..5c144ce 100644
--- a/drivers/infiniband/hw/bnxt_re/qplib_fp.c
+++ b/drivers/infiniband/hw/bnxt_re/qplib_fp.c
@@ -52,6 +52,114 @@
 
 static void bnxt_qplib_arm_cq_enable(struct bnxt_qplib_cq *cq);
 
+/* Flush list */
+
+/* To avoid processing completions if QP is already in flush list */
+static bool bnxt_qplib_is_qp_in_rq_flushlist(struct bnxt_qplib_qp *qp)
+{
+	bool flushed = false;
+	unsigned long flags;
+
+	spin_lock_irqsave(&qp->rcq->flush_lock, flags);
+	flushed = qp->rq.flushed;
+	spin_unlock_irqrestore(&qp->rcq->flush_lock, flags);
+	return flushed;
+}
+
+static bool bnxt_qplib_is_qp_in_sq_flushlist(struct bnxt_qplib_qp *qp)
+{
+	bool flushed = false;
+	unsigned long flags;
+
+	spin_lock_irqsave(&qp->scq->flush_lock, flags);
+	flushed = qp->sq.flushed;
+	spin_unlock_irqrestore(&qp->scq->flush_lock, flags);
+	return flushed;
+}
+
+static void bnxt_qplib_cancel_phantom_processing(struct bnxt_qplib_qp *qp)
+{
+	qp->sq.condition = false;
+	qp->sq.send_phantom = false;
+	qp->sq.single = false;
+}
+
+void bnxt_qplib_add_flush_qp(struct bnxt_qplib_qp *qp)
+{
+	struct bnxt_qplib_cq *scq, *rcq;
+	unsigned long flags;
+
+	scq = qp->scq;
+	rcq = qp->rcq;
+
+	spin_lock_irqsave(&scq->flush_lock, flags);
+	if (!qp->sq.flushed) {
+		dev_dbg(&scq->hwq.pdev->dev,
+			"QPLIB: FP: Adding to SQ Flush list = %p",
+			qp);
+		bnxt_qplib_cancel_phantom_processing(qp);
+		list_add_tail(&qp->sq_flush, &scq->sqf_head);
+		qp->sq.flushed = true;
+	}
+	spin_unlock_irqrestore(&scq->flush_lock, flags);
+	if (!qp->srq) {
+		spin_lock_irqsave(&rcq->flush_lock, flags);
+		if (!qp->rq.flushed) {
+			dev_dbg(&rcq->hwq.pdev->dev,
+				"QPLIB: FP: Adding to RQ Flush list = %p",
+				qp);
+			list_add_tail(&qp->rq_flush, &rcq->rqf_head);
+			qp->rq.flushed = true;
+		}
+		spin_unlock_irqrestore(&rcq->flush_lock, flags);
+	}
+}
+
+void bnxt_qplib_del_flush_qp(struct bnxt_qplib_qp *qp)
+{
+	struct bnxt_qplib_cq *scq, *rcq;
+	unsigned long flags;
+
+	scq = qp->scq;
+	rcq = qp->rcq;
+
+	spin_lock_irqsave(&scq->flush_lock, flags);
+	if (qp->sq.flushed) {
+		qp->sq.flushed = false;
+		list_del(&qp->sq_flush);
+	}
+	spin_unlock_irqrestore(&scq->flush_lock, flags);
+	if (!qp->srq) {
+		spin_lock_irqsave(&rcq->flush_lock, flags);
+		if (qp->rq.flushed) {
+			qp->rq.flushed = false;
+			list_del(&qp->rq_flush);
+		}
+		spin_unlock_irqrestore(&rcq->flush_lock, flags);
+	}
+}
+
+static void bnxt_qpn_cqn_sched_task(struct work_struct *work)
+{
+	struct bnxt_qplib_nq_work *nq_work =
+			container_of(work, struct bnxt_qplib_nq_work, work);
+
+	struct bnxt_qplib_cq *cq = nq_work->cq;
+	struct bnxt_qplib_nq *nq = nq_work->nq;
+
+	if (cq && nq) {
+		spin_lock_bh(&cq->compl_lock);
+		if (atomic_read(&cq->arm_state) && nq->cqn_handler) {
+			dev_dbg(&nq->pdev->dev,
+				"%s:Trigger cq  = %p event nq = %p\n",
+				__func__, cq, nq);
+			nq->cqn_handler(nq, cq);
+		}
+		spin_unlock_bh(&cq->compl_lock);
+	}
+	kfree(nq_work);
+}
+
 static void bnxt_qplib_free_qp_hdr_buf(struct bnxt_qplib_res *res,
 				       struct bnxt_qplib_qp *qp)
 {
@@ -119,6 +227,7 @@ static void bnxt_qplib_service_nq(unsigned long data)
 	struct bnxt_qplib_nq *nq = (struct bnxt_qplib_nq *)data;
 	struct bnxt_qplib_hwq *hwq = &nq->hwq;
 	struct nq_base *nqe, **nq_ptr;
+	struct bnxt_qplib_cq *cq;
 	int num_cqne_processed = 0;
 	u32 sw_cons, raw_cons;
 	u16 type;
@@ -143,15 +252,17 @@ static void bnxt_qplib_service_nq(unsigned long data)
 			q_handle = le32_to_cpu(nqcne->cq_handle_low);
 			q_handle |= (u64)le32_to_cpu(nqcne->cq_handle_high)
 						     << 32;
-			bnxt_qplib_arm_cq_enable((struct bnxt_qplib_cq *)
-						 ((unsigned long)q_handle));
-			if (!nq->cqn_handler(nq, (struct bnxt_qplib_cq *)
-						 ((unsigned long)q_handle)))
+			cq = (struct bnxt_qplib_cq *)(unsigned long)q_handle;
+			bnxt_qplib_arm_cq_enable(cq);
+			spin_lock_bh(&cq->compl_lock);
+			atomic_set(&cq->arm_state, 0);
+			if (!nq->cqn_handler(nq, (cq)))
 				num_cqne_processed++;
 			else
 				dev_warn(&nq->pdev->dev,
 					 "QPLIB: cqn - type 0x%x not handled",
 					 type);
+			spin_unlock_bh(&cq->compl_lock);
 			break;
 		}
 		case NQ_BASE_TYPE_DBQ_EVENT:
@@ -190,6 +301,10 @@ static irqreturn_t bnxt_qplib_nq_irq(int irq, void *dev_instance)
 
 void bnxt_qplib_disable_nq(struct bnxt_qplib_nq *nq)
 {
+	if (nq->cqn_wq) {
+		destroy_workqueue(nq->cqn_wq);
+		nq->cqn_wq = NULL;
+	}
 	/* Make sure the HW is stopped! */
 	synchronize_irq(nq->vector);
 	tasklet_disable(&nq->worker);
@@ -216,7 +331,7 @@ int bnxt_qplib_enable_nq(struct pci_dev *pdev, struct bnxt_qplib_nq *nq,
 					     void *, u8 event))
 {
 	resource_size_t nq_base;
-	int rc;
+	int rc = -1;
 
 	nq->pdev = pdev;
 	nq->vector = msix_vector;
@@ -227,6 +342,11 @@ int bnxt_qplib_enable_nq(struct pci_dev *pdev, struct bnxt_qplib_nq *nq,
 
 	tasklet_init(&nq->worker, bnxt_qplib_service_nq, (unsigned long)nq);
 
+	/* Have a task to schedule CQ notifiers in post send case */
+	nq->cqn_wq  = create_singlethread_workqueue("bnxt_qplib_nq");
+	if (!nq->cqn_wq)
+		goto fail;
+
 	nq->requested = false;
 	rc = request_irq(nq->vector, bnxt_qplib_nq_irq, 0, "bnxt_qplib_nq", nq);
 	if (rc) {
@@ -401,8 +521,8 @@ int bnxt_qplib_create_qp1(struct bnxt_qplib_res *res, struct bnxt_qplib_qp *qp)
 
 	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;
+	rcfw->qp_tbl[qp->id].qp_id = qp->id;
+	rcfw->qp_tbl[qp->id].qp_handle = (void *)qp;
 
 	return 0;
 
@@ -615,8 +735,10 @@ int bnxt_qplib_create_qp(struct bnxt_qplib_res *res, struct bnxt_qplib_qp *qp)
 
 	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;
+	INIT_LIST_HEAD(&qp->sq_flush);
+	INIT_LIST_HEAD(&qp->rq_flush);
+	rcfw->qp_tbl[qp->id].qp_id = qp->id;
+	rcfw->qp_tbl[qp->id].qp_handle = (void *)qp;
 
 	return 0;
 
@@ -963,13 +1085,19 @@ int bnxt_qplib_destroy_qp(struct bnxt_qplib_res *res,
 	u16 cmd_flags = 0;
 	int rc;
 
+	rcfw->qp_tbl[qp->id].qp_id = BNXT_QPLIB_QP_ID_INVALID;
+	rcfw->qp_tbl[qp->id].qp_handle = NULL;
+
 	RCFW_CMD_PREP(req, DESTROY_QP, cmd_flags);
 
 	req.qp_cid = cpu_to_le32(qp->id);
 	rc = bnxt_qplib_rcfw_send_message(rcfw, (void *)&req,
 					  (void *)&resp, NULL, 0);
-	if (rc)
+	if (rc) {
+		rcfw->qp_tbl[qp->id].qp_id = qp->id;
+		rcfw->qp_tbl[qp->id].qp_handle = qp;
 		return rc;
+	}
 
 	/* Must walk the associated CQs to nullified the QP ptr */
 	spin_lock_irqsave(&qp->scq->hwq.lock, flags);
@@ -1074,14 +1202,21 @@ int bnxt_qplib_post_send(struct bnxt_qplib_qp *qp,
 	struct bnxt_qplib_swq *swq;
 	struct sq_send *hw_sq_send_hdr, **hw_sq_send_ptr;
 	struct sq_sge *hw_sge;
+	struct bnxt_qplib_nq_work *nq_work = NULL;
+	bool sch_handler = false;
 	u32 sw_prod;
 	u8 wqe_size16;
 	int i, rc = 0, data_len = 0, pkt_num = 0;
 	__le32 temp32;
 
 	if (qp->state != CMDQ_MODIFY_QP_NEW_STATE_RTS) {
-		rc = -EINVAL;
-		goto done;
+		if (qp->state == CMDQ_MODIFY_QP_NEW_STATE_ERR) {
+			sch_handler = true;
+			dev_dbg(&sq->hwq.pdev->dev,
+				"%s Error QP. Scheduling for poll_cq\n",
+				__func__);
+			goto queue_err;
+		}
 	}
 
 	if (bnxt_qplib_queue_full(sq)) {
@@ -1301,12 +1436,35 @@ int bnxt_qplib_post_send(struct bnxt_qplib_qp *qp,
 			((swq->next_psn << SQ_PSN_SEARCH_NEXT_PSN_SFT) &
 			 SQ_PSN_SEARCH_NEXT_PSN_MASK));
 	}
-
+queue_err:
+	if (sch_handler) {
+		/* Store the ULP info in the software structures */
+		sw_prod = HWQ_CMP(sq->hwq.prod, &sq->hwq);
+		swq = &sq->swq[sw_prod];
+		swq->wr_id = wqe->wr_id;
+		swq->type = wqe->type;
+		swq->flags = wqe->flags;
+		if (qp->sig_type)
+			swq->flags |= SQ_SEND_FLAGS_SIGNAL_COMP;
+		swq->start_psn = sq->psn & BTH_PSN_MASK;
+	}
 	sq->hwq.prod++;
-
 	qp->wqe_cnt++;
 
 done:
+	if (sch_handler) {
+		nq_work = kzalloc(sizeof(*nq_work), GFP_ATOMIC);
+		if (nq_work) {
+			nq_work->cq = qp->scq;
+			nq_work->nq = qp->scq->nq;
+			INIT_WORK(&nq_work->work, bnxt_qpn_cqn_sched_task);
+			queue_work(qp->scq->nq->cqn_wq, &nq_work->work);
+		} else {
+			dev_err(&sq->hwq.pdev->dev,
+				"QPLIB: FP: Failed to allocate SQ nq_work!");
+			rc = -ENOMEM;
+		}
+	}
 	return rc;
 }
 
@@ -1334,15 +1492,17 @@ int bnxt_qplib_post_recv(struct bnxt_qplib_qp *qp,
 	struct bnxt_qplib_q *rq = &qp->rq;
 	struct rq_wqe *rqe, **rqe_ptr;
 	struct sq_sge *hw_sge;
+	struct bnxt_qplib_nq_work *nq_work = NULL;
+	bool sch_handler = false;
 	u32 sw_prod;
 	int i, rc = 0;
 
 	if (qp->state == CMDQ_MODIFY_QP_NEW_STATE_ERR) {
-		dev_err(&rq->hwq.pdev->dev,
-			"QPLIB: FP: QP (0x%x) is in the 0x%x state",
-			qp->id, qp->state);
-		rc = -EINVAL;
-		goto done;
+		sch_handler = true;
+		dev_dbg(&rq->hwq.pdev->dev,
+			"%s Error QP. Scheduling for poll_cq\n",
+			__func__);
+		goto queue_err;
 	}
 	if (bnxt_qplib_queue_full(rq)) {
 		dev_err(&rq->hwq.pdev->dev,
@@ -1378,7 +1538,27 @@ int bnxt_qplib_post_recv(struct bnxt_qplib_qp *qp,
 	/* Supply the rqe->wr_id index to the wr_id_tbl for now */
 	rqe->wr_id[0] = cpu_to_le32(sw_prod);
 
+queue_err:
+	if (sch_handler) {
+		/* Store the ULP info in the software structures */
+		sw_prod = HWQ_CMP(rq->hwq.prod, &rq->hwq);
+		rq->swq[sw_prod].wr_id = wqe->wr_id;
+	}
+
 	rq->hwq.prod++;
+	if (sch_handler) {
+		nq_work = kzalloc(sizeof(*nq_work), GFP_ATOMIC);
+		if (nq_work) {
+			nq_work->cq = qp->rcq;
+			nq_work->nq = qp->rcq->nq;
+			INIT_WORK(&nq_work->work, bnxt_qpn_cqn_sched_task);
+			queue_work(qp->rcq->nq->cqn_wq, &nq_work->work);
+		} else {
+			dev_err(&rq->hwq.pdev->dev,
+				"QPLIB: FP: Failed to allocate RQ nq_work!");
+			rc = -ENOMEM;
+		}
+	}
 done:
 	return rc;
 }
@@ -1471,6 +1651,10 @@ int bnxt_qplib_create_cq(struct bnxt_qplib_res *res, struct bnxt_qplib_cq *cq)
 	cq->dbr_base = res->dpi_tbl.dbr_bar_reg_iomem;
 	cq->period = BNXT_QPLIB_QUEUE_START_PERIOD;
 	init_waitqueue_head(&cq->waitq);
+	INIT_LIST_HEAD(&cq->sqf_head);
+	INIT_LIST_HEAD(&cq->rqf_head);
+	spin_lock_init(&cq->flush_lock);
+	spin_lock_init(&cq->compl_lock);
 
 	bnxt_qplib_arm_cq_enable(cq);
 	return 0;
@@ -1513,9 +1697,13 @@ static int __flush_sq(struct bnxt_qplib_q *sq, struct bnxt_qplib_qp *qp,
 	while (*budget) {
 		sw_cons = HWQ_CMP(sq->hwq.cons, &sq->hwq);
 		if (sw_cons == sw_prod) {
-			sq->flush_in_progress = false;
 			break;
 		}
+		/* Skip the FENCE WQE completions */
+		if (sq->swq[sw_cons].wr_id == BNXT_QPLIB_FENCE_WRID) {
+			bnxt_qplib_cancel_phantom_processing(qp);
+			goto skip_compl;
+		}
 		memset(cqe, 0, sizeof(*cqe));
 		cqe->status = CQ_REQ_STATUS_WORK_REQUEST_FLUSHED_ERR;
 		cqe->opcode = CQ_BASE_CQE_TYPE_REQ;
@@ -1525,6 +1713,7 @@ static int __flush_sq(struct bnxt_qplib_q *sq, struct bnxt_qplib_qp *qp,
 		cqe->type = sq->swq[sw_cons].type;
 		cqe++;
 		(*budget)--;
+skip_compl:
 		sq->hwq.cons++;
 	}
 	*pcqe = cqe;
@@ -1536,11 +1725,24 @@ static int __flush_sq(struct bnxt_qplib_q *sq, struct bnxt_qplib_qp *qp,
 }
 
 static int __flush_rq(struct bnxt_qplib_q *rq, struct bnxt_qplib_qp *qp,
-		      int opcode, struct bnxt_qplib_cqe **pcqe, int *budget)
+		      struct bnxt_qplib_cqe **pcqe, int *budget)
 {
 	struct bnxt_qplib_cqe *cqe;
 	u32 sw_prod, sw_cons;
 	int rc = 0;
+	int opcode = 0;
+
+	switch (qp->type) {
+	case CMDQ_CREATE_QP1_TYPE_GSI:
+		opcode = CQ_BASE_CQE_TYPE_RES_RAWETH_QP1;
+		break;
+	case CMDQ_CREATE_QP_TYPE_RC:
+		opcode = CQ_BASE_CQE_TYPE_RES_RC;
+		break;
+	case CMDQ_CREATE_QP_TYPE_UD:
+		opcode = CQ_BASE_CQE_TYPE_RES_UD;
+		break;
+	}
 
 	/* Flush the rest of the RQ */
 	sw_prod = HWQ_CMP(rq->hwq.prod, &rq->hwq);
@@ -1567,6 +1769,21 @@ static int __flush_rq(struct bnxt_qplib_q *rq, struct bnxt_qplib_qp *qp,
 	return rc;
 }
 
+void bnxt_qplib_mark_qp_error(void *qp_handle)
+{
+	struct bnxt_qplib_qp *qp = qp_handle;
+
+	if (!qp)
+		return;
+
+	/* Must block new posting of SQ and RQ */
+	qp->state = CMDQ_MODIFY_QP_NEW_STATE_ERR;
+	bnxt_qplib_cancel_phantom_processing(qp);
+
+	/* Add qp to flush list of the CQ */
+	bnxt_qplib_add_flush_qp(qp);
+}
+
 /* Note: SQE is valid from sw_sq_cons up to cqe_sq_cons (exclusive)
  *       CQE is track from sw_cq_cons to max_element but valid only if VALID=1
  */
@@ -1694,10 +1911,12 @@ static int bnxt_qplib_cq_process_req(struct bnxt_qplib_cq *cq,
 			cqe_sq_cons, sq->hwq.max_elements);
 		return -EINVAL;
 	}
-	/* If we were in the middle of flushing the SQ, continue */
-	if (sq->flush_in_progress)
-		goto flush;
 
+	if (bnxt_qplib_is_qp_in_sq_flushlist(qp)) {
+		dev_dbg(&cq->hwq.pdev->dev,
+			"%s: QPLIB: QP in Flush QP = %p\n", __func__, qp);
+		goto done;
+	}
 	/* Require to walk the sq's swq to fabricate CQEs for all previously
 	 * signaled SWQEs due to CQE aggregation from the current sq cons
 	 * to the cqe_sq_cons
@@ -1733,11 +1952,7 @@ static int bnxt_qplib_cq_process_req(struct bnxt_qplib_cq *cq,
 				sw_sq_cons, cqe->wr_id, cqe->status);
 			cqe++;
 			(*budget)--;
-			sq->flush_in_progress = true;
-			/* Must block new posting of SQ and RQ */
-			qp->state = CMDQ_MODIFY_QP_NEW_STATE_ERR;
-			sq->condition = false;
-			sq->single = false;
+			bnxt_qplib_mark_qp_error(qp);
 		} else {
 			if (swq->flags & SQ_SEND_FLAGS_SIGNAL_COMP) {
 				/* Before we complete, do WA 9060 */
@@ -1768,15 +1983,6 @@ static int bnxt_qplib_cq_process_req(struct bnxt_qplib_cq *cq,
 	 * the WC for this CQE
 	 */
 	sq->single = false;
-	if (!sq->flush_in_progress)
-		goto done;
-flush:
-	/* Require to walk the sq's swq to fabricate CQEs for all
-	 * previously posted SWQEs due to the error CQE received
-	 */
-	rc = __flush_sq(sq, qp, pcqe, budget);
-	if (!rc)
-		sq->flush_in_progress = false;
 done:
 	return rc;
 }
@@ -1798,6 +2004,12 @@ static int bnxt_qplib_cq_process_res_rc(struct bnxt_qplib_cq *cq,
 		dev_err(&cq->hwq.pdev->dev, "QPLIB: process_cq RC qp is NULL");
 		return -EINVAL;
 	}
+	if (bnxt_qplib_is_qp_in_rq_flushlist(qp)) {
+		dev_dbg(&cq->hwq.pdev->dev,
+			"%s: QPLIB: QP in Flush QP = %p\n", __func__, qp);
+		goto done;
+	}
+
 	cqe = *pcqe;
 	cqe->opcode = hwcqe->cqe_type_toggle & CQ_BASE_CQE_TYPE_MASK;
 	cqe->length = le32_to_cpu(hwcqe->length);
@@ -1817,8 +2029,6 @@ static int bnxt_qplib_cq_process_res_rc(struct bnxt_qplib_cq *cq,
 			wr_id_idx, rq->hwq.max_elements);
 		return -EINVAL;
 	}
-	if (rq->flush_in_progress)
-		goto flush_rq;
 
 	cqe->wr_id = rq->swq[wr_id_idx].wr_id;
 	cqe++;
@@ -1826,13 +2036,11 @@ static int bnxt_qplib_cq_process_res_rc(struct bnxt_qplib_cq *cq,
 	rq->hwq.cons++;
 	*pcqe = cqe;
 
-	if (hwcqe->status != CQ_RES_RC_STATUS_OK) {
-		rq->flush_in_progress = true;
-flush_rq:
-		rc = __flush_rq(rq, qp, CQ_BASE_CQE_TYPE_RES_RC, pcqe, budget);
-		if (!rc)
-			rq->flush_in_progress = false;
-	}
+	if (hwcqe->status != CQ_RES_RC_STATUS_OK)
+		 /* Add qp to flush list of the CQ */
+		bnxt_qplib_add_flush_qp(qp);
+
+done:
 	return rc;
 }
 
@@ -1853,6 +2061,11 @@ static int bnxt_qplib_cq_process_res_ud(struct bnxt_qplib_cq *cq,
 		dev_err(&cq->hwq.pdev->dev, "QPLIB: process_cq UD qp is NULL");
 		return -EINVAL;
 	}
+	if (bnxt_qplib_is_qp_in_rq_flushlist(qp)) {
+		dev_dbg(&cq->hwq.pdev->dev,
+			"%s: QPLIB: QP in Flush QP = %p\n", __func__, qp);
+		goto done;
+	}
 	cqe = *pcqe;
 	cqe->opcode = hwcqe->cqe_type_toggle & CQ_BASE_CQE_TYPE_MASK;
 	cqe->length = le32_to_cpu(hwcqe->length);
@@ -1876,8 +2089,6 @@ static int bnxt_qplib_cq_process_res_ud(struct bnxt_qplib_cq *cq,
 			wr_id_idx, rq->hwq.max_elements);
 		return -EINVAL;
 	}
-	if (rq->flush_in_progress)
-		goto flush_rq;
 
 	cqe->wr_id = rq->swq[wr_id_idx].wr_id;
 	cqe++;
@@ -1885,13 +2096,11 @@ static int bnxt_qplib_cq_process_res_ud(struct bnxt_qplib_cq *cq,
 	rq->hwq.cons++;
 	*pcqe = cqe;
 
-	if (hwcqe->status != CQ_RES_RC_STATUS_OK) {
-		rq->flush_in_progress = true;
-flush_rq:
-		rc = __flush_rq(rq, qp, CQ_BASE_CQE_TYPE_RES_UD, pcqe, budget);
-		if (!rc)
-			rq->flush_in_progress = false;
-	}
+	if (hwcqe->status != CQ_RES_RC_STATUS_OK)
+		/* Add qp to flush list of the CQ */
+		bnxt_qplib_add_flush_qp(qp);
+
+done:
 	return rc;
 }
 
@@ -1913,6 +2122,11 @@ static int bnxt_qplib_cq_process_res_raweth_qp1(struct bnxt_qplib_cq *cq,
 			"QPLIB: process_cq Raw/QP1 qp is NULL");
 		return -EINVAL;
 	}
+	if (bnxt_qplib_is_qp_in_rq_flushlist(qp)) {
+		dev_dbg(&cq->hwq.pdev->dev,
+			"%s: QPLIB: QP in Flush QP = %p\n", __func__, qp);
+		goto done;
+	}
 	cqe = *pcqe;
 	cqe->opcode = hwcqe->cqe_type_toggle & CQ_BASE_CQE_TYPE_MASK;
 	cqe->flags = le16_to_cpu(hwcqe->flags);
@@ -1941,8 +2155,6 @@ static int bnxt_qplib_cq_process_res_raweth_qp1(struct bnxt_qplib_cq *cq,
 			wr_id_idx, rq->hwq.max_elements);
 		return -EINVAL;
 	}
-	if (rq->flush_in_progress)
-		goto flush_rq;
 
 	cqe->wr_id = rq->swq[wr_id_idx].wr_id;
 	cqe++;
@@ -1950,14 +2162,11 @@ static int bnxt_qplib_cq_process_res_raweth_qp1(struct bnxt_qplib_cq *cq,
 	rq->hwq.cons++;
 	*pcqe = cqe;
 
-	if (hwcqe->status != CQ_RES_RC_STATUS_OK) {
-		rq->flush_in_progress = true;
-flush_rq:
-		rc = __flush_rq(rq, qp, CQ_BASE_CQE_TYPE_RES_RAWETH_QP1, pcqe,
-				budget);
-		if (!rc)
-			rq->flush_in_progress = false;
-	}
+	if (hwcqe->status != CQ_RES_RC_STATUS_OK)
+	/* Add qp to flush list of the CQ */
+		bnxt_qplib_add_flush_qp(qp);
+
+done:
 	return rc;
 }
 
@@ -1971,7 +2180,6 @@ static int bnxt_qplib_cq_process_terminal(struct bnxt_qplib_cq *cq,
 	struct bnxt_qplib_cqe *cqe;
 	u32 sw_cons = 0, cqe_cons;
 	int rc = 0;
-	u8 opcode = 0;
 
 	/* Check the Status */
 	if (hwcqe->status != CQ_TERMINAL_STATUS_OK)
@@ -2004,9 +2212,12 @@ static int bnxt_qplib_cq_process_terminal(struct bnxt_qplib_cq *cq,
 			cqe_cons, sq->hwq.max_elements);
 		goto do_rq;
 	}
-	/* If we were in the middle of flushing, continue */
-	if (sq->flush_in_progress)
-		goto flush_sq;
+
+	if (bnxt_qplib_is_qp_in_sq_flushlist(qp)) {
+		dev_dbg(&cq->hwq.pdev->dev,
+			"%s: QPLIB: QP in Flush QP = %p\n", __func__, qp);
+		goto sq_done;
+	}
 
 	/* Terminal CQE can also include aggregated successful CQEs prior.
 	 * So we must complete all CQEs from the current sq's cons to the
@@ -2036,11 +2247,6 @@ static int bnxt_qplib_cq_process_terminal(struct bnxt_qplib_cq *cq,
 		rc = -EAGAIN;
 		goto sq_done;
 	}
-	sq->flush_in_progress = true;
-flush_sq:
-	rc = __flush_sq(sq, qp, pcqe, budget);
-	if (!rc)
-		sq->flush_in_progress = false;
 sq_done:
 	if (rc)
 		return rc;
@@ -2056,26 +2262,21 @@ static int bnxt_qplib_cq_process_terminal(struct bnxt_qplib_cq *cq,
 			cqe_cons, rq->hwq.max_elements);
 		goto done;
 	}
+
+	if (bnxt_qplib_is_qp_in_rq_flushlist(qp)) {
+		dev_dbg(&cq->hwq.pdev->dev,
+			"%s: QPLIB: QP in Flush QP = %p\n", __func__, qp);
+		rc = 0;
+		goto done;
+	}
+
 	/* Terminal CQE requires all posted RQEs to complete with FLUSHED_ERR
 	 * from the current rq->cons to the rq->prod regardless what the
 	 * rq->cons the terminal CQE indicates
 	 */
-	rq->flush_in_progress = true;
-	switch (qp->type) {
-	case CMDQ_CREATE_QP1_TYPE_GSI:
-		opcode = CQ_BASE_CQE_TYPE_RES_RAWETH_QP1;
-		break;
-	case CMDQ_CREATE_QP_TYPE_RC:
-		opcode = CQ_BASE_CQE_TYPE_RES_RC;
-		break;
-	case CMDQ_CREATE_QP_TYPE_UD:
-		opcode = CQ_BASE_CQE_TYPE_RES_UD;
-		break;
-	}
 
-	rc = __flush_rq(rq, qp, opcode, pcqe, budget);
-	if (!rc)
-		rq->flush_in_progress = false;
+	/* Add qp to flush list of the CQ */
+	bnxt_qplib_add_flush_qp(qp);
 done:
 	return rc;
 }
@@ -2096,6 +2297,33 @@ static int bnxt_qplib_cq_process_cutoff(struct bnxt_qplib_cq *cq,
 	return 0;
 }
 
+int bnxt_qplib_process_flush_list(struct bnxt_qplib_cq *cq,
+				  struct bnxt_qplib_cqe *cqe,
+				  int num_cqes)
+{
+	struct bnxt_qplib_qp *qp = NULL;
+	u32 budget = num_cqes;
+	unsigned long flags;
+
+	spin_lock_irqsave(&cq->flush_lock, flags);
+	list_for_each_entry(qp, &cq->sqf_head, sq_flush) {
+		dev_dbg(&cq->hwq.pdev->dev,
+			"QPLIB: FP: Flushing SQ QP= %p",
+			qp);
+		__flush_sq(&qp->sq, qp, &cqe, &budget);
+	}
+
+	list_for_each_entry(qp, &cq->rqf_head, rq_flush) {
+		dev_dbg(&cq->hwq.pdev->dev,
+			"QPLIB: FP: Flushing RQ QP= %p",
+			qp);
+		__flush_rq(&qp->rq, qp, &cqe, &budget);
+	}
+	spin_unlock_irqrestore(&cq->flush_lock, flags);
+
+	return num_cqes - budget;
+}
+
 int bnxt_qplib_poll_cq(struct bnxt_qplib_cq *cq, struct bnxt_qplib_cqe *cqe,
 		       int num_cqes, struct bnxt_qplib_qp **lib_qp)
 {
@@ -2186,6 +2414,7 @@ void bnxt_qplib_req_notify_cq(struct bnxt_qplib_cq *cq, u32 arm_type)
 	spin_lock_irqsave(&cq->hwq.lock, flags);
 	if (arm_type)
 		bnxt_qplib_arm_cq(cq, arm_type);
-
+	/* Using cq->arm_state variable to track whether to issue cq handler */
+	atomic_set(&cq->arm_state, 1);
 	spin_unlock_irqrestore(&cq->hwq.lock, flags);
 }
diff --git a/drivers/infiniband/hw/bnxt_re/qplib_fp.h b/drivers/infiniband/hw/bnxt_re/qplib_fp.h
index 36b7b7d..18abe40 100644
--- a/drivers/infiniband/hw/bnxt_re/qplib_fp.h
+++ b/drivers/infiniband/hw/bnxt_re/qplib_fp.h
@@ -220,19 +220,20 @@ struct bnxt_qplib_q {
 	u16				q_full_delta;
 	u16				max_sge;
 	u32				psn;
-	bool				flush_in_progress;
 	bool				condition;
 	bool				single;
 	bool				send_phantom;
 	u32				phantom_wqe_cnt;
 	u32				phantom_cqe_cnt;
 	u32				next_cq_cons;
+	bool				flushed;
 };
 
 struct bnxt_qplib_qp {
 	struct bnxt_qplib_pd		*pd;
 	struct bnxt_qplib_dpi		*dpi;
 	u64				qp_handle;
+#define        BNXT_QPLIB_QP_ID_INVALID        0xFFFFFFFF
 	u32				id;
 	u8				type;
 	u8				sig_type;
@@ -296,6 +297,8 @@ struct bnxt_qplib_qp {
 	dma_addr_t			sq_hdr_buf_map;
 	void				*rq_hdr_buf;
 	dma_addr_t			rq_hdr_buf_map;
+	struct list_head		sq_flush;
+	struct list_head		rq_flush;
 };
 
 #define BNXT_QPLIB_MAX_CQE_ENTRY_SIZE	sizeof(struct cq_base)
@@ -351,6 +354,7 @@ struct bnxt_qplib_cq {
 	u16				period;
 	struct bnxt_qplib_hwq		hwq;
 	u32				cnq_hw_ring_id;
+	struct bnxt_qplib_nq		*nq;
 	bool				resize_in_progress;
 	struct scatterlist		*sghead;
 	u32				nmap;
@@ -360,6 +364,10 @@ struct bnxt_qplib_cq {
 	unsigned long			flags;
 #define CQ_FLAGS_RESIZE_IN_PROG		1
 	wait_queue_head_t		waitq;
+	spinlock_t			flush_lock; /* lock flush queue list */
+	struct list_head		sqf_head, rqf_head;
+	atomic_t			arm_state;
+	spinlock_t			compl_lock; /* synch CQ handlers */
 };
 
 #define BNXT_QPLIB_MAX_IRRQE_ENTRY_SIZE	sizeof(struct xrrq_irrq)
@@ -417,6 +425,13 @@ struct bnxt_qplib_nq {
 						(struct bnxt_qplib_nq *nq,
 						 void *srq,
 						 u8 event);
+	struct workqueue_struct         *cqn_wq;
+};
+
+struct bnxt_qplib_nq_work {
+	struct work_struct      work;
+	struct bnxt_qplib_nq    *nq;
+	struct bnxt_qplib_cq    *cq;
 };
 
 void bnxt_qplib_disable_nq(struct bnxt_qplib_nq *nq);
@@ -452,4 +467,9 @@ int bnxt_qplib_poll_cq(struct bnxt_qplib_cq *cq, struct bnxt_qplib_cqe *cqe,
 void bnxt_qplib_req_notify_cq(struct bnxt_qplib_cq *cq, u32 arm_type);
 void bnxt_qplib_free_nq(struct bnxt_qplib_nq *nq);
 int bnxt_qplib_alloc_nq(struct pci_dev *pdev, struct bnxt_qplib_nq *nq);
+void bnxt_qplib_add_flush_qp(struct bnxt_qplib_qp *qp);
+void bnxt_qplib_del_flush_qp(struct bnxt_qplib_qp *qp);
+int bnxt_qplib_process_flush_list(struct bnxt_qplib_cq *cq,
+				  struct bnxt_qplib_cqe *cqe,
+				  int num_cqes);
 #endif /* __BNXT_QPLIB_FP_H__ */
diff --git a/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c b/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c
index 16e4275..d88b5de 100644
--- a/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c
+++ b/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c
@@ -507,6 +507,7 @@ int bnxt_qplib_init_rcfw(struct bnxt_qplib_rcfw *rcfw,
 
 void bnxt_qplib_free_rcfw_channel(struct bnxt_qplib_rcfw *rcfw)
 {
+	kfree(rcfw->qp_tbl);
 	kfree(rcfw->crsqe_tbl);
 	bnxt_qplib_free_hwq(rcfw->pdev, &rcfw->cmdq);
 	bnxt_qplib_free_hwq(rcfw->pdev, &rcfw->creq);
@@ -514,7 +515,8 @@ void bnxt_qplib_free_rcfw_channel(struct bnxt_qplib_rcfw *rcfw)
 }
 
 int bnxt_qplib_alloc_rcfw_channel(struct pci_dev *pdev,
-				  struct bnxt_qplib_rcfw *rcfw)
+				  struct bnxt_qplib_rcfw *rcfw,
+				  int qp_tbl_sz)
 {
 	rcfw->pdev = pdev;
 	rcfw->creq.max_elements = BNXT_QPLIB_CREQE_MAX_CNT;
@@ -541,6 +543,12 @@ int bnxt_qplib_alloc_rcfw_channel(struct pci_dev *pdev,
 	if (!rcfw->crsqe_tbl)
 		goto fail;
 
+	rcfw->qp_tbl_size = qp_tbl_sz;
+	rcfw->qp_tbl = kcalloc(qp_tbl_sz, sizeof(struct bnxt_qplib_qp_node),
+			       GFP_KERNEL);
+	if (!rcfw->qp_tbl)
+		goto fail;
+
 	return 0;
 
 fail:
diff --git a/drivers/infiniband/hw/bnxt_re/qplib_rcfw.h b/drivers/infiniband/hw/bnxt_re/qplib_rcfw.h
index 09ce121..0ed312f 100644
--- a/drivers/infiniband/hw/bnxt_re/qplib_rcfw.h
+++ b/drivers/infiniband/hw/bnxt_re/qplib_rcfw.h
@@ -148,6 +148,11 @@ struct bnxt_qplib_rcfw_sbuf {
 	u32 size;
 };
 
+struct bnxt_qplib_qp_node {
+	u32 qp_id;              /* QP id */
+	void *qp_handle;        /* ptr to qplib_qp */
+};
+
 /* RCFW Communication Channels */
 struct bnxt_qplib_rcfw {
 	struct pci_dev		*pdev;
@@ -181,11 +186,13 @@ struct bnxt_qplib_rcfw {
 	/* Actual Cmd and Resp Queues */
 	struct bnxt_qplib_hwq	cmdq;
 	struct bnxt_qplib_crsq	*crsqe_tbl;
+	int qp_tbl_size;
+	struct bnxt_qplib_qp_node *qp_tbl;
 };
 
 void bnxt_qplib_free_rcfw_channel(struct bnxt_qplib_rcfw *rcfw);
 int bnxt_qplib_alloc_rcfw_channel(struct pci_dev *pdev,
-				  struct bnxt_qplib_rcfw *rcfw);
+				  struct bnxt_qplib_rcfw *rcfw, int qp_tbl_sz);
 void bnxt_qplib_disable_rcfw_channel(struct bnxt_qplib_rcfw *rcfw);
 int bnxt_qplib_enable_rcfw_channel(struct pci_dev *pdev,
 				   struct bnxt_qplib_rcfw *rcfw,
@@ -207,4 +214,5 @@ int bnxt_qplib_rcfw_send_message(struct bnxt_qplib_rcfw *rcfw,
 int bnxt_qplib_deinit_rcfw(struct bnxt_qplib_rcfw *rcfw);
 int bnxt_qplib_init_rcfw(struct bnxt_qplib_rcfw *rcfw,
 			 struct bnxt_qplib_ctx *ctx, int is_virtfn);
+void bnxt_qplib_mark_qp_error(void *qp_handle);
 #endif /* __BNXT_QPLIB_RCFW_H__ */
-- 
2.5.5

--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH for-next 10/13] RDMA/bnxt_re: Enable atomics only if host bios supports
       [not found] ` <1498065504-27902-1-git-send-email-selvin.xavier-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>
                     ` (8 preceding siblings ...)
  2017-06-21 17:18   ` [PATCH for-next 09/13] RDMA/bnxt_re: Allow posting when QPs are in error Selvin Xavier
@ 2017-06-21 17:18   ` Selvin Xavier
  2017-06-21 17:18   ` [PATCH for-next 11/13] RDMA/bnxt_re: Fix return value of poll routine Selvin Xavier
                     ` (2 subsequent siblings)
  12 siblings, 0 replies; 17+ messages in thread
From: Selvin Xavier @ 2017-06-21 17:18 UTC (permalink / raw)
  To: dledford-H+wXaHxf7aLQT0dZR+AlfA
  Cc: linux-rdma-u79uwXL29TY76Z2rM5mHXA, Devesh Sharma, Selvin Xavier

From: Devesh Sharma <devesh.sharma-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>

Driver shall check if the host system bios has enabled
Atomic operations capability in PCI Device Control 2
register of the pci-device. Expose the ATOMIC_HCA
flag only if the Atomic operations capability is set.

Signed-off-by: Devesh Sharma <devesh.sharma-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>
Signed-off-by: Selvin Xavier <selvin.xavier-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>
---
 drivers/infiniband/hw/bnxt_re/ib_verbs.c |  6 ++++--
 drivers/infiniband/hw/bnxt_re/qplib_sp.c | 14 ++++++++++++++
 drivers/infiniband/hw/bnxt_re/qplib_sp.h |  3 +++
 3 files changed, 21 insertions(+), 2 deletions(-)

diff --git a/drivers/infiniband/hw/bnxt_re/ib_verbs.c b/drivers/infiniband/hw/bnxt_re/ib_verbs.c
index e7d667f..5653467 100644
--- a/drivers/infiniband/hw/bnxt_re/ib_verbs.c
+++ b/drivers/infiniband/hw/bnxt_re/ib_verbs.c
@@ -173,8 +173,10 @@ int bnxt_re_query_device(struct ib_device *ibdev,
 	ib_attr->max_pd = dev_attr->max_pd;
 	ib_attr->max_qp_rd_atom = dev_attr->max_qp_rd_atom;
 	ib_attr->max_qp_init_rd_atom = dev_attr->max_qp_init_rd_atom;
-	ib_attr->atomic_cap = IB_ATOMIC_HCA;
-	ib_attr->masked_atomic_cap = IB_ATOMIC_HCA;
+	if (dev_attr->is_atomic) {
+		ib_attr->atomic_cap = IB_ATOMIC_HCA;
+		ib_attr->masked_atomic_cap = IB_ATOMIC_HCA;
+	}
 
 	ib_attr->max_ee_rd_atom = 0;
 	ib_attr->max_res_rd_atom = 0;
diff --git a/drivers/infiniband/hw/bnxt_re/qplib_sp.c b/drivers/infiniband/hw/bnxt_re/qplib_sp.c
index 33c04a0..e277e54 100644
--- a/drivers/infiniband/hw/bnxt_re/qplib_sp.c
+++ b/drivers/infiniband/hw/bnxt_re/qplib_sp.c
@@ -51,6 +51,19 @@ const struct bnxt_qplib_gid bnxt_qplib_gid_zero = {{ 0, 0, 0, 0, 0, 0, 0, 0,
 						     0, 0, 0, 0, 0, 0, 0, 0 } };
 
 /* Device */
+
+static bool bnxt_qplib_is_atomic_cap(struct bnxt_qplib_rcfw *rcfw)
+{
+	int rc;
+	u16 pcie_ctl2;
+
+	rc = pcie_capability_read_word(rcfw->pdev, PCI_EXP_DEVCTL2,
+				       &pcie_ctl2);
+	if (rc)
+		return false;
+	return !!(pcie_ctl2 & PCI_EXP_DEVCTL2_ATOMIC_REQ);
+}
+
 int bnxt_qplib_get_dev_attr(struct bnxt_qplib_rcfw *rcfw,
 			    struct bnxt_qplib_dev_attr *attr)
 {
@@ -131,6 +144,7 @@ int bnxt_qplib_get_dev_attr(struct bnxt_qplib_rcfw *rcfw,
 		attr->tqm_alloc_reqs[i * 4 + 3] = *(++tqm_alloc);
 	}
 
+	attr->is_atomic = bnxt_qplib_is_atomic_cap(rcfw);
 bail:
 	bnxt_qplib_rcfw_free_sbuf(rcfw, sbuf);
 	return rc;
diff --git a/drivers/infiniband/hw/bnxt_re/qplib_sp.h b/drivers/infiniband/hw/bnxt_re/qplib_sp.h
index e3a3ed9..1132258 100644
--- a/drivers/infiniband/hw/bnxt_re/qplib_sp.h
+++ b/drivers/infiniband/hw/bnxt_re/qplib_sp.h
@@ -42,6 +42,8 @@
 
 #define BNXT_QPLIB_RESERVED_QP_WRS	128
 
+#define PCI_EXP_DEVCTL2_ATOMIC_REQ      0x0040
+
 struct bnxt_qplib_dev_attr {
 	char				fw_ver[32];
 	u16				max_sgid;
@@ -70,6 +72,7 @@ struct bnxt_qplib_dev_attr {
 	u32				max_inline_data;
 	u32				l2_db_size;
 	u8				tqm_alloc_reqs[MAX_TQM_ALLOC_REQ];
+	bool				is_atomic;
 };
 
 struct bnxt_qplib_pd {
-- 
2.5.5

--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH for-next 11/13] RDMA/bnxt_re: Fix return value of poll routine
       [not found] ` <1498065504-27902-1-git-send-email-selvin.xavier-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>
                     ` (9 preceding siblings ...)
  2017-06-21 17:18   ` [PATCH for-next 10/13] RDMA/bnxt_re: Enable atomics only if host bios supports Selvin Xavier
@ 2017-06-21 17:18   ` Selvin Xavier
       [not found]     ` <1498065504-27902-12-git-send-email-selvin.xavier-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>
  2017-06-21 17:18   ` [PATCH for-next 12/13] RDMA/bnxt_re: Report MISSED_EVENTS in req_notify_cq Selvin Xavier
  2017-06-21 17:18   ` [PATCH for-next 13/13] RDMA/bnxt_re: Fix the value reported for local ack delay Selvin Xavier
  12 siblings, 1 reply; 17+ messages in thread
From: Selvin Xavier @ 2017-06-21 17:18 UTC (permalink / raw)
  To: dledford-H+wXaHxf7aLQT0dZR+AlfA
  Cc: linux-rdma-u79uwXL29TY76Z2rM5mHXA, Devesh Sharma, Selvin Xavier

From: Devesh Sharma <devesh.sharma-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>

Fix the incorrect reporting of number of polled
entries by taking into account the max CQ depth
in the driver.

Signed-off-by: Devesh Sharma <devesh.sharma-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>
Signed-off-by: Selvin Xavier <selvin.xavier-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>
---
 drivers/infiniband/hw/bnxt_re/ib_verbs.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/infiniband/hw/bnxt_re/ib_verbs.c b/drivers/infiniband/hw/bnxt_re/ib_verbs.c
index 5653467..27893f7 100644
--- a/drivers/infiniband/hw/bnxt_re/ib_verbs.c
+++ b/drivers/infiniband/hw/bnxt_re/ib_verbs.c
@@ -2903,6 +2903,7 @@ int bnxt_re_poll_cq(struct ib_cq *ib_cq, int num_entries, struct ib_wc *wc)
 
 	spin_lock_irqsave(&cq->cq_lock, flags);
 	budget = min_t(u32, num_entries, cq->max_cql);
+	num_entries = budget;
 	if (!cq->cql) {
 		dev_err(rdev_to_dev(cq->rdev), "POLL CQ : no CQL to use");
 		goto exit;
-- 
2.5.5

--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH for-next 12/13] RDMA/bnxt_re: Report MISSED_EVENTS in req_notify_cq
       [not found] ` <1498065504-27902-1-git-send-email-selvin.xavier-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>
                     ` (10 preceding siblings ...)
  2017-06-21 17:18   ` [PATCH for-next 11/13] RDMA/bnxt_re: Fix return value of poll routine Selvin Xavier
@ 2017-06-21 17:18   ` Selvin Xavier
  2017-06-21 17:18   ` [PATCH for-next 13/13] RDMA/bnxt_re: Fix the value reported for local ack delay Selvin Xavier
  12 siblings, 0 replies; 17+ messages in thread
From: Selvin Xavier @ 2017-06-21 17:18 UTC (permalink / raw)
  To: dledford-H+wXaHxf7aLQT0dZR+AlfA
  Cc: linux-rdma-u79uwXL29TY76Z2rM5mHXA, Selvin Xavier

While invoking the req_notify_cq hook, ULPs can request
whether the CQs have any CQEs pending. If CQEs are pending,
drivers can indicate  it by returning 1 for req_notify_cq.
The stack will poll CQ again till CQ is empty.

This patch peeks the CQ for any valid entries and return accordingly.

Signed-off-by: Selvin Xavier <selvin.xavier-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>
---
 drivers/infiniband/hw/bnxt_re/ib_verbs.c |  5 +++++
 drivers/infiniband/hw/bnxt_re/qplib_fp.c | 19 +++++++++++++++++++
 drivers/infiniband/hw/bnxt_re/qplib_fp.h |  1 +
 3 files changed, 25 insertions(+)

diff --git a/drivers/infiniband/hw/bnxt_re/ib_verbs.c b/drivers/infiniband/hw/bnxt_re/ib_verbs.c
index 27893f7..2cfcd38 100644
--- a/drivers/infiniband/hw/bnxt_re/ib_verbs.c
+++ b/drivers/infiniband/hw/bnxt_re/ib_verbs.c
@@ -3034,6 +3034,11 @@ int bnxt_re_req_notify_cq(struct ib_cq *ib_cq,
 	else if (ib_cqn_flags & IB_CQ_SOLICITED)
 		type = DBR_DBR_TYPE_CQ_ARMSE;
 
+	/* Poll to see if there are missed events */
+	if ((ib_cqn_flags & IB_CQ_REPORT_MISSED_EVENTS) &&
+	    !(bnxt_qplib_is_cq_empty(&cq->qplib_cq)))
+		return 1;
+
 	bnxt_qplib_req_notify_cq(&cq->qplib_cq, type);
 
 	return 0;
diff --git a/drivers/infiniband/hw/bnxt_re/qplib_fp.c b/drivers/infiniband/hw/bnxt_re/qplib_fp.c
index 5c144ce..1daea3d 100644
--- a/drivers/infiniband/hw/bnxt_re/qplib_fp.c
+++ b/drivers/infiniband/hw/bnxt_re/qplib_fp.c
@@ -2104,6 +2104,25 @@ static int bnxt_qplib_cq_process_res_ud(struct bnxt_qplib_cq *cq,
 	return rc;
 }
 
+bool bnxt_qplib_is_cq_empty(struct bnxt_qplib_cq *cq)
+{
+	struct cq_base *hw_cqe, **hw_cqe_ptr;
+	unsigned long flags;
+	u32 sw_cons, raw_cons;
+	bool rc = true;
+
+	spin_lock_irqsave(&cq->hwq.lock, flags);
+	raw_cons = cq->hwq.cons;
+	sw_cons = HWQ_CMP(raw_cons, &cq->hwq);
+	hw_cqe_ptr = (struct cq_base **)cq->hwq.pbl_ptr;
+	hw_cqe = &hw_cqe_ptr[CQE_PG(sw_cons)][CQE_IDX(sw_cons)];
+
+	 /* Check for Valid bit. If the CQE is valid, return false */
+	rc = !CQE_CMP_VALID(hw_cqe, raw_cons, cq->hwq.max_elements);
+	spin_unlock_irqrestore(&cq->hwq.lock, flags);
+	return rc;
+}
+
 static int bnxt_qplib_cq_process_res_raweth_qp1(struct bnxt_qplib_cq *cq,
 						struct cq_res_raweth_qp1 *hwcqe,
 						struct bnxt_qplib_cqe **pcqe,
diff --git a/drivers/infiniband/hw/bnxt_re/qplib_fp.h b/drivers/infiniband/hw/bnxt_re/qplib_fp.h
index 18abe40..465c0d1 100644
--- a/drivers/infiniband/hw/bnxt_re/qplib_fp.h
+++ b/drivers/infiniband/hw/bnxt_re/qplib_fp.h
@@ -464,6 +464,7 @@ int bnxt_qplib_create_cq(struct bnxt_qplib_res *res, struct bnxt_qplib_cq *cq);
 int bnxt_qplib_destroy_cq(struct bnxt_qplib_res *res, struct bnxt_qplib_cq *cq);
 int bnxt_qplib_poll_cq(struct bnxt_qplib_cq *cq, struct bnxt_qplib_cqe *cqe,
 		       int num, struct bnxt_qplib_qp **qp);
+bool bnxt_qplib_is_cq_empty(struct bnxt_qplib_cq *cq);
 void bnxt_qplib_req_notify_cq(struct bnxt_qplib_cq *cq, u32 arm_type);
 void bnxt_qplib_free_nq(struct bnxt_qplib_nq *nq);
 int bnxt_qplib_alloc_nq(struct pci_dev *pdev, struct bnxt_qplib_nq *nq);
-- 
2.5.5

--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH for-next 13/13] RDMA/bnxt_re: Fix the value reported for local ack delay
       [not found] ` <1498065504-27902-1-git-send-email-selvin.xavier-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>
                     ` (11 preceding siblings ...)
  2017-06-21 17:18   ` [PATCH for-next 12/13] RDMA/bnxt_re: Report MISSED_EVENTS in req_notify_cq Selvin Xavier
@ 2017-06-21 17:18   ` Selvin Xavier
  12 siblings, 0 replies; 17+ messages in thread
From: Selvin Xavier @ 2017-06-21 17:18 UTC (permalink / raw)
  To: dledford-H+wXaHxf7aLQT0dZR+AlfA
  Cc: linux-rdma-u79uwXL29TY76Z2rM5mHXA, Selvin Xavier

Local ack delay exposed by the driver is 0 which means infinite QP
timeout. Reporting the default value to 16 (approx 260ms)

Signed-off-by: Selvin Xavier <selvin.xavier-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>
---
 drivers/infiniband/hw/bnxt_re/bnxt_re.h  | 7 +++++++
 drivers/infiniband/hw/bnxt_re/ib_verbs.c | 2 +-
 2 files changed, 8 insertions(+), 1 deletion(-)

diff --git a/drivers/infiniband/hw/bnxt_re/bnxt_re.h b/drivers/infiniband/hw/bnxt_re/bnxt_re.h
index 30bff05..c1c9e62 100644
--- a/drivers/infiniband/hw/bnxt_re/bnxt_re.h
+++ b/drivers/infiniband/hw/bnxt_re/bnxt_re.h
@@ -62,6 +62,13 @@
 
 #define BNXT_RE_RQ_WQE_THRESHOLD	32
 
+/*
+ * Setting the default ack delay value to 16, which means
+ * the default timeout is approx. 260ms(4 usec * 2 ^(timeout))
+ */
+
+#define BNXT_RE_DEFAULT_ACK_DELAY	16
+
 struct bnxt_re_work {
 	struct work_struct	work;
 	unsigned long		event;
diff --git a/drivers/infiniband/hw/bnxt_re/ib_verbs.c b/drivers/infiniband/hw/bnxt_re/ib_verbs.c
index 2cfcd38..1eff59d 100644
--- a/drivers/infiniband/hw/bnxt_re/ib_verbs.c
+++ b/drivers/infiniband/hw/bnxt_re/ib_verbs.c
@@ -201,7 +201,7 @@ int bnxt_re_query_device(struct ib_device *ibdev,
 	ib_attr->max_fast_reg_page_list_len = MAX_PBL_LVL_1_PGS;
 
 	ib_attr->max_pkeys = 1;
-	ib_attr->local_ca_ack_delay = 0;
+	ib_attr->local_ca_ack_delay = BNXT_RE_DEFAULT_ACK_DELAY;
 	return 0;
 }
 
-- 
2.5.5

--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 17+ messages in thread

* Re: [PATCH for-next 09/13] RDMA/bnxt_re: Allow posting when QPs are in error
       [not found]     ` <1498065504-27902-10-git-send-email-selvin.xavier-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>
@ 2017-06-22  5:40       ` Leon Romanovsky
       [not found]         ` <20170622054010.GL1248-U/DQcQFIOTAAJjI8aNfphQ@public.gmane.org>
  0 siblings, 1 reply; 17+ messages in thread
From: Leon Romanovsky @ 2017-06-22  5:40 UTC (permalink / raw)
  To: Selvin Xavier
  Cc: dledford-H+wXaHxf7aLQT0dZR+AlfA,
	linux-rdma-u79uwXL29TY76Z2rM5mHXA, Sriharsha Basavapatna

[-- Attachment #1: Type: text/plain, Size: 32075 bytes --]

On Wed, Jun 21, 2017 at 10:18:20AM -0700, Selvin Xavier wrote:
> This  patch allows driver to post send and receive
> requests on QPs which are in  error state.
>
> Instead of flushing the QP in the context of polling
> error CQEs, the QPs will be added to a flush list
> maintained per CQ. QP state is moved to error.
> QP is added to flush list if the user moves it
> to error state using modify_qp also. After polling the HW
> CQ in poll_cq routine, this flush list is traversed
> and driver completes work requests each QP in the flush
> list, till the budget expires. The QP is moved out of
> flush list during QP destroy or during modify_QP to RESET.
>
> When ULPs post Work Requests while QP is in error state,
> driver will store the ULP data and then increments the
> QP producer s/w index, without ringing doorbell. It then
> schedules a worker to invoke the CQ handler since the
> interrupts wont be generated from the HW for this request.
>
> Signed-off-by: Sriharsha Basavapatna <sriharsha.basavapatna-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>
> Signed-off-by: Selvin Xavier <selvin.xavier-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>
> ---
>  drivers/infiniband/hw/bnxt_re/ib_verbs.c   |  22 ++
>  drivers/infiniband/hw/bnxt_re/main.c       |   3 +-
>  drivers/infiniband/hw/bnxt_re/qplib_fp.c   | 411 ++++++++++++++++++++++-------
>  drivers/infiniband/hw/bnxt_re/qplib_fp.h   |  22 +-
>  drivers/infiniband/hw/bnxt_re/qplib_rcfw.c |  10 +-
>  drivers/infiniband/hw/bnxt_re/qplib_rcfw.h |  10 +-
>  6 files changed, 383 insertions(+), 95 deletions(-)
>
> diff --git a/drivers/infiniband/hw/bnxt_re/ib_verbs.c b/drivers/infiniband/hw/bnxt_re/ib_verbs.c
> index 6629727..e7d667f 100644
> --- a/drivers/infiniband/hw/bnxt_re/ib_verbs.c
> +++ b/drivers/infiniband/hw/bnxt_re/ib_verbs.c
> @@ -829,6 +829,7 @@ int bnxt_re_destroy_qp(struct ib_qp *ib_qp)
>  	struct bnxt_re_dev *rdev = qp->rdev;
>  	int rc;
>
> +	bnxt_qplib_del_flush_qp(&qp->qplib_qp);
>  	rc = bnxt_qplib_destroy_qp(&rdev->qplib_res, &qp->qplib_qp);
>  	if (rc) {
>  		dev_err(rdev_to_dev(rdev), "Failed to destroy HW QP");
> @@ -843,6 +844,7 @@ int bnxt_re_destroy_qp(struct ib_qp *ib_qp)
>  			return rc;
>  		}
>
> +		bnxt_qplib_del_flush_qp(&qp->qplib_qp);
>  		rc = bnxt_qplib_destroy_qp(&rdev->qplib_res,
>  					   &rdev->qp1_sqp->qplib_qp);
>  		if (rc) {
> @@ -1387,6 +1389,21 @@ int bnxt_re_modify_qp(struct ib_qp *ib_qp, struct ib_qp_attr *qp_attr,
>  		}
>  		qp->qplib_qp.modify_flags |= CMDQ_MODIFY_QP_MODIFY_MASK_STATE;
>  		qp->qplib_qp.state = __from_ib_qp_state(qp_attr->qp_state);
> +
> +		if (!qp->sumem &&
> +		    qp->qplib_qp.state == CMDQ_MODIFY_QP_NEW_STATE_ERR) {
> +			dev_dbg(rdev_to_dev(rdev),
> +				"Move QP = %p to flush list\n",
> +				qp);
> +			bnxt_qplib_add_flush_qp(&qp->qplib_qp);
> +		}
> +		if (!qp->sumem &&
> +		    qp->qplib_qp.state == CMDQ_MODIFY_QP_NEW_STATE_RESET) {
> +			dev_dbg(rdev_to_dev(rdev),
> +				"Move QP = %p out of flush list\n",
> +				qp);
> +			bnxt_qplib_del_flush_qp(&qp->qplib_qp);
> +		}
>  	}
>  	if (qp_attr_mask & IB_QP_EN_SQD_ASYNC_NOTIFY) {
>  		qp->qplib_qp.modify_flags |=
> @@ -2397,6 +2414,7 @@ struct ib_cq *bnxt_re_create_cq(struct ib_device *ibdev,
>  	}
>  	cq->qplib_cq.max_wqe = entries;
>  	cq->qplib_cq.cnq_hw_ring_id = rdev->nq.ring_id;
> +	cq->qplib_cq.nq	= &rdev->nq;
>
>  	rc = bnxt_qplib_create_cq(&rdev->qplib_res, &cq->qplib_cq);
>  	if (rc) {
> @@ -2903,6 +2921,10 @@ int bnxt_re_poll_cq(struct ib_cq *ib_cq, int num_entries, struct ib_wc *wc)
>  					sq->send_phantom = false;
>  			}
>  		}
> +		if (ncqe < budget)
> +			ncqe += bnxt_qplib_process_flush_list(&cq->qplib_cq,
> +							      cqe + ncqe,
> +							      budget - ncqe);
>
>  		if (!ncqe)
>  			break;
> diff --git a/drivers/infiniband/hw/bnxt_re/main.c b/drivers/infiniband/hw/bnxt_re/main.c
> index c067b9c..ec9fc0b 100644
> --- a/drivers/infiniband/hw/bnxt_re/main.c
> +++ b/drivers/infiniband/hw/bnxt_re/main.c
> @@ -1045,7 +1045,8 @@ static int bnxt_re_ib_reg(struct bnxt_re_dev *rdev)
>  	/* Establish RCFW Communication Channel to initialize the context
>  	 * memory for the function and all child VFs
>  	 */
> -	rc = bnxt_qplib_alloc_rcfw_channel(rdev->en_dev->pdev, &rdev->rcfw);
> +	rc = bnxt_qplib_alloc_rcfw_channel(rdev->en_dev->pdev, &rdev->rcfw,
> +					   BNXT_RE_MAX_QPC_COUNT);
>  	if (rc)
>  		goto fail;
>
> diff --git a/drivers/infiniband/hw/bnxt_re/qplib_fp.c b/drivers/infiniband/hw/bnxt_re/qplib_fp.c
> index 8ef39df..5c144ce 100644
> --- a/drivers/infiniband/hw/bnxt_re/qplib_fp.c
> +++ b/drivers/infiniband/hw/bnxt_re/qplib_fp.c
> @@ -52,6 +52,114 @@
>
>  static void bnxt_qplib_arm_cq_enable(struct bnxt_qplib_cq *cq);
>
> +/* Flush list */
> +
> +/* To avoid processing completions if QP is already in flush list */
> +static bool bnxt_qplib_is_qp_in_rq_flushlist(struct bnxt_qplib_qp *qp)
> +{
> +	bool flushed = false;
> +	unsigned long flags;
> +
> +	spin_lock_irqsave(&qp->rcq->flush_lock, flags);
> +	flushed = qp->rq.flushed;
> +	spin_unlock_irqrestore(&qp->rcq->flush_lock, flags);
> +	return flushed;
> +}
> +
> +static bool bnxt_qplib_is_qp_in_sq_flushlist(struct bnxt_qplib_qp *qp)
> +{
> +	bool flushed = false;
> +	unsigned long flags;
> +
> +	spin_lock_irqsave(&qp->scq->flush_lock, flags);
> +	flushed = qp->sq.flushed;
> +	spin_unlock_irqrestore(&qp->scq->flush_lock, flags);
> +	return flushed;

I don't really understand the lock/unlock here. What exactly do you
protect? Is it the change of "flushed"? It can be and will be worthless
immediately after your unlock.

You should protect the whole flow which depends on your "flushed".

> +}
> +
> +static void bnxt_qplib_cancel_phantom_processing(struct bnxt_qplib_qp *qp)
> +{
> +	qp->sq.condition = false;
> +	qp->sq.send_phantom = false;
> +	qp->sq.single = false;
> +}
> +
> +void bnxt_qplib_add_flush_qp(struct bnxt_qplib_qp *qp)
> +{
> +	struct bnxt_qplib_cq *scq, *rcq;
> +	unsigned long flags;
> +
> +	scq = qp->scq;
> +	rcq = qp->rcq;
> +
> +	spin_lock_irqsave(&scq->flush_lock, flags);
> +	if (!qp->sq.flushed) {
> +		dev_dbg(&scq->hwq.pdev->dev,
> +			"QPLIB: FP: Adding to SQ Flush list = %p",
> +			qp);
> +		bnxt_qplib_cancel_phantom_processing(qp);
> +		list_add_tail(&qp->sq_flush, &scq->sqf_head);
> +		qp->sq.flushed = true;
> +	}
> +	spin_unlock_irqrestore(&scq->flush_lock, flags);
> +	if (!qp->srq) {
> +		spin_lock_irqsave(&rcq->flush_lock, flags);
> +		if (!qp->rq.flushed) {
> +			dev_dbg(&rcq->hwq.pdev->dev,
> +				"QPLIB: FP: Adding to RQ Flush list = %p",
> +				qp);
> +			list_add_tail(&qp->rq_flush, &rcq->rqf_head);
> +			qp->rq.flushed = true;
> +		}
> +		spin_unlock_irqrestore(&rcq->flush_lock, flags);
> +	}
> +}
> +
> +void bnxt_qplib_del_flush_qp(struct bnxt_qplib_qp *qp)
> +{
> +	struct bnxt_qplib_cq *scq, *rcq;
> +	unsigned long flags;
> +
> +	scq = qp->scq;
> +	rcq = qp->rcq;
> +
> +	spin_lock_irqsave(&scq->flush_lock, flags);
> +	if (qp->sq.flushed) {
> +		qp->sq.flushed = false;
> +		list_del(&qp->sq_flush);
> +	}
> +	spin_unlock_irqrestore(&scq->flush_lock, flags);
> +	if (!qp->srq) {
> +		spin_lock_irqsave(&rcq->flush_lock, flags);
> +		if (qp->rq.flushed) {
> +			qp->rq.flushed = false;
> +			list_del(&qp->rq_flush);
> +		}
> +		spin_unlock_irqrestore(&rcq->flush_lock, flags);
> +	}
> +}
> +
> +static void bnxt_qpn_cqn_sched_task(struct work_struct *work)
> +{
> +	struct bnxt_qplib_nq_work *nq_work =
> +			container_of(work, struct bnxt_qplib_nq_work, work);
> +
> +	struct bnxt_qplib_cq *cq = nq_work->cq;
> +	struct bnxt_qplib_nq *nq = nq_work->nq;
> +
> +	if (cq && nq) {
> +		spin_lock_bh(&cq->compl_lock);
> +		if (atomic_read(&cq->arm_state) && nq->cqn_handler) {
> +			dev_dbg(&nq->pdev->dev,
> +				"%s:Trigger cq  = %p event nq = %p\n",
> +				__func__, cq, nq);
> +			nq->cqn_handler(nq, cq);
> +		}
> +		spin_unlock_bh(&cq->compl_lock);
> +	}
> +	kfree(nq_work);
> +}
> +
>  static void bnxt_qplib_free_qp_hdr_buf(struct bnxt_qplib_res *res,
>  				       struct bnxt_qplib_qp *qp)
>  {
> @@ -119,6 +227,7 @@ static void bnxt_qplib_service_nq(unsigned long data)
>  	struct bnxt_qplib_nq *nq = (struct bnxt_qplib_nq *)data;
>  	struct bnxt_qplib_hwq *hwq = &nq->hwq;
>  	struct nq_base *nqe, **nq_ptr;
> +	struct bnxt_qplib_cq *cq;
>  	int num_cqne_processed = 0;
>  	u32 sw_cons, raw_cons;
>  	u16 type;
> @@ -143,15 +252,17 @@ static void bnxt_qplib_service_nq(unsigned long data)
>  			q_handle = le32_to_cpu(nqcne->cq_handle_low);
>  			q_handle |= (u64)le32_to_cpu(nqcne->cq_handle_high)
>  						     << 32;
> -			bnxt_qplib_arm_cq_enable((struct bnxt_qplib_cq *)
> -						 ((unsigned long)q_handle));
> -			if (!nq->cqn_handler(nq, (struct bnxt_qplib_cq *)
> -						 ((unsigned long)q_handle)))
> +			cq = (struct bnxt_qplib_cq *)(unsigned long)q_handle;
> +			bnxt_qplib_arm_cq_enable(cq);
> +			spin_lock_bh(&cq->compl_lock);
> +			atomic_set(&cq->arm_state, 0);
> +			if (!nq->cqn_handler(nq, (cq)))
>  				num_cqne_processed++;
>  			else
>  				dev_warn(&nq->pdev->dev,
>  					 "QPLIB: cqn - type 0x%x not handled",
>  					 type);
> +			spin_unlock_bh(&cq->compl_lock);
>  			break;
>  		}
>  		case NQ_BASE_TYPE_DBQ_EVENT:
> @@ -190,6 +301,10 @@ static irqreturn_t bnxt_qplib_nq_irq(int irq, void *dev_instance)
>
>  void bnxt_qplib_disable_nq(struct bnxt_qplib_nq *nq)
>  {
> +	if (nq->cqn_wq) {
> +		destroy_workqueue(nq->cqn_wq);
> +		nq->cqn_wq = NULL;
> +	}
>  	/* Make sure the HW is stopped! */
>  	synchronize_irq(nq->vector);
>  	tasklet_disable(&nq->worker);
> @@ -216,7 +331,7 @@ int bnxt_qplib_enable_nq(struct pci_dev *pdev, struct bnxt_qplib_nq *nq,
>  					     void *, u8 event))
>  {
>  	resource_size_t nq_base;
> -	int rc;
> +	int rc = -1;
>
>  	nq->pdev = pdev;
>  	nq->vector = msix_vector;
> @@ -227,6 +342,11 @@ int bnxt_qplib_enable_nq(struct pci_dev *pdev, struct bnxt_qplib_nq *nq,
>
>  	tasklet_init(&nq->worker, bnxt_qplib_service_nq, (unsigned long)nq);
>
> +	/* Have a task to schedule CQ notifiers in post send case */
> +	nq->cqn_wq  = create_singlethread_workqueue("bnxt_qplib_nq");
> +	if (!nq->cqn_wq)
> +		goto fail;
> +
>  	nq->requested = false;
>  	rc = request_irq(nq->vector, bnxt_qplib_nq_irq, 0, "bnxt_qplib_nq", nq);
>  	if (rc) {
> @@ -401,8 +521,8 @@ int bnxt_qplib_create_qp1(struct bnxt_qplib_res *res, struct bnxt_qplib_qp *qp)
>
>  	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;
> +	rcfw->qp_tbl[qp->id].qp_id = qp->id;
> +	rcfw->qp_tbl[qp->id].qp_handle = (void *)qp;
>
>  	return 0;
>
> @@ -615,8 +735,10 @@ int bnxt_qplib_create_qp(struct bnxt_qplib_res *res, struct bnxt_qplib_qp *qp)
>
>  	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;
> +	INIT_LIST_HEAD(&qp->sq_flush);
> +	INIT_LIST_HEAD(&qp->rq_flush);
> +	rcfw->qp_tbl[qp->id].qp_id = qp->id;
> +	rcfw->qp_tbl[qp->id].qp_handle = (void *)qp;
>
>  	return 0;
>
> @@ -963,13 +1085,19 @@ int bnxt_qplib_destroy_qp(struct bnxt_qplib_res *res,
>  	u16 cmd_flags = 0;
>  	int rc;
>
> +	rcfw->qp_tbl[qp->id].qp_id = BNXT_QPLIB_QP_ID_INVALID;
> +	rcfw->qp_tbl[qp->id].qp_handle = NULL;
> +
>  	RCFW_CMD_PREP(req, DESTROY_QP, cmd_flags);
>
>  	req.qp_cid = cpu_to_le32(qp->id);
>  	rc = bnxt_qplib_rcfw_send_message(rcfw, (void *)&req,
>  					  (void *)&resp, NULL, 0);
> -	if (rc)
> +	if (rc) {
> +		rcfw->qp_tbl[qp->id].qp_id = qp->id;
> +		rcfw->qp_tbl[qp->id].qp_handle = qp;
>  		return rc;
> +	}
>
>  	/* Must walk the associated CQs to nullified the QP ptr */
>  	spin_lock_irqsave(&qp->scq->hwq.lock, flags);
> @@ -1074,14 +1202,21 @@ int bnxt_qplib_post_send(struct bnxt_qplib_qp *qp,
>  	struct bnxt_qplib_swq *swq;
>  	struct sq_send *hw_sq_send_hdr, **hw_sq_send_ptr;
>  	struct sq_sge *hw_sge;
> +	struct bnxt_qplib_nq_work *nq_work = NULL;
> +	bool sch_handler = false;
>  	u32 sw_prod;
>  	u8 wqe_size16;
>  	int i, rc = 0, data_len = 0, pkt_num = 0;
>  	__le32 temp32;
>
>  	if (qp->state != CMDQ_MODIFY_QP_NEW_STATE_RTS) {
> -		rc = -EINVAL;
> -		goto done;
> +		if (qp->state == CMDQ_MODIFY_QP_NEW_STATE_ERR) {
> +			sch_handler = true;
> +			dev_dbg(&sq->hwq.pdev->dev,
> +				"%s Error QP. Scheduling for poll_cq\n",
> +				__func__);
> +			goto queue_err;
> +		}
>  	}
>
>  	if (bnxt_qplib_queue_full(sq)) {
> @@ -1301,12 +1436,35 @@ int bnxt_qplib_post_send(struct bnxt_qplib_qp *qp,
>  			((swq->next_psn << SQ_PSN_SEARCH_NEXT_PSN_SFT) &
>  			 SQ_PSN_SEARCH_NEXT_PSN_MASK));
>  	}
> -
> +queue_err:
> +	if (sch_handler) {
> +		/* Store the ULP info in the software structures */
> +		sw_prod = HWQ_CMP(sq->hwq.prod, &sq->hwq);
> +		swq = &sq->swq[sw_prod];
> +		swq->wr_id = wqe->wr_id;
> +		swq->type = wqe->type;
> +		swq->flags = wqe->flags;
> +		if (qp->sig_type)
> +			swq->flags |= SQ_SEND_FLAGS_SIGNAL_COMP;
> +		swq->start_psn = sq->psn & BTH_PSN_MASK;
> +	}
>  	sq->hwq.prod++;
> -
>  	qp->wqe_cnt++;
>
>  done:
> +	if (sch_handler) {
> +		nq_work = kzalloc(sizeof(*nq_work), GFP_ATOMIC);
> +		if (nq_work) {
> +			nq_work->cq = qp->scq;
> +			nq_work->nq = qp->scq->nq;
> +			INIT_WORK(&nq_work->work, bnxt_qpn_cqn_sched_task);
> +			queue_work(qp->scq->nq->cqn_wq, &nq_work->work);
> +		} else {
> +			dev_err(&sq->hwq.pdev->dev,
> +				"QPLIB: FP: Failed to allocate SQ nq_work!");
> +			rc = -ENOMEM;
> +		}
> +	}
>  	return rc;
>  }
>
> @@ -1334,15 +1492,17 @@ int bnxt_qplib_post_recv(struct bnxt_qplib_qp *qp,
>  	struct bnxt_qplib_q *rq = &qp->rq;
>  	struct rq_wqe *rqe, **rqe_ptr;
>  	struct sq_sge *hw_sge;
> +	struct bnxt_qplib_nq_work *nq_work = NULL;
> +	bool sch_handler = false;
>  	u32 sw_prod;
>  	int i, rc = 0;
>
>  	if (qp->state == CMDQ_MODIFY_QP_NEW_STATE_ERR) {
> -		dev_err(&rq->hwq.pdev->dev,
> -			"QPLIB: FP: QP (0x%x) is in the 0x%x state",
> -			qp->id, qp->state);
> -		rc = -EINVAL;
> -		goto done;
> +		sch_handler = true;
> +		dev_dbg(&rq->hwq.pdev->dev,
> +			"%s Error QP. Scheduling for poll_cq\n",
> +			__func__);
> +		goto queue_err;
>  	}
>  	if (bnxt_qplib_queue_full(rq)) {
>  		dev_err(&rq->hwq.pdev->dev,
> @@ -1378,7 +1538,27 @@ int bnxt_qplib_post_recv(struct bnxt_qplib_qp *qp,
>  	/* Supply the rqe->wr_id index to the wr_id_tbl for now */
>  	rqe->wr_id[0] = cpu_to_le32(sw_prod);
>
> +queue_err:
> +	if (sch_handler) {
> +		/* Store the ULP info in the software structures */
> +		sw_prod = HWQ_CMP(rq->hwq.prod, &rq->hwq);
> +		rq->swq[sw_prod].wr_id = wqe->wr_id;
> +	}
> +
>  	rq->hwq.prod++;
> +	if (sch_handler) {
> +		nq_work = kzalloc(sizeof(*nq_work), GFP_ATOMIC);
> +		if (nq_work) {
> +			nq_work->cq = qp->rcq;
> +			nq_work->nq = qp->rcq->nq;
> +			INIT_WORK(&nq_work->work, bnxt_qpn_cqn_sched_task);
> +			queue_work(qp->rcq->nq->cqn_wq, &nq_work->work);
> +		} else {
> +			dev_err(&rq->hwq.pdev->dev,
> +				"QPLIB: FP: Failed to allocate RQ nq_work!");
> +			rc = -ENOMEM;
> +		}
> +	}
>  done:
>  	return rc;
>  }
> @@ -1471,6 +1651,10 @@ int bnxt_qplib_create_cq(struct bnxt_qplib_res *res, struct bnxt_qplib_cq *cq)
>  	cq->dbr_base = res->dpi_tbl.dbr_bar_reg_iomem;
>  	cq->period = BNXT_QPLIB_QUEUE_START_PERIOD;
>  	init_waitqueue_head(&cq->waitq);
> +	INIT_LIST_HEAD(&cq->sqf_head);
> +	INIT_LIST_HEAD(&cq->rqf_head);
> +	spin_lock_init(&cq->flush_lock);
> +	spin_lock_init(&cq->compl_lock);
>
>  	bnxt_qplib_arm_cq_enable(cq);
>  	return 0;
> @@ -1513,9 +1697,13 @@ static int __flush_sq(struct bnxt_qplib_q *sq, struct bnxt_qplib_qp *qp,
>  	while (*budget) {
>  		sw_cons = HWQ_CMP(sq->hwq.cons, &sq->hwq);
>  		if (sw_cons == sw_prod) {
> -			sq->flush_in_progress = false;
>  			break;
>  		}
> +		/* Skip the FENCE WQE completions */
> +		if (sq->swq[sw_cons].wr_id == BNXT_QPLIB_FENCE_WRID) {
> +			bnxt_qplib_cancel_phantom_processing(qp);
> +			goto skip_compl;
> +		}
>  		memset(cqe, 0, sizeof(*cqe));
>  		cqe->status = CQ_REQ_STATUS_WORK_REQUEST_FLUSHED_ERR;
>  		cqe->opcode = CQ_BASE_CQE_TYPE_REQ;
> @@ -1525,6 +1713,7 @@ static int __flush_sq(struct bnxt_qplib_q *sq, struct bnxt_qplib_qp *qp,
>  		cqe->type = sq->swq[sw_cons].type;
>  		cqe++;
>  		(*budget)--;
> +skip_compl:
>  		sq->hwq.cons++;
>  	}
>  	*pcqe = cqe;
> @@ -1536,11 +1725,24 @@ static int __flush_sq(struct bnxt_qplib_q *sq, struct bnxt_qplib_qp *qp,
>  }
>
>  static int __flush_rq(struct bnxt_qplib_q *rq, struct bnxt_qplib_qp *qp,
> -		      int opcode, struct bnxt_qplib_cqe **pcqe, int *budget)
> +		      struct bnxt_qplib_cqe **pcqe, int *budget)
>  {
>  	struct bnxt_qplib_cqe *cqe;
>  	u32 sw_prod, sw_cons;
>  	int rc = 0;
> +	int opcode = 0;
> +
> +	switch (qp->type) {
> +	case CMDQ_CREATE_QP1_TYPE_GSI:
> +		opcode = CQ_BASE_CQE_TYPE_RES_RAWETH_QP1;
> +		break;
> +	case CMDQ_CREATE_QP_TYPE_RC:
> +		opcode = CQ_BASE_CQE_TYPE_RES_RC;
> +		break;
> +	case CMDQ_CREATE_QP_TYPE_UD:
> +		opcode = CQ_BASE_CQE_TYPE_RES_UD;
> +		break;
> +	}
>
>  	/* Flush the rest of the RQ */
>  	sw_prod = HWQ_CMP(rq->hwq.prod, &rq->hwq);
> @@ -1567,6 +1769,21 @@ static int __flush_rq(struct bnxt_qplib_q *rq, struct bnxt_qplib_qp *qp,
>  	return rc;
>  }
>
> +void bnxt_qplib_mark_qp_error(void *qp_handle)
> +{
> +	struct bnxt_qplib_qp *qp = qp_handle;
> +
> +	if (!qp)
> +		return;
> +
> +	/* Must block new posting of SQ and RQ */
> +	qp->state = CMDQ_MODIFY_QP_NEW_STATE_ERR;
> +	bnxt_qplib_cancel_phantom_processing(qp);
> +
> +	/* Add qp to flush list of the CQ */
> +	bnxt_qplib_add_flush_qp(qp);
> +}
> +
>  /* Note: SQE is valid from sw_sq_cons up to cqe_sq_cons (exclusive)
>   *       CQE is track from sw_cq_cons to max_element but valid only if VALID=1
>   */
> @@ -1694,10 +1911,12 @@ static int bnxt_qplib_cq_process_req(struct bnxt_qplib_cq *cq,
>  			cqe_sq_cons, sq->hwq.max_elements);
>  		return -EINVAL;
>  	}
> -	/* If we were in the middle of flushing the SQ, continue */
> -	if (sq->flush_in_progress)
> -		goto flush;
>
> +	if (bnxt_qplib_is_qp_in_sq_flushlist(qp)) {
> +		dev_dbg(&cq->hwq.pdev->dev,
> +			"%s: QPLIB: QP in Flush QP = %p\n", __func__, qp);
> +		goto done;
> +	}
>  	/* Require to walk the sq's swq to fabricate CQEs for all previously
>  	 * signaled SWQEs due to CQE aggregation from the current sq cons
>  	 * to the cqe_sq_cons
> @@ -1733,11 +1952,7 @@ static int bnxt_qplib_cq_process_req(struct bnxt_qplib_cq *cq,
>  				sw_sq_cons, cqe->wr_id, cqe->status);
>  			cqe++;
>  			(*budget)--;
> -			sq->flush_in_progress = true;
> -			/* Must block new posting of SQ and RQ */
> -			qp->state = CMDQ_MODIFY_QP_NEW_STATE_ERR;
> -			sq->condition = false;
> -			sq->single = false;
> +			bnxt_qplib_mark_qp_error(qp);
>  		} else {
>  			if (swq->flags & SQ_SEND_FLAGS_SIGNAL_COMP) {
>  				/* Before we complete, do WA 9060 */
> @@ -1768,15 +1983,6 @@ static int bnxt_qplib_cq_process_req(struct bnxt_qplib_cq *cq,
>  	 * the WC for this CQE
>  	 */
>  	sq->single = false;
> -	if (!sq->flush_in_progress)
> -		goto done;
> -flush:
> -	/* Require to walk the sq's swq to fabricate CQEs for all
> -	 * previously posted SWQEs due to the error CQE received
> -	 */
> -	rc = __flush_sq(sq, qp, pcqe, budget);
> -	if (!rc)
> -		sq->flush_in_progress = false;
>  done:
>  	return rc;
>  }
> @@ -1798,6 +2004,12 @@ static int bnxt_qplib_cq_process_res_rc(struct bnxt_qplib_cq *cq,
>  		dev_err(&cq->hwq.pdev->dev, "QPLIB: process_cq RC qp is NULL");
>  		return -EINVAL;
>  	}
> +	if (bnxt_qplib_is_qp_in_rq_flushlist(qp)) {
> +		dev_dbg(&cq->hwq.pdev->dev,
> +			"%s: QPLIB: QP in Flush QP = %p\n", __func__, qp);
> +		goto done;
> +	}
> +
>  	cqe = *pcqe;
>  	cqe->opcode = hwcqe->cqe_type_toggle & CQ_BASE_CQE_TYPE_MASK;
>  	cqe->length = le32_to_cpu(hwcqe->length);
> @@ -1817,8 +2029,6 @@ static int bnxt_qplib_cq_process_res_rc(struct bnxt_qplib_cq *cq,
>  			wr_id_idx, rq->hwq.max_elements);
>  		return -EINVAL;
>  	}
> -	if (rq->flush_in_progress)
> -		goto flush_rq;
>
>  	cqe->wr_id = rq->swq[wr_id_idx].wr_id;
>  	cqe++;
> @@ -1826,13 +2036,11 @@ static int bnxt_qplib_cq_process_res_rc(struct bnxt_qplib_cq *cq,
>  	rq->hwq.cons++;
>  	*pcqe = cqe;
>
> -	if (hwcqe->status != CQ_RES_RC_STATUS_OK) {
> -		rq->flush_in_progress = true;
> -flush_rq:
> -		rc = __flush_rq(rq, qp, CQ_BASE_CQE_TYPE_RES_RC, pcqe, budget);
> -		if (!rc)
> -			rq->flush_in_progress = false;
> -	}
> +	if (hwcqe->status != CQ_RES_RC_STATUS_OK)
> +		 /* Add qp to flush list of the CQ */
> +		bnxt_qplib_add_flush_qp(qp);
> +
> +done:
>  	return rc;
>  }
>
> @@ -1853,6 +2061,11 @@ static int bnxt_qplib_cq_process_res_ud(struct bnxt_qplib_cq *cq,
>  		dev_err(&cq->hwq.pdev->dev, "QPLIB: process_cq UD qp is NULL");
>  		return -EINVAL;
>  	}
> +	if (bnxt_qplib_is_qp_in_rq_flushlist(qp)) {
> +		dev_dbg(&cq->hwq.pdev->dev,
> +			"%s: QPLIB: QP in Flush QP = %p\n", __func__, qp);
> +		goto done;
> +	}
>  	cqe = *pcqe;
>  	cqe->opcode = hwcqe->cqe_type_toggle & CQ_BASE_CQE_TYPE_MASK;
>  	cqe->length = le32_to_cpu(hwcqe->length);
> @@ -1876,8 +2089,6 @@ static int bnxt_qplib_cq_process_res_ud(struct bnxt_qplib_cq *cq,
>  			wr_id_idx, rq->hwq.max_elements);
>  		return -EINVAL;
>  	}
> -	if (rq->flush_in_progress)
> -		goto flush_rq;
>
>  	cqe->wr_id = rq->swq[wr_id_idx].wr_id;
>  	cqe++;
> @@ -1885,13 +2096,11 @@ static int bnxt_qplib_cq_process_res_ud(struct bnxt_qplib_cq *cq,
>  	rq->hwq.cons++;
>  	*pcqe = cqe;
>
> -	if (hwcqe->status != CQ_RES_RC_STATUS_OK) {
> -		rq->flush_in_progress = true;
> -flush_rq:
> -		rc = __flush_rq(rq, qp, CQ_BASE_CQE_TYPE_RES_UD, pcqe, budget);
> -		if (!rc)
> -			rq->flush_in_progress = false;
> -	}
> +	if (hwcqe->status != CQ_RES_RC_STATUS_OK)
> +		/* Add qp to flush list of the CQ */
> +		bnxt_qplib_add_flush_qp(qp);
> +
> +done:
>  	return rc;
>  }
>
> @@ -1913,6 +2122,11 @@ static int bnxt_qplib_cq_process_res_raweth_qp1(struct bnxt_qplib_cq *cq,
>  			"QPLIB: process_cq Raw/QP1 qp is NULL");
>  		return -EINVAL;
>  	}
> +	if (bnxt_qplib_is_qp_in_rq_flushlist(qp)) {
> +		dev_dbg(&cq->hwq.pdev->dev,
> +			"%s: QPLIB: QP in Flush QP = %p\n", __func__, qp);
> +		goto done;
> +	}
>  	cqe = *pcqe;
>  	cqe->opcode = hwcqe->cqe_type_toggle & CQ_BASE_CQE_TYPE_MASK;
>  	cqe->flags = le16_to_cpu(hwcqe->flags);
> @@ -1941,8 +2155,6 @@ static int bnxt_qplib_cq_process_res_raweth_qp1(struct bnxt_qplib_cq *cq,
>  			wr_id_idx, rq->hwq.max_elements);
>  		return -EINVAL;
>  	}
> -	if (rq->flush_in_progress)
> -		goto flush_rq;
>
>  	cqe->wr_id = rq->swq[wr_id_idx].wr_id;
>  	cqe++;
> @@ -1950,14 +2162,11 @@ static int bnxt_qplib_cq_process_res_raweth_qp1(struct bnxt_qplib_cq *cq,
>  	rq->hwq.cons++;
>  	*pcqe = cqe;
>
> -	if (hwcqe->status != CQ_RES_RC_STATUS_OK) {
> -		rq->flush_in_progress = true;
> -flush_rq:
> -		rc = __flush_rq(rq, qp, CQ_BASE_CQE_TYPE_RES_RAWETH_QP1, pcqe,
> -				budget);
> -		if (!rc)
> -			rq->flush_in_progress = false;
> -	}
> +	if (hwcqe->status != CQ_RES_RC_STATUS_OK)
> +	/* Add qp to flush list of the CQ */
> +		bnxt_qplib_add_flush_qp(qp);
> +
> +done:
>  	return rc;
>  }
>
> @@ -1971,7 +2180,6 @@ static int bnxt_qplib_cq_process_terminal(struct bnxt_qplib_cq *cq,
>  	struct bnxt_qplib_cqe *cqe;
>  	u32 sw_cons = 0, cqe_cons;
>  	int rc = 0;
> -	u8 opcode = 0;
>
>  	/* Check the Status */
>  	if (hwcqe->status != CQ_TERMINAL_STATUS_OK)
> @@ -2004,9 +2212,12 @@ static int bnxt_qplib_cq_process_terminal(struct bnxt_qplib_cq *cq,
>  			cqe_cons, sq->hwq.max_elements);
>  		goto do_rq;
>  	}
> -	/* If we were in the middle of flushing, continue */
> -	if (sq->flush_in_progress)
> -		goto flush_sq;
> +
> +	if (bnxt_qplib_is_qp_in_sq_flushlist(qp)) {
> +		dev_dbg(&cq->hwq.pdev->dev,
> +			"%s: QPLIB: QP in Flush QP = %p\n", __func__, qp);
> +		goto sq_done;
> +	}
>
>  	/* Terminal CQE can also include aggregated successful CQEs prior.
>  	 * So we must complete all CQEs from the current sq's cons to the
> @@ -2036,11 +2247,6 @@ static int bnxt_qplib_cq_process_terminal(struct bnxt_qplib_cq *cq,
>  		rc = -EAGAIN;
>  		goto sq_done;
>  	}
> -	sq->flush_in_progress = true;
> -flush_sq:
> -	rc = __flush_sq(sq, qp, pcqe, budget);
> -	if (!rc)
> -		sq->flush_in_progress = false;
>  sq_done:
>  	if (rc)
>  		return rc;
> @@ -2056,26 +2262,21 @@ static int bnxt_qplib_cq_process_terminal(struct bnxt_qplib_cq *cq,
>  			cqe_cons, rq->hwq.max_elements);
>  		goto done;
>  	}
> +
> +	if (bnxt_qplib_is_qp_in_rq_flushlist(qp)) {
> +		dev_dbg(&cq->hwq.pdev->dev,
> +			"%s: QPLIB: QP in Flush QP = %p\n", __func__, qp);
> +		rc = 0;
> +		goto done;
> +	}
> +
>  	/* Terminal CQE requires all posted RQEs to complete with FLUSHED_ERR
>  	 * from the current rq->cons to the rq->prod regardless what the
>  	 * rq->cons the terminal CQE indicates
>  	 */
> -	rq->flush_in_progress = true;
> -	switch (qp->type) {
> -	case CMDQ_CREATE_QP1_TYPE_GSI:
> -		opcode = CQ_BASE_CQE_TYPE_RES_RAWETH_QP1;
> -		break;
> -	case CMDQ_CREATE_QP_TYPE_RC:
> -		opcode = CQ_BASE_CQE_TYPE_RES_RC;
> -		break;
> -	case CMDQ_CREATE_QP_TYPE_UD:
> -		opcode = CQ_BASE_CQE_TYPE_RES_UD;
> -		break;
> -	}
>
> -	rc = __flush_rq(rq, qp, opcode, pcqe, budget);
> -	if (!rc)
> -		rq->flush_in_progress = false;
> +	/* Add qp to flush list of the CQ */
> +	bnxt_qplib_add_flush_qp(qp);
>  done:
>  	return rc;
>  }
> @@ -2096,6 +2297,33 @@ static int bnxt_qplib_cq_process_cutoff(struct bnxt_qplib_cq *cq,
>  	return 0;
>  }
>
> +int bnxt_qplib_process_flush_list(struct bnxt_qplib_cq *cq,
> +				  struct bnxt_qplib_cqe *cqe,
> +				  int num_cqes)
> +{
> +	struct bnxt_qplib_qp *qp = NULL;
> +	u32 budget = num_cqes;
> +	unsigned long flags;
> +
> +	spin_lock_irqsave(&cq->flush_lock, flags);
> +	list_for_each_entry(qp, &cq->sqf_head, sq_flush) {
> +		dev_dbg(&cq->hwq.pdev->dev,
> +			"QPLIB: FP: Flushing SQ QP= %p",
> +			qp);
> +		__flush_sq(&qp->sq, qp, &cqe, &budget);
> +	}
> +
> +	list_for_each_entry(qp, &cq->rqf_head, rq_flush) {
> +		dev_dbg(&cq->hwq.pdev->dev,
> +			"QPLIB: FP: Flushing RQ QP= %p",
> +			qp);
> +		__flush_rq(&qp->rq, qp, &cqe, &budget);
> +	}
> +	spin_unlock_irqrestore(&cq->flush_lock, flags);
> +
> +	return num_cqes - budget;
> +}
> +
>  int bnxt_qplib_poll_cq(struct bnxt_qplib_cq *cq, struct bnxt_qplib_cqe *cqe,
>  		       int num_cqes, struct bnxt_qplib_qp **lib_qp)
>  {
> @@ -2186,6 +2414,7 @@ void bnxt_qplib_req_notify_cq(struct bnxt_qplib_cq *cq, u32 arm_type)
>  	spin_lock_irqsave(&cq->hwq.lock, flags);
>  	if (arm_type)
>  		bnxt_qplib_arm_cq(cq, arm_type);
> -
> +	/* Using cq->arm_state variable to track whether to issue cq handler */
> +	atomic_set(&cq->arm_state, 1);
>  	spin_unlock_irqrestore(&cq->hwq.lock, flags);
>  }
> diff --git a/drivers/infiniband/hw/bnxt_re/qplib_fp.h b/drivers/infiniband/hw/bnxt_re/qplib_fp.h
> index 36b7b7d..18abe40 100644
> --- a/drivers/infiniband/hw/bnxt_re/qplib_fp.h
> +++ b/drivers/infiniband/hw/bnxt_re/qplib_fp.h
> @@ -220,19 +220,20 @@ struct bnxt_qplib_q {
>  	u16				q_full_delta;
>  	u16				max_sge;
>  	u32				psn;
> -	bool				flush_in_progress;
>  	bool				condition;
>  	bool				single;
>  	bool				send_phantom;
>  	u32				phantom_wqe_cnt;
>  	u32				phantom_cqe_cnt;
>  	u32				next_cq_cons;
> +	bool				flushed;
>  };
>
>  struct bnxt_qplib_qp {
>  	struct bnxt_qplib_pd		*pd;
>  	struct bnxt_qplib_dpi		*dpi;
>  	u64				qp_handle;
> +#define        BNXT_QPLIB_QP_ID_INVALID        0xFFFFFFFF
>  	u32				id;
>  	u8				type;
>  	u8				sig_type;
> @@ -296,6 +297,8 @@ struct bnxt_qplib_qp {
>  	dma_addr_t			sq_hdr_buf_map;
>  	void				*rq_hdr_buf;
>  	dma_addr_t			rq_hdr_buf_map;
> +	struct list_head		sq_flush;
> +	struct list_head		rq_flush;
>  };
>
>  #define BNXT_QPLIB_MAX_CQE_ENTRY_SIZE	sizeof(struct cq_base)
> @@ -351,6 +354,7 @@ struct bnxt_qplib_cq {
>  	u16				period;
>  	struct bnxt_qplib_hwq		hwq;
>  	u32				cnq_hw_ring_id;
> +	struct bnxt_qplib_nq		*nq;
>  	bool				resize_in_progress;
>  	struct scatterlist		*sghead;
>  	u32				nmap;
> @@ -360,6 +364,10 @@ struct bnxt_qplib_cq {
>  	unsigned long			flags;
>  #define CQ_FLAGS_RESIZE_IN_PROG		1
>  	wait_queue_head_t		waitq;
> +	spinlock_t			flush_lock; /* lock flush queue list */
> +	struct list_head		sqf_head, rqf_head;
> +	atomic_t			arm_state;
> +	spinlock_t			compl_lock; /* synch CQ handlers */
>  };
>
>  #define BNXT_QPLIB_MAX_IRRQE_ENTRY_SIZE	sizeof(struct xrrq_irrq)
> @@ -417,6 +425,13 @@ struct bnxt_qplib_nq {
>  						(struct bnxt_qplib_nq *nq,
>  						 void *srq,
>  						 u8 event);
> +	struct workqueue_struct         *cqn_wq;
> +};
> +
> +struct bnxt_qplib_nq_work {
> +	struct work_struct      work;
> +	struct bnxt_qplib_nq    *nq;
> +	struct bnxt_qplib_cq    *cq;
>  };
>
>  void bnxt_qplib_disable_nq(struct bnxt_qplib_nq *nq);
> @@ -452,4 +467,9 @@ int bnxt_qplib_poll_cq(struct bnxt_qplib_cq *cq, struct bnxt_qplib_cqe *cqe,
>  void bnxt_qplib_req_notify_cq(struct bnxt_qplib_cq *cq, u32 arm_type);
>  void bnxt_qplib_free_nq(struct bnxt_qplib_nq *nq);
>  int bnxt_qplib_alloc_nq(struct pci_dev *pdev, struct bnxt_qplib_nq *nq);
> +void bnxt_qplib_add_flush_qp(struct bnxt_qplib_qp *qp);
> +void bnxt_qplib_del_flush_qp(struct bnxt_qplib_qp *qp);
> +int bnxt_qplib_process_flush_list(struct bnxt_qplib_cq *cq,
> +				  struct bnxt_qplib_cqe *cqe,
> +				  int num_cqes);
>  #endif /* __BNXT_QPLIB_FP_H__ */
> diff --git a/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c b/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c
> index 16e4275..d88b5de 100644
> --- a/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c
> +++ b/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c
> @@ -507,6 +507,7 @@ int bnxt_qplib_init_rcfw(struct bnxt_qplib_rcfw *rcfw,
>
>  void bnxt_qplib_free_rcfw_channel(struct bnxt_qplib_rcfw *rcfw)
>  {
> +	kfree(rcfw->qp_tbl);
>  	kfree(rcfw->crsqe_tbl);
>  	bnxt_qplib_free_hwq(rcfw->pdev, &rcfw->cmdq);
>  	bnxt_qplib_free_hwq(rcfw->pdev, &rcfw->creq);
> @@ -514,7 +515,8 @@ void bnxt_qplib_free_rcfw_channel(struct bnxt_qplib_rcfw *rcfw)
>  }
>
>  int bnxt_qplib_alloc_rcfw_channel(struct pci_dev *pdev,
> -				  struct bnxt_qplib_rcfw *rcfw)
> +				  struct bnxt_qplib_rcfw *rcfw,
> +				  int qp_tbl_sz)
>  {
>  	rcfw->pdev = pdev;
>  	rcfw->creq.max_elements = BNXT_QPLIB_CREQE_MAX_CNT;
> @@ -541,6 +543,12 @@ int bnxt_qplib_alloc_rcfw_channel(struct pci_dev *pdev,
>  	if (!rcfw->crsqe_tbl)
>  		goto fail;
>
> +	rcfw->qp_tbl_size = qp_tbl_sz;
> +	rcfw->qp_tbl = kcalloc(qp_tbl_sz, sizeof(struct bnxt_qplib_qp_node),
> +			       GFP_KERNEL);
> +	if (!rcfw->qp_tbl)
> +		goto fail;
> +
>  	return 0;
>
>  fail:
> diff --git a/drivers/infiniband/hw/bnxt_re/qplib_rcfw.h b/drivers/infiniband/hw/bnxt_re/qplib_rcfw.h
> index 09ce121..0ed312f 100644
> --- a/drivers/infiniband/hw/bnxt_re/qplib_rcfw.h
> +++ b/drivers/infiniband/hw/bnxt_re/qplib_rcfw.h
> @@ -148,6 +148,11 @@ struct bnxt_qplib_rcfw_sbuf {
>  	u32 size;
>  };
>
> +struct bnxt_qplib_qp_node {
> +	u32 qp_id;              /* QP id */
> +	void *qp_handle;        /* ptr to qplib_qp */
> +};
> +
>  /* RCFW Communication Channels */
>  struct bnxt_qplib_rcfw {
>  	struct pci_dev		*pdev;
> @@ -181,11 +186,13 @@ struct bnxt_qplib_rcfw {
>  	/* Actual Cmd and Resp Queues */
>  	struct bnxt_qplib_hwq	cmdq;
>  	struct bnxt_qplib_crsq	*crsqe_tbl;
> +	int qp_tbl_size;
> +	struct bnxt_qplib_qp_node *qp_tbl;
>  };
>
>  void bnxt_qplib_free_rcfw_channel(struct bnxt_qplib_rcfw *rcfw);
>  int bnxt_qplib_alloc_rcfw_channel(struct pci_dev *pdev,
> -				  struct bnxt_qplib_rcfw *rcfw);
> +				  struct bnxt_qplib_rcfw *rcfw, int qp_tbl_sz);
>  void bnxt_qplib_disable_rcfw_channel(struct bnxt_qplib_rcfw *rcfw);
>  int bnxt_qplib_enable_rcfw_channel(struct pci_dev *pdev,
>  				   struct bnxt_qplib_rcfw *rcfw,
> @@ -207,4 +214,5 @@ int bnxt_qplib_rcfw_send_message(struct bnxt_qplib_rcfw *rcfw,
>  int bnxt_qplib_deinit_rcfw(struct bnxt_qplib_rcfw *rcfw);
>  int bnxt_qplib_init_rcfw(struct bnxt_qplib_rcfw *rcfw,
>  			 struct bnxt_qplib_ctx *ctx, int is_virtfn);
> +void bnxt_qplib_mark_qp_error(void *qp_handle);
>  #endif /* __BNXT_QPLIB_RCFW_H__ */
> --
> 2.5.5
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
> the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH for-next 09/13] RDMA/bnxt_re: Allow posting when QPs are in error
       [not found]         ` <20170622054010.GL1248-U/DQcQFIOTAAJjI8aNfphQ@public.gmane.org>
@ 2017-06-22  9:16           ` Selvin Xavier
  0 siblings, 0 replies; 17+ messages in thread
From: Selvin Xavier @ 2017-06-22  9:16 UTC (permalink / raw)
  To: Leon Romanovsky
  Cc: Doug Ledford, linux-rdma-u79uwXL29TY76Z2rM5mHXA, Sriharsha Basavapatna

On Thu, Jun 22, 2017 at 11:10 AM, Leon Romanovsky <leon-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org> wrote:
>> +static bool bnxt_qplib_is_qp_in_sq_flushlist(struct bnxt_qplib_qp *qp)
>> +{
>> +     bool flushed = false;
>> +     unsigned long flags;
>> +
>> +     spin_lock_irqsave(&qp->scq->flush_lock, flags);
>> +     flushed = qp->sq.flushed;
>> +     spin_unlock_irqrestore(&qp->scq->flush_lock, flags);
>> +     return flushed;
>
> I don't really understand the lock/unlock here. What exactly do you
> protect? Is it the change of "flushed"? It can be and will be worthless
> immediately after your unlock.
>
> You should protect the whole flow which depends on your "flushed".
Agreed. This lock is required for handling the completions when the qp
moves from error to
reset state. But surely it needs a rework.  I will post  v2.
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH for-next 11/13] RDMA/bnxt_re: Fix return value of poll routine
       [not found]     ` <1498065504-27902-12-git-send-email-selvin.xavier-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>
@ 2017-06-25  5:48       ` Leon Romanovsky
  0 siblings, 0 replies; 17+ messages in thread
From: Leon Romanovsky @ 2017-06-25  5:48 UTC (permalink / raw)
  To: Selvin Xavier
  Cc: dledford-H+wXaHxf7aLQT0dZR+AlfA,
	linux-rdma-u79uwXL29TY76Z2rM5mHXA, Devesh Sharma

[-- Attachment #1: Type: text/plain, Size: 615 bytes --]

On Wed, Jun 21, 2017 at 10:18:22AM -0700, Selvin Xavier wrote:
> From: Devesh Sharma <devesh.sharma-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>
>
> Fix the incorrect reporting of number of polled
> entries by taking into account the max CQ depth
> in the driver.
>
> Signed-off-by: Devesh Sharma <devesh.sharma-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>
> Signed-off-by: Selvin Xavier <selvin.xavier-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>
> ---
>  drivers/infiniband/hw/bnxt_re/ib_verbs.c | 1 +
>  1 file changed, 1 insertion(+)
>

Thanks,
Reviewed-by: Leon Romanovsky <leonro-VPRAkNaXOzVWk0Htik3J/w@public.gmane.org>

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 17+ messages in thread

end of thread, other threads:[~2017-06-25  5:48 UTC | newest]

Thread overview: 17+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-06-21 17:18 [PATCH for-next 00/13] RDMA/bnxt_re: Misc fixes for bnxt_re Selvin Xavier
     [not found] ` <1498065504-27902-1-git-send-email-selvin.xavier-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>
2017-06-21 17:18   ` [PATCH for-next 01/13] RDMA/bnxt_re: Fix race between netdev register and unregister events Selvin Xavier
2017-06-21 17:18   ` [PATCH for-next 02/13] RDMA/bnxt_re: Free doorbell page index (DPI) during dealloc ucontext Selvin Xavier
2017-06-21 17:18   ` [PATCH for-next 03/13] RDMA/bnxt_re: Fix WQE Size posted to HW to prevent it from throwing error Selvin Xavier
2017-06-21 17:18   ` [PATCH for-next 04/13] RDMA/bnxt_re: Add vlan tag for untagged RoCE traffic when PFC is configured Selvin Xavier
2017-06-21 17:18   ` [PATCH for-next 05/13] RDMA/bnxt_re: Do not free the ctx_tbl entry if delete GID fails Selvin Xavier
2017-06-21 17:18   ` [PATCH for-next 06/13] RDMA/bnxt_re: Report supported value to IB stack in query_device Selvin Xavier
2017-06-21 17:18   ` [PATCH for-next 07/13] RDMA/bnxt_re: Fixed the max_rd_atomic support for initiator and destination QP Selvin Xavier
2017-06-21 17:18   ` [PATCH for-next 08/13] RDMA/bnxt_re: Specify RDMA component when allocating stats context Selvin Xavier
2017-06-21 17:18   ` [PATCH for-next 09/13] RDMA/bnxt_re: Allow posting when QPs are in error Selvin Xavier
     [not found]     ` <1498065504-27902-10-git-send-email-selvin.xavier-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>
2017-06-22  5:40       ` Leon Romanovsky
     [not found]         ` <20170622054010.GL1248-U/DQcQFIOTAAJjI8aNfphQ@public.gmane.org>
2017-06-22  9:16           ` Selvin Xavier
2017-06-21 17:18   ` [PATCH for-next 10/13] RDMA/bnxt_re: Enable atomics only if host bios supports Selvin Xavier
2017-06-21 17:18   ` [PATCH for-next 11/13] RDMA/bnxt_re: Fix return value of poll routine Selvin Xavier
     [not found]     ` <1498065504-27902-12-git-send-email-selvin.xavier-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>
2017-06-25  5:48       ` Leon Romanovsky
2017-06-21 17:18   ` [PATCH for-next 12/13] RDMA/bnxt_re: Report MISSED_EVENTS in req_notify_cq Selvin Xavier
2017-06-21 17:18   ` [PATCH for-next 13/13] RDMA/bnxt_re: Fix the value reported for local ack delay Selvin Xavier

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.