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