[PATCH 3/4] RDMA/ionic: add Shared receive queue (SRQ) support

From: Abhijit Gangurde

Date: Tue Jul 07 2026 - 05:57:19 EST


Implement device supported verb APIs for shared receive queue.

Signed-off-by: Abhijit Gangurde <abhijit.gangurde@xxxxxxx>
---
.../infiniband/hw/ionic/ionic_controlpath.c | 375 +++++++++++++++---
drivers/infiniband/hw/ionic/ionic_datapath.c | 2 +-
drivers/infiniband/hw/ionic/ionic_fw.h | 42 ++
drivers/infiniband/hw/ionic/ionic_ibdev.c | 16 +
drivers/infiniband/hw/ionic/ionic_ibdev.h | 26 +-
drivers/infiniband/hw/ionic/ionic_lif_cfg.c | 1 +
drivers/infiniband/hw/ionic/ionic_lif_cfg.h | 1 +
include/uapi/rdma/ionic-abi.h | 2 +-
8 files changed, 403 insertions(+), 62 deletions(-)

diff --git a/drivers/infiniband/hw/ionic/ionic_controlpath.c b/drivers/infiniband/hw/ionic/ionic_controlpath.c
index a5045c08915e..35eb08dd0761 100644
--- a/drivers/infiniband/hw/ionic/ionic_controlpath.c
+++ b/drivers/infiniband/hw/ionic/ionic_controlpath.c
@@ -14,6 +14,8 @@
#define ionic_set_ecn(tos) (((tos) | 2u) & ~1u)
#define ionic_clear_ecn(tos) ((tos) & ~3u)

+#define QP_USES_SRQ(qp) ((qp)->srq)
+
static int ionic_validate_qdesc(struct ionic_qdesc *q)
{
if (!q->addr || !q->size || !q->mask ||
@@ -289,6 +291,21 @@ static int ionic_get_qpid(struct ionic_ibdev *dev, u32 *qpid,
return rc;
}

+static int ionic_get_srqid(struct ionic_ibdev *dev, u32 *srqid,
+ u8 *udma_idx, u8 udma_mask)
+{
+ if (udma_mask &&
+ !(udma_mask & dev->next_srqid_udma_idx))
+ /* flip udma idx if it doesn't coincide with udma_mask */
+ dev->next_srqid_udma_idx ^= dev->lif_cfg.udma_count - 1;
+
+ *udma_idx = dev->next_srqid_udma_idx;
+ /* update udma_idx for next srqid allocation */
+ dev->next_srqid_udma_idx ^= dev->lif_cfg.udma_count - 1;
+
+ return ionic_get_cqid(dev, srqid, *udma_idx);
+}
+
static int ionic_get_dbid(struct ionic_ibdev *dev, u32 *dbid, phys_addr_t *addr)
{
int rc, dbpage_num;
@@ -331,6 +348,11 @@ static void ionic_put_qpid(struct ionic_ibdev *dev, u32 qpid)
ionic_resid_put(&dev->inuse_qpid, bitid);
}

+static inline void ionic_put_srqid(struct ionic_ibdev *dev, u32 srqid)
+{
+ ionic_put_cqid(dev, srqid);
+}
+
static void ionic_put_dbid(struct ionic_ibdev *dev, u32 dbid)
{
ionic_resid_put(&dev->inuse_dbid, dbid);
@@ -1360,7 +1382,7 @@ static int ionic_create_qp_cmd(struct ionic_ibdev *dev,
wr.wqe.cmd.create_qp.sq_dma_addr = ionic_pgtbl_dma(sq_buf, 0);
}

- if (qp->has_rq) {
+ if (!QP_USES_SRQ(qp)) {
wr.wqe.cmd.create_qp.rq_cq_id = cpu_to_le32(recv_cq->cqid);
wr.wqe.cmd.create_qp.rq_depth_log2 = qp->rq.q.depth_log2;
wr.wqe.cmd.create_qp.rq_stride_log2 = qp->rq.q.stride_log2;
@@ -1369,6 +1391,9 @@ static int ionic_create_qp_cmd(struct ionic_ibdev *dev,
wr.wqe.cmd.create_qp.rq_map_count =
cpu_to_le32(rq_buf->tbl_pages);
wr.wqe.cmd.create_qp.rq_dma_addr = ionic_pgtbl_dma(rq_buf, 0);
+ } else {
+ wr.wqe.cmd.create_qp.rq_tbl_index_srq_id = cpu_to_le32(qp->srq->rq.qid);
+ wr.wqe.cmd.create_qp.rq_cq_id = cpu_to_le32(recv_cq->cqid);
}

ionic_admin_post(dev, &wr);
@@ -1554,7 +1579,7 @@ static int ionic_query_qp_cmd(struct ionic_ibdev *dev,
ionic_v1_send_wqe_max_data(qp->sq.stride_log2, expdb);
}

- if (qp->has_rq) {
+ if (!QP_USES_SRQ(qp)) {
attr->cap.max_recv_sge =
ionic_v1_recv_wqe_max_sge(qp->rq.q.stride_log2,
qp->rq.spec,
@@ -1930,6 +1955,42 @@ static void ionic_qp_sq_destroy(struct ionic_ibdev *dev,
ionic_queue_destroy(&qp->sq, dev->lif_cfg.hwdev);
}

+static void ionic_rq_mmap_cmb(struct ionic_ibdev *dev,
+ struct ionic_ctx *ctx,
+ struct ionic_rq *rq,
+ u64 *cmb_offset)
+{
+ bool wc;
+
+ /* set mapping by default to uncached for
+ * expdb (to guarantee writes order) otherwise
+ * writecombine, unless this default is
+ * overridden by userspace
+ */
+ if ((rq->cmb & (IONIC_CMB_WC | IONIC_CMB_UC)) ==
+ (IONIC_CMB_WC | IONIC_CMB_UC)) {
+ ibdev_warn(&dev->ibdev,
+ "Both rq_cmb flags IONIC_CMB_WC and IONIC_CMB_UC set, using default driver mapping\n");
+ rq->cmb &= ~(IONIC_CMB_WC | IONIC_CMB_UC);
+ }
+
+ if (rq->cmb & IONIC_CMB_EXPDB)
+ wc = (rq->cmb & (IONIC_CMB_WC | IONIC_CMB_UC)) == IONIC_CMB_WC;
+ else
+ wc = (rq->cmb & (IONIC_CMB_WC | IONIC_CMB_UC)) != IONIC_CMB_UC;
+
+ /* let userspace know the mapping */
+ if (wc)
+ rq->cmb |= IONIC_CMB_WC;
+ else
+ rq->cmb |= IONIC_CMB_UC;
+
+ rq->mmap_cmb = ionic_mmap_entry_insert(ctx, rq->q.size,
+ PHYS_PFN(rq->cmb_addr),
+ wc ? IONIC_MMAP_WC : 0,
+ cmb_offset);
+}
+
static void ionic_rq_init_cmb(struct ionic_ibdev *dev,
struct ionic_rq *rq,
struct ib_udata *udata)
@@ -2163,19 +2224,26 @@ int ionic_create_qp(struct ib_qp *ibqp, struct ib_qp_init_attr *attr,
spin_lock_init(&qp->rq.lock);

qp->has_sq = 1;
- qp->has_rq = 1;
+
+ if (attr->srq)
+ qp->srq = to_ionic_srq(attr->srq);
+ else
+ qp->srq = NULL;

if (attr->qp_type == IB_QPT_GSI) {
rc = ionic_get_gsi_qpid(dev, &qp->qpid);
} else {
udma_mask = BIT(dev->lif_cfg.udma_count) - 1;

- if (qp->has_sq)
+ if (attr->send_cq)
udma_mask &= to_ionic_vcq(attr->send_cq)->udma_mask;

- if (qp->has_rq)
+ if (attr->recv_cq)
udma_mask &= to_ionic_vcq(attr->recv_cq)->udma_mask;

+ if (attr->srq)
+ udma_mask &= BIT(to_ionic_srq(attr->srq)->udma_idx);
+
if (udata && req.udma_mask)
udma_mask &= req.udma_mask;

@@ -2202,13 +2270,8 @@ int ionic_create_qp(struct ib_qp *ibqp, struct ib_qp_init_attr *attr,
goto err_ahid;
}

- if (udata) {
- if (req.rq_cmb & IONIC_CMB_ENABLE)
- qp->rq.cmb = req.rq_cmb;
-
- if (req.sq_cmb & IONIC_CMB_ENABLE)
- qp->sq_cmb = req.sq_cmb;
- }
+ if (udata && (req.sq_cmb & IONIC_CMB_ENABLE))
+ qp->sq_cmb = req.sq_cmb;

rc = ionic_qp_sq_init(dev, ctx, qp, &req.sq, &sq_buf,
attr->cap.max_send_wr, attr->cap.max_send_sge,
@@ -2216,7 +2279,17 @@ int ionic_create_qp(struct ib_qp *ibqp, struct ib_qp_init_attr *attr,
if (rc)
goto err_sq;

- if (qp->has_rq) {
+ if (QP_USES_SRQ(qp)) {
+ rq_buf.tbl_buf = NULL;
+ rq_buf.tbl_limit = 0;
+ rq_buf.tbl_pages = 0;
+
+ if (udata)
+ rc = ionic_validate_qdesc_zero(&req.rq);
+ } else {
+ if (udata && (req.rq_cmb & IONIC_CMB_ENABLE))
+ qp->rq.cmb = req.rq_cmb;
+
/* for non-srq qps, rq qid is same as qpid */
qp->rq.qid = qp->qpid;
rc = ionic_rq_init(dev, ctx, &qp->rq, &req.rq, &rq_buf,
@@ -2224,16 +2297,9 @@ int ionic_create_qp(struct ib_qp *ibqp, struct ib_qp_init_attr *attr,
req.rq_spec, udata,
(qp->ibqp.qp_type == IB_QPT_DRIVER) ?
IB_ACCESS_LOCAL_WRITE : 0);
- if (rc)
- goto err_rq;
- } else {
- rq_buf.tbl_buf = NULL;
- rq_buf.tbl_limit = 0;
- rq_buf.tbl_pages = 0;
-
- if (udata)
- rc = ionic_validate_qdesc_zero(&req.rq);
}
+ if (rc)
+ goto err_rq;

rc = ionic_create_qp_cmd(dev, pd,
to_ionic_vcq_cq(attr->send_cq, qp->udma_idx),
@@ -2279,35 +2345,9 @@ int ionic_create_qp(struct ib_qp *ibqp, struct ib_qp_init_attr *attr,
resp.sq_cmb = qp->sq_cmb;
}

- if (qp->rq.cmb & IONIC_CMB_ENABLE) {
- bool wc;
+ if (!QP_USES_SRQ(qp) && (qp->rq.cmb & IONIC_CMB_ENABLE)) {
+ ionic_rq_mmap_cmb(dev, ctx, &qp->rq, &resp.rq_cmb_offset);

- if ((qp->rq.cmb & (IONIC_CMB_WC | IONIC_CMB_UC)) ==
- (IONIC_CMB_WC | IONIC_CMB_UC)) {
- ibdev_dbg(&dev->ibdev,
- "Both rq.cmb flags IONIC_CMB_WC and IONIC_CMB_UC are set, using default driver mapping\n");
- qp->rq.cmb &= ~(IONIC_CMB_WC | IONIC_CMB_UC);
- }
-
- if (qp->rq.cmb & IONIC_CMB_EXPDB)
- wc = (qp->rq.cmb & (IONIC_CMB_WC | IONIC_CMB_UC))
- == IONIC_CMB_WC;
- else
- wc = (qp->rq.cmb & (IONIC_CMB_WC | IONIC_CMB_UC))
- != IONIC_CMB_UC;
-
- /* let userspace know the mapping */
- if (wc)
- qp->rq.cmb |= IONIC_CMB_WC;
- else
- qp->rq.cmb |= IONIC_CMB_UC;
-
- qp->rq.mmap_cmb =
- ionic_mmap_entry_insert(ctx,
- qp->rq.q.size,
- PHYS_PFN(qp->rq.cmb_addr),
- wc ? IONIC_MMAP_WC : 0,
- &resp.rq_cmb_offset);
if (!qp->rq.mmap_cmb) {
rc = -ENOMEM;
goto err_mmap_rq;
@@ -2354,7 +2394,7 @@ int ionic_create_qp(struct ib_qp *ibqp, struct ib_qp_init_attr *attr,
qp->sq_cqid = cq->cqid;
}

- if (qp->has_rq) {
+ if (!QP_USES_SRQ(qp)) {
cq = to_ionic_vcq_cq(attr->recv_cq, qp->udma_idx);

attr->cap.max_recv_wr = qp->rq.q.mask;
@@ -2368,7 +2408,7 @@ int ionic_create_qp(struct ib_qp *ibqp, struct ib_qp_init_attr *attr,
return 0;

err_resp:
- if (udata && (qp->rq.cmb & IONIC_CMB_ENABLE))
+ if (udata && !QP_USES_SRQ(qp) && (qp->rq.cmb & IONIC_CMB_ENABLE))
rdma_user_mmap_entry_remove(qp->rq.mmap_cmb);
err_mmap_rq:
if (udata && (qp->sq_cmb & IONIC_CMB_ENABLE))
@@ -2376,9 +2416,10 @@ int ionic_create_qp(struct ib_qp *ibqp, struct ib_qp_init_attr *attr,
err_mmap_sq:
ionic_destroy_qp_cmd(dev, qp->qpid);
err_cmd:
- ionic_pgtbl_unbuf(dev, &rq_buf);
- if (qp->has_rq)
+ if (!QP_USES_SRQ(qp)) {
+ ionic_pgtbl_unbuf(dev, &rq_buf);
ionic_rq_destroy(dev, ctx, &qp->rq);
+ }
err_rq:
ionic_pgtbl_unbuf(dev, &sq_buf);
ionic_qp_sq_destroy(dev, ctx, qp);
@@ -2429,7 +2470,7 @@ void ionic_flush_qp(struct ionic_ibdev *dev, struct ionic_qp *qp)
spin_unlock_irqrestore(&cq->lock, irqflags);
}

- if (qp->ibqp.recv_cq) {
+ if (qp->ibqp.recv_cq && !QP_USES_SRQ(qp)) {
cq = to_ionic_vcq_cq(qp->ibqp.recv_cq, qp->udma_idx);

/* Hold the CQ lock and QP rq.lock to set up flush */
@@ -2505,7 +2546,7 @@ static void ionic_reset_qp(struct ionic_ibdev *dev, struct ionic_qp *qp)
spin_unlock(&qp->sq_lock);
}

- if (qp->has_rq) {
+ if (!QP_USES_SRQ(qp)) {
spin_lock(&qp->rq.lock);
qp->rq.flush = false;
qp->rq.q.prod = 0;
@@ -2610,7 +2651,7 @@ int ionic_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
if (qp->has_sq)
attr->cap.max_send_wr = qp->sq.mask;

- if (qp->has_rq)
+ if (!QP_USES_SRQ(qp))
attr->cap.max_recv_wr = qp->rq.q.mask;

init_attr->event_handler = ibqp->event_handler;
@@ -2667,7 +2708,7 @@ int ionic_destroy_qp(struct ib_qp *ibqp, struct ib_udata *udata)
spin_unlock_irqrestore(&cq->lock, irqflags);
}

- if (qp->has_rq)
+ if (!QP_USES_SRQ(qp))
ionic_rq_destroy(dev, ctx, &qp->rq);

ionic_qp_sq_destroy(dev, ctx, qp);
@@ -2679,3 +2720,221 @@ int ionic_destroy_qp(struct ib_qp *ibqp, struct ib_udata *udata)

return 0;
}
+
+static int ionic_create_srq_cmd(struct ionic_ibdev *dev,
+ struct ionic_ctx *ctx,
+ struct ionic_srq *srq,
+ struct ionic_pd *pd,
+ struct ionic_tbl_buf *buf)
+{
+ const u16 dbid = ionic_ctx_dbid(dev, ctx);
+ struct ionic_admin_wr wr = {
+ .work = COMPLETION_INITIALIZER_ONSTACK(wr.work),
+ .wqe = {
+ .op = IONIC_V1_ADMIN_CREATE_SRQ,
+ .len = cpu_to_le16(IONIC_ADMIN_CREATE_SRQ_IN_V1_LEN),
+ .cmd.create_srq = {
+ .pd_id = cpu_to_le32(pd->pdid),
+ .depth_log2 = srq->rq.q.depth_log2,
+ .stride_log2 = srq->rq.q.stride_log2,
+ .page_size_log2 = buf->page_size_log2,
+ .map_count = cpu_to_le32(buf->tbl_pages),
+ .dma_addr = ionic_pgtbl_dma(buf, 0),
+ .dbid = cpu_to_le16(dbid),
+ .qid = cpu_to_le32(srq->rq.qid),
+ .low_wqes_limit = cpu_to_le32(srq->srq_limit),
+ }
+ }
+ };
+
+ if (dev->lif_cfg.admin_opcodes <= IONIC_V1_ADMIN_CREATE_SRQ)
+ return -EOPNOTSUPP;
+
+ ionic_admin_post(dev, &wr);
+
+ return ionic_admin_wait(dev, &wr, 0);
+}
+
+static int ionic_destroy_srq_cmd(struct ionic_ibdev *dev, u32 srqid)
+{
+ struct ionic_admin_wr wr = {
+ .work = COMPLETION_INITIALIZER_ONSTACK(wr.work),
+ .wqe = {
+ .op = IONIC_V1_ADMIN_DESTROY_SRQ,
+ .len = cpu_to_le16(IONIC_ADMIN_DESTROY_SRQ_IN_V1_LEN),
+ .cmd.destroy_srq = {
+ .qid = cpu_to_le32(srqid),
+ },
+ }
+ };
+
+ if (dev->lif_cfg.admin_opcodes <= IONIC_V1_ADMIN_DESTROY_SRQ)
+ return -EOPNOTSUPP;
+
+ ionic_admin_post(dev, &wr);
+
+ return ionic_admin_wait(dev, &wr, IONIC_ADMIN_F_TEARDOWN);
+}
+
+static int ionic_modify_srq_cmd(struct ionic_ibdev *dev, u32 srqid,
+ u16 srq_limit)
+{
+ struct ionic_admin_wr wr = {
+ .work = COMPLETION_INITIALIZER_ONSTACK(wr.work),
+ .wqe = {
+ .op = IONIC_V1_ADMIN_MODIFY_SRQ,
+ .len = cpu_to_le16(IONIC_ADMIN_MODIFY_SRQ_IN_V1_LEN),
+ .cmd.modify_srq = {
+ .qid = cpu_to_le32(srqid),
+ .low_wqes_limit = cpu_to_le32(srq_limit),
+ },
+ }
+ };
+
+ if (dev->lif_cfg.admin_opcodes <= IONIC_V1_ADMIN_MODIFY_SRQ)
+ return -EOPNOTSUPP;
+
+ ionic_admin_post(dev, &wr);
+
+ return ionic_admin_wait(dev, &wr, IONIC_ADMIN_F_TEARDOWN);
+}
+
+int ionic_create_srq(struct ib_srq *ibsrq, struct ib_srq_init_attr *attr,
+ struct ib_udata *udata)
+{
+ struct ionic_ibdev *dev = to_ionic_ibdev(ibsrq->device);
+ struct ionic_pd *pd = to_ionic_pd(ibsrq->pd);
+ struct ionic_srq *srq = to_ionic_srq(ibsrq);
+ struct ionic_ctx *ctx =
+ rdma_udata_to_drv_context(udata, struct ionic_ctx, ibctx);
+ struct ionic_srq_resp resp = {};
+ struct ionic_srq_req req = {};
+ struct ionic_tbl_buf buf = {};
+ u8 udma_mask;
+ int rc;
+
+ if (attr->srq_type != IB_SRQT_BASIC)
+ return -EOPNOTSUPP;
+
+ if (attr->attr.max_sge > IONIC_MAX_SRQ_SGES)
+ return -EINVAL;
+
+ if (attr->attr.srq_limit >= IONIC_MAX_SRQ_LIMIT)
+ return -EINVAL;
+
+ udma_mask = BIT(dev->lif_cfg.udma_count) - 1;
+ if (udata) {
+ rc = ib_copy_from_udata(&req, udata,
+ min(sizeof(req), udata->inlen));
+ if (rc)
+ return rc;
+
+ udma_mask &= req.udma_mask;
+ }
+
+ if (!udma_mask)
+ return -EINVAL;
+
+ rc = ionic_get_srqid(dev, &srq->rq.qid, &srq->udma_idx, udma_mask);
+ if (rc)
+ return rc;
+
+ rc = ionic_rq_init(dev, ctx, &srq->rq, &req.rq, &buf,
+ attr->attr.max_wr, attr->attr.max_sge,
+ req.rq_spec, udata, 0);
+ if (rc)
+ goto err_rq_init;
+
+ srq->srq_limit = attr->attr.srq_limit;
+
+ rc = ionic_create_srq_cmd(dev, ctx, srq, pd, &buf);
+ if (rc)
+ goto err_cmd;
+
+ if (udata) {
+ resp.srqid = srq->rq.qid;
+ resp.udma_idx = srq->udma_idx;
+
+ if (srq->rq.cmb & IONIC_CMB_ENABLE) {
+ ionic_rq_mmap_cmb(dev, ctx, &srq->rq, &resp.rq_cmb_offset);
+ if (!srq->rq.mmap_cmb)
+ goto err_mmap_rq;
+
+ resp.rq_cmb = srq->rq.cmb;
+ }
+
+ rc = ib_copy_to_udata(udata, &resp,
+ min(sizeof(resp), udata->outlen));
+ if (rc)
+ goto err_resp;
+ }
+
+ ionic_pgtbl_unbuf(dev, &buf);
+ attr->attr.max_wr = srq->rq.q.mask;
+ return 0;
+err_resp:
+ if (udata && (srq->rq.cmb & IONIC_CMB_ENABLE))
+ rdma_user_mmap_entry_remove(srq->rq.mmap_cmb);
+err_mmap_rq:
+ ionic_destroy_srq_cmd(dev, srq->rq.qid);
+err_cmd:
+ ionic_pgtbl_unbuf(dev, &buf);
+ ionic_rq_destroy(dev, ctx, &srq->rq);
+err_rq_init:
+ ionic_put_srqid(dev, srq->rq.qid);
+ return rc;
+}
+
+int ionic_destroy_srq(struct ib_srq *ibsrq, struct ib_udata *udata)
+{
+ struct ionic_ctx *ctx =
+ rdma_udata_to_drv_context(udata, struct ionic_ctx, ibctx);
+ struct ionic_ibdev *dev = to_ionic_ibdev(ibsrq->device);
+ struct ionic_srq *srq = to_ionic_srq(ibsrq);
+ int rc;
+
+ rc = ionic_destroy_srq_cmd(dev, srq->rq.qid);
+ if (rc)
+ return rc;
+
+ ionic_rq_destroy(dev, ctx, &srq->rq);
+ ionic_put_srqid(dev, srq->rq.qid);
+ return 0;
+}
+
+int ionic_query_srq(struct ib_srq *ibsrq, struct ib_srq_attr *srq_attr)
+{
+ struct ionic_srq *srq = to_ionic_srq(ibsrq);
+
+ srq_attr->max_wr = srq->rq.q.mask;
+ srq_attr->max_sge =
+ ionic_v1_recv_wqe_max_sge(srq->rq.q.stride_log2, srq->rq.spec,
+ srq->rq.cmb & IONIC_CMB_EXPDB);
+ srq_attr->srq_limit = srq->srq_limit;
+
+ return 0;
+}
+
+int ionic_modify_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr,
+ enum ib_srq_attr_mask attr_mask, struct ib_udata *udata)
+{
+ struct ionic_ibdev *dev = to_ionic_ibdev(ibsrq->device);
+ struct ionic_srq *srq = to_ionic_srq(ibsrq);
+ int rc;
+
+ if (attr_mask & IB_SRQ_MAX_WR)
+ return -EINVAL;
+
+ if (attr_mask & IB_SRQ_LIMIT) {
+ if (attr->srq_limit >= IONIC_MAX_SRQ_LIMIT)
+ return -EINVAL;
+
+ rc = ionic_modify_srq_cmd(dev, srq->rq.qid, attr->srq_limit);
+ if (rc)
+ return rc;
+
+ srq->srq_limit = attr->srq_limit;
+ }
+
+ return 0;
+}
diff --git a/drivers/infiniband/hw/ionic/ionic_datapath.c b/drivers/infiniband/hw/ionic/ionic_datapath.c
index b8fa6b6e5f33..b050f2e84f6b 100644
--- a/drivers/infiniband/hw/ionic/ionic_datapath.c
+++ b/drivers/infiniband/hw/ionic/ionic_datapath.c
@@ -1310,7 +1310,7 @@ static int ionic_post_recv_common(struct ionic_ibdev *dev,
if (!bad)
return -EINVAL;

- if (!qp->has_rq) {
+ if (qp->srq) {
*bad = wr;
return -EINVAL;
}
diff --git a/drivers/infiniband/hw/ionic/ionic_fw.h b/drivers/infiniband/hw/ionic/ionic_fw.h
index adfbb89d856c..632b16932844 100644
--- a/drivers/infiniband/hw/ionic/ionic_fw.h
+++ b/drivers/infiniband/hw/ionic/ionic_fw.h
@@ -88,6 +88,10 @@ static inline int to_ionic_mr_flags(int access)
return flags;
}

+enum ionic_srq_flags {
+ IONIC_SRQF_CMB = BIT(0),
+};
+
enum ionic_qp_flags {
/* bits that determine qp access */
IONIC_QPF_REMOTE_WRITE = BIT(0),
@@ -838,6 +842,37 @@ struct ionic_admin_query_qp {
static_assert(sizeof(struct ionic_admin_query_qp) ==
IONIC_ADMIN_QUERY_QP_IN_V1_LEN);

+struct ionic_admin_create_srq {
+ __le64 dma_addr;
+ __le32 map_count;
+ __le32 pd_id;
+ __le32 qid;
+ __le16 dbid;
+ __le16 low_wqes_limit;
+ __le16 flags;
+ __u8 depth_log2;
+ __u8 stride_log2;
+ __u8 page_size_log2;
+} __packed;
+
+#define IONIC_ADMIN_CREATE_SRQ_IN_V1_LEN 29
+static_assert(sizeof(struct ionic_admin_create_srq) == IONIC_ADMIN_CREATE_SRQ_IN_V1_LEN);
+
+struct ionic_admin_modify_srq {
+ __le32 qid;
+ __le16 low_wqes_limit;
+} __packed;
+
+#define IONIC_ADMIN_MODIFY_SRQ_IN_V1_LEN 6
+static_assert(sizeof(struct ionic_admin_modify_srq) == IONIC_ADMIN_MODIFY_SRQ_IN_V1_LEN);
+
+struct ionic_admin_destroy_srq {
+ __le32 qid;
+} __packed;
+
+#define IONIC_ADMIN_DESTROY_SRQ_IN_V1_LEN 4
+static_assert(sizeof(struct ionic_admin_destroy_srq) == IONIC_ADMIN_DESTROY_SRQ_IN_V1_LEN);
+
#define ADMIN_WQE_STRIDE 64
#define ADMIN_WQE_HDR_LEN 4

@@ -860,6 +895,9 @@ struct ionic_v1_admin_wqe {
struct ionic_admin_destroy_qp destroy_qp;
struct ionic_admin_mod_qp mod_qp;
struct ionic_admin_query_qp query_qp;
+ struct ionic_admin_create_srq create_srq;
+ struct ionic_admin_modify_srq modify_srq;
+ struct ionic_admin_destroy_srq destroy_srq;
} cmd;
};

@@ -906,6 +944,10 @@ enum ionic_v1_admin_op {
IONIC_V1_ADMIN_DESTROY_AH,
IONIC_V1_ADMIN_QP_STATS_HDRS,
IONIC_V1_ADMIN_QP_STATS_VALS,
+ IONIC_V1_ADMIN_CREATE_SRQ = 26,
+ IONIC_V1_ADMIN_MODIFY_SRQ,
+ IONIC_V1_ADMIN_QUERY_SRQ,
+ IONIC_V1_ADMIN_DESTROY_SRQ,
IONIC_V1_ADMIN_OPCODES_MAX,
};

diff --git a/drivers/infiniband/hw/ionic/ionic_ibdev.c b/drivers/infiniband/hw/ionic/ionic_ibdev.c
index 164046d00e5d..d8a8e74f56ac 100644
--- a/drivers/infiniband/hw/ionic/ionic_ibdev.c
+++ b/drivers/infiniband/hw/ionic/ionic_ibdev.c
@@ -68,6 +68,11 @@ static int ionic_query_device(struct ib_device *ibdev,
attr->max_ah = dev->lif_cfg.nahs_per_lif;
attr->max_fast_reg_page_list_len = dev->lif_cfg.npts_per_lif / 2;
attr->max_pkeys = IONIC_PKEY_TBL_LEN;
+ if (dev->lif_cfg.srq_count) {
+ attr->max_srq = dev->lif_cfg.srq_count;
+ attr->max_srq_wr = IONIC_MAX_SRQ_DEPTH;
+ attr->max_srq_sge = IONIC_MAX_SRQ_SGES;
+ }

return 0;
}
@@ -258,6 +263,15 @@ static const struct ib_device_ops ionic_dev_ops = {
INIT_RDMA_OBJ_SIZE(ib_mw, ionic_mr, ibmw),
};

+static const struct ib_device_ops ionic_srq_ops = {
+ .create_srq = ionic_create_srq,
+ .modify_srq = ionic_modify_srq,
+ .query_srq = ionic_query_srq,
+ .destroy_srq = ionic_destroy_srq,
+
+ INIT_RDMA_OBJ_SIZE(ib_srq, ionic_srq, ibsrq),
+};
+
static void ionic_init_resids(struct ionic_ibdev *dev)
{
ionic_resid_init(&dev->inuse_cqid, dev->lif_cfg.cq_count);
@@ -346,6 +360,8 @@ static struct ionic_ibdev *ionic_create_ibdev(struct ionic_aux_dev *ionic_adev)
goto err_admin;

ib_set_device_ops(&dev->ibdev, &ionic_dev_ops);
+ if (dev->lif_cfg.srq_count)
+ ib_set_device_ops(&dev->ibdev, &ionic_srq_ops);

ionic_stats_init(dev);

diff --git a/drivers/infiniband/hw/ionic/ionic_ibdev.h b/drivers/infiniband/hw/ionic/ionic_ibdev.h
index 5517638d4ced..895672283264 100644
--- a/drivers/infiniband/hw/ionic/ionic_ibdev.h
+++ b/drivers/infiniband/hw/ionic/ionic_ibdev.h
@@ -33,10 +33,13 @@
#define IONIC_MAX_QPID 0xffffff
#define IONIC_SPEC_HIGH 8
#define IONIC_MAX_PD 1024
-#define IONIC_SPEC_HIGH 8
#define IONIC_SQCMB_ORDER 5
#define IONIC_RQCMB_ORDER 0

+#define IONIC_MAX_SRQ_SGES 2
+#define IONIC_MAX_SRQ_LIMIT 0xffff
+#define IONIC_MAX_SRQ_DEPTH 0xffff
+
#define IONIC_META_LAST ((void *)1ul)
#define IONIC_META_POSTED ((void *)2ul)

@@ -116,6 +119,7 @@ struct ionic_ibdev {
struct rdma_stat_desc *hw_stats_hdrs;
struct ionic_counter_stats *counter_stats;
int hw_stats_count;
+ u8 next_srqid_udma_idx;
};

struct ionic_eq {
@@ -265,6 +269,13 @@ struct ionic_rq {
bool flush;
};

+struct ionic_srq {
+ struct ib_srq ibsrq;
+ struct ionic_rq rq;
+ u16 srq_limit;
+ u8 udma_idx;
+};
+
struct ionic_qp {
struct ib_qp ibqp;
enum ib_qp_state state;
@@ -275,7 +286,6 @@ struct ionic_qp {
u8 udma_idx;
u8 has_ah:1;
u8 has_sq:1;
- u8 has_rq:1;
u8 sig_all:1;

struct list_head qp_list_counter;
@@ -314,6 +324,7 @@ struct ionic_qp {
int dcqcn_profile;

struct ib_ud_header *hdr;
+ struct ionic_srq *srq;
};

struct ionic_ah {
@@ -401,6 +412,11 @@ static inline struct ionic_qp *to_ionic_qp(struct ib_qp *ibqp)
return container_of(ibqp, struct ionic_qp, ibqp);
}

+static inline struct ionic_srq *to_ionic_srq(struct ib_srq *ibsrq)
+{
+ return container_of(ibsrq, struct ionic_srq, ibsrq);
+}
+
static inline struct ionic_ah *to_ionic_ah(struct ib_ah *ibah)
{
return container_of(ibah, struct ionic_ah, ibah);
@@ -500,6 +516,12 @@ int ionic_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int mask,
int ionic_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int mask,
struct ib_qp_init_attr *init_attr);
int ionic_destroy_qp(struct ib_qp *ibqp, struct ib_udata *udata);
+int ionic_create_srq(struct ib_srq *ibsrq, struct ib_srq_init_attr *attr,
+ struct ib_udata *udata);
+int ionic_destroy_srq(struct ib_srq *ibsrq, struct ib_udata *udata);
+int ionic_query_srq(struct ib_srq *ibsrq, struct ib_srq_attr *srq_attr);
+int ionic_modify_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr,
+ enum ib_srq_attr_mask attr_mask, struct ib_udata *udata);

/* ionic_datapath.c */
int ionic_post_send(struct ib_qp *ibqp, const struct ib_send_wr *wr,
diff --git a/drivers/infiniband/hw/ionic/ionic_lif_cfg.c b/drivers/infiniband/hw/ionic/ionic_lif_cfg.c
index f3cd281c3a2f..35e2f0f620cd 100644
--- a/drivers/infiniband/hw/ionic/ionic_lif_cfg.c
+++ b/drivers/infiniband/hw/ionic/ionic_lif_cfg.c
@@ -73,6 +73,7 @@ void ionic_fill_lif_cfg(struct ionic_lif *lif, struct ionic_lif_cfg *cfg)
cfg->eq_count = le32_to_cpu(ident->rdma.eq_qtype.qid_count);
cfg->cq_count = le32_to_cpu(ident->rdma.cq_qtype.qid_count);
cfg->qp_count = le32_to_cpu(ident->rdma.sq_qtype.qid_count);
+ cfg->srq_count = le32_to_cpu(ident->rdma.srq_qtype.qid_count);
cfg->dbid_count = le32_to_cpu(lif->ionic->ident.dev.ndbpgs_per_lif);

cfg->aq_qtype = ident->rdma.aq_qtype.qtype;
diff --git a/drivers/infiniband/hw/ionic/ionic_lif_cfg.h b/drivers/infiniband/hw/ionic/ionic_lif_cfg.h
index 20853429f623..0ffff7178c90 100644
--- a/drivers/infiniband/hw/ionic/ionic_lif_cfg.h
+++ b/drivers/infiniband/hw/ionic/ionic_lif_cfg.h
@@ -37,6 +37,7 @@ struct ionic_lif_cfg {
int eq_count;
int cq_count;
int qp_count;
+ int srq_count;

u16 stats_type;
u8 aq_qtype;
diff --git a/include/uapi/rdma/ionic-abi.h b/include/uapi/rdma/ionic-abi.h
index 7b589d3e9728..b89ae42f5126 100644
--- a/include/uapi/rdma/ionic-abi.h
+++ b/include/uapi/rdma/ionic-abi.h
@@ -105,7 +105,7 @@ struct ionic_srq_req {
};

struct ionic_srq_resp {
- __u32 qpid;
+ __u32 srqid;
__u8 rq_cmb;
__u8 udma_idx;
__u8 rsvd[2];
--
2.43.0