blob: 842caa5ed73bfe96d439e192b3aad5ba7cdb8e23 [file] [log] [blame]
Christian König620f7742017-12-18 16:53:03 +01001/*
2 * Copyright 2017 Advanced Micro Devices, Inc.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
21 *
22 */
23#include "amdgpu_ids.h"
24
25#include <linux/idr.h>
26#include <linux/dma-fence-array.h>
27#include <drm/drmP.h>
28
29#include "amdgpu.h"
30#include "amdgpu_trace.h"
31
32/*
33 * PASID manager
34 *
35 * PASIDs are global address space identifiers that can be shared
36 * between the GPU, an IOMMU and the driver. VMs on different devices
37 * may use the same PASID if they share the same address
38 * space. Therefore PASIDs are allocated using a global IDA. VMs are
39 * looked up from the PASID per amdgpu_device.
40 */
41static DEFINE_IDA(amdgpu_pasid_ida);
42
Christian König4b5f7552018-01-05 11:16:22 +010043/* Helper to free pasid from a fence callback */
44struct amdgpu_pasid_cb {
45 struct dma_fence_cb cb;
46 unsigned int pasid;
47};
48
Christian König620f7742017-12-18 16:53:03 +010049/**
50 * amdgpu_pasid_alloc - Allocate a PASID
51 * @bits: Maximum width of the PASID in bits, must be at least 1
52 *
53 * Allocates a PASID of the given width while keeping smaller PASIDs
54 * available if possible.
55 *
56 * Returns a positive integer on success. Returns %-EINVAL if bits==0.
57 * Returns %-ENOSPC if no PASID was available. Returns %-ENOMEM on
58 * memory allocation failure.
59 */
60int amdgpu_pasid_alloc(unsigned int bits)
61{
62 int pasid = -EINVAL;
63
64 for (bits = min(bits, 31U); bits > 0; bits--) {
65 pasid = ida_simple_get(&amdgpu_pasid_ida,
66 1U << (bits - 1), 1U << bits,
67 GFP_KERNEL);
68 if (pasid != -ENOSPC)
69 break;
70 }
71
72 return pasid;
73}
74
75/**
76 * amdgpu_pasid_free - Free a PASID
77 * @pasid: PASID to free
78 */
79void amdgpu_pasid_free(unsigned int pasid)
80{
81 ida_simple_remove(&amdgpu_pasid_ida, pasid);
82}
83
Christian König4b5f7552018-01-05 11:16:22 +010084static void amdgpu_pasid_free_cb(struct dma_fence *fence,
85 struct dma_fence_cb *_cb)
86{
87 struct amdgpu_pasid_cb *cb =
88 container_of(_cb, struct amdgpu_pasid_cb, cb);
89
90 amdgpu_pasid_free(cb->pasid);
91 dma_fence_put(fence);
92 kfree(cb);
93}
94
95/**
96 * amdgpu_pasid_free_delayed - free pasid when fences signal
97 *
98 * @resv: reservation object with the fences to wait for
99 * @pasid: pasid to free
100 *
101 * Free the pasid only after all the fences in resv are signaled.
102 */
103void amdgpu_pasid_free_delayed(struct reservation_object *resv,
104 unsigned int pasid)
105{
106 struct dma_fence *fence, **fences;
107 struct amdgpu_pasid_cb *cb;
108 unsigned count;
109 int r;
110
111 r = reservation_object_get_fences_rcu(resv, NULL, &count, &fences);
112 if (r)
113 goto fallback;
114
115 if (count == 0) {
116 amdgpu_pasid_free(pasid);
117 return;
118 }
119
120 if (count == 1) {
121 fence = fences[0];
122 kfree(fences);
123 } else {
124 uint64_t context = dma_fence_context_alloc(1);
125 struct dma_fence_array *array;
126
127 array = dma_fence_array_create(count, fences, context,
128 1, false);
129 if (!array) {
130 kfree(fences);
131 goto fallback;
132 }
133 fence = &array->base;
134 }
135
136 cb = kmalloc(sizeof(*cb), GFP_KERNEL);
137 if (!cb) {
138 /* Last resort when we are OOM */
139 dma_fence_wait(fence, false);
140 dma_fence_put(fence);
141 amdgpu_pasid_free(pasid);
142 } else {
143 cb->pasid = pasid;
144 if (dma_fence_add_callback(fence, &cb->cb,
145 amdgpu_pasid_free_cb))
146 amdgpu_pasid_free_cb(fence, &cb->cb);
147 }
148
149 return;
150
151fallback:
152 /* Not enough memory for the delayed delete, as last resort
153 * block for all the fences to complete.
154 */
155 reservation_object_wait_timeout_rcu(resv, true, false,
156 MAX_SCHEDULE_TIMEOUT);
157 amdgpu_pasid_free(pasid);
158}
159
Christian König620f7742017-12-18 16:53:03 +0100160/*
161 * VMID manager
162 *
163 * VMIDs are a per VMHUB identifier for page tables handling.
164 */
165
166/**
167 * amdgpu_vmid_had_gpu_reset - check if reset occured since last use
168 *
169 * @adev: amdgpu_device pointer
170 * @id: VMID structure
171 *
172 * Check if GPU reset occured since last use of the VMID.
173 */
174bool amdgpu_vmid_had_gpu_reset(struct amdgpu_device *adev,
175 struct amdgpu_vmid *id)
176{
177 return id->current_gpu_reset_count !=
178 atomic_read(&adev->gpu_reset_counter);
179}
180
181/* idr_mgr->lock must be held */
182static int amdgpu_vmid_grab_reserved_locked(struct amdgpu_vm *vm,
183 struct amdgpu_ring *ring,
184 struct amdgpu_sync *sync,
185 struct dma_fence *fence,
186 struct amdgpu_job *job)
187{
188 struct amdgpu_device *adev = ring->adev;
189 unsigned vmhub = ring->funcs->vmhub;
190 uint64_t fence_context = adev->fence_context + ring->idx;
191 struct amdgpu_vmid *id = vm->reserved_vmid[vmhub];
192 struct amdgpu_vmid_mgr *id_mgr = &adev->vm_manager.id_mgr[vmhub];
193 struct dma_fence *updates = sync->last_vm_update;
194 int r = 0;
195 struct dma_fence *flushed, *tmp;
196 bool needs_flush = vm->use_cpu_for_update;
197
198 flushed = id->flushed_updates;
199 if ((amdgpu_vmid_had_gpu_reset(adev, id)) ||
Christian König0e36b9b2017-12-18 17:10:01 +0100200 (atomic64_read(&id->owner) != vm->entity.fence_context) ||
Christian König620f7742017-12-18 16:53:03 +0100201 (job->vm_pd_addr != id->pd_gpu_addr) ||
202 (updates && (!flushed || updates->context != flushed->context ||
203 dma_fence_is_later(updates, flushed))) ||
204 (!id->last_flush || (id->last_flush->context != fence_context &&
205 !dma_fence_is_signaled(id->last_flush)))) {
206 needs_flush = true;
207 /* to prevent one context starved by another context */
208 id->pd_gpu_addr = 0;
209 tmp = amdgpu_sync_peek_fence(&id->active, ring);
210 if (tmp) {
211 r = amdgpu_sync_fence(adev, sync, tmp, false);
212 return r;
213 }
214 }
215
216 /* Good we can use this VMID. Remember this submission as
217 * user of the VMID.
218 */
219 r = amdgpu_sync_fence(ring->adev, &id->active, fence, false);
220 if (r)
221 goto out;
222
223 if (updates && (!flushed || updates->context != flushed->context ||
224 dma_fence_is_later(updates, flushed))) {
225 dma_fence_put(id->flushed_updates);
226 id->flushed_updates = dma_fence_get(updates);
227 }
228 id->pd_gpu_addr = job->vm_pd_addr;
Christian König0e36b9b2017-12-18 17:10:01 +0100229 atomic64_set(&id->owner, vm->entity.fence_context);
Christian König620f7742017-12-18 16:53:03 +0100230 job->vm_needs_flush = needs_flush;
231 if (needs_flush) {
232 dma_fence_put(id->last_flush);
233 id->last_flush = NULL;
234 }
Christian Königc4f46f22017-12-18 17:08:25 +0100235 job->vmid = id - id_mgr->ids;
Christian König620f7742017-12-18 16:53:03 +0100236 trace_amdgpu_vm_grab_id(vm, ring, job);
237out:
238 return r;
239}
240
241/**
242 * amdgpu_vm_grab_id - allocate the next free VMID
243 *
244 * @vm: vm to allocate id for
245 * @ring: ring we want to submit job to
246 * @sync: sync object where we add dependencies
247 * @fence: fence protecting ID from reuse
248 *
249 * Allocate an id for the vm, adding fences to the sync obj as necessary.
250 */
251int amdgpu_vmid_grab(struct amdgpu_vm *vm, struct amdgpu_ring *ring,
252 struct amdgpu_sync *sync, struct dma_fence *fence,
253 struct amdgpu_job *job)
254{
255 struct amdgpu_device *adev = ring->adev;
256 unsigned vmhub = ring->funcs->vmhub;
257 struct amdgpu_vmid_mgr *id_mgr = &adev->vm_manager.id_mgr[vmhub];
258 uint64_t fence_context = adev->fence_context + ring->idx;
259 struct dma_fence *updates = sync->last_vm_update;
260 struct amdgpu_vmid *id, *idle;
261 struct dma_fence **fences;
262 unsigned i;
263 int r = 0;
264
265 mutex_lock(&id_mgr->lock);
266 if (vm->reserved_vmid[vmhub]) {
267 r = amdgpu_vmid_grab_reserved_locked(vm, ring, sync, fence, job);
268 mutex_unlock(&id_mgr->lock);
269 return r;
270 }
271 fences = kmalloc_array(sizeof(void *), id_mgr->num_ids, GFP_KERNEL);
272 if (!fences) {
273 mutex_unlock(&id_mgr->lock);
274 return -ENOMEM;
275 }
276 /* Check if we have an idle VMID */
277 i = 0;
278 list_for_each_entry(idle, &id_mgr->ids_lru, list) {
279 fences[i] = amdgpu_sync_peek_fence(&idle->active, ring);
280 if (!fences[i])
281 break;
282 ++i;
283 }
284
285 /* If we can't find a idle VMID to use, wait till one becomes available */
286 if (&idle->list == &id_mgr->ids_lru) {
287 u64 fence_context = adev->vm_manager.fence_context + ring->idx;
288 unsigned seqno = ++adev->vm_manager.seqno[ring->idx];
289 struct dma_fence_array *array;
290 unsigned j;
291
292 for (j = 0; j < i; ++j)
293 dma_fence_get(fences[j]);
294
295 array = dma_fence_array_create(i, fences, fence_context,
296 seqno, true);
297 if (!array) {
298 for (j = 0; j < i; ++j)
299 dma_fence_put(fences[j]);
300 kfree(fences);
301 r = -ENOMEM;
302 goto error;
303 }
304
305
306 r = amdgpu_sync_fence(ring->adev, sync, &array->base, false);
307 dma_fence_put(&array->base);
308 if (r)
309 goto error;
310
311 mutex_unlock(&id_mgr->lock);
312 return 0;
313
314 }
315 kfree(fences);
316
317 job->vm_needs_flush = vm->use_cpu_for_update;
318 /* Check if we can use a VMID already assigned to this VM */
319 list_for_each_entry_reverse(id, &id_mgr->ids_lru, list) {
320 struct dma_fence *flushed;
321 bool needs_flush = vm->use_cpu_for_update;
322
323 /* Check all the prerequisites to using this VMID */
324 if (amdgpu_vmid_had_gpu_reset(adev, id))
325 continue;
326
Christian König0e36b9b2017-12-18 17:10:01 +0100327 if (atomic64_read(&id->owner) != vm->entity.fence_context)
Christian König620f7742017-12-18 16:53:03 +0100328 continue;
329
330 if (job->vm_pd_addr != id->pd_gpu_addr)
331 continue;
332
333 if (!id->last_flush ||
334 (id->last_flush->context != fence_context &&
335 !dma_fence_is_signaled(id->last_flush)))
336 needs_flush = true;
337
338 flushed = id->flushed_updates;
339 if (updates && (!flushed || dma_fence_is_later(updates, flushed)))
340 needs_flush = true;
341
342 /* Concurrent flushes are only possible starting with Vega10 */
343 if (adev->asic_type < CHIP_VEGA10 && needs_flush)
344 continue;
345
346 /* Good we can use this VMID. Remember this submission as
347 * user of the VMID.
348 */
349 r = amdgpu_sync_fence(ring->adev, &id->active, fence, false);
350 if (r)
351 goto error;
352
353 if (updates && (!flushed || dma_fence_is_later(updates, flushed))) {
354 dma_fence_put(id->flushed_updates);
355 id->flushed_updates = dma_fence_get(updates);
356 }
357
358 if (needs_flush)
359 goto needs_flush;
360 else
361 goto no_flush_needed;
362
Fengguang Wu02d170e2018-01-05 07:06:46 +0800363 }
Christian König620f7742017-12-18 16:53:03 +0100364
365 /* Still no ID to use? Then use the idle one found earlier */
366 id = idle;
367
368 /* Remember this submission as user of the VMID */
369 r = amdgpu_sync_fence(ring->adev, &id->active, fence, false);
370 if (r)
371 goto error;
372
373 id->pd_gpu_addr = job->vm_pd_addr;
374 dma_fence_put(id->flushed_updates);
375 id->flushed_updates = dma_fence_get(updates);
Christian König0e36b9b2017-12-18 17:10:01 +0100376 atomic64_set(&id->owner, vm->entity.fence_context);
Christian König620f7742017-12-18 16:53:03 +0100377
378needs_flush:
379 job->vm_needs_flush = true;
380 dma_fence_put(id->last_flush);
381 id->last_flush = NULL;
382
383no_flush_needed:
384 list_move_tail(&id->list, &id_mgr->ids_lru);
385
Christian Königc4f46f22017-12-18 17:08:25 +0100386 job->vmid = id - id_mgr->ids;
Christian König620f7742017-12-18 16:53:03 +0100387 trace_amdgpu_vm_grab_id(vm, ring, job);
388
389error:
390 mutex_unlock(&id_mgr->lock);
391 return r;
392}
393
394int amdgpu_vmid_alloc_reserved(struct amdgpu_device *adev,
395 struct amdgpu_vm *vm,
396 unsigned vmhub)
397{
398 struct amdgpu_vmid_mgr *id_mgr;
399 struct amdgpu_vmid *idle;
400 int r = 0;
401
402 id_mgr = &adev->vm_manager.id_mgr[vmhub];
403 mutex_lock(&id_mgr->lock);
404 if (vm->reserved_vmid[vmhub])
405 goto unlock;
406 if (atomic_inc_return(&id_mgr->reserved_vmid_num) >
407 AMDGPU_VM_MAX_RESERVED_VMID) {
408 DRM_ERROR("Over limitation of reserved vmid\n");
409 atomic_dec(&id_mgr->reserved_vmid_num);
410 r = -EINVAL;
411 goto unlock;
412 }
413 /* Select the first entry VMID */
414 idle = list_first_entry(&id_mgr->ids_lru, struct amdgpu_vmid, list);
415 list_del_init(&idle->list);
416 vm->reserved_vmid[vmhub] = idle;
417 mutex_unlock(&id_mgr->lock);
418
419 return 0;
420unlock:
421 mutex_unlock(&id_mgr->lock);
422 return r;
423}
424
425void amdgpu_vmid_free_reserved(struct amdgpu_device *adev,
426 struct amdgpu_vm *vm,
427 unsigned vmhub)
428{
429 struct amdgpu_vmid_mgr *id_mgr = &adev->vm_manager.id_mgr[vmhub];
430
431 mutex_lock(&id_mgr->lock);
432 if (vm->reserved_vmid[vmhub]) {
433 list_add(&vm->reserved_vmid[vmhub]->list,
434 &id_mgr->ids_lru);
435 vm->reserved_vmid[vmhub] = NULL;
436 atomic_dec(&id_mgr->reserved_vmid_num);
437 }
438 mutex_unlock(&id_mgr->lock);
439}
440
441/**
442 * amdgpu_vmid_reset - reset VMID to zero
443 *
444 * @adev: amdgpu device structure
Christian Königc4f46f22017-12-18 17:08:25 +0100445 * @vmid: vmid number to use
Christian König620f7742017-12-18 16:53:03 +0100446 *
447 * Reset saved GDW, GWS and OA to force switch on next flush.
448 */
449void amdgpu_vmid_reset(struct amdgpu_device *adev, unsigned vmhub,
450 unsigned vmid)
451{
452 struct amdgpu_vmid_mgr *id_mgr = &adev->vm_manager.id_mgr[vmhub];
453 struct amdgpu_vmid *id = &id_mgr->ids[vmid];
454
455 atomic64_set(&id->owner, 0);
456 id->gds_base = 0;
457 id->gds_size = 0;
458 id->gws_base = 0;
459 id->gws_size = 0;
460 id->oa_base = 0;
461 id->oa_size = 0;
462}
463
464/**
465 * amdgpu_vmid_reset_all - reset VMID to zero
466 *
467 * @adev: amdgpu device structure
468 *
469 * Reset VMID to force flush on next use
470 */
471void amdgpu_vmid_reset_all(struct amdgpu_device *adev)
472{
473 unsigned i, j;
474
475 for (i = 0; i < AMDGPU_MAX_VMHUBS; ++i) {
476 struct amdgpu_vmid_mgr *id_mgr =
477 &adev->vm_manager.id_mgr[i];
478
479 for (j = 1; j < id_mgr->num_ids; ++j)
480 amdgpu_vmid_reset(adev, i, j);
481 }
482}
483
484/**
485 * amdgpu_vmid_mgr_init - init the VMID manager
486 *
487 * @adev: amdgpu_device pointer
488 *
489 * Initialize the VM manager structures
490 */
491void amdgpu_vmid_mgr_init(struct amdgpu_device *adev)
492{
493 unsigned i, j;
494
495 for (i = 0; i < AMDGPU_MAX_VMHUBS; ++i) {
496 struct amdgpu_vmid_mgr *id_mgr =
497 &adev->vm_manager.id_mgr[i];
498
499 mutex_init(&id_mgr->lock);
500 INIT_LIST_HEAD(&id_mgr->ids_lru);
501 atomic_set(&id_mgr->reserved_vmid_num, 0);
502
503 /* skip over VMID 0, since it is the system VM */
504 for (j = 1; j < id_mgr->num_ids; ++j) {
505 amdgpu_vmid_reset(adev, i, j);
506 amdgpu_sync_create(&id_mgr->ids[i].active);
507 list_add_tail(&id_mgr->ids[j].list, &id_mgr->ids_lru);
508 }
509 }
510
511 adev->vm_manager.fence_context =
512 dma_fence_context_alloc(AMDGPU_MAX_RINGS);
513 for (i = 0; i < AMDGPU_MAX_RINGS; ++i)
514 adev->vm_manager.seqno[i] = 0;
515}
516
517/**
518 * amdgpu_vmid_mgr_fini - cleanup VM manager
519 *
520 * @adev: amdgpu_device pointer
521 *
522 * Cleanup the VM manager and free resources.
523 */
524void amdgpu_vmid_mgr_fini(struct amdgpu_device *adev)
525{
526 unsigned i, j;
527
528 for (i = 0; i < AMDGPU_MAX_VMHUBS; ++i) {
529 struct amdgpu_vmid_mgr *id_mgr =
530 &adev->vm_manager.id_mgr[i];
531
532 mutex_destroy(&id_mgr->lock);
533 for (j = 0; j < AMDGPU_NUM_VMID; ++j) {
534 struct amdgpu_vmid *id = &id_mgr->ids[j];
535
536 amdgpu_sync_free(&id->active);
537 dma_fence_put(id->flushed_updates);
538 dma_fence_put(id->last_flush);
539 }
540 }
541}