1ae06c70bSJeff Kirsher // SPDX-License-Identifier: GPL-2.0+ 251dce24bSJeff Kirsher /* Copyright (C) 2011 Richard Cochran <richardcochran@gmail.com> */ 351dce24bSJeff Kirsher 4d339b133SRichard Cochran #include <linux/module.h> 5d339b133SRichard Cochran #include <linux/device.h> 6d339b133SRichard Cochran #include <linux/pci.h> 7ba59814bSMatthew Vick #include <linux/ptp_classify.h> 8d339b133SRichard Cochran 9d339b133SRichard Cochran #include "igb.h" 10d339b133SRichard Cochran 11d339b133SRichard Cochran #define INCVALUE_MASK 0x7fffffff 12d339b133SRichard Cochran #define ISGN 0x80000000 13d339b133SRichard Cochran 14b980ac18SJeff Kirsher /* The 82580 timesync updates the system timer every 8ns by 8ns, 157ebae817SRichard Cochran * and this update value cannot be reprogrammed. 167ebae817SRichard Cochran * 17d339b133SRichard Cochran * Neither the 82576 nor the 82580 offer registers wide enough to hold 18d339b133SRichard Cochran * nanoseconds time values for very long. For the 82580, SYSTIM always 19dbedd44eSJoe Perches * counts nanoseconds, but the upper 24 bits are not available. The 20d339b133SRichard Cochran * frequency is adjusted by changing the 32 bit fractional nanoseconds 21d339b133SRichard Cochran * register, TIMINCA. 22d339b133SRichard Cochran * 23d339b133SRichard Cochran * For the 82576, the SYSTIM register time unit is affect by the 24d339b133SRichard Cochran * choice of the 24 bit TININCA:IV (incvalue) field. Five bits of this 25d339b133SRichard Cochran * field are needed to provide the nominal 16 nanosecond period, 26d339b133SRichard Cochran * leaving 19 bits for fractional nanoseconds. 27d339b133SRichard Cochran * 287ebae817SRichard Cochran * We scale the NIC clock cycle by a large factor so that relatively 297ebae817SRichard Cochran * small clock corrections can be added or subtracted at each clock 307ebae817SRichard Cochran * tick. The drawbacks of a large factor are a) that the clock 317ebae817SRichard Cochran * register overflows more quickly (not such a big deal) and b) that 327ebae817SRichard Cochran * the increment per tick has to fit into 24 bits. As a result we 337ebae817SRichard Cochran * need to use a shift of 19 so we can fit a value of 16 into the 347ebae817SRichard Cochran * TIMINCA register. 357ebae817SRichard Cochran * 36d339b133SRichard Cochran * 37d339b133SRichard Cochran * SYSTIMH SYSTIML 38d339b133SRichard Cochran * +--------------+ +---+---+------+ 39d339b133SRichard Cochran * 82576 | 32 | | 8 | 5 | 19 | 40d339b133SRichard Cochran * +--------------+ +---+---+------+ 41d339b133SRichard Cochran * \________ 45 bits _______/ fract 42d339b133SRichard Cochran * 43d339b133SRichard Cochran * +----------+---+ +--------------+ 44d339b133SRichard Cochran * 82580 | 24 | 8 | | 32 | 45d339b133SRichard Cochran * +----------+---+ +--------------+ 46d339b133SRichard Cochran * reserved \______ 40 bits _____/ 47d339b133SRichard Cochran * 48d339b133SRichard Cochran * 49d339b133SRichard Cochran * The 45 bit 82576 SYSTIM overflows every 50d339b133SRichard Cochran * 2^45 * 10^-9 / 3600 = 9.77 hours. 51d339b133SRichard Cochran * 52d339b133SRichard Cochran * The 40 bit 82580 SYSTIM overflows every 53d339b133SRichard Cochran * 2^40 * 10^-9 / 60 = 18.3 minutes. 54094bf4d0SMiroslav Lichvar * 55094bf4d0SMiroslav Lichvar * SYSTIM is converted to real time using a timecounter. As 564c9b658eSMiroslav Lichvar * timecounter_cyc2time() allows old timestamps, the timecounter needs 574c9b658eSMiroslav Lichvar * to be updated at least once per half of the SYSTIM interval. 584c9b658eSMiroslav Lichvar * Scheduling of delayed work is not very accurate, and also the NIC 594c9b658eSMiroslav Lichvar * clock can be adjusted to run up to 6% faster and the system clock 604c9b658eSMiroslav Lichvar * up to 10% slower, so we aim for 6 minutes to be sure the actual 614c9b658eSMiroslav Lichvar * interval in the NIC time is shorter than 9.16 minutes. 62d339b133SRichard Cochran */ 63d339b133SRichard Cochran 644c9b658eSMiroslav Lichvar #define IGB_SYSTIM_OVERFLOW_PERIOD (HZ * 60 * 6) 65428f1f71SMatthew Vick #define IGB_PTP_TX_TIMEOUT (HZ * 15) 66a51d8c21SJacob Keller #define INCPERIOD_82576 BIT(E1000_TIMINCA_16NS_SHIFT) 67a51d8c21SJacob Keller #define INCVALUE_82576_MASK GENMASK(E1000_TIMINCA_16NS_SHIFT - 1, 0) 68a51d8c21SJacob Keller #define INCVALUE_82576 (16u << IGB_82576_TSYNC_SHIFT) 69d339b133SRichard Cochran #define IGB_NBITS_82580 40 70d339b133SRichard Cochran 71167f3f71SJeff Kirsher static void igb_ptp_tx_hwtstamp(struct igb_adapter *adapter); 72167f3f71SJeff Kirsher 73b980ac18SJeff Kirsher /* SYSTIM read access for the 82576 */ 74a5a1d1c2SThomas Gleixner static u64 igb_ptp_read_82576(const struct cyclecounter *cc) 75d339b133SRichard Cochran { 76d339b133SRichard Cochran struct igb_adapter *igb = container_of(cc, struct igb_adapter, cc); 77d339b133SRichard Cochran struct e1000_hw *hw = &igb->hw; 78a79f4f88SMatthew Vick u64 val; 79a79f4f88SMatthew Vick u32 lo, hi; 80d339b133SRichard Cochran 81d339b133SRichard Cochran lo = rd32(E1000_SYSTIML); 82d339b133SRichard Cochran hi = rd32(E1000_SYSTIMH); 83d339b133SRichard Cochran 84d339b133SRichard Cochran val = ((u64) hi) << 32; 85d339b133SRichard Cochran val |= lo; 86d339b133SRichard Cochran 87d339b133SRichard Cochran return val; 88d339b133SRichard Cochran } 89d339b133SRichard Cochran 90b980ac18SJeff Kirsher /* SYSTIM read access for the 82580 */ 91a5a1d1c2SThomas Gleixner static u64 igb_ptp_read_82580(const struct cyclecounter *cc) 92d339b133SRichard Cochran { 93d339b133SRichard Cochran struct igb_adapter *igb = container_of(cc, struct igb_adapter, cc); 94d339b133SRichard Cochran struct e1000_hw *hw = &igb->hw; 95e5c3370fSAkeem G Abodunrin u32 lo, hi; 96a79f4f88SMatthew Vick u64 val; 97d339b133SRichard Cochran 98b980ac18SJeff Kirsher /* The timestamp latches on lowest register read. For the 82580 997ebae817SRichard Cochran * the lowest register is SYSTIMR instead of SYSTIML. However we only 1007ebae817SRichard Cochran * need to provide nanosecond resolution, so we just ignore it. 1017ebae817SRichard Cochran */ 102e5c3370fSAkeem G Abodunrin rd32(E1000_SYSTIMR); 103d339b133SRichard Cochran lo = rd32(E1000_SYSTIML); 104d339b133SRichard Cochran hi = rd32(E1000_SYSTIMH); 105d339b133SRichard Cochran 106d339b133SRichard Cochran val = ((u64) hi) << 32; 107d339b133SRichard Cochran val |= lo; 108d339b133SRichard Cochran 109d339b133SRichard Cochran return val; 110d339b133SRichard Cochran } 111d339b133SRichard Cochran 112b980ac18SJeff Kirsher /* SYSTIM read access for I210/I211 */ 113d4c496feSRichard Cochran static void igb_ptp_read_i210(struct igb_adapter *adapter, 114d4c496feSRichard Cochran struct timespec64 *ts) 115e57b8bdbSMatthew Vick { 116e57b8bdbSMatthew Vick struct e1000_hw *hw = &adapter->hw; 117e5c3370fSAkeem G Abodunrin u32 sec, nsec; 118e57b8bdbSMatthew Vick 119b980ac18SJeff Kirsher /* The timestamp latches on lowest register read. For I210/I211, the 120e57b8bdbSMatthew Vick * lowest register is SYSTIMR. Since we only need to provide nanosecond 121e57b8bdbSMatthew Vick * resolution, we can ignore it. 122e57b8bdbSMatthew Vick */ 123e5c3370fSAkeem G Abodunrin rd32(E1000_SYSTIMR); 124e57b8bdbSMatthew Vick nsec = rd32(E1000_SYSTIML); 125e57b8bdbSMatthew Vick sec = rd32(E1000_SYSTIMH); 126e57b8bdbSMatthew Vick 127e57b8bdbSMatthew Vick ts->tv_sec = sec; 128e57b8bdbSMatthew Vick ts->tv_nsec = nsec; 129e57b8bdbSMatthew Vick } 130e57b8bdbSMatthew Vick 131e57b8bdbSMatthew Vick static void igb_ptp_write_i210(struct igb_adapter *adapter, 132d4c496feSRichard Cochran const struct timespec64 *ts) 133e57b8bdbSMatthew Vick { 134e57b8bdbSMatthew Vick struct e1000_hw *hw = &adapter->hw; 135e57b8bdbSMatthew Vick 136b980ac18SJeff Kirsher /* Writing the SYSTIMR register is not necessary as it only provides 137e57b8bdbSMatthew Vick * sub-nanosecond resolution. 138e57b8bdbSMatthew Vick */ 139e57b8bdbSMatthew Vick wr32(E1000_SYSTIML, ts->tv_nsec); 14040c9b079SArnd Bergmann wr32(E1000_SYSTIMH, (u32)ts->tv_sec); 141e57b8bdbSMatthew Vick } 142e57b8bdbSMatthew Vick 143a79f4f88SMatthew Vick /** 144a79f4f88SMatthew Vick * igb_ptp_systim_to_hwtstamp - convert system time value to hw timestamp 145a79f4f88SMatthew Vick * @adapter: board private structure 146a79f4f88SMatthew Vick * @hwtstamps: timestamp structure to update 147a79f4f88SMatthew Vick * @systim: unsigned 64bit system time value. 148a79f4f88SMatthew Vick * 149a79f4f88SMatthew Vick * We need to convert the system time value stored in the RX/TXSTMP registers 150a79f4f88SMatthew Vick * into a hwtstamp which can be used by the upper level timestamping functions. 151a79f4f88SMatthew Vick * 152a79f4f88SMatthew Vick * The 'tmreg_lock' spinlock is used to protect the consistency of the 153a79f4f88SMatthew Vick * system time value. This is needed because reading the 64 bit time 154a79f4f88SMatthew Vick * value involves reading two (or three) 32 bit registers. The first 155a79f4f88SMatthew Vick * read latches the value. Ditto for writing. 156a79f4f88SMatthew Vick * 157a79f4f88SMatthew Vick * In addition, here have extended the system time with an overflow 158a79f4f88SMatthew Vick * counter in software. 159a79f4f88SMatthew Vick **/ 160a79f4f88SMatthew Vick static void igb_ptp_systim_to_hwtstamp(struct igb_adapter *adapter, 161a79f4f88SMatthew Vick struct skb_shared_hwtstamps *hwtstamps, 162a79f4f88SMatthew Vick u64 systim) 163a79f4f88SMatthew Vick { 164a79f4f88SMatthew Vick unsigned long flags; 165a79f4f88SMatthew Vick u64 ns; 166a79f4f88SMatthew Vick 167a79f4f88SMatthew Vick switch (adapter->hw.mac.type) { 168a79f4f88SMatthew Vick case e1000_82576: 169e57b8bdbSMatthew Vick case e1000_82580: 170ceb5f13bSCarolyn Wyborny case e1000_i354: 171e57b8bdbSMatthew Vick case e1000_i350: 172a79f4f88SMatthew Vick spin_lock_irqsave(&adapter->tmreg_lock, flags); 173a79f4f88SMatthew Vick 174a79f4f88SMatthew Vick ns = timecounter_cyc2time(&adapter->tc, systim); 175a79f4f88SMatthew Vick 176a79f4f88SMatthew Vick spin_unlock_irqrestore(&adapter->tmreg_lock, flags); 177a79f4f88SMatthew Vick 178a79f4f88SMatthew Vick memset(hwtstamps, 0, sizeof(*hwtstamps)); 179a79f4f88SMatthew Vick hwtstamps->hwtstamp = ns_to_ktime(ns); 180e57b8bdbSMatthew Vick break; 181e57b8bdbSMatthew Vick case e1000_i210: 182e57b8bdbSMatthew Vick case e1000_i211: 183e57b8bdbSMatthew Vick memset(hwtstamps, 0, sizeof(*hwtstamps)); 184e57b8bdbSMatthew Vick /* Upper 32 bits contain s, lower 32 bits contain ns. */ 185e57b8bdbSMatthew Vick hwtstamps->hwtstamp = ktime_set(systim >> 32, 186e57b8bdbSMatthew Vick systim & 0xFFFFFFFF); 187e57b8bdbSMatthew Vick break; 188e57b8bdbSMatthew Vick default: 189e57b8bdbSMatthew Vick break; 190e57b8bdbSMatthew Vick } 191a79f4f88SMatthew Vick } 192a79f4f88SMatthew Vick 193b980ac18SJeff Kirsher /* PTP clock operations */ 194a79f4f88SMatthew Vick static int igb_ptp_adjfreq_82576(struct ptp_clock_info *ptp, s32 ppb) 195d339b133SRichard Cochran { 196a79f4f88SMatthew Vick struct igb_adapter *igb = container_of(ptp, struct igb_adapter, 197a79f4f88SMatthew Vick ptp_caps); 198a79f4f88SMatthew Vick struct e1000_hw *hw = &igb->hw; 199a79f4f88SMatthew Vick int neg_adj = 0; 200d339b133SRichard Cochran u64 rate; 201d339b133SRichard Cochran u32 incvalue; 202d339b133SRichard Cochran 203d339b133SRichard Cochran if (ppb < 0) { 204d339b133SRichard Cochran neg_adj = 1; 205d339b133SRichard Cochran ppb = -ppb; 206d339b133SRichard Cochran } 207d339b133SRichard Cochran rate = ppb; 208d339b133SRichard Cochran rate <<= 14; 209d339b133SRichard Cochran rate = div_u64(rate, 1953125); 210d339b133SRichard Cochran 211d339b133SRichard Cochran incvalue = 16 << IGB_82576_TSYNC_SHIFT; 212d339b133SRichard Cochran 213d339b133SRichard Cochran if (neg_adj) 214d339b133SRichard Cochran incvalue -= rate; 215d339b133SRichard Cochran else 216d339b133SRichard Cochran incvalue += rate; 217d339b133SRichard Cochran 218d339b133SRichard Cochran wr32(E1000_TIMINCA, INCPERIOD_82576 | (incvalue & INCVALUE_82576_MASK)); 219d339b133SRichard Cochran 220d339b133SRichard Cochran return 0; 221d339b133SRichard Cochran } 222d339b133SRichard Cochran 223c79e975eSRichard Cochran static int igb_ptp_adjfine_82580(struct ptp_clock_info *ptp, long scaled_ppm) 224d339b133SRichard Cochran { 225a79f4f88SMatthew Vick struct igb_adapter *igb = container_of(ptp, struct igb_adapter, 226a79f4f88SMatthew Vick ptp_caps); 227a79f4f88SMatthew Vick struct e1000_hw *hw = &igb->hw; 228a79f4f88SMatthew Vick int neg_adj = 0; 229d339b133SRichard Cochran u64 rate; 230d339b133SRichard Cochran u32 inca; 231d339b133SRichard Cochran 232c79e975eSRichard Cochran if (scaled_ppm < 0) { 233d339b133SRichard Cochran neg_adj = 1; 234c79e975eSRichard Cochran scaled_ppm = -scaled_ppm; 235d339b133SRichard Cochran } 236c79e975eSRichard Cochran rate = scaled_ppm; 237c79e975eSRichard Cochran rate <<= 13; 238c79e975eSRichard Cochran rate = div_u64(rate, 15625); 239d339b133SRichard Cochran 240d339b133SRichard Cochran inca = rate & INCVALUE_MASK; 241d339b133SRichard Cochran if (neg_adj) 242d339b133SRichard Cochran inca |= ISGN; 243d339b133SRichard Cochran 244d339b133SRichard Cochran wr32(E1000_TIMINCA, inca); 245d339b133SRichard Cochran 246d339b133SRichard Cochran return 0; 247d339b133SRichard Cochran } 248d339b133SRichard Cochran 249e57b8bdbSMatthew Vick static int igb_ptp_adjtime_82576(struct ptp_clock_info *ptp, s64 delta) 250d339b133SRichard Cochran { 251a79f4f88SMatthew Vick struct igb_adapter *igb = container_of(ptp, struct igb_adapter, 252a79f4f88SMatthew Vick ptp_caps); 253d339b133SRichard Cochran unsigned long flags; 254d339b133SRichard Cochran 255d339b133SRichard Cochran spin_lock_irqsave(&igb->tmreg_lock, flags); 2565ee698e3SRichard Cochran timecounter_adjtime(&igb->tc, delta); 257d339b133SRichard Cochran spin_unlock_irqrestore(&igb->tmreg_lock, flags); 258d339b133SRichard Cochran 259d339b133SRichard Cochran return 0; 260d339b133SRichard Cochran } 261d339b133SRichard Cochran 262e57b8bdbSMatthew Vick static int igb_ptp_adjtime_i210(struct ptp_clock_info *ptp, s64 delta) 263e57b8bdbSMatthew Vick { 264e57b8bdbSMatthew Vick struct igb_adapter *igb = container_of(ptp, struct igb_adapter, 265e57b8bdbSMatthew Vick ptp_caps); 266e57b8bdbSMatthew Vick unsigned long flags; 267d4c496feSRichard Cochran struct timespec64 now, then = ns_to_timespec64(delta); 268e57b8bdbSMatthew Vick 269e57b8bdbSMatthew Vick spin_lock_irqsave(&igb->tmreg_lock, flags); 270e57b8bdbSMatthew Vick 271e57b8bdbSMatthew Vick igb_ptp_read_i210(igb, &now); 272d4c496feSRichard Cochran now = timespec64_add(now, then); 273d4c496feSRichard Cochran igb_ptp_write_i210(igb, (const struct timespec64 *)&now); 274e57b8bdbSMatthew Vick 275e57b8bdbSMatthew Vick spin_unlock_irqrestore(&igb->tmreg_lock, flags); 276e57b8bdbSMatthew Vick 277e57b8bdbSMatthew Vick return 0; 278e57b8bdbSMatthew Vick } 279e57b8bdbSMatthew Vick 280cff8ba28SMiroslav Lichvar static int igb_ptp_gettimex_82576(struct ptp_clock_info *ptp, 281cff8ba28SMiroslav Lichvar struct timespec64 *ts, 282cff8ba28SMiroslav Lichvar struct ptp_system_timestamp *sts) 283d339b133SRichard Cochran { 284a79f4f88SMatthew Vick struct igb_adapter *igb = container_of(ptp, struct igb_adapter, 285a79f4f88SMatthew Vick ptp_caps); 286cff8ba28SMiroslav Lichvar struct e1000_hw *hw = &igb->hw; 287a79f4f88SMatthew Vick unsigned long flags; 288cff8ba28SMiroslav Lichvar u32 lo, hi; 289d339b133SRichard Cochran u64 ns; 290d339b133SRichard Cochran 291d339b133SRichard Cochran spin_lock_irqsave(&igb->tmreg_lock, flags); 292d339b133SRichard Cochran 293cff8ba28SMiroslav Lichvar ptp_read_system_prets(sts); 294cff8ba28SMiroslav Lichvar lo = rd32(E1000_SYSTIML); 295cff8ba28SMiroslav Lichvar ptp_read_system_postts(sts); 296cff8ba28SMiroslav Lichvar hi = rd32(E1000_SYSTIMH); 297cff8ba28SMiroslav Lichvar 298cff8ba28SMiroslav Lichvar ns = timecounter_cyc2time(&igb->tc, ((u64)hi << 32) | lo); 299d339b133SRichard Cochran 300d339b133SRichard Cochran spin_unlock_irqrestore(&igb->tmreg_lock, flags); 301d339b133SRichard Cochran 302350f66d5SRichard Cochran *ts = ns_to_timespec64(ns); 303d339b133SRichard Cochran 304d339b133SRichard Cochran return 0; 305d339b133SRichard Cochran } 306d339b133SRichard Cochran 307cff8ba28SMiroslav Lichvar static int igb_ptp_gettimex_82580(struct ptp_clock_info *ptp, 308cff8ba28SMiroslav Lichvar struct timespec64 *ts, 309cff8ba28SMiroslav Lichvar struct ptp_system_timestamp *sts) 310e57b8bdbSMatthew Vick { 311e57b8bdbSMatthew Vick struct igb_adapter *igb = container_of(ptp, struct igb_adapter, 312e57b8bdbSMatthew Vick ptp_caps); 313cff8ba28SMiroslav Lichvar struct e1000_hw *hw = &igb->hw; 314cff8ba28SMiroslav Lichvar unsigned long flags; 315cff8ba28SMiroslav Lichvar u32 lo, hi; 316cff8ba28SMiroslav Lichvar u64 ns; 317cff8ba28SMiroslav Lichvar 318cff8ba28SMiroslav Lichvar spin_lock_irqsave(&igb->tmreg_lock, flags); 319cff8ba28SMiroslav Lichvar 320cff8ba28SMiroslav Lichvar ptp_read_system_prets(sts); 321cff8ba28SMiroslav Lichvar rd32(E1000_SYSTIMR); 322cff8ba28SMiroslav Lichvar ptp_read_system_postts(sts); 323cff8ba28SMiroslav Lichvar lo = rd32(E1000_SYSTIML); 324cff8ba28SMiroslav Lichvar hi = rd32(E1000_SYSTIMH); 325cff8ba28SMiroslav Lichvar 326cff8ba28SMiroslav Lichvar ns = timecounter_cyc2time(&igb->tc, ((u64)hi << 32) | lo); 327cff8ba28SMiroslav Lichvar 328cff8ba28SMiroslav Lichvar spin_unlock_irqrestore(&igb->tmreg_lock, flags); 329cff8ba28SMiroslav Lichvar 330cff8ba28SMiroslav Lichvar *ts = ns_to_timespec64(ns); 331cff8ba28SMiroslav Lichvar 332cff8ba28SMiroslav Lichvar return 0; 333cff8ba28SMiroslav Lichvar } 334cff8ba28SMiroslav Lichvar 335cff8ba28SMiroslav Lichvar static int igb_ptp_gettimex_i210(struct ptp_clock_info *ptp, 336cff8ba28SMiroslav Lichvar struct timespec64 *ts, 337cff8ba28SMiroslav Lichvar struct ptp_system_timestamp *sts) 338cff8ba28SMiroslav Lichvar { 339cff8ba28SMiroslav Lichvar struct igb_adapter *igb = container_of(ptp, struct igb_adapter, 340cff8ba28SMiroslav Lichvar ptp_caps); 341cff8ba28SMiroslav Lichvar struct e1000_hw *hw = &igb->hw; 342e57b8bdbSMatthew Vick unsigned long flags; 343e57b8bdbSMatthew Vick 344e57b8bdbSMatthew Vick spin_lock_irqsave(&igb->tmreg_lock, flags); 345e57b8bdbSMatthew Vick 346cff8ba28SMiroslav Lichvar ptp_read_system_prets(sts); 347cff8ba28SMiroslav Lichvar rd32(E1000_SYSTIMR); 348cff8ba28SMiroslav Lichvar ptp_read_system_postts(sts); 349cff8ba28SMiroslav Lichvar ts->tv_nsec = rd32(E1000_SYSTIML); 350cff8ba28SMiroslav Lichvar ts->tv_sec = rd32(E1000_SYSTIMH); 351e57b8bdbSMatthew Vick 352e57b8bdbSMatthew Vick spin_unlock_irqrestore(&igb->tmreg_lock, flags); 353e57b8bdbSMatthew Vick 354e57b8bdbSMatthew Vick return 0; 355e57b8bdbSMatthew Vick } 356e57b8bdbSMatthew Vick 357e57b8bdbSMatthew Vick static int igb_ptp_settime_82576(struct ptp_clock_info *ptp, 358d4c496feSRichard Cochran const struct timespec64 *ts) 359d339b133SRichard Cochran { 360a79f4f88SMatthew Vick struct igb_adapter *igb = container_of(ptp, struct igb_adapter, 361a79f4f88SMatthew Vick ptp_caps); 362d339b133SRichard Cochran unsigned long flags; 363a79f4f88SMatthew Vick u64 ns; 364d339b133SRichard Cochran 365350f66d5SRichard Cochran ns = timespec64_to_ns(ts); 366d339b133SRichard Cochran 367d339b133SRichard Cochran spin_lock_irqsave(&igb->tmreg_lock, flags); 368d339b133SRichard Cochran 369d339b133SRichard Cochran timecounter_init(&igb->tc, &igb->cc, ns); 370d339b133SRichard Cochran 371d339b133SRichard Cochran spin_unlock_irqrestore(&igb->tmreg_lock, flags); 372d339b133SRichard Cochran 373d339b133SRichard Cochran return 0; 374d339b133SRichard Cochran } 375d339b133SRichard Cochran 376e57b8bdbSMatthew Vick static int igb_ptp_settime_i210(struct ptp_clock_info *ptp, 377d4c496feSRichard Cochran const struct timespec64 *ts) 378e57b8bdbSMatthew Vick { 379e57b8bdbSMatthew Vick struct igb_adapter *igb = container_of(ptp, struct igb_adapter, 380e57b8bdbSMatthew Vick ptp_caps); 381e57b8bdbSMatthew Vick unsigned long flags; 382e57b8bdbSMatthew Vick 383e57b8bdbSMatthew Vick spin_lock_irqsave(&igb->tmreg_lock, flags); 384e57b8bdbSMatthew Vick 385e57b8bdbSMatthew Vick igb_ptp_write_i210(igb, ts); 386e57b8bdbSMatthew Vick 387e57b8bdbSMatthew Vick spin_unlock_irqrestore(&igb->tmreg_lock, flags); 388e57b8bdbSMatthew Vick 389e57b8bdbSMatthew Vick return 0; 390e57b8bdbSMatthew Vick } 391e57b8bdbSMatthew Vick 392720db4ffSRichard Cochran static void igb_pin_direction(int pin, int input, u32 *ctrl, u32 *ctrl_ext) 393720db4ffSRichard Cochran { 394720db4ffSRichard Cochran u32 *ptr = pin < 2 ? ctrl : ctrl_ext; 395b23c0cc5SAlexander Duyck static const u32 mask[IGB_N_SDP] = { 396720db4ffSRichard Cochran E1000_CTRL_SDP0_DIR, 397720db4ffSRichard Cochran E1000_CTRL_SDP1_DIR, 398720db4ffSRichard Cochran E1000_CTRL_EXT_SDP2_DIR, 399720db4ffSRichard Cochran E1000_CTRL_EXT_SDP3_DIR, 400720db4ffSRichard Cochran }; 401720db4ffSRichard Cochran 402720db4ffSRichard Cochran if (input) 403720db4ffSRichard Cochran *ptr &= ~mask[pin]; 404720db4ffSRichard Cochran else 405720db4ffSRichard Cochran *ptr |= mask[pin]; 406720db4ffSRichard Cochran } 407720db4ffSRichard Cochran 408720db4ffSRichard Cochran static void igb_pin_extts(struct igb_adapter *igb, int chan, int pin) 409720db4ffSRichard Cochran { 410b23c0cc5SAlexander Duyck static const u32 aux0_sel_sdp[IGB_N_SDP] = { 411720db4ffSRichard Cochran AUX0_SEL_SDP0, AUX0_SEL_SDP1, AUX0_SEL_SDP2, AUX0_SEL_SDP3, 412720db4ffSRichard Cochran }; 413b23c0cc5SAlexander Duyck static const u32 aux1_sel_sdp[IGB_N_SDP] = { 414720db4ffSRichard Cochran AUX1_SEL_SDP0, AUX1_SEL_SDP1, AUX1_SEL_SDP2, AUX1_SEL_SDP3, 415720db4ffSRichard Cochran }; 416b23c0cc5SAlexander Duyck static const u32 ts_sdp_en[IGB_N_SDP] = { 417720db4ffSRichard Cochran TS_SDP0_EN, TS_SDP1_EN, TS_SDP2_EN, TS_SDP3_EN, 418720db4ffSRichard Cochran }; 419b23c0cc5SAlexander Duyck struct e1000_hw *hw = &igb->hw; 420720db4ffSRichard Cochran u32 ctrl, ctrl_ext, tssdp = 0; 421720db4ffSRichard Cochran 422720db4ffSRichard Cochran ctrl = rd32(E1000_CTRL); 423720db4ffSRichard Cochran ctrl_ext = rd32(E1000_CTRL_EXT); 424720db4ffSRichard Cochran tssdp = rd32(E1000_TSSDP); 425720db4ffSRichard Cochran 426720db4ffSRichard Cochran igb_pin_direction(pin, 1, &ctrl, &ctrl_ext); 427720db4ffSRichard Cochran 428720db4ffSRichard Cochran /* Make sure this pin is not enabled as an output. */ 429720db4ffSRichard Cochran tssdp &= ~ts_sdp_en[pin]; 430720db4ffSRichard Cochran 431720db4ffSRichard Cochran if (chan == 1) { 432720db4ffSRichard Cochran tssdp &= ~AUX1_SEL_SDP3; 433720db4ffSRichard Cochran tssdp |= aux1_sel_sdp[pin] | AUX1_TS_SDP_EN; 434720db4ffSRichard Cochran } else { 435720db4ffSRichard Cochran tssdp &= ~AUX0_SEL_SDP3; 436720db4ffSRichard Cochran tssdp |= aux0_sel_sdp[pin] | AUX0_TS_SDP_EN; 437720db4ffSRichard Cochran } 438720db4ffSRichard Cochran 439720db4ffSRichard Cochran wr32(E1000_TSSDP, tssdp); 440720db4ffSRichard Cochran wr32(E1000_CTRL, ctrl); 441720db4ffSRichard Cochran wr32(E1000_CTRL_EXT, ctrl_ext); 442720db4ffSRichard Cochran } 443720db4ffSRichard Cochran 44430c72916SRichard Cochran static void igb_pin_perout(struct igb_adapter *igb, int chan, int pin, int freq) 445720db4ffSRichard Cochran { 446b23c0cc5SAlexander Duyck static const u32 aux0_sel_sdp[IGB_N_SDP] = { 447720db4ffSRichard Cochran AUX0_SEL_SDP0, AUX0_SEL_SDP1, AUX0_SEL_SDP2, AUX0_SEL_SDP3, 448720db4ffSRichard Cochran }; 449b23c0cc5SAlexander Duyck static const u32 aux1_sel_sdp[IGB_N_SDP] = { 450720db4ffSRichard Cochran AUX1_SEL_SDP0, AUX1_SEL_SDP1, AUX1_SEL_SDP2, AUX1_SEL_SDP3, 451720db4ffSRichard Cochran }; 452b23c0cc5SAlexander Duyck static const u32 ts_sdp_en[IGB_N_SDP] = { 453720db4ffSRichard Cochran TS_SDP0_EN, TS_SDP1_EN, TS_SDP2_EN, TS_SDP3_EN, 454720db4ffSRichard Cochran }; 455b23c0cc5SAlexander Duyck static const u32 ts_sdp_sel_tt0[IGB_N_SDP] = { 456720db4ffSRichard Cochran TS_SDP0_SEL_TT0, TS_SDP1_SEL_TT0, 457720db4ffSRichard Cochran TS_SDP2_SEL_TT0, TS_SDP3_SEL_TT0, 458720db4ffSRichard Cochran }; 459b23c0cc5SAlexander Duyck static const u32 ts_sdp_sel_tt1[IGB_N_SDP] = { 460720db4ffSRichard Cochran TS_SDP0_SEL_TT1, TS_SDP1_SEL_TT1, 461720db4ffSRichard Cochran TS_SDP2_SEL_TT1, TS_SDP3_SEL_TT1, 462720db4ffSRichard Cochran }; 46330c72916SRichard Cochran static const u32 ts_sdp_sel_fc0[IGB_N_SDP] = { 46430c72916SRichard Cochran TS_SDP0_SEL_FC0, TS_SDP1_SEL_FC0, 46530c72916SRichard Cochran TS_SDP2_SEL_FC0, TS_SDP3_SEL_FC0, 46630c72916SRichard Cochran }; 46730c72916SRichard Cochran static const u32 ts_sdp_sel_fc1[IGB_N_SDP] = { 46830c72916SRichard Cochran TS_SDP0_SEL_FC1, TS_SDP1_SEL_FC1, 46930c72916SRichard Cochran TS_SDP2_SEL_FC1, TS_SDP3_SEL_FC1, 47030c72916SRichard Cochran }; 471b23c0cc5SAlexander Duyck static const u32 ts_sdp_sel_clr[IGB_N_SDP] = { 472720db4ffSRichard Cochran TS_SDP0_SEL_FC1, TS_SDP1_SEL_FC1, 473720db4ffSRichard Cochran TS_SDP2_SEL_FC1, TS_SDP3_SEL_FC1, 474720db4ffSRichard Cochran }; 475b23c0cc5SAlexander Duyck struct e1000_hw *hw = &igb->hw; 476720db4ffSRichard Cochran u32 ctrl, ctrl_ext, tssdp = 0; 477720db4ffSRichard Cochran 478720db4ffSRichard Cochran ctrl = rd32(E1000_CTRL); 479720db4ffSRichard Cochran ctrl_ext = rd32(E1000_CTRL_EXT); 480720db4ffSRichard Cochran tssdp = rd32(E1000_TSSDP); 481720db4ffSRichard Cochran 482720db4ffSRichard Cochran igb_pin_direction(pin, 0, &ctrl, &ctrl_ext); 483720db4ffSRichard Cochran 484720db4ffSRichard Cochran /* Make sure this pin is not enabled as an input. */ 485720db4ffSRichard Cochran if ((tssdp & AUX0_SEL_SDP3) == aux0_sel_sdp[pin]) 486720db4ffSRichard Cochran tssdp &= ~AUX0_TS_SDP_EN; 487720db4ffSRichard Cochran 488720db4ffSRichard Cochran if ((tssdp & AUX1_SEL_SDP3) == aux1_sel_sdp[pin]) 489720db4ffSRichard Cochran tssdp &= ~AUX1_TS_SDP_EN; 490720db4ffSRichard Cochran 491720db4ffSRichard Cochran tssdp &= ~ts_sdp_sel_clr[pin]; 49230c72916SRichard Cochran if (freq) { 49330c72916SRichard Cochran if (chan == 1) 49430c72916SRichard Cochran tssdp |= ts_sdp_sel_fc1[pin]; 49530c72916SRichard Cochran else 49630c72916SRichard Cochran tssdp |= ts_sdp_sel_fc0[pin]; 49730c72916SRichard Cochran } else { 498720db4ffSRichard Cochran if (chan == 1) 499720db4ffSRichard Cochran tssdp |= ts_sdp_sel_tt1[pin]; 500720db4ffSRichard Cochran else 501720db4ffSRichard Cochran tssdp |= ts_sdp_sel_tt0[pin]; 50230c72916SRichard Cochran } 503720db4ffSRichard Cochran tssdp |= ts_sdp_en[pin]; 504720db4ffSRichard Cochran 505720db4ffSRichard Cochran wr32(E1000_TSSDP, tssdp); 506720db4ffSRichard Cochran wr32(E1000_CTRL, ctrl); 507720db4ffSRichard Cochran wr32(E1000_CTRL_EXT, ctrl_ext); 508720db4ffSRichard Cochran } 509720db4ffSRichard Cochran 51000c65578SRichard Cochran static int igb_ptp_feature_enable_i210(struct ptp_clock_info *ptp, 51100c65578SRichard Cochran struct ptp_clock_request *rq, int on) 51200c65578SRichard Cochran { 51300c65578SRichard Cochran struct igb_adapter *igb = 51400c65578SRichard Cochran container_of(ptp, struct igb_adapter, ptp_caps); 51500c65578SRichard Cochran struct e1000_hw *hw = &igb->hw; 51630c72916SRichard Cochran u32 tsauxc, tsim, tsauxc_mask, tsim_mask, trgttiml, trgttimh, freqout; 51700c65578SRichard Cochran unsigned long flags; 51840c9b079SArnd Bergmann struct timespec64 ts; 51930c72916SRichard Cochran int use_freq = 0, pin = -1; 520720db4ffSRichard Cochran s64 ns; 52100c65578SRichard Cochran 52200c65578SRichard Cochran switch (rq->type) { 523720db4ffSRichard Cochran case PTP_CLK_REQ_EXTTS: 5246edd110bSJacob Keller /* Reject requests with unsupported flags */ 5256edd110bSJacob Keller if (rq->extts.flags & ~(PTP_ENABLE_FEATURE | 5266edd110bSJacob Keller PTP_RISING_EDGE | 5276138e687SRichard Cochran PTP_FALLING_EDGE | 5286138e687SRichard Cochran PTP_STRICT_FLAGS)) 5296edd110bSJacob Keller return -EOPNOTSUPP; 5306edd110bSJacob Keller 5315a450eb3SRichard Cochran /* Reject requests failing to enable both edges. */ 5325a450eb3SRichard Cochran if ((rq->extts.flags & PTP_STRICT_FLAGS) && 5335a450eb3SRichard Cochran (rq->extts.flags & PTP_ENABLE_FEATURE) && 5345a450eb3SRichard Cochran (rq->extts.flags & PTP_EXTTS_EDGES) != PTP_EXTTS_EDGES) 5355a450eb3SRichard Cochran return -EOPNOTSUPP; 5365a450eb3SRichard Cochran 537720db4ffSRichard Cochran if (on) { 538720db4ffSRichard Cochran pin = ptp_find_pin(igb->ptp_clock, PTP_PF_EXTTS, 539720db4ffSRichard Cochran rq->extts.index); 540720db4ffSRichard Cochran if (pin < 0) 541720db4ffSRichard Cochran return -EBUSY; 542720db4ffSRichard Cochran } 543720db4ffSRichard Cochran if (rq->extts.index == 1) { 544720db4ffSRichard Cochran tsauxc_mask = TSAUXC_EN_TS1; 545720db4ffSRichard Cochran tsim_mask = TSINTR_AUTT1; 546720db4ffSRichard Cochran } else { 547720db4ffSRichard Cochran tsauxc_mask = TSAUXC_EN_TS0; 548720db4ffSRichard Cochran tsim_mask = TSINTR_AUTT0; 549720db4ffSRichard Cochran } 550720db4ffSRichard Cochran spin_lock_irqsave(&igb->tmreg_lock, flags); 551720db4ffSRichard Cochran tsauxc = rd32(E1000_TSAUXC); 552720db4ffSRichard Cochran tsim = rd32(E1000_TSIM); 553720db4ffSRichard Cochran if (on) { 554720db4ffSRichard Cochran igb_pin_extts(igb, rq->extts.index, pin); 555720db4ffSRichard Cochran tsauxc |= tsauxc_mask; 556720db4ffSRichard Cochran tsim |= tsim_mask; 557720db4ffSRichard Cochran } else { 558720db4ffSRichard Cochran tsauxc &= ~tsauxc_mask; 559720db4ffSRichard Cochran tsim &= ~tsim_mask; 560720db4ffSRichard Cochran } 561720db4ffSRichard Cochran wr32(E1000_TSAUXC, tsauxc); 562720db4ffSRichard Cochran wr32(E1000_TSIM, tsim); 563720db4ffSRichard Cochran spin_unlock_irqrestore(&igb->tmreg_lock, flags); 564720db4ffSRichard Cochran return 0; 565720db4ffSRichard Cochran 566720db4ffSRichard Cochran case PTP_CLK_REQ_PEROUT: 5677f9048f1SJacob Keller /* Reject requests with unsupported flags */ 5687f9048f1SJacob Keller if (rq->perout.flags) 5697f9048f1SJacob Keller return -EOPNOTSUPP; 5707f9048f1SJacob Keller 571720db4ffSRichard Cochran if (on) { 572720db4ffSRichard Cochran pin = ptp_find_pin(igb->ptp_clock, PTP_PF_PEROUT, 573720db4ffSRichard Cochran rq->perout.index); 574720db4ffSRichard Cochran if (pin < 0) 575720db4ffSRichard Cochran return -EBUSY; 576720db4ffSRichard Cochran } 577720db4ffSRichard Cochran ts.tv_sec = rq->perout.period.sec; 578720db4ffSRichard Cochran ts.tv_nsec = rq->perout.period.nsec; 57940c9b079SArnd Bergmann ns = timespec64_to_ns(&ts); 580720db4ffSRichard Cochran ns = ns >> 1; 581569f3b3dSRoland Hii if (on && ((ns <= 70000000LL) || (ns == 125000000LL) || 582569f3b3dSRoland Hii (ns == 250000000LL) || (ns == 500000000LL))) { 58330c72916SRichard Cochran if (ns < 8LL) 584720db4ffSRichard Cochran return -EINVAL; 58530c72916SRichard Cochran use_freq = 1; 586720db4ffSRichard Cochran } 58740c9b079SArnd Bergmann ts = ns_to_timespec64(ns); 588720db4ffSRichard Cochran if (rq->perout.index == 1) { 58930c72916SRichard Cochran if (use_freq) { 59030c72916SRichard Cochran tsauxc_mask = TSAUXC_EN_CLK1 | TSAUXC_ST1; 59130c72916SRichard Cochran tsim_mask = 0; 59230c72916SRichard Cochran } else { 593720db4ffSRichard Cochran tsauxc_mask = TSAUXC_EN_TT1; 594720db4ffSRichard Cochran tsim_mask = TSINTR_TT1; 59530c72916SRichard Cochran } 596720db4ffSRichard Cochran trgttiml = E1000_TRGTTIML1; 597720db4ffSRichard Cochran trgttimh = E1000_TRGTTIMH1; 59830c72916SRichard Cochran freqout = E1000_FREQOUT1; 59930c72916SRichard Cochran } else { 60030c72916SRichard Cochran if (use_freq) { 60130c72916SRichard Cochran tsauxc_mask = TSAUXC_EN_CLK0 | TSAUXC_ST0; 60230c72916SRichard Cochran tsim_mask = 0; 603720db4ffSRichard Cochran } else { 604720db4ffSRichard Cochran tsauxc_mask = TSAUXC_EN_TT0; 605720db4ffSRichard Cochran tsim_mask = TSINTR_TT0; 60630c72916SRichard Cochran } 607720db4ffSRichard Cochran trgttiml = E1000_TRGTTIML0; 608720db4ffSRichard Cochran trgttimh = E1000_TRGTTIMH0; 60930c72916SRichard Cochran freqout = E1000_FREQOUT0; 610720db4ffSRichard Cochran } 611720db4ffSRichard Cochran spin_lock_irqsave(&igb->tmreg_lock, flags); 612720db4ffSRichard Cochran tsauxc = rd32(E1000_TSAUXC); 613720db4ffSRichard Cochran tsim = rd32(E1000_TSIM); 61430c72916SRichard Cochran if (rq->perout.index == 1) { 61530c72916SRichard Cochran tsauxc &= ~(TSAUXC_EN_TT1 | TSAUXC_EN_CLK1 | TSAUXC_ST1); 61630c72916SRichard Cochran tsim &= ~TSINTR_TT1; 61730c72916SRichard Cochran } else { 61830c72916SRichard Cochran tsauxc &= ~(TSAUXC_EN_TT0 | TSAUXC_EN_CLK0 | TSAUXC_ST0); 61930c72916SRichard Cochran tsim &= ~TSINTR_TT0; 62030c72916SRichard Cochran } 621720db4ffSRichard Cochran if (on) { 622720db4ffSRichard Cochran int i = rq->perout.index; 62330c72916SRichard Cochran igb_pin_perout(igb, i, pin, use_freq); 624720db4ffSRichard Cochran igb->perout[i].start.tv_sec = rq->perout.start.sec; 625720db4ffSRichard Cochran igb->perout[i].start.tv_nsec = rq->perout.start.nsec; 626720db4ffSRichard Cochran igb->perout[i].period.tv_sec = ts.tv_sec; 627720db4ffSRichard Cochran igb->perout[i].period.tv_nsec = ts.tv_nsec; 62858c98be1SRichard Cochran wr32(trgttimh, rq->perout.start.sec); 62958c98be1SRichard Cochran wr32(trgttiml, rq->perout.start.nsec); 63030c72916SRichard Cochran if (use_freq) 63130c72916SRichard Cochran wr32(freqout, ns); 632720db4ffSRichard Cochran tsauxc |= tsauxc_mask; 633720db4ffSRichard Cochran tsim |= tsim_mask; 634720db4ffSRichard Cochran } 635720db4ffSRichard Cochran wr32(E1000_TSAUXC, tsauxc); 636720db4ffSRichard Cochran wr32(E1000_TSIM, tsim); 637720db4ffSRichard Cochran spin_unlock_irqrestore(&igb->tmreg_lock, flags); 638720db4ffSRichard Cochran return 0; 639720db4ffSRichard Cochran 64000c65578SRichard Cochran case PTP_CLK_REQ_PPS: 64100c65578SRichard Cochran spin_lock_irqsave(&igb->tmreg_lock, flags); 64200c65578SRichard Cochran tsim = rd32(E1000_TSIM); 64300c65578SRichard Cochran if (on) 64400c65578SRichard Cochran tsim |= TSINTR_SYS_WRAP; 64500c65578SRichard Cochran else 64600c65578SRichard Cochran tsim &= ~TSINTR_SYS_WRAP; 647ac28b41aSJacob Keller igb->pps_sys_wrap_on = !!on; 64800c65578SRichard Cochran wr32(E1000_TSIM, tsim); 64900c65578SRichard Cochran spin_unlock_irqrestore(&igb->tmreg_lock, flags); 65000c65578SRichard Cochran return 0; 65100c65578SRichard Cochran } 65200c65578SRichard Cochran 65300c65578SRichard Cochran return -EOPNOTSUPP; 65400c65578SRichard Cochran } 65500c65578SRichard Cochran 656102be52fSJacob Keller static int igb_ptp_feature_enable(struct ptp_clock_info *ptp, 657d339b133SRichard Cochran struct ptp_clock_request *rq, int on) 658d339b133SRichard Cochran { 659d339b133SRichard Cochran return -EOPNOTSUPP; 660d339b133SRichard Cochran } 661d339b133SRichard Cochran 662720db4ffSRichard Cochran static int igb_ptp_verify_pin(struct ptp_clock_info *ptp, unsigned int pin, 663720db4ffSRichard Cochran enum ptp_pin_function func, unsigned int chan) 664720db4ffSRichard Cochran { 665720db4ffSRichard Cochran switch (func) { 666720db4ffSRichard Cochran case PTP_PF_NONE: 667720db4ffSRichard Cochran case PTP_PF_EXTTS: 668720db4ffSRichard Cochran case PTP_PF_PEROUT: 669720db4ffSRichard Cochran break; 670720db4ffSRichard Cochran case PTP_PF_PHYSYNC: 671720db4ffSRichard Cochran return -1; 672720db4ffSRichard Cochran } 673720db4ffSRichard Cochran return 0; 674720db4ffSRichard Cochran } 675720db4ffSRichard Cochran 6761f6e8178SMatthew Vick /** 6771f6e8178SMatthew Vick * igb_ptp_tx_work 6781f6e8178SMatthew Vick * @work: pointer to work struct 6791f6e8178SMatthew Vick * 6801f6e8178SMatthew Vick * This work function polls the TSYNCTXCTL valid bit to determine when a 6811f6e8178SMatthew Vick * timestamp has been taken for the current stored skb. 682b980ac18SJeff Kirsher **/ 683167f3f71SJeff Kirsher static void igb_ptp_tx_work(struct work_struct *work) 6841f6e8178SMatthew Vick { 6851f6e8178SMatthew Vick struct igb_adapter *adapter = container_of(work, struct igb_adapter, 6861f6e8178SMatthew Vick ptp_tx_work); 6871f6e8178SMatthew Vick struct e1000_hw *hw = &adapter->hw; 6881f6e8178SMatthew Vick u32 tsynctxctl; 6891f6e8178SMatthew Vick 6901f6e8178SMatthew Vick if (!adapter->ptp_tx_skb) 6911f6e8178SMatthew Vick return; 6921f6e8178SMatthew Vick 693428f1f71SMatthew Vick if (time_is_before_jiffies(adapter->ptp_tx_start + 694428f1f71SMatthew Vick IGB_PTP_TX_TIMEOUT)) { 695428f1f71SMatthew Vick dev_kfree_skb_any(adapter->ptp_tx_skb); 696428f1f71SMatthew Vick adapter->ptp_tx_skb = NULL; 697ed4420a3SJakub Kicinski clear_bit_unlock(__IGB_PTP_TX_IN_PROGRESS, &adapter->state); 698428f1f71SMatthew Vick adapter->tx_hwtstamp_timeouts++; 6993a532852SDaniel Hua /* Clear the tx valid bit in TSYNCTXCTL register to enable 7003a532852SDaniel Hua * interrupt 7013a532852SDaniel Hua */ 7023a532852SDaniel Hua rd32(E1000_TXSTMPH); 703c5ffe7e1SJakub Kicinski dev_warn(&adapter->pdev->dev, "clearing Tx timestamp hang\n"); 704428f1f71SMatthew Vick return; 705428f1f71SMatthew Vick } 706428f1f71SMatthew Vick 7071f6e8178SMatthew Vick tsynctxctl = rd32(E1000_TSYNCTXCTL); 7081f6e8178SMatthew Vick if (tsynctxctl & E1000_TSYNCTXCTL_VALID) 7091f6e8178SMatthew Vick igb_ptp_tx_hwtstamp(adapter); 7101f6e8178SMatthew Vick else 7111f6e8178SMatthew Vick /* reschedule to check later */ 7121f6e8178SMatthew Vick schedule_work(&adapter->ptp_tx_work); 7131f6e8178SMatthew Vick } 7141f6e8178SMatthew Vick 715a79f4f88SMatthew Vick static void igb_ptp_overflow_check(struct work_struct *work) 716d339b133SRichard Cochran { 717d339b133SRichard Cochran struct igb_adapter *igb = 718a79f4f88SMatthew Vick container_of(work, struct igb_adapter, ptp_overflow_work.work); 719d4c496feSRichard Cochran struct timespec64 ts; 720cff8ba28SMiroslav Lichvar u64 ns; 721d339b133SRichard Cochran 722cff8ba28SMiroslav Lichvar /* Update the timecounter */ 723cff8ba28SMiroslav Lichvar ns = timecounter_read(&igb->tc); 724d339b133SRichard Cochran 725cff8ba28SMiroslav Lichvar ts = ns_to_timespec64(ns); 72632eaf120SDavid S. Miller pr_debug("igb overflow check at %lld.%09lu\n", 72732eaf120SDavid S. Miller (long long) ts.tv_sec, ts.tv_nsec); 728d339b133SRichard Cochran 729a79f4f88SMatthew Vick schedule_delayed_work(&igb->ptp_overflow_work, 730a79f4f88SMatthew Vick IGB_SYSTIM_OVERFLOW_PERIOD); 731a79f4f88SMatthew Vick } 732a79f4f88SMatthew Vick 733a79f4f88SMatthew Vick /** 734fc580751SMatthew Vick * igb_ptp_rx_hang - detect error case when Rx timestamp registers latched 735fc580751SMatthew Vick * @adapter: private network adapter structure 736fc580751SMatthew Vick * 737fc580751SMatthew Vick * This watchdog task is scheduled to detect error case where hardware has 738fc580751SMatthew Vick * dropped an Rx packet that was timestamped when the ring is full. The 739fc580751SMatthew Vick * particular error is rare but leaves the device in a state unable to timestamp 740fc580751SMatthew Vick * any future packets. 741b980ac18SJeff Kirsher **/ 742fc580751SMatthew Vick void igb_ptp_rx_hang(struct igb_adapter *adapter) 743fc580751SMatthew Vick { 744fc580751SMatthew Vick struct e1000_hw *hw = &adapter->hw; 745fc580751SMatthew Vick u32 tsyncrxctl = rd32(E1000_TSYNCRXCTL); 746fc580751SMatthew Vick unsigned long rx_event; 747fc580751SMatthew Vick 748462f1188SJacob Keller /* Other hardware uses per-packet timestamps */ 749fc580751SMatthew Vick if (hw->mac.type != e1000_82576) 750fc580751SMatthew Vick return; 751fc580751SMatthew Vick 752fc580751SMatthew Vick /* If we don't have a valid timestamp in the registers, just update the 753fc580751SMatthew Vick * timeout counter and exit 754fc580751SMatthew Vick */ 755fc580751SMatthew Vick if (!(tsyncrxctl & E1000_TSYNCRXCTL_VALID)) { 756fc580751SMatthew Vick adapter->last_rx_ptp_check = jiffies; 757fc580751SMatthew Vick return; 758fc580751SMatthew Vick } 759fc580751SMatthew Vick 760fc580751SMatthew Vick /* Determine the most recent watchdog or rx_timestamp event */ 761fc580751SMatthew Vick rx_event = adapter->last_rx_ptp_check; 7625499a968SJakub Kicinski if (time_after(adapter->last_rx_timestamp, rx_event)) 7635499a968SJakub Kicinski rx_event = adapter->last_rx_timestamp; 764fc580751SMatthew Vick 765fc580751SMatthew Vick /* Only need to read the high RXSTMP register to clear the lock */ 766fc580751SMatthew Vick if (time_is_before_jiffies(rx_event + 5 * HZ)) { 767fc580751SMatthew Vick rd32(E1000_RXSTMPH); 768fc580751SMatthew Vick adapter->last_rx_ptp_check = jiffies; 769fc580751SMatthew Vick adapter->rx_hwtstamp_cleared++; 770c5ffe7e1SJakub Kicinski dev_warn(&adapter->pdev->dev, "clearing Rx timestamp hang\n"); 771fc580751SMatthew Vick } 772fc580751SMatthew Vick } 773fc580751SMatthew Vick 774fc580751SMatthew Vick /** 775e5f36ad1SJacob Keller * igb_ptp_tx_hang - detect error case where Tx timestamp never finishes 776e5f36ad1SJacob Keller * @adapter: private network adapter structure 777e5f36ad1SJacob Keller */ 778e5f36ad1SJacob Keller void igb_ptp_tx_hang(struct igb_adapter *adapter) 779e5f36ad1SJacob Keller { 7803a532852SDaniel Hua struct e1000_hw *hw = &adapter->hw; 781e5f36ad1SJacob Keller bool timeout = time_is_before_jiffies(adapter->ptp_tx_start + 782e5f36ad1SJacob Keller IGB_PTP_TX_TIMEOUT); 783e5f36ad1SJacob Keller 784e5f36ad1SJacob Keller if (!adapter->ptp_tx_skb) 785e5f36ad1SJacob Keller return; 786e5f36ad1SJacob Keller 787e5f36ad1SJacob Keller if (!test_bit(__IGB_PTP_TX_IN_PROGRESS, &adapter->state)) 788e5f36ad1SJacob Keller return; 789e5f36ad1SJacob Keller 790e5f36ad1SJacob Keller /* If we haven't received a timestamp within the timeout, it is 791e5f36ad1SJacob Keller * reasonable to assume that it will never occur, so we can unlock the 792e5f36ad1SJacob Keller * timestamp bit when this occurs. 793e5f36ad1SJacob Keller */ 794e5f36ad1SJacob Keller if (timeout) { 795e5f36ad1SJacob Keller cancel_work_sync(&adapter->ptp_tx_work); 796e5f36ad1SJacob Keller dev_kfree_skb_any(adapter->ptp_tx_skb); 797e5f36ad1SJacob Keller adapter->ptp_tx_skb = NULL; 798e5f36ad1SJacob Keller clear_bit_unlock(__IGB_PTP_TX_IN_PROGRESS, &adapter->state); 799e5f36ad1SJacob Keller adapter->tx_hwtstamp_timeouts++; 8003a532852SDaniel Hua /* Clear the tx valid bit in TSYNCTXCTL register to enable 8013a532852SDaniel Hua * interrupt 8023a532852SDaniel Hua */ 8033a532852SDaniel Hua rd32(E1000_TXSTMPH); 804e5f36ad1SJacob Keller dev_warn(&adapter->pdev->dev, "clearing Tx timestamp hang\n"); 805e5f36ad1SJacob Keller } 806e5f36ad1SJacob Keller } 807e5f36ad1SJacob Keller 808e5f36ad1SJacob Keller /** 809a79f4f88SMatthew Vick * igb_ptp_tx_hwtstamp - utility function which checks for TX time stamp 8101f6e8178SMatthew Vick * @adapter: Board private structure. 811a79f4f88SMatthew Vick * 812a79f4f88SMatthew Vick * If we were asked to do hardware stamping and such a time stamp is 813a79f4f88SMatthew Vick * available, then it must have been for this skb here because we only 814a79f4f88SMatthew Vick * allow only one such packet into the queue. 815b980ac18SJeff Kirsher **/ 816167f3f71SJeff Kirsher static void igb_ptp_tx_hwtstamp(struct igb_adapter *adapter) 817a79f4f88SMatthew Vick { 8184ccdc013SJacob Keller struct sk_buff *skb = adapter->ptp_tx_skb; 819a79f4f88SMatthew Vick struct e1000_hw *hw = &adapter->hw; 820a79f4f88SMatthew Vick struct skb_shared_hwtstamps shhwtstamps; 821a79f4f88SMatthew Vick u64 regval; 8223f544d2aSNathan Sullivan int adjust = 0; 823a79f4f88SMatthew Vick 824a79f4f88SMatthew Vick regval = rd32(E1000_TXSTMPL); 825a79f4f88SMatthew Vick regval |= (u64)rd32(E1000_TXSTMPH) << 32; 826a79f4f88SMatthew Vick 827a79f4f88SMatthew Vick igb_ptp_systim_to_hwtstamp(adapter, &shhwtstamps, regval); 8283f544d2aSNathan Sullivan /* adjust timestamp for the TX latency based on link speed */ 8293f544d2aSNathan Sullivan if (adapter->hw.mac.type == e1000_i210) { 8303f544d2aSNathan Sullivan switch (adapter->link_speed) { 8313f544d2aSNathan Sullivan case SPEED_10: 8323f544d2aSNathan Sullivan adjust = IGB_I210_TX_LATENCY_10; 8333f544d2aSNathan Sullivan break; 8343f544d2aSNathan Sullivan case SPEED_100: 8353f544d2aSNathan Sullivan adjust = IGB_I210_TX_LATENCY_100; 8363f544d2aSNathan Sullivan break; 8373f544d2aSNathan Sullivan case SPEED_1000: 8383f544d2aSNathan Sullivan adjust = IGB_I210_TX_LATENCY_1000; 8393f544d2aSNathan Sullivan break; 8403f544d2aSNathan Sullivan } 8413f544d2aSNathan Sullivan } 8423f544d2aSNathan Sullivan 8430066c8b6SKshitiz Gupta shhwtstamps.hwtstamp = 8440066c8b6SKshitiz Gupta ktime_add_ns(shhwtstamps.hwtstamp, adjust); 8453f544d2aSNathan Sullivan 8464ccdc013SJacob Keller /* Clear the lock early before calling skb_tstamp_tx so that 8474ccdc013SJacob Keller * applications are not woken up before the lock bit is clear. We use 8484ccdc013SJacob Keller * a copy of the skb pointer to ensure other threads can't change it 8494ccdc013SJacob Keller * while we're notifying the stack. 8504ccdc013SJacob Keller */ 8511f6e8178SMatthew Vick adapter->ptp_tx_skb = NULL; 852ed4420a3SJakub Kicinski clear_bit_unlock(__IGB_PTP_TX_IN_PROGRESS, &adapter->state); 8534ccdc013SJacob Keller 8544ccdc013SJacob Keller /* Notify the stack and free the skb after we've unlocked */ 8554ccdc013SJacob Keller skb_tstamp_tx(skb, &shhwtstamps); 8564ccdc013SJacob Keller dev_kfree_skb_any(skb); 857a79f4f88SMatthew Vick } 858a79f4f88SMatthew Vick 859b534550aSAlexander Duyck /** 860b534550aSAlexander Duyck * igb_ptp_rx_pktstamp - retrieve Rx per packet timestamp 861b534550aSAlexander Duyck * @q_vector: Pointer to interrupt specific structure 862b534550aSAlexander Duyck * @va: Pointer to address containing Rx buffer 863b534550aSAlexander Duyck * @skb: Buffer containing timestamp and packet 864b534550aSAlexander Duyck * 865b534550aSAlexander Duyck * This function is meant to retrieve a timestamp from the first buffer of an 866b534550aSAlexander Duyck * incoming frame. The value is stored in little endian format starting on 867b534550aSAlexander Duyck * byte 8. 868b980ac18SJeff Kirsher **/ 8693456fd53SAlexander Duyck void igb_ptp_rx_pktstamp(struct igb_q_vector *q_vector, void *va, 870b534550aSAlexander Duyck struct sk_buff *skb) 871b534550aSAlexander Duyck { 872ac61d515SAlexander Duyck __le64 *regval = (__le64 *)va; 8730066c8b6SKshitiz Gupta struct igb_adapter *adapter = q_vector->adapter; 8740066c8b6SKshitiz Gupta int adjust = 0; 875b534550aSAlexander Duyck 876b980ac18SJeff Kirsher /* The timestamp is recorded in little endian format. 877b534550aSAlexander Duyck * DWORD: 0 1 2 3 878b534550aSAlexander Duyck * Field: Reserved Reserved SYSTIML SYSTIMH 879b534550aSAlexander Duyck */ 8800066c8b6SKshitiz Gupta igb_ptp_systim_to_hwtstamp(adapter, skb_hwtstamps(skb), 881b534550aSAlexander Duyck le64_to_cpu(regval[1])); 8820066c8b6SKshitiz Gupta 8830066c8b6SKshitiz Gupta /* adjust timestamp for the RX latency based on link speed */ 8840066c8b6SKshitiz Gupta if (adapter->hw.mac.type == e1000_i210) { 8850066c8b6SKshitiz Gupta switch (adapter->link_speed) { 8860066c8b6SKshitiz Gupta case SPEED_10: 8870066c8b6SKshitiz Gupta adjust = IGB_I210_RX_LATENCY_10; 8880066c8b6SKshitiz Gupta break; 8890066c8b6SKshitiz Gupta case SPEED_100: 8900066c8b6SKshitiz Gupta adjust = IGB_I210_RX_LATENCY_100; 8910066c8b6SKshitiz Gupta break; 8920066c8b6SKshitiz Gupta case SPEED_1000: 8930066c8b6SKshitiz Gupta adjust = IGB_I210_RX_LATENCY_1000; 8940066c8b6SKshitiz Gupta break; 8950066c8b6SKshitiz Gupta } 8960066c8b6SKshitiz Gupta } 8970066c8b6SKshitiz Gupta skb_hwtstamps(skb)->hwtstamp = 8980066c8b6SKshitiz Gupta ktime_sub_ns(skb_hwtstamps(skb)->hwtstamp, adjust); 899b534550aSAlexander Duyck } 900b534550aSAlexander Duyck 901b534550aSAlexander Duyck /** 902b534550aSAlexander Duyck * igb_ptp_rx_rgtstamp - retrieve Rx timestamp stored in register 903b534550aSAlexander Duyck * @q_vector: Pointer to interrupt specific structure 904b534550aSAlexander Duyck * @skb: Buffer containing timestamp and packet 905b534550aSAlexander Duyck * 906b534550aSAlexander Duyck * This function is meant to retrieve a timestamp from the internal registers 907b534550aSAlexander Duyck * of the adapter and store it in the skb. 908b980ac18SJeff Kirsher **/ 909b534550aSAlexander Duyck void igb_ptp_rx_rgtstamp(struct igb_q_vector *q_vector, 910a79f4f88SMatthew Vick struct sk_buff *skb) 911a79f4f88SMatthew Vick { 912a79f4f88SMatthew Vick struct igb_adapter *adapter = q_vector->adapter; 913a79f4f88SMatthew Vick struct e1000_hw *hw = &adapter->hw; 914a79f4f88SMatthew Vick u64 regval; 9153f544d2aSNathan Sullivan int adjust = 0; 916a79f4f88SMatthew Vick 917b980ac18SJeff Kirsher /* If this bit is set, then the RX registers contain the time stamp. No 918a79f4f88SMatthew Vick * other packet will be time stamped until we read these registers, so 919a79f4f88SMatthew Vick * read the registers to make them available again. Because only one 920a79f4f88SMatthew Vick * packet can be time stamped at a time, we know that the register 921a79f4f88SMatthew Vick * values must belong to this one here and therefore we don't need to 922a79f4f88SMatthew Vick * compare any of the additional attributes stored for it. 923a79f4f88SMatthew Vick * 924a79f4f88SMatthew Vick * If nothing went wrong, then it should have a shared tx_flags that we 925a79f4f88SMatthew Vick * can turn into a skb_shared_hwtstamps. 926a79f4f88SMatthew Vick */ 927a79f4f88SMatthew Vick if (!(rd32(E1000_TSYNCRXCTL) & E1000_TSYNCRXCTL_VALID)) 928a79f4f88SMatthew Vick return; 929a79f4f88SMatthew Vick 930a79f4f88SMatthew Vick regval = rd32(E1000_RXSTMPL); 931a79f4f88SMatthew Vick regval |= (u64)rd32(E1000_RXSTMPH) << 32; 932a79f4f88SMatthew Vick 933a79f4f88SMatthew Vick igb_ptp_systim_to_hwtstamp(adapter, skb_hwtstamps(skb), regval); 9345499a968SJakub Kicinski 9353f544d2aSNathan Sullivan /* adjust timestamp for the RX latency based on link speed */ 9363f544d2aSNathan Sullivan if (adapter->hw.mac.type == e1000_i210) { 9373f544d2aSNathan Sullivan switch (adapter->link_speed) { 9383f544d2aSNathan Sullivan case SPEED_10: 9393f544d2aSNathan Sullivan adjust = IGB_I210_RX_LATENCY_10; 9403f544d2aSNathan Sullivan break; 9413f544d2aSNathan Sullivan case SPEED_100: 9423f544d2aSNathan Sullivan adjust = IGB_I210_RX_LATENCY_100; 9433f544d2aSNathan Sullivan break; 9443f544d2aSNathan Sullivan case SPEED_1000: 9453f544d2aSNathan Sullivan adjust = IGB_I210_RX_LATENCY_1000; 9463f544d2aSNathan Sullivan break; 9473f544d2aSNathan Sullivan } 9483f544d2aSNathan Sullivan } 9493f544d2aSNathan Sullivan skb_hwtstamps(skb)->hwtstamp = 9500066c8b6SKshitiz Gupta ktime_sub_ns(skb_hwtstamps(skb)->hwtstamp, adjust); 9513f544d2aSNathan Sullivan 9525499a968SJakub Kicinski /* Update the last_rx_timestamp timer in order to enable watchdog check 9535499a968SJakub Kicinski * for error case of latched timestamp on a dropped packet. 9545499a968SJakub Kicinski */ 9555499a968SJakub Kicinski adapter->last_rx_timestamp = jiffies; 956a79f4f88SMatthew Vick } 957a79f4f88SMatthew Vick 958a79f4f88SMatthew Vick /** 9596ab5f7b2SJacob Keller * igb_ptp_get_ts_config - get hardware time stamping config 960a79f4f88SMatthew Vick * @netdev: 961a79f4f88SMatthew Vick * @ifreq: 9626ab5f7b2SJacob Keller * 9636ab5f7b2SJacob Keller * Get the hwtstamp_config settings to return to the user. Rather than attempt 9646ab5f7b2SJacob Keller * to deconstruct the settings from the registers, just return a shadow copy 9656ab5f7b2SJacob Keller * of the last known settings. 9666ab5f7b2SJacob Keller **/ 9676ab5f7b2SJacob Keller int igb_ptp_get_ts_config(struct net_device *netdev, struct ifreq *ifr) 9686ab5f7b2SJacob Keller { 9696ab5f7b2SJacob Keller struct igb_adapter *adapter = netdev_priv(netdev); 9706ab5f7b2SJacob Keller struct hwtstamp_config *config = &adapter->tstamp_config; 9716ab5f7b2SJacob Keller 9726ab5f7b2SJacob Keller return copy_to_user(ifr->ifr_data, config, sizeof(*config)) ? 9736ab5f7b2SJacob Keller -EFAULT : 0; 9746ab5f7b2SJacob Keller } 9759f62ecf4SJacob Keller 9766ab5f7b2SJacob Keller /** 9779f62ecf4SJacob Keller * igb_ptp_set_timestamp_mode - setup hardware for timestamping 9789f62ecf4SJacob Keller * @adapter: networking device structure 9799f62ecf4SJacob Keller * @config: hwtstamp configuration 980a79f4f88SMatthew Vick * 981a79f4f88SMatthew Vick * Outgoing time stamping can be enabled and disabled. Play nice and 982a79f4f88SMatthew Vick * disable it when requested, although it shouldn't case any overhead 983a79f4f88SMatthew Vick * when no packet needs it. At most one packet in the queue may be 984a79f4f88SMatthew Vick * marked for time stamping, otherwise it would be impossible to tell 985a79f4f88SMatthew Vick * for sure to which packet the hardware time stamp belongs. 986a79f4f88SMatthew Vick * 987a79f4f88SMatthew Vick * Incoming time stamping has to be configured via the hardware 988a79f4f88SMatthew Vick * filters. Not all combinations are supported, in particular event 989a79f4f88SMatthew Vick * type has to be specified. Matching the kind of event packet is 990a79f4f88SMatthew Vick * not supported, with the exception of "all V2 events regardless of 991a79f4f88SMatthew Vick * level 2 or 4". 9929f62ecf4SJacob Keller */ 9939f62ecf4SJacob Keller static int igb_ptp_set_timestamp_mode(struct igb_adapter *adapter, 9949f62ecf4SJacob Keller struct hwtstamp_config *config) 995a79f4f88SMatthew Vick { 996a79f4f88SMatthew Vick struct e1000_hw *hw = &adapter->hw; 997a79f4f88SMatthew Vick u32 tsync_tx_ctl = E1000_TSYNCTXCTL_ENABLED; 998a79f4f88SMatthew Vick u32 tsync_rx_ctl = E1000_TSYNCRXCTL_ENABLED; 999a79f4f88SMatthew Vick u32 tsync_rx_cfg = 0; 1000a79f4f88SMatthew Vick bool is_l4 = false; 1001a79f4f88SMatthew Vick bool is_l2 = false; 1002a79f4f88SMatthew Vick u32 regval; 1003a79f4f88SMatthew Vick 1004a79f4f88SMatthew Vick /* reserved for future extensions */ 10056ab5f7b2SJacob Keller if (config->flags) 1006a79f4f88SMatthew Vick return -EINVAL; 1007a79f4f88SMatthew Vick 10086ab5f7b2SJacob Keller switch (config->tx_type) { 1009a79f4f88SMatthew Vick case HWTSTAMP_TX_OFF: 1010a79f4f88SMatthew Vick tsync_tx_ctl = 0; 1011a79f4f88SMatthew Vick case HWTSTAMP_TX_ON: 1012a79f4f88SMatthew Vick break; 1013a79f4f88SMatthew Vick default: 1014a79f4f88SMatthew Vick return -ERANGE; 1015a79f4f88SMatthew Vick } 1016a79f4f88SMatthew Vick 10176ab5f7b2SJacob Keller switch (config->rx_filter) { 1018a79f4f88SMatthew Vick case HWTSTAMP_FILTER_NONE: 1019a79f4f88SMatthew Vick tsync_rx_ctl = 0; 1020a79f4f88SMatthew Vick break; 1021a79f4f88SMatthew Vick case HWTSTAMP_FILTER_PTP_V1_L4_SYNC: 1022a79f4f88SMatthew Vick tsync_rx_ctl |= E1000_TSYNCRXCTL_TYPE_L4_V1; 1023a79f4f88SMatthew Vick tsync_rx_cfg = E1000_TSYNCRXCFG_PTP_V1_SYNC_MESSAGE; 1024a79f4f88SMatthew Vick is_l4 = true; 1025a79f4f88SMatthew Vick break; 1026a79f4f88SMatthew Vick case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ: 1027a79f4f88SMatthew Vick tsync_rx_ctl |= E1000_TSYNCRXCTL_TYPE_L4_V1; 1028a79f4f88SMatthew Vick tsync_rx_cfg = E1000_TSYNCRXCFG_PTP_V1_DELAY_REQ_MESSAGE; 1029a79f4f88SMatthew Vick is_l4 = true; 1030a79f4f88SMatthew Vick break; 10313e961a06SMatthew Vick case HWTSTAMP_FILTER_PTP_V2_EVENT: 10323e961a06SMatthew Vick case HWTSTAMP_FILTER_PTP_V2_L2_EVENT: 10333e961a06SMatthew Vick case HWTSTAMP_FILTER_PTP_V2_L4_EVENT: 10343e961a06SMatthew Vick case HWTSTAMP_FILTER_PTP_V2_SYNC: 1035a79f4f88SMatthew Vick case HWTSTAMP_FILTER_PTP_V2_L2_SYNC: 1036a79f4f88SMatthew Vick case HWTSTAMP_FILTER_PTP_V2_L4_SYNC: 10373e961a06SMatthew Vick case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ: 1038a79f4f88SMatthew Vick case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ: 1039a79f4f88SMatthew Vick case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ: 1040a79f4f88SMatthew Vick tsync_rx_ctl |= E1000_TSYNCRXCTL_TYPE_EVENT_V2; 10416ab5f7b2SJacob Keller config->rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT; 1042a79f4f88SMatthew Vick is_l2 = true; 1043a79f4f88SMatthew Vick is_l4 = true; 1044a79f4f88SMatthew Vick break; 10453e961a06SMatthew Vick case HWTSTAMP_FILTER_PTP_V1_L4_EVENT: 1046e3412575SMiroslav Lichvar case HWTSTAMP_FILTER_NTP_ALL: 10473e961a06SMatthew Vick case HWTSTAMP_FILTER_ALL: 10483e961a06SMatthew Vick /* 82576 cannot timestamp all packets, which it needs to do to 10493e961a06SMatthew Vick * support both V1 Sync and Delay_Req messages 10503e961a06SMatthew Vick */ 10513e961a06SMatthew Vick if (hw->mac.type != e1000_82576) { 10523e961a06SMatthew Vick tsync_rx_ctl |= E1000_TSYNCRXCTL_TYPE_ALL; 10536ab5f7b2SJacob Keller config->rx_filter = HWTSTAMP_FILTER_ALL; 10543e961a06SMatthew Vick break; 10553e961a06SMatthew Vick } 10565463fce6SJeff Kirsher fallthrough; 1057a79f4f88SMatthew Vick default: 10586ab5f7b2SJacob Keller config->rx_filter = HWTSTAMP_FILTER_NONE; 1059a79f4f88SMatthew Vick return -ERANGE; 1060a79f4f88SMatthew Vick } 1061a79f4f88SMatthew Vick 1062a79f4f88SMatthew Vick if (hw->mac.type == e1000_82575) { 1063a79f4f88SMatthew Vick if (tsync_rx_ctl | tsync_tx_ctl) 1064a79f4f88SMatthew Vick return -EINVAL; 1065a79f4f88SMatthew Vick return 0; 1066a79f4f88SMatthew Vick } 1067a79f4f88SMatthew Vick 1068b980ac18SJeff Kirsher /* Per-packet timestamping only works if all packets are 1069a79f4f88SMatthew Vick * timestamped, so enable timestamping in all packets as 1070b980ac18SJeff Kirsher * long as one Rx filter was configured. 1071a79f4f88SMatthew Vick */ 1072a79f4f88SMatthew Vick if ((hw->mac.type >= e1000_82580) && tsync_rx_ctl) { 1073a79f4f88SMatthew Vick tsync_rx_ctl = E1000_TSYNCRXCTL_ENABLED; 1074a79f4f88SMatthew Vick tsync_rx_ctl |= E1000_TSYNCRXCTL_TYPE_ALL; 10756ab5f7b2SJacob Keller config->rx_filter = HWTSTAMP_FILTER_ALL; 10763e961a06SMatthew Vick is_l2 = true; 10773e961a06SMatthew Vick is_l4 = true; 1078e57b8bdbSMatthew Vick 1079e57b8bdbSMatthew Vick if ((hw->mac.type == e1000_i210) || 1080e57b8bdbSMatthew Vick (hw->mac.type == e1000_i211)) { 1081e57b8bdbSMatthew Vick regval = rd32(E1000_RXPBS); 1082e57b8bdbSMatthew Vick regval |= E1000_RXPBS_CFG_TS_EN; 1083e57b8bdbSMatthew Vick wr32(E1000_RXPBS, regval); 1084e57b8bdbSMatthew Vick } 1085a79f4f88SMatthew Vick } 1086a79f4f88SMatthew Vick 1087a79f4f88SMatthew Vick /* enable/disable TX */ 1088a79f4f88SMatthew Vick regval = rd32(E1000_TSYNCTXCTL); 1089a79f4f88SMatthew Vick regval &= ~E1000_TSYNCTXCTL_ENABLED; 1090a79f4f88SMatthew Vick regval |= tsync_tx_ctl; 1091a79f4f88SMatthew Vick wr32(E1000_TSYNCTXCTL, regval); 1092a79f4f88SMatthew Vick 1093a79f4f88SMatthew Vick /* enable/disable RX */ 1094a79f4f88SMatthew Vick regval = rd32(E1000_TSYNCRXCTL); 1095a79f4f88SMatthew Vick regval &= ~(E1000_TSYNCRXCTL_ENABLED | E1000_TSYNCRXCTL_TYPE_MASK); 1096a79f4f88SMatthew Vick regval |= tsync_rx_ctl; 1097a79f4f88SMatthew Vick wr32(E1000_TSYNCRXCTL, regval); 1098a79f4f88SMatthew Vick 1099a79f4f88SMatthew Vick /* define which PTP packets are time stamped */ 1100a79f4f88SMatthew Vick wr32(E1000_TSYNCRXCFG, tsync_rx_cfg); 1101a79f4f88SMatthew Vick 1102a79f4f88SMatthew Vick /* define ethertype filter for timestamped packets */ 1103a79f4f88SMatthew Vick if (is_l2) 110464c75d41SGangfeng Huang wr32(E1000_ETQF(IGB_ETQF_FILTER_1588), 1105a79f4f88SMatthew Vick (E1000_ETQF_FILTER_ENABLE | /* enable filter */ 1106a79f4f88SMatthew Vick E1000_ETQF_1588 | /* enable timestamping */ 1107a79f4f88SMatthew Vick ETH_P_1588)); /* 1588 eth protocol type */ 1108a79f4f88SMatthew Vick else 110964c75d41SGangfeng Huang wr32(E1000_ETQF(IGB_ETQF_FILTER_1588), 0); 1110a79f4f88SMatthew Vick 1111a79f4f88SMatthew Vick /* L4 Queue Filter[3]: filter by destination port and protocol */ 1112a79f4f88SMatthew Vick if (is_l4) { 1113a79f4f88SMatthew Vick u32 ftqf = (IPPROTO_UDP /* UDP */ 1114a79f4f88SMatthew Vick | E1000_FTQF_VF_BP /* VF not compared */ 1115a79f4f88SMatthew Vick | E1000_FTQF_1588_TIME_STAMP /* Enable Timestamping */ 1116a79f4f88SMatthew Vick | E1000_FTQF_MASK); /* mask all inputs */ 1117a79f4f88SMatthew Vick ftqf &= ~E1000_FTQF_MASK_PROTO_BP; /* enable protocol check */ 1118a79f4f88SMatthew Vick 1119ba59814bSMatthew Vick wr32(E1000_IMIR(3), htons(PTP_EV_PORT)); 1120a79f4f88SMatthew Vick wr32(E1000_IMIREXT(3), 1121a79f4f88SMatthew Vick (E1000_IMIREXT_SIZE_BP | E1000_IMIREXT_CTRL_BP)); 1122a79f4f88SMatthew Vick if (hw->mac.type == e1000_82576) { 1123a79f4f88SMatthew Vick /* enable source port check */ 1124ba59814bSMatthew Vick wr32(E1000_SPQF(3), htons(PTP_EV_PORT)); 1125a79f4f88SMatthew Vick ftqf &= ~E1000_FTQF_MASK_SOURCE_PORT_BP; 1126a79f4f88SMatthew Vick } 1127a79f4f88SMatthew Vick wr32(E1000_FTQF(3), ftqf); 1128a79f4f88SMatthew Vick } else { 1129a79f4f88SMatthew Vick wr32(E1000_FTQF(3), E1000_FTQF_MASK); 1130a79f4f88SMatthew Vick } 1131a79f4f88SMatthew Vick wrfl(); 1132a79f4f88SMatthew Vick 1133a79f4f88SMatthew Vick /* clear TX/RX time stamp registers, just to be sure */ 1134e57b8bdbSMatthew Vick regval = rd32(E1000_TXSTMPL); 1135a79f4f88SMatthew Vick regval = rd32(E1000_TXSTMPH); 1136e57b8bdbSMatthew Vick regval = rd32(E1000_RXSTMPL); 1137a79f4f88SMatthew Vick regval = rd32(E1000_RXSTMPH); 1138a79f4f88SMatthew Vick 11399f62ecf4SJacob Keller return 0; 11409f62ecf4SJacob Keller } 11419f62ecf4SJacob Keller 11429f62ecf4SJacob Keller /** 11439f62ecf4SJacob Keller * igb_ptp_set_ts_config - set hardware time stamping config 11449f62ecf4SJacob Keller * @netdev: 11459f62ecf4SJacob Keller * @ifreq: 11469f62ecf4SJacob Keller * 11479f62ecf4SJacob Keller **/ 11489f62ecf4SJacob Keller int igb_ptp_set_ts_config(struct net_device *netdev, struct ifreq *ifr) 11499f62ecf4SJacob Keller { 11509f62ecf4SJacob Keller struct igb_adapter *adapter = netdev_priv(netdev); 11519f62ecf4SJacob Keller struct hwtstamp_config config; 11529f62ecf4SJacob Keller int err; 11539f62ecf4SJacob Keller 11549f62ecf4SJacob Keller if (copy_from_user(&config, ifr->ifr_data, sizeof(config))) 11559f62ecf4SJacob Keller return -EFAULT; 11569f62ecf4SJacob Keller 11579f62ecf4SJacob Keller err = igb_ptp_set_timestamp_mode(adapter, &config); 11589f62ecf4SJacob Keller if (err) 11599f62ecf4SJacob Keller return err; 11609f62ecf4SJacob Keller 11619f62ecf4SJacob Keller /* save these settings for future reference */ 11629f62ecf4SJacob Keller memcpy(&adapter->tstamp_config, &config, 11639f62ecf4SJacob Keller sizeof(adapter->tstamp_config)); 11649f62ecf4SJacob Keller 11659f62ecf4SJacob Keller return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ? 1166a79f4f88SMatthew Vick -EFAULT : 0; 1167d339b133SRichard Cochran } 1168d339b133SRichard Cochran 11694f3ce71bSJacob Keller /** 11704f3ce71bSJacob Keller * igb_ptp_init - Initialize PTP functionality 11714f3ce71bSJacob Keller * @adapter: Board private structure 11724f3ce71bSJacob Keller * 11734f3ce71bSJacob Keller * This function is called at device probe to initialize the PTP 11744f3ce71bSJacob Keller * functionality. 11754f3ce71bSJacob Keller */ 1176d339b133SRichard Cochran void igb_ptp_init(struct igb_adapter *adapter) 1177d339b133SRichard Cochran { 1178d339b133SRichard Cochran struct e1000_hw *hw = &adapter->hw; 1179201987e3SMatthew Vick struct net_device *netdev = adapter->netdev; 1180720db4ffSRichard Cochran int i; 1181d339b133SRichard Cochran 1182d339b133SRichard Cochran switch (hw->mac.type) { 1183d339b133SRichard Cochran case e1000_82576: 1184201987e3SMatthew Vick snprintf(adapter->ptp_caps.name, 16, "%pm", netdev->dev_addr); 1185a79f4f88SMatthew Vick adapter->ptp_caps.owner = THIS_MODULE; 118675517d92SJiri Benc adapter->ptp_caps.max_adj = 999999881; 1187a79f4f88SMatthew Vick adapter->ptp_caps.n_ext_ts = 0; 1188a79f4f88SMatthew Vick adapter->ptp_caps.pps = 0; 1189a79f4f88SMatthew Vick adapter->ptp_caps.adjfreq = igb_ptp_adjfreq_82576; 1190e57b8bdbSMatthew Vick adapter->ptp_caps.adjtime = igb_ptp_adjtime_82576; 1191cff8ba28SMiroslav Lichvar adapter->ptp_caps.gettimex64 = igb_ptp_gettimex_82576; 1192d4c496feSRichard Cochran adapter->ptp_caps.settime64 = igb_ptp_settime_82576; 1193102be52fSJacob Keller adapter->ptp_caps.enable = igb_ptp_feature_enable; 1194a79f4f88SMatthew Vick adapter->cc.read = igb_ptp_read_82576; 1195b57c8940SRichard Cochran adapter->cc.mask = CYCLECOUNTER_MASK(64); 1196d339b133SRichard Cochran adapter->cc.mult = 1; 1197d339b133SRichard Cochran adapter->cc.shift = IGB_82576_TSYNC_SHIFT; 119863737166SJacob Keller adapter->ptp_flags |= IGB_PTP_OVERFLOW_CHECK; 1199d339b133SRichard Cochran break; 1200e57b8bdbSMatthew Vick case e1000_82580: 1201ceb5f13bSCarolyn Wyborny case e1000_i354: 1202e57b8bdbSMatthew Vick case e1000_i350: 1203e57b8bdbSMatthew Vick snprintf(adapter->ptp_caps.name, 16, "%pm", netdev->dev_addr); 1204e57b8bdbSMatthew Vick adapter->ptp_caps.owner = THIS_MODULE; 1205e57b8bdbSMatthew Vick adapter->ptp_caps.max_adj = 62499999; 1206e57b8bdbSMatthew Vick adapter->ptp_caps.n_ext_ts = 0; 1207e57b8bdbSMatthew Vick adapter->ptp_caps.pps = 0; 1208c79e975eSRichard Cochran adapter->ptp_caps.adjfine = igb_ptp_adjfine_82580; 1209e57b8bdbSMatthew Vick adapter->ptp_caps.adjtime = igb_ptp_adjtime_82576; 1210cff8ba28SMiroslav Lichvar adapter->ptp_caps.gettimex64 = igb_ptp_gettimex_82580; 1211d4c496feSRichard Cochran adapter->ptp_caps.settime64 = igb_ptp_settime_82576; 1212102be52fSJacob Keller adapter->ptp_caps.enable = igb_ptp_feature_enable; 1213e57b8bdbSMatthew Vick adapter->cc.read = igb_ptp_read_82580; 1214b57c8940SRichard Cochran adapter->cc.mask = CYCLECOUNTER_MASK(IGB_NBITS_82580); 1215e57b8bdbSMatthew Vick adapter->cc.mult = 1; 1216e57b8bdbSMatthew Vick adapter->cc.shift = 0; 121763737166SJacob Keller adapter->ptp_flags |= IGB_PTP_OVERFLOW_CHECK; 1218e57b8bdbSMatthew Vick break; 1219e57b8bdbSMatthew Vick case e1000_i210: 1220e57b8bdbSMatthew Vick case e1000_i211: 1221720db4ffSRichard Cochran for (i = 0; i < IGB_N_SDP; i++) { 1222720db4ffSRichard Cochran struct ptp_pin_desc *ppd = &adapter->sdp_config[i]; 1223720db4ffSRichard Cochran 1224720db4ffSRichard Cochran snprintf(ppd->name, sizeof(ppd->name), "SDP%d", i); 1225720db4ffSRichard Cochran ppd->index = i; 1226720db4ffSRichard Cochran ppd->func = PTP_PF_NONE; 1227720db4ffSRichard Cochran } 1228e57b8bdbSMatthew Vick snprintf(adapter->ptp_caps.name, 16, "%pm", netdev->dev_addr); 1229e57b8bdbSMatthew Vick adapter->ptp_caps.owner = THIS_MODULE; 1230e57b8bdbSMatthew Vick adapter->ptp_caps.max_adj = 62499999; 1231720db4ffSRichard Cochran adapter->ptp_caps.n_ext_ts = IGB_N_EXTTS; 1232720db4ffSRichard Cochran adapter->ptp_caps.n_per_out = IGB_N_PEROUT; 1233720db4ffSRichard Cochran adapter->ptp_caps.n_pins = IGB_N_SDP; 123400c65578SRichard Cochran adapter->ptp_caps.pps = 1; 1235720db4ffSRichard Cochran adapter->ptp_caps.pin_config = adapter->sdp_config; 1236c79e975eSRichard Cochran adapter->ptp_caps.adjfine = igb_ptp_adjfine_82580; 1237e57b8bdbSMatthew Vick adapter->ptp_caps.adjtime = igb_ptp_adjtime_i210; 1238cff8ba28SMiroslav Lichvar adapter->ptp_caps.gettimex64 = igb_ptp_gettimex_i210; 1239d4c496feSRichard Cochran adapter->ptp_caps.settime64 = igb_ptp_settime_i210; 124000c65578SRichard Cochran adapter->ptp_caps.enable = igb_ptp_feature_enable_i210; 1241720db4ffSRichard Cochran adapter->ptp_caps.verify = igb_ptp_verify_pin; 1242e57b8bdbSMatthew Vick break; 1243d339b133SRichard Cochran default: 1244d339b133SRichard Cochran adapter->ptp_clock = NULL; 1245d339b133SRichard Cochran return; 1246d339b133SRichard Cochran } 1247d339b133SRichard Cochran 1248e57b8bdbSMatthew Vick spin_lock_init(&adapter->tmreg_lock); 1249e57b8bdbSMatthew Vick INIT_WORK(&adapter->ptp_tx_work, igb_ptp_tx_work); 1250e57b8bdbSMatthew Vick 12514f3ce71bSJacob Keller if (adapter->ptp_flags & IGB_PTP_OVERFLOW_CHECK) 1252e57b8bdbSMatthew Vick INIT_DELAYED_WORK(&adapter->ptp_overflow_work, 1253e57b8bdbSMatthew Vick igb_ptp_overflow_check); 12541f6e8178SMatthew Vick 12559f62ecf4SJacob Keller adapter->tstamp_config.rx_filter = HWTSTAMP_FILTER_NONE; 12569f62ecf4SJacob Keller adapter->tstamp_config.tx_type = HWTSTAMP_TX_OFF; 12579f62ecf4SJacob Keller 12584f3ce71bSJacob Keller igb_ptp_reset(adapter); 12594f3ce71bSJacob Keller 12601ef76158SRichard Cochran adapter->ptp_clock = ptp_clock_register(&adapter->ptp_caps, 12611ef76158SRichard Cochran &adapter->pdev->dev); 1262d339b133SRichard Cochran if (IS_ERR(adapter->ptp_clock)) { 1263d339b133SRichard Cochran adapter->ptp_clock = NULL; 1264d339b133SRichard Cochran dev_err(&adapter->pdev->dev, "ptp_clock_register failed\n"); 1265efee95f4SNicolas Pitre } else if (adapter->ptp_clock) { 1266d339b133SRichard Cochran dev_info(&adapter->pdev->dev, "added PHC on %s\n", 1267d339b133SRichard Cochran adapter->netdev->name); 1268462f1188SJacob Keller adapter->ptp_flags |= IGB_PTP_ENABLED; 12691f6e8178SMatthew Vick } 1270d339b133SRichard Cochran } 1271d339b133SRichard Cochran 1272a79f4f88SMatthew Vick /** 1273e3f2350dSJacob Keller * igb_ptp_suspend - Disable PTP work items and prepare for suspend 1274e3f2350dSJacob Keller * @adapter: Board private structure 1275a79f4f88SMatthew Vick * 1276e3f2350dSJacob Keller * This function stops the overflow check work and PTP Tx timestamp work, and 1277e3f2350dSJacob Keller * will prepare the device for OS suspend. 1278e3f2350dSJacob Keller */ 1279e3f2350dSJacob Keller void igb_ptp_suspend(struct igb_adapter *adapter) 1280d339b133SRichard Cochran { 128163737166SJacob Keller if (!(adapter->ptp_flags & IGB_PTP_ENABLED)) 1282d3eef8c8SCarolyn Wyborny return; 128363737166SJacob Keller 128463737166SJacob Keller if (adapter->ptp_flags & IGB_PTP_OVERFLOW_CHECK) 128563737166SJacob Keller cancel_delayed_work_sync(&adapter->ptp_overflow_work); 1286d339b133SRichard Cochran 12871f6e8178SMatthew Vick cancel_work_sync(&adapter->ptp_tx_work); 1288badc26ddSMatthew Vick if (adapter->ptp_tx_skb) { 1289badc26ddSMatthew Vick dev_kfree_skb_any(adapter->ptp_tx_skb); 1290badc26ddSMatthew Vick adapter->ptp_tx_skb = NULL; 1291ed4420a3SJakub Kicinski clear_bit_unlock(__IGB_PTP_TX_IN_PROGRESS, &adapter->state); 1292badc26ddSMatthew Vick } 1293e3f2350dSJacob Keller } 1294e3f2350dSJacob Keller 1295e3f2350dSJacob Keller /** 1296e3f2350dSJacob Keller * igb_ptp_stop - Disable PTP device and stop the overflow check. 1297e3f2350dSJacob Keller * @adapter: Board private structure. 1298e3f2350dSJacob Keller * 1299e3f2350dSJacob Keller * This function stops the PTP support and cancels the delayed work. 1300e3f2350dSJacob Keller **/ 1301e3f2350dSJacob Keller void igb_ptp_stop(struct igb_adapter *adapter) 1302e3f2350dSJacob Keller { 1303e3f2350dSJacob Keller igb_ptp_suspend(adapter); 13041f6e8178SMatthew Vick 1305d339b133SRichard Cochran if (adapter->ptp_clock) { 1306d339b133SRichard Cochran ptp_clock_unregister(adapter->ptp_clock); 1307d339b133SRichard Cochran dev_info(&adapter->pdev->dev, "removed PHC on %s\n", 1308d339b133SRichard Cochran adapter->netdev->name); 1309462f1188SJacob Keller adapter->ptp_flags &= ~IGB_PTP_ENABLED; 1310d339b133SRichard Cochran } 1311d339b133SRichard Cochran } 13121f6e8178SMatthew Vick 13131f6e8178SMatthew Vick /** 13141f6e8178SMatthew Vick * igb_ptp_reset - Re-enable the adapter for PTP following a reset. 13151f6e8178SMatthew Vick * @adapter: Board private structure. 13161f6e8178SMatthew Vick * 13171f6e8178SMatthew Vick * This function handles the reset work required to re-enable the PTP device. 13181f6e8178SMatthew Vick **/ 13191f6e8178SMatthew Vick void igb_ptp_reset(struct igb_adapter *adapter) 13201f6e8178SMatthew Vick { 13211f6e8178SMatthew Vick struct e1000_hw *hw = &adapter->hw; 13228298c1ecSRichard Cochran unsigned long flags; 13231f6e8178SMatthew Vick 13246ab5f7b2SJacob Keller /* reset the tstamp_config */ 13259f62ecf4SJacob Keller igb_ptp_set_timestamp_mode(adapter, &adapter->tstamp_config); 13266ab5f7b2SJacob Keller 13278298c1ecSRichard Cochran spin_lock_irqsave(&adapter->tmreg_lock, flags); 13288298c1ecSRichard Cochran 13291f6e8178SMatthew Vick switch (adapter->hw.mac.type) { 13301f6e8178SMatthew Vick case e1000_82576: 13311f6e8178SMatthew Vick /* Dial the nominal frequency. */ 13321f6e8178SMatthew Vick wr32(E1000_TIMINCA, INCPERIOD_82576 | INCVALUE_82576); 13331f6e8178SMatthew Vick break; 13341f6e8178SMatthew Vick case e1000_82580: 1335ceb5f13bSCarolyn Wyborny case e1000_i354: 13361f6e8178SMatthew Vick case e1000_i350: 13371f6e8178SMatthew Vick case e1000_i210: 13381f6e8178SMatthew Vick case e1000_i211: 13391f6e8178SMatthew Vick wr32(E1000_TSAUXC, 0x0); 1340720db4ffSRichard Cochran wr32(E1000_TSSDP, 0x0); 1341ac28b41aSJacob Keller wr32(E1000_TSIM, 1342ac28b41aSJacob Keller TSYNC_INTERRUPTS | 1343ac28b41aSJacob Keller (adapter->pps_sys_wrap_on ? TSINTR_SYS_WRAP : 0)); 13441f6e8178SMatthew Vick wr32(E1000_IMS, E1000_IMS_TS); 13451f6e8178SMatthew Vick break; 13461f6e8178SMatthew Vick default: 13471f6e8178SMatthew Vick /* No work to do. */ 13488298c1ecSRichard Cochran goto out; 13491f6e8178SMatthew Vick } 13501f6e8178SMatthew Vick 1351e57b8bdbSMatthew Vick /* Re-initialize the timer. */ 1352e57b8bdbSMatthew Vick if ((hw->mac.type == e1000_i210) || (hw->mac.type == e1000_i211)) { 1353d4c496feSRichard Cochran struct timespec64 ts = ktime_to_timespec64(ktime_get_real()); 1354e57b8bdbSMatthew Vick 13558298c1ecSRichard Cochran igb_ptp_write_i210(adapter, &ts); 1356e57b8bdbSMatthew Vick } else { 13571f6e8178SMatthew Vick timecounter_init(&adapter->tc, &adapter->cc, 13581f6e8178SMatthew Vick ktime_to_ns(ktime_get_real())); 13591f6e8178SMatthew Vick } 13608298c1ecSRichard Cochran out: 13618298c1ecSRichard Cochran spin_unlock_irqrestore(&adapter->tmreg_lock, flags); 13624f3ce71bSJacob Keller 13634f3ce71bSJacob Keller wrfl(); 13644f3ce71bSJacob Keller 13654f3ce71bSJacob Keller if (adapter->ptp_flags & IGB_PTP_OVERFLOW_CHECK) 13664f3ce71bSJacob Keller schedule_delayed_work(&adapter->ptp_overflow_work, 13674f3ce71bSJacob Keller IGB_SYSTIM_OVERFLOW_PERIOD); 1368e57b8bdbSMatthew Vick } 1369