18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 28c2ecf20Sopenharmony_ci/* Copyright (C) 2011 Richard Cochran <richardcochran@gmail.com> */ 38c2ecf20Sopenharmony_ci 48c2ecf20Sopenharmony_ci#include <linux/module.h> 58c2ecf20Sopenharmony_ci#include <linux/device.h> 68c2ecf20Sopenharmony_ci#include <linux/pci.h> 78c2ecf20Sopenharmony_ci#include <linux/ptp_classify.h> 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include "igb.h" 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#define INCVALUE_MASK 0x7fffffff 128c2ecf20Sopenharmony_ci#define ISGN 0x80000000 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci/* The 82580 timesync updates the system timer every 8ns by 8ns, 158c2ecf20Sopenharmony_ci * and this update value cannot be reprogrammed. 168c2ecf20Sopenharmony_ci * 178c2ecf20Sopenharmony_ci * Neither the 82576 nor the 82580 offer registers wide enough to hold 188c2ecf20Sopenharmony_ci * nanoseconds time values for very long. For the 82580, SYSTIM always 198c2ecf20Sopenharmony_ci * counts nanoseconds, but the upper 24 bits are not available. The 208c2ecf20Sopenharmony_ci * frequency is adjusted by changing the 32 bit fractional nanoseconds 218c2ecf20Sopenharmony_ci * register, TIMINCA. 228c2ecf20Sopenharmony_ci * 238c2ecf20Sopenharmony_ci * For the 82576, the SYSTIM register time unit is affect by the 248c2ecf20Sopenharmony_ci * choice of the 24 bit TININCA:IV (incvalue) field. Five bits of this 258c2ecf20Sopenharmony_ci * field are needed to provide the nominal 16 nanosecond period, 268c2ecf20Sopenharmony_ci * leaving 19 bits for fractional nanoseconds. 278c2ecf20Sopenharmony_ci * 288c2ecf20Sopenharmony_ci * We scale the NIC clock cycle by a large factor so that relatively 298c2ecf20Sopenharmony_ci * small clock corrections can be added or subtracted at each clock 308c2ecf20Sopenharmony_ci * tick. The drawbacks of a large factor are a) that the clock 318c2ecf20Sopenharmony_ci * register overflows more quickly (not such a big deal) and b) that 328c2ecf20Sopenharmony_ci * the increment per tick has to fit into 24 bits. As a result we 338c2ecf20Sopenharmony_ci * need to use a shift of 19 so we can fit a value of 16 into the 348c2ecf20Sopenharmony_ci * TIMINCA register. 358c2ecf20Sopenharmony_ci * 368c2ecf20Sopenharmony_ci * 378c2ecf20Sopenharmony_ci * SYSTIMH SYSTIML 388c2ecf20Sopenharmony_ci * +--------------+ +---+---+------+ 398c2ecf20Sopenharmony_ci * 82576 | 32 | | 8 | 5 | 19 | 408c2ecf20Sopenharmony_ci * +--------------+ +---+---+------+ 418c2ecf20Sopenharmony_ci * \________ 45 bits _______/ fract 428c2ecf20Sopenharmony_ci * 438c2ecf20Sopenharmony_ci * +----------+---+ +--------------+ 448c2ecf20Sopenharmony_ci * 82580 | 24 | 8 | | 32 | 458c2ecf20Sopenharmony_ci * +----------+---+ +--------------+ 468c2ecf20Sopenharmony_ci * reserved \______ 40 bits _____/ 478c2ecf20Sopenharmony_ci * 488c2ecf20Sopenharmony_ci * 498c2ecf20Sopenharmony_ci * The 45 bit 82576 SYSTIM overflows every 508c2ecf20Sopenharmony_ci * 2^45 * 10^-9 / 3600 = 9.77 hours. 518c2ecf20Sopenharmony_ci * 528c2ecf20Sopenharmony_ci * The 40 bit 82580 SYSTIM overflows every 538c2ecf20Sopenharmony_ci * 2^40 * 10^-9 / 60 = 18.3 minutes. 548c2ecf20Sopenharmony_ci * 558c2ecf20Sopenharmony_ci * SYSTIM is converted to real time using a timecounter. As 568c2ecf20Sopenharmony_ci * timecounter_cyc2time() allows old timestamps, the timecounter needs 578c2ecf20Sopenharmony_ci * to be updated at least once per half of the SYSTIM interval. 588c2ecf20Sopenharmony_ci * Scheduling of delayed work is not very accurate, and also the NIC 598c2ecf20Sopenharmony_ci * clock can be adjusted to run up to 6% faster and the system clock 608c2ecf20Sopenharmony_ci * up to 10% slower, so we aim for 6 minutes to be sure the actual 618c2ecf20Sopenharmony_ci * interval in the NIC time is shorter than 9.16 minutes. 628c2ecf20Sopenharmony_ci */ 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci#define IGB_SYSTIM_OVERFLOW_PERIOD (HZ * 60 * 6) 658c2ecf20Sopenharmony_ci#define IGB_PTP_TX_TIMEOUT (HZ * 15) 668c2ecf20Sopenharmony_ci#define INCPERIOD_82576 BIT(E1000_TIMINCA_16NS_SHIFT) 678c2ecf20Sopenharmony_ci#define INCVALUE_82576_MASK GENMASK(E1000_TIMINCA_16NS_SHIFT - 1, 0) 688c2ecf20Sopenharmony_ci#define INCVALUE_82576 (16u << IGB_82576_TSYNC_SHIFT) 698c2ecf20Sopenharmony_ci#define IGB_NBITS_82580 40 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_cistatic void igb_ptp_tx_hwtstamp(struct igb_adapter *adapter); 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci/* SYSTIM read access for the 82576 */ 748c2ecf20Sopenharmony_cistatic u64 igb_ptp_read_82576(const struct cyclecounter *cc) 758c2ecf20Sopenharmony_ci{ 768c2ecf20Sopenharmony_ci struct igb_adapter *igb = container_of(cc, struct igb_adapter, cc); 778c2ecf20Sopenharmony_ci struct e1000_hw *hw = &igb->hw; 788c2ecf20Sopenharmony_ci u64 val; 798c2ecf20Sopenharmony_ci u32 lo, hi; 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci lo = rd32(E1000_SYSTIML); 828c2ecf20Sopenharmony_ci hi = rd32(E1000_SYSTIMH); 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci val = ((u64) hi) << 32; 858c2ecf20Sopenharmony_ci val |= lo; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci return val; 888c2ecf20Sopenharmony_ci} 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci/* SYSTIM read access for the 82580 */ 918c2ecf20Sopenharmony_cistatic u64 igb_ptp_read_82580(const struct cyclecounter *cc) 928c2ecf20Sopenharmony_ci{ 938c2ecf20Sopenharmony_ci struct igb_adapter *igb = container_of(cc, struct igb_adapter, cc); 948c2ecf20Sopenharmony_ci struct e1000_hw *hw = &igb->hw; 958c2ecf20Sopenharmony_ci u32 lo, hi; 968c2ecf20Sopenharmony_ci u64 val; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci /* The timestamp latches on lowest register read. For the 82580 998c2ecf20Sopenharmony_ci * the lowest register is SYSTIMR instead of SYSTIML. However we only 1008c2ecf20Sopenharmony_ci * need to provide nanosecond resolution, so we just ignore it. 1018c2ecf20Sopenharmony_ci */ 1028c2ecf20Sopenharmony_ci rd32(E1000_SYSTIMR); 1038c2ecf20Sopenharmony_ci lo = rd32(E1000_SYSTIML); 1048c2ecf20Sopenharmony_ci hi = rd32(E1000_SYSTIMH); 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci val = ((u64) hi) << 32; 1078c2ecf20Sopenharmony_ci val |= lo; 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci return val; 1108c2ecf20Sopenharmony_ci} 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci/* SYSTIM read access for I210/I211 */ 1138c2ecf20Sopenharmony_cistatic void igb_ptp_read_i210(struct igb_adapter *adapter, 1148c2ecf20Sopenharmony_ci struct timespec64 *ts) 1158c2ecf20Sopenharmony_ci{ 1168c2ecf20Sopenharmony_ci struct e1000_hw *hw = &adapter->hw; 1178c2ecf20Sopenharmony_ci u32 sec, nsec; 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci /* The timestamp latches on lowest register read. For I210/I211, the 1208c2ecf20Sopenharmony_ci * lowest register is SYSTIMR. Since we only need to provide nanosecond 1218c2ecf20Sopenharmony_ci * resolution, we can ignore it. 1228c2ecf20Sopenharmony_ci */ 1238c2ecf20Sopenharmony_ci rd32(E1000_SYSTIMR); 1248c2ecf20Sopenharmony_ci nsec = rd32(E1000_SYSTIML); 1258c2ecf20Sopenharmony_ci sec = rd32(E1000_SYSTIMH); 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci ts->tv_sec = sec; 1288c2ecf20Sopenharmony_ci ts->tv_nsec = nsec; 1298c2ecf20Sopenharmony_ci} 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_cistatic void igb_ptp_write_i210(struct igb_adapter *adapter, 1328c2ecf20Sopenharmony_ci const struct timespec64 *ts) 1338c2ecf20Sopenharmony_ci{ 1348c2ecf20Sopenharmony_ci struct e1000_hw *hw = &adapter->hw; 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci /* Writing the SYSTIMR register is not necessary as it only provides 1378c2ecf20Sopenharmony_ci * sub-nanosecond resolution. 1388c2ecf20Sopenharmony_ci */ 1398c2ecf20Sopenharmony_ci wr32(E1000_SYSTIML, ts->tv_nsec); 1408c2ecf20Sopenharmony_ci wr32(E1000_SYSTIMH, (u32)ts->tv_sec); 1418c2ecf20Sopenharmony_ci} 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci/** 1448c2ecf20Sopenharmony_ci * igb_ptp_systim_to_hwtstamp - convert system time value to hw timestamp 1458c2ecf20Sopenharmony_ci * @adapter: board private structure 1468c2ecf20Sopenharmony_ci * @hwtstamps: timestamp structure to update 1478c2ecf20Sopenharmony_ci * @systim: unsigned 64bit system time value. 1488c2ecf20Sopenharmony_ci * 1498c2ecf20Sopenharmony_ci * We need to convert the system time value stored in the RX/TXSTMP registers 1508c2ecf20Sopenharmony_ci * into a hwtstamp which can be used by the upper level timestamping functions. 1518c2ecf20Sopenharmony_ci * 1528c2ecf20Sopenharmony_ci * The 'tmreg_lock' spinlock is used to protect the consistency of the 1538c2ecf20Sopenharmony_ci * system time value. This is needed because reading the 64 bit time 1548c2ecf20Sopenharmony_ci * value involves reading two (or three) 32 bit registers. The first 1558c2ecf20Sopenharmony_ci * read latches the value. Ditto for writing. 1568c2ecf20Sopenharmony_ci * 1578c2ecf20Sopenharmony_ci * In addition, here have extended the system time with an overflow 1588c2ecf20Sopenharmony_ci * counter in software. 1598c2ecf20Sopenharmony_ci **/ 1608c2ecf20Sopenharmony_cistatic void igb_ptp_systim_to_hwtstamp(struct igb_adapter *adapter, 1618c2ecf20Sopenharmony_ci struct skb_shared_hwtstamps *hwtstamps, 1628c2ecf20Sopenharmony_ci u64 systim) 1638c2ecf20Sopenharmony_ci{ 1648c2ecf20Sopenharmony_ci unsigned long flags; 1658c2ecf20Sopenharmony_ci u64 ns; 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci switch (adapter->hw.mac.type) { 1688c2ecf20Sopenharmony_ci case e1000_82576: 1698c2ecf20Sopenharmony_ci case e1000_82580: 1708c2ecf20Sopenharmony_ci case e1000_i354: 1718c2ecf20Sopenharmony_ci case e1000_i350: 1728c2ecf20Sopenharmony_ci spin_lock_irqsave(&adapter->tmreg_lock, flags); 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci ns = timecounter_cyc2time(&adapter->tc, systim); 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&adapter->tmreg_lock, flags); 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci memset(hwtstamps, 0, sizeof(*hwtstamps)); 1798c2ecf20Sopenharmony_ci hwtstamps->hwtstamp = ns_to_ktime(ns); 1808c2ecf20Sopenharmony_ci break; 1818c2ecf20Sopenharmony_ci case e1000_i210: 1828c2ecf20Sopenharmony_ci case e1000_i211: 1838c2ecf20Sopenharmony_ci memset(hwtstamps, 0, sizeof(*hwtstamps)); 1848c2ecf20Sopenharmony_ci /* Upper 32 bits contain s, lower 32 bits contain ns. */ 1858c2ecf20Sopenharmony_ci hwtstamps->hwtstamp = ktime_set(systim >> 32, 1868c2ecf20Sopenharmony_ci systim & 0xFFFFFFFF); 1878c2ecf20Sopenharmony_ci break; 1888c2ecf20Sopenharmony_ci default: 1898c2ecf20Sopenharmony_ci break; 1908c2ecf20Sopenharmony_ci } 1918c2ecf20Sopenharmony_ci} 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci/* PTP clock operations */ 1948c2ecf20Sopenharmony_cistatic int igb_ptp_adjfreq_82576(struct ptp_clock_info *ptp, s32 ppb) 1958c2ecf20Sopenharmony_ci{ 1968c2ecf20Sopenharmony_ci struct igb_adapter *igb = container_of(ptp, struct igb_adapter, 1978c2ecf20Sopenharmony_ci ptp_caps); 1988c2ecf20Sopenharmony_ci struct e1000_hw *hw = &igb->hw; 1998c2ecf20Sopenharmony_ci int neg_adj = 0; 2008c2ecf20Sopenharmony_ci u64 rate; 2018c2ecf20Sopenharmony_ci u32 incvalue; 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci if (ppb < 0) { 2048c2ecf20Sopenharmony_ci neg_adj = 1; 2058c2ecf20Sopenharmony_ci ppb = -ppb; 2068c2ecf20Sopenharmony_ci } 2078c2ecf20Sopenharmony_ci rate = ppb; 2088c2ecf20Sopenharmony_ci rate <<= 14; 2098c2ecf20Sopenharmony_ci rate = div_u64(rate, 1953125); 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci incvalue = 16 << IGB_82576_TSYNC_SHIFT; 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci if (neg_adj) 2148c2ecf20Sopenharmony_ci incvalue -= rate; 2158c2ecf20Sopenharmony_ci else 2168c2ecf20Sopenharmony_ci incvalue += rate; 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci wr32(E1000_TIMINCA, INCPERIOD_82576 | (incvalue & INCVALUE_82576_MASK)); 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci return 0; 2218c2ecf20Sopenharmony_ci} 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_cistatic int igb_ptp_adjfine_82580(struct ptp_clock_info *ptp, long scaled_ppm) 2248c2ecf20Sopenharmony_ci{ 2258c2ecf20Sopenharmony_ci struct igb_adapter *igb = container_of(ptp, struct igb_adapter, 2268c2ecf20Sopenharmony_ci ptp_caps); 2278c2ecf20Sopenharmony_ci struct e1000_hw *hw = &igb->hw; 2288c2ecf20Sopenharmony_ci int neg_adj = 0; 2298c2ecf20Sopenharmony_ci u64 rate; 2308c2ecf20Sopenharmony_ci u32 inca; 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci if (scaled_ppm < 0) { 2338c2ecf20Sopenharmony_ci neg_adj = 1; 2348c2ecf20Sopenharmony_ci scaled_ppm = -scaled_ppm; 2358c2ecf20Sopenharmony_ci } 2368c2ecf20Sopenharmony_ci rate = scaled_ppm; 2378c2ecf20Sopenharmony_ci rate <<= 13; 2388c2ecf20Sopenharmony_ci rate = div_u64(rate, 15625); 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci inca = rate & INCVALUE_MASK; 2418c2ecf20Sopenharmony_ci if (neg_adj) 2428c2ecf20Sopenharmony_ci inca |= ISGN; 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci wr32(E1000_TIMINCA, inca); 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci return 0; 2478c2ecf20Sopenharmony_ci} 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_cistatic int igb_ptp_adjtime_82576(struct ptp_clock_info *ptp, s64 delta) 2508c2ecf20Sopenharmony_ci{ 2518c2ecf20Sopenharmony_ci struct igb_adapter *igb = container_of(ptp, struct igb_adapter, 2528c2ecf20Sopenharmony_ci ptp_caps); 2538c2ecf20Sopenharmony_ci unsigned long flags; 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci spin_lock_irqsave(&igb->tmreg_lock, flags); 2568c2ecf20Sopenharmony_ci timecounter_adjtime(&igb->tc, delta); 2578c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&igb->tmreg_lock, flags); 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci return 0; 2608c2ecf20Sopenharmony_ci} 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_cistatic int igb_ptp_adjtime_i210(struct ptp_clock_info *ptp, s64 delta) 2638c2ecf20Sopenharmony_ci{ 2648c2ecf20Sopenharmony_ci struct igb_adapter *igb = container_of(ptp, struct igb_adapter, 2658c2ecf20Sopenharmony_ci ptp_caps); 2668c2ecf20Sopenharmony_ci unsigned long flags; 2678c2ecf20Sopenharmony_ci struct timespec64 now, then = ns_to_timespec64(delta); 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci spin_lock_irqsave(&igb->tmreg_lock, flags); 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci igb_ptp_read_i210(igb, &now); 2728c2ecf20Sopenharmony_ci now = timespec64_add(now, then); 2738c2ecf20Sopenharmony_ci igb_ptp_write_i210(igb, (const struct timespec64 *)&now); 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&igb->tmreg_lock, flags); 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci return 0; 2788c2ecf20Sopenharmony_ci} 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_cistatic int igb_ptp_gettimex_82576(struct ptp_clock_info *ptp, 2818c2ecf20Sopenharmony_ci struct timespec64 *ts, 2828c2ecf20Sopenharmony_ci struct ptp_system_timestamp *sts) 2838c2ecf20Sopenharmony_ci{ 2848c2ecf20Sopenharmony_ci struct igb_adapter *igb = container_of(ptp, struct igb_adapter, 2858c2ecf20Sopenharmony_ci ptp_caps); 2868c2ecf20Sopenharmony_ci struct e1000_hw *hw = &igb->hw; 2878c2ecf20Sopenharmony_ci unsigned long flags; 2888c2ecf20Sopenharmony_ci u32 lo, hi; 2898c2ecf20Sopenharmony_ci u64 ns; 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci spin_lock_irqsave(&igb->tmreg_lock, flags); 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci ptp_read_system_prets(sts); 2948c2ecf20Sopenharmony_ci lo = rd32(E1000_SYSTIML); 2958c2ecf20Sopenharmony_ci ptp_read_system_postts(sts); 2968c2ecf20Sopenharmony_ci hi = rd32(E1000_SYSTIMH); 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci ns = timecounter_cyc2time(&igb->tc, ((u64)hi << 32) | lo); 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&igb->tmreg_lock, flags); 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci *ts = ns_to_timespec64(ns); 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci return 0; 3058c2ecf20Sopenharmony_ci} 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_cistatic int igb_ptp_gettimex_82580(struct ptp_clock_info *ptp, 3088c2ecf20Sopenharmony_ci struct timespec64 *ts, 3098c2ecf20Sopenharmony_ci struct ptp_system_timestamp *sts) 3108c2ecf20Sopenharmony_ci{ 3118c2ecf20Sopenharmony_ci struct igb_adapter *igb = container_of(ptp, struct igb_adapter, 3128c2ecf20Sopenharmony_ci ptp_caps); 3138c2ecf20Sopenharmony_ci struct e1000_hw *hw = &igb->hw; 3148c2ecf20Sopenharmony_ci unsigned long flags; 3158c2ecf20Sopenharmony_ci u32 lo, hi; 3168c2ecf20Sopenharmony_ci u64 ns; 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci spin_lock_irqsave(&igb->tmreg_lock, flags); 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci ptp_read_system_prets(sts); 3218c2ecf20Sopenharmony_ci rd32(E1000_SYSTIMR); 3228c2ecf20Sopenharmony_ci ptp_read_system_postts(sts); 3238c2ecf20Sopenharmony_ci lo = rd32(E1000_SYSTIML); 3248c2ecf20Sopenharmony_ci hi = rd32(E1000_SYSTIMH); 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci ns = timecounter_cyc2time(&igb->tc, ((u64)hi << 32) | lo); 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&igb->tmreg_lock, flags); 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci *ts = ns_to_timespec64(ns); 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci return 0; 3338c2ecf20Sopenharmony_ci} 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_cistatic int igb_ptp_gettimex_i210(struct ptp_clock_info *ptp, 3368c2ecf20Sopenharmony_ci struct timespec64 *ts, 3378c2ecf20Sopenharmony_ci struct ptp_system_timestamp *sts) 3388c2ecf20Sopenharmony_ci{ 3398c2ecf20Sopenharmony_ci struct igb_adapter *igb = container_of(ptp, struct igb_adapter, 3408c2ecf20Sopenharmony_ci ptp_caps); 3418c2ecf20Sopenharmony_ci struct e1000_hw *hw = &igb->hw; 3428c2ecf20Sopenharmony_ci unsigned long flags; 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci spin_lock_irqsave(&igb->tmreg_lock, flags); 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci ptp_read_system_prets(sts); 3478c2ecf20Sopenharmony_ci rd32(E1000_SYSTIMR); 3488c2ecf20Sopenharmony_ci ptp_read_system_postts(sts); 3498c2ecf20Sopenharmony_ci ts->tv_nsec = rd32(E1000_SYSTIML); 3508c2ecf20Sopenharmony_ci ts->tv_sec = rd32(E1000_SYSTIMH); 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&igb->tmreg_lock, flags); 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci return 0; 3558c2ecf20Sopenharmony_ci} 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_cistatic int igb_ptp_settime_82576(struct ptp_clock_info *ptp, 3588c2ecf20Sopenharmony_ci const struct timespec64 *ts) 3598c2ecf20Sopenharmony_ci{ 3608c2ecf20Sopenharmony_ci struct igb_adapter *igb = container_of(ptp, struct igb_adapter, 3618c2ecf20Sopenharmony_ci ptp_caps); 3628c2ecf20Sopenharmony_ci unsigned long flags; 3638c2ecf20Sopenharmony_ci u64 ns; 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci ns = timespec64_to_ns(ts); 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci spin_lock_irqsave(&igb->tmreg_lock, flags); 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci timecounter_init(&igb->tc, &igb->cc, ns); 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&igb->tmreg_lock, flags); 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci return 0; 3748c2ecf20Sopenharmony_ci} 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_cistatic int igb_ptp_settime_i210(struct ptp_clock_info *ptp, 3778c2ecf20Sopenharmony_ci const struct timespec64 *ts) 3788c2ecf20Sopenharmony_ci{ 3798c2ecf20Sopenharmony_ci struct igb_adapter *igb = container_of(ptp, struct igb_adapter, 3808c2ecf20Sopenharmony_ci ptp_caps); 3818c2ecf20Sopenharmony_ci unsigned long flags; 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci spin_lock_irqsave(&igb->tmreg_lock, flags); 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci igb_ptp_write_i210(igb, ts); 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&igb->tmreg_lock, flags); 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci return 0; 3908c2ecf20Sopenharmony_ci} 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_cistatic void igb_pin_direction(int pin, int input, u32 *ctrl, u32 *ctrl_ext) 3938c2ecf20Sopenharmony_ci{ 3948c2ecf20Sopenharmony_ci u32 *ptr = pin < 2 ? ctrl : ctrl_ext; 3958c2ecf20Sopenharmony_ci static const u32 mask[IGB_N_SDP] = { 3968c2ecf20Sopenharmony_ci E1000_CTRL_SDP0_DIR, 3978c2ecf20Sopenharmony_ci E1000_CTRL_SDP1_DIR, 3988c2ecf20Sopenharmony_ci E1000_CTRL_EXT_SDP2_DIR, 3998c2ecf20Sopenharmony_ci E1000_CTRL_EXT_SDP3_DIR, 4008c2ecf20Sopenharmony_ci }; 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci if (input) 4038c2ecf20Sopenharmony_ci *ptr &= ~mask[pin]; 4048c2ecf20Sopenharmony_ci else 4058c2ecf20Sopenharmony_ci *ptr |= mask[pin]; 4068c2ecf20Sopenharmony_ci} 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_cistatic void igb_pin_extts(struct igb_adapter *igb, int chan, int pin) 4098c2ecf20Sopenharmony_ci{ 4108c2ecf20Sopenharmony_ci static const u32 aux0_sel_sdp[IGB_N_SDP] = { 4118c2ecf20Sopenharmony_ci AUX0_SEL_SDP0, AUX0_SEL_SDP1, AUX0_SEL_SDP2, AUX0_SEL_SDP3, 4128c2ecf20Sopenharmony_ci }; 4138c2ecf20Sopenharmony_ci static const u32 aux1_sel_sdp[IGB_N_SDP] = { 4148c2ecf20Sopenharmony_ci AUX1_SEL_SDP0, AUX1_SEL_SDP1, AUX1_SEL_SDP2, AUX1_SEL_SDP3, 4158c2ecf20Sopenharmony_ci }; 4168c2ecf20Sopenharmony_ci static const u32 ts_sdp_en[IGB_N_SDP] = { 4178c2ecf20Sopenharmony_ci TS_SDP0_EN, TS_SDP1_EN, TS_SDP2_EN, TS_SDP3_EN, 4188c2ecf20Sopenharmony_ci }; 4198c2ecf20Sopenharmony_ci struct e1000_hw *hw = &igb->hw; 4208c2ecf20Sopenharmony_ci u32 ctrl, ctrl_ext, tssdp = 0; 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci ctrl = rd32(E1000_CTRL); 4238c2ecf20Sopenharmony_ci ctrl_ext = rd32(E1000_CTRL_EXT); 4248c2ecf20Sopenharmony_ci tssdp = rd32(E1000_TSSDP); 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci igb_pin_direction(pin, 1, &ctrl, &ctrl_ext); 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci /* Make sure this pin is not enabled as an output. */ 4298c2ecf20Sopenharmony_ci tssdp &= ~ts_sdp_en[pin]; 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci if (chan == 1) { 4328c2ecf20Sopenharmony_ci tssdp &= ~AUX1_SEL_SDP3; 4338c2ecf20Sopenharmony_ci tssdp |= aux1_sel_sdp[pin] | AUX1_TS_SDP_EN; 4348c2ecf20Sopenharmony_ci } else { 4358c2ecf20Sopenharmony_ci tssdp &= ~AUX0_SEL_SDP3; 4368c2ecf20Sopenharmony_ci tssdp |= aux0_sel_sdp[pin] | AUX0_TS_SDP_EN; 4378c2ecf20Sopenharmony_ci } 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci wr32(E1000_TSSDP, tssdp); 4408c2ecf20Sopenharmony_ci wr32(E1000_CTRL, ctrl); 4418c2ecf20Sopenharmony_ci wr32(E1000_CTRL_EXT, ctrl_ext); 4428c2ecf20Sopenharmony_ci} 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_cistatic void igb_pin_perout(struct igb_adapter *igb, int chan, int pin, int freq) 4458c2ecf20Sopenharmony_ci{ 4468c2ecf20Sopenharmony_ci static const u32 aux0_sel_sdp[IGB_N_SDP] = { 4478c2ecf20Sopenharmony_ci AUX0_SEL_SDP0, AUX0_SEL_SDP1, AUX0_SEL_SDP2, AUX0_SEL_SDP3, 4488c2ecf20Sopenharmony_ci }; 4498c2ecf20Sopenharmony_ci static const u32 aux1_sel_sdp[IGB_N_SDP] = { 4508c2ecf20Sopenharmony_ci AUX1_SEL_SDP0, AUX1_SEL_SDP1, AUX1_SEL_SDP2, AUX1_SEL_SDP3, 4518c2ecf20Sopenharmony_ci }; 4528c2ecf20Sopenharmony_ci static const u32 ts_sdp_en[IGB_N_SDP] = { 4538c2ecf20Sopenharmony_ci TS_SDP0_EN, TS_SDP1_EN, TS_SDP2_EN, TS_SDP3_EN, 4548c2ecf20Sopenharmony_ci }; 4558c2ecf20Sopenharmony_ci static const u32 ts_sdp_sel_tt0[IGB_N_SDP] = { 4568c2ecf20Sopenharmony_ci TS_SDP0_SEL_TT0, TS_SDP1_SEL_TT0, 4578c2ecf20Sopenharmony_ci TS_SDP2_SEL_TT0, TS_SDP3_SEL_TT0, 4588c2ecf20Sopenharmony_ci }; 4598c2ecf20Sopenharmony_ci static const u32 ts_sdp_sel_tt1[IGB_N_SDP] = { 4608c2ecf20Sopenharmony_ci TS_SDP0_SEL_TT1, TS_SDP1_SEL_TT1, 4618c2ecf20Sopenharmony_ci TS_SDP2_SEL_TT1, TS_SDP3_SEL_TT1, 4628c2ecf20Sopenharmony_ci }; 4638c2ecf20Sopenharmony_ci static const u32 ts_sdp_sel_fc0[IGB_N_SDP] = { 4648c2ecf20Sopenharmony_ci TS_SDP0_SEL_FC0, TS_SDP1_SEL_FC0, 4658c2ecf20Sopenharmony_ci TS_SDP2_SEL_FC0, TS_SDP3_SEL_FC0, 4668c2ecf20Sopenharmony_ci }; 4678c2ecf20Sopenharmony_ci static const u32 ts_sdp_sel_fc1[IGB_N_SDP] = { 4688c2ecf20Sopenharmony_ci TS_SDP0_SEL_FC1, TS_SDP1_SEL_FC1, 4698c2ecf20Sopenharmony_ci TS_SDP2_SEL_FC1, TS_SDP3_SEL_FC1, 4708c2ecf20Sopenharmony_ci }; 4718c2ecf20Sopenharmony_ci static const u32 ts_sdp_sel_clr[IGB_N_SDP] = { 4728c2ecf20Sopenharmony_ci TS_SDP0_SEL_FC1, TS_SDP1_SEL_FC1, 4738c2ecf20Sopenharmony_ci TS_SDP2_SEL_FC1, TS_SDP3_SEL_FC1, 4748c2ecf20Sopenharmony_ci }; 4758c2ecf20Sopenharmony_ci struct e1000_hw *hw = &igb->hw; 4768c2ecf20Sopenharmony_ci u32 ctrl, ctrl_ext, tssdp = 0; 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci ctrl = rd32(E1000_CTRL); 4798c2ecf20Sopenharmony_ci ctrl_ext = rd32(E1000_CTRL_EXT); 4808c2ecf20Sopenharmony_ci tssdp = rd32(E1000_TSSDP); 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ci igb_pin_direction(pin, 0, &ctrl, &ctrl_ext); 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci /* Make sure this pin is not enabled as an input. */ 4858c2ecf20Sopenharmony_ci if ((tssdp & AUX0_SEL_SDP3) == aux0_sel_sdp[pin]) 4868c2ecf20Sopenharmony_ci tssdp &= ~AUX0_TS_SDP_EN; 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci if ((tssdp & AUX1_SEL_SDP3) == aux1_sel_sdp[pin]) 4898c2ecf20Sopenharmony_ci tssdp &= ~AUX1_TS_SDP_EN; 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci tssdp &= ~ts_sdp_sel_clr[pin]; 4928c2ecf20Sopenharmony_ci if (freq) { 4938c2ecf20Sopenharmony_ci if (chan == 1) 4948c2ecf20Sopenharmony_ci tssdp |= ts_sdp_sel_fc1[pin]; 4958c2ecf20Sopenharmony_ci else 4968c2ecf20Sopenharmony_ci tssdp |= ts_sdp_sel_fc0[pin]; 4978c2ecf20Sopenharmony_ci } else { 4988c2ecf20Sopenharmony_ci if (chan == 1) 4998c2ecf20Sopenharmony_ci tssdp |= ts_sdp_sel_tt1[pin]; 5008c2ecf20Sopenharmony_ci else 5018c2ecf20Sopenharmony_ci tssdp |= ts_sdp_sel_tt0[pin]; 5028c2ecf20Sopenharmony_ci } 5038c2ecf20Sopenharmony_ci tssdp |= ts_sdp_en[pin]; 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci wr32(E1000_TSSDP, tssdp); 5068c2ecf20Sopenharmony_ci wr32(E1000_CTRL, ctrl); 5078c2ecf20Sopenharmony_ci wr32(E1000_CTRL_EXT, ctrl_ext); 5088c2ecf20Sopenharmony_ci} 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_cistatic int igb_ptp_feature_enable_i210(struct ptp_clock_info *ptp, 5118c2ecf20Sopenharmony_ci struct ptp_clock_request *rq, int on) 5128c2ecf20Sopenharmony_ci{ 5138c2ecf20Sopenharmony_ci struct igb_adapter *igb = 5148c2ecf20Sopenharmony_ci container_of(ptp, struct igb_adapter, ptp_caps); 5158c2ecf20Sopenharmony_ci struct e1000_hw *hw = &igb->hw; 5168c2ecf20Sopenharmony_ci u32 tsauxc, tsim, tsauxc_mask, tsim_mask, trgttiml, trgttimh, freqout; 5178c2ecf20Sopenharmony_ci unsigned long flags; 5188c2ecf20Sopenharmony_ci struct timespec64 ts; 5198c2ecf20Sopenharmony_ci int use_freq = 0, pin = -1; 5208c2ecf20Sopenharmony_ci s64 ns; 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ci switch (rq->type) { 5238c2ecf20Sopenharmony_ci case PTP_CLK_REQ_EXTTS: 5248c2ecf20Sopenharmony_ci /* Reject requests with unsupported flags */ 5258c2ecf20Sopenharmony_ci if (rq->extts.flags & ~(PTP_ENABLE_FEATURE | 5268c2ecf20Sopenharmony_ci PTP_RISING_EDGE | 5278c2ecf20Sopenharmony_ci PTP_FALLING_EDGE | 5288c2ecf20Sopenharmony_ci PTP_STRICT_FLAGS)) 5298c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci /* Reject requests failing to enable both edges. */ 5328c2ecf20Sopenharmony_ci if ((rq->extts.flags & PTP_STRICT_FLAGS) && 5338c2ecf20Sopenharmony_ci (rq->extts.flags & PTP_ENABLE_FEATURE) && 5348c2ecf20Sopenharmony_ci (rq->extts.flags & PTP_EXTTS_EDGES) != PTP_EXTTS_EDGES) 5358c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci if (on) { 5388c2ecf20Sopenharmony_ci pin = ptp_find_pin(igb->ptp_clock, PTP_PF_EXTTS, 5398c2ecf20Sopenharmony_ci rq->extts.index); 5408c2ecf20Sopenharmony_ci if (pin < 0) 5418c2ecf20Sopenharmony_ci return -EBUSY; 5428c2ecf20Sopenharmony_ci } 5438c2ecf20Sopenharmony_ci if (rq->extts.index == 1) { 5448c2ecf20Sopenharmony_ci tsauxc_mask = TSAUXC_EN_TS1; 5458c2ecf20Sopenharmony_ci tsim_mask = TSINTR_AUTT1; 5468c2ecf20Sopenharmony_ci } else { 5478c2ecf20Sopenharmony_ci tsauxc_mask = TSAUXC_EN_TS0; 5488c2ecf20Sopenharmony_ci tsim_mask = TSINTR_AUTT0; 5498c2ecf20Sopenharmony_ci } 5508c2ecf20Sopenharmony_ci spin_lock_irqsave(&igb->tmreg_lock, flags); 5518c2ecf20Sopenharmony_ci tsauxc = rd32(E1000_TSAUXC); 5528c2ecf20Sopenharmony_ci tsim = rd32(E1000_TSIM); 5538c2ecf20Sopenharmony_ci if (on) { 5548c2ecf20Sopenharmony_ci igb_pin_extts(igb, rq->extts.index, pin); 5558c2ecf20Sopenharmony_ci tsauxc |= tsauxc_mask; 5568c2ecf20Sopenharmony_ci tsim |= tsim_mask; 5578c2ecf20Sopenharmony_ci } else { 5588c2ecf20Sopenharmony_ci tsauxc &= ~tsauxc_mask; 5598c2ecf20Sopenharmony_ci tsim &= ~tsim_mask; 5608c2ecf20Sopenharmony_ci } 5618c2ecf20Sopenharmony_ci wr32(E1000_TSAUXC, tsauxc); 5628c2ecf20Sopenharmony_ci wr32(E1000_TSIM, tsim); 5638c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&igb->tmreg_lock, flags); 5648c2ecf20Sopenharmony_ci return 0; 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_ci case PTP_CLK_REQ_PEROUT: 5678c2ecf20Sopenharmony_ci /* Reject requests with unsupported flags */ 5688c2ecf20Sopenharmony_ci if (rq->perout.flags) 5698c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ci if (on) { 5728c2ecf20Sopenharmony_ci pin = ptp_find_pin(igb->ptp_clock, PTP_PF_PEROUT, 5738c2ecf20Sopenharmony_ci rq->perout.index); 5748c2ecf20Sopenharmony_ci if (pin < 0) 5758c2ecf20Sopenharmony_ci return -EBUSY; 5768c2ecf20Sopenharmony_ci } 5778c2ecf20Sopenharmony_ci ts.tv_sec = rq->perout.period.sec; 5788c2ecf20Sopenharmony_ci ts.tv_nsec = rq->perout.period.nsec; 5798c2ecf20Sopenharmony_ci ns = timespec64_to_ns(&ts); 5808c2ecf20Sopenharmony_ci ns = ns >> 1; 5818c2ecf20Sopenharmony_ci if (on && ((ns <= 70000000LL) || (ns == 125000000LL) || 5828c2ecf20Sopenharmony_ci (ns == 250000000LL) || (ns == 500000000LL))) { 5838c2ecf20Sopenharmony_ci if (ns < 8LL) 5848c2ecf20Sopenharmony_ci return -EINVAL; 5858c2ecf20Sopenharmony_ci use_freq = 1; 5868c2ecf20Sopenharmony_ci } 5878c2ecf20Sopenharmony_ci ts = ns_to_timespec64(ns); 5888c2ecf20Sopenharmony_ci if (rq->perout.index == 1) { 5898c2ecf20Sopenharmony_ci if (use_freq) { 5908c2ecf20Sopenharmony_ci tsauxc_mask = TSAUXC_EN_CLK1 | TSAUXC_ST1; 5918c2ecf20Sopenharmony_ci tsim_mask = 0; 5928c2ecf20Sopenharmony_ci } else { 5938c2ecf20Sopenharmony_ci tsauxc_mask = TSAUXC_EN_TT1; 5948c2ecf20Sopenharmony_ci tsim_mask = TSINTR_TT1; 5958c2ecf20Sopenharmony_ci } 5968c2ecf20Sopenharmony_ci trgttiml = E1000_TRGTTIML1; 5978c2ecf20Sopenharmony_ci trgttimh = E1000_TRGTTIMH1; 5988c2ecf20Sopenharmony_ci freqout = E1000_FREQOUT1; 5998c2ecf20Sopenharmony_ci } else { 6008c2ecf20Sopenharmony_ci if (use_freq) { 6018c2ecf20Sopenharmony_ci tsauxc_mask = TSAUXC_EN_CLK0 | TSAUXC_ST0; 6028c2ecf20Sopenharmony_ci tsim_mask = 0; 6038c2ecf20Sopenharmony_ci } else { 6048c2ecf20Sopenharmony_ci tsauxc_mask = TSAUXC_EN_TT0; 6058c2ecf20Sopenharmony_ci tsim_mask = TSINTR_TT0; 6068c2ecf20Sopenharmony_ci } 6078c2ecf20Sopenharmony_ci trgttiml = E1000_TRGTTIML0; 6088c2ecf20Sopenharmony_ci trgttimh = E1000_TRGTTIMH0; 6098c2ecf20Sopenharmony_ci freqout = E1000_FREQOUT0; 6108c2ecf20Sopenharmony_ci } 6118c2ecf20Sopenharmony_ci spin_lock_irqsave(&igb->tmreg_lock, flags); 6128c2ecf20Sopenharmony_ci tsauxc = rd32(E1000_TSAUXC); 6138c2ecf20Sopenharmony_ci tsim = rd32(E1000_TSIM); 6148c2ecf20Sopenharmony_ci if (rq->perout.index == 1) { 6158c2ecf20Sopenharmony_ci tsauxc &= ~(TSAUXC_EN_TT1 | TSAUXC_EN_CLK1 | TSAUXC_ST1); 6168c2ecf20Sopenharmony_ci tsim &= ~TSINTR_TT1; 6178c2ecf20Sopenharmony_ci } else { 6188c2ecf20Sopenharmony_ci tsauxc &= ~(TSAUXC_EN_TT0 | TSAUXC_EN_CLK0 | TSAUXC_ST0); 6198c2ecf20Sopenharmony_ci tsim &= ~TSINTR_TT0; 6208c2ecf20Sopenharmony_ci } 6218c2ecf20Sopenharmony_ci if (on) { 6228c2ecf20Sopenharmony_ci int i = rq->perout.index; 6238c2ecf20Sopenharmony_ci igb_pin_perout(igb, i, pin, use_freq); 6248c2ecf20Sopenharmony_ci igb->perout[i].start.tv_sec = rq->perout.start.sec; 6258c2ecf20Sopenharmony_ci igb->perout[i].start.tv_nsec = rq->perout.start.nsec; 6268c2ecf20Sopenharmony_ci igb->perout[i].period.tv_sec = ts.tv_sec; 6278c2ecf20Sopenharmony_ci igb->perout[i].period.tv_nsec = ts.tv_nsec; 6288c2ecf20Sopenharmony_ci wr32(trgttimh, rq->perout.start.sec); 6298c2ecf20Sopenharmony_ci wr32(trgttiml, rq->perout.start.nsec); 6308c2ecf20Sopenharmony_ci if (use_freq) 6318c2ecf20Sopenharmony_ci wr32(freqout, ns); 6328c2ecf20Sopenharmony_ci tsauxc |= tsauxc_mask; 6338c2ecf20Sopenharmony_ci tsim |= tsim_mask; 6348c2ecf20Sopenharmony_ci } 6358c2ecf20Sopenharmony_ci wr32(E1000_TSAUXC, tsauxc); 6368c2ecf20Sopenharmony_ci wr32(E1000_TSIM, tsim); 6378c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&igb->tmreg_lock, flags); 6388c2ecf20Sopenharmony_ci return 0; 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_ci case PTP_CLK_REQ_PPS: 6418c2ecf20Sopenharmony_ci spin_lock_irqsave(&igb->tmreg_lock, flags); 6428c2ecf20Sopenharmony_ci tsim = rd32(E1000_TSIM); 6438c2ecf20Sopenharmony_ci if (on) 6448c2ecf20Sopenharmony_ci tsim |= TSINTR_SYS_WRAP; 6458c2ecf20Sopenharmony_ci else 6468c2ecf20Sopenharmony_ci tsim &= ~TSINTR_SYS_WRAP; 6478c2ecf20Sopenharmony_ci igb->pps_sys_wrap_on = !!on; 6488c2ecf20Sopenharmony_ci wr32(E1000_TSIM, tsim); 6498c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&igb->tmreg_lock, flags); 6508c2ecf20Sopenharmony_ci return 0; 6518c2ecf20Sopenharmony_ci } 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 6548c2ecf20Sopenharmony_ci} 6558c2ecf20Sopenharmony_ci 6568c2ecf20Sopenharmony_cistatic int igb_ptp_feature_enable(struct ptp_clock_info *ptp, 6578c2ecf20Sopenharmony_ci struct ptp_clock_request *rq, int on) 6588c2ecf20Sopenharmony_ci{ 6598c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 6608c2ecf20Sopenharmony_ci} 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_cistatic int igb_ptp_verify_pin(struct ptp_clock_info *ptp, unsigned int pin, 6638c2ecf20Sopenharmony_ci enum ptp_pin_function func, unsigned int chan) 6648c2ecf20Sopenharmony_ci{ 6658c2ecf20Sopenharmony_ci switch (func) { 6668c2ecf20Sopenharmony_ci case PTP_PF_NONE: 6678c2ecf20Sopenharmony_ci case PTP_PF_EXTTS: 6688c2ecf20Sopenharmony_ci case PTP_PF_PEROUT: 6698c2ecf20Sopenharmony_ci break; 6708c2ecf20Sopenharmony_ci case PTP_PF_PHYSYNC: 6718c2ecf20Sopenharmony_ci return -1; 6728c2ecf20Sopenharmony_ci } 6738c2ecf20Sopenharmony_ci return 0; 6748c2ecf20Sopenharmony_ci} 6758c2ecf20Sopenharmony_ci 6768c2ecf20Sopenharmony_ci/** 6778c2ecf20Sopenharmony_ci * igb_ptp_tx_work 6788c2ecf20Sopenharmony_ci * @work: pointer to work struct 6798c2ecf20Sopenharmony_ci * 6808c2ecf20Sopenharmony_ci * This work function polls the TSYNCTXCTL valid bit to determine when a 6818c2ecf20Sopenharmony_ci * timestamp has been taken for the current stored skb. 6828c2ecf20Sopenharmony_ci **/ 6838c2ecf20Sopenharmony_cistatic void igb_ptp_tx_work(struct work_struct *work) 6848c2ecf20Sopenharmony_ci{ 6858c2ecf20Sopenharmony_ci struct igb_adapter *adapter = container_of(work, struct igb_adapter, 6868c2ecf20Sopenharmony_ci ptp_tx_work); 6878c2ecf20Sopenharmony_ci struct e1000_hw *hw = &adapter->hw; 6888c2ecf20Sopenharmony_ci u32 tsynctxctl; 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_ci if (!adapter->ptp_tx_skb) 6918c2ecf20Sopenharmony_ci return; 6928c2ecf20Sopenharmony_ci 6938c2ecf20Sopenharmony_ci if (time_is_before_jiffies(adapter->ptp_tx_start + 6948c2ecf20Sopenharmony_ci IGB_PTP_TX_TIMEOUT)) { 6958c2ecf20Sopenharmony_ci dev_kfree_skb_any(adapter->ptp_tx_skb); 6968c2ecf20Sopenharmony_ci adapter->ptp_tx_skb = NULL; 6978c2ecf20Sopenharmony_ci clear_bit_unlock(__IGB_PTP_TX_IN_PROGRESS, &adapter->state); 6988c2ecf20Sopenharmony_ci adapter->tx_hwtstamp_timeouts++; 6998c2ecf20Sopenharmony_ci /* Clear the tx valid bit in TSYNCTXCTL register to enable 7008c2ecf20Sopenharmony_ci * interrupt 7018c2ecf20Sopenharmony_ci */ 7028c2ecf20Sopenharmony_ci rd32(E1000_TXSTMPH); 7038c2ecf20Sopenharmony_ci dev_warn(&adapter->pdev->dev, "clearing Tx timestamp hang\n"); 7048c2ecf20Sopenharmony_ci return; 7058c2ecf20Sopenharmony_ci } 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_ci tsynctxctl = rd32(E1000_TSYNCTXCTL); 7088c2ecf20Sopenharmony_ci if (tsynctxctl & E1000_TSYNCTXCTL_VALID) 7098c2ecf20Sopenharmony_ci igb_ptp_tx_hwtstamp(adapter); 7108c2ecf20Sopenharmony_ci else 7118c2ecf20Sopenharmony_ci /* reschedule to check later */ 7128c2ecf20Sopenharmony_ci schedule_work(&adapter->ptp_tx_work); 7138c2ecf20Sopenharmony_ci} 7148c2ecf20Sopenharmony_ci 7158c2ecf20Sopenharmony_cistatic void igb_ptp_overflow_check(struct work_struct *work) 7168c2ecf20Sopenharmony_ci{ 7178c2ecf20Sopenharmony_ci struct igb_adapter *igb = 7188c2ecf20Sopenharmony_ci container_of(work, struct igb_adapter, ptp_overflow_work.work); 7198c2ecf20Sopenharmony_ci struct timespec64 ts; 7208c2ecf20Sopenharmony_ci u64 ns; 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_ci /* Update the timecounter */ 7238c2ecf20Sopenharmony_ci ns = timecounter_read(&igb->tc); 7248c2ecf20Sopenharmony_ci 7258c2ecf20Sopenharmony_ci ts = ns_to_timespec64(ns); 7268c2ecf20Sopenharmony_ci pr_debug("igb overflow check at %lld.%09lu\n", 7278c2ecf20Sopenharmony_ci (long long) ts.tv_sec, ts.tv_nsec); 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_ci schedule_delayed_work(&igb->ptp_overflow_work, 7308c2ecf20Sopenharmony_ci IGB_SYSTIM_OVERFLOW_PERIOD); 7318c2ecf20Sopenharmony_ci} 7328c2ecf20Sopenharmony_ci 7338c2ecf20Sopenharmony_ci/** 7348c2ecf20Sopenharmony_ci * igb_ptp_rx_hang - detect error case when Rx timestamp registers latched 7358c2ecf20Sopenharmony_ci * @adapter: private network adapter structure 7368c2ecf20Sopenharmony_ci * 7378c2ecf20Sopenharmony_ci * This watchdog task is scheduled to detect error case where hardware has 7388c2ecf20Sopenharmony_ci * dropped an Rx packet that was timestamped when the ring is full. The 7398c2ecf20Sopenharmony_ci * particular error is rare but leaves the device in a state unable to timestamp 7408c2ecf20Sopenharmony_ci * any future packets. 7418c2ecf20Sopenharmony_ci **/ 7428c2ecf20Sopenharmony_civoid igb_ptp_rx_hang(struct igb_adapter *adapter) 7438c2ecf20Sopenharmony_ci{ 7448c2ecf20Sopenharmony_ci struct e1000_hw *hw = &adapter->hw; 7458c2ecf20Sopenharmony_ci u32 tsyncrxctl = rd32(E1000_TSYNCRXCTL); 7468c2ecf20Sopenharmony_ci unsigned long rx_event; 7478c2ecf20Sopenharmony_ci 7488c2ecf20Sopenharmony_ci /* Other hardware uses per-packet timestamps */ 7498c2ecf20Sopenharmony_ci if (hw->mac.type != e1000_82576) 7508c2ecf20Sopenharmony_ci return; 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_ci /* If we don't have a valid timestamp in the registers, just update the 7538c2ecf20Sopenharmony_ci * timeout counter and exit 7548c2ecf20Sopenharmony_ci */ 7558c2ecf20Sopenharmony_ci if (!(tsyncrxctl & E1000_TSYNCRXCTL_VALID)) { 7568c2ecf20Sopenharmony_ci adapter->last_rx_ptp_check = jiffies; 7578c2ecf20Sopenharmony_ci return; 7588c2ecf20Sopenharmony_ci } 7598c2ecf20Sopenharmony_ci 7608c2ecf20Sopenharmony_ci /* Determine the most recent watchdog or rx_timestamp event */ 7618c2ecf20Sopenharmony_ci rx_event = adapter->last_rx_ptp_check; 7628c2ecf20Sopenharmony_ci if (time_after(adapter->last_rx_timestamp, rx_event)) 7638c2ecf20Sopenharmony_ci rx_event = adapter->last_rx_timestamp; 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_ci /* Only need to read the high RXSTMP register to clear the lock */ 7668c2ecf20Sopenharmony_ci if (time_is_before_jiffies(rx_event + 5 * HZ)) { 7678c2ecf20Sopenharmony_ci rd32(E1000_RXSTMPH); 7688c2ecf20Sopenharmony_ci adapter->last_rx_ptp_check = jiffies; 7698c2ecf20Sopenharmony_ci adapter->rx_hwtstamp_cleared++; 7708c2ecf20Sopenharmony_ci dev_warn(&adapter->pdev->dev, "clearing Rx timestamp hang\n"); 7718c2ecf20Sopenharmony_ci } 7728c2ecf20Sopenharmony_ci} 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_ci/** 7758c2ecf20Sopenharmony_ci * igb_ptp_tx_hang - detect error case where Tx timestamp never finishes 7768c2ecf20Sopenharmony_ci * @adapter: private network adapter structure 7778c2ecf20Sopenharmony_ci */ 7788c2ecf20Sopenharmony_civoid igb_ptp_tx_hang(struct igb_adapter *adapter) 7798c2ecf20Sopenharmony_ci{ 7808c2ecf20Sopenharmony_ci struct e1000_hw *hw = &adapter->hw; 7818c2ecf20Sopenharmony_ci bool timeout = time_is_before_jiffies(adapter->ptp_tx_start + 7828c2ecf20Sopenharmony_ci IGB_PTP_TX_TIMEOUT); 7838c2ecf20Sopenharmony_ci 7848c2ecf20Sopenharmony_ci if (!adapter->ptp_tx_skb) 7858c2ecf20Sopenharmony_ci return; 7868c2ecf20Sopenharmony_ci 7878c2ecf20Sopenharmony_ci if (!test_bit(__IGB_PTP_TX_IN_PROGRESS, &adapter->state)) 7888c2ecf20Sopenharmony_ci return; 7898c2ecf20Sopenharmony_ci 7908c2ecf20Sopenharmony_ci /* If we haven't received a timestamp within the timeout, it is 7918c2ecf20Sopenharmony_ci * reasonable to assume that it will never occur, so we can unlock the 7928c2ecf20Sopenharmony_ci * timestamp bit when this occurs. 7938c2ecf20Sopenharmony_ci */ 7948c2ecf20Sopenharmony_ci if (timeout) { 7958c2ecf20Sopenharmony_ci cancel_work_sync(&adapter->ptp_tx_work); 7968c2ecf20Sopenharmony_ci dev_kfree_skb_any(adapter->ptp_tx_skb); 7978c2ecf20Sopenharmony_ci adapter->ptp_tx_skb = NULL; 7988c2ecf20Sopenharmony_ci clear_bit_unlock(__IGB_PTP_TX_IN_PROGRESS, &adapter->state); 7998c2ecf20Sopenharmony_ci adapter->tx_hwtstamp_timeouts++; 8008c2ecf20Sopenharmony_ci /* Clear the tx valid bit in TSYNCTXCTL register to enable 8018c2ecf20Sopenharmony_ci * interrupt 8028c2ecf20Sopenharmony_ci */ 8038c2ecf20Sopenharmony_ci rd32(E1000_TXSTMPH); 8048c2ecf20Sopenharmony_ci dev_warn(&adapter->pdev->dev, "clearing Tx timestamp hang\n"); 8058c2ecf20Sopenharmony_ci } 8068c2ecf20Sopenharmony_ci} 8078c2ecf20Sopenharmony_ci 8088c2ecf20Sopenharmony_ci/** 8098c2ecf20Sopenharmony_ci * igb_ptp_tx_hwtstamp - utility function which checks for TX time stamp 8108c2ecf20Sopenharmony_ci * @adapter: Board private structure. 8118c2ecf20Sopenharmony_ci * 8128c2ecf20Sopenharmony_ci * If we were asked to do hardware stamping and such a time stamp is 8138c2ecf20Sopenharmony_ci * available, then it must have been for this skb here because we only 8148c2ecf20Sopenharmony_ci * allow only one such packet into the queue. 8158c2ecf20Sopenharmony_ci **/ 8168c2ecf20Sopenharmony_cistatic void igb_ptp_tx_hwtstamp(struct igb_adapter *adapter) 8178c2ecf20Sopenharmony_ci{ 8188c2ecf20Sopenharmony_ci struct sk_buff *skb = adapter->ptp_tx_skb; 8198c2ecf20Sopenharmony_ci struct e1000_hw *hw = &adapter->hw; 8208c2ecf20Sopenharmony_ci struct skb_shared_hwtstamps shhwtstamps; 8218c2ecf20Sopenharmony_ci u64 regval; 8228c2ecf20Sopenharmony_ci int adjust = 0; 8238c2ecf20Sopenharmony_ci 8248c2ecf20Sopenharmony_ci regval = rd32(E1000_TXSTMPL); 8258c2ecf20Sopenharmony_ci regval |= (u64)rd32(E1000_TXSTMPH) << 32; 8268c2ecf20Sopenharmony_ci 8278c2ecf20Sopenharmony_ci igb_ptp_systim_to_hwtstamp(adapter, &shhwtstamps, regval); 8288c2ecf20Sopenharmony_ci /* adjust timestamp for the TX latency based on link speed */ 8298c2ecf20Sopenharmony_ci if (adapter->hw.mac.type == e1000_i210) { 8308c2ecf20Sopenharmony_ci switch (adapter->link_speed) { 8318c2ecf20Sopenharmony_ci case SPEED_10: 8328c2ecf20Sopenharmony_ci adjust = IGB_I210_TX_LATENCY_10; 8338c2ecf20Sopenharmony_ci break; 8348c2ecf20Sopenharmony_ci case SPEED_100: 8358c2ecf20Sopenharmony_ci adjust = IGB_I210_TX_LATENCY_100; 8368c2ecf20Sopenharmony_ci break; 8378c2ecf20Sopenharmony_ci case SPEED_1000: 8388c2ecf20Sopenharmony_ci adjust = IGB_I210_TX_LATENCY_1000; 8398c2ecf20Sopenharmony_ci break; 8408c2ecf20Sopenharmony_ci } 8418c2ecf20Sopenharmony_ci } 8428c2ecf20Sopenharmony_ci 8438c2ecf20Sopenharmony_ci shhwtstamps.hwtstamp = 8448c2ecf20Sopenharmony_ci ktime_add_ns(shhwtstamps.hwtstamp, adjust); 8458c2ecf20Sopenharmony_ci 8468c2ecf20Sopenharmony_ci /* Clear the lock early before calling skb_tstamp_tx so that 8478c2ecf20Sopenharmony_ci * applications are not woken up before the lock bit is clear. We use 8488c2ecf20Sopenharmony_ci * a copy of the skb pointer to ensure other threads can't change it 8498c2ecf20Sopenharmony_ci * while we're notifying the stack. 8508c2ecf20Sopenharmony_ci */ 8518c2ecf20Sopenharmony_ci adapter->ptp_tx_skb = NULL; 8528c2ecf20Sopenharmony_ci clear_bit_unlock(__IGB_PTP_TX_IN_PROGRESS, &adapter->state); 8538c2ecf20Sopenharmony_ci 8548c2ecf20Sopenharmony_ci /* Notify the stack and free the skb after we've unlocked */ 8558c2ecf20Sopenharmony_ci skb_tstamp_tx(skb, &shhwtstamps); 8568c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 8578c2ecf20Sopenharmony_ci} 8588c2ecf20Sopenharmony_ci 8598c2ecf20Sopenharmony_ci#define IGB_RET_PTP_DISABLED 1 8608c2ecf20Sopenharmony_ci#define IGB_RET_PTP_INVALID 2 8618c2ecf20Sopenharmony_ci 8628c2ecf20Sopenharmony_ci/** 8638c2ecf20Sopenharmony_ci * igb_ptp_rx_pktstamp - retrieve Rx per packet timestamp 8648c2ecf20Sopenharmony_ci * @q_vector: Pointer to interrupt specific structure 8658c2ecf20Sopenharmony_ci * @va: Pointer to address containing Rx buffer 8668c2ecf20Sopenharmony_ci * @skb: Buffer containing timestamp and packet 8678c2ecf20Sopenharmony_ci * 8688c2ecf20Sopenharmony_ci * This function is meant to retrieve a timestamp from the first buffer of an 8698c2ecf20Sopenharmony_ci * incoming frame. The value is stored in little endian format starting on 8708c2ecf20Sopenharmony_ci * byte 8 8718c2ecf20Sopenharmony_ci * 8728c2ecf20Sopenharmony_ci * Returns: 0 if success, nonzero if failure 8738c2ecf20Sopenharmony_ci **/ 8748c2ecf20Sopenharmony_ciint igb_ptp_rx_pktstamp(struct igb_q_vector *q_vector, void *va, 8758c2ecf20Sopenharmony_ci struct sk_buff *skb) 8768c2ecf20Sopenharmony_ci{ 8778c2ecf20Sopenharmony_ci struct igb_adapter *adapter = q_vector->adapter; 8788c2ecf20Sopenharmony_ci __le64 *regval = (__le64 *)va; 8798c2ecf20Sopenharmony_ci int adjust = 0; 8808c2ecf20Sopenharmony_ci 8818c2ecf20Sopenharmony_ci if (!(adapter->ptp_flags & IGB_PTP_ENABLED)) 8828c2ecf20Sopenharmony_ci return IGB_RET_PTP_DISABLED; 8838c2ecf20Sopenharmony_ci 8848c2ecf20Sopenharmony_ci /* The timestamp is recorded in little endian format. 8858c2ecf20Sopenharmony_ci * DWORD: 0 1 2 3 8868c2ecf20Sopenharmony_ci * Field: Reserved Reserved SYSTIML SYSTIMH 8878c2ecf20Sopenharmony_ci */ 8888c2ecf20Sopenharmony_ci 8898c2ecf20Sopenharmony_ci /* check reserved dwords are zero, be/le doesn't matter for zero */ 8908c2ecf20Sopenharmony_ci if (regval[0]) 8918c2ecf20Sopenharmony_ci return IGB_RET_PTP_INVALID; 8928c2ecf20Sopenharmony_ci 8938c2ecf20Sopenharmony_ci igb_ptp_systim_to_hwtstamp(adapter, skb_hwtstamps(skb), 8948c2ecf20Sopenharmony_ci le64_to_cpu(regval[1])); 8958c2ecf20Sopenharmony_ci 8968c2ecf20Sopenharmony_ci /* adjust timestamp for the RX latency based on link speed */ 8978c2ecf20Sopenharmony_ci if (adapter->hw.mac.type == e1000_i210) { 8988c2ecf20Sopenharmony_ci switch (adapter->link_speed) { 8998c2ecf20Sopenharmony_ci case SPEED_10: 9008c2ecf20Sopenharmony_ci adjust = IGB_I210_RX_LATENCY_10; 9018c2ecf20Sopenharmony_ci break; 9028c2ecf20Sopenharmony_ci case SPEED_100: 9038c2ecf20Sopenharmony_ci adjust = IGB_I210_RX_LATENCY_100; 9048c2ecf20Sopenharmony_ci break; 9058c2ecf20Sopenharmony_ci case SPEED_1000: 9068c2ecf20Sopenharmony_ci adjust = IGB_I210_RX_LATENCY_1000; 9078c2ecf20Sopenharmony_ci break; 9088c2ecf20Sopenharmony_ci } 9098c2ecf20Sopenharmony_ci } 9108c2ecf20Sopenharmony_ci skb_hwtstamps(skb)->hwtstamp = 9118c2ecf20Sopenharmony_ci ktime_sub_ns(skb_hwtstamps(skb)->hwtstamp, adjust); 9128c2ecf20Sopenharmony_ci 9138c2ecf20Sopenharmony_ci return 0; 9148c2ecf20Sopenharmony_ci} 9158c2ecf20Sopenharmony_ci 9168c2ecf20Sopenharmony_ci/** 9178c2ecf20Sopenharmony_ci * igb_ptp_rx_rgtstamp - retrieve Rx timestamp stored in register 9188c2ecf20Sopenharmony_ci * @q_vector: Pointer to interrupt specific structure 9198c2ecf20Sopenharmony_ci * @skb: Buffer containing timestamp and packet 9208c2ecf20Sopenharmony_ci * 9218c2ecf20Sopenharmony_ci * This function is meant to retrieve a timestamp from the internal registers 9228c2ecf20Sopenharmony_ci * of the adapter and store it in the skb. 9238c2ecf20Sopenharmony_ci **/ 9248c2ecf20Sopenharmony_civoid igb_ptp_rx_rgtstamp(struct igb_q_vector *q_vector, struct sk_buff *skb) 9258c2ecf20Sopenharmony_ci{ 9268c2ecf20Sopenharmony_ci struct igb_adapter *adapter = q_vector->adapter; 9278c2ecf20Sopenharmony_ci struct e1000_hw *hw = &adapter->hw; 9288c2ecf20Sopenharmony_ci int adjust = 0; 9298c2ecf20Sopenharmony_ci u64 regval; 9308c2ecf20Sopenharmony_ci 9318c2ecf20Sopenharmony_ci if (!(adapter->ptp_flags & IGB_PTP_ENABLED)) 9328c2ecf20Sopenharmony_ci return; 9338c2ecf20Sopenharmony_ci 9348c2ecf20Sopenharmony_ci /* If this bit is set, then the RX registers contain the time stamp. No 9358c2ecf20Sopenharmony_ci * other packet will be time stamped until we read these registers, so 9368c2ecf20Sopenharmony_ci * read the registers to make them available again. Because only one 9378c2ecf20Sopenharmony_ci * packet can be time stamped at a time, we know that the register 9388c2ecf20Sopenharmony_ci * values must belong to this one here and therefore we don't need to 9398c2ecf20Sopenharmony_ci * compare any of the additional attributes stored for it. 9408c2ecf20Sopenharmony_ci * 9418c2ecf20Sopenharmony_ci * If nothing went wrong, then it should have a shared tx_flags that we 9428c2ecf20Sopenharmony_ci * can turn into a skb_shared_hwtstamps. 9438c2ecf20Sopenharmony_ci */ 9448c2ecf20Sopenharmony_ci if (!(rd32(E1000_TSYNCRXCTL) & E1000_TSYNCRXCTL_VALID)) 9458c2ecf20Sopenharmony_ci return; 9468c2ecf20Sopenharmony_ci 9478c2ecf20Sopenharmony_ci regval = rd32(E1000_RXSTMPL); 9488c2ecf20Sopenharmony_ci regval |= (u64)rd32(E1000_RXSTMPH) << 32; 9498c2ecf20Sopenharmony_ci 9508c2ecf20Sopenharmony_ci igb_ptp_systim_to_hwtstamp(adapter, skb_hwtstamps(skb), regval); 9518c2ecf20Sopenharmony_ci 9528c2ecf20Sopenharmony_ci /* adjust timestamp for the RX latency based on link speed */ 9538c2ecf20Sopenharmony_ci if (adapter->hw.mac.type == e1000_i210) { 9548c2ecf20Sopenharmony_ci switch (adapter->link_speed) { 9558c2ecf20Sopenharmony_ci case SPEED_10: 9568c2ecf20Sopenharmony_ci adjust = IGB_I210_RX_LATENCY_10; 9578c2ecf20Sopenharmony_ci break; 9588c2ecf20Sopenharmony_ci case SPEED_100: 9598c2ecf20Sopenharmony_ci adjust = IGB_I210_RX_LATENCY_100; 9608c2ecf20Sopenharmony_ci break; 9618c2ecf20Sopenharmony_ci case SPEED_1000: 9628c2ecf20Sopenharmony_ci adjust = IGB_I210_RX_LATENCY_1000; 9638c2ecf20Sopenharmony_ci break; 9648c2ecf20Sopenharmony_ci } 9658c2ecf20Sopenharmony_ci } 9668c2ecf20Sopenharmony_ci skb_hwtstamps(skb)->hwtstamp = 9678c2ecf20Sopenharmony_ci ktime_sub_ns(skb_hwtstamps(skb)->hwtstamp, adjust); 9688c2ecf20Sopenharmony_ci 9698c2ecf20Sopenharmony_ci /* Update the last_rx_timestamp timer in order to enable watchdog check 9708c2ecf20Sopenharmony_ci * for error case of latched timestamp on a dropped packet. 9718c2ecf20Sopenharmony_ci */ 9728c2ecf20Sopenharmony_ci adapter->last_rx_timestamp = jiffies; 9738c2ecf20Sopenharmony_ci} 9748c2ecf20Sopenharmony_ci 9758c2ecf20Sopenharmony_ci/** 9768c2ecf20Sopenharmony_ci * igb_ptp_get_ts_config - get hardware time stamping config 9778c2ecf20Sopenharmony_ci * @netdev: netdev struct 9788c2ecf20Sopenharmony_ci * @ifr: interface struct 9798c2ecf20Sopenharmony_ci * 9808c2ecf20Sopenharmony_ci * Get the hwtstamp_config settings to return to the user. Rather than attempt 9818c2ecf20Sopenharmony_ci * to deconstruct the settings from the registers, just return a shadow copy 9828c2ecf20Sopenharmony_ci * of the last known settings. 9838c2ecf20Sopenharmony_ci **/ 9848c2ecf20Sopenharmony_ciint igb_ptp_get_ts_config(struct net_device *netdev, struct ifreq *ifr) 9858c2ecf20Sopenharmony_ci{ 9868c2ecf20Sopenharmony_ci struct igb_adapter *adapter = netdev_priv(netdev); 9878c2ecf20Sopenharmony_ci struct hwtstamp_config *config = &adapter->tstamp_config; 9888c2ecf20Sopenharmony_ci 9898c2ecf20Sopenharmony_ci return copy_to_user(ifr->ifr_data, config, sizeof(*config)) ? 9908c2ecf20Sopenharmony_ci -EFAULT : 0; 9918c2ecf20Sopenharmony_ci} 9928c2ecf20Sopenharmony_ci 9938c2ecf20Sopenharmony_ci/** 9948c2ecf20Sopenharmony_ci * igb_ptp_set_timestamp_mode - setup hardware for timestamping 9958c2ecf20Sopenharmony_ci * @adapter: networking device structure 9968c2ecf20Sopenharmony_ci * @config: hwtstamp configuration 9978c2ecf20Sopenharmony_ci * 9988c2ecf20Sopenharmony_ci * Outgoing time stamping can be enabled and disabled. Play nice and 9998c2ecf20Sopenharmony_ci * disable it when requested, although it shouldn't case any overhead 10008c2ecf20Sopenharmony_ci * when no packet needs it. At most one packet in the queue may be 10018c2ecf20Sopenharmony_ci * marked for time stamping, otherwise it would be impossible to tell 10028c2ecf20Sopenharmony_ci * for sure to which packet the hardware time stamp belongs. 10038c2ecf20Sopenharmony_ci * 10048c2ecf20Sopenharmony_ci * Incoming time stamping has to be configured via the hardware 10058c2ecf20Sopenharmony_ci * filters. Not all combinations are supported, in particular event 10068c2ecf20Sopenharmony_ci * type has to be specified. Matching the kind of event packet is 10078c2ecf20Sopenharmony_ci * not supported, with the exception of "all V2 events regardless of 10088c2ecf20Sopenharmony_ci * level 2 or 4". 10098c2ecf20Sopenharmony_ci */ 10108c2ecf20Sopenharmony_cistatic int igb_ptp_set_timestamp_mode(struct igb_adapter *adapter, 10118c2ecf20Sopenharmony_ci struct hwtstamp_config *config) 10128c2ecf20Sopenharmony_ci{ 10138c2ecf20Sopenharmony_ci struct e1000_hw *hw = &adapter->hw; 10148c2ecf20Sopenharmony_ci u32 tsync_tx_ctl = E1000_TSYNCTXCTL_ENABLED; 10158c2ecf20Sopenharmony_ci u32 tsync_rx_ctl = E1000_TSYNCRXCTL_ENABLED; 10168c2ecf20Sopenharmony_ci u32 tsync_rx_cfg = 0; 10178c2ecf20Sopenharmony_ci bool is_l4 = false; 10188c2ecf20Sopenharmony_ci bool is_l2 = false; 10198c2ecf20Sopenharmony_ci u32 regval; 10208c2ecf20Sopenharmony_ci 10218c2ecf20Sopenharmony_ci /* reserved for future extensions */ 10228c2ecf20Sopenharmony_ci if (config->flags) 10238c2ecf20Sopenharmony_ci return -EINVAL; 10248c2ecf20Sopenharmony_ci 10258c2ecf20Sopenharmony_ci switch (config->tx_type) { 10268c2ecf20Sopenharmony_ci case HWTSTAMP_TX_OFF: 10278c2ecf20Sopenharmony_ci tsync_tx_ctl = 0; 10288c2ecf20Sopenharmony_ci case HWTSTAMP_TX_ON: 10298c2ecf20Sopenharmony_ci break; 10308c2ecf20Sopenharmony_ci default: 10318c2ecf20Sopenharmony_ci return -ERANGE; 10328c2ecf20Sopenharmony_ci } 10338c2ecf20Sopenharmony_ci 10348c2ecf20Sopenharmony_ci switch (config->rx_filter) { 10358c2ecf20Sopenharmony_ci case HWTSTAMP_FILTER_NONE: 10368c2ecf20Sopenharmony_ci tsync_rx_ctl = 0; 10378c2ecf20Sopenharmony_ci break; 10388c2ecf20Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V1_L4_SYNC: 10398c2ecf20Sopenharmony_ci tsync_rx_ctl |= E1000_TSYNCRXCTL_TYPE_L4_V1; 10408c2ecf20Sopenharmony_ci tsync_rx_cfg = E1000_TSYNCRXCFG_PTP_V1_SYNC_MESSAGE; 10418c2ecf20Sopenharmony_ci is_l4 = true; 10428c2ecf20Sopenharmony_ci break; 10438c2ecf20Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ: 10448c2ecf20Sopenharmony_ci tsync_rx_ctl |= E1000_TSYNCRXCTL_TYPE_L4_V1; 10458c2ecf20Sopenharmony_ci tsync_rx_cfg = E1000_TSYNCRXCFG_PTP_V1_DELAY_REQ_MESSAGE; 10468c2ecf20Sopenharmony_ci is_l4 = true; 10478c2ecf20Sopenharmony_ci break; 10488c2ecf20Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V2_EVENT: 10498c2ecf20Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V2_L2_EVENT: 10508c2ecf20Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V2_L4_EVENT: 10518c2ecf20Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V2_SYNC: 10528c2ecf20Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V2_L2_SYNC: 10538c2ecf20Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V2_L4_SYNC: 10548c2ecf20Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ: 10558c2ecf20Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ: 10568c2ecf20Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ: 10578c2ecf20Sopenharmony_ci tsync_rx_ctl |= E1000_TSYNCRXCTL_TYPE_EVENT_V2; 10588c2ecf20Sopenharmony_ci config->rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT; 10598c2ecf20Sopenharmony_ci is_l2 = true; 10608c2ecf20Sopenharmony_ci is_l4 = true; 10618c2ecf20Sopenharmony_ci break; 10628c2ecf20Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V1_L4_EVENT: 10638c2ecf20Sopenharmony_ci case HWTSTAMP_FILTER_NTP_ALL: 10648c2ecf20Sopenharmony_ci case HWTSTAMP_FILTER_ALL: 10658c2ecf20Sopenharmony_ci /* 82576 cannot timestamp all packets, which it needs to do to 10668c2ecf20Sopenharmony_ci * support both V1 Sync and Delay_Req messages 10678c2ecf20Sopenharmony_ci */ 10688c2ecf20Sopenharmony_ci if (hw->mac.type != e1000_82576) { 10698c2ecf20Sopenharmony_ci tsync_rx_ctl |= E1000_TSYNCRXCTL_TYPE_ALL; 10708c2ecf20Sopenharmony_ci config->rx_filter = HWTSTAMP_FILTER_ALL; 10718c2ecf20Sopenharmony_ci break; 10728c2ecf20Sopenharmony_ci } 10738c2ecf20Sopenharmony_ci fallthrough; 10748c2ecf20Sopenharmony_ci default: 10758c2ecf20Sopenharmony_ci config->rx_filter = HWTSTAMP_FILTER_NONE; 10768c2ecf20Sopenharmony_ci return -ERANGE; 10778c2ecf20Sopenharmony_ci } 10788c2ecf20Sopenharmony_ci 10798c2ecf20Sopenharmony_ci if (hw->mac.type == e1000_82575) { 10808c2ecf20Sopenharmony_ci if (tsync_rx_ctl | tsync_tx_ctl) 10818c2ecf20Sopenharmony_ci return -EINVAL; 10828c2ecf20Sopenharmony_ci return 0; 10838c2ecf20Sopenharmony_ci } 10848c2ecf20Sopenharmony_ci 10858c2ecf20Sopenharmony_ci /* Per-packet timestamping only works if all packets are 10868c2ecf20Sopenharmony_ci * timestamped, so enable timestamping in all packets as 10878c2ecf20Sopenharmony_ci * long as one Rx filter was configured. 10888c2ecf20Sopenharmony_ci */ 10898c2ecf20Sopenharmony_ci if ((hw->mac.type >= e1000_82580) && tsync_rx_ctl) { 10908c2ecf20Sopenharmony_ci tsync_rx_ctl = E1000_TSYNCRXCTL_ENABLED; 10918c2ecf20Sopenharmony_ci tsync_rx_ctl |= E1000_TSYNCRXCTL_TYPE_ALL; 10928c2ecf20Sopenharmony_ci config->rx_filter = HWTSTAMP_FILTER_ALL; 10938c2ecf20Sopenharmony_ci is_l2 = true; 10948c2ecf20Sopenharmony_ci is_l4 = true; 10958c2ecf20Sopenharmony_ci 10968c2ecf20Sopenharmony_ci if ((hw->mac.type == e1000_i210) || 10978c2ecf20Sopenharmony_ci (hw->mac.type == e1000_i211)) { 10988c2ecf20Sopenharmony_ci regval = rd32(E1000_RXPBS); 10998c2ecf20Sopenharmony_ci regval |= E1000_RXPBS_CFG_TS_EN; 11008c2ecf20Sopenharmony_ci wr32(E1000_RXPBS, regval); 11018c2ecf20Sopenharmony_ci } 11028c2ecf20Sopenharmony_ci } 11038c2ecf20Sopenharmony_ci 11048c2ecf20Sopenharmony_ci /* enable/disable TX */ 11058c2ecf20Sopenharmony_ci regval = rd32(E1000_TSYNCTXCTL); 11068c2ecf20Sopenharmony_ci regval &= ~E1000_TSYNCTXCTL_ENABLED; 11078c2ecf20Sopenharmony_ci regval |= tsync_tx_ctl; 11088c2ecf20Sopenharmony_ci wr32(E1000_TSYNCTXCTL, regval); 11098c2ecf20Sopenharmony_ci 11108c2ecf20Sopenharmony_ci /* enable/disable RX */ 11118c2ecf20Sopenharmony_ci regval = rd32(E1000_TSYNCRXCTL); 11128c2ecf20Sopenharmony_ci regval &= ~(E1000_TSYNCRXCTL_ENABLED | E1000_TSYNCRXCTL_TYPE_MASK); 11138c2ecf20Sopenharmony_ci regval |= tsync_rx_ctl; 11148c2ecf20Sopenharmony_ci wr32(E1000_TSYNCRXCTL, regval); 11158c2ecf20Sopenharmony_ci 11168c2ecf20Sopenharmony_ci /* define which PTP packets are time stamped */ 11178c2ecf20Sopenharmony_ci wr32(E1000_TSYNCRXCFG, tsync_rx_cfg); 11188c2ecf20Sopenharmony_ci 11198c2ecf20Sopenharmony_ci /* define ethertype filter for timestamped packets */ 11208c2ecf20Sopenharmony_ci if (is_l2) 11218c2ecf20Sopenharmony_ci wr32(E1000_ETQF(IGB_ETQF_FILTER_1588), 11228c2ecf20Sopenharmony_ci (E1000_ETQF_FILTER_ENABLE | /* enable filter */ 11238c2ecf20Sopenharmony_ci E1000_ETQF_1588 | /* enable timestamping */ 11248c2ecf20Sopenharmony_ci ETH_P_1588)); /* 1588 eth protocol type */ 11258c2ecf20Sopenharmony_ci else 11268c2ecf20Sopenharmony_ci wr32(E1000_ETQF(IGB_ETQF_FILTER_1588), 0); 11278c2ecf20Sopenharmony_ci 11288c2ecf20Sopenharmony_ci /* L4 Queue Filter[3]: filter by destination port and protocol */ 11298c2ecf20Sopenharmony_ci if (is_l4) { 11308c2ecf20Sopenharmony_ci u32 ftqf = (IPPROTO_UDP /* UDP */ 11318c2ecf20Sopenharmony_ci | E1000_FTQF_VF_BP /* VF not compared */ 11328c2ecf20Sopenharmony_ci | E1000_FTQF_1588_TIME_STAMP /* Enable Timestamping */ 11338c2ecf20Sopenharmony_ci | E1000_FTQF_MASK); /* mask all inputs */ 11348c2ecf20Sopenharmony_ci ftqf &= ~E1000_FTQF_MASK_PROTO_BP; /* enable protocol check */ 11358c2ecf20Sopenharmony_ci 11368c2ecf20Sopenharmony_ci wr32(E1000_IMIR(3), htons(PTP_EV_PORT)); 11378c2ecf20Sopenharmony_ci wr32(E1000_IMIREXT(3), 11388c2ecf20Sopenharmony_ci (E1000_IMIREXT_SIZE_BP | E1000_IMIREXT_CTRL_BP)); 11398c2ecf20Sopenharmony_ci if (hw->mac.type == e1000_82576) { 11408c2ecf20Sopenharmony_ci /* enable source port check */ 11418c2ecf20Sopenharmony_ci wr32(E1000_SPQF(3), htons(PTP_EV_PORT)); 11428c2ecf20Sopenharmony_ci ftqf &= ~E1000_FTQF_MASK_SOURCE_PORT_BP; 11438c2ecf20Sopenharmony_ci } 11448c2ecf20Sopenharmony_ci wr32(E1000_FTQF(3), ftqf); 11458c2ecf20Sopenharmony_ci } else { 11468c2ecf20Sopenharmony_ci wr32(E1000_FTQF(3), E1000_FTQF_MASK); 11478c2ecf20Sopenharmony_ci } 11488c2ecf20Sopenharmony_ci wrfl(); 11498c2ecf20Sopenharmony_ci 11508c2ecf20Sopenharmony_ci /* clear TX/RX time stamp registers, just to be sure */ 11518c2ecf20Sopenharmony_ci regval = rd32(E1000_TXSTMPL); 11528c2ecf20Sopenharmony_ci regval = rd32(E1000_TXSTMPH); 11538c2ecf20Sopenharmony_ci regval = rd32(E1000_RXSTMPL); 11548c2ecf20Sopenharmony_ci regval = rd32(E1000_RXSTMPH); 11558c2ecf20Sopenharmony_ci 11568c2ecf20Sopenharmony_ci return 0; 11578c2ecf20Sopenharmony_ci} 11588c2ecf20Sopenharmony_ci 11598c2ecf20Sopenharmony_ci/** 11608c2ecf20Sopenharmony_ci * igb_ptp_set_ts_config - set hardware time stamping config 11618c2ecf20Sopenharmony_ci * @netdev: netdev struct 11628c2ecf20Sopenharmony_ci * @ifr: interface struct 11638c2ecf20Sopenharmony_ci * 11648c2ecf20Sopenharmony_ci **/ 11658c2ecf20Sopenharmony_ciint igb_ptp_set_ts_config(struct net_device *netdev, struct ifreq *ifr) 11668c2ecf20Sopenharmony_ci{ 11678c2ecf20Sopenharmony_ci struct igb_adapter *adapter = netdev_priv(netdev); 11688c2ecf20Sopenharmony_ci struct hwtstamp_config config; 11698c2ecf20Sopenharmony_ci int err; 11708c2ecf20Sopenharmony_ci 11718c2ecf20Sopenharmony_ci if (copy_from_user(&config, ifr->ifr_data, sizeof(config))) 11728c2ecf20Sopenharmony_ci return -EFAULT; 11738c2ecf20Sopenharmony_ci 11748c2ecf20Sopenharmony_ci err = igb_ptp_set_timestamp_mode(adapter, &config); 11758c2ecf20Sopenharmony_ci if (err) 11768c2ecf20Sopenharmony_ci return err; 11778c2ecf20Sopenharmony_ci 11788c2ecf20Sopenharmony_ci /* save these settings for future reference */ 11798c2ecf20Sopenharmony_ci memcpy(&adapter->tstamp_config, &config, 11808c2ecf20Sopenharmony_ci sizeof(adapter->tstamp_config)); 11818c2ecf20Sopenharmony_ci 11828c2ecf20Sopenharmony_ci return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ? 11838c2ecf20Sopenharmony_ci -EFAULT : 0; 11848c2ecf20Sopenharmony_ci} 11858c2ecf20Sopenharmony_ci 11868c2ecf20Sopenharmony_ci/** 11878c2ecf20Sopenharmony_ci * igb_ptp_init - Initialize PTP functionality 11888c2ecf20Sopenharmony_ci * @adapter: Board private structure 11898c2ecf20Sopenharmony_ci * 11908c2ecf20Sopenharmony_ci * This function is called at device probe to initialize the PTP 11918c2ecf20Sopenharmony_ci * functionality. 11928c2ecf20Sopenharmony_ci */ 11938c2ecf20Sopenharmony_civoid igb_ptp_init(struct igb_adapter *adapter) 11948c2ecf20Sopenharmony_ci{ 11958c2ecf20Sopenharmony_ci struct e1000_hw *hw = &adapter->hw; 11968c2ecf20Sopenharmony_ci struct net_device *netdev = adapter->netdev; 11978c2ecf20Sopenharmony_ci int i; 11988c2ecf20Sopenharmony_ci 11998c2ecf20Sopenharmony_ci switch (hw->mac.type) { 12008c2ecf20Sopenharmony_ci case e1000_82576: 12018c2ecf20Sopenharmony_ci snprintf(adapter->ptp_caps.name, 16, "%pm", netdev->dev_addr); 12028c2ecf20Sopenharmony_ci adapter->ptp_caps.owner = THIS_MODULE; 12038c2ecf20Sopenharmony_ci adapter->ptp_caps.max_adj = 999999881; 12048c2ecf20Sopenharmony_ci adapter->ptp_caps.n_ext_ts = 0; 12058c2ecf20Sopenharmony_ci adapter->ptp_caps.pps = 0; 12068c2ecf20Sopenharmony_ci adapter->ptp_caps.adjfreq = igb_ptp_adjfreq_82576; 12078c2ecf20Sopenharmony_ci adapter->ptp_caps.adjtime = igb_ptp_adjtime_82576; 12088c2ecf20Sopenharmony_ci adapter->ptp_caps.gettimex64 = igb_ptp_gettimex_82576; 12098c2ecf20Sopenharmony_ci adapter->ptp_caps.settime64 = igb_ptp_settime_82576; 12108c2ecf20Sopenharmony_ci adapter->ptp_caps.enable = igb_ptp_feature_enable; 12118c2ecf20Sopenharmony_ci adapter->cc.read = igb_ptp_read_82576; 12128c2ecf20Sopenharmony_ci adapter->cc.mask = CYCLECOUNTER_MASK(64); 12138c2ecf20Sopenharmony_ci adapter->cc.mult = 1; 12148c2ecf20Sopenharmony_ci adapter->cc.shift = IGB_82576_TSYNC_SHIFT; 12158c2ecf20Sopenharmony_ci adapter->ptp_flags |= IGB_PTP_OVERFLOW_CHECK; 12168c2ecf20Sopenharmony_ci break; 12178c2ecf20Sopenharmony_ci case e1000_82580: 12188c2ecf20Sopenharmony_ci case e1000_i354: 12198c2ecf20Sopenharmony_ci case e1000_i350: 12208c2ecf20Sopenharmony_ci snprintf(adapter->ptp_caps.name, 16, "%pm", netdev->dev_addr); 12218c2ecf20Sopenharmony_ci adapter->ptp_caps.owner = THIS_MODULE; 12228c2ecf20Sopenharmony_ci adapter->ptp_caps.max_adj = 62499999; 12238c2ecf20Sopenharmony_ci adapter->ptp_caps.n_ext_ts = 0; 12248c2ecf20Sopenharmony_ci adapter->ptp_caps.pps = 0; 12258c2ecf20Sopenharmony_ci adapter->ptp_caps.adjfine = igb_ptp_adjfine_82580; 12268c2ecf20Sopenharmony_ci adapter->ptp_caps.adjtime = igb_ptp_adjtime_82576; 12278c2ecf20Sopenharmony_ci adapter->ptp_caps.gettimex64 = igb_ptp_gettimex_82580; 12288c2ecf20Sopenharmony_ci adapter->ptp_caps.settime64 = igb_ptp_settime_82576; 12298c2ecf20Sopenharmony_ci adapter->ptp_caps.enable = igb_ptp_feature_enable; 12308c2ecf20Sopenharmony_ci adapter->cc.read = igb_ptp_read_82580; 12318c2ecf20Sopenharmony_ci adapter->cc.mask = CYCLECOUNTER_MASK(IGB_NBITS_82580); 12328c2ecf20Sopenharmony_ci adapter->cc.mult = 1; 12338c2ecf20Sopenharmony_ci adapter->cc.shift = 0; 12348c2ecf20Sopenharmony_ci adapter->ptp_flags |= IGB_PTP_OVERFLOW_CHECK; 12358c2ecf20Sopenharmony_ci break; 12368c2ecf20Sopenharmony_ci case e1000_i210: 12378c2ecf20Sopenharmony_ci case e1000_i211: 12388c2ecf20Sopenharmony_ci for (i = 0; i < IGB_N_SDP; i++) { 12398c2ecf20Sopenharmony_ci struct ptp_pin_desc *ppd = &adapter->sdp_config[i]; 12408c2ecf20Sopenharmony_ci 12418c2ecf20Sopenharmony_ci snprintf(ppd->name, sizeof(ppd->name), "SDP%d", i); 12428c2ecf20Sopenharmony_ci ppd->index = i; 12438c2ecf20Sopenharmony_ci ppd->func = PTP_PF_NONE; 12448c2ecf20Sopenharmony_ci } 12458c2ecf20Sopenharmony_ci snprintf(adapter->ptp_caps.name, 16, "%pm", netdev->dev_addr); 12468c2ecf20Sopenharmony_ci adapter->ptp_caps.owner = THIS_MODULE; 12478c2ecf20Sopenharmony_ci adapter->ptp_caps.max_adj = 62499999; 12488c2ecf20Sopenharmony_ci adapter->ptp_caps.n_ext_ts = IGB_N_EXTTS; 12498c2ecf20Sopenharmony_ci adapter->ptp_caps.n_per_out = IGB_N_PEROUT; 12508c2ecf20Sopenharmony_ci adapter->ptp_caps.n_pins = IGB_N_SDP; 12518c2ecf20Sopenharmony_ci adapter->ptp_caps.pps = 1; 12528c2ecf20Sopenharmony_ci adapter->ptp_caps.pin_config = adapter->sdp_config; 12538c2ecf20Sopenharmony_ci adapter->ptp_caps.adjfine = igb_ptp_adjfine_82580; 12548c2ecf20Sopenharmony_ci adapter->ptp_caps.adjtime = igb_ptp_adjtime_i210; 12558c2ecf20Sopenharmony_ci adapter->ptp_caps.gettimex64 = igb_ptp_gettimex_i210; 12568c2ecf20Sopenharmony_ci adapter->ptp_caps.settime64 = igb_ptp_settime_i210; 12578c2ecf20Sopenharmony_ci adapter->ptp_caps.enable = igb_ptp_feature_enable_i210; 12588c2ecf20Sopenharmony_ci adapter->ptp_caps.verify = igb_ptp_verify_pin; 12598c2ecf20Sopenharmony_ci break; 12608c2ecf20Sopenharmony_ci default: 12618c2ecf20Sopenharmony_ci adapter->ptp_clock = NULL; 12628c2ecf20Sopenharmony_ci return; 12638c2ecf20Sopenharmony_ci } 12648c2ecf20Sopenharmony_ci 12658c2ecf20Sopenharmony_ci adapter->ptp_clock = ptp_clock_register(&adapter->ptp_caps, 12668c2ecf20Sopenharmony_ci &adapter->pdev->dev); 12678c2ecf20Sopenharmony_ci if (IS_ERR(adapter->ptp_clock)) { 12688c2ecf20Sopenharmony_ci adapter->ptp_clock = NULL; 12698c2ecf20Sopenharmony_ci dev_err(&adapter->pdev->dev, "ptp_clock_register failed\n"); 12708c2ecf20Sopenharmony_ci } else if (adapter->ptp_clock) { 12718c2ecf20Sopenharmony_ci dev_info(&adapter->pdev->dev, "added PHC on %s\n", 12728c2ecf20Sopenharmony_ci adapter->netdev->name); 12738c2ecf20Sopenharmony_ci adapter->ptp_flags |= IGB_PTP_ENABLED; 12748c2ecf20Sopenharmony_ci 12758c2ecf20Sopenharmony_ci spin_lock_init(&adapter->tmreg_lock); 12768c2ecf20Sopenharmony_ci INIT_WORK(&adapter->ptp_tx_work, igb_ptp_tx_work); 12778c2ecf20Sopenharmony_ci 12788c2ecf20Sopenharmony_ci if (adapter->ptp_flags & IGB_PTP_OVERFLOW_CHECK) 12798c2ecf20Sopenharmony_ci INIT_DELAYED_WORK(&adapter->ptp_overflow_work, 12808c2ecf20Sopenharmony_ci igb_ptp_overflow_check); 12818c2ecf20Sopenharmony_ci 12828c2ecf20Sopenharmony_ci adapter->tstamp_config.rx_filter = HWTSTAMP_FILTER_NONE; 12838c2ecf20Sopenharmony_ci adapter->tstamp_config.tx_type = HWTSTAMP_TX_OFF; 12848c2ecf20Sopenharmony_ci 12858c2ecf20Sopenharmony_ci igb_ptp_reset(adapter); 12868c2ecf20Sopenharmony_ci } 12878c2ecf20Sopenharmony_ci} 12888c2ecf20Sopenharmony_ci 12898c2ecf20Sopenharmony_ci/** 12908c2ecf20Sopenharmony_ci * igb_ptp_suspend - Disable PTP work items and prepare for suspend 12918c2ecf20Sopenharmony_ci * @adapter: Board private structure 12928c2ecf20Sopenharmony_ci * 12938c2ecf20Sopenharmony_ci * This function stops the overflow check work and PTP Tx timestamp work, and 12948c2ecf20Sopenharmony_ci * will prepare the device for OS suspend. 12958c2ecf20Sopenharmony_ci */ 12968c2ecf20Sopenharmony_civoid igb_ptp_suspend(struct igb_adapter *adapter) 12978c2ecf20Sopenharmony_ci{ 12988c2ecf20Sopenharmony_ci if (!(adapter->ptp_flags & IGB_PTP_ENABLED)) 12998c2ecf20Sopenharmony_ci return; 13008c2ecf20Sopenharmony_ci 13018c2ecf20Sopenharmony_ci if (adapter->ptp_flags & IGB_PTP_OVERFLOW_CHECK) 13028c2ecf20Sopenharmony_ci cancel_delayed_work_sync(&adapter->ptp_overflow_work); 13038c2ecf20Sopenharmony_ci 13048c2ecf20Sopenharmony_ci cancel_work_sync(&adapter->ptp_tx_work); 13058c2ecf20Sopenharmony_ci if (adapter->ptp_tx_skb) { 13068c2ecf20Sopenharmony_ci dev_kfree_skb_any(adapter->ptp_tx_skb); 13078c2ecf20Sopenharmony_ci adapter->ptp_tx_skb = NULL; 13088c2ecf20Sopenharmony_ci clear_bit_unlock(__IGB_PTP_TX_IN_PROGRESS, &adapter->state); 13098c2ecf20Sopenharmony_ci } 13108c2ecf20Sopenharmony_ci} 13118c2ecf20Sopenharmony_ci 13128c2ecf20Sopenharmony_ci/** 13138c2ecf20Sopenharmony_ci * igb_ptp_stop - Disable PTP device and stop the overflow check. 13148c2ecf20Sopenharmony_ci * @adapter: Board private structure. 13158c2ecf20Sopenharmony_ci * 13168c2ecf20Sopenharmony_ci * This function stops the PTP support and cancels the delayed work. 13178c2ecf20Sopenharmony_ci **/ 13188c2ecf20Sopenharmony_civoid igb_ptp_stop(struct igb_adapter *adapter) 13198c2ecf20Sopenharmony_ci{ 13208c2ecf20Sopenharmony_ci igb_ptp_suspend(adapter); 13218c2ecf20Sopenharmony_ci 13228c2ecf20Sopenharmony_ci if (adapter->ptp_clock) { 13238c2ecf20Sopenharmony_ci ptp_clock_unregister(adapter->ptp_clock); 13248c2ecf20Sopenharmony_ci dev_info(&adapter->pdev->dev, "removed PHC on %s\n", 13258c2ecf20Sopenharmony_ci adapter->netdev->name); 13268c2ecf20Sopenharmony_ci adapter->ptp_flags &= ~IGB_PTP_ENABLED; 13278c2ecf20Sopenharmony_ci } 13288c2ecf20Sopenharmony_ci} 13298c2ecf20Sopenharmony_ci 13308c2ecf20Sopenharmony_ci/** 13318c2ecf20Sopenharmony_ci * igb_ptp_reset - Re-enable the adapter for PTP following a reset. 13328c2ecf20Sopenharmony_ci * @adapter: Board private structure. 13338c2ecf20Sopenharmony_ci * 13348c2ecf20Sopenharmony_ci * This function handles the reset work required to re-enable the PTP device. 13358c2ecf20Sopenharmony_ci **/ 13368c2ecf20Sopenharmony_civoid igb_ptp_reset(struct igb_adapter *adapter) 13378c2ecf20Sopenharmony_ci{ 13388c2ecf20Sopenharmony_ci struct e1000_hw *hw = &adapter->hw; 13398c2ecf20Sopenharmony_ci unsigned long flags; 13408c2ecf20Sopenharmony_ci 13418c2ecf20Sopenharmony_ci /* reset the tstamp_config */ 13428c2ecf20Sopenharmony_ci igb_ptp_set_timestamp_mode(adapter, &adapter->tstamp_config); 13438c2ecf20Sopenharmony_ci 13448c2ecf20Sopenharmony_ci spin_lock_irqsave(&adapter->tmreg_lock, flags); 13458c2ecf20Sopenharmony_ci 13468c2ecf20Sopenharmony_ci switch (adapter->hw.mac.type) { 13478c2ecf20Sopenharmony_ci case e1000_82576: 13488c2ecf20Sopenharmony_ci /* Dial the nominal frequency. */ 13498c2ecf20Sopenharmony_ci wr32(E1000_TIMINCA, INCPERIOD_82576 | INCVALUE_82576); 13508c2ecf20Sopenharmony_ci break; 13518c2ecf20Sopenharmony_ci case e1000_82580: 13528c2ecf20Sopenharmony_ci case e1000_i354: 13538c2ecf20Sopenharmony_ci case e1000_i350: 13548c2ecf20Sopenharmony_ci case e1000_i210: 13558c2ecf20Sopenharmony_ci case e1000_i211: 13568c2ecf20Sopenharmony_ci wr32(E1000_TSAUXC, 0x0); 13578c2ecf20Sopenharmony_ci wr32(E1000_TSSDP, 0x0); 13588c2ecf20Sopenharmony_ci wr32(E1000_TSIM, 13598c2ecf20Sopenharmony_ci TSYNC_INTERRUPTS | 13608c2ecf20Sopenharmony_ci (adapter->pps_sys_wrap_on ? TSINTR_SYS_WRAP : 0)); 13618c2ecf20Sopenharmony_ci wr32(E1000_IMS, E1000_IMS_TS); 13628c2ecf20Sopenharmony_ci break; 13638c2ecf20Sopenharmony_ci default: 13648c2ecf20Sopenharmony_ci /* No work to do. */ 13658c2ecf20Sopenharmony_ci goto out; 13668c2ecf20Sopenharmony_ci } 13678c2ecf20Sopenharmony_ci 13688c2ecf20Sopenharmony_ci /* Re-initialize the timer. */ 13698c2ecf20Sopenharmony_ci if ((hw->mac.type == e1000_i210) || (hw->mac.type == e1000_i211)) { 13708c2ecf20Sopenharmony_ci struct timespec64 ts = ktime_to_timespec64(ktime_get_real()); 13718c2ecf20Sopenharmony_ci 13728c2ecf20Sopenharmony_ci igb_ptp_write_i210(adapter, &ts); 13738c2ecf20Sopenharmony_ci } else { 13748c2ecf20Sopenharmony_ci timecounter_init(&adapter->tc, &adapter->cc, 13758c2ecf20Sopenharmony_ci ktime_to_ns(ktime_get_real())); 13768c2ecf20Sopenharmony_ci } 13778c2ecf20Sopenharmony_ciout: 13788c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&adapter->tmreg_lock, flags); 13798c2ecf20Sopenharmony_ci 13808c2ecf20Sopenharmony_ci wrfl(); 13818c2ecf20Sopenharmony_ci 13828c2ecf20Sopenharmony_ci if (adapter->ptp_flags & IGB_PTP_OVERFLOW_CHECK) 13838c2ecf20Sopenharmony_ci schedule_delayed_work(&adapter->ptp_overflow_work, 13848c2ecf20Sopenharmony_ci IGB_SYSTIM_OVERFLOW_PERIOD); 13858c2ecf20Sopenharmony_ci} 1386