@@ -343,10 +343,20 @@ static ssize_t vlv_rpe_freq_mhz_show(struct device *kdev,
static ssize_t gt_max_freq_mhz_show(struct device *kdev, struct device_attribute *attr, char *buf)
{
struct drm_i915_private *dev_priv = kdev_minor_to_i915(kdev);
+ struct intel_guc_slpc *slpc = &dev_priv->guc.slpc;
+ u32 freq;
- return snprintf(buf, PAGE_SIZE, "%d\n",
- intel_gpu_freq(dev_priv,
- dev_priv->gt_pm.rps.max_freq_softlimit));
+ if (USES_GUC_SLPC(dev_priv)) {
+ mutex_lock(&slpc->lock);
+ freq = dev_priv->guc.slpc.max_unslice_freq;
+ mutex_unlock(&slpc->lock);
+ } else {
+ mutex_lock(&dev_priv->pcu_lock);
+ freq = dev_priv->gt_pm.rps.max_freq_softlimit;
+ mutex_lock(&dev_priv->pcu_lock);
+ }
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", intel_gpu_freq(dev_priv, freq));
}
static ssize_t gt_max_freq_mhz_store(struct device *kdev,
@@ -362,12 +372,17 @@ static ssize_t gt_max_freq_mhz_store(struct device *kdev,
if (ret)
return ret;
+ val = intel_freq_opcode(dev_priv, val);
+
+ if (USES_GUC_SLPC(dev_priv)) {
+ ret = intel_guc_slpc_max_freq_set(&dev_priv->guc.slpc, val);
+ goto out;
+ }
+
intel_runtime_pm_get(dev_priv);
mutex_lock(&dev_priv->pcu_lock);
- val = intel_freq_opcode(dev_priv, val);
-
if (val < rps->min_freq ||
val > rps->max_freq ||
val < rps->min_freq_softlimit) {
@@ -395,16 +410,27 @@ static ssize_t gt_max_freq_mhz_store(struct device *kdev,
intel_runtime_pm_put(dev_priv);
+out:
return ret ?: count;
}
static ssize_t gt_min_freq_mhz_show(struct device *kdev, struct device_attribute *attr, char *buf)
{
struct drm_i915_private *dev_priv = kdev_minor_to_i915(kdev);
+ struct intel_guc_slpc *slpc = &dev_priv->guc.slpc;
+ u32 freq;
- return snprintf(buf, PAGE_SIZE, "%d\n",
- intel_gpu_freq(dev_priv,
- dev_priv->gt_pm.rps.min_freq_softlimit));
+ if (USES_GUC_SLPC(dev_priv)) {
+ mutex_lock(&slpc->lock);
+ freq = dev_priv->guc.slpc.min_unslice_freq;
+ mutex_unlock(&slpc->lock);
+ } else {
+ mutex_lock(&dev_priv->pcu_lock);
+ freq = dev_priv->gt_pm.rps.min_freq_softlimit;
+ mutex_lock(&dev_priv->pcu_lock);
+ }
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", intel_gpu_freq(dev_priv, freq));
}
static ssize_t gt_min_freq_mhz_store(struct device *kdev,
@@ -420,12 +446,17 @@ static ssize_t gt_min_freq_mhz_store(struct device *kdev,
if (ret)
return ret;
+ val = intel_freq_opcode(dev_priv, val);
+
+ if (USES_GUC_SLPC(dev_priv)) {
+ ret = intel_guc_slpc_min_freq_set(&dev_priv->guc.slpc, val);
+ goto out;
+ }
+
intel_runtime_pm_get(dev_priv);
mutex_lock(&dev_priv->pcu_lock);
- val = intel_freq_opcode(dev_priv, val);
-
if (val < rps->min_freq ||
val > rps->max_freq ||
val > rps->max_freq_softlimit) {
@@ -449,6 +480,7 @@ static ssize_t gt_min_freq_mhz_store(struct device *kdev,
intel_runtime_pm_put(dev_priv);
+out:
return ret ?: count;
}
@@ -630,7 +630,7 @@ int intel_guc_slpc_init(struct intel_guc_slpc *slpc)
*/
int intel_guc_slpc_enable(struct intel_guc_slpc *slpc)
{
- struct slpc_shared_data *data;
+ struct slpc_shared_data *data, output;
struct page *page;
mutex_lock(&slpc->lock);
@@ -652,7 +652,91 @@ int intel_guc_slpc_enable(struct intel_guc_slpc *slpc)
DRM_INFO("SLPC state: %s\n", slpc_get_state(slpc));
+ slpc_read_shared_data(slpc, &output);
+ slpc->max_unslice_freq = output.task_state_data.max_unslice_freq *
+ GEN9_FREQ_SCALER;
+ slpc->min_unslice_freq = output.task_state_data.min_unslice_freq *
+ GEN9_FREQ_SCALER;
+
+ mutex_unlock(&slpc->lock);
+
+ return 0;
+}
+
+/**
+ * intel_guc_slpc_max_freq_set() - Set max frequency limit for SLPC.
+ * @slpc: pointer to intel_guc_slpc.
+ * @val: encoded frequency
+ *
+ * This function will invoke GuC SLPC action to update the max frequency
+ * limit.
+ *
+ * Return: 0 on success, non-zero error code on failure.
+ */
+int intel_guc_slpc_max_freq_set(struct intel_guc_slpc *slpc, u32 val)
+{
+ struct intel_guc *guc = slpc_to_guc(slpc);
+ struct drm_i915_private *dev_priv = guc_to_i915(guc);
+
+ if (val < dev_priv->gt_pm.rps.min_freq ||
+ val > dev_priv->gt_pm.rps.max_freq ||
+ val < slpc->min_unslice_freq)
+ return -EINVAL;
+
+ intel_runtime_pm_get(dev_priv);
+ mutex_lock(&slpc->lock);
+
+ slpc_set_param(slpc,
+ SLPC_PARAM_GLOBAL_MAX_GT_UNSLICE_FREQ_MHZ,
+ intel_gpu_freq(dev_priv, val));
+ slpc_set_param(slpc,
+ SLPC_PARAM_GLOBAL_MAX_GT_SLICE_FREQ_MHZ,
+ intel_gpu_freq(dev_priv, val));
+
+ host2guc_slpc_reset(slpc);
+ slpc->max_unslice_freq = val;
+
+ mutex_unlock(&slpc->lock);
+ intel_runtime_pm_put(dev_priv);
+
+ return 0;
+}
+
+/**
+ * intel_guc_slpc_min_freq_set() - Set min frequency limit for SLPC.
+ * @slpc: pointer to intel_guc_slpc.
+ * @val: encoded frequency
+ *
+ * This function will invoke GuC SLPC action to update the min frequency
+ * limit.
+ *
+ * Return: 0 on success, non-zero error code on failure.
+ */
+int intel_guc_slpc_min_freq_set(struct intel_guc_slpc *slpc, u32 val)
+{
+ struct intel_guc *guc = slpc_to_guc(slpc);
+ struct drm_i915_private *dev_priv = guc_to_i915(guc);
+
+ if (val < dev_priv->gt_pm.rps.min_freq ||
+ val > dev_priv->gt_pm.rps.max_freq ||
+ val > slpc->max_unslice_freq)
+ return -EINVAL;
+
+ intel_runtime_pm_get(dev_priv);
+ mutex_lock(&slpc->lock);
+
+ slpc_set_param(slpc,
+ SLPC_PARAM_GLOBAL_MIN_GT_UNSLICE_FREQ_MHZ,
+ intel_gpu_freq(dev_priv, val));
+ slpc_set_param(slpc,
+ SLPC_PARAM_GLOBAL_MIN_GT_SLICE_FREQ_MHZ,
+ intel_gpu_freq(dev_priv, val));
+
+ host2guc_slpc_reset(slpc);
+ slpc->min_unslice_freq = val;
+
mutex_unlock(&slpc->lock);
+ intel_runtime_pm_put(dev_priv);
return 0;
}
@@ -12,6 +12,10 @@ struct intel_guc_slpc {
/* Protects access to vma and SLPC actions */
struct mutex lock;
struct i915_vma *vma;
+
+ /* i915 cached SLPC frequency limits */
+ u32 min_unslice_freq;
+ u32 max_unslice_freq;
};
int intel_guc_slpc_task_control(struct intel_guc_slpc *slpc, u64 val,
@@ -21,6 +25,8 @@ int intel_guc_slpc_task_status(struct intel_guc_slpc *slpc, u64 *val,
int intel_guc_slpc_init(struct intel_guc_slpc *slpc);
int intel_guc_slpc_enable(struct intel_guc_slpc *slpc);
+int intel_guc_slpc_max_freq_set(struct intel_guc_slpc *slpc, u32 val);
+int intel_guc_slpc_min_freq_set(struct intel_guc_slpc *slpc, u32 val);
void intel_guc_slpc_handle_engine_reset(struct intel_guc_slpc *slpc);
void intel_guc_slpc_disable(struct intel_guc_slpc *slpc);
void intel_guc_slpc_fini(struct intel_guc_slpc *slpc);
Update sysfs functions to set SLPC parameters when setting max/min user frequency limits. v1: Update for SLPC 2015.2.4 (params for both slice and unslice). Replace HAS_SLPC with intel_slpc_active() (Paulo) v2-v4: Rebase. v5: Removed typecasting the frequency values to u32. (Chris). Changed intel_slpc_active to guc.slpc.enabled. Carved out SLPC helpers to set min and max frequencies. v6: Rebase. Doing explicit SLPC reset on setting frequency to start sane and covered with RPM get/put. Caching SLPC limits post enabling first. v7: Rebase due to change in the dev_priv->pm.rps structure. v8: Updated returns from gt_min_freq_mhz_store and gt_max_freq_mhz_store and i915_min_freq_set and i915_max_freq_set. v9: Rebase. Debugfs interfaces will be removed hence only updated sysfs. Signed-off-by: Sagar Arun Kamble <sagar.a.kamble@intel.com> Cc: Chris Wilson <chris@chris-wilson.co.uk> Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Cc: Radoslaw Szwichtenberg <radoslaw.szwichtenberg@intel.com> Cc: Michal Wajdeczko <michal.wajdeczko@intel.com> Cc: Sujaritha Sundaresan <sujaritha.sundaresan@intel.com> Cc: Jeff McGee <jeff.mcgee@intel.com> --- drivers/gpu/drm/i915/i915_sysfs.c | 52 +++++++++++++++++---- drivers/gpu/drm/i915/intel_guc_slpc.c | 86 ++++++++++++++++++++++++++++++++++- drivers/gpu/drm/i915/intel_guc_slpc.h | 6 +++ 3 files changed, 133 insertions(+), 11 deletions(-)