18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * SPDX-License-Identifier: MIT 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright © 2018 Intel Corporation 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include <linux/random.h> 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include "gem/selftests/igt_gem_utils.h" 108c2ecf20Sopenharmony_ci#include "gem/selftests/mock_context.h" 118c2ecf20Sopenharmony_ci#include "gt/intel_gt.h" 128c2ecf20Sopenharmony_ci#include "gt/intel_gt_pm.h" 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#include "i915_selftest.h" 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#include "igt_flush_test.h" 178c2ecf20Sopenharmony_ci#include "mock_drm.h" 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_cistatic int switch_to_context(struct i915_gem_context *ctx) 208c2ecf20Sopenharmony_ci{ 218c2ecf20Sopenharmony_ci struct i915_gem_engines_iter it; 228c2ecf20Sopenharmony_ci struct intel_context *ce; 238c2ecf20Sopenharmony_ci int err = 0; 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci for_each_gem_engine(ce, i915_gem_context_lock_engines(ctx), it) { 268c2ecf20Sopenharmony_ci struct i915_request *rq; 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci rq = intel_context_create_request(ce); 298c2ecf20Sopenharmony_ci if (IS_ERR(rq)) { 308c2ecf20Sopenharmony_ci err = PTR_ERR(rq); 318c2ecf20Sopenharmony_ci break; 328c2ecf20Sopenharmony_ci } 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci i915_request_add(rq); 358c2ecf20Sopenharmony_ci } 368c2ecf20Sopenharmony_ci i915_gem_context_unlock_engines(ctx); 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci return err; 398c2ecf20Sopenharmony_ci} 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_cistatic void trash_stolen(struct drm_i915_private *i915) 428c2ecf20Sopenharmony_ci{ 438c2ecf20Sopenharmony_ci struct i915_ggtt *ggtt = &i915->ggtt; 448c2ecf20Sopenharmony_ci const u64 slot = ggtt->error_capture.start; 458c2ecf20Sopenharmony_ci const resource_size_t size = resource_size(&i915->dsm); 468c2ecf20Sopenharmony_ci unsigned long page; 478c2ecf20Sopenharmony_ci u32 prng = 0x12345678; 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci /* XXX: fsck. needs some more thought... */ 508c2ecf20Sopenharmony_ci if (!i915_ggtt_has_aperture(ggtt)) 518c2ecf20Sopenharmony_ci return; 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci for (page = 0; page < size; page += PAGE_SIZE) { 548c2ecf20Sopenharmony_ci const dma_addr_t dma = i915->dsm.start + page; 558c2ecf20Sopenharmony_ci u32 __iomem *s; 568c2ecf20Sopenharmony_ci int x; 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci ggtt->vm.insert_page(&ggtt->vm, dma, slot, I915_CACHE_NONE, 0); 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci s = io_mapping_map_atomic_wc(&ggtt->iomap, slot); 618c2ecf20Sopenharmony_ci for (x = 0; x < PAGE_SIZE / sizeof(u32); x++) { 628c2ecf20Sopenharmony_ci prng = next_pseudo_random32(prng); 638c2ecf20Sopenharmony_ci iowrite32(prng, &s[x]); 648c2ecf20Sopenharmony_ci } 658c2ecf20Sopenharmony_ci io_mapping_unmap_atomic(s); 668c2ecf20Sopenharmony_ci } 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci ggtt->vm.clear_range(&ggtt->vm, slot, PAGE_SIZE); 698c2ecf20Sopenharmony_ci} 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_cistatic void simulate_hibernate(struct drm_i915_private *i915) 728c2ecf20Sopenharmony_ci{ 738c2ecf20Sopenharmony_ci intel_wakeref_t wakeref; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci wakeref = intel_runtime_pm_get(&i915->runtime_pm); 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci /* 788c2ecf20Sopenharmony_ci * As a final sting in the tail, invalidate stolen. Under a real S4, 798c2ecf20Sopenharmony_ci * stolen is lost and needs to be refilled on resume. However, under 808c2ecf20Sopenharmony_ci * CI we merely do S4-device testing (as full S4 is too unreliable 818c2ecf20Sopenharmony_ci * for automated testing across a cluster), so to simulate the effect 828c2ecf20Sopenharmony_ci * of stolen being trashed across S4, we trash it ourselves. 838c2ecf20Sopenharmony_ci */ 848c2ecf20Sopenharmony_ci trash_stolen(i915); 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci intel_runtime_pm_put(&i915->runtime_pm, wakeref); 878c2ecf20Sopenharmony_ci} 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_cistatic int pm_prepare(struct drm_i915_private *i915) 908c2ecf20Sopenharmony_ci{ 918c2ecf20Sopenharmony_ci i915_gem_suspend(i915); 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci return 0; 948c2ecf20Sopenharmony_ci} 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_cistatic void pm_suspend(struct drm_i915_private *i915) 978c2ecf20Sopenharmony_ci{ 988c2ecf20Sopenharmony_ci intel_wakeref_t wakeref; 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci with_intel_runtime_pm(&i915->runtime_pm, wakeref) { 1018c2ecf20Sopenharmony_ci i915_ggtt_suspend(&i915->ggtt); 1028c2ecf20Sopenharmony_ci i915_gem_suspend_late(i915); 1038c2ecf20Sopenharmony_ci } 1048c2ecf20Sopenharmony_ci} 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_cistatic void pm_hibernate(struct drm_i915_private *i915) 1078c2ecf20Sopenharmony_ci{ 1088c2ecf20Sopenharmony_ci intel_wakeref_t wakeref; 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci with_intel_runtime_pm(&i915->runtime_pm, wakeref) { 1118c2ecf20Sopenharmony_ci i915_ggtt_suspend(&i915->ggtt); 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci i915_gem_freeze(i915); 1148c2ecf20Sopenharmony_ci i915_gem_freeze_late(i915); 1158c2ecf20Sopenharmony_ci } 1168c2ecf20Sopenharmony_ci} 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_cistatic void pm_resume(struct drm_i915_private *i915) 1198c2ecf20Sopenharmony_ci{ 1208c2ecf20Sopenharmony_ci intel_wakeref_t wakeref; 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci /* 1238c2ecf20Sopenharmony_ci * Both suspend and hibernate follow the same wakeup path and assume 1248c2ecf20Sopenharmony_ci * that runtime-pm just works. 1258c2ecf20Sopenharmony_ci */ 1268c2ecf20Sopenharmony_ci with_intel_runtime_pm(&i915->runtime_pm, wakeref) { 1278c2ecf20Sopenharmony_ci i915_ggtt_resume(&i915->ggtt); 1288c2ecf20Sopenharmony_ci i915_gem_resume(i915); 1298c2ecf20Sopenharmony_ci } 1308c2ecf20Sopenharmony_ci} 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_cistatic int igt_gem_suspend(void *arg) 1338c2ecf20Sopenharmony_ci{ 1348c2ecf20Sopenharmony_ci struct drm_i915_private *i915 = arg; 1358c2ecf20Sopenharmony_ci struct i915_gem_context *ctx; 1368c2ecf20Sopenharmony_ci struct file *file; 1378c2ecf20Sopenharmony_ci int err; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci file = mock_file(i915); 1408c2ecf20Sopenharmony_ci if (IS_ERR(file)) 1418c2ecf20Sopenharmony_ci return PTR_ERR(file); 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci err = -ENOMEM; 1448c2ecf20Sopenharmony_ci ctx = live_context(i915, file); 1458c2ecf20Sopenharmony_ci if (!IS_ERR(ctx)) 1468c2ecf20Sopenharmony_ci err = switch_to_context(ctx); 1478c2ecf20Sopenharmony_ci if (err) 1488c2ecf20Sopenharmony_ci goto out; 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci err = pm_prepare(i915); 1518c2ecf20Sopenharmony_ci if (err) 1528c2ecf20Sopenharmony_ci goto out; 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci pm_suspend(i915); 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci /* Here be dragons! Note that with S3RST any S3 may become S4! */ 1578c2ecf20Sopenharmony_ci simulate_hibernate(i915); 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci pm_resume(i915); 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci err = switch_to_context(ctx); 1628c2ecf20Sopenharmony_ciout: 1638c2ecf20Sopenharmony_ci fput(file); 1648c2ecf20Sopenharmony_ci return err; 1658c2ecf20Sopenharmony_ci} 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_cistatic int igt_gem_hibernate(void *arg) 1688c2ecf20Sopenharmony_ci{ 1698c2ecf20Sopenharmony_ci struct drm_i915_private *i915 = arg; 1708c2ecf20Sopenharmony_ci struct i915_gem_context *ctx; 1718c2ecf20Sopenharmony_ci struct file *file; 1728c2ecf20Sopenharmony_ci int err; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci file = mock_file(i915); 1758c2ecf20Sopenharmony_ci if (IS_ERR(file)) 1768c2ecf20Sopenharmony_ci return PTR_ERR(file); 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci err = -ENOMEM; 1798c2ecf20Sopenharmony_ci ctx = live_context(i915, file); 1808c2ecf20Sopenharmony_ci if (!IS_ERR(ctx)) 1818c2ecf20Sopenharmony_ci err = switch_to_context(ctx); 1828c2ecf20Sopenharmony_ci if (err) 1838c2ecf20Sopenharmony_ci goto out; 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci err = pm_prepare(i915); 1868c2ecf20Sopenharmony_ci if (err) 1878c2ecf20Sopenharmony_ci goto out; 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci pm_hibernate(i915); 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci /* Here be dragons! */ 1928c2ecf20Sopenharmony_ci simulate_hibernate(i915); 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci pm_resume(i915); 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci err = switch_to_context(ctx); 1978c2ecf20Sopenharmony_ciout: 1988c2ecf20Sopenharmony_ci fput(file); 1998c2ecf20Sopenharmony_ci return err; 2008c2ecf20Sopenharmony_ci} 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_cistatic int igt_gem_ww_ctx(void *arg) 2038c2ecf20Sopenharmony_ci{ 2048c2ecf20Sopenharmony_ci struct drm_i915_private *i915 = arg; 2058c2ecf20Sopenharmony_ci struct drm_i915_gem_object *obj, *obj2; 2068c2ecf20Sopenharmony_ci struct i915_gem_ww_ctx ww; 2078c2ecf20Sopenharmony_ci int err = 0; 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci obj = i915_gem_object_create_internal(i915, PAGE_SIZE); 2108c2ecf20Sopenharmony_ci if (IS_ERR(obj)) 2118c2ecf20Sopenharmony_ci return PTR_ERR(obj); 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci obj2 = i915_gem_object_create_internal(i915, PAGE_SIZE); 2148c2ecf20Sopenharmony_ci if (IS_ERR(obj2)) { 2158c2ecf20Sopenharmony_ci err = PTR_ERR(obj2); 2168c2ecf20Sopenharmony_ci goto put1; 2178c2ecf20Sopenharmony_ci } 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci i915_gem_ww_ctx_init(&ww, true); 2208c2ecf20Sopenharmony_ciretry: 2218c2ecf20Sopenharmony_ci /* Lock the objects, twice for good measure (-EALREADY handling) */ 2228c2ecf20Sopenharmony_ci err = i915_gem_object_lock(obj, &ww); 2238c2ecf20Sopenharmony_ci if (!err) 2248c2ecf20Sopenharmony_ci err = i915_gem_object_lock_interruptible(obj, &ww); 2258c2ecf20Sopenharmony_ci if (!err) 2268c2ecf20Sopenharmony_ci err = i915_gem_object_lock_interruptible(obj2, &ww); 2278c2ecf20Sopenharmony_ci if (!err) 2288c2ecf20Sopenharmony_ci err = i915_gem_object_lock(obj2, &ww); 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci if (err == -EDEADLK) { 2318c2ecf20Sopenharmony_ci err = i915_gem_ww_ctx_backoff(&ww); 2328c2ecf20Sopenharmony_ci if (!err) 2338c2ecf20Sopenharmony_ci goto retry; 2348c2ecf20Sopenharmony_ci } 2358c2ecf20Sopenharmony_ci i915_gem_ww_ctx_fini(&ww); 2368c2ecf20Sopenharmony_ci i915_gem_object_put(obj2); 2378c2ecf20Sopenharmony_ciput1: 2388c2ecf20Sopenharmony_ci i915_gem_object_put(obj); 2398c2ecf20Sopenharmony_ci return err; 2408c2ecf20Sopenharmony_ci} 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ciint i915_gem_live_selftests(struct drm_i915_private *i915) 2438c2ecf20Sopenharmony_ci{ 2448c2ecf20Sopenharmony_ci static const struct i915_subtest tests[] = { 2458c2ecf20Sopenharmony_ci SUBTEST(igt_gem_suspend), 2468c2ecf20Sopenharmony_ci SUBTEST(igt_gem_hibernate), 2478c2ecf20Sopenharmony_ci SUBTEST(igt_gem_ww_ctx), 2488c2ecf20Sopenharmony_ci }; 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci if (intel_gt_is_wedged(&i915->gt)) 2518c2ecf20Sopenharmony_ci return 0; 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci return i915_live_subtests(tests, i915); 2548c2ecf20Sopenharmony_ci} 255