Devicetree
 help / color / mirror / Atom feed
From: Jens Emil Schulz Ostergaard <jensemil.schulzostergaard@microchip.com>
To: <UNGLinuxDriver@microchip.com>, Andrew Lunn <andrew@lunn.ch>,
	"Vladimir Oltean" <olteanv@gmail.com>,
	"David S. Miller" <davem@davemloft.net>,
	"Eric Dumazet" <edumazet@google.com>,
	Jakub Kicinski <kuba@kernel.org>,
	"Paolo Abeni" <pabeni@redhat.com>,
	Simon Horman <horms@kernel.org>, Rob Herring <robh@kernel.org>,
	Krzysztof Kozlowski <krzk+dt@kernel.org>,
	Conor Dooley <conor+dt@kernel.org>,
	Woojung Huh <woojung.huh@microchip.com>,
	"Russell King" <linux@armlinux.org.uk>,
	Steen Hegelund <Steen.Hegelund@microchip.com>,
	Daniel Machon <daniel.machon@microchip.com>
Cc: <linux-kernel@vger.kernel.org>, <netdev@vger.kernel.org>,
	<devicetree@vger.kernel.org>
Subject: Re: [PATCH net-next v11 5/9] net: dsa: lan9645x: add bridge support
Date: Mon, 17 Aug 2026 16:31:42 +0200	[thread overview]
Message-ID: <81bc1f7014f70b567a3a6e4a67728fb9796c4f02.camel@microchip.com> (raw)
In-Reply-To: <20260805-dsa_lan9645x_switch_driver_base-v11-5-007ebc983a0a@microchip.com>

This is my reply to:
https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20260805-dsa_lan9645x_switch_driver_base-v11-0-007ebc983a0a%40microchip.com?part=5

> --- Patch [5]: [PATCH net-next v11 5/9] net: dsa: lan9645x: add bridge support ---
> commit a6410541102bca5214b00713a7a5b063ffd47ab2
> Author: Jens Emil Schulz Østergaard <jensemil.schulzostergaard@microchip.com>
>
> net: dsa: lan9645x: add bridge support
>
> This adds bridge offload to the lan9645x DSA driver: bridge join/leave,
> STP state and learning, port flooding flags, host flood handling through
> an ordered workqueue, and an ageing time setter. A single bridge device
> is supported.
>
> A few questions about the bridge integration below.
>
> > diff --git a/drivers/net/dsa/microchip/lan9645x/lan9645x_main.c
b/drivers/net/dsa/microchip/lan9645x/lan9645x_main.c
> > index b253813518c20..c145d28ffbb99 100644
> > --- a/drivers/net/dsa/microchip/lan9645x/lan9645x_main.c
> > +++ b/drivers/net/dsa/microchip/lan9645x/lan9645x_main.c
>
> [ ... ]
>
> > @@ -265,15 +269,34 @@ static int lan9645x_setup(struct dsa_switch *ds)
> >  
> >  	lan9645x_port_set_tail_drop_wm(lan9645x);
> >  
> > +	lan9645x->owq = alloc_ordered_workqueue("%s-owq", 0,
> > +						dev_name(lan9645x->dev));
> > +	if (!lan9645x->owq) {
> > +		err = -ENOMEM;
> > +		goto err_mutex;
> > +	}
> > +
> >  	ds->mtu_enforcement_ingress = true;
> >  	ds->assisted_learning_on_cpu_port = true;
> >  	ds->fdb_isolation = true;
>
> Discovered by: opus-5 · Missed by: fable-5, sashiko-gemini · Confirmed by: fable-5
> Should ds->max_num_bridges be set to 1 here as well, next to
> ds->fdb_isolation?
>
> In net/dsa/dsa.c, dsa_bridge_num_get() treats a zero maximum as "no FDB
> isolation" and hands back a constant bridge number:
>
> 	/* Switches without FDB isolation support don't get unique
> 	 * bridge numbering
> 	 */
> 	if (!max)
> 		return 0;
>
> and net/dsa/port.c dsa_port_bridge_create() skips the range check for the
> same reason:
>
> 	bridge->num = dsa_bridge_num_get(br, ds->max_num_bridges);
> 	if (ds->max_num_bridges && !bridge->num) {
> 		NL_SET_ERR_MSG_MOD(extack,
> 				   "Range of offloadable bridges exceeded");
>
> So the driver requests FDB isolation while the isolation key the core
> returns is always 0, and the single-bridge limit is then open coded in
> lan9645x_port_bridge_join() with -EBUSY and "Only one bridge supported".
> The other in-tree drivers that set fdb_isolation (felix, sja1105,
> vitesse-vsc73xx-core, rtl8365mb, netc) also set max_num_bridges.
>
> The driver does not consume db.bridge.num anywhere in the final series, so
> nothing is mis-keyed today; it is the mismatch between the two fields that
> looks unintended.
>

Yes, i think this is right. I will set max_num_bridges=1 and remove the open
coded single-bridge limit.

> > +	/* ANA_AUTOAGE_AGE_PERIOD is a seconds-based field and entries are
> > +	 * aged after 2 * AGE_PERIOD, giving (2 * FIELD_MAX) seconds of
> > +	 * maximum aging.
> > +	 */
> > +	ds->ageing_time_max = 2U * MSEC_PER_SEC *
> > +			      FIELD_MAX(ANA_AUTOAGE_AGE_PERIOD);
> > +
>
> Discovered by: opus-5 · Missed by: fable-5, sashiko-gemini · Confirmed by: fable-5
> Only the upper ageing bound is published to the core here, leaving
> ds->ageing_time_min at 0.  Should ds->ageing_time_min = 2 * MSEC_PER_SEC be
> set too?
>
> net/dsa/switch.c dsa_switch_ageing_time() only rejects out-of-range
> requests when the corresponding limit is nonzero:
>
> 	if (ds->ageing_time_min && ageing_time < ds->ageing_time_min)
> 		return -ERANGE;
>
> 	if (ds->ageing_time_max && ageing_time > ds->ageing_time_max)
> 		return -ERANGE;
>
> net/bridge/br_stp.c br_set_ageing_time() imposes no lower bound either, so
> a request below 2000 ms reaches lan9645x_set_ageing_time() and is clamped
> while success is reported:
>
> 	ip link set br0 type bridge ageing_time 100
> 	  -> lan9645x_set_ageing_time(ds, 1000)
> 	     age_secs = max(1, 1000 / 1000 / 2) = max(1, 0) = 1
> 	     ANA_AUTOAGE_AGE_PERIOD = 1, i.e. entries age after 2 s
>
> For any msecs in 1..3999 the division yields 0 or 1 and the clamp forces 1,
> so every sub-2 s request silently becomes an effective 2 s hardware
> ageing while the bridge keeps and reports the value userspace asked for.
> drivers/net/dsa/netc/netc_main.c sets ds->ageing_time_min alongside
> ds->ageing_time_max.

We intentionally do not set ds->ageing_time_min because we would like to support
disabling ageing with an explicit zero value.

We generally round down to a 2s multiple, but I decided to round up in the
(0,2s] interval. If a user requests a very fast ageing time, I think it is
better to configure it to 2s, than to disable ageing.

>
> >  	dev_info(lan9645x->dev,
> >  		 "SKU features: max_ports=%d\n",
> >  		 lan9645x->num_phys_ports - lan9645x->num_port_dis);
> >  
> >  	return 0;
> > +
> > +err_mutex:
> > +	mutex_destroy(&lan9645x->fwd_domain_lock);
> > +	lan9645x_npi_port_deinit(lan9645x, lan9645x->npi);
> > +	return err;
> >  }
>
> [ ... ]
>
> > @@ -282,6 +305,282 @@ static void lan9645x_port_phylink_get_caps(struct dsa_switch *ds, int port,
> >  	lan9645x_phylink_get_caps(ds->priv, port, config);
> >  }
> >  
> > +static int lan9645x_set_ageing_time(struct dsa_switch *ds, unsigned int msecs)
> > +{
> > +	u32 age_secs = max(1, msecs / MSEC_PER_SEC / 2);
> > +	struct lan9645x *lan9645x = ds->priv;
> > +
> > +	/* Entry must suffer two aging scans before it is removed, so it is
> > +	 * aged after 2*AGE_PERIOD, and the unit is in seconds.
> > +	 * An age period of 0 disables automatic aging.
> > +	 */
> > +	lan_rmw(ANA_AUTOAGE_AGE_PERIOD_SET(msecs ? age_secs : 0),
> > +		ANA_AUTOAGE_AGE_PERIOD,
> > +		lan9645x, ANA_AUTOAGE);
> > +	return 0;
> > +}
>
> [ ... ]
>
> > +static void __lan9645x_port_set_host_flood(struct lan9645x *lan9645x)
> > +{
> > +	bool mc_ena, uc_ena;
> > +	u16 unbridged;
> > +
> > +	lockdep_assert_held(&lan9645x->fwd_domain_lock);
> > +
> > +	/* We want promiscuous and all_multi to affect standalone ports, for
> > +	 * debug and test purposes.
> > +	 *
> > +	 * However, the linux bridge is incredibly eager to put bridged ports in
> > +	 * promiscuous mode.
> > +	 *
> > +	 * This is unfortunate since lan9645x flood masks are global and not per
> > +	 * ingress port. When some port triggers unknown uc/mc to the CPU, the
> > +	 * traffic from any port is forwarded to the CPU.
> > +	 *
> > +	 * If the host CPU is weak, this can cause tremendous stress. Therefore,
> > +	 * we compromise by ignoring this host flood request for bridged ports.
> > +	 */
> > +	unbridged = ~lan9645x->bridge_mask & GENMASK(NUM_PHYS_PORTS - 1, 0);
> > +
> > +	uc_ena = !!(lan9645x->host_flood_uc_mask & unbridged);
>
> Discovered by: fable-5, opus-5 · Missed by: sashiko-gemini
> This isn't a bug, but could the commit message mention the two user
> visible behaviours added here?
>
> The log says only "Add support for hardware offloading of the bridge. We
> support a single bridge device.", while this masking means a
> .port_set_host_flood request for a bridged port is accepted and then
> dropped:
>
> net/dsa/user.c dsa_user_change_rx_flags() -> dsa_user_manage_host_flood()
> -> net/dsa/port.c dsa_port_set_host_flood() -> lan9645x_port_set_host_flood()
> -> lan9645x_host_flood_work_fn() -> __lan9645x_port_set_host_flood()
>
> Since br_manage_promisc() puts bridge ports in promiscuous mode when the
> bridge has VLAN filtering disabled, the CPU port bit is never set in
> PGID_UC/PGID_MC/PGID_MCIPV4/PGID_MCIPV6 for a bridged port, and no error
> is returned to userspace.  lan9645x_port_bridge_join() also revokes an
> already granted request through __lan9645x_port_set_host_flood(), and
> lan9645x_port_bridge_leave() restores it.  The sibling driver for the same
> hardware family, felix_port_set_host_flood() in
> drivers/net/dsa/ocelot/felix.c, honours the request unconditionally.
>

I can mention this in the commit message. I would add that even when VLAN
filtering is enabled, the conditions for when a bridged port is not put in
promiscuous mode are narrow. In most regular situations a bridged port is
put into promiscuous mode, even with VLAN filtering.

> The second omission is .set_ageing_time, ds->ageing_time_max and the
> "msecs == 0 disables automatic ageing" semantic, which are described only
> in the comment above and in the changelog below the --- marker.
>
> [ ... ]
>
> > +static void lan9645x_port_bridge_stp_state_set(struct dsa_switch *ds, int port,
> > +					       u8 state)
> > +{
>
> [ ... ]
>
> > +	lan_rmw(ANA_PORT_CFG_LEARN_ENA_SET(learn_ena),
> > +		ANA_PORT_CFG_LEARN_ENA, lan9645x,
> > +		ANA_PORT_CFG(p->chip_port));
> > +
> > +	lan9645x_update_fwd_mask(lan9645x);
> > +	mutex_unlock(&lan9645x->fwd_domain_lock);
> > +}
>
> [ ... ]
>
> >  static const struct dsa_switch_ops lan9645x_switch_ops = {
> >  	.get_tag_protocol		= lan9645x_get_tag_protocol,
> >  
> > @@ -295,6 +594,15 @@ static const struct dsa_switch_ops lan9645x_switch_ops = {
> >  	/* MTU  */
> >  	.port_change_mtu		= lan9645x_change_mtu,
> >  	.port_max_mtu			= lan9645x_get_max_mtu,
> > +
> > +	/* Bridge integration */
> > +	.set_ageing_time		= lan9645x_set_ageing_time,
> > +	.port_pre_bridge_flags		= lan9645x_port_pre_bridge_flags,
> > +	.port_bridge_flags		= lan9645x_port_bridge_flags,
> > +	.port_bridge_join		= lan9645x_port_bridge_join,
> > +	.port_bridge_leave		= lan9645x_port_bridge_leave,
> > +	.port_stp_state_set		= lan9645x_port_bridge_stp_state_set,
> > +	.port_set_host_flood		= lan9645x_port_set_host_flood,
> >  };
>
> Discovered by: fable-5, opus-5 · Missed by: sashiko-gemini
> STP state and learning offload are registered here without .port_fast_age,
> so when net/dsa/port.c dsa_port_set_state() calls dsa_port_fast_age() there
> is no hardware MAC table flush.  Dynamic entries learned on a port would
> stay in the ANA MAC table after the port leaves BR_STATE_FORWARDING or
> BR_STATE_LEARNING, after BR_LEARNING is cleared, and after bridge leave.
>
> This is resolved later in the same series: the follow-up patch "net: dsa:
> lan9645x: add mac table integration" adds lan9645x_port_fast_age() calling
> lan9645x_mact_flush() and registers ".port_fast_age =
> lan9645x_port_fast_age", with the per-port flush implemented in
> lan9645x_mac.c using ANA_ANAGEFIL_PID_EN/PID_VAL plus two CMD_AGE scans.
> So the gap exists only at this intermediate patch; mentioning it here is
> just for completeness.
>
> Would it be worth reordering so the flush hook lands together with the STP
> offload, or is the intermediate state acceptable?

I will reorganize the commit order so bridge support lands after vlan, mactable
and mdb.


  parent reply	other threads:[~2026-08-17 14:31 UTC|newest]

Thread overview: 33+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-05 14:34 [PATCH net-next v11 0/9] net: dsa: add DSA support for the LAN9645x switch chip family Jens Emil Schulz Østergaard
2026-08-05 14:34 ` [PATCH net-next v11 1/9] net: dsa: add tag driver for LAN9645X Jens Emil Schulz Østergaard
2026-08-06 14:38   ` sashiko-bot
2026-08-07 14:41     ` JensEmil.SchulzOstergaard
2026-08-11 10:55       ` Paolo Abeni
2026-08-11 11:50         ` JensEmil.SchulzOstergaard
2026-08-17 14:18   ` Jens Emil Schulz Ostergaard
2026-08-05 14:34 ` [PATCH net-next v11 2/9] dt-bindings: net: lan9645x: add LAN9645X switch bindings Jens Emil Schulz Østergaard
2026-08-06 14:38   ` sashiko-bot
2026-08-07 14:15     ` JensEmil.SchulzOstergaard
2026-08-17 14:21   ` Jens Emil Schulz Ostergaard
2026-08-05 14:34 ` [PATCH net-next v11 3/9] net: dsa: lan9645x: add autogenerated register macros Jens Emil Schulz Østergaard
2026-08-05 14:34 ` [PATCH net-next v11 4/9] net: dsa: lan9645x: add basic dsa driver for LAN9645X Jens Emil Schulz Østergaard
2026-08-06 14:38   ` sashiko-bot
2026-08-07 14:07     ` JensEmil.SchulzOstergaard
2026-08-17 14:25   ` Jens Emil Schulz Ostergaard
2026-08-05 14:34 ` [PATCH net-next v11 5/9] net: dsa: lan9645x: add bridge support Jens Emil Schulz Østergaard
2026-08-06 14:38   ` sashiko-bot
2026-08-07 13:44     ` JensEmil.SchulzOstergaard
2026-08-17 14:31   ` Jens Emil Schulz Ostergaard [this message]
2026-08-05 14:34 ` [PATCH net-next v11 6/9] net: dsa: lan9645x: add vlan support Jens Emil Schulz Østergaard
2026-08-06 14:38   ` sashiko-bot
2026-08-07 13:40     ` JensEmil.SchulzOstergaard
2026-08-11 10:32   ` Paolo Abeni
2026-08-11 12:12     ` Jens Emil Schulz Ostergaard
2026-08-05 14:34 ` [PATCH net-next v11 7/9] net: dsa: lan9645x: add mac table integration Jens Emil Schulz Østergaard
2026-08-05 14:34 ` [PATCH net-next v11 8/9] net: dsa: lan9645x: add mdb management Jens Emil Schulz Østergaard
2026-08-06 14:38   ` sashiko-bot
2026-08-07 13:22     ` JensEmil.SchulzOstergaard
2026-08-05 14:34 ` [PATCH net-next v11 9/9] net: dsa: lan9645x: add port statistics Jens Emil Schulz Østergaard
2026-08-11 10:35 ` [PATCH net-next v11 0/9] net: dsa: add DSA support for the LAN9645x switch chip family Paolo Abeni
2026-08-11 10:36   ` Paolo Abeni
2026-08-11 12:18   ` Jens Emil Schulz Ostergaard

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=81bc1f7014f70b567a3a6e4a67728fb9796c4f02.camel@microchip.com \
    --to=jensemil.schulzostergaard@microchip.com \
    --cc=Steen.Hegelund@microchip.com \
    --cc=UNGLinuxDriver@microchip.com \
    --cc=andrew@lunn.ch \
    --cc=conor+dt@kernel.org \
    --cc=daniel.machon@microchip.com \
    --cc=davem@davemloft.net \
    --cc=devicetree@vger.kernel.org \
    --cc=edumazet@google.com \
    --cc=horms@kernel.org \
    --cc=krzk+dt@kernel.org \
    --cc=kuba@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux@armlinux.org.uk \
    --cc=netdev@vger.kernel.org \
    --cc=olteanv@gmail.com \
    --cc=pabeni@redhat.com \
    --cc=robh@kernel.org \
    --cc=woojung.huh@microchip.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox