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.
next prev 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