drm/i915: rc6 in sysfs

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 rc6 modes enabled (as a hex mask):
cat /sys/class/drm/card0/power/rc6_enable

displays #ms GPU has been in rc6 since boot:
cat /sys/class/drm/card0/power/rc6_residency_ms

displays #ms GPU has been in deep rc6 since boot:
cat /sys/class/drm/card0/power/rc6p_residency_ms

displays #ms GPU has been in deepest rc6 since boot:
cat /sys/class/drm/card0/power/rc6pp_residency_ms

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 can only guess at the
reason reason for this. Those writing tools that utilize this value need
to be careful and probably want to scrutinize the value very carefully.

v2: use common rc6 residency units to milliseconds for the other RC6 types

v3: don't create sysfs files for GEN <= 5
add a rc6_enable to show a mask of enabled rc6 types
use unmerge instead of remove for sysfs group
squash intel_enable_rc6() extraction into this patch

v4: rename sysfs files (Chris)

CC: Chris Wilson <chris@chris-wilson.co.uk>
CC: Daniel Vetter <daniel.vetter@ffwll.ch>f
CC: Arjan van de Ven <arjan@linux.intel.com>
Signed-off-by: Ben Widawsky <benjamin.widawsky@intel.com>
Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk>
[danvet: squash in the 64bit division fix by Chris Wilson.]
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
This commit is contained in:
Ben Widawsky 2012-04-10 21:17:01 -07:00 committed by Daniel Vetter
parent d1686ae3ab
commit 0136db586c
5 changed files with 122 additions and 1 deletions

View File

@ -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 \

View File

@ -2139,6 +2139,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();
@ -2190,6 +2192,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);

View File

@ -1385,6 +1385,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);
@ -1441,6 +1445,7 @@ extern void ironlake_enable_rc6(struct drm_device *dev);
extern void gen6_set_rps(struct drm_device *dev, u8 val);
extern void intel_detect_pch(struct drm_device *dev);
extern int intel_trans_dp_port_sel(struct drm_crtc *crtc);
extern int intel_enable_rc6(const struct drm_device *dev);
extern bool i915_semaphore_is_enabled(struct drm_device *dev);
extern void __gen6_gt_force_wake_get(struct drm_i915_private *dev_priv);

View File

@ -0,0 +1,111 @@
/*
* 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@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 */
if (!intel_enable_rc6(dev))
return 0;
raw_time = I915_READ(reg) * 128ULL + 500;
return do_div(raw_time, 100000);
}
static ssize_t
show_rc6_mask(struct device *dev, struct device_attribute *attr, char *buf)
{
struct drm_minor *dminor = container_of(dev, struct drm_minor, kdev);
return snprintf(buf, PAGE_SIZE, "%x", intel_enable_rc6(dminor->dev));
}
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_enable, S_IRUGO, show_rc6_mask, NULL);
static DEVICE_ATTR(rc6_residency_ms, S_IRUGO, show_rc6_ms, NULL);
static DEVICE_ATTR(rc6p_residency_ms, S_IRUGO, show_rc6p_ms, NULL);
static DEVICE_ATTR(rc6pp_residency_ms, S_IRUGO, show_rc6pp_ms, NULL);
static struct attribute *rc6_attrs[] = {
&dev_attr_rc6_enable.attr,
&dev_attr_rc6_residency_ms.attr,
&dev_attr_rc6p_residency_ms.attr,
&dev_attr_rc6pp_residency_ms.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;
/* ILK doesn't have any residency information */
if (INTEL_INFO(dev)->gen < 6)
return;
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_unmerge_group(&dev->primary->kdev.kobj, &rc6_attr_group);
}

View File

@ -8547,7 +8547,7 @@ void intel_init_emon(struct drm_device *dev)
dev_priv->corr = (lcfuse & LCFUSE_HIV_MASK);
}
static int intel_enable_rc6(struct drm_device *dev)
int intel_enable_rc6(const struct drm_device *dev)
{
/*
* Respect the kernel parameter if it is set