#include <linux/of_irq.h>
 #include <linux/regmap.h>
 #include <linux/if_bridge.h>
+#include <linux/if_vlan.h>
 
 #include "realtek.h"
 
 /* Maximum packet length register */
 #define RTL8365MB_CFG0_MAX_LEN_REG     0x088C
 #define   RTL8365MB_CFG0_MAX_LEN_MASK  0x3FFF
+#define RTL8365MB_CFG0_MAX_LEN_MAX     0x3FFF
 
 /* Port learning limit registers */
 #define RTL8365MB_LUT_PORT_LEARN_LIMIT_BASE            0x0A20
        }
 }
 
+static int rtl8365mb_port_change_mtu(struct dsa_switch *ds, int port,
+                                    int new_mtu)
+{
+       struct realtek_priv *priv = ds->priv;
+       int frame_size;
+
+       /* When a new MTU is set, DSA always sets the CPU port's MTU to the
+        * largest MTU of the slave ports. Because the switch only has a global
+        * RX length register, only allowing CPU port here is enough.
+        */
+       if (!dsa_is_cpu_port(ds, port))
+               return 0;
+
+       frame_size = new_mtu + VLAN_ETH_HLEN + ETH_FCS_LEN;
+
+       dev_dbg(priv->dev, "changing mtu to %d (frame size: %d)\n",
+               new_mtu, frame_size);
+
+       return regmap_update_bits(priv->map, RTL8365MB_CFG0_MAX_LEN_REG,
+                                 RTL8365MB_CFG0_MAX_LEN_MASK,
+                                 FIELD_PREP(RTL8365MB_CFG0_MAX_LEN_MASK,
+                                            frame_size));
+}
+
+static int rtl8365mb_port_max_mtu(struct dsa_switch *ds, int port)
+{
+       return RTL8365MB_CFG0_MAX_LEN_MAX - VLAN_ETH_HLEN - ETH_FCS_LEN;
+}
+
 static void rtl8365mb_port_stp_state_set(struct dsa_switch *ds, int port,
                                         u8 state)
 {
                p->index = i;
        }
 
-       /* Set maximum packet length to 1536 bytes */
-       ret = regmap_update_bits(priv->map, RTL8365MB_CFG0_MAX_LEN_REG,
-                                RTL8365MB_CFG0_MAX_LEN_MASK,
-                                FIELD_PREP(RTL8365MB_CFG0_MAX_LEN_MASK, 1536));
+       ret = rtl8365mb_port_change_mtu(ds, cpu->trap_port, ETH_DATA_LEN);
        if (ret)
                goto out_teardown_irq;
 
        .get_eth_mac_stats = rtl8365mb_get_mac_stats,
        .get_eth_ctrl_stats = rtl8365mb_get_ctrl_stats,
        .get_stats64 = rtl8365mb_get_stats64,
+       .port_change_mtu = rtl8365mb_port_change_mtu,
+       .port_max_mtu = rtl8365mb_port_max_mtu,
 };
 
 static const struct dsa_switch_ops rtl8365mb_switch_ops_mdio = {
        .get_eth_mac_stats = rtl8365mb_get_mac_stats,
        .get_eth_ctrl_stats = rtl8365mb_get_ctrl_stats,
        .get_stats64 = rtl8365mb_get_stats64,
+       .port_change_mtu = rtl8365mb_port_change_mtu,
+       .port_max_mtu = rtl8365mb_port_max_mtu,
 };
 
 static const struct realtek_ops rtl8365mb_ops = {