|
27 | 27 | #include "xe_device.h" |
28 | 28 | #include "xe_drm_client.h" |
29 | 29 | #include "xe_exec_queue.h" |
| 30 | +#include "xe_gt.h" |
30 | 31 | #include "xe_migrate.h" |
31 | 32 | #include "xe_pat.h" |
32 | 33 | #include "xe_pm.h" |
@@ -577,6 +578,74 @@ static void preempt_rebind_work_func(struct work_struct *w) |
577 | 578 | trace_xe_vm_rebind_worker_exit(vm); |
578 | 579 | } |
579 | 580 |
|
| 581 | +/** |
| 582 | + * xe_vm_add_fault_entry_pf() - Add pagefault to vm fault list |
| 583 | + * @vm: The VM. |
| 584 | + * @pf: The pagefault. |
| 585 | + * |
| 586 | + * This function takes the data from the pagefault @pf and saves it to @vm->faults.list. |
| 587 | + * |
| 588 | + * The function exits silently if the list is full, and reports a warning if the pagefault |
| 589 | + * could not be saved to the list. |
| 590 | + */ |
| 591 | +void xe_vm_add_fault_entry_pf(struct xe_vm *vm, struct xe_pagefault *pf) |
| 592 | +{ |
| 593 | + struct xe_vm_fault_entry *e; |
| 594 | + struct xe_hw_engine *hwe; |
| 595 | + |
| 596 | + /* Do not report faults on reserved engines */ |
| 597 | + hwe = xe_gt_hw_engine(pf->gt, pf->consumer.engine_class, |
| 598 | + pf->consumer.engine_instance, false); |
| 599 | + if (!hwe || xe_hw_engine_is_reserved(hwe)) |
| 600 | + return; |
| 601 | + |
| 602 | + e = kzalloc_obj(*e); |
| 603 | + if (!e) { |
| 604 | + drm_warn(&vm->xe->drm, |
| 605 | + "Could not allocate memory for fault!\n"); |
| 606 | + return; |
| 607 | + } |
| 608 | + |
| 609 | + guard(spinlock)(&vm->faults.lock); |
| 610 | + |
| 611 | + /* |
| 612 | + * Limit the number of faults in the fault list to prevent |
| 613 | + * memory overuse. |
| 614 | + */ |
| 615 | + if (vm->faults.len >= MAX_FAULTS_SAVED_PER_VM) { |
| 616 | + kfree(e); |
| 617 | + return; |
| 618 | + } |
| 619 | + |
| 620 | + e->address = pf->consumer.page_addr; |
| 621 | + /* |
| 622 | + * TODO: |
| 623 | + * Address precision is currently always SZ_4K, but this may change |
| 624 | + * in the future. |
| 625 | + */ |
| 626 | + e->address_precision = SZ_4K; |
| 627 | + e->access_type = pf->consumer.access_type; |
| 628 | + e->fault_type = FIELD_GET(XE_PAGEFAULT_TYPE_MASK, |
| 629 | + pf->consumer.fault_type_level), |
| 630 | + e->fault_level = FIELD_GET(XE_PAGEFAULT_LEVEL_MASK, |
| 631 | + pf->consumer.fault_type_level), |
| 632 | + |
| 633 | + list_add_tail(&e->list, &vm->faults.list); |
| 634 | + vm->faults.len++; |
| 635 | +} |
| 636 | + |
| 637 | +static void xe_vm_clear_fault_entries(struct xe_vm *vm) |
| 638 | +{ |
| 639 | + struct xe_vm_fault_entry *e, *tmp; |
| 640 | + |
| 641 | + guard(spinlock)(&vm->faults.lock); |
| 642 | + list_for_each_entry_safe(e, tmp, &vm->faults.list, list) { |
| 643 | + list_del(&e->list); |
| 644 | + kfree(e); |
| 645 | + } |
| 646 | + vm->faults.len = 0; |
| 647 | +} |
| 648 | + |
580 | 649 | static int xe_vma_ops_alloc(struct xe_vma_ops *vops, bool array_of_binds) |
581 | 650 | { |
582 | 651 | int i; |
@@ -1538,6 +1607,9 @@ struct xe_vm *xe_vm_create(struct xe_device *xe, u32 flags, struct xe_file *xef) |
1538 | 1607 | INIT_LIST_HEAD(&vm->userptr.invalidated); |
1539 | 1608 | spin_lock_init(&vm->userptr.invalidated_lock); |
1540 | 1609 |
|
| 1610 | + INIT_LIST_HEAD(&vm->faults.list); |
| 1611 | + spin_lock_init(&vm->faults.lock); |
| 1612 | + |
1541 | 1613 | ttm_lru_bulk_move_init(&vm->lru_bulk_move); |
1542 | 1614 |
|
1543 | 1615 | INIT_WORK(&vm->destroy_work, vm_destroy_work_func); |
@@ -1854,6 +1926,8 @@ void xe_vm_close_and_put(struct xe_vm *vm) |
1854 | 1926 | } |
1855 | 1927 | up_write(&xe->usm.lock); |
1856 | 1928 |
|
| 1929 | + xe_vm_clear_fault_entries(vm); |
| 1930 | + |
1857 | 1931 | for_each_tile(tile, xe, id) |
1858 | 1932 | xe_range_fence_tree_fini(&vm->rftree[id]); |
1859 | 1933 |
|
|
0 commit comments