@@ -1088,27 +1088,59 @@ static int i915_sr_status(struct seq_file *m, void *unused)
return 0;
}
+/* Return current power draw in mW */
+static unsigned long i915_cur_power(struct drm_device *dev)
+{
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ u32 pkg_power, units, tunit, eunit, punit;
+ unsigned long energy, time;
+
+ units = I915_READ(GEN6_PKG_POWER_SKU_UNIT);
+ pkg_power = I915_READ(GEN6_PKG_ENERGY_STATUS);
+
+ tunit = (units >> 16) & 0xf; /* 1s / 2^tunit */
+ eunit = (units >> 8) & 0x1f; /* 1J / 2^enuit */
+ punit = units & 0xf; /* 1W / 2^punit */
+
+ energy = pkg_power - dev_priv->last_pkg_power;
+ time = jiffies_to_msecs(jiffies) - dev_priv->last_pkg_power_time;
+ energy /= (1 << (eunit - 10));
+
+ dev_priv->last_pkg_power = pkg_power;
+ dev_priv->last_pkg_power_time = jiffies_to_msecs(jiffies);
+
+ return (energy * 1000) / time;
+}
+
static int i915_emon_status(struct seq_file *m, void *unused)
{
struct drm_info_node *node = (struct drm_info_node *) m->private;
struct drm_device *dev = node->minor->dev;
drm_i915_private_t *dev_priv = dev->dev_private;
- unsigned long temp, chipset, gfx;
int ret;
ret = mutex_lock_interruptible(&dev->struct_mutex);
if (ret)
return ret;
- temp = i915_mch_val(dev_priv);
- chipset = i915_chipset_val(dev_priv);
- gfx = i915_gfx_val(dev_priv);
- mutex_unlock(&dev->struct_mutex);
+ if (IS_GEN5(dev)) {
+ unsigned long temp, chipset, gfx;
+
+ temp = i915_mch_val(dev_priv);
+ chipset = i915_chipset_val(dev_priv);
+ gfx = i915_gfx_val(dev_priv);
- seq_printf(m, "GMCH temp: %ld\n", temp);
- seq_printf(m, "Chipset power: %ld\n", chipset);
- seq_printf(m, "GFX power: %ld\n", gfx);
- seq_printf(m, "Total power: %ld\n", chipset + gfx);
+ seq_printf(m, "GMCH temp: %ld\n", temp);
+ seq_printf(m, "Chipset power: %ld\n", chipset);
+ seq_printf(m, "GFX power: %ld\n", gfx);
+ seq_printf(m, "Total power: %ld\n", chipset + gfx);
+ } else if (IS_GEN6(dev)) {
+ unsigned long power = i915_cur_power(dev);
+
+ trace_i915_pkg_power(power);
+ seq_printf(m, "Current power draw: %ldmW\n", power);
+ }
+ mutex_unlock(&dev->struct_mutex);
return 0;
}
@@ -697,6 +697,8 @@ typedef struct drm_i915_private {
int r_t;
u8 corr;
spinlock_t *mchdev_lock;
+ u32 last_pkg_power;
+ unsigned long last_pkg_power_time;
enum no_fbc_reason no_fbc_reason;
@@ -1244,6 +1244,9 @@
#define GEN6_RP_STATE_LIMITS 0x145994
#define GEN6_RP_STATE_CAP 0x145998
+#define GEN6_PKG_POWER_SKU_UNIT 0x145938
+#define GEN6_PKG_ENERGY_STATUS 0x14593c
+
/*
* Logical Context regs
*/
@@ -410,6 +410,20 @@ TRACE_EVENT(i915_reg_rw,
(u32)(__entry->val >> 32))
);
+TRACE_EVENT(i915_pkg_power,
+ TP_PROTO(unsigned long power),
+ TP_ARGS(power),
+ TP_STRUCT__entry(
+ __field(unsigned long, power)
+ ),
+
+ TP_fast_assign(
+ __entry->power = power;
+ ),
+
+ TP_printk("pkg power=%ld", __entry->power)
+);
+
#endif /* _I915_TRACE_H_ */
/* This part must be outside protection */
@@ -6959,6 +6959,9 @@ void gen6_enable_rps(struct drm_i915_private *dev_priv)
I915_WRITE(GEN6_PMINTRMSK, 0);
__gen6_force_wake_put(dev_priv);
+
+ dev_priv->last_pkg_power = I915_READ(GEN6_PKG_ENERGY_STATUS);
+ dev_priv->last_pkg_power_time = jiffies_to_msecs(jiffies);
}
void intel_enable_clock_gating(struct drm_device *dev)