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 *pfn_app; |
13 | unsigned size; |
14 | unsigned int max_seg; |
15 | unsigned int expected_segments; |
16 | }; |
17 | |
18 | static void set_pages(struct page **pages, const unsigned *array, unsigned num) |
19 | { |
20 | unsigned int i; |
21 | |
22 | assert(num < MAX_PAGES); |
23 | for (i = 0; i < num; i++) |
24 | pages[i] = (struct page *)(unsigned long) |
25 | ((1 + array[i]) * PAGE_SIZE); |
26 | } |
27 | |
28 | #define pfn(...) (unsigned []){ __VA_ARGS__ } |
29 | |
30 | static void fail(struct test *test, struct sg_table *st, const char *cond) |
31 | { |
32 | unsigned int i; |
33 | |
34 | fprintf(stderr, "Failed on '%s'!\n\n" , cond); |
35 | |
36 | printf("size = %u, max segment = %u, expected nents = %u\nst->nents = %u, st->orig_nents= %u\n" , |
37 | test->size, test->max_seg, test->expected_segments, st->nents, |
38 | st->orig_nents); |
39 | |
40 | printf("%u input PFNs:" , test->num_pages); |
41 | for (i = 0; i < test->num_pages; i++) |
42 | printf(" %x" , test->pfn[i]); |
43 | printf("\n" ); |
44 | |
45 | exit(1); |
46 | } |
47 | |
48 | #define VALIDATE(cond, st, test) \ |
49 | if (!(cond)) \ |
50 | fail((test), (st), #cond); |
51 | |
52 | int main(void) |
53 | { |
54 | const unsigned int sgmax = UINT_MAX; |
55 | struct test *test, tests[] = { |
56 | { -EINVAL, 1, pfn(0), NULL, PAGE_SIZE, 0, 1 }, |
57 | { 0, 1, pfn(0), NULL, PAGE_SIZE, PAGE_SIZE + 1, 1 }, |
58 | { 0, 1, pfn(0), NULL, PAGE_SIZE, sgmax, 1 }, |
59 | { 0, 1, pfn(0), NULL, 1, sgmax, 1 }, |
60 | { 0, 2, pfn(0, 1), NULL, 2 * PAGE_SIZE, sgmax, 1 }, |
61 | { 0, 2, pfn(1, 0), NULL, 2 * PAGE_SIZE, sgmax, 2 }, |
62 | { 0, 3, pfn(0, 1, 2), NULL, 3 * PAGE_SIZE, sgmax, 1 }, |
63 | { 0, 3, pfn(0, 1, 2), NULL, 3 * PAGE_SIZE, sgmax, 1 }, |
64 | { 0, 3, pfn(0, 1, 2), pfn(3, 4, 5), 3 * PAGE_SIZE, sgmax, 1 }, |
65 | { 0, 3, pfn(0, 1, 2), pfn(4, 5, 6), 3 * PAGE_SIZE, sgmax, 2 }, |
66 | { 0, 3, pfn(0, 2, 1), NULL, 3 * PAGE_SIZE, sgmax, 3 }, |
67 | { 0, 3, pfn(0, 1, 3), NULL, 3 * PAGE_SIZE, sgmax, 2 }, |
68 | { 0, 3, pfn(1, 2, 4), NULL, 3 * PAGE_SIZE, sgmax, 2 }, |
69 | { 0, 3, pfn(1, 3, 4), NULL, 3 * PAGE_SIZE, sgmax, 2 }, |
70 | { 0, 4, pfn(0, 1, 3, 4), NULL, 4 * PAGE_SIZE, sgmax, 2 }, |
71 | { 0, 5, pfn(0, 1, 3, 4, 5), NULL, 5 * PAGE_SIZE, sgmax, 2 }, |
72 | { 0, 5, pfn(0, 1, 3, 4, 6), NULL, 5 * PAGE_SIZE, sgmax, 3 }, |
73 | { 0, 5, pfn(0, 1, 2, 3, 4), NULL, 5 * PAGE_SIZE, sgmax, 1 }, |
74 | { 0, 5, pfn(0, 1, 2, 3, 4), NULL, 5 * PAGE_SIZE, 2 * PAGE_SIZE, |
75 | 3 }, |
76 | { 0, 6, pfn(0, 1, 2, 3, 4, 5), NULL, 6 * PAGE_SIZE, |
77 | 2 * PAGE_SIZE, 3 }, |
78 | { 0, 6, pfn(0, 2, 3, 4, 5, 6), NULL, 6 * PAGE_SIZE, |
79 | 2 * PAGE_SIZE, 4 }, |
80 | { 0, 6, pfn(0, 1, 3, 4, 5, 6), pfn(7, 8, 9, 10, 11, 12), |
81 | 6 * PAGE_SIZE, 12 * PAGE_SIZE, 2 }, |
82 | { 0, 0, NULL, NULL, 0, 0, 0 }, |
83 | }; |
84 | unsigned int i; |
85 | |
86 | for (i = 0, test = tests; test->expected_segments; test++, i++) { |
87 | int left_pages = test->pfn_app ? test->num_pages : 0; |
88 | struct sg_append_table append = {}; |
89 | struct page *pages[MAX_PAGES]; |
90 | int ret; |
91 | |
92 | set_pages(pages, array: test->pfn, num: test->num_pages); |
93 | |
94 | if (test->pfn_app) |
95 | ret = sg_alloc_append_table_from_pages( |
96 | sgt: &append, pages, n_pages: test->num_pages, offset: 0, size: test->size, |
97 | max_segment: test->max_seg, left_pages, GFP_KERNEL); |
98 | else |
99 | ret = sg_alloc_table_from_pages_segment( |
100 | sgt: &append.sgt, pages, n_pages: test->num_pages, offset: 0, |
101 | size: test->size, max_segment: test->max_seg, GFP_KERNEL); |
102 | |
103 | assert(ret == test->alloc_ret); |
104 | |
105 | if (test->alloc_ret) |
106 | continue; |
107 | |
108 | if (test->pfn_app) { |
109 | set_pages(pages, array: test->pfn_app, num: test->num_pages); |
110 | ret = sg_alloc_append_table_from_pages( |
111 | sgt: &append, pages, n_pages: test->num_pages, offset: 0, size: test->size, |
112 | max_segment: test->max_seg, left_pages: 0, GFP_KERNEL); |
113 | |
114 | assert(ret == test->alloc_ret); |
115 | } |
116 | |
117 | VALIDATE(append.sgt.nents == test->expected_segments, |
118 | &append.sgt, test); |
119 | if (!test->pfn_app) |
120 | VALIDATE(append.sgt.orig_nents == |
121 | test->expected_segments, |
122 | &append.sgt, test); |
123 | |
124 | if (test->pfn_app) |
125 | sg_free_append_table(sgt: &append); |
126 | else |
127 | sg_free_table(&append.sgt); |
128 | } |
129 | |
130 | assert(i == (sizeof(tests) / sizeof(tests[0])) - 1); |
131 | |
132 | return 0; |
133 | } |
134 | |