[v12,11/17] drm/i915/guc/slpc: Add support for sysfs min/max frequency control
diff mbox

Message ID 1522398722-12161-12-git-send-email-sagar.a.kamble@intel.com
State New
Headers show

Commit Message

sagar.a.kamble@intel.com March 30, 2018, 8:31 a.m. UTC
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(-)

Patch
diff mbox

diff --git a/drivers/gpu/drm/i915/i915_sysfs.c b/drivers/gpu/drm/i915/i915_sysfs.c
index c3083fa..d1b4793 100644
--- a/drivers/gpu/drm/i915/i915_sysfs.c
+++ b/drivers/gpu/drm/i915/i915_sysfs.c
@@ -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;
 }
 
diff --git a/drivers/gpu/drm/i915/intel_guc_slpc.c b/drivers/gpu/drm/i915/intel_guc_slpc.c
index 011e442..34a5963 100644
--- a/drivers/gpu/drm/i915/intel_guc_slpc.c
+++ b/drivers/gpu/drm/i915/intel_guc_slpc.c
@@ -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;
 }
diff --git a/drivers/gpu/drm/i915/intel_guc_slpc.h b/drivers/gpu/drm/i915/intel_guc_slpc.h
index 87b504d..51189b3 100644
--- a/drivers/gpu/drm/i915/intel_guc_slpc.h
+++ b/drivers/gpu/drm/i915/intel_guc_slpc.h
@@ -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);