drm/i915/fbc: Track FBC usage per-plane
authorVille Syrjälä <ville.syrjala@linux.intel.com>
Wed, 24 Nov 2021 11:36:40 +0000 (13:36 +0200)
committerVille Syrjälä <ville.syrjala@linux.intel.com>
Fri, 3 Dec 2021 11:12:06 +0000 (13:12 +0200)
In the future we may have multiple planes on the same pipe
capable of using FBC. Prepare for that by tracking FBC usage
per-plane rather than per-crtc.

v2: s/intel_get_crtc_for_pipe/intel_crtc_for_pipe/

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20211124113652.22090-9-ville.syrjala@linux.intel.com
Reviewed-by: Mika Kahola <mika.kahola@intel.com>
drivers/gpu/drm/i915/display/intel_fbc.c
drivers/gpu/drm/i915/i915_drv.h
drivers/gpu/drm/i915/i915_trace.h

index db390c29c665f2511920ef25c82c2d124473c2f0..cf7fc0de6081fd8dcff9537b735742f365cc6a2c 100644 (file)
@@ -583,7 +583,7 @@ static bool intel_fbc_hw_is_active(struct intel_fbc *fbc)
 
 static void intel_fbc_hw_activate(struct intel_fbc *fbc)
 {
-       trace_intel_fbc_activate(fbc->crtc);
+       trace_intel_fbc_activate(fbc->plane);
 
        fbc->active = true;
        fbc->activated = true;
@@ -593,7 +593,7 @@ static void intel_fbc_hw_activate(struct intel_fbc *fbc)
 
 static void intel_fbc_hw_deactivate(struct intel_fbc *fbc)
 {
-       trace_intel_fbc_deactivate(fbc->crtc);
+       trace_intel_fbc_deactivate(fbc->plane);
 
        fbc->active = false;
 
@@ -607,7 +607,7 @@ bool intel_fbc_is_compressing(struct intel_fbc *fbc)
 
 static void intel_fbc_nuke(struct intel_fbc *fbc)
 {
-       trace_intel_fbc_nuke(fbc->crtc);
+       trace_intel_fbc_nuke(fbc->plane);
 
        fbc->funcs->nuke(fbc);
 }
@@ -1154,8 +1154,7 @@ static bool intel_fbc_can_activate(struct intel_fbc *fbc)
        return true;
 }
 
-static void intel_fbc_get_reg_params(struct intel_fbc *fbc,
-                                    struct intel_crtc *crtc)
+static void intel_fbc_get_reg_params(struct intel_fbc *fbc)
 {
        const struct intel_fbc_state *cache = &fbc->state_cache;
        struct intel_fbc_state *params = &fbc->params;
@@ -1213,30 +1212,19 @@ static bool intel_fbc_can_flip_nuke(struct intel_atomic_state *state,
        return true;
 }
 
-bool intel_fbc_pre_update(struct intel_atomic_state *state,
-                         struct intel_crtc *crtc)
+static bool __intel_fbc_pre_update(struct intel_atomic_state *state,
+                                  struct intel_crtc *crtc,
+                                  struct intel_plane *plane)
 {
-       struct intel_plane *plane = to_intel_plane(crtc->base.primary);
-       const struct intel_plane_state *plane_state =
-               intel_atomic_get_new_plane_state(state, plane);
-       struct drm_i915_private *i915 = to_i915(crtc->base.dev);
+       struct drm_i915_private *i915 = to_i915(state->base.dev);
        struct intel_fbc *fbc = plane->fbc;
-       const char *reason = "update pending";
        bool need_vblank_wait = false;
 
-       if (!fbc || !plane_state)
-               return need_vblank_wait;
-
-       mutex_lock(&fbc->lock);
-
-       if (fbc->crtc != crtc)
-               goto unlock;
-
        intel_fbc_update_state_cache(state, crtc, plane);
        fbc->flip_pending = true;
 
        if (!intel_fbc_can_flip_nuke(state, crtc, plane)) {
-               intel_fbc_deactivate(fbc, reason);
+               intel_fbc_deactivate(fbc, "update pending");
 
                /*
                 * Display WA #1198: glk+
@@ -1256,8 +1244,31 @@ bool intel_fbc_pre_update(struct intel_atomic_state *state,
                        need_vblank_wait = true;
                fbc->activated = false;
        }
-unlock:
-       mutex_unlock(&fbc->lock);
+
+       return need_vblank_wait;
+}
+
+bool intel_fbc_pre_update(struct intel_atomic_state *state,
+                         struct intel_crtc *crtc)
+{
+       const struct intel_plane_state *plane_state;
+       bool need_vblank_wait = false;
+       struct intel_plane *plane;
+       int i;
+
+       for_each_new_intel_plane_in_state(state, plane, plane_state, i) {
+               struct intel_fbc *fbc = plane->fbc;
+
+               if (!fbc || plane->pipe != crtc->pipe)
+                       continue;
+
+               mutex_lock(&fbc->lock);
+
+               if (fbc->plane == plane)
+                       need_vblank_wait |= __intel_fbc_pre_update(state, crtc, plane);
+
+               mutex_unlock(&fbc->lock);
+       }
 
        return need_vblank_wait;
 }
@@ -1265,18 +1276,18 @@ unlock:
 static void __intel_fbc_disable(struct intel_fbc *fbc)
 {
        struct drm_i915_private *i915 = fbc->i915;
-       struct intel_crtc *crtc = fbc->crtc;
+       struct intel_plane *plane = fbc->plane;
 
        drm_WARN_ON(&i915->drm, !mutex_is_locked(&fbc->lock));
-       drm_WARN_ON(&i915->drm, !fbc->crtc);
+       drm_WARN_ON(&i915->drm, !fbc->plane);
        drm_WARN_ON(&i915->drm, fbc->active);
 
-       drm_dbg_kms(&i915->drm, "Disabling FBC on pipe %c\n",
-                   pipe_name(crtc->pipe));
+       drm_dbg_kms(&i915->drm, "Disabling FBC on [PLANE:%d:%s]\n",
+                   plane->base.base.id, plane->base.name);
 
        __intel_fbc_cleanup_cfb(fbc);
 
-       fbc->crtc = NULL;
+       fbc->plane = NULL;
 }
 
 static void __intel_fbc_post_update(struct intel_fbc *fbc)
@@ -1304,27 +1315,32 @@ static void __intel_fbc_post_update(struct intel_fbc *fbc)
 void intel_fbc_post_update(struct intel_atomic_state *state,
                           struct intel_crtc *crtc)
 {
-       struct intel_plane *plane = to_intel_plane(crtc->base.primary);
-       const struct intel_plane_state *plane_state =
-               intel_atomic_get_new_plane_state(state, plane);
-       struct intel_fbc *fbc = plane->fbc;
+       const struct intel_plane_state *plane_state;
+       struct intel_plane *plane;
+       int i;
 
-       if (!fbc || !plane_state)
-               return;
+       for_each_new_intel_plane_in_state(state, plane, plane_state, i) {
+               struct intel_fbc *fbc = plane->fbc;
 
-       mutex_lock(&fbc->lock);
-       if (fbc->crtc == crtc) {
-               fbc->flip_pending = false;
-               intel_fbc_get_reg_params(fbc, crtc);
-               __intel_fbc_post_update(fbc);
+               if (!fbc || plane->pipe != crtc->pipe)
+                       continue;
+
+               mutex_lock(&fbc->lock);
+
+               if (fbc->plane == plane) {
+                       fbc->flip_pending = false;
+                       intel_fbc_get_reg_params(fbc);
+                       __intel_fbc_post_update(fbc);
+               }
+
+               mutex_unlock(&fbc->lock);
        }
-       mutex_unlock(&fbc->lock);
 }
 
 static unsigned int intel_fbc_get_frontbuffer_bit(struct intel_fbc *fbc)
 {
-       if (fbc->crtc)
-               return to_intel_plane(fbc->crtc->base.primary)->frontbuffer_bit;
+       if (fbc->plane)
+               return fbc->plane->frontbuffer_bit;
        else
                return fbc->possible_framebuffer_bits;
 }
@@ -1345,7 +1361,7 @@ void intel_fbc_invalidate(struct drm_i915_private *i915,
 
        fbc->busy_bits |= intel_fbc_get_frontbuffer_bit(fbc) & frontbuffer_bits;
 
-       if (fbc->crtc && fbc->busy_bits)
+       if (fbc->plane && fbc->busy_bits)
                intel_fbc_deactivate(fbc, "frontbuffer write");
 
        mutex_unlock(&fbc->lock);
@@ -1366,7 +1382,7 @@ void intel_fbc_flush(struct drm_i915_private *i915,
        if (origin == ORIGIN_FLIP || origin == ORIGIN_CURSOR_UPDATE)
                goto out;
 
-       if (!fbc->busy_bits && fbc->crtc &&
+       if (!fbc->busy_bits && fbc->plane &&
            (frontbuffer_bits & intel_fbc_get_frontbuffer_bit(fbc))) {
                if (fbc->active)
                        intel_fbc_nuke(fbc);
@@ -1395,43 +1411,24 @@ int intel_fbc_atomic_check(struct intel_atomic_state *state)
        return 0;
 }
 
-/**
- * intel_fbc_enable: tries to enable FBC on the CRTC
- * @crtc: the CRTC
- * @state: corresponding &drm_crtc_state for @crtc
- *
- * This function checks if the given CRTC was chosen for FBC, then enables it if
- * possible. Notice that it doesn't activate FBC. It is valid to call
- * intel_fbc_enable multiple times for the same pipe without an
- * intel_fbc_disable in the middle, as long as it is deactivated.
- */
-static void intel_fbc_enable(struct intel_atomic_state *state,
-                            struct intel_crtc *crtc)
+static void __intel_fbc_enable(struct intel_atomic_state *state,
+                              struct intel_crtc *crtc,
+                              struct intel_plane *plane)
 {
-       struct drm_i915_private *i915 = to_i915(crtc->base.dev);
-       struct intel_plane *plane = to_intel_plane(crtc->base.primary);
+       struct drm_i915_private *i915 = to_i915(state->base.dev);
        const struct intel_plane_state *plane_state =
                intel_atomic_get_new_plane_state(state, plane);
        struct intel_fbc *fbc = plane->fbc;
-       struct intel_fbc_state *cache;
-       int min_limit;
-
-       if (!fbc || !plane_state)
-               return;
-
-       cache = &fbc->state_cache;
-
-       min_limit = intel_fbc_min_limit(plane_state);
-
-       mutex_lock(&fbc->lock);
+       struct intel_fbc_state *cache = &fbc->state_cache;
+       int min_limit = intel_fbc_min_limit(plane_state);
 
-       if (fbc->crtc) {
-               if (fbc->crtc != crtc)
-                       goto out;
+       if (fbc->plane) {
+               if (fbc->plane != plane)
+                       return;
 
                if (fbc->limit >= min_limit &&
                    !intel_fbc_cfb_size_changed(fbc))
-                       goto out;
+                       return;
 
                __intel_fbc_disable(fbc);
        }
@@ -1441,22 +1438,20 @@ static void intel_fbc_enable(struct intel_atomic_state *state,
        intel_fbc_update_state_cache(state, crtc, plane);
 
        if (cache->no_fbc_reason)
-               goto out;
+               return;
 
        if (intel_fbc_alloc_cfb(fbc, intel_fbc_cfb_size(plane_state), min_limit)) {
                fbc->no_fbc_reason = "not enough stolen memory";
-               goto out;
+               return;
        }
 
-       drm_dbg_kms(&i915->drm, "Enabling FBC on pipe %c\n",
-                   pipe_name(crtc->pipe));
+       drm_dbg_kms(&i915->drm, "Enabling FBC on [PLANE:%d:%s]\n",
+                   plane->base.base.id, plane->base.name);
        fbc->no_fbc_reason = "FBC enabled but not active yet\n";
 
-       fbc->crtc = crtc;
+       fbc->plane = plane;
 
        intel_fbc_program_cfb(fbc);
-out:
-       mutex_unlock(&fbc->lock);
 }
 
 /**
@@ -1467,45 +1462,48 @@ out:
  */
 void intel_fbc_disable(struct intel_crtc *crtc)
 {
-       struct intel_plane *plane = to_intel_plane(crtc->base.primary);
-       struct intel_fbc *fbc = plane->fbc;
+       struct drm_i915_private *i915 = to_i915(crtc->base.dev);
+       struct intel_plane *plane;
 
-       if (!fbc)
-               return;
+       for_each_intel_plane(&i915->drm, plane) {
+               struct intel_fbc *fbc = plane->fbc;
 
-       mutex_lock(&fbc->lock);
-       if (fbc->crtc == crtc)
-               __intel_fbc_disable(fbc);
-       mutex_unlock(&fbc->lock);
+               if (!fbc || plane->pipe != crtc->pipe)
+                       continue;
+
+               mutex_lock(&fbc->lock);
+               if (fbc->plane == plane)
+                       __intel_fbc_disable(fbc);
+               mutex_unlock(&fbc->lock);
+       }
 }
 
-/**
- * intel_fbc_update: enable/disable FBC on the CRTC
- * @state: atomic state
- * @crtc: the CRTC
- *
- * This function checks if the given CRTC was chosen for FBC, then enables it if
- * possible. Notice that it doesn't activate FBC. It is valid to call
- * intel_fbc_update multiple times for the same pipe without an
- * intel_fbc_disable in the middle.
- */
 void intel_fbc_update(struct intel_atomic_state *state,
                      struct intel_crtc *crtc)
 {
-       struct intel_plane *plane = to_intel_plane(crtc->base.primary);
        const struct intel_crtc_state *crtc_state =
                intel_atomic_get_new_crtc_state(state, crtc);
-       const struct intel_plane_state *plane_state =
-               intel_atomic_get_new_plane_state(state, plane);
-       struct intel_fbc *fbc = plane->fbc;
+       const struct intel_plane_state *plane_state;
+       struct intel_plane *plane;
+       int i;
 
-       if (!fbc || !plane_state)
-               return;
+       for_each_new_intel_plane_in_state(state, plane, plane_state, i) {
+               struct intel_fbc *fbc = plane->fbc;
 
-       if (crtc_state->update_pipe && plane_state->no_fbc_reason)
-               intel_fbc_disable(crtc);
-       else
-               intel_fbc_enable(state, crtc);
+               if (!fbc || plane->pipe != crtc->pipe)
+                       continue;
+
+               mutex_lock(&fbc->lock);
+
+               if (crtc_state->update_pipe && plane_state->no_fbc_reason) {
+                       if (fbc->plane == plane)
+                               __intel_fbc_disable(fbc);
+               } else {
+                       __intel_fbc_enable(state, crtc, plane);
+               }
+
+               mutex_unlock(&fbc->lock);
+       }
 }
 
 /**
@@ -1522,10 +1520,8 @@ void intel_fbc_global_disable(struct drm_i915_private *i915)
                return;
 
        mutex_lock(&fbc->lock);
-       if (fbc->crtc) {
-               drm_WARN_ON(&i915->drm, fbc->crtc->active);
+       if (fbc->plane)
                __intel_fbc_disable(fbc);
-       }
        mutex_unlock(&fbc->lock);
 }
 
@@ -1538,7 +1534,7 @@ static void intel_fbc_underrun_work_fn(struct work_struct *work)
        mutex_lock(&fbc->lock);
 
        /* Maybe we were scheduled twice. */
-       if (fbc->underrun_detected || !fbc->crtc)
+       if (fbc->underrun_detected || !fbc->plane)
                goto out;
 
        drm_dbg_kms(&i915->drm, "Disabling FBC due to FIFO underrun.\n");
index 20581312ea82663d3389e03032b8150c9deb8527..493522ce9953c97e637a093d7f1576120b9638a6 100644 (file)
@@ -402,7 +402,7 @@ struct intel_fbc {
        struct mutex lock;
        unsigned int possible_framebuffer_bits;
        unsigned int busy_bits;
-       struct intel_crtc *crtc;
+       struct intel_plane *plane;
 
        struct drm_mm_node compressed_fb;
        struct drm_mm_node compressed_llb;
index 26b8d75029d440d937abfadf8d9c77586a44a2fe..185eaa49f74e2585f28d24e97233ea1fd67abe44 100644 (file)
@@ -372,8 +372,8 @@ TRACE_EVENT(intel_plane_disable_arm,
 /* fbc */
 
 TRACE_EVENT(intel_fbc_activate,
-           TP_PROTO(struct intel_crtc *crtc),
-           TP_ARGS(crtc),
+           TP_PROTO(struct intel_plane *plane),
+           TP_ARGS(plane),
 
            TP_STRUCT__entry(
                             __field(enum pipe, pipe)
@@ -382,6 +382,8 @@ TRACE_EVENT(intel_fbc_activate,
                             ),
 
            TP_fast_assign(
+                          struct intel_crtc *crtc = intel_crtc_for_pipe(to_i915(plane->base.dev),
+                                                                        plane->pipe);
                           __entry->pipe = crtc->pipe;
                           __entry->frame = intel_crtc_get_vblank_counter(crtc);
                           __entry->scanline = intel_get_crtc_scanline(crtc);
@@ -392,8 +394,8 @@ TRACE_EVENT(intel_fbc_activate,
 );
 
 TRACE_EVENT(intel_fbc_deactivate,
-           TP_PROTO(struct intel_crtc *crtc),
-           TP_ARGS(crtc),
+           TP_PROTO(struct intel_plane *plane),
+           TP_ARGS(plane),
 
            TP_STRUCT__entry(
                             __field(enum pipe, pipe)
@@ -402,6 +404,8 @@ TRACE_EVENT(intel_fbc_deactivate,
                             ),
 
            TP_fast_assign(
+                          struct intel_crtc *crtc = intel_crtc_for_pipe(to_i915(plane->base.dev),
+                                                                        plane->pipe);
                           __entry->pipe = crtc->pipe;
                           __entry->frame = intel_crtc_get_vblank_counter(crtc);
                           __entry->scanline = intel_get_crtc_scanline(crtc);
@@ -412,8 +416,8 @@ TRACE_EVENT(intel_fbc_deactivate,
 );
 
 TRACE_EVENT(intel_fbc_nuke,
-           TP_PROTO(struct intel_crtc *crtc),
-           TP_ARGS(crtc),
+           TP_PROTO(struct intel_plane *plane),
+           TP_ARGS(plane),
 
            TP_STRUCT__entry(
                             __field(enum pipe, pipe)
@@ -422,6 +426,8 @@ TRACE_EVENT(intel_fbc_nuke,
                             ),
 
            TP_fast_assign(
+                          struct intel_crtc *crtc = intel_crtc_for_pipe(to_i915(plane->base.dev),
+                                                                        plane->pipe);
                           __entry->pipe = crtc->pipe;
                           __entry->frame = intel_crtc_get_vblank_counter(crtc);
                           __entry->scanline = intel_get_crtc_scanline(crtc);