18c2ecf20Sopenharmony_ci#include <stdio.h>
28c2ecf20Sopenharmony_ci#include <assert.h>
38c2ecf20Sopenharmony_ci
48c2ecf20Sopenharmony_ci#include <linux/scatterlist.h>
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci#define MAX_PAGES (64)
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_cistruct test {
98c2ecf20Sopenharmony_ci	int alloc_ret;
108c2ecf20Sopenharmony_ci	unsigned num_pages;
118c2ecf20Sopenharmony_ci	unsigned *pfn;
128c2ecf20Sopenharmony_ci	unsigned size;
138c2ecf20Sopenharmony_ci	unsigned int max_seg;
148c2ecf20Sopenharmony_ci	unsigned int expected_segments;
158c2ecf20Sopenharmony_ci};
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_cistatic void set_pages(struct page **pages, const unsigned *array, unsigned num)
188c2ecf20Sopenharmony_ci{
198c2ecf20Sopenharmony_ci	unsigned int i;
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci	assert(num < MAX_PAGES);
228c2ecf20Sopenharmony_ci	for (i = 0; i < num; i++)
238c2ecf20Sopenharmony_ci		pages[i] = (struct page *)(unsigned long)
248c2ecf20Sopenharmony_ci			   ((1 + array[i]) * PAGE_SIZE);
258c2ecf20Sopenharmony_ci}
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci#define pfn(...) (unsigned []){ __VA_ARGS__ }
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_cistatic void fail(struct test *test, struct sg_table *st, const char *cond)
308c2ecf20Sopenharmony_ci{
318c2ecf20Sopenharmony_ci	unsigned int i;
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci	fprintf(stderr, "Failed on '%s'!\n\n", cond);
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci	printf("size = %u, max segment = %u, expected nents = %u\nst->nents = %u, st->orig_nents= %u\n",
368c2ecf20Sopenharmony_ci	       test->size, test->max_seg, test->expected_segments, st->nents,
378c2ecf20Sopenharmony_ci	       st->orig_nents);
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci	printf("%u input PFNs:", test->num_pages);
408c2ecf20Sopenharmony_ci	for (i = 0; i < test->num_pages; i++)
418c2ecf20Sopenharmony_ci		printf(" %x", test->pfn[i]);
428c2ecf20Sopenharmony_ci	printf("\n");
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci	exit(1);
458c2ecf20Sopenharmony_ci}
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci#define VALIDATE(cond, st, test) \
488c2ecf20Sopenharmony_ci	if (!(cond)) \
498c2ecf20Sopenharmony_ci		fail((test), (st), #cond);
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ciint main(void)
528c2ecf20Sopenharmony_ci{
538c2ecf20Sopenharmony_ci	const unsigned int sgmax = SCATTERLIST_MAX_SEGMENT;
548c2ecf20Sopenharmony_ci	struct test *test, tests[] = {
558c2ecf20Sopenharmony_ci		{ -EINVAL, 1, pfn(0), PAGE_SIZE, 0, 1 },
568c2ecf20Sopenharmony_ci		{ 0, 1, pfn(0), PAGE_SIZE, PAGE_SIZE + 1, 1 },
578c2ecf20Sopenharmony_ci		{ 0, 1, pfn(0), PAGE_SIZE, sgmax + 1, 1 },
588c2ecf20Sopenharmony_ci		{ 0, 1, pfn(0), PAGE_SIZE, sgmax, 1 },
598c2ecf20Sopenharmony_ci		{ 0, 1, pfn(0), 1, sgmax, 1 },
608c2ecf20Sopenharmony_ci		{ 0, 2, pfn(0, 1), 2 * PAGE_SIZE, sgmax, 1 },
618c2ecf20Sopenharmony_ci		{ 0, 2, pfn(1, 0), 2 * PAGE_SIZE, sgmax, 2 },
628c2ecf20Sopenharmony_ci		{ 0, 3, pfn(0, 1, 2), 3 * PAGE_SIZE, sgmax, 1 },
638c2ecf20Sopenharmony_ci		{ 0, 3, pfn(0, 2, 1), 3 * PAGE_SIZE, sgmax, 3 },
648c2ecf20Sopenharmony_ci		{ 0, 3, pfn(0, 1, 3), 3 * PAGE_SIZE, sgmax, 2 },
658c2ecf20Sopenharmony_ci		{ 0, 3, pfn(1, 2, 4), 3 * PAGE_SIZE, sgmax, 2 },
668c2ecf20Sopenharmony_ci		{ 0, 3, pfn(1, 3, 4), 3 * PAGE_SIZE, sgmax, 2 },
678c2ecf20Sopenharmony_ci		{ 0, 4, pfn(0, 1, 3, 4), 4 * PAGE_SIZE, sgmax, 2 },
688c2ecf20Sopenharmony_ci		{ 0, 5, pfn(0, 1, 3, 4, 5), 5 * PAGE_SIZE, sgmax, 2 },
698c2ecf20Sopenharmony_ci		{ 0, 5, pfn(0, 1, 3, 4, 6), 5 * PAGE_SIZE, sgmax, 3 },
708c2ecf20Sopenharmony_ci		{ 0, 5, pfn(0, 1, 2, 3, 4), 5 * PAGE_SIZE, sgmax, 1 },
718c2ecf20Sopenharmony_ci		{ 0, 5, pfn(0, 1, 2, 3, 4), 5 * PAGE_SIZE, 2 * PAGE_SIZE, 3 },
728c2ecf20Sopenharmony_ci		{ 0, 6, pfn(0, 1, 2, 3, 4, 5), 6 * PAGE_SIZE, 2 * PAGE_SIZE, 3 },
738c2ecf20Sopenharmony_ci		{ 0, 6, pfn(0, 2, 3, 4, 5, 6), 6 * PAGE_SIZE, 2 * PAGE_SIZE, 4 },
748c2ecf20Sopenharmony_ci		{ 0, 6, pfn(0, 1, 3, 4, 5, 6), 6 * PAGE_SIZE, 2 * PAGE_SIZE, 3 },
758c2ecf20Sopenharmony_ci		{ 0, 0, NULL, 0, 0, 0 },
768c2ecf20Sopenharmony_ci	};
778c2ecf20Sopenharmony_ci	unsigned int i;
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci	for (i = 0, test = tests; test->expected_segments; test++, i++) {
808c2ecf20Sopenharmony_ci		struct page *pages[MAX_PAGES];
818c2ecf20Sopenharmony_ci		struct sg_table st;
828c2ecf20Sopenharmony_ci		struct scatterlist *sg;
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci		set_pages(pages, test->pfn, test->num_pages);
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci		sg = __sg_alloc_table_from_pages(&st, pages, test->num_pages, 0,
878c2ecf20Sopenharmony_ci				test->size, test->max_seg, NULL, 0, GFP_KERNEL);
888c2ecf20Sopenharmony_ci		assert(PTR_ERR_OR_ZERO(sg) == test->alloc_ret);
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci		if (test->alloc_ret)
918c2ecf20Sopenharmony_ci			continue;
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci		VALIDATE(st.nents == test->expected_segments, &st, test);
948c2ecf20Sopenharmony_ci		VALIDATE(st.orig_nents == test->expected_segments, &st, test);
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci		sg_free_table(&st);
978c2ecf20Sopenharmony_ci	}
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci	assert(i == (sizeof(tests) / sizeof(tests[0])) - 1);
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci	return 0;
1028c2ecf20Sopenharmony_ci}
103