diff options
author | Christian König <christian.koenig@amd.com> | 2013-07-12 10:18:09 -0400 |
---|---|---|
committer | Alex Deucher <alexander.deucher@amd.com> | 2013-07-14 10:11:30 -0400 |
commit | 9cc2e0e9f13315559c85c9f99f141e420967c955 (patch) | |
tree | cd5215addab4c8d8d9e8d81e2d682a08677745e9 | |
parent | c9a6ca4abd5f1978ef15b3ece3474f4372ae5fe7 (diff) |
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: Christian König <christian.koenig@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
-rw-r--r-- | drivers/gpu/drm/radeon/cik.c | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon.h | 3 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_fence.c | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/radeon_uvd.c | 100 | ||||
-rw-r--r-- | drivers/gpu/drm/radeon/rv770.c | 2 |
5 files changed, 53 insertions, 56 deletions
diff --git a/drivers/gpu/drm/radeon/cik.c b/drivers/gpu/drm/radeon/cik.c index 68b4fc599e03..6dacec4e2090 100644 --- a/drivers/gpu/drm/radeon/cik.c +++ b/drivers/gpu/drm/radeon/cik.c | |||
@@ -6978,7 +6978,7 @@ int cik_uvd_resume(struct radeon_device *rdev) | |||
6978 | 6978 | ||
6979 | /* programm the VCPU memory controller bits 0-27 */ | 6979 | /* programm the VCPU memory controller bits 0-27 */ |
6980 | addr = rdev->uvd.gpu_addr >> 3; | 6980 | addr = rdev->uvd.gpu_addr >> 3; |
6981 | size = RADEON_GPU_PAGE_ALIGN(rdev->uvd_fw->size + 4) >> 3; | 6981 | size = RADEON_GPU_PAGE_ALIGN(rdev->uvd.fw_size + 4) >> 3; |
6982 | WREG32(UVD_VCPU_CACHE_OFFSET0, addr); | 6982 | WREG32(UVD_VCPU_CACHE_OFFSET0, addr); |
6983 | WREG32(UVD_VCPU_CACHE_SIZE0, size); | 6983 | WREG32(UVD_VCPU_CACHE_SIZE0, size); |
6984 | 6984 | ||
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 9b7025d02cd0..7b7d23ae3f27 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h | |||
@@ -1460,6 +1460,8 @@ struct radeon_uvd { | |||
1460 | struct radeon_bo *vcpu_bo; | 1460 | struct radeon_bo *vcpu_bo; |
1461 | void *cpu_addr; | 1461 | void *cpu_addr; |
1462 | uint64_t gpu_addr; | 1462 | uint64_t gpu_addr; |
1463 | void *saved_bo; | ||
1464 | unsigned fw_size; | ||
1463 | atomic_t handles[RADEON_MAX_UVD_HANDLES]; | 1465 | atomic_t handles[RADEON_MAX_UVD_HANDLES]; |
1464 | struct drm_file *filp[RADEON_MAX_UVD_HANDLES]; | 1466 | struct drm_file *filp[RADEON_MAX_UVD_HANDLES]; |
1465 | struct delayed_work idle_work; | 1467 | struct delayed_work idle_work; |
@@ -2054,7 +2056,6 @@ struct radeon_device { | |||
2054 | const struct firmware *rlc_fw; /* r6/700 RLC firmware */ | 2056 | const struct firmware *rlc_fw; /* r6/700 RLC firmware */ |
2055 | const struct firmware *mc_fw; /* NI MC firmware */ | 2057 | const struct firmware *mc_fw; /* NI MC firmware */ |
2056 | const struct firmware *ce_fw; /* SI CE firmware */ | 2058 | const struct firmware *ce_fw; /* SI CE firmware */ |
2057 | const struct firmware *uvd_fw; /* UVD firmware */ | ||
2058 | const struct firmware *mec_fw; /* CIK MEC firmware */ | 2059 | const struct firmware *mec_fw; /* CIK MEC firmware */ |
2059 | const struct firmware *sdma_fw; /* CIK SDMA firmware */ | 2060 | const struct firmware *sdma_fw; /* CIK SDMA firmware */ |
2060 | const struct firmware *smc_fw; /* SMC firmware */ | 2061 | 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 ddb8f8e04eb5..7ddb0efe2408 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) | |||
782 | 782 | ||
783 | } else { | 783 | } else { |
784 | /* put fence directly behind firmware */ | 784 | /* put fence directly behind firmware */ |
785 | index = ALIGN(rdev->uvd_fw->size, 8); | 785 | index = ALIGN(rdev->uvd.fw_size, 8); |
786 | rdev->fence_drv[ring].cpu_addr = rdev->uvd.cpu_addr + index; | 786 | rdev->fence_drv[ring].cpu_addr = rdev->uvd.cpu_addr + index; |
787 | rdev->fence_drv[ring].gpu_addr = rdev->uvd.gpu_addr + index; | 787 | rdev->fence_drv[ring].gpu_addr = rdev->uvd.gpu_addr + index; |
788 | } | 788 | } |
diff --git a/drivers/gpu/drm/radeon/radeon_uvd.c b/drivers/gpu/drm/radeon/radeon_uvd.c index 34444f62803f..414fd145d20e 100644 --- a/drivers/gpu/drm/radeon/radeon_uvd.c +++ b/drivers/gpu/drm/radeon/radeon_uvd.c | |||
@@ -56,6 +56,7 @@ static void radeon_uvd_idle_work_handler(struct work_struct *work); | |||
56 | 56 | ||
57 | int radeon_uvd_init(struct radeon_device *rdev) | 57 | int radeon_uvd_init(struct radeon_device *rdev) |
58 | { | 58 | { |
59 | const struct firmware *fw; | ||
59 | unsigned long bo_size; | 60 | unsigned long bo_size; |
60 | const char *fw_name; | 61 | const char *fw_name; |
61 | int i, r; | 62 | int i, r; |
@@ -104,14 +105,14 @@ int radeon_uvd_init(struct radeon_device *rdev) | |||
104 | return -EINVAL; | 105 | return -EINVAL; |
105 | } | 106 | } |
106 | 107 | ||
107 | r = request_firmware(&rdev->uvd_fw, fw_name, rdev->dev); | 108 | r = request_firmware(&fw, fw_name, rdev->dev); |
108 | if (r) { | 109 | if (r) { |
109 | dev_err(rdev->dev, "radeon_uvd: Can't load firmware \"%s\"\n", | 110 | dev_err(rdev->dev, "radeon_uvd: Can't load firmware \"%s\"\n", |
110 | fw_name); | 111 | fw_name); |
111 | return r; | 112 | return r; |
112 | } | 113 | } |
113 | 114 | ||
114 | bo_size = RADEON_GPU_PAGE_ALIGN(rdev->uvd_fw->size + 8) + | 115 | bo_size = RADEON_GPU_PAGE_ALIGN(fw->size + 8) + |
115 | RADEON_UVD_STACK_SIZE + RADEON_UVD_HEAP_SIZE; | 116 | RADEON_UVD_STACK_SIZE + RADEON_UVD_HEAP_SIZE; |
116 | r = radeon_bo_create(rdev, bo_size, PAGE_SIZE, true, | 117 | r = radeon_bo_create(rdev, bo_size, PAGE_SIZE, true, |
117 | RADEON_GEM_DOMAIN_VRAM, NULL, &rdev->uvd.vcpu_bo); | 118 | RADEON_GEM_DOMAIN_VRAM, NULL, &rdev->uvd.vcpu_bo); |
@@ -120,16 +121,35 @@ int radeon_uvd_init(struct radeon_device *rdev) | |||
120 | return r; | 121 | return r; |
121 | } | 122 | } |
122 | 123 | ||
123 | r = radeon_uvd_resume(rdev); | 124 | r = radeon_bo_reserve(rdev->uvd.vcpu_bo, false); |
124 | if (r) | 125 | if (r) { |
126 | radeon_bo_unref(&rdev->uvd.vcpu_bo); | ||
127 | dev_err(rdev->dev, "(%d) failed to reserve UVD bo\n", r); | ||
125 | return r; | 128 | return r; |
129 | } | ||
126 | 130 | ||
127 | memset(rdev->uvd.cpu_addr, 0, bo_size); | 131 | r = radeon_bo_pin(rdev->uvd.vcpu_bo, RADEON_GEM_DOMAIN_VRAM, |
128 | memcpy(rdev->uvd.cpu_addr, rdev->uvd_fw->data, rdev->uvd_fw->size); | 132 | &rdev->uvd.gpu_addr); |
133 | if (r) { | ||
134 | radeon_bo_unreserve(rdev->uvd.vcpu_bo); | ||
135 | radeon_bo_unref(&rdev->uvd.vcpu_bo); | ||
136 | dev_err(rdev->dev, "(%d) UVD bo pin failed\n", r); | ||
137 | return r; | ||
138 | } | ||
129 | 139 | ||
130 | r = radeon_uvd_suspend(rdev); | 140 | r = radeon_bo_kmap(rdev->uvd.vcpu_bo, &rdev->uvd.cpu_addr); |
131 | if (r) | 141 | if (r) { |
142 | dev_err(rdev->dev, "(%d) UVD map failed\n", r); | ||
132 | return r; | 143 | return r; |
144 | } | ||
145 | |||
146 | radeon_bo_unreserve(rdev->uvd.vcpu_bo); | ||
147 | |||
148 | rdev->uvd.fw_size = fw->size; | ||
149 | memset(rdev->uvd.cpu_addr, 0, bo_size); | ||
150 | memcpy(rdev->uvd.cpu_addr, fw->data, fw->size); | ||
151 | |||
152 | release_firmware(fw); | ||
133 | 153 | ||
134 | for (i = 0; i < RADEON_MAX_UVD_HANDLES; ++i) { | 154 | for (i = 0; i < RADEON_MAX_UVD_HANDLES; ++i) { |
135 | atomic_set(&rdev->uvd.handles[i], 0); | 155 | atomic_set(&rdev->uvd.handles[i], 0); |
@@ -141,71 +161,47 @@ int radeon_uvd_init(struct radeon_device *rdev) | |||
141 | 161 | ||
142 | void radeon_uvd_fini(struct radeon_device *rdev) | 162 | void radeon_uvd_fini(struct radeon_device *rdev) |
143 | { | 163 | { |
144 | radeon_uvd_suspend(rdev); | ||
145 | radeon_bo_unref(&rdev->uvd.vcpu_bo); | ||
146 | } | ||
147 | |||
148 | int radeon_uvd_suspend(struct radeon_device *rdev) | ||
149 | { | ||
150 | int r; | 164 | int r; |
151 | 165 | ||
152 | if (rdev->uvd.vcpu_bo == NULL) | 166 | if (rdev->uvd.vcpu_bo == NULL) |
153 | return 0; | 167 | return; |
154 | 168 | ||
155 | r = radeon_bo_reserve(rdev->uvd.vcpu_bo, false); | 169 | r = radeon_bo_reserve(rdev->uvd.vcpu_bo, false); |
156 | if (!r) { | 170 | if (!r) { |
157 | radeon_bo_kunmap(rdev->uvd.vcpu_bo); | 171 | radeon_bo_kunmap(rdev->uvd.vcpu_bo); |
158 | radeon_bo_unpin(rdev->uvd.vcpu_bo); | 172 | radeon_bo_unpin(rdev->uvd.vcpu_bo); |
159 | rdev->uvd.cpu_addr = NULL; | ||
160 | if (!radeon_bo_pin(rdev->uvd.vcpu_bo, RADEON_GEM_DOMAIN_CPU, NULL)) { | ||
161 | radeon_bo_kmap(rdev->uvd.vcpu_bo, &rdev->uvd.cpu_addr); | ||
162 | } | ||
163 | radeon_bo_unreserve(rdev->uvd.vcpu_bo); | 173 | radeon_bo_unreserve(rdev->uvd.vcpu_bo); |
164 | |||
165 | if (rdev->uvd.cpu_addr) { | ||
166 | radeon_fence_driver_start_ring(rdev, R600_RING_TYPE_UVD_INDEX); | ||
167 | } else { | ||
168 | rdev->fence_drv[R600_RING_TYPE_UVD_INDEX].cpu_addr = NULL; | ||
169 | } | ||
170 | } | 174 | } |
171 | return r; | 175 | |
176 | radeon_bo_unref(&rdev->uvd.vcpu_bo); | ||
172 | } | 177 | } |
173 | 178 | ||
174 | int radeon_uvd_resume(struct radeon_device *rdev) | 179 | int radeon_uvd_suspend(struct radeon_device *rdev) |
175 | { | 180 | { |
176 | int r; | 181 | unsigned size; |
177 | 182 | ||
178 | if (rdev->uvd.vcpu_bo == NULL) | 183 | if (rdev->uvd.vcpu_bo == NULL) |
179 | return -EINVAL; | 184 | return 0; |
180 | 185 | ||
181 | r = radeon_bo_reserve(rdev->uvd.vcpu_bo, false); | 186 | size = radeon_bo_size(rdev->uvd.vcpu_bo); |
182 | if (r) { | 187 | rdev->uvd.saved_bo = kmalloc(size, GFP_KERNEL); |
183 | radeon_bo_unref(&rdev->uvd.vcpu_bo); | 188 | memcpy(rdev->uvd.saved_bo, rdev->uvd.cpu_addr, size); |
184 | dev_err(rdev->dev, "(%d) failed to reserve UVD bo\n", r); | ||
185 | return r; | ||
186 | } | ||
187 | 189 | ||
188 | /* Have been pin in cpu unmap unpin */ | 190 | return 0; |
189 | radeon_bo_kunmap(rdev->uvd.vcpu_bo); | 191 | } |
190 | radeon_bo_unpin(rdev->uvd.vcpu_bo); | ||
191 | 192 | ||
192 | r = radeon_bo_pin(rdev->uvd.vcpu_bo, RADEON_GEM_DOMAIN_VRAM, | 193 | int radeon_uvd_resume(struct radeon_device *rdev) |
193 | &rdev->uvd.gpu_addr); | 194 | { |
194 | if (r) { | 195 | if (rdev->uvd.vcpu_bo == NULL) |
195 | radeon_bo_unreserve(rdev->uvd.vcpu_bo); | 196 | return -EINVAL; |
196 | radeon_bo_unref(&rdev->uvd.vcpu_bo); | ||
197 | dev_err(rdev->dev, "(%d) UVD bo pin failed\n", r); | ||
198 | return r; | ||
199 | } | ||
200 | 197 | ||
201 | r = radeon_bo_kmap(rdev->uvd.vcpu_bo, &rdev->uvd.cpu_addr); | 198 | if (rdev->uvd.saved_bo != NULL) { |
202 | if (r) { | 199 | unsigned size = radeon_bo_size(rdev->uvd.vcpu_bo); |
203 | dev_err(rdev->dev, "(%d) UVD map failed\n", r); | 200 | memcpy(rdev->uvd.cpu_addr, rdev->uvd.saved_bo, size); |
204 | return r; | 201 | kfree(rdev->uvd.saved_bo); |
202 | rdev->uvd.saved_bo = NULL; | ||
205 | } | 203 | } |
206 | 204 | ||
207 | radeon_bo_unreserve(rdev->uvd.vcpu_bo); | ||
208 | |||
209 | return 0; | 205 | return 0; |
210 | } | 206 | } |
211 | 207 | ||
diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c index 4a62ad2e5399..30ea14e8854c 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) | |||
813 | 813 | ||
814 | /* programm the VCPU memory controller bits 0-27 */ | 814 | /* programm the VCPU memory controller bits 0-27 */ |
815 | addr = rdev->uvd.gpu_addr >> 3; | 815 | addr = rdev->uvd.gpu_addr >> 3; |
816 | size = RADEON_GPU_PAGE_ALIGN(rdev->uvd_fw->size + 4) >> 3; | 816 | size = RADEON_GPU_PAGE_ALIGN(rdev->uvd.fw_size + 4) >> 3; |
817 | WREG32(UVD_VCPU_CACHE_OFFSET0, addr); | 817 | WREG32(UVD_VCPU_CACHE_OFFSET0, addr); |
818 | WREG32(UVD_VCPU_CACHE_SIZE0, size); | 818 | WREG32(UVD_VCPU_CACHE_SIZE0, size); |
819 | 819 | ||