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