* [PATCH net] netlink: specs: rt-link: convert bridge port flag attributes to u8
From: Danielle Ratson @ 2026-07-07 8:03 UTC (permalink / raw)
To: netdev
Cc: donald.hunter, kuba, davem, edumazet, pabeni, horms, razor, petrm,
nikolay, idosch, bridge, linux-kernel, Danielle Ratson
A number of IFLA_BRPORT_* attributes are documented in the rt-link spec
as having the "flag" type, i.e. a payload-less NLA_FLAG attribute whose
meaning is presence-only. This does not match the kernel, which emits
these attributes with nla_put_u8() and validates them as NLA_U8 in
br_port_policy[]. The values are not mere presence flags but carry a u8
payload (0/1).
Convert these bridge port attributes from "flag" to "u8" so the spec
reflects the actual wire format.
Fixes: 077b6022d24b ("doc/netlink/specs: Add sub-message type to rt_link family")
Assisted-by: Claude:claude-opus-4-8
Reviewed-by: Petr Machata <petrm@nvidia.com>
Acked-by: Nikolay Aleksandrov <nikolay@nvidia.com>
Reviewed-by: Ido Schimmel <idosch@nvidia.com>
Signed-off-by: Danielle Ratson <danieller@nvidia.com>
---
Documentation/netlink/specs/rt-link.yaml | 40 ++++++++++++------------
1 file changed, 20 insertions(+), 20 deletions(-)
diff --git a/Documentation/netlink/specs/rt-link.yaml b/Documentation/netlink/specs/rt-link.yaml
index 892979da098e..68c26a70bb64 100644
--- a/Documentation/netlink/specs/rt-link.yaml
+++ b/Documentation/netlink/specs/rt-link.yaml
@@ -1585,31 +1585,31 @@ attribute-sets:
type: u32
-
name: mode
- type: flag
+ type: u8
-
name: guard
- type: flag
+ type: u8
-
name: protect
- type: flag
+ type: u8
-
name: fast-leave
- type: flag
+ type: u8
-
name: learning
- type: flag
+ type: u8
-
name: unicast-flood
- type: flag
+ type: u8
-
name: proxyarp
- type: flag
+ type: u8
-
name: learning-sync
- type: flag
+ type: u8
-
name: proxyarp-wifi
- type: flag
+ type: u8
-
name: root-id
type: binary
@@ -1656,34 +1656,34 @@ attribute-sets:
type: pad
-
name: mcast-flood
- type: flag
+ type: u8
-
name: mcast-to-ucast
- type: flag
+ type: u8
-
name: vlan-tunnel
- type: flag
+ type: u8
-
name: bcast-flood
- type: flag
+ type: u8
-
name: group-fwd-mask
type: u16
-
name: neigh-suppress
- type: flag
+ type: u8
-
name: isolated
- type: flag
+ type: u8
-
name: backup-port
type: u32
-
name: mrp-ring-open
- type: flag
+ type: u8
-
name: mrp-in-open
- type: flag
+ type: u8
-
name: mcast-eht-hosts-limit
type: u32
@@ -1692,10 +1692,10 @@ attribute-sets:
type: u32
-
name: locked
- type: flag
+ type: u8
-
name: mab
- type: flag
+ type: u8
-
name: mcast-n-groups
type: u32
@@ -1704,7 +1704,7 @@ attribute-sets:
type: u32
-
name: neigh-vlan-suppress
- type: flag
+ type: u8
-
name: backup-nhid
type: u32
--
2.54.0
^ permalink raw reply related
* Re: [PATCH net-next v8 9/9] selftests: net: Add a test for BIG TCP in UDP tunnels
From: Paolo Abeni @ 2026-07-07 8:06 UTC (permalink / raw)
To: Alice Mikityanska, Daniel Borkmann, David S. Miller, Eric Dumazet,
Jakub Kicinski, Xin Long, Willem de Bruijn, Willem de Bruijn,
David Ahern, Nikolay Aleksandrov
Cc: Shuah Khan, Stanislav Fomichev, Andrew Lunn, Simon Horman,
Florian Westphal, netdev, Alice Mikityanska
In-Reply-To: <20260706181941.385672-10-alice.kernel@fastmail.im>
On 7/6/26 8:19 PM, Alice Mikityanska wrote:
> From: Alice Mikityanska <alice@isovalent.com>
>
> The test sets up VXLAN and GENEVE tunnels over IPv4 and IPv6 and runs
> IPv4 and IPv6 traffic through them with BIG TCP enabled. It checks that
> a non-negligible amount of big aggregated packets are seen in tcpdump.
>
> Check the number of packets on both TX and RX sides to verify that GSO
> packets are valid and not dropped. Capture on the lower netdev (veth),
> when checksum offload is on, to verify that encapsulated BIG TCP packets
> can get to their destination. In the test with TX checksum offload off,
> software GSO splits aggregated VXLAN packets before passing them to
> veth, so capture inside the tunnel instead to check that the big packets
> are not dropped.
>
> Check that the amount of SACKs is negligible. On unsupported kernels,
> some amount of broken GSO packets bigger than 65536 bytes can be
> produced in VXLAN tunnels, but they don't reach the destination. Seeing
> TCP SACKs is a sign that such packets could have been dropped (in such
> cases, the amount of SACKs is a few times bigger than the number of
> attempts to send BIG TCP packets).
>
> Signed-off-by: Alice Mikityanska <alice@isovalent.com>
> ---
> tools/testing/selftests/net/Makefile | 1 +
> .../testing/selftests/net/big_tcp_tunnels.sh | 183 ++++++++++++++++++
> 2 files changed, 184 insertions(+)
> create mode 100755 tools/testing/selftests/net/big_tcp_tunnels.sh
>
> diff --git a/tools/testing/selftests/net/Makefile b/tools/testing/selftests/net/Makefile
> index 708d960ae07d..4cb0a0bc1eea 100644
> --- a/tools/testing/selftests/net/Makefile
> +++ b/tools/testing/selftests/net/Makefile
> @@ -13,6 +13,7 @@ TEST_PROGS := \
> arp_ndisc_untracked_subnets.sh \
> bareudp.sh \
> big_tcp.sh \
> + big_tcp_tunnels.sh \
> bind_bhash.sh \
> bpf_offload.py \
> bridge_stp_mode.sh \
> diff --git a/tools/testing/selftests/net/big_tcp_tunnels.sh b/tools/testing/selftests/net/big_tcp_tunnels.sh
> new file mode 100755
> index 000000000000..128a710e74ad
> --- /dev/null
> +++ b/tools/testing/selftests/net/big_tcp_tunnels.sh
> @@ -0,0 +1,183 @@
> +#!/usr/bin/env bash
> +# SPDX-License-Identifier: GPL-2.0
> +#
> +# Testing for IPv4 and IPv6 BIG TCP over VXLAN and GENEVE tunnels.
> +
> +SERVER_NS=$(mktemp -u server-XXXXXXXX)
> +SERVER_IP4="192.168.1.1"
> +SERVER_IP6="2001:db8::1:1"
> +SERVER_IP4_TUN="192.168.2.1"
> +SERVER_IP6_TUN="2001:db8::2:1"
> +
> +CLIENT_NS=$(mktemp -u client-XXXXXXXX)
> +CLIENT_IP4="192.168.1.2"
> +CLIENT_IP6="2001:db8::1:2"
> +CLIENT_IP4_TUN="192.168.2.2"
> +CLIENT_IP6_TUN="2001:db8::2:2"
> +
> +: "${PACKETS_THRESHOLD:=1000}"
> +
> +# Kselftest framework requirement - SKIP code is 4.
> +ksft_skip=4
> +
> +setup() {
> + ip netns add "$SERVER_NS"
> + ip netns add "$CLIENT_NS"
> + ip -netns "$SERVER_NS" link add link1 type veth peer name link0 netns "$CLIENT_NS"
> +
> + ip -netns "$CLIENT_NS" link set link0 up
> + ip -netns "$CLIENT_NS" addr replace "$CLIENT_IP4/24" dev link0
> + ip -netns "$CLIENT_NS" addr replace "$CLIENT_IP6/112" dev link0 nodad
> + ip -netns "$CLIENT_NS" link set link0 \
> + gso_max_size 196608 gso_ipv4_max_size 196608 \
> + gro_max_size 196608 gro_ipv4_max_size 196608
> + ip -netns "$SERVER_NS" link set link1 up
> + ip -netns "$SERVER_NS" addr replace "$SERVER_IP4/24" dev link1
> + ip -netns "$SERVER_NS" addr replace "$SERVER_IP6/112" dev link1 nodad
> + ip -netns "$SERVER_NS" link set link1 \
> + gso_max_size 196608 gso_ipv4_max_size 196608 \
> + gro_max_size 196608 gro_ipv4_max_size 196608
> +
> + ip netns exec "$SERVER_NS" netserver >/dev/null
> +}
> +
> +setup_tunnel() {
> + if [ "$2" = 4 ]; then
> + SERVER_IP="$SERVER_IP4"
> + CLIENT_IP="$CLIENT_IP4"
> + echo "Setting up ${1^^} over IPv4, veth tx csum offload $3"
> + else
> + SERVER_IP="$SERVER_IP6"
> + CLIENT_IP="$CLIENT_IP6"
> + echo "Setting up ${1^^} over IPv6, veth tx csum offload $3"
> + fi
> +
> + if [ "$1" = vxlan ]; then
> + ip -netns "$CLIENT_NS" link add tun0 type vxlan \
> + id 5001 remote "$SERVER_IP" local "$CLIENT_IP" dev link0 dstport 4789
> + else
> + ip -netns "$CLIENT_NS" link add tun0 type geneve \
> + id 5001 remote "$SERVER_IP"
> + fi
> + ip -netns "$CLIENT_NS" link set tun0 up
> + ip -netns "$CLIENT_NS" addr replace "$CLIENT_IP4_TUN/24" dev tun0
> + ip -netns "$CLIENT_NS" addr replace "$CLIENT_IP6_TUN/112" dev tun0 nodad
> + ip -netns "$CLIENT_NS" link set tun0 \
> + gso_max_size 196608 gso_ipv4_max_size 196608 \
> + gro_max_size 196608 gro_ipv4_max_size 196608
> + if [ "$1" = vxlan ]; then
> + ip -netns "$SERVER_NS" link add tun1 type vxlan \
> + id 5001 remote "$CLIENT_IP" local "$SERVER_IP" dev link1 dstport 4789
> + else
> + ip -netns "$SERVER_NS" link add tun1 type geneve \
> + id 5001 remote "$CLIENT_IP"
> + fi
> + ip -netns "$SERVER_NS" link set tun1 up
> + ip -netns "$SERVER_NS" addr replace "$SERVER_IP4_TUN/24" dev tun1
> + ip -netns "$SERVER_NS" addr replace "$SERVER_IP6_TUN/112" dev tun1 nodad
> + ip -netns "$SERVER_NS" link set tun1 \
> + gso_max_size 196608 gso_ipv4_max_size 196608 \
> + gro_max_size 196608 gro_ipv4_max_size 196608
> +
> + ip netns exec "$CLIENT_NS" ethtool -K link0 tx-checksumming "$3" > /dev/null
> + ip netns exec "$SERVER_NS" ethtool -K link1 tx-checksumming "$3" > /dev/null
> +}
> +
> +cleanup_tunnel() {
> + ip -netns "$CLIENT_NS" link del tun0
> + ip -netns "$SERVER_NS" link del tun1
> +}
> +
> +cleanup() {
> + ip netns pids "$SERVER_NS" | xargs -r kill
> + ip netns pids "$CLIENT_NS" | xargs -r kill
> + ip netns del "$SERVER_NS"
> + ip netns del "$CLIENT_NS"
> + rm -rf "$WORKDIR"
> +}
> +
> +do_test() {
> + # When tx csum offload is off, software GSO is performed before passing the
> + # packet to veth. Check BIG TCP packets inside the VXLAN tunnel to verify
> + # the software checksum path: if the checksum code is broken, these packets
> + # will be dropped.
> + if [ "$2" = on ]; then
> + CAPTURE_IFACE='link'
> + else
> + CAPTURE_IFACE='tun'
> + fi
> +
> + ip netns exec "$SERVER_NS" tcpdump -nn -s 256 -i "${CAPTURE_IFACE}1" greater 65536 -w "$WORKDIR/server.pcap" 2> /dev/null &
> + TCPDUMP_SERVER_PID="$!"
> + ip netns exec "$CLIENT_NS" tcpdump -nn -s 256 -i "${CAPTURE_IFACE}0" greater 65536 -w "$WORKDIR/client.pcap" 2> /dev/null &
> + TCPDUMP_CLIENT_PID="$!"
> +
> + # This filter doesn't capture all possible variants of SACK, but it's aimed
> + # at the typical one where SACK follows after [nop, nop, timestamp, nop,
> + # nop] (14 bytes after the 20-byte TCP header). IPv6 needs a separate match,
> + # because man tcpdump says:
> + # > Arithmetic expression against transport layer headers, like tcp[0], does
> + # > not work against IPv6 packets. It only looks at IPv4 packets.
> + ip netns exec "$SERVER_NS" tcpdump -nn -s 256 -i "tun1" '(tcp[tcpflags] & (tcp-syn|tcp-ack) = tcp-ack and tcp[34:2] & 0xffc3 = 0x0502) or (ip6[6] = 0x06 and ip6[53] & 0x12 = 0x10 and ip6[74:2] & 0xffc3 = 0x0502)' -w "$WORKDIR/sack.pcap" 2> /dev/null &
> + TCPDUMP_SACK_PID="$!"
> +
> + if [ "$1" = 4 ]; then
> + SERVER_IP="$SERVER_IP4_TUN"
> + echo "Running IPv4 traffic in the tunnel"
> + else
> + SERVER_IP="$SERVER_IP6_TUN"
> + echo "Running IPv6 traffic in the tunnel"
> + fi
> +
> + sleep 1 # Give tcpdump a second to spin up.
> + ip netns exec "$CLIENT_NS" netperf -t TCP_STREAM -l 5 -H "$SERVER_IP" -- \
> + -m 80000 > /dev/null
> + sleep 1 # Give tcpdump a second to process buffered packets.
> + kill "$TCPDUMP_SERVER_PID" "$TCPDUMP_CLIENT_PID" "$TCPDUMP_SACK_PID"
> + wait "$TCPDUMP_SERVER_PID" "$TCPDUMP_CLIENT_PID" "$TCPDUMP_SACK_PID"
> + PACKETS_SERVER=$(tcpdump --count -r "$WORKDIR/server.pcap" 2> /dev/null | cut -d ' ' -f 1)
> + PACKETS_CLIENT=$(tcpdump --count -r "$WORKDIR/client.pcap" 2> /dev/null | cut -d ' ' -f 1)
> + PACKETS_SACK=$(tcpdump --count -r "$WORKDIR/sack.pcap" 2> /dev/null | cut -d ' ' -f 1)
> +
> + echo "Captured BIG TCP RX packets: $PACKETS_SERVER"
> + echo "Captured BIG TCP TX packets: $PACKETS_CLIENT"
> + echo "Captured TCP SACK packets: $PACKETS_SACK"
> + [ "$PACKETS_SERVER" -gt "$PACKETS_THRESHOLD" ] || return 1
> + [ "$PACKETS_CLIENT" -gt "$PACKETS_THRESHOLD" ] || return 1
> + [ "$PACKETS_SACK" -lt "$(( PACKETS_CLIENT / 2 ))" ] || return 1
KCI fails here, see:
https://netdev-ctrl.bots.linux.dev/logs/vmksft/net/results/722863/156-big-tcp-tunnels-sh/stdout
possibly the above parsing is a bit fragile/tcpdump version's dependent?!?
Note that KCI automatically drops from PW series with failing test.
/P
^ permalink raw reply
* Re: [PATCH v2 1/4] dt-bindings: arm: altera: Add Agilex5 SoCDK TSN Config2 board
From: Nazle Asmade, Muhammad Nazim Amirul @ 2026-07-07 8:08 UTC (permalink / raw)
To: Krzysztof Kozlowski, dinguyen@kernel.org,
maxime.chevallier@bootlin.com
Cc: rmk+kernel@armlinux.org.uk, krzk+dt@kernel.org,
conor+dt@kernel.org, robh@kernel.org, davem@davemloft.net,
edumazet@google.com, kuba@kernel.org, pabeni@redhat.com,
andrew+netdev@lunn.ch, devicetree@vger.kernel.org,
linux-arm-kernel@lists.infradead.org, netdev@vger.kernel.org,
linux-kernel@vger.kernel.org
In-Reply-To: <8e9a2c05-178b-4360-b814-660d049e50a3@kernel.org>
On 7/7/2026 2:41 pm, Krzysztof Kozlowski wrote:
>> Add compatible string for the Intel SoCFPGA Agilex5 SoCDK TSN Config2
>> board variant. This board enables gmac1 as a TSN port with an FPGA
>> GMII-to-RGMII converter providing the RGMII clock delays.
>>
>> Signed-off-by: Nazim Amirul<muhammad.nazim.amirul.nazle.asmade@altera.com>
> So you just ignored the tag? Sure, we can ignore patches as well.
> Dropping from patchwork.
>
> Best regards,
> Krzysztof
Hi Krzysztof,
Apologies for the oversight. In v2 we restructured the series by adding
a new patch for the net MAC binding (altr,socfpga-stmmac), and during
that reorganization we accidentally dropped your Acked-by tag from patch
1/4. This was our mistake and not intentional.
We will carry your Acked-by in v3.
BR,
Nazim
^ permalink raw reply
* Re: [PATCH net] net/tls: Consume empty data records in tls_sw_read_sock()
From: Paolo Abeni @ 2026-07-07 8:10 UTC (permalink / raw)
To: Sabrina Dubroca, Chuck Lever
Cc: john.fastabend, Jakub Kicinski, davem, edumazet, Simon Horman,
netdev
In-Reply-To: <akyxoZTzhNl7XCEG@krikkit>
On 7/7/26 9:58 AM, Sabrina Dubroca wrote:
> 2026-07-06, 15:16:21 -0400, Chuck Lever wrote:
>> On Thu, Jul 2, 2026, at 5:50 PM, Sabrina Dubroca wrote:
>>> 2026-07-02, 15:52:49 -0400, Chuck Lever wrote:
>>>>
>>>>
>>>> On Thu, Jul 2, 2026, at 2:05 PM, Sabrina Dubroca wrote:
>>>>> 2026-06-30, 15:15:51 -0400, Chuck Lever wrote:
>>>>>> A peer may send a zero-length TLS application_data record; TLS 1.3
>>>>>> explicitly permits these as a traffic-analysis countermeasure (RFC
>>>>>> 8446, Section 5.1). After decryption such a record has full_len ==
>>>>>> 0. tls_sw_read_sock() hands it to the read_actor, which has no
>>>>>> payload to consume and returns zero. The loop treats a zero return
>>>>>> as backpressure (used <= 0), requeues the skb at the head of
>>>>>> rx_list, and stops. rx_list is serviced head-first on the next
>>>>>> call, so the empty record is dequeued, fails the same way, and is
>>>>>> requeued again; every later record on the connection is blocked
>>>>>> behind it.
>>>>>>
>>>>>> tls_sw_recvmsg() does not stall on this: a zero-length data record
>>>>>> copies nothing and falls through to consume_skb(). Mirror that in
>>>>>> the read_sock() path by recognizing an empty data record before
>>>>>> the actor runs, consuming it, and continuing.
>>>>>>
>>>>>> Fixes: 662fbcec32f4 ("net/tls: implement ->read_sock()")
>>>>>> Signed-off-by: Chuck Lever <cel@kernel.org>
>>>>>> ---
>>>>>> net/tls/tls_sw.c | 11 +++++++++++
>>>>>> 1 file changed, 11 insertions(+)
>>>>>
>>>>> Reviewed-by: Sabrina Dubroca <sd@queasysnail.net>
>>>>>
>>>>> I think tls_sw_splice_read() suffers from a similar issue (returning 0
>>>>> even though more data may be available). Sashiko agrees, and also
>>>>> found a few more pre-existing issues.
>>>>
>>>> Do you want a v2 series with those issues addressed?
>>>
>>> I'd be ok with this patch going in on its own, and the other issues
>>> being addressed separately. If you have time to look into those,
>>> that'd be great.
>>
>> patchwork shows this patch continues to be marked as "New". Is there
>> something I need to do to help move it forward?
>
> I don't think there's anything blocking it other than the length of
> the maintainers' backlog.
As noted yday:
https://lore.kernel.org/netdev/c0cd72bd-6298-47a4-82a3-c43811c98063@redhat.com/
current patch processing capacity is limited.
I'm processing this one right now.
/P
^ permalink raw reply
* Re: [PATCH net] net/tls: Consume empty data records in tls_sw_read_sock()
From: patchwork-bot+netdevbpf @ 2026-07-07 8:20 UTC (permalink / raw)
To: Chuck Lever
Cc: john.fastabend, kuba, sd, davem, edumazet, pabeni, horms, netdev
In-Reply-To: <20260630191551.875664-1-cel@kernel.org>
Hello:
This patch was applied to netdev/net.git (main)
by Paolo Abeni <pabeni@redhat.com>:
On Tue, 30 Jun 2026 15:15:51 -0400 you wrote:
> A peer may send a zero-length TLS application_data record; TLS 1.3
> explicitly permits these as a traffic-analysis countermeasure (RFC
> 8446, Section 5.1). After decryption such a record has full_len ==
> 0. tls_sw_read_sock() hands it to the read_actor, which has no
> payload to consume and returns zero. The loop treats a zero return
> as backpressure (used <= 0), requeues the skb at the head of
> rx_list, and stops. rx_list is serviced head-first on the next
> call, so the empty record is dequeued, fails the same way, and is
> requeued again; every later record on the connection is blocked
> behind it.
>
> [...]
Here is the summary with links:
- [net] net/tls: Consume empty data records in tls_sw_read_sock()
https://git.kernel.org/netdev/net/c/3be28e2c9cd0
You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
^ permalink raw reply
* [syzbot] [net?] memory leak in vlan_vid_add
From: syzbot @ 2026-07-07 8:20 UTC (permalink / raw)
To: davem, edumazet, horms, kuba, linux-kernel, netdev, pabeni,
syzkaller-bugs
Hello,
syzbot found the following issue on:
HEAD commit: 71dfdfb0209b Merge tag 'vfs-7.2-rc2.fixes' of git://git.ke..
git tree: upstream
console output: https://syzkaller.appspot.com/x/log.txt?x=13bbf1b1580000
kernel config: https://syzkaller.appspot.com/x/.config?x=b80376788da8bcda
dashboard link: https://syzkaller.appspot.com/bug?extid=456957213f32970c0762
compiler: gcc (Debian 14.2.0-19) 14.2.0, GNU ld (GNU Binutils for Debian) 2.44
syz repro: https://syzkaller.appspot.com/x/repro.syz?x=10166ffe580000
C reproducer: https://syzkaller.appspot.com/x/repro.c?x=16218b1c580000
Downloadable assets:
disk image: https://storage.googleapis.com/syzbot-assets/d3c154e8d39b/disk-71dfdfb0.raw.xz
vmlinux: https://storage.googleapis.com/syzbot-assets/9f35a0982146/vmlinux-71dfdfb0.xz
kernel image: https://storage.googleapis.com/syzbot-assets/fc56d29c15a3/bzImage-71dfdfb0.xz
IMPORTANT: if you fix the issue, please add the following tag to the commit:
Reported-by: syzbot+456957213f32970c0762@syzkaller.appspotmail.com
BUG: memory leak
unreferenced object 0xffff8881147f3c00 (size 256):
comm "syz-executor", pid 5805, jiffies 4294943736
hex dump (first 32 bytes):
00 40 02 0b 81 88 ff ff 00 00 00 00 00 00 00 00 .@..............
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
backtrace (crc a66a6b91):
kmemleak_alloc_recursive include/linux/kmemleak.h:44 [inline]
slab_post_alloc_hook mm/slub.c:4625 [inline]
slab_alloc_node mm/slub.c:4945 [inline]
__kmalloc_cache_noprof+0x356/0x440 mm/slub.c:5511
_kmalloc_noprof include/linux/slab.h:969 [inline]
_kzalloc_noprof include/linux/slab.h:1290 [inline]
vlan_info_alloc net/8021q/vlan_core.c:153 [inline]
vlan_vid_add+0x1ff/0x2b0 net/8021q/vlan_core.c:329
vlan_vid0_add net/8021q/vlan.c:349 [inline]
vlan_device_event.cold+0x27/0x65 net/8021q/vlan.c:388
notifier_call_chain+0x59/0x160 kernel/notifier.c:85
call_netdevice_notifiers_info+0x7d/0xb0 net/core/dev.c:2250
call_netdevice_notifiers_extack net/core/dev.c:2288 [inline]
call_netdevice_notifiers net/core/dev.c:2302 [inline]
__dev_notify_flags+0xb1/0x1b0 net/core/dev.c:9793
netif_change_flags+0x71/0x90 net/core/dev.c:9822
do_setlink.isra.0+0x50e/0x1ce0 net/core/rtnetlink.c:3215
rtnl_changelink net/core/rtnetlink.c:3849 [inline]
__rtnl_newlink net/core/rtnetlink.c:4022 [inline]
rtnl_newlink+0xb23/0x1310 net/core/rtnetlink.c:4159
rtnetlink_rcv_msg+0x52b/0x600 net/core/rtnetlink.c:7076
netlink_rcv_skb+0x89/0x1c0 net/netlink/af_netlink.c:2556
netlink_unicast_kernel net/netlink/af_netlink.c:1319 [inline]
netlink_unicast+0x38f/0x4e0 net/netlink/af_netlink.c:1345
netlink_sendmsg+0x335/0x690 net/netlink/af_netlink.c:1900
sock_sendmsg_nosec net/socket.c:775 [inline]
__sock_sendmsg net/socket.c:790 [inline]
__sys_sendto+0x2ca/0x2e0 net/socket.c:2252
__do_sys_sendto net/socket.c:2259 [inline]
__se_sys_sendto net/socket.c:2255 [inline]
__x64_sys_sendto+0x28/0x30 net/socket.c:2255
do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
do_syscall_64+0xf8/0x610 arch/x86/entry/syscall_64.c:94
BUG: memory leak
unreferenced object 0xffff8881127a3660 (size 32):
comm "syz-executor", pid 5805, jiffies 4294943736
hex dump (first 32 bytes):
a0 3c 7f 14 81 88 ff ff a0 3c 7f 14 81 88 ff ff .<.......<......
81 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 ................
backtrace (crc a6a88710):
kmemleak_alloc_recursive include/linux/kmemleak.h:44 [inline]
slab_post_alloc_hook mm/slub.c:4625 [inline]
slab_alloc_node mm/slub.c:4945 [inline]
__kmalloc_cache_noprof+0x356/0x440 mm/slub.c:5511
_kmalloc_noprof include/linux/slab.h:969 [inline]
_kzalloc_noprof include/linux/slab.h:1290 [inline]
vlan_vid_info_alloc net/8021q/vlan_core.c:196 [inline]
__vlan_vid_add net/8021q/vlan_core.c:302 [inline]
vlan_vid_add+0x14f/0x2b0 net/8021q/vlan_core.c:336
vlan_vid0_add net/8021q/vlan.c:349 [inline]
vlan_device_event.cold+0x27/0x65 net/8021q/vlan.c:388
notifier_call_chain+0x59/0x160 kernel/notifier.c:85
call_netdevice_notifiers_info+0x7d/0xb0 net/core/dev.c:2250
call_netdevice_notifiers_extack net/core/dev.c:2288 [inline]
call_netdevice_notifiers net/core/dev.c:2302 [inline]
__dev_notify_flags+0xb1/0x1b0 net/core/dev.c:9793
netif_change_flags+0x71/0x90 net/core/dev.c:9822
do_setlink.isra.0+0x50e/0x1ce0 net/core/rtnetlink.c:3215
rtnl_changelink net/core/rtnetlink.c:3849 [inline]
__rtnl_newlink net/core/rtnetlink.c:4022 [inline]
rtnl_newlink+0xb23/0x1310 net/core/rtnetlink.c:4159
rtnetlink_rcv_msg+0x52b/0x600 net/core/rtnetlink.c:7076
netlink_rcv_skb+0x89/0x1c0 net/netlink/af_netlink.c:2556
netlink_unicast_kernel net/netlink/af_netlink.c:1319 [inline]
netlink_unicast+0x38f/0x4e0 net/netlink/af_netlink.c:1345
netlink_sendmsg+0x335/0x690 net/netlink/af_netlink.c:1900
sock_sendmsg_nosec net/socket.c:775 [inline]
__sock_sendmsg net/socket.c:790 [inline]
__sys_sendto+0x2ca/0x2e0 net/socket.c:2252
__do_sys_sendto net/socket.c:2259 [inline]
__se_sys_sendto net/socket.c:2255 [inline]
__x64_sys_sendto+0x28/0x30 net/socket.c:2255
do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
do_syscall_64+0xf8/0x610 arch/x86/entry/syscall_64.c:94
connection error: failed to recv *flatrpc.ExecutorMessageRawT: EOF
---
This report is generated by a bot. It may contain errors.
See https://goo.gl/tpsmEJ for more information about syzbot.
syzbot engineers can be reached at syzkaller@googlegroups.com.
syzbot will keep track of this issue. See:
https://goo.gl/tpsmEJ#status for how to communicate with syzbot.
If the report is already addressed, let syzbot know by replying with:
#syz fix: exact-commit-title
If you want syzbot to run the reproducer, reply with:
#syz test: git://repo/address.git branch-or-commit-hash
If you attach or paste a git patch, syzbot will apply it before testing.
If you want to overwrite report's subsystems, reply with:
#syz set subsystems: new-subsystem
(See the list of subsystem names on the web dashboard)
If the report is a duplicate of another one, reply with:
#syz dup: exact-subject-of-another-report
If you want to undo deduplication, reply with:
#syz undup
^ permalink raw reply
* [PATCH net-next 0/6] net/stmmac: Add Mediatek MT8189 support
From: Louis-Alexis Eyraud @ 2026-07-07 8:21 UTC (permalink / raw)
To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Richard Cochran, Matthias Brugger, AngeloGioacchino Del Regno,
Biao Huang, Maxime Coquelin, Alexandre Torgue
Cc: maxime.chevallier, rmk+kernel, kernel, netdev, devicetree,
linux-kernel, linux-arm-kernel, linux-mediatek, linux-stm32,
Louis-Alexis Eyraud
This series adds the Ethernet support for Mediatek MT8189 SoC and its
variants (MT8371, MT8391). These SoC integrate a Gigabit Ethernet MAC
with RGMII/RMII/MII interface, with a similar design than previous SoCs
such MT8188 or MT8195.
This series is based on net-next tree (sha1: 474cff686812).
It has been tested on Mediatek Genio 520-EVK (MT8371) and 720-EVK
(MT8391) boards, integrating an Airoha AN8801R Ethernet PHY, with
hardware enablement series ([1]) and additional devicetrees patches
for enabling the Ethernet interface.
[1]: https://lore.kernel.org/linux-mediatek/20260701-add-mediatek-genio-520-720-evk-v2-0-19d5da4ef984@collabora.com/
Signed-off-by: Louis-Alexis Eyraud <louisalexis.eyraud@collabora.com>
---
Louis-Alexis Eyraud (6):
dt-bindings: net: mediatek-dwmac: add support for MT8189 SoC
net: stmmac: mediatek: add PERI_ETH_CTRLx register offset in platform data
net: stmmac: mediatek: rename MT2712 and MT8195 variant methods
net: stmmac: mediatek: add support for TX clock output enable feature
net: stmmac: mediatek: add support for TX deallocation adjustment feature
net: stmmac: mediatek: add support for MT8189 SoC
.../devicetree/bindings/net/mediatek-dwmac.yaml | 77 ++++++++++-----
.../net/ethernet/stmicro/stmmac/dwmac-mediatek.c | 109 +++++++++++++++------
2 files changed, 135 insertions(+), 51 deletions(-)
---
base-commit: 474cff6868129755cf889edf40d7f491729fc588
change-id: 20260703-dwmac-mediatek-mt8189-9dafe3984951
Best regards,
--
Louis-Alexis Eyraud <louisalexis.eyraud@collabora.com>
^ permalink raw reply
* [PATCH net-next 1/6] dt-bindings: net: mediatek-dwmac: add support for MT8189 SoC
From: Louis-Alexis Eyraud @ 2026-07-07 8:21 UTC (permalink / raw)
To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Richard Cochran, Matthias Brugger, AngeloGioacchino Del Regno,
Biao Huang, Maxime Coquelin, Alexandre Torgue
Cc: maxime.chevallier, rmk+kernel, kernel, netdev, devicetree,
linux-kernel, linux-arm-kernel, linux-mediatek, linux-stm32,
Louis-Alexis Eyraud
In-Reply-To: <20260707-dwmac-mediatek-mt8189-v1-0-17f345eaaca3@collabora.com>
Add new compatible string and clock definitions for the Ethernet MAC
IP found in MT8189 SoC.
Signed-off-by: Louis-Alexis Eyraud <louisalexis.eyraud@collabora.com>
---
.../devicetree/bindings/net/mediatek-dwmac.yaml | 77 +++++++++++++++-------
1 file changed, 54 insertions(+), 23 deletions(-)
diff --git a/Documentation/devicetree/bindings/net/mediatek-dwmac.yaml b/Documentation/devicetree/bindings/net/mediatek-dwmac.yaml
index 3aab21b8e8de..000abec023b3 100644
--- a/Documentation/devicetree/bindings/net/mediatek-dwmac.yaml
+++ b/Documentation/devicetree/bindings/net/mediatek-dwmac.yaml
@@ -20,13 +20,11 @@ select:
enum:
- mediatek,mt2712-gmac
- mediatek,mt8188-gmac
+ - mediatek,mt8189-gmac
- mediatek,mt8195-gmac
required:
- compatible
-allOf:
- - $ref: snps,dwmac.yaml#
-
properties:
compatible:
oneOf:
@@ -36,6 +34,7 @@ properties:
- const: snps,dwmac-4.20a
- items:
- enum:
+ - mediatek,mt8189-gmac
- mediatek,mt8195-gmac
- const: snps,dwmac-5.10a
- items:
@@ -44,26 +43,6 @@ properties:
- const: mediatek,mt8195-gmac
- const: snps,dwmac-5.10a
- clocks:
- minItems: 5
- items:
- - description: AXI clock
- - description: APB clock
- - description: MAC Main clock
- - description: PTP clock
- - description: RMII reference clock provided by MAC
- - description: MAC clock gate
-
- clock-names:
- minItems: 5
- items:
- - const: axi
- - const: apb
- - const: mac_main
- - const: ptp_ref
- - const: rmii_internal
- - const: mac_cg
-
interrupts:
maxItems: 1
@@ -147,6 +126,58 @@ required:
- phy-mode
- mediatek,pericfg
+allOf:
+ - $ref: snps,dwmac.yaml#
+ - if:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - mediatek,mt2712-gmac
+ - mediatek,mt8188-gmac
+ - mediatek,mt8195-gmac
+ then:
+ properties:
+ clocks:
+ minItems: 5
+ items:
+ - description: AXI clock
+ - description: APB clock
+ - description: MAC Main clock
+ - description: PTP clock
+ - description: RMII reference clock provided by MAC
+ - description: MAC clock gate
+
+ clock-names:
+ minItems: 5
+ items:
+ - const: axi
+ - const: apb
+ - const: mac_main
+ - const: ptp_ref
+ - const: rmii_internal
+ - const: mac_cg
+
+ - if:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - mediatek,mt8189-gmac
+ then:
+ properties:
+ clocks:
+ items:
+ - description: MAC Main clock
+ - description: PTP clock
+ - description: RMII reference clock provided by MAC
+
+ clock-names:
+ items:
+ - const: mac_main
+ - const: ptp_ref
+ - const: rmii_internal
+
unevaluatedProperties: false
examples:
--
2.55.0
^ permalink raw reply related
* [PATCH net-next 2/6] net: stmmac: mediatek: add PERI_ETH_CTRLx register offset in platform data
From: Louis-Alexis Eyraud @ 2026-07-07 8:21 UTC (permalink / raw)
To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Richard Cochran, Matthias Brugger, AngeloGioacchino Del Regno,
Biao Huang, Maxime Coquelin, Alexandre Torgue
Cc: maxime.chevallier, rmk+kernel, kernel, netdev, devicetree,
linux-kernel, linux-arm-kernel, linux-mediatek, linux-stm32,
Louis-Alexis Eyraud
In-Reply-To: <20260707-dwmac-mediatek-mt8189-v1-0-17f345eaaca3@collabora.com>
In preparation of newer SoC support, that use like MT8195 the Ethernet
control registers from the peripheral configuration syscon but at a
different base offset, add a new base offset in the variant platform
data to access the PERI_ETH_CTRLx registers and use it in implemented
methods.
Signed-off-by: Louis-Alexis Eyraud <louisalexis.eyraud@collabora.com>
---
.../net/ethernet/stmicro/stmmac/dwmac-mediatek.c | 28 +++++++++++++++-------
1 file changed, 20 insertions(+), 8 deletions(-)
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-mediatek.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-mediatek.c
index 30ae0dba7fff..0cabab4fd89a 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-mediatek.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-mediatek.c
@@ -37,7 +37,9 @@
#define ETH_FINE_DLY_RXC BIT(0)
/* Peri Configuration register for mt8195 */
-#define MT8195_PERI_ETH_CTRL0 0xFD0
+#define MT8195_PERI_ETH_CTRL_BASE 0xFD0
+
+#define MT8195_PERI_ETH_CTRL0 0x0
#define MT8195_RMII_CLK_SRC_INTERNAL BIT(28)
#define MT8195_RMII_CLK_SRC_RXC BIT(27)
#define MT8195_ETH_INTF_SEL GENMASK(26, 24)
@@ -47,7 +49,7 @@
#define MT8195_DLY_GTXC_ENABLE BIT(5)
#define MT8195_DLY_GTXC_STAGES GENMASK(4, 0)
-#define MT8195_PERI_ETH_CTRL1 0xFD4
+#define MT8195_PERI_ETH_CTRL1 0x4
#define MT8195_DLY_RXC_INV BIT(25)
#define MT8195_DLY_RXC_ENABLE BIT(18)
#define MT8195_DLY_RXC_STAGES GENMASK(17, 13)
@@ -55,7 +57,7 @@
#define MT8195_DLY_TXC_ENABLE BIT(5)
#define MT8195_DLY_TXC_STAGES GENMASK(4, 0)
-#define MT8195_PERI_ETH_CTRL2 0xFD8
+#define MT8195_PERI_ETH_CTRL2 0x8
#define MT8195_DLY_RMII_RXC_INV BIT(25)
#define MT8195_DLY_RMII_RXC_ENABLE BIT(18)
#define MT8195_DLY_RMII_RXC_STAGES GENMASK(17, 13)
@@ -95,6 +97,7 @@ struct mediatek_dwmac_variant {
u32 rx_delay_max;
u32 tx_delay_max;
+ u32 peri_eth_ctrl_offset;
u8 dma_bit_mask;
};
@@ -277,6 +280,7 @@ static int mt8195_set_interface(struct mediatek_dwmac_plat_data *plat,
u8 phy_intf_sel)
{
u32 intf_val = FIELD_PREP(MT8195_ETH_INTF_SEL, phy_intf_sel);
+ u32 reg_offset = plat->variant->peri_eth_ctrl_offset;
if (phy_intf_sel == PHY_INTF_SEL_RMII) {
if (plat->rmii_clk_from_mac)
@@ -288,7 +292,9 @@ static int mt8195_set_interface(struct mediatek_dwmac_plat_data *plat,
/* MT8195 only support external PHY */
intf_val |= MT8195_EXT_PHY_MODE;
- regmap_write(plat->peri_regmap, MT8195_PERI_ETH_CTRL0, intf_val);
+ regmap_write(plat->peri_regmap,
+ reg_offset + MT8195_PERI_ETH_CTRL0,
+ intf_val);
return 0;
}
@@ -313,8 +319,9 @@ static void mt8195_delay_stage2ps(struct mediatek_dwmac_plat_data *plat)
static int mt8195_set_delay(struct mediatek_dwmac_plat_data *plat)
{
- struct mac_delay_struct *mac_delay = &plat->mac_delay;
u32 gtxc_delay_val = 0, delay_val = 0, rmii_delay_val = 0;
+ struct mac_delay_struct *mac_delay = &plat->mac_delay;
+ u32 reg_offset = plat->variant->peri_eth_ctrl_offset;
mt8195_delay_ps2stage(plat);
@@ -399,14 +406,18 @@ static int mt8195_set_delay(struct mediatek_dwmac_plat_data *plat)
}
regmap_update_bits(plat->peri_regmap,
- MT8195_PERI_ETH_CTRL0,
+ reg_offset + MT8195_PERI_ETH_CTRL0,
MT8195_RGMII_TXC_PHASE_CTRL |
MT8195_DLY_GTXC_INV |
MT8195_DLY_GTXC_ENABLE |
MT8195_DLY_GTXC_STAGES,
gtxc_delay_val);
- regmap_write(plat->peri_regmap, MT8195_PERI_ETH_CTRL1, delay_val);
- regmap_write(plat->peri_regmap, MT8195_PERI_ETH_CTRL2, rmii_delay_val);
+ regmap_write(plat->peri_regmap,
+ reg_offset + MT8195_PERI_ETH_CTRL1,
+ delay_val);
+ regmap_write(plat->peri_regmap,
+ reg_offset + MT8195_PERI_ETH_CTRL2,
+ rmii_delay_val);
mt8195_delay_stage2ps(plat);
@@ -421,6 +432,7 @@ static const struct mediatek_dwmac_variant mt8195_gmac_variant = {
.rx_delay_max = 9280,
.tx_delay_max = 9280,
.dma_bit_mask = 35,
+ .peri_eth_ctrl_offset = MT8195_PERI_ETH_CTRL_BASE,
};
static int mediatek_dwmac_config_dt(struct mediatek_dwmac_plat_data *plat)
--
2.55.0
^ permalink raw reply related
* [PATCH net-next 3/6] net: stmmac: mediatek: rename MT2712 and MT8195 variant methods
From: Louis-Alexis Eyraud @ 2026-07-07 8:21 UTC (permalink / raw)
To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Richard Cochran, Matthias Brugger, AngeloGioacchino Del Regno,
Biao Huang, Maxime Coquelin, Alexandre Torgue
Cc: maxime.chevallier, rmk+kernel, kernel, netdev, devicetree,
linux-kernel, linux-arm-kernel, linux-mediatek, linux-stm32,
Louis-Alexis Eyraud
In-Reply-To: <20260707-dwmac-mediatek-mt8189-v1-0-17f345eaaca3@collabora.com>
In preparation of newer SoC support, rename MT2712 and MT8195 variant
methods and sub functions to more generic names.
Signed-off-by: Louis-Alexis Eyraud <louisalexis.eyraud@collabora.com>
---
.../net/ethernet/stmicro/stmmac/dwmac-mediatek.c | 32 +++++++++++-----------
1 file changed, 16 insertions(+), 16 deletions(-)
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-mediatek.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-mediatek.c
index 0cabab4fd89a..28e87990b0a1 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-mediatek.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-mediatek.c
@@ -110,7 +110,7 @@ static const char * const mt8195_dwmac_clk_l[] = {
"axi", "apb", "mac_cg", "mac_main", "ptp_ref"
};
-static int mt2712_set_interface(struct mediatek_dwmac_plat_data *plat,
+static int set_phy_interface_v1(struct mediatek_dwmac_plat_data *plat,
u8 phy_intf_sel)
{
u32 intf_val = phy_intf_sel;
@@ -127,7 +127,7 @@ static int mt2712_set_interface(struct mediatek_dwmac_plat_data *plat,
return 0;
}
-static void mt2712_delay_ps2stage(struct mediatek_dwmac_plat_data *plat)
+static void delay_ps2stage_v1(struct mediatek_dwmac_plat_data *plat)
{
struct mac_delay_struct *mac_delay = &plat->mac_delay;
@@ -152,7 +152,7 @@ static void mt2712_delay_ps2stage(struct mediatek_dwmac_plat_data *plat)
}
}
-static void mt2712_delay_stage2ps(struct mediatek_dwmac_plat_data *plat)
+static void delay_stage2ps_v1(struct mediatek_dwmac_plat_data *plat)
{
struct mac_delay_struct *mac_delay = &plat->mac_delay;
@@ -177,12 +177,12 @@ static void mt2712_delay_stage2ps(struct mediatek_dwmac_plat_data *plat)
}
}
-static int mt2712_set_delay(struct mediatek_dwmac_plat_data *plat)
+static int set_delay_v1(struct mediatek_dwmac_plat_data *plat)
{
struct mac_delay_struct *mac_delay = &plat->mac_delay;
u32 delay_val = 0, fine_val = 0;
- mt2712_delay_ps2stage(plat);
+ delay_ps2stage_v1(plat);
switch (plat->phy_mode) {
case PHY_INTERFACE_MODE_MII:
@@ -261,14 +261,14 @@ static int mt2712_set_delay(struct mediatek_dwmac_plat_data *plat)
regmap_write(plat->peri_regmap, PERI_ETH_DLY, delay_val);
regmap_write(plat->peri_regmap, PERI_ETH_DLY_FINE, fine_val);
- mt2712_delay_stage2ps(plat);
+ delay_stage2ps_v1(plat);
return 0;
}
static const struct mediatek_dwmac_variant mt2712_gmac_variant = {
- .dwmac_set_phy_interface = mt2712_set_interface,
- .dwmac_set_delay = mt2712_set_delay,
+ .dwmac_set_phy_interface = set_phy_interface_v1,
+ .dwmac_set_delay = set_delay_v1,
.clk_list = mt2712_dwmac_clk_l,
.num_clks = ARRAY_SIZE(mt2712_dwmac_clk_l),
.rx_delay_max = 17600,
@@ -276,7 +276,7 @@ static const struct mediatek_dwmac_variant mt2712_gmac_variant = {
.dma_bit_mask = 33,
};
-static int mt8195_set_interface(struct mediatek_dwmac_plat_data *plat,
+static int set_phy_interface_v2(struct mediatek_dwmac_plat_data *plat,
u8 phy_intf_sel)
{
u32 intf_val = FIELD_PREP(MT8195_ETH_INTF_SEL, phy_intf_sel);
@@ -299,7 +299,7 @@ static int mt8195_set_interface(struct mediatek_dwmac_plat_data *plat,
return 0;
}
-static void mt8195_delay_ps2stage(struct mediatek_dwmac_plat_data *plat)
+static void delay_ps2stage_v2(struct mediatek_dwmac_plat_data *plat)
{
struct mac_delay_struct *mac_delay = &plat->mac_delay;
@@ -308,7 +308,7 @@ static void mt8195_delay_ps2stage(struct mediatek_dwmac_plat_data *plat)
mac_delay->rx_delay /= 290;
}
-static void mt8195_delay_stage2ps(struct mediatek_dwmac_plat_data *plat)
+static void delay_stage2ps_v2(struct mediatek_dwmac_plat_data *plat)
{
struct mac_delay_struct *mac_delay = &plat->mac_delay;
@@ -317,13 +317,13 @@ static void mt8195_delay_stage2ps(struct mediatek_dwmac_plat_data *plat)
mac_delay->rx_delay *= 290;
}
-static int mt8195_set_delay(struct mediatek_dwmac_plat_data *plat)
+static int set_delay_v2(struct mediatek_dwmac_plat_data *plat)
{
u32 gtxc_delay_val = 0, delay_val = 0, rmii_delay_val = 0;
struct mac_delay_struct *mac_delay = &plat->mac_delay;
u32 reg_offset = plat->variant->peri_eth_ctrl_offset;
- mt8195_delay_ps2stage(plat);
+ delay_ps2stage_v2(plat);
switch (plat->phy_mode) {
case PHY_INTERFACE_MODE_MII:
@@ -419,14 +419,14 @@ static int mt8195_set_delay(struct mediatek_dwmac_plat_data *plat)
reg_offset + MT8195_PERI_ETH_CTRL2,
rmii_delay_val);
- mt8195_delay_stage2ps(plat);
+ delay_stage2ps_v2(plat);
return 0;
}
static const struct mediatek_dwmac_variant mt8195_gmac_variant = {
- .dwmac_set_phy_interface = mt8195_set_interface,
- .dwmac_set_delay = mt8195_set_delay,
+ .dwmac_set_phy_interface = set_phy_interface_v2,
+ .dwmac_set_delay = set_delay_v2,
.clk_list = mt8195_dwmac_clk_l,
.num_clks = ARRAY_SIZE(mt8195_dwmac_clk_l),
.rx_delay_max = 9280,
--
2.55.0
^ permalink raw reply related
* [PATCH net-next 4/6] net: stmmac: mediatek: add support for TX clock output enable feature
From: Louis-Alexis Eyraud @ 2026-07-07 8:21 UTC (permalink / raw)
To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Richard Cochran, Matthias Brugger, AngeloGioacchino Del Regno,
Biao Huang, Maxime Coquelin, Alexandre Torgue
Cc: maxime.chevallier, rmk+kernel, kernel, netdev, devicetree,
linux-kernel, linux-arm-kernel, linux-mediatek, linux-stm32,
Louis-Alexis Eyraud
In-Reply-To: <20260707-dwmac-mediatek-mt8189-v1-0-17f345eaaca3@collabora.com>
The MT8189 SoC has in the Ethernet control 0 register from the
peripheral configuration (pericfg) an additional bit to enable the TX
clock signal output.
In preparation of MT8189 SoC support, add its definition, use in the
set_phy_interface_v2 callback, and a support flag in the platform
data.
Signed-off-by: Louis-Alexis Eyraud <louisalexis.eyraud@collabora.com>
---
drivers/net/ethernet/stmicro/stmmac/dwmac-mediatek.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-mediatek.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-mediatek.c
index 28e87990b0a1..bcc0baef3f71 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-mediatek.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-mediatek.c
@@ -36,6 +36,9 @@
#define ETH_FINE_DLY_GTXC BIT(1)
#define ETH_FINE_DLY_RXC BIT(0)
+/* Peri Configuration register for mt8189 */
+#define MT8189_CTRL0_TXC_OUT_OP BIT(20)
+
/* Peri Configuration register for mt8195 */
#define MT8195_PERI_ETH_CTRL_BASE 0xFD0
@@ -99,6 +102,7 @@ struct mediatek_dwmac_variant {
u32 tx_delay_max;
u32 peri_eth_ctrl_offset;
u8 dma_bit_mask;
+ bool use_out_op;
};
/* list of clocks required for mac */
@@ -292,6 +296,9 @@ static int set_phy_interface_v2(struct mediatek_dwmac_plat_data *plat,
/* MT8195 only support external PHY */
intf_val |= MT8195_EXT_PHY_MODE;
+ if (plat->variant->use_out_op)
+ intf_val |= MT8189_CTRL0_TXC_OUT_OP;
+
regmap_write(plat->peri_regmap,
reg_offset + MT8195_PERI_ETH_CTRL0,
intf_val);
--
2.55.0
^ permalink raw reply related
* [PATCH net-next 5/6] net: stmmac: mediatek: add support for TX deallocation adjustment feature
From: Louis-Alexis Eyraud @ 2026-07-07 8:21 UTC (permalink / raw)
To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Richard Cochran, Matthias Brugger, AngeloGioacchino Del Regno,
Biao Huang, Maxime Coquelin, Alexandre Torgue
Cc: maxime.chevallier, rmk+kernel, kernel, netdev, devicetree,
linux-kernel, linux-arm-kernel, linux-mediatek, linux-stm32,
Louis-Alexis Eyraud
In-Reply-To: <20260707-dwmac-mediatek-mt8189-v1-0-17f345eaaca3@collabora.com>
The MT8189 SoC has in the Ethernet control 0 register from the
peripheral configuration (pericfg) additional bits to adjust the TX
deallocation.
In preparation of MT8189 SoC support, add its definition, use in the
set_delay_v2 callback, and a support flag in the platform data.
Signed-off-by: Louis-Alexis Eyraud <louisalexis.eyraud@collabora.com>
---
.../net/ethernet/stmicro/stmmac/dwmac-mediatek.c | 25 ++++++++++++++++------
1 file changed, 19 insertions(+), 6 deletions(-)
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-mediatek.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-mediatek.c
index bcc0baef3f71..6b0a42b5839f 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-mediatek.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-mediatek.c
@@ -37,7 +37,8 @@
#define ETH_FINE_DLY_RXC BIT(0)
/* Peri Configuration register for mt8189 */
-#define MT8189_CTRL0_TXC_OUT_OP BIT(20)
+#define MT8189_CTRL0_TXC_OUT_OP BIT(20)
+#define MT8189_CTRL0_DLY_GTXC_STAGE_FINE GENMASK(11, 6)
/* Peri Configuration register for mt8195 */
#define MT8195_PERI_ETH_CTRL_BASE 0xFD0
@@ -103,6 +104,7 @@ struct mediatek_dwmac_variant {
u32 peri_eth_ctrl_offset;
u8 dma_bit_mask;
bool use_out_op;
+ bool use_stage_fine;
};
/* list of clocks required for mac */
@@ -326,9 +328,12 @@ static void delay_stage2ps_v2(struct mediatek_dwmac_plat_data *plat)
static int set_delay_v2(struct mediatek_dwmac_plat_data *plat)
{
- u32 gtxc_delay_val = 0, delay_val = 0, rmii_delay_val = 0;
struct mac_delay_struct *mac_delay = &plat->mac_delay;
u32 reg_offset = plat->variant->peri_eth_ctrl_offset;
+ u32 gtxc_delay_mask = 0;
+ u32 gtxc_delay_val = 0;
+ u32 rmii_delay_val = 0;
+ u32 delay_val = 0;
delay_ps2stage_v2(plat);
@@ -402,6 +407,9 @@ static int set_delay_v2(struct mediatek_dwmac_plat_data *plat)
gtxc_delay_val |= FIELD_PREP(MT8195_DLY_GTXC_STAGES, mac_delay->tx_delay);
gtxc_delay_val |= FIELD_PREP(MT8195_DLY_GTXC_INV, mac_delay->tx_inv);
+ if (plat->variant->use_stage_fine)
+ gtxc_delay_val |= MT8189_CTRL0_DLY_GTXC_STAGE_FINE;
+
delay_val |= FIELD_PREP(MT8195_DLY_RXC_ENABLE, !!mac_delay->rx_delay);
delay_val |= FIELD_PREP(MT8195_DLY_RXC_STAGES, mac_delay->rx_delay);
delay_val |= FIELD_PREP(MT8195_DLY_RXC_INV, mac_delay->rx_inv);
@@ -412,12 +420,17 @@ static int set_delay_v2(struct mediatek_dwmac_plat_data *plat)
return -EINVAL;
}
+ gtxc_delay_mask = MT8195_RGMII_TXC_PHASE_CTRL |
+ MT8195_DLY_GTXC_INV |
+ MT8195_DLY_GTXC_ENABLE |
+ MT8195_DLY_GTXC_STAGES;
+
+ if (plat->variant->use_stage_fine)
+ gtxc_delay_mask |= MT8189_CTRL0_DLY_GTXC_STAGE_FINE;
+
regmap_update_bits(plat->peri_regmap,
reg_offset + MT8195_PERI_ETH_CTRL0,
- MT8195_RGMII_TXC_PHASE_CTRL |
- MT8195_DLY_GTXC_INV |
- MT8195_DLY_GTXC_ENABLE |
- MT8195_DLY_GTXC_STAGES,
+ gtxc_delay_mask,
gtxc_delay_val);
regmap_write(plat->peri_regmap,
reg_offset + MT8195_PERI_ETH_CTRL1,
--
2.55.0
^ permalink raw reply related
* [PATCH net-next 6/6] net: stmmac: mediatek: add support for MT8189 SoC
From: Louis-Alexis Eyraud @ 2026-07-07 8:21 UTC (permalink / raw)
To: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Richard Cochran, Matthias Brugger, AngeloGioacchino Del Regno,
Biao Huang, Maxime Coquelin, Alexandre Torgue
Cc: maxime.chevallier, rmk+kernel, kernel, netdev, devicetree,
linux-kernel, linux-arm-kernel, linux-mediatek, linux-stm32,
Louis-Alexis Eyraud
In-Reply-To: <20260707-dwmac-mediatek-mt8189-v1-0-17f345eaaca3@collabora.com>
Like MT8195 SoC, MT8189 SoC uses the Ethernet control registers from
the peripheral configuration (pericfg) but at a different
offset. It also needs additional features.
Thus, add compatible, clock definitions and specific platform data to
support the MT8189 SoC.
Signed-off-by: Louis-Alexis Eyraud <louisalexis.eyraud@collabora.com>
---
.../net/ethernet/stmicro/stmmac/dwmac-mediatek.c | 21 +++++++++++++++++++++
1 file changed, 21 insertions(+)
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-mediatek.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-mediatek.c
index 6b0a42b5839f..e7e336b1f114 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-mediatek.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-mediatek.c
@@ -37,6 +37,8 @@
#define ETH_FINE_DLY_RXC BIT(0)
/* Peri Configuration register for mt8189 */
+#define MT8189_PERI_ETH_CTRL_BASE 0x270
+
#define MT8189_CTRL0_TXC_OUT_OP BIT(20)
#define MT8189_CTRL0_DLY_GTXC_STAGE_FINE GENMASK(11, 6)
@@ -116,6 +118,10 @@ static const char * const mt8195_dwmac_clk_l[] = {
"axi", "apb", "mac_cg", "mac_main", "ptp_ref"
};
+static const char * const mt8189_dwmac_clk_l[] = {
+ "mac_main", "ptp_ref"
+};
+
static int set_phy_interface_v1(struct mediatek_dwmac_plat_data *plat,
u8 phy_intf_sel)
{
@@ -444,6 +450,19 @@ static int set_delay_v2(struct mediatek_dwmac_plat_data *plat)
return 0;
}
+static const struct mediatek_dwmac_variant mt8189_gmac_variant = {
+ .dwmac_set_phy_interface = set_phy_interface_v2,
+ .dwmac_set_delay = set_delay_v2,
+ .clk_list = mt8189_dwmac_clk_l,
+ .num_clks = ARRAY_SIZE(mt8189_dwmac_clk_l),
+ .dma_bit_mask = 35,
+ .rx_delay_max = 9280,
+ .tx_delay_max = 9280,
+ .peri_eth_ctrl_offset = MT8189_PERI_ETH_CTRL_BASE,
+ .use_out_op = true,
+ .use_stage_fine = true,
+};
+
static const struct mediatek_dwmac_variant mt8195_gmac_variant = {
.dwmac_set_phy_interface = set_phy_interface_v2,
.dwmac_set_delay = set_delay_v2,
@@ -694,6 +713,8 @@ static void mediatek_dwmac_remove(struct platform_device *pdev)
static const struct of_device_id mediatek_dwmac_match[] = {
{ .compatible = "mediatek,mt2712-gmac",
.data = &mt2712_gmac_variant },
+ { .compatible = "mediatek,mt8189-gmac",
+ .data = &mt8189_gmac_variant },
{ .compatible = "mediatek,mt8195-gmac",
.data = &mt8195_gmac_variant },
{ }
--
2.55.0
^ permalink raw reply related
* [PATCH net] net: hsr: fix memory leak on slave unregistration by removing synced VLANs
From: Eric Dumazet @ 2026-07-07 8:23 UTC (permalink / raw)
To: David S . Miller, Jakub Kicinski, Paolo Abeni
Cc: Simon Horman, Andrew Lunn, netdev, eric.dumazet, Eric Dumazet,
syzbot+456957213f32970c0762
When an HSR master device is brought UP, it auto-adds VLAN 0 via
vlan_vid0_add(), which propagates VID 0 to its slave devices.
If a slave device is later unregistered while HSR is active (e.g., during
netns cleanup or interface destruction), hsr_del_port() is called to
detach the slave port from the HSR master. However, hsr_del_port() currently
does not delete the VLAN IDs that were synced to the slave device by HSR.
As a result, the slave device retains a refcount on VID 0 (and any other
synced VLANs). When the slave device is destroyed, its vlan_info /
vlan_vid_info structure remains allocated, leading to a memory leak.
Fix this by calling vlan_vids_del_by_dev(port->dev, master->dev) in
hsr_del_port() before unlinking the slave device, matching the cleanup
behavior in bonding and team drivers.
Fixes: 1a8a63a5305e ("net: hsr: Add VLAN CTAG filter support")
Reported-by: syzbot+456957213f32970c0762@syzkaller.appspotmail.com
Closes: https://lore.kernel.org/netdev/6a4cb6ca.57639fcc.86d58.000b.GAE@google.com/T/#u
Signed-off-by: Eric Dumazet <edumazet@google.com>
---
net/hsr/hsr_slave.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/net/hsr/hsr_slave.c b/net/hsr/hsr_slave.c
index d9af9e65f72f07b1997b80c85db16d812fbda488..2d1e3ea72088e35d5d870b4cc86dd2f789670394 100644
--- a/net/hsr/hsr_slave.c
+++ b/net/hsr/hsr_slave.c
@@ -242,6 +242,7 @@ void hsr_del_port(struct hsr_port *port)
netdev_rx_handler_unregister(port->dev);
if (!port->hsr->fwd_offloaded)
dev_set_promiscuity(port->dev, -1);
+ vlan_vids_del_by_dev(port->dev, master->dev);
netdev_upper_dev_unlink(port->dev, master->dev);
if (hsr->prot_version == PRP_V1 &&
port->type == HSR_PT_SLAVE_B) {
--
2.55.0.795.g602f6c329a-goog
^ permalink raw reply related
* Re: [PATCH net 1/4] ice: wait for reset completion in ice_resume()
From: Paolo Abeni @ 2026-07-07 8:28 UTC (permalink / raw)
To: Tony Nguyen, davem, kuba, edumazet, andrew+netdev, netdev
Cc: Aaron Ma, jbrandeb, stable, Kohei Enju, Aleksandr Loktionov,
Przemek Kitszel, Alexander Nowlin
In-Reply-To: <20260630214404.930923-2-anthony.l.nguyen@intel.com>
On 6/30/26 11:43 PM, Tony Nguyen wrote:
> From: Aaron Ma <aaron.ma@canonical.com>
>
> ice_resume() schedules an asynchronous PF reset and returns
> immediately. The reset runs later in ice_service_task(). If
> userspace tries to bring up the net device before the reset
> finishes, ice_open() fails with -EBUSY:
>
> ice_resume()
> ice_schedule_reset() # sets ICE_PFR_REQ, returns
> ...
> ice_open()
> ice_is_reset_in_progress() # ICE_PFR_REQ still set, -EBUSY
> ...
> ice_service_task()
> ice_do_reset()
> ice_rebuild() # clears ICE_PFR_REQ, too late
>
> Reproduced on E800 series NICs during suspend/resume with irdma
> enabled, where the aux device probe widens the race window.
>
> ice 0000:81:00.0: can't open net device while reset is in progress
>
> Add a best-effort wait (10s timeout, matching ice_devlink_info_get())
> for the reset to complete before returning from ice_resume(). In
> practice the reset completes in ~300ms.
Would not be better to (eventually) wait in ice_open()? Why? AFAICS that
would be also more consistent with i.e. the current wait in
ice_devlink_info_get().
Otherwise why don't consolidate all the wait at resume time and remove
the other one in ice_devlink_info_get()?
/P
^ permalink raw reply
* Re: [PATCH net 3/4] idpf: handle NULL adev in idpf_idc_vdev_mtu_event
From: Paolo Abeni @ 2026-07-07 8:31 UTC (permalink / raw)
To: anthony.l.nguyen
Cc: davem, kuba, pabeni, edumazet, andrew+netdev, netdev, tactii,
stable
In-Reply-To: <20260630214404.930923-4-anthony.l.nguyen@intel.com>
From: AI Reviewer <ai@example.com>
This is an AI-generated review of your patch. The human sending this
email has considered the AI review valid, or at least plausible.
Full review at: https://netdev-ai.bots.linux.dev/sashiko/
---
idpf: handle NULL adev in idpf_idc_vdev_mtu_event
This change caches vdev_info->adev with READ_ONCE() and returns early
when the cached pointer is NULL, so that device_lock()/device_unlock()
operate on the same captured auxiliary_device and do not dereference a
NULL adev field that was cleared by the teardown path.
> diff --git a/drivers/net/ethernet/intel/idpf/idpf_idc.c b/drivers/net/ethernet/intel/idpf/idpf_idc.c
> index b7d6b08fc89e..9f764135507c 100644
> --- a/drivers/net/ethernet/intel/idpf/idpf_idc.c
> +++ b/drivers/net/ethernet/intel/idpf/idpf_idc.c
> @@ -162,9 +162,12 @@ void idpf_idc_vdev_mtu_event(struct iidc_rdma_vport_dev_info *vdev_info,
>
> set_bit(event_type, event.type);
>
> - device_lock(&vdev_info->adev->dev);
> - adev = vdev_info->adev;
> - if (!adev || !adev->dev.driver)
> + adev = READ_ONCE(vdev_info->adev);
> + if (!adev)
> + return;
> +
> + device_lock(&adev->dev);
[High]
Does caching the pointer with READ_ONCE() actually make this safe against
the teardown path, or does it just narrow a NULL-deref into a
use-after-free on the mutex embedded in adev->dev?
Looking at the teardown side, idpf_idc_vport_dev_ctrl(adapter, false)
calls idpf_idc_vport_dev_down(), which calls idpf_unplug_aux_dev() on
vdev_info->adev:
idpf_unplug_aux_dev(adev)
auxiliary_device_delete(adev);
auxiliary_device_uninit(adev); /* put_device -> release -> kfree */
and only afterwards assigns vport->vdev_info->adev = NULL.
The MTU path runs under rtnl_lock and the vport_ctrl_lock, but
ig3rdma_core_remove() (which drives the IDC teardown via the auxiliary
bus) does not appear to take either of those, so the two paths are not
serialized against each other.
With the new code:
adev = READ_ONCE(vdev_info->adev);
if (!adev)
return;
device_lock(&adev->dev);
if the teardown path frees adev between the READ_ONCE() load and the
device_lock() call (it can, because the kfree happens before vdev_info->adev
is set to NULL, and there is no get_device()/put_device() or RCU barrier
on this path), then device_lock() operates on a freed struct device and
its embedded mutex.
Would the correct fix here pair the load with get_device()/put_device()
across the locked region, NULL out vdev_info->adev before the
auxiliary_device_uninit() in the teardown path, and add a
synchronize_rcu()-style barrier (or a shared lock) so the MTU path cannot
observe a freed adev?
> iadrv = container_of(adev->dev.driver,
> struct iidc_rdma_vport_auxiliary_drv,
> @@ -172,7 +175,7 @@ void idpf_idc_vdev_mtu_event(struct iidc_rdma_vport_dev_info *vdev_info,
> if (iadrv->event_handler)
> iadrv->event_handler(vdev_info, &event);
> unlock:
> - device_unlock(&vdev_info->adev->dev);
> + device_unlock(&adev->dev);
> }
--
This is an AI-generated review.
^ permalink raw reply
* Re: [PATCH net-next v8 9/9] selftests: net: Add a test for BIG TCP in UDP tunnels
From: Alice Mikityanska @ 2026-07-07 8:40 UTC (permalink / raw)
To: Paolo Abeni, Daniel Borkmann, David S. Miller, Eric Dumazet,
Jakub Kicinski, Xin Long, Willem de Bruijn, Willem de Bruijn,
David Ahern, Nikolay Aleksandrov
Cc: Shuah Khan, Stanislav Fomichev, Andrew Lunn, Simon Horman,
Florian Westphal, netdev, Alice Mikityanska
In-Reply-To: <80222d3f-e6cf-408b-b42f-0a2a6afce297@redhat.com>
On Tue, Jul 7, 2026, at 11:06, Paolo Abeni wrote:
> On 7/6/26 8:19 PM, Alice Mikityanska wrote:
>> From: Alice Mikityanska <alice@isovalent.com>
>>
>> The test sets up VXLAN and GENEVE tunnels over IPv4 and IPv6 and runs
>> IPv4 and IPv6 traffic through them with BIG TCP enabled. It checks that
>> a non-negligible amount of big aggregated packets are seen in tcpdump.
>>
>> Check the number of packets on both TX and RX sides to verify that GSO
>> packets are valid and not dropped. Capture on the lower netdev (veth),
>> when checksum offload is on, to verify that encapsulated BIG TCP packets
>> can get to their destination. In the test with TX checksum offload off,
>> software GSO splits aggregated VXLAN packets before passing them to
>> veth, so capture inside the tunnel instead to check that the big packets
>> are not dropped.
>>
>> Check that the amount of SACKs is negligible. On unsupported kernels,
>> some amount of broken GSO packets bigger than 65536 bytes can be
>> produced in VXLAN tunnels, but they don't reach the destination. Seeing
>> TCP SACKs is a sign that such packets could have been dropped (in such
>> cases, the amount of SACKs is a few times bigger than the number of
>> attempts to send BIG TCP packets).
>>
>> Signed-off-by: Alice Mikityanska <alice@isovalent.com>
>> ---
>> tools/testing/selftests/net/Makefile | 1 +
>> .../testing/selftests/net/big_tcp_tunnels.sh | 183 ++++++++++++++++++
>> 2 files changed, 184 insertions(+)
>> create mode 100755 tools/testing/selftests/net/big_tcp_tunnels.sh
>>
>> diff --git a/tools/testing/selftests/net/Makefile b/tools/testing/selftests/net/Makefile
>> index 708d960ae07d..4cb0a0bc1eea 100644
>> --- a/tools/testing/selftests/net/Makefile
>> +++ b/tools/testing/selftests/net/Makefile
>> @@ -13,6 +13,7 @@ TEST_PROGS := \
>> arp_ndisc_untracked_subnets.sh \
>> bareudp.sh \
>> big_tcp.sh \
>> + big_tcp_tunnels.sh \
>> bind_bhash.sh \
>> bpf_offload.py \
>> bridge_stp_mode.sh \
>> diff --git a/tools/testing/selftests/net/big_tcp_tunnels.sh b/tools/testing/selftests/net/big_tcp_tunnels.sh
>> new file mode 100755
>> index 000000000000..128a710e74ad
>> --- /dev/null
>> +++ b/tools/testing/selftests/net/big_tcp_tunnels.sh
>> @@ -0,0 +1,183 @@
>> +#!/usr/bin/env bash
>> +# SPDX-License-Identifier: GPL-2.0
>> +#
>> +# Testing for IPv4 and IPv6 BIG TCP over VXLAN and GENEVE tunnels.
>> +
>> +SERVER_NS=$(mktemp -u server-XXXXXXXX)
>> +SERVER_IP4="192.168.1.1"
>> +SERVER_IP6="2001:db8::1:1"
>> +SERVER_IP4_TUN="192.168.2.1"
>> +SERVER_IP6_TUN="2001:db8::2:1"
>> +
>> +CLIENT_NS=$(mktemp -u client-XXXXXXXX)
>> +CLIENT_IP4="192.168.1.2"
>> +CLIENT_IP6="2001:db8::1:2"
>> +CLIENT_IP4_TUN="192.168.2.2"
>> +CLIENT_IP6_TUN="2001:db8::2:2"
>> +
>> +: "${PACKETS_THRESHOLD:=1000}"
>> +
>> +# Kselftest framework requirement - SKIP code is 4.
>> +ksft_skip=4
>> +
>> +setup() {
>> + ip netns add "$SERVER_NS"
>> + ip netns add "$CLIENT_NS"
>> + ip -netns "$SERVER_NS" link add link1 type veth peer name link0 netns "$CLIENT_NS"
>> +
>> + ip -netns "$CLIENT_NS" link set link0 up
>> + ip -netns "$CLIENT_NS" addr replace "$CLIENT_IP4/24" dev link0
>> + ip -netns "$CLIENT_NS" addr replace "$CLIENT_IP6/112" dev link0 nodad
>> + ip -netns "$CLIENT_NS" link set link0 \
>> + gso_max_size 196608 gso_ipv4_max_size 196608 \
>> + gro_max_size 196608 gro_ipv4_max_size 196608
>> + ip -netns "$SERVER_NS" link set link1 up
>> + ip -netns "$SERVER_NS" addr replace "$SERVER_IP4/24" dev link1
>> + ip -netns "$SERVER_NS" addr replace "$SERVER_IP6/112" dev link1 nodad
>> + ip -netns "$SERVER_NS" link set link1 \
>> + gso_max_size 196608 gso_ipv4_max_size 196608 \
>> + gro_max_size 196608 gro_ipv4_max_size 196608
>> +
>> + ip netns exec "$SERVER_NS" netserver >/dev/null
>> +}
>> +
>> +setup_tunnel() {
>> + if [ "$2" = 4 ]; then
>> + SERVER_IP="$SERVER_IP4"
>> + CLIENT_IP="$CLIENT_IP4"
>> + echo "Setting up ${1^^} over IPv4, veth tx csum offload $3"
>> + else
>> + SERVER_IP="$SERVER_IP6"
>> + CLIENT_IP="$CLIENT_IP6"
>> + echo "Setting up ${1^^} over IPv6, veth tx csum offload $3"
>> + fi
>> +
>> + if [ "$1" = vxlan ]; then
>> + ip -netns "$CLIENT_NS" link add tun0 type vxlan \
>> + id 5001 remote "$SERVER_IP" local "$CLIENT_IP" dev link0 dstport 4789
>> + else
>> + ip -netns "$CLIENT_NS" link add tun0 type geneve \
>> + id 5001 remote "$SERVER_IP"
>> + fi
>> + ip -netns "$CLIENT_NS" link set tun0 up
>> + ip -netns "$CLIENT_NS" addr replace "$CLIENT_IP4_TUN/24" dev tun0
>> + ip -netns "$CLIENT_NS" addr replace "$CLIENT_IP6_TUN/112" dev tun0 nodad
>> + ip -netns "$CLIENT_NS" link set tun0 \
>> + gso_max_size 196608 gso_ipv4_max_size 196608 \
>> + gro_max_size 196608 gro_ipv4_max_size 196608
>> + if [ "$1" = vxlan ]; then
>> + ip -netns "$SERVER_NS" link add tun1 type vxlan \
>> + id 5001 remote "$CLIENT_IP" local "$SERVER_IP" dev link1 dstport 4789
>> + else
>> + ip -netns "$SERVER_NS" link add tun1 type geneve \
>> + id 5001 remote "$CLIENT_IP"
>> + fi
>> + ip -netns "$SERVER_NS" link set tun1 up
>> + ip -netns "$SERVER_NS" addr replace "$SERVER_IP4_TUN/24" dev tun1
>> + ip -netns "$SERVER_NS" addr replace "$SERVER_IP6_TUN/112" dev tun1 nodad
>> + ip -netns "$SERVER_NS" link set tun1 \
>> + gso_max_size 196608 gso_ipv4_max_size 196608 \
>> + gro_max_size 196608 gro_ipv4_max_size 196608
>> +
>> + ip netns exec "$CLIENT_NS" ethtool -K link0 tx-checksumming "$3" > /dev/null
>> + ip netns exec "$SERVER_NS" ethtool -K link1 tx-checksumming "$3" > /dev/null
>> +}
>> +
>> +cleanup_tunnel() {
>> + ip -netns "$CLIENT_NS" link del tun0
>> + ip -netns "$SERVER_NS" link del tun1
>> +}
>> +
>> +cleanup() {
>> + ip netns pids "$SERVER_NS" | xargs -r kill
>> + ip netns pids "$CLIENT_NS" | xargs -r kill
>> + ip netns del "$SERVER_NS"
>> + ip netns del "$CLIENT_NS"
>> + rm -rf "$WORKDIR"
>> +}
>> +
>> +do_test() {
>> + # When tx csum offload is off, software GSO is performed before passing the
>> + # packet to veth. Check BIG TCP packets inside the VXLAN tunnel to verify
>> + # the software checksum path: if the checksum code is broken, these packets
>> + # will be dropped.
>> + if [ "$2" = on ]; then
>> + CAPTURE_IFACE='link'
>> + else
>> + CAPTURE_IFACE='tun'
>> + fi
>> +
>> + ip netns exec "$SERVER_NS" tcpdump -nn -s 256 -i "${CAPTURE_IFACE}1" greater 65536 -w "$WORKDIR/server.pcap" 2> /dev/null &
>> + TCPDUMP_SERVER_PID="$!"
>> + ip netns exec "$CLIENT_NS" tcpdump -nn -s 256 -i "${CAPTURE_IFACE}0" greater 65536 -w "$WORKDIR/client.pcap" 2> /dev/null &
>> + TCPDUMP_CLIENT_PID="$!"
>> +
>> + # This filter doesn't capture all possible variants of SACK, but it's aimed
>> + # at the typical one where SACK follows after [nop, nop, timestamp, nop,
>> + # nop] (14 bytes after the 20-byte TCP header). IPv6 needs a separate match,
>> + # because man tcpdump says:
>> + # > Arithmetic expression against transport layer headers, like tcp[0], does
>> + # > not work against IPv6 packets. It only looks at IPv4 packets.
>> + ip netns exec "$SERVER_NS" tcpdump -nn -s 256 -i "tun1" '(tcp[tcpflags] & (tcp-syn|tcp-ack) = tcp-ack and tcp[34:2] & 0xffc3 = 0x0502) or (ip6[6] = 0x06 and ip6[53] & 0x12 = 0x10 and ip6[74:2] & 0xffc3 = 0x0502)' -w "$WORKDIR/sack.pcap" 2> /dev/null &
>> + TCPDUMP_SACK_PID="$!"
>> +
>> + if [ "$1" = 4 ]; then
>> + SERVER_IP="$SERVER_IP4_TUN"
>> + echo "Running IPv4 traffic in the tunnel"
>> + else
>> + SERVER_IP="$SERVER_IP6_TUN"
>> + echo "Running IPv6 traffic in the tunnel"
>> + fi
>> +
>> + sleep 1 # Give tcpdump a second to spin up.
>> + ip netns exec "$CLIENT_NS" netperf -t TCP_STREAM -l 5 -H "$SERVER_IP" -- \
>> + -m 80000 > /dev/null
>> + sleep 1 # Give tcpdump a second to process buffered packets.
>> + kill "$TCPDUMP_SERVER_PID" "$TCPDUMP_CLIENT_PID" "$TCPDUMP_SACK_PID"
>> + wait "$TCPDUMP_SERVER_PID" "$TCPDUMP_CLIENT_PID" "$TCPDUMP_SACK_PID"
>> + PACKETS_SERVER=$(tcpdump --count -r "$WORKDIR/server.pcap" 2> /dev/null | cut -d ' ' -f 1)
>> + PACKETS_CLIENT=$(tcpdump --count -r "$WORKDIR/client.pcap" 2> /dev/null | cut -d ' ' -f 1)
>> + PACKETS_SACK=$(tcpdump --count -r "$WORKDIR/sack.pcap" 2> /dev/null | cut -d ' ' -f 1)
>> +
>> + echo "Captured BIG TCP RX packets: $PACKETS_SERVER"
>> + echo "Captured BIG TCP TX packets: $PACKETS_CLIENT"
>> + echo "Captured TCP SACK packets: $PACKETS_SACK"
>> + [ "$PACKETS_SERVER" -gt "$PACKETS_THRESHOLD" ] || return 1
>> + [ "$PACKETS_CLIENT" -gt "$PACKETS_THRESHOLD" ] || return 1
>> + [ "$PACKETS_SACK" -lt "$(( PACKETS_CLIENT / 2 ))" ] || return 1
>
> KCI fails here, see:
>
> https://netdev-ctrl.bots.linux.dev/logs/vmksft/net/results/722863/156-big-tcp-tunnels-sh/stdout
>
> possibly the above parsing is a bit fragile/tcpdump version's dependent?!?
TL/DR: I've seen this when I ran out of space in /tmp before adding -s 256.
Hmm, the changes I made in this iteration were aimed at addressing version-
dependent behavior of tcpdump... I used to count the lines of its
output. Newer tcpdump prints two lines per encapsulated packet. Older
tcpdump can't parse BIG TCP in this test and prints one line per packet.
To make it more robust, I decided to store the pcap and count the
packets there (--count doesn't work with live capture when tcpdump is
interrupted). The pitfall is that now it takes a few hundred megabytes
in /tmp to store those pcaps.
Now, seeing empty stdout from tcpdump could be if the pcap file is empty
(doesn't contain the pcap header), because we ran out of space in /tmp
(first two tcpdumps took all space, the third didn't write the header -
I observed this behavior before I added -s 256). We don't see the
corresponding error messages, because tcpdump starts with 2> /dev/null
(otherwise it floods the screen with statistics). Could this be the
reason? How much space is allocated for /tmp in the CI runners?
I can probably address it by limiting the overall number of captured
packets with -c, but then I won't be able to compare $PACKETS_SACK
relative to $PACKETS_CLIENT.
> Note that KCI automatically drops from PW series with failing test.
>
> /P
^ permalink raw reply
* Re: [PATCH bpf-next v4 0/2] bpf, sockmap: disallow sockmap mutation from tc, xdp, socket_filter and flow_dissector
From: patchwork-bot+netdevbpf @ 2026-07-07 8:40 UTC (permalink / raw)
To: Sechang Lim
Cc: ast, daniel, andrii, eddyz87, memxor, john.fastabend, davem, kuba,
hawk, shuah, martin.lau, song, yonghong.song, jolsa, emil, sdf,
jiayuan.chen, varunrmallya, ihor.solodrai, bpf, netdev,
linux-kernel, linux-kselftest
In-Reply-To: <20260630145410.3648099-1-rhkrqnwk98@gmail.com>
Hello:
This series was applied to bpf/bpf-next.git (master)
by Daniel Borkmann <daniel@iogearbox.net>:
On Tue, 30 Jun 2026 14:54:04 +0000 you wrote:
> A tc, xdp, socket_filter or flow_dissector program updating or deleting
> a sockmap deadlocks on stab->lock vs sk_callback_lock and has no reason
> to. Patch 1 disallows it in may_update_sockmap(); patch 2 drops the
> selftests that exercised it.
>
> v4:
> - also drop BPF_PROG_TYPE_SOCKET_FILTER (John Fastabend)
>
> [...]
Here is the summary with links:
- [bpf-next,v4,1/2] bpf, sockmap: disallow update and delete from tc, xdp, socket_filter and flow_dissector
https://git.kernel.org/bpf/bpf-next/c/7fb52b3bd3a3
- [bpf-next,v4,2/2] selftests/bpf: drop tc/xdp/flow_dissector/socket_filter sockmap mutation tests
(no matching commit)
You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
^ permalink raw reply
* [PATCH RFC net-next v2] net: enforce net sysctl registration
From: Joel Granados @ 2026-07-07 8:42 UTC (permalink / raw)
To: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman
Cc: netdev, linux-kernel, Joel Granados
Replace the warning and file permission change with an error when an
"unsafe" net sysctl registration is detected.
One of the barriers preventing the const qualification of the ctl_tables
in the net directory is the permission (->mode) change in
ensure_safe_net_sysctl. This prep commit removes that barrier allowing
the const qualification of net ctl_tables.
Signed-off-by: Joel Granados <joel.granados@kernel.org>
---
What?
=====
Replace warning and file permission change with an error (reject
registration) when an "unsafe" net sysctl registration is detected.
Why?
====
The main motivation for this is to continue with the const qualification
of the ctl_table arrays [1]. The permission change inside
ensure_safe_net_sysctl disallows cons qualifiaction as it basically
modifies the entries before running the sysctl registration.
ent->mode &= ~0222;
Analysis
========
* I believe that there is currently now way that the permission change
gets executed [2]
* I found one case where the warning message was posted to lore
(vsock_sysctl_register) [3], but it made its to mainline as part of
the second case in [2].
* We should error anyway because writing to the global sysctl value
through a child netns is indicative of a bug [4].
RFC
===
I'm sending it out as an RFC as I would like to discuss the change to
ensure_safe_net_sysctl in isolation, but my idea is to send out a series
that actually const qualifies the clt_tables in the net directory. I
would be very thankful if you point me to anything that I have missed in
my analysis that shows that this cannot/shouldn't be done.
Changes in v2:
- Rebased on top of net-next
- Updated subject to "RFC net-next"
- Link to v1: https://lore.kernel.org/r/20260629-jag-net_const_qualify-v1-1-ee98b8fc400c@kernel.org
Best
[1]
https://git.kernel.org/pub/scm/linux/kernel/git/sysctl/sysctl.git/commit/?h=constfy-sysctl-6.14-rc1&id=1751f872cc97f992ed5c4c72c55588db1f0021e1
[2]
I have identified 4 contexts relevant to the ensure_safe_net_sysctl call
inside the network sysctl registration.
1. When the (struct net) == &init_net (like in iw_cm_init): In this case
ensure_safe_net_sysctl is not executed and permission modification
never happens.
2. When the ctl_table data (->data) gets "manually" assigned to
something other init_net (like in vsock_sysctl_register): In this
case ensure_safe_net_sysctl *is* executed but the data that is passed
is neither a module address (!is_module_address) nor a kernel core
address (!is_kernel_core_data); so the permission modification never
happens.
3. When the permissions are explicitly changed on a kmemdup'ed ctl_table
array (like in sysctl_core_net_init): in this case
ensure_safe_net_sysctl *is* executed but the permission modification
never happens as the mode is not writable.
4. When ctl have custom proc_handlers (like in nf_lwtunnel_net_init): In
this case ->data is NULL so it is not a module address
(!is_module_address) nor a kernel core address
(!is_kernel_core_data), so permission modification never happens.
It seems like there is no way of executing the permission change in
ensure_safe_net_sysctl. Please correct me if this is inacurate and help
me find the case that I missed.
[3]
https://lore.kernel.org/all/20260302194926.90378-1-graf@amazon.com/
[4]
The ensure_safe_net_sysctl function was introduced in Commit:
31c4d2f160eb7b17cbead24dc6efed06505a3fee ("net: Ensure net namespace
isolation of sysctls") which states that it is trying to prevent a
leak (indicative of a bug).
---
---
net/sysctl_net.c | 22 +++++++++++-----------
1 file changed, 11 insertions(+), 11 deletions(-)
diff --git a/net/sysctl_net.c b/net/sysctl_net.c
index 19e8048241bacb18de853d3b904d0f97fd2fe78a..c1630a266f8436d8962ceb87dc629964b2d71260 100644
--- a/net/sysctl_net.c
+++ b/net/sysctl_net.c
@@ -114,16 +114,16 @@ __init int net_sysctl_init(void)
goto out;
}
-/* Verify that sysctls for non-init netns are safe by either:
+/* Return error when sysctls for non-init netns are unsafe by verifying:
* 1) being read-only, or
* 2) having a data pointer which points outside of the global kernel/module
* data segment, and rather into the heap where a per-net object was
* allocated.
*/
-static void ensure_safe_net_sysctl(struct net *net, const char *path,
- struct ctl_table *table, size_t table_size)
+static int ensure_safe_net_sysctl(struct net *net, const char *path,
+ const struct ctl_table *table, size_t table_size)
{
- struct ctl_table *ent;
+ const struct ctl_table *ent;
pr_debug("Registering net sysctl (net %p): %s\n", net, path);
ent = table;
@@ -149,15 +149,14 @@ static void ensure_safe_net_sysctl(struct net *net, const char *path,
else
continue;
- /* If it is writable and points to kernel/module global
- * data, then it's probably a netns leak.
- */
+ /* Warn on netns leak. */
WARN(1, "sysctl %s/%s: data points to %s global data: %ps\n",
- path, ent->procname, where, ent->data);
+ path, ent->procname, where, ent->data);
- /* Make it "safe" by dropping writable perms */
- ent->mode &= ~0222;
+ return -EACCES;
}
+
+ return 0;
}
struct ctl_table_header *register_net_sysctl_sz(struct net *net,
@@ -166,7 +165,8 @@ struct ctl_table_header *register_net_sysctl_sz(struct net *net,
size_t table_size)
{
if (!net_eq(net, &init_net))
- ensure_safe_net_sysctl(net, path, table, table_size);
+ if (ensure_safe_net_sysctl(net, path, table, table_size))
+ return NULL;
return __register_sysctl_table(&net->sysctls, path, table, table_size);
}
---
base-commit: 474cff6868129755cf889edf40d7f491729fc588
change-id: 20260629-jag-net_const_qualify-f4e09759dac7
Best regards,
--
Joel Granados <joel.granados@kernel.org>
^ permalink raw reply related
* Re: [PATCH net-next v2 0/1] net: rnpgbe: fix mailbox endianness
From: Paolo Abeni @ 2026-07-07 8:45 UTC (permalink / raw)
To: Dong Yibo, andrew+netdev, davem, edumazet, kuba, vadim.fedorenko
Cc: netdev, linux-kernel, yaojun
In-Reply-To: <20260701032208.1843156-1-dong100@mucse.com>
On 7/1/26 5:22 AM, Dong Yibo wrote:
> The rnpgbe mailbox exchanges data through 32-bit MMIO registers in
> little-endian wire format. The original code had two problems:
>
> 1. FW structs with __le16/__le32 fields were cast to (u32 *) before
> reaching the transport, hiding the endian annotations from sparse.
>
> 2. No cpu_to_le32()/le32_to_cpu() conversion was performed between
> the CPU-endian MMIO values and the little-endian payload, causing
> data corruption on big-endian systems.
>
> v2 fixes this by introducing union wrappers around the FW structs
> and adding the missing byte-order conversions in the transport layer.
> All pointer casts on the mailbox data path are eliminated.
>
> Changelog:
> v1 -> v2:
> - Remove all pointer casts on the mailbox data path. Use union
> wrappers (mbx_fw_cmd_req_u, mbx_fw_cmd_reply_u) that overlay
> each FW struct with a __le32 dwords[] array. Callers fill
> named fields with cpu_to_le16/32() and pass dwords[] directly
> to the transport — no casts needed.
> - Change transport signatures from u32 */void * to explicit
> __le32 * so sparse can verify endian correctness.
> - Add comments in mucse_read_mbx_pf() and mucse_write_mbx_pf()
> explaining why memcpy_toio() cannot replace the readl()/writel()
> loop (the mailbox uses 32-bit MMIO registers, not byte-
> addressable RAM).
>
> links:
> ---
> v1: https://lore.kernel.org/netdev/20260617083531.251119-1-dong100@mucse.com/
A few process notes:
- this is 'net' material, I'm applying the patch there
- no needed for a cover letter for a one-patch series
/P
^ permalink raw reply
* [PATCH v4 net-next 00/14] net: enetc: cleanups and improvements
From: wei.fang @ 2026-07-07 8:18 UTC (permalink / raw)
To: claudiu.manoil, vladimir.oltean, xiaoning.wang, andrew+netdev,
davem, edumazet, kuba, pabeni, linux, wei.fang, chleroy,
maxime.chevallier
Cc: imx, netdev, linux-kernel, linuxppc-dev, linux-arm-kernel
From: Wei Fang <wei.fang@nxp.com>
The first group of patches (1, 2, 5-7) eliminates code duplication
between the ENETC v1 and v4 drivers. Since both hardware generations
share identical register layouts for MAC promiscuous mode, MAC hash
filters, and VLAN promiscuous mode - differing only in register address
offsets - common helper functions are extracted into enetc_pf_common.c
and shared by both drivers.
Patch 3 converts ndo_set_rx_mode() to ndo_set_rx_mode_async(), removing
the dedicated workqueue that was previously needed to defer MAC address
list updates to a sleepable context.
Patch 4 replaces counter-based MAFT entry tracking with a bitmap, which
keeps hardware and software state in sync and avoids partial failures
during entry allocation.
Patches 8 and 9 fix phylink-related issues: removing invalid code from
enetc4_pl_mac_link_up() and properly differentiating phylink capabilities
between pseudo-MAC and standalone MAC.
The remaining patches (10-14) are minor cleanups: removing a redundant
VLAN promiscuous mode initialization in probe, using the PCI device name
for the debugfs directory, simplifying port speed configuration, removing
a redundant num_vsi field, using alloc_etherdev_mqs() for the VF driver,
and using kzalloc_flex() for a flexible array allocation.
---
v4:
1. Improve enetc4_set_si_msix_num()
2. Update commit messages
v3 link: https://lore.kernel.org/imx/20260703101328.550714-1-wei.fang@oss.nxp.com/
v2 link: https://lore.kernel.org/imx/20260702025714.456233-1-wei.fang@oss.nxp.com/
v1 link: https://lore.kernel.org/imx/20260630072036.382761-1-wei.fang@oss.nxp.com/
---
Claudiu Manoil (1):
net: enetc: differentiate phylink capabilities for pseudo-MAC and
standalone MAC
Wei Fang (13):
net: enetc: extract common helpers for MAC promiscuous mode setting
net: enetc: extract common helpers for MAC hash filter configuration
net: enetc: convert ndo_set_rx_mode() to ndo_set_rx_mode_async()
net: enetc: improve MAFT entry management with bitmap tracking
net: enetc: use PCI device name for debugfs directory
net: enetc: simplify enetc4_set_port_speed()
net: enetc: remove invalid code from enetc4_pl_mac_link_up()
net: enetc: open-code enetc4_set_default_si_vlan_promisc()
net: enetc: refactor SI VLAN promiscuous mode configuration
net: enetc: move enetc_set_si_vlan_promisc() to enetc_pf_common.c
net: enetc: remove redundant num_vsi field from enetc_port_caps
net: enetc: use alloc_etherdev_mqs() to create netdev for VF driver
net: enetc: use kzalloc_flex() for enetc_psfp_gate allocation
drivers/net/ethernet/freescale/enetc/enetc.h | 4 +-
.../ethernet/freescale/enetc/enetc4_debugfs.c | 42 +-
.../net/ethernet/freescale/enetc/enetc4_hw.h | 6 +-
.../net/ethernet/freescale/enetc/enetc4_pf.c | 471 ++++++++----------
.../ethernet/freescale/enetc/enetc_ethtool.c | 2 +-
.../net/ethernet/freescale/enetc/enetc_hw.h | 12 +-
.../net/ethernet/freescale/enetc/enetc_pf.c | 94 +---
.../net/ethernet/freescale/enetc/enetc_pf.h | 6 -
.../freescale/enetc/enetc_pf_common.c | 150 +++++-
.../freescale/enetc/enetc_pf_common.h | 5 +
.../net/ethernet/freescale/enetc/enetc_qos.c | 4 +-
.../net/ethernet/freescale/enetc/enetc_vf.c | 9 +-
include/linux/fsl/ntmp.h | 2 +
13 files changed, 411 insertions(+), 396 deletions(-)
--
2.34.1
^ permalink raw reply
* [PATCH v4 net-next 01/14] net: enetc: extract common helpers for MAC promiscuous mode setting
From: wei.fang @ 2026-07-07 8:18 UTC (permalink / raw)
To: claudiu.manoil, vladimir.oltean, xiaoning.wang, andrew+netdev,
davem, edumazet, kuba, pabeni, linux, wei.fang, chleroy,
maxime.chevallier
Cc: imx, netdev, linux-kernel, linuxppc-dev, linux-arm-kernel
In-Reply-To: <20260707081834.710730-1-wei.fang@oss.nxp.com>
From: Wei Fang <wei.fang@nxp.com>
The PSIPMMR (Port Station Interface Promiscuous MAC Mode Register) in
ENETC v4 has the same bit layout as the PSIPMR register in ENETC v1: bit
n controls unicast promiscuous mode for SI n, and bit (n + 16) controls
multicast promiscuous mode for SI n. The only difference between the two
hardware generations is the register address offset.
Since the register functionality is identical, the MAC promiscuous mode
setting code can be shared between ENETC v1 and v4 drivers.
Rename ENETC_PSIPMR to ENETC_PSIPMMR in enetc_hw.h to match the actual
register name used in the reference manual, and extract two new common
helper functions, enetc_set_si_uc_promisc() and
enetc_set_si_mc_promisc(), into enetc_pf_common.c. These helpers select
the correct register offset based on the hardware revision via
is_enetc_rev1().
Remove the v4-specific enetc4_pf_set_si_mac_promisc() function from
enetc4_pf.c and the duplicate PSIPMMR_SI_MAC_UP/MP macro definitions
from enetc4_hw.h, as they are now superseded by the shared code.
Signed-off-by: Wei Fang <wei.fang@nxp.com>
---
.../net/ethernet/freescale/enetc/enetc4_hw.h | 2 -
.../net/ethernet/freescale/enetc/enetc4_pf.c | 21 +--------
.../ethernet/freescale/enetc/enetc_ethtool.c | 2 +-
.../net/ethernet/freescale/enetc/enetc_hw.h | 7 +--
.../net/ethernet/freescale/enetc/enetc_pf.c | 11 ++---
.../freescale/enetc/enetc_pf_common.c | 44 +++++++++++++++++++
.../freescale/enetc/enetc_pf_common.h | 2 +
7 files changed, 56 insertions(+), 33 deletions(-)
diff --git a/drivers/net/ethernet/freescale/enetc/enetc4_hw.h b/drivers/net/ethernet/freescale/enetc/enetc4_hw.h
index f18437556a0e..6a8f2ed56017 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc4_hw.h
+++ b/drivers/net/ethernet/freescale/enetc/enetc4_hw.h
@@ -69,8 +69,6 @@
/* Port Station interface promiscuous MAC mode register */
#define ENETC4_PSIPMMR 0x200
-#define PSIPMMR_SI_MAC_UP(a) BIT(a) /* a = SI index */
-#define PSIPMMR_SI_MAC_MP(a) BIT((a) + 16)
/* Port Station interface promiscuous VLAN mode register */
#define ENETC4_PSIPVMR 0x204
diff --git a/drivers/net/ethernet/freescale/enetc/enetc4_pf.c b/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
index 437a15bbb47b..304ec069654d 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
@@ -75,24 +75,6 @@ static void enetc4_pf_get_si_primary_mac(struct enetc_hw *hw, int si,
put_unaligned_le16(lower, addr + 4);
}
-static void enetc4_pf_set_si_mac_promisc(struct enetc_hw *hw, int si,
- bool uc_promisc, bool mc_promisc)
-{
- u32 val = enetc_port_rd(hw, ENETC4_PSIPMMR);
-
- if (uc_promisc)
- val |= PSIPMMR_SI_MAC_UP(si);
- else
- val &= ~PSIPMMR_SI_MAC_UP(si);
-
- if (mc_promisc)
- val |= PSIPMMR_SI_MAC_MP(si);
- else
- val &= ~PSIPMMR_SI_MAC_MP(si);
-
- enetc_port_wr(hw, ENETC4_PSIPMMR, val);
-}
-
static void enetc4_pf_set_si_uc_hash_filter(struct enetc_hw *hw, int si,
u64 hash)
{
@@ -515,7 +497,8 @@ static void enetc4_psi_do_set_rx_mode(struct work_struct *work)
type = ENETC_MAC_FILTER_TYPE_ALL;
}
- enetc4_pf_set_si_mac_promisc(hw, 0, uc_promisc, mc_promisc);
+ enetc_set_si_uc_promisc(si, 0, uc_promisc);
+ enetc_set_si_mc_promisc(si, 0, mc_promisc);
if (uc_promisc) {
enetc4_pf_set_si_uc_hash_filter(hw, 0, 0);
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c b/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c
index 71f376ef1be1..07b7832f2427 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c
@@ -29,7 +29,7 @@ static const u32 enetc_rxbdr_regs[] = {
};
static const u32 enetc_port_regs[] = {
- ENETC_PMR, ENETC_PSR, ENETC_PSIPMR, ENETC_PSIPMAR0(0),
+ ENETC_PMR, ENETC_PSR, ENETC_PSIPMMR, ENETC_PSIPMAR0(0),
ENETC_PSIPMAR1(0), ENETC_PTXMBAR, ENETC_PCAPR0, ENETC_PCAPR1,
ENETC_PSICFGR0(0), ENETC_PRFSCAPR, ENETC_PTCMSDUR(0),
ENETC_PM0_CMD_CFG, ENETC_PM0_MAXFRM, ENETC_PM0_IF_MODE
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_hw.h b/drivers/net/ethernet/freescale/enetc/enetc_hw.h
index bf99b65d7598..66bfda60da9c 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_hw.h
+++ b/drivers/net/ethernet/freescale/enetc/enetc_hw.h
@@ -180,9 +180,10 @@ enum enetc_bdr_type {TX, RX};
#define ENETC_PMR_PSPEED_1000M BIT(9)
#define ENETC_PMR_PSPEED_2500M BIT(10)
#define ENETC_PSR 0x0004 /* RO */
-#define ENETC_PSIPMR 0x0018
-#define ENETC_PSIPMR_SET_UP(n) BIT(n) /* n = SI index */
-#define ENETC_PSIPMR_SET_MP(n) BIT((n) + 16)
+#define ENETC_PSIPMMR 0x0018
+#define PSIPMMR_SI_MAC_UP(n) BIT(n) /* n = SI index */
+#define PSIPMMR_SI_MAC_MP(n) BIT((n) + 16)
+
#define ENETC_PSIPVMR 0x001c
#define ENETC_VLAN_PROMISC_MAP_ALL 0x7
#define ENETC_PSIPVMR_SET_VP(simap) ((simap) & 0x7)
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf.c b/drivers/net/ethernet/freescale/enetc/enetc_pf.c
index 2d687bb8c3a0..a97d2e2dd07b 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_pf.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc_pf.c
@@ -159,21 +159,17 @@ static void enetc_pf_set_rx_mode(struct net_device *ndev)
{
struct enetc_ndev_priv *priv = netdev_priv(ndev);
struct enetc_pf *pf = enetc_si_priv(priv->si);
- struct enetc_hw *hw = &priv->si->hw;
bool uprom = false, mprom = false;
struct enetc_mac_filter *filter;
struct netdev_hw_addr *ha;
- u32 psipmr = 0;
bool em;
if (ndev->flags & IFF_PROMISC) {
/* enable promisc mode for SI0 (PF) */
- psipmr = ENETC_PSIPMR_SET_UP(0) | ENETC_PSIPMR_SET_MP(0);
uprom = true;
mprom = true;
} else if (ndev->flags & IFF_ALLMULTI) {
/* enable multi cast promisc mode for SI0 (PF) */
- psipmr = ENETC_PSIPMR_SET_MP(0);
mprom = true;
}
@@ -211,9 +207,8 @@ static void enetc_pf_set_rx_mode(struct net_device *ndev)
/* update PF entries */
enetc_sync_mac_filters(pf);
- psipmr |= enetc_port_rd(hw, ENETC_PSIPMR) &
- ~(ENETC_PSIPMR_SET_UP(0) | ENETC_PSIPMR_SET_MP(0));
- enetc_port_wr(hw, ENETC_PSIPMR, psipmr);
+ enetc_set_si_uc_promisc(priv->si, 0, uprom);
+ enetc_set_si_mc_promisc(priv->si, 0, mprom);
}
static void enetc_set_loopback(struct net_device *ndev, bool en)
@@ -474,7 +469,7 @@ static void enetc_configure_port(struct enetc_pf *pf)
pf->vlan_promisc_simap = ENETC_VLAN_PROMISC_MAP_ALL;
enetc_set_vlan_promisc(hw, pf->vlan_promisc_simap);
- enetc_port_wr(hw, ENETC_PSIPMR, 0);
+ enetc_port_wr(hw, ENETC_PSIPMMR, 0);
/* enable port */
enetc_port_wr(hw, ENETC_PMR, ENETC_PMR_EN);
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf_common.c b/drivers/net/ethernet/freescale/enetc/enetc_pf_common.c
index 6e5d2f869915..b0c0dc668e34 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_pf_common.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc_pf_common.c
@@ -87,6 +87,50 @@ int enetc_setup_mac_addresses(struct device_node *np, struct enetc_pf *pf)
}
EXPORT_SYMBOL_GPL(enetc_setup_mac_addresses);
+void enetc_set_si_uc_promisc(struct enetc_si *si, int si_id, bool promisc)
+{
+ struct enetc_hw *hw = &si->hw;
+ int psipmmr_off;
+ u32 val;
+
+ if (is_enetc_rev1(si))
+ psipmmr_off = ENETC_PSIPMMR;
+ else
+ psipmmr_off = ENETC4_PSIPMMR;
+
+ val = enetc_port_rd(hw, psipmmr_off);
+
+ if (promisc)
+ val |= PSIPMMR_SI_MAC_UP(si_id);
+ else
+ val &= ~PSIPMMR_SI_MAC_UP(si_id);
+
+ enetc_port_wr(hw, psipmmr_off, val);
+}
+EXPORT_SYMBOL_GPL(enetc_set_si_uc_promisc);
+
+void enetc_set_si_mc_promisc(struct enetc_si *si, int si_id, bool promisc)
+{
+ struct enetc_hw *hw = &si->hw;
+ int psipmmr_off;
+ u32 val;
+
+ if (is_enetc_rev1(si))
+ psipmmr_off = ENETC_PSIPMMR;
+ else
+ psipmmr_off = ENETC4_PSIPMMR;
+
+ val = enetc_port_rd(hw, psipmmr_off);
+
+ if (promisc)
+ val |= PSIPMMR_SI_MAC_MP(si_id);
+ else
+ val &= ~PSIPMMR_SI_MAC_MP(si_id);
+
+ enetc_port_wr(hw, psipmmr_off, val);
+}
+EXPORT_SYMBOL_GPL(enetc_set_si_mc_promisc);
+
void enetc_pf_netdev_setup(struct enetc_si *si, struct net_device *ndev,
const struct net_device_ops *ndev_ops)
{
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf_common.h b/drivers/net/ethernet/freescale/enetc/enetc_pf_common.h
index 57d2e0ebd2b0..a619fb8fed9c 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_pf_common.h
+++ b/drivers/net/ethernet/freescale/enetc/enetc_pf_common.h
@@ -17,6 +17,8 @@ void enetc_set_default_rss_key(struct enetc_pf *pf);
int enetc_vlan_rx_add_vid(struct net_device *ndev, __be16 prot, u16 vid);
int enetc_vlan_rx_del_vid(struct net_device *ndev, __be16 prot, u16 vid);
int enetc_init_sriov_resources(struct enetc_pf *pf);
+void enetc_set_si_uc_promisc(struct enetc_si *si, int si_id, bool promisc);
+void enetc_set_si_mc_promisc(struct enetc_si *si, int si_id, bool promisc);
static inline u16 enetc_get_ip_revision(struct enetc_hw *hw)
{
--
2.34.1
^ permalink raw reply related
* [PATCH v4 net-next 02/14] net: enetc: extract common helpers for MAC hash filter configuration
From: wei.fang @ 2026-07-07 8:18 UTC (permalink / raw)
To: claudiu.manoil, vladimir.oltean, xiaoning.wang, andrew+netdev,
davem, edumazet, kuba, pabeni, linux, wei.fang, chleroy,
maxime.chevallier
Cc: imx, netdev, linux-kernel, linuxppc-dev, linux-arm-kernel
In-Reply-To: <20260707081834.710730-1-wei.fang@oss.nxp.com>
From: Wei Fang <wei.fang@nxp.com>
The PSIUMHFR and PSIMMHFR registers in ENETC v4 have the same bit layout
as in ENETC v1. The only difference between the two hardware generations
is the register address offsets.
Since the register functionality is identical, the MAC hash filter
configuration code can be shared between the ENETC v1 and v4 drivers.
Extract two new common helper functions, enetc_set_si_uc_hash_filter()
and enetc_set_si_mc_hash_filter(), into enetc_pf_common.c. These helpers
select the correct register offset based on the hardware revision via
is_enetc_rev1().
Remove v1-specific enetc_clear_mac_ht_flt() and enetc_set_mac_ht_flt()
from enetc_pf.c, and v4-specific enetc4_pf_set_si_uc_hash_filter() and
enetc4_pf_set_si_mc_hash_filter() from enetc4_pf.c, as they are now
superseded by the shared implementations.
Signed-off-by: Wei Fang <wei.fang@nxp.com>
---
.../net/ethernet/freescale/enetc/enetc4_pf.c | 43 +++++++---------
.../net/ethernet/freescale/enetc/enetc_pf.c | 51 +++++--------------
.../freescale/enetc/enetc_pf_common.c | 40 +++++++++++++++
.../freescale/enetc/enetc_pf_common.h | 2 +
4 files changed, 73 insertions(+), 63 deletions(-)
diff --git a/drivers/net/ethernet/freescale/enetc/enetc4_pf.c b/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
index 304ec069654d..48a74db90ed5 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
@@ -75,20 +75,6 @@ static void enetc4_pf_get_si_primary_mac(struct enetc_hw *hw, int si,
put_unaligned_le16(lower, addr + 4);
}
-static void enetc4_pf_set_si_uc_hash_filter(struct enetc_hw *hw, int si,
- u64 hash)
-{
- enetc_port_wr(hw, ENETC4_PSIUMHFR0(si), lower_32_bits(hash));
- enetc_port_wr(hw, ENETC4_PSIUMHFR1(si), upper_32_bits(hash));
-}
-
-static void enetc4_pf_set_si_mc_hash_filter(struct enetc_hw *hw, int si,
- u64 hash)
-{
- enetc_port_wr(hw, ENETC4_PSIMMHFR0(si), lower_32_bits(hash));
- enetc_port_wr(hw, ENETC4_PSIMMHFR1(si), upper_32_bits(hash));
-}
-
static void enetc4_pf_set_loopback(struct net_device *ndev, bool en)
{
struct enetc_ndev_priv *priv = netdev_priv(ndev);
@@ -147,11 +133,12 @@ static int enetc4_pf_set_uc_exact_filter(struct enetc_pf *pf)
int max_num_mfe = pf->caps.mac_filter_num;
struct enetc_mac_filter mac_filter = {};
struct net_device *ndev = pf->si->ndev;
- struct enetc_hw *hw = &pf->si->hw;
struct enetc_mac_addr *mac_tbl;
+ struct enetc_si *si = pf->si;
struct netdev_hw_addr *ha;
int i = 0, err;
int mac_cnt;
+ u64 hash;
netif_addr_lock_bh(ndev);
@@ -159,7 +146,7 @@ static int enetc4_pf_set_uc_exact_filter(struct enetc_pf *pf)
if (!mac_cnt) {
netif_addr_unlock_bh(ndev);
/* clear both MAC hash and exact filters */
- enetc4_pf_set_si_uc_hash_filter(hw, 0, 0);
+ enetc_set_si_uc_hash_filter(si, 0, 0);
enetc4_pf_clear_maft_entries(pf);
return 0;
@@ -186,11 +173,13 @@ static int enetc4_pf_set_uc_exact_filter(struct enetc_pf *pf)
/* Set temporary unicast hash filters in case of Rx loss when
* updating MAC address filter table
*/
- enetc4_pf_set_si_uc_hash_filter(hw, 0, *mac_filter.mac_hash_table);
+ bitmap_to_arr64(&hash, mac_filter.mac_hash_table,
+ ENETC_MADDR_HASH_TBL_SZ);
+ enetc_set_si_uc_hash_filter(si, 0, hash);
enetc4_pf_clear_maft_entries(pf);
if (!enetc4_pf_add_maft_entries(pf, mac_tbl, i))
- enetc4_pf_set_si_uc_hash_filter(hw, 0, 0);
+ enetc_set_si_uc_hash_filter(si, 0, 0);
kfree(mac_tbl);
@@ -206,8 +195,9 @@ static void enetc4_pf_set_mac_hash_filter(struct enetc_pf *pf, int type)
{
struct net_device *ndev = pf->si->ndev;
struct enetc_mac_filter *mac_filter;
- struct enetc_hw *hw = &pf->si->hw;
+ struct enetc_si *si = pf->si;
struct netdev_hw_addr *ha;
+ u64 hash;
netif_addr_lock_bh(ndev);
if (type & ENETC_MAC_FILTER_TYPE_UC) {
@@ -216,8 +206,9 @@ static void enetc4_pf_set_mac_hash_filter(struct enetc_pf *pf, int type)
netdev_for_each_uc_addr(ha, ndev)
enetc_add_mac_addr_ht_filter(mac_filter, ha->addr);
- enetc4_pf_set_si_uc_hash_filter(hw, 0,
- *mac_filter->mac_hash_table);
+ bitmap_to_arr64(&hash, mac_filter->mac_hash_table,
+ ENETC_MADDR_HASH_TBL_SZ);
+ enetc_set_si_uc_hash_filter(si, 0, hash);
}
if (type & ENETC_MAC_FILTER_TYPE_MC) {
@@ -226,8 +217,9 @@ static void enetc4_pf_set_mac_hash_filter(struct enetc_pf *pf, int type)
netdev_for_each_mc_addr(ha, ndev)
enetc_add_mac_addr_ht_filter(mac_filter, ha->addr);
- enetc4_pf_set_si_mc_hash_filter(hw, 0,
- *mac_filter->mac_hash_table);
+ bitmap_to_arr64(&hash, mac_filter->mac_hash_table,
+ ENETC_MADDR_HASH_TBL_SZ);
+ enetc_set_si_mc_hash_filter(si, 0, hash);
}
netif_addr_unlock_bh(ndev);
}
@@ -480,7 +472,6 @@ static void enetc4_psi_do_set_rx_mode(struct work_struct *work)
struct enetc_si *si = container_of(work, struct enetc_si, rx_mode_task);
struct enetc_pf *pf = enetc_si_priv(si);
struct net_device *ndev = si->ndev;
- struct enetc_hw *hw = &si->hw;
bool uc_promisc = false;
bool mc_promisc = false;
int type = 0;
@@ -501,12 +492,12 @@ static void enetc4_psi_do_set_rx_mode(struct work_struct *work)
enetc_set_si_mc_promisc(si, 0, mc_promisc);
if (uc_promisc) {
- enetc4_pf_set_si_uc_hash_filter(hw, 0, 0);
+ enetc_set_si_uc_hash_filter(si, 0, 0);
enetc4_pf_clear_maft_entries(pf);
}
if (mc_promisc)
- enetc4_pf_set_si_mc_hash_filter(hw, 0, 0);
+ enetc_set_si_mc_hash_filter(si, 0, 0);
/* Set new MAC filter */
enetc4_pf_set_mac_filter(pf, type);
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf.c b/drivers/net/ethernet/freescale/enetc/enetc_pf.c
index a97d2e2dd07b..db2a800a7aaf 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_pf.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc_pf.c
@@ -80,37 +80,6 @@ static void enetc_add_mac_addr_em_filter(struct enetc_mac_filter *filter,
filter->mac_addr_cnt++;
}
-static void enetc_clear_mac_ht_flt(struct enetc_si *si, int si_idx, int type)
-{
- bool err = si->errata & ENETC_ERR_UCMCSWP;
-
- if (type == UC) {
- enetc_port_wr(&si->hw, ENETC_PSIUMHFR0(si_idx, err), 0);
- enetc_port_wr(&si->hw, ENETC_PSIUMHFR1(si_idx), 0);
- } else { /* MC */
- enetc_port_wr(&si->hw, ENETC_PSIMMHFR0(si_idx, err), 0);
- enetc_port_wr(&si->hw, ENETC_PSIMMHFR1(si_idx), 0);
- }
-}
-
-static void enetc_set_mac_ht_flt(struct enetc_si *si, int si_idx, int type,
- unsigned long hash)
-{
- bool err = si->errata & ENETC_ERR_UCMCSWP;
-
- if (type == UC) {
- enetc_port_wr(&si->hw, ENETC_PSIUMHFR0(si_idx, err),
- lower_32_bits(hash));
- enetc_port_wr(&si->hw, ENETC_PSIUMHFR1(si_idx),
- upper_32_bits(hash));
- } else { /* MC */
- enetc_port_wr(&si->hw, ENETC_PSIMMHFR0(si_idx, err),
- lower_32_bits(hash));
- enetc_port_wr(&si->hw, ENETC_PSIMMHFR1(si_idx),
- upper_32_bits(hash));
- }
-}
-
static void enetc_sync_mac_filters(struct enetc_pf *pf)
{
struct enetc_mac_filter *f = pf->mac_filter;
@@ -122,12 +91,16 @@ static void enetc_sync_mac_filters(struct enetc_pf *pf)
for (i = 0; i < MADDR_TYPE; i++, f++) {
bool em = (f->mac_addr_cnt == 1) && (i == UC);
bool clear = !f->mac_addr_cnt;
+ u64 hash;
if (clear) {
- if (i == UC)
+ if (i == UC) {
enetc_clear_mac_flt_entry(si, pos);
+ enetc_set_si_uc_hash_filter(si, 0, 0);
+ } else {
+ enetc_set_si_mc_hash_filter(si, 0, 0);
+ }
- enetc_clear_mac_ht_flt(si, 0, i);
continue;
}
@@ -135,7 +108,7 @@ static void enetc_sync_mac_filters(struct enetc_pf *pf)
if (em) {
int err;
- enetc_clear_mac_ht_flt(si, 0, UC);
+ enetc_set_si_uc_hash_filter(si, 0, 0);
err = enetc_set_mac_flt_entry(si, pos, f->mac_addr,
BIT(0));
@@ -147,11 +120,15 @@ static void enetc_sync_mac_filters(struct enetc_pf *pf)
err);
}
+ bitmap_to_arr64(&hash, f->mac_hash_table,
+ ENETC_MADDR_HASH_TBL_SZ);
/* hash table filter, clear EM filter for UC entries */
- if (i == UC)
+ if (i == UC) {
enetc_clear_mac_flt_entry(si, pos);
-
- enetc_set_mac_ht_flt(si, 0, i, *f->mac_hash_table);
+ enetc_set_si_uc_hash_filter(si, 0, hash);
+ } else {
+ enetc_set_si_mc_hash_filter(si, 0, hash);
+ }
}
}
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf_common.c b/drivers/net/ethernet/freescale/enetc/enetc_pf_common.c
index b0c0dc668e34..3597cb81a7cc 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_pf_common.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc_pf_common.c
@@ -131,6 +131,46 @@ void enetc_set_si_mc_promisc(struct enetc_si *si, int si_id, bool promisc)
}
EXPORT_SYMBOL_GPL(enetc_set_si_mc_promisc);
+void enetc_set_si_uc_hash_filter(struct enetc_si *si, int si_id, u64 hash)
+{
+ int psiumhfr0_off, psiumhfr1_off;
+ struct enetc_hw *hw = &si->hw;
+
+ if (is_enetc_rev1(si)) {
+ bool err = si->errata & ENETC_ERR_UCMCSWP;
+
+ psiumhfr0_off = ENETC_PSIUMHFR0(si_id, err);
+ psiumhfr1_off = ENETC_PSIUMHFR1(si_id);
+ } else {
+ psiumhfr0_off = ENETC4_PSIUMHFR0(si_id);
+ psiumhfr1_off = ENETC4_PSIUMHFR1(si_id);
+ }
+
+ enetc_port_wr(hw, psiumhfr0_off, lower_32_bits(hash));
+ enetc_port_wr(hw, psiumhfr1_off, upper_32_bits(hash));
+}
+EXPORT_SYMBOL_GPL(enetc_set_si_uc_hash_filter);
+
+void enetc_set_si_mc_hash_filter(struct enetc_si *si, int si_id, u64 hash)
+{
+ int psimmhfr0_off, psimmhfr1_off;
+ struct enetc_hw *hw = &si->hw;
+
+ if (is_enetc_rev1(si)) {
+ bool err = si->errata & ENETC_ERR_UCMCSWP;
+
+ psimmhfr0_off = ENETC_PSIMMHFR0(si_id, err);
+ psimmhfr1_off = ENETC_PSIMMHFR1(si_id);
+ } else {
+ psimmhfr0_off = ENETC4_PSIMMHFR0(si_id);
+ psimmhfr1_off = ENETC4_PSIMMHFR1(si_id);
+ }
+
+ enetc_port_wr(hw, psimmhfr0_off, lower_32_bits(hash));
+ enetc_port_wr(hw, psimmhfr1_off, upper_32_bits(hash));
+}
+EXPORT_SYMBOL_GPL(enetc_set_si_mc_hash_filter);
+
void enetc_pf_netdev_setup(struct enetc_si *si, struct net_device *ndev,
const struct net_device_ops *ndev_ops)
{
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf_common.h b/drivers/net/ethernet/freescale/enetc/enetc_pf_common.h
index a619fb8fed9c..bf9029b0a017 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_pf_common.h
+++ b/drivers/net/ethernet/freescale/enetc/enetc_pf_common.h
@@ -19,6 +19,8 @@ int enetc_vlan_rx_del_vid(struct net_device *ndev, __be16 prot, u16 vid);
int enetc_init_sriov_resources(struct enetc_pf *pf);
void enetc_set_si_uc_promisc(struct enetc_si *si, int si_id, bool promisc);
void enetc_set_si_mc_promisc(struct enetc_si *si, int si_id, bool promisc);
+void enetc_set_si_uc_hash_filter(struct enetc_si *si, int si_id, u64 hash);
+void enetc_set_si_mc_hash_filter(struct enetc_si *si, int si_id, u64 hash);
static inline u16 enetc_get_ip_revision(struct enetc_hw *hw)
{
--
2.34.1
^ permalink raw reply related
* [PATCH v4 net-next 03/14] net: enetc: convert ndo_set_rx_mode() to ndo_set_rx_mode_async()
From: wei.fang @ 2026-07-07 8:18 UTC (permalink / raw)
To: claudiu.manoil, vladimir.oltean, xiaoning.wang, andrew+netdev,
davem, edumazet, kuba, pabeni, linux, wei.fang, chleroy,
maxime.chevallier
Cc: imx, netdev, linux-kernel, linuxppc-dev, linux-arm-kernel
In-Reply-To: <20260707081834.710730-1-wei.fang@oss.nxp.com>
From: Wei Fang <wei.fang@nxp.com>
The current ndo_set_rx_mode() is called under netif_addr_lock spinlock
with BHs disabled, which prevents drivers from sleeping. To work around
this limitation, the enetc driver uses a dedicated workqueue to defer
MAC address list updates to a sleepable context.
Since commit 3554b4345d85 ("net: introduce ndo_set_rx_mode_async and
netdev_rx_mode_work") introduced the ndo_set_rx_mode_async() callback,
drivers can now handle address list updates directly in a sleepable
context.
Therefore, convert the enetc driver to use ndo_set_rx_mode_async() and
remove the dedicated workqueue and the deferred work item accordingly.
Signed-off-by: Wei Fang <wei.fang@nxp.com>
---
drivers/net/ethernet/freescale/enetc/enetc.h | 2 -
.../net/ethernet/freescale/enetc/enetc4_pf.c | 178 ++++++------------
2 files changed, 58 insertions(+), 122 deletions(-)
diff --git a/drivers/net/ethernet/freescale/enetc/enetc.h b/drivers/net/ethernet/freescale/enetc/enetc.h
index 04a5dd5ea6c7..06a9f1ee0970 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc.h
+++ b/drivers/net/ethernet/freescale/enetc/enetc.h
@@ -324,8 +324,6 @@ struct enetc_si {
const struct enetc_drvdata *drvdata;
const struct enetc_si_ops *ops;
- struct workqueue_struct *workqueue;
- struct work_struct rx_mode_task;
struct dentry *debugfs_root;
struct enetc_msg_swbd msg; /* Only valid for VSI */
};
diff --git a/drivers/net/ethernet/freescale/enetc/enetc4_pf.c b/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
index 48a74db90ed5..a02b01753ff2 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
@@ -101,24 +101,23 @@ static void enetc4_pf_clear_maft_entries(struct enetc_pf *pf)
}
static int enetc4_pf_add_maft_entries(struct enetc_pf *pf,
- struct enetc_mac_addr *mac,
- int mac_cnt)
+ struct netdev_hw_addr_list *uc)
{
struct maft_entry_data maft = {};
+ struct netdev_hw_addr *ha;
u16 si_bit = BIT(0);
- int i, err;
+ int err;
maft.cfge.si_bitmap = cpu_to_le16(si_bit);
- for (i = 0; i < mac_cnt; i++) {
- ether_addr_copy(maft.keye.mac_addr, mac[i].addr);
- err = ntmp_maft_add_entry(&pf->si->ntmp_user, i, &maft);
- if (unlikely(err)) {
- pf->num_mfe = i;
+ netdev_hw_addr_list_for_each(ha, uc) {
+ ether_addr_copy(maft.keye.mac_addr, ha->addr);
+ err = ntmp_maft_add_entry(&pf->si->ntmp_user, pf->num_mfe,
+ &maft);
+ if (unlikely(err))
goto clear_maft_entries;
- }
- }
- pf->num_mfe = mac_cnt;
+ pf->num_mfe++;
+ }
return 0;
@@ -128,23 +127,29 @@ static int enetc4_pf_add_maft_entries(struct enetc_pf *pf,
return err;
}
-static int enetc4_pf_set_uc_exact_filter(struct enetc_pf *pf)
+static void enetc4_pf_set_uc_hash_filter(struct enetc_pf *pf,
+ struct netdev_hw_addr_list *uc)
{
- int max_num_mfe = pf->caps.mac_filter_num;
- struct enetc_mac_filter mac_filter = {};
- struct net_device *ndev = pf->si->ndev;
- struct enetc_mac_addr *mac_tbl;
- struct enetc_si *si = pf->si;
+ struct enetc_mac_filter *mac_filter = &pf->mac_filter[UC];
struct netdev_hw_addr *ha;
- int i = 0, err;
- int mac_cnt;
u64 hash;
- netif_addr_lock_bh(ndev);
+ enetc_reset_mac_addr_filter(mac_filter);
+ netdev_hw_addr_list_for_each(ha, uc)
+ enetc_add_mac_addr_ht_filter(mac_filter, ha->addr);
+
+ bitmap_to_arr64(&hash, mac_filter->mac_hash_table,
+ ENETC_MADDR_HASH_TBL_SZ);
+ enetc_set_si_uc_hash_filter(pf->si, 0, hash);
+}
+
+static int enetc4_pf_set_uc_exact_filter(struct enetc_pf *pf,
+ struct netdev_hw_addr_list *uc)
+{
+ int mac_cnt = netdev_hw_addr_list_count(uc);
+ struct enetc_si *si = pf->si;
- mac_cnt = netdev_uc_count(ndev);
if (!mac_cnt) {
- netif_addr_unlock_bh(ndev);
/* clear both MAC hash and exact filters */
enetc_set_si_uc_hash_filter(si, 0, 0);
enetc4_pf_clear_maft_entries(pf);
@@ -152,79 +157,42 @@ static int enetc4_pf_set_uc_exact_filter(struct enetc_pf *pf)
return 0;
}
- if (mac_cnt > max_num_mfe) {
- err = -ENOSPC;
- goto unlock_netif_addr;
- }
-
- mac_tbl = kzalloc_objs(*mac_tbl, mac_cnt, GFP_ATOMIC);
- if (!mac_tbl) {
- err = -ENOMEM;
- goto unlock_netif_addr;
- }
-
- netdev_for_each_uc_addr(ha, ndev) {
- enetc_add_mac_addr_ht_filter(&mac_filter, ha->addr);
- ether_addr_copy(mac_tbl[i++].addr, ha->addr);
- }
-
- netif_addr_unlock_bh(ndev);
+ if (mac_cnt > pf->caps.mac_filter_num)
+ return -ENOSPC;
/* Set temporary unicast hash filters in case of Rx loss when
* updating MAC address filter table
*/
- bitmap_to_arr64(&hash, mac_filter.mac_hash_table,
- ENETC_MADDR_HASH_TBL_SZ);
- enetc_set_si_uc_hash_filter(si, 0, hash);
+ enetc4_pf_set_uc_hash_filter(pf, uc);
enetc4_pf_clear_maft_entries(pf);
- if (!enetc4_pf_add_maft_entries(pf, mac_tbl, i))
+ if (!enetc4_pf_add_maft_entries(pf, uc)) {
+ enetc_reset_mac_addr_filter(&pf->mac_filter[UC]);
enetc_set_si_uc_hash_filter(si, 0, 0);
-
- kfree(mac_tbl);
+ }
return 0;
-
-unlock_netif_addr:
- netif_addr_unlock_bh(ndev);
-
- return err;
}
-static void enetc4_pf_set_mac_hash_filter(struct enetc_pf *pf, int type)
+static void enetc4_pf_set_mc_hash_filter(struct enetc_pf *pf,
+ struct netdev_hw_addr_list *mc)
{
- struct net_device *ndev = pf->si->ndev;
- struct enetc_mac_filter *mac_filter;
- struct enetc_si *si = pf->si;
+ struct enetc_mac_filter *mac_filter = &pf->mac_filter[MC];
struct netdev_hw_addr *ha;
u64 hash;
- netif_addr_lock_bh(ndev);
- if (type & ENETC_MAC_FILTER_TYPE_UC) {
- mac_filter = &pf->mac_filter[UC];
- enetc_reset_mac_addr_filter(mac_filter);
- netdev_for_each_uc_addr(ha, ndev)
- enetc_add_mac_addr_ht_filter(mac_filter, ha->addr);
-
- bitmap_to_arr64(&hash, mac_filter->mac_hash_table,
- ENETC_MADDR_HASH_TBL_SZ);
- enetc_set_si_uc_hash_filter(si, 0, hash);
- }
+ enetc_reset_mac_addr_filter(mac_filter);
+ netdev_hw_addr_list_for_each(ha, mc)
+ enetc_add_mac_addr_ht_filter(mac_filter, ha->addr);
- if (type & ENETC_MAC_FILTER_TYPE_MC) {
- mac_filter = &pf->mac_filter[MC];
- enetc_reset_mac_addr_filter(mac_filter);
- netdev_for_each_mc_addr(ha, ndev)
- enetc_add_mac_addr_ht_filter(mac_filter, ha->addr);
-
- bitmap_to_arr64(&hash, mac_filter->mac_hash_table,
- ENETC_MADDR_HASH_TBL_SZ);
- enetc_set_si_mc_hash_filter(si, 0, hash);
- }
- netif_addr_unlock_bh(ndev);
+ bitmap_to_arr64(&hash, mac_filter->mac_hash_table,
+ ENETC_MADDR_HASH_TBL_SZ);
+ enetc_set_si_mc_hash_filter(pf->si, 0, hash);
}
-static void enetc4_pf_set_mac_filter(struct enetc_pf *pf, int type)
+static void enetc4_pf_set_mac_filter(struct enetc_pf *pf, int type,
+ struct netdev_hw_addr_list *uc,
+ struct netdev_hw_addr_list *mc)
{
/* Currently, the MAC address filter table (MAFT) only has 4 entries,
* and multiple multicast addresses for filtering will be configured
@@ -232,15 +200,16 @@ static void enetc4_pf_set_mac_filter(struct enetc_pf *pf, int type)
* unicast filtering. If the number of unicast addresses exceeds the
* table capacity, the MAC hash filter will be used.
*/
- if (type & ENETC_MAC_FILTER_TYPE_UC && enetc4_pf_set_uc_exact_filter(pf)) {
+ if (type & ENETC_MAC_FILTER_TYPE_UC &&
+ enetc4_pf_set_uc_exact_filter(pf, uc)) {
/* Fall back to the MAC hash filter */
- enetc4_pf_set_mac_hash_filter(pf, ENETC_MAC_FILTER_TYPE_UC);
+ enetc4_pf_set_uc_hash_filter(pf, uc);
/* Clear the old MAC exact filter */
enetc4_pf_clear_maft_entries(pf);
}
if (type & ENETC_MAC_FILTER_TYPE_MC)
- enetc4_pf_set_mac_hash_filter(pf, ENETC_MAC_FILTER_TYPE_MC);
+ enetc4_pf_set_mc_hash_filter(pf, mc);
}
static const struct enetc_pf_ops enetc4_pf_ops = {
@@ -467,17 +436,17 @@ static void enetc4_pf_free(struct enetc_pf *pf)
enetc4_free_ntmp_user(pf->si);
}
-static void enetc4_psi_do_set_rx_mode(struct work_struct *work)
+static int enetc4_pf_set_rx_mode(struct net_device *ndev,
+ struct netdev_hw_addr_list *uc,
+ struct netdev_hw_addr_list *mc)
{
- struct enetc_si *si = container_of(work, struct enetc_si, rx_mode_task);
- struct enetc_pf *pf = enetc_si_priv(si);
- struct net_device *ndev = si->ndev;
+ struct enetc_ndev_priv *priv = netdev_priv(ndev);
+ struct enetc_pf *pf = enetc_si_priv(priv->si);
+ struct enetc_si *si = priv->si;
bool uc_promisc = false;
bool mc_promisc = false;
int type = 0;
- rtnl_lock();
-
if (ndev->flags & IFF_PROMISC) {
uc_promisc = true;
mc_promisc = true;
@@ -500,17 +469,9 @@ static void enetc4_psi_do_set_rx_mode(struct work_struct *work)
enetc_set_si_mc_hash_filter(si, 0, 0);
/* Set new MAC filter */
- enetc4_pf_set_mac_filter(pf, type);
-
- rtnl_unlock();
-}
+ enetc4_pf_set_mac_filter(pf, type, uc, mc);
-static void enetc4_pf_set_rx_mode(struct net_device *ndev)
-{
- struct enetc_ndev_priv *priv = netdev_priv(ndev);
- struct enetc_si *si = priv->si;
-
- queue_work(si->workqueue, &si->rx_mode_task);
+ return 0;
}
static int enetc4_pf_set_features(struct net_device *ndev,
@@ -540,7 +501,7 @@ static const struct net_device_ops enetc4_ndev_ops = {
.ndo_start_xmit = enetc_xmit,
.ndo_get_stats = enetc_get_stats,
.ndo_set_mac_address = enetc_pf_set_mac_addr,
- .ndo_set_rx_mode = enetc4_pf_set_rx_mode,
+ .ndo_set_rx_mode_async = enetc4_pf_set_rx_mode,
.ndo_set_features = enetc4_pf_set_features,
.ndo_vlan_rx_add_vid = enetc_vlan_rx_add_vid,
.ndo_vlan_rx_kill_vid = enetc_vlan_rx_del_vid,
@@ -983,19 +944,6 @@ static void enetc4_link_deinit(struct enetc_ndev_priv *priv)
enetc_mdiobus_destroy(pf);
}
-static int enetc4_psi_wq_task_init(struct enetc_si *si)
-{
- char wq_name[24];
-
- INIT_WORK(&si->rx_mode_task, enetc4_psi_do_set_rx_mode);
- snprintf(wq_name, sizeof(wq_name), "enetc-%s", pci_name(si->pdev));
- si->workqueue = create_singlethread_workqueue(wq_name);
- if (!si->workqueue)
- return -ENOMEM;
-
- return 0;
-}
-
static int enetc4_pf_netdev_create(struct enetc_si *si)
{
struct device *dev = &si->pdev->dev;
@@ -1036,12 +984,6 @@ static int enetc4_pf_netdev_create(struct enetc_si *si)
if (err)
goto err_link_init;
- err = enetc4_psi_wq_task_init(si);
- if (err) {
- dev_err(dev, "Failed to init workqueue\n");
- goto err_wq_init;
- }
-
err = register_netdev(ndev);
if (err) {
dev_err(dev, "Failed to register netdev\n");
@@ -1051,8 +993,6 @@ static int enetc4_pf_netdev_create(struct enetc_si *si)
return 0;
err_reg_netdev:
- destroy_workqueue(si->workqueue);
-err_wq_init:
enetc4_link_deinit(priv);
err_link_init:
enetc_free_msix(priv);
@@ -1070,8 +1010,6 @@ static void enetc4_pf_netdev_destroy(struct enetc_si *si)
struct net_device *ndev = si->ndev;
unregister_netdev(ndev);
- cancel_work(&si->rx_mode_task);
- destroy_workqueue(si->workqueue);
enetc4_link_deinit(priv);
enetc_free_msix(priv);
free_netdev(ndev);
--
2.34.1
^ permalink raw reply related
* [PATCH v4 net-next 04/14] net: enetc: improve MAFT entry management with bitmap tracking
From: wei.fang @ 2026-07-07 8:18 UTC (permalink / raw)
To: claudiu.manoil, vladimir.oltean, xiaoning.wang, andrew+netdev,
davem, edumazet, kuba, pabeni, linux, wei.fang, chleroy,
maxime.chevallier
Cc: imx, netdev, linux-kernel, linuxppc-dev, linux-arm-kernel
In-Reply-To: <20260707081834.710730-1-wei.fang@oss.nxp.com>
From: Wei Fang <wei.fang@nxp.com>
Replace the counter-based MAFT entry tracking (num_mfe/mac_filter_num)
with a bitmap (maft_eid_bitmap) stored in struct ntmp_user, which is a
more appropriate place for NTMP resource management.
The bitmap approach brings two improvements. First, the entry deletion
in enetc4_pf_clear_maft_entries() now checks the return value of
ntmp_maft_delete_entry() and only clears the corresponding bit on
success, keeping hardware and software state in sync. Previously, the
counter was reset unconditionally regardless of whether the hardware
deletion actually succeeded.
Second, entry allocation in enetc4_pf_add_maft_entries() uses
ntmp_lookup_free_eid() to find available IDs dynamically, with an
upfront capacity check via bitmap_weight() to avoid partial failures.
The MAFT entry count is moved into ntmp_user.maft_num_entries and
initialized once during enetc4_init_ntmp_user(). Helper functions
enetc4_ntmp_bitmap_init() and enetc4_ntmp_bitmap_free() manage the
bitmap lifetime. The debugfs show function is updated accordingly to
iterate over set bits under rtnl_lock().
Signed-off-by: Wei Fang <wei.fang@nxp.com>
---
.../ethernet/freescale/enetc/enetc4_debugfs.c | 30 ++++--
.../net/ethernet/freescale/enetc/enetc4_pf.c | 97 ++++++++++++++-----
.../net/ethernet/freescale/enetc/enetc_pf.h | 3 -
include/linux/fsl/ntmp.h | 2 +
4 files changed, 96 insertions(+), 36 deletions(-)
diff --git a/drivers/net/ethernet/freescale/enetc/enetc4_debugfs.c b/drivers/net/ethernet/freescale/enetc/enetc4_debugfs.c
index 1b1591dce73d..4a769d9e5679 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc4_debugfs.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc4_debugfs.c
@@ -31,9 +31,11 @@ static int enetc_mac_filter_show(struct seq_file *s, void *data)
struct enetc_si *si = s->private;
struct enetc_hw *hw = &si->hw;
struct maft_entry_data maft;
+ struct ntmp_user *user;
struct enetc_pf *pf;
- int i, err, num_si;
- u32 val;
+ u32 val, entry_id;
+ int i, num_si;
+ int err = 0;
pf = enetc_si_priv(si);
num_si = pf->caps.num_vsi + 1;
@@ -50,22 +52,30 @@ static int enetc_mac_filter_show(struct seq_file *s, void *data)
for (i = 0; i < num_si; i++)
enetc_show_si_mac_hash_filter(s, i);
- if (!pf->num_mfe)
- return 0;
+ user = &si->ntmp_user;
+ rtnl_lock();
+
+ if (bitmap_empty(user->maft_eid_bitmap, user->maft_num_entries))
+ goto unlock_rtnl;
/* MAC address filter table */
seq_puts(s, "MAC address filter table\n");
- for (i = 0; i < pf->num_mfe; i++) {
+ for_each_set_bit(entry_id, user->maft_eid_bitmap,
+ user->maft_num_entries) {
memset(&maft, 0, sizeof(maft));
- err = ntmp_maft_query_entry(&si->ntmp_user, i, &maft);
+ err = ntmp_maft_query_entry(user, entry_id, &maft);
if (err)
- return err;
+ goto unlock_rtnl;
- seq_printf(s, "Entry %d, MAC: %pM, SI bitmap: 0x%04x\n", i,
- maft.keye.mac_addr, le16_to_cpu(maft.cfge.si_bitmap));
+ seq_printf(s, "Entry %d, MAC: %pM, SI bitmap: 0x%04x\n",
+ entry_id, maft.keye.mac_addr,
+ le16_to_cpu(maft.cfge.si_bitmap));
}
- return 0;
+unlock_rtnl:
+ rtnl_unlock();
+
+ return err;
}
DEFINE_SHOW_ATTRIBUTE(enetc_mac_filter);
diff --git a/drivers/net/ethernet/freescale/enetc/enetc4_pf.c b/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
index a02b01753ff2..b966637572a7 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
+++ b/drivers/net/ethernet/freescale/enetc/enetc4_pf.c
@@ -32,9 +32,6 @@ static void enetc4_get_port_caps(struct enetc_pf *pf)
val = enetc_port_rd(hw, ENETC4_PMCAPR);
pf->caps.half_duplex = (val & PMCAPR_HD) ? 1 : 0;
-
- val = enetc_port_rd(hw, ENETC4_PSIMAFCAPR);
- pf->caps.mac_filter_num = val & PSIMAFCAPR_NUM_MAC_AFTE;
}
static void enetc4_get_psi_hw_features(struct enetc_si *si)
@@ -92,31 +89,45 @@ static void enetc4_pf_set_loopback(struct net_device *ndev, bool en)
static void enetc4_pf_clear_maft_entries(struct enetc_pf *pf)
{
- int i;
+ struct ntmp_user *user = &pf->si->ntmp_user;
+ u32 entry_id;
- for (i = 0; i < pf->num_mfe; i++)
- ntmp_maft_delete_entry(&pf->si->ntmp_user, i);
-
- pf->num_mfe = 0;
+ for_each_set_bit(entry_id, user->maft_eid_bitmap,
+ user->maft_num_entries) {
+ if (!ntmp_maft_delete_entry(user, entry_id))
+ ntmp_clear_eid_bitmap(user->maft_eid_bitmap, entry_id);
+ }
}
static int enetc4_pf_add_maft_entries(struct enetc_pf *pf,
struct netdev_hw_addr_list *uc)
{
+ struct ntmp_user *user = &pf->si->ntmp_user;
+ int mac_cnt = netdev_hw_addr_list_count(uc);
struct maft_entry_data maft = {};
struct netdev_hw_addr *ha;
+ u32 available_entries;
u16 si_bit = BIT(0);
+ u32 entry_id;
int err;
+ available_entries = user->maft_num_entries -
+ bitmap_weight(user->maft_eid_bitmap,
+ user->maft_num_entries);
+
+ if (mac_cnt > available_entries)
+ return -ENOSPC;
+
maft.cfge.si_bitmap = cpu_to_le16(si_bit);
netdev_hw_addr_list_for_each(ha, uc) {
+ entry_id = ntmp_lookup_free_eid(user->maft_eid_bitmap,
+ user->maft_num_entries);
ether_addr_copy(maft.keye.mac_addr, ha->addr);
- err = ntmp_maft_add_entry(&pf->si->ntmp_user, pf->num_mfe,
- &maft);
- if (unlikely(err))
+ err = ntmp_maft_add_entry(user, entry_id, &maft);
+ if (unlikely(err)) {
+ ntmp_clear_eid_bitmap(user->maft_eid_bitmap, entry_id);
goto clear_maft_entries;
-
- pf->num_mfe++;
+ }
}
return 0;
@@ -146,10 +157,10 @@ static void enetc4_pf_set_uc_hash_filter(struct enetc_pf *pf,
static int enetc4_pf_set_uc_exact_filter(struct enetc_pf *pf,
struct netdev_hw_addr_list *uc)
{
- int mac_cnt = netdev_hw_addr_list_count(uc);
struct enetc_si *si = pf->si;
+ int err;
- if (!mac_cnt) {
+ if (netdev_hw_addr_list_empty(uc)) {
/* clear both MAC hash and exact filters */
enetc_set_si_uc_hash_filter(si, 0, 0);
enetc4_pf_clear_maft_entries(pf);
@@ -157,21 +168,19 @@ static int enetc4_pf_set_uc_exact_filter(struct enetc_pf *pf,
return 0;
}
- if (mac_cnt > pf->caps.mac_filter_num)
- return -ENOSPC;
-
- /* Set temporary unicast hash filters in case of Rx loss when
+ /* Set temporary unicast hash filter in case of Rx loss when
* updating MAC address filter table
*/
enetc4_pf_set_uc_hash_filter(pf, uc);
enetc4_pf_clear_maft_entries(pf);
- if (!enetc4_pf_add_maft_entries(pf, uc)) {
+ err = enetc4_pf_add_maft_entries(pf, uc);
+ if (!err) {
enetc_reset_mac_addr_filter(&pf->mac_filter[UC]);
enetc_set_si_uc_hash_filter(si, 0, 0);
}
- return 0;
+ return err;
}
static void enetc4_pf_set_mc_hash_filter(struct enetc_pf *pf,
@@ -393,18 +402,60 @@ static void enetc4_configure_port(struct enetc_pf *pf)
enetc_set_default_rss_key(pf);
}
+static void enetc4_get_ntmp_caps(struct enetc_si *si)
+{
+ struct ntmp_user *user = &si->ntmp_user;
+ struct enetc_hw *hw = &si->hw;
+ u32 val;
+
+ val = enetc_port_rd(hw, ENETC4_PSIMAFCAPR);
+ user->maft_num_entries = FIELD_GET(PSIMAFCAPR_NUM_MAC_AFTE, val);
+}
+
+static int enetc4_ntmp_bitmap_init(struct ntmp_user *user)
+{
+ user->maft_eid_bitmap = bitmap_zalloc(user->maft_num_entries,
+ GFP_KERNEL);
+ if (!user->maft_eid_bitmap)
+ return -ENOMEM;
+
+ return 0;
+}
+
+static void enetc4_ntmp_bitmap_free(struct ntmp_user *user)
+{
+ bitmap_free(user->maft_eid_bitmap);
+ user->maft_eid_bitmap = NULL;
+}
+
static int enetc4_init_ntmp_user(struct enetc_si *si)
{
struct ntmp_user *user = &si->ntmp_user;
+ int err;
/* For ENETC 4.1, all table versions are 0 */
memset(&user->tbl, 0, sizeof(user->tbl));
- return enetc4_setup_cbdr(si);
+ err = enetc4_setup_cbdr(si);
+ if (err)
+ return err;
+
+ enetc4_get_ntmp_caps(si);
+ err = enetc4_ntmp_bitmap_init(user);
+ if (err)
+ goto teardown_cbdr;
+
+ return 0;
+
+teardown_cbdr:
+ enetc4_teardown_cbdr(si);
+
+ return err;
}
static void enetc4_free_ntmp_user(struct enetc_si *si)
{
+ enetc4_ntmp_bitmap_free(&si->ntmp_user);
enetc4_teardown_cbdr(si);
}
@@ -422,7 +473,7 @@ static int enetc4_pf_init(struct enetc_pf *pf)
err = enetc4_init_ntmp_user(pf->si);
if (err) {
- dev_err(dev, "Failed to init CBDR\n");
+ dev_err(dev, "Failed to init NTMP user\n");
return err;
}
diff --git a/drivers/net/ethernet/freescale/enetc/enetc_pf.h b/drivers/net/ethernet/freescale/enetc/enetc_pf.h
index 285b7e5c48fd..6f15f9ea1664 100644
--- a/drivers/net/ethernet/freescale/enetc/enetc_pf.h
+++ b/drivers/net/ethernet/freescale/enetc/enetc_pf.h
@@ -22,7 +22,6 @@ struct enetc_port_caps {
int num_msix;
int num_rx_bdr;
int num_tx_bdr;
- int mac_filter_num;
};
struct enetc_pf;
@@ -60,8 +59,6 @@ struct enetc_pf {
struct enetc_port_caps caps;
const struct enetc_pf_ops *ops;
-
- int num_mfe; /* number of mac address filter table entries */
};
#define phylink_to_enetc_pf(config) \
diff --git a/include/linux/fsl/ntmp.h b/include/linux/fsl/ntmp.h
index d3b6c476b91a..764ef2892608 100644
--- a/include/linux/fsl/ntmp.h
+++ b/include/linux/fsl/ntmp.h
@@ -75,8 +75,10 @@ struct ntmp_user {
/* NTMP table bitmaps for resource management */
u32 ett_bitmap_size;
u32 ect_bitmap_size;
+ u16 maft_num_entries;
unsigned long *ett_gid_bitmap; /* only valid for switch */
unsigned long *ect_gid_bitmap; /* only valid for switch */
+ unsigned long *maft_eid_bitmap; /* only valid for ENETC */
};
struct maft_entry_data {
--
2.34.1
^ permalink raw reply related
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