[dpdk-dev,v7,3/5] ethdev: redesign link speed config API

Message ID 1454028127-10401-4-git-send-email-marcdevel@gmail.com (mailing list archive)
State Superseded, archived
Delegated to: Thomas Monjalon
Headers

Commit Message

Marc Sune Jan. 29, 2016, 12:42 a.m. UTC
  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@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     |   7 +-
 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           |  78 ++++++++----------
 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, 454 insertions(+), 365 deletions(-)
  

Comments

Ananyev, Konstantin Jan. 29, 2016, 9:24 a.m. UTC | #1
Hi Marc,

> -----Original Message-----
> From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Marc Sune
> Sent: Friday, January 29, 2016 12:42 AM
> To: dev@dpdk.org; Lu, Wenzhuo; Zhang, Helin; Harish Patil; Chen, Jing D
> Subject: [dpdk-dev] [PATCH v7 3/5] 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.

Can you avoid modifications in the e1000/base code?
We do not modify (and maintain) that part on our own.
Instead we take it straight from Intel ND.  
So if you feel like these changes are really necessary - please submit a patch
to ND first, and if your changes will be applied, will pick it up from them. 
Thanks
Konstantin

> 
> Signed-off-by: Marc Sune <marcdevel@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     |   7 +-
>  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           |  78 ++++++++----------
>  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, 454 insertions(+), 365 deletions(-)
> 
> diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
> index 6d28c1b..00571bc 100644
> --- a/app/test-pmd/cmdline.c
> +++ b/app/test-pmd/cmdline.c
> @@ -956,14 +956,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()) {
> @@ -971,40 +1022,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 =
> @@ -1059,8 +1088,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");
> @@ -1070,36 +1098,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 767f36b..5db1db2 100644
> --- a/drivers/net/af_packet/rte_eth_af_packet.c
> +++ b/drivers/net/af_packet/rte_eth_af_packet.c
> @@ -116,9 +116,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 b3b30f6..3b446e1 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 5ac925e..ae11cac 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;
> @@ -1247,7 +1247,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 9cdb91c..73f9234 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 fc96199..4402f63 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 723885d..f8d61e4 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);
> @@ -1167,7 +1167,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;
> @@ -1194,7 +1194,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");
> 
> @@ -1325,7 +1326,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 bbfcae8..3a066d5 100644
> --- a/drivers/net/e1000/base/e1000_api.c
> +++ b/drivers/net/e1000/base/e1000_api.c
> @@ -673,7 +673,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 0bc471d..7327750 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);
>  int 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 69aa1f2..692845d 100644
> --- a/drivers/net/e1000/base/e1000_defines.h
> +++ b/drivers/net/e1000/base/e1000_defines.h
> @@ -348,8 +348,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 e4e4f76..30e7f3b 100644
> --- a/drivers/net/e1000/base/e1000_hw.h
> +++ b/drivers/net/e1000/base/e1000_hw.h
> @@ -686,7 +686,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 89d07e9..a6e01c7 100644
> --- a/drivers/net/e1000/base/e1000_ich8lan.c
> +++ b/drivers/net/e1000/base/e1000_ich8lan.c
> @@ -108,7 +108,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);
> @@ -1458,7 +1458,8 @@ STATIC s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw)
>  	 */
>  	if (((hw->mac.type == e1000_pch2lan) ||
>  	     (hw->mac.type == e1000_pch_lpt)) && link) {
> -		u16 speed, duplex;
> +		u16 duplex;
> +		u32 speed;
> 
>  		e1000_get_speed_and_duplex_copper_generic(hw, &speed, &duplex);
>  		tipg_reg = E1000_READ_REG(hw, E1000_TIPG);
> @@ -4623,7 +4624,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 a0f3a99..c66421c 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);
> @@ -1348,7 +1348,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");
> 
> @@ -1650,7 +1651,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;
> @@ -1690,7 +1691,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 96a260c..fef862f 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 7845b48..c7fc80f 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 d6216de..f7b5ea8 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 fd48bbf..a041710 100644
> --- a/drivers/net/e1000/em_ethdev.c
> +++ b/drivers/net/e1000/em_ethdev.c
> @@ -509,6 +509,9 @@ eth_em_start(struct rte_eth_dev *dev)
>  	struct rte_intr_handle *intr_handle = &dev->pci_dev->intr_handle;
>  	int ret, mask;
>  	uint32_t intr_vector = 0;
> +	uint32_t *speeds;
> +	int num_speeds;
> +	bool autoneg;
> 
>  	PMD_INIT_FUNC_TRACE();
> 
> @@ -583,56 +586,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);
> 
>  	if (rte_intr_allow_others(intr_handle)) {
> @@ -665,9 +658,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);
>  }
> @@ -1024,11 +1016,11 @@ eth_em_infos_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info)
>  		.nb_align = EM_TXD_ALIGN,
>  	};
> 
> -	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 */
> @@ -1077,13 +1069,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 9c8dffa..c1c41b3 100644
> --- a/drivers/net/e1000/igb_ethdev.c
> +++ b/drivers/net/e1000/igb_ethdev.c
> @@ -1119,6 +1119,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();
> 
> @@ -1219,48 +1222,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);
> 
>  	if (rte_intr_allow_others(intr_handle)) {
> @@ -1292,9 +1293,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);
>  }
> @@ -1909,11 +1909,11 @@ eth_igb_infos_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info)
>  	dev_info->rx_desc_lim = rx_desc_lim;
>  	dev_info->tx_desc_lim = tx_desc_lim;
> 
> -	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
> @@ -2023,13 +2023,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 aeb2962..702eb97 100644
> --- a/drivers/net/fm10k/fm10k_ethdev.c
> +++ b/drivers/net/fm10k/fm10k_ethdev.c
> @@ -1172,7 +1172,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;
>  }
> @@ -1334,9 +1334,9 @@ fm10k_dev_infos_get(struct rte_eth_dev *dev,
>  		.nb_align = FM10K_MULT_TX_DESC,
>  	};
> 
> -	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 d242973..34bc2c9 100644
> --- a/drivers/net/i40e/i40e_ethdev.c
> +++ b/drivers/net/i40e/i40e_ethdev.c
> @@ -1326,27 +1326,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;
>  }
> @@ -1372,9 +1365,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;
> @@ -1394,10 +1387,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;
>  	}
> @@ -1470,6 +1461,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");
> @@ -1713,7 +1711,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;
> @@ -1735,25 +1733,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)
> @@ -2308,10 +2309,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;
> 
>  }
> 
> @@ -7835,15 +7836,15 @@ i40e_start_timecounters(struct rte_eth_dev *dev)
>  	rte_i40e_dev_atomic_read_link_status(dev, &link);
> 
>  	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 14d2a50..f06f828 100644
> --- a/drivers/net/i40e/i40e_ethdev_vf.c
> +++ b/drivers/net/i40e/i40e_ethdev_vf.c
> @@ -1911,13 +1911,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 4e3ab3d..14a03e1 100644
> --- a/drivers/net/ixgbe/ixgbe_ethdev.c
> +++ b/drivers/net/ixgbe/ixgbe_ethdev.c
> @@ -1979,14 +1979,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;
>  	}
> @@ -2076,32 +2075,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;
> @@ -2828,15 +2817,16 @@ ixgbe_dev_info_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info)
>  	dev_info->reta_size = ixgbe_reta_size_get(hw->mac.type);
>  	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
> @@ -2903,9 +2893,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);
> 
> @@ -2918,8 +2908,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;
> @@ -2932,26 +2922,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);
> @@ -5725,15 +5715,15 @@ ixgbe_start_timecounters(struct rte_eth_dev *dev)
>  	rte_ixgbe_dev_atomic_read_link_status(dev, &link);
> 
>  	switch (link.link_speed) {
> -	case ETH_LINK_SPEED_100:
> +	case ETH_SPEED_NUM_100M:
>  		incval = IXGBE_INCVAL_100;
>  		shift = IXGBE_INCVAL_SHIFT_100;
>  		break;
> -	case ETH_LINK_SPEED_1000:
> +	case ETH_SPEED_NUM_1G:
>  		incval = IXGBE_INCVAL_1GB;
>  		shift = IXGBE_INCVAL_SHIFT_1GB;
>  		break;
> -	case ETH_LINK_SPEED_10000:
> +	case ETH_SPEED_NUM_10G:
>  	default:
>  		incval = IXGBE_INCVAL_10GB;
>  		shift = IXGBE_INCVAL_SHIFT_10GB;
> diff --git a/drivers/net/mlx4/mlx4.c b/drivers/net/mlx4/mlx4.c
> index 1f3ed59..4dbc8a9 100644
> --- a/drivers/net/mlx4/mlx4.c
> +++ b/drivers/net/mlx4/mlx4.c
> @@ -4637,6 +4637,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 35134ba..f42c1d4 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 77fc988..55e1fc8 100644
> --- a/drivers/net/null/rte_eth_null.c
> +++ b/drivers/net/null/rte_eth_null.c
> @@ -93,9 +93,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 f9230eb..650b521 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 d92b088..043175a 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 d928339..83a2ffe 100644
> --- a/drivers/net/virtio/virtio_ethdev.c
> +++ b/drivers/net/virtio/virtio_ethdev.c
> @@ -1631,7 +1631,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 ae2d47d..8598815 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 c363bf6..2bb6ee9 100644
> --- a/drivers/net/vmxnet3/vmxnet3_ethdev.c
> +++ b/drivers/net/vmxnet3/vmxnet3_ethdev.c
> @@ -736,9 +736,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 3f31806..0fcf5d3 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 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 void
> diff --git a/examples/ip_pipeline/config_parse.c b/examples/ip_pipeline/config_parse.c
> index 1bedbe4..c581d41 100644
> --- a/examples/ip_pipeline/config_parse.c
> +++ b/examples/ip_pipeline/config_parse.c
> @@ -84,8 +84,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 756b234..7b0214d 100644
> --- a/lib/librte_ether/rte_ethdev.c
> +++ b/lib/librte_ether/rte_ethdev.c
> @@ -865,6 +865,55 @@ rte_eth_dev_tx_queue_config(struct rte_eth_dev *dev, uint16_t nb_queues)
>  }
> 
>  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 dbc1599..9b32de5 100644
> --- a/lib/librte_ether/rte_ethdev.h
> +++ b/lib/librte_ether/rte_ethdev.h
> @@ -242,26 +242,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
> @@ -760,10 +793,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
> @@ -825,26 +862,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 {
> @@ -1811,6 +1828,22 @@ struct eth_driver {
>  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
  
Thomas Monjalon Jan. 29, 2016, 9:37 a.m. UTC | #2
2016-01-29 09:24, Ananyev, Konstantin:
> Can you avoid modifications in the e1000/base code?
> We do not modify (and maintain) that part on our own.
> Instead we take it straight from Intel ND.  
> So if you feel like these changes are really necessary - please submit a patch
> to ND first, and if your changes will be applied, will pick it up from them. 

I was not aware we can submit a change to ND for Intel base drivers.
What is the procedure please?
May it be documented in the DPDK doc?

Thanks
  
Ananyev, Konstantin Jan. 29, 2016, 9:47 a.m. UTC | #3
Hi Thomas,

> -----Original Message-----
> From: Thomas Monjalon [mailto:thomas.monjalon@6wind.com]
> Sent: Friday, January 29, 2016 9:38 AM
> To: Ananyev, Konstantin
> Cc: dev@dpdk.org; Marc Sune; Lu, Wenzhuo; Zhang, Helin; Harish Patil; Chen, Jing D; Mcnamara, John
> Subject: Re: [dpdk-dev] [PATCH v7 3/5] ethdev: redesign link speed config API
> 
> 2016-01-29 09:24, Ananyev, Konstantin:
> > Can you avoid modifications in the e1000/base code?
> > We do not modify (and maintain) that part on our own.
> > Instead we take it straight from Intel ND.
> > So if you feel like these changes are really necessary - please submit a patch
> > to ND first, and if your changes will be applied, will pick it up from them.
> 
> I was not aware we can submit a change to ND for Intel base drivers.
> What is the procedure please?

I meant not to the ND directly, but probably to the freebsd e1000 kernel driver.
As I remember, that is the closest one to what we have.
From my understanding (I might be wrong here):
If they will be accepted, we should see these changes In next code drops from ND.
Konstantin

> May it be documented in the DPDK doc?



> 
> Thanks
  
Thomas Monjalon Jan. 29, 2016, 9:53 a.m. UTC | #4
2016-01-29 09:47, Ananyev, Konstantin:
> From: Thomas Monjalon [mailto:thomas.monjalon@6wind.com]
> > 2016-01-29 09:24, Ananyev, Konstantin:
> > > Can you avoid modifications in the e1000/base code?
> > > We do not modify (and maintain) that part on our own.
> > > Instead we take it straight from Intel ND.
> > > So if you feel like these changes are really necessary - please submit a patch
> > > to ND first, and if your changes will be applied, will pick it up from them.
> > 
> > I was not aware we can submit a change to ND for Intel base drivers.
> > What is the procedure please?
> 
> I meant not to the ND directly, but probably to the freebsd e1000 kernel driver.
> As I remember, that is the closest one to what we have.
> From my understanding (I might be wrong here):
> If they will be accepted, we should see these changes In next code drops from ND.

These base drivers are used in several places.
We are allowed to submit a patch in Linux or FreeBSD but not in DPDK
where the base driver is verbatim?
We have an agreement to not touch them in DPDK but I still think the
ND team could consider some patches from dpdk.org.
  
Ananyev, Konstantin Jan. 29, 2016, 10:17 a.m. UTC | #5
> -----Original Message-----
> From: Thomas Monjalon [mailto:thomas.monjalon@6wind.com]
> Sent: Friday, January 29, 2016 9:54 AM
> To: Ananyev, Konstantin
> Cc: dev@dpdk.org; Marc Sune; Lu, Wenzhuo; Zhang, Helin; Harish Patil; Chen, Jing D; Mcnamara, John
> Subject: Re: [dpdk-dev] [PATCH v7 3/5] ethdev: redesign link speed config API
> 
> 2016-01-29 09:47, Ananyev, Konstantin:
> > From: Thomas Monjalon [mailto:thomas.monjalon@6wind.com]
> > > 2016-01-29 09:24, Ananyev, Konstantin:
> > > > Can you avoid modifications in the e1000/base code?
> > > > We do not modify (and maintain) that part on our own.
> > > > Instead we take it straight from Intel ND.
> > > > So if you feel like these changes are really necessary - please submit a patch
> > > > to ND first, and if your changes will be applied, will pick it up from them.
> > >
> > > I was not aware we can submit a change to ND for Intel base drivers.
> > > What is the procedure please?
> >
> > I meant not to the ND directly, but probably to the freebsd e1000 kernel driver.
> > As I remember, that is the closest one to what we have.
> > From my understanding (I might be wrong here):
> > If they will be accepted, we should see these changes In next code drops from ND.
> 
> These base drivers are used in several places.
> We are allowed to submit a patch in Linux or FreeBSD but not in DPDK
> where the base driver is verbatim?

Yes, that's my understanding.

> We have an agreement to not touch them in DPDK

Yes.

> but I still think the
> ND team could consider some patches from dpdk.org.

I personally think that would be a good thing,
but it is up to ND guys to make such decision.
 
Konstantin
  
Marc Sune Jan. 29, 2016, 12:40 p.m. UTC | #6
On 29 January 2016 at 11:17, Ananyev, Konstantin <
konstantin.ananyev@intel.com> wrote:

>
>
> > -----Original Message-----
> > From: Thomas Monjalon [mailto:thomas.monjalon@6wind.com]
> > Sent: Friday, January 29, 2016 9:54 AM
> > To: Ananyev, Konstantin
> > Cc: dev@dpdk.org; Marc Sune; Lu, Wenzhuo; Zhang, Helin; Harish Patil;
> Chen, Jing D; Mcnamara, John
> > Subject: Re: [dpdk-dev] [PATCH v7 3/5] ethdev: redesign link speed
> config API
> >
> > 2016-01-29 09:47, Ananyev, Konstantin:
> > > From: Thomas Monjalon [mailto:thomas.monjalon@6wind.com]
> > > > 2016-01-29 09:24, Ananyev, Konstantin:
> > > > > Can you avoid modifications in the e1000/base code?
>

Yes I can. It was just to save intermediate variables and conversions.
Previously u16 was used to store numeric throughput in mbps in ethdev, and
passed to the inner functions in e1000/base, but it cannot accommodate 100G
values, so I moved it to uint32_t. But I can do the conversion outside of
e1000/base.

> > > > We do not modify (and maintain) that part on our own.
> > > > > Instead we take it straight from Intel ND.
> > > > > So if you feel like these changes are really necessary - please
> submit a patch
> > > > > to ND first, and if your changes will be applied, will pick it up
> from them.
> > > >
> > > > I was not aware we can submit a change to ND for Intel base drivers.
> > > > What is the procedure please?
> > >
> > > I meant not to the ND directly, but probably to the freebsd e1000
> kernel driver.
> > > As I remember, that is the closest one to what we have.
> > > From my understanding (I might be wrong here):
> > > If they will be accepted, we should see these changes In next code
> drops from ND.
> >
> > These base drivers are used in several places.
> > We are allowed to submit a patch in Linux or FreeBSD but not in DPDK
> > where the base driver is verbatim?
>
> Yes, that's my understanding.
>
> > We have an agreement to not touch them in DPDK
>
> Yes.
>
> > but I still think the
> > ND team could consider some patches from dpdk.org.
>
> I personally think that would be a good thing,
> but it is up to ND guys to make such decision.


Agree, but:

Besides documenting (which is necessary), why not importing the sources via
a git submodule pointing to the base project where these files are obtained
(e.g. in  drivers/net/e1000/ext/ or even in the root folder under ext/ and
making symlinks to that in e1000 driver), and just use the raw sources and
headers from there?

That would make it more explicit that these files should not be modified by
DPDK by strictly forbidding so, and that changes should be done via the
repository pointed in drivers/net/e1000/ext/, hence following that
repository's workflow.

marc


>
> Konstantin
>
>
  
Nélio Laranjeiro Jan. 29, 2016, 4:16 p.m. UTC | #7
Hi Marc,

On Fri, Jan 29, 2016 at 01:42:05AM +0100, Marc Sune wrote:
>[...]
>  /**
> - * 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 > */
>[...]

In the previous commit you update mlx4.c to use those define, in this
commit it should update it again.

Regards,
  
Marc Sune Jan. 31, 2016, 9:24 p.m. UTC | #8
On 29 January 2016 at 17:16, Nélio Laranjeiro <nelio.laranjeiro@6wind.com>
wrote:

> Hi Marc,
>
> On Fri, Jan 29, 2016 at 01:42:05AM +0100, Marc Sune wrote:
> >[...]
> >  /**
> > - * 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 > */
> >[...]
>
> In the previous commit you update mlx4.c to use those define, in this
> commit it should update it again.
>

Neilo,

You are right, thanks. I will fix that in a new version.

marc



>
> Regards,
>
> --
> Nélio Laranjeiro
> 6WIND
>
  
Zhang, Helin Feb. 1, 2016, 12:40 a.m. UTC | #9
> -----Original Message-----
> From: Ananyev, Konstantin
> Sent: Friday, January 29, 2016 6:18 PM
> To: Thomas Monjalon
> Cc: dev@dpdk.org; Marc Sune; Lu, Wenzhuo; Zhang, Helin; Harish Patil; Chen,
> Jing D; Mcnamara, John
> Subject: RE: [dpdk-dev] [PATCH v7 3/5] ethdev: redesign link speed config
> API
> 
> 
> 
> > -----Original Message-----
> > From: Thomas Monjalon [mailto:thomas.monjalon@6wind.com]
> > Sent: Friday, January 29, 2016 9:54 AM
> > To: Ananyev, Konstantin
> > Cc: dev@dpdk.org; Marc Sune; Lu, Wenzhuo; Zhang, Helin; Harish Patil;
> > Chen, Jing D; Mcnamara, John
> > Subject: Re: [dpdk-dev] [PATCH v7 3/5] ethdev: redesign link speed
> > config API
> >
> > 2016-01-29 09:47, Ananyev, Konstantin:
> > > From: Thomas Monjalon [mailto:thomas.monjalon@6wind.com]
> > > > 2016-01-29 09:24, Ananyev, Konstantin:
> > > > > Can you avoid modifications in the e1000/base code?
> > > > > We do not modify (and maintain) that part on our own.
> > > > > Instead we take it straight from Intel ND.
> > > > > So if you feel like these changes are really necessary - please
> > > > > submit a patch to ND first, and if your changes will be applied, will pick
> it up from them.
> > > >
> > > > I was not aware we can submit a change to ND for Intel base drivers.
> > > > What is the procedure please?
> > >
> > > I meant not to the ND directly, but probably to the freebsd e1000 kernel
> driver.
> > > As I remember, that is the closest one to what we have.
> > > From my understanding (I might be wrong here):
> > > If they will be accepted, we should see these changes In next code drops
> from ND.
> >
> > These base drivers are used in several places.
> > We are allowed to submit a patch in Linux or FreeBSD but not in DPDK
> > where the base driver is verbatim?
> 
> Yes, that's my understanding.
> 
> > We have an agreement to not touch them in DPDK
> 
> Yes.
> 
> > but I still think the
> > ND team could consider some patches from dpdk.org.
> 
> I personally think that would be a good thing, but it is up to ND guys to make
> such decision.
[Zhang, Helin] The key reason of not touching base driver is we don't want to
maintain those source files, and just reuse others. This can help us a lot.
We should try to avoid touching source files in base driver, but if you still insist
something critical or a bug should be faced. First of all we can try to do something
in the dpdk developed source files (e.g. i40e_ethdev.c, i40e_rxtx.c, i40e_osdep.h).
This was what we have done for a long time, and it works quite well.
If there is no other way to fix a bug in base driver, we can try the way like
Konstantin indicated, or let me know, I will try to influence ND. But note that this
might be the lowest efficiency way, due to the complicated process.

Sorry for any inconvenience! This the way we are using now might be the best for
us right now.

Regards,
Heiln

> 
> Konstantin
  
Marc Sune Feb. 2, 2016, 12:04 a.m. UTC | #10
On 1 February 2016 at 01:40, Zhang, Helin <helin.zhang@intel.com> wrote:

>
>
> > -----Original Message-----
> > From: Ananyev, Konstantin
> > Sent: Friday, January 29, 2016 6:18 PM
> > To: Thomas Monjalon
> > Cc: dev@dpdk.org; Marc Sune; Lu, Wenzhuo; Zhang, Helin; Harish Patil;
> Chen,
> > Jing D; Mcnamara, John
> > Subject: RE: [dpdk-dev] [PATCH v7 3/5] ethdev: redesign link speed config
> > API
> >
> >
> >
> > > -----Original Message-----
> > > From: Thomas Monjalon [mailto:thomas.monjalon@6wind.com]
> > > Sent: Friday, January 29, 2016 9:54 AM
> > > To: Ananyev, Konstantin
> > > Cc: dev@dpdk.org; Marc Sune; Lu, Wenzhuo; Zhang, Helin; Harish Patil;
> > > Chen, Jing D; Mcnamara, John
> > > Subject: Re: [dpdk-dev] [PATCH v7 3/5] ethdev: redesign link speed
> > > config API
> > >
> > > 2016-01-29 09:47, Ananyev, Konstantin:
> > > > From: Thomas Monjalon [mailto:thomas.monjalon@6wind.com]
> > > > > 2016-01-29 09:24, Ananyev, Konstantin:
> > > > > > Can you avoid modifications in the e1000/base code?
> > > > > > We do not modify (and maintain) that part on our own.
> > > > > > Instead we take it straight from Intel ND.
> > > > > > So if you feel like these changes are really necessary - please
> > > > > > submit a patch to ND first, and if your changes will be applied,
> will pick
> > it up from them.
> > > > >
> > > > > I was not aware we can submit a change to ND for Intel base
> drivers.
> > > > > What is the procedure please?
> > > >
> > > > I meant not to the ND directly, but probably to the freebsd e1000
> kernel
> > driver.
> > > > As I remember, that is the closest one to what we have.
> > > > From my understanding (I might be wrong here):
> > > > If they will be accepted, we should see these changes In next code
> drops
> > from ND.
> > >
> > > These base drivers are used in several places.
> > > We are allowed to submit a patch in Linux or FreeBSD but not in DPDK
> > > where the base driver is verbatim?
> >
> > Yes, that's my understanding.
> >
> > > We have an agreement to not touch them in DPDK
> >
> > Yes.
> >
> > > but I still think the
> > > ND team could consider some patches from dpdk.org.
> >
> > I personally think that would be a good thing, but it is up to ND guys
> to make
> > such decision.
> [Zhang, Helin] The key reason of not touching base driver is we don't want
> to
> maintain those source files, and just reuse others.


So files under base/ strictly copies of what is in this other Intel
repository (ND) or there are modifications?

If IIRC rte_link was crafted so that matches e1000 (at least) so that link
reads can be done atomically. I think it makes more sense that ethdev has a
generic, device independent struct and that drivers handle the translation,
if necessary. Do we agree on this?

This can help us a lot.
> We should try to avoid touching source files in base driver, but if you
> still insist
> something critical or a bug should be faced. First of all we can try to do
> something
> in the dpdk developed source files (e.g. i40e_ethdev.c, i40e_rxtx.c,
> i40e_osdep.h).
> This was what we have done for a long time, and it works quite well.
> If there is no other way to fix a bug in base driver, we can try the way
> like
> Konstantin indicated, or let me know, I will try to influence ND. But note
> that this
> might be the lowest efficiency way, due to the complicated process.


> Sorry for any inconvenience! This the way we are using now might be the
> best for
> us right now.
>

I will go back and redesign commit 3 in the series once more. I will need
some time (other things in the pipeline). I would have appreciated rising
this red flag in one of the 6 previous versions.

marc


>
> Regards,
> Heiln
>
> >
> > Konstantin
>
>
  
Zhang, Helin Feb. 2, 2016, 12:45 a.m. UTC | #11
>From: marc.sune@gmail.com [mailto:marc.sune@gmail.com] On Behalf Of Marc

>Sent: Tuesday, February 2, 2016 8:04 AM

>To: Zhang, Helin

>Cc: Ananyev, Konstantin; Thomas Monjalon; dev@dpdk.org; Lu, Wenzhuo; Harish Patil; Chen, Jing D; Mcnamara, John

>Subject: Re: [dpdk-dev] [PATCH v7 3/5] ethdev: redesign link speed config API

>

>

>

>On 1 February 2016 at 01:40, Zhang, Helin <helin.zhang@intel.com> wrote:

>

>

>> -----Original Message-----

>> From: Ananyev, Konstantin

>> Sent: Friday, January 29, 2016 6:18 PM

>> To: Thomas Monjalon

>> Cc: dev@dpdk.org; Marc Sune; Lu, Wenzhuo; Zhang, Helin; Harish Patil; Chen,

>> Jing D; Mcnamara, John

>> Subject: RE: [dpdk-dev] [PATCH v7 3/5] ethdev: redesign link speed config

>> API

>>

>>

>>

>> > -----Original Message-----

>> > From: Thomas Monjalon [mailto:thomas.monjalon@6wind.com]

>> > Sent: Friday, January 29, 2016 9:54 AM

>> > To: Ananyev, Konstantin

>> > Cc: dev@dpdk.org; Marc Sune; Lu, Wenzhuo; Zhang, Helin; Harish Patil;

>> > Chen, Jing D; Mcnamara, John

>> > Subject: Re: [dpdk-dev] [PATCH v7 3/5] ethdev: redesign link speed

>> > config API

>> >

>> > 2016-01-29 09:47, Ananyev, Konstantin:

>> > > From: Thomas Monjalon [mailto:thomas.monjalon@6wind.com]

>> > > > 2016-01-29 09:24, Ananyev, Konstantin:

>> > > > > Can you avoid modifications in the e1000/base code?

>> > > > > We do not modify (and maintain) that part on our own.

>> > > > > Instead we take it straight from Intel ND.

>> > > > > So if you feel like these changes are really necessary - please

>> > > > > submit a patch to ND first, and if your changes will be applied, will pick

>> it up from them.

>> > > >

>> > > > I was not aware we can submit a change to ND for Intel base drivers.

>> > > > What is the procedure please?

>> > >

>> > > I meant not to the ND directly, but probably to the freebsd e1000 kernel

>> driver.

>> > > As I remember, that is the closest one to what we have.

>> > > From my understanding (I might be wrong here):

>> > > If they will be accepted, we should see these changes In next code drops

>> from ND.

>> >

>> > These base drivers are used in several places.

>> > We are allowed to submit a patch in Linux or FreeBSD but not in DPDK

>> > where the base driver is verbatim?

>>

>> Yes, that's my understanding.

>>

>> > We have an agreement to not touch them in DPDK

>>

>> Yes.

>>

>> > but I still think the

>> > ND team could consider some patches from dpdk.org.

>>

>> I personally think that would be a good thing, but it is up to ND guys to make

>> such decision.

>[Zhang, Helin] The key reason of not touching base driver is we don't want to

>maintain those source files, and just reuse others. 

>

>So files under base/ strictly copies of what is in this other Intel repository (ND) or there are modifications?

Long time ago, those source files were copied from FreeBSD version of driver, without any modification.
Though there is a bit different from that time, but they are similar.
Note that 'base/i40e_osdep.h or ixgbe_osdep.h' is the only file we can modify to support DPDK.
Of cause, all other files than base driver are what we developed, and can be modified.

>

>If IIRC rte_link was crafted so that matches e1000 (at least) so that link reads can be done atomically. I think it makes more sense that ethdev has a generic, device independent struct and that drivers handle the translation, if necessary. Do we agree on this?

I agree with you to have a generic structure in ethdev, and it can be filled with information obtained from base driver.

>

>This can help us a lot.

>We should try to avoid touching source files in base driver, but if you still insist

>something critical or a bug should be faced. First of all we can try to do something

>in the dpdk developed source files (e.g. i40e_ethdev.c, i40e_rxtx.c, i40e_osdep.h).

>This was what we have done for a long time, and it works quite well.

>If there is no other way to fix a bug in base driver, we can try the way like

>Konstantin indicated, or let me know, I will try to influence ND. But note that this

>might be the lowest efficiency way, due to the complicated process. 

>

>Sorry for any inconvenience! This the way we are using now might be the best for

>us right now.

>

>I will go back and redesign commit 3 in the series once more. I will need some time (other things in the pipeline). I would have appreciated rising this red flag in one of the 6 previous versions.

Thank you very much for the helps, and patience!

Regards,
Helin

>

>marc

> 

>

>Regards,

>Heiln

>

>>

>> Konstantin

>
  

Patch

diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
index 6d28c1b..00571bc 100644
--- a/app/test-pmd/cmdline.c
+++ b/app/test-pmd/cmdline.c
@@ -956,14 +956,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()) {
@@ -971,40 +1022,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 =
@@ -1059,8 +1088,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");
@@ -1070,36 +1098,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 767f36b..5db1db2 100644
--- a/drivers/net/af_packet/rte_eth_af_packet.c
+++ b/drivers/net/af_packet/rte_eth_af_packet.c
@@ -116,9 +116,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 b3b30f6..3b446e1 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 5ac925e..ae11cac 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;
@@ -1247,7 +1247,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 9cdb91c..73f9234 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 fc96199..4402f63 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 723885d..f8d61e4 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);
@@ -1167,7 +1167,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;
@@ -1194,7 +1194,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");
 
@@ -1325,7 +1326,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 bbfcae8..3a066d5 100644
--- a/drivers/net/e1000/base/e1000_api.c
+++ b/drivers/net/e1000/base/e1000_api.c
@@ -673,7 +673,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 0bc471d..7327750 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);
 int 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 69aa1f2..692845d 100644
--- a/drivers/net/e1000/base/e1000_defines.h
+++ b/drivers/net/e1000/base/e1000_defines.h
@@ -348,8 +348,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 e4e4f76..30e7f3b 100644
--- a/drivers/net/e1000/base/e1000_hw.h
+++ b/drivers/net/e1000/base/e1000_hw.h
@@ -686,7 +686,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 89d07e9..a6e01c7 100644
--- a/drivers/net/e1000/base/e1000_ich8lan.c
+++ b/drivers/net/e1000/base/e1000_ich8lan.c
@@ -108,7 +108,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);
@@ -1458,7 +1458,8 @@  STATIC s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw)
 	 */
 	if (((hw->mac.type == e1000_pch2lan) ||
 	     (hw->mac.type == e1000_pch_lpt)) && link) {
-		u16 speed, duplex;
+		u16 duplex;
+		u32 speed;
 
 		e1000_get_speed_and_duplex_copper_generic(hw, &speed, &duplex);
 		tipg_reg = E1000_READ_REG(hw, E1000_TIPG);
@@ -4623,7 +4624,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 a0f3a99..c66421c 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);
@@ -1348,7 +1348,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");
 
@@ -1650,7 +1651,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;
@@ -1690,7 +1691,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 96a260c..fef862f 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 7845b48..c7fc80f 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 d6216de..f7b5ea8 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 fd48bbf..a041710 100644
--- a/drivers/net/e1000/em_ethdev.c
+++ b/drivers/net/e1000/em_ethdev.c
@@ -509,6 +509,9 @@  eth_em_start(struct rte_eth_dev *dev)
 	struct rte_intr_handle *intr_handle = &dev->pci_dev->intr_handle;
 	int ret, mask;
 	uint32_t intr_vector = 0;
+	uint32_t *speeds;
+	int num_speeds;
+	bool autoneg;
 
 	PMD_INIT_FUNC_TRACE();
 
@@ -583,56 +586,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);
 
 	if (rte_intr_allow_others(intr_handle)) {
@@ -665,9 +658,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);
 }
@@ -1024,11 +1016,11 @@  eth_em_infos_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info)
 		.nb_align = EM_TXD_ALIGN,
 	};
 
-	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 */
@@ -1077,13 +1069,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 9c8dffa..c1c41b3 100644
--- a/drivers/net/e1000/igb_ethdev.c
+++ b/drivers/net/e1000/igb_ethdev.c
@@ -1119,6 +1119,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();
 
@@ -1219,48 +1222,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);
 
 	if (rte_intr_allow_others(intr_handle)) {
@@ -1292,9 +1293,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);
 }
@@ -1909,11 +1909,11 @@  eth_igb_infos_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info)
 	dev_info->rx_desc_lim = rx_desc_lim;
 	dev_info->tx_desc_lim = tx_desc_lim;
 
-	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
@@ -2023,13 +2023,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 aeb2962..702eb97 100644
--- a/drivers/net/fm10k/fm10k_ethdev.c
+++ b/drivers/net/fm10k/fm10k_ethdev.c
@@ -1172,7 +1172,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;
 }
@@ -1334,9 +1334,9 @@  fm10k_dev_infos_get(struct rte_eth_dev *dev,
 		.nb_align = FM10K_MULT_TX_DESC,
 	};
 
-	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 d242973..34bc2c9 100644
--- a/drivers/net/i40e/i40e_ethdev.c
+++ b/drivers/net/i40e/i40e_ethdev.c
@@ -1326,27 +1326,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;
 }
@@ -1372,9 +1365,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;
@@ -1394,10 +1387,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;
 	}
@@ -1470,6 +1461,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");
@@ -1713,7 +1711,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;
@@ -1735,25 +1733,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)
@@ -2308,10 +2309,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;
 
 }
 
@@ -7835,15 +7836,15 @@  i40e_start_timecounters(struct rte_eth_dev *dev)
 	rte_i40e_dev_atomic_read_link_status(dev, &link);
 
 	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 14d2a50..f06f828 100644
--- a/drivers/net/i40e/i40e_ethdev_vf.c
+++ b/drivers/net/i40e/i40e_ethdev_vf.c
@@ -1911,13 +1911,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 4e3ab3d..14a03e1 100644
--- a/drivers/net/ixgbe/ixgbe_ethdev.c
+++ b/drivers/net/ixgbe/ixgbe_ethdev.c
@@ -1979,14 +1979,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;
 	}
@@ -2076,32 +2075,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;
@@ -2828,15 +2817,16 @@  ixgbe_dev_info_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info)
 	dev_info->reta_size = ixgbe_reta_size_get(hw->mac.type);
 	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
@@ -2903,9 +2893,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);
 
@@ -2918,8 +2908,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;
@@ -2932,26 +2922,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);
@@ -5725,15 +5715,15 @@  ixgbe_start_timecounters(struct rte_eth_dev *dev)
 	rte_ixgbe_dev_atomic_read_link_status(dev, &link);
 
 	switch (link.link_speed) {
-	case ETH_LINK_SPEED_100:
+	case ETH_SPEED_NUM_100M:
 		incval = IXGBE_INCVAL_100;
 		shift = IXGBE_INCVAL_SHIFT_100;
 		break;
-	case ETH_LINK_SPEED_1000:
+	case ETH_SPEED_NUM_1G:
 		incval = IXGBE_INCVAL_1GB;
 		shift = IXGBE_INCVAL_SHIFT_1GB;
 		break;
-	case ETH_LINK_SPEED_10000:
+	case ETH_SPEED_NUM_10G:
 	default:
 		incval = IXGBE_INCVAL_10GB;
 		shift = IXGBE_INCVAL_SHIFT_10GB;
diff --git a/drivers/net/mlx4/mlx4.c b/drivers/net/mlx4/mlx4.c
index 1f3ed59..4dbc8a9 100644
--- a/drivers/net/mlx4/mlx4.c
+++ b/drivers/net/mlx4/mlx4.c
@@ -4637,6 +4637,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 35134ba..f42c1d4 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 77fc988..55e1fc8 100644
--- a/drivers/net/null/rte_eth_null.c
+++ b/drivers/net/null/rte_eth_null.c
@@ -93,9 +93,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 f9230eb..650b521 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 d92b088..043175a 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 d928339..83a2ffe 100644
--- a/drivers/net/virtio/virtio_ethdev.c
+++ b/drivers/net/virtio/virtio_ethdev.c
@@ -1631,7 +1631,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 ae2d47d..8598815 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 c363bf6..2bb6ee9 100644
--- a/drivers/net/vmxnet3/vmxnet3_ethdev.c
+++ b/drivers/net/vmxnet3/vmxnet3_ethdev.c
@@ -736,9 +736,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 3f31806..0fcf5d3 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 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 void
diff --git a/examples/ip_pipeline/config_parse.c b/examples/ip_pipeline/config_parse.c
index 1bedbe4..c581d41 100644
--- a/examples/ip_pipeline/config_parse.c
+++ b/examples/ip_pipeline/config_parse.c
@@ -84,8 +84,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 756b234..7b0214d 100644
--- a/lib/librte_ether/rte_ethdev.c
+++ b/lib/librte_ether/rte_ethdev.c
@@ -865,6 +865,55 @@  rte_eth_dev_tx_queue_config(struct rte_eth_dev *dev, uint16_t nb_queues)
 }
 
 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 dbc1599..9b32de5 100644
--- a/lib/librte_ether/rte_ethdev.h
+++ b/lib/librte_ether/rte_ethdev.h
@@ -242,26 +242,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
@@ -760,10 +793,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
@@ -825,26 +862,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 {
@@ -1811,6 +1828,22 @@  struct eth_driver {
 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