]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
drm/amd/display: Enable vblank interrupt during CRC capture
authorNicholas Kazlauskas <nicholas.kazlauskas@amd.com>
Mon, 14 Jan 2019 21:04:10 +0000 (16:04 -0500)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 5 Apr 2019 20:33:13 +0000 (22:33 +0200)
[ Upstream commit 428da2bdb05d76c48d0bd8fbfa2e4c102685be08 ]

[Why]
In order to read CRC events when CRC capture is enabled the vblank
interrput handler needs to be running for the CRTC. The handler is
enabled while there is an active vblank reference.

When running IGT tests there will often be no active vblank reference
but the test expects to read a CRC value. This is valid usage (and
works on i915 since they have a CRC interrupt handler) so the reference
to the vblank should be grabbed while capture is active.

This issue was found running:

igt@kms_plane_multiple@atomic-pipe-b-tiling-none

The pipe-b is the only one in the initial commit and was not previously
active so no vblank reference is grabbed. The vblank interrupt is
not enabled and the test times out.

[How]
Keep a reference to the vblank as long as CRC capture is enabled.
If userspace never explicitly disables it then the reference is
also dropped when removing the CRTC from the context (stream = NULL).

Signed-off-by: Nicholas Kazlauskas <nicholas.kazlauskas@amd.com>
Reviewed-by: Harry Wentland <Harry.Wentland@amd.com>
Reviewed-by: Sun peng Li <Sunpeng.Li@amd.com>
Acked-by: Leo Li <sunpeng.li@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c

index c57e85f08e23aff3c0ade0442bcd867d447643fa..2b8b892eb846f88deb7984babc58ad9608025bf7 100644 (file)
@@ -4390,10 +4390,22 @@ static int amdgpu_dm_atomic_commit(struct drm_device *dev,
         */
        for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
                struct dm_crtc_state *dm_old_crtc_state = to_dm_crtc_state(old_crtc_state);
+               struct dm_crtc_state *dm_new_crtc_state = to_dm_crtc_state(new_crtc_state);
                struct amdgpu_crtc *acrtc = to_amdgpu_crtc(crtc);
 
-               if (drm_atomic_crtc_needs_modeset(new_crtc_state) && dm_old_crtc_state->stream)
+               if (drm_atomic_crtc_needs_modeset(new_crtc_state)
+                   && dm_old_crtc_state->stream) {
+                       /*
+                        * CRC capture was enabled but not disabled.
+                        * Release the vblank reference.
+                        */
+                       if (dm_new_crtc_state->crc_enabled) {
+                               drm_crtc_vblank_put(crtc);
+                               dm_new_crtc_state->crc_enabled = false;
+                       }
+
                        manage_dm_interrupts(adev, acrtc, false);
+               }
        }
        /* Add check here for SoC's that support hardware cursor plane, to
         * unset legacy_cursor_update */
index 6a6d977ddd7ac2f5c62028622a4c057aefe66576..36a0bed9af07f826499bb822edb28339bb419f39 100644 (file)
@@ -51,6 +51,7 @@ int amdgpu_dm_crtc_set_crc_source(struct drm_crtc *crtc, const char *src_name,
 {
        struct dm_crtc_state *crtc_state = to_dm_crtc_state(crtc->state);
        struct dc_stream_state *stream_state = crtc_state->stream;
+       bool enable;
 
        enum amdgpu_dm_pipe_crc_source source = dm_parse_crc_source(src_name);
 
@@ -65,28 +66,27 @@ int amdgpu_dm_crtc_set_crc_source(struct drm_crtc *crtc, const char *src_name,
                return -EINVAL;
        }
 
+       enable = (source == AMDGPU_DM_PIPE_CRC_SOURCE_AUTO);
+
+       if (!dc_stream_configure_crc(stream_state->ctx->dc, stream_state,
+                                    enable, enable))
+               return -EINVAL;
+
        /* When enabling CRC, we should also disable dithering. */
-       if (source == AMDGPU_DM_PIPE_CRC_SOURCE_AUTO) {
-               if (dc_stream_configure_crc(stream_state->ctx->dc,
-                                           stream_state,
-                                           true, true)) {
-                       crtc_state->crc_enabled = true;
-                       dc_stream_set_dither_option(stream_state,
-                                                   DITHER_OPTION_TRUN8);
-               }
-               else
-                       return -EINVAL;
-       } else {
-               if (dc_stream_configure_crc(stream_state->ctx->dc,
-                                           stream_state,
-                                           false, false)) {
-                       crtc_state->crc_enabled = false;
-                       dc_stream_set_dither_option(stream_state,
-                                                   DITHER_OPTION_DEFAULT);
-               }
-               else
-                       return -EINVAL;
-       }
+       dc_stream_set_dither_option(stream_state,
+                                   enable ? DITHER_OPTION_TRUN8
+                                          : DITHER_OPTION_DEFAULT);
+
+       /*
+        * Reading the CRC requires the vblank interrupt handler to be
+        * enabled. Keep a reference until CRC capture stops.
+        */
+       if (!crtc_state->crc_enabled && enable)
+               drm_crtc_vblank_get(crtc);
+       else if (crtc_state->crc_enabled && !enable)
+               drm_crtc_vblank_put(crtc);
+
+       crtc_state->crc_enabled = enable;
 
        *values_cnt = 3;
        /* Reset crc_skipped on dm state */