1 // SPDX-License-Identifier: GPL-2.0 AND MIT 2 /* 3 * Copyright © 2023 Intel Corporation 4 */ 5 6 #include <linux/export.h> 7 8 #include <drm/ttm/ttm_tt.h> 9 10 #include "ttm_kunit_helpers.h" 11 12 static const struct ttm_place sys_place = { 13 .fpfn = 0, 14 .lpfn = 0, 15 .mem_type = TTM_PL_SYSTEM, 16 .flags = TTM_PL_FLAG_FALLBACK, 17 }; 18 19 static const struct ttm_place mock1_place = { 20 .fpfn = 0, 21 .lpfn = 0, 22 .mem_type = TTM_PL_MOCK1, 23 .flags = TTM_PL_FLAG_FALLBACK, 24 }; 25 26 static const struct ttm_place mock2_place = { 27 .fpfn = 0, 28 .lpfn = 0, 29 .mem_type = TTM_PL_MOCK2, 30 .flags = TTM_PL_FLAG_FALLBACK, 31 }; 32 33 static struct ttm_placement sys_placement = { 34 .num_placement = 1, 35 .placement = &sys_place, 36 }; 37 38 static struct ttm_placement bad_placement = { 39 .num_placement = 1, 40 .placement = &mock1_place, 41 }; 42 43 static struct ttm_placement mock_placement = { 44 .num_placement = 1, 45 .placement = &mock2_place, 46 }; 47 48 static struct ttm_tt *ttm_tt_simple_create(struct ttm_buffer_object *bo, u32 page_flags) 49 { 50 struct ttm_tt *tt; 51 52 tt = kzalloc(sizeof(*tt), GFP_KERNEL); 53 ttm_tt_init(tt, bo, page_flags, ttm_cached, 0); 54 55 return tt; 56 } 57 58 static void ttm_tt_simple_destroy(struct ttm_device *bdev, struct ttm_tt *ttm) 59 { 60 kfree(ttm); 61 } 62 63 static int mock_move(struct ttm_buffer_object *bo, bool evict, 64 struct ttm_operation_ctx *ctx, 65 struct ttm_resource *new_mem, 66 struct ttm_place *hop) 67 { 68 struct ttm_resource *old_mem = bo->resource; 69 70 if (!old_mem || (old_mem->mem_type == TTM_PL_SYSTEM && !bo->ttm)) { 71 ttm_bo_move_null(bo, new_mem); 72 return 0; 73 } 74 75 if (bo->resource->mem_type == TTM_PL_VRAM && 76 new_mem->mem_type == TTM_PL_SYSTEM) { 77 hop->mem_type = TTM_PL_TT; 78 hop->flags = TTM_PL_FLAG_TEMPORARY; 79 hop->fpfn = 0; 80 hop->lpfn = 0; 81 return -EMULTIHOP; 82 } 83 84 if ((old_mem->mem_type == TTM_PL_SYSTEM && 85 new_mem->mem_type == TTM_PL_TT) || 86 (old_mem->mem_type == TTM_PL_TT && 87 new_mem->mem_type == TTM_PL_SYSTEM)) { 88 ttm_bo_move_null(bo, new_mem); 89 return 0; 90 } 91 92 return ttm_bo_move_memcpy(bo, ctx, new_mem); 93 } 94 95 static void mock_evict_flags(struct ttm_buffer_object *bo, 96 struct ttm_placement *placement) 97 { 98 switch (bo->resource->mem_type) { 99 case TTM_PL_VRAM: 100 case TTM_PL_SYSTEM: 101 *placement = sys_placement; 102 break; 103 case TTM_PL_TT: 104 *placement = mock_placement; 105 break; 106 case TTM_PL_MOCK1: 107 /* Purge objects coming from this domain */ 108 break; 109 } 110 } 111 112 static void bad_evict_flags(struct ttm_buffer_object *bo, 113 struct ttm_placement *placement) 114 { 115 *placement = bad_placement; 116 } 117 118 static int ttm_device_kunit_init_with_funcs(struct ttm_test_devices *priv, 119 struct ttm_device *ttm, 120 bool use_dma_alloc, 121 bool use_dma32, 122 struct ttm_device_funcs *funcs) 123 { 124 struct drm_device *drm = priv->drm; 125 int err; 126 127 err = ttm_device_init(ttm, funcs, drm->dev, 128 drm->anon_inode->i_mapping, 129 drm->vma_offset_manager, 130 use_dma_alloc, use_dma32); 131 132 return err; 133 } 134 135 struct ttm_device_funcs ttm_dev_funcs = { 136 .ttm_tt_create = ttm_tt_simple_create, 137 .ttm_tt_destroy = ttm_tt_simple_destroy, 138 .move = mock_move, 139 .eviction_valuable = ttm_bo_eviction_valuable, 140 .evict_flags = mock_evict_flags, 141 }; 142 EXPORT_SYMBOL_GPL(ttm_dev_funcs); 143 144 int ttm_device_kunit_init(struct ttm_test_devices *priv, 145 struct ttm_device *ttm, 146 bool use_dma_alloc, 147 bool use_dma32) 148 { 149 return ttm_device_kunit_init_with_funcs(priv, ttm, use_dma_alloc, 150 use_dma32, &ttm_dev_funcs); 151 } 152 EXPORT_SYMBOL_GPL(ttm_device_kunit_init); 153 154 struct ttm_device_funcs ttm_dev_funcs_bad_evict = { 155 .ttm_tt_create = ttm_tt_simple_create, 156 .ttm_tt_destroy = ttm_tt_simple_destroy, 157 .move = mock_move, 158 .eviction_valuable = ttm_bo_eviction_valuable, 159 .evict_flags = bad_evict_flags, 160 }; 161 EXPORT_SYMBOL_GPL(ttm_dev_funcs_bad_evict); 162 163 int ttm_device_kunit_init_bad_evict(struct ttm_test_devices *priv, 164 struct ttm_device *ttm, 165 bool use_dma_alloc, 166 bool use_dma32) 167 { 168 return ttm_device_kunit_init_with_funcs(priv, ttm, use_dma_alloc, 169 use_dma32, &ttm_dev_funcs_bad_evict); 170 } 171 EXPORT_SYMBOL_GPL(ttm_device_kunit_init_bad_evict); 172 173 struct ttm_buffer_object *ttm_bo_kunit_init(struct kunit *test, 174 struct ttm_test_devices *devs, 175 size_t size, 176 struct dma_resv *obj) 177 { 178 struct drm_gem_object gem_obj = { }; 179 struct ttm_buffer_object *bo; 180 int err; 181 182 bo = kunit_kzalloc(test, sizeof(*bo), GFP_KERNEL); 183 KUNIT_ASSERT_NOT_NULL(test, bo); 184 185 bo->base = gem_obj; 186 187 if (obj) 188 bo->base.resv = obj; 189 190 err = drm_gem_object_init(devs->drm, &bo->base, size); 191 KUNIT_ASSERT_EQ(test, err, 0); 192 193 bo->bdev = devs->ttm_dev; 194 bo->destroy = dummy_ttm_bo_destroy; 195 196 kref_init(&bo->kref); 197 198 return bo; 199 } 200 EXPORT_SYMBOL_GPL(ttm_bo_kunit_init); 201 202 struct ttm_place *ttm_place_kunit_init(struct kunit *test, u32 mem_type, u32 flags) 203 { 204 struct ttm_place *place; 205 206 place = kunit_kzalloc(test, sizeof(*place), GFP_KERNEL); 207 KUNIT_ASSERT_NOT_NULL(test, place); 208 209 place->mem_type = mem_type; 210 place->flags = flags; 211 212 return place; 213 } 214 EXPORT_SYMBOL_GPL(ttm_place_kunit_init); 215 216 void dummy_ttm_bo_destroy(struct ttm_buffer_object *bo) 217 { 218 drm_gem_object_release(&bo->base); 219 } 220 EXPORT_SYMBOL_GPL(dummy_ttm_bo_destroy); 221 222 struct ttm_test_devices *ttm_test_devices_basic(struct kunit *test) 223 { 224 struct ttm_test_devices *devs; 225 226 devs = kunit_kzalloc(test, sizeof(*devs), GFP_KERNEL); 227 KUNIT_ASSERT_NOT_NULL(test, devs); 228 229 devs->dev = drm_kunit_helper_alloc_device(test); 230 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, devs->dev); 231 232 /* Set mask for alloc_coherent mappings to enable ttm_pool_alloc testing */ 233 devs->dev->coherent_dma_mask = -1; 234 235 devs->drm = __drm_kunit_helper_alloc_drm_device(test, devs->dev, 236 sizeof(*devs->drm), 0, 237 DRIVER_GEM); 238 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, devs->drm); 239 240 return devs; 241 } 242 EXPORT_SYMBOL_GPL(ttm_test_devices_basic); 243 244 struct ttm_test_devices *ttm_test_devices_all(struct kunit *test) 245 { 246 struct ttm_test_devices *devs; 247 struct ttm_device *ttm_dev; 248 int err; 249 250 devs = ttm_test_devices_basic(test); 251 252 ttm_dev = kunit_kzalloc(test, sizeof(*ttm_dev), GFP_KERNEL); 253 KUNIT_ASSERT_NOT_NULL(test, ttm_dev); 254 255 err = ttm_device_kunit_init(devs, ttm_dev, false, false); 256 KUNIT_ASSERT_EQ(test, err, 0); 257 258 devs->ttm_dev = ttm_dev; 259 260 return devs; 261 } 262 EXPORT_SYMBOL_GPL(ttm_test_devices_all); 263 264 void ttm_test_devices_put(struct kunit *test, struct ttm_test_devices *devs) 265 { 266 if (devs->ttm_dev) 267 ttm_device_fini(devs->ttm_dev); 268 269 drm_kunit_helper_free_device(test, devs->dev); 270 } 271 EXPORT_SYMBOL_GPL(ttm_test_devices_put); 272 273 int ttm_test_devices_init(struct kunit *test) 274 { 275 struct ttm_test_devices *priv; 276 277 priv = kunit_kzalloc(test, sizeof(*priv), GFP_KERNEL); 278 KUNIT_ASSERT_NOT_NULL(test, priv); 279 280 priv = ttm_test_devices_basic(test); 281 test->priv = priv; 282 283 return 0; 284 } 285 EXPORT_SYMBOL_GPL(ttm_test_devices_init); 286 287 int ttm_test_devices_all_init(struct kunit *test) 288 { 289 struct ttm_test_devices *priv; 290 291 priv = kunit_kzalloc(test, sizeof(*priv), GFP_KERNEL); 292 KUNIT_ASSERT_NOT_NULL(test, priv); 293 294 priv = ttm_test_devices_all(test); 295 test->priv = priv; 296 297 return 0; 298 } 299 EXPORT_SYMBOL_GPL(ttm_test_devices_all_init); 300 301 void ttm_test_devices_fini(struct kunit *test) 302 { 303 ttm_test_devices_put(test, test->priv); 304 } 305 EXPORT_SYMBOL_GPL(ttm_test_devices_fini); 306 307 MODULE_DESCRIPTION("TTM KUnit test helper functions"); 308 MODULE_LICENSE("GPL and additional rights"); 309