xref: /openbmc/linux/drivers/gpu/drm/nouveau/nouveau_vmm.c (revision 7d7ae873b5e0f46d19e5dc818d1a7809e4b7cc81)
124e8375bSBen Skeggs /*
224e8375bSBen Skeggs  * Copyright 2017 Red Hat Inc.
324e8375bSBen Skeggs  *
424e8375bSBen Skeggs  * Permission is hereby granted, free of charge, to any person obtaining a
524e8375bSBen Skeggs  * copy of this software and associated documentation files (the "Software"),
624e8375bSBen Skeggs  * to deal in the Software without restriction, including without limitation
724e8375bSBen Skeggs  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
824e8375bSBen Skeggs  * and/or sell copies of the Software, and to permit persons to whom the
924e8375bSBen Skeggs  * Software is furnished to do so, subject to the following conditions:
1024e8375bSBen Skeggs  *
1124e8375bSBen Skeggs  * The above copyright notice and this permission notice shall be included in
1224e8375bSBen Skeggs  * all copies or substantial portions of the Software.
1324e8375bSBen Skeggs  *
1424e8375bSBen Skeggs  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1524e8375bSBen Skeggs  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1624e8375bSBen Skeggs  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
1724e8375bSBen Skeggs  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
1824e8375bSBen Skeggs  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
1924e8375bSBen Skeggs  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
2024e8375bSBen Skeggs  * OTHER DEALINGS IN THE SOFTWARE.
2124e8375bSBen Skeggs  */
2224e8375bSBen Skeggs #include "nouveau_vmm.h"
2324e8375bSBen Skeggs #include "nouveau_drv.h"
2424e8375bSBen Skeggs #include "nouveau_bo.h"
25eeaf06acSBen Skeggs #include "nouveau_svm.h"
2624e8375bSBen Skeggs #include "nouveau_mem.h"
2724e8375bSBen Skeggs 
2824e8375bSBen Skeggs void
nouveau_vma_unmap(struct nouveau_vma * vma)2924e8375bSBen Skeggs nouveau_vma_unmap(struct nouveau_vma *vma)
3024e8375bSBen Skeggs {
3124e8375bSBen Skeggs 	if (vma->mem) {
32d7722134SBen Skeggs 		nvif_vmm_unmap(&vma->vmm->vmm, vma->addr);
3324e8375bSBen Skeggs 		vma->mem = NULL;
3424e8375bSBen Skeggs 	}
3524e8375bSBen Skeggs }
3624e8375bSBen Skeggs 
3724e8375bSBen Skeggs int
nouveau_vma_map(struct nouveau_vma * vma,struct nouveau_mem * mem)3824e8375bSBen Skeggs nouveau_vma_map(struct nouveau_vma *vma, struct nouveau_mem *mem)
3924e8375bSBen Skeggs {
40d7722134SBen Skeggs 	struct nvif_vma tmp = { .addr = vma->addr };
41d7722134SBen Skeggs 	int ret = nouveau_mem_map(mem, &vma->vmm->vmm, &tmp);
4224e8375bSBen Skeggs 	if (ret)
4324e8375bSBen Skeggs 		return ret;
4424e8375bSBen Skeggs 	vma->mem = mem;
4524e8375bSBen Skeggs 	return 0;
4624e8375bSBen Skeggs }
4724e8375bSBen Skeggs 
4824e8375bSBen Skeggs struct nouveau_vma *
nouveau_vma_find(struct nouveau_bo * nvbo,struct nouveau_vmm * vmm)4924e8375bSBen Skeggs nouveau_vma_find(struct nouveau_bo *nvbo, struct nouveau_vmm *vmm)
5024e8375bSBen Skeggs {
5124e8375bSBen Skeggs 	struct nouveau_vma *vma;
5224e8375bSBen Skeggs 
5324e8375bSBen Skeggs 	list_for_each_entry(vma, &nvbo->vma_list, head) {
5424e8375bSBen Skeggs 		if (vma->vmm == vmm)
5524e8375bSBen Skeggs 			return vma;
5624e8375bSBen Skeggs 	}
5724e8375bSBen Skeggs 
5824e8375bSBen Skeggs 	return NULL;
5924e8375bSBen Skeggs }
6024e8375bSBen Skeggs 
6124e8375bSBen Skeggs void
nouveau_vma_del(struct nouveau_vma ** pvma)6224e8375bSBen Skeggs nouveau_vma_del(struct nouveau_vma **pvma)
6324e8375bSBen Skeggs {
6424e8375bSBen Skeggs 	struct nouveau_vma *vma = *pvma;
6524e8375bSBen Skeggs 	if (vma && --vma->refs <= 0) {
66d7722134SBen Skeggs 		if (likely(vma->addr != ~0ULL)) {
67d7722134SBen Skeggs 			struct nvif_vma tmp = { .addr = vma->addr, .size = 1 };
68d7722134SBen Skeggs 			nvif_vmm_put(&vma->vmm->vmm, &tmp);
69d7722134SBen Skeggs 		}
7024e8375bSBen Skeggs 		list_del(&vma->head);
7124e8375bSBen Skeggs 		kfree(*pvma);
7224e8375bSBen Skeggs 	}
734c9ee1bfSBen Skeggs 	*pvma = NULL;
7424e8375bSBen Skeggs }
7524e8375bSBen Skeggs 
7624e8375bSBen Skeggs int
nouveau_vma_new(struct nouveau_bo * nvbo,struct nouveau_vmm * vmm,struct nouveau_vma ** pvma)7724e8375bSBen Skeggs nouveau_vma_new(struct nouveau_bo *nvbo, struct nouveau_vmm *vmm,
7824e8375bSBen Skeggs 		struct nouveau_vma **pvma)
7924e8375bSBen Skeggs {
80d3116756SChristian König 	struct nouveau_mem *mem = nouveau_mem(nvbo->bo.resource);
8124e8375bSBen Skeggs 	struct nouveau_vma *vma;
82d7722134SBen Skeggs 	struct nvif_vma tmp;
8324e8375bSBen Skeggs 	int ret;
8424e8375bSBen Skeggs 
8524e8375bSBen Skeggs 	if ((vma = *pvma = nouveau_vma_find(nvbo, vmm))) {
8624e8375bSBen Skeggs 		vma->refs++;
8724e8375bSBen Skeggs 		return 0;
8824e8375bSBen Skeggs 	}
8924e8375bSBen Skeggs 
9024e8375bSBen Skeggs 	if (!(vma = *pvma = kmalloc(sizeof(*vma), GFP_KERNEL)))
9124e8375bSBen Skeggs 		return -ENOMEM;
9224e8375bSBen Skeggs 	vma->vmm = vmm;
9324e8375bSBen Skeggs 	vma->refs = 1;
9424e8375bSBen Skeggs 	vma->addr = ~0ULL;
9524e8375bSBen Skeggs 	vma->mem = NULL;
960db912afSBen Skeggs 	vma->fence = NULL;
9724e8375bSBen Skeggs 	list_add_tail(&vma->head, &nvbo->vma_list);
9824e8375bSBen Skeggs 
99d3116756SChristian König 	if (nvbo->bo.resource->mem_type != TTM_PL_SYSTEM &&
10024e8375bSBen Skeggs 	    mem->mem.page == nvbo->page) {
101d7722134SBen Skeggs 		ret = nvif_vmm_get(&vmm->vmm, LAZY, false, mem->mem.page, 0,
102d7722134SBen Skeggs 				   mem->mem.size, &tmp);
10324e8375bSBen Skeggs 		if (ret)
10424e8375bSBen Skeggs 			goto done;
10524e8375bSBen Skeggs 
106d7722134SBen Skeggs 		vma->addr = tmp.addr;
10724e8375bSBen Skeggs 		ret = nouveau_vma_map(vma, mem);
10824e8375bSBen Skeggs 	} else {
109d7722134SBen Skeggs 		ret = nvif_vmm_get(&vmm->vmm, PTES, false, mem->mem.page, 0,
110d7722134SBen Skeggs 				   mem->mem.size, &tmp);
111*ce513692SDave Airlie 		if (ret)
112*ce513692SDave Airlie 			goto done;
113*ce513692SDave Airlie 
114d7722134SBen Skeggs 		vma->addr = tmp.addr;
11524e8375bSBen Skeggs 	}
11624e8375bSBen Skeggs 
11724e8375bSBen Skeggs done:
11824e8375bSBen Skeggs 	if (ret)
11924e8375bSBen Skeggs 		nouveau_vma_del(pvma);
12024e8375bSBen Skeggs 	return ret;
12124e8375bSBen Skeggs }
12224e8375bSBen Skeggs 
12324e8375bSBen Skeggs void
nouveau_vmm_fini(struct nouveau_vmm * vmm)12424e8375bSBen Skeggs nouveau_vmm_fini(struct nouveau_vmm *vmm)
12524e8375bSBen Skeggs {
126eeaf06acSBen Skeggs 	nouveau_svmm_fini(&vmm->svmm);
12745faf3d7SBen Skeggs 	nvif_vmm_dtor(&vmm->vmm);
12896da0bcdSBen Skeggs 	vmm->cli = NULL;
12924e8375bSBen Skeggs }
13024e8375bSBen Skeggs 
13124e8375bSBen Skeggs int
nouveau_vmm_init(struct nouveau_cli * cli,s32 oclass,struct nouveau_vmm * vmm)13224e8375bSBen Skeggs nouveau_vmm_init(struct nouveau_cli *cli, s32 oclass, struct nouveau_vmm *vmm)
13324e8375bSBen Skeggs {
1346b252cf4SDanilo Krummrich 	int ret = nvif_vmm_ctor(&cli->mmu, "drmVmm", oclass, UNMANAGED,
1356b252cf4SDanilo Krummrich 				PAGE_SIZE, 0, NULL, 0, &vmm->vmm);
13696da0bcdSBen Skeggs 	if (ret)
13796da0bcdSBen Skeggs 		return ret;
13896da0bcdSBen Skeggs 
13924e8375bSBen Skeggs 	vmm->cli = cli;
14096da0bcdSBen Skeggs 	return 0;
14124e8375bSBen Skeggs }
142