xref: /dpdk/drivers/net/mlx5/mlx5_ethdev.c (revision 634efbc2c8c05213696c36e103becc48cdbe534c)
1771fa900SAdrien Mazarguil /*-
2771fa900SAdrien Mazarguil  *   BSD LICENSE
3771fa900SAdrien Mazarguil  *
4771fa900SAdrien Mazarguil  *   Copyright 2015 6WIND S.A.
5771fa900SAdrien Mazarguil  *   Copyright 2015 Mellanox.
6771fa900SAdrien Mazarguil  *
7771fa900SAdrien Mazarguil  *   Redistribution and use in source and binary forms, with or without
8771fa900SAdrien Mazarguil  *   modification, are permitted provided that the following conditions
9771fa900SAdrien Mazarguil  *   are met:
10771fa900SAdrien Mazarguil  *
11771fa900SAdrien Mazarguil  *     * Redistributions of source code must retain the above copyright
12771fa900SAdrien Mazarguil  *       notice, this list of conditions and the following disclaimer.
13771fa900SAdrien Mazarguil  *     * Redistributions in binary form must reproduce the above copyright
14771fa900SAdrien Mazarguil  *       notice, this list of conditions and the following disclaimer in
15771fa900SAdrien Mazarguil  *       the documentation and/or other materials provided with the
16771fa900SAdrien Mazarguil  *       distribution.
17771fa900SAdrien Mazarguil  *     * Neither the name of 6WIND S.A. nor the names of its
18771fa900SAdrien Mazarguil  *       contributors may be used to endorse or promote products derived
19771fa900SAdrien Mazarguil  *       from this software without specific prior written permission.
20771fa900SAdrien Mazarguil  *
21771fa900SAdrien Mazarguil  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22771fa900SAdrien Mazarguil  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23771fa900SAdrien Mazarguil  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24771fa900SAdrien Mazarguil  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25771fa900SAdrien Mazarguil  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26771fa900SAdrien Mazarguil  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27771fa900SAdrien Mazarguil  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28771fa900SAdrien Mazarguil  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29771fa900SAdrien Mazarguil  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30771fa900SAdrien Mazarguil  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31771fa900SAdrien Mazarguil  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32771fa900SAdrien Mazarguil  */
33771fa900SAdrien Mazarguil 
34771fa900SAdrien Mazarguil #include <stddef.h>
35e60fbd5bSAdrien Mazarguil #include <assert.h>
36771fa900SAdrien Mazarguil #include <unistd.h>
37771fa900SAdrien Mazarguil #include <stdint.h>
38771fa900SAdrien Mazarguil #include <stdio.h>
39771fa900SAdrien Mazarguil #include <string.h>
40771fa900SAdrien Mazarguil #include <stdlib.h>
41771fa900SAdrien Mazarguil #include <errno.h>
42771fa900SAdrien Mazarguil #include <dirent.h>
43771fa900SAdrien Mazarguil #include <net/if.h>
44771fa900SAdrien Mazarguil #include <sys/ioctl.h>
45771fa900SAdrien Mazarguil #include <sys/socket.h>
46771fa900SAdrien Mazarguil #include <netinet/in.h>
47771fa900SAdrien Mazarguil #include <linux/if.h>
48cb8faed7SAdrien Mazarguil #include <linux/ethtool.h>
49cb8faed7SAdrien Mazarguil #include <linux/sockios.h>
50198a3c33SNelio Laranjeiro #include <fcntl.h>
51771fa900SAdrien Mazarguil 
52771fa900SAdrien Mazarguil /* DPDK headers don't like -pedantic. */
53771fa900SAdrien Mazarguil #ifdef PEDANTIC
54771fa900SAdrien Mazarguil #pragma GCC diagnostic ignored "-pedantic"
55771fa900SAdrien Mazarguil #endif
56771fa900SAdrien Mazarguil #include <rte_atomic.h>
57771fa900SAdrien Mazarguil #include <rte_ethdev.h>
58771fa900SAdrien Mazarguil #include <rte_mbuf.h>
59771fa900SAdrien Mazarguil #include <rte_common.h>
60198a3c33SNelio Laranjeiro #include <rte_interrupts.h>
61198a3c33SNelio Laranjeiro #include <rte_alarm.h>
62771fa900SAdrien Mazarguil #ifdef PEDANTIC
63771fa900SAdrien Mazarguil #pragma GCC diagnostic error "-pedantic"
64771fa900SAdrien Mazarguil #endif
65771fa900SAdrien Mazarguil 
66771fa900SAdrien Mazarguil #include "mlx5.h"
67e60fbd5bSAdrien Mazarguil #include "mlx5_rxtx.h"
68771fa900SAdrien Mazarguil #include "mlx5_utils.h"
69771fa900SAdrien Mazarguil 
70771fa900SAdrien Mazarguil /**
71771fa900SAdrien Mazarguil  * Get interface name from private structure.
72771fa900SAdrien Mazarguil  *
73771fa900SAdrien Mazarguil  * @param[in] priv
74771fa900SAdrien Mazarguil  *   Pointer to private structure.
75771fa900SAdrien Mazarguil  * @param[out] ifname
76771fa900SAdrien Mazarguil  *   Interface name output buffer.
77771fa900SAdrien Mazarguil  *
78771fa900SAdrien Mazarguil  * @return
79771fa900SAdrien Mazarguil  *   0 on success, -1 on failure and errno is set.
80771fa900SAdrien Mazarguil  */
81771fa900SAdrien Mazarguil int
82771fa900SAdrien Mazarguil priv_get_ifname(const struct priv *priv, char (*ifname)[IF_NAMESIZE])
83771fa900SAdrien Mazarguil {
84771fa900SAdrien Mazarguil 	DIR *dir;
85771fa900SAdrien Mazarguil 	struct dirent *dent;
86771fa900SAdrien Mazarguil 	unsigned int dev_type = 0;
87771fa900SAdrien Mazarguil 	unsigned int dev_port_prev = ~0u;
88771fa900SAdrien Mazarguil 	char match[IF_NAMESIZE] = "";
89771fa900SAdrien Mazarguil 
90771fa900SAdrien Mazarguil 	{
91771fa900SAdrien Mazarguil 		MKSTR(path, "%s/device/net", priv->ctx->device->ibdev_path);
92771fa900SAdrien Mazarguil 
93771fa900SAdrien Mazarguil 		dir = opendir(path);
94771fa900SAdrien Mazarguil 		if (dir == NULL)
95771fa900SAdrien Mazarguil 			return -1;
96771fa900SAdrien Mazarguil 	}
97771fa900SAdrien Mazarguil 	while ((dent = readdir(dir)) != NULL) {
98771fa900SAdrien Mazarguil 		char *name = dent->d_name;
99771fa900SAdrien Mazarguil 		FILE *file;
100771fa900SAdrien Mazarguil 		unsigned int dev_port;
101771fa900SAdrien Mazarguil 		int r;
102771fa900SAdrien Mazarguil 
103771fa900SAdrien Mazarguil 		if ((name[0] == '.') &&
104771fa900SAdrien Mazarguil 		    ((name[1] == '\0') ||
105771fa900SAdrien Mazarguil 		     ((name[1] == '.') && (name[2] == '\0'))))
106771fa900SAdrien Mazarguil 			continue;
107771fa900SAdrien Mazarguil 
108771fa900SAdrien Mazarguil 		MKSTR(path, "%s/device/net/%s/%s",
109771fa900SAdrien Mazarguil 		      priv->ctx->device->ibdev_path, name,
110771fa900SAdrien Mazarguil 		      (dev_type ? "dev_id" : "dev_port"));
111771fa900SAdrien Mazarguil 
112771fa900SAdrien Mazarguil 		file = fopen(path, "rb");
113771fa900SAdrien Mazarguil 		if (file == NULL) {
114771fa900SAdrien Mazarguil 			if (errno != ENOENT)
115771fa900SAdrien Mazarguil 				continue;
116771fa900SAdrien Mazarguil 			/*
117771fa900SAdrien Mazarguil 			 * Switch to dev_id when dev_port does not exist as
118771fa900SAdrien Mazarguil 			 * is the case with Linux kernel versions < 3.15.
119771fa900SAdrien Mazarguil 			 */
120771fa900SAdrien Mazarguil try_dev_id:
121771fa900SAdrien Mazarguil 			match[0] = '\0';
122771fa900SAdrien Mazarguil 			if (dev_type)
123771fa900SAdrien Mazarguil 				break;
124771fa900SAdrien Mazarguil 			dev_type = 1;
125771fa900SAdrien Mazarguil 			dev_port_prev = ~0u;
126771fa900SAdrien Mazarguil 			rewinddir(dir);
127771fa900SAdrien Mazarguil 			continue;
128771fa900SAdrien Mazarguil 		}
129771fa900SAdrien Mazarguil 		r = fscanf(file, (dev_type ? "%x" : "%u"), &dev_port);
130771fa900SAdrien Mazarguil 		fclose(file);
131771fa900SAdrien Mazarguil 		if (r != 1)
132771fa900SAdrien Mazarguil 			continue;
133771fa900SAdrien Mazarguil 		/*
134771fa900SAdrien Mazarguil 		 * Switch to dev_id when dev_port returns the same value for
135771fa900SAdrien Mazarguil 		 * all ports. May happen when using a MOFED release older than
136771fa900SAdrien Mazarguil 		 * 3.0 with a Linux kernel >= 3.15.
137771fa900SAdrien Mazarguil 		 */
138771fa900SAdrien Mazarguil 		if (dev_port == dev_port_prev)
139771fa900SAdrien Mazarguil 			goto try_dev_id;
140771fa900SAdrien Mazarguil 		dev_port_prev = dev_port;
141771fa900SAdrien Mazarguil 		if (dev_port == (priv->port - 1u))
142771fa900SAdrien Mazarguil 			snprintf(match, sizeof(match), "%s", name);
143771fa900SAdrien Mazarguil 	}
144771fa900SAdrien Mazarguil 	closedir(dir);
145771fa900SAdrien Mazarguil 	if (match[0] == '\0')
146771fa900SAdrien Mazarguil 		return -1;
147771fa900SAdrien Mazarguil 	strncpy(*ifname, match, sizeof(*ifname));
148771fa900SAdrien Mazarguil 	return 0;
149771fa900SAdrien Mazarguil }
150771fa900SAdrien Mazarguil 
151771fa900SAdrien Mazarguil /**
152771fa900SAdrien Mazarguil  * Read from sysfs entry.
153771fa900SAdrien Mazarguil  *
154771fa900SAdrien Mazarguil  * @param[in] priv
155771fa900SAdrien Mazarguil  *   Pointer to private structure.
156771fa900SAdrien Mazarguil  * @param[in] entry
157771fa900SAdrien Mazarguil  *   Entry name relative to sysfs path.
158771fa900SAdrien Mazarguil  * @param[out] buf
159771fa900SAdrien Mazarguil  *   Data output buffer.
160771fa900SAdrien Mazarguil  * @param size
161771fa900SAdrien Mazarguil  *   Buffer size.
162771fa900SAdrien Mazarguil  *
163771fa900SAdrien Mazarguil  * @return
164771fa900SAdrien Mazarguil  *   0 on success, -1 on failure and errno is set.
165771fa900SAdrien Mazarguil  */
166771fa900SAdrien Mazarguil static int
167771fa900SAdrien Mazarguil priv_sysfs_read(const struct priv *priv, const char *entry,
168771fa900SAdrien Mazarguil 		char *buf, size_t size)
169771fa900SAdrien Mazarguil {
170771fa900SAdrien Mazarguil 	char ifname[IF_NAMESIZE];
171771fa900SAdrien Mazarguil 	FILE *file;
172771fa900SAdrien Mazarguil 	int ret;
173771fa900SAdrien Mazarguil 	int err;
174771fa900SAdrien Mazarguil 
175771fa900SAdrien Mazarguil 	if (priv_get_ifname(priv, &ifname))
176771fa900SAdrien Mazarguil 		return -1;
177771fa900SAdrien Mazarguil 
178771fa900SAdrien Mazarguil 	MKSTR(path, "%s/device/net/%s/%s", priv->ctx->device->ibdev_path,
179771fa900SAdrien Mazarguil 	      ifname, entry);
180771fa900SAdrien Mazarguil 
181771fa900SAdrien Mazarguil 	file = fopen(path, "rb");
182771fa900SAdrien Mazarguil 	if (file == NULL)
183771fa900SAdrien Mazarguil 		return -1;
184771fa900SAdrien Mazarguil 	ret = fread(buf, 1, size, file);
185771fa900SAdrien Mazarguil 	err = errno;
186771fa900SAdrien Mazarguil 	if (((size_t)ret < size) && (ferror(file)))
187771fa900SAdrien Mazarguil 		ret = -1;
188771fa900SAdrien Mazarguil 	else
189771fa900SAdrien Mazarguil 		ret = size;
190771fa900SAdrien Mazarguil 	fclose(file);
191771fa900SAdrien Mazarguil 	errno = err;
192771fa900SAdrien Mazarguil 	return ret;
193771fa900SAdrien Mazarguil }
194771fa900SAdrien Mazarguil 
195771fa900SAdrien Mazarguil /**
196771fa900SAdrien Mazarguil  * Write to sysfs entry.
197771fa900SAdrien Mazarguil  *
198771fa900SAdrien Mazarguil  * @param[in] priv
199771fa900SAdrien Mazarguil  *   Pointer to private structure.
200771fa900SAdrien Mazarguil  * @param[in] entry
201771fa900SAdrien Mazarguil  *   Entry name relative to sysfs path.
202771fa900SAdrien Mazarguil  * @param[in] buf
203771fa900SAdrien Mazarguil  *   Data buffer.
204771fa900SAdrien Mazarguil  * @param size
205771fa900SAdrien Mazarguil  *   Buffer size.
206771fa900SAdrien Mazarguil  *
207771fa900SAdrien Mazarguil  * @return
208771fa900SAdrien Mazarguil  *   0 on success, -1 on failure and errno is set.
209771fa900SAdrien Mazarguil  */
210771fa900SAdrien Mazarguil static int
211771fa900SAdrien Mazarguil priv_sysfs_write(const struct priv *priv, const char *entry,
212771fa900SAdrien Mazarguil 		 char *buf, size_t size)
213771fa900SAdrien Mazarguil {
214771fa900SAdrien Mazarguil 	char ifname[IF_NAMESIZE];
215771fa900SAdrien Mazarguil 	FILE *file;
216771fa900SAdrien Mazarguil 	int ret;
217771fa900SAdrien Mazarguil 	int err;
218771fa900SAdrien Mazarguil 
219771fa900SAdrien Mazarguil 	if (priv_get_ifname(priv, &ifname))
220771fa900SAdrien Mazarguil 		return -1;
221771fa900SAdrien Mazarguil 
222771fa900SAdrien Mazarguil 	MKSTR(path, "%s/device/net/%s/%s", priv->ctx->device->ibdev_path,
223771fa900SAdrien Mazarguil 	      ifname, entry);
224771fa900SAdrien Mazarguil 
225771fa900SAdrien Mazarguil 	file = fopen(path, "wb");
226771fa900SAdrien Mazarguil 	if (file == NULL)
227771fa900SAdrien Mazarguil 		return -1;
228771fa900SAdrien Mazarguil 	ret = fwrite(buf, 1, size, file);
229771fa900SAdrien Mazarguil 	err = errno;
230771fa900SAdrien Mazarguil 	if (((size_t)ret < size) || (ferror(file)))
231771fa900SAdrien Mazarguil 		ret = -1;
232771fa900SAdrien Mazarguil 	else
233771fa900SAdrien Mazarguil 		ret = size;
234771fa900SAdrien Mazarguil 	fclose(file);
235771fa900SAdrien Mazarguil 	errno = err;
236771fa900SAdrien Mazarguil 	return ret;
237771fa900SAdrien Mazarguil }
238771fa900SAdrien Mazarguil 
239771fa900SAdrien Mazarguil /**
240771fa900SAdrien Mazarguil  * Get unsigned long sysfs property.
241771fa900SAdrien Mazarguil  *
242771fa900SAdrien Mazarguil  * @param priv
243771fa900SAdrien Mazarguil  *   Pointer to private structure.
244771fa900SAdrien Mazarguil  * @param[in] name
245771fa900SAdrien Mazarguil  *   Entry name relative to sysfs path.
246771fa900SAdrien Mazarguil  * @param[out] value
247771fa900SAdrien Mazarguil  *   Value output buffer.
248771fa900SAdrien Mazarguil  *
249771fa900SAdrien Mazarguil  * @return
250771fa900SAdrien Mazarguil  *   0 on success, -1 on failure and errno is set.
251771fa900SAdrien Mazarguil  */
252771fa900SAdrien Mazarguil static int
253771fa900SAdrien Mazarguil priv_get_sysfs_ulong(struct priv *priv, const char *name, unsigned long *value)
254771fa900SAdrien Mazarguil {
255771fa900SAdrien Mazarguil 	int ret;
256771fa900SAdrien Mazarguil 	unsigned long value_ret;
257771fa900SAdrien Mazarguil 	char value_str[32];
258771fa900SAdrien Mazarguil 
259771fa900SAdrien Mazarguil 	ret = priv_sysfs_read(priv, name, value_str, (sizeof(value_str) - 1));
260771fa900SAdrien Mazarguil 	if (ret == -1) {
261771fa900SAdrien Mazarguil 		DEBUG("cannot read %s value from sysfs: %s",
262771fa900SAdrien Mazarguil 		      name, strerror(errno));
263771fa900SAdrien Mazarguil 		return -1;
264771fa900SAdrien Mazarguil 	}
265771fa900SAdrien Mazarguil 	value_str[ret] = '\0';
266771fa900SAdrien Mazarguil 	errno = 0;
267771fa900SAdrien Mazarguil 	value_ret = strtoul(value_str, NULL, 0);
268771fa900SAdrien Mazarguil 	if (errno) {
269771fa900SAdrien Mazarguil 		DEBUG("invalid %s value `%s': %s", name, value_str,
270771fa900SAdrien Mazarguil 		      strerror(errno));
271771fa900SAdrien Mazarguil 		return -1;
272771fa900SAdrien Mazarguil 	}
273771fa900SAdrien Mazarguil 	*value = value_ret;
274771fa900SAdrien Mazarguil 	return 0;
275771fa900SAdrien Mazarguil }
276771fa900SAdrien Mazarguil 
277771fa900SAdrien Mazarguil /**
278771fa900SAdrien Mazarguil  * Set unsigned long sysfs property.
279771fa900SAdrien Mazarguil  *
280771fa900SAdrien Mazarguil  * @param priv
281771fa900SAdrien Mazarguil  *   Pointer to private structure.
282771fa900SAdrien Mazarguil  * @param[in] name
283771fa900SAdrien Mazarguil  *   Entry name relative to sysfs path.
284771fa900SAdrien Mazarguil  * @param value
285771fa900SAdrien Mazarguil  *   Value to set.
286771fa900SAdrien Mazarguil  *
287771fa900SAdrien Mazarguil  * @return
288771fa900SAdrien Mazarguil  *   0 on success, -1 on failure and errno is set.
289771fa900SAdrien Mazarguil  */
290771fa900SAdrien Mazarguil static int
291771fa900SAdrien Mazarguil priv_set_sysfs_ulong(struct priv *priv, const char *name, unsigned long value)
292771fa900SAdrien Mazarguil {
293771fa900SAdrien Mazarguil 	int ret;
294771fa900SAdrien Mazarguil 	MKSTR(value_str, "%lu", value);
295771fa900SAdrien Mazarguil 
296771fa900SAdrien Mazarguil 	ret = priv_sysfs_write(priv, name, value_str, (sizeof(value_str) - 1));
297771fa900SAdrien Mazarguil 	if (ret == -1) {
298771fa900SAdrien Mazarguil 		DEBUG("cannot write %s `%s' (%lu) to sysfs: %s",
299771fa900SAdrien Mazarguil 		      name, value_str, value, strerror(errno));
300771fa900SAdrien Mazarguil 		return -1;
301771fa900SAdrien Mazarguil 	}
302771fa900SAdrien Mazarguil 	return 0;
303771fa900SAdrien Mazarguil }
304771fa900SAdrien Mazarguil 
305771fa900SAdrien Mazarguil /**
306771fa900SAdrien Mazarguil  * Perform ifreq ioctl() on associated Ethernet device.
307771fa900SAdrien Mazarguil  *
308771fa900SAdrien Mazarguil  * @param[in] priv
309771fa900SAdrien Mazarguil  *   Pointer to private structure.
310771fa900SAdrien Mazarguil  * @param req
311771fa900SAdrien Mazarguil  *   Request number to pass to ioctl().
312771fa900SAdrien Mazarguil  * @param[out] ifr
313771fa900SAdrien Mazarguil  *   Interface request structure output buffer.
314771fa900SAdrien Mazarguil  *
315771fa900SAdrien Mazarguil  * @return
316771fa900SAdrien Mazarguil  *   0 on success, -1 on failure and errno is set.
317771fa900SAdrien Mazarguil  */
318771fa900SAdrien Mazarguil int
319771fa900SAdrien Mazarguil priv_ifreq(const struct priv *priv, int req, struct ifreq *ifr)
320771fa900SAdrien Mazarguil {
321771fa900SAdrien Mazarguil 	int sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
322771fa900SAdrien Mazarguil 	int ret = -1;
323771fa900SAdrien Mazarguil 
324771fa900SAdrien Mazarguil 	if (sock == -1)
325771fa900SAdrien Mazarguil 		return ret;
326771fa900SAdrien Mazarguil 	if (priv_get_ifname(priv, &ifr->ifr_name) == 0)
327771fa900SAdrien Mazarguil 		ret = ioctl(sock, req, ifr);
328771fa900SAdrien Mazarguil 	close(sock);
329771fa900SAdrien Mazarguil 	return ret;
330771fa900SAdrien Mazarguil }
331771fa900SAdrien Mazarguil 
332771fa900SAdrien Mazarguil /**
333771fa900SAdrien Mazarguil  * Get device MTU.
334771fa900SAdrien Mazarguil  *
335771fa900SAdrien Mazarguil  * @param priv
336771fa900SAdrien Mazarguil  *   Pointer to private structure.
337771fa900SAdrien Mazarguil  * @param[out] mtu
338771fa900SAdrien Mazarguil  *   MTU value output buffer.
339771fa900SAdrien Mazarguil  *
340771fa900SAdrien Mazarguil  * @return
341771fa900SAdrien Mazarguil  *   0 on success, -1 on failure and errno is set.
342771fa900SAdrien Mazarguil  */
343771fa900SAdrien Mazarguil int
344771fa900SAdrien Mazarguil priv_get_mtu(struct priv *priv, uint16_t *mtu)
345771fa900SAdrien Mazarguil {
346771fa900SAdrien Mazarguil 	unsigned long ulong_mtu;
347771fa900SAdrien Mazarguil 
348771fa900SAdrien Mazarguil 	if (priv_get_sysfs_ulong(priv, "mtu", &ulong_mtu) == -1)
349771fa900SAdrien Mazarguil 		return -1;
350771fa900SAdrien Mazarguil 	*mtu = ulong_mtu;
351771fa900SAdrien Mazarguil 	return 0;
352771fa900SAdrien Mazarguil }
353771fa900SAdrien Mazarguil 
354771fa900SAdrien Mazarguil /**
355cf37ca95SAdrien Mazarguil  * Set device MTU.
356cf37ca95SAdrien Mazarguil  *
357cf37ca95SAdrien Mazarguil  * @param priv
358cf37ca95SAdrien Mazarguil  *   Pointer to private structure.
359cf37ca95SAdrien Mazarguil  * @param mtu
360cf37ca95SAdrien Mazarguil  *   MTU value to set.
361cf37ca95SAdrien Mazarguil  *
362cf37ca95SAdrien Mazarguil  * @return
363cf37ca95SAdrien Mazarguil  *   0 on success, -1 on failure and errno is set.
364cf37ca95SAdrien Mazarguil  */
365cf37ca95SAdrien Mazarguil static int
366cf37ca95SAdrien Mazarguil priv_set_mtu(struct priv *priv, uint16_t mtu)
367cf37ca95SAdrien Mazarguil {
368cf37ca95SAdrien Mazarguil 	return priv_set_sysfs_ulong(priv, "mtu", mtu);
369cf37ca95SAdrien Mazarguil }
370cf37ca95SAdrien Mazarguil 
371cf37ca95SAdrien Mazarguil /**
372771fa900SAdrien Mazarguil  * Set device flags.
373771fa900SAdrien Mazarguil  *
374771fa900SAdrien Mazarguil  * @param priv
375771fa900SAdrien Mazarguil  *   Pointer to private structure.
376771fa900SAdrien Mazarguil  * @param keep
377771fa900SAdrien Mazarguil  *   Bitmask for flags that must remain untouched.
378771fa900SAdrien Mazarguil  * @param flags
379771fa900SAdrien Mazarguil  *   Bitmask for flags to modify.
380771fa900SAdrien Mazarguil  *
381771fa900SAdrien Mazarguil  * @return
382771fa900SAdrien Mazarguil  *   0 on success, -1 on failure and errno is set.
383771fa900SAdrien Mazarguil  */
384771fa900SAdrien Mazarguil int
385771fa900SAdrien Mazarguil priv_set_flags(struct priv *priv, unsigned int keep, unsigned int flags)
386771fa900SAdrien Mazarguil {
387771fa900SAdrien Mazarguil 	unsigned long tmp;
388771fa900SAdrien Mazarguil 
389771fa900SAdrien Mazarguil 	if (priv_get_sysfs_ulong(priv, "flags", &tmp) == -1)
390771fa900SAdrien Mazarguil 		return -1;
391771fa900SAdrien Mazarguil 	tmp &= keep;
392771fa900SAdrien Mazarguil 	tmp |= flags;
393771fa900SAdrien Mazarguil 	return priv_set_sysfs_ulong(priv, "flags", tmp);
394771fa900SAdrien Mazarguil }
395771fa900SAdrien Mazarguil 
396771fa900SAdrien Mazarguil /**
397e60fbd5bSAdrien Mazarguil  * Ethernet device configuration.
398e60fbd5bSAdrien Mazarguil  *
399e60fbd5bSAdrien Mazarguil  * Prepare the driver for a given number of TX and RX queues.
400e60fbd5bSAdrien Mazarguil  *
401e60fbd5bSAdrien Mazarguil  * @param dev
402e60fbd5bSAdrien Mazarguil  *   Pointer to Ethernet device structure.
403e60fbd5bSAdrien Mazarguil  *
404e60fbd5bSAdrien Mazarguil  * @return
405e60fbd5bSAdrien Mazarguil  *   0 on success, errno value on failure.
406e60fbd5bSAdrien Mazarguil  */
407e60fbd5bSAdrien Mazarguil static int
408e60fbd5bSAdrien Mazarguil dev_configure(struct rte_eth_dev *dev)
409e60fbd5bSAdrien Mazarguil {
410e60fbd5bSAdrien Mazarguil 	struct priv *priv = dev->data->dev_private;
411e60fbd5bSAdrien Mazarguil 	unsigned int rxqs_n = dev->data->nb_rx_queues;
412e60fbd5bSAdrien Mazarguil 	unsigned int txqs_n = dev->data->nb_tx_queues;
413*634efbc2SNelio Laranjeiro 	unsigned int i;
414*634efbc2SNelio Laranjeiro 	unsigned int j;
415*634efbc2SNelio Laranjeiro 	unsigned int reta_idx_n;
416e60fbd5bSAdrien Mazarguil 
417e60fbd5bSAdrien Mazarguil 	priv->rxqs = (void *)dev->data->rx_queues;
418e60fbd5bSAdrien Mazarguil 	priv->txqs = (void *)dev->data->tx_queues;
419e60fbd5bSAdrien Mazarguil 	if (txqs_n != priv->txqs_n) {
420e60fbd5bSAdrien Mazarguil 		INFO("%p: TX queues number update: %u -> %u",
421e60fbd5bSAdrien Mazarguil 		     (void *)dev, priv->txqs_n, txqs_n);
422e60fbd5bSAdrien Mazarguil 		priv->txqs_n = txqs_n;
423e60fbd5bSAdrien Mazarguil 	}
424*634efbc2SNelio Laranjeiro 	if (rxqs_n > priv->ind_table_max_size) {
425*634efbc2SNelio Laranjeiro 		ERROR("cannot handle this many RX queues (%u)", rxqs_n);
426*634efbc2SNelio Laranjeiro 		return EINVAL;
427*634efbc2SNelio Laranjeiro 	}
428e60fbd5bSAdrien Mazarguil 	if (rxqs_n == priv->rxqs_n)
429e60fbd5bSAdrien Mazarguil 		return 0;
430e60fbd5bSAdrien Mazarguil 	INFO("%p: RX queues number update: %u -> %u",
431e60fbd5bSAdrien Mazarguil 	     (void *)dev, priv->rxqs_n, rxqs_n);
432e60fbd5bSAdrien Mazarguil 	priv->rxqs_n = rxqs_n;
433*634efbc2SNelio Laranjeiro 	/* If the requested number of RX queues is not a power of two, use the
434*634efbc2SNelio Laranjeiro 	 * maximum indirection table size for better balancing.
435*634efbc2SNelio Laranjeiro 	 * The result is always rounded to the next power of two. */
436*634efbc2SNelio Laranjeiro 	reta_idx_n = (1 << log2above((rxqs_n & (rxqs_n - 1)) ?
437*634efbc2SNelio Laranjeiro 				     priv->ind_table_max_size :
438*634efbc2SNelio Laranjeiro 				     rxqs_n));
439*634efbc2SNelio Laranjeiro 	if (priv_rss_reta_index_resize(priv, reta_idx_n))
440*634efbc2SNelio Laranjeiro 		return ENOMEM;
441*634efbc2SNelio Laranjeiro 	/* When the number of RX queues is not a power of two, the remaining
442*634efbc2SNelio Laranjeiro 	 * table entries are padded with reused WQs and hashes are not spread
443*634efbc2SNelio Laranjeiro 	 * uniformly. */
444*634efbc2SNelio Laranjeiro 	for (i = 0, j = 0; (i != reta_idx_n); ++i) {
445*634efbc2SNelio Laranjeiro 		(*priv->reta_idx)[i] = j;
446*634efbc2SNelio Laranjeiro 		if (++j == rxqs_n)
447*634efbc2SNelio Laranjeiro 			j = 0;
448*634efbc2SNelio Laranjeiro 	}
449e60fbd5bSAdrien Mazarguil 	return 0;
450e60fbd5bSAdrien Mazarguil }
451e60fbd5bSAdrien Mazarguil 
452e60fbd5bSAdrien Mazarguil /**
453e60fbd5bSAdrien Mazarguil  * DPDK callback for Ethernet device configuration.
454e60fbd5bSAdrien Mazarguil  *
455e60fbd5bSAdrien Mazarguil  * @param dev
456e60fbd5bSAdrien Mazarguil  *   Pointer to Ethernet device structure.
457e60fbd5bSAdrien Mazarguil  *
458e60fbd5bSAdrien Mazarguil  * @return
459e60fbd5bSAdrien Mazarguil  *   0 on success, negative errno value on failure.
460e60fbd5bSAdrien Mazarguil  */
461e60fbd5bSAdrien Mazarguil int
462e60fbd5bSAdrien Mazarguil mlx5_dev_configure(struct rte_eth_dev *dev)
463e60fbd5bSAdrien Mazarguil {
464e60fbd5bSAdrien Mazarguil 	struct priv *priv = dev->data->dev_private;
465e60fbd5bSAdrien Mazarguil 	int ret;
466e60fbd5bSAdrien Mazarguil 
467e60fbd5bSAdrien Mazarguil 	priv_lock(priv);
468e60fbd5bSAdrien Mazarguil 	ret = dev_configure(dev);
469e60fbd5bSAdrien Mazarguil 	assert(ret >= 0);
470e60fbd5bSAdrien Mazarguil 	priv_unlock(priv);
471e60fbd5bSAdrien Mazarguil 	return -ret;
472e60fbd5bSAdrien Mazarguil }
473e60fbd5bSAdrien Mazarguil 
474e60fbd5bSAdrien Mazarguil /**
475e60fbd5bSAdrien Mazarguil  * DPDK callback to get information about the device.
476e60fbd5bSAdrien Mazarguil  *
477e60fbd5bSAdrien Mazarguil  * @param dev
478e60fbd5bSAdrien Mazarguil  *   Pointer to Ethernet device structure.
479e60fbd5bSAdrien Mazarguil  * @param[out] info
480e60fbd5bSAdrien Mazarguil  *   Info structure output buffer.
481e60fbd5bSAdrien Mazarguil  */
482e60fbd5bSAdrien Mazarguil void
483e60fbd5bSAdrien Mazarguil mlx5_dev_infos_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *info)
484e60fbd5bSAdrien Mazarguil {
485e60fbd5bSAdrien Mazarguil 	struct priv *priv = dev->data->dev_private;
486e60fbd5bSAdrien Mazarguil 	unsigned int max;
487e60fbd5bSAdrien Mazarguil 	char ifname[IF_NAMESIZE];
488e60fbd5bSAdrien Mazarguil 
489e60fbd5bSAdrien Mazarguil 	priv_lock(priv);
490e60fbd5bSAdrien Mazarguil 	/* FIXME: we should ask the device for these values. */
491e60fbd5bSAdrien Mazarguil 	info->min_rx_bufsize = 32;
492e60fbd5bSAdrien Mazarguil 	info->max_rx_pktlen = 65536;
493e60fbd5bSAdrien Mazarguil 	/*
494e60fbd5bSAdrien Mazarguil 	 * Since we need one CQ per QP, the limit is the minimum number
495e60fbd5bSAdrien Mazarguil 	 * between the two values.
496e60fbd5bSAdrien Mazarguil 	 */
497e60fbd5bSAdrien Mazarguil 	max = ((priv->device_attr.max_cq > priv->device_attr.max_qp) ?
498e60fbd5bSAdrien Mazarguil 	       priv->device_attr.max_qp : priv->device_attr.max_cq);
499e60fbd5bSAdrien Mazarguil 	/* If max >= 65535 then max = 0, max_rx_queues is uint16_t. */
500e60fbd5bSAdrien Mazarguil 	if (max >= 65535)
501e60fbd5bSAdrien Mazarguil 		max = 65535;
502e60fbd5bSAdrien Mazarguil 	info->max_rx_queues = max;
503e60fbd5bSAdrien Mazarguil 	info->max_tx_queues = max;
504e60fbd5bSAdrien Mazarguil 	/* Last array entry is reserved for broadcast. */
505e60fbd5bSAdrien Mazarguil 	info->max_mac_addrs = (RTE_DIM(priv->mac) - 1);
506e60fbd5bSAdrien Mazarguil 	info->rx_offload_capa =
507e60fbd5bSAdrien Mazarguil 		(priv->hw_csum ?
508e60fbd5bSAdrien Mazarguil 		 (DEV_RX_OFFLOAD_IPV4_CKSUM |
509e60fbd5bSAdrien Mazarguil 		  DEV_RX_OFFLOAD_UDP_CKSUM |
510e60fbd5bSAdrien Mazarguil 		  DEV_RX_OFFLOAD_TCP_CKSUM) :
511e60fbd5bSAdrien Mazarguil 		 0);
512e60fbd5bSAdrien Mazarguil 	info->tx_offload_capa =
513e60fbd5bSAdrien Mazarguil 		(priv->hw_csum ?
514e60fbd5bSAdrien Mazarguil 		 (DEV_TX_OFFLOAD_IPV4_CKSUM |
515e60fbd5bSAdrien Mazarguil 		  DEV_TX_OFFLOAD_UDP_CKSUM |
516e60fbd5bSAdrien Mazarguil 		  DEV_TX_OFFLOAD_TCP_CKSUM) :
517e60fbd5bSAdrien Mazarguil 		 0);
518e60fbd5bSAdrien Mazarguil 	if (priv_get_ifname(priv, &ifname) == 0)
519e60fbd5bSAdrien Mazarguil 		info->if_index = if_nametoindex(ifname);
520*634efbc2SNelio Laranjeiro 	/* FIXME: RETA update/query API expects the callee to know the size of
521*634efbc2SNelio Laranjeiro 	 * the indirection table, for this PMD the size varies depending on
522*634efbc2SNelio Laranjeiro 	 * the number of RX queues, it becomes impossible to find the correct
523*634efbc2SNelio Laranjeiro 	 * size if it is not fixed.
524*634efbc2SNelio Laranjeiro 	 * The API should be updated to solve this problem. */
525*634efbc2SNelio Laranjeiro 	info->reta_size = priv->ind_table_max_size;
526e60fbd5bSAdrien Mazarguil 	priv_unlock(priv);
527e60fbd5bSAdrien Mazarguil }
528e60fbd5bSAdrien Mazarguil 
529e60fbd5bSAdrien Mazarguil /**
530cb8faed7SAdrien Mazarguil  * DPDK callback to retrieve physical link information (unlocked version).
531cb8faed7SAdrien Mazarguil  *
532cb8faed7SAdrien Mazarguil  * @param dev
533cb8faed7SAdrien Mazarguil  *   Pointer to Ethernet device structure.
534cb8faed7SAdrien Mazarguil  * @param wait_to_complete
535cb8faed7SAdrien Mazarguil  *   Wait for request completion (ignored).
536cb8faed7SAdrien Mazarguil  */
537cb8faed7SAdrien Mazarguil static int
538cb8faed7SAdrien Mazarguil mlx5_link_update_unlocked(struct rte_eth_dev *dev, int wait_to_complete)
539cb8faed7SAdrien Mazarguil {
540cb8faed7SAdrien Mazarguil 	struct priv *priv = dev->data->dev_private;
541cb8faed7SAdrien Mazarguil 	struct ethtool_cmd edata = {
542cb8faed7SAdrien Mazarguil 		.cmd = ETHTOOL_GSET
543cb8faed7SAdrien Mazarguil 	};
544cb8faed7SAdrien Mazarguil 	struct ifreq ifr;
545cb8faed7SAdrien Mazarguil 	struct rte_eth_link dev_link;
546cb8faed7SAdrien Mazarguil 	int link_speed = 0;
547cb8faed7SAdrien Mazarguil 
548cb8faed7SAdrien Mazarguil 	(void)wait_to_complete;
549cb8faed7SAdrien Mazarguil 	if (priv_ifreq(priv, SIOCGIFFLAGS, &ifr)) {
550cb8faed7SAdrien Mazarguil 		WARN("ioctl(SIOCGIFFLAGS) failed: %s", strerror(errno));
551cb8faed7SAdrien Mazarguil 		return -1;
552cb8faed7SAdrien Mazarguil 	}
553cb8faed7SAdrien Mazarguil 	memset(&dev_link, 0, sizeof(dev_link));
554cb8faed7SAdrien Mazarguil 	dev_link.link_status = ((ifr.ifr_flags & IFF_UP) &&
555cb8faed7SAdrien Mazarguil 				(ifr.ifr_flags & IFF_RUNNING));
556cb8faed7SAdrien Mazarguil 	ifr.ifr_data = &edata;
557cb8faed7SAdrien Mazarguil 	if (priv_ifreq(priv, SIOCETHTOOL, &ifr)) {
558cb8faed7SAdrien Mazarguil 		WARN("ioctl(SIOCETHTOOL, ETHTOOL_GSET) failed: %s",
559cb8faed7SAdrien Mazarguil 		     strerror(errno));
560cb8faed7SAdrien Mazarguil 		return -1;
561cb8faed7SAdrien Mazarguil 	}
562cb8faed7SAdrien Mazarguil 	link_speed = ethtool_cmd_speed(&edata);
563cb8faed7SAdrien Mazarguil 	if (link_speed == -1)
564cb8faed7SAdrien Mazarguil 		dev_link.link_speed = 0;
565cb8faed7SAdrien Mazarguil 	else
566cb8faed7SAdrien Mazarguil 		dev_link.link_speed = link_speed;
567cb8faed7SAdrien Mazarguil 	dev_link.link_duplex = ((edata.duplex == DUPLEX_HALF) ?
568cb8faed7SAdrien Mazarguil 				ETH_LINK_HALF_DUPLEX : ETH_LINK_FULL_DUPLEX);
569cb8faed7SAdrien Mazarguil 	if (memcmp(&dev_link, &dev->data->dev_link, sizeof(dev_link))) {
570cb8faed7SAdrien Mazarguil 		/* Link status changed. */
571cb8faed7SAdrien Mazarguil 		dev->data->dev_link = dev_link;
572cb8faed7SAdrien Mazarguil 		return 0;
573cb8faed7SAdrien Mazarguil 	}
574cb8faed7SAdrien Mazarguil 	/* Link status is still the same. */
575cb8faed7SAdrien Mazarguil 	return -1;
576cb8faed7SAdrien Mazarguil }
577cb8faed7SAdrien Mazarguil 
578cb8faed7SAdrien Mazarguil /**
579cb8faed7SAdrien Mazarguil  * DPDK callback to retrieve physical link information.
580cb8faed7SAdrien Mazarguil  *
581cb8faed7SAdrien Mazarguil  * @param dev
582cb8faed7SAdrien Mazarguil  *   Pointer to Ethernet device structure.
583cb8faed7SAdrien Mazarguil  * @param wait_to_complete
584cb8faed7SAdrien Mazarguil  *   Wait for request completion (ignored).
585cb8faed7SAdrien Mazarguil  */
586cb8faed7SAdrien Mazarguil int
587cb8faed7SAdrien Mazarguil mlx5_link_update(struct rte_eth_dev *dev, int wait_to_complete)
588cb8faed7SAdrien Mazarguil {
589cb8faed7SAdrien Mazarguil 	struct priv *priv = dev->data->dev_private;
590cb8faed7SAdrien Mazarguil 	int ret;
591cb8faed7SAdrien Mazarguil 
592cb8faed7SAdrien Mazarguil 	priv_lock(priv);
593cb8faed7SAdrien Mazarguil 	ret = mlx5_link_update_unlocked(dev, wait_to_complete);
594cb8faed7SAdrien Mazarguil 	priv_unlock(priv);
595cb8faed7SAdrien Mazarguil 	return ret;
596cb8faed7SAdrien Mazarguil }
597cb8faed7SAdrien Mazarguil 
598cb8faed7SAdrien Mazarguil /**
599cf37ca95SAdrien Mazarguil  * DPDK callback to change the MTU.
600cf37ca95SAdrien Mazarguil  *
601cf37ca95SAdrien Mazarguil  * Setting the MTU affects hardware MRU (packets larger than the MTU cannot be
602cf37ca95SAdrien Mazarguil  * received). Use this as a hint to enable/disable scattered packets support
603cf37ca95SAdrien Mazarguil  * and improve performance when not needed.
604cf37ca95SAdrien Mazarguil  * Since failure is not an option, reconfiguring queues on the fly is not
605cf37ca95SAdrien Mazarguil  * recommended.
606cf37ca95SAdrien Mazarguil  *
607cf37ca95SAdrien Mazarguil  * @param dev
608cf37ca95SAdrien Mazarguil  *   Pointer to Ethernet device structure.
609cf37ca95SAdrien Mazarguil  * @param in_mtu
610cf37ca95SAdrien Mazarguil  *   New MTU.
611cf37ca95SAdrien Mazarguil  *
612cf37ca95SAdrien Mazarguil  * @return
613cf37ca95SAdrien Mazarguil  *   0 on success, negative errno value on failure.
614cf37ca95SAdrien Mazarguil  */
615cf37ca95SAdrien Mazarguil int
616cf37ca95SAdrien Mazarguil mlx5_dev_set_mtu(struct rte_eth_dev *dev, uint16_t mtu)
617cf37ca95SAdrien Mazarguil {
618cf37ca95SAdrien Mazarguil 	struct priv *priv = dev->data->dev_private;
619cf37ca95SAdrien Mazarguil 	int ret = 0;
620cf37ca95SAdrien Mazarguil 	unsigned int i;
621cf37ca95SAdrien Mazarguil 	uint16_t (*rx_func)(void *, struct rte_mbuf **, uint16_t) =
622cf37ca95SAdrien Mazarguil 		mlx5_rx_burst;
623cf37ca95SAdrien Mazarguil 
624cf37ca95SAdrien Mazarguil 	priv_lock(priv);
625cf37ca95SAdrien Mazarguil 	/* Set kernel interface MTU first. */
626cf37ca95SAdrien Mazarguil 	if (priv_set_mtu(priv, mtu)) {
627cf37ca95SAdrien Mazarguil 		ret = errno;
628cf37ca95SAdrien Mazarguil 		WARN("cannot set port %u MTU to %u: %s", priv->port, mtu,
629cf37ca95SAdrien Mazarguil 		     strerror(ret));
630cf37ca95SAdrien Mazarguil 		goto out;
631cf37ca95SAdrien Mazarguil 	} else
632cf37ca95SAdrien Mazarguil 		DEBUG("adapter port %u MTU set to %u", priv->port, mtu);
633cf37ca95SAdrien Mazarguil 	priv->mtu = mtu;
634cf37ca95SAdrien Mazarguil 	/* Temporarily replace RX handler with a fake one, assuming it has not
635cf37ca95SAdrien Mazarguil 	 * been copied elsewhere. */
636cf37ca95SAdrien Mazarguil 	dev->rx_pkt_burst = removed_rx_burst;
637cf37ca95SAdrien Mazarguil 	/* Make sure everyone has left mlx5_rx_burst() and uses
638cf37ca95SAdrien Mazarguil 	 * removed_rx_burst() instead. */
639cf37ca95SAdrien Mazarguil 	rte_wmb();
640cf37ca95SAdrien Mazarguil 	usleep(1000);
641cf37ca95SAdrien Mazarguil 	/* Reconfigure each RX queue. */
642cf37ca95SAdrien Mazarguil 	for (i = 0; (i != priv->rxqs_n); ++i) {
643cf37ca95SAdrien Mazarguil 		struct rxq *rxq = (*priv->rxqs)[i];
644cf37ca95SAdrien Mazarguil 		unsigned int max_frame_len;
645cf37ca95SAdrien Mazarguil 		int sp;
646cf37ca95SAdrien Mazarguil 
647cf37ca95SAdrien Mazarguil 		if (rxq == NULL)
648cf37ca95SAdrien Mazarguil 			continue;
649cf37ca95SAdrien Mazarguil 		/* Calculate new maximum frame length according to MTU and
650cf37ca95SAdrien Mazarguil 		 * toggle scattered support (sp) if necessary. */
651cf37ca95SAdrien Mazarguil 		max_frame_len = (priv->mtu + ETHER_HDR_LEN +
652cf37ca95SAdrien Mazarguil 				 (ETHER_MAX_VLAN_FRAME_LEN - ETHER_MAX_LEN));
653cf37ca95SAdrien Mazarguil 		sp = (max_frame_len > (rxq->mb_len - RTE_PKTMBUF_HEADROOM));
654cf37ca95SAdrien Mazarguil 		/* Provide new values to rxq_setup(). */
655cf37ca95SAdrien Mazarguil 		dev->data->dev_conf.rxmode.jumbo_frame = sp;
656cf37ca95SAdrien Mazarguil 		dev->data->dev_conf.rxmode.max_rx_pkt_len = max_frame_len;
657cf37ca95SAdrien Mazarguil 		ret = rxq_rehash(dev, rxq);
658cf37ca95SAdrien Mazarguil 		if (ret) {
659cf37ca95SAdrien Mazarguil 			/* Force SP RX if that queue requires it and abort. */
660cf37ca95SAdrien Mazarguil 			if (rxq->sp)
661cf37ca95SAdrien Mazarguil 				rx_func = mlx5_rx_burst_sp;
662cf37ca95SAdrien Mazarguil 			break;
663cf37ca95SAdrien Mazarguil 		}
664cf37ca95SAdrien Mazarguil 		/* Scattered burst function takes priority. */
665cf37ca95SAdrien Mazarguil 		if (rxq->sp)
666cf37ca95SAdrien Mazarguil 			rx_func = mlx5_rx_burst_sp;
667cf37ca95SAdrien Mazarguil 	}
668cf37ca95SAdrien Mazarguil 	/* Burst functions can now be called again. */
669cf37ca95SAdrien Mazarguil 	rte_wmb();
670cf37ca95SAdrien Mazarguil 	dev->rx_pkt_burst = rx_func;
671cf37ca95SAdrien Mazarguil out:
672cf37ca95SAdrien Mazarguil 	priv_unlock(priv);
673cf37ca95SAdrien Mazarguil 	assert(ret >= 0);
674cf37ca95SAdrien Mazarguil 	return -ret;
675cf37ca95SAdrien Mazarguil }
676cf37ca95SAdrien Mazarguil 
677cf37ca95SAdrien Mazarguil /**
67802d75430SAdrien Mazarguil  * DPDK callback to get flow control status.
67902d75430SAdrien Mazarguil  *
68002d75430SAdrien Mazarguil  * @param dev
68102d75430SAdrien Mazarguil  *   Pointer to Ethernet device structure.
68202d75430SAdrien Mazarguil  * @param[out] fc_conf
68302d75430SAdrien Mazarguil  *   Flow control output buffer.
68402d75430SAdrien Mazarguil  *
68502d75430SAdrien Mazarguil  * @return
68602d75430SAdrien Mazarguil  *   0 on success, negative errno value on failure.
68702d75430SAdrien Mazarguil  */
68802d75430SAdrien Mazarguil int
68902d75430SAdrien Mazarguil mlx5_dev_get_flow_ctrl(struct rte_eth_dev *dev, struct rte_eth_fc_conf *fc_conf)
69002d75430SAdrien Mazarguil {
69102d75430SAdrien Mazarguil 	struct priv *priv = dev->data->dev_private;
69202d75430SAdrien Mazarguil 	struct ifreq ifr;
69302d75430SAdrien Mazarguil 	struct ethtool_pauseparam ethpause = {
69402d75430SAdrien Mazarguil 		.cmd = ETHTOOL_GPAUSEPARAM
69502d75430SAdrien Mazarguil 	};
69602d75430SAdrien Mazarguil 	int ret;
69702d75430SAdrien Mazarguil 
69802d75430SAdrien Mazarguil 	ifr.ifr_data = &ethpause;
69902d75430SAdrien Mazarguil 	priv_lock(priv);
70002d75430SAdrien Mazarguil 	if (priv_ifreq(priv, SIOCETHTOOL, &ifr)) {
70102d75430SAdrien Mazarguil 		ret = errno;
70202d75430SAdrien Mazarguil 		WARN("ioctl(SIOCETHTOOL, ETHTOOL_GPAUSEPARAM)"
70302d75430SAdrien Mazarguil 		     " failed: %s",
70402d75430SAdrien Mazarguil 		     strerror(ret));
70502d75430SAdrien Mazarguil 		goto out;
70602d75430SAdrien Mazarguil 	}
70702d75430SAdrien Mazarguil 
70802d75430SAdrien Mazarguil 	fc_conf->autoneg = ethpause.autoneg;
70902d75430SAdrien Mazarguil 	if (ethpause.rx_pause && ethpause.tx_pause)
71002d75430SAdrien Mazarguil 		fc_conf->mode = RTE_FC_FULL;
71102d75430SAdrien Mazarguil 	else if (ethpause.rx_pause)
71202d75430SAdrien Mazarguil 		fc_conf->mode = RTE_FC_RX_PAUSE;
71302d75430SAdrien Mazarguil 	else if (ethpause.tx_pause)
71402d75430SAdrien Mazarguil 		fc_conf->mode = RTE_FC_TX_PAUSE;
71502d75430SAdrien Mazarguil 	else
71602d75430SAdrien Mazarguil 		fc_conf->mode = RTE_FC_NONE;
71702d75430SAdrien Mazarguil 	ret = 0;
71802d75430SAdrien Mazarguil 
71902d75430SAdrien Mazarguil out:
72002d75430SAdrien Mazarguil 	priv_unlock(priv);
72102d75430SAdrien Mazarguil 	assert(ret >= 0);
72202d75430SAdrien Mazarguil 	return -ret;
72302d75430SAdrien Mazarguil }
72402d75430SAdrien Mazarguil 
72502d75430SAdrien Mazarguil /**
72602d75430SAdrien Mazarguil  * DPDK callback to modify flow control parameters.
72702d75430SAdrien Mazarguil  *
72802d75430SAdrien Mazarguil  * @param dev
72902d75430SAdrien Mazarguil  *   Pointer to Ethernet device structure.
73002d75430SAdrien Mazarguil  * @param[in] fc_conf
73102d75430SAdrien Mazarguil  *   Flow control parameters.
73202d75430SAdrien Mazarguil  *
73302d75430SAdrien Mazarguil  * @return
73402d75430SAdrien Mazarguil  *   0 on success, negative errno value on failure.
73502d75430SAdrien Mazarguil  */
73602d75430SAdrien Mazarguil int
73702d75430SAdrien Mazarguil mlx5_dev_set_flow_ctrl(struct rte_eth_dev *dev, struct rte_eth_fc_conf *fc_conf)
73802d75430SAdrien Mazarguil {
73902d75430SAdrien Mazarguil 	struct priv *priv = dev->data->dev_private;
74002d75430SAdrien Mazarguil 	struct ifreq ifr;
74102d75430SAdrien Mazarguil 	struct ethtool_pauseparam ethpause = {
74202d75430SAdrien Mazarguil 		.cmd = ETHTOOL_SPAUSEPARAM
74302d75430SAdrien Mazarguil 	};
74402d75430SAdrien Mazarguil 	int ret;
74502d75430SAdrien Mazarguil 
74602d75430SAdrien Mazarguil 	ifr.ifr_data = &ethpause;
74702d75430SAdrien Mazarguil 	ethpause.autoneg = fc_conf->autoneg;
74802d75430SAdrien Mazarguil 	if (((fc_conf->mode & RTE_FC_FULL) == RTE_FC_FULL) ||
74902d75430SAdrien Mazarguil 	    (fc_conf->mode & RTE_FC_RX_PAUSE))
75002d75430SAdrien Mazarguil 		ethpause.rx_pause = 1;
75102d75430SAdrien Mazarguil 	else
75202d75430SAdrien Mazarguil 		ethpause.rx_pause = 0;
75302d75430SAdrien Mazarguil 
75402d75430SAdrien Mazarguil 	if (((fc_conf->mode & RTE_FC_FULL) == RTE_FC_FULL) ||
75502d75430SAdrien Mazarguil 	    (fc_conf->mode & RTE_FC_TX_PAUSE))
75602d75430SAdrien Mazarguil 		ethpause.tx_pause = 1;
75702d75430SAdrien Mazarguil 	else
75802d75430SAdrien Mazarguil 		ethpause.tx_pause = 0;
75902d75430SAdrien Mazarguil 
76002d75430SAdrien Mazarguil 	priv_lock(priv);
76102d75430SAdrien Mazarguil 	if (priv_ifreq(priv, SIOCETHTOOL, &ifr)) {
76202d75430SAdrien Mazarguil 		ret = errno;
76302d75430SAdrien Mazarguil 		WARN("ioctl(SIOCETHTOOL, ETHTOOL_SPAUSEPARAM)"
76402d75430SAdrien Mazarguil 		     " failed: %s",
76502d75430SAdrien Mazarguil 		     strerror(ret));
76602d75430SAdrien Mazarguil 		goto out;
76702d75430SAdrien Mazarguil 	}
76802d75430SAdrien Mazarguil 	ret = 0;
76902d75430SAdrien Mazarguil 
77002d75430SAdrien Mazarguil out:
77102d75430SAdrien Mazarguil 	priv_unlock(priv);
77202d75430SAdrien Mazarguil 	assert(ret >= 0);
77302d75430SAdrien Mazarguil 	return -ret;
77402d75430SAdrien Mazarguil }
77502d75430SAdrien Mazarguil 
77602d75430SAdrien Mazarguil /**
777771fa900SAdrien Mazarguil  * Get PCI information from struct ibv_device.
778771fa900SAdrien Mazarguil  *
779771fa900SAdrien Mazarguil  * @param device
780771fa900SAdrien Mazarguil  *   Pointer to Ethernet device structure.
781771fa900SAdrien Mazarguil  * @param[out] pci_addr
782771fa900SAdrien Mazarguil  *   PCI bus address output buffer.
783771fa900SAdrien Mazarguil  *
784771fa900SAdrien Mazarguil  * @return
785771fa900SAdrien Mazarguil  *   0 on success, -1 on failure and errno is set.
786771fa900SAdrien Mazarguil  */
787771fa900SAdrien Mazarguil int
788771fa900SAdrien Mazarguil mlx5_ibv_device_to_pci_addr(const struct ibv_device *device,
789771fa900SAdrien Mazarguil 			    struct rte_pci_addr *pci_addr)
790771fa900SAdrien Mazarguil {
791771fa900SAdrien Mazarguil 	FILE *file;
792771fa900SAdrien Mazarguil 	char line[32];
793771fa900SAdrien Mazarguil 	MKSTR(path, "%s/device/uevent", device->ibdev_path);
794771fa900SAdrien Mazarguil 
795771fa900SAdrien Mazarguil 	file = fopen(path, "rb");
796771fa900SAdrien Mazarguil 	if (file == NULL)
797771fa900SAdrien Mazarguil 		return -1;
798771fa900SAdrien Mazarguil 	while (fgets(line, sizeof(line), file) == line) {
799771fa900SAdrien Mazarguil 		size_t len = strlen(line);
800771fa900SAdrien Mazarguil 		int ret;
801771fa900SAdrien Mazarguil 
802771fa900SAdrien Mazarguil 		/* Truncate long lines. */
803771fa900SAdrien Mazarguil 		if (len == (sizeof(line) - 1))
804771fa900SAdrien Mazarguil 			while (line[(len - 1)] != '\n') {
805771fa900SAdrien Mazarguil 				ret = fgetc(file);
806771fa900SAdrien Mazarguil 				if (ret == EOF)
807771fa900SAdrien Mazarguil 					break;
808771fa900SAdrien Mazarguil 				line[(len - 1)] = ret;
809771fa900SAdrien Mazarguil 			}
810771fa900SAdrien Mazarguil 		/* Extract information. */
811771fa900SAdrien Mazarguil 		if (sscanf(line,
812771fa900SAdrien Mazarguil 			   "PCI_SLOT_NAME="
813771fa900SAdrien Mazarguil 			   "%" SCNx16 ":%" SCNx8 ":%" SCNx8 ".%" SCNx8 "\n",
814771fa900SAdrien Mazarguil 			   &pci_addr->domain,
815771fa900SAdrien Mazarguil 			   &pci_addr->bus,
816771fa900SAdrien Mazarguil 			   &pci_addr->devid,
817771fa900SAdrien Mazarguil 			   &pci_addr->function) == 4) {
818771fa900SAdrien Mazarguil 			ret = 0;
819771fa900SAdrien Mazarguil 			break;
820771fa900SAdrien Mazarguil 		}
821771fa900SAdrien Mazarguil 	}
822771fa900SAdrien Mazarguil 	fclose(file);
823771fa900SAdrien Mazarguil 	return 0;
824771fa900SAdrien Mazarguil }
825198a3c33SNelio Laranjeiro 
826198a3c33SNelio Laranjeiro /**
827198a3c33SNelio Laranjeiro  * Link status handler.
828198a3c33SNelio Laranjeiro  *
829198a3c33SNelio Laranjeiro  * @param priv
830198a3c33SNelio Laranjeiro  *   Pointer to private structure.
831198a3c33SNelio Laranjeiro  * @param dev
832198a3c33SNelio Laranjeiro  *   Pointer to the rte_eth_dev structure.
833198a3c33SNelio Laranjeiro  *
834198a3c33SNelio Laranjeiro  * @return
835198a3c33SNelio Laranjeiro  *   Nonzero if the callback process can be called immediately.
836198a3c33SNelio Laranjeiro  */
837198a3c33SNelio Laranjeiro static int
838198a3c33SNelio Laranjeiro priv_dev_link_status_handler(struct priv *priv, struct rte_eth_dev *dev)
839198a3c33SNelio Laranjeiro {
840198a3c33SNelio Laranjeiro 	struct ibv_async_event event;
841198a3c33SNelio Laranjeiro 	int port_change = 0;
842198a3c33SNelio Laranjeiro 	int ret = 0;
843198a3c33SNelio Laranjeiro 
844198a3c33SNelio Laranjeiro 	/* Read all message and acknowledge them. */
845198a3c33SNelio Laranjeiro 	for (;;) {
846198a3c33SNelio Laranjeiro 		if (ibv_get_async_event(priv->ctx, &event))
847198a3c33SNelio Laranjeiro 			break;
848198a3c33SNelio Laranjeiro 
849198a3c33SNelio Laranjeiro 		if (event.event_type == IBV_EVENT_PORT_ACTIVE ||
850198a3c33SNelio Laranjeiro 		    event.event_type == IBV_EVENT_PORT_ERR)
851198a3c33SNelio Laranjeiro 			port_change = 1;
852198a3c33SNelio Laranjeiro 		else
853198a3c33SNelio Laranjeiro 			DEBUG("event type %d on port %d not handled",
854198a3c33SNelio Laranjeiro 			      event.event_type, event.element.port_num);
855198a3c33SNelio Laranjeiro 		ibv_ack_async_event(&event);
856198a3c33SNelio Laranjeiro 	}
857198a3c33SNelio Laranjeiro 
858198a3c33SNelio Laranjeiro 	if (port_change ^ priv->pending_alarm) {
859198a3c33SNelio Laranjeiro 		struct rte_eth_link *link = &dev->data->dev_link;
860198a3c33SNelio Laranjeiro 
861198a3c33SNelio Laranjeiro 		priv->pending_alarm = 0;
862198a3c33SNelio Laranjeiro 		mlx5_link_update_unlocked(dev, 0);
863198a3c33SNelio Laranjeiro 		if (((link->link_speed == 0) && link->link_status) ||
864198a3c33SNelio Laranjeiro 		    ((link->link_speed != 0) && !link->link_status)) {
865198a3c33SNelio Laranjeiro 			/* Inconsistent status, check again later. */
866198a3c33SNelio Laranjeiro 			priv->pending_alarm = 1;
867198a3c33SNelio Laranjeiro 			rte_eal_alarm_set(MLX5_ALARM_TIMEOUT_US,
868198a3c33SNelio Laranjeiro 					  mlx5_dev_link_status_handler,
869198a3c33SNelio Laranjeiro 					  dev);
870198a3c33SNelio Laranjeiro 		} else
871198a3c33SNelio Laranjeiro 			ret = 1;
872198a3c33SNelio Laranjeiro 	}
873198a3c33SNelio Laranjeiro 	return ret;
874198a3c33SNelio Laranjeiro }
875198a3c33SNelio Laranjeiro 
876198a3c33SNelio Laranjeiro /**
877198a3c33SNelio Laranjeiro  * Handle delayed link status event.
878198a3c33SNelio Laranjeiro  *
879198a3c33SNelio Laranjeiro  * @param arg
880198a3c33SNelio Laranjeiro  *   Registered argument.
881198a3c33SNelio Laranjeiro  */
882198a3c33SNelio Laranjeiro void
883198a3c33SNelio Laranjeiro mlx5_dev_link_status_handler(void *arg)
884198a3c33SNelio Laranjeiro {
885198a3c33SNelio Laranjeiro 	struct rte_eth_dev *dev = arg;
886198a3c33SNelio Laranjeiro 	struct priv *priv = dev->data->dev_private;
887198a3c33SNelio Laranjeiro 	int ret;
888198a3c33SNelio Laranjeiro 
889198a3c33SNelio Laranjeiro 	priv_lock(priv);
890198a3c33SNelio Laranjeiro 	assert(priv->pending_alarm == 1);
891198a3c33SNelio Laranjeiro 	ret = priv_dev_link_status_handler(priv, dev);
892198a3c33SNelio Laranjeiro 	priv_unlock(priv);
893198a3c33SNelio Laranjeiro 	if (ret)
894198a3c33SNelio Laranjeiro 		_rte_eth_dev_callback_process(dev, RTE_ETH_EVENT_INTR_LSC);
895198a3c33SNelio Laranjeiro }
896198a3c33SNelio Laranjeiro 
897198a3c33SNelio Laranjeiro /**
898198a3c33SNelio Laranjeiro  * Handle interrupts from the NIC.
899198a3c33SNelio Laranjeiro  *
900198a3c33SNelio Laranjeiro  * @param[in] intr_handle
901198a3c33SNelio Laranjeiro  *   Interrupt handler.
902198a3c33SNelio Laranjeiro  * @param cb_arg
903198a3c33SNelio Laranjeiro  *   Callback argument.
904198a3c33SNelio Laranjeiro  */
905198a3c33SNelio Laranjeiro void
906198a3c33SNelio Laranjeiro mlx5_dev_interrupt_handler(struct rte_intr_handle *intr_handle, void *cb_arg)
907198a3c33SNelio Laranjeiro {
908198a3c33SNelio Laranjeiro 	struct rte_eth_dev *dev = cb_arg;
909198a3c33SNelio Laranjeiro 	struct priv *priv = dev->data->dev_private;
910198a3c33SNelio Laranjeiro 	int ret;
911198a3c33SNelio Laranjeiro 
912198a3c33SNelio Laranjeiro 	(void)intr_handle;
913198a3c33SNelio Laranjeiro 	priv_lock(priv);
914198a3c33SNelio Laranjeiro 	ret = priv_dev_link_status_handler(priv, dev);
915198a3c33SNelio Laranjeiro 	priv_unlock(priv);
916198a3c33SNelio Laranjeiro 	if (ret)
917198a3c33SNelio Laranjeiro 		_rte_eth_dev_callback_process(dev, RTE_ETH_EVENT_INTR_LSC);
918198a3c33SNelio Laranjeiro }
919198a3c33SNelio Laranjeiro 
920198a3c33SNelio Laranjeiro /**
921198a3c33SNelio Laranjeiro  * Uninstall interrupt handler.
922198a3c33SNelio Laranjeiro  *
923198a3c33SNelio Laranjeiro  * @param priv
924198a3c33SNelio Laranjeiro  *   Pointer to private structure.
925198a3c33SNelio Laranjeiro  * @param dev
926198a3c33SNelio Laranjeiro  *   Pointer to the rte_eth_dev structure.
927198a3c33SNelio Laranjeiro  */
928198a3c33SNelio Laranjeiro void
929198a3c33SNelio Laranjeiro priv_dev_interrupt_handler_uninstall(struct priv *priv, struct rte_eth_dev *dev)
930198a3c33SNelio Laranjeiro {
931198a3c33SNelio Laranjeiro 	if (!dev->data->dev_conf.intr_conf.lsc)
932198a3c33SNelio Laranjeiro 		return;
933198a3c33SNelio Laranjeiro 	rte_intr_callback_unregister(&priv->intr_handle,
934198a3c33SNelio Laranjeiro 				     mlx5_dev_interrupt_handler,
935198a3c33SNelio Laranjeiro 				     dev);
936198a3c33SNelio Laranjeiro 	if (priv->pending_alarm)
937198a3c33SNelio Laranjeiro 		rte_eal_alarm_cancel(mlx5_dev_link_status_handler, dev);
938198a3c33SNelio Laranjeiro 	priv->pending_alarm = 0;
939198a3c33SNelio Laranjeiro 	priv->intr_handle.fd = 0;
940198a3c33SNelio Laranjeiro 	priv->intr_handle.type = 0;
941198a3c33SNelio Laranjeiro }
942198a3c33SNelio Laranjeiro 
943198a3c33SNelio Laranjeiro /**
944198a3c33SNelio Laranjeiro  * Install interrupt handler.
945198a3c33SNelio Laranjeiro  *
946198a3c33SNelio Laranjeiro  * @param priv
947198a3c33SNelio Laranjeiro  *   Pointer to private structure.
948198a3c33SNelio Laranjeiro  * @param dev
949198a3c33SNelio Laranjeiro  *   Pointer to the rte_eth_dev structure.
950198a3c33SNelio Laranjeiro  */
951198a3c33SNelio Laranjeiro void
952198a3c33SNelio Laranjeiro priv_dev_interrupt_handler_install(struct priv *priv, struct rte_eth_dev *dev)
953198a3c33SNelio Laranjeiro {
954198a3c33SNelio Laranjeiro 	int rc, flags;
955198a3c33SNelio Laranjeiro 
956198a3c33SNelio Laranjeiro 	if (!dev->data->dev_conf.intr_conf.lsc)
957198a3c33SNelio Laranjeiro 		return;
958198a3c33SNelio Laranjeiro 	assert(priv->ctx->async_fd > 0);
959198a3c33SNelio Laranjeiro 	flags = fcntl(priv->ctx->async_fd, F_GETFL);
960198a3c33SNelio Laranjeiro 	rc = fcntl(priv->ctx->async_fd, F_SETFL, flags | O_NONBLOCK);
961198a3c33SNelio Laranjeiro 	if (rc < 0) {
962198a3c33SNelio Laranjeiro 		INFO("failed to change file descriptor async event queue");
963198a3c33SNelio Laranjeiro 		dev->data->dev_conf.intr_conf.lsc = 0;
964198a3c33SNelio Laranjeiro 	} else {
965198a3c33SNelio Laranjeiro 		priv->intr_handle.fd = priv->ctx->async_fd;
966198a3c33SNelio Laranjeiro 		priv->intr_handle.type = RTE_INTR_HANDLE_EXT;
967198a3c33SNelio Laranjeiro 		rte_intr_callback_register(&priv->intr_handle,
968198a3c33SNelio Laranjeiro 					   mlx5_dev_interrupt_handler,
969198a3c33SNelio Laranjeiro 					   dev);
970198a3c33SNelio Laranjeiro 	}
971198a3c33SNelio Laranjeiro }
972