diff options
author | Jacob Keller <jacob.e.keller@intel.com> | 2021-06-09 09:39:52 -0700 |
---|---|---|
committer | Tony Nguyen <anthony.l.nguyen@intel.com> | 2021-06-11 08:47:41 -0700 |
commit | 77a781155a659053f3b7e81a0ab115d27ff151cd (patch) | |
tree | de1317d2004afd0db0f0a1215449e2c781294486 /drivers/net/ethernet/intel/ice/ice_ptp.h | |
parent | 67569a7f940130fcfe9041e07a614a5263a9944d (diff) |
ice: enable receive hardware timestamping
Add SIOCGHWTSTAMP and SIOCSHWTSTAMP ioctl handlers to respond to
requests to enable timestamping support. If the request is for enabling
Rx timestamps, set a bit in the Rx descriptors to indicate that receive
timestamps should be reported.
Hardware captures receive timestamps in the PHY which only captures part
of the timer, and reports only 40 bits into the Rx descriptor. The upper
32 bits represent the contents of GLTSYN_TIME_L at the point of packet
reception, while the lower 8 bits represent the upper 8 bits of
GLTSYN_TIME_0.
The networking and PTP stack expect 64 bit timestamps in nanoseconds. To
support this, implement some logic to extend the timestamps by using the
full PHC time.
If the Rx timestamp was captured prior to the PHC time, then the real
timestamp is
PHC - (lower_32_bits(PHC) - timestamp)
If the Rx timestamp was captured after the PHC time, then the real
timestamp is
PHC + (timestamp - lower_32_bits(PHC))
These calculations are correct as long as neither the PHC timestamp nor
the Rx timestamps are more than 2^32-1 nanseconds old. Further, we can
detect when the Rx timestamp is before or after the PHC as long as the
PHC timestamp is no more than 2^31-1 nanoseconds old.
In that case, we calculate the delta between the lower 32 bits of the
PHC and the Rx timestamp. If it's larger than 2^31-1 then the Rx
timestamp must have been captured in the past. If it's smaller, then the
Rx timestamp must have been captured after PHC time.
Add an ice_ptp_extend_32b_ts function that relies on a cached copy of
the PHC time and implements this algorithm to calculate the proper upper
32bits of the Rx timestamps.
Cache the PHC time periodically in all of the Rx rings. This enables
each Rx ring to simply call the extension function with a recent copy of
the PHC time. By ensuring that the PHC time is kept up to date
periodically, we ensure this algorithm doesn't use stale data and
produce incorrect results.
To cache the time, introduce a kworker and a kwork item to periodically
store the Rx time. It might seem like we should use the .do_aux_work
interface of the PTP clock. This doesn't work because all PFs must cache
this time, but only one PF owns the PTP clock device.
Thus, the ice driver will manage its own kthread instead of relying on
the PTP do_aux_work handler.
With this change, the driver can now report Rx timestamps on all
incoming packets.
Signed-off-by: Jacob Keller <jacob.e.keller@intel.com>
Tested-by: Tony Brelinski <tonyx.brelinski@intel.com>
Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
Diffstat (limited to 'drivers/net/ethernet/intel/ice/ice_ptp.h')
-rw-r--r-- | drivers/net/ethernet/intel/ice/ice_ptp.h | 29 |
1 files changed, 29 insertions, 0 deletions
diff --git a/drivers/net/ethernet/intel/ice/ice_ptp.h b/drivers/net/ethernet/intel/ice/ice_ptp.h index 01f7db05ef7d..48850391ab28 100644 --- a/drivers/net/ethernet/intel/ice/ice_ptp.h +++ b/drivers/net/ethernet/intel/ice/ice_ptp.h @@ -5,17 +5,26 @@ #define _ICE_PTP_H_ #include <linux/ptp_clock_kernel.h> +#include <linux/kthread.h> #include "ice_ptp_hw.h" /** * struct ice_ptp - data used for integrating with CONFIG_PTP_1588_CLOCK + * @work: delayed work function for periodic tasks + * @cached_phc_time: a cached copy of the PHC time for timestamp extension + * @kworker: kwork thread for handling periodic work * @info: structure defining PTP hardware capabilities * @clock: pointer to registered PTP clock device + * @tstamp_config: hardware timestamping configuration */ struct ice_ptp { + struct kthread_delayed_work work; + u64 cached_phc_time; + struct kthread_worker *kworker; struct ptp_clock_info info; struct ptp_clock *clock; + struct hwtstamp_config tstamp_config; }; #define __ptp_info_to_ptp(i) \ @@ -24,17 +33,37 @@ struct ice_ptp { container_of(__ptp_info_to_ptp((i)), struct ice_pf, ptp) #define PTP_SHARED_CLK_IDX_VALID BIT(31) +#define ICE_PTP_TS_VALID BIT(0) #if IS_ENABLED(CONFIG_PTP_1588_CLOCK) struct ice_pf; +int ice_ptp_set_ts_config(struct ice_pf *pf, struct ifreq *ifr); +int ice_ptp_get_ts_config(struct ice_pf *pf, struct ifreq *ifr); int ice_get_ptp_clock_index(struct ice_pf *pf); +void +ice_ptp_rx_hwtstamp(struct ice_ring *rx_ring, + union ice_32b_rx_flex_desc *rx_desc, struct sk_buff *skb); void ice_ptp_init(struct ice_pf *pf); void ice_ptp_release(struct ice_pf *pf); #else /* IS_ENABLED(CONFIG_PTP_1588_CLOCK) */ +static inline int ice_ptp_set_ts_config(struct ice_pf *pf, struct ifreq *ifr) +{ + return -EOPNOTSUPP; +} + +static inline int ice_ptp_get_ts_config(struct ice_pf *pf, struct ifreq *ifr) +{ + return -EOPNOTSUPP; +} + static inline int ice_get_ptp_clock_index(struct ice_pf *pf) { return -1; } + +static inline void +ice_ptp_rx_hwtstamp(struct ice_ring *rx_ring, + union ice_32b_rx_flex_desc *rx_desc, struct sk_buff *skb) { } static inline void ice_ptp_init(struct ice_pf *pf) { } static inline void ice_ptp_release(struct ice_pf *pf) { } #endif /* IS_ENABLED(CONFIG_PTP_1588_CLOCK) */ |