Commit dc54d3d1 authored by Christian König's avatar Christian König Committed by Alex Deucher

drm/amdgpu: implement AMDGPU_VA_OP_CLEAR v2

A new VM operation to remove all mappings in a range.

v2: limit unmapped area as noted by Jerry
Signed-off-by: default avatarChristian König <christian.koenig@amd.com>
Reviewed-by: default avatarJunwei Zhang <Jerry.Zhang@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent 663e4577
...@@ -507,14 +507,16 @@ static int amdgpu_gem_va_check(void *param, struct amdgpu_bo *bo) ...@@ -507,14 +507,16 @@ static int amdgpu_gem_va_check(void *param, struct amdgpu_bo *bo)
* amdgpu_gem_va_update_vm -update the bo_va in its VM * amdgpu_gem_va_update_vm -update the bo_va in its VM
* *
* @adev: amdgpu_device pointer * @adev: amdgpu_device pointer
* @vm: vm to update
* @bo_va: bo_va to update * @bo_va: bo_va to update
* @list: validation list * @list: validation list
* @operation: map or unmap * @operation: map, unmap or clear
* *
* Update the bo_va directly after setting its address. Errors are not * Update the bo_va directly after setting its address. Errors are not
* vital here, so they are not reported back to userspace. * vital here, so they are not reported back to userspace.
*/ */
static void amdgpu_gem_va_update_vm(struct amdgpu_device *adev, static void amdgpu_gem_va_update_vm(struct amdgpu_device *adev,
struct amdgpu_vm *vm,
struct amdgpu_bo_va *bo_va, struct amdgpu_bo_va *bo_va,
struct list_head *list, struct list_head *list,
uint32_t operation) uint32_t operation)
...@@ -529,16 +531,16 @@ static void amdgpu_gem_va_update_vm(struct amdgpu_device *adev, ...@@ -529,16 +531,16 @@ static void amdgpu_gem_va_update_vm(struct amdgpu_device *adev,
goto error; goto error;
} }
r = amdgpu_vm_validate_pt_bos(adev, bo_va->vm, amdgpu_gem_va_check, r = amdgpu_vm_validate_pt_bos(adev, vm, amdgpu_gem_va_check,
NULL); NULL);
if (r) if (r)
goto error; goto error;
r = amdgpu_vm_update_page_directory(adev, bo_va->vm); r = amdgpu_vm_update_page_directory(adev, vm);
if (r) if (r)
goto error; goto error;
r = amdgpu_vm_clear_freed(adev, bo_va->vm); r = amdgpu_vm_clear_freed(adev, vm);
if (r) if (r)
goto error; goto error;
...@@ -592,6 +594,7 @@ int amdgpu_gem_va_ioctl(struct drm_device *dev, void *data, ...@@ -592,6 +594,7 @@ int amdgpu_gem_va_ioctl(struct drm_device *dev, void *data,
switch (args->operation) { switch (args->operation) {
case AMDGPU_VA_OP_MAP: case AMDGPU_VA_OP_MAP:
case AMDGPU_VA_OP_UNMAP: case AMDGPU_VA_OP_UNMAP:
case AMDGPU_VA_OP_CLEAR:
break; break;
default: default:
dev_err(&dev->pdev->dev, "unsupported operation %d\n", dev_err(&dev->pdev->dev, "unsupported operation %d\n",
...@@ -600,7 +603,8 @@ int amdgpu_gem_va_ioctl(struct drm_device *dev, void *data, ...@@ -600,7 +603,8 @@ int amdgpu_gem_va_ioctl(struct drm_device *dev, void *data,
} }
INIT_LIST_HEAD(&list); INIT_LIST_HEAD(&list);
if (!(args->flags & AMDGPU_VM_PAGE_PRT)) { if ((args->operation != AMDGPU_VA_OP_CLEAR) &&
!(args->flags & AMDGPU_VM_PAGE_PRT)) {
gobj = drm_gem_object_lookup(filp, args->handle); gobj = drm_gem_object_lookup(filp, args->handle);
if (gobj == NULL) if (gobj == NULL)
return -ENOENT; return -ENOENT;
...@@ -625,8 +629,10 @@ int amdgpu_gem_va_ioctl(struct drm_device *dev, void *data, ...@@ -625,8 +629,10 @@ int amdgpu_gem_va_ioctl(struct drm_device *dev, void *data,
r = -ENOENT; r = -ENOENT;
goto error_backoff; goto error_backoff;
} }
} else { } else if (args->operation != AMDGPU_VA_OP_CLEAR) {
bo_va = fpriv->prt_va; bo_va = fpriv->prt_va;
} else {
bo_va = NULL;
} }
switch (args->operation) { switch (args->operation) {
...@@ -644,11 +650,18 @@ int amdgpu_gem_va_ioctl(struct drm_device *dev, void *data, ...@@ -644,11 +650,18 @@ int amdgpu_gem_va_ioctl(struct drm_device *dev, void *data,
case AMDGPU_VA_OP_UNMAP: case AMDGPU_VA_OP_UNMAP:
r = amdgpu_vm_bo_unmap(adev, bo_va, args->va_address); r = amdgpu_vm_bo_unmap(adev, bo_va, args->va_address);
break; break;
case AMDGPU_VA_OP_CLEAR:
r = amdgpu_vm_bo_clear_mappings(adev, &fpriv->vm,
args->va_address,
args->map_size);
break;
default: default:
break; break;
} }
if (!r && !(args->flags & AMDGPU_VM_DELAY_UPDATE) && !amdgpu_vm_debug) if (!r && !(args->flags & AMDGPU_VM_DELAY_UPDATE) && !amdgpu_vm_debug)
amdgpu_gem_va_update_vm(adev, bo_va, &list, args->operation); amdgpu_gem_va_update_vm(adev, &fpriv->vm, bo_va, &list,
args->operation);
error_backoff: error_backoff:
ttm_eu_backoff_reservation(&ticket, &list); ttm_eu_backoff_reservation(&ticket, &list);
......
...@@ -188,7 +188,7 @@ TRACE_EVENT(amdgpu_vm_bo_map, ...@@ -188,7 +188,7 @@ TRACE_EVENT(amdgpu_vm_bo_map,
), ),
TP_fast_assign( TP_fast_assign(
__entry->bo = bo_va->bo; __entry->bo = bo_va ? bo_va->bo : NULL;
__entry->start = mapping->it.start; __entry->start = mapping->it.start;
__entry->last = mapping->it.last; __entry->last = mapping->it.last;
__entry->offset = mapping->offset; __entry->offset = mapping->offset;
......
...@@ -1612,6 +1612,105 @@ int amdgpu_vm_bo_unmap(struct amdgpu_device *adev, ...@@ -1612,6 +1612,105 @@ int amdgpu_vm_bo_unmap(struct amdgpu_device *adev,
return 0; return 0;
} }
/**
* amdgpu_vm_bo_clear_mappings - remove all mappings in a specific range
*
* @adev: amdgpu_device pointer
* @vm: VM structure to use
* @saddr: start of the range
* @size: size of the range
*
* Remove all mappings in a range, split them as appropriate.
* Returns 0 for success, error for failure.
*/
int amdgpu_vm_bo_clear_mappings(struct amdgpu_device *adev,
struct amdgpu_vm *vm,
uint64_t saddr, uint64_t size)
{
struct amdgpu_bo_va_mapping *before, *after, *tmp, *next;
struct interval_tree_node *it;
LIST_HEAD(removed);
uint64_t eaddr;
eaddr = saddr + size - 1;
saddr /= AMDGPU_GPU_PAGE_SIZE;
eaddr /= AMDGPU_GPU_PAGE_SIZE;
/* Allocate all the needed memory */
before = kzalloc(sizeof(*before), GFP_KERNEL);
if (!before)
return -ENOMEM;
after = kzalloc(sizeof(*after), GFP_KERNEL);
if (!after) {
kfree(before);
return -ENOMEM;
}
/* Now gather all removed mappings */
it = interval_tree_iter_first(&vm->va, saddr, eaddr);
while (it) {
tmp = container_of(it, struct amdgpu_bo_va_mapping, it);
it = interval_tree_iter_next(it, saddr, eaddr);
/* Remember mapping split at the start */
if (tmp->it.start < saddr) {
before->it.start = tmp->it.start;;
before->it.last = saddr - 1;
before->offset = tmp->offset;
before->flags = tmp->flags;
list_add(&before->list, &tmp->list);
}
/* Remember mapping split at the end */
if (tmp->it.last > eaddr) {
after->it.start = eaddr + 1;
after->it.last = tmp->it.last;
after->offset = tmp->offset;
after->offset += after->it.start - tmp->it.start;
after->flags = tmp->flags;
list_add(&after->list, &tmp->list);
}
list_del(&tmp->list);
list_add(&tmp->list, &removed);
}
/* And free them up */
list_for_each_entry_safe(tmp, next, &removed, list) {
interval_tree_remove(&tmp->it, &vm->va);
list_del(&tmp->list);
if (tmp->it.start < saddr)
tmp->it.start = saddr;
if (tmp->it.last > eaddr)
tmp->it.last = eaddr;
list_add(&tmp->list, &vm->freed);
trace_amdgpu_vm_bo_unmap(NULL, tmp);
}
/* Insert partial mapping before the range*/
if (before->it.start != before->it.last) {
interval_tree_insert(&before->it, &vm->va);
if (before->flags & AMDGPU_PTE_PRT)
amdgpu_vm_prt_get(adev);
} else {
kfree(before);
}
/* Insert partial mapping after the range */
if (after->it.start != after->it.last) {
interval_tree_insert(&after->it, &vm->va);
if (after->flags & AMDGPU_PTE_PRT)
amdgpu_vm_prt_get(adev);
} else {
kfree(after);
}
return 0;
}
/** /**
* amdgpu_vm_bo_rmv - remove a bo to a specific vm * amdgpu_vm_bo_rmv - remove a bo to a specific vm
* *
......
...@@ -210,6 +210,9 @@ int amdgpu_vm_bo_map(struct amdgpu_device *adev, ...@@ -210,6 +210,9 @@ int amdgpu_vm_bo_map(struct amdgpu_device *adev,
int amdgpu_vm_bo_unmap(struct amdgpu_device *adev, int amdgpu_vm_bo_unmap(struct amdgpu_device *adev,
struct amdgpu_bo_va *bo_va, struct amdgpu_bo_va *bo_va,
uint64_t addr); uint64_t addr);
int amdgpu_vm_bo_clear_mappings(struct amdgpu_device *adev,
struct amdgpu_vm *vm,
uint64_t saddr, uint64_t size);
void amdgpu_vm_bo_rmv(struct amdgpu_device *adev, void amdgpu_vm_bo_rmv(struct amdgpu_device *adev,
struct amdgpu_bo_va *bo_va); struct amdgpu_bo_va *bo_va);
......
...@@ -350,6 +350,7 @@ struct drm_amdgpu_gem_op { ...@@ -350,6 +350,7 @@ struct drm_amdgpu_gem_op {
#define AMDGPU_VA_OP_MAP 1 #define AMDGPU_VA_OP_MAP 1
#define AMDGPU_VA_OP_UNMAP 2 #define AMDGPU_VA_OP_UNMAP 2
#define AMDGPU_VA_OP_CLEAR 3
/* Delay the page table update till the next CS */ /* Delay the page table update till the next CS */
#define AMDGPU_VM_DELAY_UPDATE (1 << 0) #define AMDGPU_VM_DELAY_UPDATE (1 << 0)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment