[PATCH] drm/i915: deferring the HSW IPS enable at plane switch

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



To remove the wait_for_vblank from the plane switch execution path,
this change implements a function which will add a delayed work to
defer the IPS enable.

The delay is nothing but frame length, which is calculated based on
vrefresh of the hwmode. i.e IPS enable will be scheduled after a frame.
If mode is not set during the plane switch (__unlikely__), delay will
fallback to a default value 100mSec (can handle the FPS >= 10).

Signed-off-by: Ramalingam C <ramalingam.c@xxxxxxxxx>
---
 drivers/gpu/drm/i915/intel_display.c |   58 ++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/i915/intel_drv.h     |    8 +++++
 drivers/gpu/drm/i915/intel_sprite.c  |    3 +-
 3 files changed, 67 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index e77d4b8..9aa66d5 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -52,6 +52,7 @@ static void ironlake_pch_clock_get(struct intel_crtc *crtc,
 static int intel_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mode,
 			  int x, int y, struct drm_framebuffer *old_fb);
 
+#define IPS_DEFAULT_SCHEDULED_DELAY_MSECS	100	/* For >=10FPS */
 
 typedef struct {
 	int	min, max;
@@ -3452,6 +3453,53 @@ void hsw_enable_ips(struct intel_crtc *crtc)
 	}
 }
 
+void intel_ips_deferred_work_fn(struct work_struct *__work)
+{
+	struct intel_ips_deferred_work *work = container_of(
+		to_delayed_work(__work), struct intel_ips_deferred_work,
+								delayed_work);
+	struct intel_crtc *intel_crtc = to_intel_crtc(work->crtc);
+
+	hsw_enable_ips(intel_crtc);
+	kfree(work);
+	intel_crtc->ips_deferred_work = NULL;
+}
+
+int hsw_deferred_ips_enable(struct drm_crtc *crtc)
+{
+	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+	struct intel_ips_deferred_work *work;
+	int delay = 0;
+
+	/* Canceling any previous pending IPS deferred work, if any */
+	if (intel_crtc->ips_deferred_work) {
+		work = intel_crtc->ips_deferred_work;
+		cancel_delayed_work_sync(&work->delayed_work);
+		kfree(work);
+		intel_crtc->ips_deferred_work = NULL;
+	}
+
+	/* Awaits unnecessary load to wq */
+	if (!intel_crtc->primary_enabled)
+		return -EPERM;
+
+	work = kzalloc(sizeof(*work), GFP_KERNEL);
+	if (work == NULL)
+		return -ENOMEM;
+
+	work->crtc = crtc;
+	INIT_DELAYED_WORK(&work->delayed_work, intel_ips_deferred_work_fn);
+	intel_crtc->ips_deferred_work = work;
+
+	/* If mode is set, frame length is calculated, else default delay
+	 * is used */
+	delay = crtc->hwmode.vrefresh ? (1000 / crtc->hwmode.vrefresh) :
+					IPS_DEFAULT_SCHEDULED_DELAY_MSECS;
+	schedule_delayed_work(&work->delayed_work, msecs_to_jiffies(delay));
+
+	return 0;
+}
+
 void hsw_disable_ips(struct intel_crtc *crtc)
 {
 	struct drm_device *dev = crtc->base.dev;
@@ -8218,6 +8266,7 @@ static void intel_crtc_destroy(struct drm_crtc *crtc)
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 	struct drm_device *dev = crtc->dev;
 	struct intel_unpin_work *work;
+	struct intel_ips_deferred_work *ips_deferred_work;
 	unsigned long flags;
 
 	spin_lock_irqsave(&dev->event_lock, flags);
@@ -8230,6 +8279,13 @@ static void intel_crtc_destroy(struct drm_crtc *crtc)
 		kfree(work);
 	}
 
+	if (intel_crtc->ips_deferred_work) {
+		ips_deferred_work = intel_crtc->ips_deferred_work;
+		cancel_delayed_work_sync(&(ips_deferred_work->delayed_work));
+		kfree(ips_deferred_work);
+		intel_crtc->ips_deferred_work = NULL;
+	}
+
 	intel_crtc_cursor_set(crtc, NULL, 0, 0, 0);
 
 	drm_crtc_cleanup(crtc);
@@ -10193,6 +10249,8 @@ static void intel_crtc_init(struct drm_device *dev, int pipe)
 		intel_crtc->plane = !pipe;
 	}
 
+	intel_crtc->ips_deferred_work = NULL;
+
 	BUG_ON(pipe >= ARRAY_SIZE(dev_priv->plane_to_crtc_mapping) ||
 	       dev_priv->plane_to_crtc_mapping[intel_crtc->plane] != NULL);
 	dev_priv->plane_to_crtc_mapping[intel_crtc->plane] = &intel_crtc->base;
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 8754db9..aad4cf5 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -347,6 +347,8 @@ struct intel_crtc {
 
 	atomic_t unpin_work_count;
 
+	struct intel_ips_deferred_work *ips_deferred_work;
+
 	/* Display surface base address adjustement for pageflips. Note that on
 	 * gen4+ this only adjusts up to a tile, offsets within a tile are
 	 * handled in the hw itself (with the TILEOFF register). */
@@ -524,6 +526,11 @@ intel_get_crtc_for_plane(struct drm_device *dev, int plane)
 	return dev_priv->plane_to_crtc_mapping[plane];
 }
 
+struct intel_ips_deferred_work {
+	struct delayed_work delayed_work;
+	struct drm_crtc *crtc;
+};
+
 struct intel_unpin_work {
 	struct work_struct work;
 	struct drm_crtc *crtc;
@@ -707,6 +714,7 @@ ironlake_check_encoder_dotclock(const struct intel_crtc_config *pipe_config,
 bool intel_crtc_active(struct drm_crtc *crtc);
 void hsw_enable_ips(struct intel_crtc *crtc);
 void hsw_disable_ips(struct intel_crtc *crtc);
+int hsw_deferred_ips_enable(struct drm_crtc *crtc);
 void intel_display_set_init_power(struct drm_device *dev, bool enable);
 int valleyview_get_vco(struct drm_i915_private *dev_priv);
 
diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c
index fe4de89..e2c71c8 100644
--- a/drivers/gpu/drm/i915/intel_sprite.c
+++ b/drivers/gpu/drm/i915/intel_sprite.c
@@ -541,8 +541,7 @@ intel_enable_primary(struct drm_crtc *crtc)
 	 * versa.
 	 */
 	if (intel_crtc->config.ips_enabled) {
-		intel_wait_for_vblank(dev, intel_crtc->pipe);
-		hsw_enable_ips(intel_crtc);
+		hsw_deferred_ips_enable(crtc);
 	}
 
 	mutex_lock(&dev->struct_mutex);
-- 
1.7.9.5

_______________________________________________
Intel-gfx mailing list
Intel-gfx@xxxxxxxxxxxxxxxxxxxxx
http://lists.freedesktop.org/mailman/listinfo/intel-gfx




[Index of Archives]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]
  Powered by Linux