diff mbox

drm/radeon: never unpin UVD bo v2

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

Commit Message

Christian König July 12, 2013, 7:40 a.m. UTC
From: Christian König <christian.koenig@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@amd.com>
Cc: stable@vger.kernel.org
---
 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(-)

Comments

Alex Deucher July 12, 2013, 2:23 p.m. UTC | #1
On Fri, Jul 12, 2013 at 3:40 AM, Christian König
<deathsimple@vodafone.de> wrote:
> From: Christian König <christian.koenig@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@amd.com>
> Cc: stable@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
>
diff mbox

Patch

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);