Thread (7 messages) 7 messages, 4 authors, 2025-07-10

Re: [PATCH net] net: Allow non parent devices to be used for ZC DMA

From: Mina Almasry <hidden>
Date: 2025-07-09 22:56:30
Also in: io-uring, lkml

On Wed, Jul 9, 2025 at 12:54 PM Dragos Tatulea [off-list ref] wrote:
On Wed, Jul 09, 2025 at 12:29:22PM -0700, Mina Almasry wrote:
quoted
On Wed, Jul 9, 2025 at 5:46 AM Dragos Tatulea [off-list ref] wrote:
quoted
For zerocopy (io_uring, devmem), there is an assumption that the
parent device can do DMA. However that is not always the case:
ScalableFunction devices have the DMA device in the grandparent.

This patch adds a helper for getting the DMA device for a netdev from
its parent or grandparent if necessary. The NULL case is handled in the
callers.

devmem and io_uring are updated accordingly to use this helper instead
of directly using the parent.

Signed-off-by: Dragos Tatulea <dtatulea@nvidia.com>
Fixes: 170aafe35cb9 ("netdev: support binding dma-buf to netdevice")
nit: This doesn't seem like a fix? The current code supports all
devices that are not SF well enough, right? And in the case of SF
devices, I expect net_devmem_bind_dmabuf() to fail gracefully as the
dma mapping of a device that doesn't support it, I think, would fail
gracefully. So to me this seems like an improvement rather than a bug
fix.
dma_buf_map_attachment_unlocked() will return a sg_table with 0 nents.
That is graceful. However this will result in page_pools that will
always be returning errors further down the line which is very confusing
regarding the motives that caused it.

I am also fine to not make it a fix btw. Especially since the mlx5
devmem code was just accepted.
If you submit another version I'd rather it be a non-fix, especially
since applying the io_uring hunk will be challenging when backporting
this patch, but I assume hunk can be dropped while backporting, so I'm
fine either way.
quoted
quoted
Reviewed-by: Tariq Toukan <tariqt@nvidia.com>
---
Changes in v1:
- Upgraded from RFC status.
- Dropped driver specific bits for generic solution.
- Implemented single patch as a fix as requested in RFC.
- Handling of multi-PF netdevs will be handled in a subsequent patch
  series.

RFC: https://lore.kernel.org/all/20250702172433.1738947-2-dtatulea@nvidia.com/ (local)
---
 include/linux/netdevice.h | 14 ++++++++++++++
 io_uring/zcrx.c           |  2 +-
 net/core/devmem.c         | 10 +++++++++-
 3 files changed, 24 insertions(+), 2 deletions(-)
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 5847c20994d3..1cbde7193c4d 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -5560,4 +5560,18 @@ extern struct net_device *blackhole_netdev;
                atomic_long_add((VAL), &(DEV)->stats.__##FIELD)
 #define DEV_STATS_READ(DEV, FIELD) atomic_long_read(&(DEV)->stats.__##FIELD)

+static inline struct device *netdev_get_dma_dev(const struct net_device *dev)
+{
+       struct device *dma_dev = dev->dev.parent;
+
+       if (!dma_dev)
+               return NULL;
+
+       /* Some devices (e.g. SFs) have the dma device as a grandparent. */
+       if (!dma_dev->dma_mask)
I was able to confirm that !dev->dma_mask means "this device doesn't
support dma". Multiple existing places in the code seem to use this
check.
Ack. That was my understanding as well.
quoted
quoted
+               dma_dev = dma_dev->parent;
+
+       return (dma_dev && dma_dev->dma_mask) ? dma_dev : NULL;
This may be a noob question, but are we sure that !dma_dev->dma_mask
&& dma_dev->parent->dma_mask != NULL means that the parent is the
dma-device that we should use? I understand SF devices work that way
but it's not immediately obvious to me that this is generically true.
This is what I gathered from Parav's answer.
quoted
For example pavel came up with the case where for veth,
netdev->dev.parent == NULL , I wonder if there are weird devices in
the wild where netdev->dev.parent->dma_mask == NULL but that doesn't
necessarily mean that the grandparent is the dma-device that we should
use.
Yep.
quoted
I guess to keep my long question short: what makes you think this is
generically safe to do? Or is it not, but we think most devices behave
this way and we're going to handle more edge cases in follow up
patches?
It is just what we know so far about SFs. See end of mail.
I see. OK, even though this is 'just what we know so far', I'm still
in favor of this simple approach, but I would say it would be good to
communicate in the comments that this is a best-effort dma-device
finding and doesn't handle every case under the sun. Something like
(untested):

static inline struct device *netdev_get_dma_dev(const struct net_device *dev)
{
       struct device *parent = dev->dev.parent;

       if (!parent)
               return NULL;

       /* For most netdevs, the parent supports dma and is the correct
        * dma-device
        */
       if (parent->dma_mask)
               return parent;

       /* For SF devices, the parent doesn't support dma, but the grandparent
        * does, and is the correct dma-device to use (link to docs that explain
        * this if any).
        */
       if (parent->parent && parent->parent->dma_mask)
               return parent->parent;

       /* If neither the parent nor grandparent support dma, then we're not
        * sure what dma-device to use. Error out. Special handling for new
        * netdevs may need to be added in the future.
        */
       return NULL;
}

With some comments explaining the logic a bit, you can add:

Reviewed-by: Mina Almasry <redacted>

And let's see if Jakub likes this. If not, we can always do the future
proof approach with the queue API giving the driver the ability to
tell us what exactly is the dma-device to use (or whatever approach he
prefers).

-- 
Thanks,
Mina
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help