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 = >->uc.guc.slpc; 1468ee2c227SVinay Belgaumkar struct intel_rps *rps = >->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(>->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