Netdev List
 help / color / mirror / Atom feed
* [PATCH net-next v2] net: devmem: allow peer-to-peer dma-buf attach for bindings
@ 2026-10-13 21:09 Erfan Sharafzadeh
  0 siblings, 0 replies; only message in thread
From: Erfan Sharafzadeh @ 2026-10-13 21:09 UTC (permalink / raw)
  To: netdev
  Cc: davem, edumazet, kuba, pabeni, horms, almasrymina, kaiyuanz,
	willemb, asml.silence, sdf, bobbyeshleman

net_devmem_bind_dmabuf() uses dma_buf_attach(), a static attachment
with peer2peer false. Exporters must then keep the buffer reachable
without P2P; amdgpu does so by placing it in GTT (system memory), so a
device memory binding silently ends up in host memory.

Use dma_buf_dynamic_attach() with allow_peer2peer set, so an exporter
that can do P2P to the device keeps the buffer in device memory.
Dynamic attachments are not pinned on map, and devmem cannot handle the
buffer moving, so:

- pin it with dma_buf_pin() before mapping, which keeps it in place for
  the lifetime of the binding, as before;
- wait for the exporter's kernel fences after mapping, interruptibly,
  as the core does for static attachments.

This follows the pinned RDMA umem path, including its limits: the
binding cannot be revoked by the exporter, and once a P2P binding has
pinned a buffer in device memory, a later attachment to the same buffer
that cannot do P2P may fail to pin it. Exporters that cannot do P2P to
the device place the buffer as before. RX and TX bindings both go
through this function.

Signed-off-by: Erfan Sharafzadeh <erfansh@meta.com>
---
v2:
- Target net-next and drop the Fixes: tag. This adds P2P placement
  rather than fixing incorrect behaviour, and it relies on recent
  dma-buf core changes, so it should not go to stable.
- Wait for the exporter's fences interruptibly, as the core does.
- Describe the revocation and mixed-attachment limits in the commit
  message.

v1: https://lore.kernel.org/netdev/20261012170754.669462-1-erfansh@meta.com/

 net/core/devmem.c | 47 +++++++++++++++++++++++++++++++++++++----------
 1 file changed, 37 insertions(+), 10 deletions(-)

diff --git a/net/core/devmem.c b/net/core/devmem.c
index 95d714d46c6f..fd1b72744564 100644
--- a/net/core/devmem.c
+++ b/net/core/devmem.c
@@ -8,6 +8,7 @@
  */
 
 #include <linux/dma-buf.h>
+#include <linux/dma-resv.h>
 #include <linux/mm.h>
 #include <linux/netdevice.h>
 #include <linux/types.h>
@@ -50,6 +51,10 @@ static void net_iov_free_push(struct net_iov_area *area,
 	freelist[(*free_count)++] = net_iov_idx(niov);
 }
 
+static const struct dma_buf_attach_ops net_devmem_dmabuf_attach_ops = {
+	.allow_peer2peer = true,
+};
+
 static void net_devmem_dmabuf_binding_release(struct percpu_ref *ref)
 {
 	struct net_devmem_dmabuf_binding *binding =
@@ -69,8 +74,11 @@ void __net_devmem_dmabuf_binding_free(struct work_struct *wq)
 		     binding->area.num_niovs, binding->free_count);
 
 	kvfree(binding->area.niovs);
-	dma_buf_unmap_attachment_unlocked(binding->attachment, binding->sgt,
-					  binding->direction);
+	dma_resv_lock(binding->dmabuf->resv, NULL);
+	dma_buf_unmap_attachment(binding->attachment, binding->sgt,
+				 binding->direction);
+	dma_buf_unpin(binding->attachment);
+	dma_resv_unlock(binding->dmabuf->resv);
 	dma_buf_detach(binding->dmabuf, binding->attachment);
 	dma_buf_put(binding->dmabuf);
 	xa_destroy(&binding->bound_rxqs);
@@ -190,7 +198,7 @@ net_devmem_bind_dmabuf(struct net_device *dev, void *vdev,
 	unsigned int sg_idx;
 	size_t niov_idx;
 	size_t i;
-	int err;
+	long err;
 
 	if (!dma_dev) {
 		NL_SET_ERR_MSG(extack, "Device doesn't support DMA");
@@ -226,19 +234,35 @@ net_devmem_bind_dmabuf(struct net_device *dev, void *vdev,
 	binding->dmabuf = dmabuf;
 	binding->direction = direction;
 
-	binding->attachment = dma_buf_attach(binding->dmabuf, dma_dev);
+	binding->attachment =
+		dma_buf_dynamic_attach(binding->dmabuf, dma_dev,
+				       &net_devmem_dmabuf_attach_ops, binding);
 	if (IS_ERR(binding->attachment)) {
 		err = PTR_ERR(binding->attachment);
 		NL_SET_ERR_MSG(extack, "Failed to bind dmabuf to device");
 		goto err_exit_ref;
 	}
 
-	binding->sgt = dma_buf_map_attachment_unlocked(binding->attachment,
-						       direction);
+	dma_resv_lock(dmabuf->resv, NULL);
+	err = dma_buf_pin(binding->attachment);
+	if (err) {
+		NL_SET_ERR_MSG(extack, "Failed to pin dmabuf");
+		goto err_unlock;
+	}
+
+	binding->sgt = dma_buf_map_attachment(binding->attachment, direction);
 	if (IS_ERR(binding->sgt)) {
 		err = PTR_ERR(binding->sgt);
 		NL_SET_ERR_MSG(extack, "Failed to map dmabuf attachment");
-		goto err_detach;
+		goto err_unpin;
+	}
+	dma_resv_unlock(dmabuf->resv);
+
+	err = dma_resv_wait_timeout(dmabuf->resv, DMA_RESV_USAGE_KERNEL, true,
+				    MAX_SCHEDULE_TIMEOUT);
+	if (err < 0) {
+		NL_SET_ERR_MSG(extack, "Failed to wait for dmabuf fences");
+		goto err_unmap;
 	}
 
 	if (!IS_ALIGNED(dmabuf->size, niov_size)) {
@@ -332,9 +356,12 @@ net_devmem_bind_dmabuf(struct net_device *dev, void *vdev,
 	kvfree(binding->freelist);
 	kvfree(binding->tx_vec);
 err_unmap:
-	dma_buf_unmap_attachment_unlocked(binding->attachment, binding->sgt,
-					  direction);
-err_detach:
+	dma_resv_lock(dmabuf->resv, NULL);
+	dma_buf_unmap_attachment(binding->attachment, binding->sgt, direction);
+err_unpin:
+	dma_buf_unpin(binding->attachment);
+err_unlock:
+	dma_resv_unlock(dmabuf->resv);
 	dma_buf_detach(dmabuf, binding->attachment);
 err_exit_ref:
 	percpu_ref_exit(&binding->ref);
-- 
2.53.0-Meta


^ permalink raw reply related	[flat|nested] only message in thread

only message in thread, other threads:[~2026-10-13 21:10 UTC | newest]

Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-13 21:09 [PATCH net-next v2] net: devmem: allow peer-to-peer dma-buf attach for bindings Erfan Sharafzadeh

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox