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.
Fix this by: 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 <[email protected]> --- doc/guides/rel_notes/release_26_11.rst | 1 + drivers/net/enetc/enetc4_vf.c | 197 +++++++++++++------------ 2 files changed, 107 insertions(+), 91 deletions(-) diff --git a/doc/guides/rel_notes/release_26_11.rst b/doc/guides/rel_notes/release_26_11.rst index 9e333edf4f..eca0dc1dea 100644 --- a/doc/guides/rel_notes/release_26_11.rst +++ b/doc/guides/rel_notes/release_26_11.rst @@ -67,6 +67,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/enetc4_vf.c b/drivers/net/enetc/enetc4_vf.c index 90b7b99e9a..ede11a7b61 100644 --- a/drivers/net/enetc/enetc4_vf.c +++ b/drivers/net/enetc/enetc4_vf.c @@ -324,9 +324,99 @@ 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. Reverse the formula: + * SPEED = (status - ENETC_SPEED_5000) * 1000 + 5000 (in Mbps) + */ + link->link_speed = (status - ENETC_SPEED_5000) * 1000 + 5000; + link->link_duplex = RTE_ETH_LINK_FULL_DUPLEX; + 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; @@ -345,6 +435,20 @@ 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. + */ + rte_free(msg); + msg = rte_zmalloc(NULL, sizeof(*msg), RTE_CACHE_LINE_SIZE); + if (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); + } else { + ENETC_PMD_WARN("Failed to alloc msg for speed query"); + } break; case ENETC_LINK_DOWN: ENETC_PMD_DEBUG("Link is down"); @@ -1048,97 +1152,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). - * - * The PF only reports speeds that map to a well-known - * RTE_ETH_SPEED_NUM_* value, so the computed value is a - * valid DPDK speed. If a future speed not yet defined in - * DPDK needs to be supported, the corresponding - * RTE_ETH_SPEED_NUM_* value must first be added upstream. - */ - link.link_speed = (reply_msg->status - ENETC_SPEED_5000) - * 1000 + 5000; - link.link_duplex = RTE_ETH_LINK_FULL_DUPLEX; - break; - } + enetc4_decode_link_speed(reply_msg->status, + hw->vf_link_legacy, &link); } else { ENETC_PMD_ERR("Wrong reply message"); return -1; -- 2.25.1

