1 // SPDX-License-Identifier: GPL-2.0 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_bo_device *bdev, 86 unsigned long size, uint32_t page_flags, 87 struct page *dummy_read_page) 88 { 89 struct nouveau_drm *drm = nouveau_bdev(bdev); 90 struct nouveau_sgdma_be *nvbe; 91 92 nvbe = kzalloc(sizeof(*nvbe), GFP_KERNEL); 93 if (!nvbe) 94 return NULL; 95 96 if (drm->client.device.info.family < NV_DEVICE_INFO_V0_TESLA) 97 nvbe->ttm.ttm.func = &nv04_sgdma_backend; 98 else 99 nvbe->ttm.ttm.func = &nv50_sgdma_backend; 100 101 if (ttm_dma_tt_init(&nvbe->ttm, bdev, size, page_flags, dummy_read_page)) 102 /* 103 * A failing ttm_dma_tt_init() will call ttm_tt_destroy() 104 * and thus our nouveau_sgdma_destroy() hook, so we don't need 105 * to free nvbe here. 106 */ 107 return NULL; 108 return &nvbe->ttm.ttm; 109 } 110