[PATCH net-next v5 1/2] net: stmmac: dwmac-socfpga: complete cross-timestamp on ATSNS
From: Zxyan Zhu <hidden>
Date: 2026-09-10 08:10:34
Also in:
lkml, netdev
Subsystem:
arm/socfpga dwmac glue layer, networking drivers, stmmac ethernet driver, the rest · Maintainers:
Maxime Chevallier, Andrew Lunn, "David S. Miller", Eric Dumazet, Jakub Kicinski, Paolo Abeni, Linus Torvalds
The Agilex5 smtg_crosststamp() handler arms an internal auxiliary snapshot, toggles GPO0 and then polls XGMAC_INT_STATUS for TSIS to learn that the snapshot is ready. TSIS is a transient, read-to-clear status bit: it is set by any MAC timestamp event and cleared the moment XGMAC_TIMESTAMP_STATUS is read. That makes the TSIS poll racy in two ways. A stale TSIS latched by an unrelated event satisfies the poll immediately, before the auxiliary snapshot is latched, so the FIFO comes back empty and *device is never written even though the call returns 0. Conversely a concurrent reader of XGMAC_TIMESTAMP_STATUS, such as the TX timestamp completion path, can clear TSIS while the poll is waiting and make it time out with "Wait for time sync operation timeout". The auxiliary snapshot FIFO is also reported by the persistent ATSNS count in XGMAC_TIMESTAMP_STATUS. ATSNS is cleared only when the FIFO clear bit (PTP_ACR_ATSFC) is set, so it is immune to the destructive reads above. Poll ATSNS instead of TSIS, wait for the ATSFC clear to complete first so a stale ATSNS cannot be observed, and derive the count for the FIFO pop loop from the value the poll read back so it is guaranteed non-zero on the success path. Signed-off-by: Zxyan Zhu <redacted> --- .../ethernet/stmicro/stmmac/dwmac-socfpga.c | 29 +++++++++++++++---- 1 file changed, 24 insertions(+), 5 deletions(-)
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c
index 1d7f0a57d288..ee6f28637878 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c@@ -340,6 +340,18 @@ static int smtg_crosststamp(ktime_t *device, struct system_counterval_t *system, /* Release the mutex */ mutex_unlock(&priv->aux_ts_lock); + /* Wait for the FIFO clear to complete so a stale ATSNS count from + * a previous snapshot cannot satisfy the poll below before the new + * snapshot is latched. + */ + ret = readl_poll_timeout(ptpaddr + PTP_ACR, acr_value, + !(acr_value & PTP_ACR_ATSFC), 10, 10000); + if (ret) { + netdev_err(priv->dev, "%s: Failed to clear snapshot FIFO\n", + __func__); + return ret; + } + /* Trigger Internal snapshot signal. Create a rising edge by just toggle * the GPO0 to low and back to high. */
@@ -349,9 +361,17 @@ static int smtg_crosststamp(ktime_t *device, struct system_counterval_t *system, gpio_value |= XGMAC_GPIO_GPO0; writel(gpio_value, ioaddr + XGMAC_GPIO_STATUS); - /* Poll for time sync operation done */ - ret = readl_poll_timeout(priv->ioaddr + XGMAC_INT_STATUS, v, - (v & XGMAC_INT_TSIS), 100, 10000); + /* Wait for the auxiliary snapshot to be latched. TSIS is a + * transient status bit that is set by any MAC timestamp event and + * cleared by reading XGMAC_TIMESTAMP_STATUS, so it is not a + * reliable completion condition. Poll the persistent ATSNS count + * instead: it is cleared only by setting PTP_ACR_ATSFC, so + * nothing can clear it while we wait, and it reflects exactly the + * snapshot latched by this trigger. + */ + ret = readl_poll_timeout(ioaddr + XGMAC_TIMESTAMP_STATUS, v, + FIELD_GET(XGMAC_TIMESTAMP_ATSNS_MASK, v), + 100, 10000); if (ret) { netdev_err(priv->dev, "%s: Wait for time sync operation timeout\n", __func__);
@@ -364,8 +384,7 @@ static int smtg_crosststamp(ktime_t *device, struct system_counterval_t *system, .use_nsecs = false, }; - num_snapshot = FIELD_GET(XGMAC_TIMESTAMP_ATSNS_MASK, - readl(ioaddr + XGMAC_TIMESTAMP_STATUS)); + num_snapshot = FIELD_GET(XGMAC_TIMESTAMP_ATSNS_MASK, v); /* Repeat until the timestamps are from the FIFO last segment */ for (i = 0; i < num_snapshot; i++) {
--
2.34.1