With the lock in place we can expose ips enabled/disable on sysfs for developing, debugging and information purposes.
The main goal is to have an informative tab at powertop that expose the current status of power features in our driver. So let's start with this IPS one. Please remind that powertop has no access to drm properties so sysfs will be used as it is currently used for RC6. Signed-off-by: Rodrigo Vivi <rodrigo.v...@intel.com> --- drivers/gpu/drm/i915/i915_sysfs.c | 83 +++++++++++++++++++++++++++++++++++++++ drivers/gpu/drm/i915/intel_drv.h | 4 +- drivers/gpu/drm/i915/intel_ips.c | 25 +++++++++--- 3 files changed, 105 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_sysfs.c b/drivers/gpu/drm/i915/i915_sysfs.c index 50ce9ce..2d092c1 100644 --- a/drivers/gpu/drm/i915/i915_sysfs.c +++ b/drivers/gpu/drm/i915/i915_sysfs.c @@ -35,6 +35,82 @@ #define dev_to_drm_minor(d) dev_get_drvdata((d)) #ifdef CONFIG_PM + +static ssize_t +ips_show(struct device *kdev, struct device_attribute *attr, char *buf) +{ + struct drm_minor *dminor = dev_to_drm_minor(kdev); + struct drm_device *dev = dminor->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + ssize_t ret; + + mutex_lock(&dev_priv->display_ips.lock); + ret = snprintf(buf, PAGE_SIZE, "%s\n", dev_priv->display_ips.enabled ? + "enabled" : "disabled"); + mutex_unlock(&dev_priv->display_ips.lock); + + return ret; +} + + +static ssize_t +ips_toggle(struct device *kdev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct drm_minor *dminor = dev_to_drm_minor(kdev); + struct drm_device *dev = dminor->dev; + struct intel_connector *connector; + struct intel_encoder *encoder; + struct intel_crtc *crtc = NULL; + u32 val; + ssize_t ret; + + ret = kstrtou32(buf, 0, &val); + if (ret) + return ret; + + for_each_intel_connector(dev, connector) { + if (!connector->base.encoder) + continue; + encoder = to_intel_encoder(connector->base.encoder); + crtc = to_intel_crtc(encoder->base.crtc); + } + + if (!crtc) + return -ENODEV; + + switch (val) { + case 0: + ret = intel_ips_disable(crtc); + if (ret) + return ret; + break; + case 1: + ret = intel_ips_enable(crtc); + if (ret) + return ret; + break; + default: + return -EINVAL; + } + + return count; + + +} + +static DEVICE_ATTR(ips_enable, S_IRUGO | S_IWUSR, ips_show, ips_toggle); + +static struct attribute *ips_attrs[] = { + &dev_attr_ips_enable.attr, + NULL +}; + +static struct attribute_group ips_attr_group = { + .name = power_group_name, + .attrs = ips_attrs +}; + static u32 calc_residency(struct drm_device *dev, const u32 reg) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -585,6 +661,12 @@ void i915_setup_sysfs(struct drm_device *dev) int ret; #ifdef CONFIG_PM + if (HAS_IPS(dev)) { + ret = sysfs_merge_group(&dev->primary->kdev->kobj, + &ips_attr_group); + if (ret) + DRM_ERROR("IPS sysfs setup failed\n"); + } if (HAS_RC6(dev)) { ret = sysfs_merge_group(&dev->primary->kdev->kobj, &rc6_attr_group); @@ -641,6 +723,7 @@ void i915_teardown_sysfs(struct drm_device *dev) device_remove_bin_file(dev->primary->kdev, &dpf_attrs_1); device_remove_bin_file(dev->primary->kdev, &dpf_attrs); #ifdef CONFIG_PM + sysfs_unmerge_group(&dev->primary->kdev->kobj, &ips_attr_group); sysfs_unmerge_group(&dev->primary->kdev->kobj, &rc6_attr_group); sysfs_unmerge_group(&dev->primary->kdev->kobj, &rc6p_attr_group); #endif diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 04c1fc4..6f0b359 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1209,8 +1209,8 @@ u32 skl_plane_ctl_rotation(unsigned int rotation); /* intel_ips.c */ bool intel_ips_ready(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state); -void intel_ips_enable(struct intel_crtc *crtc); -void intel_ips_disable(struct intel_crtc *crtc); +int intel_ips_enable(struct intel_crtc *crtc); +int intel_ips_disable(struct intel_crtc *crtc); void intel_ips_disable_if_alone(struct intel_crtc *crtc); void intel_ips_init(struct drm_i915_private *dev_priv); diff --git a/drivers/gpu/drm/i915/intel_ips.c b/drivers/gpu/drm/i915/intel_ips.c index b867aba..6bc5c55 100644 --- a/drivers/gpu/drm/i915/intel_ips.c +++ b/drivers/gpu/drm/i915/intel_ips.c @@ -105,18 +105,21 @@ bool intel_ips_ready(struct intel_crtc *crtc, * This function is called to enable IPS on certain pipe. * All needed conditions should've checked already by intel_ips_ready. */ -void intel_ips_enable(struct intel_crtc *crtc) +int intel_ips_enable(struct intel_crtc *crtc) { struct drm_device *dev = crtc->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; + int ret = 0; if (!crtc->config->ips_ready) - return; + return -EINVAL; mutex_lock(&dev_priv->display_ips.lock); - if (dev_priv->display_ips.enabled) + if (dev_priv->display_ips.enabled) { + ret = -EALREADY; goto out; + } /* * We can only enable IPS after we enable a plane @@ -147,6 +150,7 @@ void intel_ips_enable(struct intel_crtc *crtc) */ if (wait_for(I915_READ_NOTRACE(IPS_CTL) & IPS_ENABLE, 50)) { DRM_ERROR("Timed out waiting for IPS enable\n"); + ret = -ETIMEDOUT; goto out; } } @@ -154,6 +158,7 @@ void intel_ips_enable(struct intel_crtc *crtc) dev_priv->display_ips.enabled = true; out: mutex_unlock(&dev_priv->display_ips.lock); + return ret; } /** @@ -162,16 +167,22 @@ out: * * This function is called to disable IPS on certain pipe whenever it is needed * to disable IPS on the pipe. + * + * Returns: + * 0 on success and -errno otherwise. */ -void intel_ips_disable(struct intel_crtc *crtc) +int intel_ips_disable(struct intel_crtc *crtc) { struct drm_device *dev = crtc->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; + int ret = 0; mutex_lock(&dev_priv->display_ips.lock); - if (!dev_priv->display_ips.enabled) + if (!dev_priv->display_ips.enabled) { + ret = -EALREADY; goto out; + } assert_plane_enabled(dev_priv, crtc->plane); if (IS_BROADWELL(dev)) { @@ -196,6 +207,7 @@ void intel_ips_disable(struct intel_crtc *crtc) dev_priv->display_ips.enabled = false; out: mutex_unlock(&dev_priv->display_ips.lock); + return ret; } /** @@ -206,6 +218,9 @@ out: * It checks if there is any other plane enabled on the pipe when primary is * going to be disabled. In this case IPS can continue enabled, but it needs * to be disabled otherwise. + * + * Returns: + * 0 on success and -errno otherwise. */ void intel_ips_disable_if_alone(struct intel_crtc *crtc) { -- 2.4.3 _______________________________________________ Intel-gfx mailing list Intel-gfx@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/intel-gfx