[3/3] app/testpmd: support setting lanes

Message ID 20240312075238.3319480-4-huangdengdui@huawei.com (mailing list archive)
State Changes Requested, archived
Delegated to: Ferruh Yigit
Headers
Series support setting lanes |

Checks

Context Check Description
ci/checkpatch success coding style OK
ci/loongarch-compilation success Compilation OK
ci/loongarch-unit-testing fail Unit Testing FAIL
ci/Intel-compilation fail Compilation issues
ci/intel-Testing success Testing PASS
ci/github-robot: build fail github build: failed
ci/intel-Functional success Functional PASS
ci/iol-mellanox-Performance success Performance Testing PASS
ci/iol-intel-Performance success Performance Testing PASS
ci/iol-intel-Functional success Functional Testing PASS
ci/iol-abi-testing warning Testing issues
ci/iol-compile-amd64-testing success Testing PASS
ci/iol-unit-amd64-testing fail Testing issues
ci/iol-sample-apps-testing success Testing PASS
ci/iol-unit-arm64-testing fail Testing issues
ci/iol-compile-arm64-testing success Testing PASS
ci/iol-broadcom-Performance success Performance Testing PASS
ci/iol-broadcom-Functional success Functional Testing PASS

Commit Message

Dengdui Huang March 12, 2024, 7:52 a.m. UTC
  Extended speed command for setting lane number and
Show info print lane number.

Signed-off-by: Dengdui Huang <huangdengdui@huawei.com>
---
 app/test-pmd/cmdline.c                      | 110 +++++++++++---------
 app/test-pmd/config.c                       |  60 +++++++----
 doc/guides/rel_notes/release_24_03.rst      |   1 +
 doc/guides/testpmd_app_ug/testpmd_funcs.rst |   3 +-
 4 files changed, 103 insertions(+), 71 deletions(-)
  

Comments

Damodharam Ammepalli March 15, 2024, 9:47 p.m. UTC | #1
On Tue, Mar 12, 2024 at 12:52 AM Dengdui Huang <huangdengdui@huawei.com> wrote:
>
> Extended speed command for setting lane number and
> Show info print lane number.
>
> Signed-off-by: Dengdui Huang <huangdengdui@huawei.com>
> ---
>  app/test-pmd/cmdline.c                      | 110 +++++++++++---------
>  app/test-pmd/config.c                       |  60 +++++++----
>  doc/guides/rel_notes/release_24_03.rst      |   1 +
>  doc/guides/testpmd_app_ug/testpmd_funcs.rst |   3 +-
>  4 files changed, 103 insertions(+), 71 deletions(-)
>
> diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
> index f521a1fe9e..e66daf4bba 100644
> --- a/app/test-pmd/cmdline.c
> +++ b/app/test-pmd/cmdline.c
> @@ -1356,15 +1356,20 @@ struct cmd_config_speed_all {
>         cmdline_fixed_string_t keyword;
>         cmdline_fixed_string_t all;
>         cmdline_fixed_string_t item1;
> +       cmdline_fixed_string_t lanes_item;
>         cmdline_fixed_string_t item2;
>         cmdline_fixed_string_t value1;
> +       uint8_t lanes_value;
>         cmdline_fixed_string_t value2;
>  };
>
>  static int
> -parse_and_check_speed_duplex(char *speedstr, char *duplexstr, uint32_t *speed)
> +parse_and_check_speed_duplex(char *speedstr, uint8_t lanes, char *duplexstr,
> +                            uint32_t *speed)
>  {
>
We internally implemented a similar feature, without changing the
existing testpmd speed cmd.
Instead of modifying the existing command set  we can have a  separate
cmd for the lanes
configuration similar to FEC configuration. Our internal
implementation looks something like this,
without affecting existing implementations.
testpmd> port stop 0
testpmd> port config 0 speed_lanes 4
testpmd> port config 0 speed 200000 duplex full
testpmd> port start 0
testpmd> show port summary 0
Number of available ports: 2
Port MAC Address       Name         Driver         Status   Link         Lanes
0    14:23:F2:C3:BA:D2 0000:b1:00.0 net_bnxt       up  200 Gbps 4
testpmd>
testpmd> show port info 0

********************* Infos for port 0  *********************
MAC address: 14:23:F2:C3:BA:D2
Device name: 0000:b1:00.0
Driver name: net_bnxt
Firmware-version: 228.9.115.0
Connect to socket: 2
memory allocation on the socket: 2
Link status: up
Link speed: 200 Gbps
Lanes: 4
Link duplex: full-duplex
Autoneg status: Off

> +       uint32_t speed_num;
> +       char *endptr;
>         int duplex;
>
>         if (!strcmp(duplexstr, "half")) {
> @@ -1378,47 +1383,22 @@ parse_and_check_speed_duplex(char *speedstr, char *duplexstr, uint32_t *speed)
>                 return -1;
>         }
>
> -       if (!strcmp(speedstr, "10")) {
> -               *speed = (duplex == RTE_ETH_LINK_HALF_DUPLEX) ?
> -                               RTE_ETH_LINK_SPEED_10M_HD : RTE_ETH_LINK_SPEED_10M;
> -       } else if (!strcmp(speedstr, "100")) {
> -               *speed = (duplex == RTE_ETH_LINK_HALF_DUPLEX) ?
> -                               RTE_ETH_LINK_SPEED_100M_HD : RTE_ETH_LINK_SPEED_100M;
> -       } else {
> -               if (duplex != RTE_ETH_LINK_FULL_DUPLEX) {
> -                       fprintf(stderr, "Invalid speed/duplex parameters\n");
> -                       return -1;
> -               }
> -               if (!strcmp(speedstr, "1000")) {
> -                       *speed = RTE_ETH_LINK_SPEED_1G;
> -               } else if (!strcmp(speedstr, "2500")) {
> -                       *speed = RTE_ETH_LINK_SPEED_2_5G;
> -               } else if (!strcmp(speedstr, "5000")) {
> -                       *speed = RTE_ETH_LINK_SPEED_5G;
> -               } else if (!strcmp(speedstr, "10000")) {
> -                       *speed = RTE_ETH_LINK_SPEED_10G;
> -               } else if (!strcmp(speedstr, "25000")) {
> -                       *speed = RTE_ETH_LINK_SPEED_25G;
> -               } else if (!strcmp(speedstr, "40000")) {
> -                       *speed = RTE_ETH_LINK_SPEED_40G;
> -               } else if (!strcmp(speedstr, "50000")) {
> -                       *speed = RTE_ETH_LINK_SPEED_50G;
> -               } else if (!strcmp(speedstr, "100000")) {
> -                       *speed = RTE_ETH_LINK_SPEED_100G;
> -               } else if (!strcmp(speedstr, "200000")) {
> -                       *speed = RTE_ETH_LINK_SPEED_200G;
> -               } else if (!strcmp(speedstr, "400000")) {
> -                       *speed = RTE_ETH_LINK_SPEED_400G;
> -               } else if (!strcmp(speedstr, "auto")) {
> -                       *speed = RTE_ETH_LINK_SPEED_AUTONEG;
> -               } else {
> -                       fprintf(stderr, "Unknown speed parameter\n");
> -                       return -1;
> -               }
> +       if (!strcmp(speedstr, "auto")) {
> +               *speed = RTE_ETH_LINK_SPEED_AUTONEG;
> +               return 0;
>         }
>
> -       if (*speed != RTE_ETH_LINK_SPEED_AUTONEG)
> -               *speed |= RTE_ETH_LINK_SPEED_FIXED;
> +       speed_num = strtol(speedstr, &endptr, 10);
> +       if (*endptr != '\0') {
> +               fprintf(stderr, "Unknown speed parameter\n");
> +               return -1;
> +       }
> +
> +       *speed = rte_eth_speed_bitflag(speed_num, lanes, duplex);
> +       if (*speed == 0) {
> +               fprintf(stderr, "param error\n");
> +               return -1;
> +       }
>
>         return 0;
>  }
> @@ -1429,19 +1409,27 @@ cmd_config_speed_all_parsed(void *parsed_result,
>                         __rte_unused void *data)
>  {
>         struct cmd_config_speed_all *res = parsed_result;
> +       struct rte_eth_dev_info dev_info;
>         uint32_t link_speed;
>         portid_t pid;
> +       int ret;
>
>         if (!all_ports_stopped()) {
>                 fprintf(stderr, "Please stop all ports first\n");
>                 return;
>         }
>
> -       if (parse_and_check_speed_duplex(res->value1, res->value2,
> -                       &link_speed) < 0)
> +       if (parse_and_check_speed_duplex(res->value1, res->lanes_value,
> +                                        res->value2, &link_speed) < 0)
>                 return;
>
>         RTE_ETH_FOREACH_DEV(pid) {
> +               ret = eth_dev_info_get_print_err(pid, &dev_info);
> +               if (ret != 0)
> +                       return;
> +               if ((dev_info.dev_capa & RTE_ETH_DEV_CAPA_SETTING_LANES) == 0)
> +                       fprintf(stderr, "The setting lane may not take effect because "
> +                                       "the port (%u) does not support it\n", pid);
>                 ports[pid].dev_conf.link_speeds = link_speed;
>         }
>
> @@ -1460,6 +1448,11 @@ static cmdline_parse_token_string_t cmd_config_speed_all_item1 =
>  static cmdline_parse_token_string_t cmd_config_speed_all_value1 =
>         TOKEN_STRING_INITIALIZER(struct cmd_config_speed_all, value1,
>                                 "10#100#1000#2500#5000#10000#25000#40000#50000#100000#200000#400000#auto");
> +static cmdline_parse_token_string_t cmd_config_speed_all_lanes_item =
> +       TOKEN_STRING_INITIALIZER(struct cmd_config_speed_all, lanes_item, "lanes");
> +static cmdline_parse_token_num_t cmd_config_speed_all_lanes_value =
> +       TOKEN_NUM_INITIALIZER(struct cmd_config_speed_all, lanes_value,
> +                             RTE_UINT8);
>  static cmdline_parse_token_string_t cmd_config_speed_all_item2 =
>         TOKEN_STRING_INITIALIZER(struct cmd_config_speed_all, item2, "duplex");
>  static cmdline_parse_token_string_t cmd_config_speed_all_value2 =
> @@ -1470,14 +1463,16 @@ static cmdline_parse_inst_t cmd_config_speed_all = {
>         .f = cmd_config_speed_all_parsed,
>         .data = NULL,
>         .help_str = "port config all speed "
> -               "10|100|1000|2500|5000|10000|25000|40000|50000|100000|200000|400000|auto duplex "
> -                                                       "half|full|auto",
> +               "10|100|1000|2500|5000|10000|25000|40000|50000|100000|200000|400000|auto"
> +               " lanes 1|2|4|8 duplex half|full|auto",
>         .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_lanes_item,
> +               (void *)&cmd_config_speed_all_lanes_value,
>                 (void *)&cmd_config_speed_all_item2,
>                 (void *)&cmd_config_speed_all_value2,
>                 NULL,
> @@ -1490,8 +1485,10 @@ struct cmd_config_speed_specific {
>         cmdline_fixed_string_t keyword;
>         portid_t id;
>         cmdline_fixed_string_t item1;
> +       cmdline_fixed_string_t lanes_item;
>         cmdline_fixed_string_t item2;
>         cmdline_fixed_string_t value1;
> +       uint8_t lanes_value;
>         cmdline_fixed_string_t value2;
>  };
>
> @@ -1501,7 +1498,9 @@ cmd_config_speed_specific_parsed(void *parsed_result,
>                                 __rte_unused void *data)
>  {
>         struct cmd_config_speed_specific *res = parsed_result;
> +       struct rte_eth_dev_info dev_info;
>         uint32_t link_speed;
> +       int ret;
>
>         if (port_id_is_invalid(res->id, ENABLED_WARN))
>                 return;
> @@ -1511,8 +1510,15 @@ cmd_config_speed_specific_parsed(void *parsed_result,
>                 return;
>         }
>
> -       if (parse_and_check_speed_duplex(res->value1, res->value2,
> -                       &link_speed) < 0)
> +       ret = eth_dev_info_get_print_err(res->id, &dev_info);
> +       if (ret != 0)
> +               return;
> +       if ((dev_info.dev_capa & RTE_ETH_DEV_CAPA_SETTING_LANES) == 0)
> +               fprintf(stderr, "The setting lane may not take effect because "
> +                               "the port (%d) does not support it\n", res->id);
> +
> +       if (parse_and_check_speed_duplex(res->value1, res->lanes_value,
> +                                        res->value2, &link_speed) < 0)
>                 return;
>
>         ports[res->id].dev_conf.link_speeds = link_speed;
> @@ -1535,6 +1541,12 @@ static cmdline_parse_token_string_t cmd_config_speed_specific_item1 =
>  static cmdline_parse_token_string_t cmd_config_speed_specific_value1 =
>         TOKEN_STRING_INITIALIZER(struct cmd_config_speed_specific, value1,
>                                 "10#100#1000#2500#5000#10000#25000#40000#50000#100000#200000#400000#auto");
> +static cmdline_parse_token_string_t cmd_config_speed_specific_lanes_item =
> +       TOKEN_STRING_INITIALIZER(struct cmd_config_speed_specific, lanes_item,
> +                                                               "lanes");
> +static cmdline_parse_token_num_t cmd_config_speed_specific_lanes_value =
> +       TOKEN_NUM_INITIALIZER(struct cmd_config_speed_specific, lanes_value,
> +                             RTE_UINT8);
>  static cmdline_parse_token_string_t cmd_config_speed_specific_item2 =
>         TOKEN_STRING_INITIALIZER(struct cmd_config_speed_specific, item2,
>                                                                 "duplex");
> @@ -1546,14 +1558,16 @@ static cmdline_parse_inst_t cmd_config_speed_specific = {
>         .f = cmd_config_speed_specific_parsed,
>         .data = NULL,
>         .help_str = "port config <port_id> speed "
> -               "10|100|1000|2500|5000|10000|25000|40000|50000|100000|200000|400000|auto duplex "
> -                                                       "half|full|auto",
> +               "10|100|1000|2500|5000|10000|25000|40000|50000|100000|200000|400000|auto"
> +               " lanes 1|2|4|8 duplex half|full|auto",
>         .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_lanes_item,
> +               (void *)&cmd_config_speed_specific_lanes_value,
>                 (void *)&cmd_config_speed_specific_item2,
>                 (void *)&cmd_config_speed_specific_value2,
>                 NULL,
> diff --git a/app/test-pmd/config.c b/app/test-pmd/config.c
> index 968d2164ab..c104327878 100644
> --- a/app/test-pmd/config.c
> +++ b/app/test-pmd/config.c
> @@ -587,39 +587,51 @@ device_infos_display_speeds(uint32_t speed_capa)
>         if (speed_capa == RTE_ETH_LINK_SPEED_AUTONEG)
>                 printf(" Autonegotiate (all speeds)");
>         if (speed_capa & RTE_ETH_LINK_SPEED_FIXED)
> -               printf(" Disable autonegotiate (fixed speed)  ");
> +               printf(" Disable autonegotiate (fixed speed) /");
>         if (speed_capa & RTE_ETH_LINK_SPEED_10M_HD)
> -               printf(" 10 Mbps half-duplex  ");
> +               printf(" 10Mbps_1lane_half-duplex /");
>         if (speed_capa & RTE_ETH_LINK_SPEED_10M)
> -               printf(" 10 Mbps full-duplex  ");
> +               printf(" 10Mbps_1lane_full-duplex /");
>         if (speed_capa & RTE_ETH_LINK_SPEED_100M_HD)
> -               printf(" 100 Mbps half-duplex  ");
> +               printf(" 100Mbps_lane_half-duplex /");
>         if (speed_capa & RTE_ETH_LINK_SPEED_100M)
> -               printf(" 100 Mbps full-duplex  ");
> +               printf(" 100Mbps_1lane_full-duplex /");
>         if (speed_capa & RTE_ETH_LINK_SPEED_1G)
> -               printf(" 1 Gbps  ");
> +               printf(" 1Gbps_1lane_full-duplex /");
>         if (speed_capa & RTE_ETH_LINK_SPEED_2_5G)
> -               printf(" 2.5 Gbps  ");
> +               printf(" 2.5Gbps_1lane_full-duplex /");
>         if (speed_capa & RTE_ETH_LINK_SPEED_5G)
> -               printf(" 5 Gbps  ");
> +               printf(" 5Gbps_1lane_full-duplex /");
>         if (speed_capa & RTE_ETH_LINK_SPEED_10G)
> -               printf(" 10 Gbps  ");
> -       if (speed_capa & RTE_ETH_LINK_SPEED_20G)
> -               printf(" 20 Gbps  ");
> +               printf(" 10Gbps_1lane_full-duplex /");
> +       if (speed_capa & RTE_ETH_LINK_SPEED_10G_4LANES)
> +               printf(" 10Gbps_4lane_full-duplex /");
> +       if (speed_capa & RTE_ETH_LINK_SPEED_20G_2LANES)
> +               printf(" 20Gbps_2lane_full-duplex /");
>         if (speed_capa & RTE_ETH_LINK_SPEED_25G)
> -               printf(" 25 Gbps  ");
> -       if (speed_capa & RTE_ETH_LINK_SPEED_40G)
> -               printf(" 40 Gbps  ");
> +               printf(" 25Gbps_1lane_full-duplex /");
> +       if (speed_capa & RTE_ETH_LINK_SPEED_40G_4LANES)
> +               printf(" 40Gbps_4lane_full-duplex /");
>         if (speed_capa & RTE_ETH_LINK_SPEED_50G)
> -               printf(" 50 Gbps  ");
> -       if (speed_capa & RTE_ETH_LINK_SPEED_56G)
> -               printf(" 56 Gbps  ");
> +               printf(" 50Gbps_1lane_full-duplex /");
> +       if (speed_capa & RTE_ETH_LINK_SPEED_50G_2LANES)
> +               printf(" 50Gbps_2lane_full-duplex /");
> +       if (speed_capa & RTE_ETH_LINK_SPEED_56G_4LANES)
> +               printf(" 56Gbps_4lane_full-duplex /");
>         if (speed_capa & RTE_ETH_LINK_SPEED_100G)
> -               printf(" 100 Gbps  ");
> -       if (speed_capa & RTE_ETH_LINK_SPEED_200G)
> -               printf(" 200 Gbps  ");
> -       if (speed_capa & RTE_ETH_LINK_SPEED_400G)
> -               printf(" 400 Gbps  ");
> +               printf(" 100Gbps_1lane_full-duplex /");
> +       if (speed_capa & RTE_ETH_LINK_SPEED_100G_2LANES)
> +               printf(" 100Gbps_2lane_full-duplex /");
> +       if (speed_capa & RTE_ETH_LINK_SPEED_100G_4LANES)
> +               printf(" 100Gbps_4lane_full-duplex /");
> +       if (speed_capa & RTE_ETH_LINK_SPEED_200G_4LANES)
> +               printf(" 200Gbps_4lane_full-duplex /");
> +       if (speed_capa & RTE_ETH_LINK_SPEED_200G_2LANES)
> +               printf(" 200Gbps_2lane_full-duplex /");
> +       if (speed_capa & RTE_ETH_LINK_SPEED_400G_4LANES)
> +               printf(" 400Gbps_4lane_full-duplex /");
> +       if (speed_capa & RTE_ETH_LINK_SPEED_400G_8LANES)
> +               printf(" 400Gbps_8lane_full-duplex /");
>  }
>
>  void
> @@ -828,6 +840,10 @@ port_infos_display(portid_t port_id)
>
>         printf("\nLink status: %s\n", (link.link_status) ? ("up") : ("down"));
>         printf("Link speed: %s\n", rte_eth_link_speed_to_str(link.link_speed));
> +       if (link.link_lanes == 0)
> +               printf("Link lanes: unknown\n");
> +       else
> +               printf("Link lanes: %u\n", link.link_lanes);
>         printf("Link duplex: %s\n", (link.link_duplex == RTE_ETH_LINK_FULL_DUPLEX) ?
>                ("full-duplex") : ("half-duplex"));
>         printf("Autoneg status: %s\n", (link.link_autoneg == RTE_ETH_LINK_AUTONEG) ?
> diff --git a/doc/guides/rel_notes/release_24_03.rst b/doc/guides/rel_notes/release_24_03.rst
> index c17334ac25..46aceeee93 100644
> --- a/doc/guides/rel_notes/release_24_03.rst
> +++ b/doc/guides/rel_notes/release_24_03.rst
> @@ -79,6 +79,7 @@ New Features
>  * **Support setting lanes for ethdev.**
>    * Support setting lanes by extended ``RTE_ETH_LINK_SPEED_*``.
>    * Added function to convert bitmap flag to the struct of link speed info.
> +  ``rte_eth_speed_capa_to_info()``
>
>  * **Added hash calculation of an encapsulated packet as done by the HW.**
>
> diff --git a/doc/guides/testpmd_app_ug/testpmd_funcs.rst b/doc/guides/testpmd_app_ug/testpmd_funcs.rst
> index 2fbf9220d8..087f7fe853 100644
> --- a/doc/guides/testpmd_app_ug/testpmd_funcs.rst
> +++ b/doc/guides/testpmd_app_ug/testpmd_funcs.rst
> @@ -190,6 +190,7 @@ For example:
>     memory allocation on the socket: 0
>     Link status: up
>     Link speed: 40000 Mbps
> +   Link lanes: 4
>     Link duplex: full-duplex
>     Promiscuous mode: enabled
>     Allmulticast mode: disabled
> @@ -2065,7 +2066,7 @@ 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|auto) \
> -            duplex (half|full|auto)
> +            lanes 1|2|4|8 duplex (half|full|auto)
>
>  port config - queues/descriptors
>  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> --
> 2.33.0
>
  
Dengdui Huang March 19, 2024, 2:38 a.m. UTC | #2
On 2024/3/16 5:47, Damodharam Ammepalli wrote:
> On Tue, Mar 12, 2024 at 12:52 AM Dengdui Huang <huangdengdui@huawei.com> wrote:
>>
>> Extended speed command for setting lane number and
>> Show info print lane number.
>>
>> Signed-off-by: Dengdui Huang <huangdengdui@huawei.com>
>> ---
>>  app/test-pmd/cmdline.c                      | 110 +++++++++++---------
>>  app/test-pmd/config.c                       |  60 +++++++----
>>  doc/guides/rel_notes/release_24_03.rst      |   1 +
>>  doc/guides/testpmd_app_ug/testpmd_funcs.rst |   3 +-
>>  4 files changed, 103 insertions(+), 71 deletions(-)
>>
>> diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
>> index f521a1fe9e..e66daf4bba 100644
>> --- a/app/test-pmd/cmdline.c
>> +++ b/app/test-pmd/cmdline.c
>> @@ -1356,15 +1356,20 @@ struct cmd_config_speed_all {
>>         cmdline_fixed_string_t keyword;
>>         cmdline_fixed_string_t all;
>>         cmdline_fixed_string_t item1;
>> +       cmdline_fixed_string_t lanes_item;
>>         cmdline_fixed_string_t item2;
>>         cmdline_fixed_string_t value1;
>> +       uint8_t lanes_value;
>>         cmdline_fixed_string_t value2;
>>  };
>>
>>  static int
>> -parse_and_check_speed_duplex(char *speedstr, char *duplexstr, uint32_t *speed)
>> +parse_and_check_speed_duplex(char *speedstr, uint8_t lanes, char *duplexstr,
>> +                            uint32_t *speed)
>>  {
>>
> We internally implemented a similar feature, without changing the
> existing testpmd speed cmd.
> Instead of modifying the existing command set  we can have a  separate
> cmd for the lanes
> configuration similar to FEC configuration. Our internal
> implementation looks something like this,
> without affecting existing implementations.
> testpmd> port stop 0
> testpmd> port config 0 speed_lanes 4

Hi, Damodharam,
Thanks for your review.

I think the lanes should be configured with speed and duplex,
they will eventually map to Link speed capabilities(RTE_ETH_LINK_SPEED_*).

Would it be better to add the following new command?

testpmd> port config 0 speed 200000 lanes 4 duplex full

It can be used when the driver supports setting lanes;
It cannot be used when the driver does not support the setting lanes.

what do you think?

> testpmd> port config 0 speed 200000 duplex full
> testpmd> port start 0
> testpmd> show port summary 0
> Number of available ports: 2
> Port MAC Address       Name         Driver         Status   Link         Lanes
> 0    14:23:F2:C3:BA:D2 0000:b1:00.0 net_bnxt       up  200 Gbps 4

The summary command adds print of the number of lanes.
I will implement this in the next version.

> testpmd>
> testpmd> show port info 0
> 
> ********************* Infos for port 0  *********************
> MAC address: 14:23:F2:C3:BA:D2
> Device name: 0000:b1:00.0
> Driver name: net_bnxt
> Firmware-version: 228.9.115.0
> Connect to socket: 2
> memory allocation on the socket: 2
> Link status: up
> Link speed: 200 Gbps
> Lanes: 4
> Link duplex: full-duplex
> Autoneg status: Off
> 
>> +       uint32_t speed_num;
>> +       char *endptr;
>>         int duplex;
>>
>>         if (!strcmp(duplexstr, "half")) {
>> @@ -1378,47 +1383,22 @@ parse_and_check_speed_duplex(char *speedstr, char *duplexstr, uint32_t *speed)
>>                 return -1;
>>         }
>>
>> -       if (!strcmp(speedstr, "10")) {
>> -               *speed = (duplex == RTE_ETH_LINK_HALF_DUPLEX) ?
>> -                               RTE_ETH_LINK_SPEED_10M_HD : RTE_ETH_LINK_SPEED_10M;
>> -       } else if (!strcmp(speedstr, "100")) {
>> -               *speed = (duplex == RTE_ETH_LINK_HALF_DUPLEX) ?
>> -                               RTE_ETH_LINK_SPEED_100M_HD : RTE_ETH_LINK_SPEED_100M;
>> -       } else {
>> -               if (duplex != RTE_ETH_LINK_FULL_DUPLEX) {
>> -                       fprintf(stderr, "Invalid speed/duplex parameters\n");
>> -                       return -1;
>> -               }
>> -               if (!strcmp(speedstr, "1000")) {
>> -                       *speed = RTE_ETH_LINK_SPEED_1G;
>> -               } else if (!strcmp(speedstr, "2500")) {
>> -                       *speed = RTE_ETH_LINK_SPEED_2_5G;
>> -               } else if (!strcmp(speedstr, "5000")) {
>> -                       *speed = RTE_ETH_LINK_SPEED_5G;
>> -               } else if (!strcmp(speedstr, "10000")) {
>> -                       *speed = RTE_ETH_LINK_SPEED_10G;
>> -               } else if (!strcmp(speedstr, "25000")) {
>> -                       *speed = RTE_ETH_LINK_SPEED_25G;
>> -               } else if (!strcmp(speedstr, "40000")) {
>> -                       *speed = RTE_ETH_LINK_SPEED_40G;
>> -               } else if (!strcmp(speedstr, "50000")) {
>> -                       *speed = RTE_ETH_LINK_SPEED_50G;
>> -               } else if (!strcmp(speedstr, "100000")) {
>> -                       *speed = RTE_ETH_LINK_SPEED_100G;
>> -               } else if (!strcmp(speedstr, "200000")) {
>> -                       *speed = RTE_ETH_LINK_SPEED_200G;
>> -               } else if (!strcmp(speedstr, "400000")) {
>> -                       *speed = RTE_ETH_LINK_SPEED_400G;
>> -               } else if (!strcmp(speedstr, "auto")) {
>> -                       *speed = RTE_ETH_LINK_SPEED_AUTONEG;
>> -               } else {
>> -                       fprintf(stderr, "Unknown speed parameter\n");
>> -                       return -1;
>> -               }
>> +       if (!strcmp(speedstr, "auto")) {
>> +               *speed = RTE_ETH_LINK_SPEED_AUTONEG;
>> +               return 0;
>>         }
>>
>> -       if (*speed != RTE_ETH_LINK_SPEED_AUTONEG)
>> -               *speed |= RTE_ETH_LINK_SPEED_FIXED;
>> +       speed_num = strtol(speedstr, &endptr, 10);
>> +       if (*endptr != '\0') {
>> +               fprintf(stderr, "Unknown speed parameter\n");
>> +               return -1;
>> +       }
>> +
>> +       *speed = rte_eth_speed_bitflag(speed_num, lanes, duplex);
>> +       if (*speed == 0) {
>> +               fprintf(stderr, "param error\n");
>> +               return -1;
>> +       }
>>
>>         return 0;
>>  }
>> @@ -1429,19 +1409,27 @@ cmd_config_speed_all_parsed(void *parsed_result,
>>                         __rte_unused void *data)
>>  {
>>         struct cmd_config_speed_all *res = parsed_result;
>> +       struct rte_eth_dev_info dev_info;
>>         uint32_t link_speed;
>>         portid_t pid;
>> +       int ret;
>>
>>         if (!all_ports_stopped()) {
>>                 fprintf(stderr, "Please stop all ports first\n");
>>                 return;
>>         }
>>
>> -       if (parse_and_check_speed_duplex(res->value1, res->value2,
>> -                       &link_speed) < 0)
>> +       if (parse_and_check_speed_duplex(res->value1, res->lanes_value,
>> +                                        res->value2, &link_speed) < 0)
>>                 return;
>>
>>         RTE_ETH_FOREACH_DEV(pid) {
>> +               ret = eth_dev_info_get_print_err(pid, &dev_info);
>> +               if (ret != 0)
>> +                       return;
>> +               if ((dev_info.dev_capa & RTE_ETH_DEV_CAPA_SETTING_LANES) == 0)
>> +                       fprintf(stderr, "The setting lane may not take effect because "
>> +                                       "the port (%u) does not support it\n", pid);
>>                 ports[pid].dev_conf.link_speeds = link_speed;
>>         }
>>
>> @@ -1460,6 +1448,11 @@ static cmdline_parse_token_string_t cmd_config_speed_all_item1 =
>>  static cmdline_parse_token_string_t cmd_config_speed_all_value1 =
>>         TOKEN_STRING_INITIALIZER(struct cmd_config_speed_all, value1,
>>                                 "10#100#1000#2500#5000#10000#25000#40000#50000#100000#200000#400000#auto");
>> +static cmdline_parse_token_string_t cmd_config_speed_all_lanes_item =
>> +       TOKEN_STRING_INITIALIZER(struct cmd_config_speed_all, lanes_item, "lanes");
>> +static cmdline_parse_token_num_t cmd_config_speed_all_lanes_value =
>> +       TOKEN_NUM_INITIALIZER(struct cmd_config_speed_all, lanes_value,
>> +                             RTE_UINT8);
>>  static cmdline_parse_token_string_t cmd_config_speed_all_item2 =
>>         TOKEN_STRING_INITIALIZER(struct cmd_config_speed_all, item2, "duplex");
>>  static cmdline_parse_token_string_t cmd_config_speed_all_value2 =
>> @@ -1470,14 +1463,16 @@ static cmdline_parse_inst_t cmd_config_speed_all = {
>>         .f = cmd_config_speed_all_parsed,
>>         .data = NULL,
>>         .help_str = "port config all speed "
>> -               "10|100|1000|2500|5000|10000|25000|40000|50000|100000|200000|400000|auto duplex "
>> -                                                       "half|full|auto",
>> +               "10|100|1000|2500|5000|10000|25000|40000|50000|100000|200000|400000|auto"
>> +               " lanes 1|2|4|8 duplex half|full|auto",
>>         .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_lanes_item,
>> +               (void *)&cmd_config_speed_all_lanes_value,
>>                 (void *)&cmd_config_speed_all_item2,
>>                 (void *)&cmd_config_speed_all_value2,
>>                 NULL,
>> @@ -1490,8 +1485,10 @@ struct cmd_config_speed_specific {
>>         cmdline_fixed_string_t keyword;
>>         portid_t id;
>>         cmdline_fixed_string_t item1;
>> +       cmdline_fixed_string_t lanes_item;
>>         cmdline_fixed_string_t item2;
>>         cmdline_fixed_string_t value1;
>> +       uint8_t lanes_value;
>>         cmdline_fixed_string_t value2;
>>  };
>>
>> @@ -1501,7 +1498,9 @@ cmd_config_speed_specific_parsed(void *parsed_result,
>>                                 __rte_unused void *data)
>>  {
>>         struct cmd_config_speed_specific *res = parsed_result;
>> +       struct rte_eth_dev_info dev_info;
>>         uint32_t link_speed;
>> +       int ret;
>>
>>         if (port_id_is_invalid(res->id, ENABLED_WARN))
>>                 return;
>> @@ -1511,8 +1510,15 @@ cmd_config_speed_specific_parsed(void *parsed_result,
>>                 return;
>>         }
>>
>> -       if (parse_and_check_speed_duplex(res->value1, res->value2,
>> -                       &link_speed) < 0)
>> +       ret = eth_dev_info_get_print_err(res->id, &dev_info);
>> +       if (ret != 0)
>> +               return;
>> +       if ((dev_info.dev_capa & RTE_ETH_DEV_CAPA_SETTING_LANES) == 0)
>> +               fprintf(stderr, "The setting lane may not take effect because "
>> +                               "the port (%d) does not support it\n", res->id);
>> +
>> +       if (parse_and_check_speed_duplex(res->value1, res->lanes_value,
>> +                                        res->value2, &link_speed) < 0)
>>                 return;
>>
>>         ports[res->id].dev_conf.link_speeds = link_speed;
>> @@ -1535,6 +1541,12 @@ static cmdline_parse_token_string_t cmd_config_speed_specific_item1 =
>>  static cmdline_parse_token_string_t cmd_config_speed_specific_value1 =
>>         TOKEN_STRING_INITIALIZER(struct cmd_config_speed_specific, value1,
>>                                 "10#100#1000#2500#5000#10000#25000#40000#50000#100000#200000#400000#auto");
>> +static cmdline_parse_token_string_t cmd_config_speed_specific_lanes_item =
>> +       TOKEN_STRING_INITIALIZER(struct cmd_config_speed_specific, lanes_item,
>> +                                                               "lanes");
>> +static cmdline_parse_token_num_t cmd_config_speed_specific_lanes_value =
>> +       TOKEN_NUM_INITIALIZER(struct cmd_config_speed_specific, lanes_value,
>> +                             RTE_UINT8);
>>  static cmdline_parse_token_string_t cmd_config_speed_specific_item2 =
>>         TOKEN_STRING_INITIALIZER(struct cmd_config_speed_specific, item2,
>>                                                                 "duplex");
>> @@ -1546,14 +1558,16 @@ static cmdline_parse_inst_t cmd_config_speed_specific = {
>>         .f = cmd_config_speed_specific_parsed,
>>         .data = NULL,
>>         .help_str = "port config <port_id> speed "
>> -               "10|100|1000|2500|5000|10000|25000|40000|50000|100000|200000|400000|auto duplex "
>> -                                                       "half|full|auto",
>> +               "10|100|1000|2500|5000|10000|25000|40000|50000|100000|200000|400000|auto"
>> +               " lanes 1|2|4|8 duplex half|full|auto",
>>         .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_lanes_item,
>> +               (void *)&cmd_config_speed_specific_lanes_value,
>>                 (void *)&cmd_config_speed_specific_item2,
>>                 (void *)&cmd_config_speed_specific_value2,
>>                 NULL,
>> diff --git a/app/test-pmd/config.c b/app/test-pmd/config.c
>> index 968d2164ab..c104327878 100644
>> --- a/app/test-pmd/config.c
>> +++ b/app/test-pmd/config.c
>> @@ -587,39 +587,51 @@ device_infos_display_speeds(uint32_t speed_capa)
>>         if (speed_capa == RTE_ETH_LINK_SPEED_AUTONEG)
>>                 printf(" Autonegotiate (all speeds)");
>>         if (speed_capa & RTE_ETH_LINK_SPEED_FIXED)
>> -               printf(" Disable autonegotiate (fixed speed)  ");
>> +               printf(" Disable autonegotiate (fixed speed) /");
>>         if (speed_capa & RTE_ETH_LINK_SPEED_10M_HD)
>> -               printf(" 10 Mbps half-duplex  ");
>> +               printf(" 10Mbps_1lane_half-duplex /");
>>         if (speed_capa & RTE_ETH_LINK_SPEED_10M)
>> -               printf(" 10 Mbps full-duplex  ");
>> +               printf(" 10Mbps_1lane_full-duplex /");
>>         if (speed_capa & RTE_ETH_LINK_SPEED_100M_HD)
>> -               printf(" 100 Mbps half-duplex  ");
>> +               printf(" 100Mbps_lane_half-duplex /");
>>         if (speed_capa & RTE_ETH_LINK_SPEED_100M)
>> -               printf(" 100 Mbps full-duplex  ");
>> +               printf(" 100Mbps_1lane_full-duplex /");
>>         if (speed_capa & RTE_ETH_LINK_SPEED_1G)
>> -               printf(" 1 Gbps  ");
>> +               printf(" 1Gbps_1lane_full-duplex /");
>>         if (speed_capa & RTE_ETH_LINK_SPEED_2_5G)
>> -               printf(" 2.5 Gbps  ");
>> +               printf(" 2.5Gbps_1lane_full-duplex /");
>>         if (speed_capa & RTE_ETH_LINK_SPEED_5G)
>> -               printf(" 5 Gbps  ");
>> +               printf(" 5Gbps_1lane_full-duplex /");
>>         if (speed_capa & RTE_ETH_LINK_SPEED_10G)
>> -               printf(" 10 Gbps  ");
>> -       if (speed_capa & RTE_ETH_LINK_SPEED_20G)
>> -               printf(" 20 Gbps  ");
>> +               printf(" 10Gbps_1lane_full-duplex /");
>> +       if (speed_capa & RTE_ETH_LINK_SPEED_10G_4LANES)
>> +               printf(" 10Gbps_4lane_full-duplex /");
>> +       if (speed_capa & RTE_ETH_LINK_SPEED_20G_2LANES)
>> +               printf(" 20Gbps_2lane_full-duplex /");
>>         if (speed_capa & RTE_ETH_LINK_SPEED_25G)
>> -               printf(" 25 Gbps  ");
>> -       if (speed_capa & RTE_ETH_LINK_SPEED_40G)
>> -               printf(" 40 Gbps  ");
>> +               printf(" 25Gbps_1lane_full-duplex /");
>> +       if (speed_capa & RTE_ETH_LINK_SPEED_40G_4LANES)
>> +               printf(" 40Gbps_4lane_full-duplex /");
>>         if (speed_capa & RTE_ETH_LINK_SPEED_50G)
>> -               printf(" 50 Gbps  ");
>> -       if (speed_capa & RTE_ETH_LINK_SPEED_56G)
>> -               printf(" 56 Gbps  ");
>> +               printf(" 50Gbps_1lane_full-duplex /");
>> +       if (speed_capa & RTE_ETH_LINK_SPEED_50G_2LANES)
>> +               printf(" 50Gbps_2lane_full-duplex /");
>> +       if (speed_capa & RTE_ETH_LINK_SPEED_56G_4LANES)
>> +               printf(" 56Gbps_4lane_full-duplex /");
>>         if (speed_capa & RTE_ETH_LINK_SPEED_100G)
>> -               printf(" 100 Gbps  ");
>> -       if (speed_capa & RTE_ETH_LINK_SPEED_200G)
>> -               printf(" 200 Gbps  ");
>> -       if (speed_capa & RTE_ETH_LINK_SPEED_400G)
>> -               printf(" 400 Gbps  ");
>> +               printf(" 100Gbps_1lane_full-duplex /");
>> +       if (speed_capa & RTE_ETH_LINK_SPEED_100G_2LANES)
>> +               printf(" 100Gbps_2lane_full-duplex /");
>> +       if (speed_capa & RTE_ETH_LINK_SPEED_100G_4LANES)
>> +               printf(" 100Gbps_4lane_full-duplex /");
>> +       if (speed_capa & RTE_ETH_LINK_SPEED_200G_4LANES)
>> +               printf(" 200Gbps_4lane_full-duplex /");
>> +       if (speed_capa & RTE_ETH_LINK_SPEED_200G_2LANES)
>> +               printf(" 200Gbps_2lane_full-duplex /");
>> +       if (speed_capa & RTE_ETH_LINK_SPEED_400G_4LANES)
>> +               printf(" 400Gbps_4lane_full-duplex /");
>> +       if (speed_capa & RTE_ETH_LINK_SPEED_400G_8LANES)
>> +               printf(" 400Gbps_8lane_full-duplex /");
>>  }
>>
>>  void
>> @@ -828,6 +840,10 @@ port_infos_display(portid_t port_id)
>>
>>         printf("\nLink status: %s\n", (link.link_status) ? ("up") : ("down"));
>>         printf("Link speed: %s\n", rte_eth_link_speed_to_str(link.link_speed));
>> +       if (link.link_lanes == 0)
>> +               printf("Link lanes: unknown\n");
>> +       else
>> +               printf("Link lanes: %u\n", link.link_lanes);
>>         printf("Link duplex: %s\n", (link.link_duplex == RTE_ETH_LINK_FULL_DUPLEX) ?
>>                ("full-duplex") : ("half-duplex"));
>>         printf("Autoneg status: %s\n", (link.link_autoneg == RTE_ETH_LINK_AUTONEG) ?
>> diff --git a/doc/guides/rel_notes/release_24_03.rst b/doc/guides/rel_notes/release_24_03.rst
>> index c17334ac25..46aceeee93 100644
>> --- a/doc/guides/rel_notes/release_24_03.rst
>> +++ b/doc/guides/rel_notes/release_24_03.rst
>> @@ -79,6 +79,7 @@ New Features
>>  * **Support setting lanes for ethdev.**
>>    * Support setting lanes by extended ``RTE_ETH_LINK_SPEED_*``.
>>    * Added function to convert bitmap flag to the struct of link speed info.
>> +  ``rte_eth_speed_capa_to_info()``
>>
>>  * **Added hash calculation of an encapsulated packet as done by the HW.**
>>
>> diff --git a/doc/guides/testpmd_app_ug/testpmd_funcs.rst b/doc/guides/testpmd_app_ug/testpmd_funcs.rst
>> index 2fbf9220d8..087f7fe853 100644
>> --- a/doc/guides/testpmd_app_ug/testpmd_funcs.rst
>> +++ b/doc/guides/testpmd_app_ug/testpmd_funcs.rst
>> @@ -190,6 +190,7 @@ For example:
>>     memory allocation on the socket: 0
>>     Link status: up
>>     Link speed: 40000 Mbps
>> +   Link lanes: 4
>>     Link duplex: full-duplex
>>     Promiscuous mode: enabled
>>     Allmulticast mode: disabled
>> @@ -2065,7 +2066,7 @@ 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|auto) \
>> -            duplex (half|full|auto)
>> +            lanes 1|2|4|8 duplex (half|full|auto)
>>
>>  port config - queues/descriptors
>>  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>> --
>> 2.33.0
>>
>
  
Ferruh Yigit April 4, 2024, 1:58 p.m. UTC | #3
On 3/22/2024 7:09 AM, Dengdui Huang wrote:
> At the physical layer, multiple lanes are often used to work together
> to achieve higher speeds. So a speeds can be achieved with different
> number of lanes. For example, the following solutions can be used to
> implement 100G:
> 1. Combines four 25G lanes
> 2. Combines two 50G lanes
> 3. A single 100G lane
> 
> It is assumed that two ports are interconnected and the two ports support
> the above three solutions. But, we just configured the speed to 100G and
> one port uses four 25G lanes by default and the other port uses two 50G lanes
> by default, the port cannot be up. In this case, we need to configure the
> ports to use the same solutions (for example, uses two 50G lanes) so that
> the ports can be up.
> 
> This patch set add support setting lanes for ethdev. application can use
> this feature to configure lanes to help select the same solutions.
>

Hi Dengdui, Damodharam,

As details of the implementation under discussion, I have a high level
question.

Why/when an application need to configure the lanes explicitly?

In above description, it mentions if one port is configured as 4x25G and
other 2x50G, port can't be up. How do you end up being in this situation?

Lets assume first port is configured as 100G, and FW configured it as
4x25G, and again user configured second port as 100G, why FW can't
detect this and configure ports with correct lane configuration?

In this case, if we push the responsibility to the user, when user is
configuring the second port how she will know what is the lane
configuration for first port, and what is the proper lane configuration
for the second port?

Instead of pushing this configuration to user, why it can't be handled
internally?

As long as user requested speed configured by device, the lane
configuration has no impact to the user, right?
Is there a case/reason user need to explicitly set, lets say PAM4
against NRZ?


Thanks,
ferruh
  

Patch

diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
index f521a1fe9e..e66daf4bba 100644
--- a/app/test-pmd/cmdline.c
+++ b/app/test-pmd/cmdline.c
@@ -1356,15 +1356,20 @@  struct cmd_config_speed_all {
 	cmdline_fixed_string_t keyword;
 	cmdline_fixed_string_t all;
 	cmdline_fixed_string_t item1;
+	cmdline_fixed_string_t lanes_item;
 	cmdline_fixed_string_t item2;
 	cmdline_fixed_string_t value1;
+	uint8_t lanes_value;
 	cmdline_fixed_string_t value2;
 };
 
 static int
-parse_and_check_speed_duplex(char *speedstr, char *duplexstr, uint32_t *speed)
+parse_and_check_speed_duplex(char *speedstr, uint8_t lanes, char *duplexstr,
+			     uint32_t *speed)
 {
 
+	uint32_t speed_num;
+	char *endptr;
 	int duplex;
 
 	if (!strcmp(duplexstr, "half")) {
@@ -1378,47 +1383,22 @@  parse_and_check_speed_duplex(char *speedstr, char *duplexstr, uint32_t *speed)
 		return -1;
 	}
 
-	if (!strcmp(speedstr, "10")) {
-		*speed = (duplex == RTE_ETH_LINK_HALF_DUPLEX) ?
-				RTE_ETH_LINK_SPEED_10M_HD : RTE_ETH_LINK_SPEED_10M;
-	} else if (!strcmp(speedstr, "100")) {
-		*speed = (duplex == RTE_ETH_LINK_HALF_DUPLEX) ?
-				RTE_ETH_LINK_SPEED_100M_HD : RTE_ETH_LINK_SPEED_100M;
-	} else {
-		if (duplex != RTE_ETH_LINK_FULL_DUPLEX) {
-			fprintf(stderr, "Invalid speed/duplex parameters\n");
-			return -1;
-		}
-		if (!strcmp(speedstr, "1000")) {
-			*speed = RTE_ETH_LINK_SPEED_1G;
-		} else if (!strcmp(speedstr, "2500")) {
-			*speed = RTE_ETH_LINK_SPEED_2_5G;
-		} else if (!strcmp(speedstr, "5000")) {
-			*speed = RTE_ETH_LINK_SPEED_5G;
-		} else if (!strcmp(speedstr, "10000")) {
-			*speed = RTE_ETH_LINK_SPEED_10G;
-		} else if (!strcmp(speedstr, "25000")) {
-			*speed = RTE_ETH_LINK_SPEED_25G;
-		} else if (!strcmp(speedstr, "40000")) {
-			*speed = RTE_ETH_LINK_SPEED_40G;
-		} else if (!strcmp(speedstr, "50000")) {
-			*speed = RTE_ETH_LINK_SPEED_50G;
-		} else if (!strcmp(speedstr, "100000")) {
-			*speed = RTE_ETH_LINK_SPEED_100G;
-		} else if (!strcmp(speedstr, "200000")) {
-			*speed = RTE_ETH_LINK_SPEED_200G;
-		} else if (!strcmp(speedstr, "400000")) {
-			*speed = RTE_ETH_LINK_SPEED_400G;
-		} else if (!strcmp(speedstr, "auto")) {
-			*speed = RTE_ETH_LINK_SPEED_AUTONEG;
-		} else {
-			fprintf(stderr, "Unknown speed parameter\n");
-			return -1;
-		}
+	if (!strcmp(speedstr, "auto")) {
+		*speed = RTE_ETH_LINK_SPEED_AUTONEG;
+		return 0;
 	}
 
-	if (*speed != RTE_ETH_LINK_SPEED_AUTONEG)
-		*speed |= RTE_ETH_LINK_SPEED_FIXED;
+	speed_num = strtol(speedstr, &endptr, 10);
+	if (*endptr != '\0') {
+		fprintf(stderr, "Unknown speed parameter\n");
+		return -1;
+	}
+
+	*speed = rte_eth_speed_bitflag(speed_num, lanes, duplex);
+	if (*speed == 0) {
+		fprintf(stderr, "param error\n");
+		return -1;
+	}
 
 	return 0;
 }
@@ -1429,19 +1409,27 @@  cmd_config_speed_all_parsed(void *parsed_result,
 			__rte_unused void *data)
 {
 	struct cmd_config_speed_all *res = parsed_result;
+	struct rte_eth_dev_info dev_info;
 	uint32_t link_speed;
 	portid_t pid;
+	int ret;
 
 	if (!all_ports_stopped()) {
 		fprintf(stderr, "Please stop all ports first\n");
 		return;
 	}
 
-	if (parse_and_check_speed_duplex(res->value1, res->value2,
-			&link_speed) < 0)
+	if (parse_and_check_speed_duplex(res->value1, res->lanes_value,
+					 res->value2, &link_speed) < 0)
 		return;
 
 	RTE_ETH_FOREACH_DEV(pid) {
+		ret = eth_dev_info_get_print_err(pid, &dev_info);
+		if (ret != 0)
+			return;
+		if ((dev_info.dev_capa & RTE_ETH_DEV_CAPA_SETTING_LANES) == 0)
+			fprintf(stderr, "The setting lane may not take effect because "
+					"the port (%u) does not support it\n", pid);
 		ports[pid].dev_conf.link_speeds = link_speed;
 	}
 
@@ -1460,6 +1448,11 @@  static cmdline_parse_token_string_t cmd_config_speed_all_item1 =
 static cmdline_parse_token_string_t cmd_config_speed_all_value1 =
 	TOKEN_STRING_INITIALIZER(struct cmd_config_speed_all, value1,
 				"10#100#1000#2500#5000#10000#25000#40000#50000#100000#200000#400000#auto");
+static cmdline_parse_token_string_t cmd_config_speed_all_lanes_item =
+	TOKEN_STRING_INITIALIZER(struct cmd_config_speed_all, lanes_item, "lanes");
+static cmdline_parse_token_num_t cmd_config_speed_all_lanes_value =
+	TOKEN_NUM_INITIALIZER(struct cmd_config_speed_all, lanes_value,
+			      RTE_UINT8);
 static cmdline_parse_token_string_t cmd_config_speed_all_item2 =
 	TOKEN_STRING_INITIALIZER(struct cmd_config_speed_all, item2, "duplex");
 static cmdline_parse_token_string_t cmd_config_speed_all_value2 =
@@ -1470,14 +1463,16 @@  static cmdline_parse_inst_t cmd_config_speed_all = {
 	.f = cmd_config_speed_all_parsed,
 	.data = NULL,
 	.help_str = "port config all speed "
-		"10|100|1000|2500|5000|10000|25000|40000|50000|100000|200000|400000|auto duplex "
-							"half|full|auto",
+		"10|100|1000|2500|5000|10000|25000|40000|50000|100000|200000|400000|auto"
+		" lanes 1|2|4|8 duplex half|full|auto",
 	.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_lanes_item,
+		(void *)&cmd_config_speed_all_lanes_value,
 		(void *)&cmd_config_speed_all_item2,
 		(void *)&cmd_config_speed_all_value2,
 		NULL,
@@ -1490,8 +1485,10 @@  struct cmd_config_speed_specific {
 	cmdline_fixed_string_t keyword;
 	portid_t id;
 	cmdline_fixed_string_t item1;
+	cmdline_fixed_string_t lanes_item;
 	cmdline_fixed_string_t item2;
 	cmdline_fixed_string_t value1;
+	uint8_t lanes_value;
 	cmdline_fixed_string_t value2;
 };
 
@@ -1501,7 +1498,9 @@  cmd_config_speed_specific_parsed(void *parsed_result,
 				__rte_unused void *data)
 {
 	struct cmd_config_speed_specific *res = parsed_result;
+	struct rte_eth_dev_info dev_info;
 	uint32_t link_speed;
+	int ret;
 
 	if (port_id_is_invalid(res->id, ENABLED_WARN))
 		return;
@@ -1511,8 +1510,15 @@  cmd_config_speed_specific_parsed(void *parsed_result,
 		return;
 	}
 
-	if (parse_and_check_speed_duplex(res->value1, res->value2,
-			&link_speed) < 0)
+	ret = eth_dev_info_get_print_err(res->id, &dev_info);
+	if (ret != 0)
+		return;
+	if ((dev_info.dev_capa & RTE_ETH_DEV_CAPA_SETTING_LANES) == 0)
+		fprintf(stderr, "The setting lane may not take effect because "
+				"the port (%d) does not support it\n", res->id);
+
+	if (parse_and_check_speed_duplex(res->value1, res->lanes_value,
+					 res->value2, &link_speed) < 0)
 		return;
 
 	ports[res->id].dev_conf.link_speeds = link_speed;
@@ -1535,6 +1541,12 @@  static cmdline_parse_token_string_t cmd_config_speed_specific_item1 =
 static cmdline_parse_token_string_t cmd_config_speed_specific_value1 =
 	TOKEN_STRING_INITIALIZER(struct cmd_config_speed_specific, value1,
 				"10#100#1000#2500#5000#10000#25000#40000#50000#100000#200000#400000#auto");
+static cmdline_parse_token_string_t cmd_config_speed_specific_lanes_item =
+	TOKEN_STRING_INITIALIZER(struct cmd_config_speed_specific, lanes_item,
+								"lanes");
+static cmdline_parse_token_num_t cmd_config_speed_specific_lanes_value =
+	TOKEN_NUM_INITIALIZER(struct cmd_config_speed_specific, lanes_value,
+			      RTE_UINT8);
 static cmdline_parse_token_string_t cmd_config_speed_specific_item2 =
 	TOKEN_STRING_INITIALIZER(struct cmd_config_speed_specific, item2,
 								"duplex");
@@ -1546,14 +1558,16 @@  static cmdline_parse_inst_t cmd_config_speed_specific = {
 	.f = cmd_config_speed_specific_parsed,
 	.data = NULL,
 	.help_str = "port config <port_id> speed "
-		"10|100|1000|2500|5000|10000|25000|40000|50000|100000|200000|400000|auto duplex "
-							"half|full|auto",
+		"10|100|1000|2500|5000|10000|25000|40000|50000|100000|200000|400000|auto"
+		" lanes 1|2|4|8 duplex half|full|auto",
 	.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_lanes_item,
+		(void *)&cmd_config_speed_specific_lanes_value,
 		(void *)&cmd_config_speed_specific_item2,
 		(void *)&cmd_config_speed_specific_value2,
 		NULL,
diff --git a/app/test-pmd/config.c b/app/test-pmd/config.c
index 968d2164ab..c104327878 100644
--- a/app/test-pmd/config.c
+++ b/app/test-pmd/config.c
@@ -587,39 +587,51 @@  device_infos_display_speeds(uint32_t speed_capa)
 	if (speed_capa == RTE_ETH_LINK_SPEED_AUTONEG)
 		printf(" Autonegotiate (all speeds)");
 	if (speed_capa & RTE_ETH_LINK_SPEED_FIXED)
-		printf(" Disable autonegotiate (fixed speed)  ");
+		printf(" Disable autonegotiate (fixed speed) /");
 	if (speed_capa & RTE_ETH_LINK_SPEED_10M_HD)
-		printf(" 10 Mbps half-duplex  ");
+		printf(" 10Mbps_1lane_half-duplex /");
 	if (speed_capa & RTE_ETH_LINK_SPEED_10M)
-		printf(" 10 Mbps full-duplex  ");
+		printf(" 10Mbps_1lane_full-duplex /");
 	if (speed_capa & RTE_ETH_LINK_SPEED_100M_HD)
-		printf(" 100 Mbps half-duplex  ");
+		printf(" 100Mbps_lane_half-duplex /");
 	if (speed_capa & RTE_ETH_LINK_SPEED_100M)
-		printf(" 100 Mbps full-duplex  ");
+		printf(" 100Mbps_1lane_full-duplex /");
 	if (speed_capa & RTE_ETH_LINK_SPEED_1G)
-		printf(" 1 Gbps  ");
+		printf(" 1Gbps_1lane_full-duplex /");
 	if (speed_capa & RTE_ETH_LINK_SPEED_2_5G)
-		printf(" 2.5 Gbps  ");
+		printf(" 2.5Gbps_1lane_full-duplex /");
 	if (speed_capa & RTE_ETH_LINK_SPEED_5G)
-		printf(" 5 Gbps  ");
+		printf(" 5Gbps_1lane_full-duplex /");
 	if (speed_capa & RTE_ETH_LINK_SPEED_10G)
-		printf(" 10 Gbps  ");
-	if (speed_capa & RTE_ETH_LINK_SPEED_20G)
-		printf(" 20 Gbps  ");
+		printf(" 10Gbps_1lane_full-duplex /");
+	if (speed_capa & RTE_ETH_LINK_SPEED_10G_4LANES)
+		printf(" 10Gbps_4lane_full-duplex /");
+	if (speed_capa & RTE_ETH_LINK_SPEED_20G_2LANES)
+		printf(" 20Gbps_2lane_full-duplex /");
 	if (speed_capa & RTE_ETH_LINK_SPEED_25G)
-		printf(" 25 Gbps  ");
-	if (speed_capa & RTE_ETH_LINK_SPEED_40G)
-		printf(" 40 Gbps  ");
+		printf(" 25Gbps_1lane_full-duplex /");
+	if (speed_capa & RTE_ETH_LINK_SPEED_40G_4LANES)
+		printf(" 40Gbps_4lane_full-duplex /");
 	if (speed_capa & RTE_ETH_LINK_SPEED_50G)
-		printf(" 50 Gbps  ");
-	if (speed_capa & RTE_ETH_LINK_SPEED_56G)
-		printf(" 56 Gbps  ");
+		printf(" 50Gbps_1lane_full-duplex /");
+	if (speed_capa & RTE_ETH_LINK_SPEED_50G_2LANES)
+		printf(" 50Gbps_2lane_full-duplex /");
+	if (speed_capa & RTE_ETH_LINK_SPEED_56G_4LANES)
+		printf(" 56Gbps_4lane_full-duplex /");
 	if (speed_capa & RTE_ETH_LINK_SPEED_100G)
-		printf(" 100 Gbps  ");
-	if (speed_capa & RTE_ETH_LINK_SPEED_200G)
-		printf(" 200 Gbps  ");
-	if (speed_capa & RTE_ETH_LINK_SPEED_400G)
-		printf(" 400 Gbps  ");
+		printf(" 100Gbps_1lane_full-duplex /");
+	if (speed_capa & RTE_ETH_LINK_SPEED_100G_2LANES)
+		printf(" 100Gbps_2lane_full-duplex /");
+	if (speed_capa & RTE_ETH_LINK_SPEED_100G_4LANES)
+		printf(" 100Gbps_4lane_full-duplex /");
+	if (speed_capa & RTE_ETH_LINK_SPEED_200G_4LANES)
+		printf(" 200Gbps_4lane_full-duplex /");
+	if (speed_capa & RTE_ETH_LINK_SPEED_200G_2LANES)
+		printf(" 200Gbps_2lane_full-duplex /");
+	if (speed_capa & RTE_ETH_LINK_SPEED_400G_4LANES)
+		printf(" 400Gbps_4lane_full-duplex /");
+	if (speed_capa & RTE_ETH_LINK_SPEED_400G_8LANES)
+		printf(" 400Gbps_8lane_full-duplex /");
 }
 
 void
@@ -828,6 +840,10 @@  port_infos_display(portid_t port_id)
 
 	printf("\nLink status: %s\n", (link.link_status) ? ("up") : ("down"));
 	printf("Link speed: %s\n", rte_eth_link_speed_to_str(link.link_speed));
+	if (link.link_lanes == 0)
+		printf("Link lanes: unknown\n");
+	else
+		printf("Link lanes: %u\n", link.link_lanes);
 	printf("Link duplex: %s\n", (link.link_duplex == RTE_ETH_LINK_FULL_DUPLEX) ?
 	       ("full-duplex") : ("half-duplex"));
 	printf("Autoneg status: %s\n", (link.link_autoneg == RTE_ETH_LINK_AUTONEG) ?
diff --git a/doc/guides/rel_notes/release_24_03.rst b/doc/guides/rel_notes/release_24_03.rst
index c17334ac25..46aceeee93 100644
--- a/doc/guides/rel_notes/release_24_03.rst
+++ b/doc/guides/rel_notes/release_24_03.rst
@@ -79,6 +79,7 @@  New Features
 * **Support setting lanes for ethdev.**
   * Support setting lanes by extended ``RTE_ETH_LINK_SPEED_*``.
   * Added function to convert bitmap flag to the struct of link speed info.
+  ``rte_eth_speed_capa_to_info()``
 
 * **Added hash calculation of an encapsulated packet as done by the HW.**
 
diff --git a/doc/guides/testpmd_app_ug/testpmd_funcs.rst b/doc/guides/testpmd_app_ug/testpmd_funcs.rst
index 2fbf9220d8..087f7fe853 100644
--- a/doc/guides/testpmd_app_ug/testpmd_funcs.rst
+++ b/doc/guides/testpmd_app_ug/testpmd_funcs.rst
@@ -190,6 +190,7 @@  For example:
    memory allocation on the socket: 0
    Link status: up
    Link speed: 40000 Mbps
+   Link lanes: 4
    Link duplex: full-duplex
    Promiscuous mode: enabled
    Allmulticast mode: disabled
@@ -2065,7 +2066,7 @@  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|auto) \
-            duplex (half|full|auto)
+            lanes 1|2|4|8 duplex (half|full|auto)
 
 port config - queues/descriptors
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~