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 int 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 return 0; 55 } 56 57 static struct ttm_backend_func nv04_sgdma_backend = { 58 .bind = nv04_sgdma_bind, 59 .unbind = nv04_sgdma_unbind, 60 .destroy = nouveau_sgdma_destroy 61 }; 62 63 static int 64 nv50_sgdma_bind(struct ttm_tt *ttm, struct ttm_mem_reg *reg) 65 { 66 struct nouveau_sgdma_be *nvbe = (struct nouveau_sgdma_be *)ttm; 67 struct nouveau_mem *mem = nouveau_mem(reg); 68 int ret; 69 70 ret = nouveau_mem_host(reg, &nvbe->ttm); 71 if (ret) 72 return ret; 73 74 nvbe->mem = mem; 75 return 0; 76 } 77 78 static struct ttm_backend_func nv50_sgdma_backend = { 79 .bind = nv50_sgdma_bind, 80 .unbind = nv04_sgdma_unbind, 81 .destroy = nouveau_sgdma_destroy 82 }; 83 84 struct ttm_tt * 85 nouveau_sgdma_create_ttm(struct ttm_buffer_object *bo, uint32_t page_flags) 86 { 87 struct nouveau_drm *drm = nouveau_bdev(bo->bdev); 88 struct nouveau_sgdma_be *nvbe; 89 90 nvbe = kzalloc(sizeof(*nvbe), GFP_KERNEL); 91 if (!nvbe) 92 return NULL; 93 94 if (drm->client.device.info.family < NV_DEVICE_INFO_V0_TESLA) 95 nvbe->ttm.ttm.func = &nv04_sgdma_backend; 96 else 97 nvbe->ttm.ttm.func = &nv50_sgdma_backend; 98 99 if (ttm_dma_tt_init(&nvbe->ttm, bo, page_flags)) 100 /* 101 * A failing ttm_dma_tt_init() will call ttm_tt_destroy() 102 * and thus our nouveau_sgdma_destroy() hook, so we don't need 103 * to free nvbe here. 104 */ 105 return NULL; 106 return &nvbe->ttm.ttm; 107 } 108