[PATCH net-next v5 1/2] net: stmmac: dwmac-socfpga: complete cross-timestamp on ATSNS

From: Zxyan Zhu

Date: Thu Sep 10 2026 - 04:25:29 EST


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 <zxyan0222@xxxxxxxxx>
---
.../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