diff options
| author | Serge Semin <fancer.lancer@gmail.com> | 2025-08-14 17:01:31 +0300 |
|---|---|---|
| committer | Serge Semin <fancer.lancer@gmail.com> | 2026-08-13 20:33:45 +0300 |
| commit | 2e99f6b0a728cf0ff2be3140352d24b0f7b3bc94 (patch) | |
| tree | 91cc1866b175bae9fb167de103a09465699f942d | |
| parent | 3ff969f9872138167716828c9e992504621a3414 (diff) | |
| download | linux-2e99f6b0a728cf0ff2be3140352d24b0f7b3bc94.tar.gz linux-2e99f6b0a728cf0ff2be3140352d24b0f7b3bc94.zip | |
net: stmmac: dwmac4: Detect and handle Jumbo frames
Similarly to what has been relevant for DW XGMAC the driver currently
always enable the Jumbo frames up to 16K bytes to receive and transmit for
DW QoS Ether too (DW GMAC4). It's done by permanently setting the
MAC_CONFIG.JD and MAC_CONFIG.JE flags. Basically it means the driver
completely ignores the MTU settings permitting up to 16K outgoing frames
and no greater than 9K incoming frames.
It isn't right to disregard the MTU setting especially such asymmetrically
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.
The driver currently 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 2048/16383-octets oversized frames.
Thus the behaviour will match to what is already implemented for DW
GMACs/XGMACs 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.
Also note since this change the driver will support DW QoS Ether
controller to send/receive frames up to MTU=16K. The net_device::max_mtu
parameter will be accordingly fixed a bit later.
[1] Documentation/networking/netdevices.rst
Fixes: 41f2a3e6367e ("net: stmmac: dwmac4: Enable RX Jumbo frame support")
Fixes: 477286b53f55 ("stmmac: add GMAC4 core support")
Signed-off-by: Serge Semin <fancer.lancer@gmail.com>
| -rw-r--r-- | drivers/net/ethernet/stmicro/stmmac/dwmac4.h | 12 | ||||
| -rw-r--r-- | drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c | 37 |
2 files changed, 44 insertions, 5 deletions
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4.h b/drivers/net/ethernet/stmicro/stmmac/dwmac4.h index e58194fd0c0b..53ac45b50e22 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac4.h +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4.h @@ -16,6 +16,7 @@ #define GMAC_CONFIG 0x00000000 #define GMAC_EXT_CONFIG 0x00000004 #define GMAC_PACKET_FILTER 0x00000008 +#define GMAC_WDT 0x0000000c #define GMAC_HASH_TAB(x) (0x10 + (x) * 4) #define GMAC_RX_FLOW_CTRL 0x00000090 #define GMAC_QX_TX_FLOW_CTRL(x) (0x70 + x * 4) @@ -77,6 +78,10 @@ #define GMAC_MAX_PERFECT_ADDRESSES 128 +/* MAC Watchdog timeout for received frames */ +#define GMAC_WDT_PWE BIT(8) +#define GMAC_WDT_WTO GENMASK(3, 0) + /* MAC RX Queue Enable */ #define GMAC_RX_QUEUE_CLEAR(queue) ~(GENMASK(1, 0) << ((queue) * 2)) #define GMAC_RX_AV_QUEUE_ENABLE(queue) BIT((queue) * 2) @@ -155,9 +160,11 @@ enum power_event { #define GMAC_CONFIG_SARC GENMASK(30, 28) #define GMAC_CONFIG_IPC BIT(27) #define GMAC_CONFIG_IPG GENMASK(26, 24) +#define GMAC_CONFIG_GPSLCE BIT(23) #define GMAC_CONFIG_2K BIT(22) #define GMAC_CONFIG_CST BIT(21) #define GMAC_CONFIG_ACS BIT(20) +#define GMAC_CONFIG_WD BIT(19) #define GMAC_CONFIG_BE BIT(18) #define GMAC_CONFIG_JD BIT(17) #define GMAC_CONFIG_JE BIT(16) @@ -174,6 +181,7 @@ enum power_event { #define GMAC_CONFIG_EIPG_EN BIT(24) #define GMAC_CONFIG_HDSMS GENMASK(22, 20) #define GMAC_CONFIG_HDSMS_256 FIELD_PREP_CONST(GMAC_CONFIG_HDSMS, 0x2) +#define GMAC_CONFIG_GPSL GENMASK(13, 0) /* MAC HW features0 bitmap */ #define GMAC_HW_FEAT_SAVLANINS BIT(27) @@ -472,9 +480,7 @@ static inline u32 mtl_low_credx_base_addr(const struct dwmac4_addrs *addrs, #define MTL_INT_DEFAULT_ENABLE (MTL_RX_OVERFLOW_INT | MTL_TX_UNDERFLOW_INT) /* Default operating mode of the MAC */ -#define GMAC_CORE_INIT (GMAC_CONFIG_JD | GMAC_CONFIG_PS | \ - GMAC_CONFIG_BE | GMAC_CONFIG_DCRS | \ - GMAC_CONFIG_JE) +#define GMAC_CORE_INIT (GMAC_CONFIG_PS | GMAC_CONFIG_BE | GMAC_CONFIG_DCRS) /* To dump the core regs excluding the Address Registers */ #define GMAC_REG_NUM 132 diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c index 9f53a79aa70c..4d07f421e7af 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c @@ -37,10 +37,43 @@ static void dwmac4_core_init(struct mac_device_info *hw, struct stmmac_priv *priv = netdev_priv(dev); void __iomem *ioaddr = hw->pcsr; unsigned long clk_rate; - u32 value; + int mtu = dev->mtu; + u32 value, gps; value = readl(ioaddr + GMAC_CONFIG); - writel(value | GMAC_CORE_INIT, ioaddr + GMAC_CONFIG); + value |= GMAC_CORE_INIT; + + /* Frame length limits (giant status reported or dropped) */ + gps = ETH_HLEN + ETH_FCS_LEN; + if (mtu > 16357) { /* Rx <= 16375 (+C/SVLAN headers) && Tx <= 16383 */ + gps += 16357; + value |= GMAC_CONFIG_GPSLCE | GMAC_CONFIG_JD; + } else if (mtu > 2022) { /* Rx <= MTU + Eth (+C/SVLAN headers) && Tx <= 16383 */ + gps += mtu; + value |= GMAC_CONFIG_GPSLCE | GMAC_CONFIG_JD; + } else if (mtu > 1500) { /* Rx <= MTU + Eth (+C/SVLAN headers) && Tx <= 2048 */ + gps += mtu; + value |= GMAC_CONFIG_GPSLCE; + } else { /* Rx <= 1500 + Eth (+C/SVLAN headers) && Tx <= 2048 */ + gps = 1500 + ETH_HLEN + ETH_FCS_LEN; + } + + writel(value, ioaddr + GMAC_CONFIG); + + value = readl(ioaddr + GMAC_EXT_CONFIG); + value |= FIELD_PREP(GMAC_CONFIG_GPSL, gps); + writel(value, ioaddr + GMAC_EXT_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 */ + value = FIELD_PREP(GMAC_WDT_WTO, gps) | GMAC_WDT_PWE; + writel(value, ioaddr + GMAC_WDT); /* Configure LPI 1us counter to number of CSR clock ticks in 1us - 1 */ clk_rate = clk_get_rate(priv->plat->stmmac_clk); |
