1 #include <stdio.h> 2 #include <assert.h> 3 4 #include <linux/scatterlist.h> 5 6 #define MAX_PAGES (64) 7 8 struct test { 9 int alloc_ret; 10 unsigned num_pages; 11 unsigned *pfn; 12 unsigned size; 13 unsigned int max_seg; 14 unsigned int expected_segments; 15 }; 16 17 static void set_pages(struct page **pages, const unsigned *array, unsigned num) 18 { 19 unsigned int i; 20 21 assert(num < MAX_PAGES); 22 for (i = 0; i < num; i++) 23 pages[i] = (struct page *)(unsigned long) 24 ((1 + array[i]) * PAGE_SIZE); 25 } 26 27 #define pfn(...) (unsigned []){ __VA_ARGS__ } 28 29 static void fail(struct test *test, struct sg_table *st, const char *cond) 30 { 31 unsigned int i; 32 33 fprintf(stderr, "Failed on '%s'!\n\n", cond); 34 35 printf("size = %u, max segment = %u, expected nents = %u\nst->nents = %u, st->orig_nents= %u\n", 36 test->size, test->max_seg, test->expected_segments, st->nents, 37 st->orig_nents); 38 39 printf("%u input PFNs:", test->num_pages); 40 for (i = 0; i < test->num_pages; i++) 41 printf(" %x", test->pfn[i]); 42 printf("\n"); 43 44 exit(1); 45 } 46 47 #define VALIDATE(cond, st, test) \ 48 if (!(cond)) \ 49 fail((test), (st), #cond); 50 51 int main(void) 52 { 53 const unsigned int sgmax = SCATTERLIST_MAX_SEGMENT; 54 struct test *test, tests[] = { 55 { -EINVAL, 1, pfn(0), PAGE_SIZE, PAGE_SIZE + 1, 1 }, 56 { -EINVAL, 1, pfn(0), PAGE_SIZE, 0, 1 }, 57 { -EINVAL, 1, pfn(0), PAGE_SIZE, sgmax + 1, 1 }, 58 { 0, 1, pfn(0), PAGE_SIZE, sgmax, 1 }, 59 { 0, 1, pfn(0), 1, sgmax, 1 }, 60 { 0, 2, pfn(0, 1), 2 * PAGE_SIZE, sgmax, 1 }, 61 { 0, 2, pfn(1, 0), 2 * PAGE_SIZE, sgmax, 2 }, 62 { 0, 3, pfn(0, 1, 2), 3 * PAGE_SIZE, sgmax, 1 }, 63 { 0, 3, pfn(0, 2, 1), 3 * PAGE_SIZE, sgmax, 3 }, 64 { 0, 3, pfn(0, 1, 3), 3 * PAGE_SIZE, sgmax, 2 }, 65 { 0, 3, pfn(1, 2, 4), 3 * PAGE_SIZE, sgmax, 2 }, 66 { 0, 3, pfn(1, 3, 4), 3 * PAGE_SIZE, sgmax, 2 }, 67 { 0, 4, pfn(0, 1, 3, 4), 4 * PAGE_SIZE, sgmax, 2 }, 68 { 0, 5, pfn(0, 1, 3, 4, 5), 5 * PAGE_SIZE, sgmax, 2 }, 69 { 0, 5, pfn(0, 1, 3, 4, 6), 5 * PAGE_SIZE, sgmax, 3 }, 70 { 0, 5, pfn(0, 1, 2, 3, 4), 5 * PAGE_SIZE, sgmax, 1 }, 71 { 0, 5, pfn(0, 1, 2, 3, 4), 5 * PAGE_SIZE, 2 * PAGE_SIZE, 3 }, 72 { 0, 6, pfn(0, 1, 2, 3, 4, 5), 6 * PAGE_SIZE, 2 * PAGE_SIZE, 3 }, 73 { 0, 6, pfn(0, 2, 3, 4, 5, 6), 6 * PAGE_SIZE, 2 * PAGE_SIZE, 4 }, 74 { 0, 6, pfn(0, 1, 3, 4, 5, 6), 6 * PAGE_SIZE, 2 * PAGE_SIZE, 3 }, 75 { 0, 0, NULL, 0, 0, 0 }, 76 }; 77 unsigned int i; 78 79 for (i = 0, test = tests; test->expected_segments; test++, i++) { 80 struct page *pages[MAX_PAGES]; 81 struct sg_table st; 82 struct scatterlist *sg; 83 84 set_pages(pages, test->pfn, test->num_pages); 85 86 sg = __sg_alloc_table_from_pages(&st, pages, test->num_pages, 0, 87 test->size, test->max_seg, NULL, 0, GFP_KERNEL); 88 assert(PTR_ERR_OR_ZERO(sg) == test->alloc_ret); 89 90 if (test->alloc_ret) 91 continue; 92 93 VALIDATE(st.nents == test->expected_segments, &st, test); 94 VALIDATE(st.orig_nents == test->expected_segments, &st, test); 95 96 sg_free_table(&st); 97 } 98 99 assert(i == (sizeof(tests) / sizeof(tests[0])) - 1); 100 101 return 0; 102 } 103