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