summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/amd/display/dmub/src
diff options
context:
space:
mode:
authorDillon Varone <dillon.varone@amd.com>2025-04-28 12:34:27 -0400
committerAlex Deucher <alexander.deucher@amd.com>2025-05-13 09:27:36 -0400
commitdd141b16b3a2979a01194615dfe87dbba9d87045 (patch)
treee36e860b6ebe610f498f4433e39b43f9be2587e9 /drivers/gpu/drm/amd/display/dmub/src
parent7ac37f0dcd2e0b729fa7b5513908dc8ab802b540 (diff)
drm/amd/display: Fix race in dmub_srv_wait_for_pending
[WHY] If commands are being submitted to DMCUB while concurrently waiting for pending commands to complete, rptr and wptr may never match again, and reported command count will not update. [HOW] Modify dmub_srv_wait_for_pending to constantly check wptr and rptr match, and update inbox status whenever a message is sent to avoid the race and determine message completion or idle as quickly as possible. Reviewed-by: Nicholas Kazlauskas <nicholas.kazlauskas@amd.com> Signed-off-by: Dillon Varone <dillon.varone@amd.com> Signed-off-by: Ray Wu <ray.wu@amd.com> Tested-by: Daniel Wheeler <daniel.wheeler@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Diffstat (limited to 'drivers/gpu/drm/amd/display/dmub/src')
-rw-r--r--drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c58
1 files changed, 31 insertions, 27 deletions
diff --git a/drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c b/drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c
index c917a70b3c19..acca7943a8c8 100644
--- a/drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c
+++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c
@@ -952,10 +952,8 @@ enum dmub_status dmub_srv_wait_for_pending(struct dmub_srv *dmub,
!dmub->hw_funcs.get_inbox1_wptr)
return DMUB_STATUS_INVALID;
- /* take a snapshot of the required mailbox state */
- scratch_inbox1.rb.wrpt = dmub->hw_funcs.get_inbox1_wptr(dmub);
-
for (i = 0; i <= timeout_us; i += polling_interval_us) {
+ scratch_inbox1.rb.wrpt = dmub->hw_funcs.get_inbox1_wptr(dmub);
scratch_inbox1.rb.rptr = dmub->hw_funcs.get_inbox1_rptr(dmub);
scratch_reg_inbox0.is_pending = scratch_reg_inbox0.is_pending &&
@@ -978,30 +976,6 @@ enum dmub_status dmub_srv_wait_for_pending(struct dmub_srv *dmub,
return DMUB_STATUS_TIMEOUT;
}
-static enum dmub_status dmub_srv_update_inbox_status(struct dmub_srv *dmub)
-{
- uint32_t rptr;
-
- /* update inbox1 state */
- rptr = dmub->hw_funcs.get_inbox1_rptr(dmub);
-
- if (rptr > dmub->inbox1.rb.capacity)
- return DMUB_STATUS_HW_FAILURE;
-
- if (dmub->inbox1.rb.rptr > rptr) {
- /* rb wrapped */
- dmub->inbox1.num_reported += (rptr + dmub->inbox1.rb.capacity - dmub->inbox1.rb.rptr) / DMUB_RB_CMD_SIZE;
- } else {
- dmub->inbox1.num_reported += (rptr - dmub->inbox1.rb.rptr) / DMUB_RB_CMD_SIZE;
- }
- dmub->inbox1.rb.rptr = rptr;
-
- /* update reg_inbox0 */
- dmub_srv_update_reg_inbox0_status(dmub);
-
- return DMUB_STATUS_OK;
-}
-
enum dmub_status dmub_srv_wait_for_idle(struct dmub_srv *dmub,
uint32_t timeout_us)
{
@@ -1353,3 +1327,33 @@ enum dmub_status dmub_srv_wait_for_inbox_free(struct dmub_srv *dmub,
return DMUB_STATUS_TIMEOUT;
}
+
+enum dmub_status dmub_srv_update_inbox_status(struct dmub_srv *dmub)
+{
+ uint32_t rptr;
+
+ if (!dmub->hw_init)
+ return DMUB_STATUS_INVALID;
+
+ if (dmub->power_state != DMUB_POWER_STATE_D0)
+ return DMUB_STATUS_POWER_STATE_D3;
+
+ /* update inbox1 state */
+ rptr = dmub->hw_funcs.get_inbox1_rptr(dmub);
+
+ if (rptr > dmub->inbox1.rb.capacity)
+ return DMUB_STATUS_HW_FAILURE;
+
+ if (dmub->inbox1.rb.rptr > rptr) {
+ /* rb wrapped */
+ dmub->inbox1.num_reported += (rptr + dmub->inbox1.rb.capacity - dmub->inbox1.rb.rptr) / DMUB_RB_CMD_SIZE;
+ } else {
+ dmub->inbox1.num_reported += (rptr - dmub->inbox1.rb.rptr) / DMUB_RB_CMD_SIZE;
+ }
+ dmub->inbox1.rb.rptr = rptr;
+
+ /* update reg_inbox0 */
+ dmub_srv_update_reg_inbox0_status(dmub);
+
+ return DMUB_STATUS_OK;
+}