1 /*
2 * Copyright (C) Texas Instruments - http://www.ti.com/
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 /*
18 * Test case to test ION Memory Allocator module
19 */
20
21 #include <errno.h>
22 #include <fcntl.h>
23 #include <getopt.h>
24 #include <string.h>
25 #include <stdlib.h>
26 #include <stdio.h>
27 #include <sys/mman.h>
28 #include <sys/ioctl.h>
29 #include <sys/socket.h>
30 #include <sys/stat.h>
31 #include <sys/types.h>
32 #include <unistd.h>
33
34 #include <ion/ion.h>
35 #include <linux/ion.h>
36 #include <linux/omap_ion.h>
37
38 size_t len = 1024*1024, align = 0;
39 int prot = PROT_READ | PROT_WRITE;
40 int map_flags = MAP_SHARED;
41 int alloc_flags = 0;
42 int test = -1;
43 size_t width = 1024*1024, height = 1024*1024;
44 int fmt = TILER_PIXEL_FMT_32BIT;
45 int tiler_test = 0;
46 size_t stride;
47
_ion_alloc_test(int fd,struct ion_handle ** handle)48 int _ion_alloc_test(int fd, struct ion_handle **handle)
49 {
50 int ret;
51
52 if (tiler_test)
53 ret = ion_alloc_tiler(fd, width, height, fmt, alloc_flags,
54 handle, &stride);
55 else
56 ret = ion_alloc(fd, len, align, alloc_flags, handle);
57
58 if (ret)
59 printf("%s() failed: %s\n", __func__, strerror(ret));
60 return ret;
61 }
62
ion_alloc_test(int count)63 int ion_alloc_test(int count)
64 {
65 int fd, ret = 0, i, count_alloc;
66 struct ion_handle **handle;
67
68 fd = ion_open();
69 if (fd < 0) {
70 printf("%s(): FAILED to open ion device\n", __func__);
71 return -1;
72 }
73
74 handle = (struct ion_handle **)malloc(count * sizeof(struct ion_handle *));
75 if(handle == NULL) {
76 printf("%s() : FAILED to allocate memory for ion_handles\n", __func__);
77 return -ENOMEM;
78 }
79
80 /* Allocate ion_handles */
81 count_alloc = count;
82 for(i = 0; i < count; i++) {
83 ret = _ion_alloc_test(fd, &(handle[i]));
84 printf("%s(): Alloc handle[%d]=%p\n", __func__, i, handle[i]);
85 if(ret || ((int)handle[i] == -ENOMEM)) {
86 printf("%s(): Alloc handle[%d]=%p FAILED, err:%s\n",
87 __func__, i, handle[i], strerror(ret));
88 count_alloc = i;
89 goto err_alloc;
90 }
91 }
92
93 err_alloc:
94 /* Free ion_handles */
95 for (i = 0; i < count_alloc; i++) {
96 printf("%s(): Free handle[%d]=%p\n", __func__, i, handle[i]);
97 ret = ion_free(fd, handle[i]);
98 if (ret) {
99 printf("%s(): Free handle[%d]=%p FAILED, err:%s\n",
100 __func__, i, handle[i], strerror(ret));
101 }
102 }
103
104 ion_close(fd);
105 free(handle);
106 handle = NULL;
107
108 if(ret || (count_alloc != count)) {
109 printf("\nion alloc test: FAILED\n\n");
110 if(count_alloc != count)
111 ret = -ENOMEM;
112 }
113 else
114 printf("\nion alloc test: PASSED\n\n");
115
116 return ret;
117 }
118
_ion_tiler_map_test(unsigned char * ptr)119 void _ion_tiler_map_test(unsigned char *ptr)
120 {
121 size_t row, col;
122
123 for (row = 0; row < height; row++)
124 for (col = 0; col < width; col++) {
125 int i = (row * stride) + col;
126 ptr[i] = (unsigned char)i;
127 }
128 for (row = 0; row < height; row++)
129 for (col = 0; col < width; col++) {
130 int i = (row * stride) + col;
131 if (ptr[i] != (unsigned char)i)
132 printf("%s(): FAILED, wrote %d read %d from mapped "
133 "memory\n", __func__, i, ptr[i]);
134 }
135 }
136
_ion_map_test(unsigned char * ptr)137 void _ion_map_test(unsigned char *ptr)
138 {
139 size_t i;
140
141 for (i = 0; i < len; i++) {
142 ptr[i] = (unsigned char)i;
143 }
144 for (i = 0; i < len; i++) {
145 if (ptr[i] != (unsigned char)i)
146 printf("%s(): failed wrote %d read %d from mapped "
147 "memory\n", __func__, i, ptr[i]);
148 }
149 }
150
ion_map_test(int count)151 int ion_map_test(int count)
152 {
153 int fd, ret = 0, i, count_alloc, count_map;
154 struct ion_handle **handle;
155 unsigned char **ptr;
156 int *map_fd;
157
158 fd = ion_open();
159 if (fd < 0) {
160 printf("%s(): FAILED to open ion device\n", __func__);
161 return -1;
162 }
163
164 handle = (struct ion_handle **)malloc(count * sizeof(struct ion_handle *));
165 if(handle == NULL) {
166 printf("%s(): FAILED to allocate memory for ion_handles\n", __func__);
167 return -ENOMEM;
168 }
169
170 count_alloc = count;
171 count_map = count;
172
173 /* Allocate ion_handles */
174 for(i = 0; i < count; i++) {
175 ret = _ion_alloc_test(fd, &(handle[i]));
176 printf("%s(): Alloc handle[%d]=%p\n", __func__, i, handle[i]);
177 if(ret || ((int)handle[i] == -ENOMEM)) {
178 printf("%s(): Alloc handle[%d]=%p FAILED, err:%s\n",
179 __func__, i, handle[i], strerror(ret));
180 count_alloc = i;
181 goto err_alloc;
182 }
183 }
184
185 /* Map ion_handles and validate */
186 if (tiler_test)
187 len = height * stride;
188
189 ptr = (unsigned char **)malloc(count * sizeof(unsigned char **));
190 map_fd = (int *)malloc(count * sizeof(int *));
191
192 for(i = 0; i < count; i++) {
193 /* Map ion_handle on userside */
194 ret = ion_map(fd, handle[i], len, prot, map_flags, 0, &(ptr[i]), &(map_fd[i]));
195 printf("%s(): Map handle[%d]=%p, map_fd=%d, ptr=%p\n",
196 __func__, i, handle[i], map_fd[i], ptr[i]);
197 if(ret) {
198 printf("%s Map handle[%d]=%p FAILED, err:%s\n",
199 __func__, i, handle[i], strerror(ret));
200 count_map = i;
201 goto err_map;
202 }
203
204 /* Validate mapping by writing the data and reading it back */
205 if (tiler_test)
206 _ion_tiler_map_test(ptr[i]);
207 else
208 _ion_map_test(ptr[i]);
209 }
210
211 /* clean up properly */
212 err_map:
213 for(i = 0; i < count_map; i++) {
214 /* Unmap ion_handles */
215 ret = munmap(ptr[i], len);
216 printf("%s(): Unmap handle[%d]=%p, map_fd=%d, ptr=%p\n",
217 __func__, i, handle[i], map_fd[i], ptr[i]);
218 if(ret) {
219 printf("%s(): Unmap handle[%d]=%p FAILED, err:%s\n",
220 __func__, i, handle[i], strerror(ret));
221 goto err_map;
222 }
223 /* Close fds */
224 close(map_fd[i]);
225 }
226 free(map_fd);
227 free(ptr);
228
229 err_alloc:
230 /* Free ion_handles */
231 for (i = 0; i < count_alloc; i++) {
232 printf("%s(): Free handle[%d]=%p\n", __func__, i, handle[i]);
233 ret = ion_free(fd, handle[i]);
234 if (ret) {
235 printf("%s(): Free handle[%d]=%p FAILED, err:%s\n",
236 __func__, i, handle[i], strerror(ret));
237 }
238 }
239
240 ion_close(fd);
241 free(handle);
242 handle = NULL;
243
244 if(ret || (count_alloc != count) || (count_map != count))
245 {
246 printf("\nion map test: FAILED\n\n");
247 if((count_alloc != count) || (count_map != count))
248 ret = -ENOMEM;
249 } else
250 printf("\nion map test: PASSED\n");
251
252 return ret;
253 }
254
255 /**
256 * Go on allocating buffers of specified size & type, untill the allocation fails.
257 * Then free 10 buffers and allocate 10 buffers again.
258 */
ion_alloc_fail_alloc_test()259 int ion_alloc_fail_alloc_test()
260 {
261 int fd, ret = 0, i;
262 struct ion_handle **handle;
263 const int COUNT_ALLOC_MAX = 200;
264 const int COUNT_REALLOC_MAX = 10;
265 int count_alloc = COUNT_ALLOC_MAX, count_realloc = COUNT_ALLOC_MAX;
266
267 fd = ion_open();
268 if (fd < 0) {
269 printf("%s(): FAILED to open ion device\n", __func__);
270 return -1;
271 }
272
273 handle = (struct ion_handle **)malloc(COUNT_ALLOC_MAX * sizeof(struct ion_handle *));
274 if(handle == NULL) {
275 printf("%s(): FAILED to allocate memory for ion_handles\n", __func__);
276 return -ENOMEM;
277 }
278
279 /* Allocate ion_handles as much as possible */
280 for(i = 0; i < COUNT_ALLOC_MAX; i++) {
281 ret = _ion_alloc_test(fd, &(handle[i]));
282 printf("%s(): Alloc handle[%d]=%p\n", __func__, i, handle[i]);
283 if(ret || ((int)handle[i] == -ENOMEM)) {
284 printf("%s(): Alloc handle[%d]=%p FAILED, err:%s\n\n",
285 __func__, i, handle[i], strerror(ret));
286 count_alloc = i;
287 break;
288 }
289 }
290
291 /* Free COUNT_REALLOC_MAX ion_handles */
292 for (i = count_alloc-1; i > (count_alloc-1 - COUNT_REALLOC_MAX); i--) {
293 printf("%s(): Free handle[%d]=%p\n", __func__, i, handle[i]);
294 ret = ion_free(fd, handle[i]);
295 if (ret) {
296 printf("%s(): Free handle[%d]=%p FAILED, err:%s\n\n",
297 __func__, i, handle[i], strerror(ret));
298 }
299 }
300
301 /* Again allocate COUNT_REALLOC_MAX ion_handles to test
302 that we are still able to allocate */
303 for(i = (count_alloc - COUNT_REALLOC_MAX); i < count_alloc; i++) {
304 ret = _ion_alloc_test(fd, &(handle[i]));
305 printf("%s(): Alloc handle[%d]=%p\n", __func__, i, handle[i]);
306 if(ret || ((int)handle[i] == -ENOMEM)) {
307 printf("%s(): Alloc handle[%d]=%p FAILED, err:%s\n\n",
308 __func__, i, handle[i], strerror(ret));
309 count_realloc = i;
310 goto err_alloc;
311 }
312 }
313 count_realloc = i;
314
315 err_alloc:
316 /* Free all ion_handles */
317 for (i = 0; i < count_alloc; i++) {
318 printf("%s(): Free handle[%d]=%p\n", __func__, i, handle[i]);
319 ret = ion_free(fd, handle[i]);
320 if (ret) {
321 printf("%s(): Free handle[%d]=%p FAILED, err:%s\n",
322 __func__, i, handle[i], strerror(ret));
323 }
324 }
325
326 ion_close(fd);
327 free(handle);
328 handle = NULL;
329
330 printf("\ncount_alloc=%d, count_realloc=%d\n",count_alloc, count_realloc);
331
332 if(ret || (count_alloc != count_realloc)) {
333 printf("\nion alloc->fail->alloc test: FAILED\n\n");
334 if(count_alloc != COUNT_ALLOC_MAX)
335 ret = -ENOMEM;
336 }
337 else
338 printf("\nion alloc->fail->alloc test: PASSED\n\n");
339
340 return ret;
341 }
342
custom_test(int test_number)343 int custom_test(int test_number)
344 {
345 switch(test_number) {
346 case 1 :
347 return ion_alloc_fail_alloc_test();
348 default :
349 printf("%s(): Invalid custom_test_number=%d\n", __func__, test_number);
350 return -EINVAL;
351 }
352 }
353
main(int argc,char * argv[])354 int main(int argc, char* argv[]) {
355 int c, ret;
356 unsigned int count = 1, iteration = 1, j, custom_test_num = 1;
357 enum tests {
358 ALLOC_TEST = 0, MAP_TEST, CUSTOM_TEST,
359 };
360
361 while (1) {
362 static struct option opts[] = {
363 {"alloc", no_argument, 0, 'a'},
364 {"alloc_flags", required_argument, 0, 'f'},
365 {"map", no_argument, 0, 'm'},
366 {"custom", required_argument, 0, 'c'},
367 {"len", required_argument, 0, 'l'},
368 {"align", required_argument, 0, 'g'},
369 {"map_flags", required_argument, 0, 'z'},
370 {"prot", required_argument, 0, 'p'},
371 {"alloc_tiler", no_argument, 0, 't'},
372 {"width", required_argument, 0, 'w'},
373 {"height", required_argument, 0, 'h'},
374 {"fmt", required_argument, 0, 'r'},
375 {"count", required_argument, 0, 'n'},
376 {"iteration", required_argument, 0, 'i'},
377 };
378 int i = 0;
379 c = getopt_long(argc, argv, "af:h:l:mr:stw:c:n:i:", opts, &i);
380 if (c == -1)
381 break;
382
383 switch (c) {
384 case 'l':
385 len = atol(optarg);
386 break;
387 case 'g':
388 align = atol(optarg);
389 break;
390 case 'z':
391 map_flags = 0;
392 map_flags |= strstr(optarg, "PROT_EXEC") ?
393 PROT_EXEC : 0;
394 map_flags |= strstr(optarg, "PROT_READ") ?
395 PROT_READ: 0;
396 map_flags |= strstr(optarg, "PROT_WRITE") ?
397 PROT_WRITE: 0;
398 map_flags |= strstr(optarg, "PROT_NONE") ?
399 PROT_NONE: 0;
400 break;
401 case 'p':
402 prot = 0;
403 prot |= strstr(optarg, "MAP_PRIVATE") ?
404 MAP_PRIVATE : 0;
405 prot |= strstr(optarg, "MAP_SHARED") ?
406 MAP_PRIVATE : 0;
407 break;
408 case 'f':
409 alloc_flags = atol(optarg);
410 break;
411 case 'a':
412 test = ALLOC_TEST;
413 break;
414 case 'm':
415 test = MAP_TEST;
416 break;
417 case 'c':
418 test = CUSTOM_TEST;
419 printf("KALP : Case 'c'\n");
420 custom_test_num = atol(optarg);
421 break;
422 case 'r':
423 fmt = atol(optarg);
424 break;
425 case 'w':
426 width = atol(optarg);
427 break;
428 case 'h':
429 height = atol(optarg);
430 break;
431 case 't':
432 tiler_test = 1;
433 break;
434 case 'n':
435 printf("KALP : Case 'n'\n");
436 count = atol(optarg);
437 break;
438 case 'i':
439 printf("KALP : Case 'i'\n");
440 iteration = atol(optarg);
441 break;
442 }
443 }
444 printf("test %d, len %u, width %u, height %u, fmt %u, align %u, count %d, "
445 "iteration %d, map_flags %d, prot %d, alloc_flags %d\n", test, len, width,
446 height, fmt, align, count, iteration, map_flags, prot, alloc_flags);
447
448 switch (test) {
449 case ALLOC_TEST:
450 for(j = 0; j < iteration; j++) {
451 ret = ion_alloc_test(count);
452 if(ret) {
453 printf("\nion alloc test: FAILED at iteration-%d\n", j+1);
454 break;
455 }
456 }
457 break;
458
459 case MAP_TEST:
460 for(j = 0; j < iteration; j++) {
461 ret = ion_map_test(count);
462 if(ret) {
463 printf("\nion map test: FAILED at iteration-%d\n", j+1);
464 break;
465 }
466 }
467 break;
468
469 case CUSTOM_TEST:
470 ret = custom_test(custom_test_num);
471 if(ret) {
472 printf("\nion custom test #%d: FAILED\n", custom_test_num);
473 }
474 break;
475
476 default:
477 printf("must specify a test (alloc, map, custom)\n");
478 }
479
480 return 0;
481 }
482