197f17497SC.J. Collier/*-
297f17497SC.J. Collier *   BSD LICENSE
397f17497SC.J. Collier *
497f17497SC.J. Collier *   Copyright 2015 6WIND S.A.
597f17497SC.J. Collier *   Copyright 2015 Mellanox.
697f17497SC.J. Collier *
797f17497SC.J. Collier *   Redistribution and use in source and binary forms, with or without
897f17497SC.J. Collier *   modification, are permitted provided that the following conditions
997f17497SC.J. Collier *   are met:
1097f17497SC.J. Collier *
1197f17497SC.J. Collier *     * Redistributions of source code must retain the above copyright
1297f17497SC.J. Collier *       notice, this list of conditions and the following disclaimer.
1397f17497SC.J. Collier *     * Redistributions in binary form must reproduce the above copyright
1497f17497SC.J. Collier *       notice, this list of conditions and the following disclaimer in
1597f17497SC.J. Collier *       the documentation and/or other materials provided with the
1697f17497SC.J. Collier *       distribution.
1797f17497SC.J. Collier *     * Neither the name of 6WIND S.A. nor the names of its
1897f17497SC.J. Collier *       contributors may be used to endorse or promote products derived
1997f17497SC.J. Collier *       from this software without specific prior written permission.
2097f17497SC.J. Collier *
3297f17497SC.J. Collier */
3397f17497SC.J. Collier
3497f17497SC.J. Collier#include <stddef.h>
3597f17497SC.J. Collier#include <assert.h>
3697f17497SC.J. Collier#include <unistd.h>
3797f17497SC.J. Collier#include <stdint.h>
3897f17497SC.J. Collier#include <stdio.h>
3997f17497SC.J. Collier#include <string.h>
4097f17497SC.J. Collier#include <stdlib.h>
4197f17497SC.J. Collier#include <errno.h>
4297f17497SC.J. Collier#include <dirent.h>
4397f17497SC.J. Collier#include <net/if.h>
4497f17497SC.J. Collier#include <sys/ioctl.h>
4597f17497SC.J. Collier#include <sys/socket.h>
46ce3d555eSChristian Ehrhardt#include <sys/utsname.h>
4797f17497SC.J. Collier#include <netinet/in.h>
4897f17497SC.J. Collier#include <linux/ethtool.h>
4997f17497SC.J. Collier#include <linux/sockios.h>
50ce3d555eSChristian Ehrhardt#include <linux/version.h>
5197f17497SC.J. Collier#include <fcntl.h>
5247d9763aSLuca Boccassi#include <stdalign.h>
5397f17497SC.J. Collier
5497f17497SC.J. Collier/* DPDK headers don't like -pedantic. */
5597f17497SC.J. Collier#ifdef PEDANTIC
5632e04ea0SChristian Ehrhardt#pragma GCC diagnostic ignored "-Wpedantic"
5797f17497SC.J. Collier#endif
5897f17497SC.J. Collier#include <rte_atomic.h>
5997f17497SC.J. Collier#include <rte_ethdev.h>
6097f17497SC.J. Collier#include <rte_mbuf.h>
6197f17497SC.J. Collier#include <rte_common.h>
6297f17497SC.J. Collier#include <rte_interrupts.h>
6397f17497SC.J. Collier#include <rte_alarm.h>
6497f17497SC.J. Collier#include <rte_malloc.h>
6597f17497SC.J. Collier#ifdef PEDANTIC
6632e04ea0SChristian Ehrhardt#pragma GCC diagnostic error "-Wpedantic"
6797f17497SC.J. Collier#endif
6897f17497SC.J. Collier
6997f17497SC.J. Collier#include "mlx5.h"
7097f17497SC.J. Collier#include "mlx5_rxtx.h"
7197f17497SC.J. Collier#include "mlx5_utils.h"
7297f17497SC.J. Collier
73ce3d555eSChristian Ehrhardt/* Add defines in case the running kernel is not the same as user headers. */
74ce3d555eSChristian Ehrhardt#ifndef ETHTOOL_GLINKSETTINGS
75ce3d555eSChristian Ehrhardtstruct ethtool_link_settings {
76ce3d555eSChristian Ehrhardt	uint32_t cmd;
77ce3d555eSChristian Ehrhardt	uint32_t speed;
78ce3d555eSChristian Ehrhardt	uint8_t duplex;
79ce3d555eSChristian Ehrhardt	uint8_t port;
80ce3d555eSChristian Ehrhardt	uint8_t phy_address;
81ce3d555eSChristian Ehrhardt	uint8_t autoneg;
82ce3d555eSChristian Ehrhardt	uint8_t mdio_support;
83ce3d555eSChristian Ehrhardt	uint8_t eth_to_mdix;
84ce3d555eSChristian Ehrhardt	uint8_t eth_tp_mdix_ctrl;
85ce3d555eSChristian Ehrhardt	int8_t link_mode_masks_nwords;
86ce3d555eSChristian Ehrhardt	uint32_t reserved[8];
87ce3d555eSChristian Ehrhardt	uint32_t link_mode_masks[];
88ce3d555eSChristian Ehrhardt};
89ce3d555eSChristian Ehrhardt
90ce3d555eSChristian Ehrhardt#define ETHTOOL_GLINKSETTINGS 0x0000004c
91ce3d555eSChristian Ehrhardt#define ETHTOOL_LINK_MODE_1000baseT_Full_BIT 5
92ce3d555eSChristian Ehrhardt#define ETHTOOL_LINK_MODE_Autoneg_BIT 6
93ce3d555eSChristian Ehrhardt#define ETHTOOL_LINK_MODE_1000baseKX_Full_BIT 17
94ce3d555eSChristian Ehrhardt#define ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT 18
95ce3d555eSChristian Ehrhardt#define ETHTOOL_LINK_MODE_10000baseKR_Full_BIT 19
96ce3d555eSChristian Ehrhardt#define ETHTOOL_LINK_MODE_10000baseR_FEC_BIT 20
97ce3d555eSChristian Ehrhardt#define ETHTOOL_LINK_MODE_20000baseMLD2_Full_BIT 21
98ce3d555eSChristian Ehrhardt#define ETHTOOL_LINK_MODE_20000baseKR2_Full_BIT 22
99ce3d555eSChristian Ehrhardt#define ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT 23
100ce3d555eSChristian Ehrhardt#define ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT 24
101ce3d555eSChristian Ehrhardt#define ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT 25
102ce3d555eSChristian Ehrhardt#define ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT 26
103ce3d555eSChristian Ehrhardt#define ETHTOOL_LINK_MODE_56000baseKR4_Full_BIT 27
104ce3d555eSChristian Ehrhardt#define ETHTOOL_LINK_MODE_56000baseCR4_Full_BIT 28
105ce3d555eSChristian Ehrhardt#define ETHTOOL_LINK_MODE_56000baseSR4_Full_BIT 29
106ce3d555eSChristian Ehrhardt#define ETHTOOL_LINK_MODE_56000baseLR4_Full_BIT 30
107ce3d555eSChristian Ehrhardt#endif
108ce3d555eSChristian Ehrhardt#ifndef HAVE_ETHTOOL_LINK_MODE_25G
109ce3d555eSChristian Ehrhardt#define ETHTOOL_LINK_MODE_25000baseCR_Full_BIT 31
110ce3d555eSChristian Ehrhardt#define ETHTOOL_LINK_MODE_25000baseKR_Full_BIT 32
111ce3d555eSChristian Ehrhardt#define ETHTOOL_LINK_MODE_25000baseSR_Full_BIT 33
112ce3d555eSChristian Ehrhardt#endif
113ce3d555eSChristian Ehrhardt#ifndef HAVE_ETHTOOL_LINK_MODE_50G
114ce3d555eSChristian Ehrhardt#define ETHTOOL_LINK_MODE_50000baseCR2_Full_BIT 34
115ce3d555eSChristian Ehrhardt#define ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT 35
116ce3d555eSChristian Ehrhardt#endif
117ce3d555eSChristian Ehrhardt#ifndef HAVE_ETHTOOL_LINK_MODE_100G
118ce3d555eSChristian Ehrhardt#define ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT 36
119ce3d555eSChristian Ehrhardt#define ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT 37
120ce3d555eSChristian Ehrhardt#define ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT 38
121ce3d555eSChristian Ehrhardt#define ETHTOOL_LINK_MODE_100000baseLR4_ER4_Full_BIT 39
122ce3d555eSChristian Ehrhardt#endif
123ce3d555eSChristian Ehrhardt
12497f17497SC.J. Collier/**
12597f17497SC.J. Collier * Return private structure associated with an Ethernet device.
12697f17497SC.J. Collier *
12797f17497SC.J. Collier * @param dev
12897f17497SC.J. Collier *   Pointer to Ethernet device structure.
12997f17497SC.J. Collier *
13097f17497SC.J. Collier * @return
13197f17497SC.J. Collier *   Pointer to private structure.
13297f17497SC.J. Collier */
13397f17497SC.J. Collierstruct priv *
13497f17497SC.J. Colliermlx5_get_priv(struct rte_eth_dev *dev)
13597f17497SC.J. Collier{
13697f17497SC.J. Collier	struct mlx5_secondary_data *sd;
13797f17497SC.J. Collier
13897f17497SC.J. Collier	if (!mlx5_is_secondary())
13997f17497SC.J. Collier		return dev->data->dev_private;
14097f17497SC.J. Collier	sd = &mlx5_secondary_data[dev->data->port_id];
14197f17497SC.J. Collier	return sd->data.dev_private;
14297f17497SC.J. Collier}
14397f17497SC.J. Collier
14497f17497SC.J. Collier/**
14597f17497SC.J. Collier * Check if running as a secondary process.
14697f17497SC.J. Collier *
14797f17497SC.J. Collier * @return
14897f17497SC.J. Collier *   Nonzero if running as a secondary process.
14997f17497SC.J. Collier */
15097f17497SC.J. Collierinline int
15197f17497SC.J. Colliermlx5_is_secondary(void)
15297f17497SC.J. Collier{
15397f17497SC.J. Collier	return rte_eal_process_type() != RTE_PROC_PRIMARY;
15497f17497SC.J. Collier}
15597f17497SC.J. Collier
15697f17497SC.J. Collier/**
15797f17497SC.J. Collier * Get interface name from private structure.
15897f17497SC.J. Collier *
15997f17497SC.J. Collier * @param[in] priv
16097f17497SC.J. Collier *   Pointer to private structure.
16197f17497SC.J. Collier * @param[out] ifname
16297f17497SC.J. Collier *   Interface name output buffer.
16397f17497SC.J. Collier *
16497f17497SC.J. Collier * @return
16597f17497SC.J. Collier *   0 on success, -1 on failure and errno is set.
16697f17497SC.J. Collier */
16797f17497SC.J. Collierint
16897f17497SC.J. Collierpriv_get_ifname(const struct priv *priv, char (*ifname)[IF_NAMESIZE])
16997f17497SC.J. Collier{
17097f17497SC.J. Collier	DIR *dir;
17197f17497SC.J. Collier	struct dirent *dent;
17297f17497SC.J. Collier	unsigned int dev_type = 0;
17397f17497SC.J. Collier	unsigned int dev_port_prev = ~0u;
17497f17497SC.J. Collier	char match[IF_NAMESIZE] = "";
17597f17497SC.J. Collier
17697f17497SC.J. Collier	{
17797f17497SC.J. Collier		MKSTR(path, "%s/device/net", priv->ctx->device->ibdev_path);
17897f17497SC.J. Collier
17997f17497SC.J. Collier		dir = opendir(path);
18097f17497SC.J. Collier		if (dir == NULL)
18197f17497SC.J. Collier			return -1;
18297f17497SC.J. Collier	}
18397f17497SC.J. Collier	while ((dent = readdir(dir)) != NULL) {
18497f17497SC.J. Collier		char *name = dent->d_name;
18597f17497SC.J. Collier		FILE *file;
18697f17497SC.J. Collier		unsigned int dev_port;
18797f17497SC.J. Collier		int r;
18897f17497SC.J. Collier
18997f17497SC.J. Collier		if ((name[0] == '.') &&
19097f17497SC.J. Collier		    ((name[1] == '\0') ||
19197f17497SC.J. Collier		     ((name[1] == '.') && (name[2] == '\0'))))
19297f17497SC.J. Collier			continue;
19397f17497SC.J. Collier
19497f17497SC.J. Collier		MKSTR(path, "%s/device/net/%s/%s",
19597f17497SC.J. Collier		      priv->ctx->device->ibdev_path, name,
19697f17497SC.J. Collier		      (dev_type ? "dev_id" : "dev_port"));
19797f17497SC.J. Collier
19897f17497SC.J. Collier		file = fopen(path, "rb");
19997f17497SC.J. Collier		if (file == NULL) {
20097f17497SC.J. Collier			if (errno != ENOENT)
20197f17497SC.J. Collier				continue;
20297f17497SC.J. Collier			/*
20397f17497SC.J. Collier			 * Switch to dev_id when dev_port does not exist as
20497f17497SC.J. Collier			 * is the case with Linux kernel versions < 3.15.
20597f17497SC.J. Collier			 */
20697f17497SC.J. Colliertry_dev_id:
20797f17497SC.J. Collier			match[0] = '\0';
20897f17497SC.J. Collier			if (dev_type)
20997f17497SC.J. Collier				break;
21097f17497SC.J. Collier			dev_type = 1;
21197f17497SC.J. Collier			dev_port_prev = ~0u;
21297f17497SC.J. Collier			rewinddir(dir);
21397f17497SC.J. Collier			continue;
21497f17497SC.J. Collier		}
21597f17497SC.J. Collier		r = fscanf(file, (dev_type ? "%x" : "%u"), &dev_port);
21697f17497SC.J. Collier		fclose(file);
21797f17497SC.J. Collier		if (r != 1)
21897f17497SC.J. Collier			continue;
21997f17497SC.J. Collier		/*
22097f17497SC.J. Collier		 * Switch to dev_id when dev_port returns the same value for
22197f17497SC.J. Collier		 * all ports. May happen when using a MOFED release older than
22297f17497SC.J. Collier		 * 3.0 with a Linux kernel >= 3.15.
22397f17497SC.J. Collier		 */
22497f17497SC.J. Collier		if (dev_port == dev_port_prev)
22597f17497SC.J. Collier			goto try_dev_id;
22697f17497SC.J. Collier		dev_port_prev = dev_port;
22797f17497SC.J. Collier		if (dev_port == (priv->port - 1u))
22897f17497SC.J. Collier			snprintf(match, sizeof(match), "%s", name);
22997f17497SC.J. Collier	}
23097f17497SC.J. Collier	closedir(dir);
23197f17497SC.J. Collier	if (match[0] == '\0')
23297f17497SC.J. Collier		return -1;
23397f17497SC.J. Collier	strncpy(*ifname, match, sizeof(*ifname));
23497f17497SC.J. Collier	return 0;
23597f17497SC.J. Collier}
23697f17497SC.J. Collier
23797f17497SC.J. Collier/**
23897f17497SC.J. Collier * Read from sysfs entry.
23997f17497SC.J. Collier *
24097f17497SC.J. Collier * @param[in] priv
24197f17497SC.J. Collier *   Pointer to private structure.
24297f17497SC.J. Collier * @param[in] entry
24397f17497SC.J. Collier *   Entry name relative to sysfs path.
24497f17497SC.J. Collier * @param[out] buf
24597f17497SC.J. Collier *   Data output buffer.
24697f17497SC.J. Collier * @param size
24797f17497SC.J. Collier *   Buffer size.
24897f17497SC.J. Collier *
24997f17497SC.J. Collier * @return
25097f17497SC.J. Collier *   0 on success, -1 on failure and errno is set.
25197f17497SC.J. Collier */
25297f17497SC.J. Collierstatic int
25397f17497SC.J. Collierpriv_sysfs_read(const struct priv *priv, const char *entry,
25497f17497SC.J. Collier		char *buf, size_t size)
25597f17497SC.J. Collier{
25697f17497SC.J. Collier	char ifname[IF_NAMESIZE];
25797f17497SC.J. Collier	FILE *file;
25897f17497SC.J. Collier	int ret;
25997f17497SC.J. Collier	int err;
26097f17497SC.J. Collier
26197f17497SC.J. Collier	if (priv_get_ifname(priv, &ifname))
26297f17497SC.J. Collier		return -1;
26397f17497SC.J. Collier
26497f17497SC.J. Collier	MKSTR(path, "%s/device/net/%s/%s", priv->ctx->device->ibdev_path,
26597f17497SC.J. Collier	      ifname, entry);
26697f17497SC.J. Collier
26797f17497SC.J. Collier	file = fopen(path, "rb");
26897f17497SC.J. Collier	if (file == NULL)
26997f17497SC.J. Collier		return -1;
27097f17497SC.J. Collier	ret = fread(buf, 1, size, file);
27197f17497SC.J. Collier	err = errno;
27297f17497SC.J. Collier	if (((size_t)ret < size) && (ferror(file)))
27397f17497SC.J. Collier		ret = -1;
27497f17497SC.J. Collier	else
27597f17497SC.J. Collier		ret = size;
27697f17497SC.J. Collier	fclose(file);
27797f17497SC.J. Collier	errno = err;
27897f17497SC.J. Collier	return ret;
27997f17497SC.J. Collier}
28097f17497SC.J. Collier
28197f17497SC.J. Collier/**
28297f17497SC.J. Collier * Write to sysfs entry.
28397f17497SC.J. Collier *
28497f17497SC.J. Collier * @param[in] priv
28597f17497SC.J. Collier *   Pointer to private structure.
28697f17497SC.J. Collier * @param[in] entry
28797f17497SC.J. Collier *   Entry name relative to sysfs path.
28897f17497SC.J. Collier * @param[in] buf
28997f17497SC.J. Collier *   Data buffer.
29097f17497SC.J. Collier * @param size
29197f17497SC.J. Collier *   Buffer size.
29297f17497SC.J. Collier *
29397f17497SC.J. Collier * @return
29497f17497SC.J. Collier *   0 on success, -1 on failure and errno is set.
29597f17497SC.J. Collier */
29697f17497SC.J. Collierstatic int
29797f17497SC.J. Collierpriv_sysfs_write(const struct priv *priv, const char *entry,
29897f17497SC.J. Collier		 char *buf, size_t size)
29997f17497SC.J. Collier{
30097f17497SC.J. Collier	char ifname[IF_NAMESIZE];
30197f17497SC.J. Collier	FILE *file;
30297f17497SC.J. Collier	int ret;
30397f17497SC.J. Collier	int err;
30497f17497SC.J. Collier
30597f17497SC.J. Collier	if (priv_get_ifname(priv, &ifname))
30697f17497SC.J. Collier		return -1;
30797f17497SC.J. Collier
30897f17497SC.J. Collier	MKSTR(path, "%s/device/net/%s/%s", priv->ctx->device->ibdev_path,
30997f17497SC.J. Collier	      ifname, entry);
31097f17497SC.J. Collier
31197f17497SC.J. Collier	file = fopen(path, "wb");
31297f17497SC.J. Collier	if (file == NULL)
31397f17497SC.J. Collier		return -1;
31497f17497SC.J. Collier	ret = fwrite(buf, 1, size, file);
31597f17497SC.J. Collier	err = errno;
31697f17497SC.J. Collier	if (((size_t)ret < size) || (ferror(file)))
31797f17497SC.J. Collier		ret = -1;
31897f17497SC.J. Collier	else
31997f17497SC.J. Collier		ret = size;
32097f17497SC.J. Collier	fclose(file);
32197f17497SC.J. Collier	errno = err;
32297f17497SC.J. Collier	return ret;
32397f17497SC.J. Collier}
32497f17497SC.J. Collier
32597f17497SC.J. Collier/**
32697f17497SC.J. Collier * Get unsigned long sysfs property.
32797f17497SC.J. Collier *
32897f17497SC.J. Collier * @param priv
32997f17497SC.J. Collier *   Pointer to private structure.
33097f17497SC.J. Collier * @param[in] name
33197f17497SC.J. Collier *   Entry name relative to sysfs path.
33297f17497SC.J. Collier * @param[out] value
33397f17497SC.J. Collier *   Value output buffer.
33497f17497SC.J. Collier *
33597f17497SC.J. Collier * @return
33697f17497SC.J. Collier *   0 on success, -1 on failure and errno is set.
33797f17497SC.J. Collier */
33897f17497SC.J. Collierstatic int
33997f17497SC.J. Collierpriv_get_sysfs_ulong(struct priv *priv, const char *name, unsigned long *value)
34097f17497SC.J. Collier{
34197f17497SC.J. Collier	int ret;
34297f17497SC.J. Collier	unsigned long value_ret;
34397f17497SC.J. Collier	char value_str[32];
34497f17497SC.J. Collier
34597f17497SC.J. Collier	ret = priv_sysfs_read(priv, name, value_str, (sizeof(value_str) - 1));
34697f17497SC.J. Collier	if (ret == -1) {
34797f17497SC.J. Collier		DEBUG("cannot read %s value from sysfs: %s",
34897f17497SC.J. Collier		      name, strerror(errno));
34997f17497SC.J. Collier		return -1;
35097f17497SC.J. Collier	}
35197f17497SC.J. Collier	value_str[ret] = '\0';
35297f17497SC.J. Collier	errno = 0;
35397f17497SC.J. Collier	value_ret = strtoul(value_str, NULL, 0);
35497f17497SC.J. Collier	if (errno) {
35597f17497SC.J. Collier		DEBUG("invalid %s value `%s': %s", name, value_str,
35697f17497SC.J. Collier		      strerror(errno));
35797f17497SC.J. Collier		return -1;
35897f17497SC.J. Collier	}
35997f17497SC.J. Collier	*value = value_ret;
36097f17497SC.J. Collier	return 0;
36197f17497SC.J. Collier}
36297f17497SC.J. Collier
36397f17497SC.J. Collier/**
36497f17497SC.J. Collier * Set unsigned long sysfs property.
36597f17497SC.J. Collier *
36697f17497SC.J. Collier * @param priv
36797f17497SC.J. Collier *   Pointer to private structure.
36897f17497SC.J. Collier * @param[in] name
36997f17497SC.J. Collier *   Entry name relative to sysfs path.
37097f17497SC.J. Collier * @param value
37197f17497SC.J. Collier *   Value to set.
37297f17497SC.J. Collier *
37397f17497SC.J. Collier * @return
37497f17497SC.J. Collier *   0 on success, -1 on failure and errno is set.
37597f17497SC.J. Collier */
37697f17497SC.J. Collierstatic int
37797f17497SC.J. Collierpriv_set_sysfs_ulong(struct priv *priv, const char *name, unsigned long value)
37897f17497SC.J. Collier{
37997f17497SC.J. Collier	int ret;
38097f17497SC.J. Collier	MKSTR(value_str, "%lu", value);
38197f17497SC.J. Collier
38297f17497SC.J. Collier	ret = priv_sysfs_write(priv, name, value_str, (sizeof(value_str) - 1));
38397f17497SC.J. Collier	if (ret == -1) {
38497f17497SC.J. Collier		DEBUG("cannot write %s `%s' (%lu) to sysfs: %s",
38597f17497SC.J. Collier		      name, value_str, value, strerror(errno));
38697f17497SC.J. Collier		return -1;
38797f17497SC.J. Collier	}
38897f17497SC.J. Collier	return 0;
38997f17497SC.J. Collier}
39097f17497SC.J. Collier
39197f17497SC.J. Collier/**
39297f17497SC.J. Collier * Perform ifreq ioctl() on associated Ethernet device.
39397f17497SC.J. Collier *
39497f17497SC.J. Collier * @param[in] priv
39597f17497SC.J. Collier *   Pointer to private structure.
39697f17497SC.J. Collier * @param req
39797f17497SC.J. Collier *   Request number to pass to ioctl().
39897f17497SC.J. Collier * @param[out] ifr
39997f17497SC.J. Collier *   Interface request structure output buffer.
40097f17497SC.J. Collier *
40197f17497SC.J. Collier * @return
40297f17497SC.J. Collier *   0 on success, -1 on failure and errno is set.
40397f17497SC.J. Collier */
40497f17497SC.J. Collierint
40597f17497SC.J. Collierpriv_ifreq(const struct priv *priv, int req, struct ifreq *ifr)
40697f17497SC.J. Collier{
40797f17497SC.J. Collier	int sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
40897f17497SC.J. Collier	int ret = -1;
40997f17497SC.J. Collier
41097f17497SC.J. Collier	if (sock == -1)
41197f17497SC.J. Collier		return ret;
41297f17497SC.J. Collier	if (priv_get_ifname(priv, &ifr->ifr_name) == 0)
41397f17497SC.J. Collier		ret = ioctl(sock, req, ifr);
41497f17497SC.J. Collier	close(sock);
41597f17497SC.J. Collier	return ret;
41697f17497SC.J. Collier}
41797f17497SC.J. Collier
4188b25d1adSChristian Ehrhardt/**
4198b25d1adSChristian Ehrhardt * Return the number of active VFs for the current device.
4208b25d1adSChristian Ehrhardt *
4218b25d1adSChristian Ehrhardt * @param[in] priv
4228b25d1adSChristian Ehrhardt *   Pointer to private structure.
4238b25d1adSChristian Ehrhardt * @param[out] num_vfs
4248b25d1adSChristian Ehrhardt *   Number of active VFs.
4258b25d1adSChristian Ehrhardt *
4268b25d1adSChristian Ehrhardt * @return
4278b25d1adSChristian Ehrhardt *   0 on success, -1 on failure and errno is set.
4288b25d1adSChristian Ehrhardt */
4298b25d1adSChristian Ehrhardtint
4308b25d1adSChristian Ehrhardtpriv_get_num_vfs(struct priv *priv, uint16_t *num_vfs)
4318b25d1adSChristian Ehrhardt{
4328b25d1adSChristian Ehrhardt	/* The sysfs entry name depends on the operating system. */
4338b25d1adSChristian Ehrhardt	const char **name = (const char *[]){
4348b25d1adSChristian Ehrhardt		"device/sriov_numvfs",
4358b25d1adSChristian Ehrhardt		"device/mlx5_num_vfs",
4368b25d1adSChristian Ehrhardt		NULL,
4378b25d1adSChristian Ehrhardt	};
4388b25d1adSChristian Ehrhardt	int ret;
4398b25d1adSChristian Ehrhardt
4408b25d1adSChristian Ehrhardt	do {
4418b25d1adSChristian Ehrhardt		unsigned long ulong_num_vfs;
4428b25d1adSChristian Ehrhardt
4438b25d1adSChristian Ehrhardt		ret = priv_get_sysfs_ulong(priv, *name, &ulong_num_vfs);
4448b25d1adSChristian Ehrhardt		if (!ret)
4458b25d1adSChristian Ehrhardt			*num_vfs = ulong_num_vfs;
4468b25d1adSChristian Ehrhardt	} while (*(++name) && ret);
4478b25d1adSChristian Ehrhardt	return ret;
4488b25d1adSChristian Ehrhardt}
4498b25d1adSChristian Ehrhardt
45097f17497SC.J. Collier/**
45197f17497SC.J. Collier * Get device MTU.
45297f17497SC.J. Collier *
45397f17497SC.J. Collier * @param priv
45497f17497SC.J. Collier *   Pointer to private structure.
45597f17497SC.J. Collier * @param[out] mtu
45697f17497SC.J. Collier *   MTU value output buffer.
45797f17497SC.J. Collier *
45897f17497SC.J. Collier * @return
45997f17497SC.J. Collier *   0 on success, -1 on failure and errno is set.
46097f17497SC.J. Collier */
46197f17497SC.J. Collierint
46297f17497SC.J. Collierpriv_get_mtu(struct priv *priv, uint16_t *mtu)
46397f17497SC.J. Collier{
46497f17497SC.J. Collier	unsigned long ulong_mtu;
46597f17497SC.J. Collier
46697f17497SC.J. Collier	if (priv_get_sysfs_ulong(priv, "mtu", &ulong_mtu) == -1)
46797f17497SC.J. Collier		return -1;
46897f17497SC.J. Collier	*mtu = ulong_mtu;
46997f17497SC.J. Collier	return 0;
47097f17497SC.J. Collier}
47197f17497SC.J. Collier
47297f17497SC.J. Collier/**
47397f17497SC.J. Collier * Set device MTU.
47497f17497SC.J. Collier *
47597f17497SC.J. Collier * @param priv
47697f17497SC.J. Collier *   Pointer to private structure.
47797f17497SC.J. Collier * @param mtu
47897f17497SC.J. Collier *   MTU value to set.
47997f17497SC.J. Collier *
48097f17497SC.J. Collier * @return
48197f17497SC.J. Collier *   0 on success, -1 on failure and errno is set.
48297f17497SC.J. Collier */
48397f17497SC.J. Collierstatic int
48497f17497SC.J. Collierpriv_set_mtu(struct priv *priv, uint16_t mtu)
48597f17497SC.J. Collier{
4868b25d1adSChristian Ehrhardt	uint16_t new_mtu;
4878b25d1adSChristian Ehrhardt
4888b25d1adSChristian Ehrhardt	if (priv_set_sysfs_ulong(priv, "mtu", mtu) ||
4898b25d1adSChristian Ehrhardt	    priv_get_mtu(priv, &new_mtu))
4908b25d1adSChristian Ehrhardt		return -1;
4918b25d1adSChristian Ehrhardt	if (new_mtu == mtu)
4928b25d1adSChristian Ehrhardt		return 0;
4938b25d1adSChristian Ehrhardt	errno = EINVAL;
4948b25d1adSChristian Ehrhardt	return -1;
49597f17497SC.J. Collier}
49697f17497SC.J. Collier
49797f17497SC.J. Collier/**
49897f17497SC.J. Collier * Set device flags.
49997f17497SC.J. Collier *
50097f17497SC.J. Collier * @param priv
50197f17497SC.J. Collier *   Pointer to private structure.
50297f17497SC.J. Collier * @param keep
50397f17497SC.J. Collier *   Bitmask for flags that must remain untouched.
50497f17497SC.J. Collier * @param flags
50597f17497SC.J. Collier *   Bitmask for flags to modify.
50697f17497SC.J. Collier *
50797f17497SC.J. Collier * @return
50897f17497SC.J. Collier *   0 on success, -1 on failure and errno is set.
50997f17497SC.J. Collier */
51097f17497SC.J. Collierint
51197f17497SC.J. Collierpriv_set_flags(struct priv *priv, unsigned int keep, unsigned int flags)
51297f17497SC.J. Collier{
51397f17497SC.J. Collier	unsigned long tmp;
51497f17497SC.J. Collier
51597f17497SC.J. Collier	if (priv_get_sysfs_ulong(priv, "flags", &tmp) == -1)
51697f17497SC.J. Collier		return -1;
51797f17497SC.J. Collier	tmp &= keep;
518a41e6ff1SRicardo Salveti	tmp |= (flags & (~keep));
51997f17497SC.J. Collier	return priv_set_sysfs_ulong(priv, "flags", tmp);
52097f17497SC.J. Collier}
52197f17497SC.J. Collier
52297f17497SC.J. Collier/**
52397f17497SC.J. Collier * Ethernet device configuration.
52497f17497SC.J. Collier *
52597f17497SC.J. Collier * Prepare the driver for a given number of TX and RX queues.
52697f17497SC.J. Collier *
52797f17497SC.J. Collier * @param dev
52897f17497SC.J. Collier *   Pointer to Ethernet device structure.
52997f17497SC.J. Collier *
53097f17497SC.J. Collier * @return
53197f17497SC.J. Collier *   0 on success, errno value on failure.
53297f17497SC.J. Collier */
53397f17497SC.J. Collierstatic int
53497f17497SC.J. Collierdev_configure(struct rte_eth_dev *dev)
53597f17497SC.J. Collier{
53697f17497SC.J. Collier	struct priv *priv = dev->data->dev_private;
53797f17497SC.J. Collier	unsigned int rxqs_n = dev->data->nb_rx_queues;
53897f17497SC.J. Collier	unsigned int txqs_n = dev->data->nb_tx_queues;
53997f17497SC.J. Collier	unsigned int i;
54097f17497SC.J. Collier	unsigned int j;
54197f17497SC.J. Collier	unsigned int reta_idx_n;
54297f17497SC.J. Collier
54397f17497SC.J. Collier	priv->rss_hf = dev->data->dev_conf.rx_adv_conf.rss_conf.rss_hf;
54497f17497SC.J. Collier	priv->rxqs = (void *)dev->data->rx_queues;
54597f17497SC.J. Collier	priv->txqs = (void *)dev->data->tx_queues;
54697f17497SC.J. Collier	if (txqs_n != priv->txqs_n) {
54797f17497SC.J. Collier		INFO("%p: TX queues number update: %u -> %u",
54897f17497SC.J. Collier		     (void *)dev, priv->txqs_n, txqs_n);
54997f17497SC.J. Collier		priv->txqs_n = txqs_n;
55097f17497SC.J. Collier	}
55197f17497SC.J. Collier	if (rxqs_n > priv->ind_table_max_size) {
55297f17497SC.J. Collier		ERROR("cannot handle this many RX queues (%u)", rxqs_n);
55397f17497SC.J. Collier		return EINVAL;
55497f17497SC.J. Collier	}
55597f17497SC.J. Collier	if (rxqs_n == priv->rxqs_n)
55697f17497SC.J. Collier		return 0;
55797f17497SC.J. Collier	INFO("%p: RX queues number update: %u -> %u",
55897f17497SC.J. Collier	     (void *)dev, priv->rxqs_n, rxqs_n);
55997f17497SC.J. Collier	priv->rxqs_n = rxqs_n;
56097f17497SC.J. Collier	/* If the requested number of RX queues is not a power of two, use the
56197f17497SC.J. Collier	 * maximum indirection table size for better balancing.
56297f17497SC.J. Collier	 * The result is always rounded to the next power of two. */
56397f17497SC.J. Collier	reta_idx_n = (1 << log2above((rxqs_n & (rxqs_n - 1)) ?
56497f17497SC.J. Collier				     priv->ind_table_max_size :
56597f17497SC.J. Collier				     rxqs_n));
56697f17497SC.J. Collier	if (priv_rss_reta_index_resize(priv, reta_idx_n))
56797f17497SC.J. Collier		return ENOMEM;
56897f17497SC.J. Collier	/* When the number of RX queues is not a power of two, the remaining
56997f17497SC.J. Collier	 * table entries are padded with reused WQs and hashes are not spread
57097f17497SC.J. Collier	 * uniformly. */
57197f17497SC.J. Collier	for (i = 0, j = 0; (i != reta_idx_n); ++i) {
57297f17497SC.J. Collier		(*priv->reta_idx)[i] = j;
57397f17497SC.J. Collier		if (++j == rxqs_n)
57497f17497SC.J. Collier			j = 0;
57597f17497SC.J. Collier	}
57697f17497SC.J. Collier	return 0;
57797f17497SC.J. Collier}
57897f17497SC.J. Collier
57997f17497SC.J. Collier/**
58097f17497SC.J. Collier * DPDK callback for Ethernet device configuration.
58197f17497SC.J. Collier *
58297f17497SC.J. Collier * @param dev
58397f17497SC.J. Collier *   Pointer to Ethernet device structure.
58497f17497SC.J. Collier *
58597f17497SC.J. Collier * @return
58697f17497SC.J. Collier *   0 on success, negative errno value on failure.
58797f17497SC.J. Collier */
58897f17497SC.J. Collierint
58997f17497SC.J. Colliermlx5_dev_configure(struct rte_eth_dev *dev)
59097f17497SC.J. Collier{
59197f17497SC.J. Collier	struct priv *priv = dev->data->dev_private;
59297f17497SC.J. Collier	int ret;
59397f17497SC.J. Collier
59497f17497SC.J. Collier	if (mlx5_is_secondary())
59597f17497SC.J. Collier		return -E_RTE_SECONDARY;
59697f17497SC.J. Collier
59797f17497SC.J. Collier	priv_lock(priv);
59897f17497SC.J. Collier	ret = dev_configure(dev);
59997f17497SC.J. Collier	assert(ret >= 0);
60097f17497SC.J. Collier	priv_unlock(priv);
60197f17497SC.J. Collier	return -ret;
60297f17497SC.J. Collier}
60397f17497SC.J. Collier
60497f17497SC.J. Collier/**
60597f17497SC.J. Collier * DPDK callback to get information about the device.
60697f17497SC.J. Collier *
60797f17497SC.J. Collier * @param dev
60897f17497SC.J. Collier *   Pointer to Ethernet device structure.
60997f17497SC.J. Collier * @param[out] info
61097f17497SC.J. Collier *   Info structure output buffer.
61197f17497SC.J. Collier */
61297f17497SC.J. Colliervoid
61397f17497SC.J. Colliermlx5_dev_infos_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *info)
61497f17497SC.J. Collier{
61597f17497SC.J. Collier	struct priv *priv = mlx5_get_priv(dev);
61697f17497SC.J. Collier	unsigned int max;
61797f17497SC.J. Collier	char ifname[IF_NAMESIZE];
61897f17497SC.J. Collier
61997f17497SC.J. Collier	priv_lock(priv);
62097f17497SC.J. Collier	/* FIXME: we should ask the device for these values. */
62197f17497SC.J. Collier	info->min_rx_bufsize = 32;
62297f17497SC.J. Collier	info->max_rx_pktlen = 65536;
62397f17497SC.J. Collier	/*
62497f17497SC.J. Collier	 * Since we need one CQ per QP, the limit is the minimum number
62597f17497SC.J. Collier	 * between the two values.
62697f17497SC.J. Collier	 */
62797f17497SC.J. Collier	max = ((priv->device_attr.max_cq > priv->device_attr.max_qp) ?
62897f17497SC.J. Collier	       priv->device_attr.max_qp : priv->device_attr.max_cq);
62997f17497SC.J. Collier	/* If max >= 65535 then max = 0, max_rx_queues is uint16_t. */
63097f17497SC.J. Collier	if (max >= 65535)
63197f17497SC.J. Collier		max = 65535;
63297f17497SC.J. Collier	info->max_rx_queues = max;
63397f17497SC.J. Collier	info->max_tx_queues = max;
63497f17497SC.J. Collier	info->max_mac_addrs = RTE_DIM(priv->mac);
63597f17497SC.J. Collier	info->rx_offload_capa =
63697f17497SC.J. Collier		(priv->hw_csum ?
63797f17497SC.J. Collier		 (DEV_RX_OFFLOAD_IPV4_CKSUM |
63897f17497SC.J. Collier		  DEV_RX_OFFLOAD_UDP_CKSUM |
63997f17497SC.J. Collier		  DEV_RX_OFFLOAD_TCP_CKSUM) :
64032e04ea0SChristian Ehrhardt		 0) |
64132e04ea0SChristian Ehrhardt		(priv->hw_vlan_strip ? DEV_RX_OFFLOAD_VLAN_STRIP : 0);
6428b25d1adSChristian Ehrhardt	if (!priv->mps)
6438b25d1adSChristian Ehrhardt		info->tx_offload_capa = DEV_TX_OFFLOAD_VLAN_INSERT;
64497f17497SC.J. Collier	if (priv->hw_csum)
64597f17497SC.J. Collier		info->tx_offload_capa |=
64697f17497SC.J. Collier			(DEV_TX_OFFLOAD_IPV4_CKSUM |
64797f17497SC.J. Collier			 DEV_TX_OFFLOAD_UDP_CKSUM |
64897f17497SC.J. Collier			 DEV_TX_OFFLOAD_TCP_CKSUM);
64997f17497SC.J. Collier	if (priv_get_ifname(priv, &ifname) == 0)
65097f17497SC.J. Collier		info->if_index = if_nametoindex(ifname);
65197f17497SC.J. Collier	/* FIXME: RETA update/query API expects the callee to know the size of
65297f17497SC.J. Collier	 * the indirection table, for this PMD the size varies depending on
65397f17497SC.J. Collier	 * the number of RX queues, it becomes impossible to find the correct
65497f17497SC.J. Collier	 * size if it is not fixed.
65597f17497SC.J. Collier	 * The API should be updated to solve this problem. */
65697f17497SC.J. Collier	info->reta_size = priv->ind_table_max_size;
65732e04ea0SChristian Ehrhardt	info->hash_key_size = ((*priv->rss_conf) ?
65832e04ea0SChristian Ehrhardt			       (*priv->rss_conf)[0]->rss_key_len :
65932e04ea0SChristian Ehrhardt			       0);
66032e04ea0SChristian Ehrhardt	info->speed_capa = priv->link_speed_capa;
66139157ec0SLuca Boccassi	info->flow_type_rss_offloads = ~MLX5_RSS_HF_MASK;
66297f17497SC.J. Collier	priv_unlock(priv);
66397f17497SC.J. Collier}
66497f17497SC.J. Collier
66597f17497SC.J. Collierconst uint32_t *
66697f17497SC.J. Colliermlx5_dev_supported_ptypes_get(struct rte_eth_dev *dev)
66797f17497SC.J. Collier{
66897f17497SC.J. Collier	static const uint32_t ptypes[] = {
66997f17497SC.J. Collier		/* refers to rxq_cq_to_pkt_type() */
670aab0c291SChristian Ehrhardt		RTE_PTYPE_L3_IPV4_EXT_UNKNOWN,
671aab0c291SChristian Ehrhardt		RTE_PTYPE_L3_IPV6_EXT_UNKNOWN,
672aab0c291SChristian Ehrhardt		RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN,
673aab0c291SChristian Ehrhardt		RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN,
67497f17497SC.J. Collier		RTE_PTYPE_UNKNOWN
67597f17497SC.J. Collier
67697f17497SC.J. Collier	};
67797f17497SC.J. Collier
6788b25d1adSChristian Ehrhardt	if (dev->rx_pkt_burst == mlx5_rx_burst)
67997f17497SC.J. Collier		return ptypes;
68097f17497SC.J. Collier	return NULL;
68197f17497SC.J. Collier}
68297f17497SC.J. Collier
68397f17497SC.J. Collier/**
68432e04ea0SChristian Ehrhardt * Retrieve physical link information (unlocked version using legacy ioctl).
68597f17497SC.J. Collier *
68697f17497SC.J. Collier * @param dev
68797f17497SC.J. Collier *   Pointer to Ethernet device structure.
68897f17497SC.J. Collier * @param wait_to_complete
68997f17497SC.J. Collier *   Wait for request completion (ignored).
69097f17497SC.J. Collier */
69197f17497SC.J. Collierstatic int
69232e04ea0SChristian Ehrhardtmlx5_link_update_unlocked_gset(struct rte_eth_dev *dev, int wait_to_complete)
69397f17497SC.J. Collier{
69497f17497SC.J. Collier	struct priv *priv = mlx5_get_priv(dev);
69597f17497SC.J. Collier	struct ethtool_cmd edata = {
69632e04ea0SChristian Ehrhardt		.cmd = ETHTOOL_GSET /* Deprecated since Linux v4.5. */
69797f17497SC.J. Collier	};
69897f17497SC.J. Collier	struct ifreq ifr;
69997f17497SC.J. Collier	struct rte_eth_link dev_link;
70097f17497SC.J. Collier	int link_speed = 0;
70197f17497SC.J. Collier
70297f17497SC.J. Collier	(void)wait_to_complete;
70397f17497SC.J. Collier	if (priv_ifreq(priv, SIOCGIFFLAGS, &ifr)) {
70497f17497SC.J. Collier		WARN("ioctl(SIOCGIFFLAGS) failed: %s", strerror(errno));
70597f17497SC.J. Collier		return -1;
70697f17497SC.J. Collier	}
70797f17497SC.J. Collier	memset(&dev_link, 0, sizeof(dev_link));
70897f17497SC.J. Collier	dev_link.link_status = ((ifr.ifr_flags & IFF_UP) &&
70997f17497SC.J. Collier				(ifr.ifr_flags & IFF_RUNNING));
7108b25d1adSChristian Ehrhardt	ifr.ifr_data = (void *)&edata;
71197f17497SC.J. Collier	if (priv_ifreq(priv, SIOCETHTOOL, &ifr)) {
71297f17497SC.J. Collier		WARN("ioctl(SIOCETHTOOL, ETHTOOL_GSET) failed: %s",
71397f17497SC.J. Collier		     strerror(errno));
71497f17497SC.J. Collier		return -1;
71597f17497SC.J. Collier	}
71697f17497SC.J. Collier	link_speed = ethtool_cmd_speed(&edata);
71797f17497SC.J. Collier	if (link_speed == -1)
71897f17497SC.J. Collier		dev_link.link_speed = 0;
71997f17497SC.J. Collier	else
72097f17497SC.J. Collier		dev_link.link_speed = link_speed;
72132e04ea0SChristian Ehrhardt	priv->link_speed_capa = 0;
72232e04ea0SChristian Ehrhardt	if (edata.supported & SUPPORTED_Autoneg)
72332e04ea0SChristian Ehrhardt		priv->link_speed_capa |= ETH_LINK_SPEED_AUTONEG;
72432e04ea0SChristian Ehrhardt	if (edata.supported & (SUPPORTED_1000baseT_Full |
72532e04ea0SChristian Ehrhardt			       SUPPORTED_1000baseKX_Full))
72632e04ea0SChristian Ehrhardt		priv->link_speed_capa |= ETH_LINK_SPEED_1G;
72732e04ea0SChristian Ehrhardt	if (edata.supported & SUPPORTED_10000baseKR_Full)
72832e04ea0SChristian Ehrhardt		priv->link_speed_capa |= ETH_LINK_SPEED_10G;
72932e04ea0SChristian Ehrhardt	if (edata.supported & (SUPPORTED_40000baseKR4_Full |
73032e04ea0SChristian Ehrhardt			       SUPPORTED_40000baseCR4_Full |
73132e04ea0SChristian Ehrhardt			       SUPPORTED_40000baseSR4_Full |
73232e04ea0SChristian Ehrhardt			       SUPPORTED_40000baseLR4_Full))
73332e04ea0SChristian Ehrhardt		priv->link_speed_capa |= ETH_LINK_SPEED_40G;
73497f17497SC.J. Collier	dev_link.link_duplex = ((edata.duplex == DUPLEX_HALF) ?
73697f17497SC.J. Collier	dev_link.link_autoneg = !(dev->data->dev_conf.link_speeds &
73797f17497SC.J. Collier			ETH_LINK_SPEED_FIXED);
73897f17497SC.J. Collier	if (memcmp(&dev_link, &dev->data->dev_link, sizeof(dev_link))) {
73997f17497SC.J. Collier		/* Link status changed. */
74097f17497SC.J. Collier		dev->data->dev_link = dev_link;
74197f17497SC.J. Collier		return 0;
74297f17497SC.J. Collier	}
74397f17497SC.J. Collier	/* Link status is still the same. */
74497f17497SC.J. Collier	return -1;
74597f17497SC.J. Collier}
74697f17497SC.J. Collier
74732e04ea0SChristian Ehrhardt/**
748ce3d555eSChristian Ehrhardt * Retrieve physical link information (unlocked version using new ioctl).
74932e04ea0SChristian Ehrhardt *
75032e04ea0SChristian Ehrhardt * @param dev
75132e04ea0SChristian Ehrhardt *   Pointer to Ethernet device structure.
75232e04ea0SChristian Ehrhardt * @param wait_to_complete
75332e04ea0SChristian Ehrhardt *   Wait for request completion (ignored).
75432e04ea0SChristian Ehrhardt */
75532e04ea0SChristian Ehrhardtstatic int
75632e04ea0SChristian Ehrhardtmlx5_link_update_unlocked_gs(struct rte_eth_dev *dev, int wait_to_complete)
75732e04ea0SChristian Ehrhardt{
75832e04ea0SChristian Ehrhardt	struct priv *priv = mlx5_get_priv(dev);
75947d9763aSLuca Boccassi	struct ethtool_link_settings gcmd = { .cmd = ETHTOOL_GLINKSETTINGS };
76032e04ea0SChristian Ehrhardt	struct ifreq ifr;
76132e04ea0SChristian Ehrhardt	struct rte_eth_link dev_link;
76232e04ea0SChristian Ehrhardt	uint64_t sc;
76332e04ea0SChristian Ehrhardt
76432e04ea0SChristian Ehrhardt	(void)wait_to_complete;
76532e04ea0SChristian Ehrhardt	if (priv_ifreq(priv, SIOCGIFFLAGS, &ifr)) {
76632e04ea0SChristian Ehrhardt		WARN("ioctl(SIOCGIFFLAGS) failed: %s", strerror(errno));
76732e04ea0SChristian Ehrhardt		return -1;
76832e04ea0SChristian Ehrhardt	}
76932e04ea0SChristian Ehrhardt	memset(&dev_link, 0, sizeof(dev_link));
77032e04ea0SChristian Ehrhardt	dev_link.link_status = ((ifr.ifr_flags & IFF_UP) &&
77132e04ea0SChristian Ehrhardt				(ifr.ifr_flags & IFF_RUNNING));
77247d9763aSLuca Boccassi	ifr.ifr_data = (void *)&gcmd;
77332e04ea0SChristian Ehrhardt	if (priv_ifreq(priv, SIOCETHTOOL, &ifr)) {
77432e04ea0SChristian Ehrhardt		DEBUG("ioctl(SIOCETHTOOL, ETHTOOL_GLINKSETTINGS) failed: %s",
77532e04ea0SChristian Ehrhardt		      strerror(errno));
77632e04ea0SChristian Ehrhardt		return -1;
77732e04ea0SChristian Ehrhardt	}
77847d9763aSLuca Boccassi	gcmd.link_mode_masks_nwords = -gcmd.link_mode_masks_nwords;
77947d9763aSLuca Boccassi
78047d9763aSLuca Boccassi	alignas(struct ethtool_link_settings)
78147d9763aSLuca Boccassi	uint8_t data[offsetof(struct ethtool_link_settings, link_mode_masks) +
78247d9763aSLuca Boccassi		     sizeof(uint32_t) * gcmd.link_mode_masks_nwords * 3];
78347d9763aSLuca Boccassi	struct ethtool_link_settings *ecmd = (void *)data;
78447d9763aSLuca Boccassi
78547d9763aSLuca Boccassi	*ecmd = gcmd;
78647d9763aSLuca Boccassi	ifr.ifr_data = (void *)ecmd;
787fdd2322bSLuca Boccassi	if (priv_ifreq(priv, SIOCETHTOOL, &ifr)) {
788fdd2322bSLuca Boccassi		DEBUG("ioctl(SIOCETHTOOL, ETHTOOL_GLINKSETTINGS) failed: %s",
789fdd2322bSLuca Boccassi		      strerror(errno));
790fdd2322bSLuca Boccassi		return -1;
791fdd2322bSLuca Boccassi	}
79247d9763aSLuca Boccassi	dev_link.link_speed = ecmd->speed;
79347d9763aSLuca Boccassi	sc = ecmd->link_mode_masks[0] |
79447d9763aSLuca Boccassi		((uint64_t)ecmd->link_mode_masks[1] << 32);
79532e04ea0SChristian Ehrhardt	priv->link_speed_capa = 0;
79647d9763aSLuca Boccassi	if (sc & MLX5_BITSHIFT(ETHTOOL_LINK_MODE_Autoneg_BIT))
79732e04ea0SChristian Ehrhardt		priv->link_speed_capa |= ETH_LINK_SPEED_AUTONEG;
79847d9763aSLuca Boccassi	if (sc & (MLX5_BITSHIFT(ETHTOOL_LINK_MODE_1000baseT_Full_BIT) |
79947d9763aSLuca Boccassi		  MLX5_BITSHIFT(ETHTOOL_LINK_MODE_1000baseKX_Full_BIT)))
80032e04ea0SChristian Ehrhardt		priv->link_speed_capa |= ETH_LINK_SPEED_1G;
80147d9763aSLuca Boccassi	if (sc & (MLX5_BITSHIFT(ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT) |
80247d9763aSLuca Boccassi		  MLX5_BITSHIFT(ETHTOOL_LINK_MODE_10000baseKR_Full_BIT) |
80347d9763aSLuca Boccassi		  MLX5_BITSHIFT(ETHTOOL_LINK_MODE_10000baseR_FEC_BIT)))
80432e04ea0SChristian Ehrhardt		priv->link_speed_capa |= ETH_LINK_SPEED_10G;
80547d9763aSLuca Boccassi	if (sc & (MLX5_BITSHIFT(ETHTOOL_LINK_MODE_20000baseMLD2_Full_BIT) |
80647d9763aSLuca Boccassi		  MLX5_BITSHIFT(ETHTOOL_LINK_MODE_20000baseKR2_Full_BIT)))
80732e04ea0SChristian Ehrhardt		priv->link_speed_capa |= ETH_LINK_SPEED_20G;
80847d9763aSLuca Boccassi	if (sc & (MLX5_BITSHIFT(ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT) |
80947d9763aSLuca Boccassi		  MLX5_BITSHIFT(ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT) |
81047d9763aSLuca Boccassi		  MLX5_BITSHIFT(ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT) |
81147d9763aSLuca Boccassi		  MLX5_BITSHIFT(ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT)))
81232e04ea0SChristian Ehrhardt		priv->link_speed_capa |= ETH_LINK_SPEED_40G;
81347d9763aSLuca Boccassi	if (sc & (MLX5_BITSHIFT(ETHTOOL_LINK_MODE_56000baseKR4_Full_BIT) |
81447d9763aSLuca Boccassi		  MLX5_BITSHIFT(ETHTOOL_LINK_MODE_56000baseCR4_Full_BIT) |
81547d9763aSLuca Boccassi		  MLX5_BITSHIFT(ETHTOOL_LINK_MODE_56000baseSR4_Full_BIT) |
81647d9763aSLuca Boccassi		  MLX5_BITSHIFT(ETHTOOL_LINK_MODE_56000baseLR4_Full_BIT)))
81732e04ea0SChristian Ehrhardt		priv->link_speed_capa |= ETH_LINK_SPEED_56G;
81847d9763aSLuca Boccassi	if (sc & (MLX5_BITSHIFT(ETHTOOL_LINK_MODE_25000baseCR_Full_BIT) |
81947d9763aSLuca Boccassi		  MLX5_BITSHIFT(ETHTOOL_LINK_MODE_25000baseKR_Full_BIT) |
82047d9763aSLuca Boccassi		  MLX5_BITSHIFT(ETHTOOL_LINK_MODE_25000baseSR_Full_BIT)))
82132e04ea0SChristian Ehrhardt		priv->link_speed_capa |= ETH_LINK_SPEED_25G;
82247d9763aSLuca Boccassi	if (sc & (MLX5_BITSHIFT(ETHTOOL_LINK_MODE_50000baseCR2_Full_BIT) |
82347d9763aSLuca Boccassi		  MLX5_BITSHIFT(ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT)))
82432e04ea0SChristian Ehrhardt		priv->link_speed_capa |= ETH_LINK_SPEED_50G;
82547d9763aSLuca Boccassi	if (sc & (MLX5_BITSHIFT(ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT) |
82647d9763aSLuca Boccassi		  MLX5_BITSHIFT(ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT) |
82747d9763aSLuca Boccassi		  MLX5_BITSHIFT(ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT) |
82847d9763aSLuca Boccassi		  MLX5_BITSHIFT(ETHTOOL_LINK_MODE_100000baseLR4_ER4_Full_BIT)))
82932e04ea0SChristian Ehrhardt		priv->link_speed_capa |= ETH_LINK_SPEED_100G;
83047d9763aSLuca Boccassi	dev_link.link_duplex = ((ecmd->duplex == DUPLEX_HALF) ?
83132e04ea0SChristian Ehrhardt				ETH_LINK_HALF_DUPLEX : ETH_LINK_FULL_DUPLEX);
83232e04ea0SChristian Ehrhardt	dev_link.link_autoneg = !(dev->data->dev_conf.link_speeds &
83332e04ea0SChristian Ehrhardt				  ETH_LINK_SPEED_FIXED);
83432e04ea0SChristian Ehrhardt	if (memcmp(&dev_link, &dev->data->dev_link, sizeof(dev_link))) {
83532e04ea0SChristian Ehrhardt		/* Link status changed. */
83632e04ea0SChristian Ehrhardt		dev->data->dev_link = dev_link;
83732e04ea0SChristian Ehrhardt		return 0;
83832e04ea0SChristian Ehrhardt	}
83932e04ea0SChristian Ehrhardt	/* Link status is still the same. */
84032e04ea0SChristian Ehrhardt	return -1;
84132e04ea0SChristian Ehrhardt}
84232e04ea0SChristian Ehrhardt
84332e04ea0SChristian Ehrhardt/**
84432e04ea0SChristian Ehrhardt * DPDK callback to retrieve physical link information (unlocked version).
84532e04ea0SChristian Ehrhardt *
84632e04ea0SChristian Ehrhardt * @param dev
84732e04ea0SChristian Ehrhardt *   Pointer to Ethernet device structure.
84832e04ea0SChristian Ehrhardt * @param wait_to_complete
84932e04ea0SChristian Ehrhardt *   Wait for request completion (ignored).
85032e04ea0SChristian Ehrhardt */
85132e04ea0SChristian Ehrhardtint
85232e04ea0SChristian Ehrhardtmlx5_link_update_unlocked(struct rte_eth_dev *dev, int wait_to_complete)
85332e04ea0SChristian Ehrhardt{
854ce3d555eSChristian Ehrhardt	struct utsname utsname;
855ce3d555eSChristian Ehrhardt	int ver[3];
856ce3d555eSChristian Ehrhardt
857ce3d555eSChristian Ehrhardt	if (uname(&utsname) == -1 ||
858ce3d555eSChristian Ehrhardt	    sscanf(utsname.release, "%d.%d.%d",
859ce3d555eSChristian Ehrhardt		   &ver[0], &ver[1], &ver[2]) != 3 ||
860ce3d555eSChristian Ehrhardt	    KERNEL_VERSION(ver[0], ver[1], ver[2]) < KERNEL_VERSION(4, 9, 0))
861ce3d555eSChristian Ehrhardt		return mlx5_link_update_unlocked_gset(dev, wait_to_complete);
862ce3d555eSChristian Ehrhardt	return mlx5_link_update_unlocked_gs(dev, wait_to_complete);
86332e04ea0SChristian Ehrhardt}
86432e04ea0SChristian Ehrhardt
86597f17497SC.J. Collier/**
86697f17497SC.J. Collier * DPDK callback to retrieve physical link information.
86797f17497SC.J. Collier *
86897f17497SC.J. Collier * @param dev
86997f17497SC.J. Collier *   Pointer to Ethernet device structure.
87097f17497SC.J. Collier * @param wait_to_complete
87197f17497SC.J. Collier *   Wait for request completion (ignored).
87297f17497SC.J. Collier */
87397f17497SC.J. Collierint
87497f17497SC.J. Colliermlx5_link_update(struct rte_eth_dev *dev, int wait_to_complete)
87597f17497SC.J. Collier{
87697f17497SC.J. Collier	struct priv *priv = mlx5_get_priv(dev);
87797f17497SC.J. Collier	int ret;
87897f17497SC.J. Collier
87997f17497SC.J. Collier	priv_lock(priv);
88097f17497SC.J. Collier	ret = mlx5_link_update_unlocked(dev, wait_to_complete);
88197f17497SC.J. Collier	priv_unlock(priv);
88297f17497SC.J. Collier	return ret;
88397f17497SC.J. Collier}
88497f17497SC.J. Collier
88597f17497SC.J. Collier/**
88697f17497SC.J. Collier * DPDK callback to change the MTU.
88797f17497SC.J. Collier *
88897f17497SC.J. Collier * Setting the MTU affects hardware MRU (packets larger than the MTU cannot be
88997f17497SC.J. Collier * received). Use this as a hint to enable/disable scattered packets support
89097f17497SC.J. Collier * and improve performance when not needed.
89197f17497SC.J. Collier * Since failure is not an option, reconfiguring queues on the fly is not
89297f17497SC.J. Collier * recommended.
89397f17497SC.J. Collier *
89497f17497SC.J. Collier * @param dev
89597f17497SC.J. Collier *   Pointer to Ethernet device structure.
89697f17497SC.J. Collier * @param in_mtu
89797f17497SC.J. Collier *   New MTU.
89897f17497SC.J. Collier *
89997f17497SC.J. Collier * @return
90097f17497SC.J. Collier *   0 on success, negative errno value on failure.
90197f17497SC.J. Collier */
90297f17497SC.J. Collierint
90397f17497SC.J. Colliermlx5_dev_set_mtu(struct rte_eth_dev *dev, uint16_t mtu)
90497f17497SC.J. Collier{
90597f17497SC.J. Collier	struct priv *priv = dev->data->dev_private;
90697f17497SC.J. Collier	int ret = 0;
90797f17497SC.J. Collier	unsigned int i;
90897f17497SC.J. Collier	uint16_t (*rx_func)(void *, struct rte_mbuf **, uint16_t) =
90997f17497SC.J. Collier		mlx5_rx_burst;
9108b25d1adSChristian Ehrhardt	unsigned int max_frame_len;
9118b25d1adSChristian Ehrhardt	int rehash;
9128b25d1adSChristian Ehrhardt	int restart = priv->started;
91397f17497SC.J. Collier
91497f17497SC.J. Collier	if (mlx5_is_secondary())
91597f17497SC.J. Collier		return -E_RTE_SECONDARY;
91697f17497SC.J. Collier
91797f17497SC.J. Collier	priv_lock(priv);
91897f17497SC.J. Collier	/* Set kernel interface MTU first. */
91997f17497SC.J. Collier	if (priv_set_mtu(priv, mtu)) {
92097f17497SC.J. Collier		ret = errno;
92197f17497SC.J. Collier		WARN("cannot set port %u MTU to %u: %s", priv->port, mtu,
92297f17497SC.J. Collier		     strerror(ret));
92397f17497SC.J. Collier		goto out;
92497f17497SC.J. Collier	} else
92597f17497SC.J. Collier		DEBUG("adapter port %u MTU set to %u", priv->port, mtu);
92697f17497SC.J. Collier	/* Temporarily replace RX handler with a fake one, assuming it has not
92797f17497SC.J. Collier	 * been copied elsewhere. */
92897f17497SC.J. Collier	dev->rx_pkt_burst = removed_rx_burst;
92997f17497SC.J. Collier	/* Make sure everyone has left mlx5_rx_burst() and uses
93097f17497SC.J. Collier	 * removed_rx_burst() instead. */
93197f17497SC.J. Collier	rte_wmb();
93297f17497SC.J. Collier	usleep(1000);
9338b25d1adSChristian Ehrhardt	/* MTU does not include header and CRC. */
9348b25d1adSChristian Ehrhardt	max_frame_len = ETHER_HDR_LEN + mtu + ETHER_CRC_LEN;
9358b25d1adSChristian Ehrhardt	/* Check if at least one queue is going to need a SGE update. */
9368b25d1adSChristian Ehrhardt	for (i = 0; i != priv->rxqs_n; ++i) {
9378b25d1adSChristian Ehrhardt		struct rxq *rxq = (*priv->rxqs)[i];
9388b25d1adSChristian Ehrhardt		unsigned int mb_len;
9398b25d1adSChristian Ehrhardt		unsigned int size = RTE_PKTMBUF_HEADROOM + max_frame_len;
9408b25d1adSChristian Ehrhardt		unsigned int sges_n;
9418b25d1adSChristian Ehrhardt
9428b25d1adSChristian Ehrhardt		if (rxq == NULL)
9438b25d1adSChristian Ehrhardt			continue;
9448b25d1adSChristian Ehrhardt		mb_len = rte_pktmbuf_data_room_size(rxq->mp);
9458b25d1adSChristian Ehrhardt		assert(mb_len >= RTE_PKTMBUF_HEADROOM);
9468b25d1adSChristian Ehrhardt		/*
9478b25d1adSChristian Ehrhardt		 * Determine the number of SGEs needed for a full packet
9488b25d1adSChristian Ehrhardt		 * and round it to the next power of two.
9498b25d1adSChristian Ehrhardt		 */
9508b25d1adSChristian Ehrhardt		sges_n = log2above((size / mb_len) + !!(size % mb_len));
9518b25d1adSChristian Ehrhardt		if (sges_n != rxq->sges_n)
9528b25d1adSChristian Ehrhardt			break;
9538b25d1adSChristian Ehrhardt	}
9548b25d1adSChristian Ehrhardt	/*
9558b25d1adSChristian Ehrhardt	 * If all queues have the right number of SGEs, a simple rehash
9568b25d1adSChristian Ehrhardt	 * of their buffers is enough, otherwise SGE information can only
9578b25d1adSChristian Ehrhardt	 * be updated in a queue by recreating it. All resources that depend
9588b25d1adSChristian Ehrhardt	 * on queues (flows, indirection tables) must be recreated as well in
9598b25d1adSChristian Ehrhardt	 * that case.
9608b25d1adSChristian Ehrhardt	 */
9618b25d1adSChristian Ehrhardt	rehash = (i == priv->rxqs_n);
9628b25d1adSChristian Ehrhardt	if (!rehash) {
9638b25d1adSChristian Ehrhardt		/* Clean up everything as with mlx5_dev_stop(). */
9648b25d1adSChristian Ehrhardt		priv_special_flow_disable_all(priv);
9658b25d1adSChristian Ehrhardt		priv_mac_addrs_disable(priv);
9668b25d1adSChristian Ehrhardt		priv_destroy_hash_rxqs(priv);
9678b25d1adSChristian Ehrhardt		priv_fdir_disable(priv);
9688b25d1adSChristian Ehrhardt		priv_dev_interrupt_handler_uninstall(priv, dev);
9698b25d1adSChristian Ehrhardt	}
9708b25d1adSChristian Ehrhardtrecover:
97197f17497SC.J. Collier	/* Reconfigure each RX queue. */
97297f17497SC.J. Collier	for (i = 0; (i != priv->rxqs_n); ++i) {
97397f17497SC.J. Collier		struct rxq *rxq = (*priv->rxqs)[i];
9748b25d1adSChristian Ehrhardt		struct rxq_ctrl *rxq_ctrl =
9758b25d1adSChristian Ehrhardt			container_of(rxq, struct rxq_ctrl, rxq);
97697f17497SC.J. Collier		int sp;
9778b25d1adSChristian Ehrhardt		unsigned int mb_len;
9788b25d1adSChristian Ehrhardt		unsigned int tmp;
97997f17497SC.J. Collier
98097f17497SC.J. Collier		if (rxq == NULL)
98197f17497SC.J. Collier			continue;
9828b25d1adSChristian Ehrhardt		mb_len = rte_pktmbuf_data_room_size(rxq->mp);
9838b25d1adSChristian Ehrhardt		assert(mb_len >= RTE_PKTMBUF_HEADROOM);
9848b25d1adSChristian Ehrhardt		/* Toggle scattered support (sp) if necessary. */
9858b25d1adSChristian Ehrhardt		sp = (max_frame_len > (mb_len - RTE_PKTMBUF_HEADROOM));
98697f17497SC.J. Collier		/* Provide new values to rxq_setup(). */
98797f17497SC.J. Collier		dev->data->dev_conf.rxmode.jumbo_frame = sp;
98897f17497SC.J. Collier		dev->data->dev_conf.rxmode.max_rx_pkt_len = max_frame_len;
98939157ec0SLuca Boccassi		if (!rehash)
9906b3e017eSChristian Ehrhardt			ret = rxq_ctrl_setup(dev, rxq_ctrl, 1 << rxq->elts_n,
9918b25d1adSChristian Ehrhardt					     rxq_ctrl->socket, NULL, rxq->mp);
9928b25d1adSChristian Ehrhardt		if (!ret)
9938b25d1adSChristian Ehrhardt			continue;
9948b25d1adSChristian Ehrhardt		/* Attempt to roll back in case of error. */
9958b25d1adSChristian Ehrhardt		tmp = (mb_len << rxq->sges_n) - RTE_PKTMBUF_HEADROOM;
9968b25d1adSChristian Ehrhardt		if (max_frame_len != tmp) {
9978b25d1adSChristian Ehrhardt			max_frame_len = tmp;
9988b25d1adSChristian Ehrhardt			goto recover;
99997f17497SC.J. Collier		}
10008b25d1adSChristian Ehrhardt		/* Double fault, disable RX. */
10018b25d1adSChristian Ehrhardt		break;
10028b25d1adSChristian Ehrhardt	}
10038b25d1adSChristian Ehrhardt	/*
10048b25d1adSChristian Ehrhardt	 * Use a safe RX burst function in case of error, otherwise mimic
10058b25d1adSChristian Ehrhardt	 * mlx5_dev_start().
10068b25d1adSChristian Ehrhardt	 */
10078b25d1adSChristian Ehrhardt	if (ret) {
10088b25d1adSChristian Ehrhardt		ERROR("unable to reconfigure RX queues, RX disabled");
10098b25d1adSChristian Ehrhardt		rx_func = removed_rx_burst;
10108b25d1adSChristian Ehrhardt	} else if (restart &&
10118b25d1adSChristian Ehrhardt		 !rehash &&
10128b25d1adSChristian Ehrhardt		 !priv_create_hash_rxqs(priv) &&
10138b25d1adSChristian Ehrhardt		 !priv_rehash_flows(priv)) {
10148b25d1adSChristian Ehrhardt		if (dev->data->dev_conf.fdir_conf.mode == RTE_FDIR_MODE_NONE)
10158b25d1adSChristian Ehrhardt			priv_fdir_enable(priv);
10168b25d1adSChristian Ehrhardt		priv_dev_interrupt_handler_install(priv, dev);
101797f17497SC.J. Collier	}
10188b25d1adSChristian Ehrhardt	priv->mtu = mtu;
101997f17497SC.J. Collier	/* Burst functions can now be called again. */
102097f17497SC.J. Collier	rte_wmb();
102197f17497SC.J. Collier	dev->rx_pkt_burst = rx_func;
102297f17497SC.J. Collierout:
102397f17497SC.J. Collier	priv_unlock(priv);
102497f17497SC.J. Collier	assert(ret >= 0);
102597f17497SC.J. Collier	return -ret;
102697f17497SC.J. Collier}
102797f17497SC.J. Collier
102897f17497SC.J. Collier/**
102997f17497SC.J. Collier * DPDK callback to get flow control status.
103097f17497SC.J. Collier *
103197f17497SC.J. Collier * @param dev
103297f17497SC.J. Collier *   Pointer to Ethernet device structure.
103397f17497SC.J. Collier * @param[out] fc_conf
103497f17497SC.J. Collier *   Flow control output buffer.
103597f17497SC.J. Collier *
103697f17497SC.J. Collier * @return
103797f17497SC.J. Collier *   0 on success, negative errno value on failure.
103897f17497SC.J. Collier */
103997f17497SC.J. Collierint
104097f17497SC.J. Colliermlx5_dev_get_flow_ctrl(struct rte_eth_dev *dev, struct rte_eth_fc_conf *fc_conf)
104197f17497SC.J. Collier{
104297f17497SC.J. Collier	struct priv *priv = dev->data->dev_private;
104397f17497SC.J. Collier	struct ifreq ifr;
104497f17497SC.J. Collier	struct ethtool_pauseparam ethpause = {
104597f17497SC.J. Collier		.cmd = ETHTOOL_GPAUSEPARAM
104697f17497SC.J. Collier	};
104797f17497SC.J. Collier	int ret;
104897f17497SC.J. Collier
104997f17497SC.J. Collier	if (mlx5_is_secondary())