1// SPDX-License-Identifier: GPL-2.0 AND MIT
2/*
3 * Copyright © 2023 Intel Corporation
4 */
5#include <linux/delay.h>
6#include <linux/kthread.h>
7
8#include <drm/ttm/ttm_resource.h>
9#include <drm/ttm/ttm_placement.h>
10#include <drm/ttm/ttm_tt.h>
11
12#include "ttm_kunit_helpers.h"
13#include "ttm_mock_manager.h"
14
15#define BO_SIZE SZ_4K
16#define MANAGER_SIZE SZ_1M
17
18static struct spinlock fence_lock;
19
20struct ttm_bo_validate_test_case {
21 const char *description;
22 enum ttm_bo_type bo_type;
23 u32 mem_type;
24 bool with_ttm;
25 bool no_gpu_wait;
26};
27
28static struct ttm_placement *ttm_placement_kunit_init(struct kunit *test,
29 struct ttm_place *places,
30 unsigned int num_places)
31{
32 struct ttm_placement *placement;
33
34 placement = kunit_kzalloc(test, size: sizeof(*placement), GFP_KERNEL);
35 KUNIT_ASSERT_NOT_NULL(test, placement);
36
37 placement->num_placement = num_places;
38 placement->placement = places;
39
40 return placement;
41}
42
43static const char *fence_name(struct dma_fence *f)
44{
45 return "ttm-bo-validate-fence";
46}
47
48static const struct dma_fence_ops fence_ops = {
49 .get_driver_name = fence_name,
50 .get_timeline_name = fence_name,
51};
52
53static struct dma_fence *alloc_mock_fence(struct kunit *test)
54{
55 struct dma_fence *fence;
56
57 fence = kunit_kzalloc(test, size: sizeof(*fence), GFP_KERNEL);
58 KUNIT_ASSERT_NOT_NULL(test, fence);
59
60 dma_fence_init(fence, ops: &fence_ops, lock: &fence_lock, context: 0, seqno: 0);
61
62 return fence;
63}
64
65static void dma_resv_kunit_active_fence_init(struct kunit *test,
66 struct dma_resv *resv,
67 enum dma_resv_usage usage)
68{
69 struct dma_fence *fence;
70
71 fence = alloc_mock_fence(test);
72 dma_fence_enable_sw_signaling(fence);
73
74 dma_resv_lock(obj: resv, NULL);
75 dma_resv_reserve_fences(obj: resv, num_fences: 1);
76 dma_resv_add_fence(obj: resv, fence, usage);
77 dma_resv_unlock(obj: resv);
78}
79
80static void ttm_bo_validate_case_desc(const struct ttm_bo_validate_test_case *t,
81 char *desc)
82{
83 strscpy(desc, t->description, KUNIT_PARAM_DESC_SIZE);
84}
85
86static const struct ttm_bo_validate_test_case ttm_bo_type_cases[] = {
87 {
88 .description = "Buffer object for userspace",
89 .bo_type = ttm_bo_type_device,
90 },
91 {
92 .description = "Kernel buffer object",
93 .bo_type = ttm_bo_type_kernel,
94 },
95 {
96 .description = "Shared buffer object",
97 .bo_type = ttm_bo_type_sg,
98 },
99};
100
101KUNIT_ARRAY_PARAM(ttm_bo_types, ttm_bo_type_cases,
102 ttm_bo_validate_case_desc);
103
104static void ttm_bo_init_reserved_sys_man(struct kunit *test)
105{
106 const struct ttm_bo_validate_test_case *params = test->param_value;
107 struct ttm_test_devices *priv = test->priv;
108 enum ttm_bo_type bo_type = params->bo_type;
109 u32 size = ALIGN(BO_SIZE, PAGE_SIZE);
110 struct ttm_operation_ctx ctx = { };
111 struct ttm_placement *placement;
112 struct ttm_buffer_object *bo;
113 struct ttm_place *place;
114 int err;
115
116 bo = kunit_kzalloc(test, size: sizeof(*bo), GFP_KERNEL);
117 KUNIT_ASSERT_NOT_NULL(test, bo);
118
119 place = ttm_place_kunit_init(test, TTM_PL_SYSTEM, flags: 0);
120 placement = ttm_placement_kunit_init(test, places: place, num_places: 1);
121
122 drm_gem_private_object_init(dev: priv->drm, obj: &bo->base, size);
123
124 err = ttm_bo_init_reserved(bdev: priv->ttm_dev, bo, type: bo_type, placement,
125 PAGE_SIZE, ctx: &ctx, NULL, NULL,
126 destroy: &dummy_ttm_bo_destroy);
127 dma_resv_unlock(obj: bo->base.resv);
128
129 KUNIT_EXPECT_EQ(test, err, 0);
130 KUNIT_EXPECT_EQ(test, kref_read(&bo->kref), 1);
131 KUNIT_EXPECT_PTR_EQ(test, bo->bdev, priv->ttm_dev);
132 KUNIT_EXPECT_EQ(test, bo->type, bo_type);
133 KUNIT_EXPECT_EQ(test, bo->page_alignment, PAGE_SIZE);
134 KUNIT_EXPECT_PTR_EQ(test, bo->destroy, &dummy_ttm_bo_destroy);
135 KUNIT_EXPECT_EQ(test, bo->pin_count, 0);
136 KUNIT_EXPECT_NULL(test, bo->bulk_move);
137 KUNIT_EXPECT_NOT_NULL(test, bo->ttm);
138 KUNIT_EXPECT_FALSE(test, ttm_tt_is_populated(bo->ttm));
139 KUNIT_EXPECT_NOT_NULL(test, (void *)bo->base.resv->fences);
140 KUNIT_EXPECT_EQ(test, ctx.bytes_moved, size);
141
142 if (bo_type != ttm_bo_type_kernel)
143 KUNIT_EXPECT_TRUE(test,
144 drm_mm_node_allocated(&bo->base.vma_node.vm_node));
145
146 ttm_resource_free(bo, res: &bo->resource);
147 ttm_bo_fini(bo);
148}
149
150static void ttm_bo_init_reserved_mock_man(struct kunit *test)
151{
152 const struct ttm_bo_validate_test_case *params = test->param_value;
153 enum ttm_bo_type bo_type = params->bo_type;
154 struct ttm_test_devices *priv = test->priv;
155 u32 size = ALIGN(BO_SIZE, PAGE_SIZE);
156 struct ttm_operation_ctx ctx = { };
157 struct ttm_placement *placement;
158 u32 mem_type = TTM_PL_VRAM;
159 struct ttm_buffer_object *bo;
160 struct ttm_place *place;
161 int err;
162
163 ttm_mock_manager_init(bdev: priv->ttm_dev, mem_type, MANAGER_SIZE);
164
165 bo = kunit_kzalloc(test, size: sizeof(*bo), GFP_KERNEL);
166 KUNIT_ASSERT_NOT_NULL(test, bo);
167
168 place = ttm_place_kunit_init(test, mem_type, flags: 0);
169 placement = ttm_placement_kunit_init(test, places: place, num_places: 1);
170
171 drm_gem_private_object_init(dev: priv->drm, obj: &bo->base, size);
172
173 err = ttm_bo_init_reserved(bdev: priv->ttm_dev, bo, type: bo_type, placement,
174 PAGE_SIZE, ctx: &ctx, NULL, NULL,
175 destroy: &dummy_ttm_bo_destroy);
176 dma_resv_unlock(obj: bo->base.resv);
177
178 KUNIT_EXPECT_EQ(test, err, 0);
179 KUNIT_EXPECT_EQ(test, kref_read(&bo->kref), 1);
180 KUNIT_EXPECT_PTR_EQ(test, bo->bdev, priv->ttm_dev);
181 KUNIT_EXPECT_EQ(test, bo->type, bo_type);
182 KUNIT_EXPECT_EQ(test, ctx.bytes_moved, size);
183
184 if (bo_type != ttm_bo_type_kernel)
185 KUNIT_EXPECT_TRUE(test,
186 drm_mm_node_allocated(&bo->base.vma_node.vm_node));
187
188 ttm_resource_free(bo, res: &bo->resource);
189 ttm_bo_fini(bo);
190 ttm_mock_manager_fini(bdev: priv->ttm_dev, mem_type);
191}
192
193static void ttm_bo_init_reserved_resv(struct kunit *test)
194{
195 enum ttm_bo_type bo_type = ttm_bo_type_device;
196 struct ttm_test_devices *priv = test->priv;
197 u32 size = ALIGN(BO_SIZE, PAGE_SIZE);
198 struct ttm_operation_ctx ctx = { };
199 struct ttm_placement *placement;
200 struct ttm_buffer_object *bo;
201 struct ttm_place *place;
202 struct dma_resv resv;
203 int err;
204
205 bo = kunit_kzalloc(test, size: sizeof(*bo), GFP_KERNEL);
206 KUNIT_ASSERT_NOT_NULL(test, bo);
207
208 place = ttm_place_kunit_init(test, TTM_PL_SYSTEM, flags: 0);
209 placement = ttm_placement_kunit_init(test, places: place, num_places: 1);
210
211 drm_gem_private_object_init(dev: priv->drm, obj: &bo->base, size);
212 dma_resv_init(obj: &resv);
213 dma_resv_lock(obj: &resv, NULL);
214
215 err = ttm_bo_init_reserved(bdev: priv->ttm_dev, bo, type: bo_type, placement,
216 PAGE_SIZE, ctx: &ctx, NULL, resv: &resv,
217 destroy: &dummy_ttm_bo_destroy);
218 dma_resv_unlock(obj: bo->base.resv);
219
220 KUNIT_EXPECT_EQ(test, err, 0);
221 KUNIT_EXPECT_PTR_EQ(test, bo->base.resv, &resv);
222
223 ttm_resource_free(bo, res: &bo->resource);
224 ttm_bo_fini(bo);
225}
226
227static void ttm_bo_validate_basic(struct kunit *test)
228{
229 const struct ttm_bo_validate_test_case *params = test->param_value;
230 u32 fst_mem = TTM_PL_SYSTEM, snd_mem = TTM_PL_VRAM;
231 struct ttm_operation_ctx ctx_init = { }, ctx_val = { };
232 struct ttm_placement *fst_placement, *snd_placement;
233 struct ttm_test_devices *priv = test->priv;
234 struct ttm_place *fst_place, *snd_place;
235 u32 size = ALIGN(SZ_8K, PAGE_SIZE);
236 struct ttm_buffer_object *bo;
237 int err;
238
239 ttm_mock_manager_init(bdev: priv->ttm_dev, mem_type: snd_mem, MANAGER_SIZE);
240
241 fst_place = ttm_place_kunit_init(test, mem_type: fst_mem, flags: 0);
242 fst_placement = ttm_placement_kunit_init(test, places: fst_place, num_places: 1);
243
244 bo = kunit_kzalloc(test, size: sizeof(*bo), GFP_KERNEL);
245 KUNIT_ASSERT_NOT_NULL(test, bo);
246
247 drm_gem_private_object_init(dev: priv->drm, obj: &bo->base, size);
248
249 err = ttm_bo_init_reserved(bdev: priv->ttm_dev, bo, type: params->bo_type,
250 placement: fst_placement, PAGE_SIZE, ctx: &ctx_init, NULL,
251 NULL, destroy: &dummy_ttm_bo_destroy);
252 KUNIT_EXPECT_EQ(test, err, 0);
253
254 snd_place = ttm_place_kunit_init(test, mem_type: snd_mem, DRM_BUDDY_TOPDOWN_ALLOCATION);
255 snd_placement = ttm_placement_kunit_init(test, places: snd_place, num_places: 1);
256
257 err = ttm_bo_validate(bo, placement: snd_placement, ctx: &ctx_val);
258 dma_resv_unlock(obj: bo->base.resv);
259
260 KUNIT_EXPECT_EQ(test, err, 0);
261 KUNIT_EXPECT_EQ(test, ctx_val.bytes_moved, bo->base.size);
262 KUNIT_EXPECT_NOT_NULL(test, bo->ttm);
263 KUNIT_EXPECT_TRUE(test, ttm_tt_is_populated(bo->ttm));
264 KUNIT_EXPECT_EQ(test, bo->resource->mem_type, snd_mem);
265 KUNIT_EXPECT_EQ(test, bo->resource->placement,
266 DRM_BUDDY_TOPDOWN_ALLOCATION);
267
268 ttm_bo_fini(bo);
269 ttm_mock_manager_fini(bdev: priv->ttm_dev, mem_type: snd_mem);
270}
271
272static void ttm_bo_validate_invalid_placement(struct kunit *test)
273{
274 enum ttm_bo_type bo_type = ttm_bo_type_device;
275 u32 unknown_mem_type = TTM_PL_PRIV + 1;
276 u32 size = ALIGN(BO_SIZE, PAGE_SIZE);
277 struct ttm_operation_ctx ctx = { };
278 struct ttm_placement *placement;
279 struct ttm_buffer_object *bo;
280 struct ttm_place *place;
281 int err;
282
283 place = ttm_place_kunit_init(test, mem_type: unknown_mem_type, flags: 0);
284 placement = ttm_placement_kunit_init(test, places: place, num_places: 1);
285
286 bo = ttm_bo_kunit_init(test, devs: test->priv, size, NULL);
287 bo->type = bo_type;
288
289 ttm_bo_reserve(bo, interruptible: false, no_wait: false, NULL);
290 err = ttm_bo_validate(bo, placement, ctx: &ctx);
291 dma_resv_unlock(obj: bo->base.resv);
292
293 KUNIT_EXPECT_EQ(test, err, -ENOMEM);
294
295 ttm_bo_fini(bo);
296}
297
298static void ttm_bo_validate_failed_alloc(struct kunit *test)
299{
300 enum ttm_bo_type bo_type = ttm_bo_type_device;
301 struct ttm_test_devices *priv = test->priv;
302 u32 size = ALIGN(BO_SIZE, PAGE_SIZE);
303 struct ttm_operation_ctx ctx = { };
304 struct ttm_placement *placement;
305 u32 mem_type = TTM_PL_VRAM;
306 struct ttm_buffer_object *bo;
307 struct ttm_place *place;
308 int err;
309
310 bo = ttm_bo_kunit_init(test, devs: test->priv, size, NULL);
311 bo->type = bo_type;
312
313 ttm_bad_manager_init(bdev: priv->ttm_dev, mem_type, MANAGER_SIZE);
314
315 place = ttm_place_kunit_init(test, mem_type, flags: 0);
316 placement = ttm_placement_kunit_init(test, places: place, num_places: 1);
317
318 ttm_bo_reserve(bo, interruptible: false, no_wait: false, NULL);
319 err = ttm_bo_validate(bo, placement, ctx: &ctx);
320 dma_resv_unlock(obj: bo->base.resv);
321
322 KUNIT_EXPECT_EQ(test, err, -ENOMEM);
323
324 ttm_bo_fini(bo);
325 ttm_bad_manager_fini(bdev: priv->ttm_dev, mem_type);
326}
327
328static void ttm_bo_validate_pinned(struct kunit *test)
329{
330 enum ttm_bo_type bo_type = ttm_bo_type_device;
331 u32 size = ALIGN(BO_SIZE, PAGE_SIZE);
332 struct ttm_operation_ctx ctx = { };
333 u32 mem_type = TTM_PL_SYSTEM;
334 struct ttm_placement *placement;
335 struct ttm_buffer_object *bo;
336 struct ttm_place *place;
337 int err;
338
339 place = ttm_place_kunit_init(test, mem_type, flags: 0);
340 placement = ttm_placement_kunit_init(test, places: place, num_places: 1);
341
342 bo = ttm_bo_kunit_init(test, devs: test->priv, size, NULL);
343 bo->type = bo_type;
344
345 ttm_bo_reserve(bo, interruptible: false, no_wait: false, NULL);
346 ttm_bo_pin(bo);
347 err = ttm_bo_validate(bo, placement, ctx: &ctx);
348 dma_resv_unlock(obj: bo->base.resv);
349
350 KUNIT_EXPECT_EQ(test, err, -EINVAL);
351
352 ttm_bo_reserve(bo, interruptible: false, no_wait: false, NULL);
353 ttm_bo_unpin(bo);
354 dma_resv_unlock(obj: bo->base.resv);
355
356 ttm_bo_fini(bo);
357}
358
359static const struct ttm_bo_validate_test_case ttm_mem_type_cases[] = {
360 {
361 .description = "System manager",
362 .mem_type = TTM_PL_SYSTEM,
363 },
364 {
365 .description = "VRAM manager",
366 .mem_type = TTM_PL_VRAM,
367 },
368};
369
370KUNIT_ARRAY_PARAM(ttm_bo_validate_mem, ttm_mem_type_cases,
371 ttm_bo_validate_case_desc);
372
373static void ttm_bo_validate_same_placement(struct kunit *test)
374{
375 const struct ttm_bo_validate_test_case *params = test->param_value;
376 struct ttm_operation_ctx ctx_init = { }, ctx_val = { };
377 struct ttm_test_devices *priv = test->priv;
378 u32 size = ALIGN(BO_SIZE, PAGE_SIZE);
379 struct ttm_placement *placement;
380 struct ttm_buffer_object *bo;
381 struct ttm_place *place;
382 int err;
383
384 place = ttm_place_kunit_init(test, mem_type: params->mem_type, flags: 0);
385 placement = ttm_placement_kunit_init(test, places: place, num_places: 1);
386
387 if (params->mem_type != TTM_PL_SYSTEM)
388 ttm_mock_manager_init(bdev: priv->ttm_dev, mem_type: params->mem_type, MANAGER_SIZE);
389
390 bo = kunit_kzalloc(test, size: sizeof(*bo), GFP_KERNEL);
391 KUNIT_ASSERT_NOT_NULL(test, bo);
392
393 drm_gem_private_object_init(dev: priv->drm, obj: &bo->base, size);
394
395 err = ttm_bo_init_reserved(bdev: priv->ttm_dev, bo, type: params->bo_type,
396 placement, PAGE_SIZE, ctx: &ctx_init, NULL,
397 NULL, destroy: &dummy_ttm_bo_destroy);
398 KUNIT_EXPECT_EQ(test, err, 0);
399
400 err = ttm_bo_validate(bo, placement, ctx: &ctx_val);
401 dma_resv_unlock(obj: bo->base.resv);
402
403 KUNIT_EXPECT_EQ(test, err, 0);
404 KUNIT_EXPECT_EQ(test, ctx_val.bytes_moved, 0);
405
406 ttm_bo_fini(bo);
407
408 if (params->mem_type != TTM_PL_SYSTEM)
409 ttm_mock_manager_fini(bdev: priv->ttm_dev, mem_type: params->mem_type);
410}
411
412static void ttm_bo_validate_busy_placement(struct kunit *test)
413{
414 u32 fst_mem = TTM_PL_VRAM, snd_mem = TTM_PL_VRAM + 1;
415 struct ttm_operation_ctx ctx_init = { }, ctx_val = { };
416 struct ttm_placement *placement_init, *placement_val;
417 enum ttm_bo_type bo_type = ttm_bo_type_device;
418 struct ttm_test_devices *priv = test->priv;
419 u32 size = ALIGN(BO_SIZE, PAGE_SIZE);
420 struct ttm_place *init_place, places[2];
421 struct ttm_resource_manager *man;
422 struct ttm_buffer_object *bo;
423 int err;
424
425 ttm_bad_manager_init(bdev: priv->ttm_dev, mem_type: fst_mem, MANAGER_SIZE);
426 ttm_mock_manager_init(bdev: priv->ttm_dev, mem_type: snd_mem, MANAGER_SIZE);
427
428 init_place = ttm_place_kunit_init(test, TTM_PL_SYSTEM, flags: 0);
429 placement_init = ttm_placement_kunit_init(test, places: init_place, num_places: 1);
430
431 bo = kunit_kzalloc(test, size: sizeof(*bo), GFP_KERNEL);
432 KUNIT_ASSERT_NOT_NULL(test, bo);
433
434 drm_gem_private_object_init(dev: priv->drm, obj: &bo->base, size);
435
436 err = ttm_bo_init_reserved(bdev: priv->ttm_dev, bo, type: bo_type, placement: placement_init,
437 PAGE_SIZE, ctx: &ctx_init, NULL, NULL,
438 destroy: &dummy_ttm_bo_destroy);
439 KUNIT_EXPECT_EQ(test, err, 0);
440
441 places[0] = (struct ttm_place){ .mem_type = fst_mem, .flags = TTM_PL_FLAG_DESIRED };
442 places[1] = (struct ttm_place){ .mem_type = snd_mem, .flags = TTM_PL_FLAG_FALLBACK };
443 placement_val = ttm_placement_kunit_init(test, places, num_places: 2);
444
445 err = ttm_bo_validate(bo, placement: placement_val, ctx: &ctx_val);
446 dma_resv_unlock(obj: bo->base.resv);
447
448 man = ttm_manager_type(bdev: priv->ttm_dev, mem_type: snd_mem);
449
450 KUNIT_EXPECT_EQ(test, err, 0);
451 KUNIT_EXPECT_EQ(test, ctx_val.bytes_moved, bo->base.size);
452 KUNIT_EXPECT_EQ(test, bo->resource->mem_type, snd_mem);
453 KUNIT_ASSERT_TRUE(test, list_is_singular(&man->lru[bo->priority]));
454
455 ttm_bo_fini(bo);
456 ttm_bad_manager_fini(bdev: priv->ttm_dev, mem_type: fst_mem);
457 ttm_mock_manager_fini(bdev: priv->ttm_dev, mem_type: snd_mem);
458}
459
460static void ttm_bo_validate_multihop(struct kunit *test)
461{
462 const struct ttm_bo_validate_test_case *params = test->param_value;
463 struct ttm_operation_ctx ctx_init = { }, ctx_val = { };
464 struct ttm_placement *placement_init, *placement_val;
465 u32 fst_mem = TTM_PL_VRAM, tmp_mem = TTM_PL_TT, final_mem = TTM_PL_SYSTEM;
466 struct ttm_test_devices *priv = test->priv;
467 struct ttm_place *fst_place, *final_place;
468 u32 size = ALIGN(BO_SIZE, PAGE_SIZE);
469 struct ttm_buffer_object *bo;
470 int err;
471
472 ttm_mock_manager_init(bdev: priv->ttm_dev, mem_type: fst_mem, MANAGER_SIZE);
473 ttm_mock_manager_init(bdev: priv->ttm_dev, mem_type: tmp_mem, MANAGER_SIZE);
474
475 fst_place = ttm_place_kunit_init(test, mem_type: fst_mem, flags: 0);
476 placement_init = ttm_placement_kunit_init(test, places: fst_place, num_places: 1);
477
478 bo = kunit_kzalloc(test, size: sizeof(*bo), GFP_KERNEL);
479 KUNIT_ASSERT_NOT_NULL(test, bo);
480
481 drm_gem_private_object_init(dev: priv->drm, obj: &bo->base, size);
482
483 err = ttm_bo_init_reserved(bdev: priv->ttm_dev, bo, type: params->bo_type,
484 placement: placement_init, PAGE_SIZE, ctx: &ctx_init, NULL,
485 NULL, destroy: &dummy_ttm_bo_destroy);
486 KUNIT_EXPECT_EQ(test, err, 0);
487
488 final_place = ttm_place_kunit_init(test, mem_type: final_mem, flags: 0);
489 placement_val = ttm_placement_kunit_init(test, places: final_place, num_places: 1);
490
491 err = ttm_bo_validate(bo, placement: placement_val, ctx: &ctx_val);
492 dma_resv_unlock(obj: bo->base.resv);
493
494 KUNIT_EXPECT_EQ(test, err, 0);
495 KUNIT_EXPECT_EQ(test, ctx_val.bytes_moved, size * 2);
496 KUNIT_EXPECT_EQ(test, bo->resource->mem_type, final_mem);
497
498 ttm_bo_fini(bo);
499
500 ttm_mock_manager_fini(bdev: priv->ttm_dev, mem_type: fst_mem);
501 ttm_mock_manager_fini(bdev: priv->ttm_dev, mem_type: tmp_mem);
502}
503
504static const struct ttm_bo_validate_test_case ttm_bo_no_placement_cases[] = {
505 {
506 .description = "Buffer object in system domain, no page vector",
507 },
508 {
509 .description = "Buffer object in system domain with an existing page vector",
510 .with_ttm = true,
511 },
512};
513
514KUNIT_ARRAY_PARAM(ttm_bo_no_placement, ttm_bo_no_placement_cases,
515 ttm_bo_validate_case_desc);
516
517static void ttm_bo_validate_no_placement_signaled(struct kunit *test)
518{
519 const struct ttm_bo_validate_test_case *params = test->param_value;
520 enum ttm_bo_type bo_type = ttm_bo_type_device;
521 struct ttm_test_devices *priv = test->priv;
522 u32 size = ALIGN(BO_SIZE, PAGE_SIZE);
523 struct ttm_operation_ctx ctx = { };
524 u32 mem_type = TTM_PL_SYSTEM;
525 struct ttm_resource_manager *man;
526 struct ttm_placement *placement;
527 struct ttm_buffer_object *bo;
528 struct ttm_place *place;
529 struct ttm_tt *old_tt;
530 u32 flags;
531 int err;
532
533 place = ttm_place_kunit_init(test, mem_type, flags: 0);
534 man = ttm_manager_type(bdev: priv->ttm_dev, mem_type);
535
536 bo = ttm_bo_kunit_init(test, devs: test->priv, size, NULL);
537 bo->type = bo_type;
538
539 if (params->with_ttm) {
540 old_tt = priv->ttm_dev->funcs->ttm_tt_create(bo, 0);
541 ttm_pool_alloc(pool: &priv->ttm_dev->pool, tt: old_tt, ctx: &ctx);
542 bo->ttm = old_tt;
543 }
544
545 placement = kunit_kzalloc(test, size: sizeof(*placement), GFP_KERNEL);
546 KUNIT_ASSERT_NOT_NULL(test, placement);
547
548 ttm_bo_reserve(bo, interruptible: false, no_wait: false, NULL);
549
550 err = ttm_resource_alloc(bo, place, res: &bo->resource, NULL);
551 KUNIT_EXPECT_EQ(test, err, 0);
552 KUNIT_ASSERT_EQ(test, man->usage, size);
553
554 err = ttm_bo_validate(bo, placement, ctx: &ctx);
555 ttm_bo_unreserve(bo);
556
557 KUNIT_EXPECT_EQ(test, err, 0);
558 KUNIT_ASSERT_EQ(test, man->usage, 0);
559 KUNIT_ASSERT_NOT_NULL(test, bo->ttm);
560 KUNIT_EXPECT_EQ(test, ctx.bytes_moved, 0);
561
562 if (params->with_ttm) {
563 flags = bo->ttm->page_flags;
564
565 KUNIT_ASSERT_PTR_EQ(test, bo->ttm, old_tt);
566 KUNIT_ASSERT_FALSE(test, flags & TTM_TT_FLAG_PRIV_POPULATED);
567 KUNIT_ASSERT_TRUE(test, flags & TTM_TT_FLAG_ZERO_ALLOC);
568 }
569
570 ttm_bo_fini(bo);
571}
572
573static int threaded_dma_resv_signal(void *arg)
574{
575 struct ttm_buffer_object *bo = arg;
576 struct dma_resv *resv = bo->base.resv;
577 struct dma_resv_iter cursor;
578 struct dma_fence *fence;
579
580 dma_resv_iter_begin(cursor: &cursor, obj: resv, usage: DMA_RESV_USAGE_BOOKKEEP);
581 dma_resv_for_each_fence_unlocked(&cursor, fence) {
582 dma_fence_signal(fence);
583 }
584 dma_resv_iter_end(cursor: &cursor);
585
586 return 0;
587}
588
589static void ttm_bo_validate_no_placement_not_signaled(struct kunit *test)
590{
591 const struct ttm_bo_validate_test_case *params = test->param_value;
592 enum dma_resv_usage usage = DMA_RESV_USAGE_BOOKKEEP;
593 u32 size = ALIGN(BO_SIZE, PAGE_SIZE);
594 struct ttm_operation_ctx ctx = { };
595 u32 mem_type = TTM_PL_SYSTEM;
596 struct ttm_placement *placement;
597 struct ttm_buffer_object *bo;
598 struct task_struct *task;
599 struct ttm_place *place;
600 int err;
601
602 place = ttm_place_kunit_init(test, mem_type, flags: 0);
603
604 bo = ttm_bo_kunit_init(test, devs: test->priv, size, NULL);
605 bo->type = params->bo_type;
606
607 err = ttm_resource_alloc(bo, place, res: &bo->resource, NULL);
608 KUNIT_EXPECT_EQ(test, err, 0);
609
610 placement = kunit_kzalloc(test, size: sizeof(*placement), GFP_KERNEL);
611 KUNIT_ASSERT_NOT_NULL(test, placement);
612
613 /* Create an active fence to simulate a non-idle resv object */
614 spin_lock_init(&fence_lock);
615 dma_resv_kunit_active_fence_init(test, resv: bo->base.resv, usage);
616
617 task = kthread_create(threaded_dma_resv_signal, bo, "dma-resv-signal");
618 if (IS_ERR(ptr: task))
619 KUNIT_FAIL(test, "Couldn't create dma resv signal task\n");
620
621 wake_up_process(tsk: task);
622 ttm_bo_reserve(bo, interruptible: false, no_wait: false, NULL);
623 err = ttm_bo_validate(bo, placement, ctx: &ctx);
624 ttm_bo_unreserve(bo);
625
626 KUNIT_EXPECT_EQ(test, err, 0);
627 KUNIT_ASSERT_NOT_NULL(test, bo->ttm);
628 KUNIT_ASSERT_NULL(test, bo->resource);
629 KUNIT_ASSERT_NULL(test, bo->bulk_move);
630 KUNIT_EXPECT_EQ(test, ctx.bytes_moved, 0);
631
632 if (bo->type != ttm_bo_type_sg)
633 KUNIT_ASSERT_PTR_EQ(test, bo->base.resv, &bo->base._resv);
634
635 /* Make sure we have an idle object at this point */
636 dma_resv_wait_timeout(obj: bo->base.resv, usage, intr: false, MAX_SCHEDULE_TIMEOUT);
637
638 ttm_bo_fini(bo);
639}
640
641static void ttm_bo_validate_move_fence_signaled(struct kunit *test)
642{
643 enum ttm_bo_type bo_type = ttm_bo_type_device;
644 struct ttm_test_devices *priv = test->priv;
645 u32 size = ALIGN(BO_SIZE, PAGE_SIZE);
646 struct ttm_operation_ctx ctx = { };
647 u32 mem_type = TTM_PL_SYSTEM;
648 struct ttm_resource_manager *man;
649 struct ttm_placement *placement;
650 struct ttm_buffer_object *bo;
651 struct ttm_place *place;
652 int err;
653
654 man = ttm_manager_type(bdev: priv->ttm_dev, mem_type);
655 man->eviction_fences[0] = dma_fence_get_stub();
656
657 bo = ttm_bo_kunit_init(test, devs: test->priv, size, NULL);
658 bo->type = bo_type;
659
660 place = ttm_place_kunit_init(test, mem_type, flags: 0);
661 placement = ttm_placement_kunit_init(test, places: place, num_places: 1);
662
663 ttm_bo_reserve(bo, interruptible: false, no_wait: false, NULL);
664 err = ttm_bo_validate(bo, placement, ctx: &ctx);
665 ttm_bo_unreserve(bo);
666
667 KUNIT_EXPECT_EQ(test, err, 0);
668 KUNIT_EXPECT_EQ(test, bo->resource->mem_type, mem_type);
669 KUNIT_EXPECT_EQ(test, ctx.bytes_moved, size);
670
671 ttm_bo_fini(bo);
672 dma_fence_put(fence: man->eviction_fences[0]);
673}
674
675static const struct ttm_bo_validate_test_case ttm_bo_validate_wait_cases[] = {
676 {
677 .description = "Waits for GPU",
678 .no_gpu_wait = false,
679 },
680 {
681 .description = "Tries to lock straight away",
682 .no_gpu_wait = true,
683 },
684};
685
686KUNIT_ARRAY_PARAM(ttm_bo_validate_wait, ttm_bo_validate_wait_cases,
687 ttm_bo_validate_case_desc);
688
689static int threaded_fence_signal(void *arg)
690{
691 struct dma_fence *fence = arg;
692
693 msleep(msecs: 20);
694
695 return dma_fence_signal(fence);
696}
697
698static void ttm_bo_validate_move_fence_not_signaled(struct kunit *test)
699{
700 const struct ttm_bo_validate_test_case *params = test->param_value;
701 struct ttm_operation_ctx ctx_init = { },
702 ctx_val = { .no_wait_gpu = params->no_gpu_wait };
703 u32 fst_mem = TTM_PL_VRAM, snd_mem = TTM_PL_VRAM + 1;
704 struct ttm_placement *placement_init, *placement_val;
705 enum ttm_bo_type bo_type = ttm_bo_type_device;
706 struct ttm_test_devices *priv = test->priv;
707 u32 size = ALIGN(BO_SIZE, PAGE_SIZE);
708 struct ttm_place *init_place, places[2];
709 struct ttm_resource_manager *man;
710 struct ttm_buffer_object *bo;
711 struct task_struct *task;
712 int err;
713
714 init_place = ttm_place_kunit_init(test, TTM_PL_SYSTEM, flags: 0);
715 placement_init = ttm_placement_kunit_init(test, places: init_place, num_places: 1);
716
717 bo = kunit_kzalloc(test, size: sizeof(*bo), GFP_KERNEL);
718 KUNIT_ASSERT_NOT_NULL(test, bo);
719
720 drm_gem_private_object_init(dev: priv->drm, obj: &bo->base, size);
721
722 err = ttm_bo_init_reserved(bdev: priv->ttm_dev, bo, type: bo_type, placement: placement_init,
723 PAGE_SIZE, ctx: &ctx_init, NULL, NULL,
724 destroy: &dummy_ttm_bo_destroy);
725 KUNIT_EXPECT_EQ(test, err, 0);
726
727 ttm_mock_manager_init(bdev: priv->ttm_dev, mem_type: fst_mem, MANAGER_SIZE);
728 ttm_mock_manager_init(bdev: priv->ttm_dev, mem_type: snd_mem, MANAGER_SIZE);
729
730 places[0] = (struct ttm_place){ .mem_type = fst_mem, .flags = TTM_PL_FLAG_DESIRED };
731 places[1] = (struct ttm_place){ .mem_type = snd_mem, .flags = TTM_PL_FLAG_FALLBACK };
732 placement_val = ttm_placement_kunit_init(test, places, num_places: 2);
733
734 spin_lock_init(&fence_lock);
735 man = ttm_manager_type(bdev: priv->ttm_dev, mem_type: fst_mem);
736 man->eviction_fences[0] = alloc_mock_fence(test);
737
738 task = kthread_create(threaded_fence_signal, man->eviction_fences[0], "move-fence-signal");
739 if (IS_ERR(ptr: task))
740 KUNIT_FAIL(test, "Couldn't create move fence signal task\n");
741
742 wake_up_process(tsk: task);
743 err = ttm_bo_validate(bo, placement: placement_val, ctx: &ctx_val);
744 dma_resv_unlock(obj: bo->base.resv);
745
746 dma_fence_wait_timeout(man->eviction_fences[0], intr: false, MAX_SCHEDULE_TIMEOUT);
747 man->eviction_fences[0] = NULL;
748
749 KUNIT_EXPECT_EQ(test, err, 0);
750 KUNIT_EXPECT_EQ(test, ctx_val.bytes_moved, size);
751
752 if (params->no_gpu_wait)
753 KUNIT_EXPECT_EQ(test, bo->resource->mem_type, snd_mem);
754 else
755 KUNIT_EXPECT_EQ(test, bo->resource->mem_type, fst_mem);
756
757 ttm_bo_fini(bo);
758 ttm_mock_manager_fini(bdev: priv->ttm_dev, mem_type: fst_mem);
759 ttm_mock_manager_fini(bdev: priv->ttm_dev, mem_type: snd_mem);
760}
761
762static void ttm_bo_validate_happy_evict(struct kunit *test)
763{
764 u32 mem_type = TTM_PL_VRAM, mem_multihop = TTM_PL_TT,
765 mem_type_evict = TTM_PL_SYSTEM;
766 struct ttm_operation_ctx ctx_init = { }, ctx_val = { };
767 enum ttm_bo_type bo_type = ttm_bo_type_device;
768 u32 small = SZ_8K, medium = SZ_512K,
769 big = MANAGER_SIZE - (small + medium);
770 u32 bo_sizes[] = { small, medium, big };
771 struct ttm_test_devices *priv = test->priv;
772 struct ttm_buffer_object *bos, *bo_val;
773 struct ttm_placement *placement;
774 struct ttm_place *place;
775 u32 bo_no = 3;
776 int i, err;
777
778 ttm_mock_manager_init(bdev: priv->ttm_dev, mem_type, MANAGER_SIZE);
779 ttm_mock_manager_init(bdev: priv->ttm_dev, mem_type: mem_multihop, MANAGER_SIZE);
780
781 place = ttm_place_kunit_init(test, mem_type, flags: 0);
782 placement = ttm_placement_kunit_init(test, places: place, num_places: 1);
783
784 bos = kunit_kmalloc_array(test, n: bo_no, size: sizeof(*bos), GFP_KERNEL);
785 KUNIT_ASSERT_NOT_NULL(test, bos);
786
787 memset(bos, 0, sizeof(*bos) * bo_no);
788 for (i = 0; i < bo_no; i++) {
789 drm_gem_private_object_init(dev: priv->drm, obj: &bos[i].base, size: bo_sizes[i]);
790 err = ttm_bo_init_reserved(bdev: priv->ttm_dev, bo: &bos[i], type: bo_type, placement,
791 PAGE_SIZE, ctx: &ctx_init, NULL, NULL,
792 destroy: &dummy_ttm_bo_destroy);
793 dma_resv_unlock(obj: bos[i].base.resv);
794 }
795
796 bo_val = ttm_bo_kunit_init(test, devs: test->priv, BO_SIZE, NULL);
797 bo_val->type = bo_type;
798
799 ttm_bo_reserve(bo: bo_val, interruptible: false, no_wait: false, NULL);
800 err = ttm_bo_validate(bo: bo_val, placement, ctx: &ctx_val);
801 ttm_bo_unreserve(bo: bo_val);
802
803 KUNIT_EXPECT_EQ(test, err, 0);
804 KUNIT_EXPECT_EQ(test, bos[0].resource->mem_type, mem_type_evict);
805 KUNIT_EXPECT_TRUE(test, bos[0].ttm->page_flags & TTM_TT_FLAG_ZERO_ALLOC);
806 KUNIT_EXPECT_TRUE(test, bos[0].ttm->page_flags & TTM_TT_FLAG_PRIV_POPULATED);
807 KUNIT_EXPECT_EQ(test, ctx_val.bytes_moved, small * 2 + BO_SIZE);
808 KUNIT_EXPECT_EQ(test, bos[1].resource->mem_type, mem_type);
809
810 for (i = 0; i < bo_no; i++)
811 ttm_bo_fini(bo: &bos[i]);
812 ttm_bo_fini(bo: bo_val);
813
814 ttm_mock_manager_fini(bdev: priv->ttm_dev, mem_type);
815 ttm_mock_manager_fini(bdev: priv->ttm_dev, mem_type: mem_multihop);
816}
817
818static void ttm_bo_validate_all_pinned_evict(struct kunit *test)
819{
820 struct ttm_operation_ctx ctx_init = { }, ctx_val = { };
821 enum ttm_bo_type bo_type = ttm_bo_type_device;
822 struct ttm_buffer_object *bo_big, *bo_small;
823 struct ttm_test_devices *priv = test->priv;
824 struct ttm_placement *placement;
825 u32 mem_type = TTM_PL_VRAM, mem_multihop = TTM_PL_TT;
826 struct ttm_place *place;
827 int err;
828
829 ttm_mock_manager_init(bdev: priv->ttm_dev, mem_type, MANAGER_SIZE);
830 ttm_mock_manager_init(bdev: priv->ttm_dev, mem_type: mem_multihop, MANAGER_SIZE);
831
832 place = ttm_place_kunit_init(test, mem_type, flags: 0);
833 placement = ttm_placement_kunit_init(test, places: place, num_places: 1);
834
835 bo_big = kunit_kzalloc(test, size: sizeof(*bo_big), GFP_KERNEL);
836 KUNIT_ASSERT_NOT_NULL(test, bo_big);
837
838 drm_gem_private_object_init(dev: priv->drm, obj: &bo_big->base, MANAGER_SIZE);
839 err = ttm_bo_init_reserved(bdev: priv->ttm_dev, bo: bo_big, type: bo_type, placement,
840 PAGE_SIZE, ctx: &ctx_init, NULL, NULL,
841 destroy: &dummy_ttm_bo_destroy);
842 KUNIT_EXPECT_EQ(test, err, 0);
843
844 ttm_bo_pin(bo: bo_big);
845 dma_resv_unlock(obj: bo_big->base.resv);
846
847 bo_small = ttm_bo_kunit_init(test, devs: test->priv, BO_SIZE, NULL);
848 bo_small->type = bo_type;
849
850 ttm_bo_reserve(bo: bo_small, interruptible: false, no_wait: false, NULL);
851 err = ttm_bo_validate(bo: bo_small, placement, ctx: &ctx_val);
852 ttm_bo_unreserve(bo: bo_small);
853
854 KUNIT_EXPECT_EQ(test, err, -ENOMEM);
855
856 ttm_bo_fini(bo: bo_small);
857
858 ttm_bo_reserve(bo: bo_big, interruptible: false, no_wait: false, NULL);
859 ttm_bo_unpin(bo: bo_big);
860 dma_resv_unlock(obj: bo_big->base.resv);
861 ttm_bo_fini(bo: bo_big);
862
863 ttm_mock_manager_fini(bdev: priv->ttm_dev, mem_type);
864 ttm_mock_manager_fini(bdev: priv->ttm_dev, mem_type: mem_multihop);
865}
866
867static void ttm_bo_validate_allowed_only_evict(struct kunit *test)
868{
869 u32 mem_type = TTM_PL_VRAM, mem_multihop = TTM_PL_TT,
870 mem_type_evict = TTM_PL_SYSTEM;
871 struct ttm_buffer_object *bo, *bo_evictable, *bo_pinned;
872 struct ttm_operation_ctx ctx_init = { }, ctx_val = { };
873 enum ttm_bo_type bo_type = ttm_bo_type_device;
874 struct ttm_test_devices *priv = test->priv;
875 struct ttm_placement *placement;
876 struct ttm_place *place;
877 u32 size = SZ_512K;
878 int err;
879
880 ttm_mock_manager_init(bdev: priv->ttm_dev, mem_type, MANAGER_SIZE);
881 ttm_mock_manager_init(bdev: priv->ttm_dev, mem_type: mem_multihop, MANAGER_SIZE);
882
883 place = ttm_place_kunit_init(test, mem_type, flags: 0);
884 placement = ttm_placement_kunit_init(test, places: place, num_places: 1);
885
886 bo_pinned = kunit_kzalloc(test, size: sizeof(*bo_pinned), GFP_KERNEL);
887 KUNIT_ASSERT_NOT_NULL(test, bo_pinned);
888
889 drm_gem_private_object_init(dev: priv->drm, obj: &bo_pinned->base, size);
890 err = ttm_bo_init_reserved(bdev: priv->ttm_dev, bo: bo_pinned, type: bo_type, placement,
891 PAGE_SIZE, ctx: &ctx_init, NULL, NULL,
892 destroy: &dummy_ttm_bo_destroy);
893 KUNIT_EXPECT_EQ(test, err, 0);
894 ttm_bo_pin(bo: bo_pinned);
895 dma_resv_unlock(obj: bo_pinned->base.resv);
896
897 bo_evictable = kunit_kzalloc(test, size: sizeof(*bo_evictable), GFP_KERNEL);
898 KUNIT_ASSERT_NOT_NULL(test, bo_evictable);
899
900 drm_gem_private_object_init(dev: priv->drm, obj: &bo_evictable->base, size);
901 err = ttm_bo_init_reserved(bdev: priv->ttm_dev, bo: bo_evictable, type: bo_type, placement,
902 PAGE_SIZE, ctx: &ctx_init, NULL, NULL,
903 destroy: &dummy_ttm_bo_destroy);
904 KUNIT_EXPECT_EQ(test, err, 0);
905 dma_resv_unlock(obj: bo_evictable->base.resv);
906
907 bo = ttm_bo_kunit_init(test, devs: test->priv, BO_SIZE, NULL);
908 bo->type = bo_type;
909
910 ttm_bo_reserve(bo, interruptible: false, no_wait: false, NULL);
911 err = ttm_bo_validate(bo, placement, ctx: &ctx_val);
912 ttm_bo_unreserve(bo);
913
914 KUNIT_EXPECT_EQ(test, err, 0);
915 KUNIT_EXPECT_EQ(test, bo->resource->mem_type, mem_type);
916 KUNIT_EXPECT_EQ(test, bo_pinned->resource->mem_type, mem_type);
917 KUNIT_EXPECT_EQ(test, bo_evictable->resource->mem_type, mem_type_evict);
918 KUNIT_EXPECT_EQ(test, ctx_val.bytes_moved, size * 2 + BO_SIZE);
919
920 ttm_bo_fini(bo);
921 ttm_bo_fini(bo: bo_evictable);
922
923 ttm_bo_reserve(bo: bo_pinned, interruptible: false, no_wait: false, NULL);
924 ttm_bo_unpin(bo: bo_pinned);
925 dma_resv_unlock(obj: bo_pinned->base.resv);
926 ttm_bo_fini(bo: bo_pinned);
927
928 ttm_mock_manager_fini(bdev: priv->ttm_dev, mem_type);
929 ttm_mock_manager_fini(bdev: priv->ttm_dev, mem_type: mem_multihop);
930}
931
932static void ttm_bo_validate_deleted_evict(struct kunit *test)
933{
934 struct ttm_operation_ctx ctx_init = { }, ctx_val = { };
935 u32 small = SZ_8K, big = MANAGER_SIZE - BO_SIZE;
936 enum ttm_bo_type bo_type = ttm_bo_type_device;
937 struct ttm_buffer_object *bo_big, *bo_small;
938 struct ttm_test_devices *priv = test->priv;
939 struct ttm_resource_manager *man;
940 u32 mem_type = TTM_PL_VRAM;
941 struct ttm_placement *placement;
942 struct ttm_place *place;
943 int err;
944
945 ttm_mock_manager_init(bdev: priv->ttm_dev, mem_type, MANAGER_SIZE);
946 man = ttm_manager_type(bdev: priv->ttm_dev, mem_type);
947
948 place = ttm_place_kunit_init(test, mem_type, flags: 0);
949 placement = ttm_placement_kunit_init(test, places: place, num_places: 1);
950
951 bo_big = kunit_kzalloc(test, size: sizeof(*bo_big), GFP_KERNEL);
952 KUNIT_ASSERT_NOT_NULL(test, bo_big);
953
954 drm_gem_private_object_init(dev: priv->drm, obj: &bo_big->base, size: big);
955 err = ttm_bo_init_reserved(bdev: priv->ttm_dev, bo: bo_big, type: bo_type, placement,
956 PAGE_SIZE, ctx: &ctx_init, NULL, NULL,
957 destroy: &dummy_ttm_bo_destroy);
958 KUNIT_EXPECT_EQ(test, err, 0);
959 KUNIT_EXPECT_EQ(test, ttm_resource_manager_usage(man), big);
960
961 dma_resv_unlock(obj: bo_big->base.resv);
962 bo_big->deleted = true;
963
964 bo_small = ttm_bo_kunit_init(test, devs: test->priv, size: small, NULL);
965 bo_small->type = bo_type;
966
967 ttm_bo_reserve(bo: bo_small, interruptible: false, no_wait: false, NULL);
968 err = ttm_bo_validate(bo: bo_small, placement, ctx: &ctx_val);
969 ttm_bo_unreserve(bo: bo_small);
970
971 KUNIT_EXPECT_EQ(test, err, 0);
972 KUNIT_EXPECT_EQ(test, bo_small->resource->mem_type, mem_type);
973 KUNIT_EXPECT_EQ(test, ttm_resource_manager_usage(man), small);
974 KUNIT_EXPECT_NULL(test, bo_big->ttm);
975 KUNIT_EXPECT_NULL(test, bo_big->resource);
976
977 ttm_bo_fini(bo: bo_small);
978 ttm_bo_fini(bo: bo_big);
979 ttm_mock_manager_fini(bdev: priv->ttm_dev, mem_type);
980}
981
982static void ttm_bo_validate_busy_domain_evict(struct kunit *test)
983{
984 u32 mem_type = TTM_PL_VRAM, mem_type_evict = TTM_PL_MOCK1;
985 struct ttm_operation_ctx ctx_init = { }, ctx_val = { };
986 enum ttm_bo_type bo_type = ttm_bo_type_device;
987 struct ttm_test_devices *priv = test->priv;
988 struct ttm_buffer_object *bo_init, *bo_val;
989 struct ttm_placement *placement;
990 struct ttm_place *place;
991 int err;
992
993 /*
994 * Drop the default device and setup a new one that points to busy
995 * thus unsuitable eviction domain
996 */
997 ttm_device_fini(bdev: priv->ttm_dev);
998
999 err = ttm_device_kunit_init_bad_evict(priv: test->priv, ttm: priv->ttm_dev);
1000 KUNIT_ASSERT_EQ(test, err, 0);
1001
1002 ttm_mock_manager_init(bdev: priv->ttm_dev, mem_type, MANAGER_SIZE);
1003 ttm_busy_manager_init(bdev: priv->ttm_dev, mem_type: mem_type_evict, MANAGER_SIZE);
1004
1005 place = ttm_place_kunit_init(test, mem_type, flags: 0);
1006 placement = ttm_placement_kunit_init(test, places: place, num_places: 1);
1007
1008 bo_init = kunit_kzalloc(test, size: sizeof(*bo_init), GFP_KERNEL);
1009 KUNIT_ASSERT_NOT_NULL(test, bo_init);
1010
1011 drm_gem_private_object_init(dev: priv->drm, obj: &bo_init->base, MANAGER_SIZE);
1012 err = ttm_bo_init_reserved(bdev: priv->ttm_dev, bo: bo_init, type: bo_type, placement,
1013 PAGE_SIZE, ctx: &ctx_init, NULL, NULL,
1014 destroy: &dummy_ttm_bo_destroy);
1015 KUNIT_EXPECT_EQ(test, err, 0);
1016 dma_resv_unlock(obj: bo_init->base.resv);
1017
1018 bo_val = ttm_bo_kunit_init(test, devs: test->priv, BO_SIZE, NULL);
1019 bo_val->type = bo_type;
1020
1021 ttm_bo_reserve(bo: bo_val, interruptible: false, no_wait: false, NULL);
1022 err = ttm_bo_validate(bo: bo_val, placement, ctx: &ctx_val);
1023 ttm_bo_unreserve(bo: bo_val);
1024
1025 KUNIT_EXPECT_EQ(test, err, -ENOMEM);
1026 KUNIT_EXPECT_EQ(test, bo_init->resource->mem_type, mem_type);
1027 KUNIT_EXPECT_NULL(test, bo_val->resource);
1028
1029 ttm_bo_fini(bo: bo_init);
1030 ttm_bo_fini(bo: bo_val);
1031
1032 ttm_mock_manager_fini(bdev: priv->ttm_dev, mem_type);
1033 ttm_bad_manager_fini(bdev: priv->ttm_dev, mem_type: mem_type_evict);
1034}
1035
1036static void ttm_bo_validate_evict_gutting(struct kunit *test)
1037{
1038 struct ttm_operation_ctx ctx_init = { }, ctx_val = { };
1039 enum ttm_bo_type bo_type = ttm_bo_type_device;
1040 struct ttm_test_devices *priv = test->priv;
1041 struct ttm_buffer_object *bo, *bo_evict;
1042 u32 mem_type = TTM_PL_MOCK1;
1043 struct ttm_placement *placement;
1044 struct ttm_place *place;
1045 int err;
1046
1047 ttm_mock_manager_init(bdev: priv->ttm_dev, mem_type, MANAGER_SIZE);
1048
1049 place = ttm_place_kunit_init(test, mem_type, flags: 0);
1050 placement = ttm_placement_kunit_init(test, places: place, num_places: 1);
1051
1052 bo_evict = kunit_kzalloc(test, size: sizeof(*bo_evict), GFP_KERNEL);
1053 KUNIT_ASSERT_NOT_NULL(test, bo_evict);
1054
1055 drm_gem_private_object_init(dev: priv->drm, obj: &bo_evict->base, MANAGER_SIZE);
1056 err = ttm_bo_init_reserved(bdev: priv->ttm_dev, bo: bo_evict, type: bo_type, placement,
1057 PAGE_SIZE, ctx: &ctx_init, NULL, NULL,
1058 destroy: &dummy_ttm_bo_destroy);
1059 KUNIT_EXPECT_EQ(test, err, 0);
1060 dma_resv_unlock(obj: bo_evict->base.resv);
1061
1062 bo = ttm_bo_kunit_init(test, devs: test->priv, BO_SIZE, NULL);
1063 bo->type = bo_type;
1064
1065 ttm_bo_reserve(bo, interruptible: false, no_wait: false, NULL);
1066 err = ttm_bo_validate(bo, placement, ctx: &ctx_val);
1067 ttm_bo_unreserve(bo);
1068
1069 KUNIT_EXPECT_EQ(test, err, 0);
1070 KUNIT_EXPECT_EQ(test, bo->resource->mem_type, mem_type);
1071 KUNIT_ASSERT_NULL(test, bo_evict->resource);
1072 KUNIT_ASSERT_TRUE(test, bo_evict->ttm->page_flags & TTM_TT_FLAG_ZERO_ALLOC);
1073
1074 ttm_bo_fini(bo: bo_evict);
1075 ttm_bo_fini(bo);
1076
1077 ttm_mock_manager_fini(bdev: priv->ttm_dev, mem_type);
1078}
1079
1080static void ttm_bo_validate_recrusive_evict(struct kunit *test)
1081{
1082 u32 mem_type = TTM_PL_TT, mem_type_evict = TTM_PL_MOCK2;
1083 struct ttm_operation_ctx ctx_init = { }, ctx_val = { };
1084 struct ttm_placement *placement_tt, *placement_mock;
1085 struct ttm_buffer_object *bo_tt, *bo_mock, *bo_val;
1086 enum ttm_bo_type bo_type = ttm_bo_type_device;
1087 struct ttm_test_devices *priv = test->priv;
1088 struct ttm_place *place_tt, *place_mock;
1089 int err;
1090
1091 ttm_mock_manager_init(bdev: priv->ttm_dev, mem_type, MANAGER_SIZE);
1092 ttm_mock_manager_init(bdev: priv->ttm_dev, mem_type: mem_type_evict, MANAGER_SIZE);
1093
1094 place_tt = ttm_place_kunit_init(test, mem_type, flags: 0);
1095 place_mock = ttm_place_kunit_init(test, mem_type: mem_type_evict, flags: 0);
1096
1097 placement_tt = ttm_placement_kunit_init(test, places: place_tt, num_places: 1);
1098 placement_mock = ttm_placement_kunit_init(test, places: place_mock, num_places: 1);
1099
1100 bo_tt = kunit_kzalloc(test, size: sizeof(*bo_tt), GFP_KERNEL);
1101 KUNIT_ASSERT_NOT_NULL(test, bo_tt);
1102
1103 bo_mock = kunit_kzalloc(test, size: sizeof(*bo_mock), GFP_KERNEL);
1104 KUNIT_ASSERT_NOT_NULL(test, bo_mock);
1105
1106 drm_gem_private_object_init(dev: priv->drm, obj: &bo_tt->base, MANAGER_SIZE);
1107 err = ttm_bo_init_reserved(bdev: priv->ttm_dev, bo: bo_tt, type: bo_type, placement: placement_tt,
1108 PAGE_SIZE, ctx: &ctx_init, NULL, NULL,
1109 destroy: &dummy_ttm_bo_destroy);
1110 KUNIT_EXPECT_EQ(test, err, 0);
1111 dma_resv_unlock(obj: bo_tt->base.resv);
1112
1113 drm_gem_private_object_init(dev: priv->drm, obj: &bo_mock->base, MANAGER_SIZE);
1114 err = ttm_bo_init_reserved(bdev: priv->ttm_dev, bo: bo_mock, type: bo_type, placement: placement_mock,
1115 PAGE_SIZE, ctx: &ctx_init, NULL, NULL,
1116 destroy: &dummy_ttm_bo_destroy);
1117 KUNIT_EXPECT_EQ(test, err, 0);
1118 dma_resv_unlock(obj: bo_mock->base.resv);
1119
1120 bo_val = ttm_bo_kunit_init(test, devs: test->priv, BO_SIZE, NULL);
1121 bo_val->type = bo_type;
1122
1123 ttm_bo_reserve(bo: bo_val, interruptible: false, no_wait: false, NULL);
1124 err = ttm_bo_validate(bo: bo_val, placement: placement_tt, ctx: &ctx_val);
1125 ttm_bo_unreserve(bo: bo_val);
1126
1127 KUNIT_EXPECT_EQ(test, err, 0);
1128
1129 ttm_mock_manager_fini(bdev: priv->ttm_dev, mem_type);
1130 ttm_mock_manager_fini(bdev: priv->ttm_dev, mem_type: mem_type_evict);
1131
1132 ttm_bo_fini(bo: bo_val);
1133 ttm_bo_fini(bo: bo_tt);
1134 ttm_bo_fini(bo: bo_mock);
1135}
1136
1137static struct kunit_case ttm_bo_validate_test_cases[] = {
1138 KUNIT_CASE_PARAM(ttm_bo_init_reserved_sys_man, ttm_bo_types_gen_params),
1139 KUNIT_CASE_PARAM(ttm_bo_init_reserved_mock_man, ttm_bo_types_gen_params),
1140 KUNIT_CASE(ttm_bo_init_reserved_resv),
1141 KUNIT_CASE_PARAM(ttm_bo_validate_basic, ttm_bo_types_gen_params),
1142 KUNIT_CASE(ttm_bo_validate_invalid_placement),
1143 KUNIT_CASE_PARAM(ttm_bo_validate_same_placement,
1144 ttm_bo_validate_mem_gen_params),
1145 KUNIT_CASE(ttm_bo_validate_failed_alloc),
1146 KUNIT_CASE(ttm_bo_validate_pinned),
1147 KUNIT_CASE(ttm_bo_validate_busy_placement),
1148 KUNIT_CASE_PARAM(ttm_bo_validate_multihop, ttm_bo_types_gen_params),
1149 KUNIT_CASE_PARAM(ttm_bo_validate_no_placement_signaled,
1150 ttm_bo_no_placement_gen_params),
1151 KUNIT_CASE_PARAM(ttm_bo_validate_no_placement_not_signaled,
1152 ttm_bo_types_gen_params),
1153 KUNIT_CASE(ttm_bo_validate_move_fence_signaled),
1154 KUNIT_CASE_PARAM(ttm_bo_validate_move_fence_not_signaled,
1155 ttm_bo_validate_wait_gen_params),
1156 KUNIT_CASE(ttm_bo_validate_happy_evict),
1157 KUNIT_CASE(ttm_bo_validate_all_pinned_evict),
1158 KUNIT_CASE(ttm_bo_validate_allowed_only_evict),
1159 KUNIT_CASE(ttm_bo_validate_deleted_evict),
1160 KUNIT_CASE(ttm_bo_validate_busy_domain_evict),
1161 KUNIT_CASE(ttm_bo_validate_evict_gutting),
1162 KUNIT_CASE(ttm_bo_validate_recrusive_evict),
1163 {}
1164};
1165
1166static struct kunit_suite ttm_bo_validate_test_suite = {
1167 .name = "ttm_bo_validate",
1168 .init = ttm_test_devices_all_init,
1169 .exit = ttm_test_devices_fini,
1170 .test_cases = ttm_bo_validate_test_cases,
1171};
1172
1173kunit_test_suites(&ttm_bo_validate_test_suite);
1174
1175MODULE_DESCRIPTION("KUnit tests for ttm_bo APIs");
1176MODULE_LICENSE("GPL and additional rights");
1177

source code of linux/drivers/gpu/drm/ttm/tests/ttm_bo_validate_test.c