|
15 | 15 | #include "gt/intel_gt_regs.h" |
16 | 16 | #include "gt/intel_rps.h" |
17 | 17 |
|
| 18 | +/** |
| 19 | + * DOC: SLPC - Dynamic Frequency management |
| 20 | + * |
| 21 | + * Single Loop Power Control (SLPC) is a GuC algorithm that manages |
| 22 | + * GT frequency based on busyness and how KMD initializes it. SLPC is |
| 23 | + * almost completely in control after initialization except for a few |
| 24 | + * scenarios mentioned below. |
| 25 | + * |
| 26 | + * KMD uses the concept of waitboost to ramp frequency to RP0 when there |
| 27 | + * are pending submissions for a context. It achieves this by sending GuC a |
| 28 | + * request to update the min frequency to RP0. Waitboost is disabled |
| 29 | + * when the request retires. |
| 30 | + * |
| 31 | + * Another form of frequency control happens through per-context hints. |
| 32 | + * A context can be marked as low latency during creation. That will ensure |
| 33 | + * that SLPC uses an aggressive frequency ramp when that context is active. |
| 34 | + * |
| 35 | + * Power profiles add another level of control to these mechanisms. |
| 36 | + * When power saving profile is chosen, SLPC will use conservative |
| 37 | + * thresholds to ramp frequency, thus saving power. KMD will disable |
| 38 | + * waitboosts as well, which achieves further power savings. Base profile |
| 39 | + * is default and ensures balanced performance for any workload. |
| 40 | + * |
| 41 | + * Lastly, users have some level of control through sysfs, where min/max |
| 42 | + * frequency values can be altered and the use of efficient freq |
| 43 | + * can be toggled. |
| 44 | + */ |
| 45 | + |
18 | 46 | static inline struct intel_guc *slpc_to_guc(struct intel_guc_slpc *slpc) |
19 | 47 | { |
20 | 48 | return container_of(slpc, struct intel_guc, slpc); |
@@ -265,6 +293,8 @@ int intel_guc_slpc_init(struct intel_guc_slpc *slpc) |
265 | 293 | slpc->num_boosts = 0; |
266 | 294 | slpc->media_ratio_mode = SLPC_MEDIA_RATIO_MODE_DYNAMIC_CONTROL; |
267 | 295 |
|
| 296 | + slpc->power_profile = SLPC_POWER_PROFILES_BASE; |
| 297 | + |
268 | 298 | mutex_init(&slpc->lock); |
269 | 299 | INIT_WORK(&slpc->boost_work, slpc_boost_work); |
270 | 300 |
|
@@ -567,6 +597,34 @@ int intel_guc_slpc_set_media_ratio_mode(struct intel_guc_slpc *slpc, u32 val) |
567 | 597 | return ret; |
568 | 598 | } |
569 | 599 |
|
| 600 | +int intel_guc_slpc_set_power_profile(struct intel_guc_slpc *slpc, u32 val) |
| 601 | +{ |
| 602 | + struct drm_i915_private *i915 = slpc_to_i915(slpc); |
| 603 | + intel_wakeref_t wakeref; |
| 604 | + int ret = 0; |
| 605 | + |
| 606 | + if (val > SLPC_POWER_PROFILES_POWER_SAVING) |
| 607 | + return -EINVAL; |
| 608 | + |
| 609 | + mutex_lock(&slpc->lock); |
| 610 | + wakeref = intel_runtime_pm_get(&i915->runtime_pm); |
| 611 | + |
| 612 | + ret = slpc_set_param(slpc, |
| 613 | + SLPC_PARAM_POWER_PROFILE, |
| 614 | + val); |
| 615 | + if (ret) |
| 616 | + guc_err(slpc_to_guc(slpc), |
| 617 | + "Failed to set power profile to %d: %pe\n", |
| 618 | + val, ERR_PTR(ret)); |
| 619 | + else |
| 620 | + slpc->power_profile = val; |
| 621 | + |
| 622 | + intel_runtime_pm_put(&i915->runtime_pm, wakeref); |
| 623 | + mutex_unlock(&slpc->lock); |
| 624 | + |
| 625 | + return ret; |
| 626 | +} |
| 627 | + |
570 | 628 | void intel_guc_pm_intrmsk_enable(struct intel_gt *gt) |
571 | 629 | { |
572 | 630 | u32 pm_intrmsk_mbz = 0; |
@@ -728,6 +786,13 @@ int intel_guc_slpc_enable(struct intel_guc_slpc *slpc) |
728 | 786 | /* Enable SLPC Optimized Strategy for compute */ |
729 | 787 | intel_guc_slpc_set_strategy(slpc, SLPC_OPTIMIZED_STRATEGY_COMPUTE); |
730 | 788 |
|
| 789 | + /* Set cached value of power_profile */ |
| 790 | + ret = intel_guc_slpc_set_power_profile(slpc, slpc->power_profile); |
| 791 | + if (unlikely(ret)) { |
| 792 | + guc_probe_error(guc, "Failed to set SLPC power profile: %pe\n", ERR_PTR(ret)); |
| 793 | + return ret; |
| 794 | + } |
| 795 | + |
731 | 796 | return 0; |
732 | 797 | } |
733 | 798 |
|
|
0 commit comments