1// SPDX-License-Identifier: GPL-2.0 AND MIT
2/*
3 * Copyright © 2023 Intel Corporation
4 */
5#include <drm/ttm/ttm_resource.h>
6
7#include "ttm_kunit_helpers.h"
8
9#define RES_SIZE SZ_4K
10#define TTM_PRIV_DUMMY_REG (TTM_NUM_MEM_TYPES - 1)
11
12struct ttm_resource_test_case {
13 const char *description;
14 u32 mem_type;
15 u32 flags;
16};
17
18struct ttm_resource_test_priv {
19 struct ttm_test_devices *devs;
20 struct ttm_buffer_object *bo;
21 struct ttm_place *place;
22};
23
24static const struct ttm_resource_manager_func ttm_resource_manager_mock_funcs = { };
25
26static int ttm_resource_test_init(struct kunit *test)
27{
28 struct ttm_resource_test_priv *priv;
29
30 priv = kunit_kzalloc(test, size: sizeof(*priv), GFP_KERNEL);
31 KUNIT_ASSERT_NOT_NULL(test, priv);
32
33 priv->devs = ttm_test_devices_all(test);
34 KUNIT_ASSERT_NOT_NULL(test, priv->devs);
35
36 test->priv = priv;
37
38 return 0;
39}
40
41static void ttm_resource_test_fini(struct kunit *test)
42{
43 struct ttm_resource_test_priv *priv = test->priv;
44
45 ttm_test_devices_put(test, devs: priv->devs);
46}
47
48static void ttm_init_test_mocks(struct kunit *test,
49 struct ttm_resource_test_priv *priv,
50 u32 mem_type, u32 flags)
51{
52 size_t size = RES_SIZE;
53
54 /* Make sure we have what we need for a good BO mock */
55 KUNIT_ASSERT_NOT_NULL(test, priv->devs->ttm_dev);
56
57 priv->bo = ttm_bo_kunit_init(test, devs: priv->devs, size, NULL);
58 priv->place = ttm_place_kunit_init(test, mem_type, flags);
59}
60
61static void ttm_init_test_manager(struct kunit *test,
62 struct ttm_resource_test_priv *priv,
63 u32 mem_type)
64{
65 struct ttm_device *ttm_dev = priv->devs->ttm_dev;
66 struct ttm_resource_manager *man;
67 size_t size = SZ_16K;
68
69 man = kunit_kzalloc(test, size: sizeof(*man), GFP_KERNEL);
70 KUNIT_ASSERT_NOT_NULL(test, man);
71
72 man->use_tt = false;
73 man->func = &ttm_resource_manager_mock_funcs;
74
75 ttm_resource_manager_init(man, bdev: ttm_dev, size);
76 ttm_set_driver_manager(bdev: ttm_dev, type: mem_type, manager: man);
77 ttm_resource_manager_set_used(man, used: true);
78}
79
80static const struct ttm_resource_test_case ttm_resource_cases[] = {
81 {
82 .description = "Init resource in TTM_PL_SYSTEM",
83 .mem_type = TTM_PL_SYSTEM,
84 },
85 {
86 .description = "Init resource in TTM_PL_VRAM",
87 .mem_type = TTM_PL_VRAM,
88 },
89 {
90 .description = "Init resource in a private placement",
91 .mem_type = TTM_PRIV_DUMMY_REG,
92 },
93 {
94 .description = "Init resource in TTM_PL_SYSTEM, set placement flags",
95 .mem_type = TTM_PL_SYSTEM,
96 .flags = TTM_PL_FLAG_TOPDOWN,
97 },
98};
99
100static void ttm_resource_case_desc(const struct ttm_resource_test_case *t, char *desc)
101{
102 strscpy(desc, t->description, KUNIT_PARAM_DESC_SIZE);
103}
104
105KUNIT_ARRAY_PARAM(ttm_resource, ttm_resource_cases, ttm_resource_case_desc);
106
107static void ttm_resource_init_basic(struct kunit *test)
108{
109 const struct ttm_resource_test_case *params = test->param_value;
110 struct ttm_resource_test_priv *priv = test->priv;
111 struct ttm_resource *res;
112 struct ttm_buffer_object *bo;
113 struct ttm_place *place;
114 struct ttm_resource_manager *man;
115 u64 expected_usage;
116
117 ttm_init_test_mocks(test, priv, mem_type: params->mem_type, flags: params->flags);
118 bo = priv->bo;
119 place = priv->place;
120
121 if (params->mem_type > TTM_PL_SYSTEM)
122 ttm_init_test_manager(test, priv, mem_type: params->mem_type);
123
124 res = kunit_kzalloc(test, size: sizeof(*res), GFP_KERNEL);
125 KUNIT_ASSERT_NOT_NULL(test, res);
126
127 man = ttm_manager_type(bdev: priv->devs->ttm_dev, mem_type: place->mem_type);
128 expected_usage = man->usage + RES_SIZE;
129
130 KUNIT_ASSERT_TRUE(test, list_empty(&man->lru[bo->priority]));
131
132 ttm_resource_init(bo, place, res);
133
134 KUNIT_ASSERT_EQ(test, res->start, 0);
135 KUNIT_ASSERT_EQ(test, res->size, RES_SIZE);
136 KUNIT_ASSERT_EQ(test, res->mem_type, place->mem_type);
137 KUNIT_ASSERT_EQ(test, res->placement, place->flags);
138 KUNIT_ASSERT_PTR_EQ(test, res->bo, bo);
139
140 KUNIT_ASSERT_NULL(test, res->bus.addr);
141 KUNIT_ASSERT_EQ(test, res->bus.offset, 0);
142 KUNIT_ASSERT_FALSE(test, res->bus.is_iomem);
143 KUNIT_ASSERT_EQ(test, res->bus.caching, ttm_cached);
144 KUNIT_ASSERT_EQ(test, man->usage, expected_usage);
145
146 KUNIT_ASSERT_TRUE(test, list_is_singular(&man->lru[bo->priority]));
147
148 ttm_resource_fini(man, res);
149}
150
151static void ttm_resource_init_pinned(struct kunit *test)
152{
153 struct ttm_resource_test_priv *priv = test->priv;
154 struct ttm_resource *res;
155 struct ttm_buffer_object *bo;
156 struct ttm_place *place;
157 struct ttm_resource_manager *man;
158
159 ttm_init_test_mocks(test, priv, TTM_PL_SYSTEM, flags: 0);
160 bo = priv->bo;
161 place = priv->place;
162
163 man = ttm_manager_type(bdev: priv->devs->ttm_dev, mem_type: place->mem_type);
164
165 res = kunit_kzalloc(test, size: sizeof(*res), GFP_KERNEL);
166 KUNIT_ASSERT_NOT_NULL(test, res);
167 KUNIT_ASSERT_TRUE(test, list_empty(&bo->bdev->unevictable));
168
169 dma_resv_lock(obj: bo->base.resv, NULL);
170 ttm_bo_pin(bo);
171 ttm_resource_init(bo, place, res);
172 KUNIT_ASSERT_TRUE(test, list_is_singular(&bo->bdev->unevictable));
173
174 ttm_bo_unpin(bo);
175 ttm_resource_fini(man, res);
176 dma_resv_unlock(obj: bo->base.resv);
177
178 KUNIT_ASSERT_TRUE(test, list_empty(&bo->bdev->unevictable));
179}
180
181static void ttm_resource_fini_basic(struct kunit *test)
182{
183 struct ttm_resource_test_priv *priv = test->priv;
184 struct ttm_resource *res;
185 struct ttm_buffer_object *bo;
186 struct ttm_place *place;
187 struct ttm_resource_manager *man;
188
189 ttm_init_test_mocks(test, priv, TTM_PL_SYSTEM, flags: 0);
190 bo = priv->bo;
191 place = priv->place;
192
193 man = ttm_manager_type(bdev: priv->devs->ttm_dev, mem_type: place->mem_type);
194
195 res = kunit_kzalloc(test, size: sizeof(*res), GFP_KERNEL);
196 KUNIT_ASSERT_NOT_NULL(test, res);
197
198 ttm_resource_init(bo, place, res);
199 ttm_resource_fini(man, res);
200
201 KUNIT_ASSERT_TRUE(test, list_empty(&res->lru.link));
202 KUNIT_ASSERT_EQ(test, man->usage, 0);
203}
204
205static void ttm_resource_manager_init_basic(struct kunit *test)
206{
207 struct ttm_resource_test_priv *priv = test->priv;
208 struct ttm_resource_manager *man;
209 size_t size = SZ_16K;
210 int i;
211
212 man = kunit_kzalloc(test, size: sizeof(*man), GFP_KERNEL);
213 KUNIT_ASSERT_NOT_NULL(test, man);
214
215 ttm_resource_manager_init(man, bdev: priv->devs->ttm_dev, size);
216
217 KUNIT_ASSERT_PTR_EQ(test, man->bdev, priv->devs->ttm_dev);
218 KUNIT_ASSERT_EQ(test, man->size, size);
219 KUNIT_ASSERT_EQ(test, man->usage, 0);
220 for (i = 0; i < TTM_NUM_MOVE_FENCES; i++)
221 KUNIT_ASSERT_NULL(test, man->eviction_fences[i]);
222
223 for (int i = 0; i < TTM_MAX_BO_PRIORITY; ++i)
224 KUNIT_ASSERT_TRUE(test, list_empty(&man->lru[i]));
225}
226
227static void ttm_resource_manager_usage_basic(struct kunit *test)
228{
229 struct ttm_resource_test_priv *priv = test->priv;
230 struct ttm_resource *res;
231 struct ttm_buffer_object *bo;
232 struct ttm_place *place;
233 struct ttm_resource_manager *man;
234 u64 actual_usage;
235
236 ttm_init_test_mocks(test, priv, TTM_PL_SYSTEM, TTM_PL_FLAG_TOPDOWN);
237 bo = priv->bo;
238 place = priv->place;
239
240 res = kunit_kzalloc(test, size: sizeof(*res), GFP_KERNEL);
241 KUNIT_ASSERT_NOT_NULL(test, res);
242
243 man = ttm_manager_type(bdev: priv->devs->ttm_dev, mem_type: place->mem_type);
244
245 ttm_resource_init(bo, place, res);
246 actual_usage = ttm_resource_manager_usage(man);
247
248 KUNIT_ASSERT_EQ(test, actual_usage, RES_SIZE);
249
250 ttm_resource_fini(man, res);
251}
252
253static void ttm_resource_manager_set_used_basic(struct kunit *test)
254{
255 struct ttm_resource_test_priv *priv = test->priv;
256 struct ttm_resource_manager *man;
257
258 man = ttm_manager_type(bdev: priv->devs->ttm_dev, TTM_PL_SYSTEM);
259 KUNIT_ASSERT_TRUE(test, man->use_type);
260
261 ttm_resource_manager_set_used(man, used: false);
262 KUNIT_ASSERT_FALSE(test, man->use_type);
263}
264
265static void ttm_sys_man_alloc_basic(struct kunit *test)
266{
267 struct ttm_resource_test_priv *priv = test->priv;
268 struct ttm_resource_manager *man;
269 struct ttm_buffer_object *bo;
270 struct ttm_place *place;
271 struct ttm_resource *res;
272 u32 mem_type = TTM_PL_SYSTEM;
273 int ret;
274
275 ttm_init_test_mocks(test, priv, mem_type, flags: 0);
276 bo = priv->bo;
277 place = priv->place;
278
279 man = ttm_manager_type(bdev: priv->devs->ttm_dev, mem_type);
280 ret = man->func->alloc(man, bo, place, &res);
281
282 KUNIT_ASSERT_EQ(test, ret, 0);
283 KUNIT_ASSERT_EQ(test, res->size, RES_SIZE);
284 KUNIT_ASSERT_EQ(test, res->mem_type, mem_type);
285 KUNIT_ASSERT_PTR_EQ(test, res->bo, bo);
286
287 ttm_resource_fini(man, res);
288}
289
290static void ttm_sys_man_free_basic(struct kunit *test)
291{
292 struct ttm_resource_test_priv *priv = test->priv;
293 struct ttm_resource_manager *man;
294 struct ttm_buffer_object *bo;
295 struct ttm_place *place;
296 struct ttm_resource *res;
297 u32 mem_type = TTM_PL_SYSTEM;
298
299 ttm_init_test_mocks(test, priv, mem_type, flags: 0);
300 bo = priv->bo;
301 place = priv->place;
302
303 res = kunit_kzalloc(test, size: sizeof(*res), GFP_KERNEL);
304 KUNIT_ASSERT_NOT_NULL(test, res);
305
306 ttm_resource_alloc(bo, place, res: &res, NULL);
307
308 man = ttm_manager_type(bdev: priv->devs->ttm_dev, mem_type);
309 man->func->free(man, res);
310
311 KUNIT_ASSERT_TRUE(test, list_empty(&man->lru[bo->priority]));
312 KUNIT_ASSERT_EQ(test, man->usage, 0);
313}
314
315static struct kunit_case ttm_resource_test_cases[] = {
316 KUNIT_CASE_PARAM(ttm_resource_init_basic, ttm_resource_gen_params),
317 KUNIT_CASE(ttm_resource_init_pinned),
318 KUNIT_CASE(ttm_resource_fini_basic),
319 KUNIT_CASE(ttm_resource_manager_init_basic),
320 KUNIT_CASE(ttm_resource_manager_usage_basic),
321 KUNIT_CASE(ttm_resource_manager_set_used_basic),
322 KUNIT_CASE(ttm_sys_man_alloc_basic),
323 KUNIT_CASE(ttm_sys_man_free_basic),
324 {}
325};
326
327static struct kunit_suite ttm_resource_test_suite = {
328 .name = "ttm_resource",
329 .init = ttm_resource_test_init,
330 .exit = ttm_resource_test_fini,
331 .test_cases = ttm_resource_test_cases,
332};
333
334kunit_test_suites(&ttm_resource_test_suite);
335
336MODULE_DESCRIPTION("KUnit tests for ttm_resource and ttm_sys_man APIs");
337MODULE_LICENSE("GPL and additional rights");
338

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