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