]> git.ipfire.org Git - thirdparty/openwrt.git/commitdiff
microchipsw: add MTU change support 22590/head
authorRobert Marko <robert.marko@sartura.hr>
Tue, 24 Mar 2026 17:42:52 +0000 (18:42 +0100)
committerRobert Marko <robert.marko@sartura.hr>
Tue, 24 Mar 2026 17:42:52 +0000 (18:42 +0100)
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>
target/linux/microchipsw/patches-6.12/126-net-lan969x-correct-RGMII-port-mapping-index.patch [new file with mode: 0644]
target/linux/microchipsw/patches-6.12/127-net-sparx5-add-MTU-change-framework.patch [new file with mode: 0644]
target/linux/microchipsw/patches-6.12/128-net-sparx5-add-MTU-change.patch [new file with mode: 0644]
target/linux/microchipsw/patches-6.12/129-net-lan969x-add-MTU-change.patch [new file with mode: 0644]
target/linux/microchipsw/patches-6.12/130-net-sparx5-wire-in-MTU-change.patch [new file with mode: 0644]

diff --git a/target/linux/microchipsw/patches-6.12/126-net-lan969x-correct-RGMII-port-mapping-index.patch b/target/linux/microchipsw/patches-6.12/126-net-lan969x-correct-RGMII-port-mapping-index.patch
new file mode 100644 (file)
index 0000000..b8aef7e
--- /dev/null
@@ -0,0 +1,37 @@
+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:
diff --git a/target/linux/microchipsw/patches-6.12/127-net-sparx5-add-MTU-change-framework.patch b/target/linux/microchipsw/patches-6.12/127-net-sparx5-add-MTU-change-framework.patch
new file mode 100644 (file)
index 0000000..874ac56
--- /dev/null
@@ -0,0 +1,264 @@
+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;
++}
diff --git a/target/linux/microchipsw/patches-6.12/128-net-sparx5-add-MTU-change.patch b/target/linux/microchipsw/patches-6.12/128-net-sparx5-add-MTU-change.patch
new file mode 100644 (file)
index 0000000..d628ac8
--- /dev/null
@@ -0,0 +1,107 @@
+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);
diff --git a/target/linux/microchipsw/patches-6.12/129-net-lan969x-add-MTU-change.patch b/target/linux/microchipsw/patches-6.12/129-net-lan969x-add-MTU-change.patch
new file mode 100644 (file)
index 0000000..ef89cac
--- /dev/null
@@ -0,0 +1,126 @@
+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;
++}
diff --git a/target/linux/microchipsw/patches-6.12/130-net-sparx5-wire-in-MTU-change.patch b/target/linux/microchipsw/patches-6.12/130-net-sparx5-wire-in-MTU-change.patch
new file mode 100644 (file)
index 0000000..678b601
--- /dev/null
@@ -0,0 +1,33 @@
+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;