1 | // SPDX-License-Identifier: GPL-2.0 AND MIT |
2 | /* |
3 | * Copyright © 2023 Intel Corporation |
4 | */ |
5 | #include <linux/shmem_fs.h> |
6 | #include <drm/ttm/ttm_tt.h> |
7 | |
8 | #include "ttm_kunit_helpers.h" |
9 | |
10 | #define BO_SIZE SZ_4K |
11 | |
12 | struct ttm_tt_test_case { |
13 | const char *description; |
14 | uint32_t size; |
15 | uint32_t ; |
16 | }; |
17 | |
18 | static int ttm_tt_test_init(struct kunit *test) |
19 | { |
20 | struct ttm_test_devices *priv; |
21 | |
22 | priv = kunit_kzalloc(test, size: sizeof(*priv), GFP_KERNEL); |
23 | KUNIT_ASSERT_NOT_NULL(test, priv); |
24 | |
25 | priv = ttm_test_devices_all(test); |
26 | test->priv = priv; |
27 | |
28 | return 0; |
29 | } |
30 | |
31 | static const struct ttm_tt_test_case ttm_tt_init_basic_cases[] = { |
32 | { |
33 | .description = "Page-aligned size" , |
34 | .size = SZ_4K, |
35 | }, |
36 | { |
37 | .description = "Extra pages requested" , |
38 | .size = SZ_4K, |
39 | .extra_pages_num = 1, |
40 | }, |
41 | }; |
42 | |
43 | static void ttm_tt_init_case_desc(const struct ttm_tt_test_case *t, |
44 | char *desc) |
45 | { |
46 | strscpy(desc, t->description, KUNIT_PARAM_DESC_SIZE); |
47 | } |
48 | |
49 | KUNIT_ARRAY_PARAM(ttm_tt_init_basic, ttm_tt_init_basic_cases, |
50 | ttm_tt_init_case_desc); |
51 | |
52 | static void ttm_tt_init_basic(struct kunit *test) |
53 | { |
54 | const struct ttm_tt_test_case *params = test->param_value; |
55 | struct ttm_buffer_object *bo; |
56 | struct ttm_tt *tt; |
57 | uint32_t page_flags = TTM_TT_FLAG_ZERO_ALLOC; |
58 | enum ttm_caching caching = ttm_cached; |
59 | uint32_t = params->extra_pages_num; |
60 | int num_pages = params->size >> PAGE_SHIFT; |
61 | int err; |
62 | |
63 | tt = kunit_kzalloc(test, size: sizeof(*tt), GFP_KERNEL); |
64 | KUNIT_ASSERT_NOT_NULL(test, tt); |
65 | |
66 | bo = ttm_bo_kunit_init(test, devs: test->priv, size: params->size); |
67 | |
68 | err = ttm_tt_init(ttm: tt, bo, page_flags, caching, extra_pages); |
69 | KUNIT_ASSERT_EQ(test, err, 0); |
70 | |
71 | KUNIT_ASSERT_EQ(test, tt->num_pages, num_pages + extra_pages); |
72 | |
73 | KUNIT_ASSERT_EQ(test, tt->page_flags, page_flags); |
74 | KUNIT_ASSERT_EQ(test, tt->caching, caching); |
75 | |
76 | KUNIT_ASSERT_NULL(test, tt->dma_address); |
77 | KUNIT_ASSERT_NULL(test, tt->swap_storage); |
78 | } |
79 | |
80 | static void ttm_tt_init_misaligned(struct kunit *test) |
81 | { |
82 | struct ttm_buffer_object *bo; |
83 | struct ttm_tt *tt; |
84 | enum ttm_caching caching = ttm_cached; |
85 | uint32_t size = SZ_8K; |
86 | int num_pages = (size + SZ_4K) >> PAGE_SHIFT; |
87 | int err; |
88 | |
89 | tt = kunit_kzalloc(test, size: sizeof(*tt), GFP_KERNEL); |
90 | KUNIT_ASSERT_NOT_NULL(test, tt); |
91 | |
92 | bo = ttm_bo_kunit_init(test, devs: test->priv, size); |
93 | |
94 | /* Make the object size misaligned */ |
95 | bo->base.size += 1; |
96 | |
97 | err = ttm_tt_init(ttm: tt, bo, page_flags: 0, caching, extra_pages: 0); |
98 | KUNIT_ASSERT_EQ(test, err, 0); |
99 | |
100 | KUNIT_ASSERT_EQ(test, tt->num_pages, num_pages); |
101 | } |
102 | |
103 | static void ttm_tt_fini_basic(struct kunit *test) |
104 | { |
105 | struct ttm_buffer_object *bo; |
106 | struct ttm_tt *tt; |
107 | enum ttm_caching caching = ttm_cached; |
108 | int err; |
109 | |
110 | tt = kunit_kzalloc(test, size: sizeof(*tt), GFP_KERNEL); |
111 | KUNIT_ASSERT_NOT_NULL(test, tt); |
112 | |
113 | bo = ttm_bo_kunit_init(test, devs: test->priv, BO_SIZE); |
114 | |
115 | err = ttm_tt_init(ttm: tt, bo, page_flags: 0, caching, extra_pages: 0); |
116 | KUNIT_ASSERT_EQ(test, err, 0); |
117 | KUNIT_ASSERT_NOT_NULL(test, tt->pages); |
118 | |
119 | ttm_tt_fini(ttm: tt); |
120 | KUNIT_ASSERT_NULL(test, tt->pages); |
121 | } |
122 | |
123 | static void ttm_tt_fini_sg(struct kunit *test) |
124 | { |
125 | struct ttm_buffer_object *bo; |
126 | struct ttm_tt *tt; |
127 | enum ttm_caching caching = ttm_cached; |
128 | int err; |
129 | |
130 | tt = kunit_kzalloc(test, size: sizeof(*tt), GFP_KERNEL); |
131 | KUNIT_ASSERT_NOT_NULL(test, tt); |
132 | |
133 | bo = ttm_bo_kunit_init(test, devs: test->priv, BO_SIZE); |
134 | |
135 | err = ttm_sg_tt_init(ttm_dma: tt, bo, page_flags: 0, caching); |
136 | KUNIT_ASSERT_EQ(test, err, 0); |
137 | KUNIT_ASSERT_NOT_NULL(test, tt->dma_address); |
138 | |
139 | ttm_tt_fini(ttm: tt); |
140 | KUNIT_ASSERT_NULL(test, tt->dma_address); |
141 | } |
142 | |
143 | static void ttm_tt_fini_shmem(struct kunit *test) |
144 | { |
145 | struct ttm_buffer_object *bo; |
146 | struct ttm_tt *tt; |
147 | struct file *shmem; |
148 | enum ttm_caching caching = ttm_cached; |
149 | int err; |
150 | |
151 | tt = kunit_kzalloc(test, size: sizeof(*tt), GFP_KERNEL); |
152 | KUNIT_ASSERT_NOT_NULL(test, tt); |
153 | |
154 | bo = ttm_bo_kunit_init(test, devs: test->priv, BO_SIZE); |
155 | |
156 | err = ttm_tt_init(ttm: tt, bo, page_flags: 0, caching, extra_pages: 0); |
157 | KUNIT_ASSERT_EQ(test, err, 0); |
158 | |
159 | shmem = shmem_file_setup(name: "ttm swap" , BO_SIZE, flags: 0); |
160 | tt->swap_storage = shmem; |
161 | |
162 | ttm_tt_fini(ttm: tt); |
163 | KUNIT_ASSERT_NULL(test, tt->swap_storage); |
164 | } |
165 | |
166 | static void ttm_tt_create_basic(struct kunit *test) |
167 | { |
168 | struct ttm_buffer_object *bo; |
169 | int err; |
170 | |
171 | bo = ttm_bo_kunit_init(test, devs: test->priv, BO_SIZE); |
172 | bo->type = ttm_bo_type_device; |
173 | |
174 | dma_resv_lock(obj: bo->base.resv, NULL); |
175 | err = ttm_tt_create(bo, zero_alloc: false); |
176 | dma_resv_unlock(obj: bo->base.resv); |
177 | |
178 | KUNIT_EXPECT_EQ(test, err, 0); |
179 | KUNIT_EXPECT_NOT_NULL(test, bo->ttm); |
180 | |
181 | /* Free manually, as it was allocated outside of KUnit */ |
182 | kfree(objp: bo->ttm); |
183 | } |
184 | |
185 | static void ttm_tt_create_invalid_bo_type(struct kunit *test) |
186 | { |
187 | struct ttm_buffer_object *bo; |
188 | int err; |
189 | |
190 | bo = ttm_bo_kunit_init(test, devs: test->priv, BO_SIZE); |
191 | bo->type = ttm_bo_type_sg + 1; |
192 | |
193 | dma_resv_lock(obj: bo->base.resv, NULL); |
194 | err = ttm_tt_create(bo, zero_alloc: false); |
195 | dma_resv_unlock(obj: bo->base.resv); |
196 | |
197 | KUNIT_EXPECT_EQ(test, err, -EINVAL); |
198 | KUNIT_EXPECT_NULL(test, bo->ttm); |
199 | } |
200 | |
201 | static void ttm_tt_create_ttm_exists(struct kunit *test) |
202 | { |
203 | struct ttm_buffer_object *bo; |
204 | struct ttm_tt *tt; |
205 | enum ttm_caching caching = ttm_cached; |
206 | int err; |
207 | |
208 | tt = kunit_kzalloc(test, size: sizeof(*tt), GFP_KERNEL); |
209 | KUNIT_ASSERT_NOT_NULL(test, tt); |
210 | |
211 | bo = ttm_bo_kunit_init(test, devs: test->priv, BO_SIZE); |
212 | |
213 | err = ttm_tt_init(ttm: tt, bo, page_flags: 0, caching, extra_pages: 0); |
214 | KUNIT_ASSERT_EQ(test, err, 0); |
215 | bo->ttm = tt; |
216 | |
217 | dma_resv_lock(obj: bo->base.resv, NULL); |
218 | err = ttm_tt_create(bo, zero_alloc: false); |
219 | dma_resv_unlock(obj: bo->base.resv); |
220 | |
221 | /* Expect to keep the previous TTM */ |
222 | KUNIT_ASSERT_EQ(test, err, 0); |
223 | KUNIT_ASSERT_PTR_EQ(test, tt, bo->ttm); |
224 | } |
225 | |
226 | static struct ttm_tt *ttm_tt_null_create(struct ttm_buffer_object *bo, |
227 | uint32_t page_flags) |
228 | { |
229 | return NULL; |
230 | } |
231 | |
232 | static struct ttm_device_funcs ttm_dev_empty_funcs = { |
233 | .ttm_tt_create = ttm_tt_null_create, |
234 | }; |
235 | |
236 | static void ttm_tt_create_failed(struct kunit *test) |
237 | { |
238 | const struct ttm_test_devices *devs = test->priv; |
239 | struct ttm_buffer_object *bo; |
240 | int err; |
241 | |
242 | bo = ttm_bo_kunit_init(test, devs: test->priv, BO_SIZE); |
243 | |
244 | /* Update ttm_device_funcs so we don't alloc ttm_tt */ |
245 | devs->ttm_dev->funcs = &ttm_dev_empty_funcs; |
246 | |
247 | dma_resv_lock(obj: bo->base.resv, NULL); |
248 | err = ttm_tt_create(bo, zero_alloc: false); |
249 | dma_resv_unlock(obj: bo->base.resv); |
250 | |
251 | KUNIT_ASSERT_EQ(test, err, -ENOMEM); |
252 | } |
253 | |
254 | static void ttm_tt_destroy_basic(struct kunit *test) |
255 | { |
256 | const struct ttm_test_devices *devs = test->priv; |
257 | struct ttm_buffer_object *bo; |
258 | int err; |
259 | |
260 | bo = ttm_bo_kunit_init(test, devs: test->priv, BO_SIZE); |
261 | |
262 | dma_resv_lock(obj: bo->base.resv, NULL); |
263 | err = ttm_tt_create(bo, zero_alloc: false); |
264 | dma_resv_unlock(obj: bo->base.resv); |
265 | |
266 | KUNIT_ASSERT_EQ(test, err, 0); |
267 | KUNIT_ASSERT_NOT_NULL(test, bo->ttm); |
268 | |
269 | ttm_tt_destroy(bdev: devs->ttm_dev, ttm: bo->ttm); |
270 | } |
271 | |
272 | static struct kunit_case ttm_tt_test_cases[] = { |
273 | KUNIT_CASE_PARAM(ttm_tt_init_basic, ttm_tt_init_basic_gen_params), |
274 | KUNIT_CASE(ttm_tt_init_misaligned), |
275 | KUNIT_CASE(ttm_tt_fini_basic), |
276 | KUNIT_CASE(ttm_tt_fini_sg), |
277 | KUNIT_CASE(ttm_tt_fini_shmem), |
278 | KUNIT_CASE(ttm_tt_create_basic), |
279 | KUNIT_CASE(ttm_tt_create_invalid_bo_type), |
280 | KUNIT_CASE(ttm_tt_create_ttm_exists), |
281 | KUNIT_CASE(ttm_tt_create_failed), |
282 | KUNIT_CASE(ttm_tt_destroy_basic), |
283 | {} |
284 | }; |
285 | |
286 | static struct kunit_suite ttm_tt_test_suite = { |
287 | .name = "ttm_tt" , |
288 | .init = ttm_tt_test_init, |
289 | .exit = ttm_test_devices_fini, |
290 | .test_cases = ttm_tt_test_cases, |
291 | }; |
292 | |
293 | kunit_test_suites(&ttm_tt_test_suite); |
294 | |
295 | MODULE_LICENSE("GPL" ); |
296 | |