Add the MTU change support ported from Microchip BSP kernel.
It will be sent upstream as well.
Signed-off-by: Robert Marko <robert.marko@sartura.hr>
--- /dev/null
+From 44ed546c4231fbf9d0c92738c2c48c49f8249f48 Mon Sep 17 00:00:00 2001
+From: Robert Marko <robert.marko@sartura.hr>
+Date: Tue, 24 Mar 2026 12:02:05 +0100
+Subject: [PATCH 126/130] net: lan969x: correct RGMII port mapping index
+
+Currently, the lan969x_port_dev_mapping does not check for RGMII ports
+and just returns the physical port index.
+
+However, this does not work for RGMII ports as they have dedicated DEVRGMII
+register space with an dedicated instance per RGMII port.
+
+So, check if requested port index is an RGMII port and return the correct
+DEVRGMII index.
+
+Signed-off-by: Robert Marko <robert.marko@sartura.hr>
+---
+ drivers/net/ethernet/microchip/sparx5/lan969x/lan969x.c | 9 +++++++++
+ 1 file changed, 9 insertions(+)
+
+--- a/drivers/net/ethernet/microchip/sparx5/lan969x/lan969x.c
++++ b/drivers/net/ethernet/microchip/sparx5/lan969x/lan969x.c
+@@ -142,6 +142,15 @@ static u32 lan969x_get_dev_mode_bit(stru
+
+ static u32 lan969x_port_dev_mapping(struct sparx5 *sparx5, int port)
+ {
++ if (lan969x_port_is_rgmii(port)) {
++ switch (port) {
++ case 28:
++ return 0;
++ case 29:
++ return 1;
++ }
++ }
++
+ if (lan969x_port_is_5g(port)) {
+ switch (port) {
+ case 9:
--- /dev/null
+From 372e0295a1dbf0ea4333183ac82b8620bef9c0dc Mon Sep 17 00:00:00 2001
+From: Robert Marko <robert.marko@sartura.hr>
+Date: Tue, 24 Mar 2026 12:19:03 +0100
+Subject: [PATCH 127/130] net: sparx5: add MTU change framework
+
+Port the MTU change framework from Microchip BSP kernel.
+This only wires the generic SparX-5 and LAN969x code.
+
+SparX-5 and LAN969x specific code to actually change the MTU will follow.
+
+Signed-off-by: Robert Marko <robert.marko@sartura.hr>
+---
+ .../net/ethernet/microchip/sparx5/Makefile | 2 +-
+ .../ethernet/microchip/sparx5/sparx5_fdma.c | 20 +++
+ .../ethernet/microchip/sparx5/sparx5_main.h | 8 ++
+ .../microchip/sparx5/sparx5_main_regs.h | 11 ++
+ .../ethernet/microchip/sparx5/sparx5_mtu.c | 130 ++++++++++++++++++
+ 5 files changed, 170 insertions(+), 1 deletion(-)
+ create mode 100644 drivers/net/ethernet/microchip/sparx5/sparx5_mtu.c
+
+--- a/drivers/net/ethernet/microchip/sparx5/Makefile
++++ b/drivers/net/ethernet/microchip/sparx5/Makefile
+@@ -11,7 +11,7 @@ sparx5-switch-y := sparx5_main.o sparx5
+ sparx5_ptp.o sparx5_pgid.o sparx5_tc.o sparx5_qos.o \
+ sparx5_vcap_impl.o sparx5_vcap_ag_api.o sparx5_tc_flower.o \
+ sparx5_tc_matchall.o sparx5_pool.o sparx5_sdlb.o sparx5_police.o \
+- sparx5_psfp.o sparx5_mirror.o sparx5_regs.o
++ sparx5_psfp.o sparx5_mirror.o sparx5_regs.o sparx5_mtu.o
+
+ sparx5-switch-$(CONFIG_SPARX5_DCB) += sparx5_dcb.o
+ sparx5-switch-$(CONFIG_DEBUG_FS) += sparx5_vcap_debugfs.o
+--- a/drivers/net/ethernet/microchip/sparx5/sparx5_fdma.c
++++ b/drivers/net/ethernet/microchip/sparx5/sparx5_fdma.c
+@@ -462,6 +462,15 @@ int sparx5_fdma_start(struct sparx5 *spa
+ sparx5_fdma_rx_activate(sparx5, rx);
+ sparx5_fdma_tx_activate(sparx5, tx);
+
++ for (int i = 0; i < sparx5->data->consts->n_ports; i++) {
++ struct sparx5_port *port = sparx5->ports[i];
++
++ if (!port)
++ continue;
++ if (netif_queue_stopped(port->ndev))
++ netif_wake_queue(port->ndev);
++ }
++
+ return 0;
+ }
+
+@@ -471,6 +480,7 @@ int sparx5_fdma_stop(struct sparx5 *spar
+ struct sparx5_tx *tx = &sparx5->tx;
+ u32 val;
+
++ napi_synchronize(&sparx5->rx.napi);
+ napi_disable(&rx->napi);
+
+ /* Stop the fdma and channel interrupts */
+@@ -482,5 +492,15 @@ int sparx5_fdma_stop(struct sparx5 *spar
+ FDMA_PORT_CTRL_XTR_BUF_IS_EMPTY_GET(val) == 0,
+ 500, 10000, 0, sparx5);
+
++ for (int i = 0; i < sparx5->data->consts->n_ports; i++) {
++ struct sparx5_port *port = sparx5->ports[i];
++
++ if (!port)
++ continue;
++ netif_stop_queue(port->ndev);
++ }
++
++ netif_napi_del(&sparx5->rx.napi);
++
+ return 0;
+ }
+--- a/drivers/net/ethernet/microchip/sparx5/sparx5_main.h
++++ b/drivers/net/ethernet/microchip/sparx5/sparx5_main.h
+@@ -102,6 +102,7 @@ enum sparx5_feature {
+ #define PGID_TABLE_SIZE 3290
+
+ #define IFH_LEN 9 /* 36 bytes */
++#define IFH_LEN_BYTES (IFH_LEN * sizeof(u32))
+ #define NULL_VID 0
+ #define SPX5_MACT_PULL_DELAY (2 * HZ)
+ #define SPX5_STATS_CHECK_DELAY (1 * HZ)
+@@ -188,6 +189,7 @@ struct sparx5_tx {
+ struct sparx5_tx_buf *dbs;
+ u64 packets;
+ u64 dropped;
++ u16 max_mtu;
+ };
+
+ struct sparx5_port_config {
+@@ -348,6 +350,8 @@ struct sparx5_ops {
+ int (*fdma_poll)(struct napi_struct *napi, int weight);
+ int (*fdma_xmit)(struct sparx5 *sparx5, u32 *ifh, struct sk_buff *skb,
+ struct net_device *dev);
++ int (*fdma_resize)(struct sparx5 *sparx5);
++ u32 (*get_mtu)(struct sparx5 *sparx5);
+ };
+
+ struct sparx5_main_io_resource {
+@@ -712,6 +716,10 @@ void sparx5_mirror_del(struct sparx5_mal
+ void sparx5_mirror_stats(struct sparx5_mall_entry *entry,
+ struct flow_stats *fstats);
+
++/* sparx5_mtu.c */
++int sparx5_mtu_change(struct net_device *dev, int new_mtu);
++u32 sparx5_mtu_max(struct sparx5 *sparx5);
++
+ /* Clock period in picoseconds */
+ static inline u32 sparx5_clk_period(enum sparx5_core_clockfreq cclock)
+ {
+--- a/drivers/net/ethernet/microchip/sparx5/sparx5_main_regs.h
++++ b/drivers/net/ethernet/microchip/sparx5/sparx5_main_regs.h
+@@ -8204,6 +8204,17 @@ extern const struct sparx5_regs *regs;
+ FIELD_GET(DEVRGMII_MAC_ENA_CFG_TX_ENA, x)
+
+ /* LAN969X ONLY */
++/* DEV1G:MAC_CFG_STATUS:MAC_MAXLEN_CFG */
++#define DEVRGMII_MAC_MAXLEN_CFG(t) \
++ __REG(TARGET_DEVRGMII, t, 2, 36, 0, 1, 36, 8, 0, 1, 4)
++
++#define DEVRGMII_MAC_MAXLEN_CFG_MAX_LEN GENMASK(15, 0)
++#define DEVRGMII_MAC_MAXLEN_CFG_MAX_LEN_SET(x)\
++ FIELD_PREP(DEVRGMII_MAC_MAXLEN_CFG_MAX_LEN, x)
++#define DEVRGMII_MAC_MAXLEN_CFG_MAX_LEN_GET(x)\
++ FIELD_GET(DEVRGMII_MAC_MAXLEN_CFG_MAX_LEN, x)
++
++/* LAN969X ONLY */
+ /* DEV1G:MAC_CFG_STATUS:MAC_TAGS_CFG */
+ #define DEVRGMII_MAC_TAGS_CFG(t) \
+ __REG(TARGET_DEVRGMII, t, 2, 36, 0, 1, 36, 12, 0, 1, 4)
+--- /dev/null
++++ b/drivers/net/ethernet/microchip/sparx5/sparx5_mtu.c
+@@ -0,0 +1,130 @@
++// SPDX-License-Identifier: GPL-2.0+
++/* Microchip Sparx5 Switch driver
++ *
++ * Copyright (c) 2024 Microchip Technology Inc. and its subsidiaries.
++ */
++
++#include "sparx5_main.h"
++
++#define SPX5_HW_MTU(mtu) ((mtu) + ETH_ALEN + IFH_LEN * 4 + ETH_FCS_LEN)
++
++/* Get the MTU for this port */
++static u32 sparx5_mtu_get(struct sparx5_port *port)
++{
++ struct sparx5 *sparx5 = port->sparx5;
++ const struct sparx5_ops *ops = sparx5->data->ops;
++ u32 val;
++
++ /* We always set 2G5 or RGMII MTU, so there is no point in trying to
++ * read high-speed MAC MTU here
++ */
++ if (ops->is_port_rgmii(port->portno)) {
++ u32 idx = ops->get_port_dev_index(sparx5, port->portno);
++ val = spx5_rd(sparx5, DEVRGMII_MAC_MAXLEN_CFG(idx));
++ return DEVRGMII_MAC_MAXLEN_CFG_MAX_LEN_GET(val);
++ } else {
++ val = spx5_rd(sparx5, DEV2G5_MAC_MAXLEN_CFG(port->portno));
++ return DEV2G5_MAC_MAXLEN_CFG_MAX_LEN_GET(val);
++ }
++}
++
++/* Set the MTU for this port. */
++static void sparx5_mtu_set(struct sparx5_port *port, u32 new_mtu)
++{
++ struct sparx5 *sparx5 = port->sparx5;
++ const struct sparx5_ops *ops;
++ u32 idx, hw_mtu;
++
++ ops = sparx5->data->ops;
++ idx = ops->get_port_dev_index(sparx5, port->portno);
++ hw_mtu = SPX5_HW_MTU(new_mtu);
++
++ pr_debug("Setting MTU to: %u for portno (idx: %u): %u\n", new_mtu,
++ port->portno, idx);
++
++ /* All port modules have a 2g5 shadow device (and DEV2G5 is indexed
++ * by port number). Except the RGMII ports
++ */
++ if (!ops->is_port_rgmii(port->portno))
++ spx5_rmw(DEV2G5_MAC_MAXLEN_CFG_MAX_LEN_SET(hw_mtu),
++ DEV2G5_MAC_MAXLEN_CFG_MAX_LEN, sparx5,
++ DEV2G5_MAC_MAXLEN_CFG(port->portno));
++
++ if (ops->is_port_rgmii(port->portno))
++ spx5_rmw(DEVRGMII_MAC_MAXLEN_CFG_MAX_LEN_SET(hw_mtu),
++ DEVRGMII_MAC_MAXLEN_CFG_MAX_LEN, sparx5,
++ DEVRGMII_MAC_MAXLEN_CFG(idx));
++ else if (ops->is_port_2g5(port->portno))
++ return; /* Already configured. */
++ else if (ops->is_port_5g(port->portno))
++ spx5_rmw(DEV5G_MAC_MAXLEN_CFG_MAX_LEN_SET(hw_mtu),
++ DEV5G_MAC_MAXLEN_CFG_MAX_LEN, sparx5,
++ DEV5G_MAC_MAXLEN_CFG(idx));
++ else if (ops->is_port_10g(port->portno))
++ spx5_rmw(DEV10G_MAC_MAXLEN_CFG_MAX_LEN_SET(hw_mtu),
++ DEV10G_MAC_MAXLEN_CFG_MAX_LEN, sparx5,
++ DEV10G_MAC_MAXLEN_CFG(idx));
++ else
++ spx5_rmw(DEV25G_MAC_MAXLEN_CFG_MAX_LEN_SET(hw_mtu),
++ DEV25G_MAC_MAXLEN_CFG_MAX_LEN, sparx5,
++ DEV25G_MAC_MAXLEN_CFG(idx));
++}
++
++u32 sparx5_mtu_max(struct sparx5 *sparx5)
++{
++ u32 mtu_max = 0;
++
++ for (int i = 0; i < sparx5->data->consts->n_ports; i++) {
++ struct sparx5_port *port = sparx5->ports[i];
++ u32 mtu;
++
++ if (!port)
++ continue;
++
++ mtu = sparx5_mtu_get(port) + IFH_LEN_BYTES +
++ SKB_DATA_ALIGN(sizeof(struct skb_shared_info)) +
++ VLAN_HLEN * 2 + XDP_PACKET_HEADROOM;
++
++ if (mtu > mtu_max)
++ mtu_max = mtu;
++ }
++
++ return mtu_max;
++}
++
++static int sparx5_mtu_fdma_set(struct sparx5 *sparx5)
++{
++ const struct sparx5_ops *ops = sparx5->data->ops;
++ u32 mtu_max = sparx5_mtu_max(sparx5);
++
++ /* We might not be using FDMA */
++ if (sparx5->fdma_irq <= 0)
++ return 0;
++
++ /* No need to restart FDMA if the MTU reflects the buffer size */
++ if (mtu_max == sparx5->tx.max_mtu)
++ return 0;
++
++ return ops->fdma_resize(sparx5);
++}
++
++int sparx5_mtu_change(struct net_device *dev, int new_mtu)
++{
++ struct sparx5_port *port = netdev_priv(dev);
++ struct sparx5 *sparx5 = port->sparx5;
++ int err, orig_mtu = dev->mtu;
++
++ /* Write MTU to hardware */
++ sparx5_mtu_set(port, new_mtu);
++
++ err = sparx5_mtu_fdma_set(sparx5);
++ if (err) {
++ sparx5_mtu_set(port, orig_mtu);
++ return err;
++ }
++
++ /* Let the stack know */
++ WRITE_ONCE(dev->mtu, new_mtu);
++
++ return 0;
++}
--- /dev/null
+From 466d22c9d3bdb2feda284c582d4f183879fc57ad Mon Sep 17 00:00:00 2001
+From: Robert Marko <robert.marko@sartura.hr>
+Date: Tue, 24 Mar 2026 12:26:51 +0100
+Subject: [PATCH 128/130] net: sparx5: add MTU change
+
+Add the required SparX-5 specific code to change the MTU.
+
+Signed-off-by: Robert Marko <robert.marko@sartura.hr>
+---
+ .../ethernet/microchip/sparx5/sparx5_fdma.c | 52 +++++++++++++++++++
+ .../ethernet/microchip/sparx5/sparx5_main.c | 2 +
+ .../ethernet/microchip/sparx5/sparx5_main.h | 1 +
+ 3 files changed, 55 insertions(+)
+
+--- a/drivers/net/ethernet/microchip/sparx5/sparx5_fdma.c
++++ b/drivers/net/ethernet/microchip/sparx5/sparx5_fdma.c
+@@ -278,6 +278,8 @@ static void sparx5_fdma_rx_init(struct s
+ struct fdma *fdma = &rx->fdma;
+ int idx;
+
++ sparx5->rx.page_order =
++ round_up(sparx5->tx.max_mtu, PAGE_SIZE) / PAGE_SIZE - 1;
+ fdma->channel_id = channel;
+ fdma->n_dcbs = FDMA_DCB_MAX;
+ fdma->n_dbs = FDMA_RX_DCB_MAX_DBS;
+@@ -403,6 +405,8 @@ int sparx5_fdma_init(struct sparx5 *spar
+ {
+ int err;
+
++ sparx5->tx.max_mtu = sparx5->data->ops->get_mtu(sparx5);
++
+ /* Reset FDMA state */
+ spx5_wr(FDMA_CTRL_NRESET_SET(0), sparx5, FDMA_CTRL);
+ spx5_wr(FDMA_CTRL_NRESET_SET(1), sparx5, FDMA_CTRL);
+@@ -504,3 +508,51 @@ int sparx5_fdma_stop(struct sparx5 *spar
+
+ return 0;
+ }
++
++int sparx5_fdma_resize(struct sparx5 *sparx5)
++{
++ u32 old_mtu = sparx5->tx.max_mtu;
++ struct fdma tx_fdma_old = {0};
++ struct fdma rx_fdma_old = {0};
++ int err;
++
++ memcpy(&tx_fdma_old, &sparx5->tx.fdma, sizeof(struct fdma));
++ memcpy(&rx_fdma_old, &sparx5->rx.fdma, sizeof(struct fdma));
++
++ sparx5_fdma_stop(sparx5);
++
++ err = sparx5_fdma_init(sparx5);
++ if (err)
++ goto restore;
++
++ fdma_free_phys(&rx_fdma_old);
++ fdma_free_phys(&tx_fdma_old);
++
++ goto start;
++
++restore:
++
++ /* At this point, the FDMA engine is stopped and the stack is not
++ * calling us for xmit. Restore the old MTU and rx,tx buffers and
++ * restart the engine.
++ */
++
++ sparx5->tx.max_mtu = old_mtu;
++ memcpy(&sparx5->tx.fdma, &tx_fdma_old, sizeof(struct fdma));
++ memcpy(&sparx5->rx.fdma, &rx_fdma_old, sizeof(struct fdma));
++
++ /* Old buffers have to be re-initialized. */
++
++ fdma_dcbs_init(&sparx5->rx.fdma,
++ FDMA_DCB_INFO_DATAL(sparx5->rx.fdma.db_size),
++ FDMA_DCB_STATUS_INTR);
++
++ fdma_dcbs_init(&sparx5->tx.fdma,
++ FDMA_DCB_INFO_DATAL(sparx5->tx.fdma.db_size),
++ FDMA_DCB_STATUS_DONE);
++
++start:
++ sparx5_fdma_start(sparx5);
++
++ return err;
++}
+--- a/drivers/net/ethernet/microchip/sparx5/sparx5_main.c
++++ b/drivers/net/ethernet/microchip/sparx5/sparx5_main.c
+@@ -1108,6 +1108,8 @@ static const struct sparx5_ops sparx5_op
+ .fdma_deinit = &sparx5_fdma_deinit,
+ .fdma_poll = &sparx5_fdma_napi_callback,
+ .fdma_xmit = &sparx5_fdma_xmit,
++ .fdma_resize = &sparx5_fdma_resize,
++ .get_mtu = &sparx5_mtu_max,
+ };
+
+ static const struct sparx5_match_data sparx5_desc = {
+--- a/drivers/net/ethernet/microchip/sparx5/sparx5_main.h
++++ b/drivers/net/ethernet/microchip/sparx5/sparx5_main.h
+@@ -472,6 +472,7 @@ int sparx5_fdma_xmit(struct sparx5 *spar
+ irqreturn_t sparx5_fdma_handler(int irq, void *args);
+ void sparx5_fdma_reload(struct sparx5 *sparx5, struct fdma *fdma);
+ void sparx5_fdma_injection_mode(struct sparx5 *sparx5);
++int sparx5_fdma_resize(struct sparx5 *sparx5);
+
+ /* sparx5_mactable.c */
+ void sparx5_mact_pull_work(struct work_struct *work);
--- /dev/null
+From b73c8d9fe87d3e35dc09faca85d5a5f9ee8e3f6c Mon Sep 17 00:00:00 2001
+From: Robert Marko <robert.marko@sartura.hr>
+Date: Tue, 24 Mar 2026 12:30:45 +0100
+Subject: [PATCH 129/130] net: lan969x: add MTU change
+
+Add the LAN969x specific code for MTU change.
+
+Signed-off-by: Robert Marko <robert.marko@sartura.hr>
+---
+ .../microchip/sparx5/lan969x/lan969x.c | 2 +
+ .../microchip/sparx5/lan969x/lan969x.h | 1 +
+ .../microchip/sparx5/lan969x/lan969x_fdma.c | 60 ++++++++++++++++++-
+ 3 files changed, 61 insertions(+), 2 deletions(-)
+
+--- a/drivers/net/ethernet/microchip/sparx5/lan969x/lan969x.c
++++ b/drivers/net/ethernet/microchip/sparx5/lan969x/lan969x.c
+@@ -354,6 +354,8 @@ static const struct sparx5_ops lan969x_o
+ .fdma_deinit = &lan969x_fdma_deinit,
+ .fdma_poll = &lan969x_fdma_napi_poll,
+ .fdma_xmit = &lan969x_fdma_xmit,
++ .fdma_resize = lan969x_fdma_resize,
++ .get_mtu = &sparx5_mtu_max,
+ };
+
+ const struct sparx5_match_data lan969x_desc = {
+--- a/drivers/net/ethernet/microchip/sparx5/lan969x/lan969x.h
++++ b/drivers/net/ethernet/microchip/sparx5/lan969x/lan969x.h
+@@ -78,5 +78,6 @@ int lan969x_fdma_deinit(struct sparx5 *s
+ int lan969x_fdma_napi_poll(struct napi_struct *napi, int weight);
+ int lan969x_fdma_xmit(struct sparx5 *sparx5, u32 *ifh, struct sk_buff *skb,
+ struct net_device *dev);
++int lan969x_fdma_resize(struct sparx5 *sparx5);
+
+ #endif
+--- a/drivers/net/ethernet/microchip/sparx5/lan969x/lan969x_fdma.c
++++ b/drivers/net/ethernet/microchip/sparx5/lan969x/lan969x_fdma.c
+@@ -154,7 +154,7 @@ static int lan969x_fdma_rx_alloc(struct
+ int err;
+
+ struct page_pool_params pp_params = {
+- .order = 0,
++ .order = rx->page_order,
+ .flags = PP_FLAG_DMA_MAP | PP_FLAG_DMA_SYNC_DEV,
+ .pool_size = fdma->n_dcbs * fdma->n_dbs,
+ .nid = NUMA_NO_NODE,
+@@ -209,12 +209,14 @@ static void lan969x_fdma_rx_init(struct
+ {
+ struct fdma *fdma = &sparx5->rx.fdma;
+
++ sparx5->rx.page_order =
++ round_up(sparx5->tx.max_mtu, PAGE_SIZE) / PAGE_SIZE - 1;
+ fdma->channel_id = FDMA_XTR_CHANNEL;
+ fdma->n_dcbs = FDMA_DCB_MAX;
+ fdma->n_dbs = 1;
+ fdma->priv = sparx5;
+ fdma->size = fdma_get_size(fdma);
+- fdma->db_size = PAGE_SIZE;
++ fdma->db_size = PAGE_SIZE << sparx5->rx.page_order;
+ fdma->ops.dataptr_cb = &lan969x_fdma_rx_dataptr_cb;
+ fdma->ops.nextptr_cb = &fdma_nextptr_cb;
+
+@@ -359,6 +361,8 @@ int lan969x_fdma_init(struct sparx5 *spa
+ struct sparx5_rx *rx = &sparx5->rx;
+ int err;
+
++ sparx5->tx.max_mtu = sparx5->data->ops->get_mtu(sparx5);
++
+ lan969x_fdma_rx_init(sparx5);
+ lan969x_fdma_tx_init(sparx5);
+ sparx5_fdma_injection_mode(sparx5);
+@@ -404,3 +408,55 @@ int lan969x_fdma_deinit(struct sparx5 *s
+
+ return 0;
+ }
++
++int lan969x_fdma_resize(struct sparx5 *sparx5)
++{
++ struct page_pool *page_pool_old = sparx5->rx.page_pool;
++ u32 old_mtu = sparx5->tx.max_mtu;
++ struct fdma tx_fdma_old = {0};
++ struct fdma rx_fdma_old = {0};
++ int err;
++
++ memcpy(&tx_fdma_old, &sparx5->tx.fdma, sizeof(struct fdma));
++ memcpy(&rx_fdma_old, &sparx5->rx.fdma, sizeof(struct fdma));
++
++ sparx5_fdma_stop(sparx5);
++ lan969x_fdma_free_pages(&sparx5->rx);
++
++ err = lan969x_fdma_init(sparx5);
++ if (err)
++ goto restore;
++
++ fdma_free_coherent(sparx5->dev, &rx_fdma_old);
++ fdma_free_coherent(sparx5->dev, &tx_fdma_old);
++ page_pool_destroy(page_pool_old);
++
++ goto start;
++
++restore:
++
++ /* At this point, the FDMA engine is stopped and the stack is not
++ * calling us for xmit. Restore the old MTU and rx,tx buffers and
++ * restart the engine.
++ */
++
++ sparx5->tx.max_mtu = old_mtu;
++ sparx5->rx.page_pool = page_pool_old;
++ memcpy(&sparx5->tx.fdma, &tx_fdma_old, sizeof(struct fdma));
++ memcpy(&sparx5->rx.fdma, &rx_fdma_old, sizeof(struct fdma));
++
++ /* Old buffers have to be re-initialized. */
++
++ fdma_dcbs_init(&sparx5->rx.fdma,
++ FDMA_DCB_INFO_DATAL(sparx5->rx.fdma.db_size),
++ FDMA_DCB_STATUS_INTR);
++
++ fdma_dcbs_init(&sparx5->tx.fdma,
++ FDMA_DCB_INFO_DATAL(sparx5->tx.fdma.db_size),
++ FDMA_DCB_STATUS_DONE);
++
++start:
++ sparx5_fdma_start(sparx5);
++
++ return err;
++}
--- /dev/null
+From aa92b8a004be460d68aa671c3f8e98373496b199 Mon Sep 17 00:00:00 2001
+From: Robert Marko <robert.marko@sartura.hr>
+Date: Tue, 24 Mar 2026 12:32:39 +0100
+Subject: [PATCH 130/130] net: sparx5: wire in MTU change
+
+Now that both generic and chip specific MTU code is in place, add the
+required netdev OP to trigger the MTU change.
+
+Signed-off-by: Robert Marko <robert.marko@sartura.hr>
+---
+ drivers/net/ethernet/microchip/sparx5/sparx5_netdev.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/drivers/net/ethernet/microchip/sparx5/sparx5_netdev.c
++++ b/drivers/net/ethernet/microchip/sparx5/sparx5_netdev.c
+@@ -259,6 +259,7 @@ static const struct net_device_ops sparx
+ .ndo_setup_tc = sparx5_port_setup_tc,
+ .ndo_hwtstamp_get = sparx5_port_hwtstamp_get,
+ .ndo_hwtstamp_set = sparx5_port_hwtstamp_set,
++ .ndo_change_mtu = sparx5_mtu_change,
+ };
+
+ bool sparx5_netdevice_check(const struct net_device *dev)
+@@ -279,6 +280,9 @@ struct net_device *sparx5_create_netdev(
+ ndev->hw_features |= NETIF_F_HW_TC;
+ ndev->features |= NETIF_F_HW_TC;
+
++ /* The MAC supports frame lengths of up to 14,000 bytes */
++ ndev->max_mtu = 14000;
++
+ SET_NETDEV_DEV(ndev, sparx5->dev);
+ spx5_port = netdev_priv(ndev);
+ spx5_port->ndev = ndev;