Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753309AbbHVBxY (ORCPT ); Fri, 21 Aug 2015 21:53:24 -0400 Received: from mga01.intel.com ([192.55.52.88]:46598 "EHLO mga01.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752940AbbHVBww (ORCPT ); Fri, 21 Aug 2015 21:52:52 -0400 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.15,726,1432623600"; d="scan'208";a="753236167" From: "Christopher S. Hall" To: jeffrey.t.kirsher@intel.com, hpa@zytor.com, mingo@redhat.com, tglx@linutronix.de, john.stultz@linaro.org Cc: richardcochran@gmail.com, x86@kernel.org, linux-kernel@vger.kernel.org, netdev@vger.kernel.org, intel-wired-lan@lists.osuosl.org, peterz@infradead.org, Christopher Hall Subject: [PATCH v3 4/4] Enabling hardware supported PTP system/device crosstimestamping Date: Fri, 21 Aug 2015 11:52:08 -0700 Message-Id: <1440183128-1384-5-git-send-email-christopher.s.hall@intel.com> X-Mailer: git-send-email 2.1.4 In-Reply-To: <1440183128-1384-1-git-send-email-christopher.s.hall@intel.com> References: <1440183128-1384-1-git-send-email-christopher.s.hall@intel.com> Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 6125 Lines: 176 From: Christopher Hall Add getsynctime() PTP device callback to cross timestamp system device clock using ART translation depends on platform being >= SPT and having ART getsynctime() reads ART (TSC-derived)/device cross timestamp and converts to realtime/device time reporting cross timestamp to PTP driver Signed-off-by: Christopher S. Hall --- drivers/net/ethernet/intel/e1000e/defines.h | 5 ++ drivers/net/ethernet/intel/e1000e/ptp.c | 88 +++++++++++++++++++++++++++++ drivers/net/ethernet/intel/e1000e/regs.h | 4 ++ 3 files changed, 97 insertions(+) diff --git a/drivers/net/ethernet/intel/e1000e/defines.h b/drivers/net/ethernet/intel/e1000e/defines.h index 133d407..13cff75 100644 --- a/drivers/net/ethernet/intel/e1000e/defines.h +++ b/drivers/net/ethernet/intel/e1000e/defines.h @@ -527,6 +527,11 @@ #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..228f3f3 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 +#include /** * e1000e_phc_adjfreq - adjust the frequency of the hardware clock @@ -98,6 +100,87 @@ static int e1000e_phc_adjtime(struct ptp_clock_info *ptp, s64 delta) return 0; } +#define MAX_HW_WAIT_COUNT (3) + +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; + u32 tsync_ctrl; + int ret; + + tsync_ctrl = er32(TSYNCTXCTL); + tsync_ctrl |= E1000_TSYNCTXCTL_START_SYNC | + E1000_TSYNCTXCTL_MAX_ALLOWED_DLY_MASK; + ew32(TSYNCTXCTL, tsync_ctrl); + for (i = 0; i < MAX_HW_WAIT_COUNT; ++i) { + udelay(1); + tsync_ctrl = er32(TSYNCTXCTL); + if (tsync_ctrl & E1000_TSYNCTXCTL_SYNC_COMP) + break; + } + + if (i == MAX_HW_WAIT_COUNT) { + ret = -ETIMEDOUT; + } else { + 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); + } + + return ret; +} + +/** + * e1000e_phc_getsynctime - Reads the current time from the hardware clock and + * correlated system time + * @ptp: ptp clock structure + * @devts: timespec structure to hold the current device time value + * @systs: timespec structure to hold the current system time value + * + * Read device and system (ART) clock simultaneously and return the correct + * clock values in ns after converting into a struct timespec. + **/ +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 ret; + + 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) + goto bail; + + 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; + +bail: + return ret; +} + /** * e1000e_phc_gettime - Reads the current time from the hardware clock * @ptp: ptp clock structure @@ -190,6 +273,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, }; @@ -236,6 +320,10 @@ void e1000e_ptp_init(struct e1000_adapter *adapter) break; } + /* CPU must have ART and GBe must be from Sunrise Point or greater */ + if (hw->mac.type < e1000_pch_spt || !cpu_has_art) + adapter->ptp_clock_info.getsynctime64 = NULL; + INIT_DELAYED_WORK(&adapter->systim_overflow_work, e1000e_systim_overflow_work); 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 */ -- 2.1.4 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/