1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright 2017 6WIND S.A. 3 * Copyright 2017 Mellanox Technologies, Ltd 4 */ 5 6 /** 7 * @file 8 * Miscellaneous control operations for mlx4 driver. 9 */ 10 11 #include <assert.h> 12 #include <dirent.h> 13 #include <errno.h> 14 #include <linux/ethtool.h> 15 #include <linux/sockios.h> 16 #include <net/if.h> 17 #include <netinet/ip.h> 18 #include <stddef.h> 19 #include <stdint.h> 20 #include <stdio.h> 21 #include <stdlib.h> 22 #include <string.h> 23 #include <sys/ioctl.h> 24 #include <sys/socket.h> 25 #include <unistd.h> 26 27 /* Verbs headers do not support -pedantic. */ 28 #ifdef PEDANTIC 29 #pragma GCC diagnostic ignored "-Wpedantic" 30 #endif 31 #include <infiniband/verbs.h> 32 #ifdef PEDANTIC 33 #pragma GCC diagnostic error "-Wpedantic" 34 #endif 35 36 #include <rte_bus_pci.h> 37 #include <rte_errno.h> 38 #include <rte_ethdev_driver.h> 39 #include <rte_ether.h> 40 #include <rte_flow.h> 41 #include <rte_pci.h> 42 #include <rte_string_fns.h> 43 44 #include "mlx4.h" 45 #include "mlx4_flow.h" 46 #include "mlx4_glue.h" 47 #include "mlx4_rxtx.h" 48 #include "mlx4_utils.h" 49 50 /** 51 * Get interface name from private structure. 52 * 53 * @param[in] priv 54 * Pointer to private structure. 55 * @param[out] ifname 56 * Interface name output buffer. 57 * 58 * @return 59 * 0 on success, negative errno value otherwise and rte_errno is set. 60 */ 61 int 62 mlx4_get_ifname(const struct mlx4_priv *priv, char (*ifname)[IF_NAMESIZE]) 63 { 64 DIR *dir; 65 struct dirent *dent; 66 unsigned int dev_type = 0; 67 unsigned int dev_port_prev = ~0u; 68 char match[IF_NAMESIZE] = ""; 69 70 { 71 MKSTR(path, "%s/device/net", priv->ctx->device->ibdev_path); 72 73 dir = opendir(path); 74 if (dir == NULL) { 75 rte_errno = errno; 76 return -rte_errno; 77 } 78 } 79 while ((dent = readdir(dir)) != NULL) { 80 char *name = dent->d_name; 81 FILE *file; 82 unsigned int dev_port; 83 int r; 84 85 if ((name[0] == '.') && 86 ((name[1] == '\0') || 87 ((name[1] == '.') && (name[2] == '\0')))) 88 continue; 89 90 MKSTR(path, "%s/device/net/%s/%s", 91 priv->ctx->device->ibdev_path, name, 92 (dev_type ? "dev_id" : "dev_port")); 93 94 file = fopen(path, "rb"); 95 if (file == NULL) { 96 if (errno != ENOENT) 97 continue; 98 /* 99 * Switch to dev_id when dev_port does not exist as 100 * is the case with Linux kernel versions < 3.15. 101 */ 102 try_dev_id: 103 match[0] = '\0'; 104 if (dev_type) 105 break; 106 dev_type = 1; 107 dev_port_prev = ~0u; 108 rewinddir(dir); 109 continue; 110 } 111 r = fscanf(file, (dev_type ? "%x" : "%u"), &dev_port); 112 fclose(file); 113 if (r != 1) 114 continue; 115 /* 116 * Switch to dev_id when dev_port returns the same value for 117 * all ports. May happen when using a MOFED release older than 118 * 3.0 with a Linux kernel >= 3.15. 119 */ 120 if (dev_port == dev_port_prev) 121 goto try_dev_id; 122 dev_port_prev = dev_port; 123 if (dev_port == (priv->port - 1u)) 124 strlcpy(match, name, sizeof(match)); 125 } 126 closedir(dir); 127 if (match[0] == '\0') { 128 rte_errno = ENODEV; 129 return -rte_errno; 130 } 131 strncpy(*ifname, match, sizeof(*ifname)); 132 return 0; 133 } 134 135 /** 136 * Perform ifreq ioctl() on associated Ethernet device. 137 * 138 * @param[in] priv 139 * Pointer to private structure. 140 * @param req 141 * Request number to pass to ioctl(). 142 * @param[out] ifr 143 * Interface request structure output buffer. 144 * 145 * @return 146 * 0 on success, negative errno value otherwise and rte_errno is set. 147 */ 148 static int 149 mlx4_ifreq(const struct mlx4_priv *priv, int req, struct ifreq *ifr) 150 { 151 int sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP); 152 int ret; 153 154 if (sock == -1) { 155 rte_errno = errno; 156 return -rte_errno; 157 } 158 ret = mlx4_get_ifname(priv, &ifr->ifr_name); 159 if (!ret && ioctl(sock, req, ifr) == -1) { 160 rte_errno = errno; 161 ret = -rte_errno; 162 } 163 close(sock); 164 return ret; 165 } 166 167 /** 168 * Get MAC address by querying netdevice. 169 * 170 * @param[in] priv 171 * Pointer to private structure. 172 * @param[out] mac 173 * MAC address output buffer. 174 * 175 * @return 176 * 0 on success, negative errno value otherwise and rte_errno is set. 177 */ 178 int 179 mlx4_get_mac(struct mlx4_priv *priv, uint8_t (*mac)[RTE_ETHER_ADDR_LEN]) 180 { 181 struct ifreq request; 182 int ret = mlx4_ifreq(priv, SIOCGIFHWADDR, &request); 183 184 if (ret) 185 return ret; 186 memcpy(mac, request.ifr_hwaddr.sa_data, RTE_ETHER_ADDR_LEN); 187 return 0; 188 } 189 190 /** 191 * Get device MTU. 192 * 193 * @param priv 194 * Pointer to private structure. 195 * @param[out] mtu 196 * MTU value output buffer. 197 * 198 * @return 199 * 0 on success, negative errno value otherwise and rte_errno is set. 200 */ 201 int 202 mlx4_mtu_get(struct mlx4_priv *priv, uint16_t *mtu) 203 { 204 struct ifreq request; 205 int ret = mlx4_ifreq(priv, SIOCGIFMTU, &request); 206 207 if (ret) 208 return ret; 209 *mtu = request.ifr_mtu; 210 return 0; 211 } 212 213 /** 214 * DPDK callback to change the MTU. 215 * 216 * @param priv 217 * Pointer to Ethernet device structure. 218 * @param mtu 219 * MTU value to set. 220 * 221 * @return 222 * 0 on success, negative errno value otherwise and rte_errno is set. 223 */ 224 int 225 mlx4_mtu_set(struct rte_eth_dev *dev, uint16_t mtu) 226 { 227 struct mlx4_priv *priv = dev->data->dev_private; 228 struct ifreq request = { .ifr_mtu = mtu, }; 229 int ret = mlx4_ifreq(priv, SIOCSIFMTU, &request); 230 231 if (ret) 232 return ret; 233 priv->mtu = mtu; 234 return 0; 235 } 236 237 /** 238 * Set device flags. 239 * 240 * @param priv 241 * Pointer to private structure. 242 * @param keep 243 * Bitmask for flags that must remain untouched. 244 * @param flags 245 * Bitmask for flags to modify. 246 * 247 * @return 248 * 0 on success, negative errno value otherwise and rte_errno is set. 249 */ 250 static int 251 mlx4_set_flags(struct mlx4_priv *priv, unsigned int keep, unsigned int flags) 252 { 253 struct ifreq request; 254 int ret = mlx4_ifreq(priv, SIOCGIFFLAGS, &request); 255 256 if (ret) 257 return ret; 258 request.ifr_flags &= keep; 259 request.ifr_flags |= flags & ~keep; 260 return mlx4_ifreq(priv, SIOCSIFFLAGS, &request); 261 } 262 263 /** 264 * Change the link state (UP / DOWN). 265 * 266 * @param priv 267 * Pointer to Ethernet device private data. 268 * @param up 269 * Nonzero for link up, otherwise link down. 270 * 271 * @return 272 * 0 on success, negative errno value otherwise and rte_errno is set. 273 */ 274 static int 275 mlx4_dev_set_link(struct mlx4_priv *priv, int up) 276 { 277 int err; 278 279 if (up) { 280 err = mlx4_set_flags(priv, ~IFF_UP, IFF_UP); 281 if (err) 282 return err; 283 } else { 284 err = mlx4_set_flags(priv, ~IFF_UP, ~IFF_UP); 285 if (err) 286 return err; 287 } 288 return 0; 289 } 290 291 /** 292 * DPDK callback to bring the link DOWN. 293 * 294 * @param dev 295 * Pointer to Ethernet device structure. 296 * 297 * @return 298 * 0 on success, negative errno value otherwise and rte_errno is set. 299 */ 300 int 301 mlx4_dev_set_link_down(struct rte_eth_dev *dev) 302 { 303 struct mlx4_priv *priv = dev->data->dev_private; 304 305 return mlx4_dev_set_link(priv, 0); 306 } 307 308 /** 309 * DPDK callback to bring the link UP. 310 * 311 * @param dev 312 * Pointer to Ethernet device structure. 313 * 314 * @return 315 * 0 on success, negative errno value otherwise and rte_errno is set. 316 */ 317 int 318 mlx4_dev_set_link_up(struct rte_eth_dev *dev) 319 { 320 struct mlx4_priv *priv = dev->data->dev_private; 321 322 return mlx4_dev_set_link(priv, 1); 323 } 324 325 /** 326 * Supported Rx mode toggles. 327 * 328 * Even and odd values respectively stand for off and on. 329 */ 330 enum rxmode_toggle { 331 RXMODE_TOGGLE_PROMISC_OFF, 332 RXMODE_TOGGLE_PROMISC_ON, 333 RXMODE_TOGGLE_ALLMULTI_OFF, 334 RXMODE_TOGGLE_ALLMULTI_ON, 335 }; 336 337 /** 338 * Helper function to toggle promiscuous and all multicast modes. 339 * 340 * @param dev 341 * Pointer to Ethernet device structure. 342 * @param toggle 343 * Toggle to set. 344 */ 345 static void 346 mlx4_rxmode_toggle(struct rte_eth_dev *dev, enum rxmode_toggle toggle) 347 { 348 struct mlx4_priv *priv = dev->data->dev_private; 349 const char *mode; 350 struct rte_flow_error error; 351 352 switch (toggle) { 353 case RXMODE_TOGGLE_PROMISC_OFF: 354 case RXMODE_TOGGLE_PROMISC_ON: 355 mode = "promiscuous"; 356 dev->data->promiscuous = toggle & 1; 357 break; 358 case RXMODE_TOGGLE_ALLMULTI_OFF: 359 case RXMODE_TOGGLE_ALLMULTI_ON: 360 mode = "all multicast"; 361 dev->data->all_multicast = toggle & 1; 362 break; 363 default: 364 mode = "undefined"; 365 } 366 if (!mlx4_flow_sync(priv, &error)) 367 return; 368 ERROR("cannot toggle %s mode (code %d, \"%s\")," 369 " flow error type %d, cause %p, message: %s", 370 mode, rte_errno, strerror(rte_errno), error.type, error.cause, 371 error.message ? error.message : "(unspecified)"); 372 } 373 374 /** 375 * DPDK callback to enable promiscuous mode. 376 * 377 * @param dev 378 * Pointer to Ethernet device structure. 379 */ 380 void 381 mlx4_promiscuous_enable(struct rte_eth_dev *dev) 382 { 383 mlx4_rxmode_toggle(dev, RXMODE_TOGGLE_PROMISC_ON); 384 } 385 386 /** 387 * DPDK callback to disable promiscuous mode. 388 * 389 * @param dev 390 * Pointer to Ethernet device structure. 391 */ 392 void 393 mlx4_promiscuous_disable(struct rte_eth_dev *dev) 394 { 395 mlx4_rxmode_toggle(dev, RXMODE_TOGGLE_PROMISC_OFF); 396 } 397 398 /** 399 * DPDK callback to enable all multicast mode. 400 * 401 * @param dev 402 * Pointer to Ethernet device structure. 403 */ 404 void 405 mlx4_allmulticast_enable(struct rte_eth_dev *dev) 406 { 407 mlx4_rxmode_toggle(dev, RXMODE_TOGGLE_ALLMULTI_ON); 408 } 409 410 /** 411 * DPDK callback to disable all multicast mode. 412 * 413 * @param dev 414 * Pointer to Ethernet device structure. 415 */ 416 void 417 mlx4_allmulticast_disable(struct rte_eth_dev *dev) 418 { 419 mlx4_rxmode_toggle(dev, RXMODE_TOGGLE_ALLMULTI_OFF); 420 } 421 422 /** 423 * DPDK callback to remove a MAC address. 424 * 425 * @param dev 426 * Pointer to Ethernet device structure. 427 * @param index 428 * MAC address index. 429 */ 430 void 431 mlx4_mac_addr_remove(struct rte_eth_dev *dev, uint32_t index) 432 { 433 struct mlx4_priv *priv = dev->data->dev_private; 434 struct rte_flow_error error; 435 436 if (index >= RTE_DIM(priv->mac) - priv->mac_mc) { 437 rte_errno = EINVAL; 438 return; 439 } 440 memset(&priv->mac[index], 0, sizeof(priv->mac[index])); 441 if (!mlx4_flow_sync(priv, &error)) 442 return; 443 ERROR("failed to synchronize flow rules after removing MAC address" 444 " at index %d (code %d, \"%s\")," 445 " flow error type %d, cause %p, message: %s", 446 index, rte_errno, strerror(rte_errno), error.type, error.cause, 447 error.message ? error.message : "(unspecified)"); 448 } 449 450 /** 451 * DPDK callback to add a MAC address. 452 * 453 * @param dev 454 * Pointer to Ethernet device structure. 455 * @param mac_addr 456 * MAC address to register. 457 * @param index 458 * MAC address index. 459 * @param vmdq 460 * VMDq pool index to associate address with (ignored). 461 * 462 * @return 463 * 0 on success, negative errno value otherwise and rte_errno is set. 464 */ 465 int 466 mlx4_mac_addr_add(struct rte_eth_dev *dev, struct rte_ether_addr *mac_addr, 467 uint32_t index, uint32_t vmdq) 468 { 469 struct mlx4_priv *priv = dev->data->dev_private; 470 struct rte_flow_error error; 471 int ret; 472 473 (void)vmdq; 474 if (index >= RTE_DIM(priv->mac) - priv->mac_mc) { 475 rte_errno = EINVAL; 476 return -rte_errno; 477 } 478 memcpy(&priv->mac[index], mac_addr, sizeof(priv->mac[index])); 479 ret = mlx4_flow_sync(priv, &error); 480 if (!ret) 481 return 0; 482 ERROR("failed to synchronize flow rules after adding MAC address" 483 " at index %d (code %d, \"%s\")," 484 " flow error type %d, cause %p, message: %s", 485 index, rte_errno, strerror(rte_errno), error.type, error.cause, 486 error.message ? error.message : "(unspecified)"); 487 return ret; 488 } 489 490 /** 491 * DPDK callback to configure multicast addresses. 492 * 493 * @param dev 494 * Pointer to Ethernet device structure. 495 * @param list 496 * List of MAC addresses to register. 497 * @param num 498 * Number of entries in list. 499 * 500 * @return 501 * 0 on success, negative errno value otherwise and rte_errno is set. 502 */ 503 int 504 mlx4_set_mc_addr_list(struct rte_eth_dev *dev, struct rte_ether_addr *list, 505 uint32_t num) 506 { 507 struct mlx4_priv *priv = dev->data->dev_private; 508 struct rte_flow_error error; 509 int ret; 510 511 if (num > RTE_DIM(priv->mac)) { 512 rte_errno = EINVAL; 513 return -rte_errno; 514 } 515 /* 516 * Make sure there is enough room to increase the number of 517 * multicast entries without overwriting standard entries. 518 */ 519 if (num > priv->mac_mc) { 520 unsigned int i; 521 522 for (i = RTE_DIM(priv->mac) - num; 523 i != RTE_DIM(priv->mac) - priv->mac_mc; 524 ++i) 525 if (!rte_is_zero_ether_addr(&priv->mac[i])) { 526 rte_errno = EBUSY; 527 return -rte_errno; 528 } 529 } else if (num < priv->mac_mc) { 530 /* Clear unused entries. */ 531 memset(priv->mac + RTE_DIM(priv->mac) - priv->mac_mc, 532 0, 533 sizeof(priv->mac[0]) * (priv->mac_mc - num)); 534 } 535 memcpy(priv->mac + RTE_DIM(priv->mac) - num, list, sizeof(*list) * num); 536 priv->mac_mc = num; 537 ret = mlx4_flow_sync(priv, &error); 538 if (!ret) 539 return 0; 540 ERROR("failed to synchronize flow rules after modifying MC list," 541 " (code %d, \"%s\"), flow error type %d, cause %p, message: %s", 542 rte_errno, strerror(rte_errno), error.type, error.cause, 543 error.message ? error.message : "(unspecified)"); 544 return ret; 545 } 546 547 /** 548 * DPDK callback to configure a VLAN filter. 549 * 550 * @param dev 551 * Pointer to Ethernet device structure. 552 * @param vlan_id 553 * VLAN ID to filter. 554 * @param on 555 * Toggle filter. 556 * 557 * @return 558 * 0 on success, negative errno value otherwise and rte_errno is set. 559 */ 560 int 561 mlx4_vlan_filter_set(struct rte_eth_dev *dev, uint16_t vlan_id, int on) 562 { 563 struct mlx4_priv *priv = dev->data->dev_private; 564 struct rte_flow_error error; 565 unsigned int vidx = vlan_id / 64; 566 unsigned int vbit = vlan_id % 64; 567 uint64_t *v; 568 int ret; 569 570 if (vidx >= RTE_DIM(dev->data->vlan_filter_conf.ids)) { 571 rte_errno = EINVAL; 572 return -rte_errno; 573 } 574 v = &dev->data->vlan_filter_conf.ids[vidx]; 575 *v &= ~(UINT64_C(1) << vbit); 576 *v |= (uint64_t)!!on << vbit; 577 ret = mlx4_flow_sync(priv, &error); 578 if (!ret) 579 return 0; 580 ERROR("failed to synchronize flow rules after %s VLAN filter on ID %u" 581 " (code %d, \"%s\"), " 582 " flow error type %d, cause %p, message: %s", 583 on ? "enabling" : "disabling", vlan_id, 584 rte_errno, strerror(rte_errno), error.type, error.cause, 585 error.message ? error.message : "(unspecified)"); 586 return ret; 587 } 588 589 /** 590 * DPDK callback to set the primary MAC address. 591 * 592 * @param dev 593 * Pointer to Ethernet device structure. 594 * @param mac_addr 595 * MAC address to register. 596 * 597 * @return 598 * 0 on success, negative errno value otherwise and rte_errno is set. 599 */ 600 int 601 mlx4_mac_addr_set(struct rte_eth_dev *dev, struct rte_ether_addr *mac_addr) 602 { 603 return mlx4_mac_addr_add(dev, mac_addr, 0, 0); 604 } 605 606 /** 607 * DPDK callback to get information about the device. 608 * 609 * @param dev 610 * Pointer to Ethernet device structure. 611 * @param[out] info 612 * Info structure output buffer. 613 */ 614 void 615 mlx4_dev_infos_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *info) 616 { 617 struct mlx4_priv *priv = dev->data->dev_private; 618 unsigned int max; 619 620 /* FIXME: we should ask the device for these values. */ 621 info->min_rx_bufsize = 32; 622 info->max_rx_pktlen = 65536; 623 /* 624 * Since we need one CQ per QP, the limit is the minimum number 625 * between the two values. 626 */ 627 max = ((priv->device_attr.max_cq > priv->device_attr.max_qp) ? 628 priv->device_attr.max_qp : priv->device_attr.max_cq); 629 /* If max >= 65535 then max = 0, max_rx_queues is uint16_t. */ 630 if (max >= 65535) 631 max = 65535; 632 info->max_rx_queues = max; 633 info->max_tx_queues = max; 634 info->max_mac_addrs = RTE_DIM(priv->mac); 635 info->tx_offload_capa = mlx4_get_tx_port_offloads(priv); 636 info->rx_queue_offload_capa = mlx4_get_rx_queue_offloads(priv); 637 info->rx_offload_capa = (mlx4_get_rx_port_offloads(priv) | 638 info->rx_queue_offload_capa); 639 info->if_index = priv->if_index; 640 info->hash_key_size = MLX4_RSS_HASH_KEY_SIZE; 641 info->speed_capa = 642 ETH_LINK_SPEED_1G | 643 ETH_LINK_SPEED_10G | 644 ETH_LINK_SPEED_20G | 645 ETH_LINK_SPEED_40G | 646 ETH_LINK_SPEED_56G; 647 info->flow_type_rss_offloads = mlx4_conv_rss_types(priv, 0, 1); 648 } 649 650 /** 651 * Get firmware version of a device. 652 * 653 * @param dev 654 * Ethernet device port. 655 * @param fw_ver 656 * String output allocated by caller. 657 * @param fw_size 658 * Size of the output string, including terminating null byte. 659 * 660 * @return 661 * 0 on success, or the size of the non truncated string if too big. 662 */ 663 int mlx4_fw_version_get(struct rte_eth_dev *dev, char *fw_ver, size_t fw_size) 664 { 665 struct mlx4_priv *priv = dev->data->dev_private; 666 struct ibv_device_attr *attr = &priv->device_attr; 667 size_t size = strnlen(attr->fw_ver, sizeof(attr->fw_ver)) + 1; 668 669 if (fw_size < size) 670 return size; 671 if (fw_ver != NULL) 672 strlcpy(fw_ver, attr->fw_ver, fw_size); 673 return 0; 674 } 675 676 /** 677 * DPDK callback to get device statistics. 678 * 679 * @param dev 680 * Pointer to Ethernet device structure. 681 * @param[out] stats 682 * Stats structure output buffer. 683 */ 684 int 685 mlx4_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats) 686 { 687 struct rte_eth_stats tmp; 688 unsigned int i; 689 unsigned int idx; 690 691 memset(&tmp, 0, sizeof(tmp)); 692 /* Add software counters. */ 693 for (i = 0; i != dev->data->nb_rx_queues; ++i) { 694 struct rxq *rxq = dev->data->rx_queues[i]; 695 696 if (rxq == NULL) 697 continue; 698 idx = rxq->stats.idx; 699 if (idx < RTE_ETHDEV_QUEUE_STAT_CNTRS) { 700 tmp.q_ipackets[idx] += rxq->stats.ipackets; 701 tmp.q_ibytes[idx] += rxq->stats.ibytes; 702 tmp.q_errors[idx] += (rxq->stats.idropped + 703 rxq->stats.rx_nombuf); 704 } 705 tmp.ipackets += rxq->stats.ipackets; 706 tmp.ibytes += rxq->stats.ibytes; 707 tmp.ierrors += rxq->stats.idropped; 708 tmp.rx_nombuf += rxq->stats.rx_nombuf; 709 } 710 for (i = 0; i != dev->data->nb_tx_queues; ++i) { 711 struct txq *txq = dev->data->tx_queues[i]; 712 713 if (txq == NULL) 714 continue; 715 idx = txq->stats.idx; 716 if (idx < RTE_ETHDEV_QUEUE_STAT_CNTRS) { 717 tmp.q_opackets[idx] += txq->stats.opackets; 718 tmp.q_obytes[idx] += txq->stats.obytes; 719 } 720 tmp.opackets += txq->stats.opackets; 721 tmp.obytes += txq->stats.obytes; 722 tmp.oerrors += txq->stats.odropped; 723 } 724 *stats = tmp; 725 return 0; 726 } 727 728 /** 729 * DPDK callback to clear device statistics. 730 * 731 * @param dev 732 * Pointer to Ethernet device structure. 733 */ 734 void 735 mlx4_stats_reset(struct rte_eth_dev *dev) 736 { 737 unsigned int i; 738 739 for (i = 0; i != dev->data->nb_rx_queues; ++i) { 740 struct rxq *rxq = dev->data->rx_queues[i]; 741 742 if (rxq) 743 rxq->stats = (struct mlx4_rxq_stats){ 744 .idx = rxq->stats.idx, 745 }; 746 } 747 for (i = 0; i != dev->data->nb_tx_queues; ++i) { 748 struct txq *txq = dev->data->tx_queues[i]; 749 750 if (txq) 751 txq->stats = (struct mlx4_txq_stats){ 752 .idx = txq->stats.idx, 753 }; 754 } 755 } 756 757 /** 758 * DPDK callback to retrieve physical link information. 759 * 760 * @param dev 761 * Pointer to Ethernet device structure. 762 * @param wait_to_complete 763 * Wait for request completion (ignored). 764 * 765 * @return 766 * 0 on success, negative errno value otherwise and rte_errno is set. 767 */ 768 int 769 mlx4_link_update(struct rte_eth_dev *dev, int wait_to_complete) 770 { 771 const struct mlx4_priv *priv = dev->data->dev_private; 772 struct ethtool_cmd edata = { 773 .cmd = ETHTOOL_GSET, 774 }; 775 struct ifreq ifr; 776 struct rte_eth_link dev_link; 777 int link_speed = 0; 778 779 if (priv == NULL) { 780 rte_errno = EINVAL; 781 return -rte_errno; 782 } 783 (void)wait_to_complete; 784 if (mlx4_ifreq(priv, SIOCGIFFLAGS, &ifr)) { 785 WARN("ioctl(SIOCGIFFLAGS) failed: %s", strerror(rte_errno)); 786 return -rte_errno; 787 } 788 memset(&dev_link, 0, sizeof(dev_link)); 789 dev_link.link_status = ((ifr.ifr_flags & IFF_UP) && 790 (ifr.ifr_flags & IFF_RUNNING)); 791 ifr.ifr_data = (void *)&edata; 792 if (mlx4_ifreq(priv, SIOCETHTOOL, &ifr)) { 793 WARN("ioctl(SIOCETHTOOL, ETHTOOL_GSET) failed: %s", 794 strerror(rte_errno)); 795 return -rte_errno; 796 } 797 link_speed = ethtool_cmd_speed(&edata); 798 if (link_speed == -1) 799 dev_link.link_speed = ETH_SPEED_NUM_NONE; 800 else 801 dev_link.link_speed = link_speed; 802 dev_link.link_duplex = ((edata.duplex == DUPLEX_HALF) ? 803 ETH_LINK_HALF_DUPLEX : ETH_LINK_FULL_DUPLEX); 804 dev_link.link_autoneg = !(dev->data->dev_conf.link_speeds & 805 ETH_LINK_SPEED_FIXED); 806 dev->data->dev_link = dev_link; 807 return 0; 808 } 809 810 /** 811 * DPDK callback to get flow control status. 812 * 813 * @param dev 814 * Pointer to Ethernet device structure. 815 * @param[out] fc_conf 816 * Flow control output buffer. 817 * 818 * @return 819 * 0 on success, negative errno value otherwise and rte_errno is set. 820 */ 821 int 822 mlx4_flow_ctrl_get(struct rte_eth_dev *dev, struct rte_eth_fc_conf *fc_conf) 823 { 824 struct mlx4_priv *priv = dev->data->dev_private; 825 struct ifreq ifr; 826 struct ethtool_pauseparam ethpause = { 827 .cmd = ETHTOOL_GPAUSEPARAM, 828 }; 829 int ret; 830 831 ifr.ifr_data = (void *)ðpause; 832 if (mlx4_ifreq(priv, SIOCETHTOOL, &ifr)) { 833 ret = rte_errno; 834 WARN("ioctl(SIOCETHTOOL, ETHTOOL_GPAUSEPARAM)" 835 " failed: %s", 836 strerror(rte_errno)); 837 goto out; 838 } 839 fc_conf->autoneg = ethpause.autoneg; 840 if (ethpause.rx_pause && ethpause.tx_pause) 841 fc_conf->mode = RTE_FC_FULL; 842 else if (ethpause.rx_pause) 843 fc_conf->mode = RTE_FC_RX_PAUSE; 844 else if (ethpause.tx_pause) 845 fc_conf->mode = RTE_FC_TX_PAUSE; 846 else 847 fc_conf->mode = RTE_FC_NONE; 848 ret = 0; 849 out: 850 assert(ret >= 0); 851 return -ret; 852 } 853 854 /** 855 * DPDK callback to modify flow control parameters. 856 * 857 * @param dev 858 * Pointer to Ethernet device structure. 859 * @param[in] fc_conf 860 * Flow control parameters. 861 * 862 * @return 863 * 0 on success, negative errno value otherwise and rte_errno is set. 864 */ 865 int 866 mlx4_flow_ctrl_set(struct rte_eth_dev *dev, struct rte_eth_fc_conf *fc_conf) 867 { 868 struct mlx4_priv *priv = dev->data->dev_private; 869 struct ifreq ifr; 870 struct ethtool_pauseparam ethpause = { 871 .cmd = ETHTOOL_SPAUSEPARAM, 872 }; 873 int ret; 874 875 ifr.ifr_data = (void *)ðpause; 876 ethpause.autoneg = fc_conf->autoneg; 877 if (((fc_conf->mode & RTE_FC_FULL) == RTE_FC_FULL) || 878 (fc_conf->mode & RTE_FC_RX_PAUSE)) 879 ethpause.rx_pause = 1; 880 else 881 ethpause.rx_pause = 0; 882 if (((fc_conf->mode & RTE_FC_FULL) == RTE_FC_FULL) || 883 (fc_conf->mode & RTE_FC_TX_PAUSE)) 884 ethpause.tx_pause = 1; 885 else 886 ethpause.tx_pause = 0; 887 if (mlx4_ifreq(priv, SIOCETHTOOL, &ifr)) { 888 ret = rte_errno; 889 WARN("ioctl(SIOCETHTOOL, ETHTOOL_SPAUSEPARAM)" 890 " failed: %s", 891 strerror(rte_errno)); 892 goto out; 893 } 894 ret = 0; 895 out: 896 assert(ret >= 0); 897 return -ret; 898 } 899 900 /** 901 * DPDK callback to retrieve the received packet types that are recognized 902 * by the device. 903 * 904 * @param dev 905 * Pointer to Ethernet device structure. 906 * 907 * @return 908 * Pointer to an array of recognized packet types if in Rx burst mode, 909 * NULL otherwise. 910 */ 911 const uint32_t * 912 mlx4_dev_supported_ptypes_get(struct rte_eth_dev *dev) 913 { 914 static const uint32_t ptypes[] = { 915 /* refers to rxq_cq_to_pkt_type() */ 916 RTE_PTYPE_L2_ETHER, 917 RTE_PTYPE_L3_IPV4_EXT_UNKNOWN, 918 RTE_PTYPE_L3_IPV6_EXT_UNKNOWN, 919 RTE_PTYPE_L4_FRAG, 920 RTE_PTYPE_L4_TCP, 921 RTE_PTYPE_L4_UDP, 922 RTE_PTYPE_UNKNOWN 923 }; 924 static const uint32_t ptypes_l2tun[] = { 925 /* refers to rxq_cq_to_pkt_type() */ 926 RTE_PTYPE_L2_ETHER, 927 RTE_PTYPE_L3_IPV4_EXT_UNKNOWN, 928 RTE_PTYPE_L3_IPV6_EXT_UNKNOWN, 929 RTE_PTYPE_L4_FRAG, 930 RTE_PTYPE_L4_TCP, 931 RTE_PTYPE_L4_UDP, 932 RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN, 933 RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN, 934 RTE_PTYPE_UNKNOWN 935 }; 936 struct mlx4_priv *priv = dev->data->dev_private; 937 938 if (dev->rx_pkt_burst == mlx4_rx_burst) { 939 if (priv->hw_csum_l2tun) 940 return ptypes_l2tun; 941 else 942 return ptypes; 943 } 944 return NULL; 945 } 946 947 /** 948 * Check if mlx4 device was removed. 949 * 950 * @param dev 951 * Pointer to Ethernet device structure. 952 * 953 * @return 954 * 1 when device is removed, otherwise 0. 955 */ 956 int 957 mlx4_is_removed(struct rte_eth_dev *dev) 958 { 959 struct ibv_device_attr device_attr; 960 struct mlx4_priv *priv = dev->data->dev_private; 961 962 if (mlx4_glue->query_device(priv->ctx, &device_attr) == EIO) 963 return 1; 964 return 0; 965 } 966