Skip to content

Commit 6990dc3

Browse files
chweelinchoonganguy11
authored andcommitted
igc: fix race condition in TX timestamp read for register 0
The current HW bug workaround checks the TXTT_0 ready bit first, then reads TXSTMPL_0 twice (before and after reading TXSTMPH_0) to detect whether a new timestamp was captured by timestamp register 0 during the workaround. This sequence has a race: if a new timestamp is captured after checking the TXTT_0 bit but before the first TXSTMPL_0 read, the detection fails because both the "old" and "new" values come from the same timestamp. Fix by reading TXSTMPL_0 first to establish a baseline, then checking the TXTT_0 bit. This ensures any timestamp captured during the race window will be detected. Old sequence: 1. Check TXTT_0 ready bit 2. Read TXSTMPL_0 (baseline) 3. Read TXSTMPH_0 (interrupt workaround) 4. Read TXSTMPL_0 (detect changes vs baseline) New sequence: 1. Read TXSTMPL_0 (baseline) 2. Check TXTT_0 ready bit 3. Read TXSTMPH_0 (interrupt workaround) 4. Read TXSTMPL_0 (detect changes vs baseline) Fixes: c789ad7 ("igc: Work around HW bug causing missing timestamps") Suggested-by: Avi Shalev <avi.shalev@intel.com> Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com> Co-developed-by: Song Yoong Siang <yoong.siang.song@intel.com> Signed-off-by: Song Yoong Siang <yoong.siang.song@intel.com> Signed-off-by: Chwee-Lin Choong <chwee.lin.choong@intel.com> Tested-by: Avigail Dahan <avigailx.dahan@intel.com> Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
1 parent 41a9a68 commit 6990dc3

1 file changed

Lines changed: 25 additions & 18 deletions

File tree

drivers/net/ethernet/intel/igc/igc_ptp.c

Lines changed: 25 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -774,36 +774,43 @@ static void igc_ptp_tx_reg_to_stamp(struct igc_adapter *adapter,
774774
static void igc_ptp_tx_hwtstamp(struct igc_adapter *adapter)
775775
{
776776
struct igc_hw *hw = &adapter->hw;
777+
u32 txstmpl_old;
777778
u64 regval;
778779
u32 mask;
779780
int i;
780781

782+
/* Establish baseline of TXSTMPL_0 before checking TXTT_0.
783+
* This baseline is used to detect if a new timestamp arrives in
784+
* register 0 during the hardware bug workaround below.
785+
*/
786+
txstmpl_old = rd32(IGC_TXSTMPL);
787+
781788
mask = rd32(IGC_TSYNCTXCTL) & IGC_TSYNCTXCTL_TXTT_ANY;
782789
if (mask & IGC_TSYNCTXCTL_TXTT_0) {
783790
regval = rd32(IGC_TXSTMPL);
784791
regval |= (u64)rd32(IGC_TXSTMPH) << 32;
785792
} else {
786-
/* There's a bug in the hardware that could cause
787-
* missing interrupts for TX timestamping. The issue
788-
* is that for new interrupts to be triggered, the
789-
* IGC_TXSTMPH_0 register must be read.
793+
/* TXTT_0 not set - register 0 has no new timestamp initially.
794+
*
795+
* Hardware bug: Future timestamp interrupts won't fire unless
796+
* TXSTMPH_0 is read, even if the timestamp was captured in
797+
* registers 1-3.
790798
*
791-
* To avoid discarding a valid timestamp that just
792-
* happened at the "wrong" time, we need to confirm
793-
* that there was no timestamp captured, we do that by
794-
* assuming that no two timestamps in sequence have
795-
* the same nanosecond value.
799+
* Workaround: Read TXSTMPH_0 here to enable future interrupts.
800+
* However, this read clears TXTT_0. If a timestamp arrives in
801+
* register 0 after checking TXTT_0 but before this read, it
802+
* would be lost.
796803
*
797-
* So, we read the "low" register, read the "high"
798-
* register (to latch a new timestamp) and read the
799-
* "low" register again, if "old" and "new" versions
800-
* of the "low" register are different, a valid
801-
* timestamp was captured, we can read the "high"
802-
* register again.
804+
* To detect this race: We saved a baseline read of TXSTMPL_0
805+
* before TXTT_0 check. After performing the workaround read of
806+
* TXSTMPH_0, we read TXSTMPL_0 again. Since consecutive
807+
* timestamps never share the same nanosecond value, a change
808+
* between the baseline and new TXSTMPL_0 indicates a timestamp
809+
* arrived during the race window. If so, read the complete
810+
* timestamp.
803811
*/
804-
u32 txstmpl_old, txstmpl_new;
812+
u32 txstmpl_new;
805813

806-
txstmpl_old = rd32(IGC_TXSTMPL);
807814
rd32(IGC_TXSTMPH);
808815
txstmpl_new = rd32(IGC_TXSTMPL);
809816

@@ -818,7 +825,7 @@ static void igc_ptp_tx_hwtstamp(struct igc_adapter *adapter)
818825

819826
done:
820827
/* Now that the problematic first register was handled, we can
821-
* use retrieve the timestamps from the other registers
828+
* retrieve the timestamps from the other registers
822829
* (starting from '1') with less complications.
823830
*/
824831
for (i = 1; i < IGC_MAX_TX_TSTAMP_REGS; i++) {

0 commit comments

Comments
 (0)