1 // SPDX-License-Identifier: MIT 2 #include <linux/pagemap.h> 3 #include <linux/slab.h> 4 5 #include "nouveau_drv.h" 6 #include "nouveau_mem.h" 7 #include "nouveau_ttm.h" 8 9 struct nouveau_sgdma_be { 10 /* this has to be the first field so populate/unpopulated in 11 * nouve_bo.c works properly, otherwise have to move them here 12 */ 13 struct ttm_dma_tt ttm; 14 struct nouveau_mem *mem; 15 }; 16 17 static void 18 nouveau_sgdma_destroy(struct ttm_tt *ttm) 19 { 20 struct nouveau_sgdma_be *nvbe = (struct nouveau_sgdma_be *)ttm; 21 22 if (ttm) { 23 ttm_dma_tt_fini(&nvbe->ttm); 24 kfree(nvbe); 25 } 26 } 27 28 static int 29 nv04_sgdma_bind(struct ttm_tt *ttm, struct ttm_mem_reg *reg) 30 { 31 struct nouveau_sgdma_be *nvbe = (struct nouveau_sgdma_be *)ttm; 32 struct nouveau_mem *mem = nouveau_mem(reg); 33 int ret; 34 35 ret = nouveau_mem_host(reg, &nvbe->ttm); 36 if (ret) 37 return ret; 38 39 ret = nouveau_mem_map(mem, &mem->cli->vmm.vmm, &mem->vma[0]); 40 if (ret) { 41 nouveau_mem_fini(mem); 42 return ret; 43 } 44 45 nvbe->mem = mem; 46 return 0; 47 } 48 49 static void 50 nv04_sgdma_unbind(struct ttm_tt *ttm) 51 { 52 struct nouveau_sgdma_be *nvbe = (struct nouveau_sgdma_be *)ttm; 53 nouveau_mem_fini(nvbe->mem); 54 } 55 56 static struct ttm_backend_func nv04_sgdma_backend = { 57 .bind = nv04_sgdma_bind, 58 .unbind = nv04_sgdma_unbind, 59 .destroy = nouveau_sgdma_destroy 60 }; 61 62 static int 63 nv50_sgdma_bind(struct ttm_tt *ttm, struct ttm_mem_reg *reg) 64 { 65 struct nouveau_sgdma_be *nvbe = (struct nouveau_sgdma_be *)ttm; 66 struct nouveau_mem *mem = nouveau_mem(reg); 67 int ret; 68 69 ret = nouveau_mem_host(reg, &nvbe->ttm); 70 if (ret) 71 return ret; 72 73 nvbe->mem = mem; 74 return 0; 75 } 76 77 static struct ttm_backend_func nv50_sgdma_backend = { 78 .bind = nv50_sgdma_bind, 79 .unbind = nv04_sgdma_unbind, 80 .destroy = nouveau_sgdma_destroy 81 }; 82 83 struct ttm_tt * 84 nouveau_sgdma_create_ttm(struct ttm_buffer_object *bo, uint32_t page_flags) 85 { 86 struct nouveau_drm *drm = nouveau_bdev(bo->bdev); 87 struct nouveau_sgdma_be *nvbe; 88 89 nvbe = kzalloc(sizeof(*nvbe), GFP_KERNEL); 90 if (!nvbe) 91 return NULL; 92 93 if (drm->client.device.info.family < NV_DEVICE_INFO_V0_TESLA) 94 nvbe->ttm.ttm.func = &nv04_sgdma_backend; 95 else 96 nvbe->ttm.ttm.func = &nv50_sgdma_backend; 97 98 if (ttm_dma_tt_init(&nvbe->ttm, bo, page_flags)) { 99 kfree(nvbe); 100 return NULL; 101 } 102 return &nvbe->ttm.ttm; 103 } 104