* [PATCH net v3 0/3] net: dsa: mv88e6xxx: 6141/6341 workarounds
@ 2026-07-14 23:29 Luke Howard
2026-07-14 23:29 ` [PATCH net v3 1/3] net: dsa: mv88e6xxx: write the ATU FID register on 88E6141/88E6341 Luke Howard
` (2 more replies)
0 siblings, 3 replies; 7+ messages in thread
From: Luke Howard @ 2026-07-14 23:29 UTC (permalink / raw)
To: Vladimir Oltean, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Vivien Didelot, Gregory CLEMENT, Andrew Lunn,
Richard Cochran
Cc: Cedric Jehasse, Kieran Tyrrell, Max Holtmann, Max Hunter,
Christoph Mellauner, Simon Gapp, netdev, linux-kernel,
Luke Howard
This patch series addresses three issues I found with the 88E6341
switch, which likely also apply to the 88E6141 (which is the same
chip without AVB/TSN support).
The first was a genuine bug, which assumed the chip did not have
a dedicated ATU FID register (it does).
The second is an issue I noticed with hash collisions in the ATU
on the 6341 when using multiple FIDs. Different algorithms could
be selected using devlink, but the FDB was not flushed which
resulted in a corrupted FDB. (There is an outstanding question
as to whether this should only be allowed when all user ports
are administratively down; this is not addressed in this revision.)
The third is an issue (not originally included in the first two
revisions of this patch series) where flushing a FDB entry would
instead move it to port 3.
Signed-off-by: Luke Howard <lukeh@padl.com>
---
Changes in v3:
- Don't reorder mv88e6xxx_info to optimize alignment; just add
atu_fid_reg
- Don't clip ATU Move ToPort delete sentinel (flushing learned
FDB entries was broken)
- Link to v2: https://patch.msgid.link/20260710-mv88e6x41-fixes-v2-0-e23654c65aa0@padl.com
Changes in v2:
- Rather than special casing ATU hash algorithm for the 6341, simply
ensure the ATU is flushed when changing it via devlink.
- Retartget net instead of net-next, as this is a bugfix
- Link to v1: https://patch.msgid.link/20260703-mv88e6x41-fixes-v1-0-fbd3a1bf8965@padl.com
To: Andrew Lunn <andrew@lunn.ch>
To: Vladimir Oltean <olteanv@gmail.com>
To: "David S. Miller" <davem@davemloft.net>
To: Eric Dumazet <edumazet@google.com>
To: Jakub Kicinski <kuba@kernel.org>
To: Paolo Abeni <pabeni@redhat.com>
To: Richard Cochran <richardcochran@gmail.com>
To: Vivien Didelot <vivien.didelot@gmail.com>
To: Gregory CLEMENT <gregory.clement@bootlin.com>
Cc: netdev@vger.kernel.org
Cc: linux-kernel@vger.kernel.org
---
Luke Howard (3):
net: dsa: mv88e6xxx: write the ATU FID register on 88E6141/88E6341
net: dsa: mv88e6xxx: flush the ATU when the hash algorithm changes
net: dsa: mv88e6xxx: don't clip ATU Move ToPort delete sentinel
drivers/net/dsa/mv88e6xxx/chip.c | 29 ++++++++++++++++++++++++++++-
drivers/net/dsa/mv88e6xxx/chip.h | 5 +++++
drivers/net/dsa/mv88e6xxx/devlink.c | 6 ++++++
drivers/net/dsa/mv88e6xxx/global1_atu.c | 11 ++++++++---
4 files changed, 47 insertions(+), 4 deletions(-)
---
base-commit: f6f3b36c15ed44de1fbb44e645e4fae8c4a4453e
change-id: 20260624-mv88e6x41-fixes-d4c84f955ebc
Best regards,
--
Luke Howard <lukeh@padl.com>
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH net v3 1/3] net: dsa: mv88e6xxx: write the ATU FID register on 88E6141/88E6341
2026-07-14 23:29 [PATCH net v3 0/3] net: dsa: mv88e6xxx: 6141/6341 workarounds Luke Howard
@ 2026-07-14 23:29 ` Luke Howard
2026-07-15 0:00 ` Andrew Lunn
2026-07-14 23:29 ` [PATCH net v3 2/3] net: dsa: mv88e6xxx: flush the ATU when the hash algorithm changes Luke Howard
2026-07-14 23:29 ` [PATCH net v3 3/3] net: dsa: mv88e6xxx: don't clip ATU Move ToPort delete sentinel Luke Howard
2 siblings, 1 reply; 7+ messages in thread
From: Luke Howard @ 2026-07-14 23:29 UTC (permalink / raw)
To: Vladimir Oltean, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Vivien Didelot, Gregory CLEMENT, Andrew Lunn,
Richard Cochran
Cc: Cedric Jehasse, Kieran Tyrrell, Max Holtmann, Max Hunter,
Christoph Mellauner, Simon Gapp, netdev, linux-kernel,
Luke Howard
The driver decided whether a device has a dedicated ATU FID register
from its database count, taking the register path only when there were
more than 256 databases. The 88E6141/88E6341 have 256 databases but do
have the register, so they fell back to the legacy path and the FID
register was never written. Every FDB entry was then loaded into FID 0,
breaking VLAN aware bridging.
The number of databases does not imply whether the register is present.
Add an explicit atu_fid_reg flag, set it on every device that has the
register (all that previously matched the >256 heuristic, plus the
88E6141/88E6341), and key the register access off the flag instead of
the database count.
Fixes: a75961d0ebfd ("net: dsa: mv88e6xxx: Add support for ethernet switch 88E6341")
Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Luke Howard <lukeh@padl.com>
---
drivers/net/dsa/mv88e6xxx/chip.c | 27 +++++++++++++++++++++++++++
drivers/net/dsa/mv88e6xxx/chip.h | 3 +++
drivers/net/dsa/mv88e6xxx/global1_atu.c | 4 ++--
3 files changed, 32 insertions(+), 2 deletions(-)
diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index 80b877c74513d..7938e50900ca8 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -5747,6 +5747,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.family = MV88E6XXX_FAMILY_6097,
.name = "Marvell 88E6085",
.num_databases = 4096,
+ .atu_fid_reg = true,
.num_macs = 8192,
.num_ports = 10,
.num_internal_phys = 5,
@@ -5792,6 +5793,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.family = MV88E6XXX_FAMILY_6097,
.name = "Marvell 88E6097/88E6097F",
.num_databases = 4096,
+ .atu_fid_reg = true,
.num_macs = 8192,
.num_ports = 11,
.num_internal_phys = 8,
@@ -5817,6 +5819,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.family = MV88E6XXX_FAMILY_6165,
.name = "Marvell 88E6123",
.num_databases = 4096,
+ .atu_fid_reg = true,
.num_macs = 1024,
.num_ports = 3,
.num_internal_phys = 5,
@@ -5863,6 +5866,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.family = MV88E6XXX_FAMILY_6341,
.name = "Marvell 88E6141",
.num_databases = 256,
+ .atu_fid_reg = true,
.num_macs = 2048,
.num_ports = 6,
.num_internal_phys = 5,
@@ -5889,6 +5893,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.family = MV88E6XXX_FAMILY_6165,
.name = "Marvell 88E6161",
.num_databases = 4096,
+ .atu_fid_reg = true,
.num_macs = 1024,
.num_ports = 6,
.num_internal_phys = 5,
@@ -5915,6 +5920,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.family = MV88E6XXX_FAMILY_6165,
.name = "Marvell 88E6165",
.num_databases = 4096,
+ .atu_fid_reg = true,
.num_macs = 8192,
.num_ports = 6,
.num_internal_phys = 0,
@@ -5940,6 +5946,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.family = MV88E6XXX_FAMILY_6351,
.name = "Marvell 88E6171",
.num_databases = 4096,
+ .atu_fid_reg = true,
.num_macs = 8192,
.num_ports = 7,
.num_internal_phys = 5,
@@ -5965,6 +5972,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.family = MV88E6XXX_FAMILY_6352,
.name = "Marvell 88E6172",
.num_databases = 4096,
+ .atu_fid_reg = true,
.num_macs = 8192,
.num_ports = 7,
.num_internal_phys = 5,
@@ -5991,6 +5999,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.family = MV88E6XXX_FAMILY_6351,
.name = "Marvell 88E6175",
.num_databases = 4096,
+ .atu_fid_reg = true,
.num_macs = 8192,
.num_ports = 7,
.num_internal_phys = 5,
@@ -6016,6 +6025,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.family = MV88E6XXX_FAMILY_6352,
.name = "Marvell 88E6176",
.num_databases = 4096,
+ .atu_fid_reg = true,
.num_macs = 8192,
.num_ports = 7,
.num_internal_phys = 5,
@@ -6064,6 +6074,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.family = MV88E6XXX_FAMILY_6390,
.name = "Marvell 88E6190",
.num_databases = 4096,
+ .atu_fid_reg = true,
.num_macs = 16384,
.num_ports = 11, /* 10 + Z80 */
.num_internal_phys = 9,
@@ -6089,6 +6100,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.family = MV88E6XXX_FAMILY_6390,
.name = "Marvell 88E6190X",
.num_databases = 4096,
+ .atu_fid_reg = true,
.num_macs = 16384,
.num_ports = 11, /* 10 + Z80 */
.num_internal_phys = 9,
@@ -6114,6 +6126,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.family = MV88E6XXX_FAMILY_6390,
.name = "Marvell 88E6191",
.num_databases = 4096,
+ .atu_fid_reg = true,
.num_macs = 16384,
.num_ports = 11, /* 10 + Z80 */
.num_internal_phys = 9,
@@ -6139,6 +6152,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.family = MV88E6XXX_FAMILY_6393,
.name = "Marvell 88E6191X",
.num_databases = 4096,
+ .atu_fid_reg = true,
.num_ports = 11, /* 10 + Z80 */
.num_internal_phys = 8,
.internal_phys_offset = 1,
@@ -6164,6 +6178,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.family = MV88E6XXX_FAMILY_6393,
.name = "Marvell 88E6193X",
.num_databases = 4096,
+ .atu_fid_reg = true,
.num_ports = 11, /* 10 + Z80 */
.num_internal_phys = 8,
.num_tcam_entries = 256,
@@ -6218,6 +6233,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.family = MV88E6XXX_FAMILY_6352,
.name = "Marvell 88E6240",
.num_databases = 4096,
+ .atu_fid_reg = true,
.num_macs = 8192,
.num_ports = 7,
.num_internal_phys = 5,
@@ -6267,6 +6283,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.family = MV88E6XXX_FAMILY_6390,
.name = "Marvell 88E6290",
.num_databases = 4096,
+ .atu_fid_reg = true,
.num_ports = 11, /* 10 + Z80 */
.num_internal_phys = 9,
.num_gpio = 16,
@@ -6294,6 +6311,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.family = MV88E6XXX_FAMILY_6320,
.name = "Marvell 88E6320",
.num_databases = 4096,
+ .atu_fid_reg = true,
.num_macs = 8192,
.num_ports = 7,
.num_internal_phys = 2,
@@ -6322,6 +6340,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.family = MV88E6XXX_FAMILY_6320,
.name = "Marvell 88E6321",
.num_databases = 4096,
+ .atu_fid_reg = true,
.num_macs = 8192,
.num_ports = 7,
.num_internal_phys = 2,
@@ -6350,6 +6369,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.family = MV88E6XXX_FAMILY_6341,
.name = "Marvell 88E6341",
.num_databases = 256,
+ .atu_fid_reg = true,
.num_macs = 2048,
.num_internal_phys = 5,
.num_ports = 6,
@@ -6377,6 +6397,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.family = MV88E6XXX_FAMILY_6351,
.name = "Marvell 88E6350",
.num_databases = 4096,
+ .atu_fid_reg = true,
.num_macs = 8192,
.num_ports = 7,
.num_internal_phys = 5,
@@ -6402,6 +6423,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.family = MV88E6XXX_FAMILY_6351,
.name = "Marvell 88E6351",
.num_databases = 4096,
+ .atu_fid_reg = true,
.num_macs = 8192,
.num_ports = 7,
.num_internal_phys = 5,
@@ -6427,6 +6449,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.family = MV88E6XXX_FAMILY_6352,
.name = "Marvell 88E6352",
.num_databases = 4096,
+ .atu_fid_reg = true,
.num_macs = 8192,
.num_ports = 7,
.num_internal_phys = 5,
@@ -6453,6 +6476,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.family = MV88E6XXX_FAMILY_6393,
.name = "Marvell 88E6361",
.num_databases = 4096,
+ .atu_fid_reg = true,
.num_macs = 16384,
.num_ports = 11,
/* Ports 1, 2 and 8 are not routed */
@@ -6480,6 +6504,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.family = MV88E6XXX_FAMILY_6390,
.name = "Marvell 88E6390",
.num_databases = 4096,
+ .atu_fid_reg = true,
.num_macs = 16384,
.num_ports = 11, /* 10 + Z80 */
.num_internal_phys = 9,
@@ -6508,6 +6533,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.family = MV88E6XXX_FAMILY_6390,
.name = "Marvell 88E6390X",
.num_databases = 4096,
+ .atu_fid_reg = true,
.num_macs = 16384,
.num_ports = 11, /* 10 + Z80 */
.num_internal_phys = 9,
@@ -6535,6 +6561,7 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = {
.family = MV88E6XXX_FAMILY_6393,
.name = "Marvell 88E6393X",
.num_databases = 4096,
+ .atu_fid_reg = true,
.num_ports = 11, /* 10 + Z80 */
.num_internal_phys = 8,
.num_tcam_entries = 256,
diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h
index e966e7c4cc5de..f1db12b7629bd 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.h
+++ b/drivers/net/dsa/mv88e6xxx/chip.h
@@ -176,6 +176,9 @@ struct mv88e6xxx_info {
/* Supports PTP */
bool ptp_support;
+ /* Has a dedicated ATU FID register. */
+ bool atu_fid_reg;
+
/* Internal PHY start index. 0 means that internal PHYs range starts at
* port 0, 1 means internal PHYs range starts at port 1, etc
*/
diff --git a/drivers/net/dsa/mv88e6xxx/global1_atu.c b/drivers/net/dsa/mv88e6xxx/global1_atu.c
index c47f068f56b32..522978f638e2f 100644
--- a/drivers/net/dsa/mv88e6xxx/global1_atu.c
+++ b/drivers/net/dsa/mv88e6xxx/global1_atu.c
@@ -135,7 +135,7 @@ static int mv88e6xxx_g1_atu_op(struct mv88e6xxx_chip *chip, u16 fid, u16 op)
int err;
/* FID bits are dispatched all around gradually as more are supported */
- if (mv88e6xxx_num_databases(chip) > 256) {
+ if (chip->info->atu_fid_reg) {
err = mv88e6xxx_g1_atu_fid_write(chip, fid);
if (err)
return err;
@@ -179,7 +179,7 @@ static int mv88e6xxx_g1_atu_fid_read(struct mv88e6xxx_chip *chip, u16 *fid)
u16 val = 0, upper = 0, op = 0;
int err = -EOPNOTSUPP;
- if (mv88e6xxx_num_databases(chip) > 256) {
+ if (chip->info->atu_fid_reg) {
err = mv88e6xxx_g1_read(chip, MV88E6352_G1_ATU_FID, &val);
val &= 0xfff;
if (err)
--
2.43.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH net v3 2/3] net: dsa: mv88e6xxx: flush the ATU when the hash algorithm changes
2026-07-14 23:29 [PATCH net v3 0/3] net: dsa: mv88e6xxx: 6141/6341 workarounds Luke Howard
2026-07-14 23:29 ` [PATCH net v3 1/3] net: dsa: mv88e6xxx: write the ATU FID register on 88E6141/88E6341 Luke Howard
@ 2026-07-14 23:29 ` Luke Howard
2026-07-15 0:08 ` Andrew Lunn
2026-07-14 23:29 ` [PATCH net v3 3/3] net: dsa: mv88e6xxx: don't clip ATU Move ToPort delete sentinel Luke Howard
2 siblings, 1 reply; 7+ messages in thread
From: Luke Howard @ 2026-07-14 23:29 UTC (permalink / raw)
To: Vladimir Oltean, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Vivien Didelot, Gregory CLEMENT, Andrew Lunn,
Richard Cochran
Cc: Cedric Jehasse, Kieran Tyrrell, Max Holtmann, Max Hunter,
Christoph Mellauner, Simon Gapp, netdev, linux-kernel,
Luke Howard
Changing the ATU hash algorithm invalidates existing entries: those
loaded under the previous algorithm end up in different bins and read
back corrupted.
Flush the ATU whenever the hash algorithm is changed through devlink
and reload the default broadcast entries. Per-VLAN ATU entries and
any static addresses are not replayed, so the hash must be selected
before the FDB or MDB are configured.
Fixes: 23e8b470c778 ("net: dsa: mv88e6xxx: Add devlink param for ATU hash algorithm.")
Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Luke Howard <lukeh@padl.com>
---
drivers/net/dsa/mv88e6xxx/chip.c | 2 +-
drivers/net/dsa/mv88e6xxx/chip.h | 2 ++
drivers/net/dsa/mv88e6xxx/devlink.c | 6 ++++++
3 files changed, 9 insertions(+), 1 deletion(-)
diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index 7938e50900ca8..6faae74de04a9 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -2523,7 +2523,7 @@ static int mv88e6xxx_port_add_broadcast(struct mv88e6xxx_chip *chip, int port,
return mv88e6xxx_port_db_load_purge(chip, port, broadcast, vid, state);
}
-static int mv88e6xxx_broadcast_setup(struct mv88e6xxx_chip *chip, u16 vid)
+int mv88e6xxx_broadcast_setup(struct mv88e6xxx_chip *chip, u16 vid)
{
int port;
int err;
diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h
index f1db12b7629bd..abbb446b73456 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.h
+++ b/drivers/net/dsa/mv88e6xxx/chip.h
@@ -893,4 +893,6 @@ int mv88e6xxx_vtu_walk(struct mv88e6xxx_chip *chip,
void *priv),
void *priv);
+int mv88e6xxx_broadcast_setup(struct mv88e6xxx_chip *chip, u16 vid);
+
#endif /* _MV88E6XXX_CHIP_H */
diff --git a/drivers/net/dsa/mv88e6xxx/devlink.c b/drivers/net/dsa/mv88e6xxx/devlink.c
index 6f034841883c6..5168335f52289 100644
--- a/drivers/net/dsa/mv88e6xxx/devlink.c
+++ b/drivers/net/dsa/mv88e6xxx/devlink.c
@@ -61,6 +61,12 @@ int mv88e6xxx_devlink_param_set(struct dsa_switch *ds, u32 id,
switch (id) {
case MV88E6XXX_DEVLINK_PARAM_ID_ATU_HASH:
err = mv88e6xxx_atu_set_hash(chip, ctx->val.vu8);
+ if (err)
+ break;
+ err = mv88e6xxx_g1_atu_flush(chip, 0, true);
+ if (err)
+ break;
+ err = mv88e6xxx_broadcast_setup(chip, 0);
break;
default:
err = -EOPNOTSUPP;
--
2.43.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH net v3 3/3] net: dsa: mv88e6xxx: don't clip ATU Move ToPort delete sentinel
2026-07-14 23:29 [PATCH net v3 0/3] net: dsa: mv88e6xxx: 6141/6341 workarounds Luke Howard
2026-07-14 23:29 ` [PATCH net v3 1/3] net: dsa: mv88e6xxx: write the ATU FID register on 88E6141/88E6341 Luke Howard
2026-07-14 23:29 ` [PATCH net v3 2/3] net: dsa: mv88e6xxx: flush the ATU when the hash algorithm changes Luke Howard
@ 2026-07-14 23:29 ` Luke Howard
2026-07-15 0:02 ` Andrew Lunn
2 siblings, 1 reply; 7+ messages in thread
From: Luke Howard @ 2026-07-14 23:29 UTC (permalink / raw)
To: Vladimir Oltean, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Vivien Didelot, Gregory CLEMENT, Andrew Lunn,
Richard Cochran
Cc: Cedric Jehasse, Kieran Tyrrell, Max Holtmann, Max Hunter,
Christoph Mellauner, Simon Gapp, netdev, linux-kernel,
Luke Howard
mv88e6xxx_g1_atu_data_write() masked the port vector, which is correct
for a load operation (where portvec is a bitmap) but wrong for a move,
where the portvec encodes a ToPort/FromPort pair.
An all-ones ToPort value is the sentinel used to delete an entry. Chips
with fewer than eight ports (e.g. 88E6141) clipped this value, turning a
delete into a move (to port 3 on the 6141/6341). Other chips such as
the 7-port 88E6352 were unaffected by chance.
Fix this by moving the mv88e6xxx_port_mask() mask into
mv88e6xxx_g1_atu_loadpurge(), where the portvec always represents a
bitmap; the move path then writes its ToPort/FromPort pair unmasked.
Fixes: e606ca36bbf2 ("net: dsa: mv88e6xxx: rework ATU Remove")
Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Luke Howard <lukeh@padl.com>
---
drivers/net/dsa/mv88e6xxx/global1_atu.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/drivers/net/dsa/mv88e6xxx/global1_atu.c b/drivers/net/dsa/mv88e6xxx/global1_atu.c
index 522978f638e2f..6bee943c83575 100644
--- a/drivers/net/dsa/mv88e6xxx/global1_atu.c
+++ b/drivers/net/dsa/mv88e6xxx/global1_atu.c
@@ -239,7 +239,7 @@ static int mv88e6xxx_g1_atu_data_write(struct mv88e6xxx_chip *chip,
if (entry->trunk)
data |= MV88E6XXX_G1_ATU_DATA_TRUNK;
- data |= (entry->portvec & mv88e6xxx_port_mask(chip)) << 4;
+ data |= entry->portvec << 4;
}
return mv88e6xxx_g1_write(chip, MV88E6XXX_G1_ATU_DATA, data);
@@ -326,6 +326,11 @@ int mv88e6xxx_g1_atu_loadpurge(struct mv88e6xxx_chip *chip, u16 fid,
if (err)
return err;
+ /* Mask portvec to a chip's real ports so they cannot spill into
+ * adjacent ATU Data register fields.
+ */
+ entry->portvec &= mv88e6xxx_port_mask(chip);
+
err = mv88e6xxx_g1_atu_data_write(chip, entry);
if (err)
return err;
--
2.43.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH net v3 1/3] net: dsa: mv88e6xxx: write the ATU FID register on 88E6141/88E6341
2026-07-14 23:29 ` [PATCH net v3 1/3] net: dsa: mv88e6xxx: write the ATU FID register on 88E6141/88E6341 Luke Howard
@ 2026-07-15 0:00 ` Andrew Lunn
0 siblings, 0 replies; 7+ messages in thread
From: Andrew Lunn @ 2026-07-15 0:00 UTC (permalink / raw)
To: Luke Howard
Cc: Vladimir Oltean, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Vivien Didelot, Gregory CLEMENT, Richard Cochran,
Cedric Jehasse, Kieran Tyrrell, Max Holtmann, Max Hunter,
Christoph Mellauner, Simon Gapp, netdev, linux-kernel
On Wed, Jul 15, 2026 at 09:29:41AM +1000, Luke Howard wrote:
> The driver decided whether a device has a dedicated ATU FID register
> from its database count, taking the register path only when there were
> more than 256 databases. The 88E6141/88E6341 have 256 databases but do
> have the register, so they fell back to the legacy path and the FID
> register was never written. Every FDB entry was then loaded into FID 0,
> breaking VLAN aware bridging.
>
> The number of databases does not imply whether the register is present.
> Add an explicit atu_fid_reg flag, set it on every device that has the
> register (all that previously matched the >256 heuristic, plus the
> 88E6141/88E6341), and key the register access off the flag instead of
> the database count.
>
> Fixes: a75961d0ebfd ("net: dsa: mv88e6xxx: Add support for ethernet switch 88E6341")
> Assisted-by: Claude:claude-opus-4-8
> Signed-off-by: Luke Howard <lukeh@padl.com>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Andrew
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH net v3 3/3] net: dsa: mv88e6xxx: don't clip ATU Move ToPort delete sentinel
2026-07-14 23:29 ` [PATCH net v3 3/3] net: dsa: mv88e6xxx: don't clip ATU Move ToPort delete sentinel Luke Howard
@ 2026-07-15 0:02 ` Andrew Lunn
0 siblings, 0 replies; 7+ messages in thread
From: Andrew Lunn @ 2026-07-15 0:02 UTC (permalink / raw)
To: Luke Howard
Cc: Vladimir Oltean, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Vivien Didelot, Gregory CLEMENT, Richard Cochran,
Cedric Jehasse, Kieran Tyrrell, Max Holtmann, Max Hunter,
Christoph Mellauner, Simon Gapp, netdev, linux-kernel
On Wed, Jul 15, 2026 at 09:29:43AM +1000, Luke Howard wrote:
> mv88e6xxx_g1_atu_data_write() masked the port vector, which is correct
> for a load operation (where portvec is a bitmap) but wrong for a move,
> where the portvec encodes a ToPort/FromPort pair.
>
> An all-ones ToPort value is the sentinel used to delete an entry. Chips
> with fewer than eight ports (e.g. 88E6141) clipped this value, turning a
> delete into a move (to port 3 on the 6141/6341). Other chips such as
> the 7-port 88E6352 were unaffected by chance.
>
> Fix this by moving the mv88e6xxx_port_mask() mask into
> mv88e6xxx_g1_atu_loadpurge(), where the portvec always represents a
> bitmap; the move path then writes its ToPort/FromPort pair unmasked.
>
> Fixes: e606ca36bbf2 ("net: dsa: mv88e6xxx: rework ATU Remove")
> Assisted-by: Claude:claude-opus-4-8
> Signed-off-by: Luke Howard <lukeh@padl.com>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Andrew
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH net v3 2/3] net: dsa: mv88e6xxx: flush the ATU when the hash algorithm changes
2026-07-14 23:29 ` [PATCH net v3 2/3] net: dsa: mv88e6xxx: flush the ATU when the hash algorithm changes Luke Howard
@ 2026-07-15 0:08 ` Andrew Lunn
0 siblings, 0 replies; 7+ messages in thread
From: Andrew Lunn @ 2026-07-15 0:08 UTC (permalink / raw)
To: Luke Howard, Jonas Gorski
Cc: Vladimir Oltean, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Vivien Didelot, Gregory CLEMENT, Richard Cochran,
Cedric Jehasse, Kieran Tyrrell, Max Holtmann, Max Hunter,
Christoph Mellauner, Simon Gapp, netdev, linux-kernel
On Wed, Jul 15, 2026 at 09:29:42AM +1000, Luke Howard wrote:
> Changing the ATU hash algorithm invalidates existing entries: those
> loaded under the previous algorithm end up in different bins and read
> back corrupted.
>
> Flush the ATU whenever the hash algorithm is changed through devlink
> and reload the default broadcast entries. Per-VLAN ATU entries and
> any static addresses are not replayed, so the hash must be selected
> before the FDB or MDB are configured.
Hi Jonas
For v2 you said you thought this was a bit of a foot gun. I suggested
maybe checking all user ports are admin down. What do you think?
Thanks
Andrew
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2026-07-15 0:08 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-14 23:29 [PATCH net v3 0/3] net: dsa: mv88e6xxx: 6141/6341 workarounds Luke Howard
2026-07-14 23:29 ` [PATCH net v3 1/3] net: dsa: mv88e6xxx: write the ATU FID register on 88E6141/88E6341 Luke Howard
2026-07-15 0:00 ` Andrew Lunn
2026-07-14 23:29 ` [PATCH net v3 2/3] net: dsa: mv88e6xxx: flush the ATU when the hash algorithm changes Luke Howard
2026-07-15 0:08 ` Andrew Lunn
2026-07-14 23:29 ` [PATCH net v3 3/3] net: dsa: mv88e6xxx: don't clip ATU Move ToPort delete sentinel Luke Howard
2026-07-15 0:02 ` Andrew Lunn
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox