Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright 2015 6WIND S.A.
3 : : * Copyright 2015 Mellanox Technologies, Ltd
4 : : */
5 : :
6 : : #include <stddef.h>
7 : : #include <inttypes.h>
8 : : #include <unistd.h>
9 : : #include <stdbool.h>
10 : : #include <stdint.h>
11 : : #include <stdio.h>
12 : : #include <string.h>
13 : : #include <stdlib.h>
14 : : #include <errno.h>
15 : : #include <dirent.h>
16 : : #include <net/if.h>
17 : : #include <sys/ioctl.h>
18 : : #include <sys/socket.h>
19 : : #include <netinet/in.h>
20 : : #include <linux/ethtool.h>
21 : : #include <linux/sockios.h>
22 : : #include <fcntl.h>
23 : : #include <stdalign.h>
24 : : #include <sys/un.h>
25 : : #include <time.h>
26 : :
27 : : #include <ethdev_driver.h>
28 : : #include <bus_pci_driver.h>
29 : : #include <rte_mbuf.h>
30 : : #include <rte_common.h>
31 : : #include <rte_eal_paging.h>
32 : : #include <rte_interrupts.h>
33 : : #include <rte_malloc.h>
34 : : #include <rte_string_fns.h>
35 : : #include <rte_rwlock.h>
36 : : #include <rte_cycles.h>
37 : :
38 : : #include <mlx5_glue.h>
39 : : #include <mlx5_devx_cmds.h>
40 : : #include <mlx5_common.h>
41 : : #include <mlx5_malloc.h>
42 : : #include <mlx5_nl.h>
43 : :
44 : : #include "mlx5.h"
45 : : #include "mlx5_rxtx.h"
46 : : #include "mlx5_utils.h"
47 : :
48 : : /* Supported speed values found in /usr/include/linux/ethtool.h */
49 : : #ifndef HAVE_SUPPORTED_40000baseKR4_Full
50 : : #define SUPPORTED_40000baseKR4_Full (1 << 23)
51 : : #endif
52 : : #ifndef HAVE_SUPPORTED_40000baseCR4_Full
53 : : #define SUPPORTED_40000baseCR4_Full (1 << 24)
54 : : #endif
55 : : #ifndef HAVE_SUPPORTED_40000baseSR4_Full
56 : : #define SUPPORTED_40000baseSR4_Full (1 << 25)
57 : : #endif
58 : : #ifndef HAVE_SUPPORTED_40000baseLR4_Full
59 : : #define SUPPORTED_40000baseLR4_Full (1 << 26)
60 : : #endif
61 : : #ifndef HAVE_SUPPORTED_56000baseKR4_Full
62 : : #define SUPPORTED_56000baseKR4_Full (1 << 27)
63 : : #endif
64 : : #ifndef HAVE_SUPPORTED_56000baseCR4_Full
65 : : #define SUPPORTED_56000baseCR4_Full (1 << 28)
66 : : #endif
67 : : #ifndef HAVE_SUPPORTED_56000baseSR4_Full
68 : : #define SUPPORTED_56000baseSR4_Full (1 << 29)
69 : : #endif
70 : : #ifndef HAVE_SUPPORTED_56000baseLR4_Full
71 : : #define SUPPORTED_56000baseLR4_Full (1 << 30)
72 : : #endif
73 : :
74 : : /* Add defines in case the running kernel is not the same as user headers. */
75 : : #ifndef ETHTOOL_GLINKSETTINGS
76 : : struct ethtool_link_settings {
77 : : uint32_t cmd;
78 : : uint32_t speed;
79 : : uint8_t duplex;
80 : : uint8_t port;
81 : : uint8_t phy_address;
82 : : uint8_t autoneg;
83 : : uint8_t mdio_support;
84 : : uint8_t eth_to_mdix;
85 : : uint8_t eth_tp_mdix_ctrl;
86 : : int8_t link_mode_masks_nwords;
87 : : uint32_t reserved[8];
88 : : uint32_t link_mode_masks[];
89 : : };
90 : :
91 : : /* The kernel values can be found in /include/uapi/linux/ethtool.h */
92 : : #define ETHTOOL_GLINKSETTINGS 0x0000004c
93 : : #define ETHTOOL_LINK_MODE_1000baseT_Full_BIT 5
94 : : #define ETHTOOL_LINK_MODE_Autoneg_BIT 6
95 : : #define ETHTOOL_LINK_MODE_1000baseKX_Full_BIT 17
96 : : #define ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT 18
97 : : #define ETHTOOL_LINK_MODE_10000baseKR_Full_BIT 19
98 : : #define ETHTOOL_LINK_MODE_10000baseR_FEC_BIT 20
99 : : #define ETHTOOL_LINK_MODE_20000baseMLD2_Full_BIT 21
100 : : #define ETHTOOL_LINK_MODE_20000baseKR2_Full_BIT 22
101 : : #define ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT 23
102 : : #define ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT 24
103 : : #define ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT 25
104 : : #define ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT 26
105 : : #define ETHTOOL_LINK_MODE_56000baseKR4_Full_BIT 27
106 : : #define ETHTOOL_LINK_MODE_56000baseCR4_Full_BIT 28
107 : : #define ETHTOOL_LINK_MODE_56000baseSR4_Full_BIT 29
108 : : #define ETHTOOL_LINK_MODE_56000baseLR4_Full_BIT 30
109 : : #endif
110 : : #ifndef HAVE_ETHTOOL_LINK_MODE_25G
111 : : #define ETHTOOL_LINK_MODE_25000baseCR_Full_BIT 31
112 : : #define ETHTOOL_LINK_MODE_25000baseKR_Full_BIT 32
113 : : #define ETHTOOL_LINK_MODE_25000baseSR_Full_BIT 33
114 : : #endif
115 : : #ifndef HAVE_ETHTOOL_LINK_MODE_50G
116 : : #define ETHTOOL_LINK_MODE_50000baseCR2_Full_BIT 34
117 : : #define ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT 35
118 : : #endif
119 : : #ifndef HAVE_ETHTOOL_LINK_MODE_100G
120 : : #define ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT 36
121 : : #define ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT 37
122 : : #define ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT 38
123 : : #define ETHTOOL_LINK_MODE_100000baseLR4_ER4_Full_BIT 39
124 : : #endif
125 : : #ifndef HAVE_ETHTOOL_LINK_MODE_200G
126 : : #define ETHTOOL_LINK_MODE_200000baseKR4_Full_BIT 62
127 : : #define ETHTOOL_LINK_MODE_200000baseSR4_Full_BIT 63
128 : : #define ETHTOOL_LINK_MODE_200000baseLR4_ER4_FR4_Full_BIT 0 /* 64 - 64 */
129 : : #define ETHTOOL_LINK_MODE_200000baseDR4_Full_BIT 1 /* 65 - 64 */
130 : : #define ETHTOOL_LINK_MODE_200000baseCR4_Full_BIT 2 /* 66 - 64 */
131 : : #endif
132 : :
133 : : /* Get interface index from SubFunction device name. */
134 : : int
135 : 0 : mlx5_auxiliary_get_ifindex(const char *sf_name)
136 : : {
137 : 0 : char if_name[IF_NAMESIZE] = { 0 };
138 : :
139 [ # # ]: 0 : if (mlx5_auxiliary_get_child_name(sf_name, "/net",
140 : : if_name, sizeof(if_name)) != 0)
141 : 0 : return -rte_errno;
142 : 0 : return if_nametoindex(if_name);
143 : : }
144 : :
145 : : /**
146 : : * Get interface name from private structure.
147 : : *
148 : : * This is a port representor-aware version of mlx5_get_ifname_sysfs().
149 : : *
150 : : * @param[in] dev
151 : : * Pointer to Ethernet device.
152 : : * @param[out] ifname
153 : : * Interface name output buffer.
154 : : *
155 : : * @return
156 : : * 0 on success, a negative errno value otherwise and rte_errno is set.
157 : : */
158 : : int
159 : 0 : mlx5_get_ifname(const struct rte_eth_dev *dev, char (*ifname)[MLX5_NAMESIZE])
160 : : {
161 : 0 : struct mlx5_priv *priv = dev->data->dev_private;
162 : : unsigned int ifindex;
163 : :
164 : : MLX5_ASSERT(priv);
165 : : MLX5_ASSERT(priv->sh);
166 [ # # # # ]: 0 : if (priv->master && priv->sh->bond.ifindex > 0) {
167 : 0 : memcpy(ifname, priv->sh->bond.ifname, MLX5_NAMESIZE);
168 : 0 : return 0;
169 : : }
170 : 0 : ifindex = mlx5_ifindex(dev);
171 [ # # ]: 0 : if (!ifindex) {
172 [ # # ]: 0 : if (!priv->representor)
173 : 0 : return mlx5_get_ifname_sysfs(priv->sh->ibdev_path,
174 : : *ifname);
175 : 0 : rte_errno = ENXIO;
176 : 0 : return -rte_errno;
177 : : }
178 [ # # ]: 0 : if (if_indextoname(ifindex, &(*ifname)[0]))
179 : : return 0;
180 : 0 : rte_errno = errno;
181 : 0 : return -rte_errno;
182 : : }
183 : :
184 : : /**
185 : : * Perform ifreq ioctl() on associated netdev ifname.
186 : : *
187 : : * @param[in] ifname
188 : : * Pointer to netdev name.
189 : : * @param req
190 : : * Request number to pass to ioctl().
191 : : * @param[out] ifr
192 : : * Interface request structure output buffer.
193 : : *
194 : : * @return
195 : : * 0 on success, a negative errno value otherwise and rte_errno is set.
196 : : */
197 : : static int
198 : 0 : mlx5_ifreq_by_ifname(const char *ifname, int req, struct ifreq *ifr)
199 : : {
200 : 0 : int sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
201 : : int ret = 0;
202 : :
203 [ # # ]: 0 : if (sock == -1) {
204 : 0 : rte_errno = errno;
205 : 0 : return -rte_errno;
206 : : }
207 : 0 : rte_strscpy(ifr->ifr_name, ifname, sizeof(ifr->ifr_name));
208 : 0 : ret = ioctl(sock, req, ifr);
209 [ # # ]: 0 : if (ret == -1) {
210 : 0 : rte_errno = errno;
211 : 0 : goto error;
212 : : }
213 : 0 : close(sock);
214 : 0 : return 0;
215 : : error:
216 : 0 : close(sock);
217 : 0 : return -rte_errno;
218 : : }
219 : :
220 : : /**
221 : : * Perform ifreq ioctl() on associated Ethernet device.
222 : : *
223 : : * @param[in] dev
224 : : * Pointer to Ethernet device.
225 : : * @param req
226 : : * Request number to pass to ioctl().
227 : : * @param[out] ifr
228 : : * Interface request structure output buffer.
229 : : *
230 : : * @return
231 : : * 0 on success, a negative errno value otherwise and rte_errno is set.
232 : : */
233 : : static int
234 : 0 : mlx5_ifreq(const struct rte_eth_dev *dev, int req, struct ifreq *ifr)
235 : : {
236 : : char ifname[sizeof(ifr->ifr_name)];
237 : : int ret;
238 : :
239 : 0 : ret = mlx5_get_ifname(dev, &ifname);
240 [ # # ]: 0 : if (ret)
241 : 0 : return -rte_errno;
242 : 0 : return mlx5_ifreq_by_ifname(ifname, req, ifr);
243 : : }
244 : :
245 : : /**
246 : : * Get device MTU.
247 : : *
248 : : * @param dev
249 : : * Pointer to Ethernet device.
250 : : * @param[out] mtu
251 : : * MTU value output buffer.
252 : : *
253 : : * @return
254 : : * 0 on success, a negative errno value otherwise and rte_errno is set.
255 : : */
256 : : int
257 : 0 : mlx5_get_mtu(struct rte_eth_dev *dev, uint16_t *mtu)
258 : : {
259 : : struct ifreq request;
260 : 0 : int ret = mlx5_ifreq(dev, SIOCGIFMTU, &request);
261 : :
262 [ # # ]: 0 : if (ret)
263 : : return ret;
264 : 0 : *mtu = request.ifr_mtu;
265 : 0 : return 0;
266 : : }
267 : :
268 : : /**
269 : : * Set device MTU.
270 : : *
271 : : * @param dev
272 : : * Pointer to Ethernet device.
273 : : * @param mtu
274 : : * MTU value to set.
275 : : *
276 : : * @return
277 : : * 0 on success, a negative errno value otherwise and rte_errno is set.
278 : : */
279 : : int
280 : 0 : mlx5_set_mtu(struct rte_eth_dev *dev, uint16_t mtu)
281 : : {
282 : 0 : struct ifreq request = { .ifr_mtu = mtu, };
283 : :
284 : 0 : return mlx5_ifreq(dev, SIOCSIFMTU, &request);
285 : : }
286 : :
287 : : /**
288 : : * Set device flags.
289 : : *
290 : : * @param dev
291 : : * Pointer to Ethernet device.
292 : : * @param keep
293 : : * Bitmask for flags that must remain untouched.
294 : : * @param flags
295 : : * Bitmask for flags to modify.
296 : : *
297 : : * @return
298 : : * 0 on success, a negative errno value otherwise and rte_errno is set.
299 : : */
300 : : static int
301 : 0 : mlx5_set_flags(struct rte_eth_dev *dev, unsigned int keep, unsigned int flags)
302 : : {
303 : : struct ifreq request;
304 : 0 : int ret = mlx5_ifreq(dev, SIOCGIFFLAGS, &request);
305 : :
306 [ # # ]: 0 : if (ret)
307 : : return ret;
308 : 0 : request.ifr_flags &= keep;
309 : 0 : request.ifr_flags |= flags & ~keep;
310 : 0 : return mlx5_ifreq(dev, SIOCSIFFLAGS, &request);
311 : : }
312 : :
313 : : /**
314 : : * Get device current raw clock counter
315 : : *
316 : : * @param dev
317 : : * Pointer to Ethernet device structure.
318 : : * @param[out] time
319 : : * Current raw clock counter of the device.
320 : : *
321 : : * @return
322 : : * 0 if the clock has correctly been read
323 : : * The value of errno in case of error
324 : : */
325 : : int
326 : 0 : mlx5_read_clock(struct rte_eth_dev *dev, uint64_t *clock)
327 : : {
328 : 0 : struct mlx5_priv *priv = dev->data->dev_private;
329 : 0 : struct ibv_context *ctx = priv->sh->cdev->ctx;
330 : : struct ibv_values_ex values;
331 : : int err = 0;
332 : :
333 : 0 : values.comp_mask = IBV_VALUES_MASK_RAW_CLOCK;
334 : 0 : err = mlx5_glue->query_rt_values_ex(ctx, &values);
335 [ # # ]: 0 : if (err != 0) {
336 : 0 : DRV_LOG(WARNING, "Could not query the clock !");
337 : 0 : return err;
338 : : }
339 : 0 : *clock = values.raw_clock.tv_nsec;
340 : 0 : return 0;
341 : : }
342 : :
343 : : /**
344 : : * Retrieve the master device for representor in the same switch domain.
345 : : *
346 : : * @param dev
347 : : * Pointer to representor Ethernet device structure.
348 : : *
349 : : * @return
350 : : * Master device structure on success, NULL otherwise.
351 : : */
352 : : static struct rte_eth_dev *
353 : 0 : mlx5_find_master_dev(struct rte_eth_dev *dev)
354 : : {
355 : : struct mlx5_priv *priv;
356 : : uint16_t port_id;
357 : : uint16_t domain_id;
358 : :
359 : 0 : priv = dev->data->dev_private;
360 : 0 : domain_id = priv->domain_id;
361 : : MLX5_ASSERT(priv->representor);
362 [ # # ]: 0 : MLX5_ETH_FOREACH_DEV(port_id, dev->device) {
363 : 0 : struct mlx5_priv *opriv =
364 : 0 : rte_eth_devices[port_id].data->dev_private;
365 [ # # # # ]: 0 : if (opriv &&
366 : 0 : opriv->master &&
367 [ # # ]: 0 : opriv->domain_id == domain_id &&
368 [ # # ]: 0 : opriv->sh == priv->sh)
369 : 0 : return &rte_eth_devices[port_id];
370 : : }
371 : : return NULL;
372 : : }
373 : :
374 : : /**
375 : : * DPDK callback to retrieve physical link information.
376 : : *
377 : : * @param dev
378 : : * Pointer to Ethernet device structure.
379 : : * @param[out] link
380 : : * Storage for current link status.
381 : : *
382 : : * @return
383 : : * 0 on success, a negative errno value otherwise and rte_errno is set.
384 : : */
385 : : static int
386 : 0 : mlx5_link_update_unlocked_gset(struct rte_eth_dev *dev,
387 : : struct rte_eth_link *link)
388 : : {
389 : 0 : struct mlx5_priv *priv = dev->data->dev_private;
390 : 0 : struct ethtool_cmd edata = {
391 : : .cmd = ETHTOOL_GSET /* Deprecated since Linux v4.5. */
392 : : };
393 : : struct ifreq ifr;
394 : : struct rte_eth_link dev_link;
395 : : int link_speed = 0;
396 : : int ret;
397 : :
398 : 0 : ret = mlx5_ifreq(dev, SIOCGIFFLAGS, &ifr);
399 [ # # ]: 0 : if (ret) {
400 : 0 : DRV_LOG(WARNING, "port %u ioctl(SIOCGIFFLAGS) failed: %s",
401 : : dev->data->port_id, strerror(rte_errno));
402 : 0 : return ret;
403 : : }
404 : 0 : dev_link = (struct rte_eth_link) {
405 : 0 : .link_status = ((ifr.ifr_flags & IFF_UP) &&
406 : : (ifr.ifr_flags & IFF_RUNNING)),
407 : : };
408 : 0 : ifr = (struct ifreq) {
409 : : .ifr_data = (void *)&edata,
410 : : };
411 : 0 : ret = mlx5_ifreq(dev, SIOCETHTOOL, &ifr);
412 [ # # ]: 0 : if (ret) {
413 [ # # # # ]: 0 : if (ret == -ENOTSUP && priv->representor) {
414 : : struct rte_eth_dev *master;
415 : :
416 : : /*
417 : : * For representors we can try to inherit link
418 : : * settings from the master device. Actually
419 : : * link settings do not make a lot of sense
420 : : * for representors due to missing physical
421 : : * link. The old kernel drivers supported
422 : : * emulated settings query for representors,
423 : : * the new ones do not, so we have to add
424 : : * this code for compatibility issues.
425 : : */
426 : 0 : master = mlx5_find_master_dev(dev);
427 [ # # ]: 0 : if (master) {
428 : 0 : ifr = (struct ifreq) {
429 : : .ifr_data = (void *)&edata,
430 : : };
431 : 0 : ret = mlx5_ifreq(master, SIOCETHTOOL, &ifr);
432 : : }
433 : : }
434 [ # # ]: 0 : if (ret) {
435 : 0 : DRV_LOG(WARNING,
436 : : "port %u ioctl(SIOCETHTOOL,"
437 : : " ETHTOOL_GSET) failed: %s",
438 : : dev->data->port_id, strerror(rte_errno));
439 : 0 : return ret;
440 : : }
441 : : }
442 : : link_speed = ethtool_cmd_speed(&edata);
443 [ # # ]: 0 : if (link_speed == -1)
444 : : dev_link.link_speed = RTE_ETH_SPEED_NUM_UNKNOWN;
445 : : else
446 : : dev_link.link_speed = link_speed;
447 : 0 : priv->link_speed_capa = 0;
448 [ # # ]: 0 : if (edata.supported & (SUPPORTED_1000baseT_Full |
449 : : SUPPORTED_1000baseKX_Full))
450 : 0 : priv->link_speed_capa |= RTE_ETH_LINK_SPEED_1G;
451 [ # # ]: 0 : if (edata.supported & SUPPORTED_10000baseKR_Full)
452 : 0 : priv->link_speed_capa |= RTE_ETH_LINK_SPEED_10G;
453 [ # # ]: 0 : if (edata.supported & (SUPPORTED_40000baseKR4_Full |
454 : : SUPPORTED_40000baseCR4_Full |
455 : : SUPPORTED_40000baseSR4_Full |
456 : : SUPPORTED_40000baseLR4_Full))
457 : 0 : priv->link_speed_capa |= RTE_ETH_LINK_SPEED_40G;
458 : 0 : dev_link.link_duplex = ((edata.duplex == DUPLEX_HALF) ?
459 : 0 : RTE_ETH_LINK_HALF_DUPLEX : RTE_ETH_LINK_FULL_DUPLEX);
460 : 0 : dev_link.link_autoneg = !(dev->data->dev_conf.link_speeds &
461 : : RTE_ETH_LINK_SPEED_FIXED);
462 : 0 : *link = dev_link;
463 : 0 : return 0;
464 : : }
465 : :
466 : : /**
467 : : * Retrieve physical link information (unlocked version using new ioctl).
468 : : *
469 : : * @param dev
470 : : * Pointer to Ethernet device structure.
471 : : * @param[out] link
472 : : * Storage for current link status.
473 : : *
474 : : * @return
475 : : * 0 on success, a negative errno value otherwise and rte_errno is set.
476 : : */
477 : : static int
478 : 0 : mlx5_link_update_unlocked_gs(struct rte_eth_dev *dev,
479 : : struct rte_eth_link *link)
480 : :
481 : 0 : {
482 : 0 : struct mlx5_priv *priv = dev->data->dev_private;
483 : 0 : struct ethtool_link_settings gcmd = { .cmd = ETHTOOL_GLINKSETTINGS };
484 : : struct ifreq ifr;
485 : : struct rte_eth_link dev_link;
486 : : struct rte_eth_dev *master = NULL;
487 : : uint64_t sc;
488 : : int ret;
489 : :
490 : 0 : ret = mlx5_ifreq(dev, SIOCGIFFLAGS, &ifr);
491 [ # # ]: 0 : if (ret) {
492 : 0 : DRV_LOG(WARNING, "port %u ioctl(SIOCGIFFLAGS) failed: %s",
493 : : dev->data->port_id, strerror(rte_errno));
494 : 0 : return ret;
495 : : }
496 : 0 : dev_link = (struct rte_eth_link) {
497 : 0 : .link_status = ((ifr.ifr_flags & IFF_UP) &&
498 : : (ifr.ifr_flags & IFF_RUNNING)),
499 : : };
500 : 0 : ifr = (struct ifreq) {
501 : : .ifr_data = (void *)&gcmd,
502 : : };
503 : 0 : ret = mlx5_ifreq(dev, SIOCETHTOOL, &ifr);
504 [ # # ]: 0 : if (ret) {
505 [ # # # # ]: 0 : if (ret == -ENOTSUP && priv->representor) {
506 : : /*
507 : : * For representors we can try to inherit link
508 : : * settings from the master device. Actually
509 : : * link settings do not make a lot of sense
510 : : * for representors due to missing physical
511 : : * link. The old kernel drivers supported
512 : : * emulated settings query for representors,
513 : : * the new ones do not, so we have to add
514 : : * this code for compatibility issues.
515 : : */
516 : 0 : master = mlx5_find_master_dev(dev);
517 [ # # ]: 0 : if (master) {
518 : 0 : ifr = (struct ifreq) {
519 : : .ifr_data = (void *)&gcmd,
520 : : };
521 : 0 : ret = mlx5_ifreq(master, SIOCETHTOOL, &ifr);
522 : : }
523 : : }
524 [ # # ]: 0 : if (ret) {
525 : 0 : DRV_LOG(DEBUG,
526 : : "port %u ioctl(SIOCETHTOOL,"
527 : : " ETHTOOL_GLINKSETTINGS) failed: %s",
528 : : dev->data->port_id, strerror(rte_errno));
529 : 0 : return ret;
530 : : }
531 : : }
532 : 0 : gcmd.link_mode_masks_nwords = -gcmd.link_mode_masks_nwords;
533 : :
534 : : alignas(struct ethtool_link_settings)
535 : 0 : uint8_t data[offsetof(struct ethtool_link_settings, link_mode_masks) +
536 : 0 : sizeof(uint32_t) * gcmd.link_mode_masks_nwords * 3];
537 : : struct ethtool_link_settings *ecmd = (void *)data;
538 : :
539 : 0 : *ecmd = gcmd;
540 : 0 : ifr.ifr_data = (void *)ecmd;
541 [ # # ]: 0 : ret = mlx5_ifreq(master ? master : dev, SIOCETHTOOL, &ifr);
542 [ # # ]: 0 : if (ret) {
543 : 0 : DRV_LOG(DEBUG,
544 : : "port %u ioctl(SIOCETHTOOL,"
545 : : "ETHTOOL_GLINKSETTINGS) failed: %s",
546 : : dev->data->port_id, strerror(rte_errno));
547 : 0 : return ret;
548 : : }
549 : : dev_link.link_speed = (ecmd->speed == UINT32_MAX) ?
550 : 0 : RTE_ETH_SPEED_NUM_UNKNOWN : ecmd->speed;
551 : 0 : sc = ecmd->link_mode_masks[0] |
552 : 0 : ((uint64_t)ecmd->link_mode_masks[1] << 32);
553 : 0 : priv->link_speed_capa = 0;
554 [ # # ]: 0 : if (sc & (MLX5_BITSHIFT(ETHTOOL_LINK_MODE_1000baseT_Full_BIT) |
555 : : MLX5_BITSHIFT(ETHTOOL_LINK_MODE_1000baseKX_Full_BIT)))
556 : 0 : priv->link_speed_capa |= RTE_ETH_LINK_SPEED_1G;
557 [ # # ]: 0 : if (sc & (MLX5_BITSHIFT(ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT) |
558 : : MLX5_BITSHIFT(ETHTOOL_LINK_MODE_10000baseKR_Full_BIT) |
559 : : MLX5_BITSHIFT(ETHTOOL_LINK_MODE_10000baseR_FEC_BIT)))
560 : 0 : priv->link_speed_capa |= RTE_ETH_LINK_SPEED_10G;
561 [ # # ]: 0 : if (sc & (MLX5_BITSHIFT(ETHTOOL_LINK_MODE_20000baseMLD2_Full_BIT) |
562 : : MLX5_BITSHIFT(ETHTOOL_LINK_MODE_20000baseKR2_Full_BIT)))
563 : 0 : priv->link_speed_capa |= RTE_ETH_LINK_SPEED_20G;
564 [ # # ]: 0 : if (sc & (MLX5_BITSHIFT(ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT) |
565 : : MLX5_BITSHIFT(ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT) |
566 : : MLX5_BITSHIFT(ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT) |
567 : : MLX5_BITSHIFT(ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT)))
568 : 0 : priv->link_speed_capa |= RTE_ETH_LINK_SPEED_40G;
569 [ # # ]: 0 : if (sc & (MLX5_BITSHIFT(ETHTOOL_LINK_MODE_56000baseKR4_Full_BIT) |
570 : : MLX5_BITSHIFT(ETHTOOL_LINK_MODE_56000baseCR4_Full_BIT) |
571 : : MLX5_BITSHIFT(ETHTOOL_LINK_MODE_56000baseSR4_Full_BIT) |
572 : : MLX5_BITSHIFT(ETHTOOL_LINK_MODE_56000baseLR4_Full_BIT)))
573 : 0 : priv->link_speed_capa |= RTE_ETH_LINK_SPEED_56G;
574 [ # # ]: 0 : if (sc & (MLX5_BITSHIFT(ETHTOOL_LINK_MODE_25000baseCR_Full_BIT) |
575 : : MLX5_BITSHIFT(ETHTOOL_LINK_MODE_25000baseKR_Full_BIT) |
576 : : MLX5_BITSHIFT(ETHTOOL_LINK_MODE_25000baseSR_Full_BIT)))
577 : 0 : priv->link_speed_capa |= RTE_ETH_LINK_SPEED_25G;
578 [ # # ]: 0 : if (sc & (MLX5_BITSHIFT(ETHTOOL_LINK_MODE_50000baseCR2_Full_BIT) |
579 : : MLX5_BITSHIFT(ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT)))
580 : 0 : priv->link_speed_capa |= RTE_ETH_LINK_SPEED_50G;
581 [ # # ]: 0 : if (sc & (MLX5_BITSHIFT(ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT) |
582 : : MLX5_BITSHIFT(ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT) |
583 : : MLX5_BITSHIFT(ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT) |
584 : : MLX5_BITSHIFT(ETHTOOL_LINK_MODE_100000baseLR4_ER4_Full_BIT)))
585 : 0 : priv->link_speed_capa |= RTE_ETH_LINK_SPEED_100G;
586 [ # # ]: 0 : if (sc & (MLX5_BITSHIFT(ETHTOOL_LINK_MODE_200000baseKR4_Full_BIT) |
587 : : MLX5_BITSHIFT(ETHTOOL_LINK_MODE_200000baseSR4_Full_BIT)))
588 : 0 : priv->link_speed_capa |= RTE_ETH_LINK_SPEED_200G;
589 : :
590 : 0 : sc = ecmd->link_mode_masks[2] |
591 : 0 : ((uint64_t)ecmd->link_mode_masks[3] << 32);
592 [ # # ]: 0 : if (sc & (MLX5_BITSHIFT(ETHTOOL_LINK_MODE_200000baseCR4_Full_BIT) |
593 : : MLX5_BITSHIFT
594 : : (ETHTOOL_LINK_MODE_200000baseLR4_ER4_FR4_Full_BIT) |
595 : : MLX5_BITSHIFT(ETHTOOL_LINK_MODE_200000baseDR4_Full_BIT)))
596 : 0 : priv->link_speed_capa |= RTE_ETH_LINK_SPEED_200G;
597 : 0 : dev_link.link_duplex = ((ecmd->duplex == DUPLEX_HALF) ?
598 : 0 : RTE_ETH_LINK_HALF_DUPLEX : RTE_ETH_LINK_FULL_DUPLEX);
599 : 0 : dev_link.link_autoneg = !(dev->data->dev_conf.link_speeds &
600 : : RTE_ETH_LINK_SPEED_FIXED);
601 : 0 : *link = dev_link;
602 : 0 : return 0;
603 : : }
604 : :
605 : : /**
606 : : * DPDK callback to retrieve physical link information.
607 : : *
608 : : * @param dev
609 : : * Pointer to Ethernet device structure.
610 : : * @param wait_to_complete
611 : : * Wait for request completion.
612 : : *
613 : : * @return
614 : : * 0 if link status was not updated, positive if it was, a negative errno
615 : : * value otherwise and rte_errno is set.
616 : : */
617 : : int
618 : 0 : mlx5_link_update(struct rte_eth_dev *dev, int wait_to_complete)
619 : : {
620 : : int ret;
621 : : struct rte_eth_link dev_link;
622 : 0 : time_t start_time = time(NULL);
623 : : int retry = MLX5_GET_LINK_STATUS_RETRY_COUNT;
624 : :
625 : : do {
626 : 0 : ret = mlx5_link_update_unlocked_gs(dev, &dev_link);
627 [ # # ]: 0 : if (ret == -ENOTSUP)
628 : 0 : ret = mlx5_link_update_unlocked_gset(dev, &dev_link);
629 [ # # ]: 0 : if (ret == 0)
630 : : break;
631 : : /* Handle wait to complete situation. */
632 [ # # # # ]: 0 : if ((wait_to_complete || retry) && ret == -EAGAIN) {
633 [ # # ]: 0 : if (abs((int)difftime(time(NULL), start_time)) <
634 : : MLX5_LINK_STATUS_TIMEOUT) {
635 : 0 : usleep(0);
636 : 0 : continue;
637 : : } else {
638 : 0 : rte_errno = EBUSY;
639 : 0 : return -rte_errno;
640 : : }
641 [ # # ]: 0 : } else if (ret < 0) {
642 : 0 : return ret;
643 : : }
644 [ # # # # ]: 0 : } while (wait_to_complete || retry-- > 0);
645 : 0 : ret = !!memcmp(&dev->data->dev_link, &dev_link,
646 : : sizeof(struct rte_eth_link));
647 : 0 : dev->data->dev_link = dev_link;
648 : 0 : return ret;
649 : : }
650 : :
651 : : /**
652 : : * DPDK callback to get flow control status.
653 : : *
654 : : * @param dev
655 : : * Pointer to Ethernet device structure.
656 : : * @param[out] fc_conf
657 : : * Flow control output buffer.
658 : : *
659 : : * @return
660 : : * 0 on success, a negative errno value otherwise and rte_errno is set.
661 : : */
662 : : int
663 : 0 : mlx5_dev_get_flow_ctrl(struct rte_eth_dev *dev, struct rte_eth_fc_conf *fc_conf)
664 : : {
665 : : struct ifreq ifr;
666 : 0 : struct ethtool_pauseparam ethpause = {
667 : : .cmd = ETHTOOL_GPAUSEPARAM
668 : : };
669 : : int ret;
670 : :
671 : 0 : ifr.ifr_data = (void *)ðpause;
672 : 0 : ret = mlx5_ifreq(dev, SIOCETHTOOL, &ifr);
673 [ # # ]: 0 : if (ret) {
674 : 0 : DRV_LOG(WARNING,
675 : : "port %u ioctl(SIOCETHTOOL, ETHTOOL_GPAUSEPARAM) failed:"
676 : : " %s",
677 : : dev->data->port_id, strerror(rte_errno));
678 : 0 : return ret;
679 : : }
680 : 0 : fc_conf->autoneg = ethpause.autoneg;
681 [ # # # # ]: 0 : if (ethpause.rx_pause && ethpause.tx_pause)
682 : 0 : fc_conf->mode = RTE_ETH_FC_FULL;
683 [ # # ]: 0 : else if (ethpause.rx_pause)
684 : 0 : fc_conf->mode = RTE_ETH_FC_RX_PAUSE;
685 [ # # ]: 0 : else if (ethpause.tx_pause)
686 : 0 : fc_conf->mode = RTE_ETH_FC_TX_PAUSE;
687 : : else
688 : 0 : fc_conf->mode = RTE_ETH_FC_NONE;
689 : : return 0;
690 : : }
691 : :
692 : : /**
693 : : * DPDK callback to modify flow control parameters.
694 : : *
695 : : * @param dev
696 : : * Pointer to Ethernet device structure.
697 : : * @param[in] fc_conf
698 : : * Flow control parameters.
699 : : *
700 : : * @return
701 : : * 0 on success, a negative errno value otherwise and rte_errno is set.
702 : : */
703 : : int
704 : 0 : mlx5_dev_set_flow_ctrl(struct rte_eth_dev *dev, struct rte_eth_fc_conf *fc_conf)
705 : : {
706 : : struct ifreq ifr;
707 : 0 : struct ethtool_pauseparam ethpause = {
708 : : .cmd = ETHTOOL_SPAUSEPARAM
709 : : };
710 : : int ret;
711 : :
712 : 0 : ifr.ifr_data = (void *)ðpause;
713 : 0 : ethpause.autoneg = fc_conf->autoneg;
714 [ # # ]: 0 : if (((fc_conf->mode & RTE_ETH_FC_FULL) == RTE_ETH_FC_FULL) ||
715 [ # # ]: 0 : (fc_conf->mode & RTE_ETH_FC_RX_PAUSE))
716 : 0 : ethpause.rx_pause = 1;
717 : : else
718 : : ethpause.rx_pause = 0;
719 : :
720 [ # # ]: 0 : if (((fc_conf->mode & RTE_ETH_FC_FULL) == RTE_ETH_FC_FULL) ||
721 [ # # ]: 0 : (fc_conf->mode & RTE_ETH_FC_TX_PAUSE))
722 : 0 : ethpause.tx_pause = 1;
723 : : else
724 : : ethpause.tx_pause = 0;
725 : 0 : ret = mlx5_ifreq(dev, SIOCETHTOOL, &ifr);
726 [ # # ]: 0 : if (ret) {
727 : 0 : DRV_LOG(WARNING,
728 : : "port %u ioctl(SIOCETHTOOL, ETHTOOL_SPAUSEPARAM)"
729 : : " failed: %s",
730 : : dev->data->port_id, strerror(rte_errno));
731 : 0 : return ret;
732 : : }
733 : : return 0;
734 : : }
735 : :
736 : : /**
737 : : * Handle asynchronous removal event for entire multiport device.
738 : : *
739 : : * @param sh
740 : : * Infiniband device shared context.
741 : : */
742 : : static void
743 : 0 : mlx5_dev_interrupt_device_fatal(struct mlx5_dev_ctx_shared *sh)
744 : : {
745 : : uint32_t i;
746 : :
747 [ # # ]: 0 : for (i = 0; i < sh->max_port; ++i) {
748 : : struct rte_eth_dev *dev;
749 : : struct mlx5_priv *priv;
750 : :
751 [ # # ]: 0 : if (sh->port[i].ih_port_id >= RTE_MAX_ETHPORTS) {
752 : : /*
753 : : * Or not existing port either no
754 : : * handler installed for this port.
755 : : */
756 : 0 : continue;
757 : : }
758 : 0 : dev = &rte_eth_devices[sh->port[i].ih_port_id];
759 : : MLX5_ASSERT(dev);
760 : 0 : priv = dev->data->dev_private;
761 : : MLX5_ASSERT(priv);
762 [ # # # # ]: 0 : if (!priv->rmv_notified && dev->data->dev_conf.intr_conf.rmv) {
763 : : /* Notify driver about removal only once. */
764 : 0 : priv->rmv_notified = 1;
765 : 0 : rte_eth_dev_callback_process
766 : : (dev, RTE_ETH_EVENT_INTR_RMV, NULL);
767 : : }
768 : : }
769 : 0 : }
770 : :
771 : : static void
772 : 0 : mlx5_dev_interrupt_nl_cb(struct nlmsghdr *hdr, void *cb_arg)
773 : : {
774 : : struct mlx5_dev_ctx_shared *sh = cb_arg;
775 : : uint32_t i;
776 : : uint32_t if_index;
777 : :
778 [ # # ]: 0 : if (mlx5_nl_parse_link_status_update(hdr, &if_index) < 0)
779 : 0 : return;
780 [ # # ]: 0 : for (i = 0; i < sh->max_port; i++) {
781 : : struct mlx5_dev_shared_port *port = &sh->port[i];
782 : : struct rte_eth_dev *dev;
783 : : struct mlx5_priv *priv;
784 : :
785 [ # # ]: 0 : if (port->nl_ih_port_id >= RTE_MAX_ETHPORTS)
786 : 0 : continue;
787 : 0 : dev = &rte_eth_devices[port->nl_ih_port_id];
788 : : /* Probing may initiate an LSC before configuration is done. */
789 [ # # ]: 0 : if (dev->data->dev_configured &&
790 [ # # ]: 0 : !dev->data->dev_conf.intr_conf.lsc)
791 : : break;
792 : 0 : priv = dev->data->dev_private;
793 [ # # ]: 0 : if (priv->if_index == if_index) {
794 : : /* Block logical LSC events. */
795 : 0 : uint16_t prev_status = dev->data->dev_link.link_status;
796 : :
797 [ # # ]: 0 : if (mlx5_link_update(dev, 0) < 0)
798 : 0 : DRV_LOG(ERR, "Failed to update link status: %s",
799 : : rte_strerror(rte_errno));
800 [ # # ]: 0 : else if (prev_status != dev->data->dev_link.link_status)
801 : 0 : rte_eth_dev_callback_process
802 : : (dev, RTE_ETH_EVENT_INTR_LSC, NULL);
803 : : break;
804 : : }
805 : : }
806 : : }
807 : :
808 : : void
809 : 0 : mlx5_dev_interrupt_handler_nl(void *arg)
810 : : {
811 : : struct mlx5_dev_ctx_shared *sh = arg;
812 : 0 : int nlsk_fd = rte_intr_fd_get(sh->intr_handle_nl);
813 : :
814 [ # # ]: 0 : if (nlsk_fd < 0)
815 : : return;
816 [ # # ]: 0 : if (mlx5_nl_read_events(nlsk_fd, mlx5_dev_interrupt_nl_cb, sh) < 0)
817 : 0 : DRV_LOG(ERR, "Failed to process Netlink events: %s",
818 : : rte_strerror(rte_errno));
819 : : }
820 : :
821 : : /**
822 : : * Handle shared asynchronous events the NIC (removal event
823 : : * and link status change). Supports multiport IB device.
824 : : *
825 : : * @param cb_arg
826 : : * Callback argument.
827 : : */
828 : : void
829 : 0 : mlx5_dev_interrupt_handler(void *cb_arg)
830 : : {
831 : : struct mlx5_dev_ctx_shared *sh = cb_arg;
832 : : struct ibv_async_event event;
833 : :
834 : : /* Read all message from the IB device and acknowledge them. */
835 : : for (;;) {
836 : : struct rte_eth_dev *dev;
837 : : uint32_t tmp;
838 : :
839 [ # # ]: 0 : if (mlx5_glue->get_async_event(sh->cdev->ctx, &event)) {
840 [ # # ]: 0 : if (errno == EIO) {
841 : 0 : DRV_LOG(DEBUG,
842 : : "IBV async event queue closed on: %s",
843 : : sh->ibdev_name);
844 : 0 : mlx5_dev_interrupt_device_fatal(sh);
845 : : }
846 : : break;
847 : : }
848 [ # # ]: 0 : if (event.event_type == IBV_EVENT_DEVICE_FATAL) {
849 : : /*
850 : : * The DEVICE_FATAL event can be called by kernel
851 : : * twice - from mlx5 and uverbs layers, and port
852 : : * index is not applicable. We should notify all
853 : : * existing ports.
854 : : */
855 : 0 : mlx5_dev_interrupt_device_fatal(sh);
856 : 0 : mlx5_glue->ack_async_event(&event);
857 : 0 : continue;
858 : : }
859 : : /* Retrieve and check IB port index. */
860 : 0 : tmp = (uint32_t)event.element.port_num;
861 : : MLX5_ASSERT(tmp <= sh->max_port);
862 [ # # ]: 0 : if (!tmp) {
863 : : /* Unsupported device level event. */
864 : 0 : mlx5_glue->ack_async_event(&event);
865 : 0 : DRV_LOG(DEBUG,
866 : : "unsupported common event (type %d)",
867 : : event.event_type);
868 : 0 : continue;
869 : : }
870 [ # # ]: 0 : if (tmp > sh->max_port) {
871 : : /* Invalid IB port index. */
872 : 0 : mlx5_glue->ack_async_event(&event);
873 : 0 : DRV_LOG(DEBUG,
874 : : "cannot handle an event (type %d)"
875 : : "due to invalid IB port index (%u)",
876 : : event.event_type, tmp);
877 : 0 : continue;
878 : : }
879 [ # # ]: 0 : if (sh->port[tmp - 1].ih_port_id >= RTE_MAX_ETHPORTS) {
880 : : /* No handler installed. */
881 : 0 : mlx5_glue->ack_async_event(&event);
882 : 0 : DRV_LOG(DEBUG,
883 : : "cannot handle an event (type %d)"
884 : : "due to no handler installed for port %u",
885 : : event.event_type, tmp);
886 : 0 : continue;
887 : : }
888 : : /* Retrieve ethernet device descriptor. */
889 : : tmp = sh->port[tmp - 1].ih_port_id;
890 : : dev = &rte_eth_devices[tmp];
891 : : MLX5_ASSERT(dev);
892 : 0 : DRV_LOG(DEBUG,
893 : : "port %u cannot handle an unknown event (type %d)",
894 : : dev->data->port_id, event.event_type);
895 : 0 : mlx5_glue->ack_async_event(&event);
896 : : }
897 : 0 : }
898 : :
899 : : /**
900 : : * Handle DEVX interrupts from the NIC.
901 : : * This function is probably called from the DPDK host thread.
902 : : *
903 : : * @param cb_arg
904 : : * Callback argument.
905 : : */
906 : : void
907 : 0 : mlx5_dev_interrupt_handler_devx(void *cb_arg)
908 : : {
909 : : #ifndef HAVE_IBV_DEVX_ASYNC
910 : : (void)cb_arg;
911 : : return;
912 : : #else
913 : : struct mlx5_dev_ctx_shared *sh = cb_arg;
914 : : union {
915 : : struct mlx5dv_devx_async_cmd_hdr cmd_resp;
916 : : uint8_t buf[MLX5_ST_SZ_BYTES(query_flow_counter_out) +
917 : : MLX5_ST_SZ_BYTES(traffic_counter) +
918 : : sizeof(struct mlx5dv_devx_async_cmd_hdr)];
919 : : } out;
920 : : uint8_t *buf = out.buf + sizeof(out.cmd_resp);
921 : :
922 [ # # ]: 0 : while (!mlx5_glue->devx_get_async_cmd_comp(sh->devx_comp,
923 : : &out.cmd_resp,
924 : : sizeof(out.buf)))
925 : 0 : mlx5_flow_async_pool_query_handle
926 : 0 : (sh, (uint64_t)out.cmd_resp.wr_id,
927 : : mlx5_devx_get_out_command_status(buf));
928 : : #endif /* HAVE_IBV_DEVX_ASYNC */
929 : 0 : }
930 : :
931 : : /**
932 : : * DPDK callback to bring the link DOWN.
933 : : *
934 : : * @param dev
935 : : * Pointer to Ethernet device structure.
936 : : *
937 : : * @return
938 : : * 0 on success, a negative errno value otherwise and rte_errno is set.
939 : : */
940 : : int
941 : 0 : mlx5_set_link_down(struct rte_eth_dev *dev)
942 : : {
943 : 0 : return mlx5_set_flags(dev, ~IFF_UP, ~IFF_UP);
944 : : }
945 : :
946 : : /**
947 : : * DPDK callback to bring the link UP.
948 : : *
949 : : * @param dev
950 : : * Pointer to Ethernet device structure.
951 : : *
952 : : * @return
953 : : * 0 on success, a negative errno value otherwise and rte_errno is set.
954 : : */
955 : : int
956 : 0 : mlx5_set_link_up(struct rte_eth_dev *dev)
957 : : {
958 : 0 : return mlx5_set_flags(dev, ~IFF_UP, IFF_UP);
959 : : }
960 : :
961 : : /**
962 : : * Check if mlx5 device was removed.
963 : : *
964 : : * @param dev
965 : : * Pointer to Ethernet device structure.
966 : : *
967 : : * @return
968 : : * 1 when device is removed, otherwise 0.
969 : : */
970 : : int
971 : 0 : mlx5_is_removed(struct rte_eth_dev *dev)
972 : : {
973 : : struct ibv_device_attr device_attr;
974 : 0 : struct mlx5_priv *priv = dev->data->dev_private;
975 : :
976 [ # # ]: 0 : if (mlx5_glue->query_device(priv->sh->cdev->ctx, &device_attr) == EIO)
977 : 0 : return 1;
978 : : return 0;
979 : : }
980 : :
981 : : /**
982 : : * Analyze gathered port parameters via sysfs to recognize master
983 : : * and representor devices for E-Switch configuration.
984 : : *
985 : : * @param[in] device_dir
986 : : * flag of presence of "device" directory under port device key.
987 : : * @param[inout] switch_info
988 : : * Port information, including port name as a number and port name
989 : : * type if recognized
990 : : *
991 : : * @return
992 : : * master and representor flags are set in switch_info according to
993 : : * recognized parameters (if any).
994 : : */
995 : : static void
996 : : mlx5_sysfs_check_switch_info(bool device_dir,
997 : : struct mlx5_switch_info *switch_info)
998 : : {
999 [ # # # # : 0 : switch (switch_info->name_type) {
# # ]
1000 : 0 : case MLX5_PHYS_PORT_NAME_TYPE_UNKNOWN:
1001 : : /*
1002 : : * Name is not recognized, assume the master,
1003 : : * check the device directory presence.
1004 : : */
1005 : 0 : switch_info->master = device_dir;
1006 : 0 : break;
1007 : 0 : case MLX5_PHYS_PORT_NAME_TYPE_NOTSET:
1008 : : /*
1009 : : * Name is not set, this assumes the legacy naming
1010 : : * schema for master, just check if there is
1011 : : * a device directory.
1012 : : */
1013 : 0 : switch_info->master = device_dir;
1014 : 0 : break;
1015 : 0 : case MLX5_PHYS_PORT_NAME_TYPE_UPLINK:
1016 : : /* New uplink naming schema recognized. */
1017 : 0 : switch_info->master = 1;
1018 : 0 : break;
1019 : 0 : case MLX5_PHYS_PORT_NAME_TYPE_LEGACY:
1020 : : /* Legacy representors naming schema. */
1021 : 0 : switch_info->representor = !device_dir;
1022 : 0 : break;
1023 : 0 : case MLX5_PHYS_PORT_NAME_TYPE_PFHPF:
1024 : : /* Fallthrough */
1025 : : case MLX5_PHYS_PORT_NAME_TYPE_PFVF:
1026 : : /* Fallthrough */
1027 : : case MLX5_PHYS_PORT_NAME_TYPE_PFSF:
1028 : : /* New representors naming schema. */
1029 : 0 : switch_info->representor = 1;
1030 : 0 : break;
1031 : 0 : default:
1032 : 0 : switch_info->master = device_dir;
1033 : 0 : break;
1034 : : }
1035 : : }
1036 : :
1037 : : /**
1038 : : * Get switch information associated with network interface.
1039 : : *
1040 : : * @param ifindex
1041 : : * Network interface index.
1042 : : * @param[out] info
1043 : : * Switch information object, populated in case of success.
1044 : : *
1045 : : * @return
1046 : : * 0 on success, a negative errno value otherwise and rte_errno is set.
1047 : : */
1048 : : int
1049 : 0 : mlx5_sysfs_switch_info(unsigned int ifindex, struct mlx5_switch_info *info)
1050 : 0 : {
1051 : : char ifname[IF_NAMESIZE];
1052 : 0 : char *port_name = NULL;
1053 : 0 : size_t port_name_size = 0;
1054 : : FILE *file;
1055 : 0 : struct mlx5_switch_info data = {
1056 : : .master = 0,
1057 : : .representor = 0,
1058 : : .name_type = MLX5_PHYS_PORT_NAME_TYPE_NOTSET,
1059 : : .port_name = 0,
1060 : : .switch_id = 0,
1061 : : };
1062 : : DIR *dir;
1063 : : bool port_switch_id_set = false;
1064 : : bool device_dir = false;
1065 : : char c;
1066 : : ssize_t line_size;
1067 : :
1068 [ # # ]: 0 : if (!if_indextoname(ifindex, ifname)) {
1069 : 0 : rte_errno = errno;
1070 : 0 : return -rte_errno;
1071 : : }
1072 : :
1073 : 0 : MKSTR(phys_port_name, "/sys/class/net/%s/phys_port_name",
1074 : : ifname);
1075 : 0 : MKSTR(phys_switch_id, "/sys/class/net/%s/phys_switch_id",
1076 : : ifname);
1077 : 0 : MKSTR(pci_device, "/sys/class/net/%s/device",
1078 : : ifname);
1079 : :
1080 : 0 : file = fopen(phys_port_name, "rb");
1081 [ # # ]: 0 : if (file != NULL) {
1082 : : char *tail_nl;
1083 : :
1084 : : line_size = getline(&port_name, &port_name_size, file);
1085 [ # # ]: 0 : if (line_size < 0) {
1086 : 0 : free(port_name);
1087 : 0 : fclose(file);
1088 : 0 : rte_errno = errno;
1089 : 0 : return -rte_errno;
1090 [ # # ]: 0 : } else if (line_size > 0) {
1091 : : /* Remove tailing newline character. */
1092 : 0 : tail_nl = strchr(port_name, '\n');
1093 [ # # ]: 0 : if (tail_nl)
1094 : 0 : *tail_nl = '\0';
1095 : 0 : mlx5_translate_port_name(port_name, &data);
1096 : : }
1097 : 0 : free(port_name);
1098 : 0 : fclose(file);
1099 : : }
1100 : 0 : file = fopen(phys_switch_id, "rb");
1101 [ # # ]: 0 : if (file == NULL) {
1102 : 0 : rte_errno = errno;
1103 : 0 : return -rte_errno;
1104 : : }
1105 : 0 : port_switch_id_set =
1106 [ # # ]: 0 : fscanf(file, "%" SCNx64 "%c", &data.switch_id, &c) == 2 &&
1107 [ # # ]: 0 : c == '\n';
1108 : 0 : fclose(file);
1109 : 0 : dir = opendir(pci_device);
1110 [ # # ]: 0 : if (dir != NULL) {
1111 : 0 : closedir(dir);
1112 : : device_dir = true;
1113 : : }
1114 [ # # ]: 0 : if (port_switch_id_set) {
1115 : : /* We have some E-Switch configuration. */
1116 : : mlx5_sysfs_check_switch_info(device_dir, &data);
1117 : : }
1118 : 0 : *info = data;
1119 : : MLX5_ASSERT(!(data.master && data.representor));
1120 [ # # ]: 0 : if (data.master && data.representor) {
1121 : 0 : DRV_LOG(ERR, "ifindex %u device is recognized as master"
1122 : : " and as representor", ifindex);
1123 : 0 : rte_errno = ENODEV;
1124 : 0 : return -rte_errno;
1125 : : }
1126 : : return 0;
1127 : : }
1128 : :
1129 : : /**
1130 : : * Get bond information associated with network interface.
1131 : : *
1132 : : * @param pf_ifindex
1133 : : * Network interface index of bond slave interface
1134 : : * @param[out] ifindex
1135 : : * Pointer to bond ifindex.
1136 : : * @param[out] ifname
1137 : : * Pointer to bond ifname.
1138 : : *
1139 : : * @return
1140 : : * 0 on success, a negative errno value otherwise and rte_errno is set.
1141 : : */
1142 : : int
1143 : 0 : mlx5_sysfs_bond_info(unsigned int pf_ifindex, unsigned int *ifindex,
1144 : : char *ifname)
1145 : 0 : {
1146 : : char name[IF_NAMESIZE];
1147 : : FILE *file;
1148 : : unsigned int index;
1149 : : int ret;
1150 : :
1151 [ # # # # ]: 0 : if (!if_indextoname(pf_ifindex, name) || !strlen(name)) {
1152 : 0 : rte_errno = errno;
1153 : 0 : return -rte_errno;
1154 : : }
1155 : 0 : MKSTR(bond_if, "/sys/class/net/%s/master/ifindex", name);
1156 : : /* read bond ifindex */
1157 : 0 : file = fopen(bond_if, "rb");
1158 [ # # ]: 0 : if (file == NULL) {
1159 : 0 : rte_errno = errno;
1160 : 0 : return -rte_errno;
1161 : : }
1162 : 0 : ret = fscanf(file, "%u", &index);
1163 : 0 : fclose(file);
1164 [ # # ]: 0 : if (ret <= 0) {
1165 : 0 : rte_errno = errno;
1166 : 0 : return -rte_errno;
1167 : : }
1168 [ # # ]: 0 : if (ifindex)
1169 : 0 : *ifindex = index;
1170 : :
1171 : : /* read bond device name from symbol link */
1172 [ # # ]: 0 : if (ifname) {
1173 [ # # ]: 0 : if (!if_indextoname(index, ifname)) {
1174 : 0 : rte_errno = errno;
1175 : 0 : return -rte_errno;
1176 : : }
1177 : : }
1178 : : return 0;
1179 : : }
1180 : :
1181 : : /**
1182 : : * DPDK callback to retrieve plug-in module EEPROM information (type and size).
1183 : : *
1184 : : * @param dev
1185 : : * Pointer to Ethernet device structure.
1186 : : * @param[out] modinfo
1187 : : * Storage for plug-in module EEPROM information.
1188 : : *
1189 : : * @return
1190 : : * 0 on success, a negative errno value otherwise and rte_errno is set.
1191 : : */
1192 : : int
1193 : 0 : mlx5_get_module_info(struct rte_eth_dev *dev,
1194 : : struct rte_eth_dev_module_info *modinfo)
1195 : : {
1196 : 0 : struct ethtool_modinfo info = {
1197 : : .cmd = ETHTOOL_GMODULEINFO,
1198 : : };
1199 : 0 : struct ifreq ifr = (struct ifreq) {
1200 : : .ifr_data = (void *)&info,
1201 : : };
1202 : : int ret = 0;
1203 : :
1204 [ # # ]: 0 : if (!dev) {
1205 : 0 : DRV_LOG(WARNING, "missing argument, cannot get module info");
1206 : 0 : rte_errno = EINVAL;
1207 : 0 : return -rte_errno;
1208 : : }
1209 : 0 : ret = mlx5_ifreq(dev, SIOCETHTOOL, &ifr);
1210 [ # # ]: 0 : if (ret) {
1211 : 0 : DRV_LOG(WARNING, "port %u ioctl(SIOCETHTOOL) failed: %s",
1212 : : dev->data->port_id, strerror(rte_errno));
1213 : 0 : return ret;
1214 : : }
1215 : 0 : modinfo->type = info.type;
1216 : 0 : modinfo->eeprom_len = info.eeprom_len;
1217 : 0 : return ret;
1218 : : }
1219 : :
1220 : : /**
1221 : : * DPDK callback to retrieve plug-in module EEPROM data.
1222 : : *
1223 : : * @param dev
1224 : : * Pointer to Ethernet device structure.
1225 : : * @param[out] info
1226 : : * Storage for plug-in module EEPROM data.
1227 : : *
1228 : : * @return
1229 : : * 0 on success, a negative errno value otherwise and rte_errno is set.
1230 : : */
1231 : 0 : int mlx5_get_module_eeprom(struct rte_eth_dev *dev,
1232 : : struct rte_dev_eeprom_info *info)
1233 : : {
1234 : : struct ethtool_eeprom *eeprom;
1235 : : struct ifreq ifr;
1236 : : int ret = 0;
1237 : :
1238 [ # # ]: 0 : if (!dev) {
1239 : 0 : DRV_LOG(WARNING, "missing argument, cannot get module eeprom");
1240 : 0 : rte_errno = EINVAL;
1241 : 0 : return -rte_errno;
1242 : : }
1243 : 0 : eeprom = mlx5_malloc(MLX5_MEM_ZERO,
1244 : 0 : (sizeof(struct ethtool_eeprom) + info->length), 0,
1245 : : SOCKET_ID_ANY);
1246 [ # # ]: 0 : if (!eeprom) {
1247 : 0 : DRV_LOG(WARNING, "port %u cannot allocate memory for "
1248 : : "eeprom data", dev->data->port_id);
1249 : 0 : rte_errno = ENOMEM;
1250 : 0 : return -rte_errno;
1251 : : }
1252 : 0 : eeprom->cmd = ETHTOOL_GMODULEEEPROM;
1253 : 0 : eeprom->offset = info->offset;
1254 : 0 : eeprom->len = info->length;
1255 : 0 : ifr = (struct ifreq) {
1256 : : .ifr_data = (void *)eeprom,
1257 : : };
1258 : 0 : ret = mlx5_ifreq(dev, SIOCETHTOOL, &ifr);
1259 [ # # ]: 0 : if (ret)
1260 : 0 : DRV_LOG(WARNING, "port %u ioctl(SIOCETHTOOL) failed: %s",
1261 : : dev->data->port_id, strerror(rte_errno));
1262 : : else
1263 [ # # ]: 0 : rte_memcpy(info->data, eeprom->data, info->length);
1264 : 0 : mlx5_free(eeprom);
1265 : 0 : return ret;
1266 : : }
1267 : :
1268 : : /**
1269 : : * Read device counters table.
1270 : : *
1271 : : * @param dev
1272 : : * Pointer to Ethernet device.
1273 : : * @param[in] pf
1274 : : * PF index in case of bonding device, -1 otherwise
1275 : : * @param[out] stats
1276 : : * Counters table output buffer.
1277 : : *
1278 : : * @return
1279 : : * 0 on success and stats is filled, negative errno value otherwise and
1280 : : * rte_errno is set.
1281 : : */
1282 : : static int
1283 : 0 : _mlx5_os_read_dev_counters(struct rte_eth_dev *dev, int pf, uint64_t *stats)
1284 : 0 : {
1285 : 0 : struct mlx5_priv *priv = dev->data->dev_private;
1286 : : struct mlx5_xstats_ctrl *xstats_ctrl = &priv->xstats_ctrl;
1287 : : unsigned int i;
1288 : : struct ifreq ifr;
1289 : 0 : unsigned int stats_sz = xstats_ctrl->stats_n * sizeof(uint64_t);
1290 : 0 : unsigned char et_stat_buf[sizeof(struct ethtool_stats) + stats_sz];
1291 : : struct ethtool_stats *et_stats = (struct ethtool_stats *)et_stat_buf;
1292 : : int ret;
1293 : :
1294 : 0 : et_stats->cmd = ETHTOOL_GSTATS;
1295 : 0 : et_stats->n_stats = xstats_ctrl->stats_n;
1296 : 0 : ifr.ifr_data = (caddr_t)et_stats;
1297 [ # # ]: 0 : if (pf >= 0)
1298 : 0 : ret = mlx5_ifreq_by_ifname(priv->sh->bond.ports[pf].ifname,
1299 : : SIOCETHTOOL, &ifr);
1300 : : else
1301 : 0 : ret = mlx5_ifreq(dev, SIOCETHTOOL, &ifr);
1302 [ # # ]: 0 : if (ret) {
1303 : 0 : DRV_LOG(WARNING,
1304 : : "port %u unable to read statistic values from device",
1305 : : dev->data->port_id);
1306 : 0 : return ret;
1307 : : }
1308 [ # # ]: 0 : for (i = 0; i != xstats_ctrl->mlx5_stats_n; ++i) {
1309 [ # # ]: 0 : if (xstats_ctrl->info[i].dev)
1310 : 0 : continue;
1311 : 0 : stats[i] += (uint64_t)
1312 : 0 : et_stats->data[xstats_ctrl->dev_table_idx[i]];
1313 : : }
1314 : : return 0;
1315 : : }
1316 : :
1317 : : /**
1318 : : * Read device counters.
1319 : : *
1320 : : * @param dev
1321 : : * Pointer to Ethernet device.
1322 : : * @param[out] stats
1323 : : * Counters table output buffer.
1324 : : *
1325 : : * @return
1326 : : * 0 on success and stats is filled, negative errno value otherwise and
1327 : : * rte_errno is set.
1328 : : */
1329 : : int
1330 : 0 : mlx5_os_read_dev_counters(struct rte_eth_dev *dev, uint64_t *stats)
1331 : : {
1332 : 0 : struct mlx5_priv *priv = dev->data->dev_private;
1333 : : struct mlx5_xstats_ctrl *xstats_ctrl = &priv->xstats_ctrl;
1334 : : int ret = 0, i;
1335 : :
1336 [ # # ]: 0 : memset(stats, 0, sizeof(*stats) * xstats_ctrl->mlx5_stats_n);
1337 : : /* Read ifreq counters. */
1338 [ # # # # ]: 0 : if (priv->master && priv->pf_bond >= 0) {
1339 : : /* Sum xstats from bonding device member ports. */
1340 [ # # ]: 0 : for (i = 0; i < priv->sh->bond.n_port; i++) {
1341 : 0 : ret = _mlx5_os_read_dev_counters(dev, i, stats);
1342 [ # # ]: 0 : if (ret)
1343 : 0 : return ret;
1344 : : }
1345 : : } else {
1346 : 0 : ret = _mlx5_os_read_dev_counters(dev, -1, stats);
1347 [ # # ]: 0 : if (ret)
1348 : : return ret;
1349 : : }
1350 : : /* Read IB counters. */
1351 [ # # ]: 0 : for (i = 0; i != xstats_ctrl->mlx5_stats_n; ++i) {
1352 [ # # ]: 0 : if (!xstats_ctrl->info[i].dev)
1353 : 0 : continue;
1354 : : /* return last xstats counter if fail to read. */
1355 [ # # ]: 0 : if (mlx5_os_read_dev_stat(priv, xstats_ctrl->info[i].ctr_name,
1356 : 0 : &stats[i]) == 0)
1357 : 0 : xstats_ctrl->xstats[i] = stats[i];
1358 : : else
1359 : 0 : stats[i] = xstats_ctrl->xstats[i];
1360 : : }
1361 : : return ret;
1362 : : }
1363 : :
1364 : : /**
1365 : : * Query the number of statistics provided by ETHTOOL.
1366 : : *
1367 : : * @param dev
1368 : : * Pointer to Ethernet device.
1369 : : *
1370 : : * @return
1371 : : * Number of statistics on success, negative errno value otherwise and
1372 : : * rte_errno is set.
1373 : : */
1374 : : int
1375 : 0 : mlx5_os_get_stats_n(struct rte_eth_dev *dev)
1376 : : {
1377 : 0 : struct mlx5_priv *priv = dev->data->dev_private;
1378 : : struct ethtool_drvinfo drvinfo;
1379 : : struct ifreq ifr;
1380 : : int ret;
1381 : :
1382 : 0 : drvinfo.cmd = ETHTOOL_GDRVINFO;
1383 : 0 : ifr.ifr_data = (caddr_t)&drvinfo;
1384 [ # # # # ]: 0 : if (priv->master && priv->pf_bond >= 0)
1385 : : /* Bonding PF. */
1386 : 0 : ret = mlx5_ifreq_by_ifname(priv->sh->bond.ports[0].ifname,
1387 : : SIOCETHTOOL, &ifr);
1388 : : else
1389 : 0 : ret = mlx5_ifreq(dev, SIOCETHTOOL, &ifr);
1390 [ # # ]: 0 : if (ret) {
1391 : 0 : DRV_LOG(WARNING, "port %u unable to query number of statistics",
1392 : : dev->data->port_id);
1393 : 0 : return ret;
1394 : : }
1395 : 0 : return drvinfo.n_stats;
1396 : : }
1397 : :
1398 : : static const struct mlx5_counter_ctrl mlx5_counters_init[] = {
1399 : : {
1400 : : .dpdk_name = "rx_unicast_bytes",
1401 : : .ctr_name = "rx_vport_unicast_bytes",
1402 : : },
1403 : : {
1404 : : .dpdk_name = "rx_multicast_bytes",
1405 : : .ctr_name = "rx_vport_multicast_bytes",
1406 : : },
1407 : : {
1408 : : .dpdk_name = "rx_broadcast_bytes",
1409 : : .ctr_name = "rx_vport_broadcast_bytes",
1410 : : },
1411 : : {
1412 : : .dpdk_name = "rx_unicast_packets",
1413 : : .ctr_name = "rx_vport_unicast_packets",
1414 : : },
1415 : : {
1416 : : .dpdk_name = "rx_multicast_packets",
1417 : : .ctr_name = "rx_vport_multicast_packets",
1418 : : },
1419 : : {
1420 : : .dpdk_name = "rx_broadcast_packets",
1421 : : .ctr_name = "rx_vport_broadcast_packets",
1422 : : },
1423 : : {
1424 : : .dpdk_name = "tx_unicast_bytes",
1425 : : .ctr_name = "tx_vport_unicast_bytes",
1426 : : },
1427 : : {
1428 : : .dpdk_name = "tx_multicast_bytes",
1429 : : .ctr_name = "tx_vport_multicast_bytes",
1430 : : },
1431 : : {
1432 : : .dpdk_name = "tx_broadcast_bytes",
1433 : : .ctr_name = "tx_vport_broadcast_bytes",
1434 : : },
1435 : : {
1436 : : .dpdk_name = "tx_unicast_packets",
1437 : : .ctr_name = "tx_vport_unicast_packets",
1438 : : },
1439 : : {
1440 : : .dpdk_name = "tx_multicast_packets",
1441 : : .ctr_name = "tx_vport_multicast_packets",
1442 : : },
1443 : : {
1444 : : .dpdk_name = "tx_broadcast_packets",
1445 : : .ctr_name = "tx_vport_broadcast_packets",
1446 : : },
1447 : : {
1448 : : .dpdk_name = "rx_wqe_errors",
1449 : : .ctr_name = "rx_wqe_err",
1450 : : },
1451 : : {
1452 : : .dpdk_name = "rx_phy_crc_errors",
1453 : : .ctr_name = "rx_crc_errors_phy",
1454 : : },
1455 : : {
1456 : : .dpdk_name = "rx_phy_in_range_len_errors",
1457 : : .ctr_name = "rx_in_range_len_errors_phy",
1458 : : },
1459 : : {
1460 : : .dpdk_name = "rx_phy_symbol_errors",
1461 : : .ctr_name = "rx_symbol_err_phy",
1462 : : },
1463 : : {
1464 : : .dpdk_name = "tx_phy_errors",
1465 : : .ctr_name = "tx_errors_phy",
1466 : : },
1467 : : {
1468 : : .dpdk_name = "rx_out_of_buffer",
1469 : : .ctr_name = "out_of_buffer",
1470 : : .dev = 1,
1471 : : },
1472 : : {
1473 : : .dpdk_name = "tx_phy_packets",
1474 : : .ctr_name = "tx_packets_phy",
1475 : : },
1476 : : {
1477 : : .dpdk_name = "rx_phy_packets",
1478 : : .ctr_name = "rx_packets_phy",
1479 : : },
1480 : : {
1481 : : .dpdk_name = "tx_phy_discard_packets",
1482 : : .ctr_name = "tx_discards_phy",
1483 : : },
1484 : : {
1485 : : .dpdk_name = "rx_phy_discard_packets",
1486 : : .ctr_name = "rx_discards_phy",
1487 : : },
1488 : : {
1489 : : .dpdk_name = "rx_prio0_buf_discard_packets",
1490 : : .ctr_name = "rx_prio0_buf_discard",
1491 : : },
1492 : : {
1493 : : .dpdk_name = "rx_prio1_buf_discard_packets",
1494 : : .ctr_name = "rx_prio1_buf_discard",
1495 : : },
1496 : : {
1497 : : .dpdk_name = "rx_prio2_buf_discard_packets",
1498 : : .ctr_name = "rx_prio2_buf_discard",
1499 : : },
1500 : : {
1501 : : .dpdk_name = "rx_prio3_buf_discard_packets",
1502 : : .ctr_name = "rx_prio3_buf_discard",
1503 : : },
1504 : : {
1505 : : .dpdk_name = "rx_prio4_buf_discard_packets",
1506 : : .ctr_name = "rx_prio4_buf_discard",
1507 : : },
1508 : : {
1509 : : .dpdk_name = "rx_prio5_buf_discard_packets",
1510 : : .ctr_name = "rx_prio5_buf_discard",
1511 : : },
1512 : : {
1513 : : .dpdk_name = "rx_prio6_buf_discard_packets",
1514 : : .ctr_name = "rx_prio6_buf_discard",
1515 : : },
1516 : : {
1517 : : .dpdk_name = "rx_prio7_buf_discard_packets",
1518 : : .ctr_name = "rx_prio7_buf_discard",
1519 : : },
1520 : : {
1521 : : .dpdk_name = "rx_prio0_cong_discard_packets",
1522 : : .ctr_name = "rx_prio0_cong_discard",
1523 : : },
1524 : : {
1525 : : .dpdk_name = "rx_prio1_cong_discard_packets",
1526 : : .ctr_name = "rx_prio1_cong_discard",
1527 : : },
1528 : : {
1529 : : .dpdk_name = "rx_prio2_cong_discard_packets",
1530 : : .ctr_name = "rx_prio2_cong_discard",
1531 : : },
1532 : : {
1533 : : .dpdk_name = "rx_prio3_cong_discard_packets",
1534 : : .ctr_name = "rx_prio3_cong_discard",
1535 : : },
1536 : : {
1537 : : .dpdk_name = "rx_prio4_cong_discard_packets",
1538 : : .ctr_name = "rx_prio4_cong_discard",
1539 : : },
1540 : : {
1541 : : .dpdk_name = "rx_prio5_cong_discard_packets",
1542 : : .ctr_name = "rx_prio5_cong_discard",
1543 : : },
1544 : : {
1545 : : .dpdk_name = "rx_prio6_cong_discard_packets",
1546 : : .ctr_name = "rx_prio6_cong_discard",
1547 : : },
1548 : : {
1549 : : .dpdk_name = "rx_prio7_cong_discard_packets",
1550 : : .ctr_name = "rx_prio7_cong_discard",
1551 : : },
1552 : : {
1553 : : .dpdk_name = "tx_phy_bytes",
1554 : : .ctr_name = "tx_bytes_phy",
1555 : : },
1556 : : {
1557 : : .dpdk_name = "rx_phy_bytes",
1558 : : .ctr_name = "rx_bytes_phy",
1559 : : },
1560 : : /* Representor only */
1561 : : {
1562 : : .dpdk_name = "rx_vport_packets",
1563 : : .ctr_name = "vport_rx_packets",
1564 : : },
1565 : : {
1566 : : .dpdk_name = "rx_vport_bytes",
1567 : : .ctr_name = "vport_rx_bytes",
1568 : : },
1569 : : {
1570 : : .dpdk_name = "tx_vport_packets",
1571 : : .ctr_name = "vport_tx_packets",
1572 : : },
1573 : : {
1574 : : .dpdk_name = "tx_vport_bytes",
1575 : : .ctr_name = "vport_tx_bytes",
1576 : : },
1577 : : };
1578 : :
1579 : : static const unsigned int xstats_n = RTE_DIM(mlx5_counters_init);
1580 : :
1581 : : /**
1582 : : * Init the structures to read device counters.
1583 : : *
1584 : : * @param dev
1585 : : * Pointer to Ethernet device.
1586 : : */
1587 : : void
1588 : 0 : mlx5_os_stats_init(struct rte_eth_dev *dev)
1589 : : {
1590 : 0 : struct mlx5_priv *priv = dev->data->dev_private;
1591 : : struct mlx5_xstats_ctrl *xstats_ctrl = &priv->xstats_ctrl;
1592 : : struct mlx5_stats_ctrl *stats_ctrl = &priv->stats_ctrl;
1593 : : unsigned int i;
1594 : : unsigned int j;
1595 : : struct ifreq ifr;
1596 : : struct ethtool_gstrings *strings = NULL;
1597 : : unsigned int dev_stats_n;
1598 : : unsigned int str_sz;
1599 : : int ret;
1600 : :
1601 : : /* So that it won't aggregate for each init. */
1602 : 0 : xstats_ctrl->mlx5_stats_n = 0;
1603 : 0 : ret = mlx5_os_get_stats_n(dev);
1604 [ # # ]: 0 : if (ret < 0) {
1605 : 0 : DRV_LOG(WARNING, "port %u no extended statistics available",
1606 : : dev->data->port_id);
1607 : 0 : return;
1608 : : }
1609 : 0 : dev_stats_n = ret;
1610 : : /* Allocate memory to grab stat names and values. */
1611 : 0 : str_sz = dev_stats_n * ETH_GSTRING_LEN;
1612 : : strings = (struct ethtool_gstrings *)
1613 : 0 : mlx5_malloc(0, str_sz + sizeof(struct ethtool_gstrings), 0,
1614 : : SOCKET_ID_ANY);
1615 [ # # ]: 0 : if (!strings) {
1616 : 0 : DRV_LOG(WARNING, "port %u unable to allocate memory for xstats",
1617 : : dev->data->port_id);
1618 : 0 : return;
1619 : : }
1620 : 0 : strings->cmd = ETHTOOL_GSTRINGS;
1621 : 0 : strings->string_set = ETH_SS_STATS;
1622 : 0 : strings->len = dev_stats_n;
1623 : 0 : ifr.ifr_data = (caddr_t)strings;
1624 [ # # # # ]: 0 : if (priv->master && priv->pf_bond >= 0)
1625 : : /* Bonding master. */
1626 : 0 : ret = mlx5_ifreq_by_ifname(priv->sh->bond.ports[0].ifname,
1627 : : SIOCETHTOOL, &ifr);
1628 : : else
1629 : 0 : ret = mlx5_ifreq(dev, SIOCETHTOOL, &ifr);
1630 [ # # ]: 0 : if (ret) {
1631 : 0 : DRV_LOG(WARNING, "port %u unable to get statistic names",
1632 : : dev->data->port_id);
1633 : 0 : goto free;
1634 : : }
1635 [ # # ]: 0 : for (i = 0; i != dev_stats_n; ++i) {
1636 : 0 : const char *curr_string = (const char *)
1637 : 0 : &strings->data[i * ETH_GSTRING_LEN];
1638 : :
1639 [ # # ]: 0 : for (j = 0; j != xstats_n; ++j) {
1640 [ # # ]: 0 : if (!strcmp(mlx5_counters_init[j].ctr_name,
1641 : : curr_string)) {
1642 : 0 : unsigned int idx = xstats_ctrl->mlx5_stats_n++;
1643 : :
1644 : 0 : xstats_ctrl->dev_table_idx[idx] = i;
1645 : 0 : xstats_ctrl->info[idx] = mlx5_counters_init[j];
1646 : 0 : break;
1647 : : }
1648 : : }
1649 : : }
1650 : : /* Add dev counters. */
1651 : : MLX5_ASSERT(xstats_ctrl->mlx5_stats_n <= MLX5_MAX_XSTATS);
1652 [ # # ]: 0 : for (i = 0; i != xstats_n; ++i) {
1653 [ # # ]: 0 : if (mlx5_counters_init[i].dev) {
1654 : 0 : unsigned int idx = xstats_ctrl->mlx5_stats_n++;
1655 : :
1656 : 0 : xstats_ctrl->info[idx] = mlx5_counters_init[i];
1657 : 0 : xstats_ctrl->hw_stats[idx] = 0;
1658 : : }
1659 : : }
1660 : 0 : xstats_ctrl->stats_n = dev_stats_n;
1661 : : /* Copy to base at first time. */
1662 : 0 : ret = mlx5_os_read_dev_counters(dev, xstats_ctrl->base);
1663 [ # # ]: 0 : if (ret)
1664 : 0 : DRV_LOG(ERR, "port %u cannot read device counters: %s",
1665 : : dev->data->port_id, strerror(rte_errno));
1666 : 0 : mlx5_os_read_dev_stat(priv, "out_of_buffer", &stats_ctrl->imissed_base);
1667 : 0 : stats_ctrl->imissed = 0;
1668 : 0 : free:
1669 : 0 : mlx5_free(strings);
1670 : : }
1671 : :
1672 : : /**
1673 : : * Get MAC address by querying netdevice.
1674 : : *
1675 : : * @param[in] dev
1676 : : * Pointer to Ethernet device.
1677 : : * @param[out] mac
1678 : : * MAC address output buffer.
1679 : : *
1680 : : * @return
1681 : : * 0 on success, a negative errno value otherwise and rte_errno is set.
1682 : : */
1683 : : int
1684 : 0 : mlx5_get_mac(struct rte_eth_dev *dev, uint8_t (*mac)[RTE_ETHER_ADDR_LEN])
1685 : : {
1686 : : struct ifreq request;
1687 : : int ret;
1688 : :
1689 : 0 : ret = mlx5_ifreq(dev, SIOCGIFHWADDR, &request);
1690 [ # # ]: 0 : if (ret)
1691 : : return ret;
1692 : : memcpy(mac, request.ifr_hwaddr.sa_data, RTE_ETHER_ADDR_LEN);
1693 : 0 : return 0;
1694 : : }
1695 : :
1696 : : /*
1697 : : * Query dropless_rq private flag value provided by ETHTOOL.
1698 : : *
1699 : : * @param dev
1700 : : * Pointer to Ethernet device.
1701 : : *
1702 : : * @return
1703 : : * - 0 on success, flag is not set.
1704 : : * - 1 on success, flag is set.
1705 : : * - negative errno value otherwise and rte_errno is set.
1706 : : */
1707 : 0 : int mlx5_get_flag_dropless_rq(struct rte_eth_dev *dev)
1708 : : {
1709 : 0 : struct ethtool_sset_info *sset_info = NULL;
1710 : : struct ethtool_drvinfo drvinfo;
1711 : : struct ifreq ifr;
1712 : : struct ethtool_gstrings *strings = NULL;
1713 : : struct ethtool_value flags;
1714 : : const int32_t flag_len = sizeof(flags.data) * CHAR_BIT;
1715 : : int32_t str_sz;
1716 : : int32_t len;
1717 : : int32_t i;
1718 : : int ret;
1719 : :
1720 : 0 : sset_info = mlx5_malloc(0, sizeof(struct ethtool_sset_info) +
1721 : : sizeof(uint32_t), 0, SOCKET_ID_ANY);
1722 [ # # ]: 0 : if (sset_info == NULL) {
1723 : 0 : rte_errno = ENOMEM;
1724 : 0 : return -rte_errno;
1725 : : }
1726 : 0 : sset_info->cmd = ETHTOOL_GSSET_INFO;
1727 : 0 : sset_info->reserved = 0;
1728 : 0 : sset_info->sset_mask = 1ULL << ETH_SS_PRIV_FLAGS;
1729 : 0 : ifr.ifr_data = (caddr_t)&sset_info;
1730 : 0 : ret = mlx5_ifreq(dev, SIOCETHTOOL, &ifr);
1731 [ # # ]: 0 : if (!ret) {
1732 : 0 : const uint32_t *sset_lengths = sset_info->data;
1733 : :
1734 [ # # ]: 0 : len = sset_info->sset_mask ? sset_lengths[0] : 0;
1735 [ # # ]: 0 : } else if (ret == -EOPNOTSUPP) {
1736 : 0 : drvinfo.cmd = ETHTOOL_GDRVINFO;
1737 : 0 : ifr.ifr_data = (caddr_t)&drvinfo;
1738 : 0 : ret = mlx5_ifreq(dev, SIOCETHTOOL, &ifr);
1739 [ # # ]: 0 : if (ret) {
1740 : 0 : DRV_LOG(WARNING, "port %u cannot get the driver info",
1741 : : dev->data->port_id);
1742 : 0 : goto exit;
1743 : : }
1744 : 0 : len = *(uint32_t *)((char *)&drvinfo +
1745 : : offsetof(struct ethtool_drvinfo, n_priv_flags));
1746 : : } else {
1747 : 0 : DRV_LOG(WARNING, "port %u cannot get the sset info",
1748 : : dev->data->port_id);
1749 : 0 : goto exit;
1750 : : }
1751 [ # # ]: 0 : if (!len) {
1752 : 0 : DRV_LOG(WARNING, "port %u does not have private flag",
1753 : : dev->data->port_id);
1754 : 0 : rte_errno = EOPNOTSUPP;
1755 : : ret = -rte_errno;
1756 : 0 : goto exit;
1757 [ # # ]: 0 : } else if (len > flag_len) {
1758 : 0 : DRV_LOG(WARNING, "port %u maximal private flags number is %d",
1759 : : dev->data->port_id, flag_len);
1760 : : len = flag_len;
1761 : : }
1762 : 0 : str_sz = ETH_GSTRING_LEN * len;
1763 : : strings = (struct ethtool_gstrings *)
1764 : 0 : mlx5_malloc(0, str_sz + sizeof(struct ethtool_gstrings), 0,
1765 : : SOCKET_ID_ANY);
1766 [ # # ]: 0 : if (!strings) {
1767 : 0 : DRV_LOG(WARNING, "port %u unable to allocate memory for"
1768 : : " private flags", dev->data->port_id);
1769 : 0 : rte_errno = ENOMEM;
1770 : : ret = -rte_errno;
1771 : 0 : goto exit;
1772 : : }
1773 : 0 : strings->cmd = ETHTOOL_GSTRINGS;
1774 : 0 : strings->string_set = ETH_SS_PRIV_FLAGS;
1775 : 0 : strings->len = len;
1776 : 0 : ifr.ifr_data = (caddr_t)strings;
1777 : 0 : ret = mlx5_ifreq(dev, SIOCETHTOOL, &ifr);
1778 [ # # ]: 0 : if (ret) {
1779 : 0 : DRV_LOG(WARNING, "port %u unable to get private flags strings",
1780 : : dev->data->port_id);
1781 : 0 : goto exit;
1782 : : }
1783 [ # # ]: 0 : for (i = 0; i < len; i++) {
1784 : 0 : strings->data[(i + 1) * ETH_GSTRING_LEN - 1] = 0;
1785 [ # # ]: 0 : if (!strcmp((const char *)strings->data + i * ETH_GSTRING_LEN,
1786 : : "dropless_rq"))
1787 : : break;
1788 : : }
1789 [ # # ]: 0 : if (i == len) {
1790 : 0 : DRV_LOG(WARNING, "port %u does not support dropless_rq",
1791 : : dev->data->port_id);
1792 : 0 : rte_errno = EOPNOTSUPP;
1793 : : ret = -rte_errno;
1794 : 0 : goto exit;
1795 : : }
1796 : 0 : flags.cmd = ETHTOOL_GPFLAGS;
1797 : 0 : ifr.ifr_data = (caddr_t)&flags;
1798 : 0 : ret = mlx5_ifreq(dev, SIOCETHTOOL, &ifr);
1799 [ # # ]: 0 : if (ret) {
1800 : 0 : DRV_LOG(WARNING, "port %u unable to get private flags status",
1801 : : dev->data->port_id);
1802 : 0 : goto exit;
1803 : : }
1804 : 0 : ret = !!(flags.data & (1U << i));
1805 : 0 : exit:
1806 : 0 : mlx5_free(strings);
1807 : 0 : mlx5_free(sset_info);
1808 : 0 : return ret;
1809 : : }
1810 : :
1811 : : /**
1812 : : * Unmaps HCA PCI BAR from the current process address space.
1813 : : *
1814 : : * @param dev
1815 : : * Pointer to Ethernet device structure.
1816 : : */
1817 : 0 : void mlx5_txpp_unmap_hca_bar(struct rte_eth_dev *dev)
1818 : : {
1819 : 0 : struct mlx5_proc_priv *ppriv = dev->process_private;
1820 : :
1821 [ # # # # ]: 0 : if (ppriv && ppriv->hca_bar) {
1822 : 0 : rte_mem_unmap(ppriv->hca_bar, MLX5_ST_SZ_BYTES(initial_seg));
1823 : 0 : ppriv->hca_bar = NULL;
1824 : : }
1825 : 0 : }
1826 : :
1827 : : /**
1828 : : * Maps HCA PCI BAR to the current process address space.
1829 : : * Stores pointer in the process private structure allowing
1830 : : * to read internal and real time counter directly from the HW.
1831 : : *
1832 : : * @param dev
1833 : : * Pointer to Ethernet device structure.
1834 : : *
1835 : : * @return
1836 : : * 0 on success and not NULL pointer to mapped area in process structure.
1837 : : * negative otherwise and NULL pointer
1838 : : */
1839 : 0 : int mlx5_txpp_map_hca_bar(struct rte_eth_dev *dev)
1840 : 0 : {
1841 : 0 : struct mlx5_proc_priv *ppriv = dev->process_private;
1842 : 0 : char pci_addr[PCI_PRI_STR_SIZE] = { 0 };
1843 : : void *base, *expected = NULL;
1844 : : int fd, ret;
1845 : :
1846 [ # # ]: 0 : if (!ppriv) {
1847 : 0 : rte_errno = ENOMEM;
1848 : 0 : return -rte_errno;
1849 : : }
1850 [ # # ]: 0 : if (ppriv->hca_bar)
1851 : : return 0;
1852 : 0 : ret = mlx5_dev_to_pci_str(dev->device, pci_addr, sizeof(pci_addr));
1853 [ # # ]: 0 : if (ret < 0)
1854 : 0 : return -rte_errno;
1855 : : /* Open PCI device resource 0 - HCA initialize segment */
1856 : 0 : MKSTR(name, "/sys/bus/pci/devices/%s/resource0", pci_addr);
1857 : : fd = open(name, O_RDWR | O_SYNC);
1858 [ # # ]: 0 : if (fd == -1) {
1859 : 0 : rte_errno = ENOTSUP;
1860 : 0 : return -ENOTSUP;
1861 : : }
1862 : 0 : base = rte_mem_map(NULL, MLX5_ST_SZ_BYTES(initial_seg),
1863 : : RTE_PROT_READ, RTE_MAP_SHARED, fd, 0);
1864 : 0 : close(fd);
1865 [ # # ]: 0 : if (!base) {
1866 : 0 : rte_errno = ENOTSUP;
1867 : 0 : return -ENOTSUP;
1868 : : }
1869 : : /* Check there is no concurrent mapping in other thread. */
1870 [ # # ]: 0 : if (!__atomic_compare_exchange_n(&ppriv->hca_bar, &expected,
1871 : : base, false,
1872 : : __ATOMIC_RELAXED, __ATOMIC_RELAXED))
1873 : 0 : rte_mem_unmap(base, MLX5_ST_SZ_BYTES(initial_seg));
1874 : : return 0;
1875 : : }
1876 : :
|