[dpdk-dev] [PATCH v6 3/5] ethdev: redesign link speed config API

Marc Sune marcdevel at gmail.com
Sun Oct 25 23:03:54 CET 2015


While testing this patch with some XL710, it seems even with current HEAD,
setting link speed into dev_conf to 10G does not work, it always takes
autoneg with all speeds.

Besides, this patch in particular should be tested for the rest of drivers
which I don't have HW for.

Regards
marc

2015-10-25 22:59 GMT+01:00 Marc Sune <marcdevel at gmail.com>:

> This patch redesigns the API to set the link speed/s configure
> for an ethernet port. Specifically:
>
> - it allows to define a set of advertised speeds for
>   auto-negociation.
> - it allows to disable link auto-negociation (single fixed speed).
> - default: auto-negociate all supported speeds.
>
> Other changes:
>
> * Added utility MACROs ETH_SPEED_NUM_XXX with the numeric
>   values of all supported link speeds, in Mbps.
> * Converted link_speed to uint32_t to accomodate 100G speeds
>   (bug).
> * Added autoneg flag in struct rte_eth_link to indicate if
>   link speed was a result of auto-negociation or was fixed
>   by configuration.
> * Added utility function to convert numeric speeds to bitmap
>   fields.
>
> Signed-off-by: Marc Sune <marcdevel at gmail.com>
> ---
>  app/test-pmd/cmdline.c                     | 124
> +++++++++++++++--------------
>  app/test/virtual_pmd.c                     |   4 +-
>  drivers/net/af_packet/rte_eth_af_packet.c  |   5 +-
>  drivers/net/bonding/rte_eth_bond_8023ad.c  |  14 ++--
>  drivers/net/cxgbe/base/t4_hw.c             |   8 +-
>  drivers/net/e1000/base/e1000_80003es2lan.c |   6 +-
>  drivers/net/e1000/base/e1000_82541.c       |   8 +-
>  drivers/net/e1000/base/e1000_82543.c       |   4 +-
>  drivers/net/e1000/base/e1000_82575.c       |  11 +--
>  drivers/net/e1000/base/e1000_api.c         |   2 +-
>  drivers/net/e1000/base/e1000_api.h         |   2 +-
>  drivers/net/e1000/base/e1000_defines.h     |   4 +-
>  drivers/net/e1000/base/e1000_hw.h          |   2 +-
>  drivers/net/e1000/base/e1000_ich8lan.c     |   4 +-
>  drivers/net/e1000/base/e1000_mac.c         |   9 ++-
>  drivers/net/e1000/base/e1000_mac.h         |   6 +-
>  drivers/net/e1000/base/e1000_vf.c          |   4 +-
>  drivers/net/e1000/base/e1000_vf.h          |   2 +-
>  drivers/net/e1000/em_ethdev.c              | 113
> +++++++++++++-------------
>  drivers/net/e1000/igb_ethdev.c             | 108 +++++++++++++------------
>  drivers/net/fm10k/fm10k_ethdev.c           |   8 +-
>  drivers/net/i40e/i40e_ethdev.c             |  73 ++++++++---------
>  drivers/net/i40e/i40e_ethdev_vf.c          |  11 +--
>  drivers/net/ixgbe/ixgbe_ethdev.c           |  72 ++++++++---------
>  drivers/net/mlx4/mlx4.c                    |   2 +
>  drivers/net/mpipe/mpipe_tilegx.c           |   6 +-
>  drivers/net/null/rte_eth_null.c            |   5 +-
>  drivers/net/pcap/rte_eth_pcap.c            |   9 ++-
>  drivers/net/ring/rte_eth_ring.c            |   5 +-
>  drivers/net/virtio/virtio_ethdev.c         |   2 +-
>  drivers/net/virtio/virtio_ethdev.h         |   2 -
>  drivers/net/vmxnet3/vmxnet3_ethdev.c       |   5 +-
>  drivers/net/xenvirt/rte_eth_xenvirt.c      |   5 +-
>  examples/ip_pipeline/config_parse.c        |   3 +-
>  lib/librte_ether/rte_ethdev.c              |  49 ++++++++++++
>  lib/librte_ether/rte_ethdev.h              | 113
> ++++++++++++++++----------
>  36 files changed, 449 insertions(+), 361 deletions(-)
>
> diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
> index 0f8f48f..c62f5be 100644
> --- a/app/test-pmd/cmdline.c
> +++ b/app/test-pmd/cmdline.c
> @@ -897,14 +897,65 @@ struct cmd_config_speed_all {
>         cmdline_fixed_string_t value2;
>  };
>
> +static int
> +parse_and_check_speed_duplex(char *value1, char *value2, uint32_t
> *link_speed)
> +{
> +
> +       int duplex;
> +
> +       if (!strcmp(value2, "half")) {
> +               duplex = 0;
> +       } else if (!strcmp(value2, "full")) {
> +               duplex = 1;
> +       } else if (!strcmp(value2, "auto")) {
> +               duplex = 1;
> +       } else {
> +               printf("Unknown parameter\n");
> +               return -1;
> +       }
> +
> +       if (!strcmp(value1, "10")) {
> +               *link_speed = (duplex) ? ETH_LINK_SPEED_10M :
> +
>  ETH_LINK_SPEED_10M_HD;
> +       } else if (!strcmp(value1, "100")) {
> +               *link_speed = (duplex) ? ETH_LINK_SPEED_100M :
> +
>  ETH_LINK_SPEED_100M_HD;
> +       } else if (!strcmp(value1, "1000")) {
> +               if (!duplex)
> +                       goto invalid_speed_param;
> +               *link_speed = ETH_LINK_SPEED_1G;
> +       } else if (!strcmp(value1, "10000")) {
> +               if (!duplex)
> +                       goto invalid_speed_param;
> +               *link_speed = ETH_LINK_SPEED_10G;
> +       } else if (!strcmp(value1, "40000")) {
> +               if (!duplex)
> +                       goto invalid_speed_param;
> +               *link_speed = ETH_LINK_SPEED_40G;
> +       } else if (!strcmp(value1, "auto")) {
> +               if (!duplex)
> +                       goto invalid_speed_param;
> +               *link_speed = ETH_LINK_SPEED_AUTONEG;
> +       } else {
> +               printf("Unknown parameter\n");
> +               return -1;
> +       }
> +
> +       return 0;
> +
> +invalid_speed_param:
> +
> +       printf("Invalid speed parameter\n");
> +       return -1;
> +}
> +
>  static void
>  cmd_config_speed_all_parsed(void *parsed_result,
>                         __attribute__((unused)) struct cmdline *cl,
>                         __attribute__((unused)) void *data)
>  {
>         struct cmd_config_speed_all *res = parsed_result;
> -       uint16_t link_speed = ETH_LINK_SPEED_AUTONEG;
> -       uint16_t link_duplex = 0;
> +       uint32_t link_speed;
>         portid_t pid;
>
>         if (!all_ports_stopped()) {
> @@ -912,40 +963,18 @@ cmd_config_speed_all_parsed(void *parsed_result,
>                 return;
>         }
>
> -       if (!strcmp(res->value1, "10"))
> -               link_speed = ETH_LINK_SPEED_10;
> -       else if (!strcmp(res->value1, "100"))
> -               link_speed = ETH_LINK_SPEED_100;
> -       else if (!strcmp(res->value1, "1000"))
> -               link_speed = ETH_LINK_SPEED_1000;
> -       else if (!strcmp(res->value1, "10000"))
> -               link_speed = ETH_LINK_SPEED_10G;
> -       else if (!strcmp(res->value1, "40000"))
> -               link_speed = ETH_LINK_SPEED_40G;
> -       else if (!strcmp(res->value1, "auto"))
> -               link_speed = ETH_LINK_SPEED_AUTONEG;
> -       else {
> -               printf("Unknown parameter\n");
> +       if (parse_and_check_speed_duplex(res->value1,
> +                                               res->value2,
> +                                               &link_speed) < 0)
>                 return;
> -       }
> -
> -       if (!strcmp(res->value2, "half"))
> -               link_duplex = ETH_LINK_HALF_DUPLEX;
> -       else if (!strcmp(res->value2, "full"))
> -               link_duplex = ETH_LINK_FULL_DUPLEX;
> -       else if (!strcmp(res->value2, "auto"))
> -               link_duplex = ETH_LINK_AUTONEG_DUPLEX;
> -       else {
> -               printf("Unknown parameter\n");
> -               return;
> -       }
>
>         FOREACH_PORT(pid, ports) {
> -               ports[pid].dev_conf.link_speed = link_speed;
> -               ports[pid].dev_conf.link_duplex = link_duplex;
> +               ports[pid].dev_conf.link_speeds = link_speed;
>         }
>
>         cmd_reconfig_device_queue(RTE_PORT_ALL, 1, 1);
> +
> +       return;
>  }
>
>  cmdline_parse_token_string_t cmd_config_speed_all_port =
> @@ -1000,8 +1029,7 @@ cmd_config_speed_specific_parsed(void *parsed_result,
>                                 __attribute__((unused)) void *data)
>  {
>         struct cmd_config_speed_specific *res = parsed_result;
> -       uint16_t link_speed = ETH_LINK_SPEED_AUTONEG;
> -       uint16_t link_duplex = 0;
> +       uint32_t link_speed;
>
>         if (!all_ports_stopped()) {
>                 printf("Please stop all ports first\n");
> @@ -1011,36 +1039,12 @@ cmd_config_speed_specific_parsed(void
> *parsed_result,
>         if (port_id_is_invalid(res->id, ENABLED_WARN))
>                 return;
>
> -       if (!strcmp(res->value1, "10"))
> -               link_speed = ETH_LINK_SPEED_10;
> -       else if (!strcmp(res->value1, "100"))
> -               link_speed = ETH_LINK_SPEED_100;
> -       else if (!strcmp(res->value1, "1000"))
> -               link_speed = ETH_LINK_SPEED_1000;
> -       else if (!strcmp(res->value1, "10000"))
> -               link_speed = ETH_LINK_SPEED_10000;
> -       else if (!strcmp(res->value1, "40000"))
> -               link_speed = ETH_LINK_SPEED_40G;
> -       else if (!strcmp(res->value1, "auto"))
> -               link_speed = ETH_LINK_SPEED_AUTONEG;
> -       else {
> -               printf("Unknown parameter\n");
> +       if (parse_and_check_speed_duplex(res->value1,
> +                                               res->value2,
> +                                               &link_speed) < 0)
>                 return;
> -       }
> -
> -       if (!strcmp(res->value2, "half"))
> -               link_duplex = ETH_LINK_HALF_DUPLEX;
> -       else if (!strcmp(res->value2, "full"))
> -               link_duplex = ETH_LINK_FULL_DUPLEX;
> -       else if (!strcmp(res->value2, "auto"))
> -               link_duplex = ETH_LINK_AUTONEG_DUPLEX;
> -       else {
> -               printf("Unknown parameter\n");
> -               return;
> -       }
>
> -       ports[res->id].dev_conf.link_speed = link_speed;
> -       ports[res->id].dev_conf.link_duplex = link_duplex;
> +       ports[res->id].dev_conf.link_speeds = link_speed;
>
>         cmd_reconfig_device_queue(RTE_PORT_ALL, 1, 1);
>  }
> diff --git a/app/test/virtual_pmd.c b/app/test/virtual_pmd.c
> index a538c8a..3c4040b 100644
> --- a/app/test/virtual_pmd.c
> +++ b/app/test/virtual_pmd.c
> @@ -603,8 +603,8 @@ virtual_ethdev_create(const char *name, struct
> ether_addr *mac_addr,
>
>         TAILQ_INIT(&(eth_dev->link_intr_cbs));
>
> -       eth_dev->data->dev_link.link_status = 0;
> -       eth_dev->data->dev_link.link_speed = ETH_LINK_SPEED_10000;
> +       eth_dev->data->dev_link.link_status = ETH_LINK_DOWN;
> +       eth_dev->data->dev_link.link_speed = ETH_SPEED_NUM_10G;
>         eth_dev->data->dev_link.link_duplex = ETH_LINK_FULL_DUPLEX;
>
>         eth_dev->data->mac_addrs = rte_zmalloc(name, ETHER_ADDR_LEN, 0);
> diff --git a/drivers/net/af_packet/rte_eth_af_packet.c
> b/drivers/net/af_packet/rte_eth_af_packet.c
> index bdd9628..a5d689d 100644
> --- a/drivers/net/af_packet/rte_eth_af_packet.c
> +++ b/drivers/net/af_packet/rte_eth_af_packet.c
> @@ -115,9 +115,10 @@ static const char *valid_arguments[] = {
>  static const char *drivername = "AF_PACKET PMD";
>
>  static struct rte_eth_link pmd_link = {
> -       .link_speed = 10000,
> +       .link_speed = ETH_SPEED_NUM_10G,
>         .link_duplex = ETH_LINK_FULL_DUPLEX,
> -       .link_status = 0
> +       .link_status = ETH_LINK_DOWN,
> +       .link_autoneg = ETH_LINK_SPEED_NEG
>  };
>
>  static uint16_t
> diff --git a/drivers/net/bonding/rte_eth_bond_8023ad.c
> b/drivers/net/bonding/rte_eth_bond_8023ad.c
> index c0f0b99..f375f95 100644
> --- a/drivers/net/bonding/rte_eth_bond_8023ad.c
> +++ b/drivers/net/bonding/rte_eth_bond_8023ad.c
> @@ -708,25 +708,25 @@ link_speed_key(uint16_t speed) {
>         uint16_t key_speed;
>
>         switch (speed) {
> -       case ETH_LINK_SPEED_AUTONEG:
> +       case ETH_SPEED_NUM_NONE:
>                 key_speed = 0x00;
>                 break;
> -       case ETH_LINK_SPEED_10:
> +       case ETH_SPEED_NUM_10M:
>                 key_speed = BOND_LINK_SPEED_KEY_10M;
>                 break;
> -       case ETH_LINK_SPEED_100:
> +       case ETH_SPEED_NUM_100M:
>                 key_speed = BOND_LINK_SPEED_KEY_100M;
>                 break;
> -       case ETH_LINK_SPEED_1000:
> +       case ETH_SPEED_NUM_1G:
>                 key_speed = BOND_LINK_SPEED_KEY_1000M;
>                 break;
> -       case ETH_LINK_SPEED_10G:
> +       case ETH_SPEED_NUM_10G:
>                 key_speed = BOND_LINK_SPEED_KEY_10G;
>                 break;
> -       case ETH_LINK_SPEED_20G:
> +       case ETH_SPEED_NUM_20G:
>                 key_speed = BOND_LINK_SPEED_KEY_20G;
>                 break;
> -       case ETH_LINK_SPEED_40G:
> +       case ETH_SPEED_NUM_40G:
>                 key_speed = BOND_LINK_SPEED_KEY_40G;
>                 break;
>         default:
> diff --git a/drivers/net/cxgbe/base/t4_hw.c
> b/drivers/net/cxgbe/base/t4_hw.c
> index 884d2cf..79af806 100644
> --- a/drivers/net/cxgbe/base/t4_hw.c
> +++ b/drivers/net/cxgbe/base/t4_hw.c
> @@ -2159,13 +2159,13 @@ int t4_handle_fw_rpl(struct adapter *adap, const
> __be64 *rpl)
>                 if (stat & F_FW_PORT_CMD_TXPAUSE)
>                         fc |= PAUSE_TX;
>                 if (stat & V_FW_PORT_CMD_LSPEED(FW_PORT_CAP_SPEED_100M))
> -                       speed = ETH_LINK_SPEED_100;
> +                       speed = ETH_SPEED_NUM_100M;
>                 else if (stat & V_FW_PORT_CMD_LSPEED(FW_PORT_CAP_SPEED_1G))
> -                       speed = ETH_LINK_SPEED_1000;
> +                       speed = ETH_SPEED_NUM_1G;
>                 else if (stat &
> V_FW_PORT_CMD_LSPEED(FW_PORT_CAP_SPEED_10G))
> -                       speed = ETH_LINK_SPEED_10000;
> +                       speed = ETH_SPEED_NUM_10G;
>                 else if (stat &
> V_FW_PORT_CMD_LSPEED(FW_PORT_CAP_SPEED_40G))
> -                       speed = ETH_LINK_SPEED_40G;
> +                       speed = ETH_SPEED_NUM_40G;
>
>                 for_each_port(adap, i) {
>                         pi = adap2pinfo(adap, i);
> diff --git a/drivers/net/e1000/base/e1000_80003es2lan.c
> b/drivers/net/e1000/base/e1000_80003es2lan.c
> index 72692d9..8ca66c4 100644
> --- a/drivers/net/e1000/base/e1000_80003es2lan.c
> +++ b/drivers/net/e1000/base/e1000_80003es2lan.c
> @@ -52,7 +52,7 @@ STATIC s32  e1000_write_nvm_80003es2lan(struct e1000_hw
> *hw, u16 offset,
>  STATIC s32  e1000_get_cfg_done_80003es2lan(struct e1000_hw *hw);
>  STATIC s32  e1000_phy_force_speed_duplex_80003es2lan(struct e1000_hw *hw);
>  STATIC s32  e1000_get_cable_length_80003es2lan(struct e1000_hw *hw);
> -STATIC s32  e1000_get_link_up_info_80003es2lan(struct e1000_hw *hw, u16
> *speed,
> +STATIC s32  e1000_get_link_up_info_80003es2lan(struct e1000_hw *hw, u32
> *speed,
>                                                u16 *duplex);
>  STATIC s32  e1000_reset_hw_80003es2lan(struct e1000_hw *hw);
>  STATIC s32  e1000_init_hw_80003es2lan(struct e1000_hw *hw);
> @@ -789,7 +789,7 @@ STATIC s32 e1000_get_cable_length_80003es2lan(struct
> e1000_hw *hw)
>   *
>   *  Retrieve the current speed and duplex configuration.
>   **/
> -STATIC s32 e1000_get_link_up_info_80003es2lan(struct e1000_hw *hw, u16
> *speed,
> +STATIC s32 e1000_get_link_up_info_80003es2lan(struct e1000_hw *hw, u32
> *speed,
>                                               u16 *duplex)
>  {
>         s32 ret_val;
> @@ -1236,7 +1236,7 @@ STATIC s32
> e1000_setup_copper_link_80003es2lan(struct e1000_hw *hw)
>  STATIC s32 e1000_cfg_on_link_up_80003es2lan(struct e1000_hw *hw)
>  {
>         s32 ret_val = E1000_SUCCESS;
> -       u16 speed;
> +       u32 speed;
>         u16 duplex;
>
>         DEBUGFUNC("e1000_configure_on_link_up");
> diff --git a/drivers/net/e1000/base/e1000_82541.c
> b/drivers/net/e1000/base/e1000_82541.c
> index 952aea2..707b317 100644
> --- a/drivers/net/e1000/base/e1000_82541.c
> +++ b/drivers/net/e1000/base/e1000_82541.c
> @@ -47,7 +47,7 @@ STATIC s32  e1000_init_nvm_params_82541(struct e1000_hw
> *hw);
>  STATIC s32  e1000_init_mac_params_82541(struct e1000_hw *hw);
>  STATIC s32  e1000_reset_hw_82541(struct e1000_hw *hw);
>  STATIC s32  e1000_init_hw_82541(struct e1000_hw *hw);
> -STATIC s32  e1000_get_link_up_info_82541(struct e1000_hw *hw, u16 *speed,
> +STATIC s32  e1000_get_link_up_info_82541(struct e1000_hw *hw, u32 *speed,
>                                          u16 *duplex);
>  STATIC s32  e1000_phy_hw_reset_82541(struct e1000_hw *hw);
>  STATIC s32  e1000_setup_copper_link_82541(struct e1000_hw *hw);
> @@ -437,7 +437,7 @@ out:
>   *
>   * Retrieve the current speed and duplex configuration.
>   **/
> -STATIC s32 e1000_get_link_up_info_82541(struct e1000_hw *hw, u16 *speed,
> +STATIC s32 e1000_get_link_up_info_82541(struct e1000_hw *hw, u32 *speed,
>                                         u16 *duplex)
>  {
>         struct e1000_phy_info *phy = &hw->phy;
> @@ -667,8 +667,8 @@ STATIC s32
> e1000_config_dsp_after_link_change_82541(struct e1000_hw *hw,
>         struct e1000_phy_info *phy = &hw->phy;
>         struct e1000_dev_spec_82541 *dev_spec = &hw->dev_spec._82541;
>         s32 ret_val;
> -       u32 idle_errs = 0;
> -       u16 phy_data, phy_saved_data, speed, duplex, i;
> +       u32 idle_errs = 0, speed;
> +       u16 phy_data, phy_saved_data, duplex, i;
>         u16 ffe_idle_err_timeout = FFE_IDLE_ERR_COUNT_TIMEOUT_20;
>         u16 dsp_reg_array[IGP01E1000_PHY_CHANNEL_NUM] = {
>                                                 IGP01E1000_PHY_AGC_PARAM_A,
> diff --git a/drivers/net/e1000/base/e1000_82543.c
> b/drivers/net/e1000/base/e1000_82543.c
> index 36335ba..9ef3d80 100644
> --- a/drivers/net/e1000/base/e1000_82543.c
> +++ b/drivers/net/e1000/base/e1000_82543.c
> @@ -1192,9 +1192,9 @@ out:
>  STATIC s32 e1000_check_for_copper_link_82543(struct e1000_hw *hw)
>  {
>         struct e1000_mac_info *mac = &hw->mac;
> -       u32 icr, rctl;
> +       u32 icr, rctl, speed;
>         s32 ret_val;
> -       u16 speed, duplex;
> +       u16 duplex;
>         bool link;
>
>         DEBUGFUNC("e1000_check_for_copper_link_82543");
> diff --git a/drivers/net/e1000/base/e1000_82575.c
> b/drivers/net/e1000/base/e1000_82575.c
> index 25fa672..386f058 100644
> --- a/drivers/net/e1000/base/e1000_82575.c
> +++ b/drivers/net/e1000/base/e1000_82575.c
> @@ -53,7 +53,7 @@ STATIC void e1000_release_nvm_82575(struct e1000_hw *hw);
>  STATIC s32  e1000_check_for_link_82575(struct e1000_hw *hw);
>  STATIC s32  e1000_check_for_link_media_swap(struct e1000_hw *hw);
>  STATIC s32  e1000_get_cfg_done_82575(struct e1000_hw *hw);
> -STATIC s32  e1000_get_link_up_info_82575(struct e1000_hw *hw, u16 *speed,
> +STATIC s32  e1000_get_link_up_info_82575(struct e1000_hw *hw, u32 *speed,
>                                          u16 *duplex);
>  STATIC s32  e1000_phy_hw_reset_sgmii_82575(struct e1000_hw *hw);
>  STATIC s32  e1000_read_phy_reg_sgmii_82575(struct e1000_hw *hw, u32
> offset,
> @@ -80,7 +80,7 @@ STATIC s32  e1000_write_phy_reg_sgmii_82575(struct
> e1000_hw *hw,
>  STATIC void e1000_clear_hw_cntrs_82575(struct e1000_hw *hw);
>  STATIC s32  e1000_acquire_swfw_sync_82575(struct e1000_hw *hw, u16 mask);
>  STATIC s32  e1000_get_pcs_speed_and_duplex_82575(struct e1000_hw *hw,
> -                                                u16 *speed, u16 *duplex);
> +                                                u32 *speed, u16 *duplex);
>  STATIC s32  e1000_get_phy_id_82575(struct e1000_hw *hw);
>  STATIC void e1000_release_swfw_sync_82575(struct e1000_hw *hw, u16 mask);
>  STATIC bool e1000_sgmii_active_82575(struct e1000_hw *hw);
> @@ -1165,7 +1165,7 @@ STATIC s32 e1000_get_cfg_done_82575(struct e1000_hw
> *hw)
>   *  interface, use PCS to retrieve the link speed and duplex information.
>   *  Otherwise, use the generic function to get the link speed and duplex
> info.
>   **/
> -STATIC s32 e1000_get_link_up_info_82575(struct e1000_hw *hw, u16 *speed,
> +STATIC s32 e1000_get_link_up_info_82575(struct e1000_hw *hw, u32 *speed,
>                                         u16 *duplex)
>  {
>         s32 ret_val;
> @@ -1192,7 +1192,8 @@ STATIC s32 e1000_get_link_up_info_82575(struct
> e1000_hw *hw, u16 *speed,
>  STATIC s32 e1000_check_for_link_82575(struct e1000_hw *hw)
>  {
>         s32 ret_val;
> -       u16 speed, duplex;
> +       u32 speed;
> +       u16 duplex;
>
>         DEBUGFUNC("e1000_check_for_link_82575");
>
> @@ -1316,7 +1317,7 @@ STATIC void e1000_power_up_serdes_link_82575(struct
> e1000_hw *hw)
>   *  duplex, then store the values in the pointers provided.
>   **/
>  STATIC s32 e1000_get_pcs_speed_and_duplex_82575(struct e1000_hw *hw,
> -                                               u16 *speed, u16 *duplex)
> +                                               u32 *speed, u16 *duplex)
>  {
>         struct e1000_mac_info *mac = &hw->mac;
>         u32 pcs;
> diff --git a/drivers/net/e1000/base/e1000_api.c
> b/drivers/net/e1000/base/e1000_api.c
> index a064565..08e103a 100644
> --- a/drivers/net/e1000/base/e1000_api.c
> +++ b/drivers/net/e1000/base/e1000_api.c
> @@ -669,7 +669,7 @@ s32 e1000_setup_link(struct e1000_hw *hw)
>   *  variables passed in. This is a function pointer entry point called
>   *  by drivers.
>   **/
> -s32 e1000_get_speed_and_duplex(struct e1000_hw *hw, u16 *speed, u16
> *duplex)
> +s32 e1000_get_speed_and_duplex(struct e1000_hw *hw, u32 *speed, u16
> *duplex)
>  {
>         if (hw->mac.ops.get_link_up_info)
>                 return hw->mac.ops.get_link_up_info(hw, speed, duplex);
> diff --git a/drivers/net/e1000/base/e1000_api.h
> b/drivers/net/e1000/base/e1000_api.h
> index 02b16da..39579e0 100644
> --- a/drivers/net/e1000/base/e1000_api.h
> +++ b/drivers/net/e1000/base/e1000_api.h
> @@ -65,7 +65,7 @@ s32 e1000_check_for_link(struct e1000_hw *hw);
>  s32 e1000_reset_hw(struct e1000_hw *hw);
>  s32 e1000_init_hw(struct e1000_hw *hw);
>  s32 e1000_setup_link(struct e1000_hw *hw);
> -s32 e1000_get_speed_and_duplex(struct e1000_hw *hw, u16 *speed, u16
> *duplex);
> +s32 e1000_get_speed_and_duplex(struct e1000_hw *hw, u32 *speed, u16
> *duplex);
>  s32 e1000_disable_pcie_master(struct e1000_hw *hw);
>  void e1000_config_collision_dist(struct e1000_hw *hw);
>  void e1000_rar_set(struct e1000_hw *hw, u8 *addr, u32 index);
> diff --git a/drivers/net/e1000/base/e1000_defines.h
> b/drivers/net/e1000/base/e1000_defines.h
> index 278c507..20c4153 100644
> --- a/drivers/net/e1000/base/e1000_defines.h
> +++ b/drivers/net/e1000/base/e1000_defines.h
> @@ -347,8 +347,8 @@ POSSIBILITY OF SUCH DAMAGE.
>  #define SPEED_100      100
>  #define SPEED_1000     1000
>  #define SPEED_2500     2500
> -#define HALF_DUPLEX    1
> -#define FULL_DUPLEX    2
> +#define HALF_DUPLEX    0
> +#define FULL_DUPLEX    1
>
>  #define PHY_FORCE_TIME 20
>
> diff --git a/drivers/net/e1000/base/e1000_hw.h
> b/drivers/net/e1000/base/e1000_hw.h
> index 4dd92a3..b48a759 100644
> --- a/drivers/net/e1000/base/e1000_hw.h
> +++ b/drivers/net/e1000/base/e1000_hw.h
> @@ -682,7 +682,7 @@ struct e1000_mac_operations {
>         void (*clear_vfta)(struct e1000_hw *);
>         s32  (*get_bus_info)(struct e1000_hw *);
>         void (*set_lan_id)(struct e1000_hw *);
> -       s32  (*get_link_up_info)(struct e1000_hw *, u16 *, u16 *);
> +       s32  (*get_link_up_info)(struct e1000_hw *, u32 *, u16 *);
>         s32  (*led_on)(struct e1000_hw *);
>         s32  (*led_off)(struct e1000_hw *);
>         void (*update_mc_addr_list)(struct e1000_hw *, u8 *, u32);
> diff --git a/drivers/net/e1000/base/e1000_ich8lan.c
> b/drivers/net/e1000/base/e1000_ich8lan.c
> index 3b1627b..7fe9955 100644
> --- a/drivers/net/e1000/base/e1000_ich8lan.c
> +++ b/drivers/net/e1000/base/e1000_ich8lan.c
> @@ -104,7 +104,7 @@ STATIC s32  e1000_setup_link_ich8lan(struct e1000_hw
> *hw);
>  STATIC s32  e1000_setup_copper_link_ich8lan(struct e1000_hw *hw);
>  STATIC s32  e1000_setup_copper_link_pch_lpt(struct e1000_hw *hw);
>  STATIC s32  e1000_get_link_up_info_ich8lan(struct e1000_hw *hw,
> -                                          u16 *speed, u16 *duplex);
> +                                          u32 *speed, u16 *duplex);
>  STATIC s32  e1000_cleanup_led_ich8lan(struct e1000_hw *hw);
>  STATIC s32  e1000_led_on_ich8lan(struct e1000_hw *hw);
>  STATIC s32  e1000_led_off_ich8lan(struct e1000_hw *hw);
> @@ -4561,7 +4561,7 @@ STATIC s32 e1000_setup_copper_link_pch_lpt(struct
> e1000_hw *hw)
>   *  information and then calls the Kumeran lock loss workaround for links
> at
>   *  gigabit speeds.
>   **/
> -STATIC s32 e1000_get_link_up_info_ich8lan(struct e1000_hw *hw, u16 *speed,
> +STATIC s32 e1000_get_link_up_info_ich8lan(struct e1000_hw *hw, u32 *speed,
>                                           u16 *duplex)
>  {
>         s32 ret_val;
> diff --git a/drivers/net/e1000/base/e1000_mac.c
> b/drivers/net/e1000/base/e1000_mac.c
> index c8ec049..6703a17 100644
> --- a/drivers/net/e1000/base/e1000_mac.c
> +++ b/drivers/net/e1000/base/e1000_mac.c
> @@ -106,7 +106,7 @@ void e1000_null_mac_generic(struct e1000_hw
> E1000_UNUSEDARG *hw)
>   *  @hw: pointer to the HW structure
>   **/
>  s32 e1000_null_link_info(struct e1000_hw E1000_UNUSEDARG *hw,
> -                        u16 E1000_UNUSEDARG *s, u16 E1000_UNUSEDARG *d)
> +                        u32 E1000_UNUSEDARG *s, u16 E1000_UNUSEDARG *d)
>  {
>         DEBUGFUNC("e1000_null_link_info");
>         UNREFERENCED_3PARAMETER(hw, s, d);
> @@ -1346,7 +1346,8 @@ s32 e1000_config_fc_after_link_up_generic(struct
> e1000_hw *hw)
>         s32 ret_val = E1000_SUCCESS;
>         u32 pcs_status_reg, pcs_adv_reg, pcs_lp_ability_reg, pcs_ctrl_reg;
>         u16 mii_status_reg, mii_nway_adv_reg, mii_nway_lp_ability_reg;
> -       u16 speed, duplex;
> +       u32 speed;
> +       u16 duplex;
>
>         DEBUGFUNC("e1000_config_fc_after_link_up_generic");
>
> @@ -1648,7 +1649,7 @@ s32 e1000_config_fc_after_link_up_generic(struct
> e1000_hw *hw)
>   *  Read the status register for the current speed/duplex and store the
> current
>   *  speed and duplex for copper connections.
>   **/
> -s32 e1000_get_speed_and_duplex_copper_generic(struct e1000_hw *hw, u16
> *speed,
> +s32 e1000_get_speed_and_duplex_copper_generic(struct e1000_hw *hw, u32
> *speed,
>                                               u16 *duplex)
>  {
>         u32 status;
> @@ -1688,7 +1689,7 @@ s32 e1000_get_speed_and_duplex_copper_generic(struct
> e1000_hw *hw, u16 *speed,
>   *  for fiber/serdes links.
>   **/
>  s32 e1000_get_speed_and_duplex_fiber_serdes_generic(struct e1000_hw
> E1000_UNUSEDARG *hw,
> -                                                   u16 *speed, u16
> *duplex)
> +                                                   u32 *speed, u16
> *duplex)
>  {
>         DEBUGFUNC("e1000_get_speed_and_duplex_fiber_serdes_generic");
>         UNREFERENCED_1PARAMETER(hw);
> diff --git a/drivers/net/e1000/base/e1000_mac.h
> b/drivers/net/e1000/base/e1000_mac.h
> index 5a7ce4a..987df76 100644
> --- a/drivers/net/e1000/base/e1000_mac.h
> +++ b/drivers/net/e1000/base/e1000_mac.h
> @@ -40,7 +40,7 @@ void e1000_init_mac_ops_generic(struct e1000_hw *hw);
>  #endif /* E1000_REMOVED */
>  void e1000_null_mac_generic(struct e1000_hw *hw);
>  s32  e1000_null_ops_generic(struct e1000_hw *hw);
> -s32  e1000_null_link_info(struct e1000_hw *hw, u16 *s, u16 *d);
> +s32  e1000_null_link_info(struct e1000_hw *hw, u32 *s, u16 *d);
>  bool e1000_null_mng_mode(struct e1000_hw *hw);
>  void e1000_null_update_mc(struct e1000_hw *hw, u8 *h, u32 a);
>  void e1000_null_write_vfta(struct e1000_hw *hw, u32 a, u32 b);
> @@ -61,10 +61,10 @@ s32  e1000_get_bus_info_pcie_generic(struct e1000_hw
> *hw);
>  void e1000_set_lan_id_single_port(struct e1000_hw *hw);
>  void e1000_set_lan_id_multi_port_pci(struct e1000_hw *hw);
>  s32  e1000_get_hw_semaphore_generic(struct e1000_hw *hw);
> -s32  e1000_get_speed_and_duplex_copper_generic(struct e1000_hw *hw, u16
> *speed,
> +s32  e1000_get_speed_and_duplex_copper_generic(struct e1000_hw *hw, u32
> *speed,
>                                                u16 *duplex);
>  s32  e1000_get_speed_and_duplex_fiber_serdes_generic(struct e1000_hw *hw,
> -                                                    u16 *speed, u16
> *duplex);
> +                                                    u32 *speed, u16
> *duplex);
>  s32  e1000_id_led_init_generic(struct e1000_hw *hw);
>  s32  e1000_led_on_generic(struct e1000_hw *hw);
>  s32  e1000_led_off_generic(struct e1000_hw *hw);
> diff --git a/drivers/net/e1000/base/e1000_vf.c
> b/drivers/net/e1000/base/e1000_vf.c
> index 778561e..2221f1c 100644
> --- a/drivers/net/e1000/base/e1000_vf.c
> +++ b/drivers/net/e1000/base/e1000_vf.c
> @@ -43,7 +43,7 @@ STATIC s32 e1000_setup_link_vf(struct e1000_hw *hw);
>  STATIC s32 e1000_get_bus_info_pcie_vf(struct e1000_hw *hw);
>  STATIC s32 e1000_init_mac_params_vf(struct e1000_hw *hw);
>  STATIC s32 e1000_check_for_link_vf(struct e1000_hw *hw);
> -STATIC s32 e1000_get_link_up_info_vf(struct e1000_hw *hw, u16 *speed,
> +STATIC s32 e1000_get_link_up_info_vf(struct e1000_hw *hw, u32 *speed,
>                                      u16 *duplex);
>  STATIC s32 e1000_init_hw_vf(struct e1000_hw *hw);
>  STATIC s32 e1000_reset_hw_vf(struct e1000_hw *hw);
> @@ -220,7 +220,7 @@ STATIC s32 e1000_get_bus_info_pcie_vf(struct e1000_hw
> *hw)
>   *  Since we cannot read the PHY and get accurate link info, we must rely
> upon
>   *  the status register's data which is often stale and inaccurate.
>   **/
> -STATIC s32 e1000_get_link_up_info_vf(struct e1000_hw *hw, u16 *speed,
> +STATIC s32 e1000_get_link_up_info_vf(struct e1000_hw *hw, u32 *speed,
>                                      u16 *duplex)
>  {
>         s32 status;
> diff --git a/drivers/net/e1000/base/e1000_vf.h
> b/drivers/net/e1000/base/e1000_vf.h
> index 6d5bd99..9d801ad 100644
> --- a/drivers/net/e1000/base/e1000_vf.h
> +++ b/drivers/net/e1000/base/e1000_vf.h
> @@ -201,7 +201,7 @@ struct e1000_mac_operations {
>         s32  (*check_for_link)(struct e1000_hw *);
>         void (*clear_vfta)(struct e1000_hw *);
>         s32  (*get_bus_info)(struct e1000_hw *);
> -       s32  (*get_link_up_info)(struct e1000_hw *, u16 *, u16 *);
> +       s32  (*get_link_up_info)(struct e1000_hw *, u32 *, u16 *);
>         void (*update_mc_addr_list)(struct e1000_hw *, u8 *, u32);
>         s32  (*reset_hw)(struct e1000_hw *);
>         s32  (*init_hw)(struct e1000_hw *);
> diff --git a/drivers/net/e1000/em_ethdev.c b/drivers/net/e1000/em_ethdev.c
> index 72f792c..35ef558 100644
> --- a/drivers/net/e1000/em_ethdev.c
> +++ b/drivers/net/e1000/em_ethdev.c
> @@ -493,6 +493,9 @@ eth_em_start(struct rte_eth_dev *dev)
>         struct e1000_hw *hw =
>                 E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
>         int ret, mask;
> +       uint32_t *speeds;
> +       int num_speeds;
> +       bool autoneg;
>
>         PMD_INIT_FUNC_TRACE();
>
> @@ -547,56 +550,46 @@ eth_em_start(struct rte_eth_dev *dev)
>         E1000_WRITE_REG(hw, E1000_ITR, UINT16_MAX);
>
>         /* Setup link speed and duplex */
> -       switch (dev->data->dev_conf.link_speed) {
> -       case ETH_LINK_SPEED_AUTONEG:
> -               if (dev->data->dev_conf.link_duplex ==
> ETH_LINK_AUTONEG_DUPLEX)
> -                       hw->phy.autoneg_advertised =
> E1000_ALL_SPEED_DUPLEX;
> -               else if (dev->data->dev_conf.link_duplex ==
> -                                       ETH_LINK_HALF_DUPLEX)
> -                       hw->phy.autoneg_advertised = E1000_ALL_HALF_DUPLEX;
> -               else if (dev->data->dev_conf.link_duplex ==
> -                                       ETH_LINK_FULL_DUPLEX)
> -                       hw->phy.autoneg_advertised = E1000_ALL_FULL_DUPLEX;
> -               else
> -                       goto error_invalid_config;
> -               break;
> -       case ETH_LINK_SPEED_10:
> -               if (dev->data->dev_conf.link_duplex ==
> ETH_LINK_AUTONEG_DUPLEX)
> -                       hw->phy.autoneg_advertised = E1000_ALL_10_SPEED;
> -               else if (dev->data->dev_conf.link_duplex ==
> -                                       ETH_LINK_HALF_DUPLEX)
> -                       hw->phy.autoneg_advertised = ADVERTISE_10_HALF;
> -               else if (dev->data->dev_conf.link_duplex ==
> -                                       ETH_LINK_FULL_DUPLEX)
> -                       hw->phy.autoneg_advertised = ADVERTISE_10_FULL;
> -               else
> -                       goto error_invalid_config;
> -               break;
> -       case ETH_LINK_SPEED_100:
> -               if (dev->data->dev_conf.link_duplex ==
> ETH_LINK_AUTONEG_DUPLEX)
> -                       hw->phy.autoneg_advertised = E1000_ALL_100_SPEED;
> -               else if (dev->data->dev_conf.link_duplex ==
> -                                       ETH_LINK_HALF_DUPLEX)
> -                       hw->phy.autoneg_advertised = ADVERTISE_100_HALF;
> -               else if (dev->data->dev_conf.link_duplex ==
> -                                       ETH_LINK_FULL_DUPLEX)
> -                       hw->phy.autoneg_advertised = ADVERTISE_100_FULL;
> -               else
> +       speeds = &dev->data->dev_conf.link_speeds;
> +       if (*speeds == ETH_LINK_SPEED_AUTONEG) {
> +               hw->phy.autoneg_advertised = E1000_ALL_SPEED_DUPLEX;
> +       } else {
> +               num_speeds = 0;
> +               autoneg = ~(*speeds & ETH_LINK_SPEED_NO_AUTONEG);
> +
> +               /* Reset */
> +               hw->phy.autoneg_advertised = 0;
> +
> +               if (*speeds & ~(ETH_LINK_SPEED_10M_HD | ETH_LINK_SPEED_10M
> |
> +                               ETH_LINK_SPEED_100M_HD |
> ETH_LINK_SPEED_100M |
> +                               ETH_LINK_SPEED_1G)) {
> +                       num_speeds = -1;
>                         goto error_invalid_config;
> -               break;
> -       case ETH_LINK_SPEED_1000:
> -               if ((dev->data->dev_conf.link_duplex ==
> -                               ETH_LINK_AUTONEG_DUPLEX) ||
> -                       (dev->data->dev_conf.link_duplex ==
> -                                       ETH_LINK_FULL_DUPLEX))
> -                       hw->phy.autoneg_advertised = ADVERTISE_1000_FULL;
> -               else
> +               }
> +               if (*speeds & ETH_LINK_SPEED_10M_HD) {
> +                       hw->phy.autoneg_advertised |= ADVERTISE_10_HALF;
> +                       num_speeds++;
> +               }
> +               if (*speeds & ETH_LINK_SPEED_10M) {
> +                       hw->phy.autoneg_advertised |= ADVERTISE_10_FULL;
> +                       num_speeds++;
> +               }
> +               if (*speeds & ETH_LINK_SPEED_100M_HD) {
> +                       hw->phy.autoneg_advertised |= ADVERTISE_100_HALF;
> +                       num_speeds++;
> +               }
> +               if (*speeds & ETH_LINK_SPEED_100M) {
> +                       hw->phy.autoneg_advertised |= ADVERTISE_100_FULL;
> +                       num_speeds++;
> +               }
> +               if (*speeds & ETH_LINK_SPEED_1G) {
> +                       hw->phy.autoneg_advertised |= ADVERTISE_1000_FULL;
> +                       num_speeds++;
> +               }
> +               if (num_speeds == 0 || (!autoneg && (num_speeds > 2)))
>                         goto error_invalid_config;
> -               break;
> -       case ETH_LINK_SPEED_10000:
> -       default:
> -               goto error_invalid_config;
>         }
> +
>         e1000_setup_link(hw);
>
>         /* check if lsc interrupt feature is enabled */
> @@ -616,9 +609,8 @@ eth_em_start(struct rte_eth_dev *dev)
>         return (0);
>
>  error_invalid_config:
> -       PMD_INIT_LOG(ERR, "Invalid link_speed/link_duplex (%u/%u) for port
> %u",
> -                    dev->data->dev_conf.link_speed,
> -                    dev->data->dev_conf.link_duplex, dev->data->port_id);
> +       PMD_INIT_LOG(ERR, "Invalid advertised speeds (%u) for port %u",
> +                    dev->data->dev_conf.link_speeds, dev->data->port_id);
>         em_dev_clear_queues(dev);
>         return (-EINVAL);
>  }
> @@ -934,11 +926,11 @@ eth_em_infos_get(struct rte_eth_dev *dev, struct
> rte_eth_dev_info *dev_info)
>         dev_info->max_rx_queues = 1;
>         dev_info->max_tx_queues = 1;
>
> -       dev_info->speed_capa = ETH_SPEED_CAP_10M_HD |
> -                                       ETH_SPEED_CAP_10M_FD |
> -                                       ETH_SPEED_CAP_100M_HD |
> -                                       ETH_SPEED_CAP_100M_FD |
> -                                       ETH_SPEED_CAP_1G;
> +       dev_info->speed_capa = ETH_LINK_SPEED_10M_HD |
> +                                       ETH_LINK_SPEED_10M |
> +                                       ETH_LINK_SPEED_100M_HD |
> +                                       ETH_LINK_SPEED_100M |
> +                                       ETH_LINK_SPEED_1G;
>  }
>
>  /* return 0 means link status changed, -1 means not changed */
> @@ -987,13 +979,16 @@ eth_em_link_update(struct rte_eth_dev *dev, int
> wait_to_complete)
>
>         /* Now we check if a transition has happened */
>         if (link_check && (link.link_status == 0)) {
> +               uint16_t duplex;
>                 hw->mac.ops.get_link_up_info(hw, &link.link_speed,
> -                       &link.link_duplex);
> -               link.link_status = 1;
> +                       &duplex);
> +               link.link_duplex = (duplex) ? ETH_LINK_FULL_DUPLEX :
> +                                               ETH_LINK_HALF_DUPLEX;
> +               link.link_status = ETH_LINK_UP;
>         } else if (!link_check && (link.link_status == 1)) {
>                 link.link_speed = 0;
> -               link.link_duplex = 0;
> -               link.link_status = 0;
> +               link.link_duplex = ETH_LINK_HALF_DUPLEX;
> +               link.link_status = ETH_LINK_DOWN;
>         }
>         rte_em_dev_atomic_write_link_status(dev, &link);
>
> diff --git a/drivers/net/e1000/igb_ethdev.c
> b/drivers/net/e1000/igb_ethdev.c
> index 927f5d9..2bbac02 100644
> --- a/drivers/net/e1000/igb_ethdev.c
> +++ b/drivers/net/e1000/igb_ethdev.c
> @@ -889,6 +889,9 @@ eth_igb_start(struct rte_eth_dev *dev)
>         int ret, mask;
>         uint32_t intr_vector = 0;
>         uint32_t ctrl_ext;
> +       uint32_t *speeds;
> +       int num_speeds;
> +       bool autoneg;
>
>         PMD_INIT_FUNC_TRACE();
>
> @@ -984,48 +987,46 @@ eth_igb_start(struct rte_eth_dev *dev)
>         }
>
>         /* Setup link speed and duplex */
> -       switch (dev->data->dev_conf.link_speed) {
> -       case ETH_LINK_SPEED_AUTONEG:
> -               if (dev->data->dev_conf.link_duplex ==
> ETH_LINK_AUTONEG_DUPLEX)
> -                       hw->phy.autoneg_advertised =
> E1000_ALL_SPEED_DUPLEX;
> -               else if (dev->data->dev_conf.link_duplex ==
> ETH_LINK_HALF_DUPLEX)
> -                       hw->phy.autoneg_advertised = E1000_ALL_HALF_DUPLEX;
> -               else if (dev->data->dev_conf.link_duplex ==
> ETH_LINK_FULL_DUPLEX)
> -                       hw->phy.autoneg_advertised = E1000_ALL_FULL_DUPLEX;
> -               else
> -                       goto error_invalid_config;
> -               break;
> -       case ETH_LINK_SPEED_10:
> -               if (dev->data->dev_conf.link_duplex ==
> ETH_LINK_AUTONEG_DUPLEX)
> -                       hw->phy.autoneg_advertised = E1000_ALL_10_SPEED;
> -               else if (dev->data->dev_conf.link_duplex ==
> ETH_LINK_HALF_DUPLEX)
> -                       hw->phy.autoneg_advertised = ADVERTISE_10_HALF;
> -               else if (dev->data->dev_conf.link_duplex ==
> ETH_LINK_FULL_DUPLEX)
> -                       hw->phy.autoneg_advertised = ADVERTISE_10_FULL;
> -               else
> -                       goto error_invalid_config;
> -               break;
> -       case ETH_LINK_SPEED_100:
> -               if (dev->data->dev_conf.link_duplex ==
> ETH_LINK_AUTONEG_DUPLEX)
> -                       hw->phy.autoneg_advertised = E1000_ALL_100_SPEED;
> -               else if (dev->data->dev_conf.link_duplex ==
> ETH_LINK_HALF_DUPLEX)
> -                       hw->phy.autoneg_advertised = ADVERTISE_100_HALF;
> -               else if (dev->data->dev_conf.link_duplex ==
> ETH_LINK_FULL_DUPLEX)
> -                       hw->phy.autoneg_advertised = ADVERTISE_100_FULL;
> -               else
> +       speeds = &dev->data->dev_conf.link_speeds;
> +       if (*speeds == ETH_LINK_SPEED_AUTONEG) {
> +               hw->phy.autoneg_advertised = E1000_ALL_SPEED_DUPLEX;
> +       } else {
> +               num_speeds = 0;
> +               autoneg = ~(*speeds & ETH_LINK_SPEED_NO_AUTONEG);
> +
> +               /* Reset */
> +               hw->phy.autoneg_advertised = 0;
> +
> +               if (*speeds & ~(ETH_LINK_SPEED_10M_HD | ETH_LINK_SPEED_10M
> |
> +                               ETH_LINK_SPEED_100M_HD |
> ETH_LINK_SPEED_100M |
> +                               ETH_LINK_SPEED_1G)) {
> +                       num_speeds = -1;
>                         goto error_invalid_config;
> -               break;
> -       case ETH_LINK_SPEED_1000:
> -               if ((dev->data->dev_conf.link_duplex ==
> ETH_LINK_AUTONEG_DUPLEX) ||
> -                               (dev->data->dev_conf.link_duplex ==
> ETH_LINK_FULL_DUPLEX))
> -                       hw->phy.autoneg_advertised = ADVERTISE_1000_FULL;
> -               else
> +               }
> +               if (*speeds & ETH_LINK_SPEED_10M_HD) {
> +                       hw->phy.autoneg_advertised |= ADVERTISE_10_HALF;
> +                       num_speeds++;
> +               }
> +               if (*speeds & ETH_LINK_SPEED_10M) {
> +                       hw->phy.autoneg_advertised |= ADVERTISE_10_FULL;
> +                       num_speeds++;
> +               }
> +               if (*speeds & ETH_LINK_SPEED_100M_HD) {
> +                       hw->phy.autoneg_advertised |= ADVERTISE_100_HALF;
> +                       num_speeds++;
> +               }
> +               if (*speeds & ETH_LINK_SPEED_100M) {
> +                       hw->phy.autoneg_advertised |= ADVERTISE_100_FULL;
> +                       num_speeds++;
> +               }
> +               if (*speeds & ETH_LINK_SPEED_1G) {
> +                       hw->phy.autoneg_advertised |= ADVERTISE_1000_FULL;
> +                       num_speeds++;
> +               }
> +               if (num_speeds == 0 || (!autoneg && (num_speeds > 2)))
>                         goto error_invalid_config;
> -               break;
> -       case ETH_LINK_SPEED_10000:
> -       default:
> -               goto error_invalid_config;
>         }
> +
>         e1000_setup_link(hw);
>
>         /* check if lsc interrupt feature is enabled */
> @@ -1055,9 +1056,8 @@ eth_igb_start(struct rte_eth_dev *dev)
>         return (0);
>
>  error_invalid_config:
> -       PMD_INIT_LOG(ERR, "Invalid link_speed/link_duplex (%u/%u) for port
> %u",
> -                    dev->data->dev_conf.link_speed,
> -                    dev->data->dev_conf.link_duplex, dev->data->port_id);
> +       PMD_INIT_LOG(ERR, "Invalid advertised speeds (%u) for port %u",
> +                    dev->data->dev_conf.link_speeds, dev->data->port_id);
>         igb_dev_clear_queues(dev);
>         return (-EINVAL);
>  }
> @@ -1571,11 +1571,11 @@ eth_igb_infos_get(struct rte_eth_dev *dev, struct
> rte_eth_dev_info *dev_info)
>                 .txq_flags = 0,
>         };
>
> -       dev_info->speed_capa = ETH_SPEED_CAP_10M_HD |
> -                                       ETH_SPEED_CAP_10M_FD |
> -                                       ETH_SPEED_CAP_100M_HD |
> -                                       ETH_SPEED_CAP_100M_FD |
> -                                       ETH_SPEED_CAP_1G;
> +       dev_info->speed_capa = ETH_LINK_SPEED_10M_HD |
> +                                       ETH_LINK_SPEED_10M |
> +                                       ETH_LINK_SPEED_100M_HD |
> +                                       ETH_LINK_SPEED_100M |
> +                                       ETH_LINK_SPEED_1G;
>  }
>
>  static void
> @@ -1681,13 +1681,19 @@ eth_igb_link_update(struct rte_eth_dev *dev, int
> wait_to_complete)
>
>         /* Now we check if a transition has happened */
>         if (link_check) {
> +               uint16_t duplex;
>                 hw->mac.ops.get_link_up_info(hw, &link.link_speed,
> -                                         &link.link_duplex);
> -               link.link_status = 1;
> +                                         &duplex);
> +               link.link_duplex = (duplex) ? ETH_LINK_FULL_DUPLEX :
> +
>  ETH_LINK_HALF_DUPLEX ;
> +               link.link_status = ETH_LINK_UP;
> +               link.link_autoneg = ~(dev->data->dev_conf.link_speeds &
> +                                               ETH_LINK_SPEED_NO_AUTONEG);
>         } else if (!link_check) {
>                 link.link_speed = 0;
> -               link.link_duplex = 0;
> -               link.link_status = 0;
> +               link.link_duplex = ETH_LINK_HALF_DUPLEX;
> +               link.link_status = ETH_LINK_DOWN;
> +               link.link_autoneg = ETH_LINK_SPEED_FIXED;
>         }
>         rte_igb_dev_atomic_write_link_status(dev, &link);
>
> diff --git a/drivers/net/fm10k/fm10k_ethdev.c
> b/drivers/net/fm10k/fm10k_ethdev.c
> index ca6357c..6e05355 100644
> --- a/drivers/net/fm10k/fm10k_ethdev.c
> +++ b/drivers/net/fm10k/fm10k_ethdev.c
> @@ -862,7 +862,7 @@ fm10k_link_update(struct rte_eth_dev *dev,
>          * is no 50Gbps Ethernet. */
>         dev->data->dev_link.link_speed  = 0;
>         dev->data->dev_link.link_duplex = ETH_LINK_FULL_DUPLEX;
> -       dev->data->dev_link.link_status = 1;
> +       dev->data->dev_link.link_status = ETH_LINK_UP;
>
>         return 0;
>  }
> @@ -964,9 +964,9 @@ fm10k_dev_infos_get(struct rte_eth_dev *dev,
>                                 ETH_TXQ_FLAGS_NOOFFLOADS,
>         };
>
> -       dev_info->speed_capa = ETH_SPEED_CAP_1G | ETH_SPEED_CAP_2_5G |
> -                                       ETH_SPEED_CAP_10G |
> ETH_SPEED_CAP_25G |
> -                                       ETH_SPEED_CAP_40G |
> ETH_SPEED_CAP_100G;
> +       dev_info->speed_capa = ETH_LINK_SPEED_1G | ETH_LINK_SPEED_2_5G |
> +                               ETH_LINK_SPEED_10G | ETH_LINK_SPEED_25G |
> +                               ETH_LINK_SPEED_40G | ETH_LINK_SPEED_100G;
>  }
>
>  static int
> diff --git a/drivers/net/i40e/i40e_ethdev.c
> b/drivers/net/i40e/i40e_ethdev.c
> index 8a5dfbf..b18e81f 100644
> --- a/drivers/net/i40e/i40e_ethdev.c
> +++ b/drivers/net/i40e/i40e_ethdev.c
> @@ -835,27 +835,20 @@ i40e_vsi_disable_queues_intr(struct i40e_vsi *vsi)
>  }
>
>  static inline uint8_t
> -i40e_parse_link_speed(uint16_t eth_link_speed)
> +i40e_parse_link_speeds(uint16_t link_speeds)
>  {
>         uint8_t link_speed = I40E_LINK_SPEED_UNKNOWN;
>
> -       switch (eth_link_speed) {
> -       case ETH_LINK_SPEED_40G:
> -               link_speed = I40E_LINK_SPEED_40GB;
> -               break;
> -       case ETH_LINK_SPEED_20G:
> -               link_speed = I40E_LINK_SPEED_20GB;
> -               break;
> -       case ETH_LINK_SPEED_10G:
> -               link_speed = I40E_LINK_SPEED_10GB;
> -               break;
> -       case ETH_LINK_SPEED_1000:
> -               link_speed = I40E_LINK_SPEED_1GB;
> -               break;
> -       case ETH_LINK_SPEED_100:
> -               link_speed = I40E_LINK_SPEED_100MB;
> -               break;
> -       }
> +       if (link_speeds & ETH_LINK_SPEED_40G)
> +               link_speed |= I40E_LINK_SPEED_40GB;
> +       if (link_speeds & ETH_LINK_SPEED_20G)
> +               link_speed |= I40E_LINK_SPEED_20GB;
> +       if (link_speeds & ETH_LINK_SPEED_10G)
> +               link_speed |= I40E_LINK_SPEED_10GB;
> +       if (link_speeds & ETH_LINK_SPEED_1G)
> +               link_speed |= I40E_LINK_SPEED_1GB;
> +       if (link_speeds & ETH_LINK_SPEED_100M)
> +               link_speed |= I40E_LINK_SPEED_100MB;
>
>         return link_speed;
>  }
> @@ -924,9 +917,9 @@ i40e_apply_link_speed(struct rte_eth_dev *dev)
>         struct i40e_hw *hw =
> I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
>         struct rte_eth_conf *conf = &dev->data->dev_conf;
>
> -       speed = i40e_parse_link_speed(conf->link_speed);
> +       speed = i40e_parse_link_speeds(conf->link_speeds);
>         abilities |= I40E_AQ_PHY_ENABLE_ATOMIC_LINK;
> -       if (conf->link_speed == ETH_LINK_SPEED_AUTONEG)
> +       if (conf->link_speeds & ETH_LINK_SPEED_AUTONEG)
>                 abilities |= I40E_AQ_PHY_AN_ENABLED;
>         else
>                 abilities |= I40E_AQ_PHY_LINK_ENABLED;
> @@ -944,10 +937,8 @@ i40e_dev_start(struct rte_eth_dev *dev)
>
>         hw->adapter_stopped = 0;
>
> -       if ((dev->data->dev_conf.link_duplex != ETH_LINK_AUTONEG_DUPLEX) &&
> -               (dev->data->dev_conf.link_duplex != ETH_LINK_FULL_DUPLEX))
> {
> -               PMD_INIT_LOG(ERR, "Invalid link_duplex (%hu) for port
> %hhu",
> -                            dev->data->dev_conf.link_duplex,
> +       if (dev->data->dev_conf.link_speeds & ETH_LINK_SPEED_NO_AUTONEG) {
> +               PMD_INIT_LOG(ERR, "Invalid link_speeds for port %hhu;
> autonegociation disabled",
>                              dev->data->port_id);
>                 return -EINVAL;
>         }
> @@ -995,6 +986,13 @@ i40e_dev_start(struct rte_eth_dev *dev)
>         }
>
>         /* Apply link configure */
> +       if (dev->data->dev_conf.link_speeds & ~(ETH_LINK_SPEED_100M |
> +                               ETH_LINK_SPEED_1G | ETH_LINK_SPEED_10G |
> +                               ETH_LINK_SPEED_20G | ETH_LINK_SPEED_40G)) {
> +               PMD_DRV_LOG(ERR, "Invalid link setting");
> +               goto err_up;
> +       }
> +
>         ret = i40e_apply_link_speed(dev);
>         if (I40E_SUCCESS != ret) {
>                 PMD_DRV_LOG(ERR, "Fail to apply link setting");
> @@ -1209,7 +1207,7 @@ i40e_dev_link_update(struct rte_eth_dev *dev,
>                 /* Get link status information from hardware */
>                 status = i40e_aq_get_link_info(hw, false, &link_status,
> NULL);
>                 if (status != I40E_SUCCESS) {
> -                       link.link_speed = ETH_LINK_SPEED_100;
> +                       link.link_speed = ETH_SPEED_NUM_100M;
>                         link.link_duplex = ETH_LINK_FULL_DUPLEX;
>                         PMD_DRV_LOG(ERR, "Failed to get link info");
>                         goto out;
> @@ -1231,25 +1229,28 @@ i40e_dev_link_update(struct rte_eth_dev *dev,
>         /* Parse the link status */
>         switch (link_status.link_speed) {
>         case I40E_LINK_SPEED_100MB:
> -               link.link_speed = ETH_LINK_SPEED_100;
> +               link.link_speed = ETH_SPEED_NUM_100M;
>                 break;
>         case I40E_LINK_SPEED_1GB:
> -               link.link_speed = ETH_LINK_SPEED_1000;
> +               link.link_speed = ETH_SPEED_NUM_1G;
>                 break;
>         case I40E_LINK_SPEED_10GB:
> -               link.link_speed = ETH_LINK_SPEED_10G;
> +               link.link_speed = ETH_SPEED_NUM_10G;
>                 break;
>         case I40E_LINK_SPEED_20GB:
> -               link.link_speed = ETH_LINK_SPEED_20G;
> +               link.link_speed = ETH_SPEED_NUM_20G;
>                 break;
>         case I40E_LINK_SPEED_40GB:
> -               link.link_speed = ETH_LINK_SPEED_40G;
> +               link.link_speed = ETH_SPEED_NUM_40G;
>                 break;
>         default:
> -               link.link_speed = ETH_LINK_SPEED_100;
> +               link.link_speed = ETH_SPEED_NUM_100M;
>                 break;
>         }
>
> +       link.link_autoneg = ~(dev->data->dev_conf.link_speeds &
> +                                               ETH_LINK_SPEED_NO_AUTONEG);
> +
>  out:
>         rte_i40e_dev_atomic_write_link_status(dev, &link);
>         if (link.link_status == old.link_status)
> @@ -1687,10 +1688,10 @@ i40e_dev_info_get(struct rte_eth_dev *dev, struct
> rte_eth_dev_info *dev_info)
>
>         if (i40e_is_40G_device(hw->device_id))
>                 /* For XL710 */
> -               dev_info->speed_capa = ETH_SPEED_CAP_1G |
> ETH_SPEED_CAP_10G;
> +               dev_info->speed_capa = ETH_LINK_SPEED_1G |
> ETH_LINK_SPEED_10G;
>         else
>                 /* For X710 */
> -               dev_info->speed_capa = ETH_SPEED_CAP_10G |
> ETH_SPEED_CAP_40G;
> +               dev_info->speed_capa = ETH_LINK_SPEED_10G |
> ETH_LINK_SPEED_40G;
>
>  }
>
> @@ -6195,15 +6196,15 @@ i40e_timesync_enable(struct rte_eth_dev *dev)
>         uint32_t tsync_inc_h;
>
>         switch (link->link_speed) {
> -       case ETH_LINK_SPEED_40G:
> +       case ETH_SPEED_NUM_40G:
>                 tsync_inc_l = I40E_PTP_40GB_INCVAL & 0xFFFFFFFF;
>                 tsync_inc_h = I40E_PTP_40GB_INCVAL >> 32;
>                 break;
> -       case ETH_LINK_SPEED_10G:
> +       case ETH_SPEED_NUM_10G:
>                 tsync_inc_l = I40E_PTP_10GB_INCVAL & 0xFFFFFFFF;
>                 tsync_inc_h = I40E_PTP_10GB_INCVAL >> 32;
>                 break;
> -       case ETH_LINK_SPEED_1000:
> +       case ETH_SPEED_NUM_1G:
>                 tsync_inc_l = I40E_PTP_1GB_INCVAL & 0xFFFFFFFF;
>                 tsync_inc_h = I40E_PTP_1GB_INCVAL >> 32;
>                 break;
> diff --git a/drivers/net/i40e/i40e_ethdev_vf.c
> b/drivers/net/i40e/i40e_ethdev_vf.c
> index b694400..8d3acae 100644
> --- a/drivers/net/i40e/i40e_ethdev_vf.c
> +++ b/drivers/net/i40e/i40e_ethdev_vf.c
> @@ -1635,13 +1635,14 @@ i40evf_dev_link_update(struct rte_eth_dev *dev,
>          * DPDK pf host provide interfacet to acquire link status
>          * while Linux driver does not
>          */
> -       if (vf->version_major == I40E_DPDK_VERSION_MAJOR)
> +       if (vf->version_major == I40E_DPDK_VERSION_MAJOR) {
>                 i40evf_get_link_status(dev, &new_link);
> -       else {
> +       } else {
>                 /* Always assume it's up, for Linux driver PF host */
> -               new_link.link_duplex = ETH_LINK_AUTONEG_DUPLEX;
> -               new_link.link_speed  = ETH_LINK_SPEED_10000;
> -               new_link.link_status = 1;
> +               new_link.link_speed  = ETH_SPEED_NUM_10G;
> +               new_link.link_duplex = ETH_LINK_FULL_DUPLEX;
> +               new_link.link_autoneg = ETH_LINK_SPEED_NEG;
> +               new_link.link_status = ETH_LINK_UP;
>         }
>         i40evf_dev_atomic_write_link_status(dev, &new_link);
>
> diff --git a/drivers/net/ixgbe/ixgbe_ethdev.c
> b/drivers/net/ixgbe/ixgbe_ethdev.c
> index 3be84aa..f4dd1d2 100644
> --- a/drivers/net/ixgbe/ixgbe_ethdev.c
> +++ b/drivers/net/ixgbe/ixgbe_ethdev.c
> @@ -1676,14 +1676,13 @@ ixgbe_dev_start(struct rte_eth_dev *dev)
>         int mask = 0;
>         int status;
>         uint16_t vf, idx;
> +       uint32_t *link_speeds;
>
>         PMD_INIT_FUNC_TRACE();
>
>         /* IXGBE devices don't support half duplex */
> -       if ((dev->data->dev_conf.link_duplex != ETH_LINK_AUTONEG_DUPLEX) &&
> -                       (dev->data->dev_conf.link_duplex !=
> ETH_LINK_FULL_DUPLEX)) {
> -               PMD_INIT_LOG(ERR, "Invalid link_duplex (%hu) for port
> %hhu",
> -                            dev->data->dev_conf.link_duplex,
> +       if (dev->data->dev_conf.link_speeds & ETH_LINK_SPEED_NO_AUTONEG) {
> +               PMD_INIT_LOG(ERR, "Invalid link_speeds for port %hhu;
> autonegociation disabled",
>                              dev->data->port_id);
>                 return -EINVAL;
>         }
> @@ -1769,32 +1768,22 @@ ixgbe_dev_start(struct rte_eth_dev *dev)
>         if (err)
>                 goto error;
>
> -       switch(dev->data->dev_conf.link_speed) {
> -       case ETH_LINK_SPEED_AUTONEG:
> -               speed = (hw->mac.type != ixgbe_mac_82598EB) ?
> -                               IXGBE_LINK_SPEED_82599_AUTONEG :
> -                               IXGBE_LINK_SPEED_82598_AUTONEG;
> -               break;
> -       case ETH_LINK_SPEED_100:
> -               /*
> -                * Invalid for 82598 but error will be detected by
> -                * ixgbe_setup_link()
> -                */
> -               speed = IXGBE_LINK_SPEED_100_FULL;
> -               break;
> -       case ETH_LINK_SPEED_1000:
> -               speed = IXGBE_LINK_SPEED_1GB_FULL;
> -               break;
> -       case ETH_LINK_SPEED_10000:
> -               speed = IXGBE_LINK_SPEED_10GB_FULL;
> -               break;
> -       default:
> -               PMD_INIT_LOG(ERR, "Invalid link_speed (%hu) for port %hhu",
> -                            dev->data->dev_conf.link_speed,
> -                            dev->data->port_id);
> +       link_speeds = &dev->data->dev_conf.link_speeds;
> +       if (*link_speeds & ~(ETH_LINK_SPEED_100M | ETH_LINK_SPEED_1G |
> +
>  ETH_LINK_SPEED_10G)) {
> +               PMD_INIT_LOG(ERR, "Invalid link setting");
>                 goto error;
>         }
>
> +       speed = 0x0;
> +
> +       if (*link_speeds & ETH_LINK_SPEED_10G)
> +               speed |= IXGBE_LINK_SPEED_10GB_FULL;
> +       if (*link_speeds & ETH_LINK_SPEED_1G)
> +               speed |= IXGBE_LINK_SPEED_1GB_FULL;
> +       if (*link_speeds & ETH_LINK_SPEED_100M)
> +               speed |= IXGBE_LINK_SPEED_100_FULL;
> +
>         err = ixgbe_setup_link(hw, speed, link_up);
>         if (err)
>                 goto error;
> @@ -2400,15 +2389,16 @@ ixgbe_dev_info_get(struct rte_eth_dev *dev, struct
> rte_eth_dev_info *dev_info)
>         dev_info->reta_size = ETH_RSS_RETA_SIZE_128;
>         dev_info->flow_type_rss_offloads = IXGBE_RSS_OFFLOAD_ALL;
>
> -       dev_info->speed_capa = ETH_SPEED_CAP_1G | ETH_SPEED_CAP_10G;
> +       dev_info->speed_capa = ETH_LINK_SPEED_1G | ETH_LINK_SPEED_10G;
>
>         if (hw->mac.type == ixgbe_mac_X540 ||
>             hw->mac.type == ixgbe_mac_X540_vf ||
>             hw->mac.type == ixgbe_mac_X550 ||
> -           hw->mac.type == ixgbe_mac_X550_vf)
> +           hw->mac.type == ixgbe_mac_X550_vf) {
>
> -               dev_info->speed_capa |= ETH_SPEED_CAP_100M_FD /*|
> -                                       ETH_SPEED_CAP_100M_HD*/;
> +               dev_info->speed_capa |= ETH_LINK_SPEED_100M /*|
> +                                       ETH_LINK_SPEED_100M_HD*/;
> +       }
>  }
>
>  static void
> @@ -2471,9 +2461,9 @@ ixgbe_dev_link_update(struct rte_eth_dev *dev, int
> wait_to_complete)
>         int link_up;
>         int diag;
>
> -       link.link_status = 0;
> +       link.link_status = ETH_LINK_DOWN;
>         link.link_speed = 0;
> -       link.link_duplex = 0;
> +       link.link_duplex = ETH_LINK_HALF_DUPLEX;
>         memset(&old, 0, sizeof(old));
>         rte_ixgbe_dev_atomic_read_link_status(dev, &old);
>
> @@ -2486,8 +2476,8 @@ ixgbe_dev_link_update(struct rte_eth_dev *dev, int
> wait_to_complete)
>                 diag = ixgbe_check_link(hw, &link_speed, &link_up, 1);
>
>         if (diag != 0) {
> -               link.link_speed = ETH_LINK_SPEED_100;
> -               link.link_duplex = ETH_LINK_HALF_DUPLEX;
> +               link.link_speed = ETH_SPEED_NUM_100M;
> +               link.link_duplex = ETH_LINK_FULL_DUPLEX;
>                 rte_ixgbe_dev_atomic_write_link_status(dev, &link);
>                 if (link.link_status == old.link_status)
>                         return -1;
> @@ -2500,26 +2490,26 @@ ixgbe_dev_link_update(struct rte_eth_dev *dev, int
> wait_to_complete)
>                         return -1;
>                 return 0;
>         }
> -       link.link_status = 1;
> +       link.link_status = ETH_LINK_UP;
>         link.link_duplex = ETH_LINK_FULL_DUPLEX;
>
>         switch (link_speed) {
>         default:
>         case IXGBE_LINK_SPEED_UNKNOWN:
> -               link.link_duplex = ETH_LINK_HALF_DUPLEX;
> -               link.link_speed = ETH_LINK_SPEED_100;
> +               link.link_duplex = ETH_LINK_FULL_DUPLEX;
> +               link.link_speed = ETH_SPEED_NUM_100M;
>                 break;
>
>         case IXGBE_LINK_SPEED_100_FULL:
> -               link.link_speed = ETH_LINK_SPEED_100;
> +               link.link_speed = ETH_SPEED_NUM_100M;
>                 break;
>
>         case IXGBE_LINK_SPEED_1GB_FULL:
> -               link.link_speed = ETH_LINK_SPEED_1000;
> +               link.link_speed = ETH_SPEED_NUM_1G;
>                 break;
>
>         case IXGBE_LINK_SPEED_10GB_FULL:
> -               link.link_speed = ETH_LINK_SPEED_10000;
> +               link.link_speed = ETH_SPEED_NUM_10G;
>                 break;
>         }
>         rte_ixgbe_dev_atomic_write_link_status(dev, &link);
> diff --git a/drivers/net/mlx4/mlx4.c b/drivers/net/mlx4/mlx4.c
> index b45e21a..96fe4b6 100644
> --- a/drivers/net/mlx4/mlx4.c
> +++ b/drivers/net/mlx4/mlx4.c
> @@ -4207,6 +4207,8 @@ mlx4_link_update_unlocked(struct rte_eth_dev *dev,
> int wait_to_complete)
>                 dev_link.link_speed = link_speed;
>         dev_link.link_duplex = ((edata.duplex == DUPLEX_HALF) ?
>                                 ETH_LINK_HALF_DUPLEX :
> ETH_LINK_FULL_DUPLEX);
> +       dev_link.link_autoneg = ~(dev->data->dev_conf.link_speeds &
> +                                               ETH_LINK_SPEED_NO_AUTONEG);
>         if (memcmp(&dev_link, &dev->data->dev_link, sizeof(dev_link))) {
>                 /* Link status changed. */
>                 dev->data->dev_link = dev_link;
> diff --git a/drivers/net/mpipe/mpipe_tilegx.c
> b/drivers/net/mpipe/mpipe_tilegx.c
> index 743feef..5875371 100644
> --- a/drivers/net/mpipe/mpipe_tilegx.c
> +++ b/drivers/net/mpipe/mpipe_tilegx.c
> @@ -388,14 +388,16 @@ mpipe_link_update(struct rte_eth_dev *dev, int
> wait_to_complete)
>
>                 speed = state & GXIO_MPIPE_LINK_SPEED_MASK;
>
> +               new.link_autoneg = ~(dev->data->dev_conf.link_speeds &
> +                                               ETH_LINK_SPEED_NO_AUTONEG);
>                 if (speed == GXIO_MPIPE_LINK_1G) {
>                         new.link_speed = ETH_LINK_SPEED_1000;
>                         new.link_duplex = ETH_LINK_FULL_DUPLEX;
> -                       new.link_status = 1;
> +                       new.link_status = ETH_LINK_UP;
>                 } else if (speed == GXIO_MPIPE_LINK_10G) {
>                         new.link_speed = ETH_LINK_SPEED_10000;
>                         new.link_duplex = ETH_LINK_FULL_DUPLEX;
> -                       new.link_status = 1;
> +                       new.link_status = ETH_LINK_UP;
>                 }
>
>                 rc = mpipe_link_compare(&old, &new);
> diff --git a/drivers/net/null/rte_eth_null.c
> b/drivers/net/null/rte_eth_null.c
> index e244595..7704fa6 100644
> --- a/drivers/net/null/rte_eth_null.c
> +++ b/drivers/net/null/rte_eth_null.c
> @@ -79,9 +79,10 @@ struct pmd_internals {
>  static struct ether_addr eth_addr = { .addr_bytes = {0} };
>  static const char *drivername = "Null PMD";
>  static struct rte_eth_link pmd_link = {
> -       .link_speed = 10000,
> +       .link_speed = ETH_SPEED_NUM_10G,
>         .link_duplex = ETH_LINK_FULL_DUPLEX,
> -       .link_status = 0
> +       .link_status = ETH_LINK_DOWN,
> +       .link_autoneg = ETH_LINK_SPEED_NEG,
>  };
>
>  static uint16_t
> diff --git a/drivers/net/pcap/rte_eth_pcap.c
> b/drivers/net/pcap/rte_eth_pcap.c
> index f2e4634..ea7a28f 100644
> --- a/drivers/net/pcap/rte_eth_pcap.c
> +++ b/drivers/net/pcap/rte_eth_pcap.c
> @@ -125,9 +125,10 @@ static int open_single_iface(const char *iface,
> pcap_t **pcap);
>  static struct ether_addr eth_addr = { .addr_bytes = { 0, 0, 0, 0x1, 0x2,
> 0x3 } };
>  static const char *drivername = "Pcap PMD";
>  static struct rte_eth_link pmd_link = {
> -               .link_speed = 10000,
> +               .link_speed = ETH_SPEED_NUM_10G,
>                 .link_duplex = ETH_LINK_FULL_DUPLEX,
> -               .link_status = 0
> +               .link_status = ETH_LINK_DOWN,
> +               .link_autoneg = ETH_LINK_SPEED_FIXED,
>  };
>
>  static int
> @@ -430,7 +431,7 @@ eth_dev_start(struct rte_eth_dev *dev)
>
>  status_up:
>
> -       dev->data->dev_link.link_status = 1;
> +       dev->data->dev_link.link_status = ETH_LINK_UP;
>         return 0;
>  }
>
> @@ -481,7 +482,7 @@ eth_dev_stop(struct rte_eth_dev *dev)
>         }
>
>  status_down:
> -       dev->data->dev_link.link_status = 0;
> +       dev->data->dev_link.link_status = ETH_LINK_DOWN;
>  }
>
>  static int
> diff --git a/drivers/net/ring/rte_eth_ring.c
> b/drivers/net/ring/rte_eth_ring.c
> index 0ba36d5..626c381 100644
> --- a/drivers/net/ring/rte_eth_ring.c
> +++ b/drivers/net/ring/rte_eth_ring.c
> @@ -71,9 +71,10 @@ struct pmd_internals {
>
>  static const char *drivername = "Rings PMD";
>  static struct rte_eth_link pmd_link = {
> -               .link_speed = 10000,
> +               .link_speed = ETH_SPEED_NUM_10G,
>                 .link_duplex = ETH_LINK_FULL_DUPLEX,
> -               .link_status = 0
> +               .link_status = ETH_LINK_DOWN,
> +               .link_autoneg = ETH_LINK_SPEED_NEG
>  };
>
>  static uint16_t
> diff --git a/drivers/net/virtio/virtio_ethdev.c
> b/drivers/net/virtio/virtio_ethdev.c
> index 465d3cd..ecbf9f2 100644
> --- a/drivers/net/virtio/virtio_ethdev.c
> +++ b/drivers/net/virtio/virtio_ethdev.c
> @@ -1517,7 +1517,7 @@ virtio_dev_link_update(struct rte_eth_dev *dev,
> __rte_unused int wait_to_complet
>         memset(&link, 0, sizeof(link));
>         virtio_dev_atomic_read_link_status(dev, &link);
>         old = link;
> -       link.link_duplex = FULL_DUPLEX;
> +       link.link_duplex = ETH_LINK_FULL_DUPLEX;
>         link.link_speed  = SPEED_10G;
>
>         if (vtpci_with_feature(hw, VIRTIO_NET_F_STATUS)) {
> diff --git a/drivers/net/virtio/virtio_ethdev.h
> b/drivers/net/virtio/virtio_ethdev.h
> index 9026d42..424d650 100644
> --- a/drivers/net/virtio/virtio_ethdev.h
> +++ b/drivers/net/virtio/virtio_ethdev.h
> @@ -42,8 +42,6 @@
>  #define SPEED_100      100
>  #define SPEED_1000     1000
>  #define SPEED_10G      10000
> -#define HALF_DUPLEX    1
> -#define FULL_DUPLEX    2
>
>  #ifndef PAGE_SIZE
>  #define PAGE_SIZE 4096
> diff --git a/drivers/net/vmxnet3/vmxnet3_ethdev.c
> b/drivers/net/vmxnet3/vmxnet3_ethdev.c
> index a70be5c..6860360 100644
> --- a/drivers/net/vmxnet3/vmxnet3_ethdev.c
> +++ b/drivers/net/vmxnet3/vmxnet3_ethdev.c
> @@ -697,9 +697,10 @@ vmxnet3_dev_link_update(struct rte_eth_dev *dev,
> __attribute__((unused)) int wai
>         ret = VMXNET3_READ_BAR1_REG(hw, VMXNET3_REG_CMD);
>
>         if (ret & 0x1) {
> -               link.link_status = 1;
> +               link.link_status = ETH_LINK_UP;
>                 link.link_duplex = ETH_LINK_FULL_DUPLEX;
> -               link.link_speed = ETH_LINK_SPEED_10000;
> +               link.link_speed = ETH_SPEED_NUM_10G;
> +               link.link_autoneg = ETH_LINK_SPEED_FIXED;
>         }
>
>         vmxnet3_dev_atomic_write_link_status(dev, &link);
> diff --git a/drivers/net/xenvirt/rte_eth_xenvirt.c
> b/drivers/net/xenvirt/rte_eth_xenvirt.c
> index 73e8bce..fb492ee 100644
> --- a/drivers/net/xenvirt/rte_eth_xenvirt.c
> +++ b/drivers/net/xenvirt/rte_eth_xenvirt.c
> @@ -70,9 +70,10 @@ static int virtio_idx = 0;
>  static const char *drivername = "xen dummy virtio PMD";
>
>  static struct rte_eth_link pmd_link = {
> -               .link_speed = 10000,
> +               .link_speed = ETH_SPEED_NUM_10G,
>                 .link_duplex = ETH_LINK_FULL_DUPLEX,
> -               .link_status = 0
> +               .link_status = ETH_LINK_DOWN,
> +               .link_autoneg = ETH_LINK_SPEED_FIXED
>  };
>
>  static inline struct rte_mbuf *
> diff --git a/examples/ip_pipeline/config_parse.c
> b/examples/ip_pipeline/config_parse.c
> index c9b78f9..92e6a18 100644
> --- a/examples/ip_pipeline/config_parse.c
> +++ b/examples/ip_pipeline/config_parse.c
> @@ -83,8 +83,7 @@ static const struct app_link_params link_params_default
> = {
>         .mac_addr = 0,
>
>         .conf = {
> -               .link_speed = 0,
> -               .link_duplex = 0,
> +               .link_speeds = 0,
>                 .rxmode = {
>                         .mq_mode = ETH_MQ_RX_NONE,
>
> diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c
> index f593f6e..29b2960 100644
> --- a/lib/librte_ether/rte_ethdev.c
> +++ b/lib/librte_ether/rte_ethdev.c
> @@ -1072,6 +1072,55 @@ rte_eth_dev_check_mq_mode(uint8_t port_id, uint16_t
> nb_rx_q, uint16_t nb_tx_q,
>  }
>
>  int
> +rte_eth_speed_to_bm_flag(uint32_t speed, int duplex, uint32_t *flag)
> +{
> +       switch (speed) {
> +       case ETH_SPEED_NUM_10M:
> +               *flag = (duplex) ? ETH_LINK_SPEED_10M :
> +
>  ETH_LINK_SPEED_10M_HD;
> +               break;
> +       case ETH_SPEED_NUM_100M:
> +               *flag = (duplex) ? ETH_LINK_SPEED_100M :
> +
>  ETH_LINK_SPEED_100M_HD;
> +               break;
> +       case ETH_SPEED_NUM_1G:
> +               *flag = ETH_LINK_SPEED_1G;
> +               break;
> +       case ETH_SPEED_NUM_2_5G:
> +               *flag = ETH_LINK_SPEED_2_5G;
> +               break;
> +       case ETH_SPEED_NUM_5G:
> +               *flag = ETH_LINK_SPEED_5G;
> +               break;
> +       case ETH_SPEED_NUM_10G:
> +               *flag = ETH_LINK_SPEED_10G;
> +               break;
> +       case ETH_SPEED_NUM_20G:
> +               *flag = ETH_LINK_SPEED_20G;
> +               break;
> +       case ETH_SPEED_NUM_25G:
> +               *flag = ETH_LINK_SPEED_25G;
> +               break;
> +       case ETH_SPEED_NUM_40G:
> +               *flag = ETH_LINK_SPEED_40G;
> +               break;
> +       case ETH_SPEED_NUM_50G:
> +               *flag = ETH_LINK_SPEED_50G;
> +               break;
> +       case ETH_SPEED_NUM_56G:
> +               *flag = ETH_LINK_SPEED_56G;
> +               break;
> +       case ETH_SPEED_NUM_100G:
> +               *flag = ETH_LINK_SPEED_100G;
> +               break;
> +       default:
> +               return -EINVAL;
> +       }
> +
> +       return 0;
> +}
> +
> +int
>  rte_eth_dev_configure(uint8_t port_id, uint16_t nb_rx_q, uint16_t nb_tx_q,
>                       const struct rte_eth_conf *dev_conf)
>  {
> diff --git a/lib/librte_ether/rte_ethdev.h b/lib/librte_ether/rte_ethdev.h
> index 951a423..54ee6f9 100644
> --- a/lib/librte_ether/rte_ethdev.h
> +++ b/lib/librte_ether/rte_ethdev.h
> @@ -238,26 +238,59 @@ struct rte_eth_stats {
>  };
>
>  /**
> + * Device supported speeds bitmap flags
> + */
> +#define ETH_LINK_SPEED_AUTONEG         (0 << 0)  /*< Autonegociate (all
> speeds)  */
> +#define ETH_LINK_SPEED_NO_AUTONEG      (1 << 0)  /*< Disable autoneg
> (fixed speed)  */
> +#define ETH_LINK_SPEED_10M_HD          (1 << 1)  /*< 10 Mbps half-duplex
> */
> +#define ETH_LINK_SPEED_10M             (1 << 2)  /*< 10 Mbps full-duplex
> */
> +#define ETH_LINK_SPEED_100M_HD         (1 << 3)  /*< 100 Mbps half-duplex
> */
> +#define ETH_LINK_SPEED_100M            (1 << 4)  /*< 100 Mbps full-duplex
> */
> +#define ETH_LINK_SPEED_1G              (1 << 5)  /*< 1 Gbps */
> +#define ETH_LINK_SPEED_2_5G            (1 << 6)  /*< 2.5 Gbps */
> +#define ETH_LINK_SPEED_5G              (1 << 7)  /*< 5 Gbps */
> +#define ETH_LINK_SPEED_10G             (1 << 8)  /*< 10 Mbps */
> +#define ETH_LINK_SPEED_20G             (1 << 9)  /*< 20 Gbps */
> +#define ETH_LINK_SPEED_25G             (1 << 10)  /*< 25 Gbps */
> +#define ETH_LINK_SPEED_40G             (1 << 11)  /*< 40 Gbps */
> +#define ETH_LINK_SPEED_50G             (1 << 12)  /*< 50 Gbps */
> +#define ETH_LINK_SPEED_56G             (1 << 13)  /*< 56 Gbps */
> +#define ETH_LINK_SPEED_100G            (1 << 14)  /*< 100 Gbps */
> +
> +/**
> + * Ethernet numeric link speeds in Mbps
> + */
> +#define ETH_SPEED_NUM_NONE     0      /*< Not defined */
> +#define ETH_SPEED_NUM_10M      10     /*< 10 Mbps */
> +#define ETH_SPEED_NUM_100M     100    /*< 100 Mbps */
> +#define ETH_SPEED_NUM_1G       1000   /*< 1 Gbps */
> +#define ETH_SPEED_NUM_2_5G     2500   /*< 2.5 Gbps */
> +#define ETH_SPEED_NUM_5G       5000   /*< 5 Gbps */
> +#define ETH_SPEED_NUM_10G      10000  /*< 10 Mbps */
> +#define ETH_SPEED_NUM_20G      20000  /*< 20 Gbps */
> +#define ETH_SPEED_NUM_25G      25000  /*< 25 Gbps */
> +#define ETH_SPEED_NUM_40G      40000  /*< 40 Gbps */
> +#define ETH_SPEED_NUM_50G      50000  /*< 50 Gbps */
> +#define ETH_SPEED_NUM_56G      56000  /*< 56 Gbps */
> +#define ETH_SPEED_NUM_100G     100000 /*< 100 Gbps */
> +
> +/**
>   * A structure used to retrieve link-level information of an Ethernet
> port.
>   */
>  struct rte_eth_link {
> -       uint16_t link_speed;      /**< ETH_LINK_SPEED_[10, 100, 1000,
> 10000] */
> -       uint16_t link_duplex;     /**< ETH_LINK_[HALF_DUPLEX, FULL_DUPLEX]
> */
> -       uint8_t  link_status : 1; /**< 1 -> link up, 0 -> link down */
> -}__attribute__((aligned(8)));     /**< aligned for atomic64 read/write */
> -
> -#define ETH_LINK_SPEED_AUTONEG  0       /**< Auto-negotiate link speed. */
> -#define ETH_LINK_SPEED_10       10      /**< 10 megabits/second. */
> -#define ETH_LINK_SPEED_100      100     /**< 100 megabits/second. */
> -#define ETH_LINK_SPEED_1000     1000    /**< 1 gigabits/second. */
> -#define ETH_LINK_SPEED_10000    10000   /**< 10 gigabits/second. */
> -#define ETH_LINK_SPEED_10G      10000   /**< alias of 10 gigabits/second.
> */
> -#define ETH_LINK_SPEED_20G      20000   /**< 20 gigabits/second. */
> -#define ETH_LINK_SPEED_40G      40000   /**< 40 gigabits/second. */
> +       uint32_t link_speed;        /**< Link speed (ETH_SPEED_NUM_) */
> +       uint16_t link_duplex  : 1;  /**< 1 -> full duplex, 0 -> half
> duplex */
> +       uint16_t link_autoneg : 1;  /**< 1 -> link speed has been autoneg
> */
> +       uint16_t link_status  : 1;  /**< 1 -> link up, 0 -> link down */
> +} __attribute__((aligned(8)));      /**< aligned for atomic64 read/write
> */
>
> -#define ETH_LINK_AUTONEG_DUPLEX 0       /**< Auto-negotiate duplex. */
> -#define ETH_LINK_HALF_DUPLEX    1       /**< Half-duplex connection. */
> -#define ETH_LINK_FULL_DUPLEX    2       /**< Full-duplex connection. */
> +/* Utility constants */
> +#define ETH_LINK_HALF_DUPLEX    0      /**< Half-duplex connection. */
> +#define ETH_LINK_FULL_DUPLEX    1      /**< Full-duplex connection. */
> +#define ETH_LINK_SPEED_FIXED    0      /**< Link speed was not
> autonegociated. */
> +#define ETH_LINK_SPEED_NEG      1      /**< Link speed was
> autonegociated. */
> +#define ETH_LINK_DOWN          0       /**< Link is down. */
> +#define ETH_LINK_UP            1       /**< Link is up. */
>
>  /**
>   * A structure used to configure the ring threshold registers of an RX/TX
> @@ -747,10 +780,14 @@ struct rte_intr_conf {
>   * configuration settings may be needed.
>   */
>  struct rte_eth_conf {
> -       uint16_t link_speed;
> -       /**< ETH_LINK_SPEED_10[0|00|000], or 0 for autonegotation */
> -       uint16_t link_duplex;
> -       /**< ETH_LINK_[HALF_DUPLEX|FULL_DUPLEX], or 0 for autonegotation */
> +       uint32_t link_speeds; /**< bitmap of ETH_LINK_SPEED_XXX of speeds
> to be
> +                               used. ETH_LINK_SPEED_NO_AUTONEG disables
> link
> +                               autonegociation, and a unique speed shall
> be
> +                               set. Otherwise, the bitmap defines the set
> of
> +                               speeds to be advertised. If the special
> value
> +                               ETH_LINK_SPEED_AUTONEG (0) is used, all
> speeds
> +                               supported are advertised.
> +                               */
>         struct rte_eth_rxmode rxmode; /**< Port RX configuration. */
>         struct rte_eth_txmode txmode; /**< Port TX configuration. */
>         uint32_t lpbk_mode; /**< Loopback operation mode. By default the
> value
> @@ -812,26 +849,6 @@ struct rte_eth_conf {
>  #define DEV_TX_OFFLOAD_QINQ_INSERT 0x00000100
>
>  /**
> - * Device supported speeds
> - */
> -#define ETH_SPEED_CAP_NOT_PHY  (0)  /*< No phy media > */
> -#define ETH_SPEED_CAP_10M_HD   (1 << 0)  /*< 10 Mbps half-duplex> */
> -#define ETH_SPEED_CAP_10M_FD   (1 << 1)  /*< 10 Mbps full-duplex> */
> -#define ETH_SPEED_CAP_100M_HD  (1 << 2)  /*< 100 Mbps half-duplex> */
> -#define ETH_SPEED_CAP_100M_FD  (1 << 3)  /*< 100 Mbps full-duplex> */
> -#define ETH_SPEED_CAP_1G       (1 << 4)  /*< 1 Gbps > */
> -#define ETH_SPEED_CAP_2_5G     (1 << 5)  /*< 2.5 Gbps > */
> -#define ETH_SPEED_CAP_5G       (1 << 6)  /*< 5 Gbps > */
> -#define ETH_SPEED_CAP_10G      (1 << 7)  /*< 10 Mbps > */
> -#define ETH_SPEED_CAP_20G      (1 << 8)  /*< 20 Gbps > */
> -#define ETH_SPEED_CAP_25G      (1 << 9)  /*< 25 Gbps > */
> -#define ETH_SPEED_CAP_40G      (1 << 10)  /*< 40 Gbps > */
> -#define ETH_SPEED_CAP_50G      (1 << 11)  /*< 50 Gbps > */
> -#define ETH_SPEED_CAP_56G      (1 << 12)  /*< 56 Gbps > */
> -#define ETH_SPEED_CAP_100G     (1 << 13)  /*< 100 Gbps > */
> -
> -
> -/**
>   * Ethernet device information
>   */
>  struct rte_eth_dev_info {
> @@ -1667,6 +1684,22 @@ struct eth_driver {
>  extern void rte_eth_driver_register(struct eth_driver *eth_drv);
>
>  /**
> + * Convert a numerical speed in Mbps to a bitmap flag that can be used in
> + * the bitmap link_speeds of the struct rte_eth_conf
> + *
> + * @param
> + *   Numerical speed value in Mbps
> + * @param
> + *   Boolean is duplex (only for 10/100 speeds)
> + * @param
> + *   On success, the converted speed into a bitmap flag
> + * @return
> + *   0 on success, -EINVAL if the speed cannot be mapped
> + */
> +extern int rte_eth_speed_to_bm_flag(uint32_t speed, int duplex,
> +                                                       uint32_t *flag);
> +
> +/**
>   * Configure an Ethernet device.
>   * This function must be invoked first before any other function in the
>   * Ethernet API. This function can also be re-invoked when a device is in
> the
> --
> 2.1.4
>
>


More information about the dev mailing list