* [PATCH net v4 2/2] amt: make the head writable before rewriting the L2 header
From: Michael Bommarito @ 2026-07-07 19:32 UTC (permalink / raw)
To: Taehee Yoo, Andrew Lunn, David S . Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni
Cc: netdev, linux-kernel
In-Reply-To: <20260707193243.3448201-1-michael.bommarito@gmail.com>
amt_multicast_data_handler(), amt_membership_query_handler() and
amt_update_handler() rewrite the ethernet header of the decapsulated
skb in place (eth->h_proto, eth->h_dest and, for the query, also
eth->h_source) before handing it up the stack. The skb head may be
shared, for example when a packet tap has cloned it on the underlay
interface, so writing through it corrupts the other reader's copy.
Call skb_cow_head() before the rewrite so the head is private. It is
placed before the pointers into the head are (re-)derived, so a
reallocation caused by the copy is picked up by those derivations.
Fixes: cbc21dc1cfe9 ("amt: add data plane of amt interface")
Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com>
---
drivers/net/amt.c | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
diff --git a/drivers/net/amt.c b/drivers/net/amt.c
index 1d6b2de4b73cc..f7375e40bc8f2 100644
--- a/drivers/net/amt.c
+++ b/drivers/net/amt.c
@@ -2330,6 +2330,12 @@ static bool amt_multicast_data_handler(struct amt_dev *amt, struct sk_buff *skb)
skb_reset_mac_header(skb);
skb_pull(skb, sizeof(*eth));
+ /* The L2 header is rewritten below; make the head private first so a
+ * cloned skb (for example one taken by a packet tap) is not modified.
+ */
+ if (skb_cow_head(skb, 0))
+ return true;
+
if (!pskb_may_pull(skb, sizeof(*iph)))
return true;
iph = ip_hdr(skb);
@@ -2413,6 +2419,11 @@ static bool amt_membership_query_handler(struct amt_dev *amt,
eth = eth_hdr(skb);
/* Snapshot the outer source MAC before a later pull can free it. */
ether_addr_copy(h_source, oeth->h_source);
+ /* The L2 header is rewritten below; make the head private first so a
+ * cloned skb (for example one taken by a packet tap) is not modified.
+ */
+ if (skb_cow_head(skb, 0))
+ return true;
if (!pskb_may_pull(skb, sizeof(*iph)))
return true;
@@ -2538,6 +2549,12 @@ static bool amt_update_handler(struct amt_dev *amt, struct sk_buff *skb)
if (!pskb_may_pull(skb, sizeof(*iph)))
return true;
+ /* The L2 header is rewritten below; make the head private first so a
+ * cloned skb (for example one taken by a packet tap) is not modified.
+ */
+ if (skb_cow_head(skb, 0))
+ return true;
+
iph = ip_hdr(skb);
if (iph->version == 4) {
if (ip_mc_check_igmp(skb)) {
--
2.53.0
^ permalink raw reply related
* Re: [PATCH net-next v14 0/9] tls: Add TLS 1.3 hardware offload support
From: Nils Juenemann @ 2026-07-07 19:34 UTC (permalink / raw)
To: rjethwani
Cc: borisp, davem, edumazet, john.fastabend, kuba, leon, mbloch,
netdev, pabeni, saeedm, sd, tariqt
In-Reply-To: <CAKaoeS3Yg=kncNQRRcVh8JrQXy4Aah=3fuBwcitD6mjAEJOKOw@mail.gmail.com>
On Mon, Jul 6, 2026 at 3:14 PM Rishikesh Jethwani <rjethwani@everpuredata.com> wrote:
>
> Following two patches should fix this issue:
[...]
Thanks, Rishikesh.
Both patches apply cleanly on net-next and fix the crash in our setup. I
tested repeated channel-count changes between 64 and 32 under live TLS 1.3
RX HW offload load.
Tested-by: Nils Juenemann <nils.juenemann@gmail.com>
^ permalink raw reply
* Re: [PATCH net v2] psp: fix NULL genl_sock deref race with concurrent netns teardown
From: Wei Wang @ 2026-07-07 19:50 UTC (permalink / raw)
To: Kiran Kella
Cc: daniel.zahka, kuba, willemdebruijn.kernel, davem, edumazet,
pabeni, horms, weibunny, netdev, linux-kernel,
jayakrishnan.udayavarma, ajit.khaparde, akhilesh.samineni,
Vikas Gupta, Bhargava Marreddy, Daniel Zahka
In-Reply-To: <20260707185937.3177211-1-kiran.kella@broadcom.com>
On Tue, Jul 7, 2026 at 12:00 PM Kiran Kella <kiran.kella@broadcom.com> wrote:
>
> >
> The race occurs between network namespace removal and PSP device
> unregistration. When a netns is deleted while a PSP device associated
> with that netns is concurrently being removed, psp_dev_unregister()
> triggers psp_nl_notify_dev() to send a device change notification.
> Concurrently, cleanup_net() running in the netns workqueue calls
> genl_pernet_exit(), which sets net->genl_sock to NULL. If
> genl_pernet_exit() wins the race, two sites in psp_nl_multicast_per_ns()
> then dereference the NULL socket and crash:
>
> CPU 0 (netns teardown) CPU 1 (PSP device unregister)
> ====================== =============================
> cleanup_net [workqueue]
> genl_pernet_exit() psp_dev_unregister()
> net->genl_sock = NULL psp_nl_notify_dev()
> psp_nl_multicast_per_ns()
> build_ntf()
> -> netlink_has_listeners(NULL)
> /* crash */
> genlmsg_multicast_netns()
> -> nlmsg_multicast_filtered(NULL)
> /* crash */
>
> Both the main_net path (derived from psd->main_netdev) and each
> assoc_net entry in psd->assoc_dev_list are affected.
>
> Fix by replacing the bare dev_net() calls with maybe_get_net().
> maybe_get_net() returns NULL if the namespace is already dying.
> Holding the reference ensures genl_sock remains valid across both the
> build_ntf() and genlmsg_multicast_netns() calls.
>
> Fixes: 00c94ca2b99e ("psp: base PSP device support")
> Fixes: 06c2dce2d0f6 ("psp: add new netlink cmd for dev-assoc and dev-disassoc")
> Reviewed-by: Ajit Khaparde <ajit.khaparde@broadcom.com>
> Reviewed-by: Vikas Gupta <vikas.gupta@broadcom.com>
> Reviewed-by: Bhargava Marreddy <bhargava.marreddy@broadcom.com>
> Reviewed-by: Akhilesh Samineni <akhilesh.samineni@broadcom.com>
> Reviewed-by: Daniel Zahka <daniel.zahka@broadcom.com>
> Tested-by: Daniel Zahka <daniel.zahka@broadcom.com>
> Signed-off-by: Kiran Kella <kiran.kella@broadcom.com>
> ---
> v2:
> - get rid of the extra struct net *net, by doing
> (!maybe_get_net(assoc_net)) directly (as suggested by Daniel Zahka)
>
> v1: https://lore.kernel.org/all/20260703112431.2860506-1-kiran.kella@broadcom.com/
>
LGTM! Thanks for the fix!
Reviewed-by: Wei Wang <weibunny@fb.com>
> net/psp/psp_nl.c | 23 ++++++++++++++---------
> 1 file changed, 14 insertions(+), 9 deletions(-)
>
> diff --git a/net/psp/psp_nl.c b/net/psp/psp_nl.c
> index 9610d8c456ff..1438dbb07949 100644
> --- a/net/psp/psp_nl.c
> +++ b/net/psp/psp_nl.c
> @@ -62,7 +62,10 @@ psp_nl_multicast_per_ns(struct psp_dev *psd, unsigned int group,
> struct net *main_net;
> struct sk_buff *ntf;
>
> - main_net = dev_net(psd->main_netdev);
> + main_net = maybe_get_net(dev_net(psd->main_netdev));
> + if (!main_net)
> + return;
> +
> xa_init(&sent_nets);
>
> list_for_each_entry(entry, &psd->assoc_dev_list, dev_list) {
> @@ -77,21 +80,23 @@ psp_nl_multicast_per_ns(struct psp_dev *psd, unsigned int group,
> if (ret == -EBUSY)
> continue;
>
> - ntf = build_ntf(psd, assoc_net, ctx);
> - if (!ntf)
> + if (!maybe_get_net(assoc_net))
> continue;
>
> - genlmsg_multicast_netns(&psp_nl_family, assoc_net, ntf, 0,
> - group, GFP_KERNEL);
> + ntf = build_ntf(psd, assoc_net, ctx);
> + if (ntf)
> + genlmsg_multicast_netns(&psp_nl_family, assoc_net, ntf,
> + 0, group, GFP_KERNEL);
> + put_net(assoc_net);
> }
> xa_destroy(&sent_nets);
>
> /* Send to main device netns */
> ntf = build_ntf(psd, main_net, ctx);
> - if (!ntf)
> - return;
> - genlmsg_multicast_netns(&psp_nl_family, main_net, ntf, 0, group,
> - GFP_KERNEL);
> + if (ntf)
> + genlmsg_multicast_netns(&psp_nl_family, main_net, ntf, 0, group,
> + GFP_KERNEL);
> + put_net(main_net);
> }
>
> static struct sk_buff *psp_nl_clone_ntf(struct psp_dev *psd, struct net *net,
> --
> 2.54.0
>
^ permalink raw reply
* [PATCH nf-next 0/4] netfilter: replace u_int*_t with kernel int types (batch 3)
From: Carlos Grillet @ 2026-07-07 19:51 UTC (permalink / raw)
To: Pablo Neira Ayuso, Florian Westphal, Phil Sutter, Simon Horman,
Julian Anastasov, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni
Cc: netfilter-devel, coreteam, linux-kernel, netdev, lvs-devel
This patch series replaces POSIX u_int8_t/u_int16_t/u_int32_t with the
preferred kernel types u8/u16/u32 across several netfilter files and
updates the corresponding header definition.
This continues the work started in:
https://lore.kernel.org/all/20260616182948.96865-1-carlos@carlosgrillet.me
No functional changes.
Carlos Grillet (4):
netfilter: ip_vs_core: replace u_int32_t with u32
netfilter: nf_conntrack_sip: replace u_int16_t with u16
netfilter: nf_nat_amanda: replace u_int16_t with u16
netfilter: nfnetlink_osf: replace u_int8_t with u8
include/linux/netfilter/nfnetlink_osf.h | 2 +-
net/netfilter/ipvs/ip_vs_core.c | 2 +-
net/netfilter/nf_conntrack_sip.c | 2 +-
net/netfilter/nf_nat_amanda.c | 2 +-
net/netfilter/nfnetlink_osf.c | 2 +-
5 files changed, 5 insertions(+), 5 deletions(-)
--
2.55.0
^ permalink raw reply
* [PATCH nf-next 1/4] netfilter: ip_vs_core: replace u_int32_t with u32
From: Carlos Grillet @ 2026-07-07 19:51 UTC (permalink / raw)
To: Simon Horman, Julian Anastasov, Pablo Neira Ayuso,
Florian Westphal, Phil Sutter, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni
Cc: netdev, lvs-devel, netfilter-devel, coreteam, linux-kernel
In-Reply-To: <20260707195111.34899-1-carlos@carlosgrillet.me>
Use preferred kernel integer type u32 instead of the POSIX u_int32_t
variant.
No functional change.
Signed-off-by: Carlos Grillet <carlos@carlosgrillet.me>
---
net/netfilter/ipvs/ip_vs_core.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/net/netfilter/ipvs/ip_vs_core.c b/net/netfilter/ipvs/ip_vs_core.c
index d40b404c1bf6..1ae997660148 100644
--- a/net/netfilter/ipvs/ip_vs_core.c
+++ b/net/netfilter/ipvs/ip_vs_core.c
@@ -882,7 +882,7 @@ static inline enum ip_defrag_users ip_vs_defrag_user(unsigned int hooknum)
}
static inline int ip_vs_gather_frags(struct netns_ipvs *ipvs,
- struct sk_buff *skb, u_int32_t user)
+ struct sk_buff *skb, u32 user)
{
int err;
--
2.55.0
^ permalink raw reply related
* [PATCH nf-next 3/4] netfilter: nf_nat_amanda: replace u_int16_t with u16
From: Carlos Grillet @ 2026-07-07 19:51 UTC (permalink / raw)
To: Pablo Neira Ayuso, Florian Westphal, Phil Sutter, David S. Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni, Simon Horman
Cc: netfilter-devel, coreteam, netdev, linux-kernel
In-Reply-To: <20260707195111.34899-1-carlos@carlosgrillet.me>
Use preferred kernel integer type u16 instead of the POSIX u_int16_t
variant.
No functional change.
Signed-off-by: Carlos Grillet <carlos@carlosgrillet.me>
---
net/netfilter/nf_nat_amanda.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/net/netfilter/nf_nat_amanda.c b/net/netfilter/nf_nat_amanda.c
index 8f1054920a85..fe054cb4fc0b 100644
--- a/net/netfilter/nf_nat_amanda.c
+++ b/net/netfilter/nf_nat_amanda.c
@@ -33,7 +33,7 @@ static unsigned int help(struct sk_buff *skb,
struct nf_conntrack_expect *exp)
{
char buffer[sizeof("65535")];
- u_int16_t port;
+ u16 port;
/* Connection comes from client. */
exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port;
--
2.55.0
^ permalink raw reply related
* [PATCH nf-next 2/4] netfilter: nf_conntrack_sip: replace u_int16_t with u16
From: Carlos Grillet @ 2026-07-07 19:51 UTC (permalink / raw)
To: Pablo Neira Ayuso, Florian Westphal, Phil Sutter, David S. Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni, Simon Horman
Cc: netfilter-devel, coreteam, netdev, linux-kernel
In-Reply-To: <20260707195111.34899-1-carlos@carlosgrillet.me>
Use preferred kernel integer type u16 instead of the POSIX u_int16_t
variant.
No functional change.
Signed-off-by: Carlos Grillet <carlos@carlosgrillet.me>
---
net/netfilter/nf_conntrack_sip.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c
index 0ff089e03891..87c9c6b92a6d 100644
--- a/net/netfilter/nf_conntrack_sip.c
+++ b/net/netfilter/nf_conntrack_sip.c
@@ -935,7 +935,7 @@ static int set_expected_rtp_rtcp(struct sk_buff *skb, unsigned int protoff,
union nf_inet_addr *saddr;
struct nf_conntrack_tuple tuple;
int direct_rtp = 0, skip_expect = 0, ret = NF_DROP;
- u_int16_t base_port;
+ u16 base_port;
__be16 rtp_port, rtcp_port;
const struct nf_nat_sip_hooks *hooks;
struct nf_conn_help *help;
--
2.55.0
^ permalink raw reply related
* [PATCH nf-next 4/4] netfilter: nfnetlink_osf: replace u_int8_t with u8
From: Carlos Grillet @ 2026-07-07 19:51 UTC (permalink / raw)
To: Pablo Neira Ayuso, Florian Westphal, Phil Sutter, David S. Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni, Simon Horman
Cc: netfilter-devel, coreteam, linux-kernel, netdev
In-Reply-To: <20260707195111.34899-1-carlos@carlosgrillet.me>
Use preferred kernel integer type u8 instead of the POSIX u_int8_t
variant and update the corresponding header definition.
No functional change.
Signed-off-by: Carlos Grillet <carlos@carlosgrillet.me>
---
include/linux/netfilter/nfnetlink_osf.h | 2 +-
net/netfilter/nfnetlink_osf.c | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/include/linux/netfilter/nfnetlink_osf.h b/include/linux/netfilter/nfnetlink_osf.h
index 788613f36935..d720abf59ca8 100644
--- a/include/linux/netfilter/nfnetlink_osf.h
+++ b/include/linux/netfilter/nfnetlink_osf.h
@@ -26,7 +26,7 @@ struct nf_osf_data {
const char *version;
};
-bool nf_osf_match(const struct sk_buff *skb, u_int8_t family,
+bool nf_osf_match(const struct sk_buff *skb, u8 family,
int hooknum, struct net_device *in, struct net_device *out,
const struct nf_osf_info *info, struct net *net,
const struct list_head *nf_osf_fingers);
diff --git a/net/netfilter/nfnetlink_osf.c b/net/netfilter/nfnetlink_osf.c
index 92002079f8ea..88382e2108eb 100644
--- a/net/netfilter/nfnetlink_osf.c
+++ b/net/netfilter/nfnetlink_osf.c
@@ -179,7 +179,7 @@ static const struct tcphdr *nf_osf_hdr_ctx_init(struct nf_osf_hdr_ctx *ctx,
}
bool
-nf_osf_match(const struct sk_buff *skb, u_int8_t family,
+nf_osf_match(const struct sk_buff *skb, u8 family,
int hooknum, struct net_device *in, struct net_device *out,
const struct nf_osf_info *info, struct net *net,
const struct list_head *nf_osf_fingers)
--
2.55.0
^ permalink raw reply related
* [PATCH net v2] net: stmmac: resume PHY before hardware setup when opening the interface
From: Stefan Agner @ 2026-07-07 19:54 UTC (permalink / raw)
To: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Andrew Lunn
Cc: Russell King (Oracle), Maxime Chevallier, Ovidiu Panait,
Maxime Coquelin, Alexandre Torgue, netdev, linux-stm32,
linux-arm-kernel, regressions, Stefan Agner
In-Reply-To: <message-id-of-your-v1-mail>
Since the referenced commit, changing the MTU on a running interface no
longer disconnects and reconnects the PHY; __stmmac_release() merely
stops phylink, which also suspends the PHY (BMCR power-down) when WoL
is not enabled. __stmmac_open() then performs the DMA software reset in
stmmac_hw_setup() before phylink_start() resumes the PHY again.
IEEE 802.3 22.2.4.1.5 allows a PHY to stop its receive clock while
powered down, and stmmac requires a running receive clock for the DMA
software reset to complete (the phylink config sets mac_requires_rxc).
On such setups, e.g. the RK3566-based Home Assistant Green with an
RTL8211F-VD PHY in RGMII mode, any runtime MTU change now times out and
leaves the interface dead:
rk_gmac-dwmac fe010000.ethernet end0: Failed to reset the dma
rk_gmac-dwmac fe010000.ethernet end0: stmmac_hw_setup: DMA engine initialization failed
rk_gmac-dwmac fe010000.ethernet end0: __stmmac_open: Hw setup failed
rk_gmac-dwmac fe010000.ethernet end0: failed reopening the interface after MTU change
In the field this is triggered by NetworkManager applying an MTU while
activating the connection, breaking networking entirely.
Resume the PHY in __stmmac_open() before the hardware setup, making it
the counterpart of the phylink_stop() in __stmmac_release(), like
stmmac_resume() already does for the same reason. phylink_start() also
resumes the PHY, but only after stmmac_hw_setup(), and it cannot be
moved before the hardware setup since it may bring the link up
immediately from a workqueue, racing with the initialization (see the
comment in stmmac_resume()). For the regular ndo_open path the PHY has
just been attached and is not suspended, in which case
phylink_prepare_resume() does nothing.
Fixes: db299a0c09e9 ("net: stmmac: move PHY handling out of __stmmac_open()/release()")
Link: https://github.com/home-assistant/operating-system/issues/4858
Signed-off-by: Stefan Agner <stefan@agner.ch>
---
Changes in v2:
- Move the PHY resume from stmmac_change_mtu() into __stmmac_open() so
that it also counters the PHY suspend caused by __stmmac_release()
(suggested by Andrew Lunn), placed before stmmac_reset_queues_param()
to match the ordering used in stmmac_resume()
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -4147,6 +4147,15 @@
dma_conf->tx_queue[i].tbs = priv->dma_conf.tx_queue[i].tbs;
memcpy(&priv->dma_conf, dma_conf, sizeof(*dma_conf));
+ /* The PHY is suspended when the interface is reopened without
+ * disconnecting the PHY, e.g. on MTU change. IEEE 802.3 allows PHYs
+ * to stop their receive clock while powered down, but the DMA
+ * software reset in stmmac_hw_setup() requires a running receive
+ * clock, and phylink_start() below resumes the PHY only after the
+ * hardware setup. Resume a suspended PHY here first.
+ */
+ phylink_prepare_resume(priv->phylink);
+
stmmac_reset_queues_param(priv);
ret = stmmac_hw_setup(dev);
--
2.49.0
^ permalink raw reply
* Re: [PATCH net v2] tun/tap & vhost-net: make qdisc backpressure opt-in via IFF_BACKPRESSURE
From: Brett A C Sheffield @ 2026-07-07 20:05 UTC (permalink / raw)
To: Simon Schippers
Cc: Michael S. Tsirkin, Willem de Bruijn, Jason Wang,
David S . Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
netdev, Simon Horman, Jonathan Corbet, Shuah Khan, Andrew Lunn,
Tim Gebauer, linux-doc, linux-kernel
In-Reply-To: <0d28fdc4-3c03-48d6-bd59-e59f7a01f4b6@tu-dortmund.de>
On 2026-07-07 08:52, Simon Schippers wrote:
> Brett, can you try the two attached patches here with iperf3?
> I think testing with 8 and 16 threads is enough, so where there is a
> regression.
>
> The two patches are about time when to wake:
> Currently we wake after consuming half the internal ring buffer.
> One of the attached patches wakes after 2 cachelines (128 of 1000
> packets) and the other one just wakes once the ring buffer is empty.
>
> This would really help :)
Sure...
7.2.0-rc2 (unpatched)
threads 1
[ 5] 0.00-10.00 sec 20.4 GBytes 17.5 Gbits/sec 0 sender
[ 5] 0.00-10.00 sec 2.00 GBytes 1.72 Gbits/sec receiver
threads 2
[SUM] 0.00-10.00 sec 12.7 GBytes 10.9 Gbits/sec 0 sender
[SUM] 0.00-10.00 sec 4.00 GBytes 3.43 Gbits/sec receiver
threads 8
[SUM] 0.00-10.00 sec 11.5 GBytes 9.85 Gbits/sec 0 sender
[SUM] 0.00-10.01 sec 11.4 GBytes 9.83 Gbits/sec receiver
threads 16
[SUM] 0.00-10.00 sec 11.6 GBytes 9.95 Gbits/sec 0 sender
[SUM] 0.00-10.01 sec 11.5 GBytes 9.91 Gbits/sec receiver
7.2.0-rc2 with 0001-tun-set-waking-threshold-to-ptr_ring_empty.patch
threads 1
[ 5] 0.00-10.00 sec 19.6 GBytes 16.8 Gbits/sec 0 sender
[ 5] 0.00-10.00 sec 2.00 GBytes 1.72 Gbits/sec receiver
threads 2
[SUM] 0.00-10.00 sec 11.1 GBytes 9.50 Gbits/sec 0 sender
[SUM] 0.00-10.00 sec 4.00 GBytes 3.43 Gbits/sec receiver
threads 8
[SUM] 0.00-10.00 sec 10.8 GBytes 9.25 Gbits/sec 0 sender
[SUM] 0.00-10.01 sec 10.7 GBytes 9.23 Gbits/sec receiver
threads 16
[SUM] 0.00-10.00 sec 10.9 GBytes 9.34 Gbits/sec 0 sender
[SUM] 0.00-10.01 sec 10.8 GBytes 9.30 Gbits/sec receiver
7.2.0-rc2 with 0001-tun-set-waking-threshold-to-tx_ring.batch.patch
threads 1
[ 5] 0.00-10.00 sec 19.6 GBytes 16.9 Gbits/sec 2 sender
[ 5] 0.00-10.00 sec 2.00 GBytes 1.72 Gbits/sec receiver
threads 2
[SUM] 0.00-10.00 sec 13.9 GBytes 11.9 Gbits/sec 0 sender
[SUM] 0.00-10.00 sec 4.00 GBytes 3.43 Gbits/sec receiver
threads 8
[SUM] 0.00-10.00 sec 12.7 GBytes 10.9 Gbits/sec 0 sender
[SUM] 0.00-10.01 sec 12.3 GBytes 10.6 Gbits/sec receiver
threads 16
[SUM] 0.00-10.00 sec 12.5 GBytes 10.7 Gbits/sec 0 sender
[SUM] 0.00-10.00 sec 12.4 GBytes 10.7 Gbits/sec receiver
HTH,
Brett
--
Brett Sheffield (he/him)
Librecast - Decentralising the Internet with Multicast
https://librecast.net/
https://blog.brettsheffield.com/
^ permalink raw reply
* [PATCH net] sctp: validate stream count in sctp_process_strreset_inreq()
From: Cen Zhang (Microsoft) @ 2026-07-07 20:32 UTC (permalink / raw)
To: marcelo.leitner, lucien.xin, davem, edumazet, kuba, pabeni
Cc: horms, linux-sctp, netdev, linux-kernel, AutonomousCodeSecurity,
tgopinath, kys, blbllhy
When processing a RESET_IN_REQUEST from a peer,
sctp_process_strreset_inreq() derives the stream count from the
parameter length but does not check whether the resulting
RESET_OUT_REQUEST response would exceed SCTP_MAX_CHUNK_LEN.
The OUT request header (sctp_strreset_outreq, 16 bytes) is 8 bytes larger
than the IN request header (sctp_strreset_inreq, 8 bytes). Generally, the
IP payload is bounded to 65535 bytes, so the stream list cannot be
large enough to trigger the overflow. However, on interfaces with MTU >
65535 (e.g., loopback with IPv6 jumbograms), a stream list that fits
within the incoming IN parameter can cause a __u16 overflow in
sctp_make_strreset_req() when computing the OUT response size, leading to
an undersized skb allocation, raising a kernel BUG:
net/core/skbuff.c:207 skb_panic
net/core/skbuff.c:2625 skb_put
net/sctp/sm_make_chunk.c:1535 sctp_addto_chunk
net/sctp/sm_make_chunk.c:3695 sctp_make_strreset_req
net/sctp/stream.c:655 sctp_process_strreset_inreq
The local setsockopt path (sctp_send_reset_streams) already performs length
validation, but the network packet path does not. Fix by adding similar
length check before calling sctp_make_strreset_req().
Fixes: 7f9d68ac944e ("sctp: implement sender-side procedures for SSN Reset
Request Parameter")
Reported-by: AutonomousCodeSecurity@microsoft.com
Signed-off-by: Cen Zhang (Microsoft) <blbllhy@gmail.com>
---
net/sctp/stream.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/net/sctp/stream.c b/net/sctp/stream.c
index 5c2fdedea..ea3805712 100644
--- a/net/sctp/stream.c
+++ b/net/sctp/stream.c
@@ -639,6 +639,10 @@ struct sctp_chunk *sctp_process_strreset_inreq(
nums = (ntohs(param.p->length) - sizeof(*inreq)) / sizeof(__u16);
str_p = inreq->list_of_streams;
+ if (nums * sizeof(__u16) + sizeof(struct sctp_strreset_outreq)
+ > SCTP_MAX_CHUNK_LEN - sizeof(struct sctp_reconf_chunk)) {
+ goto out;
+ }
for (i = 0; i < nums; i++) {
if (ntohs(str_p[i]) >= stream->outcnt) {
result = SCTP_STRRESET_ERR_WRONG_SSN;
--
2.53.0
^ permalink raw reply related
* Re: [PATCH net-next v4 1/3] net: devmem: allow rx-buf-size > PAGE_SIZE per dmabuf binding
From: Mina Almasry @ 2026-07-07 20:36 UTC (permalink / raw)
To: Bobby Eshleman
Cc: Donald Hunter, Jakub Kicinski, David S. Miller, Eric Dumazet,
Paolo Abeni, Simon Horman, Andrew Lunn, Gerd Hoffmann,
Vivek Kasireddy, Sumit Semwal, Christian König, Shuah Khan,
netdev, linux-kernel, dri-devel, linux-media, linaro-mm-sig,
linux-kselftest, sdf, razor, daniel, matttbe, skhawaja, dw,
Joe Damato, Bobby Eshleman
In-Reply-To: <20260701-tcpdm-large-niovs-v4-1-ca4654f37570@meta.com>
On Wed, Jul 1, 2026 at 12:22 PM Bobby Eshleman <bobbyeshleman@gmail.com> wrote:
>
> From: Bobby Eshleman <bobbyeshleman@meta.com>
>
> Every devmem dmabuf binding today hands the page_pool PAGE_SIZE niovs.
> This caps a single RX descriptor at PAGE_SIZE, burning CPU on buffer
> churn for large flows.
>
> Add a bind-time netlink attribute, NETDEV_A_DMABUF_RX_BUF_SIZE, that
> lets userspace request a larger niov size. The value must be a power of
> two >= PAGE_SIZE.
>
> Measurements
> ------------
> Setup: kperf in devmem RX/TX cuda mode, 4 flows, 64 MB messages, 60s,
> dctcp, num-rx-queues=4, dmabuf-rx/tx-size-mb=2048, 10 runs per niov
> size, mlx5.
>
> CPU Util:
>
> niov net sirq % net idle % app sys % app idle %
> ----- ---------------- ---------------- ---------------- ----------------
> 4K 62.38 +/- 8.27 33.40 +/- 7.51 54.15 +/- 10.23 43.67 +/- 10.53
> 16K 58.91 +/- 5.35 35.23 +/- 5.88 41.05 +/- 8.87 56.42 +/- 9.24
> 32K 64.12 +/- 0.68 31.09 +/- 1.48 44.54 +/- 3.51 52.63 +/- 3.65
> 64K 54.69 +/- 5.54 39.67 +/- 5.81 35.47 +/- 3.11 61.97 +/- 3.27
>
> RX app sys % drops ~19% from 4K to 64K.
>
> Throughput:
>
> niov RX dev Gbps RX flow avg Gbps
> ----- ---------------- -----------------
> 4K 300.63 +/- 53.21 75.16 +/- 13.30
> 16K 321.35 +/- 28.20 80.34 +/- 7.05
> 32K 347.63 +/- 2.20 86.91 +/- 0.55
> 64K 332.11 +/- 14.26 83.03 +/- 3.56
>
> Throughput seems to increase, but the stdev is pretty wide so could just
> be noise.
>
> kperf support (not yet merged):
> https://github.com/facebookexperimental/kperf/commit/8837577f920876bce6986ec18869ac04439ebcd2
>
> Signed-off-by: Bobby Eshleman <bobbyeshleman@meta.com>
> Acked-by: Stanislav Fomichev <sdf@fomichev.me>
I'm pretty happy to see most of this patch being a spot-for-spot
replacement of PAGE_SIZE with a variable. FWIW:
Reviewed-by: Mina Almasry <almasrymina@google.com>
> ---
> Documentation/netlink/specs/netdev.yaml | 8 +++++
> include/uapi/linux/netdev.h | 1 +
> net/core/devmem.c | 55 +++++++++++++++++++--------------
> net/core/devmem.h | 13 +++++---
> net/core/netdev-genl-gen.c | 5 +--
> net/core/netdev-genl.c | 19 ++++++++++--
> tools/include/uapi/linux/netdev.h | 1 +
> 7 files changed, 71 insertions(+), 31 deletions(-)
>
> diff --git a/Documentation/netlink/specs/netdev.yaml b/Documentation/netlink/specs/netdev.yaml
> index 5f143da7458c..70b902008bd3 100644
> --- a/Documentation/netlink/specs/netdev.yaml
> +++ b/Documentation/netlink/specs/netdev.yaml
> @@ -598,6 +598,13 @@ attribute-sets:
> type: u32
> checks:
> min: 1
> + -
> + name: rx-buf-size
> + doc: |
> + Size in bytes of each RX buffer the NIC writes into from the bound
> + dmabuf. Must be a power of two and >= PAGE_SIZE; defaults to
> + PAGE_SIZE.
> + type: u32
>
> operations:
> list:
> @@ -812,6 +819,7 @@ operations:
> - ifindex
> - fd
> - queues
> + - rx-buf-size
> reply:
> attributes:
> - id
> diff --git a/include/uapi/linux/netdev.h b/include/uapi/linux/netdev.h
> index 2f3ab75e8cc0..85e1d20c6268 100644
> --- a/include/uapi/linux/netdev.h
> +++ b/include/uapi/linux/netdev.h
> @@ -219,6 +219,7 @@ enum {
> NETDEV_A_DMABUF_QUEUES,
> NETDEV_A_DMABUF_FD,
> NETDEV_A_DMABUF_ID,
> + NETDEV_A_DMABUF_RX_BUF_SIZE,
>
> __NETDEV_A_DMABUF_MAX,
> NETDEV_A_DMABUF_MAX = (__NETDEV_A_DMABUF_MAX - 1)
> diff --git a/net/core/devmem.c b/net/core/devmem.c
> index 957d6b96216b..3d6cf35e50f3 100644
> --- a/net/core/devmem.c
> +++ b/net/core/devmem.c
> @@ -46,7 +46,7 @@ static dma_addr_t net_devmem_get_dma_addr(const struct net_iov *niov)
>
> owner = net_devmem_iov_to_chunk_owner(niov);
> return owner->base_dma_addr +
> - ((dma_addr_t)net_iov_idx(niov) << PAGE_SHIFT);
> + ((dma_addr_t)net_iov_idx(niov) << owner->binding->niov_shift);
> }
>
> static void net_devmem_dmabuf_binding_release(struct percpu_ref *ref)
> @@ -90,16 +90,17 @@ net_devmem_alloc_dmabuf(struct net_devmem_dmabuf_binding *binding)
> struct dmabuf_genpool_chunk_owner *owner;
> unsigned long dma_addr;
> struct net_iov *niov;
> - ssize_t offset;
> - ssize_t index;
> + size_t offset;
> + size_t index;
>
nit: I would keep this signed. Some of the most frustrating issues I
ran into is some of the underflowing and then passing a > check or
something. Although if the LLM is not complaining about this
particular case, there is probably no issue with it. I also notice a
lot of existing code that deals with indexes and offsets goes for
signed.
--
Thanks,
Mina
^ permalink raw reply
* Re: [PATCH net-next v5 1/4] dt-bindings: net: pse-pd: add bindings for Realtek/Broadcom PSE MCU
From: Jonas Jelonek @ 2026-07-07 20:50 UTC (permalink / raw)
To: Conor Dooley
Cc: Oleksij Rempel, Kory Maincent, Andrew Lunn, David S . Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, netdev, devicetree,
linux-kernel, Daniel Golle, Bjørn Mork
In-Reply-To: <20260707-dove-fretful-e3c8e237f1eb@spud>
Hi Conor,
On 07.07.26 19:25, Conor Dooley wrote:
> On Mon, Jul 06, 2026 at 10:30:00PM +0200, Jonas Jelonek wrote:
>> [...]
>> The protocol and firmware on the MCU, most likely the whole "solution",
>> is from Realtek. The setup is always the same on most Realtek-based
>> switches (saying most because a few counterexamples use completely
>> different setups, not even Broadcom or Realtek PSE silicon). The host
>> interface is always the same (except for I2C vs. SMBus vs. UART, which
>> is likely just a config in the MCU firmware). Therefore "realtek," is the
>> right prefix for all of these.
>>
>> Broadcom is not really involved here except for their PSE silicon being
>> used. Maybe Realtek modeled their MCU host protocol after the one that
>> Broadcom PSE silicon uses as host interface, but this is rather guessing.
>>
>> Maybe a historical view might help. Older RTL83xx-based switches with
>> PoE shipped with this setup using Broadcom PSE silicon. From what I know,
>> at this point Realtek didn't design their own PSE silicon. They used the
>> Broadcom silicon, put a MCU as a manager in front of it with their firmware
>> and a host protocol based on what Broadcom PSE itself uses. At some
>> point Realtek started to design their own PSE silicon which then was
>> used in newer switches instead of Broadcom PSE.
> Right, in that case it does make sense to use a realtek prefix, since
> the software and mcu solution is all theirs.
>
>> [...]
>> Only one at a time is used, but not combined in any way. All switches
>> I've seen so far always have a single management MCU for PoE, not
>> multiple. Thus, only a single variant is used. Which variant is used
>> likely depends on the board vendor which then tells Realtek "I want your
>> PoE solution, I can attach it via (I2C/SMBus/UART)". At least for UART vs.
>> I2C/SMBus there are sometimes valid reasons to use UART over the other.
>>
>> There is only a single switch (from Linksys) where the MCU expects raw
>> I2C messages. SMBus transaction fail actually. But I don't see the reason
>> why Linksys did it that way. The reason can't be that the MCU is attached
>> on a bit-banged I2C because another switch uses SMBus transaction on
>> a bit-banged I2C.
> Reading this, it feels like you "should" have compatibles that uniquely
> identify the protocol used.
Ok, I hope I put this together correctly. A concrete proposal:
"realtek,pse-mcu-gen1" (Protocol Gen 1, UART)
"realtek,pse-mcu-gen1-smbus" (Protocol Gen 1, SMBus)
"realtek,pse-mcu-gen2" (Protocol Gen 2, UART)
"realtek,pse-mcu-gen2-i2c" (Protocol Gen 2, raw I2C)
"realtek,pse-mcu-gen2-smbus" (Protocol Gen 2, SMBus)
This uniquely identifies the protocol used: first generation and second
generation. As Rob mentioned before [1], this also pulls in the raw I2C
vs. SMBus framing in contrast to having it in a property. The framing
suffix appears only on I2C attachments because it doesn't apply to
UART transport, and this is given by the parent serial@ node.
Though I'm still open for suggestions regarding the protocol
identification if "-gen1"/"-gen2" is not acceptable.
> Looking at the devices below, it seems like it
> would be possible to use compatibles based on the switches themselves, e.g.
> zyxel,xs1930-pse etc. If there are other devices that use the same
> protocol, they could fall back to the ones below.
>
> It'd be good to have the net developers weigh in though, as to whether
> using compatibles based on the switches is suitable.
I'd lean against, but happy to defer to you and the net maintainers. The
node describes the MCU with its Realtek firmware — the firmware/protocol
defines the device. Everything that differs between instances on the
controller level would be captured by the compatibles proposed above, so
a board compatible would encode nothing there the gen+framing string
doesn't.
Observed variation lives on another level. For instance, some boards have
heterogeneous per-port caps (e.g. 16 ports at 60W, 8 ports at 30W). This
is clearly something that should be expressed per-pse-pi, not in a
switch-specific compatible.
It would also be an exception to the other PSE-PD bindings. They describe
controllers used across many switches too, yet none encode the
switch/enclosure. Board-specific compatibles might still be added later in
case a device really has a variation or quirk that genuinely needs its own
compatible.
> [...]
Best regards,
Jonas
[1] https://lore.kernel.org/netdev/20260615212959.GA1679454-robh@kernel.org/
^ permalink raw reply
* Re: [PATCH net v2] net: stmmac: resume PHY before hardware setup when opening the interface
From: Jakub Raczynski @ 2026-07-07 21:13 UTC (permalink / raw)
To: Stefan Agner
Cc: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Andrew Lunn, Russell King (Oracle), Maxime Chevallier,
Ovidiu Panait, Maxime Coquelin, Alexandre Torgue, netdev,
linux-stm32, linux-arm-kernel, regressions
In-Reply-To: <20260707195425.405989-1-stefan@agner.ch>
[-- Attachment #1: Type: text/plain, Size: 2032 bytes --]
Please read
https://www.kernel.org/doc/html/latest/process/maintainer-netdev.html
in this case 'don’t repost your patches within one 24h period'
Because:
- you have two patches now processing and no changes requested yet,
nor did you get AI review that is currently employed
https://patchwork.kernel.org/project/netdevbpf/patch/20260707195425.405989-1-stefan@agner.ch/
and
https://patchwork.kernel.org/project/netdevbpf/patch/20260707162146.73823-1-stefan@agner.ch/
- This change is actually broken - in previous patch rtnl_lock() was asserted
by dev_ioctl(), but in this version it is not asserted anywhere and will
trigger WARN_ONCE().
- Full tests within an hour is possible, but no need to rush patches
- Please spend time reviewing patches, as I spent few minutes to make sure
you (or rather Fable AI) is correct that rtnl_lock() was asserted, so my
review would be accurate (previous patch was ok, this is not).
- Please respond yourself to comments, take time to understand codebase.
I would prefer not getting copy-paste answer from AI,
we have Sashiko review for that.
- Missing link to previous thread, shown below
- Moving code to other lines does not justify dropping "Assisted by AI"
I am not maintainer, just random reviewer. Some maintainer will give input
surely soon.
But rule of thumb, do not repost patches till your patch gets
'Changes requested' in patchwork or like 2 weeks have passed
(maybe during vacation even longer, as currently there are >600 patches
pending review).
On Tue, Jul 07, 2026 at 09:54:25PM +0200, Stefan Agner wrote:
> Changes in v2:
> - Move the PHY resume from stmmac_change_mtu() into __stmmac_open() so
> that it also counters the PHY suspend caused by __stmmac_release()
> (suggested by Andrew Lunn), placed before stmmac_reset_queues_param()
> to match the ordering used in stmmac_resume()
Missing link to previous thread
>
> drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 9 +++++++++
> 1 file changed, 9 insertions(+)
>
BR
Jakub Raczynski
[-- Attachment #2: Type: text/plain, Size: 0 bytes --]
^ permalink raw reply
* Re: [PATCH net v2] net: stmmac: resume PHY before hardware setup when opening the interface
From: Jakub Raczynski @ 2026-07-07 21:45 UTC (permalink / raw)
To: Stefan Agner
Cc: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Andrew Lunn, Russell King (Oracle), Maxime Chevallier,
Ovidiu Panait, Maxime Coquelin, Alexandre Torgue, netdev,
linux-stm32, linux-arm-kernel, regressions
In-Reply-To: <ak1rseUKTWFKzBib@AMDC4622.eu.corp.samsungelectronics.net>
[-- Attachment #1: Type: text/plain, Size: 450 bytes --]
On Tue, Jul 07, 2026 at 11:13:46PM +0200, Jakub Raczynski wrote:
> - This change is actually broken - in previous patch rtnl_lock() was asserted
> by dev_ioctl(), but in this version it is not asserted anywhere and will
> trigger WARN_ONCE().
Ok, as I looked again, I am wrong again, ndo_open() does hold rtnl_lock
already. So from this point it is good. Relocking would create deadlock,
so I take that part of comment back.
BR
Jakub Raczynski
[-- Attachment #2: Type: text/plain, Size: 0 bytes --]
^ permalink raw reply
* ethtool 7.1 released
From: Michal Kubecek @ 2026-07-07 21:51 UTC (permalink / raw)
To: netdev
[-- Attachment #1: Type: text/plain, Size: 758 bytes --]
Hello,
ethtool 7.1 has been released.
Home page: https://www.kernel.org/pub/software/network/ethtool/
Download link: https://www.kernel.org/pub/software/network/ethtool/ethtool-7.1.tar.xz
Release notes:
* Feature: track TX pause storm events (-I -a)
* Feature: update doc for ETHTOOL_PFC_PREVENTION_TOUT tunable
* Feature: RX CQE coalescing params (-c, -C)
* Feature: allow hex dump of all pages (-m)
* Feature: qsfp: support newer SFF-8636 compliance codes (-m)
* Feature: sfpid: support newer SFF-8636 compliance codes (-m)
* Fix: document --disable-netlink in help output (-h)
* Fix: add missing newlines in FEC output (--show-fec)
* Fix: sfpid: fix 10G Base-ER module detection (-m)
* Misc: clarify 10000baseCR link mode in man page
Michal
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply
* Re: [PATCH] net: phy: marvell: Add soft reset for 88E1510
From: Ben Brown @ 2026-07-07 21:59 UTC (permalink / raw)
To: Andrew Lunn
Cc: hkallweit1@gmail.com, linux@armlinux.org.uk, davem@davemloft.net,
edumazet@google.com, kuba@kernel.org, pabeni@redhat.com,
linux-kernel@vger.kernel.org, netdev@vger.kernel.org,
Chris Packham
In-Reply-To: <3c493e6f-b5d8-42ed-a752-fdce6452926d@lunn.ch>
On 7/4/26 00:53, Andrew Lunn wrote:
> On Fri, Jul 03, 2026 at 12:14:26AM +0000, Ben Brown wrote:
>>
>>
>> On 7/3/26 11:04, Andrew Lunn wrote:
>>> On Fri, Jul 03, 2026 at 10:50:34AM +1200, Ben Brown wrote:
>>>> When bringing down then up the link on a 88e1512 phy a link is not
>>>> getting established. This is because the phy is coming out of reset then
>>>> immediately getting configured. During configuration the page is
>>>> unsuccessfully updated causing writes to the wrong registers.
>>>>
>>>> Add the soft reset function that does a reset then polling read waiting
>>>> for the phy to come back online, at which stage the page register can be
>>>> updated successfully.
>>>>
>>>> This was tested on a 88E1512 phy, using ip link to bring up/down the
>>>> link.
>>>
>>> What makes the 88E1512 special that it needs this, but no other
>>> Marvell PHY does?
>>>
>>> Andrew
>>
>> This may be needed on the other marvell phys, but I only have access to
>> a 88E1512 phy so I am only updating what I have seen this on.
>
> The Marvell driver is used a lot, so i would of expected somebody else
> to of noticed.
>
> Lets take a step back.
>
> What sort of reset are we talking about? Software or hardware?
>
> Andrew
It is doing a hardware reset using a GPIO line.
When linked down the phy gets put into reset using a hardware GPIO line,
during link up the phy initializes the hardware using phy_init_hw(),
which de-asserts that reset GPIO. Then trivial setup is done before
the driver specific config_init().
When we are doing the marvell m88e1510_config_init() the first page
write is not applying so it ends up writing configuration to the wrong
registers. When testing fixes adding a 15us sleep before changing the
page also meant the page was updated correctly.
^ permalink raw reply
* Re: [PATCH net-next v4 0/3] net: devmem: allow rx-buf-size > PAGE_SIZE per binding
From: Bobby Eshleman @ 2026-07-07 22:02 UTC (permalink / raw)
To: Mina Almasry
Cc: Donald Hunter, Jakub Kicinski, David S. Miller, Eric Dumazet,
Paolo Abeni, Simon Horman, Andrew Lunn, Gerd Hoffmann,
Vivek Kasireddy, Sumit Semwal, Christian König, Shuah Khan,
netdev, linux-kernel, dri-devel, linux-media, linaro-mm-sig,
linux-kselftest, sdf, razor, daniel, matttbe, skhawaja, dw,
Joe Damato, Bobby Eshleman
In-Reply-To: <CAHS8izOmA_U=Q6WOO5mcoi2vBps_JFEtAQa3gXk=JcL3rqE1BA@mail.gmail.com>
On Tue, Jul 07, 2026 at 12:24:21PM -0700, Mina Almasry wrote:
> (I'm kinda reviewing this very late here. Some suggestions/comments
> but feel free to ignore if not useful).
>
> On Wed, Jul 1, 2026 at 12:22 PM Bobby Eshleman <bobbyeshleman@gmail.com> wrote:
> >
> > Every devmem dmabuf binding hands the page_pool PAGE_SIZE niovs today.
> > On NICs that consume one descriptor per netmem, this caps a single RX
> > descriptor at PAGE_SIZE and burns CPU on buffer churn.
> >
> > In this series, we add a bind-time netlink attribute,
> > NETDEV_A_DMABUF_RX_BUF_SIZE, that lets userspace request a larger niov size
> > (power of two >= PAGE_SIZE).
>
> FWIW we may be able to support arbitrary sizes with devmem. Because
> the genpool supports byte-aligned allocations AFAIR. Also the
> dma-mapping happens with the dma-buf size, so the actual niov size
> doesn't matter. The only thing I can think off which may not be
> flexible to arbitrary sizes is the driver itself. IDK what happens if
> you ask the driver to dma into a buffer that is frag size 5023 or
> something like that.
>
> But that is something that can be relaxed in the future.
I think at least for mlx5 there would be some issues, as it splits the
memory region into fixed-size strides (256B), so I'd expect it needs to
at least be divisible by the stride length. The mlx5 driver seems to
guard against this by checking for sz > PAGE_SIZE && is_power_of_2.
>
> > Drivers must opt in via
> > queue_mgmt_ops.QCFG_RX_PAGE_SIZE.
> >
>
> nit that probably doesn't matter: ...QCFG_RX_NETMEM_SIZE, or
> (...NIOV_SIZE). This doesn't actually work with pages, right?
I probably could have worded this in the message more clearly, but this
name is not introduced by this series, so we probably can't get away
with changing it.
>
> If you decide to extend to arbrary sizes, I would add to the
> queue_mgmt ops supports_netmem_size(size_t size) function, and let the
> driver enforce "it has to be power of 2" if it needs to. AFAICT core
> doesn't need to.
>
> > Selftests use udmabuf, but udmabuf sgtables were previously hardcoded to
> > PAGE_SIZE. This series modifies udmabuf to respect folio sizes in its exported
> > sgtable. The result is that when backing udmabuf with MFD_HUGETLB 2MB pages,
> > the sgtable is populated with 2MB entries, allowing devmem's gen_pool to carve
> > out large (eg. 64K) niovs.
> >
> > Measurements
> > ------------
> >
> > Setup: kperf devmem RX/TX cuda, 4 flows, 64 MB messages, 60s, dctcp,
> > num-rx-queues=4, dmabuf-rx/tx-size-mb=2048, 10 runs per niov size,
> > mlx5.
> >
> > niov RX dev Gbps RX flow avg Gbps app sys %
> > ----- ---------------- ----------------- ----------------
> > 4K 300.63 +/- 53.21 75.16 +/- 13.30 54.15 +/- 10.23
> > 16K 321.35 +/- 28.20 80.34 +/- 7.05 41.05 +/- 8.87
> > 32K 347.63 +/- 2.20 86.91 +/- 0.55 44.54 +/- 3.51
> > 64K 332.11 +/- 14.26 83.03 +/- 3.56 35.47 +/- 3.11
> >
> > RX app sys % drops ~19% from 4K to 64K.
> >
>
> Hard to read the columns for me but seems like good perf data. Did
> performance become worse from 32K to 64K? I wonder why.
The drop off struck my eye too, but didn't investigate further. Given
the wide stdev, it appears to me like the trend is positive but probably
not huge. The cpu util deltas, on the other hand, look stronger to me.
>
> I have some devmem performance fixes that are very critical for our
> production that I haven't gotten around to upstreaming yet. I wonder
> if I can send them to you for upstream submission. Are you potentially
> interested?
Definitely interested!
>
> --
> Thanks,
> Mina
Thanks Mina.
Best,
Bobby
^ permalink raw reply
* Re: [PATCH net] net: stmmac: intel: don't reconfigure SerDes on unchanged mode
From: Markus Breitenberger @ 2026-07-07 22:04 UTC (permalink / raw)
To: maxime.chevallier
Cc: andrew+netdev, bre, bre, davem, edumazet, kuba, netdev, pabeni,
stable, yong.liang.choong
In-Reply-To: <565c18f3-8b1b-4832-b060-617b7d683eb6@bootlin.com>
Hi Maxime,
Thanks for the review, and sorry - my commit message was wrong and
sent you down the wrong path.
> One thing is that now we 'blindly' rely on the bootloader / fw
> having correctly configured the initial interface.
That impression came from my commit message, where I wrote that
"firmware already programs the ModPHY for the configured interface".
That was incorrect: the kernel programs the SerDes rate itself, in
intel_serdes_powerup(), from priv->plat->phy_interface. I'll drop that
claim in v2.
> Maybe instead the serdes interaction logic can be reworked so that
> you query the serdes rate, see if you need to adjust it based on the
> selected interface, and if so you re-configure it ?
That's a good suggestion, and I'll do exactly that in v2. Instead of
comparing the cached priv->plat->phy_interface, it will read the
current lane rate back from SERDES_GCR0 and only run the disruptive PMC
reconfiguration when the rate actually differs from what the selected
interface needs:
cur_rate = (data & SERDES_RATE_MASK) >> SERDES_RATE_PCIE_SHIFT;
want_rate = interface == PHY_INTERFACE_MODE_2500BASEX ?
SERDES_RATE_PCIE_GEN2 : SERDES_RATE_PCIE_GEN1;
return cur_rate != want_rate;
The callback selects between the 1G and 2.5G ModPHY programming tables
from the requested interface, and the SerDes lane rate is the
observable state that tells us whether that programming is already
active. intel_mac_finish() applies the selected table to the shared
ModPHY LCPLL through the PMC IPC (intel_set_reg_access()) and then
power-cycles the SerDes, and that power-cycle is what disturbs the
on-die AHCI SATA PHY sharing the ModPHY on Elkhart Lake. Gating on the
actual rate keeps that reprogramming out of the boot path when the
SerDes is already configured correctly, while still handling a genuine
SGMII to 2500BASE-X change at runtime. If the read cannot be completed,
the helper returns true so the reconfiguration runs as before.
One caveat: the read-back covers the SerDes rate bits, which is
the setting relevant to this regression; it does not read back the
full LCPLL DWORD state. I'm keying on the rate because that is what the
initial mac_finish() would re-apply on this path, but if you'd rather
key the decision off something more specific I'm happy to adjust.
Thanks again for the pointer - reading the hardware is clearly the
more robust check.
Markus
^ permalink raw reply
* Re: [PATCH net] net: stmmac: intel: don't reconfigure SerDes on unchanged mode
From: Markus Breitenberger @ 2026-07-07 22:08 UTC (permalink / raw)
To: andrew
Cc: andrew+netdev, bre, bre, davem, edumazet, kuba, netdev, pabeni,
stable, yong.liang.choong
In-Reply-To: <abd431d1-2819-4dc9-97f5-8e2b2ceb2658@lunn.ch>
Hi Andrew,
Thanks for looking at this, and you're right - the runtime case is the
more dangerous one. If a genuine interface change (SGMII <-> 2500BASE-X)
happened at runtime while the disk was live, reprogramming the shared
ModPHY LCPLL would disturb the SATA PHY under an active filesystem, and
a failed boot would be preferable to that.
Two points of clarification:
- A plain switch change does not reprogram the ModPHY on my fixed-PHY
setup. mac_finish() only runs a real reconfiguration when the
MAC-side interface mode changes (e.g. a multi-rate SFP moving between
SGMII and 2500BASE-X). On a fixed copper PHY the interface mode does
not change, so changing the link partner / switch does not trigger
the reconfiguration.
- The runtime reconfiguration path is not introduced by this patch. It
came in with the Fixes: commit a42f6b3f1cc1 ("net: stmmac: configure
SerDes according to the interface mode"), which added
intel_mac_finish()/intel_set_reg_access() and the PMC LCPLL
reprogramming. v2 will only read the current SerDes rate back from
SERDES_GCR0 and skip the reconfiguration when it already matches the
selected interface. At boot that suppresses the redundant reprogram
that breaks SATA; for a real rate change, v2 leaves the
reconfiguration unchanged from mainline.
So for the runtime case you are worried about - a real ModPHY rate
change while SATA is live - this patch does not make things safer or
more dangerous; it only removes the spurious boot-time reprogramming.
The broader question of protecting a live SATA disk against a real
runtime ModPHY change is pre-existing, and I don't have a board that
combines a multi-rate SFP with SATA on the same ModPHY, so I can't
exercise or safely test a guard for that topology.
Given that, I'd like to keep this patch scoped to the boot regression
and leave the pre-existing shared-ModPHY-with-live-SATA question to the
maintainers, who have the hardware knowledge to decide whether a
stronger guard is warranted.
Thanks,
Markus
^ permalink raw reply
* [PATCH net] openvswitch: fix GSO userspace truncation underflow
From: Kyle Zeng @ 2026-07-07 22:16 UTC (permalink / raw)
To: netdev; +Cc: Aaron Conole, Eelco Chaudron, Ilya Maximets, Kyle Zeng, stable
OVS_ACTION_ATTR_TRUNC currently stores a delta from the original skb
length in OVS_CB(skb)->cutlen. When a later userspace action segments a
GSO skb, queue_gso_packets() reuses that delta for each smaller segment.
A segment can then reach queue_userspace_packet() with cutlen greater
than skb->len, underflowing the length passed to skb_zerocopy().
Store the maximum preserved length instead and bound each consumer
against the current skb length. Use U32_MAX as the no-truncation
sentinel so the value remains valid if skb geometry changes before a
consumer handles it.
Fixes: f2a4d086ed4c ("openvswitch: Add packet truncation support.")
Cc: stable@vger.kernel.org
Assisted-by: Codex:gpt-5.5
Signed-off-by: Kyle Zeng <kylebot@openai.com>
---
net/openvswitch/actions.c | 19 +++++++------------
net/openvswitch/datapath.c | 25 ++++++++++++++-----------
net/openvswitch/datapath.h | 2 +-
net/openvswitch/vport.c | 2 +-
4 files changed, 23 insertions(+), 25 deletions(-)
diff --git a/net/openvswitch/actions.c b/net/openvswitch/actions.c
index 140388a18ae0..513fca6a8e8a 100644
--- a/net/openvswitch/actions.c
+++ b/net/openvswitch/actions.c
@@ -837,12 +837,8 @@ static void do_output(struct datapath *dp, struct sk_buff *skb, int out_port,
u16 mru = OVS_CB(skb)->mru;
u32 cutlen = OVS_CB(skb)->cutlen;
- if (unlikely(cutlen > 0)) {
- if (skb->len - cutlen > ovs_mac_header_len(key))
- pskb_trim(skb, skb->len - cutlen);
- else
- pskb_trim(skb, ovs_mac_header_len(key));
- }
+ if (unlikely(cutlen < skb->len))
+ pskb_trim(skb, max(cutlen, ovs_mac_header_len(key)));
if (likely(!mru ||
(skb->len <= mru + vport->dev->hard_header_len))) {
@@ -1234,7 +1230,7 @@ static void execute_psample(struct datapath *dp, struct sk_buff *skb,
psample_group.net = ovs_dp_get_net(dp);
md.in_ifindex = OVS_CB(skb)->input_vport->dev->ifindex;
- md.trunc_size = skb->len - OVS_CB(skb)->cutlen;
+ md.trunc_size = min(skb->len, OVS_CB(skb)->cutlen);
md.rate_as_probability = 1;
rate = OVS_CB(skb)->probability ? OVS_CB(skb)->probability : U32_MAX;
@@ -1284,22 +1280,21 @@ static int do_execute_actions(struct datapath *dp, struct sk_buff *skb,
clone = skb_clone(skb, GFP_ATOMIC);
if (clone)
do_output(dp, clone, port, key);
- OVS_CB(skb)->cutlen = 0;
+ OVS_CB(skb)->cutlen = U32_MAX;
break;
}
case OVS_ACTION_ATTR_TRUNC: {
struct ovs_action_trunc *trunc = nla_data(a);
- if (skb->len > trunc->max_len)
- OVS_CB(skb)->cutlen = skb->len - trunc->max_len;
+ OVS_CB(skb)->cutlen = trunc->max_len;
break;
}
case OVS_ACTION_ATTR_USERSPACE:
output_userspace(dp, skb, key, a, attr,
len, OVS_CB(skb)->cutlen);
- OVS_CB(skb)->cutlen = 0;
+ OVS_CB(skb)->cutlen = U32_MAX;
if (nla_is_last(a, rem)) {
consume_skb(skb);
return 0;
@@ -1453,7 +1448,7 @@ static int do_execute_actions(struct datapath *dp, struct sk_buff *skb,
case OVS_ACTION_ATTR_PSAMPLE:
execute_psample(dp, skb, a);
- OVS_CB(skb)->cutlen = 0;
+ OVS_CB(skb)->cutlen = U32_MAX;
if (nla_is_last(a, rem)) {
consume_skb(skb);
return 0;
diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c
index f0164817d9b7..eaf332b156d7 100644
--- a/net/openvswitch/datapath.c
+++ b/net/openvswitch/datapath.c
@@ -276,7 +276,7 @@ void ovs_dp_process_packet(struct sk_buff *skb, struct sw_flow_key *key)
upcall.portid = ovs_vport_find_upcall_portid(p, skb);
upcall.mru = OVS_CB(skb)->mru;
- error = ovs_dp_upcall(dp, skb, key, &upcall, 0);
+ error = ovs_dp_upcall(dp, skb, key, &upcall, U32_MAX);
switch (error) {
case 0:
case -EAGAIN:
@@ -457,7 +457,8 @@ static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb,
struct sk_buff *nskb = NULL;
struct sk_buff *user_skb = NULL; /* to be queued to userspace */
struct nlattr *nla;
- size_t len;
+ size_t msg_size;
+ size_t skb_len;
unsigned int hlen;
int err, dp_ifindex;
u64 hash;
@@ -478,7 +479,8 @@ static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb,
skb = nskb;
}
- if (nla_attr_size(skb->len) > USHRT_MAX) {
+ skb_len = min(skb->len, cutlen);
+ if (nla_attr_size(skb_len) > USHRT_MAX) {
err = -EFBIG;
goto out;
}
@@ -493,13 +495,13 @@ static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb,
* padding logic. Only perform zerocopy if padding is not required.
*/
if (dp->user_features & OVS_DP_F_UNALIGNED)
- hlen = skb_zerocopy_headlen(skb);
+ hlen = min(skb_zerocopy_headlen(skb), cutlen);
else
- hlen = skb->len;
+ hlen = skb_len;
- len = upcall_msg_size(upcall_info, hlen - cutlen,
- OVS_CB(skb)->acts_origlen);
- user_skb = genlmsg_new(len, GFP_ATOMIC);
+ msg_size = upcall_msg_size(upcall_info, hlen,
+ OVS_CB(skb)->acts_origlen);
+ user_skb = genlmsg_new(msg_size, GFP_ATOMIC);
if (!user_skb) {
err = -ENOMEM;
goto out;
@@ -560,7 +562,7 @@ static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb,
}
/* Add OVS_PACKET_ATTR_LEN when packet is truncated */
- if (cutlen > 0 &&
+ if (skb_len < skb->len &&
nla_put_u32(user_skb, OVS_PACKET_ATTR_LEN, skb->len)) {
err = -ENOBUFS;
goto out;
@@ -585,9 +587,9 @@ static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb,
err = -ENOBUFS;
goto out;
}
- nla->nla_len = nla_attr_size(skb->len - cutlen);
+ nla->nla_len = nla_attr_size(skb_len);
- err = skb_zerocopy(user_skb, skb, skb->len - cutlen, hlen);
+ err = skb_zerocopy(user_skb, skb, skb_len, hlen);
if (err)
goto out;
@@ -644,6 +646,7 @@ static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info)
packet->ignore_df = 1;
}
OVS_CB(packet)->mru = mru;
+ OVS_CB(packet)->cutlen = U32_MAX;
if (a[OVS_PACKET_ATTR_HASH]) {
hash = nla_get_u64(a[OVS_PACKET_ATTR_HASH]);
diff --git a/net/openvswitch/datapath.h b/net/openvswitch/datapath.h
index db0c3e69d66c..696640e88fa7 100644
--- a/net/openvswitch/datapath.h
+++ b/net/openvswitch/datapath.h
@@ -118,7 +118,7 @@ struct datapath {
* @mru: The maximum received fragement size; 0 if the packet is not
* fragmented.
* @acts_origlen: The netlink size of the flow actions applied to this skb.
- * @cutlen: The number of bytes from the packet end to be removed.
+ * @cutlen: The number of bytes in the packet to preserve on output.
* @probability: The sampling probability that was applied to this skb; 0 means
* no sampling has occurred; U32_MAX means 100% probability.
* @upcall_pid: Netlink socket PID to use for sending this packet to userspace;
diff --git a/net/openvswitch/vport.c b/net/openvswitch/vport.c
index 56b2e2d1a749..12741485c939 100644
--- a/net/openvswitch/vport.c
+++ b/net/openvswitch/vport.c
@@ -502,7 +502,7 @@ int ovs_vport_receive(struct vport *vport, struct sk_buff *skb,
OVS_CB(skb)->input_vport = vport;
OVS_CB(skb)->mru = 0;
- OVS_CB(skb)->cutlen = 0;
+ OVS_CB(skb)->cutlen = U32_MAX;
OVS_CB(skb)->probability = 0;
OVS_CB(skb)->upcall_pid = 0;
if (unlikely(dev_net(skb->dev) != ovs_dp_get_net(vport->dp))) {
--
2.54.0
^ permalink raw reply related
* Re: [PATCH v14 0/9] tls: Add TLS 1.3 hardware offload support
From: Rishikesh Jethwani @ 2026-07-07 22:21 UTC (permalink / raw)
To: Nils Juenemann
Cc: netdev, borisp, davem, edumazet, john.fastabend, kuba, leon,
mbloch, saeedm, sd, tariqt
In-Reply-To: <CAKaoeS1dxK+SLrUPdE1J16TpL_M5mj8JTccL7C2OzfnNQEFNSQ@mail.gmail.com>
On Thu, Jun 25, 2026 at 3:57 PM Rishikesh Jethwani
<rjethwani@everpuredata.com> wrote:
>
> On Tue, Jun 23, 2026 at 10:53 AM Nils Juenemann
> <nils.juenemann@gmail.com> wrote:
> >
> > Hi Rishikesh, all,
> >
> > we have been testing the v14 TLS 1.3 HW offload series on a ConnectX-6
> > DX and hit a sendfile() final-record loss on the device TX path. We
> > reduced it to a self-contained C reproducer and characterized it;
> > reporting it here with the analysis and a question on where a fix belongs.
> >
> > Setup:
> >
> > NIC: ConnectX-6 DX (crypto enabled), FW 22.47.1026, SR-IOV VF,
> > TX offload only
> >
> > Kernel: net-next + this v14 series
> >
> > TLS 1.3, AES-128-GCM, kTLS installed via setsockopt(TLS_TX) on the
> > sending side with fixed test crypto material and no handshake, like
> > tools/testing/selftests/net/tls
> >
> > a server sends a file with the raw sendfile(2) syscall; a client on
> > another host reads the decrypted stream and counts the bytes
> >
> > Trigger: sendfile(2) with a count larger than the bytes remaining in
> > the file (count > EOF). This is what a generic copy loop / Go's
> > net.TCPConn.ReadFrom passes for a file of unknown length (~2 GiB). The
> > kernel sends up to EOF, but the connection's final TLS record then
> > appears not to be put on the wire unless a subsequent write flushes it.
> > An abrupt close() appears to drop it, and the peer receives the whole
> > body except the last record's bytes.
> >
> > Reproducer results (two hosts over the ConnectX - a loopback/same-host
> > connection stays on TLS_SW and does not show it). Same file, 226965
> > bytes (= 13*16384 + 13973):
> >
> > TLS_HW count>EOF close() -> 212992 short
> > TLS_HW count>EOF close(), no zerocopy -> 212992 same
> > TLS_HW count==exact close() -> 226965 full
> > TLS_HW count>EOF close_notify, then close() -> 226965 full
> > TLS_SW count>EOF close(), hw-tx-offload off -> 226965 full
> >
> > So it is specific to the device-offload TX path: the final record of a
> > count > EOF sendfile() appears not to be finalized/flushed at EOF, only
> > by a following write. A bounded count, a trailing write (close_notify),
> > or software kTLS all avoid it. TLS_TX_ZEROCOPY_RO makes no difference.
> > We are currently using the exact-count workaround in a preview environment.
> >
> > We may be misreading the code, so this is only a pointer: with
> > count > EOF tls_push_data() fills the last record without reaching the
> > size==0 case; on the device path tls_device_record_close() for that
> > pending record appears to run only on the next push, and an abrupt
> > teardown appears to discard it. The software path seems to flush
> > pending TX records on close (tls_sw_release_resources_tx), which would
> > explain why it is unaffected.
> >
> > Reproducer:
> > https://gist.github.com/totallyunknown/a8f0ad3c54e40befde2f5a8d360fa6be
> >
> > It installs kTLS with fixed test crypto material via
> > setsockopt(TLS_TX/TLS_RX), sends a file using the raw sendfile(2)
> > syscall, and compares count > EOF against exact-count and close_notify.
> > The v14 selftest (patch 9/9) sends via send() only and ends cleanly, so
> > it misses this; a sendfile() + count > EOF case reproduces it
> > deterministically for us.
> >
> > Question: should the device offload finalize and flush the connection's
> > final record at EOF / on close, the way software kTLS does, or is a
> > trailing write required by contract? And should a fix live in net/tls
> > (device record close on the final partial record / the close path) or
> > on the mlx5 side?
> >
>
> close() should be sufficient here.
> I will fix this in net/tls/tls_device.c:tls_device_splice_eof().
> tls_device_splice_eof() only checked tls_is_partially_sent_record(),
> but it also needs to handle tls_is_pending_open_record()
> (pending_open_record_frags). On the device TX path, that state occurs
> when tls_push_data() exits with MSG_MORE set, which is what
> splice/sendfile does while count > EOF still leaves requested bytes
> outstanding.
> So EOF can be reached with a final open record still pending. The fix
> is to close and push that record from tls_device_splice_eof(), so
> close() remains sufficient and no trailing write is required.
Patch:
tls: device: push pending open record on splice EOF
diff --git a/net/tls/tls_device.c b/net/tls/tls_device.c
index aa4ef04e9c43..0d43ebf67b8b 100644
--- a/net/tls/tls_device.c
+++ b/net/tls/tls_device.c
@@ -794,13 +794,15 @@ void tls_device_splice_eof(struct socket *sock)
struct tls_context *tls_ctx = tls_get_ctx(sk);
struct iov_iter iter = {};
- if (!tls_is_partially_sent_record(tls_ctx))
+ if (!tls_is_partially_sent_record(tls_ctx) &&
+ !tls_is_pending_open_record(tls_ctx))
return;
mutex_lock(&tls_ctx->tx_lock);
lock_sock(sk);
- if (tls_is_partially_sent_record(tls_ctx)) {
+ if (tls_is_partially_sent_record(tls_ctx) ||
+ tls_is_pending_open_record(tls_ctx)) {
iov_iter_bvec(&iter, ITER_SOURCE, NULL, 0, 0);
tls_push_data(sk, &iter, 0, 0, TLS_RECORD_TYPE_DATA);
}
^ permalink raw reply related
* [PATCH net-next v5 02/13] net: ethernet: oa_tc6: Handle the OA TC6 SPI protected mode
From: Ciprian Regus via B4 Relay @ 2026-07-07 22:33 UTC (permalink / raw)
To: Parthiban Veerasooran, Andrew Lunn, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Jonathan Corbet,
Shuah Khan, Andrew Lunn, Heiner Kallweit, Russell King,
Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: netdev, linux-kernel, linux-doc, devicetree, Ciprian Regus
In-Reply-To: <20260708-adin1140-driver-v5-0-4aca7b51a58b@analog.com>
From: Ciprian Regus <ciprian.regus@analog.com>
Implement the OA TC6 standard defined protected mode for control (register
access) transactions. In addition to the current register access formats
the oa_tc6 driver handles, 1's complement values of the data field
are included (by both the host and the MACPHY) in the SPI transfer frames.
This feature acts as an integrity check.
Control write transactions look like this:
|<- 32 bits ->|<--- data_size --->|<- 32 bits ->|
MOSI: | ctrl header | reg write data | ignored |
MISO: | (discard) | echoed ctrl hdr | echoed data |
data_size (LEN = number of registers to read in a sequence):
Unprotected: 32 x (LEN + 1) bits
Protected: 2 x 32 x (LEN + 1) bits
Control read transaction:
|<- 32 bits ->|<--- 32 bits --> |<- data_size ->|
MOSI: | ctrl header | ignored ... |
MISO: | (discard) | echoed ctrl hdr | reg read data |
data_size (LEN = number of registers to read in a sequence):
Unprotected: 32 x (LEN + 1) bits
Protected: 2 x 32 x (LEN + 1) bits
Register data format ("reg write data" and "reg read data"):
Unprotected:
| W1 (normal) | W2 (normal) | ... | Wx (normal) |
Protected:
| W1 (normal) | W1 (complement) | ... | Wx (normal) | Wx (complement)|
The protected mode state can be read from the bit 5 of CONFIG0 (0x4)
register, and this setting is usually only configured during the
MACPHY's reset (depending on the device it can be done by setting the
state of a pin). We can read the protected mode configuration before any
other register access and since the SPI transfer is initially sized for an
unprotected read, the MACPHY's complement words are never clocked out
and no checking is required. The data transactions (Ethernet frames)
remain unchanged.
Signed-off-by: Ciprian Regus <ciprian.regus@analog.com>
---
v5 changelog:
- no change
v4 changelog:
- no change
v3 changelog:
- no change
v2 changelog:
- Updated OA_TC6_CTRL_SPI_BUF_SIZE to always alloc the control
transaction buffer size required by the protected mode, instead of
calling krealloc if the PROTE bit is set.
- Formatting to fit the 80 character column limit.
---
drivers/net/ethernet/oa_tc6.c | 93 +++++++++++++++++++++++++++++++++++--------
1 file changed, 76 insertions(+), 17 deletions(-)
diff --git a/drivers/net/ethernet/oa_tc6.c b/drivers/net/ethernet/oa_tc6.c
index 0727d53345a3..8b9655883496 100644
--- a/drivers/net/ethernet/oa_tc6.c
+++ b/drivers/net/ethernet/oa_tc6.c
@@ -25,6 +25,7 @@
#define OA_TC6_REG_CONFIG0 0x0004
#define CONFIG0_SYNC BIT(15)
#define CONFIG0_ZARFE_ENABLE BIT(12)
+#define CONFIG0_PROTE BIT(5)
/* Status Register #0 */
#define OA_TC6_REG_STATUS0 0x0008
@@ -90,14 +91,17 @@
#define OA_TC6_PHY_C45_AUTO_NEG_MMS5 5 /* MMD 7 */
#define OA_TC6_PHY_C45_POWER_UNIT_MMS6 6 /* MMD 13 */
+#define OA_TC6_CTRL_PROT_REPLY_SIZE 4
#define OA_TC6_CTRL_HEADER_SIZE 4
#define OA_TC6_CTRL_REG_VALUE_SIZE 4
#define OA_TC6_CTRL_IGNORED_SIZE 4
#define OA_TC6_CTRL_MAX_REGISTERS 128
-#define OA_TC6_CTRL_SPI_BUF_SIZE (OA_TC6_CTRL_HEADER_SIZE +\
- (OA_TC6_CTRL_MAX_REGISTERS *\
- OA_TC6_CTRL_REG_VALUE_SIZE) +\
- OA_TC6_CTRL_IGNORED_SIZE)
+#define OA_TC6_CTRL_SPI_BUF_SIZE (OA_TC6_CTRL_HEADER_SIZE +\
+ (OA_TC6_CTRL_MAX_REGISTERS *\
+ (OA_TC6_CTRL_REG_VALUE_SIZE +\
+ OA_TC6_CTRL_PROT_REPLY_SIZE)) +\
+ OA_TC6_CTRL_IGNORED_SIZE)
+
#define OA_TC6_CHUNK_PAYLOAD_SIZE 64
#define OA_TC6_DATA_HEADER_SIZE 4
#define OA_TC6_CHUNK_SIZE (OA_TC6_DATA_HEADER_SIZE +\
@@ -130,6 +134,7 @@ struct oa_tc6 {
bool rx_buf_overflow;
bool int_flag;
bool disable_traffic;
+ bool prot_ctrl;
};
enum oa_tc6_header_type {
@@ -213,25 +218,36 @@ static void oa_tc6_update_ctrl_write_data(struct oa_tc6 *tc6, u32 value[],
{
__be32 *tx_buf = tc6->spi_ctrl_tx_buf + OA_TC6_CTRL_HEADER_SIZE;
- for (int i = 0; i < length; i++)
+ for (int i = 0; i < length; i++) {
*tx_buf++ = cpu_to_be32(value[i]);
+ if (tc6->prot_ctrl)
+ *tx_buf++ = cpu_to_be32(~value[i]);
+ }
}
-static u16 oa_tc6_calculate_ctrl_buf_size(u8 length)
+static u16 oa_tc6_calculate_ctrl_buf_size(u8 length, bool ctrl_prot)
{
+ u32 reply_size = OA_TC6_CTRL_REG_VALUE_SIZE;
+
+ if (ctrl_prot)
+ reply_size += OA_TC6_CTRL_PROT_REPLY_SIZE;
+
/* Control command consists 4 bytes header + 4 bytes register value for
- * each register + 4 bytes ignored value.
+ * each register (+ 4 bytes for the register value complement in case
+ * protected mode is used) + 4 bytes ignored value.
*/
- return OA_TC6_CTRL_HEADER_SIZE + OA_TC6_CTRL_REG_VALUE_SIZE * length +
+ return OA_TC6_CTRL_HEADER_SIZE + reply_size * length +
OA_TC6_CTRL_IGNORED_SIZE;
}
static void oa_tc6_prepare_ctrl_spi_buf(struct oa_tc6 *tc6, u32 address,
u32 value[], u8 length,
- enum oa_tc6_register_op reg_op)
+ enum oa_tc6_register_op reg_op,
+ u16 buf_size)
{
__be32 *tx_buf = tc6->spi_ctrl_tx_buf;
+ memset(tx_buf, 0, buf_size);
*tx_buf = oa_tc6_prepare_ctrl_header(address, length, reg_op);
if (reg_op == OA_TC6_CTRL_REG_WRITE)
@@ -254,10 +270,12 @@ static int oa_tc6_check_ctrl_write_reply(struct oa_tc6 *tc6, u8 size)
return 0;
}
-static int oa_tc6_check_ctrl_read_reply(struct oa_tc6 *tc6, u8 size)
+static int oa_tc6_check_ctrl_read_reply(struct oa_tc6 *tc6, u8 length)
{
- u32 *rx_buf = tc6->spi_ctrl_rx_buf + OA_TC6_CTRL_IGNORED_SIZE;
- u32 *tx_buf = tc6->spi_ctrl_tx_buf;
+ __be32 *rx_buf = tc6->spi_ctrl_rx_buf + OA_TC6_CTRL_IGNORED_SIZE;
+ __be32 *tx_buf = tc6->spi_ctrl_tx_buf;
+ u32 complement;
+ u32 reply;
/* The echoed control read header must match with the one that was
* transmitted.
@@ -265,6 +283,20 @@ static int oa_tc6_check_ctrl_read_reply(struct oa_tc6 *tc6, u8 size)
if (*tx_buf != *rx_buf)
return -EPROTO;
+ if (tc6->prot_ctrl) {
+ /* Skip past the echoed header to the value/complement pairs */
+ rx_buf += 1;
+ for (int i = 0; i < length; i++) {
+ reply = be32_to_cpu(rx_buf[0]);
+ complement = be32_to_cpu(rx_buf[1]);
+
+ if (complement != ~reply)
+ return -EPROTO;
+
+ rx_buf += 2;
+ }
+ }
+
return 0;
}
@@ -274,8 +306,13 @@ static void oa_tc6_copy_ctrl_read_data(struct oa_tc6 *tc6, u32 value[],
__be32 *rx_buf = tc6->spi_ctrl_rx_buf + OA_TC6_CTRL_IGNORED_SIZE +
OA_TC6_CTRL_HEADER_SIZE;
- for (int i = 0; i < length; i++)
+ for (int i = 0; i < length; i++) {
value[i] = be32_to_cpu(*rx_buf++);
+
+ /* skip complement word */
+ if (tc6->prot_ctrl)
+ rx_buf++;
+ }
}
static int oa_tc6_perform_ctrl(struct oa_tc6 *tc6, u32 address, u32 value[],
@@ -284,10 +321,10 @@ static int oa_tc6_perform_ctrl(struct oa_tc6 *tc6, u32 address, u32 value[],
u16 size;
int ret;
- /* Prepare control command and copy to SPI control buffer */
- oa_tc6_prepare_ctrl_spi_buf(tc6, address, value, length, reg_op);
+ size = oa_tc6_calculate_ctrl_buf_size(length, tc6->prot_ctrl);
- size = oa_tc6_calculate_ctrl_buf_size(length);
+ /* Prepare control command and copy to SPI control buffer */
+ oa_tc6_prepare_ctrl_spi_buf(tc6, address, value, length, reg_op, size);
/* Perform SPI transfer */
ret = oa_tc6_spi_transfer(tc6, OA_TC6_CTRL_HEADER, size);
@@ -302,7 +339,7 @@ static int oa_tc6_perform_ctrl(struct oa_tc6 *tc6, u32 address, u32 value[],
return oa_tc6_check_ctrl_write_reply(tc6, size);
/* Check echoed/received control read command reply for errors */
- ret = oa_tc6_check_ctrl_read_reply(tc6, size);
+ ret = oa_tc6_check_ctrl_read_reply(tc6, length);
if (ret)
return ret;
@@ -1272,6 +1309,20 @@ netdev_tx_t oa_tc6_start_xmit(struct oa_tc6 *tc6, struct sk_buff *skb)
}
EXPORT_SYMBOL_GPL(oa_tc6_start_xmit);
+static int oa_tc6_check_ctrl_protection(struct oa_tc6 *tc6)
+{
+ u32 regval;
+ int ret;
+
+ ret = oa_tc6_read_register(tc6, OA_TC6_REG_CONFIG0, ®val);
+ if (ret)
+ return ret;
+
+ tc6->prot_ctrl = FIELD_GET(CONFIG0_PROTE, regval);
+
+ return 0;
+}
+
/**
* oa_tc6_init - allocates and initializes oa_tc6 structure.
* @spi: device with which data will be exchanged.
@@ -1324,6 +1375,14 @@ struct oa_tc6 *oa_tc6_init(struct spi_device *spi, struct net_device *netdev)
if (!tc6->spi_data_rx_buf)
return NULL;
+ /* Check the PROTE bit status so that we can reset the device */
+ ret = oa_tc6_check_ctrl_protection(tc6);
+ if (ret) {
+ dev_err(&tc6->spi->dev,
+ "Failed to check the protection mode: %d\n", ret);
+ return NULL;
+ }
+
ret = oa_tc6_sw_reset_macphy(tc6);
if (ret) {
dev_err(&tc6->spi->dev,
--
2.43.0
^ permalink raw reply related
* [PATCH net-next v5 01/13] dt-bindings: net: Add ADIN1140
From: Ciprian Regus via B4 Relay @ 2026-07-07 22:33 UTC (permalink / raw)
To: Parthiban Veerasooran, Andrew Lunn, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Jonathan Corbet,
Shuah Khan, Andrew Lunn, Heiner Kallweit, Russell King,
Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: netdev, linux-kernel, linux-doc, devicetree, Ciprian Regus,
Conor Dooley
In-Reply-To: <20260708-adin1140-driver-v5-0-4aca7b51a58b@analog.com>
From: Ciprian Regus <ciprian.regus@analog.com>
The ADIN1140 is a single port 10BASE-T1S Ethernet controller that
includes both the MAC and a PHY in the same package.
Reviewed-by: Conor Dooley <conor.dooley@microchip.com>
Signed-off-by: Ciprian Regus <ciprian.regus@analog.com>
---
v5:
- no change
v4 changelog:
- renamed the dt bindings file after the fallback compatible device
(adi,ad3306).
v3 changelog:
- set adi,ad3306 as a fallback compatible.
v2 changelog:
- Reorder the compatible entries in the dt schema (ad3306, adin1140).
- Removed "dt-bindings" from the commit title and message.
- Updated the DT example to use IRQ_TYPE_LEVEL_LOW instead of
IRQ_TYPE_EDGE_FALLING for the interrupt trigger condition.
- "implements" -> "tries to implement" in the description.
- Removed the MAINTAINERS entry, as it will be added in a later patch
in the series.
- Reordered as the first patch of the series
---
.../devicetree/bindings/net/adi,ad3306.yaml | 71 ++++++++++++++++++++++
1 file changed, 71 insertions(+)
diff --git a/Documentation/devicetree/bindings/net/adi,ad3306.yaml b/Documentation/devicetree/bindings/net/adi,ad3306.yaml
new file mode 100644
index 000000000000..785d05c995db
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/adi,ad3306.yaml
@@ -0,0 +1,71 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/net/adi,ad3306.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: ADI ADIN1140 10BASE-T1S MAC-PHY
+
+maintainers:
+ - Ciprian Regus <ciprian.regus@analog.com>
+
+description: |
+ The ADIN1140 (also called AD3306) is a low power single port
+ 10BASE-T1S MAC-PHY. It integrates an Ethernet PHY with a MAC
+ and all the associated analog circuitry.
+ The device tries to implement the Open Alliance TC6 10BASE-T1x MAC-PHY
+ Serial Interface specification and is compliant with the
+ IEEE 802.3cg-2019 Ethernet standard for 10 Mbps single pair
+ Ethernet (SPE). The device has a 4-wire SPI interface for
+ communication between the MAC and host processor.
+
+allOf:
+ - $ref: /schemas/net/ethernet-controller.yaml#
+ - $ref: /schemas/spi/spi-peripheral-props.yaml#
+
+properties:
+ compatible:
+ oneOf:
+ - items:
+ - const: adi,adin1140
+ - const: adi,ad3306
+ - const: adi,ad3306
+
+ reg:
+ maxItems: 1
+
+ spi-max-frequency:
+ maximum: 25000000
+
+ interrupts:
+ maxItems: 1
+ description: Interrupt from the MAC-PHY for receive data available
+ and error conditions
+
+required:
+ - compatible
+ - reg
+ - interrupts
+ - spi-max-frequency
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/interrupt-controller/irq.h>
+
+ spi {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ ethernet@0 {
+ compatible = "adi,ad3306";
+ reg = <0>;
+ spi-max-frequency = <23000000>;
+
+ interrupt-parent = <&gpio>;
+ interrupts = <6 IRQ_TYPE_LEVEL_LOW>;
+
+ local-mac-address = [ 00 11 22 33 44 55 ];
+ };
+ };
--
2.43.0
^ permalink raw reply related
* [PATCH net-next v5 00/13] net: Add ADIN1140 support
From: Ciprian Regus via B4 Relay @ 2026-07-07 22:33 UTC (permalink / raw)
To: Parthiban Veerasooran, Andrew Lunn, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Jonathan Corbet,
Shuah Khan, Andrew Lunn, Heiner Kallweit, Russell King,
Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: netdev, linux-kernel, linux-doc, devicetree, Ciprian Regus,
Conor Dooley
This series introduces support for the ADIN1140 (also called AD3306)
10BASE-T1S single port MACPHY. The device integrates the MAC and PHY in
the same package. The communication with the host CPU is done through an
SPI interface, using the Open Alliance TC6 protocol for control and data
transactions. As a result, the oa_tc6 framework is used to implement
the communication with the device (register accesses and Ethernet frame
RX/TX).
The MAC and PHY are connected internally using an MII and MDIO bus.
The PHY is a half duplex 10Mbps device, which implements both the PLCA
RS (IEEE 802.3 clause 148) and CSMA/CD methods of accessing the Ethernet
medium. The 10BASE-T1S standard allows multiple PHY devices to be
connected (in parallel) on the same single twisted pair network segment,
so PLCA can be configured in order to provide a fair access scheme to
all the nodes and reduce the jitter introduced by the unordered CSMA/CD
transmits. The PHY's internal register map can be accessed using the
direct MDIO mode of the OA TC6. The control, status, phy id 1 & 2 C22
registers are mapped to the 0xFF00 - 0xFF03 range. As for C45
addressable devices, the PHY has PCS, PMA and PLCA blocks.
The oa_tc6 framework patches are changes that would make the library
usable by the subsequent ADIN1140 MAC driver.
The protected mode patch is required because the ADIN1140 only allows
protected mode OA TC6 control transactions, which the oa_tc6 framework
doesn't currently implement.
The OA_TC6_BROKEN_PHY quirk patch is required in order to allow the MAC
driver to have a custom implementation for the mii_bus access methods as a
workaround for hardware issues:
1. The OA TC6 standard defines the direct and indirect access modes for
MDIO transactions. The ADIN1140 incorrectly advertises indirect mode
only (supported capabilities register - 0x2, bit 9), while actually
implementing just the direct mode. We cannot rely on the CAP register
to choose an access method (which oa_tc6 does by default, even though
it only implements the direct mode), so the driver has to use its
own.
2. The ADIN1140 cannot access the C22 register space of the internal
PHY, while the PHY is busy receiving frames. If that happens, the
CONFIG0 and CONFIG2 registers of the MAC will get corrupted and the
data transfer will stop. Those two registers configure settings for
the transfer protocol between the MAC and host, so the value for some
of their subfields shouldn't be changed while the netdev is up.
Since we know the PHY is internal, the MAC driver can implement a
custom mii_bus, which can intercept C22 accesses. Most of the
registers mapped in the 0x0 - 0x3 range (the only ones the PHY offers)
are read only, and their value can be read from somewhere else (e.g
the PHYID 1 & 2 have the same value as 0x1 in the MAC memory map).
C45 accesses do not cause this issue, so we can properly implement
them.
Even though they have different driver, the MAC one cannot function
without the PHY driver, since the PHY is not compatible with the generic
c22 driver. As such CONFIG_ADIN1140 selects CONFIG_ADIN1140_PHY.
Signed-off-by: Ciprian Regus <ciprian.regus@analog.com>
---
Changes in v5:
- Used ndo_set_rx_mode_async instead of ndo_set_rx_mode for configuring
the MAC filter table in the adin1140 driver.
- Updated the MAC filter logic to allow setting individual
unicast/multicast entries when IFF_ALLMULTI is enabled.
- Configured the MAC hardware to clear statistics registers on read and
accumulated the values in the software stats counter.
- Removed some MAC statistics counters from the custom ethtool strings,
since they were already included in the standard set.
- Link to v4: https://lore.kernel.org/r/20260609-adin1140-driver-v4-0-0753e28ee004@analog.com
Changes in v4:
- Renamed the dt bindings file after the adi,ad3306 compatible.
- Renamed a few register address macros to match the OA TC6 standard and
the ADIN1140 reference manual.
- Link to v3: https://lore.kernel.org/r/20260604-adin1140-driver-v3-0-5debdb3173c4@analog.com
Changes in v3:
- Added adi,ad3306 as a fallback compatible in the DT schema.
- Keep the current spi_device and net_device parameters for
oa_tc6_init() and add a new struct parameter for passing the quirk
flags, insted of changing the function to take a single config
parameter.
- Add the oa_tc6_write_register_mms() and oa_tc6_read_register_mms()
functions instead of defining a new macro for MMS and register address
formatting.
- Split the OA TC6 register address macro exports patch into two
different commits (export + rename).
- Use the devres API for mii_bus and net_device management in the
ADIN1140 driver.
- Fix a bug related to the destination MAC filter mask in the ADIN1140
driver.
- Link to v2: https://lore.kernel.org/r/20260527-adin1140-driver-v2-0-37e5c8d4e0a0@analog.com
Changes in v2:
- Add the OA_TC6_BROKEN_PHY quirk flag to the oa_tc6 framework in order
to allow ethernet drivers to manage their own mii_bus struct and PHY.
- Move the OA TC6 standard register definitions in the oa_tc6.h header
so other drivers can use them. Do the same for the C45 access
functions
- Add the genphy_read_mmd_c45 and genphy_write_mmd_c45 functions to
genphy, which allow drivers that have been discovered over C22 to make
direct C45 operations, without using the 0xD and 0xE register. The
change was implemented based on the suggestion in this thread:
https://lore.kernel.org/all/CY8PR02MB9249CDA8F2C560FDD0F662D883382@CY8PR02MB9249.namprd02.prod.outlook.com/
- Link to v1: https://lore.kernel.org/r/20260503-adin1140-driver-v1-0-dd043cdd88f0@analog.com
---
Ciprian Regus (13):
dt-bindings: net: Add ADIN1140
net: ethernet: oa_tc6: Handle the OA TC6 SPI protected mode
net: ethernet: oa_tc6: add OA_TC6_BROKEN_PHY quirk flag
net: ethernet: oa_tc6: Export the C45 access functions
net: ethernet: oa_tc6: Export standard defined registers
net: ethernet: oa_tc6: Add the OA_TC6_ prefix to standard registers
net: ethernet: oa_tc6: Add read_mms/write_mms register access functions
net: ethernet: oa_tc6: Use the read_mms/write_mms functions for C45
net: ethernet: oa_tc6: Add new register address defines
net: phy: add generic helpers for direct C45 MMD access
net: phy: microchip-t1s: use generic C45 MMD access helpers
net: phy: Add support for the ADIN1140 PHY
net: ethernet: adi: Add a driver for the ADIN1140 MACPHY
.../devicetree/bindings/net/adi,ad3306.yaml | 71 ++
Documentation/networking/oa-tc6-framework.rst | 3 +-
MAINTAINERS | 15 +
drivers/net/ethernet/adi/Kconfig | 12 +
drivers/net/ethernet/adi/Makefile | 1 +
drivers/net/ethernet/adi/adin1140.c | 791 +++++++++++++++++++++
drivers/net/ethernet/microchip/lan865x/lan865x.c | 2 +-
drivers/net/ethernet/oa_tc6.c | 263 ++++---
drivers/net/phy/Kconfig | 6 +
drivers/net/phy/Makefile | 1 +
drivers/net/phy/adin1140-phy.c | 72 ++
drivers/net/phy/microchip_t1s.c | 32 +-
drivers/net/phy/phy_device.c | 25 +
include/linux/oa_tc6.h | 73 +-
include/linux/phy.h | 3 +
15 files changed, 1240 insertions(+), 130 deletions(-)
---
base-commit: 538d89fd914610852a6fb20b823ba70566153d46
change-id: 20260429-adin1140-driver-93ae0d376318
Best regards,
--
Ciprian Regus <ciprian.regus@analog.com>
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox