Skip to content

Commit a71849c

Browse files
Evan Quanalexdeucher
authored andcommitted
drm/amd/pm: fix the deadlock issue observed on SI
The adev->pm.mutx is already held at the beginning of amdgpu_dpm_compute_clocks/amdgpu_dpm_enable_uvd/amdgpu_dpm_enable_vce. But on their calling path, amdgpu_display_bandwidth_update will be called and thus its sub functions amdgpu_dpm_get_sclk/mclk. They will then try to acquire the same adev->pm.mutex and deadlock will occur. By placing amdgpu_display_bandwidth_update outside of adev->pm.mutex protection(considering logically they do not need such protection) and restructuring the call flow accordingly, we can eliminate the deadlock issue. This comes with no real logics change. Fixes: 3712e7a ("drm/amd/pm: unified lock protections in amdgpu_dpm.c") Reported-by: Paul Menzel <[email protected]> Reported-by: Arthur Marsh <[email protected]> Link: https://lore.kernel.org/all/[email protected]/ BugLink: https://gitlab.freedesktop.org/drm/amd/-/issues/1957 Signed-off-by: Evan Quan <[email protected]> Reviewed-by: Lijo Lazar <[email protected]> Signed-off-by: Alex Deucher <[email protected]>
1 parent 65e5498 commit a71849c

File tree

4 files changed

+39
-55
lines changed

4 files changed

+39
-55
lines changed

drivers/gpu/drm/amd/pm/amdgpu_dpm.c

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -427,13 +427,23 @@ int amdgpu_dpm_read_sensor(struct amdgpu_device *adev, enum amd_pp_sensors senso
427427
void amdgpu_dpm_compute_clocks(struct amdgpu_device *adev)
428428
{
429429
const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs;
430+
int i;
430431

431432
if (!adev->pm.dpm_enabled)
432433
return;
433434

434435
if (!pp_funcs->pm_compute_clocks)
435436
return;
436437

438+
if (adev->mode_info.num_crtc)
439+
amdgpu_display_bandwidth_update(adev);
440+
441+
for (i = 0; i < AMDGPU_MAX_RINGS; i++) {
442+
struct amdgpu_ring *ring = adev->rings[i];
443+
if (ring && ring->sched.ready)
444+
amdgpu_fence_wait_empty(ring);
445+
}
446+
437447
mutex_lock(&adev->pm.mutex);
438448
pp_funcs->pm_compute_clocks(adev->powerplay.pp_handle);
439449
mutex_unlock(&adev->pm.mutex);
@@ -443,6 +453,20 @@ void amdgpu_dpm_enable_uvd(struct amdgpu_device *adev, bool enable)
443453
{
444454
int ret = 0;
445455

456+
if (adev->family == AMDGPU_FAMILY_SI) {
457+
mutex_lock(&adev->pm.mutex);
458+
if (enable) {
459+
adev->pm.dpm.uvd_active = true;
460+
adev->pm.dpm.state = POWER_STATE_TYPE_INTERNAL_UVD;
461+
} else {
462+
adev->pm.dpm.uvd_active = false;
463+
}
464+
mutex_unlock(&adev->pm.mutex);
465+
466+
amdgpu_dpm_compute_clocks(adev);
467+
return;
468+
}
469+
446470
ret = amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_UVD, !enable);
447471
if (ret)
448472
DRM_ERROR("Dpm %s uvd failed, ret = %d. \n",
@@ -453,6 +477,21 @@ void amdgpu_dpm_enable_vce(struct amdgpu_device *adev, bool enable)
453477
{
454478
int ret = 0;
455479

480+
if (adev->family == AMDGPU_FAMILY_SI) {
481+
mutex_lock(&adev->pm.mutex);
482+
if (enable) {
483+
adev->pm.dpm.vce_active = true;
484+
/* XXX select vce level based on ring/task */
485+
adev->pm.dpm.vce_level = AMD_VCE_LEVEL_AC_ALL;
486+
} else {
487+
adev->pm.dpm.vce_active = false;
488+
}
489+
mutex_unlock(&adev->pm.mutex);
490+
491+
amdgpu_dpm_compute_clocks(adev);
492+
return;
493+
}
494+
456495
ret = amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_VCE, !enable);
457496
if (ret)
458497
DRM_ERROR("Dpm %s vce failed, ret = %d. \n",

drivers/gpu/drm/amd/pm/legacy-dpm/legacy_dpm.c

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1028,16 +1028,6 @@ static int amdgpu_dpm_change_power_state_locked(struct amdgpu_device *adev)
10281028
void amdgpu_legacy_dpm_compute_clocks(void *handle)
10291029
{
10301030
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
1031-
int i = 0;
1032-
1033-
if (adev->mode_info.num_crtc)
1034-
amdgpu_display_bandwidth_update(adev);
1035-
1036-
for (i = 0; i < AMDGPU_MAX_RINGS; i++) {
1037-
struct amdgpu_ring *ring = adev->rings[i];
1038-
if (ring && ring->sched.ready)
1039-
amdgpu_fence_wait_empty(ring);
1040-
}
10411031

10421032
amdgpu_dpm_get_active_displays(adev);
10431033

drivers/gpu/drm/amd/pm/legacy-dpm/si_dpm.c

Lines changed: 0 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -3892,40 +3892,6 @@ static int si_set_boot_state(struct amdgpu_device *adev)
38923892
}
38933893
#endif
38943894

3895-
static int si_set_powergating_by_smu(void *handle,
3896-
uint32_t block_type,
3897-
bool gate)
3898-
{
3899-
struct amdgpu_device *adev = (struct amdgpu_device *)handle;
3900-
3901-
switch (block_type) {
3902-
case AMD_IP_BLOCK_TYPE_UVD:
3903-
if (!gate) {
3904-
adev->pm.dpm.uvd_active = true;
3905-
adev->pm.dpm.state = POWER_STATE_TYPE_INTERNAL_UVD;
3906-
} else {
3907-
adev->pm.dpm.uvd_active = false;
3908-
}
3909-
3910-
amdgpu_legacy_dpm_compute_clocks(handle);
3911-
break;
3912-
case AMD_IP_BLOCK_TYPE_VCE:
3913-
if (!gate) {
3914-
adev->pm.dpm.vce_active = true;
3915-
/* XXX select vce level based on ring/task */
3916-
adev->pm.dpm.vce_level = AMD_VCE_LEVEL_AC_ALL;
3917-
} else {
3918-
adev->pm.dpm.vce_active = false;
3919-
}
3920-
3921-
amdgpu_legacy_dpm_compute_clocks(handle);
3922-
break;
3923-
default:
3924-
break;
3925-
}
3926-
return 0;
3927-
}
3928-
39293895
static int si_set_sw_state(struct amdgpu_device *adev)
39303896
{
39313897
return (amdgpu_si_send_msg_to_smc(adev, PPSMC_MSG_SwitchToSwState) == PPSMC_Result_OK) ?
@@ -8125,7 +8091,6 @@ static const struct amd_pm_funcs si_dpm_funcs = {
81258091
.print_power_state = &si_dpm_print_power_state,
81268092
.debugfs_print_current_performance_level = &si_dpm_debugfs_print_current_performance_level,
81278093
.force_performance_level = &si_dpm_force_performance_level,
8128-
.set_powergating_by_smu = &si_set_powergating_by_smu,
81298094
.vblank_too_short = &si_dpm_vblank_too_short,
81308095
.set_fan_control_mode = &si_dpm_set_fan_control_mode,
81318096
.get_fan_control_mode = &si_dpm_get_fan_control_mode,

drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1487,16 +1487,6 @@ static void pp_pm_compute_clocks(void *handle)
14871487
{
14881488
struct pp_hwmgr *hwmgr = handle;
14891489
struct amdgpu_device *adev = hwmgr->adev;
1490-
int i = 0;
1491-
1492-
if (adev->mode_info.num_crtc)
1493-
amdgpu_display_bandwidth_update(adev);
1494-
1495-
for (i = 0; i < AMDGPU_MAX_RINGS; i++) {
1496-
struct amdgpu_ring *ring = adev->rings[i];
1497-
if (ring && ring->sched.ready)
1498-
amdgpu_fence_wait_empty(ring);
1499-
}
15001490

15011491
if (!amdgpu_device_has_dc_support(adev)) {
15021492
amdgpu_dpm_get_active_displays(adev);

0 commit comments

Comments
 (0)