The current HW bug workaround checks the TXTT_0 ready bit first, then reads LOW -> HIGH -> LOW from register 0 to detect if a timestamp was captured. This sequence has a race: if a new timestamp is latched after reading the TXTT mask but before the first LOW read, both old and new timestamp match, causing the driver to drop a valid timestamp. Fix by reading the LOW register first, then the TXTT mask, so a newly latched timestamp will always be detected. This fix also prevents TX unit hangs observed under heavy timestamping load. Fixes: c789ad7cbebc ("igc: Work around HW bug causing missing timestamps") Suggested-by: Avi Shalev Signed-off-by: Song Yoong Siang Signed-off-by: Chwee-Lin Choong --- drivers/net/ethernet/intel/igc/igc_ptp.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/intel/igc/igc_ptp.c b/drivers/net/ethernet/intel/igc/igc_ptp.c index b7b46d863bee..930486b02fc1 100644 --- a/drivers/net/ethernet/intel/igc/igc_ptp.c +++ b/drivers/net/ethernet/intel/igc/igc_ptp.c @@ -774,10 +774,17 @@ static void igc_ptp_tx_reg_to_stamp(struct igc_adapter *adapter, static void igc_ptp_tx_hwtstamp(struct igc_adapter *adapter) { struct igc_hw *hw = &adapter->hw; + u32 txstmpl_old; u64 regval; u32 mask; int i; + /* Read the "low" register 0 first to establish a baseline value. + * This avoids a race where a new timestamp could be latched + * after checking the TXTT mask. + */ + txstmpl_old = rd32(IGC_TXSTMPL); + mask = rd32(IGC_TSYNCTXCTL) & IGC_TSYNCTXCTL_TXTT_ANY; if (mask & IGC_TSYNCTXCTL_TXTT_0) { regval = rd32(IGC_TXSTMPL); @@ -801,9 +808,8 @@ static void igc_ptp_tx_hwtstamp(struct igc_adapter *adapter) * timestamp was captured, we can read the "high" * register again. */ - u32 txstmpl_old, txstmpl_new; + u32 txstmpl_new; - txstmpl_old = rd32(IGC_TXSTMPL); rd32(IGC_TXSTMPH); txstmpl_new = rd32(IGC_TXSTMPL); -- 2.42.0