561 lines · c
1/*2 * SPDX-License-Identifier: MIT3 *4 * Copyright © 2016 Intel Corporation5 */6 7#include "i915_drv.h"8#include "i915_selftest.h"9#include "gem/i915_gem_context.h"10#include "gt/intel_gt.h"11 12#include "mock_context.h"13#include "mock_dmabuf.h"14#include "igt_gem_utils.h"15#include "selftests/mock_drm.h"16#include "selftests/mock_gem_device.h"17 18static int igt_dmabuf_export(void *arg)19{20 struct drm_i915_private *i915 = arg;21 struct drm_i915_gem_object *obj;22 struct dma_buf *dmabuf;23 24 obj = i915_gem_object_create_shmem(i915, PAGE_SIZE);25 if (IS_ERR(obj))26 return PTR_ERR(obj);27 28 dmabuf = i915_gem_prime_export(&obj->base, 0);29 i915_gem_object_put(obj);30 if (IS_ERR(dmabuf)) {31 pr_err("i915_gem_prime_export failed with err=%d\n",32 (int)PTR_ERR(dmabuf));33 return PTR_ERR(dmabuf);34 }35 36 dma_buf_put(dmabuf);37 return 0;38}39 40static int igt_dmabuf_import_self(void *arg)41{42 struct drm_i915_private *i915 = arg;43 struct drm_i915_gem_object *obj, *import_obj;44 struct drm_gem_object *import;45 struct dma_buf *dmabuf;46 int err;47 48 obj = i915_gem_object_create_shmem(i915, PAGE_SIZE);49 if (IS_ERR(obj))50 return PTR_ERR(obj);51 52 dmabuf = i915_gem_prime_export(&obj->base, 0);53 if (IS_ERR(dmabuf)) {54 pr_err("i915_gem_prime_export failed with err=%d\n",55 (int)PTR_ERR(dmabuf));56 err = PTR_ERR(dmabuf);57 goto out;58 }59 60 import = i915_gem_prime_import(&i915->drm, dmabuf);61 if (IS_ERR(import)) {62 pr_err("i915_gem_prime_import failed with err=%d\n",63 (int)PTR_ERR(import));64 err = PTR_ERR(import);65 goto out_dmabuf;66 }67 import_obj = to_intel_bo(import);68 69 if (import != &obj->base) {70 pr_err("i915_gem_prime_import created a new object!\n");71 err = -EINVAL;72 goto out_import;73 }74 75 i915_gem_object_lock(import_obj, NULL);76 err = __i915_gem_object_get_pages(import_obj);77 i915_gem_object_unlock(import_obj);78 if (err) {79 pr_err("Same object dma-buf get_pages failed!\n");80 goto out_import;81 }82 83 err = 0;84out_import:85 i915_gem_object_put(import_obj);86out_dmabuf:87 dma_buf_put(dmabuf);88out:89 i915_gem_object_put(obj);90 return err;91}92 93static int igt_dmabuf_import_same_driver_lmem(void *arg)94{95 struct drm_i915_private *i915 = arg;96 struct intel_memory_region *lmem = i915->mm.regions[INTEL_REGION_LMEM_0];97 struct drm_i915_gem_object *obj;98 struct drm_gem_object *import;99 struct dma_buf *dmabuf;100 int err;101 102 if (!lmem)103 return 0;104 105 force_different_devices = true;106 107 obj = __i915_gem_object_create_user(i915, PAGE_SIZE, &lmem, 1);108 if (IS_ERR(obj)) {109 pr_err("__i915_gem_object_create_user failed with err=%ld\n",110 PTR_ERR(obj));111 err = PTR_ERR(obj);112 goto out_ret;113 }114 115 dmabuf = i915_gem_prime_export(&obj->base, 0);116 if (IS_ERR(dmabuf)) {117 pr_err("i915_gem_prime_export failed with err=%ld\n",118 PTR_ERR(dmabuf));119 err = PTR_ERR(dmabuf);120 goto out;121 }122 123 /*124 * We expect an import of an LMEM-only object to fail with125 * -EOPNOTSUPP because it can't be migrated to SMEM.126 */127 import = i915_gem_prime_import(&i915->drm, dmabuf);128 if (!IS_ERR(import)) {129 drm_gem_object_put(import);130 pr_err("i915_gem_prime_import succeeded when it shouldn't have\n");131 err = -EINVAL;132 } else if (PTR_ERR(import) != -EOPNOTSUPP) {133 pr_err("i915_gem_prime_import failed with the wrong err=%ld\n",134 PTR_ERR(import));135 err = PTR_ERR(import);136 } else {137 err = 0;138 }139 140 dma_buf_put(dmabuf);141out:142 i915_gem_object_put(obj);143out_ret:144 force_different_devices = false;145 return err;146}147 148static int verify_access(struct drm_i915_private *i915,149 struct drm_i915_gem_object *native_obj,150 struct drm_i915_gem_object *import_obj)151{152 struct i915_gem_engines_iter it;153 struct i915_gem_context *ctx;154 struct intel_context *ce;155 struct i915_vma *vma;156 struct file *file;157 u32 *vaddr;158 int err = 0, i;159 unsigned int mode;160 161 file = mock_file(i915);162 if (IS_ERR(file))163 return PTR_ERR(file);164 165 ctx = live_context(i915, file);166 if (IS_ERR(ctx)) {167 err = PTR_ERR(ctx);168 goto out_file;169 }170 171 for_each_gem_engine(ce, i915_gem_context_lock_engines(ctx), it) {172 if (intel_engine_can_store_dword(ce->engine))173 break;174 }175 i915_gem_context_unlock_engines(ctx);176 if (!ce)177 goto out_file;178 179 vma = i915_vma_instance(import_obj, ce->vm, NULL);180 if (IS_ERR(vma)) {181 err = PTR_ERR(vma);182 goto out_file;183 }184 185 err = i915_vma_pin(vma, 0, 0, PIN_USER);186 if (err)187 goto out_file;188 189 err = igt_gpu_fill_dw(ce, vma, 0,190 vma->size >> PAGE_SHIFT, 0xdeadbeaf);191 i915_vma_unpin(vma);192 if (err)193 goto out_file;194 195 err = i915_gem_object_wait(import_obj, 0, MAX_SCHEDULE_TIMEOUT);196 if (err)197 goto out_file;198 199 mode = intel_gt_coherent_map_type(to_gt(i915), native_obj, false);200 vaddr = i915_gem_object_pin_map_unlocked(native_obj, mode);201 if (IS_ERR(vaddr)) {202 err = PTR_ERR(vaddr);203 goto out_file;204 }205 206 for (i = 0; i < native_obj->base.size / sizeof(u32); i += PAGE_SIZE / sizeof(u32)) {207 if (vaddr[i] != 0xdeadbeaf) {208 pr_err("Data mismatch [%d]=%u\n", i, vaddr[i]);209 err = -EINVAL;210 goto out_file;211 }212 }213 214out_file:215 fput(file);216 return err;217}218 219static int igt_dmabuf_import_same_driver(struct drm_i915_private *i915,220 struct intel_memory_region **regions,221 unsigned int num_regions)222{223 struct drm_i915_gem_object *obj, *import_obj;224 struct drm_gem_object *import;225 struct dma_buf *dmabuf;226 struct dma_buf_attachment *import_attach;227 struct sg_table *st;228 long timeout;229 int err;230 231 force_different_devices = true;232 233 obj = __i915_gem_object_create_user(i915, SZ_8M,234 regions, num_regions);235 if (IS_ERR(obj)) {236 pr_err("__i915_gem_object_create_user failed with err=%ld\n",237 PTR_ERR(obj));238 err = PTR_ERR(obj);239 goto out_ret;240 }241 242 dmabuf = i915_gem_prime_export(&obj->base, 0);243 if (IS_ERR(dmabuf)) {244 pr_err("i915_gem_prime_export failed with err=%ld\n",245 PTR_ERR(dmabuf));246 err = PTR_ERR(dmabuf);247 goto out;248 }249 250 import = i915_gem_prime_import(&i915->drm, dmabuf);251 if (IS_ERR(import)) {252 pr_err("i915_gem_prime_import failed with err=%ld\n",253 PTR_ERR(import));254 err = PTR_ERR(import);255 goto out_dmabuf;256 }257 import_obj = to_intel_bo(import);258 259 if (import == &obj->base) {260 pr_err("i915_gem_prime_import reused gem object!\n");261 err = -EINVAL;262 goto out_import;263 }264 265 i915_gem_object_lock(import_obj, NULL);266 err = __i915_gem_object_get_pages(import_obj);267 if (err) {268 pr_err("Different objects dma-buf get_pages failed!\n");269 i915_gem_object_unlock(import_obj);270 goto out_import;271 }272 273 /*274 * If the exported object is not in system memory, something275 * weird is going on. TODO: When p2p is supported, this is no276 * longer considered weird.277 */278 if (obj->mm.region != i915->mm.regions[INTEL_REGION_SMEM]) {279 pr_err("Exported dma-buf is not in system memory\n");280 err = -EINVAL;281 }282 283 i915_gem_object_unlock(import_obj);284 285 err = verify_access(i915, obj, import_obj);286 if (err)287 goto out_import;288 289 /* Now try a fake an importer */290 import_attach = dma_buf_attach(dmabuf, obj->base.dev->dev);291 if (IS_ERR(import_attach)) {292 err = PTR_ERR(import_attach);293 goto out_import;294 }295 296 st = dma_buf_map_attachment_unlocked(import_attach, DMA_BIDIRECTIONAL);297 if (IS_ERR(st)) {298 err = PTR_ERR(st);299 goto out_detach;300 }301 302 timeout = dma_resv_wait_timeout(dmabuf->resv, DMA_RESV_USAGE_WRITE,303 true, 5 * HZ);304 if (!timeout) {305 pr_err("dmabuf wait for exclusive fence timed out.\n");306 timeout = -ETIME;307 }308 err = timeout > 0 ? 0 : timeout;309 dma_buf_unmap_attachment_unlocked(import_attach, st, DMA_BIDIRECTIONAL);310out_detach:311 dma_buf_detach(dmabuf, import_attach);312out_import:313 i915_gem_object_put(import_obj);314out_dmabuf:315 dma_buf_put(dmabuf);316out:317 i915_gem_object_put(obj);318out_ret:319 force_different_devices = false;320 return err;321}322 323static int igt_dmabuf_import_same_driver_smem(void *arg)324{325 struct drm_i915_private *i915 = arg;326 struct intel_memory_region *smem = i915->mm.regions[INTEL_REGION_SMEM];327 328 return igt_dmabuf_import_same_driver(i915, &smem, 1);329}330 331static int igt_dmabuf_import_same_driver_lmem_smem(void *arg)332{333 struct drm_i915_private *i915 = arg;334 struct intel_memory_region *regions[2];335 336 if (!i915->mm.regions[INTEL_REGION_LMEM_0])337 return 0;338 339 regions[0] = i915->mm.regions[INTEL_REGION_LMEM_0];340 regions[1] = i915->mm.regions[INTEL_REGION_SMEM];341 return igt_dmabuf_import_same_driver(i915, regions, 2);342}343 344static int igt_dmabuf_import(void *arg)345{346 struct drm_i915_private *i915 = arg;347 struct drm_i915_gem_object *obj;348 struct dma_buf *dmabuf;349 void *obj_map, *dma_map;350 struct iosys_map map;351 u32 pattern[] = { 0, 0xaa, 0xcc, 0x55, 0xff };352 int err, i;353 354 dmabuf = mock_dmabuf(1);355 if (IS_ERR(dmabuf))356 return PTR_ERR(dmabuf);357 358 obj = to_intel_bo(i915_gem_prime_import(&i915->drm, dmabuf));359 if (IS_ERR(obj)) {360 pr_err("i915_gem_prime_import failed with err=%d\n",361 (int)PTR_ERR(obj));362 err = PTR_ERR(obj);363 goto out_dmabuf;364 }365 366 if (obj->base.dev != &i915->drm) {367 pr_err("i915_gem_prime_import created a non-i915 object!\n");368 err = -EINVAL;369 goto out_obj;370 }371 372 if (obj->base.size != PAGE_SIZE) {373 pr_err("i915_gem_prime_import is wrong size found %lld, expected %ld\n",374 (long long)obj->base.size, PAGE_SIZE);375 err = -EINVAL;376 goto out_obj;377 }378 379 err = dma_buf_vmap_unlocked(dmabuf, &map);380 dma_map = err ? NULL : map.vaddr;381 if (!dma_map) {382 pr_err("dma_buf_vmap failed\n");383 err = -ENOMEM;384 goto out_obj;385 }386 387 if (0) { /* Can not yet map dmabuf */388 obj_map = i915_gem_object_pin_map(obj, I915_MAP_WB);389 if (IS_ERR(obj_map)) {390 err = PTR_ERR(obj_map);391 pr_err("i915_gem_object_pin_map failed with err=%d\n", err);392 goto out_dma_map;393 }394 395 for (i = 0; i < ARRAY_SIZE(pattern); i++) {396 memset(dma_map, pattern[i], PAGE_SIZE);397 if (memchr_inv(obj_map, pattern[i], PAGE_SIZE)) {398 err = -EINVAL;399 pr_err("imported vmap not all set to %x!\n", pattern[i]);400 i915_gem_object_unpin_map(obj);401 goto out_dma_map;402 }403 }404 405 for (i = 0; i < ARRAY_SIZE(pattern); i++) {406 memset(obj_map, pattern[i], PAGE_SIZE);407 if (memchr_inv(dma_map, pattern[i], PAGE_SIZE)) {408 err = -EINVAL;409 pr_err("exported vmap not all set to %x!\n", pattern[i]);410 i915_gem_object_unpin_map(obj);411 goto out_dma_map;412 }413 }414 415 i915_gem_object_unpin_map(obj);416 }417 418 err = 0;419out_dma_map:420 dma_buf_vunmap_unlocked(dmabuf, &map);421out_obj:422 i915_gem_object_put(obj);423out_dmabuf:424 dma_buf_put(dmabuf);425 return err;426}427 428static int igt_dmabuf_import_ownership(void *arg)429{430 struct drm_i915_private *i915 = arg;431 struct drm_i915_gem_object *obj;432 struct dma_buf *dmabuf;433 struct iosys_map map;434 void *ptr;435 int err;436 437 dmabuf = mock_dmabuf(1);438 if (IS_ERR(dmabuf))439 return PTR_ERR(dmabuf);440 441 err = dma_buf_vmap_unlocked(dmabuf, &map);442 ptr = err ? NULL : map.vaddr;443 if (!ptr) {444 pr_err("dma_buf_vmap failed\n");445 err = -ENOMEM;446 goto err_dmabuf;447 }448 449 memset(ptr, 0xc5, PAGE_SIZE);450 dma_buf_vunmap_unlocked(dmabuf, &map);451 452 obj = to_intel_bo(i915_gem_prime_import(&i915->drm, dmabuf));453 if (IS_ERR(obj)) {454 pr_err("i915_gem_prime_import failed with err=%d\n",455 (int)PTR_ERR(obj));456 err = PTR_ERR(obj);457 goto err_dmabuf;458 }459 460 dma_buf_put(dmabuf);461 462 err = i915_gem_object_pin_pages_unlocked(obj);463 if (err) {464 pr_err("i915_gem_object_pin_pages failed with err=%d\n", err);465 goto out_obj;466 }467 468 err = 0;469 i915_gem_object_unpin_pages(obj);470out_obj:471 i915_gem_object_put(obj);472 return err;473 474err_dmabuf:475 dma_buf_put(dmabuf);476 return err;477}478 479static int igt_dmabuf_export_vmap(void *arg)480{481 struct drm_i915_private *i915 = arg;482 struct drm_i915_gem_object *obj;483 struct dma_buf *dmabuf;484 struct iosys_map map;485 void *ptr;486 int err;487 488 obj = i915_gem_object_create_shmem(i915, PAGE_SIZE);489 if (IS_ERR(obj))490 return PTR_ERR(obj);491 492 dmabuf = i915_gem_prime_export(&obj->base, 0);493 if (IS_ERR(dmabuf)) {494 pr_err("i915_gem_prime_export failed with err=%d\n",495 (int)PTR_ERR(dmabuf));496 err = PTR_ERR(dmabuf);497 goto err_obj;498 }499 i915_gem_object_put(obj);500 501 err = dma_buf_vmap_unlocked(dmabuf, &map);502 ptr = err ? NULL : map.vaddr;503 if (!ptr) {504 pr_err("dma_buf_vmap failed\n");505 err = -ENOMEM;506 goto out;507 }508 509 if (!mem_is_zero(ptr, dmabuf->size)) {510 pr_err("Exported object not initialised to zero!\n");511 err = -EINVAL;512 goto out;513 }514 515 memset(ptr, 0xc5, dmabuf->size);516 517 err = 0;518 dma_buf_vunmap_unlocked(dmabuf, &map);519out:520 dma_buf_put(dmabuf);521 return err;522 523err_obj:524 i915_gem_object_put(obj);525 return err;526}527 528int i915_gem_dmabuf_mock_selftests(void)529{530 static const struct i915_subtest tests[] = {531 SUBTEST(igt_dmabuf_export),532 SUBTEST(igt_dmabuf_import_self),533 SUBTEST(igt_dmabuf_import),534 SUBTEST(igt_dmabuf_import_ownership),535 SUBTEST(igt_dmabuf_export_vmap),536 };537 struct drm_i915_private *i915;538 int err;539 540 i915 = mock_gem_device();541 if (!i915)542 return -ENOMEM;543 544 err = i915_subtests(tests, i915);545 546 mock_destroy_device(i915);547 return err;548}549 550int i915_gem_dmabuf_live_selftests(struct drm_i915_private *i915)551{552 static const struct i915_subtest tests[] = {553 SUBTEST(igt_dmabuf_export),554 SUBTEST(igt_dmabuf_import_same_driver_lmem),555 SUBTEST(igt_dmabuf_import_same_driver_smem),556 SUBTEST(igt_dmabuf_import_same_driver_lmem_smem),557 };558 559 return i915_live_subtests(tests, i915);560}561