]> git.proxmox.com Git - mirror_ubuntu-kernels.git/commitdiff
drm/amd/display: Wake DMCUB before executing GPINT commands
authorNicholas Kazlauskas <nicholas.kazlauskas@amd.com>
Tue, 5 Dec 2023 16:22:56 +0000 (11:22 -0500)
committerAlex Deucher <alexander.deucher@amd.com>
Tue, 19 Dec 2023 19:59:02 +0000 (14:59 -0500)
[Why]
DMCUB can be in idle when we attempt to interface with the HW through
the GPINT mailbox resulting in a system hang.

[How]
Add dc_wake_and_execute_gpint() to wrap the wake, execute, sleep
sequence.

If the GPINT executes successfully then DMCUB will be put back into
sleep after the optional response is returned.

It functions similar to the inbox command interface.

Cc: Mario Limonciello <mario.limonciello@amd.com>
Cc: Alex Deucher <alexander.deucher@amd.com>
Cc: stable@vger.kernel.org
Reviewed-by: Hansen Dsouza <hansen.dsouza@amd.com>
Acked-by: Wayne Lin <wayne.lin@amd.com>
Signed-off-by: Nicholas Kazlauskas <nicholas.kazlauskas@amd.com>
Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c
drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c
drivers/gpu/drm/amd/display/dc/dc_dmub_srv.h
drivers/gpu/drm/amd/display/dc/dce/dmub_psr.c

index 98b41ec7288e8979867680e624d4a961c8722b3f..68a846323912768edea6c6d330a3491c3aff1b27 100644 (file)
@@ -2976,7 +2976,6 @@ static int dmub_trace_mask_set(void *data, u64 val)
        struct amdgpu_device *adev = data;
        struct dmub_srv *srv = adev->dm.dc->ctx->dmub_srv->dmub;
        enum dmub_gpint_command cmd;
-       enum dmub_status status;
        u64 mask = 0xffff;
        u8 shift = 0;
        u32 res;
@@ -3003,13 +3002,7 @@ static int dmub_trace_mask_set(void *data, u64 val)
                        break;
                }
 
-               status = dmub_srv_send_gpint_command(srv, cmd, res, 30);
-
-               if (status == DMUB_STATUS_TIMEOUT)
-                       return -ETIMEDOUT;
-               else if (status == DMUB_STATUS_INVALID)
-                       return -EINVAL;
-               else if (status != DMUB_STATUS_OK)
+               if (!dc_wake_and_execute_gpint(adev->dm.dc->ctx, cmd, res, NULL, DM_DMUB_WAIT_TYPE_WAIT))
                        return -EIO;
 
                usleep_range(100, 1000);
@@ -3026,7 +3019,6 @@ static int dmub_trace_mask_show(void *data, u64 *val)
        enum dmub_gpint_command cmd = DMUB_GPINT__GET_TRACE_BUFFER_MASK_WORD0;
        struct amdgpu_device *adev = data;
        struct dmub_srv *srv = adev->dm.dc->ctx->dmub_srv->dmub;
-       enum dmub_status status;
        u8 shift = 0;
        u64 raw = 0;
        u64 res = 0;
@@ -3036,23 +3028,12 @@ static int dmub_trace_mask_show(void *data, u64 *val)
                return -EINVAL;
 
        while (i < 4) {
-               status = dmub_srv_send_gpint_command(srv, cmd, 0, 30);
-
-               if (status == DMUB_STATUS_OK) {
-                       status = dmub_srv_get_gpint_response(srv, (u32 *) &raw);
-
-                       if (status == DMUB_STATUS_INVALID)
-                               return -EINVAL;
-                       else if (status != DMUB_STATUS_OK)
-                               return -EIO;
-               } else if (status == DMUB_STATUS_TIMEOUT) {
-                       return -ETIMEDOUT;
-               } else if (status == DMUB_STATUS_INVALID) {
-                       return -EINVAL;
-               } else {
+               uint32_t response;
+
+               if (!dc_wake_and_execute_gpint(adev->dm.dc->ctx, cmd, 0, &response, DM_DMUB_WAIT_TYPE_WAIT_WITH_REPLY))
                        return -EIO;
-               }
 
+               raw = response;
                usleep_range(100, 1000);
 
                cmd++;
index fea13bcd4dc75e42f12022cf1d3ecc1ff9b0aa36..4b93e7a529d5093f1faa26d624ea169bf6b11347 100644 (file)
@@ -301,17 +301,11 @@ bool dc_dmub_srv_optimized_init_done(struct dc_dmub_srv *dc_dmub_srv)
 bool dc_dmub_srv_notify_stream_mask(struct dc_dmub_srv *dc_dmub_srv,
                                    unsigned int stream_mask)
 {
-       struct dmub_srv *dmub;
-       const uint32_t timeout = 30;
-
        if (!dc_dmub_srv || !dc_dmub_srv->dmub)
                return false;
 
-       dmub = dc_dmub_srv->dmub;
-
-       return dmub_srv_send_gpint_command(
-                      dmub, DMUB_GPINT__IDLE_OPT_NOTIFY_STREAM_MASK,
-                      stream_mask, timeout) == DMUB_STATUS_OK;
+       return dc_wake_and_execute_gpint(dc_dmub_srv->ctx, DMUB_GPINT__IDLE_OPT_NOTIFY_STREAM_MASK,
+                                        stream_mask, NULL, DM_DMUB_WAIT_TYPE_WAIT);
 }
 
 bool dc_dmub_srv_is_restore_required(struct dc_dmub_srv *dc_dmub_srv)
@@ -1126,25 +1120,20 @@ bool dc_dmub_check_min_version(struct dmub_srv *srv)
 void dc_dmub_srv_enable_dpia_trace(const struct dc *dc)
 {
        struct dc_dmub_srv *dc_dmub_srv = dc->ctx->dmub_srv;
-       struct dmub_srv *dmub;
-       enum dmub_status status;
-       static const uint32_t timeout_us = 30;
 
        if (!dc_dmub_srv || !dc_dmub_srv->dmub) {
                DC_LOG_ERROR("%s: invalid parameters.", __func__);
                return;
        }
 
-       dmub = dc_dmub_srv->dmub;
-
-       status = dmub_srv_send_gpint_command(dmub, DMUB_GPINT__SET_TRACE_BUFFER_MASK_WORD1, 0x0010, timeout_us);
-       if (status != DMUB_STATUS_OK) {
+       if (!dc_wake_and_execute_gpint(dc->ctx, DMUB_GPINT__SET_TRACE_BUFFER_MASK_WORD1,
+                                      0x0010, NULL, DM_DMUB_WAIT_TYPE_WAIT)) {
                DC_LOG_ERROR("timeout updating trace buffer mask word\n");
                return;
        }
 
-       status = dmub_srv_send_gpint_command(dmub, DMUB_GPINT__UPDATE_TRACE_BUFFER_MASK, 0x0000, timeout_us);
-       if (status != DMUB_STATUS_OK) {
+       if (!dc_wake_and_execute_gpint(dc->ctx, DMUB_GPINT__UPDATE_TRACE_BUFFER_MASK,
+                                      0x0000, NULL, DM_DMUB_WAIT_TYPE_WAIT)) {
                DC_LOG_ERROR("timeout updating trace buffer mask word\n");
                return;
        }
@@ -1368,3 +1357,52 @@ bool dc_wake_and_execute_dmub_cmd_list(const struct dc_context *ctx, unsigned in
 
        return result;
 }
+
+static bool dc_dmub_execute_gpint(const struct dc_context *ctx, enum dmub_gpint_command command_code,
+                                 uint16_t param, uint32_t *response, enum dm_dmub_wait_type wait_type)
+{
+       struct dc_dmub_srv *dc_dmub_srv = ctx->dmub_srv;
+       const uint32_t wait_us = wait_type == DM_DMUB_WAIT_TYPE_NO_WAIT ? 0 : 30;
+       enum dmub_status status;
+
+       if (response)
+               *response = 0;
+
+       if (!dc_dmub_srv || !dc_dmub_srv->dmub)
+               return false;
+
+       status = dmub_srv_send_gpint_command(dc_dmub_srv->dmub, command_code, param, wait_us);
+       if (status != DMUB_STATUS_OK) {
+               if (status == DMUB_STATUS_TIMEOUT && wait_type == DM_DMUB_WAIT_TYPE_NO_WAIT)
+                       return true;
+
+               return false;
+       }
+
+       if (response && wait_type == DM_DMUB_WAIT_TYPE_WAIT_WITH_REPLY)
+               dmub_srv_get_gpint_response(dc_dmub_srv->dmub, response);
+
+       return true;
+}
+
+bool dc_wake_and_execute_gpint(const struct dc_context *ctx, enum dmub_gpint_command command_code,
+                              uint16_t param, uint32_t *response, enum dm_dmub_wait_type wait_type)
+{
+       struct dc_dmub_srv *dc_dmub_srv = ctx->dmub_srv;
+       bool result = false, reallow_idle = false;
+
+       if (!dc_dmub_srv || !dc_dmub_srv->dmub)
+               return false;
+
+       if (dc_dmub_srv->idle_allowed) {
+               dc_dmub_srv_apply_idle_power_optimizations(ctx->dc, false);
+               reallow_idle = true;
+       }
+
+       result = dc_dmub_execute_gpint(ctx, command_code, param, response, wait_type);
+
+       if (result && reallow_idle)
+               dc_dmub_srv_apply_idle_power_optimizations(ctx->dc, true);
+
+       return result;
+}
index 784ca3e4441438a5dd11812db0b936f17109e56e..952bfb368886e3adfc371afd671298f741024daf 100644 (file)
@@ -145,5 +145,16 @@ bool dc_wake_and_execute_dmub_cmd(const struct dc_context *ctx, union dmub_rb_cm
 bool dc_wake_and_execute_dmub_cmd_list(const struct dc_context *ctx, unsigned int count,
                                       union dmub_rb_cmd *cmd, enum dm_dmub_wait_type wait_type);
 
+/**
+ * dc_wake_and_execute_gpint()
+ *
+ * @ctx: DC context
+ * @command_code: The command ID to send to DMCUB
+ * @param: The parameter to message DMCUB
+ * @response: Optional response out value - may be NULL.
+ * @wait_type: The wait behavior for the execution
+ */
+bool dc_wake_and_execute_gpint(const struct dc_context *ctx, enum dmub_gpint_command command_code,
+                              uint16_t param, uint32_t *response, enum dm_dmub_wait_type wait_type);
 
 #endif /* _DMUB_DC_SRV_H_ */
index 3d7cef17f88181f890bb3285f1952e4b78086a8f..3e243e407bb87ec6934eea4899baa78cc0992423 100644 (file)
@@ -105,23 +105,18 @@ static enum dc_psr_state convert_psr_state(uint32_t raw_state)
  */
 static void dmub_psr_get_state(struct dmub_psr *dmub, enum dc_psr_state *state, uint8_t panel_inst)
 {
-       struct dmub_srv *srv = dmub->ctx->dmub_srv->dmub;
        uint32_t raw_state = 0;
        uint32_t retry_count = 0;
-       enum dmub_status status;
 
        do {
                // Send gpint command and wait for ack
-               status = dmub_srv_send_gpint_command(srv, DMUB_GPINT__GET_PSR_STATE, panel_inst, 30);
-
-               if (status == DMUB_STATUS_OK) {
-                       // GPINT was executed, get response
-                       dmub_srv_get_gpint_response(srv, &raw_state);
+               if (dc_wake_and_execute_gpint(dmub->ctx, DMUB_GPINT__GET_PSR_STATE, panel_inst, &raw_state,
+                                             DM_DMUB_WAIT_TYPE_WAIT_WITH_REPLY)) {
                        *state = convert_psr_state(raw_state);
-               } else
+               } else {
                        // Return invalid state when GPINT times out
                        *state = PSR_STATE_INVALID;
-
+               }
        } while (++retry_count <= 1000 && *state == PSR_STATE_INVALID);
 
        // Assert if max retry hit
@@ -452,13 +447,11 @@ static void dmub_psr_force_static(struct dmub_psr *dmub, uint8_t panel_inst)
  */
 static void dmub_psr_get_residency(struct dmub_psr *dmub, uint32_t *residency, uint8_t panel_inst)
 {
-       struct dmub_srv *srv = dmub->ctx->dmub_srv->dmub;
        uint16_t param = (uint16_t)(panel_inst << 8);
 
        /* Send gpint command and wait for ack */
-       dmub_srv_send_gpint_command(srv, DMUB_GPINT__PSR_RESIDENCY, param, 30);
-
-       dmub_srv_get_gpint_response(srv, residency);
+       dc_wake_and_execute_gpint(dmub->ctx, DMUB_GPINT__PSR_RESIDENCY, param, residency,
+                                 DM_DMUB_WAIT_TYPE_WAIT_WITH_REPLY);
 }
 
 static const struct dmub_psr_funcs psr_funcs = {