Home | History | Annotate | Line # | Download | only in nouveau
      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