linux/drivers/gpu/drm/i915/gt/selftest_engine_pm.c
<<
>>
Prefs
   1/*
   2 * SPDX-License-Identifier: GPL-2.0
   3 *
   4 * Copyright © 2018 Intel Corporation
   5 */
   6
   7#include "i915_selftest.h"
   8#include "selftest_engine.h"
   9#include "selftest_engine_heartbeat.h"
  10#include "selftests/igt_atomic.h"
  11#include "selftests/igt_flush_test.h"
  12#include "selftests/igt_spinner.h"
  13
  14static int live_engine_busy_stats(void *arg)
  15{
  16        struct intel_gt *gt = arg;
  17        struct intel_engine_cs *engine;
  18        enum intel_engine_id id;
  19        struct igt_spinner spin;
  20        int err = 0;
  21
  22        /*
  23         * Check that if an engine supports busy-stats, they tell the truth.
  24         */
  25
  26        if (igt_spinner_init(&spin, gt))
  27                return -ENOMEM;
  28
  29        GEM_BUG_ON(intel_gt_pm_is_awake(gt));
  30        for_each_engine(engine, gt, id) {
  31                struct i915_request *rq;
  32                ktime_t de, dt;
  33                ktime_t t[2];
  34
  35                if (!intel_engine_supports_stats(engine))
  36                        continue;
  37
  38                if (!intel_engine_can_store_dword(engine))
  39                        continue;
  40
  41                if (intel_gt_pm_wait_for_idle(gt)) {
  42                        err = -EBUSY;
  43                        break;
  44                }
  45
  46                st_engine_heartbeat_disable(engine);
  47
  48                ENGINE_TRACE(engine, "measuring idle time\n");
  49                preempt_disable();
  50                de = intel_engine_get_busy_time(engine, &t[0]);
  51                udelay(100);
  52                de = ktime_sub(intel_engine_get_busy_time(engine, &t[1]), de);
  53                preempt_enable();
  54                dt = ktime_sub(t[1], t[0]);
  55                if (de < 0 || de > 10) {
  56                        pr_err("%s: reported %lldns [%d%%] busyness while sleeping [for %lldns]\n",
  57                               engine->name,
  58                               de, (int)div64_u64(100 * de, dt), dt);
  59                        GEM_TRACE_DUMP();
  60                        err = -EINVAL;
  61                        goto end;
  62                }
  63
  64                /* 100% busy */
  65                rq = igt_spinner_create_request(&spin,
  66                                                engine->kernel_context,
  67                                                MI_NOOP);
  68                if (IS_ERR(rq)) {
  69                        err = PTR_ERR(rq);
  70                        goto end;
  71                }
  72                i915_request_add(rq);
  73
  74                if (!igt_wait_for_spinner(&spin, rq)) {
  75                        intel_gt_set_wedged(engine->gt);
  76                        err = -ETIME;
  77                        goto end;
  78                }
  79
  80                ENGINE_TRACE(engine, "measuring busy time\n");
  81                preempt_disable();
  82                de = intel_engine_get_busy_time(engine, &t[0]);
  83                udelay(100);
  84                de = ktime_sub(intel_engine_get_busy_time(engine, &t[1]), de);
  85                preempt_enable();
  86                dt = ktime_sub(t[1], t[0]);
  87                if (100 * de < 95 * dt || 95 * de > 100 * dt) {
  88                        pr_err("%s: reported %lldns [%d%%] busyness while spinning [for %lldns]\n",
  89                               engine->name,
  90                               de, (int)div64_u64(100 * de, dt), dt);
  91                        GEM_TRACE_DUMP();
  92                        err = -EINVAL;
  93                        goto end;
  94                }
  95
  96end:
  97                st_engine_heartbeat_enable(engine);
  98                igt_spinner_end(&spin);
  99                if (igt_flush_test(gt->i915))
 100                        err = -EIO;
 101                if (err)
 102                        break;
 103        }
 104
 105        igt_spinner_fini(&spin);
 106        if (igt_flush_test(gt->i915))
 107                err = -EIO;
 108        return err;
 109}
 110
 111static int live_engine_pm(void *arg)
 112{
 113        struct intel_gt *gt = arg;
 114        struct intel_engine_cs *engine;
 115        enum intel_engine_id id;
 116
 117        /*
 118         * Check we can call intel_engine_pm_put from any context. No
 119         * failures are reported directly, but if we mess up lockdep should
 120         * tell us.
 121         */
 122        if (intel_gt_pm_wait_for_idle(gt)) {
 123                pr_err("Unable to flush GT pm before test\n");
 124                return -EBUSY;
 125        }
 126
 127        GEM_BUG_ON(intel_gt_pm_is_awake(gt));
 128        for_each_engine(engine, gt, id) {
 129                const typeof(*igt_atomic_phases) *p;
 130
 131                for (p = igt_atomic_phases; p->name; p++) {
 132                        /*
 133                         * Acquisition is always synchronous, except if we
 134                         * know that the engine is already awake, in which
 135                         * case we should use intel_engine_pm_get_if_awake()
 136                         * to atomically grab the wakeref.
 137                         *
 138                         * In practice,
 139                         *    intel_engine_pm_get();
 140                         *    intel_engine_pm_put();
 141                         * occurs in one thread, while simultaneously
 142                         *    intel_engine_pm_get_if_awake();
 143                         *    intel_engine_pm_put();
 144                         * occurs from atomic context in another.
 145                         */
 146                        GEM_BUG_ON(intel_engine_pm_is_awake(engine));
 147                        intel_engine_pm_get(engine);
 148
 149                        p->critical_section_begin();
 150                        if (!intel_engine_pm_get_if_awake(engine))
 151                                pr_err("intel_engine_pm_get_if_awake(%s) failed under %s\n",
 152                                       engine->name, p->name);
 153                        else
 154                                intel_engine_pm_put_async(engine);
 155                        intel_engine_pm_put_async(engine);
 156                        p->critical_section_end();
 157
 158                        intel_engine_pm_flush(engine);
 159
 160                        if (intel_engine_pm_is_awake(engine)) {
 161                                pr_err("%s is still awake after flushing pm\n",
 162                                       engine->name);
 163                                return -EINVAL;
 164                        }
 165
 166                        /* gt wakeref is async (deferred to workqueue) */
 167                        if (intel_gt_pm_wait_for_idle(gt)) {
 168                                pr_err("GT failed to idle\n");
 169                                return -EINVAL;
 170                        }
 171                }
 172        }
 173
 174        return 0;
 175}
 176
 177int live_engine_pm_selftests(struct intel_gt *gt)
 178{
 179        static const struct i915_subtest tests[] = {
 180                SUBTEST(live_engine_busy_stats),
 181                SUBTEST(live_engine_pm),
 182        };
 183
 184        return intel_gt_live_subtests(tests, gt);
 185}
 186