18ee2c227SVinay Belgaumkar // SPDX-License-Identifier: MIT
28ee2c227SVinay Belgaumkar /*
38ee2c227SVinay Belgaumkar  * Copyright © 2021 Intel Corporation
48ee2c227SVinay Belgaumkar  */
58ee2c227SVinay Belgaumkar 
68ee2c227SVinay Belgaumkar #define NUM_STEPS 5
78ee2c227SVinay Belgaumkar #define H2G_DELAY 50000
88ee2c227SVinay Belgaumkar #define delay_for_h2g() usleep_range(H2G_DELAY, H2G_DELAY + 10000)
98ee2c227SVinay Belgaumkar #define FREQUENCY_REQ_UNIT	DIV_ROUND_CLOSEST(GT_FREQUENCY_MULTIPLIER, \
108ee2c227SVinay Belgaumkar 						  GEN9_FREQ_SCALER)
1179398d24SVinay Belgaumkar enum test_type {
1279398d24SVinay Belgaumkar 	VARY_MIN,
1379398d24SVinay Belgaumkar 	VARY_MAX,
1479398d24SVinay Belgaumkar 	MAX_GRANTED
1579398d24SVinay Belgaumkar };
168ee2c227SVinay Belgaumkar 
178ee2c227SVinay Belgaumkar static int slpc_set_min_freq(struct intel_guc_slpc *slpc, u32 freq)
188ee2c227SVinay Belgaumkar {
198ee2c227SVinay Belgaumkar 	int ret;
208ee2c227SVinay Belgaumkar 
218ee2c227SVinay Belgaumkar 	ret = intel_guc_slpc_set_min_freq(slpc, freq);
228ee2c227SVinay Belgaumkar 	if (ret)
238ee2c227SVinay Belgaumkar 		pr_err("Could not set min frequency to [%u]\n", freq);
248ee2c227SVinay Belgaumkar 	else /* Delay to ensure h2g completes */
258ee2c227SVinay Belgaumkar 		delay_for_h2g();
268ee2c227SVinay Belgaumkar 
278ee2c227SVinay Belgaumkar 	return ret;
288ee2c227SVinay Belgaumkar }
298ee2c227SVinay Belgaumkar 
308ee2c227SVinay Belgaumkar static int slpc_set_max_freq(struct intel_guc_slpc *slpc, u32 freq)
318ee2c227SVinay Belgaumkar {
328ee2c227SVinay Belgaumkar 	int ret;
338ee2c227SVinay Belgaumkar 
348ee2c227SVinay Belgaumkar 	ret = intel_guc_slpc_set_max_freq(slpc, freq);
358ee2c227SVinay Belgaumkar 	if (ret)
368ee2c227SVinay Belgaumkar 		pr_err("Could not set maximum frequency [%u]\n",
378ee2c227SVinay Belgaumkar 		       freq);
388ee2c227SVinay Belgaumkar 	else /* Delay to ensure h2g completes */
398ee2c227SVinay Belgaumkar 		delay_for_h2g();
408ee2c227SVinay Belgaumkar 
418ee2c227SVinay Belgaumkar 	return ret;
428ee2c227SVinay Belgaumkar }
438ee2c227SVinay Belgaumkar 
4479398d24SVinay Belgaumkar static int vary_max_freq(struct intel_guc_slpc *slpc, struct intel_rps *rps,
4579398d24SVinay Belgaumkar 			 u32 *max_act_freq)
468ee2c227SVinay Belgaumkar {
4779398d24SVinay Belgaumkar 	u32 step, max_freq, req_freq;
4879398d24SVinay Belgaumkar 	u32 act_freq;
4979398d24SVinay Belgaumkar 	int err = 0;
5079398d24SVinay Belgaumkar 
5179398d24SVinay Belgaumkar 	/* Go from max to min in 5 steps */
5279398d24SVinay Belgaumkar 	step = (slpc->rp0_freq - slpc->min_freq) / NUM_STEPS;
5379398d24SVinay Belgaumkar 	*max_act_freq = slpc->min_freq;
5479398d24SVinay Belgaumkar 	for (max_freq = slpc->rp0_freq; max_freq > slpc->min_freq;
5579398d24SVinay Belgaumkar 				max_freq -= step) {
5679398d24SVinay Belgaumkar 		err = slpc_set_max_freq(slpc, max_freq);
5779398d24SVinay Belgaumkar 		if (err)
5879398d24SVinay Belgaumkar 			break;
5979398d24SVinay Belgaumkar 
6079398d24SVinay Belgaumkar 		req_freq = intel_rps_read_punit_req_frequency(rps);
6179398d24SVinay Belgaumkar 
6279398d24SVinay Belgaumkar 		/* GuC requests freq in multiples of 50/3 MHz */
6379398d24SVinay Belgaumkar 		if (req_freq > (max_freq + FREQUENCY_REQ_UNIT)) {
6479398d24SVinay Belgaumkar 			pr_err("SWReq is %d, should be at most %d\n", req_freq,
6579398d24SVinay Belgaumkar 			       max_freq + FREQUENCY_REQ_UNIT);
6679398d24SVinay Belgaumkar 			err = -EINVAL;
6779398d24SVinay Belgaumkar 		}
6879398d24SVinay Belgaumkar 
6979398d24SVinay Belgaumkar 		act_freq =  intel_rps_read_actual_frequency(rps);
7079398d24SVinay Belgaumkar 		if (act_freq > *max_act_freq)
7179398d24SVinay Belgaumkar 			*max_act_freq = act_freq;
7279398d24SVinay Belgaumkar 
7379398d24SVinay Belgaumkar 		if (err)
7479398d24SVinay Belgaumkar 			break;
7579398d24SVinay Belgaumkar 	}
7679398d24SVinay Belgaumkar 
7779398d24SVinay Belgaumkar 	return err;
7879398d24SVinay Belgaumkar }
7979398d24SVinay Belgaumkar 
8079398d24SVinay Belgaumkar static int vary_min_freq(struct intel_guc_slpc *slpc, struct intel_rps *rps,
8179398d24SVinay Belgaumkar 			 u32 *max_act_freq)
8279398d24SVinay Belgaumkar {
8379398d24SVinay Belgaumkar 	u32 step, min_freq, req_freq;
8479398d24SVinay Belgaumkar 	u32 act_freq;
8579398d24SVinay Belgaumkar 	int err = 0;
8679398d24SVinay Belgaumkar 
8779398d24SVinay Belgaumkar 	/* Go from min to max in 5 steps */
8879398d24SVinay Belgaumkar 	step = (slpc->rp0_freq - slpc->min_freq) / NUM_STEPS;
8979398d24SVinay Belgaumkar 	*max_act_freq = slpc->min_freq;
9079398d24SVinay Belgaumkar 	for (min_freq = slpc->min_freq; min_freq < slpc->rp0_freq;
9179398d24SVinay Belgaumkar 				min_freq += step) {
9279398d24SVinay Belgaumkar 		err = slpc_set_min_freq(slpc, min_freq);
9379398d24SVinay Belgaumkar 		if (err)
9479398d24SVinay Belgaumkar 			break;
9579398d24SVinay Belgaumkar 
9679398d24SVinay Belgaumkar 		req_freq = intel_rps_read_punit_req_frequency(rps);
9779398d24SVinay Belgaumkar 
9879398d24SVinay Belgaumkar 		/* GuC requests freq in multiples of 50/3 MHz */
9979398d24SVinay Belgaumkar 		if (req_freq < (min_freq - FREQUENCY_REQ_UNIT)) {
10079398d24SVinay Belgaumkar 			pr_err("SWReq is %d, should be at least %d\n", req_freq,
10179398d24SVinay Belgaumkar 			       min_freq - FREQUENCY_REQ_UNIT);
10279398d24SVinay Belgaumkar 			err = -EINVAL;
10379398d24SVinay Belgaumkar 		}
10479398d24SVinay Belgaumkar 
10579398d24SVinay Belgaumkar 		act_freq =  intel_rps_read_actual_frequency(rps);
10679398d24SVinay Belgaumkar 		if (act_freq > *max_act_freq)
10779398d24SVinay Belgaumkar 			*max_act_freq = act_freq;
10879398d24SVinay Belgaumkar 
10979398d24SVinay Belgaumkar 		if (err)
11079398d24SVinay Belgaumkar 			break;
11179398d24SVinay Belgaumkar 	}
11279398d24SVinay Belgaumkar 
11379398d24SVinay Belgaumkar 	return err;
11479398d24SVinay Belgaumkar }
11579398d24SVinay Belgaumkar 
11679398d24SVinay Belgaumkar static int max_granted_freq(struct intel_guc_slpc *slpc, struct intel_rps *rps, u32 *max_act_freq)
11779398d24SVinay Belgaumkar {
11879398d24SVinay Belgaumkar 	struct intel_gt *gt = rps_to_gt(rps);
11979398d24SVinay Belgaumkar 	u32 perf_limit_reasons;
12079398d24SVinay Belgaumkar 	int err = 0;
12179398d24SVinay Belgaumkar 
12279398d24SVinay Belgaumkar 	err = slpc_set_min_freq(slpc, slpc->rp0_freq);
12379398d24SVinay Belgaumkar 	if (err)
12479398d24SVinay Belgaumkar 		return err;
12579398d24SVinay Belgaumkar 
12679398d24SVinay Belgaumkar 	*max_act_freq =  intel_rps_read_actual_frequency(rps);
12779398d24SVinay Belgaumkar 	if (*max_act_freq != slpc->rp0_freq) {
12879398d24SVinay Belgaumkar 		/* Check if there was some throttling by pcode */
12979398d24SVinay Belgaumkar 		perf_limit_reasons = intel_uncore_read(gt->uncore, GT0_PERF_LIMIT_REASONS);
13079398d24SVinay Belgaumkar 
13179398d24SVinay Belgaumkar 		/* If not, this is an error */
13279398d24SVinay Belgaumkar 		if (!(perf_limit_reasons & GT0_PERF_LIMIT_REASONS_MASK)) {
13379398d24SVinay Belgaumkar 			pr_err("Pcode did not grant max freq\n");
13479398d24SVinay Belgaumkar 			err = -EINVAL;
13579398d24SVinay Belgaumkar 		} else {
13679398d24SVinay Belgaumkar 			pr_info("Pcode throttled frequency 0x%x\n", perf_limit_reasons);
13779398d24SVinay Belgaumkar 		}
13879398d24SVinay Belgaumkar 	}
13979398d24SVinay Belgaumkar 
14079398d24SVinay Belgaumkar 	return err;
14179398d24SVinay Belgaumkar }
14279398d24SVinay Belgaumkar 
14379398d24SVinay Belgaumkar static int run_test(struct intel_gt *gt, int test_type)
14479398d24SVinay Belgaumkar {
1458ee2c227SVinay Belgaumkar 	struct intel_guc_slpc *slpc = &gt->uc.guc.slpc;
1468ee2c227SVinay Belgaumkar 	struct intel_rps *rps = &gt->rps;
1478ee2c227SVinay Belgaumkar 	struct intel_engine_cs *engine;
1488ee2c227SVinay Belgaumkar 	enum intel_engine_id id;
1498ee2c227SVinay Belgaumkar 	struct igt_spinner spin;
1508ee2c227SVinay Belgaumkar 	u32 slpc_min_freq, slpc_max_freq;
1518ee2c227SVinay Belgaumkar 	int err = 0;
1528ee2c227SVinay Belgaumkar 
1538ee2c227SVinay Belgaumkar 	if (!intel_uc_uses_guc_slpc(&gt->uc))
1548ee2c227SVinay Belgaumkar 		return 0;
1558ee2c227SVinay Belgaumkar 
1568ee2c227SVinay Belgaumkar 	if (igt_spinner_init(&spin, gt))
1578ee2c227SVinay Belgaumkar 		return -ENOMEM;
1588ee2c227SVinay Belgaumkar 
1598ee2c227SVinay Belgaumkar 	if (intel_guc_slpc_get_max_freq(slpc, &slpc_max_freq)) {
1608ee2c227SVinay Belgaumkar 		pr_err("Could not get SLPC max freq\n");
1618ee2c227SVinay Belgaumkar 		return -EIO;
1628ee2c227SVinay Belgaumkar 	}
1638ee2c227SVinay Belgaumkar 
1648ee2c227SVinay Belgaumkar 	if (intel_guc_slpc_get_min_freq(slpc, &slpc_min_freq)) {
1658ee2c227SVinay Belgaumkar 		pr_err("Could not get SLPC min freq\n");
1668ee2c227SVinay Belgaumkar 		return -EIO;
1678ee2c227SVinay Belgaumkar 	}
1688ee2c227SVinay Belgaumkar 
16995ccf312SVinay Belgaumkar 	/*
17095ccf312SVinay Belgaumkar 	 * FIXME: With efficient frequency enabled, GuC can request
17195ccf312SVinay Belgaumkar 	 * frequencies higher than the SLPC max. While this is fixed
17295ccf312SVinay Belgaumkar 	 * in GuC, we level set these tests with RPn as min.
17395ccf312SVinay Belgaumkar 	 */
17495ccf312SVinay Belgaumkar 	err = slpc_set_min_freq(slpc, slpc->min_freq);
17595ccf312SVinay Belgaumkar 	if (err)
17695ccf312SVinay Belgaumkar 		return err;
17795ccf312SVinay Belgaumkar 
17879398d24SVinay Belgaumkar 	if (slpc->min_freq == slpc->rp0_freq) {
1798ee2c227SVinay Belgaumkar 		pr_err("Min/Max are fused to the same value\n");
1808ee2c227SVinay Belgaumkar 		return -EINVAL;
1818ee2c227SVinay Belgaumkar 	}
1828ee2c227SVinay Belgaumkar 
1838ee2c227SVinay Belgaumkar 	intel_gt_pm_wait_for_idle(gt);
1848ee2c227SVinay Belgaumkar 	intel_gt_pm_get(gt);
1858ee2c227SVinay Belgaumkar 	for_each_engine(engine, gt, id) {
1868ee2c227SVinay Belgaumkar 		struct i915_request *rq;
18779398d24SVinay Belgaumkar 		u32 max_act_freq;
1888ee2c227SVinay Belgaumkar 
1898ee2c227SVinay Belgaumkar 		if (!intel_engine_can_store_dword(engine))
1908ee2c227SVinay Belgaumkar 			continue;
1918ee2c227SVinay Belgaumkar 
1928ee2c227SVinay Belgaumkar 		st_engine_heartbeat_disable(engine);
1938ee2c227SVinay Belgaumkar 
1948ee2c227SVinay Belgaumkar 		rq = igt_spinner_create_request(&spin,
1958ee2c227SVinay Belgaumkar 						engine->kernel_context,
1968ee2c227SVinay Belgaumkar 						MI_NOOP);
1978ee2c227SVinay Belgaumkar 		if (IS_ERR(rq)) {
1988ee2c227SVinay Belgaumkar 			err = PTR_ERR(rq);
1998ee2c227SVinay Belgaumkar 			st_engine_heartbeat_enable(engine);
2008ee2c227SVinay Belgaumkar 			break;
2018ee2c227SVinay Belgaumkar 		}
2028ee2c227SVinay Belgaumkar 
2038ee2c227SVinay Belgaumkar 		i915_request_add(rq);
2048ee2c227SVinay Belgaumkar 
2058ee2c227SVinay Belgaumkar 		if (!igt_wait_for_spinner(&spin, rq)) {
2068ee2c227SVinay Belgaumkar 			pr_err("%s: Spinner did not start\n",
2078ee2c227SVinay Belgaumkar 			       engine->name);
2088ee2c227SVinay Belgaumkar 			igt_spinner_end(&spin);
2098ee2c227SVinay Belgaumkar 			st_engine_heartbeat_enable(engine);
2108ee2c227SVinay Belgaumkar 			intel_gt_set_wedged(engine->gt);
2118ee2c227SVinay Belgaumkar 			err = -EIO;
2128ee2c227SVinay Belgaumkar 			break;
2138ee2c227SVinay Belgaumkar 		}
2148ee2c227SVinay Belgaumkar 
21579398d24SVinay Belgaumkar 		switch (test_type) {
21679398d24SVinay Belgaumkar 		case VARY_MIN:
21779398d24SVinay Belgaumkar 			err = vary_min_freq(slpc, rps, &max_act_freq);
21879398d24SVinay Belgaumkar 			break;
2198ee2c227SVinay Belgaumkar 
22079398d24SVinay Belgaumkar 		case VARY_MAX:
22179398d24SVinay Belgaumkar 			err = vary_max_freq(slpc, rps, &max_act_freq);
22279398d24SVinay Belgaumkar 			break;
2238ee2c227SVinay Belgaumkar 
22479398d24SVinay Belgaumkar 		case MAX_GRANTED:
22579398d24SVinay Belgaumkar 			/* Media engines have a different RP0 */
22679398d24SVinay Belgaumkar 			if (engine->class == VIDEO_DECODE_CLASS ||
22779398d24SVinay Belgaumkar 			    engine->class == VIDEO_ENHANCEMENT_CLASS) {
2288ee2c227SVinay Belgaumkar 				igt_spinner_end(&spin);
2298ee2c227SVinay Belgaumkar 				st_engine_heartbeat_enable(engine);
23079398d24SVinay Belgaumkar 				err = 0;
23179398d24SVinay Belgaumkar 				continue;
2328ee2c227SVinay Belgaumkar 			}
2338ee2c227SVinay Belgaumkar 
23479398d24SVinay Belgaumkar 			err = max_granted_freq(slpc, rps, &max_act_freq);
23579398d24SVinay Belgaumkar 			break;
2368ee2c227SVinay Belgaumkar 		}
2378ee2c227SVinay Belgaumkar 
2388ee2c227SVinay Belgaumkar 		pr_info("Max actual frequency for %s was %d\n",
2398ee2c227SVinay Belgaumkar 			engine->name, max_act_freq);
2408ee2c227SVinay Belgaumkar 
2418ee2c227SVinay Belgaumkar 		/* Actual frequency should rise above min */
24279398d24SVinay Belgaumkar 		if (max_act_freq <= slpc_min_freq) {
2438ee2c227SVinay Belgaumkar 			pr_err("Actual freq did not rise above min\n");
24479398d24SVinay Belgaumkar 			pr_err("Perf Limit Reasons: 0x%x\n",
24579398d24SVinay Belgaumkar 			       intel_uncore_read(gt->uncore, GT0_PERF_LIMIT_REASONS));
2468ee2c227SVinay Belgaumkar 			err = -EINVAL;
2478ee2c227SVinay Belgaumkar 		}
2488ee2c227SVinay Belgaumkar 
24979398d24SVinay Belgaumkar 		igt_spinner_end(&spin);
25079398d24SVinay Belgaumkar 		st_engine_heartbeat_enable(engine);
25179398d24SVinay Belgaumkar 
2528ee2c227SVinay Belgaumkar 		if (err)
2538ee2c227SVinay Belgaumkar 			break;
2548ee2c227SVinay Belgaumkar 	}
2558ee2c227SVinay Belgaumkar 
2568ee2c227SVinay Belgaumkar 	/* Restore min/max frequencies */
2578ee2c227SVinay Belgaumkar 	slpc_set_max_freq(slpc, slpc_max_freq);
2588ee2c227SVinay Belgaumkar 	slpc_set_min_freq(slpc, slpc_min_freq);
2598ee2c227SVinay Belgaumkar 
2608ee2c227SVinay Belgaumkar 	if (igt_flush_test(gt->i915))
2618ee2c227SVinay Belgaumkar 		err = -EIO;
2628ee2c227SVinay Belgaumkar 
2638ee2c227SVinay Belgaumkar 	intel_gt_pm_put(gt);
2648ee2c227SVinay Belgaumkar 	igt_spinner_fini(&spin);
2658ee2c227SVinay Belgaumkar 	intel_gt_pm_wait_for_idle(gt);
2668ee2c227SVinay Belgaumkar 
2678ee2c227SVinay Belgaumkar 	return err;
2688ee2c227SVinay Belgaumkar }
2698ee2c227SVinay Belgaumkar 
27079398d24SVinay Belgaumkar static int live_slpc_vary_min(void *arg)
2718ee2c227SVinay Belgaumkar {
2728ee2c227SVinay Belgaumkar 	struct drm_i915_private *i915 = arg;
273*c09ae4edSRiana Tauro 	struct intel_gt *gt;
274*c09ae4edSRiana Tauro 	unsigned int i;
275*c09ae4edSRiana Tauro 	int ret;
2768ee2c227SVinay Belgaumkar 
277*c09ae4edSRiana Tauro 	for_each_gt(gt, i915, i) {
278*c09ae4edSRiana Tauro 		ret = run_test(gt, VARY_MIN);
279*c09ae4edSRiana Tauro 		if (ret)
280*c09ae4edSRiana Tauro 			return ret;
281*c09ae4edSRiana Tauro 	}
282*c09ae4edSRiana Tauro 
283*c09ae4edSRiana Tauro 	return ret;
2848ee2c227SVinay Belgaumkar }
2858ee2c227SVinay Belgaumkar 
28679398d24SVinay Belgaumkar static int live_slpc_vary_max(void *arg)
28779398d24SVinay Belgaumkar {
28879398d24SVinay Belgaumkar 	struct drm_i915_private *i915 = arg;
289*c09ae4edSRiana Tauro 	struct intel_gt *gt;
290*c09ae4edSRiana Tauro 	unsigned int i;
291*c09ae4edSRiana Tauro 	int ret;
29279398d24SVinay Belgaumkar 
293*c09ae4edSRiana Tauro 	for_each_gt(gt, i915, i) {
294*c09ae4edSRiana Tauro 		ret = run_test(gt, VARY_MAX);
295*c09ae4edSRiana Tauro 		if (ret)
296*c09ae4edSRiana Tauro 			return ret;
297*c09ae4edSRiana Tauro 	}
298*c09ae4edSRiana Tauro 
299*c09ae4edSRiana Tauro 	return ret;
3008ee2c227SVinay Belgaumkar }
3018ee2c227SVinay Belgaumkar 
30279398d24SVinay Belgaumkar /* check if pcode can grant RP0 */
30379398d24SVinay Belgaumkar static int live_slpc_max_granted(void *arg)
30479398d24SVinay Belgaumkar {
30579398d24SVinay Belgaumkar 	struct drm_i915_private *i915 = arg;
306*c09ae4edSRiana Tauro 	struct intel_gt *gt;
307*c09ae4edSRiana Tauro 	unsigned int i;
308*c09ae4edSRiana Tauro 	int ret;
3098ee2c227SVinay Belgaumkar 
310*c09ae4edSRiana Tauro 	for_each_gt(gt, i915, i) {
311*c09ae4edSRiana Tauro 		ret = run_test(gt, MAX_GRANTED);
312*c09ae4edSRiana Tauro 		if (ret)
313*c09ae4edSRiana Tauro 			return ret;
314*c09ae4edSRiana Tauro 	}
315*c09ae4edSRiana Tauro 
316*c09ae4edSRiana Tauro 	return ret;
3178ee2c227SVinay Belgaumkar }
3188ee2c227SVinay Belgaumkar 
3198ee2c227SVinay Belgaumkar int intel_slpc_live_selftests(struct drm_i915_private *i915)
3208ee2c227SVinay Belgaumkar {
3218ee2c227SVinay Belgaumkar 	static const struct i915_subtest tests[] = {
32279398d24SVinay Belgaumkar 		SUBTEST(live_slpc_vary_max),
32379398d24SVinay Belgaumkar 		SUBTEST(live_slpc_vary_min),
32479398d24SVinay Belgaumkar 		SUBTEST(live_slpc_max_granted),
3258ee2c227SVinay Belgaumkar 	};
3268ee2c227SVinay Belgaumkar 
327*c09ae4edSRiana Tauro 	struct intel_gt *gt;
328*c09ae4edSRiana Tauro 	unsigned int i;
329*c09ae4edSRiana Tauro 
330*c09ae4edSRiana Tauro 	for_each_gt(gt, i915, i) {
331*c09ae4edSRiana Tauro 		if (intel_gt_is_wedged(gt))
3328ee2c227SVinay Belgaumkar 			return 0;
333*c09ae4edSRiana Tauro 	}
3348ee2c227SVinay Belgaumkar 
3358ee2c227SVinay Belgaumkar 	return i915_live_subtests(tests, i915);
3368ee2c227SVinay Belgaumkar }
337