aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
diff options
context:
space:
mode:
authorChristian König <christian.koenig@amd.com>2018-09-01 04:36:48 -0400
committerAlex Deucher <alexander.deucher@amd.com>2018-09-13 16:14:08 -0400
commit73633e3223e6e19bd22775b4ad725fdc65d5d8ed (patch)
tree682d84a8ae00717ae93c7da075ea7411df51227a /drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
parent52e211c1f04f7544bf3d3cf5ed3939708d5988d2 (diff)
drm/amdgpu: add some VM PD/PT iterators v2
Both a leaf as well as dfs iterator to walk over all the PDs/PTs. v2: update comments and fix for_each_amdgpu_vm_pt_dfs_safe Signed-off-by: Christian König <christian.koenig@amd.com> Reviewed-by: Huang Rui <ray.huang@amd.com> Reviewed-by: Junwei Zhang <Jerry.Zhang@amd.com> Reviewed-by: Felix Kuehling <Felix.Kuehling@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Diffstat (limited to 'drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c')
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c224
1 files changed, 224 insertions, 0 deletions
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
index be1659fedf94..06a173e843ce 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
@@ -356,6 +356,230 @@ static struct amdgpu_vm_pt *amdgpu_vm_pt_parent(struct amdgpu_vm_pt *pt)
356} 356}
357 357
358/** 358/**
359 * amdgpu_vm_pt_cursor - state for for_each_amdgpu_vm_pt
360 */
361struct amdgpu_vm_pt_cursor {
362 uint64_t pfn;
363 struct amdgpu_vm_pt *parent;
364 struct amdgpu_vm_pt *entry;
365 unsigned level;
366};
367
368/**
369 * amdgpu_vm_pt_start - start PD/PT walk
370 *
371 * @adev: amdgpu_device pointer
372 * @vm: amdgpu_vm structure
373 * @start: start address of the walk
374 * @cursor: state to initialize
375 *
376 * Initialize a amdgpu_vm_pt_cursor to start a walk.
377 */
378static void amdgpu_vm_pt_start(struct amdgpu_device *adev,
379 struct amdgpu_vm *vm, uint64_t start,
380 struct amdgpu_vm_pt_cursor *cursor)
381{
382 cursor->pfn = start;
383 cursor->parent = NULL;
384 cursor->entry = &vm->root;
385 cursor->level = adev->vm_manager.root_level;
386}
387
388/**
389 * amdgpu_vm_pt_descendant - go to child node
390 *
391 * @adev: amdgpu_device pointer
392 * @cursor: current state
393 *
394 * Walk to the child node of the current node.
395 * Returns:
396 * True if the walk was possible, false otherwise.
397 */
398static bool amdgpu_vm_pt_descendant(struct amdgpu_device *adev,
399 struct amdgpu_vm_pt_cursor *cursor)
400{
401 unsigned num_entries, shift, idx;
402
403 if (!cursor->entry->entries)
404 return false;
405
406 BUG_ON(!cursor->entry->base.bo);
407 num_entries = amdgpu_vm_num_entries(adev, cursor->level);
408 shift = amdgpu_vm_level_shift(adev, cursor->level);
409
410 ++cursor->level;
411 idx = (cursor->pfn >> shift) % num_entries;
412 cursor->parent = cursor->entry;
413 cursor->entry = &cursor->entry->entries[idx];
414 return true;
415}
416
417/**
418 * amdgpu_vm_pt_sibling - go to sibling node
419 *
420 * @adev: amdgpu_device pointer
421 * @cursor: current state
422 *
423 * Walk to the sibling node of the current node.
424 * Returns:
425 * True if the walk was possible, false otherwise.
426 */
427static bool amdgpu_vm_pt_sibling(struct amdgpu_device *adev,
428 struct amdgpu_vm_pt_cursor *cursor)
429{
430 unsigned shift, num_entries;
431
432 /* Root doesn't have a sibling */
433 if (!cursor->parent)
434 return false;
435
436 /* Go to our parents and see if we got a sibling */
437 shift = amdgpu_vm_level_shift(adev, cursor->level - 1);
438 num_entries = amdgpu_vm_num_entries(adev, cursor->level - 1);
439
440 if (cursor->entry == &cursor->parent->entries[num_entries - 1])
441 return false;
442
443 cursor->pfn += 1ULL << shift;
444 cursor->pfn &= ~((1ULL << shift) - 1);
445 ++cursor->entry;
446 return true;
447}
448
449/**
450 * amdgpu_vm_pt_ancestor - go to parent node
451 *
452 * @cursor: current state
453 *
454 * Walk to the parent node of the current node.
455 * Returns:
456 * True if the walk was possible, false otherwise.
457 */
458static bool amdgpu_vm_pt_ancestor(struct amdgpu_vm_pt_cursor *cursor)
459{
460 if (!cursor->parent)
461 return false;
462
463 --cursor->level;
464 cursor->entry = cursor->parent;
465 cursor->parent = amdgpu_vm_pt_parent(cursor->parent);
466 return true;
467}
468
469/**
470 * amdgpu_vm_pt_next - get next PD/PT in hieratchy
471 *
472 * @adev: amdgpu_device pointer
473 * @cursor: current state
474 *
475 * Walk the PD/PT tree to the next node.
476 */
477static void amdgpu_vm_pt_next(struct amdgpu_device *adev,
478 struct amdgpu_vm_pt_cursor *cursor)
479{
480 /* First try a newborn child */
481 if (amdgpu_vm_pt_descendant(adev, cursor))
482 return;
483
484 /* If that didn't worked try to find a sibling */
485 while (!amdgpu_vm_pt_sibling(adev, cursor)) {
486 /* No sibling, go to our parents and grandparents */
487 if (!amdgpu_vm_pt_ancestor(cursor)) {
488 cursor->pfn = ~0ll;
489 return;
490 }
491 }
492}
493
494/**
495 * amdgpu_vm_pt_first_leaf - get first leaf PD/PT
496 *
497 * @adev: amdgpu_device pointer
498 * @vm: amdgpu_vm structure
499 * @start: start addr of the walk
500 * @cursor: state to initialize
501 *
502 * Start a walk and go directly to the leaf node.
503 */
504static void amdgpu_vm_pt_first_leaf(struct amdgpu_device *adev,
505 struct amdgpu_vm *vm, uint64_t start,
506 struct amdgpu_vm_pt_cursor *cursor)
507{
508 amdgpu_vm_pt_start(adev, vm, start, cursor);
509 while (amdgpu_vm_pt_descendant(adev, cursor));
510}
511
512/**
513 * amdgpu_vm_pt_next_leaf - get next leaf PD/PT
514 *
515 * @adev: amdgpu_device pointer
516 * @cursor: current state
517 *
518 * Walk the PD/PT tree to the next leaf node.
519 */
520static void amdgpu_vm_pt_next_leaf(struct amdgpu_device *adev,
521 struct amdgpu_vm_pt_cursor *cursor)
522{
523 amdgpu_vm_pt_next(adev, cursor);
524 while (amdgpu_vm_pt_descendant(adev, cursor));
525}
526
527/**
528 * for_each_amdgpu_vm_pt_leaf - walk over all leaf PDs/PTs in the hierarchy
529 */
530#define for_each_amdgpu_vm_pt_leaf(adev, vm, start, end, cursor) \
531 for (amdgpu_vm_pt_first_leaf((adev), (vm), (start), &(cursor)); \
532 (cursor).pfn <= end; amdgpu_vm_pt_next_leaf((adev), &(cursor)))
533
534/**
535 * amdgpu_vm_pt_first_dfs - start a deep first search
536 *
537 * @adev: amdgpu_device structure
538 * @vm: amdgpu_vm structure
539 * @cursor: state to initialize
540 *
541 * Starts a deep first traversal of the PD/PT tree.
542 */
543static void amdgpu_vm_pt_first_dfs(struct amdgpu_device *adev,
544 struct amdgpu_vm *vm,
545 struct amdgpu_vm_pt_cursor *cursor)
546{
547 amdgpu_vm_pt_start(adev, vm, 0, cursor);
548 while (amdgpu_vm_pt_descendant(adev, cursor));
549}
550
551/**
552 * amdgpu_vm_pt_next_dfs - get the next node for a deep first search
553 *
554 * @adev: amdgpu_device structure
555 * @cursor: current state
556 *
557 * Move the cursor to the next node in a deep first search.
558 */
559static void amdgpu_vm_pt_next_dfs(struct amdgpu_device *adev,
560 struct amdgpu_vm_pt_cursor *cursor)
561{
562 if (!cursor->entry)
563 return;
564
565 if (!cursor->parent)
566 cursor->entry = NULL;
567 else if (amdgpu_vm_pt_sibling(adev, cursor))
568 while (amdgpu_vm_pt_descendant(adev, cursor));
569 else
570 amdgpu_vm_pt_ancestor(cursor);
571}
572
573/**
574 * for_each_amdgpu_vm_pt_dfs_safe - safe deep first search of all PDs/PTs
575 */
576#define for_each_amdgpu_vm_pt_dfs_safe(adev, vm, cursor, entry) \
577 for (amdgpu_vm_pt_first_dfs((adev), (vm), &(cursor)), \
578 (entry) = (cursor).entry, amdgpu_vm_pt_next_dfs((adev), &(cursor));\
579 (entry); (entry) = (cursor).entry, \
580 amdgpu_vm_pt_next_dfs((adev), &(cursor)))
581
582/**
359 * amdgpu_vm_get_pd_bo - add the VM PD to a validation list 583 * amdgpu_vm_get_pd_bo - add the VM PD to a validation list
360 * 584 *
361 * @vm: vm providing the BOs 585 * @vm: vm providing the BOs