From: Abhijit Gangurde <abhijit.gangurde@amd.com>
To: <jgg@ziepe.ca>, <leon@kernel.org>, <brett.creeley@amd.com>,
<andrew+netdev@lunn.ch>, <davem@davemloft.net>,
<edumazet@google.com>, <kuba@kernel.org>, <pabeni@redhat.com>
Cc: <allen.hubbe@amd.com>, <nikhil.agarwal@amd.com>,
<linux-rdma@vger.kernel.org>, <netdev@vger.kernel.org>,
<linux-kernel@vger.kernel.org>,
Abhijit Gangurde <abhijit.gangurde@amd.com>
Subject: [for-next v1 2/5] RDMA/ionic: support firmware-assigned CQ IDs
Date: Tue, 8 Sep 2026 14:37:58 +0530 [thread overview]
Message-ID: <20260908090802.152142-3-abhijit.gangurde@amd.com> (raw)
In-Reply-To: <20260908090802.152142-1-abhijit.gangurde@amd.com>
When the LIF advertises qid allocation for CQ, let firmware return
the completion queue ID instead of allocating it in the driver bitmap.
Split CQ create/destroy into distinct phases so cq_tbl is updated only
after the ID is known and removed before the destroy admin command
returns the ID to firmware, avoiding a race where a concurrent create
reusing the same cqid could have its xarray entry erased by a stale
destroy.
Signed-off-by: Abhijit Gangurde <abhijit.gangurde@amd.com>
---
drivers/infiniband/hw/ionic/ionic_admin.c | 70 ++++++++--
.../infiniband/hw/ionic/ionic_controlpath.c | 121 ++++++++++++++----
drivers/infiniband/hw/ionic/ionic_fw.h | 15 ++-
drivers/infiniband/hw/ionic/ionic_ibdev.h | 12 +-
drivers/infiniband/hw/ionic/ionic_lif_cfg.c | 1 +
drivers/infiniband/hw/ionic/ionic_lif_cfg.h | 1 +
6 files changed, 181 insertions(+), 39 deletions(-)
diff --git a/drivers/infiniband/hw/ionic/ionic_admin.c b/drivers/infiniband/hw/ionic/ionic_admin.c
index 37e24450d129..cda48c36c047 100644
--- a/drivers/infiniband/hw/ionic/ionic_admin.c
+++ b/drivers/infiniband/hw/ionic/ionic_admin.c
@@ -489,6 +489,49 @@ static int ionic_rdma_queue_devcmd(struct ionic_ibdev *dev,
return ionic_rdma_devcmd(dev, &admin);
}
+static int ionic_rdma_cq_devcmd(struct ionic_vcq *vcq,
+ struct ionic_queue *q,
+ u32 *qid, u32 cid, u16 opcode,
+ u8 udma_mask)
+{
+ struct ionic_ibdev *dev = to_ionic_ibdev(vcq->ibcq.device);
+ struct ionic_admin_ctx admin = {
+ .work = COMPLETION_INITIALIZER_ONSTACK(admin.work),
+ .cmd.rdma_queue = {
+ .opcode = opcode,
+ .lif_index = cpu_to_le16(dev->lif_cfg.lif_index),
+ .qid_ver = cpu_to_le32(*qid),
+ .cid = cpu_to_le32(cid),
+ .dbid = cpu_to_le16(dev->lif_cfg.dbid),
+ .depth_log2 = q->depth_log2,
+ .stride_log2 = q->stride_log2,
+ .dma_addr = cpu_to_le64(q->dma),
+ },
+ };
+ int rc;
+
+ if (ionic_fw_has_qid_alloc(dev, IONIC_LIF_RDMA_ALLOC_QID_CQ)) {
+ struct ionic_admin_create_cq_resp resp_buf;
+
+ /* Indicates use of CQ create V2 response format. */
+ admin.cmd.rdma_queue.qid_ver = cpu_to_le32(IONIC_CREATE_CQ_CMD_V2_MAGIC);
+ admin.cmd.rdma_queue.udma_mask = udma_mask;
+
+ rc = ionic_rdma_devcmd(dev, &admin);
+ if (rc)
+ return rc;
+
+ memcpy(&resp_buf, admin.comp.comp.cmd_data, sizeof(resp_buf));
+ *qid = le32_to_cpu(resp_buf.id);
+ } else {
+ rc = ionic_rdma_devcmd(dev, &admin);
+ if (rc)
+ return rc;
+ }
+
+ return 0;
+}
+
static void ionic_rdma_admincq_comp(struct ib_cq *ibcq, void *cq_context)
{
struct ionic_aq *aq = cq_context;
@@ -533,12 +576,16 @@ static struct ionic_vcq *ionic_create_rdma_admincq(struct ionic_ibdev *dev,
cq = &vcq->cq[0];
rc = ionic_create_cq_common(vcq, &buf, &attr, NULL, NULL,
- NULL, NULL, 0);
+ NULL, 0);
if (rc)
goto err_init;
- rc = ionic_rdma_queue_devcmd(dev, &cq->q, cq->cqid, cq->eqid,
- IONIC_CMD_RDMA_CREATE_CQ);
+ rc = ionic_rdma_cq_devcmd(vcq, &cq->q, &cq->cqid, cq->eqid,
+ IONIC_CMD_RDMA_CREATE_CQ, 0);
+ if (rc)
+ goto err_cmd;
+
+ rc = ionic_post_create_cq_cmd(cq, &buf, NULL, NULL);
if (rc)
goto err_cmd;
@@ -552,6 +599,14 @@ static struct ionic_vcq *ionic_create_rdma_admincq(struct ionic_ibdev *dev,
return ERR_PTR(rc);
}
+static void ionic_destroy_rdma_admincq(struct ionic_ibdev *dev,
+ struct ionic_vcq *vcq)
+{
+ ionic_pre_destroy_cq_cmd(dev, &vcq->cq[0]);
+ ionic_destroy_cq_common(dev, &vcq->cq[0]);
+ kfree(vcq);
+}
+
static struct ionic_aq *__ionic_create_rdma_adminq(struct ionic_ibdev *dev,
u32 aqid, u32 cqid)
{
@@ -1153,8 +1208,7 @@ int ionic_create_rdma_admin(struct ionic_ibdev *dev)
vcq->cq[0].cqid);
if (IS_ERR(aq)) {
/* Clean up the dangling CQ */
- ionic_destroy_cq_common(dev, &vcq->cq[0]);
- kfree(vcq);
+ ionic_destroy_rdma_admincq(dev, vcq);
rc = PTR_ERR(aq);
@@ -1207,10 +1261,8 @@ void ionic_destroy_rdma_admin(struct ionic_ibdev *dev)
cancel_work_sync(&aq->work);
__ionic_destroy_rdma_adminq(dev, aq);
- if (vcq) {
- ionic_destroy_cq_common(dev, &vcq->cq[0]);
- kfree(vcq);
- }
+ if (vcq)
+ ionic_destroy_rdma_admincq(dev, vcq);
}
kfree(dev->aq_vec);
diff --git a/drivers/infiniband/hw/ionic/ionic_controlpath.c b/drivers/infiniband/hw/ionic/ionic_controlpath.c
index 37f71fb43811..57103c1a464d 100644
--- a/drivers/infiniband/hw/ionic/ionic_controlpath.c
+++ b/drivers/infiniband/hw/ionic/ionic_controlpath.c
@@ -79,12 +79,10 @@ int ionic_create_cq_common(struct ionic_vcq *vcq,
struct ionic_ctx *ctx,
struct ib_udata *udata,
struct ionic_qdesc *req_cq,
- __u32 *resp_cqid,
int udma_idx)
{
struct ionic_ibdev *dev = to_ionic_ibdev(vcq->ibcq.device);
struct ionic_cq *cq = &vcq->cq[udma_idx];
- void *entry;
int rc;
cq->vcq = vcq;
@@ -94,9 +92,11 @@ int ionic_create_cq_common(struct ionic_vcq *vcq,
goto err_args;
}
- rc = ionic_get_cqid(dev, &cq->cqid, udma_idx);
- if (rc)
- goto err_args;
+ if (!ionic_fw_has_qid_alloc(dev, IONIC_LIF_RDMA_ALLOC_QID_CQ)) {
+ rc = ionic_get_cqid(dev, &cq->cqid, udma_idx);
+ if (rc)
+ goto err_args;
+ }
cq->eqid = ionic_get_eqid(dev, attr->comp_vector, udma_idx);
@@ -122,8 +122,6 @@ int ionic_create_cq_common(struct ionic_vcq *vcq,
cq->q.mask = req_cq->mask;
cq->q.depth_log2 = req_cq->depth_log2;
cq->q.stride_log2 = req_cq->stride_log2;
-
- *resp_cqid = cq->cqid;
} else {
rc = ionic_queue_init(&cq->q, dev->lif_cfg.hwdev,
attr->cqe + IONIC_CQ_GRACE,
@@ -131,7 +129,6 @@ int ionic_create_cq_common(struct ionic_vcq *vcq,
if (rc)
goto err_q_init;
- ionic_queue_dbell_init(&cq->q, cq->cqid);
cq->color = true;
cq->credit = cq->q.mask;
}
@@ -143,20 +140,8 @@ int ionic_create_cq_common(struct ionic_vcq *vcq,
init_completion(&cq->cq_rel_comp);
kref_init(&cq->cq_kref);
- entry = xa_store_irq(&dev->cq_tbl, cq->cqid, cq, GFP_KERNEL);
- if (entry) {
- if (!xa_is_err(entry))
- rc = -EINVAL;
- else
- rc = xa_err(entry);
-
- goto err_xa;
- }
-
return 0;
-err_xa:
- ionic_pgtbl_unbuf(dev, buf);
err_pgtbl_init:
if (!udata)
ionic_queue_destroy(&cq->q, dev->lif_cfg.hwdev);
@@ -164,14 +149,30 @@ int ionic_create_cq_common(struct ionic_vcq *vcq,
if (cq->umem)
ib_umem_release(cq->umem);
err_qdesc:
- ionic_put_cqid(dev, cq->cqid);
+ if (!ionic_fw_has_qid_alloc(dev, IONIC_LIF_RDMA_ALLOC_QID_CQ))
+ ionic_put_cqid(dev, cq->cqid);
err_args:
cq->vcq = NULL;
return rc;
}
-void ionic_destroy_cq_common(struct ionic_ibdev *dev, struct ionic_cq *cq)
+int ionic_post_create_cq_cmd(struct ionic_cq *cq,
+ struct ionic_tbl_buf *buf,
+ struct ib_udata *udata,
+ __u32 *resp_cqid)
+{
+ struct ionic_ibdev *dev = to_ionic_ibdev(cq->vcq->ibcq.device);
+
+ if (udata && resp_cqid)
+ *resp_cqid = cq->cqid;
+ else
+ ionic_queue_dbell_init(&cq->q, cq->cqid);
+
+ return xa_insert_irq(&dev->cq_tbl, cq->cqid, cq, GFP_KERNEL);
+}
+
+void ionic_pre_destroy_cq_cmd(struct ionic_ibdev *dev, struct ionic_cq *cq)
{
if (!cq->vcq)
return;
@@ -180,13 +181,20 @@ void ionic_destroy_cq_common(struct ionic_ibdev *dev, struct ionic_cq *cq)
kref_put(&cq->cq_kref, ionic_cq_complete);
wait_for_completion(&cq->cq_rel_comp);
+}
+
+void ionic_destroy_cq_common(struct ionic_ibdev *dev, struct ionic_cq *cq)
+{
+ if (!cq->vcq)
+ return;
if (cq->umem)
ib_umem_release(cq->umem);
else
ionic_queue_destroy(&cq->q, dev->lif_cfg.hwdev);
- ionic_put_cqid(dev, cq->cqid);
+ if (!ionic_fw_has_qid_alloc(dev, IONIC_LIF_RDMA_ALLOC_QID_CQ))
+ ionic_put_cqid(dev, cq->cqid);
cq->vcq = NULL;
}
@@ -1222,8 +1230,11 @@ int ionic_dealloc_mw(struct ib_mw *ibmw)
static int ionic_create_cq_cmd(struct ionic_ibdev *dev,
struct ionic_ctx *ctx,
struct ionic_cq *cq,
- struct ionic_tbl_buf *buf)
+ struct ionic_tbl_buf *buf,
+ int udma_mask,
+ int *out_udma_idx)
{
+ struct ionic_admin_create_cq_resp *resp_buf;
const u16 dbid = ionic_ctx_dbid(dev, ctx);
struct ionic_admin_wr wr = {
.work = COMPLETION_INITIALIZER_ONSTACK(wr.work),
@@ -1243,13 +1254,55 @@ static int ionic_create_cq_cmd(struct ionic_ibdev *dev,
}
}
};
+ dma_addr_t resp_buf_dma;
+ int rc;
if (dev->lif_cfg.admin_opcodes <= IONIC_V1_ADMIN_CREATE_CQ)
return -EBADRQC;
+ if (!ionic_fw_has_qid_alloc(dev, IONIC_LIF_RDMA_ALLOC_QID_CQ)) {
+ ionic_admin_post(dev, &wr);
+ return ionic_admin_wait(dev, &wr, 0);
+ }
+
+ resp_buf = kzalloc_obj(*resp_buf);
+ if (!resp_buf)
+ return -ENOMEM;
+
+ resp_buf_dma = dma_map_single(dev->lif_cfg.hwdev, resp_buf,
+ sizeof(*resp_buf),
+ DMA_FROM_DEVICE);
+
+ rc = dma_mapping_error(dev->lif_cfg.hwdev, resp_buf_dma);
+ if (rc)
+ goto err_dma;
+
+ wr.wqe.len = cpu_to_le16(IONIC_ADMIN_CREATE_CQ_IN_V2_LEN);
+ wr.wqe.cmd.create_cq.udma_mask = udma_mask;
+ wr.wqe.cmd.create_cq.resp_dma_addr = cpu_to_le64(resp_buf_dma);
+ wr.wqe.cmd.create_cq.resp_buf_len = cpu_to_le32(IONIC_ADMIN_CREATE_CQ_OUT_V1_LEN);
+
ionic_admin_post(dev, &wr);
+ rc = ionic_admin_wait(dev, &wr, 0);
+ if (rc)
+ goto err_admin;
- return ionic_admin_wait(dev, &wr, 0);
+ if (be32_to_cpu(wr.cqe.status_length) < IONIC_ADMIN_CREATE_CQ_OUT_V1_LEN) {
+ rc = -EOPNOTSUPP;
+ goto err_admin;
+ }
+
+ cq->cqid = le32_to_cpu(resp_buf->id);
+ if (out_udma_idx)
+ *out_udma_idx = resp_buf->udma_idx;
+
+err_admin:
+ dma_unmap_single(dev->lif_cfg.hwdev, resp_buf_dma, sizeof(*resp_buf),
+ DMA_FROM_DEVICE);
+err_dma:
+ kfree(resp_buf);
+
+ return rc;
}
static int ionic_destroy_cq_cmd(struct ionic_ibdev *dev, u32 cqid)
@@ -1308,16 +1361,21 @@ int ionic_create_cq(struct ib_cq *ibcq, const struct ib_cq_init_attr *attr,
rc = ionic_create_cq_common(vcq, &buf, attr, ctx, udata,
&req.cq[udma_idx],
- &resp.cqid[udma_idx],
udma_idx);
if (rc)
goto err_init;
- rc = ionic_create_cq_cmd(dev, ctx, &vcq->cq[udma_idx], &buf);
+ rc = ionic_create_cq_cmd(dev, ctx, &vcq->cq[udma_idx], &buf,
+ udma_idx, NULL);
if (rc)
goto err_cmd;
ionic_pgtbl_unbuf(dev, &buf);
+
+ rc = ionic_post_create_cq_cmd(&vcq->cq[udma_idx], &buf, udata,
+ &resp.cqid[udma_idx]);
+ if (rc)
+ goto err_post;
}
vcq->ibcq.cqe = attr->cqe;
@@ -1337,6 +1395,8 @@ int ionic_create_cq(struct ib_cq *ibcq, const struct ib_cq_init_attr *attr,
--udma_idx;
if (!(vcq->udma_mask & BIT(udma_idx)))
continue;
+ ionic_pre_destroy_cq_cmd(dev, &vcq->cq[udma_idx]);
+err_post:
ionic_destroy_cq_cmd(dev, vcq->cq[udma_idx].cqid);
err_cmd:
ionic_pgtbl_unbuf(dev, &buf);
@@ -1364,6 +1424,13 @@ int ionic_destroy_cq(struct ib_cq *ibcq, struct ib_udata *udata)
if (!(vcq->udma_mask & BIT(udma_idx)))
continue;
+ /*
+ * Untrack the CQ before releasing its hardware ID below, so a
+ * concurrent create that gets the same ID reused by firmware
+ * cannot have its fresh XArray entry erased by this destroy.
+ */
+ ionic_pre_destroy_cq_cmd(dev, &vcq->cq[udma_idx]);
+
rc_tmp = ionic_destroy_cq_cmd(dev, vcq->cq[udma_idx].cqid);
if (rc_tmp) {
if (!rc)
diff --git a/drivers/infiniband/hw/ionic/ionic_fw.h b/drivers/infiniband/hw/ionic/ionic_fw.h
index d0a5bce85ed8..7a02e799de2b 100644
--- a/drivers/infiniband/hw/ionic/ionic_fw.h
+++ b/drivers/infiniband/hw/ionic/ionic_fw.h
@@ -746,11 +746,22 @@ struct ionic_admin_create_cq {
__le32 map_count;
__le64 dma_addr;
__le16 dbid_flags;
+ __u8 udma_mask;
+ __le32 resp_buf_len;
+ __le64 resp_dma_addr;
} __packed;
#define IONIC_ADMIN_CREATE_CQ_IN_V1_LEN 34
-static_assert(sizeof(struct ionic_admin_create_cq) ==
- IONIC_ADMIN_CREATE_CQ_IN_V1_LEN);
+#define IONIC_ADMIN_CREATE_CQ_IN_V2_LEN 47
+static_assert(sizeof(struct ionic_admin_create_cq) == IONIC_ADMIN_CREATE_CQ_IN_V2_LEN);
+
+struct ionic_admin_create_cq_resp {
+ __le32 id;
+ __u8 udma_idx;
+} __packed;
+
+#define IONIC_ADMIN_CREATE_CQ_OUT_V1_LEN 5
+static_assert(sizeof(struct ionic_admin_create_cq_resp) == IONIC_ADMIN_CREATE_CQ_OUT_V1_LEN);
struct ionic_admin_destroy_cq {
__le32 cq_id;
diff --git a/drivers/infiniband/hw/ionic/ionic_ibdev.h b/drivers/infiniband/hw/ionic/ionic_ibdev.h
index 32b6a8a45fa2..d7358e63f678 100644
--- a/drivers/infiniband/hw/ionic/ionic_ibdev.h
+++ b/drivers/infiniband/hw/ionic/ionic_ibdev.h
@@ -438,6 +438,12 @@ static inline void ionic_cq_complete(struct kref *kref)
complete(&cq->cq_rel_comp);
}
+static inline bool ionic_fw_has_qid_alloc(struct ionic_ibdev *dev,
+ enum ionic_lif_rdma_alloc_qid qtype)
+{
+ return dev->lif_cfg.alloc_qid_cap & qtype;
+}
+
/* ionic_admin.c */
extern struct workqueue_struct *ionic_evt_workq;
void ionic_admin_post(struct ionic_ibdev *dev, struct ionic_admin_wr *wr);
@@ -457,8 +463,12 @@ int ionic_create_cq_common(struct ionic_vcq *vcq,
struct ionic_ctx *ctx,
struct ib_udata *udata,
struct ionic_qdesc *req_cq,
- __u32 *resp_cqid,
int udma_idx);
+int ionic_post_create_cq_cmd(struct ionic_cq *cq,
+ struct ionic_tbl_buf *buf,
+ struct ib_udata *udata,
+ __u32 *resp_cqid);
+void ionic_pre_destroy_cq_cmd(struct ionic_ibdev *dev, struct ionic_cq *cq);
void ionic_destroy_cq_common(struct ionic_ibdev *dev, struct ionic_cq *cq);
void ionic_flush_qp(struct ionic_ibdev *dev, struct ionic_qp *qp);
void ionic_notify_flush_cq(struct ionic_cq *cq);
diff --git a/drivers/infiniband/hw/ionic/ionic_lif_cfg.c b/drivers/infiniband/hw/ionic/ionic_lif_cfg.c
index 1e37bd09490f..c381bda4360d 100644
--- a/drivers/infiniband/hw/ionic/ionic_lif_cfg.c
+++ b/drivers/infiniband/hw/ionic/ionic_lif_cfg.c
@@ -93,6 +93,7 @@ void ionic_fill_lif_cfg(struct ionic_lif *lif, struct ionic_lif_cfg *cfg)
!!(lif->qtype_info[IONIC_QTYPE_TXQ].features & IONIC_QIDENT_F_EXPDB);
cfg->rq_expdb =
!!(lif->qtype_info[IONIC_QTYPE_RXQ].features & IONIC_QIDENT_F_EXPDB);
+ cfg->alloc_qid_cap = ident->rdma.alloc_qid_cap;
}
struct net_device *ionic_lif_netdev(struct ionic_lif *lif)
diff --git a/drivers/infiniband/hw/ionic/ionic_lif_cfg.h b/drivers/infiniband/hw/ionic/ionic_lif_cfg.h
index d7835ac27896..68aec06908ca 100644
--- a/drivers/infiniband/hw/ionic/ionic_lif_cfg.h
+++ b/drivers/infiniband/hw/ionic/ionic_lif_cfg.h
@@ -58,6 +58,7 @@ struct ionic_lif_cfg {
bool rq_expdb;
u8 expdb_mask;
u8 rcq_sign_bit;
+ u8 alloc_qid_cap;
};
void ionic_fill_lif_cfg(struct ionic_lif *lif, struct ionic_lif_cfg *cfg);
--
2.43.0
next prev parent reply other threads:[~2026-09-08 9:09 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-08 9:07 [for-next v1 0/5] RDMA/ionic: add SRQ support and firmware assigned CQ and SRQ IDs Abhijit Gangurde
2026-09-08 9:07 ` [for-next v1 1/5] net: ionic: Fetch qid allocation and SRQ capability from firmware Abhijit Gangurde
2026-09-09 9:10 ` sashiko-bot
2026-09-08 9:07 ` Abhijit Gangurde [this message]
2026-09-09 9:10 ` [for-next v1 2/5] RDMA/ionic: support firmware-assigned CQ IDs sashiko-bot
2026-09-08 9:07 ` [for-next v1 3/5] RDMA/ionic: segregate rq related fields from ionic_qp into a new ionic_rq struct Abhijit Gangurde
2026-09-09 9:10 ` sashiko-bot
2026-09-08 9:08 ` [for-next v1 4/5] RDMA/ionic: add Shared receive queue (SRQ) support Abhijit Gangurde
2026-09-09 9:10 ` sashiko-bot
2026-09-08 9:08 ` [for-next v1 5/5] RDMA/ionic: implement SRQ event handling support Abhijit Gangurde
2026-09-09 9:10 ` sashiko-bot
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260908090802.152142-3-abhijit.gangurde@amd.com \
--to=abhijit.gangurde@amd.com \
--cc=allen.hubbe@amd.com \
--cc=andrew+netdev@lunn.ch \
--cc=brett.creeley@amd.com \
--cc=davem@davemloft.net \
--cc=edumazet@google.com \
--cc=jgg@ziepe.ca \
--cc=kuba@kernel.org \
--cc=leon@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-rdma@vger.kernel.org \
--cc=netdev@vger.kernel.org \
--cc=nikhil.agarwal@amd.com \
--cc=pabeni@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox