xref: /spdk/test/common/lib/test_env.c (revision 877573897ad52be4fa8989f7617bd655b87e05c4)
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 
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