[PATCH v7 08/14] net/enetc: refresh link speed on VF link-up interrupt
Gagandeep Singh
g.singh at nxp.com
Tue Aug 11 09:47:39 CEST 2026
The interrupt-driven link-status path (enetc4_process_psi_msg) only
updated link_status when a PSI-to-VSI notification arrived; it never
re-queried the link speed from the PF. As a result, after a link-down
followed by a link-up the cached link_speed showed the speed from the
previous session rather than the freshly negotiated one.
1. Introducing enetc4_decode_link_speed() - a shared helper that maps
a PF-to-VF speed status code to the corresponding RTE_ETH_SPEED_NUM_*
/ RTE_ETH_LINK_*_DUPLEX values, handling both the current and the
legacy (vf_link_legacy) 4-bit message layout.
2. Calling enetc4_vf_get_link_speed() inside enetc4_process_psi_msg()
on ENETC_LINK_UP so the negotiated speed is fetched from the PF and
decoded immediately, before rte_eth_linkstatus_set() is called and
the LSC callback is fired.
Signed-off-by: Gagandeep Singh <g.singh at nxp.com>
---
doc/guides/rel_notes/release_26_11.rst | 1 +
drivers/net/enetc/enetc.h | 2 +
drivers/net/enetc/enetc4_ethdev.c | 1 +
drivers/net/enetc/enetc4_vf.c | 257 +++++++++++++------------
4 files changed, 141 insertions(+), 120 deletions(-)
diff --git a/doc/guides/rel_notes/release_26_11.rst b/doc/guides/rel_notes/release_26_11.rst
index ec223a93ba..1765adc1bc 100644
--- a/doc/guides/rel_notes/release_26_11.rst
+++ b/doc/guides/rel_notes/release_26_11.rst
@@ -69,6 +69,7 @@ New Features
* Added firmware version reporting for the ENETC4 VF.
* Added register dump support for ENETC4 PF and VF.
* Added ring parameters support for the ENETC4 VF (rxq_info_get / txq_info_get).
+ * Refreshed VF link speed on the link-up interrupt in the ENETC4 VF driver.
Removed Items
-------------
diff --git a/drivers/net/enetc/enetc.h b/drivers/net/enetc/enetc.h
index 4b563851b8..185fd8c4ee 100644
--- a/drivers/net/enetc/enetc.h
+++ b/drivers/net/enetc/enetc.h
@@ -5,6 +5,7 @@
#ifndef _ENETC_H_
#define _ENETC_H_
+#include <pthread.h>
#include <rte_time.h>
#include <ethdev_pci.h>
@@ -123,6 +124,7 @@ struct enetc_eth_hw {
* for PF kernel versions before 6.18.37. Set via vf_link_legacy devarg.
*/
uint8_t vf_link_legacy;
+ pthread_mutex_t vsi_lock; /* serializes all VSI-PSI mailbox transactions */
};
/*
diff --git a/drivers/net/enetc/enetc4_ethdev.c b/drivers/net/enetc/enetc4_ethdev.c
index ad6ef84214..3d86072593 100644
--- a/drivers/net/enetc/enetc4_ethdev.c
+++ b/drivers/net/enetc/enetc4_ethdev.c
@@ -844,6 +844,7 @@ enetc4_dev_close(struct rte_eth_dev *dev)
if (dev->data->dev_conf.intr_conf.lsc != 0)
enetc4_vf_dev_intr(dev, false);
ret = enetc4_vf_dev_stop(dev);
+ pthread_mutex_destroy(&hw->vsi_lock);
} else {
ret = enetc4_dev_stop(dev);
}
diff --git a/drivers/net/enetc/enetc4_vf.c b/drivers/net/enetc/enetc4_vf.c
index 3da84941a2..da41b999cb 100644
--- a/drivers/net/enetc/enetc4_vf.c
+++ b/drivers/net/enetc/enetc4_vf.c
@@ -323,9 +323,130 @@ enetc4_msg_get_psi_msg(struct enetc_hw *enetc_hw, struct enetc_psi_reply_msg *re
reply_msg->status = status;
}
+/* Forward declaration: defined later in this file */
+static int enetc4_vf_get_link_speed(struct rte_eth_dev *dev,
+ struct enetc_psi_reply_msg *reply_msg);
+
+/*
+ * Decode a PF-to-VF link-speed status code into the link_speed and
+ * link_duplex fields of *link. vf_link_legacy selects the older
+ * 4-bit code layout used by kernel PFs before v6.18.37.
+ */
+static void
+enetc4_decode_link_speed(uint8_t status, bool vf_link_legacy,
+ struct rte_eth_link *link)
+{
+ switch (status) {
+ case ENETC_SPEED_UNKNOWN:
+ ENETC_PMD_DEBUG("Speed unknown");
+ link->link_speed = RTE_ETH_SPEED_NUM_NONE;
+ break;
+ case ENETC_SPEED_10_HALF_DUPLEX:
+ link->link_speed = RTE_ETH_SPEED_NUM_10M;
+ link->link_duplex = RTE_ETH_LINK_HALF_DUPLEX;
+ break;
+ case ENETC_SPEED_10_FULL_DUPLEX:
+ link->link_speed = RTE_ETH_SPEED_NUM_10M;
+ link->link_duplex = RTE_ETH_LINK_FULL_DUPLEX;
+ break;
+ case ENETC_SPEED_100_HALF_DUPLEX:
+ link->link_speed = RTE_ETH_SPEED_NUM_100M;
+ link->link_duplex = RTE_ETH_LINK_HALF_DUPLEX;
+ break;
+ case ENETC_SPEED_100_FULL_DUPLEX:
+ link->link_speed = RTE_ETH_SPEED_NUM_100M;
+ link->link_duplex = RTE_ETH_LINK_FULL_DUPLEX;
+ break;
+ case ENETC_SPEED_1000:
+ link->link_speed = RTE_ETH_SPEED_NUM_1G;
+ link->link_duplex = RTE_ETH_LINK_FULL_DUPLEX;
+ break;
+ case ENETC_SPEED_2500:
+ link->link_speed = RTE_ETH_SPEED_NUM_2_5G;
+ link->link_duplex = RTE_ETH_LINK_FULL_DUPLEX;
+ break;
+ case ENETC_SPEED_5000:
+ link->link_speed = RTE_ETH_SPEED_NUM_5G;
+ link->link_duplex = RTE_ETH_LINK_FULL_DUPLEX;
+ break;
+ default:
+ if (vf_link_legacy) {
+ /* Legacy PF-to-VF message layout (older kernel PF):
+ * speeds above 5Gbps use fixed 4-bit class codes.
+ */
+ switch (status) {
+ case ENETC_SPEED_LEGACY_10G:
+ link->link_speed = RTE_ETH_SPEED_NUM_10G;
+ link->link_duplex = RTE_ETH_LINK_FULL_DUPLEX;
+ break;
+ case ENETC_SPEED_LEGACY_25G:
+ link->link_speed = RTE_ETH_SPEED_NUM_25G;
+ link->link_duplex = RTE_ETH_LINK_FULL_DUPLEX;
+ break;
+ case ENETC_SPEED_LEGACY_50G:
+ link->link_speed = RTE_ETH_SPEED_NUM_50G;
+ link->link_duplex = RTE_ETH_LINK_FULL_DUPLEX;
+ break;
+ case ENETC_SPEED_LEGACY_100G:
+ link->link_speed = RTE_ETH_SPEED_NUM_100G;
+ link->link_duplex = RTE_ETH_LINK_FULL_DUPLEX;
+ break;
+ case ENETC_SPEED_LEGACY_NOT_SUPPORTED:
+ ENETC_PMD_DEBUG("Speed not supported");
+ link->link_speed = RTE_ETH_SPEED_NUM_UNKNOWN;
+ break;
+ default:
+ ENETC_PMD_ERR("Unknown speed status");
+ link->link_speed = RTE_ETH_SPEED_NUM_UNKNOWN;
+ break;
+ }
+ break;
+ }
+ /* Any status here is > ENETC_SPEED_5000. Validate against
+ * the set of speeds that the NETC IP is known to support.
+ * An unrecognised code yields UNKNOWN rather than a
+ * fabricated speed.
+ */
+ switch ((status - ENETC_SPEED_5000) * 1000 + 5000) {
+ case RTE_ETH_SPEED_NUM_10G:
+ link->link_speed = RTE_ETH_SPEED_NUM_10G;
+ link->link_duplex = RTE_ETH_LINK_FULL_DUPLEX;
+ break;
+ case RTE_ETH_SPEED_NUM_25G:
+ link->link_speed = RTE_ETH_SPEED_NUM_25G;
+ link->link_duplex = RTE_ETH_LINK_FULL_DUPLEX;
+ break;
+ case RTE_ETH_SPEED_NUM_40G:
+ link->link_speed = RTE_ETH_SPEED_NUM_40G;
+ link->link_duplex = RTE_ETH_LINK_FULL_DUPLEX;
+ break;
+ case RTE_ETH_SPEED_NUM_50G:
+ link->link_speed = RTE_ETH_SPEED_NUM_50G;
+ link->link_duplex = RTE_ETH_LINK_FULL_DUPLEX;
+ break;
+ case RTE_ETH_SPEED_NUM_100G:
+ link->link_speed = RTE_ETH_SPEED_NUM_100G;
+ link->link_duplex = RTE_ETH_LINK_FULL_DUPLEX;
+ break;
+ case RTE_ETH_SPEED_NUM_200G:
+ link->link_speed = RTE_ETH_SPEED_NUM_200G;
+ link->link_duplex = RTE_ETH_LINK_FULL_DUPLEX;
+ break;
+ default:
+ ENETC_PMD_WARN("Unrecognized speed code 0x%x, "
+ "reporting unknown", status);
+ link->link_speed = RTE_ETH_SPEED_NUM_UNKNOWN;
+ break;
+ }
+ break;
+ }
+}
+
static void
enetc4_process_psi_msg(struct rte_eth_dev *eth_dev, struct enetc_hw *enetc_hw)
{
+ struct enetc_eth_hw *hw =
+ ENETC_DEV_PRIVATE_TO_HW(eth_dev->data->dev_private);
struct enetc_psi_reply_msg *msg;
struct rte_eth_link link;
int ret = 0;
@@ -344,6 +465,15 @@ enetc4_process_psi_msg(struct rte_eth_dev *eth_dev, struct enetc_hw *enetc_hw)
case ENETC_LINK_UP:
ENETC_PMD_DEBUG("Link is up");
link.link_status = RTE_ETH_LINK_UP;
+ /* Re-query speed from PF so the cached value reflects
+ * the current negotiated speed after link-up.
+ */
+ memset(msg, 0, sizeof(*msg));
+ if (!enetc4_vf_get_link_speed(eth_dev, msg) &&
+ msg->class_id == ENETC_CLASS_ID_LINK_SPEED)
+ enetc4_decode_link_speed(msg->status,
+ hw->vf_link_legacy,
+ &link);
break;
case ENETC_LINK_DOWN:
ENETC_PMD_DEBUG("Link is down");
@@ -379,6 +509,7 @@ enetc4_msg_vsi_send(struct enetc_eth_hw *hw, struct enetc_msg_swbd *msg)
int err = 0;
int vsimsgsr;
+ pthread_mutex_lock(&hw->vsi_lock);
enetc4_msg_vsi_write_msg(enetc_hw, msg);
do {
@@ -390,11 +521,13 @@ enetc4_msg_vsi_send(struct enetc_eth_hw *hw, struct enetc_msg_swbd *msg)
if (!timeout) {
ENETC_PMD_ERR("Message not processed by PSI");
+ pthread_mutex_unlock(&hw->vsi_lock);
return -ETIMEDOUT;
}
/* check for message delivery error */
if (vsimsgsr & ENETC4_VSIMSGSR_MS) {
ENETC_PMD_ERR("Transfer error when copying the data");
+ pthread_mutex_unlock(&hw->vsi_lock);
return -EIO;
}
@@ -441,6 +574,7 @@ enetc4_msg_vsi_send(struct enetc_eth_hw *hw, struct enetc_msg_swbd *msg)
}
}
+ pthread_mutex_unlock(&hw->vsi_lock);
return err;
}
@@ -1051,126 +1185,8 @@ enetc4_vf_link_update(struct rte_eth_dev *dev, int wait_to_complete __rte_unused
}
if (reply_msg->class_id == ENETC_CLASS_ID_LINK_SPEED) {
- switch (reply_msg->status) {
- case ENETC_SPEED_UNKNOWN:
- ENETC_PMD_DEBUG("Speed unknown");
- link.link_speed = RTE_ETH_SPEED_NUM_NONE;
- break;
- case ENETC_SPEED_10_HALF_DUPLEX:
- link.link_speed = RTE_ETH_SPEED_NUM_10M;
- link.link_duplex = RTE_ETH_LINK_HALF_DUPLEX;
- break;
- case ENETC_SPEED_10_FULL_DUPLEX:
- link.link_speed = RTE_ETH_SPEED_NUM_10M;
- link.link_duplex = RTE_ETH_LINK_FULL_DUPLEX;
- break;
- case ENETC_SPEED_100_HALF_DUPLEX:
- link.link_speed = RTE_ETH_SPEED_NUM_100M;
- link.link_duplex = RTE_ETH_LINK_HALF_DUPLEX;
- break;
- case ENETC_SPEED_100_FULL_DUPLEX:
- link.link_speed = RTE_ETH_SPEED_NUM_100M;
- link.link_duplex = RTE_ETH_LINK_FULL_DUPLEX;
- break;
- case ENETC_SPEED_1000:
- link.link_speed = RTE_ETH_SPEED_NUM_1G;
- link.link_duplex = RTE_ETH_LINK_FULL_DUPLEX;
- break;
- case ENETC_SPEED_2500:
- link.link_speed = RTE_ETH_SPEED_NUM_2_5G;
- link.link_duplex = RTE_ETH_LINK_FULL_DUPLEX;
- break;
- case ENETC_SPEED_5000:
- link.link_speed = RTE_ETH_SPEED_NUM_5G;
- link.link_duplex = RTE_ETH_LINK_FULL_DUPLEX;
- break;
- default:
- if (hw->vf_link_legacy) {
- /* Legacy PF-to-VF message layout (older kernel
- * PF): speeds greater than 5Gbps are encoded
- * with fixed 4-bit class codes rather than the
- * formula below.
- */
- switch (reply_msg->status) {
- case ENETC_SPEED_LEGACY_10G:
- link.link_speed = RTE_ETH_SPEED_NUM_10G;
- link.link_duplex = RTE_ETH_LINK_FULL_DUPLEX;
- break;
- case ENETC_SPEED_LEGACY_25G:
- link.link_speed = RTE_ETH_SPEED_NUM_25G;
- link.link_duplex = RTE_ETH_LINK_FULL_DUPLEX;
- break;
- case ENETC_SPEED_LEGACY_50G:
- link.link_speed = RTE_ETH_SPEED_NUM_50G;
- link.link_duplex = RTE_ETH_LINK_FULL_DUPLEX;
- break;
- case ENETC_SPEED_LEGACY_100G:
- link.link_speed = RTE_ETH_SPEED_NUM_100G;
- link.link_duplex = RTE_ETH_LINK_FULL_DUPLEX;
- break;
- case ENETC_SPEED_LEGACY_NOT_SUPPORTED:
- ENETC_PMD_DEBUG("Speed not supported");
- link.link_speed = RTE_ETH_SPEED_NUM_UNKNOWN;
- break;
- default:
- ENETC_PMD_ERR("Unknown speed status");
- link.link_speed = RTE_ETH_SPEED_NUM_UNKNOWN;
- break;
- }
- break;
- }
-
- /* Any status reaching here is greater than
- * ENETC_SPEED_5000, as all values from 0x0 to
- * ENETC_SPEED_5000 are handled by the cases above. Speeds
- * greater than 5Gbps are not enumerated and follow the
- * formula:
- *
- * SPEED = (link_speed - 5000) / 1000 + ENETC_SPEED_5000
- *
- * where link_speed is in Mbps. Reverse it here to get the
- * actual link speed (RTE_ETH_SPEED_NUM_* values are in Mbps).
- *
- * Validate the computed value against the set of speeds
- * that the NETC IP is known to support (> 5Gbps).
- * An unrecognised code yields UNKNOWN rather than a
- * fabricated speed.
- */
- switch ((reply_msg->status - ENETC_SPEED_5000)
- * 1000 + 5000) {
- case RTE_ETH_SPEED_NUM_10G:
- link.link_speed = RTE_ETH_SPEED_NUM_10G;
- link.link_duplex = RTE_ETH_LINK_FULL_DUPLEX;
- break;
- case RTE_ETH_SPEED_NUM_25G:
- link.link_speed = RTE_ETH_SPEED_NUM_25G;
- link.link_duplex = RTE_ETH_LINK_FULL_DUPLEX;
- break;
- case RTE_ETH_SPEED_NUM_40G:
- link.link_speed = RTE_ETH_SPEED_NUM_40G;
- link.link_duplex = RTE_ETH_LINK_FULL_DUPLEX;
- break;
- case RTE_ETH_SPEED_NUM_50G:
- link.link_speed = RTE_ETH_SPEED_NUM_50G;
- link.link_duplex = RTE_ETH_LINK_FULL_DUPLEX;
- break;
- case RTE_ETH_SPEED_NUM_100G:
- link.link_speed = RTE_ETH_SPEED_NUM_100G;
- link.link_duplex = RTE_ETH_LINK_FULL_DUPLEX;
- break;
- case RTE_ETH_SPEED_NUM_200G:
- link.link_speed = RTE_ETH_SPEED_NUM_200G;
- link.link_duplex = RTE_ETH_LINK_FULL_DUPLEX;
- break;
- default:
- ENETC_PMD_WARN("Unrecognized speed code 0x%x, "
- "reporting unknown",
- reply_msg->status);
- link.link_speed = RTE_ETH_SPEED_NUM_UNKNOWN;
- break;
- }
- break;
- }
+ enetc4_decode_link_speed(reply_msg->status,
+ hw->vf_link_legacy, &link);
} else {
ENETC_PMD_ERR("Wrong reply message");
return -1;
@@ -1741,6 +1757,7 @@ enetc4_vf_dev_init(struct rte_eth_dev *eth_dev)
}
enetc4_dev_hw_init(eth_dev);
+ pthread_mutex_init(&hw->vsi_lock, NULL);
hw->nc_mode = 0;
enetc4_vf_get_devarg_nc(eth_dev);
--
2.25.1
More information about the dev
mailing list