diff mbox series

[net] net: dsa: mv88e6xxx: Respect other ports when setting chip-wide MTU

Message ID 20240716120808.396514-1-martin@strongswan.org (mailing list archive)
State Changes Requested
Delegated to: Netdev Maintainers
Headers show
Series [net] net: dsa: mv88e6xxx: Respect other ports when setting chip-wide MTU | expand

Checks

Context Check Description
netdev/series_format success Single patches do not need cover letters
netdev/tree_selection success Clearly marked for net
netdev/ynl success Generated files up to date; no warnings/errors; no diff in generated;
netdev/fixes_present success Fixes tag present in non-next series
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit success Errors and warnings before: 833 this patch: 833
netdev/build_tools success No tools touched, skip
netdev/cc_maintainers success CCed 8 of 8 maintainers
netdev/build_clang success Errors and warnings before: 835 this patch: 835
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/deprecated_api success None detected
netdev/check_selftest success No net selftest shell script
netdev/verify_fixes success Fixes tag looks correct
netdev/build_allmodconfig_warn success Errors and warnings before: 835 this patch: 835
netdev/checkpatch success total: 0 errors, 0 warnings, 0 checks, 34 lines checked
netdev/build_clang_rust success No Rust files in patch. Skipping build
netdev/kdoc success Errors and warnings before: 0 this patch: 0
netdev/source_inline success Was 0 now: 0
netdev/contest success net-next-2024-07-16--21-00 (tests: 696)

Commit Message

Martin Willi July 16, 2024, 12:08 p.m. UTC
DSA chips not supporting per-port jumbo frame size configurations use a
chip-wide setting. In the commit referenced with the Fixes tag, the
setting is applied just for the last port changing its MTU. This may
result in two issues:

  * Starting with commit b9c587fed61c ("dsa: mv88e6xxx: Include tagger
    overhead when setting MTU for DSA and CPU ports"), the CPU port
    accounts for tagger overhead. If a user port is configured after
    the CPU port, the chip-wide setting may be reduced again, as the
    user port does not account for tagger overhead.
  * If different user ports use different MTUs (say within different
    L2 domains), setting the lower MTU after the higher MTU may result
    in a chip-wide setting for the lower MTU, only.

Any of the above may result in clearing MV88E6185_G1_CTL1_MAX_FRAME_1632
while it is actually required for the current configuration on some (CPU)
ports. Specifically, on a MV88E6097 this results in dropped frames when
setting the MTU to 1500 and sending local full-sized frames over a user
port.

To respect the MTU requirements of all CPU and user ports, get the maximum
frame size requirements over all ports when updating the chip-wide
setting.

Fixes: 1baf0fac10fb ("net: dsa: mv88e6xxx: Use chip-wide max frame size for MTU")
Signed-off-by: Martin Willi <martin@strongswan.org>
---
 drivers/net/dsa/mv88e6xxx/chip.c | 18 +++++++++++++++++-
 1 file changed, 17 insertions(+), 1 deletion(-)

Comments

Vladimir Oltean July 16, 2024, 2:17 p.m. UTC | #1
Hi Martin,

On Tue, Jul 16, 2024 at 02:08:08PM +0200, Martin Willi wrote:
> DSA chips not supporting per-port jumbo frame size configurations use a
> chip-wide setting. In the commit referenced with the Fixes tag, the
> setting is applied just for the last port changing its MTU. This may
> result in two issues:
> 
>   * Starting with commit b9c587fed61c ("dsa: mv88e6xxx: Include tagger
>     overhead when setting MTU for DSA and CPU ports"), the CPU port
>     accounts for tagger overhead. If a user port is configured after
>     the CPU port, the chip-wide setting may be reduced again, as the
>     user port does not account for tagger overhead.
>   * If different user ports use different MTUs (say within different
>     L2 domains), setting the lower MTU after the higher MTU may result
>     in a chip-wide setting for the lower MTU, only.
> 
> Any of the above may result in clearing MV88E6185_G1_CTL1_MAX_FRAME_1632
> while it is actually required for the current configuration on some (CPU)
> ports. Specifically, on a MV88E6097 this results in dropped frames when
> setting the MTU to 1500 and sending local full-sized frames over a user
> port.
> 
> To respect the MTU requirements of all CPU and user ports, get the maximum
> frame size requirements over all ports when updating the chip-wide
> setting.
> 
> Fixes: 1baf0fac10fb ("net: dsa: mv88e6xxx: Use chip-wide max frame size for MTU")
> Signed-off-by: Martin Willi <martin@strongswan.org>
> ---

There is actually a much simpler solution which I advise you to take.

We already know, by construction, that the MTU applied to the CPU port
is the largest among the MTUs of all user ports.

So you can program to hardware a chip-wide value which corresponds only
to the MTU of the CPU port.

You can see that rtl8365mb_port_change_mtu(), qca8k_port_change_mtu(),
mt7530_port_change_mtu(), ksz8_change_mtu(), ksz9477_change_mtu()
already do this. And we also have rtl8366rb_change_mtu() which takes the
long route, as you do, and which could be simplified.

This fix should work, I believe:

-	else if (chip->info->ops->set_max_frame_size)
+	else if (chip->info->ops->set_max_frame_size && dsa_is_cpu_port(ds, port))
 		ret = chip->info->ops->set_max_frame_size(chip, new_mtu);

BTW, I now realize b53_change_mtu() suffers from the same problem.
It would be great if you could also send a patch fixing that driver in
the same way.
diff mbox series

Patch

diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index 07c897b13de1..c231c956bf9a 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -3604,9 +3604,19 @@  static int mv88e6xxx_get_max_mtu(struct dsa_switch *ds, int port)
 	return ETH_DATA_LEN;
 }
 
+static int mv88e6xxx_get_port_mtu(struct dsa_port *dp)
+{
+	if (dsa_port_is_cpu(dp))
+		return dp->conduit->mtu;
+	if (dsa_port_is_user(dp) && dp->user)
+		return dp->user->mtu;
+	return 0;
+}
+
 static int mv88e6xxx_change_mtu(struct dsa_switch *ds, int port, int new_mtu)
 {
 	struct mv88e6xxx_chip *chip = ds->priv;
+	struct dsa_port *dp;
 	int ret = 0;
 
 	/* For families where we don't know how to alter the MTU,
@@ -3626,8 +3636,14 @@  static int mv88e6xxx_change_mtu(struct dsa_switch *ds, int port, int new_mtu)
 	mv88e6xxx_reg_lock(chip);
 	if (chip->info->ops->port_set_jumbo_size)
 		ret = chip->info->ops->port_set_jumbo_size(chip, port, new_mtu);
-	else if (chip->info->ops->set_max_frame_size)
+	else if (chip->info->ops->set_max_frame_size) {
+		dsa_switch_for_each_port(dp, ds) {
+			if (dp->index == port)
+				continue;
+			new_mtu = max(new_mtu, mv88e6xxx_get_port_mtu(dp));
+		}
 		ret = chip->info->ops->set_max_frame_size(chip, new_mtu);
+	}
 	mv88e6xxx_reg_unlock(chip);
 
 	return ret;