[PATCH] drm/radeon: never unpin UVD bo v2

Alex Deucher alexdeucher at gmail.com
Fri Jul 12 07:23:44 PDT 2013


On Fri, Jul 12, 2013 at 3:40 AM, Christian König
<deathsimple at vodafone.de> wrote:
> From: Christian König <christian.koenig at amd.com>
>
> Changing the UVD BOs offset on suspend/resume doesn't work cause the VCPU
> internally keeps pointers to it. Just keep it always pinned and save the
> content manually.
>
> Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=66425
>
> v2: fix compiler warning
>
> Signed-off-by: Christian König <christian.koenig at amd.com>
> Cc: stable at vger.kernel.org

I'll send this version to stable.  I had to tweak it slightly for CIK
for 3.11.  Applied.

Thanks,

Alex


> ---
>  drivers/gpu/drm/radeon/radeon.h       |    3 +-
>  drivers/gpu/drm/radeon/radeon_fence.c |    2 +-
>  drivers/gpu/drm/radeon/radeon_uvd.c   |  100 ++++++++++++++++-----------------
>  drivers/gpu/drm/radeon/rv770.c        |    2 +-
>  4 files changed, 52 insertions(+), 55 deletions(-)
>
> diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
> index 9b7025d..7b7d23a 100644
> --- a/drivers/gpu/drm/radeon/radeon.h
> +++ b/drivers/gpu/drm/radeon/radeon.h
> @@ -1460,6 +1460,8 @@ struct radeon_uvd {
>         struct radeon_bo        *vcpu_bo;
>         void                    *cpu_addr;
>         uint64_t                gpu_addr;
> +       void                    *saved_bo;
> +       unsigned                fw_size;
>         atomic_t                handles[RADEON_MAX_UVD_HANDLES];
>         struct drm_file         *filp[RADEON_MAX_UVD_HANDLES];
>         struct delayed_work     idle_work;
> @@ -2054,7 +2056,6 @@ struct radeon_device {
>         const struct firmware *rlc_fw;  /* r6/700 RLC firmware */
>         const struct firmware *mc_fw;   /* NI MC firmware */
>         const struct firmware *ce_fw;   /* SI CE firmware */
> -       const struct firmware *uvd_fw;  /* UVD firmware */
>         const struct firmware *mec_fw;  /* CIK MEC firmware */
>         const struct firmware *sdma_fw; /* CIK SDMA firmware */
>         const struct firmware *smc_fw;  /* SMC firmware */
> diff --git a/drivers/gpu/drm/radeon/radeon_fence.c b/drivers/gpu/drm/radeon/radeon_fence.c
> index ddb8f8e..7ddb0ef 100644
> --- a/drivers/gpu/drm/radeon/radeon_fence.c
> +++ b/drivers/gpu/drm/radeon/radeon_fence.c
> @@ -782,7 +782,7 @@ int radeon_fence_driver_start_ring(struct radeon_device *rdev, int ring)
>
>                 } else {
>                         /* put fence directly behind firmware */
> -                       index = ALIGN(rdev->uvd_fw->size, 8);
> +                       index = ALIGN(rdev->uvd.fw_size, 8);
>                         rdev->fence_drv[ring].cpu_addr = rdev->uvd.cpu_addr + index;
>                         rdev->fence_drv[ring].gpu_addr = rdev->uvd.gpu_addr + index;
>                 }
> diff --git a/drivers/gpu/drm/radeon/radeon_uvd.c b/drivers/gpu/drm/radeon/radeon_uvd.c
> index 41efcec..43b083d 100644
> --- a/drivers/gpu/drm/radeon/radeon_uvd.c
> +++ b/drivers/gpu/drm/radeon/radeon_uvd.c
> @@ -57,6 +57,7 @@ static void radeon_uvd_idle_work_handler(struct work_struct *work);
>  int radeon_uvd_init(struct radeon_device *rdev)
>  {
>         struct platform_device *pdev;
> +       const struct firmware *fw;
>         unsigned long bo_size;
>         const char *fw_name;
>         int i, r;
> @@ -112,7 +113,7 @@ int radeon_uvd_init(struct radeon_device *rdev)
>                 return -EINVAL;
>         }
>
> -       r = request_firmware(&rdev->uvd_fw, fw_name, &pdev->dev);
> +       r = request_firmware(&fw, fw_name, &pdev->dev);
>         if (r) {
>                 dev_err(rdev->dev, "radeon_uvd: Can't load firmware \"%s\"\n",
>                         fw_name);
> @@ -122,7 +123,7 @@ int radeon_uvd_init(struct radeon_device *rdev)
>
>         platform_device_unregister(pdev);
>
> -       bo_size = RADEON_GPU_PAGE_ALIGN(rdev->uvd_fw->size + 8) +
> +       bo_size = RADEON_GPU_PAGE_ALIGN(fw->size + 8) +
>                   RADEON_UVD_STACK_SIZE + RADEON_UVD_HEAP_SIZE;
>         r = radeon_bo_create(rdev, bo_size, PAGE_SIZE, true,
>                              RADEON_GEM_DOMAIN_VRAM, NULL, &rdev->uvd.vcpu_bo);
> @@ -131,16 +132,35 @@ int radeon_uvd_init(struct radeon_device *rdev)
>                 return r;
>         }
>
> -       r = radeon_uvd_resume(rdev);
> -       if (r)
> +       r = radeon_bo_reserve(rdev->uvd.vcpu_bo, false);
> +       if (r) {
> +               radeon_bo_unref(&rdev->uvd.vcpu_bo);
> +               dev_err(rdev->dev, "(%d) failed to reserve UVD bo\n", r);
>                 return r;
> +       }
>
> -       memset(rdev->uvd.cpu_addr, 0, bo_size);
> -       memcpy(rdev->uvd.cpu_addr, rdev->uvd_fw->data, rdev->uvd_fw->size);
> +       r = radeon_bo_pin(rdev->uvd.vcpu_bo, RADEON_GEM_DOMAIN_VRAM,
> +                         &rdev->uvd.gpu_addr);
> +       if (r) {
> +               radeon_bo_unreserve(rdev->uvd.vcpu_bo);
> +               radeon_bo_unref(&rdev->uvd.vcpu_bo);
> +               dev_err(rdev->dev, "(%d) UVD bo pin failed\n", r);
> +               return r;
> +       }
>
> -       r = radeon_uvd_suspend(rdev);
> -       if (r)
> +       r = radeon_bo_kmap(rdev->uvd.vcpu_bo, &rdev->uvd.cpu_addr);
> +       if (r) {
> +               dev_err(rdev->dev, "(%d) UVD map failed\n", r);
>                 return r;
> +       }
> +
> +       radeon_bo_unreserve(rdev->uvd.vcpu_bo);
> +
> +       rdev->uvd.fw_size = fw->size;
> +       memset(rdev->uvd.cpu_addr, 0, bo_size);
> +       memcpy(rdev->uvd.cpu_addr, fw->data, fw->size);
> +
> +       release_firmware(fw);
>
>         for (i = 0; i < RADEON_MAX_UVD_HANDLES; ++i) {
>                 atomic_set(&rdev->uvd.handles[i], 0);
> @@ -152,71 +172,47 @@ int radeon_uvd_init(struct radeon_device *rdev)
>
>  void radeon_uvd_fini(struct radeon_device *rdev)
>  {
> -       radeon_uvd_suspend(rdev);
> -       radeon_bo_unref(&rdev->uvd.vcpu_bo);
> -}
> -
> -int radeon_uvd_suspend(struct radeon_device *rdev)
> -{
>         int r;
>
>         if (rdev->uvd.vcpu_bo == NULL)
> -               return 0;
> +               return;
>
>         r = radeon_bo_reserve(rdev->uvd.vcpu_bo, false);
>         if (!r) {
>                 radeon_bo_kunmap(rdev->uvd.vcpu_bo);
>                 radeon_bo_unpin(rdev->uvd.vcpu_bo);
> -               rdev->uvd.cpu_addr = NULL;
> -               if (!radeon_bo_pin(rdev->uvd.vcpu_bo, RADEON_GEM_DOMAIN_CPU, NULL)) {
> -                       radeon_bo_kmap(rdev->uvd.vcpu_bo, &rdev->uvd.cpu_addr);
> -               }
>                 radeon_bo_unreserve(rdev->uvd.vcpu_bo);
> -
> -               if (rdev->uvd.cpu_addr) {
> -                       radeon_fence_driver_start_ring(rdev, R600_RING_TYPE_UVD_INDEX);
> -               } else {
> -                       rdev->fence_drv[R600_RING_TYPE_UVD_INDEX].cpu_addr = NULL;
> -               }
>         }
> -       return r;
> +
> +       radeon_bo_unref(&rdev->uvd.vcpu_bo);
>  }
>
> -int radeon_uvd_resume(struct radeon_device *rdev)
> +int radeon_uvd_suspend(struct radeon_device *rdev)
>  {
> -       int r;
> +       unsigned size;
>
>         if (rdev->uvd.vcpu_bo == NULL)
> -               return -EINVAL;
> +               return 0;
>
> -       r = radeon_bo_reserve(rdev->uvd.vcpu_bo, false);
> -       if (r) {
> -               radeon_bo_unref(&rdev->uvd.vcpu_bo);
> -               dev_err(rdev->dev, "(%d) failed to reserve UVD bo\n", r);
> -               return r;
> -       }
> +       size = radeon_bo_size(rdev->uvd.vcpu_bo);
> +       rdev->uvd.saved_bo = kmalloc(size, GFP_KERNEL);
> +       memcpy(rdev->uvd.saved_bo, rdev->uvd.cpu_addr, size);
>
> -       /* Have been pin in cpu unmap unpin */
> -       radeon_bo_kunmap(rdev->uvd.vcpu_bo);
> -       radeon_bo_unpin(rdev->uvd.vcpu_bo);
> +       return 0;
> +}
>
> -       r = radeon_bo_pin(rdev->uvd.vcpu_bo, RADEON_GEM_DOMAIN_VRAM,
> -                         &rdev->uvd.gpu_addr);
> -       if (r) {
> -               radeon_bo_unreserve(rdev->uvd.vcpu_bo);
> -               radeon_bo_unref(&rdev->uvd.vcpu_bo);
> -               dev_err(rdev->dev, "(%d) UVD bo pin failed\n", r);
> -               return r;
> -       }
> +int radeon_uvd_resume(struct radeon_device *rdev)
> +{
> +       if (rdev->uvd.vcpu_bo == NULL)
> +               return -EINVAL;
>
> -       r = radeon_bo_kmap(rdev->uvd.vcpu_bo, &rdev->uvd.cpu_addr);
> -       if (r) {
> -               dev_err(rdev->dev, "(%d) UVD map failed\n", r);
> -               return r;
> +       if (rdev->uvd.saved_bo != NULL) {
> +               unsigned size = radeon_bo_size(rdev->uvd.vcpu_bo);
> +               memcpy(rdev->uvd.cpu_addr, rdev->uvd.saved_bo, size);
> +               kfree(rdev->uvd.saved_bo);
> +               rdev->uvd.saved_bo = NULL;
>         }
>
> -       radeon_bo_unreserve(rdev->uvd.vcpu_bo);
> -
>         return 0;
>  }
>
> diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c
> index 4a62ad2..30ea14e 100644
> --- a/drivers/gpu/drm/radeon/rv770.c
> +++ b/drivers/gpu/drm/radeon/rv770.c
> @@ -813,7 +813,7 @@ int rv770_uvd_resume(struct radeon_device *rdev)
>
>         /* programm the VCPU memory controller bits 0-27 */
>         addr = rdev->uvd.gpu_addr >> 3;
> -       size = RADEON_GPU_PAGE_ALIGN(rdev->uvd_fw->size + 4) >> 3;
> +       size = RADEON_GPU_PAGE_ALIGN(rdev->uvd.fw_size + 4) >> 3;
>         WREG32(UVD_VCPU_CACHE_OFFSET0, addr);
>         WREG32(UVD_VCPU_CACHE_SIZE0, size);
>
> --
> 1.7.9.5
>


More information about the dri-devel mailing list