Looks good to me, thanks for the test case (btw maybe it's worth mentioning in the commit message that the test fails without doing gt.resume?) Reviewed-by: Jakub Bartmiński <jakub.bartminski@xxxxxxxxx> On Thu, 2018-08-30 at 14:48 +0100, Chris Wilson wrote: > Although we cannot do a full system-level test of suspend/hibernate > from > deep with the kernel selftests, we can exercise the GEM subsystem in > isolation and simulate the external effects (such as losing stolen > contents and trashing the register state). > > v2: Don't forget to hold rpm > v3: Suspend the GTT mappings, and more rpm! > > Signed-off-by: Chris Wilson <chris@xxxxxxxxxxxxxxxxxx> > Cc: Jakub Bartmiński <jakub.bartminski@xxxxxxxxx> > Cc: Matthew Auld <matthew.william.auld@xxxxxxxxx> > Cc: Joonas Lahtinen <joonas.lahtinen@xxxxxxxxxxxxxxx> > --- > drivers/gpu/drm/i915/i915_gem.c | 1 + > drivers/gpu/drm/i915/selftests/i915_gem.c | 221 > ++++++++++++++++++ > .../drm/i915/selftests/i915_live_selftests.h | 1 + > 3 files changed, 223 insertions(+) > create mode 100644 drivers/gpu/drm/i915/selftests/i915_gem.c > > diff --git a/drivers/gpu/drm/i915/i915_gem.c > b/drivers/gpu/drm/i915/i915_gem.c > index 0453eb42a1a3..7b7bbfe59697 100644 > --- a/drivers/gpu/drm/i915/i915_gem.c > +++ b/drivers/gpu/drm/i915/i915_gem.c > @@ -6207,4 +6207,5 @@ int i915_gem_object_attach_phys(struct > drm_i915_gem_object *obj, int align) > #include "selftests/huge_pages.c" > #include "selftests/i915_gem_object.c" > #include "selftests/i915_gem_coherency.c" > +#include "selftests/i915_gem.c" > #endif > diff --git a/drivers/gpu/drm/i915/selftests/i915_gem.c > b/drivers/gpu/drm/i915/selftests/i915_gem.c > new file mode 100644 > index 000000000000..e9cfc1fb0c07 > --- /dev/null > +++ b/drivers/gpu/drm/i915/selftests/i915_gem.c > @@ -0,0 +1,221 @@ > +/* > + * SPDX-License-Identifier: MIT > + * > + * Copyright © 2018 Intel Corporation > + */ > + > +#include <linux/random.h> > + > +#include "../i915_selftest.h" > + > +#include "mock_context.h" > +#include "igt_flush_test.h" > + > +static int switch_to_context(struct drm_i915_private *i915, > + struct i915_gem_context *ctx) > +{ > + struct intel_engine_cs *engine; > + enum intel_engine_id id; > + int err = 0; > + > + intel_runtime_pm_get(i915); > + > + for_each_engine(engine, i915, id) { > + struct i915_request *rq; > + > + rq = i915_request_alloc(engine, ctx); > + if (IS_ERR(rq)) { > + err = PTR_ERR(rq); > + break; > + } > + > + i915_request_add(rq); > + } > + > + intel_runtime_pm_put(i915); > + > + return err; > +} > + > +static int pm_prepare(struct drm_i915_private *i915) > +{ > + int err = 0; > + > + if (i915_gem_suspend(i915)) { > + pr_err("i915_gem_suspend failed\n"); > + err = -EINVAL; > + } > + > + return err; > +} > + > +static void trash_stolen(struct drm_i915_private *i915) > +{ > + struct i915_ggtt *ggtt = &i915->ggtt; > + const u64 slot = ggtt->error_capture.start; > + const resource_size_t size = resource_size(&i915->dsm); > + unsigned long page; > + u32 prng = 0x12345678; > + > + for (page = 0; page < size; page += PAGE_SIZE) { > + const dma_addr_t dma = i915->dsm.start + page; > + u32 __iomem *s; > + int x; > + > + ggtt->vm.insert_page(&ggtt->vm, dma, slot, > I915_CACHE_NONE, 0); > + > + s = io_mapping_map_atomic_wc(&ggtt->iomap, slot); > + for (x = 0; x < PAGE_SIZE / sizeof(u32); x++) { > + prng = next_pseudo_random32(prng); > + iowrite32(prng, &s[x]); > + } > + io_mapping_unmap_atomic(s); > + } > + > + ggtt->vm.clear_range(&ggtt->vm, slot, PAGE_SIZE); > +} > + > +static void simulate_hibernate(struct drm_i915_private *i915) > +{ > + intel_runtime_pm_get(i915); > + > + /* > + * As a final sting in the tail, invalidate stolen. Under a > real S4, > + * stolen is lost and needs to be refilled on resume. > However, under > + * CI we merely do S4-device testing (as full S4 is too > unreliable > + * for automated testing across a cluster), so to simulate > the effect > + * of stolen being trashed across S4, we trash it ourselves. > + */ > + trash_stolen(i915); > + > + intel_runtime_pm_put(i915); > +} > + > +static void pm_resume(struct drm_i915_private *i915) > +{ > + /* > + * Both suspend and hibernate follow the same wakeup path > and assume > + * that runtime-pm just works. > + */ > + intel_runtime_pm_get(i915); > + > + intel_engines_sanitize(i915); > + i915_gem_sanitize(i915); > + i915_gem_resume(i915); > + > + intel_runtime_pm_put(i915); > +} > + > +static void pm_suspend(struct drm_i915_private *i915) > +{ > + intel_runtime_pm_get(i915); > + > + i915_gem_suspend_gtt_mappings(i915); > + i915_gem_suspend_late(i915); > + > + intel_runtime_pm_put(i915); > +} > + > +static int igt_gem_suspend(void *arg) > +{ > + struct drm_i915_private *i915 = arg; > + struct i915_gem_context *ctx; > + struct drm_file *file; > + int err; > + > + file = mock_file(i915); > + if (IS_ERR(file)) > + return PTR_ERR(file); > + > + err = -ENOMEM; > + mutex_lock(&i915->drm.struct_mutex); > + ctx = live_context(i915, file); > + if (!IS_ERR(ctx)) > + err = switch_to_context(i915, ctx); > + mutex_unlock(&i915->drm.struct_mutex); > + if (err) > + goto out; > + > + err = pm_prepare(i915); > + if (err) > + goto out; > + > + pm_suspend(i915); > + > + /* Here be dragons! Note that with S3RST any S3 may become > S4! */ > + simulate_hibernate(i915); > + > + pm_resume(i915); > + > + mutex_lock(&i915->drm.struct_mutex); > + err = switch_to_context(i915, ctx); > + if (igt_flush_test(i915, I915_WAIT_LOCKED)) > + err = -EIO; > + mutex_unlock(&i915->drm.struct_mutex); > +out: > + mock_file_free(i915, file); > + return err; > +} > + > +static void pm_hibernate(struct drm_i915_private *i915) > +{ > + intel_runtime_pm_get(i915); > + > + i915_gem_suspend_gtt_mappings(i915); > + > + i915_gem_freeze(i915); > + i915_gem_freeze_late(i915); > + > + intel_runtime_pm_put(i915); > +} > + > +static int igt_gem_hibernate(void *arg) > +{ > + struct drm_i915_private *i915 = arg; > + struct i915_gem_context *ctx; > + struct drm_file *file; > + int err; > + > + file = mock_file(i915); > + if (IS_ERR(file)) > + return PTR_ERR(file); > + > + err = -ENOMEM; > + mutex_lock(&i915->drm.struct_mutex); > + ctx = live_context(i915, file); > + if (!IS_ERR(ctx)) > + err = switch_to_context(i915, ctx); > + mutex_unlock(&i915->drm.struct_mutex); > + if (err) > + goto out; > + > + err = pm_prepare(i915); > + if (err) > + goto out; > + > + pm_hibernate(i915); > + > + /* Here be dragons! */ > + simulate_hibernate(i915); > + > + pm_resume(i915); > + > + mutex_lock(&i915->drm.struct_mutex); > + err = switch_to_context(i915, ctx); > + if (igt_flush_test(i915, I915_WAIT_LOCKED)) > + err = -EIO; > + mutex_unlock(&i915->drm.struct_mutex); > +out: > + mock_file_free(i915, file); > + return err; > +} > + > +int i915_gem_live_selftests(struct drm_i915_private *i915) > +{ > + static const struct i915_subtest tests[] = { > + SUBTEST(igt_gem_suspend), > + SUBTEST(igt_gem_hibernate), > + }; > + > + return i915_subtests(tests, i915); > +} > diff --git a/drivers/gpu/drm/i915/selftests/i915_live_selftests.h > b/drivers/gpu/drm/i915/selftests/i915_live_selftests.h > index a00e2bd08bce..a15713cae3b3 100644 > --- a/drivers/gpu/drm/i915/selftests/i915_live_selftests.h > +++ b/drivers/gpu/drm/i915/selftests/i915_live_selftests.h > @@ -17,6 +17,7 @@ selftest(objects, i915_gem_object_live_selftests) > selftest(dmabuf, i915_gem_dmabuf_live_selftests) > selftest(coherency, i915_gem_coherency_live_selftests) > selftest(gtt, i915_gem_gtt_live_selftests) > +selftest(gem, i915_gem_live_selftests) > selftest(evict, i915_gem_evict_live_selftests) > selftest(hugepages, i915_gem_huge_page_live_selftests) > selftest(contexts, i915_gem_context_live_selftests)
Attachment:
smime.p7s
Description: S/MIME cryptographic signature
_______________________________________________ Intel-gfx mailing list Intel-gfx@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/intel-gfx