* [PATCH 0/4] net/ice: support outer checksum in vector Tx
@ 2026-08-24 10:21 Anurag Mandal
2026-08-24 10:21 ` [PATCH 1/4] net/common: share Tx context descriptor flag Anurag Mandal
` (4 more replies)
0 siblings, 5 replies; 15+ messages in thread
From: Anurag Mandal @ 2026-08-24 10:21 UTC (permalink / raw)
To: dev; +Cc: bruce.richardson, anatoly.burakov, Anurag Mandal
Added AVX2 and AVX-512 context descriptor Tx paths
for outer IPv4 and UDP checksum offloads,
avoiding scalar Tx fallback.
Anurag Mandal (4):
net/common: share Tx context descriptor flag
net/ice: add vector tunnel context encoding
net/ice: add AVX2 context descriptor Tx path
net/ice: add AVX-512 context descriptor Tx path
doc/guides/rel_notes/release_26_11.rst | 6 +
drivers/net/intel/common/tx.h | 2 +-
drivers/net/intel/ice/ice_dcf_ethdev.c | 4 +-
drivers/net/intel/ice/ice_ethdev.h | 2 +
drivers/net/intel/ice/ice_rxtx.c | 41 +++++-
drivers/net/intel/ice/ice_rxtx.h | 11 ++
drivers/net/intel/ice/ice_rxtx_vec_avx2.c | 119 +++++++++++++++++
drivers/net/intel/ice/ice_rxtx_vec_avx512.c | 141 ++++++++++++++++++++
drivers/net/intel/ice/ice_rxtx_vec_common.h | 53 +++++++-
9 files changed, 371 insertions(+), 8 deletions(-)
--
2.34.1
^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH 1/4] net/common: share Tx context descriptor flag
2026-08-24 10:21 [PATCH 0/4] net/ice: support outer checksum in vector Tx Anurag Mandal
@ 2026-08-24 10:21 ` Anurag Mandal
2026-08-24 10:21 ` [PATCH 2/4] net/ice: add vector tunnel context encoding Anurag Mandal
` (3 subsequent siblings)
4 siblings, 0 replies; 15+ messages in thread
From: Anurag Mandal @ 2026-08-24 10:21 UTC (permalink / raw)
To: dev; +Cc: bruce.richardson, anatoly.burakov, Anurag Mandal
Moved context descriptor state to the common
Tx queue for reuse by ice.
Signed-off-by: Anurag Mandal <anurag.mandal@intel.com>
---
drivers/net/intel/common/tx.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/intel/common/tx.h b/drivers/net/intel/common/tx.h
index 55757d34d7..61ad041065 100644
--- a/drivers/net/intel/common/tx.h
+++ b/drivers/net/intel/common/tx.h
@@ -175,6 +175,7 @@ struct ci_tx_queue {
bool tx_deferred_start; /* don't start this queue in dev start */
bool q_set; /* indicate if tx queue has been configured */
bool use_vec_entry; /* use sw_ring_vec (true for vector and simple paths) */
+ bool use_ctx; /* each packet uses a context and data descriptor */
union { /* the VSI this queue belongs to */
struct i40e_vsi *i40e_vsi;
struct iavf_vsi *iavf_vsi;
@@ -196,7 +197,6 @@ struct ci_tx_queue {
#define IAVF_TX_FLAGS_VLAN_TAG_LOC_L2TAG2 BIT(1)
uint8_t vlan_flag;
uint8_t tc;
- bool use_ctx; /* with ctx info, each pkt needs two descriptors */
bool lldp_enabled;
};
struct { /* ixgbe specific values */
--
2.34.1
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 2/4] net/ice: add vector tunnel context encoding
2026-08-24 10:21 [PATCH 0/4] net/ice: support outer checksum in vector Tx Anurag Mandal
2026-08-24 10:21 ` [PATCH 1/4] net/common: share Tx context descriptor flag Anurag Mandal
@ 2026-08-24 10:21 ` Anurag Mandal
2026-08-24 14:37 ` Bruce Richardson
2026-08-24 14:51 ` David Marchand
2026-08-24 10:21 ` [PATCH 3/4] net/ice: add AVX2 context descriptor Tx path Anurag Mandal
` (2 subsequent siblings)
4 siblings, 2 replies; 15+ messages in thread
From: Anurag Mandal @ 2026-08-24 10:21 UTC (permalink / raw)
To: dev; +Cc: bruce.richardson, anatoly.burakov, Anurag Mandal
Added helpers to encode tunnel context descriptors,
and checksum offsets.
Signed-off-by: Anurag Mandal <anurag.mandal@intel.com>
---
drivers/net/intel/ice/ice_rxtx_vec_common.h | 53 ++++++++++++++++++++-
1 file changed, 51 insertions(+), 2 deletions(-)
diff --git a/drivers/net/intel/ice/ice_rxtx_vec_common.h b/drivers/net/intel/ice/ice_rxtx_vec_common.h
index 1d83a087cc..b84456357f 100644
--- a/drivers/net/intel/ice/ice_rxtx_vec_common.h
+++ b/drivers/net/intel/ice/ice_rxtx_vec_common.h
@@ -123,8 +123,12 @@ ice_txd_enable_offload(struct rte_mbuf *tx_pkt,
/* Tx Checksum Offload */
/* SET MACLEN */
- td_offset |= (tx_pkt->l2_len >> 1) <<
- CI_TX_DESC_LEN_MACLEN_S;
+ if (ol_flags & RTE_MBUF_F_TX_TUNNEL_MASK)
+ td_offset |= (tx_pkt->outer_l2_len >> 1) <<
+ CI_TX_DESC_LEN_MACLEN_S;
+ else
+ td_offset |= (tx_pkt->l2_len >> 1) <<
+ CI_TX_DESC_LEN_MACLEN_S;
/* Enable L3 checksum offload */
if (ol_flags & RTE_MBUF_F_TX_IP_CKSUM) {
@@ -172,4 +176,49 @@ ice_txd_enable_offload(struct rte_mbuf *tx_pkt,
*txd_hi |= ((uint64_t)td_cmd) << CI_TXD_QW1_CMD_S;
}
+
+static inline uint64_t
+ice_txd_tunneling_ctx(const struct rte_mbuf *tx_pkt)
+{
+ const uint64_t ol_flags = tx_pkt->ol_flags;
+ uint64_t ctx = 0;
+
+ if (!(ol_flags & RTE_MBUF_F_TX_TUNNEL_MASK))
+ return 0;
+
+ if (ol_flags & RTE_MBUF_F_TX_OUTER_IP_CKSUM)
+ ctx |= ICE_TX_CTX_EIPT_IPV4;
+ else if (ol_flags & RTE_MBUF_F_TX_OUTER_IPV4)
+ ctx |= ICE_TX_CTX_EIPT_IPV4_NO_CSUM;
+ else if (ol_flags & RTE_MBUF_F_TX_OUTER_IPV6)
+ ctx |= ICE_TX_CTX_EIPT_IPV6;
+
+ ctx |= (uint64_t)(tx_pkt->outer_l3_len >> 2) << ICE_TXD_CTX_QW0_EIPLEN_S;
+
+ switch (ol_flags & RTE_MBUF_F_TX_TUNNEL_MASK) {
+ case RTE_MBUF_F_TX_TUNNEL_IPIP:
+ break;
+ case RTE_MBUF_F_TX_TUNNEL_VXLAN:
+ case RTE_MBUF_F_TX_TUNNEL_VXLAN_GPE:
+ case RTE_MBUF_F_TX_TUNNEL_GTP:
+ case RTE_MBUF_F_TX_TUNNEL_GENEVE:
+ ctx |= ICE_TXD_CTX_UDP_TUNNELING;
+ break;
+ case RTE_MBUF_F_TX_TUNNEL_GRE:
+ ctx |= ICE_TXD_CTX_GRE_TUNNELING;
+ break;
+ default:
+ PMD_TX_LOG(ERR, "Tunnel type not supported");
+ return ctx;
+ }
+
+ ctx |= (uint64_t)(tx_pkt->l2_len >> 1) << ICE_TXD_CTX_QW0_NATLEN_S;
+
+ if ((ctx & ICE_TXD_CTX_QW0_EIPT_M) &&
+ (ctx & ICE_TXD_CTX_UDP_TUNNELING) &&
+ (ol_flags & RTE_MBUF_F_TX_OUTER_UDP_CKSUM))
+ ctx |= ICE_TXD_CTX_QW0_L4T_CS_M;
+
+ return ctx;
+}
#endif
--
2.34.1
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 3/4] net/ice: add AVX2 context descriptor Tx path
2026-08-24 10:21 [PATCH 0/4] net/ice: support outer checksum in vector Tx Anurag Mandal
2026-08-24 10:21 ` [PATCH 1/4] net/common: share Tx context descriptor flag Anurag Mandal
2026-08-24 10:21 ` [PATCH 2/4] net/ice: add vector tunnel context encoding Anurag Mandal
@ 2026-08-24 10:21 ` Anurag Mandal
2026-08-24 14:47 ` Bruce Richardson
2026-08-24 10:21 ` [PATCH 4/4] net/ice: add AVX-512 " Anurag Mandal
2026-08-31 10:35 ` [PATCH v2 0/4] net/ice: support outer checksum in vector Tx Anurag Mandal
4 siblings, 1 reply; 15+ messages in thread
From: Anurag Mandal @ 2026-08-24 10:21 UTC (permalink / raw)
To: dev; +Cc: bruce.richardson, anatoly.burakov, Anurag Mandal
Added an AVX2 context descriptor path for tunneled
outer IPv4 and UDP checksum offloads.
Signed-off-by: Anurag Mandal <anurag.mandal@intel.com>
---
doc/guides/rel_notes/release_26_11.rst | 5 +
drivers/net/intel/ice/ice_dcf_ethdev.c | 4 +-
drivers/net/intel/ice/ice_ethdev.h | 1 +
drivers/net/intel/ice/ice_rxtx.c | 31 +++++-
drivers/net/intel/ice/ice_rxtx.h | 8 ++
drivers/net/intel/ice/ice_rxtx_vec_avx2.c | 119 ++++++++++++++++++++++
6 files changed, 163 insertions(+), 5 deletions(-)
diff --git a/doc/guides/rel_notes/release_26_11.rst b/doc/guides/rel_notes/release_26_11.rst
index 907f9013ff..8ce1875843 100644
--- a/doc/guides/rel_notes/release_26_11.rst
+++ b/doc/guides/rel_notes/release_26_11.rst
@@ -55,6 +55,11 @@ New Features
Also, make sure to start the actual text at the margin.
=======================================================
+* **Updated Intel ice driver.**
+
+ Added an AVX2 Tx path using context descriptors, allowing tunneled outer IPv4
+ and UDP checksum offloads without falling back to scalar Tx.
+
* **Updated Intel iavf driver.**
* Runtime Rx/Tx queue setup is now automatically disabled while a
diff --git a/drivers/net/intel/ice/ice_dcf_ethdev.c b/drivers/net/intel/ice/ice_dcf_ethdev.c
index c78b290b0d..d1cdae6eb9 100644
--- a/drivers/net/intel/ice/ice_dcf_ethdev.c
+++ b/drivers/net/intel/ice/ice_dcf_ethdev.c
@@ -498,7 +498,7 @@ ice_dcf_tx_queue_stop(struct rte_eth_dev *dev, uint16_t tx_queue_id)
}
txq = dev->data->tx_queues[tx_queue_id];
- ci_txq_release_all_mbufs(txq, false);
+ ci_txq_release_all_mbufs(txq, txq->use_ctx);
reset_tx_queue(txq);
dev->data->tx_queue_state[tx_queue_id] = RTE_ETH_QUEUE_STATE_STOPPED;
@@ -648,7 +648,7 @@ ice_dcf_stop_queues(struct rte_eth_dev *dev)
txq = dev->data->tx_queues[i];
if (!txq)
continue;
- ci_txq_release_all_mbufs(txq, false);
+ ci_txq_release_all_mbufs(txq, txq->use_ctx);
reset_tx_queue(txq);
dev->data->tx_queue_state[i] = RTE_ETH_QUEUE_STATE_STOPPED;
}
diff --git a/drivers/net/intel/ice/ice_ethdev.h b/drivers/net/intel/ice/ice_ethdev.h
index 7ee3ea8a70..0e74f8d776 100644
--- a/drivers/net/intel/ice/ice_ethdev.h
+++ b/drivers/net/intel/ice/ice_ethdev.h
@@ -213,6 +213,7 @@ enum ice_tx_func_type {
ICE_TX_SIMPLE,
ICE_TX_AVX2,
ICE_TX_AVX2_OFFLOAD,
+ ICE_TX_AVX2_CTX_OFFLOAD,
ICE_TX_AVX512,
ICE_TX_AVX512_OFFLOAD,
ICE_TX_NEON,
diff --git a/drivers/net/intel/ice/ice_rxtx.c b/drivers/net/intel/ice/ice_rxtx.c
index c4b5454c53..5ec0b4d1fd 100644
--- a/drivers/net/intel/ice/ice_rxtx.c
+++ b/drivers/net/intel/ice/ice_rxtx.c
@@ -1193,7 +1193,7 @@ ice_tx_queue_stop(struct rte_eth_dev *dev, uint16_t tx_queue_id)
return -EINVAL;
}
- ci_txq_release_all_mbufs(txq, false);
+ ci_txq_release_all_mbufs(txq, txq->use_ctx);
ice_reset_tx_queue(txq);
dev->data->tx_queue_state[tx_queue_id] = RTE_ETH_QUEUE_STATE_STOPPED;
@@ -1256,7 +1256,7 @@ ice_fdir_tx_queue_stop(struct rte_eth_dev *dev, uint16_t tx_queue_id)
return -EINVAL;
}
- ci_txq_release_all_mbufs(txq, false);
+ ci_txq_release_all_mbufs(txq, txq->use_ctx);
txq->qtx_tail = NULL;
return 0;
@@ -1744,7 +1744,7 @@ ice_tx_queue_release(void *txq)
return;
}
- ci_txq_release_all_mbufs(q, false);
+ ci_txq_release_all_mbufs(q, q->use_ctx);
rte_free(q->sw_ring);
rte_free(q->rs_last_id);
if (q->tsq) {
@@ -3554,6 +3554,16 @@ static const struct ci_tx_path_info ice_tx_path_infos[] = {
},
.pkt_prep = ice_prep_pkts
},
+ [ICE_TX_AVX2_CTX_OFFLOAD] = {
+ .pkt_burst = ice_xmit_pkts_vec_avx2_ctx_offload,
+ .info = "Context Offload Vector AVX2",
+ .features = {
+ .tx_offloads = ICE_TX_VECTOR_CTX_OFFLOAD_OFFLOADS,
+ .simd_width = RTE_VECT_SIMD_256,
+ .ctx_desc = true
+ },
+ .pkt_prep = ice_prep_pkts
+ },
#ifdef CC_AVX512_SUPPORT
[ICE_TX_AVX512] = {
.pkt_burst = ice_xmit_pkts_vec_avx512,
@@ -3755,11 +3765,17 @@ ice_set_tx_function(struct rte_eth_dev *dev)
{
struct ice_adapter *ad =
ICE_DEV_PRIVATE_TO_ADAPTER(dev->data->dev_private);
+ const struct ci_tx_path_features *selected_features;
+ struct ci_tx_queue *txq;
int mbuf_check = ad->devargs.mbuf_check;
+ int i;
struct ci_tx_path_features req_features = {
.tx_offloads = dev->data->dev_conf.txmode.offloads,
.simd_width = RTE_VECT_SIMD_DISABLED,
};
+ req_features.ctx_desc = req_features.tx_offloads &
+ (RTE_ETH_TX_OFFLOAD_OUTER_IPV4_CKSUM |
+ RTE_ETH_TX_OFFLOAD_OUTER_UDP_CKSUM);
/* If the device has started the function has already been selected. */
if (dev->data->dev_started)
@@ -3785,6 +3801,15 @@ ice_set_tx_function(struct rte_eth_dev *dev)
ad->tx_vec_allowed =
(ice_tx_path_infos[ad->tx_func_type].features.simd_width >= RTE_VECT_SIMD_128);
#endif
+ selected_features = &ice_tx_path_infos[ad->tx_func_type].features;
+ for (i = 0; i < dev->data->nb_tx_queues; i++) {
+ txq = dev->data->tx_queues[i];
+ if (!txq)
+ continue;
+ txq->use_ctx = selected_features->ctx_desc;
+ txq->use_vec_entry = selected_features->simple_tx ||
+ selected_features->simd_width >= RTE_VECT_SIMD_128;
+ }
dev->tx_pkt_burst = mbuf_check ? ice_xmit_pkts_check :
ice_tx_path_infos[ad->tx_func_type].pkt_burst;
diff --git a/drivers/net/intel/ice/ice_rxtx.h b/drivers/net/intel/ice/ice_rxtx.h
index 999b6b30d6..37e346fe39 100644
--- a/drivers/net/intel/ice/ice_rxtx.h
+++ b/drivers/net/intel/ice/ice_rxtx.h
@@ -136,6 +136,11 @@
RTE_ETH_TX_OFFLOAD_TCP_CKSUM | \
RTE_ETH_TX_OFFLOAD_SCTP_CKSUM)
+#define ICE_TX_VECTOR_CTX_OFFLOAD_OFFLOADS ( \
+ ICE_TX_VECTOR_OFFLOAD_OFFLOADS | \
+ RTE_ETH_TX_OFFLOAD_OUTER_IPV4_CKSUM | \
+ RTE_ETH_TX_OFFLOAD_OUTER_UDP_CKSUM)
+
/* Max header size can be 2K - 64 bytes */
#define ICE_RX_HDR_BUF_SIZE (2048 - 64)
@@ -284,6 +289,9 @@ uint16_t ice_xmit_pkts_vec_avx2(void *tx_queue, struct rte_mbuf **tx_pkts,
uint16_t nb_pkts);
uint16_t ice_xmit_pkts_vec_avx2_offload(void *tx_queue, struct rte_mbuf **tx_pkts,
uint16_t nb_pkts);
+uint16_t ice_xmit_pkts_vec_avx2_ctx_offload(void *tx_queue,
+ struct rte_mbuf **tx_pkts,
+ uint16_t nb_pkts);
uint16_t ice_recv_pkts_vec_avx512(void *rx_queue, struct rte_mbuf **rx_pkts,
uint16_t nb_pkts);
uint16_t ice_recv_pkts_vec_avx512_offload(void *rx_queue,
diff --git a/drivers/net/intel/ice/ice_rxtx_vec_avx2.c b/drivers/net/intel/ice/ice_rxtx_vec_avx2.c
index b72f69a47b..88a3dfb1b6 100644
--- a/drivers/net/intel/ice/ice_rxtx_vec_avx2.c
+++ b/drivers/net/intel/ice/ice_rxtx_vec_avx2.c
@@ -837,6 +837,125 @@ ice_vtx(volatile struct ci_tx_desc *txdp,
}
}
+static inline void
+ice_ctx_vtx1(volatile struct ci_tx_desc *txdp, struct rte_mbuf *pkt,
+ uint64_t flags, bool offload)
+{
+ uint64_t high_data_qw = CI_TX_DESC_DTYPE_DATA |
+ (flags << CI_TXD_QW1_CMD_S) |
+ ((uint64_t)pkt->data_len << CI_TXD_QW1_TX_BUF_SZ_S);
+ const uint64_t low_ctx_qw = offload ? ice_txd_tunneling_ctx(pkt) : 0;
+
+ if (offload)
+ ice_txd_enable_offload(pkt, &high_data_qw);
+
+ const __m256i ctx_data_desc = _mm256_set_epi64x(high_data_qw,
+ rte_pktmbuf_iova(pkt), CI_TX_DESC_DTYPE_CTX, low_ctx_qw);
+
+ _mm256_store_si256(RTE_CAST_PTR(__m256i *, txdp), ctx_data_desc);
+}
+
+static inline void
+ice_ctx_vtx(volatile struct ci_tx_desc *txdp, struct rte_mbuf **pkt,
+ uint16_t nb_pkts, uint64_t flags, bool offload)
+{
+ while (nb_pkts) {
+ ice_ctx_vtx1(txdp, *pkt, flags, offload);
+ txdp += 2;
+ pkt++;
+ nb_pkts--;
+ }
+}
+
+static inline uint16_t
+ice_xmit_fixed_burst_vec_avx2_ctx(void *tx_queue, struct rte_mbuf **tx_pkts,
+ uint16_t nb_pkts, bool offload)
+{
+ struct ci_tx_queue *txq = tx_queue;
+ volatile struct ci_tx_desc *txdp;
+ struct ci_tx_entry_vec *txep;
+ uint16_t n, nb_commit, nb_mbuf, tx_id;
+ const uint64_t flags = CI_TX_DESC_CMD_DEFAULT;
+ const uint64_t rs = CI_TX_DESC_CMD_RS | flags;
+
+ if (txq->nb_tx_free < txq->tx_free_thresh)
+ ci_tx_free_bufs_vec(txq, ice_tx_desc_done, true);
+
+ nb_commit = (uint16_t)RTE_MIN(txq->nb_tx_free,
+ (uint32_t)nb_pkts * 2);
+ nb_commit &= (uint16_t)~1;
+ if (unlikely(nb_commit == 0))
+ return 0;
+
+ nb_pkts = nb_commit >> 1;
+ tx_id = txq->tx_tail;
+ txdp = &txq->ci_tx_ring[tx_id];
+ txep = &txq->sw_ring_vec[tx_id >> 1];
+
+ txq->nb_tx_free = (uint16_t)(txq->nb_tx_free - nb_commit);
+ n = (uint16_t)(txq->nb_tx_desc - tx_id);
+
+ if (nb_commit >= n) {
+ nb_mbuf = n >> 1;
+ ci_tx_backlog_entry_vec(txep, tx_pkts, nb_mbuf);
+
+ ice_ctx_vtx(txdp, tx_pkts, nb_mbuf - 1, flags, offload);
+ tx_pkts += nb_mbuf - 1;
+ txdp += n - 2;
+ ice_ctx_vtx1(txdp, *tx_pkts++, rs, offload);
+
+ nb_commit = (uint16_t)(nb_commit - n);
+ txq->tx_next_rs = (uint16_t)(txq->tx_rs_thresh - 1);
+ tx_id = 0;
+ txdp = txq->ci_tx_ring;
+ txep = txq->sw_ring_vec;
+ }
+
+ nb_mbuf = nb_commit >> 1;
+ ci_tx_backlog_entry_vec(txep, tx_pkts, nb_mbuf);
+ ice_ctx_vtx(txdp, tx_pkts, nb_mbuf, flags, offload);
+ tx_id = (uint16_t)(tx_id + nb_commit);
+
+ if (tx_id > txq->tx_next_rs) {
+ txq->ci_tx_ring[txq->tx_next_rs].cmd_type_offset_bsz |=
+ rte_cpu_to_le_64((uint64_t)CI_TX_DESC_CMD_RS << CI_TXD_QW1_CMD_S);
+ txq->tx_next_rs = (uint16_t)(txq->tx_next_rs + txq->tx_rs_thresh);
+ }
+
+ txq->tx_tail = tx_id;
+ ICE_PCI_REG_WC_WRITE(txq->qtx_tail, txq->tx_tail);
+
+ return nb_pkts;
+}
+
+static inline uint16_t
+ice_xmit_pkts_vec_avx2_ctx_common(void *tx_queue, struct rte_mbuf **tx_pkts,
+ uint16_t nb_pkts, bool offload)
+{
+ struct ci_tx_queue *txq = tx_queue;
+ uint16_t nb_tx = 0;
+
+ while (nb_pkts) {
+ const uint16_t num = RTE_MIN(nb_pkts, txq->tx_rs_thresh >> 1);
+ const uint16_t ret = ice_xmit_fixed_burst_vec_avx2_ctx(tx_queue,
+ &tx_pkts[nb_tx], num, offload);
+
+ nb_tx += ret;
+ nb_pkts -= ret;
+ if (ret < num)
+ break;
+ }
+
+ return nb_tx;
+}
+
+uint16_t
+ice_xmit_pkts_vec_avx2_ctx_offload(void *tx_queue,
+ struct rte_mbuf **tx_pkts, uint16_t nb_pkts)
+{
+ return ice_xmit_pkts_vec_avx2_ctx_common(tx_queue, tx_pkts, nb_pkts, true);
+}
+
static __rte_always_inline uint16_t
ice_xmit_fixed_burst_vec_avx2(void *tx_queue, struct rte_mbuf **tx_pkts,
uint16_t nb_pkts, bool offload)
--
2.34.1
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH 4/4] net/ice: add AVX-512 context descriptor Tx path
2026-08-24 10:21 [PATCH 0/4] net/ice: support outer checksum in vector Tx Anurag Mandal
` (2 preceding siblings ...)
2026-08-24 10:21 ` [PATCH 3/4] net/ice: add AVX2 context descriptor Tx path Anurag Mandal
@ 2026-08-24 10:21 ` Anurag Mandal
2026-08-31 10:35 ` [PATCH v2 0/4] net/ice: support outer checksum in vector Tx Anurag Mandal
4 siblings, 0 replies; 15+ messages in thread
From: Anurag Mandal @ 2026-08-24 10:21 UTC (permalink / raw)
To: dev; +Cc: bruce.richardson, anatoly.burakov, Anurag Mandal
Added an AVX-512 context descriptor path for tunneled
outer IPv4 and UDP checksum offloads.
Signed-off-by: Anurag Mandal <anurag.mandal@intel.com>
---
doc/guides/rel_notes/release_26_11.rst | 5 +-
drivers/net/intel/ice/ice_ethdev.h | 1 +
drivers/net/intel/ice/ice_rxtx.c | 10 ++
drivers/net/intel/ice/ice_rxtx.h | 3 +
drivers/net/intel/ice/ice_rxtx_vec_avx512.c | 141 ++++++++++++++++++++
5 files changed, 158 insertions(+), 2 deletions(-)
diff --git a/doc/guides/rel_notes/release_26_11.rst b/doc/guides/rel_notes/release_26_11.rst
index 8ce1875843..1239f1ab0d 100644
--- a/doc/guides/rel_notes/release_26_11.rst
+++ b/doc/guides/rel_notes/release_26_11.rst
@@ -57,8 +57,9 @@ New Features
* **Updated Intel ice driver.**
- Added an AVX2 Tx path using context descriptors, allowing tunneled outer IPv4
- and UDP checksum offloads without falling back to scalar Tx.
+ * Added AVX2 and AVX-512 context-descriptor Tx paths,
+ enabling outer IPv4 and UDP checksum offloads for
+ tunneled packets without falling back to scalar Tx.
* **Updated Intel iavf driver.**
diff --git a/drivers/net/intel/ice/ice_ethdev.h b/drivers/net/intel/ice/ice_ethdev.h
index 0e74f8d776..00facd48bd 100644
--- a/drivers/net/intel/ice/ice_ethdev.h
+++ b/drivers/net/intel/ice/ice_ethdev.h
@@ -216,6 +216,7 @@ enum ice_tx_func_type {
ICE_TX_AVX2_CTX_OFFLOAD,
ICE_TX_AVX512,
ICE_TX_AVX512_OFFLOAD,
+ ICE_TX_AVX512_CTX_OFFLOAD,
ICE_TX_NEON,
};
diff --git a/drivers/net/intel/ice/ice_rxtx.c b/drivers/net/intel/ice/ice_rxtx.c
index 5ec0b4d1fd..a3ee235edf 100644
--- a/drivers/net/intel/ice/ice_rxtx.c
+++ b/drivers/net/intel/ice/ice_rxtx.c
@@ -3583,6 +3583,16 @@ static const struct ci_tx_path_info ice_tx_path_infos[] = {
},
.pkt_prep = ice_prep_pkts
},
+ [ICE_TX_AVX512_CTX_OFFLOAD] = {
+ .pkt_burst = ice_xmit_pkts_vec_avx512_ctx_offload,
+ .info = "Context Offload Vector AVX512",
+ .features = {
+ .tx_offloads = ICE_TX_VECTOR_CTX_OFFLOAD_OFFLOADS,
+ .simd_width = RTE_VECT_SIMD_512,
+ .ctx_desc = true
+ },
+ .pkt_prep = ice_prep_pkts
+ },
#endif
#elif defined(RTE_ARCH_ARM64)
[ICE_TX_NEON] = {
diff --git a/drivers/net/intel/ice/ice_rxtx.h b/drivers/net/intel/ice/ice_rxtx.h
index 37e346fe39..7aef372136 100644
--- a/drivers/net/intel/ice/ice_rxtx.h
+++ b/drivers/net/intel/ice/ice_rxtx.h
@@ -308,6 +308,9 @@ uint16_t ice_xmit_pkts_vec_avx512(void *tx_queue, struct rte_mbuf **tx_pkts,
uint16_t ice_xmit_pkts_vec_avx512_offload(void *tx_queue,
struct rte_mbuf **tx_pkts,
uint16_t nb_pkts);
+uint16_t ice_xmit_pkts_vec_avx512_ctx_offload(void *tx_queue,
+ struct rte_mbuf **tx_pkts,
+ uint16_t nb_pkts);
int ice_fdir_programming(struct ice_pf *pf, struct ice_fltr_desc *fdir_desc);
int ice_tx_done_cleanup(void *txq, uint32_t free_cnt);
int ice_get_monitor_addr(void *rx_queue, struct rte_power_monitor_cond *pmc);
diff --git a/drivers/net/intel/ice/ice_rxtx_vec_avx512.c b/drivers/net/intel/ice/ice_rxtx_vec_avx512.c
index 309ab9fca7..f598caef47 100644
--- a/drivers/net/intel/ice/ice_rxtx_vec_avx512.c
+++ b/drivers/net/intel/ice/ice_rxtx_vec_avx512.c
@@ -901,6 +901,147 @@ ice_vtx(volatile struct ci_tx_desc *txdp, struct rte_mbuf **pkt,
}
}
+static inline void
+ice_ctx_vtx1(volatile struct ci_tx_desc *txdp, struct rte_mbuf *pkt,
+ uint64_t flags, bool offload)
+{
+ uint64_t high_data_qw = CI_TX_DESC_DTYPE_DATA |
+ (flags << CI_TXD_QW1_CMD_S) |
+ ((uint64_t)pkt->data_len << CI_TXD_QW1_TX_BUF_SZ_S);
+ const uint64_t low_ctx_qw = offload ? ice_txd_tunneling_ctx(pkt) : 0;
+
+ if (offload)
+ ice_txd_enable_offload(pkt, &high_data_qw);
+
+ const __m256i ctx_data_desc = _mm256_set_epi64x(high_data_qw,
+ rte_pktmbuf_iova(pkt), CI_TX_DESC_DTYPE_CTX, low_ctx_qw);
+
+ _mm256_store_si256(RTE_CAST_PTR(__m256i *, txdp), ctx_data_desc);
+}
+
+static inline void
+ice_ctx_vtx(volatile struct ci_tx_desc *txdp, struct rte_mbuf **pkt,
+ uint16_t nb_pkts, uint64_t flags, bool offload)
+{
+ while (nb_pkts > 1) {
+ uint64_t high_data_qw1 = CI_TX_DESC_DTYPE_DATA |
+ (flags << CI_TXD_QW1_CMD_S) |
+ ((uint64_t)pkt[1]->data_len << CI_TXD_QW1_TX_BUF_SZ_S);
+ uint64_t high_data_qw0 = CI_TX_DESC_DTYPE_DATA |
+ (flags << CI_TXD_QW1_CMD_S) |
+ ((uint64_t)pkt[0]->data_len << CI_TXD_QW1_TX_BUF_SZ_S);
+ const uint64_t low_ctx_qw1 = offload ? ice_txd_tunneling_ctx(pkt[1]) : 0;
+ const uint64_t low_ctx_qw0 = offload ? ice_txd_tunneling_ctx(pkt[0]) : 0;
+
+ if (offload) {
+ ice_txd_enable_offload(pkt[1], &high_data_qw1);
+ ice_txd_enable_offload(pkt[0], &high_data_qw0);
+ }
+
+ const __m512i ctx_data_desc = _mm512_set_epi64(high_data_qw1,
+ rte_pktmbuf_iova(pkt[1]), CI_TX_DESC_DTYPE_CTX, low_ctx_qw1,
+ high_data_qw0, rte_pktmbuf_iova(pkt[0]),
+ CI_TX_DESC_DTYPE_CTX, low_ctx_qw0);
+
+ _mm512_storeu_si512(RTE_CAST_PTR(void *, txdp), ctx_data_desc);
+ txdp += 4;
+ pkt += 2;
+ nb_pkts -= 2;
+ }
+
+ if (nb_pkts)
+ ice_ctx_vtx1(txdp, *pkt, flags, offload);
+}
+
+static inline uint16_t
+ice_xmit_fixed_burst_vec_avx512_ctx(void *tx_queue, struct rte_mbuf **tx_pkts,
+ uint16_t nb_pkts, bool offload)
+{
+ struct ci_tx_queue *txq = tx_queue;
+ volatile struct ci_tx_desc *txdp;
+ struct ci_tx_entry_vec *txep;
+ uint16_t n, nb_commit, nb_mbuf, tx_id;
+ const uint64_t flags = CI_TX_DESC_CMD_DEFAULT;
+ const uint64_t rs = CI_TX_DESC_CMD_RS | flags;
+
+ if (txq->nb_tx_free < txq->tx_free_thresh)
+ ci_tx_free_bufs_vec(txq, ice_tx_desc_done, true);
+
+ nb_commit = (uint16_t)RTE_MIN(txq->nb_tx_free,
+ (uint32_t)nb_pkts * 2);
+ nb_commit &= (uint16_t)~1;
+ if (unlikely(nb_commit == 0))
+ return 0;
+
+ nb_pkts = nb_commit >> 1;
+ tx_id = txq->tx_tail;
+ txdp = &txq->ci_tx_ring[tx_id];
+ txep = &txq->sw_ring_vec[tx_id >> 1];
+
+ txq->nb_tx_free = (uint16_t)(txq->nb_tx_free - nb_commit);
+ n = (uint16_t)(txq->nb_tx_desc - tx_id);
+
+ if (nb_commit >= n) {
+ nb_mbuf = n >> 1;
+ ci_tx_backlog_entry_vec(txep, tx_pkts, nb_mbuf);
+
+ ice_ctx_vtx(txdp, tx_pkts, nb_mbuf - 1, flags, offload);
+ tx_pkts += nb_mbuf - 1;
+ txdp += n - 2;
+ ice_ctx_vtx1(txdp, *tx_pkts++, rs, offload);
+
+ nb_commit = (uint16_t)(nb_commit - n);
+ txq->tx_next_rs = (uint16_t)(txq->tx_rs_thresh - 1);
+ tx_id = 0;
+ txdp = txq->ci_tx_ring;
+ txep = txq->sw_ring_vec;
+ }
+
+ nb_mbuf = nb_commit >> 1;
+ ci_tx_backlog_entry_vec(txep, tx_pkts, nb_mbuf);
+ ice_ctx_vtx(txdp, tx_pkts, nb_mbuf, flags, offload);
+ tx_id = (uint16_t)(tx_id + nb_commit);
+
+ if (tx_id > txq->tx_next_rs) {
+ txq->ci_tx_ring[txq->tx_next_rs].cmd_type_offset_bsz |=
+ rte_cpu_to_le_64((uint64_t)CI_TX_DESC_CMD_RS << CI_TXD_QW1_CMD_S);
+ txq->tx_next_rs = (uint16_t)(txq->tx_next_rs + txq->tx_rs_thresh);
+ }
+
+ txq->tx_tail = tx_id;
+ ICE_PCI_REG_WC_WRITE(txq->qtx_tail, txq->tx_tail);
+
+ return nb_pkts;
+}
+
+static inline uint16_t
+ice_xmit_pkts_vec_avx512_ctx_common(void *tx_queue, struct rte_mbuf **tx_pkts,
+ uint16_t nb_pkts, bool offload)
+{
+ struct ci_tx_queue *txq = tx_queue;
+ uint16_t nb_tx = 0;
+
+ while (nb_pkts) {
+ const uint16_t num = RTE_MIN(nb_pkts, txq->tx_rs_thresh >> 1);
+ const uint16_t ret = ice_xmit_fixed_burst_vec_avx512_ctx(tx_queue,
+ &tx_pkts[nb_tx], num, offload);
+
+ nb_tx += ret;
+ nb_pkts -= ret;
+ if (ret < num)
+ break;
+ }
+
+ return nb_tx;
+}
+
+uint16_t
+ice_xmit_pkts_vec_avx512_ctx_offload(void *tx_queue,
+ struct rte_mbuf **tx_pkts, uint16_t nb_pkts)
+{
+ return ice_xmit_pkts_vec_avx512_ctx_common(tx_queue, tx_pkts, nb_pkts, true);
+}
+
static __rte_always_inline uint16_t
ice_xmit_fixed_burst_vec_avx512(void *tx_queue, struct rte_mbuf **tx_pkts,
uint16_t nb_pkts, bool do_offload)
--
2.34.1
^ permalink raw reply related [flat|nested] 15+ messages in thread
* Re: [PATCH 2/4] net/ice: add vector tunnel context encoding
2026-08-24 10:21 ` [PATCH 2/4] net/ice: add vector tunnel context encoding Anurag Mandal
@ 2026-08-24 14:37 ` Bruce Richardson
2026-08-24 14:51 ` David Marchand
1 sibling, 0 replies; 15+ messages in thread
From: Bruce Richardson @ 2026-08-24 14:37 UTC (permalink / raw)
To: Anurag Mandal; +Cc: dev, anatoly.burakov
On Mon, Aug 24, 2026 at 10:21:52AM +0000, Anurag Mandal wrote:
> Added helpers to encode tunnel context descriptors,
> and checksum offsets.
>
> Signed-off-by: Anurag Mandal <anurag.mandal@intel.com>
> ---
Some comments inline below.
/Bruce
> drivers/net/intel/ice/ice_rxtx_vec_common.h | 53 ++++++++++++++++++++-
> 1 file changed, 51 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/net/intel/ice/ice_rxtx_vec_common.h b/drivers/net/intel/ice/ice_rxtx_vec_common.h
> index 1d83a087cc..b84456357f 100644
> --- a/drivers/net/intel/ice/ice_rxtx_vec_common.h
> +++ b/drivers/net/intel/ice/ice_rxtx_vec_common.h
> @@ -123,8 +123,12 @@ ice_txd_enable_offload(struct rte_mbuf *tx_pkt,
>
> /* Tx Checksum Offload */
> /* SET MACLEN */
> - td_offset |= (tx_pkt->l2_len >> 1) <<
> - CI_TX_DESC_LEN_MACLEN_S;
> + if (ol_flags & RTE_MBUF_F_TX_TUNNEL_MASK)
> + td_offset |= (tx_pkt->outer_l2_len >> 1) <<
> + CI_TX_DESC_LEN_MACLEN_S;
> + else
> + td_offset |= (tx_pkt->l2_len >> 1) <<
> + CI_TX_DESC_LEN_MACLEN_S;
I don't think these lines need to be split. It's copy-paste from iavf, but I'd
still adjust to be single-line.
>
> /* Enable L3 checksum offload */
> if (ol_flags & RTE_MBUF_F_TX_IP_CKSUM) {
> @@ -172,4 +176,49 @@ ice_txd_enable_offload(struct rte_mbuf *tx_pkt,
>
> *txd_hi |= ((uint64_t)td_cmd) << CI_TXD_QW1_CMD_S;
> }
> +
> +static inline uint64_t
> +ice_txd_tunneling_ctx(const struct rte_mbuf *tx_pkt)
> +{
> + const uint64_t ol_flags = tx_pkt->ol_flags;
> + uint64_t ctx = 0;
> +
> + if (!(ol_flags & RTE_MBUF_F_TX_TUNNEL_MASK))
> + return 0;
> +
> + if (ol_flags & RTE_MBUF_F_TX_OUTER_IP_CKSUM)
> + ctx |= ICE_TX_CTX_EIPT_IPV4;
> + else if (ol_flags & RTE_MBUF_F_TX_OUTER_IPV4)
> + ctx |= ICE_TX_CTX_EIPT_IPV4_NO_CSUM;
> + else if (ol_flags & RTE_MBUF_F_TX_OUTER_IPV6)
> + ctx |= ICE_TX_CTX_EIPT_IPV6;
> +
> + ctx |= (uint64_t)(tx_pkt->outer_l3_len >> 2) << ICE_TXD_CTX_QW0_EIPLEN_S;
Is this meant to be unconditionally encoded in the context?
Same with the l2_len below? Are we relying on the HW to ignore these values
if the flags for them are not set? Comparing against iavf, these are set in
the switch block per protocol.
> +
> + switch (ol_flags & RTE_MBUF_F_TX_TUNNEL_MASK) {
> + case RTE_MBUF_F_TX_TUNNEL_IPIP:
> + break;
> + case RTE_MBUF_F_TX_TUNNEL_VXLAN:
> + case RTE_MBUF_F_TX_TUNNEL_VXLAN_GPE:
> + case RTE_MBUF_F_TX_TUNNEL_GTP:
> + case RTE_MBUF_F_TX_TUNNEL_GENEVE:
> + ctx |= ICE_TXD_CTX_UDP_TUNNELING;
> + break;
> + case RTE_MBUF_F_TX_TUNNEL_GRE:
> + ctx |= ICE_TXD_CTX_GRE_TUNNELING;
> + break;
> + default:
> + PMD_TX_LOG(ERR, "Tunnel type not supported");
> + return ctx;
Should this not return 0, rather than a half-completed ctx?
> + }
> +
> + ctx |= (uint64_t)(tx_pkt->l2_len >> 1) << ICE_TXD_CTX_QW0_NATLEN_S;
> +
> + if ((ctx & ICE_TXD_CTX_QW0_EIPT_M) &&
> + (ctx & ICE_TXD_CTX_UDP_TUNNELING) &&
> + (ol_flags & RTE_MBUF_F_TX_OUTER_UDP_CKSUM))
> + ctx |= ICE_TXD_CTX_QW0_L4T_CS_M;
> +
> + return ctx;
> +}
> #endif
> --
> 2.34.1
>
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 3/4] net/ice: add AVX2 context descriptor Tx path
2026-08-24 10:21 ` [PATCH 3/4] net/ice: add AVX2 context descriptor Tx path Anurag Mandal
@ 2026-08-24 14:47 ` Bruce Richardson
2026-08-31 10:47 ` Mandal, Anurag
0 siblings, 1 reply; 15+ messages in thread
From: Bruce Richardson @ 2026-08-24 14:47 UTC (permalink / raw)
To: Anurag Mandal; +Cc: dev, anatoly.burakov
On Mon, Aug 24, 2026 at 10:21:53AM +0000, Anurag Mandal wrote:
> Added an AVX2 context descriptor path for tunneled
> outer IPv4 and UDP checksum offloads.
>
> Signed-off-by: Anurag Mandal <anurag.mandal@intel.com>
> ---
> doc/guides/rel_notes/release_26_11.rst | 5 +
> drivers/net/intel/ice/ice_dcf_ethdev.c | 4 +-
> drivers/net/intel/ice/ice_ethdev.h | 1 +
> drivers/net/intel/ice/ice_rxtx.c | 31 +++++-
> drivers/net/intel/ice/ice_rxtx.h | 8 ++
> drivers/net/intel/ice/ice_rxtx_vec_avx2.c | 119 ++++++++++++++++++++++
> 6 files changed, 163 insertions(+), 5 deletions(-)
>
I asked AI to take a look at this patch and review it by comparison to the
existing iavf driver. Here's the output, most of which seems relevant. [It
also is flagging an alignment change that could be fixed in iavf driver,
but that is a separate, minor issue]
Please review feedback below for a new revision. Ideally, I'd like to keep
the ice implementation as aligned as possible to the iavf one, so we can
merge those code paths in future.
/Bruce
Review: net/ice: add AVX2 context descriptor Tx path
Errors
ice_tx_queue_start does not set use_ctx, so runtime-added queues get the wrong value.
ice_set_tx_function iterates all existing queues and sets use_ctx. However,
ice_tx_queue_start (called via rte_eth_tx_queue_start) does not set
use_ctx. A queue added at runtime after device start will have use_ctx =
false while the device burst function (ice_xmit_pkts_vec_avx2_ctx_offload)
treats every queue as using context descriptors. When that queue is stopped
or released, ci_txq_release_all_mbufs(txq, txq->use_ctx) with use_ctx =
false iterates physical descriptor indices into sw_ring_vec, which is sized
at nb_tx_desc / 2 — producing an out-of-bounds read on the sw_ring_vec
array.
iavf avoids this by checking txq->use_ctx in the Tx burst path itself (it's
set at configure time from the per-queue IAVF_TX_OFFLOAD_CTX flag). The ice
implementation sets it only once globally.
Warnings
Outer IPv6 tunneling (without checksum offload) skips the context descriptor path.
req_features.ctx_desc is set only when RTE_ETH_TX_OFFLOAD_OUTER_IPV4_CKSUM
or RTE_ETH_TX_OFFLOAD_OUTER_UDP_CKSUM is configured. An application that
only uses outer-IPv6 tunneling (no outer cksum offload needed) will not
select ICE_TX_AVX2_CTX_OFFLOAD, and the hardware will receive no context
descriptor with the tunnel type or outer IP type — even though
ice_txd_tunneling_ctx would encode them correctly. iavf triggers use_ctx on
any per-packet RTE_MBUF_F_TX_TUNNEL_MASK flag at the burst entry,
regardless of device-level offload configuration. Whether ice hardware
needs the context descriptor for outer IPv6 tunnels at all is
hardware-dependent and should be documented or validated.
No validation that tx_rs_thresh is adequate for 2-descriptor-per-packet mode.
ice_tx_vec_queue_default enforces tx_rs_thresh >= ICE_VPMD_TX_BURST (32).
In ctx mode, each batch handles tx_rs_thresh >> 1 packets. With
tx_rs_thresh = 32, that's 16 packets per burst. No check ensures this is
above a meaningful minimum. This is a weak warning — the current minimum
(16 packets) is still functional — but it's worth a comment.
Implementation Comparison (new ctx path vs iavf)
Aspect ice (ice_ctx_vtx1) iavf (ctx_vtx1)
256-bit store _mm256_store_si256 (aligned) _mm256_storeu_si256 (unaligned)
Context desc high word CI_TX_DESC_DTYPE_CTX only DTYPE_CONTEXT + optional IL2TAG2/LLDP bits
VLAN QinQ support Not handled in ctx path Handled in ctx descriptor
ctx_desc triggering Device-level offload flags Per-packet ol_flags at burst entry
use_ctx set per-queue Only in ice_set_tx_function (device start) Also maintained per-queue in setup
The use of _mm256_store_si256 (aligned) is consistent with the existing
non-ctx ice_vtx loop which also uses aligned stores, and is safe because
descriptor rings are cache-line aligned and tx_id is always even in ctx
mode.
> diff --git a/doc/guides/rel_notes/release_26_11.rst b/doc/guides/rel_notes/release_26_11.rst
> index 907f9013ff..8ce1875843 100644
> --- a/doc/guides/rel_notes/release_26_11.rst
> +++ b/doc/guides/rel_notes/release_26_11.rst
> @@ -55,6 +55,11 @@ New Features
> Also, make sure to start the actual text at the margin.
> =======================================================
>
> +* **Updated Intel ice driver.**
> +
> + Added an AVX2 Tx path using context descriptors, allowing tunneled outer IPv4
> + and UDP checksum offloads without falling back to scalar Tx.
> +
> * **Updated Intel iavf driver.**
>
> * Runtime Rx/Tx queue setup is now automatically disabled while a
> diff --git a/drivers/net/intel/ice/ice_dcf_ethdev.c b/drivers/net/intel/ice/ice_dcf_ethdev.c
> index c78b290b0d..d1cdae6eb9 100644
> --- a/drivers/net/intel/ice/ice_dcf_ethdev.c
> +++ b/drivers/net/intel/ice/ice_dcf_ethdev.c
> @@ -498,7 +498,7 @@ ice_dcf_tx_queue_stop(struct rte_eth_dev *dev, uint16_t tx_queue_id)
> }
>
> txq = dev->data->tx_queues[tx_queue_id];
> - ci_txq_release_all_mbufs(txq, false);
> + ci_txq_release_all_mbufs(txq, txq->use_ctx);
> reset_tx_queue(txq);
> dev->data->tx_queue_state[tx_queue_id] = RTE_ETH_QUEUE_STATE_STOPPED;
>
> @@ -648,7 +648,7 @@ ice_dcf_stop_queues(struct rte_eth_dev *dev)
> txq = dev->data->tx_queues[i];
> if (!txq)
> continue;
> - ci_txq_release_all_mbufs(txq, false);
> + ci_txq_release_all_mbufs(txq, txq->use_ctx);
> reset_tx_queue(txq);
> dev->data->tx_queue_state[i] = RTE_ETH_QUEUE_STATE_STOPPED;
> }
> diff --git a/drivers/net/intel/ice/ice_ethdev.h b/drivers/net/intel/ice/ice_ethdev.h
> index 7ee3ea8a70..0e74f8d776 100644
> --- a/drivers/net/intel/ice/ice_ethdev.h
> +++ b/drivers/net/intel/ice/ice_ethdev.h
> @@ -213,6 +213,7 @@ enum ice_tx_func_type {
> ICE_TX_SIMPLE,
> ICE_TX_AVX2,
> ICE_TX_AVX2_OFFLOAD,
> + ICE_TX_AVX2_CTX_OFFLOAD,
> ICE_TX_AVX512,
> ICE_TX_AVX512_OFFLOAD,
> ICE_TX_NEON,
> diff --git a/drivers/net/intel/ice/ice_rxtx.c b/drivers/net/intel/ice/ice_rxtx.c
> index c4b5454c53..5ec0b4d1fd 100644
> --- a/drivers/net/intel/ice/ice_rxtx.c
> +++ b/drivers/net/intel/ice/ice_rxtx.c
> @@ -1193,7 +1193,7 @@ ice_tx_queue_stop(struct rte_eth_dev *dev, uint16_t tx_queue_id)
> return -EINVAL;
> }
>
> - ci_txq_release_all_mbufs(txq, false);
> + ci_txq_release_all_mbufs(txq, txq->use_ctx);
> ice_reset_tx_queue(txq);
> dev->data->tx_queue_state[tx_queue_id] = RTE_ETH_QUEUE_STATE_STOPPED;
>
> @@ -1256,7 +1256,7 @@ ice_fdir_tx_queue_stop(struct rte_eth_dev *dev, uint16_t tx_queue_id)
> return -EINVAL;
> }
>
> - ci_txq_release_all_mbufs(txq, false);
> + ci_txq_release_all_mbufs(txq, txq->use_ctx);
> txq->qtx_tail = NULL;
>
> return 0;
> @@ -1744,7 +1744,7 @@ ice_tx_queue_release(void *txq)
> return;
> }
>
> - ci_txq_release_all_mbufs(q, false);
> + ci_txq_release_all_mbufs(q, q->use_ctx);
> rte_free(q->sw_ring);
> rte_free(q->rs_last_id);
> if (q->tsq) {
> @@ -3554,6 +3554,16 @@ static const struct ci_tx_path_info ice_tx_path_infos[] = {
> },
> .pkt_prep = ice_prep_pkts
> },
> + [ICE_TX_AVX2_CTX_OFFLOAD] = {
> + .pkt_burst = ice_xmit_pkts_vec_avx2_ctx_offload,
> + .info = "Context Offload Vector AVX2",
> + .features = {
> + .tx_offloads = ICE_TX_VECTOR_CTX_OFFLOAD_OFFLOADS,
> + .simd_width = RTE_VECT_SIMD_256,
> + .ctx_desc = true
> + },
> + .pkt_prep = ice_prep_pkts
> + },
> #ifdef CC_AVX512_SUPPORT
> [ICE_TX_AVX512] = {
> .pkt_burst = ice_xmit_pkts_vec_avx512,
> @@ -3755,11 +3765,17 @@ ice_set_tx_function(struct rte_eth_dev *dev)
> {
> struct ice_adapter *ad =
> ICE_DEV_PRIVATE_TO_ADAPTER(dev->data->dev_private);
> + const struct ci_tx_path_features *selected_features;
> + struct ci_tx_queue *txq;
> int mbuf_check = ad->devargs.mbuf_check;
> + int i;
> struct ci_tx_path_features req_features = {
> .tx_offloads = dev->data->dev_conf.txmode.offloads,
> .simd_width = RTE_VECT_SIMD_DISABLED,
> };
> + req_features.ctx_desc = req_features.tx_offloads &
> + (RTE_ETH_TX_OFFLOAD_OUTER_IPV4_CKSUM |
> + RTE_ETH_TX_OFFLOAD_OUTER_UDP_CKSUM);
>
> /* If the device has started the function has already been selected. */
> if (dev->data->dev_started)
> @@ -3785,6 +3801,15 @@ ice_set_tx_function(struct rte_eth_dev *dev)
> ad->tx_vec_allowed =
> (ice_tx_path_infos[ad->tx_func_type].features.simd_width >= RTE_VECT_SIMD_128);
> #endif
> + selected_features = &ice_tx_path_infos[ad->tx_func_type].features;
> + for (i = 0; i < dev->data->nb_tx_queues; i++) {
> + txq = dev->data->tx_queues[i];
> + if (!txq)
> + continue;
> + txq->use_ctx = selected_features->ctx_desc;
> + txq->use_vec_entry = selected_features->simple_tx ||
> + selected_features->simd_width >= RTE_VECT_SIMD_128;
> + }
>
> dev->tx_pkt_burst = mbuf_check ? ice_xmit_pkts_check :
> ice_tx_path_infos[ad->tx_func_type].pkt_burst;
> diff --git a/drivers/net/intel/ice/ice_rxtx.h b/drivers/net/intel/ice/ice_rxtx.h
> index 999b6b30d6..37e346fe39 100644
> --- a/drivers/net/intel/ice/ice_rxtx.h
> +++ b/drivers/net/intel/ice/ice_rxtx.h
> @@ -136,6 +136,11 @@
> RTE_ETH_TX_OFFLOAD_TCP_CKSUM | \
> RTE_ETH_TX_OFFLOAD_SCTP_CKSUM)
>
> +#define ICE_TX_VECTOR_CTX_OFFLOAD_OFFLOADS ( \
> + ICE_TX_VECTOR_OFFLOAD_OFFLOADS | \
> + RTE_ETH_TX_OFFLOAD_OUTER_IPV4_CKSUM | \
> + RTE_ETH_TX_OFFLOAD_OUTER_UDP_CKSUM)
> +
> /* Max header size can be 2K - 64 bytes */
> #define ICE_RX_HDR_BUF_SIZE (2048 - 64)
>
> @@ -284,6 +289,9 @@ uint16_t ice_xmit_pkts_vec_avx2(void *tx_queue, struct rte_mbuf **tx_pkts,
> uint16_t nb_pkts);
> uint16_t ice_xmit_pkts_vec_avx2_offload(void *tx_queue, struct rte_mbuf **tx_pkts,
> uint16_t nb_pkts);
> +uint16_t ice_xmit_pkts_vec_avx2_ctx_offload(void *tx_queue,
> + struct rte_mbuf **tx_pkts,
> + uint16_t nb_pkts);
> uint16_t ice_recv_pkts_vec_avx512(void *rx_queue, struct rte_mbuf **rx_pkts,
> uint16_t nb_pkts);
> uint16_t ice_recv_pkts_vec_avx512_offload(void *rx_queue,
> diff --git a/drivers/net/intel/ice/ice_rxtx_vec_avx2.c b/drivers/net/intel/ice/ice_rxtx_vec_avx2.c
> index b72f69a47b..88a3dfb1b6 100644
> --- a/drivers/net/intel/ice/ice_rxtx_vec_avx2.c
> +++ b/drivers/net/intel/ice/ice_rxtx_vec_avx2.c
> @@ -837,6 +837,125 @@ ice_vtx(volatile struct ci_tx_desc *txdp,
> }
> }
>
> +static inline void
> +ice_ctx_vtx1(volatile struct ci_tx_desc *txdp, struct rte_mbuf *pkt,
> + uint64_t flags, bool offload)
> +{
> + uint64_t high_data_qw = CI_TX_DESC_DTYPE_DATA |
> + (flags << CI_TXD_QW1_CMD_S) |
> + ((uint64_t)pkt->data_len << CI_TXD_QW1_TX_BUF_SZ_S);
> + const uint64_t low_ctx_qw = offload ? ice_txd_tunneling_ctx(pkt) : 0;
> +
> + if (offload)
> + ice_txd_enable_offload(pkt, &high_data_qw);
> +
> + const __m256i ctx_data_desc = _mm256_set_epi64x(high_data_qw,
> + rte_pktmbuf_iova(pkt), CI_TX_DESC_DTYPE_CTX, low_ctx_qw);
> +
> + _mm256_store_si256(RTE_CAST_PTR(__m256i *, txdp), ctx_data_desc);
> +}
> +
> +static inline void
> +ice_ctx_vtx(volatile struct ci_tx_desc *txdp, struct rte_mbuf **pkt,
> + uint16_t nb_pkts, uint64_t flags, bool offload)
> +{
> + while (nb_pkts) {
> + ice_ctx_vtx1(txdp, *pkt, flags, offload);
> + txdp += 2;
> + pkt++;
> + nb_pkts--;
> + }
> +}
> +
> +static inline uint16_t
> +ice_xmit_fixed_burst_vec_avx2_ctx(void *tx_queue, struct rte_mbuf **tx_pkts,
> + uint16_t nb_pkts, bool offload)
> +{
> + struct ci_tx_queue *txq = tx_queue;
> + volatile struct ci_tx_desc *txdp;
> + struct ci_tx_entry_vec *txep;
> + uint16_t n, nb_commit, nb_mbuf, tx_id;
> + const uint64_t flags = CI_TX_DESC_CMD_DEFAULT;
> + const uint64_t rs = CI_TX_DESC_CMD_RS | flags;
> +
> + if (txq->nb_tx_free < txq->tx_free_thresh)
> + ci_tx_free_bufs_vec(txq, ice_tx_desc_done, true);
> +
> + nb_commit = (uint16_t)RTE_MIN(txq->nb_tx_free,
> + (uint32_t)nb_pkts * 2);
> + nb_commit &= (uint16_t)~1;
> + if (unlikely(nb_commit == 0))
> + return 0;
> +
> + nb_pkts = nb_commit >> 1;
> + tx_id = txq->tx_tail;
> + txdp = &txq->ci_tx_ring[tx_id];
> + txep = &txq->sw_ring_vec[tx_id >> 1];
> +
> + txq->nb_tx_free = (uint16_t)(txq->nb_tx_free - nb_commit);
> + n = (uint16_t)(txq->nb_tx_desc - tx_id);
> +
> + if (nb_commit >= n) {
> + nb_mbuf = n >> 1;
> + ci_tx_backlog_entry_vec(txep, tx_pkts, nb_mbuf);
> +
> + ice_ctx_vtx(txdp, tx_pkts, nb_mbuf - 1, flags, offload);
> + tx_pkts += nb_mbuf - 1;
> + txdp += n - 2;
> + ice_ctx_vtx1(txdp, *tx_pkts++, rs, offload);
> +
> + nb_commit = (uint16_t)(nb_commit - n);
> + txq->tx_next_rs = (uint16_t)(txq->tx_rs_thresh - 1);
> + tx_id = 0;
> + txdp = txq->ci_tx_ring;
> + txep = txq->sw_ring_vec;
> + }
> +
> + nb_mbuf = nb_commit >> 1;
> + ci_tx_backlog_entry_vec(txep, tx_pkts, nb_mbuf);
> + ice_ctx_vtx(txdp, tx_pkts, nb_mbuf, flags, offload);
> + tx_id = (uint16_t)(tx_id + nb_commit);
> +
> + if (tx_id > txq->tx_next_rs) {
> + txq->ci_tx_ring[txq->tx_next_rs].cmd_type_offset_bsz |=
> + rte_cpu_to_le_64((uint64_t)CI_TX_DESC_CMD_RS << CI_TXD_QW1_CMD_S);
> + txq->tx_next_rs = (uint16_t)(txq->tx_next_rs + txq->tx_rs_thresh);
> + }
> +
> + txq->tx_tail = tx_id;
> + ICE_PCI_REG_WC_WRITE(txq->qtx_tail, txq->tx_tail);
> +
> + return nb_pkts;
> +}
> +
> +static inline uint16_t
> +ice_xmit_pkts_vec_avx2_ctx_common(void *tx_queue, struct rte_mbuf **tx_pkts,
> + uint16_t nb_pkts, bool offload)
> +{
> + struct ci_tx_queue *txq = tx_queue;
> + uint16_t nb_tx = 0;
> +
> + while (nb_pkts) {
> + const uint16_t num = RTE_MIN(nb_pkts, txq->tx_rs_thresh >> 1);
> + const uint16_t ret = ice_xmit_fixed_burst_vec_avx2_ctx(tx_queue,
> + &tx_pkts[nb_tx], num, offload);
> +
> + nb_tx += ret;
> + nb_pkts -= ret;
> + if (ret < num)
> + break;
> + }
> +
> + return nb_tx;
> +}
> +
> +uint16_t
> +ice_xmit_pkts_vec_avx2_ctx_offload(void *tx_queue,
> + struct rte_mbuf **tx_pkts, uint16_t nb_pkts)
> +{
> + return ice_xmit_pkts_vec_avx2_ctx_common(tx_queue, tx_pkts, nb_pkts, true);
> +}
> +
> static __rte_always_inline uint16_t
> ice_xmit_fixed_burst_vec_avx2(void *tx_queue, struct rte_mbuf **tx_pkts,
> uint16_t nb_pkts, bool offload)
> --
> 2.34.1
>
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 2/4] net/ice: add vector tunnel context encoding
2026-08-24 10:21 ` [PATCH 2/4] net/ice: add vector tunnel context encoding Anurag Mandal
2026-08-24 14:37 ` Bruce Richardson
@ 2026-08-24 14:51 ` David Marchand
2026-08-24 14:57 ` Bruce Richardson
1 sibling, 1 reply; 15+ messages in thread
From: David Marchand @ 2026-08-24 14:51 UTC (permalink / raw)
To: Anurag Mandal, bruce.richardson; +Cc: dev, anatoly.burakov
On Mon, 24 Aug 2026 at 12:23, Anurag Mandal <anurag.mandal@intel.com> wrote:
>
> Added helpers to encode tunnel context descriptors,
> and checksum offsets.
>
> Signed-off-by: Anurag Mandal <anurag.mandal@intel.com>
> ---
> drivers/net/intel/ice/ice_rxtx_vec_common.h | 53 ++++++++++++++++++++-
> 1 file changed, 51 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/net/intel/ice/ice_rxtx_vec_common.h b/drivers/net/intel/ice/ice_rxtx_vec_common.h
> index 1d83a087cc..b84456357f 100644
> --- a/drivers/net/intel/ice/ice_rxtx_vec_common.h
> +++ b/drivers/net/intel/ice/ice_rxtx_vec_common.h
> @@ -123,8 +123,12 @@ ice_txd_enable_offload(struct rte_mbuf *tx_pkt,
>
> /* Tx Checksum Offload */
> /* SET MACLEN */
> - td_offset |= (tx_pkt->l2_len >> 1) <<
> - CI_TX_DESC_LEN_MACLEN_S;
> + if (ol_flags & RTE_MBUF_F_TX_TUNNEL_MASK)
> + td_offset |= (tx_pkt->outer_l2_len >> 1) <<
> + CI_TX_DESC_LEN_MACLEN_S;
> + else
> + td_offset |= (tx_pkt->l2_len >> 1) <<
> + CI_TX_DESC_LEN_MACLEN_S;
>
> /* Enable L3 checksum offload */
> if (ol_flags & RTE_MBUF_F_TX_IP_CKSUM) {
> @@ -172,4 +176,49 @@ ice_txd_enable_offload(struct rte_mbuf *tx_pkt,
>
> *txd_hi |= ((uint64_t)td_cmd) << CI_TXD_QW1_CMD_S;
> }
> +
> +static inline uint64_t
> +ice_txd_tunneling_ctx(const struct rte_mbuf *tx_pkt)
> +{
> + const uint64_t ol_flags = tx_pkt->ol_flags;
> + uint64_t ctx = 0;
> +
> + if (!(ol_flags & RTE_MBUF_F_TX_TUNNEL_MASK))
> + return 0;
> +
> + if (ol_flags & RTE_MBUF_F_TX_OUTER_IP_CKSUM)
> + ctx |= ICE_TX_CTX_EIPT_IPV4;
> + else if (ol_flags & RTE_MBUF_F_TX_OUTER_IPV4)
> + ctx |= ICE_TX_CTX_EIPT_IPV4_NO_CSUM;
> + else if (ol_flags & RTE_MBUF_F_TX_OUTER_IPV6)
> + ctx |= ICE_TX_CTX_EIPT_IPV6;
> +
> + ctx |= (uint64_t)(tx_pkt->outer_l3_len >> 2) << ICE_TXD_CTX_QW0_EIPLEN_S;
> +
> + switch (ol_flags & RTE_MBUF_F_TX_TUNNEL_MASK) {
> + case RTE_MBUF_F_TX_TUNNEL_IPIP:
> + break;
> + case RTE_MBUF_F_TX_TUNNEL_VXLAN:
> + case RTE_MBUF_F_TX_TUNNEL_VXLAN_GPE:
> + case RTE_MBUF_F_TX_TUNNEL_GTP:
> + case RTE_MBUF_F_TX_TUNNEL_GENEVE:
> + ctx |= ICE_TXD_CTX_UDP_TUNNELING;
> + break;
> + case RTE_MBUF_F_TX_TUNNEL_GRE:
> + ctx |= ICE_TXD_CTX_GRE_TUNNELING;
> + break;
> + default:
> + PMD_TX_LOG(ERR, "Tunnel type not supported");
> + return ctx;
> + }
> +
> + ctx |= (uint64_t)(tx_pkt->l2_len >> 1) << ICE_TXD_CTX_QW0_NATLEN_S;
> +
> + if ((ctx & ICE_TXD_CTX_QW0_EIPT_M) &&
> + (ctx & ICE_TXD_CTX_UDP_TUNNELING) &&
> + (ol_flags & RTE_MBUF_F_TX_OUTER_UDP_CKSUM))
> + ctx |= ICE_TXD_CTX_QW0_L4T_CS_M;
> +
> + return ctx;
> +}
> #endif
Why copy/paste this code in a new helper?
The scalar path seems to have the same code, simply moving existing
code should be enough, or do I miss something?
Besides, all of this looks really close to the iavf code.
Can this be factorised in drivers/net/intel/common in some way?
--
David Marchand
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH 2/4] net/ice: add vector tunnel context encoding
2026-08-24 14:51 ` David Marchand
@ 2026-08-24 14:57 ` Bruce Richardson
0 siblings, 0 replies; 15+ messages in thread
From: Bruce Richardson @ 2026-08-24 14:57 UTC (permalink / raw)
To: David Marchand; +Cc: Anurag Mandal, dev, anatoly.burakov
On Mon, Aug 24, 2026 at 04:51:11PM +0200, David Marchand wrote:
> On Mon, 24 Aug 2026 at 12:23, Anurag Mandal <anurag.mandal@intel.com> wrote:
> >
> > Added helpers to encode tunnel context descriptors,
> > and checksum offsets.
> >
> > Signed-off-by: Anurag Mandal <anurag.mandal@intel.com>
> > ---
> > drivers/net/intel/ice/ice_rxtx_vec_common.h | 53 ++++++++++++++++++++-
> > 1 file changed, 51 insertions(+), 2 deletions(-)
> >
> > diff --git a/drivers/net/intel/ice/ice_rxtx_vec_common.h b/drivers/net/intel/ice/ice_rxtx_vec_common.h
> > index 1d83a087cc..b84456357f 100644
> > --- a/drivers/net/intel/ice/ice_rxtx_vec_common.h
> > +++ b/drivers/net/intel/ice/ice_rxtx_vec_common.h
> > @@ -123,8 +123,12 @@ ice_txd_enable_offload(struct rte_mbuf *tx_pkt,
> >
> > /* Tx Checksum Offload */
> > /* SET MACLEN */
> > - td_offset |= (tx_pkt->l2_len >> 1) <<
> > - CI_TX_DESC_LEN_MACLEN_S;
> > + if (ol_flags & RTE_MBUF_F_TX_TUNNEL_MASK)
> > + td_offset |= (tx_pkt->outer_l2_len >> 1) <<
> > + CI_TX_DESC_LEN_MACLEN_S;
> > + else
> > + td_offset |= (tx_pkt->l2_len >> 1) <<
> > + CI_TX_DESC_LEN_MACLEN_S;
> >
> > /* Enable L3 checksum offload */
> > if (ol_flags & RTE_MBUF_F_TX_IP_CKSUM) {
> > @@ -172,4 +176,49 @@ ice_txd_enable_offload(struct rte_mbuf *tx_pkt,
> >
> > *txd_hi |= ((uint64_t)td_cmd) << CI_TXD_QW1_CMD_S;
> > }
> > +
> > +static inline uint64_t
> > +ice_txd_tunneling_ctx(const struct rte_mbuf *tx_pkt)
> > +{
> > + const uint64_t ol_flags = tx_pkt->ol_flags;
> > + uint64_t ctx = 0;
> > +
> > + if (!(ol_flags & RTE_MBUF_F_TX_TUNNEL_MASK))
> > + return 0;
> > +
> > + if (ol_flags & RTE_MBUF_F_TX_OUTER_IP_CKSUM)
> > + ctx |= ICE_TX_CTX_EIPT_IPV4;
> > + else if (ol_flags & RTE_MBUF_F_TX_OUTER_IPV4)
> > + ctx |= ICE_TX_CTX_EIPT_IPV4_NO_CSUM;
> > + else if (ol_flags & RTE_MBUF_F_TX_OUTER_IPV6)
> > + ctx |= ICE_TX_CTX_EIPT_IPV6;
> > +
> > + ctx |= (uint64_t)(tx_pkt->outer_l3_len >> 2) << ICE_TXD_CTX_QW0_EIPLEN_S;
> > +
> > + switch (ol_flags & RTE_MBUF_F_TX_TUNNEL_MASK) {
> > + case RTE_MBUF_F_TX_TUNNEL_IPIP:
> > + break;
> > + case RTE_MBUF_F_TX_TUNNEL_VXLAN:
> > + case RTE_MBUF_F_TX_TUNNEL_VXLAN_GPE:
> > + case RTE_MBUF_F_TX_TUNNEL_GTP:
> > + case RTE_MBUF_F_TX_TUNNEL_GENEVE:
> > + ctx |= ICE_TXD_CTX_UDP_TUNNELING;
> > + break;
> > + case RTE_MBUF_F_TX_TUNNEL_GRE:
> > + ctx |= ICE_TXD_CTX_GRE_TUNNELING;
> > + break;
> > + default:
> > + PMD_TX_LOG(ERR, "Tunnel type not supported");
> > + return ctx;
> > + }
> > +
> > + ctx |= (uint64_t)(tx_pkt->l2_len >> 1) << ICE_TXD_CTX_QW0_NATLEN_S;
> > +
> > + if ((ctx & ICE_TXD_CTX_QW0_EIPT_M) &&
> > + (ctx & ICE_TXD_CTX_UDP_TUNNELING) &&
> > + (ol_flags & RTE_MBUF_F_TX_OUTER_UDP_CKSUM))
> > + ctx |= ICE_TXD_CTX_QW0_L4T_CS_M;
> > +
> > + return ctx;
> > +}
> > #endif
>
> Why copy/paste this code in a new helper?
> The scalar path seems to have the same code, simply moving existing
> code should be enough, or do I miss something?
>
>
> Besides, all of this looks really close to the iavf code.
> Can this be factorised in drivers/net/intel/common in some way?
>
I was looking at that myself earlier in the summer, and have a half-done
prototype lying around somewhere. There are enough inconsistentencies in
the implementations to be annoying, and the options for VLAN tag placement
I remember struggling with a bit too.
In short, it's being looked at, but maybe not this release....
/Bruce
^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH v2 0/4] net/ice: support outer checksum in vector Tx
2026-08-24 10:21 [PATCH 0/4] net/ice: support outer checksum in vector Tx Anurag Mandal
` (3 preceding siblings ...)
2026-08-24 10:21 ` [PATCH 4/4] net/ice: add AVX-512 " Anurag Mandal
@ 2026-08-31 10:35 ` Anurag Mandal
2026-08-31 10:35 ` [PATCH v2 1/4] net/common: share Tx context descriptor flag Anurag Mandal
` (3 more replies)
4 siblings, 4 replies; 15+ messages in thread
From: Anurag Mandal @ 2026-08-31 10:35 UTC (permalink / raw)
To: dev; +Cc: bruce.richardson, anatoly.burakov, Anurag Mandal
V2-changes:
- Addressed Bruce Richardson's comments
- Put the MACLEN assignments on single lines.
- Only encode EIPLEN when an outer IP type (EIPT) was selected,
matching how iavf sets eip_len per protocol case.
- Returned success instead of a partially built context when
the tunnel type is not supported, so a half-completed
context descriptor can never be written.
- Recorded use_ctx and use_vec_entry in one place only. The
duplicate use_vec_entry assignment in ice_tx_queue_start() is
removed; ice_set_tx_function() runs before any queue is started
and now covers every queue, matching iavf. This also fixes DCF
queues, which never passed through ice_tx_queue_start() and so
never had use_vec_entry recorded.
- Declared .ctx_desc = true for the scalar path, which does emit
context descriptors, so it is not filtered out of path selection
when a context descriptor is requested. Matches IAVF_TX_DEFAULT.
- Folded the ctx_desc condition into the req_features initializer.
- Marked the new AVX2 and AVX-512 context Tx helpers
with __rte_always_inline so the compile-time offload flag
is folded, as for the existing ice_vtx()/ice_vtx1() helpers.
Added AVX2 and AVX-512 context descriptor Tx paths
for outer IPv4 and UDP checksum offloads,
avoiding scalar Tx fallback.
Anurag Mandal (4):
net/common: share Tx context descriptor flag
net/ice: add vector tunnel context encoding
net/ice: add AVX2 context descriptor Tx path
net/ice: add AVX-512 context descriptor Tx path
doc/guides/rel_notes/release_26_11.rst | 6 +
drivers/net/intel/common/tx.h | 2 +-
drivers/net/intel/ice/ice_dcf_ethdev.c | 4 +-
drivers/net/intel/ice/ice_ethdev.h | 2 +
drivers/net/intel/ice/ice_rxtx.c | 49 +++++--
drivers/net/intel/ice/ice_rxtx.h | 11 ++
drivers/net/intel/ice/ice_rxtx_vec_avx2.c | 119 +++++++++++++++++
drivers/net/intel/ice/ice_rxtx_vec_avx512.c | 141 ++++++++++++++++++++
drivers/net/intel/ice/ice_rxtx_vec_common.h | 53 +++++++-
9 files changed, 374 insertions(+), 13 deletions(-)
--
2.34.1
^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH v2 1/4] net/common: share Tx context descriptor flag
2026-08-31 10:35 ` [PATCH v2 0/4] net/ice: support outer checksum in vector Tx Anurag Mandal
@ 2026-08-31 10:35 ` Anurag Mandal
2026-08-31 10:35 ` [PATCH v2 2/4] net/ice: add vector tunnel context encoding Anurag Mandal
` (2 subsequent siblings)
3 siblings, 0 replies; 15+ messages in thread
From: Anurag Mandal @ 2026-08-31 10:35 UTC (permalink / raw)
To: dev; +Cc: bruce.richardson, anatoly.burakov, Anurag Mandal
Moved context descriptor state to the common
Tx queue for reuse by ice.
Signed-off-by: Anurag Mandal <anurag.mandal@intel.com>
---
drivers/net/intel/common/tx.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/intel/common/tx.h b/drivers/net/intel/common/tx.h
index 55757d34d7..61ad041065 100644
--- a/drivers/net/intel/common/tx.h
+++ b/drivers/net/intel/common/tx.h
@@ -175,6 +175,7 @@ struct ci_tx_queue {
bool tx_deferred_start; /* don't start this queue in dev start */
bool q_set; /* indicate if tx queue has been configured */
bool use_vec_entry; /* use sw_ring_vec (true for vector and simple paths) */
+ bool use_ctx; /* each packet uses a context and data descriptor */
union { /* the VSI this queue belongs to */
struct i40e_vsi *i40e_vsi;
struct iavf_vsi *iavf_vsi;
@@ -196,7 +197,6 @@ struct ci_tx_queue {
#define IAVF_TX_FLAGS_VLAN_TAG_LOC_L2TAG2 BIT(1)
uint8_t vlan_flag;
uint8_t tc;
- bool use_ctx; /* with ctx info, each pkt needs two descriptors */
bool lldp_enabled;
};
struct { /* ixgbe specific values */
--
2.34.1
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH v2 2/4] net/ice: add vector tunnel context encoding
2026-08-31 10:35 ` [PATCH v2 0/4] net/ice: support outer checksum in vector Tx Anurag Mandal
2026-08-31 10:35 ` [PATCH v2 1/4] net/common: share Tx context descriptor flag Anurag Mandal
@ 2026-08-31 10:35 ` Anurag Mandal
2026-08-31 10:35 ` [PATCH v2 3/4] net/ice: add AVX2 context descriptor Tx path Anurag Mandal
2026-08-31 10:35 ` [PATCH v2 4/4] net/ice: add AVX-512 " Anurag Mandal
3 siblings, 0 replies; 15+ messages in thread
From: Anurag Mandal @ 2026-08-31 10:35 UTC (permalink / raw)
To: dev; +Cc: bruce.richardson, anatoly.burakov, Anurag Mandal
Added helpers to encode tunnel context descriptors,
and checksum offsets.
Signed-off-by: Anurag Mandal <anurag.mandal@intel.com>
---
drivers/net/intel/ice/ice_rxtx_vec_common.h | 53 ++++++++++++++++++++-
1 file changed, 51 insertions(+), 2 deletions(-)
diff --git a/drivers/net/intel/ice/ice_rxtx_vec_common.h b/drivers/net/intel/ice/ice_rxtx_vec_common.h
index 1d83a087cc..30f5245622 100644
--- a/drivers/net/intel/ice/ice_rxtx_vec_common.h
+++ b/drivers/net/intel/ice/ice_rxtx_vec_common.h
@@ -123,8 +123,10 @@ ice_txd_enable_offload(struct rte_mbuf *tx_pkt,
/* Tx Checksum Offload */
/* SET MACLEN */
- td_offset |= (tx_pkt->l2_len >> 1) <<
- CI_TX_DESC_LEN_MACLEN_S;
+ if (ol_flags & RTE_MBUF_F_TX_TUNNEL_MASK)
+ td_offset |= (tx_pkt->outer_l2_len >> 1) << CI_TX_DESC_LEN_MACLEN_S;
+ else
+ td_offset |= (tx_pkt->l2_len >> 1) << CI_TX_DESC_LEN_MACLEN_S;
/* Enable L3 checksum offload */
if (ol_flags & RTE_MBUF_F_TX_IP_CKSUM) {
@@ -172,4 +174,51 @@ ice_txd_enable_offload(struct rte_mbuf *tx_pkt,
*txd_hi |= ((uint64_t)td_cmd) << CI_TXD_QW1_CMD_S;
}
+
+static inline uint64_t
+ice_txd_tunneling_ctx(const struct rte_mbuf *tx_pkt)
+{
+ const uint64_t ol_flags = tx_pkt->ol_flags;
+ uint64_t ctx = 0;
+
+ if (!(ol_flags & RTE_MBUF_F_TX_TUNNEL_MASK))
+ return 0;
+
+ if (ol_flags & RTE_MBUF_F_TX_OUTER_IP_CKSUM)
+ ctx |= ICE_TX_CTX_EIPT_IPV4;
+ else if (ol_flags & RTE_MBUF_F_TX_OUTER_IPV4)
+ ctx |= ICE_TX_CTX_EIPT_IPV4_NO_CSUM;
+ else if (ol_flags & RTE_MBUF_F_TX_OUTER_IPV6)
+ ctx |= ICE_TX_CTX_EIPT_IPV6;
+
+ /* EIPLEN: outer IP header length in DWords, only valid if EIPT is set */
+ if (ctx & ICE_TXD_CTX_QW0_EIPT_M)
+ ctx |= (uint64_t)(tx_pkt->outer_l3_len >> 2) << ICE_TXD_CTX_QW0_EIPLEN_S;
+
+ switch (ol_flags & RTE_MBUF_F_TX_TUNNEL_MASK) {
+ case RTE_MBUF_F_TX_TUNNEL_IPIP:
+ break;
+ case RTE_MBUF_F_TX_TUNNEL_VXLAN:
+ case RTE_MBUF_F_TX_TUNNEL_VXLAN_GPE:
+ case RTE_MBUF_F_TX_TUNNEL_GTP:
+ case RTE_MBUF_F_TX_TUNNEL_GENEVE:
+ ctx |= ICE_TXD_CTX_UDP_TUNNELING;
+ break;
+ case RTE_MBUF_F_TX_TUNNEL_GRE:
+ ctx |= ICE_TXD_CTX_GRE_TUNNELING;
+ break;
+ default:
+ PMD_TX_LOG(ERR, "Tunnel type not supported");
+ return 0;
+ }
+
+ ctx |= (uint64_t)(tx_pkt->l2_len >> 1) << ICE_TXD_CTX_QW0_NATLEN_S;
+
+ if ((ctx & ICE_TXD_CTX_QW0_EIPT_M) &&
+ (ctx & ICE_TXD_CTX_UDP_TUNNELING) &&
+ (ol_flags & RTE_MBUF_F_TX_OUTER_UDP_CKSUM))
+ ctx |= ICE_TXD_CTX_QW0_L4T_CS_M;
+
+ return ctx;
+}
#endif
--
2.34.1
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH v2 3/4] net/ice: add AVX2 context descriptor Tx path
2026-08-31 10:35 ` [PATCH v2 0/4] net/ice: support outer checksum in vector Tx Anurag Mandal
2026-08-31 10:35 ` [PATCH v2 1/4] net/common: share Tx context descriptor flag Anurag Mandal
2026-08-31 10:35 ` [PATCH v2 2/4] net/ice: add vector tunnel context encoding Anurag Mandal
@ 2026-08-31 10:35 ` Anurag Mandal
2026-08-31 10:35 ` [PATCH v2 4/4] net/ice: add AVX-512 " Anurag Mandal
3 siblings, 0 replies; 15+ messages in thread
From: Anurag Mandal @ 2026-08-31 10:35 UTC (permalink / raw)
To: dev; +Cc: bruce.richardson, anatoly.burakov, Anurag Mandal
Added an AVX2 context descriptor path for tunneled
outer IPv4 and UDP checksum offloads.
Signed-off-by: Anurag Mandal <anurag.mandal@intel.com>
---
doc/guides/rel_notes/release_26_11.rst | 5 +
drivers/net/intel/ice/ice_dcf_ethdev.c | 4 +-
drivers/net/intel/ice/ice_ethdev.h | 1 +
drivers/net/intel/ice/ice_rxtx.c | 39 +++++--
drivers/net/intel/ice/ice_rxtx.h | 8 ++
drivers/net/intel/ice/ice_rxtx_vec_avx2.c | 119 ++++++++++++++++++++++
6 files changed, 166 insertions(+), 10 deletions(-)
diff --git a/doc/guides/rel_notes/release_26_11.rst b/doc/guides/rel_notes/release_26_11.rst
index 907f9013ff..8ce1875843 100644
--- a/doc/guides/rel_notes/release_26_11.rst
+++ b/doc/guides/rel_notes/release_26_11.rst
@@ -55,6 +55,11 @@ New Features
Also, make sure to start the actual text at the margin.
=======================================================
+* **Updated Intel ice driver.**
+
+ Added an AVX2 Tx path using context descriptors, allowing tunneled outer IPv4
+ and UDP checksum offloads without falling back to scalar Tx.
+
* **Updated Intel iavf driver.**
* Runtime Rx/Tx queue setup is now automatically disabled while a
diff --git a/drivers/net/intel/ice/ice_dcf_ethdev.c b/drivers/net/intel/ice/ice_dcf_ethdev.c
index c78b290b0d..d1cdae6eb9 100644
--- a/drivers/net/intel/ice/ice_dcf_ethdev.c
+++ b/drivers/net/intel/ice/ice_dcf_ethdev.c
@@ -498,7 +498,7 @@ ice_dcf_tx_queue_stop(struct rte_eth_dev *dev, uint16_t tx_queue_id)
}
txq = dev->data->tx_queues[tx_queue_id];
- ci_txq_release_all_mbufs(txq, false);
+ ci_txq_release_all_mbufs(txq, txq->use_ctx);
reset_tx_queue(txq);
dev->data->tx_queue_state[tx_queue_id] = RTE_ETH_QUEUE_STATE_STOPPED;
@@ -648,7 +648,7 @@ ice_dcf_stop_queues(struct rte_eth_dev *dev)
txq = dev->data->tx_queues[i];
if (!txq)
continue;
- ci_txq_release_all_mbufs(txq, false);
+ ci_txq_release_all_mbufs(txq, txq->use_ctx);
reset_tx_queue(txq);
dev->data->tx_queue_state[i] = RTE_ETH_QUEUE_STATE_STOPPED;
}
diff --git a/drivers/net/intel/ice/ice_ethdev.h b/drivers/net/intel/ice/ice_ethdev.h
index 7ee3ea8a70..0e74f8d776 100644
--- a/drivers/net/intel/ice/ice_ethdev.h
+++ b/drivers/net/intel/ice/ice_ethdev.h
@@ -213,6 +213,7 @@ enum ice_tx_func_type {
ICE_TX_SIMPLE,
ICE_TX_AVX2,
ICE_TX_AVX2_OFFLOAD,
+ ICE_TX_AVX2_CTX_OFFLOAD,
ICE_TX_AVX512,
ICE_TX_AVX512_OFFLOAD,
ICE_TX_NEON,
diff --git a/drivers/net/intel/ice/ice_rxtx.c b/drivers/net/intel/ice/ice_rxtx.c
index c4b5454c53..7e83541f5d 100644
--- a/drivers/net/intel/ice/ice_rxtx.c
+++ b/drivers/net/intel/ice/ice_rxtx.c
@@ -793,7 +793,6 @@ ice_tx_queue_start(struct rte_eth_dev *dev, uint16_t tx_queue_id)
struct ice_aqc_add_tx_qgrp *txq_elem;
struct ice_tlan_ctx tx_ctx;
int buf_len;
- struct ice_adapter *ad = ICE_DEV_PRIVATE_TO_ADAPTER(dev->data->dev_private);
u16 q_base, q_range, cgd_idx = 0;
PMD_INIT_FUNC_TRACE();
@@ -881,9 +880,6 @@ ice_tx_queue_start(struct rte_eth_dev *dev, uint16_t tx_queue_id)
return -EIO;
}
- /* record what kind of descriptor cleanup we need on teardown */
- txq->use_vec_entry = ad->tx_vec_allowed || ad->tx_simple_allowed;
-
if (txq->tsq != NULL && txq->tsq->ts_flag > 0) {
struct ice_aqc_set_txtime_qgrp *ts_elem;
struct ice_txtime_ctx txtime_ctx = { 0 };
@@ -1193,7 +1189,7 @@ ice_tx_queue_stop(struct rte_eth_dev *dev, uint16_t tx_queue_id)
return -EINVAL;
}
- ci_txq_release_all_mbufs(txq, false);
+ ci_txq_release_all_mbufs(txq, txq->use_ctx);
ice_reset_tx_queue(txq);
dev->data->tx_queue_state[tx_queue_id] = RTE_ETH_QUEUE_STATE_STOPPED;
@@ -1256,7 +1252,7 @@ ice_fdir_tx_queue_stop(struct rte_eth_dev *dev, uint16_t tx_queue_id)
return -EINVAL;
}
- ci_txq_release_all_mbufs(txq, false);
+ ci_txq_release_all_mbufs(txq, txq->use_ctx);
txq->qtx_tail = NULL;
return 0;
@@ -1744,7 +1740,7 @@ ice_tx_queue_release(void *txq)
return;
}
- ci_txq_release_all_mbufs(q, false);
+ ci_txq_release_all_mbufs(q, q->use_ctx);
rte_free(q->sw_ring);
rte_free(q->rs_last_id);
if (q->tsq) {
@@ -3522,7 +3518,8 @@ static const struct ci_tx_path_info ice_tx_path_infos[] = {
.pkt_burst = ice_xmit_pkts,
.info = "Scalar",
.features = {
- .tx_offloads = ICE_TX_SCALAR_OFFLOADS
+ .tx_offloads = ICE_TX_SCALAR_OFFLOADS,
+ .ctx_desc = true
},
.pkt_prep = ice_prep_pkts
},
@@ -3554,6 +3551,16 @@ static const struct ci_tx_path_info ice_tx_path_infos[] = {
},
.pkt_prep = ice_prep_pkts
},
+ [ICE_TX_AVX2_CTX_OFFLOAD] = {
+ .pkt_burst = ice_xmit_pkts_vec_avx2_ctx_offload,
+ .info = "Context Offload Vector AVX2",
+ .features = {
+ .tx_offloads = ICE_TX_VECTOR_CTX_OFFLOAD_OFFLOADS,
+ .simd_width = RTE_VECT_SIMD_256,
+ .ctx_desc = true
+ },
+ .pkt_prep = ice_prep_pkts
+ },
#ifdef CC_AVX512_SUPPORT
[ICE_TX_AVX512] = {
.pkt_burst = ice_xmit_pkts_vec_avx512,
@@ -3755,10 +3762,17 @@ ice_set_tx_function(struct rte_eth_dev *dev)
{
struct ice_adapter *ad =
ICE_DEV_PRIVATE_TO_ADAPTER(dev->data->dev_private);
+ const struct ci_tx_path_features *selected_features;
+ struct ci_tx_queue *txq;
int mbuf_check = ad->devargs.mbuf_check;
+ int i;
struct ci_tx_path_features req_features = {
.tx_offloads = dev->data->dev_conf.txmode.offloads,
.simd_width = RTE_VECT_SIMD_DISABLED,
+ /* outer checksum offloads are only encoded in a context descriptor */
+ .ctx_desc = (dev->data->dev_conf.txmode.offloads &
+ (RTE_ETH_TX_OFFLOAD_OUTER_IPV4_CKSUM |
+ RTE_ETH_TX_OFFLOAD_OUTER_UDP_CKSUM)) != 0,
};
/* If the device has started the function has already been selected. */
@@ -3785,6 +3799,15 @@ ice_set_tx_function(struct rte_eth_dev *dev)
ad->tx_vec_allowed =
(ice_tx_path_infos[ad->tx_func_type].features.simd_width >= RTE_VECT_SIMD_128);
#endif
+ selected_features = &ice_tx_path_infos[ad->tx_func_type].features;
+ for (i = 0; i < dev->data->nb_tx_queues; i++) {
+ txq = dev->data->tx_queues[i];
+ if (!txq)
+ continue;
+ txq->use_ctx = selected_features->ctx_desc;
+ txq->use_vec_entry = selected_features->simple_tx ||
+ selected_features->simd_width >= RTE_VECT_SIMD_128;
+ }
dev->tx_pkt_burst = mbuf_check ? ice_xmit_pkts_check :
ice_tx_path_infos[ad->tx_func_type].pkt_burst;
diff --git a/drivers/net/intel/ice/ice_rxtx.h b/drivers/net/intel/ice/ice_rxtx.h
index 999b6b30d6..37e346fe39 100644
--- a/drivers/net/intel/ice/ice_rxtx.h
+++ b/drivers/net/intel/ice/ice_rxtx.h
@@ -136,6 +136,11 @@
RTE_ETH_TX_OFFLOAD_TCP_CKSUM | \
RTE_ETH_TX_OFFLOAD_SCTP_CKSUM)
+#define ICE_TX_VECTOR_CTX_OFFLOAD_OFFLOADS ( \
+ ICE_TX_VECTOR_OFFLOAD_OFFLOADS | \
+ RTE_ETH_TX_OFFLOAD_OUTER_IPV4_CKSUM | \
+ RTE_ETH_TX_OFFLOAD_OUTER_UDP_CKSUM)
+
/* Max header size can be 2K - 64 bytes */
#define ICE_RX_HDR_BUF_SIZE (2048 - 64)
@@ -284,6 +289,9 @@ uint16_t ice_xmit_pkts_vec_avx2(void *tx_queue, struct rte_mbuf **tx_pkts,
uint16_t nb_pkts);
uint16_t ice_xmit_pkts_vec_avx2_offload(void *tx_queue, struct rte_mbuf **tx_pkts,
uint16_t nb_pkts);
+uint16_t ice_xmit_pkts_vec_avx2_ctx_offload(void *tx_queue,
+ struct rte_mbuf **tx_pkts,
+ uint16_t nb_pkts);
uint16_t ice_recv_pkts_vec_avx512(void *rx_queue, struct rte_mbuf **rx_pkts,
uint16_t nb_pkts);
uint16_t ice_recv_pkts_vec_avx512_offload(void *rx_queue,
diff --git a/drivers/net/intel/ice/ice_rxtx_vec_avx2.c b/drivers/net/intel/ice/ice_rxtx_vec_avx2.c
index b72f69a47b..9bfd18d82b 100644
--- a/drivers/net/intel/ice/ice_rxtx_vec_avx2.c
+++ b/drivers/net/intel/ice/ice_rxtx_vec_avx2.c
@@ -837,6 +837,125 @@ ice_vtx(volatile struct ci_tx_desc *txdp,
}
}
+static __rte_always_inline void
+ice_ctx_vtx1(volatile struct ci_tx_desc *txdp, struct rte_mbuf *pkt,
+ uint64_t flags, bool offload)
+{
+ uint64_t high_data_qw = CI_TX_DESC_DTYPE_DATA |
+ (flags << CI_TXD_QW1_CMD_S) |
+ ((uint64_t)pkt->data_len << CI_TXD_QW1_TX_BUF_SZ_S);
+ const uint64_t low_ctx_qw = offload ? ice_txd_tunneling_ctx(pkt) : 0;
+
+ if (offload)
+ ice_txd_enable_offload(pkt, &high_data_qw);
+
+ const __m256i ctx_data_desc = _mm256_set_epi64x(high_data_qw,
+ rte_pktmbuf_iova(pkt), CI_TX_DESC_DTYPE_CTX, low_ctx_qw);
+
+ _mm256_store_si256(RTE_CAST_PTR(__m256i *, txdp), ctx_data_desc);
+}
+
+static __rte_always_inline void
+ice_ctx_vtx(volatile struct ci_tx_desc *txdp, struct rte_mbuf **pkt,
+ uint16_t nb_pkts, uint64_t flags, bool offload)
+{
+ while (nb_pkts) {
+ ice_ctx_vtx1(txdp, *pkt, flags, offload);
+ txdp += 2;
+ pkt++;
+ nb_pkts--;
+ }
+}
+
+static __rte_always_inline uint16_t
+ice_xmit_fixed_burst_vec_avx2_ctx(void *tx_queue, struct rte_mbuf **tx_pkts,
+ uint16_t nb_pkts, bool offload)
+{
+ struct ci_tx_queue *txq = tx_queue;
+ volatile struct ci_tx_desc *txdp;
+ struct ci_tx_entry_vec *txep;
+ uint16_t n, nb_commit, nb_mbuf, tx_id;
+ const uint64_t flags = CI_TX_DESC_CMD_DEFAULT;
+ const uint64_t rs = CI_TX_DESC_CMD_RS | flags;
+
+ if (txq->nb_tx_free < txq->tx_free_thresh)
+ ci_tx_free_bufs_vec(txq, ice_tx_desc_done, true);
+
+ nb_commit = (uint16_t)RTE_MIN(txq->nb_tx_free,
+ (uint32_t)nb_pkts * 2);
+ nb_commit &= (uint16_t)~1;
+ if (unlikely(nb_commit == 0))
+ return 0;
+
+ nb_pkts = nb_commit >> 1;
+ tx_id = txq->tx_tail;
+ txdp = &txq->ci_tx_ring[tx_id];
+ txep = &txq->sw_ring_vec[tx_id >> 1];
+
+ txq->nb_tx_free = (uint16_t)(txq->nb_tx_free - nb_commit);
+ n = (uint16_t)(txq->nb_tx_desc - tx_id);
+
+ if (nb_commit >= n) {
+ nb_mbuf = n >> 1;
+ ci_tx_backlog_entry_vec(txep, tx_pkts, nb_mbuf);
+
+ ice_ctx_vtx(txdp, tx_pkts, nb_mbuf - 1, flags, offload);
+ tx_pkts += nb_mbuf - 1;
+ txdp += n - 2;
+ ice_ctx_vtx1(txdp, *tx_pkts++, rs, offload);
+
+ nb_commit = (uint16_t)(nb_commit - n);
+ txq->tx_next_rs = (uint16_t)(txq->tx_rs_thresh - 1);
+ tx_id = 0;
+ txdp = txq->ci_tx_ring;
+ txep = txq->sw_ring_vec;
+ }
+
+ nb_mbuf = nb_commit >> 1;
+ ci_tx_backlog_entry_vec(txep, tx_pkts, nb_mbuf);
+ ice_ctx_vtx(txdp, tx_pkts, nb_mbuf, flags, offload);
+ tx_id = (uint16_t)(tx_id + nb_commit);
+
+ if (tx_id > txq->tx_next_rs) {
+ txq->ci_tx_ring[txq->tx_next_rs].cmd_type_offset_bsz |=
+ rte_cpu_to_le_64((uint64_t)CI_TX_DESC_CMD_RS << CI_TXD_QW1_CMD_S);
+ txq->tx_next_rs = (uint16_t)(txq->tx_next_rs + txq->tx_rs_thresh);
+ }
+
+ txq->tx_tail = tx_id;
+ ICE_PCI_REG_WC_WRITE(txq->qtx_tail, txq->tx_tail);
+
+ return nb_pkts;
+}
+
+static __rte_always_inline uint16_t
+ice_xmit_pkts_vec_avx2_ctx_common(void *tx_queue, struct rte_mbuf **tx_pkts,
+ uint16_t nb_pkts, bool offload)
+{
+ struct ci_tx_queue *txq = tx_queue;
+ uint16_t nb_tx = 0;
+
+ while (nb_pkts) {
+ const uint16_t num = RTE_MIN(nb_pkts, txq->tx_rs_thresh >> 1);
+ const uint16_t ret = ice_xmit_fixed_burst_vec_avx2_ctx(tx_queue,
+ &tx_pkts[nb_tx], num, offload);
+
+ nb_tx += ret;
+ nb_pkts -= ret;
+ if (ret < num)
+ break;
+ }
+
+ return nb_tx;
+}
+
+uint16_t
+ice_xmit_pkts_vec_avx2_ctx_offload(void *tx_queue,
+ struct rte_mbuf **tx_pkts, uint16_t nb_pkts)
+{
+ return ice_xmit_pkts_vec_avx2_ctx_common(tx_queue, tx_pkts, nb_pkts, true);
+}
+
static __rte_always_inline uint16_t
ice_xmit_fixed_burst_vec_avx2(void *tx_queue, struct rte_mbuf **tx_pkts,
uint16_t nb_pkts, bool offload)
--
2.34.1
^ permalink raw reply related [flat|nested] 15+ messages in thread
* [PATCH v2 4/4] net/ice: add AVX-512 context descriptor Tx path
2026-08-31 10:35 ` [PATCH v2 0/4] net/ice: support outer checksum in vector Tx Anurag Mandal
` (2 preceding siblings ...)
2026-08-31 10:35 ` [PATCH v2 3/4] net/ice: add AVX2 context descriptor Tx path Anurag Mandal
@ 2026-08-31 10:35 ` Anurag Mandal
3 siblings, 0 replies; 15+ messages in thread
From: Anurag Mandal @ 2026-08-31 10:35 UTC (permalink / raw)
To: dev; +Cc: bruce.richardson, anatoly.burakov, Anurag Mandal
Added an AVX-512 context descriptor path for tunneled
outer IPv4 and UDP checksum offloads.
Signed-off-by: Anurag Mandal <anurag.mandal@intel.com>
---
doc/guides/rel_notes/release_26_11.rst | 5 +-
drivers/net/intel/ice/ice_ethdev.h | 1 +
drivers/net/intel/ice/ice_rxtx.c | 10 ++
drivers/net/intel/ice/ice_rxtx.h | 3 +
drivers/net/intel/ice/ice_rxtx_vec_avx512.c | 141 ++++++++++++++++++++
5 files changed, 158 insertions(+), 2 deletions(-)
diff --git a/doc/guides/rel_notes/release_26_11.rst b/doc/guides/rel_notes/release_26_11.rst
index 8ce1875843..1239f1ab0d 100644
--- a/doc/guides/rel_notes/release_26_11.rst
+++ b/doc/guides/rel_notes/release_26_11.rst
@@ -57,8 +57,9 @@ New Features
* **Updated Intel ice driver.**
- Added an AVX2 Tx path using context descriptors, allowing tunneled outer IPv4
- and UDP checksum offloads without falling back to scalar Tx.
+ * Added AVX2 and AVX-512 context-descriptor Tx paths,
+ enabling outer IPv4 and UDP checksum offloads for
+ tunneled packets without falling back to scalar Tx.
* **Updated Intel iavf driver.**
diff --git a/drivers/net/intel/ice/ice_ethdev.h b/drivers/net/intel/ice/ice_ethdev.h
index 0e74f8d776..00facd48bd 100644
--- a/drivers/net/intel/ice/ice_ethdev.h
+++ b/drivers/net/intel/ice/ice_ethdev.h
@@ -216,6 +216,7 @@ enum ice_tx_func_type {
ICE_TX_AVX2_CTX_OFFLOAD,
ICE_TX_AVX512,
ICE_TX_AVX512_OFFLOAD,
+ ICE_TX_AVX512_CTX_OFFLOAD,
ICE_TX_NEON,
};
diff --git a/drivers/net/intel/ice/ice_rxtx.c b/drivers/net/intel/ice/ice_rxtx.c
index 7e83541f5d..ea43006d79 100644
--- a/drivers/net/intel/ice/ice_rxtx.c
+++ b/drivers/net/intel/ice/ice_rxtx.c
@@ -3580,6 +3580,16 @@ static const struct ci_tx_path_info ice_tx_path_infos[] = {
},
.pkt_prep = ice_prep_pkts
},
+ [ICE_TX_AVX512_CTX_OFFLOAD] = {
+ .pkt_burst = ice_xmit_pkts_vec_avx512_ctx_offload,
+ .info = "Context Offload Vector AVX512",
+ .features = {
+ .tx_offloads = ICE_TX_VECTOR_CTX_OFFLOAD_OFFLOADS,
+ .simd_width = RTE_VECT_SIMD_512,
+ .ctx_desc = true
+ },
+ .pkt_prep = ice_prep_pkts
+ },
#endif
#elif defined(RTE_ARCH_ARM64)
[ICE_TX_NEON] = {
diff --git a/drivers/net/intel/ice/ice_rxtx.h b/drivers/net/intel/ice/ice_rxtx.h
index 37e346fe39..8d6bb0af01 100644
--- a/drivers/net/intel/ice/ice_rxtx.h
+++ b/drivers/net/intel/ice/ice_rxtx.h
@@ -308,6 +308,9 @@ uint16_t ice_xmit_pkts_vec_avx512(void *tx_queue, struct rte_mbuf **tx_pkts,
uint16_t ice_xmit_pkts_vec_avx512_offload(void *tx_queue,
struct rte_mbuf **tx_pkts,
uint16_t nb_pkts);
+uint16_t ice_xmit_pkts_vec_avx512_ctx_offload(void *tx_queue,
+ struct rte_mbuf **tx_pkts,
+ uint16_t nb_pkts);
int ice_fdir_programming(struct ice_pf *pf, struct ice_fltr_desc *fdir_desc);
int ice_tx_done_cleanup(void *txq, uint32_t free_cnt);
int ice_get_monitor_addr(void *rx_queue, struct rte_power_monitor_cond *pmc);
diff --git a/drivers/net/intel/ice/ice_rxtx_vec_avx512.c b/drivers/net/intel/ice/ice_rxtx_vec_avx512.c
index 309ab9fca7..c8c3e103c5 100644
--- a/drivers/net/intel/ice/ice_rxtx_vec_avx512.c
+++ b/drivers/net/intel/ice/ice_rxtx_vec_avx512.c
@@ -901,6 +901,147 @@ ice_vtx(volatile struct ci_tx_desc *txdp, struct rte_mbuf **pkt,
}
}
+static __rte_always_inline void
+ice_ctx_vtx1(volatile struct ci_tx_desc *txdp, struct rte_mbuf *pkt,
+ uint64_t flags, bool offload)
+{
+ uint64_t high_data_qw = CI_TX_DESC_DTYPE_DATA |
+ (flags << CI_TXD_QW1_CMD_S) |
+ ((uint64_t)pkt->data_len << CI_TXD_QW1_TX_BUF_SZ_S);
+ const uint64_t low_ctx_qw = offload ? ice_txd_tunneling_ctx(pkt) : 0;
+
+ if (offload)
+ ice_txd_enable_offload(pkt, &high_data_qw);
+
+ const __m256i ctx_data_desc = _mm256_set_epi64x(high_data_qw,
+ rte_pktmbuf_iova(pkt), CI_TX_DESC_DTYPE_CTX, low_ctx_qw);
+
+ _mm256_store_si256(RTE_CAST_PTR(__m256i *, txdp), ctx_data_desc);
+}
+
+static __rte_always_inline void
+ice_ctx_vtx(volatile struct ci_tx_desc *txdp, struct rte_mbuf **pkt,
+ uint16_t nb_pkts, uint64_t flags, bool offload)
+{
+ while (nb_pkts > 1) {
+ uint64_t high_data_qw1 = CI_TX_DESC_DTYPE_DATA |
+ (flags << CI_TXD_QW1_CMD_S) |
+ ((uint64_t)pkt[1]->data_len << CI_TXD_QW1_TX_BUF_SZ_S);
+ uint64_t high_data_qw0 = CI_TX_DESC_DTYPE_DATA |
+ (flags << CI_TXD_QW1_CMD_S) |
+ ((uint64_t)pkt[0]->data_len << CI_TXD_QW1_TX_BUF_SZ_S);
+ const uint64_t low_ctx_qw1 = offload ? ice_txd_tunneling_ctx(pkt[1]) : 0;
+ const uint64_t low_ctx_qw0 = offload ? ice_txd_tunneling_ctx(pkt[0]) : 0;
+
+ if (offload) {
+ ice_txd_enable_offload(pkt[1], &high_data_qw1);
+ ice_txd_enable_offload(pkt[0], &high_data_qw0);
+ }
+
+ const __m512i ctx_data_desc = _mm512_set_epi64(high_data_qw1,
+ rte_pktmbuf_iova(pkt[1]), CI_TX_DESC_DTYPE_CTX, low_ctx_qw1,
+ high_data_qw0, rte_pktmbuf_iova(pkt[0]),
+ CI_TX_DESC_DTYPE_CTX, low_ctx_qw0);
+
+ _mm512_storeu_si512(RTE_CAST_PTR(void *, txdp), ctx_data_desc);
+ txdp += 4;
+ pkt += 2;
+ nb_pkts -= 2;
+ }
+
+ if (nb_pkts)
+ ice_ctx_vtx1(txdp, *pkt, flags, offload);
+}
+
+static __rte_always_inline uint16_t
+ice_xmit_fixed_burst_vec_avx512_ctx(void *tx_queue, struct rte_mbuf **tx_pkts,
+ uint16_t nb_pkts, bool offload)
+{
+ struct ci_tx_queue *txq = tx_queue;
+ volatile struct ci_tx_desc *txdp;
+ struct ci_tx_entry_vec *txep;
+ uint16_t n, nb_commit, nb_mbuf, tx_id;
+ const uint64_t flags = CI_TX_DESC_CMD_DEFAULT;
+ const uint64_t rs = CI_TX_DESC_CMD_RS | flags;
+
+ if (txq->nb_tx_free < txq->tx_free_thresh)
+ ci_tx_free_bufs_vec(txq, ice_tx_desc_done, true);
+
+ nb_commit = (uint16_t)RTE_MIN(txq->nb_tx_free,
+ (uint32_t)nb_pkts * 2);
+ nb_commit &= (uint16_t)~1;
+ if (unlikely(nb_commit == 0))
+ return 0;
+
+ nb_pkts = nb_commit >> 1;
+ tx_id = txq->tx_tail;
+ txdp = &txq->ci_tx_ring[tx_id];
+ txep = &txq->sw_ring_vec[tx_id >> 1];
+
+ txq->nb_tx_free = (uint16_t)(txq->nb_tx_free - nb_commit);
+ n = (uint16_t)(txq->nb_tx_desc - tx_id);
+
+ if (nb_commit >= n) {
+ nb_mbuf = n >> 1;
+ ci_tx_backlog_entry_vec(txep, tx_pkts, nb_mbuf);
+
+ ice_ctx_vtx(txdp, tx_pkts, nb_mbuf - 1, flags, offload);
+ tx_pkts += nb_mbuf - 1;
+ txdp += n - 2;
+ ice_ctx_vtx1(txdp, *tx_pkts++, rs, offload);
+
+ nb_commit = (uint16_t)(nb_commit - n);
+ txq->tx_next_rs = (uint16_t)(txq->tx_rs_thresh - 1);
+ tx_id = 0;
+ txdp = txq->ci_tx_ring;
+ txep = txq->sw_ring_vec;
+ }
+
+ nb_mbuf = nb_commit >> 1;
+ ci_tx_backlog_entry_vec(txep, tx_pkts, nb_mbuf);
+ ice_ctx_vtx(txdp, tx_pkts, nb_mbuf, flags, offload);
+ tx_id = (uint16_t)(tx_id + nb_commit);
+
+ if (tx_id > txq->tx_next_rs) {
+ txq->ci_tx_ring[txq->tx_next_rs].cmd_type_offset_bsz |=
+ rte_cpu_to_le_64((uint64_t)CI_TX_DESC_CMD_RS << CI_TXD_QW1_CMD_S);
+ txq->tx_next_rs = (uint16_t)(txq->tx_next_rs + txq->tx_rs_thresh);
+ }
+
+ txq->tx_tail = tx_id;
+ ICE_PCI_REG_WC_WRITE(txq->qtx_tail, txq->tx_tail);
+
+ return nb_pkts;
+}
+
+static __rte_always_inline uint16_t
+ice_xmit_pkts_vec_avx512_ctx_common(void *tx_queue, struct rte_mbuf **tx_pkts,
+ uint16_t nb_pkts, bool offload)
+{
+ struct ci_tx_queue *txq = tx_queue;
+ uint16_t nb_tx = 0;
+
+ while (nb_pkts) {
+ const uint16_t num = RTE_MIN(nb_pkts, txq->tx_rs_thresh >> 1);
+ const uint16_t ret = ice_xmit_fixed_burst_vec_avx512_ctx(tx_queue,
+ &tx_pkts[nb_tx], num, offload);
+
+ nb_tx += ret;
+ nb_pkts -= ret;
+ if (ret < num)
+ break;
+ }
+
+ return nb_tx;
+}
+
+uint16_t
+ice_xmit_pkts_vec_avx512_ctx_offload(void *tx_queue,
+ struct rte_mbuf **tx_pkts, uint16_t nb_pkts)
+{
+ return ice_xmit_pkts_vec_avx512_ctx_common(tx_queue, tx_pkts, nb_pkts, true);
+}
+
static __rte_always_inline uint16_t
ice_xmit_fixed_burst_vec_avx512(void *tx_queue, struct rte_mbuf **tx_pkts,
uint16_t nb_pkts, bool do_offload)
--
2.34.1
^ permalink raw reply related [flat|nested] 15+ messages in thread
* RE: [PATCH 3/4] net/ice: add AVX2 context descriptor Tx path
2026-08-24 14:47 ` Bruce Richardson
@ 2026-08-31 10:47 ` Mandal, Anurag
0 siblings, 0 replies; 15+ messages in thread
From: Mandal, Anurag @ 2026-08-31 10:47 UTC (permalink / raw)
To: Richardson, Bruce; +Cc: dev@dpdk.org, Burakov, Anatoly
[-- Attachment #1: Type: text/plain, Size: 21408 bytes --]
> -----Original Message-----
> From: Richardson, Bruce <bruce.richardson@intel.com>
> Sent: 24 August 2026 20:17
> To: Mandal, Anurag <anurag.mandal@intel.com>
> Cc: dev@dpdk.org; Burakov, Anatoly <anatoly.burakov@intel.com>
> Subject: Re: [PATCH 3/4] net/ice: add AVX2 context descriptor Tx path
>
> On Mon, Aug 24, 2026 at 10:21:53AM +0000, Anurag Mandal wrote:
> > Added an AVX2 context descriptor path for tunneled outer IPv4 and UDP
> > checksum offloads.
> >
> > Signed-off-by: Anurag Mandal <anurag.mandal@intel.com<mailto:anurag.mandal@intel.com>>
> > ---
> > doc/guides/rel_notes/release_26_11.rst | 5 +
> > drivers/net/intel/ice/ice_dcf_ethdev.c | 4 +-
> > drivers/net/intel/ice/ice_ethdev.h | 1 +
> > drivers/net/intel/ice/ice_rxtx.c | 31 +++++-
> > drivers/net/intel/ice/ice_rxtx.h | 8 ++
> > drivers/net/intel/ice/ice_rxtx_vec_avx2.c | 119
> > ++++++++++++++++++++++
> > 6 files changed, 163 insertions(+), 5 deletions(-)
> >
>
> I asked AI to take a look at this patch and review it by comparison to the
> existing iavf driver. Here's the output, most of which seems relevant. [It also is
> flagging an alignment change that could be fixed in iavf driver, but that is a
> separate, minor issue]
>
> Please review feedback below for a new revision. Ideally, I'd like to keep the ice
> implementation as aligned as possible to the iavf one, so we can merge those
> code paths in future.
>
> /Bruce
>
> Review: net/ice: add AVX2 context descriptor Tx path Errors
> ice_tx_queue_start does not set use_ctx, so runtime-added queues get the
> wrong value.
>
> ice_set_tx_function iterates all existing queues and sets use_ctx. However,
> ice_tx_queue_start (called via rte_eth_tx_queue_start) does not set use_ctx. A
> queue added at runtime after device start will have use_ctx = false while the
> device burst function (ice_xmit_pkts_vec_avx2_ctx_offload)
> treats every queue as using context descriptors. When that queue is stopped
> or released, ci_txq_release_all_mbufs(txq, txq->use_ctx) with use_ctx = false
> iterates physical descriptor indices into sw_ring_vec, which is sized at
> nb_tx_desc / 2 — producing an out-of-bounds read on the sw_ring_vec array.
>
>
> iavf avoids this by checking txq->use_ctx in the Tx burst path itself (it's set at
> configure time from the per-queue IAVF_TX_OFFLOAD_CTX flag). The ice
> implementation sets it only once globally.
>
> Warnings
> Outer IPv6 tunneling (without checksum offload) skips the context descriptor
> path.
>
> req_features.ctx_desc is set only when
> RTE_ETH_TX_OFFLOAD_OUTER_IPV4_CKSUM
> or RTE_ETH_TX_OFFLOAD_OUTER_UDP_CKSUM is configured. An application
> that only uses outer-IPv6 tunneling (no outer cksum offload needed) will not
> select ICE_TX_AVX2_CTX_OFFLOAD, and the hardware will receive no context
> descriptor with the tunnel type or outer IP type — even though
> ice_txd_tunneling_ctx would encode them correctly. iavf triggers use_ctx on
> any per-packet RTE_MBUF_F_TX_TUNNEL_MASK flag at the burst entry,
> regardless of device-level offload configuration. Whether ice hardware needs
> the context descriptor for outer IPv6 tunnels at all is hardware-dependent and
> should be documented or validated.
>
> No validation that tx_rs_thresh is adequate for 2-descriptor-per-packet mode.
>
> ice_tx_vec_queue_default enforces tx_rs_thresh >= ICE_VPMD_TX_BURST
> (32).
> In ctx mode, each batch handles tx_rs_thresh >> 1 packets. With tx_rs_thresh =
> 32, that's 16 packets per burst. No check ensures this is above a meaningful
> minimum. This is a weak warning — the current minimum
> (16 packets) is still functional — but it's worth a comment.
>
> Implementation Comparison (new ctx path vs iavf)
> Aspect ice (ice_ctx_vtx1) iavf (ctx_vtx1)
> 256-bit store _mm256_store_si256 (aligned)
> _mm256_storeu_si256 (unaligned)
> Context desc high word CI_TX_DESC_DTYPE_CTX only DTYPE_CONTEXT +
> optional IL2TAG2/LLDP bits
> VLAN QinQ support Not handled in ctx path Handled in ctx
> descriptor
> ctx_desc triggering Device-level offload flags Per-packet ol_flags at
> burst entry
> use_ctx set per-queue Only in ice_set_tx_function (device start) Also
> maintained per-queue in setup
>
> The use of _mm256_store_si256 (aligned) is consistent with the existing non-
> ctx ice_vtx loop which also uses aligned stores, and is safe because descriptor
> rings are cache-line aligned and tx_id is always even in ctx mode.
>
Hi Bruce,
I have sent v2. Also, have following comments w.r.t. comparisons between ice and iavf.
1. Aligned vs unaligned store:- It is safe in ice because ctx mode keeps tx_id even, so txdp is always 32-byte aligned, and it matches the existing ice_vtx()/ice_vtx1(). iavf uses storeu plus an explicit "if unaligned, do one to align" prologue in ctx_vtx() — that prologue is dead code inherited from the non-ctx path, since iavf's ctx mode also guarantees even tx_id. If anything, iavf should adopt ice's form, not the reverse. Note the AVX-512 ice_ctx_vtx() does use _mm512_storeu_si512, correctly, since a 4-descriptor group is only 32-byte aligned.
2. Context descriptor high word:- The extra bits iavf sets have no ice PF equivalent: SWTCH_UPLINK/LLDP is a VF-specific devarg, and IL2TAG2 is only needed for the L2TAG2 VLAN insertion mode that iavf negotiates over virtchnl. ice's vector path inserts VLAN via IL2TAG1 in the data descriptor in ice_txd_enable_offload(). ice also uses the common CI_TX_DESC_DTYPE_CTX rather than a driver-local DTYPE_CONTEXT, so it is ahead of iavf on the merge path here.
3. QinQ:- RTE_ETH_TX_OFFLOAD_QINQ_INSERT is deliberately absent from ICE_TX_VECTOR_CTX_OFFLOAD_OFFLOADS, so requesting QinQ falls back to scalar, which handles it. It is in ICE_TX_SCALAR_OFFLOADS and advertised in dev_info, so nothing is silently dropped.
Adding QinQ to the ctx path is a reasonable follow-up patch separately.
4. ctx_desc triggering — iavf does not inspect per-packet ol_flags at burst entry. iavf_xmit_pkts_vec_avx512_ctx_offload() → iavf_xmit_pkts_vec_avx512_ctx_cmn() just loops on tx_rs_thresh and writes a context descriptor for every packet unconditionally. Selection is entirely device-level in iavf_rxtx.c:3936: offload matching via IAVF_TX_VECTOR_CTX_OFFLOAD_OFFLOADS, plus req_features.ctx_desc = true for the LLDP devarg and the per-queue L2TAG2 VLAN case. ice uses the same mechanism; there is nothing to align.
5. use_ctx per-queue — iavf sets use_ctx in exactly one place, the “out:” block of “iavf_set_tx_function()”; it is never touched in queue setup. The only real inconsistency was on the ice side, where use_vec_entry was separately re-recorded in ice_tx_queue_start(), and that duplicate is removed in the revision I sent now.
Thanks,
Anurag
> > diff --git a/doc/guides/rel_notes/release_26_11.rst
> > b/doc/guides/rel_notes/release_26_11.rst
> > index 907f9013ff..8ce1875843 100644
> > --- a/doc/guides/rel_notes/release_26_11.rst
> > +++ b/doc/guides/rel_notes/release_26_11.rst
> > @@ -55,6 +55,11 @@ New Features
> > Also, make sure to start the actual text at the margin.
> > =======================================================
> >
> > +* **Updated Intel ice driver.**
> > +
> > + Added an AVX2 Tx path using context descriptors, allowing tunneled
> > + outer IPv4 and UDP checksum offloads without falling back to scalar Tx.
> > +
> > * **Updated Intel iavf driver.**
> >
> > * Runtime Rx/Tx queue setup is now automatically disabled while a
> > diff --git a/drivers/net/intel/ice/ice_dcf_ethdev.c
> > b/drivers/net/intel/ice/ice_dcf_ethdev.c
> > index c78b290b0d..d1cdae6eb9 100644
> > --- a/drivers/net/intel/ice/ice_dcf_ethdev.c
> > +++ b/drivers/net/intel/ice/ice_dcf_ethdev.c
> > @@ -498,7 +498,7 @@ ice_dcf_tx_queue_stop(struct rte_eth_dev *dev,
> uint16_t tx_queue_id)
> > }
> >
> > txq = dev->data->tx_queues[tx_queue_id];
> > - ci_txq_release_all_mbufs(txq, false);
> > + ci_txq_release_all_mbufs(txq, txq->use_ctx);
> > reset_tx_queue(txq);
> > dev->data->tx_queue_state[tx_queue_id] =
> > RTE_ETH_QUEUE_STATE_STOPPED;
> >
> > @@ -648,7 +648,7 @@ ice_dcf_stop_queues(struct rte_eth_dev *dev)
> > txq = dev->data->tx_queues[i];
> > if (!txq)
> > continue;
> > - ci_txq_release_all_mbufs(txq, false);
> > + ci_txq_release_all_mbufs(txq, txq->use_ctx);
> > reset_tx_queue(txq);
> > dev->data->tx_queue_state[i] =
> RTE_ETH_QUEUE_STATE_STOPPED;
> > }
> > diff --git a/drivers/net/intel/ice/ice_ethdev.h
> > b/drivers/net/intel/ice/ice_ethdev.h
> > index 7ee3ea8a70..0e74f8d776 100644
> > --- a/drivers/net/intel/ice/ice_ethdev.h
> > +++ b/drivers/net/intel/ice/ice_ethdev.h
> > @@ -213,6 +213,7 @@ enum ice_tx_func_type {
> > ICE_TX_SIMPLE,
> > ICE_TX_AVX2,
> > ICE_TX_AVX2_OFFLOAD,
> > + ICE_TX_AVX2_CTX_OFFLOAD,
> > ICE_TX_AVX512,
> > ICE_TX_AVX512_OFFLOAD,
> > ICE_TX_NEON,
> > diff --git a/drivers/net/intel/ice/ice_rxtx.c
> > b/drivers/net/intel/ice/ice_rxtx.c
> > index c4b5454c53..5ec0b4d1fd 100644
> > --- a/drivers/net/intel/ice/ice_rxtx.c
> > +++ b/drivers/net/intel/ice/ice_rxtx.c
> > @@ -1193,7 +1193,7 @@ ice_tx_queue_stop(struct rte_eth_dev *dev,
> uint16_t tx_queue_id)
> > return -EINVAL;
> > }
> >
> > - ci_txq_release_all_mbufs(txq, false);
> > + ci_txq_release_all_mbufs(txq, txq->use_ctx);
> > ice_reset_tx_queue(txq);
> > dev->data->tx_queue_state[tx_queue_id] =
> > RTE_ETH_QUEUE_STATE_STOPPED;
> >
> > @@ -1256,7 +1256,7 @@ ice_fdir_tx_queue_stop(struct rte_eth_dev *dev,
> uint16_t tx_queue_id)
> > return -EINVAL;
> > }
> >
> > - ci_txq_release_all_mbufs(txq, false);
> > + ci_txq_release_all_mbufs(txq, txq->use_ctx);
> > txq->qtx_tail = NULL;
> >
> > return 0;
> > @@ -1744,7 +1744,7 @@ ice_tx_queue_release(void *txq)
> > return;
> > }
> >
> > - ci_txq_release_all_mbufs(q, false);
> > + ci_txq_release_all_mbufs(q, q->use_ctx);
> > rte_free(q->sw_ring);
> > rte_free(q->rs_last_id);
> > if (q->tsq) {
> > @@ -3554,6 +3554,16 @@ static const struct ci_tx_path_info
> ice_tx_path_infos[] = {
> > },
> > .pkt_prep = ice_prep_pkts
> > },
> > + [ICE_TX_AVX2_CTX_OFFLOAD] = {
> > + .pkt_burst = ice_xmit_pkts_vec_avx2_ctx_offload,
> > + .info = "Context Offload Vector AVX2",
> > + .features = {
> > + .tx_offloads =
> ICE_TX_VECTOR_CTX_OFFLOAD_OFFLOADS,
> > + .simd_width = RTE_VECT_SIMD_256,
> > + .ctx_desc = true
> > + },
> > + .pkt_prep = ice_prep_pkts
> > + },
> > #ifdef CC_AVX512_SUPPORT
> > [ICE_TX_AVX512] = {
> > .pkt_burst = ice_xmit_pkts_vec_avx512, @@ -3755,11
> +3765,17 @@
> > ice_set_tx_function(struct rte_eth_dev *dev) {
> > struct ice_adapter *ad =
> > ICE_DEV_PRIVATE_TO_ADAPTER(dev->data->dev_private);
> > + const struct ci_tx_path_features *selected_features;
> > + struct ci_tx_queue *txq;
> > int mbuf_check = ad->devargs.mbuf_check;
> > + int i;
> > struct ci_tx_path_features req_features = {
> > .tx_offloads = dev->data->dev_conf.txmode.offloads,
> > .simd_width = RTE_VECT_SIMD_DISABLED,
> > };
> > + req_features.ctx_desc = req_features.tx_offloads &
> > + (RTE_ETH_TX_OFFLOAD_OUTER_IPV4_CKSUM |
> > + RTE_ETH_TX_OFFLOAD_OUTER_UDP_CKSUM);
> >
> > /* If the device has started the function has already been selected. */
> > if (dev->data->dev_started)
> > @@ -3785,6 +3801,15 @@ ice_set_tx_function(struct rte_eth_dev *dev)
> > ad->tx_vec_allowed =
> > (ice_tx_path_infos[ad->tx_func_type].features.simd_width >=
> > RTE_VECT_SIMD_128); #endif
> > + selected_features = &ice_tx_path_infos[ad->tx_func_type].features;
> > + for (i = 0; i < dev->data->nb_tx_queues; i++) {
> > + txq = dev->data->tx_queues[i];
> > + if (!txq)
> > + continue;
> > + txq->use_ctx = selected_features->ctx_desc;
> > + txq->use_vec_entry = selected_features->simple_tx ||
> > + selected_features->simd_width >=
> RTE_VECT_SIMD_128;
> > + }
> >
> > dev->tx_pkt_burst = mbuf_check ? ice_xmit_pkts_check :
> > ice_tx_path_infos[ad-
> >tx_func_type].pkt_burst;
> > diff --git a/drivers/net/intel/ice/ice_rxtx.h
> > b/drivers/net/intel/ice/ice_rxtx.h
> > index 999b6b30d6..37e346fe39 100644
> > --- a/drivers/net/intel/ice/ice_rxtx.h
> > +++ b/drivers/net/intel/ice/ice_rxtx.h
> > @@ -136,6 +136,11 @@
> > RTE_ETH_TX_OFFLOAD_TCP_CKSUM | \
> > RTE_ETH_TX_OFFLOAD_SCTP_CKSUM)
> >
> > +#define ICE_TX_VECTOR_CTX_OFFLOAD_OFFLOADS ( \
> > + ICE_TX_VECTOR_OFFLOAD_OFFLOADS | \
> > + RTE_ETH_TX_OFFLOAD_OUTER_IPV4_CKSUM | \
> > + RTE_ETH_TX_OFFLOAD_OUTER_UDP_CKSUM)
> > +
> > /* Max header size can be 2K - 64 bytes */
> > #define ICE_RX_HDR_BUF_SIZE (2048 - 64)
> >
> > @@ -284,6 +289,9 @@ uint16_t ice_xmit_pkts_vec_avx2(void *tx_queue,
> struct rte_mbuf **tx_pkts,
> > uint16_t nb_pkts);
> > uint16_t ice_xmit_pkts_vec_avx2_offload(void *tx_queue, struct rte_mbuf
> **tx_pkts,
> > uint16_t nb_pkts);
> > +uint16_t ice_xmit_pkts_vec_avx2_ctx_offload(void *tx_queue,
> > + struct rte_mbuf **tx_pkts,
> > + uint16_t nb_pkts);
> > uint16_t ice_recv_pkts_vec_avx512(void *rx_queue, struct rte_mbuf
> **rx_pkts,
> > uint16_t nb_pkts);
> > uint16_t ice_recv_pkts_vec_avx512_offload(void *rx_queue, diff --git
> > a/drivers/net/intel/ice/ice_rxtx_vec_avx2.c
> > b/drivers/net/intel/ice/ice_rxtx_vec_avx2.c
> > index b72f69a47b..88a3dfb1b6 100644
> > --- a/drivers/net/intel/ice/ice_rxtx_vec_avx2.c
> > +++ b/drivers/net/intel/ice/ice_rxtx_vec_avx2.c
> > @@ -837,6 +837,125 @@ ice_vtx(volatile struct ci_tx_desc *txdp,
> > }
> > }
> >
> > +static inline void
> > +ice_ctx_vtx1(volatile struct ci_tx_desc *txdp, struct rte_mbuf *pkt,
> > + uint64_t flags, bool offload)
> > +{
> > + uint64_t high_data_qw = CI_TX_DESC_DTYPE_DATA |
> > + (flags << CI_TXD_QW1_CMD_S) |
> > + ((uint64_t)pkt->data_len <<
> CI_TXD_QW1_TX_BUF_SZ_S);
> > + const uint64_t low_ctx_qw = offload ? ice_txd_tunneling_ctx(pkt) :
> > +0;
> > +
> > + if (offload)
> > + ice_txd_enable_offload(pkt, &high_data_qw);
> > +
> > + const __m256i ctx_data_desc = _mm256_set_epi64x(high_data_qw,
> > + rte_pktmbuf_iova(pkt), CI_TX_DESC_DTYPE_CTX,
> low_ctx_qw);
> > +
> > + _mm256_store_si256(RTE_CAST_PTR(__m256i *, txdp),
> ctx_data_desc); }
> > +
> > +static inline void
> > +ice_ctx_vtx(volatile struct ci_tx_desc *txdp, struct rte_mbuf **pkt,
> > + uint16_t nb_pkts, uint64_t flags, bool offload) {
> > + while (nb_pkts) {
> > + ice_ctx_vtx1(txdp, *pkt, flags, offload);
> > + txdp += 2;
> > + pkt++;
> > + nb_pkts--;
> > + }
> > +}
> > +
> > +static inline uint16_t
> > +ice_xmit_fixed_burst_vec_avx2_ctx(void *tx_queue, struct rte_mbuf
> **tx_pkts,
> > + uint16_t nb_pkts, bool offload) {
> > + struct ci_tx_queue *txq = tx_queue;
> > + volatile struct ci_tx_desc *txdp;
> > + struct ci_tx_entry_vec *txep;
> > + uint16_t n, nb_commit, nb_mbuf, tx_id;
> > + const uint64_t flags = CI_TX_DESC_CMD_DEFAULT;
> > + const uint64_t rs = CI_TX_DESC_CMD_RS | flags;
> > +
> > + if (txq->nb_tx_free < txq->tx_free_thresh)
> > + ci_tx_free_bufs_vec(txq, ice_tx_desc_done, true);
> > +
> > + nb_commit = (uint16_t)RTE_MIN(txq->nb_tx_free,
> > + (uint32_t)nb_pkts * 2);
> > + nb_commit &= (uint16_t)~1;
> > + if (unlikely(nb_commit == 0))
> > + return 0;
> > +
> > + nb_pkts = nb_commit >> 1;
> > + tx_id = txq->tx_tail;
> > + txdp = &txq->ci_tx_ring[tx_id];
> > + txep = &txq->sw_ring_vec[tx_id >> 1];
> > +
> > + txq->nb_tx_free = (uint16_t)(txq->nb_tx_free - nb_commit);
> > + n = (uint16_t)(txq->nb_tx_desc - tx_id);
> > +
> > + if (nb_commit >= n) {
> > + nb_mbuf = n >> 1;
> > + ci_tx_backlog_entry_vec(txep, tx_pkts, nb_mbuf);
> > +
> > + ice_ctx_vtx(txdp, tx_pkts, nb_mbuf - 1, flags, offload);
> > + tx_pkts += nb_mbuf - 1;
> > + txdp += n - 2;
> > + ice_ctx_vtx1(txdp, *tx_pkts++, rs, offload);
> > +
> > + nb_commit = (uint16_t)(nb_commit - n);
> > + txq->tx_next_rs = (uint16_t)(txq->tx_rs_thresh - 1);
> > + tx_id = 0;
> > + txdp = txq->ci_tx_ring;
> > + txep = txq->sw_ring_vec;
> > + }
> > +
> > + nb_mbuf = nb_commit >> 1;
> > + ci_tx_backlog_entry_vec(txep, tx_pkts, nb_mbuf);
> > + ice_ctx_vtx(txdp, tx_pkts, nb_mbuf, flags, offload);
> > + tx_id = (uint16_t)(tx_id + nb_commit);
> > +
> > + if (tx_id > txq->tx_next_rs) {
> > + txq->ci_tx_ring[txq->tx_next_rs].cmd_type_offset_bsz |=
> > + rte_cpu_to_le_64((uint64_t)CI_TX_DESC_CMD_RS <<
> CI_TXD_QW1_CMD_S);
> > + txq->tx_next_rs = (uint16_t)(txq->tx_next_rs + txq-
> >tx_rs_thresh);
> > + }
> > +
> > + txq->tx_tail = tx_id;
> > + ICE_PCI_REG_WC_WRITE(txq->qtx_tail, txq->tx_tail);
> > +
> > + return nb_pkts;
> > +}
> > +
> > +static inline uint16_t
> > +ice_xmit_pkts_vec_avx2_ctx_common(void *tx_queue, struct rte_mbuf
> **tx_pkts,
> > + uint16_t nb_pkts, bool offload) {
> > + struct ci_tx_queue *txq = tx_queue;
> > + uint16_t nb_tx = 0;
> > +
> > + while (nb_pkts) {
> > + const uint16_t num = RTE_MIN(nb_pkts, txq->tx_rs_thresh >>
> 1);
> > + const uint16_t ret =
> ice_xmit_fixed_burst_vec_avx2_ctx(tx_queue,
> > + &tx_pkts[nb_tx], num, offload);
> > +
> > + nb_tx += ret;
> > + nb_pkts -= ret;
> > + if (ret < num)
> > + break;
> > + }
> > +
> > + return nb_tx;
> > +}
> > +
> > +uint16_t
> > +ice_xmit_pkts_vec_avx2_ctx_offload(void *tx_queue,
> > + struct rte_mbuf **tx_pkts, uint16_t nb_pkts) {
> > + return ice_xmit_pkts_vec_avx2_ctx_common(tx_queue, tx_pkts,
> nb_pkts,
> > +true); }
> > +
> > static __rte_always_inline uint16_t
> > ice_xmit_fixed_burst_vec_avx2(void *tx_queue, struct rte_mbuf **tx_pkts,
> > uint16_t nb_pkts, bool offload)
> > --
> > 2.34.1
> >
[-- Attachment #2: Type: text/html, Size: 52078 bytes --]
^ permalink raw reply [flat|nested] 15+ messages in thread
end of thread, other threads:[~2026-08-31 10:47 UTC | newest]
Thread overview: 15+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-24 10:21 [PATCH 0/4] net/ice: support outer checksum in vector Tx Anurag Mandal
2026-08-24 10:21 ` [PATCH 1/4] net/common: share Tx context descriptor flag Anurag Mandal
2026-08-24 10:21 ` [PATCH 2/4] net/ice: add vector tunnel context encoding Anurag Mandal
2026-08-24 14:37 ` Bruce Richardson
2026-08-24 14:51 ` David Marchand
2026-08-24 14:57 ` Bruce Richardson
2026-08-24 10:21 ` [PATCH 3/4] net/ice: add AVX2 context descriptor Tx path Anurag Mandal
2026-08-24 14:47 ` Bruce Richardson
2026-08-31 10:47 ` Mandal, Anurag
2026-08-24 10:21 ` [PATCH 4/4] net/ice: add AVX-512 " Anurag Mandal
2026-08-31 10:35 ` [PATCH v2 0/4] net/ice: support outer checksum in vector Tx Anurag Mandal
2026-08-31 10:35 ` [PATCH v2 1/4] net/common: share Tx context descriptor flag Anurag Mandal
2026-08-31 10:35 ` [PATCH v2 2/4] net/ice: add vector tunnel context encoding Anurag Mandal
2026-08-31 10:35 ` [PATCH v2 3/4] net/ice: add AVX2 context descriptor Tx path Anurag Mandal
2026-08-31 10:35 ` [PATCH v2 4/4] net/ice: add AVX-512 " Anurag Mandal
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.