xref: /OK3568_Linux_fs/kernel/drivers/gpu/drm/nouveau/nouveau_bo.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * Copyright 2007 Dave Airlied
3*4882a593Smuzhiyun  * All Rights Reserved.
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Permission is hereby granted, free of charge, to any person obtaining a
6*4882a593Smuzhiyun  * copy of this software and associated documentation files (the "Software"),
7*4882a593Smuzhiyun  * to deal in the Software without restriction, including without limitation
8*4882a593Smuzhiyun  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9*4882a593Smuzhiyun  * and/or sell copies of the Software, and to permit persons to whom the
10*4882a593Smuzhiyun  * Software is furnished to do so, subject to the following conditions:
11*4882a593Smuzhiyun  *
12*4882a593Smuzhiyun  * The above copyright notice and this permission notice (including the next
13*4882a593Smuzhiyun  * paragraph) shall be included in all copies or substantial portions of the
14*4882a593Smuzhiyun  * Software.
15*4882a593Smuzhiyun  *
16*4882a593Smuzhiyun  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17*4882a593Smuzhiyun  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18*4882a593Smuzhiyun  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19*4882a593Smuzhiyun  * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20*4882a593Smuzhiyun  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21*4882a593Smuzhiyun  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22*4882a593Smuzhiyun  * OTHER DEALINGS IN THE SOFTWARE.
23*4882a593Smuzhiyun  */
24*4882a593Smuzhiyun /*
25*4882a593Smuzhiyun  * Authors: Dave Airlied <airlied@linux.ie>
26*4882a593Smuzhiyun  *	    Ben Skeggs   <darktama@iinet.net.au>
27*4882a593Smuzhiyun  *	    Jeremy Kolb  <jkolb@brandeis.edu>
28*4882a593Smuzhiyun  */
29*4882a593Smuzhiyun 
30*4882a593Smuzhiyun #include <linux/dma-mapping.h>
31*4882a593Smuzhiyun #include <linux/swiotlb.h>
32*4882a593Smuzhiyun 
33*4882a593Smuzhiyun #include "nouveau_drv.h"
34*4882a593Smuzhiyun #include "nouveau_chan.h"
35*4882a593Smuzhiyun #include "nouveau_fence.h"
36*4882a593Smuzhiyun 
37*4882a593Smuzhiyun #include "nouveau_bo.h"
38*4882a593Smuzhiyun #include "nouveau_ttm.h"
39*4882a593Smuzhiyun #include "nouveau_gem.h"
40*4882a593Smuzhiyun #include "nouveau_mem.h"
41*4882a593Smuzhiyun #include "nouveau_vmm.h"
42*4882a593Smuzhiyun 
43*4882a593Smuzhiyun #include <nvif/class.h>
44*4882a593Smuzhiyun #include <nvif/if500b.h>
45*4882a593Smuzhiyun #include <nvif/if900b.h>
46*4882a593Smuzhiyun 
47*4882a593Smuzhiyun static int nouveau_ttm_tt_bind(struct ttm_bo_device *bdev, struct ttm_tt *ttm,
48*4882a593Smuzhiyun 			       struct ttm_resource *reg);
49*4882a593Smuzhiyun 
50*4882a593Smuzhiyun /*
51*4882a593Smuzhiyun  * NV10-NV40 tiling helpers
52*4882a593Smuzhiyun  */
53*4882a593Smuzhiyun 
54*4882a593Smuzhiyun static void
nv10_bo_update_tile_region(struct drm_device * dev,struct nouveau_drm_tile * reg,u32 addr,u32 size,u32 pitch,u32 flags)55*4882a593Smuzhiyun nv10_bo_update_tile_region(struct drm_device *dev, struct nouveau_drm_tile *reg,
56*4882a593Smuzhiyun 			   u32 addr, u32 size, u32 pitch, u32 flags)
57*4882a593Smuzhiyun {
58*4882a593Smuzhiyun 	struct nouveau_drm *drm = nouveau_drm(dev);
59*4882a593Smuzhiyun 	int i = reg - drm->tile.reg;
60*4882a593Smuzhiyun 	struct nvkm_fb *fb = nvxx_fb(&drm->client.device);
61*4882a593Smuzhiyun 	struct nvkm_fb_tile *tile = &fb->tile.region[i];
62*4882a593Smuzhiyun 
63*4882a593Smuzhiyun 	nouveau_fence_unref(&reg->fence);
64*4882a593Smuzhiyun 
65*4882a593Smuzhiyun 	if (tile->pitch)
66*4882a593Smuzhiyun 		nvkm_fb_tile_fini(fb, i, tile);
67*4882a593Smuzhiyun 
68*4882a593Smuzhiyun 	if (pitch)
69*4882a593Smuzhiyun 		nvkm_fb_tile_init(fb, i, addr, size, pitch, flags, tile);
70*4882a593Smuzhiyun 
71*4882a593Smuzhiyun 	nvkm_fb_tile_prog(fb, i, tile);
72*4882a593Smuzhiyun }
73*4882a593Smuzhiyun 
74*4882a593Smuzhiyun static struct nouveau_drm_tile *
nv10_bo_get_tile_region(struct drm_device * dev,int i)75*4882a593Smuzhiyun nv10_bo_get_tile_region(struct drm_device *dev, int i)
76*4882a593Smuzhiyun {
77*4882a593Smuzhiyun 	struct nouveau_drm *drm = nouveau_drm(dev);
78*4882a593Smuzhiyun 	struct nouveau_drm_tile *tile = &drm->tile.reg[i];
79*4882a593Smuzhiyun 
80*4882a593Smuzhiyun 	spin_lock(&drm->tile.lock);
81*4882a593Smuzhiyun 
82*4882a593Smuzhiyun 	if (!tile->used &&
83*4882a593Smuzhiyun 	    (!tile->fence || nouveau_fence_done(tile->fence)))
84*4882a593Smuzhiyun 		tile->used = true;
85*4882a593Smuzhiyun 	else
86*4882a593Smuzhiyun 		tile = NULL;
87*4882a593Smuzhiyun 
88*4882a593Smuzhiyun 	spin_unlock(&drm->tile.lock);
89*4882a593Smuzhiyun 	return tile;
90*4882a593Smuzhiyun }
91*4882a593Smuzhiyun 
92*4882a593Smuzhiyun static void
nv10_bo_put_tile_region(struct drm_device * dev,struct nouveau_drm_tile * tile,struct dma_fence * fence)93*4882a593Smuzhiyun nv10_bo_put_tile_region(struct drm_device *dev, struct nouveau_drm_tile *tile,
94*4882a593Smuzhiyun 			struct dma_fence *fence)
95*4882a593Smuzhiyun {
96*4882a593Smuzhiyun 	struct nouveau_drm *drm = nouveau_drm(dev);
97*4882a593Smuzhiyun 
98*4882a593Smuzhiyun 	if (tile) {
99*4882a593Smuzhiyun 		spin_lock(&drm->tile.lock);
100*4882a593Smuzhiyun 		tile->fence = (struct nouveau_fence *)dma_fence_get(fence);
101*4882a593Smuzhiyun 		tile->used = false;
102*4882a593Smuzhiyun 		spin_unlock(&drm->tile.lock);
103*4882a593Smuzhiyun 	}
104*4882a593Smuzhiyun }
105*4882a593Smuzhiyun 
106*4882a593Smuzhiyun static struct nouveau_drm_tile *
nv10_bo_set_tiling(struct drm_device * dev,u32 addr,u32 size,u32 pitch,u32 zeta)107*4882a593Smuzhiyun nv10_bo_set_tiling(struct drm_device *dev, u32 addr,
108*4882a593Smuzhiyun 		   u32 size, u32 pitch, u32 zeta)
109*4882a593Smuzhiyun {
110*4882a593Smuzhiyun 	struct nouveau_drm *drm = nouveau_drm(dev);
111*4882a593Smuzhiyun 	struct nvkm_fb *fb = nvxx_fb(&drm->client.device);
112*4882a593Smuzhiyun 	struct nouveau_drm_tile *tile, *found = NULL;
113*4882a593Smuzhiyun 	int i;
114*4882a593Smuzhiyun 
115*4882a593Smuzhiyun 	for (i = 0; i < fb->tile.regions; i++) {
116*4882a593Smuzhiyun 		tile = nv10_bo_get_tile_region(dev, i);
117*4882a593Smuzhiyun 
118*4882a593Smuzhiyun 		if (pitch && !found) {
119*4882a593Smuzhiyun 			found = tile;
120*4882a593Smuzhiyun 			continue;
121*4882a593Smuzhiyun 
122*4882a593Smuzhiyun 		} else if (tile && fb->tile.region[i].pitch) {
123*4882a593Smuzhiyun 			/* Kill an unused tile region. */
124*4882a593Smuzhiyun 			nv10_bo_update_tile_region(dev, tile, 0, 0, 0, 0);
125*4882a593Smuzhiyun 		}
126*4882a593Smuzhiyun 
127*4882a593Smuzhiyun 		nv10_bo_put_tile_region(dev, tile, NULL);
128*4882a593Smuzhiyun 	}
129*4882a593Smuzhiyun 
130*4882a593Smuzhiyun 	if (found)
131*4882a593Smuzhiyun 		nv10_bo_update_tile_region(dev, found, addr, size, pitch, zeta);
132*4882a593Smuzhiyun 	return found;
133*4882a593Smuzhiyun }
134*4882a593Smuzhiyun 
135*4882a593Smuzhiyun static void
nouveau_bo_del_ttm(struct ttm_buffer_object * bo)136*4882a593Smuzhiyun nouveau_bo_del_ttm(struct ttm_buffer_object *bo)
137*4882a593Smuzhiyun {
138*4882a593Smuzhiyun 	struct nouveau_drm *drm = nouveau_bdev(bo->bdev);
139*4882a593Smuzhiyun 	struct drm_device *dev = drm->dev;
140*4882a593Smuzhiyun 	struct nouveau_bo *nvbo = nouveau_bo(bo);
141*4882a593Smuzhiyun 
142*4882a593Smuzhiyun 	WARN_ON(nvbo->pin_refcnt > 0);
143*4882a593Smuzhiyun 	nouveau_bo_del_io_reserve_lru(bo);
144*4882a593Smuzhiyun 	nv10_bo_put_tile_region(dev, nvbo->tile, NULL);
145*4882a593Smuzhiyun 
146*4882a593Smuzhiyun 	/*
147*4882a593Smuzhiyun 	 * If nouveau_bo_new() allocated this buffer, the GEM object was never
148*4882a593Smuzhiyun 	 * initialized, so don't attempt to release it.
149*4882a593Smuzhiyun 	 */
150*4882a593Smuzhiyun 	if (bo->base.dev)
151*4882a593Smuzhiyun 		drm_gem_object_release(&bo->base);
152*4882a593Smuzhiyun 
153*4882a593Smuzhiyun 	kfree(nvbo);
154*4882a593Smuzhiyun }
155*4882a593Smuzhiyun 
156*4882a593Smuzhiyun static inline u64
roundup_64(u64 x,u32 y)157*4882a593Smuzhiyun roundup_64(u64 x, u32 y)
158*4882a593Smuzhiyun {
159*4882a593Smuzhiyun 	x += y - 1;
160*4882a593Smuzhiyun 	do_div(x, y);
161*4882a593Smuzhiyun 	return x * y;
162*4882a593Smuzhiyun }
163*4882a593Smuzhiyun 
164*4882a593Smuzhiyun static void
nouveau_bo_fixup_align(struct nouveau_bo * nvbo,int * align,u64 * size)165*4882a593Smuzhiyun nouveau_bo_fixup_align(struct nouveau_bo *nvbo, int *align, u64 *size)
166*4882a593Smuzhiyun {
167*4882a593Smuzhiyun 	struct nouveau_drm *drm = nouveau_bdev(nvbo->bo.bdev);
168*4882a593Smuzhiyun 	struct nvif_device *device = &drm->client.device;
169*4882a593Smuzhiyun 
170*4882a593Smuzhiyun 	if (device->info.family < NV_DEVICE_INFO_V0_TESLA) {
171*4882a593Smuzhiyun 		if (nvbo->mode) {
172*4882a593Smuzhiyun 			if (device->info.chipset >= 0x40) {
173*4882a593Smuzhiyun 				*align = 65536;
174*4882a593Smuzhiyun 				*size = roundup_64(*size, 64 * nvbo->mode);
175*4882a593Smuzhiyun 
176*4882a593Smuzhiyun 			} else if (device->info.chipset >= 0x30) {
177*4882a593Smuzhiyun 				*align = 32768;
178*4882a593Smuzhiyun 				*size = roundup_64(*size, 64 * nvbo->mode);
179*4882a593Smuzhiyun 
180*4882a593Smuzhiyun 			} else if (device->info.chipset >= 0x20) {
181*4882a593Smuzhiyun 				*align = 16384;
182*4882a593Smuzhiyun 				*size = roundup_64(*size, 64 * nvbo->mode);
183*4882a593Smuzhiyun 
184*4882a593Smuzhiyun 			} else if (device->info.chipset >= 0x10) {
185*4882a593Smuzhiyun 				*align = 16384;
186*4882a593Smuzhiyun 				*size = roundup_64(*size, 32 * nvbo->mode);
187*4882a593Smuzhiyun 			}
188*4882a593Smuzhiyun 		}
189*4882a593Smuzhiyun 	} else {
190*4882a593Smuzhiyun 		*size = roundup_64(*size, (1 << nvbo->page));
191*4882a593Smuzhiyun 		*align = max((1 <<  nvbo->page), *align);
192*4882a593Smuzhiyun 	}
193*4882a593Smuzhiyun 
194*4882a593Smuzhiyun 	*size = roundup_64(*size, PAGE_SIZE);
195*4882a593Smuzhiyun }
196*4882a593Smuzhiyun 
197*4882a593Smuzhiyun struct nouveau_bo *
nouveau_bo_alloc(struct nouveau_cli * cli,u64 * size,int * align,u32 domain,u32 tile_mode,u32 tile_flags)198*4882a593Smuzhiyun nouveau_bo_alloc(struct nouveau_cli *cli, u64 *size, int *align, u32 domain,
199*4882a593Smuzhiyun 		 u32 tile_mode, u32 tile_flags)
200*4882a593Smuzhiyun {
201*4882a593Smuzhiyun 	struct nouveau_drm *drm = cli->drm;
202*4882a593Smuzhiyun 	struct nouveau_bo *nvbo;
203*4882a593Smuzhiyun 	struct nvif_mmu *mmu = &cli->mmu;
204*4882a593Smuzhiyun 	struct nvif_vmm *vmm = cli->svm.cli ? &cli->svm.vmm : &cli->vmm.vmm;
205*4882a593Smuzhiyun 	int i, pi = -1;
206*4882a593Smuzhiyun 
207*4882a593Smuzhiyun 	if (!*size) {
208*4882a593Smuzhiyun 		NV_WARN(drm, "skipped size %016llx\n", *size);
209*4882a593Smuzhiyun 		return ERR_PTR(-EINVAL);
210*4882a593Smuzhiyun 	}
211*4882a593Smuzhiyun 
212*4882a593Smuzhiyun 	nvbo = kzalloc(sizeof(struct nouveau_bo), GFP_KERNEL);
213*4882a593Smuzhiyun 	if (!nvbo)
214*4882a593Smuzhiyun 		return ERR_PTR(-ENOMEM);
215*4882a593Smuzhiyun 	INIT_LIST_HEAD(&nvbo->head);
216*4882a593Smuzhiyun 	INIT_LIST_HEAD(&nvbo->entry);
217*4882a593Smuzhiyun 	INIT_LIST_HEAD(&nvbo->vma_list);
218*4882a593Smuzhiyun 	nvbo->bo.bdev = &drm->ttm.bdev;
219*4882a593Smuzhiyun 
220*4882a593Smuzhiyun 	/* This is confusing, and doesn't actually mean we want an uncached
221*4882a593Smuzhiyun 	 * mapping, but is what NOUVEAU_GEM_DOMAIN_COHERENT gets translated
222*4882a593Smuzhiyun 	 * into in nouveau_gem_new().
223*4882a593Smuzhiyun 	 */
224*4882a593Smuzhiyun 	if (domain & NOUVEAU_GEM_DOMAIN_COHERENT) {
225*4882a593Smuzhiyun 		/* Determine if we can get a cache-coherent map, forcing
226*4882a593Smuzhiyun 		 * uncached mapping if we can't.
227*4882a593Smuzhiyun 		 */
228*4882a593Smuzhiyun 		if (!nouveau_drm_use_coherent_gpu_mapping(drm))
229*4882a593Smuzhiyun 			nvbo->force_coherent = true;
230*4882a593Smuzhiyun 	}
231*4882a593Smuzhiyun 
232*4882a593Smuzhiyun 	if (cli->device.info.family >= NV_DEVICE_INFO_V0_FERMI) {
233*4882a593Smuzhiyun 		nvbo->kind = (tile_flags & 0x0000ff00) >> 8;
234*4882a593Smuzhiyun 		if (!nvif_mmu_kind_valid(mmu, nvbo->kind)) {
235*4882a593Smuzhiyun 			kfree(nvbo);
236*4882a593Smuzhiyun 			return ERR_PTR(-EINVAL);
237*4882a593Smuzhiyun 		}
238*4882a593Smuzhiyun 
239*4882a593Smuzhiyun 		nvbo->comp = mmu->kind[nvbo->kind] != nvbo->kind;
240*4882a593Smuzhiyun 	} else
241*4882a593Smuzhiyun 	if (cli->device.info.family >= NV_DEVICE_INFO_V0_TESLA) {
242*4882a593Smuzhiyun 		nvbo->kind = (tile_flags & 0x00007f00) >> 8;
243*4882a593Smuzhiyun 		nvbo->comp = (tile_flags & 0x00030000) >> 16;
244*4882a593Smuzhiyun 		if (!nvif_mmu_kind_valid(mmu, nvbo->kind)) {
245*4882a593Smuzhiyun 			kfree(nvbo);
246*4882a593Smuzhiyun 			return ERR_PTR(-EINVAL);
247*4882a593Smuzhiyun 		}
248*4882a593Smuzhiyun 	} else {
249*4882a593Smuzhiyun 		nvbo->zeta = (tile_flags & 0x00000007);
250*4882a593Smuzhiyun 	}
251*4882a593Smuzhiyun 	nvbo->mode = tile_mode;
252*4882a593Smuzhiyun 	nvbo->contig = !(tile_flags & NOUVEAU_GEM_TILE_NONCONTIG);
253*4882a593Smuzhiyun 
254*4882a593Smuzhiyun 	/* Determine the desirable target GPU page size for the buffer. */
255*4882a593Smuzhiyun 	for (i = 0; i < vmm->page_nr; i++) {
256*4882a593Smuzhiyun 		/* Because we cannot currently allow VMM maps to fail
257*4882a593Smuzhiyun 		 * during buffer migration, we need to determine page
258*4882a593Smuzhiyun 		 * size for the buffer up-front, and pre-allocate its
259*4882a593Smuzhiyun 		 * page tables.
260*4882a593Smuzhiyun 		 *
261*4882a593Smuzhiyun 		 * Skip page sizes that can't support needed domains.
262*4882a593Smuzhiyun 		 */
263*4882a593Smuzhiyun 		if (cli->device.info.family > NV_DEVICE_INFO_V0_CURIE &&
264*4882a593Smuzhiyun 		    (domain & NOUVEAU_GEM_DOMAIN_VRAM) && !vmm->page[i].vram)
265*4882a593Smuzhiyun 			continue;
266*4882a593Smuzhiyun 		if ((domain & NOUVEAU_GEM_DOMAIN_GART) &&
267*4882a593Smuzhiyun 		    (!vmm->page[i].host || vmm->page[i].shift > PAGE_SHIFT))
268*4882a593Smuzhiyun 			continue;
269*4882a593Smuzhiyun 
270*4882a593Smuzhiyun 		/* Select this page size if it's the first that supports
271*4882a593Smuzhiyun 		 * the potential memory domains, or when it's compatible
272*4882a593Smuzhiyun 		 * with the requested compression settings.
273*4882a593Smuzhiyun 		 */
274*4882a593Smuzhiyun 		if (pi < 0 || !nvbo->comp || vmm->page[i].comp)
275*4882a593Smuzhiyun 			pi = i;
276*4882a593Smuzhiyun 
277*4882a593Smuzhiyun 		/* Stop once the buffer is larger than the current page size. */
278*4882a593Smuzhiyun 		if (*size >= 1ULL << vmm->page[i].shift)
279*4882a593Smuzhiyun 			break;
280*4882a593Smuzhiyun 	}
281*4882a593Smuzhiyun 
282*4882a593Smuzhiyun 	if (WARN_ON(pi < 0)) {
283*4882a593Smuzhiyun 		kfree(nvbo);
284*4882a593Smuzhiyun 		return ERR_PTR(-EINVAL);
285*4882a593Smuzhiyun 	}
286*4882a593Smuzhiyun 
287*4882a593Smuzhiyun 	/* Disable compression if suitable settings couldn't be found. */
288*4882a593Smuzhiyun 	if (nvbo->comp && !vmm->page[pi].comp) {
289*4882a593Smuzhiyun 		if (mmu->object.oclass >= NVIF_CLASS_MMU_GF100)
290*4882a593Smuzhiyun 			nvbo->kind = mmu->kind[nvbo->kind];
291*4882a593Smuzhiyun 		nvbo->comp = 0;
292*4882a593Smuzhiyun 	}
293*4882a593Smuzhiyun 	nvbo->page = vmm->page[pi].shift;
294*4882a593Smuzhiyun 
295*4882a593Smuzhiyun 	nouveau_bo_fixup_align(nvbo, align, size);
296*4882a593Smuzhiyun 
297*4882a593Smuzhiyun 	return nvbo;
298*4882a593Smuzhiyun }
299*4882a593Smuzhiyun 
300*4882a593Smuzhiyun int
nouveau_bo_init(struct nouveau_bo * nvbo,u64 size,int align,u32 domain,struct sg_table * sg,struct dma_resv * robj)301*4882a593Smuzhiyun nouveau_bo_init(struct nouveau_bo *nvbo, u64 size, int align, u32 domain,
302*4882a593Smuzhiyun 		struct sg_table *sg, struct dma_resv *robj)
303*4882a593Smuzhiyun {
304*4882a593Smuzhiyun 	int type = sg ? ttm_bo_type_sg : ttm_bo_type_device;
305*4882a593Smuzhiyun 	size_t acc_size;
306*4882a593Smuzhiyun 	int ret;
307*4882a593Smuzhiyun 
308*4882a593Smuzhiyun 	acc_size = ttm_bo_dma_acc_size(nvbo->bo.bdev, size, sizeof(*nvbo));
309*4882a593Smuzhiyun 
310*4882a593Smuzhiyun 	nvbo->bo.mem.num_pages = size >> PAGE_SHIFT;
311*4882a593Smuzhiyun 	nouveau_bo_placement_set(nvbo, domain, 0);
312*4882a593Smuzhiyun 	INIT_LIST_HEAD(&nvbo->io_reserve_lru);
313*4882a593Smuzhiyun 
314*4882a593Smuzhiyun 	ret = ttm_bo_init(nvbo->bo.bdev, &nvbo->bo, size, type,
315*4882a593Smuzhiyun 			  &nvbo->placement, align >> PAGE_SHIFT, false,
316*4882a593Smuzhiyun 			  acc_size, sg, robj, nouveau_bo_del_ttm);
317*4882a593Smuzhiyun 	if (ret) {
318*4882a593Smuzhiyun 		/* ttm will call nouveau_bo_del_ttm if it fails.. */
319*4882a593Smuzhiyun 		return ret;
320*4882a593Smuzhiyun 	}
321*4882a593Smuzhiyun 
322*4882a593Smuzhiyun 	return 0;
323*4882a593Smuzhiyun }
324*4882a593Smuzhiyun 
325*4882a593Smuzhiyun int
nouveau_bo_new(struct nouveau_cli * cli,u64 size,int align,uint32_t domain,uint32_t tile_mode,uint32_t tile_flags,struct sg_table * sg,struct dma_resv * robj,struct nouveau_bo ** pnvbo)326*4882a593Smuzhiyun nouveau_bo_new(struct nouveau_cli *cli, u64 size, int align,
327*4882a593Smuzhiyun 	       uint32_t domain, uint32_t tile_mode, uint32_t tile_flags,
328*4882a593Smuzhiyun 	       struct sg_table *sg, struct dma_resv *robj,
329*4882a593Smuzhiyun 	       struct nouveau_bo **pnvbo)
330*4882a593Smuzhiyun {
331*4882a593Smuzhiyun 	struct nouveau_bo *nvbo;
332*4882a593Smuzhiyun 	int ret;
333*4882a593Smuzhiyun 
334*4882a593Smuzhiyun 	nvbo = nouveau_bo_alloc(cli, &size, &align, domain, tile_mode,
335*4882a593Smuzhiyun 				tile_flags);
336*4882a593Smuzhiyun 	if (IS_ERR(nvbo))
337*4882a593Smuzhiyun 		return PTR_ERR(nvbo);
338*4882a593Smuzhiyun 
339*4882a593Smuzhiyun 	ret = nouveau_bo_init(nvbo, size, align, domain, sg, robj);
340*4882a593Smuzhiyun 	if (ret)
341*4882a593Smuzhiyun 		return ret;
342*4882a593Smuzhiyun 
343*4882a593Smuzhiyun 	*pnvbo = nvbo;
344*4882a593Smuzhiyun 	return 0;
345*4882a593Smuzhiyun }
346*4882a593Smuzhiyun 
347*4882a593Smuzhiyun static void
set_placement_list(struct nouveau_drm * drm,struct ttm_place * pl,unsigned * n,uint32_t domain,uint32_t flags)348*4882a593Smuzhiyun set_placement_list(struct nouveau_drm *drm, struct ttm_place *pl, unsigned *n,
349*4882a593Smuzhiyun 		   uint32_t domain, uint32_t flags)
350*4882a593Smuzhiyun {
351*4882a593Smuzhiyun 	*n = 0;
352*4882a593Smuzhiyun 
353*4882a593Smuzhiyun 	if (domain & NOUVEAU_GEM_DOMAIN_VRAM) {
354*4882a593Smuzhiyun 		struct nvif_mmu *mmu = &drm->client.mmu;
355*4882a593Smuzhiyun 
356*4882a593Smuzhiyun 		pl[*n].mem_type = TTM_PL_VRAM;
357*4882a593Smuzhiyun 		pl[*n].flags = flags & ~TTM_PL_FLAG_CACHED;
358*4882a593Smuzhiyun 
359*4882a593Smuzhiyun 		/* Some BARs do not support being ioremapped WC */
360*4882a593Smuzhiyun 		if (drm->client.device.info.family >= NV_DEVICE_INFO_V0_TESLA &&
361*4882a593Smuzhiyun 		    mmu->type[drm->ttm.type_vram].type & NVIF_MEM_UNCACHED)
362*4882a593Smuzhiyun 			pl[*n].flags &= ~TTM_PL_FLAG_WC;
363*4882a593Smuzhiyun 
364*4882a593Smuzhiyun 		(*n)++;
365*4882a593Smuzhiyun 	}
366*4882a593Smuzhiyun 	if (domain & NOUVEAU_GEM_DOMAIN_GART) {
367*4882a593Smuzhiyun 		pl[*n].mem_type = TTM_PL_TT;
368*4882a593Smuzhiyun 		pl[*n].flags = flags;
369*4882a593Smuzhiyun 
370*4882a593Smuzhiyun 		if (drm->agp.bridge)
371*4882a593Smuzhiyun 			pl[*n].flags &= ~TTM_PL_FLAG_CACHED;
372*4882a593Smuzhiyun 
373*4882a593Smuzhiyun 		(*n)++;
374*4882a593Smuzhiyun 	}
375*4882a593Smuzhiyun 	if (domain & NOUVEAU_GEM_DOMAIN_CPU) {
376*4882a593Smuzhiyun 		pl[*n].mem_type = TTM_PL_SYSTEM;
377*4882a593Smuzhiyun 		pl[(*n)++].flags = flags;
378*4882a593Smuzhiyun 	}
379*4882a593Smuzhiyun }
380*4882a593Smuzhiyun 
381*4882a593Smuzhiyun static void
set_placement_range(struct nouveau_bo * nvbo,uint32_t domain)382*4882a593Smuzhiyun set_placement_range(struct nouveau_bo *nvbo, uint32_t domain)
383*4882a593Smuzhiyun {
384*4882a593Smuzhiyun 	struct nouveau_drm *drm = nouveau_bdev(nvbo->bo.bdev);
385*4882a593Smuzhiyun 	u32 vram_pages = drm->client.device.info.ram_size >> PAGE_SHIFT;
386*4882a593Smuzhiyun 	unsigned i, fpfn, lpfn;
387*4882a593Smuzhiyun 
388*4882a593Smuzhiyun 	if (drm->client.device.info.family == NV_DEVICE_INFO_V0_CELSIUS &&
389*4882a593Smuzhiyun 	    nvbo->mode && (domain & NOUVEAU_GEM_DOMAIN_VRAM) &&
390*4882a593Smuzhiyun 	    nvbo->bo.mem.num_pages < vram_pages / 4) {
391*4882a593Smuzhiyun 		/*
392*4882a593Smuzhiyun 		 * Make sure that the color and depth buffers are handled
393*4882a593Smuzhiyun 		 * by independent memory controller units. Up to a 9x
394*4882a593Smuzhiyun 		 * speed up when alpha-blending and depth-test are enabled
395*4882a593Smuzhiyun 		 * at the same time.
396*4882a593Smuzhiyun 		 */
397*4882a593Smuzhiyun 		if (nvbo->zeta) {
398*4882a593Smuzhiyun 			fpfn = vram_pages / 2;
399*4882a593Smuzhiyun 			lpfn = ~0;
400*4882a593Smuzhiyun 		} else {
401*4882a593Smuzhiyun 			fpfn = 0;
402*4882a593Smuzhiyun 			lpfn = vram_pages / 2;
403*4882a593Smuzhiyun 		}
404*4882a593Smuzhiyun 		for (i = 0; i < nvbo->placement.num_placement; ++i) {
405*4882a593Smuzhiyun 			nvbo->placements[i].fpfn = fpfn;
406*4882a593Smuzhiyun 			nvbo->placements[i].lpfn = lpfn;
407*4882a593Smuzhiyun 		}
408*4882a593Smuzhiyun 		for (i = 0; i < nvbo->placement.num_busy_placement; ++i) {
409*4882a593Smuzhiyun 			nvbo->busy_placements[i].fpfn = fpfn;
410*4882a593Smuzhiyun 			nvbo->busy_placements[i].lpfn = lpfn;
411*4882a593Smuzhiyun 		}
412*4882a593Smuzhiyun 	}
413*4882a593Smuzhiyun }
414*4882a593Smuzhiyun 
415*4882a593Smuzhiyun void
nouveau_bo_placement_set(struct nouveau_bo * nvbo,uint32_t domain,uint32_t busy)416*4882a593Smuzhiyun nouveau_bo_placement_set(struct nouveau_bo *nvbo, uint32_t domain,
417*4882a593Smuzhiyun 			 uint32_t busy)
418*4882a593Smuzhiyun {
419*4882a593Smuzhiyun 	struct nouveau_drm *drm = nouveau_bdev(nvbo->bo.bdev);
420*4882a593Smuzhiyun 	struct ttm_placement *pl = &nvbo->placement;
421*4882a593Smuzhiyun 	uint32_t flags = (nvbo->force_coherent ? TTM_PL_FLAG_UNCACHED :
422*4882a593Smuzhiyun 						 TTM_PL_MASK_CACHING) |
423*4882a593Smuzhiyun 			 (nvbo->pin_refcnt ? TTM_PL_FLAG_NO_EVICT : 0);
424*4882a593Smuzhiyun 
425*4882a593Smuzhiyun 	pl->placement = nvbo->placements;
426*4882a593Smuzhiyun 	set_placement_list(drm, nvbo->placements, &pl->num_placement,
427*4882a593Smuzhiyun 			   domain, flags);
428*4882a593Smuzhiyun 
429*4882a593Smuzhiyun 	pl->busy_placement = nvbo->busy_placements;
430*4882a593Smuzhiyun 	set_placement_list(drm, nvbo->busy_placements, &pl->num_busy_placement,
431*4882a593Smuzhiyun 			   domain | busy, flags);
432*4882a593Smuzhiyun 
433*4882a593Smuzhiyun 	set_placement_range(nvbo, domain);
434*4882a593Smuzhiyun }
435*4882a593Smuzhiyun 
436*4882a593Smuzhiyun int
nouveau_bo_pin(struct nouveau_bo * nvbo,uint32_t domain,bool contig)437*4882a593Smuzhiyun nouveau_bo_pin(struct nouveau_bo *nvbo, uint32_t domain, bool contig)
438*4882a593Smuzhiyun {
439*4882a593Smuzhiyun 	struct nouveau_drm *drm = nouveau_bdev(nvbo->bo.bdev);
440*4882a593Smuzhiyun 	struct ttm_buffer_object *bo = &nvbo->bo;
441*4882a593Smuzhiyun 	bool force = false, evict = false;
442*4882a593Smuzhiyun 	int ret;
443*4882a593Smuzhiyun 
444*4882a593Smuzhiyun 	ret = ttm_bo_reserve(bo, false, false, NULL);
445*4882a593Smuzhiyun 	if (ret)
446*4882a593Smuzhiyun 		return ret;
447*4882a593Smuzhiyun 
448*4882a593Smuzhiyun 	if (drm->client.device.info.family >= NV_DEVICE_INFO_V0_TESLA &&
449*4882a593Smuzhiyun 	    domain == NOUVEAU_GEM_DOMAIN_VRAM && contig) {
450*4882a593Smuzhiyun 		if (!nvbo->contig) {
451*4882a593Smuzhiyun 			nvbo->contig = true;
452*4882a593Smuzhiyun 			force = true;
453*4882a593Smuzhiyun 			evict = true;
454*4882a593Smuzhiyun 		}
455*4882a593Smuzhiyun 	}
456*4882a593Smuzhiyun 
457*4882a593Smuzhiyun 	if (nvbo->pin_refcnt) {
458*4882a593Smuzhiyun 		bool error = evict;
459*4882a593Smuzhiyun 
460*4882a593Smuzhiyun 		switch (bo->mem.mem_type) {
461*4882a593Smuzhiyun 		case TTM_PL_VRAM:
462*4882a593Smuzhiyun 			error |= !(domain & NOUVEAU_GEM_DOMAIN_VRAM);
463*4882a593Smuzhiyun 			break;
464*4882a593Smuzhiyun 		case TTM_PL_TT:
465*4882a593Smuzhiyun 			error |= !(domain & NOUVEAU_GEM_DOMAIN_GART);
466*4882a593Smuzhiyun 		default:
467*4882a593Smuzhiyun 			break;
468*4882a593Smuzhiyun 		}
469*4882a593Smuzhiyun 
470*4882a593Smuzhiyun 		if (error) {
471*4882a593Smuzhiyun 			NV_ERROR(drm, "bo %p pinned elsewhere: "
472*4882a593Smuzhiyun 				      "0x%08x vs 0x%08x\n", bo,
473*4882a593Smuzhiyun 				 bo->mem.mem_type, domain);
474*4882a593Smuzhiyun 			ret = -EBUSY;
475*4882a593Smuzhiyun 		}
476*4882a593Smuzhiyun 		nvbo->pin_refcnt++;
477*4882a593Smuzhiyun 		goto out;
478*4882a593Smuzhiyun 	}
479*4882a593Smuzhiyun 
480*4882a593Smuzhiyun 	if (evict) {
481*4882a593Smuzhiyun 		nouveau_bo_placement_set(nvbo, NOUVEAU_GEM_DOMAIN_GART, 0);
482*4882a593Smuzhiyun 		ret = nouveau_bo_validate(nvbo, false, false);
483*4882a593Smuzhiyun 		if (ret)
484*4882a593Smuzhiyun 			goto out;
485*4882a593Smuzhiyun 	}
486*4882a593Smuzhiyun 
487*4882a593Smuzhiyun 	nvbo->pin_refcnt++;
488*4882a593Smuzhiyun 	nouveau_bo_placement_set(nvbo, domain, 0);
489*4882a593Smuzhiyun 
490*4882a593Smuzhiyun 	/* drop pin_refcnt temporarily, so we don't trip the assertion
491*4882a593Smuzhiyun 	 * in nouveau_bo_move() that makes sure we're not trying to
492*4882a593Smuzhiyun 	 * move a pinned buffer
493*4882a593Smuzhiyun 	 */
494*4882a593Smuzhiyun 	nvbo->pin_refcnt--;
495*4882a593Smuzhiyun 	ret = nouveau_bo_validate(nvbo, false, false);
496*4882a593Smuzhiyun 	if (ret)
497*4882a593Smuzhiyun 		goto out;
498*4882a593Smuzhiyun 	nvbo->pin_refcnt++;
499*4882a593Smuzhiyun 
500*4882a593Smuzhiyun 	switch (bo->mem.mem_type) {
501*4882a593Smuzhiyun 	case TTM_PL_VRAM:
502*4882a593Smuzhiyun 		drm->gem.vram_available -= bo->mem.size;
503*4882a593Smuzhiyun 		break;
504*4882a593Smuzhiyun 	case TTM_PL_TT:
505*4882a593Smuzhiyun 		drm->gem.gart_available -= bo->mem.size;
506*4882a593Smuzhiyun 		break;
507*4882a593Smuzhiyun 	default:
508*4882a593Smuzhiyun 		break;
509*4882a593Smuzhiyun 	}
510*4882a593Smuzhiyun 
511*4882a593Smuzhiyun out:
512*4882a593Smuzhiyun 	if (force && ret)
513*4882a593Smuzhiyun 		nvbo->contig = false;
514*4882a593Smuzhiyun 	ttm_bo_unreserve(bo);
515*4882a593Smuzhiyun 	return ret;
516*4882a593Smuzhiyun }
517*4882a593Smuzhiyun 
518*4882a593Smuzhiyun int
nouveau_bo_unpin(struct nouveau_bo * nvbo)519*4882a593Smuzhiyun nouveau_bo_unpin(struct nouveau_bo *nvbo)
520*4882a593Smuzhiyun {
521*4882a593Smuzhiyun 	struct nouveau_drm *drm = nouveau_bdev(nvbo->bo.bdev);
522*4882a593Smuzhiyun 	struct ttm_buffer_object *bo = &nvbo->bo;
523*4882a593Smuzhiyun 	int ret, ref;
524*4882a593Smuzhiyun 
525*4882a593Smuzhiyun 	ret = ttm_bo_reserve(bo, false, false, NULL);
526*4882a593Smuzhiyun 	if (ret)
527*4882a593Smuzhiyun 		return ret;
528*4882a593Smuzhiyun 
529*4882a593Smuzhiyun 	ref = --nvbo->pin_refcnt;
530*4882a593Smuzhiyun 	WARN_ON_ONCE(ref < 0);
531*4882a593Smuzhiyun 	if (ref)
532*4882a593Smuzhiyun 		goto out;
533*4882a593Smuzhiyun 
534*4882a593Smuzhiyun 	switch (bo->mem.mem_type) {
535*4882a593Smuzhiyun 	case TTM_PL_VRAM:
536*4882a593Smuzhiyun 		nouveau_bo_placement_set(nvbo, NOUVEAU_GEM_DOMAIN_VRAM, 0);
537*4882a593Smuzhiyun 		break;
538*4882a593Smuzhiyun 	case TTM_PL_TT:
539*4882a593Smuzhiyun 		nouveau_bo_placement_set(nvbo, NOUVEAU_GEM_DOMAIN_GART, 0);
540*4882a593Smuzhiyun 		break;
541*4882a593Smuzhiyun 	default:
542*4882a593Smuzhiyun 		break;
543*4882a593Smuzhiyun 	}
544*4882a593Smuzhiyun 
545*4882a593Smuzhiyun 	ret = nouveau_bo_validate(nvbo, false, false);
546*4882a593Smuzhiyun 	if (ret == 0) {
547*4882a593Smuzhiyun 		switch (bo->mem.mem_type) {
548*4882a593Smuzhiyun 		case TTM_PL_VRAM:
549*4882a593Smuzhiyun 			drm->gem.vram_available += bo->mem.size;
550*4882a593Smuzhiyun 			break;
551*4882a593Smuzhiyun 		case TTM_PL_TT:
552*4882a593Smuzhiyun 			drm->gem.gart_available += bo->mem.size;
553*4882a593Smuzhiyun 			break;
554*4882a593Smuzhiyun 		default:
555*4882a593Smuzhiyun 			break;
556*4882a593Smuzhiyun 		}
557*4882a593Smuzhiyun 	}
558*4882a593Smuzhiyun 
559*4882a593Smuzhiyun out:
560*4882a593Smuzhiyun 	ttm_bo_unreserve(bo);
561*4882a593Smuzhiyun 	return ret;
562*4882a593Smuzhiyun }
563*4882a593Smuzhiyun 
564*4882a593Smuzhiyun int
nouveau_bo_map(struct nouveau_bo * nvbo)565*4882a593Smuzhiyun nouveau_bo_map(struct nouveau_bo *nvbo)
566*4882a593Smuzhiyun {
567*4882a593Smuzhiyun 	int ret;
568*4882a593Smuzhiyun 
569*4882a593Smuzhiyun 	ret = ttm_bo_reserve(&nvbo->bo, false, false, NULL);
570*4882a593Smuzhiyun 	if (ret)
571*4882a593Smuzhiyun 		return ret;
572*4882a593Smuzhiyun 
573*4882a593Smuzhiyun 	ret = ttm_bo_kmap(&nvbo->bo, 0, nvbo->bo.mem.num_pages, &nvbo->kmap);
574*4882a593Smuzhiyun 
575*4882a593Smuzhiyun 	ttm_bo_unreserve(&nvbo->bo);
576*4882a593Smuzhiyun 	return ret;
577*4882a593Smuzhiyun }
578*4882a593Smuzhiyun 
579*4882a593Smuzhiyun void
nouveau_bo_unmap(struct nouveau_bo * nvbo)580*4882a593Smuzhiyun nouveau_bo_unmap(struct nouveau_bo *nvbo)
581*4882a593Smuzhiyun {
582*4882a593Smuzhiyun 	if (!nvbo)
583*4882a593Smuzhiyun 		return;
584*4882a593Smuzhiyun 
585*4882a593Smuzhiyun 	ttm_bo_kunmap(&nvbo->kmap);
586*4882a593Smuzhiyun }
587*4882a593Smuzhiyun 
588*4882a593Smuzhiyun void
nouveau_bo_sync_for_device(struct nouveau_bo * nvbo)589*4882a593Smuzhiyun nouveau_bo_sync_for_device(struct nouveau_bo *nvbo)
590*4882a593Smuzhiyun {
591*4882a593Smuzhiyun 	struct nouveau_drm *drm = nouveau_bdev(nvbo->bo.bdev);
592*4882a593Smuzhiyun 	struct ttm_dma_tt *ttm_dma = (struct ttm_dma_tt *)nvbo->bo.ttm;
593*4882a593Smuzhiyun 	int i;
594*4882a593Smuzhiyun 
595*4882a593Smuzhiyun 	if (!ttm_dma || !ttm_dma->dma_address)
596*4882a593Smuzhiyun 		return;
597*4882a593Smuzhiyun 
598*4882a593Smuzhiyun 	/* Don't waste time looping if the object is coherent */
599*4882a593Smuzhiyun 	if (nvbo->force_coherent)
600*4882a593Smuzhiyun 		return;
601*4882a593Smuzhiyun 
602*4882a593Smuzhiyun 	for (i = 0; i < ttm_dma->ttm.num_pages; i++)
603*4882a593Smuzhiyun 		dma_sync_single_for_device(drm->dev->dev,
604*4882a593Smuzhiyun 					   ttm_dma->dma_address[i],
605*4882a593Smuzhiyun 					   PAGE_SIZE, DMA_TO_DEVICE);
606*4882a593Smuzhiyun }
607*4882a593Smuzhiyun 
608*4882a593Smuzhiyun void
nouveau_bo_sync_for_cpu(struct nouveau_bo * nvbo)609*4882a593Smuzhiyun nouveau_bo_sync_for_cpu(struct nouveau_bo *nvbo)
610*4882a593Smuzhiyun {
611*4882a593Smuzhiyun 	struct nouveau_drm *drm = nouveau_bdev(nvbo->bo.bdev);
612*4882a593Smuzhiyun 	struct ttm_dma_tt *ttm_dma = (struct ttm_dma_tt *)nvbo->bo.ttm;
613*4882a593Smuzhiyun 	int i;
614*4882a593Smuzhiyun 
615*4882a593Smuzhiyun 	if (!ttm_dma || !ttm_dma->dma_address)
616*4882a593Smuzhiyun 		return;
617*4882a593Smuzhiyun 
618*4882a593Smuzhiyun 	/* Don't waste time looping if the object is coherent */
619*4882a593Smuzhiyun 	if (nvbo->force_coherent)
620*4882a593Smuzhiyun 		return;
621*4882a593Smuzhiyun 
622*4882a593Smuzhiyun 	for (i = 0; i < ttm_dma->ttm.num_pages; i++)
623*4882a593Smuzhiyun 		dma_sync_single_for_cpu(drm->dev->dev, ttm_dma->dma_address[i],
624*4882a593Smuzhiyun 					PAGE_SIZE, DMA_FROM_DEVICE);
625*4882a593Smuzhiyun }
626*4882a593Smuzhiyun 
nouveau_bo_add_io_reserve_lru(struct ttm_buffer_object * bo)627*4882a593Smuzhiyun void nouveau_bo_add_io_reserve_lru(struct ttm_buffer_object *bo)
628*4882a593Smuzhiyun {
629*4882a593Smuzhiyun 	struct nouveau_drm *drm = nouveau_bdev(bo->bdev);
630*4882a593Smuzhiyun 	struct nouveau_bo *nvbo = nouveau_bo(bo);
631*4882a593Smuzhiyun 
632*4882a593Smuzhiyun 	mutex_lock(&drm->ttm.io_reserve_mutex);
633*4882a593Smuzhiyun 	list_move_tail(&nvbo->io_reserve_lru, &drm->ttm.io_reserve_lru);
634*4882a593Smuzhiyun 	mutex_unlock(&drm->ttm.io_reserve_mutex);
635*4882a593Smuzhiyun }
636*4882a593Smuzhiyun 
nouveau_bo_del_io_reserve_lru(struct ttm_buffer_object * bo)637*4882a593Smuzhiyun void nouveau_bo_del_io_reserve_lru(struct ttm_buffer_object *bo)
638*4882a593Smuzhiyun {
639*4882a593Smuzhiyun 	struct nouveau_drm *drm = nouveau_bdev(bo->bdev);
640*4882a593Smuzhiyun 	struct nouveau_bo *nvbo = nouveau_bo(bo);
641*4882a593Smuzhiyun 
642*4882a593Smuzhiyun 	mutex_lock(&drm->ttm.io_reserve_mutex);
643*4882a593Smuzhiyun 	list_del_init(&nvbo->io_reserve_lru);
644*4882a593Smuzhiyun 	mutex_unlock(&drm->ttm.io_reserve_mutex);
645*4882a593Smuzhiyun }
646*4882a593Smuzhiyun 
647*4882a593Smuzhiyun int
nouveau_bo_validate(struct nouveau_bo * nvbo,bool interruptible,bool no_wait_gpu)648*4882a593Smuzhiyun nouveau_bo_validate(struct nouveau_bo *nvbo, bool interruptible,
649*4882a593Smuzhiyun 		    bool no_wait_gpu)
650*4882a593Smuzhiyun {
651*4882a593Smuzhiyun 	struct ttm_operation_ctx ctx = { interruptible, no_wait_gpu };
652*4882a593Smuzhiyun 	int ret;
653*4882a593Smuzhiyun 
654*4882a593Smuzhiyun 	ret = ttm_bo_validate(&nvbo->bo, &nvbo->placement, &ctx);
655*4882a593Smuzhiyun 	if (ret)
656*4882a593Smuzhiyun 		return ret;
657*4882a593Smuzhiyun 
658*4882a593Smuzhiyun 	nouveau_bo_sync_for_device(nvbo);
659*4882a593Smuzhiyun 
660*4882a593Smuzhiyun 	return 0;
661*4882a593Smuzhiyun }
662*4882a593Smuzhiyun 
663*4882a593Smuzhiyun void
nouveau_bo_wr16(struct nouveau_bo * nvbo,unsigned index,u16 val)664*4882a593Smuzhiyun nouveau_bo_wr16(struct nouveau_bo *nvbo, unsigned index, u16 val)
665*4882a593Smuzhiyun {
666*4882a593Smuzhiyun 	bool is_iomem;
667*4882a593Smuzhiyun 	u16 *mem = ttm_kmap_obj_virtual(&nvbo->kmap, &is_iomem);
668*4882a593Smuzhiyun 
669*4882a593Smuzhiyun 	mem += index;
670*4882a593Smuzhiyun 
671*4882a593Smuzhiyun 	if (is_iomem)
672*4882a593Smuzhiyun 		iowrite16_native(val, (void __force __iomem *)mem);
673*4882a593Smuzhiyun 	else
674*4882a593Smuzhiyun 		*mem = val;
675*4882a593Smuzhiyun }
676*4882a593Smuzhiyun 
677*4882a593Smuzhiyun u32
nouveau_bo_rd32(struct nouveau_bo * nvbo,unsigned index)678*4882a593Smuzhiyun nouveau_bo_rd32(struct nouveau_bo *nvbo, unsigned index)
679*4882a593Smuzhiyun {
680*4882a593Smuzhiyun 	bool is_iomem;
681*4882a593Smuzhiyun 	u32 *mem = ttm_kmap_obj_virtual(&nvbo->kmap, &is_iomem);
682*4882a593Smuzhiyun 
683*4882a593Smuzhiyun 	mem += index;
684*4882a593Smuzhiyun 
685*4882a593Smuzhiyun 	if (is_iomem)
686*4882a593Smuzhiyun 		return ioread32_native((void __force __iomem *)mem);
687*4882a593Smuzhiyun 	else
688*4882a593Smuzhiyun 		return *mem;
689*4882a593Smuzhiyun }
690*4882a593Smuzhiyun 
691*4882a593Smuzhiyun void
nouveau_bo_wr32(struct nouveau_bo * nvbo,unsigned index,u32 val)692*4882a593Smuzhiyun nouveau_bo_wr32(struct nouveau_bo *nvbo, unsigned index, u32 val)
693*4882a593Smuzhiyun {
694*4882a593Smuzhiyun 	bool is_iomem;
695*4882a593Smuzhiyun 	u32 *mem = ttm_kmap_obj_virtual(&nvbo->kmap, &is_iomem);
696*4882a593Smuzhiyun 
697*4882a593Smuzhiyun 	mem += index;
698*4882a593Smuzhiyun 
699*4882a593Smuzhiyun 	if (is_iomem)
700*4882a593Smuzhiyun 		iowrite32_native(val, (void __force __iomem *)mem);
701*4882a593Smuzhiyun 	else
702*4882a593Smuzhiyun 		*mem = val;
703*4882a593Smuzhiyun }
704*4882a593Smuzhiyun 
705*4882a593Smuzhiyun static struct ttm_tt *
nouveau_ttm_tt_create(struct ttm_buffer_object * bo,uint32_t page_flags)706*4882a593Smuzhiyun nouveau_ttm_tt_create(struct ttm_buffer_object *bo, uint32_t page_flags)
707*4882a593Smuzhiyun {
708*4882a593Smuzhiyun #if IS_ENABLED(CONFIG_AGP)
709*4882a593Smuzhiyun 	struct nouveau_drm *drm = nouveau_bdev(bo->bdev);
710*4882a593Smuzhiyun 
711*4882a593Smuzhiyun 	if (drm->agp.bridge) {
712*4882a593Smuzhiyun 		return ttm_agp_tt_create(bo, drm->agp.bridge, page_flags);
713*4882a593Smuzhiyun 	}
714*4882a593Smuzhiyun #endif
715*4882a593Smuzhiyun 
716*4882a593Smuzhiyun 	return nouveau_sgdma_create_ttm(bo, page_flags);
717*4882a593Smuzhiyun }
718*4882a593Smuzhiyun 
719*4882a593Smuzhiyun static int
nouveau_ttm_tt_bind(struct ttm_bo_device * bdev,struct ttm_tt * ttm,struct ttm_resource * reg)720*4882a593Smuzhiyun nouveau_ttm_tt_bind(struct ttm_bo_device *bdev, struct ttm_tt *ttm,
721*4882a593Smuzhiyun 		    struct ttm_resource *reg)
722*4882a593Smuzhiyun {
723*4882a593Smuzhiyun #if IS_ENABLED(CONFIG_AGP)
724*4882a593Smuzhiyun 	struct nouveau_drm *drm = nouveau_bdev(bdev);
725*4882a593Smuzhiyun #endif
726*4882a593Smuzhiyun 	if (!reg)
727*4882a593Smuzhiyun 		return -EINVAL;
728*4882a593Smuzhiyun #if IS_ENABLED(CONFIG_AGP)
729*4882a593Smuzhiyun 	if (drm->agp.bridge)
730*4882a593Smuzhiyun 		return ttm_agp_bind(ttm, reg);
731*4882a593Smuzhiyun #endif
732*4882a593Smuzhiyun 	return nouveau_sgdma_bind(bdev, ttm, reg);
733*4882a593Smuzhiyun }
734*4882a593Smuzhiyun 
735*4882a593Smuzhiyun static void
nouveau_ttm_tt_unbind(struct ttm_bo_device * bdev,struct ttm_tt * ttm)736*4882a593Smuzhiyun nouveau_ttm_tt_unbind(struct ttm_bo_device *bdev, struct ttm_tt *ttm)
737*4882a593Smuzhiyun {
738*4882a593Smuzhiyun #if IS_ENABLED(CONFIG_AGP)
739*4882a593Smuzhiyun 	struct nouveau_drm *drm = nouveau_bdev(bdev);
740*4882a593Smuzhiyun 
741*4882a593Smuzhiyun 	if (drm->agp.bridge) {
742*4882a593Smuzhiyun 		ttm_agp_unbind(ttm);
743*4882a593Smuzhiyun 		return;
744*4882a593Smuzhiyun 	}
745*4882a593Smuzhiyun #endif
746*4882a593Smuzhiyun 	nouveau_sgdma_unbind(bdev, ttm);
747*4882a593Smuzhiyun }
748*4882a593Smuzhiyun 
749*4882a593Smuzhiyun static void
nouveau_bo_evict_flags(struct ttm_buffer_object * bo,struct ttm_placement * pl)750*4882a593Smuzhiyun nouveau_bo_evict_flags(struct ttm_buffer_object *bo, struct ttm_placement *pl)
751*4882a593Smuzhiyun {
752*4882a593Smuzhiyun 	struct nouveau_bo *nvbo = nouveau_bo(bo);
753*4882a593Smuzhiyun 
754*4882a593Smuzhiyun 	switch (bo->mem.mem_type) {
755*4882a593Smuzhiyun 	case TTM_PL_VRAM:
756*4882a593Smuzhiyun 		nouveau_bo_placement_set(nvbo, NOUVEAU_GEM_DOMAIN_GART,
757*4882a593Smuzhiyun 					 NOUVEAU_GEM_DOMAIN_CPU);
758*4882a593Smuzhiyun 		break;
759*4882a593Smuzhiyun 	default:
760*4882a593Smuzhiyun 		nouveau_bo_placement_set(nvbo, NOUVEAU_GEM_DOMAIN_CPU, 0);
761*4882a593Smuzhiyun 		break;
762*4882a593Smuzhiyun 	}
763*4882a593Smuzhiyun 
764*4882a593Smuzhiyun 	*pl = nvbo->placement;
765*4882a593Smuzhiyun }
766*4882a593Smuzhiyun 
767*4882a593Smuzhiyun static int
nouveau_bo_move_prep(struct nouveau_drm * drm,struct ttm_buffer_object * bo,struct ttm_resource * reg)768*4882a593Smuzhiyun nouveau_bo_move_prep(struct nouveau_drm *drm, struct ttm_buffer_object *bo,
769*4882a593Smuzhiyun 		     struct ttm_resource *reg)
770*4882a593Smuzhiyun {
771*4882a593Smuzhiyun 	struct nouveau_mem *old_mem = nouveau_mem(&bo->mem);
772*4882a593Smuzhiyun 	struct nouveau_mem *new_mem = nouveau_mem(reg);
773*4882a593Smuzhiyun 	struct nvif_vmm *vmm = &drm->client.vmm.vmm;
774*4882a593Smuzhiyun 	int ret;
775*4882a593Smuzhiyun 
776*4882a593Smuzhiyun 	ret = nvif_vmm_get(vmm, LAZY, false, old_mem->mem.page, 0,
777*4882a593Smuzhiyun 			   old_mem->mem.size, &old_mem->vma[0]);
778*4882a593Smuzhiyun 	if (ret)
779*4882a593Smuzhiyun 		return ret;
780*4882a593Smuzhiyun 
781*4882a593Smuzhiyun 	ret = nvif_vmm_get(vmm, LAZY, false, new_mem->mem.page, 0,
782*4882a593Smuzhiyun 			   new_mem->mem.size, &old_mem->vma[1]);
783*4882a593Smuzhiyun 	if (ret)
784*4882a593Smuzhiyun 		goto done;
785*4882a593Smuzhiyun 
786*4882a593Smuzhiyun 	ret = nouveau_mem_map(old_mem, vmm, &old_mem->vma[0]);
787*4882a593Smuzhiyun 	if (ret)
788*4882a593Smuzhiyun 		goto done;
789*4882a593Smuzhiyun 
790*4882a593Smuzhiyun 	ret = nouveau_mem_map(new_mem, vmm, &old_mem->vma[1]);
791*4882a593Smuzhiyun done:
792*4882a593Smuzhiyun 	if (ret) {
793*4882a593Smuzhiyun 		nvif_vmm_put(vmm, &old_mem->vma[1]);
794*4882a593Smuzhiyun 		nvif_vmm_put(vmm, &old_mem->vma[0]);
795*4882a593Smuzhiyun 	}
796*4882a593Smuzhiyun 	return 0;
797*4882a593Smuzhiyun }
798*4882a593Smuzhiyun 
799*4882a593Smuzhiyun static int
nouveau_bo_move_m2mf(struct ttm_buffer_object * bo,int evict,bool intr,bool no_wait_gpu,struct ttm_resource * new_reg)800*4882a593Smuzhiyun nouveau_bo_move_m2mf(struct ttm_buffer_object *bo, int evict, bool intr,
801*4882a593Smuzhiyun 		     bool no_wait_gpu, struct ttm_resource *new_reg)
802*4882a593Smuzhiyun {
803*4882a593Smuzhiyun 	struct nouveau_drm *drm = nouveau_bdev(bo->bdev);
804*4882a593Smuzhiyun 	struct nouveau_channel *chan = drm->ttm.chan;
805*4882a593Smuzhiyun 	struct nouveau_cli *cli = (void *)chan->user.client;
806*4882a593Smuzhiyun 	struct nouveau_fence *fence;
807*4882a593Smuzhiyun 	int ret;
808*4882a593Smuzhiyun 
809*4882a593Smuzhiyun 	/* create temporary vmas for the transfer and attach them to the
810*4882a593Smuzhiyun 	 * old nvkm_mem node, these will get cleaned up after ttm has
811*4882a593Smuzhiyun 	 * destroyed the ttm_resource
812*4882a593Smuzhiyun 	 */
813*4882a593Smuzhiyun 	if (drm->client.device.info.family >= NV_DEVICE_INFO_V0_TESLA) {
814*4882a593Smuzhiyun 		ret = nouveau_bo_move_prep(drm, bo, new_reg);
815*4882a593Smuzhiyun 		if (ret)
816*4882a593Smuzhiyun 			return ret;
817*4882a593Smuzhiyun 	}
818*4882a593Smuzhiyun 
819*4882a593Smuzhiyun 	mutex_lock_nested(&cli->mutex, SINGLE_DEPTH_NESTING);
820*4882a593Smuzhiyun 	ret = nouveau_fence_sync(nouveau_bo(bo), chan, true, intr);
821*4882a593Smuzhiyun 	if (ret == 0) {
822*4882a593Smuzhiyun 		ret = drm->ttm.move(chan, bo, &bo->mem, new_reg);
823*4882a593Smuzhiyun 		if (ret == 0) {
824*4882a593Smuzhiyun 			ret = nouveau_fence_new(chan, false, &fence);
825*4882a593Smuzhiyun 			if (ret == 0) {
826*4882a593Smuzhiyun 				ret = ttm_bo_move_accel_cleanup(bo,
827*4882a593Smuzhiyun 								&fence->base,
828*4882a593Smuzhiyun 								evict, false,
829*4882a593Smuzhiyun 								new_reg);
830*4882a593Smuzhiyun 				nouveau_fence_unref(&fence);
831*4882a593Smuzhiyun 			}
832*4882a593Smuzhiyun 		}
833*4882a593Smuzhiyun 	}
834*4882a593Smuzhiyun 	mutex_unlock(&cli->mutex);
835*4882a593Smuzhiyun 	return ret;
836*4882a593Smuzhiyun }
837*4882a593Smuzhiyun 
838*4882a593Smuzhiyun void
nouveau_bo_move_init(struct nouveau_drm * drm)839*4882a593Smuzhiyun nouveau_bo_move_init(struct nouveau_drm *drm)
840*4882a593Smuzhiyun {
841*4882a593Smuzhiyun 	static const struct _method_table {
842*4882a593Smuzhiyun 		const char *name;
843*4882a593Smuzhiyun 		int engine;
844*4882a593Smuzhiyun 		s32 oclass;
845*4882a593Smuzhiyun 		int (*exec)(struct nouveau_channel *,
846*4882a593Smuzhiyun 			    struct ttm_buffer_object *,
847*4882a593Smuzhiyun 			    struct ttm_resource *, struct ttm_resource *);
848*4882a593Smuzhiyun 		int (*init)(struct nouveau_channel *, u32 handle);
849*4882a593Smuzhiyun 	} _methods[] = {
850*4882a593Smuzhiyun 		{  "COPY", 4, 0xc5b5, nve0_bo_move_copy, nve0_bo_move_init },
851*4882a593Smuzhiyun 		{  "GRCE", 0, 0xc5b5, nve0_bo_move_copy, nvc0_bo_move_init },
852*4882a593Smuzhiyun 		{  "COPY", 4, 0xc3b5, nve0_bo_move_copy, nve0_bo_move_init },
853*4882a593Smuzhiyun 		{  "GRCE", 0, 0xc3b5, nve0_bo_move_copy, nvc0_bo_move_init },
854*4882a593Smuzhiyun 		{  "COPY", 4, 0xc1b5, nve0_bo_move_copy, nve0_bo_move_init },
855*4882a593Smuzhiyun 		{  "GRCE", 0, 0xc1b5, nve0_bo_move_copy, nvc0_bo_move_init },
856*4882a593Smuzhiyun 		{  "COPY", 4, 0xc0b5, nve0_bo_move_copy, nve0_bo_move_init },
857*4882a593Smuzhiyun 		{  "GRCE", 0, 0xc0b5, nve0_bo_move_copy, nvc0_bo_move_init },
858*4882a593Smuzhiyun 		{  "COPY", 4, 0xb0b5, nve0_bo_move_copy, nve0_bo_move_init },
859*4882a593Smuzhiyun 		{  "GRCE", 0, 0xb0b5, nve0_bo_move_copy, nvc0_bo_move_init },
860*4882a593Smuzhiyun 		{  "COPY", 4, 0xa0b5, nve0_bo_move_copy, nve0_bo_move_init },
861*4882a593Smuzhiyun 		{  "GRCE", 0, 0xa0b5, nve0_bo_move_copy, nvc0_bo_move_init },
862*4882a593Smuzhiyun 		{ "COPY1", 5, 0x90b8, nvc0_bo_move_copy, nvc0_bo_move_init },
863*4882a593Smuzhiyun 		{ "COPY0", 4, 0x90b5, nvc0_bo_move_copy, nvc0_bo_move_init },
864*4882a593Smuzhiyun 		{  "COPY", 0, 0x85b5, nva3_bo_move_copy, nv50_bo_move_init },
865*4882a593Smuzhiyun 		{ "CRYPT", 0, 0x74c1, nv84_bo_move_exec, nv50_bo_move_init },
866*4882a593Smuzhiyun 		{  "M2MF", 0, 0x9039, nvc0_bo_move_m2mf, nvc0_bo_move_init },
867*4882a593Smuzhiyun 		{  "M2MF", 0, 0x5039, nv50_bo_move_m2mf, nv50_bo_move_init },
868*4882a593Smuzhiyun 		{  "M2MF", 0, 0x0039, nv04_bo_move_m2mf, nv04_bo_move_init },
869*4882a593Smuzhiyun 		{},
870*4882a593Smuzhiyun 	};
871*4882a593Smuzhiyun 	const struct _method_table *mthd = _methods;
872*4882a593Smuzhiyun 	const char *name = "CPU";
873*4882a593Smuzhiyun 	int ret;
874*4882a593Smuzhiyun 
875*4882a593Smuzhiyun 	do {
876*4882a593Smuzhiyun 		struct nouveau_channel *chan;
877*4882a593Smuzhiyun 
878*4882a593Smuzhiyun 		if (mthd->engine)
879*4882a593Smuzhiyun 			chan = drm->cechan;
880*4882a593Smuzhiyun 		else
881*4882a593Smuzhiyun 			chan = drm->channel;
882*4882a593Smuzhiyun 		if (chan == NULL)
883*4882a593Smuzhiyun 			continue;
884*4882a593Smuzhiyun 
885*4882a593Smuzhiyun 		ret = nvif_object_ctor(&chan->user, "ttmBoMove",
886*4882a593Smuzhiyun 				       mthd->oclass | (mthd->engine << 16),
887*4882a593Smuzhiyun 				       mthd->oclass, NULL, 0,
888*4882a593Smuzhiyun 				       &drm->ttm.copy);
889*4882a593Smuzhiyun 		if (ret == 0) {
890*4882a593Smuzhiyun 			ret = mthd->init(chan, drm->ttm.copy.handle);
891*4882a593Smuzhiyun 			if (ret) {
892*4882a593Smuzhiyun 				nvif_object_dtor(&drm->ttm.copy);
893*4882a593Smuzhiyun 				continue;
894*4882a593Smuzhiyun 			}
895*4882a593Smuzhiyun 
896*4882a593Smuzhiyun 			drm->ttm.move = mthd->exec;
897*4882a593Smuzhiyun 			drm->ttm.chan = chan;
898*4882a593Smuzhiyun 			name = mthd->name;
899*4882a593Smuzhiyun 			break;
900*4882a593Smuzhiyun 		}
901*4882a593Smuzhiyun 	} while ((++mthd)->exec);
902*4882a593Smuzhiyun 
903*4882a593Smuzhiyun 	NV_INFO(drm, "MM: using %s for buffer copies\n", name);
904*4882a593Smuzhiyun }
905*4882a593Smuzhiyun 
906*4882a593Smuzhiyun static int
nouveau_bo_move_flipd(struct ttm_buffer_object * bo,bool evict,bool intr,bool no_wait_gpu,struct ttm_resource * new_reg)907*4882a593Smuzhiyun nouveau_bo_move_flipd(struct ttm_buffer_object *bo, bool evict, bool intr,
908*4882a593Smuzhiyun 		      bool no_wait_gpu, struct ttm_resource *new_reg)
909*4882a593Smuzhiyun {
910*4882a593Smuzhiyun 	struct ttm_operation_ctx ctx = { intr, no_wait_gpu };
911*4882a593Smuzhiyun 	struct ttm_place placement_memtype = {
912*4882a593Smuzhiyun 		.fpfn = 0,
913*4882a593Smuzhiyun 		.lpfn = 0,
914*4882a593Smuzhiyun 		.mem_type = TTM_PL_TT,
915*4882a593Smuzhiyun 		.flags = TTM_PL_MASK_CACHING
916*4882a593Smuzhiyun 	};
917*4882a593Smuzhiyun 	struct ttm_placement placement;
918*4882a593Smuzhiyun 	struct ttm_resource tmp_reg;
919*4882a593Smuzhiyun 	int ret;
920*4882a593Smuzhiyun 
921*4882a593Smuzhiyun 	placement.num_placement = placement.num_busy_placement = 1;
922*4882a593Smuzhiyun 	placement.placement = placement.busy_placement = &placement_memtype;
923*4882a593Smuzhiyun 
924*4882a593Smuzhiyun 	tmp_reg = *new_reg;
925*4882a593Smuzhiyun 	tmp_reg.mm_node = NULL;
926*4882a593Smuzhiyun 	ret = ttm_bo_mem_space(bo, &placement, &tmp_reg, &ctx);
927*4882a593Smuzhiyun 	if (ret)
928*4882a593Smuzhiyun 		return ret;
929*4882a593Smuzhiyun 
930*4882a593Smuzhiyun 	ret = ttm_tt_populate(bo->bdev, bo->ttm, &ctx);
931*4882a593Smuzhiyun 	if (ret)
932*4882a593Smuzhiyun 		goto out;
933*4882a593Smuzhiyun 
934*4882a593Smuzhiyun 	ret = nouveau_ttm_tt_bind(bo->bdev, bo->ttm, &tmp_reg);
935*4882a593Smuzhiyun 	if (ret)
936*4882a593Smuzhiyun 		goto out;
937*4882a593Smuzhiyun 
938*4882a593Smuzhiyun 	ret = nouveau_bo_move_m2mf(bo, true, intr, no_wait_gpu, &tmp_reg);
939*4882a593Smuzhiyun 	if (ret)
940*4882a593Smuzhiyun 		goto out;
941*4882a593Smuzhiyun 
942*4882a593Smuzhiyun 	ret = ttm_bo_move_ttm(bo, &ctx, new_reg);
943*4882a593Smuzhiyun out:
944*4882a593Smuzhiyun 	ttm_resource_free(bo, &tmp_reg);
945*4882a593Smuzhiyun 	return ret;
946*4882a593Smuzhiyun }
947*4882a593Smuzhiyun 
948*4882a593Smuzhiyun static int
nouveau_bo_move_flips(struct ttm_buffer_object * bo,bool evict,bool intr,bool no_wait_gpu,struct ttm_resource * new_reg)949*4882a593Smuzhiyun nouveau_bo_move_flips(struct ttm_buffer_object *bo, bool evict, bool intr,
950*4882a593Smuzhiyun 		      bool no_wait_gpu, struct ttm_resource *new_reg)
951*4882a593Smuzhiyun {
952*4882a593Smuzhiyun 	struct ttm_operation_ctx ctx = { intr, no_wait_gpu };
953*4882a593Smuzhiyun 	struct ttm_place placement_memtype = {
954*4882a593Smuzhiyun 		.fpfn = 0,
955*4882a593Smuzhiyun 		.lpfn = 0,
956*4882a593Smuzhiyun 		.mem_type = TTM_PL_TT,
957*4882a593Smuzhiyun 		.flags = TTM_PL_MASK_CACHING
958*4882a593Smuzhiyun 	};
959*4882a593Smuzhiyun 	struct ttm_placement placement;
960*4882a593Smuzhiyun 	struct ttm_resource tmp_reg;
961*4882a593Smuzhiyun 	int ret;
962*4882a593Smuzhiyun 
963*4882a593Smuzhiyun 	placement.num_placement = placement.num_busy_placement = 1;
964*4882a593Smuzhiyun 	placement.placement = placement.busy_placement = &placement_memtype;
965*4882a593Smuzhiyun 
966*4882a593Smuzhiyun 	tmp_reg = *new_reg;
967*4882a593Smuzhiyun 	tmp_reg.mm_node = NULL;
968*4882a593Smuzhiyun 	ret = ttm_bo_mem_space(bo, &placement, &tmp_reg, &ctx);
969*4882a593Smuzhiyun 	if (ret)
970*4882a593Smuzhiyun 		return ret;
971*4882a593Smuzhiyun 
972*4882a593Smuzhiyun 	ret = ttm_bo_move_ttm(bo, &ctx, &tmp_reg);
973*4882a593Smuzhiyun 	if (ret)
974*4882a593Smuzhiyun 		goto out;
975*4882a593Smuzhiyun 
976*4882a593Smuzhiyun 	ret = nouveau_bo_move_m2mf(bo, true, intr, no_wait_gpu, new_reg);
977*4882a593Smuzhiyun 	if (ret)
978*4882a593Smuzhiyun 		goto out;
979*4882a593Smuzhiyun 
980*4882a593Smuzhiyun out:
981*4882a593Smuzhiyun 	ttm_resource_free(bo, &tmp_reg);
982*4882a593Smuzhiyun 	return ret;
983*4882a593Smuzhiyun }
984*4882a593Smuzhiyun 
985*4882a593Smuzhiyun static void
nouveau_bo_move_ntfy(struct ttm_buffer_object * bo,bool evict,struct ttm_resource * new_reg)986*4882a593Smuzhiyun nouveau_bo_move_ntfy(struct ttm_buffer_object *bo, bool evict,
987*4882a593Smuzhiyun 		     struct ttm_resource *new_reg)
988*4882a593Smuzhiyun {
989*4882a593Smuzhiyun 	struct nouveau_mem *mem = new_reg ? nouveau_mem(new_reg) : NULL;
990*4882a593Smuzhiyun 	struct nouveau_bo *nvbo = nouveau_bo(bo);
991*4882a593Smuzhiyun 	struct nouveau_vma *vma;
992*4882a593Smuzhiyun 
993*4882a593Smuzhiyun 	/* ttm can now (stupidly) pass the driver bos it didn't create... */
994*4882a593Smuzhiyun 	if (bo->destroy != nouveau_bo_del_ttm)
995*4882a593Smuzhiyun 		return;
996*4882a593Smuzhiyun 
997*4882a593Smuzhiyun 	nouveau_bo_del_io_reserve_lru(bo);
998*4882a593Smuzhiyun 
999*4882a593Smuzhiyun 	if (mem && new_reg->mem_type != TTM_PL_SYSTEM &&
1000*4882a593Smuzhiyun 	    mem->mem.page == nvbo->page) {
1001*4882a593Smuzhiyun 		list_for_each_entry(vma, &nvbo->vma_list, head) {
1002*4882a593Smuzhiyun 			nouveau_vma_map(vma, mem);
1003*4882a593Smuzhiyun 		}
1004*4882a593Smuzhiyun 	} else {
1005*4882a593Smuzhiyun 		list_for_each_entry(vma, &nvbo->vma_list, head) {
1006*4882a593Smuzhiyun 			WARN_ON(ttm_bo_wait(bo, false, false));
1007*4882a593Smuzhiyun 			nouveau_vma_unmap(vma);
1008*4882a593Smuzhiyun 		}
1009*4882a593Smuzhiyun 	}
1010*4882a593Smuzhiyun 
1011*4882a593Smuzhiyun 	if (new_reg) {
1012*4882a593Smuzhiyun 		if (new_reg->mm_node)
1013*4882a593Smuzhiyun 			nvbo->offset = (new_reg->start << PAGE_SHIFT);
1014*4882a593Smuzhiyun 		else
1015*4882a593Smuzhiyun 			nvbo->offset = 0;
1016*4882a593Smuzhiyun 	}
1017*4882a593Smuzhiyun 
1018*4882a593Smuzhiyun }
1019*4882a593Smuzhiyun 
1020*4882a593Smuzhiyun static int
nouveau_bo_vm_bind(struct ttm_buffer_object * bo,struct ttm_resource * new_reg,struct nouveau_drm_tile ** new_tile)1021*4882a593Smuzhiyun nouveau_bo_vm_bind(struct ttm_buffer_object *bo, struct ttm_resource *new_reg,
1022*4882a593Smuzhiyun 		   struct nouveau_drm_tile **new_tile)
1023*4882a593Smuzhiyun {
1024*4882a593Smuzhiyun 	struct nouveau_drm *drm = nouveau_bdev(bo->bdev);
1025*4882a593Smuzhiyun 	struct drm_device *dev = drm->dev;
1026*4882a593Smuzhiyun 	struct nouveau_bo *nvbo = nouveau_bo(bo);
1027*4882a593Smuzhiyun 	u64 offset = new_reg->start << PAGE_SHIFT;
1028*4882a593Smuzhiyun 
1029*4882a593Smuzhiyun 	*new_tile = NULL;
1030*4882a593Smuzhiyun 	if (new_reg->mem_type != TTM_PL_VRAM)
1031*4882a593Smuzhiyun 		return 0;
1032*4882a593Smuzhiyun 
1033*4882a593Smuzhiyun 	if (drm->client.device.info.family >= NV_DEVICE_INFO_V0_CELSIUS) {
1034*4882a593Smuzhiyun 		*new_tile = nv10_bo_set_tiling(dev, offset, new_reg->size,
1035*4882a593Smuzhiyun 					       nvbo->mode, nvbo->zeta);
1036*4882a593Smuzhiyun 	}
1037*4882a593Smuzhiyun 
1038*4882a593Smuzhiyun 	return 0;
1039*4882a593Smuzhiyun }
1040*4882a593Smuzhiyun 
1041*4882a593Smuzhiyun static void
nouveau_bo_vm_cleanup(struct ttm_buffer_object * bo,struct nouveau_drm_tile * new_tile,struct nouveau_drm_tile ** old_tile)1042*4882a593Smuzhiyun nouveau_bo_vm_cleanup(struct ttm_buffer_object *bo,
1043*4882a593Smuzhiyun 		      struct nouveau_drm_tile *new_tile,
1044*4882a593Smuzhiyun 		      struct nouveau_drm_tile **old_tile)
1045*4882a593Smuzhiyun {
1046*4882a593Smuzhiyun 	struct nouveau_drm *drm = nouveau_bdev(bo->bdev);
1047*4882a593Smuzhiyun 	struct drm_device *dev = drm->dev;
1048*4882a593Smuzhiyun 	struct dma_fence *fence = dma_resv_get_excl(bo->base.resv);
1049*4882a593Smuzhiyun 
1050*4882a593Smuzhiyun 	nv10_bo_put_tile_region(dev, *old_tile, fence);
1051*4882a593Smuzhiyun 	*old_tile = new_tile;
1052*4882a593Smuzhiyun }
1053*4882a593Smuzhiyun 
1054*4882a593Smuzhiyun static int
nouveau_bo_move(struct ttm_buffer_object * bo,bool evict,struct ttm_operation_ctx * ctx,struct ttm_resource * new_reg)1055*4882a593Smuzhiyun nouveau_bo_move(struct ttm_buffer_object *bo, bool evict,
1056*4882a593Smuzhiyun 		struct ttm_operation_ctx *ctx,
1057*4882a593Smuzhiyun 		struct ttm_resource *new_reg)
1058*4882a593Smuzhiyun {
1059*4882a593Smuzhiyun 	struct nouveau_drm *drm = nouveau_bdev(bo->bdev);
1060*4882a593Smuzhiyun 	struct nouveau_bo *nvbo = nouveau_bo(bo);
1061*4882a593Smuzhiyun 	struct ttm_resource *old_reg = &bo->mem;
1062*4882a593Smuzhiyun 	struct nouveau_drm_tile *new_tile = NULL;
1063*4882a593Smuzhiyun 	int ret = 0;
1064*4882a593Smuzhiyun 
1065*4882a593Smuzhiyun 	ret = ttm_bo_wait(bo, ctx->interruptible, ctx->no_wait_gpu);
1066*4882a593Smuzhiyun 	if (ret)
1067*4882a593Smuzhiyun 		return ret;
1068*4882a593Smuzhiyun 
1069*4882a593Smuzhiyun 	if (nvbo->pin_refcnt)
1070*4882a593Smuzhiyun 		NV_WARN(drm, "Moving pinned object %p!\n", nvbo);
1071*4882a593Smuzhiyun 
1072*4882a593Smuzhiyun 	if (drm->client.device.info.family < NV_DEVICE_INFO_V0_TESLA) {
1073*4882a593Smuzhiyun 		ret = nouveau_bo_vm_bind(bo, new_reg, &new_tile);
1074*4882a593Smuzhiyun 		if (ret)
1075*4882a593Smuzhiyun 			return ret;
1076*4882a593Smuzhiyun 	}
1077*4882a593Smuzhiyun 
1078*4882a593Smuzhiyun 	/* Fake bo copy. */
1079*4882a593Smuzhiyun 	if (old_reg->mem_type == TTM_PL_SYSTEM && !bo->ttm) {
1080*4882a593Smuzhiyun 		ttm_bo_move_null(bo, new_reg);
1081*4882a593Smuzhiyun 		goto out;
1082*4882a593Smuzhiyun 	}
1083*4882a593Smuzhiyun 
1084*4882a593Smuzhiyun 	/* Hardware assisted copy. */
1085*4882a593Smuzhiyun 	if (drm->ttm.move) {
1086*4882a593Smuzhiyun 		if (new_reg->mem_type == TTM_PL_SYSTEM)
1087*4882a593Smuzhiyun 			ret = nouveau_bo_move_flipd(bo, evict,
1088*4882a593Smuzhiyun 						    ctx->interruptible,
1089*4882a593Smuzhiyun 						    ctx->no_wait_gpu, new_reg);
1090*4882a593Smuzhiyun 		else if (old_reg->mem_type == TTM_PL_SYSTEM)
1091*4882a593Smuzhiyun 			ret = nouveau_bo_move_flips(bo, evict,
1092*4882a593Smuzhiyun 						    ctx->interruptible,
1093*4882a593Smuzhiyun 						    ctx->no_wait_gpu, new_reg);
1094*4882a593Smuzhiyun 		else
1095*4882a593Smuzhiyun 			ret = nouveau_bo_move_m2mf(bo, evict,
1096*4882a593Smuzhiyun 						   ctx->interruptible,
1097*4882a593Smuzhiyun 						   ctx->no_wait_gpu, new_reg);
1098*4882a593Smuzhiyun 		if (!ret)
1099*4882a593Smuzhiyun 			goto out;
1100*4882a593Smuzhiyun 	}
1101*4882a593Smuzhiyun 
1102*4882a593Smuzhiyun 	/* Fallback to software copy. */
1103*4882a593Smuzhiyun 	ret = ttm_bo_wait(bo, ctx->interruptible, ctx->no_wait_gpu);
1104*4882a593Smuzhiyun 	if (ret == 0)
1105*4882a593Smuzhiyun 		ret = ttm_bo_move_memcpy(bo, ctx, new_reg);
1106*4882a593Smuzhiyun 
1107*4882a593Smuzhiyun out:
1108*4882a593Smuzhiyun 	if (drm->client.device.info.family < NV_DEVICE_INFO_V0_TESLA) {
1109*4882a593Smuzhiyun 		if (ret)
1110*4882a593Smuzhiyun 			nouveau_bo_vm_cleanup(bo, NULL, &new_tile);
1111*4882a593Smuzhiyun 		else
1112*4882a593Smuzhiyun 			nouveau_bo_vm_cleanup(bo, new_tile, &nvbo->tile);
1113*4882a593Smuzhiyun 	}
1114*4882a593Smuzhiyun 
1115*4882a593Smuzhiyun 	return ret;
1116*4882a593Smuzhiyun }
1117*4882a593Smuzhiyun 
1118*4882a593Smuzhiyun static int
nouveau_bo_verify_access(struct ttm_buffer_object * bo,struct file * filp)1119*4882a593Smuzhiyun nouveau_bo_verify_access(struct ttm_buffer_object *bo, struct file *filp)
1120*4882a593Smuzhiyun {
1121*4882a593Smuzhiyun 	struct nouveau_bo *nvbo = nouveau_bo(bo);
1122*4882a593Smuzhiyun 
1123*4882a593Smuzhiyun 	return drm_vma_node_verify_access(&nvbo->bo.base.vma_node,
1124*4882a593Smuzhiyun 					  filp->private_data);
1125*4882a593Smuzhiyun }
1126*4882a593Smuzhiyun 
1127*4882a593Smuzhiyun static void
nouveau_ttm_io_mem_free_locked(struct nouveau_drm * drm,struct ttm_resource * reg)1128*4882a593Smuzhiyun nouveau_ttm_io_mem_free_locked(struct nouveau_drm *drm,
1129*4882a593Smuzhiyun 			       struct ttm_resource *reg)
1130*4882a593Smuzhiyun {
1131*4882a593Smuzhiyun 	struct nouveau_mem *mem = nouveau_mem(reg);
1132*4882a593Smuzhiyun 
1133*4882a593Smuzhiyun 	if (drm->client.mem->oclass >= NVIF_CLASS_MEM_NV50) {
1134*4882a593Smuzhiyun 		switch (reg->mem_type) {
1135*4882a593Smuzhiyun 		case TTM_PL_TT:
1136*4882a593Smuzhiyun 			if (mem->kind)
1137*4882a593Smuzhiyun 				nvif_object_unmap_handle(&mem->mem.object);
1138*4882a593Smuzhiyun 			break;
1139*4882a593Smuzhiyun 		case TTM_PL_VRAM:
1140*4882a593Smuzhiyun 			nvif_object_unmap_handle(&mem->mem.object);
1141*4882a593Smuzhiyun 			break;
1142*4882a593Smuzhiyun 		default:
1143*4882a593Smuzhiyun 			break;
1144*4882a593Smuzhiyun 		}
1145*4882a593Smuzhiyun 	}
1146*4882a593Smuzhiyun }
1147*4882a593Smuzhiyun 
1148*4882a593Smuzhiyun static int
nouveau_ttm_io_mem_reserve(struct ttm_bo_device * bdev,struct ttm_resource * reg)1149*4882a593Smuzhiyun nouveau_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_resource *reg)
1150*4882a593Smuzhiyun {
1151*4882a593Smuzhiyun 	struct nouveau_drm *drm = nouveau_bdev(bdev);
1152*4882a593Smuzhiyun 	struct nvkm_device *device = nvxx_device(&drm->client.device);
1153*4882a593Smuzhiyun 	struct nouveau_mem *mem = nouveau_mem(reg);
1154*4882a593Smuzhiyun 	int ret;
1155*4882a593Smuzhiyun 
1156*4882a593Smuzhiyun 	mutex_lock(&drm->ttm.io_reserve_mutex);
1157*4882a593Smuzhiyun retry:
1158*4882a593Smuzhiyun 	switch (reg->mem_type) {
1159*4882a593Smuzhiyun 	case TTM_PL_SYSTEM:
1160*4882a593Smuzhiyun 		/* System memory */
1161*4882a593Smuzhiyun 		ret = 0;
1162*4882a593Smuzhiyun 		goto out;
1163*4882a593Smuzhiyun 	case TTM_PL_TT:
1164*4882a593Smuzhiyun #if IS_ENABLED(CONFIG_AGP)
1165*4882a593Smuzhiyun 		if (drm->agp.bridge) {
1166*4882a593Smuzhiyun 			reg->bus.offset = (reg->start << PAGE_SHIFT) +
1167*4882a593Smuzhiyun 				drm->agp.base;
1168*4882a593Smuzhiyun 			reg->bus.is_iomem = !drm->agp.cma;
1169*4882a593Smuzhiyun 		}
1170*4882a593Smuzhiyun #endif
1171*4882a593Smuzhiyun 		if (drm->client.mem->oclass < NVIF_CLASS_MEM_NV50 ||
1172*4882a593Smuzhiyun 		    !mem->kind) {
1173*4882a593Smuzhiyun 			/* untiled */
1174*4882a593Smuzhiyun 			ret = 0;
1175*4882a593Smuzhiyun 			break;
1176*4882a593Smuzhiyun 		}
1177*4882a593Smuzhiyun 		fallthrough;	/* tiled memory */
1178*4882a593Smuzhiyun 	case TTM_PL_VRAM:
1179*4882a593Smuzhiyun 		reg->bus.offset = (reg->start << PAGE_SHIFT) +
1180*4882a593Smuzhiyun 			device->func->resource_addr(device, 1);
1181*4882a593Smuzhiyun 		reg->bus.is_iomem = true;
1182*4882a593Smuzhiyun 		if (drm->client.mem->oclass >= NVIF_CLASS_MEM_NV50) {
1183*4882a593Smuzhiyun 			union {
1184*4882a593Smuzhiyun 				struct nv50_mem_map_v0 nv50;
1185*4882a593Smuzhiyun 				struct gf100_mem_map_v0 gf100;
1186*4882a593Smuzhiyun 			} args;
1187*4882a593Smuzhiyun 			u64 handle, length;
1188*4882a593Smuzhiyun 			u32 argc = 0;
1189*4882a593Smuzhiyun 
1190*4882a593Smuzhiyun 			switch (mem->mem.object.oclass) {
1191*4882a593Smuzhiyun 			case NVIF_CLASS_MEM_NV50:
1192*4882a593Smuzhiyun 				args.nv50.version = 0;
1193*4882a593Smuzhiyun 				args.nv50.ro = 0;
1194*4882a593Smuzhiyun 				args.nv50.kind = mem->kind;
1195*4882a593Smuzhiyun 				args.nv50.comp = mem->comp;
1196*4882a593Smuzhiyun 				argc = sizeof(args.nv50);
1197*4882a593Smuzhiyun 				break;
1198*4882a593Smuzhiyun 			case NVIF_CLASS_MEM_GF100:
1199*4882a593Smuzhiyun 				args.gf100.version = 0;
1200*4882a593Smuzhiyun 				args.gf100.ro = 0;
1201*4882a593Smuzhiyun 				args.gf100.kind = mem->kind;
1202*4882a593Smuzhiyun 				argc = sizeof(args.gf100);
1203*4882a593Smuzhiyun 				break;
1204*4882a593Smuzhiyun 			default:
1205*4882a593Smuzhiyun 				WARN_ON(1);
1206*4882a593Smuzhiyun 				break;
1207*4882a593Smuzhiyun 			}
1208*4882a593Smuzhiyun 
1209*4882a593Smuzhiyun 			ret = nvif_object_map_handle(&mem->mem.object,
1210*4882a593Smuzhiyun 						     &args, argc,
1211*4882a593Smuzhiyun 						     &handle, &length);
1212*4882a593Smuzhiyun 			if (ret != 1) {
1213*4882a593Smuzhiyun 				if (WARN_ON(ret == 0))
1214*4882a593Smuzhiyun 					ret = -EINVAL;
1215*4882a593Smuzhiyun 				goto out;
1216*4882a593Smuzhiyun 			}
1217*4882a593Smuzhiyun 
1218*4882a593Smuzhiyun 			reg->bus.offset = handle;
1219*4882a593Smuzhiyun 		}
1220*4882a593Smuzhiyun 		ret = 0;
1221*4882a593Smuzhiyun 		break;
1222*4882a593Smuzhiyun 	default:
1223*4882a593Smuzhiyun 		ret = -EINVAL;
1224*4882a593Smuzhiyun 	}
1225*4882a593Smuzhiyun 
1226*4882a593Smuzhiyun out:
1227*4882a593Smuzhiyun 	if (ret == -ENOSPC) {
1228*4882a593Smuzhiyun 		struct nouveau_bo *nvbo;
1229*4882a593Smuzhiyun 
1230*4882a593Smuzhiyun 		nvbo = list_first_entry_or_null(&drm->ttm.io_reserve_lru,
1231*4882a593Smuzhiyun 						typeof(*nvbo),
1232*4882a593Smuzhiyun 						io_reserve_lru);
1233*4882a593Smuzhiyun 		if (nvbo) {
1234*4882a593Smuzhiyun 			list_del_init(&nvbo->io_reserve_lru);
1235*4882a593Smuzhiyun 			drm_vma_node_unmap(&nvbo->bo.base.vma_node,
1236*4882a593Smuzhiyun 					   bdev->dev_mapping);
1237*4882a593Smuzhiyun 			nouveau_ttm_io_mem_free_locked(drm, &nvbo->bo.mem);
1238*4882a593Smuzhiyun 			goto retry;
1239*4882a593Smuzhiyun 		}
1240*4882a593Smuzhiyun 
1241*4882a593Smuzhiyun 	}
1242*4882a593Smuzhiyun 	mutex_unlock(&drm->ttm.io_reserve_mutex);
1243*4882a593Smuzhiyun 	return ret;
1244*4882a593Smuzhiyun }
1245*4882a593Smuzhiyun 
1246*4882a593Smuzhiyun static void
nouveau_ttm_io_mem_free(struct ttm_bo_device * bdev,struct ttm_resource * reg)1247*4882a593Smuzhiyun nouveau_ttm_io_mem_free(struct ttm_bo_device *bdev, struct ttm_resource *reg)
1248*4882a593Smuzhiyun {
1249*4882a593Smuzhiyun 	struct nouveau_drm *drm = nouveau_bdev(bdev);
1250*4882a593Smuzhiyun 
1251*4882a593Smuzhiyun 	mutex_lock(&drm->ttm.io_reserve_mutex);
1252*4882a593Smuzhiyun 	nouveau_ttm_io_mem_free_locked(drm, reg);
1253*4882a593Smuzhiyun 	mutex_unlock(&drm->ttm.io_reserve_mutex);
1254*4882a593Smuzhiyun }
1255*4882a593Smuzhiyun 
1256*4882a593Smuzhiyun static int
nouveau_ttm_fault_reserve_notify(struct ttm_buffer_object * bo)1257*4882a593Smuzhiyun nouveau_ttm_fault_reserve_notify(struct ttm_buffer_object *bo)
1258*4882a593Smuzhiyun {
1259*4882a593Smuzhiyun 	struct nouveau_drm *drm = nouveau_bdev(bo->bdev);
1260*4882a593Smuzhiyun 	struct nouveau_bo *nvbo = nouveau_bo(bo);
1261*4882a593Smuzhiyun 	struct nvkm_device *device = nvxx_device(&drm->client.device);
1262*4882a593Smuzhiyun 	u32 mappable = device->func->resource_size(device, 1) >> PAGE_SHIFT;
1263*4882a593Smuzhiyun 	int i, ret;
1264*4882a593Smuzhiyun 
1265*4882a593Smuzhiyun 	/* as long as the bo isn't in vram, and isn't tiled, we've got
1266*4882a593Smuzhiyun 	 * nothing to do here.
1267*4882a593Smuzhiyun 	 */
1268*4882a593Smuzhiyun 	if (bo->mem.mem_type != TTM_PL_VRAM) {
1269*4882a593Smuzhiyun 		if (drm->client.device.info.family < NV_DEVICE_INFO_V0_TESLA ||
1270*4882a593Smuzhiyun 		    !nvbo->kind)
1271*4882a593Smuzhiyun 			return 0;
1272*4882a593Smuzhiyun 
1273*4882a593Smuzhiyun 		if (bo->mem.mem_type == TTM_PL_SYSTEM) {
1274*4882a593Smuzhiyun 			nouveau_bo_placement_set(nvbo, NOUVEAU_GEM_DOMAIN_GART,
1275*4882a593Smuzhiyun 						 0);
1276*4882a593Smuzhiyun 
1277*4882a593Smuzhiyun 			ret = nouveau_bo_validate(nvbo, false, false);
1278*4882a593Smuzhiyun 			if (ret)
1279*4882a593Smuzhiyun 				return ret;
1280*4882a593Smuzhiyun 		}
1281*4882a593Smuzhiyun 		return 0;
1282*4882a593Smuzhiyun 	}
1283*4882a593Smuzhiyun 
1284*4882a593Smuzhiyun 	/* make sure bo is in mappable vram */
1285*4882a593Smuzhiyun 	if (drm->client.device.info.family >= NV_DEVICE_INFO_V0_TESLA ||
1286*4882a593Smuzhiyun 	    bo->mem.start + bo->mem.num_pages < mappable)
1287*4882a593Smuzhiyun 		return 0;
1288*4882a593Smuzhiyun 
1289*4882a593Smuzhiyun 	for (i = 0; i < nvbo->placement.num_placement; ++i) {
1290*4882a593Smuzhiyun 		nvbo->placements[i].fpfn = 0;
1291*4882a593Smuzhiyun 		nvbo->placements[i].lpfn = mappable;
1292*4882a593Smuzhiyun 	}
1293*4882a593Smuzhiyun 
1294*4882a593Smuzhiyun 	for (i = 0; i < nvbo->placement.num_busy_placement; ++i) {
1295*4882a593Smuzhiyun 		nvbo->busy_placements[i].fpfn = 0;
1296*4882a593Smuzhiyun 		nvbo->busy_placements[i].lpfn = mappable;
1297*4882a593Smuzhiyun 	}
1298*4882a593Smuzhiyun 
1299*4882a593Smuzhiyun 	nouveau_bo_placement_set(nvbo, NOUVEAU_GEM_DOMAIN_VRAM, 0);
1300*4882a593Smuzhiyun 	return nouveau_bo_validate(nvbo, false, false);
1301*4882a593Smuzhiyun }
1302*4882a593Smuzhiyun 
1303*4882a593Smuzhiyun static int
nouveau_ttm_tt_populate(struct ttm_bo_device * bdev,struct ttm_tt * ttm,struct ttm_operation_ctx * ctx)1304*4882a593Smuzhiyun nouveau_ttm_tt_populate(struct ttm_bo_device *bdev,
1305*4882a593Smuzhiyun 			struct ttm_tt *ttm, struct ttm_operation_ctx *ctx)
1306*4882a593Smuzhiyun {
1307*4882a593Smuzhiyun 	struct ttm_dma_tt *ttm_dma = (void *)ttm;
1308*4882a593Smuzhiyun 	struct nouveau_drm *drm;
1309*4882a593Smuzhiyun 	struct device *dev;
1310*4882a593Smuzhiyun 	bool slave = !!(ttm->page_flags & TTM_PAGE_FLAG_SG);
1311*4882a593Smuzhiyun 
1312*4882a593Smuzhiyun 	if (ttm_tt_is_populated(ttm))
1313*4882a593Smuzhiyun 		return 0;
1314*4882a593Smuzhiyun 
1315*4882a593Smuzhiyun 	if (slave && ttm->sg) {
1316*4882a593Smuzhiyun 		/* make userspace faulting work */
1317*4882a593Smuzhiyun 		drm_prime_sg_to_page_addr_arrays(ttm->sg, ttm->pages,
1318*4882a593Smuzhiyun 						 ttm_dma->dma_address, ttm->num_pages);
1319*4882a593Smuzhiyun 		ttm_tt_set_populated(ttm);
1320*4882a593Smuzhiyun 		return 0;
1321*4882a593Smuzhiyun 	}
1322*4882a593Smuzhiyun 
1323*4882a593Smuzhiyun 	drm = nouveau_bdev(bdev);
1324*4882a593Smuzhiyun 	dev = drm->dev->dev;
1325*4882a593Smuzhiyun 
1326*4882a593Smuzhiyun #if IS_ENABLED(CONFIG_AGP)
1327*4882a593Smuzhiyun 	if (drm->agp.bridge) {
1328*4882a593Smuzhiyun 		return ttm_pool_populate(ttm, ctx);
1329*4882a593Smuzhiyun 	}
1330*4882a593Smuzhiyun #endif
1331*4882a593Smuzhiyun 
1332*4882a593Smuzhiyun #if IS_ENABLED(CONFIG_SWIOTLB) && IS_ENABLED(CONFIG_X86)
1333*4882a593Smuzhiyun 	if (swiotlb_nr_tbl()) {
1334*4882a593Smuzhiyun 		return ttm_dma_populate((void *)ttm, dev, ctx);
1335*4882a593Smuzhiyun 	}
1336*4882a593Smuzhiyun #endif
1337*4882a593Smuzhiyun 	return ttm_populate_and_map_pages(dev, ttm_dma, ctx);
1338*4882a593Smuzhiyun }
1339*4882a593Smuzhiyun 
1340*4882a593Smuzhiyun static void
nouveau_ttm_tt_unpopulate(struct ttm_bo_device * bdev,struct ttm_tt * ttm)1341*4882a593Smuzhiyun nouveau_ttm_tt_unpopulate(struct ttm_bo_device *bdev,
1342*4882a593Smuzhiyun 			  struct ttm_tt *ttm)
1343*4882a593Smuzhiyun {
1344*4882a593Smuzhiyun 	struct ttm_dma_tt *ttm_dma = (void *)ttm;
1345*4882a593Smuzhiyun 	struct nouveau_drm *drm;
1346*4882a593Smuzhiyun 	struct device *dev;
1347*4882a593Smuzhiyun 	bool slave = !!(ttm->page_flags & TTM_PAGE_FLAG_SG);
1348*4882a593Smuzhiyun 
1349*4882a593Smuzhiyun 	if (slave)
1350*4882a593Smuzhiyun 		return;
1351*4882a593Smuzhiyun 
1352*4882a593Smuzhiyun 	drm = nouveau_bdev(bdev);
1353*4882a593Smuzhiyun 	dev = drm->dev->dev;
1354*4882a593Smuzhiyun 
1355*4882a593Smuzhiyun #if IS_ENABLED(CONFIG_AGP)
1356*4882a593Smuzhiyun 	if (drm->agp.bridge) {
1357*4882a593Smuzhiyun 		ttm_pool_unpopulate(ttm);
1358*4882a593Smuzhiyun 		return;
1359*4882a593Smuzhiyun 	}
1360*4882a593Smuzhiyun #endif
1361*4882a593Smuzhiyun 
1362*4882a593Smuzhiyun #if IS_ENABLED(CONFIG_SWIOTLB) && IS_ENABLED(CONFIG_X86)
1363*4882a593Smuzhiyun 	if (swiotlb_nr_tbl()) {
1364*4882a593Smuzhiyun 		ttm_dma_unpopulate((void *)ttm, dev);
1365*4882a593Smuzhiyun 		return;
1366*4882a593Smuzhiyun 	}
1367*4882a593Smuzhiyun #endif
1368*4882a593Smuzhiyun 
1369*4882a593Smuzhiyun 	ttm_unmap_and_unpopulate_pages(dev, ttm_dma);
1370*4882a593Smuzhiyun }
1371*4882a593Smuzhiyun 
1372*4882a593Smuzhiyun static void
nouveau_ttm_tt_destroy(struct ttm_bo_device * bdev,struct ttm_tt * ttm)1373*4882a593Smuzhiyun nouveau_ttm_tt_destroy(struct ttm_bo_device *bdev,
1374*4882a593Smuzhiyun 		       struct ttm_tt *ttm)
1375*4882a593Smuzhiyun {
1376*4882a593Smuzhiyun #if IS_ENABLED(CONFIG_AGP)
1377*4882a593Smuzhiyun 	struct nouveau_drm *drm = nouveau_bdev(bdev);
1378*4882a593Smuzhiyun 	if (drm->agp.bridge) {
1379*4882a593Smuzhiyun 		ttm_agp_unbind(ttm);
1380*4882a593Smuzhiyun 		ttm_tt_destroy_common(bdev, ttm);
1381*4882a593Smuzhiyun 		ttm_agp_destroy(ttm);
1382*4882a593Smuzhiyun 		return;
1383*4882a593Smuzhiyun 	}
1384*4882a593Smuzhiyun #endif
1385*4882a593Smuzhiyun 	nouveau_sgdma_destroy(bdev, ttm);
1386*4882a593Smuzhiyun }
1387*4882a593Smuzhiyun 
1388*4882a593Smuzhiyun void
nouveau_bo_fence(struct nouveau_bo * nvbo,struct nouveau_fence * fence,bool exclusive)1389*4882a593Smuzhiyun nouveau_bo_fence(struct nouveau_bo *nvbo, struct nouveau_fence *fence, bool exclusive)
1390*4882a593Smuzhiyun {
1391*4882a593Smuzhiyun 	struct dma_resv *resv = nvbo->bo.base.resv;
1392*4882a593Smuzhiyun 
1393*4882a593Smuzhiyun 	if (exclusive)
1394*4882a593Smuzhiyun 		dma_resv_add_excl_fence(resv, &fence->base);
1395*4882a593Smuzhiyun 	else if (fence)
1396*4882a593Smuzhiyun 		dma_resv_add_shared_fence(resv, &fence->base);
1397*4882a593Smuzhiyun }
1398*4882a593Smuzhiyun 
1399*4882a593Smuzhiyun struct ttm_bo_driver nouveau_bo_driver = {
1400*4882a593Smuzhiyun 	.ttm_tt_create = &nouveau_ttm_tt_create,
1401*4882a593Smuzhiyun 	.ttm_tt_populate = &nouveau_ttm_tt_populate,
1402*4882a593Smuzhiyun 	.ttm_tt_unpopulate = &nouveau_ttm_tt_unpopulate,
1403*4882a593Smuzhiyun 	.ttm_tt_bind = &nouveau_ttm_tt_bind,
1404*4882a593Smuzhiyun 	.ttm_tt_unbind = &nouveau_ttm_tt_unbind,
1405*4882a593Smuzhiyun 	.ttm_tt_destroy = &nouveau_ttm_tt_destroy,
1406*4882a593Smuzhiyun 	.eviction_valuable = ttm_bo_eviction_valuable,
1407*4882a593Smuzhiyun 	.evict_flags = nouveau_bo_evict_flags,
1408*4882a593Smuzhiyun 	.move_notify = nouveau_bo_move_ntfy,
1409*4882a593Smuzhiyun 	.move = nouveau_bo_move,
1410*4882a593Smuzhiyun 	.verify_access = nouveau_bo_verify_access,
1411*4882a593Smuzhiyun 	.fault_reserve_notify = &nouveau_ttm_fault_reserve_notify,
1412*4882a593Smuzhiyun 	.io_mem_reserve = &nouveau_ttm_io_mem_reserve,
1413*4882a593Smuzhiyun 	.io_mem_free = &nouveau_ttm_io_mem_free,
1414*4882a593Smuzhiyun };
1415