162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 262306a36Sopenharmony_ci/* Copyright (C) 2011 Richard Cochran <richardcochran@gmail.com> */ 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci#include <linux/module.h> 562306a36Sopenharmony_ci#include <linux/device.h> 662306a36Sopenharmony_ci#include <linux/pci.h> 762306a36Sopenharmony_ci#include <linux/ptp_classify.h> 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include "igb.h" 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#define INCVALUE_MASK 0x7fffffff 1262306a36Sopenharmony_ci#define ISGN 0x80000000 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci/* The 82580 timesync updates the system timer every 8ns by 8ns, 1562306a36Sopenharmony_ci * and this update value cannot be reprogrammed. 1662306a36Sopenharmony_ci * 1762306a36Sopenharmony_ci * Neither the 82576 nor the 82580 offer registers wide enough to hold 1862306a36Sopenharmony_ci * nanoseconds time values for very long. For the 82580, SYSTIM always 1962306a36Sopenharmony_ci * counts nanoseconds, but the upper 24 bits are not available. The 2062306a36Sopenharmony_ci * frequency is adjusted by changing the 32 bit fractional nanoseconds 2162306a36Sopenharmony_ci * register, TIMINCA. 2262306a36Sopenharmony_ci * 2362306a36Sopenharmony_ci * For the 82576, the SYSTIM register time unit is affect by the 2462306a36Sopenharmony_ci * choice of the 24 bit TININCA:IV (incvalue) field. Five bits of this 2562306a36Sopenharmony_ci * field are needed to provide the nominal 16 nanosecond period, 2662306a36Sopenharmony_ci * leaving 19 bits for fractional nanoseconds. 2762306a36Sopenharmony_ci * 2862306a36Sopenharmony_ci * We scale the NIC clock cycle by a large factor so that relatively 2962306a36Sopenharmony_ci * small clock corrections can be added or subtracted at each clock 3062306a36Sopenharmony_ci * tick. The drawbacks of a large factor are a) that the clock 3162306a36Sopenharmony_ci * register overflows more quickly (not such a big deal) and b) that 3262306a36Sopenharmony_ci * the increment per tick has to fit into 24 bits. As a result we 3362306a36Sopenharmony_ci * need to use a shift of 19 so we can fit a value of 16 into the 3462306a36Sopenharmony_ci * TIMINCA register. 3562306a36Sopenharmony_ci * 3662306a36Sopenharmony_ci * 3762306a36Sopenharmony_ci * SYSTIMH SYSTIML 3862306a36Sopenharmony_ci * +--------------+ +---+---+------+ 3962306a36Sopenharmony_ci * 82576 | 32 | | 8 | 5 | 19 | 4062306a36Sopenharmony_ci * +--------------+ +---+---+------+ 4162306a36Sopenharmony_ci * \________ 45 bits _______/ fract 4262306a36Sopenharmony_ci * 4362306a36Sopenharmony_ci * +----------+---+ +--------------+ 4462306a36Sopenharmony_ci * 82580 | 24 | 8 | | 32 | 4562306a36Sopenharmony_ci * +----------+---+ +--------------+ 4662306a36Sopenharmony_ci * reserved \______ 40 bits _____/ 4762306a36Sopenharmony_ci * 4862306a36Sopenharmony_ci * 4962306a36Sopenharmony_ci * The 45 bit 82576 SYSTIM overflows every 5062306a36Sopenharmony_ci * 2^45 * 10^-9 / 3600 = 9.77 hours. 5162306a36Sopenharmony_ci * 5262306a36Sopenharmony_ci * The 40 bit 82580 SYSTIM overflows every 5362306a36Sopenharmony_ci * 2^40 * 10^-9 / 60 = 18.3 minutes. 5462306a36Sopenharmony_ci * 5562306a36Sopenharmony_ci * SYSTIM is converted to real time using a timecounter. As 5662306a36Sopenharmony_ci * timecounter_cyc2time() allows old timestamps, the timecounter needs 5762306a36Sopenharmony_ci * to be updated at least once per half of the SYSTIM interval. 5862306a36Sopenharmony_ci * Scheduling of delayed work is not very accurate, and also the NIC 5962306a36Sopenharmony_ci * clock can be adjusted to run up to 6% faster and the system clock 6062306a36Sopenharmony_ci * up to 10% slower, so we aim for 6 minutes to be sure the actual 6162306a36Sopenharmony_ci * interval in the NIC time is shorter than 9.16 minutes. 6262306a36Sopenharmony_ci */ 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci#define IGB_SYSTIM_OVERFLOW_PERIOD (HZ * 60 * 6) 6562306a36Sopenharmony_ci#define IGB_PTP_TX_TIMEOUT (HZ * 15) 6662306a36Sopenharmony_ci#define INCPERIOD_82576 BIT(E1000_TIMINCA_16NS_SHIFT) 6762306a36Sopenharmony_ci#define INCVALUE_82576_MASK GENMASK(E1000_TIMINCA_16NS_SHIFT - 1, 0) 6862306a36Sopenharmony_ci#define INCVALUE_82576 (16u << IGB_82576_TSYNC_SHIFT) 6962306a36Sopenharmony_ci#define IGB_NBITS_82580 40 7062306a36Sopenharmony_ci#define IGB_82580_BASE_PERIOD 0x800000000 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_cistatic void igb_ptp_tx_hwtstamp(struct igb_adapter *adapter); 7362306a36Sopenharmony_cistatic void igb_ptp_sdp_init(struct igb_adapter *adapter); 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci/* SYSTIM read access for the 82576 */ 7662306a36Sopenharmony_cistatic u64 igb_ptp_read_82576(const struct cyclecounter *cc) 7762306a36Sopenharmony_ci{ 7862306a36Sopenharmony_ci struct igb_adapter *igb = container_of(cc, struct igb_adapter, cc); 7962306a36Sopenharmony_ci struct e1000_hw *hw = &igb->hw; 8062306a36Sopenharmony_ci u64 val; 8162306a36Sopenharmony_ci u32 lo, hi; 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci lo = rd32(E1000_SYSTIML); 8462306a36Sopenharmony_ci hi = rd32(E1000_SYSTIMH); 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci val = ((u64) hi) << 32; 8762306a36Sopenharmony_ci val |= lo; 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci return val; 9062306a36Sopenharmony_ci} 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci/* SYSTIM read access for the 82580 */ 9362306a36Sopenharmony_cistatic u64 igb_ptp_read_82580(const struct cyclecounter *cc) 9462306a36Sopenharmony_ci{ 9562306a36Sopenharmony_ci struct igb_adapter *igb = container_of(cc, struct igb_adapter, cc); 9662306a36Sopenharmony_ci struct e1000_hw *hw = &igb->hw; 9762306a36Sopenharmony_ci u32 lo, hi; 9862306a36Sopenharmony_ci u64 val; 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci /* The timestamp latches on lowest register read. For the 82580 10162306a36Sopenharmony_ci * the lowest register is SYSTIMR instead of SYSTIML. However we only 10262306a36Sopenharmony_ci * need to provide nanosecond resolution, so we just ignore it. 10362306a36Sopenharmony_ci */ 10462306a36Sopenharmony_ci rd32(E1000_SYSTIMR); 10562306a36Sopenharmony_ci lo = rd32(E1000_SYSTIML); 10662306a36Sopenharmony_ci hi = rd32(E1000_SYSTIMH); 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci val = ((u64) hi) << 32; 10962306a36Sopenharmony_ci val |= lo; 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci return val; 11262306a36Sopenharmony_ci} 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci/* SYSTIM read access for I210/I211 */ 11562306a36Sopenharmony_cistatic void igb_ptp_read_i210(struct igb_adapter *adapter, 11662306a36Sopenharmony_ci struct timespec64 *ts) 11762306a36Sopenharmony_ci{ 11862306a36Sopenharmony_ci struct e1000_hw *hw = &adapter->hw; 11962306a36Sopenharmony_ci u32 sec, nsec; 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci /* The timestamp latches on lowest register read. For I210/I211, the 12262306a36Sopenharmony_ci * lowest register is SYSTIMR. Since we only need to provide nanosecond 12362306a36Sopenharmony_ci * resolution, we can ignore it. 12462306a36Sopenharmony_ci */ 12562306a36Sopenharmony_ci rd32(E1000_SYSTIMR); 12662306a36Sopenharmony_ci nsec = rd32(E1000_SYSTIML); 12762306a36Sopenharmony_ci sec = rd32(E1000_SYSTIMH); 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci ts->tv_sec = sec; 13062306a36Sopenharmony_ci ts->tv_nsec = nsec; 13162306a36Sopenharmony_ci} 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_cistatic void igb_ptp_write_i210(struct igb_adapter *adapter, 13462306a36Sopenharmony_ci const struct timespec64 *ts) 13562306a36Sopenharmony_ci{ 13662306a36Sopenharmony_ci struct e1000_hw *hw = &adapter->hw; 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci /* Writing the SYSTIMR register is not necessary as it only provides 13962306a36Sopenharmony_ci * sub-nanosecond resolution. 14062306a36Sopenharmony_ci */ 14162306a36Sopenharmony_ci wr32(E1000_SYSTIML, ts->tv_nsec); 14262306a36Sopenharmony_ci wr32(E1000_SYSTIMH, (u32)ts->tv_sec); 14362306a36Sopenharmony_ci} 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci/** 14662306a36Sopenharmony_ci * igb_ptp_systim_to_hwtstamp - convert system time value to hw timestamp 14762306a36Sopenharmony_ci * @adapter: board private structure 14862306a36Sopenharmony_ci * @hwtstamps: timestamp structure to update 14962306a36Sopenharmony_ci * @systim: unsigned 64bit system time value. 15062306a36Sopenharmony_ci * 15162306a36Sopenharmony_ci * We need to convert the system time value stored in the RX/TXSTMP registers 15262306a36Sopenharmony_ci * into a hwtstamp which can be used by the upper level timestamping functions. 15362306a36Sopenharmony_ci * 15462306a36Sopenharmony_ci * The 'tmreg_lock' spinlock is used to protect the consistency of the 15562306a36Sopenharmony_ci * system time value. This is needed because reading the 64 bit time 15662306a36Sopenharmony_ci * value involves reading two (or three) 32 bit registers. The first 15762306a36Sopenharmony_ci * read latches the value. Ditto for writing. 15862306a36Sopenharmony_ci * 15962306a36Sopenharmony_ci * In addition, here have extended the system time with an overflow 16062306a36Sopenharmony_ci * counter in software. 16162306a36Sopenharmony_ci **/ 16262306a36Sopenharmony_cistatic void igb_ptp_systim_to_hwtstamp(struct igb_adapter *adapter, 16362306a36Sopenharmony_ci struct skb_shared_hwtstamps *hwtstamps, 16462306a36Sopenharmony_ci u64 systim) 16562306a36Sopenharmony_ci{ 16662306a36Sopenharmony_ci unsigned long flags; 16762306a36Sopenharmony_ci u64 ns; 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci memset(hwtstamps, 0, sizeof(*hwtstamps)); 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci switch (adapter->hw.mac.type) { 17262306a36Sopenharmony_ci case e1000_82576: 17362306a36Sopenharmony_ci case e1000_82580: 17462306a36Sopenharmony_ci case e1000_i354: 17562306a36Sopenharmony_ci case e1000_i350: 17662306a36Sopenharmony_ci spin_lock_irqsave(&adapter->tmreg_lock, flags); 17762306a36Sopenharmony_ci ns = timecounter_cyc2time(&adapter->tc, systim); 17862306a36Sopenharmony_ci spin_unlock_irqrestore(&adapter->tmreg_lock, flags); 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci hwtstamps->hwtstamp = ns_to_ktime(ns); 18162306a36Sopenharmony_ci break; 18262306a36Sopenharmony_ci case e1000_i210: 18362306a36Sopenharmony_ci case e1000_i211: 18462306a36Sopenharmony_ci /* Upper 32 bits contain s, lower 32 bits contain ns. */ 18562306a36Sopenharmony_ci hwtstamps->hwtstamp = ktime_set(systim >> 32, 18662306a36Sopenharmony_ci systim & 0xFFFFFFFF); 18762306a36Sopenharmony_ci break; 18862306a36Sopenharmony_ci default: 18962306a36Sopenharmony_ci break; 19062306a36Sopenharmony_ci } 19162306a36Sopenharmony_ci} 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci/* PTP clock operations */ 19462306a36Sopenharmony_cistatic int igb_ptp_adjfine_82576(struct ptp_clock_info *ptp, long scaled_ppm) 19562306a36Sopenharmony_ci{ 19662306a36Sopenharmony_ci struct igb_adapter *igb = container_of(ptp, struct igb_adapter, 19762306a36Sopenharmony_ci ptp_caps); 19862306a36Sopenharmony_ci struct e1000_hw *hw = &igb->hw; 19962306a36Sopenharmony_ci u64 incvalue; 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci incvalue = adjust_by_scaled_ppm(INCVALUE_82576, scaled_ppm); 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci wr32(E1000_TIMINCA, INCPERIOD_82576 | (incvalue & INCVALUE_82576_MASK)); 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci return 0; 20662306a36Sopenharmony_ci} 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_cistatic int igb_ptp_adjfine_82580(struct ptp_clock_info *ptp, long scaled_ppm) 20962306a36Sopenharmony_ci{ 21062306a36Sopenharmony_ci struct igb_adapter *igb = container_of(ptp, struct igb_adapter, 21162306a36Sopenharmony_ci ptp_caps); 21262306a36Sopenharmony_ci struct e1000_hw *hw = &igb->hw; 21362306a36Sopenharmony_ci bool neg_adj; 21462306a36Sopenharmony_ci u64 rate; 21562306a36Sopenharmony_ci u32 inca; 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci neg_adj = diff_by_scaled_ppm(IGB_82580_BASE_PERIOD, scaled_ppm, &rate); 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci inca = rate & INCVALUE_MASK; 22062306a36Sopenharmony_ci if (neg_adj) 22162306a36Sopenharmony_ci inca |= ISGN; 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci wr32(E1000_TIMINCA, inca); 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci return 0; 22662306a36Sopenharmony_ci} 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_cistatic int igb_ptp_adjtime_82576(struct ptp_clock_info *ptp, s64 delta) 22962306a36Sopenharmony_ci{ 23062306a36Sopenharmony_ci struct igb_adapter *igb = container_of(ptp, struct igb_adapter, 23162306a36Sopenharmony_ci ptp_caps); 23262306a36Sopenharmony_ci unsigned long flags; 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci spin_lock_irqsave(&igb->tmreg_lock, flags); 23562306a36Sopenharmony_ci timecounter_adjtime(&igb->tc, delta); 23662306a36Sopenharmony_ci spin_unlock_irqrestore(&igb->tmreg_lock, flags); 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci return 0; 23962306a36Sopenharmony_ci} 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_cistatic int igb_ptp_adjtime_i210(struct ptp_clock_info *ptp, s64 delta) 24262306a36Sopenharmony_ci{ 24362306a36Sopenharmony_ci struct igb_adapter *igb = container_of(ptp, struct igb_adapter, 24462306a36Sopenharmony_ci ptp_caps); 24562306a36Sopenharmony_ci unsigned long flags; 24662306a36Sopenharmony_ci struct timespec64 now, then = ns_to_timespec64(delta); 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci spin_lock_irqsave(&igb->tmreg_lock, flags); 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci igb_ptp_read_i210(igb, &now); 25162306a36Sopenharmony_ci now = timespec64_add(now, then); 25262306a36Sopenharmony_ci igb_ptp_write_i210(igb, (const struct timespec64 *)&now); 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci spin_unlock_irqrestore(&igb->tmreg_lock, flags); 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci return 0; 25762306a36Sopenharmony_ci} 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_cistatic int igb_ptp_gettimex_82576(struct ptp_clock_info *ptp, 26062306a36Sopenharmony_ci struct timespec64 *ts, 26162306a36Sopenharmony_ci struct ptp_system_timestamp *sts) 26262306a36Sopenharmony_ci{ 26362306a36Sopenharmony_ci struct igb_adapter *igb = container_of(ptp, struct igb_adapter, 26462306a36Sopenharmony_ci ptp_caps); 26562306a36Sopenharmony_ci struct e1000_hw *hw = &igb->hw; 26662306a36Sopenharmony_ci unsigned long flags; 26762306a36Sopenharmony_ci u32 lo, hi; 26862306a36Sopenharmony_ci u64 ns; 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci spin_lock_irqsave(&igb->tmreg_lock, flags); 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci ptp_read_system_prets(sts); 27362306a36Sopenharmony_ci lo = rd32(E1000_SYSTIML); 27462306a36Sopenharmony_ci ptp_read_system_postts(sts); 27562306a36Sopenharmony_ci hi = rd32(E1000_SYSTIMH); 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci ns = timecounter_cyc2time(&igb->tc, ((u64)hi << 32) | lo); 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci spin_unlock_irqrestore(&igb->tmreg_lock, flags); 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci *ts = ns_to_timespec64(ns); 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci return 0; 28462306a36Sopenharmony_ci} 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_cistatic int igb_ptp_gettimex_82580(struct ptp_clock_info *ptp, 28762306a36Sopenharmony_ci struct timespec64 *ts, 28862306a36Sopenharmony_ci struct ptp_system_timestamp *sts) 28962306a36Sopenharmony_ci{ 29062306a36Sopenharmony_ci struct igb_adapter *igb = container_of(ptp, struct igb_adapter, 29162306a36Sopenharmony_ci ptp_caps); 29262306a36Sopenharmony_ci struct e1000_hw *hw = &igb->hw; 29362306a36Sopenharmony_ci unsigned long flags; 29462306a36Sopenharmony_ci u32 lo, hi; 29562306a36Sopenharmony_ci u64 ns; 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci spin_lock_irqsave(&igb->tmreg_lock, flags); 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci ptp_read_system_prets(sts); 30062306a36Sopenharmony_ci rd32(E1000_SYSTIMR); 30162306a36Sopenharmony_ci ptp_read_system_postts(sts); 30262306a36Sopenharmony_ci lo = rd32(E1000_SYSTIML); 30362306a36Sopenharmony_ci hi = rd32(E1000_SYSTIMH); 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci ns = timecounter_cyc2time(&igb->tc, ((u64)hi << 32) | lo); 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci spin_unlock_irqrestore(&igb->tmreg_lock, flags); 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci *ts = ns_to_timespec64(ns); 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci return 0; 31262306a36Sopenharmony_ci} 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_cistatic int igb_ptp_gettimex_i210(struct ptp_clock_info *ptp, 31562306a36Sopenharmony_ci struct timespec64 *ts, 31662306a36Sopenharmony_ci struct ptp_system_timestamp *sts) 31762306a36Sopenharmony_ci{ 31862306a36Sopenharmony_ci struct igb_adapter *igb = container_of(ptp, struct igb_adapter, 31962306a36Sopenharmony_ci ptp_caps); 32062306a36Sopenharmony_ci struct e1000_hw *hw = &igb->hw; 32162306a36Sopenharmony_ci unsigned long flags; 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci spin_lock_irqsave(&igb->tmreg_lock, flags); 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci ptp_read_system_prets(sts); 32662306a36Sopenharmony_ci rd32(E1000_SYSTIMR); 32762306a36Sopenharmony_ci ptp_read_system_postts(sts); 32862306a36Sopenharmony_ci ts->tv_nsec = rd32(E1000_SYSTIML); 32962306a36Sopenharmony_ci ts->tv_sec = rd32(E1000_SYSTIMH); 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci spin_unlock_irqrestore(&igb->tmreg_lock, flags); 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci return 0; 33462306a36Sopenharmony_ci} 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_cistatic int igb_ptp_settime_82576(struct ptp_clock_info *ptp, 33762306a36Sopenharmony_ci const struct timespec64 *ts) 33862306a36Sopenharmony_ci{ 33962306a36Sopenharmony_ci struct igb_adapter *igb = container_of(ptp, struct igb_adapter, 34062306a36Sopenharmony_ci ptp_caps); 34162306a36Sopenharmony_ci unsigned long flags; 34262306a36Sopenharmony_ci u64 ns; 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci ns = timespec64_to_ns(ts); 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci spin_lock_irqsave(&igb->tmreg_lock, flags); 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci timecounter_init(&igb->tc, &igb->cc, ns); 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci spin_unlock_irqrestore(&igb->tmreg_lock, flags); 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci return 0; 35362306a36Sopenharmony_ci} 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_cistatic int igb_ptp_settime_i210(struct ptp_clock_info *ptp, 35662306a36Sopenharmony_ci const struct timespec64 *ts) 35762306a36Sopenharmony_ci{ 35862306a36Sopenharmony_ci struct igb_adapter *igb = container_of(ptp, struct igb_adapter, 35962306a36Sopenharmony_ci ptp_caps); 36062306a36Sopenharmony_ci unsigned long flags; 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci spin_lock_irqsave(&igb->tmreg_lock, flags); 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci igb_ptp_write_i210(igb, ts); 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci spin_unlock_irqrestore(&igb->tmreg_lock, flags); 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci return 0; 36962306a36Sopenharmony_ci} 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_cistatic void igb_pin_direction(int pin, int input, u32 *ctrl, u32 *ctrl_ext) 37262306a36Sopenharmony_ci{ 37362306a36Sopenharmony_ci u32 *ptr = pin < 2 ? ctrl : ctrl_ext; 37462306a36Sopenharmony_ci static const u32 mask[IGB_N_SDP] = { 37562306a36Sopenharmony_ci E1000_CTRL_SDP0_DIR, 37662306a36Sopenharmony_ci E1000_CTRL_SDP1_DIR, 37762306a36Sopenharmony_ci E1000_CTRL_EXT_SDP2_DIR, 37862306a36Sopenharmony_ci E1000_CTRL_EXT_SDP3_DIR, 37962306a36Sopenharmony_ci }; 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci if (input) 38262306a36Sopenharmony_ci *ptr &= ~mask[pin]; 38362306a36Sopenharmony_ci else 38462306a36Sopenharmony_ci *ptr |= mask[pin]; 38562306a36Sopenharmony_ci} 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_cistatic void igb_pin_extts(struct igb_adapter *igb, int chan, int pin) 38862306a36Sopenharmony_ci{ 38962306a36Sopenharmony_ci static const u32 aux0_sel_sdp[IGB_N_SDP] = { 39062306a36Sopenharmony_ci AUX0_SEL_SDP0, AUX0_SEL_SDP1, AUX0_SEL_SDP2, AUX0_SEL_SDP3, 39162306a36Sopenharmony_ci }; 39262306a36Sopenharmony_ci static const u32 aux1_sel_sdp[IGB_N_SDP] = { 39362306a36Sopenharmony_ci AUX1_SEL_SDP0, AUX1_SEL_SDP1, AUX1_SEL_SDP2, AUX1_SEL_SDP3, 39462306a36Sopenharmony_ci }; 39562306a36Sopenharmony_ci static const u32 ts_sdp_en[IGB_N_SDP] = { 39662306a36Sopenharmony_ci TS_SDP0_EN, TS_SDP1_EN, TS_SDP2_EN, TS_SDP3_EN, 39762306a36Sopenharmony_ci }; 39862306a36Sopenharmony_ci struct e1000_hw *hw = &igb->hw; 39962306a36Sopenharmony_ci u32 ctrl, ctrl_ext, tssdp = 0; 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci ctrl = rd32(E1000_CTRL); 40262306a36Sopenharmony_ci ctrl_ext = rd32(E1000_CTRL_EXT); 40362306a36Sopenharmony_ci tssdp = rd32(E1000_TSSDP); 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci igb_pin_direction(pin, 1, &ctrl, &ctrl_ext); 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci /* Make sure this pin is not enabled as an output. */ 40862306a36Sopenharmony_ci tssdp &= ~ts_sdp_en[pin]; 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci if (chan == 1) { 41162306a36Sopenharmony_ci tssdp &= ~AUX1_SEL_SDP3; 41262306a36Sopenharmony_ci tssdp |= aux1_sel_sdp[pin] | AUX1_TS_SDP_EN; 41362306a36Sopenharmony_ci } else { 41462306a36Sopenharmony_ci tssdp &= ~AUX0_SEL_SDP3; 41562306a36Sopenharmony_ci tssdp |= aux0_sel_sdp[pin] | AUX0_TS_SDP_EN; 41662306a36Sopenharmony_ci } 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci wr32(E1000_TSSDP, tssdp); 41962306a36Sopenharmony_ci wr32(E1000_CTRL, ctrl); 42062306a36Sopenharmony_ci wr32(E1000_CTRL_EXT, ctrl_ext); 42162306a36Sopenharmony_ci} 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_cistatic void igb_pin_perout(struct igb_adapter *igb, int chan, int pin, int freq) 42462306a36Sopenharmony_ci{ 42562306a36Sopenharmony_ci static const u32 aux0_sel_sdp[IGB_N_SDP] = { 42662306a36Sopenharmony_ci AUX0_SEL_SDP0, AUX0_SEL_SDP1, AUX0_SEL_SDP2, AUX0_SEL_SDP3, 42762306a36Sopenharmony_ci }; 42862306a36Sopenharmony_ci static const u32 aux1_sel_sdp[IGB_N_SDP] = { 42962306a36Sopenharmony_ci AUX1_SEL_SDP0, AUX1_SEL_SDP1, AUX1_SEL_SDP2, AUX1_SEL_SDP3, 43062306a36Sopenharmony_ci }; 43162306a36Sopenharmony_ci static const u32 ts_sdp_en[IGB_N_SDP] = { 43262306a36Sopenharmony_ci TS_SDP0_EN, TS_SDP1_EN, TS_SDP2_EN, TS_SDP3_EN, 43362306a36Sopenharmony_ci }; 43462306a36Sopenharmony_ci static const u32 ts_sdp_sel_tt0[IGB_N_SDP] = { 43562306a36Sopenharmony_ci TS_SDP0_SEL_TT0, TS_SDP1_SEL_TT0, 43662306a36Sopenharmony_ci TS_SDP2_SEL_TT0, TS_SDP3_SEL_TT0, 43762306a36Sopenharmony_ci }; 43862306a36Sopenharmony_ci static const u32 ts_sdp_sel_tt1[IGB_N_SDP] = { 43962306a36Sopenharmony_ci TS_SDP0_SEL_TT1, TS_SDP1_SEL_TT1, 44062306a36Sopenharmony_ci TS_SDP2_SEL_TT1, TS_SDP3_SEL_TT1, 44162306a36Sopenharmony_ci }; 44262306a36Sopenharmony_ci static const u32 ts_sdp_sel_fc0[IGB_N_SDP] = { 44362306a36Sopenharmony_ci TS_SDP0_SEL_FC0, TS_SDP1_SEL_FC0, 44462306a36Sopenharmony_ci TS_SDP2_SEL_FC0, TS_SDP3_SEL_FC0, 44562306a36Sopenharmony_ci }; 44662306a36Sopenharmony_ci static const u32 ts_sdp_sel_fc1[IGB_N_SDP] = { 44762306a36Sopenharmony_ci TS_SDP0_SEL_FC1, TS_SDP1_SEL_FC1, 44862306a36Sopenharmony_ci TS_SDP2_SEL_FC1, TS_SDP3_SEL_FC1, 44962306a36Sopenharmony_ci }; 45062306a36Sopenharmony_ci static const u32 ts_sdp_sel_clr[IGB_N_SDP] = { 45162306a36Sopenharmony_ci TS_SDP0_SEL_FC1, TS_SDP1_SEL_FC1, 45262306a36Sopenharmony_ci TS_SDP2_SEL_FC1, TS_SDP3_SEL_FC1, 45362306a36Sopenharmony_ci }; 45462306a36Sopenharmony_ci struct e1000_hw *hw = &igb->hw; 45562306a36Sopenharmony_ci u32 ctrl, ctrl_ext, tssdp = 0; 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci ctrl = rd32(E1000_CTRL); 45862306a36Sopenharmony_ci ctrl_ext = rd32(E1000_CTRL_EXT); 45962306a36Sopenharmony_ci tssdp = rd32(E1000_TSSDP); 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci igb_pin_direction(pin, 0, &ctrl, &ctrl_ext); 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci /* Make sure this pin is not enabled as an input. */ 46462306a36Sopenharmony_ci if ((tssdp & AUX0_SEL_SDP3) == aux0_sel_sdp[pin]) 46562306a36Sopenharmony_ci tssdp &= ~AUX0_TS_SDP_EN; 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci if ((tssdp & AUX1_SEL_SDP3) == aux1_sel_sdp[pin]) 46862306a36Sopenharmony_ci tssdp &= ~AUX1_TS_SDP_EN; 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci tssdp &= ~ts_sdp_sel_clr[pin]; 47162306a36Sopenharmony_ci if (freq) { 47262306a36Sopenharmony_ci if (chan == 1) 47362306a36Sopenharmony_ci tssdp |= ts_sdp_sel_fc1[pin]; 47462306a36Sopenharmony_ci else 47562306a36Sopenharmony_ci tssdp |= ts_sdp_sel_fc0[pin]; 47662306a36Sopenharmony_ci } else { 47762306a36Sopenharmony_ci if (chan == 1) 47862306a36Sopenharmony_ci tssdp |= ts_sdp_sel_tt1[pin]; 47962306a36Sopenharmony_ci else 48062306a36Sopenharmony_ci tssdp |= ts_sdp_sel_tt0[pin]; 48162306a36Sopenharmony_ci } 48262306a36Sopenharmony_ci tssdp |= ts_sdp_en[pin]; 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ci wr32(E1000_TSSDP, tssdp); 48562306a36Sopenharmony_ci wr32(E1000_CTRL, ctrl); 48662306a36Sopenharmony_ci wr32(E1000_CTRL_EXT, ctrl_ext); 48762306a36Sopenharmony_ci} 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_cistatic int igb_ptp_feature_enable_82580(struct ptp_clock_info *ptp, 49062306a36Sopenharmony_ci struct ptp_clock_request *rq, int on) 49162306a36Sopenharmony_ci{ 49262306a36Sopenharmony_ci struct igb_adapter *igb = 49362306a36Sopenharmony_ci container_of(ptp, struct igb_adapter, ptp_caps); 49462306a36Sopenharmony_ci u32 tsauxc, tsim, tsauxc_mask, tsim_mask, trgttiml, trgttimh, systiml, 49562306a36Sopenharmony_ci systimh, level_mask, level, rem; 49662306a36Sopenharmony_ci struct e1000_hw *hw = &igb->hw; 49762306a36Sopenharmony_ci struct timespec64 ts, start; 49862306a36Sopenharmony_ci unsigned long flags; 49962306a36Sopenharmony_ci u64 systim, now; 50062306a36Sopenharmony_ci int pin = -1; 50162306a36Sopenharmony_ci s64 ns; 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci switch (rq->type) { 50462306a36Sopenharmony_ci case PTP_CLK_REQ_EXTTS: 50562306a36Sopenharmony_ci /* Reject requests with unsupported flags */ 50662306a36Sopenharmony_ci if (rq->extts.flags & ~(PTP_ENABLE_FEATURE | 50762306a36Sopenharmony_ci PTP_RISING_EDGE | 50862306a36Sopenharmony_ci PTP_FALLING_EDGE | 50962306a36Sopenharmony_ci PTP_STRICT_FLAGS)) 51062306a36Sopenharmony_ci return -EOPNOTSUPP; 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci if (on) { 51362306a36Sopenharmony_ci pin = ptp_find_pin(igb->ptp_clock, PTP_PF_EXTTS, 51462306a36Sopenharmony_ci rq->extts.index); 51562306a36Sopenharmony_ci if (pin < 0) 51662306a36Sopenharmony_ci return -EBUSY; 51762306a36Sopenharmony_ci } 51862306a36Sopenharmony_ci if (rq->extts.index == 1) { 51962306a36Sopenharmony_ci tsauxc_mask = TSAUXC_EN_TS1; 52062306a36Sopenharmony_ci tsim_mask = TSINTR_AUTT1; 52162306a36Sopenharmony_ci } else { 52262306a36Sopenharmony_ci tsauxc_mask = TSAUXC_EN_TS0; 52362306a36Sopenharmony_ci tsim_mask = TSINTR_AUTT0; 52462306a36Sopenharmony_ci } 52562306a36Sopenharmony_ci spin_lock_irqsave(&igb->tmreg_lock, flags); 52662306a36Sopenharmony_ci tsauxc = rd32(E1000_TSAUXC); 52762306a36Sopenharmony_ci tsim = rd32(E1000_TSIM); 52862306a36Sopenharmony_ci if (on) { 52962306a36Sopenharmony_ci igb_pin_extts(igb, rq->extts.index, pin); 53062306a36Sopenharmony_ci tsauxc |= tsauxc_mask; 53162306a36Sopenharmony_ci tsim |= tsim_mask; 53262306a36Sopenharmony_ci } else { 53362306a36Sopenharmony_ci tsauxc &= ~tsauxc_mask; 53462306a36Sopenharmony_ci tsim &= ~tsim_mask; 53562306a36Sopenharmony_ci } 53662306a36Sopenharmony_ci wr32(E1000_TSAUXC, tsauxc); 53762306a36Sopenharmony_ci wr32(E1000_TSIM, tsim); 53862306a36Sopenharmony_ci spin_unlock_irqrestore(&igb->tmreg_lock, flags); 53962306a36Sopenharmony_ci return 0; 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci case PTP_CLK_REQ_PEROUT: 54262306a36Sopenharmony_ci /* Reject requests with unsupported flags */ 54362306a36Sopenharmony_ci if (rq->perout.flags) 54462306a36Sopenharmony_ci return -EOPNOTSUPP; 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_ci if (on) { 54762306a36Sopenharmony_ci pin = ptp_find_pin(igb->ptp_clock, PTP_PF_PEROUT, 54862306a36Sopenharmony_ci rq->perout.index); 54962306a36Sopenharmony_ci if (pin < 0) 55062306a36Sopenharmony_ci return -EBUSY; 55162306a36Sopenharmony_ci } 55262306a36Sopenharmony_ci ts.tv_sec = rq->perout.period.sec; 55362306a36Sopenharmony_ci ts.tv_nsec = rq->perout.period.nsec; 55462306a36Sopenharmony_ci ns = timespec64_to_ns(&ts); 55562306a36Sopenharmony_ci ns = ns >> 1; 55662306a36Sopenharmony_ci if (on && ns < 8LL) 55762306a36Sopenharmony_ci return -EINVAL; 55862306a36Sopenharmony_ci ts = ns_to_timespec64(ns); 55962306a36Sopenharmony_ci if (rq->perout.index == 1) { 56062306a36Sopenharmony_ci tsauxc_mask = TSAUXC_EN_TT1; 56162306a36Sopenharmony_ci tsim_mask = TSINTR_TT1; 56262306a36Sopenharmony_ci trgttiml = E1000_TRGTTIML1; 56362306a36Sopenharmony_ci trgttimh = E1000_TRGTTIMH1; 56462306a36Sopenharmony_ci } else { 56562306a36Sopenharmony_ci tsauxc_mask = TSAUXC_EN_TT0; 56662306a36Sopenharmony_ci tsim_mask = TSINTR_TT0; 56762306a36Sopenharmony_ci trgttiml = E1000_TRGTTIML0; 56862306a36Sopenharmony_ci trgttimh = E1000_TRGTTIMH0; 56962306a36Sopenharmony_ci } 57062306a36Sopenharmony_ci spin_lock_irqsave(&igb->tmreg_lock, flags); 57162306a36Sopenharmony_ci tsauxc = rd32(E1000_TSAUXC); 57262306a36Sopenharmony_ci tsim = rd32(E1000_TSIM); 57362306a36Sopenharmony_ci if (rq->perout.index == 1) { 57462306a36Sopenharmony_ci tsauxc &= ~(TSAUXC_EN_TT1 | TSAUXC_EN_CLK1 | TSAUXC_ST1); 57562306a36Sopenharmony_ci tsim &= ~TSINTR_TT1; 57662306a36Sopenharmony_ci } else { 57762306a36Sopenharmony_ci tsauxc &= ~(TSAUXC_EN_TT0 | TSAUXC_EN_CLK0 | TSAUXC_ST0); 57862306a36Sopenharmony_ci tsim &= ~TSINTR_TT0; 57962306a36Sopenharmony_ci } 58062306a36Sopenharmony_ci if (on) { 58162306a36Sopenharmony_ci int i = rq->perout.index; 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_ci /* read systim registers in sequence */ 58462306a36Sopenharmony_ci rd32(E1000_SYSTIMR); 58562306a36Sopenharmony_ci systiml = rd32(E1000_SYSTIML); 58662306a36Sopenharmony_ci systimh = rd32(E1000_SYSTIMH); 58762306a36Sopenharmony_ci systim = (((u64)(systimh & 0xFF)) << 32) | ((u64)systiml); 58862306a36Sopenharmony_ci now = timecounter_cyc2time(&igb->tc, systim); 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci if (pin < 2) { 59162306a36Sopenharmony_ci level_mask = (i == 1) ? 0x80000 : 0x40000; 59262306a36Sopenharmony_ci level = (rd32(E1000_CTRL) & level_mask) ? 1 : 0; 59362306a36Sopenharmony_ci } else { 59462306a36Sopenharmony_ci level_mask = (i == 1) ? 0x80 : 0x40; 59562306a36Sopenharmony_ci level = (rd32(E1000_CTRL_EXT) & level_mask) ? 1 : 0; 59662306a36Sopenharmony_ci } 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ci div_u64_rem(now, ns, &rem); 59962306a36Sopenharmony_ci systim = systim + (ns - rem); 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci /* synchronize pin level with rising/falling edges */ 60262306a36Sopenharmony_ci div_u64_rem(now, ns << 1, &rem); 60362306a36Sopenharmony_ci if (rem < ns) { 60462306a36Sopenharmony_ci /* first half of period */ 60562306a36Sopenharmony_ci if (level == 0) { 60662306a36Sopenharmony_ci /* output is already low, skip this period */ 60762306a36Sopenharmony_ci systim += ns; 60862306a36Sopenharmony_ci } 60962306a36Sopenharmony_ci } else { 61062306a36Sopenharmony_ci /* second half of period */ 61162306a36Sopenharmony_ci if (level == 1) { 61262306a36Sopenharmony_ci /* output is already high, skip this period */ 61362306a36Sopenharmony_ci systim += ns; 61462306a36Sopenharmony_ci } 61562306a36Sopenharmony_ci } 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_ci start = ns_to_timespec64(systim + (ns - rem)); 61862306a36Sopenharmony_ci igb_pin_perout(igb, i, pin, 0); 61962306a36Sopenharmony_ci igb->perout[i].start.tv_sec = start.tv_sec; 62062306a36Sopenharmony_ci igb->perout[i].start.tv_nsec = start.tv_nsec; 62162306a36Sopenharmony_ci igb->perout[i].period.tv_sec = ts.tv_sec; 62262306a36Sopenharmony_ci igb->perout[i].period.tv_nsec = ts.tv_nsec; 62362306a36Sopenharmony_ci 62462306a36Sopenharmony_ci wr32(trgttiml, (u32)systim); 62562306a36Sopenharmony_ci wr32(trgttimh, ((u32)(systim >> 32)) & 0xFF); 62662306a36Sopenharmony_ci tsauxc |= tsauxc_mask; 62762306a36Sopenharmony_ci tsim |= tsim_mask; 62862306a36Sopenharmony_ci } 62962306a36Sopenharmony_ci wr32(E1000_TSAUXC, tsauxc); 63062306a36Sopenharmony_ci wr32(E1000_TSIM, tsim); 63162306a36Sopenharmony_ci spin_unlock_irqrestore(&igb->tmreg_lock, flags); 63262306a36Sopenharmony_ci return 0; 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci case PTP_CLK_REQ_PPS: 63562306a36Sopenharmony_ci return -EOPNOTSUPP; 63662306a36Sopenharmony_ci } 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_ci return -EOPNOTSUPP; 63962306a36Sopenharmony_ci} 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_cistatic int igb_ptp_feature_enable_i210(struct ptp_clock_info *ptp, 64262306a36Sopenharmony_ci struct ptp_clock_request *rq, int on) 64362306a36Sopenharmony_ci{ 64462306a36Sopenharmony_ci struct igb_adapter *igb = 64562306a36Sopenharmony_ci container_of(ptp, struct igb_adapter, ptp_caps); 64662306a36Sopenharmony_ci struct e1000_hw *hw = &igb->hw; 64762306a36Sopenharmony_ci u32 tsauxc, tsim, tsauxc_mask, tsim_mask, trgttiml, trgttimh, freqout; 64862306a36Sopenharmony_ci unsigned long flags; 64962306a36Sopenharmony_ci struct timespec64 ts; 65062306a36Sopenharmony_ci int use_freq = 0, pin = -1; 65162306a36Sopenharmony_ci s64 ns; 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_ci switch (rq->type) { 65462306a36Sopenharmony_ci case PTP_CLK_REQ_EXTTS: 65562306a36Sopenharmony_ci /* Reject requests with unsupported flags */ 65662306a36Sopenharmony_ci if (rq->extts.flags & ~(PTP_ENABLE_FEATURE | 65762306a36Sopenharmony_ci PTP_RISING_EDGE | 65862306a36Sopenharmony_ci PTP_FALLING_EDGE | 65962306a36Sopenharmony_ci PTP_STRICT_FLAGS)) 66062306a36Sopenharmony_ci return -EOPNOTSUPP; 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_ci /* Reject requests failing to enable both edges. */ 66362306a36Sopenharmony_ci if ((rq->extts.flags & PTP_STRICT_FLAGS) && 66462306a36Sopenharmony_ci (rq->extts.flags & PTP_ENABLE_FEATURE) && 66562306a36Sopenharmony_ci (rq->extts.flags & PTP_EXTTS_EDGES) != PTP_EXTTS_EDGES) 66662306a36Sopenharmony_ci return -EOPNOTSUPP; 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_ci if (on) { 66962306a36Sopenharmony_ci pin = ptp_find_pin(igb->ptp_clock, PTP_PF_EXTTS, 67062306a36Sopenharmony_ci rq->extts.index); 67162306a36Sopenharmony_ci if (pin < 0) 67262306a36Sopenharmony_ci return -EBUSY; 67362306a36Sopenharmony_ci } 67462306a36Sopenharmony_ci if (rq->extts.index == 1) { 67562306a36Sopenharmony_ci tsauxc_mask = TSAUXC_EN_TS1; 67662306a36Sopenharmony_ci tsim_mask = TSINTR_AUTT1; 67762306a36Sopenharmony_ci } else { 67862306a36Sopenharmony_ci tsauxc_mask = TSAUXC_EN_TS0; 67962306a36Sopenharmony_ci tsim_mask = TSINTR_AUTT0; 68062306a36Sopenharmony_ci } 68162306a36Sopenharmony_ci spin_lock_irqsave(&igb->tmreg_lock, flags); 68262306a36Sopenharmony_ci tsauxc = rd32(E1000_TSAUXC); 68362306a36Sopenharmony_ci tsim = rd32(E1000_TSIM); 68462306a36Sopenharmony_ci if (on) { 68562306a36Sopenharmony_ci igb_pin_extts(igb, rq->extts.index, pin); 68662306a36Sopenharmony_ci tsauxc |= tsauxc_mask; 68762306a36Sopenharmony_ci tsim |= tsim_mask; 68862306a36Sopenharmony_ci } else { 68962306a36Sopenharmony_ci tsauxc &= ~tsauxc_mask; 69062306a36Sopenharmony_ci tsim &= ~tsim_mask; 69162306a36Sopenharmony_ci } 69262306a36Sopenharmony_ci wr32(E1000_TSAUXC, tsauxc); 69362306a36Sopenharmony_ci wr32(E1000_TSIM, tsim); 69462306a36Sopenharmony_ci spin_unlock_irqrestore(&igb->tmreg_lock, flags); 69562306a36Sopenharmony_ci return 0; 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_ci case PTP_CLK_REQ_PEROUT: 69862306a36Sopenharmony_ci /* Reject requests with unsupported flags */ 69962306a36Sopenharmony_ci if (rq->perout.flags) 70062306a36Sopenharmony_ci return -EOPNOTSUPP; 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_ci if (on) { 70362306a36Sopenharmony_ci pin = ptp_find_pin(igb->ptp_clock, PTP_PF_PEROUT, 70462306a36Sopenharmony_ci rq->perout.index); 70562306a36Sopenharmony_ci if (pin < 0) 70662306a36Sopenharmony_ci return -EBUSY; 70762306a36Sopenharmony_ci } 70862306a36Sopenharmony_ci ts.tv_sec = rq->perout.period.sec; 70962306a36Sopenharmony_ci ts.tv_nsec = rq->perout.period.nsec; 71062306a36Sopenharmony_ci ns = timespec64_to_ns(&ts); 71162306a36Sopenharmony_ci ns = ns >> 1; 71262306a36Sopenharmony_ci if (on && ((ns <= 70000000LL) || (ns == 125000000LL) || 71362306a36Sopenharmony_ci (ns == 250000000LL) || (ns == 500000000LL))) { 71462306a36Sopenharmony_ci if (ns < 8LL) 71562306a36Sopenharmony_ci return -EINVAL; 71662306a36Sopenharmony_ci use_freq = 1; 71762306a36Sopenharmony_ci } 71862306a36Sopenharmony_ci ts = ns_to_timespec64(ns); 71962306a36Sopenharmony_ci if (rq->perout.index == 1) { 72062306a36Sopenharmony_ci if (use_freq) { 72162306a36Sopenharmony_ci tsauxc_mask = TSAUXC_EN_CLK1 | TSAUXC_ST1; 72262306a36Sopenharmony_ci tsim_mask = 0; 72362306a36Sopenharmony_ci } else { 72462306a36Sopenharmony_ci tsauxc_mask = TSAUXC_EN_TT1; 72562306a36Sopenharmony_ci tsim_mask = TSINTR_TT1; 72662306a36Sopenharmony_ci } 72762306a36Sopenharmony_ci trgttiml = E1000_TRGTTIML1; 72862306a36Sopenharmony_ci trgttimh = E1000_TRGTTIMH1; 72962306a36Sopenharmony_ci freqout = E1000_FREQOUT1; 73062306a36Sopenharmony_ci } else { 73162306a36Sopenharmony_ci if (use_freq) { 73262306a36Sopenharmony_ci tsauxc_mask = TSAUXC_EN_CLK0 | TSAUXC_ST0; 73362306a36Sopenharmony_ci tsim_mask = 0; 73462306a36Sopenharmony_ci } else { 73562306a36Sopenharmony_ci tsauxc_mask = TSAUXC_EN_TT0; 73662306a36Sopenharmony_ci tsim_mask = TSINTR_TT0; 73762306a36Sopenharmony_ci } 73862306a36Sopenharmony_ci trgttiml = E1000_TRGTTIML0; 73962306a36Sopenharmony_ci trgttimh = E1000_TRGTTIMH0; 74062306a36Sopenharmony_ci freqout = E1000_FREQOUT0; 74162306a36Sopenharmony_ci } 74262306a36Sopenharmony_ci spin_lock_irqsave(&igb->tmreg_lock, flags); 74362306a36Sopenharmony_ci tsauxc = rd32(E1000_TSAUXC); 74462306a36Sopenharmony_ci tsim = rd32(E1000_TSIM); 74562306a36Sopenharmony_ci if (rq->perout.index == 1) { 74662306a36Sopenharmony_ci tsauxc &= ~(TSAUXC_EN_TT1 | TSAUXC_EN_CLK1 | TSAUXC_ST1); 74762306a36Sopenharmony_ci tsim &= ~TSINTR_TT1; 74862306a36Sopenharmony_ci } else { 74962306a36Sopenharmony_ci tsauxc &= ~(TSAUXC_EN_TT0 | TSAUXC_EN_CLK0 | TSAUXC_ST0); 75062306a36Sopenharmony_ci tsim &= ~TSINTR_TT0; 75162306a36Sopenharmony_ci } 75262306a36Sopenharmony_ci if (on) { 75362306a36Sopenharmony_ci int i = rq->perout.index; 75462306a36Sopenharmony_ci igb_pin_perout(igb, i, pin, use_freq); 75562306a36Sopenharmony_ci igb->perout[i].start.tv_sec = rq->perout.start.sec; 75662306a36Sopenharmony_ci igb->perout[i].start.tv_nsec = rq->perout.start.nsec; 75762306a36Sopenharmony_ci igb->perout[i].period.tv_sec = ts.tv_sec; 75862306a36Sopenharmony_ci igb->perout[i].period.tv_nsec = ts.tv_nsec; 75962306a36Sopenharmony_ci wr32(trgttimh, rq->perout.start.sec); 76062306a36Sopenharmony_ci wr32(trgttiml, rq->perout.start.nsec); 76162306a36Sopenharmony_ci if (use_freq) 76262306a36Sopenharmony_ci wr32(freqout, ns); 76362306a36Sopenharmony_ci tsauxc |= tsauxc_mask; 76462306a36Sopenharmony_ci tsim |= tsim_mask; 76562306a36Sopenharmony_ci } 76662306a36Sopenharmony_ci wr32(E1000_TSAUXC, tsauxc); 76762306a36Sopenharmony_ci wr32(E1000_TSIM, tsim); 76862306a36Sopenharmony_ci spin_unlock_irqrestore(&igb->tmreg_lock, flags); 76962306a36Sopenharmony_ci return 0; 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_ci case PTP_CLK_REQ_PPS: 77262306a36Sopenharmony_ci spin_lock_irqsave(&igb->tmreg_lock, flags); 77362306a36Sopenharmony_ci tsim = rd32(E1000_TSIM); 77462306a36Sopenharmony_ci if (on) 77562306a36Sopenharmony_ci tsim |= TSINTR_SYS_WRAP; 77662306a36Sopenharmony_ci else 77762306a36Sopenharmony_ci tsim &= ~TSINTR_SYS_WRAP; 77862306a36Sopenharmony_ci igb->pps_sys_wrap_on = !!on; 77962306a36Sopenharmony_ci wr32(E1000_TSIM, tsim); 78062306a36Sopenharmony_ci spin_unlock_irqrestore(&igb->tmreg_lock, flags); 78162306a36Sopenharmony_ci return 0; 78262306a36Sopenharmony_ci } 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_ci return -EOPNOTSUPP; 78562306a36Sopenharmony_ci} 78662306a36Sopenharmony_ci 78762306a36Sopenharmony_cistatic int igb_ptp_feature_enable(struct ptp_clock_info *ptp, 78862306a36Sopenharmony_ci struct ptp_clock_request *rq, int on) 78962306a36Sopenharmony_ci{ 79062306a36Sopenharmony_ci return -EOPNOTSUPP; 79162306a36Sopenharmony_ci} 79262306a36Sopenharmony_ci 79362306a36Sopenharmony_cistatic int igb_ptp_verify_pin(struct ptp_clock_info *ptp, unsigned int pin, 79462306a36Sopenharmony_ci enum ptp_pin_function func, unsigned int chan) 79562306a36Sopenharmony_ci{ 79662306a36Sopenharmony_ci switch (func) { 79762306a36Sopenharmony_ci case PTP_PF_NONE: 79862306a36Sopenharmony_ci case PTP_PF_EXTTS: 79962306a36Sopenharmony_ci case PTP_PF_PEROUT: 80062306a36Sopenharmony_ci break; 80162306a36Sopenharmony_ci case PTP_PF_PHYSYNC: 80262306a36Sopenharmony_ci return -1; 80362306a36Sopenharmony_ci } 80462306a36Sopenharmony_ci return 0; 80562306a36Sopenharmony_ci} 80662306a36Sopenharmony_ci 80762306a36Sopenharmony_ci/** 80862306a36Sopenharmony_ci * igb_ptp_tx_work 80962306a36Sopenharmony_ci * @work: pointer to work struct 81062306a36Sopenharmony_ci * 81162306a36Sopenharmony_ci * This work function polls the TSYNCTXCTL valid bit to determine when a 81262306a36Sopenharmony_ci * timestamp has been taken for the current stored skb. 81362306a36Sopenharmony_ci **/ 81462306a36Sopenharmony_cistatic void igb_ptp_tx_work(struct work_struct *work) 81562306a36Sopenharmony_ci{ 81662306a36Sopenharmony_ci struct igb_adapter *adapter = container_of(work, struct igb_adapter, 81762306a36Sopenharmony_ci ptp_tx_work); 81862306a36Sopenharmony_ci struct e1000_hw *hw = &adapter->hw; 81962306a36Sopenharmony_ci u32 tsynctxctl; 82062306a36Sopenharmony_ci 82162306a36Sopenharmony_ci if (!adapter->ptp_tx_skb) 82262306a36Sopenharmony_ci return; 82362306a36Sopenharmony_ci 82462306a36Sopenharmony_ci if (time_is_before_jiffies(adapter->ptp_tx_start + 82562306a36Sopenharmony_ci IGB_PTP_TX_TIMEOUT)) { 82662306a36Sopenharmony_ci dev_kfree_skb_any(adapter->ptp_tx_skb); 82762306a36Sopenharmony_ci adapter->ptp_tx_skb = NULL; 82862306a36Sopenharmony_ci clear_bit_unlock(__IGB_PTP_TX_IN_PROGRESS, &adapter->state); 82962306a36Sopenharmony_ci adapter->tx_hwtstamp_timeouts++; 83062306a36Sopenharmony_ci /* Clear the tx valid bit in TSYNCTXCTL register to enable 83162306a36Sopenharmony_ci * interrupt 83262306a36Sopenharmony_ci */ 83362306a36Sopenharmony_ci rd32(E1000_TXSTMPH); 83462306a36Sopenharmony_ci dev_warn(&adapter->pdev->dev, "clearing Tx timestamp hang\n"); 83562306a36Sopenharmony_ci return; 83662306a36Sopenharmony_ci } 83762306a36Sopenharmony_ci 83862306a36Sopenharmony_ci tsynctxctl = rd32(E1000_TSYNCTXCTL); 83962306a36Sopenharmony_ci if (tsynctxctl & E1000_TSYNCTXCTL_VALID) 84062306a36Sopenharmony_ci igb_ptp_tx_hwtstamp(adapter); 84162306a36Sopenharmony_ci else 84262306a36Sopenharmony_ci /* reschedule to check later */ 84362306a36Sopenharmony_ci schedule_work(&adapter->ptp_tx_work); 84462306a36Sopenharmony_ci} 84562306a36Sopenharmony_ci 84662306a36Sopenharmony_cistatic void igb_ptp_overflow_check(struct work_struct *work) 84762306a36Sopenharmony_ci{ 84862306a36Sopenharmony_ci struct igb_adapter *igb = 84962306a36Sopenharmony_ci container_of(work, struct igb_adapter, ptp_overflow_work.work); 85062306a36Sopenharmony_ci struct timespec64 ts; 85162306a36Sopenharmony_ci u64 ns; 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_ci /* Update the timecounter */ 85462306a36Sopenharmony_ci ns = timecounter_read(&igb->tc); 85562306a36Sopenharmony_ci 85662306a36Sopenharmony_ci ts = ns_to_timespec64(ns); 85762306a36Sopenharmony_ci pr_debug("igb overflow check at %lld.%09lu\n", 85862306a36Sopenharmony_ci (long long) ts.tv_sec, ts.tv_nsec); 85962306a36Sopenharmony_ci 86062306a36Sopenharmony_ci schedule_delayed_work(&igb->ptp_overflow_work, 86162306a36Sopenharmony_ci IGB_SYSTIM_OVERFLOW_PERIOD); 86262306a36Sopenharmony_ci} 86362306a36Sopenharmony_ci 86462306a36Sopenharmony_ci/** 86562306a36Sopenharmony_ci * igb_ptp_rx_hang - detect error case when Rx timestamp registers latched 86662306a36Sopenharmony_ci * @adapter: private network adapter structure 86762306a36Sopenharmony_ci * 86862306a36Sopenharmony_ci * This watchdog task is scheduled to detect error case where hardware has 86962306a36Sopenharmony_ci * dropped an Rx packet that was timestamped when the ring is full. The 87062306a36Sopenharmony_ci * particular error is rare but leaves the device in a state unable to timestamp 87162306a36Sopenharmony_ci * any future packets. 87262306a36Sopenharmony_ci **/ 87362306a36Sopenharmony_civoid igb_ptp_rx_hang(struct igb_adapter *adapter) 87462306a36Sopenharmony_ci{ 87562306a36Sopenharmony_ci struct e1000_hw *hw = &adapter->hw; 87662306a36Sopenharmony_ci u32 tsyncrxctl = rd32(E1000_TSYNCRXCTL); 87762306a36Sopenharmony_ci unsigned long rx_event; 87862306a36Sopenharmony_ci 87962306a36Sopenharmony_ci /* Other hardware uses per-packet timestamps */ 88062306a36Sopenharmony_ci if (hw->mac.type != e1000_82576) 88162306a36Sopenharmony_ci return; 88262306a36Sopenharmony_ci 88362306a36Sopenharmony_ci /* If we don't have a valid timestamp in the registers, just update the 88462306a36Sopenharmony_ci * timeout counter and exit 88562306a36Sopenharmony_ci */ 88662306a36Sopenharmony_ci if (!(tsyncrxctl & E1000_TSYNCRXCTL_VALID)) { 88762306a36Sopenharmony_ci adapter->last_rx_ptp_check = jiffies; 88862306a36Sopenharmony_ci return; 88962306a36Sopenharmony_ci } 89062306a36Sopenharmony_ci 89162306a36Sopenharmony_ci /* Determine the most recent watchdog or rx_timestamp event */ 89262306a36Sopenharmony_ci rx_event = adapter->last_rx_ptp_check; 89362306a36Sopenharmony_ci if (time_after(adapter->last_rx_timestamp, rx_event)) 89462306a36Sopenharmony_ci rx_event = adapter->last_rx_timestamp; 89562306a36Sopenharmony_ci 89662306a36Sopenharmony_ci /* Only need to read the high RXSTMP register to clear the lock */ 89762306a36Sopenharmony_ci if (time_is_before_jiffies(rx_event + 5 * HZ)) { 89862306a36Sopenharmony_ci rd32(E1000_RXSTMPH); 89962306a36Sopenharmony_ci adapter->last_rx_ptp_check = jiffies; 90062306a36Sopenharmony_ci adapter->rx_hwtstamp_cleared++; 90162306a36Sopenharmony_ci dev_warn(&adapter->pdev->dev, "clearing Rx timestamp hang\n"); 90262306a36Sopenharmony_ci } 90362306a36Sopenharmony_ci} 90462306a36Sopenharmony_ci 90562306a36Sopenharmony_ci/** 90662306a36Sopenharmony_ci * igb_ptp_tx_hang - detect error case where Tx timestamp never finishes 90762306a36Sopenharmony_ci * @adapter: private network adapter structure 90862306a36Sopenharmony_ci */ 90962306a36Sopenharmony_civoid igb_ptp_tx_hang(struct igb_adapter *adapter) 91062306a36Sopenharmony_ci{ 91162306a36Sopenharmony_ci struct e1000_hw *hw = &adapter->hw; 91262306a36Sopenharmony_ci bool timeout = time_is_before_jiffies(adapter->ptp_tx_start + 91362306a36Sopenharmony_ci IGB_PTP_TX_TIMEOUT); 91462306a36Sopenharmony_ci 91562306a36Sopenharmony_ci if (!adapter->ptp_tx_skb) 91662306a36Sopenharmony_ci return; 91762306a36Sopenharmony_ci 91862306a36Sopenharmony_ci if (!test_bit(__IGB_PTP_TX_IN_PROGRESS, &adapter->state)) 91962306a36Sopenharmony_ci return; 92062306a36Sopenharmony_ci 92162306a36Sopenharmony_ci /* If we haven't received a timestamp within the timeout, it is 92262306a36Sopenharmony_ci * reasonable to assume that it will never occur, so we can unlock the 92362306a36Sopenharmony_ci * timestamp bit when this occurs. 92462306a36Sopenharmony_ci */ 92562306a36Sopenharmony_ci if (timeout) { 92662306a36Sopenharmony_ci cancel_work_sync(&adapter->ptp_tx_work); 92762306a36Sopenharmony_ci dev_kfree_skb_any(adapter->ptp_tx_skb); 92862306a36Sopenharmony_ci adapter->ptp_tx_skb = NULL; 92962306a36Sopenharmony_ci clear_bit_unlock(__IGB_PTP_TX_IN_PROGRESS, &adapter->state); 93062306a36Sopenharmony_ci adapter->tx_hwtstamp_timeouts++; 93162306a36Sopenharmony_ci /* Clear the tx valid bit in TSYNCTXCTL register to enable 93262306a36Sopenharmony_ci * interrupt 93362306a36Sopenharmony_ci */ 93462306a36Sopenharmony_ci rd32(E1000_TXSTMPH); 93562306a36Sopenharmony_ci dev_warn(&adapter->pdev->dev, "clearing Tx timestamp hang\n"); 93662306a36Sopenharmony_ci } 93762306a36Sopenharmony_ci} 93862306a36Sopenharmony_ci 93962306a36Sopenharmony_ci/** 94062306a36Sopenharmony_ci * igb_ptp_tx_hwtstamp - utility function which checks for TX time stamp 94162306a36Sopenharmony_ci * @adapter: Board private structure. 94262306a36Sopenharmony_ci * 94362306a36Sopenharmony_ci * If we were asked to do hardware stamping and such a time stamp is 94462306a36Sopenharmony_ci * available, then it must have been for this skb here because we only 94562306a36Sopenharmony_ci * allow only one such packet into the queue. 94662306a36Sopenharmony_ci **/ 94762306a36Sopenharmony_cistatic void igb_ptp_tx_hwtstamp(struct igb_adapter *adapter) 94862306a36Sopenharmony_ci{ 94962306a36Sopenharmony_ci struct sk_buff *skb = adapter->ptp_tx_skb; 95062306a36Sopenharmony_ci struct e1000_hw *hw = &adapter->hw; 95162306a36Sopenharmony_ci struct skb_shared_hwtstamps shhwtstamps; 95262306a36Sopenharmony_ci u64 regval; 95362306a36Sopenharmony_ci int adjust = 0; 95462306a36Sopenharmony_ci 95562306a36Sopenharmony_ci regval = rd32(E1000_TXSTMPL); 95662306a36Sopenharmony_ci regval |= (u64)rd32(E1000_TXSTMPH) << 32; 95762306a36Sopenharmony_ci 95862306a36Sopenharmony_ci igb_ptp_systim_to_hwtstamp(adapter, &shhwtstamps, regval); 95962306a36Sopenharmony_ci /* adjust timestamp for the TX latency based on link speed */ 96062306a36Sopenharmony_ci if (hw->mac.type == e1000_i210 || hw->mac.type == e1000_i211) { 96162306a36Sopenharmony_ci switch (adapter->link_speed) { 96262306a36Sopenharmony_ci case SPEED_10: 96362306a36Sopenharmony_ci adjust = IGB_I210_TX_LATENCY_10; 96462306a36Sopenharmony_ci break; 96562306a36Sopenharmony_ci case SPEED_100: 96662306a36Sopenharmony_ci adjust = IGB_I210_TX_LATENCY_100; 96762306a36Sopenharmony_ci break; 96862306a36Sopenharmony_ci case SPEED_1000: 96962306a36Sopenharmony_ci adjust = IGB_I210_TX_LATENCY_1000; 97062306a36Sopenharmony_ci break; 97162306a36Sopenharmony_ci } 97262306a36Sopenharmony_ci } 97362306a36Sopenharmony_ci 97462306a36Sopenharmony_ci shhwtstamps.hwtstamp = 97562306a36Sopenharmony_ci ktime_add_ns(shhwtstamps.hwtstamp, adjust); 97662306a36Sopenharmony_ci 97762306a36Sopenharmony_ci /* Clear the lock early before calling skb_tstamp_tx so that 97862306a36Sopenharmony_ci * applications are not woken up before the lock bit is clear. We use 97962306a36Sopenharmony_ci * a copy of the skb pointer to ensure other threads can't change it 98062306a36Sopenharmony_ci * while we're notifying the stack. 98162306a36Sopenharmony_ci */ 98262306a36Sopenharmony_ci adapter->ptp_tx_skb = NULL; 98362306a36Sopenharmony_ci clear_bit_unlock(__IGB_PTP_TX_IN_PROGRESS, &adapter->state); 98462306a36Sopenharmony_ci 98562306a36Sopenharmony_ci /* Notify the stack and free the skb after we've unlocked */ 98662306a36Sopenharmony_ci skb_tstamp_tx(skb, &shhwtstamps); 98762306a36Sopenharmony_ci dev_kfree_skb_any(skb); 98862306a36Sopenharmony_ci} 98962306a36Sopenharmony_ci 99062306a36Sopenharmony_ci/** 99162306a36Sopenharmony_ci * igb_ptp_rx_pktstamp - retrieve Rx per packet timestamp 99262306a36Sopenharmony_ci * @q_vector: Pointer to interrupt specific structure 99362306a36Sopenharmony_ci * @va: Pointer to address containing Rx buffer 99462306a36Sopenharmony_ci * @timestamp: Pointer where timestamp will be stored 99562306a36Sopenharmony_ci * 99662306a36Sopenharmony_ci * This function is meant to retrieve a timestamp from the first buffer of an 99762306a36Sopenharmony_ci * incoming frame. The value is stored in little endian format starting on 99862306a36Sopenharmony_ci * byte 8 99962306a36Sopenharmony_ci * 100062306a36Sopenharmony_ci * Returns: The timestamp header length or 0 if not available 100162306a36Sopenharmony_ci **/ 100262306a36Sopenharmony_ciint igb_ptp_rx_pktstamp(struct igb_q_vector *q_vector, void *va, 100362306a36Sopenharmony_ci ktime_t *timestamp) 100462306a36Sopenharmony_ci{ 100562306a36Sopenharmony_ci struct igb_adapter *adapter = q_vector->adapter; 100662306a36Sopenharmony_ci struct e1000_hw *hw = &adapter->hw; 100762306a36Sopenharmony_ci struct skb_shared_hwtstamps ts; 100862306a36Sopenharmony_ci __le64 *regval = (__le64 *)va; 100962306a36Sopenharmony_ci int adjust = 0; 101062306a36Sopenharmony_ci 101162306a36Sopenharmony_ci if (!(adapter->ptp_flags & IGB_PTP_ENABLED)) 101262306a36Sopenharmony_ci return 0; 101362306a36Sopenharmony_ci 101462306a36Sopenharmony_ci /* The timestamp is recorded in little endian format. 101562306a36Sopenharmony_ci * DWORD: 0 1 2 3 101662306a36Sopenharmony_ci * Field: Reserved Reserved SYSTIML SYSTIMH 101762306a36Sopenharmony_ci */ 101862306a36Sopenharmony_ci 101962306a36Sopenharmony_ci /* check reserved dwords are zero, be/le doesn't matter for zero */ 102062306a36Sopenharmony_ci if (regval[0]) 102162306a36Sopenharmony_ci return 0; 102262306a36Sopenharmony_ci 102362306a36Sopenharmony_ci igb_ptp_systim_to_hwtstamp(adapter, &ts, le64_to_cpu(regval[1])); 102462306a36Sopenharmony_ci 102562306a36Sopenharmony_ci /* adjust timestamp for the RX latency based on link speed */ 102662306a36Sopenharmony_ci if (hw->mac.type == e1000_i210 || hw->mac.type == e1000_i211) { 102762306a36Sopenharmony_ci switch (adapter->link_speed) { 102862306a36Sopenharmony_ci case SPEED_10: 102962306a36Sopenharmony_ci adjust = IGB_I210_RX_LATENCY_10; 103062306a36Sopenharmony_ci break; 103162306a36Sopenharmony_ci case SPEED_100: 103262306a36Sopenharmony_ci adjust = IGB_I210_RX_LATENCY_100; 103362306a36Sopenharmony_ci break; 103462306a36Sopenharmony_ci case SPEED_1000: 103562306a36Sopenharmony_ci adjust = IGB_I210_RX_LATENCY_1000; 103662306a36Sopenharmony_ci break; 103762306a36Sopenharmony_ci } 103862306a36Sopenharmony_ci } 103962306a36Sopenharmony_ci 104062306a36Sopenharmony_ci *timestamp = ktime_sub_ns(ts.hwtstamp, adjust); 104162306a36Sopenharmony_ci 104262306a36Sopenharmony_ci return IGB_TS_HDR_LEN; 104362306a36Sopenharmony_ci} 104462306a36Sopenharmony_ci 104562306a36Sopenharmony_ci/** 104662306a36Sopenharmony_ci * igb_ptp_rx_rgtstamp - retrieve Rx timestamp stored in register 104762306a36Sopenharmony_ci * @q_vector: Pointer to interrupt specific structure 104862306a36Sopenharmony_ci * @skb: Buffer containing timestamp and packet 104962306a36Sopenharmony_ci * 105062306a36Sopenharmony_ci * This function is meant to retrieve a timestamp from the internal registers 105162306a36Sopenharmony_ci * of the adapter and store it in the skb. 105262306a36Sopenharmony_ci **/ 105362306a36Sopenharmony_civoid igb_ptp_rx_rgtstamp(struct igb_q_vector *q_vector, struct sk_buff *skb) 105462306a36Sopenharmony_ci{ 105562306a36Sopenharmony_ci struct igb_adapter *adapter = q_vector->adapter; 105662306a36Sopenharmony_ci struct e1000_hw *hw = &adapter->hw; 105762306a36Sopenharmony_ci int adjust = 0; 105862306a36Sopenharmony_ci u64 regval; 105962306a36Sopenharmony_ci 106062306a36Sopenharmony_ci if (!(adapter->ptp_flags & IGB_PTP_ENABLED)) 106162306a36Sopenharmony_ci return; 106262306a36Sopenharmony_ci 106362306a36Sopenharmony_ci /* If this bit is set, then the RX registers contain the time stamp. No 106462306a36Sopenharmony_ci * other packet will be time stamped until we read these registers, so 106562306a36Sopenharmony_ci * read the registers to make them available again. Because only one 106662306a36Sopenharmony_ci * packet can be time stamped at a time, we know that the register 106762306a36Sopenharmony_ci * values must belong to this one here and therefore we don't need to 106862306a36Sopenharmony_ci * compare any of the additional attributes stored for it. 106962306a36Sopenharmony_ci * 107062306a36Sopenharmony_ci * If nothing went wrong, then it should have a shared tx_flags that we 107162306a36Sopenharmony_ci * can turn into a skb_shared_hwtstamps. 107262306a36Sopenharmony_ci */ 107362306a36Sopenharmony_ci if (!(rd32(E1000_TSYNCRXCTL) & E1000_TSYNCRXCTL_VALID)) 107462306a36Sopenharmony_ci return; 107562306a36Sopenharmony_ci 107662306a36Sopenharmony_ci regval = rd32(E1000_RXSTMPL); 107762306a36Sopenharmony_ci regval |= (u64)rd32(E1000_RXSTMPH) << 32; 107862306a36Sopenharmony_ci 107962306a36Sopenharmony_ci igb_ptp_systim_to_hwtstamp(adapter, skb_hwtstamps(skb), regval); 108062306a36Sopenharmony_ci 108162306a36Sopenharmony_ci /* adjust timestamp for the RX latency based on link speed */ 108262306a36Sopenharmony_ci if (adapter->hw.mac.type == e1000_i210) { 108362306a36Sopenharmony_ci switch (adapter->link_speed) { 108462306a36Sopenharmony_ci case SPEED_10: 108562306a36Sopenharmony_ci adjust = IGB_I210_RX_LATENCY_10; 108662306a36Sopenharmony_ci break; 108762306a36Sopenharmony_ci case SPEED_100: 108862306a36Sopenharmony_ci adjust = IGB_I210_RX_LATENCY_100; 108962306a36Sopenharmony_ci break; 109062306a36Sopenharmony_ci case SPEED_1000: 109162306a36Sopenharmony_ci adjust = IGB_I210_RX_LATENCY_1000; 109262306a36Sopenharmony_ci break; 109362306a36Sopenharmony_ci } 109462306a36Sopenharmony_ci } 109562306a36Sopenharmony_ci skb_hwtstamps(skb)->hwtstamp = 109662306a36Sopenharmony_ci ktime_sub_ns(skb_hwtstamps(skb)->hwtstamp, adjust); 109762306a36Sopenharmony_ci 109862306a36Sopenharmony_ci /* Update the last_rx_timestamp timer in order to enable watchdog check 109962306a36Sopenharmony_ci * for error case of latched timestamp on a dropped packet. 110062306a36Sopenharmony_ci */ 110162306a36Sopenharmony_ci adapter->last_rx_timestamp = jiffies; 110262306a36Sopenharmony_ci} 110362306a36Sopenharmony_ci 110462306a36Sopenharmony_ci/** 110562306a36Sopenharmony_ci * igb_ptp_get_ts_config - get hardware time stamping config 110662306a36Sopenharmony_ci * @netdev: netdev struct 110762306a36Sopenharmony_ci * @ifr: interface struct 110862306a36Sopenharmony_ci * 110962306a36Sopenharmony_ci * Get the hwtstamp_config settings to return to the user. Rather than attempt 111062306a36Sopenharmony_ci * to deconstruct the settings from the registers, just return a shadow copy 111162306a36Sopenharmony_ci * of the last known settings. 111262306a36Sopenharmony_ci **/ 111362306a36Sopenharmony_ciint igb_ptp_get_ts_config(struct net_device *netdev, struct ifreq *ifr) 111462306a36Sopenharmony_ci{ 111562306a36Sopenharmony_ci struct igb_adapter *adapter = netdev_priv(netdev); 111662306a36Sopenharmony_ci struct hwtstamp_config *config = &adapter->tstamp_config; 111762306a36Sopenharmony_ci 111862306a36Sopenharmony_ci return copy_to_user(ifr->ifr_data, config, sizeof(*config)) ? 111962306a36Sopenharmony_ci -EFAULT : 0; 112062306a36Sopenharmony_ci} 112162306a36Sopenharmony_ci 112262306a36Sopenharmony_ci/** 112362306a36Sopenharmony_ci * igb_ptp_set_timestamp_mode - setup hardware for timestamping 112462306a36Sopenharmony_ci * @adapter: networking device structure 112562306a36Sopenharmony_ci * @config: hwtstamp configuration 112662306a36Sopenharmony_ci * 112762306a36Sopenharmony_ci * Outgoing time stamping can be enabled and disabled. Play nice and 112862306a36Sopenharmony_ci * disable it when requested, although it shouldn't case any overhead 112962306a36Sopenharmony_ci * when no packet needs it. At most one packet in the queue may be 113062306a36Sopenharmony_ci * marked for time stamping, otherwise it would be impossible to tell 113162306a36Sopenharmony_ci * for sure to which packet the hardware time stamp belongs. 113262306a36Sopenharmony_ci * 113362306a36Sopenharmony_ci * Incoming time stamping has to be configured via the hardware 113462306a36Sopenharmony_ci * filters. Not all combinations are supported, in particular event 113562306a36Sopenharmony_ci * type has to be specified. Matching the kind of event packet is 113662306a36Sopenharmony_ci * not supported, with the exception of "all V2 events regardless of 113762306a36Sopenharmony_ci * level 2 or 4". 113862306a36Sopenharmony_ci */ 113962306a36Sopenharmony_cistatic int igb_ptp_set_timestamp_mode(struct igb_adapter *adapter, 114062306a36Sopenharmony_ci struct hwtstamp_config *config) 114162306a36Sopenharmony_ci{ 114262306a36Sopenharmony_ci struct e1000_hw *hw = &adapter->hw; 114362306a36Sopenharmony_ci u32 tsync_tx_ctl = E1000_TSYNCTXCTL_ENABLED; 114462306a36Sopenharmony_ci u32 tsync_rx_ctl = E1000_TSYNCRXCTL_ENABLED; 114562306a36Sopenharmony_ci u32 tsync_rx_cfg = 0; 114662306a36Sopenharmony_ci bool is_l4 = false; 114762306a36Sopenharmony_ci bool is_l2 = false; 114862306a36Sopenharmony_ci u32 regval; 114962306a36Sopenharmony_ci 115062306a36Sopenharmony_ci switch (config->tx_type) { 115162306a36Sopenharmony_ci case HWTSTAMP_TX_OFF: 115262306a36Sopenharmony_ci tsync_tx_ctl = 0; 115362306a36Sopenharmony_ci break; 115462306a36Sopenharmony_ci case HWTSTAMP_TX_ON: 115562306a36Sopenharmony_ci break; 115662306a36Sopenharmony_ci default: 115762306a36Sopenharmony_ci return -ERANGE; 115862306a36Sopenharmony_ci } 115962306a36Sopenharmony_ci 116062306a36Sopenharmony_ci switch (config->rx_filter) { 116162306a36Sopenharmony_ci case HWTSTAMP_FILTER_NONE: 116262306a36Sopenharmony_ci tsync_rx_ctl = 0; 116362306a36Sopenharmony_ci break; 116462306a36Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V1_L4_SYNC: 116562306a36Sopenharmony_ci tsync_rx_ctl |= E1000_TSYNCRXCTL_TYPE_L4_V1; 116662306a36Sopenharmony_ci tsync_rx_cfg = E1000_TSYNCRXCFG_PTP_V1_SYNC_MESSAGE; 116762306a36Sopenharmony_ci is_l4 = true; 116862306a36Sopenharmony_ci break; 116962306a36Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ: 117062306a36Sopenharmony_ci tsync_rx_ctl |= E1000_TSYNCRXCTL_TYPE_L4_V1; 117162306a36Sopenharmony_ci tsync_rx_cfg = E1000_TSYNCRXCFG_PTP_V1_DELAY_REQ_MESSAGE; 117262306a36Sopenharmony_ci is_l4 = true; 117362306a36Sopenharmony_ci break; 117462306a36Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V2_EVENT: 117562306a36Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V2_L2_EVENT: 117662306a36Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V2_L4_EVENT: 117762306a36Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V2_SYNC: 117862306a36Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V2_L2_SYNC: 117962306a36Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V2_L4_SYNC: 118062306a36Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ: 118162306a36Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ: 118262306a36Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ: 118362306a36Sopenharmony_ci tsync_rx_ctl |= E1000_TSYNCRXCTL_TYPE_EVENT_V2; 118462306a36Sopenharmony_ci config->rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT; 118562306a36Sopenharmony_ci is_l2 = true; 118662306a36Sopenharmony_ci is_l4 = true; 118762306a36Sopenharmony_ci break; 118862306a36Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V1_L4_EVENT: 118962306a36Sopenharmony_ci case HWTSTAMP_FILTER_NTP_ALL: 119062306a36Sopenharmony_ci case HWTSTAMP_FILTER_ALL: 119162306a36Sopenharmony_ci /* 82576 cannot timestamp all packets, which it needs to do to 119262306a36Sopenharmony_ci * support both V1 Sync and Delay_Req messages 119362306a36Sopenharmony_ci */ 119462306a36Sopenharmony_ci if (hw->mac.type != e1000_82576) { 119562306a36Sopenharmony_ci tsync_rx_ctl |= E1000_TSYNCRXCTL_TYPE_ALL; 119662306a36Sopenharmony_ci config->rx_filter = HWTSTAMP_FILTER_ALL; 119762306a36Sopenharmony_ci break; 119862306a36Sopenharmony_ci } 119962306a36Sopenharmony_ci fallthrough; 120062306a36Sopenharmony_ci default: 120162306a36Sopenharmony_ci config->rx_filter = HWTSTAMP_FILTER_NONE; 120262306a36Sopenharmony_ci return -ERANGE; 120362306a36Sopenharmony_ci } 120462306a36Sopenharmony_ci 120562306a36Sopenharmony_ci if (hw->mac.type == e1000_82575) { 120662306a36Sopenharmony_ci if (tsync_rx_ctl | tsync_tx_ctl) 120762306a36Sopenharmony_ci return -EINVAL; 120862306a36Sopenharmony_ci return 0; 120962306a36Sopenharmony_ci } 121062306a36Sopenharmony_ci 121162306a36Sopenharmony_ci /* Per-packet timestamping only works if all packets are 121262306a36Sopenharmony_ci * timestamped, so enable timestamping in all packets as 121362306a36Sopenharmony_ci * long as one Rx filter was configured. 121462306a36Sopenharmony_ci */ 121562306a36Sopenharmony_ci if ((hw->mac.type >= e1000_82580) && tsync_rx_ctl) { 121662306a36Sopenharmony_ci tsync_rx_ctl = E1000_TSYNCRXCTL_ENABLED; 121762306a36Sopenharmony_ci tsync_rx_ctl |= E1000_TSYNCRXCTL_TYPE_ALL; 121862306a36Sopenharmony_ci config->rx_filter = HWTSTAMP_FILTER_ALL; 121962306a36Sopenharmony_ci is_l2 = true; 122062306a36Sopenharmony_ci is_l4 = true; 122162306a36Sopenharmony_ci 122262306a36Sopenharmony_ci if ((hw->mac.type == e1000_i210) || 122362306a36Sopenharmony_ci (hw->mac.type == e1000_i211)) { 122462306a36Sopenharmony_ci regval = rd32(E1000_RXPBS); 122562306a36Sopenharmony_ci regval |= E1000_RXPBS_CFG_TS_EN; 122662306a36Sopenharmony_ci wr32(E1000_RXPBS, regval); 122762306a36Sopenharmony_ci } 122862306a36Sopenharmony_ci } 122962306a36Sopenharmony_ci 123062306a36Sopenharmony_ci /* enable/disable TX */ 123162306a36Sopenharmony_ci regval = rd32(E1000_TSYNCTXCTL); 123262306a36Sopenharmony_ci regval &= ~E1000_TSYNCTXCTL_ENABLED; 123362306a36Sopenharmony_ci regval |= tsync_tx_ctl; 123462306a36Sopenharmony_ci wr32(E1000_TSYNCTXCTL, regval); 123562306a36Sopenharmony_ci 123662306a36Sopenharmony_ci /* enable/disable RX */ 123762306a36Sopenharmony_ci regval = rd32(E1000_TSYNCRXCTL); 123862306a36Sopenharmony_ci regval &= ~(E1000_TSYNCRXCTL_ENABLED | E1000_TSYNCRXCTL_TYPE_MASK); 123962306a36Sopenharmony_ci regval |= tsync_rx_ctl; 124062306a36Sopenharmony_ci wr32(E1000_TSYNCRXCTL, regval); 124162306a36Sopenharmony_ci 124262306a36Sopenharmony_ci /* define which PTP packets are time stamped */ 124362306a36Sopenharmony_ci wr32(E1000_TSYNCRXCFG, tsync_rx_cfg); 124462306a36Sopenharmony_ci 124562306a36Sopenharmony_ci /* define ethertype filter for timestamped packets */ 124662306a36Sopenharmony_ci if (is_l2) 124762306a36Sopenharmony_ci wr32(E1000_ETQF(IGB_ETQF_FILTER_1588), 124862306a36Sopenharmony_ci (E1000_ETQF_FILTER_ENABLE | /* enable filter */ 124962306a36Sopenharmony_ci E1000_ETQF_1588 | /* enable timestamping */ 125062306a36Sopenharmony_ci ETH_P_1588)); /* 1588 eth protocol type */ 125162306a36Sopenharmony_ci else 125262306a36Sopenharmony_ci wr32(E1000_ETQF(IGB_ETQF_FILTER_1588), 0); 125362306a36Sopenharmony_ci 125462306a36Sopenharmony_ci /* L4 Queue Filter[3]: filter by destination port and protocol */ 125562306a36Sopenharmony_ci if (is_l4) { 125662306a36Sopenharmony_ci u32 ftqf = (IPPROTO_UDP /* UDP */ 125762306a36Sopenharmony_ci | E1000_FTQF_VF_BP /* VF not compared */ 125862306a36Sopenharmony_ci | E1000_FTQF_1588_TIME_STAMP /* Enable Timestamping */ 125962306a36Sopenharmony_ci | E1000_FTQF_MASK); /* mask all inputs */ 126062306a36Sopenharmony_ci ftqf &= ~E1000_FTQF_MASK_PROTO_BP; /* enable protocol check */ 126162306a36Sopenharmony_ci 126262306a36Sopenharmony_ci wr32(E1000_IMIR(3), (__force unsigned int)htons(PTP_EV_PORT)); 126362306a36Sopenharmony_ci wr32(E1000_IMIREXT(3), 126462306a36Sopenharmony_ci (E1000_IMIREXT_SIZE_BP | E1000_IMIREXT_CTRL_BP)); 126562306a36Sopenharmony_ci if (hw->mac.type == e1000_82576) { 126662306a36Sopenharmony_ci /* enable source port check */ 126762306a36Sopenharmony_ci wr32(E1000_SPQF(3), (__force unsigned int)htons(PTP_EV_PORT)); 126862306a36Sopenharmony_ci ftqf &= ~E1000_FTQF_MASK_SOURCE_PORT_BP; 126962306a36Sopenharmony_ci } 127062306a36Sopenharmony_ci wr32(E1000_FTQF(3), ftqf); 127162306a36Sopenharmony_ci } else { 127262306a36Sopenharmony_ci wr32(E1000_FTQF(3), E1000_FTQF_MASK); 127362306a36Sopenharmony_ci } 127462306a36Sopenharmony_ci wrfl(); 127562306a36Sopenharmony_ci 127662306a36Sopenharmony_ci /* clear TX/RX time stamp registers, just to be sure */ 127762306a36Sopenharmony_ci regval = rd32(E1000_TXSTMPL); 127862306a36Sopenharmony_ci regval = rd32(E1000_TXSTMPH); 127962306a36Sopenharmony_ci regval = rd32(E1000_RXSTMPL); 128062306a36Sopenharmony_ci regval = rd32(E1000_RXSTMPH); 128162306a36Sopenharmony_ci 128262306a36Sopenharmony_ci return 0; 128362306a36Sopenharmony_ci} 128462306a36Sopenharmony_ci 128562306a36Sopenharmony_ci/** 128662306a36Sopenharmony_ci * igb_ptp_set_ts_config - set hardware time stamping config 128762306a36Sopenharmony_ci * @netdev: netdev struct 128862306a36Sopenharmony_ci * @ifr: interface struct 128962306a36Sopenharmony_ci * 129062306a36Sopenharmony_ci **/ 129162306a36Sopenharmony_ciint igb_ptp_set_ts_config(struct net_device *netdev, struct ifreq *ifr) 129262306a36Sopenharmony_ci{ 129362306a36Sopenharmony_ci struct igb_adapter *adapter = netdev_priv(netdev); 129462306a36Sopenharmony_ci struct hwtstamp_config config; 129562306a36Sopenharmony_ci int err; 129662306a36Sopenharmony_ci 129762306a36Sopenharmony_ci if (copy_from_user(&config, ifr->ifr_data, sizeof(config))) 129862306a36Sopenharmony_ci return -EFAULT; 129962306a36Sopenharmony_ci 130062306a36Sopenharmony_ci err = igb_ptp_set_timestamp_mode(adapter, &config); 130162306a36Sopenharmony_ci if (err) 130262306a36Sopenharmony_ci return err; 130362306a36Sopenharmony_ci 130462306a36Sopenharmony_ci /* save these settings for future reference */ 130562306a36Sopenharmony_ci memcpy(&adapter->tstamp_config, &config, 130662306a36Sopenharmony_ci sizeof(adapter->tstamp_config)); 130762306a36Sopenharmony_ci 130862306a36Sopenharmony_ci return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ? 130962306a36Sopenharmony_ci -EFAULT : 0; 131062306a36Sopenharmony_ci} 131162306a36Sopenharmony_ci 131262306a36Sopenharmony_ci/** 131362306a36Sopenharmony_ci * igb_ptp_init - Initialize PTP functionality 131462306a36Sopenharmony_ci * @adapter: Board private structure 131562306a36Sopenharmony_ci * 131662306a36Sopenharmony_ci * This function is called at device probe to initialize the PTP 131762306a36Sopenharmony_ci * functionality. 131862306a36Sopenharmony_ci */ 131962306a36Sopenharmony_civoid igb_ptp_init(struct igb_adapter *adapter) 132062306a36Sopenharmony_ci{ 132162306a36Sopenharmony_ci struct e1000_hw *hw = &adapter->hw; 132262306a36Sopenharmony_ci struct net_device *netdev = adapter->netdev; 132362306a36Sopenharmony_ci 132462306a36Sopenharmony_ci switch (hw->mac.type) { 132562306a36Sopenharmony_ci case e1000_82576: 132662306a36Sopenharmony_ci snprintf(adapter->ptp_caps.name, 16, "%pm", netdev->dev_addr); 132762306a36Sopenharmony_ci adapter->ptp_caps.owner = THIS_MODULE; 132862306a36Sopenharmony_ci adapter->ptp_caps.max_adj = 999999881; 132962306a36Sopenharmony_ci adapter->ptp_caps.n_ext_ts = 0; 133062306a36Sopenharmony_ci adapter->ptp_caps.pps = 0; 133162306a36Sopenharmony_ci adapter->ptp_caps.adjfine = igb_ptp_adjfine_82576; 133262306a36Sopenharmony_ci adapter->ptp_caps.adjtime = igb_ptp_adjtime_82576; 133362306a36Sopenharmony_ci adapter->ptp_caps.gettimex64 = igb_ptp_gettimex_82576; 133462306a36Sopenharmony_ci adapter->ptp_caps.settime64 = igb_ptp_settime_82576; 133562306a36Sopenharmony_ci adapter->ptp_caps.enable = igb_ptp_feature_enable; 133662306a36Sopenharmony_ci adapter->cc.read = igb_ptp_read_82576; 133762306a36Sopenharmony_ci adapter->cc.mask = CYCLECOUNTER_MASK(64); 133862306a36Sopenharmony_ci adapter->cc.mult = 1; 133962306a36Sopenharmony_ci adapter->cc.shift = IGB_82576_TSYNC_SHIFT; 134062306a36Sopenharmony_ci adapter->ptp_flags |= IGB_PTP_OVERFLOW_CHECK; 134162306a36Sopenharmony_ci break; 134262306a36Sopenharmony_ci case e1000_82580: 134362306a36Sopenharmony_ci case e1000_i354: 134462306a36Sopenharmony_ci case e1000_i350: 134562306a36Sopenharmony_ci igb_ptp_sdp_init(adapter); 134662306a36Sopenharmony_ci snprintf(adapter->ptp_caps.name, 16, "%pm", netdev->dev_addr); 134762306a36Sopenharmony_ci adapter->ptp_caps.owner = THIS_MODULE; 134862306a36Sopenharmony_ci adapter->ptp_caps.max_adj = 62499999; 134962306a36Sopenharmony_ci adapter->ptp_caps.n_ext_ts = IGB_N_EXTTS; 135062306a36Sopenharmony_ci adapter->ptp_caps.n_per_out = IGB_N_PEROUT; 135162306a36Sopenharmony_ci adapter->ptp_caps.n_pins = IGB_N_SDP; 135262306a36Sopenharmony_ci adapter->ptp_caps.pps = 0; 135362306a36Sopenharmony_ci adapter->ptp_caps.pin_config = adapter->sdp_config; 135462306a36Sopenharmony_ci adapter->ptp_caps.adjfine = igb_ptp_adjfine_82580; 135562306a36Sopenharmony_ci adapter->ptp_caps.adjtime = igb_ptp_adjtime_82576; 135662306a36Sopenharmony_ci adapter->ptp_caps.gettimex64 = igb_ptp_gettimex_82580; 135762306a36Sopenharmony_ci adapter->ptp_caps.settime64 = igb_ptp_settime_82576; 135862306a36Sopenharmony_ci adapter->ptp_caps.enable = igb_ptp_feature_enable_82580; 135962306a36Sopenharmony_ci adapter->ptp_caps.verify = igb_ptp_verify_pin; 136062306a36Sopenharmony_ci adapter->cc.read = igb_ptp_read_82580; 136162306a36Sopenharmony_ci adapter->cc.mask = CYCLECOUNTER_MASK(IGB_NBITS_82580); 136262306a36Sopenharmony_ci adapter->cc.mult = 1; 136362306a36Sopenharmony_ci adapter->cc.shift = 0; 136462306a36Sopenharmony_ci adapter->ptp_flags |= IGB_PTP_OVERFLOW_CHECK; 136562306a36Sopenharmony_ci break; 136662306a36Sopenharmony_ci case e1000_i210: 136762306a36Sopenharmony_ci case e1000_i211: 136862306a36Sopenharmony_ci igb_ptp_sdp_init(adapter); 136962306a36Sopenharmony_ci snprintf(adapter->ptp_caps.name, 16, "%pm", netdev->dev_addr); 137062306a36Sopenharmony_ci adapter->ptp_caps.owner = THIS_MODULE; 137162306a36Sopenharmony_ci adapter->ptp_caps.max_adj = 62499999; 137262306a36Sopenharmony_ci adapter->ptp_caps.n_ext_ts = IGB_N_EXTTS; 137362306a36Sopenharmony_ci adapter->ptp_caps.n_per_out = IGB_N_PEROUT; 137462306a36Sopenharmony_ci adapter->ptp_caps.n_pins = IGB_N_SDP; 137562306a36Sopenharmony_ci adapter->ptp_caps.pps = 1; 137662306a36Sopenharmony_ci adapter->ptp_caps.pin_config = adapter->sdp_config; 137762306a36Sopenharmony_ci adapter->ptp_caps.adjfine = igb_ptp_adjfine_82580; 137862306a36Sopenharmony_ci adapter->ptp_caps.adjtime = igb_ptp_adjtime_i210; 137962306a36Sopenharmony_ci adapter->ptp_caps.gettimex64 = igb_ptp_gettimex_i210; 138062306a36Sopenharmony_ci adapter->ptp_caps.settime64 = igb_ptp_settime_i210; 138162306a36Sopenharmony_ci adapter->ptp_caps.enable = igb_ptp_feature_enable_i210; 138262306a36Sopenharmony_ci adapter->ptp_caps.verify = igb_ptp_verify_pin; 138362306a36Sopenharmony_ci break; 138462306a36Sopenharmony_ci default: 138562306a36Sopenharmony_ci adapter->ptp_clock = NULL; 138662306a36Sopenharmony_ci return; 138762306a36Sopenharmony_ci } 138862306a36Sopenharmony_ci 138962306a36Sopenharmony_ci adapter->ptp_clock = ptp_clock_register(&adapter->ptp_caps, 139062306a36Sopenharmony_ci &adapter->pdev->dev); 139162306a36Sopenharmony_ci if (IS_ERR(adapter->ptp_clock)) { 139262306a36Sopenharmony_ci adapter->ptp_clock = NULL; 139362306a36Sopenharmony_ci dev_err(&adapter->pdev->dev, "ptp_clock_register failed\n"); 139462306a36Sopenharmony_ci } else if (adapter->ptp_clock) { 139562306a36Sopenharmony_ci dev_info(&adapter->pdev->dev, "added PHC on %s\n", 139662306a36Sopenharmony_ci adapter->netdev->name); 139762306a36Sopenharmony_ci adapter->ptp_flags |= IGB_PTP_ENABLED; 139862306a36Sopenharmony_ci 139962306a36Sopenharmony_ci spin_lock_init(&adapter->tmreg_lock); 140062306a36Sopenharmony_ci INIT_WORK(&adapter->ptp_tx_work, igb_ptp_tx_work); 140162306a36Sopenharmony_ci 140262306a36Sopenharmony_ci if (adapter->ptp_flags & IGB_PTP_OVERFLOW_CHECK) 140362306a36Sopenharmony_ci INIT_DELAYED_WORK(&adapter->ptp_overflow_work, 140462306a36Sopenharmony_ci igb_ptp_overflow_check); 140562306a36Sopenharmony_ci 140662306a36Sopenharmony_ci adapter->tstamp_config.rx_filter = HWTSTAMP_FILTER_NONE; 140762306a36Sopenharmony_ci adapter->tstamp_config.tx_type = HWTSTAMP_TX_OFF; 140862306a36Sopenharmony_ci 140962306a36Sopenharmony_ci igb_ptp_reset(adapter); 141062306a36Sopenharmony_ci } 141162306a36Sopenharmony_ci} 141262306a36Sopenharmony_ci 141362306a36Sopenharmony_ci/** 141462306a36Sopenharmony_ci * igb_ptp_sdp_init - utility function which inits the SDP config structs 141562306a36Sopenharmony_ci * @adapter: Board private structure. 141662306a36Sopenharmony_ci **/ 141762306a36Sopenharmony_civoid igb_ptp_sdp_init(struct igb_adapter *adapter) 141862306a36Sopenharmony_ci{ 141962306a36Sopenharmony_ci int i; 142062306a36Sopenharmony_ci 142162306a36Sopenharmony_ci for (i = 0; i < IGB_N_SDP; i++) { 142262306a36Sopenharmony_ci struct ptp_pin_desc *ppd = &adapter->sdp_config[i]; 142362306a36Sopenharmony_ci 142462306a36Sopenharmony_ci snprintf(ppd->name, sizeof(ppd->name), "SDP%d", i); 142562306a36Sopenharmony_ci ppd->index = i; 142662306a36Sopenharmony_ci ppd->func = PTP_PF_NONE; 142762306a36Sopenharmony_ci } 142862306a36Sopenharmony_ci} 142962306a36Sopenharmony_ci 143062306a36Sopenharmony_ci/** 143162306a36Sopenharmony_ci * igb_ptp_suspend - Disable PTP work items and prepare for suspend 143262306a36Sopenharmony_ci * @adapter: Board private structure 143362306a36Sopenharmony_ci * 143462306a36Sopenharmony_ci * This function stops the overflow check work and PTP Tx timestamp work, and 143562306a36Sopenharmony_ci * will prepare the device for OS suspend. 143662306a36Sopenharmony_ci */ 143762306a36Sopenharmony_civoid igb_ptp_suspend(struct igb_adapter *adapter) 143862306a36Sopenharmony_ci{ 143962306a36Sopenharmony_ci if (!(adapter->ptp_flags & IGB_PTP_ENABLED)) 144062306a36Sopenharmony_ci return; 144162306a36Sopenharmony_ci 144262306a36Sopenharmony_ci if (adapter->ptp_flags & IGB_PTP_OVERFLOW_CHECK) 144362306a36Sopenharmony_ci cancel_delayed_work_sync(&adapter->ptp_overflow_work); 144462306a36Sopenharmony_ci 144562306a36Sopenharmony_ci cancel_work_sync(&adapter->ptp_tx_work); 144662306a36Sopenharmony_ci if (adapter->ptp_tx_skb) { 144762306a36Sopenharmony_ci dev_kfree_skb_any(adapter->ptp_tx_skb); 144862306a36Sopenharmony_ci adapter->ptp_tx_skb = NULL; 144962306a36Sopenharmony_ci clear_bit_unlock(__IGB_PTP_TX_IN_PROGRESS, &adapter->state); 145062306a36Sopenharmony_ci } 145162306a36Sopenharmony_ci} 145262306a36Sopenharmony_ci 145362306a36Sopenharmony_ci/** 145462306a36Sopenharmony_ci * igb_ptp_stop - Disable PTP device and stop the overflow check. 145562306a36Sopenharmony_ci * @adapter: Board private structure. 145662306a36Sopenharmony_ci * 145762306a36Sopenharmony_ci * This function stops the PTP support and cancels the delayed work. 145862306a36Sopenharmony_ci **/ 145962306a36Sopenharmony_civoid igb_ptp_stop(struct igb_adapter *adapter) 146062306a36Sopenharmony_ci{ 146162306a36Sopenharmony_ci igb_ptp_suspend(adapter); 146262306a36Sopenharmony_ci 146362306a36Sopenharmony_ci if (adapter->ptp_clock) { 146462306a36Sopenharmony_ci ptp_clock_unregister(adapter->ptp_clock); 146562306a36Sopenharmony_ci dev_info(&adapter->pdev->dev, "removed PHC on %s\n", 146662306a36Sopenharmony_ci adapter->netdev->name); 146762306a36Sopenharmony_ci adapter->ptp_flags &= ~IGB_PTP_ENABLED; 146862306a36Sopenharmony_ci } 146962306a36Sopenharmony_ci} 147062306a36Sopenharmony_ci 147162306a36Sopenharmony_ci/** 147262306a36Sopenharmony_ci * igb_ptp_reset - Re-enable the adapter for PTP following a reset. 147362306a36Sopenharmony_ci * @adapter: Board private structure. 147462306a36Sopenharmony_ci * 147562306a36Sopenharmony_ci * This function handles the reset work required to re-enable the PTP device. 147662306a36Sopenharmony_ci **/ 147762306a36Sopenharmony_civoid igb_ptp_reset(struct igb_adapter *adapter) 147862306a36Sopenharmony_ci{ 147962306a36Sopenharmony_ci struct e1000_hw *hw = &adapter->hw; 148062306a36Sopenharmony_ci unsigned long flags; 148162306a36Sopenharmony_ci 148262306a36Sopenharmony_ci /* reset the tstamp_config */ 148362306a36Sopenharmony_ci igb_ptp_set_timestamp_mode(adapter, &adapter->tstamp_config); 148462306a36Sopenharmony_ci 148562306a36Sopenharmony_ci spin_lock_irqsave(&adapter->tmreg_lock, flags); 148662306a36Sopenharmony_ci 148762306a36Sopenharmony_ci switch (adapter->hw.mac.type) { 148862306a36Sopenharmony_ci case e1000_82576: 148962306a36Sopenharmony_ci /* Dial the nominal frequency. */ 149062306a36Sopenharmony_ci wr32(E1000_TIMINCA, INCPERIOD_82576 | INCVALUE_82576); 149162306a36Sopenharmony_ci break; 149262306a36Sopenharmony_ci case e1000_82580: 149362306a36Sopenharmony_ci case e1000_i354: 149462306a36Sopenharmony_ci case e1000_i350: 149562306a36Sopenharmony_ci case e1000_i210: 149662306a36Sopenharmony_ci case e1000_i211: 149762306a36Sopenharmony_ci wr32(E1000_TSAUXC, 0x0); 149862306a36Sopenharmony_ci wr32(E1000_TSSDP, 0x0); 149962306a36Sopenharmony_ci wr32(E1000_TSIM, 150062306a36Sopenharmony_ci TSYNC_INTERRUPTS | 150162306a36Sopenharmony_ci (adapter->pps_sys_wrap_on ? TSINTR_SYS_WRAP : 0)); 150262306a36Sopenharmony_ci wr32(E1000_IMS, E1000_IMS_TS); 150362306a36Sopenharmony_ci break; 150462306a36Sopenharmony_ci default: 150562306a36Sopenharmony_ci /* No work to do. */ 150662306a36Sopenharmony_ci goto out; 150762306a36Sopenharmony_ci } 150862306a36Sopenharmony_ci 150962306a36Sopenharmony_ci /* Re-initialize the timer. */ 151062306a36Sopenharmony_ci if ((hw->mac.type == e1000_i210) || (hw->mac.type == e1000_i211)) { 151162306a36Sopenharmony_ci struct timespec64 ts = ktime_to_timespec64(ktime_get_real()); 151262306a36Sopenharmony_ci 151362306a36Sopenharmony_ci igb_ptp_write_i210(adapter, &ts); 151462306a36Sopenharmony_ci } else { 151562306a36Sopenharmony_ci timecounter_init(&adapter->tc, &adapter->cc, 151662306a36Sopenharmony_ci ktime_to_ns(ktime_get_real())); 151762306a36Sopenharmony_ci } 151862306a36Sopenharmony_ciout: 151962306a36Sopenharmony_ci spin_unlock_irqrestore(&adapter->tmreg_lock, flags); 152062306a36Sopenharmony_ci 152162306a36Sopenharmony_ci wrfl(); 152262306a36Sopenharmony_ci 152362306a36Sopenharmony_ci if (adapter->ptp_flags & IGB_PTP_OVERFLOW_CHECK) 152462306a36Sopenharmony_ci schedule_delayed_work(&adapter->ptp_overflow_work, 152562306a36Sopenharmony_ci IGB_SYSTIM_OVERFLOW_PERIOD); 152662306a36Sopenharmony_ci} 1527