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 12 struct ttm_resource_test_case { 13 const char *description; 14 u32 mem_type; 15 u32 flags; 16 }; 17 18 struct ttm_resource_test_priv { 19 struct ttm_test_devices *devs; 20 struct ttm_buffer_object *bo; 21 struct ttm_place *place; 22 }; 23 24 static const struct ttm_resource_manager_func ttm_resource_manager_mock_funcs = { }; 25 26 static int ttm_resource_test_init(struct kunit *test) 27 { 28 struct ttm_resource_test_priv *priv; 29 30 priv = kunit_kzalloc(test, 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 41 static 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, priv->devs); 46 } 47 48 static 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, priv->devs, size, NULL); 58 priv->place = ttm_place_kunit_init(test, mem_type, flags); 59 } 60 61 static 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, 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, ttm_dev, size); 76 ttm_set_driver_manager(ttm_dev, mem_type, man); 77 ttm_resource_manager_set_used(man, true); 78 } 79 80 static 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 100 static 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 105 KUNIT_ARRAY_PARAM(ttm_resource, ttm_resource_cases, ttm_resource_case_desc); 106 107 static 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, params->mem_type, 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, params->mem_type); 123 124 res = kunit_kzalloc(test, sizeof(*res), GFP_KERNEL); 125 KUNIT_ASSERT_NOT_NULL(test, res); 126 127 man = ttm_manager_type(priv->devs->ttm_dev, 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 151 static 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, 0); 160 bo = priv->bo; 161 place = priv->place; 162 163 man = ttm_manager_type(priv->devs->ttm_dev, place->mem_type); 164 165 res = kunit_kzalloc(test, sizeof(*res), GFP_KERNEL); 166 KUNIT_ASSERT_NOT_NULL(test, res); 167 KUNIT_ASSERT_TRUE(test, list_empty(&bo->bdev->pinned)); 168 169 dma_resv_lock(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->pinned)); 173 174 ttm_bo_unpin(bo); 175 ttm_resource_fini(man, res); 176 dma_resv_unlock(bo->base.resv); 177 178 KUNIT_ASSERT_TRUE(test, list_empty(&bo->bdev->pinned)); 179 } 180 181 static 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, 0); 190 bo = priv->bo; 191 place = priv->place; 192 193 man = ttm_manager_type(priv->devs->ttm_dev, place->mem_type); 194 195 res = kunit_kzalloc(test, 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 205 static 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 211 man = kunit_kzalloc(test, sizeof(*man), GFP_KERNEL); 212 KUNIT_ASSERT_NOT_NULL(test, man); 213 214 ttm_resource_manager_init(man, priv->devs->ttm_dev, size); 215 216 KUNIT_ASSERT_PTR_EQ(test, man->bdev, priv->devs->ttm_dev); 217 KUNIT_ASSERT_EQ(test, man->size, size); 218 KUNIT_ASSERT_EQ(test, man->usage, 0); 219 KUNIT_ASSERT_NULL(test, man->move); 220 KUNIT_ASSERT_NOT_NULL(test, &man->move_lock); 221 222 for (int i = 0; i < TTM_MAX_BO_PRIORITY; ++i) 223 KUNIT_ASSERT_TRUE(test, list_empty(&man->lru[i])); 224 } 225 226 static void ttm_resource_manager_usage_basic(struct kunit *test) 227 { 228 struct ttm_resource_test_priv *priv = test->priv; 229 struct ttm_resource *res; 230 struct ttm_buffer_object *bo; 231 struct ttm_place *place; 232 struct ttm_resource_manager *man; 233 u64 actual_usage; 234 235 ttm_init_test_mocks(test, priv, TTM_PL_SYSTEM, TTM_PL_FLAG_TOPDOWN); 236 bo = priv->bo; 237 place = priv->place; 238 239 res = kunit_kzalloc(test, sizeof(*res), GFP_KERNEL); 240 KUNIT_ASSERT_NOT_NULL(test, res); 241 242 man = ttm_manager_type(priv->devs->ttm_dev, place->mem_type); 243 244 ttm_resource_init(bo, place, res); 245 actual_usage = ttm_resource_manager_usage(man); 246 247 KUNIT_ASSERT_EQ(test, actual_usage, RES_SIZE); 248 249 ttm_resource_fini(man, res); 250 } 251 252 static void ttm_resource_manager_set_used_basic(struct kunit *test) 253 { 254 struct ttm_resource_test_priv *priv = test->priv; 255 struct ttm_resource_manager *man; 256 257 man = ttm_manager_type(priv->devs->ttm_dev, TTM_PL_SYSTEM); 258 KUNIT_ASSERT_TRUE(test, man->use_type); 259 260 ttm_resource_manager_set_used(man, false); 261 KUNIT_ASSERT_FALSE(test, man->use_type); 262 } 263 264 static void ttm_sys_man_alloc_basic(struct kunit *test) 265 { 266 struct ttm_resource_test_priv *priv = test->priv; 267 struct ttm_resource_manager *man; 268 struct ttm_buffer_object *bo; 269 struct ttm_place *place; 270 struct ttm_resource *res; 271 u32 mem_type = TTM_PL_SYSTEM; 272 int ret; 273 274 ttm_init_test_mocks(test, priv, mem_type, 0); 275 bo = priv->bo; 276 place = priv->place; 277 278 man = ttm_manager_type(priv->devs->ttm_dev, mem_type); 279 ret = man->func->alloc(man, bo, place, &res); 280 281 KUNIT_ASSERT_EQ(test, ret, 0); 282 KUNIT_ASSERT_EQ(test, res->size, RES_SIZE); 283 KUNIT_ASSERT_EQ(test, res->mem_type, mem_type); 284 KUNIT_ASSERT_PTR_EQ(test, res->bo, bo); 285 286 ttm_resource_fini(man, res); 287 } 288 289 static void ttm_sys_man_free_basic(struct kunit *test) 290 { 291 struct ttm_resource_test_priv *priv = test->priv; 292 struct ttm_resource_manager *man; 293 struct ttm_buffer_object *bo; 294 struct ttm_place *place; 295 struct ttm_resource *res; 296 u32 mem_type = TTM_PL_SYSTEM; 297 298 ttm_init_test_mocks(test, priv, mem_type, 0); 299 bo = priv->bo; 300 place = priv->place; 301 302 res = kunit_kzalloc(test, sizeof(*res), GFP_KERNEL); 303 KUNIT_ASSERT_NOT_NULL(test, res); 304 305 ttm_resource_alloc(bo, place, &res); 306 307 man = ttm_manager_type(priv->devs->ttm_dev, mem_type); 308 man->func->free(man, res); 309 310 KUNIT_ASSERT_TRUE(test, list_empty(&man->lru[bo->priority])); 311 KUNIT_ASSERT_EQ(test, man->usage, 0); 312 } 313 314 static struct kunit_case ttm_resource_test_cases[] = { 315 KUNIT_CASE_PARAM(ttm_resource_init_basic, ttm_resource_gen_params), 316 KUNIT_CASE(ttm_resource_init_pinned), 317 KUNIT_CASE(ttm_resource_fini_basic), 318 KUNIT_CASE(ttm_resource_manager_init_basic), 319 KUNIT_CASE(ttm_resource_manager_usage_basic), 320 KUNIT_CASE(ttm_resource_manager_set_used_basic), 321 KUNIT_CASE(ttm_sys_man_alloc_basic), 322 KUNIT_CASE(ttm_sys_man_free_basic), 323 {} 324 }; 325 326 static struct kunit_suite ttm_resource_test_suite = { 327 .name = "ttm_resource", 328 .init = ttm_resource_test_init, 329 .exit = ttm_resource_test_fini, 330 .test_cases = ttm_resource_test_cases, 331 }; 332 333 kunit_test_suites(&ttm_resource_test_suite); 334 335 MODULE_DESCRIPTION("KUnit tests for ttm_resource and ttm_sys_man APIs"); 336 MODULE_LICENSE("GPL and additional rights"); 337