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 <[email protected]>
---
 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

Reply via email to