diff mbox

[3/4] drm/i915: Allow controlling idle frequency from userspace

Message ID 1463493186-10582-3-git-send-email-michal.winiarski@intel.com (mailing list archive)
State New, archived
Headers show

Commit Message

MichaƂ Winiarski May 17, 2016, 1:53 p.m. UTC
Since commit aed242ff7ebb697e4dff912bd4dc7ec7192f7581
Author: Chris Wilson <chris@chris-wilson.co.uk>
Date:   Wed Mar 18 09:48:21 2015 +0000

    drm/i915: Relax RPS contraints to allows setting minfreq on idle

When we idle, we set the GPU frequency to the hardware minimum (not user
minimum).

Let's add sysfs/debugfs knobs allowing userspace to control idle
frequency, similar to softmin/softmax frequency.

Cc: Chris Wilson <chris@chris-wilson.co.uk>
Signed-off-by: Micha? Winiarski <michal.winiarski@intel.com>
---
 drivers/gpu/drm/i915/i915_debugfs.c | 69 ++++++++++++++++++++++++++++++++++++-
 drivers/gpu/drm/i915/i915_sysfs.c   | 69 ++++++++++++++++++++++++++++++++++++-
 drivers/gpu/drm/i915/intel_pm.c     | 20 ++++++-----
 3 files changed, 148 insertions(+), 10 deletions(-)
diff mbox

Patch

diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
index 24f4105..6988213 100644
--- a/drivers/gpu/drm/i915/i915_debugfs.c
+++ b/drivers/gpu/drm/i915/i915_debugfs.c
@@ -5050,7 +5050,9 @@  i915_min_freq_set(void *data, u64 val)
 	hw_max = dev_priv->rps.max_freq;
 	hw_min = dev_priv->rps.min_freq;
 
-	if (val < hw_min || val > hw_max || val > dev_priv->rps.max_freq_softlimit) {
+	if (val < hw_min || val > hw_max ||
+	    val > dev_priv->rps.max_freq_softlimit ||
+	    val < dev_priv->rps.idle_freq) {
 		mutex_unlock(&dev_priv->rps.hw_lock);
 		return -EINVAL;
 	}
@@ -5069,6 +5071,70 @@  DEFINE_SIMPLE_ATTRIBUTE(i915_min_freq_fops,
 			"%llu\n");
 
 static int
+i915_idle_freq_get(void *data, u64 *val)
+{
+	struct drm_device *dev = data;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	int ret;
+
+	if (INTEL_INFO(dev)->gen < 6)
+		return -ENODEV;
+
+	flush_delayed_work(&dev_priv->rps.delayed_resume_work);
+
+	ret = mutex_lock_interruptible(&dev_priv->rps.hw_lock);
+	if (ret)
+		return ret;
+
+	*val = intel_gpu_freq(dev_priv, dev_priv->rps.idle_freq);
+	mutex_unlock(&dev_priv->rps.hw_lock);
+
+	return 0;
+}
+
+static int
+i915_idle_freq_set(void *data, u64 val)
+{
+	struct drm_device *dev = data;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	u32 hw_max, hw_min;
+	int ret;
+
+	if (INTEL_INFO(dev)->gen < 6)
+		return -ENODEV;
+
+	flush_delayed_work(&dev_priv->rps.delayed_resume_work);
+
+	DRM_DEBUG_DRIVER("Manually setting idle freq to %llu\n", val);
+
+	ret = mutex_lock_interruptible(&dev_priv->rps.hw_lock);
+	if (ret)
+		return ret;
+
+	val = intel_freq_opcode(dev_priv, val);
+
+	hw_max = dev_priv->rps.max_freq;
+	hw_min = dev_priv->rps.min_freq;
+
+	if (val < hw_min || val > hw_max || val > dev_priv->rps.min_freq_softlimit) {
+		mutex_unlock(&dev_priv->rps.hw_lock);
+		return -EINVAL;
+	}
+
+	dev_priv->rps.idle_freq = val;
+
+	intel_set_rps(dev_priv, val);
+
+	mutex_unlock(&dev_priv->rps.hw_lock);
+
+	return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(i915_idle_freq_fops,
+			i915_idle_freq_get, i915_idle_freq_set,
+			"%llu\n");
+
+static int
 i915_cache_sharing_get(void *data, u64 *val)
 {
 	struct drm_device *dev = data;
@@ -5436,6 +5502,7 @@  static const struct i915_debugfs_files {
 	{"i915_wedged", &i915_wedged_fops},
 	{"i915_max_freq", &i915_max_freq_fops},
 	{"i915_min_freq", &i915_min_freq_fops},
+	{"i915_idle_freq", &i915_idle_freq_fops},
 	{"i915_cache_sharing", &i915_cache_sharing_fops},
 	{"i915_ring_stop", &i915_ring_stop_fops},
 	{"i915_ring_missed_irq", &i915_ring_missed_irq_fops},
diff --git a/drivers/gpu/drm/i915/i915_sysfs.c b/drivers/gpu/drm/i915/i915_sysfs.c
index 37b6444..1c6930a 100644
--- a/drivers/gpu/drm/i915/i915_sysfs.c
+++ b/drivers/gpu/drm/i915/i915_sysfs.c
@@ -445,7 +445,8 @@  static ssize_t gt_min_freq_mhz_store(struct device *kdev,
 
 	if (val < dev_priv->rps.min_freq ||
 	    val > dev_priv->rps.max_freq ||
-	    val > dev_priv->rps.max_freq_softlimit) {
+	    val > dev_priv->rps.max_freq_softlimit ||
+	    val < dev_priv->rps.idle_freq) {
 		mutex_unlock(&dev_priv->rps.hw_lock);
 		intel_runtime_pm_put(dev_priv);
 		return -EINVAL;
@@ -470,10 +471,74 @@  static ssize_t gt_min_freq_mhz_store(struct device *kdev,
 
 }
 
+static ssize_t gt_idle_freq_mhz_show(struct device *kdev, struct device_attribute *attr, char *buf)
+{
+	struct drm_minor *minor = dev_to_drm_minor(kdev);
+	struct drm_device *dev = minor->dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	int ret;
+
+	flush_delayed_work(&dev_priv->rps.delayed_resume_work);
+
+	mutex_lock(&dev_priv->rps.hw_lock);
+	ret = intel_gpu_freq(dev_priv, dev_priv->rps.idle_freq);
+	mutex_unlock(&dev_priv->rps.hw_lock);
+
+	return snprintf(buf, PAGE_SIZE, "%d\n", ret);
+}
+static ssize_t gt_idle_freq_mhz_store(struct device *kdev,
+				     struct device_attribute *attr,
+				     const char *buf, size_t count)
+{
+	struct drm_minor *minor = dev_to_drm_minor(kdev);
+	struct drm_device *dev = minor->dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	u32 val;
+	ssize_t ret;
+
+	ret = kstrtou32(buf, 0, &val);
+	if (ret)
+		return ret;
+
+	flush_delayed_work(&dev_priv->rps.delayed_resume_work);
+
+	intel_runtime_pm_get(dev_priv);
+
+	mutex_lock(&dev_priv->rps.hw_lock);
+
+	val = intel_freq_opcode(dev_priv, val);
+
+	if (val < dev_priv->rps.min_freq ||
+	    val > dev_priv->rps.max_freq ||
+	    val > dev_priv->rps.min_freq_softlimit) {
+		mutex_unlock(&dev_priv->rps.hw_lock);
+		intel_runtime_pm_put(dev_priv);
+		return -EINVAL;
+	}
+
+	dev_priv->rps.idle_freq = val;
+
+	val = clamp_t(int, dev_priv->rps.cur_freq,
+		      dev_priv->rps.min_freq_softlimit,
+		      dev_priv->rps.max_freq_softlimit);
+
+	/* We still need *_set_rps to process the new min_delay and
+	 * update the interrupt limits and PMINTRMSK even though
+	 * frequency request may be unchanged. */
+	intel_set_rps(dev_priv, val);
+
+	mutex_unlock(&dev_priv->rps.hw_lock);
+
+	intel_runtime_pm_put(dev_priv);
+
+	return count;
+}
+
 static DEVICE_ATTR(gt_act_freq_mhz, S_IRUGO, gt_act_freq_mhz_show, NULL);
 static DEVICE_ATTR(gt_cur_freq_mhz, S_IRUGO, gt_cur_freq_mhz_show, NULL);
 static DEVICE_ATTR(gt_max_freq_mhz, S_IRUGO | S_IWUSR, gt_max_freq_mhz_show, gt_max_freq_mhz_store);
 static DEVICE_ATTR(gt_min_freq_mhz, S_IRUGO | S_IWUSR, gt_min_freq_mhz_show, gt_min_freq_mhz_store);
+static DEVICE_ATTR(gt_idl_freq_mhz, S_IRUGO | S_IWUSR, gt_idle_freq_mhz_show, gt_idle_freq_mhz_store);
 
 static DEVICE_ATTR(vlv_rpe_freq_mhz, S_IRUGO, vlv_rpe_freq_mhz_show, NULL);
 
@@ -507,6 +572,7 @@  static const struct attribute *gen6_attrs[] = {
 	&dev_attr_gt_cur_freq_mhz.attr,
 	&dev_attr_gt_max_freq_mhz.attr,
 	&dev_attr_gt_min_freq_mhz.attr,
+	&dev_attr_gt_idl_freq_mhz.attr,
 	&dev_attr_gt_RP0_freq_mhz.attr,
 	&dev_attr_gt_RP1_freq_mhz.attr,
 	&dev_attr_gt_RPn_freq_mhz.attr,
@@ -518,6 +584,7 @@  static const struct attribute *vlv_attrs[] = {
 	&dev_attr_gt_cur_freq_mhz.attr,
 	&dev_attr_gt_max_freq_mhz.attr,
 	&dev_attr_gt_min_freq_mhz.attr,
+	&dev_attr_gt_idl_freq_mhz.attr,
 	&dev_attr_gt_RP0_freq_mhz.attr,
 	&dev_attr_gt_RP1_freq_mhz.attr,
 	&dev_attr_gt_RPn_freq_mhz.attr,
diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
index 287a885..1f84f21 100644
--- a/drivers/gpu/drm/i915/intel_pm.c
+++ b/drivers/gpu/drm/i915/intel_pm.c
@@ -4954,12 +4954,13 @@  static void gen6_init_rps_frequencies(struct drm_i915_private *dev_priv)
 		dev_priv->rps.efficient_freq *= GEN9_FREQ_SCALER;
 	}
 
-	dev_priv->rps.idle_freq = dev_priv->rps.min_freq;
-
-	/* Preserve min/max settings in case of re-init */
+	/* Preserve min/max/idle settings in case of re-init */
 	if (dev_priv->rps.max_freq_softlimit == 0)
 		dev_priv->rps.max_freq_softlimit = dev_priv->rps.max_freq;
 
+	if (dev_priv->rps.idle_freq == 0)
+		dev_priv->rps.idle_freq = dev_priv->rps.min_freq;
+
 	if (dev_priv->rps.min_freq_softlimit == 0) {
 		if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv))
 			dev_priv->rps.min_freq_softlimit =
@@ -5612,12 +5613,14 @@  static void valleyview_init_gt_powersave(struct drm_i915_private *dev_priv)
 			 intel_gpu_freq(dev_priv, dev_priv->rps.min_freq),
 			 dev_priv->rps.min_freq);
 
-	dev_priv->rps.idle_freq = dev_priv->rps.min_freq;
 
-	/* Preserve min/max settings in case of re-init */
+	/* Preserve min/max/idle settings in case of re-init */
 	if (dev_priv->rps.max_freq_softlimit == 0)
 		dev_priv->rps.max_freq_softlimit = dev_priv->rps.max_freq;
 
+	if (dev_priv->rps.idle_freq == 0)
+		dev_priv->rps.idle_freq = dev_priv->rps.min_freq;
+
 	if (dev_priv->rps.min_freq_softlimit == 0)
 		dev_priv->rps.min_freq_softlimit = dev_priv->rps.min_freq;
 
@@ -5676,12 +5679,13 @@  static void cherryview_init_gt_powersave(struct drm_i915_private *dev_priv)
 		   dev_priv->rps.min_freq) & 1,
 		  "Odd GPU freq values\n");
 
-	dev_priv->rps.idle_freq = dev_priv->rps.min_freq;
-
-	/* Preserve min/max settings in case of re-init */
+	/* Preserve min/max/idle settings in case of re-init */
 	if (dev_priv->rps.max_freq_softlimit == 0)
 		dev_priv->rps.max_freq_softlimit = dev_priv->rps.max_freq;
 
+	if (dev_priv->rps.idle_freq == 0)
+		dev_priv->rps.idle_freq = dev_priv->rps.min_freq;
+
 	if (dev_priv->rps.min_freq_softlimit == 0)
 		dev_priv->rps.min_freq_softlimit = dev_priv->rps.min_freq;