--- /dev/null
+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_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(¶ms, 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
+