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	uint32_t size;
 15	uint32_t extra_pages_num;
 16};
 17
 18static int ttm_tt_test_init(struct kunit *test)
 19{
 20	struct ttm_test_devices *priv;
 21
 22	priv = kunit_kzalloc(test, 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
 31static 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
 43static 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
 49KUNIT_ARRAY_PARAM(ttm_tt_init_basic, ttm_tt_init_basic_cases,
 50		  ttm_tt_init_case_desc);
 51
 52static 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 extra_pages = params->extra_pages_num;
 60	int num_pages = params->size >> PAGE_SHIFT;
 61	int err;
 62
 63	tt = kunit_kzalloc(test, sizeof(*tt), GFP_KERNEL);
 64	KUNIT_ASSERT_NOT_NULL(test, tt);
 65
 66	bo = ttm_bo_kunit_init(test, test->priv, params->size);
 67
 68	err = ttm_tt_init(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
 80static 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, sizeof(*tt), GFP_KERNEL);
 90	KUNIT_ASSERT_NOT_NULL(test, tt);
 91
 92	bo = ttm_bo_kunit_init(test, test->priv, size);
 93
 94	/* Make the object size misaligned */
 95	bo->base.size += 1;
 96
 97	err = ttm_tt_init(tt, bo, 0, caching, 0);
 98	KUNIT_ASSERT_EQ(test, err, 0);
 99
100	KUNIT_ASSERT_EQ(test, tt->num_pages, num_pages);
101}
102
103static 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, sizeof(*tt), GFP_KERNEL);
111	KUNIT_ASSERT_NOT_NULL(test, tt);
112
113	bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE);
114
115	err = ttm_tt_init(tt, bo, 0, caching, 0);
116	KUNIT_ASSERT_EQ(test, err, 0);
117	KUNIT_ASSERT_NOT_NULL(test, tt->pages);
118
119	ttm_tt_fini(tt);
120	KUNIT_ASSERT_NULL(test, tt->pages);
121}
122
123static 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, sizeof(*tt), GFP_KERNEL);
131	KUNIT_ASSERT_NOT_NULL(test, tt);
132
133	bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE);
134
135	err = ttm_sg_tt_init(tt, bo, 0, caching);
136	KUNIT_ASSERT_EQ(test, err, 0);
137	KUNIT_ASSERT_NOT_NULL(test, tt->dma_address);
138
139	ttm_tt_fini(tt);
140	KUNIT_ASSERT_NULL(test, tt->dma_address);
141}
142
143static 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, sizeof(*tt), GFP_KERNEL);
152	KUNIT_ASSERT_NOT_NULL(test, tt);
153
154	bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE);
155
156	err = ttm_tt_init(tt, bo, 0, caching, 0);
157	KUNIT_ASSERT_EQ(test, err, 0);
158
159	shmem = shmem_file_setup("ttm swap", BO_SIZE, 0);
160	tt->swap_storage = shmem;
161
162	ttm_tt_fini(tt);
163	KUNIT_ASSERT_NULL(test, tt->swap_storage);
164}
165
166static 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, test->priv, BO_SIZE);
172	bo->type = ttm_bo_type_device;
173
174	dma_resv_lock(bo->base.resv, NULL);
175	err = ttm_tt_create(bo, false);
176	dma_resv_unlock(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(bo->ttm);
183}
184
185static 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, test->priv, BO_SIZE);
191	bo->type = ttm_bo_type_sg + 1;
192
193	dma_resv_lock(bo->base.resv, NULL);
194	err = ttm_tt_create(bo, false);
195	dma_resv_unlock(bo->base.resv);
196
197	KUNIT_EXPECT_EQ(test, err, -EINVAL);
198	KUNIT_EXPECT_NULL(test, bo->ttm);
199}
200
201static 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, sizeof(*tt), GFP_KERNEL);
209	KUNIT_ASSERT_NOT_NULL(test, tt);
210
211	bo = ttm_bo_kunit_init(test, test->priv, BO_SIZE);
212
213	err = ttm_tt_init(tt, bo, 0, caching, 0);
214	KUNIT_ASSERT_EQ(test, err, 0);
215	bo->ttm = tt;
216
217	dma_resv_lock(bo->base.resv, NULL);
218	err = ttm_tt_create(bo, false);
219	dma_resv_unlock(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
226static struct ttm_tt *ttm_tt_null_create(struct ttm_buffer_object *bo,
227					 uint32_t page_flags)
228{
229	return NULL;
230}
231
232static struct ttm_device_funcs ttm_dev_empty_funcs = {
233	.ttm_tt_create = ttm_tt_null_create,
234};
235
236static 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, 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(bo->base.resv, NULL);
248	err = ttm_tt_create(bo, false);
249	dma_resv_unlock(bo->base.resv);
250
251	KUNIT_ASSERT_EQ(test, err, -ENOMEM);
252}
253
254static 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, test->priv, BO_SIZE);
261
262	dma_resv_lock(bo->base.resv, NULL);
263	err = ttm_tt_create(bo, false);
264	dma_resv_unlock(bo->base.resv);
265
266	KUNIT_ASSERT_EQ(test, err, 0);
267	KUNIT_ASSERT_NOT_NULL(test, bo->ttm);
268
269	ttm_tt_destroy(devs->ttm_dev, bo->ttm);
270}
271
272static 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
286static 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
293kunit_test_suites(&ttm_tt_test_suite);
294
295MODULE_LICENSE("GPL");