Reads ART (TSC correlated clocksource), converts to realtime clock, and reports cross timestamp to PTP driver --- drivers/net/ethernet/intel/e1000e/defines.h | 7 +++ drivers/net/ethernet/intel/e1000e/ptp.c | 88 +++++++++++++++++++++++++++++ drivers/net/ethernet/intel/e1000e/regs.h | 4 ++ 3 files changed, 99 insertions(+)
diff --git a/drivers/net/ethernet/intel/e1000e/defines.h b/drivers/net/ethernet/intel/e1000e/defines.h index 133d407..9f16269 100644 --- a/drivers/net/ethernet/intel/e1000e/defines.h +++ b/drivers/net/ethernet/intel/e1000e/defines.h @@ -527,6 +527,13 @@ #define E1000_RXCW_C 0x20000000 /* Receive config */ #define E1000_RXCW_SYNCH 0x40000000 /* Receive config synch */ +/* HH Time Sync */ +#define E1000_TSYNCTXCTL_MAX_ALLOWED_DLY_MASK 0x0000F000 /* max delay */ +#define E1000_TSYNCTXCTL_SYNC_COMP 0x40000000 /* sync complete + */ +#define E1000_TSYNCTXCTL_START_SYNC 0x80000000 /* initiate sync + */ + #define E1000_TSYNCTXCTL_VALID 0x00000001 /* Tx timestamp valid */ #define E1000_TSYNCTXCTL_ENABLED 0x00000010 /* enable Tx timestamping */ diff --git a/drivers/net/ethernet/intel/e1000e/ptp.c b/drivers/net/ethernet/intel/e1000e/ptp.c index 25a0ad5..c3d80c4 100644 --- a/drivers/net/ethernet/intel/e1000e/ptp.c +++ b/drivers/net/ethernet/intel/e1000e/ptp.c @@ -25,6 +25,8 @@ */ #include "e1000.h" +#include <asm/tsc.h> +#include <linux/timekeeping.h> /** * e1000e_phc_adjfreq - adjust the frequency of the hardware clock @@ -98,6 +100,91 @@ static int e1000e_phc_adjtime(struct ptp_clock_info *ptp, s64 delta) return 0; } +#define HW_WAIT_COUNT (2) +#define HW_RETRY_COUNT (2) + +static int e1000e_phc_get_ts(struct correlated_ts *cts) +{ + struct e1000_adapter *adapter = (struct e1000_adapter *) cts->private; + struct e1000_hw *hw = &adapter->hw; + int i, j; + u32 tsync_ctrl; + int ret; + + if (hw->mac.type < e1000_pch_spt) + return -EOPNOTSUPP; + + for (j = 0; j < HW_RETRY_COUNT; ++j) { + tsync_ctrl = er32(TSYNCTXCTL); + tsync_ctrl |= E1000_TSYNCTXCTL_START_SYNC | + E1000_TSYNCTXCTL_MAX_ALLOWED_DLY_MASK; + ew32(TSYNCTXCTL, tsync_ctrl); + ret = 0; + for (i = 0; i < HW_WAIT_COUNT; ++i) { + udelay(2); + tsync_ctrl = er32(TSYNCTXCTL); + if (tsync_ctrl & E1000_TSYNCTXCTL_SYNC_COMP) + break; + } + + if (i == HW_WAIT_COUNT) { + ret = -ETIMEDOUT; + } else if (ret == 0) { + cts->system_ts = er32(PLTSTMPH); + cts->system_ts <<= 32; + cts->system_ts |= er32(PLTSTMPL); + cts->device_ts = er32(SYSSTMPH); + cts->device_ts <<= 32; + cts->device_ts |= er32(SYSSTMPL); + break; + } + } + + return ret; +} + +#define SYNCTIME_RETRY_COUNT (2) + +static int e1000e_phc_getsynctime(struct ptp_clock_info *ptp, + struct timespec64 *devts, + struct timespec64 *systs) +{ + struct e1000_adapter *adapter = container_of(ptp, struct e1000_adapter, + ptp_clock_info); + unsigned long flags; + u32 remainder; + struct correlated_ts art_correlated_ts; + u64 device_time; + int i, ret; + + if (!cpu_has_art) + return -EOPNOTSUPP; + + for (i = 0; i < SYNCTIME_RETRY_COUNT; ++i) { + art_correlated_ts.get_ts = e1000e_phc_get_ts; + art_correlated_ts.private = adapter; + ret = get_correlated_timestamp(&art_correlated_ts, + &art_timestamper); + if (ret != 0) + continue; + + systs->tv_sec = + div_u64_rem(art_correlated_ts.system_real.tv64, + NSEC_PER_SEC, &remainder); + systs->tv_nsec = remainder; + spin_lock_irqsave(&adapter->systim_lock, flags); + device_time = timecounter_cyc2time(&adapter->tc, + art_correlated_ts.device_ts); + spin_unlock_irqrestore(&adapter->systim_lock, flags); + devts->tv_sec = + div_u64_rem(device_time, NSEC_PER_SEC, &remainder); + devts->tv_nsec = remainder; + break; + } + + return ret; +} + /** * e1000e_phc_gettime - Reads the current time from the hardware clock * @ptp: ptp clock structure @@ -190,6 +277,7 @@ static const struct ptp_clock_info e1000e_ptp_clock_info = { .adjfreq = e1000e_phc_adjfreq, .adjtime = e1000e_phc_adjtime, .gettime64 = e1000e_phc_gettime, + .getsynctime64 = e1000e_phc_getsynctime, .settime64 = e1000e_phc_settime, .enable = e1000e_phc_enable, }; diff --git a/drivers/net/ethernet/intel/e1000e/regs.h b/drivers/net/ethernet/intel/e1000e/regs.h index b24e5fe..4dd5b54 100644 --- a/drivers/net/ethernet/intel/e1000e/regs.h +++ b/drivers/net/ethernet/intel/e1000e/regs.h @@ -246,6 +246,10 @@ #define E1000_SYSTIML 0x0B600 /* System time register Low - RO */ #define E1000_SYSTIMH 0x0B604 /* System time register High - RO */ #define E1000_TIMINCA 0x0B608 /* Increment attributes register - RW */ +#define E1000_SYSSTMPL 0x0B648 /* HH Timesync system stamp low register */ +#define E1000_SYSSTMPH 0x0B64C /* HH Timesync system stamp hi register */ +#define E1000_PLTSTMPL 0x0B640 /* HH Timesync platform stamp low register */ +#define E1000_PLTSTMPH 0x0B644 /* HH Timesync platform stamp hi register */ #define E1000_RXMTRL 0x0B634 /* Time sync Rx EtherType and Msg Type - RW */ #define E1000_RXUDP 0x0B638 /* Time Sync Rx UDP Port - RW */ -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html