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
38size_t len = 1024*1024, align = 0;
39int prot = PROT_READ | PROT_WRITE;
40int map_flags = MAP_SHARED;
41int alloc_flags = 0;
42int test = -1;
43size_t width = 1024*1024, height = 1024*1024;
44int fmt = TILER_PIXEL_FMT_32BIT;
45int tiler_test = 0;
46size_t stride;
47
48int _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
63int 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
119void _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
137void _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
151int 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 */
259int 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
343int 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
354int 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