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 u32 size; 15 u32 extra_pages_num; 16 }; 17 18 static 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 30 static 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 36 KUNIT_ARRAY_PARAM(ttm_tt_init_basic, ttm_tt_init_basic_cases, 37 ttm_tt_init_case_desc); 38 39 static 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 67 static 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 90 static 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 110 static 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 130 static 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 153 static 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 172 static 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 188 static 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 213 static struct ttm_tt *ttm_tt_null_create(struct ttm_buffer_object *bo, 214 u32 page_flags) 215 { 216 return NULL; 217 } 218 219 static struct ttm_device_funcs ttm_dev_empty_funcs = { 220 .ttm_tt_create = ttm_tt_null_create, 221 }; 222 223 static 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 241 static 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 259 static 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 269 static 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 294 static 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 318 static 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 337 static 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 373 static 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 392 static 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 399 kunit_test_suites(&ttm_tt_test_suite); 400 401 MODULE_DESCRIPTION("KUnit tests for ttm_tt APIs"); 402 MODULE_LICENSE("GPL and additional rights"); 403