Re: [PATCH v3 4/4] Enabling hardware supported PTP system/device crosstimestamping
On Fri, 21 Aug 2015, Christopher S. Hall wrote: > 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 See patch 1/4 > 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 The usual way to order includes is: #include #include #include "e1000.h" > +/** > + * 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(_correlated_ts, > +_timestamper); Pointless line break > + if (ret != 0) > + goto bail; What's the purpose of this goto? if (ret) return ret; is completely sufficient. > + > + systs->tv_sec = > + div_u64_rem(art_correlated_ts.system_real.tv64, > + NSEC_PER_SEC, ); > + systs->tv_nsec = remainder; ktime_to_timespec64() perhaps? And please move that conversion to the ptp ioctl > + spin_lock_irqsave(>systim_lock, flags); > + device_time = timecounter_cyc2time(>tc, > +art_correlated_ts.device_ts); > + /* 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; We do it the other way round. We leave the default NULL and update it if we detect the feature. Thanks, tglx -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH v3 4/4] Enabling hardware supported PTP system/device crosstimestamping
On Fri, 21 Aug 2015, Christopher S. Hall wrote: From: Christopher Hall christopher.s.h...@intel.com 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 See patch 1/4 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 asm/tsc.h +#include linux/timekeeping.h The usual way to order includes is: #include linux/timekeeping.h #include asm/tsc.h #include e1000.h +/** + * 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); Pointless line break + if (ret != 0) + goto bail; What's the purpose of this goto? if (ret) return ret; is completely sufficient. + + systs-tv_sec = + div_u64_rem(art_correlated_ts.system_real.tv64, + NSEC_PER_SEC, remainder); + systs-tv_nsec = remainder; ktime_to_timespec64() perhaps? And please move that conversion to the ptp ioctl + spin_lock_irqsave(adapter-systim_lock, flags); + device_time = timecounter_cyc2time(adapter-tc, +art_correlated_ts.device_ts); + /* 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; We do it the other way round. We leave the default NULL and update it if we detect the feature. Thanks, tglx -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH v3 4/4] Enabling hardware supported PTP system/device crosstimestamping
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 0x2000/* Receive config */ #define E1000_RXCW_SYNCH 0x4000/* Receive config synch */ +/* HH Time Sync */ +#define E1000_TSYNCTXCTL_MAX_ALLOWED_DLY_MASK 0xF000 /* max delay */ +#define E1000_TSYNCTXCTL_SYNC_COMP 0x4000 /* sync complete */ +#define E1000_TSYNCTXCTL_START_SYNC0x8000 /* initiate sync */ + #define E1000_TSYNCTXCTL_VALID 0x0001 /* Tx timestamp valid */ #define E1000_TSYNCTXCTL_ENABLED 0x0010 /* 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 = >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(_correlated_ts, + _timestamper); + if (ret != 0) + goto bail; + + systs->tv_sec = + div_u64_rem(art_correlated_ts.system_real.tv64, + NSEC_PER_SEC, ); + systs->tv_nsec = remainder; + spin_lock_irqsave(>systim_lock, flags); + device_time = timecounter_cyc2time(>tc, + art_correlated_ts.device_ts); + spin_unlock_irqrestore(>systim_lock, flags); + devts->tv_sec = + div_u64_rem(device_time, NSEC_PER_SEC, ); + 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,
[PATCH v3 4/4] Enabling hardware supported PTP system/device crosstimestamping
From: Christopher Hall christopher.s.h...@intel.com 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 christopher.s.h...@intel.com --- 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 0x2000/* Receive config */ #define E1000_RXCW_SYNCH 0x4000/* Receive config synch */ +/* HH Time Sync */ +#define E1000_TSYNCTXCTL_MAX_ALLOWED_DLY_MASK 0xF000 /* max delay */ +#define E1000_TSYNCTXCTL_SYNC_COMP 0x4000 /* sync complete */ +#define E1000_TSYNCTXCTL_START_SYNC0x8000 /* initiate sync */ + #define E1000_TSYNCTXCTL_VALID 0x0001 /* Tx timestamp valid */ #define E1000_TSYNCTXCTL_ENABLED 0x0010 /* 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 asm/tsc.h +#include linux/timekeeping.h /** * 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