add prefix to cache line macros
[dpdk.git] / app / test / test_memzone.c
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
5  *   All rights reserved.
6  *
7  *   Redistribution and use in source and binary forms, with or without
8  *   modification, are permitted provided that the following conditions
9  *   are met:
10  *
11  *     * Redistributions of source code must retain the above copyright
12  *       notice, this list of conditions and the following disclaimer.
13  *     * Redistributions in binary form must reproduce the above copyright
14  *       notice, this list of conditions and the following disclaimer in
15  *       the documentation and/or other materials provided with the
16  *       distribution.
17  *     * Neither the name of Intel Corporation nor the names of its
18  *       contributors may be used to endorse or promote products derived
19  *       from this software without specific prior written permission.
20  *
21  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33
34 #include <stdio.h>
35 #include <stdint.h>
36 #include <inttypes.h>
37 #include <sys/queue.h>
38
39 #include <rte_random.h>
40 #include <rte_cycles.h>
41 #include <rte_memory.h>
42 #include <rte_memzone.h>
43 #include <rte_tailq.h>
44 #include <rte_eal.h>
45 #include <rte_eal_memconfig.h>
46 #include <rte_common.h>
47 #include <rte_string_fns.h>
48
49 #include "test.h"
50
51 /*
52  * Memzone
53  * =======
54  *
55  * - Search for three reserved zones or reserve them if they do not exist:
56  *
57  *   - One is on any socket id.
58  *   - The second is on socket 0.
59  *   - The last one is on socket 1 (if socket 1 exists).
60  *
61  * - Check that the zones exist.
62  *
63  * - Check that the zones are cache-aligned.
64  *
65  * - Check that zones do not overlap.
66  *
67  * - Check that the zones are on the correct socket id.
68  *
69  * - Check that a lookup of the first zone returns the same pointer.
70  *
71  * - Check that it is not possible to create another zone with the
72  *   same name as an existing zone.
73  *
74  * - Check flags for specific huge page size reservation
75  */
76
77 /* Test if memory overlaps: return 1 if true, or 0 if false. */
78 static int
79 is_memory_overlap(phys_addr_t ptr1, size_t len1, phys_addr_t ptr2, size_t len2)
80 {
81         if (ptr2 >= ptr1 && (ptr2 - ptr1) < len1)
82                 return 1;
83         else if (ptr2 < ptr1 && (ptr1 - ptr2) < len2)
84                 return 1;
85         return 0;
86 }
87
88 static int
89 test_memzone_invalid_alignment(void)
90 {
91         const struct rte_memzone * mz;
92
93         mz = rte_memzone_lookup("invalid_alignment");
94         if (mz != NULL) {
95                 printf("Zone with invalid alignment has been reserved\n");
96                 return -1;
97         }
98
99         mz = rte_memzone_reserve_aligned("invalid_alignment", 100,
100                         SOCKET_ID_ANY, 0, 100);
101         if (mz != NULL) {
102                 printf("Zone with invalid alignment has been reserved\n");
103                 return -1;
104         }
105         return 0;
106 }
107
108 static int
109 test_memzone_reserving_zone_size_bigger_than_the_maximum(void)
110 {
111         const struct rte_memzone * mz;
112
113         mz = rte_memzone_lookup("zone_size_bigger_than_the_maximum");
114         if (mz != NULL) {
115                 printf("zone_size_bigger_than_the_maximum has been reserved\n");
116                 return -1;
117         }
118
119         mz = rte_memzone_reserve("zone_size_bigger_than_the_maximum", (size_t)-1,
120                         SOCKET_ID_ANY, 0);
121         if (mz != NULL) {
122                 printf("It is impossible to reserve such big a memzone\n");
123                 return -1;
124         }
125
126         return 0;
127 }
128
129 static int
130 test_memzone_reserve_flags(void)
131 {
132         const struct rte_memzone *mz;
133         const struct rte_memseg *ms;
134         int hugepage_2MB_avail = 0;
135         int hugepage_1GB_avail = 0;
136         int hugepage_16MB_avail = 0;
137         int hugepage_16GB_avail = 0;
138         const size_t size = 100;
139         int i = 0;
140         ms = rte_eal_get_physmem_layout();
141         for (i = 0; i < RTE_MAX_MEMSEG; i++) {
142                 if (ms[i].hugepage_sz == RTE_PGSIZE_2M)
143                         hugepage_2MB_avail = 1;
144                 if (ms[i].hugepage_sz == RTE_PGSIZE_1G)
145                         hugepage_1GB_avail = 1;
146                 if (ms[i].hugepage_sz == RTE_PGSIZE_16M)
147                         hugepage_16MB_avail = 1;
148                 if (ms[i].hugepage_sz == RTE_PGSIZE_16G)
149                         hugepage_16GB_avail = 1;
150         }
151         /* Display the availability of 2MB ,1GB, 16MB, 16GB pages */
152         if (hugepage_2MB_avail)
153                 printf("2MB Huge pages available\n");
154         if (hugepage_1GB_avail)
155                 printf("1GB Huge pages available\n");
156         if (hugepage_16MB_avail)
157                 printf("16MB Huge pages available\n");
158         if (hugepage_16GB_avail)
159                 printf("16GB Huge pages available\n");
160         /*
161          * If 2MB pages available, check that a small memzone is correctly
162          * reserved from 2MB huge pages when requested by the RTE_MEMZONE_2MB flag.
163          * Also check that RTE_MEMZONE_SIZE_HINT_ONLY flag only defaults to an
164          * available page size (i.e 1GB ) when 2MB pages are unavailable.
165          */
166         if (hugepage_2MB_avail) {
167                 mz = rte_memzone_reserve("flag_zone_2M", size, SOCKET_ID_ANY,
168                                 RTE_MEMZONE_2MB);
169                 if (mz == NULL) {
170                         printf("MEMZONE FLAG 2MB\n");
171                         return -1;
172                 }
173                 if (mz->hugepage_sz != RTE_PGSIZE_2M) {
174                         printf("hugepage_sz not equal 2M\n");
175                         return -1;
176                 }
177
178                 mz = rte_memzone_reserve("flag_zone_2M_HINT", size, SOCKET_ID_ANY,
179                                 RTE_MEMZONE_2MB|RTE_MEMZONE_SIZE_HINT_ONLY);
180                 if (mz == NULL) {
181                         printf("MEMZONE FLAG 2MB\n");
182                         return -1;
183                 }
184                 if (mz->hugepage_sz != RTE_PGSIZE_2M) {
185                         printf("hugepage_sz not equal 2M\n");
186                         return -1;
187                 }
188
189                 /* Check if 1GB huge pages are unavailable, that function fails unless
190                  * HINT flag is indicated
191                  */
192                 if (!hugepage_1GB_avail) {
193                         mz = rte_memzone_reserve("flag_zone_1G_HINT", size, SOCKET_ID_ANY,
194                                         RTE_MEMZONE_1GB|RTE_MEMZONE_SIZE_HINT_ONLY);
195                         if (mz == NULL) {
196                                 printf("MEMZONE FLAG 1GB & HINT\n");
197                                 return -1;
198                         }
199                         if (mz->hugepage_sz != RTE_PGSIZE_2M) {
200                                 printf("hugepage_sz not equal 2M\n");
201                                 return -1;
202                         }
203
204                         mz = rte_memzone_reserve("flag_zone_1G", size, SOCKET_ID_ANY,
205                                         RTE_MEMZONE_1GB);
206                         if (mz != NULL) {
207                                 printf("MEMZONE FLAG 1GB\n");
208                                 return -1;
209                         }
210                 }
211         }
212
213         /*As with 2MB tests above for 1GB huge page requests*/
214         if (hugepage_1GB_avail) {
215                 mz = rte_memzone_reserve("flag_zone_1G", size, SOCKET_ID_ANY,
216                                 RTE_MEMZONE_1GB);
217                 if (mz == NULL) {
218                         printf("MEMZONE FLAG 1GB\n");
219                         return -1;
220                 }
221                 if (mz->hugepage_sz != RTE_PGSIZE_1G) {
222                         printf("hugepage_sz not equal 1G\n");
223                         return -1;
224                 }
225
226                 mz = rte_memzone_reserve("flag_zone_1G_HINT", size, SOCKET_ID_ANY,
227                                 RTE_MEMZONE_1GB|RTE_MEMZONE_SIZE_HINT_ONLY);
228                 if (mz == NULL) {
229                         printf("MEMZONE FLAG 1GB\n");
230                         return -1;
231                 }
232                 if (mz->hugepage_sz != RTE_PGSIZE_1G) {
233                         printf("hugepage_sz not equal 1G\n");
234                         return -1;
235                 }
236
237                 /* Check if 1GB huge pages are unavailable, that function fails unless
238                  * HINT flag is indicated
239                  */
240                 if (!hugepage_2MB_avail) {
241                         mz = rte_memzone_reserve("flag_zone_2M_HINT", size, SOCKET_ID_ANY,
242                                         RTE_MEMZONE_2MB|RTE_MEMZONE_SIZE_HINT_ONLY);
243                         if (mz == NULL){
244                                 printf("MEMZONE FLAG 2MB & HINT\n");
245                                 return -1;
246                         }
247                         if (mz->hugepage_sz != RTE_PGSIZE_1G) {
248                                 printf("hugepage_sz not equal 1G\n");
249                                 return -1;
250                         }
251                         mz = rte_memzone_reserve("flag_zone_2M", size, SOCKET_ID_ANY,
252                                         RTE_MEMZONE_2MB);
253                         if (mz != NULL) {
254                                 printf("MEMZONE FLAG 2MB\n");
255                                 return -1;
256                         }
257                 }
258
259                 if (hugepage_2MB_avail && hugepage_1GB_avail) {
260                         mz = rte_memzone_reserve("flag_zone_2M_HINT", size, SOCKET_ID_ANY,
261                                                                 RTE_MEMZONE_2MB|RTE_MEMZONE_1GB);
262                         if (mz != NULL) {
263                                 printf("BOTH SIZES SET\n");
264                                 return -1;
265                         }
266                 }
267         }
268         /*
269          * This option is for IBM Power. If 16MB pages available, check
270          * that a small memzone is correctly reserved from 16MB huge pages
271          * when requested by the RTE_MEMZONE_16MB flag. Also check that
272          * RTE_MEMZONE_SIZE_HINT_ONLY flag only defaults to an available
273          * page size (i.e 16GB ) when 16MB pages are unavailable.
274          */
275         if (hugepage_16MB_avail) {
276                 mz = rte_memzone_reserve("flag_zone_16M", size, SOCKET_ID_ANY,
277                                 RTE_MEMZONE_16MB);
278                 if (mz == NULL) {
279                         printf("MEMZONE FLAG 16MB\n");
280                         return -1;
281                 }
282                 if (mz->hugepage_sz != RTE_PGSIZE_16M) {
283                         printf("hugepage_sz not equal 16M\n");
284                         return -1;
285                 }
286
287                 mz = rte_memzone_reserve("flag_zone_16M_HINT", size,
288                 SOCKET_ID_ANY, RTE_MEMZONE_16MB|RTE_MEMZONE_SIZE_HINT_ONLY);
289                 if (mz == NULL) {
290                         printf("MEMZONE FLAG 2MB\n");
291                         return -1;
292                 }
293                 if (mz->hugepage_sz != RTE_PGSIZE_16M) {
294                         printf("hugepage_sz not equal 16M\n");
295                         return -1;
296                 }
297
298                 /* Check if 1GB huge pages are unavailable, that function fails
299                  * unless HINT flag is indicated
300                  */
301                 if (!hugepage_16GB_avail) {
302                         mz = rte_memzone_reserve("flag_zone_16G_HINT", size,
303                                 SOCKET_ID_ANY,
304                                 RTE_MEMZONE_16GB|RTE_MEMZONE_SIZE_HINT_ONLY);
305                         if (mz == NULL) {
306                                 printf("MEMZONE FLAG 16GB & HINT\n");
307                                 return -1;
308                         }
309                         if (mz->hugepage_sz != RTE_PGSIZE_16M) {
310                                 printf("hugepage_sz not equal 16M\n");
311                                 return -1;
312                         }
313
314                         mz = rte_memzone_reserve("flag_zone_16G", size,
315                                 SOCKET_ID_ANY, RTE_MEMZONE_16GB);
316                         if (mz != NULL) {
317                                 printf("MEMZONE FLAG 16GB\n");
318                                 return -1;
319                         }
320                 }
321         }
322         /*As with 16MB tests above for 16GB huge page requests*/
323         if (hugepage_16GB_avail) {
324                 mz = rte_memzone_reserve("flag_zone_16G", size, SOCKET_ID_ANY,
325                                 RTE_MEMZONE_16GB);
326                 if (mz == NULL) {
327                         printf("MEMZONE FLAG 16GB\n");
328                         return -1;
329                 }
330                 if (mz->hugepage_sz != RTE_PGSIZE_16G) {
331                         printf("hugepage_sz not equal 16G\n");
332                         return -1;
333                 }
334
335                 mz = rte_memzone_reserve("flag_zone_16G_HINT", size,
336                 SOCKET_ID_ANY, RTE_MEMZONE_16GB|RTE_MEMZONE_SIZE_HINT_ONLY);
337                 if (mz == NULL) {
338                         printf("MEMZONE FLAG 16GB\n");
339                         return -1;
340                 }
341                 if (mz->hugepage_sz != RTE_PGSIZE_16G) {
342                         printf("hugepage_sz not equal 16G\n");
343                         return -1;
344                 }
345
346                 /* Check if 1GB huge pages are unavailable, that function fails
347                  * unless HINT flag is indicated
348                  */
349                 if (!hugepage_16MB_avail) {
350                         mz = rte_memzone_reserve("flag_zone_16M_HINT", size,
351                                 SOCKET_ID_ANY,
352                                 RTE_MEMZONE_16MB|RTE_MEMZONE_SIZE_HINT_ONLY);
353                         if (mz == NULL) {
354                                 printf("MEMZONE FLAG 16MB & HINT\n");
355                                 return -1;
356                         }
357                         if (mz->hugepage_sz != RTE_PGSIZE_16G) {
358                                 printf("hugepage_sz not equal 16G\n");
359                                 return -1;
360                         }
361                         mz = rte_memzone_reserve("flag_zone_16M", size,
362                                 SOCKET_ID_ANY, RTE_MEMZONE_16MB);
363                         if (mz != NULL) {
364                                 printf("MEMZONE FLAG 16MB\n");
365                                 return -1;
366                         }
367                 }
368
369                 if (hugepage_16MB_avail && hugepage_16GB_avail) {
370                         mz = rte_memzone_reserve("flag_zone_16M_HINT", size,
371                                 SOCKET_ID_ANY,
372                                 RTE_MEMZONE_16MB|RTE_MEMZONE_16GB);
373                         if (mz != NULL) {
374                                 printf("BOTH SIZES SET\n");
375                                 return -1;
376                         }
377                 }
378         }
379         return 0;
380 }
381
382 static int
383 test_memzone_reserve_max(void)
384 {
385         const struct rte_memzone *mz;
386         const struct rte_config *config;
387         const struct rte_memseg *ms;
388         int memseg_idx = 0;
389         int memzone_idx = 0;
390         size_t len = 0;
391         void* last_addr;
392         size_t maxlen = 0;
393
394         /* get pointer to global configuration */
395         config = rte_eal_get_configuration();
396
397         ms = rte_eal_get_physmem_layout();
398
399         for (memseg_idx = 0; memseg_idx < RTE_MAX_MEMSEG; memseg_idx++){
400                 /* ignore smaller memsegs as they can only get smaller */
401                 if (ms[memseg_idx].len < maxlen)
402                         continue;
403
404                 /* align everything */
405                 last_addr = RTE_PTR_ALIGN_CEIL(ms[memseg_idx].addr, RTE_CACHE_LINE_SIZE);
406                 len = ms[memseg_idx].len - RTE_PTR_DIFF(last_addr, ms[memseg_idx].addr);
407                 len &= ~((size_t) RTE_CACHE_LINE_MASK);
408
409                 /* cycle through all memzones */
410                 for (memzone_idx = 0; memzone_idx < RTE_MAX_MEMZONE; memzone_idx++) {
411
412                         /* stop when reaching last allocated memzone */
413                         if (config->mem_config->memzone[memzone_idx].addr == NULL)
414                                 break;
415
416                         /* check if the memzone is in our memseg and subtract length */
417                         if ((config->mem_config->memzone[memzone_idx].addr >=
418                              ms[memseg_idx].addr) &&
419                             (config->mem_config->memzone[memzone_idx].addr <
420                              (RTE_PTR_ADD(ms[memseg_idx].addr, ms[memseg_idx].len)))) {
421                                 /* since the zones can now be aligned and occasionally skip
422                                  * some space, we should calculate the length based on
423                                  * reported length and start addresses difference. Addresses
424                                  * are allocated sequentially so we don't need to worry about
425                                  * them being in the right order.
426                                  */
427                                 len -= RTE_PTR_DIFF(
428                                                     config->mem_config->memzone[memzone_idx].addr,
429                                                     last_addr);
430                                 len -= config->mem_config->memzone[memzone_idx].len;
431                                 last_addr = RTE_PTR_ADD(config->mem_config->memzone[memzone_idx].addr,
432                                                         (size_t) config->mem_config->memzone[memzone_idx].len);
433                         }
434                 }
435
436                 /* we don't need to calculate offset here since length
437                  * is always cache-aligned */
438                 if (len > maxlen)
439                         maxlen = len;
440         }
441
442         if (maxlen == 0) {
443                 printf("There is no space left!\n");
444                 return 0;
445         }
446
447         mz = rte_memzone_reserve("max_zone", 0, SOCKET_ID_ANY, 0);
448         if (mz == NULL){
449                 printf("Failed to reserve a big chunk of memory\n");
450                 rte_dump_physmem_layout(stdout);
451                 rte_memzone_dump(stdout);
452                 return -1;
453         }
454
455         if (mz->len != maxlen) {
456                 printf("Memzone reserve with 0 size did not return bigest block\n");
457                 printf("Expected size = %zu, actual size = %zu\n",
458                        maxlen, mz->len);
459                 rte_dump_physmem_layout(stdout);
460                 rte_memzone_dump(stdout);
461
462                 return -1;
463         }
464         return 0;
465 }
466
467 static int
468 test_memzone_reserve_max_aligned(void)
469 {
470         const struct rte_memzone *mz;
471         const struct rte_config *config;
472         const struct rte_memseg *ms;
473         int memseg_idx = 0;
474         int memzone_idx = 0;
475         uintptr_t addr_offset;
476         size_t len = 0;
477         void* last_addr;
478         size_t maxlen = 0;
479
480         /* random alignment */
481         rte_srand((unsigned)rte_rdtsc());
482         const unsigned align = 1 << ((rte_rand() % 8) + 5); /* from 128 up to 4k alignment */
483
484         /* get pointer to global configuration */
485         config = rte_eal_get_configuration();
486
487         ms = rte_eal_get_physmem_layout();
488
489         addr_offset = 0;
490
491         for (memseg_idx = 0; memseg_idx < RTE_MAX_MEMSEG; memseg_idx++){
492
493                 /* ignore smaller memsegs as they can only get smaller */
494                 if (ms[memseg_idx].len < maxlen)
495                         continue;
496
497                 /* align everything */
498                 last_addr = RTE_PTR_ALIGN_CEIL(ms[memseg_idx].addr, RTE_CACHE_LINE_SIZE);
499                 len = ms[memseg_idx].len - RTE_PTR_DIFF(last_addr, ms[memseg_idx].addr);
500                 len &= ~((size_t) RTE_CACHE_LINE_MASK);
501
502                 /* cycle through all memzones */
503                 for (memzone_idx = 0; memzone_idx < RTE_MAX_MEMZONE; memzone_idx++) {
504
505                         /* stop when reaching last allocated memzone */
506                         if (config->mem_config->memzone[memzone_idx].addr == NULL)
507                                 break;
508
509                         /* check if the memzone is in our memseg and subtract length */
510                         if ((config->mem_config->memzone[memzone_idx].addr >=
511                                         ms[memseg_idx].addr) &&
512                                         (config->mem_config->memzone[memzone_idx].addr <
513                                         (RTE_PTR_ADD(ms[memseg_idx].addr, ms[memseg_idx].len)))) {
514                                 /* since the zones can now be aligned and occasionally skip
515                                  * some space, we should calculate the length based on
516                                  * reported length and start addresses difference.
517                                  */
518                                 len -= (uintptr_t) RTE_PTR_SUB(
519                                                 config->mem_config->memzone[memzone_idx].addr,
520                                                 (uintptr_t) last_addr);
521                                 len -= config->mem_config->memzone[memzone_idx].len;
522                                 last_addr =
523                                                 RTE_PTR_ADD(config->mem_config->memzone[memzone_idx].addr,
524                                                 (size_t) config->mem_config->memzone[memzone_idx].len);
525                         }
526                 }
527
528                 /* make sure we get the alignment offset */
529                 if (len > maxlen) {
530                         addr_offset = RTE_PTR_ALIGN_CEIL((uintptr_t) last_addr, align) - (uintptr_t) last_addr;
531                         maxlen = len;
532                 }
533         }
534
535         if (maxlen == 0 || maxlen == addr_offset) {
536                 printf("There is no space left for biggest %u-aligned memzone!\n", align);
537                 return 0;
538         }
539
540         maxlen -= addr_offset;
541
542         mz = rte_memzone_reserve_aligned("max_zone_aligned", 0,
543                         SOCKET_ID_ANY, 0, align);
544         if (mz == NULL){
545                 printf("Failed to reserve a big chunk of memory\n");
546                 rte_dump_physmem_layout(stdout);
547                 rte_memzone_dump(stdout);
548                 return -1;
549         }
550
551         if (mz->len != maxlen) {
552                 printf("Memzone reserve with 0 size and alignment %u did not return"
553                                 " bigest block\n", align);
554                 printf("Expected size = %zu, actual size = %zu\n",
555                                 maxlen, mz->len);
556                 rte_dump_physmem_layout(stdout);
557                 rte_memzone_dump(stdout);
558
559                 return -1;
560         }
561         return 0;
562 }
563
564 static int
565 test_memzone_aligned(void)
566 {
567         const struct rte_memzone *memzone_aligned_32;
568         const struct rte_memzone *memzone_aligned_128;
569         const struct rte_memzone *memzone_aligned_256;
570         const struct rte_memzone *memzone_aligned_512;
571         const struct rte_memzone *memzone_aligned_1024;
572
573         /* memzone that should automatically be adjusted to align on 64 bytes */
574         memzone_aligned_32 = rte_memzone_reserve_aligned("aligned_32", 100,
575                                 SOCKET_ID_ANY, 0, 32);
576
577         /* memzone that is supposed to be aligned on a 128 byte boundary */
578         memzone_aligned_128 = rte_memzone_reserve_aligned("aligned_128", 100,
579                                 SOCKET_ID_ANY, 0, 128);
580
581         /* memzone that is supposed to be aligned on a 256 byte boundary */
582         memzone_aligned_256 = rte_memzone_reserve_aligned("aligned_256", 100,
583                                 SOCKET_ID_ANY, 0, 256);
584
585         /* memzone that is supposed to be aligned on a 512 byte boundary */
586         memzone_aligned_512 = rte_memzone_reserve_aligned("aligned_512", 100,
587                                 SOCKET_ID_ANY, 0, 512);
588
589         /* memzone that is supposed to be aligned on a 1024 byte boundary */
590         memzone_aligned_1024 = rte_memzone_reserve_aligned("aligned_1024", 100,
591                                 SOCKET_ID_ANY, 0, 1024);
592
593         printf("check alignments and lengths\n");
594         if (memzone_aligned_32 == NULL) {
595                 printf("Unable to reserve 64-byte aligned memzone!\n");
596                 return -1;
597         }
598         if ((memzone_aligned_32->phys_addr & RTE_CACHE_LINE_MASK) != 0)
599                 return -1;
600         if (((uintptr_t) memzone_aligned_32->addr & RTE_CACHE_LINE_MASK) != 0)
601                 return -1;
602         if ((memzone_aligned_32->len & RTE_CACHE_LINE_MASK) != 0)
603                 return -1;
604
605         if (memzone_aligned_128 == NULL) {
606                 printf("Unable to reserve 128-byte aligned memzone!\n");
607                 return -1;
608         }
609         if ((memzone_aligned_128->phys_addr & 127) != 0)
610                 return -1;
611         if (((uintptr_t) memzone_aligned_128->addr & 127) != 0)
612                 return -1;
613         if ((memzone_aligned_128->len & RTE_CACHE_LINE_MASK) != 0)
614                 return -1;
615
616         if (memzone_aligned_256 == NULL) {
617                 printf("Unable to reserve 256-byte aligned memzone!\n");
618                 return -1;
619         }
620         if ((memzone_aligned_256->phys_addr & 255) != 0)
621                 return -1;
622         if (((uintptr_t) memzone_aligned_256->addr & 255) != 0)
623                 return -1;
624         if ((memzone_aligned_256->len & RTE_CACHE_LINE_MASK) != 0)
625                 return -1;
626
627         if (memzone_aligned_512 == NULL) {
628                 printf("Unable to reserve 512-byte aligned memzone!\n");
629                 return -1;
630         }
631         if ((memzone_aligned_512->phys_addr & 511) != 0)
632                 return -1;
633         if (((uintptr_t) memzone_aligned_512->addr & 511) != 0)
634                 return -1;
635         if ((memzone_aligned_512->len & RTE_CACHE_LINE_MASK) != 0)
636                 return -1;
637
638         if (memzone_aligned_1024 == NULL) {
639                 printf("Unable to reserve 1024-byte aligned memzone!\n");
640                 return -1;
641         }
642         if ((memzone_aligned_1024->phys_addr & 1023) != 0)
643                 return -1;
644         if (((uintptr_t) memzone_aligned_1024->addr & 1023) != 0)
645                 return -1;
646         if ((memzone_aligned_1024->len & RTE_CACHE_LINE_MASK) != 0)
647                 return -1;
648
649         /* check that zones don't overlap */
650         printf("check overlapping\n");
651         if (is_memory_overlap(memzone_aligned_32->phys_addr, memzone_aligned_32->len,
652                                         memzone_aligned_128->phys_addr, memzone_aligned_128->len))
653                 return -1;
654         if (is_memory_overlap(memzone_aligned_32->phys_addr, memzone_aligned_32->len,
655                                         memzone_aligned_256->phys_addr, memzone_aligned_256->len))
656                 return -1;
657         if (is_memory_overlap(memzone_aligned_32->phys_addr, memzone_aligned_32->len,
658                                         memzone_aligned_512->phys_addr, memzone_aligned_512->len))
659                 return -1;
660         if (is_memory_overlap(memzone_aligned_32->phys_addr, memzone_aligned_32->len,
661                                         memzone_aligned_1024->phys_addr, memzone_aligned_1024->len))
662                 return -1;
663         if (is_memory_overlap(memzone_aligned_128->phys_addr, memzone_aligned_128->len,
664                                         memzone_aligned_256->phys_addr, memzone_aligned_256->len))
665                 return -1;
666         if (is_memory_overlap(memzone_aligned_128->phys_addr, memzone_aligned_128->len,
667                                         memzone_aligned_512->phys_addr, memzone_aligned_512->len))
668                 return -1;
669         if (is_memory_overlap(memzone_aligned_128->phys_addr, memzone_aligned_128->len,
670                                         memzone_aligned_1024->phys_addr, memzone_aligned_1024->len))
671                 return -1;
672         if (is_memory_overlap(memzone_aligned_256->phys_addr, memzone_aligned_256->len,
673                                         memzone_aligned_512->phys_addr, memzone_aligned_512->len))
674                 return -1;
675         if (is_memory_overlap(memzone_aligned_256->phys_addr, memzone_aligned_256->len,
676                                         memzone_aligned_1024->phys_addr, memzone_aligned_1024->len))
677                 return -1;
678         if (is_memory_overlap(memzone_aligned_512->phys_addr, memzone_aligned_512->len,
679                                         memzone_aligned_1024->phys_addr, memzone_aligned_1024->len))
680                 return -1;
681         return 0;
682 }
683
684 static int
685 check_memzone_bounded(const char *name, uint32_t len,  uint32_t align,
686         uint32_t bound)
687 {
688         const struct rte_memzone *mz;
689         phys_addr_t bmask;
690
691         bmask = ~((phys_addr_t)bound - 1);
692
693         if ((mz = rte_memzone_reserve_bounded(name, len, SOCKET_ID_ANY, 0,
694                         align, bound)) == NULL) {
695                 printf("%s(%s): memzone creation failed\n",
696                         __func__, name);
697                 return (-1);
698         }
699
700         if ((mz->phys_addr & ((phys_addr_t)align - 1)) != 0) {
701                 printf("%s(%s): invalid phys addr alignment\n",
702                         __func__, mz->name);
703                 return (-1);
704         }
705
706         if (((uintptr_t) mz->addr & ((uintptr_t)align - 1)) != 0) {
707                 printf("%s(%s): invalid virtual addr alignment\n",
708                         __func__, mz->name);
709                 return (-1);
710         }
711
712         if ((mz->len & RTE_CACHE_LINE_MASK) != 0 || mz->len < len ||
713                         mz->len < RTE_CACHE_LINE_SIZE) {
714                 printf("%s(%s): invalid length\n",
715                         __func__, mz->name);
716                 return (-1);
717         }
718
719         if ((mz->phys_addr & bmask) !=
720                         ((mz->phys_addr + mz->len - 1) & bmask)) {
721                 printf("%s(%s): invalid memzone boundary %u crossed\n",
722                         __func__, mz->name, bound);
723                 return (-1);
724         }
725
726         return (0);
727 }
728
729 static int
730 test_memzone_bounded(void)
731 {
732         const struct rte_memzone *memzone_err;
733         const char *name;
734         int rc;
735
736         /* should fail as boundary is not power of two */
737         name = "bounded_error_31";
738         if ((memzone_err = rte_memzone_reserve_bounded(name,
739                         100, SOCKET_ID_ANY, 0, 32, UINT32_MAX)) != NULL) {
740                 printf("%s(%s)created a memzone with invalid boundary "
741                         "conditions\n", __func__, memzone_err->name);
742                 return (-1);
743         }
744
745         /* should fail as len is greater then boundary */
746         name = "bounded_error_32";
747         if ((memzone_err = rte_memzone_reserve_bounded(name,
748                         100, SOCKET_ID_ANY, 0, 32, 32)) != NULL) {
749                 printf("%s(%s)created a memzone with invalid boundary "
750                         "conditions\n", __func__, memzone_err->name);
751                 return (-1);
752         }
753
754         if ((rc = check_memzone_bounded("bounded_128", 100, 128, 128)) != 0)
755                 return (rc);
756
757         if ((rc = check_memzone_bounded("bounded_256", 100, 256, 128)) != 0)
758                 return (rc);
759
760         if ((rc = check_memzone_bounded("bounded_1K", 100, 64, 1024)) != 0)
761                 return (rc);
762
763         if ((rc = check_memzone_bounded("bounded_1K_MAX", 0, 64, 1024)) != 0)
764                 return (rc);
765
766         return (0);
767 }
768
769 static int
770 test_memzone_reserve_memory_in_smallest_segment(void)
771 {
772         const struct rte_memzone *mz;
773         const struct rte_memseg *ms, *min_ms, *prev_min_ms;
774         size_t min_len, prev_min_len;
775         const struct rte_config *config;
776         int i;
777
778         config = rte_eal_get_configuration();
779
780         min_ms = NULL;  /*< smallest segment */
781         prev_min_ms = NULL; /*< second smallest segment */
782
783         /* find two smallest segments */
784         for (i = 0; i < RTE_MAX_MEMSEG; i++) {
785                 ms = &config->mem_config->free_memseg[i];
786
787                 if (ms->addr == NULL)
788                         break;
789                 if (ms->len == 0)
790                         continue;
791
792                 if (min_ms == NULL)
793                         min_ms = ms;
794                 else if (min_ms->len > ms->len) {
795                         /* set last smallest to second last */
796                         prev_min_ms = min_ms;
797
798                         /* set new smallest */
799                         min_ms = ms;
800                 } else if ((prev_min_ms == NULL)
801                         || (prev_min_ms->len > ms->len))
802                         prev_min_ms = ms;
803         }
804
805         if (min_ms == NULL || prev_min_ms == NULL) {
806                 printf("Smallest segments not found!\n");
807                 return -1;
808         }
809
810         min_len = min_ms->len;
811         prev_min_len = prev_min_ms->len;
812
813         /* try reserving a memzone in the smallest memseg */
814         mz = rte_memzone_reserve("smallest_mz", RTE_CACHE_LINE_SIZE,
815                         SOCKET_ID_ANY, 0);
816         if (mz == NULL) {
817                 printf("Failed to reserve memory from smallest memseg!\n");
818                 return -1;
819         }
820         if (prev_min_ms->len != prev_min_len &&
821                         min_ms->len != min_len - RTE_CACHE_LINE_SIZE) {
822                 printf("Reserved memory from wrong memseg!\n");
823                 return -1;
824         }
825
826         return 0;
827 }
828
829 /* this test is a bit  tricky, and thus warrants explanation.
830  *
831  * first, we find two smallest memsegs to conduct our experiments on.
832  *
833  * then, we bring them within alignment from each other: if second segment is
834  * twice+ as big as the first, reserve memory from that segment; if second
835  * segment is comparable in length to the first, then cut the first segment
836  * down until it becomes less than half of second segment, and then cut down
837  * the second segment to be within alignment of the first.
838  *
839  * then, we have to pass the following test: if segments are within alignment
840  * of each other (that is, the difference is less than 256 bytes, which is what
841  * our alignment will be), segment with smallest offset should be picked.
842  *
843  * we know that min_ms will be our smallest segment, so we need to make sure
844  * that we adjust the alignments so that the bigger segment has smallest
845  * alignment (in our case, smallest segment will have 64-byte alignment, while
846  * bigger segment will have 128-byte alignment).
847  */
848 static int
849 test_memzone_reserve_memory_with_smallest_offset(void)
850 {
851         const struct rte_memseg *ms, *min_ms, *prev_min_ms;
852         size_t len, min_len, prev_min_len;
853         const struct rte_config *config;
854         int i, align;
855
856         config = rte_eal_get_configuration();
857
858         min_ms = NULL;  /*< smallest segment */
859         prev_min_ms = NULL; /*< second smallest segment */
860         align = RTE_CACHE_LINE_SIZE * 4;
861
862         /* find two smallest segments */
863         for (i = 0; i < RTE_MAX_MEMSEG; i++) {
864                 ms = &config->mem_config->free_memseg[i];
865
866                 if (ms->addr == NULL)
867                         break;
868                 if (ms->len == 0)
869                         continue;
870
871                 if (min_ms == NULL)
872                         min_ms = ms;
873                 else if (min_ms->len > ms->len) {
874                         /* set last smallest to second last */
875                         prev_min_ms = min_ms;
876
877                         /* set new smallest */
878                         min_ms = ms;
879                 } else if ((prev_min_ms == NULL)
880                         || (prev_min_ms->len > ms->len)) {
881                         prev_min_ms = ms;
882                 }
883         }
884
885         if (min_ms == NULL || prev_min_ms == NULL) {
886                 printf("Smallest segments not found!\n");
887                 return -1;
888         }
889
890         prev_min_len = prev_min_ms->len;
891         min_len = min_ms->len;
892
893         /* if smallest segment is bigger than half of bigger segment */
894         if (prev_min_ms->len - min_ms->len <= min_ms->len) {
895
896                 len = (min_ms->len * 2) - prev_min_ms->len;
897
898                 /* make sure final length is *not* aligned */
899                 while (((min_ms->addr_64 + len) & (align-1)) == 0)
900                         len += RTE_CACHE_LINE_SIZE;
901
902                 if (rte_memzone_reserve("dummy_mz1", len, SOCKET_ID_ANY, 0) == NULL) {
903                         printf("Cannot reserve memory!\n");
904                         return -1;
905                 }
906
907                 /* check if we got memory from correct segment */
908                 if (min_ms->len != min_len - len) {
909                         printf("Reserved memory from wrong segment!\n");
910                         return -1;
911                 }
912         }
913     /* if we don't need to touch smallest segment but it's aligned */
914     else if ((min_ms->addr_64 & (align-1)) == 0) {
915             if (rte_memzone_reserve("align_mz1", RTE_CACHE_LINE_SIZE,
916                     SOCKET_ID_ANY, 0) == NULL) {
917                             printf("Cannot reserve memory!\n");
918                             return -1;
919             }
920             if (min_ms->len != min_len - RTE_CACHE_LINE_SIZE) {
921                     printf("Reserved memory from wrong segment!\n");
922                     return -1;
923             }
924     }
925
926         /* if smallest segment is less than half of bigger segment */
927         if (prev_min_ms->len - min_ms->len > min_ms->len) {
928                 len = prev_min_ms->len - min_ms->len - align;
929
930                 /* make sure final length is aligned */
931                 while (((prev_min_ms->addr_64 + len) & (align-1)) != 0)
932                         len += RTE_CACHE_LINE_SIZE;
933
934                 if (rte_memzone_reserve("dummy_mz2", len, SOCKET_ID_ANY, 0) == NULL) {
935                         printf("Cannot reserve memory!\n");
936                         return -1;
937                 }
938
939                 /* check if we got memory from correct segment */
940                 if (prev_min_ms->len != prev_min_len - len) {
941                         printf("Reserved memory from wrong segment!\n");
942                         return -1;
943                 }
944         }
945         len = RTE_CACHE_LINE_SIZE;
946
947
948
949         prev_min_len = prev_min_ms->len;
950         min_len = min_ms->len;
951
952         if (min_len >= prev_min_len || prev_min_len - min_len > (unsigned) align) {
953                 printf("Segments are of wrong lengths!\n");
954                 return -1;
955         }
956
957         /* try reserving from a bigger segment */
958         if (rte_memzone_reserve_aligned("smallest_offset", len, SOCKET_ID_ANY, 0, align) ==
959                         NULL) {
960                 printf("Cannot reserve memory!\n");
961                 return -1;
962         }
963
964         /* check if we got memory from correct segment */
965         if (min_ms->len != min_len && prev_min_ms->len != (prev_min_len - len)) {
966                 printf("Reserved memory from segment with smaller offset!\n");
967                 return -1;
968         }
969
970         return 0;
971 }
972
973 static int
974 test_memzone_reserve_remainder(void)
975 {
976         const struct rte_memzone *mz1, *mz2;
977         const struct rte_memseg *ms, *min_ms = NULL;
978         size_t min_len;
979         const struct rte_config *config;
980         int i, align;
981
982         min_len = 0;
983         align = RTE_CACHE_LINE_SIZE;
984
985         config = rte_eal_get_configuration();
986
987         /* find minimum free contiguous length */
988         for (i = 0; i < RTE_MAX_MEMSEG; i++) {
989                 ms = &config->mem_config->free_memseg[i];
990
991                 if (ms->addr == NULL)
992                         break;
993                 if (ms->len == 0)
994                         continue;
995
996                 if (min_len == 0 || ms->len < min_len) {
997                         min_len = ms->len;
998                         min_ms = ms;
999
1000                         /* find maximum alignment this segment is able to hold */
1001                         align = RTE_CACHE_LINE_SIZE;
1002                         while ((ms->addr_64 & (align-1)) == 0) {
1003                                 align <<= 1;
1004                         }
1005                 }
1006         }
1007
1008         if (min_ms == NULL) {
1009                 printf("Minimal sized segment not found!\n");
1010                 return -1;
1011         }
1012
1013         /* try reserving min_len bytes with alignment - this should not affect our
1014          * memseg, the memory will be taken from a different one.
1015          */
1016         mz1 = rte_memzone_reserve_aligned("reserve_remainder_1", min_len,
1017                         SOCKET_ID_ANY, 0, align);
1018         if (mz1 == NULL) {
1019                 printf("Failed to reserve %zu bytes aligned on %i bytes\n", min_len,
1020                                 align);
1021                 return -1;
1022         }
1023         if (min_ms->len != min_len) {
1024                 printf("Memseg memory should not have been reserved!\n");
1025                 return -1;
1026         }
1027
1028         /* try reserving min_len bytes with less alignment - this should fill up
1029          * the segment.
1030          */
1031         mz2 = rte_memzone_reserve("reserve_remainder_2", min_len,
1032                         SOCKET_ID_ANY, 0);
1033         if (mz2 == NULL) {
1034                 printf("Failed to reserve %zu bytes\n", min_len);
1035                 return -1;
1036         }
1037         if (min_ms->len != 0) {
1038                 printf("Memseg memory should have been reserved!\n");
1039                 return -1;
1040         }
1041
1042         return 0;
1043 }
1044
1045 static int
1046 test_memzone(void)
1047 {
1048         const struct rte_memzone *memzone1;
1049         const struct rte_memzone *memzone2;
1050         const struct rte_memzone *memzone3;
1051         const struct rte_memzone *memzone4;
1052         const struct rte_memzone *mz;
1053
1054         memzone1 = rte_memzone_reserve("testzone1", 100,
1055                                 SOCKET_ID_ANY, 0);
1056
1057         memzone2 = rte_memzone_reserve("testzone2", 1000,
1058                                 0, 0);
1059
1060         memzone3 = rte_memzone_reserve("testzone3", 1000,
1061                                 1, 0);
1062
1063         memzone4 = rte_memzone_reserve("testzone4", 1024,
1064                                 SOCKET_ID_ANY, 0);
1065
1066         /* memzone3 may be NULL if we don't have NUMA */
1067         if (memzone1 == NULL || memzone2 == NULL || memzone4 == NULL)
1068                 return -1;
1069
1070         rte_memzone_dump(stdout);
1071
1072         /* check cache-line alignments */
1073         printf("check alignments and lengths\n");
1074
1075         if ((memzone1->phys_addr & RTE_CACHE_LINE_MASK) != 0)
1076                 return -1;
1077         if ((memzone2->phys_addr & RTE_CACHE_LINE_MASK) != 0)
1078                 return -1;
1079         if (memzone3 != NULL && (memzone3->phys_addr & RTE_CACHE_LINE_MASK) != 0)
1080                 return -1;
1081         if ((memzone1->len & RTE_CACHE_LINE_MASK) != 0 || memzone1->len == 0)
1082                 return -1;
1083         if ((memzone2->len & RTE_CACHE_LINE_MASK) != 0 || memzone2->len == 0)
1084                 return -1;
1085         if (memzone3 != NULL && ((memzone3->len & RTE_CACHE_LINE_MASK) != 0 ||
1086                         memzone3->len == 0))
1087                 return -1;
1088         if (memzone4->len != 1024)
1089                 return -1;
1090
1091         /* check that zones don't overlap */
1092         printf("check overlapping\n");
1093
1094         if (is_memory_overlap(memzone1->phys_addr, memzone1->len,
1095                         memzone2->phys_addr, memzone2->len))
1096                 return -1;
1097         if (memzone3 != NULL &&
1098                         is_memory_overlap(memzone1->phys_addr, memzone1->len,
1099                                         memzone3->phys_addr, memzone3->len))
1100                 return -1;
1101         if (memzone3 != NULL &&
1102                         is_memory_overlap(memzone2->phys_addr, memzone2->len,
1103                                         memzone3->phys_addr, memzone3->len))
1104                 return -1;
1105
1106         printf("check socket ID\n");
1107
1108         /* memzone2 must be on socket id 0 and memzone3 on socket 1 */
1109         if (memzone2->socket_id != 0)
1110                 return -1;
1111         if (memzone3 != NULL && memzone3->socket_id != 1)
1112                 return -1;
1113
1114         printf("test zone lookup\n");
1115         mz = rte_memzone_lookup("testzone1");
1116         if (mz != memzone1)
1117                 return -1;
1118
1119         printf("test duplcate zone name\n");
1120         mz = rte_memzone_reserve("testzone1", 100,
1121                         SOCKET_ID_ANY, 0);
1122         if (mz != NULL)
1123                 return -1;
1124
1125         printf("test reserving memzone with bigger size than the maximum\n");
1126         if (test_memzone_reserving_zone_size_bigger_than_the_maximum() < 0)
1127                 return -1;
1128
1129         printf("test reserving memory in smallest segments\n");
1130         if (test_memzone_reserve_memory_in_smallest_segment() < 0)
1131                 return -1;
1132
1133         printf("test reserving memory in segments with smallest offsets\n");
1134         if (test_memzone_reserve_memory_with_smallest_offset() < 0)
1135                 return -1;
1136
1137         printf("test memzone_reserve flags\n");
1138         if (test_memzone_reserve_flags() < 0)
1139                 return -1;
1140
1141         printf("test alignment for memzone_reserve\n");
1142         if (test_memzone_aligned() < 0)
1143                 return -1;
1144
1145         printf("test boundary alignment for memzone_reserve\n");
1146         if (test_memzone_bounded() < 0)
1147                 return -1;
1148
1149         printf("test invalid alignment for memzone_reserve\n");
1150         if (test_memzone_invalid_alignment() < 0)
1151                 return -1;
1152
1153         printf("test reserving amounts of memory equal to segment's length\n");
1154         if (test_memzone_reserve_remainder() < 0)
1155                 return -1;
1156
1157         printf("test reserving the largest size memzone possible\n");
1158         if (test_memzone_reserve_max() < 0)
1159                 return -1;
1160
1161         printf("test reserving the largest size aligned memzone possible\n");
1162         if (test_memzone_reserve_max_aligned() < 0)
1163                 return -1;
1164
1165         return 0;
1166 }
1167
1168 static struct test_command memzone_cmd = {
1169         .command = "memzone_autotest",
1170         .callback = test_memzone,
1171 };
1172 REGISTER_TEST_COMMAND(memzone_cmd);