[dpdk-dev] [PATCH v5 3/4] ethdev: redesign link speed config API

Harish Patil harish.patil at qlogic.com
Thu Jan 28 18:33:20 CET 2016



From: Marc Sune <marcdevel at gmail.com<mailto:marcdevel at gmail.com>>
Date: Sunday, October 4, 2015 at 2:12 PM
To: "dev at dpdk.org<mailto:dev at dpdk.org>" <dev at dpdk.org<mailto:dev at dpdk.org>>
Subject: [dpdk-dev] [PATCH v5 3/4] ethdev: redesign link speed config API

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.
* Adapted testpmd to the new link API.

Signed-off-by: Marc Sune <marcdevel at gmail.com<mailto: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              | 108 ++++++++++++-------------
 drivers/net/e1000/igb_ethdev.c             | 103 ++++++++++++------------
 drivers/net/fm10k/fm10k_ethdev.c           |   8 +-
 drivers/net/i40e/i40e_ethdev.c             |  70 ++++++++--------
 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/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 ++++++++++++++++----------
 34 files changed, 437 insertions(+), 356 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..19d774f 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 */
@@ -989,11 +981,11 @@ eth_em_link_update(struct rte_eth_dev *dev, int wait_to_complete)
     if (link_check && (link.link_status == 0)) {
         hw->mac.ops.get_link_up_info(hw, &link.link_speed,
             &link.link_duplex);
-        link.link_status = 1;
+        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..7d407f4 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
@@ -1683,11 +1683,14 @@ eth_igb_link_update(struct rte_eth_dev *dev, int wait_to_complete)
     if (link_check) {
         hw->mac.ops.get_link_up_info(hw, &link.link_speed,
                       &link.link_duplex);
-        link.link_status = 1;
+        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..c3b3b9e 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,22 +1229,22 @@ 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;
     }

@@ -1687,10 +1685,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 +6193,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 053c77e..a1103f0 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 88f95e5..41c0ad1 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/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..bd333e4 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 ->  full duplex, 0 ->  half duplex */
+    uint8_t link_autoneg : 1;  /**<  1 ->  link speed has been autoneg */
+    uint8_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


Acked-by: Harish Patil <harish.patil at qlogic.com<mailto:harish.patil at qlogic.com>>

Hi Marc,
When can we expect it to be merged to the latest DPDK?

Thanks,
Harish




________________________________

This message and any attached documents contain information from the sending company or its parent company(s), subsidiaries, divisions or branch offices that may be confidential. If you are not the intended recipient, you may not read, copy, distribute, or use this information. If you have received this transmission in error, please notify the sender immediately by reply e-mail and then delete this message.


More information about the dev mailing list