[PATCH v2] net/i40e: add IEEE1588 handling to AVX vector paths
Bruce Richardson
bruce.richardson at intel.com
Mon Oct 19 17:53:01 CEST 2026
The IEEE1588 timesync support was only supported on the scalar RX paths,
but is, in a number of ways, quite similar to how FDIR support works: we
read and process values from the various per-packet flags and then do a
single store to the mbuf. Add support for IEEE1588 to the AVX2 and
AVX-512 vector functions inline in the main descriptor processing loop,
as well as the appropriate one-line fix for the case of scattered
packets.
Suggested-by: Anurag Mandal <anurag.mandal at intel.com>
Signed-off-by: Bruce Richardson <bruce.richardson at intel.com>
---
drivers/net/intel/common/rx.h | 3 +
drivers/net/intel/i40e/i40e_rxtx_vec_avx2.c | 59 ++++++++++++++++++
drivers/net/intel/i40e/i40e_rxtx_vec_avx512.c | 61 +++++++++++++++++++
drivers/net/intel/i40e/i40e_rxtx_vec_common.h | 12 ++--
4 files changed, 131 insertions(+), 4 deletions(-)
diff --git a/drivers/net/intel/common/rx.h b/drivers/net/intel/common/rx.h
index e0bf520ebd..8f4454d477 100644
--- a/drivers/net/intel/common/rx.h
+++ b/drivers/net/intel/common/rx.h
@@ -167,6 +167,9 @@ ci_rx_reassemble_packets(struct rte_mbuf **rx_bufs, uint16_t nb_bufs, uint8_t *s
start->hash = end->hash;
start->vlan_tci = end->vlan_tci;
start->ol_flags = end->ol_flags;
+#ifdef RTE_LIBRTE_IEEE1588
+ start->timesync = end->timesync;
+#endif
/* we need to strip crc for the whole packet */
start->pkt_len -= crc_len;
if (end->data_len > crc_len) {
diff --git a/drivers/net/intel/i40e/i40e_rxtx_vec_avx2.c b/drivers/net/intel/i40e/i40e_rxtx_vec_avx2.c
index dd06e258ad..652a915db2 100644
--- a/drivers/net/intel/i40e/i40e_rxtx_vec_avx2.c
+++ b/drivers/net/intel/i40e/i40e_rxtx_vec_avx2.c
@@ -494,6 +494,65 @@ _recv_raw_pkts_vec_avx2(struct ci_rx_queue *rxq, struct rte_mbuf **rx_pkts,
} /* if() on FDIR enabled */
+#ifdef RTE_LIBRTE_IEEE1588
+ /* The TSYNVALID and TSYNINDX bits are already present in
+ * status0_7, so the PTP timestamp flags can be built with
+ * no extra descriptor reads, the same way the RSS/FDIR flags
+ * are above. Only the 2-bit timestamp register index has to
+ * land in a specific mbuf field, so it still needs a
+ * per-packet store, done the same way as the FDIR ID above.
+ */
+ const __m256i tsyn_valid_mask = _mm256_set1_epi32(
+ 1 << I40E_RXD_QW1_STATUS_TSYNVALID_SHIFT);
+ const __m256i tsyn_valid = _mm256_cmpeq_epi32(
+ _mm256_and_si256(status0_7, tsyn_valid_mask),
+ tsyn_valid_mask);
+ const __m256i tmst_flags = _mm256_and_si256(tsyn_valid,
+ _mm256_set1_epi32(RTE_MBUF_F_RX_IEEE1588_TMST));
+ mbuf_flags = _mm256_or_si256(mbuf_flags, tmst_flags);
+
+ /* zero the index unless TSYNVALID is set, to match the
+ * scalar driver, which only ever assigns tsyn & 0x03
+ */
+ const __m256i tsyn_indx = _mm256_and_si256(tsyn_valid,
+ _mm256_srli_epi32(_mm256_and_si256(status0_7,
+ _mm256_set1_epi32(0x3 << I40E_RXD_QW1_STATUS_TSYNINDX_SHIFT)),
+ I40E_RXD_QW1_STATUS_TSYNINDX_SHIFT));
+
+ /* status0_7 packet order is (hi->lo): [1, 3, 5, 7, 0, 2, 4, 6] */
+ rx_pkts[i + 1]->timesync = _mm256_extract_epi32(tsyn_indx, 7);
+ rx_pkts[i + 3]->timesync = _mm256_extract_epi32(tsyn_indx, 6);
+ rx_pkts[i + 5]->timesync = _mm256_extract_epi32(tsyn_indx, 5);
+ rx_pkts[i + 7]->timesync = _mm256_extract_epi32(tsyn_indx, 4);
+ rx_pkts[i + 0]->timesync = _mm256_extract_epi32(tsyn_indx, 3);
+ rx_pkts[i + 2]->timesync = _mm256_extract_epi32(tsyn_indx, 2);
+ rx_pkts[i + 4]->timesync = _mm256_extract_epi32(tsyn_indx, 1);
+ rx_pkts[i + 6]->timesync = _mm256_extract_epi32(tsyn_indx, 0);
+
+ /* the PTP flag only depends on packet_type, which was already
+ * looked up above for each packet, so again no extra reads
+ * are needed to build it
+ */
+ const __m256i ptp_flags = _mm256_set_epi32(
+ (ptype_tbl[ptype1] & RTE_PTYPE_L2_MASK) == RTE_PTYPE_L2_ETHER_TIMESYNC ?
+ RTE_MBUF_F_RX_IEEE1588_PTP : 0,
+ (ptype_tbl[ptype3] & RTE_PTYPE_L2_MASK) == RTE_PTYPE_L2_ETHER_TIMESYNC ?
+ RTE_MBUF_F_RX_IEEE1588_PTP : 0,
+ (ptype_tbl[ptype5] & RTE_PTYPE_L2_MASK) == RTE_PTYPE_L2_ETHER_TIMESYNC ?
+ RTE_MBUF_F_RX_IEEE1588_PTP : 0,
+ (ptype_tbl[ptype7] & RTE_PTYPE_L2_MASK) == RTE_PTYPE_L2_ETHER_TIMESYNC ?
+ RTE_MBUF_F_RX_IEEE1588_PTP : 0,
+ (ptype_tbl[ptype0] & RTE_PTYPE_L2_MASK) == RTE_PTYPE_L2_ETHER_TIMESYNC ?
+ RTE_MBUF_F_RX_IEEE1588_PTP : 0,
+ (ptype_tbl[ptype2] & RTE_PTYPE_L2_MASK) == RTE_PTYPE_L2_ETHER_TIMESYNC ?
+ RTE_MBUF_F_RX_IEEE1588_PTP : 0,
+ (ptype_tbl[ptype4] & RTE_PTYPE_L2_MASK) == RTE_PTYPE_L2_ETHER_TIMESYNC ?
+ RTE_MBUF_F_RX_IEEE1588_PTP : 0,
+ (ptype_tbl[ptype6] & RTE_PTYPE_L2_MASK) == RTE_PTYPE_L2_ETHER_TIMESYNC ?
+ RTE_MBUF_F_RX_IEEE1588_PTP : 0);
+ mbuf_flags = _mm256_or_si256(mbuf_flags, ptp_flags);
+#endif /* RTE_LIBRTE_IEEE1588 */
+
/*
* At this point, we have the 8 sets of flags in the low 16-bits
* of each 32-bit value in vlan0.
diff --git a/drivers/net/intel/i40e/i40e_rxtx_vec_avx512.c b/drivers/net/intel/i40e/i40e_rxtx_vec_avx512.c
index ea2e6dc024..f96e965914 100644
--- a/drivers/net/intel/i40e/i40e_rxtx_vec_avx512.c
+++ b/drivers/net/intel/i40e/i40e_rxtx_vec_avx512.c
@@ -543,6 +543,67 @@ _recv_raw_pkts_vec_avx512(struct ci_rx_queue *rxq, struct rte_mbuf **rx_pkts,
} /* if() on FDIR enabled */
+#ifdef RTE_LIBRTE_IEEE1588
+ /* The TSYNVALID and TSYNINDX bits are already present in
+ * status0_7, so the PTP timestamp flags can be built with
+ * no extra descriptor reads, the same way the RSS/FDIR flags
+ * are above. Only the 2-bit timestamp register index has to
+ * land in a specific mbuf field, so it still needs a
+ * per-packet store, done the same way as the FDIR ID above.
+ */
+ const __m256i tsyn_valid_mask = _mm256_set1_epi32(
+ 1 << I40E_RXD_QW1_STATUS_TSYNVALID_SHIFT);
+ const __m256i tsyn_valid = _mm256_cmpeq_epi32(
+ _mm256_and_si256(status0_7, tsyn_valid_mask),
+ tsyn_valid_mask);
+ const __m256i tmst_flags = _mm256_and_si256(tsyn_valid,
+ _mm256_set1_epi32(RTE_MBUF_F_RX_IEEE1588_TMST));
+
+ mbuf_flags = _mm256_or_si256(mbuf_flags, tmst_flags);
+
+ /* zero the index unless TSYNVALID is set, to match the
+ * scalar driver, which only ever assigns tsyn & 0x03
+ */
+ const __m256i tsyn_indx = _mm256_and_si256(tsyn_valid,
+ _mm256_srli_epi32(_mm256_and_si256(status0_7,
+ _mm256_set1_epi32(0x3 << I40E_RXD_QW1_STATUS_TSYNINDX_SHIFT)),
+ I40E_RXD_QW1_STATUS_TSYNINDX_SHIFT));
+
+ /* status0_7 packet order is (hi->lo): [1, 3, 5, 7, 0, 2, 4, 6] */
+ rx_pkts[i + 1]->timesync = _mm256_extract_epi32(tsyn_indx, 7);
+ rx_pkts[i + 3]->timesync = _mm256_extract_epi32(tsyn_indx, 6);
+ rx_pkts[i + 5]->timesync = _mm256_extract_epi32(tsyn_indx, 5);
+ rx_pkts[i + 7]->timesync = _mm256_extract_epi32(tsyn_indx, 4);
+ rx_pkts[i + 0]->timesync = _mm256_extract_epi32(tsyn_indx, 3);
+ rx_pkts[i + 2]->timesync = _mm256_extract_epi32(tsyn_indx, 2);
+ rx_pkts[i + 4]->timesync = _mm256_extract_epi32(tsyn_indx, 1);
+ rx_pkts[i + 6]->timesync = _mm256_extract_epi32(tsyn_indx, 0);
+
+ /* the PTP flag only depends on packet_type, which was already
+ * looked up above for each packet, so again no extra reads
+ * are needed to build it
+ */
+ const __m256i ptp_flags = _mm256_set_epi32(
+ (ptype_tbl[ptype1] & RTE_PTYPE_L2_MASK) == RTE_PTYPE_L2_ETHER_TIMESYNC ?
+ RTE_MBUF_F_RX_IEEE1588_PTP : 0,
+ (ptype_tbl[ptype3] & RTE_PTYPE_L2_MASK) == RTE_PTYPE_L2_ETHER_TIMESYNC ?
+ RTE_MBUF_F_RX_IEEE1588_PTP : 0,
+ (ptype_tbl[ptype5] & RTE_PTYPE_L2_MASK) == RTE_PTYPE_L2_ETHER_TIMESYNC ?
+ RTE_MBUF_F_RX_IEEE1588_PTP : 0,
+ (ptype_tbl[ptype7] & RTE_PTYPE_L2_MASK) == RTE_PTYPE_L2_ETHER_TIMESYNC ?
+ RTE_MBUF_F_RX_IEEE1588_PTP : 0,
+ (ptype_tbl[ptype0] & RTE_PTYPE_L2_MASK) == RTE_PTYPE_L2_ETHER_TIMESYNC ?
+ RTE_MBUF_F_RX_IEEE1588_PTP : 0,
+ (ptype_tbl[ptype2] & RTE_PTYPE_L2_MASK) == RTE_PTYPE_L2_ETHER_TIMESYNC ?
+ RTE_MBUF_F_RX_IEEE1588_PTP : 0,
+ (ptype_tbl[ptype4] & RTE_PTYPE_L2_MASK) == RTE_PTYPE_L2_ETHER_TIMESYNC ?
+ RTE_MBUF_F_RX_IEEE1588_PTP : 0,
+ (ptype_tbl[ptype6] & RTE_PTYPE_L2_MASK) == RTE_PTYPE_L2_ETHER_TIMESYNC ?
+ RTE_MBUF_F_RX_IEEE1588_PTP : 0);
+
+ mbuf_flags = _mm256_or_si256(mbuf_flags, ptp_flags);
+#endif /* RTE_LIBRTE_IEEE1588 */
+
/* At this point, we have the 8 sets of flags in the low 16-bits
* of each 32-bit value in vlan0.
* We want to extract these, and merge them with the mbuf init data
diff --git a/drivers/net/intel/i40e/i40e_rxtx_vec_common.h b/drivers/net/intel/i40e/i40e_rxtx_vec_common.h
index 292a39501e..521e206438 100644
--- a/drivers/net/intel/i40e/i40e_rxtx_vec_common.h
+++ b/drivers/net/intel/i40e/i40e_rxtx_vec_common.h
@@ -53,7 +53,14 @@ _i40e_rx_queue_release_mbufs_vec(struct ci_rx_queue *rxq)
static inline int
i40e_rx_vec_dev_conf_condition_check_default(struct rte_eth_dev *dev)
{
-#ifndef RTE_LIBRTE_IEEE1588
+#if defined(RTE_LIBRTE_IEEE1588) && !defined(RTE_ARCH_X86)
+ /* Only the AVX2/AVX512 Rx paths propagate the IEEE1588 PTP flags and
+ * the hardware timestamp register index, so other architectures
+ * still have to fall back to the scalar Rx path.
+ */
+ RTE_SET_USED(dev);
+ return -1;
+#else
/**
* Vector mode is allowed only when number of Rx queue
* descriptor is power of 2.
@@ -67,9 +74,6 @@ i40e_rx_vec_dev_conf_condition_check_default(struct rte_eth_dev *dev)
}
return 0;
-#else
- RTE_SET_USED(dev);
- return -1;
#endif
}
--
2.53.0
More information about the dev
mailing list