This allows to enable/disable rps and rc6 from userspace. This is necessary for to have predictable results from hardware counters, and also to provide a finer granularity over power control from userspace. As an additional trick, we also change the value of i915_enable_rc6 by using this value, to allow the module to know the latest status of rc6 requested by user. Signed-off-by: Eugeni Dodonov <eugeni.dodonov at intel.com> --- drivers/gpu/drm/i915/i915_debugfs.c | 101 ++++++++++++++++++++++++++++++++++ drivers/gpu/drm/i915/intel_display.c | 2 +- drivers/gpu/drm/i915/intel_drv.h | 3 + 3 files changed, 105 insertions(+), 1 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 4f40f1c..dffc998 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -1340,6 +1340,79 @@ static const struct file_operations i915_wedged_fops = { }; static int +i915_enable_rc6_open(struct inode *inode, + struct file *filp) +{ + filp->private_data = inode->i_private; + return 0; +} + +static ssize_t +i915_enable_rc6_read(struct file *filp, + char __user *ubuf, + size_t max, + loff_t *ppos) +{ + char buf[80]; + int len; + + len = snprintf(buf, sizeof(buf), + "%d\n", i915_enable_rc6); + + if (len > sizeof(buf)) + len = sizeof(buf); + + return simple_read_from_buffer(ubuf, max, ppos, buf, len); +} + +static ssize_t +i915_enable_rc6_write(struct file *filp, + const char __user *ubuf, + size_t cnt, + loff_t *ppos) +{ + struct drm_device *dev = filp->private_data; + struct drm_i915_private *dev_priv = dev->dev_private; + char buf[20]; + int val = -1; + + if (cnt > 0) { + if (cnt > sizeof(buf) - 1) + return -EINVAL; + + if (copy_from_user(buf, ubuf, cnt)) + return -EFAULT; + buf[cnt] = 0; + + val = simple_strtol(buf, NULL, 0); + } + + if (INTEL_INFO(dev)->gen < 5) + return cnt; + + DRM_DEBUG_DRIVER("Manually setting rps and rc6 status to %d\n", val); + i915_enable_rc6 = val; + + if (val == 0) { + if (IS_IRONLAKE_M(dev)) + ironlake_disable_rc6(dev); + else { + gen6_disable_rps(dev); + gen6_update_ring_freq(dev_priv); + } + } else { + if (IS_IRONLAKE_M(dev)) + ironlake_disable_rc6(dev); + else { + gen6_enable_rps(dev_priv); + gen6_update_ring_freq(dev_priv); + } + } + + return cnt; +} + +static int i915_max_freq_open(struct inode *inode, struct file *filp) { @@ -1401,6 +1474,14 @@ i915_max_freq_write(struct file *filp, return cnt; } +static const struct file_operations i915_enable_rc6_fops = { + .owner = THIS_MODULE, + .open = i915_enable_rc6_open, + .read = i915_enable_rc6_read, + .write = i915_enable_rc6_write, + .llseek = default_llseek, +}; + static const struct file_operations i915_max_freq_fops = { .owner = THIS_MODULE, .open = i915_max_freq_open, @@ -1605,6 +1686,21 @@ static int i915_max_freq_create(struct dentry *root, struct drm_minor *minor) return drm_add_fake_info_node(minor, ent, &i915_max_freq_fops); } +static int i915_enable_rc6_create(struct dentry *root, struct drm_minor *minor) +{ + struct drm_device *dev = minor->dev; + struct dentry *ent; + + ent = debugfs_create_file("i915_enable_rc6", + S_IRUGO | S_IWUSR, + root, dev, + &i915_enable_rc6_fops); + if (IS_ERR(ent)) + return PTR_ERR(ent); + + return drm_add_fake_info_node(minor, ent, &i915_enable_rc6_fops); +} + static int i915_cache_sharing_create(struct dentry *root, struct drm_minor *minor) { struct drm_device *dev = minor->dev; @@ -1676,6 +1772,9 @@ int i915_debugfs_init(struct drm_minor *minor) ret = i915_max_freq_create(minor->debugfs_root, minor); if (ret) return ret; + ret = i915_enable_rc6_create(minor->debugfs_root, minor); + if (ret) + return ret; ret = i915_cache_sharing_create(minor->debugfs_root, minor); if (ret) return ret; @@ -1695,6 +1794,8 @@ void i915_debugfs_cleanup(struct drm_minor *minor) 1, minor); drm_debugfs_remove_files((struct drm_info_list *) &i915_max_freq_fops, 1, minor); + drm_debugfs_remove_files((struct drm_info_list *) &i915_enable_rc6_fops, + 1, minor); drm_debugfs_remove_files((struct drm_info_list *) &i915_cache_sharing_fops, 1, minor); } diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index d1e5726..cb15c8a 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -8311,7 +8311,7 @@ static void ironlake_teardown_rc6(struct drm_device *dev) } } -static void ironlake_disable_rc6(struct drm_device *dev) +void ironlake_disable_rc6(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index bd9a604..ce11cc3 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -353,6 +353,9 @@ extern void gen6_update_ring_freq(struct drm_i915_private *dev_priv); extern void gen6_disable_rps(struct drm_device *dev); extern void intel_init_emon(struct drm_device *dev); +extern void ironlake_enable_rc6(struct drm_device *dev); +extern void ironlake_disable_rc6(struct drm_device *dev); + extern int intel_pin_and_fence_fb_obj(struct drm_device *dev, struct drm_i915_gem_object *obj, struct intel_ring_buffer *pipelined); -- 1.7.7.4