diff options
| author | Serge Semin <fancer.lancer@gmail.com> | 2025-08-14 16:04:45 +0300 |
|---|---|---|
| committer | Serge Semin <fancer.lancer@gmail.com> | 2026-08-13 20:33:45 +0300 |
| commit | 3ff969f9872138167716828c9e992504621a3414 (patch) | |
| tree | 1dc72eb78690e3e1ff767b020a03237f2480d018 | |
| parent | 7dcefeeb505d48a34ca44db31d131c9dc5685a2b (diff) | |
| download | linux-3ff969f9872138167716828c9e992504621a3414.tar.gz linux-3ff969f9872138167716828c9e992504621a3414.zip | |
net: stmmac: dwxgmac2: Detect and handle Jumbo frames
The driver currently always enables the Jumbo frames up to 16K bytes to
receive and transmit. It's done by setting the MAC_TX_CONFIG.JD flag and
initializing the MAC_RX_CONFIG.GPSL field with the 16K frame size.
Basically it means the driver completely ignores the MTU settings despite
of what was said in the commit 8a488c3f97cd ("net: stmmac: xgmac: Enable
RX Jumbo frame support").
It isn't right to disregard the MTU setting since the MTU value might be
an important parameter of an Ethernet network segment. Moreover based on
what is said in [1] the most preferred way to support MTU would be to drop
the oversized frames instead of passing them up to the networking core
subsystem. It's also important to note that even though [1] says that the
upper layer protocols must not pass a socket buffer (skb) to a device to
transmit with more data than the MTU in fact it does at least in case of
the pktgen module.
So currently the driver doesn't fulfill these requirements and
passes/transfers the incoming/outcoming frames further ignoring the MTU
value. Let's fix that by activating the Giant frame setting and by setting
the internal watchdog up to drop the incoming frames which size is greater
then MTU and truncate the outgoing oversized frames with size threshold
2048/16383. Thus the behaviour will get to be closer to what is already
implemented for DW GMACs (except a more accurate Giant frame setting and
one truncation threshold less of the Tx frames) and follow the networking
subsystem recommendations. This shall significantly speed up the oversized
frames handling.
Note the driver currently just drops the frames with over Giant frame size
so the describes recv truncation seems unnecessary. But it will be
utilized in the NETIF_F_RXALL feature implementation.
[1] Documentation/networking/netdevices.rst
Fixes: 8a488c3f97cd ("net: stmmac: xgmac: Enable RX Jumbo frame support")
Fixes: 2142754f8b9c ("net: stmmac: Add MAC related callbacks for XGMAC2")
Signed-off-by: Serge Semin <fancer.lancer@gmail.com>
| -rw-r--r-- | drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h | 8 | ||||
| -rw-r--r-- | drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c | 36 |
2 files changed, 36 insertions, 8 deletions
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h index 6391e3d46c8d6..65d28dca41851 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h +++ b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2.h @@ -26,7 +26,6 @@ #define XGMAC_CONFIG_SARC GENMASK(22, 20) #define XGMAC_CONFIG_JD BIT(16) #define XGMAC_CONFIG_TE BIT(0) -#define XGMAC_CORE_INIT_TX (XGMAC_CONFIG_JD) #define XGMAC_RX_CONFIG 0x00000004 #define XGMAC_CONFIG_ARPEN BIT(31) #define XGMAC_CONFIG_GPSL GENMASK(29, 16) @@ -42,10 +41,6 @@ #define XGMAC_CONFIG_CST BIT(2) #define XGMAC_CONFIG_ACS BIT(1) #define XGMAC_CONFIG_RE BIT(0) -#define XGMAC_CORE_INIT_RX (XGMAC_CONFIG_GPSLCE | \ - XGMAC_CONFIG_WD | \ - FIELD_PREP(XGMAC_CONFIG_GPSL, \ - XGMAC_JUMBO_LEN)) #define XGMAC_PACKET_FILTER 0x00000008 #define XGMAC_FILTER_RA BIT(31) #define XGMAC_FILTER_IPFE BIT(20) @@ -55,6 +50,9 @@ #define XGMAC_FILTER_PM BIT(4) #define XGMAC_FILTER_HMC BIT(2) #define XGMAC_FILTER_PR BIT(0) +#define XGMAC_WDT 0x0000000c +#define XGMAC_WDT_PWE BIT(8) +#define XGMAC_WDT_WTO GENMASK(3, 0) #define XGMAC_HASH_TABLE(x) (0x00000010 + (x) * 4) #define XGMAC_MAX_HASH_TABLE 8 #define XGMAC_RXQ_CTRL0 0x000000a0 diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c index 13093b7defc58..c4458b622de97 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c @@ -18,13 +18,43 @@ static void dwxgmac2_core_init(struct mac_device_info *hw, struct net_device *dev) { void __iomem *ioaddr = hw->pcsr; - u32 tx, rx; + int mtu = dev->mtu; + u32 tx, rx, gps; tx = readl(ioaddr + XGMAC_TX_CONFIG); rx = readl(ioaddr + XGMAC_RX_CONFIG); - writel(tx | XGMAC_CORE_INIT_TX, ioaddr + XGMAC_TX_CONFIG); - writel(rx | XGMAC_CORE_INIT_RX, ioaddr + XGMAC_RX_CONFIG); + /* Frame length limits (giant status reported or dropped) */ + gps = ETH_HLEN + ETH_FCS_LEN; + if (mtu > 16357) { /* Rx <= 16375 (+C/SVLAN headers) && Tx <= 16383 */ + tx |= XGMAC_CONFIG_JD; + gps += 16357; + rx |= XGMAC_CONFIG_GPSLCE | FIELD_PREP(XGMAC_CONFIG_GPSL, gps); + } else if (mtu > 2022) { /* Rx <= MTU + Eth (+C/SVLAN headers) && Tx <= 16383 */ + tx |= XGMAC_CONFIG_JD; + gps += mtu; + rx |= XGMAC_CONFIG_GPSLCE | FIELD_PREP(XGMAC_CONFIG_GPSL, gps); + } else if (mtu > 1500) { /* Rx <= MTU + Eth (+C/SVLAN headers) && Tx <= 2048 */ + gps += mtu; + rx |= XGMAC_CONFIG_GPSLCE | FIELD_PREP(XGMAC_CONFIG_GPSL, gps); + } else { /* Rx <= 1500 + Eth (+C/SVLAN headers) && Tx <= 2048 */ + gps += 1500; + } + + writel(tx, ioaddr + XGMAC_TX_CONFIG); + writel(rx, ioaddr + XGMAC_RX_CONFIG); + + /* Over 2K, 3K, ..., 16K-1 frames will be truncated on Rx */ + gps = ALIGN(gps + 2 * VLAN_HLEN, SZ_1K); + if (gps >= SZ_2K) + gps = gps / SZ_1K - 2; + else + gps = 0; + + /* Over giant frame watchdog fine-tuning (available since v2.00a) */ + rx = FIELD_PREP(XGMAC_WDT_WTO, gps) | XGMAC_WDT_PWE; + writel(rx, ioaddr + XGMAC_WDT); + writel(XGMAC_INT_DEFAULT_EN, ioaddr + XGMAC_INT_EN); } |
