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.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 * Perform ifreq ioctl() on associated Ethernet device. 163 * 164 * @param[in] priv 165 * Pointer to private structure. 166 * @param req 167 * Request number to pass to ioctl(). 168 * @param[out] ifr 169 * Interface request structure output buffer. 170 * 171 * @return 172 * 0 on success, negative errno value otherwise and rte_errno is set. 173 */ 174 static int 175 mlx4_ifreq(const struct priv *priv, int req, struct ifreq *ifr) 176 { 177 int sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP); 178 int ret; 179 180 if (sock == -1) { 181 rte_errno = errno; 182 return -rte_errno; 183 } 184 ret = mlx4_get_ifname(priv, &ifr->ifr_name); 185 if (!ret && ioctl(sock, req, ifr) == -1) { 186 rte_errno = errno; 187 ret = -rte_errno; 188 } 189 close(sock); 190 return ret; 191 } 192 193 /** 194 * Get MAC address by querying netdevice. 195 * 196 * @param[in] priv 197 * Pointer to private structure. 198 * @param[out] mac 199 * MAC address output buffer. 200 * 201 * @return 202 * 0 on success, negative errno value otherwise and rte_errno is set. 203 */ 204 int 205 mlx4_get_mac(struct priv *priv, uint8_t (*mac)[ETHER_ADDR_LEN]) 206 { 207 struct ifreq request; 208 int ret = mlx4_ifreq(priv, SIOCGIFHWADDR, &request); 209 210 if (ret) 211 return ret; 212 memcpy(mac, request.ifr_hwaddr.sa_data, ETHER_ADDR_LEN); 213 return 0; 214 } 215 216 /** 217 * Get device MTU. 218 * 219 * @param priv 220 * Pointer to private structure. 221 * @param[out] mtu 222 * MTU value output buffer. 223 * 224 * @return 225 * 0 on success, negative errno value otherwise and rte_errno is set. 226 */ 227 int 228 mlx4_mtu_get(struct priv *priv, uint16_t *mtu) 229 { 230 struct ifreq request; 231 int ret = mlx4_ifreq(priv, SIOCGIFMTU, &request); 232 233 if (ret) 234 return ret; 235 *mtu = request.ifr_mtu; 236 return 0; 237 } 238 239 /** 240 * DPDK callback to change the MTU. 241 * 242 * @param priv 243 * Pointer to Ethernet device structure. 244 * @param mtu 245 * MTU value to set. 246 * 247 * @return 248 * 0 on success, negative errno value otherwise and rte_errno is set. 249 */ 250 int 251 mlx4_mtu_set(struct rte_eth_dev *dev, uint16_t mtu) 252 { 253 struct priv *priv = dev->data->dev_private; 254 struct ifreq request = { .ifr_mtu = mtu, }; 255 int ret = mlx4_ifreq(priv, SIOCSIFMTU, &request); 256 257 if (ret) 258 return ret; 259 priv->mtu = mtu; 260 return 0; 261 } 262 263 /** 264 * Set device flags. 265 * 266 * @param priv 267 * Pointer to private structure. 268 * @param keep 269 * Bitmask for flags that must remain untouched. 270 * @param flags 271 * Bitmask for flags to modify. 272 * 273 * @return 274 * 0 on success, negative errno value otherwise and rte_errno is set. 275 */ 276 static int 277 mlx4_set_flags(struct priv *priv, unsigned int keep, unsigned int flags) 278 { 279 struct ifreq request; 280 int ret = mlx4_ifreq(priv, SIOCGIFFLAGS, &request); 281 282 if (ret) 283 return ret; 284 request.ifr_flags &= keep; 285 request.ifr_flags |= flags & ~keep; 286 return mlx4_ifreq(priv, SIOCSIFFLAGS, &request); 287 } 288 289 /** 290 * Change the link state (UP / DOWN). 291 * 292 * @param priv 293 * Pointer to Ethernet device private data. 294 * @param up 295 * Nonzero for link up, otherwise link down. 296 * 297 * @return 298 * 0 on success, negative errno value otherwise and rte_errno is set. 299 */ 300 static int 301 mlx4_dev_set_link(struct priv *priv, int up) 302 { 303 int err; 304 305 if (up) { 306 err = mlx4_set_flags(priv, ~IFF_UP, IFF_UP); 307 if (err) 308 return err; 309 } else { 310 err = mlx4_set_flags(priv, ~IFF_UP, ~IFF_UP); 311 if (err) 312 return err; 313 } 314 return 0; 315 } 316 317 /** 318 * DPDK callback to bring the link DOWN. 319 * 320 * @param dev 321 * Pointer to Ethernet device structure. 322 * 323 * @return 324 * 0 on success, negative errno value otherwise and rte_errno is set. 325 */ 326 int 327 mlx4_dev_set_link_down(struct rte_eth_dev *dev) 328 { 329 struct priv *priv = dev->data->dev_private; 330 331 return mlx4_dev_set_link(priv, 0); 332 } 333 334 /** 335 * DPDK callback to bring the link UP. 336 * 337 * @param dev 338 * Pointer to Ethernet device structure. 339 * 340 * @return 341 * 0 on success, negative errno value otherwise and rte_errno is set. 342 */ 343 int 344 mlx4_dev_set_link_up(struct rte_eth_dev *dev) 345 { 346 struct priv *priv = dev->data->dev_private; 347 348 return mlx4_dev_set_link(priv, 1); 349 } 350 351 /** 352 * Supported Rx mode toggles. 353 * 354 * Even and odd values respectively stand for off and on. 355 */ 356 enum rxmode_toggle { 357 RXMODE_TOGGLE_PROMISC_OFF, 358 RXMODE_TOGGLE_PROMISC_ON, 359 RXMODE_TOGGLE_ALLMULTI_OFF, 360 RXMODE_TOGGLE_ALLMULTI_ON, 361 }; 362 363 /** 364 * Helper function to toggle promiscuous and all multicast modes. 365 * 366 * @param dev 367 * Pointer to Ethernet device structure. 368 * @param toggle 369 * Toggle to set. 370 */ 371 static void 372 mlx4_rxmode_toggle(struct rte_eth_dev *dev, enum rxmode_toggle toggle) 373 { 374 struct priv *priv = dev->data->dev_private; 375 const char *mode; 376 struct rte_flow_error error; 377 378 switch (toggle) { 379 case RXMODE_TOGGLE_PROMISC_OFF: 380 case RXMODE_TOGGLE_PROMISC_ON: 381 mode = "promiscuous"; 382 dev->data->promiscuous = toggle & 1; 383 break; 384 case RXMODE_TOGGLE_ALLMULTI_OFF: 385 case RXMODE_TOGGLE_ALLMULTI_ON: 386 mode = "all multicast"; 387 dev->data->all_multicast = toggle & 1; 388 break; 389 } 390 if (!mlx4_flow_sync(priv, &error)) 391 return; 392 ERROR("cannot toggle %s mode (code %d, \"%s\")," 393 " flow error type %d, cause %p, message: %s", 394 mode, rte_errno, strerror(rte_errno), error.type, error.cause, 395 error.message ? error.message : "(unspecified)"); 396 } 397 398 /** 399 * DPDK callback to enable promiscuous mode. 400 * 401 * @param dev 402 * Pointer to Ethernet device structure. 403 */ 404 void 405 mlx4_promiscuous_enable(struct rte_eth_dev *dev) 406 { 407 mlx4_rxmode_toggle(dev, RXMODE_TOGGLE_PROMISC_ON); 408 } 409 410 /** 411 * DPDK callback to disable promiscuous mode. 412 * 413 * @param dev 414 * Pointer to Ethernet device structure. 415 */ 416 void 417 mlx4_promiscuous_disable(struct rte_eth_dev *dev) 418 { 419 mlx4_rxmode_toggle(dev, RXMODE_TOGGLE_PROMISC_OFF); 420 } 421 422 /** 423 * DPDK callback to enable all multicast mode. 424 * 425 * @param dev 426 * Pointer to Ethernet device structure. 427 */ 428 void 429 mlx4_allmulticast_enable(struct rte_eth_dev *dev) 430 { 431 mlx4_rxmode_toggle(dev, RXMODE_TOGGLE_ALLMULTI_ON); 432 } 433 434 /** 435 * DPDK callback to disable all multicast mode. 436 * 437 * @param dev 438 * Pointer to Ethernet device structure. 439 */ 440 void 441 mlx4_allmulticast_disable(struct rte_eth_dev *dev) 442 { 443 mlx4_rxmode_toggle(dev, RXMODE_TOGGLE_ALLMULTI_OFF); 444 } 445 446 /** 447 * DPDK callback to remove a MAC address. 448 * 449 * @param dev 450 * Pointer to Ethernet device structure. 451 * @param index 452 * MAC address index. 453 */ 454 void 455 mlx4_mac_addr_remove(struct rte_eth_dev *dev, uint32_t index) 456 { 457 struct priv *priv = dev->data->dev_private; 458 struct rte_flow_error error; 459 460 if (index >= RTE_DIM(priv->mac)) { 461 rte_errno = EINVAL; 462 return; 463 } 464 memset(&priv->mac[index], 0, sizeof(priv->mac[index])); 465 if (!mlx4_flow_sync(priv, &error)) 466 return; 467 ERROR("failed to synchronize flow rules after removing MAC address" 468 " at index %d (code %d, \"%s\")," 469 " flow error type %d, cause %p, message: %s", 470 index, rte_errno, strerror(rte_errno), error.type, error.cause, 471 error.message ? error.message : "(unspecified)"); 472 } 473 474 /** 475 * DPDK callback to add a MAC address. 476 * 477 * @param dev 478 * Pointer to Ethernet device structure. 479 * @param mac_addr 480 * MAC address to register. 481 * @param index 482 * MAC address index. 483 * @param vmdq 484 * VMDq pool index to associate address with (ignored). 485 * 486 * @return 487 * 0 on success, negative errno value otherwise and rte_errno is set. 488 */ 489 int 490 mlx4_mac_addr_add(struct rte_eth_dev *dev, struct ether_addr *mac_addr, 491 uint32_t index, uint32_t vmdq) 492 { 493 struct priv *priv = dev->data->dev_private; 494 struct rte_flow_error error; 495 int ret; 496 497 (void)vmdq; 498 if (index >= RTE_DIM(priv->mac)) { 499 rte_errno = EINVAL; 500 return -rte_errno; 501 } 502 memcpy(&priv->mac[index], mac_addr, sizeof(priv->mac[index])); 503 ret = mlx4_flow_sync(priv, &error); 504 if (!ret) 505 return 0; 506 ERROR("failed to synchronize flow rules after adding MAC address" 507 " at index %d (code %d, \"%s\")," 508 " flow error type %d, cause %p, message: %s", 509 index, rte_errno, strerror(rte_errno), error.type, error.cause, 510 error.message ? error.message : "(unspecified)"); 511 return ret; 512 } 513 514 /** 515 * DPDK callback to configure a VLAN filter. 516 * 517 * @param dev 518 * Pointer to Ethernet device structure. 519 * @param vlan_id 520 * VLAN ID to filter. 521 * @param on 522 * Toggle filter. 523 * 524 * @return 525 * 0 on success, negative errno value otherwise and rte_errno is set. 526 */ 527 int 528 mlx4_vlan_filter_set(struct rte_eth_dev *dev, uint16_t vlan_id, int on) 529 { 530 struct priv *priv = dev->data->dev_private; 531 struct rte_flow_error error; 532 unsigned int vidx = vlan_id / 64; 533 unsigned int vbit = vlan_id % 64; 534 uint64_t *v; 535 int ret; 536 537 if (vidx >= RTE_DIM(dev->data->vlan_filter_conf.ids)) { 538 rte_errno = EINVAL; 539 return -rte_errno; 540 } 541 v = &dev->data->vlan_filter_conf.ids[vidx]; 542 *v &= ~(UINT64_C(1) << vbit); 543 *v |= (uint64_t)!!on << vbit; 544 ret = mlx4_flow_sync(priv, &error); 545 if (!ret) 546 return 0; 547 ERROR("failed to synchronize flow rules after %s VLAN filter on ID %u" 548 " (code %d, \"%s\"), " 549 " flow error type %d, cause %p, message: %s", 550 on ? "enabling" : "disabling", vlan_id, 551 rte_errno, strerror(rte_errno), error.type, error.cause, 552 error.message ? error.message : "(unspecified)"); 553 return ret; 554 } 555 556 /** 557 * DPDK callback to set the primary MAC address. 558 * 559 * @param dev 560 * Pointer to Ethernet device structure. 561 * @param mac_addr 562 * MAC address to register. 563 */ 564 void 565 mlx4_mac_addr_set(struct rte_eth_dev *dev, struct ether_addr *mac_addr) 566 { 567 mlx4_mac_addr_add(dev, mac_addr, 0, 0); 568 } 569 570 /** 571 * DPDK callback to get information about the device. 572 * 573 * @param dev 574 * Pointer to Ethernet device structure. 575 * @param[out] info 576 * Info structure output buffer. 577 */ 578 void 579 mlx4_dev_infos_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *info) 580 { 581 struct priv *priv = dev->data->dev_private; 582 unsigned int max; 583 char ifname[IF_NAMESIZE]; 584 585 info->pci_dev = RTE_ETH_DEV_TO_PCI(dev); 586 /* FIXME: we should ask the device for these values. */ 587 info->min_rx_bufsize = 32; 588 info->max_rx_pktlen = 65536; 589 /* 590 * Since we need one CQ per QP, the limit is the minimum number 591 * between the two values. 592 */ 593 max = ((priv->device_attr.max_cq > priv->device_attr.max_qp) ? 594 priv->device_attr.max_qp : priv->device_attr.max_cq); 595 /* If max >= 65535 then max = 0, max_rx_queues is uint16_t. */ 596 if (max >= 65535) 597 max = 65535; 598 info->max_rx_queues = max; 599 info->max_tx_queues = max; 600 info->max_mac_addrs = RTE_DIM(priv->mac); 601 info->rx_offload_capa = 0; 602 info->tx_offload_capa = 0; 603 if (priv->hw_csum) { 604 info->tx_offload_capa |= (DEV_TX_OFFLOAD_IPV4_CKSUM | 605 DEV_TX_OFFLOAD_UDP_CKSUM | 606 DEV_TX_OFFLOAD_TCP_CKSUM); 607 info->rx_offload_capa |= (DEV_RX_OFFLOAD_IPV4_CKSUM | 608 DEV_RX_OFFLOAD_UDP_CKSUM | 609 DEV_RX_OFFLOAD_TCP_CKSUM); 610 } 611 if (priv->hw_csum_l2tun) 612 info->tx_offload_capa |= DEV_TX_OFFLOAD_OUTER_IPV4_CKSUM; 613 if (mlx4_get_ifname(priv, &ifname) == 0) 614 info->if_index = if_nametoindex(ifname); 615 info->hash_key_size = MLX4_RSS_HASH_KEY_SIZE; 616 info->speed_capa = 617 ETH_LINK_SPEED_1G | 618 ETH_LINK_SPEED_10G | 619 ETH_LINK_SPEED_20G | 620 ETH_LINK_SPEED_40G | 621 ETH_LINK_SPEED_56G; 622 } 623 624 /** 625 * DPDK callback to get device statistics. 626 * 627 * @param dev 628 * Pointer to Ethernet device structure. 629 * @param[out] stats 630 * Stats structure output buffer. 631 */ 632 int 633 mlx4_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats) 634 { 635 struct rte_eth_stats tmp; 636 unsigned int i; 637 unsigned int idx; 638 639 memset(&tmp, 0, sizeof(tmp)); 640 /* Add software counters. */ 641 for (i = 0; i != dev->data->nb_rx_queues; ++i) { 642 struct rxq *rxq = dev->data->rx_queues[i]; 643 644 if (rxq == NULL) 645 continue; 646 idx = rxq->stats.idx; 647 if (idx < RTE_ETHDEV_QUEUE_STAT_CNTRS) { 648 tmp.q_ipackets[idx] += rxq->stats.ipackets; 649 tmp.q_ibytes[idx] += rxq->stats.ibytes; 650 tmp.q_errors[idx] += (rxq->stats.idropped + 651 rxq->stats.rx_nombuf); 652 } 653 tmp.ipackets += rxq->stats.ipackets; 654 tmp.ibytes += rxq->stats.ibytes; 655 tmp.ierrors += rxq->stats.idropped; 656 tmp.rx_nombuf += rxq->stats.rx_nombuf; 657 } 658 for (i = 0; i != dev->data->nb_tx_queues; ++i) { 659 struct txq *txq = dev->data->tx_queues[i]; 660 661 if (txq == NULL) 662 continue; 663 idx = txq->stats.idx; 664 if (idx < RTE_ETHDEV_QUEUE_STAT_CNTRS) { 665 tmp.q_opackets[idx] += txq->stats.opackets; 666 tmp.q_obytes[idx] += txq->stats.obytes; 667 tmp.q_errors[idx] += txq->stats.odropped; 668 } 669 tmp.opackets += txq->stats.opackets; 670 tmp.obytes += txq->stats.obytes; 671 tmp.oerrors += txq->stats.odropped; 672 } 673 *stats = tmp; 674 return 0; 675 } 676 677 /** 678 * DPDK callback to clear device statistics. 679 * 680 * @param dev 681 * Pointer to Ethernet device structure. 682 */ 683 void 684 mlx4_stats_reset(struct rte_eth_dev *dev) 685 { 686 unsigned int i; 687 688 for (i = 0; i != dev->data->nb_rx_queues; ++i) { 689 struct rxq *rxq = dev->data->rx_queues[i]; 690 691 if (rxq) 692 rxq->stats = (struct mlx4_rxq_stats){ 693 .idx = rxq->stats.idx, 694 }; 695 } 696 for (i = 0; i != dev->data->nb_tx_queues; ++i) { 697 struct txq *txq = dev->data->tx_queues[i]; 698 699 if (txq) 700 txq->stats = (struct mlx4_txq_stats){ 701 .idx = txq->stats.idx, 702 }; 703 } 704 } 705 706 /** 707 * DPDK callback to retrieve physical link information. 708 * 709 * @param dev 710 * Pointer to Ethernet device structure. 711 * @param wait_to_complete 712 * Wait for request completion (ignored). 713 * 714 * @return 715 * 0 on success, negative errno value otherwise and rte_errno is set. 716 */ 717 int 718 mlx4_link_update(struct rte_eth_dev *dev, int wait_to_complete) 719 { 720 const struct priv *priv = dev->data->dev_private; 721 struct ethtool_cmd edata = { 722 .cmd = ETHTOOL_GSET, 723 }; 724 struct ifreq ifr; 725 struct rte_eth_link dev_link; 726 int link_speed = 0; 727 728 if (priv == NULL) { 729 rte_errno = EINVAL; 730 return -rte_errno; 731 } 732 (void)wait_to_complete; 733 if (mlx4_ifreq(priv, SIOCGIFFLAGS, &ifr)) { 734 WARN("ioctl(SIOCGIFFLAGS) failed: %s", strerror(rte_errno)); 735 return -rte_errno; 736 } 737 memset(&dev_link, 0, sizeof(dev_link)); 738 dev_link.link_status = ((ifr.ifr_flags & IFF_UP) && 739 (ifr.ifr_flags & IFF_RUNNING)); 740 ifr.ifr_data = (void *)&edata; 741 if (mlx4_ifreq(priv, SIOCETHTOOL, &ifr)) { 742 WARN("ioctl(SIOCETHTOOL, ETHTOOL_GSET) failed: %s", 743 strerror(rte_errno)); 744 return -rte_errno; 745 } 746 link_speed = ethtool_cmd_speed(&edata); 747 if (link_speed == -1) 748 dev_link.link_speed = 0; 749 else 750 dev_link.link_speed = link_speed; 751 dev_link.link_duplex = ((edata.duplex == DUPLEX_HALF) ? 752 ETH_LINK_HALF_DUPLEX : ETH_LINK_FULL_DUPLEX); 753 dev_link.link_autoneg = !(dev->data->dev_conf.link_speeds & 754 ETH_LINK_SPEED_FIXED); 755 dev->data->dev_link = dev_link; 756 return 0; 757 } 758 759 /** 760 * DPDK callback to get flow control status. 761 * 762 * @param dev 763 * Pointer to Ethernet device structure. 764 * @param[out] fc_conf 765 * Flow control output buffer. 766 * 767 * @return 768 * 0 on success, negative errno value otherwise and rte_errno is set. 769 */ 770 int 771 mlx4_flow_ctrl_get(struct rte_eth_dev *dev, struct rte_eth_fc_conf *fc_conf) 772 { 773 struct priv *priv = dev->data->dev_private; 774 struct ifreq ifr; 775 struct ethtool_pauseparam ethpause = { 776 .cmd = ETHTOOL_GPAUSEPARAM, 777 }; 778 int ret; 779 780 ifr.ifr_data = (void *)ðpause; 781 if (mlx4_ifreq(priv, SIOCETHTOOL, &ifr)) { 782 ret = rte_errno; 783 WARN("ioctl(SIOCETHTOOL, ETHTOOL_GPAUSEPARAM)" 784 " failed: %s", 785 strerror(rte_errno)); 786 goto out; 787 } 788 fc_conf->autoneg = ethpause.autoneg; 789 if (ethpause.rx_pause && ethpause.tx_pause) 790 fc_conf->mode = RTE_FC_FULL; 791 else if (ethpause.rx_pause) 792 fc_conf->mode = RTE_FC_RX_PAUSE; 793 else if (ethpause.tx_pause) 794 fc_conf->mode = RTE_FC_TX_PAUSE; 795 else 796 fc_conf->mode = RTE_FC_NONE; 797 ret = 0; 798 out: 799 assert(ret >= 0); 800 return -ret; 801 } 802 803 /** 804 * DPDK callback to modify flow control parameters. 805 * 806 * @param dev 807 * Pointer to Ethernet device structure. 808 * @param[in] fc_conf 809 * Flow control parameters. 810 * 811 * @return 812 * 0 on success, negative errno value otherwise and rte_errno is set. 813 */ 814 int 815 mlx4_flow_ctrl_set(struct rte_eth_dev *dev, struct rte_eth_fc_conf *fc_conf) 816 { 817 struct priv *priv = dev->data->dev_private; 818 struct ifreq ifr; 819 struct ethtool_pauseparam ethpause = { 820 .cmd = ETHTOOL_SPAUSEPARAM, 821 }; 822 int ret; 823 824 ifr.ifr_data = (void *)ðpause; 825 ethpause.autoneg = fc_conf->autoneg; 826 if (((fc_conf->mode & RTE_FC_FULL) == RTE_FC_FULL) || 827 (fc_conf->mode & RTE_FC_RX_PAUSE)) 828 ethpause.rx_pause = 1; 829 else 830 ethpause.rx_pause = 0; 831 if (((fc_conf->mode & RTE_FC_FULL) == RTE_FC_FULL) || 832 (fc_conf->mode & RTE_FC_TX_PAUSE)) 833 ethpause.tx_pause = 1; 834 else 835 ethpause.tx_pause = 0; 836 if (mlx4_ifreq(priv, SIOCETHTOOL, &ifr)) { 837 ret = rte_errno; 838 WARN("ioctl(SIOCETHTOOL, ETHTOOL_SPAUSEPARAM)" 839 " failed: %s", 840 strerror(rte_errno)); 841 goto out; 842 } 843 ret = 0; 844 out: 845 assert(ret >= 0); 846 return -ret; 847 } 848 849 /** 850 * DPDK callback to retrieve the received packet types that are recognized 851 * by the device. 852 * 853 * @param dev 854 * Pointer to Ethernet device structure. 855 * 856 * @return 857 * Pointer to an array of recognized packet types if in Rx burst mode, 858 * NULL otherwise. 859 */ 860 const uint32_t * 861 mlx4_dev_supported_ptypes_get(struct rte_eth_dev *dev) 862 { 863 static const uint32_t ptypes[] = { 864 /* refers to rxq_cq_to_pkt_type() */ 865 RTE_PTYPE_L2_ETHER, 866 RTE_PTYPE_L3_IPV4_EXT_UNKNOWN, 867 RTE_PTYPE_L3_IPV6_EXT_UNKNOWN, 868 RTE_PTYPE_L4_FRAG, 869 RTE_PTYPE_L4_TCP, 870 RTE_PTYPE_L4_UDP, 871 RTE_PTYPE_UNKNOWN 872 }; 873 static const uint32_t ptypes_l2tun[] = { 874 /* refers to rxq_cq_to_pkt_type() */ 875 RTE_PTYPE_L2_ETHER, 876 RTE_PTYPE_L3_IPV4_EXT_UNKNOWN, 877 RTE_PTYPE_L3_IPV6_EXT_UNKNOWN, 878 RTE_PTYPE_L4_FRAG, 879 RTE_PTYPE_L4_TCP, 880 RTE_PTYPE_L4_UDP, 881 RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN, 882 RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN, 883 RTE_PTYPE_UNKNOWN 884 }; 885 struct priv *priv = dev->data->dev_private; 886 887 if (dev->rx_pkt_burst == mlx4_rx_burst) { 888 if (priv->hw_csum_l2tun) 889 return ptypes_l2tun; 890 else 891 return ptypes; 892 } 893 return NULL; 894 } 895