Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  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
 12struct ttm_tt_test_case {
 13	const char *description;
 14	u32 size;
 15	u32 extra_pages_num;
 16};
 17
 18static const struct ttm_tt_test_case ttm_tt_init_basic_cases[] = {
 19	{
 20		.description = "Page-aligned size",
 21		.size = SZ_4K,
 22	},
 23	{
 24		.description = "Extra pages requested",
 25		.size = SZ_4K,
 26		.extra_pages_num = 1,
 27	},
 28};
 29
 30static void ttm_tt_init_case_desc(const struct ttm_tt_test_case *t,
 31				  char *desc)
 32{
 33	strscpy(desc, t->description, KUNIT_PARAM_DESC_SIZE);
 34}
 35
 36KUNIT_ARRAY_PARAM(ttm_tt_init_basic, ttm_tt_init_basic_cases,
 37		  ttm_tt_init_case_desc);
 38
 39static void ttm_tt_init_basic(struct kunit *test)
 40{
 41	const struct ttm_tt_test_case *params = test->param_value;
 42	struct ttm_buffer_object *bo;
 43	struct ttm_tt *tt;
 44	u32 page_flags = TTM_TT_FLAG_ZERO_ALLOC;
 45	enum ttm_caching caching = ttm_cached;
 46	u32 extra_pages = params->extra_pages_num;
 47	int num_pages = params->size >> PAGE_SHIFT;
 48	int err;
 49
 50	tt = kunit_kzalloc(test, sizeof(*tt), GFP_KERNEL);
 51	KUNIT_ASSERT_NOT_NULL(test, tt);
 52
 53	bo = ttm_bo_kunit_init(test, test->priv, params->size, NULL);
 54
 55	err = ttm_tt_init(tt, bo, page_flags, caching, extra_pages);
 56	KUNIT_ASSERT_EQ(test, err, 0);
 57
 58	KUNIT_ASSERT_EQ(test, tt->num_pages, num_pages + extra_pages);
 59
 60	KUNIT_ASSERT_EQ(test, tt->page_flags, page_flags);
 61	KUNIT_ASSERT_EQ(test, tt->caching, caching);
 62
 63	KUNIT_ASSERT_NULL(test, tt->dma_address);
 64	KUNIT_ASSERT_NULL(test, tt->swap_storage);
 65}
 66
 67static void ttm_tt_init_misaligned(struct kunit *test)
 68{
 69	struct ttm_buffer_object *bo;
 70	struct ttm_tt *tt;
 71	enum ttm_caching caching = ttm_cached;
 72	u32 size = SZ_8K;
 73	int num_pages = (size + SZ_4K) >> PAGE_SHIFT;
 74	int err;
 75
 76	tt = kunit_kzalloc(test, sizeof(*tt), GFP_KERNEL);
 77	KUNIT_ASSERT_NOT_NULL(test, tt);
 78
 79	bo = ttm_bo_kunit_init(test, test->priv, size, NULL);
 80
 81	/* Make the object size misaligned */
 82	bo->base.size += 1;
 83
 84	err = ttm_tt_init(tt, bo, 0, caching, 0);
 85	KUNIT_ASSERT_EQ(test, err, 0);
 86
 87	KUNIT_ASSERT_EQ(test, tt->num_pages, num_pages);
 88}
 89
 90static void ttm_tt_fini_basic(struct kunit *test)
 91{
 92	struct ttm_buffer_object *bo;
 93	struct ttm_tt *tt;
 94	enum ttm_caching caching = ttm_cached;
 95	int err;
 96
 97	tt = kunit_kzalloc(test, sizeof(*tt), GFP_KERNEL);
 98	KUNIT_ASSERT_NOT_NULL(test, tt);
 99
100	bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE, NULL);
101
102	err = ttm_tt_init(tt, bo, 0, caching, 0);
103	KUNIT_ASSERT_EQ(test, err, 0);
104	KUNIT_ASSERT_NOT_NULL(test, tt->pages);
105
106	ttm_tt_fini(tt);
107	KUNIT_ASSERT_NULL(test, tt->pages);
108}
109
110static void ttm_tt_fini_sg(struct kunit *test)
111{
112	struct ttm_buffer_object *bo;
113	struct ttm_tt *tt;
114	enum ttm_caching caching = ttm_cached;
115	int err;
116
117	tt = kunit_kzalloc(test, sizeof(*tt), GFP_KERNEL);
118	KUNIT_ASSERT_NOT_NULL(test, tt);
119
120	bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE, NULL);
121
122	err = ttm_sg_tt_init(tt, bo, 0, caching);
123	KUNIT_ASSERT_EQ(test, err, 0);
124	KUNIT_ASSERT_NOT_NULL(test, tt->dma_address);
125
126	ttm_tt_fini(tt);
127	KUNIT_ASSERT_NULL(test, tt->dma_address);
128}
129
130static void ttm_tt_fini_shmem(struct kunit *test)
131{
132	struct ttm_buffer_object *bo;
133	struct ttm_tt *tt;
134	struct file *shmem;
135	enum ttm_caching caching = ttm_cached;
136	int err;
137
138	tt = kunit_kzalloc(test, sizeof(*tt), GFP_KERNEL);
139	KUNIT_ASSERT_NOT_NULL(test, tt);
140
141	bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE, NULL);
142
143	err = ttm_tt_init(tt, bo, 0, caching, 0);
144	KUNIT_ASSERT_EQ(test, err, 0);
145
146	shmem = shmem_file_setup("ttm swap", BO_SIZE, 0);
147	tt->swap_storage = shmem;
148
149	ttm_tt_fini(tt);
150	KUNIT_ASSERT_NULL(test, tt->swap_storage);
151}
152
153static void ttm_tt_create_basic(struct kunit *test)
154{
155	struct ttm_buffer_object *bo;
156	int err;
157
158	bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE, NULL);
159	bo->type = ttm_bo_type_device;
160
161	dma_resv_lock(bo->base.resv, NULL);
162	err = ttm_tt_create(bo, false);
163	dma_resv_unlock(bo->base.resv);
164
165	KUNIT_EXPECT_EQ(test, err, 0);
166	KUNIT_EXPECT_NOT_NULL(test, bo->ttm);
167
168	/* Free manually, as it was allocated outside of KUnit */
169	kfree(bo->ttm);
170}
171
172static void ttm_tt_create_invalid_bo_type(struct kunit *test)
173{
174	struct ttm_buffer_object *bo;
175	int err;
176
177	bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE, NULL);
178	bo->type = ttm_bo_type_sg + 1;
179
180	dma_resv_lock(bo->base.resv, NULL);
181	err = ttm_tt_create(bo, false);
182	dma_resv_unlock(bo->base.resv);
183
184	KUNIT_EXPECT_EQ(test, err, -EINVAL);
185	KUNIT_EXPECT_NULL(test, bo->ttm);
186}
187
188static void ttm_tt_create_ttm_exists(struct kunit *test)
189{
190	struct ttm_buffer_object *bo;
191	struct ttm_tt *tt;
192	enum ttm_caching caching = ttm_cached;
193	int err;
194
195	tt = kunit_kzalloc(test, sizeof(*tt), GFP_KERNEL);
196	KUNIT_ASSERT_NOT_NULL(test, tt);
197
198	bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE, NULL);
199
200	err = ttm_tt_init(tt, bo, 0, caching, 0);
201	KUNIT_ASSERT_EQ(test, err, 0);
202	bo->ttm = tt;
203
204	dma_resv_lock(bo->base.resv, NULL);
205	err = ttm_tt_create(bo, false);
206	dma_resv_unlock(bo->base.resv);
207
208	/* Expect to keep the previous TTM */
209	KUNIT_ASSERT_EQ(test, err, 0);
210	KUNIT_ASSERT_PTR_EQ(test, tt, bo->ttm);
211}
212
213static struct ttm_tt *ttm_tt_null_create(struct ttm_buffer_object *bo,
214					 u32 page_flags)
215{
216	return NULL;
217}
218
219static struct ttm_device_funcs ttm_dev_empty_funcs = {
220	.ttm_tt_create = ttm_tt_null_create,
221};
222
223static void ttm_tt_create_failed(struct kunit *test)
224{
225	const struct ttm_test_devices *devs = test->priv;
226	struct ttm_buffer_object *bo;
227	int err;
228
229	bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE, NULL);
230
231	/* Update ttm_device_funcs so we don't alloc ttm_tt */
232	devs->ttm_dev->funcs = &ttm_dev_empty_funcs;
233
234	dma_resv_lock(bo->base.resv, NULL);
235	err = ttm_tt_create(bo, false);
236	dma_resv_unlock(bo->base.resv);
237
238	KUNIT_ASSERT_EQ(test, err, -ENOMEM);
239}
240
241static void ttm_tt_destroy_basic(struct kunit *test)
242{
243	const struct ttm_test_devices *devs = test->priv;
244	struct ttm_buffer_object *bo;
245	int err;
246
247	bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE, NULL);
248
249	dma_resv_lock(bo->base.resv, NULL);
250	err = ttm_tt_create(bo, false);
251	dma_resv_unlock(bo->base.resv);
252
253	KUNIT_ASSERT_EQ(test, err, 0);
254	KUNIT_ASSERT_NOT_NULL(test, bo->ttm);
255
256	ttm_tt_destroy(devs->ttm_dev, bo->ttm);
257}
258
259static void ttm_tt_populate_null_ttm(struct kunit *test)
260{
261	const struct ttm_test_devices *devs = test->priv;
262	struct ttm_operation_ctx ctx = { };
263	int err;
264
265	err = ttm_tt_populate(devs->ttm_dev, NULL, &ctx);
266	KUNIT_ASSERT_EQ(test, err, -EINVAL);
267}
268
269static void ttm_tt_populate_populated_ttm(struct kunit *test)
270{
271	const struct ttm_test_devices *devs = test->priv;
272	struct ttm_operation_ctx ctx = { };
273	struct ttm_buffer_object *bo;
274	struct ttm_tt *tt;
275	struct page *populated_page;
276	int err;
277
278	bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE, NULL);
279
280	tt = kunit_kzalloc(test, sizeof(*tt), GFP_KERNEL);
281	KUNIT_ASSERT_NOT_NULL(test, tt);
282
283	err = ttm_tt_init(tt, bo, 0, ttm_cached, 0);
284	KUNIT_ASSERT_EQ(test, err, 0);
285
286	err = ttm_tt_populate(devs->ttm_dev, tt, &ctx);
287	KUNIT_ASSERT_EQ(test, err, 0);
288	populated_page = *tt->pages;
289
290	err = ttm_tt_populate(devs->ttm_dev, tt, &ctx);
291	KUNIT_ASSERT_PTR_EQ(test, populated_page, *tt->pages);
292}
293
294static void ttm_tt_unpopulate_basic(struct kunit *test)
295{
296	const struct ttm_test_devices *devs = test->priv;
297	struct ttm_operation_ctx ctx = { };
298	struct ttm_buffer_object *bo;
299	struct ttm_tt *tt;
300	int err;
301
302	bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE, NULL);
303
304	tt = kunit_kzalloc(test, sizeof(*tt), GFP_KERNEL);
305	KUNIT_ASSERT_NOT_NULL(test, tt);
306
307	err = ttm_tt_init(tt, bo, 0, ttm_cached, 0);
308	KUNIT_ASSERT_EQ(test, err, 0);
309
310	err = ttm_tt_populate(devs->ttm_dev, tt, &ctx);
311	KUNIT_ASSERT_EQ(test, err, 0);
312	KUNIT_ASSERT_TRUE(test, ttm_tt_is_populated(tt));
313
314	ttm_tt_unpopulate(devs->ttm_dev, tt);
315	KUNIT_ASSERT_FALSE(test, ttm_tt_is_populated(tt));
316}
317
318static void ttm_tt_unpopulate_empty_ttm(struct kunit *test)
319{
320	const struct ttm_test_devices *devs = test->priv;
321	struct ttm_buffer_object *bo;
322	struct ttm_tt *tt;
323	int err;
324
325	bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE, NULL);
326
327	tt = kunit_kzalloc(test, sizeof(*tt), GFP_KERNEL);
328	KUNIT_ASSERT_NOT_NULL(test, tt);
329
330	err = ttm_tt_init(tt, bo, 0, ttm_cached, 0);
331	KUNIT_ASSERT_EQ(test, err, 0);
332
333	ttm_tt_unpopulate(devs->ttm_dev, tt);
334	/* Expect graceful handling of unpopulated TTs */
335}
336
337static void ttm_tt_swapin_basic(struct kunit *test)
338{
339	const struct ttm_test_devices *devs = test->priv;
340	int expected_num_pages = BO_SIZE >> PAGE_SHIFT;
341	struct ttm_operation_ctx ctx = { };
342	struct ttm_buffer_object *bo;
343	struct ttm_tt *tt;
344	int err, num_pages;
345
346	bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE, NULL);
347
348	tt = kunit_kzalloc(test, sizeof(*tt), GFP_KERNEL);
349	KUNIT_ASSERT_NOT_NULL(test, tt);
350
351	err = ttm_tt_init(tt, bo, 0, ttm_cached, 0);
352	KUNIT_ASSERT_EQ(test, err, 0);
353
354	err = ttm_tt_populate(devs->ttm_dev, tt, &ctx);
355	KUNIT_ASSERT_EQ(test, err, 0);
356	KUNIT_ASSERT_TRUE(test, ttm_tt_is_populated(tt));
357
358	num_pages = ttm_tt_swapout(devs->ttm_dev, tt, GFP_KERNEL);
359	KUNIT_ASSERT_EQ(test, num_pages, expected_num_pages);
360	KUNIT_ASSERT_NOT_NULL(test, tt->swap_storage);
361	KUNIT_ASSERT_TRUE(test, tt->page_flags & TTM_TT_FLAG_SWAPPED);
362
363	/* Swapout depopulates TT, allocate pages and then swap them in */
364	err = ttm_pool_alloc(&devs->ttm_dev->pool, tt, &ctx);
365	KUNIT_ASSERT_EQ(test, err, 0);
366
367	err = ttm_tt_swapin(tt);
368	KUNIT_ASSERT_EQ(test, err, 0);
369	KUNIT_ASSERT_NULL(test, tt->swap_storage);
370	KUNIT_ASSERT_FALSE(test, tt->page_flags & TTM_TT_FLAG_SWAPPED);
371}
372
373static struct kunit_case ttm_tt_test_cases[] = {
374	KUNIT_CASE_PARAM(ttm_tt_init_basic, ttm_tt_init_basic_gen_params),
375	KUNIT_CASE(ttm_tt_init_misaligned),
376	KUNIT_CASE(ttm_tt_fini_basic),
377	KUNIT_CASE(ttm_tt_fini_sg),
378	KUNIT_CASE(ttm_tt_fini_shmem),
379	KUNIT_CASE(ttm_tt_create_basic),
380	KUNIT_CASE(ttm_tt_create_invalid_bo_type),
381	KUNIT_CASE(ttm_tt_create_ttm_exists),
382	KUNIT_CASE(ttm_tt_create_failed),
383	KUNIT_CASE(ttm_tt_destroy_basic),
384	KUNIT_CASE(ttm_tt_populate_null_ttm),
385	KUNIT_CASE(ttm_tt_populate_populated_ttm),
386	KUNIT_CASE(ttm_tt_unpopulate_basic),
387	KUNIT_CASE(ttm_tt_unpopulate_empty_ttm),
388	KUNIT_CASE(ttm_tt_swapin_basic),
389	{}
390};
391
392static struct kunit_suite ttm_tt_test_suite = {
393	.name = "ttm_tt",
394	.init = ttm_test_devices_all_init,
395	.exit = ttm_test_devices_fini,
396	.test_cases = ttm_tt_test_cases,
397};
398
399kunit_test_suites(&ttm_tt_test_suite);
400
401MODULE_DESCRIPTION("KUnit tests for ttm_tt APIs");
402MODULE_LICENSE("GPL and additional rights");