1 /* $NetBSD: nouveau_mem.c,v 1.3 2021/12/19 10:51:56 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_mem.c,v 1.3 2021/12/19 10:51:56 riastradh Exp $"); 26 27 #include "nouveau_mem.h" 28 #include "nouveau_drv.h" 29 #include "nouveau_bo.h" 30 31 #include <drm/ttm/ttm_bo_driver.h> 32 33 #include <nvif/class.h> 34 #include <nvif/if000a.h> 35 #include <nvif/if500b.h> 36 #include <nvif/if500d.h> 37 #include <nvif/if900b.h> 38 #include <nvif/if900d.h> 39 40 #include <linux/nbsd-namespace.h> 41 42 int 43 nouveau_mem_map(struct nouveau_mem *mem, 44 struct nvif_vmm *vmm, struct nvif_vma *vma) 45 { 46 union { 47 struct nv50_vmm_map_v0 nv50; 48 struct gf100_vmm_map_v0 gf100; 49 } args; 50 u32 argc = 0; 51 bool super; 52 int ret; 53 54 switch (vmm->object.oclass) { 55 case NVIF_CLASS_VMM_NV04: 56 break; 57 case NVIF_CLASS_VMM_NV50: 58 args.nv50.version = 0; 59 args.nv50.ro = 0; 60 args.nv50.priv = 0; 61 args.nv50.kind = mem->kind; 62 args.nv50.comp = mem->comp; 63 argc = sizeof(args.nv50); 64 break; 65 case NVIF_CLASS_VMM_GF100: 66 case NVIF_CLASS_VMM_GM200: 67 case NVIF_CLASS_VMM_GP100: 68 args.gf100.version = 0; 69 if (mem->mem.type & NVIF_MEM_VRAM) 70 args.gf100.vol = 0; 71 else 72 args.gf100.vol = 1; 73 args.gf100.ro = 0; 74 args.gf100.priv = 0; 75 args.gf100.kind = mem->kind; 76 argc = sizeof(args.gf100); 77 break; 78 default: 79 WARN_ON(1); 80 return -ENOSYS; 81 } 82 83 super = vmm->object.client->super; 84 vmm->object.client->super = true; 85 ret = nvif_vmm_map(vmm, vma->addr, mem->mem.size, &args, argc, 86 &mem->mem, 0); 87 vmm->object.client->super = super; 88 return ret; 89 } 90 91 void 92 nouveau_mem_fini(struct nouveau_mem *mem) 93 { 94 nvif_vmm_put(&mem->cli->drm->client.vmm.vmm, &mem->vma[1]); 95 nvif_vmm_put(&mem->cli->drm->client.vmm.vmm, &mem->vma[0]); 96 mutex_lock(&mem->cli->drm->master.lock); 97 nvif_mem_fini(&mem->mem); 98 mutex_unlock(&mem->cli->drm->master.lock); 99 } 100 101 int 102 nouveau_mem_host(struct ttm_mem_reg *reg, struct ttm_dma_tt *tt) 103 { 104 struct nouveau_mem *mem = nouveau_mem(reg); 105 struct nouveau_cli *cli = mem->cli; 106 struct nouveau_drm *drm = cli->drm; 107 struct nvif_mmu *mmu = &cli->mmu; 108 struct nvif_mem_ram_v0 args = {}; 109 bool super = cli->base.super; 110 u8 type; 111 int ret; 112 113 if (!nouveau_drm_use_coherent_gpu_mapping(drm)) 114 type = drm->ttm.type_ncoh[!!mem->kind]; 115 else 116 type = drm->ttm.type_host[0]; 117 118 if (mem->kind && !(mmu->type[type].type & NVIF_MEM_KIND)) 119 mem->comp = mem->kind = 0; 120 if (mem->comp && !(mmu->type[type].type & NVIF_MEM_COMP)) { 121 if (mmu->object.oclass >= NVIF_CLASS_MMU_GF100) 122 mem->kind = mmu->kind[mem->kind]; 123 mem->comp = 0; 124 } 125 126 #ifdef __NetBSD__ /* XXX prime */ 127 args.dma = tt->dma_address; 128 #else 129 if (tt->ttm.sg) args.sgl = tt->ttm.sg->sgl; 130 else args.dma = tt->dma_address; 131 #endif 132 133 mutex_lock(&drm->master.lock); 134 cli->base.super = true; 135 ret = nvif_mem_init_type(mmu, cli->mem->oclass, type, PAGE_SHIFT, 136 reg->num_pages << PAGE_SHIFT, 137 &args, sizeof(args), &mem->mem); 138 cli->base.super = super; 139 mutex_unlock(&drm->master.lock); 140 return ret; 141 } 142 143 int 144 nouveau_mem_vram(struct ttm_mem_reg *reg, bool contig, u8 page) 145 { 146 struct nouveau_mem *mem = nouveau_mem(reg); 147 struct nouveau_cli *cli = mem->cli; 148 struct nouveau_drm *drm = cli->drm; 149 struct nvif_mmu *mmu = &cli->mmu; 150 bool super = cli->base.super; 151 u64 size = ALIGN(reg->num_pages << PAGE_SHIFT, 1 << page); 152 int ret; 153 154 mutex_lock(&drm->master.lock); 155 cli->base.super = true; 156 switch (cli->mem->oclass) { 157 case NVIF_CLASS_MEM_GF100: 158 ret = nvif_mem_init_type(mmu, cli->mem->oclass, 159 drm->ttm.type_vram, page, size, 160 &(struct gf100_mem_v0) { 161 .contig = contig, 162 }, sizeof(struct gf100_mem_v0), 163 &mem->mem); 164 break; 165 case NVIF_CLASS_MEM_NV50: 166 ret = nvif_mem_init_type(mmu, cli->mem->oclass, 167 drm->ttm.type_vram, page, size, 168 &(struct nv50_mem_v0) { 169 .bankswz = mmu->kind[mem->kind] == 2, 170 .contig = contig, 171 }, sizeof(struct nv50_mem_v0), 172 &mem->mem); 173 break; 174 default: 175 ret = -ENOSYS; 176 WARN_ON(1); 177 break; 178 } 179 cli->base.super = super; 180 mutex_unlock(&drm->master.lock); 181 182 reg->start = mem->mem.addr >> PAGE_SHIFT; 183 return ret; 184 } 185 186 void 187 nouveau_mem_del(struct ttm_mem_reg *reg) 188 { 189 struct nouveau_mem *mem = nouveau_mem(reg); 190 nouveau_mem_fini(mem); 191 kfree(reg->mm_node); 192 reg->mm_node = NULL; 193 } 194 195 int 196 nouveau_mem_new(struct nouveau_cli *cli, u8 kind, u8 comp, 197 struct ttm_mem_reg *reg) 198 { 199 struct nouveau_mem *mem; 200 201 if (!(mem = kzalloc(sizeof(*mem), GFP_KERNEL))) 202 return -ENOMEM; 203 mem->cli = cli; 204 mem->kind = kind; 205 mem->comp = comp; 206 207 reg->mm_node = mem; 208 return 0; 209 } 210