[Intel-gfx] [PATCH v4] drm/i915/selftests: Add a simple exerciser for suspend/hibernate
Chris Wilson
chris at chris-wilson.co.uk
Fri Aug 31 08:00:39 UTC 2018
Quoting Chris Wilson (2018-08-30 14:48:06)
> 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 at chris-wilson.co.uk>
> Cc: Jakub Bartmiński <jakub.bartminski at intel.com>
> Cc: Matthew Auld <matthew.william.auld at gmail.com>
> Cc: Joonas Lahtinen <joonas.lahtinen at linux.intel.com>
The dust has finally settled; care for a perusal?
-Chris
> ---
> 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)
> --
> 2.19.0.rc1
>
More information about the Intel-gfx
mailing list