diff mbox

drm/radeon: fix halting UVD

Message ID 1375371247-2318-1-git-send-email-deathsimple@vodafone.de (mailing list archive)
State New, archived
Headers show

Commit Message

Christian König Aug. 1, 2013, 3:34 p.m. UTC
From: Christian König <christian.koenig@amd.com>

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: Christian König <christian.koenig@amd.com>
Cc: stable@vger.kernel.org
---
 drivers/gpu/drm/radeon/cik.c         |    3 ++-
 drivers/gpu/drm/radeon/evergreen.c   |    3 ++-
 drivers/gpu/drm/radeon/ni.c          |    3 ++-
 drivers/gpu/drm/radeon/r600.c        |   28 +++++++++++++++++++++++-----
 drivers/gpu/drm/radeon/radeon_asic.h |    2 +-
 drivers/gpu/drm/radeon/rv770.c       |    2 ++
 drivers/gpu/drm/radeon/si.c          |    6 ++++--
 7 files changed, 36 insertions(+), 11 deletions(-)

Comments

Alex Deucher Aug. 1, 2013, 4 p.m. UTC | #1
On Thu, Aug 1, 2013 at 11:34 AM, Christian König
<deathsimple@vodafone.de> wrote:
> From: Christian König <christian.koenig@amd.com>
>
> 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: Christian König <christian.koenig@amd.com>
> Cc: stable@vger.kernel.org

Applied to my -fixes queue.

Alex

> ---
>  drivers/gpu/drm/radeon/cik.c         |    3 ++-
>  drivers/gpu/drm/radeon/evergreen.c   |    3 ++-
>  drivers/gpu/drm/radeon/ni.c          |    3 ++-
>  drivers/gpu/drm/radeon/r600.c        |   28 +++++++++++++++++++++++-----
>  drivers/gpu/drm/radeon/radeon_asic.h |    2 +-
>  drivers/gpu/drm/radeon/rv770.c       |    2 ++
>  drivers/gpu/drm/radeon/si.c          |    6 ++++--
>  7 files changed, 36 insertions(+), 11 deletions(-)
>
> diff --git a/drivers/gpu/drm/radeon/cik.c b/drivers/gpu/drm/radeon/cik.c
> index 6dacec4..524db70 100644
> --- a/drivers/gpu/drm/radeon/cik.c
> +++ b/drivers/gpu/drm/radeon/cik.c
> @@ -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);
> diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c
> index 038dcac..5b98e57 100644
> --- a/drivers/gpu/drm/radeon/evergreen.c
> +++ b/drivers/gpu/drm/radeon/evergreen.c
> @@ -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);
> diff --git a/drivers/gpu/drm/radeon/ni.c b/drivers/gpu/drm/radeon/ni.c
> index 56bd4f3..16e91b0 100644
> --- a/drivers/gpu/drm/radeon/ni.c
> +++ b/drivers/gpu/drm/radeon/ni.c
> @@ -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);
> diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c
> index 10f712e..0a9553a 100644
> --- a/drivers/gpu/drm/radeon/r600.c
> +++ b/drivers/gpu/drm/radeon/r600.c
> @@ -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);
> diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h
> index 902479f..3d61d5a 100644
> --- a/drivers/gpu/drm/radeon/radeon_asic.h
> +++ b/drivers/gpu/drm/radeon/radeon_asic.h
> @@ -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);
> diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c
> index 30ea14e..f101013 100644
> --- a/drivers/gpu/drm/radeon/rv770.c
> +++ b/drivers/gpu/drm/radeon/rv770.c
> @@ -1983,6 +1983,7 @@ int rv770_resume(struct radeon_device *rdev)
>  int rv770_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);
> @@ -2098,6 +2099,7 @@ void rv770_fini(struct radeon_device *rdev)
>         radeon_ib_pool_fini(rdev);
>         radeon_irq_kms_fini(rdev);
>         rv770_pcie_gart_fini(rdev);
> +       r600_uvd_stop(rdev);
>         radeon_uvd_fini(rdev);
>         r600_vram_scratch_fini(rdev);
>         radeon_gem_fini(rdev);
> diff --git a/drivers/gpu/drm/radeon/si.c b/drivers/gpu/drm/radeon/si.c
> index 6ca9046..242c1ac 100644
> --- a/drivers/gpu/drm/radeon/si.c
> +++ b/drivers/gpu/drm/radeon/si.c
> @@ -6621,7 +6621,7 @@ int si_suspend(struct radeon_device *rdev)
>         si_cp_enable(rdev, false);
>         cayman_dma_stop(rdev);
>         if (rdev->has_uvd) {
> -               r600_uvd_rbc_stop(rdev);
> +               r600_uvd_stop(rdev);
>                 radeon_uvd_suspend(rdev);
>         }
>         si_irq_suspend(rdev);
> @@ -6763,8 +6763,10 @@ void si_fini(struct radeon_device *rdev)
>         radeon_vm_manager_fini(rdev);
>         radeon_ib_pool_fini(rdev);
>         radeon_irq_kms_fini(rdev);
> -       if (rdev->has_uvd)
> +       if (rdev->has_uvd) {
> +               r600_uvd_stop(rdev);
>                 radeon_uvd_fini(rdev);
> +       }
>         si_pcie_gart_fini(rdev);
>         r600_vram_scratch_fini(rdev);
>         radeon_gem_fini(rdev);
> --
> 1.7.9.5
>
diff mbox

Patch

diff --git a/drivers/gpu/drm/radeon/cik.c b/drivers/gpu/drm/radeon/cik.c
index 6dacec4..524db70 100644
--- a/drivers/gpu/drm/radeon/cik.c
+++ b/drivers/gpu/drm/radeon/cik.c
@@ -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);
diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c
index 038dcac..5b98e57 100644
--- a/drivers/gpu/drm/radeon/evergreen.c
+++ b/drivers/gpu/drm/radeon/evergreen.c
@@ -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);
diff --git a/drivers/gpu/drm/radeon/ni.c b/drivers/gpu/drm/radeon/ni.c
index 56bd4f3..16e91b0 100644
--- a/drivers/gpu/drm/radeon/ni.c
+++ b/drivers/gpu/drm/radeon/ni.c
@@ -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);
diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c
index 10f712e..0a9553a 100644
--- a/drivers/gpu/drm/radeon/r600.c
+++ b/drivers/gpu/drm/radeon/r600.c
@@ -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);
diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h
index 902479f..3d61d5a 100644
--- a/drivers/gpu/drm/radeon/radeon_asic.h
+++ b/drivers/gpu/drm/radeon/radeon_asic.h
@@ -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);
diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c
index 30ea14e..f101013 100644
--- a/drivers/gpu/drm/radeon/rv770.c
+++ b/drivers/gpu/drm/radeon/rv770.c
@@ -1983,6 +1983,7 @@  int rv770_resume(struct radeon_device *rdev)
 int rv770_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);
@@ -2098,6 +2099,7 @@  void rv770_fini(struct radeon_device *rdev)
 	radeon_ib_pool_fini(rdev);
 	radeon_irq_kms_fini(rdev);
 	rv770_pcie_gart_fini(rdev);
+	r600_uvd_stop(rdev);
 	radeon_uvd_fini(rdev);
 	r600_vram_scratch_fini(rdev);
 	radeon_gem_fini(rdev);
diff --git a/drivers/gpu/drm/radeon/si.c b/drivers/gpu/drm/radeon/si.c
index 6ca9046..242c1ac 100644
--- a/drivers/gpu/drm/radeon/si.c
+++ b/drivers/gpu/drm/radeon/si.c
@@ -6621,7 +6621,7 @@  int si_suspend(struct radeon_device *rdev)
 	si_cp_enable(rdev, false);
 	cayman_dma_stop(rdev);
 	if (rdev->has_uvd) {
-		r600_uvd_rbc_stop(rdev);
+		r600_uvd_stop(rdev);
 		radeon_uvd_suspend(rdev);
 	}
 	si_irq_suspend(rdev);
@@ -6763,8 +6763,10 @@  void si_fini(struct radeon_device *rdev)
 	radeon_vm_manager_fini(rdev);
 	radeon_ib_pool_fini(rdev);
 	radeon_irq_kms_fini(rdev);
-	if (rdev->has_uvd)
+	if (rdev->has_uvd) {
+		r600_uvd_stop(rdev);
 		radeon_uvd_fini(rdev);
+	}
 	si_pcie_gart_fini(rdev);
 	r600_vram_scratch_fini(rdev);
 	radeon_gem_fini(rdev);