[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