]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
net: stmmac: eswin: validate RGMII delay values
authorZhi Li <lizhi2@eswincomputing.com>
Mon, 18 May 2026 02:22:13 +0000 (10:22 +0800)
committerPaolo Abeni <pabeni@redhat.com>
Thu, 21 May 2026 09:58:17 +0000 (11:58 +0200)
Validate rx-internal-delay-ps and tx-internal-delay-ps against the
hardware capabilities of the EIC7700 MAC.

The programmable RGMII delay supports 20 ps steps and a maximum value of
2540 ps. The driver previously accepted arbitrary values and silently
truncated unsupported settings when converting them to hardware units.

As a result, invalid device tree values could lead to unexpected delay
programming and incorrect RGMII timing.

Reject delay values that are not multiples of 20 ps or exceed the
supported hardware range.

Fixes: ea77dbbdbc4e ("net: stmmac: add Eswin EIC7700 glue driver")
Signed-off-by: Zhi Li <lizhi2@eswincomputing.com>
Link: https://patch.msgid.link/20260518022214.507-1-lizhi2@eswincomputing.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
drivers/net/ethernet/stmicro/stmmac/dwmac-eic7700.c

index ef60cab24533e24cfe90c788d6c3342bf749db9b..4ac979d874d6edc4ac9c715e4cc43e6972b067f3 100644 (file)
 #define EIC7700_ETH_TX_ADJ_DELAY       GENMASK(14, 8)
 #define EIC7700_ETH_RX_ADJ_DELAY       GENMASK(30, 24)
 
-#define EIC7700_MAX_DELAY_UNIT 0x7F
+#define EIC7700_MAX_DELAY_STEPS                0x7F
+#define EIC7700_DELAY_STEP_PS          20
+#define EIC7700_MAX_DELAY_PS   \
+       (EIC7700_MAX_DELAY_STEPS * EIC7700_DELAY_STEP_PS)
 
 static const char * const eic7700_clk_names[] = {
        "tx", "axi", "cfg",
@@ -128,7 +131,7 @@ static int eic7700_dwmac_probe(struct platform_device *pdev)
        struct plat_stmmacenet_data *plat_dat;
        struct stmmac_resources stmmac_res;
        struct eic7700_qos_priv *dwc_priv;
-       u32 delay_ps;
+       u32 delay_ps, val;
        int i, ret;
 
        ret = stmmac_get_platform_resources(pdev, &stmmac_res);
@@ -148,7 +151,16 @@ static int eic7700_dwmac_probe(struct platform_device *pdev)
        /* Read rx-internal-delay-ps and update rx_clk delay */
        if (!of_property_read_u32(pdev->dev.of_node,
                                  "rx-internal-delay-ps", &delay_ps)) {
-               u32 val = min(delay_ps / 20, EIC7700_MAX_DELAY_UNIT);
+               if (delay_ps % EIC7700_DELAY_STEP_PS)
+                       return dev_err_probe(&pdev->dev, -EINVAL,
+                               "rx delay must be multiple of %dps\n",
+                               EIC7700_DELAY_STEP_PS);
+
+               if (delay_ps > EIC7700_MAX_DELAY_PS)
+                       return dev_err_probe(&pdev->dev, -EINVAL,
+                               "rx delay out of range\n");
+
+               val = delay_ps / EIC7700_DELAY_STEP_PS;
 
                dwc_priv->eth_clk_dly_param &= ~EIC7700_ETH_RX_ADJ_DELAY;
                dwc_priv->eth_clk_dly_param |=
@@ -161,7 +173,16 @@ static int eic7700_dwmac_probe(struct platform_device *pdev)
        /* Read tx-internal-delay-ps and update tx_clk delay */
        if (!of_property_read_u32(pdev->dev.of_node,
                                  "tx-internal-delay-ps", &delay_ps)) {
-               u32 val = min(delay_ps / 20, EIC7700_MAX_DELAY_UNIT);
+               if (delay_ps % EIC7700_DELAY_STEP_PS)
+                       return dev_err_probe(&pdev->dev, -EINVAL,
+                               "tx delay must be multiple of %dps\n",
+                               EIC7700_DELAY_STEP_PS);
+
+               if (delay_ps > EIC7700_MAX_DELAY_PS)
+                       return dev_err_probe(&pdev->dev, -EINVAL,
+                               "tx delay out of range\n");
+
+               val = delay_ps / EIC7700_DELAY_STEP_PS;
 
                dwc_priv->eth_clk_dly_param &= ~EIC7700_ETH_TX_ADJ_DELAY;
                dwc_priv->eth_clk_dly_param |=