ethdev: redesign link speed config
authorMarc Sune <marcdevel@gmail.com>
Thu, 31 Mar 2016 22:12:29 +0000 (00:12 +0200)
committerThomas Monjalon <thomas.monjalon@6wind.com>
Fri, 1 Apr 2016 19:38:34 +0000 (21:38 +0200)
This patch redesigns the API to set the link speed/s configuration
of 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.

A flag autoneg in struct rte_eth_link indicates if link speed was a
result of auto-negociation or was fixed by configuration.

Signed-off-by: Marc Sune <marcdevel@gmail.com>
Tested-by: Nelio Laranjeiro <nelio.laranjeiro@6wind.com>
Signed-off-by: Thomas Monjalon <thomas.monjalon@6wind.com>
Tested-by: Beilei Xing <beilei.xing@intel.com>
Tested-by: Adrien Mazarguil <adrien.mazarguil@6wind.com>
22 files changed:
app/test-pmd/cmdline.c
doc/guides/rel_notes/deprecation.rst
doc/guides/rel_notes/release_16_04.rst
drivers/net/af_packet/rte_eth_af_packet.c
drivers/net/bnx2x/bnx2x_ethdev.c
drivers/net/bonding/rte_eth_bond_8023ad.c
drivers/net/e1000/em_ethdev.c
drivers/net/e1000/igb_ethdev.c
drivers/net/i40e/i40e_ethdev.c
drivers/net/i40e/i40e_ethdev_vf.c
drivers/net/ixgbe/ixgbe_ethdev.c
drivers/net/mlx4/mlx4.c
drivers/net/mlx5/mlx5_ethdev.c
drivers/net/mpipe/mpipe_tilegx.c
drivers/net/null/rte_eth_null.c
drivers/net/pcap/rte_eth_pcap.c
drivers/net/ring/rte_eth_ring.c
drivers/net/szedata2/rte_eth_szedata2.c
drivers/net/vmxnet3/vmxnet3_ethdev.c
drivers/net/xenvirt/rte_eth_xenvirt.c
examples/ip_pipeline/config_parse.c
lib/librte_ether/rte_ethdev.h

index 815b53b..741cac3 100644 (file)
@@ -989,7 +989,7 @@ struct cmd_config_speed_all {
 };
 
 static int
-parse_and_check_speed_duplex(char *speedstr, char *duplexstr, uint16_t *speed)
+parse_and_check_speed_duplex(char *speedstr, char *duplexstr, uint32_t *speed)
 {
 
        int duplex;
@@ -1006,20 +1006,22 @@ parse_and_check_speed_duplex(char *speedstr, char *duplexstr, uint16_t *speed)
        }
 
        if (!strcmp(speedstr, "10")) {
-               *speed = ETH_SPEED_NUM_10M;
+               *speed = (duplex == ETH_LINK_HALF_DUPLEX) ?
+                               ETH_LINK_SPEED_10M_HD : ETH_LINK_SPEED_10M;
        } else if (!strcmp(speedstr, "100")) {
-               *speed = ETH_SPEED_NUM_100M;
+               *speed = (duplex == ETH_LINK_HALF_DUPLEX) ?
+                               ETH_LINK_SPEED_100M_HD : ETH_LINK_SPEED_100M;
        } else {
                if (duplex != ETH_LINK_FULL_DUPLEX) {
                        printf("Invalid speed/duplex parameters\n");
                        return -1;
                }
                if (!strcmp(speedstr, "1000")) {
-                       *speed = ETH_SPEED_NUM_1G;
+                       *speed = ETH_LINK_SPEED_1G;
                } else if (!strcmp(speedstr, "10000")) {
-                       *speed = ETH_SPEED_NUM_10G;
+                       *speed = ETH_LINK_SPEED_10G;
                } else if (!strcmp(speedstr, "40000")) {
-                       *speed = ETH_SPEED_NUM_40G;
+                       *speed = ETH_LINK_SPEED_40G;
                } else if (!strcmp(speedstr, "auto")) {
                        *speed = ETH_LINK_SPEED_AUTONEG;
                } else {
@@ -1037,8 +1039,7 @@ cmd_config_speed_all_parsed(void *parsed_result,
                        __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()) {
@@ -1051,8 +1052,7 @@ cmd_config_speed_all_parsed(void *parsed_result,
                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);
@@ -1110,8 +1110,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");
@@ -1125,8 +1124,7 @@ cmd_config_speed_specific_parsed(void *parsed_result,
                        &link_speed) < 0)
                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);
 }
index 179e30f..c47610d 100644 (file)
@@ -19,9 +19,6 @@ Deprecation Notices
   ibadcrc, ibadlen, imcasts, fdirmatch, fdirmiss,
   tx_pause_xon, rx_pause_xon, tx_pause_xoff, rx_pause_xoff
 
-* The ethdev structures rte_eth_link, rte_eth_dev_info and rte_eth_conf
-  must be updated to support 100G link and to have a cleaner link speed API.
-
 * ABI changes are planned for adding four new flow types. This impacts
   RTE_ETH_FLOW_MAX. The release 2.2 does not contain these ABI changes,
   but release 2.3 will. [postponed]
index 8e565ab..05bf808 100644 (file)
@@ -52,6 +52,12 @@ This section should contain new features added in this release. Sample format:
   The structure ``rte_eth_dev_info`` has now a ``speed_capa`` bitmap, which
   allows the application to know the supported speeds of each device.
 
+* **Added bitmap of link speeds to advertise.**
+
+  Allow defining a set of advertised speeds for auto-negotiation,
+  explicitly disabling link auto-negotiation (single speed)
+  and full auto-negotiation.
+
 * **Added new poll-mode driver for Amazon Elastic Network Adapters (ENA).**
 
   The driver operates variety of ENA adapters through feature negotiation
@@ -472,6 +478,9 @@ This section should contain API changes. Sample format:
 * The ethdev structure ``rte_eth_dev_info`` was changed to support device
   speed capabilities.
 
+* The ethdev structures ``rte_eth_link`` and ``rte_eth_conf`` were changed to
+  support the new link API.
+
 * The functions ``rte_eth_dev_udp_tunnel_add`` and ``rte_eth_dev_udp_tunnel_delete``
   have been renamed into ``rte_eth_dev_udp_tunnel_port_add`` and
   ``rte_eth_dev_udp_tunnel_port_delete``.
index 641f849..f17bd7e 100644 (file)
@@ -119,6 +119,7 @@ static struct rte_eth_link pmd_link = {
        .link_speed = ETH_SPEED_NUM_10G,
        .link_duplex = ETH_LINK_FULL_DUPLEX,
        .link_status = ETH_LINK_DOWN,
+       .link_autoneg = ETH_LINK_SPEED_AUTONEG
 };
 
 static uint16_t
index 897081f..071b44f 100644 (file)
@@ -44,9 +44,9 @@ bnx2x_link_update(struct rte_eth_dev *dev)
                case DUPLEX_HALF:
                        dev->data->dev_link.link_duplex = ETH_LINK_HALF_DUPLEX;
                        break;
-               default:
-                       dev->data->dev_link.link_duplex = ETH_LINK_AUTONEG_DUPLEX;
        }
+       dev->data->dev_link.link_autoneg = !(dev->data->dev_conf.link_speeds &
+                       ETH_LINK_SPEED_FIXED);
        dev->data->dev_link.link_status = sc->link_vars.link_up;
 }
 
index 6ff2816..8b4db50 100644 (file)
@@ -708,7 +708,7 @@ 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_SPEED_NUM_10M:
index 890c5c3..653be09 100644 (file)
@@ -538,6 +538,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();
 
@@ -612,56 +615,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_SPEED_NUM_10M:
-               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_SPEED_NUM_100M:
-               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_FIXED) == 0;
+
+               /* 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 | ETH_LINK_SPEED_FIXED)) {
+                       num_speeds = -1;
                        goto error_invalid_config;
-               break;
-       case ETH_SPEED_NUM_1G:
-               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 > 1)))
                        goto error_invalid_config;
-               break;
-       case ETH_SPEED_NUM_10G:
-       default:
-               goto error_invalid_config;
        }
+
        e1000_setup_link(hw);
 
        if (rte_intr_allow_others(intr_handle)) {
@@ -695,9 +688,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;
 }
@@ -1107,13 +1099,20 @@ 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 == ETH_LINK_DOWN)) {
-               hw->mac.ops.get_link_up_info(hw, &link.link_speed,
-                       &link.link_duplex);
+               uint16_t duplex, speed;
+               hw->mac.ops.get_link_up_info(hw, &speed, &duplex);
+               link.link_duplex = (duplex == FULL_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_FIXED);
        } else if (!link_check && (link.link_status == ETH_LINK_UP)) {
                link.link_speed = 0;
                link.link_duplex = ETH_LINK_HALF_DUPLEX;
                link.link_status = ETH_LINK_DOWN;
+               link.link_autoneg = ETH_LINK_SPEED_FIXED;
        }
        rte_em_dev_atomic_write_link_status(dev, &link);
 
index 95d1711..e0053fe 100644 (file)
@@ -1133,6 +1133,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();
 
@@ -1233,48 +1236,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_SPEED_NUM_10M:
-               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_SPEED_NUM_100M:
-               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_FIXED) == 0;
+
+               /* 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 | ETH_LINK_SPEED_FIXED)) {
+                       num_speeds = -1;
                        goto error_invalid_config;
-               break;
-       case ETH_SPEED_NUM_1G:
-               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 > 1)))
                        goto error_invalid_config;
-               break;
-       case ETH_SPEED_NUM_10G:
-       default:
-               goto error_invalid_config;
        }
+
        e1000_setup_link(hw);
 
        if (rte_intr_allow_others(intr_handle)) {
@@ -1306,9 +1307,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;
 }
@@ -2061,13 +2061,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);
+               uint16_t duplex, speed;
+               hw->mac.ops.get_link_up_info(hw, &speed, &duplex);
+               link.link_duplex = (duplex == FULL_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_FIXED);
        } else if (!link_check) {
                link.link_speed = 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);
 
index cde314d..bc28d3c 100644 (file)
@@ -1381,27 +1381,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_SPEED_NUM_40G:
-               link_speed = I40E_LINK_SPEED_40GB;
-               break;
-       case ETH_SPEED_NUM_20G:
-               link_speed = I40E_LINK_SPEED_20GB;
-               break;
-       case ETH_SPEED_NUM_10G:
-               link_speed = I40E_LINK_SPEED_10GB;
-               break;
-       case ETH_SPEED_NUM_1G:
-               link_speed = I40E_LINK_SPEED_1GB;
-               break;
-       case ETH_SPEED_NUM_100M:
-               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;
 }
@@ -1427,9 +1420,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_FIXED))
                abilities |= I40E_AQ_PHY_AN_ENABLED;
        else
                abilities |= I40E_AQ_PHY_LINK_ENABLED;
@@ -1449,10 +1442,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_FIXED) {
+               PMD_INIT_LOG(ERR, "Invalid link_speeds for port %hhu; autonegotiation disabled",
                             dev->data->port_id);
                return -EINVAL;
        }
@@ -1525,6 +1516,12 @@ 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");
@@ -1809,6 +1806,9 @@ i40e_dev_link_update(struct rte_eth_dev *dev,
                break;
        }
 
+       link.link_autoneg = !(dev->data->dev_conf.link_speeds &
+                       ETH_LINK_SPEED_FIXED);
+
 out:
        rte_i40e_dev_atomic_write_link_status(dev, &link);
        if (link.link_status == old.link_status)
index 295dcd2..8cf22ee 100644 (file)
@@ -2121,12 +2121,13 @@ 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_SPEED_NUM_10G;
+               new_link.link_duplex = ETH_LINK_FULL_DUPLEX;
+               new_link.link_autoneg = ETH_LINK_SPEED_AUTONEG;
                new_link.link_status = ETH_LINK_UP;
        }
        i40evf_dev_atomic_write_link_status(dev, &new_link);
index 894278f..3f1ebc1 100644 (file)
@@ -2094,14 +2094,16 @@ 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,
+       /* IXGBE devices don't support:
+       *    - half duplex (checked afterwards for valid speeds)
+       *    - fixed speed: TODO implement
+       */
+       if (dev->data->dev_conf.link_speeds & ETH_LINK_SPEED_FIXED) {
+               PMD_INIT_LOG(ERR, "Invalid link_speeds for port %hhu; fix speed not supported",
                             dev->data->port_id);
                return -EINVAL;
        }
@@ -2198,30 +2200,25 @@ ixgbe_dev_start(struct rte_eth_dev *dev)
        if (err)
                goto error;
 
-       switch(dev->data->dev_conf.link_speed) {
-       case ETH_LINK_SPEED_AUTONEG:
+       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_AUTONEG) {
                speed = (hw->mac.type != ixgbe_mac_82598EB) ?
                                IXGBE_LINK_SPEED_82599_AUTONEG :
                                IXGBE_LINK_SPEED_82598_AUTONEG;
-               break;
-       case ETH_SPEED_NUM_100M:
-               /*
-                * Invalid for 82598 but error will be detected by
-                * ixgbe_setup_link()
-                */
-               speed = IXGBE_LINK_SPEED_100_FULL;
-               break;
-       case ETH_SPEED_NUM_1G:
-               speed = IXGBE_LINK_SPEED_1GB_FULL;
-               break;
-       case ETH_SPEED_NUM_10G:
-               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);
-               goto error;
+       } else {
+               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);
@@ -3088,7 +3085,7 @@ ixgbe_dev_link_update(struct rte_eth_dev *dev, int wait_to_complete)
 
        if (diag != 0) {
                link.link_speed = ETH_SPEED_NUM_100M;
-               link.link_duplex = ETH_LINK_HALF_DUPLEX;
+               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;
@@ -3107,7 +3104,7 @@ ixgbe_dev_link_update(struct rte_eth_dev *dev, int wait_to_complete)
        switch (link_speed) {
        default:
        case IXGBE_LINK_SPEED_UNKNOWN:
-               link.link_duplex = ETH_LINK_HALF_DUPLEX;
+               link.link_duplex = ETH_LINK_FULL_DUPLEX;
                link.link_speed = ETH_SPEED_NUM_100M;
                break;
 
index ed2f488..4f21dbe 100644 (file)
@@ -4736,6 +4736,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_FIXED);
        if (memcmp(&dev_link, &dev->data->dev_link, sizeof(dev_link))) {
                /* Link status changed. */
                dev->data->dev_link = dev_link;
index d7a0eea..beecc63 100644 (file)
@@ -629,6 +629,8 @@ mlx5_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_FIXED);
        if (memcmp(&dev_link, &dev->data->dev_link, sizeof(dev_link))) {
                /* Link status changed. */
                dev->data->dev_link = dev_link;
index 1a77c7a..adcbc19 100644 (file)
@@ -394,6 +394,8 @@ 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_AUTONEG);
                if (speed == GXIO_MPIPE_LINK_1G) {
                        new.link_speed = ETH_SPEED_NUM_1G;
                        new.link_duplex = ETH_LINK_FULL_DUPLEX;
index 5640585..5e8e203 100644 (file)
@@ -92,6 +92,7 @@ static struct rte_eth_link pmd_link = {
        .link_speed = ETH_SPEED_NUM_10G,
        .link_duplex = ETH_LINK_FULL_DUPLEX,
        .link_status = ETH_LINK_DOWN,
+       .link_autoneg = ETH_LINK_SPEED_AUTONEG,
 };
 
 static uint16_t
index c657951..c98e234 100644 (file)
@@ -126,6 +126,7 @@ static struct rte_eth_link pmd_link = {
                .link_speed = ETH_SPEED_NUM_10G,
                .link_duplex = ETH_LINK_FULL_DUPLEX,
                .link_status = ETH_LINK_DOWN,
+               .link_autoneg = ETH_LINK_SPEED_FIXED,
 };
 
 static int
index 58685e9..b1783c3 100644 (file)
@@ -80,6 +80,7 @@ static struct rte_eth_link pmd_link = {
                .link_speed = ETH_SPEED_NUM_10G,
                .link_duplex = ETH_LINK_FULL_DUPLEX,
                .link_status = ETH_LINK_DOWN,
+               .link_autoneg = ETH_LINK_SPEED_AUTONEG
 };
 
 static uint16_t
index dd1ae9e..ee97a4e 100644 (file)
@@ -1174,6 +1174,8 @@ eth_link_update(struct rte_eth_dev *dev,
        link.link_status = (cgmii_ibuf_is_enabled(ibuf) &&
                        cgmii_ibuf_is_link_up(ibuf)) ? ETH_LINK_UP : ETH_LINK_DOWN;
 
+       link.link_autoneg = ETH_LINK_SPEED_FIXED;
+
        rte_atomic64_cmpset((uint64_t *)dev_link, *(uint64_t *)dev_link,
                        *(uint64_t *)link_ptr);
 
index 95d533f..bd7a2bb 100644 (file)
@@ -779,6 +779,7 @@ vmxnet3_dev_link_update(struct rte_eth_dev *dev, __attribute__((unused)) int wai
                link.link_status = ETH_LINK_UP;
                link.link_duplex = ETH_LINK_FULL_DUPLEX;
                link.link_speed = ETH_SPEED_NUM_10G;
+               link.link_autoneg = ETH_LINK_SPEED_FIXED;
        }
 
        vmxnet3_dev_atomic_write_link_status(dev, &link);
index 77d3ba1..b9638d9 100644 (file)
@@ -73,6 +73,7 @@ static struct rte_eth_link pmd_link = {
                .link_speed = ETH_SPEED_NUM_10G,
                .link_duplex = ETH_LINK_FULL_DUPLEX,
                .link_status = ETH_LINK_DOWN,
+               .link_autoneg = ETH_LINK_SPEED_FIXED
 };
 
 static void
index 152889d..2cd5707 100644 (file)
@@ -87,8 +87,7 @@ static const struct app_link_params link_params_default = {
        .pci_bdf = {0},
 
        .conf = {
-               .link_speed = 0,
-               .link_duplex = 0,
+               .link_speeds = 0,
                .rxmode = {
                        .mq_mode = ETH_MQ_RX_NONE,
 
index 49fdcb7..b88300d 100644 (file)
@@ -244,6 +244,8 @@ struct rte_eth_stats {
 /**
  * Device supported speeds bitmap flags
  */
+#define ETH_LINK_SPEED_AUTONEG  (0 <<  0)  /**< Autonegotiate (all speeds) */
+#define ETH_LINK_SPEED_FIXED    (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 */
@@ -261,7 +263,7 @@ struct rte_eth_stats {
 /**
  * Ethernet numeric link speeds in Mbps
  */
-#define ETH_LINK_SPEED_AUTONEG     0 /**< Auto-negotiate link speed. */
+#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 */
@@ -278,17 +280,19 @@ struct rte_eth_stats {
  * A structure used to retrieve link-level information of an Ethernet port.
  */
 struct rte_eth_link {
-       uint16_t link_speed;      /**< ETH_SPEED_NUM_ */
-       uint16_t link_duplex;     /**< ETH_LINK_[HALF/FULL]_DUPLEX */
-       uint8_t  link_status : 1; /**< ETH_LINK_[DOWN/UP] */
-}__attribute__((aligned(8)));     /**< aligned for atomic64 read/write */
+       uint16_t link_speed;        /**< ETH_SPEED_NUM_ */
+       uint16_t link_duplex  : 1;  /**< ETH_LINK_[HALF/FULL]_DUPLEX */
+       uint16_t link_autoneg : 1;  /**< ETH_LINK_SPEED_[AUTONEG/FIXED] */
+       uint16_t link_status  : 1;  /**< ETH_LINK_[DOWN/UP] */
+} __attribute__((aligned(8)));      /**< aligned for atomic64 read/write */
 
 /* Utility constants */
-#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. */
+#define ETH_LINK_HALF_DUPLEX    0 /**< Half-duplex connection. */
+#define ETH_LINK_FULL_DUPLEX    1 /**< Full-duplex connection. */
 #define ETH_LINK_DOWN           0 /**< Link is down. */
 #define ETH_LINK_UP             1 /**< Link is up. */
+#define ETH_LINK_FIXED          0 /**< No autonegotiation. */
+#define ETH_LINK_AUTONEG        1 /**< Autonegotiated. */
 
 /**
  * A structure used to configure the ring threshold registers of an RX/TX
@@ -802,10 +806,13 @@ struct rte_intr_conf {
  * configuration settings may be needed.
  */
 struct rte_eth_conf {
-       uint16_t link_speed;
-       /**< ETH_SPEED_NUM_ or 0 for autonegotiation */
-       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_FIXED disables link
+                               autonegotiation, 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