1 // SPDX-License-Identifier: GPL-2.0 AND MIT 2 /* 3 * Copyright © 2022 Intel Corporation 4 */ 5 6 #include <uapi/drm/xe_drm.h> 7 8 #include <kunit/test.h> 9 #include <kunit/visibility.h> 10 11 #include "tests/xe_kunit_helpers.h" 12 #include "tests/xe_pci_test.h" 13 14 #include "xe_pci.h" 15 #include "xe_pm.h" 16 17 static bool p2p_enabled(struct dma_buf_test_params *params) 18 { 19 return IS_ENABLED(CONFIG_PCI_P2PDMA) && params->attach_ops && 20 params->attach_ops->allow_peer2peer; 21 } 22 23 static bool is_dynamic(struct dma_buf_test_params *params) 24 { 25 return IS_ENABLED(CONFIG_DMABUF_MOVE_NOTIFY) && params->attach_ops && 26 params->attach_ops->move_notify; 27 } 28 29 static void check_residency(struct kunit *test, struct xe_bo *exported, 30 struct xe_bo *imported, struct dma_buf *dmabuf, 31 struct drm_exec *exec) 32 { 33 struct dma_buf_test_params *params = to_dma_buf_test_params(test->priv); 34 struct dma_buf_attachment *attach; 35 u32 mem_type; 36 int ret; 37 38 xe_bo_assert_held(exported); 39 xe_bo_assert_held(imported); 40 41 mem_type = XE_PL_VRAM0; 42 if (!(params->mem_mask & XE_BO_FLAG_VRAM0)) 43 /* No VRAM allowed */ 44 mem_type = XE_PL_TT; 45 else if (params->force_different_devices && !p2p_enabled(params)) 46 /* No P2P */ 47 mem_type = XE_PL_TT; 48 else if (params->force_different_devices && !is_dynamic(params) && 49 (params->mem_mask & XE_BO_FLAG_SYSTEM)) 50 /* Pin migrated to TT on non-dynamic attachments. */ 51 mem_type = XE_PL_TT; 52 53 if (!xe_bo_is_mem_type(exported, mem_type)) { 54 KUNIT_FAIL(test, "Exported bo was not in expected memory type.\n"); 55 return; 56 } 57 58 if (xe_bo_is_pinned(exported)) 59 return; 60 61 /* 62 * Evict exporter. Evicting the exported bo will 63 * evict also the imported bo through the move_notify() functionality if 64 * importer is on a different device. If they're on the same device, 65 * the exporter and the importer should be the same bo. 66 */ 67 ret = xe_bo_evict(exported, exec); 68 if (ret) { 69 if (ret != -EINTR && ret != -ERESTARTSYS) 70 KUNIT_FAIL(test, "Evicting exporter failed with err=%d.\n", 71 ret); 72 return; 73 } 74 75 /* Verify that also importer has been evicted to SYSTEM */ 76 if (exported != imported && !xe_bo_is_mem_type(imported, XE_PL_SYSTEM)) { 77 KUNIT_FAIL(test, "Importer wasn't properly evicted.\n"); 78 return; 79 } 80 81 /* Re-validate the importer. This should move also exporter in. */ 82 ret = xe_bo_validate(imported, NULL, false, exec); 83 if (ret) { 84 if (ret != -EINTR && ret != -ERESTARTSYS) 85 KUNIT_FAIL(test, "Validating importer failed with err=%d.\n", 86 ret); 87 return; 88 } 89 90 KUNIT_EXPECT_TRUE(test, xe_bo_is_mem_type(exported, mem_type)); 91 92 /* Check that we can pin without migrating. */ 93 attach = list_first_entry_or_null(&dmabuf->attachments, typeof(*attach), node); 94 if (attach) { 95 int err = dma_buf_pin(attach); 96 97 if (!err) { 98 KUNIT_EXPECT_TRUE(test, xe_bo_is_mem_type(exported, mem_type)); 99 dma_buf_unpin(attach); 100 } 101 KUNIT_EXPECT_EQ(test, err, 0); 102 } 103 104 if (params->force_different_devices) 105 KUNIT_EXPECT_TRUE(test, xe_bo_is_mem_type(imported, XE_PL_TT)); 106 else 107 KUNIT_EXPECT_TRUE(test, exported == imported); 108 } 109 110 static void xe_test_dmabuf_import_same_driver(struct xe_device *xe) 111 { 112 struct kunit *test = kunit_get_current_test(); 113 struct dma_buf_test_params *params = to_dma_buf_test_params(test->priv); 114 struct drm_gem_object *import; 115 struct dma_buf *dmabuf; 116 struct xe_bo *bo; 117 size_t size; 118 119 /* No VRAM on this device? */ 120 if (!ttm_manager_type(&xe->ttm, XE_PL_VRAM0) && 121 (params->mem_mask & XE_BO_FLAG_VRAM0)) 122 return; 123 124 size = PAGE_SIZE; 125 if ((params->mem_mask & XE_BO_FLAG_VRAM0) && 126 xe->info.vram_flags & XE_VRAM_FLAGS_NEED64K) 127 size = SZ_64K; 128 129 kunit_info(test, "running %s\n", __func__); 130 bo = xe_bo_create_user(xe, NULL, size, DRM_XE_GEM_CPU_CACHING_WC, 131 params->mem_mask, NULL); 132 if (IS_ERR(bo)) { 133 KUNIT_FAIL(test, "xe_bo_create() failed with err=%ld\n", 134 PTR_ERR(bo)); 135 return; 136 } 137 138 dmabuf = xe_gem_prime_export(&bo->ttm.base, 0); 139 if (IS_ERR(dmabuf)) { 140 KUNIT_FAIL(test, "xe_gem_prime_export() failed with err=%ld\n", 141 PTR_ERR(dmabuf)); 142 goto out; 143 } 144 bo->ttm.base.dma_buf = dmabuf; 145 146 import = xe_gem_prime_import(&xe->drm, dmabuf); 147 if (!IS_ERR(import)) { 148 struct xe_bo *import_bo = gem_to_xe_bo(import); 149 150 /* 151 * Did import succeed when it shouldn't due to lack of p2p support? 152 */ 153 if (params->force_different_devices && 154 !p2p_enabled(params) && 155 !(params->mem_mask & XE_BO_FLAG_SYSTEM)) { 156 KUNIT_FAIL(test, 157 "xe_gem_prime_import() succeeded when it shouldn't have\n"); 158 } else { 159 struct drm_exec *exec = XE_VALIDATION_OPT_OUT; 160 int err; 161 162 /* Is everything where we expect it to be? */ 163 xe_bo_lock(import_bo, false); 164 err = xe_bo_validate(import_bo, NULL, false, exec); 165 166 /* Pinning in VRAM is not allowed for non-dynamic attachments */ 167 if (!is_dynamic(params) && 168 params->force_different_devices && 169 !(params->mem_mask & XE_BO_FLAG_SYSTEM)) 170 KUNIT_EXPECT_EQ(test, err, -EINVAL); 171 /* Otherwise only expect interrupts or success. */ 172 else if (err && err != -EINTR && err != -ERESTARTSYS) 173 KUNIT_EXPECT_TRUE(test, !err || err == -EINTR || 174 err == -ERESTARTSYS); 175 176 if (!err) 177 check_residency(test, bo, import_bo, dmabuf, exec); 178 xe_bo_unlock(import_bo); 179 } 180 drm_gem_object_put(import); 181 } else if (PTR_ERR(import) != -EOPNOTSUPP) { 182 /* Unexpected error code. */ 183 KUNIT_FAIL(test, 184 "xe_gem_prime_import failed with the wrong err=%ld\n", 185 PTR_ERR(import)); 186 } else if (!params->force_different_devices || 187 p2p_enabled(params) || 188 (params->mem_mask & XE_BO_FLAG_SYSTEM)) { 189 /* Shouldn't fail if we can reuse same bo, use p2p or use system */ 190 KUNIT_FAIL(test, "dynamic p2p attachment failed with err=%ld\n", 191 PTR_ERR(import)); 192 } 193 bo->ttm.base.dma_buf = NULL; 194 dma_buf_put(dmabuf); 195 out: 196 drm_gem_object_put(&bo->ttm.base); 197 } 198 199 static const struct dma_buf_attach_ops nop2p_attach_ops = { 200 .allow_peer2peer = false, 201 .move_notify = xe_dma_buf_move_notify 202 }; 203 204 /* 205 * We test the implementation with bos of different residency and with 206 * importers with different capabilities; some lacking p2p support and some 207 * lacking dynamic capabilities (attach_ops == NULL). We also fake 208 * different devices avoiding the import shortcut that just reuses the same 209 * gem object. 210 */ 211 static const struct dma_buf_test_params test_params[] = { 212 {.mem_mask = XE_BO_FLAG_VRAM0, 213 .attach_ops = &xe_dma_buf_attach_ops}, 214 {.mem_mask = XE_BO_FLAG_VRAM0 | XE_BO_FLAG_NEEDS_CPU_ACCESS, 215 .attach_ops = &xe_dma_buf_attach_ops, 216 .force_different_devices = true}, 217 218 {.mem_mask = XE_BO_FLAG_VRAM0, 219 .attach_ops = &nop2p_attach_ops}, 220 {.mem_mask = XE_BO_FLAG_VRAM0, 221 .attach_ops = &nop2p_attach_ops, 222 .force_different_devices = true}, 223 224 {.mem_mask = XE_BO_FLAG_VRAM0}, 225 {.mem_mask = XE_BO_FLAG_VRAM0, 226 .force_different_devices = true}, 227 228 {.mem_mask = XE_BO_FLAG_SYSTEM, 229 .attach_ops = &xe_dma_buf_attach_ops}, 230 {.mem_mask = XE_BO_FLAG_SYSTEM, 231 .attach_ops = &xe_dma_buf_attach_ops, 232 .force_different_devices = true}, 233 234 {.mem_mask = XE_BO_FLAG_SYSTEM, 235 .attach_ops = &nop2p_attach_ops}, 236 {.mem_mask = XE_BO_FLAG_SYSTEM, 237 .attach_ops = &nop2p_attach_ops, 238 .force_different_devices = true}, 239 240 {.mem_mask = XE_BO_FLAG_SYSTEM}, 241 {.mem_mask = XE_BO_FLAG_SYSTEM, 242 .force_different_devices = true}, 243 244 {.mem_mask = XE_BO_FLAG_SYSTEM | XE_BO_FLAG_VRAM0, 245 .attach_ops = &xe_dma_buf_attach_ops}, 246 {.mem_mask = XE_BO_FLAG_SYSTEM | XE_BO_FLAG_VRAM0 | 247 XE_BO_FLAG_NEEDS_CPU_ACCESS, 248 .attach_ops = &xe_dma_buf_attach_ops, 249 .force_different_devices = true}, 250 251 {.mem_mask = XE_BO_FLAG_SYSTEM | XE_BO_FLAG_VRAM0, 252 .attach_ops = &nop2p_attach_ops}, 253 {.mem_mask = XE_BO_FLAG_SYSTEM | XE_BO_FLAG_VRAM0, 254 .attach_ops = &nop2p_attach_ops, 255 .force_different_devices = true}, 256 257 {.mem_mask = XE_BO_FLAG_SYSTEM | XE_BO_FLAG_VRAM0}, 258 {.mem_mask = XE_BO_FLAG_SYSTEM | XE_BO_FLAG_VRAM0, 259 .force_different_devices = true}, 260 261 {} 262 }; 263 264 static int dma_buf_run_device(struct xe_device *xe) 265 { 266 const struct dma_buf_test_params *params; 267 struct kunit *test = kunit_get_current_test(); 268 269 xe_pm_runtime_get(xe); 270 for (params = test_params; params->mem_mask; ++params) { 271 struct dma_buf_test_params p = *params; 272 273 p.base.id = XE_TEST_LIVE_DMA_BUF; 274 test->priv = &p; 275 xe_test_dmabuf_import_same_driver(xe); 276 } 277 xe_pm_runtime_put(xe); 278 279 /* A non-zero return would halt iteration over driver devices */ 280 return 0; 281 } 282 283 static void xe_dma_buf_kunit(struct kunit *test) 284 { 285 struct xe_device *xe = test->priv; 286 287 dma_buf_run_device(xe); 288 } 289 290 static struct kunit_case xe_dma_buf_tests[] = { 291 KUNIT_CASE_PARAM(xe_dma_buf_kunit, xe_pci_live_device_gen_param), 292 {} 293 }; 294 295 VISIBLE_IF_KUNIT 296 struct kunit_suite xe_dma_buf_test_suite = { 297 .name = "xe_dma_buf", 298 .test_cases = xe_dma_buf_tests, 299 .init = xe_kunit_helper_xe_device_live_test_init, 300 }; 301 EXPORT_SYMBOL_IF_KUNIT(xe_dma_buf_test_suite); 302