drm/amd/display: Fix crc_src is not thread safe
authorWayne Lin <Wayne.Lin@amd.com>
Tue, 9 Feb 2021 08:52:22 +0000 (16:52 +0800)
committerAlex Deucher <alexander.deucher@amd.com>
Fri, 5 Mar 2021 20:11:39 +0000 (15:11 -0500)
[Why & How]
Find out that referring to crtc_state->crc_src is not thread safe.
Move crc_src from dm_crtc_state to dm_irq_params to fix this.

Signed-off-by: Wayne Lin <Wayne.Lin@amd.com>
Reviewed-by: Nicholas Kazlauskas <Nicholas.Kazlauskas@amd.com>
Acked-by: Eryk Brol <eryk.brol@amd.com>
Acked-by: Rodrigo Siqueira <Rodrigo.Siqueira@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq_params.h

index 278a11b..15a5121 100644 (file)
@@ -5510,7 +5510,6 @@ dm_crtc_duplicate_state(struct drm_crtc *crtc)
        state->abm_level = cur->abm_level;
        state->vrr_supported = cur->vrr_supported;
        state->freesync_config = cur->freesync_config;
-       state->crc_src = cur->crc_src;
        state->cm_has_degamma = cur->cm_has_degamma;
        state->cm_is_degamma_srgb = cur->cm_is_degamma_srgb;
 
@@ -8650,6 +8649,9 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)
         */
        for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
                struct amdgpu_crtc *acrtc = to_amdgpu_crtc(crtc);
+#ifdef CONFIG_DEBUG_FS
+               enum amdgpu_dm_pipe_crc_source cur_crc_src;
+#endif
 
                dm_new_crtc_state = to_dm_crtc_state(new_crtc_state);
 
@@ -8666,11 +8668,14 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)
                         * settings for the stream.
                         */
                        dm_new_crtc_state = to_dm_crtc_state(new_crtc_state);
+                       spin_lock_irqsave(&adev_to_drm(adev)->event_lock, flags);
+                       cur_crc_src = acrtc->dm_irq_params.crc_src;
+                       spin_unlock_irqrestore(&adev_to_drm(adev)->event_lock, flags);
 
-                       if (amdgpu_dm_is_valid_crc_source(dm_new_crtc_state->crc_src)) {
+                       if (amdgpu_dm_is_valid_crc_source(cur_crc_src)) {
                                amdgpu_dm_crtc_configure_crc_source(
                                        crtc, dm_new_crtc_state,
-                                       dm_new_crtc_state->crc_src);
+                                       cur_crc_src);
                        }
 #endif
                }
index 4fbea83..b713d04 100644 (file)
@@ -452,7 +452,6 @@ struct dm_crtc_state {
        int active_planes;
 
        int crc_skip_count;
-       enum amdgpu_dm_pipe_crc_source crc_src;
 
        bool freesync_timing_changed;
        bool freesync_vrr_info_changed;
index 66cb873..a967706 100644 (file)
@@ -142,8 +142,11 @@ unlock:
 int amdgpu_dm_crtc_set_crc_source(struct drm_crtc *crtc, const char *src_name)
 {
        enum amdgpu_dm_pipe_crc_source source = dm_parse_crc_source(src_name);
+       enum amdgpu_dm_pipe_crc_source cur_crc_src;
        struct drm_crtc_commit *commit;
        struct dm_crtc_state *crtc_state;
+       struct drm_device *drm_dev = crtc->dev;
+       struct amdgpu_crtc *acrtc = to_amdgpu_crtc(crtc);
        struct drm_dp_aux *aux = NULL;
        bool enable = false;
        bool enabled = false;
@@ -182,6 +185,9 @@ int amdgpu_dm_crtc_set_crc_source(struct drm_crtc *crtc, const char *src_name)
 
        enable = amdgpu_dm_is_valid_crc_source(source);
        crtc_state = to_dm_crtc_state(crtc->state);
+       spin_lock_irq(&drm_dev->event_lock);
+       cur_crc_src = acrtc->dm_irq_params.crc_src;
+       spin_unlock_irq(&drm_dev->event_lock);
 
        /*
         * USER REQ SRC | CURRENT SRC | BEHAVIOR
@@ -198,7 +204,7 @@ int amdgpu_dm_crtc_set_crc_source(struct drm_crtc *crtc, const char *src_name)
         */
        if (dm_is_crc_source_dprx(source) ||
            (source == AMDGPU_DM_PIPE_CRC_SOURCE_NONE &&
-            dm_is_crc_source_dprx(crtc_state->crc_src))) {
+            dm_is_crc_source_dprx(cur_crc_src))) {
                struct amdgpu_dm_connector *aconn = NULL;
                struct drm_connector *connector;
                struct drm_connector_list_iter conn_iter;
@@ -237,7 +243,7 @@ int amdgpu_dm_crtc_set_crc_source(struct drm_crtc *crtc, const char *src_name)
         * Reading the CRC requires the vblank interrupt handler to be
         * enabled. Keep a reference until CRC capture stops.
         */
-       enabled = amdgpu_dm_is_valid_crc_source(crtc_state->crc_src);
+       enabled = amdgpu_dm_is_valid_crc_source(cur_crc_src);
        if (!enabled && enable) {
                ret = drm_crtc_vblank_get(crtc);
                if (ret)
@@ -261,7 +267,9 @@ int amdgpu_dm_crtc_set_crc_source(struct drm_crtc *crtc, const char *src_name)
                }
        }
 
-       crtc_state->crc_src = source;
+       spin_lock_irq(&drm_dev->event_lock);
+       acrtc->dm_irq_params.crc_src = source;
+       spin_unlock_irq(&drm_dev->event_lock);
 
        /* Reset crc_skipped on dm state */
        crtc_state->crc_skip_count = 0;
@@ -286,16 +294,26 @@ void amdgpu_dm_crtc_handle_crc_irq(struct drm_crtc *crtc)
 {
        struct dm_crtc_state *crtc_state;
        struct dc_stream_state *stream_state;
+       struct drm_device *drm_dev = NULL;
+       enum amdgpu_dm_pipe_crc_source cur_crc_src;
+       struct amdgpu_crtc *acrtc = NULL;
        uint32_t crcs[3];
+       unsigned long flags;
 
        if (crtc == NULL)
                return;
 
        crtc_state = to_dm_crtc_state(crtc->state);
        stream_state = crtc_state->stream;
+       acrtc = to_amdgpu_crtc(crtc);
+       drm_dev = crtc->dev;
+
+       spin_lock_irqsave(&drm_dev->event_lock, flags);
+       cur_crc_src = acrtc->dm_irq_params.crc_src;
+       spin_unlock_irqrestore(&drm_dev->event_lock, flags);
 
        /* Early return if CRC capture is not enabled. */
-       if (!amdgpu_dm_is_valid_crc_source(crtc_state->crc_src))
+       if (!amdgpu_dm_is_valid_crc_source(cur_crc_src))
                return;
 
        /*
@@ -309,7 +327,7 @@ void amdgpu_dm_crtc_handle_crc_irq(struct drm_crtc *crtc)
                return;
        }
 
-       if (dm_is_crc_source_crtc(crtc_state->crc_src)) {
+       if (dm_is_crc_source_crtc(cur_crc_src)) {
                if (!dc_stream_get_crc(stream_state->ctx->dc, stream_state,
                                       &crcs[0], &crcs[1], &crcs[2]))
                        return;
index 45825a3..db2e770 100644 (file)
 #ifndef __AMDGPU_DM_IRQ_PARAMS_H__
 #define __AMDGPU_DM_IRQ_PARAMS_H__
 
+#include "amdgpu_dm_crc.h"
+
 struct dm_irq_params {
        u32 last_flip_vblank;
        struct mod_vrr_params vrr_params;
        struct dc_stream_state *stream;
        int active_planes;
        struct mod_freesync_config freesync_config;
+
+#ifdef CONFIG_DEBUG_FS
+       enum amdgpu_dm_pipe_crc_source crc_src;
+#endif
 };
 
 #endif /* __AMDGPU_DM_IRQ_PARAMS_H__ */