13f51b7e1SChris Wilson /* 23f51b7e1SChris Wilson * SPDX-License-Identifier: MIT 33f51b7e1SChris Wilson * 43f51b7e1SChris Wilson * Copyright © 2018 Intel Corporation 53f51b7e1SChris Wilson */ 63f51b7e1SChris Wilson 73f51b7e1SChris Wilson #include <linux/random.h> 83f51b7e1SChris Wilson 910be98a7SChris Wilson #include "gem/selftests/igt_gem_utils.h" 1010be98a7SChris Wilson #include "gem/selftests/mock_context.h" 1129d88083SChris Wilson #include "gem/i915_gem_pm.h" 12cb823ed9SChris Wilson #include "gt/intel_gt.h" 13e26b6d43SChris Wilson #include "gt/intel_gt_pm.h" 143f51b7e1SChris Wilson 1510be98a7SChris Wilson #include "i915_selftest.h" 1610be98a7SChris Wilson 173f51b7e1SChris Wilson #include "igt_flush_test.h" 1810be98a7SChris Wilson #include "mock_drm.h" 193f51b7e1SChris Wilson 20c31c9e82SChris Wilson static int switch_to_context(struct i915_gem_context *ctx) 213f51b7e1SChris Wilson { 22c31c9e82SChris Wilson struct i915_gem_engines_iter it; 23c31c9e82SChris Wilson struct intel_context *ce; 24e16302cbSChris Wilson int err = 0; 253f51b7e1SChris Wilson 26c31c9e82SChris Wilson for_each_gem_engine(ce, i915_gem_context_lock_engines(ctx), it) { 273f51b7e1SChris Wilson struct i915_request *rq; 283f51b7e1SChris Wilson 29c31c9e82SChris Wilson rq = intel_context_create_request(ce); 30e16302cbSChris Wilson if (IS_ERR(rq)) { 31e16302cbSChris Wilson err = PTR_ERR(rq); 32e16302cbSChris Wilson break; 33e16302cbSChris Wilson } 343f51b7e1SChris Wilson 353f51b7e1SChris Wilson i915_request_add(rq); 363f51b7e1SChris Wilson } 37e16302cbSChris Wilson i915_gem_context_unlock_engines(ctx); 383f51b7e1SChris Wilson 39e16302cbSChris Wilson return err; 403f51b7e1SChris Wilson } 413f51b7e1SChris Wilson 423f51b7e1SChris Wilson static void trash_stolen(struct drm_i915_private *i915) 433f51b7e1SChris Wilson { 44*17190a34SMichał Winiarski struct i915_ggtt *ggtt = to_gt(i915)->ggtt; 453f51b7e1SChris Wilson const u64 slot = ggtt->error_capture.start; 463f51b7e1SChris Wilson const resource_size_t size = resource_size(&i915->dsm); 473f51b7e1SChris Wilson unsigned long page; 483f51b7e1SChris Wilson u32 prng = 0x12345678; 493f51b7e1SChris Wilson 50e60f7bb7SMatthew Auld /* XXX: fsck. needs some more thought... */ 51e60f7bb7SMatthew Auld if (!i915_ggtt_has_aperture(ggtt)) 52e60f7bb7SMatthew Auld return; 53e60f7bb7SMatthew Auld 543f51b7e1SChris Wilson for (page = 0; page < size; page += PAGE_SIZE) { 553f51b7e1SChris Wilson const dma_addr_t dma = i915->dsm.start + page; 563f51b7e1SChris Wilson u32 __iomem *s; 573f51b7e1SChris Wilson int x; 583f51b7e1SChris Wilson 593f51b7e1SChris Wilson ggtt->vm.insert_page(&ggtt->vm, dma, slot, I915_CACHE_NONE, 0); 603f51b7e1SChris Wilson 613f51b7e1SChris Wilson s = io_mapping_map_atomic_wc(&ggtt->iomap, slot); 623f51b7e1SChris Wilson for (x = 0; x < PAGE_SIZE / sizeof(u32); x++) { 633f51b7e1SChris Wilson prng = next_pseudo_random32(prng); 643f51b7e1SChris Wilson iowrite32(prng, &s[x]); 653f51b7e1SChris Wilson } 663f51b7e1SChris Wilson io_mapping_unmap_atomic(s); 673f51b7e1SChris Wilson } 683f51b7e1SChris Wilson 693f51b7e1SChris Wilson ggtt->vm.clear_range(&ggtt->vm, slot, PAGE_SIZE); 703f51b7e1SChris Wilson } 713f51b7e1SChris Wilson 723f51b7e1SChris Wilson static void simulate_hibernate(struct drm_i915_private *i915) 733f51b7e1SChris Wilson { 74c9d08cc3SChris Wilson intel_wakeref_t wakeref; 75c9d08cc3SChris Wilson 76d858d569SDaniele Ceraolo Spurio wakeref = intel_runtime_pm_get(&i915->runtime_pm); 773f51b7e1SChris Wilson 783f51b7e1SChris Wilson /* 793f51b7e1SChris Wilson * As a final sting in the tail, invalidate stolen. Under a real S4, 803f51b7e1SChris Wilson * stolen is lost and needs to be refilled on resume. However, under 813f51b7e1SChris Wilson * CI we merely do S4-device testing (as full S4 is too unreliable 823f51b7e1SChris Wilson * for automated testing across a cluster), so to simulate the effect 833f51b7e1SChris Wilson * of stolen being trashed across S4, we trash it ourselves. 843f51b7e1SChris Wilson */ 853f51b7e1SChris Wilson trash_stolen(i915); 863f51b7e1SChris Wilson 87d858d569SDaniele Ceraolo Spurio intel_runtime_pm_put(&i915->runtime_pm, wakeref); 883f51b7e1SChris Wilson } 893f51b7e1SChris Wilson 905b117056SHsin-Yi Wang static int igt_pm_prepare(struct drm_i915_private *i915) 913f51b7e1SChris Wilson { 925861b013SChris Wilson i915_gem_suspend(i915); 933f51b7e1SChris Wilson 945861b013SChris Wilson return 0; 953f51b7e1SChris Wilson } 963f51b7e1SChris Wilson 975b117056SHsin-Yi Wang static void igt_pm_suspend(struct drm_i915_private *i915) 983f51b7e1SChris Wilson { 99c9d08cc3SChris Wilson intel_wakeref_t wakeref; 100c9d08cc3SChris Wilson 101c447ff7dSDaniele Ceraolo Spurio with_intel_runtime_pm(&i915->runtime_pm, wakeref) { 102*17190a34SMichał Winiarski i915_ggtt_suspend(to_gt(i915)->ggtt); 1033f51b7e1SChris Wilson i915_gem_suspend_late(i915); 104d4225a53SChris Wilson } 1053f51b7e1SChris Wilson } 1063f51b7e1SChris Wilson 1075b117056SHsin-Yi Wang static void igt_pm_hibernate(struct drm_i915_private *i915) 1083f51b7e1SChris Wilson { 109c9d08cc3SChris Wilson intel_wakeref_t wakeref; 110c9d08cc3SChris Wilson 111c447ff7dSDaniele Ceraolo Spurio with_intel_runtime_pm(&i915->runtime_pm, wakeref) { 112*17190a34SMichał Winiarski i915_ggtt_suspend(to_gt(i915)->ggtt); 1133f51b7e1SChris Wilson 1143f51b7e1SChris Wilson i915_gem_freeze(i915); 1153f51b7e1SChris Wilson i915_gem_freeze_late(i915); 116d4225a53SChris Wilson } 1173f51b7e1SChris Wilson } 1183f51b7e1SChris Wilson 1195b117056SHsin-Yi Wang static void igt_pm_resume(struct drm_i915_private *i915) 1203f51b7e1SChris Wilson { 121c9d08cc3SChris Wilson intel_wakeref_t wakeref; 122c9d08cc3SChris Wilson 1233f51b7e1SChris Wilson /* 1243f51b7e1SChris Wilson * Both suspend and hibernate follow the same wakeup path and assume 1253f51b7e1SChris Wilson * that runtime-pm just works. 1263f51b7e1SChris Wilson */ 127c447ff7dSDaniele Ceraolo Spurio with_intel_runtime_pm(&i915->runtime_pm, wakeref) { 128*17190a34SMichał Winiarski i915_ggtt_resume(to_gt(i915)->ggtt); 1293f51b7e1SChris Wilson i915_gem_resume(i915); 130d4225a53SChris Wilson } 1313f51b7e1SChris Wilson } 1323f51b7e1SChris Wilson 1333f51b7e1SChris Wilson static int igt_gem_suspend(void *arg) 1343f51b7e1SChris Wilson { 1353f51b7e1SChris Wilson struct drm_i915_private *i915 = arg; 1363f51b7e1SChris Wilson struct i915_gem_context *ctx; 137a8c9a7f5SChris Wilson struct file *file; 1383f51b7e1SChris Wilson int err; 1393f51b7e1SChris Wilson 1403f51b7e1SChris Wilson file = mock_file(i915); 1413f51b7e1SChris Wilson if (IS_ERR(file)) 1423f51b7e1SChris Wilson return PTR_ERR(file); 1433f51b7e1SChris Wilson 1443f51b7e1SChris Wilson err = -ENOMEM; 1453f51b7e1SChris Wilson ctx = live_context(i915, file); 1463f51b7e1SChris Wilson if (!IS_ERR(ctx)) 147c31c9e82SChris Wilson err = switch_to_context(ctx); 1483f51b7e1SChris Wilson if (err) 1493f51b7e1SChris Wilson goto out; 1503f51b7e1SChris Wilson 1515b117056SHsin-Yi Wang err = igt_pm_prepare(i915); 1523f51b7e1SChris Wilson if (err) 1533f51b7e1SChris Wilson goto out; 1543f51b7e1SChris Wilson 1555b117056SHsin-Yi Wang igt_pm_suspend(i915); 1563f51b7e1SChris Wilson 1573f51b7e1SChris Wilson /* Here be dragons! Note that with S3RST any S3 may become S4! */ 1583f51b7e1SChris Wilson simulate_hibernate(i915); 1593f51b7e1SChris Wilson 1605b117056SHsin-Yi Wang igt_pm_resume(i915); 1613f51b7e1SChris Wilson 162c31c9e82SChris Wilson err = switch_to_context(ctx); 1633f51b7e1SChris Wilson out: 164a8c9a7f5SChris Wilson fput(file); 1653f51b7e1SChris Wilson return err; 1663f51b7e1SChris Wilson } 1673f51b7e1SChris Wilson 1683f51b7e1SChris Wilson static int igt_gem_hibernate(void *arg) 1693f51b7e1SChris Wilson { 1703f51b7e1SChris Wilson struct drm_i915_private *i915 = arg; 1713f51b7e1SChris Wilson struct i915_gem_context *ctx; 172a8c9a7f5SChris Wilson struct file *file; 1733f51b7e1SChris Wilson int err; 1743f51b7e1SChris Wilson 1753f51b7e1SChris Wilson file = mock_file(i915); 1763f51b7e1SChris Wilson if (IS_ERR(file)) 1773f51b7e1SChris Wilson return PTR_ERR(file); 1783f51b7e1SChris Wilson 1793f51b7e1SChris Wilson err = -ENOMEM; 1803f51b7e1SChris Wilson ctx = live_context(i915, file); 1813f51b7e1SChris Wilson if (!IS_ERR(ctx)) 182c31c9e82SChris Wilson err = switch_to_context(ctx); 1833f51b7e1SChris Wilson if (err) 1843f51b7e1SChris Wilson goto out; 1853f51b7e1SChris Wilson 1865b117056SHsin-Yi Wang err = igt_pm_prepare(i915); 1873f51b7e1SChris Wilson if (err) 1883f51b7e1SChris Wilson goto out; 1893f51b7e1SChris Wilson 1905b117056SHsin-Yi Wang igt_pm_hibernate(i915); 1913f51b7e1SChris Wilson 1923f51b7e1SChris Wilson /* Here be dragons! */ 1933f51b7e1SChris Wilson simulate_hibernate(i915); 1943f51b7e1SChris Wilson 1955b117056SHsin-Yi Wang igt_pm_resume(i915); 1963f51b7e1SChris Wilson 197c31c9e82SChris Wilson err = switch_to_context(ctx); 1983f51b7e1SChris Wilson out: 199a8c9a7f5SChris Wilson fput(file); 2003f51b7e1SChris Wilson return err; 2013f51b7e1SChris Wilson } 2023f51b7e1SChris Wilson 20380f0b679SMaarten Lankhorst static int igt_gem_ww_ctx(void *arg) 20480f0b679SMaarten Lankhorst { 20580f0b679SMaarten Lankhorst struct drm_i915_private *i915 = arg; 20680f0b679SMaarten Lankhorst struct drm_i915_gem_object *obj, *obj2; 20780f0b679SMaarten Lankhorst struct i915_gem_ww_ctx ww; 20880f0b679SMaarten Lankhorst int err = 0; 20980f0b679SMaarten Lankhorst 21080f0b679SMaarten Lankhorst obj = i915_gem_object_create_internal(i915, PAGE_SIZE); 21180f0b679SMaarten Lankhorst if (IS_ERR(obj)) 21280f0b679SMaarten Lankhorst return PTR_ERR(obj); 21380f0b679SMaarten Lankhorst 21480f0b679SMaarten Lankhorst obj2 = i915_gem_object_create_internal(i915, PAGE_SIZE); 215352ded44SDan Carpenter if (IS_ERR(obj2)) { 216352ded44SDan Carpenter err = PTR_ERR(obj2); 21780f0b679SMaarten Lankhorst goto put1; 21880f0b679SMaarten Lankhorst } 21980f0b679SMaarten Lankhorst 22080f0b679SMaarten Lankhorst i915_gem_ww_ctx_init(&ww, true); 22180f0b679SMaarten Lankhorst retry: 22280f0b679SMaarten Lankhorst /* Lock the objects, twice for good measure (-EALREADY handling) */ 22380f0b679SMaarten Lankhorst err = i915_gem_object_lock(obj, &ww); 22480f0b679SMaarten Lankhorst if (!err) 22580f0b679SMaarten Lankhorst err = i915_gem_object_lock_interruptible(obj, &ww); 22680f0b679SMaarten Lankhorst if (!err) 22780f0b679SMaarten Lankhorst err = i915_gem_object_lock_interruptible(obj2, &ww); 22880f0b679SMaarten Lankhorst if (!err) 22980f0b679SMaarten Lankhorst err = i915_gem_object_lock(obj2, &ww); 23080f0b679SMaarten Lankhorst 23180f0b679SMaarten Lankhorst if (err == -EDEADLK) { 23280f0b679SMaarten Lankhorst err = i915_gem_ww_ctx_backoff(&ww); 23380f0b679SMaarten Lankhorst if (!err) 23480f0b679SMaarten Lankhorst goto retry; 23580f0b679SMaarten Lankhorst } 23680f0b679SMaarten Lankhorst i915_gem_ww_ctx_fini(&ww); 23780f0b679SMaarten Lankhorst i915_gem_object_put(obj2); 23880f0b679SMaarten Lankhorst put1: 23980f0b679SMaarten Lankhorst i915_gem_object_put(obj); 24080f0b679SMaarten Lankhorst return err; 24180f0b679SMaarten Lankhorst } 24280f0b679SMaarten Lankhorst 2433f51b7e1SChris Wilson int i915_gem_live_selftests(struct drm_i915_private *i915) 2443f51b7e1SChris Wilson { 2453f51b7e1SChris Wilson static const struct i915_subtest tests[] = { 2463f51b7e1SChris Wilson SUBTEST(igt_gem_suspend), 2473f51b7e1SChris Wilson SUBTEST(igt_gem_hibernate), 24880f0b679SMaarten Lankhorst SUBTEST(igt_gem_ww_ctx), 2493f51b7e1SChris Wilson }; 2503f51b7e1SChris Wilson 2518c2699faSAndi Shyti if (intel_gt_is_wedged(to_gt(i915))) 2521ab494ccSChris Wilson return 0; 2531ab494ccSChris Wilson 25463251685SChris Wilson return i915_live_subtests(tests, i915); 2553f51b7e1SChris Wilson } 256