* [PATCH] netfilter: nf_conntrack_helper: pass helper to expect cleanup
From: Qi Tang @ 2026-03-29 16:50 UTC (permalink / raw)
To: Pablo Neira Ayuso, Florian Westphal
Cc: Phil Sutter, netfilter-devel, coreteam, netdev, Qi Tang
nf_conntrack_helper_unregister() calls nf_ct_expect_iterate_destroy()
to remove expectations belonging to the helper being unregistered.
However, it passes NULL instead of the helper pointer as the data
argument, so expect_iter_me() never matches any expectation and all
of them survive the cleanup.
After unregister returns, nfnl_cthelper_del() frees the helper
object immediately. Subsequent expectation dumps or packet-driven
init_conntrack() calls then dereference the freed exp->helper,
causing a use-after-free.
Pass the actual helper pointer so expectations referencing it are
properly destroyed before the helper object is freed.
BUG: KASAN: slab-use-after-free in string+0x38f/0x430
Read of size 1 at addr ffff888003b14d20 by task poc/103
Call Trace:
string+0x38f/0x430
vsnprintf+0x3cc/0x1170
seq_printf+0x17a/0x240
exp_seq_show+0x2e5/0x560
seq_read_iter+0x419/0x1280
proc_reg_read+0x1ac/0x270
vfs_read+0x179/0x930
ksys_read+0xef/0x1c0
Freed by task 103:
The buggy address is located 32 bytes inside of
freed 192-byte region [ffff888003b14d00, ffff888003b14dc0)
Fixes: ac7b84839003 ("netfilter: expect: add and use nf_ct_expect_iterate helpers")
Signed-off-by: Qi Tang <tpluszz77@gmail.com>
---
net/netfilter/nf_conntrack_helper.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/net/netfilter/nf_conntrack_helper.c b/net/netfilter/nf_conntrack_helper.c
index 1b330ba6613b..a715304a53d8 100644
--- a/net/netfilter/nf_conntrack_helper.c
+++ b/net/netfilter/nf_conntrack_helper.c
@@ -415,7 +415,7 @@ void nf_conntrack_helper_unregister(struct nf_conntrack_helper *me)
*/
synchronize_rcu();
- nf_ct_expect_iterate_destroy(expect_iter_me, NULL);
+ nf_ct_expect_iterate_destroy(expect_iter_me, me);
nf_ct_iterate_destroy(unhelp, me);
/* nf_ct_iterate_destroy() does an unconditional synchronize_rcu() as
--
2.43.0
^ permalink raw reply related
* Re: [PATCH net-next v2] net: phy: bcm84881: add BCM84891/BCM84892 support
From: Daniel Wagner @ 2026-03-29 16:47 UTC (permalink / raw)
To: netdev
Cc: 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>
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.
Daniel
On Tue, Mar 24, 2026 at 7:06 PM Daniel Wagner <wagner.daniel.t@gmail.com> 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/
>
> 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
* [PATCH net] i40e: fix memcmp of pointer in i40e_hw_set_dcb_config()
From: Aaron Esau @ 2026-03-29 16:21 UTC (permalink / raw)
To: intel-wired-lan
Cc: netdev, anthony.l.nguyen, przemyslaw.kitszel,
arkadiusz.kubalewski, stable, Aaron Esau
In i40e_hw_set_dcb_config(), both new_cfg and old_cfg are pointers to
struct i40e_dcbx_config, so sizeof(new_cfg) evaluates to the size of a
pointer (8 bytes on 64-bit) rather than the size of the struct. Likewise,
&new_cfg and &old_cfg are the addresses of the pointer variables on the
stack, not the addresses of the actual config structs.
As a result, the memcmp never compares the actual configuration data,
meaning the "no change needed" early return never fires. Every call to
this function performs a full DCB reconfiguration (quiescing all VSIs,
reprogramming via "Set LLDP MIB" AQC, and reconfiguring VEB/VSIs) even
when the configuration has not changed.
Fix this by comparing the structs themselves rather than the pointers.
Fixes: 4b208eaa8078 ("i40e: Add init and default config of software based DCB")
Cc: stable@vger.kernel.org
Signed-off-by: Aaron Esau <aaron1esau@gmail.com>
---
Found using Coccinelle/spatch with a semantic patch that matches
sizeof(ptr) and &ptr used together where ptr is a pointer type.
drivers/net/ethernet/intel/i40e/i40e_main.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c
index XXXXXXX..XXXXXXX 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_main.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_main.c
@@ -6904,7 +6904,7 @@ static int i40e_hw_set_dcb_config(struct i40e_pf *pf,
int ret;
/* Check if need reconfiguration */
- if (!memcmp(&new_cfg, &old_cfg, sizeof(new_cfg))) {
+ if (!memcmp(new_cfg, old_cfg, sizeof(*new_cfg))) {
dev_dbg(&pf->pdev->dev, "No Change in DCB Config required.\n");
return 0;
}
--
2.49.0
^ permalink raw reply
* [PATCH v2] selftests/bpf: Reject malformed IPv4/IPv6 skb test input
From: Sun Jian @ 2026-03-29 16:17 UTC (permalink / raw)
To: ast, daniel, andrii
Cc: martin.lau, eddyz87, song, yonghong.song, john.fastabend, kpsingh,
sdf, haoluo, jolsa, davem, edumazet, kuba, pabeni, horms, bpf,
netdev, linux-kernel, Sun Jian, syzbot+619b9ef527f510a57cfc
bpf_prog_test_run_skb() derives skb->protocol from the Ethernet header
through eth_type_trans(), but it does not verify that the provided
linear input is long enough to contain the corresponding L3 base header.
This can result in an inconsistent skb being passed to test_run helpers
such as bpf_skb_adjust_room(), where inferred protocol offsets can lead
to operating on uninitialized memory, triggering KMSAN errors.
To reject such malformed test input, we check that the linear head is
sufficiently large to contain the corresponding L3 base header (IPv4
or IPv6) before running the program.
Reported-by: syzbot+619b9ef527f510a57cfc@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=619b9ef527f510a57cfc
Signed-off-by: Sun Jian <sun.jian.kdev@gmail.com>
---
v2:
- Ensured that the linear head is large enough to accommodate the corresponding L3 base header (IPv4 or IPv6), before running the program.
Link: <https://lore.kernel.org/bpf/129d235b04aca276c0a57c7c3646ce48644458cdc85d9b92b25f405e2d58a9ae@mail.kernel.org/>
net/bpf/test_run.c | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)
diff --git a/net/bpf/test_run.c b/net/bpf/test_run.c
index 178c4738e63b..4790bee535b9 100644
--- a/net/bpf/test_run.c
+++ b/net/bpf/test_run.c
@@ -1118,6 +1118,25 @@ int bpf_prog_test_run_skb(struct bpf_prog *prog, const union bpf_attr *kattr,
skb->protocol = eth_type_trans(skb, dev);
skb_reset_network_header(skb);
+ switch (skb->protocol) {
+ case htons(ETH_P_IP):
+ if (skb_headlen(skb) < sizeof(struct iphdr)) {
+ ret = -EINVAL;
+ goto out;
+ }
+ break;
+#if IS_ENABLED(CONFIG_IPV6)
+ case htons(ETH_P_IPV6):
+ if (skb_headlen(skb) < sizeof(struct ipv6hdr)) {
+ ret = -EINVAL;
+ goto out;
+ }
+ break;
+#endif
+ default:
+ break;
+ }
+
switch (skb->protocol) {
case htons(ETH_P_IP):
sk->sk_family = AF_INET;
base-commit: cbfffcca2bf0622b601b7eaf477aa29035169184
--
2.43.0
^ permalink raw reply related
* [PATCH 3/3] net: pse-pd: add lazy PSE control resolution for modular drivers
From: Carlo Szelinsky @ 2026-03-29 16:10 UTC (permalink / raw)
To: Kory Maincent, Oleksij Rempel, Andrew Lunn
Cc: Heiner Kallweit, Russell King, Jakub Kicinski, David S . Miller,
Eric Dumazet, Paolo Abeni, Simon Horman, netdev, linux-kernel,
Carlo Szelinsky
In-Reply-To: <20260329161014.2908509-1-github@szelinsky.de>
When a PSE controller driver is built as a module and was not probed
during PHY registration, the PHY ends up with psec=NULL. Add
pse_control_try_resolve() to lazily resolve the PSE control on first
ethtool access.
Call pse_control_try_resolve() in both the GET and SET ethtool PSE
handlers, before checking phydev->psec. The function is serialized by
RTNL (enforced via ASSERT_RTNL), preventing concurrent callers from
double-allocating a PSE control.
If resolution fails (e.g. the module still has not loaded), a debug
message is emitted via phydev_dbg() and the handler falls through to
the existing "No PSE is attached" error path.
Signed-off-by: Carlo Szelinsky <github@szelinsky.de>
---
drivers/net/pse-pd/pse_core.c | 36 +++++++++++++++++++++++++++++++++++
include/linux/pse-pd/pse.h | 5 +++++
net/ethtool/pse-pd.c | 4 ++++
3 files changed, 45 insertions(+)
diff --git a/drivers/net/pse-pd/pse_core.c b/drivers/net/pse-pd/pse_core.c
index 566b07c336bf..390df23a991c 100644
--- a/drivers/net/pse-pd/pse_core.c
+++ b/drivers/net/pse-pd/pse_core.c
@@ -1569,6 +1569,42 @@ struct pse_control *of_pse_control_get(struct device_node *node,
}
EXPORT_SYMBOL_GPL(of_pse_control_get);
+/**
+ * pse_control_try_resolve - attempt to resolve a deferred PSE control
+ * @phydev: the PHY device whose PSE control may need resolution
+ *
+ * When a PSE controller driver is built as a module, it may not have
+ * probed when PHYs were registered on the MDIO bus. This function
+ * retries PSE control acquisition and should be called before
+ * accessing phydev->psec in ethtool handlers.
+ *
+ * Context: Caller must hold RTNL.
+ */
+void pse_control_try_resolve(struct phy_device *phydev)
+{
+ struct device_node *np;
+ struct pse_control *psec;
+
+ ASSERT_RTNL();
+
+ if (phydev->psec)
+ return;
+
+ np = phydev->mdio.dev.of_node;
+ if (!np || !of_property_present(np, "pses"))
+ return;
+
+ psec = of_pse_control_get(np, phydev);
+ if (IS_ERR(psec)) {
+ phydev_dbg(phydev, "failed to resolve PSE control: %pe\n",
+ psec);
+ return;
+ }
+
+ phydev->psec = psec;
+}
+EXPORT_SYMBOL_GPL(pse_control_try_resolve);
+
/**
* pse_get_sw_admin_state - Convert the software admin state to c33 or podl
* admin state value used in the standard
diff --git a/include/linux/pse-pd/pse.h b/include/linux/pse-pd/pse.h
index b86cce740551..d2f9b7c1acdf 100644
--- a/include/linux/pse-pd/pse.h
+++ b/include/linux/pse-pd/pse.h
@@ -350,6 +350,7 @@ int devm_pse_irq_helper(struct pse_controller_dev *pcdev, int irq,
struct pse_control *of_pse_control_get(struct device_node *node,
struct phy_device *phydev);
void pse_control_put(struct pse_control *psec);
+void pse_control_try_resolve(struct phy_device *phydev);
int pse_ethtool_get_status(struct pse_control *psec,
struct netlink_ext_ack *extack,
@@ -379,6 +380,10 @@ static inline void pse_control_put(struct pse_control *psec)
{
}
+static inline void pse_control_try_resolve(struct phy_device *phydev)
+{
+}
+
static inline int pse_ethtool_get_status(struct pse_control *psec,
struct netlink_ext_ack *extack,
struct ethtool_pse_control_status *status)
diff --git a/net/ethtool/pse-pd.c b/net/ethtool/pse-pd.c
index 2eb9bdc2dcb9..adffc230acd6 100644
--- a/net/ethtool/pse-pd.c
+++ b/net/ethtool/pse-pd.c
@@ -42,6 +42,8 @@ static int pse_get_pse_attributes(struct phy_device *phydev,
return -EOPNOTSUPP;
}
+ pse_control_try_resolve(phydev);
+
if (!phydev->psec) {
NL_SET_ERR_MSG(extack, "No PSE is attached");
return -EOPNOTSUPP;
@@ -249,6 +251,8 @@ ethnl_set_pse_validate(struct phy_device *phydev, struct genl_info *info)
return -EOPNOTSUPP;
}
+ pse_control_try_resolve(phydev);
+
if (!phydev->psec) {
NL_SET_ERR_MSG(info->extack, "No PSE is attached");
return -EOPNOTSUPP;
--
2.43.0
^ permalink raw reply related
* [PATCH 2/3] net: pse-pd: prevent regulator cleanup from disabling unclaimed PSE PIs
From: Carlo Szelinsky @ 2026-03-29 16:10 UTC (permalink / raw)
To: Kory Maincent, Oleksij Rempel, Andrew Lunn
Cc: Heiner Kallweit, Russell King, Jakub Kicinski, David S . Miller,
Eric Dumazet, Paolo Abeni, Simon Horman, netdev, linux-kernel,
Carlo Szelinsky
In-Reply-To: <20260329161014.2908509-1-github@szelinsky.de>
When a PSE controller driver is loaded as a module, its PI regulators
are registered before any consumer (PHY) acquires the corresponding PSE
control via of_pse_control_get(). The regulator framework's
regulator_late_cleanup then calls pse_pi_is_enabled(), which queries
hardware and sees the PI is enabled. Since no consumer holds it
(use_count == 0), regulator_late_cleanup disables it, killing PoE.
Add an admin_state_synced flag to struct pse_pi that is set when a
consumer first acquires the PSE control and syncs admin_state_enabled
from hardware. In pse_pi_is_enabled(), report unsynchronized PIs as
disabled so regulator_late_cleanup skips them.
This preserves the existing dual-path behavior: software-tracked state
for software-controlled power domains, and hardware queries for
hardware-controlled domains. The admin_state_synced flag is only false
before the first consumer acquisition, which is the exact window where
regulator_late_cleanup could incorrectly disable the PI.
Signed-off-by: Carlo Szelinsky <github@szelinsky.de>
---
drivers/net/pse-pd/pse_core.c | 13 +++++++++++++
include/linux/pse-pd/pse.h | 1 +
2 files changed, 14 insertions(+)
diff --git a/drivers/net/pse-pd/pse_core.c b/drivers/net/pse-pd/pse_core.c
index 3beaaaeec9e1..566b07c336bf 100644
--- a/drivers/net/pse-pd/pse_core.c
+++ b/drivers/net/pse-pd/pse_core.c
@@ -421,6 +421,18 @@ static int pse_pi_is_enabled(struct regulator_dev *rdev)
id = rdev_get_id(rdev);
mutex_lock(&pcdev->lock);
+
+ /*
+ * Report the PI as disabled until a consumer has acquired it
+ * and synced admin_state_enabled from hardware. This prevents
+ * regulator_late_cleanup from disabling unclaimed PSE PIs
+ * when the PSE controller driver loads as a module.
+ */
+ if (!pcdev->pi[id].admin_state_synced) {
+ ret = 0;
+ goto out;
+ }
+
if (pse_pw_d_is_sw_pw_control(pcdev, pcdev->pi[id].pw_d)) {
ret = pcdev->pi[id].admin_state_enabled;
goto out;
@@ -1431,6 +1443,7 @@ pse_control_get_internal(struct pse_controller_dev *pcdev, unsigned int index,
goto free_psec;
pcdev->pi[index].admin_state_enabled = ret;
+ pcdev->pi[index].admin_state_synced = true;
psec->ps = devm_regulator_get_exclusive(pcdev->dev,
rdev_get_name(pcdev->pi[index].rdev));
if (IS_ERR(psec->ps)) {
diff --git a/include/linux/pse-pd/pse.h b/include/linux/pse-pd/pse.h
index 4e5696cfade7..b86cce740551 100644
--- a/include/linux/pse-pd/pse.h
+++ b/include/linux/pse-pd/pse.h
@@ -260,6 +260,7 @@ struct pse_pi {
struct device_node *np;
struct regulator_dev *rdev;
bool admin_state_enabled;
+ bool admin_state_synced;
struct pse_power_domain *pw_d;
int prio;
bool isr_pd_detected;
--
2.43.0
^ permalink raw reply related
* [PATCH 1/3] net: mdio: treat PSE EPROBE_DEFER as non-fatal during PHY registration
From: Carlo Szelinsky @ 2026-03-29 16:10 UTC (permalink / raw)
To: Kory Maincent, Oleksij Rempel, Andrew Lunn
Cc: Heiner Kallweit, Russell King, Jakub Kicinski, David S . Miller,
Eric Dumazet, Paolo Abeni, Simon Horman, netdev, linux-kernel,
Carlo Szelinsky
In-Reply-To: <20260329161014.2908509-1-github@szelinsky.de>
When a PSE controller driver is built as a module, it may not be probed
yet when PHYs are registered on the MDIO bus. This causes
fwnode_find_pse_control() -> of_pse_control_get() to return
-EPROBE_DEFER, which currently propagates up and destroys the PHY
device.
Treat -EPROBE_DEFER as non-fatal, allowing the PHY to register
successfully with psec=NULL. The PSE control can be resolved lazily
when first needed.
Signed-off-by: Carlo Szelinsky <github@szelinsky.de>
---
drivers/net/mdio/fwnode_mdio.c | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/drivers/net/mdio/fwnode_mdio.c b/drivers/net/mdio/fwnode_mdio.c
index ba7091518265..2a03b3fc41e6 100644
--- a/drivers/net/mdio/fwnode_mdio.c
+++ b/drivers/net/mdio/fwnode_mdio.c
@@ -161,8 +161,12 @@ int fwnode_mdiobus_register_phy(struct mii_bus *bus,
psec = fwnode_find_pse_control(child, phy);
if (IS_ERR(psec)) {
- rc = PTR_ERR(psec);
- goto unregister_phy;
+ if (PTR_ERR(psec) == -EPROBE_DEFER) {
+ psec = NULL;
+ } else {
+ rc = PTR_ERR(psec);
+ goto unregister_phy;
+ }
}
phy->psec = psec;
--
2.43.0
^ permalink raw reply related
* [PATCH 0/3] net: pse-pd: support module-based PSE controller drivers
From: Carlo Szelinsky @ 2026-03-29 16:10 UTC (permalink / raw)
To: Kory Maincent, Oleksij Rempel, Andrew Lunn
Cc: Heiner Kallweit, Russell King, Jakub Kicinski, David S . Miller,
Eric Dumazet, Paolo Abeni, Simon Horman, netdev, linux-kernel,
Carlo Szelinsky
When a PSE controller driver is built as a module, it may not be probed
yet when PHYs are registered on the MDIO bus. This causes
of_pse_control_get() to return -EPROBE_DEFER, destroying the PHY device.
Later, regulator_late_cleanup disables the unclaimed PSE regulators,
permanently killing PoE.
This series fixes the issue in three steps:
1. Treat -EPROBE_DEFER as non-fatal during PHY registration, allowing
the PHY to register with psec=NULL.
2. Add an admin_state_synced flag to pse_pi so that pse_pi_is_enabled()
reports unclaimed PIs as disabled, preventing regulator_late_cleanup
from shutting them down. The existing dual-path behavior (software-
tracked vs. hardware-queried state) is preserved for claimed PIs.
3. Add pse_control_try_resolve() for lazy PSE control resolution on
first ethtool access, serialized by RTNL.
This is tested on my setup, but I am not fully sure if this is the right
approach to solve this problem. I would love to get feedback from the
maintainers on whether the overall design direction makes sense, or if
there is a better way to handle the deferred PSE control acquisition.
Carlo Szelinsky (3):
net: mdio: treat PSE EPROBE_DEFER as non-fatal during PHY registration
net: pse-pd: prevent regulator cleanup from disabling unclaimed PSE
PIs
net: pse-pd: add lazy PSE control resolution for modular drivers
drivers/net/mdio/fwnode_mdio.c | 8 ++++--
drivers/net/pse-pd/pse_core.c | 49 ++++++++++++++++++++++++++++++++++
include/linux/pse-pd/pse.h | 6 +++++
net/ethtool/pse-pd.c | 4 +++
4 files changed, 65 insertions(+), 2 deletions(-)
--
2.43.0
^ permalink raw reply
* Re: [PATCH net 2/3] e1000: fix endianness conversion of uninitialized words
From: Fedor Pchelkin @ 2026-03-29 16:02 UTC (permalink / raw)
To: Jacob Keller
Cc: Tony Nguyen, Agalakov Daniil, lvc-project, Roman Razov,
Przemek Kitszel, linux-kernel, Andrew Lunn, Eric Dumazet,
intel-wired-lan, netdev, Jakub Kicinski, Paolo Abeni,
Daniil Iskhakov, David S. Miller
In-Reply-To: <3a0f74f0-7031-43e3-8268-473badd9f1fe@intel.com>
On Wed, 25. Mar 16:01, Jacob Keller wrote:
> On 3/25/2026 8:19 AM, Fedor Pchelkin wrote:
> > Hi,
> >
> > On Tue, 24. Mar 16:26, Tony Nguyen wrote:
> >> On 3/18/2026 5:05 AM, Agalakov Daniil wrote:
> >>> [Why]
> >>> In e1000_set_eeprom(), the eeprom_buff is allocated to hold a range of
> >>> words. However, only the boundary words (the first and the last) are
> >>> populated from the EEPROM if the write request is not word-aligned.
> >>> The words in the middle of the buffer remain uninitialized because they
> >>> are intended to be completely overwritten by the new data via memcpy().
> >>>
> >>> The previous implementation had a loop that performed le16_to_cpus()
> >>> on the entire buffer. This resulted in endianness conversion being
> >>> performed on uninitialized memory for all interior words.
> >>>
> >>> Fix this by converting the endianness only for the boundary words
> >>> immediately after they are successfully read from the EEPROM.
> >>>
> >>> Found by Linux Verification Center (linuxtesting.org) with SVACE.
> >>>
> >>> Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
> >>
> >> While this is definitely better, I'm not sure there's a bug here since it's
> >> being immediately overwritten. Seems like this patch would be better going
> >> to *-next as an improvement.
> >
> > It's worth stating in the commit message that the uninitialized memory is
> > touched with le16_to_cpus() in the loop only on BE systems. Little-endian
> > ones are not affected - le16_to_cpus() is a no-op there.
> >
> > Anyway, for the BE case, touching and manipulating uninit memory bytes is
> > still in general considered a bug, even if this memory is overwritten a
> > few lines after that. I guess if KMSAN supported big-endian architectures,
> > it would hit this, and that wouldn't be a false-positive.
> >
> > I'm not aware of the details on how you treat the bugs in these drivers
> > for BE-systems: maybe they aren't prioritized and then would occasionnaly
> > go as -next material. But, again, this situation looks like a real bug
> > worth fixing on BE-systems.
> >
>
> Typically the bar for a fixes and a net change is that it requires some
> user visible behavioral impact. That's where the hesitance on our end
> comes from: how does this cause a user-visible bug?
>
> If there are truly user-visible impact on BE system for touching and
> manipulating the uninitialized memory, then it makes sense to go to net
> for me. I guess "KASAN/UBSAN complains you touched uninitialized memory"
> would be such a bug.
My first thought was that reading and writing uninitialized memory is just
undefined behavior in C. It's hard to say what some compiler might invent
here.
The current situation is not trivial though because there is a chunk of
uninit memory allocated with kmalloc() to which we have a valid pointer,
and we are swapping the order of uninitialized bytes inside this chunk,
i.e. reading/writing uninitialized memory. Basically it should just go
down to swapping garbage values without any suspicious compiler
optimizations - I don't think the compiler is aware that kmalloc() returns
uninit memory.
KMSAN actually supports one big-endian arch - that's s390 (the only arch
except x86 that KMSAN supports). I've tried quickly to trigger the splat
out of curiosity, but booting the KMSAN-enabled kernel with s390 QEMU TCG
looks like taking forever so unfortunately no specific results here.
KASAN/UBSAN don't catch error patterns of this type.
>
> Alternatively: is there a risk of some side channel method to capture
> that uninitialized data and leak kernel memory? I don't recall enough to
> know whether that would be an issue here...
>
> I don't personally have an objection to going through net (besides
> fixing the commit hash for the Fixes: tag on the patch that was wrong)
> since its an obvious fix.
Thanks for the feedback. I see Daniil has already sent some newer
versions targeting -next. The problem in question is rather obscure about
severity of its consequences but spending some time on investigating this
now I'm more inclined to think there should be no opportunity for UB here
and it's okay to process the patch like Tony suggested..
^ permalink raw reply
* [PATCH net-next v3 3/3] net: pse-pd: add LED trigger support via notification path
From: Carlo Szelinsky @ 2026-03-29 15:31 UTC (permalink / raw)
To: Oleksij Rempel, Kory Maincent
Cc: Andrew Lunn, David S . Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Rob Herring, Krzysztof Kozlowski,
Krzysztof Kozlowski, Conor Dooley, netdev, devicetree,
linux-kernel, linux-leds, Carlo Szelinsky, kernel test robot
In-Reply-To: <20260329153124.2823980-1-github@szelinsky.de>
Add per-PI "delivering" and "enabled" LED triggers to the PSE core
subsystem. LED state is updated from the shared pse_handle_events()
function whenever the IRQ or poll path detects a state change, as well
as from the regulator enable/disable paths so that host-initiated
admin state changes via ethtool are immediately reflected.
Both C33 and PoDL power status and admin state are checked so that LED
triggers work for both controller types.
Trigger names use dev_name(dev) (e.g. "pse-1-003c:port0:delivering")
to ensure uniqueness when multiple PSE controllers are present on the
same system.
Initial LED state is queried at registration time so already-active
ports are reflected immediately without waiting for a hardware event.
LED trigger registration is performed before adding the controller to
the global list, avoiding a race where an IRQ or poll event could
invoke pse_led_update() on a partially initialized trigger.
Reported-by: kernel test robot <lkp@intel.com>
Closes: https://lore.kernel.org/oe-kbuild-all/202603251254.o5PqMBRU-lkp@intel.com/
Closes: https://lore.kernel.org/oe-kbuild-all/202603251250.cuMCk5Yv-lkp@intel.com/
Signed-off-by: Carlo Szelinsky <github@szelinsky.de>
---
drivers/net/pse-pd/pse_core.c | 134 +++++++++++++++++++++++++++++++++-
include/linux/pse-pd/pse.h | 22 ++++++
2 files changed, 154 insertions(+), 2 deletions(-)
diff --git a/drivers/net/pse-pd/pse_core.c b/drivers/net/pse-pd/pse_core.c
index 23783bf2edf4..dd0895ca07ad 100644
--- a/drivers/net/pse-pd/pse_core.c
+++ b/drivers/net/pse-pd/pse_core.c
@@ -12,9 +12,10 @@
#include <linux/phy.h>
#include <linux/pse-pd/pse.h>
#include <linux/regulator/driver.h>
+#include <linux/leds.h>
+#include <linux/workqueue.h>
#include <linux/regulator/machine.h>
#include <linux/rtnetlink.h>
-#include <linux/workqueue.h>
#include <net/net_trackers.h>
#define PSE_PW_D_LIMIT INT_MAX
@@ -670,6 +671,111 @@ static int _pse_pi_delivery_power_sw_pw_ctrl(struct pse_controller_dev *pcdev,
return 0;
}
+#if IS_ENABLED(CONFIG_LEDS_TRIGGERS)
+/**
+ * pse_led_update - Update LED triggers for a PI based on current state
+ * @pcdev: PSE controller device
+ * @id: PI index
+ *
+ * Queries the current power status and admin state of the PI and
+ * fires LED trigger events on state changes. Called from the
+ * notification path and the regulator enable/disable paths.
+ *
+ * Must be called with pcdev->lock held.
+ */
+static void pse_led_update(struct pse_controller_dev *pcdev, int id)
+{
+ struct pse_pi_led_triggers *trigs;
+ struct pse_pw_status pw_status = {};
+ struct pse_admin_state admin_state = {};
+ bool delivering, enabled;
+
+ if (!pcdev->pi_led_trigs)
+ return;
+
+ trigs = &pcdev->pi_led_trigs[id];
+ if (!trigs->delivering.name)
+ return;
+
+ if (pcdev->ops->pi_get_pw_status(pcdev, id, &pw_status))
+ return;
+ if (pcdev->ops->pi_get_admin_state(pcdev, id, &admin_state))
+ return;
+
+ delivering = pw_status.c33_pw_status ==
+ ETHTOOL_C33_PSE_PW_D_STATUS_DELIVERING ||
+ pw_status.podl_pw_status ==
+ ETHTOOL_PODL_PSE_PW_D_STATUS_DELIVERING;
+ enabled = admin_state.c33_admin_state ==
+ ETHTOOL_C33_PSE_ADMIN_STATE_ENABLED ||
+ admin_state.podl_admin_state ==
+ ETHTOOL_PODL_PSE_ADMIN_STATE_ENABLED;
+
+ if (trigs->last_delivering != delivering) {
+ trigs->last_delivering = delivering;
+ led_trigger_event(&trigs->delivering,
+ delivering ? LED_FULL : LED_OFF);
+ }
+
+ if (trigs->last_enabled != enabled) {
+ trigs->last_enabled = enabled;
+ led_trigger_event(&trigs->enabled,
+ enabled ? LED_FULL : LED_OFF);
+ }
+}
+
+static int pse_led_triggers_register(struct pse_controller_dev *pcdev)
+{
+ struct device *dev = pcdev->dev;
+ const char *dev_id;
+ int i, ret;
+
+ dev_id = dev_name(dev);
+
+ pcdev->pi_led_trigs = devm_kcalloc(dev, pcdev->nr_lines,
+ sizeof(*pcdev->pi_led_trigs),
+ GFP_KERNEL);
+ if (!pcdev->pi_led_trigs)
+ return -ENOMEM;
+
+ for (i = 0; i < pcdev->nr_lines; i++) {
+ struct pse_pi_led_triggers *trigs = &pcdev->pi_led_trigs[i];
+
+ /* Skip PIs not described in device tree */
+ if (!pcdev->no_of_pse_pi && !pcdev->pi[i].np)
+ continue;
+
+ trigs->delivering.name = devm_kasprintf(dev, GFP_KERNEL,
+ "pse-%s:port%d:delivering",
+ dev_id, i);
+ if (!trigs->delivering.name)
+ return -ENOMEM;
+
+ ret = devm_led_trigger_register(dev, &trigs->delivering);
+ if (ret)
+ return ret;
+
+ trigs->enabled.name = devm_kasprintf(dev, GFP_KERNEL,
+ "pse-%s:port%d:enabled",
+ dev_id, i);
+ if (!trigs->enabled.name)
+ return -ENOMEM;
+
+ ret = devm_led_trigger_register(dev, &trigs->enabled);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+#else
+static inline void pse_led_update(struct pse_controller_dev *pcdev, int id) {}
+static int pse_led_triggers_register(struct pse_controller_dev *pcdev)
+{
+ return 0;
+}
+#endif /* CONFIG_LEDS_TRIGGERS */
+
static int pse_pi_enable(struct regulator_dev *rdev)
{
struct pse_controller_dev *pcdev = rdev_get_drvdata(rdev);
@@ -695,6 +801,7 @@ static int pse_pi_enable(struct regulator_dev *rdev)
pcdev->pi[id].admin_state_enabled = 1;
ret = 0;
}
+ pse_led_update(pcdev, id);
mutex_unlock(&pcdev->lock);
return ret;
}
@@ -702,6 +809,7 @@ static int pse_pi_enable(struct regulator_dev *rdev)
ret = ops->pi_enable(pcdev, id);
if (!ret)
pcdev->pi[id].admin_state_enabled = 1;
+ pse_led_update(pcdev, id);
mutex_unlock(&pcdev->lock);
return ret;
@@ -719,6 +827,7 @@ static int pse_pi_disable(struct regulator_dev *rdev)
ret = _pse_pi_disable(pcdev, id);
if (!ret)
pi->admin_state_enabled = 0;
+ pse_led_update(pcdev, id);
mutex_unlock(&pcdev->lock);
return 0;
@@ -1108,6 +1217,20 @@ int pse_controller_register(struct pse_controller_dev *pcdev)
if (ret)
return ret;
+ ret = pse_led_triggers_register(pcdev);
+ if (ret) {
+ dev_warn(pcdev->dev, "Failed to register LED triggers: %d\n",
+ ret);
+ }
+
+ /* Query initial LED state for all PIs so already-active ports
+ * are reflected immediately without waiting for a hardware event.
+ */
+ for (i = 0; i < pcdev->nr_lines; i++) {
+ if (pcdev->no_of_pse_pi || pcdev->pi[i].np)
+ pse_led_update(pcdev, i);
+ }
+
mutex_lock(&pse_list_mutex);
list_add(&pcdev->list, &pse_controller_list);
mutex_unlock(&pse_list_mutex);
@@ -1265,7 +1388,14 @@ static void pse_handle_events(struct pse_controller_dev *pcdev,
struct pse_ntf ntf = {};
int ret;
- /* Do nothing PI not described */
+ /* Update LEDs for described PIs regardless of consumer state.
+ * LED triggers are registered at controller init, before any
+ * PHY claims a PSE control, so rdev may still be NULL here.
+ */
+ if (pcdev->no_of_pse_pi || pcdev->pi[i].np)
+ pse_led_update(pcdev, i);
+
+ /* Skip regulator/netlink path for PIs without consumers */
if (!pcdev->pi[i].rdev)
continue;
diff --git a/include/linux/pse-pd/pse.h b/include/linux/pse-pd/pse.h
index 44d5d10e239d..0058636a6299 100644
--- a/include/linux/pse-pd/pse.h
+++ b/include/linux/pse-pd/pse.h
@@ -10,6 +10,7 @@
#include <linux/kfifo.h>
#include <uapi/linux/ethtool.h>
#include <uapi/linux/ethtool_netlink_generated.h>
+#include <linux/leds.h>
#include <linux/regulator/driver.h>
/* Maximum current in uA according to IEEE 802.3-2022 Table 145-1 */
@@ -266,6 +267,23 @@ struct pse_pi {
int pw_allocated_mW;
};
+#if IS_ENABLED(CONFIG_LEDS_TRIGGERS)
+/**
+ * struct pse_pi_led_triggers - LED trigger state for a PSE PI
+ *
+ * @delivering: LED trigger for power delivering state
+ * @enabled: LED trigger for admin enabled state
+ * @last_delivering: cached delivering state for change detection
+ * @last_enabled: cached enabled state for change detection
+ */
+struct pse_pi_led_triggers {
+ struct led_trigger delivering;
+ struct led_trigger enabled;
+ bool last_delivering;
+ bool last_enabled;
+};
+#endif
+
/**
* struct pse_ntf - PSE notification element
*
@@ -303,6 +321,7 @@ struct pse_ntf {
* @ntf_work: workqueue for PSE notification management
* @ntf_fifo: PSE notifications FIFO
* @ntf_fifo_lock: protect @ntf_fifo writer
+ * @pi_led_trigs: per-PI LED trigger state array
*/
struct pse_controller_dev {
const struct pse_controller_ops *ops;
@@ -327,6 +346,9 @@ struct pse_controller_dev {
struct work_struct ntf_work;
DECLARE_KFIFO_PTR(ntf_fifo, struct pse_ntf);
spinlock_t ntf_fifo_lock; /* Protect @ntf_fifo writer */
+#if IS_ENABLED(CONFIG_LEDS_TRIGGERS)
+ struct pse_pi_led_triggers *pi_led_trigs;
+#endif
};
/**
--
2.43.0
^ permalink raw reply related
* [PATCH net-next v3 2/3] net: pse-pd: add devm_pse_poll_helper()
From: Carlo Szelinsky @ 2026-03-29 15:31 UTC (permalink / raw)
To: Oleksij Rempel, Kory Maincent
Cc: Andrew Lunn, David S . Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Rob Herring, Krzysztof Kozlowski,
Krzysztof Kozlowski, Conor Dooley, netdev, devicetree,
linux-kernel, linux-leds, Carlo Szelinsky
In-Reply-To: <20260329153124.2823980-1-github@szelinsky.de>
Extract the common event handling loop from pse_isr() into a shared
pse_handle_events() function, and add a generic poll-based alternative
to the IRQ path for PSE controllers that lack interrupt support or
have IRQ lines not wired on the board.
The new devm_pse_poll_helper() function sets up a delayed work that
periodically calls the driver's map_event callback to detect state
changes, feeding events into the existing ntf_fifo / pse_send_ntf_worker
notification pipeline. This reuses the same pse_irq_desc interface as
the IRQ path — the driver provides a map_event callback that populates
per-PI notification arrays.
The poll worker uses system_freezable_wq to avoid running during system
suspend when the underlying hardware (e.g. I2C bus) may be inaccessible.
Work cancellation on teardown is handled via devm_add_action_or_reset()
to ensure the delayed work is cancelled before poll_notifs is freed
by devres, avoiding a use-after-free when devm_pse_poll_helper() is
called after devm_pse_controller_register() (devres LIFO ordering).
The poll interval is configurable via the DT property "poll-interval-ms"
and defaults to 500ms, balancing responsiveness against I2C bus load.
Signed-off-by: Carlo Szelinsky <github@szelinsky.de>
---
drivers/net/pse-pd/pse_core.c | 166 ++++++++++++++++++++++++++++------
include/linux/pse-pd/pse.h | 12 +++
2 files changed, 148 insertions(+), 30 deletions(-)
diff --git a/drivers/net/pse-pd/pse_core.c b/drivers/net/pse-pd/pse_core.c
index 3beaaaeec9e1..23783bf2edf4 100644
--- a/drivers/net/pse-pd/pse_core.c
+++ b/drivers/net/pse-pd/pse_core.c
@@ -14,10 +14,18 @@
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
#include <linux/rtnetlink.h>
+#include <linux/workqueue.h>
#include <net/net_trackers.h>
#define PSE_PW_D_LIMIT INT_MAX
+/*
+ * Default poll interval for controllers without IRQ support.
+ * 500ms provides a reasonable trade-off between responsiveness
+ * (event detection, PD detection) and I2C bus utilization.
+ */
+#define PSE_DEFAULT_POLL_INTERVAL_MS 500
+
static DEFINE_MUTEX(pse_list_mutex);
static LIST_HEAD(pse_controller_list);
static DEFINE_XARRAY_ALLOC(pse_pw_d_map);
@@ -1238,66 +1246,103 @@ static int pse_set_config_isr(struct pse_controller_dev *pcdev, int id,
}
/**
- * pse_isr - IRQ handler for PSE
- * @irq: irq number
- * @data: pointer to user interrupt structure
+ * pse_handle_events - Process PSE events for all PIs
+ * @pcdev: a pointer to the PSE controller device
+ * @notifs: per-PI notification array
+ * @notifs_mask: bitmask of PIs with events
*
- * Return: irqreturn_t - status of IRQ
+ * Common event handling shared between IRQ and poll paths.
+ * Caller must hold pcdev->lock.
*/
-static irqreturn_t pse_isr(int irq, void *data)
+static void pse_handle_events(struct pse_controller_dev *pcdev,
+ unsigned long *notifs,
+ unsigned long notifs_mask)
{
- struct pse_controller_dev *pcdev;
- unsigned long notifs_mask = 0;
- struct pse_irq_desc *desc;
- struct pse_irq *h = data;
- int ret, i;
-
- desc = &h->desc;
- pcdev = h->pcdev;
-
- /* Clear notifs mask */
- memset(h->notifs, 0, pcdev->nr_lines * sizeof(*h->notifs));
- mutex_lock(&pcdev->lock);
- ret = desc->map_event(irq, pcdev, h->notifs, ¬ifs_mask);
- if (ret || !notifs_mask) {
- mutex_unlock(&pcdev->lock);
- return IRQ_NONE;
- }
+ int i;
for_each_set_bit(i, ¬ifs_mask, pcdev->nr_lines) {
- unsigned long notifs, rnotifs;
+ unsigned long pi_notifs, rnotifs;
struct pse_ntf ntf = {};
+ int ret;
/* Do nothing PI not described */
if (!pcdev->pi[i].rdev)
continue;
- notifs = h->notifs[i];
+ pi_notifs = notifs[i];
if (pse_pw_d_is_sw_pw_control(pcdev, pcdev->pi[i].pw_d)) {
- ret = pse_set_config_isr(pcdev, i, notifs);
+ ret = pse_set_config_isr(pcdev, i, pi_notifs);
if (ret)
- notifs |= ETHTOOL_PSE_EVENT_SW_PW_CONTROL_ERROR;
+ pi_notifs |= ETHTOOL_PSE_EVENT_SW_PW_CONTROL_ERROR;
}
- dev_dbg(h->pcdev->dev,
- "Sending PSE notification EVT 0x%lx\n", notifs);
+ dev_dbg(pcdev->dev,
+ "Sending PSE notification EVT 0x%lx\n", pi_notifs);
- ntf.notifs = notifs;
+ ntf.notifs = pi_notifs;
ntf.id = i;
kfifo_in_spinlocked(&pcdev->ntf_fifo, &ntf, 1,
&pcdev->ntf_fifo_lock);
schedule_work(&pcdev->ntf_work);
- rnotifs = pse_to_regulator_notifs(notifs);
+ rnotifs = pse_to_regulator_notifs(pi_notifs);
regulator_notifier_call_chain(pcdev->pi[i].rdev, rnotifs,
NULL);
}
+}
+
+/**
+ * pse_isr - IRQ handler for PSE
+ * @irq: irq number
+ * @data: pointer to user interrupt structure
+ *
+ * Return: irqreturn_t - status of IRQ
+ */
+static irqreturn_t pse_isr(int irq, void *data)
+{
+ struct pse_controller_dev *pcdev;
+ unsigned long notifs_mask = 0;
+ struct pse_irq *h = data;
+ int ret;
+ pcdev = h->pcdev;
+
+ /* Clear notifs mask */
+ memset(h->notifs, 0, pcdev->nr_lines * sizeof(*h->notifs));
+ mutex_lock(&pcdev->lock);
+ ret = h->desc.map_event(irq, pcdev, h->notifs, ¬ifs_mask);
+ if (ret || !notifs_mask) {
+ mutex_unlock(&pcdev->lock);
+ return IRQ_NONE;
+ }
+
+ pse_handle_events(pcdev, h->notifs, notifs_mask);
mutex_unlock(&pcdev->lock);
return IRQ_HANDLED;
}
+static void pse_poll_worker(struct work_struct *work)
+{
+ struct pse_controller_dev *pcdev =
+ container_of(work, struct pse_controller_dev,
+ poll_work.work);
+ unsigned long notifs_mask = 0;
+ int ret;
+
+ memset(pcdev->poll_notifs, 0,
+ pcdev->nr_lines * sizeof(*pcdev->poll_notifs));
+ mutex_lock(&pcdev->lock);
+ ret = pcdev->poll_desc.map_event(0, pcdev, pcdev->poll_notifs,
+ ¬ifs_mask);
+ if (!ret && notifs_mask)
+ pse_handle_events(pcdev, pcdev->poll_notifs, notifs_mask);
+ mutex_unlock(&pcdev->lock);
+
+ queue_delayed_work(system_freezable_wq, &pcdev->poll_work,
+ msecs_to_jiffies(pcdev->poll_interval_ms));
+}
+
/**
* devm_pse_irq_helper - Register IRQ based PSE event notifier
* @pcdev: a pointer to the PSE
@@ -1351,6 +1396,67 @@ int devm_pse_irq_helper(struct pse_controller_dev *pcdev, int irq,
}
EXPORT_SYMBOL_GPL(devm_pse_irq_helper);
+static void pse_poll_cancel(void *data)
+{
+ struct pse_controller_dev *pcdev = data;
+
+ cancel_delayed_work_sync(&pcdev->poll_work);
+}
+
+/**
+ * devm_pse_poll_helper - Register poll-based PSE event notifier
+ * @pcdev: a pointer to the PSE controller device
+ * @d: PSE event description (uses same pse_irq_desc as IRQ path)
+ *
+ * For PSE controllers without IRQ support or with IRQ not wired. Sets
+ * up a delayed work that periodically calls the driver's map_event
+ * callback to detect state changes, feeding events into the standard
+ * notification pipeline.
+ *
+ * The poll worker uses system_freezable_wq to ensure it does not run
+ * during system suspend while the hardware may be inaccessible.
+ *
+ * Return: 0 on success and errno on failure
+ */
+int devm_pse_poll_helper(struct pse_controller_dev *pcdev,
+ const struct pse_irq_desc *d)
+{
+ struct device *dev = pcdev->dev;
+ int ret;
+
+ if (!d || !d->map_event || !d->name)
+ return -EINVAL;
+
+ pcdev->poll_desc = *d;
+ pcdev->poll_notifs = devm_kcalloc(dev, pcdev->nr_lines,
+ sizeof(*pcdev->poll_notifs),
+ GFP_KERNEL);
+ if (!pcdev->poll_notifs)
+ return -ENOMEM;
+
+ of_property_read_u32(dev->of_node, "poll-interval-ms",
+ &pcdev->poll_interval_ms);
+ if (!pcdev->poll_interval_ms)
+ pcdev->poll_interval_ms = PSE_DEFAULT_POLL_INTERVAL_MS;
+
+ INIT_DELAYED_WORK(&pcdev->poll_work, pse_poll_worker);
+ pcdev->polling = true;
+
+ /* Register devm action to cancel poll work before poll_notifs is
+ * freed by devres. This ensures correct teardown ordering since
+ * devm_pse_poll_helper() is called after devm_pse_controller_register().
+ */
+ ret = devm_add_action_or_reset(dev, pse_poll_cancel, pcdev);
+ if (ret)
+ return ret;
+
+ queue_delayed_work(system_freezable_wq, &pcdev->poll_work,
+ msecs_to_jiffies(pcdev->poll_interval_ms));
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(devm_pse_poll_helper);
+
/* PSE control section */
static void __pse_control_release(struct kref *kref)
diff --git a/include/linux/pse-pd/pse.h b/include/linux/pse-pd/pse.h
index 4e5696cfade7..44d5d10e239d 100644
--- a/include/linux/pse-pd/pse.h
+++ b/include/linux/pse-pd/pse.h
@@ -292,6 +292,11 @@ struct pse_ntf {
* @pi: table of PSE PIs described in this controller device
* @no_of_pse_pi: flag set if the pse_pis devicetree node is not used
* @irq: PSE interrupt
+ * @polling: flag indicating poll-based event detection is active
+ * @poll_interval_ms: poll interval in milliseconds
+ * @poll_work: delayed work for poll-based event detection
+ * @poll_desc: copy of the driver's event descriptor for polling
+ * @poll_notifs: per-PI notification scratch space for poll worker
* @pis_prio_max: Maximum value allowed for the PSE PIs priority
* @supp_budget_eval_strategies: budget evaluation strategies supported
* by the PSE
@@ -312,6 +317,11 @@ struct pse_controller_dev {
struct pse_pi *pi;
bool no_of_pse_pi;
int irq;
+ bool polling;
+ unsigned int poll_interval_ms;
+ struct delayed_work poll_work;
+ struct pse_irq_desc poll_desc;
+ unsigned long *poll_notifs;
unsigned int pis_prio_max;
u32 supp_budget_eval_strategies;
struct work_struct ntf_work;
@@ -345,6 +355,8 @@ int devm_pse_controller_register(struct device *dev,
struct pse_controller_dev *pcdev);
int devm_pse_irq_helper(struct pse_controller_dev *pcdev, int irq,
int irq_flags, const struct pse_irq_desc *d);
+int devm_pse_poll_helper(struct pse_controller_dev *pcdev,
+ const struct pse_irq_desc *d);
struct pse_control *of_pse_control_get(struct device_node *node,
struct phy_device *phydev);
--
2.43.0
^ permalink raw reply related
* [PATCH net-next v3 1/3] dt-bindings: net: pse-pd: add poll-interval-ms property
From: Carlo Szelinsky @ 2026-03-29 15:31 UTC (permalink / raw)
To: Oleksij Rempel, Kory Maincent
Cc: Andrew Lunn, David S . Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Rob Herring, Krzysztof Kozlowski,
Krzysztof Kozlowski, Conor Dooley, netdev, devicetree,
linux-kernel, linux-leds, Carlo Szelinsky
In-Reply-To: <20260329153124.2823980-1-github@szelinsky.de>
Add the optional poll-interval-ms property for PSE controllers that
use poll-based event detection instead of interrupts. Defaults to
500ms if not specified.
Reviewed-by: Kory Maincent <kory.maincent@bootlin.com>
Signed-off-by: Carlo Szelinsky <github@szelinsky.de>
---
.../devicetree/bindings/net/pse-pd/pse-controller.yaml | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/Documentation/devicetree/bindings/net/pse-pd/pse-controller.yaml b/Documentation/devicetree/bindings/net/pse-pd/pse-controller.yaml
index cd09560e0aea..329d020f054c 100644
--- a/Documentation/devicetree/bindings/net/pse-pd/pse-controller.yaml
+++ b/Documentation/devicetree/bindings/net/pse-pd/pse-controller.yaml
@@ -27,6 +27,14 @@ properties:
subnode. This property is deprecated, please use pse-pis instead.
enum: [0, 1]
+ poll-interval-ms:
+ description:
+ Polling interval in milliseconds for PSE controllers using
+ poll-based event detection instead of interrupts. Used when the
+ controller lacks IRQ support or the IRQ line is not wired.
+ default: 500
+ minimum: 50
+
pse-pis:
type: object
description:
--
2.43.0
^ permalink raw reply related
* [PATCH net-next v3 0/3] net: pse-pd: add poll path and LED trigger support
From: Carlo Szelinsky @ 2026-03-29 15:31 UTC (permalink / raw)
To: Oleksij Rempel, Kory Maincent
Cc: Andrew Lunn, David S . Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Rob Herring, Krzysztof Kozlowski,
Krzysztof Kozlowski, Conor Dooley, netdev, devicetree,
linux-kernel, linux-leds, Carlo Szelinsky
Big thanks to Kory, Oleksij and Krzysztof for all the helpful feedback
on v2 — really appreciate the time you put into reviewing this.
I learned a lot!
This series adds poll-based event detection and LED trigger support
to the PSE core subsystem.
Patches 1-2 introduce the poll path independently of LED support,
so it can be tested in isolation on boards with and without IRQ
configured.
Patch 3 adds LED triggers that hook into the shared event handling
path introduced by patch 2.
Note: pse_handle_events() and the existing pse_isr() pass notifs_mask
as a single unsigned long, which limits the bitmask to BITS_PER_LONG
PI lines. This is a pre-existing constraint in the IRQ path and is
sufficient for all current PSE controllers (max 48 ports vs 64-bit
unsigned long), but may need to be converted to DECLARE_BITMAP() if
future hardware exceeds this limit.
Changes since v2:
- Based on net-next/main, added net-next subject prefix
- Added --base tree information
- Added CC for devicetree list and DT maintainers
- Collected Reviewed-by from Kory Maincent on patch 1/3
- Fixed build error when CONFIG_LEDS_TRIGGERS is disabled:
moved LED registration before list_add(), removing the
pcdev->pi_led_trigs = NULL assignment on conditionally
compiled struct member (reported by kernel test robot)
- Fixed use-after-free on device unbind: poll work is now
cancelled via devm_add_action_or_reset() to ensure correct
devres teardown ordering (poll_work cancelled before
poll_notifs is freed)
- Used system_freezable_wq for poll worker to prevent hardware
access during system suspend
- Added PoDL power status and admin state checks to LED triggers
so they work for both C33 and PoDL controller types
- Used dev_name(dev) for LED trigger names to ensure uniqueness
across multiple PSE controllers (of_node->name can be generic)
- Added initial LED state query at registration so already-active
ports are reflected immediately
- Added pse_led_update() calls in regulator enable/disable paths
so ethtool admin state changes are reflected in LEDs
- Moved LED trigger registration before list_add() to prevent
race where IRQ/poll could invoke pse_led_update() on partially
initialized triggers
Changes since v1:
- Split single patch into 3 separate patches
- Extracted pse_handle_events() and devm_pse_poll_helper() as a
standalone poll path (patches 1-2), testable without LED code
- Added DT binding for poll-interval-ms as a separate patch
- Renamed led-poll-interval-ms to poll-interval-ms for generic use
- Fire LED triggers from the notification path rather than a
separate poll loop
Tested on Realtek RTL9303 with HS104 PoE chip, poll path only
(without IRQ configured). Verified PD connect/disconnect notifications
and LED trigger state changes.
Link: https://lore.kernel.org/all/20260323201225.1836561-1-github@szelinsky.de/
Link: https://lore.kernel.org/all/20260314235916.2391678-1-github@szelinsky.de/
Carlo Szelinsky (3):
dt-bindings: net: pse-pd: add poll-interval-ms property
net: pse-pd: add devm_pse_poll_helper()
net: pse-pd: add LED trigger support via notification path
.../bindings/net/pse-pd/pse-controller.yaml | 8 +
drivers/net/pse-pd/pse_core.c | 298 ++++++++++++++++--
include/linux/pse-pd/pse.h | 34 ++
3 files changed, 309 insertions(+), 31 deletions(-)
base-commit: ced629dc8e5c51ff2b5d847adeeb1035cd655d58
--
2.43.0
^ permalink raw reply
* Re: [PATCH net 0/2] Fix page fragment handling when PAGE_SIZE > 4K
From: Dimitri Daskalakis @ 2026-03-29 15:10 UTC (permalink / raw)
To: Jakub Kicinski
Cc: David S . Miller, Alexander Duyck, Eric Dumazet, Paolo Abeni,
Andrew Lunn, Simon Horman, Mike Marciniszyn, Lee Trager,
Jacob Keller, Mohsin Bashir, Mina Almasry, netdev, kernel-team
In-Reply-To: <20260327202958.53d26d46@kernel.org>
On 3/27/26 8:29 PM, Jakub Kicinski wrote:
> On Tue, 24 Mar 2026 12:51:21 -0700 Dimitri Daskalakis wrote:
>> FBNIC operates on fixed size descriptors (4K). When the OS supports pages
>> larger than 4K, we fragment the page across multiple descriptors.
>>
>> While performance testing, I found several issues with our page fragment
>> handling, resulting in low throughput and potential RX stalls.
> Google AI reviewer points out that we will also be toast if someone
> configures the ring size to just 16 descriptors. Can you check what
> is the min size that doesn't wedge w/ 64kB pages and let's just set
> the min to that instead of the current 16?
Yeah, this looks legit. Bumping the min to 32 should work, but I'll
test/verify before submitting the fix.
^ permalink raw reply
* Re: [PATCH v3 net-next] net: hsr: sync hw addr of slave2 according to slave1 hw addr on PRP
From: Luka Gejak @ 2026-03-29 15:07 UTC (permalink / raw)
To: Fernando Fernandez Mancera, netdev
Cc: edumazet, pabeni, shannon.nelson, horms, luka.gejak, lukma, kuba
In-Reply-To: <20250409101911.3120-1-ffmancera@riseup.net>
On Wed Apr 9, 2025 at 12:19 PM CEST, Fernando Fernandez Mancera wrote:
> In order to work properly PRP requires slave1 and slave2 to share the
> same MAC address. To ease the configuration process on userspace tools,
> sync the slave2 MAC address with slave1. In addition, when deleting the
> port from the list, restore the original MAC address.
>
> Signed-off-by: Fernando Fernandez Mancera <ffmancera@riseup.net>
> ---
> v3: restore the original MAC address on slave removal.
> ---
> net/hsr/hsr_device.c | 5 +++++
> net/hsr/hsr_main.c | 9 +++++++++
> net/hsr/hsr_main.h | 1 +
> net/hsr/hsr_slave.c | 2 ++
> 4 files changed, 17 insertions(+)
>
> diff --git a/net/hsr/hsr_device.c b/net/hsr/hsr_device.c
> index 439cfb7ad5d1..e8922e8d9398 100644
> --- a/net/hsr/hsr_device.c
> +++ b/net/hsr/hsr_device.c
> @@ -761,6 +761,11 @@ int hsr_dev_finalize(struct net_device *hsr_dev, struct net_device *slave[2],
> if (res)
> goto err_unregister;
>
> + if (protocol_version == PRP_V1) {
> + eth_hw_addr_set(slave[1], slave[0]->dev_addr);
> + call_netdevice_notifiers(NETDEV_CHANGEADDR, slave[1]);
> + }
> +
> if (interlink) {
> res = hsr_add_port(hsr, interlink, HSR_PT_INTERLINK, extack);
> if (res)
> diff --git a/net/hsr/hsr_main.c b/net/hsr/hsr_main.c
> index d7ae32473c41..192893c3f2ec 100644
> --- a/net/hsr/hsr_main.c
> +++ b/net/hsr/hsr_main.c
> @@ -78,6 +78,15 @@ static int hsr_netdev_notify(struct notifier_block *nb, unsigned long event,
> eth_hw_addr_set(master->dev, dev->dev_addr);
> call_netdevice_notifiers(NETDEV_CHANGEADDR,
> master->dev);
> +
> + if (hsr->prot_version == PRP_V1) {
> + port = hsr_port_get_hsr(hsr, HSR_PT_SLAVE_B);
> + if (port) {
> + eth_hw_addr_set(port->dev, dev->dev_addr);
> + call_netdevice_notifiers(NETDEV_CHANGEADDR,
> + port->dev);
> + }
> + }
> }
>
> /* Make sure we recognize frames from ourselves in hsr_rcv() */
> diff --git a/net/hsr/hsr_main.h b/net/hsr/hsr_main.h
> index 1bc47b17a296..135ec5fce019 100644
> --- a/net/hsr/hsr_main.h
> +++ b/net/hsr/hsr_main.h
> @@ -155,6 +155,7 @@ struct hsr_port {
> struct hsr_priv *hsr;
> enum hsr_port_type type;
> struct rcu_head rcu;
> + unsigned char original_macaddress[ETH_ALEN];
> };
>
> struct hsr_frame_info;
> diff --git a/net/hsr/hsr_slave.c b/net/hsr/hsr_slave.c
> index 2a802a5de2ac..b87b6a6fe070 100644
> --- a/net/hsr/hsr_slave.c
> +++ b/net/hsr/hsr_slave.c
> @@ -196,6 +196,7 @@ int hsr_add_port(struct hsr_priv *hsr, struct net_device *dev,
> port->hsr = hsr;
> port->dev = dev;
> port->type = type;
> + ether_addr_copy(port->original_macaddress, dev->dev_addr);
>
> if (type != HSR_PT_MASTER) {
> res = hsr_portdev_setup(hsr, dev, port, extack);
> @@ -232,6 +233,7 @@ void hsr_del_port(struct hsr_port *port)
> if (!port->hsr->fwd_offloaded)
> dev_set_promiscuity(port->dev, -1);
> netdev_upper_dev_unlink(port->dev, master->dev);
> + eth_hw_addr_set(port->dev, port->original_macaddress);
> }
>
> kfree_rcu(port, rcu);
Hi Fernando,
Thanks for the patch. The logic to sync the slave2 MAC address with
slave1 for PRP is sound, but there are a few implementation issues here
that will cause hardware filtering problems and style violations.
1. Hardware MAC Filtering
In your current implementation:
if (protocol_version == PRP_V1) {
eth_hw_addr_set(slave[1], slave[0]->dev_addr);
call_netdevice_notifiers(NETDEV_CHANGEADDR, slave[1]);
}
eth_hw_addr_set() is appropriate for virtual devices (like the hsr_dev
itself), but slave[1] is a physical net_device. By using this helper,
you are bypassing dev->netdev_ops->ndo_set_mac_address. This means the
physical NIC's hardware MAC filter will not be programmed, and it will
silently drop unicast traffic destined for the new PRP MAC address
unless the interface happens to be in promiscuous mode. You should use
dev_set_mac_address() here instead. Note that unlike eth_hw_addr_set(),
dev_set_mac_address() can fail and returns an error code, so you will
need to check its return value and handle the error path accordingly.
2. Teardown Notifiers
In hsr_del_port():
netdev_upper_dev_unlink(port->dev, master->dev);
eth_hw_addr_set(port->dev, port->original_macaddress);
You have the same issue with eth_hw_addr_set() here. Additionally,
unlike the setup paths, this version omits call_netdevice_notifiers
(NETDEV_CHANGEADDR, port->dev). Switching to dev_set_mac_address() for
the restoration will handle both the hardware programming and the
notifier chain automatically.
3. Coding Style
In hsr_main.h:
unsigned char original_macaddress[ETH_ALEN];
Please use u8 instead of unsigned char for byte arrays to align with
standard netdev coding styles.
Please address these points and submit a v4.
Best regards,
Luka Gejak
^ permalink raw reply
* [PATCH iwl-net v1] igc: fix potential skb leak in igc_fpe_xmit_smd_frame()
From: Kohei Enju @ 2026-03-29 14:50 UTC (permalink / raw)
To: intel-wired-lan, netdev
Cc: Tony Nguyen, Przemek Kitszel, Andrew Lunn, David S. Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni, Faizal Rahim,
Kohei Enju
When igc_fpe_init_tx_descriptor() fails, no one takes care of an
allocated skb, leaking it. [1]
Use dev_kfree_skb_any() on failure.
Also call igc_flush_tx_descriptors() only on success.
[1]
unreferenced object 0xffff88813aee1b40 (size 224):
comm "softirq", pid 0, jiffies 4294709256
[...]
backtrace (crc dee31384):
kmem_cache_alloc_node_noprof+0x54f/0x640
__alloc_skb+0xd9/0x5b0
igc_fpe_xmit_smd_frame.isra.0+0xad/0x510
igc_fpe_send_mpacket+0x32/0x80
[...]
Fixes: 5422570c0010 ("igc: add support for frame preemption verification")
Signed-off-by: Kohei Enju <kohei@enjuk.jp>
---
drivers/net/ethernet/intel/igc/igc_tsn.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/intel/igc/igc_tsn.c b/drivers/net/ethernet/intel/igc/igc_tsn.c
index 8a110145bfee..eaa274248d54 100644
--- a/drivers/net/ethernet/intel/igc/igc_tsn.c
+++ b/drivers/net/ethernet/intel/igc/igc_tsn.c
@@ -109,10 +109,14 @@ static int igc_fpe_xmit_smd_frame(struct igc_adapter *adapter,
__netif_tx_lock(nq, cpu);
err = igc_fpe_init_tx_descriptor(ring, skb, type);
- igc_flush_tx_descriptors(ring);
+ if (!err)
+ igc_flush_tx_descriptors(ring);
__netif_tx_unlock(nq);
+ if (err)
+ dev_kfree_skb_any(skb);
+
return err;
}
--
2.51.0
^ permalink raw reply related
* Re: (subset) [PATCH net-next v4 0/2] Add ICSSG0 dual EMAC support for AM642 EVM
From: Vignesh Raghavendra @ 2026-03-29 14:49 UTC (permalink / raw)
To: Nishanth Menon, Meghana Malladi
Cc: Tero Kristo, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
linux-arm-kernel, devicetree, linux-kernel, netdev, srk,
danishanwar
In-Reply-To: <20260323090358.632329-1-m-malladi@ti.com>
Hi Meghana Malladi,
On Mon, 23 Mar 2026 14:33:56 +0530, Meghana Malladi wrote:
> Add ICSSG0 dual EMAC support for AM642 EVM
>
> This series adds device tree overlay support for enabling ICSSG0 dual EMAC
> on the AM642 EVM, along with the necessary PHY driver configuration.
>
> The overlay enables both ICSSG0 Ethernet interfaces (port0 and port1) in
> dual EMAC mode and can be combined with the existing ICSSG1 overlay to
> enable all four ICSSG interfaces if needed.
>
> [...]
I have applied the following to branch ti-k3-config-next on [1].
Thank you!
[2/2] arm64: defconfig: Enable DP83TG720 PHY driver
commit: 192c7f34d2f63552211ef4cb8bbd2933f95106e2
All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent up the chain during
the next merge window (or sooner if it is a relevant bug fix), however if
problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying
to this mail.
[1] https://git.kernel.org/pub/scm/linux/kernel/git/ti/linux.git
--
Vignesh
^ permalink raw reply
* Re: (subset) [PATCH v3 0/2] Add ICSSG0 dual EMAC support for AM642 EVM
From: Vignesh Raghavendra @ 2026-03-29 14:48 UTC (permalink / raw)
To: Nishanth Menon, Meghana Malladi
Cc: Vignesh Raghavendra, Tero Kristo, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, linux-arm-kernel, devicetree,
linux-kernel, netdev, srk, danishanwar
In-Reply-To: <20260311053852.1034244-1-m-malladi@ti.com>
Hi Meghana Malladi,
On Wed, 11 Mar 2026 11:08:50 +0530, Meghana Malladi wrote:
> This series adds device tree overlay support for enabling ICSSG0 dual EMAC
> on the AM642 EVM, along with the necessary PHY driver configuration.
>
> The overlay enables both ICSSG0 Ethernet interfaces (port0 and port1) in
> dual EMAC mode and can be combined with the existing ICSSG1 overlay to
> enable all four ICSSG interfaces if needed.
>
> [...]
I have applied the following to branch ti-k3-dts-next on [1].
Thank you!
[1/2] arm64: dts: ti: k3-am642-evm: Add ICSSG0 overlay for dual EMAC support
commit: 8bafdf5dd89b961b698d8bd2cfcebc8e4d3764fd
All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent up the chain during
the next merge window (or sooner if it is a relevant bug fix), however if
problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying
to this mail.
[1] https://git.kernel.org/pub/scm/linux/kernel/git/ti/linux.git
--
Vignesh
^ permalink raw reply
* [PATCH 5/5] hamradio: mkiss: cleanup indentation and coding style
From: Mashiro Chen @ 2026-03-29 14:34 UTC (permalink / raw)
To: andrew+netdev, davem, edumazet, kuba, pabeni
Cc: netdev, linux-hams, linux-kernel, Mashiro Chen
In-Reply-To: <20260329143408.747197-1-mashiro.chen@mailbox.org>
Clean up the remaining coding style issues in mkiss.c
to follow the Linux Kernel coding standards. The
primary changes include fixing indentation and
alignment issues by using tabs instead of spaces where
possible. Additionally, add missing spaces after
keywords and blank lines after variable declarations.
Block comment formatting is also adjusted to use a
separate line for the trailing delimiter.
Signed-off-by: Mashiro Chen <mashiro.chen@mailbox.org>
---
drivers/net/hamradio/mkiss.c | 34 +++++++++++++++++++---------------
1 file changed, 19 insertions(+), 15 deletions(-)
diff --git a/drivers/net/hamradio/mkiss.c b/drivers/net/hamradio/mkiss.c
index 75b9bd2e1..8939582ac 100644
--- a/drivers/net/hamradio/mkiss.c
+++ b/drivers/net/hamradio/mkiss.c
@@ -64,7 +64,7 @@ struct mkiss {
#define AXF_OUTWAIT 4 /* is outpacket was flag */
int mode;
- int crcmode; /* MW: for FlexNet, SMACK etc. */
+ int crcmode; /* MW: for FlexNet, SMACK etc. */
int crcauto; /* CRC auto mode */
#define CRC_MODE_NONE 0
@@ -439,27 +439,30 @@ static void ax_encaps(struct net_device *dev, unsigned char *icp, int len)
/* Configuration Command (kissparms(1).
* Protocol spec says: never append CRC.
* This fixes a very old bug in the linux
- * kiss driver. -- dl9sau */
+ * kiss driver. -- dl9sau
+ */
switch (*p & 0xff) {
case 0x85:
/* command from userspace especially for us,
- * not for delivery to the tnc */
+ * not for delivery to the tnc
+ */
if (len > 1) {
int cmd = (p[1] & 0xff);
- switch(cmd) {
+
+ switch (cmd) {
case 3:
- ax->crcmode = CRC_MODE_SMACK;
- break;
+ ax->crcmode = CRC_MODE_SMACK;
+ break;
case 2:
- ax->crcmode = CRC_MODE_FLEX;
- break;
+ ax->crcmode = CRC_MODE_FLEX;
+ break;
case 1:
- ax->crcmode = CRC_MODE_NONE;
- break;
+ ax->crcmode = CRC_MODE_NONE;
+ break;
case 0:
default:
- ax->crcmode = CRC_MODE_SMACK_TEST;
- cmd = 0;
+ ax->crcmode = CRC_MODE_SMACK_TEST;
+ cmd = 0;
}
ax->crcauto = (cmd ? 0 : 1);
netdev_info(ax->dev, "crc mode set to %d\n", cmd);
@@ -473,6 +476,7 @@ static void ax_encaps(struct net_device *dev, unsigned char *icp, int len)
}
} else {
unsigned short crc;
+
switch (ax->crcmode) {
case CRC_MODE_SMACK_TEST:
ax->crcmode = CRC_MODE_FLEX_TEST;
@@ -812,7 +816,7 @@ static int mkiss_ioctl(struct tty_struct *tty, unsigned int cmd,
switch (cmd) {
case SIOCGIFNAME:
err = copy_to_user((void __user *) arg, ax->dev->name,
- strlen(ax->dev->name) + 1) ? -EFAULT : 0;
+ strlen(ax->dev->name) + 1) ? -EFAULT : 0;
break;
case SIOCGIFENCAP:
@@ -828,7 +832,7 @@ static int mkiss_ioctl(struct tty_struct *tty, unsigned int cmd,
ax->mode = tmp;
dev->addr_len = AX25_ADDR_LEN;
dev->hard_header_len = AX25_KISS_HEADER_LEN +
- AX25_MAX_HEADER_LEN + 3;
+ AX25_MAX_HEADER_LEN + 3;
dev->type = ARPHRD_AX25;
err = 0;
@@ -838,7 +842,7 @@ static int mkiss_ioctl(struct tty_struct *tty, unsigned int cmd,
char addr[AX25_ADDR_LEN];
if (copy_from_user(&addr,
- (void __user *) arg, AX25_ADDR_LEN)) {
+ (void __user *)arg, AX25_ADDR_LEN)) {
err = -EFAULT;
break;
}
--
2.53.0
^ permalink raw reply related
* [PATCH 4/5] hamradio: mkiss: modernize logging with netdev and pr macros
From: Mashiro Chen @ 2026-03-29 14:34 UTC (permalink / raw)
To: andrew+netdev, davem, edumazet, kuba, pabeni
Cc: netdev, linux-hams, linux-kernel, Mashiro Chen
In-Reply-To: <20260329143408.747197-1-mashiro.chen@mailbox.org>
Replace legacy printk() calls with modern logging macros.
This allows for better device-specific context by using
netdev_err() and netdev_info() where possible. For global
module-level messages, use pr_info() and pr_err(). This
modernization also allows the removal of the redundant
'banner' and 'msg_regfail' static strings, simplifying
the driver initialization logic.
Signed-off-by: Mashiro Chen <mashiro.chen@mailbox.org>
---
drivers/net/hamradio/mkiss.c | 51 ++++++++++++------------------------
1 file changed, 17 insertions(+), 34 deletions(-)
diff --git a/drivers/net/hamradio/mkiss.c b/drivers/net/hamradio/mkiss.c
index b9160b95f..75b9bd2e1 100644
--- a/drivers/net/hamradio/mkiss.c
+++ b/drivers/net/hamradio/mkiss.c
@@ -249,9 +249,7 @@ static void ax_bump(struct mkiss *ax)
return;
}
if (ax->crcmode != CRC_MODE_SMACK && ax->crcauto) {
- printk(KERN_INFO
- "mkiss: %s: Switching to crc-smack\n",
- ax->dev->name);
+ netdev_info(ax->dev, "Switching to crc-smack\n");
ax->crcmode = CRC_MODE_SMACK;
}
ax->rcount -= 2;
@@ -263,9 +261,7 @@ static void ax_bump(struct mkiss *ax)
return;
}
if (ax->crcmode != CRC_MODE_FLEX && ax->crcauto) {
- printk(KERN_INFO
- "mkiss: %s: Switching to crc-flexnet\n",
- ax->dev->name);
+ netdev_info(ax->dev, "Switching to crc-flexnet\n");
ax->crcmode = CRC_MODE_FLEX;
}
ax->rcount -= 2;
@@ -284,8 +280,7 @@ static void ax_bump(struct mkiss *ax)
skb = dev_alloc_skb(count);
if (!skb) {
- printk(KERN_ERR "mkiss: %s: memory squeeze, dropping packet.\n",
- ax->dev->name);
+ netdev_err(ax->dev, "memory squeeze, dropping packet.\n");
ax->dev->stats.rx_dropped++;
spin_unlock_bh(&ax->buflock);
return;
@@ -376,9 +371,7 @@ static void ax_changedmtu(struct mkiss *ax)
rbuff = kmalloc(len + 4, GFP_ATOMIC);
if (xbuff == NULL || rbuff == NULL) {
- printk(KERN_ERR "mkiss: %s: unable to grow ax25 buffers, "
- "MTU change cancelled.\n",
- ax->dev->name);
+ netdev_err(ax->dev, "unable to grow ax25 buffers, MTU change cancelled.\n");
dev->mtu = ax->mtu;
kfree(xbuff);
kfree(rbuff);
@@ -433,7 +426,7 @@ static void ax_encaps(struct net_device *dev, unsigned char *icp, int len)
ax_changedmtu(ax);
if (len > ax->mtu) { /* Sigh, shouldn't occur BUT ... */
- printk(KERN_ERR "mkiss: %s: truncating oversized transmit packet!\n", ax->dev->name);
+ netdev_err(ax->dev, "truncating oversized transmit packet!\n");
dev->stats.tx_dropped++;
netif_start_queue(dev);
return;
@@ -469,8 +462,7 @@ static void ax_encaps(struct net_device *dev, unsigned char *icp, int len)
cmd = 0;
}
ax->crcauto = (cmd ? 0 : 1);
- printk(KERN_INFO "mkiss: %s: crc mode set to %d\n",
- ax->dev->name, cmd);
+ netdev_info(ax->dev, "crc mode set to %d\n", cmd);
}
spin_unlock_bh(&ax->buflock);
netif_start_queue(dev);
@@ -484,7 +476,7 @@ static void ax_encaps(struct net_device *dev, unsigned char *icp, int len)
switch (ax->crcmode) {
case CRC_MODE_SMACK_TEST:
ax->crcmode = CRC_MODE_FLEX_TEST;
- printk(KERN_INFO "mkiss: %s: Trying crc-smack\n", ax->dev->name);
+ netdev_info(ax->dev, "Trying crc-smack\n");
fallthrough;
case CRC_MODE_SMACK:
*p |= 0x80;
@@ -493,7 +485,7 @@ static void ax_encaps(struct net_device *dev, unsigned char *icp, int len)
break;
case CRC_MODE_FLEX_TEST:
ax->crcmode = CRC_MODE_NONE;
- printk(KERN_INFO "mkiss: %s: Trying crc-flexnet\n", ax->dev->name);
+ netdev_info(ax->dev, "Trying crc-flexnet\n");
fallthrough;
case CRC_MODE_FLEX:
*p |= 0x20;
@@ -526,7 +518,7 @@ static netdev_tx_t ax_xmit(struct sk_buff *skb, struct net_device *dev)
return ax25_ip_xmit(skb);
if (!netif_running(dev)) {
- printk(KERN_ERR "mkiss: %s: xmit call when iface is down\n", dev->name);
+ netdev_err(ax->dev, "xmit call when iface is down\n");
return NETDEV_TX_BUSY;
}
@@ -540,8 +532,8 @@ static netdev_tx_t ax_xmit(struct sk_buff *skb, struct net_device *dev)
return NETDEV_TX_BUSY;
}
- printk(KERN_ERR "mkiss: %s: transmit timed out, %s?\n", dev->name,
- (tty_chars_in_buffer(ax->tty) || ax->xleft) ?
+ netdev_err(ax->dev, "transmit timed out, %s?\n",
+ (tty_chars_in_buffer(ax->tty) || ax->xleft) ?
"bad line quality" : "driver error");
ax->xleft = 0;
@@ -735,24 +727,20 @@ static int mkiss_open(struct tty_struct *tty)
switch (crc_force) {
case 3:
ax->crcmode = CRC_MODE_SMACK;
- printk(KERN_INFO "mkiss: %s: crc mode smack forced.\n",
- ax->dev->name);
+ netdev_info(ax->dev, "crc mode smack forced.\n");
break;
case 2:
ax->crcmode = CRC_MODE_FLEX;
- printk(KERN_INFO "mkiss: %s: crc mode flexnet forced.\n",
- ax->dev->name);
+ netdev_info(ax->dev, "crc mode flexnet forced.\n");
break;
case 1:
ax->crcmode = CRC_MODE_NONE;
- printk(KERN_INFO "mkiss: %s: crc mode disabled.\n",
- ax->dev->name);
+ netdev_info(ax->dev, "crc mode disabled.\n");
break;
case 0:
default:
crc_force = 0;
- printk(KERN_INFO "mkiss: %s: crc mode is auto.\n",
- ax->dev->name);
+ netdev_info(ax->dev, "crc mode is auto.\n");
ax->crcmode = CRC_MODE_SMACK_TEST;
}
ax->crcauto = (crc_force ? 0 : 1);
@@ -949,20 +937,15 @@ static struct tty_ldisc_ops ax_ldisc = {
.write_wakeup = mkiss_write_wakeup
};
-static const char banner[] __initconst = KERN_INFO \
- "mkiss: AX.25 Multikiss, Hans Albas PE1AYX\n";
-static const char msg_regfail[] __initconst = KERN_ERR \
- "mkiss: can't register line discipline (err = %d)\n";
-
static int __init mkiss_init_driver(void)
{
int status;
- printk(banner);
+ pr_info("mkiss: AX.25 Multikiss, Hans Albas PE1AYX\n");
status = tty_register_ldisc(&ax_ldisc);
if (status != 0)
- printk(msg_regfail, status);
+ pr_err("mkiss: can't register line discipline (err = %d)\n", status);
return status;
}
--
2.53.0
^ permalink raw reply related
* [PATCH 3/5] hamradio: mkiss: fix spacing around assignment operator
From: Mashiro Chen @ 2026-03-29 14:34 UTC (permalink / raw)
To: andrew+netdev, davem, edumazet, kuba, pabeni
Cc: netdev, linux-hams, linux-kernel, Mashiro Chen
In-Reply-To: <20260329143408.747197-1-mashiro.chen@mailbox.org>
Add missing spaces around the assignment operator to
adhere to the Linux Kernel coding style.
Signed-off-by: Mashiro Chen <mashiro.chen@mailbox.org>
---
drivers/net/hamradio/mkiss.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/hamradio/mkiss.c b/drivers/net/hamradio/mkiss.c
index 3721572ce..b9160b95f 100644
--- a/drivers/net/hamradio/mkiss.c
+++ b/drivers/net/hamradio/mkiss.c
@@ -201,7 +201,7 @@ static int kiss_esc_crc(unsigned char *s, unsigned char *d, unsigned short crc,
int len)
{
unsigned char *ptr = d;
- unsigned char c=0;
+ unsigned char c = 0;
*ptr++ = END;
while (len > 0) {
--
2.53.0
^ permalink raw reply related
* [PATCH 2/5] hamradio: mkiss: remove redundant static initialization to 0
From: Mashiro Chen @ 2026-03-29 14:34 UTC (permalink / raw)
To: andrew+netdev, davem, edumazet, kuba, pabeni
Cc: netdev, linux-hams, linux-kernel, Mashiro Chen
In-Reply-To: <20260329143408.747197-1-mashiro.chen@mailbox.org>
Static variables are automatically initialized to 0 by the
compiler.
Remove the explicit initialization to comply with the Linux
Kernel coding standards.
Signed-off-by: Mashiro Chen <mashiro.chen@mailbox.org>
---
drivers/net/hamradio/mkiss.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/hamradio/mkiss.c b/drivers/net/hamradio/mkiss.c
index eac45d936..3721572ce 100644
--- a/drivers/net/hamradio/mkiss.c
+++ b/drivers/net/hamradio/mkiss.c
@@ -686,7 +686,7 @@ static void mkiss_put(struct mkiss *ax)
complete(&ax->dead);
}
-static int crc_force = 0; /* Can be overridden with insmod */
+static int crc_force; /* Can be overridden with insmod */
static int mkiss_open(struct tty_struct *tty)
{
--
2.53.0
^ permalink raw reply related
* [PATCH 1/5] hamradio: mkiss: move assignments out of if conditions
From: Mashiro Chen @ 2026-03-29 14:34 UTC (permalink / raw)
To: andrew+netdev, davem, edumazet, kuba, pabeni
Cc: netdev, linux-hams, linux-kernel, Mashiro Chen
In-Reply-To: <20260329143408.747197-1-mashiro.chen@mailbox.org>
Move assignments out of if conditions to comply with
the Linux Kernel coding style and improve code
readability. This also switches to the preferred
'if (!ptr)' idiom for NULL pointer checks.
Signed-off-by: Mashiro Chen <mashiro.chen@mailbox.org>
---
drivers/net/hamradio/mkiss.c | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/drivers/net/hamradio/mkiss.c b/drivers/net/hamradio/mkiss.c
index 5f38a002b..eac45d936 100644
--- a/drivers/net/hamradio/mkiss.c
+++ b/drivers/net/hamradio/mkiss.c
@@ -282,7 +282,8 @@ static void ax_bump(struct mkiss *ax)
count = ax->rcount;
- if ((skb = dev_alloc_skb(count)) == NULL) {
+ skb = dev_alloc_skb(count);
+ if (!skb) {
printk(KERN_ERR "mkiss: %s: memory squeeze, dropping packet.\n",
ax->dev->name);
ax->dev->stats.rx_dropped++;
@@ -591,10 +592,12 @@ static int ax_open(struct net_device *dev)
if (len < 576 * 2)
len = 576 * 2;
- if ((ax->rbuff = kmalloc(len + 4, GFP_KERNEL)) == NULL)
+ ax->rbuff = kmalloc(len + 4, GFP_KERNEL);
+ if (!ax->rbuff)
goto norbuff;
- if ((ax->xbuff = kmalloc(len + 4, GFP_KERNEL)) == NULL)
+ ax->xbuff = kmalloc(len + 4, GFP_KERNEL);
+ if (!ax->xbuff)
goto noxbuff;
ax->mtu = dev->mtu + 73;
--
2.53.0
^ permalink raw reply related
* [PATCH 0/5] hamradio: mkiss: modernize and clean up mkiss driver
From: Mashiro Chen @ 2026-03-29 14:34 UTC (permalink / raw)
To: andrew+netdev, davem, edumazet, kuba, pabeni
Cc: netdev, linux-hams, linux-kernel, Mashiro Chen
This patch series modernizes the mkiss driver, which is used for
AX.25 communication over serial lines.
The series starts by moving variable assignments out of 'if'
conditions to improve code safety and readability.
The second patch removes redundant static initializations to 0.
The third patch fixes missing spaces around assignment operations.
The fourth patch modernizes the logging system by replacing legacy
printk() calls with netdev_* and pr_* macros for better
device-specific context.
The fifth patch addresses remaining checkpatch.pl issues, primarily
converting space-based indentation to tabs, aligning parameters, and
fixing comment formats.
These changes have been compile-tested.
Mashiro Chen (5):
hamradio: mkiss: move assignments out of if conditions
hamradio: mkiss: remove redundant static initialization to 0
hamradio: mkiss: fix spacing around assignment operator
hamradio: mkiss: modernize logging with netdev and pr macros
hamradio: mkiss: cleanup indentation and coding style
drivers/net/hamradio/mkiss.c | 98 ++++++++++++++++--------------------
1 file changed, 44 insertions(+), 54 deletions(-)
--
2.53.0
^ permalink raw reply
* Re: [PATCH net-next 01/10] net: stmmac: fix TSO support when some channels have TBS available
From: Andrew Lunn @ 2026-03-29 14:03 UTC (permalink / raw)
To: Russell King (Oracle)
Cc: Alexandre Torgue, Andrew Lunn, David S. Miller, Eric Dumazet,
Jakub Kicinski, linux-arm-kernel, linux-stm32, netdev,
Ong Boon Leong, Paolo Abeni
In-Reply-To: <acjzmxY9xmBInSwm@shell.armlinux.org.uk>
> * Packets that won't trigger the COE e.g. most DSA-tagged packets will
> * also have to be checksummed in software.
> */
I doubt DSA will work with TSO, it would have to include the DSA
header into the replicated header when doing segmentation.
I thought we had some code in DSA to turn off features which are
likely to cause issues. But i don't see it.
Hardware checksumming has been an issue in the past with DSA. Some MAC
hardware from switch vendors, Marvell, Broadcom etc, understand the
DSA header and so can do the checksum correctly when the DSA tag is
present. MAC hardware from other vendors often get confused so
software checksumming is needed.
Andrew
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox