diff options
| author | Serge Semin <fancer.lancer@gmail.com> | 2025-08-25 20:30:10 +0300 |
|---|---|---|
| committer | Serge Semin <fancer.lancer@gmail.com> | 2026-08-13 20:33:46 +0300 |
| commit | e43ea4fb081a9595a2dd4a7c708637a87f61d2b1 (patch) | |
| tree | 0f4c189afe501b4b9f215ec99f8a02b452f36833 | |
| parent | de1c106ece101ececceaef06b13a848283309cdb (diff) | |
| download | linux-e43ea4fb081a9595a2dd4a7c708637a87f61d2b1.tar.gz linux-e43ea4fb081a9595a2dd4a7c708637a87f61d2b1.zip | |
net: stmmac: Fix improper max MTU value setup
Currently the driver initialize the maximum MTU value as follows:
1. DW XGMAC/XLGMAC: 16KiB
2. DW GMAC with Enhanced DMA-descriptors and DW QoS Ether: 9000 bytes
3. DW MAX100 and DW GMAC with Normal DMA-descriptors: PAGE_SIZE.
This is wrong in the aspects 2. and 3. Here is why. First of all DW QoS
Ether have always supported Tx and Rx up to 16KiB frames size in the same
way as DW XGMAC-like devices. The latest Jumbo-related commit has enabled
that in the driver too. Secondly no matter what type of the DMA-descriptor
selected DMA GMACs have always supported up to 9K frames at least in the
cross-descriptor manner. Thirdly the legacy DW MAC100 controllers have
never been able to xmit/recv frames greater than 1500 bytes. There is no
any Jumbo-like setup in the MAC config registers. It has been even more
wrong to use SKB_MAX_HEAD() macro to calculate max MTU constraint since
it's basically converted to PAGE_SIZE which is platform-specific, can be
even greater than 16KiB and doesn't determine the actual MTU constraint
applicable for the particular DW network controller. Finally the MTU
verification procedure isn't complete in the net_device:ndo_change_mtu()
method. The upper-limit is specific to the DW XGMACs only (and actually
redundant). Moreover the Tx FIFO size-based constraint is also incorrect -
it isn't enough to set up the upper MTU-limit based on the Tx-FIFO size
(but it will be fixed later).
Let's fix all of the inconsistencies above by activating the 16KiB Jumbos
for DW QoS Ethernet, setting up 9000 max MTU for any DW GMAC, getting
back the normal max MTU for the legacy controllers and dropping the manual
max MTU verification in the net_device:ndo_change_mtu() method.
Fixes: eaf4fac47807 ("net: stmmac: Do not accept invalid MTU values")
Fixes: f748be531d70 ("stmmac: support new GMAC4")
Fixes: 45db81e1590c ("stmmac: limit max_mtu in case of 4KiB and use __netdev_alloc_skb (V2)")
Fixes: 48febf7e6476 ("stmmac: allow mtu bigger than 1500 in case of normal desc (V4)")
Signed-off-by: Serge Semin <fancer.lancer@gmail.com>
| -rw-r--r-- | drivers/net/ethernet/stmicro/stmmac/common.h | 7 | ||||
| -rw-r--r-- | drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h | 3 | ||||
| -rw-r--r-- | drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 61 |
3 files changed, 46 insertions, 25 deletions
diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h b/drivers/net/ethernet/stmicro/stmmac/common.h index 95faae938b04..7b86414006d1 100644 --- a/drivers/net/ethernet/stmicro/stmmac/common.h +++ b/drivers/net/ethernet/stmicro/stmmac/common.h @@ -575,7 +575,12 @@ void stmmac_axi_blen_to_mask(u32 *regval, const u32 *blen, size_t len); #define STMMAC_CHAIN_MODE 0x1 #define STMMAC_RING_MODE 0x2 -#define JUMBO_LEN 9000 +/* MAC MTU constraint */ +#define STMMAC_MTU_GIANT (SZ_16K - ETH_HLEN - 2*VLAN_HLEN - ETH_FCS_LEN - 1) +#define STMMAC_MTU_JUMBO 9000 +#define STMMAC_MTU_NORMAL ETH_DATA_LEN +#define XGMAC_JUMBO_LEN STMMAC_MTU_GIANT +#define JUMBO_LEN STMMAC_MTU_JUMBO /* Receive Side Scaling */ #define STMMAC_RSS_HASH_KEY_SIZE 40 diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h index 65d28dca4185..1798289ef6ab 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h +++ b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h @@ -9,9 +9,6 @@ #include "common.h" -/* Misc */ -#define XGMAC_JUMBO_LEN 16368 - /* MAC Registers */ #define XGMAC_TX_CONFIG 0x00000000 #define XGMAC_CONFIG_SS_OFF 29 diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 7cacc3aa6b39..94b05994fe53 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -1552,6 +1552,43 @@ static void stmmac_display_rings(struct stmmac_priv *priv, } /** + * stmmac_get_min_mtu - retrieve minimal supported MTU + * @priv: driver private structure + * Return: minimal MTU. + */ +static unsigned int stmmac_get_min_mtu(struct stmmac_priv *priv) +{ + return ETH_ZLEN - ETH_HLEN; +} + +/** + * stmmac_get_max_mtu - retrieve maximal supported MTU + * @priv: driver private structure + * Description: calculate the maximum MTU supported by DW controller in + * accordance with the device active features. + * Return: maximum MTU. + */ +static unsigned int stmmac_get_max_mtu(struct stmmac_priv *priv) +{ + unsigned int max_mtu; + + /* MTU constraint caused by the MAC implementation */ + if (dwmac_is_xmac(priv->plat->core_type)) + max_mtu = STMMAC_MTU_GIANT; + else if (priv->plat->core_type == DWMAC_CORE_GMAC) + max_mtu = STMMAC_MTU_JUMBO; + else + max_mtu = STMMAC_MTU_NORMAL; + + /* Override only with valid platform-specific max MTU constraint */ + if (priv->plat->maxmtu >= stmmac_get_min_mtu(priv) && + priv->plat->maxmtu < max_mtu) + max_mtu = priv->plat->maxmtu; + + return max_mtu; +} + +/** * stmmac_fs_offset - find out platform-specific frame offset * Description: retrieve Rx DMA-buffer offset to align up the incoming * frames within the IP-header. @@ -6260,8 +6297,7 @@ static int stmmac_change_mtu(struct net_device *dev, int new_mtu) return -EINVAL; } - /* If condition true, FIFO is too small or MTU too large */ - if ((txfifosz < new_mtu) || (new_mtu > XGMAC_JUMBO_LEN)) + if (new_mtu > txfifosz) return -EINVAL; if (netif_running(dev)) { @@ -8510,25 +8546,8 @@ static int __stmmac_dvr_probe(struct device *device, ndev->vlan_features |= ndev->features; - /* MTU range: 46 - hw-specific max */ - ndev->min_mtu = ETH_ZLEN - ETH_HLEN; - - if (priv->plat->core_type == DWMAC_CORE_XGMAC) - ndev->max_mtu = XGMAC_JUMBO_LEN; - else if (priv->plat->enh_desc || priv->synopsys_id >= DWMAC_CORE_4_00) - ndev->max_mtu = JUMBO_LEN; - else - ndev->max_mtu = SKB_MAX_HEAD(NET_SKB_PAD + NET_IP_ALIGN); - - /* Warn if the platform's maxmtu is smaller than the minimum MTU, - * otherwise clamp the maximum MTU above to the platform's maxmtu. - */ - if (priv->plat->maxmtu < ndev->min_mtu) - dev_warn(priv->device, - "%s: warning: maxmtu having invalid value (%d)\n", - __func__, priv->plat->maxmtu); - else if (priv->plat->maxmtu < ndev->max_mtu) - ndev->max_mtu = priv->plat->maxmtu; + ndev->min_mtu = stmmac_get_min_mtu(priv); + ndev->max_mtu = stmmac_get_max_mtu(priv); ndev->priv_flags |= IFF_LIVE_ADDR_CHANGE; |
