* [PATCH net-next v6 1/3] net: stmmac: dwmac-socfpga: complete cross-timestamp on ATSNS
2026-09-29 7:35 [PATCH net-next v6 0/3] net: stmmac: dwxgmac2: timestamp interrupt support + Agilex5 fix Zxyan Zhu
@ 2026-09-29 7:35 ` Zxyan Zhu
2026-09-29 7:35 ` [PATCH net-next v6 2/3] net: stmmac: guard against a zero channel in the aux snapshot handler Zxyan Zhu
` (2 subsequent siblings)
3 siblings, 0 replies; 5+ messages in thread
From: Zxyan Zhu @ 2026-09-29 7:35 UTC (permalink / raw)
To: andrew+netdev, davem, edumazet, kuba, pabeni
Cc: mcoquelin.stm32, alexandre.torgue, richardcochran,
maxime.chevallier, muhammad.nazim.amirul.nazle.asmade,
rohan.g.thomas, netdev, linux-stm32, linux-arm-kernel,
linux-kernel, Zxyan Zhu
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 level is also reported by the ATSNS count
in XGMAC_TIMESTAMP_STATUS. Reading XGMAC_TIMESTAMP_STATUS does not
affect ATSNS, so the destructive reads above cannot disturb it. Poll
ATSNS instead of TSIS, and wait for the PTP_ACR_ATSFC FIFO clear to
complete first so a stale ATSNS from a previous snapshot cannot satisfy
the poll before the new snapshot is latched.
Hold aux_ts_lock across the whole sequence instead of dropping it
right after arming, so a concurrent PTP_CLK_REQ_EXTTS request cannot
set PTP_ACR_ATSFC and flush the FIFO between the poll and the drain
loop, which would leave *device filled from an empty FIFO.
Fixes: fd8c4f645496 ("net: stmmac: socfpga: Add hardware supported cross-timestamp")
Signed-off-by: Zxyan Zhu <zxyan0222@gmail.com>
---
.../ethernet/stmicro/stmmac/dwmac-socfpga.c | 31 ++++++++++++++-----
1 file changed, 24 insertions(+), 7 deletions(-)
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c
index 1d7f0a57d288..c5f71bfc7cf4 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c
@@ -337,8 +337,18 @@ static int smtg_crosststamp(ktime_t *device, struct system_counterval_t *system,
acr_value = readl(ptpaddr + PTP_ACR);
acr_value |= PTP_ACR_ATSFC;
writel(acr_value, ptpaddr + PTP_ACR);
- /* Release the mutex */
- mutex_unlock(&priv->aux_ts_lock);
+
+ /* Wait for the FIFO clear to complete, so the poll below only
+ * observes snapshots latched by this trigger.
+ */
+ ret = readl_poll_timeout(ptpaddr + PTP_ACR, acr_value,
+ !(acr_value & PTP_ACR_ATSFC), 10, 10000);
+ if (ret) {
+ mutex_unlock(&priv->aux_ts_lock);
+ 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,10 +359,16 @@ 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: the ATSNS count
+ * is the FIFO level and is not affected by reading
+ * XGMAC_TIMESTAMP_STATUS, so concurrent readers cannot disturb
+ * the poll.
+ */
+ ret = readl_poll_timeout(ioaddr + XGMAC_TIMESTAMP_STATUS, v,
+ FIELD_GET(XGMAC_TIMESTAMP_ATSNS_MASK, v),
+ 100, 10000);
if (ret) {
+ mutex_unlock(&priv->aux_ts_lock);
netdev_err(priv->dev, "%s: Wait for time sync operation timeout\n",
__func__);
return ret;
@@ -364,8 +380,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++) {
@@ -375,6 +390,8 @@ static int smtg_crosststamp(ktime_t *device, struct system_counterval_t *system,
read_unlock_irqrestore(&priv->ptp_lock, flags);
}
+ mutex_unlock(&priv->aux_ts_lock);
+
get_smtgtime(priv->mii, SMTG_MDIO_ADDR, &smtg_time);
system->cycles = smtg_time;
--
2.34.1
^ permalink raw reply [flat|nested] 5+ messages in thread* [PATCH net-next v6 3/3] net: stmmac: dwxgmac2: add XGMAC timestamp interrupt support
2026-09-29 7:35 [PATCH net-next v6 0/3] net: stmmac: dwxgmac2: timestamp interrupt support + Agilex5 fix Zxyan Zhu
2026-09-29 7:35 ` [PATCH net-next v6 1/3] net: stmmac: dwmac-socfpga: complete cross-timestamp on ATSNS Zxyan Zhu
2026-09-29 7:35 ` [PATCH net-next v6 2/3] net: stmmac: guard against a zero channel in the aux snapshot handler Zxyan Zhu
@ 2026-09-29 7:35 ` Zxyan Zhu
2026-09-29 7:38 ` [PATCH net-next v6 0/3] net: stmmac: dwxgmac2: timestamp interrupt support + Agilex5 fix netdev-bot+sinfo
3 siblings, 0 replies; 5+ messages in thread
From: Zxyan Zhu @ 2026-09-29 7:35 UTC (permalink / raw)
To: andrew+netdev, davem, edumazet, kuba, pabeni
Cc: mcoquelin.stm32, alexandre.torgue, richardcochran,
maxime.chevallier, muhammad.nazim.amirul.nazle.asmade,
rohan.g.thomas, netdev, linux-stm32, linux-arm-kernel,
linux-kernel, Zxyan Zhu
The DWXGMAC2 hwif entries use the generic stmmac_ptp hwtimestamp ops,
whose timestamp_interrupt callback reads the dwmac4 offset
GMAC_TIMESTAMP_STATUS (0xb20) instead of the XGMAC register at 0xd20,
and whose interrupt enable mask XGMAC_INT_DEFAULT_EN omits XGMAC_TSIE.
The PTP clock nevertheless advertises the auxiliary snapshot channels
on XGMAC, so PTP_EXTTS_REQUEST succeeds but no PTP_CLOCK_EXTTS event is
ever delivered.
Fix this with a dedicated DWXGMAC2 timestamp interrupt handler that
reads XGMAC_TIMESTAMP_STATUS and reports the pending auxiliary
snapshots as PTP_CLOCK_EXTTS events. The handler deliberately does
not gate its status read on XGMAC_INT_TSIS: TSIS is an aggregate,
read-to-clear bit that the TX timestamp completion path (which polls
the same register for TXTSC) clears before the handler can observe
it, while ATSNS and the snapshot FIFO still hold the aux events. A
dwmac4-style TSIS gate would silently drop them.
XGMAC_TSIE is not added back to XGMAC_INT_DEFAULT_EN, which
30300d9f9150 ("net: stmmac: xgmac: Disable the Timestamp interrupt by
default") deliberately keeps clear. Instead it is armed on demand from
the PTP_CLK_REQ_EXTTS enable/disable path of stmmac_enable(), through a
new optional stmmac_ops->timestamp_interrupt_cfg() callback implemented
only for DWXGMAC2/DWXLGMAC2 (on top of dwxgmac2_irq_modify()), like
dwmac1000 does with dwmac1000_timestamp_interrupt_cfg(). This keeps
platforms that do not use EXTTS at their current interrupt load and
leaves the other cores untouched: stmmac_enable() is shared with
dwmac4/dwmac5, whose timestamp interrupt stays always-enabled and is
relied upon by intel_crosststamp(), so a direct irq_modify() call
there is not an option; cores that do not implement the callback keep
their current behaviour.
The interrupt is only touched after the PTP_ACR_ATSFC FIFO clear has
completed, and the handler refuses to drain entries while that clear
is still in flight, so a stale snapshot is never reported as an event;
if the clear times out, the error is returned without changing the
interrupt state. The handler also leaves the snapshot FIFO alone
while an internal cross-timestamp owns it: smtg_crosststamp() sets
STMMAC_FLAG_INT_SNAPSHOT_EN for the duration of the cross-timestamp,
raised and dropped under aux_ts_lock so concurrent requests cannot
lose it, and the handler returns early when that flag is set, mirroring
the dwmac4 handler's treatment of intel_crosststamp().
The timestamp interrupt is also disarmed after
ptp_clock_unregister(), which drops STMMAC_FLAG_EXT_SNAPSHOT_EN as
well. stmmac_hw_setup() reprograms
XGMAC_INT_EN from XGMAC_INT_DEFAULT_EN on resume, which drops
XGMAC_TSIE, so
stmmac_rearm_timestamp_irq() re-arms it there whenever an auxiliary
snapshot channel was left enabled.
Fixes: 4bb7aff9e6d0 ("net: stmmac: Add PTP support for XGMAC2")
Signed-off-by: Zxyan Zhu <zxyan0222@gmail.com>
---
.../ethernet/stmicro/stmmac/dwmac-socfpga.c | 5 ++
.../ethernet/stmicro/stmmac/dwxgmac2_core.c | 54 +++++++++++++++++++
drivers/net/ethernet/stmicro/stmmac/hwif.c | 4 +-
drivers/net/ethernet/stmicro/stmmac/hwif.h | 5 ++
.../ethernet/stmicro/stmmac/stmmac_hwtstamp.c | 12 +++++
.../net/ethernet/stmicro/stmmac/stmmac_main.c | 14 +++++
.../net/ethernet/stmicro/stmmac/stmmac_ptp.c | 9 ++++
.../net/ethernet/stmicro/stmmac/stmmac_ptp.h | 1 +
8 files changed, 102 insertions(+), 2 deletions(-)
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c
index c5f71bfc7cf4..9030cc1cc677 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c
@@ -311,6 +311,7 @@ static int smtg_crosststamp(ktime_t *device, struct system_counterval_t *system,
return -EBUSY;
mutex_lock(&priv->aux_ts_lock);
+ priv->plat->flags |= STMMAC_FLAG_INT_SNAPSHOT_EN;
/* Enable Internal snapshot trigger */
acr_value = readl(ptpaddr + PTP_ACR);
acr_value &= ~PTP_ACR_MASK;
@@ -328,6 +329,7 @@ static int smtg_crosststamp(ktime_t *device, struct system_counterval_t *system,
acr_value |= PTP_ACR_ATSEN3;
break;
default:
+ priv->plat->flags &= ~STMMAC_FLAG_INT_SNAPSHOT_EN;
mutex_unlock(&priv->aux_ts_lock);
return -EINVAL;
}
@@ -344,6 +346,7 @@ static int smtg_crosststamp(ktime_t *device, struct system_counterval_t *system,
ret = readl_poll_timeout(ptpaddr + PTP_ACR, acr_value,
!(acr_value & PTP_ACR_ATSFC), 10, 10000);
if (ret) {
+ priv->plat->flags &= ~STMMAC_FLAG_INT_SNAPSHOT_EN;
mutex_unlock(&priv->aux_ts_lock);
netdev_err(priv->dev, "%s: Failed to clear snapshot FIFO\n",
__func__);
@@ -368,6 +371,7 @@ static int smtg_crosststamp(ktime_t *device, struct system_counterval_t *system,
FIELD_GET(XGMAC_TIMESTAMP_ATSNS_MASK, v),
100, 10000);
if (ret) {
+ priv->plat->flags &= ~STMMAC_FLAG_INT_SNAPSHOT_EN;
mutex_unlock(&priv->aux_ts_lock);
netdev_err(priv->dev, "%s: Wait for time sync operation timeout\n",
__func__);
@@ -390,6 +394,7 @@ static int smtg_crosststamp(ktime_t *device, struct system_counterval_t *system,
read_unlock_irqrestore(&priv->ptp_lock, flags);
}
+ priv->plat->flags &= ~STMMAC_FLAG_INT_SNAPSHOT_EN;
mutex_unlock(&priv->aux_ts_lock);
get_smtgtime(priv->mii, SMTG_MDIO_ADDR, &smtg_time);
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c
index 1a88cbaed70c..8a39028fa4bb 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c
@@ -42,6 +42,12 @@ static void dwxgmac2_irq_modify(struct mac_device_info *hw, u32 disable,
spin_unlock_irqrestore(&hw->irq_ctrl_lock, flags);
}
+static void dwxgmac2_timestamp_interrupt_cfg(struct stmmac_priv *priv, bool en)
+{
+ stmmac_mac_irq_modify(priv, en ? 0 : XGMAC_TSIE,
+ en ? XGMAC_TSIE : 0);
+}
+
static void dwxgmac2_update_caps(struct stmmac_priv *priv)
{
if (!priv->dma_cap.mbps_10_100)
@@ -1154,6 +1160,52 @@ static int dwxgmac2_get_mac_tx_timestamp(struct mac_device_info *hw, u64 *ts)
return 0;
}
+void dwxgmac2_timestamp_interrupt(struct stmmac_priv *priv)
+{
+ u32 ts_status, pending_snapshots, acr_value, channel;
+ struct ptp_clock_event event;
+ unsigned long flags;
+ u64 ptp_time;
+ int i;
+
+ if (priv->plat->flags & STMMAC_FLAG_INT_SNAPSHOT_EN)
+ return;
+
+ /* Reading XGMAC_TIMESTAMP_STATUS clears the TSIS and AUXTSTRIG
+ * bits, so the ATSNS count is the only reliable indication of
+ * pending auxiliary snapshots. TXTSC is cleared by
+ * XGMAC_TXTIMESTAMP_SEC and is not affected by this read.
+ */
+ ts_status = readl(priv->ioaddr + XGMAC_TIMESTAMP_STATUS);
+
+ if (!(priv->plat->flags & STMMAC_FLAG_EXT_SNAPSHOT_EN) || !priv->ptp_clock)
+ return;
+
+ pending_snapshots = FIELD_GET(XGMAC_TIMESTAMP_ATSNS_MASK, ts_status);
+ if (!pending_snapshots)
+ return;
+
+ acr_value = readl(priv->ptpaddr + PTP_ACR);
+ /* Entries observed while the FIFO is being flushed are stale. */
+ if (acr_value & PTP_ACR_ATSFC)
+ return;
+ channel = FIELD_GET(PTP_ACR_MASK, acr_value);
+ if (!channel)
+ return;
+ channel = ilog2(channel);
+
+ for (i = 0; i < pending_snapshots; i++) {
+ read_lock_irqsave(&priv->ptp_lock, flags);
+ stmmac_get_ptptime(priv, priv->ptpaddr, &ptp_time);
+ read_unlock_irqrestore(&priv->ptp_lock, flags);
+
+ event.type = PTP_CLOCK_EXTTS;
+ event.index = channel;
+ event.timestamp = ptp_time;
+ ptp_clock_event(priv->ptp_clock, &event);
+ }
+}
+
static int dwxgmac2_flex_pps_config(void __iomem *ioaddr, int index,
struct stmmac_pps_cfg *cfg, bool enable,
u32 sub_second_inc, u32 systime_flags)
@@ -1413,6 +1465,7 @@ static int dwxgmac2_config_l4_filter(struct mac_device_info *hw, u32 filter_no,
const struct stmmac_ops dwxgmac210_ops = {
.core_init = dwxgmac2_core_init,
.irq_modify = dwxgmac2_irq_modify,
+ .timestamp_interrupt_cfg = dwxgmac2_timestamp_interrupt_cfg,
.update_caps = dwxgmac2_update_caps,
.set_mac = dwxgmac2_set_mac,
.rx_ipc = dwxgmac2_rx_ipc,
@@ -1468,6 +1521,7 @@ static void dwxlgmac2_rx_queue_enable(struct mac_device_info *hw, u8 mode,
const struct stmmac_ops dwxlgmac2_ops = {
.core_init = dwxgmac2_core_init,
.irq_modify = dwxgmac2_irq_modify,
+ .timestamp_interrupt_cfg = dwxgmac2_timestamp_interrupt_cfg,
.set_mac = dwxgmac2_set_mac,
.rx_ipc = dwxgmac2_rx_ipc,
.rx_queue_enable = dwxlgmac2_rx_queue_enable,
diff --git a/drivers/net/ethernet/stmicro/stmmac/hwif.c b/drivers/net/ethernet/stmicro/stmmac/hwif.c
index 265671170bf6..eba87410f985 100644
--- a/drivers/net/ethernet/stmicro/stmmac/hwif.c
+++ b/drivers/net/ethernet/stmicro/stmmac/hwif.c
@@ -258,7 +258,7 @@ static const struct stmmac_hwif_entry {
.dma = &dwxgmac210_dma_ops,
.mac = &dwxgmac210_ops,
.vlan = &dwxgmac210_vlan_ops,
- .hwtimestamp = &stmmac_ptp,
+ .hwtimestamp = &dwxgmac2_ptp,
.ptp = &stmmac_ptp_clock_ops,
.mode = NULL,
.tc = &dwmac510_tc_ops,
@@ -280,7 +280,7 @@ static const struct stmmac_hwif_entry {
.dma = &dwxgmac210_dma_ops,
.mac = &dwxlgmac2_ops,
.vlan = &dwxlgmac2_vlan_ops,
- .hwtimestamp = &stmmac_ptp,
+ .hwtimestamp = &dwxgmac2_ptp,
.ptp = &stmmac_ptp_clock_ops,
.mode = NULL,
.tc = &dwmac510_tc_ops,
diff --git a/drivers/net/ethernet/stmicro/stmmac/hwif.h b/drivers/net/ethernet/stmicro/stmmac/hwif.h
index fe18f98fae45..345bb8bdee86 100644
--- a/drivers/net/ethernet/stmicro/stmmac/hwif.h
+++ b/drivers/net/ethernet/stmicro/stmmac/hwif.h
@@ -317,6 +317,8 @@ struct stmmac_ops {
void (*update_caps)(struct stmmac_priv *priv);
/* Change the interrupt enable setting. Enable takes precedence. */
void (*irq_modify)(struct mac_device_info *hw, u32 disable, u32 enable);
+ /* Arm or disarm the timestamp interrupt on demand (optional) */
+ void (*timestamp_interrupt_cfg)(struct stmmac_priv *priv, bool en);
/* Enable the MAC RX/TX */
void (*set_mac)(void __iomem *ioaddr, bool enable);
/* Enable and verify that the IPC module is supported */
@@ -420,6 +422,8 @@ struct stmmac_ops {
stmmac_do_void_callback(__priv, mac, update_caps, __priv)
#define stmmac_mac_irq_modify(__priv, __args...) \
stmmac_do_void_callback(__priv, mac, irq_modify, (__priv)->hw, __args)
+#define stmmac_mac_timestamp_interrupt_cfg(__priv, __args...) \
+ stmmac_do_void_callback(__priv, mac, timestamp_interrupt_cfg, __priv, __args)
#define stmmac_mac_set(__priv, __args...) \
stmmac_do_void_callback(__priv, mac, set_mac, __args)
#define stmmac_rx_ipc(__priv, __args...) \
@@ -672,6 +676,7 @@ extern const struct stmmac_desc_ops ndesc_ops;
extern const struct stmmac_hwtimestamp stmmac_ptp;
extern const struct stmmac_hwtimestamp dwmac1000_ptp;
+extern const struct stmmac_hwtimestamp dwxgmac2_ptp;
extern const struct stmmac_mode_ops ring_mode_ops;
extern const struct stmmac_mode_ops chain_mode_ops;
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_hwtstamp.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_hwtstamp.c
index 2a076e228e9a..4b906bc33d26 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_hwtstamp.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_hwtstamp.c
@@ -280,3 +280,15 @@ const struct stmmac_hwtimestamp dwmac1000_ptp = {
.get_ptptime = dwmac1000_get_ptptime,
.timestamp_interrupt = dwmac1000_timestamp_interrupt,
};
+
+const struct stmmac_hwtimestamp dwxgmac2_ptp = {
+ .config_hw_tstamping = config_hw_tstamping,
+ .init_systime = init_systime,
+ .config_sub_second_increment = config_sub_second_increment,
+ .config_addend = config_addend,
+ .adjust_systime = adjust_systime,
+ .get_systime = get_systime,
+ .get_ptptime = get_ptptime,
+ .timestamp_interrupt = dwxgmac2_timestamp_interrupt,
+ .hwtstamp_correct_latency = hwtstamp_correct_latency,
+};
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index 66ae365e1c89..357dd197298f 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -885,6 +885,19 @@ static int stmmac_init_tstamp_counter(struct stmmac_priv *priv,
return 0;
}
+/**
+ * stmmac_rearm_timestamp_irq - re-arm the timestamp interrupt
+ * @priv: driver private structure
+ * Description: this re-arms the on-demand timestamp interrupt if an
+ * auxiliary snapshot channel was left enabled.
+ */
+static void stmmac_rearm_timestamp_irq(struct stmmac_priv *priv)
+{
+ if (priv->plat->flags & STMMAC_FLAG_EXT_SNAPSHOT_EN &&
+ priv->ptp_clock)
+ stmmac_mac_timestamp_interrupt_cfg(priv, true);
+}
+
/**
* stmmac_init_timestamping - initialise timestamping
* @priv: driver private structure
@@ -8314,6 +8327,7 @@ int stmmac_resume(struct device *dev)
}
stmmac_init_timestamping(priv);
+ stmmac_rearm_timestamp_irq(priv);
stmmac_init_coalesce(priv);
phylink_rx_clk_stop_block(priv->phylink);
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c
index 960249960004..971cea455803 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.c
@@ -255,6 +255,12 @@ static int stmmac_enable(struct ptp_clock_info *ptp,
ret = readl_poll_timeout(ptpaddr + PTP_ACR, acr_value,
!(acr_value & PTP_ACR_ATSFC),
10, 10000);
+ /* Arm or disarm the timestamp interrupt only once the FIFO
+ * clear has completed, so the handler does not observe a
+ * snapshot that the clear is about to discard.
+ */
+ if (!ret)
+ stmmac_mac_timestamp_interrupt_cfg(priv, on);
break;
}
@@ -395,6 +401,9 @@ void stmmac_ptp_unregister(struct stmmac_priv *priv)
pr_debug("Removed PTP HW clock successfully on %s\n",
priv->dev->name);
+ stmmac_mac_timestamp_interrupt_cfg(priv, false);
+ priv->plat->flags &= ~STMMAC_FLAG_EXT_SNAPSHOT_EN;
+
mutex_destroy(&priv->aux_ts_lock);
}
}
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.h b/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.h
index 3fe0e3a80e80..dade09614163 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.h
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ptp.h
@@ -103,6 +103,7 @@ int dwmac1000_ptp_enable(struct ptp_clock_info *ptp,
void dwmac1000_get_ptptime(void __iomem *ptpaddr, u64 *ptp_time);
void dwmac1000_timestamp_interrupt(struct stmmac_priv *priv);
+void dwxgmac2_timestamp_interrupt(struct stmmac_priv *priv);
extern const struct ptp_clock_info stmmac_ptp_clock_ops;
extern const struct ptp_clock_info dwmac1000_ptp_clock_ops;
--
2.34.1
^ permalink raw reply [flat|nested] 5+ messages in thread