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