When a particular speed was specified for a port in testpmd, the flags
passed to the underlying API call always included the
RTE_ETH_LINK_SPEED_FIXED flag. This flag is not a mandatory part of the
bitmap when setting speeds, and is used to disable autonegotiation.
It's possible to have a link report only a single speed while
still have negotiation enabled, so testpmd needs to be extended to
support setting a speed both with and without the flag.

This patch does so by adding optional "autoneg on|off" setting after
speed and duplex settings specified by the user. This new option adjusts
the presence or absence of the FIXED speed bit in the ethdev
configuration structure "rte_eth_conf.link_speeds" bitmap. For backward
compatibility, the default value is "autoneg off" for fixed speeds if
not specified, meaning that the RTE_ETH_LINK_SPEED_FIXED flag is set on
the speed value by default.

Signed-off-by: Bruce Richardson <[email protected]>
---
V2:
* changed syntax to more closely match that of ethtool, adding
  autoneg on|off at the end of the command.
* increased compatibility by ensuring that when no autoneg value is
  specified, a numeric speed sets the fixed flag (autoneg off), while an
  "auto" speed keeps autoneg on.
---
 app/test-pmd/cmdline.c                      | 90 +++++++++++++++++++--
 doc/guides/rel_notes/release_26_11.rst      |  6 ++
 doc/guides/testpmd_app_ug/testpmd_funcs.rst |  8 +-
 3 files changed, 95 insertions(+), 9 deletions(-)

diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
index 51078a2a73..676ed18aca 100644
--- a/app/test-pmd/cmdline.c
+++ b/app/test-pmd/cmdline.c
@@ -726,8 +726,8 @@ static void cmd_help_long_parsed(void *parsed_result,
                        "port config (port_id|all)"
                        " speed (10|100|1000|2500|5000|10000|25000|40000|50000|"
                        "100000|200000|400000|800000|auto)"
-                       " duplex (half|full|auto)\n"
-                       "    Set speed and duplex for all ports or port_id\n\n"
+                       " duplex (half|full|auto) [autoneg (on|off)]\n"
+                       "    Set speed and duplex; optionally enable or disable 
link autonegotiation\n\n"
 
                        "port config (port_id|all) loopback (mode)\n"
                        "    Set loopback mode for all ports or port_id\n\n"
@@ -1395,10 +1395,21 @@ struct cmd_config_speed_all {
        cmdline_fixed_string_t item2;
        cmdline_fixed_string_t value1;
        cmdline_fixed_string_t value2;
+       cmdline_fixed_string_t autoneg;
+       cmdline_fixed_string_t autoneg_value;
 };
 
+static uint32_t
+link_speed_fixed_bit(const char *speed, const char *autoneg)
+{
+       if (autoneg == NULL)
+               return strcmp(speed, "auto") == 0 ? 0 : 
RTE_ETH_LINK_SPEED_FIXED;
+
+       return strcmp(autoneg, "off") == 0 ? RTE_ETH_LINK_SPEED_FIXED : 0;
+}
+
 static int
-parse_and_check_speed_duplex(char *speedstr, char *duplexstr, uint32_t *speed)
+parse_and_check_speed_duplex(char *speedstr, char *duplexstr, bool fixed, 
uint32_t *speed)
 {
 
        int duplex;
@@ -1455,8 +1466,13 @@ parse_and_check_speed_duplex(char *speedstr, char 
*duplexstr, uint32_t *speed)
                }
        }
 
-       if (*speed != RTE_ETH_LINK_SPEED_AUTONEG)
+       if (fixed) {
+               if (*speed == RTE_ETH_LINK_SPEED_AUTONEG) {
+                       fprintf(stderr, "A fixed link requires a specific 
speed\n");
+                       return -1;
+               }
                *speed |= RTE_ETH_LINK_SPEED_FIXED;
+       }
 
        return 0;
 }
@@ -1464,9 +1480,11 @@ parse_and_check_speed_duplex(char *speedstr, char 
*duplexstr, uint32_t *speed)
 static void
 cmd_config_speed_all_parsed(void *parsed_result,
                        __rte_unused struct cmdline *cl,
-                       __rte_unused void *data)
+                       void *data)
 {
        struct cmd_config_speed_all *res = parsed_result;
+       /* data is used to identify command variant with/without explicit 
autoneg setting */
+       const char *autoneg = data != NULL ? res->autoneg_value : NULL;
        uint32_t link_speed;
        portid_t pid;
 
@@ -1476,7 +1494,7 @@ cmd_config_speed_all_parsed(void *parsed_result,
        }
 
        if (parse_and_check_speed_duplex(res->value1, res->value2,
-                       &link_speed) < 0)
+                       link_speed_fixed_bit(res->value1, autoneg) != 0, 
&link_speed) < 0)
                return;
 
        RTE_ETH_FOREACH_DEV(pid) {
@@ -1504,6 +1522,10 @@ static cmdline_parse_token_string_t 
cmd_config_speed_all_item2 =
 static cmdline_parse_token_string_t cmd_config_speed_all_value2 =
        TOKEN_STRING_INITIALIZER(struct cmd_config_speed_all, value2,
                                                "half#full#auto");
+static cmdline_parse_token_string_t cmd_config_speed_all_autoneg_token =
+       TOKEN_STRING_INITIALIZER(struct cmd_config_speed_all, autoneg, 
"autoneg");
+static cmdline_parse_token_string_t cmd_config_speed_all_autoneg_value =
+       TOKEN_STRING_INITIALIZER(struct cmd_config_speed_all, autoneg_value, 
"on#off");
 
 static cmdline_parse_inst_t cmd_config_speed_all = {
        .f = cmd_config_speed_all_parsed,
@@ -1524,6 +1546,27 @@ static cmdline_parse_inst_t cmd_config_speed_all = {
        },
 };
 
+static cmdline_parse_inst_t cmd_config_speed_all_autoneg = {
+       .f = cmd_config_speed_all_parsed,
+       .data = &cmd_config_speed_all_autoneg,
+       .help_str = "port config all speed "
+               "10|100|1000|2500|5000|10000|25000|40000|50000|"
+               "100000|200000|400000|800000|auto "
+               "duplex half|full|auto autoneg on|off",
+       .tokens = {
+               (void *)&cmd_config_speed_all_port,
+               (void *)&cmd_config_speed_all_keyword,
+               (void *)&cmd_config_speed_all_all,
+               (void *)&cmd_config_speed_all_item1,
+               (void *)&cmd_config_speed_all_value1,
+               (void *)&cmd_config_speed_all_item2,
+               (void *)&cmd_config_speed_all_value2,
+               (void *)&cmd_config_speed_all_autoneg_token,
+               (void *)&cmd_config_speed_all_autoneg_value,
+               NULL,
+       },
+};
+
 /* *** configure speed for specific port *** */
 struct cmd_config_speed_specific {
        cmdline_fixed_string_t port;
@@ -1533,14 +1576,18 @@ struct cmd_config_speed_specific {
        cmdline_fixed_string_t item2;
        cmdline_fixed_string_t value1;
        cmdline_fixed_string_t value2;
+       cmdline_fixed_string_t autoneg;
+       cmdline_fixed_string_t autoneg_value;
 };
 
 static void
 cmd_config_speed_specific_parsed(void *parsed_result,
                                __rte_unused struct cmdline *cl,
-                               __rte_unused void *data)
+                               void *data)
 {
        struct cmd_config_speed_specific *res = parsed_result;
+       /* data is used to identify command variant with/without explicit 
autoneg setting */
+       const char *autoneg = data != NULL ? res->autoneg_value : NULL;
        uint32_t link_speed;
 
        if (port_id_is_invalid(res->id, ENABLED_WARN))
@@ -1552,7 +1599,7 @@ cmd_config_speed_specific_parsed(void *parsed_result,
        }
 
        if (parse_and_check_speed_duplex(res->value1, res->value2,
-                       &link_speed) < 0)
+                       link_speed_fixed_bit(res->value1, autoneg) != 0, 
&link_speed) < 0)
                return;
 
        ports[res->id].dev_conf.link_speeds = link_speed;
@@ -1582,6 +1629,10 @@ static cmdline_parse_token_string_t 
cmd_config_speed_specific_item2 =
 static cmdline_parse_token_string_t cmd_config_speed_specific_value2 =
        TOKEN_STRING_INITIALIZER(struct cmd_config_speed_specific, value2,
                                                        "half#full#auto");
+static cmdline_parse_token_string_t cmd_config_speed_specific_autoneg_token =
+       TOKEN_STRING_INITIALIZER(struct cmd_config_speed_specific, autoneg, 
"autoneg");
+static cmdline_parse_token_string_t cmd_config_speed_specific_autoneg_value =
+       TOKEN_STRING_INITIALIZER(struct cmd_config_speed_specific, 
autoneg_value, "on#off");
 
 static cmdline_parse_inst_t cmd_config_speed_specific = {
        .f = cmd_config_speed_specific_parsed,
@@ -1602,6 +1653,27 @@ static cmdline_parse_inst_t cmd_config_speed_specific = {
        },
 };
 
+static cmdline_parse_inst_t cmd_config_speed_specific_autoneg = {
+       .f = cmd_config_speed_specific_parsed,
+       .data = &cmd_config_speed_specific_autoneg,
+       .help_str = "port config <port_id> speed "
+               "10|100|1000|2500|5000|10000|25000|40000|50000|"
+               "100000|200000|400000|800000|auto "
+               "duplex half|full|auto autoneg on|off",
+       .tokens = {
+               (void *)&cmd_config_speed_specific_port,
+               (void *)&cmd_config_speed_specific_keyword,
+               (void *)&cmd_config_speed_specific_id,
+               (void *)&cmd_config_speed_specific_item1,
+               (void *)&cmd_config_speed_specific_value1,
+               (void *)&cmd_config_speed_specific_item2,
+               (void *)&cmd_config_speed_specific_value2,
+               (void *)&cmd_config_speed_specific_autoneg_token,
+               (void *)&cmd_config_speed_specific_autoneg_value,
+               NULL,
+       },
+};
+
 static int
 parse_speed_lanes_cfg(portid_t pid, uint32_t lanes)
 {
@@ -14357,7 +14429,9 @@ static cmdline_parse_ctx_t builtin_ctx[] = {
        &cmd_operate_detach_device,
        &cmd_set_port_setup_on,
        &cmd_config_speed_all,
+       &cmd_config_speed_all_autoneg,
        &cmd_config_speed_specific,
+       &cmd_config_speed_specific_autoneg,
        &cmd_config_speed_lanes_all,
        &cmd_config_speed_lanes_specific,
        &cmd_show_speed_lanes,
diff --git a/doc/guides/rel_notes/release_26_11.rst 
b/doc/guides/rel_notes/release_26_11.rst
index 8ca8379cc6..29fccf09e3 100644
--- a/doc/guides/rel_notes/release_26_11.rst
+++ b/doc/guides/rel_notes/release_26_11.rst
@@ -340,6 +340,12 @@ New Features
   Added ``dpdk-validate-bpf`` tool to pre-validate eBPF programs
   for compatibility with the ``lib/bpf`` execution context.
 
+* **Added explicit link autonegotiation control in testpmd.**
+
+  Added an optional ``autoneg on|off`` setting after ``duplex`` in the port 
speed configuration command.
+  For compatibility with older behavior, if unspecified,
+  auto-negotiation is disabled by default for numeric speeds, and enabled for 
"auto" speed selection.
+
 
 Removed Items
 -------------
diff --git a/doc/guides/testpmd_app_ug/testpmd_funcs.rst 
b/doc/guides/testpmd_app_ug/testpmd_funcs.rst
index a967bbef76..6bac4d2763 100644
--- a/doc/guides/testpmd_app_ug/testpmd_funcs.rst
+++ b/doc/guides/testpmd_app_ug/testpmd_funcs.rst
@@ -2167,7 +2167,13 @@ port config - speed
 Set the speed and duplex mode for all ports or a specific port::
 
    testpmd> port config (port_id|all) speed 
(10|100|1000|2500|5000|10000|25000|40000|50000|100000|200000|400000|800000|auto)
 \
-            duplex (half|full|auto)
+            duplex (half|full|auto) [autoneg (on|off)]
+
+With ``autoneg on``, the selected speed is advertised with link 
autonegotiation enabled.
+With ``autoneg off``, link autonegotiation is disabled and the selected speed 
is forced.
+If ``autoneg`` parameter is omitted for a numeric speed, link autonegotiation 
is disabled.
+The ``auto`` speed advertises all supported speeds and enables link 
autonegotiation if ``autoneg`` is omitted.
+NOTE: Combining ``auto`` speed with ``autoneg off`` is an error.
 
 port config - queues/descriptors
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-- 
2.55.0

Reply via email to