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

Reply via email to