I sent stale patches, but this is the only one with a big effect. See inline for what's fixed, and feel free to review the rest. On Sat, 24 Mar 2012 19:09:46 -0700 Ben Widawsky <ben at bwidawsk.net> wrote: > 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 libdrm). 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. > > 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_debugfs.c | 2 +- > drivers/gpu/drm/i915/i915_dma.c | 4 ++ > drivers/gpu/drm/i915/i915_drv.h | 4 ++ > drivers/gpu/drm/i915/i915_sysfs.c | 106 > +++++++++++++++++++++++++++++++++++ 5 files changed, 116 > insertions(+), 1 deletion(-) 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_debugfs.c > b/drivers/gpu/drm/i915/i915_debugfs.c index 72457ff..4257151 100644 > --- a/drivers/gpu/drm/i915/i915_debugfs.c > +++ b/drivers/gpu/drm/i915/i915_debugfs.c > @@ -1134,9 +1134,9 @@ static int gen6_drpc_info(struct seq_file *m) > seq_printf(m, "Core Power Down: %s\n", > yesno(gt_core_status & GEN6_CORE_CPD_STATE_MASK)); > > + /* Not exactly sure what this is */ > seq_printf(m, "RC6 \"Locked to RPn\" residency since boot: > %d\n", I915_READ(GEN6_GT_GFX_RC6_LOCKED)); > - /* Not exactly sure what this is */ > seq_printf(m, "RC6 residency since boot: %d\n", > I915_READ(GEN6_GT_GFX_RC6)); > seq_printf(m, "RC6+ residency since boot: %d\n", This hunk should be rebased on patch 1... my bad. I'll fix after waiting on some review. > 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..a18a955f > --- /dev/null > +++ b/drivers/gpu/drm/i915/i915_sysfs.c > @@ -0,0 +1,106 @@ > +/* > + * 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; > + 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_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 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); > + struct drm_i915_private *dev_priv = dminor->dev->dev_private; > + /* 32b value may overflow during fixed point math */ > + u64 time = (I915_READ(GEN6_GT_GFX_RC6) * 128); > + u32 rc6_residency = DIV_ROUND_CLOSEST(time, 1000) / 100; > + 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); > + struct drm_i915_private *dev_priv = dminor->dev->dev_private; > + /* 32b value may overflow during fixed point math */ > + u64 time = (I915_READ(GEN6_GT_GFX_RC6p) * 128); > + u32 rc6p_residency = DIV_ROUND_CLOSEST(time, 1000) / 100; > + return snprintf(buf, PAGE_SIZE, "%u", rc6p_residency); > +} These all use calc_residenc() in the newer patch. Again will wait on some review before fixing. > + > +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); +}