Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2858c00d authored by Christian König's avatar Christian König Committed by Alex Deucher
Browse files

drm/radeon: fix halting UVD



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.

Signed-off-by: default avatarChristian König <christian.koenig@amd.com>
Cc: stable@vger.kernel.org
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent 797f203f
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -6194,7 +6194,7 @@ int cik_suspend(struct radeon_device *rdev)
	radeon_vm_manager_fini(rdev);
	cik_cp_enable(rdev, false);
	cik_sdma_enable(rdev, false);
	r600_uvd_rbc_stop(rdev);
	r600_uvd_stop(rdev);
	radeon_uvd_suspend(rdev);
	cik_irq_suspend(rdev);
	radeon_wb_disable(rdev);
@@ -6358,6 +6358,7 @@ void cik_fini(struct radeon_device *rdev)
	radeon_vm_manager_fini(rdev);
	radeon_ib_pool_fini(rdev);
	radeon_irq_kms_fini(rdev);
	r600_uvd_stop(rdev);
	radeon_uvd_fini(rdev);
	cik_pcie_gart_fini(rdev);
	r600_vram_scratch_fini(rdev);
+2 −1
Original line number Diff line number Diff line
@@ -5291,10 +5291,10 @@ int evergreen_resume(struct radeon_device *rdev)
int evergreen_suspend(struct radeon_device *rdev)
{
	r600_audio_fini(rdev);
	r600_uvd_stop(rdev);
	radeon_uvd_suspend(rdev);
	r700_cp_stop(rdev);
	r600_dma_stop(rdev);
	r600_uvd_rbc_stop(rdev);
	evergreen_irq_suspend(rdev);
	radeon_wb_disable(rdev);
	evergreen_pcie_gart_disable(rdev);
@@ -5429,6 +5429,7 @@ void evergreen_fini(struct radeon_device *rdev)
	radeon_ib_pool_fini(rdev);
	radeon_irq_kms_fini(rdev);
	evergreen_pcie_gart_fini(rdev);
	r600_uvd_stop(rdev);
	radeon_uvd_fini(rdev);
	r600_vram_scratch_fini(rdev);
	radeon_gem_fini(rdev);
+2 −1
Original line number Diff line number Diff line
@@ -2286,7 +2286,7 @@ int cayman_suspend(struct radeon_device *rdev)
	radeon_vm_manager_fini(rdev);
	cayman_cp_enable(rdev, false);
	cayman_dma_stop(rdev);
	r600_uvd_rbc_stop(rdev);
	r600_uvd_stop(rdev);
	radeon_uvd_suspend(rdev);
	evergreen_irq_suspend(rdev);
	radeon_wb_disable(rdev);
@@ -2418,6 +2418,7 @@ void cayman_fini(struct radeon_device *rdev)
	radeon_vm_manager_fini(rdev);
	radeon_ib_pool_fini(rdev);
	radeon_irq_kms_fini(rdev);
	r600_uvd_stop(rdev);
	radeon_uvd_fini(rdev);
	cayman_pcie_gart_fini(rdev);
	r600_vram_scratch_fini(rdev);
+23 −5
Original line number Diff line number Diff line
@@ -2697,12 +2697,29 @@ int r600_uvd_rbc_start(struct radeon_device *rdev)
	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];

	/* force RBC into idle state */
	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;
}

@@ -2722,6 +2739,11 @@ int r600_uvd_init(struct radeon_device *rdev)
	/* disable interupt */
	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 */
	WREG32(UVD_SOFT_RESET, LMI_SOFT_RESET | VCPU_SOFT_RESET |
	       LBSI_SOFT_RESET | RBC_SOFT_RESET | CSM_SOFT_RESET |
@@ -2751,10 +2773,6 @@ int r600_uvd_init(struct radeon_device *rdev)
	WREG32(UVD_MPC_SET_ALU, 0);
	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 */
	WREG32(UVD_SOFT_RESET, VCPU_SOFT_RESET);
	mdelay(5);
+1 −1
Original line number Diff line number Diff line
@@ -441,7 +441,7 @@ void rs780_dpm_debugfs_print_current_performance_level(struct radeon_device *rde
/* uvd */
int r600_uvd_init(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);
void r600_uvd_fence_emit(struct radeon_device *rdev,
			 struct radeon_fence *fence);
Loading