drm/i915: rc6 in sysfs
authorBen Widawsky <ben@bwidawsk.net>
Wed, 11 Apr 2012 04:17:01 +0000 (21:17 -0700)
committerDaniel Vetter <daniel.vetter@ffwll.ch>
Thu, 12 Apr 2012 19:14:09 +0000 (21:14 +0200)
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>
drivers/gpu/drm/i915/Makefile
drivers/gpu/drm/i915/i915_dma.c
drivers/gpu/drm/i915/i915_drv.h
drivers/gpu/drm/i915/i915_sysfs.c [new file with mode: 0644]
drivers/gpu/drm/i915/intel_display.c

index ce7fc77678b4ce00e6eae112166af5773c44bb0a..f8013302581f959fb4b08883ff1f1e1aa7a2e366 100644 (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 \
index 652f43f00ef2b7405eeb43312edf5c1cc7c47e35..333b7468c8ecb5860fcfb2757353a22712eccf52 100644 (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);
 
index 7dcdccb5580ea464f59387e521cfcfde13df4dbd..a189f756036f70a14eba4eb824354a1b39e98d62 100644 (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);
diff --git a/drivers/gpu/drm/i915/i915_sysfs.c b/drivers/gpu/drm/i915/i915_sysfs.c
new file mode 100644 (file)
index 0000000..f1b5108
--- /dev/null
@@ -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);
+}
index 42dbe147560268d63e40e680a705eff1f7179b49..5b8b3d15d0ee2843fa05c19e84201ef3991a87a0 100644 (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