summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSerge Semin <fancer.lancer@gmail.com>2025-08-14 17:01:31 +0300
committerSerge Semin <fancer.lancer@gmail.com>2026-08-13 20:33:45 +0300
commit2e99f6b0a728cf0ff2be3140352d24b0f7b3bc94 (patch)
tree91cc1866b175bae9fb167de103a09465699f942d
parent3ff969f9872138167716828c9e992504621a3414 (diff)
downloadlinux-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.h12
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c37
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);