[Intel-gfx] [PATCH] drm/i915: deferring the HSW IPS enable at plane switch
Ramalingam C
ramalingam.c at intel.com
Sun Jan 19 13:47:13 CET 2014
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 at intel.com>
---
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
More information about the Intel-gfx
mailing list