Commit 806a7335 authored by Ben Skeggs's avatar Ben Skeggs
Browse files

drm/nouveau/mmu: implement base for new vm management



This is the first chunk of the new VMM code that provides the structures
needed to describe a GPU virtual address-space layout, as well as common
interfaces to handle VMM creation, and connecting instances to a VMM.

The constructor now allocates the PD itself, rather than having the user
handle that manually.  This won't/can't be used until after all backends
have been ported to these interfaces, so a little bit of memory will be
wasted on Fermi and newer for a couple of commits in the series.

Compatibility has been hacked into the old code to allow each GPU backend
to be ported individually.

Signed-off-by: default avatarBen Skeggs <bskeggs@redhat.com>
parent f1280394
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -14,6 +14,8 @@
#define NVIF_CLASS_SW_NV50                           /* if0005.h */ -0x00000006
#define NVIF_CLASS_SW_GF100                          /* if0005.h */ -0x00000007

#define NVIF_CLASS_VMM                               /* if000c.h */  0x0000000c

/* the below match nvidia-assigned (either in hw, or sw) class numbers */
#define NV_NULL_CLASS                                                0x00000030

+3 −0
Original line number Diff line number Diff line
#ifndef __NVIF_IF000C_H__
#define __NVIF_IF000C_H__
#endif
+12 −4
Original line number Diff line number Diff line
@@ -26,20 +26,28 @@ struct nvkm_vma {
};

struct nvkm_vm {
	const struct nvkm_vmm_func *func;
	struct nvkm_mmu *mmu;

	const char *name;
	struct kref kref;
	struct mutex mutex;

	u64 start;
	u64 limit;

	struct nvkm_vmm_pt *pd;
	u16 pd_offset;
	struct list_head join;

	struct nvkm_mm mm;
	struct kref refcount;

	struct list_head pgd_list;
	atomic_t engref[NVKM_SUBDEV_NR];

	struct nvkm_vm_pgt *pgt;
	u32 fpde;
	u32 lpde;

	bool bootstrapped;
	atomic_t engref[NVKM_SUBDEV_NR];
};

int  nvkm_vm_new(struct nvkm_device *, u64 offset, u64 length, u64 mm_offset,
+2 −0
Original line number Diff line number Diff line
@@ -11,3 +11,5 @@ nvkm-y += nvkm/subdev/mmu/gm200.o
nvkm-y += nvkm/subdev/mmu/gm20b.o
nvkm-y += nvkm/subdev/mmu/gp100.o
nvkm-y += nvkm/subdev/mmu/gp10b.o

nvkm-y += nvkm/subdev/mmu/vmm.o
+64 −12
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@
 * Authors: Ben Skeggs
 */
#include "priv.h"
#include "vmm.h"

#include <core/gpuobj.h>
#include <subdev/fb.h>
@@ -584,22 +585,14 @@ nvkm_vm_boot(struct nvkm_vm *vm, u64 size)
	return ret;
}

int
nvkm_vm_create(struct nvkm_mmu *mmu, u64 offset, u64 length, u64 mm_offset,
	       u32 block, struct lock_class_key *key, struct nvkm_vm **pvm)
static int
nvkm_vm_legacy(struct nvkm_mmu *mmu, u64 offset, u64 length, u64 mm_offset,
	       u32 block, struct nvkm_vm *vm)
{
	static struct lock_class_key _key;
	struct nvkm_vm *vm;
	u64 mm_length = (offset + length) - mm_offset;
	int ret;

	vm = kzalloc(sizeof(*vm), GFP_KERNEL);
	if (!vm)
		return -ENOMEM;

	__mutex_init(&vm->mutex, "&vm->mutex", key ? key : &_key);
	INIT_LIST_HEAD(&vm->pgd_list);
	vm->mmu = mmu;
	kref_init(&vm->refcount);
	vm->fpde = offset >> (mmu->func->pgt_bits + 12);
	vm->lpde = (offset + length - 1) >> (mmu->func->pgt_bits + 12);
@@ -610,16 +603,41 @@ nvkm_vm_create(struct nvkm_mmu *mmu, u64 offset, u64 length, u64 mm_offset,
		return -ENOMEM;
	}

	if (block > length)
		block = length;

	ret = nvkm_mm_init(&vm->mm, 0, mm_offset >> 12, mm_length >> 12,
			   block >> 12);
	if (ret) {
		vfree(vm->pgt);
		return ret;
	}

	return 0;
}

int
nvkm_vm_create(struct nvkm_mmu *mmu, u64 offset, u64 length, u64 mm_offset,
	       u32 block, struct lock_class_key *key, struct nvkm_vm **pvm)
{
	static struct lock_class_key _key;
	struct nvkm_vm *vm;
	int ret;

	vm = kzalloc(sizeof(*vm), GFP_KERNEL);
	if (!vm)
		return -ENOMEM;

	__mutex_init(&vm->mutex, "&vm->mutex", key ? key : &_key);
	vm->mmu = mmu;

	ret = nvkm_vm_legacy(mmu, offset, length, mm_offset, block, vm);
	if (ret) {
		kfree(vm);
		return ret;
	}

	*pvm = vm;

	return 0;
}

@@ -628,8 +646,29 @@ nvkm_vm_new(struct nvkm_device *device, u64 offset, u64 length, u64 mm_offset,
	    struct lock_class_key *key, struct nvkm_vm **pvm)
{
	struct nvkm_mmu *mmu = device->mmu;

	*pvm = NULL;
	if (mmu->func->vmm.ctor) {
		int ret = mmu->func->vmm.ctor(mmu, mm_offset,
					      offset + length - mm_offset,
					      NULL, 0, key, "legacy", pvm);
		if (ret) {
			nvkm_vm_ref(NULL, pvm, NULL);
			return ret;
		}

		ret = nvkm_vm_legacy(mmu, offset, length, mm_offset,
				     (*pvm)->func->page_block ?
				     (*pvm)->func->page_block : 4096, *pvm);
		if (ret)
			nvkm_vm_ref(NULL, pvm, NULL);

		return ret;
	}

	if (!mmu->func->create)
		return -EINVAL;

	return mmu->func->create(mmu, offset, length, mm_offset, key, pvm);
}

@@ -688,6 +727,9 @@ nvkm_vm_del(struct kref *kref)

	nvkm_mm_fini(&vm->mm);
	vfree(vm->pgt);

	if (vm->func)
		nvkm_vmm_dtor(vm);
	kfree(vm);
}

@@ -717,8 +759,17 @@ static int
nvkm_mmu_oneinit(struct nvkm_subdev *subdev)
{
	struct nvkm_mmu *mmu = nvkm_mmu(subdev);

	if (mmu->func->vmm.global) {
		int ret = nvkm_vm_new(subdev->device, 0, mmu->limit, 0,
				      NULL, &mmu->vmm);
		if (ret)
			return ret;
	}

	if (mmu->func->oneinit)
		return mmu->func->oneinit(mmu);

	return 0;
}

@@ -739,6 +790,7 @@ nvkm_mmu_dtor(struct nvkm_subdev *subdev)

	if (mmu->func->dtor)
		data = mmu->func->dtor(mmu);
	nvkm_vm_ref(NULL, &mmu->vmm, NULL);

	nvkm_mmu_ptc_fini(mmu);
	return data;
Loading