1 /* $NetBSD: nouveau_vmm.c,v 1.2 2021/12/18 23:45:32 riastradh Exp $ */ 2 3 /* 4 * Copyright 2017 Red Hat Inc. 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a 7 * copy of this software and associated documentation files (the "Software"), 8 * to deal in the Software without restriction, including without limitation 9 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 * and/or sell copies of the Software, and to permit persons to whom the 11 * Software is furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be included in 14 * all copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 * OTHER DEALINGS IN THE SOFTWARE. 23 */ 24 #include <sys/cdefs.h> 25 __KERNEL_RCSID(0, "$NetBSD: nouveau_vmm.c,v 1.2 2021/12/18 23:45:32 riastradh Exp $"); 26 27 #include "nouveau_vmm.h" 28 #include "nouveau_drv.h" 29 #include "nouveau_bo.h" 30 #include "nouveau_svm.h" 31 #include "nouveau_mem.h" 32 33 void 34 nouveau_vma_unmap(struct nouveau_vma *vma) 35 { 36 if (vma->mem) { 37 nvif_vmm_unmap(&vma->vmm->vmm, vma->addr); 38 vma->mem = NULL; 39 } 40 } 41 42 int 43 nouveau_vma_map(struct nouveau_vma *vma, struct nouveau_mem *mem) 44 { 45 struct nvif_vma tmp = { .addr = vma->addr }; 46 int ret = nouveau_mem_map(mem, &vma->vmm->vmm, &tmp); 47 if (ret) 48 return ret; 49 vma->mem = mem; 50 return 0; 51 } 52 53 struct nouveau_vma * 54 nouveau_vma_find(struct nouveau_bo *nvbo, struct nouveau_vmm *vmm) 55 { 56 struct nouveau_vma *vma; 57 58 list_for_each_entry(vma, &nvbo->vma_list, head) { 59 if (vma->vmm == vmm) 60 return vma; 61 } 62 63 return NULL; 64 } 65 66 void 67 nouveau_vma_del(struct nouveau_vma **pvma) 68 { 69 struct nouveau_vma *vma = *pvma; 70 if (vma && --vma->refs <= 0) { 71 if (likely(vma->addr != ~0ULL)) { 72 struct nvif_vma tmp = { .addr = vma->addr, .size = 1 }; 73 nvif_vmm_put(&vma->vmm->vmm, &tmp); 74 } 75 list_del(&vma->head); 76 kfree(*pvma); 77 } 78 *pvma = NULL; 79 } 80 81 int 82 nouveau_vma_new(struct nouveau_bo *nvbo, struct nouveau_vmm *vmm, 83 struct nouveau_vma **pvma) 84 { 85 struct nouveau_mem *mem = nouveau_mem(&nvbo->bo.mem); 86 struct nouveau_vma *vma; 87 struct nvif_vma tmp; 88 int ret; 89 90 if ((vma = *pvma = nouveau_vma_find(nvbo, vmm))) { 91 vma->refs++; 92 return 0; 93 } 94 95 if (!(vma = *pvma = kmalloc(sizeof(*vma), GFP_KERNEL))) 96 return -ENOMEM; 97 vma->vmm = vmm; 98 vma->refs = 1; 99 vma->addr = ~0ULL; 100 vma->mem = NULL; 101 vma->fence = NULL; 102 list_add_tail(&vma->head, &nvbo->vma_list); 103 104 if (nvbo->bo.mem.mem_type != TTM_PL_SYSTEM && 105 mem->mem.page == nvbo->page) { 106 ret = nvif_vmm_get(&vmm->vmm, LAZY, false, mem->mem.page, 0, 107 mem->mem.size, &tmp); 108 if (ret) 109 goto done; 110 111 vma->addr = tmp.addr; 112 ret = nouveau_vma_map(vma, mem); 113 } else { 114 ret = nvif_vmm_get(&vmm->vmm, PTES, false, mem->mem.page, 0, 115 mem->mem.size, &tmp); 116 vma->addr = tmp.addr; 117 } 118 119 done: 120 if (ret) 121 nouveau_vma_del(pvma); 122 return ret; 123 } 124 125 void 126 nouveau_vmm_fini(struct nouveau_vmm *vmm) 127 { 128 nouveau_svmm_fini(&vmm->svmm); 129 nvif_vmm_fini(&vmm->vmm); 130 vmm->cli = NULL; 131 } 132 133 int 134 nouveau_vmm_init(struct nouveau_cli *cli, s32 oclass, struct nouveau_vmm *vmm) 135 { 136 int ret = nvif_vmm_init(&cli->mmu, oclass, false, PAGE_SIZE, 0, NULL, 0, 137 &vmm->vmm); 138 if (ret) 139 return ret; 140 141 vmm->cli = cli; 142 return 0; 143 } 144