[PATCH v5 08/14] net/enetc: refresh link speed on VF link-up interrupt

Gagandeep Singh <[email protected]>
Newsgroups org.dpdk.dev
Message-ID <[email protected]>
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/enetc4_vf.c          | 257 +++++++++++++------------
 2 files changed, 138 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/enetc4_vf.c b/drivers/net/enetc/enetc4_vf.c
index 406559094f..dae6e4c772 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,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");
@@ -1047,126 +1182,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;
-- 
2.25.1
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.