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 uint32_t size; 15 uint32_t extra_pages_num; 16 }; 17 18 static 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 31 static 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 43 static 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 49 KUNIT_ARRAY_PARAM(ttm_tt_init_basic, ttm_tt_init_basic_cases, 50 ttm_tt_init_case_desc); 51 52 static 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 80 static 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 103 static 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 123 static 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 143 static 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 166 static 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 185 static 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 201 static 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 226 static struct ttm_tt *ttm_tt_null_create(struct ttm_buffer_object *bo, 227 uint32_t page_flags) 228 { 229 return NULL; 230 } 231 232 static struct ttm_device_funcs ttm_dev_empty_funcs = { 233 .ttm_tt_create = ttm_tt_null_create, 234 }; 235 236 static 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 254 static 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 272 static 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 286 static 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 293 kunit_test_suites(&ttm_tt_test_suite); 294 295 MODULE_LICENSE("GPL"); 296