Commit 6b061129 authored by Christian König's avatar Christian König Committed by Greg Kroah-Hartman

drm/radeon: fix halting UVD

commit 2858c00d upstream.

Removing the clock/power or resetting the VCPU can cause
hangs if that happens in the middle of a register write.

Stall the memory and register bus before putting the VCPU
into reset. Keep it in reset when unloading the module or
suspending.

v2: rebased on 3.10-stable tree
Signed-off-by: default avatarChristian König <christian.koenig@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 86813a19
...@@ -4854,10 +4854,10 @@ int evergreen_resume(struct radeon_device *rdev) ...@@ -4854,10 +4854,10 @@ int evergreen_resume(struct radeon_device *rdev)
int evergreen_suspend(struct radeon_device *rdev) int evergreen_suspend(struct radeon_device *rdev)
{ {
r600_audio_fini(rdev); r600_audio_fini(rdev);
r600_uvd_stop(rdev);
radeon_uvd_suspend(rdev); radeon_uvd_suspend(rdev);
r700_cp_stop(rdev); r700_cp_stop(rdev);
r600_dma_stop(rdev); r600_dma_stop(rdev);
r600_uvd_rbc_stop(rdev);
evergreen_irq_suspend(rdev); evergreen_irq_suspend(rdev);
radeon_wb_disable(rdev); radeon_wb_disable(rdev);
evergreen_pcie_gart_disable(rdev); evergreen_pcie_gart_disable(rdev);
...@@ -4988,6 +4988,7 @@ void evergreen_fini(struct radeon_device *rdev) ...@@ -4988,6 +4988,7 @@ void evergreen_fini(struct radeon_device *rdev)
radeon_ib_pool_fini(rdev); radeon_ib_pool_fini(rdev);
radeon_irq_kms_fini(rdev); radeon_irq_kms_fini(rdev);
evergreen_pcie_gart_fini(rdev); evergreen_pcie_gart_fini(rdev);
r600_uvd_stop(rdev);
radeon_uvd_fini(rdev); radeon_uvd_fini(rdev);
r600_vram_scratch_fini(rdev); r600_vram_scratch_fini(rdev);
radeon_gem_fini(rdev); radeon_gem_fini(rdev);
......
...@@ -2133,7 +2133,7 @@ int cayman_suspend(struct radeon_device *rdev) ...@@ -2133,7 +2133,7 @@ int cayman_suspend(struct radeon_device *rdev)
radeon_vm_manager_fini(rdev); radeon_vm_manager_fini(rdev);
cayman_cp_enable(rdev, false); cayman_cp_enable(rdev, false);
cayman_dma_stop(rdev); cayman_dma_stop(rdev);
r600_uvd_rbc_stop(rdev); r600_uvd_stop(rdev);
radeon_uvd_suspend(rdev); radeon_uvd_suspend(rdev);
evergreen_irq_suspend(rdev); evergreen_irq_suspend(rdev);
radeon_wb_disable(rdev); radeon_wb_disable(rdev);
...@@ -2265,6 +2265,7 @@ void cayman_fini(struct radeon_device *rdev) ...@@ -2265,6 +2265,7 @@ void cayman_fini(struct radeon_device *rdev)
radeon_vm_manager_fini(rdev); radeon_vm_manager_fini(rdev);
radeon_ib_pool_fini(rdev); radeon_ib_pool_fini(rdev);
radeon_irq_kms_fini(rdev); radeon_irq_kms_fini(rdev);
r600_uvd_stop(rdev);
radeon_uvd_fini(rdev); radeon_uvd_fini(rdev);
cayman_pcie_gart_fini(rdev); cayman_pcie_gart_fini(rdev);
r600_vram_scratch_fini(rdev); r600_vram_scratch_fini(rdev);
......
...@@ -2675,12 +2675,29 @@ int r600_uvd_rbc_start(struct radeon_device *rdev) ...@@ -2675,12 +2675,29 @@ int r600_uvd_rbc_start(struct radeon_device *rdev)
return 0; return 0;
} }
void r600_uvd_rbc_stop(struct radeon_device *rdev) void r600_uvd_stop(struct radeon_device *rdev)
{ {
struct radeon_ring *ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX]; struct radeon_ring *ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX];
/* force RBC into idle state */ /* force RBC into idle state */
WREG32(UVD_RBC_RB_CNTL, 0x11010101); WREG32(UVD_RBC_RB_CNTL, 0x11010101);
/* Stall UMC and register bus before resetting VCPU */
WREG32_P(UVD_LMI_CTRL2, 1 << 8, ~(1 << 8));
WREG32_P(UVD_RB_ARB_CTRL, 1 << 3, ~(1 << 3));
mdelay(1);
/* put VCPU into reset */
WREG32(UVD_SOFT_RESET, VCPU_SOFT_RESET);
mdelay(5);
/* disable VCPU clock */
WREG32(UVD_VCPU_CNTL, 0x0);
/* Unstall UMC and register bus */
WREG32_P(UVD_LMI_CTRL2, 0, ~(1 << 8));
WREG32_P(UVD_RB_ARB_CTRL, 0, ~(1 << 3));
ring->ready = false; ring->ready = false;
} }
...@@ -2700,6 +2717,11 @@ int r600_uvd_init(struct radeon_device *rdev) ...@@ -2700,6 +2717,11 @@ int r600_uvd_init(struct radeon_device *rdev)
/* disable interupt */ /* disable interupt */
WREG32_P(UVD_MASTINT_EN, 0, ~(1 << 1)); WREG32_P(UVD_MASTINT_EN, 0, ~(1 << 1));
/* Stall UMC and register bus before resetting VCPU */
WREG32_P(UVD_LMI_CTRL2, 1 << 8, ~(1 << 8));
WREG32_P(UVD_RB_ARB_CTRL, 1 << 3, ~(1 << 3));
mdelay(1);
/* put LMI, VCPU, RBC etc... into reset */ /* put LMI, VCPU, RBC etc... into reset */
WREG32(UVD_SOFT_RESET, LMI_SOFT_RESET | VCPU_SOFT_RESET | WREG32(UVD_SOFT_RESET, LMI_SOFT_RESET | VCPU_SOFT_RESET |
LBSI_SOFT_RESET | RBC_SOFT_RESET | CSM_SOFT_RESET | LBSI_SOFT_RESET | RBC_SOFT_RESET | CSM_SOFT_RESET |
...@@ -2729,10 +2751,6 @@ int r600_uvd_init(struct radeon_device *rdev) ...@@ -2729,10 +2751,6 @@ int r600_uvd_init(struct radeon_device *rdev)
WREG32(UVD_MPC_SET_ALU, 0); WREG32(UVD_MPC_SET_ALU, 0);
WREG32(UVD_MPC_SET_MUX, 0x88); WREG32(UVD_MPC_SET_MUX, 0x88);
/* Stall UMC */
WREG32_P(UVD_LMI_CTRL2, 1 << 8, ~(1 << 8));
WREG32_P(UVD_RB_ARB_CTRL, 1 << 3, ~(1 << 3));
/* take all subblocks out of reset, except VCPU */ /* take all subblocks out of reset, except VCPU */
WREG32(UVD_SOFT_RESET, VCPU_SOFT_RESET); WREG32(UVD_SOFT_RESET, VCPU_SOFT_RESET);
mdelay(5); mdelay(5);
......
...@@ -399,7 +399,7 @@ uint64_t r600_get_gpu_clock_counter(struct radeon_device *rdev); ...@@ -399,7 +399,7 @@ uint64_t r600_get_gpu_clock_counter(struct radeon_device *rdev);
/* uvd */ /* uvd */
int r600_uvd_init(struct radeon_device *rdev); int r600_uvd_init(struct radeon_device *rdev);
int r600_uvd_rbc_start(struct radeon_device *rdev); int r600_uvd_rbc_start(struct radeon_device *rdev);
void r600_uvd_rbc_stop(struct radeon_device *rdev); void r600_uvd_stop(struct radeon_device *rdev);
int r600_uvd_ib_test(struct radeon_device *rdev, struct radeon_ring *ring); int r600_uvd_ib_test(struct radeon_device *rdev, struct radeon_ring *ring);
void r600_uvd_fence_emit(struct radeon_device *rdev, void r600_uvd_fence_emit(struct radeon_device *rdev,
struct radeon_fence *fence); struct radeon_fence *fence);
......
...@@ -1983,6 +1983,7 @@ int rv770_resume(struct radeon_device *rdev) ...@@ -1983,6 +1983,7 @@ int rv770_resume(struct radeon_device *rdev)
int rv770_suspend(struct radeon_device *rdev) int rv770_suspend(struct radeon_device *rdev)
{ {
r600_audio_fini(rdev); r600_audio_fini(rdev);
r600_uvd_stop(rdev);
radeon_uvd_suspend(rdev); radeon_uvd_suspend(rdev);
r700_cp_stop(rdev); r700_cp_stop(rdev);
r600_dma_stop(rdev); r600_dma_stop(rdev);
...@@ -2098,6 +2099,7 @@ void rv770_fini(struct radeon_device *rdev) ...@@ -2098,6 +2099,7 @@ void rv770_fini(struct radeon_device *rdev)
radeon_ib_pool_fini(rdev); radeon_ib_pool_fini(rdev);
radeon_irq_kms_fini(rdev); radeon_irq_kms_fini(rdev);
rv770_pcie_gart_fini(rdev); rv770_pcie_gart_fini(rdev);
r600_uvd_stop(rdev);
radeon_uvd_fini(rdev); radeon_uvd_fini(rdev);
r600_vram_scratch_fini(rdev); r600_vram_scratch_fini(rdev);
radeon_gem_fini(rdev); radeon_gem_fini(rdev);
......
...@@ -5473,7 +5473,7 @@ int si_suspend(struct radeon_device *rdev) ...@@ -5473,7 +5473,7 @@ int si_suspend(struct radeon_device *rdev)
si_cp_enable(rdev, false); si_cp_enable(rdev, false);
cayman_dma_stop(rdev); cayman_dma_stop(rdev);
if (rdev->has_uvd) { if (rdev->has_uvd) {
r600_uvd_rbc_stop(rdev); r600_uvd_stop(rdev);
radeon_uvd_suspend(rdev); radeon_uvd_suspend(rdev);
} }
si_irq_suspend(rdev); si_irq_suspend(rdev);
...@@ -5613,8 +5613,10 @@ void si_fini(struct radeon_device *rdev) ...@@ -5613,8 +5613,10 @@ void si_fini(struct radeon_device *rdev)
radeon_vm_manager_fini(rdev); radeon_vm_manager_fini(rdev);
radeon_ib_pool_fini(rdev); radeon_ib_pool_fini(rdev);
radeon_irq_kms_fini(rdev); radeon_irq_kms_fini(rdev);
if (rdev->has_uvd) if (rdev->has_uvd) {
r600_uvd_stop(rdev);
radeon_uvd_fini(rdev); radeon_uvd_fini(rdev);
}
si_pcie_gart_fini(rdev); si_pcie_gart_fini(rdev);
r600_vram_scratch_fini(rdev); r600_vram_scratch_fini(rdev);
radeon_gem_fini(rdev); radeon_gem_fini(rdev);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment