Skip to content

Commit 297e4c9

Browse files
committed
RDMA/efa: Add CQ with external memory support
JIRA: https://issues.redhat.com/browse/RHEL-109942 commit 9fb3dd8 Author: Michael Margolin <mrgolin@amazon.com> Date: Tue Jul 8 20:23:08 2025 +0000 RDMA/efa: Add CQ with external memory support Add an option to create CQ using external memory instead of allocating in the driver. The memory can be passed from userspace by dmabuf fd and an offset or a VA. One of the possible usages is creating CQs that reside in accelerator memory, allowing low latency asynchronous direct polling from the accelerator device. Add a capability bit to reflect on the feature support. Reviewed-by: Daniel Kranzdorf <dkkranzd@amazon.com> Reviewed-by: Yonatan Nachum <ynachum@amazon.com> Signed-off-by: Michael Margolin <mrgolin@amazon.com> Link: https://patch.msgid.link/20250708202308.24783-4-mrgolin@amazon.com Reviewed-by: Jason Gunthorpe <jgg@nvidia.com> Signed-off-by: Leon Romanovsky <leon@kernel.org> Signed-off-by: Kamal Heib <kheib@redhat.com>
1 parent 1756b67 commit 297e4c9

File tree

4 files changed

+53
-15
lines changed

4 files changed

+53
-15
lines changed

drivers/infiniband/hw/efa/efa.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ struct efa_cq {
107107
u16 cq_idx;
108108
/* NULL when no interrupts requested */
109109
struct efa_eq *eq;
110+
struct ib_umem *umem;
110111
};
111112

112113
struct efa_qp {
@@ -162,6 +163,8 @@ int efa_create_qp(struct ib_qp *ibqp, struct ib_qp_init_attr *init_attr,
162163
int efa_destroy_cq(struct ib_cq *ibcq, struct ib_udata *udata);
163164
int efa_create_cq(struct ib_cq *ibcq, const struct ib_cq_init_attr *attr,
164165
struct uverbs_attr_bundle *attrs);
166+
int efa_create_cq_umem(struct ib_cq *ibcq, const struct ib_cq_init_attr *attr,
167+
struct ib_umem *umem, struct uverbs_attr_bundle *attrs);
165168
struct ib_mr *efa_reg_mr(struct ib_pd *ibpd, u64 start, u64 length,
166169
u64 virt_addr, int access_flags,
167170
struct ib_dmah *dmah,

drivers/infiniband/hw/efa/efa_main.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -372,6 +372,7 @@ static const struct ib_device_ops efa_dev_ops = {
372372
.alloc_pd = efa_alloc_pd,
373373
.alloc_ucontext = efa_alloc_ucontext,
374374
.create_cq = efa_create_cq,
375+
.create_cq_umem = efa_create_cq_umem,
375376
.create_qp = efa_create_qp,
376377
.create_user_ah = efa_create_ah,
377378
.dealloc_pd = efa_dealloc_pd,

drivers/infiniband/hw/efa/efa_verbs.c

Lines changed: 47 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,7 @@ int efa_query_device(struct ib_device *ibdev,
249249
resp.max_rdma_size = dev_attr->max_rdma_size;
250250

251251
resp.device_caps |= EFA_QUERY_DEVICE_CAPS_CQ_WITH_SGID;
252+
resp.device_caps |= EFA_QUERY_DEVICE_CAPS_CQ_WITH_EXT_MEM;
252253
if (EFA_DEV_CAP(dev, RDMA_READ))
253254
resp.device_caps |= EFA_QUERY_DEVICE_CAPS_RDMA_READ;
254255

@@ -1082,8 +1083,11 @@ int efa_destroy_cq(struct ib_cq *ibcq, struct ib_udata *udata)
10821083
xa_erase(&dev->cqs_xa, cq->cq_idx);
10831084
synchronize_irq(cq->eq->irq.irqn);
10841085
}
1085-
efa_free_mapped(dev, cq->cpu_addr, cq->dma_addr, cq->size,
1086-
DMA_FROM_DEVICE);
1086+
1087+
if (cq->umem)
1088+
ib_umem_release(cq->umem);
1089+
else
1090+
efa_free_mapped(dev, cq->cpu_addr, cq->dma_addr, cq->size, DMA_FROM_DEVICE);
10871091
return 0;
10881092
}
10891093

@@ -1122,8 +1126,8 @@ static int cq_mmap_entries_setup(struct efa_dev *dev, struct efa_cq *cq,
11221126
return 0;
11231127
}
11241128

1125-
int efa_create_cq(struct ib_cq *ibcq, const struct ib_cq_init_attr *attr,
1126-
struct uverbs_attr_bundle *attrs)
1129+
int efa_create_cq_umem(struct ib_cq *ibcq, const struct ib_cq_init_attr *attr,
1130+
struct ib_umem *umem, struct uverbs_attr_bundle *attrs)
11271131
{
11281132
struct ib_udata *udata = &attrs->driver_udata;
11291133
struct efa_ucontext *ucontext = rdma_udata_to_drv_context(
@@ -1202,11 +1206,30 @@ int efa_create_cq(struct ib_cq *ibcq, const struct ib_cq_init_attr *attr,
12021206

12031207
cq->ucontext = ucontext;
12041208
cq->size = PAGE_ALIGN(cmd.cq_entry_size * entries * cmd.num_sub_cqs);
1205-
cq->cpu_addr = efa_zalloc_mapped(dev, &cq->dma_addr, cq->size,
1206-
DMA_FROM_DEVICE);
1207-
if (!cq->cpu_addr) {
1208-
err = -ENOMEM;
1209-
goto err_out;
1209+
1210+
if (umem) {
1211+
if (umem->length < cq->size) {
1212+
ibdev_dbg(&dev->ibdev, "External memory too small\n");
1213+
err = -EINVAL;
1214+
goto err_free_mem;
1215+
}
1216+
1217+
if (!ib_umem_is_contiguous(umem)) {
1218+
ibdev_dbg(&dev->ibdev, "Non contiguous CQ unsupported\n");
1219+
err = -EINVAL;
1220+
goto err_free_mem;
1221+
}
1222+
1223+
cq->cpu_addr = NULL;
1224+
cq->dma_addr = ib_umem_start_dma_addr(umem);
1225+
cq->umem = umem;
1226+
} else {
1227+
cq->cpu_addr = efa_zalloc_mapped(dev, &cq->dma_addr, cq->size,
1228+
DMA_FROM_DEVICE);
1229+
if (!cq->cpu_addr) {
1230+
err = -ENOMEM;
1231+
goto err_out;
1232+
}
12101233
}
12111234

12121235
params.uarn = cq->ucontext->uarn;
@@ -1223,15 +1246,17 @@ int efa_create_cq(struct ib_cq *ibcq, const struct ib_cq_init_attr *attr,
12231246

12241247
err = efa_com_create_cq(&dev->edev, &params, &result);
12251248
if (err)
1226-
goto err_free_mapped;
1249+
goto err_free_mem;
12271250

12281251
resp.db_off = result.db_off;
12291252
resp.cq_idx = result.cq_idx;
12301253
cq->cq_idx = result.cq_idx;
12311254
cq->ibcq.cqe = result.actual_depth;
12321255
WARN_ON_ONCE(entries != result.actual_depth);
12331256

1234-
err = cq_mmap_entries_setup(dev, cq, &resp, result.db_valid);
1257+
if (!umem)
1258+
err = cq_mmap_entries_setup(dev, cq, &resp, result.db_valid);
1259+
12351260
if (err) {
12361261
ibdev_dbg(ibdev, "Could not setup cq[%u] mmap entries\n",
12371262
cq->cq_idx);
@@ -1269,15 +1294,23 @@ int efa_create_cq(struct ib_cq *ibcq, const struct ib_cq_init_attr *attr,
12691294
efa_cq_user_mmap_entries_remove(cq);
12701295
err_destroy_cq:
12711296
efa_destroy_cq_idx(dev, cq->cq_idx);
1272-
err_free_mapped:
1273-
efa_free_mapped(dev, cq->cpu_addr, cq->dma_addr, cq->size,
1274-
DMA_FROM_DEVICE);
1297+
err_free_mem:
1298+
if (umem)
1299+
ib_umem_release(umem);
1300+
else
1301+
efa_free_mapped(dev, cq->cpu_addr, cq->dma_addr, cq->size, DMA_FROM_DEVICE);
12751302

12761303
err_out:
12771304
atomic64_inc(&dev->stats.create_cq_err);
12781305
return err;
12791306
}
12801307

1308+
int efa_create_cq(struct ib_cq *ibcq, const struct ib_cq_init_attr *attr,
1309+
struct uverbs_attr_bundle *attrs)
1310+
{
1311+
return efa_create_cq_umem(ibcq, attr, NULL, attrs);
1312+
}
1313+
12811314
static int umem_to_page_list(struct efa_dev *dev,
12821315
struct ib_umem *umem,
12831316
u64 *page_list,

include/uapi/rdma/efa-abi.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-2-Clause) */
22
/*
3-
* Copyright 2018-2024 Amazon.com, Inc. or its affiliates. All rights reserved.
3+
* Copyright 2018-2025 Amazon.com, Inc. or its affiliates. All rights reserved.
44
*/
55

66
#ifndef EFA_ABI_USER_H
@@ -131,6 +131,7 @@ enum {
131131
EFA_QUERY_DEVICE_CAPS_DATA_POLLING_128 = 1 << 4,
132132
EFA_QUERY_DEVICE_CAPS_RDMA_WRITE = 1 << 5,
133133
EFA_QUERY_DEVICE_CAPS_UNSOLICITED_WRITE_RECV = 1 << 6,
134+
EFA_QUERY_DEVICE_CAPS_CQ_WITH_EXT_MEM = 1 << 7,
134135
};
135136

136137
struct efa_ibv_ex_query_device_resp {

0 commit comments

Comments
 (0)