[PATCH] drm/radeon: fix halting UVD

Alex Deucher alexdeucher at gmail.com
Thu Aug 1 09:00:16 PDT 2013


On Thu, Aug 1, 2013 at 11:34 AM, Christian König
<deathsimple at vodafone.de> wrote:
> From: Christian König <christian.koenig at 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 at amd.com>
> Cc: stable at 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
>


More information about the dri-devel mailing list