1 1.10 riastrad /* $NetBSD: nouveau_ttm.c,v 1.10 2022/05/21 17:50:21 riastradh Exp $ */ 2 1.2 riastrad 3 1.8 riastrad // SPDX-License-Identifier: GPL-2.0 OR MIT 4 1.1 riastrad /* 5 1.1 riastrad * Copyright (c) 2007-2008 Tungsten Graphics, Inc., Cedar Park, TX., USA, 6 1.1 riastrad * Copyright (c) 2009 VMware, Inc., Palo Alto, CA., USA, 7 1.1 riastrad * 8 1.1 riastrad * Permission is hereby granted, free of charge, to any person obtaining a 9 1.1 riastrad * copy of this software and associated documentation files (the "Software"), 10 1.1 riastrad * to deal in the Software without restriction, including without limitation 11 1.1 riastrad * the rights to use, copy, modify, merge, publish, distribute, sub license, 12 1.1 riastrad * and/or sell copies of the Software, and to permit persons to whom the 13 1.1 riastrad * Software is furnished to do so, subject to the following conditions: 14 1.1 riastrad * 15 1.1 riastrad * The above copyright notice and this permission notice (including the 16 1.1 riastrad * next paragraph) shall be included in all copies or substantial portions 17 1.1 riastrad * of the Software. 18 1.1 riastrad * 19 1.1 riastrad * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 1.1 riastrad * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 1.1 riastrad * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 22 1.1 riastrad * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, 23 1.1 riastrad * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 24 1.1 riastrad * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 25 1.1 riastrad * USE OR OTHER DEALINGS IN THE SOFTWARE. 26 1.1 riastrad */ 27 1.2 riastrad #include <sys/cdefs.h> 28 1.10 riastrad __KERNEL_RCSID(0, "$NetBSD: nouveau_ttm.c,v 1.10 2022/05/21 17:50:21 riastradh Exp $"); 29 1.1 riastrad 30 1.6 riastrad #include <sys/param.h> 31 1.6 riastrad #include <uvm/uvm_extern.h> /* pmap_pv_track/untrack */ 32 1.6 riastrad 33 1.8 riastrad #include "nouveau_drv.h" 34 1.8 riastrad #include "nouveau_gem.h" 35 1.8 riastrad #include "nouveau_mem.h" 36 1.1 riastrad #include "nouveau_ttm.h" 37 1.1 riastrad 38 1.8 riastrad #include <drm/drm_legacy.h> 39 1.5 riastrad 40 1.5 riastrad #include <core/tegra.h> 41 1.5 riastrad 42 1.1 riastrad static int 43 1.8 riastrad nouveau_manager_init(struct ttm_mem_type_manager *man, unsigned long psize) 44 1.1 riastrad { 45 1.1 riastrad return 0; 46 1.1 riastrad } 47 1.1 riastrad 48 1.1 riastrad static int 49 1.8 riastrad nouveau_manager_fini(struct ttm_mem_type_manager *man) 50 1.1 riastrad { 51 1.1 riastrad return 0; 52 1.1 riastrad } 53 1.1 riastrad 54 1.8 riastrad static void 55 1.8 riastrad nouveau_manager_del(struct ttm_mem_type_manager *man, struct ttm_mem_reg *reg) 56 1.1 riastrad { 57 1.8 riastrad nouveau_mem_del(reg); 58 1.1 riastrad } 59 1.1 riastrad 60 1.1 riastrad static void 61 1.8 riastrad nouveau_manager_debug(struct ttm_mem_type_manager *man, 62 1.8 riastrad struct drm_printer *printer) 63 1.1 riastrad { 64 1.1 riastrad } 65 1.1 riastrad 66 1.1 riastrad static int 67 1.1 riastrad nouveau_vram_manager_new(struct ttm_mem_type_manager *man, 68 1.1 riastrad struct ttm_buffer_object *bo, 69 1.5 riastrad const struct ttm_place *place, 70 1.8 riastrad struct ttm_mem_reg *reg) 71 1.1 riastrad { 72 1.1 riastrad struct nouveau_bo *nvbo = nouveau_bo(bo); 73 1.8 riastrad struct nouveau_drm *drm = nouveau_bdev(bo->bdev); 74 1.1 riastrad int ret; 75 1.1 riastrad 76 1.8 riastrad if (drm->client.device.info.ram_size == 0) 77 1.5 riastrad return -ENOMEM; 78 1.5 riastrad 79 1.8 riastrad ret = nouveau_mem_new(&drm->master, nvbo->kind, nvbo->comp, reg); 80 1.8 riastrad if (ret) 81 1.8 riastrad return ret; 82 1.1 riastrad 83 1.8 riastrad ret = nouveau_mem_vram(reg, nvbo->contig, nvbo->page); 84 1.1 riastrad if (ret) { 85 1.8 riastrad nouveau_mem_del(reg); 86 1.8 riastrad if (ret == -ENOSPC) { 87 1.8 riastrad reg->mm_node = NULL; 88 1.8 riastrad return 0; 89 1.8 riastrad } 90 1.8 riastrad return ret; 91 1.1 riastrad } 92 1.1 riastrad 93 1.1 riastrad return 0; 94 1.1 riastrad } 95 1.1 riastrad 96 1.1 riastrad const struct ttm_mem_type_manager_func nouveau_vram_manager = { 97 1.8 riastrad .init = nouveau_manager_init, 98 1.8 riastrad .takedown = nouveau_manager_fini, 99 1.8 riastrad .get_node = nouveau_vram_manager_new, 100 1.8 riastrad .put_node = nouveau_manager_del, 101 1.8 riastrad .debug = nouveau_manager_debug, 102 1.1 riastrad }; 103 1.1 riastrad 104 1.1 riastrad static int 105 1.1 riastrad nouveau_gart_manager_new(struct ttm_mem_type_manager *man, 106 1.1 riastrad struct ttm_buffer_object *bo, 107 1.5 riastrad const struct ttm_place *place, 108 1.8 riastrad struct ttm_mem_reg *reg) 109 1.1 riastrad { 110 1.8 riastrad struct nouveau_bo *nvbo = nouveau_bo(bo); 111 1.1 riastrad struct nouveau_drm *drm = nouveau_bdev(bo->bdev); 112 1.8 riastrad int ret; 113 1.1 riastrad 114 1.8 riastrad ret = nouveau_mem_new(&drm->master, nvbo->kind, nvbo->comp, reg); 115 1.8 riastrad if (ret) 116 1.8 riastrad return ret; 117 1.1 riastrad 118 1.8 riastrad reg->start = 0; 119 1.1 riastrad return 0; 120 1.1 riastrad } 121 1.1 riastrad 122 1.1 riastrad const struct ttm_mem_type_manager_func nouveau_gart_manager = { 123 1.8 riastrad .init = nouveau_manager_init, 124 1.8 riastrad .takedown = nouveau_manager_fini, 125 1.8 riastrad .get_node = nouveau_gart_manager_new, 126 1.8 riastrad .put_node = nouveau_manager_del, 127 1.8 riastrad .debug = nouveau_manager_debug 128 1.1 riastrad }; 129 1.1 riastrad 130 1.1 riastrad static int 131 1.1 riastrad nv04_gart_manager_new(struct ttm_mem_type_manager *man, 132 1.1 riastrad struct ttm_buffer_object *bo, 133 1.5 riastrad const struct ttm_place *place, 134 1.8 riastrad struct ttm_mem_reg *reg) 135 1.1 riastrad { 136 1.8 riastrad struct nouveau_bo *nvbo = nouveau_bo(bo); 137 1.8 riastrad struct nouveau_drm *drm = nouveau_bdev(bo->bdev); 138 1.8 riastrad struct nouveau_mem *mem; 139 1.1 riastrad int ret; 140 1.1 riastrad 141 1.8 riastrad ret = nouveau_mem_new(&drm->master, nvbo->kind, nvbo->comp, reg); 142 1.8 riastrad mem = nouveau_mem(reg); 143 1.8 riastrad if (ret) 144 1.8 riastrad return ret; 145 1.1 riastrad 146 1.8 riastrad ret = nvif_vmm_get(&mem->cli->vmm.vmm, PTES, false, 12, 0, 147 1.8 riastrad reg->num_pages << PAGE_SHIFT, &mem->vma[0]); 148 1.1 riastrad if (ret) { 149 1.8 riastrad nouveau_mem_del(reg); 150 1.8 riastrad if (ret == -ENOSPC) { 151 1.8 riastrad reg->mm_node = NULL; 152 1.8 riastrad return 0; 153 1.8 riastrad } 154 1.1 riastrad return ret; 155 1.1 riastrad } 156 1.1 riastrad 157 1.8 riastrad reg->start = mem->vma[0].addr >> PAGE_SHIFT; 158 1.1 riastrad return 0; 159 1.1 riastrad } 160 1.1 riastrad 161 1.1 riastrad const struct ttm_mem_type_manager_func nv04_gart_manager = { 162 1.8 riastrad .init = nouveau_manager_init, 163 1.8 riastrad .takedown = nouveau_manager_fini, 164 1.8 riastrad .get_node = nv04_gart_manager_new, 165 1.8 riastrad .put_node = nouveau_manager_del, 166 1.8 riastrad .debug = nouveau_manager_debug 167 1.1 riastrad }; 168 1.1 riastrad 169 1.3 riastrad #ifdef __NetBSD__ 170 1.3 riastrad 171 1.3 riastrad int 172 1.3 riastrad nouveau_ttm_mmap_object(struct drm_device *dev, off_t offset, size_t size, 173 1.3 riastrad vm_prot_t prot, struct uvm_object **uobjp, voff_t *uoffsetp, 174 1.3 riastrad struct file *file) 175 1.3 riastrad { 176 1.3 riastrad struct nouveau_drm *const drm = nouveau_drm(dev); 177 1.3 riastrad 178 1.3 riastrad KASSERT(0 == (offset & (PAGE_SIZE - 1))); 179 1.3 riastrad 180 1.10 riastrad return ttm_bo_mmap_object(&drm->ttm.bdev, offset, size, prot, 181 1.10 riastrad uobjp, uoffsetp, file); 182 1.3 riastrad } 183 1.3 riastrad 184 1.3 riastrad #else 185 1.3 riastrad 186 1.1 riastrad int 187 1.1 riastrad nouveau_ttm_mmap(struct file *filp, struct vm_area_struct *vma) 188 1.1 riastrad { 189 1.1 riastrad struct drm_file *file_priv = filp->private_data; 190 1.1 riastrad struct nouveau_drm *drm = nouveau_drm(file_priv->minor->dev); 191 1.1 riastrad 192 1.1 riastrad return ttm_bo_mmap(filp, vma, &drm->ttm.bdev); 193 1.1 riastrad } 194 1.1 riastrad 195 1.3 riastrad #endif 196 1.3 riastrad 197 1.1 riastrad static int 198 1.8 riastrad nouveau_ttm_init_host(struct nouveau_drm *drm, u8 kind) 199 1.1 riastrad { 200 1.8 riastrad struct nvif_mmu *mmu = &drm->client.mmu; 201 1.8 riastrad int typei; 202 1.1 riastrad 203 1.8 riastrad typei = nvif_mmu_type(mmu, NVIF_MEM_HOST | NVIF_MEM_MAPPABLE | 204 1.8 riastrad kind | NVIF_MEM_COHERENT); 205 1.8 riastrad if (typei < 0) 206 1.8 riastrad return -ENOSYS; 207 1.1 riastrad 208 1.8 riastrad drm->ttm.type_host[!!kind] = typei; 209 1.1 riastrad 210 1.8 riastrad typei = nvif_mmu_type(mmu, NVIF_MEM_HOST | NVIF_MEM_MAPPABLE | kind); 211 1.8 riastrad if (typei < 0) 212 1.8 riastrad return -ENOSYS; 213 1.1 riastrad 214 1.8 riastrad drm->ttm.type_ncoh[!!kind] = typei; 215 1.1 riastrad return 0; 216 1.1 riastrad } 217 1.1 riastrad 218 1.1 riastrad int 219 1.1 riastrad nouveau_ttm_init(struct nouveau_drm *drm) 220 1.1 riastrad { 221 1.8 riastrad struct nvkm_device *device = nvxx_device(&drm->client.device); 222 1.5 riastrad struct nvkm_pci *pci = device->pci; 223 1.8 riastrad struct nvif_mmu *mmu = &drm->client.mmu; 224 1.1 riastrad struct drm_device *dev = drm->dev; 225 1.8 riastrad int typei, ret; 226 1.8 riastrad 227 1.8 riastrad ret = nouveau_ttm_init_host(drm, 0); 228 1.8 riastrad if (ret) 229 1.8 riastrad return ret; 230 1.8 riastrad 231 1.8 riastrad if (drm->client.device.info.family >= NV_DEVICE_INFO_V0_TESLA && 232 1.8 riastrad drm->client.device.info.chipset != 0x50) { 233 1.8 riastrad ret = nouveau_ttm_init_host(drm, NVIF_MEM_KIND); 234 1.8 riastrad if (ret) 235 1.8 riastrad return ret; 236 1.8 riastrad } 237 1.8 riastrad 238 1.8 riastrad if (drm->client.device.info.platform != NV_DEVICE_INFO_V0_SOC && 239 1.8 riastrad drm->client.device.info.family >= NV_DEVICE_INFO_V0_TESLA) { 240 1.8 riastrad typei = nvif_mmu_type(mmu, NVIF_MEM_VRAM | NVIF_MEM_MAPPABLE | 241 1.8 riastrad NVIF_MEM_KIND | 242 1.8 riastrad NVIF_MEM_COMP | 243 1.8 riastrad NVIF_MEM_DISP); 244 1.8 riastrad if (typei < 0) 245 1.8 riastrad return -ENOSYS; 246 1.8 riastrad 247 1.8 riastrad drm->ttm.type_vram = typei; 248 1.8 riastrad } else { 249 1.8 riastrad drm->ttm.type_vram = -1; 250 1.8 riastrad } 251 1.1 riastrad 252 1.5 riastrad if (pci && pci->agp.bridge) { 253 1.5 riastrad drm->agp.bridge = pci->agp.bridge; 254 1.5 riastrad drm->agp.base = pci->agp.base; 255 1.5 riastrad drm->agp.size = pci->agp.size; 256 1.5 riastrad drm->agp.cma = pci->agp.cma; 257 1.5 riastrad } 258 1.5 riastrad 259 1.1 riastrad ret = ttm_bo_device_init(&drm->ttm.bdev, 260 1.1 riastrad &nouveau_bo_driver, 261 1.2 riastrad #ifdef __NetBSD__ 262 1.2 riastrad dev->bst, 263 1.2 riastrad dev->dmat, 264 1.2 riastrad #else 265 1.1 riastrad dev->anon_inode->i_mapping, 266 1.2 riastrad #endif 267 1.8 riastrad dev->vma_offset_manager, 268 1.8 riastrad drm->client.mmu.dmabits <= 32 ? true : false); 269 1.1 riastrad if (ret) { 270 1.1 riastrad NV_ERROR(drm, "error initialising bo driver, %d\n", ret); 271 1.1 riastrad return ret; 272 1.1 riastrad } 273 1.1 riastrad 274 1.1 riastrad /* VRAM init */ 275 1.8 riastrad drm->gem.vram_available = drm->client.device.info.ram_user; 276 1.8 riastrad 277 1.8 riastrad arch_io_reserve_memtype_wc(device->func->resource_addr(device, 1), 278 1.8 riastrad device->func->resource_size(device, 1)); 279 1.1 riastrad 280 1.1 riastrad ret = ttm_bo_init_mm(&drm->ttm.bdev, TTM_PL_VRAM, 281 1.1 riastrad drm->gem.vram_available >> PAGE_SHIFT); 282 1.1 riastrad if (ret) { 283 1.1 riastrad NV_ERROR(drm, "VRAM mm init failed, %d\n", ret); 284 1.1 riastrad return ret; 285 1.1 riastrad } 286 1.1 riastrad 287 1.5 riastrad drm->ttm.mtrr = arch_phys_wc_add(device->func->resource_addr(device, 1), 288 1.5 riastrad device->func->resource_size(device, 1)); 289 1.1 riastrad 290 1.4 riastrad #ifdef __NetBSD__ 291 1.6 riastrad pmap_pv_track(device->func->resource_addr(device, 1), 292 1.6 riastrad device->func->resource_size(device, 1)); 293 1.4 riastrad #endif 294 1.4 riastrad 295 1.1 riastrad /* GART init */ 296 1.5 riastrad if (!drm->agp.bridge) { 297 1.8 riastrad drm->gem.gart_available = drm->client.vmm.vmm.limit; 298 1.1 riastrad } else { 299 1.1 riastrad drm->gem.gart_available = drm->agp.size; 300 1.1 riastrad } 301 1.1 riastrad 302 1.1 riastrad ret = ttm_bo_init_mm(&drm->ttm.bdev, TTM_PL_TT, 303 1.1 riastrad drm->gem.gart_available >> PAGE_SHIFT); 304 1.1 riastrad if (ret) { 305 1.1 riastrad NV_ERROR(drm, "GART mm init failed, %d\n", ret); 306 1.1 riastrad return ret; 307 1.1 riastrad } 308 1.1 riastrad 309 1.1 riastrad NV_INFO(drm, "VRAM: %d MiB\n", (u32)(drm->gem.vram_available >> 20)); 310 1.1 riastrad NV_INFO(drm, "GART: %d MiB\n", (u32)(drm->gem.gart_available >> 20)); 311 1.1 riastrad return 0; 312 1.1 riastrad } 313 1.1 riastrad 314 1.1 riastrad void 315 1.1 riastrad nouveau_ttm_fini(struct nouveau_drm *drm) 316 1.1 riastrad { 317 1.8 riastrad struct nvkm_device *device = nvxx_device(&drm->client.device); 318 1.8 riastrad 319 1.1 riastrad ttm_bo_clean_mm(&drm->ttm.bdev, TTM_PL_VRAM); 320 1.1 riastrad ttm_bo_clean_mm(&drm->ttm.bdev, TTM_PL_TT); 321 1.1 riastrad 322 1.1 riastrad ttm_bo_device_release(&drm->ttm.bdev); 323 1.1 riastrad 324 1.1 riastrad arch_phys_wc_del(drm->ttm.mtrr); 325 1.1 riastrad drm->ttm.mtrr = 0; 326 1.4 riastrad 327 1.4 riastrad #ifdef __NetBSD__ 328 1.6 riastrad pmap_pv_untrack(device->func->resource_addr(device, 1), 329 1.6 riastrad device->func->resource_size(device, 1)); 330 1.4 riastrad #endif 331 1.8 riastrad arch_io_free_memtype_wc(device->func->resource_addr(device, 1), 332 1.8 riastrad device->func->resource_size(device, 1)); 333 1.8 riastrad 334 1.1 riastrad } 335