Commit 9cc2e0e9 authored by Christian König's avatar Christian König Committed by Alex Deucher

drm/radeon: never unpin UVD bo v3

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: default avatarChristian König <christian.koenig@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent c9a6ca4a
...@@ -6978,7 +6978,7 @@ int cik_uvd_resume(struct radeon_device *rdev) ...@@ -6978,7 +6978,7 @@ int cik_uvd_resume(struct radeon_device *rdev)
/* programm the VCPU memory controller bits 0-27 */ /* programm the VCPU memory controller bits 0-27 */
addr = rdev->uvd.gpu_addr >> 3; 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_OFFSET0, addr);
WREG32(UVD_VCPU_CACHE_SIZE0, size); WREG32(UVD_VCPU_CACHE_SIZE0, size);
......
...@@ -1460,6 +1460,8 @@ struct radeon_uvd { ...@@ -1460,6 +1460,8 @@ struct radeon_uvd {
struct radeon_bo *vcpu_bo; struct radeon_bo *vcpu_bo;
void *cpu_addr; void *cpu_addr;
uint64_t gpu_addr; uint64_t gpu_addr;
void *saved_bo;
unsigned fw_size;
atomic_t handles[RADEON_MAX_UVD_HANDLES]; atomic_t handles[RADEON_MAX_UVD_HANDLES];
struct drm_file *filp[RADEON_MAX_UVD_HANDLES]; struct drm_file *filp[RADEON_MAX_UVD_HANDLES];
struct delayed_work idle_work; struct delayed_work idle_work;
...@@ -2054,7 +2056,6 @@ struct radeon_device { ...@@ -2054,7 +2056,6 @@ struct radeon_device {
const struct firmware *rlc_fw; /* r6/700 RLC firmware */ const struct firmware *rlc_fw; /* r6/700 RLC firmware */
const struct firmware *mc_fw; /* NI MC firmware */ const struct firmware *mc_fw; /* NI MC firmware */
const struct firmware *ce_fw; /* SI CE 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 *mec_fw; /* CIK MEC firmware */
const struct firmware *sdma_fw; /* CIK SDMA firmware */ const struct firmware *sdma_fw; /* CIK SDMA firmware */
const struct firmware *smc_fw; /* SMC firmware */ const struct firmware *smc_fw; /* SMC firmware */
......
...@@ -782,7 +782,7 @@ int radeon_fence_driver_start_ring(struct radeon_device *rdev, int ring) ...@@ -782,7 +782,7 @@ int radeon_fence_driver_start_ring(struct radeon_device *rdev, int ring)
} else { } else {
/* put fence directly behind firmware */ /* 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].cpu_addr = rdev->uvd.cpu_addr + index;
rdev->fence_drv[ring].gpu_addr = rdev->uvd.gpu_addr + index; rdev->fence_drv[ring].gpu_addr = rdev->uvd.gpu_addr + index;
} }
......
...@@ -56,6 +56,7 @@ static void radeon_uvd_idle_work_handler(struct work_struct *work); ...@@ -56,6 +56,7 @@ static void radeon_uvd_idle_work_handler(struct work_struct *work);
int radeon_uvd_init(struct radeon_device *rdev) int radeon_uvd_init(struct radeon_device *rdev)
{ {
const struct firmware *fw;
unsigned long bo_size; unsigned long bo_size;
const char *fw_name; const char *fw_name;
int i, r; int i, r;
...@@ -104,14 +105,14 @@ int radeon_uvd_init(struct radeon_device *rdev) ...@@ -104,14 +105,14 @@ int radeon_uvd_init(struct radeon_device *rdev)
return -EINVAL; return -EINVAL;
} }
r = request_firmware(&rdev->uvd_fw, fw_name, rdev->dev); r = request_firmware(&fw, fw_name, rdev->dev);
if (r) { if (r) {
dev_err(rdev->dev, "radeon_uvd: Can't load firmware \"%s\"\n", dev_err(rdev->dev, "radeon_uvd: Can't load firmware \"%s\"\n",
fw_name); fw_name);
return r; 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; RADEON_UVD_STACK_SIZE + RADEON_UVD_HEAP_SIZE;
r = radeon_bo_create(rdev, bo_size, PAGE_SIZE, true, r = radeon_bo_create(rdev, bo_size, PAGE_SIZE, true,
RADEON_GEM_DOMAIN_VRAM, NULL, &rdev->uvd.vcpu_bo); RADEON_GEM_DOMAIN_VRAM, NULL, &rdev->uvd.vcpu_bo);
...@@ -120,16 +121,35 @@ int radeon_uvd_init(struct radeon_device *rdev) ...@@ -120,16 +121,35 @@ int radeon_uvd_init(struct radeon_device *rdev)
return r; return r;
} }
r = radeon_uvd_resume(rdev); r = radeon_bo_reserve(rdev->uvd.vcpu_bo, false);
if (r) if (r) {
radeon_bo_unref(&rdev->uvd.vcpu_bo);
dev_err(rdev->dev, "(%d) failed to reserve UVD bo\n", r);
return r; return r;
}
memset(rdev->uvd.cpu_addr, 0, bo_size); r = radeon_bo_pin(rdev->uvd.vcpu_bo, RADEON_GEM_DOMAIN_VRAM,
memcpy(rdev->uvd.cpu_addr, rdev->uvd_fw->data, rdev->uvd_fw->size); &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); r = radeon_bo_kmap(rdev->uvd.vcpu_bo, &rdev->uvd.cpu_addr);
if (r) if (r) {
dev_err(rdev->dev, "(%d) UVD map failed\n", r);
return 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) { for (i = 0; i < RADEON_MAX_UVD_HANDLES; ++i) {
atomic_set(&rdev->uvd.handles[i], 0); atomic_set(&rdev->uvd.handles[i], 0);
...@@ -140,72 +160,48 @@ int radeon_uvd_init(struct radeon_device *rdev) ...@@ -140,72 +160,48 @@ int radeon_uvd_init(struct radeon_device *rdev)
} }
void radeon_uvd_fini(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; int r;
if (rdev->uvd.vcpu_bo == NULL) if (rdev->uvd.vcpu_bo == NULL)
return 0; return;
r = radeon_bo_reserve(rdev->uvd.vcpu_bo, false); r = radeon_bo_reserve(rdev->uvd.vcpu_bo, false);
if (!r) { if (!r) {
radeon_bo_kunmap(rdev->uvd.vcpu_bo); radeon_bo_kunmap(rdev->uvd.vcpu_bo);
radeon_bo_unpin(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); 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) if (rdev->uvd.vcpu_bo == NULL)
return -EINVAL; return 0;
r = radeon_bo_reserve(rdev->uvd.vcpu_bo, false); size = radeon_bo_size(rdev->uvd.vcpu_bo);
if (r) { rdev->uvd.saved_bo = kmalloc(size, GFP_KERNEL);
radeon_bo_unref(&rdev->uvd.vcpu_bo); memcpy(rdev->uvd.saved_bo, rdev->uvd.cpu_addr, size);
dev_err(rdev->dev, "(%d) failed to reserve UVD bo\n", r);
return r;
}
/* Have been pin in cpu unmap unpin */ return 0;
radeon_bo_kunmap(rdev->uvd.vcpu_bo); }
radeon_bo_unpin(rdev->uvd.vcpu_bo);
r = radeon_bo_pin(rdev->uvd.vcpu_bo, RADEON_GEM_DOMAIN_VRAM, int radeon_uvd_resume(struct radeon_device *rdev)
&rdev->uvd.gpu_addr); {
if (r) { if (rdev->uvd.vcpu_bo == NULL)
radeon_bo_unreserve(rdev->uvd.vcpu_bo); return -EINVAL;
radeon_bo_unref(&rdev->uvd.vcpu_bo);
dev_err(rdev->dev, "(%d) UVD bo pin failed\n", r);
return r;
}
r = radeon_bo_kmap(rdev->uvd.vcpu_bo, &rdev->uvd.cpu_addr); if (rdev->uvd.saved_bo != NULL) {
if (r) { unsigned size = radeon_bo_size(rdev->uvd.vcpu_bo);
dev_err(rdev->dev, "(%d) UVD map failed\n", r); memcpy(rdev->uvd.cpu_addr, rdev->uvd.saved_bo, size);
return r; kfree(rdev->uvd.saved_bo);
rdev->uvd.saved_bo = NULL;
} }
radeon_bo_unreserve(rdev->uvd.vcpu_bo);
return 0; return 0;
} }
......
...@@ -813,7 +813,7 @@ int rv770_uvd_resume(struct radeon_device *rdev) ...@@ -813,7 +813,7 @@ int rv770_uvd_resume(struct radeon_device *rdev)
/* programm the VCPU memory controller bits 0-27 */ /* programm the VCPU memory controller bits 0-27 */
addr = rdev->uvd.gpu_addr >> 3; 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_OFFSET0, addr);
WREG32(UVD_VCPU_CACHE_SIZE0, size); WREG32(UVD_VCPU_CACHE_SIZE0, size);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment