xref: /dpdk/drivers/net/mlx5/mlx5_ethdev.c (revision ecc1c29df8564d4e880e9b5946114763424cf60c)
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright 2015 6WIND S.A.
5  *   Copyright 2015 Mellanox.
6  *
7  *   Redistribution and use in source and binary forms, with or without
8  *   modification, are permitted provided that the following conditions
9  *   are met:
10  *
11  *     * Redistributions of source code must retain the above copyright
12  *       notice, this list of conditions and the following disclaimer.
13  *     * Redistributions in binary form must reproduce the above copyright
14  *       notice, this list of conditions and the following disclaimer in
15  *       the documentation and/or other materials provided with the
16  *       distribution.
17  *     * Neither the name of 6WIND S.A. nor the names of its
18  *       contributors may be used to endorse or promote products derived
19  *       from this software without specific prior written permission.
20  *
21  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 #include <stddef.h>
35 #include <assert.h>
36 #include <unistd.h>
37 #include <stdint.h>
38 #include <stdio.h>
39 #include <string.h>
40 #include <stdlib.h>
41 #include <errno.h>
42 #include <dirent.h>
43 #include <net/if.h>
44 #include <sys/ioctl.h>
45 #include <sys/socket.h>
46 #include <netinet/in.h>
47 #include <linux/if.h>
48 #include <linux/ethtool.h>
49 #include <linux/sockios.h>
50 
51 /* DPDK headers don't like -pedantic. */
52 #ifdef PEDANTIC
53 #pragma GCC diagnostic ignored "-pedantic"
54 #endif
55 #include <rte_atomic.h>
56 #include <rte_ethdev.h>
57 #include <rte_mbuf.h>
58 #include <rte_common.h>
59 #ifdef PEDANTIC
60 #pragma GCC diagnostic error "-pedantic"
61 #endif
62 
63 #include "mlx5.h"
64 #include "mlx5_rxtx.h"
65 #include "mlx5_utils.h"
66 
67 /**
68  * Get interface name from private structure.
69  *
70  * @param[in] priv
71  *   Pointer to private structure.
72  * @param[out] ifname
73  *   Interface name output buffer.
74  *
75  * @return
76  *   0 on success, -1 on failure and errno is set.
77  */
78 int
79 priv_get_ifname(const struct priv *priv, char (*ifname)[IF_NAMESIZE])
80 {
81 	DIR *dir;
82 	struct dirent *dent;
83 	unsigned int dev_type = 0;
84 	unsigned int dev_port_prev = ~0u;
85 	char match[IF_NAMESIZE] = "";
86 
87 	{
88 		MKSTR(path, "%s/device/net", priv->ctx->device->ibdev_path);
89 
90 		dir = opendir(path);
91 		if (dir == NULL)
92 			return -1;
93 	}
94 	while ((dent = readdir(dir)) != NULL) {
95 		char *name = dent->d_name;
96 		FILE *file;
97 		unsigned int dev_port;
98 		int r;
99 
100 		if ((name[0] == '.') &&
101 		    ((name[1] == '\0') ||
102 		     ((name[1] == '.') && (name[2] == '\0'))))
103 			continue;
104 
105 		MKSTR(path, "%s/device/net/%s/%s",
106 		      priv->ctx->device->ibdev_path, name,
107 		      (dev_type ? "dev_id" : "dev_port"));
108 
109 		file = fopen(path, "rb");
110 		if (file == NULL) {
111 			if (errno != ENOENT)
112 				continue;
113 			/*
114 			 * Switch to dev_id when dev_port does not exist as
115 			 * is the case with Linux kernel versions < 3.15.
116 			 */
117 try_dev_id:
118 			match[0] = '\0';
119 			if (dev_type)
120 				break;
121 			dev_type = 1;
122 			dev_port_prev = ~0u;
123 			rewinddir(dir);
124 			continue;
125 		}
126 		r = fscanf(file, (dev_type ? "%x" : "%u"), &dev_port);
127 		fclose(file);
128 		if (r != 1)
129 			continue;
130 		/*
131 		 * Switch to dev_id when dev_port returns the same value for
132 		 * all ports. May happen when using a MOFED release older than
133 		 * 3.0 with a Linux kernel >= 3.15.
134 		 */
135 		if (dev_port == dev_port_prev)
136 			goto try_dev_id;
137 		dev_port_prev = dev_port;
138 		if (dev_port == (priv->port - 1u))
139 			snprintf(match, sizeof(match), "%s", name);
140 	}
141 	closedir(dir);
142 	if (match[0] == '\0')
143 		return -1;
144 	strncpy(*ifname, match, sizeof(*ifname));
145 	return 0;
146 }
147 
148 /**
149  * Read from sysfs entry.
150  *
151  * @param[in] priv
152  *   Pointer to private structure.
153  * @param[in] entry
154  *   Entry name relative to sysfs path.
155  * @param[out] buf
156  *   Data output buffer.
157  * @param size
158  *   Buffer size.
159  *
160  * @return
161  *   0 on success, -1 on failure and errno is set.
162  */
163 static int
164 priv_sysfs_read(const struct priv *priv, const char *entry,
165 		char *buf, size_t size)
166 {
167 	char ifname[IF_NAMESIZE];
168 	FILE *file;
169 	int ret;
170 	int err;
171 
172 	if (priv_get_ifname(priv, &ifname))
173 		return -1;
174 
175 	MKSTR(path, "%s/device/net/%s/%s", priv->ctx->device->ibdev_path,
176 	      ifname, entry);
177 
178 	file = fopen(path, "rb");
179 	if (file == NULL)
180 		return -1;
181 	ret = fread(buf, 1, size, file);
182 	err = errno;
183 	if (((size_t)ret < size) && (ferror(file)))
184 		ret = -1;
185 	else
186 		ret = size;
187 	fclose(file);
188 	errno = err;
189 	return ret;
190 }
191 
192 /**
193  * Write to sysfs entry.
194  *
195  * @param[in] priv
196  *   Pointer to private structure.
197  * @param[in] entry
198  *   Entry name relative to sysfs path.
199  * @param[in] buf
200  *   Data buffer.
201  * @param size
202  *   Buffer size.
203  *
204  * @return
205  *   0 on success, -1 on failure and errno is set.
206  */
207 static int
208 priv_sysfs_write(const struct priv *priv, const char *entry,
209 		 char *buf, size_t size)
210 {
211 	char ifname[IF_NAMESIZE];
212 	FILE *file;
213 	int ret;
214 	int err;
215 
216 	if (priv_get_ifname(priv, &ifname))
217 		return -1;
218 
219 	MKSTR(path, "%s/device/net/%s/%s", priv->ctx->device->ibdev_path,
220 	      ifname, entry);
221 
222 	file = fopen(path, "wb");
223 	if (file == NULL)
224 		return -1;
225 	ret = fwrite(buf, 1, size, file);
226 	err = errno;
227 	if (((size_t)ret < size) || (ferror(file)))
228 		ret = -1;
229 	else
230 		ret = size;
231 	fclose(file);
232 	errno = err;
233 	return ret;
234 }
235 
236 /**
237  * Get unsigned long sysfs property.
238  *
239  * @param priv
240  *   Pointer to private structure.
241  * @param[in] name
242  *   Entry name relative to sysfs path.
243  * @param[out] value
244  *   Value output buffer.
245  *
246  * @return
247  *   0 on success, -1 on failure and errno is set.
248  */
249 static int
250 priv_get_sysfs_ulong(struct priv *priv, const char *name, unsigned long *value)
251 {
252 	int ret;
253 	unsigned long value_ret;
254 	char value_str[32];
255 
256 	ret = priv_sysfs_read(priv, name, value_str, (sizeof(value_str) - 1));
257 	if (ret == -1) {
258 		DEBUG("cannot read %s value from sysfs: %s",
259 		      name, strerror(errno));
260 		return -1;
261 	}
262 	value_str[ret] = '\0';
263 	errno = 0;
264 	value_ret = strtoul(value_str, NULL, 0);
265 	if (errno) {
266 		DEBUG("invalid %s value `%s': %s", name, value_str,
267 		      strerror(errno));
268 		return -1;
269 	}
270 	*value = value_ret;
271 	return 0;
272 }
273 
274 /**
275  * Set unsigned long sysfs property.
276  *
277  * @param priv
278  *   Pointer to private structure.
279  * @param[in] name
280  *   Entry name relative to sysfs path.
281  * @param value
282  *   Value to set.
283  *
284  * @return
285  *   0 on success, -1 on failure and errno is set.
286  */
287 static int
288 priv_set_sysfs_ulong(struct priv *priv, const char *name, unsigned long value)
289 {
290 	int ret;
291 	MKSTR(value_str, "%lu", value);
292 
293 	ret = priv_sysfs_write(priv, name, value_str, (sizeof(value_str) - 1));
294 	if (ret == -1) {
295 		DEBUG("cannot write %s `%s' (%lu) to sysfs: %s",
296 		      name, value_str, value, strerror(errno));
297 		return -1;
298 	}
299 	return 0;
300 }
301 
302 /**
303  * Perform ifreq ioctl() on associated Ethernet device.
304  *
305  * @param[in] priv
306  *   Pointer to private structure.
307  * @param req
308  *   Request number to pass to ioctl().
309  * @param[out] ifr
310  *   Interface request structure output buffer.
311  *
312  * @return
313  *   0 on success, -1 on failure and errno is set.
314  */
315 int
316 priv_ifreq(const struct priv *priv, int req, struct ifreq *ifr)
317 {
318 	int sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
319 	int ret = -1;
320 
321 	if (sock == -1)
322 		return ret;
323 	if (priv_get_ifname(priv, &ifr->ifr_name) == 0)
324 		ret = ioctl(sock, req, ifr);
325 	close(sock);
326 	return ret;
327 }
328 
329 /**
330  * Get device MTU.
331  *
332  * @param priv
333  *   Pointer to private structure.
334  * @param[out] mtu
335  *   MTU value output buffer.
336  *
337  * @return
338  *   0 on success, -1 on failure and errno is set.
339  */
340 int
341 priv_get_mtu(struct priv *priv, uint16_t *mtu)
342 {
343 	unsigned long ulong_mtu;
344 
345 	if (priv_get_sysfs_ulong(priv, "mtu", &ulong_mtu) == -1)
346 		return -1;
347 	*mtu = ulong_mtu;
348 	return 0;
349 }
350 
351 /**
352  * Set device MTU.
353  *
354  * @param priv
355  *   Pointer to private structure.
356  * @param mtu
357  *   MTU value to set.
358  *
359  * @return
360  *   0 on success, -1 on failure and errno is set.
361  */
362 static int
363 priv_set_mtu(struct priv *priv, uint16_t mtu)
364 {
365 	return priv_set_sysfs_ulong(priv, "mtu", mtu);
366 }
367 
368 /**
369  * Set device flags.
370  *
371  * @param priv
372  *   Pointer to private structure.
373  * @param keep
374  *   Bitmask for flags that must remain untouched.
375  * @param flags
376  *   Bitmask for flags to modify.
377  *
378  * @return
379  *   0 on success, -1 on failure and errno is set.
380  */
381 int
382 priv_set_flags(struct priv *priv, unsigned int keep, unsigned int flags)
383 {
384 	unsigned long tmp;
385 
386 	if (priv_get_sysfs_ulong(priv, "flags", &tmp) == -1)
387 		return -1;
388 	tmp &= keep;
389 	tmp |= flags;
390 	return priv_set_sysfs_ulong(priv, "flags", tmp);
391 }
392 
393 /**
394  * Ethernet device configuration.
395  *
396  * Prepare the driver for a given number of TX and RX queues.
397  *
398  * @param dev
399  *   Pointer to Ethernet device structure.
400  *
401  * @return
402  *   0 on success, errno value on failure.
403  */
404 static int
405 dev_configure(struct rte_eth_dev *dev)
406 {
407 	struct priv *priv = dev->data->dev_private;
408 	unsigned int rxqs_n = dev->data->nb_rx_queues;
409 	unsigned int txqs_n = dev->data->nb_tx_queues;
410 
411 	priv->rxqs = (void *)dev->data->rx_queues;
412 	priv->txqs = (void *)dev->data->tx_queues;
413 	if (txqs_n != priv->txqs_n) {
414 		INFO("%p: TX queues number update: %u -> %u",
415 		     (void *)dev, priv->txqs_n, txqs_n);
416 		priv->txqs_n = txqs_n;
417 	}
418 	if (rxqs_n == priv->rxqs_n)
419 		return 0;
420 	INFO("%p: RX queues number update: %u -> %u",
421 	     (void *)dev, priv->rxqs_n, rxqs_n);
422 	priv->rxqs_n = rxqs_n;
423 	return 0;
424 }
425 
426 /**
427  * DPDK callback for Ethernet device configuration.
428  *
429  * @param dev
430  *   Pointer to Ethernet device structure.
431  *
432  * @return
433  *   0 on success, negative errno value on failure.
434  */
435 int
436 mlx5_dev_configure(struct rte_eth_dev *dev)
437 {
438 	struct priv *priv = dev->data->dev_private;
439 	int ret;
440 
441 	priv_lock(priv);
442 	ret = dev_configure(dev);
443 	assert(ret >= 0);
444 	priv_unlock(priv);
445 	return -ret;
446 }
447 
448 /**
449  * DPDK callback to get information about the device.
450  *
451  * @param dev
452  *   Pointer to Ethernet device structure.
453  * @param[out] info
454  *   Info structure output buffer.
455  */
456 void
457 mlx5_dev_infos_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *info)
458 {
459 	struct priv *priv = dev->data->dev_private;
460 	unsigned int max;
461 	char ifname[IF_NAMESIZE];
462 
463 	priv_lock(priv);
464 	/* FIXME: we should ask the device for these values. */
465 	info->min_rx_bufsize = 32;
466 	info->max_rx_pktlen = 65536;
467 	/*
468 	 * Since we need one CQ per QP, the limit is the minimum number
469 	 * between the two values.
470 	 */
471 	max = ((priv->device_attr.max_cq > priv->device_attr.max_qp) ?
472 	       priv->device_attr.max_qp : priv->device_attr.max_cq);
473 	/* If max >= 65535 then max = 0, max_rx_queues is uint16_t. */
474 	if (max >= 65535)
475 		max = 65535;
476 	info->max_rx_queues = max;
477 	info->max_tx_queues = max;
478 	/* Last array entry is reserved for broadcast. */
479 	info->max_mac_addrs = (RTE_DIM(priv->mac) - 1);
480 	info->rx_offload_capa =
481 		(priv->hw_csum ?
482 		 (DEV_RX_OFFLOAD_IPV4_CKSUM |
483 		  DEV_RX_OFFLOAD_UDP_CKSUM |
484 		  DEV_RX_OFFLOAD_TCP_CKSUM) :
485 		 0);
486 	info->tx_offload_capa =
487 		(priv->hw_csum ?
488 		 (DEV_TX_OFFLOAD_IPV4_CKSUM |
489 		  DEV_TX_OFFLOAD_UDP_CKSUM |
490 		  DEV_TX_OFFLOAD_TCP_CKSUM) :
491 		 0);
492 	if (priv_get_ifname(priv, &ifname) == 0)
493 		info->if_index = if_nametoindex(ifname);
494 	priv_unlock(priv);
495 }
496 
497 /**
498  * DPDK callback to retrieve physical link information (unlocked version).
499  *
500  * @param dev
501  *   Pointer to Ethernet device structure.
502  * @param wait_to_complete
503  *   Wait for request completion (ignored).
504  */
505 static int
506 mlx5_link_update_unlocked(struct rte_eth_dev *dev, int wait_to_complete)
507 {
508 	struct priv *priv = dev->data->dev_private;
509 	struct ethtool_cmd edata = {
510 		.cmd = ETHTOOL_GSET
511 	};
512 	struct ifreq ifr;
513 	struct rte_eth_link dev_link;
514 	int link_speed = 0;
515 
516 	(void)wait_to_complete;
517 	if (priv_ifreq(priv, SIOCGIFFLAGS, &ifr)) {
518 		WARN("ioctl(SIOCGIFFLAGS) failed: %s", strerror(errno));
519 		return -1;
520 	}
521 	memset(&dev_link, 0, sizeof(dev_link));
522 	dev_link.link_status = ((ifr.ifr_flags & IFF_UP) &&
523 				(ifr.ifr_flags & IFF_RUNNING));
524 	ifr.ifr_data = &edata;
525 	if (priv_ifreq(priv, SIOCETHTOOL, &ifr)) {
526 		WARN("ioctl(SIOCETHTOOL, ETHTOOL_GSET) failed: %s",
527 		     strerror(errno));
528 		return -1;
529 	}
530 	link_speed = ethtool_cmd_speed(&edata);
531 	if (link_speed == -1)
532 		dev_link.link_speed = 0;
533 	else
534 		dev_link.link_speed = link_speed;
535 	dev_link.link_duplex = ((edata.duplex == DUPLEX_HALF) ?
536 				ETH_LINK_HALF_DUPLEX : ETH_LINK_FULL_DUPLEX);
537 	if (memcmp(&dev_link, &dev->data->dev_link, sizeof(dev_link))) {
538 		/* Link status changed. */
539 		dev->data->dev_link = dev_link;
540 		return 0;
541 	}
542 	/* Link status is still the same. */
543 	return -1;
544 }
545 
546 /**
547  * DPDK callback to retrieve physical link information.
548  *
549  * @param dev
550  *   Pointer to Ethernet device structure.
551  * @param wait_to_complete
552  *   Wait for request completion (ignored).
553  */
554 int
555 mlx5_link_update(struct rte_eth_dev *dev, int wait_to_complete)
556 {
557 	struct priv *priv = dev->data->dev_private;
558 	int ret;
559 
560 	priv_lock(priv);
561 	ret = mlx5_link_update_unlocked(dev, wait_to_complete);
562 	priv_unlock(priv);
563 	return ret;
564 }
565 
566 /**
567  * DPDK callback to change the MTU.
568  *
569  * Setting the MTU affects hardware MRU (packets larger than the MTU cannot be
570  * received). Use this as a hint to enable/disable scattered packets support
571  * and improve performance when not needed.
572  * Since failure is not an option, reconfiguring queues on the fly is not
573  * recommended.
574  *
575  * @param dev
576  *   Pointer to Ethernet device structure.
577  * @param in_mtu
578  *   New MTU.
579  *
580  * @return
581  *   0 on success, negative errno value on failure.
582  */
583 int
584 mlx5_dev_set_mtu(struct rte_eth_dev *dev, uint16_t mtu)
585 {
586 	struct priv *priv = dev->data->dev_private;
587 	int ret = 0;
588 	unsigned int i;
589 	uint16_t (*rx_func)(void *, struct rte_mbuf **, uint16_t) =
590 		mlx5_rx_burst;
591 
592 	priv_lock(priv);
593 	/* Set kernel interface MTU first. */
594 	if (priv_set_mtu(priv, mtu)) {
595 		ret = errno;
596 		WARN("cannot set port %u MTU to %u: %s", priv->port, mtu,
597 		     strerror(ret));
598 		goto out;
599 	} else
600 		DEBUG("adapter port %u MTU set to %u", priv->port, mtu);
601 	priv->mtu = mtu;
602 	/* Temporarily replace RX handler with a fake one, assuming it has not
603 	 * been copied elsewhere. */
604 	dev->rx_pkt_burst = removed_rx_burst;
605 	/* Make sure everyone has left mlx5_rx_burst() and uses
606 	 * removed_rx_burst() instead. */
607 	rte_wmb();
608 	usleep(1000);
609 	/* Reconfigure each RX queue. */
610 	for (i = 0; (i != priv->rxqs_n); ++i) {
611 		struct rxq *rxq = (*priv->rxqs)[i];
612 		unsigned int max_frame_len;
613 		int sp;
614 
615 		if (rxq == NULL)
616 			continue;
617 		/* Calculate new maximum frame length according to MTU and
618 		 * toggle scattered support (sp) if necessary. */
619 		max_frame_len = (priv->mtu + ETHER_HDR_LEN +
620 				 (ETHER_MAX_VLAN_FRAME_LEN - ETHER_MAX_LEN));
621 		sp = (max_frame_len > (rxq->mb_len - RTE_PKTMBUF_HEADROOM));
622 		/* Provide new values to rxq_setup(). */
623 		dev->data->dev_conf.rxmode.jumbo_frame = sp;
624 		dev->data->dev_conf.rxmode.max_rx_pkt_len = max_frame_len;
625 		ret = rxq_rehash(dev, rxq);
626 		if (ret) {
627 			/* Force SP RX if that queue requires it and abort. */
628 			if (rxq->sp)
629 				rx_func = mlx5_rx_burst_sp;
630 			break;
631 		}
632 		/* Scattered burst function takes priority. */
633 		if (rxq->sp)
634 			rx_func = mlx5_rx_burst_sp;
635 	}
636 	/* Burst functions can now be called again. */
637 	rte_wmb();
638 	dev->rx_pkt_burst = rx_func;
639 out:
640 	priv_unlock(priv);
641 	assert(ret >= 0);
642 	return -ret;
643 }
644 
645 /**
646  * DPDK callback to get flow control status.
647  *
648  * @param dev
649  *   Pointer to Ethernet device structure.
650  * @param[out] fc_conf
651  *   Flow control output buffer.
652  *
653  * @return
654  *   0 on success, negative errno value on failure.
655  */
656 int
657 mlx5_dev_get_flow_ctrl(struct rte_eth_dev *dev, struct rte_eth_fc_conf *fc_conf)
658 {
659 	struct priv *priv = dev->data->dev_private;
660 	struct ifreq ifr;
661 	struct ethtool_pauseparam ethpause = {
662 		.cmd = ETHTOOL_GPAUSEPARAM
663 	};
664 	int ret;
665 
666 	ifr.ifr_data = &ethpause;
667 	priv_lock(priv);
668 	if (priv_ifreq(priv, SIOCETHTOOL, &ifr)) {
669 		ret = errno;
670 		WARN("ioctl(SIOCETHTOOL, ETHTOOL_GPAUSEPARAM)"
671 		     " failed: %s",
672 		     strerror(ret));
673 		goto out;
674 	}
675 
676 	fc_conf->autoneg = ethpause.autoneg;
677 	if (ethpause.rx_pause && ethpause.tx_pause)
678 		fc_conf->mode = RTE_FC_FULL;
679 	else if (ethpause.rx_pause)
680 		fc_conf->mode = RTE_FC_RX_PAUSE;
681 	else if (ethpause.tx_pause)
682 		fc_conf->mode = RTE_FC_TX_PAUSE;
683 	else
684 		fc_conf->mode = RTE_FC_NONE;
685 	ret = 0;
686 
687 out:
688 	priv_unlock(priv);
689 	assert(ret >= 0);
690 	return -ret;
691 }
692 
693 /**
694  * DPDK callback to modify flow control parameters.
695  *
696  * @param dev
697  *   Pointer to Ethernet device structure.
698  * @param[in] fc_conf
699  *   Flow control parameters.
700  *
701  * @return
702  *   0 on success, negative errno value on failure.
703  */
704 int
705 mlx5_dev_set_flow_ctrl(struct rte_eth_dev *dev, struct rte_eth_fc_conf *fc_conf)
706 {
707 	struct priv *priv = dev->data->dev_private;
708 	struct ifreq ifr;
709 	struct ethtool_pauseparam ethpause = {
710 		.cmd = ETHTOOL_SPAUSEPARAM
711 	};
712 	int ret;
713 
714 	ifr.ifr_data = &ethpause;
715 	ethpause.autoneg = fc_conf->autoneg;
716 	if (((fc_conf->mode & RTE_FC_FULL) == RTE_FC_FULL) ||
717 	    (fc_conf->mode & RTE_FC_RX_PAUSE))
718 		ethpause.rx_pause = 1;
719 	else
720 		ethpause.rx_pause = 0;
721 
722 	if (((fc_conf->mode & RTE_FC_FULL) == RTE_FC_FULL) ||
723 	    (fc_conf->mode & RTE_FC_TX_PAUSE))
724 		ethpause.tx_pause = 1;
725 	else
726 		ethpause.tx_pause = 0;
727 
728 	priv_lock(priv);
729 	if (priv_ifreq(priv, SIOCETHTOOL, &ifr)) {
730 		ret = errno;
731 		WARN("ioctl(SIOCETHTOOL, ETHTOOL_SPAUSEPARAM)"
732 		     " failed: %s",
733 		     strerror(ret));
734 		goto out;
735 	}
736 	ret = 0;
737 
738 out:
739 	priv_unlock(priv);
740 	assert(ret >= 0);
741 	return -ret;
742 }
743 
744 /**
745  * Get PCI information from struct ibv_device.
746  *
747  * @param device
748  *   Pointer to Ethernet device structure.
749  * @param[out] pci_addr
750  *   PCI bus address output buffer.
751  *
752  * @return
753  *   0 on success, -1 on failure and errno is set.
754  */
755 int
756 mlx5_ibv_device_to_pci_addr(const struct ibv_device *device,
757 			    struct rte_pci_addr *pci_addr)
758 {
759 	FILE *file;
760 	char line[32];
761 	MKSTR(path, "%s/device/uevent", device->ibdev_path);
762 
763 	file = fopen(path, "rb");
764 	if (file == NULL)
765 		return -1;
766 	while (fgets(line, sizeof(line), file) == line) {
767 		size_t len = strlen(line);
768 		int ret;
769 
770 		/* Truncate long lines. */
771 		if (len == (sizeof(line) - 1))
772 			while (line[(len - 1)] != '\n') {
773 				ret = fgetc(file);
774 				if (ret == EOF)
775 					break;
776 				line[(len - 1)] = ret;
777 			}
778 		/* Extract information. */
779 		if (sscanf(line,
780 			   "PCI_SLOT_NAME="
781 			   "%" SCNx16 ":%" SCNx8 ":%" SCNx8 ".%" SCNx8 "\n",
782 			   &pci_addr->domain,
783 			   &pci_addr->bus,
784 			   &pci_addr->devid,
785 			   &pci_addr->function) == 4) {
786 			ret = 0;
787 			break;
788 		}
789 	}
790 	fclose(file);
791 	return 0;
792 }
793