Devmem TX frags are bounded only by the net_iov size, which is about to grow up to 2MB, more than some devices can describe in a single TX descriptor. Add netmem_tx_max_frag_size, U32_MAX by default, and cap devmem TX frags to the limit of the device the binding is attached to. Signed-off-by: Stanislav Fomichev --- Documentation/networking/net_cachelines/net_device.rst | 1 + Documentation/networking/netmem.rst | 6 ++++++ include/linux/netdevice.h | 2 ++ net/core/datagram.c | 1 + net/core/dev.c | 1 + net/core/devmem.c | 1 + net/core/devmem.h | 1 + 7 files changed, 13 insertions(+) diff --git a/Documentation/networking/net_cachelines/net_device.rst b/Documentation/networking/net_cachelines/net_device.rst index 8eceaa80b686..4f5fd5b99154 100644 --- a/Documentation/networking/net_cachelines/net_device.rst +++ b/Documentation/networking/net_cachelines/net_device.rst @@ -76,6 +76,7 @@ unsigned_short dev_id unsigned_short dev_port spinlock_t addr_list_lock int irq +u32 netmem_tx_max_frag_size struct netdev_hw_addr_list uc struct netdev_hw_addr_list mc struct netdev_hw_addr_list dev_addrs diff --git a/Documentation/networking/netmem.rst b/Documentation/networking/netmem.rst index 6871dcdd700c..04861c60cfa1 100644 --- a/Documentation/networking/netmem.rst +++ b/Documentation/networking/netmem.rst @@ -155,3 +155,9 @@ Driver TX Requirements - `NETMEM_TX_NO_DMA`: for virtual or passthrough devices that do not DMA, but still support handling of netmem-backed skbs. + +3. Drivers which limit the size of a single TX buffer should set + `netdev->netmem_tx_max_frag_size` to that limit. Devmem TX frags are + capped at it, otherwise a frag can span a whole net_iov, which may be + much larger than a page. The default is U32_MAX, the value is read when + the dmabuf binding is created. diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index c0ae442c4344..4453b80bf7ea 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -1845,6 +1845,7 @@ enum netdev_reg_state { * drivers. Mainly used by logical interfaces, such as * bonding and tunnels * @netmem_tx: device netmem TX mode + * @netmem_tx_max_frag_size: max size of a netmem TX frag * @pacing_offload: enable EDT pacing offload. * * @name: This is the first field of the "visible" part of this structure @@ -2342,6 +2343,7 @@ struct net_device { unsigned short dev_port; int irq; u32 priv_len; + u32 netmem_tx_max_frag_size; spinlock_t addr_list_lock; diff --git a/net/core/datagram.c b/net/core/datagram.c index 489d92fe6dae..a8d3f87d38c5 100644 --- a/net/core/datagram.c +++ b/net/core/datagram.c @@ -734,6 +734,7 @@ zerocopy_fill_skb_from_devmem(struct sk_buff *skb, struct iov_iter *from, size = min_t(size_t, size, length); size = min_t(size_t, size, iter_iov_len(from)); + size = min_t(size_t, size, binding->tx_max_frag_size); netmem_inc_ref(net_iov_to_netmem(niov)); skb_add_rx_frag_netmem(skb, i, net_iov_to_netmem(niov), off, diff --git a/net/core/dev.c b/net/core/dev.c index 3ac700d37e59..ba2f887dcd39 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -12350,6 +12350,7 @@ struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name, dev->gro_ipv4_max_size = GRO_LEGACY_MAX_SIZE; dev->tso_max_size = TSO_LEGACY_MAX_SIZE; dev->tso_max_segs = TSO_MAX_SEGS; + dev->netmem_tx_max_frag_size = U32_MAX; dev->upper_level = 1; dev->lower_level = 1; #ifdef CONFIG_LOCKDEP diff --git a/net/core/devmem.c b/net/core/devmem.c index 6339f221bc82..19c039ed2cb2 100644 --- a/net/core/devmem.c +++ b/net/core/devmem.c @@ -218,6 +218,7 @@ net_devmem_bind_dmabuf(struct net_device *dev, void *vdev, binding->dev = dev; binding->vdev = vdev; + binding->tx_max_frag_size = dev->netmem_tx_max_frag_size; write_pnet(&binding->net, sock_net(nl_sk)); binding->uid = sk_uid(nl_sk); binding->niov_shift = niov_shift; diff --git a/net/core/devmem.h b/net/core/devmem.h index 8fa089776610..97ff1f13fb84 100644 --- a/net/core/devmem.h +++ b/net/core/devmem.h @@ -79,6 +79,7 @@ struct net_devmem_dmabuf_binding { struct net_iov **tx_vec; unsigned int niov_shift; + u32 tx_max_frag_size; struct work_struct unbind_w; }; -- 2.53.0-Meta