diff options
author | Christian König <christian.koenig@amd.com> | 2018-09-01 04:36:48 -0400 |
---|---|---|
committer | Alex Deucher <alexander.deucher@amd.com> | 2018-09-13 16:14:08 -0400 |
commit | 73633e3223e6e19bd22775b4ad725fdc65d5d8ed (patch) | |
tree | 682d84a8ae00717ae93c7da075ea7411df51227a /drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c | |
parent | 52e211c1f04f7544bf3d3cf5ed3939708d5988d2 (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.c | 224 |
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 | */ | ||
361 | struct 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 | */ | ||
378 | static 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 | */ | ||
398 | static 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 | */ | ||
427 | static 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 | */ | ||
458 | static 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 | */ | ||
477 | static 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 | */ | ||
504 | static 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 | */ | ||
520 | static 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 | */ | ||
543 | static 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 | */ | ||
559 | static 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 |