* [PATCH v9 net-next 1/5] psp: add admin/non-admin version of psp_device_get_locked
From: Wei Wang @ 2026-03-30 22:31 UTC (permalink / raw)
To: netdev, Jakub Kicinski, Daniel Zahka, Willem de Bruijn, David Wei,
Andrew Lunn, David S . Miller, Eric Dumazet, Simon Horman
Cc: Wei Wang
In-Reply-To: <20260330223143.2394706-1-weibunny.kernel@gmail.com>
From: Wei Wang <weibunny@fb.com>
Introduce 2 versions of psp_device_get_locked:
1. psp_device_get_locked_admin(): This version is used for operations
that would change the status of the psd, and are currently used for
dev-set nad key-rotation.
2. psp_device_get_locked(): This is the non-admin version, which are
used for broader user issued operations including: dev-get, rx-assoc,
tx-assoc, get-stats.
Following commit will be implementing both of the checks.
Signed-off-by: Wei Wang <weibunny@fb.com>
---
Documentation/netlink/specs/psp.yaml | 4 ++--
net/psp/psp-nl-gen.c | 4 ++--
net/psp/psp-nl-gen.h | 2 ++
net/psp/psp.h | 2 +-
net/psp/psp_main.c | 7 +++++-
net/psp/psp_nl.c | 33 ++++++++++++++++++++--------
6 files changed, 37 insertions(+), 15 deletions(-)
diff --git a/Documentation/netlink/specs/psp.yaml b/Documentation/netlink/specs/psp.yaml
index f3a57782d2cf..fe2cdc966604 100644
--- a/Documentation/netlink/specs/psp.yaml
+++ b/Documentation/netlink/specs/psp.yaml
@@ -195,7 +195,7 @@ operations:
- psp-versions-ena
reply:
attributes: []
- pre: psp-device-get-locked
+ pre: psp-device-get-locked-admin
post: psp-device-unlock
-
name: dev-change-ntf
@@ -214,7 +214,7 @@ operations:
reply:
attributes:
- id
- pre: psp-device-get-locked
+ pre: psp-device-get-locked-admin
post: psp-device-unlock
-
name: key-rotate-ntf
diff --git a/net/psp/psp-nl-gen.c b/net/psp/psp-nl-gen.c
index 22a48d0fa378..1f5e73e7ccc1 100644
--- a/net/psp/psp-nl-gen.c
+++ b/net/psp/psp-nl-gen.c
@@ -71,7 +71,7 @@ static const struct genl_split_ops psp_nl_ops[] = {
},
{
.cmd = PSP_CMD_DEV_SET,
- .pre_doit = psp_device_get_locked,
+ .pre_doit = psp_device_get_locked_admin,
.doit = psp_nl_dev_set_doit,
.post_doit = psp_device_unlock,
.policy = psp_dev_set_nl_policy,
@@ -80,7 +80,7 @@ static const struct genl_split_ops psp_nl_ops[] = {
},
{
.cmd = PSP_CMD_KEY_ROTATE,
- .pre_doit = psp_device_get_locked,
+ .pre_doit = psp_device_get_locked_admin,
.doit = psp_nl_key_rotate_doit,
.post_doit = psp_device_unlock,
.policy = psp_key_rotate_nl_policy,
diff --git a/net/psp/psp-nl-gen.h b/net/psp/psp-nl-gen.h
index 599c5f1c82f2..977355455395 100644
--- a/net/psp/psp-nl-gen.h
+++ b/net/psp/psp-nl-gen.h
@@ -17,6 +17,8 @@ extern const struct nla_policy psp_keys_nl_policy[PSP_A_KEYS_SPI + 1];
int psp_device_get_locked(const struct genl_split_ops *ops,
struct sk_buff *skb, struct genl_info *info);
+int psp_device_get_locked_admin(const struct genl_split_ops *ops,
+ struct sk_buff *skb, struct genl_info *info);
int psp_assoc_device_get_locked(const struct genl_split_ops *ops,
struct sk_buff *skb, struct genl_info *info);
void
diff --git a/net/psp/psp.h b/net/psp/psp.h
index 9f19137593a0..0f9c4e4e52cb 100644
--- a/net/psp/psp.h
+++ b/net/psp/psp.h
@@ -14,7 +14,7 @@ extern struct xarray psp_devs;
extern struct mutex psp_devs_lock;
void psp_dev_free(struct psp_dev *psd);
-int psp_dev_check_access(struct psp_dev *psd, struct net *net);
+int psp_dev_check_access(struct psp_dev *psd, struct net *net, bool admin);
void psp_nl_notify_dev(struct psp_dev *psd, u32 cmd);
diff --git a/net/psp/psp_main.c b/net/psp/psp_main.c
index 9508b6c38003..82de78a1d6bd 100644
--- a/net/psp/psp_main.c
+++ b/net/psp/psp_main.c
@@ -27,10 +27,15 @@ struct mutex psp_devs_lock;
* psp_dev_check_access() - check if user in a given net ns can access PSP dev
* @psd: PSP device structure user is trying to access
* @net: net namespace user is in
+ * @admin: If true, only allow access from @psd's main device's netns,
+ * for admin operations like config changes and key rotation.
+ * If false, also allow access from network namespaces that have
+ * an associated device with @psd, for read-only and association
+ * management operations.
*
* Return: 0 if PSP device should be visible in @net, errno otherwise.
*/
-int psp_dev_check_access(struct psp_dev *psd, struct net *net)
+int psp_dev_check_access(struct psp_dev *psd, struct net *net, bool admin)
{
if (dev_net(psd->main_netdev) == net)
return 0;
diff --git a/net/psp/psp_nl.c b/net/psp/psp_nl.c
index 6afd7707ec12..eb47a9ee4438 100644
--- a/net/psp/psp_nl.c
+++ b/net/psp/psp_nl.c
@@ -41,7 +41,8 @@ static int psp_nl_reply_send(struct sk_buff *rsp, struct genl_info *info)
/* Device stuff */
static struct psp_dev *
-psp_device_get_and_lock(struct net *net, struct nlattr *dev_id)
+psp_device_get_and_lock(struct net *net, struct nlattr *dev_id,
+ bool admin)
{
struct psp_dev *psd;
int err;
@@ -56,7 +57,7 @@ psp_device_get_and_lock(struct net *net, struct nlattr *dev_id)
mutex_lock(&psd->lock);
mutex_unlock(&psp_devs_lock);
- err = psp_dev_check_access(psd, net);
+ err = psp_dev_check_access(psd, net, admin);
if (err) {
mutex_unlock(&psd->lock);
return ERR_PTR(err);
@@ -65,17 +66,31 @@ psp_device_get_and_lock(struct net *net, struct nlattr *dev_id)
return psd;
}
-int psp_device_get_locked(const struct genl_split_ops *ops,
- struct sk_buff *skb, struct genl_info *info)
+static int __psp_device_get_locked(const struct genl_split_ops *ops,
+ struct sk_buff *skb, struct genl_info *info,
+ bool admin)
{
if (GENL_REQ_ATTR_CHECK(info, PSP_A_DEV_ID))
return -EINVAL;
info->user_ptr[0] = psp_device_get_and_lock(genl_info_net(info),
- info->attrs[PSP_A_DEV_ID]);
+ info->attrs[PSP_A_DEV_ID],
+ admin);
return PTR_ERR_OR_ZERO(info->user_ptr[0]);
}
+int psp_device_get_locked_admin(const struct genl_split_ops *ops,
+ struct sk_buff *skb, struct genl_info *info)
+{
+ return __psp_device_get_locked(ops, skb, info, true);
+}
+
+int psp_device_get_locked(const struct genl_split_ops *ops,
+ struct sk_buff *skb, struct genl_info *info)
+{
+ return __psp_device_get_locked(ops, skb, info, false);
+}
+
void
psp_device_unlock(const struct genl_split_ops *ops, struct sk_buff *skb,
struct genl_info *info)
@@ -160,7 +175,7 @@ static int
psp_nl_dev_get_dumpit_one(struct sk_buff *rsp, struct netlink_callback *cb,
struct psp_dev *psd)
{
- if (psp_dev_check_access(psd, sock_net(rsp->sk)))
+ if (psp_dev_check_access(psd, sock_net(rsp->sk), false))
return 0;
return psp_nl_dev_fill(psd, rsp, genl_info_dump(cb));
@@ -305,7 +320,7 @@ int psp_assoc_device_get_locked(const struct genl_split_ops *ops,
psd = psp_dev_get_for_sock(socket->sk);
if (psd) {
- err = psp_dev_check_access(psd, genl_info_net(info));
+ err = psp_dev_check_access(psd, genl_info_net(info), false);
if (err) {
psp_dev_put(psd);
psd = NULL;
@@ -330,7 +345,7 @@ int psp_assoc_device_get_locked(const struct genl_split_ops *ops,
psp_dev_put(psd);
} else {
- psd = psp_device_get_and_lock(genl_info_net(info), id);
+ psd = psp_device_get_and_lock(genl_info_net(info), id, false);
if (IS_ERR(psd)) {
err = PTR_ERR(psd);
goto err_sock_put;
@@ -573,7 +588,7 @@ static int
psp_nl_stats_get_dumpit_one(struct sk_buff *rsp, struct netlink_callback *cb,
struct psp_dev *psd)
{
- if (psp_dev_check_access(psd, sock_net(rsp->sk)))
+ if (psp_dev_check_access(psd, sock_net(rsp->sk), false))
return 0;
return psp_nl_stats_fill(psd, rsp, genl_info_dump(cb));
--
2.52.0
^ permalink raw reply related
* [PATCH v9 net-next 3/5] psp: add a new netdev event for dev unregister
From: Wei Wang @ 2026-03-30 22:31 UTC (permalink / raw)
To: netdev, Jakub Kicinski, Daniel Zahka, Willem de Bruijn, David Wei,
Andrew Lunn, David S . Miller, Eric Dumazet, Simon Horman
Cc: Wei Wang
In-Reply-To: <20260330223143.2394706-1-weibunny.kernel@gmail.com>
From: Wei Wang <weibunny@fb.com>
Add a new netdev event for dev unregister and handle the removal of this
dev from psp->assoc_dev_list, upon the first dev-assoc operation.
Signed-off-by: Wei Wang <weibunny@fb.com>
---
Documentation/netlink/specs/psp.yaml | 2 +-
net/psp/psp-nl-gen.c | 2 +-
net/psp/psp-nl-gen.h | 3 ++
net/psp/psp.h | 1 +
net/psp/psp_main.c | 70 ++++++++++++++++++++++++++++
net/psp/psp_nl.c | 8 ++++
6 files changed, 84 insertions(+), 2 deletions(-)
diff --git a/Documentation/netlink/specs/psp.yaml b/Documentation/netlink/specs/psp.yaml
index 336ef19155ff..d7c1fc62de1c 100644
--- a/Documentation/netlink/specs/psp.yaml
+++ b/Documentation/netlink/specs/psp.yaml
@@ -320,7 +320,7 @@ operations:
- nsid
reply:
attributes: []
- pre: psp-device-get-locked
+ pre: psp-device-get-locked-dev-assoc
post: psp-device-unlock
-
name: dev-disassoc
diff --git a/net/psp/psp-nl-gen.c b/net/psp/psp-nl-gen.c
index 114299c64423..389a8480cc3d 100644
--- a/net/psp/psp-nl-gen.c
+++ b/net/psp/psp-nl-gen.c
@@ -135,7 +135,7 @@ static const struct genl_split_ops psp_nl_ops[] = {
},
{
.cmd = PSP_CMD_DEV_ASSOC,
- .pre_doit = psp_device_get_locked,
+ .pre_doit = psp_device_get_locked_dev_assoc,
.doit = psp_nl_dev_assoc_doit,
.post_doit = psp_device_unlock,
.policy = psp_dev_assoc_nl_policy,
diff --git a/net/psp/psp-nl-gen.h b/net/psp/psp-nl-gen.h
index 4dd0f0f23053..24d51bff997f 100644
--- a/net/psp/psp-nl-gen.h
+++ b/net/psp/psp-nl-gen.h
@@ -21,6 +21,9 @@ int psp_device_get_locked_admin(const struct genl_split_ops *ops,
struct sk_buff *skb, struct genl_info *info);
int psp_assoc_device_get_locked(const struct genl_split_ops *ops,
struct sk_buff *skb, struct genl_info *info);
+int psp_device_get_locked_dev_assoc(const struct genl_split_ops *ops,
+ struct sk_buff *skb,
+ struct genl_info *info);
void
psp_device_unlock(const struct genl_split_ops *ops, struct sk_buff *skb,
struct genl_info *info);
diff --git a/net/psp/psp.h b/net/psp/psp.h
index 0f9c4e4e52cb..fd7457dedd30 100644
--- a/net/psp/psp.h
+++ b/net/psp/psp.h
@@ -15,6 +15,7 @@ extern struct mutex psp_devs_lock;
void psp_dev_free(struct psp_dev *psd);
int psp_dev_check_access(struct psp_dev *psd, struct net *net, bool admin);
+void psp_attach_netdev_notifier(void);
void psp_nl_notify_dev(struct psp_dev *psd, u32 cmd);
diff --git a/net/psp/psp_main.c b/net/psp/psp_main.c
index 178b848989f1..160eaf3e7229 100644
--- a/net/psp/psp_main.c
+++ b/net/psp/psp_main.c
@@ -375,10 +375,80 @@ int psp_dev_rcv(struct sk_buff *skb, u16 dev_id, u8 generation, bool strip_icv)
}
EXPORT_SYMBOL(psp_dev_rcv);
+static void psp_dev_disassoc_one(struct psp_dev *psd, struct net_device *dev)
+{
+ struct psp_assoc_dev *entry, *tmp;
+
+ list_for_each_entry_safe(entry, tmp, &psd->assoc_dev_list, dev_list) {
+ if (entry->assoc_dev == dev) {
+ list_del(&entry->dev_list);
+ rcu_assign_pointer(entry->assoc_dev->psp_dev, NULL);
+ netdev_put(entry->assoc_dev, &entry->dev_tracker);
+ kfree(entry);
+ return;
+ }
+ }
+}
+
+static int psp_netdev_event(struct notifier_block *nb, unsigned long event,
+ void *ptr)
+{
+ struct net_device *dev = netdev_notifier_info_to_dev(ptr);
+ struct psp_dev *psd;
+
+ if (event != NETDEV_UNREGISTER)
+ return NOTIFY_DONE;
+
+ rcu_read_lock();
+ psd = rcu_dereference(dev->psp_dev);
+ if (psd && psp_dev_tryget(psd)) {
+ rcu_read_unlock();
+ mutex_lock(&psd->lock);
+ psp_dev_disassoc_one(psd, dev);
+ mutex_unlock(&psd->lock);
+ psp_dev_put(psd);
+ } else {
+ rcu_read_unlock();
+ }
+
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block psp_netdev_notifier = {
+ .notifier_call = psp_netdev_event,
+};
+
+static bool psp_notifier_registered;
+
+/**
+ * psp_attach_netdev_notifier() - register netdev notifier on first use
+ *
+ * Register the netdevice notifier when the first device association
+ * is created. In many installations no associations will be created and
+ * the notifier won't be needed.
+ *
+ * Must be called without psd->lock held, due to lock ordering:
+ * rtnl_lock -> psd->lock (the notifier callback runs under rtnl_lock
+ * and takes psd->lock).
+ */
+void psp_attach_netdev_notifier(void)
+{
+ if (READ_ONCE(psp_notifier_registered))
+ return;
+
+ mutex_lock(&psp_devs_lock);
+ if (!psp_notifier_registered) {
+ if (!register_netdevice_notifier(&psp_netdev_notifier))
+ WRITE_ONCE(psp_notifier_registered, true);
+ }
+ mutex_unlock(&psp_devs_lock);
+}
+
static int __init psp_init(void)
{
mutex_init(&psp_devs_lock);
return genl_register_family(&psp_nl_family);
}
+
subsys_initcall(psp_init);
diff --git a/net/psp/psp_nl.c b/net/psp/psp_nl.c
index 8a70848c74d7..e77c4ec3991e 100644
--- a/net/psp/psp_nl.c
+++ b/net/psp/psp_nl.c
@@ -159,6 +159,14 @@ int psp_device_get_locked(const struct genl_split_ops *ops,
return __psp_device_get_locked(ops, skb, info, false);
}
+int psp_device_get_locked_dev_assoc(const struct genl_split_ops *ops,
+ struct sk_buff *skb, struct genl_info *info)
+{
+ psp_attach_netdev_notifier();
+
+ return __psp_device_get_locked(ops, skb, info, false);
+}
+
void
psp_device_unlock(const struct genl_split_ops *ops, struct sk_buff *skb,
struct genl_info *info)
--
2.52.0
^ permalink raw reply related
* [PATCH v9 net-next 4/5] selftests/net: Add bpf skb forwarding program
From: Wei Wang @ 2026-03-30 22:31 UTC (permalink / raw)
To: netdev, Jakub Kicinski, Daniel Zahka, Willem de Bruijn, David Wei,
Andrew Lunn, David S . Miller, Eric Dumazet, Simon Horman
Cc: Wei Wang, Bobby Eshleman
In-Reply-To: <20260330223143.2394706-1-weibunny.kernel@gmail.com>
From: Wei Wang <weibunny@fb.com>
Add nk_redirect.bpf.c, a BPF program that forwards skbs matching some IPv6
prefix received on eth0 ifindex to a specified dev ifindex.
bpf_redirect_neigh() is used to make sure neighbor lookup is performed
and proper MAC addr is being used.
Signed-off-by: Wei Wang <weibunny@fb.com>
Reviewed-by: Bobby Eshleman <bobbyeshleman@meta.com>
Tested-by: Bobby Eshleman <bobbyeshleman@meta.com>
---
.../drivers/net/hw/nk_redirect.bpf.c | 60 +++++++++++++++++++
1 file changed, 60 insertions(+)
create mode 100644 tools/testing/selftests/drivers/net/hw/nk_redirect.bpf.c
diff --git a/tools/testing/selftests/drivers/net/hw/nk_redirect.bpf.c b/tools/testing/selftests/drivers/net/hw/nk_redirect.bpf.c
new file mode 100644
index 000000000000..7ac9ffd50f15
--- /dev/null
+++ b/tools/testing/selftests/drivers/net/hw/nk_redirect.bpf.c
@@ -0,0 +1,60 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * BPF program for redirecting traffic using bpf_redirect_neigh().
+ * Unlike bpf_redirect() which preserves L2 headers, bpf_redirect_neigh()
+ * performs neighbor lookup and fills in the correct L2 addresses for the
+ * target interface. This is necessary when redirecting across different
+ * device types (e.g., from netdevsim to netkit).
+ */
+#include <linux/bpf.h>
+#include <linux/pkt_cls.h>
+#include <linux/if_ether.h>
+#include <linux/ipv6.h>
+#include <linux/in6.h>
+#include <bpf/bpf_endian.h>
+#include <bpf/bpf_helpers.h>
+
+#define TC_ACT_OK 0
+#define ETH_P_IPV6 0x86DD
+
+#define ctx_ptr(field) ((void *)(long)(field))
+
+#define v6_p64_equal(a, b) (a.s6_addr32[0] == b.s6_addr32[0] && \
+ a.s6_addr32[1] == b.s6_addr32[1])
+
+volatile __u32 redirect_ifindex;
+volatile __u8 ipv6_prefix[16];
+
+SEC("tc/ingress")
+int tc_redirect(struct __sk_buff *skb)
+{
+ void *data_end = ctx_ptr(skb->data_end);
+ void *data = ctx_ptr(skb->data);
+ struct in6_addr *match_prefix;
+ struct ipv6hdr *ip6h;
+ struct ethhdr *eth;
+
+ match_prefix = (struct in6_addr *)ipv6_prefix;
+
+ if (skb->protocol != bpf_htons(ETH_P_IPV6))
+ return TC_ACT_OK;
+
+ eth = data;
+ if ((void *)(eth + 1) > data_end)
+ return TC_ACT_OK;
+
+ ip6h = data + sizeof(struct ethhdr);
+ if ((void *)(ip6h + 1) > data_end)
+ return TC_ACT_OK;
+
+ if (!v6_p64_equal(ip6h->daddr, (*match_prefix)))
+ return TC_ACT_OK;
+
+ /*
+ * Use bpf_redirect_neigh() to perform neighbor lookup and fill in
+ * correct L2 addresses for the target interface.
+ */
+ return bpf_redirect_neigh(redirect_ifindex, NULL, 0, 0);
+}
+
+char __license[] SEC("license") = "GPL";
--
2.52.0
^ permalink raw reply related
* [PATCH v9 net-next 5/5] selftest/net: psp: Add test for dev-assoc/disassoc
From: Wei Wang @ 2026-03-30 22:31 UTC (permalink / raw)
To: netdev, Jakub Kicinski, Daniel Zahka, Willem de Bruijn, David Wei,
Andrew Lunn, David S . Miller, Eric Dumazet, Simon Horman
Cc: Wei Wang
In-Reply-To: <20260330223143.2394706-1-weibunny.kernel@gmail.com>
From: Wei Wang <weibunny@fb.com>
Add a new param to NetDrvContEnv to add an additional bpf redirect
program on nk_host to redirect traffic to the psp_dev_local.
The topology looks like this:
Host NS: psp_dev_local <---> nk_host
| |
| | (netkit pair)
| |
Remote NS: psp_dev_peer Guest NS: nk_guest
(responder) (PSP tests)
Add following tests for dev-assoc/dev-disassoc functionality:
1. Test the output of `./tools/net/ynl/pyynl/cli.py --spec
Documentation/netlink/specs/psp.yaml --dump dev-get` in both default and
the guest netns.
2. Test the case where we associate netkit with psp_dev_local, and
send PSP traffic from nk_guest to psp_dev_peer in 2 different netns.
3. Test to make sure the key rotation notification is sent to the netns
for associated dev as well
4. Test to make sure the dev change notification is sent to the netns
for associated dev as well
5. Test for dev-assoc/dev-disassoc without nsid parameter.
6. Test the deletion of nk_guest in client netns, and proper cleanup in
the assoc-list for psp dev.
Signed-off-by: Wei Wang <weibunny@fb.com>
---
tools/testing/selftests/drivers/net/config | 1 +
.../selftests/drivers/net/lib/py/env.py | 54 +-
tools/testing/selftests/drivers/net/psp.py | 492 ++++++++++++++++--
3 files changed, 513 insertions(+), 34 deletions(-)
diff --git a/tools/testing/selftests/drivers/net/config b/tools/testing/selftests/drivers/net/config
index 77ccf83d87e0..cdde8234dc07 100644
--- a/tools/testing/selftests/drivers/net/config
+++ b/tools/testing/selftests/drivers/net/config
@@ -7,4 +7,5 @@ CONFIG_NETCONSOLE=m
CONFIG_NETCONSOLE_DYNAMIC=y
CONFIG_NETCONSOLE_EXTENDED_LOG=y
CONFIG_NETDEVSIM=m
+CONFIG_NETKIT=y
CONFIG_XDP_SOCKETS=y
diff --git a/tools/testing/selftests/drivers/net/lib/py/env.py b/tools/testing/selftests/drivers/net/lib/py/env.py
index 6a71c7e7f136..a70d776cf6b8 100644
--- a/tools/testing/selftests/drivers/net/lib/py/env.py
+++ b/tools/testing/selftests/drivers/net/lib/py/env.py
@@ -2,6 +2,7 @@
import ipaddress
import os
+import re
import time
import json
from pathlib import Path
@@ -327,7 +328,7 @@ class NetDrvContEnv(NetDrvEpEnv):
+---------------+
"""
- def __init__(self, src_path, rxqueues=1, **kwargs):
+ def __init__(self, src_path, rxqueues=1, install_tx_redirect_bpf=False, **kwargs):
self.netns = None
self._nk_host_ifname = None
self._nk_guest_ifname = None
@@ -338,6 +339,8 @@ class NetDrvContEnv(NetDrvEpEnv):
self._init_ns_attached = False
self._old_fwd = None
self._old_accept_ra = None
+ self._nk_host_tc_attached = False
+ self._nk_host_bpf_prog_pref = None
super().__init__(src_path, **kwargs)
@@ -388,7 +391,13 @@ class NetDrvContEnv(NetDrvEpEnv):
self._setup_ns()
self._attach_bpf()
+ if install_tx_redirect_bpf:
+ self._attach_tx_redirect_bpf()
+
def __del__(self):
+ if self._nk_host_tc_attached:
+ cmd(f"tc filter del dev {self._nk_host_ifname} ingress pref {self._nk_host_bpf_prog_pref}", fail=False)
+ self._nk_host_tc_attached = False
if self._tc_attached:
cmd(f"tc filter del dev {self.ifname} ingress pref {self._bpf_prog_pref}")
self._tc_attached = False
@@ -496,3 +505,46 @@ class NetDrvContEnv(NetDrvEpEnv):
value = ipv6_bytes + ifindex_bytes
value_hex = ' '.join(f'{b:02x}' for b in value)
bpftool(f"map update id {bss_map_id} key hex 00 00 00 00 value hex {value_hex}")
+
+ def _attach_tx_redirect_bpf(self):
+ """
+ Attach BPF program on nk_host ingress to redirect TX traffic.
+
+ Packets from nk_guest destined for the nsim network arrive at nk_host
+ via the netkit pair. This BPF program redirects them to the physical
+ interface so they can reach the remote peer.
+ """
+ bpf_obj = self.test_dir / "nk_redirect.bpf.o"
+ if not bpf_obj.exists():
+ raise KsftSkipEx("BPF prog nk_redirect.bpf.o not found")
+
+ cmd(f"tc qdisc add dev {self._nk_host_ifname} clsact")
+
+ cmd(f"tc filter add dev {self._nk_host_ifname} ingress bpf obj {bpf_obj} sec tc/ingress direct-action")
+ self._nk_host_tc_attached = True
+
+ tc_info = cmd(f"tc filter show dev {self._nk_host_ifname} ingress").stdout
+ match = re.search(r'pref (\d+).*nk_redirect\.bpf.*id (\d+)', tc_info)
+ if not match:
+ raise Exception("Failed to get TX redirect BPF prog ID")
+ self._nk_host_bpf_prog_pref = int(match.group(1))
+ nk_host_bpf_prog_id = int(match.group(2))
+
+ prog_info = bpftool(f"prog show id {nk_host_bpf_prog_id}", json=True)
+ map_ids = prog_info.get("map_ids", [])
+
+ bss_map_id = None
+ for map_id in map_ids:
+ map_info = bpftool(f"map show id {map_id}", json=True)
+ if map_info.get("name").endswith("bss"):
+ bss_map_id = map_id
+
+ if bss_map_id is None:
+ raise Exception("Failed to find TX redirect BPF .bss map")
+
+ ipv6_addr = ipaddress.IPv6Address(self.nsim_v6_pfx)
+ ipv6_bytes = ipv6_addr.packed
+ ifindex_bytes = self.ifindex.to_bytes(4, byteorder='little')
+ value = ipv6_bytes + ifindex_bytes
+ value_hex = ' '.join(f'{b:02x}' for b in value)
+ bpftool(f"map update id {bss_map_id} key hex 00 00 00 00 value hex {value_hex}")
diff --git a/tools/testing/selftests/drivers/net/psp.py b/tools/testing/selftests/drivers/net/psp.py
index 864d9fce1094..0ef6a522769e 100755
--- a/tools/testing/selftests/drivers/net/psp.py
+++ b/tools/testing/selftests/drivers/net/psp.py
@@ -5,6 +5,7 @@
import errno
import fcntl
+import os
import socket
import struct
import termios
@@ -14,9 +15,12 @@ from lib.py import defer
from lib.py import ksft_run, ksft_exit, ksft_pr
from lib.py import ksft_true, ksft_eq, ksft_ne, ksft_gt, ksft_raises
from lib.py import ksft_not_none
-from lib.py import KsftSkipEx
-from lib.py import NetDrvEpEnv, PSPFamily, NlError
+from lib.py import ksft_variants, KsftNamedVariant
+from lib.py import KsftSkipEx, KsftFailEx
+from lib.py import NetDrvEpEnv, NetDrvContEnv, PSPFamily, NlError
+from lib.py import NetNSEnter
from lib.py import bkg, rand_port, wait_port_listen
+from lib.py import ip
def _get_outq(s):
@@ -117,11 +121,13 @@ def _get_stat(cfg, key):
# Test case boiler plate
#
-def _init_psp_dev(cfg):
+def _init_psp_dev(cfg, use_psp_ifindex=False):
if not hasattr(cfg, 'psp_dev_id'):
# Figure out which local device we are testing against
+ # For NetDrvContEnv: use psp_ifindex instead of ifindex
+ target_ifindex = cfg.psp_ifindex if use_psp_ifindex else cfg.ifindex
for dev in cfg.pspnl.dev_get({}, dump=True):
- if dev['ifindex'] == cfg.ifindex:
+ if dev['ifindex'] == target_ifindex:
cfg.psp_info = dev
cfg.psp_dev_id = cfg.psp_info['id']
break
@@ -394,6 +400,297 @@ def _data_basic_send(cfg, version, ipver):
_close_psp_conn(cfg, s)
+def _data_basic_send_netkit_psp_assoc(cfg, version, ipver):
+ """
+ Test basic data send with netkit interface associated with PSP dev.
+ """
+
+ _init_psp_dev(cfg, True)
+ psp_dev_id_for_assoc = cfg.psp_dev_id
+
+ # Associate PSP device with nk_guest interface (in guest namespace)
+ nk_guest_dev = ip(f"link show dev {cfg._nk_guest_ifname}", json=True, ns=cfg.netns)[0]
+ nk_guest_ifindex = nk_guest_dev['ifindex']
+
+ cfg.pspnl.dev_assoc({'id': psp_dev_id_for_assoc, 'ifindex': nk_guest_ifindex, 'nsid': cfg.psp_dev_peer_nsid})
+
+ # Check if assoc-list contains nk_guest
+ dev_info = cfg.pspnl.dev_get({'id': psp_dev_id_for_assoc})
+
+ if 'assoc-list' in dev_info:
+ found = False
+ for assoc in dev_info['assoc-list']:
+ if assoc['ifindex'] == nk_guest_ifindex and assoc['nsid'] == cfg.psp_dev_peer_nsid:
+ found = True
+ break
+ ksft_true(found, "Associated device not found in dev_get() response")
+ else:
+ raise RuntimeError("No assoc-list in dev_get() response after association")
+
+ # Enter guest namespace (netns) to run PSP test
+ with NetNSEnter(cfg.netns.name):
+ cfg.pspnl = PSPFamily()
+
+ s = _make_psp_conn(cfg, version, ipver)
+
+ rx_assoc = cfg.pspnl.rx_assoc({"version": version,
+ "dev-id": cfg.psp_dev_id,
+ "sock-fd": s.fileno()})
+ rx = rx_assoc['rx-key']
+ tx = _spi_xchg(s, rx)
+
+ cfg.pspnl.tx_assoc({"dev-id": cfg.psp_dev_id,
+ "version": version,
+ "tx-key": tx,
+ "sock-fd": s.fileno()})
+
+ data_len = _send_careful(cfg, s, 100)
+ _check_data_rx(cfg, data_len)
+ _close_psp_conn(cfg, s)
+
+ # Clean up - back in host namespace
+ cfg.pspnl = PSPFamily()
+ cfg.pspnl.dev_disassoc({'id': psp_dev_id_for_assoc, 'ifindex': nk_guest_ifindex, 'nsid': cfg.psp_dev_peer_nsid})
+
+ del cfg.psp_dev_id
+ del cfg.psp_info
+
+
+def _key_rotation_notify_multi_ns_netkit(cfg, version, ipver):
+ """ Test key rotation notifications across multiple namespaces using netkit """
+ _init_psp_dev(cfg, True)
+ psp_dev_id_for_assoc = cfg.psp_dev_id
+
+ # Associate PSP device with nk_guest interface (in guest namespace)
+ nk_guest_dev = ip(f"link show dev {cfg._nk_guest_ifname}", json=True, ns=cfg.netns)[0]
+ nk_guest_ifindex = nk_guest_dev['ifindex']
+
+ cfg.pspnl.dev_assoc({'id': psp_dev_id_for_assoc, 'ifindex': nk_guest_ifindex, 'nsid': cfg.psp_dev_peer_nsid})
+
+ # Create listener in guest namespace; socket stays bound to that ns
+ with NetNSEnter(cfg.netns.name):
+ peer_pspnl = PSPFamily()
+ peer_pspnl.ntf_subscribe('use')
+
+ # Create listener in main namespace
+ main_pspnl = PSPFamily()
+ main_pspnl.ntf_subscribe('use')
+
+ # Trigger key rotation on the PSP device
+ cfg.pspnl.key_rotate({"id": psp_dev_id_for_assoc})
+
+ # Poll both sockets from main thread
+ for pspnl, label in [(main_pspnl, "main"), (peer_pspnl, "guest")]:
+ for i in range(100):
+ pspnl.check_ntf()
+
+ try:
+ msg = pspnl.async_msg_queue.get_nowait()
+ break
+ except Exception:
+ pass
+
+ time.sleep(0.1)
+ else:
+ raise KsftFailEx(f"No key rotation notification received in {label} namespace")
+
+ ksft_true(msg['msg'].get('id') == psp_dev_id_for_assoc,
+ f"Key rotation notification for correct device not found in {label} namespace")
+
+ # Clean up
+ cfg.pspnl.dev_disassoc({'id': psp_dev_id_for_assoc, 'ifindex': nk_guest_ifindex, 'nsid': cfg.psp_dev_peer_nsid})
+ del cfg.psp_dev_id
+ del cfg.psp_info
+
+
+def _dev_change_notify_multi_ns_netkit(cfg, version, ipver):
+ """ Test dev_change notifications across multiple namespaces using netkit """
+ _init_psp_dev(cfg, True)
+ psp_dev_id_for_assoc = cfg.psp_dev_id
+
+ # Associate PSP device with nk_guest interface (in guest namespace)
+ nk_guest_dev = ip(f"link show dev {cfg._nk_guest_ifname}", json=True, ns=cfg.netns)[0]
+ nk_guest_ifindex = nk_guest_dev['ifindex']
+
+ cfg.pspnl.dev_assoc({'id': psp_dev_id_for_assoc, 'ifindex': nk_guest_ifindex, 'nsid': cfg.psp_dev_peer_nsid})
+
+ # Create listener in guest namespace; socket stays bound to that ns
+ with NetNSEnter(cfg.netns.name):
+ peer_pspnl = PSPFamily()
+ peer_pspnl.ntf_subscribe('mgmt')
+
+ # Create listener in main namespace
+ main_pspnl = PSPFamily()
+ main_pspnl.ntf_subscribe('mgmt')
+
+ # Trigger dev_change by calling dev_set (notification is always sent)
+ cfg.pspnl.dev_set({'id': psp_dev_id_for_assoc, 'psp-versions-ena': cfg.psp_info['psp-versions-cap']})
+
+ # Poll both sockets from main thread
+ for pspnl, label in [(main_pspnl, "main"), (peer_pspnl, "guest")]:
+ for i in range(100):
+ pspnl.check_ntf()
+
+ try:
+ msg = pspnl.async_msg_queue.get_nowait()
+ break
+ except Exception:
+ pass
+
+ time.sleep(0.1)
+ else:
+ raise KsftFailEx(f"No dev_change notification received in {label} namespace")
+
+ ksft_true(msg['msg'].get('id') == psp_dev_id_for_assoc,
+ f"Dev_change notification for correct device not found in {label} namespace")
+
+ # Clean up
+ cfg.pspnl.dev_disassoc({'id': psp_dev_id_for_assoc, 'ifindex': nk_guest_ifindex, 'nsid': cfg.psp_dev_peer_nsid})
+ del cfg.psp_dev_id
+ del cfg.psp_info
+
+
+def _psp_dev_get_check_netkit_psp_assoc(cfg, version, ipver):
+ """ Check psp dev-get output with netkit interface associated with PSP dev """
+
+ _init_psp_dev(cfg, True)
+ psp_dev_id_for_assoc = cfg.psp_dev_id
+
+ # Associate PSP device with nk_guest interface (in guest namespace)
+ nk_guest_dev = ip(f"link show dev {cfg._nk_guest_ifname}", json=True, ns=cfg.netns)[0]
+ nk_guest_ifindex = nk_guest_dev['ifindex']
+
+ cfg.pspnl.dev_assoc({'id': psp_dev_id_for_assoc, 'ifindex': nk_guest_ifindex, 'nsid': cfg.psp_dev_peer_nsid})
+
+ # Check 1: In default netns, verify dev-get has correct ifindex and assoc-list
+ dev_info = cfg.pspnl.dev_get({'id': psp_dev_id_for_assoc})
+
+ # Verify the PSP device has the correct ifindex
+ ksft_eq(dev_info['ifindex'], cfg.psp_ifindex)
+
+ # Verify assoc-list exists and contains the associated nk_guest with correct ifindex and nsid
+ ksft_true('assoc-list' in dev_info, "No assoc-list in dev_get() response after association")
+ found = False
+ for assoc in dev_info['assoc-list']:
+ if assoc['ifindex'] == nk_guest_ifindex and assoc['nsid'] == cfg.psp_dev_peer_nsid:
+ found = True
+ break
+ ksft_true(found, "Associated device not found in assoc-list with correct ifindex and nsid")
+
+ # Check 2: In guest netns, verify dev-get has assoc-list with nk_guest device
+ with NetNSEnter(cfg.netns.name):
+ peer_pspnl = PSPFamily()
+
+ # Dump all devices in the guest namespace
+ peer_devices = peer_pspnl.dev_get({}, dump=True)
+
+ # Find the device with by-association flag
+ peer_dev = None
+ for dev in peer_devices:
+ if dev.get('by-association'):
+ peer_dev = dev
+ break
+
+ ksft_not_none(peer_dev, "No PSP device found with by-association flag in guest netns")
+
+ # Verify assoc-list contains the nk_guest device
+ ksft_true('assoc-list' in peer_dev and len(peer_dev['assoc-list']) > 0,
+ "Guest device should have assoc-list with local devices")
+
+ # Verify the assoc-list contains nk_guest ifindex with nsid=-1 (same namespace)
+ found = False
+ for assoc in peer_dev['assoc-list']:
+ if assoc['ifindex'] == nk_guest_ifindex:
+ ksft_eq(assoc['nsid'], -1,
+ "nsid should be -1 (NETNSA_NSID_NOT_ASSIGNED) for same-namespace device")
+ found = True
+ break
+ ksft_true(found, "nk_guest ifindex not found in assoc-list")
+
+ # Clean up
+ cfg.pspnl.dev_disassoc({'id': psp_dev_id_for_assoc, 'ifindex': nk_guest_ifindex, 'nsid': cfg.psp_dev_peer_nsid})
+
+ del cfg.psp_dev_id
+ del cfg.psp_info
+
+
+def _dev_assoc_no_nsid(cfg):
+ """ Test dev-assoc and dev-disassoc without nsid attribute """
+ _init_psp_dev(cfg, True)
+ psp_dev_id = cfg.psp_dev_id
+
+ # Get nk_host's ifindex (in host namespace, same as caller)
+ nk_host_dev = ip(f"link show dev {cfg._nk_host_ifname}", json=True)[0]
+ nk_host_ifindex = nk_host_dev['ifindex']
+
+ # Associate without nsid - should look up ifindex in caller's netns
+ cfg.pspnl.dev_assoc({'id': psp_dev_id, 'ifindex': nk_host_ifindex})
+
+ # Verify assoc-list contains the device
+ dev_info = cfg.pspnl.dev_get({'id': psp_dev_id})
+ ksft_true('assoc-list' in dev_info, "No assoc-list after association")
+ found = False
+ for assoc in dev_info['assoc-list']:
+ if assoc['ifindex'] == nk_host_ifindex:
+ found = True
+ break
+ ksft_true(found, "Associated device not found in assoc-list")
+
+ # Disassociate without nsid - should also use caller's netns
+ cfg.pspnl.dev_disassoc({'id': psp_dev_id, 'ifindex': nk_host_ifindex})
+
+ # Verify assoc-list no longer contains the device
+ dev_info = cfg.pspnl.dev_get({'id': psp_dev_id})
+ found = False
+ if 'assoc-list' in dev_info:
+ for assoc in dev_info['assoc-list']:
+ if assoc['ifindex'] == nk_host_ifindex:
+ found = True
+ break
+ ksft_true(not found, "Device should not be in assoc-list after disassociation")
+
+ del cfg.psp_dev_id
+ del cfg.psp_info
+
+
+def _psp_dev_assoc_cleanup_on_netkit_del(cfg):
+ """ Test that assoc-list is cleared when associated netkit interface is deleted """
+ _init_psp_dev(cfg, True)
+ psp_dev_id_for_assoc = cfg.psp_dev_id
+
+ # Associate PSP device with nk_guest interface (in guest namespace)
+ nk_guest_dev = ip(f"link show dev {cfg._nk_guest_ifname}", json=True, ns=cfg.netns)[0]
+ nk_guest_ifindex = nk_guest_dev['ifindex']
+
+ cfg.pspnl.dev_assoc({'id': psp_dev_id_for_assoc, 'ifindex': nk_guest_ifindex, 'nsid': cfg.psp_dev_peer_nsid})
+
+ # Verify assoc-list exists in default netns
+ dev_info = cfg.pspnl.dev_get({'id': psp_dev_id_for_assoc})
+ ksft_true('assoc-list' in dev_info, "No assoc-list after association")
+ found = False
+ for assoc in dev_info['assoc-list']:
+ if assoc['ifindex'] == nk_guest_ifindex and assoc['nsid'] == cfg.psp_dev_peer_nsid:
+ found = True
+ break
+ ksft_true(found, "Associated device not found in assoc-list")
+
+ # Delete the netkit interface in the guest namespace
+ ip(f"link del {cfg._nk_guest_ifname}", ns=cfg.netns)
+
+ # Mark netkit as already deleted so cleanup won't try to delete it again
+ # (deleting nk_guest also removes nk_host since they're a pair)
+ cfg._nk_host_ifname = None
+ cfg._nk_guest_ifname = None
+
+ # Verify assoc-list is gone in default netns after netkit deletion
+ dev_info = cfg.pspnl.dev_get({'id': psp_dev_id_for_assoc})
+ ksft_true('assoc-list' not in dev_info or len(dev_info['assoc-list']) == 0,
+ "assoc-list should be empty after netkit deletion")
+
+ del cfg.psp_dev_id
+ del cfg.psp_info
+
+
def __bad_xfer_do(cfg, s, tx, version='hdr0-aes-gcm-128'):
# Make sure we accept the ACK for the SPI before we seal with the bad assoc
_check_data_outq(s, 0)
@@ -571,33 +868,162 @@ def removal_device_bi(cfg):
_close_conn(cfg, s)
-def psp_ip_ver_test_builder(name, test_func, psp_ver, ipver):
- """Build test cases for each combo of PSP version and IP version"""
- def test_case(cfg):
- cfg.require_ipver(ipver)
- test_func(cfg, psp_ver, ipver)
-
- test_case.__name__ = f"{name}_v{psp_ver}_ip{ipver}"
- return test_case
+@ksft_variants([
+ KsftNamedVariant(f"v{v}_ip{ip}", v, ip)
+ for v in range(4) for ip in ("4", "6")
+])
+def data_basic_send(cfg, version, ipver):
+ cfg.require_ipver(ipver)
+ _data_basic_send(cfg, version, ipver)
+
+
+@ksft_variants([
+ KsftNamedVariant(f"ip{ip}", ip)
+ for ip in ("4", "6")
+])
+def data_mss_adjust(cfg, ipver):
+ cfg.require_ipver(ipver)
+ _data_mss_adjust(cfg, ipver)
+
+
+@ksft_variants([
+ KsftNamedVariant(f"v{v}_ip6", v, "6")
+ for v in range(4)
+])
+def data_basic_send_netkit_psp_assoc(cfg, version, ipver):
+ cfg.require_ipver(ipver)
+ _data_basic_send_netkit_psp_assoc(cfg, version, ipver)
+
+
+@ksft_variants([
+ KsftNamedVariant(f"v{v}_ip6", v, "6")
+ for v in range(4)
+])
+def key_rotation_notify_multi_ns_netkit(cfg, version, ipver):
+ cfg.require_ipver(ipver)
+ _key_rotation_notify_multi_ns_netkit(cfg, version, ipver)
+
+
+@ksft_variants([
+ KsftNamedVariant(f"v{v}_ip6", v, "6")
+ for v in range(4)
+])
+def dev_change_notify_multi_ns_netkit(cfg, version, ipver):
+ cfg.require_ipver(ipver)
+ _dev_change_notify_multi_ns_netkit(cfg, version, ipver)
+
+
+@ksft_variants([
+ KsftNamedVariant(f"v{v}_ip6", v, "6")
+ for v in range(4)
+])
+def psp_dev_get_check_netkit_psp_assoc(cfg, version, ipver):
+ cfg.require_ipver(ipver)
+ _psp_dev_get_check_netkit_psp_assoc(cfg, version, ipver)
+
+
+@ksft_variants([
+ KsftNamedVariant(f"v{v}_ip6", v, "6")
+ for v in range(4)
+])
+def dev_assoc_no_nsid(cfg, version, ipver):
+ cfg.require_ipver(ipver)
+ _dev_assoc_no_nsid(cfg)
+
+
+def _get_nsid(ns_name):
+ """Get the nsid for a namespace."""
+ for entry in ip("netns list-id", json=True):
+ if entry.get("name") == str(ns_name):
+ return entry["nsid"]
+ raise KsftSkipEx(f"nsid not found for namespace {ns_name}")
+
+
+def _setup_psp_attributes(cfg):
+ """
+ Set up PSP-specific attributes on the environment.
+
+ This sets attributes needed for PSP tests based on whether we're using
+ netdevsim or a real NIC.
+ """
+ if cfg._ns is not None:
+ # netdevsim case: PSP device is the local dev (in host namespace)
+ cfg.psp_dev = cfg._ns.nsims[0].dev
+ cfg.psp_ifname = cfg.psp_dev['ifname']
+ cfg.psp_ifindex = cfg.psp_dev['ifindex']
+
+ # PSP peer device is the remote dev (in _netns, where psp_responder runs)
+ cfg.psp_dev_peer = cfg._ns_peer.nsims[0].dev
+ cfg.psp_dev_peer_ifname = cfg.psp_dev_peer['ifname']
+ cfg.psp_dev_peer_ifindex = cfg.psp_dev_peer['ifindex']
+ else:
+ # Real NIC case: PSP device is the local interface
+ cfg.psp_dev = cfg.dev
+ cfg.psp_ifname = cfg.ifname
+ cfg.psp_ifindex = cfg.ifindex
+
+ # PSP peer device is the remote interface
+ cfg.psp_dev_peer = cfg.remote_dev
+ cfg.psp_dev_peer_ifname = cfg.remote_ifname
+ cfg.psp_dev_peer_ifindex = cfg.remote_ifindex
+
+ # Get nsid for the guest namespace (netns) where nk_guest is
+ cfg.psp_dev_peer_nsid = _get_nsid(cfg.netns.name)
+
+
+def _setup_psp_routes(cfg):
+ """
+ Set up routes for cross-namespace connectivity.
+
+ Traffic flows:
+ 1. remote (_netns) -> nk_guest (netns):
+ psp_dev_peer -> psp_dev_local -> BPF redirect -> nk_host -> nk_guest
+ Needs: route in _netns to nk_v6_pfx/64 via psp_dev_local
+
+ 2. nk_guest (netns) -> remote (_netns):
+ nk_guest -> nk_host -> psp_dev_local -> psp_dev_peer
+ Needs: route in netns to dev_v6_pfx/64 via nk_host
+ """
+ # In _netns (remote namespace): add route to nk_guest prefix via psp_dev_local
+ # psp_dev_peer can reach psp_dev_local via the link, then traffic goes through BPF
+ ip(f"-6 route add {cfg.nk_v6_pfx}/64 via {cfg.nsim_v6_pfx}1 dev {cfg.psp_dev_peer_ifname}",
+ ns=cfg._netns)
+
+ # In netns (guest namespace): add route to remote peer prefix
+ # nk_guest default route goes to nk_host, but we need explicit route to dev_v6_pfx/64
+ ip(f"-6 route add {cfg.nsim_v6_pfx}/64 via fe80::1 dev {cfg._nk_guest_ifname}",
+ ns=cfg.netns)
-def ipver_test_builder(name, test_func, ipver):
- """Build test cases for each IP version"""
- def test_case(cfg):
- cfg.require_ipver(ipver)
- test_func(cfg, ipver)
+def main() -> None:
+ """ Ksft boiler plate main """
- test_case.__name__ = f"{name}_ip{ipver}"
- return test_case
+ # Use a different prefix for netkit guest to avoid conflict with dev prefix
+ nk_v6_pfx = "2001:db9::"
+ # Set LOCAL_PREFIX_V6 to a DIFFERENT prefix than the dev prefix to avoid BPF
+ # redirecting psp_responder traffic. The BPF only redirects traffic
+ # matching LOCAL_PREFIX_V6, so dev traffic (2001:db8::) won't be affected.
+ if "LOCAL_PREFIX_V6" not in os.environ:
+ os.environ["LOCAL_PREFIX_V6"] = nk_v6_pfx
-def main() -> None:
- """ Ksft boiler plate main """
+ try:
+ env = NetDrvContEnv(__file__, install_tx_redirect_bpf=True)
+ has_cont = True
+ except KsftSkipEx:
+ env = NetDrvEpEnv(__file__)
+ has_cont = False
- with NetDrvEpEnv(__file__) as cfg:
+ with env as cfg:
cfg.pspnl = PSPFamily()
+ if has_cont:
+ cfg.nk_v6_pfx = nk_v6_pfx
+ _setup_psp_attributes(cfg)
+ _setup_psp_routes(cfg)
+
# Set up responder and communication sock
+ # psp_responder runs in _netns (remote namespace with psp_dev_peer)
responder = cfg.remote.deploy("psp_responder")
cfg.comm_port = rand_port()
@@ -611,17 +1037,17 @@ def main() -> None:
cfg.comm_port),
timeout=1)
- cases = [
- psp_ip_ver_test_builder(
- "data_basic_send", _data_basic_send, version, ipver
- )
- for version in range(0, 4)
- for ipver in ("4", "6")
- ]
- cases += [
- ipver_test_builder("data_mss_adjust", _data_mss_adjust, ipver)
- for ipver in ("4", "6")
- ]
+ cases = [data_basic_send, data_mss_adjust]
+
+ if has_cont:
+ cases += [
+ data_basic_send_netkit_psp_assoc,
+ key_rotation_notify_multi_ns_netkit,
+ dev_change_notify_multi_ns_netkit,
+ psp_dev_get_check_netkit_psp_assoc,
+ dev_assoc_no_nsid,
+ _psp_dev_assoc_cleanup_on_netkit_del,
+ ]
ksft_run(cases=cases, globs=globals(),
case_pfx={"dev_", "data_", "assoc_", "removal_"},
--
2.52.0
^ permalink raw reply related
* Re: [PATCH v24 10/11] cxl: Avoid dax creation for accelerators
From: Alison Schofield @ 2026-03-30 22:36 UTC (permalink / raw)
To: Alejandro Lucero Palau
Cc: alejandro.lucero-palau, linux-cxl, netdev, dave.jiang,
dan.j.williams, edward.cree, davem, kuba, pabeni, edumazet,
Jonathan Cameron, Davidlohr Bueso, Ben Cheatham
In-Reply-To: <8737035f-07e9-4c14-93a9-bb542197d7f7@amd.com>
On Mon, Mar 30, 2026 at 03:26:41PM +0100, Alejandro Lucero Palau wrote:
>
> On 3/25/26 02:59, Alison Schofield wrote:
> > On Mon, Mar 23, 2026 at 11:31:16AM +0000, alejandro.lucero-palau@amd.com wrote:
> > > From: Alejandro Lucero <alucerop@amd.com>
> > >
> > > By definition a type2 cxl device will use the host managed memory for
> > > specific functionality, therefore it should not be available to other
> > > uses.
> > Hi Alejandro,
> >
> > I'm wondering if we're skipping too much, or perhaps just needs
> > a clarifying comment?
> >
> > Commit message says 'Avoid dax creation...', that's specific.
> >
> > Commit log says 'should not be available to other uses', that's less specific
>
>
> Hi Allison,
>
>
> Would you prefer something like "should not be available to other uses like
> DAX".?
The point really is that this skips 3 things, not just DAX creation.
So, address each of those things in the commit message, or narrow
what is skipped to be only the DAX creation.
see below...
>
>
> > follow me ...
> >
> > > Signed-off-by: Alejandro Lucero <alucerop@amd.com>
> > > Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
> > > Reviewed-by: Davidlohr Bueso <daves@stgolabs.net>
> > > Reviewed-by: Dave Jiang <dave.jiang@intel.com>
> > > Reviewed-by: Ben Cheatham <benjamin.cheatham@amd.com>
> > > ---
> > > drivers/cxl/core/region.c | 7 +++++++
> > > 1 file changed, 7 insertions(+)
> > >
> > > diff --git a/drivers/cxl/core/region.c b/drivers/cxl/core/region.c
> > > index 8bb53a095290..2f9bdb4f1f4f 100644
> > > --- a/drivers/cxl/core/region.c
> > > +++ b/drivers/cxl/core/region.c
> > > @@ -4263,6 +4263,13 @@ static int cxl_region_probe(struct device *dev)
> > > if (rc)
> > > return rc;
> > > + /*
> > > + * HDM-D[B] (device-memory) regions have accelerator specific usage.
> > > + * Skip device-dax registration.
> > > + */
> > > + if (cxlr->type == CXL_DECODER_DEVMEM)
> > > + return 0;
> > > +
> > And above says 'Skip device-dax' specific again, and is indeed skipped.
> >
> > This escape is not surgically placed at the point where dax is added.
> > We are skipping a few other things before dax registration actually
> > happens. Why skip memory notifiers, shutdown_notifiers, poison setup?
>
>
> posion setup crashes with a type2 and I'm not sure if the memory notifiers
> make sense for Type2.
>
wrt - poison set crashes with a type2:
Let's not leave a known crash to be tripped upon in the future.
The crash is probably on a dereference on cxl_memdev_state, mds, which
you guarded against in Patch 4/11 in other paths. I think this needs
similar check added to cxl_memdev_has_poison_cmd(). With that, I expect
the cxl_region_setup_poison() in this path here. Success meaning it looked
to see if it's member devices supported poison, they do not, so no poison
set up.
I'm not familiar w the notifiers.
>
> If it is really needed, I would prefer to support it as a follow up.
>
>
> Thank you
>
>
> >
> > > /*
> > > * From this point on any path that changes the region's state away from
> > > * CXL_CONFIG_COMMIT is also responsible for releasing the driver.
> > > --
> > > 2.34.1
> > >
> > >
^ permalink raw reply
* Re: [PATCH v2 5/7] phy: ti: gmii-sel: add support for J722S SoC family
From: Vladimir Oltean @ 2026-03-30 22:37 UTC (permalink / raw)
To: Nora Schiffer
Cc: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Nishanth Menon, Vignesh Raghavendra, Tero Kristo,
Siddharth Vadapalli, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Vinod Koul, Neil Armstrong, netdev, devicetree,
linux-kernel, linux-phy, linux-arm-kernel, linux
In-Reply-To: <5d00697f133cd33a1df62ac7ebf73e507e49ed2f.1774354734.git.nora.schiffer@ew.tq-group.com>
Hi Nora,
On Tue, Mar 24, 2026 at 01:29:41PM +0100, Nora Schiffer wrote:
> The J722S gmii-sel is mostly identical to the AM64's, but additionally
> supports SGMII.
>
> Signed-off-by: Nora Schiffer <nora.schiffer@ew.tq-group.com>
> ---
> drivers/phy/ti/phy-gmii-sel.c | 11 +++++++++++
> 1 file changed, 11 insertions(+)
>
> diff --git a/drivers/phy/ti/phy-gmii-sel.c b/drivers/phy/ti/phy-gmii-sel.c
> index 6213c2b6005a5..4e242b1892334 100644
> --- a/drivers/phy/ti/phy-gmii-sel.c
> +++ b/drivers/phy/ti/phy-gmii-sel.c
> @@ -251,6 +251,13 @@ struct phy_gmii_sel_soc_data phy_gmii_sel_soc_am654 = {
> .regfields = phy_gmii_sel_fields_am654,
> };
>
> +static const
> +struct phy_gmii_sel_soc_data phy_gmii_sel_soc_j722s = {
> + .use_of_data = true,
> + .regfields = phy_gmii_sel_fields_am654,
> + .extra_modes = BIT(PHY_INTERFACE_MODE_SGMII),
I'm not familiar with the hardware, but "mostly identical to AM64, but
additionally supports SGMII" does not explain why j722s does not inherit
the features that am654 has (PHY_GMII_SEL_RGMII_ID_MODE and
BIT(PHY_GMII_SEL_FIXED_TX_DELAY).
The phy-gmii-sel from j722s does support RGMII, right? Because in lack
of the PHY_GMII_SEL_RGMII_ID_MODE feature, phy_gmii_sel_mode() will just
silently skip the regmap_field_write(regfield, rgmii_id) call, and
return successfully despite an incomplete configuration.
We have the phy_validate() call and phy_ops::validate() through which
the PHY can report to the Ethernet controller which phy_interface_t it
supports and which it doesn't. If the j722s doesn't support RGMII, maybe
it should implement this method.
> +};
> +
^ permalink raw reply
* Re: [PATCH net-next v2] net: phy: bcm84881: add BCM84891/BCM84892 support
From: Jakub Kicinski @ 2026-03-30 22:39 UTC (permalink / raw)
To: Daniel Wagner
Cc: netdev, Florian Fainelli, Andrew Lunn, Heiner Kallweit,
Russell King, bcm-kernel-feedback-list, Eric Dumazet, Paolo Abeni
In-Reply-To: <CAMsLQxGcnD1Q8REcgKWJQR-cgS2Z1KaTJgs9r989p2pxz6vV4Q@mail.gmail.com>
On Sun, 29 Mar 2026 17:47:47 +0100 Daniel Wagner wrote:
> I see v2 is marked as "changes requested" on patchwork; I believe it
> addresses the original points, but happy to make further changes if I
> missed something. LEDs will follow in a separate patch.
Repost it, say in the change log that it's identical to v2.
You posted this while the discussion was still ongoing which
is an automatic expulsion from patchwork.
^ permalink raw reply
* Re: [PATCH net-next v1] net: macb: fix use of at91_default_usrio without CONFIG_OF
From: Jakub Kicinski @ 2026-03-30 22:43 UTC (permalink / raw)
To: Conor Dooley
Cc: netdev, Conor Dooley, kernel test robot, Jiawen Wu, Andrew Lunn,
David S. Miller, Eric Dumazet, Paolo Abeni, Nicolas Ferre,
Claudiu Beznea, devicetree, linux-kernel, linux-riscv
In-Reply-To: <20260330-overture-cactus-c8eb7b9cbecc@spud>
On Mon, 30 Mar 2026 10:02:00 +0100 Conor Dooley wrote:
> @@ -5778,7 +5778,7 @@ static int macb_probe(struct platform_device *pdev)
>
> macb_config = of_device_get_match_data(&pdev->dev);
> if (!macb_config)
> - macb_config = &default_gem_config;
> + return -EINVAL;
>
AI reviewer says this will break macb_pci.c which registers a platform
device and will never have match data?
Feel free to post the v2 without the full 24h netdev wait if needed.
--
pw-bot: cr
^ permalink raw reply
* Re: [PATCH net-next v2] net: phy: bcm84881: add BCM84891/BCM84892 support
From: Nicolai Buchwitz @ 2026-03-30 22:44 UTC (permalink / raw)
To: Daniel Wagner
Cc: netdev, Florian Fainelli, Andrew Lunn, Heiner Kallweit,
Russell King, bcm-kernel-feedback-list, Jakub Kicinski,
Eric Dumazet, Paolo Abeni
In-Reply-To: <20260324190601.1616343-1-wagner.daniel.t@gmail.com>
On 24.3.2026 20:06, Daniel Wagner wrote:
> The BCM84891 and BCM84892 are 10GBASE-T PHYs in the same family as the
> BCM84881, sharing the register map and most callbacks. They add USXGMII
> as a host interface mode.
>
> bcm8489x_config_init() is separate from bcm84881_config_init(): it
> allows only USXGMII (the only host mode available on the tested
> hardware) and clears MDIO_CTRL1_LPOWER, which is set at boot on the
> tested platform. Does not recur on ifdown/ifup, cable events, or
> link-partner advertisement changes, so config_init is sufficient.
>
> For USXGMII, read_status() skips the 0x4011 host-mode register: it
> returns the same value regardless of negotiated copper speed (USXGMII
> symbol replication). Speed comes from phy_resolve_aneg_linkmode() via
> standard C45 AN resolution.
>
> Tested on TRENDnet TEG-S750 (RTL9303 + 1x BCM84891 + 4x BCM84892)
> running OpenWrt, where the MDIO controller driver is currently
> OpenWrt-specific. Link verified at 100M, 1G, 2.5G, 10G.
>
> Signed-off-by: Daniel Wagner <wagner.daniel.t@gmail.com>
> ---
> Changes in v2:
> - Separate bcm8489x_config_init() that allows only USXGMII. v1 also
> allowed USXGMII for BCM84881 (which doesn't support it), and put
> SGMII/2500BASEX/10GBASER in the 8489x possible_interfaces which I
> can't substantiate on this hardware. (Russell)
> - LPOWER clear moved from config_aneg to config_init. Characterized on
> hardware: boot-time only, does not recur on ifdown/ifup, cable
> events, or link-partner advertisement changes. (Russell)
> - Dropped LED support; will figure out the PHY LED framework approach
> for bicolor speed-mapped LEDs as a follow-up. (Russell, Andrew)
> - PHY_ID_MATCH_MODEL(). (Russell, Andrew)
> - is_bcm8489x() helper removed; the interface mode now suffices as a
> discriminator in read_status since only the 8489x config_init allows
> USXGMII.
>
> v1:
> https://lore.kernel.org/netdev/20260324152503.1522071-2-wagner.daniel.t@gmail.com/
>
> [...]
Checked the patch against the public datasheet and everything resolves.
Reviewed-by: Nicolai Buchwitz <nb@tipi-net.de>
^ permalink raw reply
* [PATCH net-next v2 0/2] net: phy: microchip: add downshift support for LAN88xx
From: Nicolai Buchwitz @ 2026-03-30 22:46 UTC (permalink / raw)
To: netdev; +Cc: Phil Elwell, Nicolai Buchwitz
Add standard ETHTOOL_PHY_DOWNSHIFT tunable support for the Microchip
LAN88xx PHY, following the same pattern used by Marvell and other PHY
drivers.
Ethernet cables with faulty or missing pairs (specifically C and D)
can successfully auto-negotiate 1000BASE-T but fail to establish a
stable link. The LAN88xx PHY supports automatic downshift to
100BASE-TX after a configurable number of failed attempts (2-5).
Patch 1 adds the get/set tunable implementation.
Patch 2 enables downshift by default with a count of 2.
Based on an earlier downstream implementation by Phil Elwell.
Tested on Raspberry Pi 3B+ (LAN7515/LAN88xx).
Changes since v1:
- Replace switch statements with FIELD_GET()/FIELD_PREP() (Andrew Lunn)
- Drop unused per-count register defines from microchipphy.h
Nicolai Buchwitz (2):
net: phy: microchip: add downshift tunable support for LAN88xx
net: phy: microchip: enable downshift by default on LAN88xx
drivers/net/phy/microchip.c | 71 +++++++++++++++++++++++++++++++++++-
include/linux/microchipphy.h | 5 +++
2 files changed, 75 insertions(+), 1 deletion(-)
--
2.51.0
^ permalink raw reply
* [PATCH v2 1/2] net: phy: microchip: add downshift tunable support for LAN88xx
From: Nicolai Buchwitz @ 2026-03-30 22:46 UTC (permalink / raw)
To: netdev
Cc: Phil Elwell, Nicolai Buchwitz, Andrew Lunn, Heiner Kallweit,
Russell King, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, linux-kernel
In-Reply-To: <20260330224630.579937-1-nb@tipi-net.de>
Implement the standard ETHTOOL_PHY_DOWNSHIFT tunable for the LAN88xx
PHY. This allows runtime configuration of the auto-downshift feature
via ethtool:
ethtool --set-phy-tunable eth0 downshift on count 3
The LAN88xx PHY supports downshifting from 1000BASE-T to 100BASE-TX
after 2-5 failed auto-negotiation attempts. Valid count values are
2, 3, 4 and 5.
This is based on an earlier downstream implementation by Phil Elwell.
Signed-off-by: Nicolai Buchwitz <nb@tipi-net.de>
---
drivers/net/phy/microchip.c | 64 ++++++++++++++++++++++++++++++++++++
include/linux/microchipphy.h | 5 +++
2 files changed, 69 insertions(+)
diff --git a/drivers/net/phy/microchip.c b/drivers/net/phy/microchip.c
index dc8634e7bcbe..bc293d2dd130 100644
--- a/drivers/net/phy/microchip.c
+++ b/drivers/net/phy/microchip.c
@@ -2,6 +2,7 @@
/*
* Copyright (C) 2015 Microchip Technology
*/
+#include <linux/bitfield.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mii.h>
@@ -193,6 +194,67 @@ static void lan88xx_config_TR_regs(struct phy_device *phydev)
phydev_warn(phydev, "Failed to Set Register[0x1686]\n");
}
+static int lan88xx_get_downshift(struct phy_device *phydev, u8 *data)
+{
+ int val;
+
+ val = phy_read_paged(phydev, 1, LAN78XX_PHY_CTRL3);
+ if (val < 0)
+ return val;
+
+ if (!(val & LAN78XX_PHY_CTRL3_AUTO_DOWNSHIFT)) {
+ *data = DOWNSHIFT_DEV_DISABLE;
+ return 0;
+ }
+
+ *data = FIELD_GET(LAN78XX_PHY_CTRL3_DOWNSHIFT_CTRL_MASK, val) + 2;
+
+ return 0;
+}
+
+static int lan88xx_set_downshift(struct phy_device *phydev, u8 cnt)
+{
+ u32 mask = LAN78XX_PHY_CTRL3_DOWNSHIFT_CTRL_MASK |
+ LAN78XX_PHY_CTRL3_AUTO_DOWNSHIFT;
+
+ if (cnt == DOWNSHIFT_DEV_DISABLE)
+ return phy_modify_paged(phydev, 1, LAN78XX_PHY_CTRL3,
+ LAN78XX_PHY_CTRL3_AUTO_DOWNSHIFT, 0);
+
+ if (cnt == DOWNSHIFT_DEV_DEFAULT_COUNT)
+ cnt = 2;
+
+ if (cnt < 2 || cnt > 5)
+ return -EINVAL;
+
+ return phy_modify_paged(phydev, 1, LAN78XX_PHY_CTRL3, mask,
+ FIELD_PREP(LAN78XX_PHY_CTRL3_DOWNSHIFT_CTRL_MASK,
+ cnt - 2) |
+ LAN78XX_PHY_CTRL3_AUTO_DOWNSHIFT);
+}
+
+static int lan88xx_get_tunable(struct phy_device *phydev,
+ struct ethtool_tunable *tuna, void *data)
+{
+ switch (tuna->id) {
+ case ETHTOOL_PHY_DOWNSHIFT:
+ return lan88xx_get_downshift(phydev, data);
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static int lan88xx_set_tunable(struct phy_device *phydev,
+ struct ethtool_tunable *tuna, const void *data)
+{
+ switch (tuna->id) {
+ case ETHTOOL_PHY_DOWNSHIFT:
+ return lan88xx_set_downshift(phydev, *(const u8 *)data);
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
static int lan88xx_probe(struct phy_device *phydev)
{
struct device *dev = &phydev->mdio.dev;
@@ -499,6 +561,8 @@ static struct phy_driver microchip_phy_driver[] = {
.set_wol = lan88xx_set_wol,
.read_page = lan88xx_read_page,
.write_page = lan88xx_write_page,
+ .get_tunable = lan88xx_get_tunable,
+ .set_tunable = lan88xx_set_tunable,
},
{
PHY_ID_MATCH_MODEL(PHY_ID_LAN937X_TX),
diff --git a/include/linux/microchipphy.h b/include/linux/microchipphy.h
index 517288da19fd..7da956c666a0 100644
--- a/include/linux/microchipphy.h
+++ b/include/linux/microchipphy.h
@@ -61,6 +61,11 @@
/* Registers specific to the LAN7800/LAN7850 embedded phy */
#define LAN78XX_PHY_LED_MODE_SELECT (0x1D)
+/* PHY Control 3 register (page 1) */
+#define LAN78XX_PHY_CTRL3 (0x14)
+#define LAN78XX_PHY_CTRL3_AUTO_DOWNSHIFT BIT(4)
+#define LAN78XX_PHY_CTRL3_DOWNSHIFT_CTRL_MASK GENMASK(3, 2)
+
/* DSP registers */
#define PHY_ARDENNES_MMD_DEV_3_PHY_CFG (0x806A)
#define PHY_ARDENNES_MMD_DEV_3_PHY_CFG_ZD_DLY_EN_ (0x2000)
--
2.51.0
^ permalink raw reply related
* [PATCH v2 2/2] net: phy: microchip: enable downshift by default on LAN88xx
From: Nicolai Buchwitz @ 2026-03-30 22:46 UTC (permalink / raw)
To: netdev
Cc: Phil Elwell, Nicolai Buchwitz, Andrew Lunn, Heiner Kallweit,
Russell King, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, linux-kernel
In-Reply-To: <20260330224630.579937-1-nb@tipi-net.de>
Enable auto-downshift from 1000BASE-T to 100BASE-TX after 2 failed
auto-negotiation attempts by default. This ensures that links with
faulty or missing cable pairs (C and D) fall back to 100Mbps without
requiring userspace configuration.
Users can override or disable downshift at runtime:
ethtool --set-phy-tunable eth0 downshift off
Signed-off-by: Nicolai Buchwitz <nb@tipi-net.de>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
---
drivers/net/phy/microchip.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/drivers/net/phy/microchip.c b/drivers/net/phy/microchip.c
index bc293d2dd130..802b8a6e54e6 100644
--- a/drivers/net/phy/microchip.c
+++ b/drivers/net/phy/microchip.c
@@ -346,7 +346,7 @@ static void lan88xx_set_mdix(struct phy_device *phydev)
static int lan88xx_config_init(struct phy_device *phydev)
{
- int val;
+ int val, err;
/*Zerodetect delay enable */
val = phy_read_mmd(phydev, MDIO_MMD_PCS,
@@ -359,6 +359,11 @@ static int lan88xx_config_init(struct phy_device *phydev)
/* Config DSP registers */
lan88xx_config_TR_regs(phydev);
+ /* Enable downshift after 2 failed attempts by default */
+ err = lan88xx_set_downshift(phydev, 2);
+ if (err < 0)
+ return err;
+
return 0;
}
--
2.51.0
^ permalink raw reply related
* Re: [PATCH net-next,v4] net: mana: Force full-page RX buffers via ethtool private flag
From: Jakub Kicinski @ 2026-03-30 22:47 UTC (permalink / raw)
To: Dipayaan Roy
Cc: kys, haiyangz, wei.liu, decui, andrew+netdev, davem, edumazet,
pabeni, leon, longli, kotaranov, horms, shradhagupta, ssengar,
ernis, shirazsaleem, linux-hyperv, netdev, linux-kernel,
linux-rdma, stephen, jacob.e.keller, leitao, kees, dipayanroy
In-Reply-To: <acrkwuIFyBXhwICF@linuxonhyperv3.guj3yctzbm1etfxqx2vob5hsef.xx.internal.cloudapp.net>
On Mon, 30 Mar 2026 14:01:54 -0700 Dipayaan Roy wrote:
> On some ARM64 platforms with 4K PAGE_SIZE, page_pool fragment
> allocation in the RX refill path can cause 15-20% throughput
> regression under high connection counts (>16 TCP streams).
Did you investigate what makes such a difference exactly?
As I said I suspect there are some improvements we could
make in the page pool fragmentation logic that could yield
similar wins without bothering the user.
> Add an ethtool private flag "full-page-rx" that allows the user to
> force one RX buffer per page, bypassing the page_pool fragment path.
> This restores line-rate(180+ Gbps) performance on affected platforms.
>
> Usage:
> ethtool --set-priv-flags eth0 full-page-rx on
>
> There is no behavioral change by default. The flag must be explicitly
> enabled by the user or udev rule.
>
> The existing single-buffer-per-page logic for XDP and jumbo frames is
> consolidated into a new helper mana_use_single_rxbuf_per_page().
ethtool -g rx-buf-len could also fit the bill but I guess this is more
of a hack / workaround than legit config so no strong preference.
> -static void mana_get_strings(struct net_device *ndev, u32 stringset, u8 *data)
> +static void mana_get_strings_stats(struct mana_port_context *apc, u8 **data)
> {
> - struct mana_port_context *apc = netdev_priv(ndev);
> unsigned int num_queues = apc->num_queues;
> int i, j;
>
> - if (stringset != ETH_SS_STATS)
> - return;
> for (i = 0; i < ARRAY_SIZE(mana_eth_stats); i++)
> - ethtool_puts(&data, mana_eth_stats[i].name);
> + ethtool_puts(data, mana_eth_stats[i].name);
>
> for (i = 0; i < ARRAY_SIZE(mana_hc_stats); i++)
> - ethtool_puts(&data, mana_hc_stats[i].name);
> + ethtool_puts(data, mana_hc_stats[i].name);
>
> for (i = 0; i < ARRAY_SIZE(mana_phy_stats); i++)
> - ethtool_puts(&data, mana_phy_stats[i].name);
> + ethtool_puts(data, mana_phy_stats[i].name);
>
> for (i = 0; i < num_queues; i++) {
> - ethtool_sprintf(&data, "rx_%d_packets", i);
> - ethtool_sprintf(&data, "rx_%d_bytes", i);
> - ethtool_sprintf(&data, "rx_%d_xdp_drop", i);
> - ethtool_sprintf(&data, "rx_%d_xdp_tx", i);
> - ethtool_sprintf(&data, "rx_%d_xdp_redirect", i);
> - ethtool_sprintf(&data, "rx_%d_pkt_len0_err", i);
> + ethtool_sprintf(data, "rx_%d_packets", i);
Please factor out the noisy, no-op prep work into a separate patch for
ease of review
--
pw-bot: cr
^ permalink raw reply
* [PATCH net-next] net: dsa: mxl862xx: cancel pending work on probe error
From: Daniel Golle @ 2026-03-30 22:52 UTC (permalink / raw)
To: Daniel Golle, Andrew Lunn, Vladimir Oltean, David S. Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni, netdev, linux-kernel
Call mxl862xx_host_shutdown() in case dsa_register_switch() returns
an error, so any still pending crc_err_work get canceled.
Fixes: a319d0c8c8ce ("net: dsa: mxl862xx: add CRC for MDIO communication")
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
---
Note that this targets net-next despite having a Fixes:-tag because the
is still only in net-next.
drivers/net/dsa/mxl862xx/mxl862xx.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/drivers/net/dsa/mxl862xx/mxl862xx.c b/drivers/net/dsa/mxl862xx/mxl862xx.c
index 78eef639628a0..af9b00b2d2c43 100644
--- a/drivers/net/dsa/mxl862xx/mxl862xx.c
+++ b/drivers/net/dsa/mxl862xx/mxl862xx.c
@@ -407,6 +407,7 @@ static int mxl862xx_probe(struct mdio_device *mdiodev)
struct device *dev = &mdiodev->dev;
struct mxl862xx_priv *priv;
struct dsa_switch *ds;
+ int err;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
@@ -428,7 +429,11 @@ static int mxl862xx_probe(struct mdio_device *mdiodev)
dev_set_drvdata(dev, ds);
- return dsa_register_switch(ds);
+ err = dsa_register_switch(ds);
+ if (err)
+ mxl862xx_host_shutdown(priv);
+
+ return err;
}
static void mxl862xx_remove(struct mdio_device *mdiodev)
--
2.53.0
^ permalink raw reply related
* [PATCH net-next v3] net: phy: bcm84881: add BCM84891/BCM84892 support
From: Daniel Wagner @ 2026-03-30 22:53 UTC (permalink / raw)
To: netdev
Cc: Florian Fainelli, Andrew Lunn, Heiner Kallweit, Russell King,
bcm-kernel-feedback-list, Jakub Kicinski, Eric Dumazet,
Paolo Abeni, Nicolai Buchwitz, Daniel Wagner
The BCM84891 and BCM84892 are 10GBASE-T PHYs in the same family as the
BCM84881, sharing the register map and most callbacks. They add USXGMII
as a host interface mode.
bcm8489x_config_init() is separate from bcm84881_config_init(): it
allows only USXGMII (the only host mode available on the tested
hardware) and clears MDIO_CTRL1_LPOWER, which is set at boot on the
tested platform. Does not recur on ifdown/ifup, cable events, or
link-partner advertisement changes, so config_init is sufficient.
For USXGMII, read_status() skips the 0x4011 host-mode register: it
returns the same value regardless of negotiated copper speed (USXGMII
symbol replication). Speed comes from phy_resolve_aneg_linkmode() via
standard C45 AN resolution.
Tested on TRENDnet TEG-S750 (RTL9303 + 1x BCM84891 + 4x BCM84892)
running OpenWrt, where the MDIO controller driver is currently
OpenWrt-specific. Link verified at 100M, 1G, 2.5G, 10G.
Signed-off-by: Daniel Wagner <wagner.daniel.t@gmail.com>
Reviewed-by: Florian Fainelli <florian.fainelli@broadcom.com>
Reviewed-by: Nicolai Buchwitz <nb@tipi-net.de>
---
v3: No code changes. Resend per Jakub's request (v2 was posted while
the v1 discussion was still ongoing). Collected Reviewed-by tags.
v2: https://lore.kernel.org/netdev/20260324190601.1616343-1-wagner.daniel.t@gmail.com/
- Separate bcm8489x_config_init() that allows only USXGMII. v1 also
allowed USXGMII for BCM84881 (which doesn't support it), and put
SGMII/2500BASEX/10GBASER in the 8489x possible_interfaces which I
can't substantiate on this hardware. (Russell)
- LPOWER clear moved from config_aneg to config_init. Characterized on
hardware: boot-time only, does not recur on ifdown/ifup, cable
events, or link-partner advertisement changes. (Russell)
- Dropped LED support; will figure out the PHY LED framework approach
for bicolor speed-mapped LEDs as a follow-up. (Russell, Andrew)
- PHY_ID_MATCH_MODEL(). (Russell, Andrew)
- is_bcm8489x() helper removed; the interface mode now suffices as a
discriminator in read_status since only the 8489x config_init allows
USXGMII.
v1: https://lore.kernel.org/netdev/20260324152503.1522071-2-wagner.daniel.t@gmail.com/
drivers/net/phy/bcm84881.c | 48 +++++++++++++++++++++++++++++++++++++-
1 file changed, 47 insertions(+), 1 deletion(-)
diff --git a/drivers/net/phy/bcm84881.c b/drivers/net/phy/bcm84881.c
index d7f7cc44c5..f114212dd3 100644
--- a/drivers/net/phy/bcm84881.c
+++ b/drivers/net/phy/bcm84881.c
@@ -54,6 +54,21 @@ static int bcm84881_config_init(struct phy_device *phydev)
return 0;
}
+static int bcm8489x_config_init(struct phy_device *phydev)
+{
+ __set_bit(PHY_INTERFACE_MODE_USXGMII, phydev->possible_interfaces);
+
+ if (phydev->interface != PHY_INTERFACE_MODE_USXGMII)
+ return -ENODEV;
+
+ /* MDIO_CTRL1_LPOWER is set at boot on the tested platform. Does not
+ * recur on ifdown/ifup, cable events, or link-partner advertisement
+ * changes; clear it once.
+ */
+ return phy_clear_bits_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_CTRL1,
+ MDIO_CTRL1_LPOWER);
+}
+
static int bcm84881_probe(struct phy_device *phydev)
{
/* This driver requires PMAPMD and AN blocks */
@@ -201,6 +216,15 @@ static int bcm84881_read_status(struct phy_device *phydev)
return 0;
}
+ /* BCM84891/92 on USXGMII: the host interface mode doesn't change
+ * with copper speed (USXGMII symbol replication; the MAC receives
+ * the negotiated copper speed, not 10G, so no rate adaptation).
+ * Skip 0x4011; phy_resolve_aneg_linkmode() above already set the
+ * speed. Only bcm8489x_config_init() allows USXGMII.
+ */
+ if (phydev->interface == PHY_INTERFACE_MODE_USXGMII)
+ return genphy_c45_read_mdix(phydev);
+
/* Set the host link mode - we set the phy interface mode and
* the speed according to this register so that downshift works.
* We leave the duplex setting as per the resolution from the
@@ -256,6 +280,26 @@ static struct phy_driver bcm84881_drivers[] = {
.config_aneg = bcm84881_config_aneg,
.aneg_done = bcm84881_aneg_done,
.read_status = bcm84881_read_status,
+ }, {
+ PHY_ID_MATCH_MODEL(0x35905080),
+ .name = "Broadcom BCM84891",
+ .inband_caps = bcm84881_inband_caps,
+ .config_init = bcm8489x_config_init,
+ .probe = bcm84881_probe,
+ .get_features = bcm84881_get_features,
+ .config_aneg = bcm84881_config_aneg,
+ .aneg_done = bcm84881_aneg_done,
+ .read_status = bcm84881_read_status,
+ }, {
+ PHY_ID_MATCH_MODEL(0x359050a0),
+ .name = "Broadcom BCM84892",
+ .inband_caps = bcm84881_inband_caps,
+ .config_init = bcm8489x_config_init,
+ .probe = bcm84881_probe,
+ .get_features = bcm84881_get_features,
+ .config_aneg = bcm84881_config_aneg,
+ .aneg_done = bcm84881_aneg_done,
+ .read_status = bcm84881_read_status,
},
};
@@ -264,9 +308,11 @@ module_phy_driver(bcm84881_drivers);
/* FIXME: module auto-loading for Clause 45 PHYs seems non-functional */
static const struct mdio_device_id __maybe_unused bcm84881_tbl[] = {
{ 0xae025150, 0xfffffff0 },
+ { PHY_ID_MATCH_MODEL(0x35905080) },
+ { PHY_ID_MATCH_MODEL(0x359050a0) },
{ },
};
MODULE_AUTHOR("Russell King");
-MODULE_DESCRIPTION("Broadcom BCM84881 PHY driver");
+MODULE_DESCRIPTION("Broadcom BCM84881/BCM84891/BCM84892 PHY driver");
MODULE_DEVICE_TABLE(mdio, bcm84881_tbl);
MODULE_LICENSE("GPL");
--
2.47.3
^ permalink raw reply related
* [PATCH net-next 00/15][pull request] Intel Wired LAN Driver Updates 2026-03-30 (igc, igb, ice)
From: Tony Nguyen @ 2026-03-30 23:02 UTC (permalink / raw)
To: davem, kuba, pabeni, edumazet, andrew+netdev, netdev; +Cc: Tony Nguyen
For igc:
Mika Westerberg makes improvements to power management flows with a
focus on PTM.
Kohei Enju adds ethtool support for get/set hash key.
Maximilian Pezzullo fixes some typos.
For igb:
Takashi Kozu adds ethtool support for get/set hash key.
Kohei Enju adds setting of skb hash type based on values from Rx
descriptor.
Maximilian Pezzullo fixes some typos here as well.
For ice:
Arkadiusz adds support for unmanaged DPLL for ice E830 devices; device
settings are fixed but can be queried by DPLL.
Jake adds clarification for needed action on devlink reload command.
Przemyslaw Korba expands the size of a char array to silence a
format-truncation warning.
The following are changes since commit cf0d9080c6f795bc6be08babbffa29b62c06e9b0:
Merge branch 'net-hsr-subsystem-cleanups-and-modernization'
and are available in the git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/tnguy/next-queue 1GbE
Arkadiusz Kubalewski (1):
ice: add support for unmanaged DPLL on E830 NIC
Jacob Keller (1):
ice: mention fw_activate action along with devlink reload
Kohei Enju (4):
igc: prepare for RSS key get/set support
igc: expose RSS key via ethtool get_rxfh
igc: allow configuring RSS key via ethtool set_rxfh
igb: set skb hash type from RSS_TYPE
Maximilian Pezzullo (2):
igb: fix typos in comments
igc: fix typos in comments
Mika Westerberg (3):
igc: Call netif_queue_set_napi() with rtnl locked
igc: Let the PCI core deal with the PM resume flow
igc: Don't reset the hardware on suspend path
Przemyslaw Korba (1):
ice: dpll: Fix compilation warning
Takashi Kozu (3):
igb: prepare for RSS key get/set support
igb: expose RSS key via ethtool get_rxfh
igb: allow configuring RSS key via ethtool set_rxfh
.../device_drivers/ethernet/intel/ice.rst | 83 +++++
.../net/ethernet/intel/ice/devlink/health.c | 4 +
.../net/ethernet/intel/ice/ice_adminq_cmd.h | 12 +
drivers/net/ethernet/intel/ice/ice_common.c | 136 ++++++++
drivers/net/ethernet/intel/ice/ice_common.h | 8 +
drivers/net/ethernet/intel/ice/ice_dpll.c | 304 ++++++++++++++++--
drivers/net/ethernet/intel/ice/ice_dpll.h | 10 +
.../net/ethernet/intel/ice/ice_fw_update.c | 2 +-
drivers/net/ethernet/intel/ice/ice_main.c | 11 +-
drivers/net/ethernet/intel/ice/ice_ptp_hw.c | 46 +++
drivers/net/ethernet/intel/ice/ice_ptp_hw.h | 1 +
drivers/net/ethernet/intel/igb/e1000_82575.h | 21 ++
.../net/ethernet/intel/igb/e1000_defines.h | 2 +-
drivers/net/ethernet/intel/igb/e1000_mac.c | 2 +-
drivers/net/ethernet/intel/igb/e1000_mbx.h | 2 +-
drivers/net/ethernet/intel/igb/e1000_nvm.c | 2 +-
drivers/net/ethernet/intel/igb/igb.h | 3 +
drivers/net/ethernet/intel/igb/igb_ethtool.c | 85 +++--
drivers/net/ethernet/intel/igb/igb_main.c | 25 +-
drivers/net/ethernet/intel/igc/igc.h | 5 +-
drivers/net/ethernet/intel/igc/igc_diag.c | 2 +-
drivers/net/ethernet/intel/igc/igc_ethtool.c | 73 +++--
drivers/net/ethernet/intel/igc/igc_main.c | 43 ++-
23 files changed, 774 insertions(+), 108 deletions(-)
--
2.47.1
^ permalink raw reply
* [PATCH net-next 01/15] igc: Call netif_queue_set_napi() with rtnl locked
From: Tony Nguyen @ 2026-03-30 23:02 UTC (permalink / raw)
To: davem, kuba, pabeni, edumazet, andrew+netdev, netdev
Cc: Mika Westerberg, anthony.l.nguyen, andriy.shevchenko,
ilpo.jarvinen, dima.ruinskiy, mbloch, leon, linux-pci, saeedm,
tariqt, lukas, bhelgaas, richardcochran, Vinicius Costa Gomes,
Jacob Keller, Avigail Dahan
In-Reply-To: <20260330230248.646900-1-anthony.l.nguyen@intel.com>
From: Mika Westerberg <mika.westerberg@linux.intel.com>
When runtime resuming igc we get:
[ 516.161666] RTNL: assertion failed at ./include/net/netdev_lock.h (72)
Happens because commit 310ae9eb2617 ("net: designate queue -> napi
linking as "ops protected"") added check for this. For this reason drop
the special case for runtime PM from __igc_resume(). This makes it take
rtnl lock unconditionally.
Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Acked-by: Vinicius Costa Gomes <vinicius.gomes@intel.com>
Reviewed-by: Jacob Keller <jacob.e.keller@intel.com>
Tested-by: Avigail Dahan <avigailx.dahan@intel.com>
Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
---
drivers/net/ethernet/intel/igc/igc_main.c | 12 +++++-------
1 file changed, 5 insertions(+), 7 deletions(-)
diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c
index 72bc5128d8b8..98024b46789f 100644
--- a/drivers/net/ethernet/intel/igc/igc_main.c
+++ b/drivers/net/ethernet/intel/igc/igc_main.c
@@ -7536,7 +7536,7 @@ static void igc_deliver_wake_packet(struct net_device *netdev)
netif_rx(skb);
}
-static int __igc_resume(struct device *dev, bool rpm)
+static int __igc_resume(struct device *dev)
{
struct pci_dev *pdev = to_pci_dev(dev);
struct net_device *netdev = pci_get_drvdata(pdev);
@@ -7581,11 +7581,9 @@ static int __igc_resume(struct device *dev, bool rpm)
wr32(IGC_WUS, ~0);
if (netif_running(netdev)) {
- if (!rpm)
- rtnl_lock();
+ rtnl_lock();
err = __igc_open(netdev, true);
- if (!rpm)
- rtnl_unlock();
+ rtnl_unlock();
if (!err)
netif_device_attach(netdev);
}
@@ -7595,12 +7593,12 @@ static int __igc_resume(struct device *dev, bool rpm)
static int igc_resume(struct device *dev)
{
- return __igc_resume(dev, false);
+ return __igc_resume(dev);
}
static int igc_runtime_resume(struct device *dev)
{
- return __igc_resume(dev, true);
+ return __igc_resume(dev);
}
static int igc_suspend(struct device *dev)
--
2.47.1
^ permalink raw reply related
* [PATCH net-next 02/15] igc: Let the PCI core deal with the PM resume flow
From: Tony Nguyen @ 2026-03-30 23:02 UTC (permalink / raw)
To: davem, kuba, pabeni, edumazet, andrew+netdev, netdev
Cc: Mika Westerberg, anthony.l.nguyen, andriy.shevchenko,
ilpo.jarvinen, dima.ruinskiy, mbloch, leon, linux-pci, saeedm,
tariqt, lukas, bhelgaas, richardcochran, Vinicius Costa Gomes,
Jacob Keller, Avigail Dahan
In-Reply-To: <20260330230248.646900-1-anthony.l.nguyen@intel.com>
From: Mika Westerberg <mika.westerberg@linux.intel.com>
Currently igc driver calls pci_set_power_state() and pci_restore_state()
and the like to bring the device back from low power states. However,
PCI core handles all this on behalf of the driver. Furthermore with PTM
enabled the PCI core re-enables it on resume but the driver calls
pci_restore_state() which ends up disabling it again.
For this reason let the PCI core handle the common PM resume flow.
Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@intel.com>
Acked-by: Vinicius Costa Gomes <vinicius.gomes@intel.com>
Reviewed-by: Jacob Keller <jacob.e.keller@intel.com>
Tested-by: Avigail Dahan <avigailx.dahan@intel.com>
Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
---
drivers/net/ethernet/intel/igc/igc_main.c | 6 ------
1 file changed, 6 deletions(-)
diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c
index 98024b46789f..0e785af0a3a3 100644
--- a/drivers/net/ethernet/intel/igc/igc_main.c
+++ b/drivers/net/ethernet/intel/igc/igc_main.c
@@ -7544,9 +7544,6 @@ static int __igc_resume(struct device *dev)
struct igc_hw *hw = &adapter->hw;
u32 err, val;
- pci_set_power_state(pdev, PCI_D0);
- pci_restore_state(pdev);
-
if (!pci_device_is_present(pdev))
return -ENODEV;
err = pci_enable_device_mem(pdev);
@@ -7556,9 +7553,6 @@ static int __igc_resume(struct device *dev)
}
pci_set_master(pdev);
- pci_enable_wake(pdev, PCI_D3hot, 0);
- pci_enable_wake(pdev, PCI_D3cold, 0);
-
if (igc_is_device_id_i226(hw))
pci_disable_link_state(pdev, PCIE_LINK_STATE_L1_2);
--
2.47.1
^ permalink raw reply related
* [PATCH net-next 03/15] igc: Don't reset the hardware on suspend path
From: Tony Nguyen @ 2026-03-30 23:02 UTC (permalink / raw)
To: davem, kuba, pabeni, edumazet, andrew+netdev, netdev
Cc: Mika Westerberg, anthony.l.nguyen, andriy.shevchenko,
ilpo.jarvinen, dima.ruinskiy, mbloch, leon, linux-pci, saeedm,
tariqt, lukas, bhelgaas, richardcochran, Vinicius Costa Gomes,
Jacob Keller, Avigail Dahan
In-Reply-To: <20260330230248.646900-1-anthony.l.nguyen@intel.com>
From: Mika Westerberg <mika.westerberg@linux.intel.com>
Commit c01163dbd1b8 ("PCI/PM: Always disable PTM for all devices during
suspend") made the PCI core to suspend (disable) PTM before driver
suspend hooks are called. In case of igc what happens is that on suspend
path PCI core calls pci_suspend_ptm() then igc suspend hook that calls
igc_down() that ends up calling igc_ptp_reset() (which according to the
comment is actually needed for re-enabling the device). Anyways that
function also poll IGC_PTM_STAT that will end up timing out because PTM
is already disabled:
[ 160.716119] igc 0000:03:00.0 enp3s0: Timeout reading IGC_PTM_STAT register
There should be no reason resetting the hardware on suspend path so fix
this by avoiding the reset.
Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Acked-by: Vinicius Costa Gomes <vinicius.gomes@intel.com>
Reviewed-by: Jacob Keller <jacob.e.keller@intel.com>
Tested-by: Avigail Dahan <avigailx.dahan@intel.com>
Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
---
drivers/net/ethernet/intel/igc/igc.h | 2 +-
drivers/net/ethernet/intel/igc/igc_ethtool.c | 6 +++---
drivers/net/ethernet/intel/igc/igc_main.c | 13 +++++++------
3 files changed, 11 insertions(+), 10 deletions(-)
diff --git a/drivers/net/ethernet/intel/igc/igc.h b/drivers/net/ethernet/intel/igc/igc.h
index 17236813965d..caa5b89b2b24 100644
--- a/drivers/net/ethernet/intel/igc/igc.h
+++ b/drivers/net/ethernet/intel/igc/igc.h
@@ -349,7 +349,7 @@ struct igc_adapter {
};
void igc_up(struct igc_adapter *adapter);
-void igc_down(struct igc_adapter *adapter);
+void igc_down(struct igc_adapter *adapter, bool reset);
int igc_open(struct net_device *netdev);
int igc_close(struct net_device *netdev);
int igc_setup_tx_resources(struct igc_ring *ring);
diff --git a/drivers/net/ethernet/intel/igc/igc_ethtool.c b/drivers/net/ethernet/intel/igc/igc_ethtool.c
index 0122009bedd0..4d1bcc19255f 100644
--- a/drivers/net/ethernet/intel/igc/igc_ethtool.c
+++ b/drivers/net/ethernet/intel/igc/igc_ethtool.c
@@ -638,7 +638,7 @@ igc_ethtool_set_ringparam(struct net_device *netdev,
goto clear_reset;
}
- igc_down(adapter);
+ igc_down(adapter, true);
/* We can't just free everything and then setup again,
* because the ISRs in MSI-X mode get passed pointers
@@ -737,7 +737,7 @@ static int igc_ethtool_set_pauseparam(struct net_device *netdev,
if (adapter->fc_autoneg == AUTONEG_ENABLE) {
hw->fc.requested_mode = igc_fc_default;
if (netif_running(adapter->netdev)) {
- igc_down(adapter);
+ igc_down(adapter, true);
igc_up(adapter);
} else {
igc_reset(adapter);
@@ -2077,7 +2077,7 @@ igc_ethtool_set_link_ksettings(struct net_device *netdev,
/* reset the link */
if (netif_running(adapter->netdev)) {
- igc_down(adapter);
+ igc_down(adapter, true);
igc_up(adapter);
} else {
igc_reset(adapter);
diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c
index 0e785af0a3a3..80a90ce0ad0e 100644
--- a/drivers/net/ethernet/intel/igc/igc_main.c
+++ b/drivers/net/ethernet/intel/igc/igc_main.c
@@ -5312,8 +5312,9 @@ void igc_update_stats(struct igc_adapter *adapter)
/**
* igc_down - Close the interface
* @adapter: board private structure
+ * @reset: issue reset
*/
-void igc_down(struct igc_adapter *adapter)
+void igc_down(struct igc_adapter *adapter, bool reset)
{
struct net_device *netdev = adapter->netdev;
struct igc_hw *hw = &adapter->hw;
@@ -5369,7 +5370,7 @@ void igc_down(struct igc_adapter *adapter)
adapter->link_speed = 0;
adapter->link_duplex = 0;
- if (!pci_channel_offline(adapter->pdev))
+ if (reset && !pci_channel_offline(adapter->pdev))
igc_reset(adapter);
/* clear VLAN promisc flag so VFTA will be updated if necessary */
@@ -5387,7 +5388,7 @@ void igc_reinit_locked(struct igc_adapter *adapter)
{
while (test_and_set_bit(__IGC_RESETTING, &adapter->state))
usleep_range(1000, 2000);
- igc_down(adapter);
+ igc_down(adapter, true);
igc_up(adapter);
clear_bit(__IGC_RESETTING, &adapter->state);
}
@@ -5441,7 +5442,7 @@ static int igc_change_mtu(struct net_device *netdev, int new_mtu)
adapter->max_frame_size = max_frame;
if (netif_running(netdev))
- igc_down(adapter);
+ igc_down(adapter, true);
netdev_dbg(netdev, "changing MTU from %d to %d\n", netdev->mtu, new_mtu);
WRITE_ONCE(netdev->mtu, new_mtu);
@@ -6305,7 +6306,7 @@ static int __igc_close(struct net_device *netdev, bool suspending)
if (!suspending)
pm_runtime_get_sync(&pdev->dev);
- igc_down(adapter);
+ igc_down(adapter, !suspending);
igc_release_hw_control(adapter);
@@ -7646,7 +7647,7 @@ static pci_ers_result_t igc_io_error_detected(struct pci_dev *pdev,
}
if (netif_running(netdev))
- igc_down(adapter);
+ igc_down(adapter, true);
pci_disable_device(pdev);
rtnl_unlock();
--
2.47.1
^ permalink raw reply related
* [PATCH net-next 04/15] igc: prepare for RSS key get/set support
From: Tony Nguyen @ 2026-03-30 23:02 UTC (permalink / raw)
To: davem, kuba, pabeni, edumazet, andrew+netdev, netdev
Cc: Kohei Enju, anthony.l.nguyen, dima.ruinskiy, kohei.enju, horms,
Aleksandr Loktionov, Avigail Dahan
In-Reply-To: <20260330230248.646900-1-anthony.l.nguyen@intel.com>
From: Kohei Enju <kohei@enjuk.jp>
Store the RSS key inside struct igc_adapter and introduce the
igc_write_rss_key() helper function. This allows the driver to program
the RSSRK registers using a persistent RSS key, instead of using a
stack-local buffer in igc_setup_mrqc().
This is a preparation patch for adding RSS key get/set support in
subsequent changes, and no functional change is intended in this patch.
Signed-off-by: Kohei Enju <kohei@enjuk.jp>
Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
Reviewed-by: Simon Horman <horms@kernel.org>
Tested-by: Avigail Dahan <avigailx.dahan@intel.com>
Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
---
drivers/net/ethernet/intel/igc/igc.h | 3 +++
drivers/net/ethernet/intel/igc/igc_ethtool.c | 20 ++++++++++++++++++++
drivers/net/ethernet/intel/igc/igc_main.c | 8 ++++----
3 files changed, 27 insertions(+), 4 deletions(-)
diff --git a/drivers/net/ethernet/intel/igc/igc.h b/drivers/net/ethernet/intel/igc/igc.h
index caa5b89b2b24..e66799507f81 100644
--- a/drivers/net/ethernet/intel/igc/igc.h
+++ b/drivers/net/ethernet/intel/igc/igc.h
@@ -30,6 +30,7 @@ void igc_ethtool_set_ops(struct net_device *);
#define MAX_ETYPE_FILTER 8
#define IGC_RETA_SIZE 128
+#define IGC_RSS_KEY_SIZE 40
/* SDP support */
#define IGC_N_EXTTS 2
@@ -302,6 +303,7 @@ struct igc_adapter {
unsigned int nfc_rule_count;
u8 rss_indir_tbl[IGC_RETA_SIZE];
+ u8 rss_key[IGC_RSS_KEY_SIZE];
unsigned long link_check_timeout;
struct igc_info ei;
@@ -360,6 +362,7 @@ unsigned int igc_get_max_rss_queues(struct igc_adapter *adapter);
void igc_set_flag_queue_pairs(struct igc_adapter *adapter,
const u32 max_rss_queues);
int igc_reinit_queues(struct igc_adapter *adapter);
+void igc_write_rss_key(struct igc_adapter *adapter);
void igc_write_rss_indir_tbl(struct igc_adapter *adapter);
bool igc_has_link(struct igc_adapter *adapter);
void igc_reset(struct igc_adapter *adapter);
diff --git a/drivers/net/ethernet/intel/igc/igc_ethtool.c b/drivers/net/ethernet/intel/igc/igc_ethtool.c
index 4d1bcc19255f..c2300232c8b1 100644
--- a/drivers/net/ethernet/intel/igc/igc_ethtool.c
+++ b/drivers/net/ethernet/intel/igc/igc_ethtool.c
@@ -1460,6 +1460,26 @@ static int igc_ethtool_set_rxnfc(struct net_device *dev,
}
}
+/**
+ * igc_write_rss_key - Program the RSS key into device registers
+ * @adapter: board private structure
+ *
+ * Write the RSS key stored in adapter->rss_key to the IGC_RSSRK registers.
+ * Each 32-bit chunk of the key is read using get_unaligned_le32() and written
+ * to the appropriate register.
+ */
+void igc_write_rss_key(struct igc_adapter *adapter)
+{
+ struct igc_hw *hw = &adapter->hw;
+ u32 val;
+ int i;
+
+ for (i = 0; i < IGC_RSS_KEY_SIZE / 4; i++) {
+ val = get_unaligned_le32(&adapter->rss_key[i * 4]);
+ wr32(IGC_RSSRK(i), val);
+ }
+}
+
void igc_write_rss_indir_tbl(struct igc_adapter *adapter)
{
struct igc_hw *hw = &adapter->hw;
diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c
index 80a90ce0ad0e..ebd831a4ff53 100644
--- a/drivers/net/ethernet/intel/igc/igc_main.c
+++ b/drivers/net/ethernet/intel/igc/igc_main.c
@@ -785,11 +785,8 @@ static void igc_setup_mrqc(struct igc_adapter *adapter)
struct igc_hw *hw = &adapter->hw;
u32 j, num_rx_queues;
u32 mrqc, rxcsum;
- u32 rss_key[10];
- netdev_rss_key_fill(rss_key, sizeof(rss_key));
- for (j = 0; j < 10; j++)
- wr32(IGC_RSSRK(j), rss_key[j]);
+ igc_write_rss_key(adapter);
num_rx_queues = adapter->rss_queues;
@@ -5048,6 +5045,9 @@ static int igc_sw_init(struct igc_adapter *adapter)
pci_read_config_word(pdev, PCI_COMMAND, &hw->bus.pci_cmd_word);
+ /* init RSS key */
+ netdev_rss_key_fill(adapter->rss_key, sizeof(adapter->rss_key));
+
/* set default ring sizes */
adapter->tx_ring_count = IGC_DEFAULT_TXD;
adapter->rx_ring_count = IGC_DEFAULT_RXD;
--
2.47.1
^ permalink raw reply related
* [PATCH net-next 05/15] igc: expose RSS key via ethtool get_rxfh
From: Tony Nguyen @ 2026-03-30 23:02 UTC (permalink / raw)
To: davem, kuba, pabeni, edumazet, andrew+netdev, netdev
Cc: Kohei Enju, anthony.l.nguyen, dima.ruinskiy, kohei.enju, horms,
Avigail Dahan, Aleksandr Loktionov
In-Reply-To: <20260330230248.646900-1-anthony.l.nguyen@intel.com>
From: Kohei Enju <kohei@enjuk.jp>
Implement igc_ethtool_get_rxfh_key_size() and extend
igc_ethtool_get_rxfh() to return the RSS key to userspace.
This can be tested using `ethtool -x <dev>`.
Signed-off-by: Kohei Enju <kohei@enjuk.jp>
Tested-by: Avigail Dahan <avigailx.dahan@intel.com>
Reviewed-by: Vitaly Lifshits <vitaly.lifshits@intel.com>
Reviewed-by: Simon Horman <horms@kernel.org>
Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
---
drivers/net/ethernet/intel/igc/igc_ethtool.c | 17 +++++++++++++----
1 file changed, 13 insertions(+), 4 deletions(-)
diff --git a/drivers/net/ethernet/intel/igc/igc_ethtool.c b/drivers/net/ethernet/intel/igc/igc_ethtool.c
index c2300232c8b1..abe8eb695c2a 100644
--- a/drivers/net/ethernet/intel/igc/igc_ethtool.c
+++ b/drivers/net/ethernet/intel/igc/igc_ethtool.c
@@ -1502,6 +1502,11 @@ void igc_write_rss_indir_tbl(struct igc_adapter *adapter)
}
}
+static u32 igc_ethtool_get_rxfh_key_size(struct net_device *netdev)
+{
+ return IGC_RSS_KEY_SIZE;
+}
+
static u32 igc_ethtool_get_rxfh_indir_size(struct net_device *netdev)
{
return IGC_RETA_SIZE;
@@ -1514,10 +1519,13 @@ static int igc_ethtool_get_rxfh(struct net_device *netdev,
int i;
rxfh->hfunc = ETH_RSS_HASH_TOP;
- if (!rxfh->indir)
- return 0;
- for (i = 0; i < IGC_RETA_SIZE; i++)
- rxfh->indir[i] = adapter->rss_indir_tbl[i];
+
+ if (rxfh->indir)
+ for (i = 0; i < IGC_RETA_SIZE; i++)
+ rxfh->indir[i] = adapter->rss_indir_tbl[i];
+
+ if (rxfh->key)
+ memcpy(rxfh->key, adapter->rss_key, sizeof(adapter->rss_key));
return 0;
}
@@ -2195,6 +2203,7 @@ static const struct ethtool_ops igc_ethtool_ops = {
.get_rxnfc = igc_ethtool_get_rxnfc,
.set_rxnfc = igc_ethtool_set_rxnfc,
.get_rx_ring_count = igc_ethtool_get_rx_ring_count,
+ .get_rxfh_key_size = igc_ethtool_get_rxfh_key_size,
.get_rxfh_indir_size = igc_ethtool_get_rxfh_indir_size,
.get_rxfh = igc_ethtool_get_rxfh,
.set_rxfh = igc_ethtool_set_rxfh,
--
2.47.1
^ permalink raw reply related
* [PATCH net-next 06/15] igc: allow configuring RSS key via ethtool set_rxfh
From: Tony Nguyen @ 2026-03-30 23:02 UTC (permalink / raw)
To: davem, kuba, pabeni, edumazet, andrew+netdev, netdev
Cc: Kohei Enju, anthony.l.nguyen, dima.ruinskiy, kohei.enju, horms,
Avigail Dahan
In-Reply-To: <20260330230248.646900-1-anthony.l.nguyen@intel.com>
From: Kohei Enju <kohei@enjuk.jp>
Change igc_ethtool_set_rxfh() to accept and save a userspace-provided
RSS key. When a key is provided, store it in the adapter and write the
RSSRK registers accordingly.
This can be tested using `ethtool -X <dev> hkey <key>`.
Signed-off-by: Kohei Enju <kohei@enjuk.jp>
Reviewed-by: Simon Horman <horms@kernel.org>
Tested-by: Avigail Dahan <avigailx.dahan@intel.com>
Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
---
drivers/net/ethernet/intel/igc/igc_ethtool.c | 30 +++++++++++---------
1 file changed, 17 insertions(+), 13 deletions(-)
diff --git a/drivers/net/ethernet/intel/igc/igc_ethtool.c b/drivers/net/ethernet/intel/igc/igc_ethtool.c
index abe8eb695c2a..3a63c6db4241 100644
--- a/drivers/net/ethernet/intel/igc/igc_ethtool.c
+++ b/drivers/net/ethernet/intel/igc/igc_ethtool.c
@@ -1539,24 +1539,28 @@ static int igc_ethtool_set_rxfh(struct net_device *netdev,
int i;
/* We do not allow change in unsupported parameters */
- if (rxfh->key ||
- (rxfh->hfunc != ETH_RSS_HASH_NO_CHANGE &&
- rxfh->hfunc != ETH_RSS_HASH_TOP))
+ if (rxfh->hfunc != ETH_RSS_HASH_NO_CHANGE &&
+ rxfh->hfunc != ETH_RSS_HASH_TOP)
return -EOPNOTSUPP;
- if (!rxfh->indir)
- return 0;
- num_queues = adapter->rss_queues;
+ if (rxfh->indir) {
+ num_queues = adapter->rss_queues;
- /* Verify user input. */
- for (i = 0; i < IGC_RETA_SIZE; i++)
- if (rxfh->indir[i] >= num_queues)
- return -EINVAL;
+ /* Verify user input. */
+ for (i = 0; i < IGC_RETA_SIZE; i++)
+ if (rxfh->indir[i] >= num_queues)
+ return -EINVAL;
- for (i = 0; i < IGC_RETA_SIZE; i++)
- adapter->rss_indir_tbl[i] = rxfh->indir[i];
+ for (i = 0; i < IGC_RETA_SIZE; i++)
+ adapter->rss_indir_tbl[i] = rxfh->indir[i];
- igc_write_rss_indir_tbl(adapter);
+ igc_write_rss_indir_tbl(adapter);
+ }
+
+ if (rxfh->key) {
+ memcpy(adapter->rss_key, rxfh->key, sizeof(adapter->rss_key));
+ igc_write_rss_key(adapter);
+ }
return 0;
}
--
2.47.1
^ permalink raw reply related
* [PATCH net-next 07/15] igb: prepare for RSS key get/set support
From: Tony Nguyen @ 2026-03-30 23:02 UTC (permalink / raw)
To: davem, kuba, pabeni, edumazet, andrew+netdev, netdev
Cc: Takashi Kozu, anthony.l.nguyen, horms, enjuk, Piotr Kwapulinski,
Aleksandr Loktionov, Rinitha S
In-Reply-To: <20260330230248.646900-1-anthony.l.nguyen@intel.com>
From: Takashi Kozu <takkozu@amazon.com>
Store the RSS key inside struct igb_adapter and introduce the
igb_write_rss_key() helper function. This allows the driver to program
the E1000 registers using a persistent RSS key, instead of using a
stack-local buffer in igb_setup_mrqc().
Reviewed-by: Simon Horman <horms@kernel.org>
Reviewed-by: Piotr Kwapulinski <piotr.kwapulinski@intel.com>
Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
Signed-off-by: Takashi Kozu <takkozu@amazon.com>
Tested-by: Rinitha S <sx.rinitha@intel.com> (A Contingent worker at Intel)
Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
---
drivers/net/ethernet/intel/igb/igb.h | 3 +++
drivers/net/ethernet/intel/igb/igb_ethtool.c | 21 ++++++++++++++++++++
drivers/net/ethernet/intel/igb/igb_main.c | 8 ++++----
3 files changed, 28 insertions(+), 4 deletions(-)
diff --git a/drivers/net/ethernet/intel/igb/igb.h b/drivers/net/ethernet/intel/igb/igb.h
index 0fff1df81b7b..8c9b02058cec 100644
--- a/drivers/net/ethernet/intel/igb/igb.h
+++ b/drivers/net/ethernet/intel/igb/igb.h
@@ -495,6 +495,7 @@ struct hwmon_buff {
#define IGB_N_PEROUT 2
#define IGB_N_SDP 4
#define IGB_RETA_SIZE 128
+#define IGB_RSS_KEY_SIZE 40
enum igb_filter_match_flags {
IGB_FILTER_FLAG_ETHER_TYPE = 0x1,
@@ -655,6 +656,7 @@ struct igb_adapter {
struct i2c_client *i2c_client;
u32 rss_indir_tbl_init;
u8 rss_indir_tbl[IGB_RETA_SIZE];
+ u8 rss_key[IGB_RSS_KEY_SIZE];
unsigned long link_check_timeout;
int copper_tries;
@@ -735,6 +737,7 @@ void igb_down(struct igb_adapter *);
void igb_reinit_locked(struct igb_adapter *);
void igb_reset(struct igb_adapter *);
int igb_reinit_queues(struct igb_adapter *);
+void igb_write_rss_key(struct igb_adapter *adapter);
void igb_write_rss_indir_tbl(struct igb_adapter *);
int igb_set_spd_dplx(struct igb_adapter *, u32, u8);
int igb_setup_tx_resources(struct igb_ring *);
diff --git a/drivers/net/ethernet/intel/igb/igb_ethtool.c b/drivers/net/ethernet/intel/igb/igb_ethtool.c
index f7938c1da835..9a105e59f432 100644
--- a/drivers/net/ethernet/intel/igb/igb_ethtool.c
+++ b/drivers/net/ethernet/intel/igb/igb_ethtool.c
@@ -3019,6 +3019,27 @@ static int igb_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd)
return ret;
}
+/**
+ * igb_write_rss_key - Program the RSS key into device registers
+ * @adapter: board private structure
+ *
+ * Write the RSS key stored in adapter->rss_key to the E1000 hardware registers.
+ * Each 32-bit chunk of the key is read using get_unaligned_le32() and written
+ * to the appropriate register.
+ */
+void igb_write_rss_key(struct igb_adapter *adapter)
+{
+ struct e1000_hw *hw = &adapter->hw;
+
+ ASSERT_RTNL();
+
+ for (int i = 0; i < IGB_RSS_KEY_SIZE / 4; i++) {
+ u32 val = get_unaligned_le32(&adapter->rss_key[i * 4]);
+
+ wr32(E1000_RSSRK(i), val);
+ }
+}
+
static int igb_get_eee(struct net_device *netdev, struct ethtool_keee *edata)
{
struct igb_adapter *adapter = netdev_priv(netdev);
diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c
index ee99fd8fd513..f40fe12419f1 100644
--- a/drivers/net/ethernet/intel/igb/igb_main.c
+++ b/drivers/net/ethernet/intel/igb/igb_main.c
@@ -4049,6 +4049,9 @@ static int igb_sw_init(struct igb_adapter *adapter)
pci_read_config_word(pdev, PCI_COMMAND, &hw->bus.pci_cmd_word);
+ /* init RSS key */
+ netdev_rss_key_fill(adapter->rss_key, sizeof(adapter->rss_key));
+
/* set default ring sizes */
adapter->tx_ring_count = IGB_DEFAULT_TXD;
adapter->rx_ring_count = IGB_DEFAULT_RXD;
@@ -4523,11 +4526,8 @@ static void igb_setup_mrqc(struct igb_adapter *adapter)
struct e1000_hw *hw = &adapter->hw;
u32 mrqc, rxcsum;
u32 j, num_rx_queues;
- u32 rss_key[10];
- netdev_rss_key_fill(rss_key, sizeof(rss_key));
- for (j = 0; j < 10; j++)
- wr32(E1000_RSSRK(j), rss_key[j]);
+ igb_write_rss_key(adapter);
num_rx_queues = adapter->rss_queues;
--
2.47.1
^ permalink raw reply related
* [PATCH net-next 08/15] igb: expose RSS key via ethtool get_rxfh
From: Tony Nguyen @ 2026-03-30 23:02 UTC (permalink / raw)
To: davem, kuba, pabeni, edumazet, andrew+netdev, netdev
Cc: Takashi Kozu, anthony.l.nguyen, horms, enjuk, Aleksandr Loktionov,
Rinitha S
In-Reply-To: <20260330230248.646900-1-anthony.l.nguyen@intel.com>
From: Takashi Kozu <takkozu@amazon.com>
Implement igb_get_rxfh_key_size() and extend
igb_get_rxfh() to return the RSS key to userspace.
This can be tested using `ethtool -x <dev>`.
Reviewed-by: Simon Horman <horms@kernel.org>
Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com>
Signed-off-by: Takashi Kozu <takkozu@amazon.com>
Tested-by: Rinitha S <sx.rinitha@intel.com> (A Contingent worker at Intel)
Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
---
drivers/net/ethernet/intel/igb/igb_ethtool.c | 16 ++++++++++++----
1 file changed, 12 insertions(+), 4 deletions(-)
diff --git a/drivers/net/ethernet/intel/igb/igb_ethtool.c b/drivers/net/ethernet/intel/igb/igb_ethtool.c
index 9a105e59f432..47fc620026a9 100644
--- a/drivers/net/ethernet/intel/igb/igb_ethtool.c
+++ b/drivers/net/ethernet/intel/igb/igb_ethtool.c
@@ -3297,10 +3297,12 @@ static int igb_get_rxfh(struct net_device *netdev,
int i;
rxfh->hfunc = ETH_RSS_HASH_TOP;
- if (!rxfh->indir)
- return 0;
- for (i = 0; i < IGB_RETA_SIZE; i++)
- rxfh->indir[i] = adapter->rss_indir_tbl[i];
+ if (rxfh->indir)
+ for (i = 0; i < IGB_RETA_SIZE; i++)
+ rxfh->indir[i] = adapter->rss_indir_tbl[i];
+
+ if (rxfh->key)
+ memcpy(rxfh->key, adapter->rss_key, sizeof(adapter->rss_key));
return 0;
}
@@ -3340,6 +3342,11 @@ void igb_write_rss_indir_tbl(struct igb_adapter *adapter)
}
}
+static u32 igb_get_rxfh_key_size(struct net_device *netdev)
+{
+ return IGB_RSS_KEY_SIZE;
+}
+
static int igb_set_rxfh(struct net_device *netdev,
struct ethtool_rxfh_param *rxfh,
struct netlink_ext_ack *extack)
@@ -3504,6 +3511,7 @@ static const struct ethtool_ops igb_ethtool_ops = {
.get_module_eeprom = igb_get_module_eeprom,
.get_rxfh_indir_size = igb_get_rxfh_indir_size,
.get_rxfh = igb_get_rxfh,
+ .get_rxfh_key_size = igb_get_rxfh_key_size,
.set_rxfh = igb_set_rxfh,
.get_rxfh_fields = igb_get_rxfh_fields,
.set_rxfh_fields = igb_set_rxfh_fields,
--
2.47.1
^ permalink raw reply related
* [PATCH net-next 09/15] igb: allow configuring RSS key via ethtool set_rxfh
From: Tony Nguyen @ 2026-03-30 23:02 UTC (permalink / raw)
To: davem, kuba, pabeni, edumazet, andrew+netdev, netdev
Cc: Takashi Kozu, anthony.l.nguyen, horms, enjuk, Kohei Enju,
Rinitha S
In-Reply-To: <20260330230248.646900-1-anthony.l.nguyen@intel.com>
From: Takashi Kozu <takkozu@amazon.com>
Change igb_set_rxfh() to accept and save a userspace-provided
RSS key. When a key is provided, store it in the adapter and write the
E1000 registers accordingly.
This can be tested using `ethtool -X <dev> hkey <key>`.
Reviewed-by: Simon Horman <horms@kernel.org>
Signed-off-by: Takashi Kozu <takkozu@amazon.com>
Tested-by: Kohei Enju <kohei@enjuk.jp>
Tested-by: Rinitha S <sx.rinitha@intel.com> (A Contingent worker at Intel)
Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
---
drivers/net/ethernet/intel/igb/igb_ethtool.c | 48 +++++++++++---------
1 file changed, 26 insertions(+), 22 deletions(-)
diff --git a/drivers/net/ethernet/intel/igb/igb_ethtool.c b/drivers/net/ethernet/intel/igb/igb_ethtool.c
index 47fc620026a9..65014a54a6d1 100644
--- a/drivers/net/ethernet/intel/igb/igb_ethtool.c
+++ b/drivers/net/ethernet/intel/igb/igb_ethtool.c
@@ -3357,35 +3357,39 @@ static int igb_set_rxfh(struct net_device *netdev,
u32 num_queues;
/* We do not allow change in unsupported parameters */
- if (rxfh->key ||
- (rxfh->hfunc != ETH_RSS_HASH_NO_CHANGE &&
- rxfh->hfunc != ETH_RSS_HASH_TOP))
+ if (rxfh->hfunc != ETH_RSS_HASH_NO_CHANGE &&
+ rxfh->hfunc != ETH_RSS_HASH_TOP)
return -EOPNOTSUPP;
- if (!rxfh->indir)
- return 0;
- num_queues = adapter->rss_queues;
+ if (rxfh->indir) {
+ num_queues = adapter->rss_queues;
- switch (hw->mac.type) {
- case e1000_82576:
- /* 82576 supports 2 RSS queues for SR-IOV */
- if (adapter->vfs_allocated_count)
- num_queues = 2;
- break;
- default:
- break;
- }
+ switch (hw->mac.type) {
+ case e1000_82576:
+ /* 82576 supports 2 RSS queues for SR-IOV */
+ if (adapter->vfs_allocated_count)
+ num_queues = 2;
+ break;
+ default:
+ break;
+ }
- /* Verify user input. */
- for (i = 0; i < IGB_RETA_SIZE; i++)
- if (rxfh->indir[i] >= num_queues)
- return -EINVAL;
+ /* Verify user input. */
+ for (i = 0; i < IGB_RETA_SIZE; i++)
+ if (rxfh->indir[i] >= num_queues)
+ return -EINVAL;
- for (i = 0; i < IGB_RETA_SIZE; i++)
- adapter->rss_indir_tbl[i] = rxfh->indir[i];
+ for (i = 0; i < IGB_RETA_SIZE; i++)
+ adapter->rss_indir_tbl[i] = rxfh->indir[i];
+
+ igb_write_rss_indir_tbl(adapter);
+ }
- igb_write_rss_indir_tbl(adapter);
+ if (rxfh->key) {
+ memcpy(adapter->rss_key, rxfh->key, sizeof(adapter->rss_key));
+ igb_write_rss_key(adapter);
+ }
return 0;
}
--
2.47.1
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox