aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c')
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c99
1 files changed, 99 insertions, 0 deletions
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
index 296e985d0b65..b67e94e25cfc 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c
@@ -1613,6 +1613,105 @@ int amdgpu_vm_bo_unmap(struct amdgpu_device *adev,
1613} 1613}
1614 1614
1615/** 1615/**
1616 * amdgpu_vm_bo_clear_mappings - remove all mappings in a specific range
1617 *
1618 * @adev: amdgpu_device pointer
1619 * @vm: VM structure to use
1620 * @saddr: start of the range
1621 * @size: size of the range
1622 *
1623 * Remove all mappings in a range, split them as appropriate.
1624 * Returns 0 for success, error for failure.
1625 */
1626int amdgpu_vm_bo_clear_mappings(struct amdgpu_device *adev,
1627 struct amdgpu_vm *vm,
1628 uint64_t saddr, uint64_t size)
1629{
1630 struct amdgpu_bo_va_mapping *before, *after, *tmp, *next;
1631 struct interval_tree_node *it;
1632 LIST_HEAD(removed);
1633 uint64_t eaddr;
1634
1635 eaddr = saddr + size - 1;
1636 saddr /= AMDGPU_GPU_PAGE_SIZE;
1637 eaddr /= AMDGPU_GPU_PAGE_SIZE;
1638
1639 /* Allocate all the needed memory */
1640 before = kzalloc(sizeof(*before), GFP_KERNEL);
1641 if (!before)
1642 return -ENOMEM;
1643
1644 after = kzalloc(sizeof(*after), GFP_KERNEL);
1645 if (!after) {
1646 kfree(before);
1647 return -ENOMEM;
1648 }
1649
1650 /* Now gather all removed mappings */
1651 it = interval_tree_iter_first(&vm->va, saddr, eaddr);
1652 while (it) {
1653 tmp = container_of(it, struct amdgpu_bo_va_mapping, it);
1654 it = interval_tree_iter_next(it, saddr, eaddr);
1655
1656 /* Remember mapping split at the start */
1657 if (tmp->it.start < saddr) {
1658 before->it.start = tmp->it.start;;
1659 before->it.last = saddr - 1;
1660 before->offset = tmp->offset;
1661 before->flags = tmp->flags;
1662 list_add(&before->list, &tmp->list);
1663 }
1664
1665 /* Remember mapping split at the end */
1666 if (tmp->it.last > eaddr) {
1667 after->it.start = eaddr + 1;
1668 after->it.last = tmp->it.last;
1669 after->offset = tmp->offset;
1670 after->offset += after->it.start - tmp->it.start;
1671 after->flags = tmp->flags;
1672 list_add(&after->list, &tmp->list);
1673 }
1674
1675 list_del(&tmp->list);
1676 list_add(&tmp->list, &removed);
1677 }
1678
1679 /* And free them up */
1680 list_for_each_entry_safe(tmp, next, &removed, list) {
1681 interval_tree_remove(&tmp->it, &vm->va);
1682 list_del(&tmp->list);
1683
1684 if (tmp->it.start < saddr)
1685 tmp->it.start = saddr;
1686 if (tmp->it.last > eaddr)
1687 tmp->it.last = eaddr;
1688
1689 list_add(&tmp->list, &vm->freed);
1690 trace_amdgpu_vm_bo_unmap(NULL, tmp);
1691 }
1692
1693 /* Insert partial mapping before the range*/
1694 if (before->it.start != before->it.last) {
1695 interval_tree_insert(&before->it, &vm->va);
1696 if (before->flags & AMDGPU_PTE_PRT)
1697 amdgpu_vm_prt_get(adev);
1698 } else {
1699 kfree(before);
1700 }
1701
1702 /* Insert partial mapping after the range */
1703 if (after->it.start != after->it.last) {
1704 interval_tree_insert(&after->it, &vm->va);
1705 if (after->flags & AMDGPU_PTE_PRT)
1706 amdgpu_vm_prt_get(adev);
1707 } else {
1708 kfree(after);
1709 }
1710
1711 return 0;
1712}
1713
1714/**
1616 * amdgpu_vm_bo_rmv - remove a bo to a specific vm 1715 * amdgpu_vm_bo_rmv - remove a bo to a specific vm
1617 * 1716 *
1618 * @adev: amdgpu_device pointer 1717 * @adev: amdgpu_device pointer