mem: add huge page sizes for IBM Power
[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, CACHE_LINE_SIZE);
406                 len = ms[memseg_idx].len - RTE_PTR_DIFF(last_addr, ms[memseg_idx].addr);
407                 len &= ~((size_t) 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, CACHE_LINE_SIZE);
499                 len = ms[memseg_idx].len - RTE_PTR_DIFF(last_addr, ms[memseg_idx].addr);
500                 len &= ~((size_t) 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 & CACHE_LINE_MASK) != 0)
599                 return -1;
600         if (((uintptr_t) memzone_aligned_32->addr & CACHE_LINE_MASK) != 0)
601                 return -1;
602         if ((memzone_aligned_32->len & 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 & 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 & 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 & 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 & 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 & CACHE_LINE_MASK) != 0 || mz->len < len ||
713                         mz->len < 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                 }
801                 else if (prev_min_ms == NULL) {
802                         prev_min_ms = ms;
803                 }
804         }
805
806         if (min_ms == NULL || prev_min_ms == NULL) {
807                 printf("Smallest segments not found!\n");
808                 return -1;
809         }
810
811         min_len = min_ms->len;
812         prev_min_len = prev_min_ms->len;
813
814         /* try reserving a memzone in the smallest memseg */
815         mz = rte_memzone_reserve("smallest_mz", CACHE_LINE_SIZE,
816                         SOCKET_ID_ANY, 0);
817         if (mz == NULL) {
818                 printf("Failed to reserve memory from smallest memseg!\n");
819                 return -1;
820         }
821         if (prev_min_ms->len != prev_min_len &&
822                         min_ms->len != min_len - CACHE_LINE_SIZE) {
823                 printf("Reserved memory from wrong memseg!\n");
824                 return -1;
825         }
826
827         return 0;
828 }
829
830 /* this test is a bit  tricky, and thus warrants explanation.
831  *
832  * first, we find two smallest memsegs to conduct our experiments on.
833  *
834  * then, we bring them within alignment from each other: if second segment is
835  * twice+ as big as the first, reserve memory from that segment; if second
836  * segment is comparable in length to the first, then cut the first segment
837  * down until it becomes less than half of second segment, and then cut down
838  * the second segment to be within alignment of the first.
839  *
840  * then, we have to pass the following test: if segments are within alignment
841  * of each other (that is, the difference is less than 256 bytes, which is what
842  * our alignment will be), segment with smallest offset should be picked.
843  *
844  * we know that min_ms will be our smallest segment, so we need to make sure
845  * that we adjust the alignments so that the bigger segment has smallest
846  * alignment (in our case, smallest segment will have 64-byte alignment, while
847  * bigger segment will have 128-byte alignment).
848  */
849 static int
850 test_memzone_reserve_memory_with_smallest_offset(void)
851 {
852         const struct rte_memseg *ms, *min_ms, *prev_min_ms;
853         size_t len, min_len, prev_min_len;
854         const struct rte_config *config;
855         int i, align;
856
857         config = rte_eal_get_configuration();
858
859         min_ms = NULL;  /*< smallest segment */
860         prev_min_ms = NULL; /*< second smallest segment */
861         align = CACHE_LINE_SIZE * 4;
862
863         /* find two smallest segments */
864         for (i = 0; i < RTE_MAX_MEMSEG; i++) {
865                 ms = &config->mem_config->free_memseg[i];
866
867                 if (ms->addr == NULL)
868                         break;
869                 if (ms->len == 0)
870                         continue;
871
872                 if (min_ms == NULL)
873                         min_ms = ms;
874                 else if (min_ms->len > ms->len) {
875                         /* set last smallest to second last */
876                         prev_min_ms = min_ms;
877
878                         /* set new smallest */
879                         min_ms = ms;
880                 }
881                 else if (prev_min_ms == NULL) {
882                         prev_min_ms = ms;
883                 }
884         }
885
886         if (min_ms == NULL || prev_min_ms == NULL) {
887                 printf("Smallest segments not found!\n");
888                 return -1;
889         }
890
891         prev_min_len = prev_min_ms->len;
892         min_len = min_ms->len;
893
894         /* if smallest segment is bigger than half of bigger segment */
895         if (prev_min_ms->len - min_ms->len <= min_ms->len) {
896
897                 len = (min_ms->len * 2) - prev_min_ms->len;
898
899                 /* make sure final length is *not* aligned */
900                 while (((min_ms->addr_64 + len) & (align-1)) == 0)
901                         len += CACHE_LINE_SIZE;
902
903                 if (rte_memzone_reserve("dummy_mz1", len, SOCKET_ID_ANY, 0) == NULL) {
904                         printf("Cannot reserve memory!\n");
905                         return -1;
906                 }
907
908                 /* check if we got memory from correct segment */
909                 if (min_ms->len != min_len - len) {
910                         printf("Reserved memory from wrong segment!\n");
911                         return -1;
912                 }
913         }
914     /* if we don't need to touch smallest segment but it's aligned */
915     else if ((min_ms->addr_64 & (align-1)) == 0) {
916             if (rte_memzone_reserve("align_mz1", CACHE_LINE_SIZE,
917                     SOCKET_ID_ANY, 0) == NULL) {
918                             printf("Cannot reserve memory!\n");
919                             return -1;
920             }
921             if (min_ms->len != min_len - CACHE_LINE_SIZE) {
922                     printf("Reserved memory from wrong segment!\n");
923                     return -1;
924             }
925     }
926
927         /* if smallest segment is less than half of bigger segment */
928         if (prev_min_ms->len - min_ms->len > min_ms->len) {
929                 len = prev_min_ms->len - min_ms->len - align;
930
931                 /* make sure final length is aligned */
932                 while (((prev_min_ms->addr_64 + len) & (align-1)) != 0)
933                         len += CACHE_LINE_SIZE;
934
935                 if (rte_memzone_reserve("dummy_mz2", len, SOCKET_ID_ANY, 0) == NULL) {
936                         printf("Cannot reserve memory!\n");
937                         return -1;
938                 }
939
940                 /* check if we got memory from correct segment */
941                 if (prev_min_ms->len != prev_min_len - len) {
942                         printf("Reserved memory from wrong segment!\n");
943                         return -1;
944                 }
945         }
946         len = CACHE_LINE_SIZE;
947
948
949
950         prev_min_len = prev_min_ms->len;
951         min_len = min_ms->len;
952
953         if (min_len >= prev_min_len || prev_min_len - min_len > (unsigned) align) {
954                 printf("Segments are of wrong lengths!\n");
955                 return -1;
956         }
957
958         /* try reserving from a bigger segment */
959         if (rte_memzone_reserve_aligned("smallest_offset", len, SOCKET_ID_ANY, 0, align) ==
960                         NULL) {
961                 printf("Cannot reserve memory!\n");
962                 return -1;
963         }
964
965         /* check if we got memory from correct segment */
966         if (min_ms->len != min_len && prev_min_ms->len != (prev_min_len - len)) {
967                 printf("Reserved memory from segment with smaller offset!\n");
968                 return -1;
969         }
970
971         return 0;
972 }
973
974 static int
975 test_memzone_reserve_remainder(void)
976 {
977         const struct rte_memzone *mz1, *mz2;
978         const struct rte_memseg *ms, *min_ms = NULL;
979         size_t min_len;
980         const struct rte_config *config;
981         int i, align;
982
983         min_len = 0;
984         align = CACHE_LINE_SIZE;
985
986         config = rte_eal_get_configuration();
987
988         /* find minimum free contiguous length */
989         for (i = 0; i < RTE_MAX_MEMSEG; i++) {
990                 ms = &config->mem_config->free_memseg[i];
991
992                 if (ms->addr == NULL)
993                         break;
994                 if (ms->len == 0)
995                         continue;
996
997                 if (min_len == 0 || ms->len < min_len) {
998                         min_len = ms->len;
999                         min_ms = ms;
1000
1001                         /* find maximum alignment this segment is able to hold */
1002                         align = CACHE_LINE_SIZE;
1003                         while ((ms->addr_64 & (align-1)) == 0) {
1004                                 align <<= 1;
1005                         }
1006                 }
1007         }
1008
1009         if (min_ms == NULL) {
1010                 printf("Minimal sized segment not found!\n");
1011                 return -1;
1012         }
1013
1014         /* try reserving min_len bytes with alignment - this should not affect our
1015          * memseg, the memory will be taken from a different one.
1016          */
1017         mz1 = rte_memzone_reserve_aligned("reserve_remainder_1", min_len,
1018                         SOCKET_ID_ANY, 0, align);
1019         if (mz1 == NULL) {
1020                 printf("Failed to reserve %zu bytes aligned on %i bytes\n", min_len,
1021                                 align);
1022                 return -1;
1023         }
1024         if (min_ms->len != min_len) {
1025                 printf("Memseg memory should not have been reserved!\n");
1026                 return -1;
1027         }
1028
1029         /* try reserving min_len bytes with less alignment - this should fill up
1030          * the segment.
1031          */
1032         mz2 = rte_memzone_reserve("reserve_remainder_2", min_len,
1033                         SOCKET_ID_ANY, 0);
1034         if (mz2 == NULL) {
1035                 printf("Failed to reserve %zu bytes\n", min_len);
1036                 return -1;
1037         }
1038         if (min_ms->len != 0) {
1039                 printf("Memseg memory should have been reserved!\n");
1040                 return -1;
1041         }
1042
1043         return 0;
1044 }
1045
1046 static int
1047 test_memzone(void)
1048 {
1049         const struct rte_memzone *memzone1;
1050         const struct rte_memzone *memzone2;
1051         const struct rte_memzone *memzone3;
1052         const struct rte_memzone *memzone4;
1053         const struct rte_memzone *mz;
1054
1055         memzone1 = rte_memzone_reserve("testzone1", 100,
1056                                 SOCKET_ID_ANY, 0);
1057
1058         memzone2 = rte_memzone_reserve("testzone2", 1000,
1059                                 0, 0);
1060
1061         memzone3 = rte_memzone_reserve("testzone3", 1000,
1062                                 1, 0);
1063
1064         memzone4 = rte_memzone_reserve("testzone4", 1024,
1065                                 SOCKET_ID_ANY, 0);
1066
1067         /* memzone3 may be NULL if we don't have NUMA */
1068         if (memzone1 == NULL || memzone2 == NULL || memzone4 == NULL)
1069                 return -1;
1070
1071         rte_memzone_dump(stdout);
1072
1073         /* check cache-line alignments */
1074         printf("check alignments and lengths\n");
1075
1076         if ((memzone1->phys_addr & CACHE_LINE_MASK) != 0)
1077                 return -1;
1078         if ((memzone2->phys_addr & CACHE_LINE_MASK) != 0)
1079                 return -1;
1080         if (memzone3 != NULL && (memzone3->phys_addr & CACHE_LINE_MASK) != 0)
1081                 return -1;
1082         if ((memzone1->len & CACHE_LINE_MASK) != 0 || memzone1->len == 0)
1083                 return -1;
1084         if ((memzone2->len & CACHE_LINE_MASK) != 0 || memzone2->len == 0)
1085                 return -1;
1086         if (memzone3 != NULL && ((memzone3->len & CACHE_LINE_MASK) != 0 ||
1087                         memzone3->len == 0))
1088                 return -1;
1089         if (memzone4->len != 1024)
1090                 return -1;
1091
1092         /* check that zones don't overlap */
1093         printf("check overlapping\n");
1094
1095         if (is_memory_overlap(memzone1->phys_addr, memzone1->len,
1096                         memzone2->phys_addr, memzone2->len))
1097                 return -1;
1098         if (memzone3 != NULL &&
1099                         is_memory_overlap(memzone1->phys_addr, memzone1->len,
1100                                         memzone3->phys_addr, memzone3->len))
1101                 return -1;
1102         if (memzone3 != NULL &&
1103                         is_memory_overlap(memzone2->phys_addr, memzone2->len,
1104                                         memzone3->phys_addr, memzone3->len))
1105                 return -1;
1106
1107         printf("check socket ID\n");
1108
1109         /* memzone2 must be on socket id 0 and memzone3 on socket 1 */
1110         if (memzone2->socket_id != 0)
1111                 return -1;
1112         if (memzone3 != NULL && memzone3->socket_id != 1)
1113                 return -1;
1114
1115         printf("test zone lookup\n");
1116         mz = rte_memzone_lookup("testzone1");
1117         if (mz != memzone1)
1118                 return -1;
1119
1120         printf("test duplcate zone name\n");
1121         mz = rte_memzone_reserve("testzone1", 100,
1122                         SOCKET_ID_ANY, 0);
1123         if (mz != NULL)
1124                 return -1;
1125
1126         printf("test reserving memzone with bigger size than the maximum\n");
1127         if (test_memzone_reserving_zone_size_bigger_than_the_maximum() < 0)
1128                 return -1;
1129
1130         printf("test reserving memory in smallest segments\n");
1131         if (test_memzone_reserve_memory_in_smallest_segment() < 0)
1132                 return -1;
1133
1134         printf("test reserving memory in segments with smallest offsets\n");
1135         if (test_memzone_reserve_memory_with_smallest_offset() < 0)
1136                 return -1;
1137
1138         printf("test memzone_reserve flags\n");
1139         if (test_memzone_reserve_flags() < 0)
1140                 return -1;
1141
1142         printf("test alignment for memzone_reserve\n");
1143         if (test_memzone_aligned() < 0)
1144                 return -1;
1145
1146         printf("test boundary alignment for memzone_reserve\n");
1147         if (test_memzone_bounded() < 0)
1148                 return -1;
1149
1150         printf("test invalid alignment for memzone_reserve\n");
1151         if (test_memzone_invalid_alignment() < 0)
1152                 return -1;
1153
1154         printf("test reserving amounts of memory equal to segment's length\n");
1155         if (test_memzone_reserve_remainder() < 0)
1156                 return -1;
1157
1158         printf("test reserving the largest size memzone possible\n");
1159         if (test_memzone_reserve_max() < 0)
1160                 return -1;
1161
1162         printf("test reserving the largest size aligned memzone possible\n");
1163         if (test_memzone_reserve_max_aligned() < 0)
1164                 return -1;
1165
1166         return 0;
1167 }
1168
1169 static struct test_command memzone_cmd = {
1170         .command = "memzone_autotest",
1171         .callback = test_memzone,
1172 };
1173 REGISTER_TEST_COMMAND(memzone_cmd);