DPDK patches and discussions
 help / color / mirror / Atom feed
* [PATCH] igc/ixgbe: add get/set link settings interface
@ 2024-03-26 23:59 Marek Pazdan
  2024-03-27 11:12 ` Bruce Richardson
                   ` (2 more replies)
  0 siblings, 3 replies; 17+ messages in thread
From: Marek Pazdan @ 2024-03-26 23:59 UTC (permalink / raw)
  To: Thomas Monjalon, Aman Singh, Yuying Zhang, Ferruh Yigit,
	Andrew Rybchenko
  Cc: dev, Marek Pazdan

There are link settings parameters available from PMD drivers level
which are currently not exposed to the user via consistent interface.
When interface is available for system level those information can
be acquired with 'ethtool DEVNAME' (ioctl: ETHTOOL_SLINKSETTINGS/
ETHTOOL_GLINKSETTINGS). There are use cases where
physical interface is passthrough to dpdk driver and is not available
from system level. Information provided by ioctl carries information
useful for link auto negotiation settings among others.
Additionally dpdk-testpmd application has been extended to provided
testing tool for newly implemtented interface functions.

Signed-off-by: Marek Pazdan <mpazdan@arista.com>
---
 .mailmap                           |   1 +
 app/test-pmd/cmdline.c             |   9 +
 app/test-pmd/cmdline_settings.c    | 516 +++++++++++++++++++++++++++++
 app/test-pmd/cmdline_settings.h    |  14 +
 app/test-pmd/meson.build           |   1 +
 app/test-pmd/testpmd.h             |   1 +
 app/test-pmd/util.c                |  10 +
 drivers/net/igc/igc_ethdev.c       | 229 ++++++++++++-
 drivers/net/ixgbe/base/ixgbe_phy.h |   7 +
 drivers/net/ixgbe/ixgbe_ethdev.c   | 395 ++++++++++++++++++++++
 lib/ethdev/ethdev_driver.h         |  33 ++
 lib/ethdev/rte_ethdev.c            |  26 ++
 lib/ethdev/rte_ethdev.h            | 215 +++++++++++-
 lib/ethdev/version.map             |   3 +
 14 files changed, 1450 insertions(+), 10 deletions(-)
 create mode 100644 app/test-pmd/cmdline_settings.c
 create mode 100644 app/test-pmd/cmdline_settings.h

diff --git a/.mailmap b/.mailmap
index 3843868716..145ce726ba 100644
--- a/.mailmap
+++ b/.mailmap
@@ -885,6 +885,7 @@ Marcin Wojtas <mw@semihalf.com>
 Marcin Zapolski <marcinx.a.zapolski@intel.com>
 Marco Varlese <mvarlese@suse.de>
 Marc Sune <marcdevel@gmail.com> <marc.sune@bisdn.de>
+Marek Pazdan <mpazdan@arista.com>
 Maria Lingemark <maria.lingemark@ericsson.com>
 Mario Carrillo <mario.alfredo.c.arevalo@intel.com>
 Mário Kuka <kuka@cesnet.cz>
diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
index b7759e38a8..7fdd134467 100644
--- a/app/test-pmd/cmdline.c
+++ b/app/test-pmd/cmdline.c
@@ -65,6 +65,7 @@
 #include "cmdline_cman.h"
 #include "cmdline_mtr.h"
 #include "cmdline_tm.h"
+#include "cmdline_settings.h"
 #include "bpf_cmd.h"
 
 static struct cmdline *testpmd_cl;
@@ -255,6 +256,9 @@ static void cmd_help_long_parsed(void *parsed_result,
 			"show port (port_id) flow_ctrl"
 			"	Show flow control info of a port.\n\n"
 
+			"show port (port_id) link settings"
+			"	Show link settings of a port.\n\n"
+
 			"dump_physmem\n"
 			"    Dumps all physical memory segment layouts\n\n"
 
@@ -661,6 +665,9 @@ static void cmd_help_long_parsed(void *parsed_result,
 			"(max_thresh) (prob_inv)]\n"
 			"    Set congestion management configuration\n\n"
 
+			"set port (port_id) link settings advertising (bitmap_str)"
+			"	Set link advertising settings of a port.\n\n"
+
 			, list_pkt_forwarding_modes()
 		);
 	}
@@ -13219,6 +13226,8 @@ static cmdline_parse_ctx_t builtin_ctx[] = {
 	(cmdline_parse_inst_t *)&cmd_link_flow_control_set_macfwd,
 	(cmdline_parse_inst_t *)&cmd_link_flow_control_set_autoneg,
 	(cmdline_parse_inst_t *)&cmd_link_flow_control_show,
+	(cmdline_parse_inst_t *)&cmd_link_settings_show,
+	(cmdline_parse_inst_t *)&cmd_link_settings_set_advertising,
 	(cmdline_parse_inst_t *)&cmd_priority_flow_control_set,
 	(cmdline_parse_inst_t *)&cmd_queue_priority_flow_control_set,
 	(cmdline_parse_inst_t *)&cmd_config_dcb,
diff --git a/app/test-pmd/cmdline_settings.c b/app/test-pmd/cmdline_settings.c
new file mode 100644
index 0000000000..4db6bd4e9a
--- /dev/null
+++ b/app/test-pmd/cmdline_settings.c
@@ -0,0 +1,516 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (c) 2024 Arista Networks, Inc.  All rights reserved.
+ * Arista Networks, Inc. Confidential and Proprietary
+ */
+
+#include <stdio.h>
+#include <rte_ethdev.h>
+
+#include <cmdline_parse_string.h>
+#include <cmdline_parse_num.h>
+
+#include "testpmd.h"
+
+/* *** GET CURRENT ETHERNET LINK SETTINGS *** */
+struct cmd_link_settings_show {
+	cmdline_fixed_string_t show;
+	cmdline_fixed_string_t port;
+	portid_t port_id;
+	cmdline_fixed_string_t link;
+	cmdline_fixed_string_t settings;
+};
+
+cmdline_parse_token_string_t cmd_ls_show_show =
+	TOKEN_STRING_INITIALIZER(struct cmd_link_settings_show,
+				show, "show");
+cmdline_parse_token_string_t cmd_ls_show_port =
+	TOKEN_STRING_INITIALIZER(struct cmd_link_settings_show,
+				port, "port");
+cmdline_parse_token_num_t cmd_ls_show_portid =
+	TOKEN_NUM_INITIALIZER(struct cmd_link_settings_show,
+				port_id, RTE_UINT16);
+cmdline_parse_token_string_t cmd_ls_show_link =
+	TOKEN_STRING_INITIALIZER(struct cmd_link_settings_show,
+				link, "link");
+cmdline_parse_token_string_t cmd_ls_show_settings =
+	TOKEN_STRING_INITIALIZER(struct cmd_link_settings_show,
+				settings, "settings");
+
+/* Print link capability flags (supported, advertised or lp_advertised).
+ * Assumes that the corresponding SUPPORTED and ADVERTISED flags are equal.
+ */
+static void dump_link_caps(const char *prefix, const char *an_prefix,
+		const uint32_t *mask, int link_mode_only)
+{
+	static const struct {
+		int same_line; /* print on same line as previous */
+		unsigned int bit_index;
+		const char *name;
+	} mode_defs[] = {
+		{ 0, RTE_LINK_MODE_10baseT_Half_BIT,
+		  "10baseT/Half" },
+		{ 1, RTE_LINK_MODE_10baseT_Full_BIT,
+		  "10baseT/Full" },
+		{ 0, RTE_LINK_MODE_100baseT_Half_BIT,
+		  "100baseT/Half" },
+		{ 1, RTE_LINK_MODE_100baseT_Full_BIT,
+		  "100baseT/Full" },
+		{ 0, RTE_LINK_MODE_100baseT1_Full_BIT,
+		  "100baseT1/Full" },
+		{ 0, RTE_LINK_MODE_1000baseT_Half_BIT,
+		  "1000baseT/Half" },
+		{ 1, RTE_LINK_MODE_1000baseT_Full_BIT,
+		  "1000baseT/Full" },
+		{ 0, RTE_LINK_MODE_1000baseT1_Full_BIT,
+		  "1000baseT1/Full" },
+		{ 0, RTE_LINK_MODE_1000baseKX_Full_BIT,
+		  "1000baseKX/Full" },
+		{ 0, RTE_LINK_MODE_2500baseX_Full_BIT,
+		  "2500baseX/Full" },
+		{ 0, RTE_LINK_MODE_10000baseT_Full_BIT,
+		  "10000baseT/Full" },
+		{ 0, RTE_LINK_MODE_10000baseKX4_Full_BIT,
+		  "10000baseKX4/Full" },
+		{ 0, RTE_LINK_MODE_10000baseKR_Full_BIT,
+		  "10000baseKR/Full" },
+		{ 0, RTE_LINK_MODE_10000baseR_FEC_BIT,
+		  "10000baseR_FEC" },
+		{ 0, RTE_LINK_MODE_20000baseMLD2_Full_BIT,
+		  "20000baseMLD2/Full" },
+		{ 0, RTE_LINK_MODE_20000baseKR2_Full_BIT,
+		  "20000baseKR2/Full" },
+		{ 0, RTE_LINK_MODE_40000baseKR4_Full_BIT,
+		  "40000baseKR4/Full" },
+		{ 0, RTE_LINK_MODE_40000baseCR4_Full_BIT,
+		  "40000baseCR4/Full" },
+		{ 0, RTE_LINK_MODE_40000baseSR4_Full_BIT,
+		  "40000baseSR4/Full" },
+		{ 0, RTE_LINK_MODE_40000baseLR4_Full_BIT,
+		  "40000baseLR4/Full" },
+		{ 0, RTE_LINK_MODE_56000baseKR4_Full_BIT,
+		  "56000baseKR4/Full" },
+		{ 0, RTE_LINK_MODE_56000baseCR4_Full_BIT,
+		  "56000baseCR4/Full" },
+		{ 0, RTE_LINK_MODE_56000baseSR4_Full_BIT,
+		  "56000baseSR4/Full" },
+		{ 0, RTE_LINK_MODE_56000baseLR4_Full_BIT,
+		  "56000baseLR4/Full" },
+		{ 0, RTE_LINK_MODE_25000baseCR_Full_BIT,
+		  "25000baseCR/Full" },
+		{ 0, RTE_LINK_MODE_25000baseKR_Full_BIT,
+		  "25000baseKR/Full" },
+		{ 0, RTE_LINK_MODE_25000baseSR_Full_BIT,
+		  "25000baseSR/Full" },
+		{ 0, RTE_LINK_MODE_50000baseCR2_Full_BIT,
+		  "50000baseCR2/Full" },
+		{ 0, RTE_LINK_MODE_50000baseKR2_Full_BIT,
+		  "50000baseKR2/Full" },
+		{ 0, RTE_LINK_MODE_100000baseKR4_Full_BIT,
+		  "100000baseKR4/Full" },
+		{ 0, RTE_LINK_MODE_100000baseSR4_Full_BIT,
+		  "100000baseSR4/Full" },
+		{ 0, RTE_LINK_MODE_100000baseCR4_Full_BIT,
+		  "100000baseCR4/Full" },
+		{ 0, RTE_LINK_MODE_100000baseLR4_ER4_Full_BIT,
+		  "100000baseLR4_ER4/Full" },
+		{ 0, RTE_LINK_MODE_50000baseSR2_Full_BIT,
+		  "50000baseSR2/Full" },
+		{ 0, RTE_LINK_MODE_1000baseX_Full_BIT,
+		  "1000baseX/Full" },
+		{ 0, RTE_LINK_MODE_10000baseCR_Full_BIT,
+		  "10000baseCR/Full" },
+		{ 0, RTE_LINK_MODE_10000baseSR_Full_BIT,
+		  "10000baseSR/Full" },
+		{ 0, RTE_LINK_MODE_10000baseLR_Full_BIT,
+		  "10000baseLR/Full" },
+		{ 0, RTE_LINK_MODE_10000baseLRM_Full_BIT,
+		  "10000baseLRM/Full" },
+		{ 0, RTE_LINK_MODE_10000baseER_Full_BIT,
+		  "10000baseER/Full" },
+		{ 0, RTE_LINK_MODE_2500baseT_Full_BIT,
+		  "2500baseT/Full" },
+		{ 0, RTE_LINK_MODE_5000baseT_Full_BIT,
+		  "5000baseT/Full" },
+		{ 0, RTE_LINK_MODE_50000baseKR_Full_BIT,
+		  "50000baseKR/Full" },
+		{ 0, RTE_LINK_MODE_50000baseSR_Full_BIT,
+		  "50000baseSR/Full" },
+		{ 0, RTE_LINK_MODE_50000baseCR_Full_BIT,
+		  "50000baseCR/Full" },
+		{ 0, RTE_LINK_MODE_50000baseLR_ER_FR_Full_BIT,
+		  "50000baseLR_ER_FR/Full" },
+		{ 0, RTE_LINK_MODE_50000baseDR_Full_BIT,
+		  "50000baseDR/Full" },
+		{ 0, RTE_LINK_MODE_100000baseKR2_Full_BIT,
+		  "100000baseKR2/Full" },
+		{ 0, RTE_LINK_MODE_100000baseSR2_Full_BIT,
+		  "100000baseSR2/Full" },
+		{ 0, RTE_LINK_MODE_100000baseCR2_Full_BIT,
+		  "100000baseCR2/Full" },
+		{ 0, RTE_LINK_MODE_100000baseLR2_ER2_FR2_Full_BIT,
+		  "100000baseLR2_ER2_FR2/Full" },
+		{ 0, RTE_LINK_MODE_100000baseDR2_Full_BIT,
+		  "100000baseDR2/Full" },
+		{ 0, RTE_LINK_MODE_200000baseKR4_Full_BIT,
+		  "200000baseKR4/Full" },
+		{ 0, RTE_LINK_MODE_200000baseSR4_Full_BIT,
+		  "200000baseSR4/Full" },
+		{ 0, RTE_LINK_MODE_200000baseLR4_ER4_FR4_Full_BIT,
+		  "200000baseLR4_ER4_FR4/Full" },
+		{ 0, RTE_LINK_MODE_200000baseDR4_Full_BIT,
+		  "200000baseDR4/Full" },
+		{ 0, RTE_LINK_MODE_200000baseCR4_Full_BIT,
+		  "200000baseCR4/Full" },
+	};
+	int indent;
+	int did1;
+	int new_line_pend;
+	int fecreported = 0;
+
+	/* Indent just like the separate functions used to */
+	indent = strlen(prefix) + 14;
+	if (indent < 24)
+		indent = 24;
+
+	fprintf(stdout, "       %s link modes:%*s", prefix,
+		indent - (int)strlen(prefix) - 12, "");
+	did1 = 0;
+	new_line_pend = 0;
+	for (uint32_t i = 0; i < RTE_DIM(mode_defs); i++) {
+		if (did1 && !mode_defs[i].same_line)
+			new_line_pend = 1;
+		if (get_bit(mask, mode_defs[i].bit_index)) {
+			if (new_line_pend) {
+				fprintf(stdout, "\n");
+				fprintf(stdout, "       %*s", indent, "");
+				new_line_pend = 0;
+			}
+			did1++;
+			fprintf(stdout, "%s ", mode_defs[i].name);
+		}
+	}
+	if (did1 == 0)
+		fprintf(stdout, "Not reported");
+	fprintf(stdout, "\n");
+
+	if (!link_mode_only) {
+		fprintf(stdout, "       %s pause frame use: ", prefix);
+		if (get_bit(mask, RTE_LINK_MODE_Pause_BIT)) {
+			fprintf(stdout, "Symmetric");
+			if (get_bit(mask, RTE_LINK_MODE_Asym_Pause_BIT))
+				fprintf(stdout, " Receive-only");
+			fprintf(stdout, "\n");
+		} else {
+			if (get_bit(mask, RTE_LINK_MODE_Asym_Pause_BIT))
+				fprintf(stdout, "Transmit-only\n");
+			else
+				fprintf(stdout, "No\n");
+		}
+
+		fprintf(stdout, "       %s auto-negotiation: ", an_prefix);
+		if (get_bit(mask, RTE_LINK_MODE_Autoneg_BIT))
+			fprintf(stdout, "Yes\n");
+		else
+			fprintf(stdout, "No\n");
+
+		fprintf(stdout, "       %s FEC modes:", prefix);
+		if (get_bit(mask, RTE_LINK_MODE_FEC_NONE_BIT)) {
+			fprintf(stdout, " None");
+			fecreported = 1;
+		}
+		if (get_bit(mask, RTE_LINK_MODE_FEC_BASER_BIT)) {
+			fprintf(stdout, " BaseR");
+			fecreported = 1;
+		}
+		if (get_bit(mask, RTE_LINK_MODE_FEC_RS_BIT)) {
+			fprintf(stdout, " RS");
+			fecreported = 1;
+		}
+		if (!fecreported)
+			fprintf(stdout, " Not reported");
+		fprintf(stdout, "\n");
+	}
+}
+
+static void
+dump_supported(const struct rte_link_settings *link_settings)
+{
+	fprintf(stdout, "       Supported ports: [ ");
+	if (get_bit(link_settings->link_modes.supported,
+		    RTE_LINK_MODE_TP_BIT))
+		fprintf(stdout, "TP ");
+	if (get_bit(link_settings->link_modes.supported,
+		    RTE_LINK_MODE_AUI_BIT))
+		fprintf(stdout, "AUI ");
+	if (get_bit(link_settings->link_modes.supported,
+		    RTE_LINK_MODE_BNC_BIT))
+		fprintf(stdout, "BNC ");
+	if (get_bit(link_settings->link_modes.supported,
+		    RTE_LINK_MODE_MII_BIT))
+		fprintf(stdout, "MII ");
+	if (get_bit(link_settings->link_modes.supported,
+		    RTE_LINK_MODE_FIBRE_BIT))
+		fprintf(stdout, "FIBRE ");
+	if (get_bit(link_settings->link_modes.supported,
+		    RTE_LINK_MODE_Backplane_BIT))
+		fprintf(stdout, "Backplane ");
+	fprintf(stdout, "]\n");
+
+	dump_link_caps("Supported", "Supports",
+		       link_settings->link_modes.supported, 0);
+}
+
+
+
+static void
+cmd_link_settings_show_parsed(void *parsed_result,
+			      __rte_unused struct cmdline *cl,
+			      __rte_unused void *data)
+{
+	struct cmd_link_settings_show *res = parsed_result;
+	static const char *info_border = "*********************";
+	struct rte_link_settings link_settings;
+	int ret;
+
+	memset(&link_settings, 0x00, sizeof(link_settings));
+	ret = rte_eth_dev_get_link_settings(res->port_id, &link_settings);
+	if (ret != 0) {
+		fprintf(stderr,
+			"Failed to get current link settings: err = %d\n",
+			ret);
+		return;
+	}
+
+	printf("\n%s Link settings for port %-2d %s\n",
+		info_border, res->port_id, info_border);
+
+	dump_supported(&link_settings);
+	dump_link_caps("Advertised", "Advertised",
+			link_settings.link_modes.advertising, 0);
+
+	bool show_lp_advertising = false;
+	for (uint32_t idx = 0; idx < RTE_DIM(link_settings.link_modes.lp_advertising); idx++) {
+		if (link_settings.link_modes.lp_advertising[idx] != 0) {
+			show_lp_advertising = true;
+			break;
+		}
+	}
+
+	if (show_lp_advertising) {
+		dump_link_caps("Link partner advertised",
+				"Link partner advertised",
+				link_settings.link_modes.lp_advertising, 0);
+	}
+
+	fprintf(stdout, "       Speed: ");
+	if (link_settings.base.link.link_speed == 0
+	    || link_settings.base.link.link_speed == (uint16_t)(-1)
+	    || link_settings.base.link.link_speed == (uint32_t)(-1))
+		fprintf(stdout, "Unknown!\n");
+	else
+		fprintf(stdout, "%uMb/s\n", link_settings.base.link.link_speed);
+
+	fprintf(stdout, "       Duplex: ");
+	switch (link_settings.base.link.link_duplex) {
+	case RTE_ETH_LINK_HALF_DUPLEX:
+		fprintf(stdout, "Half\n");
+		break;
+	case RTE_ETH_LINK_FULL_DUPLEX:
+		fprintf(stdout, "Full\n");
+		break;
+	default:
+		fprintf(stdout, "Unknown! (%i)\n", link_settings.base.link.link_duplex);
+		break;
+	};
+
+	fprintf(stdout, "       Port: ");
+	switch (link_settings.base.port) {
+	case RTE_PORT_TP:
+		fprintf(stdout, "Twisted Pair\n");
+		break;
+	case RTE_PORT_AUI:
+		fprintf(stdout, "AUI\n");
+		break;
+	case RTE_PORT_BNC:
+		fprintf(stdout, "BNC\n");
+		break;
+	case RTE_PORT_MII:
+		fprintf(stdout, "MII\n");
+		break;
+	case RTE_PORT_FIBRE:
+		fprintf(stdout, "FIBRE\n");
+		break;
+	case RTE_PORT_DA:
+		fprintf(stdout, "Direct Attach Copper\n");
+		break;
+	case RTE_PORT_NONE:
+		fprintf(stdout, "None\n");
+		break;
+	case RTE_PORT_OTHER:
+		fprintf(stdout, "Other\n");
+		break;
+	default:
+		fprintf(stdout, "Unknown! (%i)\n", link_settings.base.port);
+		break;
+	};
+
+	fprintf(stdout, "       PHYAD: %d\n", link_settings.base.phy_address);
+
+	fprintf(stdout, "       Auto-negotiation: %s\n",
+		(link_settings.base.link.link_autoneg == RTE_AUTONEG_DISABLE) ?
+		"off" : "on");
+
+	if (link_settings.base.port == RTE_PORT_TP) {
+		fprintf(stdout, "       MDI-X: ");
+		if (link_settings.base.eth_tp_mdix_ctrl == RTE_TP_MDI) {
+			fprintf(stdout, "off (forced)\n");
+		} else if (link_settings.base.eth_tp_mdix_ctrl
+			   == RTE_TP_MDI_X) {
+			fprintf(stdout, "on (forced)\n");
+		} else {
+			switch (link_settings.base.eth_tp_mdix) {
+			case RTE_TP_MDI:
+				fprintf(stdout, "off");
+				break;
+			case RTE_TP_MDI_X:
+				fprintf(stdout, "on");
+				break;
+			default:
+				fprintf(stdout, "Unknown");
+				break;
+			}
+			if (link_settings.base.eth_tp_mdix_ctrl
+			    == RTE_TP_MDI_AUTO)
+				fprintf(stdout, " (auto)");
+			fprintf(stdout, "\n");
+		}
+	}
+}
+
+cmdline_parse_inst_t cmd_link_settings_show = {
+	.f = cmd_link_settings_show_parsed,
+	.data = NULL,
+	.help_str = "show port <port_id> link settings",
+	.tokens = {
+		(void *)&cmd_ls_show_show,
+		(void *)&cmd_ls_show_port,
+		(void *)&cmd_ls_show_portid,
+		(void *)&cmd_ls_show_link,
+		(void *)&cmd_ls_show_settings,
+		NULL,
+	},
+};
+
+static int parse_hex_u32_bitmap(const char *s,
+				unsigned int nbits, uint32_t *result)
+{
+	const unsigned int nwords = RTE_DIV_ROUND_UP(nbits, 32);
+	size_t slen = strlen(s);
+	size_t i;
+
+	/* ignore optional '0x' prefix */
+	if ((slen > 2) && (strncasecmp(s, "0x", 2) == 0)) {
+		slen -= 2;
+		s += 2;
+	}
+
+	if (slen > 8 * nwords)  /* up to 2 digits per byte */
+		return -1;
+
+	memset(result, 0, 4 * nwords);
+	for (i = 0; i < slen; ++i) {
+		const unsigned int shift = (slen - 1 - i) * 4;
+		uint32_t *dest = &result[shift / 32];
+		uint32_t nibble;
+
+		if ('a' <= s[i] && s[i] <= 'f')
+			nibble = 0xa + (s[i] - 'a');
+		else if ('A' <= s[i] && s[i] <= 'F')
+			nibble = 0xa + (s[i] - 'A');
+		else if ('0' <= s[i] && s[i] <= '9')
+			nibble = (s[i] - '0');
+		else
+			return -1;
+
+		*dest |= (nibble << (shift % 32));
+	}
+
+	return 0;
+}
+
+/* *** SET ETHERNET LINK SETTINGS *** */
+struct cmd_link_settings_set {
+	cmdline_fixed_string_t set;
+	cmdline_fixed_string_t port;
+	portid_t port_id;
+	cmdline_fixed_string_t link;
+	cmdline_fixed_string_t settings;
+	cmdline_fixed_string_t advertising;
+	cmdline_multi_string_t bitmap_str;
+};
+
+cmdline_parse_token_string_t cmd_ls_set_set =
+	TOKEN_STRING_INITIALIZER(struct cmd_link_settings_set,
+				set, "set");
+cmdline_parse_token_string_t cmd_ls_set_port =
+	TOKEN_STRING_INITIALIZER(struct cmd_link_settings_set,
+				port, "port");
+cmdline_parse_token_num_t cmd_ls_set_portid =
+	TOKEN_NUM_INITIALIZER(struct cmd_link_settings_set,
+				port_id, RTE_UINT16);
+cmdline_parse_token_string_t cmd_ls_set_link =
+	TOKEN_STRING_INITIALIZER(struct cmd_link_settings_set,
+				link, "link");
+cmdline_parse_token_string_t cmd_ls_set_settings =
+	TOKEN_STRING_INITIALIZER(struct cmd_link_settings_set,
+				settings, "settings");
+cmdline_parse_token_string_t cmd_ls_set_advertising =
+	TOKEN_STRING_INITIALIZER(struct cmd_link_settings_set,
+				advertising, "advertising");
+cmdline_parse_token_string_t cmd_ls_set_bitmap_str =
+	TOKEN_STRING_INITIALIZER(struct cmd_link_settings_set,
+				bitmap_str, TOKEN_STRING_MULTI);
+
+static void
+cmd_link_settings_set_advertising_parsed(void *parsed_result,
+			      __rte_unused struct cmdline *cl,
+			      __rte_unused void *data)
+{
+	struct cmd_link_settings_set *res = parsed_result;
+	struct rte_link_settings link_settings;
+	int ret;
+
+	if (parse_hex_u32_bitmap(res->bitmap_str,
+				__RTE_LINK_MODE_MASK_NBITS,
+				link_settings.link_modes.advertising)) {
+		fprintf(stderr, "cannot parse bitmap_str\n");
+		return;
+
+	}
+
+	link_settings.base.link.link_autoneg = RTE_AUTONEG_ENABLE;
+
+	ret = rte_eth_dev_set_link_settings(res->port_id, &link_settings);
+	if (ret != 0) {
+		fprintf(stderr,
+			"Failed to set link settings: err = %d\n",
+			ret);
+	}
+}
+
+cmdline_parse_inst_t cmd_link_settings_set_advertising = {
+	.f = cmd_link_settings_set_advertising_parsed,
+	.data = NULL,
+	.help_str = "set port <port_id> link settings advertising <bitmap_str>"
+		" Bitmap_str - bitmap respresentation of advertising speeds",
+	.tokens = {
+		(void *)&cmd_ls_set_set,
+		(void *)&cmd_ls_set_port,
+		(void *)&cmd_ls_set_portid,
+		(void *)&cmd_ls_set_link,
+		(void *)&cmd_ls_set_settings,
+		(void *)&cmd_ls_set_advertising,
+		(void *)&cmd_ls_set_bitmap_str,
+		NULL,
+	},
+};
diff --git a/app/test-pmd/cmdline_settings.h b/app/test-pmd/cmdline_settings.h
new file mode 100644
index 0000000000..1bcd75f7ef
--- /dev/null
+++ b/app/test-pmd/cmdline_settings.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright (c) 2024 Arista Networks, Inc.  All rights reserved.
+ * Arista Networks, Inc. Confidential and Proprietary
+ */
+
+#ifndef _CMDLINE_SETTINGS_H
+#define _CMDLINE_SETTINGS_H
+
+/* Link settings CLI */
+extern cmdline_parse_inst_t cmd_link_settings_show;
+extern cmdline_parse_inst_t cmd_link_settings_set_advertising;
+
+#endif /* _CMDLINE_SETTINGS_H */
+
diff --git a/app/test-pmd/meson.build b/app/test-pmd/meson.build
index 719f875be0..7aadc2ec42 100644
--- a/app/test-pmd/meson.build
+++ b/app/test-pmd/meson.build
@@ -11,6 +11,7 @@ sources = files(
         'cmdline_flow.c',
         'cmdline_mtr.c',
         'cmdline_tm.c',
+        'cmdline_settings.c',
         'cmd_flex_item.c',
         'config.c',
         'csumonly.c',
diff --git a/app/test-pmd/testpmd.h b/app/test-pmd/testpmd.h
index 0afae7d771..1873b45d23 100644
--- a/app/test-pmd/testpmd.h
+++ b/app/test-pmd/testpmd.h
@@ -1187,6 +1187,7 @@ void eth_set_allmulticast_mode(uint16_t port, int enable);
 int eth_link_get_nowait_print_err(uint16_t port_id, struct rte_eth_link *link);
 int eth_macaddr_get_print_err(uint16_t port_id,
 			struct rte_ether_addr *mac_addr);
+int get_bit(const uint32_t *ptr, uint32_t pos);
 
 /* Functions to display the set of MAC addresses added to a port*/
 void show_macs(portid_t port_id);
diff --git a/app/test-pmd/util.c b/app/test-pmd/util.c
index bf9b639d95..4d26776cc7 100644
--- a/app/test-pmd/util.c
+++ b/app/test-pmd/util.c
@@ -17,6 +17,8 @@
 
 #define MAX_STRING_LEN 8192
 
+#define UINT_32_BIT_WIDTH (CHAR_BIT * sizeof(uint32_t))
+
 #define MKDUMPSTR(buf, buf_size, cur_len, ...) \
 do { \
 	if (cur_len >= buf_size) \
@@ -525,3 +527,11 @@ eth_macaddr_get_print_err(uint16_t port_id, struct rte_ether_addr *mac_addr)
 
 	return ret;
 }
+
+int
+get_bit(const uint32_t *ptr, uint32_t pos)
+{
+	uint32_t byte_idx = pos / UINT_32_BIT_WIDTH;
+	uint32_t bit_idx = pos % UINT_32_BIT_WIDTH;
+	return (ptr[byte_idx] >> bit_idx) & 0x1;
+}
diff --git a/drivers/net/igc/igc_ethdev.c b/drivers/net/igc/igc_ethdev.c
index 87d7f7caa0..af11a6a3dd 100644
--- a/drivers/net/igc/igc_ethdev.c
+++ b/drivers/net/igc/igc_ethdev.c
@@ -91,6 +91,8 @@
 uint64_t igc_tx_timestamp_dynflag;
 int igc_tx_timestamp_dynfield_offset = -1;
 
+#define IGC_32_BIT_WIDTH (CHAR_BIT * sizeof(uint32_t))
+
 static const struct rte_eth_desc_lim rx_desc_lim = {
 	.nb_max = IGC_MAX_RXD,
 	.nb_min = IGC_MIN_RXD,
@@ -273,6 +275,10 @@ static int eth_igc_timesync_read_time(struct rte_eth_dev *dev,
 static int eth_igc_timesync_write_time(struct rte_eth_dev *dev,
 				   const struct timespec *timestamp);
 static int eth_igc_read_clock(struct rte_eth_dev *dev, uint64_t *clock);
+static int eth_igc_get_link_settings(struct rte_eth_dev *dev,
+				struct rte_link_settings *link_settings);
+static int eth_igc_set_link_settings(struct rte_eth_dev *dev,
+				const struct rte_link_settings *link_settings);
 
 static const struct eth_dev_ops eth_igc_ops = {
 	.dev_configure		= eth_igc_configure,
@@ -334,6 +340,8 @@ static const struct eth_dev_ops eth_igc_ops = {
 	.timesync_read_time	= eth_igc_timesync_read_time,
 	.timesync_write_time	= eth_igc_timesync_write_time,
 	.read_clock             = eth_igc_read_clock,
+	.get_link_settings      = eth_igc_get_link_settings,
+	.set_link_settings      = eth_igc_set_link_settings,
 };
 
 /*
@@ -532,8 +540,8 @@ eth_igc_link_update(struct rte_eth_dev *dev, int wait_to_complete)
 			}
 		}
 	} else {
-		link.link_speed = 0;
-		link.link_duplex = RTE_ETH_LINK_HALF_DUPLEX;
+		link.link_speed = RTE_ETH_SPEED_NUM_UNKNOWN;
+		link.link_duplex = RTE_ETH_LINK_UNKNOWN_DUPLEX;
 		link.link_status = RTE_ETH_LINK_DOWN;
 		link.link_autoneg = RTE_ETH_LINK_FIXED;
 	}
@@ -2876,6 +2884,223 @@ eth_igc_read_clock(__rte_unused struct rte_eth_dev *dev, uint64_t *clock)
 	return 0;
 }
 
+static inline void
+igc_set_bit(uint32_t *ptr, uint32_t pos)
+{
+	uint32_t byte_idx = pos / IGC_32_BIT_WIDTH;
+	uint32_t bit_idx = pos % IGC_32_BIT_WIDTH;
+	uint32_t tmp;
+
+	tmp = ptr[byte_idx];
+	tmp &= ~(RTE_BIT32(bit_idx));
+	tmp |= RTE_BIT32(bit_idx);
+	ptr[byte_idx] = tmp;
+}
+
+static inline uint8_t
+igc_get_bit(const uint32_t *ptr, uint32_t pos)
+{
+	uint32_t byte_idx = pos / IGC_32_BIT_WIDTH;
+	uint32_t bit_idx = pos % IGC_32_BIT_WIDTH;
+
+	return (ptr[byte_idx] >> bit_idx) & 0x1;
+}
+
+static int eth_igc_get_link_settings(struct rte_eth_dev *dev,
+				     struct rte_link_settings *link_settings)
+{
+	s32 ret_val = IGC_SUCCESS;
+	s32 link_check = 0;
+	struct igc_hw *hw = IGC_DEV_PRIVATE_HW(dev);
+	uint32_t *supported = link_settings->link_modes.supported;
+	uint32_t *advertising = link_settings->link_modes.advertising;
+	uint32_t *lp_advertising = link_settings->link_modes.lp_advertising;
+
+	memset(supported, 0x00, __RTE_LINK_MODE_MASK_NU32 * sizeof(uint32_t));
+	memset(advertising, 0x00, __RTE_LINK_MODE_MASK_NU32 * sizeof(uint32_t));
+	memset(lp_advertising, 0x00, __RTE_LINK_MODE_MASK_NU32 * sizeof(uint32_t));
+
+	igc_set_bit(supported, RTE_LINK_MODE_10baseT_Half_BIT);
+	igc_set_bit(supported, RTE_LINK_MODE_10baseT_Full_BIT);
+	igc_set_bit(supported, RTE_LINK_MODE_100baseT_Half_BIT);
+	igc_set_bit(supported, RTE_LINK_MODE_100baseT_Full_BIT);
+	igc_set_bit(supported, RTE_LINK_MODE_1000baseT_Full_BIT);
+	igc_set_bit(supported, RTE_LINK_MODE_2500baseT_Full_BIT);
+
+	/* twisted pair */
+	link_settings->base.port = RTE_PORT_TP;
+	/* MDIO address of PHY (transceiver) */
+	link_settings->base.phy_address = hw->phy.addr;
+	igc_set_bit(supported, RTE_LINK_MODE_TP_BIT);
+	igc_set_bit(advertising, RTE_LINK_MODE_TP_BIT);
+
+	if (hw->phy.autoneg_advertised & ADVERTISE_10_HALF)
+		igc_set_bit(advertising, RTE_LINK_MODE_10baseT_Half_BIT);
+	if (hw->phy.autoneg_advertised & ADVERTISE_10_FULL)
+		igc_set_bit(advertising, RTE_LINK_MODE_10baseT_Full_BIT);
+	if (hw->phy.autoneg_advertised & ADVERTISE_100_HALF)
+		igc_set_bit(advertising, RTE_LINK_MODE_100baseT_Half_BIT);
+	if (hw->phy.autoneg_advertised & ADVERTISE_100_FULL)
+		igc_set_bit(advertising, RTE_LINK_MODE_100baseT_Full_BIT);
+	if (hw->phy.autoneg_advertised & ADVERTISE_1000_FULL)
+		igc_set_bit(advertising, RTE_LINK_MODE_1000baseT_Full_BIT);
+	if (hw->phy.autoneg_advertised & ADVERTISE_2500_FULL)
+		igc_set_bit(advertising, RTE_LINK_MODE_2500baseT_Full_BIT);
+
+	/* set autoneg settings */
+	if (hw->mac.autoneg == 1) {
+		igc_set_bit(supported, RTE_LINK_MODE_Autoneg_BIT);
+		igc_set_bit(advertising, RTE_LINK_MODE_Autoneg_BIT);
+		link_settings->base.link.link_autoneg = RTE_AUTONEG_ENABLE;
+	} else {
+		link_settings->base.link.link_autoneg = RTE_AUTONEG_DISABLE;
+	}
+
+	/* Set pause flow control settings */
+	igc_set_bit(supported, RTE_LINK_MODE_Pause_BIT);
+
+	switch (hw->fc.requested_mode) {
+	case igc_fc_full:
+		igc_set_bit(advertising, RTE_LINK_MODE_Pause_BIT);
+		break;
+	case igc_fc_rx_pause:
+		igc_set_bit(advertising, RTE_LINK_MODE_Pause_BIT);
+		igc_set_bit(advertising, RTE_LINK_MODE_Asym_Pause_BIT);
+		break;
+	case igc_fc_tx_pause:
+		igc_set_bit(advertising, RTE_LINK_MODE_Asym_Pause_BIT);
+		break;
+	default:
+		break;
+	}
+
+	hw->mac.get_link_status = 1;
+	/* Read the real link status */
+	switch (hw->phy.media_type) {
+	case igc_media_type_copper:
+		/* Do the work to read phy */
+		igc_check_for_link(hw);
+		link_check = !hw->mac.get_link_status;
+		break;
+	case igc_media_type_fiber:
+		igc_check_for_link(hw);
+		link_check = (IGC_READ_REG(hw, IGC_STATUS) &
+			      IGC_STATUS_LU);
+		break;
+	case igc_media_type_internal_serdes:
+		igc_check_for_link(hw);
+		link_check = hw->mac.serdes_has_link;
+		break;
+	default:
+		break;
+	}
+
+	/* Now we check if a transition has happened */
+	if (link_check) {
+		uint16_t duplex, speed;
+		hw->mac.ops.get_link_up_info(hw, &speed, &duplex);
+		link_settings->base.link.link_duplex = (duplex == FULL_DUPLEX) ?
+				RTE_ETH_LINK_FULL_DUPLEX :
+				RTE_ETH_LINK_HALF_DUPLEX;
+		link_settings->base.link.link_speed = speed;
+		link_settings->base.link.link_status = RTE_ETH_LINK_UP;
+		link_settings->base.link.link_autoneg = !(dev->data->dev_conf.link_speeds &
+				RTE_ETH_LINK_SPEED_FIXED);
+		if (speed == SPEED_2500) {
+			uint32_t tipg = IGC_READ_REG(hw, IGC_TIPG);
+			if ((tipg & IGC_TIPG_IPGT_MASK) != 0x0b) {
+				tipg &= ~IGC_TIPG_IPGT_MASK;
+				tipg |= 0x0b;
+				IGC_WRITE_REG(hw, IGC_TIPG, tipg);
+			}
+		}
+	} else {
+		link_settings->base.link.link_speed = 0;
+		link_settings->base.link.link_duplex = RTE_ETH_LINK_HALF_DUPLEX;
+		link_settings->base.link.link_status = RTE_ETH_LINK_DOWN;
+		link_settings->base.link.link_autoneg = RTE_ETH_LINK_FIXED;
+	}
+
+	/* MDI-X => 2; MDI =>1; Invalid =>0 */
+	if (hw->phy.media_type == igc_media_type_copper)
+		link_settings->base.eth_tp_mdix = hw->phy.is_mdix ? RTE_TP_MDI_X :
+						      RTE_TP_MDI;
+	else
+		link_settings->base.eth_tp_mdix = RTE_TP_MDI_INVALID;
+
+	if (hw->phy.mdix == 0) /* AUTO_ALL_MODES */
+		link_settings->base.eth_tp_mdix_ctrl = RTE_TP_MDI_AUTO;
+	else
+		link_settings->base.eth_tp_mdix_ctrl = hw->phy.mdix;
+
+	return ret_val;
+}
+
+static int eth_igc_set_link_settings(struct rte_eth_dev *dev,
+			 const struct rte_link_settings *link_settings)
+{
+	struct igc_hw *hw = IGC_DEV_PRIVATE_HW(dev);
+	struct igc_adapter *adapter = IGC_DEV_PRIVATE(dev);
+	const uint32_t *advertising = link_settings->link_modes.advertising;
+	int ret = IGC_SUCCESS;
+
+	if (igc_check_reset_block(hw)) {
+		PMD_DRV_LOG(ERR, "Cannot change link characteristics when reset is active\n");
+		return -EINVAL;
+	}
+
+	/* MDI setting is only allowed when autoneg enabled because
+	 * some hardware doesn't allow MDI setting when speed or
+	 * duplex is forced.
+	 */
+	if (link_settings->base.eth_tp_mdix_ctrl) {
+		if (link_settings->base.eth_tp_mdix_ctrl != RTE_TP_MDI_AUTO &&
+		    link_settings->base.link.link_autoneg != RTE_AUTONEG_ENABLE) {
+			PMD_DRV_LOG(ERR, "Forcing MDI/MDI-X state is not supported "
+					 "when link speed and/or duplex are forced\n");
+			return -EINVAL;
+		}
+	}
+
+	/* All modes for igc but one fits into first byte of bitmask */
+	uint32_t igc_advertising = link_settings->link_modes.advertising[0];
+	/* Converting to u32 drops RTE_LINK_MODE_2500baseT_Full_BIT.
+	 * We have to check this and convert it to ADVERTISE_2500_FULL
+	 * (aka RTE_LINK_MODE_2500baseX_Full_BIT) explicitly.
+	 */
+	if (igc_get_bit(advertising, RTE_LINK_MODE_2500baseT_Full_BIT))
+		igc_advertising |= ADVERTISE_2500_FULL;
+
+	if (link_settings->base.link.link_autoneg == RTE_AUTONEG_ENABLE) {
+		hw->mac.autoneg = 1;
+		hw->phy.autoneg_advertised = igc_advertising;
+		hw->fc.requested_mode = igc_fc_default;
+	} else {
+		PMD_DRV_LOG(INFO, "Force mode currently not supported\n");
+	}
+
+	/* MDI-X => 2; MDI => 1; Auto => 3 */
+	if (link_settings->base.eth_tp_mdix_ctrl) {
+		/* fix up the value for auto (3 => 0) as zero is mapped
+		 * internally to auto
+		 */
+		if (link_settings->base.eth_tp_mdix_ctrl == RTE_TP_MDI_AUTO)
+			hw->phy.mdix = 0; /* AUTO_ALL_MODES */
+		else
+			hw->phy.mdix = link_settings->base.eth_tp_mdix_ctrl;
+	}
+
+	/* reset the link */
+	if (!adapter->stopped) {
+		eth_igc_set_link_down(dev);
+		eth_igc_set_link_up(dev);
+	} else {
+		eth_igc_reset(dev);
+	}
+
+	return ret;
+}
+
 static int
 eth_igc_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,
 	struct rte_pci_device *pci_dev)
diff --git a/drivers/net/ixgbe/base/ixgbe_phy.h b/drivers/net/ixgbe/base/ixgbe_phy.h
index ceefbb3e68..f4d22951be 100644
--- a/drivers/net/ixgbe/base/ixgbe_phy.h
+++ b/drivers/net/ixgbe/base/ixgbe_phy.h
@@ -125,6 +125,13 @@
 /* SFP+ SFF-8472 Compliance */
 #define IXGBE_SFF_SFF_8472_UNSUP	0x00
 
+#define IXGBE_SPEED_10000	10000
+
+/* Duplex, half or full. */
+#define IXGBE_DUPLEX_HALF	0x00
+#define IXGBE_DUPLEX_FULL	0x01
+#define IXGBE_DUPLEX_UNKNOWN	0xff
+
 s32 ixgbe_init_phy_ops_generic(struct ixgbe_hw *hw);
 bool ixgbe_validate_phy_addr(struct ixgbe_hw *hw, u32 phy_addr);
 enum ixgbe_phy_type ixgbe_get_phy_type_from_id(u32 phy_id);
diff --git a/drivers/net/ixgbe/ixgbe_ethdev.c b/drivers/net/ixgbe/ixgbe_ethdev.c
index c61c52b296..2fd4a34b55 100644
--- a/drivers/net/ixgbe/ixgbe_ethdev.c
+++ b/drivers/net/ixgbe/ixgbe_ethdev.c
@@ -94,6 +94,7 @@
 #define IXGBE_4_BIT_MASK   RTE_LEN2MASK(IXGBE_4_BIT_WIDTH, uint8_t)
 #define IXGBE_8_BIT_WIDTH  CHAR_BIT
 #define IXGBE_8_BIT_MASK   UINT8_MAX
+#define IXGBE_32_BIT_WIDTH (CHAR_BIT * sizeof(uint32_t))
 
 #define IXGBEVF_PMD_NAME "rte_ixgbevf_pmd" /* PMD name */
 
@@ -130,6 +131,8 @@
 
 #define IXGBE_DEVARG_FIBER_SDP3_NOT_TX_DISABLE	"fiber_sdp3_no_tx_disable"
 
+#define IXGBE_ISBACKPLANE(type)             ((type) == ixgbe_media_type_backplane)
+
 static const char * const ixgbe_valid_arguments[] = {
 	IXGBE_DEVARG_FIBER_SDP3_NOT_TX_DISABLE,
 	NULL
@@ -353,6 +356,10 @@ static int ixgbe_dev_udp_tunnel_port_add(struct rte_eth_dev *dev,
 					 struct rte_eth_udp_tunnel *udp_tunnel);
 static int ixgbe_dev_udp_tunnel_port_del(struct rte_eth_dev *dev,
 					 struct rte_eth_udp_tunnel *udp_tunnel);
+static int ixgbe_get_link_settings(struct rte_eth_dev *dev,
+				   struct rte_link_settings *link_settings);
+static int ixgbe_set_link_settings(struct rte_eth_dev *dev,
+				   const struct rte_link_settings *link_settings);
 static int ixgbe_filter_restore(struct rte_eth_dev *dev);
 static void ixgbe_l2_tunnel_conf(struct rte_eth_dev *dev);
 static int ixgbe_wait_for_link_up(struct ixgbe_hw *hw);
@@ -564,6 +571,8 @@ static const struct eth_dev_ops ixgbe_eth_dev_ops = {
 	.tm_ops_get           = ixgbe_tm_ops_get,
 	.tx_done_cleanup      = ixgbe_dev_tx_done_cleanup,
 	.get_monitor_addr     = ixgbe_get_monitor_addr,
+	.get_link_settings    = ixgbe_get_link_settings,
+	.set_link_settings    = ixgbe_set_link_settings,
 };
 
 /*
@@ -7791,6 +7800,392 @@ ixgbe_dev_udp_tunnel_port_del(struct rte_eth_dev *dev,
 	return ret;
 }
 
+static inline void
+ixgbe_set_bit(uint32_t *ptr, uint32_t pos)
+{
+	uint32_t byte_idx = pos / IXGBE_32_BIT_WIDTH;
+	uint32_t bit_idx = pos % IXGBE_32_BIT_WIDTH;
+	uint32_t tmp;
+
+	tmp = ptr[byte_idx];
+	tmp &= ~(1 << bit_idx);
+	tmp |= 1 << bit_idx;
+	ptr[byte_idx] = tmp;
+}
+
+static inline uint8_t
+ixgbe_get_bit(const uint32_t *ptr, uint32_t pos)
+{
+	uint32_t byte_idx = pos / IXGBE_32_BIT_WIDTH;
+	uint32_t bit_idx = pos % IXGBE_32_BIT_WIDTH;
+
+	return (ptr[byte_idx] >> bit_idx) & 0x1;
+}
+
+
+static inline bool
+ixgbe_is_subset(const uint32_t *bitmap1, const uint32_t *bitmap2,
+		uint32_t nbits)
+{
+	uint32_t full_bytes_cnt = nbits / IXGBE_32_BIT_WIDTH;
+	uint32_t last_byte_bit_idx = nbits % IXGBE_32_BIT_WIDTH;
+
+	for (uint32_t idx = 0; idx < full_bytes_cnt; idx++) {
+		if (bitmap1[idx] & ~bitmap2[idx])
+			return false;
+	}
+
+	uint32_t last_chunk_mask = ((1ULL << last_byte_bit_idx) - 1) |
+				    (1ULL << last_byte_bit_idx);
+	if ((bitmap1[full_bytes_cnt] & ~bitmap2[full_bytes_cnt]) & last_chunk_mask)
+		return false;
+
+	return true;
+}
+
+static void ixgbe_set_supported_10gtypes(struct ixgbe_hw *hw,
+					 uint32_t *bitmap)
+{
+	if (!IXGBE_ISBACKPLANE(hw->phy.media_type)) {
+		ixgbe_set_bit(bitmap, RTE_LINK_MODE_10000baseT_Full_BIT);
+		return;
+	}
+
+	switch (hw->device_id) {
+	case IXGBE_DEV_ID_82598:
+	case IXGBE_DEV_ID_82599_KX4:
+	case IXGBE_DEV_ID_82599_KX4_MEZZ:
+	case IXGBE_DEV_ID_X550EM_X_KX4:
+		ixgbe_set_bit(bitmap, RTE_LINK_MODE_10000baseKX4_Full_BIT);
+		break;
+	case IXGBE_DEV_ID_82598_BX:
+	case IXGBE_DEV_ID_82599_KR:
+	case IXGBE_DEV_ID_X550EM_X_KR:
+	case IXGBE_DEV_ID_X550EM_X_XFI:
+		ixgbe_set_bit(bitmap, RTE_LINK_MODE_10000baseKR_Full_BIT);
+		break;
+	default:
+		ixgbe_set_bit(bitmap, RTE_LINK_MODE_10000baseKX4_Full_BIT);
+		ixgbe_set_bit(bitmap, RTE_LINK_MODE_10000baseKR_Full_BIT);
+		break;
+	}
+}
+
+static int ixgbe_get_link_settings(struct rte_eth_dev *dev,
+				   struct rte_link_settings *link_settings)
+{
+	int ret_val = IXGBE_SUCCESS;
+	int wait = 1;
+	bool link_up;
+	bool autoneg;
+	uint32_t esdp_reg;
+	ixgbe_link_speed link_speed = IXGBE_LINK_SPEED_UNKNOWN;
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	struct ixgbe_adapter *ad = dev->data->dev_private;
+	uint32_t *supported = link_settings->link_modes.supported;
+	uint32_t *advertising = link_settings->link_modes.advertising;
+	uint32_t *lp_advertising = link_settings->link_modes.lp_advertising;
+
+	memset(supported, 0x00, __RTE_LINK_MODE_MASK_NU32 * sizeof(uint32_t));
+	memset(advertising, 0x00, __RTE_LINK_MODE_MASK_NU32 * sizeof(uint32_t));
+	memset(lp_advertising, 0x00, __RTE_LINK_MODE_MASK_NU32 * sizeof(uint32_t));
+
+	/* Get supported speeds */
+	ret_val = ixgbe_get_link_capabilities(hw, &link_speed, &autoneg);
+	if (ret_val != IXGBE_SUCCESS)
+		return ret_val;
+
+	if (link_speed & IXGBE_LINK_SPEED_10GB_FULL) {
+		ixgbe_set_supported_10gtypes(hw, supported);
+		ixgbe_set_supported_10gtypes(hw, advertising);
+	}
+
+	if (link_speed & IXGBE_LINK_SPEED_5GB_FULL)
+		ixgbe_set_bit(supported, RTE_LINK_MODE_5000baseT_Full_BIT);
+
+	if (link_speed & IXGBE_LINK_SPEED_2_5GB_FULL)
+		ixgbe_set_bit(supported, RTE_LINK_MODE_2500baseT_Full_BIT);
+
+	if (link_speed & IXGBE_LINK_SPEED_1GB_FULL) {
+		if (IXGBE_ISBACKPLANE(hw->phy.media_type)) {
+			ixgbe_set_bit(supported, RTE_LINK_MODE_1000baseKX_Full_BIT);
+			ixgbe_set_bit(advertising, RTE_LINK_MODE_1000baseKX_Full_BIT);
+		} else {
+			ixgbe_set_bit(supported, RTE_LINK_MODE_1000baseT_Full_BIT);
+			ixgbe_set_bit(advertising, RTE_LINK_MODE_1000baseT_Full_BIT);
+		}
+	}
+	if (link_speed & IXGBE_LINK_SPEED_100_FULL) {
+		ixgbe_set_bit(supported, RTE_LINK_MODE_100baseT_Full_BIT);
+		ixgbe_set_bit(advertising, RTE_LINK_MODE_100baseT_Full_BIT);
+	}
+	if (link_speed & IXGBE_LINK_SPEED_10_FULL) {
+		ixgbe_set_bit(supported, RTE_LINK_MODE_10baseT_Full_BIT);
+		ixgbe_set_bit(advertising, RTE_LINK_MODE_10baseT_Full_BIT);
+	}
+
+	/* set the advertised speeds */
+	if (hw->phy.autoneg_advertised) {
+		if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_10_FULL)
+			ixgbe_set_bit(advertising, RTE_LINK_MODE_10baseT_Full_BIT);
+		if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_100_FULL)
+			ixgbe_set_bit(advertising, RTE_LINK_MODE_100baseT_Full_BIT);
+		if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_10GB_FULL)
+			ixgbe_set_supported_10gtypes(hw, advertising);
+		if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_1GB_FULL) {
+			if (ixgbe_get_bit(supported, RTE_LINK_MODE_1000baseKX_Full_BIT))
+				ixgbe_set_bit(advertising,
+					      RTE_LINK_MODE_1000baseKX_Full_BIT);
+			else
+				ixgbe_set_bit(advertising,
+					      RTE_LINK_MODE_1000baseT_Full_BIT);
+		}
+		if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_5GB_FULL)
+			ixgbe_set_bit(advertising, RTE_LINK_MODE_5000baseT_Full_BIT);
+		if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_2_5GB_FULL)
+			ixgbe_set_bit(advertising, RTE_LINK_MODE_2500baseT_Full_BIT);
+	} else {
+		if (hw->phy.multispeed_fiber && !autoneg) {
+			if (link_speed & IXGBE_LINK_SPEED_10GB_FULL)
+				ixgbe_set_bit(advertising,
+					      RTE_LINK_MODE_10000baseT_Full_BIT);
+		}
+	}
+
+	if (autoneg) {
+		ixgbe_set_bit(supported, RTE_LINK_MODE_Autoneg_BIT);
+		ixgbe_set_bit(advertising, RTE_LINK_MODE_Autoneg_BIT);
+		link_settings->base.link.link_autoneg = RTE_AUTONEG_ENABLE;
+	} else {
+		link_settings->base.link.link_autoneg = RTE_AUTONEG_DISABLE;
+	}
+
+	switch (hw->phy.type) {
+	case ixgbe_phy_tn:
+	case ixgbe_phy_aq:
+	case ixgbe_phy_x550em_ext_t:
+	case ixgbe_phy_fw:
+	case ixgbe_phy_cu_unknown:
+		ixgbe_set_bit(supported, RTE_LINK_MODE_TP_BIT);
+		ixgbe_set_bit(advertising, RTE_LINK_MODE_TP_BIT);
+		link_settings->base.port = RTE_PORT_TP;
+		break;
+	case ixgbe_phy_qt:
+		ixgbe_set_bit(supported, RTE_LINK_MODE_FIBRE_BIT);
+		ixgbe_set_bit(advertising, RTE_LINK_MODE_FIBRE_BIT);
+		link_settings->base.port = RTE_PORT_FIBRE;
+		break;
+	case ixgbe_phy_nl:
+	case ixgbe_phy_sfp_passive_tyco:
+	case ixgbe_phy_sfp_passive_unknown:
+	case ixgbe_phy_sfp_ftl:
+	case ixgbe_phy_sfp_avago:
+	case ixgbe_phy_sfp_intel:
+	case ixgbe_phy_sfp_unknown:
+	case ixgbe_phy_qsfp_passive_unknown:
+	case ixgbe_phy_qsfp_active_unknown:
+	case ixgbe_phy_qsfp_intel:
+	case ixgbe_phy_qsfp_unknown:
+		/* SFP+ devices, further checking needed */
+		switch (hw->phy.sfp_type) {
+		case ixgbe_sfp_type_da_cu:
+		case ixgbe_sfp_type_da_cu_core0:
+		case ixgbe_sfp_type_da_cu_core1:
+			ixgbe_set_bit(supported, RTE_LINK_MODE_FIBRE_BIT);
+			ixgbe_set_bit(advertising, RTE_LINK_MODE_FIBRE_BIT);
+			link_settings->base.port = RTE_PORT_DA;
+			break;
+		case ixgbe_sfp_type_sr:
+		case ixgbe_sfp_type_lr:
+		case ixgbe_sfp_type_srlr_core0:
+		case ixgbe_sfp_type_srlr_core1:
+		case ixgbe_sfp_type_1g_sx_core0:
+		case ixgbe_sfp_type_1g_sx_core1:
+		case ixgbe_sfp_type_1g_lx_core0:
+		case ixgbe_sfp_type_1g_lx_core1:
+			ixgbe_set_bit(supported, RTE_LINK_MODE_FIBRE_BIT);
+			ixgbe_set_bit(advertising, RTE_LINK_MODE_FIBRE_BIT);
+			link_settings->base.port = RTE_PORT_FIBRE;
+			break;
+		case ixgbe_sfp_type_not_present:
+			ixgbe_set_bit(supported, RTE_LINK_MODE_FIBRE_BIT);
+			ixgbe_set_bit(advertising, RTE_LINK_MODE_FIBRE_BIT);
+			link_settings->base.port = RTE_PORT_NONE;
+			break;
+		case ixgbe_sfp_type_1g_cu_core0:
+		case ixgbe_sfp_type_1g_cu_core1:
+			ixgbe_set_bit(supported, RTE_LINK_MODE_TP_BIT);
+			ixgbe_set_bit(advertising, RTE_LINK_MODE_TP_BIT);
+			link_settings->base.port = RTE_PORT_TP;
+			break;
+		case ixgbe_sfp_type_unknown:
+		default:
+			ixgbe_set_bit(supported, RTE_LINK_MODE_FIBRE_BIT);
+			ixgbe_set_bit(advertising, RTE_LINK_MODE_FIBRE_BIT);
+			link_settings->base.port = RTE_PORT_OTHER;
+			break;
+		}
+		break;
+	case ixgbe_phy_xaui:
+		ixgbe_set_bit(supported, RTE_LINK_MODE_FIBRE_BIT);
+		ixgbe_set_bit(advertising, RTE_LINK_MODE_FIBRE_BIT);
+		link_settings->base.port = RTE_PORT_NONE;
+		break;
+	case ixgbe_phy_unknown:
+	case ixgbe_phy_generic:
+	case ixgbe_phy_sfp_unsupported:
+	default:
+		ixgbe_set_bit(supported, RTE_LINK_MODE_FIBRE_BIT);
+		ixgbe_set_bit(advertising, RTE_LINK_MODE_FIBRE_BIT);
+		link_settings->base.port = RTE_PORT_OTHER;
+		break;
+	}
+
+	/* Indicate pause support */
+	ixgbe_set_bit(supported, RTE_LINK_MODE_Pause_BIT);
+	switch (hw->fc.requested_mode) {
+	case ixgbe_fc_full:
+		ixgbe_set_bit(advertising, RTE_LINK_MODE_Pause_BIT);
+		break;
+	case ixgbe_fc_rx_pause:
+		ixgbe_set_bit(advertising, RTE_LINK_MODE_Pause_BIT);
+		ixgbe_set_bit(advertising, RTE_LINK_MODE_Asym_Pause_BIT);
+		break;
+	case ixgbe_fc_tx_pause:
+		ixgbe_set_bit(advertising, RTE_LINK_MODE_Asym_Pause_BIT);
+		break;
+	default:
+		ixgbe_set_bit(advertising, RTE_LINK_MODE_Pause_BIT);
+		ixgbe_set_bit(advertising, RTE_LINK_MODE_Asym_Pause_BIT);
+	}
+
+	link_settings->base.link.link_status = RTE_ETH_LINK_DOWN;
+	link_settings->base.link.link_speed = RTE_ETH_SPEED_NUM_NONE;
+	link_settings->base.link.link_duplex = RTE_ETH_LINK_HALF_DUPLEX;
+
+	hw->mac.get_link_status = true;
+	/* check if it needs to wait to complete, if lsc interrupt is enabled */
+	if (dev->data->dev_conf.intr_conf.lsc != 0)
+		wait = 0;
+
+	ret_val = ixgbe_check_link(hw, &link_speed, &link_up, wait);
+	if (ret_val != IXGBE_SUCCESS)
+		return ret_val;
+
+	if (ixgbe_get_media_type(hw) == ixgbe_media_type_fiber &&
+		!ad->sdp3_no_tx_disable) {
+		esdp_reg = IXGBE_READ_REG(hw, IXGBE_ESDP);
+		if ((esdp_reg & IXGBE_ESDP_SDP3))
+			link_up = 0;
+	}
+
+	if (link_up) {
+		link_settings->base.link.link_status = RTE_ETH_LINK_UP;
+		link_settings->base.link.link_status = RTE_ETH_LINK_FULL_DUPLEX;
+		switch (link_speed) {
+		default:
+		case IXGBE_LINK_SPEED_UNKNOWN:
+			link_settings->base.link.link_speed = RTE_ETH_SPEED_NUM_UNKNOWN;
+			break;
+
+		case IXGBE_LINK_SPEED_10_FULL:
+			link_settings->base.link.link_speed = RTE_ETH_SPEED_NUM_10M;
+			break;
+
+		case IXGBE_LINK_SPEED_100_FULL:
+			link_settings->base.link.link_speed = RTE_ETH_SPEED_NUM_100M;
+			break;
+
+		case IXGBE_LINK_SPEED_1GB_FULL:
+			link_settings->base.link.link_speed = RTE_ETH_SPEED_NUM_1G;
+			break;
+
+		case IXGBE_LINK_SPEED_2_5GB_FULL:
+			link_settings->base.link.link_speed = RTE_ETH_SPEED_NUM_2_5G;
+			break;
+
+		case IXGBE_LINK_SPEED_5GB_FULL:
+			link_settings->base.link.link_speed = RTE_ETH_SPEED_NUM_5G;
+			break;
+
+		case IXGBE_LINK_SPEED_10GB_FULL:
+			link_settings->base.link.link_speed = RTE_ETH_SPEED_NUM_10G;
+			break;
+		}
+	}
+
+	return ret_val;
+}
+
+static int ixgbe_set_link_settings(struct rte_eth_dev *dev,
+				   const struct rte_link_settings *link_settings)
+{
+	struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	const uint32_t *supported = link_settings->link_modes.supported;
+	const uint32_t *advertising = link_settings->link_modes.advertising;
+
+	u32 advertised, old;
+	int ret = 0;
+
+	if (hw->phy.media_type == ixgbe_media_type_copper ||
+	    (IXGBE_ISBACKPLANE(hw->phy.media_type)) ||
+	    hw->phy.multispeed_fiber) {
+		/*
+		 * Check if advertising is subset of supported
+		 */
+		if (!ixgbe_is_subset(advertising, supported,
+				     __RTE_LINK_MODE_MASK_NBITS))
+			return -EINVAL;
+
+		/* only allow one speed at a time if no autoneg */
+		if (!link_settings->base.link.link_autoneg && hw->phy.multispeed_fiber) {
+			if (ixgbe_get_bit(advertising,
+					  RTE_LINK_MODE_10000baseT_Full_BIT) &&
+			    ixgbe_get_bit(advertising,
+					  RTE_LINK_MODE_1000baseT_Full_BIT))
+				return -EINVAL;
+		}
+
+		old = hw->phy.autoneg_advertised;
+		advertised = 0;
+		if ((ixgbe_get_bit(advertising, RTE_LINK_MODE_10000baseT_Full_BIT)) ||
+		    (ixgbe_get_bit(advertising, RTE_LINK_MODE_10000baseKR_Full_BIT)) ||
+		    (ixgbe_get_bit(advertising, RTE_LINK_MODE_10000baseKX4_Full_BIT)))
+			advertised |= IXGBE_LINK_SPEED_10GB_FULL;
+		if (ixgbe_get_bit(advertising, RTE_LINK_MODE_5000baseT_Full_BIT))
+			advertised |= IXGBE_LINK_SPEED_5GB_FULL;
+		if (ixgbe_get_bit(advertising, RTE_LINK_MODE_2500baseT_Full_BIT))
+			advertised |= IXGBE_LINK_SPEED_2_5GB_FULL;
+		if ((ixgbe_get_bit(advertising, RTE_LINK_MODE_1000baseT_Full_BIT)) ||
+		    (ixgbe_get_bit(advertising, RTE_LINK_MODE_1000baseKX_Full_BIT)))
+			advertised |= IXGBE_LINK_SPEED_1GB_FULL;
+		if (ixgbe_get_bit(advertising, RTE_LINK_MODE_100baseT_Full_BIT))
+			advertised |= IXGBE_LINK_SPEED_100_FULL;
+		if (ixgbe_get_bit(advertising, RTE_LINK_MODE_10baseT_Full_BIT))
+			advertised |= IXGBE_LINK_SPEED_10_FULL;
+		if (old == advertised)
+			return ret;
+
+		hw->mac.autotry_restart = true;
+		ret = hw->mac.ops.setup_link(hw, advertised, true);
+		if (ret) {
+			PMD_DRV_LOG(WARNING, "setup link failed with code %d\n", ret);
+			hw->mac.ops.setup_link(hw, old, true);
+		}
+	} else {
+		/* in this case we currently only support 10Gb/FULL */
+		u32 speed = link_settings->base.link.link_speed;
+
+		if (link_settings->base.link.link_autoneg == RTE_AUTONEG_ENABLE ||
+		    (!ixgbe_get_bit(advertising, RTE_LINK_MODE_10000baseT_Full_BIT)) ||
+		    (speed + link_settings->base.link.link_duplex !=
+						IXGBE_SPEED_10000 + IXGBE_DUPLEX_FULL))
+			return -EINVAL;
+	}
+
+	return ret;
+}
+
 static int
 ixgbevf_dev_promiscuous_enable(struct rte_eth_dev *dev)
 {
diff --git a/lib/ethdev/ethdev_driver.h b/lib/ethdev/ethdev_driver.h
index 0dbf2dd6a2..ee8f786b99 100644
--- a/lib/ethdev/ethdev_driver.h
+++ b/lib/ethdev/ethdev_driver.h
@@ -1119,6 +1119,34 @@ typedef const uint32_t *(*eth_buffer_split_supported_hdr_ptypes_get_t)(struct rt
  */
 typedef int (*eth_dev_priv_dump_t)(struct rte_eth_dev *dev, FILE *file);
 
+/** @internal Retrieve physical link settings of a port.
+ *
+ * @param dev
+ *   Port (ethdev) handle
+ *
+ * @param[out] settings
+ *   Physical port link settings.
+ *
+ * @return
+ *   Negative errno value on error, zero otherwise
+ */
+typedef int (*eth_get_link_settings_t)(struct rte_eth_dev *dev,
+				 struct rte_link_settings *settings);
+
+/** @internal Configure physical link settings of a port.
+ *
+ * @param dev
+ *   Port (ethdev) handle
+ *
+ * @param settings
+ *   Physical port link settings.
+ *
+ * @return
+ *   Negative errno value on error, zero otherwise
+ */
+typedef int (*eth_set_link_settings_t)(struct rte_eth_dev *dev,
+				 const struct rte_link_settings *settings);
+
 /**
  * @internal Set Rx queue available descriptors threshold.
  * @see rte_eth_rx_avail_thresh_set()
@@ -1474,6 +1502,11 @@ struct eth_dev_ops {
 	eth_count_aggr_ports_t count_aggr_ports;
 	/** Map a Tx queue with an aggregated port of the DPDK port */
 	eth_map_aggr_tx_affinity_t map_aggr_tx_affinity;
+
+	/** Retrieve physical link settings */
+	eth_get_link_settings_t get_link_settings;
+	/** Configure physical link settings */
+	eth_set_link_settings_t set_link_settings;
 };
 
 /**
diff --git a/lib/ethdev/rte_ethdev.c b/lib/ethdev/rte_ethdev.c
index f1c658f49e..d2c52921ef 100644
--- a/lib/ethdev/rte_ethdev.c
+++ b/lib/ethdev/rte_ethdev.c
@@ -6844,6 +6844,32 @@ rte_eth_dev_priv_dump(uint16_t port_id, FILE *file)
 	return eth_err(port_id, (*dev->dev_ops->eth_dev_priv_dump)(dev, file));
 }
 
+int rte_eth_dev_get_link_settings(uint16_t port_id,
+				  struct rte_link_settings *settings)
+{
+	struct rte_eth_dev *dev;
+
+	RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);
+	dev = &rte_eth_devices[port_id];
+
+	if (*dev->dev_ops->get_link_settings == NULL)
+		return -ENOTSUP;
+	return eth_err(port_id, (*dev->dev_ops->get_link_settings)(dev, settings));
+}
+
+int rte_eth_dev_set_link_settings(uint16_t port_id,
+				  const struct rte_link_settings *settings)
+{
+	struct rte_eth_dev *dev;
+
+	RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);
+	dev = &rte_eth_devices[port_id];
+
+	if (*dev->dev_ops->set_link_settings == NULL)
+		return -ENOTSUP;
+	return eth_err(port_id, (*dev->dev_ops->set_link_settings)(dev, settings));
+}
+
 int
 rte_eth_rx_descriptor_dump(uint16_t port_id, uint16_t queue_id,
 			   uint16_t offset, uint16_t num, FILE *file)
diff --git a/lib/ethdev/rte_ethdev.h b/lib/ethdev/rte_ethdev.h
index 147257d6a2..66aad925d0 100644
--- a/lib/ethdev/rte_ethdev.h
+++ b/lib/ethdev/rte_ethdev.h
@@ -335,7 +335,7 @@ struct rte_eth_stats {
 __extension__
 struct __rte_aligned(8) rte_eth_link { /**< aligned for atomic64 read/write */
 	uint32_t link_speed;        /**< RTE_ETH_SPEED_NUM_ */
-	uint16_t link_duplex  : 1;  /**< RTE_ETH_LINK_[HALF/FULL]_DUPLEX */
+	uint16_t link_duplex  : 2;  /**< RTE_ETH_LINK_[HALF/FULL/UNKNOWN]_DUPLEX */
 	uint16_t link_autoneg : 1;  /**< RTE_ETH_LINK_[AUTONEG/FIXED] */
 	uint16_t link_status  : 1;  /**< RTE_ETH_LINK_[DOWN/UP] */
 };
@@ -343,13 +343,27 @@ struct __rte_aligned(8) rte_eth_link { /**< aligned for atomic64 read/write */
 /**@{@name Link negotiation
  * Constants used in link management.
  */
-#define RTE_ETH_LINK_HALF_DUPLEX 0 /**< Half-duplex connection (see link_duplex). */
-#define RTE_ETH_LINK_FULL_DUPLEX 1 /**< Full-duplex connection (see link_duplex). */
-#define RTE_ETH_LINK_DOWN        0 /**< Link is down (see link_status). */
-#define RTE_ETH_LINK_UP          1 /**< Link is up (see link_status). */
-#define RTE_ETH_LINK_FIXED       0 /**< No autonegotiation (see link_autoneg). */
-#define RTE_ETH_LINK_AUTONEG     1 /**< Autonegotiated (see link_autoneg). */
-#define RTE_ETH_LINK_MAX_STR_LEN 40 /**< Max length of default link string. */
+#define RTE_ETH_LINK_HALF_DUPLEX	0 /**< Half-duplex connection (see link_duplex). */
+#define RTE_ETH_LINK_FULL_DUPLEX	1 /**< Full-duplex connection (see link_duplex). */
+#define RTE_ETH_LINK_UNKNOWN_DUPLEX	2 /**</ Unknown-duplex (see link_duplex). */
+#define RTE_ETH_LINK_DOWN		0 /**< Link is down (see link_status). */
+#define RTE_ETH_LINK_UP			1 /**< Link is up (see link_status). */
+#define RTE_ETH_LINK_FIXED		0 /**< No autonegotiation (see link_autoneg). */
+#define RTE_ETH_LINK_AUTONEG		1 /**< Autonegotiated (see link_autoneg). */
+#define RTE_ETH_LINK_MAX_STR_LEN	40 /**< Max length of default link string. */
+/**@}*/
+
+/**@{@name Link negotiation
+ * Constants used in link management to specify connector port.
+ */
+#define RTE_PORT_TP             0x00
+#define RTE_PORT_AUI            0x01
+#define RTE_PORT_MII            0x02
+#define RTE_PORT_FIBRE          0x03
+#define RTE_PORT_BNC            0x04
+#define RTE_PORT_DA             0x05
+#define RTE_PORT_NONE           0xef
+#define RTE_PORT_OTHER          0xff
 /**@}*/
 
 /**
@@ -1433,6 +1447,147 @@ struct rte_eth_pfc_queue_conf {
 	} tx_pause; /* Valid when (mode == FC_TX_PAUSE || mode == FC_FULL) */
 };
 
+/* Enable or disable autonegotiation. */
+#define RTE_AUTONEG_DISABLE         0x00
+#define RTE_AUTONEG_ENABLE          0x01
+
+/* MDI or MDI-X status/control - if MDI/MDI_X/AUTO is set then
+ * the driver is required to renegotiate link
+ */
+#define RTE_TP_MDI_INVALID      0x00 /* status: unknown; control: unsupported */
+#define RTE_TP_MDI              0x01 /* status: MDI;     control: force MDI */
+#define RTE_TP_MDI_X            0x02 /* status: MDI-X;   control: force MDI-X */
+#define RTE_TP_MDI_AUTO         0x03 /*                  control: auto-select */
+
+/* Link mode bit indices */
+enum rte_link_mode_bit_indices {
+	RTE_LINK_MODE_10baseT_Half_BIT	= 0,
+	RTE_LINK_MODE_10baseT_Full_BIT	= 1,
+	RTE_LINK_MODE_100baseT_Half_BIT	= 2,
+	RTE_LINK_MODE_100baseT_Full_BIT	= 3,
+	RTE_LINK_MODE_1000baseT_Half_BIT	= 4,
+	RTE_LINK_MODE_1000baseT_Full_BIT	= 5,
+	RTE_LINK_MODE_Autoneg_BIT		= 6,
+	RTE_LINK_MODE_TP_BIT		= 7,
+	RTE_LINK_MODE_AUI_BIT		= 8,
+	RTE_LINK_MODE_MII_BIT		= 9,
+	RTE_LINK_MODE_FIBRE_BIT		= 10,
+	RTE_LINK_MODE_BNC_BIT		= 11,
+	RTE_LINK_MODE_10000baseT_Full_BIT	= 12,
+	RTE_LINK_MODE_Pause_BIT		= 13,
+	RTE_LINK_MODE_Asym_Pause_BIT	= 14,
+	RTE_LINK_MODE_2500baseX_Full_BIT	= 15,
+	RTE_LINK_MODE_Backplane_BIT		= 16,
+	RTE_LINK_MODE_1000baseKX_Full_BIT	= 17,
+	RTE_LINK_MODE_10000baseKX4_Full_BIT	= 18,
+	RTE_LINK_MODE_10000baseKR_Full_BIT	= 19,
+	RTE_LINK_MODE_10000baseR_FEC_BIT	= 20,
+	RTE_LINK_MODE_20000baseMLD2_Full_BIT = 21,
+	RTE_LINK_MODE_20000baseKR2_Full_BIT	= 22,
+	RTE_LINK_MODE_40000baseKR4_Full_BIT	= 23,
+	RTE_LINK_MODE_40000baseCR4_Full_BIT	= 24,
+	RTE_LINK_MODE_40000baseSR4_Full_BIT	= 25,
+	RTE_LINK_MODE_40000baseLR4_Full_BIT	= 26,
+	RTE_LINK_MODE_56000baseKR4_Full_BIT	= 27,
+	RTE_LINK_MODE_56000baseCR4_Full_BIT	= 28,
+	RTE_LINK_MODE_56000baseSR4_Full_BIT	= 29,
+	RTE_LINK_MODE_56000baseLR4_Full_BIT	= 30,
+	RTE_LINK_MODE_25000baseCR_Full_BIT	= 31,
+	RTE_LINK_MODE_25000baseKR_Full_BIT	= 32,
+	RTE_LINK_MODE_25000baseSR_Full_BIT	= 33,
+	RTE_LINK_MODE_50000baseCR2_Full_BIT	= 34,
+	RTE_LINK_MODE_50000baseKR2_Full_BIT	= 35,
+	RTE_LINK_MODE_100000baseKR4_Full_BIT	= 36,
+	RTE_LINK_MODE_100000baseSR4_Full_BIT	= 37,
+	RTE_LINK_MODE_100000baseCR4_Full_BIT	= 38,
+	RTE_LINK_MODE_100000baseLR4_ER4_Full_BIT	= 39,
+	RTE_LINK_MODE_50000baseSR2_Full_BIT		= 40,
+	RTE_LINK_MODE_1000baseX_Full_BIT	= 41,
+	RTE_LINK_MODE_10000baseCR_Full_BIT	= 42,
+	RTE_LINK_MODE_10000baseSR_Full_BIT	= 43,
+	RTE_LINK_MODE_10000baseLR_Full_BIT	= 44,
+	RTE_LINK_MODE_10000baseLRM_Full_BIT	= 45,
+	RTE_LINK_MODE_10000baseER_Full_BIT	= 46,
+	RTE_LINK_MODE_2500baseT_Full_BIT	= 47,
+	RTE_LINK_MODE_5000baseT_Full_BIT	= 48,
+
+	RTE_LINK_MODE_FEC_NONE_BIT	= 49,
+	RTE_LINK_MODE_FEC_RS_BIT	= 50,
+	RTE_LINK_MODE_FEC_BASER_BIT	= 51,
+	RTE_LINK_MODE_50000baseKR_Full_BIT		 = 52,
+	RTE_LINK_MODE_50000baseSR_Full_BIT		 = 53,
+	RTE_LINK_MODE_50000baseCR_Full_BIT		 = 54,
+	RTE_LINK_MODE_50000baseLR_ER_FR_Full_BIT	 = 55,
+	RTE_LINK_MODE_50000baseDR_Full_BIT		 = 56,
+	RTE_LINK_MODE_100000baseKR2_Full_BIT	 = 57,
+	RTE_LINK_MODE_100000baseSR2_Full_BIT	 = 58,
+	RTE_LINK_MODE_100000baseCR2_Full_BIT	 = 59,
+	RTE_LINK_MODE_100000baseLR2_ER2_FR2_Full_BIT = 60,
+	RTE_LINK_MODE_100000baseDR2_Full_BIT	 = 61,
+	RTE_LINK_MODE_200000baseKR4_Full_BIT	 = 62,
+	RTE_LINK_MODE_200000baseSR4_Full_BIT	 = 63,
+	RTE_LINK_MODE_200000baseLR4_ER4_FR4_Full_BIT = 64,
+	RTE_LINK_MODE_200000baseDR4_Full_BIT	 = 65,
+	RTE_LINK_MODE_200000baseCR4_Full_BIT	 = 66,
+	RTE_LINK_MODE_100baseT1_Full_BIT		 = 67,
+	RTE_LINK_MODE_1000baseT1_Full_BIT		 = 68,
+	RTE_LINK_MODE_400000baseKR8_Full_BIT	 = 69,
+	RTE_LINK_MODE_400000baseSR8_Full_BIT	 = 70,
+	RTE_LINK_MODE_400000baseLR8_ER8_FR8_Full_BIT = 71,
+	RTE_LINK_MODE_400000baseDR8_Full_BIT	 = 72,
+	RTE_LINK_MODE_400000baseCR8_Full_BIT	 = 73,
+	RTE_LINK_MODE_FEC_LLRS_BIT			 = 74,
+	RTE_LINK_MODE_100000baseKR_Full_BIT		 = 75,
+	RTE_LINK_MODE_100000baseSR_Full_BIT		 = 76,
+	RTE_LINK_MODE_100000baseLR_ER_FR_Full_BIT	 = 77,
+	RTE_LINK_MODE_100000baseCR_Full_BIT		 = 78,
+	RTE_LINK_MODE_100000baseDR_Full_BIT		 = 79,
+	RTE_LINK_MODE_200000baseKR2_Full_BIT	 = 80,
+	RTE_LINK_MODE_200000baseSR2_Full_BIT	 = 81,
+	RTE_LINK_MODE_200000baseLR2_ER2_FR2_Full_BIT = 82,
+	RTE_LINK_MODE_200000baseDR2_Full_BIT	 = 83,
+	RTE_LINK_MODE_200000baseCR2_Full_BIT	 = 84,
+	RTE_LINK_MODE_400000baseKR4_Full_BIT	 = 85,
+	RTE_LINK_MODE_400000baseSR4_Full_BIT	 = 86,
+	RTE_LINK_MODE_400000baseLR4_ER4_FR4_Full_BIT = 87,
+	RTE_LINK_MODE_400000baseDR4_Full_BIT	 = 88,
+	RTE_LINK_MODE_400000baseCR4_Full_BIT	 = 89,
+	RTE_LINK_MODE_100baseFX_Half_BIT		 = 90,
+	RTE_LINK_MODE_100baseFX_Full_BIT		 = 91,
+	/* must be last entry */
+	__RTE_LINK_MODE_MASK_NBITS
+};
+
+/* number of 32-bit words to store the user's link mode bitmaps */
+#define RTE_DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d))
+#define __RTE_LINK_MODE_MASK_NU32                   \
+	RTE_DIV_ROUND_UP(__RTE_LINK_MODE_MASK_NBITS, 32)
+
+/**
+ * Link control and status
+ * @speed: Link speed (Mbps)
+ * @duplex: Duplex mode; one of %DUPLEX_*
+ * @port: Physical connector type; one of %PORT_*
+ * @autoneg: Enable/disable autonegotiation and auto-detection;
+ *	either %AUTONEG_DISABLE or %AUTONEG_ENABLE
+ */
+struct rte_link_base_settings {
+	struct rte_eth_link link;
+	uint8_t port;
+	uint8_t phy_address;
+	uint8_t eth_tp_mdix;
+	uint8_t eth_tp_mdix_ctrl;
+};
+
+struct rte_link_settings {
+	struct rte_link_base_settings base;
+	struct {
+		uint32_t supported[__RTE_LINK_MODE_MASK_NU32];
+		uint32_t advertising[__RTE_LINK_MODE_MASK_NU32];
+		uint32_t lp_advertising[__RTE_LINK_MODE_MASK_NU32];
+	} link_modes;
+};
+
 /**
  * Tunnel type for device-specific classifier configuration.
  * @see rte_eth_udp_tunnel
@@ -5936,6 +6091,50 @@ int rte_eth_cman_config_init(uint16_t port_id, struct rte_eth_cman_config *confi
 __rte_experimental
 int rte_eth_cman_config_set(uint16_t port_id, const struct rte_eth_cman_config *config);
 
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * Retrieve link settings
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param settings
+ *   A pointer to a structure of type *rte_link_settings* to retrieve
+ *   link settings parameters for the given port.
+ *
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if support for cman_config_get does not exist.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - (-EINVAL) if bad parameter.
+ */
+__rte_experimental
+int rte_eth_dev_get_link_settings(uint16_t port_id,
+				  struct rte_link_settings *settings);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * Configure link settings
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param settings
+ *   A pointer to a structure of type *rte_link_settings* to configure
+ *   link settings parameters for the given port.
+ *
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if support for cman_config_get does not exist.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - (-EINVAL) if bad parameter.
+ */
+__rte_experimental
+int rte_eth_dev_set_link_settings(uint16_t port_id,
+				  const struct rte_link_settings *settings);
+
 /**
  * @warning
  * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
diff --git a/lib/ethdev/version.map b/lib/ethdev/version.map
index 79f6f5293b..5e138a3d10 100644
--- a/lib/ethdev/version.map
+++ b/lib/ethdev/version.map
@@ -325,6 +325,9 @@ EXPERIMENTAL {
 	rte_flow_template_table_resizable;
 	rte_flow_template_table_resize;
 	rte_flow_template_table_resize_complete;
+	rte_eth_dev_get_link_settings;
+	rte_eth_dev_set_link_settings;
+
 };
 
 INTERNAL {
-- 
2.41.0


^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH] igc/ixgbe: add get/set link settings interface
  2024-03-26 23:59 [PATCH] igc/ixgbe: add get/set link settings interface Marek Pazdan
@ 2024-03-27 11:12 ` Bruce Richardson
  2024-04-03 13:40 ` [PATCH] lib: " Marek Pazdan
  2024-04-03 13:59 ` Marek Pazdan
  2 siblings, 0 replies; 17+ messages in thread
From: Bruce Richardson @ 2024-03-27 11:12 UTC (permalink / raw)
  To: Marek Pazdan
  Cc: Thomas Monjalon, Aman Singh, Yuying Zhang, Ferruh Yigit,
	Andrew Rybchenko, dev

On Tue, Mar 26, 2024 at 04:59:07PM -0700, Marek Pazdan wrote:
> There are link settings parameters available from PMD drivers level
> which are currently not exposed to the user via consistent interface.
> When interface is available for system level those information can
> be acquired with 'ethtool DEVNAME' (ioctl: ETHTOOL_SLINKSETTINGS/
> ETHTOOL_GLINKSETTINGS). There are use cases where
> physical interface is passthrough to dpdk driver and is not available
> from system level. Information provided by ioctl carries information
> useful for link auto negotiation settings among others.
> Additionally dpdk-testpmd application has been extended to provided
> testing tool for newly implemtented interface functions.
> 
> Signed-off-by: Marek Pazdan <mpazdan@arista.com>
> ---
>  .mailmap                           |   1 +
>  app/test-pmd/cmdline.c             |   9 +
>  app/test-pmd/cmdline_settings.c    | 516 +++++++++++++++++++++++++++++
>  app/test-pmd/cmdline_settings.h    |  14 +
>  app/test-pmd/meson.build           |   1 +
>  app/test-pmd/testpmd.h             |   1 +
>  app/test-pmd/util.c                |  10 +
>  drivers/net/igc/igc_ethdev.c       | 229 ++++++++++++-
>  drivers/net/ixgbe/base/ixgbe_phy.h |   7 +
>  drivers/net/ixgbe/ixgbe_ethdev.c   | 395 ++++++++++++++++++++++
>  lib/ethdev/ethdev_driver.h         |  33 ++
>  lib/ethdev/rte_ethdev.c            |  26 ++
>  lib/ethdev/rte_ethdev.h            | 215 +++++++++++-
>  lib/ethdev/version.map             |   3 +
>  14 files changed, 1450 insertions(+), 10 deletions(-)
>  create mode 100644 app/test-pmd/cmdline_settings.c
>  create mode 100644 app/test-pmd/cmdline_settings.h
> 

Hi Marek,

it seems this patch is not just for igc and ixgbe drivers, but is adding a
new feature and pair of functions to ethdev, correct? In order to simplify
review, can you please split this patch up into multiple patches based on
component, for example, ethdev hooks, then testpmd calls using those hooks
and finally the individual driver changes to implement the new functions.
Even the driver changes could probably be omitted, if you want, for the
early versions of the patchset, as we'd need to get agreement on the ethdev
APIs before looking at specific implementations in detail.

Thanks for the contribution,

/Bruce

^ permalink raw reply	[flat|nested] 17+ messages in thread

* [PATCH]  lib: add get/set link settings interface
  2024-03-26 23:59 [PATCH] igc/ixgbe: add get/set link settings interface Marek Pazdan
  2024-03-27 11:12 ` Bruce Richardson
@ 2024-04-03 13:40 ` Marek Pazdan
  2024-04-03 16:49   ` Tyler Retzlaff
  2024-04-03 13:59 ` Marek Pazdan
  2 siblings, 1 reply; 17+ messages in thread
From: Marek Pazdan @ 2024-04-03 13:40 UTC (permalink / raw)
  To: Thomas Monjalon, Ferruh Yigit, Andrew Rybchenko; +Cc: dev, Marek Pazdan

 There are link settings parameters available from PMD drivers level
 which are currently not exposed to the user via consistent interface.
 When interface is available for system level those information can
 be acquired with 'ethtool DEVNAME' (ioctl: ETHTOOL_SLINKSETTINGS/
 ETHTOOL_GLINKSETTINGS). There are use cases where
 physical interface is passthrough to dpdk driver and is not available
 from system level. Information provided by ioctl carries information
 useful for link auto negotiation settings among others.

Signed-off-by: Marek Pazdan <mpazdan@arista.com>
---
 .mailmap                   |   1 +
 lib/ethdev/ethdev_driver.h |  33 ++++++
 lib/ethdev/rte_ethdev.c    |  26 +++++
 lib/ethdev/rte_ethdev.h    | 215 +++++++++++++++++++++++++++++++++++--
 lib/ethdev/version.map     |   3 +
 5 files changed, 270 insertions(+), 8 deletions(-)

diff --git a/.mailmap b/.mailmap
index 3843868716..145ce726ba 100644
--- a/.mailmap
+++ b/.mailmap
@@ -885,6 +885,7 @@ Marcin Wojtas <mw@semihalf.com>
 Marcin Zapolski <marcinx.a.zapolski@intel.com>
 Marco Varlese <mvarlese@suse.de>
 Marc Sune <marcdevel@gmail.com> <marc.sune@bisdn.de>
+Marek Pazdan <mpazdan@arista.com>
 Maria Lingemark <maria.lingemark@ericsson.com>
 Mario Carrillo <mario.alfredo.c.arevalo@intel.com>
 Mário Kuka <kuka@cesnet.cz>
diff --git a/lib/ethdev/ethdev_driver.h b/lib/ethdev/ethdev_driver.h
index 0dbf2dd6a2..ee8f786b99 100644
--- a/lib/ethdev/ethdev_driver.h
+++ b/lib/ethdev/ethdev_driver.h
@@ -1119,6 +1119,34 @@ typedef const uint32_t *(*eth_buffer_split_supported_hdr_ptypes_get_t)(struct rt
  */
 typedef int (*eth_dev_priv_dump_t)(struct rte_eth_dev *dev, FILE *file);
 
+/** @internal Retrieve physical link settings of a port.
+ *
+ * @param dev
+ *   Port (ethdev) handle
+ *
+ * @param[out] settings
+ *   Physical port link settings.
+ *
+ * @return
+ *   Negative errno value on error, zero otherwise
+ */
+typedef int (*eth_get_link_settings_t)(struct rte_eth_dev *dev,
+				 struct rte_link_settings *settings);
+
+/** @internal Configure physical link settings of a port.
+ *
+ * @param dev
+ *   Port (ethdev) handle
+ *
+ * @param settings
+ *   Physical port link settings.
+ *
+ * @return
+ *   Negative errno value on error, zero otherwise
+ */
+typedef int (*eth_set_link_settings_t)(struct rte_eth_dev *dev,
+				 const struct rte_link_settings *settings);
+
 /**
  * @internal Set Rx queue available descriptors threshold.
  * @see rte_eth_rx_avail_thresh_set()
@@ -1474,6 +1502,11 @@ struct eth_dev_ops {
 	eth_count_aggr_ports_t count_aggr_ports;
 	/** Map a Tx queue with an aggregated port of the DPDK port */
 	eth_map_aggr_tx_affinity_t map_aggr_tx_affinity;
+
+	/** Retrieve physical link settings */
+	eth_get_link_settings_t get_link_settings;
+	/** Configure physical link settings */
+	eth_set_link_settings_t set_link_settings;
 };
 
 /**
diff --git a/lib/ethdev/rte_ethdev.c b/lib/ethdev/rte_ethdev.c
index f1c658f49e..d2c52921ef 100644
--- a/lib/ethdev/rte_ethdev.c
+++ b/lib/ethdev/rte_ethdev.c
@@ -6844,6 +6844,32 @@ rte_eth_dev_priv_dump(uint16_t port_id, FILE *file)
 	return eth_err(port_id, (*dev->dev_ops->eth_dev_priv_dump)(dev, file));
 }
 
+int rte_eth_dev_get_link_settings(uint16_t port_id,
+				  struct rte_link_settings *settings)
+{
+	struct rte_eth_dev *dev;
+
+	RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);
+	dev = &rte_eth_devices[port_id];
+
+	if (*dev->dev_ops->get_link_settings == NULL)
+		return -ENOTSUP;
+	return eth_err(port_id, (*dev->dev_ops->get_link_settings)(dev, settings));
+}
+
+int rte_eth_dev_set_link_settings(uint16_t port_id,
+				  const struct rte_link_settings *settings)
+{
+	struct rte_eth_dev *dev;
+
+	RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);
+	dev = &rte_eth_devices[port_id];
+
+	if (*dev->dev_ops->set_link_settings == NULL)
+		return -ENOTSUP;
+	return eth_err(port_id, (*dev->dev_ops->set_link_settings)(dev, settings));
+}
+
 int
 rte_eth_rx_descriptor_dump(uint16_t port_id, uint16_t queue_id,
 			   uint16_t offset, uint16_t num, FILE *file)
diff --git a/lib/ethdev/rte_ethdev.h b/lib/ethdev/rte_ethdev.h
index 147257d6a2..66aad925d0 100644
--- a/lib/ethdev/rte_ethdev.h
+++ b/lib/ethdev/rte_ethdev.h
@@ -335,7 +335,7 @@ struct rte_eth_stats {
 __extension__
 struct __rte_aligned(8) rte_eth_link { /**< aligned for atomic64 read/write */
 	uint32_t link_speed;        /**< RTE_ETH_SPEED_NUM_ */
-	uint16_t link_duplex  : 1;  /**< RTE_ETH_LINK_[HALF/FULL]_DUPLEX */
+	uint16_t link_duplex  : 2;  /**< RTE_ETH_LINK_[HALF/FULL/UNKNOWN]_DUPLEX */
 	uint16_t link_autoneg : 1;  /**< RTE_ETH_LINK_[AUTONEG/FIXED] */
 	uint16_t link_status  : 1;  /**< RTE_ETH_LINK_[DOWN/UP] */
 };
@@ -343,13 +343,27 @@ struct __rte_aligned(8) rte_eth_link { /**< aligned for atomic64 read/write */
 /**@{@name Link negotiation
  * Constants used in link management.
  */
-#define RTE_ETH_LINK_HALF_DUPLEX 0 /**< Half-duplex connection (see link_duplex). */
-#define RTE_ETH_LINK_FULL_DUPLEX 1 /**< Full-duplex connection (see link_duplex). */
-#define RTE_ETH_LINK_DOWN        0 /**< Link is down (see link_status). */
-#define RTE_ETH_LINK_UP          1 /**< Link is up (see link_status). */
-#define RTE_ETH_LINK_FIXED       0 /**< No autonegotiation (see link_autoneg). */
-#define RTE_ETH_LINK_AUTONEG     1 /**< Autonegotiated (see link_autoneg). */
-#define RTE_ETH_LINK_MAX_STR_LEN 40 /**< Max length of default link string. */
+#define RTE_ETH_LINK_HALF_DUPLEX	0 /**< Half-duplex connection (see link_duplex). */
+#define RTE_ETH_LINK_FULL_DUPLEX	1 /**< Full-duplex connection (see link_duplex). */
+#define RTE_ETH_LINK_UNKNOWN_DUPLEX	2 /**</ Unknown-duplex (see link_duplex). */
+#define RTE_ETH_LINK_DOWN		0 /**< Link is down (see link_status). */
+#define RTE_ETH_LINK_UP			1 /**< Link is up (see link_status). */
+#define RTE_ETH_LINK_FIXED		0 /**< No autonegotiation (see link_autoneg). */
+#define RTE_ETH_LINK_AUTONEG		1 /**< Autonegotiated (see link_autoneg). */
+#define RTE_ETH_LINK_MAX_STR_LEN	40 /**< Max length of default link string. */
+/**@}*/
+
+/**@{@name Link negotiation
+ * Constants used in link management to specify connector port.
+ */
+#define RTE_PORT_TP             0x00
+#define RTE_PORT_AUI            0x01
+#define RTE_PORT_MII            0x02
+#define RTE_PORT_FIBRE          0x03
+#define RTE_PORT_BNC            0x04
+#define RTE_PORT_DA             0x05
+#define RTE_PORT_NONE           0xef
+#define RTE_PORT_OTHER          0xff
 /**@}*/
 
 /**
@@ -1433,6 +1447,147 @@ struct rte_eth_pfc_queue_conf {
 	} tx_pause; /* Valid when (mode == FC_TX_PAUSE || mode == FC_FULL) */
 };
 
+/* Enable or disable autonegotiation. */
+#define RTE_AUTONEG_DISABLE         0x00
+#define RTE_AUTONEG_ENABLE          0x01
+
+/* MDI or MDI-X status/control - if MDI/MDI_X/AUTO is set then
+ * the driver is required to renegotiate link
+ */
+#define RTE_TP_MDI_INVALID      0x00 /* status: unknown; control: unsupported */
+#define RTE_TP_MDI              0x01 /* status: MDI;     control: force MDI */
+#define RTE_TP_MDI_X            0x02 /* status: MDI-X;   control: force MDI-X */
+#define RTE_TP_MDI_AUTO         0x03 /*                  control: auto-select */
+
+/* Link mode bit indices */
+enum rte_link_mode_bit_indices {
+	RTE_LINK_MODE_10baseT_Half_BIT	= 0,
+	RTE_LINK_MODE_10baseT_Full_BIT	= 1,
+	RTE_LINK_MODE_100baseT_Half_BIT	= 2,
+	RTE_LINK_MODE_100baseT_Full_BIT	= 3,
+	RTE_LINK_MODE_1000baseT_Half_BIT	= 4,
+	RTE_LINK_MODE_1000baseT_Full_BIT	= 5,
+	RTE_LINK_MODE_Autoneg_BIT		= 6,
+	RTE_LINK_MODE_TP_BIT		= 7,
+	RTE_LINK_MODE_AUI_BIT		= 8,
+	RTE_LINK_MODE_MII_BIT		= 9,
+	RTE_LINK_MODE_FIBRE_BIT		= 10,
+	RTE_LINK_MODE_BNC_BIT		= 11,
+	RTE_LINK_MODE_10000baseT_Full_BIT	= 12,
+	RTE_LINK_MODE_Pause_BIT		= 13,
+	RTE_LINK_MODE_Asym_Pause_BIT	= 14,
+	RTE_LINK_MODE_2500baseX_Full_BIT	= 15,
+	RTE_LINK_MODE_Backplane_BIT		= 16,
+	RTE_LINK_MODE_1000baseKX_Full_BIT	= 17,
+	RTE_LINK_MODE_10000baseKX4_Full_BIT	= 18,
+	RTE_LINK_MODE_10000baseKR_Full_BIT	= 19,
+	RTE_LINK_MODE_10000baseR_FEC_BIT	= 20,
+	RTE_LINK_MODE_20000baseMLD2_Full_BIT = 21,
+	RTE_LINK_MODE_20000baseKR2_Full_BIT	= 22,
+	RTE_LINK_MODE_40000baseKR4_Full_BIT	= 23,
+	RTE_LINK_MODE_40000baseCR4_Full_BIT	= 24,
+	RTE_LINK_MODE_40000baseSR4_Full_BIT	= 25,
+	RTE_LINK_MODE_40000baseLR4_Full_BIT	= 26,
+	RTE_LINK_MODE_56000baseKR4_Full_BIT	= 27,
+	RTE_LINK_MODE_56000baseCR4_Full_BIT	= 28,
+	RTE_LINK_MODE_56000baseSR4_Full_BIT	= 29,
+	RTE_LINK_MODE_56000baseLR4_Full_BIT	= 30,
+	RTE_LINK_MODE_25000baseCR_Full_BIT	= 31,
+	RTE_LINK_MODE_25000baseKR_Full_BIT	= 32,
+	RTE_LINK_MODE_25000baseSR_Full_BIT	= 33,
+	RTE_LINK_MODE_50000baseCR2_Full_BIT	= 34,
+	RTE_LINK_MODE_50000baseKR2_Full_BIT	= 35,
+	RTE_LINK_MODE_100000baseKR4_Full_BIT	= 36,
+	RTE_LINK_MODE_100000baseSR4_Full_BIT	= 37,
+	RTE_LINK_MODE_100000baseCR4_Full_BIT	= 38,
+	RTE_LINK_MODE_100000baseLR4_ER4_Full_BIT	= 39,
+	RTE_LINK_MODE_50000baseSR2_Full_BIT		= 40,
+	RTE_LINK_MODE_1000baseX_Full_BIT	= 41,
+	RTE_LINK_MODE_10000baseCR_Full_BIT	= 42,
+	RTE_LINK_MODE_10000baseSR_Full_BIT	= 43,
+	RTE_LINK_MODE_10000baseLR_Full_BIT	= 44,
+	RTE_LINK_MODE_10000baseLRM_Full_BIT	= 45,
+	RTE_LINK_MODE_10000baseER_Full_BIT	= 46,
+	RTE_LINK_MODE_2500baseT_Full_BIT	= 47,
+	RTE_LINK_MODE_5000baseT_Full_BIT	= 48,
+
+	RTE_LINK_MODE_FEC_NONE_BIT	= 49,
+	RTE_LINK_MODE_FEC_RS_BIT	= 50,
+	RTE_LINK_MODE_FEC_BASER_BIT	= 51,
+	RTE_LINK_MODE_50000baseKR_Full_BIT		 = 52,
+	RTE_LINK_MODE_50000baseSR_Full_BIT		 = 53,
+	RTE_LINK_MODE_50000baseCR_Full_BIT		 = 54,
+	RTE_LINK_MODE_50000baseLR_ER_FR_Full_BIT	 = 55,
+	RTE_LINK_MODE_50000baseDR_Full_BIT		 = 56,
+	RTE_LINK_MODE_100000baseKR2_Full_BIT	 = 57,
+	RTE_LINK_MODE_100000baseSR2_Full_BIT	 = 58,
+	RTE_LINK_MODE_100000baseCR2_Full_BIT	 = 59,
+	RTE_LINK_MODE_100000baseLR2_ER2_FR2_Full_BIT = 60,
+	RTE_LINK_MODE_100000baseDR2_Full_BIT	 = 61,
+	RTE_LINK_MODE_200000baseKR4_Full_BIT	 = 62,
+	RTE_LINK_MODE_200000baseSR4_Full_BIT	 = 63,
+	RTE_LINK_MODE_200000baseLR4_ER4_FR4_Full_BIT = 64,
+	RTE_LINK_MODE_200000baseDR4_Full_BIT	 = 65,
+	RTE_LINK_MODE_200000baseCR4_Full_BIT	 = 66,
+	RTE_LINK_MODE_100baseT1_Full_BIT		 = 67,
+	RTE_LINK_MODE_1000baseT1_Full_BIT		 = 68,
+	RTE_LINK_MODE_400000baseKR8_Full_BIT	 = 69,
+	RTE_LINK_MODE_400000baseSR8_Full_BIT	 = 70,
+	RTE_LINK_MODE_400000baseLR8_ER8_FR8_Full_BIT = 71,
+	RTE_LINK_MODE_400000baseDR8_Full_BIT	 = 72,
+	RTE_LINK_MODE_400000baseCR8_Full_BIT	 = 73,
+	RTE_LINK_MODE_FEC_LLRS_BIT			 = 74,
+	RTE_LINK_MODE_100000baseKR_Full_BIT		 = 75,
+	RTE_LINK_MODE_100000baseSR_Full_BIT		 = 76,
+	RTE_LINK_MODE_100000baseLR_ER_FR_Full_BIT	 = 77,
+	RTE_LINK_MODE_100000baseCR_Full_BIT		 = 78,
+	RTE_LINK_MODE_100000baseDR_Full_BIT		 = 79,
+	RTE_LINK_MODE_200000baseKR2_Full_BIT	 = 80,
+	RTE_LINK_MODE_200000baseSR2_Full_BIT	 = 81,
+	RTE_LINK_MODE_200000baseLR2_ER2_FR2_Full_BIT = 82,
+	RTE_LINK_MODE_200000baseDR2_Full_BIT	 = 83,
+	RTE_LINK_MODE_200000baseCR2_Full_BIT	 = 84,
+	RTE_LINK_MODE_400000baseKR4_Full_BIT	 = 85,
+	RTE_LINK_MODE_400000baseSR4_Full_BIT	 = 86,
+	RTE_LINK_MODE_400000baseLR4_ER4_FR4_Full_BIT = 87,
+	RTE_LINK_MODE_400000baseDR4_Full_BIT	 = 88,
+	RTE_LINK_MODE_400000baseCR4_Full_BIT	 = 89,
+	RTE_LINK_MODE_100baseFX_Half_BIT		 = 90,
+	RTE_LINK_MODE_100baseFX_Full_BIT		 = 91,
+	/* must be last entry */
+	__RTE_LINK_MODE_MASK_NBITS
+};
+
+/* number of 32-bit words to store the user's link mode bitmaps */
+#define RTE_DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d))
+#define __RTE_LINK_MODE_MASK_NU32                   \
+	RTE_DIV_ROUND_UP(__RTE_LINK_MODE_MASK_NBITS, 32)
+
+/**
+ * Link control and status
+ * @speed: Link speed (Mbps)
+ * @duplex: Duplex mode; one of %DUPLEX_*
+ * @port: Physical connector type; one of %PORT_*
+ * @autoneg: Enable/disable autonegotiation and auto-detection;
+ *	either %AUTONEG_DISABLE or %AUTONEG_ENABLE
+ */
+struct rte_link_base_settings {
+	struct rte_eth_link link;
+	uint8_t port;
+	uint8_t phy_address;
+	uint8_t eth_tp_mdix;
+	uint8_t eth_tp_mdix_ctrl;
+};
+
+struct rte_link_settings {
+	struct rte_link_base_settings base;
+	struct {
+		uint32_t supported[__RTE_LINK_MODE_MASK_NU32];
+		uint32_t advertising[__RTE_LINK_MODE_MASK_NU32];
+		uint32_t lp_advertising[__RTE_LINK_MODE_MASK_NU32];
+	} link_modes;
+};
+
 /**
  * Tunnel type for device-specific classifier configuration.
  * @see rte_eth_udp_tunnel
@@ -5936,6 +6091,50 @@ int rte_eth_cman_config_init(uint16_t port_id, struct rte_eth_cman_config *confi
 __rte_experimental
 int rte_eth_cman_config_set(uint16_t port_id, const struct rte_eth_cman_config *config);
 
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * Retrieve link settings
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param settings
+ *   A pointer to a structure of type *rte_link_settings* to retrieve
+ *   link settings parameters for the given port.
+ *
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if support for cman_config_get does not exist.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - (-EINVAL) if bad parameter.
+ */
+__rte_experimental
+int rte_eth_dev_get_link_settings(uint16_t port_id,
+				  struct rte_link_settings *settings);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * Configure link settings
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param settings
+ *   A pointer to a structure of type *rte_link_settings* to configure
+ *   link settings parameters for the given port.
+ *
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if support for cman_config_get does not exist.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - (-EINVAL) if bad parameter.
+ */
+__rte_experimental
+int rte_eth_dev_set_link_settings(uint16_t port_id,
+				  const struct rte_link_settings *settings);
+
 /**
  * @warning
  * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
diff --git a/lib/ethdev/version.map b/lib/ethdev/version.map
index 79f6f5293b..5e138a3d10 100644
--- a/lib/ethdev/version.map
+++ b/lib/ethdev/version.map
@@ -325,6 +325,9 @@ EXPERIMENTAL {
 	rte_flow_template_table_resizable;
 	rte_flow_template_table_resize;
 	rte_flow_template_table_resize_complete;
+	rte_eth_dev_get_link_settings;
+	rte_eth_dev_set_link_settings;
+
 };
 
 INTERNAL {
-- 
2.41.0


^ permalink raw reply	[flat|nested] 17+ messages in thread

* [PATCH]  lib: add get/set link settings interface
  2024-03-26 23:59 [PATCH] igc/ixgbe: add get/set link settings interface Marek Pazdan
  2024-03-27 11:12 ` Bruce Richardson
  2024-04-03 13:40 ` [PATCH] lib: " Marek Pazdan
@ 2024-04-03 13:59 ` Marek Pazdan
  2024-04-03 14:48   ` Thomas Monjalon
  2 siblings, 1 reply; 17+ messages in thread
From: Marek Pazdan @ 2024-04-03 13:59 UTC (permalink / raw)
  To: Thomas Monjalon, Ferruh Yigit, Andrew Rybchenko; +Cc: dev, Marek Pazdan

 There are link settings parameters available from PMD drivers level
 which are currently not exposed to the user via consistent interface.
 When interface is available for system level those information can
 be acquired with 'ethtool DEVNAME' (ioctl: ETHTOOL_SLINKSETTINGS/
 ETHTOOL_GLINKSETTINGS). There are use cases where
 physical interface is passthrough to dpdk driver and is not available
 from system level. Information provided by ioctl carries information
 useful for link auto negotiation settings among others.

Signed-off-by: Marek Pazdan <mpazdan@arista.com>
---
 .mailmap                   |   1 +
 lib/ethdev/ethdev_driver.h |  33 ++++++
 lib/ethdev/rte_ethdev.c    |  26 +++++
 lib/ethdev/rte_ethdev.h    | 215 +++++++++++++++++++++++++++++++++++--
 lib/ethdev/version.map     |   3 +
 5 files changed, 270 insertions(+), 8 deletions(-)

diff --git a/.mailmap b/.mailmap
index 3843868716..145ce726ba 100644
--- a/.mailmap
+++ b/.mailmap
@@ -885,6 +885,7 @@ Marcin Wojtas <mw@semihalf.com>
 Marcin Zapolski <marcinx.a.zapolski@intel.com>
 Marco Varlese <mvarlese@suse.de>
 Marc Sune <marcdevel@gmail.com> <marc.sune@bisdn.de>
+Marek Pazdan <mpazdan@arista.com>
 Maria Lingemark <maria.lingemark@ericsson.com>
 Mario Carrillo <mario.alfredo.c.arevalo@intel.com>
 Mário Kuka <kuka@cesnet.cz>
diff --git a/lib/ethdev/ethdev_driver.h b/lib/ethdev/ethdev_driver.h
index 0dbf2dd6a2..ee8f786b99 100644
--- a/lib/ethdev/ethdev_driver.h
+++ b/lib/ethdev/ethdev_driver.h
@@ -1119,6 +1119,34 @@ typedef const uint32_t *(*eth_buffer_split_supported_hdr_ptypes_get_t)(struct rt
  */
 typedef int (*eth_dev_priv_dump_t)(struct rte_eth_dev *dev, FILE *file);
 
+/** @internal Retrieve physical link settings of a port.
+ *
+ * @param dev
+ *   Port (ethdev) handle
+ *
+ * @param[out] settings
+ *   Physical port link settings.
+ *
+ * @return
+ *   Negative errno value on error, zero otherwise
+ */
+typedef int (*eth_get_link_settings_t)(struct rte_eth_dev *dev,
+				 struct rte_link_settings *settings);
+
+/** @internal Configure physical link settings of a port.
+ *
+ * @param dev
+ *   Port (ethdev) handle
+ *
+ * @param settings
+ *   Physical port link settings.
+ *
+ * @return
+ *   Negative errno value on error, zero otherwise
+ */
+typedef int (*eth_set_link_settings_t)(struct rte_eth_dev *dev,
+				 const struct rte_link_settings *settings);
+
 /**
  * @internal Set Rx queue available descriptors threshold.
  * @see rte_eth_rx_avail_thresh_set()
@@ -1474,6 +1502,11 @@ struct eth_dev_ops {
 	eth_count_aggr_ports_t count_aggr_ports;
 	/** Map a Tx queue with an aggregated port of the DPDK port */
 	eth_map_aggr_tx_affinity_t map_aggr_tx_affinity;
+
+	/** Retrieve physical link settings */
+	eth_get_link_settings_t get_link_settings;
+	/** Configure physical link settings */
+	eth_set_link_settings_t set_link_settings;
 };
 
 /**
diff --git a/lib/ethdev/rte_ethdev.c b/lib/ethdev/rte_ethdev.c
index f1c658f49e..d2c52921ef 100644
--- a/lib/ethdev/rte_ethdev.c
+++ b/lib/ethdev/rte_ethdev.c
@@ -6844,6 +6844,32 @@ rte_eth_dev_priv_dump(uint16_t port_id, FILE *file)
 	return eth_err(port_id, (*dev->dev_ops->eth_dev_priv_dump)(dev, file));
 }
 
+int rte_eth_dev_get_link_settings(uint16_t port_id,
+				  struct rte_link_settings *settings)
+{
+	struct rte_eth_dev *dev;
+
+	RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);
+	dev = &rte_eth_devices[port_id];
+
+	if (*dev->dev_ops->get_link_settings == NULL)
+		return -ENOTSUP;
+	return eth_err(port_id, (*dev->dev_ops->get_link_settings)(dev, settings));
+}
+
+int rte_eth_dev_set_link_settings(uint16_t port_id,
+				  const struct rte_link_settings *settings)
+{
+	struct rte_eth_dev *dev;
+
+	RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);
+	dev = &rte_eth_devices[port_id];
+
+	if (*dev->dev_ops->set_link_settings == NULL)
+		return -ENOTSUP;
+	return eth_err(port_id, (*dev->dev_ops->set_link_settings)(dev, settings));
+}
+
 int
 rte_eth_rx_descriptor_dump(uint16_t port_id, uint16_t queue_id,
 			   uint16_t offset, uint16_t num, FILE *file)
diff --git a/lib/ethdev/rte_ethdev.h b/lib/ethdev/rte_ethdev.h
index 147257d6a2..66aad925d0 100644
--- a/lib/ethdev/rte_ethdev.h
+++ b/lib/ethdev/rte_ethdev.h
@@ -335,7 +335,7 @@ struct rte_eth_stats {
 __extension__
 struct __rte_aligned(8) rte_eth_link { /**< aligned for atomic64 read/write */
 	uint32_t link_speed;        /**< RTE_ETH_SPEED_NUM_ */
-	uint16_t link_duplex  : 1;  /**< RTE_ETH_LINK_[HALF/FULL]_DUPLEX */
+	uint16_t link_duplex  : 2;  /**< RTE_ETH_LINK_[HALF/FULL/UNKNOWN]_DUPLEX */
 	uint16_t link_autoneg : 1;  /**< RTE_ETH_LINK_[AUTONEG/FIXED] */
 	uint16_t link_status  : 1;  /**< RTE_ETH_LINK_[DOWN/UP] */
 };
@@ -343,13 +343,27 @@ struct __rte_aligned(8) rte_eth_link { /**< aligned for atomic64 read/write */
 /**@{@name Link negotiation
  * Constants used in link management.
  */
-#define RTE_ETH_LINK_HALF_DUPLEX 0 /**< Half-duplex connection (see link_duplex). */
-#define RTE_ETH_LINK_FULL_DUPLEX 1 /**< Full-duplex connection (see link_duplex). */
-#define RTE_ETH_LINK_DOWN        0 /**< Link is down (see link_status). */
-#define RTE_ETH_LINK_UP          1 /**< Link is up (see link_status). */
-#define RTE_ETH_LINK_FIXED       0 /**< No autonegotiation (see link_autoneg). */
-#define RTE_ETH_LINK_AUTONEG     1 /**< Autonegotiated (see link_autoneg). */
-#define RTE_ETH_LINK_MAX_STR_LEN 40 /**< Max length of default link string. */
+#define RTE_ETH_LINK_HALF_DUPLEX	0 /**< Half-duplex connection (see link_duplex). */
+#define RTE_ETH_LINK_FULL_DUPLEX	1 /**< Full-duplex connection (see link_duplex). */
+#define RTE_ETH_LINK_UNKNOWN_DUPLEX	2 /**</ Unknown-duplex (see link_duplex). */
+#define RTE_ETH_LINK_DOWN		0 /**< Link is down (see link_status). */
+#define RTE_ETH_LINK_UP			1 /**< Link is up (see link_status). */
+#define RTE_ETH_LINK_FIXED		0 /**< No autonegotiation (see link_autoneg). */
+#define RTE_ETH_LINK_AUTONEG		1 /**< Autonegotiated (see link_autoneg). */
+#define RTE_ETH_LINK_MAX_STR_LEN	40 /**< Max length of default link string. */
+/**@}*/
+
+/**@{@name Link negotiation
+ * Constants used in link management to specify connector port.
+ */
+#define RTE_PORT_TP             0x00
+#define RTE_PORT_AUI            0x01
+#define RTE_PORT_MII            0x02
+#define RTE_PORT_FIBRE          0x03
+#define RTE_PORT_BNC            0x04
+#define RTE_PORT_DA             0x05
+#define RTE_PORT_NONE           0xef
+#define RTE_PORT_OTHER          0xff
 /**@}*/
 
 /**
@@ -1433,6 +1447,147 @@ struct rte_eth_pfc_queue_conf {
 	} tx_pause; /* Valid when (mode == FC_TX_PAUSE || mode == FC_FULL) */
 };
 
+/* Enable or disable autonegotiation. */
+#define RTE_AUTONEG_DISABLE         0x00
+#define RTE_AUTONEG_ENABLE          0x01
+
+/* MDI or MDI-X status/control - if MDI/MDI_X/AUTO is set then
+ * the driver is required to renegotiate link
+ */
+#define RTE_TP_MDI_INVALID      0x00 /* status: unknown; control: unsupported */
+#define RTE_TP_MDI              0x01 /* status: MDI;     control: force MDI */
+#define RTE_TP_MDI_X            0x02 /* status: MDI-X;   control: force MDI-X */
+#define RTE_TP_MDI_AUTO         0x03 /*                  control: auto-select */
+
+/* Link mode bit indices */
+enum rte_link_mode_bit_indices {
+	RTE_LINK_MODE_10baseT_Half_BIT	= 0,
+	RTE_LINK_MODE_10baseT_Full_BIT	= 1,
+	RTE_LINK_MODE_100baseT_Half_BIT	= 2,
+	RTE_LINK_MODE_100baseT_Full_BIT	= 3,
+	RTE_LINK_MODE_1000baseT_Half_BIT	= 4,
+	RTE_LINK_MODE_1000baseT_Full_BIT	= 5,
+	RTE_LINK_MODE_Autoneg_BIT		= 6,
+	RTE_LINK_MODE_TP_BIT		= 7,
+	RTE_LINK_MODE_AUI_BIT		= 8,
+	RTE_LINK_MODE_MII_BIT		= 9,
+	RTE_LINK_MODE_FIBRE_BIT		= 10,
+	RTE_LINK_MODE_BNC_BIT		= 11,
+	RTE_LINK_MODE_10000baseT_Full_BIT	= 12,
+	RTE_LINK_MODE_Pause_BIT		= 13,
+	RTE_LINK_MODE_Asym_Pause_BIT	= 14,
+	RTE_LINK_MODE_2500baseX_Full_BIT	= 15,
+	RTE_LINK_MODE_Backplane_BIT		= 16,
+	RTE_LINK_MODE_1000baseKX_Full_BIT	= 17,
+	RTE_LINK_MODE_10000baseKX4_Full_BIT	= 18,
+	RTE_LINK_MODE_10000baseKR_Full_BIT	= 19,
+	RTE_LINK_MODE_10000baseR_FEC_BIT	= 20,
+	RTE_LINK_MODE_20000baseMLD2_Full_BIT = 21,
+	RTE_LINK_MODE_20000baseKR2_Full_BIT	= 22,
+	RTE_LINK_MODE_40000baseKR4_Full_BIT	= 23,
+	RTE_LINK_MODE_40000baseCR4_Full_BIT	= 24,
+	RTE_LINK_MODE_40000baseSR4_Full_BIT	= 25,
+	RTE_LINK_MODE_40000baseLR4_Full_BIT	= 26,
+	RTE_LINK_MODE_56000baseKR4_Full_BIT	= 27,
+	RTE_LINK_MODE_56000baseCR4_Full_BIT	= 28,
+	RTE_LINK_MODE_56000baseSR4_Full_BIT	= 29,
+	RTE_LINK_MODE_56000baseLR4_Full_BIT	= 30,
+	RTE_LINK_MODE_25000baseCR_Full_BIT	= 31,
+	RTE_LINK_MODE_25000baseKR_Full_BIT	= 32,
+	RTE_LINK_MODE_25000baseSR_Full_BIT	= 33,
+	RTE_LINK_MODE_50000baseCR2_Full_BIT	= 34,
+	RTE_LINK_MODE_50000baseKR2_Full_BIT	= 35,
+	RTE_LINK_MODE_100000baseKR4_Full_BIT	= 36,
+	RTE_LINK_MODE_100000baseSR4_Full_BIT	= 37,
+	RTE_LINK_MODE_100000baseCR4_Full_BIT	= 38,
+	RTE_LINK_MODE_100000baseLR4_ER4_Full_BIT	= 39,
+	RTE_LINK_MODE_50000baseSR2_Full_BIT		= 40,
+	RTE_LINK_MODE_1000baseX_Full_BIT	= 41,
+	RTE_LINK_MODE_10000baseCR_Full_BIT	= 42,
+	RTE_LINK_MODE_10000baseSR_Full_BIT	= 43,
+	RTE_LINK_MODE_10000baseLR_Full_BIT	= 44,
+	RTE_LINK_MODE_10000baseLRM_Full_BIT	= 45,
+	RTE_LINK_MODE_10000baseER_Full_BIT	= 46,
+	RTE_LINK_MODE_2500baseT_Full_BIT	= 47,
+	RTE_LINK_MODE_5000baseT_Full_BIT	= 48,
+
+	RTE_LINK_MODE_FEC_NONE_BIT	= 49,
+	RTE_LINK_MODE_FEC_RS_BIT	= 50,
+	RTE_LINK_MODE_FEC_BASER_BIT	= 51,
+	RTE_LINK_MODE_50000baseKR_Full_BIT		 = 52,
+	RTE_LINK_MODE_50000baseSR_Full_BIT		 = 53,
+	RTE_LINK_MODE_50000baseCR_Full_BIT		 = 54,
+	RTE_LINK_MODE_50000baseLR_ER_FR_Full_BIT	 = 55,
+	RTE_LINK_MODE_50000baseDR_Full_BIT		 = 56,
+	RTE_LINK_MODE_100000baseKR2_Full_BIT	 = 57,
+	RTE_LINK_MODE_100000baseSR2_Full_BIT	 = 58,
+	RTE_LINK_MODE_100000baseCR2_Full_BIT	 = 59,
+	RTE_LINK_MODE_100000baseLR2_ER2_FR2_Full_BIT = 60,
+	RTE_LINK_MODE_100000baseDR2_Full_BIT	 = 61,
+	RTE_LINK_MODE_200000baseKR4_Full_BIT	 = 62,
+	RTE_LINK_MODE_200000baseSR4_Full_BIT	 = 63,
+	RTE_LINK_MODE_200000baseLR4_ER4_FR4_Full_BIT = 64,
+	RTE_LINK_MODE_200000baseDR4_Full_BIT	 = 65,
+	RTE_LINK_MODE_200000baseCR4_Full_BIT	 = 66,
+	RTE_LINK_MODE_100baseT1_Full_BIT		 = 67,
+	RTE_LINK_MODE_1000baseT1_Full_BIT		 = 68,
+	RTE_LINK_MODE_400000baseKR8_Full_BIT	 = 69,
+	RTE_LINK_MODE_400000baseSR8_Full_BIT	 = 70,
+	RTE_LINK_MODE_400000baseLR8_ER8_FR8_Full_BIT = 71,
+	RTE_LINK_MODE_400000baseDR8_Full_BIT	 = 72,
+	RTE_LINK_MODE_400000baseCR8_Full_BIT	 = 73,
+	RTE_LINK_MODE_FEC_LLRS_BIT			 = 74,
+	RTE_LINK_MODE_100000baseKR_Full_BIT		 = 75,
+	RTE_LINK_MODE_100000baseSR_Full_BIT		 = 76,
+	RTE_LINK_MODE_100000baseLR_ER_FR_Full_BIT	 = 77,
+	RTE_LINK_MODE_100000baseCR_Full_BIT		 = 78,
+	RTE_LINK_MODE_100000baseDR_Full_BIT		 = 79,
+	RTE_LINK_MODE_200000baseKR2_Full_BIT	 = 80,
+	RTE_LINK_MODE_200000baseSR2_Full_BIT	 = 81,
+	RTE_LINK_MODE_200000baseLR2_ER2_FR2_Full_BIT = 82,
+	RTE_LINK_MODE_200000baseDR2_Full_BIT	 = 83,
+	RTE_LINK_MODE_200000baseCR2_Full_BIT	 = 84,
+	RTE_LINK_MODE_400000baseKR4_Full_BIT	 = 85,
+	RTE_LINK_MODE_400000baseSR4_Full_BIT	 = 86,
+	RTE_LINK_MODE_400000baseLR4_ER4_FR4_Full_BIT = 87,
+	RTE_LINK_MODE_400000baseDR4_Full_BIT	 = 88,
+	RTE_LINK_MODE_400000baseCR4_Full_BIT	 = 89,
+	RTE_LINK_MODE_100baseFX_Half_BIT		 = 90,
+	RTE_LINK_MODE_100baseFX_Full_BIT		 = 91,
+	/* must be last entry */
+	__RTE_LINK_MODE_MASK_NBITS
+};
+
+/* number of 32-bit words to store the user's link mode bitmaps */
+#define RTE_DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d))
+#define __RTE_LINK_MODE_MASK_NU32                   \
+	RTE_DIV_ROUND_UP(__RTE_LINK_MODE_MASK_NBITS, 32)
+
+/**
+ * Link control and status
+ * @speed: Link speed (Mbps)
+ * @duplex: Duplex mode; one of %DUPLEX_*
+ * @port: Physical connector type; one of %PORT_*
+ * @autoneg: Enable/disable autonegotiation and auto-detection;
+ *	either %AUTONEG_DISABLE or %AUTONEG_ENABLE
+ */
+struct rte_link_base_settings {
+	struct rte_eth_link link;
+	uint8_t port;
+	uint8_t phy_address;
+	uint8_t eth_tp_mdix;
+	uint8_t eth_tp_mdix_ctrl;
+};
+
+struct rte_link_settings {
+	struct rte_link_base_settings base;
+	struct {
+		uint32_t supported[__RTE_LINK_MODE_MASK_NU32];
+		uint32_t advertising[__RTE_LINK_MODE_MASK_NU32];
+		uint32_t lp_advertising[__RTE_LINK_MODE_MASK_NU32];
+	} link_modes;
+};
+
 /**
  * Tunnel type for device-specific classifier configuration.
  * @see rte_eth_udp_tunnel
@@ -5936,6 +6091,50 @@ int rte_eth_cman_config_init(uint16_t port_id, struct rte_eth_cman_config *confi
 __rte_experimental
 int rte_eth_cman_config_set(uint16_t port_id, const struct rte_eth_cman_config *config);
 
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * Retrieve link settings
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param settings
+ *   A pointer to a structure of type *rte_link_settings* to retrieve
+ *   link settings parameters for the given port.
+ *
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if support for cman_config_get does not exist.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - (-EINVAL) if bad parameter.
+ */
+__rte_experimental
+int rte_eth_dev_get_link_settings(uint16_t port_id,
+				  struct rte_link_settings *settings);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
+ *
+ * Configure link settings
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param settings
+ *   A pointer to a structure of type *rte_link_settings* to configure
+ *   link settings parameters for the given port.
+ *
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if support for cman_config_get does not exist.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - (-EINVAL) if bad parameter.
+ */
+__rte_experimental
+int rte_eth_dev_set_link_settings(uint16_t port_id,
+				  const struct rte_link_settings *settings);
+
 /**
  * @warning
  * @b EXPERIMENTAL: this API may change, or be removed, without prior notice
diff --git a/lib/ethdev/version.map b/lib/ethdev/version.map
index 79f6f5293b..5e138a3d10 100644
--- a/lib/ethdev/version.map
+++ b/lib/ethdev/version.map
@@ -325,6 +325,9 @@ EXPERIMENTAL {
 	rte_flow_template_table_resizable;
 	rte_flow_template_table_resize;
 	rte_flow_template_table_resize_complete;
+	rte_eth_dev_get_link_settings;
+	rte_eth_dev_set_link_settings;
+
 };
 
 INTERNAL {
-- 
2.41.0


^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH]  lib: add get/set link settings interface
  2024-04-03 13:59 ` Marek Pazdan
@ 2024-04-03 14:48   ` Thomas Monjalon
  2024-04-03 14:59     ` Marek Pazdan
  0 siblings, 1 reply; 17+ messages in thread
From: Thomas Monjalon @ 2024-04-03 14:48 UTC (permalink / raw)
  To: Marek Pazdan; +Cc: Ferruh Yigit, Andrew Rybchenko, dev

03/04/2024 15:59, Marek Pazdan:
>  There are link settings parameters available from PMD drivers level
>  which are currently not exposed to the user via consistent interface.
>  When interface is available for system level those information can
>  be acquired with 'ethtool DEVNAME' (ioctl: ETHTOOL_SLINKSETTINGS/
>  ETHTOOL_GLINKSETTINGS). There are use cases where
>  physical interface is passthrough to dpdk driver and is not available
>  from system level. Information provided by ioctl carries information
>  useful for link auto negotiation settings among others.

Which information is missing exactly?
Why are you trying to mimic ethtool API?

Please let's add what is missing instead of adding a full new API.



^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH] lib: add get/set link settings interface
  2024-04-03 14:48   ` Thomas Monjalon
@ 2024-04-03 14:59     ` Marek Pazdan
  2024-04-03 16:13       ` Thomas Monjalon
  2024-04-03 17:23       ` Stephen Hemminger
  0 siblings, 2 replies; 17+ messages in thread
From: Marek Pazdan @ 2024-04-03 14:59 UTC (permalink / raw)
  To: Thomas Monjalon; +Cc: Ferruh Yigit, Andrew Rybchenko, dev

[-- Attachment #1: Type: text/plain, Size: 1375 bytes --]

Hi Thomas,

Information like advertising: speed, pause, autonegotiation etc. and that
same for link partner advertising.
I try to mimic ethtool since it's a common, well known and widely used tool
so adding an API which provides the same set of information in case the
interface is passthrough to dpdk will be useful I think.
I've 2 more patches dependent on the one we are discussing now, but I need
patchwork id to add dependency information. I need moderator approval for
the current patch.

Regards,
Marek

On Wed, Apr 3, 2024 at 4:48 PM Thomas Monjalon <thomas@monjalon.net> wrote:

> 03/04/2024 15:59, Marek Pazdan:
> >  There are link settings parameters available from PMD drivers level
> >  which are currently not exposed to the user via consistent interface.
> >  When interface is available for system level those information can
> >  be acquired with 'ethtool DEVNAME' (ioctl: ETHTOOL_SLINKSETTINGS/
> >  ETHTOOL_GLINKSETTINGS). There are use cases where
> >  physical interface is passthrough to dpdk driver and is not available
> >  from system level. Information provided by ioctl carries information
> >  useful for link auto negotiation settings among others.
>
> Which information is missing exactly?
> Why are you trying to mimic ethtool API?
>
> Please let's add what is missing instead of adding a full new API.
>
>
>

[-- Attachment #2: Type: text/html, Size: 1829 bytes --]

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH] lib: add get/set link settings interface
  2024-04-03 14:59     ` Marek Pazdan
@ 2024-04-03 16:13       ` Thomas Monjalon
  2024-04-03 17:23       ` Stephen Hemminger
  1 sibling, 0 replies; 17+ messages in thread
From: Thomas Monjalon @ 2024-04-03 16:13 UTC (permalink / raw)
  To: Marek Pazdan; +Cc: Ferruh Yigit, Andrew Rybchenko, dev

03/04/2024 16:59, Marek Pazdan:
> Hi Thomas,
> 
> Information like advertising: speed, pause, autonegotiation etc. and that
> same for link partner advertising.

speed and duplex are already provided in some existing API.


> I try to mimic ethtool since it's a common, well known and widely used tool
> so adding an API which provides the same set of information in case the
> interface is passthrough to dpdk will be useful I think.

DPDK API is widely used as well :)
I am not sure adding a new API for the same thing is a good idea.


> I've 2 more patches dependent on the one we are discussing now, but I need
> patchwork id to add dependency information. I need moderator approval for
> the current patch.

I've approved your mails,
but you would not need a manual approval if you register.
Note that you can disable receiving other threads in ML options.
See an explanation here:
https://www.dpdk.org/first-patch-submission-to-the-dpdk-open-source-project/



> On Wed, Apr 3, 2024 at 4:48 PM Thomas Monjalon <thomas@monjalon.net> wrote:
> 
> > 03/04/2024 15:59, Marek Pazdan:
> > >  There are link settings parameters available from PMD drivers level
> > >  which are currently not exposed to the user via consistent interface.
> > >  When interface is available for system level those information can
> > >  be acquired with 'ethtool DEVNAME' (ioctl: ETHTOOL_SLINKSETTINGS/
> > >  ETHTOOL_GLINKSETTINGS). There are use cases where
> > >  physical interface is passthrough to dpdk driver and is not available
> > >  from system level. Information provided by ioctl carries information
> > >  useful for link auto negotiation settings among others.
> >
> > Which information is missing exactly?
> > Why are you trying to mimic ethtool API?
> >
> > Please let's add what is missing instead of adding a full new API.




^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH]  lib: add get/set link settings interface
  2024-04-03 13:40 ` [PATCH] lib: " Marek Pazdan
@ 2024-04-03 16:49   ` Tyler Retzlaff
  2024-04-04  7:09     ` David Marchand
  0 siblings, 1 reply; 17+ messages in thread
From: Tyler Retzlaff @ 2024-04-03 16:49 UTC (permalink / raw)
  To: Marek Pazdan
  Cc: Thomas Monjalon, Ferruh Yigit, Andrew Rybchenko, dev, david.marchand

On Wed, Apr 03, 2024 at 06:40:24AM -0700, Marek Pazdan wrote:
>  There are link settings parameters available from PMD drivers level
>  which are currently not exposed to the user via consistent interface.
>  When interface is available for system level those information can
>  be acquired with 'ethtool DEVNAME' (ioctl: ETHTOOL_SLINKSETTINGS/
>  ETHTOOL_GLINKSETTINGS). There are use cases where
>  physical interface is passthrough to dpdk driver and is not available
>  from system level. Information provided by ioctl carries information
>  useful for link auto negotiation settings among others.
> 
> Signed-off-by: Marek Pazdan <mpazdan@arista.com>
> ---
> diff --git a/lib/ethdev/rte_ethdev.h b/lib/ethdev/rte_ethdev.h
> index 147257d6a2..66aad925d0 100644
> --- a/lib/ethdev/rte_ethdev.h
> +++ b/lib/ethdev/rte_ethdev.h
> @@ -335,7 +335,7 @@ struct rte_eth_stats {
>  __extension__
>  struct __rte_aligned(8) rte_eth_link { /**< aligned for atomic64 read/write */
>  	uint32_t link_speed;        /**< RTE_ETH_SPEED_NUM_ */
> -	uint16_t link_duplex  : 1;  /**< RTE_ETH_LINK_[HALF/FULL]_DUPLEX */
> +	uint16_t link_duplex  : 2;  /**< RTE_ETH_LINK_[HALF/FULL/UNKNOWN]_DUPLEX */
>  	uint16_t link_autoneg : 1;  /**< RTE_ETH_LINK_[AUTONEG/FIXED] */
>  	uint16_t link_status  : 1;  /**< RTE_ETH_LINK_[DOWN/UP] */
>  };

this breaks the abi. David does libabigail pick this up i wonder?

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH] lib: add get/set link settings interface
  2024-04-03 14:59     ` Marek Pazdan
  2024-04-03 16:13       ` Thomas Monjalon
@ 2024-04-03 17:23       ` Stephen Hemminger
  2024-04-03 22:08         ` Marek Pazdan
  1 sibling, 1 reply; 17+ messages in thread
From: Stephen Hemminger @ 2024-04-03 17:23 UTC (permalink / raw)
  To: Marek Pazdan; +Cc: Thomas Monjalon, Ferruh Yigit, Andrew Rybchenko, dev

On Wed, 3 Apr 2024 16:59:08 +0200
Marek Pazdan <mpazdan@arista.com> wrote:

> Hi Thomas,
> 
> Information like advertising: speed, pause, autonegotiation etc. and that
> same for link partner advertising.
> I try to mimic ethtool since it's a common, well known and widely used tool
> so adding an API which provides the same set of information in case the
> interface is passthrough to dpdk will be useful I think.
> I've 2 more patches dependent on the one we are discussing now, but I need
> patchwork id to add dependency information. I need moderator approval for
> the current patch.
> 
> Regards,
> Marek

DPDK already had this info under rte_eth_conf and it is supported
on all drivers. Why introduce yet another API and only for some drivers?

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH] lib: add get/set link settings interface
  2024-04-03 17:23       ` Stephen Hemminger
@ 2024-04-03 22:08         ` Marek Pazdan
  2024-04-03 23:38           ` Stephen Hemminger
  0 siblings, 1 reply; 17+ messages in thread
From: Marek Pazdan @ 2024-04-03 22:08 UTC (permalink / raw)
  To: stephen; +Cc: Thomas Monjalon, Ferruh Yigit, Andrew Rybchenko, dev

[-- Attachment #1: Type: text/plain, Size: 1309 bytes --]

I can remove this part (rte_eth_config), but the new API provides other
link information which is not available from the existing API, like
supported/advertising/partner_advertising link modes.
Additionally from what I see, rte_eth_confg is available from
rte_eth_dev_conf_get API and it's copy of requested configuration:
`memcpy(dev_conf, &dev->data->dev_conf, sizeof(struct rte_eth_conf));`


On Wed, Apr 3, 2024 at 7:23 PM Stephen Hemminger <stephen@networkplumber.org>
wrote:

> On Wed, 3 Apr 2024 16:59:08 +0200
> Marek Pazdan <mpazdan@arista.com> wrote:
>
> > Hi Thomas,
> >
> > Information like advertising: speed, pause, autonegotiation etc. and that
> > same for link partner advertising.
> > I try to mimic ethtool since it's a common, well known and widely used
> tool
> > so adding an API which provides the same set of information in case the
> > interface is passthrough to dpdk will be useful I think.
> > I've 2 more patches dependent on the one we are discussing now, but I
> need
> > patchwork id to add dependency information. I need moderator approval for
> > the current patch.
> >
> > Regards,
> > Marek
>
> DPDK already had this info under rte_eth_conf and it is supported
> on all drivers. Why introduce yet another API and only for some drivers?
>

[-- Attachment #2: Type: text/html, Size: 1798 bytes --]

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH] lib: add get/set link settings interface
  2024-04-03 22:08         ` Marek Pazdan
@ 2024-04-03 23:38           ` Stephen Hemminger
  2024-07-22 14:55             ` Ferruh Yigit
  0 siblings, 1 reply; 17+ messages in thread
From: Stephen Hemminger @ 2024-04-03 23:38 UTC (permalink / raw)
  To: Marek Pazdan; +Cc: Thomas Monjalon, Ferruh Yigit, Andrew Rybchenko, dev

On Thu, 4 Apr 2024 00:08:41 +0200
Marek Pazdan <mpazdan@arista.com> wrote:

> I can remove this part (rte_eth_config), but the new API provides other
> link information which is not available from the existing API, like
> supported/advertising/partner_advertising link modes.
> Additionally from what I see, rte_eth_confg is available from
> rte_eth_dev_conf_get API and it's copy of requested configuration:
> `memcpy(dev_conf, &dev->data->dev_conf, sizeof(struct rte_eth_conf));`


Then the new info should go in the rte_eth_config in a future version
of DPDK. Having bits in different places makes the API confusing.

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH] lib: add get/set link settings interface
  2024-04-03 16:49   ` Tyler Retzlaff
@ 2024-04-04  7:09     ` David Marchand
  2024-04-05  0:55       ` Tyler Retzlaff
  0 siblings, 1 reply; 17+ messages in thread
From: David Marchand @ 2024-04-04  7:09 UTC (permalink / raw)
  To: Tyler Retzlaff, Marek Pazdan
  Cc: Thomas Monjalon, Ferruh Yigit, Andrew Rybchenko, dev

Hello Tyler, Marek,

On Wed, Apr 3, 2024 at 6:49 PM Tyler Retzlaff
<roretzla@linux.microsoft.com> wrote:
>
> On Wed, Apr 03, 2024 at 06:40:24AM -0700, Marek Pazdan wrote:
> >  There are link settings parameters available from PMD drivers level
> >  which are currently not exposed to the user via consistent interface.
> >  When interface is available for system level those information can
> >  be acquired with 'ethtool DEVNAME' (ioctl: ETHTOOL_SLINKSETTINGS/
> >  ETHTOOL_GLINKSETTINGS). There are use cases where
> >  physical interface is passthrough to dpdk driver and is not available
> >  from system level. Information provided by ioctl carries information
> >  useful for link auto negotiation settings among others.
> >
> > Signed-off-by: Marek Pazdan <mpazdan@arista.com>
> > ---
> > diff --git a/lib/ethdev/rte_ethdev.h b/lib/ethdev/rte_ethdev.h
> > index 147257d6a2..66aad925d0 100644
> > --- a/lib/ethdev/rte_ethdev.h
> > +++ b/lib/ethdev/rte_ethdev.h
> > @@ -335,7 +335,7 @@ struct rte_eth_stats {
> >  __extension__
> >  struct __rte_aligned(8) rte_eth_link { /**< aligned for atomic64 read/write */
> >       uint32_t link_speed;        /**< RTE_ETH_SPEED_NUM_ */
> > -     uint16_t link_duplex  : 1;  /**< RTE_ETH_LINK_[HALF/FULL]_DUPLEX */
> > +     uint16_t link_duplex  : 2;  /**< RTE_ETH_LINK_[HALF/FULL/UNKNOWN]_DUPLEX */
> >       uint16_t link_autoneg : 1;  /**< RTE_ETH_LINK_[AUTONEG/FIXED] */
> >       uint16_t link_status  : 1;  /**< RTE_ETH_LINK_[DOWN/UP] */
> >  };
>
> this breaks the abi. David does libabigail pick this up i wonder?
>

Yes, the CI flagged it.

Looking at the UNH report (in patchwork):
http://mails.dpdk.org/archives/test-report/2024-April/631222.html

1 function with some indirect sub-type change:

[C] 'function int rte_eth_link_get(uint16_t, rte_eth_link*)' at
rte_ethdev.c:2972:1 has some indirect sub-type changes:
parameter 2 of type 'rte_eth_link*' has sub-type changes:
in pointed to type 'struct rte_eth_link' at rte_ethdev.h:336:1:
type size hasn't changed
2 data member changes:
'uint16_t link_autoneg' offset changed from 33 to 34 (in bits) (by +1 bits)
'uint16_t link_status' offset changed from 34 to 35 (in bits) (by +1 bits)

Error: ABI issue reported for abidiff --suppr
/home-local/jenkins-local/jenkins-agent/workspace/Generic-DPDK-Compile-ABI
at 3/dpdk/devtools/libabigail.abignore --no-added-syms --headers-dir1
reference/usr/local/include --headers-dir2
build_install/usr/local/include
reference/usr/local/lib/x86_64-linux-gnu/librte_ethdev.so.24.0
build_install/usr/local/lib/x86_64-linux-gnu/librte_ethdev.so.24.2
ABIDIFF_ABI_CHANGE, this change requires a review (abidiff flagged
this as a potential issue).


GHA would have caught it too, but the documentation generation failed
before reaching the ABI check.
http://mails.dpdk.org/archives/test-report/2024-April/631086.html


-- 
David Marchand


^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH] lib: add get/set link settings interface
  2024-04-04  7:09     ` David Marchand
@ 2024-04-05  0:55       ` Tyler Retzlaff
  2024-04-05  0:56         ` Tyler Retzlaff
  2024-04-05  8:58         ` David Marchand
  0 siblings, 2 replies; 17+ messages in thread
From: Tyler Retzlaff @ 2024-04-05  0:55 UTC (permalink / raw)
  To: David Marchand
  Cc: Marek Pazdan, Thomas Monjalon, Ferruh Yigit, Andrew Rybchenko, dev

On Thu, Apr 04, 2024 at 09:09:40AM +0200, David Marchand wrote:
> Hello Tyler, Marek,
> 
> On Wed, Apr 3, 2024 at 6:49 PM Tyler Retzlaff
> <roretzla@linux.microsoft.com> wrote:
> >
> > On Wed, Apr 03, 2024 at 06:40:24AM -0700, Marek Pazdan wrote:
> > >  There are link settings parameters available from PMD drivers level
> > >  which are currently not exposed to the user via consistent interface.
> > >  When interface is available for system level those information can
> > >  be acquired with 'ethtool DEVNAME' (ioctl: ETHTOOL_SLINKSETTINGS/
> > >  ETHTOOL_GLINKSETTINGS). There are use cases where
> > >  physical interface is passthrough to dpdk driver and is not available
> > >  from system level. Information provided by ioctl carries information
> > >  useful for link auto negotiation settings among others.
> > >
> > > Signed-off-by: Marek Pazdan <mpazdan@arista.com>
> > > ---
> > > diff --git a/lib/ethdev/rte_ethdev.h b/lib/ethdev/rte_ethdev.h
> > > index 147257d6a2..66aad925d0 100644
> > > --- a/lib/ethdev/rte_ethdev.h
> > > +++ b/lib/ethdev/rte_ethdev.h
> > > @@ -335,7 +335,7 @@ struct rte_eth_stats {
> > >  __extension__
> > >  struct __rte_aligned(8) rte_eth_link { /**< aligned for atomic64 read/write */
> > >       uint32_t link_speed;        /**< RTE_ETH_SPEED_NUM_ */
> > > -     uint16_t link_duplex  : 1;  /**< RTE_ETH_LINK_[HALF/FULL]_DUPLEX */
> > > +     uint16_t link_duplex  : 2;  /**< RTE_ETH_LINK_[HALF/FULL/UNKNOWN]_DUPLEX */
> > >       uint16_t link_autoneg : 1;  /**< RTE_ETH_LINK_[AUTONEG/FIXED] */
> > >       uint16_t link_status  : 1;  /**< RTE_ETH_LINK_[DOWN/UP] */
> > >  };
> >
> > this breaks the abi. David does libabigail pick this up i wonder?
> >
> 
> Yes, the CI flagged it.
> 
> Looking at the UNH report (in patchwork):
> http://mails.dpdk.org/archives/test-report/2024-April/631222.html

i'm jealous we don't have libabigail on windows, so helpfull.

> 
> 1 function with some indirect sub-type change:
> 
> [C] 'function int rte_eth_link_get(uint16_t, rte_eth_link*)' at
> rte_ethdev.c:2972:1 has some indirect sub-type changes:
> parameter 2 of type 'rte_eth_link*' has sub-type changes:
> in pointed to type 'struct rte_eth_link' at rte_ethdev.h:336:1:
> type size hasn't changed
> 2 data member changes:
> 'uint16_t link_autoneg' offset changed from 33 to 34 (in bits) (by +1 bits)
> 'uint16_t link_status' offset changed from 34 to 35 (in bits) (by +1 bits)
> 
> Error: ABI issue reported for abidiff --suppr
> /home-local/jenkins-local/jenkins-agent/workspace/Generic-DPDK-Compile-ABI
> at 3/dpdk/devtools/libabigail.abignore --no-added-syms --headers-dir1
> reference/usr/local/include --headers-dir2
> build_install/usr/local/include
> reference/usr/local/lib/x86_64-linux-gnu/librte_ethdev.so.24.0
> build_install/usr/local/lib/x86_64-linux-gnu/librte_ethdev.so.24.2
> ABIDIFF_ABI_CHANGE, this change requires a review (abidiff flagged
> this as a potential issue).
> 
> 
> GHA would have caught it too, but the documentation generation failed
> before reaching the ABI check.
> http://mails.dpdk.org/archives/test-report/2024-April/631086.html
> 
> 
> -- 
> David Marchand

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH] lib: add get/set link settings interface
  2024-04-05  0:55       ` Tyler Retzlaff
@ 2024-04-05  0:56         ` Tyler Retzlaff
  2024-04-05  8:58         ` David Marchand
  1 sibling, 0 replies; 17+ messages in thread
From: Tyler Retzlaff @ 2024-04-05  0:56 UTC (permalink / raw)
  To: David Marchand
  Cc: Marek Pazdan, Thomas Monjalon, Ferruh Yigit, Andrew Rybchenko, dev

On Thu, Apr 04, 2024 at 05:55:18PM -0700, Tyler Retzlaff wrote:
> On Thu, Apr 04, 2024 at 09:09:40AM +0200, David Marchand wrote:
> > Hello Tyler, Marek,
> > 
> > On Wed, Apr 3, 2024 at 6:49 PM Tyler Retzlaff
> > <roretzla@linux.microsoft.com> wrote:
> > >
> > > On Wed, Apr 03, 2024 at 06:40:24AM -0700, Marek Pazdan wrote:
> > > >  There are link settings parameters available from PMD drivers level
> > > >  which are currently not exposed to the user via consistent interface.
> > > >  When interface is available for system level those information can
> > > >  be acquired with 'ethtool DEVNAME' (ioctl: ETHTOOL_SLINKSETTINGS/
> > > >  ETHTOOL_GLINKSETTINGS). There are use cases where
> > > >  physical interface is passthrough to dpdk driver and is not available
> > > >  from system level. Information provided by ioctl carries information
> > > >  useful for link auto negotiation settings among others.
> > > >
> > > > Signed-off-by: Marek Pazdan <mpazdan@arista.com>
> > > > ---
> > > > diff --git a/lib/ethdev/rte_ethdev.h b/lib/ethdev/rte_ethdev.h
> > > > index 147257d6a2..66aad925d0 100644
> > > > --- a/lib/ethdev/rte_ethdev.h
> > > > +++ b/lib/ethdev/rte_ethdev.h
> > > > @@ -335,7 +335,7 @@ struct rte_eth_stats {
> > > >  __extension__
> > > >  struct __rte_aligned(8) rte_eth_link { /**< aligned for atomic64 read/write */
> > > >       uint32_t link_speed;        /**< RTE_ETH_SPEED_NUM_ */
> > > > -     uint16_t link_duplex  : 1;  /**< RTE_ETH_LINK_[HALF/FULL]_DUPLEX */
> > > > +     uint16_t link_duplex  : 2;  /**< RTE_ETH_LINK_[HALF/FULL/UNKNOWN]_DUPLEX */
> > > >       uint16_t link_autoneg : 1;  /**< RTE_ETH_LINK_[AUTONEG/FIXED] */
> > > >       uint16_t link_status  : 1;  /**< RTE_ETH_LINK_[DOWN/UP] */
> > > >  };
> > >
> > > this breaks the abi. David does libabigail pick this up i wonder?
> > >
> > 
> > Yes, the CI flagged it.
> > 
> > Looking at the UNH report (in patchwork):
> > http://mails.dpdk.org/archives/test-report/2024-April/631222.html
> 
> i'm jealous we don't have libabigail on windows, so helpfull.

s/ll/l/ end of day bah.

> 
> > 
> > 1 function with some indirect sub-type change:
> > 
> > [C] 'function int rte_eth_link_get(uint16_t, rte_eth_link*)' at
> > rte_ethdev.c:2972:1 has some indirect sub-type changes:
> > parameter 2 of type 'rte_eth_link*' has sub-type changes:
> > in pointed to type 'struct rte_eth_link' at rte_ethdev.h:336:1:
> > type size hasn't changed
> > 2 data member changes:
> > 'uint16_t link_autoneg' offset changed from 33 to 34 (in bits) (by +1 bits)
> > 'uint16_t link_status' offset changed from 34 to 35 (in bits) (by +1 bits)
> > 
> > Error: ABI issue reported for abidiff --suppr
> > /home-local/jenkins-local/jenkins-agent/workspace/Generic-DPDK-Compile-ABI
> > at 3/dpdk/devtools/libabigail.abignore --no-added-syms --headers-dir1
> > reference/usr/local/include --headers-dir2
> > build_install/usr/local/include
> > reference/usr/local/lib/x86_64-linux-gnu/librte_ethdev.so.24.0
> > build_install/usr/local/lib/x86_64-linux-gnu/librte_ethdev.so.24.2
> > ABIDIFF_ABI_CHANGE, this change requires a review (abidiff flagged
> > this as a potential issue).
> > 
> > 
> > GHA would have caught it too, but the documentation generation failed
> > before reaching the ABI check.
> > http://mails.dpdk.org/archives/test-report/2024-April/631086.html
> > 
> > 
> > -- 
> > David Marchand

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH] lib: add get/set link settings interface
  2024-04-05  0:55       ` Tyler Retzlaff
  2024-04-05  0:56         ` Tyler Retzlaff
@ 2024-04-05  8:58         ` David Marchand
  2024-04-05 13:05           ` Dodji Seketeli
  1 sibling, 1 reply; 17+ messages in thread
From: David Marchand @ 2024-04-05  8:58 UTC (permalink / raw)
  To: Tyler Retzlaff, Dodji Seketeli; +Cc: Thomas Monjalon, dev

On Fri, Apr 5, 2024 at 2:55 AM Tyler Retzlaff
<roretzla@linux.microsoft.com> wrote:
> On Thu, Apr 04, 2024 at 09:09:40AM +0200, David Marchand wrote:
> > On Wed, Apr 3, 2024 at 6:49 PM Tyler Retzlaff
> > > this breaks the abi. David does libabigail pick this up i wonder?
> >
> > Yes, the CI flagged it.
> >
> > Looking at the UNH report (in patchwork):
> > http://mails.dpdk.org/archives/test-report/2024-April/631222.html
>
> i'm jealous we don't have libabigail on windows, so helpful.

libabigail is written in C++ and relies on the elfutils and libxml2 libraries.
I am unclear about what binary format is used in Windows... so I am
not sure how much work would be required to have it on Windows.

That's more something to discuss with Dodji :-).


-- 
David Marchand


^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH] lib: add get/set link settings interface
  2024-04-05  8:58         ` David Marchand
@ 2024-04-05 13:05           ` Dodji Seketeli
  0 siblings, 0 replies; 17+ messages in thread
From: Dodji Seketeli @ 2024-04-05 13:05 UTC (permalink / raw)
  To: David Marchand; +Cc: Tyler Retzlaff, Thomas Monjalon, dev

Hello,

> On Fri, Apr 5, 2024 at 2:55 AM Tyler Retzlaff

[...]

>> i'm jealous we don't have libabigail on windows, so helpful.

Heh, thank you for the kind words.

David Marchand <david.marchand@redhat.com> writes:

[...]

> libabigail is written in C++ and relies on the elfutils and libxml2
> libraries.

That is correct.  Thank you for chiming in, David.

> I am unclear about what binary format is used in Windows... so I am
> not sure how much work would be required to have it on Windows.

So for a little bit of context, libabigail constructs its own internal
representation (IR) of the artifacts relevant to perform the analysis.
The middle-end of the system then performs the needed analysis on that
IR.

The binary format itself it handled by a front-end.  Today, we have
front-ends that reads the ELF format and constructs the IR and hands it
over to the middle end.

One could very well imagine a new front-end that knows how to read the
Portable Executable (PE) format that is used on Windows, along with its
accompanying debug information.

Luckily, I've written articles[1][2] that explains how libabigail
recently switched to having a multi-front-end architecture that we have
used to support alternative debug information formats like CTF[3] and
BTF.

In light of that, adding a new PE front-end would be "just work to do",
I would think.  And I would obviously not be opposed to helping such a
project and merging the result in the end.

As for any feature request, I would encourage potentially interested
parties to file an "enhancement request" on the bug tracker of the
project[4].

> That's more something to discuss with Dodji :-).

Thanks for the plug ;-)

I hope this helps.

[1]: https://developers.redhat.com/articles/2023/01/05/libabigail-multiple-debugging-formats#the_resulting_multi_front_end_architecture
[2]: https://www.redhat.com/en/blog/bpf-type-format-support-libabigail-23
[3]: https://lwn.net/Articles/795384/
[4]: https://sourceware.org/bugzilla/enter_bug.cgi?product=libabigail

Cheers,

-- 
		Dodji


^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH] lib: add get/set link settings interface
  2024-04-03 23:38           ` Stephen Hemminger
@ 2024-07-22 14:55             ` Ferruh Yigit
  0 siblings, 0 replies; 17+ messages in thread
From: Ferruh Yigit @ 2024-07-22 14:55 UTC (permalink / raw)
  To: Stephen Hemminger, Marek Pazdan; +Cc: Thomas Monjalon, Andrew Rybchenko, dev

On 4/4/2024 12:38 AM, Stephen Hemminger wrote:
> On Thu, 4 Apr 2024 00:08:41 +0200
> Marek Pazdan <mpazdan@arista.com> wrote:
> 
>> I can remove this part (rte_eth_config), but the new API provides other
>> link information which is not available from the existing API, like
>> supported/advertising/partner_advertising link modes.
>> Additionally from what I see, rte_eth_confg is available from
>> rte_eth_dev_conf_get API and it's copy of requested configuration:
>> `memcpy(dev_conf, &dev->data->dev_conf, sizeof(struct rte_eth_conf));`
> 
> 
> Then the new info should go in the rte_eth_config in a future version
> of DPDK. Having bits in different places makes the API confusing.
>

Hi Marek,

Not able to get enough justification for the new set of ethdev APIs for
the link.

It can be an option to extend existing APIs, and have a more focused API
for the missing part. This depends on what is missing.

I am marking this patch and two relevant patches [1] as change
requested, if the functionality is still relevant please start with a
new RFC in next release with one of the above approaches to enable
discussion again.

Thanks,
ferruh

[1]
-
https://patches.dpdk.org/project/dpdk/patch/20240403135953.7209-1-mpazdan@arista.com/
-
https://patches.dpdk.org/project/dpdk/patch/20240403225333.16260-1-mpazdan@arista.com/

^ permalink raw reply	[flat|nested] 17+ messages in thread

end of thread, other threads:[~2024-07-22 14:55 UTC | newest]

Thread overview: 17+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-03-26 23:59 [PATCH] igc/ixgbe: add get/set link settings interface Marek Pazdan
2024-03-27 11:12 ` Bruce Richardson
2024-04-03 13:40 ` [PATCH] lib: " Marek Pazdan
2024-04-03 16:49   ` Tyler Retzlaff
2024-04-04  7:09     ` David Marchand
2024-04-05  0:55       ` Tyler Retzlaff
2024-04-05  0:56         ` Tyler Retzlaff
2024-04-05  8:58         ` David Marchand
2024-04-05 13:05           ` Dodji Seketeli
2024-04-03 13:59 ` Marek Pazdan
2024-04-03 14:48   ` Thomas Monjalon
2024-04-03 14:59     ` Marek Pazdan
2024-04-03 16:13       ` Thomas Monjalon
2024-04-03 17:23       ` Stephen Hemminger
2024-04-03 22:08         ` Marek Pazdan
2024-04-03 23:38           ` Stephen Hemminger
2024-07-22 14:55             ` Ferruh Yigit

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).