Skip to content

Commit c666832

Browse files
committed
iavf: add support for Rx timestamps to hotpath
JIRA: https://issues.redhat.com/browse/RHEL-83568 commit 48ccdcd Author: Jacob Keller <jacob.e.keller@intel.com> Date: Wed Nov 6 12:37:31 2024 -0500 iavf: add support for Rx timestamps to hotpath Add support for receive timestamps to the Rx hotpath. This support only works when using the flexible descriptor format, so make sure that we request this format by default if we have receive timestamp support available in the PTP capabilities. In order to report the timestamps to userspace, we need to perform timestamp extension. The Rx descriptor does actually contain the "40 bit" timestamp. However, upper 32 bits which contain nanoseconds are conveniently stored separately in the descriptor. We could extract the 32bits and lower 8 bits, then perform a bitwise OR to calculate the 40bit value. This makes no sense, because the timestamp extension algorithm would simply discard the lower 8 bits anyways. Thus, implement timestamp extension as iavf_ptp_extend_32b_timestamp(), and extract and forward only the 32bits of nominal nanoseconds. Signed-off-by: Jacob Keller <jacob.e.keller@intel.com> Reviewed-by: Rahul Rameshbabu <rrameshbabu@nvidia.com> Reviewed-by: Sunil Goutham <sgoutham@marvell.com> Reviewed-by: Simon Horman <horms@kernel.org> Tested-by: Rafal Romanowski <rafal.romanowski@intel.com> Signed-off-by: Mateusz Polchlopek <mateusz.polchlopek@intel.com> Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com> Signed-off-by: Michal Schmidt <mschmidt@redhat.com>
1 parent 736611f commit c666832

File tree

5 files changed

+125
-0
lines changed

5 files changed

+125
-0
lines changed

drivers/net/ethernet/intel/iavf/iavf_main.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -730,6 +730,15 @@ static u8 iavf_select_rx_desc_format(const struct iavf_adapter *adapter)
730730
if (!IAVF_RXDID_ALLOWED(adapter))
731731
return VIRTCHNL_RXDID_1_32B_BASE;
732732

733+
/* Rx timestamping requires the use of flexible NIC descriptors */
734+
if (iavf_ptp_cap_supported(adapter, VIRTCHNL_1588_PTP_CAP_RX_TSTAMP)) {
735+
if (rxdids & BIT(VIRTCHNL_RXDID_2_FLEX_SQ_NIC))
736+
return VIRTCHNL_RXDID_2_FLEX_SQ_NIC;
737+
738+
pci_warn(adapter->pdev,
739+
"Unable to negotiate flexible descriptor format\n");
740+
}
741+
733742
/* Warn if the PF does not list support for the default legacy
734743
* descriptor format. This shouldn't happen, as this is the format
735744
* used if VIRTCHNL_VF_OFFLOAD_RX_FLEX_DESC is not supported. It is

drivers/net/ethernet/intel/iavf/iavf_ptp.c

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,9 @@ void iavf_ptp_release(struct iavf_adapter *adapter)
394394
}
395395
adapter->aq_required &= ~IAVF_FLAG_AQ_SEND_PTP_CMD;
396396
mutex_unlock(&adapter->ptp.aq_cmd_lock);
397+
398+
adapter->ptp.hwtstamp_config.rx_filter = HWTSTAMP_FILTER_NONE;
399+
iavf_ptp_disable_rx_tstamp(adapter);
397400
}
398401

399402
/**
@@ -422,3 +425,61 @@ void iavf_ptp_process_caps(struct iavf_adapter *adapter)
422425
iavf_ptp_disable_rx_tstamp(adapter);
423426
}
424427
}
428+
429+
/**
430+
* iavf_ptp_extend_32b_timestamp - Convert a 32b nanoseconds timestamp to 64b
431+
* nanoseconds
432+
* @cached_phc_time: recently cached copy of PHC time
433+
* @in_tstamp: Ingress/egress 32b nanoseconds timestamp value
434+
*
435+
* Hardware captures timestamps which contain only 32 bits of nominal
436+
* nanoseconds, as opposed to the 64bit timestamps that the stack expects.
437+
*
438+
* Extend the 32bit nanosecond timestamp using the following algorithm and
439+
* assumptions:
440+
*
441+
* 1) have a recently cached copy of the PHC time
442+
* 2) assume that the in_tstamp was captured 2^31 nanoseconds (~2.1
443+
* seconds) before or after the PHC time was captured.
444+
* 3) calculate the delta between the cached time and the timestamp
445+
* 4) if the delta is smaller than 2^31 nanoseconds, then the timestamp was
446+
* captured after the PHC time. In this case, the full timestamp is just
447+
* the cached PHC time plus the delta.
448+
* 5) otherwise, if the delta is larger than 2^31 nanoseconds, then the
449+
* timestamp was captured *before* the PHC time, i.e. because the PHC
450+
* cache was updated after the timestamp was captured by hardware. In this
451+
* case, the full timestamp is the cached time minus the inverse delta.
452+
*
453+
* This algorithm works even if the PHC time was updated after a Tx timestamp
454+
* was requested, but before the Tx timestamp event was reported from
455+
* hardware.
456+
*
457+
* This calculation primarily relies on keeping the cached PHC time up to
458+
* date. If the timestamp was captured more than 2^31 nanoseconds after the
459+
* PHC time, it is possible that the lower 32bits of PHC time have
460+
* overflowed more than once, and we might generate an incorrect timestamp.
461+
*
462+
* This is prevented by (a) periodically updating the cached PHC time once
463+
* a second, and (b) discarding any Tx timestamp packet if it has waited for
464+
* a timestamp for more than one second.
465+
*
466+
* Return: extended timestamp (to 64b).
467+
*/
468+
u64 iavf_ptp_extend_32b_timestamp(u64 cached_phc_time, u32 in_tstamp)
469+
{
470+
u32 low = lower_32_bits(cached_phc_time);
471+
u32 delta = in_tstamp - low;
472+
u64 ns;
473+
474+
/* Do not assume that the in_tstamp is always more recent than the
475+
* cached PHC time. If the delta is large, it indicates that the
476+
* in_tstamp was taken in the past, and should be converted
477+
* forward.
478+
*/
479+
if (delta > S32_MAX)
480+
ns = cached_phc_time - (low - in_tstamp);
481+
else
482+
ns = cached_phc_time + delta;
483+
484+
return ns;
485+
}

drivers/net/ethernet/intel/iavf/iavf_ptp.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66

77
#include "iavf_types.h"
88

9+
/* bit indicating whether a 40bit timestamp is valid */
10+
#define IAVF_PTP_40B_TSTAMP_VALID BIT(24)
11+
912
#if IS_ENABLED(CONFIG_PTP_1588_CLOCK)
1013
void iavf_ptp_init(struct iavf_adapter *adapter);
1114
void iavf_ptp_release(struct iavf_adapter *adapter);
@@ -15,6 +18,7 @@ void iavf_virtchnl_send_ptp_cmd(struct iavf_adapter *adapter);
1518
int iavf_ptp_set_ts_config(struct iavf_adapter *adapter,
1619
struct kernel_hwtstamp_config *config,
1720
struct netlink_ext_ack *extack);
21+
u64 iavf_ptp_extend_32b_timestamp(u64 cached_phc_time, u32 in_tstamp);
1822
#else /* IS_ENABLED(CONFIG_PTP_1588_CLOCK) */
1923
static inline void iavf_ptp_init(struct iavf_adapter *adapter) { }
2024
static inline void iavf_ptp_release(struct iavf_adapter *adapter) { }
@@ -32,5 +36,12 @@ static inline int iavf_ptp_set_ts_config(struct iavf_adapter *adapter,
3236
{
3337
return -1;
3438
}
39+
40+
static inline u64 iavf_ptp_extend_32b_timestamp(u64 cached_phc_time,
41+
u32 in_tstamp)
42+
{
43+
return 0;
44+
}
45+
3546
#endif /* IS_ENABLED(CONFIG_PTP_1588_CLOCK) */
3647
#endif /* _IAVF_PTP_H_ */

drivers/net/ethernet/intel/iavf/iavf_txrx.c

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include "iavf.h"
99
#include "iavf_trace.h"
1010
#include "iavf_prototype.h"
11+
#include "iavf_ptp.h"
1112

1213
/**
1314
* iavf_is_descriptor_done - tests DD bit in Rx descriptor
@@ -1076,6 +1077,45 @@ static void iavf_flex_rx_hash(const struct iavf_ring *ring, __le64 qw1,
10761077
}
10771078
}
10781079

1080+
/**
1081+
* iavf_flex_rx_tstamp - Capture Rx timestamp from the descriptor
1082+
* @rx_ring: descriptor ring
1083+
* @qw2: quad word 2 of descriptor
1084+
* @qw3: quad word 3 of descriptor
1085+
* @skb: skb currently being received
1086+
*
1087+
* Read the Rx timestamp value from the descriptor and pass it to the stack.
1088+
*
1089+
* This function only operates on the VIRTCHNL_RXDID_2_FLEX_SQ_NIC flexible
1090+
* descriptor writeback format.
1091+
*/
1092+
static void iavf_flex_rx_tstamp(const struct iavf_ring *rx_ring, __le64 qw2,
1093+
__le64 qw3, struct sk_buff *skb)
1094+
{
1095+
u32 tstamp;
1096+
u64 ns;
1097+
1098+
/* Skip processing if timestamps aren't enabled */
1099+
if (!(rx_ring->flags & IAVF_TXRX_FLAGS_HW_TSTAMP))
1100+
return;
1101+
1102+
/* Check if this Rx descriptor has a valid timestamp */
1103+
if (!le64_get_bits(qw2, IAVF_PTP_40B_TSTAMP_VALID))
1104+
return;
1105+
1106+
/* the ts_low field only contains the valid bit and sub-nanosecond
1107+
* precision, so we don't need to extract it.
1108+
*/
1109+
tstamp = le64_get_bits(qw3, IAVF_RXD_FLEX_QW3_TSTAMP_HIGH_M);
1110+
1111+
ns = iavf_ptp_extend_32b_timestamp(rx_ring->ptp->cached_phc_time,
1112+
tstamp);
1113+
1114+
*skb_hwtstamps(skb) = (struct skb_shared_hwtstamps) {
1115+
.hwtstamp = ns_to_ktime(ns),
1116+
};
1117+
}
1118+
10791119
/**
10801120
* iavf_process_skb_fields - Populate skb header fields from Rx descriptor
10811121
* @rx_ring: rx descriptor ring packet is being transacted on
@@ -1097,11 +1137,14 @@ static void iavf_process_skb_fields(const struct iavf_ring *rx_ring,
10971137
struct libeth_rx_pt decoded_pt;
10981138
__le64 qw0 = rx_desc->qw0;
10991139
__le64 qw1 = rx_desc->qw1;
1140+
__le64 qw2 = rx_desc->qw2;
1141+
__le64 qw3 = rx_desc->qw3;
11001142

11011143
decoded_pt = libie_rx_pt_parse(ptype);
11021144

11031145
if (flex) {
11041146
iavf_flex_rx_hash(rx_ring, qw1, skb, decoded_pt);
1147+
iavf_flex_rx_tstamp(rx_ring, qw2, qw3, skb);
11051148
csum_bits = iavf_flex_rx_csum(rx_ring->vsi, le64_to_cpu(qw1),
11061149
decoded_pt);
11071150
} else {

drivers/net/ethernet/intel/iavf/iavf_type.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,7 @@ struct iavf_rx_desc {
285285
/* L2 Tag 2 Presence */
286286
#define IAVF_RXD_FLEX_L2TAG2P_M BIT(11)
287287
aligned_le64 qw3;
288+
#define IAVF_RXD_FLEX_QW3_TSTAMP_HIGH_M GENMASK_ULL(63, 32)
288289
} __aligned(4 * sizeof(__le64));
289290
static_assert(sizeof(struct iavf_rx_desc) == 32);
290291

0 commit comments

Comments
 (0)