diff options
Diffstat (limited to 'drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c')
-rw-r--r-- | drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c | 116 |
1 files changed, 61 insertions, 55 deletions
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c index 264c5968a1d3..d9dc8bea5e98 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c | |||
@@ -50,6 +50,9 @@ | |||
50 | * SI supports 16. | 50 | * SI supports 16. |
51 | */ | 51 | */ |
52 | 52 | ||
53 | /* Special value that no flush is necessary */ | ||
54 | #define AMDGPU_VM_NO_FLUSH (~0ll) | ||
55 | |||
53 | /** | 56 | /** |
54 | * amdgpu_vm_num_pde - return the number of page directory entries | 57 | * amdgpu_vm_num_pde - return the number of page directory entries |
55 | * | 58 | * |
@@ -157,50 +160,70 @@ void amdgpu_vm_move_pt_bos_in_lru(struct amdgpu_device *adev, | |||
157 | * Allocate an id for the vm, adding fences to the sync obj as necessary. | 160 | * Allocate an id for the vm, adding fences to the sync obj as necessary. |
158 | */ | 161 | */ |
159 | int amdgpu_vm_grab_id(struct amdgpu_vm *vm, struct amdgpu_ring *ring, | 162 | int amdgpu_vm_grab_id(struct amdgpu_vm *vm, struct amdgpu_ring *ring, |
160 | struct amdgpu_sync *sync, struct fence *fence) | 163 | struct amdgpu_sync *sync, struct fence *fence, |
164 | unsigned *vm_id, uint64_t *vm_pd_addr) | ||
161 | { | 165 | { |
162 | struct amdgpu_vm_id *vm_id = &vm->ids[ring->idx]; | 166 | uint64_t pd_addr = amdgpu_bo_gpu_offset(vm->page_directory); |
163 | struct amdgpu_device *adev = ring->adev; | 167 | struct amdgpu_device *adev = ring->adev; |
164 | struct amdgpu_vm_manager_id *id; | 168 | struct amdgpu_vm_id *id = &vm->ids[ring->idx]; |
169 | struct fence *updates = sync->last_vm_update; | ||
165 | int r; | 170 | int r; |
166 | 171 | ||
167 | mutex_lock(&adev->vm_manager.lock); | 172 | mutex_lock(&adev->vm_manager.lock); |
168 | 173 | ||
169 | /* check if the id is still valid */ | 174 | /* check if the id is still valid */ |
170 | if (vm_id->id) { | 175 | if (id->mgr_id) { |
176 | struct fence *flushed = id->flushed_updates; | ||
177 | bool is_later; | ||
171 | long owner; | 178 | long owner; |
172 | 179 | ||
173 | id = &adev->vm_manager.ids[vm_id->id]; | 180 | if (!flushed) |
174 | owner = atomic_long_read(&id->owner); | 181 | is_later = true; |
175 | if (owner == (long)vm) { | 182 | else if (!updates) |
176 | list_move_tail(&id->list, &adev->vm_manager.ids_lru); | 183 | is_later = false; |
177 | trace_amdgpu_vm_grab_id(vm, vm_id->id, ring->idx); | 184 | else |
185 | is_later = fence_is_later(updates, flushed); | ||
186 | |||
187 | owner = atomic_long_read(&id->mgr_id->owner); | ||
188 | if (!is_later && owner == (long)id && | ||
189 | pd_addr == id->pd_gpu_addr) { | ||
190 | |||
191 | fence_put(id->mgr_id->active); | ||
192 | id->mgr_id->active = fence_get(fence); | ||
193 | |||
194 | list_move_tail(&id->mgr_id->list, | ||
195 | &adev->vm_manager.ids_lru); | ||
178 | 196 | ||
179 | fence_put(id->active); | 197 | *vm_id = id->mgr_id - adev->vm_manager.ids; |
180 | id->active = fence_get(fence); | 198 | *vm_pd_addr = AMDGPU_VM_NO_FLUSH; |
199 | trace_amdgpu_vm_grab_id(vm, ring->idx, *vm_id, | ||
200 | *vm_pd_addr); | ||
181 | 201 | ||
182 | mutex_unlock(&adev->vm_manager.lock); | 202 | mutex_unlock(&adev->vm_manager.lock); |
183 | return 0; | 203 | return 0; |
184 | } | 204 | } |
185 | } | 205 | } |
186 | 206 | ||
187 | /* we definately need to flush */ | 207 | id->mgr_id = list_first_entry(&adev->vm_manager.ids_lru, |
188 | vm_id->pd_gpu_addr = ~0ll; | 208 | struct amdgpu_vm_manager_id, |
209 | list); | ||
189 | 210 | ||
190 | id = list_first_entry(&adev->vm_manager.ids_lru, | 211 | r = amdgpu_sync_fence(ring->adev, sync, id->mgr_id->active); |
191 | struct amdgpu_vm_manager_id, | 212 | if (!r) { |
192 | list); | 213 | fence_put(id->mgr_id->active); |
193 | list_move_tail(&id->list, &adev->vm_manager.ids_lru); | 214 | id->mgr_id->active = fence_get(fence); |
194 | atomic_long_set(&id->owner, (long)vm); | ||
195 | 215 | ||
196 | vm_id->id = id - adev->vm_manager.ids; | 216 | fence_put(id->flushed_updates); |
197 | trace_amdgpu_vm_grab_id(vm, vm_id->id, ring->idx); | 217 | id->flushed_updates = fence_get(updates); |
198 | 218 | ||
199 | r = amdgpu_sync_fence(ring->adev, sync, id->active); | 219 | id->pd_gpu_addr = pd_addr; |
200 | 220 | ||
201 | if (!r) { | 221 | list_move_tail(&id->mgr_id->list, &adev->vm_manager.ids_lru); |
202 | fence_put(id->active); | 222 | atomic_long_set(&id->mgr_id->owner, (long)id); |
203 | id->active = fence_get(fence); | 223 | |
224 | *vm_id = id->mgr_id - adev->vm_manager.ids; | ||
225 | *vm_pd_addr = pd_addr; | ||
226 | trace_amdgpu_vm_grab_id(vm, ring->idx, *vm_id, *vm_pd_addr); | ||
204 | } | 227 | } |
205 | 228 | ||
206 | mutex_unlock(&adev->vm_manager.lock); | 229 | mutex_unlock(&adev->vm_manager.lock); |
@@ -211,35 +234,18 @@ int amdgpu_vm_grab_id(struct amdgpu_vm *vm, struct amdgpu_ring *ring, | |||
211 | * amdgpu_vm_flush - hardware flush the vm | 234 | * amdgpu_vm_flush - hardware flush the vm |
212 | * | 235 | * |
213 | * @ring: ring to use for flush | 236 | * @ring: ring to use for flush |
214 | * @vm: vm we want to flush | 237 | * @vmid: vmid number to use |
215 | * @updates: last vm update that we waited for | 238 | * @pd_addr: address of the page directory |
216 | * | 239 | * |
217 | * Flush the vm. | 240 | * Emit a VM flush when it is necessary. |
218 | */ | 241 | */ |
219 | void amdgpu_vm_flush(struct amdgpu_ring *ring, | 242 | void amdgpu_vm_flush(struct amdgpu_ring *ring, |
220 | struct amdgpu_vm *vm, | 243 | unsigned vmid, |
221 | struct fence *updates) | 244 | uint64_t pd_addr) |
222 | { | 245 | { |
223 | uint64_t pd_addr = amdgpu_bo_gpu_offset(vm->page_directory); | 246 | if (pd_addr != AMDGPU_VM_NO_FLUSH) { |
224 | struct amdgpu_vm_id *vm_id = &vm->ids[ring->idx]; | 247 | trace_amdgpu_vm_flush(pd_addr, ring->idx, vmid); |
225 | struct fence *flushed_updates = vm_id->flushed_updates; | 248 | amdgpu_ring_emit_vm_flush(ring, vmid, pd_addr); |
226 | bool is_later; | ||
227 | |||
228 | if (!flushed_updates) | ||
229 | is_later = true; | ||
230 | else if (!updates) | ||
231 | is_later = false; | ||
232 | else | ||
233 | is_later = fence_is_later(updates, flushed_updates); | ||
234 | |||
235 | if (pd_addr != vm_id->pd_gpu_addr || is_later) { | ||
236 | trace_amdgpu_vm_flush(pd_addr, ring->idx, vm_id->id); | ||
237 | if (is_later) { | ||
238 | vm_id->flushed_updates = fence_get(updates); | ||
239 | fence_put(flushed_updates); | ||
240 | } | ||
241 | vm_id->pd_gpu_addr = pd_addr; | ||
242 | amdgpu_ring_emit_vm_flush(ring, vm_id->id, vm_id->pd_gpu_addr); | ||
243 | } | 249 | } |
244 | } | 250 | } |
245 | 251 | ||
@@ -1284,7 +1290,7 @@ int amdgpu_vm_init(struct amdgpu_device *adev, struct amdgpu_vm *vm) | |||
1284 | int i, r; | 1290 | int i, r; |
1285 | 1291 | ||
1286 | for (i = 0; i < AMDGPU_MAX_RINGS; ++i) { | 1292 | for (i = 0; i < AMDGPU_MAX_RINGS; ++i) { |
1287 | vm->ids[i].id = 0; | 1293 | vm->ids[i].mgr_id = NULL; |
1288 | vm->ids[i].flushed_updates = NULL; | 1294 | vm->ids[i].flushed_updates = NULL; |
1289 | } | 1295 | } |
1290 | vm->va = RB_ROOT; | 1296 | vm->va = RB_ROOT; |
@@ -1381,13 +1387,13 @@ void amdgpu_vm_fini(struct amdgpu_device *adev, struct amdgpu_vm *vm) | |||
1381 | amdgpu_bo_unref(&vm->page_directory); | 1387 | amdgpu_bo_unref(&vm->page_directory); |
1382 | fence_put(vm->page_directory_fence); | 1388 | fence_put(vm->page_directory_fence); |
1383 | for (i = 0; i < AMDGPU_MAX_RINGS; ++i) { | 1389 | for (i = 0; i < AMDGPU_MAX_RINGS; ++i) { |
1384 | unsigned id = vm->ids[i].id; | 1390 | struct amdgpu_vm_id *id = &vm->ids[i]; |
1385 | 1391 | ||
1386 | atomic_long_cmpxchg(&adev->vm_manager.ids[id].owner, | 1392 | if (id->mgr_id) |
1387 | (long)vm, 0); | 1393 | atomic_long_cmpxchg(&id->mgr_id->owner, |
1388 | fence_put(vm->ids[i].flushed_updates); | 1394 | (long)id, 0); |
1395 | fence_put(id->flushed_updates); | ||
1389 | } | 1396 | } |
1390 | |||
1391 | } | 1397 | } |
1392 | 1398 | ||
1393 | /** | 1399 | /** |