@@ -1160,6 +1160,9 @@ struct intel_gen6_power_mgmt {
* Must be taken after struct_mutex if nested.
*/
struct mutex hw_lock;
+
+ /* Delayed work to adjust RC6 promotion timer */
+ struct delayed_work vlv_media_timeout_work;
};
/* defined intel_pm.c */
@@ -1272,6 +1272,21 @@ i915_gem_ringbuffer_submission(struct drm_device *dev, struct drm_file *file,
i915_gem_execbuffer_move_to_active(vmas, ring);
i915_gem_execbuffer_retire_commands(dev, file, ring, batch_obj);
+ /* For vlv/chv, modify RC6 promotion timer upon hitting Media workload only
+ * This will help in better power savings with media scenarios.
+ */
+ if (((args->flags & I915_EXEC_RING_MASK) == I915_EXEC_BSD) &&
+ IS_VALLEYVIEW(dev) && dev_priv->rps.enabled) {
+
+ vlv_modify_rc6_promotion_timer(dev_priv, true);
+
+ /* Start a timer for 1 sec to reset this value to original */
+ mod_delayed_work(dev_priv->wq,
+ &dev_priv->rps.vlv_media_timeout_work,
+ msecs_to_jiffies(1000));
+
+ }
+
error:
kfree(cliprects);
return ret;
@@ -1234,6 +1234,8 @@ void ilk_wm_get_hw_state(struct drm_device *dev);
void skl_wm_get_hw_state(struct drm_device *dev);
void skl_ddb_get_hw_state(struct drm_i915_private *dev_priv,
struct skl_ddb_allocation *ddb /* out */);
+void vlv_modify_rc6_promotion_timer(struct drm_i915_private *dev_priv,
+ bool media_active);
/* intel_sdvo.c */
@@ -716,6 +716,21 @@ int intel_execlists_submission(struct drm_device *dev, struct drm_file *file,
i915_gem_execbuffer_move_to_active(vmas, ring);
i915_gem_execbuffer_retire_commands(dev, file, ring, batch_obj);
+ /*
+ * CHV: Extend RC6 promotion timer upon hitting Media workload to help
+ * increase power savings with media scenarios.
+ */
+ if (((args->flags & I915_EXEC_RING_MASK) == I915_EXEC_BSD) &&
+ IS_CHERRYVIEW(dev_priv->dev) && dev_priv->rps.enabled) {
+
+ vlv_modify_rc6_promotion_timer(dev_priv, true);
+
+ /* Start a timer for 1 sec to reset this value to original */
+ mod_delayed_work(dev_priv->wq,
+ &dev_priv->rps.vlv_media_timeout_work,
+ msecs_to_jiffies(1000));
+ }
+
return 0;
}
@@ -3941,6 +3941,9 @@ static void cherryview_disable_rps(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
+ /* Cancel any pending work-item */
+ cancel_delayed_work_sync(&dev_priv->rps.vlv_media_timeout_work);
+
I915_WRITE(GEN6_RC_CONTROL, 0);
}
@@ -3952,6 +3955,9 @@ static void valleyview_disable_rps(struct drm_device *dev)
* This what the BIOS expects when going into suspend */
intel_uncore_forcewake_get(dev_priv, FORCEWAKE_ALL);
+ /* Cancel any pending work-item */
+ cancel_delayed_work_sync(&dev_priv->rps.vlv_media_timeout_work);
+
I915_WRITE(GEN6_RC_CONTROL, 0);
intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL);
@@ -4857,6 +4863,32 @@ static void cherryview_enable_rps(struct drm_device *dev)
intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL);
}
+void vlv_modify_rc6_promotion_timer(struct drm_i915_private *dev_priv,
+ bool media_active)
+{
+ if (media_active) {
+ /* TO threshold set to 250 us ( 0xC3 * 1.28 us) */
+ I915_WRITE(GEN6_RC6_THRESHOLD, 0xC3);
+ } else {
+ if (IS_CHERRYVIEW(dev_priv->dev)) {
+ /* TO threshold set to 500 us ( 0x186 * 1.28 us) */
+ I915_WRITE(GEN6_RC6_THRESHOLD, 0x186);
+ } else {
+ /* TO threshold set to 1750 us ( 0x557 * 1.28 us) */
+ I915_WRITE(GEN6_RC6_THRESHOLD, 0x557);
+ }
+ }
+}
+
+static void vlv_media_timeout_work_func(struct work_struct *work)
+{
+ struct drm_i915_private *dev_priv = container_of(work, struct drm_i915_private,
+ rps.vlv_media_timeout_work.work);
+
+ vlv_modify_rc6_promotion_timer(dev_priv, false);
+}
+
+
static void valleyview_enable_rps(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
@@ -6687,5 +6719,8 @@ void intel_pm_setup(struct drm_device *dev)
INIT_DELAYED_WORK(&dev_priv->rps.delayed_resume_work,
intel_gen6_powersave_work);
+ INIT_DELAYED_WORK(&dev_priv->rps.vlv_media_timeout_work,
+ vlv_media_timeout_work_func);
+
dev_priv->pm.suspended = false;
}