* Re: [PATCH v1 05/22] dt-bindings: clock: Add StarFive JHB100 System-0 clock and reset generator
From: Changhuang Liang @ 2026-04-03 0:53 UTC (permalink / raw)
To: Philipp Zabel, Michael Turquette, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Stephen Boyd, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti, Emil Renner Berthing,
Kees Cook, Gustavo A . R . Silva, Richard Cochran
Cc: linux-clk@vger.kernel.org, linux-kernel@vger.kernel.org,
devicetree@vger.kernel.org, linux-riscv@lists.infradead.org,
linux-hardening@vger.kernel.org, netdev@vger.kernel.org,
JeeHeng Sia, Hal Feng, Leyfoon Tan
In-Reply-To: <2d3ef7359f63fb364cb7bc13b721132894428874.camel@pengutronix.de>
> On Do, 2026-04-02 at 03:55 -0700, Changhuang Liang wrote:
> > Add bindings for the System-0 clocks and reset generator (SYS0CRG) on
> > JHB100 SoC.
> >
> > Signed-off-by: Changhuang Liang <changhuang.liang@starfivetech.com>
> > ---
> > .../clock/starfive,jhb100-sys0crg.yaml | 63
> +++++++++++++++++++
> > .../dt-bindings/clock/starfive,jhb100-crg.h | 56 +++++++++++++++++
> > .../dt-bindings/reset/starfive,jhb100-crg.h | 30 +++++++++
> > 3 files changed, 149 insertions(+)
> > create mode 100644
> > Documentation/devicetree/bindings/clock/starfive,jhb100-sys0crg.yaml
> > create mode 100644 include/dt-bindings/clock/starfive,jhb100-crg.h
> > create mode 100644 include/dt-bindings/reset/starfive,jhb100-crg.h
> >
> [...]
> > diff --git a/include/dt-bindings/reset/starfive,jhb100-crg.h
> > b/include/dt-bindings/reset/starfive,jhb100-crg.h
> > new file mode 100644
> > index 000000000000..71affdcdf733
> > --- /dev/null
> > +++ b/include/dt-bindings/reset/starfive,jhb100-crg.h
> > @@ -0,0 +1,30 @@
> > +/* SPDX-License-Identifier: GPL-2.0 OR MIT */
> > +/*
> > + * Copyright (C) 2024 StarFive Technology Co., Ltd.
> > + * Author: Changhuang Liang <changhuang.liang@starfivetech.com>
> > + *
> > + */
> > +
> > +#ifndef __DT_BINDINGS_RESET_STARFIVE_JHB100_CRG_H__
> > +#define __DT_BINDINGS_RESET_STARFIVE_JHB100_CRG_H__
> > +
> > +/* SYS0CRG resets */
> > +#define JHB100_SYS0RST_RESOURCE_ARB 0
>
> Where are resets 1 and 2, ...
>
> > +#define JHB100_SYS0RST_SYS0_IOMUX_PRESETN 3
> > +#define JHB100_SYS0RST_SYS0H_IOMUX_PRESETN 4
> > +#define JHB100_SYS0RST_RST_ADAPTOR_TIMEOUT_RSTN
> 5
>
> ... where are 6-13?
>
> > +
> > +#define JHB100_SYS0RST_BMCPCIERP_RSTN_BUS 14
> [...]
>
> If there are non-reset bits in these registers, please enumerate reset controls
> in a contiguous range for this binding and add a mapping table in the driver.
>
I will do this.
Best Regards,
Changhuang
^ permalink raw reply
* Re: [PATCH] net: altera-tse: fix skb leak on DMA mapping error in tse_start_xmit()
From: patchwork-bot+netdevbpf @ 2026-04-03 1:30 UTC (permalink / raw)
To: David Carlier
Cc: boon.khai.ng, andrew+netdev, edumazet, kuba, pabeni,
vbridgers2013, netdev, stable
In-Reply-To: <20260401211218.279185-1-devnexen@gmail.com>
Hello:
This patch was applied to netdev/net.git (main)
by Jakub Kicinski <kuba@kernel.org>:
On Wed, 1 Apr 2026 22:12:18 +0100 you wrote:
> When dma_map_single() fails in tse_start_xmit(), the function returns
> NETDEV_TX_OK without freeing the skb. Since NETDEV_TX_OK tells the
> stack the packet was consumed, the skb is never freed, leaking memory
> on every DMA mapping failure.
>
> Add dev_kfree_skb_any() before returning to properly free the skb.
>
> [...]
Here is the summary with links:
- net: altera-tse: fix skb leak on DMA mapping error in tse_start_xmit()
https://git.kernel.org/netdev/net/c/6dede3967619
You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
^ permalink raw reply
* Re: [net-next v36] mctp pcc: Implement MCTP over PCC Transport
From: Jeremy Kerr @ 2026-04-03 1:30 UTC (permalink / raw)
To: Adam Young, Adam Young, Matt Johnston, Andrew Lunn,
David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni
Cc: netdev, linux-kernel, Sudeep Holla, Jonathan Cameron, Huisong Li
In-Reply-To: <0eb9a307-78fb-4a4c-9e63-fb53295b6f4b@amperemail.onmicrosoft.com>
Hi Adam,
> > On the latter, could you expand on what happens on close? Does the PCC
> > channel end up calling tx_done() on each pending TX during the channel
> > free? I'm not familiar with the PCC paths, but it doesn't look like it
> > (or the mailbox core) has a case to deal with this on free.
> >
> > Maybe I am missing something, but could this leak skbs?
>
> Yes, it could, but since they are held by another subsystem, and there
> is no way to access them, it is safer to leak than to free. The Ring
> Buffer in the Mailbox layer is not accessable from the MCTP Client.
> Additionally, there is no way to force a flush of ring buffer.
Sure, but it looks like the messages are essentially lost on
free; a re-bind will clear the mailbox channel's msg buf.
Without a mechanism to purge the message queue on free, it looks like
the only leak-less way to handle this is to keep track of the pending
skbs manually.
> There is a potential for this kind of leak even if we were to transfer
> the data out of SKB: the two options are to either leave it in the ring
> buffer or risk a use-after-free event.
Neither of those are good.
Where is the use-after-free here? Once the pcc_mbox_free_channel()
returns, the pending message buf seems to be forgotten, and so I can't
see how any pending skb gets referenced.
> Bringing the link back up would immediately send the
> remaining skbs and cause them to be free, so they are not frozen in
> perpetuity with no chance of being sent.
Same here - the mbox message queue looks to be reset on client bind, so
it appears that they wouldn't get sent?
If you do need to track the skbs yourself, that could be fairly simple:
keep a sk_buff_head of pending skbs, remove from the list on tx
completion, and skb_queue_purge on ndo_close.
> Whether the backend could handle this is a different story.
A cancellation callback would be handy, yeah.
Cheers,
Jeremy
^ permalink raw reply
* [PATCH] net/tls: fix use-after-free in -EBUSY error path of tls_do_encryption
From: Muhammad Alifa Ramdhan @ 2026-04-03 1:36 UTC (permalink / raw)
To: netdev
Cc: kuba, sd, davem, edumazet, pabeni, john.fastabend, info,
Muhammad Alifa Ramdhan, stable
The -EBUSY handling in tls_do_encryption(), introduced by commit
859054147318 ("net: tls: handle backlogging of crypto requests"), has
a use-after-free due to double cleanup of encrypt_pending and the
scatterlist entry.
When crypto_aead_encrypt() returns -EBUSY, the request is enqueued to
the cryptd backlog and the async callback tls_encrypt_done() will be
invoked upon completion. That callback unconditionally restores the
scatterlist entry (sge->offset, sge->length) and decrements
ctx->encrypt_pending. However, if tls_encrypt_async_wait() returns an
error, the synchronous error path in tls_do_encryption() performs the
same cleanup again, double-decrementing encrypt_pending and
double-restoring the scatterlist.
The double-decrement corrupts the encrypt_pending sentinel (initialized
to 1), making tls_encrypt_async_wait() permanently skip the wait for
pending async callbacks. A subsequent sendmsg can then free the
tls_rec via bpf_exec_tx_verdict() while a cryptd callback is still
pending, resulting in a use-after-free when the callback fires on the
freed record.
Fix this by skipping the synchronous cleanup when the -EBUSY async
wait returns an error, since the callback has already handled
encrypt_pending and sge restoration.
Fixes: 859054147318 ("net: tls: handle backlogging of crypto requests")
Cc: stable@vger.kernel.org
Signed-off-by: Muhammad Alifa Ramdhan <ramdhan@starlabs.sg>
---
net/tls/tls_sw.c | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/net/tls/tls_sw.c b/net/tls/tls_sw.c
--- a/net/tls/tls_sw.c
+++ b/net/tls/tls_sw.c
@@ -584,6 +584,16 @@ static int tls_do_encryption(struct sock *sk,
if (rc == -EBUSY) {
rc = tls_encrypt_async_wait(ctx);
rc = rc ?: -EINPROGRESS;
+ /*
+ * The async callback tls_encrypt_done() has already
+ * decremented encrypt_pending and restored the sge on
+ * both success and error. Skip the synchronous cleanup
+ * below on error, just remove the record and return.
+ */
+ if (rc != -EINPROGRESS) {
+ list_del(&rec->list);
+ return rc;
+ }
}
if (!rc || rc != -EINPROGRESS) {
atomic_dec(&ctx->encrypt_pending);
--
2.43.0
^ permalink raw reply
* Re: [PATCH net v2] net: stmmac: fix integer underflow in chain mode
From: patchwork-bot+netdevbpf @ 2026-04-03 1:40 UTC (permalink / raw)
To: Tyllis Xu
Cc: netdev, andrew+netdev, davem, edumazet, kuba, pabeni,
peppe.cavallaro, rayagond, stable, linux-kernel, danisjiang,
ychen, LivelyCarpet87
In-Reply-To: <20260401044708.1386919-1-LivelyCarpet87@gmail.com>
Hello:
This patch was applied to netdev/net.git (main)
by Jakub Kicinski <kuba@kernel.org>:
On Tue, 31 Mar 2026 23:47:07 -0500 you wrote:
> The jumbo_frm() chain-mode implementation unconditionally computes
>
> len = nopaged_len - bmax;
>
> where nopaged_len = skb_headlen(skb) (linear bytes only) and bmax is
> BUF_SIZE_8KiB or BUF_SIZE_2KiB. However, the caller stmmac_xmit()
> decides to invoke jumbo_frm() based on skb->len (total length including
> page fragments):
>
> [...]
Here is the summary with links:
- [net,v2] net: stmmac: fix integer underflow in chain mode
https://git.kernel.org/netdev/net/c/51f4e090b9f8
You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
^ permalink raw reply
* [PATCH net v2] net: skb: fix cross-cache free of KFENCE-allocated skb head
From: Jiayuan Chen @ 2026-04-03 1:45 UTC (permalink / raw)
To: netdev
Cc: Jiayuan Chen, Antonius, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Jason Xing,
Kuniyuki Iwashima, Michal Luczaj, Mina Almasry, Eric Biggers,
Toke Høiland-Jørgensen, Alexander Duyck,
Soheil Hassas Yeganeh, linux-kernel, bpf
SKB_SMALL_HEAD_CACHE_SIZE is intentionally set to a non-power-of-2
value (e.g. 704 on x86_64) to avoid collisions with generic kmalloc
bucket sizes. This ensures that skb_kfree_head() can reliably use
skb_end_offset to distinguish skb heads allocated from
skb_small_head_cache vs. generic kmalloc caches.
However, when KFENCE is enabled, kfence_ksize() returns the exact
requested allocation size instead of the slab bucket size. If a caller
(e.g. bpf_test_init) allocates skb head data via kzalloc() and the
requested size happens to equal SKB_SMALL_HEAD_CACHE_SIZE, then
slab_build_skb() -> ksize() returns that exact value. After subtracting
skb_shared_info overhead, skb_end_offset ends up matching
SKB_SMALL_HEAD_HEADROOM, causing skb_kfree_head() to incorrectly free
the object to skb_small_head_cache instead of back to the original
kmalloc cache, resulting in a slab cross-cache free:
kmem_cache_free(skbuff_small_head): Wrong slab cache. Expected
skbuff_small_head but got kmalloc-1k
Fix this by always calling kfree(head) in skb_kfree_head(). This keeps
the free path generic and avoids allocator-specific misclassification
for KFENCE objects.
Fixes: bf9f1baa279f ("net: add dedicated kmem_cache for typical/small skb->head")
Reported-by: Antonius <antonius@bluedragonsec.com>
Closes: https://lore.kernel.org/netdev/CAK8a0jxC5L5N7hq-DT2_NhUyjBxrPocoiDazzsBk4TGgT1r4-A@mail.gmail.com/
Signed-off-by: Jiayuan Chen <jiayuan.chen@linux.dev>
---
v1->v2: https://lore.kernel.org/netdev/20260402033138.388574-1-jiayuan.chen@linux.dev/
- switch skb_kfree_head() to plain kfree(head)
---
net/core/skbuff.c | 5 +----
1 file changed, 1 insertion(+), 4 deletions(-)
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 0e217041958a..43ee86dcf2ea 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -1083,10 +1083,7 @@ static int skb_pp_frag_ref(struct sk_buff *skb)
static void skb_kfree_head(void *head, unsigned int end_offset)
{
- if (end_offset == SKB_SMALL_HEAD_HEADROOM)
- kmem_cache_free(net_hotdata.skb_small_head_cache, head);
- else
- kfree(head);
+ kfree(head);
}
static void skb_free_head(struct sk_buff *skb)
--
2.43.0
^ permalink raw reply related
* [PATCH bpf v6 0/2] bpf: tcp: Fix null-ptr-deref in arbitrary SYN Cookie
From: Jiayuan Chen @ 2026-04-03 1:58 UTC (permalink / raw)
To: bpf
Cc: Jiayuan Chen, Martin KaFai Lau, Daniel Borkmann, John Fastabend,
Stanislav Fomichev, Alexei Starovoitov, Andrii Nakryiko,
Eduard Zingerman, Kumar Kartikeya Dwivedi, Song Liu,
Yonghong Song, Jiri Olsa, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Shuah Khan,
Jiayuan Chen, Kuniyuki Iwashima, netdev, linux-kernel,
linux-kselftest
From: Jiayuan Chen <jiayuan.chen@shopee.com>
bpf_sk_assign_tcp_reqsk() does not validate the L4 protocol of the skb,
only checking skb->protocol (L3). A BPF program that calls this kfunc on
a non-TCP skb (e.g. UDP) will succeed, attaching a TCP reqsk to the skb.
When the skb enters the UDP receive path, skb_steal_sock() returns the
TCP listener socket from the reqsk. The UDP code then casts this TCP
socket to udp_sock and accesses UDP-specific fields at invalid offsets,
causing a null pointer dereference:
BUG: KASAN: null-ptr-deref in __udp_enqueue_schedule_skb+0x19d/0x1df0
Read of size 4 at addr 0000000000000008 by task test_progs/537
CPU: 1 UID: 0 PID: 537 Comm: test_progs Not tainted 7.0.0-rc4+ #46 PREEMPT
Call Trace:
<IRQ>
dump_stack_lvl (lib/dump_stack.c:123)
print_report (mm/kasan/report.c:487)
kasan_report (mm/kasan/report.c:597)
__kasan_check_read (mm/kasan/shadow.c:32)
__udp_enqueue_schedule_skb (net/ipv4/udp.c:1719)
udp_queue_rcv_one_skb (net/ipv4/udp.c:2370 net/ipv4/udp.c:2500)
udp_queue_rcv_skb (net/ipv4/udp.c:2532)
udp_unicast_rcv_skb (net/ipv4/udp.c:2684)
__udp4_lib_rcv (net/ipv4/udp.c:2742)
udp_rcv (net/ipv4/udp.c:2937)
ip_protocol_deliver_rcu (net/ipv4/ip_input.c:209)
ip_local_deliver_finish (./include/linux/rcupdate.h:879 net/ipv4/ip_input.c:242)
ip_local_deliver (net/ipv4/ip_input.c:265)
__netif_receive_skb_one_core (net/core/dev.c:6164 (discriminator 4))
__netif_receive_skb (net/core/dev.c:6280)
Solution
Patch 1: Add L4 protocol validation in bpf_sk_assign_tcp_reqsk(). Check
ip_hdr(skb)->protocol (IPv4) and ipv6_hdr(skb)->nexthdr (IPv6) against
IPPROTO_TCP, returning -EINVAL for non-TCP skbs.
Patch 2: Add selftest that calls bpf_sk_assign_tcp_reqsk() on a UDP skb
and verifies the kfunc rejects it.
---
v1: https://lore.kernel.org/bpf/20260323105510.51990-1-jiayuan.chen@linux.dev/
v2: https://lore.kernel.org/bpf/20260326062657.88446-1-jiayuan.chen@linux.dev/
v3: https://lore.kernel.org/bpf/20260327133915.286037-1-jiayuan.chen@linux.dev/
v4: https://lore.kernel.org/bpf/20260330080746.319680-1-jiayuan.chen@linux.dev/
v5: https://lore.kernel.org/bpf/20260401110511.73355-1-jiayuan.chen@linux.dev/
Changes in v5:
- use skb_header_pointer instead of pskb_may_pull.
Changes in v5:
- Add pskb_may_pull before accessing IP/IPv6 headers in kfunc
- Use buf[] instead of buf[32], verify recv data with ASSERT_STREQ
- Remove unnecessary variable initializations in selftest and BPF
Changes in v4:
- Check if assign_ret is EINVAL instead of checking if it is 0
Changes in v3:
- Add IPv6 test coverage, reuse test_cases[] to iterate over both
address families
- Share TCP/UDP port to simplify BPF program, remove unnecessary
global variables
- Use connect_to_fd() + send()/recv() instead of manual sockaddr
construction
- Suggested by Kuniyuki Iwashima
Changes in v2:
- Add Reviewed-by tag from Kuniyuki Iwashima for patch 1
- Use UDP socket recv() instead of kern_sync_rcu() for synchronization
in selftest
Jiayuan Chen (2):
bpf: tcp: Reject non-TCP skb in bpf_sk_assign_tcp_reqsk()
selftests/bpf: Add protocol check test for bpf_sk_assign_tcp_reqsk()
net/core/filter.c | 20 +++-
.../bpf/prog_tests/tcp_custom_syncookie.c | 93 ++++++++++++++-
.../bpf/progs/test_tcp_custom_syncookie.c | 109 ++++++++++++++++++
3 files changed, 216 insertions(+), 6 deletions(-)
--
2.43.0
^ permalink raw reply
* [PATCH bpf v6 1/2] bpf: tcp: Reject non-TCP skb in bpf_sk_assign_tcp_reqsk()
From: Jiayuan Chen @ 2026-04-03 1:58 UTC (permalink / raw)
To: bpf
Cc: Jiayuan Chen, Kuniyuki Iwashima, Alexei Starovoitov,
Daniel Borkmann, Andrii Nakryiko, Martin KaFai Lau,
Eduard Zingerman, Kumar Kartikeya Dwivedi, Song Liu,
Yonghong Song, Jiri Olsa, John Fastabend, Stanislav Fomichev,
David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, Shuah Khan, netdev, linux-kernel, linux-kselftest
In-Reply-To: <20260403015851.148209-1-jiayuan.chen@linux.dev>
bpf_sk_assign_tcp_reqsk() only validates skb->protocol (L3) but does not
check the L4 protocol in the IP header. A BPF program can call this kfunc
on a UDP skb with a valid TCP listener socket, which will succeed and
attach a TCP reqsk to the UDP skb.
When the UDP skb enters the UDP receive path, skb_steal_sock() returns
the TCP listener from the reqsk. The UDP code then passes this TCP socket
to udp_unicast_rcv_skb() -> __udp_enqueue_schedule_skb(), which casts
it to udp_sock and accesses UDP-specific fields at invalid offsets,
causing a null pointer dereference and kernel panic:
BUG: KASAN: null-ptr-deref in __udp_enqueue_schedule_skb+0x19d/0x1df0
Read of size 4 at addr 0000000000000008 by task test_progs/537
CPU: 1 UID: 0 PID: 537 Comm: test_progs Not tainted 7.0.0-rc4+ #46 PREEMPT
Call Trace:
<IRQ>
dump_stack_lvl (lib/dump_stack.c:123)
print_report (mm/kasan/report.c:487)
kasan_report (mm/kasan/report.c:597)
__kasan_check_read (mm/kasan/shadow.c:32)
__udp_enqueue_schedule_skb (net/ipv4/udp.c:1719)
udp_queue_rcv_one_skb (net/ipv4/udp.c:2370 net/ipv4/udp.c:2500)
udp_queue_rcv_skb (net/ipv4/udp.c:2532)
udp_unicast_rcv_skb (net/ipv4/udp.c:2684)
__udp4_lib_rcv (net/ipv4/udp.c:2742)
udp_rcv (net/ipv4/udp.c:2937)
ip_protocol_deliver_rcu (net/ipv4/ip_input.c:209)
ip_local_deliver_finish (./include/linux/rcupdate.h:879 net/ipv4/ip_input.c:242)
ip_local_deliver (net/ipv4/ip_input.c:265)
__netif_receive_skb_one_core (net/core/dev.c:6164 (discriminator 4))
__netif_receive_skb (net/core/dev.c:6280)
Fix this by checking the IP header's protocol field in
bpf_sk_assign_tcp_reqsk() and rejecting non-TCP skbs with -EINVAL.
Note that for IPv6, the nexthdr check does not walk extension headers.
This is uncommon for TCP SYN packets in practice, and keeping it simple
was agreed upon by Kuniyuki Iwashima.
Fixes: e472f88891ab ("bpf: tcp: Support arbitrary SYN Cookie.")
Reviewed-by: Kuniyuki Iwashima <kuniyu@google.com>
Signed-off-by: Jiayuan Chen <jiayuan.chen@linux.dev>
---
net/core/filter.c | 20 ++++++++++++++++++--
1 file changed, 18 insertions(+), 2 deletions(-)
diff --git a/net/core/filter.c b/net/core/filter.c
index 78b548158fb05..523a63584cba0 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -12247,15 +12247,31 @@ __bpf_kfunc int bpf_sk_assign_tcp_reqsk(struct __sk_buff *s, struct sock *sk,
return -ENETUNREACH;
switch (skb->protocol) {
- case htons(ETH_P_IP):
+ case htons(ETH_P_IP): {
+ struct iphdr *iph, _iph;
+
+ iph = skb_header_pointer(skb, skb_network_offset(skb),
+ sizeof(*iph), &_iph);
+ if (!iph || iph->protocol != IPPROTO_TCP)
+ return -EINVAL;
+
ops = &tcp_request_sock_ops;
min_mss = 536;
break;
+ }
#if IS_BUILTIN(CONFIG_IPV6)
- case htons(ETH_P_IPV6):
+ case htons(ETH_P_IPV6): {
+ struct ipv6hdr *ip6h, _ip6h;
+
+ ip6h = skb_header_pointer(skb, skb_network_offset(skb),
+ sizeof(*ip6h), &_ip6h);
+ if (!ip6h || ip6h->nexthdr != IPPROTO_TCP)
+ return -EINVAL;
+
ops = &tcp6_request_sock_ops;
min_mss = IPV6_MIN_MTU - 60;
break;
+ }
#endif
default:
return -EINVAL;
--
2.43.0
^ permalink raw reply related
* [PATCH bpf v6 2/2] selftests/bpf: Add protocol check test for bpf_sk_assign_tcp_reqsk()
From: Jiayuan Chen @ 2026-04-03 1:58 UTC (permalink / raw)
To: bpf
Cc: Jiayuan Chen, Martin KaFai Lau, Daniel Borkmann, John Fastabend,
Stanislav Fomichev, Alexei Starovoitov, Andrii Nakryiko,
Eduard Zingerman, Kumar Kartikeya Dwivedi, Song Liu,
Yonghong Song, Jiri Olsa, David S. Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Simon Horman, Shuah Khan,
Kuniyuki Iwashima, netdev, linux-kernel, linux-kselftest
In-Reply-To: <20260403015851.148209-1-jiayuan.chen@linux.dev>
Add test_tcp_custom_syncookie_protocol_check to verify that
bpf_sk_assign_tcp_reqsk() rejects non-TCP skbs. The test sends a UDP
packet through TC ingress where a BPF program calls
bpf_sk_assign_tcp_reqsk() on it and checks that the kfunc returns an
error. A UDP server recv() is used as synchronization to ensure the
BPF program has finished processing before checking the result.
Without the fix in bpf_sk_assign_tcp_reqsk(), the kfunc succeeds and
attaches a TCP reqsk to the UDP skb, which causes a null pointer
dereference panic when the kernel processes it through the UDP receive
path.
Test result:
./test_progs -a tcp_custom_syncookie_protocol_check -v
setup_netns:PASS:create netns 0 nsec
setup_netns:PASS:ip 0 nsec
write_sysctl:PASS:open sysctl 0 nsec
write_sysctl:PASS:write sysctl 0 nsec
setup_netns:PASS:write_sysctl 0 nsec
test_tcp_custom_syncookie_protocol_check:PASS:open_and_load 0 nsec
setup_tc:PASS:qdisc add dev lo clsact 0 nsec
setup_tc:PASS:filter add dev lo ingress 0 nsec
run_protocol_check:PASS:start tcp_server 0 nsec
run_protocol_check:PASS:start udp_server 0 nsec
run_protocol_check:PASS:connect udp_client 0 nsec
run_protocol_check:PASS:send udp 0 nsec
run_protocol_check:PASS:recv udp 0 nsec
run_protocol_check:PASS:recv data 0 nsec
run_protocol_check:PASS:udp_intercepted 0 nsec
run_protocol_check:PASS:assign_ret 0 nsec
#471/1 tcp_custom_syncookie_protocol_check/IPv4 TCP:OK
run_protocol_check:PASS:start tcp_server 0 nsec
run_protocol_check:PASS:start udp_server 0 nsec
run_protocol_check:PASS:connect udp_client 0 nsec
run_protocol_check:PASS:send udp 0 nsec
run_protocol_check:PASS:recv udp 0 nsec
run_protocol_check:PASS:recv data 0 nsec
run_protocol_check:PASS:udp_intercepted 0 nsec
run_protocol_check:PASS:assign_ret 0 nsec
#471/2 tcp_custom_syncookie_protocol_check/IPv6 TCP:OK
#471 tcp_custom_syncookie_protocol_check:OK
Summary: 1/2 PASSED, 0 SKIPPED, 0 FAILED
Signed-off-by: Jiayuan Chen <jiayuan.chen@linux.dev>
---
.../bpf/prog_tests/tcp_custom_syncookie.c | 93 ++++++++++++++-
.../bpf/progs/test_tcp_custom_syncookie.c | 109 ++++++++++++++++++
2 files changed, 198 insertions(+), 4 deletions(-)
diff --git a/tools/testing/selftests/bpf/prog_tests/tcp_custom_syncookie.c b/tools/testing/selftests/bpf/prog_tests/tcp_custom_syncookie.c
index eaf441dc7e79b..017836581669f 100644
--- a/tools/testing/selftests/bpf/prog_tests/tcp_custom_syncookie.c
+++ b/tools/testing/selftests/bpf/prog_tests/tcp_custom_syncookie.c
@@ -5,6 +5,7 @@
#include <sched.h>
#include <stdlib.h>
#include <net/if.h>
+#include <netinet/in.h>
#include "test_progs.h"
#include "cgroup_helpers.h"
@@ -47,11 +48,10 @@ static int setup_netns(void)
return -1;
}
-static int setup_tc(struct test_tcp_custom_syncookie *skel)
+static int setup_tc(int prog_fd)
{
LIBBPF_OPTS(bpf_tc_hook, qdisc_lo, .attach_point = BPF_TC_INGRESS);
- LIBBPF_OPTS(bpf_tc_opts, tc_attach,
- .prog_fd = bpf_program__fd(skel->progs.tcp_custom_syncookie));
+ LIBBPF_OPTS(bpf_tc_opts, tc_attach, .prog_fd = prog_fd);
qdisc_lo.ifindex = if_nametoindex("lo");
if (!ASSERT_OK(bpf_tc_hook_create(&qdisc_lo), "qdisc add dev lo clsact"))
@@ -127,7 +127,7 @@ void test_tcp_custom_syncookie(void)
if (!ASSERT_OK_PTR(skel, "open_and_load"))
return;
- if (setup_tc(skel))
+ if (setup_tc(bpf_program__fd(skel->progs.tcp_custom_syncookie)))
goto destroy_skel;
for (i = 0; i < ARRAY_SIZE(test_cases); i++) {
@@ -145,6 +145,91 @@ void test_tcp_custom_syncookie(void)
destroy_skel:
system("tc qdisc del dev lo clsact");
+ test_tcp_custom_syncookie__destroy(skel);
+}
+
+/* Test: bpf_sk_assign_tcp_reqsk() should reject non-TCP skb.
+ *
+ * Send a UDP packet through TC ingress where a BPF program calls
+ * bpf_sk_assign_tcp_reqsk() on it. The kfunc should return an error
+ * because the skb carries UDP, not TCP.
+ *
+ * TCP and UDP servers share the same port. The BPF program intercepts
+ * the UDP packet, looks up the TCP listener via the dest port, and
+ * attempts to assign a TCP reqsk to the UDP skb.
+ */
+static void run_protocol_check(struct test_tcp_custom_syncookie *skel,
+ int family, const char *addr)
+{
+ int tcp_server, udp_server, udp_client;
+ char buf[] = "test";
+ int port, ret;
+
+ tcp_server = start_server(family, SOCK_STREAM, addr, 0, 0);
+ if (!ASSERT_NEQ(tcp_server, -1, "start tcp_server"))
+ return;
+
+ port = ntohs(get_socket_local_port(tcp_server));
+
+ /* UDP server on same port for synchronization and port sharing */
+ udp_server = start_server(family, SOCK_DGRAM, addr, port, 0);
+ if (!ASSERT_NEQ(udp_server, -1, "start udp_server"))
+ goto close_tcp;
+
+ skel->bss->udp_intercepted = false;
+ skel->bss->assign_ret = 0;
+
+ udp_client = connect_to_fd(udp_server, 0);
+ if (!ASSERT_NEQ(udp_client, -1, "connect udp_client"))
+ goto close_udp_server;
+
+ ret = send(udp_client, buf, sizeof(buf), 0);
+ if (!ASSERT_EQ(ret, sizeof(buf), "send udp"))
+ goto close_udp_client;
+
+ memset(buf, 0, sizeof(buf));
+
+ /* recv() ensures TC ingress BPF has processed the skb */
+ ret = recv(udp_server, buf, sizeof(buf), 0);
+ if (!ASSERT_EQ(ret, sizeof(buf), "recv udp"))
+ goto close_udp_client;
+
+ ASSERT_STREQ(buf, "test", "recv data");
+ ASSERT_EQ(skel->bss->udp_intercepted, true, "udp_intercepted");
+ ASSERT_EQ(skel->bss->assign_ret, -EINVAL, "assign_ret");
+
+close_udp_client:
+ close(udp_client);
+close_udp_server:
+ close(udp_server);
+close_tcp:
+ close(tcp_server);
+}
+
+void test_tcp_custom_syncookie_protocol_check(void)
+{
+ struct test_tcp_custom_syncookie *skel;
+ int i;
+
+ if (setup_netns())
+ return;
+
+ skel = test_tcp_custom_syncookie__open_and_load();
+ if (!ASSERT_OK_PTR(skel, "open_and_load"))
+ return;
+
+ if (setup_tc(bpf_program__fd(skel->progs.tcp_custom_syncookie_badproto)))
+ goto destroy_skel;
+
+ for (i = 0; i < ARRAY_SIZE(test_cases); i++) {
+ if (!test__start_subtest(test_cases[i].name))
+ continue;
+ run_protocol_check(skel, test_cases[i].family,
+ test_cases[i].addr);
+ }
+
+destroy_skel:
+ system("tc qdisc del dev lo clsact");
test_tcp_custom_syncookie__destroy(skel);
}
diff --git a/tools/testing/selftests/bpf/progs/test_tcp_custom_syncookie.c b/tools/testing/selftests/bpf/progs/test_tcp_custom_syncookie.c
index 7d5293de19523..7e87773a95adb 100644
--- a/tools/testing/selftests/bpf/progs/test_tcp_custom_syncookie.c
+++ b/tools/testing/selftests/bpf/progs/test_tcp_custom_syncookie.c
@@ -588,4 +588,113 @@ int tcp_custom_syncookie(struct __sk_buff *skb)
return tcp_handle_ack(&ctx);
}
+/* Test: call bpf_sk_assign_tcp_reqsk() on a UDP skb.
+ * The kfunc should reject it because the skb is not TCP.
+ *
+ * TCP and UDP servers share the same port. The BPF program intercepts
+ * UDP packets, looks up the TCP listener on the same port, and tries
+ * to assign a TCP reqsk to the UDP skb.
+ */
+int assign_ret;
+bool udp_intercepted;
+
+static int badproto_lookup_assign(struct __sk_buff *skb,
+ struct bpf_sock_tuple *tuple, u32 tuple_size)
+{
+ struct bpf_tcp_req_attrs attrs = {};
+ struct bpf_sock *skc;
+ struct sock *sk;
+
+ skc = bpf_skc_lookup_tcp(skb, tuple, tuple_size, -1, 0);
+ if (!skc)
+ return TC_ACT_OK;
+
+ if (skc->state != TCP_LISTEN) {
+ bpf_sk_release(skc);
+ return TC_ACT_OK;
+ }
+
+ sk = (struct sock *)bpf_skc_to_tcp_sock(skc);
+ if (!sk) {
+ bpf_sk_release(skc);
+ return TC_ACT_OK;
+ }
+
+ attrs.mss = 1460;
+ attrs.wscale_ok = 1;
+ attrs.snd_wscale = 7;
+ attrs.rcv_wscale = 7;
+ attrs.sack_ok = 1;
+
+ assign_ret = bpf_sk_assign_tcp_reqsk(skb, sk, &attrs, sizeof(attrs));
+
+ bpf_sk_release(skc);
+ return TC_ACT_OK;
+}
+
+SEC("tc")
+int tcp_custom_syncookie_badproto(struct __sk_buff *skb)
+{
+ void *data = (void *)(long)skb->data;
+ void *data_end = (void *)(long)skb->data_end;
+ struct bpf_sock_tuple tuple = {};
+ struct ethhdr *eth;
+ struct iphdr *iph;
+ struct ipv6hdr *ip6h;
+ struct udphdr *udp;
+
+ eth = (struct ethhdr *)data;
+ if (eth + 1 > data_end)
+ return TC_ACT_OK;
+
+ switch (bpf_ntohs(eth->h_proto)) {
+ case ETH_P_IP:
+ iph = (struct iphdr *)(eth + 1);
+ if (iph + 1 > data_end)
+ return TC_ACT_OK;
+
+ if (iph->protocol != IPPROTO_UDP)
+ return TC_ACT_OK;
+
+ udp = (struct udphdr *)(iph + 1);
+ if (udp + 1 > data_end)
+ return TC_ACT_OK;
+
+ udp_intercepted = true;
+
+ tuple.ipv4.saddr = iph->saddr;
+ tuple.ipv4.daddr = iph->daddr;
+ tuple.ipv4.sport = udp->source;
+ tuple.ipv4.dport = udp->dest;
+
+ return badproto_lookup_assign(skb, &tuple,
+ sizeof(tuple.ipv4));
+ case ETH_P_IPV6:
+ ip6h = (struct ipv6hdr *)(eth + 1);
+ if (ip6h + 1 > data_end)
+ return TC_ACT_OK;
+
+ if (ip6h->nexthdr != IPPROTO_UDP)
+ return TC_ACT_OK;
+
+ udp = (struct udphdr *)(ip6h + 1);
+ if (udp + 1 > data_end)
+ return TC_ACT_OK;
+
+ udp_intercepted = true;
+
+ __builtin_memcpy(tuple.ipv6.saddr, &ip6h->saddr,
+ sizeof(tuple.ipv6.saddr));
+ __builtin_memcpy(tuple.ipv6.daddr, &ip6h->daddr,
+ sizeof(tuple.ipv6.daddr));
+ tuple.ipv6.sport = udp->source;
+ tuple.ipv6.dport = udp->dest;
+
+ return badproto_lookup_assign(skb, &tuple,
+ sizeof(tuple.ipv6));
+ default:
+ return TC_ACT_OK;
+ }
+}
+
char _license[] SEC("license") = "GPL";
--
2.43.0
^ permalink raw reply related
* Re: [PATCH net-next V4 10/12] devlink: Add resource scope filtering to resource dump
From: Jakub Kicinski @ 2026-04-03 2:02 UTC (permalink / raw)
To: Tariq Toukan
Cc: Eric Dumazet, Paolo Abeni, Andrew Lunn, David S. Miller,
Simon Horman, Donald Hunter, Jiri Pirko, Jonathan Corbet,
Shuah Khan, Saeed Mahameed, Leon Romanovsky, Mark Bloch,
Shuah Khan, Chuck Lever, Matthieu Baerts (NGI0), Carolina Jubran,
Or Har-Toov, Moshe Shemesh, Dragos Tatulea, Shahar Shitrit,
Daniel Zahka, Jacob Keller, Cosmin Ratiu, Parav Pandit,
Shay Drori, Adithya Jayachandran, Kees Cook, Daniel Jurgens,
netdev, linux-kernel, linux-doc, linux-rdma, linux-kselftest,
Gal Pressman
In-Reply-To: <20260401184947.135205-11-tariqt@nvidia.com>
On Wed, 1 Apr 2026 21:49:45 +0300 Tariq Toukan wrote:
> @@ -873,6 +881,16 @@ attribute-sets:
> doc: Unique devlink instance index.
> checks:
> max: u32-max
> + -
> + name: resource-scope-mask
> + type: bitfield32
no need for a bitfield here, this is a simpler selector
bitfield is for cases when we need to update some persistent
state, in that case we want to indicate which bits we intend
to update:
cfg = (cfg & ~bf.mask) | bf.val
scope is a straight attribute, there's no updating of anything.
u32 or unit would do
> + enum: resource-scope
> + enum-as-flags: true
> + doc: |
> + Bitmask selecting which resource classes to include in a
> + resource-dump response. Bit 0 (dev) selects device-level
> + resources; bit 1 (port) selects port-level resources.
> + When absent all classes are returned.
> -
> name: dl-dev-stats
> subset-of: devlink
> @@ -1775,7 +1793,11 @@ operations:
> - resource-list
> dump:
> request:
> - attributes: *dev-id-attrs
> + attributes:
> + - bus-name
> + - dev-name
> + - index
> + - resource-scope-mask
> reply: *resource-dump-reply
>
> -
> diff --git a/include/uapi/linux/devlink.h b/include/uapi/linux/devlink.h
> index 7de2d8cc862f..e0a0b523ce5c 100644
> --- a/include/uapi/linux/devlink.h
> +++ b/include/uapi/linux/devlink.h
> @@ -645,6 +645,7 @@ enum devlink_attr {
> DEVLINK_ATTR_PARAM_RESET_DEFAULT, /* flag */
>
> DEVLINK_ATTR_INDEX, /* uint */
> + DEVLINK_ATTR_RESOURCE_SCOPE_MASK, /* bitfield32 */
>
> /* Add new attributes above here, update the spec in
> * Documentation/netlink/specs/devlink.yaml and re-generate
> @@ -704,6 +705,22 @@ enum devlink_resource_unit {
> DEVLINK_RESOURCE_UNIT_ENTRY,
> };
>
> +enum devlink_resource_scope {
> + DEVLINK_RESOURCE_SCOPE_DEV_BIT,
> + DEVLINK_RESOURCE_SCOPE_PORT_BIT,
> +
> + __DEVLINK_RESOURCE_SCOPE_MAX_BIT,
> + DEVLINK_RESOURCE_SCOPE_MAX_BIT =
do we need this? it's not an attr enum all we care about here is
the mask, really so just a trailing value which is max real value + 1
is enough for all users?
> + __DEVLINK_RESOURCE_SCOPE_MAX_BIT - 1
> +};
> +
> +#define DEVLINK_RESOURCE_SCOPE_DEV \
> + _BITUL(DEVLINK_RESOURCE_SCOPE_DEV_BIT)
> +#define DEVLINK_RESOURCE_SCOPE_PORT \
> + _BITUL(DEVLINK_RESOURCE_SCOPE_PORT_BIT)
> +#define DEVLINK_RESOURCE_SCOPE_VALID_MASK \
> + (_BITUL(__DEVLINK_RESOURCE_SCOPE_MAX_BIT) - 1)
> +
> enum devlink_port_fn_attr_cap {
> DEVLINK_PORT_FN_ATTR_CAP_ROCE_BIT,
> DEVLINK_PORT_FN_ATTR_CAP_MIGRATABLE_BIT,
> +static u32 devlink_resource_scope_get(struct nlattr **attrs, int *flags)
> +{
> + struct nla_bitfield32 scope;
> + u32 value;
> +
> + if (!attrs || !attrs[DEVLINK_ATTR_RESOURCE_SCOPE_MASK])
> + return DEVLINK_RESOURCE_SCOPE_VALID_MASK;
> +
> + scope = nla_get_bitfield32(attrs[DEVLINK_ATTR_RESOURCE_SCOPE_MASK]);
> + value = scope.value & scope.selector;
> + if (value != DEVLINK_RESOURCE_SCOPE_VALID_MASK)
> + *flags |= NLM_F_DUMP_FILTERED;
> +
> + return value;
> +}
> +
> static int
> devlink_resource_dump_fill_one(struct sk_buff *skb, struct devlink *devlink,
> struct devlink_port *devlink_port,
> @@ -400,16 +416,27 @@ devlink_nl_resource_dump_one(struct sk_buff *skb, struct devlink *devlink,
> struct devlink_nl_dump_state *state = devlink_dump_state(cb);
> struct devlink_port *devlink_port;
> unsigned long port_idx;
> + u32 scope;
> int err;
>
> - if (!state->port_number) {
> + scope = devlink_resource_scope_get(genl_info_dump(cb)->attrs, &flags);
> + if (!scope) {
> + NL_SET_ERR_MSG_ATTR(genl_info_dump(cb)->extack,
> + genl_info_dump(cb)->attrs[DEVLINK_ATTR_RESOURCE_SCOPE_MASK],
we have genl_info_dump(cb) 3 times here, let's save the pointer
on the stack to make the lines shorter.
> + "empty resource scope selection");
> + return -EINVAL;
> + }
> + if (!state->port_number && (scope & DEVLINK_RESOURCE_SCOPE_DEV)) {
> err = devlink_resource_dump_fill_one(skb, devlink, NULL,
> - cb, flags, &state->idx);
> + cb, flags,
> + &state->idx);
> if (err)
> return err;
> state->idx = 0;
> }
>
> + if (!(scope & DEVLINK_RESOURCE_SCOPE_PORT))
> + goto out;
> xa_for_each_start(&devlink->ports, port_idx, devlink_port,
> state->port_number ? state->port_number - 1 : 0) {
> err = devlink_resource_dump_fill_one(skb, devlink, devlink_port,
> @@ -420,6 +447,7 @@ devlink_nl_resource_dump_one(struct sk_buff *skb, struct devlink *devlink,
> }
> state->idx = 0;
> }
> +out:
> state->port_number = 0;
> return 0;
> }
^ permalink raw reply
* Re: [PATCH v9 net-next 6/6] octeontx2-af: npc: Support for custom KPU profile from filesystem
From: Ratheesh Kannoth @ 2026-04-03 2:05 UTC (permalink / raw)
To: Paolo Abeni
Cc: netdev, linux-kernel, linux-rdma, sgoutham, andrew+netdev, davem,
edumazet, kuba, donald.hunter, horms, jiri, chuck.lever, matttbe,
cjubran, saeedm, leon, tariqt, mbloch, dtatulea
In-Reply-To: <ac20d8bc-4af5-4338-adc3-01e4aac4e70e@redhat.com>
On 2026-04-02 at 14:24:42, Paolo Abeni (pabeni@redhat.com) wrote:
> On 3/30/26 7:31 AM, Ratheesh Kannoth wrote:
> Also there are several remarks for sashiko, some of them looks valid:
>
> https://sashiko.dev/#/patchset/20260330053105.2722453-1-rkannoth%40marvell.com
>
> please a look.
> +static u64 dstats[MAX_NUM_BANKS][MAX_SUBBANK_DEPTH * MAX_NUM_SUB_BANKS] = {};
> +static int npc_mcam_dstats_show(struct seq_file *s, void *unused)
> +{
[ ... ]
> + stats = rvu_read64(rvu, blkaddr,
> + NPC_AF_CN20K_MCAMEX_BANKX_STAT_EXT(idx, bank));
> + if (!stats)
> + continue;
> + if (stats == dstats[bank][idx])
> + continue;
[ ... ]
> + seq_printf(s, "%u\t%#04x\t%llu\n",
> + mcam_idx, pf, delta);
> + dstats[bank][idx] = stats;
> + }
> + }
> + return 0;
> +}
> +DEFINE_SHOW_ATTRIBUTE(npc_mcam_dstats);
"Can this cause truncated output if the printed data exceeds the initial
seq_file buffer?
When seq_read() encounters a buffer overflow (typically at 4KB), it
discards the buffer, allocates a larger one, and re-invokes the show
callback from the beginning. Since the global dstats array is updated
during the first partial run, won't the retry skip those previously
processed entries due to the "stats == dstats[bank][idx]" check?
Also, since the dstats array is modified here without any locks, will
concurrent reads of this debugfs file race and corrupt the statistics?"
dtsats is for debugging. Evenif the first time it fails, second time it will
show the correct stats as live traffic will update stats.
> free_rules:
> + blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPC, 0);
> + if (blkaddr < 0)
> + return;
>
> - free_req.hdr.pcifunc = pcifunc;
> - free_req.all = 1;
> - rc = rvu_mbox_handler_npc_mcam_free_entry(rvu, &free_req, &rsp);
> - if (rc)
> - dev_err(rvu->dev,
> - "%s: Error deleting default entries (pcifunc=%#x\n",
> - __func__, pcifunc);
> + for (int i = 0; i < 4; i++) {
> + if (ptr[i] == USHRT_MAX)
> + continue;
> +
> + mutex_lock(&mcam->lock);
> + npc_mcam_clear_bit(mcam, ptr[i]);
"Could this lead to a double-free corrupting the free-count metadata?
If a VF or DPDK application manually frees a default MCAM entry prior to
teardown using the NPC_MCAM_FREE_ENTRY mailbox message, the bit is cleared.
When NIX LF teardown runs here, it calls npc_mcam_clear_bit() again. Because
npc_mcam_clear_bit() unconditionally increments mcam->bmap_fcnt++, doing so
twice on the same index corrupts the free-count metadata."
default entries are alloated and freed by kernel.
>
> Thanks,
>
> Paolo
>
^ permalink raw reply
* [PATCH 1/1] rxrpc: only handle RESPONSE during service challenge
From: Yang Yang @ 2026-04-03 2:17 UTC (permalink / raw)
To: netdev
Cc: dhowells, marc.dionne, davem, edumazet, kuba, pabeni, horms,
yifanwucs, tomapufckgml, yuantan098, bird, jiewang2024, n05ec
In-Reply-To: <20260403021351.530453-1-n05ec@lzu.edu.cn>
From: Wang Jie <jiewang2024@lzu.edu.cn>
Only process RESPONSE packets while the service connection is still in
RXRPC_CONN_SERVICE_CHALLENGING. Check that state under state_lock before
running response verification and security initialization, then use a local
secured flag to decide whether to queue the secured-connection work after
the state transition. This keeps duplicate or late RESPONSE packets from
re-running the setup path and removes the unlocked post-transition state
test.
Fixes: 17926a79320a ("net: AF_RXRPC: Provide secure RxRPC sockets for use by userspace and kernel both")
Reported-by: Yifan Wu <yifanwucs@gmail.com>
Reported-by: Juefei Pu <tomapufckgml@gmail.com>
Co-developed-by: Yuan Tan <yuantan098@gmail.com>
Signed-off-by: Yuan Tan <yuantan098@gmail.com>
Suggested-by: Xin Liu <bird@lzu.edu.cn>
Signed-off-by: Jie Wang <jiewang2024@lzu.edu.cn>
Signed-off-by: Yang Yang <n05ec@lzu.edu.cn>
---
net/rxrpc/conn_event.c | 14 ++++++++++++--
1 file changed, 12 insertions(+), 2 deletions(-)
diff --git a/net/rxrpc/conn_event.c b/net/rxrpc/conn_event.c
index 98ad9b51ca2c..74823f70b57a 100644
--- a/net/rxrpc/conn_event.c
+++ b/net/rxrpc/conn_event.c
@@ -247,6 +247,7 @@ static int rxrpc_process_event(struct rxrpc_connection *conn,
struct sk_buff *skb)
{
struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
+ bool secured = false;
int ret;
if (conn->state == RXRPC_CONN_ABORTED)
@@ -262,6 +263,13 @@ static int rxrpc_process_event(struct rxrpc_connection *conn,
return ret;
case RXRPC_PACKET_TYPE_RESPONSE:
+ spin_lock_irq(&conn->state_lock);
+ if (conn->state != RXRPC_CONN_SERVICE_CHALLENGING) {
+ spin_unlock_irq(&conn->state_lock);
+ return 0;
+ }
+ spin_unlock_irq(&conn->state_lock);
+
ret = conn->security->verify_response(conn, skb);
if (ret < 0)
return ret;
@@ -272,11 +280,13 @@ static int rxrpc_process_event(struct rxrpc_connection *conn,
return ret;
spin_lock_irq(&conn->state_lock);
- if (conn->state == RXRPC_CONN_SERVICE_CHALLENGING)
+ if (conn->state == RXRPC_CONN_SERVICE_CHALLENGING) {
conn->state = RXRPC_CONN_SERVICE;
+ secured = true;
+ }
spin_unlock_irq(&conn->state_lock);
- if (conn->state == RXRPC_CONN_SERVICE) {
+ if (secured) {
/* Offload call state flipping to the I/O thread. As
* we've already received the packet, put it on the
* front of the queue.
--
2.43.0
^ permalink raw reply related
* [PATCH net-next] net: mctp: tests: use actual address when creating dev with addr
From: Jeremy Kerr @ 2026-04-03 2:21 UTC (permalink / raw)
To: Matt Johnston, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Simon Horman
Cc: netdev
Sashiko reports:
> This isn't a bug in the core networking code, but the addr parameter
> appears to be ignored here.
In mctp_test_create_dev_with_addr(), we are ignoring the addr argument
and just using `8`. Use the passed address instead.
All invocations use 8 anyway, so no effective change at present.
Fixes: 22cb45afd221 ("net: mctp: perform source address lookups when we populate our dst")
Signed-off-by: Jeremy Kerr <jk@codeconstruct.com.au>
---
net/mctp/test/utils.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/net/mctp/test/utils.c b/net/mctp/test/utils.c
index 2f79f8c1a2b4..c3987d5ade7a 100644
--- a/net/mctp/test/utils.c
+++ b/net/mctp/test/utils.c
@@ -95,7 +95,7 @@ struct mctp_test_dev *mctp_test_create_dev_with_addr(mctp_eid_t addr)
}
dev->mdev->num_addrs = 1;
- dev->mdev->addrs[0] = 8;
+ dev->mdev->addrs[0] = addr;
return dev;
}
---
base-commit: 8b0e64d6c9e7feec5ba5643b4fa8b7fd54464778
change-id: 20260403-dev-mctp-fix-test-addr-4ee89cf80edc
Best regards,
--
Jeremy Kerr <jk@codeconstruct.com.au>
^ permalink raw reply related
* Re: [PATCH net v2] net: skb: fix cross-cache free of KFENCE-allocated skb head
From: Eric Dumazet @ 2026-04-03 2:23 UTC (permalink / raw)
To: Jiayuan Chen
Cc: netdev, Antonius, David S. Miller, Jakub Kicinski, Paolo Abeni,
Simon Horman, Jason Xing, Kuniyuki Iwashima, Michal Luczaj,
Mina Almasry, Eric Biggers, Toke Høiland-Jørgensen,
Alexander Duyck, Soheil Hassas Yeganeh, linux-kernel, bpf
In-Reply-To: <20260403014517.142550-1-jiayuan.chen@linux.dev>
On Thu, Apr 2, 2026 at 6:45 PM Jiayuan Chen <jiayuan.chen@linux.dev> wrote:
>
> SKB_SMALL_HEAD_CACHE_SIZE is intentionally set to a non-power-of-2
> value (e.g. 704 on x86_64) to avoid collisions with generic kmalloc
> bucket sizes. This ensures that skb_kfree_head() can reliably use
> skb_end_offset to distinguish skb heads allocated from
> skb_small_head_cache vs. generic kmalloc caches.
>
> However, when KFENCE is enabled, kfence_ksize() returns the exact
> requested allocation size instead of the slab bucket size. If a caller
> (e.g. bpf_test_init) allocates skb head data via kzalloc() and the
> requested size happens to equal SKB_SMALL_HEAD_CACHE_SIZE, then
> slab_build_skb() -> ksize() returns that exact value. After subtracting
> skb_shared_info overhead, skb_end_offset ends up matching
> SKB_SMALL_HEAD_HEADROOM, causing skb_kfree_head() to incorrectly free
> the object to skb_small_head_cache instead of back to the original
> kmalloc cache, resulting in a slab cross-cache free:
>
> kmem_cache_free(skbuff_small_head): Wrong slab cache. Expected
> skbuff_small_head but got kmalloc-1k
>
> Fix this by always calling kfree(head) in skb_kfree_head(). This keeps
> the free path generic and avoids allocator-specific misclassification
> for KFENCE objects.
>
> Fixes: bf9f1baa279f ("net: add dedicated kmem_cache for typical/small skb->head")
> Reported-by: Antonius <antonius@bluedragonsec.com>
> Closes: https://lore.kernel.org/netdev/CAK8a0jxC5L5N7hq-DT2_NhUyjBxrPocoiDazzsBk4TGgT1r4-A@mail.gmail.com/
> Signed-off-by: Jiayuan Chen <jiayuan.chen@linux.dev>
Reviewed-by: Eric Dumazet <edumazet@google.com>
^ permalink raw reply
* [PATCH net-next] net: dropreason: add SKB_DROP_REASON_{BROAD,MULTI}CAST_BACKLOG
From: Eric Dumazet @ 2026-04-03 2:24 UTC (permalink / raw)
To: David S . Miller, Jakub Kicinski, Paolo Abeni
Cc: Simon Horman, Kuniyuki Iwashima, Andrew Lunn, netdev,
eric.dumazet, Eric Dumazet
ipvlan and macvlan use queues to process broadcast or multicast packets
from a work queue.
Under attack these queues can drop packets.
Add BROADCAST_BACKLOG drop_reason for macvlan broadcast queue.
Add MULTICAST_BACKLOG drop_reason for ipvlan multicast queue.
Also change ipvlan_rcv_frame() to use SKB_DROP_REASON_DEV_READY
when the device is not UP.
Signed-off-by: Eric Dumazet <edumazet@google.com>
---
drivers/net/ipvlan/ipvlan_core.c | 4 ++--
drivers/net/macvlan.c | 2 +-
include/net/dropreason-core.h | 12 ++++++++++++
3 files changed, 15 insertions(+), 3 deletions(-)
diff --git a/drivers/net/ipvlan/ipvlan_core.c b/drivers/net/ipvlan/ipvlan_core.c
index 68fdb42068d0060c67d751b869a059e8cb1b6bd1..162e08200012ef272d9b1aee09ab54e724c9bc71 100644
--- a/drivers/net/ipvlan/ipvlan_core.c
+++ b/drivers/net/ipvlan/ipvlan_core.c
@@ -337,7 +337,7 @@ static int ipvlan_rcv_frame(struct ipvl_addr *addr, struct sk_buff **pskb,
*/
if (local) {
if (unlikely(!(dev->flags & IFF_UP))) {
- kfree_skb(skb);
+ kfree_skb_reason(skb, SKB_DROP_REASON_DEV_READY);
goto out;
}
@@ -596,7 +596,7 @@ static void ipvlan_multicast_enqueue(struct ipvl_port *port,
} else {
spin_unlock(&port->backlog.lock);
dev_core_stats_rx_dropped_inc(skb->dev);
- kfree_skb(skb);
+ kfree_skb_reason(skb, SKB_DROP_REASON_MULTICAST_BACKLOG);
}
}
diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c
index 54c514acacc5e24fcdb88904f41fd1d29b1e34d0..6c9f6fe3b5c08ae86a79af790fdbc6699aebf435 100644
--- a/drivers/net/macvlan.c
+++ b/drivers/net/macvlan.c
@@ -386,7 +386,7 @@ static void macvlan_broadcast_enqueue(struct macvlan_port *port,
return;
free_nskb:
- kfree_skb(nskb);
+ kfree_skb_reason(nskb, SKB_DROP_REASON_BROADCAST_BACKLOG);
err:
dev_core_stats_rx_dropped_inc(skb->dev);
}
diff --git a/include/net/dropreason-core.h b/include/net/dropreason-core.h
index de61dd5dbfd9dc7d91d22d79a510d42fb69eb60a..e81e7ae8b3271ba1a947104339bbc9e440f189f5 100644
--- a/include/net/dropreason-core.h
+++ b/include/net/dropreason-core.h
@@ -69,6 +69,8 @@
FN(QDISC_DROP) \
FN(QDISC_BURST_DROP) \
FN(CPU_BACKLOG) \
+ FN(BROADCAST_BACKLOG) \
+ FN(MULTICAST_BACKLOG) \
FN(XDP) \
FN(TC_INGRESS) \
FN(UNHANDLED_PROTO) \
@@ -382,6 +384,16 @@ enum skb_drop_reason {
* netdev_max_backlog in net.rst) or RPS flow limit
*/
SKB_DROP_REASON_CPU_BACKLOG,
+ /**
+ * @SKB_DROP_REASON_BROADCAST_BACKLOG: failed to enqueue the skb
+ * to macvlan broadcast queue.
+ */
+ SKB_DROP_REASON_BROADCAST_BACKLOG,
+ /**
+ * @SKB_DROP_REASON_MULTICAST_BACKLOG: failed to enqueue the skb
+ * to ipvlan multicast queue.
+ */
+ SKB_DROP_REASON_MULTICAST_BACKLOG,
/** @SKB_DROP_REASON_XDP: dropped by XDP in input path */
SKB_DROP_REASON_XDP,
/** @SKB_DROP_REASON_TC_INGRESS: dropped in TC ingress HOOK */
--
2.53.0.1213.gd9a14994de-goog
^ permalink raw reply related
* [PATCH net-next] net: mctp: defer creation of dst after source-address check
From: Jeremy Kerr @ 2026-04-03 2:24 UTC (permalink / raw)
To: Matt Johnston, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Simon Horman
Cc: netdev
Sashiko reports:
> mctp_dst_from_route() increments the device reference count by calling
> mctp_dev_hold(). When a valid route is found and dst is NULL, the
> structure copy is bypassed and rc is set to 0.
Instead of optimistically creating a dst from the final route (then
releasing it if the saddr is invalid), perform the saddr check first.
This means we don't have an unuecessary hold/release on the dev, which
could leak if the dst pointer is NULL. No caller passes a NULL dst at
present though (so the leak is not possible), but this is an intended
use of mctp_dst_from_route().
Fixes: 22cb45afd221 ("net: mctp: perform source address lookups when we populate our dst")
Signed-off-by: Jeremy Kerr <jk@codeconstruct.com.au>
---
net/mctp/route.c | 22 +++++++++++-----------
1 file changed, 11 insertions(+), 11 deletions(-)
diff --git a/net/mctp/route.c b/net/mctp/route.c
index 78263e7ae423..26fb8c6bbad2 100644
--- a/net/mctp/route.c
+++ b/net/mctp/route.c
@@ -897,7 +897,8 @@ static mctp_eid_t mctp_dev_saddr(struct mctp_dev *dev)
/* must only be called on a direct route, as the final output hop */
static void mctp_dst_from_route(struct mctp_dst *dst, mctp_eid_t eid,
- unsigned int mtu, struct mctp_route *route)
+ mctp_eid_t saddr, unsigned int mtu,
+ struct mctp_route *route)
{
mctp_dev_hold(route->dev);
dst->nexthop = eid;
@@ -907,7 +908,7 @@ static void mctp_dst_from_route(struct mctp_dst *dst, mctp_eid_t eid,
dst->mtu = min(dst->mtu, mtu);
dst->halen = 0;
dst->output = route->output;
- dst->saddr = mctp_dev_saddr(route->dev);
+ dst->saddr = saddr;
}
int mctp_dst_from_extaddr(struct mctp_dst *dst, struct net *net, int ifindex,
@@ -975,7 +976,6 @@ int mctp_route_lookup(struct net *net, unsigned int dnet,
{
const unsigned int max_depth = 32;
unsigned int depth, mtu = 0;
- struct mctp_dst dst_tmp;
int rc = -EHOSTUNREACH;
rcu_read_lock();
@@ -996,15 +996,15 @@ int mctp_route_lookup(struct net *net, unsigned int dnet,
mtu = mtu ?: rt->mtu;
if (rt->dst_type == MCTP_ROUTE_DIRECT) {
- mctp_dst_from_route(&dst_tmp, daddr, mtu, rt);
+ mctp_eid_t saddr = mctp_dev_saddr(rt->dev);
+
/* cannot do gateway-ed routes without a src */
- if (dst_tmp.saddr == MCTP_ADDR_NULL && depth != 0) {
- mctp_dst_release(&dst_tmp);
- } else {
- if (dst)
- *dst = dst_tmp;
- rc = 0;
- }
+ if (saddr == MCTP_ADDR_NULL && depth != 0)
+ break;
+
+ if (dst)
+ mctp_dst_from_route(dst, daddr, saddr, mtu, rt);
+ rc = 0;
break;
} else if (rt->dst_type == MCTP_ROUTE_GATEWAY) {
---
base-commit: 8b0e64d6c9e7feec5ba5643b4fa8b7fd54464778
change-id: 20260403-dev-mctp-dst-defer-93e88da84ed9
Best regards,
--
Jeremy Kerr <jk@codeconstruct.com.au>
^ permalink raw reply related
* Re: [PATCH bpf v6 1/2] bpf: tcp: Reject non-TCP skb in bpf_sk_assign_tcp_reqsk()
From: Eric Dumazet @ 2026-04-03 2:26 UTC (permalink / raw)
To: Jiayuan Chen
Cc: bpf, Kuniyuki Iwashima, Alexei Starovoitov, Daniel Borkmann,
Andrii Nakryiko, Martin KaFai Lau, Eduard Zingerman,
Kumar Kartikeya Dwivedi, Song Liu, Yonghong Song, Jiri Olsa,
John Fastabend, Stanislav Fomichev, David S. Miller,
Jakub Kicinski, Paolo Abeni, Simon Horman, Shuah Khan, netdev,
linux-kernel, linux-kselftest
In-Reply-To: <20260403015851.148209-2-jiayuan.chen@linux.dev>
On Thu, Apr 2, 2026 at 6:59 PM Jiayuan Chen <jiayuan.chen@linux.dev> wrote:
>
> bpf_sk_assign_tcp_reqsk() only validates skb->protocol (L3) but does not
> check the L4 protocol in the IP header. A BPF program can call this kfunc
> on a UDP skb with a valid TCP listener socket, which will succeed and
> attach a TCP reqsk to the UDP skb.
>
> When the UDP skb enters the UDP receive path, skb_steal_sock() returns
> the TCP listener from the reqsk. The UDP code then passes this TCP socket
> to udp_unicast_rcv_skb() -> __udp_enqueue_schedule_skb(), which casts
> it to udp_sock and accesses UDP-specific fields at invalid offsets,
> causing a null pointer dereference and kernel panic:
>
> BUG: KASAN: null-ptr-deref in __udp_enqueue_schedule_skb+0x19d/0x1df0
> Read of size 4 at addr 0000000000000008 by task test_progs/537
>
> Fix this by checking the IP header's protocol field in
> bpf_sk_assign_tcp_reqsk() and rejecting non-TCP skbs with -EINVAL.
>
> Note that for IPv6, the nexthdr check does not walk extension headers.
> This is uncommon for TCP SYN packets in practice, and keeping it simple
> was agreed upon by Kuniyuki Iwashima.
>
> Fixes: e472f88891ab ("bpf: tcp: Support arbitrary SYN Cookie.")
> Reviewed-by: Kuniyuki Iwashima <kuniyu@google.com>
> Signed-off-by: Jiayuan Chen <jiayuan.chen@linux.dev>
Reviewed-by: Eric Dumazet <edumazet@google.com>
^ permalink raw reply
* Re: [PATCH net v2] net: skb: fix cross-cache free of KFENCE-allocated skb head
From: Eric Dumazet @ 2026-04-03 2:28 UTC (permalink / raw)
To: Jiayuan Chen
Cc: netdev, Antonius, David S. Miller, Jakub Kicinski, Paolo Abeni,
Simon Horman, Jason Xing, Kuniyuki Iwashima, Michal Luczaj,
Mina Almasry, Eric Biggers, Toke Høiland-Jørgensen,
Alexander Duyck, Soheil Hassas Yeganeh, linux-kernel, bpf
In-Reply-To: <CANn89iJru14aPMCXMHmsek1S5TH+sLkczJKUPpcfZHnYxR9KEw@mail.gmail.com>
On Thu, Apr 2, 2026 at 7:23 PM Eric Dumazet <edumazet@google.com> wrote:
>
> On Thu, Apr 2, 2026 at 6:45 PM Jiayuan Chen <jiayuan.chen@linux.dev> wrote:
> >
> > SKB_SMALL_HEAD_CACHE_SIZE is intentionally set to a non-power-of-2
> > value (e.g. 704 on x86_64) to avoid collisions with generic kmalloc
> > bucket sizes. This ensures that skb_kfree_head() can reliably use
> > skb_end_offset to distinguish skb heads allocated from
> > skb_small_head_cache vs. generic kmalloc caches.
> >
> > However, when KFENCE is enabled, kfence_ksize() returns the exact
> > requested allocation size instead of the slab bucket size. If a caller
> > (e.g. bpf_test_init) allocates skb head data via kzalloc() and the
> > requested size happens to equal SKB_SMALL_HEAD_CACHE_SIZE, then
> > slab_build_skb() -> ksize() returns that exact value. After subtracting
> > skb_shared_info overhead, skb_end_offset ends up matching
> > SKB_SMALL_HEAD_HEADROOM, causing skb_kfree_head() to incorrectly free
> > the object to skb_small_head_cache instead of back to the original
> > kmalloc cache, resulting in a slab cross-cache free:
> >
> > kmem_cache_free(skbuff_small_head): Wrong slab cache. Expected
> > skbuff_small_head but got kmalloc-1k
> >
> > Fix this by always calling kfree(head) in skb_kfree_head(). This keeps
> > the free path generic and avoids allocator-specific misclassification
> > for KFENCE objects.
> >
> > Fixes: bf9f1baa279f ("net: add dedicated kmem_cache for typical/small skb->head")
> > Reported-by: Antonius <antonius@bluedragonsec.com>
> > Closes: https://lore.kernel.org/netdev/CAK8a0jxC5L5N7hq-DT2_NhUyjBxrPocoiDazzsBk4TGgT1r4-A@mail.gmail.com/
> > Signed-off-by: Jiayuan Chen <jiayuan.chen@linux.dev>
>
> Reviewed-by: Eric Dumazet <edumazet@google.com>
Note: we can later in net-next remove skb_kfree_head() completely.
^ permalink raw reply
* Re: [net-next v8 07/10] net: bnxt: Implement software USO
From: Eric Dumazet @ 2026-04-03 2:42 UTC (permalink / raw)
To: Joe Damato
Cc: netdev, Michael Chan, Pavan Chebbi, Andrew Lunn, David S. Miller,
Jakub Kicinski, Paolo Abeni, horms, linux-kernel, leon
In-Reply-To: <20260403003524.2564973-8-joe@dama.to>
On Thu, Apr 2, 2026 at 5:36 PM Joe Damato <joe@dama.to> wrote:
>
> Implement bnxt_sw_udp_gso_xmit() using the core tso_dma_map API and
> the pre-allocated TX inline buffer for per-segment headers.
>
> The xmit path:
> 1. Calls tso_start() to initialize TSO state
> 2. Stack-allocates a tso_dma_map and calls tso_dma_map_init() to
> DMA-map the linear payload and all frags upfront.
> 3. For each segment:
> - Copies and patches headers via tso_build_hdr() into the
> pre-allocated tx_inline_buf (DMA-synced per segment)
> - Counts payload BDs via tso_dma_map_count()
> - Emits long BD (header) + ext BD + payload BDs
> - Payload BDs use tso_dma_map_next() which yields (dma_addr,
> chunk_len, mapping_len) tuples.
>
> Header BDs set dma_unmap_len=0 since the inline buffer is pre-allocated
> and unmapped only at ring teardown.
>
> Completion state is updated by calling tso_dma_map_completion_save() for
> the last segment.
>
> Suggested-by: Jakub Kicinski <kuba@kernel.org>
> Signed-off-by: Joe Damato <joe@dama.to>
> ---
>
> diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h
> index 6b38b84924e0..fe50576ae525 100644
> --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h
> +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h
> @@ -11,6 +11,8 @@
> #ifndef BNXT_H
> #define BNXT_H
>
> +#include <net/tso.h>
> +
> #define DRV_MODULE_NAME "bnxt_en"
>
> /* DO NOT CHANGE DRV_VER_* defines
> @@ -899,6 +901,7 @@ struct bnxt_sw_tx_bd {
> u16 rx_prod;
> u16 txts_prod;
> };
> + struct tso_dma_map_completion_state sw_gso_cstate;
> };
>
> #define BNXT_SW_GSO_MID 1
> diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_gso.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_gso.c
> index b296769ee4fe..7a7d40e36cea 100644
> --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_gso.c
> +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_gso.c
> @@ -19,11 +19,213 @@
> #include "bnxt.h"
> #include "bnxt_gso.h"
>
> +static u32 bnxt_sw_gso_lhint(unsigned int len)
> +{
> + if (len <= 512)
> + return TX_BD_FLAGS_LHINT_512_AND_SMALLER;
> + else if (len <= 1023)
> + return TX_BD_FLAGS_LHINT_512_TO_1023;
> + else if (len <= 2047)
> + return TX_BD_FLAGS_LHINT_1024_TO_2047;
> + else
> + return TX_BD_FLAGS_LHINT_2048_AND_LARGER;
> +}
> +
> netdev_tx_t bnxt_sw_udp_gso_xmit(struct bnxt *bp,
> struct bnxt_tx_ring_info *txr,
> struct netdev_queue *txq,
> struct sk_buff *skb)
> {
> + unsigned int last_unmap_len __maybe_unused = 0;
> + dma_addr_t last_unmap_addr __maybe_unused = 0;
> + struct bnxt_sw_tx_bd *last_unmap_buf = NULL;
> + unsigned int hdr_len, mss, num_segs;
> + struct pci_dev *pdev = bp->pdev;
> + unsigned int total_payload;
> + struct tso_dma_map map;
> + u32 vlan_tag_flags = 0;
> + int i, bds_needed;
> + struct tso_t tso;
> + u16 cfa_action;
> + u16 prod;
> +
> + hdr_len = tso_start(skb, &tso);
Orthogonal to your patch:
It seems that tso_start() users do not really check if hdr_len could
be bigger than
their expectations ( TSO_HEADER_SIZE for many of them).
Presumably these drivers should have an ndo_features_check() to detect
this and fallback to GSO.
I can send a series to fix this.
^ permalink raw reply
* [PATCH v10 net-next 0/6] octeontx2-af: npc: Enhancements.
From: Ratheesh Kannoth @ 2026-04-03 2:55 UTC (permalink / raw)
To: netdev, linux-kernel, linux-rdma
Cc: sgoutham, andrew+netdev, davem, edumazet, kuba, pabeni,
donald.hunter, horms, jiri, chuck.lever, matttbe, cjubran, saeedm,
leon, tariqt, mbloch, dtatulea, Ratheesh Kannoth
This series extends Marvell octeontx2-af support for CN20K NPC (MCAM
debuggability, allocation policy, default-rule lifetime, and optional
KPU profiles from firmware files) and adds a devlink mechanism for
multi-value parameters, with a small mlx5 follow-up to keep stack usage
within -Wframe-larger-than limits once union devlink_param_value grows.
Patch 1 improves CN20K MCAM visibility in debugfs: mcam_layout marks
enabled entries, dstats reports per-entry hit deltas, and mismatch lists
enabled entries without a PF mapping. MCAM enable state is tracked in a
bitmap updated from the CN20K enable path.
Patch 2 heap-allocates the temporary devlink param value array in
mlx5e_pcie_cong_get_thresh_config() so a larger union devlink_param_value
does not overflow the stack (patch 3).
Patch 3 (Saeed) introduces DEVLINK_PARAM_TYPE_U64_ARRAY and nested
DEVLINK_ATTR_PARAM_VALUE_DATA attributes so drivers and user space can
exchange bounded u64 arrays; devlink_nl_param_fill() moves large locals
to the heap as well.
Patch 4 adds a runtime devlink parameter npc_srch_order (U64 array) to
reorder CN20K subbank search during MCAM allocation.
Patch 5 ties default MCAM entries (broadcast, multicast, promisc, ucast)
to NIX LF alloc/free on CN20K, adds NIX_LF_DONT_FREE_DFT_IDXS for kernel
PF suspend-style teardown, and adjusts free-all and default-entry paths
so default rules are not freed as ordinary user rules.
Patch 6 allows loading a custom KPU profile from /lib/firmware/kpu via
module parameter kpu_profile on non-CN20K paths, with cam2/ptype support
and shared helpers for firmware-sourced vs filesystem-sourced profiles;
CN20K continues to use its existing custom KPU apply path.
The mlx5 change is placed immediately before the devlink union growth
so the series applies cleanly and stays warning-free when built
incrementally.
Ratheesh Kannoth (5):
octeontx2-af: npc: cn20k: debugfs enhancements
net/mlx5e: heap-allocate devlink param values
octeontx2-af: npc: cn20k: add subbank search order control
octeontx2-af: npc: cn20k: dynamically allocate and free default MCAM
entries
octeontx2-af: npc: Support for custom KPU profile from filesystem
Saeed Mahameed (1):
devlink: Implement devlink param multi attribute nested data values
Documentation/netlink/specs/devlink.yaml | 4 +
.../marvell/octeontx2/af/cn20k/debugfs.c | 126 ++++-
.../ethernet/marvell/octeontx2/af/cn20k/npc.c | 255 +++++++--
.../ethernet/marvell/octeontx2/af/cn20k/npc.h | 10 +
.../net/ethernet/marvell/octeontx2/af/mbox.h | 1 +
.../net/ethernet/marvell/octeontx2/af/npc.h | 17 +
.../net/ethernet/marvell/octeontx2/af/rvu.h | 6 +-
.../marvell/octeontx2/af/rvu_devlink.c | 92 +++-
.../ethernet/marvell/octeontx2/af/rvu_nix.c | 16 +-
.../ethernet/marvell/octeontx2/af/rvu_npc.c | 521 ++++++++++++++----
.../ethernet/marvell/octeontx2/af/rvu_npc.h | 17 +
.../ethernet/marvell/octeontx2/af/rvu_reg.h | 1 +
.../ethernet/marvell/octeontx2/nic/otx2_pf.c | 6 +-
.../mellanox/mlx5/core/en/pcie_cong_event.c | 11 +-
include/net/devlink.h | 8 +
include/uapi/linux/devlink.h | 1 +
net/devlink/netlink_gen.c | 2 +
net/devlink/param.c | 91 ++-
18 files changed, 979 insertions(+), 206 deletions(-)
--
v9 -> v10: Addressed Paolo comments
https://lore.kernel.org/netdev/20260330053105.2722453-1-rkannoth@marvell.com/
v8 -> v9: Addressed Simon comments
https://lore.kernel.org/netdev/20260325072159.1126964-1-rkannoth@marvell.com/
v7 -> v8: Addressed Simon comments
https://lore.kernel.org/netdev/20260323035110.3908741-1-rkannoth@marvell.com/T/#t
v6 -> v7: Addressed Simon comments
https://lore.kernel.org/netdev/20260320165432.98832-1-horms@kernel.org/
v5 -> v6: Addressed Jakub,Jiri comments
https://lore.kernel.org/netdev/20260317045623.250187-1-rkannoth@marvell.com/
v4 -> v5: Addressed Jakub comments
https://lore.kernel.org/netdev/20260312022754.2029595-6-rkannoth@marvell.com/
v3 -> v4: Addressed Simon comments
https://lore.kernel.org/netdev/abDeXLpMMxp7G1v3@rkannoth-OptiPlex-7090/#t
v2 -> v3: Addressed Simon comments.
https://lore.kernel.org/netdev/20260304043032.3661647-1-rkannoth@marvell.com/
v1 -> v2: Addressed Jakub comments.
https://lore.kernel.org/netdev/20260302085803.2449828-1-rkannoth@marvell.com/#t
2.43.0
^ permalink raw reply
* [PATCH v10 net-next 1/6] octeontx2-af: npc: cn20k: debugfs enhancements
From: Ratheesh Kannoth @ 2026-04-03 2:55 UTC (permalink / raw)
To: netdev, linux-kernel, linux-rdma
Cc: sgoutham, andrew+netdev, davem, edumazet, kuba, pabeni,
donald.hunter, horms, jiri, chuck.lever, matttbe, cjubran, saeedm,
leon, tariqt, mbloch, dtatulea, Ratheesh Kannoth
In-Reply-To: <20260403025533.6250-1-rkannoth@marvell.com>
Improve MCAM visibility and field debugging for CN20K NPC.
- Extend "mcam_layout" to show enabled (+) or disabled state per entry
so status can be verified without parsing the full "mcam_entry" dump.
- Add "dstats" debugfs entry: reports recently hit MCAM indices with
packet counts; stats are cleared on read so each read shows deltas.
- Add "mismatch" debugfs entry: lists MCAM entries that are enabled
but not explicitly allocated, helping diagnose allocation/field issues.
Signed-off-by: Ratheesh Kannoth <rkannoth@marvell.com>
---
.../marvell/octeontx2/af/cn20k/debugfs.c | 126 +++++++++++++++++-
.../ethernet/marvell/octeontx2/af/cn20k/npc.c | 16 ++-
.../ethernet/marvell/octeontx2/af/cn20k/npc.h | 7 +
3 files changed, 135 insertions(+), 14 deletions(-)
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/debugfs.c b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/debugfs.c
index 3debf2fae1a4..e8f85ed5ead7 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/debugfs.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/debugfs.c
@@ -13,6 +13,7 @@
#include "struct.h"
#include "rvu.h"
#include "debugfs.h"
+#include "cn20k/reg.h"
#include "cn20k/npc.h"
static int npc_mcam_layout_show(struct seq_file *s, void *unused)
@@ -58,7 +59,8 @@ static int npc_mcam_layout_show(struct seq_file *s, void *unused)
"v:%u", vidx0);
}
- seq_printf(s, "\t%u(%#x) %s\n", idx0, pf1,
+ seq_printf(s, "\t%u(%#x)%c %s\n", idx0, pf1,
+ test_bit(idx0, npc_priv->en_map) ? '+' : ' ',
map ? buf0 : " ");
}
goto next;
@@ -101,9 +103,13 @@ static int npc_mcam_layout_show(struct seq_file *s, void *unused)
vidx1);
}
- seq_printf(s, "%05u(%#x) %s\t\t%05u(%#x) %s\n",
- idx1, pf2, v1 ? buf1 : " ",
- idx0, pf1, v0 ? buf0 : " ");
+ seq_printf(s, "%05u(%#x)%c %s\t\t%05u(%#x)%c %s\n",
+ idx1, pf2,
+ test_bit(idx1, npc_priv->en_map) ? '+' : ' ',
+ v1 ? buf1 : " ",
+ idx0, pf1,
+ test_bit(idx0, npc_priv->en_map) ? '+' : ' ',
+ v0 ? buf0 : " ");
continue;
}
@@ -120,8 +126,9 @@ static int npc_mcam_layout_show(struct seq_file *s, void *unused)
vidx0);
}
- seq_printf(s, "\t\t \t\t%05u(%#x) %s\n", idx0,
- pf1, map ? buf0 : " ");
+ seq_printf(s, "\t\t \t\t%05u(%#x)%c %s\n", idx0, pf1,
+ test_bit(idx0, npc_priv->en_map) ? '+' : ' ',
+ map ? buf0 : " ");
continue;
}
@@ -134,7 +141,8 @@ static int npc_mcam_layout_show(struct seq_file *s, void *unused)
snprintf(buf1, sizeof(buf1), "v:%05u", vidx1);
}
- seq_printf(s, "%05u(%#x) %s\n", idx1, pf1,
+ seq_printf(s, "%05u(%#x)%c %s\n", idx1, pf1,
+ test_bit(idx1, npc_priv->en_map) ? '+' : ' ',
map ? buf1 : " ");
}
next:
@@ -145,6 +153,100 @@ static int npc_mcam_layout_show(struct seq_file *s, void *unused)
DEFINE_SHOW_ATTRIBUTE(npc_mcam_layout);
+static u64 dstats[MAX_NUM_BANKS][MAX_SUBBANK_DEPTH * MAX_NUM_SUB_BANKS] = {};
+static int npc_mcam_dstats_show(struct seq_file *s, void *unused)
+{
+ struct npc_priv_t *npc_priv;
+ int blkaddr, pf, mcam_idx;
+ u64 stats, delta;
+ struct rvu *rvu;
+ u8 key_type;
+ void *map;
+
+ npc_priv = npc_priv_get();
+ rvu = s->private;
+ blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPC, 0);
+ if (blkaddr < 0)
+ return 0;
+
+ seq_puts(s, "idx\tpfunc\tstats\n");
+ for (int bank = npc_priv->num_banks - 1; bank >= 0; bank--) {
+ for (int idx = npc_priv->bank_depth - 1; idx >= 0; idx--) {
+ mcam_idx = bank * npc_priv->bank_depth + idx;
+
+ npc_mcam_idx_2_key_type(rvu, mcam_idx, &key_type);
+ if (key_type == NPC_MCAM_KEY_X4 && bank != 0)
+ continue;
+
+ if (!test_bit(mcam_idx, npc_priv->en_map))
+ continue;
+
+ stats = rvu_read64(rvu, blkaddr,
+ NPC_AF_CN20K_MCAMEX_BANKX_STAT_EXT(idx, bank));
+ if (!stats)
+ continue;
+ if (stats == dstats[bank][idx])
+ continue;
+
+ if (stats < dstats[bank][idx])
+ dstats[bank][idx] = 0;
+
+ pf = 0xFFFF;
+ map = xa_load(&npc_priv->xa_idx2pf_map, mcam_idx);
+ if (map)
+ pf = xa_to_value(map);
+
+ if (stats > dstats[bank][idx])
+ delta = stats - dstats[bank][idx];
+ else
+ delta = stats;
+
+ seq_printf(s, "%u\t%#04x\t%llu\n",
+ mcam_idx, pf, delta);
+ dstats[bank][idx] = stats;
+ }
+ }
+ return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(npc_mcam_dstats);
+
+static int npc_mcam_mismatch_show(struct seq_file *s, void *unused)
+{
+ struct npc_priv_t *npc_priv;
+ struct npc_subbank *sb;
+ int mcam_idx, sb_off;
+ struct rvu *rvu;
+ void *map;
+ int rc;
+
+ npc_priv = npc_priv_get();
+ rvu = s->private;
+
+ seq_puts(s, "index\tsb idx\tkw type\n");
+ for (int bank = npc_priv->num_banks - 1; bank >= 0; bank--) {
+ for (int idx = npc_priv->bank_depth - 1; idx >= 0; idx--) {
+ mcam_idx = bank * npc_priv->bank_depth + idx;
+
+ if (!test_bit(mcam_idx, npc_priv->en_map))
+ continue;
+
+ map = xa_load(&npc_priv->xa_idx2pf_map, mcam_idx);
+ if (map)
+ continue;
+
+ rc = npc_mcam_idx_2_subbank_idx(rvu, mcam_idx,
+ &sb, &sb_off);
+ if (rc)
+ continue;
+
+ seq_printf(s, "%u\t%d\t%u\n", mcam_idx, sb->idx,
+ sb->key_type);
+ }
+ }
+ return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(npc_mcam_mismatch);
+
static int npc_mcam_default_show(struct seq_file *s, void *unused)
{
struct npc_priv_t *npc_priv;
@@ -257,6 +359,16 @@ int npc_cn20k_debugfs_init(struct rvu *rvu)
if (!npc_dentry)
return -EFAULT;
+ npc_dentry = debugfs_create_file("dstats", 0444, rvu->rvu_dbg.npc, rvu,
+ &npc_mcam_dstats_fops);
+ if (!npc_dentry)
+ return -EFAULT;
+
+ npc_dentry = debugfs_create_file("mismatch", 0444, rvu->rvu_dbg.npc, rvu,
+ &npc_mcam_mismatch_fops);
+ if (!npc_dentry)
+ return -EFAULT;
+
npc_dentry = debugfs_create_file("mcam_default", 0444, rvu->rvu_dbg.npc,
rvu, &npc_mcam_default_fops);
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c
index 7291fdb89b03..e854b85ced9e 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c
@@ -808,6 +808,9 @@ npc_cn20k_enable_mcam_entry(struct rvu *rvu, int blkaddr,
u64 cfg, hw_prio;
u8 kw_type;
+ enable ? set_bit(index, npc_priv.en_map) :
+ clear_bit(index, npc_priv.en_map);
+
npc_mcam_idx_2_key_type(rvu, index, &kw_type);
if (kw_type == NPC_MCAM_KEY_X2) {
cfg = rvu_read64(rvu, blkaddr,
@@ -1016,14 +1019,12 @@ static void npc_cn20k_config_kw_x4(struct rvu *rvu, struct npc_mcam *mcam,
static void
npc_cn20k_set_mcam_bank_cfg(struct rvu *rvu, int blkaddr, int mcam_idx,
- int bank, u8 kw_type, bool enable, u8 hw_prio)
+ int bank, u8 kw_type, u8 hw_prio)
{
struct npc_mcam *mcam = &rvu->hw->mcam;
u64 bank_cfg;
bank_cfg = (u64)hw_prio << 24;
- if (enable)
- bank_cfg |= 0x1;
if (kw_type == NPC_MCAM_KEY_X2) {
rvu_write64(rvu, blkaddr,
@@ -1119,7 +1120,8 @@ void npc_cn20k_config_mcam_entry(struct rvu *rvu, int blkaddr, int index,
/* TODO: */
/* PF installing VF rule */
npc_cn20k_set_mcam_bank_cfg(rvu, blkaddr, mcam_idx, bank,
- kw_type, enable, hw_prio);
+ kw_type, hw_prio);
+ npc_cn20k_enable_mcam_entry(rvu, blkaddr, index, enable);
}
void npc_cn20k_copy_mcam_entry(struct rvu *rvu, int blkaddr, u16 src, u16 dest)
@@ -1735,9 +1737,9 @@ static int npc_subbank_idx_2_mcam_idx(struct rvu *rvu, struct npc_subbank *sb,
return 0;
}
-static int npc_mcam_idx_2_subbank_idx(struct rvu *rvu, u16 mcam_idx,
- struct npc_subbank **sb,
- int *sb_off)
+int npc_mcam_idx_2_subbank_idx(struct rvu *rvu, u16 mcam_idx,
+ struct npc_subbank **sb,
+ int *sb_off)
{
int bank_off, sb_id;
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.h b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.h
index 815d0b257a7e..004a556c7b90 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.h
+++ b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.h
@@ -170,6 +170,7 @@ struct npc_defrag_show_node {
* @num_banks: Number of banks.
* @num_subbanks: Number of subbanks.
* @subbank_depth: Depth of subbank.
+ * @en_map: Enable/disable status.
* @kw: Kex configured key type.
* @sb: Subbank array.
* @xa_sb_used: Array of used subbanks.
@@ -193,6 +194,9 @@ struct npc_priv_t {
const int num_banks;
int num_subbanks;
int subbank_depth;
+ DECLARE_BITMAP(en_map, MAX_NUM_BANKS *
+ MAX_NUM_SUB_BANKS *
+ MAX_SUBBANK_DEPTH);
u8 kw;
struct npc_subbank *sb;
struct xarray xa_sb_used;
@@ -336,5 +340,8 @@ int npc_mcam_idx_2_key_type(struct rvu *rvu, u16 mcam_idx, u8 *key_type);
u16 npc_cn20k_vidx2idx(u16 index);
u16 npc_cn20k_idx2vidx(u16 idx);
int npc_cn20k_defrag(struct rvu *rvu);
+int npc_mcam_idx_2_subbank_idx(struct rvu *rvu, u16 mcam_idx,
+ struct npc_subbank **sb,
+ int *sb_off);
#endif /* NPC_CN20K_H */
--
2.43.0
^ permalink raw reply related
* [PATCH v10 net-next 2/6] net/mlx5e: heap-allocate devlink param values
From: Ratheesh Kannoth @ 2026-04-03 2:55 UTC (permalink / raw)
To: netdev, linux-kernel, linux-rdma
Cc: sgoutham, andrew+netdev, davem, edumazet, kuba, pabeni,
donald.hunter, horms, jiri, chuck.lever, matttbe, cjubran, saeedm,
leon, tariqt, mbloch, dtatulea, Ratheesh Kannoth
In-Reply-To: <20260403025533.6250-1-rkannoth@marvell.com>
union devlink_param_value grows when U64 array params
are added to devlink. Keeping a four-element array of that
union on the stack in mlx5e_pcie_cong_get_thresh_config()
then trips -Wframe-larger-than=1280. Allocate the temporary
values with kcalloc() and free them on success and
error paths.
Signed-off-by: Ratheesh Kannoth <rkannoth@marvell.com>
---
.../ethernet/mellanox/mlx5/core/en/pcie_cong_event.c | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/pcie_cong_event.c b/drivers/net/ethernet/mellanox/mlx5/core/en/pcie_cong_event.c
index 2eb666a46f39..f02995552129 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/en/pcie_cong_event.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/en/pcie_cong_event.c
@@ -259,15 +259,21 @@ mlx5e_pcie_cong_get_thresh_config(struct mlx5_core_dev *dev,
MLX5_DEVLINK_PARAM_ID_PCIE_CONG_OUT_HIGH,
};
struct devlink *devlink = priv_to_devlink(dev);
- union devlink_param_value val[4];
+ union devlink_param_value *val;
+
+ val = kcalloc(4, sizeof(*val), GFP_KERNEL);
+ if (!val)
+ return -ENOMEM;
for (int i = 0; i < 4; i++) {
u32 id = ids[i];
int err;
err = devl_param_driverinit_value_get(devlink, id, &val[i]);
- if (err)
+ if (err) {
+ kfree(val);
return err;
+ }
}
config->inbound_low = val[0].vu16;
@@ -275,6 +281,7 @@ mlx5e_pcie_cong_get_thresh_config(struct mlx5_core_dev *dev,
config->outbound_low = val[2].vu16;
config->outbound_high = val[3].vu16;
+ kfree(val);
return 0;
}
--
2.43.0
^ permalink raw reply related
* [PATCH v10 net-next 3/6] devlink: Implement devlink param multi attribute nested data values
From: Ratheesh Kannoth @ 2026-04-03 2:55 UTC (permalink / raw)
To: netdev, linux-kernel, linux-rdma
Cc: sgoutham, andrew+netdev, davem, edumazet, kuba, pabeni,
donald.hunter, horms, jiri, chuck.lever, matttbe, cjubran, saeedm,
leon, tariqt, mbloch, dtatulea, Ratheesh Kannoth
In-Reply-To: <20260403025533.6250-1-rkannoth@marvell.com>
From: Saeed Mahameed <saeedm@nvidia.com>
Devlink param value attribute is not defined since devlink is handling
the value validating and parsing internally, this allows us to implement
multi attribute values without breaking any policies.
Devlink param multi-attribute values are considered to be dynamically
sized arrays of u64 values, by introducing a new devlink param type
DEVLINK_PARAM_TYPE_U64_ARRAY, driver and user space can set a variable
count of u32 values into the DEVLINK_ATTR_PARAM_VALUE_DATA attribute.
Implement get/set parsing and add to the internal value structure passed
to drivers.
This is useful for devices that need to configure a list of values for
a specific configuration.
example:
$ devlink dev param show pci/... name multi-value-param
name multi-value-param type driver-specific
values:
cmode permanent value: 0,1,2,3,4,5,6,7
$ devlink dev param set pci/... name multi-value-param \
value 4,5,6,7,0,1,2,3 cmode permanent
Signed-off-by: Saeed Mahameed <saeedm@nvidia.com>
Signed-off-by: Ratheesh Kannoth <rkannoth@marvell.com>
---
Documentation/netlink/specs/devlink.yaml | 4 ++
include/net/devlink.h | 8 +++
include/uapi/linux/devlink.h | 1 +
net/devlink/netlink_gen.c | 2 +
net/devlink/param.c | 91 +++++++++++++++++++-----
5 files changed, 89 insertions(+), 17 deletions(-)
diff --git a/Documentation/netlink/specs/devlink.yaml b/Documentation/netlink/specs/devlink.yaml
index b495d56b9137..b619de4fe08a 100644
--- a/Documentation/netlink/specs/devlink.yaml
+++ b/Documentation/netlink/specs/devlink.yaml
@@ -226,6 +226,10 @@ definitions:
value: 10
-
name: binary
+ -
+ name: u64-array
+ value: 129
+
-
name: rate-tc-index-max
type: const
diff --git a/include/net/devlink.h b/include/net/devlink.h
index 3038af6ec017..3a355fea8189 100644
--- a/include/net/devlink.h
+++ b/include/net/devlink.h
@@ -432,6 +432,13 @@ enum devlink_param_type {
DEVLINK_PARAM_TYPE_U64 = DEVLINK_VAR_ATTR_TYPE_U64,
DEVLINK_PARAM_TYPE_STRING = DEVLINK_VAR_ATTR_TYPE_STRING,
DEVLINK_PARAM_TYPE_BOOL = DEVLINK_VAR_ATTR_TYPE_FLAG,
+ DEVLINK_PARAM_TYPE_U64_ARRAY = DEVLINK_VAR_ATTR_TYPE_U64_ARRAY,
+};
+
+#define __DEVLINK_PARAM_MAX_ARRAY_SIZE 32
+struct devlink_param_u64_array {
+ u64 size;
+ u64 val[__DEVLINK_PARAM_MAX_ARRAY_SIZE];
};
union devlink_param_value {
@@ -441,6 +448,7 @@ union devlink_param_value {
u64 vu64;
char vstr[__DEVLINK_PARAM_MAX_STRING_VALUE];
bool vbool;
+ struct devlink_param_u64_array u64arr;
};
struct devlink_param_gset_ctx {
diff --git a/include/uapi/linux/devlink.h b/include/uapi/linux/devlink.h
index 7de2d8cc862f..5332223dd6d0 100644
--- a/include/uapi/linux/devlink.h
+++ b/include/uapi/linux/devlink.h
@@ -406,6 +406,7 @@ enum devlink_var_attr_type {
DEVLINK_VAR_ATTR_TYPE_BINARY,
__DEVLINK_VAR_ATTR_TYPE_CUSTOM_BASE = 0x80,
/* Any possible custom types, unrelated to NLA_* values go below */
+ DEVLINK_VAR_ATTR_TYPE_U64_ARRAY,
};
enum devlink_attr {
diff --git a/net/devlink/netlink_gen.c b/net/devlink/netlink_gen.c
index eb35e80e01d1..7aaf462f27ee 100644
--- a/net/devlink/netlink_gen.c
+++ b/net/devlink/netlink_gen.c
@@ -37,6 +37,8 @@ devlink_attr_param_type_validate(const struct nlattr *attr,
case DEVLINK_VAR_ATTR_TYPE_NUL_STRING:
fallthrough;
case DEVLINK_VAR_ATTR_TYPE_BINARY:
+ fallthrough;
+ case DEVLINK_VAR_ATTR_TYPE_U64_ARRAY:
return 0;
}
NL_SET_ERR_MSG_ATTR(extack, attr, "invalid enum value");
diff --git a/net/devlink/param.c b/net/devlink/param.c
index cf95268da5b0..2ec85dffd8ac 100644
--- a/net/devlink/param.c
+++ b/net/devlink/param.c
@@ -252,6 +252,14 @@ devlink_nl_param_value_put(struct sk_buff *msg, enum devlink_param_type type,
return -EMSGSIZE;
}
break;
+ case DEVLINK_PARAM_TYPE_U64_ARRAY:
+ if (val.u64arr.size > __DEVLINK_PARAM_MAX_ARRAY_SIZE)
+ return -EMSGSIZE;
+
+ for (int i = 0; i < val.u64arr.size; i++)
+ if (nla_put_uint(msg, nla_type, val.u64arr.val[i]))
+ return -EMSGSIZE;
+ break;
}
return 0;
}
@@ -304,56 +312,78 @@ static int devlink_nl_param_fill(struct sk_buff *msg, struct devlink *devlink,
u32 portid, u32 seq, int flags,
struct netlink_ext_ack *extack)
{
- union devlink_param_value default_value[DEVLINK_PARAM_CMODE_MAX + 1];
- union devlink_param_value param_value[DEVLINK_PARAM_CMODE_MAX + 1];
bool default_value_set[DEVLINK_PARAM_CMODE_MAX + 1] = {};
bool param_value_set[DEVLINK_PARAM_CMODE_MAX + 1] = {};
const struct devlink_param *param = param_item->param;
- struct devlink_param_gset_ctx ctx;
+ union devlink_param_value *default_value;
+ union devlink_param_value *param_value;
+ struct devlink_param_gset_ctx *ctx;
struct nlattr *param_values_list;
struct nlattr *param_attr;
void *hdr;
int err;
int i;
+ default_value = kcalloc(DEVLINK_PARAM_CMODE_MAX + 1,
+ sizeof(*default_value), GFP_KERNEL);
+ if (!default_value)
+ return -ENOMEM;
+
+ param_value = kcalloc(DEVLINK_PARAM_CMODE_MAX + 1,
+ sizeof(*param_value), GFP_KERNEL);
+ if (!param_value) {
+ kfree(default_value);
+ return -ENOMEM;
+ }
+
+ ctx = kmalloc_obj(*ctx);
+ if (!ctx) {
+ kfree(param_value);
+ kfree(default_value);
+ return -ENOMEM;
+ }
+
/* Get value from driver part to driverinit configuration mode */
for (i = 0; i <= DEVLINK_PARAM_CMODE_MAX; i++) {
if (!devlink_param_cmode_is_supported(param, i))
continue;
if (i == DEVLINK_PARAM_CMODE_DRIVERINIT) {
- if (param_item->driverinit_value_new_valid)
+ if (param_item->driverinit_value_new_valid) {
param_value[i] = param_item->driverinit_value_new;
- else if (param_item->driverinit_value_valid)
+ } else if (param_item->driverinit_value_valid) {
param_value[i] = param_item->driverinit_value;
- else
- return -EOPNOTSUPP;
+ } else {
+ err = -EOPNOTSUPP;
+ goto get_put_fail;
+ }
if (param_item->driverinit_value_valid) {
default_value[i] = param_item->driverinit_default;
default_value_set[i] = true;
}
} else {
- ctx.cmode = i;
- err = devlink_param_get(devlink, param, &ctx, extack);
+ ctx->cmode = i;
+ err = devlink_param_get(devlink, param, ctx, extack);
if (err)
- return err;
- param_value[i] = ctx.val;
+ goto get_put_fail;
+ param_value[i] = ctx->val;
- err = devlink_param_get_default(devlink, param, &ctx,
+ err = devlink_param_get_default(devlink, param, ctx,
extack);
if (!err) {
- default_value[i] = ctx.val;
+ default_value[i] = ctx->val;
default_value_set[i] = true;
} else if (err != -EOPNOTSUPP) {
- return err;
+ goto get_put_fail;
}
}
param_value_set[i] = true;
}
+ err = -EMSGSIZE;
hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
if (!hdr)
- return -EMSGSIZE;
+ goto get_put_fail;
if (devlink_nl_put_handle(msg, devlink))
goto genlmsg_cancel;
@@ -393,6 +423,9 @@ static int devlink_nl_param_fill(struct sk_buff *msg, struct devlink *devlink,
nla_nest_end(msg, param_values_list);
nla_nest_end(msg, param_attr);
genlmsg_end(msg, hdr);
+ kfree(default_value);
+ kfree(param_value);
+ kfree(ctx);
return 0;
values_list_nest_cancel:
@@ -401,7 +434,11 @@ static int devlink_nl_param_fill(struct sk_buff *msg, struct devlink *devlink,
nla_nest_cancel(msg, param_attr);
genlmsg_cancel:
genlmsg_cancel(msg, hdr);
- return -EMSGSIZE;
+get_put_fail:
+ kfree(default_value);
+ kfree(param_value);
+ kfree(ctx);
+ return err;
}
static void devlink_param_notify(struct devlink *devlink,
@@ -507,7 +544,7 @@ devlink_param_value_get_from_info(const struct devlink_param *param,
union devlink_param_value *value)
{
struct nlattr *param_data;
- int len;
+ int len, cnt, rem;
param_data = info->attrs[DEVLINK_ATTR_PARAM_VALUE_DATA];
@@ -547,6 +584,26 @@ devlink_param_value_get_from_info(const struct devlink_param *param,
return -EINVAL;
value->vbool = nla_get_flag(param_data);
break;
+
+ case DEVLINK_PARAM_TYPE_U64_ARRAY:
+ cnt = 0;
+ nla_for_each_attr_type(param_data,
+ DEVLINK_ATTR_PARAM_VALUE_DATA,
+ genlmsg_data(info->genlhdr),
+ genlmsg_len(info->genlhdr), rem) {
+ if (cnt >= __DEVLINK_PARAM_MAX_ARRAY_SIZE)
+ return -EMSGSIZE;
+
+ if ((nla_len(param_data) != sizeof(u64)) &&
+ (nla_len(param_data) != sizeof(u32)))
+ return -EINVAL;
+
+ value->u64arr.val[cnt] = (u64)nla_get_uint(param_data);
+ cnt++;
+ }
+
+ value->u64arr.size = cnt;
+ break;
}
return 0;
}
--
2.43.0
^ permalink raw reply related
* [PATCH v10 net-next 4/6] octeontx2-af: npc: cn20k: add subbank search order control
From: Ratheesh Kannoth @ 2026-04-03 2:55 UTC (permalink / raw)
To: netdev, linux-kernel, linux-rdma
Cc: sgoutham, andrew+netdev, davem, edumazet, kuba, pabeni,
donald.hunter, horms, jiri, chuck.lever, matttbe, cjubran, saeedm,
leon, tariqt, mbloch, dtatulea, Ratheesh Kannoth
In-Reply-To: <20260403025533.6250-1-rkannoth@marvell.com>
CN20K NPC MCAM is split into 32 subbanks that are searched in a
predefined order during allocation. Lower-numbered subbanks have
higher priority than higher-numbered ones.
Add a runtime devlink parameter "srch_order" (
DEVLINK_PARAM_TYPE_U32_ARRAY) to control the order in which
subbanks are searched during MCAM allocation.
Signed-off-by: Ratheesh Kannoth <rkannoth@marvell.com>
---
.../ethernet/marvell/octeontx2/af/cn20k/npc.c | 91 +++++++++++++++++-
.../ethernet/marvell/octeontx2/af/cn20k/npc.h | 2 +
.../marvell/octeontx2/af/rvu_devlink.c | 92 +++++++++++++++++--
3 files changed, 173 insertions(+), 12 deletions(-)
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c
index e854b85ced9e..153765b3e504 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c
@@ -3317,7 +3317,7 @@ rvu_mbox_handler_npc_cn20k_get_kex_cfg(struct rvu *rvu,
return 0;
}
-static int *subbank_srch_order;
+static u32 *subbank_srch_order;
static void npc_populate_restricted_idxs(int num_subbanks)
{
@@ -3329,7 +3329,7 @@ static int npc_create_srch_order(int cnt)
{
int val = 0;
- subbank_srch_order = kcalloc(cnt, sizeof(int),
+ subbank_srch_order = kcalloc(cnt, sizeof(u32),
GFP_KERNEL);
if (!subbank_srch_order)
return -ENOMEM;
@@ -3809,6 +3809,93 @@ static void npc_unlock_all_subbank(void)
mutex_unlock(&npc_priv.sb[i].lock);
}
+int npc_cn20k_search_order_set(struct rvu *rvu,
+ u64 arr[MAX_NUM_SUB_BANKS], int cnt)
+{
+ struct npc_mcam *mcam = &rvu->hw->mcam;
+ u32 fslots[MAX_NUM_SUB_BANKS][2];
+ u32 uslots[MAX_NUM_SUB_BANKS][2];
+ int fcnt = 0, ucnt = 0;
+ struct npc_subbank *sb;
+ int idx, val, rc = 0;
+
+ unsigned long index;
+ void *v;
+
+ if (cnt != npc_priv.num_subbanks) {
+ dev_err(rvu->dev, "Number of entries(%u) != %u\n",
+ cnt, npc_priv.num_subbanks);
+ return -EINVAL;
+ }
+
+ mutex_lock(&mcam->lock);
+ npc_lock_all_subbank();
+ restrict_valid = false;
+
+ for (int i = 0; i < cnt; i++)
+ subbank_srch_order[i] = (u32)arr[i];
+
+ xa_for_each(&npc_priv.xa_sb_used, index, v) {
+ val = xa_to_value(v);
+ uslots[ucnt][0] = index;
+ uslots[ucnt][1] = val;
+ xa_erase(&npc_priv.xa_sb_used, index);
+ ucnt++;
+ }
+
+ xa_for_each(&npc_priv.xa_sb_free, index, v) {
+ val = xa_to_value(v);
+ fslots[fcnt][0] = index;
+ fslots[fcnt][1] = val;
+ xa_erase(&npc_priv.xa_sb_free, index);
+ fcnt++;
+ }
+
+ /* xa_store() is done under lock. If xa_store fails
+ * ,no rollback is planned as it might also fail.
+ */
+ for (int i = 0; i < ucnt; i++) {
+ idx = uslots[i][1];
+ sb = &npc_priv.sb[idx];
+ sb->arr_idx = subbank_srch_order[sb->idx];
+ rc = xa_err(xa_store(&npc_priv.xa_sb_used, sb->arr_idx,
+ xa_mk_value(sb->idx), GFP_KERNEL));
+ if (rc) {
+ dev_err(rvu->dev,
+ "Error to insert index to used list %u\n",
+ sb->idx);
+ goto fail_used;
+ }
+ }
+
+ for (int i = 0; i < fcnt; i++) {
+ idx = fslots[i][1];
+ sb = &npc_priv.sb[idx];
+ sb->arr_idx = subbank_srch_order[sb->idx];
+ rc = xa_err(xa_store(&npc_priv.xa_sb_free, sb->arr_idx,
+ xa_mk_value(sb->idx), GFP_KERNEL));
+ if (rc) {
+ dev_err(rvu->dev,
+ "Error to insert index to free list %u\n",
+ sb->idx);
+ goto fail_used;
+ }
+ }
+
+fail_used:
+ npc_unlock_all_subbank();
+ mutex_unlock(&mcam->lock);
+
+ return rc;
+}
+
+const u32 *npc_cn20k_search_order_get(bool *restricted_order, u32 *sz)
+{
+ *restricted_order = restrict_valid;
+ *sz = npc_priv.num_subbanks;
+ return subbank_srch_order;
+}
+
/* Only non-ref non-contigous mcam indexes
* are picked for defrag process
*/
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.h b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.h
index 004a556c7b90..6f9f796940f3 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.h
+++ b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.h
@@ -343,5 +343,7 @@ int npc_cn20k_defrag(struct rvu *rvu);
int npc_mcam_idx_2_subbank_idx(struct rvu *rvu, u16 mcam_idx,
struct npc_subbank **sb,
int *sb_off);
+const u32 *npc_cn20k_search_order_get(bool *restricted_order, u32 *sz);
+int npc_cn20k_search_order_set(struct rvu *rvu, u64 arr[32], int cnt);
#endif /* NPC_CN20K_H */
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_devlink.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_devlink.c
index 6494a9ee2f0d..0e8e33c836c9 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_devlink.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_devlink.c
@@ -1258,6 +1258,7 @@ enum rvu_af_dl_param_id {
RVU_AF_DEVLINK_PARAM_ID_NPC_EXACT_FEATURE_DISABLE,
RVU_AF_DEVLINK_PARAM_ID_NPC_DEF_RULE_CNTR_ENABLE,
RVU_AF_DEVLINK_PARAM_ID_NPC_DEFRAG,
+ RVU_AF_DEVLINK_PARAM_ID_NPC_SRCH_ORDER,
RVU_AF_DEVLINK_PARAM_ID_NIX_MAXLF,
};
@@ -1619,12 +1620,83 @@ static int rvu_devlink_eswitch_mode_set(struct devlink *devlink, u16 mode,
return 0;
}
+static int rvu_af_dl_npc_srch_order_set(struct devlink *devlink, u32 id,
+ struct devlink_param_gset_ctx *ctx,
+ struct netlink_ext_ack *extack)
+{
+ struct rvu_devlink *rvu_dl = devlink_priv(devlink);
+ struct rvu *rvu = rvu_dl->rvu;
+
+ return npc_cn20k_search_order_set(rvu,
+ ctx->val.u64arr.val,
+ ctx->val.u64arr.size);
+}
+
+static int rvu_af_dl_npc_srch_order_get(struct devlink *devlink, u32 id,
+ struct devlink_param_gset_ctx *ctx,
+ struct netlink_ext_ack *extack)
+{
+ bool restricted_order;
+ const u32 *order;
+ u32 sz;
+
+ order = npc_cn20k_search_order_get(&restricted_order, &sz);
+ ctx->val.u64arr.size = sz;
+ for (int i = 0; i < sz; i++)
+ ctx->val.u64arr.val[i] = order[i];
+
+ return 0;
+}
+
+static int rvu_af_dl_npc_srch_order_validate(struct devlink *devlink, u32 id,
+ union devlink_param_value val,
+ struct netlink_ext_ack *extack)
+{
+ struct rvu_devlink *rvu_dl = devlink_priv(devlink);
+ struct rvu *rvu = rvu_dl->rvu;
+ bool restricted_order;
+ unsigned long w = 0;
+ u64 *arr;
+ u32 sz;
+
+ npc_cn20k_search_order_get(&restricted_order, &sz);
+ if (sz != val.u64arr.size) {
+ dev_err(rvu->dev,
+ "Wrong size %llu, should be %u\n",
+ val.u64arr.size, sz);
+ return -EINVAL;
+ }
+
+ arr = val.u64arr.val;
+ for (int i = 0; i < sz; i++) {
+ if (arr[i] >= sz)
+ return -EINVAL;
+
+ w |= BIT_ULL(arr[i]);
+ }
+
+ if (bitmap_weight(&w, sz) != sz) {
+ dev_err(rvu->dev,
+ "Duplicate or out-of-range subbank index. %lu\n",
+ find_first_zero_bit(&w, sz));
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static const struct devlink_ops rvu_devlink_ops = {
.eswitch_mode_get = rvu_devlink_eswitch_mode_get,
.eswitch_mode_set = rvu_devlink_eswitch_mode_set,
};
-static const struct devlink_param rvu_af_dl_param_defrag[] = {
+static const struct devlink_param rvu_af_dl_cn20k_params[] = {
+ DEVLINK_PARAM_DRIVER(RVU_AF_DEVLINK_PARAM_ID_NPC_SRCH_ORDER,
+ "npc_srch_order", DEVLINK_PARAM_TYPE_U64_ARRAY,
+ BIT(DEVLINK_PARAM_CMODE_RUNTIME),
+ rvu_af_dl_npc_srch_order_get,
+ rvu_af_dl_npc_srch_order_set,
+ rvu_af_dl_npc_srch_order_validate),
DEVLINK_PARAM_DRIVER(RVU_AF_DEVLINK_PARAM_ID_NPC_DEFRAG,
"npc_defrag", DEVLINK_PARAM_TYPE_STRING,
BIT(DEVLINK_PARAM_CMODE_RUNTIME),
@@ -1666,13 +1738,13 @@ int rvu_register_dl(struct rvu *rvu)
}
if (is_cn20k(rvu->pdev)) {
- err = devlink_params_register(dl, rvu_af_dl_param_defrag,
- ARRAY_SIZE(rvu_af_dl_param_defrag));
+ err = devlink_params_register(dl, rvu_af_dl_cn20k_params,
+ ARRAY_SIZE(rvu_af_dl_cn20k_params));
if (err) {
dev_err(rvu->dev,
- "devlink defrag params register failed with error %d",
+ "devlink cn20k params register failed with error %d",
err);
- goto err_dl_defrag;
+ goto err_dl_cn20k_params;
}
}
@@ -1695,10 +1767,10 @@ int rvu_register_dl(struct rvu *rvu)
err_dl_exact_match:
if (is_cn20k(rvu->pdev))
- devlink_params_unregister(dl, rvu_af_dl_param_defrag,
- ARRAY_SIZE(rvu_af_dl_param_defrag));
+ devlink_params_unregister(dl, rvu_af_dl_cn20k_params,
+ ARRAY_SIZE(rvu_af_dl_cn20k_params));
-err_dl_defrag:
+err_dl_cn20k_params:
devlink_params_unregister(dl, rvu_af_dl_params, ARRAY_SIZE(rvu_af_dl_params));
err_dl_health:
@@ -1717,8 +1789,8 @@ void rvu_unregister_dl(struct rvu *rvu)
devlink_params_unregister(dl, rvu_af_dl_params, ARRAY_SIZE(rvu_af_dl_params));
if (is_cn20k(rvu->pdev))
- devlink_params_unregister(dl, rvu_af_dl_param_defrag,
- ARRAY_SIZE(rvu_af_dl_param_defrag));
+ devlink_params_unregister(dl, rvu_af_dl_cn20k_params,
+ ARRAY_SIZE(rvu_af_dl_cn20k_params));
/* Unregister exact match devlink only for CN10K-B */
if (rvu_npc_exact_has_match_table(rvu))
--
2.43.0
^ permalink raw reply related
* [PATCH v10 net-next 5/6] octeontx2-af: npc: cn20k: dynamically allocate and free default MCAM entries
From: Ratheesh Kannoth @ 2026-04-03 2:55 UTC (permalink / raw)
To: netdev, linux-kernel, linux-rdma
Cc: sgoutham, andrew+netdev, davem, edumazet, kuba, pabeni,
donald.hunter, horms, jiri, chuck.lever, matttbe, cjubran, saeedm,
leon, tariqt, mbloch, dtatulea, Ratheesh Kannoth
In-Reply-To: <20260403025533.6250-1-rkannoth@marvell.com>
Improve MCAM utilization by tying default (broadcast, multicast,
promisc, ucast) entry lifetime to NIX LF usage.
- On NIX LF alloc (e.g. kernel or DPDK), allocate default MCAM entries
if missing; on NIX LF free, release them so they return to the pool.
- Add NIX_LF_DONT_FREE_DFT_IDXS so the kernel PF driver can free the
NIX LF without releasing default entries (e.g. across suspend/resume).
- When NIX LF is used by DPDK, default entries are allocated on first
use and freed when the LF is released if NIX_LF_DONT_FREE_DFT_IDXS is
not set
Signed-off-by: Ratheesh Kannoth <rkannoth@marvell.com>
---
.../ethernet/marvell/octeontx2/af/cn20k/npc.c | 108 ++++++++++-----
.../ethernet/marvell/octeontx2/af/cn20k/npc.h | 1 +
.../net/ethernet/marvell/octeontx2/af/mbox.h | 1 +
.../ethernet/marvell/octeontx2/af/rvu_nix.c | 69 ++++++----
.../ethernet/marvell/octeontx2/af/rvu_npc.c | 125 +++++++++++++-----
.../ethernet/marvell/octeontx2/nic/otx2_pf.c | 4 +-
6 files changed, 218 insertions(+), 90 deletions(-)
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c
index 153765b3e504..69439ff76e10 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.c
@@ -808,6 +808,11 @@ npc_cn20k_enable_mcam_entry(struct rvu *rvu, int blkaddr,
u64 cfg, hw_prio;
u8 kw_type;
+ if (index < 0 || index >= mcam->total_entries) {
+ WARN(1, "Wrong mcam index %d\n", index);
+ return;
+ }
+
enable ? set_bit(index, npc_priv.en_map) :
clear_bit(index, npc_priv.en_map);
@@ -1053,6 +1058,11 @@ void npc_cn20k_config_mcam_entry(struct rvu *rvu, int blkaddr, int index,
int kw = 0;
u8 kw_type;
+ if (index < 0 || index >= mcam->total_entries) {
+ WARN(1, "Wrong mcam index %d\n", index);
+ return;
+ }
+
/* Disable before mcam entry update */
npc_cn20k_enable_mcam_entry(rvu, blkaddr, index, false);
@@ -1132,6 +1142,11 @@ void npc_cn20k_copy_mcam_entry(struct rvu *rvu, int blkaddr, u16 src, u16 dest)
int bank, i, sb, db;
int dbank, sbank;
+ if (src >= mcam->total_entries || dest >= mcam->total_entries) {
+ WARN(1, "Wrong mcam index src=%u dest=%u\n", src, dest);
+ return;
+ }
+
dbank = npc_get_bank(mcam, dest);
sbank = npc_get_bank(mcam, src);
npc_mcam_idx_2_key_type(rvu, src, &src_kwtype);
@@ -1190,11 +1205,24 @@ void npc_cn20k_read_mcam_entry(struct rvu *rvu, int blkaddr, u16 index,
int kw = 0, bank;
u8 kw_type;
+ if (index >= mcam->total_entries) {
+ WARN(1, "Wrong mcam index %u\n", index);
+ return;
+ }
+
npc_mcam_idx_2_key_type(rvu, index, &kw_type);
bank = npc_get_bank(mcam, index);
index &= (mcam->banksize - 1);
+ cfg = rvu_read64(rvu, blkaddr,
+ NPC_AF_CN20K_MCAMEX_BANKX_ACTIONX_EXT(index, bank, 0));
+ entry->action = cfg;
+
+ cfg = rvu_read64(rvu, blkaddr,
+ NPC_AF_CN20K_MCAMEX_BANKX_ACTIONX_EXT(index, bank, 1));
+ entry->vtag_action = cfg;
+
cfg = rvu_read64(rvu, blkaddr,
NPC_AF_CN20K_MCAMEX_BANKX_CAMX_INTF_EXT(index,
bank, 1)) & 3;
@@ -1244,7 +1272,7 @@ void npc_cn20k_read_mcam_entry(struct rvu *rvu, int blkaddr, u16 index,
bank,
0));
npc_cn20k_fill_entryword(entry, kw + 3, cam0, cam1);
- goto read_action;
+ return;
}
for (bank = 0; bank < mcam->banks_per_entry; bank++, kw = kw + 4) {
@@ -1289,17 +1317,6 @@ void npc_cn20k_read_mcam_entry(struct rvu *rvu, int blkaddr, u16 index,
npc_cn20k_fill_entryword(entry, kw + 3, cam0, cam1);
}
-read_action:
- /* 'action' is set to same value for both bank '0' and '1'.
- * Hence, reading bank '0' should be enough.
- */
- cfg = rvu_read64(rvu, blkaddr,
- NPC_AF_CN20K_MCAMEX_BANKX_ACTIONX_EXT(index, 0, 0));
- entry->action = cfg;
-
- cfg = rvu_read64(rvu, blkaddr,
- NPC_AF_CN20K_MCAMEX_BANKX_ACTIONX_EXT(index, 0, 1));
- entry->vtag_action = cfg;
}
int rvu_mbox_handler_npc_cn20k_mcam_write_entry(struct rvu *rvu,
@@ -1671,8 +1688,8 @@ int npc_mcam_idx_2_key_type(struct rvu *rvu, u16 mcam_idx, u8 *key_type)
/* mcam_idx should be less than (2 * bank depth) */
if (mcam_idx >= npc_priv.bank_depth * 2) {
- dev_err(rvu->dev, "%s: bad params\n",
- __func__);
+ dev_err(rvu->dev, "%s: bad params mcam_idx=%u\n",
+ __func__, mcam_idx);
return -EINVAL;
}
@@ -4024,6 +4041,13 @@ int npc_cn20k_dft_rules_idx_get(struct rvu *rvu, u16 pcifunc, u16 *bcast,
void *val;
int i, j;
+ for (int i = 0; i < ARRAY_SIZE(ptr); i++) {
+ if (!ptr[i])
+ continue;
+
+ *ptr[i] = USHRT_MAX;
+ }
+
if (!npc_priv.init_done)
return 0;
@@ -4039,7 +4063,6 @@ int npc_cn20k_dft_rules_idx_get(struct rvu *rvu, u16 pcifunc, u16 *bcast,
npc_dft_rule_name[NPC_DFT_RULE_PROMISC_ID],
pcifunc);
- *ptr[0] = USHRT_MAX;
return -ESRCH;
}
@@ -4059,7 +4082,6 @@ int npc_cn20k_dft_rules_idx_get(struct rvu *rvu, u16 pcifunc, u16 *bcast,
npc_dft_rule_name[NPC_DFT_RULE_UCAST_ID],
pcifunc);
- *ptr[3] = USHRT_MAX;
return -ESRCH;
}
@@ -4079,7 +4101,6 @@ int npc_cn20k_dft_rules_idx_get(struct rvu *rvu, u16 pcifunc, u16 *bcast,
__func__,
npc_dft_rule_name[i], pcifunc);
- *ptr[j] = USHRT_MAX;
continue;
}
@@ -4174,7 +4195,7 @@ int rvu_mbox_handler_npc_get_dft_rl_idxs(struct rvu *rvu, struct msg_req *req,
return 0;
}
-static bool npc_is_cgx_or_lbk(struct rvu *rvu, u16 pcifunc)
+bool npc_is_cgx_or_lbk(struct rvu *rvu, u16 pcifunc)
{
return is_pf_cgxmapped(rvu, rvu_get_pf(rvu->pdev, pcifunc)) ||
is_lbk_vf(rvu, pcifunc);
@@ -4182,9 +4203,10 @@ static bool npc_is_cgx_or_lbk(struct rvu *rvu, u16 pcifunc)
void npc_cn20k_dft_rules_free(struct rvu *rvu, u16 pcifunc)
{
- struct npc_mcam_free_entry_req free_req = { 0 };
+ struct npc_mcam *mcam = &rvu->hw->mcam;
+ struct rvu_npc_mcam_rule *rule, *tmp;
unsigned long index;
- struct msg_rsp rsp;
+ int blkaddr;
u16 ptr[4];
int rc, i;
void *map;
@@ -4209,7 +4231,7 @@ void npc_cn20k_dft_rules_free(struct rvu *rvu, u16 pcifunc)
index = NPC_DFT_RULE_ID_MK(pcifunc, NPC_DFT_RULE_PROMISC_ID);
map = xa_erase(&npc_priv.xa_pf2dfl_rmap, index);
if (!map)
- dev_dbg(rvu->dev,
+ dev_err(rvu->dev,
"%s: Err from delete %s mcam idx from xarray (pcifunc=%#x\n",
__func__,
npc_dft_rule_name[NPC_DFT_RULE_PROMISC_ID],
@@ -4223,7 +4245,7 @@ void npc_cn20k_dft_rules_free(struct rvu *rvu, u16 pcifunc)
index = NPC_DFT_RULE_ID_MK(pcifunc, NPC_DFT_RULE_UCAST_ID);
map = xa_erase(&npc_priv.xa_pf2dfl_rmap, index);
if (!map)
- dev_dbg(rvu->dev,
+ dev_err(rvu->dev,
"%s: Err from delete %s mcam idx from xarray (pcifunc=%#x\n",
__func__,
npc_dft_rule_name[NPC_DFT_RULE_UCAST_ID],
@@ -4237,21 +4259,47 @@ void npc_cn20k_dft_rules_free(struct rvu *rvu, u16 pcifunc)
index = NPC_DFT_RULE_ID_MK(pcifunc, i);
map = xa_erase(&npc_priv.xa_pf2dfl_rmap, index);
if (!map)
- dev_dbg(rvu->dev,
+ dev_err(rvu->dev,
"%s: Err from delete %s mcam idx from xarray (pcifunc=%#x\n",
__func__, npc_dft_rule_name[i],
pcifunc);
}
free_rules:
+ blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPC, 0);
+ if (blkaddr < 0)
+ return;
- free_req.hdr.pcifunc = pcifunc;
- free_req.all = 1;
- rc = rvu_mbox_handler_npc_mcam_free_entry(rvu, &free_req, &rsp);
- if (rc)
- dev_err(rvu->dev,
- "%s: Error deleting default entries (pcifunc=%#x\n",
- __func__, pcifunc);
+ for (int i = 0; i < 4; i++) {
+ if (ptr[i] == USHRT_MAX)
+ continue;
+
+ mutex_lock(&mcam->lock);
+ npc_mcam_clear_bit(mcam, ptr[i]);
+ mcam->entry2pfvf_map[ptr[i]] = NPC_MCAM_INVALID_MAP;
+ npc_cn20k_enable_mcam_entry(rvu, blkaddr, ptr[i], false);
+ mcam->entry2target_pffunc[ptr[i]] = 0x0;
+ mutex_unlock(&mcam->lock);
+
+ rc = npc_cn20k_idx_free(rvu, &ptr[i], 1);
+ if (rc)
+ dev_err(rvu->dev,
+ "%s:%d Error deleting default entries (pcifunc=%#x) mcam_idx=%u\n",
+ __func__, __LINE__, pcifunc, ptr[i]);
+ }
+
+ mutex_lock(&mcam->lock);
+ list_for_each_entry_safe(rule, tmp, &mcam->mcam_rules, list) {
+ for (int i = 0; i < 4; i++) {
+ if (ptr[i] != rule->entry)
+ continue;
+
+ list_del(&rule->list);
+ kfree(rule);
+ break;
+ }
+ }
+ mutex_unlock(&mcam->lock);
}
int npc_cn20k_dft_rules_alloc(struct rvu *rvu, u16 pcifunc)
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.h b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.h
index 6f9f796940f3..1b4b4a6fa378 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.h
+++ b/drivers/net/ethernet/marvell/octeontx2/af/cn20k/npc.h
@@ -345,5 +345,6 @@ int npc_mcam_idx_2_subbank_idx(struct rvu *rvu, u16 mcam_idx,
int *sb_off);
const u32 *npc_cn20k_search_order_get(bool *restricted_order, u32 *sz);
int npc_cn20k_search_order_set(struct rvu *rvu, u64 arr[32], int cnt);
+bool npc_is_cgx_or_lbk(struct rvu *rvu, u16 pcifunc);
#endif /* NPC_CN20K_H */
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h
index dc42c81c0942..e07fbf842b94 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/mbox.h
+++ b/drivers/net/ethernet/marvell/octeontx2/af/mbox.h
@@ -1009,6 +1009,7 @@ struct nix_lf_free_req {
struct mbox_msghdr hdr;
#define NIX_LF_DISABLE_FLOWS BIT_ULL(0)
#define NIX_LF_DONT_FREE_TX_VTAG BIT_ULL(1)
+#define NIX_LF_DONT_FREE_DFT_IDXS BIT_ULL(2)
u64 flags;
};
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c
index ef5b081162eb..584e98e25f11 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c
@@ -16,6 +16,7 @@
#include "cgx.h"
#include "lmac_common.h"
#include "rvu_npc_hash.h"
+#include "cn20k/npc.h"
static void nix_free_tx_vtag_entries(struct rvu *rvu, u16 pcifunc);
static int rvu_nix_get_bpid(struct rvu *rvu, struct nix_bp_cfg_req *req,
@@ -1499,7 +1500,7 @@ int rvu_mbox_handler_nix_lf_alloc(struct rvu *rvu,
struct nix_lf_alloc_req *req,
struct nix_lf_alloc_rsp *rsp)
{
- int nixlf, qints, hwctx_size, intf, err, rc = 0;
+ int nixlf, qints, hwctx_size, intf, rc = 0;
struct rvu_hwinfo *hw = rvu->hw;
u16 pcifunc = req->hdr.pcifunc;
struct rvu_block *block;
@@ -1555,8 +1556,8 @@ int rvu_mbox_handler_nix_lf_alloc(struct rvu *rvu,
return NIX_AF_ERR_RSS_GRPS_INVALID;
/* Reset this NIX LF */
- err = rvu_lf_reset(rvu, block, nixlf);
- if (err) {
+ rc = rvu_lf_reset(rvu, block, nixlf);
+ if (rc) {
dev_err(rvu->dev, "Failed to reset NIX%d LF%d\n",
block->addr - BLKADDR_NIX0, nixlf);
return NIX_AF_ERR_LF_RESET;
@@ -1566,13 +1567,15 @@ int rvu_mbox_handler_nix_lf_alloc(struct rvu *rvu,
/* Alloc NIX RQ HW context memory and config the base */
hwctx_size = 1UL << ((ctx_cfg >> 4) & 0xF);
- err = qmem_alloc(rvu->dev, &pfvf->rq_ctx, req->rq_cnt, hwctx_size);
- if (err)
+ rc = qmem_alloc(rvu->dev, &pfvf->rq_ctx, req->rq_cnt, hwctx_size);
+ if (rc)
goto free_mem;
pfvf->rq_bmap = kcalloc(req->rq_cnt, sizeof(long), GFP_KERNEL);
- if (!pfvf->rq_bmap)
+ if (!pfvf->rq_bmap) {
+ rc = -ENOMEM;
goto free_mem;
+ }
rvu_write64(rvu, blkaddr, NIX_AF_LFX_RQS_BASE(nixlf),
(u64)pfvf->rq_ctx->iova);
@@ -1583,13 +1586,15 @@ int rvu_mbox_handler_nix_lf_alloc(struct rvu *rvu,
/* Alloc NIX SQ HW context memory and config the base */
hwctx_size = 1UL << (ctx_cfg & 0xF);
- err = qmem_alloc(rvu->dev, &pfvf->sq_ctx, req->sq_cnt, hwctx_size);
- if (err)
+ rc = qmem_alloc(rvu->dev, &pfvf->sq_ctx, req->sq_cnt, hwctx_size);
+ if (rc)
goto free_mem;
pfvf->sq_bmap = kcalloc(req->sq_cnt, sizeof(long), GFP_KERNEL);
- if (!pfvf->sq_bmap)
+ if (!pfvf->sq_bmap) {
+ rc = -ENOMEM;
goto free_mem;
+ }
rvu_write64(rvu, blkaddr, NIX_AF_LFX_SQS_BASE(nixlf),
(u64)pfvf->sq_ctx->iova);
@@ -1599,13 +1604,15 @@ int rvu_mbox_handler_nix_lf_alloc(struct rvu *rvu,
/* Alloc NIX CQ HW context memory and config the base */
hwctx_size = 1UL << ((ctx_cfg >> 8) & 0xF);
- err = qmem_alloc(rvu->dev, &pfvf->cq_ctx, req->cq_cnt, hwctx_size);
- if (err)
+ rc = qmem_alloc(rvu->dev, &pfvf->cq_ctx, req->cq_cnt, hwctx_size);
+ if (rc)
goto free_mem;
pfvf->cq_bmap = kcalloc(req->cq_cnt, sizeof(long), GFP_KERNEL);
- if (!pfvf->cq_bmap)
+ if (!pfvf->cq_bmap) {
+ rc = -ENOMEM;
goto free_mem;
+ }
rvu_write64(rvu, blkaddr, NIX_AF_LFX_CQS_BASE(nixlf),
(u64)pfvf->cq_ctx->iova);
@@ -1615,18 +1622,18 @@ int rvu_mbox_handler_nix_lf_alloc(struct rvu *rvu,
/* Initialize receive side scaling (RSS) */
hwctx_size = 1UL << ((ctx_cfg >> 12) & 0xF);
- err = nixlf_rss_ctx_init(rvu, blkaddr, pfvf, nixlf, req->rss_sz,
- req->rss_grps, hwctx_size, req->way_mask,
- !!(req->flags & NIX_LF_RSS_TAG_LSB_AS_ADDER));
- if (err)
+ rc = nixlf_rss_ctx_init(rvu, blkaddr, pfvf, nixlf, req->rss_sz,
+ req->rss_grps, hwctx_size, req->way_mask,
+ !!(req->flags & NIX_LF_RSS_TAG_LSB_AS_ADDER));
+ if (rc)
goto free_mem;
/* Alloc memory for CQINT's HW contexts */
cfg = rvu_read64(rvu, blkaddr, NIX_AF_CONST2);
qints = (cfg >> 24) & 0xFFF;
hwctx_size = 1UL << ((ctx_cfg >> 24) & 0xF);
- err = qmem_alloc(rvu->dev, &pfvf->cq_ints_ctx, qints, hwctx_size);
- if (err)
+ rc = qmem_alloc(rvu->dev, &pfvf->cq_ints_ctx, qints, hwctx_size);
+ if (rc)
goto free_mem;
rvu_write64(rvu, blkaddr, NIX_AF_LFX_CINTS_BASE(nixlf),
@@ -1639,8 +1646,8 @@ int rvu_mbox_handler_nix_lf_alloc(struct rvu *rvu,
cfg = rvu_read64(rvu, blkaddr, NIX_AF_CONST2);
qints = (cfg >> 12) & 0xFFF;
hwctx_size = 1UL << ((ctx_cfg >> 20) & 0xF);
- err = qmem_alloc(rvu->dev, &pfvf->nix_qints_ctx, qints, hwctx_size);
- if (err)
+ rc = qmem_alloc(rvu->dev, &pfvf->nix_qints_ctx, qints, hwctx_size);
+ if (rc)
goto free_mem;
rvu_write64(rvu, blkaddr, NIX_AF_LFX_QINTS_BASE(nixlf),
@@ -1684,10 +1691,16 @@ int rvu_mbox_handler_nix_lf_alloc(struct rvu *rvu,
if (is_sdp_pfvf(rvu, pcifunc))
intf = NIX_INTF_TYPE_SDP;
- err = nix_interface_init(rvu, pcifunc, intf, nixlf, rsp,
- !!(req->flags & NIX_LF_LBK_BLK_SEL));
- if (err)
- goto free_mem;
+ if (is_cn20k(rvu->pdev)) {
+ rc = npc_cn20k_dft_rules_alloc(rvu, pcifunc);
+ if (rc)
+ goto free_mem;
+ }
+
+ rc = nix_interface_init(rvu, pcifunc, intf, nixlf, rsp,
+ !!(req->flags & NIX_LF_LBK_BLK_SEL));
+ if (rc)
+ goto free_dft;
/* Disable NPC entries as NIXLF's contexts are not initialized yet */
rvu_npc_disable_default_entries(rvu, pcifunc, nixlf);
@@ -1699,9 +1712,12 @@ int rvu_mbox_handler_nix_lf_alloc(struct rvu *rvu,
goto exit;
+free_dft:
+ if (is_cn20k(rvu->pdev))
+ npc_cn20k_dft_rules_free(rvu, pcifunc);
+
free_mem:
nix_ctx_free(rvu, pfvf);
- rc = -ENOMEM;
exit:
/* Set macaddr of this PF/VF */
@@ -1775,6 +1791,9 @@ int rvu_mbox_handler_nix_lf_free(struct rvu *rvu, struct nix_lf_free_req *req,
nix_ctx_free(rvu, pfvf);
+ if (is_cn20k(rvu->pdev) && !(req->flags & NIX_LF_DONT_FREE_DFT_IDXS))
+ npc_cn20k_dft_rules_free(rvu, pcifunc);
+
return 0;
}
diff --git a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c
index c2ca5ed1d028..8d260bcfbf38 100644
--- a/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c
+++ b/drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c
@@ -165,12 +165,20 @@ int npc_get_nixlf_mcam_index(struct npc_mcam *mcam,
switch (type) {
case NIXLF_BCAST_ENTRY:
+ if (bcast == USHRT_MAX)
+ return -EINVAL;
return bcast;
case NIXLF_ALLMULTI_ENTRY:
+ if (mcast == USHRT_MAX)
+ return -EINVAL;
return mcast;
case NIXLF_PROMISC_ENTRY:
+ if (promisc == USHRT_MAX)
+ return -EINVAL;
return promisc;
case NIXLF_UCAST_ENTRY:
+ if (ucast == USHRT_MAX)
+ return -EINVAL;
return ucast;
default:
return -EINVAL;
@@ -237,12 +245,8 @@ void npc_enable_mcam_entry(struct rvu *rvu, struct npc_mcam *mcam,
int bank = npc_get_bank(mcam, index);
int actbank = bank;
- if (is_cn20k(rvu->pdev)) {
- if (index < 0 || index >= mcam->banksize * mcam->banks)
- return;
-
+ if (is_cn20k(rvu->pdev))
return npc_cn20k_enable_mcam_entry(rvu, blkaddr, index, enable);
- }
index &= (mcam->banksize - 1);
for (; bank < (actbank + mcam->banks_per_entry); bank++) {
@@ -1113,7 +1117,7 @@ void rvu_npc_update_flowkey_alg_idx(struct rvu *rvu, u16 pcifunc, int nixlf,
index = mcam_index;
}
- if (index >= mcam->total_entries)
+ if (index < 0 || index >= mcam->total_entries)
return;
bank = npc_get_bank(mcam, index);
@@ -1158,16 +1162,18 @@ void rvu_npc_update_flowkey_alg_idx(struct rvu *rvu, u16 pcifunc, int nixlf,
/* If PF's promiscuous entry is enabled,
* Set RSS action for that entry as well
*/
- npc_update_rx_action_with_alg_idx(rvu, action, pfvf, index,
- blkaddr, alg_idx);
+ if (index >= 0)
+ npc_update_rx_action_with_alg_idx(rvu, action, pfvf,
+ index, blkaddr, alg_idx);
index = npc_get_nixlf_mcam_index(mcam, pcifunc,
nixlf, NIXLF_ALLMULTI_ENTRY);
/* If PF's allmulti entry is enabled,
* Set RSS action for that entry as well
*/
- npc_update_rx_action_with_alg_idx(rvu, action, pfvf, index,
- blkaddr, alg_idx);
+ if (index >= 0)
+ npc_update_rx_action_with_alg_idx(rvu, action, pfvf,
+ index, blkaddr, alg_idx);
}
}
@@ -1212,8 +1218,13 @@ static void npc_enadis_default_entries(struct rvu *rvu, u16 pcifunc,
{
struct rvu_pfvf *pfvf = rvu_get_pfvf(rvu, pcifunc);
struct npc_mcam *mcam = &rvu->hw->mcam;
+ int type = NIXLF_UCAST_ENTRY;
int index, blkaddr;
+ /* only CGX or LBK interfaces have default entries */
+ if (is_cn20k(rvu->pdev) && !npc_is_cgx_or_lbk(rvu, pcifunc))
+ return;
+
blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPC, 0);
if (blkaddr < 0)
return;
@@ -1221,8 +1232,11 @@ static void npc_enadis_default_entries(struct rvu *rvu, u16 pcifunc,
/* Ucast MCAM match entry of this PF/VF */
if (npc_is_feature_supported(rvu, BIT_ULL(NPC_DMAC),
pfvf->nix_rx_intf)) {
+ if (is_cn20k(rvu->pdev) && is_lbk_vf(rvu, pcifunc))
+ type = NIXLF_PROMISC_ENTRY;
+
index = npc_get_nixlf_mcam_index(mcam, pcifunc,
- nixlf, NIXLF_UCAST_ENTRY);
+ nixlf, type);
npc_enable_mcam_entry(rvu, mcam, blkaddr, index, enable);
}
@@ -1232,9 +1246,13 @@ static void npc_enadis_default_entries(struct rvu *rvu, u16 pcifunc,
if ((pcifunc & RVU_PFVF_FUNC_MASK) && !rvu->hw->cap.nix_rx_multicast)
return;
+ type = NIXLF_BCAST_ENTRY;
+ if (is_cn20k(rvu->pdev) && is_lbk_vf(rvu, pcifunc))
+ type = NIXLF_PROMISC_ENTRY;
+
/* add/delete pf_func to broadcast MCE list */
npc_enadis_default_mce_entry(rvu, pcifunc, nixlf,
- NIXLF_BCAST_ENTRY, enable);
+ type, enable);
}
void rvu_npc_disable_default_entries(struct rvu *rvu, u16 pcifunc, int nixlf)
@@ -1244,6 +1262,9 @@ void rvu_npc_disable_default_entries(struct rvu *rvu, u16 pcifunc, int nixlf)
npc_enadis_default_entries(rvu, pcifunc, nixlf, false);
+ if (is_cn20k(rvu->pdev) && is_vf(pcifunc))
+ return;
+
/* Delete multicast and promisc MCAM entries */
npc_enadis_default_mce_entry(rvu, pcifunc, nixlf,
NIXLF_ALLMULTI_ENTRY, false);
@@ -1301,6 +1322,10 @@ void rvu_npc_disable_mcam_entries(struct rvu *rvu, u16 pcifunc, int nixlf)
if (blkaddr < 0)
return;
+ /* only CGX or LBK interfaces have default entries */
+ if (is_cn20k(rvu->pdev) && !npc_is_cgx_or_lbk(rvu, pcifunc))
+ return;
+
mutex_lock(&mcam->lock);
/* Disable MCAM entries directing traffic to this 'pcifunc' */
@@ -2504,33 +2529,58 @@ void npc_mcam_clear_bit(struct npc_mcam *mcam, u16 index)
static void npc_mcam_free_all_entries(struct rvu *rvu, struct npc_mcam *mcam,
int blkaddr, u16 pcifunc)
{
+ u16 dft_idxs[NPC_DFT_RULE_MAX_ID] = {[0 ... NPC_DFT_RULE_MAX_ID - 1] = USHRT_MAX};
u16 index, cntr;
+ bool dft_rl;
int rc;
+ npc_cn20k_dft_rules_idx_get(rvu, pcifunc,
+ &dft_idxs[NPC_DFT_RULE_BCAST_ID],
+ &dft_idxs[NPC_DFT_RULE_MCAST_ID],
+ &dft_idxs[NPC_DFT_RULE_PROMISC_ID],
+ &dft_idxs[NPC_DFT_RULE_UCAST_ID]);
+
/* Scan all MCAM entries and free the ones mapped to 'pcifunc' */
for (index = 0; index < mcam->bmap_entries; index++) {
- if (mcam->entry2pfvf_map[index] == pcifunc) {
- mcam->entry2pfvf_map[index] = NPC_MCAM_INVALID_MAP;
- /* Free the entry in bitmap */
- npc_mcam_clear_bit(mcam, index);
- /* Disable the entry */
- npc_enable_mcam_entry(rvu, mcam, blkaddr, index, false);
-
- /* Update entry2counter mapping */
- cntr = mcam->entry2cntr_map[index];
- if (cntr != NPC_MCAM_INVALID_MAP)
- npc_unmap_mcam_entry_and_cntr(rvu, mcam,
- blkaddr, index,
- cntr);
- mcam->entry2target_pffunc[index] = 0x0;
- if (is_cn20k(rvu->pdev)) {
- rc = npc_cn20k_idx_free(rvu, &index, 1);
- if (rc)
- dev_err(rvu->dev,
- "Failed to free mcam idx=%u pcifunc=%#x\n",
- index, pcifunc);
+ if (mcam->entry2pfvf_map[index] != pcifunc)
+ continue;
+
+ mcam->entry2pfvf_map[index] = NPC_MCAM_INVALID_MAP;
+
+ dft_rl = false;
+ if (is_cn20k(rvu->pdev)) {
+ if (dft_idxs[NPC_DFT_RULE_BCAST_ID] == index ||
+ dft_idxs[NPC_DFT_RULE_MCAST_ID] == index ||
+ dft_idxs[NPC_DFT_RULE_PROMISC_ID] == index ||
+ dft_idxs[NPC_DFT_RULE_UCAST_ID] == index) {
+ dft_rl = true;
}
}
+
+ /* Free the entry in bitmap.*/
+ if (!dft_rl)
+ npc_mcam_clear_bit(mcam, index);
+
+ /* Disable the entry */
+ npc_enable_mcam_entry(rvu, mcam, blkaddr, index, false);
+
+ /* Update entry2counter mapping */
+ cntr = mcam->entry2cntr_map[index];
+ if (cntr != NPC_MCAM_INVALID_MAP)
+ npc_unmap_mcam_entry_and_cntr(rvu, mcam,
+ blkaddr, index,
+ cntr);
+ mcam->entry2target_pffunc[index] = 0x0;
+ if (is_cn20k(rvu->pdev)) {
+ if (dft_rl)
+ continue;
+
+ rc = npc_cn20k_idx_free(rvu, &index, 1);
+ if (rc)
+ dev_err(rvu->dev,
+ "Failed to free mcam idx=%u pcifunc=%#x\n",
+ index, pcifunc);
+ }
}
}
@@ -3917,13 +3967,22 @@ void rvu_npc_clear_ucast_entry(struct rvu *rvu, int pcifunc, int nixlf)
struct npc_mcam *mcam = &rvu->hw->mcam;
struct rvu_npc_mcam_rule *rule;
int ucast_idx, blkaddr;
+ u8 type;
blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPC, 0);
if (blkaddr < 0)
return;
+ type = NIXLF_UCAST_ENTRY;
+ if (is_cn20k(rvu->pdev) && is_lbk_vf(rvu, pcifunc))
+ type = NIXLF_PROMISC_ENTRY;
+
ucast_idx = npc_get_nixlf_mcam_index(mcam, pcifunc,
- nixlf, NIXLF_UCAST_ENTRY);
+ nixlf, type);
+
+ /* In cn20k, default rules are freed before detach rsrc */
+ if (ucast_idx < 0)
+ return;
npc_enable_mcam_entry(rvu, mcam, blkaddr, ucast_idx, false);
diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c
index ee623476e5ff..366850742862 100644
--- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c
+++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c
@@ -1729,7 +1729,7 @@ int otx2_init_hw_resources(struct otx2_nic *pf)
mutex_lock(&mbox->lock);
free_req = otx2_mbox_alloc_msg_nix_lf_free(mbox);
if (free_req) {
- free_req->flags = NIX_LF_DISABLE_FLOWS;
+ free_req->flags = NIX_LF_DISABLE_FLOWS | NIX_LF_DONT_FREE_DFT_IDXS;
if (otx2_sync_mbox_msg(mbox))
dev_err(pf->dev, "%s failed to free nixlf\n", __func__);
}
@@ -1803,7 +1803,7 @@ void otx2_free_hw_resources(struct otx2_nic *pf)
/* Reset NIX LF */
free_req = otx2_mbox_alloc_msg_nix_lf_free(mbox);
if (free_req) {
- free_req->flags = NIX_LF_DISABLE_FLOWS;
+ free_req->flags = NIX_LF_DISABLE_FLOWS | NIX_LF_DONT_FREE_DFT_IDXS;
if (!(pf->flags & OTX2_FLAG_PF_SHUTDOWN))
free_req->flags |= NIX_LF_DONT_FREE_TX_VTAG;
if (otx2_sync_mbox_msg(mbox))
--
2.43.0
^ 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