1 /* SPDX-License-Identifier: BSD-3-Clause 2 * 3 * Copyright(c) 2021 Xilinx, Inc. 4 */ 5 #include <rte_dev.h> 6 #include <rte_bitmap.h> 7 8 #include "sfc.h" 9 #include "sfc_rx.h" 10 #include "sfc_tx.h" 11 #include "sfc_sw_stats.h" 12 13 #define SFC_SW_STAT_INVALID UINT64_MAX 14 15 #define SFC_SW_STATS_GROUP_SIZE_MAX 2U 16 #define SFC_SW_STAT_GOOD_PACKETS "packets" 17 #define SFC_SW_STAT_GOOD_BYTES "bytes" 18 19 enum sfc_sw_stats_type { 20 SFC_SW_STATS_RX, 21 SFC_SW_STATS_TX, 22 }; 23 24 enum sfc_sw_stats_group_basic { 25 SFC_SW_STATS_GROUP_BASIC_PKTS = 0, 26 SFC_SW_STATS_GROUP_BASIC_BYTES, 27 SFX_SW_STATS_GROUP_BASIC_MAX 28 }; 29 30 typedef void sfc_get_sw_stat_val_t(struct sfc_adapter *sa, uint16_t qid, 31 uint64_t *values, unsigned int values_count); 32 33 struct sfc_sw_stat_descr { 34 const char *name; 35 enum sfc_sw_stats_type type; 36 sfc_get_sw_stat_val_t *get_val; 37 bool provide_total; 38 }; 39 40 static sfc_get_sw_stat_val_t sfc_sw_stat_get_rx_good_pkts_bytes; 41 static void 42 sfc_sw_stat_get_rx_good_pkts_bytes(struct sfc_adapter *sa, uint16_t qid, 43 uint64_t *values, 44 unsigned int values_count) 45 { 46 struct sfc_adapter_shared *sas = sfc_sa2shared(sa); 47 struct sfc_rxq_info *rxq_info; 48 union sfc_pkts_bytes qstats; 49 50 RTE_SET_USED(values_count); 51 SFC_ASSERT(values_count == SFX_SW_STATS_GROUP_BASIC_MAX); 52 rxq_info = sfc_rxq_info_by_ethdev_qid(sas, qid); 53 if (rxq_info->state & SFC_RXQ_INITIALIZED) { 54 sfc_pkts_bytes_get(&rxq_info->dp->dpq.stats, &qstats); 55 values[SFC_SW_STATS_GROUP_BASIC_PKTS] = qstats.pkts; 56 values[SFC_SW_STATS_GROUP_BASIC_BYTES] = qstats.bytes; 57 } else { 58 values[SFC_SW_STATS_GROUP_BASIC_PKTS] = 0; 59 values[SFC_SW_STATS_GROUP_BASIC_BYTES] = 0; 60 } 61 } 62 63 static sfc_get_sw_stat_val_t sfc_sw_stat_get_tx_good_pkts_bytes; 64 static void 65 sfc_sw_stat_get_tx_good_pkts_bytes(struct sfc_adapter *sa, uint16_t qid, 66 uint64_t *values, 67 unsigned int values_count) 68 { 69 struct sfc_adapter_shared *sas = sfc_sa2shared(sa); 70 struct sfc_txq_info *txq_info; 71 union sfc_pkts_bytes qstats; 72 73 RTE_SET_USED(values_count); 74 SFC_ASSERT(values_count == SFX_SW_STATS_GROUP_BASIC_MAX); 75 txq_info = sfc_txq_info_by_ethdev_qid(sas, qid); 76 if (txq_info->state & SFC_TXQ_INITIALIZED) { 77 sfc_pkts_bytes_get(&txq_info->dp->dpq.stats, &qstats); 78 values[SFC_SW_STATS_GROUP_BASIC_PKTS] = qstats.pkts; 79 values[SFC_SW_STATS_GROUP_BASIC_BYTES] = qstats.bytes; 80 } else { 81 values[SFC_SW_STATS_GROUP_BASIC_PKTS] = 0; 82 values[SFC_SW_STATS_GROUP_BASIC_BYTES] = 0; 83 } 84 } 85 86 static sfc_get_sw_stat_val_t sfc_get_sw_stat_val_rx_dbells; 87 static void 88 sfc_get_sw_stat_val_rx_dbells(struct sfc_adapter *sa, uint16_t qid, 89 uint64_t *values, unsigned int values_count) 90 { 91 struct sfc_adapter_shared *sas = sfc_sa2shared(sa); 92 struct sfc_rxq_info *rxq_info; 93 94 RTE_SET_USED(values_count); 95 SFC_ASSERT(values_count == 1); 96 rxq_info = sfc_rxq_info_by_ethdev_qid(sas, qid); 97 values[0] = rxq_info->state & SFC_RXQ_INITIALIZED ? 98 rxq_info->dp->dpq.rx_dbells : 0; 99 } 100 101 static sfc_get_sw_stat_val_t sfc_get_sw_stat_val_tx_dbells; 102 static void 103 sfc_get_sw_stat_val_tx_dbells(struct sfc_adapter *sa, uint16_t qid, 104 uint64_t *values, unsigned int values_count) 105 { 106 struct sfc_adapter_shared *sas = sfc_sa2shared(sa); 107 struct sfc_txq_info *txq_info; 108 109 RTE_SET_USED(values_count); 110 SFC_ASSERT(values_count == 1); 111 txq_info = sfc_txq_info_by_ethdev_qid(sas, qid); 112 values[0] = txq_info->state & SFC_TXQ_INITIALIZED ? 113 txq_info->dp->dpq.tx_dbells : 0; 114 } 115 116 /* 117 * SW stats can be grouped together. When stats are grouped the corresponding 118 * stats values for each queue are obtained during calling one get value 119 * callback. Stats of the same group are contiguous in the structure below. 120 * The start of the group is denoted by stat implementing get value callback. 121 */ 122 const struct sfc_sw_stat_descr sfc_sw_stats_descr[] = { 123 /* Group of Rx packets/bytes stats */ 124 { 125 .name = SFC_SW_STAT_GOOD_PACKETS, 126 .type = SFC_SW_STATS_RX, 127 .get_val = sfc_sw_stat_get_rx_good_pkts_bytes, 128 .provide_total = false, 129 }, 130 { 131 .name = SFC_SW_STAT_GOOD_BYTES, 132 .type = SFC_SW_STATS_RX, 133 .get_val = NULL, 134 .provide_total = false, 135 }, 136 /* Group of Tx packets/bytes stats */ 137 { 138 .name = SFC_SW_STAT_GOOD_PACKETS, 139 .type = SFC_SW_STATS_TX, 140 .get_val = sfc_sw_stat_get_tx_good_pkts_bytes, 141 .provide_total = false, 142 }, 143 { 144 .name = SFC_SW_STAT_GOOD_BYTES, 145 .type = SFC_SW_STATS_TX, 146 .get_val = NULL, 147 .provide_total = false, 148 }, 149 /* End of basic stats */ 150 { 151 .name = "dbells", 152 .type = SFC_SW_STATS_RX, 153 .get_val = sfc_get_sw_stat_val_rx_dbells, 154 .provide_total = true, 155 }, 156 { 157 .name = "dbells", 158 .type = SFC_SW_STATS_TX, 159 .get_val = sfc_get_sw_stat_val_tx_dbells, 160 .provide_total = true, 161 } 162 }; 163 164 static int 165 sfc_sw_stat_get_name(struct sfc_adapter *sa, 166 const struct sfc_sw_stat_descr *sw_stat, char *name, 167 size_t name_size, unsigned int id_off) 168 { 169 const char *prefix; 170 int ret; 171 172 switch (sw_stat->type) { 173 case SFC_SW_STATS_RX: 174 prefix = "rx"; 175 break; 176 case SFC_SW_STATS_TX: 177 prefix = "tx"; 178 break; 179 default: 180 sfc_err(sa, "%s: unknown software statistics type %d", 181 __func__, sw_stat->type); 182 return -EINVAL; 183 } 184 185 if (sw_stat->provide_total && id_off == 0) { 186 ret = snprintf(name, name_size, "%s_%s", prefix, 187 sw_stat->name); 188 if (ret < 0 || ret >= (int)name_size) { 189 sfc_err(sa, "%s: failed to fill xstat name %s_%s, err %d", 190 __func__, prefix, sw_stat->name, ret); 191 return ret > 0 ? -EINVAL : ret; 192 } 193 } else { 194 uint16_t qid = id_off - sw_stat->provide_total; 195 ret = snprintf(name, name_size, "%s_q%u_%s", prefix, qid, 196 sw_stat->name); 197 if (ret < 0 || ret >= (int)name_size) { 198 sfc_err(sa, "%s: failed to fill xstat name %s_q%u_%s, err %d", 199 __func__, prefix, qid, sw_stat->name, ret); 200 return ret > 0 ? -EINVAL : ret; 201 } 202 } 203 204 return 0; 205 } 206 207 static unsigned int 208 sfc_sw_stat_get_queue_count(struct sfc_adapter *sa, 209 const struct sfc_sw_stat_descr *sw_stat) 210 { 211 struct sfc_adapter_shared *sas = sfc_sa2shared(sa); 212 213 switch (sw_stat->type) { 214 case SFC_SW_STATS_RX: 215 return sas->ethdev_rxq_count; 216 case SFC_SW_STATS_TX: 217 return sas->ethdev_txq_count; 218 default: 219 sfc_err(sa, "%s: unknown software statistics type %d", 220 __func__, sw_stat->type); 221 return 0; 222 } 223 } 224 225 static unsigned int 226 sfc_sw_xstat_per_queue_get_count(const struct sfc_sw_stat_descr *sw_stat, 227 unsigned int nb_queues) 228 { 229 /* Take into account the total xstat of all queues */ 230 return nb_queues > 0 ? sw_stat->provide_total + nb_queues : 0; 231 } 232 233 static unsigned int 234 sfc_sw_xstat_get_nb_supported(struct sfc_adapter *sa, 235 const struct sfc_sw_stat_descr *sw_stat) 236 { 237 unsigned int nb_queues; 238 239 nb_queues = sfc_sw_stat_get_queue_count(sa, sw_stat); 240 return sfc_sw_xstat_per_queue_get_count(sw_stat, nb_queues); 241 } 242 243 static int 244 sfc_sw_stat_get_names(struct sfc_adapter *sa, 245 const struct sfc_sw_stat_descr *sw_stat, 246 struct rte_eth_xstat_name *xstats_names, 247 unsigned int xstats_names_sz, 248 unsigned int *nb_written, 249 unsigned int *nb_supported) 250 { 251 const size_t name_size = sizeof(xstats_names[0].name); 252 unsigned int id_base = *nb_supported; 253 unsigned int nb_queues; 254 unsigned int qid; 255 int rc; 256 257 nb_queues = sfc_sw_stat_get_queue_count(sa, sw_stat); 258 if (nb_queues == 0) 259 return 0; 260 *nb_supported += sfc_sw_xstat_per_queue_get_count(sw_stat, nb_queues); 261 262 /* 263 * The order of each software xstat type is the total xstat 264 * followed by per-queue xstats. 265 */ 266 if (*nb_written < xstats_names_sz && sw_stat->provide_total) { 267 rc = sfc_sw_stat_get_name(sa, sw_stat, 268 xstats_names[*nb_written].name, 269 name_size, *nb_written - id_base); 270 if (rc != 0) 271 return rc; 272 (*nb_written)++; 273 } 274 275 for (qid = 0; qid < nb_queues; ++qid) { 276 if (*nb_written < xstats_names_sz) { 277 rc = sfc_sw_stat_get_name(sa, sw_stat, 278 xstats_names[*nb_written].name, 279 name_size, *nb_written - id_base); 280 if (rc != 0) 281 return rc; 282 (*nb_written)++; 283 } 284 } 285 286 return 0; 287 } 288 289 static int 290 sfc_sw_xstat_get_names_by_id(struct sfc_adapter *sa, 291 const struct sfc_sw_stat_descr *sw_stat, 292 const uint64_t *ids, 293 struct rte_eth_xstat_name *xstats_names, 294 unsigned int size, 295 unsigned int *nb_supported) 296 { 297 const size_t name_size = sizeof(xstats_names[0].name); 298 unsigned int id_base = *nb_supported; 299 unsigned int id_end; 300 unsigned int nb_queues; 301 unsigned int i; 302 int rc; 303 304 nb_queues = sfc_sw_stat_get_queue_count(sa, sw_stat); 305 if (nb_queues == 0) 306 return 0; 307 *nb_supported += sfc_sw_xstat_per_queue_get_count(sw_stat, nb_queues); 308 309 /* 310 * The order of each software xstat type is the total xstat 311 * followed by per-queue xstats. 312 */ 313 id_end = id_base + sw_stat->provide_total + nb_queues; 314 for (i = 0; i < size; i++) { 315 if (id_base <= ids[i] && ids[i] < id_end) { 316 rc = sfc_sw_stat_get_name(sa, sw_stat, 317 xstats_names[i].name, 318 name_size, ids[i] - id_base); 319 if (rc != 0) 320 return rc; 321 } 322 } 323 324 return 0; 325 } 326 327 static uint64_t 328 sfc_sw_stat_get_val(struct sfc_adapter *sa, 329 unsigned int sw_stat_idx, uint16_t qid) 330 { 331 struct sfc_sw_stats *sw_stats = &sa->sw_stats; 332 uint64_t *res = &sw_stats->supp[sw_stat_idx].cache[qid]; 333 uint64_t values[SFC_SW_STATS_GROUP_SIZE_MAX]; 334 unsigned int group_start_idx; 335 unsigned int group_size; 336 unsigned int i; 337 338 if (*res != SFC_SW_STAT_INVALID) 339 return *res; 340 341 /* 342 * Search for the group start, i.e. the stat that implements 343 * get value callback. 344 */ 345 group_start_idx = sw_stat_idx; 346 while (sw_stats->supp[group_start_idx].descr->get_val == NULL) 347 group_start_idx--; 348 349 /* 350 * Calculate number of elements in the group with loop till the next 351 * group start or the list end. 352 */ 353 group_size = 1; 354 for (i = sw_stat_idx + 1; i < sw_stats->supp_count; i++) { 355 if (sw_stats->supp[i].descr->get_val != NULL) 356 break; 357 group_size++; 358 } 359 group_size += sw_stat_idx - group_start_idx; 360 361 SFC_ASSERT(group_size <= SFC_SW_STATS_GROUP_SIZE_MAX); 362 sw_stats->supp[group_start_idx].descr->get_val(sa, qid, values, 363 group_size); 364 for (i = group_start_idx; i < (group_start_idx + group_size); i++) 365 sw_stats->supp[i].cache[qid] = values[i - group_start_idx]; 366 367 return *res; 368 } 369 370 static void 371 sfc_sw_xstat_get_values(struct sfc_adapter *sa, 372 const struct sfc_sw_stat_descr *sw_stat, 373 unsigned int sw_stat_idx, 374 struct rte_eth_xstat *xstats, 375 unsigned int xstats_size, 376 unsigned int *nb_written, 377 unsigned int *nb_supported) 378 { 379 unsigned int qid; 380 uint64_t value; 381 struct rte_eth_xstat *total_xstat; 382 bool count_total_value = false; 383 unsigned int nb_queues; 384 385 nb_queues = sfc_sw_stat_get_queue_count(sa, sw_stat); 386 if (nb_queues == 0) 387 return; 388 *nb_supported += sfc_sw_xstat_per_queue_get_count(sw_stat, nb_queues); 389 390 /* 391 * The order of each software xstat type is the total xstat 392 * followed by per-queue xstats. 393 */ 394 if (*nb_written < xstats_size && sw_stat->provide_total) { 395 count_total_value = true; 396 total_xstat = &xstats[*nb_written]; 397 xstats[*nb_written].id = *nb_written; 398 xstats[*nb_written].value = 0; 399 (*nb_written)++; 400 } 401 402 for (qid = 0; qid < nb_queues; ++qid) { 403 value = sfc_sw_stat_get_val(sa, sw_stat_idx, qid); 404 405 if (*nb_written < xstats_size) { 406 xstats[*nb_written].id = *nb_written; 407 xstats[*nb_written].value = value; 408 (*nb_written)++; 409 } 410 411 if (count_total_value) 412 total_xstat->value += value; 413 } 414 } 415 416 static void 417 sfc_sw_xstat_get_values_by_id(struct sfc_adapter *sa, 418 const struct sfc_sw_stat_descr *sw_stat, 419 unsigned int sw_stat_idx, 420 const uint64_t *ids, 421 uint64_t *values, 422 unsigned int ids_size, 423 unsigned int *nb_supported) 424 { 425 rte_spinlock_t *bmp_lock = &sa->sw_stats.queues_bitmap_lock; 426 struct rte_bitmap *bmp = sa->sw_stats.queues_bitmap; 427 unsigned int id_base = *nb_supported; 428 unsigned int id_base_q; 429 unsigned int id_end; 430 bool count_total_value = false; 431 unsigned int total_value_idx; 432 uint64_t total_value = 0; 433 unsigned int i, qid; 434 unsigned int nb_queues; 435 436 437 rte_spinlock_lock(bmp_lock); 438 rte_bitmap_reset(bmp); 439 440 nb_queues = sfc_sw_stat_get_queue_count(sa, sw_stat); 441 if (nb_queues == 0) 442 goto unlock; 443 *nb_supported += sfc_sw_xstat_per_queue_get_count(sw_stat, nb_queues); 444 445 /* 446 * The order of each software xstat type is the total xstat 447 * followed by per-queue xstats. 448 */ 449 id_end = id_base + sw_stat->provide_total + nb_queues; 450 for (i = 0; i < ids_size; i++) { 451 if (id_base <= ids[i] && ids[i] < id_end) { 452 if (sw_stat->provide_total && ids[i] == id_base) { 453 /* Accumulative value */ 454 count_total_value = true; 455 total_value_idx = i; 456 continue; 457 } 458 id_base_q = id_base + sw_stat->provide_total; 459 qid = ids[i] - id_base_q; 460 values[i] = sfc_sw_stat_get_val(sa, sw_stat_idx, qid); 461 total_value += values[i]; 462 463 rte_bitmap_set(bmp, qid); 464 } 465 } 466 467 if (count_total_value) { 468 values[total_value_idx] = 0; 469 for (qid = 0; qid < nb_queues; ++qid) { 470 if (rte_bitmap_get(bmp, qid) != 0) 471 continue; 472 values[total_value_idx] += sfc_sw_stat_get_val(sa, 473 sw_stat_idx, 474 qid); 475 } 476 values[total_value_idx] += total_value; 477 } 478 479 unlock: 480 rte_spinlock_unlock(bmp_lock); 481 } 482 483 unsigned int 484 sfc_sw_xstats_get_nb_supported(struct sfc_adapter *sa) 485 { 486 SFC_ASSERT(sfc_adapter_is_locked(sa)); 487 return sa->sw_stats.xstats_count; 488 } 489 490 static void 491 sfc_sw_stats_clear_cache(struct sfc_adapter *sa) 492 { 493 unsigned int cache_count = sa->sw_stats.cache_count; 494 uint64_t *cache = sa->sw_stats.cache; 495 496 RTE_BUILD_BUG_ON(UINT64_C(0xffffffffffffffff) != SFC_SW_STAT_INVALID); 497 memset(cache, 0xff, cache_count * sizeof(*cache)); 498 } 499 500 void 501 sfc_sw_xstats_get_vals(struct sfc_adapter *sa, 502 struct rte_eth_xstat *xstats, 503 unsigned int xstats_count, 504 unsigned int *nb_written, 505 unsigned int *nb_supported) 506 { 507 uint64_t *reset_vals = sa->sw_stats.reset_vals; 508 struct sfc_sw_stats *sw_stats = &sa->sw_stats; 509 unsigned int sw_xstats_offset; 510 unsigned int i; 511 512 sfc_adapter_lock(sa); 513 514 sfc_sw_stats_clear_cache(sa); 515 516 sw_xstats_offset = *nb_supported; 517 518 for (i = 0; i < sw_stats->supp_count; i++) { 519 sfc_sw_xstat_get_values(sa, sw_stats->supp[i].descr, i, 520 xstats, xstats_count, nb_written, nb_supported); 521 } 522 523 for (i = sw_xstats_offset; i < *nb_written; i++) 524 xstats[i].value -= reset_vals[i - sw_xstats_offset]; 525 526 sfc_adapter_unlock(sa); 527 } 528 529 int 530 sfc_sw_xstats_get_names(struct sfc_adapter *sa, 531 struct rte_eth_xstat_name *xstats_names, 532 unsigned int xstats_count, 533 unsigned int *nb_written, 534 unsigned int *nb_supported) 535 { 536 struct sfc_sw_stats *sw_stats = &sa->sw_stats; 537 unsigned int i; 538 int ret; 539 540 sfc_adapter_lock(sa); 541 542 for (i = 0; i < sw_stats->supp_count; i++) { 543 ret = sfc_sw_stat_get_names(sa, sw_stats->supp[i].descr, 544 xstats_names, xstats_count, 545 nb_written, nb_supported); 546 if (ret != 0) { 547 sfc_adapter_unlock(sa); 548 return ret; 549 } 550 } 551 552 sfc_adapter_unlock(sa); 553 554 return 0; 555 } 556 557 void 558 sfc_sw_xstats_get_vals_by_id(struct sfc_adapter *sa, 559 const uint64_t *ids, 560 uint64_t *values, 561 unsigned int n, 562 unsigned int *nb_supported) 563 { 564 uint64_t *reset_vals = sa->sw_stats.reset_vals; 565 struct sfc_sw_stats *sw_stats = &sa->sw_stats; 566 unsigned int sw_xstats_offset; 567 unsigned int i; 568 569 sfc_adapter_lock(sa); 570 571 sfc_sw_stats_clear_cache(sa); 572 573 sw_xstats_offset = *nb_supported; 574 575 for (i = 0; i < sw_stats->supp_count; i++) { 576 sfc_sw_xstat_get_values_by_id(sa, sw_stats->supp[i].descr, i, 577 ids, values, n, nb_supported); 578 } 579 580 for (i = 0; i < n; i++) { 581 if (sw_xstats_offset <= ids[i] && ids[i] < *nb_supported) 582 values[i] -= reset_vals[ids[i] - sw_xstats_offset]; 583 } 584 585 sfc_adapter_unlock(sa); 586 } 587 588 int 589 sfc_sw_xstats_get_names_by_id(struct sfc_adapter *sa, 590 const uint64_t *ids, 591 struct rte_eth_xstat_name *xstats_names, 592 unsigned int size, 593 unsigned int *nb_supported) 594 { 595 struct sfc_sw_stats *sw_stats = &sa->sw_stats; 596 unsigned int i; 597 int ret; 598 599 sfc_adapter_lock(sa); 600 601 for (i = 0; i < sw_stats->supp_count; i++) { 602 ret = sfc_sw_xstat_get_names_by_id(sa, sw_stats->supp[i].descr, 603 ids, xstats_names, size, 604 nb_supported); 605 if (ret != 0) { 606 sfc_adapter_unlock(sa); 607 SFC_ASSERT(ret < 0); 608 return ret; 609 } 610 } 611 612 sfc_adapter_unlock(sa); 613 614 return 0; 615 } 616 617 static void 618 sfc_sw_xstat_reset(struct sfc_adapter *sa, 619 const struct sfc_sw_stat_descr *sw_stat, 620 unsigned int sw_stat_idx, 621 uint64_t *reset_vals) 622 { 623 unsigned int nb_queues; 624 unsigned int qid; 625 uint64_t *total_xstat_reset = NULL; 626 627 SFC_ASSERT(sfc_adapter_is_locked(sa)); 628 629 nb_queues = sfc_sw_stat_get_queue_count(sa, sw_stat); 630 if (nb_queues == 0) 631 return; 632 633 /* 634 * The order of each software xstat type is the total xstat 635 * followed by per-queue xstats. 636 */ 637 if (sw_stat->provide_total) { 638 total_xstat_reset = reset_vals; 639 *total_xstat_reset = 0; 640 reset_vals++; 641 } 642 643 for (qid = 0; qid < nb_queues; ++qid) { 644 reset_vals[qid] = sfc_sw_stat_get_val(sa, sw_stat_idx, qid); 645 if (sw_stat->provide_total) 646 *total_xstat_reset += reset_vals[qid]; 647 } 648 } 649 650 void 651 sfc_sw_xstats_reset(struct sfc_adapter *sa) 652 { 653 uint64_t *reset_vals = sa->sw_stats.reset_vals; 654 struct sfc_sw_stats *sw_stats = &sa->sw_stats; 655 unsigned int i; 656 657 SFC_ASSERT(sfc_adapter_is_locked(sa)); 658 659 sfc_sw_stats_clear_cache(sa); 660 661 for (i = 0; i < sw_stats->supp_count; i++) { 662 sfc_sw_xstat_reset(sa, sw_stats->supp[i].descr, i, reset_vals); 663 reset_vals += sfc_sw_xstat_get_nb_supported(sa, 664 sw_stats->supp[i].descr); 665 } 666 } 667 668 static bool 669 sfc_sw_stats_is_packets_or_bytes(const char *xstat_name) 670 { 671 return strcmp(xstat_name, SFC_SW_STAT_GOOD_PACKETS) == 0 || 672 strcmp(xstat_name, SFC_SW_STAT_GOOD_BYTES) == 0; 673 } 674 675 static void 676 sfc_sw_stats_fill_available_descr(struct sfc_adapter *sa) 677 { 678 const struct sfc_adapter_priv *sap = &sa->priv; 679 bool have_dp_rx_stats = sap->dp_rx->features & SFC_DP_RX_FEAT_STATS; 680 bool have_dp_tx_stats = sap->dp_tx->features & SFC_DP_TX_FEAT_STATS; 681 struct sfc_sw_stats *sw_stats = &sa->sw_stats; 682 const struct sfc_sw_stat_descr *sw_stat_descr; 683 unsigned int i; 684 685 sw_stats->supp_count = 0; 686 for (i = 0; i < RTE_DIM(sfc_sw_stats_descr); i++) { 687 sw_stat_descr = &sfc_sw_stats_descr[i]; 688 if (!have_dp_rx_stats && 689 sw_stat_descr->type == SFC_SW_STATS_RX && 690 sfc_sw_stats_is_packets_or_bytes(sw_stat_descr->name)) 691 continue; 692 if (!have_dp_tx_stats && 693 sw_stat_descr->type == SFC_SW_STATS_TX && 694 sfc_sw_stats_is_packets_or_bytes(sw_stat_descr->name)) 695 continue; 696 sw_stats->supp[sw_stats->supp_count].descr = sw_stat_descr; 697 sw_stats->supp_count++; 698 } 699 } 700 701 static int 702 sfc_sw_stats_set_reset_basic_stats(struct sfc_adapter *sa) 703 { 704 uint64_t *reset_vals = sa->sw_stats.reset_vals; 705 struct sfc_sw_stats *sw_stats = &sa->sw_stats; 706 const struct sfc_sw_stat_descr *sw_stat; 707 unsigned int i; 708 709 for (i = 0; i < sw_stats->supp_count; i++) { 710 sw_stat = sw_stats->supp[i].descr; 711 712 switch (sw_stat->type) { 713 case SFC_SW_STATS_RX: 714 if (strcmp(sw_stat->name, 715 SFC_SW_STAT_GOOD_PACKETS) == 0) 716 sa->sw_stats.reset_rx_pkts = reset_vals; 717 else if (strcmp(sw_stat->name, 718 SFC_SW_STAT_GOOD_BYTES) == 0) 719 sa->sw_stats.reset_rx_bytes = reset_vals; 720 break; 721 case SFC_SW_STATS_TX: 722 if (strcmp(sw_stat->name, 723 SFC_SW_STAT_GOOD_PACKETS) == 0) 724 sa->sw_stats.reset_tx_pkts = reset_vals; 725 else if (strcmp(sw_stat->name, 726 SFC_SW_STAT_GOOD_BYTES) == 0) 727 sa->sw_stats.reset_tx_bytes = reset_vals; 728 break; 729 default: 730 SFC_GENERIC_LOG(ERR, "Unknown SW stat type"); 731 return -EINVAL; 732 } 733 734 reset_vals += sfc_sw_xstat_get_nb_supported(sa, sw_stat); 735 } 736 737 return 0; 738 } 739 740 int 741 sfc_sw_xstats_configure(struct sfc_adapter *sa) 742 { 743 uint64_t **reset_vals = &sa->sw_stats.reset_vals; 744 struct sfc_sw_stats *sw_stats = &sa->sw_stats; 745 unsigned int cache_count = 0; 746 uint64_t **cache = &sa->sw_stats.cache; 747 uint64_t *stat_cache; 748 size_t nb_supported = 0; 749 unsigned int i; 750 int rc; 751 752 sw_stats->supp_count = RTE_DIM(sfc_sw_stats_descr); 753 if (sw_stats->supp == NULL) { 754 sw_stats->supp = rte_malloc(NULL, sw_stats->supp_count * 755 sizeof(*sw_stats->supp), 0); 756 if (sw_stats->supp == NULL) 757 return -ENOMEM; 758 } 759 for (i = 0; i < sw_stats->supp_count; i++) 760 sw_stats->supp[i].descr = &sfc_sw_stats_descr[i]; 761 sfc_sw_stats_fill_available_descr(sa); 762 763 for (i = 0; i < sw_stats->supp_count; i++) { 764 nb_supported += sfc_sw_xstat_get_nb_supported(sa, 765 sw_stats->supp[i].descr); 766 cache_count += sfc_sw_stat_get_queue_count(sa, 767 sw_stats->supp[i].descr); 768 } 769 sa->sw_stats.xstats_count = nb_supported; 770 771 *reset_vals = rte_realloc(*reset_vals, 772 nb_supported * sizeof(**reset_vals), 0); 773 if (*reset_vals == NULL) { 774 rc = -ENOMEM; 775 goto fail_reset_vals; 776 } 777 778 memset(*reset_vals, 0, nb_supported * sizeof(**reset_vals)); 779 780 *cache = rte_realloc(*cache, cache_count * sizeof(*cache), 0); 781 if (*cache == NULL) { 782 rc = ENOMEM; 783 goto fail_cache; 784 } 785 sa->sw_stats.cache_count = cache_count; 786 stat_cache = *cache; 787 rc = sfc_sw_stats_set_reset_basic_stats(sa); 788 if (rc != 0) 789 goto fail_reset_basic_stats; 790 791 for (i = 0; i < sw_stats->supp_count; i++) { 792 sw_stats->supp[i].cache = stat_cache; 793 stat_cache += sfc_sw_stat_get_queue_count(sa, 794 sw_stats->supp[i].descr); 795 } 796 797 return 0; 798 799 fail_reset_basic_stats: 800 rte_free(*cache); 801 *cache = NULL; 802 sa->sw_stats.cache_count = 0; 803 fail_cache: 804 rte_free(*reset_vals); 805 *reset_vals = NULL; 806 fail_reset_vals: 807 sa->sw_stats.xstats_count = 0; 808 rte_free(sw_stats->supp); 809 sw_stats->supp = NULL; 810 sw_stats->supp_count = 0; 811 812 return rc; 813 } 814 815 static void 816 sfc_sw_xstats_free_queues_bitmap(struct sfc_adapter *sa) 817 { 818 rte_bitmap_free(sa->sw_stats.queues_bitmap); 819 rte_free(sa->sw_stats.queues_bitmap_mem); 820 } 821 822 static int 823 sfc_sw_xstats_alloc_queues_bitmap(struct sfc_adapter *sa) 824 { 825 struct rte_bitmap **queues_bitmap = &sa->sw_stats.queues_bitmap; 826 void **queues_bitmap_mem = &sa->sw_stats.queues_bitmap_mem; 827 uint32_t bmp_size; 828 int rc; 829 830 bmp_size = rte_bitmap_get_memory_footprint(RTE_MAX_QUEUES_PER_PORT); 831 *queues_bitmap_mem = NULL; 832 *queues_bitmap = NULL; 833 834 *queues_bitmap_mem = rte_calloc_socket("bitmap_mem", bmp_size, 1, 0, 835 sa->socket_id); 836 if (*queues_bitmap_mem == NULL) 837 return ENOMEM; 838 839 *queues_bitmap = rte_bitmap_init(RTE_MAX_QUEUES_PER_PORT, 840 *queues_bitmap_mem, bmp_size); 841 if (*queues_bitmap == NULL) { 842 rc = EINVAL; 843 goto fail; 844 } 845 846 rte_spinlock_init(&sa->sw_stats.queues_bitmap_lock); 847 return 0; 848 849 fail: 850 sfc_sw_xstats_free_queues_bitmap(sa); 851 return rc; 852 } 853 854 int 855 sfc_sw_xstats_init(struct sfc_adapter *sa) 856 { 857 sa->sw_stats.xstats_count = 0; 858 sa->sw_stats.supp = NULL; 859 sa->sw_stats.supp_count = 0; 860 sa->sw_stats.cache = NULL; 861 sa->sw_stats.cache_count = 0; 862 sa->sw_stats.reset_vals = NULL; 863 864 return sfc_sw_xstats_alloc_queues_bitmap(sa); 865 } 866 867 void 868 sfc_sw_xstats_close(struct sfc_adapter *sa) 869 { 870 sfc_sw_xstats_free_queues_bitmap(sa); 871 sa->sw_stats.reset_vals = NULL; 872 rte_free(sa->sw_stats.cache); 873 sa->sw_stats.cache = NULL; 874 sa->sw_stats.cache_count = 0; 875 rte_free(sa->sw_stats.reset_vals); 876 rte_free(sa->sw_stats.supp); 877 sa->sw_stats.supp = NULL; 878 sa->sw_stats.supp_count = 0; 879 sa->sw_stats.xstats_count = 0; 880 } 881