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 "selftests/igt_atomic.h"
10 
11 static int live_engine_pm(void *arg)
12 {
13 	struct intel_gt *gt = arg;
14 	struct intel_engine_cs *engine;
15 	enum intel_engine_id id;
16 
17 	/*
18 	 * Check we can call intel_engine_pm_put from any context. No
19 	 * failures are reported directly, but if we mess up lockdep should
20 	 * tell us.
21 	 */
22 	if (intel_gt_pm_wait_for_idle(gt)) {
23 		pr_err("Unable to flush GT pm before test\n");
24 		return -EBUSY;
25 	}
26 
27 	GEM_BUG_ON(intel_gt_pm_is_awake(gt));
28 	for_each_engine(engine, gt, id) {
29 		const typeof(*igt_atomic_phases) *p;
30 
31 		for (p = igt_atomic_phases; p->name; p++) {
32 			/*
33 			 * Acquisition is always synchronous, except if we
34 			 * know that the engine is already awake, in which
35 			 * case we should use intel_engine_pm_get_if_awake()
36 			 * to atomically grab the wakeref.
37 			 *
38 			 * In practice,
39 			 *    intel_engine_pm_get();
40 			 *    intel_engine_pm_put();
41 			 * occurs in one thread, while simultaneously
42 			 *    intel_engine_pm_get_if_awake();
43 			 *    intel_engine_pm_put();
44 			 * occurs from atomic context in another.
45 			 */
46 			GEM_BUG_ON(intel_engine_pm_is_awake(engine));
47 			intel_engine_pm_get(engine);
48 
49 			p->critical_section_begin();
50 			if (!intel_engine_pm_get_if_awake(engine))
51 				pr_err("intel_engine_pm_get_if_awake(%s) failed under %s\n",
52 				       engine->name, p->name);
53 			else
54 				intel_engine_pm_put_async(engine);
55 			intel_engine_pm_put_async(engine);
56 			p->critical_section_end();
57 
58 			intel_engine_pm_flush(engine);
59 
60 			if (intel_engine_pm_is_awake(engine)) {
61 				pr_err("%s is still awake after flushing pm\n",
62 				       engine->name);
63 				return -EINVAL;
64 			}
65 
66 			/* gt wakeref is async (deferred to workqueue) */
67 			if (intel_gt_pm_wait_for_idle(gt)) {
68 				pr_err("GT failed to idle\n");
69 				return -EINVAL;
70 			}
71 		}
72 	}
73 
74 	return 0;
75 }
76 
77 int live_engine_pm_selftests(struct intel_gt *gt)
78 {
79 	static const struct i915_subtest tests[] = {
80 		SUBTEST(live_engine_pm),
81 	};
82 
83 	return intel_gt_live_subtests(tests, gt);
84 }
85