Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * SPDX-License-Identifier: MIT
0003  *
0004  * Copyright © 2018 Intel Corporation
0005  */
0006 
0007 #include <linux/random.h>
0008 
0009 #include "gem/i915_gem_internal.h"
0010 #include "gem/i915_gem_pm.h"
0011 #include "gem/selftests/igt_gem_utils.h"
0012 #include "gem/selftests/mock_context.h"
0013 #include "gt/intel_gt.h"
0014 #include "gt/intel_gt_pm.h"
0015 
0016 #include "i915_selftest.h"
0017 
0018 #include "igt_flush_test.h"
0019 #include "mock_drm.h"
0020 
0021 static int switch_to_context(struct i915_gem_context *ctx)
0022 {
0023     struct i915_gem_engines_iter it;
0024     struct intel_context *ce;
0025     int err = 0;
0026 
0027     for_each_gem_engine(ce, i915_gem_context_lock_engines(ctx), it) {
0028         struct i915_request *rq;
0029 
0030         rq = intel_context_create_request(ce);
0031         if (IS_ERR(rq)) {
0032             err = PTR_ERR(rq);
0033             break;
0034         }
0035 
0036         i915_request_add(rq);
0037     }
0038     i915_gem_context_unlock_engines(ctx);
0039 
0040     return err;
0041 }
0042 
0043 static void trash_stolen(struct drm_i915_private *i915)
0044 {
0045     struct i915_ggtt *ggtt = to_gt(i915)->ggtt;
0046     const u64 slot = ggtt->error_capture.start;
0047     const resource_size_t size = resource_size(&i915->dsm);
0048     unsigned long page;
0049     u32 prng = 0x12345678;
0050 
0051     /* XXX: fsck. needs some more thought... */
0052     if (!i915_ggtt_has_aperture(ggtt))
0053         return;
0054 
0055     for (page = 0; page < size; page += PAGE_SIZE) {
0056         const dma_addr_t dma = i915->dsm.start + page;
0057         u32 __iomem *s;
0058         int x;
0059 
0060         ggtt->vm.insert_page(&ggtt->vm, dma, slot, I915_CACHE_NONE, 0);
0061 
0062         s = io_mapping_map_atomic_wc(&ggtt->iomap, slot);
0063         for (x = 0; x < PAGE_SIZE / sizeof(u32); x++) {
0064             prng = next_pseudo_random32(prng);
0065             iowrite32(prng, &s[x]);
0066         }
0067         io_mapping_unmap_atomic(s);
0068     }
0069 
0070     ggtt->vm.clear_range(&ggtt->vm, slot, PAGE_SIZE);
0071 }
0072 
0073 static void simulate_hibernate(struct drm_i915_private *i915)
0074 {
0075     intel_wakeref_t wakeref;
0076 
0077     wakeref = intel_runtime_pm_get(&i915->runtime_pm);
0078 
0079     /*
0080      * As a final sting in the tail, invalidate stolen. Under a real S4,
0081      * stolen is lost and needs to be refilled on resume. However, under
0082      * CI we merely do S4-device testing (as full S4 is too unreliable
0083      * for automated testing across a cluster), so to simulate the effect
0084      * of stolen being trashed across S4, we trash it ourselves.
0085      */
0086     trash_stolen(i915);
0087 
0088     intel_runtime_pm_put(&i915->runtime_pm, wakeref);
0089 }
0090 
0091 static int igt_pm_prepare(struct drm_i915_private *i915)
0092 {
0093     i915_gem_suspend(i915);
0094 
0095     return 0;
0096 }
0097 
0098 static void igt_pm_suspend(struct drm_i915_private *i915)
0099 {
0100     intel_wakeref_t wakeref;
0101 
0102     with_intel_runtime_pm(&i915->runtime_pm, wakeref) {
0103         i915_ggtt_suspend(to_gt(i915)->ggtt);
0104         i915_gem_suspend_late(i915);
0105     }
0106 }
0107 
0108 static void igt_pm_hibernate(struct drm_i915_private *i915)
0109 {
0110     intel_wakeref_t wakeref;
0111 
0112     with_intel_runtime_pm(&i915->runtime_pm, wakeref) {
0113         i915_ggtt_suspend(to_gt(i915)->ggtt);
0114 
0115         i915_gem_freeze(i915);
0116         i915_gem_freeze_late(i915);
0117     }
0118 }
0119 
0120 static void igt_pm_resume(struct drm_i915_private *i915)
0121 {
0122     intel_wakeref_t wakeref;
0123 
0124     /*
0125      * Both suspend and hibernate follow the same wakeup path and assume
0126      * that runtime-pm just works.
0127      */
0128     with_intel_runtime_pm(&i915->runtime_pm, wakeref) {
0129         i915_ggtt_resume(to_gt(i915)->ggtt);
0130         i915_gem_resume(i915);
0131     }
0132 }
0133 
0134 static int igt_gem_suspend(void *arg)
0135 {
0136     struct drm_i915_private *i915 = arg;
0137     struct i915_gem_context *ctx;
0138     struct file *file;
0139     int err;
0140 
0141     file = mock_file(i915);
0142     if (IS_ERR(file))
0143         return PTR_ERR(file);
0144 
0145     err = -ENOMEM;
0146     ctx = live_context(i915, file);
0147     if (!IS_ERR(ctx))
0148         err = switch_to_context(ctx);
0149     if (err)
0150         goto out;
0151 
0152     err = igt_pm_prepare(i915);
0153     if (err)
0154         goto out;
0155 
0156     igt_pm_suspend(i915);
0157 
0158     /* Here be dragons! Note that with S3RST any S3 may become S4! */
0159     simulate_hibernate(i915);
0160 
0161     igt_pm_resume(i915);
0162 
0163     err = switch_to_context(ctx);
0164 out:
0165     fput(file);
0166     return err;
0167 }
0168 
0169 static int igt_gem_hibernate(void *arg)
0170 {
0171     struct drm_i915_private *i915 = arg;
0172     struct i915_gem_context *ctx;
0173     struct file *file;
0174     int err;
0175 
0176     file = mock_file(i915);
0177     if (IS_ERR(file))
0178         return PTR_ERR(file);
0179 
0180     err = -ENOMEM;
0181     ctx = live_context(i915, file);
0182     if (!IS_ERR(ctx))
0183         err = switch_to_context(ctx);
0184     if (err)
0185         goto out;
0186 
0187     err = igt_pm_prepare(i915);
0188     if (err)
0189         goto out;
0190 
0191     igt_pm_hibernate(i915);
0192 
0193     /* Here be dragons! */
0194     simulate_hibernate(i915);
0195 
0196     igt_pm_resume(i915);
0197 
0198     err = switch_to_context(ctx);
0199 out:
0200     fput(file);
0201     return err;
0202 }
0203 
0204 static int igt_gem_ww_ctx(void *arg)
0205 {
0206     struct drm_i915_private *i915 = arg;
0207     struct drm_i915_gem_object *obj, *obj2;
0208     struct i915_gem_ww_ctx ww;
0209     int err = 0;
0210 
0211     obj = i915_gem_object_create_internal(i915, PAGE_SIZE);
0212     if (IS_ERR(obj))
0213         return PTR_ERR(obj);
0214 
0215     obj2 = i915_gem_object_create_internal(i915, PAGE_SIZE);
0216     if (IS_ERR(obj2)) {
0217         err = PTR_ERR(obj2);
0218         goto put1;
0219     }
0220 
0221     i915_gem_ww_ctx_init(&ww, true);
0222 retry:
0223     /* Lock the objects, twice for good measure (-EALREADY handling) */
0224     err = i915_gem_object_lock(obj, &ww);
0225     if (!err)
0226         err = i915_gem_object_lock_interruptible(obj, &ww);
0227     if (!err)
0228         err = i915_gem_object_lock_interruptible(obj2, &ww);
0229     if (!err)
0230         err = i915_gem_object_lock(obj2, &ww);
0231 
0232     if (err == -EDEADLK) {
0233         err = i915_gem_ww_ctx_backoff(&ww);
0234         if (!err)
0235             goto retry;
0236     }
0237     i915_gem_ww_ctx_fini(&ww);
0238     i915_gem_object_put(obj2);
0239 put1:
0240     i915_gem_object_put(obj);
0241     return err;
0242 }
0243 
0244 int i915_gem_live_selftests(struct drm_i915_private *i915)
0245 {
0246     static const struct i915_subtest tests[] = {
0247         SUBTEST(igt_gem_suspend),
0248         SUBTEST(igt_gem_hibernate),
0249         SUBTEST(igt_gem_ww_ctx),
0250     };
0251 
0252     if (intel_gt_is_wedged(to_gt(i915)))
0253         return 0;
0254 
0255     return i915_live_subtests(tests, i915);
0256 }