linux/drivers/gpu/drm/i915/selftests/i915_active.c
<<
>>
Prefs
   1/*
   2 * SPDX-License-Identifier: MIT
   3 *
   4 * Copyright © 2018 Intel Corporation
   5 */
   6
   7#include "gem/i915_gem_pm.h"
   8
   9#include "i915_selftest.h"
  10
  11#include "igt_flush_test.h"
  12#include "lib_sw_fence.h"
  13
  14struct live_active {
  15        struct i915_active base;
  16        bool retired;
  17};
  18
  19static void __live_active_retire(struct i915_active *base)
  20{
  21        struct live_active *active = container_of(base, typeof(*active), base);
  22
  23        active->retired = true;
  24}
  25
  26static int __live_active_setup(struct drm_i915_private *i915,
  27                               struct live_active *active)
  28{
  29        struct intel_engine_cs *engine;
  30        struct i915_sw_fence *submit;
  31        enum intel_engine_id id;
  32        unsigned int count = 0;
  33        int err = 0;
  34
  35        submit = heap_fence_create(GFP_KERNEL);
  36        if (!submit)
  37                return -ENOMEM;
  38
  39        i915_active_init(i915, &active->base, __live_active_retire);
  40        active->retired = false;
  41
  42        if (!i915_active_acquire(&active->base)) {
  43                pr_err("First i915_active_acquire should report being idle\n");
  44                err = -EINVAL;
  45                goto out;
  46        }
  47
  48        for_each_engine(engine, i915, id) {
  49                struct i915_request *rq;
  50
  51                rq = i915_request_create(engine->kernel_context);
  52                if (IS_ERR(rq)) {
  53                        err = PTR_ERR(rq);
  54                        break;
  55                }
  56
  57                err = i915_sw_fence_await_sw_fence_gfp(&rq->submit,
  58                                                       submit,
  59                                                       GFP_KERNEL);
  60                if (err >= 0)
  61                        err = i915_active_ref(&active->base,
  62                                              rq->fence.context, rq);
  63                i915_request_add(rq);
  64                if (err) {
  65                        pr_err("Failed to track active ref!\n");
  66                        break;
  67                }
  68
  69                count++;
  70        }
  71
  72        i915_active_release(&active->base);
  73        if (active->retired && count) {
  74                pr_err("i915_active retired before submission!\n");
  75                err = -EINVAL;
  76        }
  77        if (active->base.count != count) {
  78                pr_err("i915_active not tracking all requests, found %d, expected %d\n",
  79                       active->base.count, count);
  80                err = -EINVAL;
  81        }
  82
  83out:
  84        i915_sw_fence_commit(submit);
  85        heap_fence_put(submit);
  86
  87        return err;
  88}
  89
  90static int live_active_wait(void *arg)
  91{
  92        struct drm_i915_private *i915 = arg;
  93        struct live_active active;
  94        intel_wakeref_t wakeref;
  95        int err;
  96
  97        /* Check that we get a callback when requests retire upon waiting */
  98
  99        mutex_lock(&i915->drm.struct_mutex);
 100        wakeref = intel_runtime_pm_get(&i915->runtime_pm);
 101
 102        err = __live_active_setup(i915, &active);
 103
 104        i915_active_wait(&active.base);
 105        if (!active.retired) {
 106                pr_err("i915_active not retired after waiting!\n");
 107                err = -EINVAL;
 108        }
 109
 110        i915_active_fini(&active.base);
 111        if (igt_flush_test(i915, I915_WAIT_LOCKED))
 112                err = -EIO;
 113
 114        intel_runtime_pm_put(&i915->runtime_pm, wakeref);
 115        mutex_unlock(&i915->drm.struct_mutex);
 116        return err;
 117}
 118
 119static int live_active_retire(void *arg)
 120{
 121        struct drm_i915_private *i915 = arg;
 122        struct live_active active;
 123        intel_wakeref_t wakeref;
 124        int err;
 125
 126        /* Check that we get a callback when requests are indirectly retired */
 127
 128        mutex_lock(&i915->drm.struct_mutex);
 129        wakeref = intel_runtime_pm_get(&i915->runtime_pm);
 130
 131        err = __live_active_setup(i915, &active);
 132
 133        /* waits for & retires all requests */
 134        if (igt_flush_test(i915, I915_WAIT_LOCKED))
 135                err = -EIO;
 136
 137        if (!active.retired) {
 138                pr_err("i915_active not retired after flushing!\n");
 139                err = -EINVAL;
 140        }
 141
 142        i915_active_fini(&active.base);
 143        intel_runtime_pm_put(&i915->runtime_pm, wakeref);
 144        mutex_unlock(&i915->drm.struct_mutex);
 145        return err;
 146}
 147
 148int i915_active_live_selftests(struct drm_i915_private *i915)
 149{
 150        static const struct i915_subtest tests[] = {
 151                SUBTEST(live_active_wait),
 152                SUBTEST(live_active_retire),
 153        };
 154
 155        if (i915_terminally_wedged(i915))
 156                return 0;
 157
 158        return i915_subtests(tests, i915);
 159}
 160