18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* Copyright(c) 1999 - 2018 Intel Corporation. */ 38c2ecf20Sopenharmony_ci 48c2ecf20Sopenharmony_ci#include "ixgbe.h" 58c2ecf20Sopenharmony_ci#include <linux/ptp_classify.h> 68c2ecf20Sopenharmony_ci#include <linux/clocksource.h> 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci/* 98c2ecf20Sopenharmony_ci * The 82599 and the X540 do not have true 64bit nanosecond scale 108c2ecf20Sopenharmony_ci * counter registers. Instead, SYSTIME is defined by a fixed point 118c2ecf20Sopenharmony_ci * system which allows the user to define the scale counter increment 128c2ecf20Sopenharmony_ci * value at every level change of the oscillator driving the SYSTIME 138c2ecf20Sopenharmony_ci * value. For both devices the TIMINCA:IV field defines this 148c2ecf20Sopenharmony_ci * increment. On the X540 device, 31 bits are provided. However on the 158c2ecf20Sopenharmony_ci * 82599 only provides 24 bits. The time unit is determined by the 168c2ecf20Sopenharmony_ci * clock frequency of the oscillator in combination with the TIMINCA 178c2ecf20Sopenharmony_ci * register. When these devices link at 10Gb the oscillator has a 188c2ecf20Sopenharmony_ci * period of 6.4ns. In order to convert the scale counter into 198c2ecf20Sopenharmony_ci * nanoseconds the cyclecounter and timecounter structures are 208c2ecf20Sopenharmony_ci * used. The SYSTIME registers need to be converted to ns values by use 218c2ecf20Sopenharmony_ci * of only a right shift (division by power of 2). The following math 228c2ecf20Sopenharmony_ci * determines the largest incvalue that will fit into the available 238c2ecf20Sopenharmony_ci * bits in the TIMINCA register. 248c2ecf20Sopenharmony_ci * 258c2ecf20Sopenharmony_ci * PeriodWidth: Number of bits to store the clock period 268c2ecf20Sopenharmony_ci * MaxWidth: The maximum width value of the TIMINCA register 278c2ecf20Sopenharmony_ci * Period: The clock period for the oscillator 288c2ecf20Sopenharmony_ci * round(): discard the fractional portion of the calculation 298c2ecf20Sopenharmony_ci * 308c2ecf20Sopenharmony_ci * Period * [ 2 ^ ( MaxWidth - PeriodWidth ) ] 318c2ecf20Sopenharmony_ci * 328c2ecf20Sopenharmony_ci * For the X540, MaxWidth is 31 bits, and the base period is 6.4 ns 338c2ecf20Sopenharmony_ci * For the 82599, MaxWidth is 24 bits, and the base period is 6.4 ns 348c2ecf20Sopenharmony_ci * 358c2ecf20Sopenharmony_ci * The period also changes based on the link speed: 368c2ecf20Sopenharmony_ci * At 10Gb link or no link, the period remains the same. 378c2ecf20Sopenharmony_ci * At 1Gb link, the period is multiplied by 10. (64ns) 388c2ecf20Sopenharmony_ci * At 100Mb link, the period is multiplied by 100. (640ns) 398c2ecf20Sopenharmony_ci * 408c2ecf20Sopenharmony_ci * The calculated value allows us to right shift the SYSTIME register 418c2ecf20Sopenharmony_ci * value in order to quickly convert it into a nanosecond clock, 428c2ecf20Sopenharmony_ci * while allowing for the maximum possible adjustment value. 438c2ecf20Sopenharmony_ci * 448c2ecf20Sopenharmony_ci * These diagrams are only for the 10Gb link period 458c2ecf20Sopenharmony_ci * 468c2ecf20Sopenharmony_ci * SYSTIMEH SYSTIMEL 478c2ecf20Sopenharmony_ci * +--------------+ +--------------+ 488c2ecf20Sopenharmony_ci * X540 | 32 | | 1 | 3 | 28 | 498c2ecf20Sopenharmony_ci * *--------------+ +--------------+ 508c2ecf20Sopenharmony_ci * \________ 36 bits ______/ fract 518c2ecf20Sopenharmony_ci * 528c2ecf20Sopenharmony_ci * +--------------+ +--------------+ 538c2ecf20Sopenharmony_ci * 82599 | 32 | | 8 | 3 | 21 | 548c2ecf20Sopenharmony_ci * *--------------+ +--------------+ 558c2ecf20Sopenharmony_ci * \________ 43 bits ______/ fract 568c2ecf20Sopenharmony_ci * 578c2ecf20Sopenharmony_ci * The 36 bit X540 SYSTIME overflows every 588c2ecf20Sopenharmony_ci * 2^36 * 10^-9 / 60 = 1.14 minutes or 69 seconds 598c2ecf20Sopenharmony_ci * 608c2ecf20Sopenharmony_ci * The 43 bit 82599 SYSTIME overflows every 618c2ecf20Sopenharmony_ci * 2^43 * 10^-9 / 3600 = 2.4 hours 628c2ecf20Sopenharmony_ci */ 638c2ecf20Sopenharmony_ci#define IXGBE_INCVAL_10GB 0x66666666 648c2ecf20Sopenharmony_ci#define IXGBE_INCVAL_1GB 0x40000000 658c2ecf20Sopenharmony_ci#define IXGBE_INCVAL_100 0x50000000 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci#define IXGBE_INCVAL_SHIFT_10GB 28 688c2ecf20Sopenharmony_ci#define IXGBE_INCVAL_SHIFT_1GB 24 698c2ecf20Sopenharmony_ci#define IXGBE_INCVAL_SHIFT_100 21 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci#define IXGBE_INCVAL_SHIFT_82599 7 728c2ecf20Sopenharmony_ci#define IXGBE_INCPER_SHIFT_82599 24 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci#define IXGBE_OVERFLOW_PERIOD (HZ * 30) 758c2ecf20Sopenharmony_ci#define IXGBE_PTP_TX_TIMEOUT (HZ) 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci/* We use our own definitions instead of NSEC_PER_SEC because we want to mark 788c2ecf20Sopenharmony_ci * the value as a ULL to force precision when bit shifting. 798c2ecf20Sopenharmony_ci */ 808c2ecf20Sopenharmony_ci#define NS_PER_SEC 1000000000ULL 818c2ecf20Sopenharmony_ci#define NS_PER_HALF_SEC 500000000ULL 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci/* In contrast, the X550 controller has two registers, SYSTIMEH and SYSTIMEL 848c2ecf20Sopenharmony_ci * which contain measurements of seconds and nanoseconds respectively. This 858c2ecf20Sopenharmony_ci * matches the standard linux representation of time in the kernel. In addition, 868c2ecf20Sopenharmony_ci * the X550 also has a SYSTIMER register which represents residue, or 878c2ecf20Sopenharmony_ci * subnanosecond overflow adjustments. To control clock adjustment, the TIMINCA 888c2ecf20Sopenharmony_ci * register is used, but it is unlike the X540 and 82599 devices. TIMINCA 898c2ecf20Sopenharmony_ci * represents units of 2^-32 nanoseconds, and uses 31 bits for this, with the 908c2ecf20Sopenharmony_ci * high bit representing whether the adjustent is positive or negative. Every 918c2ecf20Sopenharmony_ci * clock cycle, the X550 will add 12.5 ns + TIMINCA which can result in a range 928c2ecf20Sopenharmony_ci * of 12 to 13 nanoseconds adjustment. Unlike the 82599 and X540 devices, the 938c2ecf20Sopenharmony_ci * X550's clock for purposes of SYSTIME generation is constant and not dependent 948c2ecf20Sopenharmony_ci * on the link speed. 958c2ecf20Sopenharmony_ci * 968c2ecf20Sopenharmony_ci * SYSTIMEH SYSTIMEL SYSTIMER 978c2ecf20Sopenharmony_ci * +--------------+ +--------------+ +-------------+ 988c2ecf20Sopenharmony_ci * X550 | 32 | | 32 | | 32 | 998c2ecf20Sopenharmony_ci * *--------------+ +--------------+ +-------------+ 1008c2ecf20Sopenharmony_ci * \____seconds___/ \_nanoseconds_/ \__2^-32 ns__/ 1018c2ecf20Sopenharmony_ci * 1028c2ecf20Sopenharmony_ci * This results in a full 96 bits to represent the clock, with 32 bits for 1038c2ecf20Sopenharmony_ci * seconds, 32 bits for nanoseconds (largest value is 0d999999999 or just under 1048c2ecf20Sopenharmony_ci * 1 second) and an additional 32 bits to measure sub nanosecond adjustments for 1058c2ecf20Sopenharmony_ci * underflow of adjustments. 1068c2ecf20Sopenharmony_ci * 1078c2ecf20Sopenharmony_ci * The 32 bits of seconds for the X550 overflows every 1088c2ecf20Sopenharmony_ci * 2^32 / ( 365.25 * 24 * 60 * 60 ) = ~136 years. 1098c2ecf20Sopenharmony_ci * 1108c2ecf20Sopenharmony_ci * In order to adjust the clock frequency for the X550, the TIMINCA register is 1118c2ecf20Sopenharmony_ci * provided. This register represents a + or minus nearly 0.5 ns adjustment to 1128c2ecf20Sopenharmony_ci * the base frequency. It is measured in 2^-32 ns units, with the high bit being 1138c2ecf20Sopenharmony_ci * the sign bit. This register enables software to calculate frequency 1148c2ecf20Sopenharmony_ci * adjustments and apply them directly to the clock rate. 1158c2ecf20Sopenharmony_ci * 1168c2ecf20Sopenharmony_ci * The math for converting ppb into TIMINCA values is fairly straightforward. 1178c2ecf20Sopenharmony_ci * TIMINCA value = ( Base_Frequency * ppb ) / 1000000000ULL 1188c2ecf20Sopenharmony_ci * 1198c2ecf20Sopenharmony_ci * This assumes that ppb is never high enough to create a value bigger than 1208c2ecf20Sopenharmony_ci * TIMINCA's 31 bits can store. This is ensured by the stack. Calculating this 1218c2ecf20Sopenharmony_ci * value is also simple. 1228c2ecf20Sopenharmony_ci * Max ppb = ( Max Adjustment / Base Frequency ) / 1000000000ULL 1238c2ecf20Sopenharmony_ci * 1248c2ecf20Sopenharmony_ci * For the X550, the Max adjustment is +/- 0.5 ns, and the base frequency is 1258c2ecf20Sopenharmony_ci * 12.5 nanoseconds. This means that the Max ppb is 39999999 1268c2ecf20Sopenharmony_ci * Note: We subtract one in order to ensure no overflow, because the TIMINCA 1278c2ecf20Sopenharmony_ci * register can only hold slightly under 0.5 nanoseconds. 1288c2ecf20Sopenharmony_ci * 1298c2ecf20Sopenharmony_ci * Because TIMINCA is measured in 2^-32 ns units, we have to convert 12.5 ns 1308c2ecf20Sopenharmony_ci * into 2^-32 units, which is 1318c2ecf20Sopenharmony_ci * 1328c2ecf20Sopenharmony_ci * 12.5 * 2^32 = C80000000 1338c2ecf20Sopenharmony_ci * 1348c2ecf20Sopenharmony_ci * Some revisions of hardware have a faster base frequency than the registers 1358c2ecf20Sopenharmony_ci * were defined for. To fix this, we use a timecounter structure with the 1368c2ecf20Sopenharmony_ci * proper mult and shift to convert the cycles into nanoseconds of time. 1378c2ecf20Sopenharmony_ci */ 1388c2ecf20Sopenharmony_ci#define IXGBE_X550_BASE_PERIOD 0xC80000000ULL 1398c2ecf20Sopenharmony_ci#define INCVALUE_MASK 0x7FFFFFFF 1408c2ecf20Sopenharmony_ci#define ISGN 0x80000000 1418c2ecf20Sopenharmony_ci#define MAX_TIMADJ 0x7FFFFFFF 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci/** 1448c2ecf20Sopenharmony_ci * ixgbe_ptp_setup_sdp_X540 1458c2ecf20Sopenharmony_ci * @adapter: private adapter structure 1468c2ecf20Sopenharmony_ci * 1478c2ecf20Sopenharmony_ci * this function enables or disables the clock out feature on SDP0 for 1488c2ecf20Sopenharmony_ci * the X540 device. It will create a 1 second periodic output that can 1498c2ecf20Sopenharmony_ci * be used as the PPS (via an interrupt). 1508c2ecf20Sopenharmony_ci * 1518c2ecf20Sopenharmony_ci * It calculates when the system time will be on an exact second, and then 1528c2ecf20Sopenharmony_ci * aligns the start of the PPS signal to that value. 1538c2ecf20Sopenharmony_ci * 1548c2ecf20Sopenharmony_ci * This works by using the cycle counter shift and mult values in reverse, and 1558c2ecf20Sopenharmony_ci * assumes that the values we're shifting will not overflow. 1568c2ecf20Sopenharmony_ci */ 1578c2ecf20Sopenharmony_cistatic void ixgbe_ptp_setup_sdp_X540(struct ixgbe_adapter *adapter) 1588c2ecf20Sopenharmony_ci{ 1598c2ecf20Sopenharmony_ci struct cyclecounter *cc = &adapter->hw_cc; 1608c2ecf20Sopenharmony_ci struct ixgbe_hw *hw = &adapter->hw; 1618c2ecf20Sopenharmony_ci u32 esdp, tsauxc, clktiml, clktimh, trgttiml, trgttimh, rem; 1628c2ecf20Sopenharmony_ci u64 ns = 0, clock_edge = 0, clock_period; 1638c2ecf20Sopenharmony_ci unsigned long flags; 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci /* disable the pin first */ 1668c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_TSAUXC, 0x0); 1678c2ecf20Sopenharmony_ci IXGBE_WRITE_FLUSH(hw); 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci if (!(adapter->flags2 & IXGBE_FLAG2_PTP_PPS_ENABLED)) 1708c2ecf20Sopenharmony_ci return; 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci esdp = IXGBE_READ_REG(hw, IXGBE_ESDP); 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci /* enable the SDP0 pin as output, and connected to the 1758c2ecf20Sopenharmony_ci * native function for Timesync (ClockOut) 1768c2ecf20Sopenharmony_ci */ 1778c2ecf20Sopenharmony_ci esdp |= IXGBE_ESDP_SDP0_DIR | 1788c2ecf20Sopenharmony_ci IXGBE_ESDP_SDP0_NATIVE; 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci /* enable the Clock Out feature on SDP0, and allow 1818c2ecf20Sopenharmony_ci * interrupts to occur when the pin changes 1828c2ecf20Sopenharmony_ci */ 1838c2ecf20Sopenharmony_ci tsauxc = (IXGBE_TSAUXC_EN_CLK | 1848c2ecf20Sopenharmony_ci IXGBE_TSAUXC_SYNCLK | 1858c2ecf20Sopenharmony_ci IXGBE_TSAUXC_SDP0_INT); 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci /* Determine the clock time period to use. This assumes that the 1888c2ecf20Sopenharmony_ci * cycle counter shift is small enough to avoid overflow. 1898c2ecf20Sopenharmony_ci */ 1908c2ecf20Sopenharmony_ci clock_period = div_u64((NS_PER_HALF_SEC << cc->shift), cc->mult); 1918c2ecf20Sopenharmony_ci clktiml = (u32)(clock_period); 1928c2ecf20Sopenharmony_ci clktimh = (u32)(clock_period >> 32); 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci /* Read the current clock time, and save the cycle counter value */ 1958c2ecf20Sopenharmony_ci spin_lock_irqsave(&adapter->tmreg_lock, flags); 1968c2ecf20Sopenharmony_ci ns = timecounter_read(&adapter->hw_tc); 1978c2ecf20Sopenharmony_ci clock_edge = adapter->hw_tc.cycle_last; 1988c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&adapter->tmreg_lock, flags); 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci /* Figure out how many seconds to add in order to round up */ 2018c2ecf20Sopenharmony_ci div_u64_rem(ns, NS_PER_SEC, &rem); 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci /* Figure out how many nanoseconds to add to round the clock edge up 2048c2ecf20Sopenharmony_ci * to the next full second 2058c2ecf20Sopenharmony_ci */ 2068c2ecf20Sopenharmony_ci rem = (NS_PER_SEC - rem); 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci /* Adjust the clock edge to align with the next full second. */ 2098c2ecf20Sopenharmony_ci clock_edge += div_u64(((u64)rem << cc->shift), cc->mult); 2108c2ecf20Sopenharmony_ci trgttiml = (u32)clock_edge; 2118c2ecf20Sopenharmony_ci trgttimh = (u32)(clock_edge >> 32); 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_CLKTIML, clktiml); 2148c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_CLKTIMH, clktimh); 2158c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_TRGTTIML0, trgttiml); 2168c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_TRGTTIMH0, trgttimh); 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp); 2198c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_TSAUXC, tsauxc); 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci IXGBE_WRITE_FLUSH(hw); 2228c2ecf20Sopenharmony_ci} 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci/** 2258c2ecf20Sopenharmony_ci * ixgbe_ptp_setup_sdp_X550 2268c2ecf20Sopenharmony_ci * @adapter: private adapter structure 2278c2ecf20Sopenharmony_ci * 2288c2ecf20Sopenharmony_ci * Enable or disable a clock output signal on SDP 0 for X550 hardware. 2298c2ecf20Sopenharmony_ci * 2308c2ecf20Sopenharmony_ci * Use the target time feature to align the output signal on the next full 2318c2ecf20Sopenharmony_ci * second. 2328c2ecf20Sopenharmony_ci * 2338c2ecf20Sopenharmony_ci * This works by using the cycle counter shift and mult values in reverse, and 2348c2ecf20Sopenharmony_ci * assumes that the values we're shifting will not overflow. 2358c2ecf20Sopenharmony_ci */ 2368c2ecf20Sopenharmony_cistatic void ixgbe_ptp_setup_sdp_X550(struct ixgbe_adapter *adapter) 2378c2ecf20Sopenharmony_ci{ 2388c2ecf20Sopenharmony_ci u32 esdp, tsauxc, freqout, trgttiml, trgttimh, rem, tssdp; 2398c2ecf20Sopenharmony_ci struct cyclecounter *cc = &adapter->hw_cc; 2408c2ecf20Sopenharmony_ci struct ixgbe_hw *hw = &adapter->hw; 2418c2ecf20Sopenharmony_ci u64 ns = 0, clock_edge = 0; 2428c2ecf20Sopenharmony_ci struct timespec64 ts; 2438c2ecf20Sopenharmony_ci unsigned long flags; 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci /* disable the pin first */ 2468c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_TSAUXC, 0x0); 2478c2ecf20Sopenharmony_ci IXGBE_WRITE_FLUSH(hw); 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci if (!(adapter->flags2 & IXGBE_FLAG2_PTP_PPS_ENABLED)) 2508c2ecf20Sopenharmony_ci return; 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci esdp = IXGBE_READ_REG(hw, IXGBE_ESDP); 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci /* enable the SDP0 pin as output, and connected to the 2558c2ecf20Sopenharmony_ci * native function for Timesync (ClockOut) 2568c2ecf20Sopenharmony_ci */ 2578c2ecf20Sopenharmony_ci esdp |= IXGBE_ESDP_SDP0_DIR | 2588c2ecf20Sopenharmony_ci IXGBE_ESDP_SDP0_NATIVE; 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci /* enable the Clock Out feature on SDP0, and use Target Time 0 to 2618c2ecf20Sopenharmony_ci * enable generation of interrupts on the clock change. 2628c2ecf20Sopenharmony_ci */ 2638c2ecf20Sopenharmony_ci#define IXGBE_TSAUXC_DIS_TS_CLEAR 0x40000000 2648c2ecf20Sopenharmony_ci tsauxc = (IXGBE_TSAUXC_EN_CLK | IXGBE_TSAUXC_ST0 | 2658c2ecf20Sopenharmony_ci IXGBE_TSAUXC_EN_TT0 | IXGBE_TSAUXC_SDP0_INT | 2668c2ecf20Sopenharmony_ci IXGBE_TSAUXC_DIS_TS_CLEAR); 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci tssdp = (IXGBE_TSSDP_TS_SDP0_EN | 2698c2ecf20Sopenharmony_ci IXGBE_TSSDP_TS_SDP0_CLK0); 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci /* Determine the clock time period to use. This assumes that the 2728c2ecf20Sopenharmony_ci * cycle counter shift is small enough to avoid overflowing a 32bit 2738c2ecf20Sopenharmony_ci * value. 2748c2ecf20Sopenharmony_ci */ 2758c2ecf20Sopenharmony_ci freqout = div_u64(NS_PER_HALF_SEC << cc->shift, cc->mult); 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci /* Read the current clock time, and save the cycle counter value */ 2788c2ecf20Sopenharmony_ci spin_lock_irqsave(&adapter->tmreg_lock, flags); 2798c2ecf20Sopenharmony_ci ns = timecounter_read(&adapter->hw_tc); 2808c2ecf20Sopenharmony_ci clock_edge = adapter->hw_tc.cycle_last; 2818c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&adapter->tmreg_lock, flags); 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci /* Figure out how far past the next second we are */ 2848c2ecf20Sopenharmony_ci div_u64_rem(ns, NS_PER_SEC, &rem); 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci /* Figure out how many nanoseconds to add to round the clock edge up 2878c2ecf20Sopenharmony_ci * to the next full second 2888c2ecf20Sopenharmony_ci */ 2898c2ecf20Sopenharmony_ci rem = (NS_PER_SEC - rem); 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci /* Adjust the clock edge to align with the next full second. */ 2928c2ecf20Sopenharmony_ci clock_edge += div_u64(((u64)rem << cc->shift), cc->mult); 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci /* X550 hardware stores the time in 32bits of 'billions of cycles' and 2958c2ecf20Sopenharmony_ci * 32bits of 'cycles'. There's no guarantee that cycles represents 2968c2ecf20Sopenharmony_ci * nanoseconds. However, we can use the math from a timespec64 to 2978c2ecf20Sopenharmony_ci * convert into the hardware representation. 2988c2ecf20Sopenharmony_ci * 2998c2ecf20Sopenharmony_ci * See ixgbe_ptp_read_X550() for more details. 3008c2ecf20Sopenharmony_ci */ 3018c2ecf20Sopenharmony_ci ts = ns_to_timespec64(clock_edge); 3028c2ecf20Sopenharmony_ci trgttiml = (u32)ts.tv_nsec; 3038c2ecf20Sopenharmony_ci trgttimh = (u32)ts.tv_sec; 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_FREQOUT0, freqout); 3068c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_TRGTTIML0, trgttiml); 3078c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_TRGTTIMH0, trgttimh); 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp); 3108c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_TSSDP, tssdp); 3118c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_TSAUXC, tsauxc); 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci IXGBE_WRITE_FLUSH(hw); 3148c2ecf20Sopenharmony_ci} 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci/** 3178c2ecf20Sopenharmony_ci * ixgbe_ptp_read_X550 - read cycle counter value 3188c2ecf20Sopenharmony_ci * @cc: cyclecounter structure 3198c2ecf20Sopenharmony_ci * 3208c2ecf20Sopenharmony_ci * This function reads SYSTIME registers. It is called by the cyclecounter 3218c2ecf20Sopenharmony_ci * structure to convert from internal representation into nanoseconds. We need 3228c2ecf20Sopenharmony_ci * this for X550 since some skews do not have expected clock frequency and 3238c2ecf20Sopenharmony_ci * result of SYSTIME is 32bits of "billions of cycles" and 32 bits of 3248c2ecf20Sopenharmony_ci * "cycles", rather than seconds and nanoseconds. 3258c2ecf20Sopenharmony_ci */ 3268c2ecf20Sopenharmony_cistatic u64 ixgbe_ptp_read_X550(const struct cyclecounter *cc) 3278c2ecf20Sopenharmony_ci{ 3288c2ecf20Sopenharmony_ci struct ixgbe_adapter *adapter = 3298c2ecf20Sopenharmony_ci container_of(cc, struct ixgbe_adapter, hw_cc); 3308c2ecf20Sopenharmony_ci struct ixgbe_hw *hw = &adapter->hw; 3318c2ecf20Sopenharmony_ci struct timespec64 ts; 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci /* storage is 32 bits of 'billions of cycles' and 32 bits of 'cycles'. 3348c2ecf20Sopenharmony_ci * Some revisions of hardware run at a higher frequency and so the 3358c2ecf20Sopenharmony_ci * cycles are not guaranteed to be nanoseconds. The timespec64 created 3368c2ecf20Sopenharmony_ci * here is used for its math/conversions but does not necessarily 3378c2ecf20Sopenharmony_ci * represent nominal time. 3388c2ecf20Sopenharmony_ci * 3398c2ecf20Sopenharmony_ci * It should be noted that this cyclecounter will overflow at a 3408c2ecf20Sopenharmony_ci * non-bitmask field since we have to convert our billions of cycles 3418c2ecf20Sopenharmony_ci * into an actual cycles count. This results in some possible weird 3428c2ecf20Sopenharmony_ci * situations at high cycle counter stamps. However given that 32 bits 3438c2ecf20Sopenharmony_ci * of "seconds" is ~138 years this isn't a problem. Even at the 3448c2ecf20Sopenharmony_ci * increased frequency of some revisions, this is still ~103 years. 3458c2ecf20Sopenharmony_ci * Since the SYSTIME values start at 0 and we never write them, it is 3468c2ecf20Sopenharmony_ci * highly unlikely for the cyclecounter to overflow in practice. 3478c2ecf20Sopenharmony_ci */ 3488c2ecf20Sopenharmony_ci IXGBE_READ_REG(hw, IXGBE_SYSTIMR); 3498c2ecf20Sopenharmony_ci ts.tv_nsec = IXGBE_READ_REG(hw, IXGBE_SYSTIML); 3508c2ecf20Sopenharmony_ci ts.tv_sec = IXGBE_READ_REG(hw, IXGBE_SYSTIMH); 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci return (u64)timespec64_to_ns(&ts); 3538c2ecf20Sopenharmony_ci} 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci/** 3568c2ecf20Sopenharmony_ci * ixgbe_ptp_read_82599 - read raw cycle counter (to be used by time counter) 3578c2ecf20Sopenharmony_ci * @cc: the cyclecounter structure 3588c2ecf20Sopenharmony_ci * 3598c2ecf20Sopenharmony_ci * this function reads the cyclecounter registers and is called by the 3608c2ecf20Sopenharmony_ci * cyclecounter structure used to construct a ns counter from the 3618c2ecf20Sopenharmony_ci * arbitrary fixed point registers 3628c2ecf20Sopenharmony_ci */ 3638c2ecf20Sopenharmony_cistatic u64 ixgbe_ptp_read_82599(const struct cyclecounter *cc) 3648c2ecf20Sopenharmony_ci{ 3658c2ecf20Sopenharmony_ci struct ixgbe_adapter *adapter = 3668c2ecf20Sopenharmony_ci container_of(cc, struct ixgbe_adapter, hw_cc); 3678c2ecf20Sopenharmony_ci struct ixgbe_hw *hw = &adapter->hw; 3688c2ecf20Sopenharmony_ci u64 stamp = 0; 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci stamp |= (u64)IXGBE_READ_REG(hw, IXGBE_SYSTIML); 3718c2ecf20Sopenharmony_ci stamp |= (u64)IXGBE_READ_REG(hw, IXGBE_SYSTIMH) << 32; 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci return stamp; 3748c2ecf20Sopenharmony_ci} 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci/** 3778c2ecf20Sopenharmony_ci * ixgbe_ptp_convert_to_hwtstamp - convert register value to hw timestamp 3788c2ecf20Sopenharmony_ci * @adapter: private adapter structure 3798c2ecf20Sopenharmony_ci * @hwtstamp: stack timestamp structure 3808c2ecf20Sopenharmony_ci * @timestamp: unsigned 64bit system time value 3818c2ecf20Sopenharmony_ci * 3828c2ecf20Sopenharmony_ci * We need to convert the adapter's RX/TXSTMP registers into a hwtstamp value 3838c2ecf20Sopenharmony_ci * which can be used by the stack's ptp functions. 3848c2ecf20Sopenharmony_ci * 3858c2ecf20Sopenharmony_ci * The lock is used to protect consistency of the cyclecounter and the SYSTIME 3868c2ecf20Sopenharmony_ci * registers. However, it does not need to protect against the Rx or Tx 3878c2ecf20Sopenharmony_ci * timestamp registers, as there can't be a new timestamp until the old one is 3888c2ecf20Sopenharmony_ci * unlatched by reading. 3898c2ecf20Sopenharmony_ci * 3908c2ecf20Sopenharmony_ci * In addition to the timestamp in hardware, some controllers need a software 3918c2ecf20Sopenharmony_ci * overflow cyclecounter, and this function takes this into account as well. 3928c2ecf20Sopenharmony_ci **/ 3938c2ecf20Sopenharmony_cistatic void ixgbe_ptp_convert_to_hwtstamp(struct ixgbe_adapter *adapter, 3948c2ecf20Sopenharmony_ci struct skb_shared_hwtstamps *hwtstamp, 3958c2ecf20Sopenharmony_ci u64 timestamp) 3968c2ecf20Sopenharmony_ci{ 3978c2ecf20Sopenharmony_ci unsigned long flags; 3988c2ecf20Sopenharmony_ci struct timespec64 systime; 3998c2ecf20Sopenharmony_ci u64 ns; 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci memset(hwtstamp, 0, sizeof(*hwtstamp)); 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci switch (adapter->hw.mac.type) { 4048c2ecf20Sopenharmony_ci /* X550 and later hardware supposedly represent time using a seconds 4058c2ecf20Sopenharmony_ci * and nanoseconds counter, instead of raw 64bits nanoseconds. We need 4068c2ecf20Sopenharmony_ci * to convert the timestamp into cycles before it can be fed to the 4078c2ecf20Sopenharmony_ci * cyclecounter. We need an actual cyclecounter because some revisions 4088c2ecf20Sopenharmony_ci * of hardware run at a higher frequency and thus the counter does 4098c2ecf20Sopenharmony_ci * not represent seconds/nanoseconds. Instead it can be thought of as 4108c2ecf20Sopenharmony_ci * cycles and billions of cycles. 4118c2ecf20Sopenharmony_ci */ 4128c2ecf20Sopenharmony_ci case ixgbe_mac_X550: 4138c2ecf20Sopenharmony_ci case ixgbe_mac_X550EM_x: 4148c2ecf20Sopenharmony_ci case ixgbe_mac_x550em_a: 4158c2ecf20Sopenharmony_ci /* Upper 32 bits represent billions of cycles, lower 32 bits 4168c2ecf20Sopenharmony_ci * represent cycles. However, we use timespec64_to_ns for the 4178c2ecf20Sopenharmony_ci * correct math even though the units haven't been corrected 4188c2ecf20Sopenharmony_ci * yet. 4198c2ecf20Sopenharmony_ci */ 4208c2ecf20Sopenharmony_ci systime.tv_sec = timestamp >> 32; 4218c2ecf20Sopenharmony_ci systime.tv_nsec = timestamp & 0xFFFFFFFF; 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci timestamp = timespec64_to_ns(&systime); 4248c2ecf20Sopenharmony_ci break; 4258c2ecf20Sopenharmony_ci default: 4268c2ecf20Sopenharmony_ci break; 4278c2ecf20Sopenharmony_ci } 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci spin_lock_irqsave(&adapter->tmreg_lock, flags); 4308c2ecf20Sopenharmony_ci ns = timecounter_cyc2time(&adapter->hw_tc, timestamp); 4318c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&adapter->tmreg_lock, flags); 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci hwtstamp->hwtstamp = ns_to_ktime(ns); 4348c2ecf20Sopenharmony_ci} 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci/** 4378c2ecf20Sopenharmony_ci * ixgbe_ptp_adjfreq_82599 4388c2ecf20Sopenharmony_ci * @ptp: the ptp clock structure 4398c2ecf20Sopenharmony_ci * @ppb: parts per billion adjustment from base 4408c2ecf20Sopenharmony_ci * 4418c2ecf20Sopenharmony_ci * adjust the frequency of the ptp cycle counter by the 4428c2ecf20Sopenharmony_ci * indicated ppb from the base frequency. 4438c2ecf20Sopenharmony_ci */ 4448c2ecf20Sopenharmony_cistatic int ixgbe_ptp_adjfreq_82599(struct ptp_clock_info *ptp, s32 ppb) 4458c2ecf20Sopenharmony_ci{ 4468c2ecf20Sopenharmony_ci struct ixgbe_adapter *adapter = 4478c2ecf20Sopenharmony_ci container_of(ptp, struct ixgbe_adapter, ptp_caps); 4488c2ecf20Sopenharmony_ci struct ixgbe_hw *hw = &adapter->hw; 4498c2ecf20Sopenharmony_ci u64 freq, incval; 4508c2ecf20Sopenharmony_ci u32 diff; 4518c2ecf20Sopenharmony_ci int neg_adj = 0; 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci if (ppb < 0) { 4548c2ecf20Sopenharmony_ci neg_adj = 1; 4558c2ecf20Sopenharmony_ci ppb = -ppb; 4568c2ecf20Sopenharmony_ci } 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci smp_mb(); 4598c2ecf20Sopenharmony_ci incval = READ_ONCE(adapter->base_incval); 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci freq = incval; 4628c2ecf20Sopenharmony_ci freq *= ppb; 4638c2ecf20Sopenharmony_ci diff = div_u64(freq, 1000000000ULL); 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci incval = neg_adj ? (incval - diff) : (incval + diff); 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci switch (hw->mac.type) { 4688c2ecf20Sopenharmony_ci case ixgbe_mac_X540: 4698c2ecf20Sopenharmony_ci if (incval > 0xFFFFFFFFULL) 4708c2ecf20Sopenharmony_ci e_dev_warn("PTP ppb adjusted SYSTIME rate overflowed!\n"); 4718c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_TIMINCA, (u32)incval); 4728c2ecf20Sopenharmony_ci break; 4738c2ecf20Sopenharmony_ci case ixgbe_mac_82599EB: 4748c2ecf20Sopenharmony_ci if (incval > 0x00FFFFFFULL) 4758c2ecf20Sopenharmony_ci e_dev_warn("PTP ppb adjusted SYSTIME rate overflowed!\n"); 4768c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_TIMINCA, 4778c2ecf20Sopenharmony_ci BIT(IXGBE_INCPER_SHIFT_82599) | 4788c2ecf20Sopenharmony_ci ((u32)incval & 0x00FFFFFFUL)); 4798c2ecf20Sopenharmony_ci break; 4808c2ecf20Sopenharmony_ci default: 4818c2ecf20Sopenharmony_ci break; 4828c2ecf20Sopenharmony_ci } 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci return 0; 4858c2ecf20Sopenharmony_ci} 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci/** 4888c2ecf20Sopenharmony_ci * ixgbe_ptp_adjfreq_X550 4898c2ecf20Sopenharmony_ci * @ptp: the ptp clock structure 4908c2ecf20Sopenharmony_ci * @ppb: parts per billion adjustment from base 4918c2ecf20Sopenharmony_ci * 4928c2ecf20Sopenharmony_ci * adjust the frequency of the SYSTIME registers by the indicated ppb from base 4938c2ecf20Sopenharmony_ci * frequency 4948c2ecf20Sopenharmony_ci */ 4958c2ecf20Sopenharmony_cistatic int ixgbe_ptp_adjfreq_X550(struct ptp_clock_info *ptp, s32 ppb) 4968c2ecf20Sopenharmony_ci{ 4978c2ecf20Sopenharmony_ci struct ixgbe_adapter *adapter = 4988c2ecf20Sopenharmony_ci container_of(ptp, struct ixgbe_adapter, ptp_caps); 4998c2ecf20Sopenharmony_ci struct ixgbe_hw *hw = &adapter->hw; 5008c2ecf20Sopenharmony_ci int neg_adj = 0; 5018c2ecf20Sopenharmony_ci u64 rate = IXGBE_X550_BASE_PERIOD; 5028c2ecf20Sopenharmony_ci u32 inca; 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci if (ppb < 0) { 5058c2ecf20Sopenharmony_ci neg_adj = 1; 5068c2ecf20Sopenharmony_ci ppb = -ppb; 5078c2ecf20Sopenharmony_ci } 5088c2ecf20Sopenharmony_ci rate *= ppb; 5098c2ecf20Sopenharmony_ci rate = div_u64(rate, 1000000000ULL); 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ci /* warn if rate is too large */ 5128c2ecf20Sopenharmony_ci if (rate >= INCVALUE_MASK) 5138c2ecf20Sopenharmony_ci e_dev_warn("PTP ppb adjusted SYSTIME rate overflowed!\n"); 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci inca = rate & INCVALUE_MASK; 5168c2ecf20Sopenharmony_ci if (neg_adj) 5178c2ecf20Sopenharmony_ci inca |= ISGN; 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_TIMINCA, inca); 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci return 0; 5228c2ecf20Sopenharmony_ci} 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci/** 5258c2ecf20Sopenharmony_ci * ixgbe_ptp_adjtime 5268c2ecf20Sopenharmony_ci * @ptp: the ptp clock structure 5278c2ecf20Sopenharmony_ci * @delta: offset to adjust the cycle counter by 5288c2ecf20Sopenharmony_ci * 5298c2ecf20Sopenharmony_ci * adjust the timer by resetting the timecounter structure. 5308c2ecf20Sopenharmony_ci */ 5318c2ecf20Sopenharmony_cistatic int ixgbe_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta) 5328c2ecf20Sopenharmony_ci{ 5338c2ecf20Sopenharmony_ci struct ixgbe_adapter *adapter = 5348c2ecf20Sopenharmony_ci container_of(ptp, struct ixgbe_adapter, ptp_caps); 5358c2ecf20Sopenharmony_ci unsigned long flags; 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci spin_lock_irqsave(&adapter->tmreg_lock, flags); 5388c2ecf20Sopenharmony_ci timecounter_adjtime(&adapter->hw_tc, delta); 5398c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&adapter->tmreg_lock, flags); 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_ci if (adapter->ptp_setup_sdp) 5428c2ecf20Sopenharmony_ci adapter->ptp_setup_sdp(adapter); 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_ci return 0; 5458c2ecf20Sopenharmony_ci} 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_ci/** 5488c2ecf20Sopenharmony_ci * ixgbe_ptp_gettimex 5498c2ecf20Sopenharmony_ci * @ptp: the ptp clock structure 5508c2ecf20Sopenharmony_ci * @ts: timespec to hold the PHC timestamp 5518c2ecf20Sopenharmony_ci * @sts: structure to hold the system time before and after reading the PHC 5528c2ecf20Sopenharmony_ci * 5538c2ecf20Sopenharmony_ci * read the timecounter and return the correct value on ns, 5548c2ecf20Sopenharmony_ci * after converting it into a struct timespec. 5558c2ecf20Sopenharmony_ci */ 5568c2ecf20Sopenharmony_cistatic int ixgbe_ptp_gettimex(struct ptp_clock_info *ptp, 5578c2ecf20Sopenharmony_ci struct timespec64 *ts, 5588c2ecf20Sopenharmony_ci struct ptp_system_timestamp *sts) 5598c2ecf20Sopenharmony_ci{ 5608c2ecf20Sopenharmony_ci struct ixgbe_adapter *adapter = 5618c2ecf20Sopenharmony_ci container_of(ptp, struct ixgbe_adapter, ptp_caps); 5628c2ecf20Sopenharmony_ci struct ixgbe_hw *hw = &adapter->hw; 5638c2ecf20Sopenharmony_ci unsigned long flags; 5648c2ecf20Sopenharmony_ci u64 ns, stamp; 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_ci spin_lock_irqsave(&adapter->tmreg_lock, flags); 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_ci switch (adapter->hw.mac.type) { 5698c2ecf20Sopenharmony_ci case ixgbe_mac_X550: 5708c2ecf20Sopenharmony_ci case ixgbe_mac_X550EM_x: 5718c2ecf20Sopenharmony_ci case ixgbe_mac_x550em_a: 5728c2ecf20Sopenharmony_ci /* Upper 32 bits represent billions of cycles, lower 32 bits 5738c2ecf20Sopenharmony_ci * represent cycles. However, we use timespec64_to_ns for the 5748c2ecf20Sopenharmony_ci * correct math even though the units haven't been corrected 5758c2ecf20Sopenharmony_ci * yet. 5768c2ecf20Sopenharmony_ci */ 5778c2ecf20Sopenharmony_ci ptp_read_system_prets(sts); 5788c2ecf20Sopenharmony_ci IXGBE_READ_REG(hw, IXGBE_SYSTIMR); 5798c2ecf20Sopenharmony_ci ptp_read_system_postts(sts); 5808c2ecf20Sopenharmony_ci ts->tv_nsec = IXGBE_READ_REG(hw, IXGBE_SYSTIML); 5818c2ecf20Sopenharmony_ci ts->tv_sec = IXGBE_READ_REG(hw, IXGBE_SYSTIMH); 5828c2ecf20Sopenharmony_ci stamp = timespec64_to_ns(ts); 5838c2ecf20Sopenharmony_ci break; 5848c2ecf20Sopenharmony_ci default: 5858c2ecf20Sopenharmony_ci ptp_read_system_prets(sts); 5868c2ecf20Sopenharmony_ci stamp = IXGBE_READ_REG(hw, IXGBE_SYSTIML); 5878c2ecf20Sopenharmony_ci ptp_read_system_postts(sts); 5888c2ecf20Sopenharmony_ci stamp |= (u64)IXGBE_READ_REG(hw, IXGBE_SYSTIMH) << 32; 5898c2ecf20Sopenharmony_ci break; 5908c2ecf20Sopenharmony_ci } 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci ns = timecounter_cyc2time(&adapter->hw_tc, stamp); 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&adapter->tmreg_lock, flags); 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci *ts = ns_to_timespec64(ns); 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci return 0; 5998c2ecf20Sopenharmony_ci} 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci/** 6028c2ecf20Sopenharmony_ci * ixgbe_ptp_settime 6038c2ecf20Sopenharmony_ci * @ptp: the ptp clock structure 6048c2ecf20Sopenharmony_ci * @ts: the timespec containing the new time for the cycle counter 6058c2ecf20Sopenharmony_ci * 6068c2ecf20Sopenharmony_ci * reset the timecounter to use a new base value instead of the kernel 6078c2ecf20Sopenharmony_ci * wall timer value. 6088c2ecf20Sopenharmony_ci */ 6098c2ecf20Sopenharmony_cistatic int ixgbe_ptp_settime(struct ptp_clock_info *ptp, 6108c2ecf20Sopenharmony_ci const struct timespec64 *ts) 6118c2ecf20Sopenharmony_ci{ 6128c2ecf20Sopenharmony_ci struct ixgbe_adapter *adapter = 6138c2ecf20Sopenharmony_ci container_of(ptp, struct ixgbe_adapter, ptp_caps); 6148c2ecf20Sopenharmony_ci unsigned long flags; 6158c2ecf20Sopenharmony_ci u64 ns = timespec64_to_ns(ts); 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_ci /* reset the timecounter */ 6188c2ecf20Sopenharmony_ci spin_lock_irqsave(&adapter->tmreg_lock, flags); 6198c2ecf20Sopenharmony_ci timecounter_init(&adapter->hw_tc, &adapter->hw_cc, ns); 6208c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&adapter->tmreg_lock, flags); 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_ci if (adapter->ptp_setup_sdp) 6238c2ecf20Sopenharmony_ci adapter->ptp_setup_sdp(adapter); 6248c2ecf20Sopenharmony_ci return 0; 6258c2ecf20Sopenharmony_ci} 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ci/** 6288c2ecf20Sopenharmony_ci * ixgbe_ptp_feature_enable 6298c2ecf20Sopenharmony_ci * @ptp: the ptp clock structure 6308c2ecf20Sopenharmony_ci * @rq: the requested feature to change 6318c2ecf20Sopenharmony_ci * @on: whether to enable or disable the feature 6328c2ecf20Sopenharmony_ci * 6338c2ecf20Sopenharmony_ci * enable (or disable) ancillary features of the phc subsystem. 6348c2ecf20Sopenharmony_ci * our driver only supports the PPS feature on the X540 6358c2ecf20Sopenharmony_ci */ 6368c2ecf20Sopenharmony_cistatic int ixgbe_ptp_feature_enable(struct ptp_clock_info *ptp, 6378c2ecf20Sopenharmony_ci struct ptp_clock_request *rq, int on) 6388c2ecf20Sopenharmony_ci{ 6398c2ecf20Sopenharmony_ci struct ixgbe_adapter *adapter = 6408c2ecf20Sopenharmony_ci container_of(ptp, struct ixgbe_adapter, ptp_caps); 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_ci /** 6438c2ecf20Sopenharmony_ci * When PPS is enabled, unmask the interrupt for the ClockOut 6448c2ecf20Sopenharmony_ci * feature, so that the interrupt handler can send the PPS 6458c2ecf20Sopenharmony_ci * event when the clock SDP triggers. Clear mask when PPS is 6468c2ecf20Sopenharmony_ci * disabled 6478c2ecf20Sopenharmony_ci */ 6488c2ecf20Sopenharmony_ci if (rq->type != PTP_CLK_REQ_PPS || !adapter->ptp_setup_sdp) 6498c2ecf20Sopenharmony_ci return -ENOTSUPP; 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_ci if (on) 6528c2ecf20Sopenharmony_ci adapter->flags2 |= IXGBE_FLAG2_PTP_PPS_ENABLED; 6538c2ecf20Sopenharmony_ci else 6548c2ecf20Sopenharmony_ci adapter->flags2 &= ~IXGBE_FLAG2_PTP_PPS_ENABLED; 6558c2ecf20Sopenharmony_ci 6568c2ecf20Sopenharmony_ci adapter->ptp_setup_sdp(adapter); 6578c2ecf20Sopenharmony_ci return 0; 6588c2ecf20Sopenharmony_ci} 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_ci/** 6618c2ecf20Sopenharmony_ci * ixgbe_ptp_check_pps_event 6628c2ecf20Sopenharmony_ci * @adapter: the private adapter structure 6638c2ecf20Sopenharmony_ci * 6648c2ecf20Sopenharmony_ci * This function is called by the interrupt routine when checking for 6658c2ecf20Sopenharmony_ci * interrupts. It will check and handle a pps event. 6668c2ecf20Sopenharmony_ci */ 6678c2ecf20Sopenharmony_civoid ixgbe_ptp_check_pps_event(struct ixgbe_adapter *adapter) 6688c2ecf20Sopenharmony_ci{ 6698c2ecf20Sopenharmony_ci struct ixgbe_hw *hw = &adapter->hw; 6708c2ecf20Sopenharmony_ci struct ptp_clock_event event; 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci event.type = PTP_CLOCK_PPS; 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_ci /* this check is necessary in case the interrupt was enabled via some 6758c2ecf20Sopenharmony_ci * alternative means (ex. debug_fs). Better to check here than 6768c2ecf20Sopenharmony_ci * everywhere that calls this function. 6778c2ecf20Sopenharmony_ci */ 6788c2ecf20Sopenharmony_ci if (!adapter->ptp_clock) 6798c2ecf20Sopenharmony_ci return; 6808c2ecf20Sopenharmony_ci 6818c2ecf20Sopenharmony_ci switch (hw->mac.type) { 6828c2ecf20Sopenharmony_ci case ixgbe_mac_X540: 6838c2ecf20Sopenharmony_ci ptp_clock_event(adapter->ptp_clock, &event); 6848c2ecf20Sopenharmony_ci break; 6858c2ecf20Sopenharmony_ci default: 6868c2ecf20Sopenharmony_ci break; 6878c2ecf20Sopenharmony_ci } 6888c2ecf20Sopenharmony_ci} 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_ci/** 6918c2ecf20Sopenharmony_ci * ixgbe_ptp_overflow_check - watchdog task to detect SYSTIME overflow 6928c2ecf20Sopenharmony_ci * @adapter: private adapter struct 6938c2ecf20Sopenharmony_ci * 6948c2ecf20Sopenharmony_ci * this watchdog task periodically reads the timecounter 6958c2ecf20Sopenharmony_ci * in order to prevent missing when the system time registers wrap 6968c2ecf20Sopenharmony_ci * around. This needs to be run approximately twice a minute. 6978c2ecf20Sopenharmony_ci */ 6988c2ecf20Sopenharmony_civoid ixgbe_ptp_overflow_check(struct ixgbe_adapter *adapter) 6998c2ecf20Sopenharmony_ci{ 7008c2ecf20Sopenharmony_ci bool timeout = time_is_before_jiffies(adapter->last_overflow_check + 7018c2ecf20Sopenharmony_ci IXGBE_OVERFLOW_PERIOD); 7028c2ecf20Sopenharmony_ci unsigned long flags; 7038c2ecf20Sopenharmony_ci 7048c2ecf20Sopenharmony_ci if (timeout) { 7058c2ecf20Sopenharmony_ci /* Update the timecounter */ 7068c2ecf20Sopenharmony_ci spin_lock_irqsave(&adapter->tmreg_lock, flags); 7078c2ecf20Sopenharmony_ci timecounter_read(&adapter->hw_tc); 7088c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&adapter->tmreg_lock, flags); 7098c2ecf20Sopenharmony_ci 7108c2ecf20Sopenharmony_ci adapter->last_overflow_check = jiffies; 7118c2ecf20Sopenharmony_ci } 7128c2ecf20Sopenharmony_ci} 7138c2ecf20Sopenharmony_ci 7148c2ecf20Sopenharmony_ci/** 7158c2ecf20Sopenharmony_ci * ixgbe_ptp_rx_hang - detect error case when Rx timestamp registers latched 7168c2ecf20Sopenharmony_ci * @adapter: private network adapter structure 7178c2ecf20Sopenharmony_ci * 7188c2ecf20Sopenharmony_ci * this watchdog task is scheduled to detect error case where hardware has 7198c2ecf20Sopenharmony_ci * dropped an Rx packet that was timestamped when the ring is full. The 7208c2ecf20Sopenharmony_ci * particular error is rare but leaves the device in a state unable to timestamp 7218c2ecf20Sopenharmony_ci * any future packets. 7228c2ecf20Sopenharmony_ci */ 7238c2ecf20Sopenharmony_civoid ixgbe_ptp_rx_hang(struct ixgbe_adapter *adapter) 7248c2ecf20Sopenharmony_ci{ 7258c2ecf20Sopenharmony_ci struct ixgbe_hw *hw = &adapter->hw; 7268c2ecf20Sopenharmony_ci u32 tsyncrxctl = IXGBE_READ_REG(hw, IXGBE_TSYNCRXCTL); 7278c2ecf20Sopenharmony_ci struct ixgbe_ring *rx_ring; 7288c2ecf20Sopenharmony_ci unsigned long rx_event; 7298c2ecf20Sopenharmony_ci int n; 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_ci /* if we don't have a valid timestamp in the registers, just update the 7328c2ecf20Sopenharmony_ci * timeout counter and exit 7338c2ecf20Sopenharmony_ci */ 7348c2ecf20Sopenharmony_ci if (!(tsyncrxctl & IXGBE_TSYNCRXCTL_VALID)) { 7358c2ecf20Sopenharmony_ci adapter->last_rx_ptp_check = jiffies; 7368c2ecf20Sopenharmony_ci return; 7378c2ecf20Sopenharmony_ci } 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_ci /* determine the most recent watchdog or rx_timestamp event */ 7408c2ecf20Sopenharmony_ci rx_event = adapter->last_rx_ptp_check; 7418c2ecf20Sopenharmony_ci for (n = 0; n < adapter->num_rx_queues; n++) { 7428c2ecf20Sopenharmony_ci rx_ring = adapter->rx_ring[n]; 7438c2ecf20Sopenharmony_ci if (time_after(rx_ring->last_rx_timestamp, rx_event)) 7448c2ecf20Sopenharmony_ci rx_event = rx_ring->last_rx_timestamp; 7458c2ecf20Sopenharmony_ci } 7468c2ecf20Sopenharmony_ci 7478c2ecf20Sopenharmony_ci /* only need to read the high RXSTMP register to clear the lock */ 7488c2ecf20Sopenharmony_ci if (time_is_before_jiffies(rx_event + 5 * HZ)) { 7498c2ecf20Sopenharmony_ci IXGBE_READ_REG(hw, IXGBE_RXSTMPH); 7508c2ecf20Sopenharmony_ci adapter->last_rx_ptp_check = jiffies; 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_ci adapter->rx_hwtstamp_cleared++; 7538c2ecf20Sopenharmony_ci e_warn(drv, "clearing RX Timestamp hang\n"); 7548c2ecf20Sopenharmony_ci } 7558c2ecf20Sopenharmony_ci} 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_ci/** 7588c2ecf20Sopenharmony_ci * ixgbe_ptp_clear_tx_timestamp - utility function to clear Tx timestamp state 7598c2ecf20Sopenharmony_ci * @adapter: the private adapter structure 7608c2ecf20Sopenharmony_ci * 7618c2ecf20Sopenharmony_ci * This function should be called whenever the state related to a Tx timestamp 7628c2ecf20Sopenharmony_ci * needs to be cleared. This helps ensure that all related bits are reset for 7638c2ecf20Sopenharmony_ci * the next Tx timestamp event. 7648c2ecf20Sopenharmony_ci */ 7658c2ecf20Sopenharmony_cistatic void ixgbe_ptp_clear_tx_timestamp(struct ixgbe_adapter *adapter) 7668c2ecf20Sopenharmony_ci{ 7678c2ecf20Sopenharmony_ci struct ixgbe_hw *hw = &adapter->hw; 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_ci IXGBE_READ_REG(hw, IXGBE_TXSTMPH); 7708c2ecf20Sopenharmony_ci if (adapter->ptp_tx_skb) { 7718c2ecf20Sopenharmony_ci dev_kfree_skb_any(adapter->ptp_tx_skb); 7728c2ecf20Sopenharmony_ci adapter->ptp_tx_skb = NULL; 7738c2ecf20Sopenharmony_ci } 7748c2ecf20Sopenharmony_ci clear_bit_unlock(__IXGBE_PTP_TX_IN_PROGRESS, &adapter->state); 7758c2ecf20Sopenharmony_ci} 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_ci/** 7788c2ecf20Sopenharmony_ci * ixgbe_ptp_tx_hang - detect error case where Tx timestamp never finishes 7798c2ecf20Sopenharmony_ci * @adapter: private network adapter structure 7808c2ecf20Sopenharmony_ci */ 7818c2ecf20Sopenharmony_civoid ixgbe_ptp_tx_hang(struct ixgbe_adapter *adapter) 7828c2ecf20Sopenharmony_ci{ 7838c2ecf20Sopenharmony_ci bool timeout = time_is_before_jiffies(adapter->ptp_tx_start + 7848c2ecf20Sopenharmony_ci IXGBE_PTP_TX_TIMEOUT); 7858c2ecf20Sopenharmony_ci 7868c2ecf20Sopenharmony_ci if (!adapter->ptp_tx_skb) 7878c2ecf20Sopenharmony_ci return; 7888c2ecf20Sopenharmony_ci 7898c2ecf20Sopenharmony_ci if (!test_bit(__IXGBE_PTP_TX_IN_PROGRESS, &adapter->state)) 7908c2ecf20Sopenharmony_ci return; 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_ci /* If we haven't received a timestamp within the timeout, it is 7938c2ecf20Sopenharmony_ci * reasonable to assume that it will never occur, so we can unlock the 7948c2ecf20Sopenharmony_ci * timestamp bit when this occurs. 7958c2ecf20Sopenharmony_ci */ 7968c2ecf20Sopenharmony_ci if (timeout) { 7978c2ecf20Sopenharmony_ci cancel_work_sync(&adapter->ptp_tx_work); 7988c2ecf20Sopenharmony_ci ixgbe_ptp_clear_tx_timestamp(adapter); 7998c2ecf20Sopenharmony_ci adapter->tx_hwtstamp_timeouts++; 8008c2ecf20Sopenharmony_ci e_warn(drv, "clearing Tx timestamp hang\n"); 8018c2ecf20Sopenharmony_ci } 8028c2ecf20Sopenharmony_ci} 8038c2ecf20Sopenharmony_ci 8048c2ecf20Sopenharmony_ci/** 8058c2ecf20Sopenharmony_ci * ixgbe_ptp_tx_hwtstamp - utility function which checks for TX time stamp 8068c2ecf20Sopenharmony_ci * @adapter: the private adapter struct 8078c2ecf20Sopenharmony_ci * 8088c2ecf20Sopenharmony_ci * if the timestamp is valid, we convert it into the timecounter ns 8098c2ecf20Sopenharmony_ci * value, then store that result into the shhwtstamps structure which 8108c2ecf20Sopenharmony_ci * is passed up the network stack 8118c2ecf20Sopenharmony_ci */ 8128c2ecf20Sopenharmony_cistatic void ixgbe_ptp_tx_hwtstamp(struct ixgbe_adapter *adapter) 8138c2ecf20Sopenharmony_ci{ 8148c2ecf20Sopenharmony_ci struct sk_buff *skb = adapter->ptp_tx_skb; 8158c2ecf20Sopenharmony_ci struct ixgbe_hw *hw = &adapter->hw; 8168c2ecf20Sopenharmony_ci struct skb_shared_hwtstamps shhwtstamps; 8178c2ecf20Sopenharmony_ci u64 regval = 0; 8188c2ecf20Sopenharmony_ci 8198c2ecf20Sopenharmony_ci regval |= (u64)IXGBE_READ_REG(hw, IXGBE_TXSTMPL); 8208c2ecf20Sopenharmony_ci regval |= (u64)IXGBE_READ_REG(hw, IXGBE_TXSTMPH) << 32; 8218c2ecf20Sopenharmony_ci ixgbe_ptp_convert_to_hwtstamp(adapter, &shhwtstamps, regval); 8228c2ecf20Sopenharmony_ci 8238c2ecf20Sopenharmony_ci /* Handle cleanup of the ptp_tx_skb ourselves, and unlock the state 8248c2ecf20Sopenharmony_ci * bit prior to notifying the stack via skb_tstamp_tx(). This prevents 8258c2ecf20Sopenharmony_ci * well behaved applications from attempting to timestamp again prior 8268c2ecf20Sopenharmony_ci * to the lock bit being clear. 8278c2ecf20Sopenharmony_ci */ 8288c2ecf20Sopenharmony_ci adapter->ptp_tx_skb = NULL; 8298c2ecf20Sopenharmony_ci clear_bit_unlock(__IXGBE_PTP_TX_IN_PROGRESS, &adapter->state); 8308c2ecf20Sopenharmony_ci 8318c2ecf20Sopenharmony_ci /* Notify the stack and then free the skb after we've unlocked */ 8328c2ecf20Sopenharmony_ci skb_tstamp_tx(skb, &shhwtstamps); 8338c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 8348c2ecf20Sopenharmony_ci} 8358c2ecf20Sopenharmony_ci 8368c2ecf20Sopenharmony_ci/** 8378c2ecf20Sopenharmony_ci * ixgbe_ptp_tx_hwtstamp_work 8388c2ecf20Sopenharmony_ci * @work: pointer to the work struct 8398c2ecf20Sopenharmony_ci * 8408c2ecf20Sopenharmony_ci * This work item polls TSYNCTXCTL valid bit to determine when a Tx hardware 8418c2ecf20Sopenharmony_ci * timestamp has been taken for the current skb. It is necessary, because the 8428c2ecf20Sopenharmony_ci * descriptor's "done" bit does not correlate with the timestamp event. 8438c2ecf20Sopenharmony_ci */ 8448c2ecf20Sopenharmony_cistatic void ixgbe_ptp_tx_hwtstamp_work(struct work_struct *work) 8458c2ecf20Sopenharmony_ci{ 8468c2ecf20Sopenharmony_ci struct ixgbe_adapter *adapter = container_of(work, struct ixgbe_adapter, 8478c2ecf20Sopenharmony_ci ptp_tx_work); 8488c2ecf20Sopenharmony_ci struct ixgbe_hw *hw = &adapter->hw; 8498c2ecf20Sopenharmony_ci bool timeout = time_is_before_jiffies(adapter->ptp_tx_start + 8508c2ecf20Sopenharmony_ci IXGBE_PTP_TX_TIMEOUT); 8518c2ecf20Sopenharmony_ci u32 tsynctxctl; 8528c2ecf20Sopenharmony_ci 8538c2ecf20Sopenharmony_ci /* we have to have a valid skb to poll for a timestamp */ 8548c2ecf20Sopenharmony_ci if (!adapter->ptp_tx_skb) { 8558c2ecf20Sopenharmony_ci ixgbe_ptp_clear_tx_timestamp(adapter); 8568c2ecf20Sopenharmony_ci return; 8578c2ecf20Sopenharmony_ci } 8588c2ecf20Sopenharmony_ci 8598c2ecf20Sopenharmony_ci /* stop polling once we have a valid timestamp */ 8608c2ecf20Sopenharmony_ci tsynctxctl = IXGBE_READ_REG(hw, IXGBE_TSYNCTXCTL); 8618c2ecf20Sopenharmony_ci if (tsynctxctl & IXGBE_TSYNCTXCTL_VALID) { 8628c2ecf20Sopenharmony_ci ixgbe_ptp_tx_hwtstamp(adapter); 8638c2ecf20Sopenharmony_ci return; 8648c2ecf20Sopenharmony_ci } 8658c2ecf20Sopenharmony_ci 8668c2ecf20Sopenharmony_ci if (timeout) { 8678c2ecf20Sopenharmony_ci ixgbe_ptp_clear_tx_timestamp(adapter); 8688c2ecf20Sopenharmony_ci adapter->tx_hwtstamp_timeouts++; 8698c2ecf20Sopenharmony_ci e_warn(drv, "clearing Tx Timestamp hang\n"); 8708c2ecf20Sopenharmony_ci } else { 8718c2ecf20Sopenharmony_ci /* reschedule to keep checking if it's not available yet */ 8728c2ecf20Sopenharmony_ci schedule_work(&adapter->ptp_tx_work); 8738c2ecf20Sopenharmony_ci } 8748c2ecf20Sopenharmony_ci} 8758c2ecf20Sopenharmony_ci 8768c2ecf20Sopenharmony_ci/** 8778c2ecf20Sopenharmony_ci * ixgbe_ptp_rx_pktstamp - utility function to get RX time stamp from buffer 8788c2ecf20Sopenharmony_ci * @q_vector: structure containing interrupt and ring information 8798c2ecf20Sopenharmony_ci * @skb: the packet 8808c2ecf20Sopenharmony_ci * 8818c2ecf20Sopenharmony_ci * This function will be called by the Rx routine of the timestamp for this 8828c2ecf20Sopenharmony_ci * packet is stored in the buffer. The value is stored in little endian format 8838c2ecf20Sopenharmony_ci * starting at the end of the packet data. 8848c2ecf20Sopenharmony_ci */ 8858c2ecf20Sopenharmony_civoid ixgbe_ptp_rx_pktstamp(struct ixgbe_q_vector *q_vector, 8868c2ecf20Sopenharmony_ci struct sk_buff *skb) 8878c2ecf20Sopenharmony_ci{ 8888c2ecf20Sopenharmony_ci __le64 regval; 8898c2ecf20Sopenharmony_ci 8908c2ecf20Sopenharmony_ci /* copy the bits out of the skb, and then trim the skb length */ 8918c2ecf20Sopenharmony_ci skb_copy_bits(skb, skb->len - IXGBE_TS_HDR_LEN, ®val, 8928c2ecf20Sopenharmony_ci IXGBE_TS_HDR_LEN); 8938c2ecf20Sopenharmony_ci __pskb_trim(skb, skb->len - IXGBE_TS_HDR_LEN); 8948c2ecf20Sopenharmony_ci 8958c2ecf20Sopenharmony_ci /* The timestamp is recorded in little endian format, and is stored at 8968c2ecf20Sopenharmony_ci * the end of the packet. 8978c2ecf20Sopenharmony_ci * 8988c2ecf20Sopenharmony_ci * DWORD: N N + 1 N + 2 8998c2ecf20Sopenharmony_ci * Field: End of Packet SYSTIMH SYSTIML 9008c2ecf20Sopenharmony_ci */ 9018c2ecf20Sopenharmony_ci ixgbe_ptp_convert_to_hwtstamp(q_vector->adapter, skb_hwtstamps(skb), 9028c2ecf20Sopenharmony_ci le64_to_cpu(regval)); 9038c2ecf20Sopenharmony_ci} 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_ci/** 9068c2ecf20Sopenharmony_ci * ixgbe_ptp_rx_rgtstamp - utility function which checks for RX time stamp 9078c2ecf20Sopenharmony_ci * @q_vector: structure containing interrupt and ring information 9088c2ecf20Sopenharmony_ci * @skb: particular skb to send timestamp with 9098c2ecf20Sopenharmony_ci * 9108c2ecf20Sopenharmony_ci * if the timestamp is valid, we convert it into the timecounter ns 9118c2ecf20Sopenharmony_ci * value, then store that result into the shhwtstamps structure which 9128c2ecf20Sopenharmony_ci * is passed up the network stack 9138c2ecf20Sopenharmony_ci */ 9148c2ecf20Sopenharmony_civoid ixgbe_ptp_rx_rgtstamp(struct ixgbe_q_vector *q_vector, 9158c2ecf20Sopenharmony_ci struct sk_buff *skb) 9168c2ecf20Sopenharmony_ci{ 9178c2ecf20Sopenharmony_ci struct ixgbe_adapter *adapter; 9188c2ecf20Sopenharmony_ci struct ixgbe_hw *hw; 9198c2ecf20Sopenharmony_ci u64 regval = 0; 9208c2ecf20Sopenharmony_ci u32 tsyncrxctl; 9218c2ecf20Sopenharmony_ci 9228c2ecf20Sopenharmony_ci /* we cannot process timestamps on a ring without a q_vector */ 9238c2ecf20Sopenharmony_ci if (!q_vector || !q_vector->adapter) 9248c2ecf20Sopenharmony_ci return; 9258c2ecf20Sopenharmony_ci 9268c2ecf20Sopenharmony_ci adapter = q_vector->adapter; 9278c2ecf20Sopenharmony_ci hw = &adapter->hw; 9288c2ecf20Sopenharmony_ci 9298c2ecf20Sopenharmony_ci /* Read the tsyncrxctl register afterwards in order to prevent taking an 9308c2ecf20Sopenharmony_ci * I/O hit on every packet. 9318c2ecf20Sopenharmony_ci */ 9328c2ecf20Sopenharmony_ci 9338c2ecf20Sopenharmony_ci tsyncrxctl = IXGBE_READ_REG(hw, IXGBE_TSYNCRXCTL); 9348c2ecf20Sopenharmony_ci if (!(tsyncrxctl & IXGBE_TSYNCRXCTL_VALID)) 9358c2ecf20Sopenharmony_ci return; 9368c2ecf20Sopenharmony_ci 9378c2ecf20Sopenharmony_ci regval |= (u64)IXGBE_READ_REG(hw, IXGBE_RXSTMPL); 9388c2ecf20Sopenharmony_ci regval |= (u64)IXGBE_READ_REG(hw, IXGBE_RXSTMPH) << 32; 9398c2ecf20Sopenharmony_ci 9408c2ecf20Sopenharmony_ci ixgbe_ptp_convert_to_hwtstamp(adapter, skb_hwtstamps(skb), regval); 9418c2ecf20Sopenharmony_ci} 9428c2ecf20Sopenharmony_ci 9438c2ecf20Sopenharmony_ci/** 9448c2ecf20Sopenharmony_ci * ixgbe_ptp_get_ts_config - get current hardware timestamping configuration 9458c2ecf20Sopenharmony_ci * @adapter: pointer to adapter structure 9468c2ecf20Sopenharmony_ci * @ifr: ioctl data 9478c2ecf20Sopenharmony_ci * 9488c2ecf20Sopenharmony_ci * This function returns the current timestamping settings. Rather than 9498c2ecf20Sopenharmony_ci * attempt to deconstruct registers to fill in the values, simply keep a copy 9508c2ecf20Sopenharmony_ci * of the old settings around, and return a copy when requested. 9518c2ecf20Sopenharmony_ci */ 9528c2ecf20Sopenharmony_ciint ixgbe_ptp_get_ts_config(struct ixgbe_adapter *adapter, struct ifreq *ifr) 9538c2ecf20Sopenharmony_ci{ 9548c2ecf20Sopenharmony_ci struct hwtstamp_config *config = &adapter->tstamp_config; 9558c2ecf20Sopenharmony_ci 9568c2ecf20Sopenharmony_ci return copy_to_user(ifr->ifr_data, config, 9578c2ecf20Sopenharmony_ci sizeof(*config)) ? -EFAULT : 0; 9588c2ecf20Sopenharmony_ci} 9598c2ecf20Sopenharmony_ci 9608c2ecf20Sopenharmony_ci/** 9618c2ecf20Sopenharmony_ci * ixgbe_ptp_set_timestamp_mode - setup the hardware for the requested mode 9628c2ecf20Sopenharmony_ci * @adapter: the private ixgbe adapter structure 9638c2ecf20Sopenharmony_ci * @config: the hwtstamp configuration requested 9648c2ecf20Sopenharmony_ci * 9658c2ecf20Sopenharmony_ci * Outgoing time stamping can be enabled and disabled. Play nice and 9668c2ecf20Sopenharmony_ci * disable it when requested, although it shouldn't cause any overhead 9678c2ecf20Sopenharmony_ci * when no packet needs it. At most one packet in the queue may be 9688c2ecf20Sopenharmony_ci * marked for time stamping, otherwise it would be impossible to tell 9698c2ecf20Sopenharmony_ci * for sure to which packet the hardware time stamp belongs. 9708c2ecf20Sopenharmony_ci * 9718c2ecf20Sopenharmony_ci * Incoming time stamping has to be configured via the hardware 9728c2ecf20Sopenharmony_ci * filters. Not all combinations are supported, in particular event 9738c2ecf20Sopenharmony_ci * type has to be specified. Matching the kind of event packet is 9748c2ecf20Sopenharmony_ci * not supported, with the exception of "all V2 events regardless of 9758c2ecf20Sopenharmony_ci * level 2 or 4". 9768c2ecf20Sopenharmony_ci * 9778c2ecf20Sopenharmony_ci * Since hardware always timestamps Path delay packets when timestamping V2 9788c2ecf20Sopenharmony_ci * packets, regardless of the type specified in the register, only use V2 9798c2ecf20Sopenharmony_ci * Event mode. This more accurately tells the user what the hardware is going 9808c2ecf20Sopenharmony_ci * to do anyways. 9818c2ecf20Sopenharmony_ci * 9828c2ecf20Sopenharmony_ci * Note: this may modify the hwtstamp configuration towards a more general 9838c2ecf20Sopenharmony_ci * mode, if required to support the specifically requested mode. 9848c2ecf20Sopenharmony_ci */ 9858c2ecf20Sopenharmony_cistatic int ixgbe_ptp_set_timestamp_mode(struct ixgbe_adapter *adapter, 9868c2ecf20Sopenharmony_ci struct hwtstamp_config *config) 9878c2ecf20Sopenharmony_ci{ 9888c2ecf20Sopenharmony_ci struct ixgbe_hw *hw = &adapter->hw; 9898c2ecf20Sopenharmony_ci u32 tsync_tx_ctl = IXGBE_TSYNCTXCTL_ENABLED; 9908c2ecf20Sopenharmony_ci u32 tsync_rx_ctl = IXGBE_TSYNCRXCTL_ENABLED; 9918c2ecf20Sopenharmony_ci u32 tsync_rx_mtrl = PTP_EV_PORT << 16; 9928c2ecf20Sopenharmony_ci u32 aflags = adapter->flags; 9938c2ecf20Sopenharmony_ci bool is_l2 = false; 9948c2ecf20Sopenharmony_ci u32 regval; 9958c2ecf20Sopenharmony_ci 9968c2ecf20Sopenharmony_ci /* reserved for future extensions */ 9978c2ecf20Sopenharmony_ci if (config->flags) 9988c2ecf20Sopenharmony_ci return -EINVAL; 9998c2ecf20Sopenharmony_ci 10008c2ecf20Sopenharmony_ci switch (config->tx_type) { 10018c2ecf20Sopenharmony_ci case HWTSTAMP_TX_OFF: 10028c2ecf20Sopenharmony_ci tsync_tx_ctl = 0; 10038c2ecf20Sopenharmony_ci case HWTSTAMP_TX_ON: 10048c2ecf20Sopenharmony_ci break; 10058c2ecf20Sopenharmony_ci default: 10068c2ecf20Sopenharmony_ci return -ERANGE; 10078c2ecf20Sopenharmony_ci } 10088c2ecf20Sopenharmony_ci 10098c2ecf20Sopenharmony_ci switch (config->rx_filter) { 10108c2ecf20Sopenharmony_ci case HWTSTAMP_FILTER_NONE: 10118c2ecf20Sopenharmony_ci tsync_rx_ctl = 0; 10128c2ecf20Sopenharmony_ci tsync_rx_mtrl = 0; 10138c2ecf20Sopenharmony_ci aflags &= ~(IXGBE_FLAG_RX_HWTSTAMP_ENABLED | 10148c2ecf20Sopenharmony_ci IXGBE_FLAG_RX_HWTSTAMP_IN_REGISTER); 10158c2ecf20Sopenharmony_ci break; 10168c2ecf20Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V1_L4_SYNC: 10178c2ecf20Sopenharmony_ci tsync_rx_ctl |= IXGBE_TSYNCRXCTL_TYPE_L4_V1; 10188c2ecf20Sopenharmony_ci tsync_rx_mtrl |= IXGBE_RXMTRL_V1_SYNC_MSG; 10198c2ecf20Sopenharmony_ci aflags |= (IXGBE_FLAG_RX_HWTSTAMP_ENABLED | 10208c2ecf20Sopenharmony_ci IXGBE_FLAG_RX_HWTSTAMP_IN_REGISTER); 10218c2ecf20Sopenharmony_ci break; 10228c2ecf20Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ: 10238c2ecf20Sopenharmony_ci tsync_rx_ctl |= IXGBE_TSYNCRXCTL_TYPE_L4_V1; 10248c2ecf20Sopenharmony_ci tsync_rx_mtrl |= IXGBE_RXMTRL_V1_DELAY_REQ_MSG; 10258c2ecf20Sopenharmony_ci aflags |= (IXGBE_FLAG_RX_HWTSTAMP_ENABLED | 10268c2ecf20Sopenharmony_ci IXGBE_FLAG_RX_HWTSTAMP_IN_REGISTER); 10278c2ecf20Sopenharmony_ci break; 10288c2ecf20Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V2_EVENT: 10298c2ecf20Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V2_L2_EVENT: 10308c2ecf20Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V2_L4_EVENT: 10318c2ecf20Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V2_SYNC: 10328c2ecf20Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V2_L2_SYNC: 10338c2ecf20Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V2_L4_SYNC: 10348c2ecf20Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ: 10358c2ecf20Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ: 10368c2ecf20Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ: 10378c2ecf20Sopenharmony_ci tsync_rx_ctl |= IXGBE_TSYNCRXCTL_TYPE_EVENT_V2; 10388c2ecf20Sopenharmony_ci is_l2 = true; 10398c2ecf20Sopenharmony_ci config->rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT; 10408c2ecf20Sopenharmony_ci aflags |= (IXGBE_FLAG_RX_HWTSTAMP_ENABLED | 10418c2ecf20Sopenharmony_ci IXGBE_FLAG_RX_HWTSTAMP_IN_REGISTER); 10428c2ecf20Sopenharmony_ci break; 10438c2ecf20Sopenharmony_ci case HWTSTAMP_FILTER_PTP_V1_L4_EVENT: 10448c2ecf20Sopenharmony_ci case HWTSTAMP_FILTER_NTP_ALL: 10458c2ecf20Sopenharmony_ci case HWTSTAMP_FILTER_ALL: 10468c2ecf20Sopenharmony_ci /* The X550 controller is capable of timestamping all packets, 10478c2ecf20Sopenharmony_ci * which allows it to accept any filter. 10488c2ecf20Sopenharmony_ci */ 10498c2ecf20Sopenharmony_ci if (hw->mac.type >= ixgbe_mac_X550) { 10508c2ecf20Sopenharmony_ci tsync_rx_ctl |= IXGBE_TSYNCRXCTL_TYPE_ALL; 10518c2ecf20Sopenharmony_ci config->rx_filter = HWTSTAMP_FILTER_ALL; 10528c2ecf20Sopenharmony_ci aflags |= IXGBE_FLAG_RX_HWTSTAMP_ENABLED; 10538c2ecf20Sopenharmony_ci break; 10548c2ecf20Sopenharmony_ci } 10558c2ecf20Sopenharmony_ci fallthrough; 10568c2ecf20Sopenharmony_ci default: 10578c2ecf20Sopenharmony_ci /* 10588c2ecf20Sopenharmony_ci * register RXMTRL must be set in order to do V1 packets, 10598c2ecf20Sopenharmony_ci * therefore it is not possible to time stamp both V1 Sync and 10608c2ecf20Sopenharmony_ci * Delay_Req messages and hardware does not support 10618c2ecf20Sopenharmony_ci * timestamping all packets => return error 10628c2ecf20Sopenharmony_ci */ 10638c2ecf20Sopenharmony_ci config->rx_filter = HWTSTAMP_FILTER_NONE; 10648c2ecf20Sopenharmony_ci return -ERANGE; 10658c2ecf20Sopenharmony_ci } 10668c2ecf20Sopenharmony_ci 10678c2ecf20Sopenharmony_ci if (hw->mac.type == ixgbe_mac_82598EB) { 10688c2ecf20Sopenharmony_ci adapter->flags &= ~(IXGBE_FLAG_RX_HWTSTAMP_ENABLED | 10698c2ecf20Sopenharmony_ci IXGBE_FLAG_RX_HWTSTAMP_IN_REGISTER); 10708c2ecf20Sopenharmony_ci if (tsync_rx_ctl | tsync_tx_ctl) 10718c2ecf20Sopenharmony_ci return -ERANGE; 10728c2ecf20Sopenharmony_ci return 0; 10738c2ecf20Sopenharmony_ci } 10748c2ecf20Sopenharmony_ci 10758c2ecf20Sopenharmony_ci /* Per-packet timestamping only works if the filter is set to all 10768c2ecf20Sopenharmony_ci * packets. Since this is desired, always timestamp all packets as long 10778c2ecf20Sopenharmony_ci * as any Rx filter was configured. 10788c2ecf20Sopenharmony_ci */ 10798c2ecf20Sopenharmony_ci switch (hw->mac.type) { 10808c2ecf20Sopenharmony_ci case ixgbe_mac_X550: 10818c2ecf20Sopenharmony_ci case ixgbe_mac_X550EM_x: 10828c2ecf20Sopenharmony_ci case ixgbe_mac_x550em_a: 10838c2ecf20Sopenharmony_ci /* enable timestamping all packets only if at least some 10848c2ecf20Sopenharmony_ci * packets were requested. Otherwise, play nice and disable 10858c2ecf20Sopenharmony_ci * timestamping 10868c2ecf20Sopenharmony_ci */ 10878c2ecf20Sopenharmony_ci if (config->rx_filter == HWTSTAMP_FILTER_NONE) 10888c2ecf20Sopenharmony_ci break; 10898c2ecf20Sopenharmony_ci 10908c2ecf20Sopenharmony_ci tsync_rx_ctl = IXGBE_TSYNCRXCTL_ENABLED | 10918c2ecf20Sopenharmony_ci IXGBE_TSYNCRXCTL_TYPE_ALL | 10928c2ecf20Sopenharmony_ci IXGBE_TSYNCRXCTL_TSIP_UT_EN; 10938c2ecf20Sopenharmony_ci config->rx_filter = HWTSTAMP_FILTER_ALL; 10948c2ecf20Sopenharmony_ci aflags |= IXGBE_FLAG_RX_HWTSTAMP_ENABLED; 10958c2ecf20Sopenharmony_ci aflags &= ~IXGBE_FLAG_RX_HWTSTAMP_IN_REGISTER; 10968c2ecf20Sopenharmony_ci is_l2 = true; 10978c2ecf20Sopenharmony_ci break; 10988c2ecf20Sopenharmony_ci default: 10998c2ecf20Sopenharmony_ci break; 11008c2ecf20Sopenharmony_ci } 11018c2ecf20Sopenharmony_ci 11028c2ecf20Sopenharmony_ci /* define ethertype filter for timestamping L2 packets */ 11038c2ecf20Sopenharmony_ci if (is_l2) 11048c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_ETQF(IXGBE_ETQF_FILTER_1588), 11058c2ecf20Sopenharmony_ci (IXGBE_ETQF_FILTER_EN | /* enable filter */ 11068c2ecf20Sopenharmony_ci IXGBE_ETQF_1588 | /* enable timestamping */ 11078c2ecf20Sopenharmony_ci ETH_P_1588)); /* 1588 eth protocol type */ 11088c2ecf20Sopenharmony_ci else 11098c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_ETQF(IXGBE_ETQF_FILTER_1588), 0); 11108c2ecf20Sopenharmony_ci 11118c2ecf20Sopenharmony_ci /* enable/disable TX */ 11128c2ecf20Sopenharmony_ci regval = IXGBE_READ_REG(hw, IXGBE_TSYNCTXCTL); 11138c2ecf20Sopenharmony_ci regval &= ~IXGBE_TSYNCTXCTL_ENABLED; 11148c2ecf20Sopenharmony_ci regval |= tsync_tx_ctl; 11158c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_TSYNCTXCTL, regval); 11168c2ecf20Sopenharmony_ci 11178c2ecf20Sopenharmony_ci /* enable/disable RX */ 11188c2ecf20Sopenharmony_ci regval = IXGBE_READ_REG(hw, IXGBE_TSYNCRXCTL); 11198c2ecf20Sopenharmony_ci regval &= ~(IXGBE_TSYNCRXCTL_ENABLED | IXGBE_TSYNCRXCTL_TYPE_MASK); 11208c2ecf20Sopenharmony_ci regval |= tsync_rx_ctl; 11218c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_TSYNCRXCTL, regval); 11228c2ecf20Sopenharmony_ci 11238c2ecf20Sopenharmony_ci /* define which PTP packets are time stamped */ 11248c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_RXMTRL, tsync_rx_mtrl); 11258c2ecf20Sopenharmony_ci 11268c2ecf20Sopenharmony_ci IXGBE_WRITE_FLUSH(hw); 11278c2ecf20Sopenharmony_ci 11288c2ecf20Sopenharmony_ci /* configure adapter flags only when HW is actually configured */ 11298c2ecf20Sopenharmony_ci adapter->flags = aflags; 11308c2ecf20Sopenharmony_ci 11318c2ecf20Sopenharmony_ci /* clear TX/RX time stamp registers, just to be sure */ 11328c2ecf20Sopenharmony_ci ixgbe_ptp_clear_tx_timestamp(adapter); 11338c2ecf20Sopenharmony_ci IXGBE_READ_REG(hw, IXGBE_RXSTMPH); 11348c2ecf20Sopenharmony_ci 11358c2ecf20Sopenharmony_ci return 0; 11368c2ecf20Sopenharmony_ci} 11378c2ecf20Sopenharmony_ci 11388c2ecf20Sopenharmony_ci/** 11398c2ecf20Sopenharmony_ci * ixgbe_ptp_set_ts_config - user entry point for timestamp mode 11408c2ecf20Sopenharmony_ci * @adapter: pointer to adapter struct 11418c2ecf20Sopenharmony_ci * @ifr: ioctl data 11428c2ecf20Sopenharmony_ci * 11438c2ecf20Sopenharmony_ci * Set hardware to requested mode. If unsupported, return an error with no 11448c2ecf20Sopenharmony_ci * changes. Otherwise, store the mode for future reference. 11458c2ecf20Sopenharmony_ci */ 11468c2ecf20Sopenharmony_ciint ixgbe_ptp_set_ts_config(struct ixgbe_adapter *adapter, struct ifreq *ifr) 11478c2ecf20Sopenharmony_ci{ 11488c2ecf20Sopenharmony_ci struct hwtstamp_config config; 11498c2ecf20Sopenharmony_ci int err; 11508c2ecf20Sopenharmony_ci 11518c2ecf20Sopenharmony_ci if (copy_from_user(&config, ifr->ifr_data, sizeof(config))) 11528c2ecf20Sopenharmony_ci return -EFAULT; 11538c2ecf20Sopenharmony_ci 11548c2ecf20Sopenharmony_ci err = ixgbe_ptp_set_timestamp_mode(adapter, &config); 11558c2ecf20Sopenharmony_ci if (err) 11568c2ecf20Sopenharmony_ci return err; 11578c2ecf20Sopenharmony_ci 11588c2ecf20Sopenharmony_ci /* save these settings for future reference */ 11598c2ecf20Sopenharmony_ci memcpy(&adapter->tstamp_config, &config, 11608c2ecf20Sopenharmony_ci sizeof(adapter->tstamp_config)); 11618c2ecf20Sopenharmony_ci 11628c2ecf20Sopenharmony_ci return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ? 11638c2ecf20Sopenharmony_ci -EFAULT : 0; 11648c2ecf20Sopenharmony_ci} 11658c2ecf20Sopenharmony_ci 11668c2ecf20Sopenharmony_cistatic void ixgbe_ptp_link_speed_adjust(struct ixgbe_adapter *adapter, 11678c2ecf20Sopenharmony_ci u32 *shift, u32 *incval) 11688c2ecf20Sopenharmony_ci{ 11698c2ecf20Sopenharmony_ci /** 11708c2ecf20Sopenharmony_ci * Scale the NIC cycle counter by a large factor so that 11718c2ecf20Sopenharmony_ci * relatively small corrections to the frequency can be added 11728c2ecf20Sopenharmony_ci * or subtracted. The drawbacks of a large factor include 11738c2ecf20Sopenharmony_ci * (a) the clock register overflows more quickly, (b) the cycle 11748c2ecf20Sopenharmony_ci * counter structure must be able to convert the systime value 11758c2ecf20Sopenharmony_ci * to nanoseconds using only a multiplier and a right-shift, 11768c2ecf20Sopenharmony_ci * and (c) the value must fit within the timinca register space 11778c2ecf20Sopenharmony_ci * => math based on internal DMA clock rate and available bits 11788c2ecf20Sopenharmony_ci * 11798c2ecf20Sopenharmony_ci * Note that when there is no link, internal DMA clock is same as when 11808c2ecf20Sopenharmony_ci * link speed is 10Gb. Set the registers correctly even when link is 11818c2ecf20Sopenharmony_ci * down to preserve the clock setting 11828c2ecf20Sopenharmony_ci */ 11838c2ecf20Sopenharmony_ci switch (adapter->link_speed) { 11848c2ecf20Sopenharmony_ci case IXGBE_LINK_SPEED_100_FULL: 11858c2ecf20Sopenharmony_ci *shift = IXGBE_INCVAL_SHIFT_100; 11868c2ecf20Sopenharmony_ci *incval = IXGBE_INCVAL_100; 11878c2ecf20Sopenharmony_ci break; 11888c2ecf20Sopenharmony_ci case IXGBE_LINK_SPEED_1GB_FULL: 11898c2ecf20Sopenharmony_ci *shift = IXGBE_INCVAL_SHIFT_1GB; 11908c2ecf20Sopenharmony_ci *incval = IXGBE_INCVAL_1GB; 11918c2ecf20Sopenharmony_ci break; 11928c2ecf20Sopenharmony_ci case IXGBE_LINK_SPEED_10GB_FULL: 11938c2ecf20Sopenharmony_ci default: 11948c2ecf20Sopenharmony_ci *shift = IXGBE_INCVAL_SHIFT_10GB; 11958c2ecf20Sopenharmony_ci *incval = IXGBE_INCVAL_10GB; 11968c2ecf20Sopenharmony_ci break; 11978c2ecf20Sopenharmony_ci } 11988c2ecf20Sopenharmony_ci} 11998c2ecf20Sopenharmony_ci 12008c2ecf20Sopenharmony_ci/** 12018c2ecf20Sopenharmony_ci * ixgbe_ptp_start_cyclecounter - create the cycle counter from hw 12028c2ecf20Sopenharmony_ci * @adapter: pointer to the adapter structure 12038c2ecf20Sopenharmony_ci * 12048c2ecf20Sopenharmony_ci * This function should be called to set the proper values for the TIMINCA 12058c2ecf20Sopenharmony_ci * register and tell the cyclecounter structure what the tick rate of SYSTIME 12068c2ecf20Sopenharmony_ci * is. It does not directly modify SYSTIME registers or the timecounter 12078c2ecf20Sopenharmony_ci * structure. It should be called whenever a new TIMINCA value is necessary, 12088c2ecf20Sopenharmony_ci * such as during initialization or when the link speed changes. 12098c2ecf20Sopenharmony_ci */ 12108c2ecf20Sopenharmony_civoid ixgbe_ptp_start_cyclecounter(struct ixgbe_adapter *adapter) 12118c2ecf20Sopenharmony_ci{ 12128c2ecf20Sopenharmony_ci struct ixgbe_hw *hw = &adapter->hw; 12138c2ecf20Sopenharmony_ci struct cyclecounter cc; 12148c2ecf20Sopenharmony_ci unsigned long flags; 12158c2ecf20Sopenharmony_ci u32 incval = 0; 12168c2ecf20Sopenharmony_ci u32 fuse0 = 0; 12178c2ecf20Sopenharmony_ci 12188c2ecf20Sopenharmony_ci /* For some of the boards below this mask is technically incorrect. 12198c2ecf20Sopenharmony_ci * The timestamp mask overflows at approximately 61bits. However the 12208c2ecf20Sopenharmony_ci * particular hardware does not overflow on an even bitmask value. 12218c2ecf20Sopenharmony_ci * Instead, it overflows due to conversion of upper 32bits billions of 12228c2ecf20Sopenharmony_ci * cycles. Timecounters are not really intended for this purpose so 12238c2ecf20Sopenharmony_ci * they do not properly function if the overflow point isn't 2^N-1. 12248c2ecf20Sopenharmony_ci * However, the actual SYSTIME values in question take ~138 years to 12258c2ecf20Sopenharmony_ci * overflow. In practice this means they won't actually overflow. A 12268c2ecf20Sopenharmony_ci * proper fix to this problem would require modification of the 12278c2ecf20Sopenharmony_ci * timecounter delta calculations. 12288c2ecf20Sopenharmony_ci */ 12298c2ecf20Sopenharmony_ci cc.mask = CLOCKSOURCE_MASK(64); 12308c2ecf20Sopenharmony_ci cc.mult = 1; 12318c2ecf20Sopenharmony_ci cc.shift = 0; 12328c2ecf20Sopenharmony_ci 12338c2ecf20Sopenharmony_ci switch (hw->mac.type) { 12348c2ecf20Sopenharmony_ci case ixgbe_mac_X550EM_x: 12358c2ecf20Sopenharmony_ci /* SYSTIME assumes X550EM_x board frequency is 300Mhz, and is 12368c2ecf20Sopenharmony_ci * designed to represent seconds and nanoseconds when this is 12378c2ecf20Sopenharmony_ci * the case. However, some revisions of hardware have a 400Mhz 12388c2ecf20Sopenharmony_ci * clock and we have to compensate for this frequency 12398c2ecf20Sopenharmony_ci * variation using corrected mult and shift values. 12408c2ecf20Sopenharmony_ci */ 12418c2ecf20Sopenharmony_ci fuse0 = IXGBE_READ_REG(hw, IXGBE_FUSES0_GROUP(0)); 12428c2ecf20Sopenharmony_ci if (!(fuse0 & IXGBE_FUSES0_300MHZ)) { 12438c2ecf20Sopenharmony_ci cc.mult = 3; 12448c2ecf20Sopenharmony_ci cc.shift = 2; 12458c2ecf20Sopenharmony_ci } 12468c2ecf20Sopenharmony_ci fallthrough; 12478c2ecf20Sopenharmony_ci case ixgbe_mac_x550em_a: 12488c2ecf20Sopenharmony_ci case ixgbe_mac_X550: 12498c2ecf20Sopenharmony_ci cc.read = ixgbe_ptp_read_X550; 12508c2ecf20Sopenharmony_ci break; 12518c2ecf20Sopenharmony_ci case ixgbe_mac_X540: 12528c2ecf20Sopenharmony_ci cc.read = ixgbe_ptp_read_82599; 12538c2ecf20Sopenharmony_ci 12548c2ecf20Sopenharmony_ci ixgbe_ptp_link_speed_adjust(adapter, &cc.shift, &incval); 12558c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_TIMINCA, incval); 12568c2ecf20Sopenharmony_ci break; 12578c2ecf20Sopenharmony_ci case ixgbe_mac_82599EB: 12588c2ecf20Sopenharmony_ci cc.read = ixgbe_ptp_read_82599; 12598c2ecf20Sopenharmony_ci 12608c2ecf20Sopenharmony_ci ixgbe_ptp_link_speed_adjust(adapter, &cc.shift, &incval); 12618c2ecf20Sopenharmony_ci incval >>= IXGBE_INCVAL_SHIFT_82599; 12628c2ecf20Sopenharmony_ci cc.shift -= IXGBE_INCVAL_SHIFT_82599; 12638c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_TIMINCA, 12648c2ecf20Sopenharmony_ci BIT(IXGBE_INCPER_SHIFT_82599) | incval); 12658c2ecf20Sopenharmony_ci break; 12668c2ecf20Sopenharmony_ci default: 12678c2ecf20Sopenharmony_ci /* other devices aren't supported */ 12688c2ecf20Sopenharmony_ci return; 12698c2ecf20Sopenharmony_ci } 12708c2ecf20Sopenharmony_ci 12718c2ecf20Sopenharmony_ci /* update the base incval used to calculate frequency adjustment */ 12728c2ecf20Sopenharmony_ci WRITE_ONCE(adapter->base_incval, incval); 12738c2ecf20Sopenharmony_ci smp_mb(); 12748c2ecf20Sopenharmony_ci 12758c2ecf20Sopenharmony_ci /* need lock to prevent incorrect read while modifying cyclecounter */ 12768c2ecf20Sopenharmony_ci spin_lock_irqsave(&adapter->tmreg_lock, flags); 12778c2ecf20Sopenharmony_ci memcpy(&adapter->hw_cc, &cc, sizeof(adapter->hw_cc)); 12788c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&adapter->tmreg_lock, flags); 12798c2ecf20Sopenharmony_ci} 12808c2ecf20Sopenharmony_ci 12818c2ecf20Sopenharmony_ci/** 12828c2ecf20Sopenharmony_ci * ixgbe_ptp_init_systime - Initialize SYSTIME registers 12838c2ecf20Sopenharmony_ci * @adapter: the ixgbe private board structure 12848c2ecf20Sopenharmony_ci * 12858c2ecf20Sopenharmony_ci * Initialize and start the SYSTIME registers. 12868c2ecf20Sopenharmony_ci */ 12878c2ecf20Sopenharmony_cistatic void ixgbe_ptp_init_systime(struct ixgbe_adapter *adapter) 12888c2ecf20Sopenharmony_ci{ 12898c2ecf20Sopenharmony_ci struct ixgbe_hw *hw = &adapter->hw; 12908c2ecf20Sopenharmony_ci u32 tsauxc; 12918c2ecf20Sopenharmony_ci 12928c2ecf20Sopenharmony_ci switch (hw->mac.type) { 12938c2ecf20Sopenharmony_ci case ixgbe_mac_X550EM_x: 12948c2ecf20Sopenharmony_ci case ixgbe_mac_x550em_a: 12958c2ecf20Sopenharmony_ci case ixgbe_mac_X550: 12968c2ecf20Sopenharmony_ci tsauxc = IXGBE_READ_REG(hw, IXGBE_TSAUXC); 12978c2ecf20Sopenharmony_ci 12988c2ecf20Sopenharmony_ci /* Reset SYSTIME registers to 0 */ 12998c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_SYSTIMR, 0); 13008c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_SYSTIML, 0); 13018c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_SYSTIMH, 0); 13028c2ecf20Sopenharmony_ci 13038c2ecf20Sopenharmony_ci /* Reset interrupt settings */ 13048c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_TSIM, IXGBE_TSIM_TXTS); 13058c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_EIMS, IXGBE_EIMS_TIMESYNC); 13068c2ecf20Sopenharmony_ci 13078c2ecf20Sopenharmony_ci /* Activate the SYSTIME counter */ 13088c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_TSAUXC, 13098c2ecf20Sopenharmony_ci tsauxc & ~IXGBE_TSAUXC_DISABLE_SYSTIME); 13108c2ecf20Sopenharmony_ci break; 13118c2ecf20Sopenharmony_ci case ixgbe_mac_X540: 13128c2ecf20Sopenharmony_ci case ixgbe_mac_82599EB: 13138c2ecf20Sopenharmony_ci /* Reset SYSTIME registers to 0 */ 13148c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_SYSTIML, 0); 13158c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_SYSTIMH, 0); 13168c2ecf20Sopenharmony_ci break; 13178c2ecf20Sopenharmony_ci default: 13188c2ecf20Sopenharmony_ci /* Other devices aren't supported */ 13198c2ecf20Sopenharmony_ci return; 13208c2ecf20Sopenharmony_ci }; 13218c2ecf20Sopenharmony_ci 13228c2ecf20Sopenharmony_ci IXGBE_WRITE_FLUSH(hw); 13238c2ecf20Sopenharmony_ci} 13248c2ecf20Sopenharmony_ci 13258c2ecf20Sopenharmony_ci/** 13268c2ecf20Sopenharmony_ci * ixgbe_ptp_reset 13278c2ecf20Sopenharmony_ci * @adapter: the ixgbe private board structure 13288c2ecf20Sopenharmony_ci * 13298c2ecf20Sopenharmony_ci * When the MAC resets, all the hardware bits for timesync are reset. This 13308c2ecf20Sopenharmony_ci * function is used to re-enable the device for PTP based on current settings. 13318c2ecf20Sopenharmony_ci * We do lose the current clock time, so just reset the cyclecounter to the 13328c2ecf20Sopenharmony_ci * system real clock time. 13338c2ecf20Sopenharmony_ci * 13348c2ecf20Sopenharmony_ci * This function will maintain hwtstamp_config settings, and resets the SDP 13358c2ecf20Sopenharmony_ci * output if it was enabled. 13368c2ecf20Sopenharmony_ci */ 13378c2ecf20Sopenharmony_civoid ixgbe_ptp_reset(struct ixgbe_adapter *adapter) 13388c2ecf20Sopenharmony_ci{ 13398c2ecf20Sopenharmony_ci struct ixgbe_hw *hw = &adapter->hw; 13408c2ecf20Sopenharmony_ci unsigned long flags; 13418c2ecf20Sopenharmony_ci 13428c2ecf20Sopenharmony_ci /* reset the hardware timestamping mode */ 13438c2ecf20Sopenharmony_ci ixgbe_ptp_set_timestamp_mode(adapter, &adapter->tstamp_config); 13448c2ecf20Sopenharmony_ci 13458c2ecf20Sopenharmony_ci /* 82598 does not support PTP */ 13468c2ecf20Sopenharmony_ci if (hw->mac.type == ixgbe_mac_82598EB) 13478c2ecf20Sopenharmony_ci return; 13488c2ecf20Sopenharmony_ci 13498c2ecf20Sopenharmony_ci ixgbe_ptp_start_cyclecounter(adapter); 13508c2ecf20Sopenharmony_ci 13518c2ecf20Sopenharmony_ci ixgbe_ptp_init_systime(adapter); 13528c2ecf20Sopenharmony_ci 13538c2ecf20Sopenharmony_ci spin_lock_irqsave(&adapter->tmreg_lock, flags); 13548c2ecf20Sopenharmony_ci timecounter_init(&adapter->hw_tc, &adapter->hw_cc, 13558c2ecf20Sopenharmony_ci ktime_to_ns(ktime_get_real())); 13568c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&adapter->tmreg_lock, flags); 13578c2ecf20Sopenharmony_ci 13588c2ecf20Sopenharmony_ci adapter->last_overflow_check = jiffies; 13598c2ecf20Sopenharmony_ci 13608c2ecf20Sopenharmony_ci /* Now that the shift has been calculated and the systime 13618c2ecf20Sopenharmony_ci * registers reset, (re-)enable the Clock out feature 13628c2ecf20Sopenharmony_ci */ 13638c2ecf20Sopenharmony_ci if (adapter->ptp_setup_sdp) 13648c2ecf20Sopenharmony_ci adapter->ptp_setup_sdp(adapter); 13658c2ecf20Sopenharmony_ci} 13668c2ecf20Sopenharmony_ci 13678c2ecf20Sopenharmony_ci/** 13688c2ecf20Sopenharmony_ci * ixgbe_ptp_create_clock 13698c2ecf20Sopenharmony_ci * @adapter: the ixgbe private adapter structure 13708c2ecf20Sopenharmony_ci * 13718c2ecf20Sopenharmony_ci * This function performs setup of the user entry point function table and 13728c2ecf20Sopenharmony_ci * initializes the PTP clock device, which is used to access the clock-like 13738c2ecf20Sopenharmony_ci * features of the PTP core. It will be called by ixgbe_ptp_init, and may 13748c2ecf20Sopenharmony_ci * reuse a previously initialized clock (such as during a suspend/resume 13758c2ecf20Sopenharmony_ci * cycle). 13768c2ecf20Sopenharmony_ci */ 13778c2ecf20Sopenharmony_cistatic long ixgbe_ptp_create_clock(struct ixgbe_adapter *adapter) 13788c2ecf20Sopenharmony_ci{ 13798c2ecf20Sopenharmony_ci struct net_device *netdev = adapter->netdev; 13808c2ecf20Sopenharmony_ci long err; 13818c2ecf20Sopenharmony_ci 13828c2ecf20Sopenharmony_ci /* do nothing if we already have a clock device */ 13838c2ecf20Sopenharmony_ci if (!IS_ERR_OR_NULL(adapter->ptp_clock)) 13848c2ecf20Sopenharmony_ci return 0; 13858c2ecf20Sopenharmony_ci 13868c2ecf20Sopenharmony_ci switch (adapter->hw.mac.type) { 13878c2ecf20Sopenharmony_ci case ixgbe_mac_X540: 13888c2ecf20Sopenharmony_ci snprintf(adapter->ptp_caps.name, 13898c2ecf20Sopenharmony_ci sizeof(adapter->ptp_caps.name), 13908c2ecf20Sopenharmony_ci "%s", netdev->name); 13918c2ecf20Sopenharmony_ci adapter->ptp_caps.owner = THIS_MODULE; 13928c2ecf20Sopenharmony_ci adapter->ptp_caps.max_adj = 250000000; 13938c2ecf20Sopenharmony_ci adapter->ptp_caps.n_alarm = 0; 13948c2ecf20Sopenharmony_ci adapter->ptp_caps.n_ext_ts = 0; 13958c2ecf20Sopenharmony_ci adapter->ptp_caps.n_per_out = 0; 13968c2ecf20Sopenharmony_ci adapter->ptp_caps.pps = 1; 13978c2ecf20Sopenharmony_ci adapter->ptp_caps.adjfreq = ixgbe_ptp_adjfreq_82599; 13988c2ecf20Sopenharmony_ci adapter->ptp_caps.adjtime = ixgbe_ptp_adjtime; 13998c2ecf20Sopenharmony_ci adapter->ptp_caps.gettimex64 = ixgbe_ptp_gettimex; 14008c2ecf20Sopenharmony_ci adapter->ptp_caps.settime64 = ixgbe_ptp_settime; 14018c2ecf20Sopenharmony_ci adapter->ptp_caps.enable = ixgbe_ptp_feature_enable; 14028c2ecf20Sopenharmony_ci adapter->ptp_setup_sdp = ixgbe_ptp_setup_sdp_X540; 14038c2ecf20Sopenharmony_ci break; 14048c2ecf20Sopenharmony_ci case ixgbe_mac_82599EB: 14058c2ecf20Sopenharmony_ci snprintf(adapter->ptp_caps.name, 14068c2ecf20Sopenharmony_ci sizeof(adapter->ptp_caps.name), 14078c2ecf20Sopenharmony_ci "%s", netdev->name); 14088c2ecf20Sopenharmony_ci adapter->ptp_caps.owner = THIS_MODULE; 14098c2ecf20Sopenharmony_ci adapter->ptp_caps.max_adj = 250000000; 14108c2ecf20Sopenharmony_ci adapter->ptp_caps.n_alarm = 0; 14118c2ecf20Sopenharmony_ci adapter->ptp_caps.n_ext_ts = 0; 14128c2ecf20Sopenharmony_ci adapter->ptp_caps.n_per_out = 0; 14138c2ecf20Sopenharmony_ci adapter->ptp_caps.pps = 0; 14148c2ecf20Sopenharmony_ci adapter->ptp_caps.adjfreq = ixgbe_ptp_adjfreq_82599; 14158c2ecf20Sopenharmony_ci adapter->ptp_caps.adjtime = ixgbe_ptp_adjtime; 14168c2ecf20Sopenharmony_ci adapter->ptp_caps.gettimex64 = ixgbe_ptp_gettimex; 14178c2ecf20Sopenharmony_ci adapter->ptp_caps.settime64 = ixgbe_ptp_settime; 14188c2ecf20Sopenharmony_ci adapter->ptp_caps.enable = ixgbe_ptp_feature_enable; 14198c2ecf20Sopenharmony_ci break; 14208c2ecf20Sopenharmony_ci case ixgbe_mac_X550: 14218c2ecf20Sopenharmony_ci case ixgbe_mac_X550EM_x: 14228c2ecf20Sopenharmony_ci case ixgbe_mac_x550em_a: 14238c2ecf20Sopenharmony_ci snprintf(adapter->ptp_caps.name, 16, "%s", netdev->name); 14248c2ecf20Sopenharmony_ci adapter->ptp_caps.owner = THIS_MODULE; 14258c2ecf20Sopenharmony_ci adapter->ptp_caps.max_adj = 30000000; 14268c2ecf20Sopenharmony_ci adapter->ptp_caps.n_alarm = 0; 14278c2ecf20Sopenharmony_ci adapter->ptp_caps.n_ext_ts = 0; 14288c2ecf20Sopenharmony_ci adapter->ptp_caps.n_per_out = 0; 14298c2ecf20Sopenharmony_ci adapter->ptp_caps.pps = 1; 14308c2ecf20Sopenharmony_ci adapter->ptp_caps.adjfreq = ixgbe_ptp_adjfreq_X550; 14318c2ecf20Sopenharmony_ci adapter->ptp_caps.adjtime = ixgbe_ptp_adjtime; 14328c2ecf20Sopenharmony_ci adapter->ptp_caps.gettimex64 = ixgbe_ptp_gettimex; 14338c2ecf20Sopenharmony_ci adapter->ptp_caps.settime64 = ixgbe_ptp_settime; 14348c2ecf20Sopenharmony_ci adapter->ptp_caps.enable = ixgbe_ptp_feature_enable; 14358c2ecf20Sopenharmony_ci adapter->ptp_setup_sdp = ixgbe_ptp_setup_sdp_X550; 14368c2ecf20Sopenharmony_ci break; 14378c2ecf20Sopenharmony_ci default: 14388c2ecf20Sopenharmony_ci adapter->ptp_clock = NULL; 14398c2ecf20Sopenharmony_ci adapter->ptp_setup_sdp = NULL; 14408c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 14418c2ecf20Sopenharmony_ci } 14428c2ecf20Sopenharmony_ci 14438c2ecf20Sopenharmony_ci adapter->ptp_clock = ptp_clock_register(&adapter->ptp_caps, 14448c2ecf20Sopenharmony_ci &adapter->pdev->dev); 14458c2ecf20Sopenharmony_ci if (IS_ERR(adapter->ptp_clock)) { 14468c2ecf20Sopenharmony_ci err = PTR_ERR(adapter->ptp_clock); 14478c2ecf20Sopenharmony_ci adapter->ptp_clock = NULL; 14488c2ecf20Sopenharmony_ci e_dev_err("ptp_clock_register failed\n"); 14498c2ecf20Sopenharmony_ci return err; 14508c2ecf20Sopenharmony_ci } else if (adapter->ptp_clock) 14518c2ecf20Sopenharmony_ci e_dev_info("registered PHC device on %s\n", netdev->name); 14528c2ecf20Sopenharmony_ci 14538c2ecf20Sopenharmony_ci /* set default timestamp mode to disabled here. We do this in 14548c2ecf20Sopenharmony_ci * create_clock instead of init, because we don't want to override the 14558c2ecf20Sopenharmony_ci * previous settings during a resume cycle. 14568c2ecf20Sopenharmony_ci */ 14578c2ecf20Sopenharmony_ci adapter->tstamp_config.rx_filter = HWTSTAMP_FILTER_NONE; 14588c2ecf20Sopenharmony_ci adapter->tstamp_config.tx_type = HWTSTAMP_TX_OFF; 14598c2ecf20Sopenharmony_ci 14608c2ecf20Sopenharmony_ci return 0; 14618c2ecf20Sopenharmony_ci} 14628c2ecf20Sopenharmony_ci 14638c2ecf20Sopenharmony_ci/** 14648c2ecf20Sopenharmony_ci * ixgbe_ptp_init 14658c2ecf20Sopenharmony_ci * @adapter: the ixgbe private adapter structure 14668c2ecf20Sopenharmony_ci * 14678c2ecf20Sopenharmony_ci * This function performs the required steps for enabling PTP 14688c2ecf20Sopenharmony_ci * support. If PTP support has already been loaded it simply calls the 14698c2ecf20Sopenharmony_ci * cyclecounter init routine and exits. 14708c2ecf20Sopenharmony_ci */ 14718c2ecf20Sopenharmony_civoid ixgbe_ptp_init(struct ixgbe_adapter *adapter) 14728c2ecf20Sopenharmony_ci{ 14738c2ecf20Sopenharmony_ci /* initialize the spin lock first since we can't control when a user 14748c2ecf20Sopenharmony_ci * will call the entry functions once we have initialized the clock 14758c2ecf20Sopenharmony_ci * device 14768c2ecf20Sopenharmony_ci */ 14778c2ecf20Sopenharmony_ci spin_lock_init(&adapter->tmreg_lock); 14788c2ecf20Sopenharmony_ci 14798c2ecf20Sopenharmony_ci /* obtain a PTP device, or re-use an existing device */ 14808c2ecf20Sopenharmony_ci if (ixgbe_ptp_create_clock(adapter)) 14818c2ecf20Sopenharmony_ci return; 14828c2ecf20Sopenharmony_ci 14838c2ecf20Sopenharmony_ci /* we have a clock so we can initialize work now */ 14848c2ecf20Sopenharmony_ci INIT_WORK(&adapter->ptp_tx_work, ixgbe_ptp_tx_hwtstamp_work); 14858c2ecf20Sopenharmony_ci 14868c2ecf20Sopenharmony_ci /* reset the PTP related hardware bits */ 14878c2ecf20Sopenharmony_ci ixgbe_ptp_reset(adapter); 14888c2ecf20Sopenharmony_ci 14898c2ecf20Sopenharmony_ci /* enter the IXGBE_PTP_RUNNING state */ 14908c2ecf20Sopenharmony_ci set_bit(__IXGBE_PTP_RUNNING, &adapter->state); 14918c2ecf20Sopenharmony_ci 14928c2ecf20Sopenharmony_ci return; 14938c2ecf20Sopenharmony_ci} 14948c2ecf20Sopenharmony_ci 14958c2ecf20Sopenharmony_ci/** 14968c2ecf20Sopenharmony_ci * ixgbe_ptp_suspend - stop PTP work items 14978c2ecf20Sopenharmony_ci * @adapter: pointer to adapter struct 14988c2ecf20Sopenharmony_ci * 14998c2ecf20Sopenharmony_ci * this function suspends PTP activity, and prevents more PTP work from being 15008c2ecf20Sopenharmony_ci * generated, but does not destroy the PTP clock device. 15018c2ecf20Sopenharmony_ci */ 15028c2ecf20Sopenharmony_civoid ixgbe_ptp_suspend(struct ixgbe_adapter *adapter) 15038c2ecf20Sopenharmony_ci{ 15048c2ecf20Sopenharmony_ci /* Leave the IXGBE_PTP_RUNNING state. */ 15058c2ecf20Sopenharmony_ci if (!test_and_clear_bit(__IXGBE_PTP_RUNNING, &adapter->state)) 15068c2ecf20Sopenharmony_ci return; 15078c2ecf20Sopenharmony_ci 15088c2ecf20Sopenharmony_ci adapter->flags2 &= ~IXGBE_FLAG2_PTP_PPS_ENABLED; 15098c2ecf20Sopenharmony_ci if (adapter->ptp_setup_sdp) 15108c2ecf20Sopenharmony_ci adapter->ptp_setup_sdp(adapter); 15118c2ecf20Sopenharmony_ci 15128c2ecf20Sopenharmony_ci /* ensure that we cancel any pending PTP Tx work item in progress */ 15138c2ecf20Sopenharmony_ci cancel_work_sync(&adapter->ptp_tx_work); 15148c2ecf20Sopenharmony_ci ixgbe_ptp_clear_tx_timestamp(adapter); 15158c2ecf20Sopenharmony_ci} 15168c2ecf20Sopenharmony_ci 15178c2ecf20Sopenharmony_ci/** 15188c2ecf20Sopenharmony_ci * ixgbe_ptp_stop - close the PTP device 15198c2ecf20Sopenharmony_ci * @adapter: pointer to adapter struct 15208c2ecf20Sopenharmony_ci * 15218c2ecf20Sopenharmony_ci * completely destroy the PTP device, should only be called when the device is 15228c2ecf20Sopenharmony_ci * being fully closed. 15238c2ecf20Sopenharmony_ci */ 15248c2ecf20Sopenharmony_civoid ixgbe_ptp_stop(struct ixgbe_adapter *adapter) 15258c2ecf20Sopenharmony_ci{ 15268c2ecf20Sopenharmony_ci /* first, suspend PTP activity */ 15278c2ecf20Sopenharmony_ci ixgbe_ptp_suspend(adapter); 15288c2ecf20Sopenharmony_ci 15298c2ecf20Sopenharmony_ci /* disable the PTP clock device */ 15308c2ecf20Sopenharmony_ci if (adapter->ptp_clock) { 15318c2ecf20Sopenharmony_ci ptp_clock_unregister(adapter->ptp_clock); 15328c2ecf20Sopenharmony_ci adapter->ptp_clock = NULL; 15338c2ecf20Sopenharmony_ci e_dev_info("removed PHC on %s\n", 15348c2ecf20Sopenharmony_ci adapter->netdev->name); 15358c2ecf20Sopenharmony_ci } 15368c2ecf20Sopenharmony_ci} 1537