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