1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright (C) 2016 Intel Corporation. 3 * Copyright (c) 2022 NVIDIA CORPORATION & AFFILIATES. 4 * All rights reserved. 5 */ 6 7 #include "spdk/stdinc.h" 8 9 #include "spdk_internal/mock.h" 10 11 #include "spdk/env.h" 12 #include "spdk/queue.h" 13 #include "spdk/util.h" 14 #include "spdk/string.h" 15 16 static uint32_t g_ut_num_cores; 17 static bool *g_ut_cores; 18 19 void allocate_cores(uint32_t num_cores); 20 void free_cores(void); 21 22 DEFINE_STUB(spdk_process_is_primary, bool, (void), true) 23 DEFINE_STUB(spdk_memzone_lookup, void *, (const char *name), NULL) 24 DEFINE_STUB_V(spdk_pci_driver_register, (const char *name, struct spdk_pci_id *id_table, 25 uint32_t flags)); 26 DEFINE_STUB(spdk_pci_nvme_get_driver, struct spdk_pci_driver *, (void), NULL) 27 DEFINE_STUB(spdk_pci_ioat_get_driver, struct spdk_pci_driver *, (void), NULL) 28 DEFINE_STUB(spdk_pci_virtio_get_driver, struct spdk_pci_driver *, (void), NULL) 29 DEFINE_STUB(spdk_env_thread_launch_pinned, int, (uint32_t core, thread_start_fn fn, void *arg), 0); 30 DEFINE_STUB_V(spdk_env_thread_wait_all, (void)); 31 DEFINE_STUB_V(spdk_env_opts_init, (struct spdk_env_opts *opts)); 32 DEFINE_STUB(spdk_env_init, int, (const struct spdk_env_opts *opts), 0); 33 DEFINE_STUB_V(spdk_env_fini, (void)); 34 35 void 36 allocate_cores(uint32_t num_cores) 37 { 38 uint32_t i; 39 40 g_ut_num_cores = num_cores; 41 42 g_ut_cores = calloc(num_cores, sizeof(bool)); 43 assert(g_ut_cores != NULL); 44 45 for (i = 0; i < num_cores; i++) { 46 g_ut_cores[i] = true; 47 } 48 } 49 50 void 51 free_cores(void) 52 { 53 free(g_ut_cores); 54 g_ut_cores = NULL; 55 g_ut_num_cores = 0; 56 } 57 58 static uint32_t 59 ut_get_next_core(uint32_t i) 60 { 61 i++; 62 63 while (i < g_ut_num_cores) { 64 if (!g_ut_cores[i]) { 65 i++; 66 continue; 67 } 68 break; 69 } 70 71 if (i < g_ut_num_cores) { 72 return i; 73 } else { 74 return UINT32_MAX; 75 } 76 } 77 78 uint32_t 79 spdk_env_get_first_core(void) 80 { 81 return ut_get_next_core(-1); 82 } 83 84 uint32_t 85 spdk_env_get_next_core(uint32_t prev_core) 86 { 87 return ut_get_next_core(prev_core); 88 } 89 90 uint32_t 91 spdk_env_get_core_count(void) 92 { 93 return g_ut_num_cores; 94 } 95 96 uint32_t 97 spdk_env_get_last_core(void) 98 { 99 uint32_t i; 100 uint32_t last_core = UINT32_MAX; 101 102 SPDK_ENV_FOREACH_CORE(i) { 103 last_core = i; 104 } 105 106 return last_core; 107 } 108 109 DEFINE_RETURN_MOCK(spdk_env_get_current_core, uint32_t); 110 uint32_t 111 spdk_env_get_current_core(void) 112 { 113 HANDLE_RETURN_MOCK(spdk_env_get_current_core); 114 115 return UINT32_MAX; 116 } 117 118 DEFINE_RETURN_MOCK(spdk_env_get_socket_id, uint32_t); 119 uint32_t 120 spdk_env_get_socket_id(uint32_t core) 121 { 122 HANDLE_RETURN_MOCK(spdk_env_get_socket_id); 123 124 return SPDK_ENV_SOCKET_ID_ANY; 125 } 126 127 /* 128 * These mocks don't use the DEFINE_STUB macros because 129 * their default implementation is more complex. 130 */ 131 132 DEFINE_RETURN_MOCK(spdk_memzone_reserve, void *); 133 void * 134 spdk_memzone_reserve(const char *name, size_t len, int socket_id, unsigned flags) 135 { 136 HANDLE_RETURN_MOCK(spdk_memzone_reserve); 137 138 return malloc(len); 139 } 140 141 DEFINE_RETURN_MOCK(spdk_memzone_reserve_aligned, void *); 142 void * 143 spdk_memzone_reserve_aligned(const char *name, size_t len, int socket_id, 144 unsigned flags, unsigned align) 145 { 146 HANDLE_RETURN_MOCK(spdk_memzone_reserve_aligned); 147 148 return malloc(len); 149 } 150 151 DEFINE_RETURN_MOCK(spdk_malloc, void *); 152 void * 153 spdk_malloc(size_t size, size_t align, uint64_t *phys_addr, int socket_id, uint32_t flags) 154 { 155 HANDLE_RETURN_MOCK(spdk_malloc); 156 157 void *buf = NULL; 158 159 if (size == 0) { 160 /* Align how mock handles 0 size with rte functions - return NULL. 161 * According to posix_memalig docs, if size is 0, then the 162 * value placed in *memptr is either NULL or a unique pointer value. */ 163 return NULL; 164 } 165 166 if (align == 0) { 167 align = 8; 168 } 169 170 if (posix_memalign(&buf, align, size)) { 171 return NULL; 172 } 173 if (phys_addr) { 174 *phys_addr = (uint64_t)buf; 175 } 176 177 return buf; 178 } 179 180 DEFINE_RETURN_MOCK(spdk_zmalloc, void *); 181 void * 182 spdk_zmalloc(size_t size, size_t align, uint64_t *phys_addr, int socket_id, uint32_t flags) 183 { 184 HANDLE_RETURN_MOCK(spdk_zmalloc); 185 186 void *buf = spdk_malloc(size, align, phys_addr, -1, 1); 187 188 if (buf != NULL) { 189 memset(buf, 0, size); 190 } 191 return buf; 192 } 193 194 DEFINE_RETURN_MOCK(spdk_dma_malloc, void *); 195 void * 196 spdk_dma_malloc(size_t size, size_t align, uint64_t *phys_addr) 197 { 198 HANDLE_RETURN_MOCK(spdk_dma_malloc); 199 200 return spdk_malloc(size, align, phys_addr, -1, 1); 201 } 202 203 DEFINE_RETURN_MOCK(spdk_realloc, void *); 204 void * 205 spdk_realloc(void *buf, size_t size, size_t align) 206 { 207 HANDLE_RETURN_MOCK(spdk_realloc); 208 209 return realloc(buf, size); 210 } 211 212 DEFINE_RETURN_MOCK(spdk_dma_zmalloc, void *); 213 void * 214 spdk_dma_zmalloc(size_t size, size_t align, uint64_t *phys_addr) 215 { 216 HANDLE_RETURN_MOCK(spdk_dma_zmalloc); 217 218 return spdk_zmalloc(size, align, phys_addr, -1, 1); 219 } 220 221 DEFINE_RETURN_MOCK(spdk_dma_malloc_socket, void *); 222 void * 223 spdk_dma_malloc_socket(size_t size, size_t align, uint64_t *phys_addr, int socket_id) 224 { 225 HANDLE_RETURN_MOCK(spdk_dma_malloc_socket); 226 227 return spdk_dma_malloc(size, align, phys_addr); 228 } 229 230 DEFINE_RETURN_MOCK(spdk_dma_zmalloc_socket, void *); 231 void * 232 spdk_dma_zmalloc_socket(size_t size, size_t align, uint64_t *phys_addr, int socket_id) 233 { 234 HANDLE_RETURN_MOCK(spdk_dma_zmalloc_socket); 235 236 return spdk_dma_zmalloc(size, align, phys_addr); 237 } 238 239 DEFINE_RETURN_MOCK(spdk_dma_realloc, void *); 240 void * 241 spdk_dma_realloc(void *buf, size_t size, size_t align, uint64_t *phys_addr) 242 { 243 HANDLE_RETURN_MOCK(spdk_dma_realloc); 244 245 return realloc(buf, size); 246 } 247 248 void 249 spdk_free(void *buf) 250 { 251 /* fix for false-positives in *certain* static analysis tools. */ 252 assert((uintptr_t)buf != UINTPTR_MAX); 253 free(buf); 254 } 255 256 void 257 spdk_dma_free(void *buf) 258 { 259 return spdk_free(buf); 260 } 261 262 #ifndef UNIT_TEST_NO_VTOPHYS 263 DEFINE_RETURN_MOCK(spdk_vtophys, uint64_t); 264 uint64_t 265 spdk_vtophys(const void *buf, uint64_t *size) 266 { 267 HANDLE_RETURN_MOCK(spdk_vtophys); 268 269 return (uintptr_t)buf; 270 } 271 #endif 272 273 void 274 spdk_memzone_dump(FILE *f) 275 { 276 return; 277 } 278 279 DEFINE_RETURN_MOCK(spdk_memzone_free, int); 280 int 281 spdk_memzone_free(const char *name) 282 { 283 HANDLE_RETURN_MOCK(spdk_memzone_free); 284 285 return 0; 286 } 287 288 struct test_mempool { 289 size_t count; 290 size_t ele_size; 291 }; 292 293 DEFINE_RETURN_MOCK(spdk_mempool_create, struct spdk_mempool *); 294 struct spdk_mempool * 295 spdk_mempool_create(const char *name, size_t count, 296 size_t ele_size, size_t cache_size, int socket_id) 297 { 298 struct test_mempool *mp; 299 300 HANDLE_RETURN_MOCK(spdk_mempool_create); 301 302 mp = calloc(1, sizeof(*mp)); 303 if (mp == NULL) { 304 return NULL; 305 } 306 307 mp->count = count; 308 mp->ele_size = ele_size; 309 310 return (struct spdk_mempool *)mp; 311 } 312 313 void 314 spdk_mempool_free(struct spdk_mempool *_mp) 315 { 316 struct test_mempool *mp = (struct test_mempool *)_mp; 317 318 free(mp); 319 } 320 321 DEFINE_RETURN_MOCK(spdk_mempool_get, void *); 322 void * 323 spdk_mempool_get(struct spdk_mempool *_mp) 324 { 325 struct test_mempool *mp = (struct test_mempool *)_mp; 326 size_t ele_size = 0x10000; 327 void *buf; 328 329 HANDLE_RETURN_MOCK(spdk_mempool_get); 330 331 if (mp && mp->count == 0) { 332 return NULL; 333 } 334 335 if (mp) { 336 ele_size = mp->ele_size; 337 } 338 339 if (posix_memalign(&buf, 64, spdk_align32pow2(ele_size))) { 340 return NULL; 341 } else { 342 if (mp) { 343 mp->count--; 344 } 345 return buf; 346 } 347 } 348 349 int 350 spdk_mempool_get_bulk(struct spdk_mempool *mp, void **ele_arr, size_t count) 351 { 352 struct test_mempool *test_mp = (struct test_mempool *)mp; 353 354 if (test_mp && test_mp->count < count) { 355 return -1; 356 } 357 358 for (size_t i = 0; i < count; i++) { 359 ele_arr[i] = spdk_mempool_get(mp); 360 if (ele_arr[i] == NULL) { 361 return -1; 362 } 363 } 364 return 0; 365 } 366 367 void 368 spdk_mempool_put(struct spdk_mempool *_mp, void *ele) 369 { 370 struct test_mempool *mp = (struct test_mempool *)_mp; 371 372 if (mp) { 373 mp->count++; 374 } 375 free(ele); 376 } 377 378 void 379 spdk_mempool_put_bulk(struct spdk_mempool *mp, void **ele_arr, size_t count) 380 { 381 for (size_t i = 0; i < count; i++) { 382 spdk_mempool_put(mp, ele_arr[i]); 383 } 384 } 385 386 DEFINE_RETURN_MOCK(spdk_mempool_count, size_t); 387 size_t 388 spdk_mempool_count(const struct spdk_mempool *_mp) 389 { 390 struct test_mempool *mp = (struct test_mempool *)_mp; 391 392 HANDLE_RETURN_MOCK(spdk_mempool_count); 393 394 if (mp) { 395 return mp->count; 396 } else { 397 return 1024; 398 } 399 } 400 401 struct spdk_ring_ele { 402 void *ele; 403 TAILQ_ENTRY(spdk_ring_ele) link; 404 }; 405 406 struct spdk_ring { 407 TAILQ_HEAD(, spdk_ring_ele) elements; 408 pthread_mutex_t lock; 409 size_t count; 410 }; 411 412 DEFINE_RETURN_MOCK(spdk_ring_create, struct spdk_ring *); 413 struct spdk_ring * 414 spdk_ring_create(enum spdk_ring_type type, size_t count, int socket_id) 415 { 416 struct spdk_ring *ring; 417 418 HANDLE_RETURN_MOCK(spdk_ring_create); 419 420 ring = calloc(1, sizeof(*ring)); 421 if (!ring) { 422 return NULL; 423 } 424 425 if (pthread_mutex_init(&ring->lock, NULL)) { 426 free(ring); 427 return NULL; 428 } 429 430 TAILQ_INIT(&ring->elements); 431 return ring; 432 } 433 434 void 435 spdk_ring_free(struct spdk_ring *ring) 436 { 437 struct spdk_ring_ele *ele, *tmp; 438 439 if (!ring) { 440 return; 441 } 442 443 TAILQ_FOREACH_SAFE(ele, &ring->elements, link, tmp) { 444 free(ele); 445 } 446 447 pthread_mutex_destroy(&ring->lock); 448 free(ring); 449 } 450 451 DEFINE_RETURN_MOCK(spdk_ring_enqueue, size_t); 452 size_t 453 spdk_ring_enqueue(struct spdk_ring *ring, void **objs, size_t count, 454 size_t *free_space) 455 { 456 struct spdk_ring_ele *ele; 457 size_t i; 458 459 HANDLE_RETURN_MOCK(spdk_ring_enqueue); 460 461 pthread_mutex_lock(&ring->lock); 462 463 for (i = 0; i < count; i++) { 464 ele = calloc(1, sizeof(*ele)); 465 if (!ele) { 466 break; 467 } 468 469 ele->ele = objs[i]; 470 TAILQ_INSERT_TAIL(&ring->elements, ele, link); 471 ring->count++; 472 } 473 474 pthread_mutex_unlock(&ring->lock); 475 return i; 476 } 477 478 DEFINE_RETURN_MOCK(spdk_ring_dequeue, size_t); 479 size_t 480 spdk_ring_dequeue(struct spdk_ring *ring, void **objs, size_t count) 481 { 482 struct spdk_ring_ele *ele, *tmp; 483 size_t i = 0; 484 485 HANDLE_RETURN_MOCK(spdk_ring_dequeue); 486 487 if (count == 0) { 488 return 0; 489 } 490 491 pthread_mutex_lock(&ring->lock); 492 493 TAILQ_FOREACH_SAFE(ele, &ring->elements, link, tmp) { 494 TAILQ_REMOVE(&ring->elements, ele, link); 495 ring->count--; 496 objs[i] = ele->ele; 497 free(ele); 498 i++; 499 if (i >= count) { 500 break; 501 } 502 } 503 504 pthread_mutex_unlock(&ring->lock); 505 return i; 506 507 } 508 509 510 DEFINE_RETURN_MOCK(spdk_ring_count, size_t); 511 size_t 512 spdk_ring_count(struct spdk_ring *ring) 513 { 514 HANDLE_RETURN_MOCK(spdk_ring_count); 515 return ring->count; 516 } 517 518 DEFINE_RETURN_MOCK(spdk_get_ticks, uint64_t); 519 uint64_t 520 spdk_get_ticks(void) 521 { 522 HANDLE_RETURN_MOCK(spdk_get_ticks); 523 524 return ut_spdk_get_ticks; 525 } 526 527 DEFINE_RETURN_MOCK(spdk_get_ticks_hz, uint64_t); 528 uint64_t 529 spdk_get_ticks_hz(void) 530 { 531 HANDLE_RETURN_MOCK(spdk_get_ticks_hz); 532 533 return 1000000; 534 } 535 536 void 537 spdk_delay_us(unsigned int us) 538 { 539 /* spdk_get_ticks_hz is 1000000, meaning 1 tick per us. */ 540 ut_spdk_get_ticks += us; 541 } 542 543 #ifndef UNIT_TEST_NO_PCI_ADDR 544 DEFINE_RETURN_MOCK(spdk_pci_addr_parse, int); 545 int 546 spdk_pci_addr_parse(struct spdk_pci_addr *addr, const char *bdf) 547 { 548 unsigned domain, bus, dev, func; 549 550 HANDLE_RETURN_MOCK(spdk_pci_addr_parse); 551 552 if (addr == NULL || bdf == NULL) { 553 return -EINVAL; 554 } 555 556 if ((sscanf(bdf, "%x:%x:%x.%x", &domain, &bus, &dev, &func) == 4) || 557 (sscanf(bdf, "%x.%x.%x.%x", &domain, &bus, &dev, &func) == 4)) { 558 /* Matched a full address - all variables are initialized */ 559 } else if (sscanf(bdf, "%x:%x:%x", &domain, &bus, &dev) == 3) { 560 func = 0; 561 } else if ((sscanf(bdf, "%x:%x.%x", &bus, &dev, &func) == 3) || 562 (sscanf(bdf, "%x.%x.%x", &bus, &dev, &func) == 3)) { 563 domain = 0; 564 } else if ((sscanf(bdf, "%x:%x", &bus, &dev) == 2) || 565 (sscanf(bdf, "%x.%x", &bus, &dev) == 2)) { 566 domain = 0; 567 func = 0; 568 } else { 569 return -EINVAL; 570 } 571 572 if (bus > 0xFF || dev > 0x1F || func > 7) { 573 return -EINVAL; 574 } 575 576 addr->domain = domain; 577 addr->bus = bus; 578 addr->dev = dev; 579 addr->func = func; 580 581 return 0; 582 } 583 584 DEFINE_RETURN_MOCK(spdk_pci_addr_fmt, int); 585 int 586 spdk_pci_addr_fmt(char *bdf, size_t sz, const struct spdk_pci_addr *addr) 587 { 588 int rc; 589 590 HANDLE_RETURN_MOCK(spdk_pci_addr_fmt); 591 592 rc = snprintf(bdf, sz, "%04x:%02x:%02x.%x", 593 addr->domain, addr->bus, 594 addr->dev, addr->func); 595 596 if (rc > 0 && (size_t)rc < sz) { 597 return 0; 598 } 599 600 return -1; 601 } 602 603 DEFINE_RETURN_MOCK(spdk_pci_addr_compare, int); 604 int 605 spdk_pci_addr_compare(const struct spdk_pci_addr *a1, const struct spdk_pci_addr *a2) 606 { 607 HANDLE_RETURN_MOCK(spdk_pci_addr_compare); 608 609 if (a1->domain > a2->domain) { 610 return 1; 611 } else if (a1->domain < a2->domain) { 612 return -1; 613 } else if (a1->bus > a2->bus) { 614 return 1; 615 } else if (a1->bus < a2->bus) { 616 return -1; 617 } else if (a1->dev > a2->dev) { 618 return 1; 619 } else if (a1->dev < a2->dev) { 620 return -1; 621 } else if (a1->func > a2->func) { 622 return 1; 623 } else if (a1->func < a2->func) { 624 return -1; 625 } 626 627 return 0; 628 } 629 #endif 630