Netdev List
 help / color / mirror / Atom feed
* [PATCH net 0/2] net: ti: icssg-prueth: fix port config and rx_mode drops
@ 2026-10-14 12:59 Rishi Kumar
  2026-10-14 12:59 ` [PATCH net 1/2] net: ti: icssg-prueth: fix missing port config on second interface open Rishi Kumar
                   ` (2 more replies)
  0 siblings, 3 replies; 7+ messages in thread
From: Rishi Kumar @ 2026-10-14 12:59 UTC (permalink / raw)
  To: netdev
  Cc: MD Danish Anwar, Roger Quadros, Andrew Lunn, David S . Miller,
	Eric Dumazet, Jakub Kicinski, Paolo Abeni, Jacob Keller,
	Meghana Malladi, Vadim Fedorenko, Kevin Hao, linux-arm-kernel,
	linux-kernel, j-rameshbabu, aaron.richard, l-chinnannavar,
	m-santhoshkadavan, k-tiwari1, a-dev, r-kumar12, pratheesh

Two independent fixes for the ICSSG PRUETH driver, both hit during
switch offload testing with ports opened/closed in varying order.


Patch 1 fixes icssg_enable_fw_offload() running only once, on the
first port to open (gated by !emacs_initialized), so a sibling port
that opens later never gets its FDB/VLAN table/PVID configured. Each
port now configures itself at open time.

Patch 2 fixes icssg_set_port_state() commands (e.g. promisc/allmulti
flood enable from rx_mode_work) being silently dropped when they race
a PRU/RTU/txPRU firmware reboot, by re-queuing rx_mode_work for all
running ports once the firmware is confirmed back up.

Rishi Kumar (2):
  net: ti: icssg-prueth: fix missing port config on second interface
    open
  net: ti: icssg-prueth: re-apply rx_mode state after firmware reboot

 drivers/net/ethernet/ti/icssg/icssg_prueth.c | 89 ++++++++++++++------
 1 file changed, 61 insertions(+), 28 deletions(-)

-- 
2.53.0


^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH net 1/2] net: ti: icssg-prueth: fix missing port config on second interface open
  2026-10-14 12:59 [PATCH net 0/2] net: ti: icssg-prueth: fix port config and rx_mode drops Rishi Kumar
@ 2026-10-14 12:59 ` Rishi Kumar
  2026-10-18 13:22   ` netdev-bot+sashiko
  2026-10-14 12:59 ` [PATCH net 2/2] net: ti: icssg-prueth: re-apply rx_mode state after firmware reboot Rishi Kumar
  2026-10-14 13:05 ` [PATCH net 0/2] net: ti: icssg-prueth: fix port config and rx_mode drops netdev-bot+sinfo
  2 siblings, 1 reply; 7+ messages in thread
From: Rishi Kumar @ 2026-10-14 12:59 UTC (permalink / raw)
  To: netdev
  Cc: MD Danish Anwar, Roger Quadros, Andrew Lunn, David S . Miller,
	Eric Dumazet, Jakub Kicinski, Paolo Abeni, Jacob Keller,
	Meghana Malladi, Vadim Fedorenko, Kevin Hao, linux-arm-kernel,
	linux-kernel, j-rameshbabu, aaron.richard, l-chinnannavar,
	m-santhoshkadavan, k-tiwari1, a-dev, r-kumar12, pratheesh

icssg_enable_fw_offload() is gated by !prueth->emacs_initialized, so it
runs only once, on whichever port opens first. If the sibling port is
not yet running at that point, the netif_running() check skips it and
its FDB entry and VLAN table membership are never configured. If one
port is later brought down and up while the sibling stays up,
emacs_initialized is still non-zero, so the function never runs again
and the port is left unconfigured, depending on bring-up order.

Extract the per-port FDB, VLAN table, PVID and VLAN-aware setup into a
new helper icssg_enable_fw_offload_emac(), and the HSR Rx offload
setup into icssg_update_hsr_rx_offload(). Call both unconditionally
from emac_ndo_open() for the port that is actually opening, so each
port configures itself at open time regardless of sibling port state.

icssg_enable_fw_offload() now uses the same helpers and is kept for
icssg_change_mode(), which needs to reconfigure all running ports
after a full firmware restart.

prefix logs: https://gist.github.com/r-kumar12/2279fbfeb5b451a427c4c9778cdfca4a
postfix logs: https://gist.github.com/r-kumar12/071bd3625040fc1fb71207df4e652f58

Fixes: 01792bc3e5bd ("net: ti: icssg-prueth: Fix HSR and switch offload Enablement during firwmare reload.")
Signed-off-by: Rishi Kumar <r-kumar12@ti.com>
---
 drivers/net/ethernet/ti/icssg/icssg_prueth.c | 72 ++++++++++++--------
 1 file changed, 44 insertions(+), 28 deletions(-)

diff --git a/drivers/net/ethernet/ti/icssg/icssg_prueth.c b/drivers/net/ethernet/ti/icssg/icssg_prueth.c
index f43c1394179f..745178fe7cf3 100644
--- a/drivers/net/ethernet/ti/icssg/icssg_prueth.c
+++ b/drivers/net/ethernet/ti/icssg/icssg_prueth.c
@@ -206,6 +206,44 @@ static void prueth_emac_stop(struct prueth *prueth)
 	}
 }
 
+static void icssg_update_hsr_rx_offload(struct prueth_emac *emac)
+{
+	struct prueth *prueth = emac->prueth;
+
+	if (!prueth->is_hsr_offload_mode)
+		return;
+
+	if (emac->ndev->features & NETIF_F_HW_HSR_TAG_RM)
+		icssg_set_port_state(emac, ICSSG_EMAC_HSR_RX_OFFLOAD_ENABLE);
+	else
+		icssg_set_port_state(emac, ICSSG_EMAC_HSR_RX_OFFLOAD_DISABLE);
+}
+
+static void icssg_enable_fw_offload_emac(struct prueth_emac *emac)
+{
+	struct prueth *prueth = emac->prueth;
+
+	if (prueth->is_switch_mode || prueth->is_hsr_offload_mode) {
+		icssg_fdb_add_del(emac, eth_stp_addr, prueth->default_vlan,
+				  ICSSG_FDB_ENTRY_P0_MEMBERSHIP |
+				  ICSSG_FDB_ENTRY_P1_MEMBERSHIP |
+				  ICSSG_FDB_ENTRY_P2_MEMBERSHIP |
+				  ICSSG_FDB_ENTRY_BLOCK,
+				  true);
+		icssg_vtbl_modify(emac, emac->port_vlan | DEFAULT_VID,
+				  BIT(emac->port_id) | DEFAULT_PORT_MASK,
+				  BIT(emac->port_id) | DEFAULT_UNTAG_MASK,
+				  true);
+		if (prueth->is_hsr_offload_mode)
+			icssg_vtbl_modify(emac, DEFAULT_VID,
+					  DEFAULT_PORT_MASK,
+					  DEFAULT_UNTAG_MASK, true);
+		icssg_set_pvid(prueth, emac->port_vlan, emac->port_id);
+		if (prueth->is_switch_mode)
+			icssg_set_port_state(emac, ICSSG_EMAC_PORT_VLAN_AWARE_ENABLE);
+	}
+}
+
 static void icssg_enable_fw_offload(struct prueth *prueth)
 {
 	struct prueth_emac *emac;
@@ -213,34 +251,11 @@ static void icssg_enable_fw_offload(struct prueth *prueth)
 
 	for (mac = PRUETH_MAC0; mac < PRUETH_NUM_MACS; mac++) {
 		emac = prueth->emac[mac];
-		if (prueth->is_hsr_offload_mode) {
-			if (emac->ndev->features & NETIF_F_HW_HSR_TAG_RM)
-				icssg_set_port_state(emac, ICSSG_EMAC_HSR_RX_OFFLOAD_ENABLE);
-			else
-				icssg_set_port_state(emac, ICSSG_EMAC_HSR_RX_OFFLOAD_DISABLE);
-		}
 
-		if (prueth->is_switch_mode || prueth->is_hsr_offload_mode) {
-			if (netif_running(emac->ndev)) {
-				icssg_fdb_add_del(emac, eth_stp_addr, prueth->default_vlan,
-						  ICSSG_FDB_ENTRY_P0_MEMBERSHIP |
-						  ICSSG_FDB_ENTRY_P1_MEMBERSHIP |
-						  ICSSG_FDB_ENTRY_P2_MEMBERSHIP |
-						  ICSSG_FDB_ENTRY_BLOCK,
-						  true);
-				icssg_vtbl_modify(emac, emac->port_vlan | DEFAULT_VID,
-						  BIT(emac->port_id) | DEFAULT_PORT_MASK,
-						  BIT(emac->port_id) | DEFAULT_UNTAG_MASK,
-						  true);
-				if (prueth->is_hsr_offload_mode)
-					icssg_vtbl_modify(emac, DEFAULT_VID,
-							  DEFAULT_PORT_MASK,
-							  DEFAULT_UNTAG_MASK, true);
-				icssg_set_pvid(prueth, emac->port_vlan, emac->port_id);
-				if (prueth->is_switch_mode)
-					icssg_set_port_state(emac, ICSSG_EMAC_PORT_VLAN_AWARE_ENABLE);
-			}
-		}
+		icssg_update_hsr_rx_offload(emac);
+
+		if (netif_running(emac->ndev))
+			icssg_enable_fw_offload_emac(emac);
 	}
 }
 
@@ -1073,8 +1088,9 @@ static int emac_ndo_open(struct net_device *ndev)
 		ret = prueth_emac_common_start(prueth);
 		if (ret)
 			goto free_rx_irq;
-		icssg_enable_fw_offload(prueth);
 	}
+	icssg_update_hsr_rx_offload(emac);
+	icssg_enable_fw_offload_emac(emac);
 
 	flow_cfg = emac->dram.va + ICSSG_CONFIG_OFFSET + PSI_L_REGULAR_FLOW_ID_BASE_OFFSET;
 	writew(emac->rx_flow_id_base, &flow_cfg->rx_base_flow);
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH net 2/2] net: ti: icssg-prueth: re-apply rx_mode state after firmware reboot
  2026-10-14 12:59 [PATCH net 0/2] net: ti: icssg-prueth: fix port config and rx_mode drops Rishi Kumar
  2026-10-14 12:59 ` [PATCH net 1/2] net: ti: icssg-prueth: fix missing port config on second interface open Rishi Kumar
@ 2026-10-14 12:59 ` Rishi Kumar
  2026-10-18 13:22   ` netdev-bot+sashiko
  2026-10-14 13:05 ` [PATCH net 0/2] net: ti: icssg-prueth: fix port config and rx_mode drops netdev-bot+sinfo
  2 siblings, 1 reply; 7+ messages in thread
From: Rishi Kumar @ 2026-10-14 12:59 UTC (permalink / raw)
  To: netdev
  Cc: MD Danish Anwar, Roger Quadros, Andrew Lunn, David S . Miller,
	Eric Dumazet, Jakub Kicinski, Paolo Abeni, Jacob Keller,
	Meghana Malladi, Vadim Fedorenko, Kevin Hao, linux-arm-kernel,
	linux-kernel, j-rameshbabu, aaron.richard, l-chinnannavar,
	m-santhoshkadavan, k-tiwari1, a-dev, r-kumar12, pratheesh

prueth_emac_common_start() reboots the PRU/RTU/txPRU cores whenever
the first port opens, or on a full mode change via
icssg_change_mode(). Any icssg_set_port_state() command sent while a
core is stopped or still booting times out waiting for firmware to
ack it ("timeout waiting for command done"), and the write is lost
with no retry.

emac_ndo_set_rx_mode_work() sends exactly this kind of command to
enable/disable UC/MC flooding based on IFF_PROMISC/IFF_ALLMULTI. If
a port's rx_mode_work runs while firmware is being rebooted, the
flood-enable command can be dropped, leaving that port without
multicast flooding.

Re-queue rx_mode_work for every running port at the end of the
firmware start sequence in prueth_emac_common_start(), so the current
IFF_PROMISC/IFF_ALLMULTI state is re-applied after a reboot. Also
cancel the pending work in the stop_pruss error path so it cannot run
after the cores are stopped again.

prefix logs: https://gist.github.com/r-kumar12/91ee6fecd40ea3f22dcc65aba42705e1
postfix logs: https://gist.github.com/r-kumar12/4d5ade22d783020552b8a1e0c6d7102f

Fixes: 9facce84f406 ("net: ti: icssg-prueth: Fix firmware load sequence.")
Signed-off-by: Rishi Kumar <r-kumar12@ti.com>
---
 drivers/net/ethernet/ti/icssg/icssg_prueth.c | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)

diff --git a/drivers/net/ethernet/ti/icssg/icssg_prueth.c b/drivers/net/ethernet/ti/icssg/icssg_prueth.c
index 745178fe7cf3..96ad6227f405 100644
--- a/drivers/net/ethernet/ti/icssg/icssg_prueth.c
+++ b/drivers/net/ethernet/ti/icssg/icssg_prueth.c
@@ -311,6 +311,18 @@ static int prueth_emac_common_start(struct prueth *prueth)
 	if (ret)
 		goto disable_class;
 
+	/* PRU/RTU/txPRU are up now: re-sync any port
+	 * config (e.g. flood/promisc flags) that may have been
+	 * dropped while firmware was still rebooting above.
+	 */
+	for (slice = 0; slice < PRUETH_NUM_MACS; slice++) {
+		emac = prueth->emac[slice];
+		if (!emac)
+			continue;
+		if (netif_running(emac->ndev))
+			schedule_work(&emac->rx_mode_work);
+	}
+
 	emac = prueth->emac[ICSS_SLICE0] ? prueth->emac[ICSS_SLICE0] :
 	       prueth->emac[ICSS_SLICE1];
 	ret = icss_iep_init(emac->iep, &prueth_iep_clockops,
@@ -323,6 +335,11 @@ static int prueth_emac_common_start(struct prueth *prueth)
 	return 0;
 
 stop_pruss:
+	for (slice = 0; slice < PRUETH_NUM_MACS; slice++) {
+		emac = prueth->emac[slice];
+		if (emac)
+			cancel_work_sync(&emac->rx_mode_work);
+	}
 	prueth_emac_stop(prueth);
 
 disable_class:
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [PATCH net 0/2] net: ti: icssg-prueth: fix port config and rx_mode drops
  2026-10-14 12:59 [PATCH net 0/2] net: ti: icssg-prueth: fix port config and rx_mode drops Rishi Kumar
  2026-10-14 12:59 ` [PATCH net 1/2] net: ti: icssg-prueth: fix missing port config on second interface open Rishi Kumar
  2026-10-14 12:59 ` [PATCH net 2/2] net: ti: icssg-prueth: re-apply rx_mode state after firmware reboot Rishi Kumar
@ 2026-10-14 13:05 ` netdev-bot+sinfo
  2026-10-14 13:38   ` KUMAR, RISHI
  2 siblings, 1 reply; 7+ messages in thread
From: netdev-bot+sinfo @ 2026-10-14 13:05 UTC (permalink / raw)
  To: Rishi Kumar
  Cc: netdev, MD Danish Anwar, Roger Quadros, Andrew Lunn,
	David S . Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Jacob Keller, Meghana Malladi, Vadim Fedorenko, Kevin Hao,
	linux-arm-kernel, linux-kernel, j-rameshbabu, aaron.richard,
	l-chinnannavar, m-santhoshkadavan, k-tiwari1, a-dev, pratheesh

Hi!

This is an automated message. This series looks like a fix, but its
commit messages seem to be missing some information:

 - What hardware the change was tested on. For driver fixes please
   mention the device (and if relevant firmware version) used for
   testing, or say that the change was not tested on real hardware.

Please do not repost the series just to address the above. Instead,
reply to this email with the missing information, so that reviewers
can take it into account. If the series needs another revision for
other reasons, please include the information in the commit messages
then.

The evaluation is done by an LLM so it may be wrong, if you think
that is the case please reply and explain.

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH net 0/2] net: ti: icssg-prueth: fix port config and rx_mode drops
  2026-10-14 13:05 ` [PATCH net 0/2] net: ti: icssg-prueth: fix port config and rx_mode drops netdev-bot+sinfo
@ 2026-10-14 13:38   ` KUMAR, RISHI
  0 siblings, 0 replies; 7+ messages in thread
From: KUMAR, RISHI @ 2026-10-14 13:38 UTC (permalink / raw)
  To: netdev-bot+sinfo
  Cc: netdev, MD Danish Anwar, Roger Quadros, Andrew Lunn,
	David S . Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Jacob Keller, Meghana Malladi, Vadim Fedorenko, Kevin Hao,
	linux-arm-kernel, linux-kernel, j-rameshbabu, aaron.richard,
	l-chinnannavar, m-santhoshkadavan, k-tiwari1, a-dev, pratheesh

Hi All,

On 10/14/2026 6:35 PM, netdev-bot+sinfo@kernel.org wrote:
>   - What hardware the change was tested on. For driver fixes please
>     mention the device (and if relevant firmware version) used for
>     testing, or say that the change was not tested on real hardware.
> 

Both patches were tested on real hardware.

Board:    AM64x EVM (AM6442)

ICSSG:    REL.PRU-ICSS-ETHERNET-SWITCH_02.02.16.01 firmware

Software: TI SDK 12.01.00.05.03 rt-am64xx-evm root filesystem, with
             a kernel built from net/main plus these two patches

Setup:    eth1 and eth2 bridged in br0 (switch offload)

Patch 1 (fix missing port config on second interface open):
Brought up br0 with eth1/eth2, then cycled the links (eth1 down,
eth2 down, eth1 up, eth2 up, and the reverse order). Sent 30
multicast frames to each port.

Before: after the cycle, fid_c1 of the default VLAN was 0x3 (or 0x5
for the reversed order), so only P0 and one slave port were members.
Multicast forwarded in one direction only.
After: each port is configured when it opens (fid_c1 = 0x7, P0 + P1
+ P2), and forwarding works in both directions after the cycle.

Patch 2 (re-apply rx_mode state after firmware reboot):
Brought up the offloaded switch interfaces and sent 30 multicast
frames to each port in turn.

Before: NRT_HOST_RX_PKT_COUNT did not increment for one port.
After: it increments for both ports, and forwarding works in both
directions.

HSR regression: brought up hsr0, sent 30 HSR-tagged frames in both
directions, cycled eth1/eth2 down and up, and sent again. Forwarding
works in both directions and NRT_HOST_RX_PKT_COUNT increments both
times.

Logs are in the gist links in the commit messages.

Thanks,
Rishi Kumar
ICSS India


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH net 1/2] net: ti: icssg-prueth: fix missing port config on second interface open
  2026-10-14 12:59 ` [PATCH net 1/2] net: ti: icssg-prueth: fix missing port config on second interface open Rishi Kumar
@ 2026-10-18 13:22   ` netdev-bot+sashiko
  0 siblings, 0 replies; 7+ messages in thread
From: netdev-bot+sashiko @ 2026-10-18 13:22 UTC (permalink / raw)
  To: r-kumar12
  Cc: netdev, danishanwar, rogerq, andrew+netdev, davem, edumazet, kuba,
	pabeni, jacob.e.keller, m-malladi, vadim.fedorenko, haokexin,
	linux-arm-kernel, linux-kernel, j-rameshbabu, aaron.richard,
	l-chinnannavar, m-santhoshkadavan, k-tiwari1, a-dev, pratheesh

Thank you for your contribution! Sashiko AI review found 1 potential
issue(s) to consider.

Critical: 0 · High: 0 · Medium: 1 · Low: 0 (1)

If you believe none of the issues are legitimate, please reply to each
issue of Medium severity or higher and explain why the AI is wrong.
If any of them are legitimate and you plan to respin, please let patchwork
know by including "pw-bot: cr" as a separate line at the end of your reply
(one such reply per series is enough).

- [Medium] Reopening one port while its sibling stays up now resets that
  port's live VLAN configuration to the driver defaults.

Pre-existing issues:
- [Low] The two join paths set emac->port_vlan differently.

--

net: ti: icssg-prueth: fix missing port config on second interface open

This commit moves the per-port FDB, VLAN table, PVID and VLAN-aware setup
out of icssg_enable_fw_offload() into a new icssg_enable_fw_offload_emac().
It also moves the HSR Rx offload setup into icssg_update_hsr_rx_offload().
emac_ndo_open() now calls both helpers unconditionally for the opening
port, and icssg_enable_fw_offload() is kept for icssg_change_mode().

> diff --git a/drivers/net/ethernet/ti/icssg/icssg_prueth.c b/drivers/net/ethernet/ti/icssg/icssg_prueth.c
> index 591be5c8056b4..cd4c918fe2b89 100644
> --- a/drivers/net/ethernet/ti/icssg/icssg_prueth.c
> +++ b/drivers/net/ethernet/ti/icssg/icssg_prueth.c
> @@ -206,6 +206,44 @@ static void prueth_emac_stop(struct prueth *prueth)

[ ... ]

> +static void icssg_enable_fw_offload_emac(struct prueth_emac *emac)
> +{
> +	struct prueth *prueth = emac->prueth;
> +
> +	if (prueth->is_switch_mode || prueth->is_hsr_offload_mode) {
> +		icssg_fdb_add_del(emac, eth_stp_addr, prueth->default_vlan,
> +				  ICSSG_FDB_ENTRY_P0_MEMBERSHIP |
> +				  ICSSG_FDB_ENTRY_P1_MEMBERSHIP |
> +				  ICSSG_FDB_ENTRY_P2_MEMBERSHIP |
> +				  ICSSG_FDB_ENTRY_BLOCK,
> +				  true);
> +		icssg_vtbl_modify(emac, emac->port_vlan | DEFAULT_VID,
> +				  BIT(emac->port_id) | DEFAULT_PORT_MASK,
> +				  BIT(emac->port_id) | DEFAULT_UNTAG_MASK,
> +				  true);
> +		if (prueth->is_hsr_offload_mode)
> +			icssg_vtbl_modify(emac, DEFAULT_VID,
> +					  DEFAULT_PORT_MASK,
> +					  DEFAULT_UNTAG_MASK, true);
> +		icssg_set_pvid(prueth, emac->port_vlan, emac->port_id);

[Severity: Low]
This isn't a bug introduced by this patch, but is emac->port_vlan set
for both ports in switch mode?

In prueth_netdevice_port_link(), only the port whose join completes
br_members gets port_vlan set:

	if (!prueth->is_switch_mode) {
		if (prueth->br_members & BIT(PRUETH_PORT_MII0) &&
		    prueth->br_members & BIT(PRUETH_PORT_MII1)) {
			prueth->is_switch_mode = true;
			prueth->default_vlan = PRUETH_DFLT_VLAN_SW;
			emac->port_vlan = prueth->default_vlan;
			icssg_change_mode(prueth);
		}
	}

prueth_hsr_port_link() sets it on both emac0 and emac1.

This means the port that joined the bridge first keeps port_vlan == 0.
icssg_set_pvid() here then programs PVID 0 for that port and PVID 1 for
the other one. Both ports still get VID 1 table membership, because
0 | DEFAULT_VID == 1.

The unlink paths have the same asymmetry. The switch unlink path resets
port_vlan on one emac, while the HSR unlink path resets both.

icssg_change_mode()->icssg_enable_fw_offload() already behaved this way
before this patch. This patch adds another call site that applies the
value.

A concrete forwarding failure from this hasn't been shown. With 8021q
loaded, NETDEV_UP already sets PVID 0 via ndo_vlan_rx_add_vid(0). How the
firmware handles PVID 0 is not known.

Should prueth_netdevice_port_link() set port_vlan on both ports, the
same way the HSR path does?

> +		if (prueth->is_switch_mode)
> +			icssg_set_port_state(emac, ICSSG_EMAC_PORT_VLAN_AWARE_ENABLE);
> +	}
> +}

[ ... ]

> @@ -1067,8 +1082,9 @@ static int emac_ndo_open(struct net_device *ndev)
>  		ret = prueth_emac_common_start(prueth);
>  		if (ret)
>  			goto free_rx_irq;
> -		icssg_enable_fw_offload(prueth);
>  	}
> +	icssg_update_hsr_rx_offload(emac);
> +	icssg_enable_fw_offload_emac(emac);

[Severity: Medium]
Can this reset a port's live VLAN configuration when the port is
reopened while its sibling stays up?

When the sibling is up, emac_ndo_stop() does not stop the firmware and
does not remove any FDB, VLAN or PVID state:

	/* stop PRUs */
	if (prueth->emacs_initialized == 1)
		prueth_emac_common_stop(prueth);

The next open also skips prueth_emac_common_start(). So the shared-RAM
VLAN table and the per-port PVID word still hold whatever the bridge or
8021q programmed. icssg_enable_fw_offload_emac() then runs:

	icssg_vtbl_modify(emac, emac->port_vlan | DEFAULT_VID,
			  BIT(emac->port_id) | DEFAULT_PORT_MASK,
			  BIT(emac->port_id) | DEFAULT_UNTAG_MASK,
			  true);
	...
	icssg_set_pvid(prueth, emac->port_vlan, emac->port_id);

This adds the port back to VID 1 with untagged egress, and overwrites the
PVID with emac->port_vlan.

emac->port_vlan is only ever 0 or the mode default. The runtime VLAN
paths write the hardware directly and never update it:

prueth_switchdev_vlan_add()
	icssg_vtbl_modify(emac, vid, port_mask, untag_mask, true);
	icssg_set_pvid(emac->prueth, vid, emac->port_id);

prueth_switchdev_vlan_del()
	icssg_vtbl_modify(emac, vid, port_mask, 0, false);

emac_ndo_vlan_rx_add_vid()
	icssg_set_pvid(emac->prueth, vid, emac->port_id);

For example, on an offloaded bridge, the admin runs "bridge vlan del dev
eth1 vid 1" or makes VID 1 tagged on eth1. Then "ip link set eth1 down;
ip link set eth1 up" runs while eth2 is still up. In hardware, eth1 ends
up as an untagged member of VID 1 again. The software bridge still shows
the old configuration, and nothing replays the switchdev VLAN objects on
NETDEV_UP.

Without 8021q, a bridge-configured PVID such as "bridge vlan add dev eth1
vid 10 pvid untagged" is also replaced, with 1 or with 0 for the port
that joined the bridge first. With 8021q loaded, its NETDEV_UP handler
already sets PVID 0 through ndo_vlan_rx_add_vid(0) on every up, both
before and after this patch.

Before this patch, none of this ran on a single-port reopen, so VLAN
membership and tagging survived it. The later commit in the series, "net:
ti: icssg-prueth: re-apply rx_mode state after firmware reboot", only
adds rx_mode_work scheduling in prueth_emac_common_start(). It does not
change icssg_enable_fw_offload_emac() or the open path.

The commit message also says:

    If one port is later brought down and up while the sibling stays up,
    emacs_initialized is still non-zero, so the function never runs again
    and the port is left unconfigured, depending on bring-up order.

Is that accurate? emac_ndo_stop() never removes the port's FDB, VLAN or
PVID state, so a port configured at first open stays configured. Only
the port opened second seems to have been missing its configuration.

Should the open path avoid overwriting state that the firmware still
holds while the sibling port is running?

>  
>  	flow_cfg = emac->dram.va + ICSSG_CONFIG_OFFSET + PSI_L_REGULAR_FLOW_ID_BASE_OFFSET;
>  	writew(emac->rx_flow_id_base, &flow_cfg->rx_base_flow);

-- 
Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20261014125948.230571-1-r-kumar12%40ti.com

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH net 2/2] net: ti: icssg-prueth: re-apply rx_mode state after firmware reboot
  2026-10-14 12:59 ` [PATCH net 2/2] net: ti: icssg-prueth: re-apply rx_mode state after firmware reboot Rishi Kumar
@ 2026-10-18 13:22   ` netdev-bot+sashiko
  0 siblings, 0 replies; 7+ messages in thread
From: netdev-bot+sashiko @ 2026-10-18 13:22 UTC (permalink / raw)
  To: r-kumar12
  Cc: netdev, danishanwar, rogerq, andrew+netdev, davem, edumazet, kuba,
	pabeni, jacob.e.keller, m-malladi, vadim.fedorenko, haokexin,
	linux-arm-kernel, linux-kernel, j-rameshbabu, aaron.richard,
	l-chinnannavar, m-santhoshkadavan, k-tiwari1, a-dev, pratheesh

Thank you for your contribution! Sashiko AI review found 3 potential
issue(s) to consider.

Critical: 0 · High: 1 · Medium: 2 · Low: 0

If you believe none of the issues are legitimate, please reply to each
issue of Medium severity or higher and explain why the AI is wrong.
If any of them are legitimate and you plan to respin, please let patchwork
know by including "pw-bot: cr" as a separate line at the end of your reply
(one such reply per series is enough).

- [High] net: silent hardware state loss due to rtnl_trylock failure in
  rx_mode_work
- [Medium] prueth_emac_common_start() now queues rx_mode_work for every
  running port before returning success.
- [Medium] The new schedule_work() loop in prueth_emac_common_start()
  lets the opening port's rx_mode_work run while emac_ndo_open() is…

--

net: ti: icssg-prueth: re-apply rx_mode state after firmware reboot

At the end of prueth_emac_common_start(), this commit re-queues
rx_mode_work for every running port. The aim is to re-apply the
IFF_PROMISC/IFF_ALLMULTI flood state after the PRU/RTU/txPRU firmware
reboots. It also cancels the pending work in the stop_pruss error path.

> diff --git a/drivers/net/ethernet/ti/icssg/icssg_prueth.c b/drivers/net/ethernet/ti/icssg/icssg_prueth.c
> index cd4c918fe2b89..9d38cbbdaf27f 100644
> --- a/drivers/net/ethernet/ti/icssg/icssg_prueth.c
> +++ b/drivers/net/ethernet/ti/icssg/icssg_prueth.c
> @@ -311,6 +311,18 @@ static int prueth_emac_common_start(struct prueth *prueth)
>  	if (ret)
>  		goto disable_class;
>  
> +	/* PRU/RTU/txPRU are up now: re-sync any port
> +	 * config (e.g. flood/promisc flags) that may have been
> +	 * dropped while firmware was still rebooting above.
> +	 */
> +	for (slice = 0; slice < PRUETH_NUM_MACS; slice++) {
> +		emac = prueth->emac[slice];
> +		if (!emac)
> +			continue;
> +		if (netif_running(emac->ndev))
> +			schedule_work(&emac->rx_mode_work);
> +	}

[Severity: High]
Does the VLAN multicast part of the re-sync actually happen when the
work is queued from here?

prueth_emac_common_start() is called with rtnl_lock held in both
paths. It is called from emac_ndo_open() via __dev_open(), and from
icssg_change_mode() via the NETDEV_CHANGEUPPER notifier. The caller
still holds rtnl while it runs icss_iep_init() and the rest of
ndo_open or the mode change.

The work queued here will usually run inside that window. The worker
first sends its icssg_set_port_state() commands, which wait for a
firmware ack. In the non-promisc, non-allmulti case,
emac_ndo_set_rx_mode_work() then ends with:

	if (rtnl_trylock()) {
		vlan_for_each(ndev, icssg_update_vlan_mcast, emac);
		rtnl_unlock();
	}

HSR offload mode does the same with prueth->hsr_dev. If the trylock
fails, the vlan_for_each() call is skipped silently. The work does
not requeue itself, and nothing records that the update was skipped.

The firmware restart has just cleared SHRAM, MSMC and the VLAN table.
The per-VLAN multicast entries tracked in emac->vlan_mcast_list are
exactly the state that needs to be reprogrammed.

In the icssg_change_mode() path, this loop is the only thing that
queues rx_mode_work for a port that is already running. For the
opening port, the ndo_set_rx_mode call that __dev_open() makes later
also runs under rtnl. If the trylock loses in these cases, are the
VLAN multicast groups left unprogrammed in the firmware FDB, so that
multicast reception on those VLANs breaks?

The rtnl_trylock() skip existed before this patch. However, the patch
now uses this work as the re-sync mechanism and queues it from
contexts that are known to hold rtnl. That turns the skip from a rare
race into the likely outcome.

Should the worker reschedule itself when rtnl_trylock() fails? Or
could the VLAN multicast re-sync be done directly from the start
path, which already holds rtnl?

[Severity: Medium]
Can the opening port's rx_mode_work now run while emac_ndo_open() is
still sending its own HWQ commands on the same slice?

Before this patch, the work could not run for a port still inside
ndo_open, because __dev_set_rx_mode() requires IFF_UP.

With this loop, take a first open in non-promisc, non-allmulti mode
with pending multicast entries. For example, IPv6 adds 33:33:00:00:00:01
at NETDEV_REGISTER. The work then does:

emac_ndo_set_rx_mode_work()
  __dev_mc_sync()
    icssg_prueth_add_mcast()
      icssg_fdb_lookup()
      icssg_fdb_add_del()

Meanwhile emac_ndo_open() continues with:

	icssg_enable_fw_offload_emac(emac);
	...
	ret = emac_fdb_flow_id_updated(emac);

In switch/HSR mode the first of these sends FDB add commands. The second
always runs. Both paths end up in icssg_send_fdb_msg(), which takes no
lock:

- It pops a command buffer, pushes the command, then polls the response
  queue and takes whichever response comes out first.
- icssg_fdb_lookup() reads its result from the single per-slice
  FDB_CMD_BUFFER in DRAM.
- prueth->icssg_hwcmdseq is incremented non-atomically.

Only icssg_set_port_state() is serialized, by cmd_lock.

With two commands in flight, could the responses get swapped? That
could lead to:

- the seqnum mismatch WARN_ON in emac_fdb_flow_id_updated();
- ndo_open failing because it got another command's status;
- a wrong port_mask written into the FDB/VLAN table from another
  command's lookup data.

The flood commands could also reach the firmware before the RX flow ID
base is configured.

The restart path seems to have a similar window. After
prueth_emac_restart(), icssg_change_mode() calls
icssg_enable_fw_offload(), and the work queued here for both ports may
be running at that point.

> +
>  	emac = prueth->emac[ICSS_SLICE0] ? prueth->emac[ICSS_SLICE0] :
>  	       prueth->emac[ICSS_SLICE1];
>  	ret = icss_iep_init(emac->iep, &prueth_iep_clockops,
> @@ -323,6 +335,11 @@ static int prueth_emac_common_start(struct prueth *prueth)
>  	return 0;
>  
>  stop_pruss:
> +	for (slice = 0; slice < PRUETH_NUM_MACS; slice++) {
> +		emac = prueth->emac[slice];
> +		if (emac)
> +			cancel_work_sync(&emac->rx_mode_work);
> +	}
>  	prueth_emac_stop(prueth);

[Severity: Medium]
The commit message says the cancel is there "so it cannot run after
the cores are stopped again". However, this label is reached only when
icss_iep_init() fails.

Is the newly queued work also cancelled when emac_ndo_open() fails
after prueth_emac_common_start() has already succeeded?

__dev_open() sets __LINK_STATE_START before calling ndo_open. So
netif_running() is already true for the port being opened, and its
rx_mode_work is queued by the loop above.

A later step in emac_ndo_open() can still fail. Examples are
request_threaded_irq() for tx_ts_irq, prueth_create_rxq(),
prueth_create_txq(), or:

	ret = emac_fdb_flow_id_updated(emac);

The error path then ends at:

stop:
	if (!prueth->emacs_initialized)
		prueth_emac_common_stop(prueth);

This shuts down the PRU/RTU/txPRU cores without cancelling
rx_mode_work.

emac_ndo_stop() does call cancel_work_sync(&emac->rx_mode_work) before
prueth_emac_common_stop(). But ndo_stop is not called after a failed
open.

A work item that is still pending or running would then send commands
to halted cores:

- icssg_set_port_state() commands, each timing out with "timeout
  waiting for command done";
- in the non-promisc case, icssg_send_fdb_msg() commands that can poll
  for up to 20 seconds.

The multicast list may also be affected after the failure.
icssg_prueth_add_mcast() always returns 0, so __dev_mc_sync() marks the
addresses as synced.

After a failed open, nothing calls __dev_mc_unsync(). That includes
the stop_pruss path, where cancel_work_sync() cannot undo a sync that
has already completed.

The next successful open clears SHRAM, MSMC and the VLAN table and
reboots the firmware. Its __dev_mc_sync() would then skip the addresses
that are still marked synced.

Could this leave those multicast groups unprogrammed in the firmware
FDB?

Before this patch, the opening port's rx_mode_work could not run during
its own ndo_open, so this problem appears to be new.

>  
>  disable_class:

-- 
Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20261014125948.230571-1-r-kumar12%40ti.com

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2026-10-18 13:22 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-14 12:59 [PATCH net 0/2] net: ti: icssg-prueth: fix port config and rx_mode drops Rishi Kumar
2026-10-14 12:59 ` [PATCH net 1/2] net: ti: icssg-prueth: fix missing port config on second interface open Rishi Kumar
2026-10-18 13:22   ` netdev-bot+sashiko
2026-10-14 12:59 ` [PATCH net 2/2] net: ti: icssg-prueth: re-apply rx_mode state after firmware reboot Rishi Kumar
2026-10-18 13:22   ` netdev-bot+sashiko
2026-10-14 13:05 ` [PATCH net 0/2] net: ti: icssg-prueth: fix port config and rx_mode drops netdev-bot+sinfo
2026-10-14 13:38   ` KUMAR, RISHI

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox