mk: build with _GNU_SOURCE defined by default
[dpdk.git] / drivers / net / mlx5 / mlx5_ethdev.c
index f6cebae..d178ed6 100644 (file)
@@ -3,8 +3,6 @@
  * Copyright 2015 Mellanox Technologies, Ltd
  */
 
-#define _GNU_SOURCE
-
 #include <stddef.h>
 #include <assert.h>
 #include <inttypes.h>
 #include "mlx5_rxtx.h"
 #include "mlx5_utils.h"
 
+/* Supported speed values found in /usr/include/linux/ethtool.h */
+#ifndef HAVE_SUPPORTED_40000baseKR4_Full
+#define SUPPORTED_40000baseKR4_Full (1 << 23)
+#endif
+#ifndef HAVE_SUPPORTED_40000baseCR4_Full
+#define SUPPORTED_40000baseCR4_Full (1 << 24)
+#endif
+#ifndef HAVE_SUPPORTED_40000baseSR4_Full
+#define SUPPORTED_40000baseSR4_Full (1 << 25)
+#endif
+#ifndef HAVE_SUPPORTED_40000baseLR4_Full
+#define SUPPORTED_40000baseLR4_Full (1 << 26)
+#endif
+#ifndef HAVE_SUPPORTED_56000baseKR4_Full
+#define SUPPORTED_56000baseKR4_Full (1 << 27)
+#endif
+#ifndef HAVE_SUPPORTED_56000baseCR4_Full
+#define SUPPORTED_56000baseCR4_Full (1 << 28)
+#endif
+#ifndef HAVE_SUPPORTED_56000baseSR4_Full
+#define SUPPORTED_56000baseSR4_Full (1 << 29)
+#endif
+#ifndef HAVE_SUPPORTED_56000baseLR4_Full
+#define SUPPORTED_56000baseLR4_Full (1 << 30)
+#endif
+
 /* Add defines in case the running kernel is not the same as user headers. */
 #ifndef ETHTOOL_GLINKSETTINGS
 struct ethtool_link_settings {
@@ -93,7 +117,7 @@ struct ethtool_link_settings {
 #endif
 
 /**
- * Get interface name from private structure.
+ * Get master interface name from private structure.
  *
  * @param[in] dev
  *   Pointer to Ethernet device.
@@ -103,8 +127,9 @@ struct ethtool_link_settings {
  * @return
  *   0 on success, a negative errno value otherwise and rte_errno is set.
  */
-int
-mlx5_get_ifname(const struct rte_eth_dev *dev, char (*ifname)[IF_NAMESIZE])
+static int
+mlx5_get_master_ifname(const struct rte_eth_dev *dev,
+                      char (*ifname)[IF_NAMESIZE])
 {
        struct priv *priv = dev->data->dev_private;
        DIR *dir;
@@ -166,7 +191,7 @@ try_dev_id:
                if (dev_port == dev_port_prev)
                        goto try_dev_id;
                dev_port_prev = dev_port;
-               if (dev_port == (priv->port - 1u))
+               if (dev_port == 0)
                        strlcpy(match, name, sizeof(match));
        }
        closedir(dir);
@@ -179,30 +204,59 @@ try_dev_id:
 }
 
 /**
- * Get the interface index from device name.
+ * Get interface name from private structure.
+ *
+ * This is a port representor-aware version of mlx5_get_master_ifname().
  *
  * @param[in] dev
  *   Pointer to Ethernet device.
+ * @param[out] ifname
+ *   Interface name output buffer.
  *
  * @return
- *   Interface index on success, a negative errno value otherwise and
- *   rte_errno is set.
+ *   0 on success, a negative errno value otherwise and rte_errno is set.
  */
 int
+mlx5_get_ifname(const struct rte_eth_dev *dev, char (*ifname)[IF_NAMESIZE])
+{
+       struct priv *priv = dev->data->dev_private;
+       unsigned int ifindex =
+               priv->nl_socket_rdma >= 0 ?
+               mlx5_nl_ifindex(priv->nl_socket_rdma, priv->ibdev_name) : 0;
+
+       if (!ifindex) {
+               if (!priv->representor)
+                       return mlx5_get_master_ifname(dev, ifname);
+               rte_errno = ENXIO;
+               return -rte_errno;
+       }
+       if (if_indextoname(ifindex, &(*ifname)[0]))
+               return 0;
+       rte_errno = errno;
+       return -rte_errno;
+}
+
+/**
+ * Get the interface index from device name.
+ *
+ * @param[in] dev
+ *   Pointer to Ethernet device.
+ *
+ * @return
+ *   Nonzero interface index on success, zero otherwise and rte_errno is set.
+ */
+unsigned int
 mlx5_ifindex(const struct rte_eth_dev *dev)
 {
        char ifname[IF_NAMESIZE];
-       int ret;
+       unsigned int ifindex;
 
-       ret = mlx5_get_ifname(dev, &ifname);
-       if (ret)
-               return ret;
-       ret = if_nametoindex(ifname);
-       if (ret == -1) {
+       if (mlx5_get_ifname(dev, &ifname))
+               return 0;
+       ifindex = if_nametoindex(ifname);
+       if (!ifindex)
                rte_errno = errno;
-               return -rte_errno;
-       }
-       return ret;
+       return ifindex;
 }
 
 /**
@@ -335,15 +389,15 @@ mlx5_dev_configure(struct rte_eth_dev *dev)
 
        if (use_app_rss_key &&
            (dev->data->dev_conf.rx_adv_conf.rss_conf.rss_key_len !=
-            rss_hash_default_key_len)) {
-               DRV_LOG(ERR, "port %u RSS key len must be %zu Bytes long",
-                       dev->data->port_id, rss_hash_default_key_len);
+            MLX5_RSS_HASH_KEY_LEN)) {
+               DRV_LOG(ERR, "port %u RSS key len must be %s Bytes long",
+                       dev->data->port_id, RTE_STR(MLX5_RSS_HASH_KEY_LEN));
                rte_errno = EINVAL;
                return -rte_errno;
        }
        priv->rss_conf.rss_key =
                rte_realloc(priv->rss_conf.rss_key,
-                           rss_hash_default_key_len, 0);
+                           MLX5_RSS_HASH_KEY_LEN, 0);
        if (!priv->rss_conf.rss_key) {
                DRV_LOG(ERR, "port %u cannot allocate RSS hash key memory (%u)",
                        dev->data->port_id, rxqs_n);
@@ -354,8 +408,8 @@ mlx5_dev_configure(struct rte_eth_dev *dev)
               use_app_rss_key ?
               dev->data->dev_conf.rx_adv_conf.rss_conf.rss_key :
               rss_hash_default_key,
-              rss_hash_default_key_len);
-       priv->rss_conf.rss_key_len = rss_hash_default_key_len;
+              MLX5_RSS_HASH_KEY_LEN);
+       priv->rss_conf.rss_key_len = MLX5_RSS_HASH_KEY_LEN;
        priv->rss_conf.rss_hf = dev->data->dev_conf.rx_adv_conf.rss_conf.rss_hf;
        priv->rxqs = (void *)dev->data->rx_queues;
        priv->txqs = (void *)dev->data->tx_queues;
@@ -392,17 +446,6 @@ mlx5_dev_configure(struct rte_eth_dev *dev)
                if (++j == rxqs_n)
                        j = 0;
        }
-       /*
-        * Once the device is added to the list of memory event callback, its
-        * global MR cache table cannot be expanded on the fly because of
-        * deadlock. If it overflows, lookup should be done by searching MR list
-        * linearly, which is slow.
-        */
-       if (mlx5_mr_btree_init(&priv->mr.cache, MLX5_MR_BTREE_CACHE_N * 2,
-                              dev->device->numa_node)) {
-               /* rte_errno is already set. */
-               return -rte_errno;
-       }
        return 0;
 }
 
@@ -484,10 +527,34 @@ mlx5_dev_infos_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *info)
                info->if_index = if_nametoindex(ifname);
        info->reta_size = priv->reta_idx_n ?
                priv->reta_idx_n : config->ind_table_max_size;
-       info->hash_key_size = rss_hash_default_key_len;
+       info->hash_key_size = MLX5_RSS_HASH_KEY_LEN;
        info->speed_capa = priv->link_speed_capa;
        info->flow_type_rss_offloads = ~MLX5_RSS_HF_MASK;
        mlx5_set_default_params(dev, info);
+       info->switch_info.name = dev->data->name;
+       info->switch_info.domain_id = priv->domain_id;
+       info->switch_info.port_id = priv->representor_id;
+       if (priv->representor) {
+               unsigned int i = mlx5_dev_to_port_id(dev->device, NULL, 0);
+               uint16_t port_id[i];
+
+               i = RTE_MIN(mlx5_dev_to_port_id(dev->device, port_id, i), i);
+               while (i--) {
+                       struct priv *opriv =
+                               rte_eth_devices[port_id[i]].data->dev_private;
+
+                       if (!opriv ||
+                           opriv->representor ||
+                           opriv->domain_id != priv->domain_id)
+                               continue;
+                       /*
+                        * Override switch name with that of the master
+                        * device.
+                        */
+                       info->switch_info.name = opriv->dev_data->name;
+                       break;
+               }
+       }
 }
 
 /**
@@ -557,10 +624,13 @@ mlx5_link_update_unlocked_gset(struct rte_eth_dev *dev,
                        dev->data->port_id, strerror(rte_errno));
                return ret;
        }
-       memset(&dev_link, 0, sizeof(dev_link));
-       dev_link.link_status = ((ifr.ifr_flags & IFF_UP) &&
-                               (ifr.ifr_flags & IFF_RUNNING));
-       ifr.ifr_data = (void *)&edata;
+       dev_link = (struct rte_eth_link) {
+               .link_status = ((ifr.ifr_flags & IFF_UP) &&
+                               (ifr.ifr_flags & IFF_RUNNING)),
+       };
+       ifr = (struct ifreq) {
+               .ifr_data = (void *)&edata,
+       };
        ret = mlx5_ifreq(dev, SIOCETHTOOL, &ifr);
        if (ret) {
                DRV_LOG(WARNING,
@@ -590,8 +660,8 @@ mlx5_link_update_unlocked_gset(struct rte_eth_dev *dev,
                                ETH_LINK_HALF_DUPLEX : ETH_LINK_FULL_DUPLEX);
        dev_link.link_autoneg = !(dev->data->dev_conf.link_speeds &
                        ETH_LINK_SPEED_FIXED);
-       if ((dev_link.link_speed && !dev_link.link_status) ||
-           (!dev_link.link_speed && dev_link.link_status)) {
+       if (((dev_link.link_speed && !dev_link.link_status) ||
+            (!dev_link.link_speed && dev_link.link_status))) {
                rte_errno = EAGAIN;
                return -rte_errno;
        }
@@ -628,10 +698,13 @@ mlx5_link_update_unlocked_gs(struct rte_eth_dev *dev,
                        dev->data->port_id, strerror(rte_errno));
                return ret;
        }
-       memset(&dev_link, 0, sizeof(dev_link));
-       dev_link.link_status = ((ifr.ifr_flags & IFF_UP) &&
-                               (ifr.ifr_flags & IFF_RUNNING));
-       ifr.ifr_data = (void *)&gcmd;
+       dev_link = (struct rte_eth_link) {
+               .link_status = ((ifr.ifr_flags & IFF_UP) &&
+                               (ifr.ifr_flags & IFF_RUNNING)),
+       };
+       ifr = (struct ifreq) {
+               .ifr_data = (void *)&gcmd,
+       };
        ret = mlx5_ifreq(dev, SIOCETHTOOL, &ifr);
        if (ret) {
                DRV_LOG(DEBUG,
@@ -699,8 +772,8 @@ mlx5_link_update_unlocked_gs(struct rte_eth_dev *dev,
                                ETH_LINK_HALF_DUPLEX : ETH_LINK_FULL_DUPLEX);
        dev_link.link_autoneg = !(dev->data->dev_conf.link_speeds &
                                  ETH_LINK_SPEED_FIXED);
-       if ((dev_link.link_speed && !dev_link.link_status) ||
-           (!dev_link.link_speed && dev_link.link_status)) {
+       if (((dev_link.link_speed && !dev_link.link_status) ||
+            (!dev_link.link_speed && dev_link.link_status))) {
                rte_errno = EAGAIN;
                return -rte_errno;
        }
@@ -1204,3 +1277,90 @@ mlx5_is_removed(struct rte_eth_dev *dev)
                return 1;
        return 0;
 }
+
+/**
+ * Get port ID list of mlx5 instances sharing a common device.
+ *
+ * @param[in] dev
+ *   Device to look for.
+ * @param[out] port_list
+ *   Result buffer for collected port IDs.
+ * @param port_list_n
+ *   Maximum number of entries in result buffer. If 0, @p port_list can be
+ *   NULL.
+ *
+ * @return
+ *   Number of matching instances regardless of the @p port_list_n
+ *   parameter, 0 if none were found.
+ */
+unsigned int
+mlx5_dev_to_port_id(const struct rte_device *dev, uint16_t *port_list,
+                   unsigned int port_list_n)
+{
+       uint16_t id;
+       unsigned int n = 0;
+
+       RTE_ETH_FOREACH_DEV(id) {
+               struct rte_eth_dev *ldev = &rte_eth_devices[id];
+
+               if (ldev->device != dev)
+                       continue;
+               if (n < port_list_n)
+                       port_list[n] = id;
+               n++;
+       }
+       return n;
+}
+
+/**
+ * Get switch information associated with network interface.
+ *
+ * @param ifindex
+ *   Network interface index.
+ * @param[out] info
+ *   Switch information object, populated in case of success.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise and rte_errno is set.
+ */
+int
+mlx5_sysfs_switch_info(unsigned int ifindex, struct mlx5_switch_info *info)
+{
+       char ifname[IF_NAMESIZE];
+       FILE *file;
+       struct mlx5_switch_info data = { .master = 0, };
+       bool port_name_set = false;
+       bool port_switch_id_set = false;
+       char c;
+
+       if (!if_indextoname(ifindex, ifname)) {
+               rte_errno = errno;
+               return -rte_errno;
+       }
+
+       MKSTR(phys_port_name, "/sys/class/net/%s/phys_port_name",
+             ifname);
+       MKSTR(phys_switch_id, "/sys/class/net/%s/phys_switch_id",
+             ifname);
+
+       file = fopen(phys_port_name, "rb");
+       if (file != NULL) {
+               port_name_set =
+                       fscanf(file, "%d%c", &data.port_name, &c) == 2 &&
+                       c == '\n';
+               fclose(file);
+       }
+       file = fopen(phys_switch_id, "rb");
+       if (file == NULL) {
+               rte_errno = errno;
+               return -rte_errno;
+       }
+       port_switch_id_set =
+               fscanf(file, "%" SCNx64 "%c", &data.switch_id, &c) == 2 &&
+               c == '\n';
+       fclose(file);
+       data.master = port_switch_id_set && !port_name_set;
+       data.representor = port_switch_id_set && port_name_set;
+       *info = data;
+       return 0;
+}