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