@@ -96,6 +96,9 @@ int intel_guc_slpc_init(struct intel_guc_slpc *slpc)
9696 return err ;
9797 }
9898
99+ slpc -> max_freq_softlimit = 0 ;
100+ slpc -> min_freq_softlimit = 0 ;
101+
99102 return err ;
100103}
101104
@@ -126,6 +129,17 @@ static int guc_action_slpc_set_param(struct intel_guc *guc, u8 id, u32 value)
126129 return ret > 0 ? - EPROTO : ret ;
127130}
128131
132+ static int guc_action_slpc_unset_param (struct intel_guc * guc , u8 id )
133+ {
134+ u32 request [] = {
135+ GUC_ACTION_HOST2GUC_PC_SLPC_REQUEST ,
136+ SLPC_EVENT (SLPC_EVENT_PARAMETER_UNSET , 2 ),
137+ id ,
138+ };
139+
140+ return intel_guc_send (guc , request , ARRAY_SIZE (request ));
141+ }
142+
129143static bool slpc_is_running (struct intel_guc_slpc * slpc )
130144{
131145 return slpc_get_state (slpc ) == SLPC_GLOBAL_STATE_RUNNING ;
@@ -179,6 +193,16 @@ static int slpc_set_param(struct intel_guc_slpc *slpc, u8 id, u32 value)
179193 return ret ;
180194}
181195
196+ static int slpc_unset_param (struct intel_guc_slpc * slpc ,
197+ u8 id )
198+ {
199+ struct intel_guc * guc = slpc_to_guc (slpc );
200+
201+ GEM_BUG_ON (id >= SLPC_MAX_PARAM );
202+
203+ return guc_action_slpc_unset_param (guc , id );
204+ }
205+
182206static const char * slpc_global_state_to_string (enum slpc_global_state state )
183207{
184208 switch (state ) {
@@ -300,6 +324,11 @@ int intel_guc_slpc_set_max_freq(struct intel_guc_slpc *slpc, u32 val)
300324 intel_wakeref_t wakeref ;
301325 int ret ;
302326
327+ if (val < slpc -> min_freq ||
328+ val > slpc -> rp0_freq ||
329+ val < slpc -> min_freq_softlimit )
330+ return - EINVAL ;
331+
303332 with_intel_runtime_pm (& i915 -> runtime_pm , wakeref ) {
304333 ret = slpc_set_param (slpc ,
305334 SLPC_PARAM_GLOBAL_MAX_GT_UNSLICE_FREQ_MHZ ,
@@ -310,6 +339,9 @@ int intel_guc_slpc_set_max_freq(struct intel_guc_slpc *slpc, u32 val)
310339 ret = - EIO ;
311340 }
312341
342+ if (!ret )
343+ slpc -> max_freq_softlimit = val ;
344+
313345 return ret ;
314346}
315347
@@ -356,6 +388,11 @@ int intel_guc_slpc_set_min_freq(struct intel_guc_slpc *slpc, u32 val)
356388 intel_wakeref_t wakeref ;
357389 int ret ;
358390
391+ if (val < slpc -> min_freq ||
392+ val > slpc -> rp0_freq ||
393+ val > slpc -> max_freq_softlimit )
394+ return - EINVAL ;
395+
359396 with_intel_runtime_pm (& i915 -> runtime_pm , wakeref ) {
360397 ret = slpc_set_param (slpc ,
361398 SLPC_PARAM_GLOBAL_MIN_GT_UNSLICE_FREQ_MHZ ,
@@ -366,6 +403,9 @@ int intel_guc_slpc_set_min_freq(struct intel_guc_slpc *slpc, u32 val)
366403 ret = - EIO ;
367404 }
368405
406+ if (!ret )
407+ slpc -> min_freq_softlimit = val ;
408+
369409 return ret ;
370410}
371411
@@ -411,6 +451,79 @@ void intel_guc_pm_intrmsk_enable(struct intel_gt *gt)
411451 GEN6_PMINTRMSK , pm_intrmsk_mbz , 0 );
412452}
413453
454+ static int slpc_set_softlimits (struct intel_guc_slpc * slpc )
455+ {
456+ int ret = 0 ;
457+
458+ /*
459+ * Softlimits are initially equivalent to platform limits
460+ * unless they have deviated from defaults, in which case,
461+ * we retain the values and set min/max accordingly.
462+ */
463+ if (!slpc -> max_freq_softlimit )
464+ slpc -> max_freq_softlimit = slpc -> rp0_freq ;
465+ else if (slpc -> max_freq_softlimit != slpc -> rp0_freq )
466+ ret = intel_guc_slpc_set_max_freq (slpc ,
467+ slpc -> max_freq_softlimit );
468+
469+ if (unlikely (ret ))
470+ return ret ;
471+
472+ if (!slpc -> min_freq_softlimit )
473+ slpc -> min_freq_softlimit = slpc -> min_freq ;
474+ else if (slpc -> min_freq_softlimit != slpc -> min_freq )
475+ return intel_guc_slpc_set_min_freq (slpc ,
476+ slpc -> min_freq_softlimit );
477+
478+ return 0 ;
479+ }
480+
481+ static int slpc_ignore_eff_freq (struct intel_guc_slpc * slpc , bool ignore )
482+ {
483+ int ret = 0 ;
484+
485+ if (ignore ) {
486+ ret = slpc_set_param (slpc ,
487+ SLPC_PARAM_IGNORE_EFFICIENT_FREQUENCY ,
488+ ignore );
489+ if (!ret )
490+ return slpc_set_param (slpc ,
491+ SLPC_PARAM_GLOBAL_MIN_GT_UNSLICE_FREQ_MHZ ,
492+ slpc -> min_freq );
493+ } else {
494+ ret = slpc_unset_param (slpc ,
495+ SLPC_PARAM_IGNORE_EFFICIENT_FREQUENCY );
496+ if (!ret )
497+ return slpc_unset_param (slpc ,
498+ SLPC_PARAM_GLOBAL_MIN_GT_UNSLICE_FREQ_MHZ );
499+ }
500+
501+ return ret ;
502+ }
503+
504+ static int slpc_use_fused_rp0 (struct intel_guc_slpc * slpc )
505+ {
506+ /* Force SLPC to used platform rp0 */
507+ return slpc_set_param (slpc ,
508+ SLPC_PARAM_GLOBAL_MAX_GT_UNSLICE_FREQ_MHZ ,
509+ slpc -> rp0_freq );
510+ }
511+
512+ static void slpc_get_rp_values (struct intel_guc_slpc * slpc )
513+ {
514+ u32 rp_state_cap ;
515+
516+ rp_state_cap = intel_uncore_read (slpc_to_gt (slpc )-> uncore ,
517+ GEN6_RP_STATE_CAP );
518+
519+ slpc -> rp0_freq = REG_FIELD_GET (RP0_CAP_MASK , rp_state_cap ) *
520+ GT_FREQUENCY_MULTIPLIER ;
521+ slpc -> rp1_freq = REG_FIELD_GET (RP1_CAP_MASK , rp_state_cap ) *
522+ GT_FREQUENCY_MULTIPLIER ;
523+ slpc -> min_freq = REG_FIELD_GET (RPN_CAP_MASK , rp_state_cap ) *
524+ GT_FREQUENCY_MULTIPLIER ;
525+ }
526+
414527/*
415528 * intel_guc_slpc_enable() - Start SLPC
416529 * @slpc: pointer to intel_guc_slpc.
@@ -446,6 +559,32 @@ int intel_guc_slpc_enable(struct intel_guc_slpc *slpc)
446559
447560 intel_guc_pm_intrmsk_enable (& i915 -> gt );
448561
562+ slpc_get_rp_values (slpc );
563+
564+ /* Ignore efficient freq and set min to platform min */
565+ ret = slpc_ignore_eff_freq (slpc , true);
566+ if (unlikely (ret )) {
567+ drm_err (& i915 -> drm , "Failed to set SLPC min to RPn (%pe)\n" ,
568+ ERR_PTR (ret ));
569+ return ret ;
570+ }
571+
572+ /* Set SLPC max limit to RP0 */
573+ ret = slpc_use_fused_rp0 (slpc );
574+ if (unlikely (ret )) {
575+ drm_err (& i915 -> drm , "Failed to set SLPC max to RP0 (%pe)\n" ,
576+ ERR_PTR (ret ));
577+ return ret ;
578+ }
579+
580+ /* Revert SLPC min/max to softlimits if necessary */
581+ ret = slpc_set_softlimits (slpc );
582+ if (unlikely (ret )) {
583+ drm_err (& i915 -> drm , "Failed to set SLPC softlimits (%pe)\n" ,
584+ ERR_PTR (ret ));
585+ return ret ;
586+ }
587+
449588 return 0 ;
450589}
451590
0 commit comments