drm/radeon: never unpin UVD bo v3
authorChristian König <christian.koenig@amd.com>
Fri, 12 Jul 2013 14:18:09 +0000 (10:18 -0400)
committerAlex Deucher <alexander.deucher@amd.com>
Sun, 14 Jul 2013 14:11:30 +0000 (10:11 -0400)
Changing the UVD BOs offset on suspend/resume doesn't work because 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
v3: fix CIK support

Note: a version of this patch needs to go to stable.

Signed-off-by: Christian König <christian.koenig@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/radeon/cik.c
drivers/gpu/drm/radeon/radeon.h
drivers/gpu/drm/radeon/radeon_fence.c
drivers/gpu/drm/radeon/radeon_uvd.c
drivers/gpu/drm/radeon/rv770.c

index 68b4fc599e0378edb6fcddde10c394689be3af7e..6dacec4e20901bd1f12e428a387434a8db8a91a8 100644 (file)
@@ -6978,7 +6978,7 @@ int cik_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);
 
index 9b7025d02cd0cf42504d08fca87d6daf640c876d..7b7d23ae3f27e95587a58240a5ac758c1166aa8d 100644 (file)
@@ -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 */
index ddb8f8e04eb549f4fd264b2f704cdd407bcc65e0..7ddb0efe2408cadc2de230109689a159cdbf0fbd 100644 (file)
@@ -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;
                }
index 34444f62803fb3c65d484262d6c6c2c91cdcf3b1..414fd145d20eee458ebf8e0a5c1dfb1940ae2589 100644 (file)
@@ -56,6 +56,7 @@ static void radeon_uvd_idle_work_handler(struct work_struct *work);
 
 int radeon_uvd_init(struct radeon_device *rdev)
 {
+       const struct firmware *fw;
        unsigned long bo_size;
        const char *fw_name;
        int i, r;
@@ -104,14 +105,14 @@ int radeon_uvd_init(struct radeon_device *rdev)
                return -EINVAL;
        }
 
-       r = request_firmware(&rdev->uvd_fw, fw_name, rdev->dev);
+       r = request_firmware(&fw, fw_name, rdev->dev);
        if (r) {
                dev_err(rdev->dev, "radeon_uvd: Can't load firmware \"%s\"\n",
                        fw_name);
                return r;
        }
 
-       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);
@@ -120,16 +121,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);
@@ -140,72 +160,48 @@ 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;
 }
 
index 4a62ad2e539944ffaefc73b7169733bfefff86ff..30ea14e8854c465add9148cb4099142a3295fbd0 100644 (file)
@@ -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);