[PATCH rdma-next v2 3/5] RDMA/mana_ib: Revise UD receive posting with GDMA_WR_IB_SGL
From: Konstantin Taranov
Date: Fri Sep 18 2026 - 10:25:01 EST
From: Konstantin Taranov <kotaranov@xxxxxxxxxxxxx>
Pass receive verbs SGEs directly to GDMA instead of copying them into
a small stack array. Accept the receive SGE limit, supply a dummy SGE
for zero-length requests, and ring once after each successful batch.
Introduce GDMA_WR_IB_SGL, its request union, and the wrap-aware verbs
SGE writer together with their first consumer. These shared GDMA pieces
must precede the later extended-WQE patch so this receive path does not
depend on definitions or encoding support introduced after it.
Address verbs SGEs by ring offset so both scattered-page boundaries and
ring wrap preserve the local kernel baseline's non-contiguous buffers.
Signed-off-by: Konstantin Taranov <kotaranov@xxxxxxxxxxxxx>
---
drivers/infiniband/hw/mana/wr.c | 70 +++++++++++--------
.../net/ethernet/microsoft/mana/gdma_main.c | 23 +++++-
include/net/mana/gdma.h | 7 +-
3 files changed, 70 insertions(+), 30 deletions(-)
diff --git a/drivers/infiniband/hw/mana/wr.c b/drivers/infiniband/hw/mana/wr.c
index f25df2fad..eb671b45b 100644
--- a/drivers/infiniband/hw/mana/wr.c
+++ b/drivers/infiniband/hw/mana/wr.c
@@ -7,29 +7,30 @@
#define MAX_WR_SGL_NUM (2)
-static int mana_ib_post_recv_ud(struct mana_ib_qp *qp, const struct ib_recv_wr *wr)
+static int mana_ib_post_rq(struct mana_ib_qp *qp, const struct ib_recv_wr *wr)
{
- struct mana_ib_dev *mdev = container_of(qp->ibqp.device, struct mana_ib_dev, ib_dev);
- struct gdma_queue *queue = qp->ud_qp.queues[MANA_UD_RECV_QUEUE].kmem;
+ struct ib_sge mana_ib_dummy_sge = {.addr = 1, .length = 0, .lkey = 0};
+ struct mana_ib_queue *ib_rq = mana_qp_get_rq(qp);
struct gdma_posted_wqe_info wqe_info = {0};
- struct gdma_sge gdma_sgl[MAX_WR_SGL_NUM];
+ struct gdma_queue *queue = ib_rq->kmem;
struct gdma_wqe_request wqe_req = {0};
struct shadow_wqe_header *shadow_wqe;
- int err, i;
+ int err;
if (shadow_queue_full(&qp->shadow_rq))
return -EINVAL;
- if (wr->num_sge > MAX_WR_SGL_NUM)
+ if (wr->num_sge > MAX_RX_WQE_SGL_ENTRIES)
return -EINVAL;
- for (i = 0; i < wr->num_sge; ++i) {
- gdma_sgl[i].address = wr->sg_list[i].addr;
- gdma_sgl[i].mem_key = wr->sg_list[i].lkey;
- gdma_sgl[i].size = wr->sg_list[i].length;
- }
wqe_req.num_sge = wr->num_sge;
- wqe_req.sgl = gdma_sgl;
+ wqe_req.ib_sgl = wr->sg_list;
+ wqe_req.flags = GDMA_WR_IB_SGL;
+
+ if (wr->num_sge == 0) {
+ wqe_req.ib_sgl = &mana_ib_dummy_sge;
+ wqe_req.num_sge = 1;
+ }
err = mana_gd_post_work_request(queue, &wqe_req, &wqe_info);
if (err)
@@ -41,36 +42,49 @@ static int mana_ib_post_recv_ud(struct mana_ib_qp *qp, const struct ib_recv_wr *
shadow_wqe->wqe_size_in_bu = wqe_info.wqe_size_in_bu;
shadow_queue_advance_producer(&qp->shadow_rq);
- mana_gd_wq_ring_doorbell(mdev_to_gc(mdev), queue);
return 0;
}
-int mana_ib_post_recv(struct ib_qp *ibqp, const struct ib_recv_wr *wr,
- const struct ib_recv_wr **bad_wr)
+static int mana_ib_post_recv_ud(struct mana_ib_qp *qp, const struct ib_recv_wr *wr,
+ const struct ib_recv_wr **bad_wr)
{
- struct mana_ib_qp *qp = container_of(ibqp, struct mana_ib_qp, ibqp);
+ struct mana_ib_dev *mdev = container_of(qp->ibqp.device, struct mana_ib_dev, ib_dev);
+ struct mana_ib_queue *ib_rq = mana_qp_get_rq(qp);
+ struct gdma_queue *rq = ib_rq->kmem;
+ bool ring_rq = false;
int err = 0;
for (; wr; wr = wr->next) {
- switch (ibqp->qp_type) {
- case IB_QPT_UD:
- case IB_QPT_GSI:
- err = mana_ib_post_recv_ud(qp, wr);
- if (unlikely(err)) {
- *bad_wr = wr;
- return err;
- }
+ err = mana_ib_post_rq(qp, wr);
+ if (unlikely(err)) {
+ *bad_wr = wr;
break;
- default:
- ibdev_dbg(ibqp->device, "Posting recv wr on qp type %u is not supported\n",
- ibqp->qp_type);
- return -EINVAL;
}
+ ring_rq = true;
}
+ if (ring_rq)
+ mana_gd_wq_ring_doorbell(mdev_to_gc(mdev), rq);
+
return err;
}
+int mana_ib_post_recv(struct ib_qp *ibqp, const struct ib_recv_wr *wr,
+ const struct ib_recv_wr **bad_wr)
+{
+ struct mana_ib_qp *qp = container_of(ibqp, struct mana_ib_qp, ibqp);
+
+ switch (ibqp->qp_type) {
+ case IB_QPT_UD:
+ case IB_QPT_GSI:
+ return mana_ib_post_recv_ud(qp, wr, bad_wr);
+ default:
+ /* Unsupported QP type */
+ *bad_wr = wr;
+ return -EINVAL;
+ }
+}
+
static int mana_ib_post_send_ud_one(struct mana_ib_qp *qp, const struct ib_ud_wr *wr)
{
struct mana_ib_dev *mdev = container_of(qp->ibqp.device, struct mana_ib_dev, ib_dev);
diff --git a/drivers/net/ethernet/microsoft/mana/gdma_main.c b/drivers/net/ethernet/microsoft/mana/gdma_main.c
index f92b2d0bf..542491a6c 100644
--- a/drivers/net/ethernet/microsoft/mana/gdma_main.c
+++ b/drivers/net/ethernet/microsoft/mana/gdma_main.c
@@ -1738,6 +1738,24 @@ static void mana_gd_write_sgl(struct gdma_queue *wq, u32 sgl_offset,
memcpy(mana_gd_ring_ptr(wq, sgl_offset), address, sgl_size);
}
+static void mana_gd_write_ib_sgl(struct gdma_queue *wq, u32 sgl_offset,
+ const struct gdma_wqe_request *wqe_req)
+{
+ const struct ib_sge *sge = wqe_req->ib_sgl;
+ struct gdma_sge *gdma_sgl;
+ u32 i;
+
+ for (i = 0; i < wqe_req->num_sge; ++i, ++sge) {
+ gdma_sgl = mana_gd_ring_ptr(wq, sgl_offset);
+ gdma_sgl->address = sge->addr;
+ gdma_sgl->size = sge->length;
+ gdma_sgl->mem_key = sge->lkey;
+ sgl_offset += sizeof(*gdma_sgl);
+ if (sgl_offset == wq->queue_size)
+ sgl_offset = 0;
+ }
+}
+
int mana_gd_post_work_request(struct gdma_queue *wq,
const struct gdma_wqe_request *wqe_req,
struct gdma_posted_wqe_info *wqe_info)
@@ -1792,7 +1810,10 @@ int mana_gd_post_work_request(struct gdma_queue *wq,
if (sgl_offset >= wq->queue_size)
sgl_offset -= wq->queue_size;
- mana_gd_write_sgl(wq, sgl_offset, wqe_req);
+ if (wqe_req->flags & GDMA_WR_IB_SGL)
+ mana_gd_write_ib_sgl(wq, sgl_offset, wqe_req);
+ else
+ mana_gd_write_sgl(wq, sgl_offset, wqe_req);
wq->head += wqe_size / GDMA_WQE_BU_SIZE;
diff --git a/include/net/mana/gdma.h b/include/net/mana/gdma.h
index 06af65d50..8ccbe2d57 100644
--- a/include/net/mana/gdma.h
+++ b/include/net/mana/gdma.h
@@ -6,6 +6,7 @@
#include <linux/dma-mapping.h>
#include <linux/netdevice.h>
+#include <rdma/ib_verbs.h>
#include "shm_channel.h"
@@ -54,6 +55,7 @@ enum gdma_work_request_flags {
GDMA_WR_NONE = 0,
GDMA_WR_OOB_IN_SGL = BIT(0),
GDMA_WR_PAD_BY_SGE0 = BIT(1),
+ GDMA_WR_IB_SGL = BIT(2),
};
enum gdma_eqe_type {
@@ -212,7 +214,10 @@ struct gdma_sge {
}; /* HW DATA */
struct gdma_wqe_request {
- struct gdma_sge *sgl;
+ union {
+ struct gdma_sge *sgl;
+ struct ib_sge *ib_sgl;
+ };
u32 num_sge;
u32 inline_oob_size;
--
2.43.0