[dpdk-dev,v8,3/4] ethdev: redesign link speed config API

Message ID 1455488259-1000-4-git-send-email-marcdevel@gmail.com (mailing list archive)
State Superseded, archived
Headers

Commit Message

Marc Sune Feb. 14, 2016, 10:17 p.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 uint64_t to accomodate 100G speeds
  and beyond (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.
* Added rte_eth_speed_to_bm_flag() to version map.

Signed-off-by: Marc Sune <marcdevel@gmail.com>
---
 app/test-pipeline/init.c                  |   2 +-
 app/test-pmd/cmdline.c                    | 124 +++++++++++++++---------------
 app/test-pmd/config.c                     |   4 +-
 app/test/virtual_pmd.c                    |   4 +-
 drivers/net/af_packet/rte_eth_af_packet.c |   5 +-
 drivers/net/bnx2x/bnx2x_ethdev.c          |   8 +-
 drivers/net/bonding/rte_eth_bond_8023ad.c |  14 ++--
 drivers/net/cxgbe/base/t4_hw.c            |   8 +-
 drivers/net/cxgbe/cxgbe_ethdev.c          |   2 +-
 drivers/net/e1000/em_ethdev.c             | 116 ++++++++++++++--------------
 drivers/net/e1000/igb_ethdev.c            | 111 +++++++++++++-------------
 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                   |   6 +-
 drivers/net/mpipe/mpipe_tilegx.c          |   6 +-
 drivers/net/nfp/nfp_net.c                 |   4 +-
 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 +++++++++++++++++----------
 lib/librte_ether/rte_ether_version.map    |   6 ++
 29 files changed, 443 insertions(+), 345 deletions(-)
  

Comments

Nélio Laranjeiro Feb. 15, 2016, 8:46 a.m. UTC | #1
On Sun, Feb 14, 2016 at 11:17:38PM +0100, Marc Sune wrote:
> 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.
> 
>[...]
> diff --git a/drivers/net/mlx4/mlx4.c b/drivers/net/mlx4/mlx4.c
> index c5688a7..01c3a5c 100644
> --- a/drivers/net/mlx4/mlx4.c
> +++ b/drivers/net/mlx4/mlx4.c
> @@ -4265,8 +4265,8 @@ mlx4_dev_infos_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *info)
>  	if (priv_get_ifname(priv, &ifname) == 0)
>  		info->if_index = if_nametoindex(ifname);
>  
> -	info->speed_capa = ETH_SPEED_CAP_10G |ETH_SPEED_CAP_40G |
> -					ETH_SPEED_CAP_56G;
> +	info->speed_capa = ETH_LINK_SPEED_10G |ETH_LINK_SPEED_40G |
> +					ETH_LINK_SPEED_56G;
>  
>  	priv_unlock(priv);
>  }
> @@ -4636,6 +4636,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;
>[...]

The same modification are missing in mlx5.
  
Marc Sune Feb. 15, 2016, 11 a.m. UTC | #2
On 15 February 2016 at 09:46, Nélio Laranjeiro <nelio.laranjeiro@6wind.com>
wrote:

> On Sun, Feb 14, 2016 at 11:17:38PM +0100, Marc Sune wrote:
> > 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.
> >
> >[...]
> > diff --git a/drivers/net/mlx4/mlx4.c b/drivers/net/mlx4/mlx4.c
> > index c5688a7..01c3a5c 100644
> > --- a/drivers/net/mlx4/mlx4.c
> > +++ b/drivers/net/mlx4/mlx4.c
> > @@ -4265,8 +4265,8 @@ mlx4_dev_infos_get(struct rte_eth_dev *dev, struct
> rte_eth_dev_info *info)
> >       if (priv_get_ifname(priv, &ifname) == 0)
> >               info->if_index = if_nametoindex(ifname);
> >
> > -     info->speed_capa = ETH_SPEED_CAP_10G |ETH_SPEED_CAP_40G |
> > -                                     ETH_SPEED_CAP_56G;
> > +     info->speed_capa = ETH_LINK_SPEED_10G |ETH_LINK_SPEED_40G |
> > +                                     ETH_LINK_SPEED_56G;
> >
> >       priv_unlock(priv);
> >  }
> > @@ -4636,6 +4636,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;
> >[...]
>
> The same modification are missing in mlx5.
>
>
Damn.. are the required closed-source libraries for MLX4/5 available
somewhere or is there a chance automatic builds can also compile drivers
that require external dependencies (like this MLX)?

It is very prone to errors having to guess what is going to happen without
being able to compile these drivers.

Marc

--
> Nélio Laranjeiro
> 6WIND
>
  
Olga Shern Feb. 15, 2016, 11:39 a.m. UTC | #3
Hi Marc, 

You can download MLNX_OFED from Mellanox web site:
http://www.mellanox.com/page/products_dyn?product_family=26&mtag=linux_sw_drivers

Best Regards,
Olga

-----Original Message-----
From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Marc

Sent: Monday, February 15, 2016 1:00 PM
To: Nélio Laranjeiro
Cc: dev@dpdk.org
Subject: Re: [dpdk-dev] [PATCH v8 3/4] ethdev: redesign link speed config API

On 15 February 2016 at 09:46, Nélio Laranjeiro <nelio.laranjeiro@6wind.com>
wrote:

> On Sun, Feb 14, 2016 at 11:17:38PM +0100, Marc Sune wrote:

> > 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.

> >

> >[...]

> > diff --git a/drivers/net/mlx4/mlx4.c b/drivers/net/mlx4/mlx4.c  

> >index c5688a7..01c3a5c 100644

> > --- a/drivers/net/mlx4/mlx4.c

> > +++ b/drivers/net/mlx4/mlx4.c

> > @@ -4265,8 +4265,8 @@ mlx4_dev_infos_get(struct rte_eth_dev *dev, 

> > struct

> rte_eth_dev_info *info)

> >       if (priv_get_ifname(priv, &ifname) == 0)

> >               info->if_index = if_nametoindex(ifname);

> >

> > -     info->speed_capa = ETH_SPEED_CAP_10G |ETH_SPEED_CAP_40G |

> > -                                     ETH_SPEED_CAP_56G;

> > +     info->speed_capa = ETH_LINK_SPEED_10G |ETH_LINK_SPEED_40G |

> > +                                     ETH_LINK_SPEED_56G;

> >

> >       priv_unlock(priv);

> >  }

> > @@ -4636,6 +4636,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; [...]

>

> The same modification are missing in mlx5.

>

>

Damn.. are the required closed-source libraries for MLX4/5 available somewhere or is there a chance automatic builds can also compile drivers that require external dependencies (like this MLX)?

It is very prone to errors having to guess what is going to happen without being able to compile these drivers.

Marc

--
> Nélio Laranjeiro

> 6WIND

>
  
Matej Vido Feb. 16, 2016, 10:28 a.m. UTC | #4
Dňa 14.02.2016 o 23:17 Marc Sune napísal(a):
> 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 uint64_t to accomodate 100G speeds
>    and beyond (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.
> * Added rte_eth_speed_to_bm_flag() to version map.
>
> Signed-off-by: Marc Sune <marcdevel@gmail.com>
> ---
>   app/test-pipeline/init.c                  |   2 +-
>   app/test-pmd/cmdline.c                    | 124 +++++++++++++++---------------
>   app/test-pmd/config.c                     |   4 +-
>   app/test/virtual_pmd.c                    |   4 +-
>   drivers/net/af_packet/rte_eth_af_packet.c |   5 +-
>   drivers/net/bnx2x/bnx2x_ethdev.c          |   8 +-
>   drivers/net/bonding/rte_eth_bond_8023ad.c |  14 ++--
>   drivers/net/cxgbe/base/t4_hw.c            |   8 +-
>   drivers/net/cxgbe/cxgbe_ethdev.c          |   2 +-
>   drivers/net/e1000/em_ethdev.c             | 116 ++++++++++++++--------------
>   drivers/net/e1000/igb_ethdev.c            | 111 +++++++++++++-------------
>   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                   |   6 +-
>   drivers/net/mpipe/mpipe_tilegx.c          |   6 +-
>   drivers/net/nfp/nfp_net.c                 |   4 +-
>   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 +++++++++++++++++----------
>   lib/librte_ether/rte_ether_version.map    |   6 ++
>   29 files changed, 443 insertions(+), 345 deletions(-)
>
> [...]

Hi,

some drivers (at least: e1000, i40e, ixgbe, mpipe, nfp, virtio, vmxnet3) 
use rte_atomic64_cmpset() to read and write link state like:

static inline int
rte_em_dev_atomic_read_link_status(struct rte_eth_dev *dev,
                                 struct rte_eth_link *link)
{
         struct rte_eth_link *dst = link;
         struct rte_eth_link *src = &(dev->data->dev_link);

         if (rte_atomic64_cmpset((uint64_t *)dst, *(uint64_t *)dst,
                                         *(uint64_t *)src) == 0)
                 return -1;

         return 0;
}

static inline int
rte_em_dev_atomic_write_link_status(struct rte_eth_dev *dev,
                                 struct rte_eth_link *link)
{
         struct rte_eth_link *dst = &(dev->data->dev_link);
         struct rte_eth_link *src = link;

         if (rte_atomic64_cmpset((uint64_t *)dst, *(uint64_t *)dst,
                                         *(uint64_t *)src) == 0)
                 return -1;

         return 0;
}


When link_speed is changed to uint64_t, struct rte_eth_link exceeds 64 
bits. Shouldn't these functions be adapted in this patch series?

Szedata2 PMD will also use rte_atomic64_cmpset() after patch [1].
I can take care of this change in szedata2 PMD when patch [1] is 
accepted together with adjusting speeds in szedata2 PMD.

[1] http://dpdk.org/ml/archives/dev/2016-January/032281.html

Regards,
Matej
  
Marc Sune Feb. 16, 2016, 10:55 p.m. UTC | #5
Matej,

On 16 February 2016 at 11:28, Matej Vido <vido@cesnet.cz> wrote:

> Dňa 14.02.2016 o 23:17 Marc Sune napísal(a):
>
>> 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 uint64_t to accomodate 100G speeds
>>    and beyond (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.
>> * Added rte_eth_speed_to_bm_flag() to version map.
>>
>> Signed-off-by: Marc Sune <marcdevel@gmail.com>
>> ---
>>   app/test-pipeline/init.c                  |   2 +-
>>   app/test-pmd/cmdline.c                    | 124
>> +++++++++++++++---------------
>>   app/test-pmd/config.c                     |   4 +-
>>   app/test/virtual_pmd.c                    |   4 +-
>>   drivers/net/af_packet/rte_eth_af_packet.c |   5 +-
>>   drivers/net/bnx2x/bnx2x_ethdev.c          |   8 +-
>>   drivers/net/bonding/rte_eth_bond_8023ad.c |  14 ++--
>>   drivers/net/cxgbe/base/t4_hw.c            |   8 +-
>>   drivers/net/cxgbe/cxgbe_ethdev.c          |   2 +-
>>   drivers/net/e1000/em_ethdev.c             | 116
>> ++++++++++++++--------------
>>   drivers/net/e1000/igb_ethdev.c            | 111
>> +++++++++++++-------------
>>   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                   |   6 +-
>>   drivers/net/mpipe/mpipe_tilegx.c          |   6 +-
>>   drivers/net/nfp/nfp_net.c                 |   4 +-
>>   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
>> +++++++++++++++++----------
>>   lib/librte_ether/rte_ether_version.map    |   6 ++
>>   29 files changed, 443 insertions(+), 345 deletions(-)
>>
>> [...]
>>
>
> Hi,
>
> some drivers (at least: e1000, i40e, ixgbe, mpipe, nfp, virtio, vmxnet3)
> use rte_atomic64_cmpset() to read and write link state like:
>
> static inline int
> rte_em_dev_atomic_read_link_status(struct rte_eth_dev *dev,
>                                 struct rte_eth_link *link)
> {
>         struct rte_eth_link *dst = link;
>         struct rte_eth_link *src = &(dev->data->dev_link);
>
>         if (rte_atomic64_cmpset((uint64_t *)dst, *(uint64_t *)dst,
>                                         *(uint64_t *)src) == 0)
>                 return -1;
>
>         return 0;
> }
>
> static inline int
> rte_em_dev_atomic_write_link_status(struct rte_eth_dev *dev,
>                                 struct rte_eth_link *link)
> {
>         struct rte_eth_link *dst = &(dev->data->dev_link);
>         struct rte_eth_link *src = link;
>
>         if (rte_atomic64_cmpset((uint64_t *)dst, *(uint64_t *)dst,
>                                         *(uint64_t *)src) == 0)
>                 return -1;
>
>         return 0;
> }
>
>
> When link_speed is changed to uint64_t, struct rte_eth_link exceeds 64
> bits. Shouldn't these functions be adapted in this patch series?
>
> Szedata2 PMD will also use rte_atomic64_cmpset() after patch [1].
> I can take care of this change in szedata2 PMD when patch [1] is accepted
> together with adjusting speeds in szedata2 PMD.
>

Indeed, thanks. I will take care of them in v9 (incl. szedata2).

marc


> [1] http://dpdk.org/ml/archives/dev/2016-January/032281.html
>
> Regards,
> Matej
>
  

Patch

diff --git a/app/test-pipeline/init.c b/app/test-pipeline/init.c
index db2196b..08fb041 100644
--- a/app/test-pipeline/init.c
+++ b/app/test-pipeline/init.c
@@ -200,7 +200,7 @@  app_ports_check_link(void)
 		port = (uint8_t) app.ports[i];
 		memset(&link, 0, sizeof(link));
 		rte_eth_link_get_nowait(port, &link);
-		RTE_LOG(INFO, USER1, "Port %u (%u Gbps) %s\n",
+		RTE_LOG(INFO, USER1, "Port %u (%" PRIu64 " Gbps) %s\n",
 			port,
 			link.link_speed / 1000,
 			link.link_status ? "UP" : "DOWN");
diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
index 52e9f5f..57ad25f 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-pmd/config.c b/app/test-pmd/config.c
index 0062484..caeb2d9 100644
--- a/app/test-pmd/config.c
+++ b/app/test-pmd/config.c
@@ -2241,7 +2241,7 @@  set_queue_rate_limit(portid_t port_id, uint16_t queue_idx, uint16_t rate)
 		return 1;
 	rte_eth_link_get_nowait(port_id, &link);
 	if (rate > link.link_speed) {
-		printf("Invalid rate value:%u bigger than link speed: %u\n",
+		printf("Invalid rate value:%u bigger than link speed: %" PRIu64 "\n",
 			rate, link.link_speed);
 		return 1;
 	}
@@ -2266,7 +2266,7 @@  set_vf_rate_limit(portid_t port_id, uint16_t vf, uint16_t rate, uint64_t q_msk)
 		return 1;
 	rte_eth_link_get_nowait(port_id, &link);
 	if (rate > link.link_speed) {
-		printf("Invalid rate value:%u bigger than link speed: %u\n",
+		printf("Invalid rate value:%u bigger than link speed: %" PRIu64 "\n",
 			rate, link.link_speed);
 		return 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/bnx2x/bnx2x_ethdev.c b/drivers/net/bnx2x/bnx2x_ethdev.c
index b547ac3..efefae6 100644
--- a/drivers/net/bnx2x/bnx2x_ethdev.c
+++ b/drivers/net/bnx2x/bnx2x_ethdev.c
@@ -45,8 +45,12 @@  bnx2x_link_update(struct rte_eth_dev *dev)
 			dev->data->dev_link.link_duplex = ETH_LINK_HALF_DUPLEX;
 			break;
 		default:
-			dev->data->dev_link.link_duplex = ETH_LINK_AUTONEG_DUPLEX;
+			break;
 	}
+
+	dev->data->dev_link.link_autoneg = ~(dev->data->dev_conf.link_speeds &
+						ETH_LINK_SPEED_NO_AUTONEG);
+
 	dev->data->dev_link.link_status = sc->link_vars.link_up;
 }
 
@@ -347,7 +351,7 @@  bnx2x_dev_infos_get(struct rte_eth_dev *dev, __rte_unused struct rte_eth_dev_inf
 	dev_info->min_rx_bufsize = BNX2X_MIN_RX_BUF_SIZE;
 	dev_info->max_rx_pktlen  = BNX2X_MAX_RX_PKT_LEN;
 	dev_info->max_mac_addrs  = BNX2X_MAX_MAC_ADDRS;
-	dev_info->speed_capa = ETH_SPEED_CAP_10G | ETH_SPEED_CAP_20G;
+	dev_info->speed_capa = ETH_LINK_SPEED_10G | ETH_LINK_SPEED_20G;
 }
 
 static void
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/cxgbe/cxgbe_ethdev.c b/drivers/net/cxgbe/cxgbe_ethdev.c
index 203e119..05b954d 100644
--- a/drivers/net/cxgbe/cxgbe_ethdev.c
+++ b/drivers/net/cxgbe/cxgbe_ethdev.c
@@ -171,7 +171,7 @@  static void cxgbe_dev_info_get(struct rte_eth_dev *eth_dev,
 
 	device_info->rx_desc_lim = cxgbe_desc_lim;
 	device_info->tx_desc_lim = cxgbe_desc_lim;
-	device_info->speed_capa = ETH_SPEED_CAP_10G | ETH_SPEED_CAP_40G;
+	device_info->speed_capa = ETH_LINK_SPEED_10G | ETH_LINK_SPEED_40G;
 }
 
 static void cxgbe_dev_promiscuous_enable(struct rte_eth_dev *eth_dev)
diff --git a/drivers/net/e1000/em_ethdev.c b/drivers/net/e1000/em_ethdev.c
index e40dc37..12c4c63 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,17 @@  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)) {
-		hw->mac.ops.get_link_up_info(hw, &link.link_speed,
-			&link.link_duplex);
-		link.link_status = 1;
+		uint16_t duplex, speed;
+		hw->mac.ops.get_link_up_info(hw, &speed, &duplex);
+
+		link.link_duplex = (duplex) ? ETH_LINK_FULL_DUPLEX :
+						ETH_LINK_HALF_DUPLEX;
+		link.link_speed = speed;
+		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 7eac8ea..6682df5 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,20 @@  eth_igb_link_update(struct rte_eth_dev *dev, int wait_to_complete)
 
 	/* Now we check if a transition has happened */
 	if (link_check) {
-		hw->mac.ops.get_link_up_info(hw, &link.link_speed,
-					  &link.link_duplex);
-		link.link_status = 1;
+		uint16_t duplex, speed;
+		hw->mac.ops.get_link_up_info(hw, &speed, &duplex);
+
+		link.link_duplex = (duplex) ? ETH_LINK_FULL_DUPLEX :
+							ETH_LINK_HALF_DUPLEX;
+		link.link_speed = speed;
+		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 2e6ec60..f44818f 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 78a0cbd..e440dcf 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 13c5b3d..dd8f1e2 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 7e29c18..4fa07b6 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 c5688a7..01c3a5c 100644
--- a/drivers/net/mlx4/mlx4.c
+++ b/drivers/net/mlx4/mlx4.c
@@ -4265,8 +4265,8 @@  mlx4_dev_infos_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *info)
 	if (priv_get_ifname(priv, &ifname) == 0)
 		info->if_index = if_nametoindex(ifname);
 
-	info->speed_capa = ETH_SPEED_CAP_10G |ETH_SPEED_CAP_40G |
-					ETH_SPEED_CAP_56G;
+	info->speed_capa = ETH_LINK_SPEED_10G |ETH_LINK_SPEED_40G |
+					ETH_LINK_SPEED_56G;
 
 	priv_unlock(priv);
 }
@@ -4636,6 +4636,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 04f3c9f..ecb69b1 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/nfp/nfp_net.c b/drivers/net/nfp/nfp_net.c
index 98a957a..adde1a2 100644
--- a/drivers/net/nfp/nfp_net.c
+++ b/drivers/net/nfp/nfp_net.c
@@ -831,7 +831,7 @@  nfp_net_link_update(struct rte_eth_dev *dev, __rte_unused int wait_to_complete)
 
 	link.link_duplex = ETH_LINK_FULL_DUPLEX;
 	/* Other cards can limit the tx and rx rate per VF */
-	link.link_speed = ETH_LINK_SPEED_40G;
+	link.link_speed = ETH_SPEED_NUM_40G;
 
 	if (old.link_status != link.link_status) {
 		nfp_net_dev_atomic_write_link_status(dev, &link);
@@ -1072,7 +1072,7 @@  nfp_net_infos_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info)
 	dev_info->reta_size = NFP_NET_CFG_RSS_ITBL_SZ;
 	dev_info->hash_key_size = NFP_NET_CFG_RSS_KEY_SZ;
 
-	dev_info->speed_capa = ETH_SPEED_CAP_50G | ETH_SPEED_CAP_100G;
+	dev_info->speed_capa = ETH_LINK_SPEED_50G | ETH_LINK_SPEED_100G;
 }
 
 static uint32_t
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 caa970c..12e71af 100644
--- a/drivers/net/virtio/virtio_ethdev.c
+++ b/drivers/net/virtio/virtio_ethdev.c
@@ -1381,7 +1381,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 fed9571..66423a0 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 83ddbb7..8661521 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. */
+	uint64_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
diff --git a/lib/librte_ether/rte_ether_version.map b/lib/librte_ether/rte_ether_version.map
index d8db24d..2c14ad7 100644
--- a/lib/librte_ether/rte_ether_version.map
+++ b/lib/librte_ether/rte_ether_version.map
@@ -117,3 +117,9 @@  DPDK_2.2 {
 
 	local: *;
 };
+
+DPDK_2.3 {
+	global:
+
+	rte_eth_speed_to_bm_flag;
+}DPDK_2.2;