Home Home > GIT Browse
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKernel Build Daemon <kbuild@suse.de>2019-04-21 07:00:49 +0200
committerKernel Build Daemon <kbuild@suse.de>2019-04-21 07:00:49 +0200
commit79784a08aaa0d6463b4f8e212d8f93f8459bc75d (patch)
treefe62d7c2aefb33cc0a68f76a5b2162244b255ad0
parent62e58acd0398fbaf06410900a917ca3354f82adf (diff)
parentab1de4bdffba86d97e4140969f55468af3cff0f9 (diff)
Merge branch 'SLE15' into SLE15-AZURE
-rw-r--r--blacklist.conf1
-rw-r--r--patches.fixes/0001-RDMA-iw_cxgb4-Drop-__GFP_NOFAIL.patch34
-rw-r--r--patches.fixes/0001-rdma-cxgb4-Add-support-for-kernel-mode-SRQ-s.patch1750
-rw-r--r--patches.fixes/0001-rdma-cxgb4-Add-support-for-srq-functions-structs.patch319
-rw-r--r--patches.fixes/0001-rdma-cxgb4-Remove-a-set-but-not-used-variable.patch40
-rw-r--r--patches.fixes/0001-rdma-cxgb4-fix-some-info-leaks.patch66
-rw-r--r--patches.suse/0001-RDMA-cxgb4-Make-c4iw_poll_cq_one-easier-to-analyze.patch119
-rw-r--r--patches.suse/0001-rdma-cxgb4-Add-support-for-64Byte-cqes.patch256
-rw-r--r--series.conf7
9 files changed, 2592 insertions, 0 deletions
diff --git a/blacklist.conf b/blacklist.conf
index c4f91dde71..7ef56ae834 100644
--- a/blacklist.conf
+++ b/blacklist.conf
@@ -1069,3 +1069,4 @@ b59c4830ca185ba0e9f9e046fb1cd10a4a92627a # No bugfix, just cleanup
ea145aacf4ae8485cf179a4d0dc502e9f75044f4 # No bugfix, just cleanup
83cdb56864bcb1466b454f17fff47348ca7925a2 # No bugfix, just cleanup
bebd024e4815b1a170fcd21ead9c2222b23ce9e6 # SLE kernels already enable this
+23ff6ba8feec5c4bdf993af3fba3937d57883dc8 # applied with rdma/cxgb4: Add support for kernel mode SRQ's
diff --git a/patches.fixes/0001-RDMA-iw_cxgb4-Drop-__GFP_NOFAIL.patch b/patches.fixes/0001-RDMA-iw_cxgb4-Drop-__GFP_NOFAIL.patch
new file mode 100644
index 0000000000..12e0cbd62b
--- /dev/null
+++ b/patches.fixes/0001-RDMA-iw_cxgb4-Drop-__GFP_NOFAIL.patch
@@ -0,0 +1,34 @@
+From: Jason Gunthorpe <jgg@mellanox.com>
+Subject: RDMA/iw_cxgb4: Drop __GFP_NOFAIL
+Patch-mainline: v5.1-rc1
+Git-commit: 8ba0ddd09406e35782259f2ac18187ec77d8c093
+References: bsc#1127371
+
+There is no reason for this __GFP_NOFAIL, none of the other routines in
+this file use it, and there is an error unwind here. NOFAIL should be
+reserved for special cases, not used by network drivers.
+
+Fixes: 6a0b6174d35a ("rdma/cxgb4: Add support for kernel mode SRQ's")
+Reported-by: Nicholas Mc Guire <hofrat@osadl.org>
+Signed-off-by: Jason Gunthorpe <jgg@mellanox.com>
+Acked-by: Denis Kirjanov <dkirjanov@suse.com>
+---
+ drivers/infiniband/hw/cxgb4/qp.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/infiniband/hw/cxgb4/qp.c b/drivers/infiniband/hw/cxgb4/qp.c
+index 03f4c66c2659..c00a41144126 100644
+--- a/drivers/infiniband/hw/cxgb4/qp.c
++++ b/drivers/infiniband/hw/cxgb4/qp.c
+@@ -2597,7 +2597,7 @@ static int alloc_srq_queue(struct c4iw_srq *srq, struct c4iw_dev_ucontext *uctx,
+ /* build fw_ri_res_wr */
+ wr_len = sizeof(*res_wr) + sizeof(*res);
+
+- skb = alloc_skb(wr_len, GFP_KERNEL | __GFP_NOFAIL);
++ skb = alloc_skb(wr_len, GFP_KERNEL);
+ if (!skb)
+ goto err_free_queue;
+ set_wr_txq(skb, CPL_PRIORITY_CONTROL, 0);
+--
+2.12.3
+
diff --git a/patches.fixes/0001-rdma-cxgb4-Add-support-for-kernel-mode-SRQ-s.patch b/patches.fixes/0001-rdma-cxgb4-Add-support-for-kernel-mode-SRQ-s.patch
new file mode 100644
index 0000000000..ac40c8f40c
--- /dev/null
+++ b/patches.fixes/0001-rdma-cxgb4-Add-support-for-kernel-mode-SRQ-s.patch
@@ -0,0 +1,1750 @@
+From: Raju Rangoju <rajur@chelsio.com>
+Subject: rdma/cxgb4: Add support for kernel mode SRQ's
+Patch-mainline: v4.19-rc1
+Git-commit: 6a0b6174d35a141dfa30a32c848a3903e2d7f495
+References: bsc#1127371
+
+This patch implements the srq specific verbs such as create/destroy/modify
+and post_srq_recv. And adds srq specific structures and defines to t4.h
+and uapi.
+
+Also updates the cq poll logic to deal with completions that are
+associated with the SRQ's.
+
+This patch also handles kernel mode SRQ_LIMIT events as well as flushed
+SRQ buffers
+
+Signed-off-by: Raju Rangoju <rajur@chelsio.com>
+Reviewed-by: Steve Wise <swise@opengridcomputing.com>
+Signed-off-by: Jason Gunthorpe <jgg@mellanox.com>
+Signed-off-by: Denis Kirjanov <dkirjanov@suse.com>
+---
+ drivers/infiniband/hw/cxgb4/cm.c | 42 +-
+ drivers/infiniband/hw/cxgb4/cq.c | 144 +++++-
+ drivers/infiniband/hw/cxgb4/device.c | 19 +-
+ drivers/infiniband/hw/cxgb4/iw_cxgb4.h | 3 +-
+ drivers/infiniband/hw/cxgb4/provider.c | 12 +-
+ drivers/infiniband/hw/cxgb4/qp.c | 818 ++++++++++++++++++++++++++++-----
+ drivers/infiniband/hw/cxgb4/resource.c | 51 +-
+ drivers/infiniband/hw/cxgb4/t4.h | 9 +-
+ include/uapi/rdma/cxgb4-abi.h | 17 +
+ 9 files changed, 947 insertions(+), 168 deletions(-)
+
+diff --git a/drivers/infiniband/hw/cxgb4/cm.c b/drivers/infiniband/hw/cxgb4/cm.c
+index 099019ca0c99..bfdbb05b4fa8 100644
+--- a/drivers/infiniband/hw/cxgb4/cm.c
++++ b/drivers/infiniband/hw/cxgb4/cm.c
+@@ -1855,10 +1855,34 @@ static int rx_data(struct c4iw_dev *dev, struct sk_buff *skb)
+ return 0;
+ }
+
++static void complete_cached_srq_buffers(struct c4iw_ep *ep, u32 srqidx_status)
++{
++ enum chip_type adapter_type;
++ u32 srqidx;
++ u8 status;
++
++ adapter_type = ep->com.dev->rdev.lldi.adapter_type;
++ status = ABORT_RSS_STATUS_G(be32_to_cpu(srqidx_status));
++ srqidx = ABORT_RSS_SRQIDX_G(be32_to_cpu(srqidx_status));
++
++ /*
++ * If this TCB had a srq buffer cached, then we must complete
++ * it. For user mode, that means saving the srqidx in the
++ * user/kernel status page for this qp. For kernel mode, just
++ * synthesize the CQE now.
++ */
++ if (CHELSIO_CHIP_VERSION(adapter_type) > CHELSIO_T5 && srqidx) {
++ if (ep->com.qp->ibqp.uobject)
++ t4_set_wq_in_error(&ep->com.qp->wq, srqidx);
++ else
++ c4iw_flush_srqidx(ep->com.qp, srqidx);
++ }
++}
++
+ static int abort_rpl(struct c4iw_dev *dev, struct sk_buff *skb)
+ {
+ struct c4iw_ep *ep;
+- struct cpl_abort_rpl_rss *rpl = cplhdr(skb);
++ struct cpl_abort_rpl_rss6 *rpl = cplhdr(skb);
+ int release = 0;
+ unsigned int tid = GET_TID(rpl);
+
+@@ -1867,6 +1891,9 @@ static int abort_rpl(struct c4iw_dev *dev, struct sk_buff *skb)
+ pr_warn("Abort rpl to freed endpoint\n");
+ return 0;
+ }
++
++ complete_cached_srq_buffers(ep, rpl->srqidx_status);
++
+ pr_debug("ep %p tid %u\n", ep, ep->hwtid);
+ mutex_lock(&ep->com.mutex);
+ switch (ep->com.state) {
+@@ -2722,28 +2749,35 @@ static int peer_close(struct c4iw_dev *dev, struct sk_buff *skb)
+
+ static int peer_abort(struct c4iw_dev *dev, struct sk_buff *skb)
+ {
+- struct cpl_abort_req_rss *req = cplhdr(skb);
++ struct cpl_abort_req_rss6 *req = cplhdr(skb);
+ struct c4iw_ep *ep;
+ struct sk_buff *rpl_skb;
+ struct c4iw_qp_attributes attrs;
+ int ret;
+ int release = 0;
+ unsigned int tid = GET_TID(req);
++ u8 status;
++
+ u32 len = roundup(sizeof(struct cpl_abort_rpl), 16);
+
+ ep = get_ep_from_tid(dev, tid);
+ if (!ep)
+ return 0;
+
+- if (cxgb_is_neg_adv(req->status)) {
++ status = ABORT_RSS_STATUS_G(be32_to_cpu(req->srqidx_status));
++
++ if (cxgb_is_neg_adv(status)) {
+ pr_debug("Negative advice on abort- tid %u status %d (%s)\n",
+- ep->hwtid, req->status, neg_adv_str(req->status));
++ ep->hwtid, status, neg_adv_str(status));
+ ep->stats.abort_neg_adv++;
+ mutex_lock(&dev->rdev.stats.lock);
+ dev->rdev.stats.neg_adv++;
+ mutex_unlock(&dev->rdev.stats.lock);
+ goto deref_ep;
+ }
++
++ complete_cached_srq_buffers(ep, req->srqidx_status);
++
+ pr_debug("ep %p tid %u state %u\n", ep, ep->hwtid,
+ ep->com.state);
+ set_bit(PEER_ABORT, &ep->com.history);
+diff --git a/drivers/infiniband/hw/cxgb4/cq.c b/drivers/infiniband/hw/cxgb4/cq.c
+index 187de3ffba7e..d266c8d0bf94 100644
+--- a/drivers/infiniband/hw/cxgb4/cq.c
++++ b/drivers/infiniband/hw/cxgb4/cq.c
+@@ -182,7 +182,7 @@ static int create_cq(struct c4iw_rdev *rdev, struct t4_cq *cq,
+ return ret;
+ }
+
+-static void insert_recv_cqe(struct t4_wq *wq, struct t4_cq *cq)
++static void insert_recv_cqe(struct t4_wq *wq, struct t4_cq *cq, u32 srqidx)
+ {
+ struct t4_cqe cqe;
+
+@@ -195,6 +195,8 @@ static void insert_recv_cqe(struct t4_wq *wq, struct t4_cq *cq)
+ CQE_SWCQE_V(1) |
+ CQE_QPID_V(wq->sq.qid));
+ cqe.bits_type_ts = cpu_to_be64(CQE_GENBIT_V((u64)cq->gen));
++ if (srqidx)
++ cqe.u.srcqe.abs_rqe_idx = cpu_to_be32(srqidx);
+ cq->sw_queue[cq->sw_pidx] = cqe;
+ t4_swcq_produce(cq);
+ }
+@@ -207,7 +209,7 @@ int c4iw_flush_rq(struct t4_wq *wq, struct t4_cq *cq, int count)
+ pr_debug("wq %p cq %p rq.in_use %u skip count %u\n",
+ wq, cq, wq->rq.in_use, count);
+ while (in_use--) {
+- insert_recv_cqe(wq, cq);
++ insert_recv_cqe(wq, cq, 0);
+ flushed++;
+ }
+ return flushed;
+@@ -458,6 +460,72 @@ void c4iw_count_rcqes(struct t4_cq *cq, struct t4_wq *wq, int *count)
+ pr_debug("cq %p count %d\n", cq, *count);
+ }
+
++static void post_pending_srq_wrs(struct t4_srq *srq)
++{
++ struct t4_srq_pending_wr *pwr;
++ u16 idx = 0;
++
++ while (srq->pending_in_use) {
++ pwr = &srq->pending_wrs[srq->pending_cidx];
++ srq->sw_rq[srq->pidx].wr_id = pwr->wr_id;
++ srq->sw_rq[srq->pidx].valid = 1;
++
++ pr_debug("%s posting pending cidx %u pidx %u wq_pidx %u in_use %u rq_size %u wr_id %llx\n",
++ __func__,
++ srq->cidx, srq->pidx, srq->wq_pidx,
++ srq->in_use, srq->size,
++ (unsigned long long)pwr->wr_id);
++
++ c4iw_copy_wr_to_srq(srq, &pwr->wqe, pwr->len16);
++ t4_srq_consume_pending_wr(srq);
++ t4_srq_produce(srq, pwr->len16);
++ idx += DIV_ROUND_UP(pwr->len16 * 16, T4_EQ_ENTRY_SIZE);
++ }
++
++ if (idx) {
++ t4_ring_srq_db(srq, idx, pwr->len16, &pwr->wqe);
++ srq->queue[srq->size].status.host_wq_pidx =
++ srq->wq_pidx;
++ }
++}
++
++static u64 reap_srq_cqe(struct t4_cqe *hw_cqe, struct t4_srq *srq)
++{
++ int rel_idx = CQE_ABS_RQE_IDX(hw_cqe) - srq->rqt_abs_idx;
++ u64 wr_id;
++
++ srq->sw_rq[rel_idx].valid = 0;
++ wr_id = srq->sw_rq[rel_idx].wr_id;
++
++ if (rel_idx == srq->cidx) {
++ pr_debug("%s in order cqe rel_idx %u cidx %u pidx %u wq_pidx %u in_use %u rq_size %u wr_id %llx\n",
++ __func__, rel_idx, srq->cidx, srq->pidx,
++ srq->wq_pidx, srq->in_use, srq->size,
++ (unsigned long long)srq->sw_rq[rel_idx].wr_id);
++ t4_srq_consume(srq);
++ while (srq->ooo_count && !srq->sw_rq[srq->cidx].valid) {
++ pr_debug("%s eat ooo cidx %u pidx %u wq_pidx %u in_use %u rq_size %u ooo_count %u wr_id %llx\n",
++ __func__, srq->cidx, srq->pidx,
++ srq->wq_pidx, srq->in_use,
++ srq->size, srq->ooo_count,
++ (unsigned long long)
++ srq->sw_rq[srq->cidx].wr_id);
++ t4_srq_consume_ooo(srq);
++ }
++ if (srq->ooo_count == 0 && srq->pending_in_use)
++ post_pending_srq_wrs(srq);
++ } else {
++ pr_debug("%s ooo cqe rel_idx %u cidx %u pidx %u wq_pidx %u in_use %u rq_size %u ooo_count %u wr_id %llx\n",
++ __func__, rel_idx, srq->cidx,
++ srq->pidx, srq->wq_pidx,
++ srq->in_use, srq->size,
++ srq->ooo_count,
++ (unsigned long long)srq->sw_rq[rel_idx].wr_id);
++ t4_srq_produce_ooo(srq);
++ }
++ return wr_id;
++}
++
+ /*
+ * poll_cq
+ *
+@@ -475,7 +543,8 @@ void c4iw_count_rcqes(struct t4_cq *cq, struct t4_wq *wq, int *count)
+ * -EOVERFLOW CQ overflow detected.
+ */
+ static int poll_cq(struct t4_wq *wq, struct t4_cq *cq, struct t4_cqe *cqe,
+- u8 *cqe_flushed, u64 *cookie, u32 *credit)
++ u8 *cqe_flushed, u64 *cookie, u32 *credit,
++ struct t4_srq *srq)
+ {
+ int ret = 0;
+ struct t4_cqe *hw_cqe, read_cqe;
+@@ -540,7 +609,7 @@ static int poll_cq(struct t4_wq *wq, struct t4_cq *cq, struct t4_cqe *cqe,
+ */
+ if (CQE_TYPE(hw_cqe) == 1) {
+ if (CQE_STATUS(hw_cqe))
+- t4_set_wq_in_error(wq);
++ t4_set_wq_in_error(wq, 0);
+ ret = -EAGAIN;
+ goto skip_cqe;
+ }
+@@ -551,7 +620,7 @@ static int poll_cq(struct t4_wq *wq, struct t4_cq *cq, struct t4_cqe *cqe,
+ */
+ if (CQE_WRID_STAG(hw_cqe) == 1) {
+ if (CQE_STATUS(hw_cqe))
+- t4_set_wq_in_error(wq);
++ t4_set_wq_in_error(wq, 0);
+ ret = -EAGAIN;
+ goto skip_cqe;
+ }
+@@ -576,7 +645,7 @@ static int poll_cq(struct t4_wq *wq, struct t4_cq *cq, struct t4_cqe *cqe,
+
+ if (CQE_STATUS(hw_cqe) || t4_wq_in_error(wq)) {
+ *cqe_flushed = (CQE_STATUS(hw_cqe) == T4_ERR_SWFLUSH);
+- t4_set_wq_in_error(wq);
++ t4_set_wq_in_error(wq, 0);
+ }
+
+ /*
+@@ -590,15 +659,9 @@ static int poll_cq(struct t4_wq *wq, struct t4_cq *cq, struct t4_cqe *cqe,
+ * then we complete this with T4_ERR_MSN and mark the wq in
+ * error.
+ */
+-
+- if (t4_rq_empty(wq)) {
+- t4_set_wq_in_error(wq);
+- ret = -EAGAIN;
+- goto skip_cqe;
+- }
+ if (unlikely(!CQE_STATUS(hw_cqe) &&
+ CQE_WRID_MSN(hw_cqe) != wq->rq.msn)) {
+- t4_set_wq_in_error(wq);
++ t4_set_wq_in_error(wq, 0);
+ hw_cqe->header |= cpu_to_be32(CQE_STATUS_V(T4_ERR_MSN));
+ }
+ goto proc_cqe;
+@@ -657,11 +720,16 @@ static int poll_cq(struct t4_wq *wq, struct t4_cq *cq, struct t4_cqe *cqe,
+ c4iw_log_wr_stats(wq, hw_cqe);
+ t4_sq_consume(wq);
+ } else {
+- pr_debug("completing rq idx %u\n", wq->rq.cidx);
+- *cookie = wq->rq.sw_rq[wq->rq.cidx].wr_id;
+- if (c4iw_wr_log)
+- c4iw_log_wr_stats(wq, hw_cqe);
+- t4_rq_consume(wq);
++ if (!srq) {
++ pr_debug("completing rq idx %u\n", wq->rq.cidx);
++ *cookie = wq->rq.sw_rq[wq->rq.cidx].wr_id;
++ if (c4iw_wr_log)
++ c4iw_log_wr_stats(wq, hw_cqe);
++ t4_rq_consume(wq);
++ } else {
++ *cookie = reap_srq_cqe(hw_cqe, srq);
++ }
++ wq->rq.msn++;
+ goto skip_cqe;
+ }
+
+@@ -685,16 +753,17 @@ static int poll_cq(struct t4_wq *wq, struct t4_cq *cq, struct t4_cqe *cqe,
+ }
+
+ static int __c4iw_poll_cq_one(struct c4iw_cq *chp, struct c4iw_qp *qhp,
+- struct ib_wc *wc)
++ struct ib_wc *wc, struct c4iw_srq *srq)
+ {
+- struct t4_cqe cqe;
++ struct t4_cqe uninitialized_var(cqe);
+ struct t4_wq *wq = qhp ? &qhp->wq : NULL;
+ u32 credit = 0;
+ u8 cqe_flushed;
+ u64 cookie = 0;
+ int ret;
+
+- ret = poll_cq(wq, &(chp->cq), &cqe, &cqe_flushed, &cookie, &credit);
++ ret = poll_cq(wq, &(chp->cq), &cqe, &cqe_flushed, &cookie, &credit,
++ srq ? &srq->wq : NULL);
+ if (ret)
+ goto out;
+
+@@ -703,6 +772,13 @@ static int __c4iw_poll_cq_one(struct c4iw_cq *chp, struct c4iw_qp *qhp,
+ wc->vendor_err = CQE_STATUS(&cqe);
+ wc->wc_flags = 0;
+
++ /*
++ * Simulate a SRQ_LIMIT_REACHED HW notification if required.
++ */
++ if (srq && !(srq->flags & T4_SRQ_LIMIT_SUPPORT) && srq->armed &&
++ srq->wq.in_use < srq->srq_limit)
++ c4iw_dispatch_srq_limit_reached_event(srq);
++
+ pr_debug("qpid 0x%x type %d opcode %d status 0x%x len %u wrid hi 0x%x lo 0x%x cookie 0x%llx\n",
+ CQE_QPID(&cqe),
+ CQE_TYPE(&cqe), CQE_OPCODE(&cqe),
+@@ -828,6 +904,7 @@ static int __c4iw_poll_cq_one(struct c4iw_cq *chp, struct c4iw_qp *qhp,
+ */
+ static int c4iw_poll_cq_one(struct c4iw_cq *chp, struct ib_wc *wc)
+ {
++ struct c4iw_srq *srq = NULL;
+ struct c4iw_qp *qhp = NULL;
+ struct t4_cqe *rd_cqe;
+ int ret;
+@@ -840,10 +917,15 @@ static int c4iw_poll_cq_one(struct c4iw_cq *chp, struct ib_wc *wc)
+ qhp = get_qhp(chp->rhp, CQE_QPID(rd_cqe));
+ if (qhp) {
+ spin_lock(&qhp->lock);
+- ret = __c4iw_poll_cq_one(chp, qhp, wc);
++ srq = qhp->srq;
++ if (srq)
++ spin_lock(&srq->lock);
++ ret = __c4iw_poll_cq_one(chp, qhp, wc, srq);
+ spin_unlock(&qhp->lock);
++ if (srq)
++ spin_unlock(&srq->lock);
+ } else {
+- ret = __c4iw_poll_cq_one(chp, NULL, wc);
++ ret = __c4iw_poll_cq_one(chp, NULL, wc, NULL);
+ }
+ return ret;
+ }
+@@ -1078,3 +1160,19 @@ int c4iw_arm_cq(struct ib_cq *ibcq, enum ib_cq_notify_flags flags)
+ spin_unlock_irqrestore(&chp->lock, flag);
+ return ret;
+ }
++
++void c4iw_flush_srqidx(struct c4iw_qp *qhp, u32 srqidx)
++{
++ struct c4iw_cq *rchp = to_c4iw_cq(qhp->ibqp.recv_cq);
++ unsigned long flag;
++
++ /* locking heirarchy: cq lock first, then qp lock. */
++ spin_lock_irqsave(&rchp->lock, flag);
++ spin_lock(&qhp->lock);
++
++ /* create a SRQ RECV CQE for srqidx */
++ insert_recv_cqe(&qhp->wq, &rchp->cq, srqidx);
++
++ spin_unlock(&qhp->lock);
++ spin_unlock_irqrestore(&rchp->lock, flag);
++}
+diff --git a/drivers/infiniband/hw/cxgb4/device.c b/drivers/infiniband/hw/cxgb4/device.c
+index d921fea5bf54..e2241100ad4f 100644
+--- a/drivers/infiniband/hw/cxgb4/device.c
++++ b/drivers/infiniband/hw/cxgb4/device.c
+@@ -279,10 +279,11 @@ static int dump_qp(int id, void *p, void *data)
+
+ set_ep_sin_addrs(ep, &lsin, &rsin, &m_lsin, &m_rsin);
+ cc = snprintf(qpd->buf + qpd->pos, space,
+- "rc qp sq id %u rq id %u state %u "
++ "rc qp sq id %u %s id %u state %u "
+ "onchip %u ep tid %u state %u "
+ "%pI4:%u/%u->%pI4:%u/%u\n",
+- qp->wq.sq.qid, qp->wq.rq.qid,
++ qp->wq.sq.qid, qp->srq ? "srq" : "rq",
++ qp->srq ? qp->srq->idx : qp->wq.rq.qid,
+ (int)qp->attr.state,
+ qp->wq.sq.flags & T4_SQ_ONCHIP,
+ ep->hwtid, (int)ep->com.state,
+@@ -484,6 +485,9 @@ static int stats_show(struct seq_file *seq, void *v)
+ seq_printf(seq, " QID: %10llu %10llu %10llu %10llu\n",
+ dev->rdev.stats.qid.total, dev->rdev.stats.qid.cur,
+ dev->rdev.stats.qid.max, dev->rdev.stats.qid.fail);
++ seq_printf(seq, " SRQS: %10llu %10llu %10llu %10llu\n",
++ dev->rdev.stats.srqt.total, dev->rdev.stats.srqt.cur,
++ dev->rdev.stats.srqt.max, dev->rdev.stats.srqt.fail);
+ seq_printf(seq, " TPTMEM: %10llu %10llu %10llu %10llu\n",
+ dev->rdev.stats.stag.total, dev->rdev.stats.stag.cur,
+ dev->rdev.stats.stag.max, dev->rdev.stats.stag.fail);
+@@ -534,6 +538,8 @@ static ssize_t stats_clear(struct file *file, const char __user *buf,
+ dev->rdev.stats.pbl.fail = 0;
+ dev->rdev.stats.rqt.max = 0;
+ dev->rdev.stats.rqt.fail = 0;
++ dev->rdev.stats.rqt.max = 0;
++ dev->rdev.stats.rqt.fail = 0;
+ dev->rdev.stats.ocqp.max = 0;
+ dev->rdev.stats.ocqp.fail = 0;
+ dev->rdev.stats.db_full = 0;
+@@ -839,10 +846,12 @@ static int c4iw_rdev_open(struct c4iw_rdev *rdev)
+ rdev->stats.stag.total = rdev->lldi.vr->stag.size;
+ rdev->stats.pbl.total = rdev->lldi.vr->pbl.size;
+ rdev->stats.rqt.total = rdev->lldi.vr->rq.size;
++ rdev->stats.srqt.total = rdev->lldi.vr->srq.size;
+ rdev->stats.ocqp.total = rdev->lldi.vr->ocq.size;
+ rdev->stats.qid.total = rdev->lldi.vr->qp.size;
+
+- err = c4iw_init_resource(rdev, c4iw_num_stags(rdev), T4_MAX_NUM_PD);
++ err = c4iw_init_resource(rdev, c4iw_num_stags(rdev),
++ T4_MAX_NUM_PD, rdev->lldi.vr->srq.size);
+ if (err) {
+ pr_err("error %d initializing resources\n", err);
+ return err;
+diff --git a/drivers/infiniband/hw/cxgb4/iw_cxgb4.h b/drivers/infiniband/hw/cxgb4/iw_cxgb4.h
+index 0bc28df859fa..ec53c61fcdc6 100644
+--- a/drivers/infiniband/hw/cxgb4/iw_cxgb4.h
++++ b/drivers/infiniband/hw/cxgb4/iw_cxgb4.h
+@@ -1013,7 +1013,8 @@ void c4iw_put_qpid(struct c4iw_rdev *rdev, u32 qpid,
+ struct c4iw_dev_ucontext *uctx);
+ u32 c4iw_get_resource(struct c4iw_id_table *id_table);
+ void c4iw_put_resource(struct c4iw_id_table *id_table, u32 entry);
+-int c4iw_init_resource(struct c4iw_rdev *rdev, u32 nr_tpt, u32 nr_pdid);
++int c4iw_init_resource(struct c4iw_rdev *rdev, u32 nr_tpt,
++ u32 nr_pdid, u32 nr_srqt);
+ int c4iw_init_ctrl_qp(struct c4iw_rdev *rdev);
+ int c4iw_pblpool_create(struct c4iw_rdev *rdev);
+ int c4iw_rqtpool_create(struct c4iw_rdev *rdev);
+diff --git a/drivers/infiniband/hw/cxgb4/provider.c b/drivers/infiniband/hw/cxgb4/provider.c
+index 596ceaefacf4..252cca86aab0 100644
+--- a/drivers/infiniband/hw/cxgb4/provider.c
++++ b/drivers/infiniband/hw/cxgb4/provider.c
+@@ -342,8 +342,11 @@ static int c4iw_query_device(struct ib_device *ibdev, struct ib_device_attr *pro
+ props->vendor_part_id = (u32)dev->rdev.lldi.pdev->device;
+ props->max_mr_size = T4_MAX_MR_SIZE;
+ props->max_qp = dev->rdev.lldi.vr->qp.size / 2;
++ props->max_srq = dev->rdev.lldi.vr->srq.size;
+ props->max_qp_wr = dev->rdev.hw_queue.t4_max_qp_depth;
++ props->max_srq_wr = dev->rdev.hw_queue.t4_max_qp_depth;
+ props->max_sge = T4_MAX_RECV_SGE;
++ props->max_srq_sge = T4_MAX_RECV_SGE;
+ props->max_sge_rd = 1;
+ props->max_res_rd_atom = dev->rdev.lldi.max_ird_adapter;
+ props->max_qp_rd_atom = min(dev->rdev.lldi.max_ordird_qp,
+@@ -585,7 +588,10 @@ void c4iw_register_device(struct work_struct *work)
+ (1ull << IB_USER_VERBS_CMD_POLL_CQ) |
+ (1ull << IB_USER_VERBS_CMD_DESTROY_QP) |
+ (1ull << IB_USER_VERBS_CMD_POST_SEND) |
+- (1ull << IB_USER_VERBS_CMD_POST_RECV);
++ (1ull << IB_USER_VERBS_CMD_POST_RECV) |
++ (1ull << IB_USER_VERBS_CMD_CREATE_SRQ) |
++ (1ull << IB_USER_VERBS_CMD_MODIFY_SRQ) |
++ (1ull << IB_USER_VERBS_CMD_DESTROY_SRQ);
+ dev->ibdev.node_type = RDMA_NODE_RNIC;
+ BUILD_BUG_ON(sizeof(C4IW_NODE_DESC) > IB_DEVICE_NODE_DESC_MAX);
+ memcpy(dev->ibdev.node_desc, C4IW_NODE_DESC, sizeof(C4IW_NODE_DESC));
+@@ -607,6 +613,9 @@ void c4iw_register_device(struct work_struct *work)
+ dev->ibdev.modify_qp = c4iw_ib_modify_qp;
+ dev->ibdev.query_qp = c4iw_ib_query_qp;
+ dev->ibdev.destroy_qp = c4iw_destroy_qp;
++ dev->ibdev.create_srq = c4iw_create_srq;
++ dev->ibdev.modify_srq = c4iw_modify_srq;
++ dev->ibdev.destroy_srq = c4iw_destroy_srq;
+ dev->ibdev.create_cq = c4iw_create_cq;
+ dev->ibdev.destroy_cq = c4iw_destroy_cq;
+ dev->ibdev.resize_cq = c4iw_resize_cq;
+@@ -624,6 +633,7 @@ void c4iw_register_device(struct work_struct *work)
+ dev->ibdev.req_notify_cq = c4iw_arm_cq;
+ dev->ibdev.post_send = c4iw_post_send;
+ dev->ibdev.post_recv = c4iw_post_receive;
++ dev->ibdev.post_srq_recv = c4iw_post_srq_recv;
+ dev->ibdev.alloc_hw_stats = c4iw_alloc_stats;
+ dev->ibdev.get_hw_stats = c4iw_get_mib;
+ dev->ibdev.uverbs_abi_ver = C4IW_UVERBS_ABI_VERSION;
+diff --git a/drivers/infiniband/hw/cxgb4/qp.c b/drivers/infiniband/hw/cxgb4/qp.c
+index 5026be5be973..19e2fff210bf 100644
+--- a/drivers/infiniband/hw/cxgb4/qp.c
++++ b/drivers/infiniband/hw/cxgb4/qp.c
+@@ -147,21 +147,24 @@ static int alloc_sq(struct c4iw_rdev *rdev, struct t4_sq *sq, int user)
+ }
+
+ static int destroy_qp(struct c4iw_rdev *rdev, struct t4_wq *wq,
+- struct c4iw_dev_ucontext *uctx)
++ struct c4iw_dev_ucontext *uctx, int has_rq)
+ {
+ /*
+ * uP clears EQ contexts when the connection exits rdma mode,
+ * so no need to post a RESET WR for these EQs.
+ */
+- dma_free_coherent(&(rdev->lldi.pdev->dev),
+- wq->rq.memsize, wq->rq.queue,
+- dma_unmap_addr(&wq->rq, mapping));
+ dealloc_sq(rdev, &wq->sq);
+- c4iw_rqtpool_free(rdev, wq->rq.rqt_hwaddr, wq->rq.rqt_size);
+- kfree(wq->rq.sw_rq);
+ kfree(wq->sq.sw_sq);
+- c4iw_put_qpid(rdev, wq->rq.qid, uctx);
+ c4iw_put_qpid(rdev, wq->sq.qid, uctx);
++
++ if (has_rq) {
++ dma_free_coherent(&rdev->lldi.pdev->dev,
++ wq->rq.memsize, wq->rq.queue,
++ dma_unmap_addr(&wq->rq, mapping));
++ c4iw_rqtpool_free(rdev, wq->rq.rqt_hwaddr, wq->rq.rqt_size);
++ kfree(wq->rq.sw_rq);
++ c4iw_put_qpid(rdev, wq->rq.qid, uctx);
++ }
+ return 0;
+ }
+
+@@ -195,7 +198,8 @@ void __iomem *c4iw_bar2_addrs(struct c4iw_rdev *rdev, unsigned int qid,
+ static int create_qp(struct c4iw_rdev *rdev, struct t4_wq *wq,
+ struct t4_cq *rcq, struct t4_cq *scq,
+ struct c4iw_dev_ucontext *uctx,
+- struct c4iw_wr_wait *wr_waitp)
++ struct c4iw_wr_wait *wr_waitp,
++ int need_rq)
+ {
+ int user = (uctx != &rdev->uctx);
+ struct fw_ri_res_wr *res_wr;
+@@ -209,10 +213,12 @@ static int create_qp(struct c4iw_rdev *rdev, struct t4_wq *wq,
+ if (!wq->sq.qid)
+ return -ENOMEM;
+
+- wq->rq.qid = c4iw_get_qpid(rdev, uctx);
+- if (!wq->rq.qid) {
+- ret = -ENOMEM;
+- goto free_sq_qid;
++ if (need_rq) {
++ wq->rq.qid = c4iw_get_qpid(rdev, uctx);
++ if (!wq->rq.qid) {
++ ret = -ENOMEM;
++ goto free_sq_qid;
++ }
+ }
+
+ if (!user) {
+@@ -220,25 +226,31 @@ static int create_qp(struct c4iw_rdev *rdev, struct t4_wq *wq,
+ GFP_KERNEL);
+ if (!wq->sq.sw_sq) {
+ ret = -ENOMEM;
+- goto free_rq_qid;
++ goto free_rq_qid;//FIXME
+ }
+
+- wq->rq.sw_rq = kzalloc(wq->rq.size * sizeof *wq->rq.sw_rq,
+- GFP_KERNEL);
+- if (!wq->rq.sw_rq) {
+- ret = -ENOMEM;
+- goto free_sw_sq;
++ if (need_rq) {
++ wq->rq.sw_rq = kcalloc(wq->rq.size,
++ sizeof(*wq->rq.sw_rq),
++ GFP_KERNEL);
++ if (!wq->rq.sw_rq) {
++ ret = -ENOMEM;
++ goto free_sw_sq;
++ }
+ }
+ }
+
+- /*
+- * RQT must be a power of 2 and at least 16 deep.
+- */
+- wq->rq.rqt_size = roundup_pow_of_two(max_t(u16, wq->rq.size, 16));
+- wq->rq.rqt_hwaddr = c4iw_rqtpool_alloc(rdev, wq->rq.rqt_size);
+- if (!wq->rq.rqt_hwaddr) {
+- ret = -ENOMEM;
+- goto free_sw_rq;
++ if (need_rq) {
++ /*
++ * RQT must be a power of 2 and at least 16 deep.
++ */
++ wq->rq.rqt_size =
++ roundup_pow_of_two(max_t(u16, wq->rq.size, 16));
++ wq->rq.rqt_hwaddr = c4iw_rqtpool_alloc(rdev, wq->rq.rqt_size);
++ if (!wq->rq.rqt_hwaddr) {
++ ret = -ENOMEM;
++ goto free_sw_rq;
++ }
+ }
+
+ ret = alloc_sq(rdev, &wq->sq, user);
+@@ -247,34 +259,39 @@ static int create_qp(struct c4iw_rdev *rdev, struct t4_wq *wq,
+ memset(wq->sq.queue, 0, wq->sq.memsize);
+ dma_unmap_addr_set(&wq->sq, mapping, wq->sq.dma_addr);
+
+- wq->rq.queue = dma_alloc_coherent(&(rdev->lldi.pdev->dev),
+- wq->rq.memsize, &(wq->rq.dma_addr),
+- GFP_KERNEL);
+- if (!wq->rq.queue) {
+- ret = -ENOMEM;
+- goto free_sq;
++ if (need_rq) {
++ wq->rq.queue = dma_alloc_coherent(&rdev->lldi.pdev->dev,
++ wq->rq.memsize,
++ &wq->rq.dma_addr,
++ GFP_KERNEL);
++ if (!wq->rq.queue) {
++ ret = -ENOMEM;
++ goto free_sq;
++ }
++ pr_debug("sq base va 0x%p pa 0x%llx rq base va 0x%p pa 0x%llx\n",
++ wq->sq.queue,
++ (unsigned long long)virt_to_phys(wq->sq.queue),
++ wq->rq.queue,
++ (unsigned long long)virt_to_phys(wq->rq.queue));
++ memset(wq->rq.queue, 0, wq->rq.memsize);
++ dma_unmap_addr_set(&wq->rq, mapping, wq->rq.dma_addr);
+ }
+- pr_debug("sq base va 0x%p pa 0x%llx rq base va 0x%p pa 0x%llx\n",
+- wq->sq.queue,
+- (unsigned long long)virt_to_phys(wq->sq.queue),
+- wq->rq.queue,
+- (unsigned long long)virt_to_phys(wq->rq.queue));
+- memset(wq->rq.queue, 0, wq->rq.memsize);
+- dma_unmap_addr_set(&wq->rq, mapping, wq->rq.dma_addr);
+
+ wq->db = rdev->lldi.db_reg;
+
+ wq->sq.bar2_va = c4iw_bar2_addrs(rdev, wq->sq.qid, T4_BAR2_QTYPE_EGRESS,
+ &wq->sq.bar2_qid,
+ user ? &wq->sq.bar2_pa : NULL);
+- wq->rq.bar2_va = c4iw_bar2_addrs(rdev, wq->rq.qid, T4_BAR2_QTYPE_EGRESS,
+- &wq->rq.bar2_qid,
+- user ? &wq->rq.bar2_pa : NULL);
++ if (need_rq)
++ wq->rq.bar2_va = c4iw_bar2_addrs(rdev, wq->rq.qid,
++ T4_BAR2_QTYPE_EGRESS,
++ &wq->rq.bar2_qid,
++ user ? &wq->rq.bar2_pa : NULL);
+
+ /*
+ * User mode must have bar2 access.
+ */
+- if (user && (!wq->sq.bar2_pa || !wq->rq.bar2_pa)) {
++ if (user && (!wq->sq.bar2_pa || (need_rq && !wq->rq.bar2_pa))) {
+ pr_warn("%s: sqid %u or rqid %u not in BAR2 range\n",
+ pci_name(rdev->lldi.pdev), wq->sq.qid, wq->rq.qid);
+ goto free_dma;
+@@ -285,7 +302,8 @@ static int create_qp(struct c4iw_rdev *rdev, struct t4_wq *wq,
+
+ /* build fw_ri_res_wr */
+ wr_len = sizeof *res_wr + 2 * sizeof *res;
+-
++ if (need_rq)
++ wr_len += sizeof(*res);
+ skb = alloc_skb(wr_len, GFP_KERNEL);
+ if (!skb) {
+ ret = -ENOMEM;
+@@ -296,7 +314,7 @@ static int create_qp(struct c4iw_rdev *rdev, struct t4_wq *wq,
+ res_wr = __skb_put_zero(skb, wr_len);
+ res_wr->op_nres = cpu_to_be32(
+ FW_WR_OP_V(FW_RI_RES_WR) |
+- FW_RI_RES_WR_NRES_V(2) |
++ FW_RI_RES_WR_NRES_V(need_rq ? 2 : 1) |
+ FW_WR_COMPL_F);
+ res_wr->len16_pkd = cpu_to_be32(DIV_ROUND_UP(wr_len, 16));
+ res_wr->cookie = (uintptr_t)wr_waitp;
+@@ -327,30 +345,36 @@ static int create_qp(struct c4iw_rdev *rdev, struct t4_wq *wq,
+ FW_RI_RES_WR_EQSIZE_V(eqsize));
+ res->u.sqrq.eqid = cpu_to_be32(wq->sq.qid);
+ res->u.sqrq.eqaddr = cpu_to_be64(wq->sq.dma_addr);
+- res++;
+- res->u.sqrq.restype = FW_RI_RES_TYPE_RQ;
+- res->u.sqrq.op = FW_RI_RES_OP_WRITE;
+
+- /*
+- * eqsize is the number of 64B entries plus the status page size.
+- */
+- eqsize = wq->rq.size * T4_RQ_NUM_SLOTS +
+- rdev->hw_queue.t4_eq_status_entries;
+- res->u.sqrq.fetchszm_to_iqid = cpu_to_be32(
+- FW_RI_RES_WR_HOSTFCMODE_V(0) | /* no host cidx updates */
+- FW_RI_RES_WR_CPRIO_V(0) | /* don't keep in chip cache */
+- FW_RI_RES_WR_PCIECHN_V(0) | /* set by uP at ri_init time */
+- FW_RI_RES_WR_IQID_V(rcq->cqid));
+- res->u.sqrq.dcaen_to_eqsize = cpu_to_be32(
+- FW_RI_RES_WR_DCAEN_V(0) |
+- FW_RI_RES_WR_DCACPU_V(0) |
+- FW_RI_RES_WR_FBMIN_V(2) |
+- FW_RI_RES_WR_FBMAX_V(3) |
+- FW_RI_RES_WR_CIDXFTHRESHO_V(0) |
+- FW_RI_RES_WR_CIDXFTHRESH_V(0) |
+- FW_RI_RES_WR_EQSIZE_V(eqsize));
+- res->u.sqrq.eqid = cpu_to_be32(wq->rq.qid);
+- res->u.sqrq.eqaddr = cpu_to_be64(wq->rq.dma_addr);
++ if (need_rq) {
++ res++;
++ res->u.sqrq.restype = FW_RI_RES_TYPE_RQ;
++ res->u.sqrq.op = FW_RI_RES_OP_WRITE;
++
++ /*
++ * eqsize is the number of 64B entries plus the status page size
++ */
++ eqsize = wq->rq.size * T4_RQ_NUM_SLOTS +
++ rdev->hw_queue.t4_eq_status_entries;
++ res->u.sqrq.fetchszm_to_iqid =
++ /* no host cidx updates */
++ cpu_to_be32(FW_RI_RES_WR_HOSTFCMODE_V(0) |
++ /* don't keep in chip cache */
++ FW_RI_RES_WR_CPRIO_V(0) |
++ /* set by uP at ri_init time */
++ FW_RI_RES_WR_PCIECHN_V(0) |
++ FW_RI_RES_WR_IQID_V(rcq->cqid));
++ res->u.sqrq.dcaen_to_eqsize =
++ cpu_to_be32(FW_RI_RES_WR_DCAEN_V(0) |
++ FW_RI_RES_WR_DCACPU_V(0) |
++ FW_RI_RES_WR_FBMIN_V(2) |
++ FW_RI_RES_WR_FBMAX_V(3) |
++ FW_RI_RES_WR_CIDXFTHRESHO_V(0) |
++ FW_RI_RES_WR_CIDXFTHRESH_V(0) |
++ FW_RI_RES_WR_EQSIZE_V(eqsize));
++ res->u.sqrq.eqid = cpu_to_be32(wq->rq.qid);
++ res->u.sqrq.eqaddr = cpu_to_be64(wq->rq.dma_addr);
++ }
+
+ c4iw_init_wr_wait(wr_waitp);
+ ret = c4iw_ref_send_wait(rdev, skb, wr_waitp, 0, wq->sq.qid, __func__);
+@@ -363,19 +387,23 @@ static int create_qp(struct c4iw_rdev *rdev, struct t4_wq *wq,
+
+ return 0;
+ free_dma:
+- dma_free_coherent(&(rdev->lldi.pdev->dev),
+- wq->rq.memsize, wq->rq.queue,
+- dma_unmap_addr(&wq->rq, mapping));
++ if (need_rq)
++ dma_free_coherent(&rdev->lldi.pdev->dev,
++ wq->rq.memsize, wq->rq.queue,
++ dma_unmap_addr(&wq->rq, mapping));
+ free_sq:
+ dealloc_sq(rdev, &wq->sq);
+ free_hwaddr:
+- c4iw_rqtpool_free(rdev, wq->rq.rqt_hwaddr, wq->rq.rqt_size);
++ if (need_rq)
++ c4iw_rqtpool_free(rdev, wq->rq.rqt_hwaddr, wq->rq.rqt_size);
+ free_sw_rq:
+- kfree(wq->rq.sw_rq);
++ if (need_rq)
++ kfree(wq->rq.sw_rq);
+ free_sw_sq:
+ kfree(wq->sq.sw_sq);
+ free_rq_qid:
+- c4iw_put_qpid(rdev, wq->rq.qid, uctx);
++ if (need_rq)
++ c4iw_put_qpid(rdev, wq->rq.qid, uctx);
+ free_sq_qid:
+ c4iw_put_qpid(rdev, wq->sq.qid, uctx);
+ return ret;
+@@ -605,6 +633,20 @@ static int build_rdma_recv(struct c4iw_qp *qhp, union t4_recv_wr *wqe,
+ return 0;
+ }
+
++static int build_srq_recv(union t4_recv_wr *wqe, struct ib_recv_wr *wr,
++ u8 *len16)
++{
++ int ret;
++
++ ret = build_isgl((__be64 *)wqe, (__be64 *)(wqe + 1),
++ &wqe->recv.isgl, wr->sg_list, wr->num_sge, NULL);
++ if (ret)
++ return ret;
++ *len16 = DIV_ROUND_UP(sizeof(wqe->recv) +
++ wr->num_sge * sizeof(struct fw_ri_sge), 16);
++ return 0;
++}
++
+ static void build_tpte_memreg(struct fw_ri_fr_nsmr_tpte_wr *fr,
+ struct ib_reg_wr *wr, struct c4iw_mr *mhp,
+ u8 *len16)
+@@ -721,7 +763,7 @@ static void free_qp_work(struct work_struct *work)
+
+ pr_debug("qhp %p ucontext %p\n", qhp, ucontext);
+ destroy_qp(&rhp->rdev, &qhp->wq,
+- ucontext ? &ucontext->uctx : &rhp->rdev.uctx);
++ ucontext ? &ucontext->uctx : &rhp->rdev.uctx, !qhp->srq);
+
+ if (ucontext)
+ c4iw_put_ucontext(ucontext);
+@@ -1145,6 +1187,89 @@ int c4iw_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *wr,
+ return err;
+ }
+
++static void defer_srq_wr(struct t4_srq *srq, union t4_recv_wr *wqe,
++ u64 wr_id, u8 len16)
++{
++ struct t4_srq_pending_wr *pwr = &srq->pending_wrs[srq->pending_pidx];
++
++ pr_debug("%s cidx %u pidx %u wq_pidx %u in_use %u ooo_count %u wr_id 0x%llx pending_cidx %u pending_pidx %u pending_in_use %u\n",
++ __func__, srq->cidx, srq->pidx, srq->wq_pidx,
++ srq->in_use, srq->ooo_count,
++ (unsigned long long)wr_id, srq->pending_cidx,
++ srq->pending_pidx, srq->pending_in_use);
++ pwr->wr_id = wr_id;
++ pwr->len16 = len16;
++ memcpy(&pwr->wqe, wqe, len16 * 16);
++ t4_srq_produce_pending_wr(srq);
++}
++
++int c4iw_post_srq_recv(struct ib_srq *ibsrq, struct ib_recv_wr *wr,
++ struct ib_recv_wr **bad_wr)
++{
++ union t4_recv_wr *wqe, lwqe;
++ struct c4iw_srq *srq;
++ unsigned long flag;
++ u8 len16 = 0;
++ u16 idx = 0;
++ int err = 0;
++ u32 num_wrs;
++
++ srq = to_c4iw_srq(ibsrq);
++ spin_lock_irqsave(&srq->lock, flag);
++ num_wrs = t4_srq_avail(&srq->wq);
++ if (num_wrs == 0) {
++ spin_unlock_irqrestore(&srq->lock, flag);
++ return -ENOMEM;
++ }
++ while (wr) {
++ if (wr->num_sge > T4_MAX_RECV_SGE) {
++ err = -EINVAL;
++ *bad_wr = wr;
++ break;
++ }
++ wqe = &lwqe;
++ if (num_wrs)
++ err = build_srq_recv(wqe, wr, &len16);
++ else
++ err = -ENOMEM;
++ if (err) {
++ *bad_wr = wr;
++ break;
++ }
++
++ wqe->recv.opcode = FW_RI_RECV_WR;
++ wqe->recv.r1 = 0;
++ wqe->recv.wrid = srq->wq.pidx;
++ wqe->recv.r2[0] = 0;
++ wqe->recv.r2[1] = 0;
++ wqe->recv.r2[2] = 0;
++ wqe->recv.len16 = len16;
++
++ if (srq->wq.ooo_count ||
++ srq->wq.pending_in_use ||
++ srq->wq.sw_rq[srq->wq.pidx].valid) {
++ defer_srq_wr(&srq->wq, wqe, wr->wr_id, len16);
++ } else {
++ srq->wq.sw_rq[srq->wq.pidx].wr_id = wr->wr_id;
++ srq->wq.sw_rq[srq->wq.pidx].valid = 1;
++ c4iw_copy_wr_to_srq(&srq->wq, wqe, len16);
++ pr_debug("%s cidx %u pidx %u wq_pidx %u in_use %u wr_id 0x%llx\n",
++ __func__, srq->wq.cidx,
++ srq->wq.pidx, srq->wq.wq_pidx,
++ srq->wq.in_use,
++ (unsigned long long)wr->wr_id);
++ t4_srq_produce(&srq->wq, len16);
++ idx += DIV_ROUND_UP(len16 * 16, T4_EQ_ENTRY_SIZE);
++ }
++ wr = wr->next;
++ num_wrs--;
++ }
++ if (idx)
++ t4_ring_srq_db(&srq->wq, idx, len16, wqe);
++ spin_unlock_irqrestore(&srq->lock, flag);
++ return err;
++}
++
+ static inline void build_term_codes(struct t4_cqe *err_cqe, u8 *layer_type,
+ u8 *ecode)
+ {
+@@ -1322,7 +1447,7 @@ static void __flush_qp(struct c4iw_qp *qhp, struct c4iw_cq *rchp,
+ struct c4iw_cq *schp)
+ {
+ int count;
+- int rq_flushed, sq_flushed;
++ int rq_flushed = 0, sq_flushed;
+ unsigned long flag;
+
+ pr_debug("qhp %p rchp %p schp %p\n", qhp, rchp, schp);
+@@ -1341,11 +1466,13 @@ static void __flush_qp(struct c4iw_qp *qhp, struct c4iw_cq *rchp,
+ return;
+ }
+ qhp->wq.flushed = 1;
+- t4_set_wq_in_error(&qhp->wq);
++ t4_set_wq_in_error(&qhp->wq, 0);
+
+ c4iw_flush_hw_cq(rchp, qhp);
+- c4iw_count_rcqes(&rchp->cq, &qhp->wq, &count);
+- rq_flushed = c4iw_flush_rq(&qhp->wq, &rchp->cq, count);
++ if (!qhp->srq) {
++ c4iw_count_rcqes(&rchp->cq, &qhp->wq, &count);
++ rq_flushed = c4iw_flush_rq(&qhp->wq, &rchp->cq, count);
++ }
+
+ if (schp != rchp)
+ c4iw_flush_hw_cq(schp, qhp);
+@@ -1389,7 +1516,7 @@ static void flush_qp(struct c4iw_qp *qhp)
+ schp = to_c4iw_cq(qhp->ibqp.send_cq);
+
+ if (qhp->ibqp.uobject) {
+- t4_set_wq_in_error(&qhp->wq);
++ t4_set_wq_in_error(&qhp->wq, 0);
+ t4_set_cq_in_error(&rchp->cq);
+ spin_lock_irqsave(&rchp->comp_handler_lock, flag);
+ (*rchp->ibcq.comp_handler)(&rchp->ibcq, rchp->ibcq.cq_context);
+@@ -1520,16 +1647,21 @@ static int rdma_init(struct c4iw_dev *rhp, struct c4iw_qp *qhp)
+ wqe->u.init.pdid = cpu_to_be32(qhp->attr.pd);
+ wqe->u.init.qpid = cpu_to_be32(qhp->wq.sq.qid);
+ wqe->u.init.sq_eqid = cpu_to_be32(qhp->wq.sq.qid);
+- wqe->u.init.rq_eqid = cpu_to_be32(qhp->wq.rq.qid);
++ if (qhp->srq) {
++ wqe->u.init.rq_eqid = cpu_to_be32(FW_RI_INIT_RQEQID_SRQ |
++ qhp->srq->idx);
++ } else {
++ wqe->u.init.rq_eqid = cpu_to_be32(qhp->wq.rq.qid);
++ wqe->u.init.hwrqsize = cpu_to_be32(qhp->wq.rq.rqt_size);
++ wqe->u.init.hwrqaddr = cpu_to_be32(qhp->wq.rq.rqt_hwaddr -
++ rhp->rdev.lldi.vr->rq.start);
++ }
+ wqe->u.init.scqid = cpu_to_be32(qhp->attr.scq);
+ wqe->u.init.rcqid = cpu_to_be32(qhp->attr.rcq);
+ wqe->u.init.ord_max = cpu_to_be32(qhp->attr.max_ord);
+ wqe->u.init.ird_max = cpu_to_be32(qhp->attr.max_ird);
+ wqe->u.init.iss = cpu_to_be32(qhp->ep->snd_seq);
+ wqe->u.init.irs = cpu_to_be32(qhp->ep->rcv_seq);
+- wqe->u.init.hwrqsize = cpu_to_be32(qhp->wq.rq.rqt_size);
+- wqe->u.init.hwrqaddr = cpu_to_be32(qhp->wq.rq.rqt_hwaddr -
+- rhp->rdev.lldi.vr->rq.start);
+ if (qhp->attr.mpa_attr.initiator)
+ build_rtr_msg(qhp->attr.mpa_attr.p2p_type, &wqe->u.init);
+
+@@ -1646,7 +1778,7 @@ int c4iw_modify_qp(struct c4iw_dev *rhp, struct c4iw_qp *qhp,
+ case C4IW_QP_STATE_RTS:
+ switch (attrs->next_state) {
+ case C4IW_QP_STATE_CLOSING:
+- t4_set_wq_in_error(&qhp->wq);
++ t4_set_wq_in_error(&qhp->wq, 0);
+ set_state(qhp, C4IW_QP_STATE_CLOSING);
+ ep = qhp->ep;
+ if (!internal) {
+@@ -1659,7 +1791,7 @@ int c4iw_modify_qp(struct c4iw_dev *rhp, struct c4iw_qp *qhp,
+ goto err;
+ break;
+ case C4IW_QP_STATE_TERMINATE:
+- t4_set_wq_in_error(&qhp->wq);
++ t4_set_wq_in_error(&qhp->wq, 0);
+ set_state(qhp, C4IW_QP_STATE_TERMINATE);
+ qhp->attr.layer_etype = attrs->layer_etype;
+ qhp->attr.ecode = attrs->ecode;
+@@ -1676,7 +1808,7 @@ int c4iw_modify_qp(struct c4iw_dev *rhp, struct c4iw_qp *qhp,
+ }
+ break;
+ case C4IW_QP_STATE_ERROR:
+- t4_set_wq_in_error(&qhp->wq);
++ t4_set_wq_in_error(&qhp->wq, 0);
+ set_state(qhp, C4IW_QP_STATE_ERROR);
+ if (!internal) {
+ abort = 1;
+@@ -1822,7 +1954,7 @@ struct ib_qp *c4iw_create_qp(struct ib_pd *pd, struct ib_qp_init_attr *attrs,
+ struct c4iw_cq *schp;
+ struct c4iw_cq *rchp;
+ struct c4iw_create_qp_resp uresp;
+- unsigned int sqsize, rqsize;
++ unsigned int sqsize, rqsize = 0;
+ struct c4iw_ucontext *ucontext;
+ int ret;
+ struct c4iw_mm_entry *sq_key_mm, *rq_key_mm = NULL, *sq_db_key_mm;
+@@ -1843,11 +1975,13 @@ struct ib_qp *c4iw_create_qp(struct ib_pd *pd, struct ib_qp_init_attr *attrs,
+ if (attrs->cap.max_inline_data > T4_MAX_SEND_INLINE)
+ return ERR_PTR(-EINVAL);
+
+- if (attrs->cap.max_recv_wr > rhp->rdev.hw_queue.t4_max_rq_size)
+- return ERR_PTR(-E2BIG);
+- rqsize = attrs->cap.max_recv_wr + 1;
+- if (rqsize < 8)
+- rqsize = 8;
++ if (!attrs->srq) {
++ if (attrs->cap.max_recv_wr > rhp->rdev.hw_queue.t4_max_rq_size)
++ return ERR_PTR(-E2BIG);
++ rqsize = attrs->cap.max_recv_wr + 1;
++ if (rqsize < 8)
++ rqsize = 8;
++ }
+
+ if (attrs->cap.max_send_wr > rhp->rdev.hw_queue.t4_max_sq_size)
+ return ERR_PTR(-E2BIG);
+@@ -1872,19 +2006,23 @@ struct ib_qp *c4iw_create_qp(struct ib_pd *pd, struct ib_qp_init_attr *attrs,
+ (sqsize + rhp->rdev.hw_queue.t4_eq_status_entries) *
+ sizeof(*qhp->wq.sq.queue) + 16 * sizeof(__be64);
+ qhp->wq.sq.flush_cidx = -1;
+- qhp->wq.rq.size = rqsize;
+- qhp->wq.rq.memsize =
+- (rqsize + rhp->rdev.hw_queue.t4_eq_status_entries) *
+- sizeof(*qhp->wq.rq.queue);
++ if (!attrs->srq) {
++ qhp->wq.rq.size = rqsize;
++ qhp->wq.rq.memsize =
++ (rqsize + rhp->rdev.hw_queue.t4_eq_status_entries) *
++ sizeof(*qhp->wq.rq.queue);
++ }
+
+ if (ucontext) {
+ qhp->wq.sq.memsize = roundup(qhp->wq.sq.memsize, PAGE_SIZE);
+- qhp->wq.rq.memsize = roundup(qhp->wq.rq.memsize, PAGE_SIZE);
++ if (!attrs->srq)
++ qhp->wq.rq.memsize =
++ roundup(qhp->wq.rq.memsize, PAGE_SIZE);
+ }
+
+ ret = create_qp(&rhp->rdev, &qhp->wq, &schp->cq, &rchp->cq,
+ ucontext ? &ucontext->uctx : &rhp->rdev.uctx,
+- qhp->wr_waitp);
++ qhp->wr_waitp, !attrs->srq);
+ if (ret)
+ goto err_free_wr_wait;
+
+@@ -1897,10 +2035,12 @@ struct ib_qp *c4iw_create_qp(struct ib_pd *pd, struct ib_qp_init_attr *attrs,
+ qhp->attr.scq = ((struct c4iw_cq *) attrs->send_cq)->cq.cqid;
+ qhp->attr.rcq = ((struct c4iw_cq *) attrs->recv_cq)->cq.cqid;
+ qhp->attr.sq_num_entries = attrs->cap.max_send_wr;
+- qhp->attr.rq_num_entries = attrs->cap.max_recv_wr;
+ qhp->attr.sq_max_sges = attrs->cap.max_send_sge;
+ qhp->attr.sq_max_sges_rdma_write = attrs->cap.max_send_sge;
+- qhp->attr.rq_max_sges = attrs->cap.max_recv_sge;
++ if (!attrs->srq) {
++ qhp->attr.rq_num_entries = attrs->cap.max_recv_wr;
++ qhp->attr.rq_max_sges = attrs->cap.max_recv_sge;
++ }
+ qhp->attr.state = C4IW_QP_STATE_IDLE;
+ qhp->attr.next_state = C4IW_QP_STATE_IDLE;
+ qhp->attr.enable_rdma_read = 1;
+@@ -1925,20 +2065,25 @@ struct ib_qp *c4iw_create_qp(struct ib_pd *pd, struct ib_qp_init_attr *attrs,
+ ret = -ENOMEM;
+ goto err_remove_handle;
+ }
+- rq_key_mm = kmalloc(sizeof(*rq_key_mm), GFP_KERNEL);
+- if (!rq_key_mm) {
+- ret = -ENOMEM;
+- goto err_free_sq_key;
++ if (!attrs->srq) {
++ rq_key_mm = kmalloc(sizeof(*rq_key_mm), GFP_KERNEL);
++ if (!rq_key_mm) {
++ ret = -ENOMEM;
++ goto err_free_sq_key;
++ }
+ }
+ sq_db_key_mm = kmalloc(sizeof(*sq_db_key_mm), GFP_KERNEL);
+ if (!sq_db_key_mm) {
+ ret = -ENOMEM;
+ goto err_free_rq_key;
+ }
+- rq_db_key_mm = kmalloc(sizeof(*rq_db_key_mm), GFP_KERNEL);
+- if (!rq_db_key_mm) {
+- ret = -ENOMEM;
+- goto err_free_sq_db_key;
++ if (!attrs->srq) {
++ rq_db_key_mm =
++ kmalloc(sizeof(*rq_db_key_mm), GFP_KERNEL);
++ if (!rq_db_key_mm) {
++ ret = -ENOMEM;
++ goto err_free_sq_db_key;
++ }
+ }
+ if (t4_sq_onchip(&qhp->wq.sq)) {
+ ma_sync_key_mm = kmalloc(sizeof(*ma_sync_key_mm),
+@@ -1954,9 +2099,11 @@ struct ib_qp *c4iw_create_qp(struct ib_pd *pd, struct ib_qp_init_attr *attrs,
+ uresp.sqid = qhp->wq.sq.qid;
+ uresp.sq_size = qhp->wq.sq.size;
+ uresp.sq_memsize = qhp->wq.sq.memsize;
+- uresp.rqid = qhp->wq.rq.qid;
+- uresp.rq_size = qhp->wq.rq.size;
+- uresp.rq_memsize = qhp->wq.rq.memsize;
++ if (!attrs->srq) {
++ uresp.rqid = qhp->wq.rq.qid;
++ uresp.rq_size = qhp->wq.rq.size;
++ uresp.rq_memsize = qhp->wq.rq.memsize;
++ }
+ spin_lock(&ucontext->mmap_lock);
+ if (ma_sync_key_mm) {
+ uresp.ma_sync_key = ucontext->key;
+@@ -1966,12 +2113,16 @@ struct ib_qp *c4iw_create_qp(struct ib_pd *pd, struct ib_qp_init_attr *attrs,
+ }
+ uresp.sq_key = ucontext->key;
+ ucontext->key += PAGE_SIZE;
+- uresp.rq_key = ucontext->key;
+- ucontext->key += PAGE_SIZE;
++ if (!attrs->srq) {
++ uresp.rq_key = ucontext->key;
++ ucontext->key += PAGE_SIZE;
++ }
+ uresp.sq_db_gts_key = ucontext->key;
+ ucontext->key += PAGE_SIZE;
+- uresp.rq_db_gts_key = ucontext->key;
+- ucontext->key += PAGE_SIZE;
++ if (!attrs->srq) {
++ uresp.rq_db_gts_key = ucontext->key;
++ ucontext->key += PAGE_SIZE;
++ }
+ spin_unlock(&ucontext->mmap_lock);
+ ret = ib_copy_to_udata(udata, &uresp, sizeof uresp);
+ if (ret)
+@@ -1980,18 +2131,23 @@ struct ib_qp *c4iw_create_qp(struct ib_pd *pd, struct ib_qp_init_attr *attrs,
+ sq_key_mm->addr = qhp->wq.sq.phys_addr;
+ sq_key_mm->len = PAGE_ALIGN(qhp->wq.sq.memsize);
+ insert_mmap(ucontext, sq_key_mm);
+- rq_key_mm->key = uresp.rq_key;
+- rq_key_mm->addr = virt_to_phys(qhp->wq.rq.queue);
+- rq_key_mm->len = PAGE_ALIGN(qhp->wq.rq.memsize);
+- insert_mmap(ucontext, rq_key_mm);
++ if (!attrs->srq) {
++ rq_key_mm->key = uresp.rq_key;
++ rq_key_mm->addr = virt_to_phys(qhp->wq.rq.queue);
++ rq_key_mm->len = PAGE_ALIGN(qhp->wq.rq.memsize);
++ insert_mmap(ucontext, rq_key_mm);
++ }
+ sq_db_key_mm->key = uresp.sq_db_gts_key;
+ sq_db_key_mm->addr = (u64)(unsigned long)qhp->wq.sq.bar2_pa;
+ sq_db_key_mm->len = PAGE_SIZE;
+ insert_mmap(ucontext, sq_db_key_mm);
+- rq_db_key_mm->key = uresp.rq_db_gts_key;
+- rq_db_key_mm->addr = (u64)(unsigned long)qhp->wq.rq.bar2_pa;
+- rq_db_key_mm->len = PAGE_SIZE;
+- insert_mmap(ucontext, rq_db_key_mm);
++ if (!attrs->srq) {
++ rq_db_key_mm->key = uresp.rq_db_gts_key;
++ rq_db_key_mm->addr =
++ (u64)(unsigned long)qhp->wq.rq.bar2_pa;
++ rq_db_key_mm->len = PAGE_SIZE;
++ insert_mmap(ucontext, rq_db_key_mm);
++ }
+ if (ma_sync_key_mm) {
+ ma_sync_key_mm->key = uresp.ma_sync_key;
+ ma_sync_key_mm->addr =
+@@ -2004,7 +2160,19 @@ struct ib_qp *c4iw_create_qp(struct ib_pd *pd, struct ib_qp_init_attr *attrs,
+ c4iw_get_ucontext(ucontext);
+ qhp->ucontext = ucontext;
+ }
++ if (!attrs->srq) {
++ qhp->wq.qp_errp =
++ &qhp->wq.rq.queue[qhp->wq.rq.size].status.qp_err;
++ } else {
++ qhp->wq.qp_errp =
++ &qhp->wq.sq.queue[qhp->wq.sq.size].status.qp_err;
++ qhp->wq.srqidxp =
++ &qhp->wq.sq.queue[qhp->wq.sq.size].status.srqidx;
++ }
++
+ qhp->ibqp.qp_num = qhp->wq.sq.qid;
++ if (attrs->srq)
++ qhp->srq = to_c4iw_srq(attrs->srq);
+ init_timer(&(qhp->timer));
+ INIT_LIST_HEAD(&qhp->db_fc_entry);
+ pr_debug("sq id %u size %u memsize %zu num_entries %u rq id %u size %u memsize %zu num_entries %u\n",
+@@ -2015,18 +2183,20 @@ struct ib_qp *c4iw_create_qp(struct ib_pd *pd, struct ib_qp_init_attr *attrs,
+ err_free_ma_sync_key:
+ kfree(ma_sync_key_mm);
+ err_free_rq_db_key:
+- kfree(rq_db_key_mm);
++ if (!attrs->srq)
++ kfree(rq_db_key_mm);
+ err_free_sq_db_key:
+ kfree(sq_db_key_mm);
+ err_free_rq_key:
+- kfree(rq_key_mm);
++ if (!attrs->srq)
++ kfree(rq_key_mm);
+ err_free_sq_key:
+ kfree(sq_key_mm);
+ err_remove_handle:
+ remove_handle(rhp, &rhp->qpidr, qhp->wq.sq.qid);
+ err_destroy_qp:
+ destroy_qp(&rhp->rdev, &qhp->wq,
+- ucontext ? &ucontext->uctx : &rhp->rdev.uctx);
++ ucontext ? &ucontext->uctx : &rhp->rdev.uctx, !attrs->srq);
+ err_free_wr_wait:
+ c4iw_put_wr_wait(qhp->wr_waitp);
+ err_free_qhp:
+@@ -2092,6 +2262,45 @@ struct ib_qp *c4iw_get_qp(struct ib_device *dev, int qpn)
+ return (struct ib_qp *)get_qhp(to_c4iw_dev(dev), qpn);
+ }
+
++void c4iw_dispatch_srq_limit_reached_event(struct c4iw_srq *srq)
++{
++ struct ib_event event = {0};
++
++ event.device = &srq->rhp->ibdev;
++ event.element.srq = &srq->ibsrq;
++ event.event = IB_EVENT_SRQ_LIMIT_REACHED;
++ ib_dispatch_event(&event);
++}
++
++int c4iw_modify_srq(struct ib_srq *ib_srq, struct ib_srq_attr *attr,
++ enum ib_srq_attr_mask srq_attr_mask,
++ struct ib_udata *udata)
++{
++ struct c4iw_srq *srq = to_c4iw_srq(ib_srq);
++ int ret = 0;
++
++ /*
++ * XXX 0 mask == a SW interrupt for srq_limit reached...
++ */
++ if (udata && !srq_attr_mask) {
++ c4iw_dispatch_srq_limit_reached_event(srq);
++ goto out;
++ }
++
++ /* no support for this yet */
++ if (srq_attr_mask & IB_SRQ_MAX_WR) {
++ ret = -EINVAL;
++ goto out;
++ }
++
++ if (!udata && (srq_attr_mask & IB_SRQ_LIMIT)) {
++ srq->armed = true;
++ srq->srq_limit = attr->srq_limit;
++ }
++out:
++ return ret;
++}
++
+ int c4iw_ib_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
+ int attr_mask, struct ib_qp_init_attr *init_attr)
+ {
+@@ -2108,3 +2317,358 @@ int c4iw_ib_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
+ init_attr->sq_sig_type = qhp->sq_sig_all ? IB_SIGNAL_ALL_WR : 0;
+ return 0;
+ }
++
++static void free_srq_queue(struct c4iw_srq *srq, struct c4iw_dev_ucontext *uctx,
++ struct c4iw_wr_wait *wr_waitp)
++{
++ struct c4iw_rdev *rdev = &srq->rhp->rdev;
++ struct sk_buff *skb = srq->destroy_skb;
++ struct t4_srq *wq = &srq->wq;
++ struct fw_ri_res_wr *res_wr;
++ struct fw_ri_res *res;
++ int wr_len;
++
++ wr_len = sizeof(*res_wr) + sizeof(*res);
++ set_wr_txq(skb, CPL_PRIORITY_CONTROL, 0);
++
++ res_wr = (struct fw_ri_res_wr *)__skb_put(skb, wr_len);
++ memset(res_wr, 0, wr_len);
++ res_wr->op_nres = cpu_to_be32(FW_WR_OP_V(FW_RI_RES_WR) |
++ FW_RI_RES_WR_NRES_V(1) |
++ FW_WR_COMPL_F);
++ res_wr->len16_pkd = cpu_to_be32(DIV_ROUND_UP(wr_len, 16));
++ res_wr->cookie = (uintptr_t)wr_waitp;
++ res = res_wr->res;
++ res->u.srq.restype = FW_RI_RES_TYPE_SRQ;
++ res->u.srq.op = FW_RI_RES_OP_RESET;
++ res->u.srq.srqid = cpu_to_be32(srq->idx);
++ res->u.srq.eqid = cpu_to_be32(wq->qid);
++
++ c4iw_init_wr_wait(wr_waitp);
++ c4iw_ref_send_wait(rdev, skb, wr_waitp, 0, 0, __func__);
++
++ dma_free_coherent(&rdev->lldi.pdev->dev,
++ wq->memsize, wq->queue,
++ pci_unmap_addr(wq, mapping));
++ c4iw_rqtpool_free(rdev, wq->rqt_hwaddr, wq->rqt_size);
++ kfree(wq->sw_rq);
++ c4iw_put_qpid(rdev, wq->qid, uctx);
++}
++
++static int alloc_srq_queue(struct c4iw_srq *srq, struct c4iw_dev_ucontext *uctx,
++ struct c4iw_wr_wait *wr_waitp)
++{
++ struct c4iw_rdev *rdev = &srq->rhp->rdev;
++ int user = (uctx != &rdev->uctx);
++ struct t4_srq *wq = &srq->wq;
++ struct fw_ri_res_wr *res_wr;
++ struct fw_ri_res *res;
++ struct sk_buff *skb;
++ int wr_len;
++ int eqsize;
++ int ret = -ENOMEM;
++
++ wq->qid = c4iw_get_qpid(rdev, uctx);
++ if (!wq->qid)
++ goto err;
++
++ if (!user) {
++ wq->sw_rq = kcalloc(wq->size, sizeof(*wq->sw_rq),
++ GFP_KERNEL);
++ if (!wq->sw_rq)
++ goto err_put_qpid;
++ wq->pending_wrs = kcalloc(srq->wq.size,
++ sizeof(*srq->wq.pending_wrs),
++ GFP_KERNEL);
++ if (!wq->pending_wrs)
++ goto err_free_sw_rq;
++ }
++
++ wq->rqt_size = wq->size;
++ wq->rqt_hwaddr = c4iw_rqtpool_alloc(rdev, wq->rqt_size);
++ if (!wq->rqt_hwaddr)
++ goto err_free_pending_wrs;
++ wq->rqt_abs_idx = (wq->rqt_hwaddr - rdev->lldi.vr->rq.start) >>
++ T4_RQT_ENTRY_SHIFT;
++
++ wq->queue = dma_alloc_coherent(&rdev->lldi.pdev->dev,
++ wq->memsize, &wq->dma_addr,
++ GFP_KERNEL);
++ if (!wq->queue)
++ goto err_free_rqtpool;
++
++ memset(wq->queue, 0, wq->memsize);
++ pci_unmap_addr_set(wq, mapping, wq->dma_addr);
++
++ wq->bar2_va = c4iw_bar2_addrs(rdev, wq->qid, T4_BAR2_QTYPE_EGRESS,
++ &wq->bar2_qid,
++ user ? &wq->bar2_pa : NULL);
++
++ /*
++ * User mode must have bar2 access.
++ */
++
++ if (user && !wq->bar2_va) {
++ pr_warn(MOD "%s: srqid %u not in BAR2 range.\n",
++ pci_name(rdev->lldi.pdev), wq->qid);
++ ret = -EINVAL;
++ goto err_free_queue;
++ }
++
++ /* build fw_ri_res_wr */
++ wr_len = sizeof(*res_wr) + sizeof(*res);
++
++ skb = alloc_skb(wr_len, GFP_KERNEL | __GFP_NOFAIL);
++ if (!skb)
++ goto err_free_queue;
++ set_wr_txq(skb, CPL_PRIORITY_CONTROL, 0);
++
++ res_wr = (struct fw_ri_res_wr *)__skb_put(skb, wr_len);
++ memset(res_wr, 0, wr_len);
++ res_wr->op_nres = cpu_to_be32(FW_WR_OP_V(FW_RI_RES_WR) |
++ FW_RI_RES_WR_NRES_V(1) |
++ FW_WR_COMPL_F);
++ res_wr->len16_pkd = cpu_to_be32(DIV_ROUND_UP(wr_len, 16));
++ res_wr->cookie = (uintptr_t)wr_waitp;
++ res = res_wr->res;
++ res->u.srq.restype = FW_RI_RES_TYPE_SRQ;
++ res->u.srq.op = FW_RI_RES_OP_WRITE;
++
++ /*
++ * eqsize is the number of 64B entries plus the status page size.
++ */
++ eqsize = wq->size * T4_RQ_NUM_SLOTS +
++ rdev->hw_queue.t4_eq_status_entries;
++ res->u.srq.eqid = cpu_to_be32(wq->qid);
++ res->u.srq.fetchszm_to_iqid =
++ /* no host cidx updates */
++ cpu_to_be32(FW_RI_RES_WR_HOSTFCMODE_V(0) |
++ FW_RI_RES_WR_CPRIO_V(0) | /* don't keep in chip cache */
++ FW_RI_RES_WR_PCIECHN_V(0) | /* set by uP at ri_init time */
++ FW_RI_RES_WR_FETCHRO_V(0)); /* relaxed_ordering */
++ res->u.srq.dcaen_to_eqsize =
++ cpu_to_be32(FW_RI_RES_WR_DCAEN_V(0) |
++ FW_RI_RES_WR_DCACPU_V(0) |
++ FW_RI_RES_WR_FBMIN_V(2) |
++ FW_RI_RES_WR_FBMAX_V(3) |
++ FW_RI_RES_WR_CIDXFTHRESHO_V(0) |
++ FW_RI_RES_WR_CIDXFTHRESH_V(0) |
++ FW_RI_RES_WR_EQSIZE_V(eqsize));
++ res->u.srq.eqaddr = cpu_to_be64(wq->dma_addr);
++ res->u.srq.srqid = cpu_to_be32(srq->idx);
++ res->u.srq.pdid = cpu_to_be32(srq->pdid);
++ res->u.srq.hwsrqsize = cpu_to_be32(wq->rqt_size);
++ res->u.srq.hwsrqaddr = cpu_to_be32(wq->rqt_hwaddr -
++ rdev->lldi.vr->rq.start);
++
++ c4iw_init_wr_wait(wr_waitp);
++
++ ret = c4iw_ref_send_wait(rdev, skb, wr_waitp, 0, wq->qid, __func__);
++ if (ret)
++ goto err_free_queue;
++
++ pr_debug("%s srq %u eqid %u pdid %u queue va %p pa 0x%llx\n"
++ " bar2_addr %p rqt addr 0x%x size %d\n",
++ __func__, srq->idx, wq->qid, srq->pdid, wq->queue,
++ (u64)virt_to_phys(wq->queue), wq->bar2_va,
++ wq->rqt_hwaddr, wq->rqt_size);
++
++ return 0;
++err_free_queue:
++ dma_free_coherent(&rdev->lldi.pdev->dev,
++ wq->memsize, wq->queue,
++ pci_unmap_addr(wq, mapping));
++err_free_rqtpool:
++ c4iw_rqtpool_free(rdev, wq->rqt_hwaddr, wq->rqt_size);
++err_free_pending_wrs:
++ if (!user)
++ kfree(wq->pending_wrs);
++err_free_sw_rq:
++ if (!user)
++ kfree(wq->sw_rq);
++err_put_qpid:
++ c4iw_put_qpid(rdev, wq->qid, uctx);
++err:
++ return ret;
++}
++
++void c4iw_copy_wr_to_srq(struct t4_srq *srq, union t4_recv_wr *wqe, u8 len16)
++{
++ u64 *src, *dst;
++
++ src = (u64 *)wqe;
++ dst = (u64 *)((u8 *)srq->queue + srq->wq_pidx * T4_EQ_ENTRY_SIZE);
++ while (len16) {
++ *dst++ = *src++;
++ if (dst >= (u64 *)&srq->queue[srq->size])
++ dst = (u64 *)srq->queue;
++ *dst++ = *src++;
++ if (dst >= (u64 *)&srq->queue[srq->size])
++ dst = (u64 *)srq->queue;
++ len16--;
++ }
++}
++
++struct ib_srq *c4iw_create_srq(struct ib_pd *pd, struct ib_srq_init_attr *attrs,
++ struct ib_udata *udata)
++{
++ struct c4iw_dev *rhp;
++ struct c4iw_srq *srq;
++ struct c4iw_pd *php;
++ struct c4iw_create_srq_resp uresp;
++ struct c4iw_ucontext *ucontext;
++ struct c4iw_mm_entry *srq_key_mm, *srq_db_key_mm;
++ int rqsize;
++ int ret;
++ int wr_len;
++
++ pr_debug("%s ib_pd %p\n", __func__, pd);
++
++ php = to_c4iw_pd(pd);
++ rhp = php->rhp;
++
++ if (!rhp->rdev.lldi.vr->srq.size)
++ return ERR_PTR(-EINVAL);
++ if (attrs->attr.max_wr > rhp->rdev.hw_queue.t4_max_rq_size)
++ return ERR_PTR(-E2BIG);
++ if (attrs->attr.max_sge > T4_MAX_RECV_SGE)
++ return ERR_PTR(-E2BIG);
++
++ /*
++ * SRQ RQT and RQ must be a power of 2 and at least 16 deep.
++ */
++ rqsize = attrs->attr.max_wr + 1;
++ rqsize = roundup_pow_of_two(max_t(u16, rqsize, 16));
++
++ ucontext = pd->uobject ? to_c4iw_ucontext(pd->uobject->context) : NULL;
++
++ srq = kzalloc(sizeof(*srq), GFP_KERNEL);
++ if (!srq)
++ return ERR_PTR(-ENOMEM);
++
++ srq->wr_waitp = c4iw_alloc_wr_wait(GFP_KERNEL);
++ if (!srq->wr_waitp) {
++ ret = -ENOMEM;
++ goto err_free_srq;
++ }
++
++ srq->idx = c4iw_alloc_srq_idx(&rhp->rdev);
++ if (srq->idx < 0) {
++ ret = -ENOMEM;
++ goto err_free_wr_wait;
++ }
++
++ wr_len = sizeof(struct fw_ri_res_wr) + sizeof(struct fw_ri_res);
++ srq->destroy_skb = alloc_skb(wr_len, GFP_KERNEL);
++ if (!srq->destroy_skb) {
++ ret = -ENOMEM;
++ goto err_free_srq_idx;
++ }
++
++ srq->rhp = rhp;
++ srq->pdid = php->pdid;
++
++ srq->wq.size = rqsize;
++ srq->wq.memsize =
++ (rqsize + rhp->rdev.hw_queue.t4_eq_status_entries) *
++ sizeof(*srq->wq.queue);
++ if (ucontext)
++ srq->wq.memsize = roundup(srq->wq.memsize, PAGE_SIZE);
++
++ ret = alloc_srq_queue(srq, ucontext ? &ucontext->uctx :
++ &rhp->rdev.uctx, srq->wr_waitp);
++ if (ret)
++ goto err_free_skb;
++ attrs->attr.max_wr = rqsize - 1;
++
++ if (CHELSIO_CHIP_VERSION(rhp->rdev.lldi.adapter_type) > CHELSIO_T6)
++ srq->flags = T4_SRQ_LIMIT_SUPPORT;
++
++ ret = insert_handle(rhp, &rhp->qpidr, srq, srq->wq.qid);
++ if (ret)
++ goto err_free_queue;
++
++ if (udata) {
++ srq_key_mm = kmalloc(sizeof(*srq_key_mm), GFP_KERNEL);
++ if (!srq_key_mm) {
++ ret = -ENOMEM;
++ goto err_remove_handle;
++ }
++ srq_db_key_mm = kmalloc(sizeof(*srq_db_key_mm), GFP_KERNEL);
++ if (!srq_db_key_mm) {
++ ret = -ENOMEM;
++ goto err_free_srq_key_mm;
++ }
++ uresp.flags = srq->flags;
++ uresp.qid_mask = rhp->rdev.qpmask;
++ uresp.srqid = srq->wq.qid;
++ uresp.srq_size = srq->wq.size;
++ uresp.srq_memsize = srq->wq.memsize;
++ uresp.rqt_abs_idx = srq->wq.rqt_abs_idx;
++ spin_lock(&ucontext->mmap_lock);
++ uresp.srq_key = ucontext->key;
++ ucontext->key += PAGE_SIZE;
++ uresp.srq_db_gts_key = ucontext->key;
++ ucontext->key += PAGE_SIZE;
++ spin_unlock(&ucontext->mmap_lock);
++ ret = ib_copy_to_udata(udata, &uresp, sizeof(uresp));
++ if (ret)
++ goto err_free_srq_db_key_mm;
++ srq_key_mm->key = uresp.srq_key;
++ srq_key_mm->addr = virt_to_phys(srq->wq.queue);
++ srq_key_mm->len = PAGE_ALIGN(srq->wq.memsize);
++ insert_mmap(ucontext, srq_key_mm);
++ srq_db_key_mm->key = uresp.srq_db_gts_key;
++ srq_db_key_mm->addr = (u64)(unsigned long)srq->wq.bar2_pa;
++ srq_db_key_mm->len = PAGE_SIZE;
++ insert_mmap(ucontext, srq_db_key_mm);
++ }
++
++ pr_debug("%s srq qid %u idx %u size %u memsize %lu num_entries %u\n",
++ __func__, srq->wq.qid, srq->idx, srq->wq.size,
++ (unsigned long)srq->wq.memsize, attrs->attr.max_wr);
++
++ spin_lock_init(&srq->lock);
++ return &srq->ibsrq;
++err_free_srq_db_key_mm:
++ kfree(srq_db_key_mm);
++err_free_srq_key_mm:
++ kfree(srq_key_mm);
++err_remove_handle:
++ remove_handle(rhp, &rhp->qpidr, srq->wq.qid);
++err_free_queue:
++ free_srq_queue(srq, ucontext ? &ucontext->uctx : &rhp->rdev.uctx,
++ srq->wr_waitp);
++err_free_skb:
++ if (srq->destroy_skb)
++ kfree_skb(srq->destroy_skb);
++err_free_srq_idx:
++ c4iw_free_srq_idx(&rhp->rdev, srq->idx);
++err_free_wr_wait:
++ c4iw_put_wr_wait(srq->wr_waitp);
++err_free_srq:
++ kfree(srq);
++ return ERR_PTR(ret);
++}
++
++int c4iw_destroy_srq(struct ib_srq *ibsrq)
++{
++ struct c4iw_dev *rhp;
++ struct c4iw_srq *srq;
++ struct c4iw_ucontext *ucontext;
++
++ srq = to_c4iw_srq(ibsrq);
++ rhp = srq->rhp;
++
++ pr_debug("%s id %d\n", __func__, srq->wq.qid);
++
++ remove_handle(rhp, &rhp->qpidr, srq->wq.qid);
++ ucontext = ibsrq->uobject ?
++ to_c4iw_ucontext(ibsrq->uobject->context) : NULL;
++ free_srq_queue(srq, ucontext ? &ucontext->uctx : &rhp->rdev.uctx,
++ srq->wr_waitp);
++ c4iw_free_srq_idx(&rhp->rdev, srq->idx);
++ c4iw_put_wr_wait(srq->wr_waitp);
++ kfree(srq);
++ return 0;
++}
+diff --git a/drivers/infiniband/hw/cxgb4/resource.c b/drivers/infiniband/hw/cxgb4/resource.c
+index 0ef25ae05e6f..57ed26b3cc21 100644
+--- a/drivers/infiniband/hw/cxgb4/resource.c
++++ b/drivers/infiniband/hw/cxgb4/resource.c
+@@ -53,7 +53,8 @@ static int c4iw_init_qid_table(struct c4iw_rdev *rdev)
+ }
+
+ /* nr_* must be power of 2 */
+-int c4iw_init_resource(struct c4iw_rdev *rdev, u32 nr_tpt, u32 nr_pdid)
++int c4iw_init_resource(struct c4iw_rdev *rdev, u32 nr_tpt,
++ u32 nr_pdid, u32 nr_srqt)
+ {
+ int err = 0;
+ err = c4iw_id_table_alloc(&rdev->resource.tpt_table, 0, nr_tpt, 1,
+@@ -67,7 +68,17 @@ int c4iw_init_resource(struct c4iw_rdev *rdev, u32 nr_tpt, u32 nr_pdid)
+ nr_pdid, 1, 0);
+ if (err)
+ goto pdid_err;
++ if (!nr_srqt)
++ err = c4iw_id_table_alloc(&rdev->resource.srq_table, 0,
++ 1, 1, 0);
++ else
++ err = c4iw_id_table_alloc(&rdev->resource.srq_table, 0,
++ nr_srqt, 0, 0);
++ if (err)
++ goto srq_err;
+ return 0;
++ srq_err:
++ c4iw_id_table_free(&rdev->resource.pdid_table);
+ pdid_err:
+ c4iw_id_table_free(&rdev->resource.qid_table);
+ qid_err:
+@@ -371,13 +382,21 @@ void c4iw_rqtpool_free(struct c4iw_rdev *rdev, u32 addr, int size)
+ int c4iw_rqtpool_create(struct c4iw_rdev *rdev)
+ {
+ unsigned rqt_start, rqt_chunk, rqt_top;
++ int skip = 0;
+
+ rdev->rqt_pool = gen_pool_create(MIN_RQT_SHIFT, -1);
+ if (!rdev->rqt_pool)
+ return -ENOMEM;
+
+- rqt_start = rdev->lldi.vr->rq.start;
+- rqt_chunk = rdev->lldi.vr->rq.size;
++ /*
++ * If SRQs are supported, then never use the first RQE from
++ * the RQT region. This is because HW uses RQT index 0 as NULL.
++ */
++ if (rdev->lldi.vr->srq.size)
++ skip = T4_RQT_ENTRY_SIZE;
++
++ rqt_start = rdev->lldi.vr->rq.start + skip;
++ rqt_chunk = rdev->lldi.vr->rq.size - skip;
+ rqt_top = rqt_start + rqt_chunk;
+
+ while (rqt_start < rqt_top) {
+@@ -405,6 +424,32 @@ void c4iw_rqtpool_destroy(struct c4iw_rdev *rdev)
+ kref_put(&rdev->rqt_kref, destroy_rqtpool);
+ }
+
++int c4iw_alloc_srq_idx(struct c4iw_rdev *rdev)
++{
++ int idx;
++
++ idx = c4iw_id_alloc(&rdev->resource.srq_table);
++ mutex_lock(&rdev->stats.lock);
++ if (idx == -1) {
++ rdev->stats.srqt.fail++;
++ mutex_unlock(&rdev->stats.lock);
++ return -ENOMEM;
++ }
++ rdev->stats.srqt.cur++;
++ if (rdev->stats.srqt.cur > rdev->stats.srqt.max)
++ rdev->stats.srqt.max = rdev->stats.srqt.cur;
++ mutex_unlock(&rdev->stats.lock);
++ return idx;
++}
++
++void c4iw_free_srq_idx(struct c4iw_rdev *rdev, int idx)
++{
++ c4iw_id_free(&rdev->resource.srq_table, idx);
++ mutex_lock(&rdev->stats.lock);
++ rdev->stats.srqt.cur--;
++ mutex_unlock(&rdev->stats.lock);
++}
++
+ /*
+ * On-Chip QP Memory.
+ */
+diff --git a/drivers/infiniband/hw/cxgb4/t4.h b/drivers/infiniband/hw/cxgb4/t4.h
+index 130ef87fa038..7a1478a981ff 100644
+--- a/drivers/infiniband/hw/cxgb4/t4.h
++++ b/drivers/infiniband/hw/cxgb4/t4.h
+@@ -491,7 +491,6 @@ static inline void t4_rq_produce(struct t4_wq *wq, u8 len16)
+ static inline void t4_rq_consume(struct t4_wq *wq)
+ {
+ wq->rq.in_use--;
+- wq->rq.msn++;
+ if (++wq->rq.cidx == wq->rq.size)
+ wq->rq.cidx = 0;
+ }
+@@ -641,12 +640,14 @@ static inline void t4_ring_rq_db(struct t4_wq *wq, u16 inc,
+
+ static inline int t4_wq_in_error(struct t4_wq *wq)
+ {
+- return wq->rq.queue[wq->rq.size].status.qp_err;
++ return *wq->qp_errp;
+ }
+
+-static inline void t4_set_wq_in_error(struct t4_wq *wq)
++static inline void t4_set_wq_in_error(struct t4_wq *wq, u32 srqidx)
+ {
+- wq->rq.queue[wq->rq.size].status.qp_err = 1;
++ if (srqidx)
++ *wq->srqidxp = srqidx;
++ *wq->qp_errp = 1;
+ }
+
+ static inline void t4_disable_wq_db(struct t4_wq *wq)
+diff --git a/include/uapi/rdma/cxgb4-abi.h b/include/uapi/rdma/cxgb4-abi.h
+index 822db6c1bdfa..dbad098a8f76 100644
+--- a/include/uapi/rdma/cxgb4-abi.h
++++ b/include/uapi/rdma/cxgb4-abi.h
+@@ -83,6 +83,23 @@ struct c4iw_create_qp_resp {
+ __u32 flags;
+ };
+
++struct c4iw_create_srq_resp {
++ __aligned_u64 srq_key;
++ __aligned_u64 srq_db_gts_key;
++ __aligned_u64 srq_memsize;
++ __u32 srqid;
++ __u32 srq_size;
++ __u32 rqt_abs_idx;
++ __u32 qid_mask;
++ __u32 flags;
++ __u32 reserved; /* explicit padding */
++};
++
++enum {
++ /* HW supports SRQ_LIMIT_REACHED event */
++ T4_SRQ_LIMIT_SUPPORT = 1 << 0,
++};
++
+ struct c4iw_alloc_ucontext_resp {
+ __u64 status_page_key;
+ __u32 status_page_size;
+--
+2.12.3
+
diff --git a/patches.fixes/0001-rdma-cxgb4-Add-support-for-srq-functions-structs.patch b/patches.fixes/0001-rdma-cxgb4-Add-support-for-srq-functions-structs.patch
new file mode 100644
index 0000000000..0e14b60949
--- /dev/null
+++ b/patches.fixes/0001-rdma-cxgb4-Add-support-for-srq-functions-structs.patch
@@ -0,0 +1,319 @@
+From: Raju Rangoju <rajur@chelsio.com>
+Subject: rdma/cxgb4: Add support for srq functions & structs
+Patch-mainline: v4.19-rc1
+Git-commit: 7fc7a7cffab6b94cb5e47148e6852ba633078ea1
+References: bsc#1127371
+
+This patch adds kernel mode t4_srq structures and support functions,
+uapi structures and defines, as well as firmware work request structures.
+
+Signed-off-by: Raju Rangoju <rajur@chelsio.com>
+Reviewed-by: Steve Wise <swise@opengridcomputing.com>
+Signed-off-by: Jason Gunthorpe <jgg@mellanox.com>
+Signed-off-by: Denis Kirjanov <dkirjanov@suse.com>
+---
+ drivers/infiniband/hw/cxgb4/iw_cxgb4.h | 38 ++++++++++
+ drivers/infiniband/hw/cxgb4/t4.h | 117 +++++++++++++++++++++++++++++-
+ drivers/infiniband/hw/cxgb4/t4fw_ri_api.h | 19 +++++
+ 3 files changed, 173 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/infiniband/hw/cxgb4/iw_cxgb4.h b/drivers/infiniband/hw/cxgb4/iw_cxgb4.h
+index 5d9bea174a86..392f542462b3 100644
+--- a/drivers/infiniband/hw/cxgb4/iw_cxgb4.h
++++ b/drivers/infiniband/hw/cxgb4/iw_cxgb4.h
+@@ -96,6 +96,7 @@ struct c4iw_resource {
+ struct c4iw_id_table tpt_table;
+ struct c4iw_id_table qid_table;
+ struct c4iw_id_table pdid_table;
++ struct c4iw_id_table srq_table;
+ };
+
+ struct c4iw_qid_list {
+@@ -129,6 +130,8 @@ struct c4iw_stats {
+ struct c4iw_stat stag;
+ struct c4iw_stat pbl;
+ struct c4iw_stat rqt;
++ struct c4iw_stat srqt;
++ struct c4iw_stat srq;
+ struct c4iw_stat ocqp;
+ u64 db_full;
+ u64 db_empty;
+@@ -549,6 +552,7 @@ struct c4iw_qp {
+ wait_queue_head_t wait;
+ struct timer_list timer;
+ int sq_sig_all;
++ struct c4iw_srq *srq;
+ struct work_struct free_work;
+ struct c4iw_ucontext *ucontext;
+ struct c4iw_wr_wait *wr_waitp;
+@@ -559,6 +563,26 @@ static inline struct c4iw_qp *to_c4iw_qp(struct ib_qp *ibqp)
+ return container_of(ibqp, struct c4iw_qp, ibqp);
+ }
+
++struct c4iw_srq {
++ struct ib_srq ibsrq;
++ struct list_head db_fc_entry;
++ struct c4iw_dev *rhp;
++ struct t4_srq wq;
++ struct sk_buff *destroy_skb;
++ u32 srq_limit;
++ u32 pdid;
++ int idx;
++ u32 flags;
++ spinlock_t lock; /* protects srq */
++ struct c4iw_wr_wait *wr_waitp;
++ bool armed;
++};
++
++static inline struct c4iw_srq *to_c4iw_srq(struct ib_srq *ibsrq)
++{
++ return container_of(ibsrq, struct c4iw_srq, ibsrq);
++}
++
+ struct c4iw_ucontext {
+ struct ib_ucontext ibucontext;
+ struct c4iw_dev_ucontext uctx;
+@@ -1039,6 +1063,13 @@ struct ib_cq *c4iw_create_cq(struct ib_device *ibdev,
+ struct ib_udata *udata);
+ int c4iw_resize_cq(struct ib_cq *cq, int cqe, struct ib_udata *udata);
+ int c4iw_arm_cq(struct ib_cq *ibcq, enum ib_cq_notify_flags flags);
++int c4iw_modify_srq(struct ib_srq *ib_srq, struct ib_srq_attr *attr,
++ enum ib_srq_attr_mask srq_attr_mask,
++ struct ib_udata *udata);
++int c4iw_destroy_srq(struct ib_srq *ib_srq);
++struct ib_srq *c4iw_create_srq(struct ib_pd *pd,
++ struct ib_srq_init_attr *attrs,
++ struct ib_udata *udata);
+ int c4iw_destroy_qp(struct ib_qp *ib_qp);
+ struct ib_qp *c4iw_create_qp(struct ib_pd *pd,
+ struct ib_qp_init_attr *attrs,
+@@ -1075,12 +1106,19 @@ extern c4iw_handler_func c4iw_handlers[NUM_CPL_CMDS];
+ void __iomem *c4iw_bar2_addrs(struct c4iw_rdev *rdev, unsigned int qid,
+ enum cxgb4_bar2_qtype qtype,
+ unsigned int *pbar2_qid, u64 *pbar2_pa);
++int c4iw_alloc_srq_idx(struct c4iw_rdev *rdev);
++void c4iw_free_srq_idx(struct c4iw_rdev *rdev, int idx);
+ extern void c4iw_log_wr_stats(struct t4_wq *wq, struct t4_cqe *cqe);
+ extern int c4iw_wr_log;
+ extern int db_fc_threshold;
+ extern int db_coalescing_threshold;
+ extern int use_dsgl;
+ void c4iw_invalidate_mr(struct c4iw_dev *rhp, u32 rkey);
++void c4iw_dispatch_srq_limit_reached_event(struct c4iw_srq *srq);
++void c4iw_copy_wr_to_srq(struct t4_srq *srq, union t4_recv_wr *wqe, u8 len16);
++void c4iw_flush_srqidx(struct c4iw_qp *qhp, u32 srqidx);
++int c4iw_post_srq_recv(struct ib_srq *ibsrq, struct ib_recv_wr *wr,
++ struct ib_recv_wr **bad_wr);
+ struct c4iw_wr_wait *c4iw_alloc_wr_wait(gfp_t gfp);
+
+ #endif
+diff --git a/drivers/infiniband/hw/cxgb4/t4.h b/drivers/infiniband/hw/cxgb4/t4.h
+index 79e8ee12c391..860a90980132 100644
+--- a/drivers/infiniband/hw/cxgb4/t4.h
++++ b/drivers/infiniband/hw/cxgb4/t4.h
+@@ -52,12 +52,16 @@ struct t4_status_page {
+ __be16 pidx;
+ u8 qp_err; /* flit 1 - sw owns */
+ u8 db_off;
+- u8 pad;
++ u8 pad[2];
+ u16 host_wq_pidx;
+ u16 host_cidx;
+ u16 host_pidx;
++ u16 pad2;
++ u32 srqidx;
+ };
+
++#define T4_RQT_ENTRY_SHIFT 6
++#define T4_RQT_ENTRY_SIZE BIT(T4_RQT_ENTRY_SHIFT)
+ #define T4_EQ_ENTRY_SIZE 64
+
+ #define T4_SQ_NUM_SLOTS 5
+@@ -237,6 +241,7 @@ struct t4_cqe {
+ /* used for RQ completion processing */
+ #define CQE_WRID_STAG(x) (be32_to_cpu((x)->u.rcqe.stag))
+ #define CQE_WRID_MSN(x) (be32_to_cpu((x)->u.rcqe.msn))
++#define CQE_ABS_RQE_IDX(x) (be32_to_cpu((x)->u.srcqe.abs_rqe_idx))
+
+ /* used for SQ completion processing */
+ #define CQE_WRID_SQ_IDX(x) ((x)->u.scqe.cidx)
+@@ -320,6 +325,7 @@ struct t4_swrqe {
+ u64 wr_id;
+ struct timespec host_ts;
+ u64 sge_ts;
++ int valid;
+ };
+
+ struct t4_rq {
+@@ -349,8 +355,98 @@ struct t4_wq {
+ void __iomem *db;
+ struct c4iw_rdev *rdev;
+ int flushed;
++ u8 *qp_errp;
++ u32 *srqidxp;
++};
++
++struct t4_srq_pending_wr {
++ u64 wr_id;
++ union t4_recv_wr wqe;
++ u8 len16;
+ };
+
++struct t4_srq {
++ union t4_recv_wr *queue;
++ dma_addr_t dma_addr;
++ DECLARE_PCI_UNMAP_ADDR(mapping);
++ struct t4_swrqe *sw_rq;
++ void __iomem *bar2_va;
++ u64 bar2_pa;
++ size_t memsize;
++ u32 bar2_qid;
++ u32 qid;
++ u32 msn;
++ u32 rqt_hwaddr;
++ u32 rqt_abs_idx;
++ u16 rqt_size;
++ u16 size;
++ u16 cidx;
++ u16 pidx;
++ u16 wq_pidx;
++ u16 wq_pidx_inc;
++ u16 in_use;
++ struct t4_srq_pending_wr *pending_wrs;
++ u16 pending_cidx;
++ u16 pending_pidx;
++ u16 pending_in_use;
++ u16 ooo_count;
++};
++
++static inline u32 t4_srq_avail(struct t4_srq *srq)
++{
++ return srq->size - 1 - srq->in_use;
++}
++
++static inline void t4_srq_produce(struct t4_srq *srq, u8 len16)
++{
++ srq->in_use++;
++ if (++srq->pidx == srq->size)
++ srq->pidx = 0;
++ srq->wq_pidx += DIV_ROUND_UP(len16 * 16, T4_EQ_ENTRY_SIZE);
++ if (srq->wq_pidx >= srq->size * T4_RQ_NUM_SLOTS)
++ srq->wq_pidx %= srq->size * T4_RQ_NUM_SLOTS;
++ srq->queue[srq->size].status.host_pidx = srq->pidx;
++}
++
++static inline void t4_srq_produce_pending_wr(struct t4_srq *srq)
++{
++ srq->pending_in_use++;
++ srq->in_use++;
++ if (++srq->pending_pidx == srq->size)
++ srq->pending_pidx = 0;
++}
++
++static inline void t4_srq_consume_pending_wr(struct t4_srq *srq)
++{
++ srq->pending_in_use--;
++ srq->in_use--;
++ if (++srq->pending_cidx == srq->size)
++ srq->pending_cidx = 0;
++}
++
++static inline void t4_srq_produce_ooo(struct t4_srq *srq)
++{
++ srq->in_use--;
++ srq->ooo_count++;
++}
++
++static inline void t4_srq_consume_ooo(struct t4_srq *srq)
++{
++ srq->cidx++;
++ if (srq->cidx == srq->size)
++ srq->cidx = 0;
++ srq->queue[srq->size].status.host_cidx = srq->cidx;
++ srq->ooo_count--;
++}
++
++static inline void t4_srq_consume(struct t4_srq *srq)
++{
++ srq->in_use--;
++ if (++srq->cidx == srq->size)
++ srq->cidx = 0;
++ srq->queue[srq->size].status.host_cidx = srq->cidx;
++}
++
+ static inline int t4_rqes_posted(struct t4_wq *wq)
+ {
+ return wq->rq.in_use;
+@@ -464,6 +560,25 @@ static inline void pio_copy(u64 __iomem *dst, u64 *src)
+ }
+ }
+
++static inline void t4_ring_srq_db(struct t4_srq *srq, u16 inc, u8 len16,
++ union t4_recv_wr *wqe)
++{
++ /* Flush host queue memory writes. */
++ wmb();
++ if (inc == 1 && srq->bar2_qid == 0 && wqe) {
++ pr_debug("%s : WC srq->pidx = %d; len16=%d\n",
++ __func__, srq->pidx, len16);
++ pio_copy(srq->bar2_va + SGE_UDB_WCDOORBELL, (u64 *)wqe);
++ } else {
++ pr_debug("%s: DB srq->pidx = %d; len16=%d\n",
++ __func__, srq->pidx, len16);
++ writel(PIDX_T5_V(inc) | QID_V(srq->bar2_qid),
++ srq->bar2_va + SGE_UDB_KDOORBELL);
++ }
++ /* Flush user doorbell area writes. */
++ wmb();
++}
++
+ static inline void t4_ring_sq_db(struct t4_wq *wq, u16 inc, union t4_wr *wqe)
+ {
+
+diff --git a/drivers/infiniband/hw/cxgb4/t4fw_ri_api.h b/drivers/infiniband/hw/cxgb4/t4fw_ri_api.h
+index 58c531db4f4a..0f4f86b004d6 100644
+--- a/drivers/infiniband/hw/cxgb4/t4fw_ri_api.h
++++ b/drivers/infiniband/hw/cxgb4/t4fw_ri_api.h
+@@ -263,6 +263,7 @@ enum fw_ri_res_type {
+ FW_RI_RES_TYPE_SQ,
+ FW_RI_RES_TYPE_RQ,
+ FW_RI_RES_TYPE_CQ,
++ FW_RI_RES_TYPE_SRQ,
+ };
+
+ enum fw_ri_res_op {
+@@ -296,6 +297,20 @@ struct fw_ri_res {
+ __be32 r6_lo;
+ __be64 r7;
+ } cq;
++ struct fw_ri_res_srq {
++ __u8 restype;
++ __u8 op;
++ __be16 r3;
++ __be32 eqid;
++ __be32 r4[2];
++ __be32 fetchszm_to_iqid;
++ __be32 dcaen_to_eqsize;
++ __be64 eqaddr;
++ __be32 srqid;
++ __be32 pdid;
++ __be32 hwsrqsize;
++ __be32 hwsrqaddr;
++ } srq;
+ } u;
+ };
+
+@@ -707,6 +722,10 @@ enum fw_ri_init_p2ptype {
+ FW_RI_INIT_P2PTYPE_DISABLED = 0xf,
+ };
+
++enum fw_ri_init_rqeqid_srq {
++ FW_RI_INIT_RQEQID_SRQ = 1 << 31,
++};
++
+ struct fw_ri_wr {
+ __be32 op_compl;
+ __be32 flowid_len16;
+--
+2.12.3
+
diff --git a/patches.fixes/0001-rdma-cxgb4-Remove-a-set-but-not-used-variable.patch b/patches.fixes/0001-rdma-cxgb4-Remove-a-set-but-not-used-variable.patch
new file mode 100644
index 0000000000..0340208d5e
--- /dev/null
+++ b/patches.fixes/0001-rdma-cxgb4-Remove-a-set-but-not-used-variable.patch
@@ -0,0 +1,40 @@
+From: Bart Van Assche <bart.vanassche@wdc.com>
+Subject: rdma/cxgb4: Remove a set-but-not-used variable
+Patch-mainline: v4.19-rc1
+Git-commit: 7810e09bfba56bc0f2aff705ca7086e6c1f103f6
+References: bsc#1127371
+
+This patch avoids that the following warning is reported when building with
+W=1:
+
+drivers/infiniband/hw/cxgb4/cm.c:1860:5: warning: variable 'status' set but not used [-Wunused-but-set-variable]
+ u8 status;
+ ^~~~~~
+
+Fixes: 6a0b6174d35a ("rdma/cxgb4: Add support for kernel mode SRQ's")
+Signed-off-by: Bart Van Assche <bart.vanassche@wdc.com>
+Acked-by: Steve Wise <swise@opengridcomputing.com>
+Signed-off-by: Jason Gunthorpe <jgg@mellanox.com>
+Acked-by: Denis Kirjanov <dkirjanov@suse.com>
+---
+ drivers/infiniband/hw/cxgb4/cm.c | 2 --
+ 1 file changed, 2 deletions(-)
+
+diff --git a/drivers/infiniband/hw/cxgb4/cm.c b/drivers/infiniband/hw/cxgb4/cm.c
+index 54f7fbef7880..d7cfa38baad2 100644
+--- a/drivers/infiniband/hw/cxgb4/cm.c
++++ b/drivers/infiniband/hw/cxgb4/cm.c
+@@ -1857,10 +1857,8 @@ static void complete_cached_srq_buffers(struct c4iw_ep *ep, u32 srqidx_status)
+ {
+ enum chip_type adapter_type;
+ u32 srqidx;
+- u8 status;
+
+ adapter_type = ep->com.dev->rdev.lldi.adapter_type;
+- status = ABORT_RSS_STATUS_G(be32_to_cpu(srqidx_status));
+ srqidx = ABORT_RSS_SRQIDX_G(be32_to_cpu(srqidx_status));
+
+ /*
+--
+2.12.3
+
diff --git a/patches.fixes/0001-rdma-cxgb4-fix-some-info-leaks.patch b/patches.fixes/0001-rdma-cxgb4-fix-some-info-leaks.patch
new file mode 100644
index 0000000000..321170dbe3
--- /dev/null
+++ b/patches.fixes/0001-rdma-cxgb4-fix-some-info-leaks.patch
@@ -0,0 +1,66 @@
+From: Dan Carpenter <dan.carpenter@oracle.com>
+Subject: rdma/cxgb4: fix some info leaks
+Patch-mainline: v4.19-rc1
+Git-commit: 8001b717f09460d9e17457f6bade6699aa14604f
+References: bsc#1127371
+
+In c4iw_create_qp() there are several struct members which potentially
+aren't inintialized like uresp.rq_key. I've fixed this code before in
+in commit ae1fe07f3f42 ("RDMA/cxgb4: Fix stack info leak in
+c4iw_create_qp()") so this time I'm just going to take a big hammer
+approach and memset the whole struct to zero. Hopefully, it will stay
+fixed this time.
+
+In c4iw_create_srq() we don't clear uresp.reserved.
+
+Fixes: 6a0b6174d35a ("rdma/cxgb4: Add support for kernel mode SRQ's")
+Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com>
+Acked-by: Raju Rangoju <rajur@chelsio.com>
+Signed-off-by: Jason Gunthorpe <jgg@mellanox.com>
+Acked-by: Denis Kirjanov <dkirjanov@suse.com>
+---
+ drivers/infiniband/hw/cxgb4/qp.c | 7 +++----
+ 1 file changed, 3 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/infiniband/hw/cxgb4/qp.c b/drivers/infiniband/hw/cxgb4/qp.c
+index c26086c76f0b..dbd99370a0de 100644
+--- a/drivers/infiniband/hw/cxgb4/qp.c
++++ b/drivers/infiniband/hw/cxgb4/qp.c
+@@ -2088,6 +2088,7 @@ struct ib_qp *c4iw_create_qp(struct ib_pd *pd, struct ib_qp_init_attr *attrs,
+ goto err_free_sq_db_key;
+ }
+ }
++ memset(&uresp, 0, sizeof(uresp));
+ if (t4_sq_onchip(&qhp->wq.sq)) {
+ ma_sync_key_mm = kmalloc(sizeof(*ma_sync_key_mm),
+ GFP_KERNEL);
+@@ -2096,8 +2097,7 @@ struct ib_qp *c4iw_create_qp(struct ib_pd *pd, struct ib_qp_init_attr *attrs,
+ goto err_free_rq_db_key;
+ }
+ uresp.flags = C4IW_QPF_ONCHIP;
+- } else
+- uresp.flags = 0;
++ }
+ uresp.qid_mask = rhp->rdev.qpmask;
+ uresp.sqid = qhp->wq.sq.qid;
+ uresp.sq_size = qhp->wq.sq.size;
+@@ -2111,8 +2111,6 @@ struct ib_qp *c4iw_create_qp(struct ib_pd *pd, struct ib_qp_init_attr *attrs,
+ if (ma_sync_key_mm) {
+ uresp.ma_sync_key = ucontext->key;
+ ucontext->key += PAGE_SIZE;
+- } else {
+- uresp.ma_sync_key = 0;
+ }
+ uresp.sq_key = ucontext->key;
+ ucontext->key += PAGE_SIZE;
+@@ -2601,6 +2599,7 @@ struct ib_srq *c4iw_create_srq(struct ib_pd *pd, struct ib_srq_init_attr *attrs,
+ ret = -ENOMEM;
+ goto err_free_srq_key_mm;
+ }
++ memset(&uresp, 0, sizeof(uresp));
+ uresp.flags = srq->flags;
+ uresp.qid_mask = rhp->rdev.qpmask;
+ uresp.srqid = srq->wq.qid;
+--
+2.12.3
+
diff --git a/patches.suse/0001-RDMA-cxgb4-Make-c4iw_poll_cq_one-easier-to-analyze.patch b/patches.suse/0001-RDMA-cxgb4-Make-c4iw_poll_cq_one-easier-to-analyze.patch
new file mode 100644
index 0000000000..99d4df6f10
--- /dev/null
+++ b/patches.suse/0001-RDMA-cxgb4-Make-c4iw_poll_cq_one-easier-to-analyze.patch
@@ -0,0 +1,119 @@
+From: Bart Van Assche <bart.vanassche@wdc.com>
+Subject: RDMA/cxgb4: Make c4iw_poll_cq_one() easier to analyze
+Patch-mainline: v4.19-rc1
+Git-commit: 4ab39e2f98f2f49e97c8dd8e239697bd0bab8103
+References: bsc#1127371
+
+Introduce the function __c4iw_poll_cq_one() such that c4iw_poll_cq_one()
+becomes easier to analyze for static source code analyzers. This patch
+avoids that sparse reports the following:
+
+drivers/infiniband/hw/cxgb4/cq.c:401:36: warning: context imbalance in 'c4iw_flush_hw_cq' - unexpected unlock
+drivers/infiniband/hw/cxgb4/cq.c:824:9: warning: context imbalance in 'c4iw_poll_cq_one' - different lock contexts for basic block
+
+Compile-tested only.
+
+Signed-off-by: Bart Van Assche <bart.vanassche@wdc.com>
+Cc: Steve Wise <swise@chelsio.com>
+Acked-by: Steve Wise <swise@opengridcomputing.com>
+Signed-off-by: Jason Gunthorpe <jgg@mellanox.com>
+Acked-by: Denis Kirjanov <dkirjanov@suse.com>
+---
+ drivers/infiniband/hw/cxgb4/cq.c | 62 +++++++++++++++++++++++-----------------
+ 1 file changed, 35 insertions(+), 27 deletions(-)
+
+diff --git a/drivers/infiniband/hw/cxgb4/cq.c b/drivers/infiniband/hw/cxgb4/cq.c
+index 2be2e1ac1b5f..a5280d8d002f 100644
+--- a/drivers/infiniband/hw/cxgb4/cq.c
++++ b/drivers/infiniband/hw/cxgb4/cq.c
+@@ -668,43 +668,22 @@ static int poll_cq(struct t4_wq *wq, struct t4_cq *cq, struct t4_cqe *cqe,
+ return ret;
+ }
+
+-/*
+- * Get one cq entry from c4iw and map it to openib.
+- *
+- * Returns:
+- * 0 cqe returned
+- * -ENODATA EMPTY;
+- * -EAGAIN caller must try again
+- * any other -errno fatal error
+- */
+-static int c4iw_poll_cq_one(struct c4iw_cq *chp, struct ib_wc *wc)
++static int __c4iw_poll_cq_one(struct c4iw_cq *chp, struct c4iw_qp *qhp,
++ struct ib_wc *wc)
+ {
+- struct c4iw_qp *qhp = NULL;
+- struct t4_cqe uninitialized_var(cqe), *rd_cqe;
+- struct t4_wq *wq;
++ struct t4_cqe cqe;
++ struct t4_wq *wq = qhp ? &qhp->wq : NULL;
+ u32 credit = 0;
+ u8 cqe_flushed;
+ u64 cookie = 0;
+ int ret;
+
+- ret = t4_next_cqe(&chp->cq, &rd_cqe);
+-
+- if (ret)
+- return ret;
+-
+- qhp = get_qhp(chp->rhp, CQE_QPID(rd_cqe));
+- if (!qhp)
+- wq = NULL;
+- else {
+- spin_lock(&qhp->lock);
+- wq = &(qhp->wq);
+- }
+ ret = poll_cq(wq, &(chp->cq), &cqe, &cqe_flushed, &cookie, &credit);
+ if (ret)
+ goto out;
+
+ wc->wr_id = cookie;
+- wc->qp = &qhp->ibqp;
++ wc->qp = qhp ? &qhp->ibqp : NULL;
+ wc->vendor_err = CQE_STATUS(&cqe);
+ wc->wc_flags = 0;
+
+@@ -819,8 +798,37 @@ static int c4iw_poll_cq_one(struct c4iw_cq *chp, struct ib_wc *wc)
+ }
+ }
+ out:
+- if (wq)
++ return ret;
++}
++
++/*
++ * Get one cq entry from c4iw and map it to openib.
++ *
++ * Returns:
++ * 0 cqe returned
++ * -ENODATA EMPTY;
++ * -EAGAIN caller must try again
++ * any other -errno fatal error
++ */
++static int c4iw_poll_cq_one(struct c4iw_cq *chp, struct ib_wc *wc)
++{
++ struct c4iw_qp *qhp = NULL;
++ struct t4_cqe *rd_cqe;
++ int ret;
++
++ ret = t4_next_cqe(&chp->cq, &rd_cqe);
++
++ if (ret)
++ return ret;
++
++ qhp = get_qhp(chp->rhp, CQE_QPID(rd_cqe));
++ if (qhp) {
++ spin_lock(&qhp->lock);
++ ret = __c4iw_poll_cq_one(chp, qhp, wc);
+ spin_unlock(&qhp->lock);
++ } else {
++ ret = __c4iw_poll_cq_one(chp, NULL, wc);
++ }
+ return ret;
+ }
+
+--
+2.12.3
+
diff --git a/patches.suse/0001-rdma-cxgb4-Add-support-for-64Byte-cqes.patch b/patches.suse/0001-rdma-cxgb4-Add-support-for-64Byte-cqes.patch
new file mode 100644
index 0000000000..2045527ce2
--- /dev/null
+++ b/patches.suse/0001-rdma-cxgb4-Add-support-for-64Byte-cqes.patch
@@ -0,0 +1,256 @@
+From: Raju Rangoju <rajur@chelsio.com>
+Subject: rdma/cxgb4: Add support for 64Byte cqes
+Patch-mainline: v4.19-rc1
+Git-commit: 65ca8d9670b70aa8076054c0c23be032c6ac5c77
+References: bsc#1127371
+
+This patch adds support for iw_cxb4 to extend cqes from existing 32Byte
+size to 64Byte.
+
+Also includes adds backward compatibility support (for 32Byte) to work
+with older libraries.
+
+Signed-off-by: Raju Rangoju <rajur@chelsio.com>
+Reviewed-by: Steve Wise <swise@opengridcomputing.com>
+Signed-off-by: Jason Gunthorpe <jgg@mellanox.com>
+Signed-off-by: Denis Kirjanov <dkirjanov@suse.com>
+---
+ drivers/infiniband/hw/cxgb4/cq.c | 43 +++++++++++++++++++++++++++++-----
+ drivers/infiniband/hw/cxgb4/ev.c | 5 ++--
+ drivers/infiniband/hw/cxgb4/iw_cxgb4.h | 1 +
+ drivers/infiniband/hw/cxgb4/t4.h | 18 +++++++++++---
+ include/uapi/rdma/cxgb4-abi.h | 12 +++++++++-
+ 5 files changed, 67 insertions(+), 12 deletions(-)
+
+diff --git a/drivers/infiniband/hw/cxgb4/cq.c b/drivers/infiniband/hw/cxgb4/cq.c
+index a5280d8d002f..187de3ffba7e 100644
+--- a/drivers/infiniband/hw/cxgb4/cq.c
++++ b/drivers/infiniband/hw/cxgb4/cq.c
+@@ -77,6 +77,10 @@ static int create_cq(struct c4iw_rdev *rdev, struct t4_cq *cq,
+ int user = (uctx != &rdev->uctx);
+ int ret;
+ struct sk_buff *skb;
++ struct c4iw_ucontext *ucontext = NULL;
++
++ if (user)
++ ucontext = container_of(uctx, struct c4iw_ucontext, uctx);
+
+ cq->cqid = c4iw_get_cqid(rdev, uctx);
+ if (!cq->cqid) {
+@@ -100,6 +104,16 @@ static int create_cq(struct c4iw_rdev *rdev, struct t4_cq *cq,
+ dma_unmap_addr_set(cq, mapping, cq->dma_addr);
+ memset(cq->queue, 0, cq->memsize);
+
++ if (user && ucontext->is_32b_cqe) {
++ cq->qp_errp = &((struct t4_status_page *)
++ ((u8 *)cq->queue + (cq->size - 1) *
++ (sizeof(*cq->queue) / 2)))->qp_err;
++ } else {
++ cq->qp_errp = &((struct t4_status_page *)
++ ((u8 *)cq->queue + (cq->size - 1) *
++ sizeof(*cq->queue)))->qp_err;
++ }
++
+ /* build fw_ri_res_wr */
+ wr_len = sizeof *res_wr + sizeof *res;
+
+@@ -132,7 +146,9 @@ static int create_cq(struct c4iw_rdev *rdev, struct t4_cq *cq,
+ FW_RI_RES_WR_IQPCIECH_V(2) |
+ FW_RI_RES_WR_IQINTCNTTHRESH_V(0) |
+ FW_RI_RES_WR_IQO_F |
+- FW_RI_RES_WR_IQESIZE_V(1));
++ ((user && ucontext->is_32b_cqe) ?
++ FW_RI_RES_WR_IQESIZE_V(1) :
++ FW_RI_RES_WR_IQESIZE_V(2)));
+ res->u.cq.iqsize = cpu_to_be16(cq->size);
+ res->u.cq.iqaddr = cpu_to_be64(cq->dma_addr);
+
+@@ -884,6 +900,7 @@ struct ib_cq *c4iw_create_cq(struct ib_device *ibdev,
+ int vector = attr->comp_vector;
+ struct c4iw_dev *rhp;
+ struct c4iw_cq *chp;
++ struct c4iw_create_cq ucmd;
+ struct c4iw_create_cq_resp uresp;
+ struct c4iw_ucontext *ucontext = NULL;
+ int ret, wr_len;
+@@ -899,9 +916,16 @@ struct ib_cq *c4iw_create_cq(struct ib_device *ibdev,
+ if (vector >= rhp->rdev.lldi.nciq)
+ return ERR_PTR(-EINVAL);
+
++ if (ib_context) {
++ ucontext = to_c4iw_ucontext(ib_context);
++ if (udata->inlen < sizeof(ucmd))
++ ucontext->is_32b_cqe = 1;
++ }
++
+ chp = kzalloc(sizeof(*chp), GFP_KERNEL);
+ if (!chp)
+ return ERR_PTR(-ENOMEM);
++
+ chp->wr_waitp = c4iw_alloc_wr_wait(GFP_KERNEL);
+ if (!chp->wr_waitp) {
+ ret = -ENOMEM;
+@@ -916,9 +940,6 @@ struct ib_cq *c4iw_create_cq(struct ib_device *ibdev,
+ goto err_free_wr_wait;
+ }
+
+- if (ib_context)
+- ucontext = to_c4iw_ucontext(ib_context);
+-
+ /* account for the status page. */
+ entries++;
+
+@@ -942,13 +963,15 @@ struct ib_cq *c4iw_create_cq(struct ib_device *ibdev,
+ if (hwentries < 64)
+ hwentries = 64;
+
+- memsize = hwentries * sizeof *chp->cq.queue;
++ memsize = hwentries * ((ucontext && ucontext->is_32b_cqe) ?
++ (sizeof(*chp->cq.queue) / 2) : sizeof(*chp->cq.queue));
+
+ /*
+ * memsize must be a multiple of the page size if its a user cq.
+ */
+ if (ucontext)
+ memsize = roundup(memsize, PAGE_SIZE);
++
+ chp->cq.size = hwentries;
+ chp->cq.memsize = memsize;
+ chp->cq.vector = vector;
+@@ -979,6 +1002,7 @@ struct ib_cq *c4iw_create_cq(struct ib_device *ibdev,
+ if (!mm2)
+ goto err_free_mm;
+
++ memset(&uresp, 0, sizeof(uresp));
+ uresp.qid_mask = rhp->rdev.cqmask;
+ uresp.cqid = chp->cq.cqid;
+ uresp.size = chp->cq.size;
+@@ -988,9 +1012,16 @@ struct ib_cq *c4iw_create_cq(struct ib_device *ibdev,
+ ucontext->key += PAGE_SIZE;
+ uresp.gts_key = ucontext->key;
+ ucontext->key += PAGE_SIZE;
++ /* communicate to the userspace that
++ * kernel driver supports 64B CQE
++ */
++ uresp.flags |= C4IW_64B_CQE;
++
+ spin_unlock(&ucontext->mmap_lock);
+ ret = ib_copy_to_udata(udata, &uresp,
+- sizeof(uresp) - sizeof(uresp.reserved));
++ ucontext->is_32b_cqe ?
++ sizeof(uresp) - sizeof(uresp.flags) :
++ sizeof(uresp));
+ if (ret)
+ goto err_free_mm2;
+
+diff --git a/drivers/infiniband/hw/cxgb4/ev.c b/drivers/infiniband/hw/cxgb4/ev.c
+index 3e9d8b277ab9..8741d23168f3 100644
+--- a/drivers/infiniband/hw/cxgb4/ev.c
++++ b/drivers/infiniband/hw/cxgb4/ev.c
+@@ -70,9 +70,10 @@ static void dump_err_cqe(struct c4iw_dev *dev, struct t4_cqe *err_cqe)
+ CQE_STATUS(err_cqe), CQE_TYPE(err_cqe), ntohl(err_cqe->len),
+ CQE_WRID_HI(err_cqe), CQE_WRID_LOW(err_cqe));
+
+- pr_debug("%016llx %016llx %016llx %016llx\n",
++ pr_debug("%016llx %016llx %016llx %016llx - %016llx %016llx %016llx %016llx\n",
+ be64_to_cpu(p[0]), be64_to_cpu(p[1]), be64_to_cpu(p[2]),
+- be64_to_cpu(p[3]));
++ be64_to_cpu(p[3]), be64_to_cpu(p[4]), be64_to_cpu(p[5]),
++ be64_to_cpu(p[6]), be64_to_cpu(p[7]));
+
+ /*
+ * Ingress WRITE and READ_RESP errors provide
+diff --git a/drivers/infiniband/hw/cxgb4/iw_cxgb4.h b/drivers/infiniband/hw/cxgb4/iw_cxgb4.h
+index 392f542462b3..0bc28df859fa 100644
+--- a/drivers/infiniband/hw/cxgb4/iw_cxgb4.h
++++ b/drivers/infiniband/hw/cxgb4/iw_cxgb4.h
+@@ -590,6 +590,7 @@ struct c4iw_ucontext {
+ spinlock_t mmap_lock;
+ struct list_head mmaps;
+ struct kref kref;
++ bool is_32b_cqe;
+ };
+
+ static inline struct c4iw_ucontext *to_c4iw_ucontext(struct ib_ucontext *c)
+diff --git a/drivers/infiniband/hw/cxgb4/t4.h b/drivers/infiniband/hw/cxgb4/t4.h
+index 860a90980132..130ef87fa038 100644
+--- a/drivers/infiniband/hw/cxgb4/t4.h
++++ b/drivers/infiniband/hw/cxgb4/t4.h
+@@ -183,9 +183,20 @@ struct t4_cqe {
+ __be32 wrid_hi;
+ __be32 wrid_low;
+ } gen;
++ struct {
++ __be32 stag;
++ __be32 msn;
++ __be32 reserved;
++ __be32 abs_rqe_idx;
++ } srcqe;
++ struct {
++ __be64 imm_data;
++ } imm_data_rcqe;
++
+ u64 drain_cookie;
++ __be64 flits[3];
+ } u;
+- __be64 reserved;
++ __be64 reserved[3];
+ __be64 bits_type_ts;
+ };
+
+@@ -680,6 +691,7 @@ struct t4_cq {
+ u16 cidx_inc;
+ u8 gen;
+ u8 error;
++ u8 *qp_errp;
+ unsigned long flags;
+ };
+
+@@ -813,12 +825,12 @@ static inline int t4_next_cqe(struct t4_cq *cq, struct t4_cqe **cqe)
+
+ static inline int t4_cq_in_error(struct t4_cq *cq)
+ {
+- return ((struct t4_status_page *)&cq->queue[cq->size])->qp_err;
++ return *cq->qp_errp;
+ }
+
+ static inline void t4_set_cq_in_error(struct t4_cq *cq)
+ {
+- ((struct t4_status_page *)&cq->queue[cq->size])->qp_err = 1;
++ *cq->qp_errp = 1;
+ }
+ #endif
+
+diff --git a/include/uapi/rdma/cxgb4-abi.h b/include/uapi/rdma/cxgb4-abi.h
+index 63e78ef82505..822db6c1bdfa 100644
+--- a/include/uapi/rdma/cxgb4-abi.h
++++ b/include/uapi/rdma/cxgb4-abi.h
+@@ -43,6 +43,16 @@
+ * In particular do not use pointer types -- pass pointers in __u64
+ * instead.
+ */
++
++enum {
++ C4IW_64B_CQE = (1 << 0)
++};
++
++struct c4iw_create_cq {
++ __u32 flags;
++ __u32 reserved;
++};
++
+ struct c4iw_create_cq_resp {
+ __u64 key;
+ __u64 gts_key;
+@@ -50,7 +60,7 @@ struct c4iw_create_cq_resp {
+ __u32 cqid;
+ __u32 size;
+ __u32 qid_mask;
+- __u32 reserved; /* explicit padding (optional for i386) */
++ __u32 flags;
+ };
+
+ enum {
+--
+2.12.3
+
diff --git a/series.conf b/series.conf
index f53cc89a3a..3553348934 100644
--- a/series.conf
+++ b/series.conf
@@ -18526,10 +18526,16 @@
patches.drivers/IB-core-type-promotion-bug-in-rdma_rw_init_one_mr.patch
patches.drivers/RDMA-bnxt_re-Fix-a-couple-off-by-one-bugs.patch
patches.drivers/RDMA-bnxt_re-Fix-a-bunch-of-off-by-one-bugs-in-qplib.patch
+ patches.suse/0001-RDMA-cxgb4-Make-c4iw_poll_cq_one-easier-to-analyze.patch
patches.drivers/IB-mlx5-fix-uaccess-beyond-count-in-debugfs-read-wri.patch
+ patches.suse/0001-rdma-cxgb4-Add-support-for-64Byte-cqes.patch
patches.drivers/IB-ipoib-Fix-error-return-code-in-ipoib_dev_init.patch
+ patches.fixes/0001-rdma-cxgb4-Add-support-for-srq-functions-structs.patch
+ patches.fixes/0001-rdma-cxgb4-Add-support-for-kernel-mode-SRQ-s.patch
patches.drivers/IB-mlx4-Use-4K-pages-for-kernel-QP-s-WQE-buffer.patch
+ patches.fixes/0001-rdma-cxgb4-Remove-a-set-but-not-used-variable.patch
patches.drivers/IB-IPoIB-Set-ah-valid-flag-in-multicast-send-flow.patch
+ patches.fixes/0001-rdma-cxgb4-fix-some-info-leaks.patch
patches.fixes/dax-remove-VM_MIXEDMAP-for-fsdax-and-device-dax.patch
patches.fixes/fs-dcache.c-fix-kmemcheck-splat-at-take_dentry_name_.patch
patches.suse/mm-page_alloc-double-zone-s-batchsize.patch
@@ -21269,6 +21275,7 @@
patches.drivers/PCI-PME-Fix-hotplug-sysfs-remove-deadlock-in-pcie_pm.patch
patches.drivers/pci-qcom-don-t-deassert-reset-gpio-during-probe
patches.drivers/PCI-endpoint-functions-Use-memcpy_fromio-memcpy_toio.patch
+ patches.fixes/0001-RDMA-iw_cxgb4-Drop-__GFP_NOFAIL.patch
patches.drivers/IB-core-Destroy-QP-if-XRC-QP-fails.patch
patches.drivers/RDMA-vmw_pvrdma-Support-upto-64-bit-PFNs.patch
patches.drivers/IB-core-Unregister-notifier-before-freeing-MAD-secur.patch