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 9b508d01fSJani Nikula #include "gem/i915_gem_internal.h" 10b508d01fSJani Nikula #include "gem/i915_gem_pm.h" 1110be98a7SChris Wilson #include "gem/selftests/igt_gem_utils.h" 1210be98a7SChris Wilson #include "gem/selftests/mock_context.h" 13cb823ed9SChris Wilson #include "gt/intel_gt.h" 14e26b6d43SChris Wilson #include "gt/intel_gt_pm.h" 153f51b7e1SChris Wilson 1610be98a7SChris Wilson #include "i915_selftest.h" 1710be98a7SChris Wilson 183f51b7e1SChris Wilson #include "igt_flush_test.h" 1910be98a7SChris Wilson #include "mock_drm.h" 203f51b7e1SChris Wilson 21c31c9e82SChris Wilson static int switch_to_context(struct i915_gem_context *ctx) 223f51b7e1SChris Wilson { 23c31c9e82SChris Wilson struct i915_gem_engines_iter it; 24c31c9e82SChris Wilson struct intel_context *ce; 25e16302cbSChris Wilson int err = 0; 263f51b7e1SChris Wilson 27c31c9e82SChris Wilson for_each_gem_engine(ce, i915_gem_context_lock_engines(ctx), it) { 283f51b7e1SChris Wilson struct i915_request *rq; 293f51b7e1SChris Wilson 30c31c9e82SChris Wilson rq = intel_context_create_request(ce); 31e16302cbSChris Wilson if (IS_ERR(rq)) { 32e16302cbSChris Wilson err = PTR_ERR(rq); 33e16302cbSChris Wilson break; 34e16302cbSChris Wilson } 353f51b7e1SChris Wilson 363f51b7e1SChris Wilson i915_request_add(rq); 373f51b7e1SChris Wilson } 38e16302cbSChris Wilson i915_gem_context_unlock_engines(ctx); 393f51b7e1SChris Wilson 40e16302cbSChris Wilson return err; 413f51b7e1SChris Wilson } 423f51b7e1SChris Wilson 433f51b7e1SChris Wilson static void trash_stolen(struct drm_i915_private *i915) 443f51b7e1SChris Wilson { 4517190a34SMichał Winiarski struct i915_ggtt *ggtt = to_gt(i915)->ggtt; 463f51b7e1SChris Wilson const u64 slot = ggtt->error_capture.start; 47*1eca0778SJani Nikula const resource_size_t size = resource_size(&i915->dsm.stolen); 483f51b7e1SChris Wilson unsigned long page; 493f51b7e1SChris Wilson u32 prng = 0x12345678; 503f51b7e1SChris Wilson 51e60f7bb7SMatthew Auld /* XXX: fsck. needs some more thought... */ 52e60f7bb7SMatthew Auld if (!i915_ggtt_has_aperture(ggtt)) 53e60f7bb7SMatthew Auld return; 54e60f7bb7SMatthew Auld 553f51b7e1SChris Wilson for (page = 0; page < size; page += PAGE_SIZE) { 56*1eca0778SJani Nikula const dma_addr_t dma = i915->dsm.stolen.start + page; 573f51b7e1SChris Wilson u32 __iomem *s; 583f51b7e1SChris Wilson int x; 593f51b7e1SChris Wilson 603f51b7e1SChris Wilson ggtt->vm.insert_page(&ggtt->vm, dma, slot, I915_CACHE_NONE, 0); 613f51b7e1SChris Wilson 623f51b7e1SChris Wilson s = io_mapping_map_atomic_wc(&ggtt->iomap, slot); 633f51b7e1SChris Wilson for (x = 0; x < PAGE_SIZE / sizeof(u32); x++) { 643f51b7e1SChris Wilson prng = next_pseudo_random32(prng); 653f51b7e1SChris Wilson iowrite32(prng, &s[x]); 663f51b7e1SChris Wilson } 673f51b7e1SChris Wilson io_mapping_unmap_atomic(s); 683f51b7e1SChris Wilson } 693f51b7e1SChris Wilson 703f51b7e1SChris Wilson ggtt->vm.clear_range(&ggtt->vm, slot, PAGE_SIZE); 713f51b7e1SChris Wilson } 723f51b7e1SChris Wilson 733f51b7e1SChris Wilson static void simulate_hibernate(struct drm_i915_private *i915) 743f51b7e1SChris Wilson { 75c9d08cc3SChris Wilson intel_wakeref_t wakeref; 76c9d08cc3SChris Wilson 77d858d569SDaniele Ceraolo Spurio wakeref = intel_runtime_pm_get(&i915->runtime_pm); 783f51b7e1SChris Wilson 793f51b7e1SChris Wilson /* 803f51b7e1SChris Wilson * As a final sting in the tail, invalidate stolen. Under a real S4, 813f51b7e1SChris Wilson * stolen is lost and needs to be refilled on resume. However, under 823f51b7e1SChris Wilson * CI we merely do S4-device testing (as full S4 is too unreliable 833f51b7e1SChris Wilson * for automated testing across a cluster), so to simulate the effect 843f51b7e1SChris Wilson * of stolen being trashed across S4, we trash it ourselves. 853f51b7e1SChris Wilson */ 863f51b7e1SChris Wilson trash_stolen(i915); 873f51b7e1SChris Wilson 88d858d569SDaniele Ceraolo Spurio intel_runtime_pm_put(&i915->runtime_pm, wakeref); 893f51b7e1SChris Wilson } 903f51b7e1SChris Wilson 915b117056SHsin-Yi Wang static int igt_pm_prepare(struct drm_i915_private *i915) 923f51b7e1SChris Wilson { 935861b013SChris Wilson i915_gem_suspend(i915); 943f51b7e1SChris Wilson 955861b013SChris Wilson return 0; 963f51b7e1SChris Wilson } 973f51b7e1SChris Wilson 985b117056SHsin-Yi Wang static void igt_pm_suspend(struct drm_i915_private *i915) 993f51b7e1SChris Wilson { 100c9d08cc3SChris Wilson intel_wakeref_t wakeref; 101c9d08cc3SChris Wilson 102c447ff7dSDaniele Ceraolo Spurio with_intel_runtime_pm(&i915->runtime_pm, wakeref) { 10317190a34SMichał Winiarski i915_ggtt_suspend(to_gt(i915)->ggtt); 1043f51b7e1SChris Wilson i915_gem_suspend_late(i915); 105d4225a53SChris Wilson } 1063f51b7e1SChris Wilson } 1073f51b7e1SChris Wilson 1085b117056SHsin-Yi Wang static void igt_pm_hibernate(struct drm_i915_private *i915) 1093f51b7e1SChris Wilson { 110c9d08cc3SChris Wilson intel_wakeref_t wakeref; 111c9d08cc3SChris Wilson 112c447ff7dSDaniele Ceraolo Spurio with_intel_runtime_pm(&i915->runtime_pm, wakeref) { 11317190a34SMichał Winiarski i915_ggtt_suspend(to_gt(i915)->ggtt); 1143f51b7e1SChris Wilson 1153f51b7e1SChris Wilson i915_gem_freeze(i915); 1163f51b7e1SChris Wilson i915_gem_freeze_late(i915); 117d4225a53SChris Wilson } 1183f51b7e1SChris Wilson } 1193f51b7e1SChris Wilson 1205b117056SHsin-Yi Wang static void igt_pm_resume(struct drm_i915_private *i915) 1213f51b7e1SChris Wilson { 122c9d08cc3SChris Wilson intel_wakeref_t wakeref; 123c9d08cc3SChris Wilson 1243f51b7e1SChris Wilson /* 1253f51b7e1SChris Wilson * Both suspend and hibernate follow the same wakeup path and assume 1263f51b7e1SChris Wilson * that runtime-pm just works. 1273f51b7e1SChris Wilson */ 128c447ff7dSDaniele Ceraolo Spurio with_intel_runtime_pm(&i915->runtime_pm, wakeref) { 12917190a34SMichał Winiarski i915_ggtt_resume(to_gt(i915)->ggtt); 1303f51b7e1SChris Wilson i915_gem_resume(i915); 131d4225a53SChris Wilson } 1323f51b7e1SChris Wilson } 1333f51b7e1SChris Wilson 1343f51b7e1SChris Wilson static int igt_gem_suspend(void *arg) 1353f51b7e1SChris Wilson { 1363f51b7e1SChris Wilson struct drm_i915_private *i915 = arg; 1373f51b7e1SChris Wilson struct i915_gem_context *ctx; 138a8c9a7f5SChris Wilson struct file *file; 1393f51b7e1SChris Wilson int err; 1403f51b7e1SChris Wilson 1413f51b7e1SChris Wilson file = mock_file(i915); 1423f51b7e1SChris Wilson if (IS_ERR(file)) 1433f51b7e1SChris Wilson return PTR_ERR(file); 1443f51b7e1SChris Wilson 1453f51b7e1SChris Wilson err = -ENOMEM; 1463f51b7e1SChris Wilson ctx = live_context(i915, file); 1473f51b7e1SChris Wilson if (!IS_ERR(ctx)) 148c31c9e82SChris Wilson err = switch_to_context(ctx); 1493f51b7e1SChris Wilson if (err) 1503f51b7e1SChris Wilson goto out; 1513f51b7e1SChris Wilson 1525b117056SHsin-Yi Wang err = igt_pm_prepare(i915); 1533f51b7e1SChris Wilson if (err) 1543f51b7e1SChris Wilson goto out; 1553f51b7e1SChris Wilson 1565b117056SHsin-Yi Wang igt_pm_suspend(i915); 1573f51b7e1SChris Wilson 1583f51b7e1SChris Wilson /* Here be dragons! Note that with S3RST any S3 may become S4! */ 1593f51b7e1SChris Wilson simulate_hibernate(i915); 1603f51b7e1SChris Wilson 1615b117056SHsin-Yi Wang igt_pm_resume(i915); 1623f51b7e1SChris Wilson 163c31c9e82SChris Wilson err = switch_to_context(ctx); 1643f51b7e1SChris Wilson out: 165a8c9a7f5SChris Wilson fput(file); 1663f51b7e1SChris Wilson return err; 1673f51b7e1SChris Wilson } 1683f51b7e1SChris Wilson 1693f51b7e1SChris Wilson static int igt_gem_hibernate(void *arg) 1703f51b7e1SChris Wilson { 1713f51b7e1SChris Wilson struct drm_i915_private *i915 = arg; 1723f51b7e1SChris Wilson struct i915_gem_context *ctx; 173a8c9a7f5SChris Wilson struct file *file; 1743f51b7e1SChris Wilson int err; 1753f51b7e1SChris Wilson 1763f51b7e1SChris Wilson file = mock_file(i915); 1773f51b7e1SChris Wilson if (IS_ERR(file)) 1783f51b7e1SChris Wilson return PTR_ERR(file); 1793f51b7e1SChris Wilson 1803f51b7e1SChris Wilson err = -ENOMEM; 1813f51b7e1SChris Wilson ctx = live_context(i915, file); 1823f51b7e1SChris Wilson if (!IS_ERR(ctx)) 183c31c9e82SChris Wilson err = switch_to_context(ctx); 1843f51b7e1SChris Wilson if (err) 1853f51b7e1SChris Wilson goto out; 1863f51b7e1SChris Wilson 1875b117056SHsin-Yi Wang err = igt_pm_prepare(i915); 1883f51b7e1SChris Wilson if (err) 1893f51b7e1SChris Wilson goto out; 1903f51b7e1SChris Wilson 1915b117056SHsin-Yi Wang igt_pm_hibernate(i915); 1923f51b7e1SChris Wilson 1933f51b7e1SChris Wilson /* Here be dragons! */ 1943f51b7e1SChris Wilson simulate_hibernate(i915); 1953f51b7e1SChris Wilson 1965b117056SHsin-Yi Wang igt_pm_resume(i915); 1973f51b7e1SChris Wilson 198c31c9e82SChris Wilson err = switch_to_context(ctx); 1993f51b7e1SChris Wilson out: 200a8c9a7f5SChris Wilson fput(file); 2013f51b7e1SChris Wilson return err; 2023f51b7e1SChris Wilson } 2033f51b7e1SChris Wilson 20480f0b679SMaarten Lankhorst static int igt_gem_ww_ctx(void *arg) 20580f0b679SMaarten Lankhorst { 20680f0b679SMaarten Lankhorst struct drm_i915_private *i915 = arg; 20780f0b679SMaarten Lankhorst struct drm_i915_gem_object *obj, *obj2; 20880f0b679SMaarten Lankhorst struct i915_gem_ww_ctx ww; 20980f0b679SMaarten Lankhorst int err = 0; 21080f0b679SMaarten Lankhorst 21180f0b679SMaarten Lankhorst obj = i915_gem_object_create_internal(i915, PAGE_SIZE); 21280f0b679SMaarten Lankhorst if (IS_ERR(obj)) 21380f0b679SMaarten Lankhorst return PTR_ERR(obj); 21480f0b679SMaarten Lankhorst 21580f0b679SMaarten Lankhorst obj2 = i915_gem_object_create_internal(i915, PAGE_SIZE); 216352ded44SDan Carpenter if (IS_ERR(obj2)) { 217352ded44SDan Carpenter err = PTR_ERR(obj2); 21880f0b679SMaarten Lankhorst goto put1; 21980f0b679SMaarten Lankhorst } 22080f0b679SMaarten Lankhorst 22180f0b679SMaarten Lankhorst i915_gem_ww_ctx_init(&ww, true); 22280f0b679SMaarten Lankhorst retry: 22380f0b679SMaarten Lankhorst /* Lock the objects, twice for good measure (-EALREADY handling) */ 22480f0b679SMaarten Lankhorst err = i915_gem_object_lock(obj, &ww); 22580f0b679SMaarten Lankhorst if (!err) 22680f0b679SMaarten Lankhorst err = i915_gem_object_lock_interruptible(obj, &ww); 22780f0b679SMaarten Lankhorst if (!err) 22880f0b679SMaarten Lankhorst err = i915_gem_object_lock_interruptible(obj2, &ww); 22980f0b679SMaarten Lankhorst if (!err) 23080f0b679SMaarten Lankhorst err = i915_gem_object_lock(obj2, &ww); 23180f0b679SMaarten Lankhorst 23280f0b679SMaarten Lankhorst if (err == -EDEADLK) { 23380f0b679SMaarten Lankhorst err = i915_gem_ww_ctx_backoff(&ww); 23480f0b679SMaarten Lankhorst if (!err) 23580f0b679SMaarten Lankhorst goto retry; 23680f0b679SMaarten Lankhorst } 23780f0b679SMaarten Lankhorst i915_gem_ww_ctx_fini(&ww); 23880f0b679SMaarten Lankhorst i915_gem_object_put(obj2); 23980f0b679SMaarten Lankhorst put1: 24080f0b679SMaarten Lankhorst i915_gem_object_put(obj); 24180f0b679SMaarten Lankhorst return err; 24280f0b679SMaarten Lankhorst } 24380f0b679SMaarten Lankhorst 2443f51b7e1SChris Wilson int i915_gem_live_selftests(struct drm_i915_private *i915) 2453f51b7e1SChris Wilson { 2463f51b7e1SChris Wilson static const struct i915_subtest tests[] = { 2473f51b7e1SChris Wilson SUBTEST(igt_gem_suspend), 2483f51b7e1SChris Wilson SUBTEST(igt_gem_hibernate), 24980f0b679SMaarten Lankhorst SUBTEST(igt_gem_ww_ctx), 2503f51b7e1SChris Wilson }; 2513f51b7e1SChris Wilson 2528c2699faSAndi Shyti if (intel_gt_is_wedged(to_gt(i915))) 2531ab494ccSChris Wilson return 0; 2541ab494ccSChris Wilson 25563251685SChris Wilson return i915_live_subtests(tests, i915); 2563f51b7e1SChris Wilson } 257