[PATCH net 2/6] net: stmmac: selftests: Validate EEE based on the actual LPI timer value

From: Maxime Chevallier

Date: Wed Sep 09 2026 - 03:55:13 EST


The EEE selftest is a 2-step test :
- It validates that we enter in LPI mode with the
irq_tx_path_in_lpi_mode_n counter
- It then validates that we exit LPI when sending a frame, with the
irq_tx_path_exit_lpi_mode_n counter.

The current state of the test lacks 2 main things :

- We don't know exactly when was the previous frame sent (it's from the
previous selftest)

- The timeout is hardcoded, while the LPI is entered after a
user-configurable delay. On top of that, the timeout loop uses a
pre-decrement iterator (--retries) that actually only iterate nine
times, so 900ms while the default LPI value is 1 second.

Let's therefore make it more deterministic :

- Send a frame at the beginning of the test
- Wait for more than the lpi timer value, we timeout after about twice
the value,
- Then send another frame, and verify that we do go out of LPI, also
with a timeout.

Note that the test's goal isn't to validate the LPI timer value itself,
only that we enter/leave LPI mode.

Fixes: 091810dbded9 ("net: stmmac: Introduce selftests support")
Signed-off-by: Maxime Chevallier <maxime.chevallier@xxxxxxxxxxx>
---
.../stmicro/stmmac/stmmac_selftests.c | 33 ++++++++++++++-----
1 file changed, 25 insertions(+), 8 deletions(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_selftests.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_selftests.c
index 6503678b646e..4564b9f29194 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_selftests.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_selftests.c
@@ -462,7 +462,7 @@ static int stmmac_test_mmc(struct stmmac_priv *priv)
static int stmmac_test_eee(struct stmmac_priv *priv)
{
struct stmmac_extra_stats *initial, *final;
- int retries = 10;
+ unsigned long timeout, max_duration;
int ret;

if (!priv->dma_cap.eee || !priv->eee_active)
@@ -478,14 +478,18 @@ static int stmmac_test_eee(struct stmmac_priv *priv)
goto out_free_initial;
}

- memcpy(initial, &priv->xstats, sizeof(*initial));
-
+ /* Send a frame, then wait to enter LPI */
ret = stmmac_test_mac_loopback(priv);
if (ret)
goto out_free_final;

+ max_duration = usecs_to_jiffies(2 * priv->tx_lpi_timer);
+
+ memcpy(initial, &priv->xstats, sizeof(*initial));
+
/* We have no traffic in the line so, sooner or later it will go LPI */
- while (--retries) {
+ timeout = jiffies + max_duration;
+ while (!time_after(jiffies, timeout)) {
memcpy(final, &priv->xstats, sizeof(*final));

if (final->irq_tx_path_in_lpi_mode_n >
@@ -494,17 +498,30 @@ static int stmmac_test_eee(struct stmmac_priv *priv)
msleep(100);
}

- if (!retries) {
+ memcpy(final, &priv->xstats, sizeof(*final));
+ if (final->irq_tx_path_in_lpi_mode_n <=
+ initial->irq_tx_path_in_lpi_mode_n) {
ret = -ETIMEDOUT;
goto out_free_final;
}

- if (final->irq_tx_path_in_lpi_mode_n <=
- initial->irq_tx_path_in_lpi_mode_n) {
- ret = -EINVAL;
+ /* TX something so we go out of LPI */
+ ret = stmmac_test_mac_loopback(priv);
+ if (ret)
goto out_free_final;
+
+ /* Wait for the exit LPI interrupt */
+ timeout = jiffies + max_duration;
+ while (!time_after(jiffies, timeout)) {
+ memcpy(final, &priv->xstats, sizeof(*final));
+
+ if (final->irq_tx_path_exit_lpi_mode_n >
+ initial->irq_tx_path_exit_lpi_mode_n)
+ break;
+ msleep(100);
}

+ memcpy(final, &priv->xstats, sizeof(*final));
if (final->irq_tx_path_exit_lpi_mode_n <=
initial->irq_tx_path_exit_lpi_mode_n) {
ret = -EINVAL;
--
2.55.0