[PATCH 13/14] net/enetc4: enable TX PAUSE via VF RX congestion mode
Gagandeep Singh
g.singh at nxp.com
Thu Aug 6 13:28:35 CEST 2026
When the PF negotiates TX PAUSE on the port it signals this to the VF
via BIT(1) of the PF-to-VF link status mailbox message. The VF PMD must
respond by setting RBMR_CM (BIT(4)) on all active RX rings so the MAC
emits PAUSE frames on ingress pressure.
Add ENETC_RBMR_CM register definition, ENETC_LINK_TX_PAUSE bitmask,
and tx_pause_active state flag. Add enetc4_vf_set_congestion_mode() to
update all active RX rings and persist the state for rings started
later. Hook it into both the interrupt and poll link-update paths, and
apply the saved state in rx_queue_setup() and rx_queue_start().
RX PAUSE (honoring received PAUSE frames) is handled at the MAC level
by the PF and requires no VF PMD changes.
Signed-off-by: Gagandeep Singh <g.singh at nxp.com>
---
doc/guides/nics/features/enetc4.ini | 1 +
doc/guides/rel_notes/release_26_11.rst | 1 +
drivers/net/enetc/base/enetc_hw.h | 1 +
drivers/net/enetc/enetc.h | 9 +++-
drivers/net/enetc/enetc4_ethdev.c | 13 +++++-
drivers/net/enetc/enetc4_vf.c | 59 ++++++++++++++++++++++++--
6 files changed, 78 insertions(+), 6 deletions(-)
diff --git a/doc/guides/nics/features/enetc4.ini b/doc/guides/nics/features/enetc4.ini
index 9dc8fd33f8..d4e186559e 100644
--- a/doc/guides/nics/features/enetc4.ini
+++ b/doc/guides/nics/features/enetc4.ini
@@ -14,6 +14,7 @@ Promiscuous mode = Y
Allmulticast mode = Y
Unicast MAC filter = Y
VLAN filter = Y
+Flow control = Y
VLAN offload = Y
RSS hash = Y
Packet type parsing = Y
diff --git a/doc/guides/rel_notes/release_26_11.rst b/doc/guides/rel_notes/release_26_11.rst
index 5323f4fea3..d69888aafb 100644
--- a/doc/guides/rel_notes/release_26_11.rst
+++ b/doc/guides/rel_notes/release_26_11.rst
@@ -72,6 +72,7 @@ New Features
* Added per-queue MSI-X Rx interrupt support for the ENETC4 VF.
* Added SI-based port VLAN insertion (Tx) and removal (Rx) for ENETC4 PF and VF.
* Updated ENETC4 VF link status reporting to use bitmask encoding.
+ * Added TX PAUSE support for the ENETC4 VF via RX congestion mode.
Removed Items
-------------
diff --git a/drivers/net/enetc/base/enetc_hw.h b/drivers/net/enetc/base/enetc_hw.h
index 6e96562850..33d075fe59 100644
--- a/drivers/net/enetc/base/enetc_hw.h
+++ b/drivers/net/enetc/base/enetc_hw.h
@@ -51,6 +51,7 @@ enum enetc_bdr_type {TX, RX};
+ (off))
/* RX BDR reg offsets */
#define ENETC_RBMR 0x0 /* RX BDR mode register*/
+#define ENETC_RBMR_CM BIT(4) /* congestion mode: assert congestion to emit TX PAUSE */
#define ENETC_RBMR_EN BIT(31)
#define ENETC_BMR_RESET 0x0 /* BDR reset*/
diff --git a/drivers/net/enetc/enetc.h b/drivers/net/enetc/enetc.h
index 40bad56341..8aaf8a7eb1 100644
--- a/drivers/net/enetc/enetc.h
+++ b/drivers/net/enetc/enetc.h
@@ -140,6 +140,10 @@ struct enetc_eth_hw {
* for PF kernel versions before 6.18.37. Set via vf_link_legacy devarg.
*/
uint8_t vf_link_legacy;
+ /* 1 = TX PAUSE negotiated on port; VF RX rings must have RBMR_CM set.
+ * Updated from the PF-to-VF link status mailbox message (BIT(1)).
+ */
+ uint8_t tx_pause_active;
/* Baseline snapshot for VF stats reset (software delta approach). */
struct enetc4_vf_stats_saved vf_stats_saved;
};
@@ -238,8 +242,11 @@ enum vlan_status {
/* Link status bitmask in PF-to-VF mailbox notification.
* Link up is encoded as the DOWN bit being clear.
+ * TX_PAUSE is set when the port has negotiated TX PAUSE; VF must enable
+ * congestion mode (ENETC_RBMR_CM) on its RX rings accordingly.
*/
-#define ENETC_LINK_DOWN (1u << 0)
+#define ENETC_LINK_DOWN (1u << 0)
+#define ENETC_LINK_TX_PAUSE (1u << 1)
enum speed {
ENETC_SPEED_UNKNOWN = 0x0,
diff --git a/drivers/net/enetc/enetc4_ethdev.c b/drivers/net/enetc/enetc4_ethdev.c
index ae40cc69e0..2355522515 100644
--- a/drivers/net/enetc/enetc4_ethdev.c
+++ b/drivers/net/enetc/enetc4_ethdev.c
@@ -712,8 +712,12 @@ enetc4_rx_queue_setup(struct rte_eth_dev *dev,
}
if (!rx_conf->rx_deferred_start) {
- /* enable ring */
+ /* Enable ring; apply congestion mode if TX PAUSE is already active. */
rx_enable |= ENETC_RBMR_EN;
+ if (adapter->hw.tx_pause_active)
+ rx_enable |= ENETC_RBMR_CM;
+ else
+ rx_enable &= ~(uint32_t)ENETC_RBMR_CM;
enetc4_rxbdr_wr(&adapter->hw.hw, rx_ring->index, ENETC_RBMR,
rx_enable);
dev->data->rx_queue_state[rx_ring->index] =
@@ -1089,7 +1093,12 @@ enetc4_rx_queue_start(struct rte_eth_dev *dev, uint16_t qidx)
if (dev->data->rx_queue_state[qidx] == RTE_ETH_QUEUE_STATE_STOPPED) {
rx_data = enetc4_rxbdr_rd(&priv->hw.hw, rx_ring->index,
ENETC_RBMR);
- rx_data = rx_data | ENETC_RBMR_EN;
+ rx_data |= ENETC_RBMR_EN;
+ /* Restore congestion mode if TX PAUSE is active. */
+ if (priv->hw.tx_pause_active)
+ rx_data |= ENETC_RBMR_CM;
+ else
+ rx_data &= ~(uint32_t)ENETC_RBMR_CM;
enetc4_rxbdr_wr(&priv->hw.hw, rx_ring->index, ENETC_RBMR,
rx_data);
dev->data->rx_queue_state[qidx] = RTE_ETH_QUEUE_STATE_STARTED;
diff --git a/drivers/net/enetc/enetc4_vf.c b/drivers/net/enetc/enetc4_vf.c
index d38b31c10a..9223d5d179 100644
--- a/drivers/net/enetc/enetc4_vf.c
+++ b/drivers/net/enetc/enetc4_vf.c
@@ -461,6 +461,37 @@ enetc4_decode_link_speed(uint8_t status, bool vf_link_legacy,
}
}
+/*
+ * Set or clear ENETC_RBMR_CM (congestion mode) on all active VF RX rings.
+ * When set, the ring signals congestion to the MAC, causing it to emit TX
+ * PAUSE frames on ingress pressure. hw->tx_pause_active is updated so rings
+ * started later inherit the correct state.
+ */
+static void
+enetc4_vf_set_congestion_mode(struct rte_eth_dev *eth_dev, bool enable)
+{
+ struct enetc_eth_hw *hw =
+ ENETC_DEV_PRIVATE_TO_HW(eth_dev->data->dev_private);
+ struct enetc_hw *enetc_hw = &hw->hw;
+ uint16_t nb_rx = eth_dev->data->nb_rx_queues;
+ uint16_t i;
+ uint32_t rbmr;
+
+ hw->tx_pause_active = enable ? 1 : 0;
+
+ for (i = 0; i < nb_rx; i++) {
+ rbmr = enetc4_rxbdr_rd(enetc_hw, i, ENETC_RBMR);
+ if (enable)
+ rbmr |= ENETC_RBMR_CM;
+ else
+ rbmr &= ~(uint32_t)ENETC_RBMR_CM;
+ enetc4_rxbdr_wr(enetc_hw, i, ENETC_RBMR, rbmr);
+ }
+
+ ENETC_PMD_DEBUG("VF congestion mode %s on %u RX rings",
+ enable ? "enabled" : "disabled", nb_rx);
+}
+
static void
enetc4_process_psi_msg(struct rte_eth_dev *eth_dev, struct enetc_hw *enetc_hw)
{
@@ -468,6 +499,7 @@ enetc4_process_psi_msg(struct rte_eth_dev *eth_dev, struct enetc_hw *enetc_hw)
ENETC_DEV_PRIVATE_TO_HW(eth_dev->data->dev_private);
struct enetc_psi_reply_msg *msg;
struct rte_eth_link link;
+ bool tx_pause;
int ret = 0;
msg = rte_zmalloc(NULL, sizeof(*msg), RTE_CACHE_LINE_SIZE);
@@ -483,9 +515,24 @@ enetc4_process_psi_msg(struct rte_eth_dev *eth_dev, struct enetc_hw *enetc_hw)
if (msg->status & ENETC_LINK_DOWN) {
ENETC_PMD_DEBUG("Link is down");
link.link_status = RTE_ETH_LINK_DOWN;
+ /* Clear congestion mode on link-down so VF rings do not
+ * assert congestion while the port is offline.
+ */
+ enetc4_vf_set_congestion_mode(eth_dev, false);
} else {
- ENETC_PMD_DEBUG("Link is up");
+ /* BIT(1) is set when the port has negotiated TX PAUSE.
+ * Legacy PF does not set this bit so tx_pause stays false.
+ */
+ tx_pause = !!(msg->status & ENETC_LINK_TX_PAUSE);
+ ENETC_PMD_DEBUG("Link is up, tx_pause=%d", tx_pause);
link.link_status = RTE_ETH_LINK_UP;
+
+ /* Apply congestion mode before raising the carrier so
+ * the VF rings are ready to emit PAUSE before traffic
+ * starts flowing.
+ */
+ enetc4_vf_set_congestion_mode(eth_dev, tx_pause);
+
/* Re-query speed from PF so the cached value reflects
* the current negotiated speed after link-up.
*/
@@ -1174,10 +1221,16 @@ enetc4_vf_link_update(struct rte_eth_dev *dev, int wait_to_complete __rte_unused
}
if (reply_msg->class_id == ENETC_CLASS_ID_LINK_STATUS) {
- if (reply_msg->status & ENETC_LINK_DOWN)
+ if (reply_msg->status & ENETC_LINK_DOWN) {
link.link_status = RTE_ETH_LINK_DOWN;
- else
+ /* Link is down: disable congestion mode on all RX rings. */
+ enetc4_vf_set_congestion_mode(dev, false);
+ } else {
link.link_status = RTE_ETH_LINK_UP;
+ /* Restore congestion mode from the TX PAUSE bit. */
+ enetc4_vf_set_congestion_mode(dev,
+ !!(reply_msg->status & ENETC_LINK_TX_PAUSE));
+ }
} else {
ENETC_PMD_ERR("Wrong reply message");
return -1;
More information about the dev
mailing list