Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e35fb064 authored by Christian König's avatar Christian König Committed by Alex Deucher
Browse files

drm/amdgpu: free PDs/PTs on demand



When something is unmapped we now free the affected PDs/PTs again.

Signed-off-by: default avatarChristian König <christian.koenig@amd.com>
Reviewed-by: default avatarFelix Kuehling <Felix.Kuehling@amd.com>
Acked-by: default avatarHuang Rui <ray.huang@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent 0ce15d6f
Loading
Loading
Loading
Loading
+53 −18
Original line number Original line Diff line number Diff line
@@ -531,12 +531,31 @@ static void amdgpu_vm_pt_next(struct amdgpu_device *adev,
 */
 */
static void amdgpu_vm_pt_first_dfs(struct amdgpu_device *adev,
static void amdgpu_vm_pt_first_dfs(struct amdgpu_device *adev,
				   struct amdgpu_vm *vm,
				   struct amdgpu_vm *vm,
				   struct amdgpu_vm_pt_cursor *start,
				   struct amdgpu_vm_pt_cursor *cursor)
				   struct amdgpu_vm_pt_cursor *cursor)
{
{
	if (start)
		*cursor = *start;
	else
		amdgpu_vm_pt_start(adev, vm, 0, cursor);
		amdgpu_vm_pt_start(adev, vm, 0, cursor);
	while (amdgpu_vm_pt_descendant(adev, cursor));
	while (amdgpu_vm_pt_descendant(adev, cursor));
}
}


/**
 * amdgpu_vm_pt_continue_dfs - check if the deep first search should continue
 *
 * @start: starting point for the search
 * @entry: current entry
 *
 * Returns:
 * True when the search should continue, false otherwise.
 */
static bool amdgpu_vm_pt_continue_dfs(struct amdgpu_vm_pt_cursor *start,
				      struct amdgpu_vm_pt *entry)
{
	return entry && (!start || entry != start->entry);
}

/**
/**
 * amdgpu_vm_pt_next_dfs - get the next node for a deep first search
 * amdgpu_vm_pt_next_dfs - get the next node for a deep first search
 *
 *
@@ -562,11 +581,11 @@ static void amdgpu_vm_pt_next_dfs(struct amdgpu_device *adev,
/**
/**
 * for_each_amdgpu_vm_pt_dfs_safe - safe deep first search of all PDs/PTs
 * for_each_amdgpu_vm_pt_dfs_safe - safe deep first search of all PDs/PTs
 */
 */
#define for_each_amdgpu_vm_pt_dfs_safe(adev, vm, cursor, entry)			\
#define for_each_amdgpu_vm_pt_dfs_safe(adev, vm, start, cursor, entry)		\
	for (amdgpu_vm_pt_first_dfs((adev), (vm), &(cursor)),			\
	for (amdgpu_vm_pt_first_dfs((adev), (vm), (start), &(cursor)),		\
	     (entry) = (cursor).entry, amdgpu_vm_pt_next_dfs((adev), &(cursor));\
	     (entry) = (cursor).entry, amdgpu_vm_pt_next_dfs((adev), &(cursor));\
	     (entry); (entry) = (cursor).entry,					\
	     amdgpu_vm_pt_continue_dfs((start), (entry));			\
	     amdgpu_vm_pt_next_dfs((adev), &(cursor)))
	     (entry) = (cursor).entry, amdgpu_vm_pt_next_dfs((adev), &(cursor)))


/**
/**
 * amdgpu_vm_get_pd_bo - add the VM PD to a validation list
 * amdgpu_vm_get_pd_bo - add the VM PD to a validation list
@@ -944,32 +963,46 @@ static int amdgpu_vm_alloc_pts(struct amdgpu_device *adev,
	return r;
	return r;
}
}


/**
 * amdgpu_vm_free_table - fre one PD/PT
 *
 * @entry: PDE to free
 */
static void amdgpu_vm_free_table(struct amdgpu_vm_pt *entry)
{
	if (entry->base.bo) {
		entry->base.bo->vm_bo = NULL;
		list_del(&entry->base.vm_status);
		amdgpu_bo_unref(&entry->base.bo->shadow);
		amdgpu_bo_unref(&entry->base.bo);
	}
	kvfree(entry->entries);
	entry->entries = NULL;
}

/**
/**
 * amdgpu_vm_free_pts - free PD/PT levels
 * amdgpu_vm_free_pts - free PD/PT levels
 *
 *
 * @adev: amdgpu device structure
 * @adev: amdgpu device structure
 * @vm: amdgpu vm structure
 * @vm: amdgpu vm structure
 * @start: optional cursor where to start freeing PDs/PTs
 *
 *
 * Free the page directory or page table level and all sub levels.
 * Free the page directory or page table level and all sub levels.
 */
 */
static void amdgpu_vm_free_pts(struct amdgpu_device *adev,
static void amdgpu_vm_free_pts(struct amdgpu_device *adev,
			       struct amdgpu_vm *vm)
			       struct amdgpu_vm *vm,
			       struct amdgpu_vm_pt_cursor *start)
{
{
	struct amdgpu_vm_pt_cursor cursor;
	struct amdgpu_vm_pt_cursor cursor;
	struct amdgpu_vm_pt *entry;
	struct amdgpu_vm_pt *entry;


	for_each_amdgpu_vm_pt_dfs_safe(adev, vm, cursor, entry) {
	vm->bulk_moveable = false;


		if (entry->base.bo) {
	for_each_amdgpu_vm_pt_dfs_safe(adev, vm, start, cursor, entry)
			entry->base.bo->vm_bo = NULL;
		amdgpu_vm_free_table(entry);
			list_del(&entry->base.vm_status);
			amdgpu_bo_unref(&entry->base.bo->shadow);
			amdgpu_bo_unref(&entry->base.bo);
		}
		kvfree(entry->entries);
	}


	BUG_ON(vm->root.base.bo);
	if (start)
		amdgpu_vm_free_table(start->entry);
}
}


/**
/**
@@ -1365,7 +1398,7 @@ static void amdgpu_vm_invalidate_pds(struct amdgpu_device *adev,
	struct amdgpu_vm_pt_cursor cursor;
	struct amdgpu_vm_pt_cursor cursor;
	struct amdgpu_vm_pt *entry;
	struct amdgpu_vm_pt *entry;


	for_each_amdgpu_vm_pt_dfs_safe(adev, vm, cursor, entry)
	for_each_amdgpu_vm_pt_dfs_safe(adev, vm, NULL, cursor, entry)
		if (entry->base.bo && !entry->base.moved)
		if (entry->base.bo && !entry->base.moved)
			amdgpu_vm_bo_relocated(&entry->base);
			amdgpu_vm_bo_relocated(&entry->base);
}
}
@@ -1673,6 +1706,7 @@ static int amdgpu_vm_update_ptes(struct amdgpu_pte_update_params *params,
			/* Mark all child entries as huge */
			/* Mark all child entries as huge */
			while (cursor.pfn < frag_start) {
			while (cursor.pfn < frag_start) {
				cursor.entry->huge = true;
				cursor.entry->huge = true;
				amdgpu_vm_free_pts(adev, params->vm, &cursor);
				amdgpu_vm_pt_next(adev, &cursor);
				amdgpu_vm_pt_next(adev, &cursor);
			}
			}


@@ -3236,10 +3270,11 @@ void amdgpu_vm_fini(struct amdgpu_device *adev, struct amdgpu_vm *vm)
	if (r) {
	if (r) {
		dev_err(adev->dev, "Leaking page tables because BO reservation failed\n");
		dev_err(adev->dev, "Leaking page tables because BO reservation failed\n");
	} else {
	} else {
		amdgpu_vm_free_pts(adev, vm);
		amdgpu_vm_free_pts(adev, vm, NULL);
		amdgpu_bo_unreserve(root);
		amdgpu_bo_unreserve(root);
	}
	}
	amdgpu_bo_unref(&root);
	amdgpu_bo_unref(&root);
	WARN_ON(vm->root.base.bo);
	dma_fence_put(vm->last_update);
	dma_fence_put(vm->last_update);
	for (i = 0; i < AMDGPU_MAX_VMHUBS; i++)
	for (i = 0; i < AMDGPU_MAX_VMHUBS; i++)
		amdgpu_vmid_free_reserved(adev, vm, i);
		amdgpu_vmid_free_reserved(adev, vm, i);