Merge rc6 information into the power group for our device. Until now the i915 driver has not had any sysfs entries (aside from the connector stuff enabled by drm core). Since it seems like we're likely to have more in the future I created a new file for sysfs stubs, as well as the rc6 sysfs functions which don't really belong elsewhere (perhaps i915_suspend, but most of the stuff is in intel_display,c). displays #ms GPU has been in rc6 since boot: cat /sys/class/drm/card0/power/rc6 displays #ms GPU has been in deep rc6 since boot: cat /sys/class/drm/card0/power/rc6p displays #ms GPU has been in deepest rc6 since boot: cat /sys/class/drm/card0/power/rc6pp Important note: I've seen on SNB that even when RC6 is *not* enabled the rc6 register seems to have a random value in it. I cannot explain a reason for this. Those writing tools that utilize this value need to be careful and probably want to scrutinize the value very carefully. Please see intel-gpu-tools patches for sample code. Untested on IVB. v2: use calc_residency units to milliseconds for the other RC6 types CC: Arjan van de Ven <arjan at linux.intel.com> Signed-off-by: Ben Widawsky <ben at bwidawsk.net> --- drivers/gpu/drm/i915/Makefile | 1 + drivers/gpu/drm/i915/i915_dma.c | 4 ++ drivers/gpu/drm/i915/i915_drv.h | 4 ++ drivers/gpu/drm/i915/i915_sysfs.c | 100 +++++++++++++++++++++++++++++++++++++ 4 files changed, 109 insertions(+) create mode 100644 drivers/gpu/drm/i915/i915_sysfs.c diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index ce7fc77..f801330 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -12,6 +12,7 @@ i915-y := i915_drv.o i915_dma.o i915_irq.o \ i915_gem_execbuffer.o \ i915_gem_gtt.o \ i915_gem_tiling.o \ + i915_sysfs.o \ i915_trace_points.o \ intel_display.o \ intel_crt.o \ diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index fdff009..64dfbb8 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -2113,6 +2113,8 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) } } + i915_setup_sysfs(dev); + /* Must be done after probing outputs */ intel_opregion_init(dev); acpi_video_register(); @@ -2164,6 +2166,8 @@ int i915_driver_unload(struct drm_device *dev) i915_mch_dev = NULL; spin_unlock(&mchdev_lock); + i915_teardown_sysfs(dev); + if (dev_priv->mm.inactive_shrinker.shrink) unregister_shrinker(&dev_priv->mm.inactive_shrinker); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 22ab4db..e267774 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1365,6 +1365,10 @@ extern int i915_restore_state(struct drm_device *dev); extern int i915_save_state(struct drm_device *dev); extern int i915_restore_state(struct drm_device *dev); +/* i915_sysfs.c */ +void i915_setup_sysfs(struct drm_device *dev_priv); +void i915_teardown_sysfs(struct drm_device *dev_priv); + /* intel_i2c.c */ extern int intel_setup_gmbus(struct drm_device *dev); extern void intel_teardown_gmbus(struct drm_device *dev); diff --git a/drivers/gpu/drm/i915/i915_sysfs.c b/drivers/gpu/drm/i915/i915_sysfs.c new file mode 100644 index 0000000..125d0cc --- /dev/null +++ b/drivers/gpu/drm/i915/i915_sysfs.c @@ -0,0 +1,100 @@ +/* + * Copyright ? 2012 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Authors: + * Ben Widawsky <ben at bwidawsk.net> + * + */ + +#include <linux/device.h> +#include <linux/module.h> +#include <linux/stat.h> +#include <linux/sysfs.h> +#include "i915_drv.h" + +static u32 calc_residency(struct drm_device *dev, const u32 reg) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + u64 raw_time; /* 32b value may overflow during fixed point math */ + u32 residency; + + if (!intel_enable_rc6(dev)) + return 0; + + raw_time = I915_READ(reg) * 128ULL; + residency = DIV_ROUND_CLOSEST(raw_time, 1000) / 100; + return residency; +} + +static ssize_t +show_rc6_ms(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct drm_minor *dminor = container_of(dev, struct drm_minor, kdev); + u32 rc6_residency = calc_residency(dminor->dev, GEN6_GT_GFX_RC6); + return snprintf(buf, PAGE_SIZE, "%u", rc6_residency); +} + +static ssize_t +show_rc6p_ms(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct drm_minor *dminor = container_of(dev, struct drm_minor, kdev); + u32 rc6p_residency = calc_residency(dminor->dev, GEN6_GT_GFX_RC6p); + return snprintf(buf, PAGE_SIZE, "%u", rc6p_residency); +} + +static ssize_t +show_rc6pp_ms(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct drm_minor *dminor = container_of(dev, struct drm_minor, kdev); + u32 rc6pp_residency = calc_residency(dminor->dev, GEN6_GT_GFX_RC6pp); + return snprintf(buf, PAGE_SIZE, "%u", rc6pp_residency); +} + +static DEVICE_ATTR(rc6, S_IRUGO, show_rc6_ms, NULL); +static DEVICE_ATTR(rc6p, S_IRUGO, show_rc6p_ms, NULL); +static DEVICE_ATTR(rc6pp, S_IRUGO, show_rc6pp_ms, NULL); + +static struct attribute *rc6_attrs[] = { + &dev_attr_rc6.attr, + &dev_attr_rc6p.attr, + &dev_attr_rc6pp.attr, + NULL +}; + +static struct attribute_group rc6_attr_group = { + .name = power_group_name, + .attrs = rc6_attrs +}; + +void i915_setup_sysfs(struct drm_device *dev) +{ + int ret; + + ret = sysfs_merge_group(&dev->primary->kdev.kobj, &rc6_attr_group); + if (ret) + DRM_ERROR("sysfs setup failed\n"); +} + +void i915_teardown_sysfs(struct drm_device *dev) +{ + sysfs_remove_group(&dev->primary->kdev.kobj, &rc6_attr_group); +} -- 1.7.9.4