1 /* SPDX-License-Identifier: BSD-3-Clause 2 * 3 * Copyright(c) 2019-2021 Xilinx, Inc. 4 * Copyright(c) 2016-2019 Solarflare Communications Inc. 5 * 6 * This software was jointly developed between OKTET Labs (under contract 7 * for Solarflare) and Solarflare Communications, Inc. 8 */ 9 10 #include <rte_bitmap.h> 11 12 #include "efx.h" 13 14 #include "sfc.h" 15 #include "sfc_debug.h" 16 #include "sfc_log.h" 17 #include "sfc_kvargs.h" 18 19 /** Default MAC statistics update period is 1 second */ 20 #define SFC_MAC_STATS_UPDATE_PERIOD_MS_DEF MS_PER_S 21 22 /** The number of microseconds to sleep on attempt to get statistics update */ 23 #define SFC_MAC_STATS_UPDATE_RETRY_INTERVAL_US 10 24 25 /** The number of attempts to await arrival of freshly generated statistics */ 26 #define SFC_MAC_STATS_UPDATE_NB_ATTEMPTS 50 27 28 /** 29 * Update MAC statistics in the buffer. 30 * 31 * @param sa Adapter 32 * @param force_upload Flag to upload MAC stats in any case 33 * 34 * @return Status code 35 * @retval 0 Success 36 * @retval EAGAIN Try again 37 * @retval ENOMEM Memory allocation failure 38 */ 39 int 40 sfc_port_update_mac_stats(struct sfc_adapter *sa, boolean_t force_upload) 41 { 42 struct sfc_port *port = &sa->port; 43 efsys_mem_t *esmp = &port->mac_stats_dma_mem; 44 uint32_t *genp = NULL; 45 uint32_t gen_old; 46 unsigned int nb_attempts = 0; 47 int rc; 48 49 SFC_ASSERT(sfc_adapter_is_locked(sa)); 50 51 if (sa->state != SFC_ADAPTER_STARTED) 52 return 0; 53 54 /* 55 * If periodic statistics DMA'ing is off or if not supported, 56 * make a manual request and keep an eye on timer if need be 57 */ 58 if (!port->mac_stats_periodic_dma_supported || 59 (port->mac_stats_update_period_ms == 0) || force_upload) { 60 if (port->mac_stats_update_period_ms != 0) { 61 uint64_t timestamp = sfc_get_system_msecs(); 62 63 if ((timestamp - 64 port->mac_stats_last_request_timestamp) < 65 port->mac_stats_update_period_ms) 66 return 0; 67 68 port->mac_stats_last_request_timestamp = timestamp; 69 } 70 71 rc = efx_mac_stats_upload(sa->nic, esmp); 72 if (rc != 0) 73 return rc; 74 75 genp = &port->mac_stats_update_generation; 76 gen_old = *genp; 77 } 78 79 do { 80 if (nb_attempts > 0) 81 rte_delay_us(SFC_MAC_STATS_UPDATE_RETRY_INTERVAL_US); 82 83 rc = efx_mac_stats_update(sa->nic, esmp, 84 port->mac_stats_buf, genp); 85 if (rc != 0) 86 return rc; 87 88 } while ((genp != NULL) && (*genp == gen_old) && 89 (++nb_attempts < SFC_MAC_STATS_UPDATE_NB_ATTEMPTS)); 90 91 return 0; 92 } 93 94 static void 95 sfc_port_reset_sw_stats(struct sfc_adapter *sa) 96 { 97 struct sfc_port *port = &sa->port; 98 99 /* 100 * Reset diff stats explicitly since check which does not allow 101 * the statistics to grow backward could deny it. 102 */ 103 port->ipackets = 0; 104 } 105 106 int 107 sfc_port_reset_mac_stats(struct sfc_adapter *sa) 108 { 109 int rc; 110 111 SFC_ASSERT(sfc_adapter_is_locked(sa)); 112 113 rc = efx_mac_stats_clear(sa->nic); 114 if (rc == 0) 115 sfc_port_reset_sw_stats(sa); 116 117 return rc; 118 } 119 120 static int 121 sfc_port_init_dev_link(struct sfc_adapter *sa) 122 { 123 struct rte_eth_link *dev_link = &sa->eth_dev->data->dev_link; 124 int rc; 125 efx_link_mode_t link_mode; 126 struct rte_eth_link current_link; 127 128 rc = efx_port_poll(sa->nic, &link_mode); 129 if (rc != 0) 130 return rc; 131 132 sfc_port_link_mode_to_info(link_mode, ¤t_link); 133 134 EFX_STATIC_ASSERT(sizeof(*dev_link) == sizeof(rte_atomic64_t)); 135 rte_atomic64_set((rte_atomic64_t *)dev_link, 136 *(uint64_t *)¤t_link); 137 138 return 0; 139 } 140 141 #if EFSYS_OPT_LOOPBACK 142 143 static efx_link_mode_t 144 sfc_port_phy_caps_to_max_link_speed(uint32_t phy_caps) 145 { 146 if (phy_caps & (1u << EFX_PHY_CAP_100000FDX)) 147 return EFX_LINK_100000FDX; 148 if (phy_caps & (1u << EFX_PHY_CAP_50000FDX)) 149 return EFX_LINK_50000FDX; 150 if (phy_caps & (1u << EFX_PHY_CAP_40000FDX)) 151 return EFX_LINK_40000FDX; 152 if (phy_caps & (1u << EFX_PHY_CAP_25000FDX)) 153 return EFX_LINK_25000FDX; 154 if (phy_caps & (1u << EFX_PHY_CAP_10000FDX)) 155 return EFX_LINK_10000FDX; 156 if (phy_caps & (1u << EFX_PHY_CAP_1000FDX)) 157 return EFX_LINK_1000FDX; 158 return EFX_LINK_UNKNOWN; 159 } 160 161 #endif 162 163 static void 164 sfc_port_fill_mac_stats_info(struct sfc_adapter *sa) 165 { 166 unsigned int mac_stats_nb_supported = 0; 167 struct sfc_port *port = &sa->port; 168 unsigned int stat_idx; 169 170 efx_mac_stats_get_mask(sa->nic, port->mac_stats_mask, 171 sizeof(port->mac_stats_mask)); 172 173 for (stat_idx = 0; stat_idx < EFX_MAC_NSTATS; ++stat_idx) { 174 if (!EFX_MAC_STAT_SUPPORTED(port->mac_stats_mask, stat_idx)) 175 continue; 176 177 port->mac_stats_by_id[mac_stats_nb_supported] = stat_idx; 178 mac_stats_nb_supported++; 179 } 180 181 port->mac_stats_nb_supported = mac_stats_nb_supported; 182 } 183 184 int 185 sfc_port_start(struct sfc_adapter *sa) 186 { 187 struct sfc_port *port = &sa->port; 188 int rc; 189 uint32_t phy_adv_cap; 190 const uint32_t phy_pause_caps = 191 ((1u << EFX_PHY_CAP_PAUSE) | (1u << EFX_PHY_CAP_ASYM)); 192 193 sfc_log_init(sa, "entry"); 194 195 sfc_log_init(sa, "init filters"); 196 rc = efx_filter_init(sa->nic); 197 if (rc != 0) 198 goto fail_filter_init; 199 200 sfc_log_init(sa, "init port"); 201 rc = efx_port_init(sa->nic); 202 if (rc != 0) 203 goto fail_port_init; 204 205 #if EFSYS_OPT_LOOPBACK 206 if (sa->eth_dev->data->dev_conf.lpbk_mode != 0) { 207 efx_link_mode_t link_mode; 208 209 link_mode = 210 sfc_port_phy_caps_to_max_link_speed(port->phy_adv_cap); 211 sfc_log_init(sa, "set loopback link_mode=%u type=%u", link_mode, 212 sa->eth_dev->data->dev_conf.lpbk_mode); 213 rc = efx_port_loopback_set(sa->nic, link_mode, 214 sa->eth_dev->data->dev_conf.lpbk_mode); 215 if (rc != 0) 216 goto fail_loopback_set; 217 } 218 #endif 219 220 sfc_log_init(sa, "set flow control to %#x autoneg=%u", 221 port->flow_ctrl, port->flow_ctrl_autoneg); 222 rc = efx_mac_fcntl_set(sa->nic, port->flow_ctrl, 223 port->flow_ctrl_autoneg); 224 if (rc != 0) 225 goto fail_mac_fcntl_set; 226 227 /* Preserve pause capabilities set by above efx_mac_fcntl_set() */ 228 efx_phy_adv_cap_get(sa->nic, EFX_PHY_CAP_CURRENT, &phy_adv_cap); 229 SFC_ASSERT((port->phy_adv_cap & phy_pause_caps) == 0); 230 phy_adv_cap = port->phy_adv_cap | (phy_adv_cap & phy_pause_caps); 231 232 /* 233 * No controls for FEC yet. Use default FEC mode. 234 * I.e. advertise everything supported (*_FEC=1), but do not request 235 * anything explicitly (*_FEC_REQUESTED=0). 236 */ 237 phy_adv_cap |= port->phy_adv_cap_mask & 238 (1u << EFX_PHY_CAP_BASER_FEC | 239 1u << EFX_PHY_CAP_RS_FEC | 240 1u << EFX_PHY_CAP_25G_BASER_FEC); 241 242 sfc_log_init(sa, "set phy adv caps to %#x", phy_adv_cap); 243 rc = efx_phy_adv_cap_set(sa->nic, phy_adv_cap); 244 if (rc != 0) 245 goto fail_phy_adv_cap_set; 246 247 sfc_log_init(sa, "set MAC PDU %u", (unsigned int)port->pdu); 248 rc = efx_mac_pdu_set(sa->nic, port->pdu); 249 if (rc != 0) 250 goto fail_mac_pdu_set; 251 252 if (!sfc_sa2shared(sa)->isolated) { 253 struct rte_ether_addr *addr = &port->default_mac_addr; 254 255 sfc_log_init(sa, "set MAC address"); 256 rc = efx_mac_addr_set(sa->nic, addr->addr_bytes); 257 if (rc != 0) 258 goto fail_mac_addr_set; 259 260 sfc_log_init(sa, "set MAC filters"); 261 port->promisc = (sa->eth_dev->data->promiscuous != 0) ? 262 B_TRUE : B_FALSE; 263 port->allmulti = (sa->eth_dev->data->all_multicast != 0) ? 264 B_TRUE : B_FALSE; 265 rc = sfc_set_rx_mode_unchecked(sa); 266 if (rc != 0) 267 goto fail_mac_filter_set; 268 269 sfc_log_init(sa, "set multicast address list"); 270 rc = efx_mac_multicast_list_set(sa->nic, port->mcast_addrs, 271 port->nb_mcast_addrs); 272 if (rc != 0) 273 goto fail_mcast_address_list_set; 274 } 275 276 if (port->mac_stats_reset_pending) { 277 rc = sfc_port_reset_mac_stats(sa); 278 if (rc != 0) 279 sfc_err(sa, "statistics reset failed (requested " 280 "before the port was started)"); 281 282 port->mac_stats_reset_pending = B_FALSE; 283 } 284 285 sfc_port_fill_mac_stats_info(sa); 286 287 port->mac_stats_update_generation = 0; 288 289 if (port->mac_stats_update_period_ms != 0) { 290 /* 291 * Update MAC stats using periodic DMA; 292 * any positive update interval different from 293 * 1000 ms can be set only on SFN8xxx provided 294 * that FW version is 6.2.1.1033 or higher 295 */ 296 sfc_log_init(sa, "request MAC stats DMA'ing"); 297 rc = efx_mac_stats_periodic(sa->nic, &port->mac_stats_dma_mem, 298 port->mac_stats_update_period_ms, 299 B_FALSE); 300 if (rc == 0) { 301 port->mac_stats_periodic_dma_supported = B_TRUE; 302 } else if (rc == EOPNOTSUPP) { 303 port->mac_stats_periodic_dma_supported = B_FALSE; 304 port->mac_stats_last_request_timestamp = 0; 305 } else { 306 goto fail_mac_stats_periodic; 307 } 308 } 309 310 if ((port->mac_stats_update_period_ms != 0) && 311 port->mac_stats_periodic_dma_supported) { 312 /* 313 * Request an explicit MAC stats upload immediately to 314 * preclude bogus figures readback if the user decides 315 * to read stats before periodic DMA is really started 316 */ 317 rc = efx_mac_stats_upload(sa->nic, &port->mac_stats_dma_mem); 318 if (rc != 0) 319 goto fail_mac_stats_upload; 320 } 321 322 sfc_log_init(sa, "disable MAC drain"); 323 rc = efx_mac_drain(sa->nic, B_FALSE); 324 if (rc != 0) 325 goto fail_mac_drain; 326 327 /* Synchronize link status knowledge */ 328 rc = sfc_port_init_dev_link(sa); 329 if (rc != 0) 330 goto fail_port_init_dev_link; 331 332 sfc_log_init(sa, "done"); 333 return 0; 334 335 fail_port_init_dev_link: 336 (void)efx_mac_drain(sa->nic, B_TRUE); 337 338 fail_mac_drain: 339 fail_mac_stats_upload: 340 (void)efx_mac_stats_periodic(sa->nic, &port->mac_stats_dma_mem, 341 0, B_FALSE); 342 343 fail_mac_stats_periodic: 344 fail_mcast_address_list_set: 345 fail_mac_filter_set: 346 fail_mac_addr_set: 347 fail_mac_pdu_set: 348 fail_phy_adv_cap_set: 349 fail_mac_fcntl_set: 350 #if EFSYS_OPT_LOOPBACK 351 fail_loopback_set: 352 #endif 353 efx_port_fini(sa->nic); 354 355 fail_port_init: 356 efx_filter_fini(sa->nic); 357 358 fail_filter_init: 359 sfc_log_init(sa, "failed %d", rc); 360 return rc; 361 } 362 363 void 364 sfc_port_stop(struct sfc_adapter *sa) 365 { 366 sfc_log_init(sa, "entry"); 367 368 efx_mac_drain(sa->nic, B_TRUE); 369 370 (void)efx_mac_stats_periodic(sa->nic, &sa->port.mac_stats_dma_mem, 371 0, B_FALSE); 372 373 sfc_port_update_mac_stats(sa, B_TRUE); 374 375 efx_port_fini(sa->nic); 376 efx_filter_fini(sa->nic); 377 378 sfc_log_init(sa, "done"); 379 } 380 381 int 382 sfc_port_configure(struct sfc_adapter *sa) 383 { 384 const struct rte_eth_dev_data *dev_data = sa->eth_dev->data; 385 struct sfc_port *port = &sa->port; 386 const struct rte_eth_rxmode *rxmode = &dev_data->dev_conf.rxmode; 387 388 sfc_log_init(sa, "entry"); 389 390 if (rxmode->offloads & DEV_RX_OFFLOAD_JUMBO_FRAME) 391 port->pdu = rxmode->max_rx_pkt_len; 392 else 393 port->pdu = EFX_MAC_PDU(dev_data->mtu); 394 395 return 0; 396 } 397 398 void 399 sfc_port_close(struct sfc_adapter *sa) 400 { 401 sfc_log_init(sa, "entry"); 402 } 403 404 int 405 sfc_port_attach(struct sfc_adapter *sa) 406 { 407 struct sfc_port *port = &sa->port; 408 const efx_nic_cfg_t *encp = efx_nic_cfg_get(sa->nic); 409 const struct rte_ether_addr *from; 410 uint32_t mac_nstats; 411 size_t mac_stats_size; 412 long kvarg_stats_update_period_ms; 413 int rc; 414 415 sfc_log_init(sa, "entry"); 416 417 efx_phy_adv_cap_get(sa->nic, EFX_PHY_CAP_PERM, &port->phy_adv_cap_mask); 418 419 /* Enable flow control by default */ 420 port->flow_ctrl = EFX_FCNTL_RESPOND | EFX_FCNTL_GENERATE; 421 port->flow_ctrl_autoneg = B_TRUE; 422 423 RTE_BUILD_BUG_ON(sizeof(encp->enc_mac_addr) != sizeof(*from)); 424 from = (const struct rte_ether_addr *)(encp->enc_mac_addr); 425 rte_ether_addr_copy(from, &port->default_mac_addr); 426 427 port->max_mcast_addrs = EFX_MAC_MULTICAST_LIST_MAX; 428 port->nb_mcast_addrs = 0; 429 port->mcast_addrs = rte_calloc_socket("mcast_addr_list_buf", 430 port->max_mcast_addrs, 431 EFX_MAC_ADDR_LEN, 0, 432 sa->socket_id); 433 if (port->mcast_addrs == NULL) { 434 rc = ENOMEM; 435 goto fail_mcast_addr_list_buf_alloc; 436 } 437 438 rc = ENOMEM; 439 port->mac_stats_buf = rte_calloc_socket("mac_stats_buf", EFX_MAC_NSTATS, 440 sizeof(uint64_t), 0, 441 sa->socket_id); 442 if (port->mac_stats_buf == NULL) 443 goto fail_mac_stats_buf_alloc; 444 445 mac_nstats = efx_nic_cfg_get(sa->nic)->enc_mac_stats_nstats; 446 mac_stats_size = RTE_ALIGN(mac_nstats * sizeof(uint64_t), EFX_BUF_SIZE); 447 rc = sfc_dma_alloc(sa, "mac_stats", 0, mac_stats_size, 448 sa->socket_id, &port->mac_stats_dma_mem); 449 if (rc != 0) 450 goto fail_mac_stats_dma_alloc; 451 452 port->mac_stats_reset_pending = B_FALSE; 453 454 kvarg_stats_update_period_ms = SFC_MAC_STATS_UPDATE_PERIOD_MS_DEF; 455 456 rc = sfc_kvargs_process(sa, SFC_KVARG_STATS_UPDATE_PERIOD_MS, 457 sfc_kvarg_long_handler, 458 &kvarg_stats_update_period_ms); 459 if ((rc == 0) && 460 ((kvarg_stats_update_period_ms < 0) || 461 (kvarg_stats_update_period_ms > UINT16_MAX))) { 462 sfc_err(sa, "wrong '" SFC_KVARG_STATS_UPDATE_PERIOD_MS "' " 463 "was set (%ld);", kvarg_stats_update_period_ms); 464 sfc_err(sa, "it must not be less than 0 " 465 "or greater than %" PRIu16, UINT16_MAX); 466 rc = EINVAL; 467 goto fail_kvarg_stats_update_period_ms; 468 } else if (rc != 0) { 469 goto fail_kvarg_stats_update_period_ms; 470 } 471 472 port->mac_stats_update_period_ms = kvarg_stats_update_period_ms; 473 474 sfc_log_init(sa, "done"); 475 return 0; 476 477 fail_kvarg_stats_update_period_ms: 478 sfc_dma_free(sa, &port->mac_stats_dma_mem); 479 480 fail_mac_stats_dma_alloc: 481 rte_free(port->mac_stats_buf); 482 483 fail_mac_stats_buf_alloc: 484 rte_free(port->mcast_addrs); 485 486 fail_mcast_addr_list_buf_alloc: 487 sfc_log_init(sa, "failed %d", rc); 488 return rc; 489 } 490 491 void 492 sfc_port_detach(struct sfc_adapter *sa) 493 { 494 struct sfc_port *port = &sa->port; 495 496 sfc_log_init(sa, "entry"); 497 498 sfc_dma_free(sa, &port->mac_stats_dma_mem); 499 rte_free(port->mac_stats_buf); 500 501 rte_free(port->mcast_addrs); 502 503 sfc_log_init(sa, "done"); 504 } 505 506 static boolean_t 507 sfc_get_requested_all_ucast(struct sfc_port *port) 508 { 509 return port->promisc; 510 } 511 512 static boolean_t 513 sfc_get_requested_all_mcast(struct sfc_port *port) 514 { 515 return port->promisc || port->allmulti; 516 } 517 518 int 519 sfc_set_rx_mode_unchecked(struct sfc_adapter *sa) 520 { 521 struct sfc_port *port = &sa->port; 522 boolean_t requested_all_ucast = sfc_get_requested_all_ucast(port); 523 boolean_t requested_all_mcast = sfc_get_requested_all_mcast(port); 524 int rc; 525 526 rc = efx_mac_filter_set(sa->nic, requested_all_ucast, B_TRUE, 527 requested_all_mcast, B_TRUE); 528 if (rc != 0) 529 return rc; 530 531 return 0; 532 } 533 534 int 535 sfc_set_rx_mode(struct sfc_adapter *sa) 536 { 537 struct sfc_port *port = &sa->port; 538 boolean_t old_all_ucast; 539 boolean_t old_all_mcast; 540 boolean_t requested_all_ucast = sfc_get_requested_all_ucast(port); 541 boolean_t requested_all_mcast = sfc_get_requested_all_mcast(port); 542 boolean_t actual_all_ucast; 543 boolean_t actual_all_mcast; 544 int rc; 545 546 efx_mac_filter_get_all_ucast_mcast(sa->nic, &old_all_ucast, 547 &old_all_mcast); 548 549 rc = sfc_set_rx_mode_unchecked(sa); 550 if (rc != 0) 551 return rc; 552 553 efx_mac_filter_get_all_ucast_mcast(sa->nic, &actual_all_ucast, 554 &actual_all_mcast); 555 556 if (actual_all_ucast != requested_all_ucast || 557 actual_all_mcast != requested_all_mcast) { 558 /* 559 * MAC filter set succeeded but not all requested modes 560 * were applied. The rollback is necessary to bring back the 561 * consistent old state. 562 */ 563 (void)efx_mac_filter_set(sa->nic, old_all_ucast, B_TRUE, 564 old_all_mcast, B_TRUE); 565 566 return EPERM; 567 } 568 569 return 0; 570 } 571 572 void 573 sfc_port_link_mode_to_info(efx_link_mode_t link_mode, 574 struct rte_eth_link *link_info) 575 { 576 SFC_ASSERT(link_mode < EFX_LINK_NMODES); 577 578 memset(link_info, 0, sizeof(*link_info)); 579 if ((link_mode == EFX_LINK_DOWN) || (link_mode == EFX_LINK_UNKNOWN)) 580 link_info->link_status = ETH_LINK_DOWN; 581 else 582 link_info->link_status = ETH_LINK_UP; 583 584 switch (link_mode) { 585 case EFX_LINK_10HDX: 586 link_info->link_speed = ETH_SPEED_NUM_10M; 587 link_info->link_duplex = ETH_LINK_HALF_DUPLEX; 588 break; 589 case EFX_LINK_10FDX: 590 link_info->link_speed = ETH_SPEED_NUM_10M; 591 link_info->link_duplex = ETH_LINK_FULL_DUPLEX; 592 break; 593 case EFX_LINK_100HDX: 594 link_info->link_speed = ETH_SPEED_NUM_100M; 595 link_info->link_duplex = ETH_LINK_HALF_DUPLEX; 596 break; 597 case EFX_LINK_100FDX: 598 link_info->link_speed = ETH_SPEED_NUM_100M; 599 link_info->link_duplex = ETH_LINK_FULL_DUPLEX; 600 break; 601 case EFX_LINK_1000HDX: 602 link_info->link_speed = ETH_SPEED_NUM_1G; 603 link_info->link_duplex = ETH_LINK_HALF_DUPLEX; 604 break; 605 case EFX_LINK_1000FDX: 606 link_info->link_speed = ETH_SPEED_NUM_1G; 607 link_info->link_duplex = ETH_LINK_FULL_DUPLEX; 608 break; 609 case EFX_LINK_10000FDX: 610 link_info->link_speed = ETH_SPEED_NUM_10G; 611 link_info->link_duplex = ETH_LINK_FULL_DUPLEX; 612 break; 613 case EFX_LINK_25000FDX: 614 link_info->link_speed = ETH_SPEED_NUM_25G; 615 link_info->link_duplex = ETH_LINK_FULL_DUPLEX; 616 break; 617 case EFX_LINK_40000FDX: 618 link_info->link_speed = ETH_SPEED_NUM_40G; 619 link_info->link_duplex = ETH_LINK_FULL_DUPLEX; 620 break; 621 case EFX_LINK_50000FDX: 622 link_info->link_speed = ETH_SPEED_NUM_50G; 623 link_info->link_duplex = ETH_LINK_FULL_DUPLEX; 624 break; 625 case EFX_LINK_100000FDX: 626 link_info->link_speed = ETH_SPEED_NUM_100G; 627 link_info->link_duplex = ETH_LINK_FULL_DUPLEX; 628 break; 629 default: 630 SFC_ASSERT(B_FALSE); 631 /* FALLTHROUGH */ 632 case EFX_LINK_UNKNOWN: 633 case EFX_LINK_DOWN: 634 link_info->link_speed = ETH_SPEED_NUM_NONE; 635 link_info->link_duplex = 0; 636 break; 637 } 638 639 link_info->link_autoneg = ETH_LINK_AUTONEG; 640 } 641 642 int 643 sfc_port_get_mac_stats(struct sfc_adapter *sa, struct rte_eth_xstat *xstats, 644 unsigned int xstats_count, unsigned int *nb_written) 645 { 646 struct sfc_port *port = &sa->port; 647 uint64_t *mac_stats; 648 unsigned int i; 649 int nstats = 0; 650 int ret; 651 652 sfc_adapter_lock(sa); 653 654 ret = sfc_port_update_mac_stats(sa, B_FALSE); 655 if (ret != 0) { 656 SFC_ASSERT(ret > 0); 657 ret = -ret; 658 goto unlock; 659 } 660 661 mac_stats = port->mac_stats_buf; 662 663 for (i = 0; i < EFX_MAC_NSTATS; ++i) { 664 if (EFX_MAC_STAT_SUPPORTED(port->mac_stats_mask, i)) { 665 if (nstats < (int)xstats_count) { 666 xstats[nstats].id = nstats; 667 xstats[nstats].value = mac_stats[i]; 668 (*nb_written)++; 669 } 670 nstats++; 671 } 672 } 673 ret = nstats; 674 675 unlock: 676 sfc_adapter_unlock(sa); 677 678 return ret; 679 } 680 681 int 682 sfc_port_get_mac_stats_by_id(struct sfc_adapter *sa, const uint64_t *ids, 683 uint64_t *values, unsigned int n) 684 { 685 struct sfc_port *port = &sa->port; 686 uint64_t *mac_stats; 687 unsigned int i; 688 int ret; 689 int rc; 690 691 sfc_adapter_lock(sa); 692 693 rc = sfc_port_update_mac_stats(sa, B_FALSE); 694 if (rc != 0) { 695 SFC_ASSERT(rc > 0); 696 ret = -rc; 697 goto unlock; 698 } 699 700 mac_stats = port->mac_stats_buf; 701 702 SFC_ASSERT(port->mac_stats_nb_supported <= 703 RTE_DIM(port->mac_stats_by_id)); 704 705 for (i = 0; i < n; i++) { 706 if (ids[i] < port->mac_stats_nb_supported) 707 values[i] = mac_stats[port->mac_stats_by_id[ids[i]]]; 708 } 709 710 ret = 0; 711 712 unlock: 713 sfc_adapter_unlock(sa); 714 715 return ret; 716 } 717