]> git.openfabrics.org - ~emulex/for-vlad/old/compat-rdma.git/commitdiff
RDMA/ocrdma: Syncup patches from upstream kernel.
authorMitesh Ahuja <mitesh.ahuja@emulex.com>
Thu, 18 Dec 2014 11:05:44 +0000 (03:05 -0800)
committerSelvin Xavier <selvin.xavier@emulex.com>
Thu, 18 Dec 2014 11:05:44 +0000 (03:05 -0800)
linux-next-pending/0006-RDMA-ocrdma-Syncup-patches-from-upstream-kernel.patch [new file with mode: 0644]

diff --git a/linux-next-pending/0006-RDMA-ocrdma-Syncup-patches-from-upstream-kernel.patch b/linux-next-pending/0006-RDMA-ocrdma-Syncup-patches-from-upstream-kernel.patch
new file mode 100644 (file)
index 0000000..b7dddcd
--- /dev/null
@@ -0,0 +1,1656 @@
+From f1eb7580709585a031d0a778c6fd654ce9a23e0e Mon Sep 17 00:00:00 2001
+From: Mitesh Ahuja <mitesh.ahuja@emulex.com>
+Date: Thu, 18 Dec 2014 02:25:27 -0800
+Subject: [PATCH] RDMA/ocrdma: Syncup patches from upstream kernel.
+
+---
+ drivers/infiniband/hw/ocrdma/ocrdma.h       |   38 +++-
+ drivers/infiniband/hw/ocrdma/ocrdma_ah.c    |   43 +++-
+ drivers/infiniband/hw/ocrdma/ocrdma_ah.h    |    6 +
+ drivers/infiniband/hw/ocrdma/ocrdma_hw.c    |  313 +++++++++++++++++++++++----
+ drivers/infiniband/hw/ocrdma/ocrdma_hw.h    |    2 +
+ drivers/infiniband/hw/ocrdma/ocrdma_main.c  |   12 +-
+ drivers/infiniband/hw/ocrdma/ocrdma_sli.h   |   68 ++++++-
+ drivers/infiniband/hw/ocrdma/ocrdma_stats.c |  242 +++++++++++++++++++++
+ drivers/infiniband/hw/ocrdma/ocrdma_stats.h |    6 +-
+ drivers/infiniband/hw/ocrdma/ocrdma_verbs.c |  172 ++++++++++++---
+ 10 files changed, 813 insertions(+), 89 deletions(-)
+
+diff --git a/drivers/infiniband/hw/ocrdma/ocrdma.h b/drivers/infiniband/hw/ocrdma/ocrdma.h
+index b43456a..c9780d9 100644
+--- a/drivers/infiniband/hw/ocrdma/ocrdma.h
++++ b/drivers/infiniband/hw/ocrdma/ocrdma.h
+@@ -40,7 +40,7 @@
+ #include <be_roce.h>
+ #include "ocrdma_sli.h"
+-#define OCRDMA_ROCE_DRV_VERSION "10.2.287.0u"
++#define OCRDMA_ROCE_DRV_VERSION "10.4.205.0u"
+ #define OCRDMA_ROCE_DRV_DESC "Emulex OneConnect RoCE Driver"
+ #define OCRDMA_NODE_DESC "Emulex OneConnect RoCE HCA"
+@@ -55,12 +55,19 @@
+ #define OCRDMA_UVERBS(CMD_NAME) (1ull << IB_USER_VERBS_CMD_##CMD_NAME)
+ #define convert_to_64bit(lo, hi) ((u64)hi << 32 | (u64)lo)
++#define EQ_INTR_PER_SEC_THRSH_HI 150000
++#define EQ_INTR_PER_SEC_THRSH_LOW 100000
++#define EQ_AIC_MAX_EQD 20
++#define EQ_AIC_MIN_EQD 0
++
++void ocrdma_eqd_set_task(struct work_struct *work);
+ struct ocrdma_dev_attr {
+       u8 fw_ver[32];
+       u32 vendor_id;
+       u32 device_id;
+       u16 max_pd;
++      u16 max_dpp_pds;
+       u16 max_cq;
+       u16 max_cqe;
+       u16 max_qp;
+@@ -116,12 +123,19 @@ struct ocrdma_queue_info {
+       bool created;
+ };
++struct ocrdma_aic_obj {         /* Adaptive interrupt coalescing (AIC) info */
++      u32 prev_eqd;
++      u64 eq_intr_cnt;
++      u64 prev_eq_intr_cnt;
++};
++
+ struct ocrdma_eq {
+       struct ocrdma_queue_info q;
+       u32 vector;
+       int cq_cnt;
+       struct ocrdma_dev *dev;
+       char irq_name[32];
++      struct ocrdma_aic_obj aic_obj;
+ };
+ struct ocrdma_mq {
+@@ -171,6 +185,21 @@ struct ocrdma_stats {
+       struct ocrdma_dev *dev;
+ };
++struct ocrdma_pd_resource_mgr {
++      u32 pd_norm_start;
++      u16 pd_norm_count;
++      u16 pd_norm_thrsh;
++      u16 max_normal_pd;
++      u32 pd_dpp_start;
++      u16 pd_dpp_count;
++      u16 pd_dpp_thrsh;
++      u16 max_dpp_pd;
++      u16 dpp_page_index;
++      unsigned long *pd_norm_bitmap;
++      unsigned long *pd_dpp_bitmap;
++      bool pd_prealloc_valid;
++};
++
+ struct stats_mem {
+       struct ocrdma_mqe mqe;
+       void *va;
+@@ -198,6 +227,7 @@ struct ocrdma_dev {
+       struct ocrdma_eq *eq_tbl;
+       int eq_cnt;
++      struct delayed_work eqd_work;
+       u16 base_eqid;
+       u16 max_eq;
+@@ -255,7 +285,12 @@ struct ocrdma_dev {
+       struct ocrdma_stats rx_qp_err_stats;
+       struct ocrdma_stats tx_dbg_stats;
+       struct ocrdma_stats rx_dbg_stats;
++      struct ocrdma_stats driver_stats;
++      struct ocrdma_stats reset_stats;
+       struct dentry *dir;
++      atomic_t async_err_stats[OCRDMA_MAX_ASYNC_ERRORS];
++      atomic_t cqe_err_stats[OCRDMA_MAX_CQE_ERR];
++      struct ocrdma_pd_resource_mgr *pd_mgr;
+ };
+ struct ocrdma_cq {
+@@ -335,7 +370,6 @@ struct ocrdma_srq {
+ struct ocrdma_qp {
+       struct ib_qp ibqp;
+-      struct ocrdma_dev *dev;
+       u8 __iomem *sq_db;
+       struct ocrdma_qp_hwq_info sq;
+diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_ah.c b/drivers/infiniband/hw/ocrdma/ocrdma_ah.c
+index ac02ce4..d812904 100644
+--- a/drivers/infiniband/hw/ocrdma/ocrdma_ah.c
++++ b/drivers/infiniband/hw/ocrdma/ocrdma_ah.c
+@@ -29,19 +29,22 @@
+ #include <net/netevent.h>
+ #include <rdma/ib_addr.h>
++#include <rdma/ib_mad.h>
+ #include "ocrdma.h"
+ #include "ocrdma_verbs.h"
+ #include "ocrdma_ah.h"
+ #include "ocrdma_hw.h"
++#include "ocrdma_stats.h"
+ #define OCRDMA_VID_PCP_SHIFT  0xD
+ static inline int set_av_attr(struct ocrdma_dev *dev, struct ocrdma_ah *ah,
+-                      struct ib_ah_attr *attr, union ib_gid *sgid, int pdid)
++                      struct ib_ah_attr *attr, union ib_gid *sgid,
++                      int pdid, bool *isvlan)
+ {
+       int status = 0;
+-      u16 vlan_tag; bool vlan_enabled = false;
++      u16 vlan_tag;
+       struct ocrdma_eth_vlan eth;
+       struct ocrdma_grh grh;
+       int eth_sz;
+@@ -59,7 +62,7 @@ static inline int set_av_attr(struct ocrdma_dev *dev, struct ocrdma_ah *ah,
+               vlan_tag |= (dev->sl & 0x07) << OCRDMA_VID_PCP_SHIFT;
+               eth.vlan_tag = cpu_to_be16(vlan_tag);
+               eth_sz = sizeof(struct ocrdma_eth_vlan);
+-              vlan_enabled = true;
++              *isvlan = true;
+       } else {
+               eth.eth_type = cpu_to_be16(OCRDMA_ROCE_ETH_TYPE);
+               eth_sz = sizeof(struct ocrdma_eth_basic);
+@@ -82,7 +85,7 @@ static inline int set_av_attr(struct ocrdma_dev *dev, struct ocrdma_ah *ah,
+       /* Eth HDR */
+       memcpy(&ah->av->eth_hdr, &eth, eth_sz);
+       memcpy((u8 *)ah->av + eth_sz, &grh, sizeof(struct ocrdma_grh));
+-      if (vlan_enabled)
++      if (*isvlan)
+               ah->av->valid |= OCRDMA_AV_VLAN_VALID;
+       ah->av->valid = cpu_to_le32(ah->av->valid);
+       return status;
+@@ -91,12 +94,12 @@ static inline int set_av_attr(struct ocrdma_dev *dev, struct ocrdma_ah *ah,
+ struct ib_ah *ocrdma_create_ah(struct ib_pd *ibpd, struct ib_ah_attr *attr)
+ {
+       u32 *ahid_addr;
++      bool isvlan = false;
+       int status;
+       struct ocrdma_ah *ah;
+       struct ocrdma_pd *pd = get_ocrdma_pd(ibpd);
+       struct ocrdma_dev *dev = get_ocrdma_dev(ibpd->device);
+       union ib_gid sgid;
+-      u8 zmac[ETH_ALEN];
+       if (!(attr->ah_flags & IB_AH_GRH))
+               return ERR_PTR(-EINVAL);
+@@ -118,9 +121,7 @@ struct ib_ah *ocrdma_create_ah(struct ib_pd *ibpd, struct ib_ah_attr *attr)
+               goto av_conf_err;
+       }
+-      memset(&zmac, 0, ETH_ALEN);
+-      if (pd->uctx &&
+-          memcmp(attr->dmac, &zmac, ETH_ALEN)) {
++      if (pd->uctx) {
+               status = rdma_addr_find_dmac_by_grh(&sgid, &attr->grh.dgid,
+                                         attr->dmac, &attr->vlan_id);
+               if (status) {
+@@ -130,15 +131,20 @@ struct ib_ah *ocrdma_create_ah(struct ib_pd *ibpd, struct ib_ah_attr *attr)
+               }
+       }
+-      status = set_av_attr(dev, ah, attr, &sgid, pd->id);
++      status = set_av_attr(dev, ah, attr, &sgid, pd->id, &isvlan);
+       if (status)
+               goto av_conf_err;
+       /* if pd is for the user process, pass the ah_id to user space */
+       if ((pd->uctx) && (pd->uctx->ah_tbl.va)) {
+               ahid_addr = pd->uctx->ah_tbl.va + attr->dlid;
+-              *ahid_addr = ah->id;
++              *ahid_addr = 0;
++              *ahid_addr |= ah->id & OCRDMA_AH_ID_MASK;
++              if (isvlan)
++                      *ahid_addr |= (OCRDMA_AH_VLAN_VALID_MASK <<
++                                     OCRDMA_AH_VLAN_VALID_SHIFT);
+       }
++
+       return &ah->ibah;
+ av_conf_err:
+@@ -194,5 +200,20 @@ int ocrdma_process_mad(struct ib_device *ibdev,
+                      struct ib_grh *in_grh,
+                      struct ib_mad *in_mad, struct ib_mad *out_mad)
+ {
+-      return IB_MAD_RESULT_SUCCESS;
++      int status;
++      struct ocrdma_dev *dev;
++
++      switch (in_mad->mad_hdr.mgmt_class) {
++      case IB_MGMT_CLASS_PERF_MGMT:
++              dev = get_ocrdma_dev(ibdev);
++              if (!ocrdma_pma_counters(dev, out_mad))
++                      status = IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_REPLY;
++              else
++                      status = IB_MAD_RESULT_SUCCESS;
++              break;
++      default:
++              status = IB_MAD_RESULT_SUCCESS;
++              break;
++      }
++      return status;
+ }
+diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_ah.h b/drivers/infiniband/hw/ocrdma/ocrdma_ah.h
+index 8ac49e7..726a87c 100644
+--- a/drivers/infiniband/hw/ocrdma/ocrdma_ah.h
++++ b/drivers/infiniband/hw/ocrdma/ocrdma_ah.h
+@@ -28,6 +28,12 @@
+ #ifndef __OCRDMA_AH_H__
+ #define __OCRDMA_AH_H__
++enum {
++      OCRDMA_AH_ID_MASK               = 0x3FF,
++      OCRDMA_AH_VLAN_VALID_MASK       = 0x01,
++      OCRDMA_AH_VLAN_VALID_SHIFT      = 0x1F
++};
++
+ struct ib_ah *ocrdma_create_ah(struct ib_pd *, struct ib_ah_attr *);
+ int ocrdma_destroy_ah(struct ib_ah *);
+ int ocrdma_query_ah(struct ib_ah *, struct ib_ah_attr *);
+diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_hw.c b/drivers/infiniband/hw/ocrdma/ocrdma_hw.c
+index 638bff1..6e58f39 100644
+--- a/drivers/infiniband/hw/ocrdma/ocrdma_hw.c
++++ b/drivers/infiniband/hw/ocrdma/ocrdma_hw.c
+@@ -734,6 +734,9 @@ static void ocrdma_dispatch_ibevent(struct ocrdma_dev *dev,
+               break;
+       }
++      if (type < OCRDMA_MAX_ASYNC_ERRORS)
++              atomic_inc(&dev->async_err_stats[type]);
++
+       if (qp_event) {
+               if (qp->ibqp.event_handler)
+                       qp->ibqp.event_handler(&ib_evt, qp->ibqp.qp_context);
+@@ -831,20 +834,20 @@ static int ocrdma_mq_cq_handler(struct ocrdma_dev *dev, u16 cq_id)
+       return 0;
+ }
+-static void ocrdma_qp_buddy_cq_handler(struct ocrdma_dev *dev,
+-                                     struct ocrdma_cq *cq)
++static struct ocrdma_cq *_ocrdma_qp_buddy_cq_handler(struct ocrdma_dev *dev,
++                              struct ocrdma_cq *cq, bool sq)
+ {
+-      unsigned long flags;
+       struct ocrdma_qp *qp;
+-      bool buddy_cq_found = false;
+-      /* Go through list of QPs in error state which are using this CQ
+-       * and invoke its callback handler to trigger CQE processing for
+-       * error/flushed CQE. It is rare to find more than few entries in
+-       * this list as most consumers stops after getting error CQE.
+-       * List is traversed only once when a matching buddy cq found for a QP.
+-       */
+-      spin_lock_irqsave(&dev->flush_q_lock, flags);
+-      list_for_each_entry(qp, &cq->sq_head, sq_entry) {
++      struct list_head *cur;
++      struct ocrdma_cq *bcq = NULL;
++      struct list_head *head = sq?(&cq->sq_head):(&cq->rq_head);
++
++      list_for_each(cur, head) {
++              if (sq)
++                      qp = list_entry(cur, struct ocrdma_qp, sq_entry);
++              else
++                      qp = list_entry(cur, struct ocrdma_qp, rq_entry);
++
+               if (qp->srq)
+                       continue;
+               /* if wq and rq share the same cq, than comp_handler
+@@ -856,19 +859,41 @@ static void ocrdma_qp_buddy_cq_handler(struct ocrdma_dev *dev,
+                * if completion came on rq, sq's cq is buddy cq.
+                */
+               if (qp->sq_cq == cq)
+-                      cq = qp->rq_cq;
++                      bcq = qp->rq_cq;
+               else
+-                      cq = qp->sq_cq;
+-              buddy_cq_found = true;
+-              break;
++                      bcq = qp->sq_cq;
++              return bcq;
+       }
++      return NULL;
++}
++
++static void ocrdma_qp_buddy_cq_handler(struct ocrdma_dev *dev,
++                                     struct ocrdma_cq *cq)
++{
++      unsigned long flags;
++      struct ocrdma_cq *bcq = NULL;
++
++      /* Go through list of QPs in error state which are using this CQ
++       * and invoke its callback handler to trigger CQE processing for
++       * error/flushed CQE. It is rare to find more than few entries in
++       * this list as most consumers stops after getting error CQE.
++       * List is traversed only once when a matching buddy cq found for a QP.
++       */
++      spin_lock_irqsave(&dev->flush_q_lock, flags);
++      /* Check if buddy CQ is present.
++       * true - Check for  SQ CQ
++       * false - Check for RQ CQ
++       */
++      bcq = _ocrdma_qp_buddy_cq_handler(dev, cq, true);
++      if (bcq == NULL)
++              bcq = _ocrdma_qp_buddy_cq_handler(dev, cq, false);
+       spin_unlock_irqrestore(&dev->flush_q_lock, flags);
+-      if (buddy_cq_found == false)
+-              return;
+-      if (cq->ibcq.comp_handler) {
+-              spin_lock_irqsave(&cq->comp_handler_lock, flags);
+-              (*cq->ibcq.comp_handler) (&cq->ibcq, cq->ibcq.cq_context);
+-              spin_unlock_irqrestore(&cq->comp_handler_lock, flags);
++
++      /* if there is valid buddy cq, look for its completion handler */
++      if (bcq && bcq->ibcq.comp_handler) {
++              spin_lock_irqsave(&bcq->comp_handler_lock, flags);
++              (*bcq->ibcq.comp_handler) (&bcq->ibcq, bcq->ibcq.cq_context);
++              spin_unlock_irqrestore(&bcq->comp_handler_lock, flags);
+       }
+ }
+@@ -935,6 +960,7 @@ static irqreturn_t ocrdma_irq_handler(int irq, void *handle)
+       } while (budget);
++      eq->aic_obj.eq_intr_cnt++;
+       ocrdma_ring_eq_db(dev, eq->q.id, true, true, 0);
+       return IRQ_HANDLED;
+ }
+@@ -1050,6 +1076,9 @@ static void ocrdma_get_attr(struct ocrdma_dev *dev,
+       attr->max_pd =
+           (rsp->max_pd_ca_ack_delay & OCRDMA_MBX_QUERY_CFG_MAX_PD_MASK) >>
+           OCRDMA_MBX_QUERY_CFG_MAX_PD_SHIFT;
++      attr->max_dpp_pds =
++         (rsp->max_dpp_pds_credits & OCRDMA_MBX_QUERY_CFG_MAX_DPP_PDS_MASK) >>
++          OCRDMA_MBX_QUERY_CFG_MAX_DPP_PDS_OFFSET;
+       attr->max_qp =
+           (rsp->qp_srq_cq_ird_ord & OCRDMA_MBX_QUERY_CFG_MAX_QP_MASK) >>
+           OCRDMA_MBX_QUERY_CFG_MAX_QP_SHIFT;
+@@ -1396,6 +1425,123 @@ int ocrdma_mbx_dealloc_pd(struct ocrdma_dev *dev, struct ocrdma_pd *pd)
+       return status;
+ }
++
++static int ocrdma_mbx_alloc_pd_range(struct ocrdma_dev *dev)
++{
++      int status = -ENOMEM;
++      size_t pd_bitmap_size;
++      struct ocrdma_alloc_pd_range *cmd;
++      struct ocrdma_alloc_pd_range_rsp *rsp;
++
++      /* Pre allocate the DPP PDs */
++      cmd = ocrdma_init_emb_mqe(OCRDMA_CMD_ALLOC_PD_RANGE, sizeof(*cmd));
++      if (!cmd)
++              return -ENOMEM;
++      cmd->pd_count = dev->attr.max_dpp_pds;
++      cmd->enable_dpp_rsvd |= OCRDMA_ALLOC_PD_ENABLE_DPP;
++      status = ocrdma_mbx_cmd(dev, (struct ocrdma_mqe *)cmd);
++      if (status)
++              goto mbx_err;
++      rsp = (struct ocrdma_alloc_pd_range_rsp *)cmd;
++
++      if ((rsp->dpp_page_pdid & OCRDMA_ALLOC_PD_RSP_DPP) && rsp->pd_count) {
++              dev->pd_mgr->dpp_page_index = rsp->dpp_page_pdid >>
++                              OCRDMA_ALLOC_PD_RSP_DPP_PAGE_SHIFT;
++              dev->pd_mgr->pd_dpp_start = rsp->dpp_page_pdid &
++                              OCRDMA_ALLOC_PD_RNG_RSP_START_PDID_MASK;
++              dev->pd_mgr->max_dpp_pd = rsp->pd_count;
++              pd_bitmap_size = BITS_TO_LONGS(rsp->pd_count) * sizeof(long);
++              dev->pd_mgr->pd_dpp_bitmap = kzalloc(pd_bitmap_size,
++                                                   GFP_KERNEL);
++      }
++      kfree(cmd);
++
++      cmd = ocrdma_init_emb_mqe(OCRDMA_CMD_ALLOC_PD_RANGE, sizeof(*cmd));
++      if (!cmd)
++              return -ENOMEM;
++
++      cmd->pd_count = dev->attr.max_pd - dev->attr.max_dpp_pds;
++      status = ocrdma_mbx_cmd(dev, (struct ocrdma_mqe *)cmd);
++      if (status)
++              goto mbx_err;
++      rsp = (struct ocrdma_alloc_pd_range_rsp *)cmd;
++      if (rsp->pd_count) {
++              dev->pd_mgr->pd_norm_start = rsp->dpp_page_pdid &
++                                      OCRDMA_ALLOC_PD_RNG_RSP_START_PDID_MASK;
++              dev->pd_mgr->max_normal_pd = rsp->pd_count;
++              pd_bitmap_size = BITS_TO_LONGS(rsp->pd_count) * sizeof(long);
++              dev->pd_mgr->pd_norm_bitmap = kzalloc(pd_bitmap_size,
++                                                    GFP_KERNEL);
++      }
++
++      if (dev->pd_mgr->pd_norm_bitmap || dev->pd_mgr->pd_dpp_bitmap) {
++              /* Enable PD resource manager */
++              dev->pd_mgr->pd_prealloc_valid = true;
++      } else {
++              return -ENOMEM;
++      }
++mbx_err:
++      kfree(cmd);
++      return status;
++}
++
++static void ocrdma_mbx_dealloc_pd_range(struct ocrdma_dev *dev)
++{
++      struct ocrdma_dealloc_pd_range *cmd;
++
++      /* return normal PDs to firmware */
++      cmd = ocrdma_init_emb_mqe(OCRDMA_CMD_DEALLOC_PD_RANGE, sizeof(*cmd));
++      if (!cmd)
++              goto mbx_err;
++
++      if (dev->pd_mgr->max_normal_pd) {
++              cmd->start_pd_id = dev->pd_mgr->pd_norm_start;
++              cmd->pd_count = dev->pd_mgr->max_normal_pd;
++              ocrdma_mbx_cmd(dev, (struct ocrdma_mqe *)cmd);
++      }
++
++      if (dev->pd_mgr->max_dpp_pd) {
++              kfree(cmd);
++              /* return DPP PDs to firmware */
++              cmd = ocrdma_init_emb_mqe(OCRDMA_CMD_DEALLOC_PD_RANGE,
++                                        sizeof(*cmd));
++              if (!cmd)
++                      goto mbx_err;
++
++              cmd->start_pd_id = dev->pd_mgr->pd_dpp_start;
++              cmd->pd_count = dev->pd_mgr->max_dpp_pd;
++              ocrdma_mbx_cmd(dev, (struct ocrdma_mqe *)cmd);
++      }
++mbx_err:
++      kfree(cmd);
++      return;
++}
++
++void ocrdma_alloc_pd_pool(struct ocrdma_dev *dev)
++{
++      int status;
++      dev->pd_mgr = kzalloc(sizeof(struct ocrdma_pd_resource_mgr),
++                            GFP_KERNEL);
++      if (!dev->pd_mgr) {
++              pr_err("%s(%d)Memory allocation failure.\n", __func__, dev->id);
++              return;
++      }
++      status = ocrdma_mbx_alloc_pd_range(dev);
++      if (status) {
++              pr_err("%s(%d) Unable to initialize PD pool, using default.\n",
++                       __func__, dev->id);
++      }
++      return;
++}
++
++void ocrdma_free_pd_pool(struct ocrdma_dev *dev)
++{
++      ocrdma_mbx_dealloc_pd_range(dev);
++      kfree(dev->pd_mgr->pd_norm_bitmap);
++      kfree(dev->pd_mgr->pd_dpp_bitmap);
++      kfree(dev->pd_mgr);
++}
++
+ static int ocrdma_build_q_conf(u32 *num_entries, int entry_size,
+                              int *num_pages, int *page_size)
+ {
+@@ -1896,8 +2042,9 @@ void ocrdma_flush_qp(struct ocrdma_qp *qp)
+ {
+       bool found;
+       unsigned long flags;
++      struct ocrdma_dev *dev = get_ocrdma_dev(qp->ibqp.device);
+-      spin_lock_irqsave(&qp->dev->flush_q_lock, flags);
++      spin_lock_irqsave(&dev->flush_q_lock, flags);
+       found = ocrdma_is_qp_in_sq_flushlist(qp->sq_cq, qp);
+       if (!found)
+               list_add_tail(&qp->sq_entry, &qp->sq_cq->sq_head);
+@@ -1906,7 +2053,7 @@ void ocrdma_flush_qp(struct ocrdma_qp *qp)
+               if (!found)
+                       list_add_tail(&qp->rq_entry, &qp->rq_cq->rq_head);
+       }
+-      spin_unlock_irqrestore(&qp->dev->flush_q_lock, flags);
++      spin_unlock_irqrestore(&dev->flush_q_lock, flags);
+ }
+ static void ocrdma_init_hwq_ptr(struct ocrdma_qp *qp)
+@@ -1972,7 +2119,8 @@ static int ocrdma_set_create_qp_sq_cmd(struct ocrdma_create_qp_req *cmd,
+       int status;
+       u32 len, hw_pages, hw_page_size;
+       dma_addr_t pa;
+-      struct ocrdma_dev *dev = qp->dev;
++      struct ocrdma_pd *pd = qp->pd;
++      struct ocrdma_dev *dev = get_ocrdma_dev(pd->ibpd.device);
+       struct pci_dev *pdev = dev->nic_info.pdev;
+       u32 max_wqe_allocated;
+       u32 max_sges = attrs->cap.max_send_sge;
+@@ -2027,7 +2175,8 @@ static int ocrdma_set_create_qp_rq_cmd(struct ocrdma_create_qp_req *cmd,
+       int status;
+       u32 len, hw_pages, hw_page_size;
+       dma_addr_t pa = 0;
+-      struct ocrdma_dev *dev = qp->dev;
++      struct ocrdma_pd *pd = qp->pd;
++      struct ocrdma_dev *dev = get_ocrdma_dev(pd->ibpd.device);
+       struct pci_dev *pdev = dev->nic_info.pdev;
+       u32 max_rqe_allocated = attrs->cap.max_recv_wr + 1;
+@@ -2086,7 +2235,8 @@ static void ocrdma_set_create_qp_dpp_cmd(struct ocrdma_create_qp_req *cmd,
+ static int ocrdma_set_create_qp_ird_cmd(struct ocrdma_create_qp_req *cmd,
+                                       struct ocrdma_qp *qp)
+ {
+-      struct ocrdma_dev *dev = qp->dev;
++      struct ocrdma_pd *pd = qp->pd;
++      struct ocrdma_dev *dev = get_ocrdma_dev(pd->ibpd.device);
+       struct pci_dev *pdev = dev->nic_info.pdev;
+       dma_addr_t pa = 0;
+       int ird_page_size = dev->attr.ird_page_size;
+@@ -2157,8 +2307,8 @@ int ocrdma_mbx_create_qp(struct ocrdma_qp *qp, struct ib_qp_init_attr *attrs,
+ {
+       int status = -ENOMEM;
+       u32 flags = 0;
+-      struct ocrdma_dev *dev = qp->dev;
+       struct ocrdma_pd *pd = qp->pd;
++      struct ocrdma_dev *dev = get_ocrdma_dev(pd->ibpd.device);
+       struct pci_dev *pdev = dev->nic_info.pdev;
+       struct ocrdma_cq *cq;
+       struct ocrdma_create_qp_req *cmd;
+@@ -2281,11 +2431,12 @@ static int ocrdma_set_av_params(struct ocrdma_qp *qp,
+       union ib_gid sgid, zgid;
+       u32 vlan_id;
+       u8 mac_addr[6];
++      struct ocrdma_dev *dev = get_ocrdma_dev(qp->ibqp.device);
+       if ((ah_attr->ah_flags & IB_AH_GRH) == 0)
+               return -EINVAL;
+-      if (atomic_cmpxchg(&qp->dev->update_sl, 1, 0))
+-              ocrdma_init_service_level(qp->dev);
++      if (atomic_cmpxchg(&dev->update_sl, 1, 0))
++              ocrdma_init_service_level(dev);
+       cmd->params.tclass_sq_psn |=
+           (ah_attr->grh.traffic_class << OCRDMA_QP_PARAMS_TCLASS_SHIFT);
+       cmd->params.rnt_rc_sl_fl |=
+@@ -2296,7 +2447,7 @@ static int ocrdma_set_av_params(struct ocrdma_qp *qp,
+       cmd->flags |= OCRDMA_QP_PARA_FLOW_LBL_VALID;
+       memcpy(&cmd->params.dgid[0], &ah_attr->grh.dgid.raw[0],
+              sizeof(cmd->params.dgid));
+-      status = ocrdma_query_gid(&qp->dev->ibdev, 1,
++      status = ocrdma_query_gid(&dev->ibdev, 1,
+                       ah_attr->grh.sgid_index, &sgid);
+       if (status)
+               return status;
+@@ -2307,7 +2458,9 @@ static int ocrdma_set_av_params(struct ocrdma_qp *qp,
+       qp->sgid_idx = ah_attr->grh.sgid_index;
+       memcpy(&cmd->params.sgid[0], &sgid.raw[0], sizeof(cmd->params.sgid));
+-      ocrdma_resolve_dmac(qp->dev, ah_attr, &mac_addr[0]);
++      status = ocrdma_resolve_dmac(dev, ah_attr, &mac_addr[0]);
++      if (status)
++              return status;
+       cmd->params.dmac_b0_to_b3 = mac_addr[0] | (mac_addr[1] << 8) |
+                               (mac_addr[2] << 16) | (mac_addr[3] << 24);
+       /* convert them to LE format. */
+@@ -2320,7 +2473,7 @@ static int ocrdma_set_av_params(struct ocrdma_qp *qp,
+                   vlan_id << OCRDMA_QP_PARAMS_VLAN_SHIFT;
+               cmd->flags |= OCRDMA_QP_PARA_VLAN_EN_VALID;
+               cmd->params.rnt_rc_sl_fl |=
+-                      (qp->dev->sl & 0x07) << OCRDMA_QP_PARAMS_SL_SHIFT;
++                      (dev->sl & 0x07) << OCRDMA_QP_PARAMS_SL_SHIFT;
+       }
+       return 0;
+ }
+@@ -2330,6 +2483,7 @@ static int ocrdma_set_qp_params(struct ocrdma_qp *qp,
+                               struct ib_qp_attr *attrs, int attr_mask)
+ {
+       int status = 0;
++      struct ocrdma_dev *dev = get_ocrdma_dev(qp->ibqp.device);
+       if (attr_mask & IB_QP_PKEY_INDEX) {
+               cmd->params.path_mtu_pkey_indx |= (attrs->pkey_index &
+@@ -2347,12 +2501,12 @@ static int ocrdma_set_qp_params(struct ocrdma_qp *qp,
+                       return status;
+       } else if (qp->qp_type == IB_QPT_GSI || qp->qp_type == IB_QPT_UD) {
+               /* set the default mac address for UD, GSI QPs */
+-              cmd->params.dmac_b0_to_b3 = qp->dev->nic_info.mac_addr[0] |
+-                      (qp->dev->nic_info.mac_addr[1] << 8) |
+-                      (qp->dev->nic_info.mac_addr[2] << 16) |
+-                      (qp->dev->nic_info.mac_addr[3] << 24);
+-              cmd->params.vlan_dmac_b4_to_b5 = qp->dev->nic_info.mac_addr[4] |
+-                                      (qp->dev->nic_info.mac_addr[5] << 8);
++              cmd->params.dmac_b0_to_b3 = dev->nic_info.mac_addr[0] |
++                      (dev->nic_info.mac_addr[1] << 8) |
++                      (dev->nic_info.mac_addr[2] << 16) |
++                      (dev->nic_info.mac_addr[3] << 24);
++              cmd->params.vlan_dmac_b4_to_b5 = dev->nic_info.mac_addr[4] |
++                                      (dev->nic_info.mac_addr[5] << 8);
+       }
+       if ((attr_mask & IB_QP_EN_SQD_ASYNC_NOTIFY) &&
+           attrs->en_sqd_async_notify) {
+@@ -2409,7 +2563,7 @@ static int ocrdma_set_qp_params(struct ocrdma_qp *qp,
+               cmd->flags |= OCRDMA_QP_PARA_RQPSN_VALID;
+       }
+       if (attr_mask & IB_QP_MAX_QP_RD_ATOMIC) {
+-              if (attrs->max_rd_atomic > qp->dev->attr.max_ord_per_qp) {
++              if (attrs->max_rd_atomic > dev->attr.max_ord_per_qp) {
+                       status = -EINVAL;
+                       goto pmtu_err;
+               }
+@@ -2417,7 +2571,7 @@ static int ocrdma_set_qp_params(struct ocrdma_qp *qp,
+               cmd->flags |= OCRDMA_QP_PARA_MAX_ORD_VALID;
+       }
+       if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC) {
+-              if (attrs->max_dest_rd_atomic > qp->dev->attr.max_ird_per_qp) {
++              if (attrs->max_dest_rd_atomic > dev->attr.max_ird_per_qp) {
+                       status = -EINVAL;
+                       goto pmtu_err;
+               }
+@@ -2870,6 +3024,82 @@ done:
+       return status;
+ }
++static int ocrdma_mbx_modify_eqd(struct ocrdma_dev *dev, struct ocrdma_eq *eq,
++                               int num)
++{
++      int i, status = -ENOMEM;
++      struct ocrdma_modify_eqd_req *cmd;
++
++      cmd = ocrdma_init_emb_mqe(OCRDMA_CMD_MODIFY_EQ_DELAY, sizeof(*cmd));
++      if (!cmd)
++              return status;
++
++      ocrdma_init_mch(&cmd->cmd.req, OCRDMA_CMD_MODIFY_EQ_DELAY,
++                      OCRDMA_SUBSYS_COMMON, sizeof(*cmd));
++
++      cmd->cmd.num_eq = num;
++      for (i = 0; i < num; i++) {
++              cmd->cmd.set_eqd[i].eq_id = eq[i].q.id;
++              cmd->cmd.set_eqd[i].phase = 0;
++              cmd->cmd.set_eqd[i].delay_multiplier =
++                              (eq[i].aic_obj.prev_eqd * 65)/100;
++      }
++      status = ocrdma_mbx_cmd(dev, (struct ocrdma_mqe *)cmd);
++      if (status)
++              goto mbx_err;
++mbx_err:
++      kfree(cmd);
++      return status;
++}
++
++static int ocrdma_modify_eqd(struct ocrdma_dev *dev, struct ocrdma_eq *eq,
++                           int num)
++{
++      int num_eqs, i = 0;
++      if (num > 8) {
++              while (num) {
++                      num_eqs = min(num, 8);
++                      ocrdma_mbx_modify_eqd(dev, &eq[i], num_eqs);
++                      i += num_eqs;
++                      num -= num_eqs;
++              }
++      } else {
++              ocrdma_mbx_modify_eqd(dev, eq, num);
++      }
++      return 0;
++}
++
++void ocrdma_eqd_set_task(struct work_struct *work)
++{
++      struct ocrdma_dev *dev =
++              container_of(work, struct ocrdma_dev, eqd_work.work);
++      struct ocrdma_eq *eq = 0;
++      int i, num = 0, status = -EINVAL;
++      u64 eq_intr;
++
++      for (i = 0; i < dev->eq_cnt; i++) {
++              eq = &dev->eq_tbl[i];
++              if (eq->aic_obj.eq_intr_cnt > eq->aic_obj.prev_eq_intr_cnt) {
++                      eq_intr = eq->aic_obj.eq_intr_cnt -
++                                eq->aic_obj.prev_eq_intr_cnt;
++                      if ((eq_intr > EQ_INTR_PER_SEC_THRSH_HI) &&
++                          (eq->aic_obj.prev_eqd == EQ_AIC_MIN_EQD)) {
++                              eq->aic_obj.prev_eqd = EQ_AIC_MAX_EQD;
++                              num++;
++                      } else if ((eq_intr < EQ_INTR_PER_SEC_THRSH_LOW) &&
++                                 (eq->aic_obj.prev_eqd == EQ_AIC_MAX_EQD)) {
++                              eq->aic_obj.prev_eqd = EQ_AIC_MIN_EQD;
++                              num++;
++                      }
++              }
++              eq->aic_obj.prev_eq_intr_cnt = eq->aic_obj.eq_intr_cnt;
++      }
++
++      if (num)
++              status = ocrdma_modify_eqd(dev, &dev->eq_tbl[0], num);
++      schedule_delayed_work(&dev->eqd_work, msecs_to_jiffies(1000));
++}
++
+ int ocrdma_init_hw(struct ocrdma_dev *dev)
+ {
+       int status;
+@@ -2915,6 +3145,7 @@ qpeq_err:
+ void ocrdma_cleanup_hw(struct ocrdma_dev *dev)
+ {
++      ocrdma_free_pd_pool(dev);
+       ocrdma_mbx_delete_ah_tbl(dev);
+       /* cleanup the eqs */
+diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_hw.h b/drivers/infiniband/hw/ocrdma/ocrdma_hw.h
+index 6eed8f1..e905972 100644
+--- a/drivers/infiniband/hw/ocrdma/ocrdma_hw.h
++++ b/drivers/infiniband/hw/ocrdma/ocrdma_hw.h
+@@ -136,5 +136,7 @@ int ocrdma_get_irq(struct ocrdma_dev *dev, struct ocrdma_eq *eq);
+ int ocrdma_mbx_rdma_stats(struct ocrdma_dev *, bool reset);
+ char *port_speed_string(struct ocrdma_dev *dev);
+ void ocrdma_init_service_level(struct ocrdma_dev *);
++void ocrdma_alloc_pd_pool(struct ocrdma_dev *dev);
++void ocrdma_free_pd_range(struct ocrdma_dev *dev);
+ #endif                                /* __OCRDMA_HW_H__ */
+diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_main.c b/drivers/infiniband/hw/ocrdma/ocrdma_main.c
+index b0b2257..7a2b59a 100644
+--- a/drivers/infiniband/hw/ocrdma/ocrdma_main.c
++++ b/drivers/infiniband/hw/ocrdma/ocrdma_main.c
+@@ -239,7 +239,7 @@ static int ocrdma_register_device(struct ocrdma_dev *dev)
+       dev->ibdev.node_type = RDMA_NODE_IB_CA;
+       dev->ibdev.phys_port_cnt = 1;
+-      dev->ibdev.num_comp_vectors = 1;
++      dev->ibdev.num_comp_vectors = dev->eq_cnt;
+       /* mandatory verbs. */
+       dev->ibdev.query_device = ocrdma_query_device;
+@@ -329,6 +329,8 @@ static int ocrdma_alloc_resources(struct ocrdma_dev *dev)
+       if (dev->stag_arr == NULL)
+               goto alloc_err;
++      ocrdma_alloc_pd_pool(dev);
++
+       spin_lock_init(&dev->av_tbl.lock);
+       spin_lock_init(&dev->flush_q_lock);
+       return 0;
+@@ -491,6 +493,9 @@ static struct ocrdma_dev *ocrdma_add(struct be_dev_info *dev_info)
+       spin_unlock(&ocrdma_devlist_lock);
+       /* Init stats */
+       ocrdma_add_port_stats(dev);
++      /* Interrupt Moderation */
++      INIT_DELAYED_WORK(&dev->eqd_work, ocrdma_eqd_set_task);
++      schedule_delayed_work(&dev->eqd_work, msecs_to_jiffies(1000));
+       pr_info("%s %s: %s \"%s\" port %d\n",
+               dev_name(&dev->nic_info.pdev->dev), hca_name(dev),
+@@ -528,11 +533,12 @@ static void ocrdma_remove(struct ocrdma_dev *dev)
+       /* first unregister with stack to stop all the active traffic
+        * of the registered clients.
+        */
+-      ocrdma_rem_port_stats(dev);
++      cancel_delayed_work_sync(&dev->eqd_work);
+       ocrdma_remove_sysfiles(dev);
+-
+       ib_unregister_device(&dev->ibdev);
++      ocrdma_rem_port_stats(dev);
++
+       spin_lock(&ocrdma_devlist_lock);
+       list_del_rcu(&dev->entry);
+       spin_unlock(&ocrdma_devlist_lock);
+diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_sli.h b/drivers/infiniband/hw/ocrdma/ocrdma_sli.h
+index 4e03648..243c87c 100644
+--- a/drivers/infiniband/hw/ocrdma/ocrdma_sli.h
++++ b/drivers/infiniband/hw/ocrdma/ocrdma_sli.h
+@@ -75,6 +75,8 @@ enum {
+       OCRDMA_CMD_DESTROY_RBQ = 26,
+       OCRDMA_CMD_GET_RDMA_STATS = 27,
++      OCRDMA_CMD_ALLOC_PD_RANGE = 28,
++      OCRDMA_CMD_DEALLOC_PD_RANGE = 29,
+       OCRDMA_CMD_MAX
+ };
+@@ -87,6 +89,7 @@ enum {
+       OCRDMA_CMD_CREATE_MQ            = 21,
+       OCRDMA_CMD_GET_CTRL_ATTRIBUTES  = 32,
+       OCRDMA_CMD_GET_FW_VER           = 35,
++      OCRDMA_CMD_MODIFY_EQ_DELAY      = 41,
+       OCRDMA_CMD_DELETE_MQ            = 53,
+       OCRDMA_CMD_DELETE_CQ            = 54,
+       OCRDMA_CMD_DELETE_EQ            = 55,
+@@ -101,7 +104,7 @@ enum {
+       QTYPE_MCCQ      = 3
+ };
+-#define OCRDMA_MAX_SGID               8
++#define OCRDMA_MAX_SGID               16
+ #define OCRDMA_MAX_QP    2048
+ #define OCRDMA_MAX_CQ    2048
+@@ -314,6 +317,29 @@ struct ocrdma_create_eq_rsp {
+ #define OCRDMA_EQ_MINOR_OTHER 0x1
++struct ocrmda_set_eqd {
++      u32 eq_id;
++      u32 phase;
++      u32 delay_multiplier;
++};
++
++struct ocrdma_modify_eqd_cmd {
++      struct ocrdma_mbx_hdr req;
++      u32 num_eq;
++      struct ocrmda_set_eqd set_eqd[8];
++} __packed;
++
++struct ocrdma_modify_eqd_req {
++      struct ocrdma_mqe_hdr hdr;
++      struct ocrdma_modify_eqd_cmd cmd;
++};
++
++
++struct ocrdma_modify_eq_delay_rsp {
++      struct ocrdma_mbx_rsp hdr;
++      u32 rsvd0;
++} __packed;
++
+ enum {
+       OCRDMA_MCQE_STATUS_SHIFT        = 0,
+       OCRDMA_MCQE_STATUS_MASK         = 0xFFFF,
+@@ -441,7 +467,9 @@ enum OCRDMA_ASYNC_EVENT_TYPE {
+       OCRDMA_DEVICE_FATAL_EVENT       = 0x08,
+       OCRDMA_SRQCAT_ERROR             = 0x0E,
+       OCRDMA_SRQ_LIMIT_EVENT          = 0x0F,
+-      OCRDMA_QP_LAST_WQE_EVENT        = 0x10
++      OCRDMA_QP_LAST_WQE_EVENT        = 0x10,
++
++      OCRDMA_MAX_ASYNC_ERRORS
+ };
+ /* mailbox command request and responses */
+@@ -1297,6 +1325,37 @@ struct ocrdma_dealloc_pd_rsp {
+       struct ocrdma_mbx_rsp rsp;
+ };
++struct ocrdma_alloc_pd_range {
++      struct ocrdma_mqe_hdr hdr;
++      struct ocrdma_mbx_hdr req;
++      u32 enable_dpp_rsvd;
++      u32 pd_count;
++};
++
++struct ocrdma_alloc_pd_range_rsp {
++      struct ocrdma_mqe_hdr hdr;
++      struct ocrdma_mbx_rsp rsp;
++      u32 dpp_page_pdid;
++      u32 pd_count;
++};
++
++enum {
++      OCRDMA_ALLOC_PD_RNG_RSP_START_PDID_MASK = 0xFFFF,
++};
++
++struct ocrdma_dealloc_pd_range {
++      struct ocrdma_mqe_hdr hdr;
++      struct ocrdma_mbx_hdr req;
++      u32 start_pd_id;
++      u32 pd_count;
++};
++
++struct ocrdma_dealloc_pd_range_rsp {
++      struct ocrdma_mqe_hdr hdr;
++      struct ocrdma_mbx_hdr req;
++      u32 rsvd;
++};
++
+ enum {
+       OCRDMA_ADDR_CHECK_ENABLE        = 1,
+       OCRDMA_ADDR_CHECK_DISABLE       = 0
+@@ -1597,7 +1656,9 @@ enum OCRDMA_CQE_STATUS {
+       OCRDMA_CQE_INV_EEC_STATE_ERR,
+       OCRDMA_CQE_FATAL_ERR,
+       OCRDMA_CQE_RESP_TIMEOUT_ERR,
+-      OCRDMA_CQE_GENERAL_ERR
++      OCRDMA_CQE_GENERAL_ERR,
++
++      OCRDMA_MAX_CQE_ERR
+ };
+ enum {
+@@ -1673,6 +1734,7 @@ enum {
+       OCRDMA_FLAG_FENCE_R     = 0x8,
+       OCRDMA_FLAG_SOLICIT     = 0x10,
+       OCRDMA_FLAG_IMM         = 0x20,
++      OCRDMA_FLAG_AH_VLAN_PR  = 0x40,
+       /* Stag flags */
+       OCRDMA_LKEY_FLAG_LOCAL_WR       = 0x1,
+diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_stats.c b/drivers/infiniband/hw/ocrdma/ocrdma_stats.c
+index 41a9aec..a8822a2 100644
+--- a/drivers/infiniband/hw/ocrdma/ocrdma_stats.c
++++ b/drivers/infiniband/hw/ocrdma/ocrdma_stats.c
+@@ -26,6 +26,7 @@
+  *******************************************************************/
+ #include <rdma/ib_addr.h>
++#include <rdma/ib_pma.h>
+ #include "ocrdma_stats.h"
+ static struct dentry *ocrdma_dbgfs_dir;
+@@ -249,6 +250,27 @@ static char *ocrdma_rx_stats(struct ocrdma_dev *dev)
+       return stats;
+ }
++u64 ocrdma_sysfs_rcv_pkts(struct ocrdma_dev *dev)
++{
++      struct ocrdma_rdma_stats_resp *rdma_stats =
++              (struct ocrdma_rdma_stats_resp *)dev->stats_mem.va;
++      struct ocrdma_rx_stats *rx_stats = &rdma_stats->rx_stats;
++
++      return convert_to_64bit(rx_stats->roce_frames_lo,
++              rx_stats->roce_frames_hi) + (u64)rx_stats->roce_frame_icrc_drops
++              + (u64)rx_stats->roce_frame_payload_len_drops;
++}
++
++u64 ocrdma_sysfs_rcv_data(struct ocrdma_dev *dev)
++{
++      struct ocrdma_rdma_stats_resp *rdma_stats =
++              (struct ocrdma_rdma_stats_resp *)dev->stats_mem.va;
++      struct ocrdma_rx_stats *rx_stats = &rdma_stats->rx_stats;
++
++      return (convert_to_64bit(rx_stats->roce_frame_bytes_lo,
++              rx_stats->roce_frame_bytes_hi))/4;
++}
++
+ static char *ocrdma_tx_stats(struct ocrdma_dev *dev)
+ {
+       char *stats = dev->stats_mem.debugfs_mem, *pcur;
+@@ -292,6 +314,37 @@ static char *ocrdma_tx_stats(struct ocrdma_dev *dev)
+       return stats;
+ }
++u64 ocrdma_sysfs_xmit_pkts(struct ocrdma_dev *dev)
++{
++      struct ocrdma_rdma_stats_resp *rdma_stats =
++              (struct ocrdma_rdma_stats_resp *)dev->stats_mem.va;
++      struct ocrdma_tx_stats *tx_stats = &rdma_stats->tx_stats;
++
++      return (convert_to_64bit(tx_stats->send_pkts_lo,
++                               tx_stats->send_pkts_hi) +
++      convert_to_64bit(tx_stats->write_pkts_lo, tx_stats->write_pkts_hi) +
++      convert_to_64bit(tx_stats->read_pkts_lo, tx_stats->read_pkts_hi) +
++      convert_to_64bit(tx_stats->read_rsp_pkts_lo,
++                       tx_stats->read_rsp_pkts_hi) +
++      convert_to_64bit(tx_stats->ack_pkts_lo, tx_stats->ack_pkts_hi)) ;
++}
++
++u64 ocrdma_sysfs_xmit_data(struct ocrdma_dev *dev)
++{
++        struct ocrdma_rdma_stats_resp *rdma_stats =
++              (struct ocrdma_rdma_stats_resp *)dev->stats_mem.va;
++        struct ocrdma_tx_stats *tx_stats = &rdma_stats->tx_stats;
++
++      return (convert_to_64bit(tx_stats->send_bytes_lo,
++                               tx_stats->send_bytes_hi) +
++              convert_to_64bit(tx_stats->write_bytes_lo,
++                               tx_stats->write_bytes_hi) +
++              convert_to_64bit(tx_stats->read_req_bytes_lo,
++                               tx_stats->read_req_bytes_hi) +
++              convert_to_64bit(tx_stats->read_rsp_bytes_lo,
++                               tx_stats->read_rsp_bytes_hi))/4;
++}
++
+ static char *ocrdma_wqe_stats(struct ocrdma_dev *dev)
+ {
+       char *stats = dev->stats_mem.debugfs_mem, *pcur;
+@@ -432,10 +485,118 @@ static char *ocrdma_rx_dbg_stats(struct ocrdma_dev *dev)
+       return dev->stats_mem.debugfs_mem;
+ }
++static char *ocrdma_driver_dbg_stats(struct ocrdma_dev *dev)
++{
++      char *stats = dev->stats_mem.debugfs_mem, *pcur;
++
++
++      memset(stats, 0, (OCRDMA_MAX_DBGFS_MEM));
++
++      pcur = stats;
++      pcur += ocrdma_add_stat(stats, pcur, "async_cq_err",
++                              (u64)(dev->async_err_stats
++                              [OCRDMA_CQ_ERROR].counter));
++      pcur += ocrdma_add_stat(stats, pcur, "async_cq_overrun_err",
++                              (u64)dev->async_err_stats
++                              [OCRDMA_CQ_OVERRUN_ERROR].counter);
++      pcur += ocrdma_add_stat(stats, pcur, "async_cq_qpcat_err",
++                              (u64)dev->async_err_stats
++                              [OCRDMA_CQ_QPCAT_ERROR].counter);
++      pcur += ocrdma_add_stat(stats, pcur, "async_qp_access_err",
++                              (u64)dev->async_err_stats
++                              [OCRDMA_QP_ACCESS_ERROR].counter);
++      pcur += ocrdma_add_stat(stats, pcur, "async_qp_commm_est_evt",
++                              (u64)dev->async_err_stats
++                              [OCRDMA_QP_COMM_EST_EVENT].counter);
++      pcur += ocrdma_add_stat(stats, pcur, "async_sq_drained_evt",
++                              (u64)dev->async_err_stats
++                              [OCRDMA_SQ_DRAINED_EVENT].counter);
++      pcur += ocrdma_add_stat(stats, pcur, "async_dev_fatal_evt",
++                              (u64)dev->async_err_stats
++                              [OCRDMA_DEVICE_FATAL_EVENT].counter);
++      pcur += ocrdma_add_stat(stats, pcur, "async_srqcat_err",
++                              (u64)dev->async_err_stats
++                              [OCRDMA_SRQCAT_ERROR].counter);
++      pcur += ocrdma_add_stat(stats, pcur, "async_srq_limit_evt",
++                              (u64)dev->async_err_stats
++                              [OCRDMA_SRQ_LIMIT_EVENT].counter);
++      pcur += ocrdma_add_stat(stats, pcur, "async_qp_last_wqe_evt",
++                              (u64)dev->async_err_stats
++                              [OCRDMA_QP_LAST_WQE_EVENT].counter);
++
++      pcur += ocrdma_add_stat(stats, pcur, "cqe_loc_len_err",
++                              (u64)dev->cqe_err_stats
++                              [OCRDMA_CQE_LOC_LEN_ERR].counter);
++      pcur += ocrdma_add_stat(stats, pcur, "cqe_loc_qp_op_err",
++                              (u64)dev->cqe_err_stats
++                              [OCRDMA_CQE_LOC_QP_OP_ERR].counter);
++      pcur += ocrdma_add_stat(stats, pcur, "cqe_loc_eec_op_err",
++                              (u64)dev->cqe_err_stats
++                              [OCRDMA_CQE_LOC_EEC_OP_ERR].counter);
++      pcur += ocrdma_add_stat(stats, pcur, "cqe_loc_prot_err",
++                              (u64)dev->cqe_err_stats
++                              [OCRDMA_CQE_LOC_PROT_ERR].counter);
++      pcur += ocrdma_add_stat(stats, pcur, "cqe_wr_flush_err",
++                              (u64)dev->cqe_err_stats
++                              [OCRDMA_CQE_WR_FLUSH_ERR].counter);
++      pcur += ocrdma_add_stat(stats, pcur, "cqe_mw_bind_err",
++                              (u64)dev->cqe_err_stats
++                              [OCRDMA_CQE_MW_BIND_ERR].counter);
++      pcur += ocrdma_add_stat(stats, pcur, "cqe_bad_resp_err",
++                              (u64)dev->cqe_err_stats
++                              [OCRDMA_CQE_BAD_RESP_ERR].counter);
++      pcur += ocrdma_add_stat(stats, pcur, "cqe_loc_access_err",
++                              (u64)dev->cqe_err_stats
++                              [OCRDMA_CQE_LOC_ACCESS_ERR].counter);
++      pcur += ocrdma_add_stat(stats, pcur, "cqe_rem_inv_req_err",
++                              (u64)dev->cqe_err_stats
++                              [OCRDMA_CQE_REM_INV_REQ_ERR].counter);
++      pcur += ocrdma_add_stat(stats, pcur, "cqe_rem_access_err",
++                              (u64)dev->cqe_err_stats
++                              [OCRDMA_CQE_REM_ACCESS_ERR].counter);
++      pcur += ocrdma_add_stat(stats, pcur, "cqe_rem_op_err",
++                              (u64)dev->cqe_err_stats
++                              [OCRDMA_CQE_REM_OP_ERR].counter);
++      pcur += ocrdma_add_stat(stats, pcur, "cqe_retry_exc_err",
++                              (u64)dev->cqe_err_stats
++                              [OCRDMA_CQE_RETRY_EXC_ERR].counter);
++      pcur += ocrdma_add_stat(stats, pcur, "cqe_rnr_retry_exc_err",
++                              (u64)dev->cqe_err_stats
++                              [OCRDMA_CQE_RNR_RETRY_EXC_ERR].counter);
++      pcur += ocrdma_add_stat(stats, pcur, "cqe_loc_rdd_viol_err",
++                              (u64)dev->cqe_err_stats
++                              [OCRDMA_CQE_LOC_RDD_VIOL_ERR].counter);
++      pcur += ocrdma_add_stat(stats, pcur, "cqe_rem_inv_rd_req_err",
++                              (u64)dev->cqe_err_stats
++                              [OCRDMA_CQE_REM_INV_RD_REQ_ERR].counter);
++      pcur += ocrdma_add_stat(stats, pcur, "cqe_rem_abort_err",
++                              (u64)dev->cqe_err_stats
++                              [OCRDMA_CQE_REM_ABORT_ERR].counter);
++      pcur += ocrdma_add_stat(stats, pcur, "cqe_inv_eecn_err",
++                              (u64)dev->cqe_err_stats
++                              [OCRDMA_CQE_INV_EECN_ERR].counter);
++      pcur += ocrdma_add_stat(stats, pcur, "cqe_inv_eec_state_err",
++                              (u64)dev->cqe_err_stats
++                              [OCRDMA_CQE_INV_EEC_STATE_ERR].counter);
++      pcur += ocrdma_add_stat(stats, pcur, "cqe_fatal_err",
++                              (u64)dev->cqe_err_stats
++                              [OCRDMA_CQE_FATAL_ERR].counter);
++      pcur += ocrdma_add_stat(stats, pcur, "cqe_resp_timeout_err",
++                              (u64)dev->cqe_err_stats
++                              [OCRDMA_CQE_RESP_TIMEOUT_ERR].counter);
++      pcur += ocrdma_add_stat(stats, pcur, "cqe_general_err",
++                              (u64)dev->cqe_err_stats
++                              [OCRDMA_CQE_GENERAL_ERR].counter);
++      return stats;
++}
++
+ static void ocrdma_update_stats(struct ocrdma_dev *dev)
+ {
+       ulong now = jiffies, secs;
+       int status = 0;
++      struct ocrdma_rdma_stats_resp *rdma_stats =
++                    (struct ocrdma_rdma_stats_resp *)dev->stats_mem.va;
++      struct ocrdma_rsrc_stats *rsrc_stats = &rdma_stats->act_rsrc_stats;
+       secs = jiffies_to_msecs(now - dev->last_stats_time) / 1000U;
+       if (secs) {
+@@ -444,10 +605,75 @@ static void ocrdma_update_stats(struct ocrdma_dev *dev)
+               if (status)
+                       pr_err("%s: stats mbox failed with status = %d\n",
+                              __func__, status);
++              /* Update PD counters from PD resource manager */
++              if (dev->pd_mgr->pd_prealloc_valid) {
++                      rsrc_stats->dpp_pds = dev->pd_mgr->pd_dpp_count;
++                      rsrc_stats->non_dpp_pds = dev->pd_mgr->pd_norm_count;
++                      /* Threshold stata*/
++                      rsrc_stats = &rdma_stats->th_rsrc_stats;
++                      rsrc_stats->dpp_pds = dev->pd_mgr->pd_dpp_thrsh;
++                      rsrc_stats->non_dpp_pds = dev->pd_mgr->pd_norm_thrsh;
++              }
+               dev->last_stats_time = jiffies;
+       }
+ }
++static ssize_t ocrdma_dbgfs_ops_write(struct file *filp,
++                                      const char __user *buffer,
++                                      size_t count, loff_t *ppos)
++{
++      char tmp_str[32];
++      long reset;
++      int status = 0;
++      struct ocrdma_stats *pstats = filp->private_data;
++      struct ocrdma_dev *dev = pstats->dev;
++
++      if (count > 32)
++              goto err;
++
++      if (copy_from_user(tmp_str, buffer, count))
++              goto err;
++
++      tmp_str[count-1] = '\0';
++      if (kstrtol(tmp_str, 10, &reset))
++              goto err;
++
++      switch (pstats->type) {
++      case OCRDMA_RESET_STATS:
++              if (reset) {
++                      status = ocrdma_mbx_rdma_stats(dev, true);
++                      if (status) {
++                              pr_err("Failed to reset stats = %d",
++                                              status) ;
++                              goto err;
++                      }
++              }
++              break;
++      default:
++              goto err;
++      }
++
++      return count;
++err:
++      return -EFAULT;
++}
++
++int ocrdma_pma_counters(struct ocrdma_dev *dev,
++                      struct ib_mad *out_mad)
++{
++      struct ib_pma_portcounters *pma_cnt;
++
++      memset(out_mad->data, 0, sizeof out_mad->data);
++      pma_cnt = (void *)(out_mad->data + 40);
++      ocrdma_update_stats(dev);
++
++      pma_cnt->port_xmit_data    = cpu_to_be32(ocrdma_sysfs_xmit_data(dev));
++      pma_cnt->port_rcv_data     = cpu_to_be32(ocrdma_sysfs_rcv_data(dev));
++      pma_cnt->port_xmit_packets = cpu_to_be32(ocrdma_sysfs_xmit_pkts(dev));
++      pma_cnt->port_rcv_packets  = cpu_to_be32(ocrdma_sysfs_rcv_pkts(dev));
++      return 0;
++}
++
+ static ssize_t ocrdma_dbgfs_ops_read(struct file *filp, char __user *buffer,
+                                       size_t usr_buf_len, loff_t *ppos)
+ {
+@@ -492,6 +718,9 @@ static ssize_t ocrdma_dbgfs_ops_read(struct file *filp, char __user *buffer,
+       case OCRDMA_RX_DBG_STATS:
+               data = ocrdma_rx_dbg_stats(dev);
+               break;
++      case OCRDMA_DRV_STATS:
++              data = ocrdma_driver_dbg_stats(dev);
++              break;
+       default:
+               status = -EFAULT;
+@@ -514,6 +743,7 @@ static const struct file_operations ocrdma_dbg_ops = {
+       .owner = THIS_MODULE,
+       .open = simple_open,
+       .read = ocrdma_dbgfs_ops_read,
++      .write = ocrdma_dbgfs_ops_write,
+ };
+ void ocrdma_add_port_stats(struct ocrdma_dev *dev)
+@@ -582,6 +812,18 @@ void ocrdma_add_port_stats(struct ocrdma_dev *dev)
+                                &dev->rx_dbg_stats, &ocrdma_dbg_ops))
+               goto err;
++      dev->driver_stats.type = OCRDMA_DRV_STATS;
++      dev->driver_stats.dev = dev;
++      if (!debugfs_create_file("driver_dbg_stats", S_IRUSR, dev->dir,
++                                      &dev->driver_stats, &ocrdma_dbg_ops))
++              goto err;
++
++      dev->reset_stats.type = OCRDMA_RESET_STATS;
++      dev->reset_stats.dev = dev;
++      if (!debugfs_create_file("reset_stats", S_IRUSR, dev->dir,
++                              &dev->reset_stats, &ocrdma_dbg_ops))
++              goto err;
++
+       /* Now create dma_mem for stats mbx command */
+       if (!ocrdma_alloc_stats_mem(dev))
+               goto err;
+diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_stats.h b/drivers/infiniband/hw/ocrdma/ocrdma_stats.h
+index 5f5e20c..091edd6 100644
+--- a/drivers/infiniband/hw/ocrdma/ocrdma_stats.h
++++ b/drivers/infiniband/hw/ocrdma/ocrdma_stats.h
+@@ -43,12 +43,16 @@ enum OCRDMA_STATS_TYPE {
+       OCRDMA_RXQP_ERRSTATS,
+       OCRDMA_TXQP_ERRSTATS,
+       OCRDMA_TX_DBG_STATS,
+-      OCRDMA_RX_DBG_STATS
++      OCRDMA_RX_DBG_STATS,
++      OCRDMA_DRV_STATS,
++      OCRDMA_RESET_STATS
+ };
+ void ocrdma_rem_debugfs(void);
+ void ocrdma_init_debugfs(void);
+ void ocrdma_rem_port_stats(struct ocrdma_dev *dev);
+ void ocrdma_add_port_stats(struct ocrdma_dev *dev);
++int ocrdma_pma_counters(struct ocrdma_dev *dev,
++                      struct ib_mad *out_mad);
+ #endif        /* __OCRDMA_STATS_H__ */
+diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c b/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c
+index 4c68305..7f8c450 100644
+--- a/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c
++++ b/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c
+@@ -253,6 +253,107 @@ static bool ocrdma_search_mmap(struct ocrdma_ucontext *uctx, u64 phy_addr,
+       return found;
+ }
++
++static u16 _ocrdma_pd_mgr_get_bitmap(struct ocrdma_dev *dev, bool dpp_pool)
++{
++      u16 pd_bitmap_idx = 0;
++      const unsigned long *pd_bitmap;
++
++      if (dpp_pool) {
++              pd_bitmap = dev->pd_mgr->pd_dpp_bitmap;
++              pd_bitmap_idx = find_first_zero_bit(pd_bitmap,
++                                                  dev->pd_mgr->max_dpp_pd);
++              __set_bit(pd_bitmap_idx, dev->pd_mgr->pd_dpp_bitmap);
++              dev->pd_mgr->pd_dpp_count++;
++              if (dev->pd_mgr->pd_dpp_count > dev->pd_mgr->pd_dpp_thrsh)
++                      dev->pd_mgr->pd_dpp_thrsh = dev->pd_mgr->pd_dpp_count;
++      } else {
++              pd_bitmap = dev->pd_mgr->pd_norm_bitmap;
++              pd_bitmap_idx = find_first_zero_bit(pd_bitmap,
++                                                  dev->pd_mgr->max_normal_pd);
++              __set_bit(pd_bitmap_idx, dev->pd_mgr->pd_norm_bitmap);
++              dev->pd_mgr->pd_norm_count++;
++              if (dev->pd_mgr->pd_norm_count > dev->pd_mgr->pd_norm_thrsh)
++                      dev->pd_mgr->pd_norm_thrsh = dev->pd_mgr->pd_norm_count;
++      }
++      return pd_bitmap_idx;
++}
++
++static u8 _ocrdma_pd_mgr_put_bitmap(struct ocrdma_dev *dev, u16 pd_id,
++                                      bool dpp_pool)
++{
++      int status = 0;
++      u16 pd_count;
++      u16 pd_bit_index;
++
++      pd_count = dpp_pool ? dev->pd_mgr->pd_dpp_count :
++                            dev->pd_mgr->pd_norm_count;
++      if (pd_count == 0)
++              return -EINVAL;
++
++      if (dpp_pool) {
++              pd_bit_index = pd_id - dev->pd_mgr->pd_dpp_start;
++              if (pd_bit_index >= dev->pd_mgr->max_dpp_pd) {
++                      status = -EINVAL;
++              } else {
++                      __clear_bit(pd_bit_index, dev->pd_mgr->pd_dpp_bitmap);
++                      dev->pd_mgr->pd_dpp_count--;
++              }
++      } else {
++              pd_bit_index = pd_id - dev->pd_mgr->pd_norm_start;
++              if (pd_bit_index >= dev->pd_mgr->max_normal_pd) {
++                      status = -EINVAL;
++              } else {
++                      __clear_bit(pd_bit_index, dev->pd_mgr->pd_norm_bitmap);
++                      dev->pd_mgr->pd_norm_count--;
++              }
++      }
++      return status;
++}
++
++static u8 ocrdma_put_pd_num(struct ocrdma_dev *dev, u16 pd_id,
++                                 bool dpp_pool)
++{
++      int status;
++
++      mutex_lock(&dev->dev_lock);
++      status = _ocrdma_pd_mgr_put_bitmap(dev, pd_id, dpp_pool);
++      mutex_unlock(&dev->dev_lock);
++      return status;
++}
++
++static int ocrdma_get_pd_num(struct ocrdma_dev *dev, struct ocrdma_pd *pd)
++{
++      u16 pd_idx = 0;
++      int status = 0;
++
++      mutex_lock(&dev->dev_lock);
++      if (pd->dpp_enabled) {
++              /* try allocating DPP PD, if not available then normal PD */
++              if (dev->pd_mgr->pd_dpp_count < dev->pd_mgr->max_dpp_pd) {
++                      pd_idx = _ocrdma_pd_mgr_get_bitmap(dev, true);
++                      pd->id = dev->pd_mgr->pd_dpp_start + pd_idx;
++                      pd->dpp_page = dev->pd_mgr->dpp_page_index + pd_idx;
++              } else if (dev->pd_mgr->pd_norm_count <
++                         dev->pd_mgr->max_normal_pd) {
++                      pd_idx = _ocrdma_pd_mgr_get_bitmap(dev, false);
++                      pd->id = dev->pd_mgr->pd_norm_start + pd_idx;
++                      pd->dpp_enabled = false;
++              } else {
++                      status = -EINVAL;
++              }
++      } else {
++              if (dev->pd_mgr->pd_norm_count < dev->pd_mgr->max_normal_pd) {
++                      pd_idx = _ocrdma_pd_mgr_get_bitmap(dev, false);
++                      pd->id = dev->pd_mgr->pd_norm_start + pd_idx;
++              } else {
++                      status = -EINVAL;
++              }
++      }
++      mutex_unlock(&dev->dev_lock);
++      return status;
++}
++
+ static struct ocrdma_pd *_ocrdma_alloc_pd(struct ocrdma_dev *dev,
+                                         struct ocrdma_ucontext *uctx,
+                                         struct ib_udata *udata)
+@@ -272,6 +373,11 @@ static struct ocrdma_pd *_ocrdma_alloc_pd(struct ocrdma_dev *dev,
+                                          dev->attr.wqe_size) : 0;
+       }
++      if (dev->pd_mgr->pd_prealloc_valid) {
++              status = ocrdma_get_pd_num(dev, pd);
++              return (status == 0) ? pd : ERR_PTR(status);
++      }
++
+ retry:
+       status = ocrdma_mbx_alloc_pd(dev, pd);
+       if (status) {
+@@ -299,7 +405,11 @@ static int _ocrdma_dealloc_pd(struct ocrdma_dev *dev,
+ {
+       int status = 0;
+-      status = ocrdma_mbx_dealloc_pd(dev, pd);
++      if (dev->pd_mgr->pd_prealloc_valid)
++              status = ocrdma_put_pd_num(dev, pd->id, pd->dpp_enabled);
++      else
++              status = ocrdma_mbx_dealloc_pd(dev, pd);
++
+       kfree(pd);
+       return status;
+ }
+@@ -325,7 +435,6 @@ err:
+ static int ocrdma_dealloc_ucontext_pd(struct ocrdma_ucontext *uctx)
+ {
+-      int status = 0;
+       struct ocrdma_pd *pd = uctx->cntxt_pd;
+       struct ocrdma_dev *dev = get_ocrdma_dev(pd->ibpd.device);
+@@ -334,8 +443,8 @@ static int ocrdma_dealloc_ucontext_pd(struct ocrdma_ucontext *uctx)
+                      __func__, dev->id, pd->id);
+       }
+       uctx->cntxt_pd = NULL;
+-      status = _ocrdma_dealloc_pd(dev, pd);
+-      return status;
++      (void)_ocrdma_dealloc_pd(dev, pd);
++      return 0;
+ }
+ static struct ocrdma_pd *ocrdma_get_ucontext_pd(struct ocrdma_ucontext *uctx)
+@@ -569,7 +678,7 @@ err:
+       if (is_uctx_pd) {
+               ocrdma_release_ucontext_pd(uctx);
+       } else {
+-              status = ocrdma_mbx_dealloc_pd(dev, pd);
++              status = _ocrdma_dealloc_pd(dev, pd);
+               kfree(pd);
+       }
+ exit:
+@@ -837,9 +946,8 @@ int ocrdma_dereg_mr(struct ib_mr *ib_mr)
+ {
+       struct ocrdma_mr *mr = get_ocrdma_mr(ib_mr);
+       struct ocrdma_dev *dev = get_ocrdma_dev(ib_mr->device);
+-      int status;
+-      status = ocrdma_mbx_dealloc_lkey(dev, mr->hwmr.fr_mr, mr->hwmr.lkey);
++      (void) ocrdma_mbx_dealloc_lkey(dev, mr->hwmr.fr_mr, mr->hwmr.lkey);
+       ocrdma_free_mr_pbl_tbl(dev, &mr->hwmr);
+@@ -850,11 +958,10 @@ int ocrdma_dereg_mr(struct ib_mr *ib_mr)
+       /* Don't stop cleanup, in case FW is unresponsive */
+       if (dev->mqe_ctx.fw_error_state) {
+-              status = 0;
+               pr_err("%s(%d) fw not responding.\n",
+                      __func__, dev->id);
+       }
+-      return status;
++      return 0;
+ }
+ static int ocrdma_copy_cq_uresp(struct ocrdma_dev *dev, struct ocrdma_cq *cq,
+@@ -986,7 +1093,6 @@ static void ocrdma_flush_cq(struct ocrdma_cq *cq)
+ int ocrdma_destroy_cq(struct ib_cq *ibcq)
+ {
+-      int status;
+       struct ocrdma_cq *cq = get_ocrdma_cq(ibcq);
+       struct ocrdma_eq *eq = NULL;
+       struct ocrdma_dev *dev = get_ocrdma_dev(ibcq->device);
+@@ -1003,7 +1109,7 @@ int ocrdma_destroy_cq(struct ib_cq *ibcq)
+       synchronize_irq(irq);
+       ocrdma_flush_cq(cq);
+-      status = ocrdma_mbx_destroy_cq(dev, cq);
++      (void)ocrdma_mbx_destroy_cq(dev, cq);
+       if (cq->ucontext) {
+               pdid = cq->ucontext->cntxt_pd->id;
+               ocrdma_del_mmap(cq->ucontext, (u64) cq->pa,
+@@ -1014,7 +1120,7 @@ int ocrdma_destroy_cq(struct ib_cq *ibcq)
+       }
+       kfree(cq);
+-      return status;
++      return 0;
+ }
+ static int ocrdma_add_qpn_map(struct ocrdma_dev *dev, struct ocrdma_qp *qp)
+@@ -1113,8 +1219,8 @@ static int ocrdma_copy_qp_uresp(struct ocrdma_qp *qp,
+       int status = 0;
+       u64 usr_db;
+       struct ocrdma_create_qp_uresp uresp;
+-      struct ocrdma_dev *dev = qp->dev;
+       struct ocrdma_pd *pd = qp->pd;
++      struct ocrdma_dev *dev = get_ocrdma_dev(pd->ibpd.device);
+       memset(&uresp, 0, sizeof(uresp));
+       usr_db = dev->nic_info.unmapped_db +
+@@ -1253,7 +1359,6 @@ struct ib_qp *ocrdma_create_qp(struct ib_pd *ibpd,
+               status = -ENOMEM;
+               goto gen_err;
+       }
+-      qp->dev = dev;
+       ocrdma_set_qp_init_params(qp, pd, attrs);
+       if (udata == NULL)
+               qp->cap_flags |= (OCRDMA_QP_MW_BIND | OCRDMA_QP_LKEY0 |
+@@ -1312,7 +1417,7 @@ int _ocrdma_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
+       enum ib_qp_state old_qps;
+       qp = get_ocrdma_qp(ibqp);
+-      dev = qp->dev;
++      dev = get_ocrdma_dev(ibqp->device);
+       if (attr_mask & IB_QP_STATE)
+               status = ocrdma_qp_state_change(qp, attr->qp_state, &old_qps);
+       /* if new and previous states are same hw doesn't need to
+@@ -1335,7 +1440,7 @@ int ocrdma_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
+       enum ib_qp_state old_qps, new_qps;
+       qp = get_ocrdma_qp(ibqp);
+-      dev = qp->dev;
++      dev = get_ocrdma_dev(ibqp->device);
+       /* syncronize with multiple context trying to change, retrive qps */
+       mutex_lock(&dev->dev_lock);
+@@ -1402,7 +1507,7 @@ int ocrdma_query_qp(struct ib_qp *ibqp,
+       u32 qp_state;
+       struct ocrdma_qp_params params;
+       struct ocrdma_qp *qp = get_ocrdma_qp(ibqp);
+-      struct ocrdma_dev *dev = qp->dev;
++      struct ocrdma_dev *dev = get_ocrdma_dev(ibqp->device);
+       memset(&params, 0, sizeof(params));
+       mutex_lock(&dev->dev_lock);
+@@ -1410,8 +1515,8 @@ int ocrdma_query_qp(struct ib_qp *ibqp,
+       mutex_unlock(&dev->dev_lock);
+       if (status)
+               goto mbx_err;
+-      qp_attr->qp_state = get_ibqp_state(IB_QPS_INIT);
+-      qp_attr->cur_qp_state = get_ibqp_state(IB_QPS_INIT);
++      if (qp->qp_type == IB_QPT_UD)
++              qp_attr->qkey = params.qkey;
+       qp_attr->path_mtu =
+               ocrdma_mtu_int_to_enum(params.path_mtu_pkey_indx &
+                               OCRDMA_QP_PARAMS_PATH_MTU_MASK) >>
+@@ -1466,6 +1571,8 @@ int ocrdma_query_qp(struct ib_qp *ibqp,
+       memset(&qp_attr->alt_ah_attr, 0, sizeof(qp_attr->alt_ah_attr));
+       qp_state = (params.max_sge_recv_flags & OCRDMA_QP_PARAMS_STATE_MASK) >>
+                   OCRDMA_QP_PARAMS_STATE_SHIFT;
++      qp_attr->qp_state = get_ibqp_state(qp_state);
++      qp_attr->cur_qp_state = qp_attr->qp_state;
+       qp_attr->sq_draining = (qp_state == OCRDMA_QPS_SQ_DRAINING) ? 1 : 0;
+       qp_attr->max_dest_rd_atomic =
+           params.max_ord_ird >> OCRDMA_QP_PARAMS_MAX_ORD_SHIFT;
+@@ -1473,6 +1580,8 @@ int ocrdma_query_qp(struct ib_qp *ibqp,
+           params.max_ord_ird & OCRDMA_QP_PARAMS_MAX_IRD_MASK;
+       qp_attr->en_sqd_async_notify = (params.max_sge_recv_flags &
+                               OCRDMA_QP_PARAMS_FLAGS_SQD_ASYNC) ? 1 : 0;
++      /* Sync driver QP state with FW */
++      ocrdma_qp_state_change(qp, qp_attr->qp_state, NULL);
+ mbx_err:
+       return status;
+ }
+@@ -1594,7 +1703,7 @@ void ocrdma_del_flush_qp(struct ocrdma_qp *qp)
+ {
+       int found = false;
+       unsigned long flags;
+-      struct ocrdma_dev *dev = qp->dev;
++      struct ocrdma_dev *dev = get_ocrdma_dev(qp->ibqp.device);
+       /* sync with any active CQ poll */
+       spin_lock_irqsave(&dev->flush_q_lock, flags);
+@@ -1611,7 +1720,6 @@ void ocrdma_del_flush_qp(struct ocrdma_qp *qp)
+ int ocrdma_destroy_qp(struct ib_qp *ibqp)
+ {
+-      int status;
+       struct ocrdma_pd *pd;
+       struct ocrdma_qp *qp;
+       struct ocrdma_dev *dev;
+@@ -1620,7 +1728,7 @@ int ocrdma_destroy_qp(struct ib_qp *ibqp)
+       unsigned long flags;
+       qp = get_ocrdma_qp(ibqp);
+-      dev = qp->dev;
++      dev = get_ocrdma_dev(ibqp->device);
+       attrs.qp_state = IB_QPS_ERR;
+       pd = qp->pd;
+@@ -1633,7 +1741,7 @@ int ocrdma_destroy_qp(struct ib_qp *ibqp)
+        * discarded until the old CQEs are discarded.
+        */
+       mutex_lock(&dev->dev_lock);
+-      status = ocrdma_mbx_destroy_qp(dev, qp);
++      (void) ocrdma_mbx_destroy_qp(dev, qp);
+       /*
+        * acquire CQ lock while destroy is in progress, in order to
+@@ -1668,7 +1776,7 @@ int ocrdma_destroy_qp(struct ib_qp *ibqp)
+       kfree(qp->wqe_wr_id_tbl);
+       kfree(qp->rqe_wr_id_tbl);
+       kfree(qp);
+-      return status;
++      return 0;
+ }
+ static int ocrdma_copy_srq_uresp(struct ocrdma_dev *dev, struct ocrdma_srq *srq,
+@@ -1829,6 +1937,8 @@ static void ocrdma_build_ud_hdr(struct ocrdma_qp *qp,
+       else
+               ud_hdr->qkey = wr->wr.ud.remote_qkey;
+       ud_hdr->rsvd_ahid = ah->id;
++      if (ah->av->valid & OCRDMA_AV_VLAN_VALID)
++              hdr->cw |= (OCRDMA_FLAG_AH_VLAN_PR << OCRDMA_WQE_FLAGS_SHIFT);
+ }
+ static void ocrdma_build_sges(struct ocrdma_hdr_wqe *hdr,
+@@ -2005,11 +2115,12 @@ static int ocrdma_build_fr(struct ocrdma_qp *qp, struct ocrdma_hdr_wqe *hdr,
+       u64 fbo;
+       struct ocrdma_ewqe_fr *fast_reg = (struct ocrdma_ewqe_fr *)(hdr + 1);
+       struct ocrdma_mr *mr;
++      struct ocrdma_dev *dev = get_ocrdma_dev(qp->ibqp.device);
+       u32 wqe_size = sizeof(*fast_reg) + sizeof(*hdr);
+       wqe_size = roundup(wqe_size, OCRDMA_WQE_ALIGN_BYTES);
+-      if (wr->wr.fast_reg.page_list_len > qp->dev->attr.max_pages_per_frmr)
++      if (wr->wr.fast_reg.page_list_len > dev->attr.max_pages_per_frmr)
+               return -EINVAL;
+       hdr->cw |= (OCRDMA_FR_MR << OCRDMA_WQE_OPCODE_SHIFT);
+@@ -2037,7 +2148,7 @@ static int ocrdma_build_fr(struct ocrdma_qp *qp, struct ocrdma_hdr_wqe *hdr,
+       fast_reg->size_sge =
+               get_encoded_page_size(1 << wr->wr.fast_reg.page_shift);
+       mr = (struct ocrdma_mr *) (unsigned long)
+-              qp->dev->stag_arr[(hdr->lkey >> 8) & (OCRDMA_MAX_STAG - 1)];
++              dev->stag_arr[(hdr->lkey >> 8) & (OCRDMA_MAX_STAG - 1)];
+       build_frmr_pbes(wr, mr->hwmr.pbl_table, &mr->hwmr);
+       return 0;
+ }
+@@ -2110,8 +2221,6 @@ int ocrdma_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
+                       hdr->cw |= (OCRDMA_WRITE << OCRDMA_WQE_OPCODE_SHIFT);
+                       status = ocrdma_build_write(qp, hdr, wr);
+                       break;
+-              case IB_WR_RDMA_READ_WITH_INV:
+-                      hdr->cw |= (OCRDMA_FLAG_INV << OCRDMA_WQE_FLAGS_SHIFT);
+               case IB_WR_RDMA_READ:
+                       ocrdma_build_read(qp, hdr, wr);
+                       break;
+@@ -2482,8 +2591,11 @@ static bool ocrdma_poll_err_scqe(struct ocrdma_qp *qp,
+                                bool *polled, bool *stop)
+ {
+       bool expand;
++      struct ocrdma_dev *dev = get_ocrdma_dev(qp->ibqp.device);
+       int status = (le32_to_cpu(cqe->flags_status_srcqpn) &
+               OCRDMA_CQE_STATUS_MASK) >> OCRDMA_CQE_STATUS_SHIFT;
++      if (status < OCRDMA_MAX_CQE_ERR)
++              atomic_inc(&dev->cqe_err_stats[status]);
+       /* when hw sq is empty, but rq is not empty, so we continue
+        * to keep the cqe in order to get the cq event again.
+@@ -2602,6 +2714,10 @@ static bool ocrdma_poll_err_rcqe(struct ocrdma_qp *qp, struct ocrdma_cqe *cqe,
+                               int status)
+ {
+       bool expand;
++      struct ocrdma_dev *dev = get_ocrdma_dev(qp->ibqp.device);
++
++      if (status < OCRDMA_MAX_CQE_ERR)
++              atomic_inc(&dev->cqe_err_stats[status]);
+       /* when hw_rq is empty, but wq is not empty, so continue
+        * to keep the cqe to get the cq event again.
+-- 
+1.7.1
+