[PATCH 11/26] drm/i915: pass the crtc as an argument to intel_fbc_update()

Paulo Zanoni
2015-10-27T16:50:57Z

There's no need to reevaluate the status of every single crtc when a
single crtc changes its state.

With this, we're cutting the case where due to a change in pipe B,
intel_fbc_update() is called, then intel_fbc_find_crtc() concludes FBC
should be enabled on pipe A, then it completely rechecks the state of
pipe A only to conclude FBC should remain enabled on pipe A. If any
change on pipe A triggers a need to recompute whether FBC is valid on
pipe A, then at some point someone is going to call
intel_fbc_update(PIPE_A).

The addition of intel_fbc_deactivate() is necessary so we keep track
of the previously selected CRTC when we do invalidate/flush. We're
also going to continue the enable/disable/activate/deactivate concept
in the next patches.

v2: Rebase.

Signed-off-by: Paulo Zanoni <paulo.r.zanoni@intel.com>
---
drivers/gpu/drm/i915/intel_display.c | 3 +-
drivers/gpu/drm/i915/intel_drv.h | 2 +-
drivers/gpu/drm/i915/intel_fbc.c | 68 +++++++++++++++---------------------
3 files changed, 31 insertions(+), 42 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index d9378c3..820ad1e 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -4778,7 +4778,6 @@ static void intel_post_plane_update(struct intel_crtc *crtc)
{
struct intel_crtc_atomic_commit *atomic = &crtc->atomic;
struct drm_device *dev = crtc->base.dev;
- struct drm_i915_private *dev_priv = dev->dev_private;

if (atomic->wait_vblank)
intel_wait_for_vblank(dev, crtc->pipe);
@@ -4792,7 +4791,7 @@ static void intel_post_plane_update(struct intel_crtc *crtc)
intel_update_watermarks(&crtc->base);

if (atomic->update_fbc)
- intel_fbc_update(dev_priv);
+ intel_fbc_update(crtc);

if (atomic->post_enable_primary)
intel_post_enable_primary(&crtc->base);
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 9065a8f..b463bae 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -1296,7 +1296,7 @@ static inline void intel_fbdev_restore_mode(struct drm_device *dev)

/* intel_fbc.c */
bool intel_fbc_enabled(struct drm_i915_private *dev_priv);
-void intel_fbc_update(struct drm_i915_private *dev_priv);
+void intel_fbc_update(struct intel_crtc *crtc);
void intel_fbc_init(struct drm_i915_private *dev_priv);
void intel_fbc_disable(struct drm_i915_private *dev_priv);
void intel_fbc_disable_crtc(struct intel_crtc *crtc);
diff --git a/drivers/gpu/drm/i915/intel_fbc.c b/drivers/gpu/drm/i915/intel_fbc.c
index 1b39037..6b952ee 100644
--- a/drivers/gpu/drm/i915/intel_fbc.c
+++ b/drivers/gpu/drm/i915/intel_fbc.c
@@ -488,13 +488,18 @@ static void intel_fbc_schedule_enable(struct intel_crtc *crtc)
schedule_delayed_work(&work->work, msecs_to_jiffies(50));
}

-static void __intel_fbc_disable(struct drm_i915_private *dev_priv)
+static void intel_fbc_deactivate(struct drm_i915_private *dev_priv)
{
WARN_ON(!mutex_is_locked(&dev_priv->fbc.lock));

intel_fbc_cancel_work(dev_priv);

dev_priv->fbc.disable_fbc(dev_priv);
+}
+
+static void __intel_fbc_disable(struct drm_i915_private *dev_priv)
+{
+ intel_fbc_deactivate(dev_priv);
dev_priv->fbc.crtc = NULL;
}

@@ -559,24 +564,6 @@ static bool crtc_is_valid(struct intel_crtc *crtc)
return true;
}

-static struct drm_crtc *intel_fbc_find_crtc(struct drm_i915_private *dev_priv)
-{
- struct drm_crtc *crtc = NULL, *tmp_crtc;
- enum pipe pipe;
-
- for_each_pipe(dev_priv, pipe) {
- tmp_crtc = dev_priv->pipe_to_crtc_mapping[pipe];
-
- if (crtc_is_valid(to_intel_crtc(tmp_crtc)))
- crtc = tmp_crtc;
- }
-
- if (!crtc)
- return NULL;
-
- return crtc;
-}
-
static bool multiple_pipes_ok(struct drm_i915_private *dev_priv)
{
enum pipe pipe;
@@ -859,21 +846,28 @@ static bool intel_fbc_hw_tracking_covers_screen(struct intel_crtc *crtc)

/**
* __intel_fbc_update - enable/disable FBC as needed, unlocked
- * @dev_priv: i915 device instance
+ * @crtc: the CRTC that triggered the update
*
* This function completely reevaluates the status of FBC, then enables,
* disables or maintains it on the same state.
*/
-static void __intel_fbc_update(struct drm_i915_private *dev_priv)
+static void __intel_fbc_update(struct intel_crtc *crtc)
{
- struct drm_crtc *drm_crtc = NULL;
- struct intel_crtc *crtc;
+ struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
struct drm_framebuffer *fb;
struct drm_i915_gem_object *obj;
const struct drm_display_mode *adjusted_mode;

WARN_ON(!mutex_is_locked(&dev_priv->fbc.lock));

+ if (!multiple_pipes_ok(dev_priv)) {
+ set_no_fbc_reason(dev_priv, "more than one pipe active");
+ goto out_disable;
+ }
+
+ if (dev_priv->fbc.crtc != NULL && dev_priv->fbc.crtc != crtc)
+ return;
+
if (intel_vgpu_active(dev_priv->dev))
i915.enable_fbc = 0;

@@ -887,18 +881,11 @@ static void __intel_fbc_update(struct drm_i915_private *dev_priv)
goto out_disable;
}

- drm_crtc = intel_fbc_find_crtc(dev_priv);
- if (!drm_crtc) {
+ if (!crtc_is_valid(crtc)) {
set_no_fbc_reason(dev_priv, "no output");
goto out_disable;
}

- if (!multiple_pipes_ok(dev_priv)) {
- set_no_fbc_reason(dev_priv, "more than one pipe active");
- goto out_disable;
- }
-
- crtc = to_intel_crtc(drm_crtc);
fb = crtc->base.primary->fb;
obj = intel_fb_obj(fb);
adjusted_mode = &crtc->config->base.adjusted_mode;
@@ -970,7 +957,8 @@ static void __intel_fbc_update(struct drm_i915_private *dev_priv)
*/
if (dev_priv->fbc.crtc == crtc &&
dev_priv->fbc.fb_id == fb->base.id &&
- dev_priv->fbc.y == crtc->base.y)
+ dev_priv->fbc.y == crtc->base.y &&
+ dev_priv->fbc.enabled)
return;

if (intel_fbc_enabled(dev_priv)) {
@@ -1016,17 +1004,19 @@ out_disable:

/*
* intel_fbc_update - enable/disable FBC as needed
- * @dev_priv: i915 device instance
+ * @crtc: the CRTC that triggered the update
*
* This function reevaluates the overall state and enables or disables FBC.
*/
-void intel_fbc_update(struct drm_i915_private *dev_priv)
+void intel_fbc_update(struct intel_crtc *crtc)
{
+ struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
+
if (!fbc_supported(dev_priv))
return;

mutex_lock(&dev_priv->fbc.lock);
- __intel_fbc_update(dev_priv);
+ __intel_fbc_update(crtc);
mutex_unlock(&dev_priv->fbc.lock);
}

@@ -1052,7 +1042,7 @@ void intel_fbc_invalidate(struct drm_i915_private *dev_priv,
dev_priv->fbc.busy_bits |= (fbc_bits & frontbuffer_bits);

if (dev_priv->fbc.busy_bits)
- __intel_fbc_disable(dev_priv);
+ intel_fbc_deactivate(dev_priv);

mutex_unlock(&dev_priv->fbc.lock);
}
@@ -1077,11 +1067,11 @@ void intel_fbc_flush(struct drm_i915_private *dev_priv,

dev_priv->fbc.busy_bits &= ~frontbuffer_bits;

- if (!dev_priv->fbc.busy_bits) {
+ if (!dev_priv->fbc.busy_bits && dev_priv->fbc.crtc) {
if (dev_priv->fbc.enabled)
intel_fbc_recompress(dev_priv);
else
- __intel_fbc_update(dev_priv);
+ __intel_fbc_update(dev_priv->fbc.crtc);
}

mutex_unlock(&dev_priv->fbc.lock);
@@ -1104,7 +1094,7 @@ void intel_fbc_flip_prepare(struct drm_i915_private *dev_priv,
} else if (dev_priv->fbc.fbc_work) {
fbc_bits = INTEL_FRONTBUFFER_PRIMARY(dev_priv->fbc.crtc->pipe);
if (fbc_bits & frontbuffer_bits)
- __intel_fbc_disable(dev_priv);
+ intel_fbc_deactivate(dev_priv);
}

mutex_unlock(&dev_priv->fbc.lock);