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)[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, 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)) { 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 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)) { 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 a VLAN filter. 492 * 493 * @param dev 494 * Pointer to Ethernet device structure. 495 * @param vlan_id 496 * VLAN ID to filter. 497 * @param on 498 * Toggle filter. 499 * 500 * @return 501 * 0 on success, negative errno value otherwise and rte_errno is set. 502 */ 503 int 504 mlx4_vlan_filter_set(struct rte_eth_dev *dev, uint16_t vlan_id, int on) 505 { 506 struct mlx4_priv *priv = dev->data->dev_private; 507 struct rte_flow_error error; 508 unsigned int vidx = vlan_id / 64; 509 unsigned int vbit = vlan_id % 64; 510 uint64_t *v; 511 int ret; 512 513 if (vidx >= RTE_DIM(dev->data->vlan_filter_conf.ids)) { 514 rte_errno = EINVAL; 515 return -rte_errno; 516 } 517 v = &dev->data->vlan_filter_conf.ids[vidx]; 518 *v &= ~(UINT64_C(1) << vbit); 519 *v |= (uint64_t)!!on << vbit; 520 ret = mlx4_flow_sync(priv, &error); 521 if (!ret) 522 return 0; 523 ERROR("failed to synchronize flow rules after %s VLAN filter on ID %u" 524 " (code %d, \"%s\"), " 525 " flow error type %d, cause %p, message: %s", 526 on ? "enabling" : "disabling", vlan_id, 527 rte_errno, strerror(rte_errno), error.type, error.cause, 528 error.message ? error.message : "(unspecified)"); 529 return ret; 530 } 531 532 /** 533 * DPDK callback to set the primary MAC address. 534 * 535 * @param dev 536 * Pointer to Ethernet device structure. 537 * @param mac_addr 538 * MAC address to register. 539 * 540 * @return 541 * 0 on success, negative errno value otherwise and rte_errno is set. 542 */ 543 int 544 mlx4_mac_addr_set(struct rte_eth_dev *dev, struct ether_addr *mac_addr) 545 { 546 return mlx4_mac_addr_add(dev, mac_addr, 0, 0); 547 } 548 549 /** 550 * DPDK callback to get information about the device. 551 * 552 * @param dev 553 * Pointer to Ethernet device structure. 554 * @param[out] info 555 * Info structure output buffer. 556 */ 557 void 558 mlx4_dev_infos_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *info) 559 { 560 struct mlx4_priv *priv = dev->data->dev_private; 561 unsigned int max; 562 563 /* FIXME: we should ask the device for these values. */ 564 info->min_rx_bufsize = 32; 565 info->max_rx_pktlen = 65536; 566 /* 567 * Since we need one CQ per QP, the limit is the minimum number 568 * between the two values. 569 */ 570 max = ((priv->device_attr.max_cq > priv->device_attr.max_qp) ? 571 priv->device_attr.max_qp : priv->device_attr.max_cq); 572 /* If max >= 65535 then max = 0, max_rx_queues is uint16_t. */ 573 if (max >= 65535) 574 max = 65535; 575 info->max_rx_queues = max; 576 info->max_tx_queues = max; 577 info->max_mac_addrs = RTE_DIM(priv->mac); 578 info->tx_offload_capa = mlx4_get_tx_port_offloads(priv); 579 info->rx_queue_offload_capa = mlx4_get_rx_queue_offloads(priv); 580 info->rx_offload_capa = (mlx4_get_rx_port_offloads(priv) | 581 info->rx_queue_offload_capa); 582 info->if_index = priv->if_index; 583 info->hash_key_size = MLX4_RSS_HASH_KEY_SIZE; 584 info->speed_capa = 585 ETH_LINK_SPEED_1G | 586 ETH_LINK_SPEED_10G | 587 ETH_LINK_SPEED_20G | 588 ETH_LINK_SPEED_40G | 589 ETH_LINK_SPEED_56G; 590 info->flow_type_rss_offloads = mlx4_conv_rss_types(priv, 0, 1); 591 } 592 593 /** 594 * DPDK callback to get device statistics. 595 * 596 * @param dev 597 * Pointer to Ethernet device structure. 598 * @param[out] stats 599 * Stats structure output buffer. 600 */ 601 int 602 mlx4_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats) 603 { 604 struct rte_eth_stats tmp; 605 unsigned int i; 606 unsigned int idx; 607 608 memset(&tmp, 0, sizeof(tmp)); 609 /* Add software counters. */ 610 for (i = 0; i != dev->data->nb_rx_queues; ++i) { 611 struct rxq *rxq = dev->data->rx_queues[i]; 612 613 if (rxq == NULL) 614 continue; 615 idx = rxq->stats.idx; 616 if (idx < RTE_ETHDEV_QUEUE_STAT_CNTRS) { 617 tmp.q_ipackets[idx] += rxq->stats.ipackets; 618 tmp.q_ibytes[idx] += rxq->stats.ibytes; 619 tmp.q_errors[idx] += (rxq->stats.idropped + 620 rxq->stats.rx_nombuf); 621 } 622 tmp.ipackets += rxq->stats.ipackets; 623 tmp.ibytes += rxq->stats.ibytes; 624 tmp.ierrors += rxq->stats.idropped; 625 tmp.rx_nombuf += rxq->stats.rx_nombuf; 626 } 627 for (i = 0; i != dev->data->nb_tx_queues; ++i) { 628 struct txq *txq = dev->data->tx_queues[i]; 629 630 if (txq == NULL) 631 continue; 632 idx = txq->stats.idx; 633 if (idx < RTE_ETHDEV_QUEUE_STAT_CNTRS) { 634 tmp.q_opackets[idx] += txq->stats.opackets; 635 tmp.q_obytes[idx] += txq->stats.obytes; 636 tmp.q_errors[idx] += txq->stats.odropped; 637 } 638 tmp.opackets += txq->stats.opackets; 639 tmp.obytes += txq->stats.obytes; 640 tmp.oerrors += txq->stats.odropped; 641 } 642 *stats = tmp; 643 return 0; 644 } 645 646 /** 647 * DPDK callback to clear device statistics. 648 * 649 * @param dev 650 * Pointer to Ethernet device structure. 651 */ 652 void 653 mlx4_stats_reset(struct rte_eth_dev *dev) 654 { 655 unsigned int i; 656 657 for (i = 0; i != dev->data->nb_rx_queues; ++i) { 658 struct rxq *rxq = dev->data->rx_queues[i]; 659 660 if (rxq) 661 rxq->stats = (struct mlx4_rxq_stats){ 662 .idx = rxq->stats.idx, 663 }; 664 } 665 for (i = 0; i != dev->data->nb_tx_queues; ++i) { 666 struct txq *txq = dev->data->tx_queues[i]; 667 668 if (txq) 669 txq->stats = (struct mlx4_txq_stats){ 670 .idx = txq->stats.idx, 671 }; 672 } 673 } 674 675 /** 676 * DPDK callback to retrieve physical link information. 677 * 678 * @param dev 679 * Pointer to Ethernet device structure. 680 * @param wait_to_complete 681 * Wait for request completion (ignored). 682 * 683 * @return 684 * 0 on success, negative errno value otherwise and rte_errno is set. 685 */ 686 int 687 mlx4_link_update(struct rte_eth_dev *dev, int wait_to_complete) 688 { 689 const struct mlx4_priv *priv = dev->data->dev_private; 690 struct ethtool_cmd edata = { 691 .cmd = ETHTOOL_GSET, 692 }; 693 struct ifreq ifr; 694 struct rte_eth_link dev_link; 695 int link_speed = 0; 696 697 if (priv == NULL) { 698 rte_errno = EINVAL; 699 return -rte_errno; 700 } 701 (void)wait_to_complete; 702 if (mlx4_ifreq(priv, SIOCGIFFLAGS, &ifr)) { 703 WARN("ioctl(SIOCGIFFLAGS) failed: %s", strerror(rte_errno)); 704 return -rte_errno; 705 } 706 memset(&dev_link, 0, sizeof(dev_link)); 707 dev_link.link_status = ((ifr.ifr_flags & IFF_UP) && 708 (ifr.ifr_flags & IFF_RUNNING)); 709 ifr.ifr_data = (void *)&edata; 710 if (mlx4_ifreq(priv, SIOCETHTOOL, &ifr)) { 711 WARN("ioctl(SIOCETHTOOL, ETHTOOL_GSET) failed: %s", 712 strerror(rte_errno)); 713 return -rte_errno; 714 } 715 link_speed = ethtool_cmd_speed(&edata); 716 if (link_speed == -1) 717 dev_link.link_speed = ETH_SPEED_NUM_NONE; 718 else 719 dev_link.link_speed = link_speed; 720 dev_link.link_duplex = ((edata.duplex == DUPLEX_HALF) ? 721 ETH_LINK_HALF_DUPLEX : ETH_LINK_FULL_DUPLEX); 722 dev_link.link_autoneg = !(dev->data->dev_conf.link_speeds & 723 ETH_LINK_SPEED_FIXED); 724 dev->data->dev_link = dev_link; 725 return 0; 726 } 727 728 /** 729 * DPDK callback to get flow control status. 730 * 731 * @param dev 732 * Pointer to Ethernet device structure. 733 * @param[out] fc_conf 734 * Flow control output buffer. 735 * 736 * @return 737 * 0 on success, negative errno value otherwise and rte_errno is set. 738 */ 739 int 740 mlx4_flow_ctrl_get(struct rte_eth_dev *dev, struct rte_eth_fc_conf *fc_conf) 741 { 742 struct mlx4_priv *priv = dev->data->dev_private; 743 struct ifreq ifr; 744 struct ethtool_pauseparam ethpause = { 745 .cmd = ETHTOOL_GPAUSEPARAM, 746 }; 747 int ret; 748 749 ifr.ifr_data = (void *)ðpause; 750 if (mlx4_ifreq(priv, SIOCETHTOOL, &ifr)) { 751 ret = rte_errno; 752 WARN("ioctl(SIOCETHTOOL, ETHTOOL_GPAUSEPARAM)" 753 " failed: %s", 754 strerror(rte_errno)); 755 goto out; 756 } 757 fc_conf->autoneg = ethpause.autoneg; 758 if (ethpause.rx_pause && ethpause.tx_pause) 759 fc_conf->mode = RTE_FC_FULL; 760 else if (ethpause.rx_pause) 761 fc_conf->mode = RTE_FC_RX_PAUSE; 762 else if (ethpause.tx_pause) 763 fc_conf->mode = RTE_FC_TX_PAUSE; 764 else 765 fc_conf->mode = RTE_FC_NONE; 766 ret = 0; 767 out: 768 assert(ret >= 0); 769 return -ret; 770 } 771 772 /** 773 * DPDK callback to modify flow control parameters. 774 * 775 * @param dev 776 * Pointer to Ethernet device structure. 777 * @param[in] fc_conf 778 * Flow control parameters. 779 * 780 * @return 781 * 0 on success, negative errno value otherwise and rte_errno is set. 782 */ 783 int 784 mlx4_flow_ctrl_set(struct rte_eth_dev *dev, struct rte_eth_fc_conf *fc_conf) 785 { 786 struct mlx4_priv *priv = dev->data->dev_private; 787 struct ifreq ifr; 788 struct ethtool_pauseparam ethpause = { 789 .cmd = ETHTOOL_SPAUSEPARAM, 790 }; 791 int ret; 792 793 ifr.ifr_data = (void *)ðpause; 794 ethpause.autoneg = fc_conf->autoneg; 795 if (((fc_conf->mode & RTE_FC_FULL) == RTE_FC_FULL) || 796 (fc_conf->mode & RTE_FC_RX_PAUSE)) 797 ethpause.rx_pause = 1; 798 else 799 ethpause.rx_pause = 0; 800 if (((fc_conf->mode & RTE_FC_FULL) == RTE_FC_FULL) || 801 (fc_conf->mode & RTE_FC_TX_PAUSE)) 802 ethpause.tx_pause = 1; 803 else 804 ethpause.tx_pause = 0; 805 if (mlx4_ifreq(priv, SIOCETHTOOL, &ifr)) { 806 ret = rte_errno; 807 WARN("ioctl(SIOCETHTOOL, ETHTOOL_SPAUSEPARAM)" 808 " failed: %s", 809 strerror(rte_errno)); 810 goto out; 811 } 812 ret = 0; 813 out: 814 assert(ret >= 0); 815 return -ret; 816 } 817 818 /** 819 * DPDK callback to retrieve the received packet types that are recognized 820 * by the device. 821 * 822 * @param dev 823 * Pointer to Ethernet device structure. 824 * 825 * @return 826 * Pointer to an array of recognized packet types if in Rx burst mode, 827 * NULL otherwise. 828 */ 829 const uint32_t * 830 mlx4_dev_supported_ptypes_get(struct rte_eth_dev *dev) 831 { 832 static const uint32_t ptypes[] = { 833 /* refers to rxq_cq_to_pkt_type() */ 834 RTE_PTYPE_L2_ETHER, 835 RTE_PTYPE_L3_IPV4_EXT_UNKNOWN, 836 RTE_PTYPE_L3_IPV6_EXT_UNKNOWN, 837 RTE_PTYPE_L4_FRAG, 838 RTE_PTYPE_L4_TCP, 839 RTE_PTYPE_L4_UDP, 840 RTE_PTYPE_UNKNOWN 841 }; 842 static const uint32_t ptypes_l2tun[] = { 843 /* refers to rxq_cq_to_pkt_type() */ 844 RTE_PTYPE_L2_ETHER, 845 RTE_PTYPE_L3_IPV4_EXT_UNKNOWN, 846 RTE_PTYPE_L3_IPV6_EXT_UNKNOWN, 847 RTE_PTYPE_L4_FRAG, 848 RTE_PTYPE_L4_TCP, 849 RTE_PTYPE_L4_UDP, 850 RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN, 851 RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN, 852 RTE_PTYPE_UNKNOWN 853 }; 854 struct mlx4_priv *priv = dev->data->dev_private; 855 856 if (dev->rx_pkt_burst == mlx4_rx_burst) { 857 if (priv->hw_csum_l2tun) 858 return ptypes_l2tun; 859 else 860 return ptypes; 861 } 862 return NULL; 863 } 864 865 /** 866 * Check if mlx4 device was removed. 867 * 868 * @param dev 869 * Pointer to Ethernet device structure. 870 * 871 * @return 872 * 1 when device is removed, otherwise 0. 873 */ 874 int 875 mlx4_is_removed(struct rte_eth_dev *dev) 876 { 877 struct ibv_device_attr device_attr; 878 struct mlx4_priv *priv = dev->data->dev_private; 879 880 if (mlx4_glue->query_device(priv->ctx, &device_attr) == EIO) 881 return 1; 882 return 0; 883 } 884