xref: /openbmc/linux/drivers/gpu/drm/nouveau/nouveau_bo.c (revision 7b7fd0ac7dc1ffcaf24d9bca0f051b0168e43cd4)
16ee73861SBen Skeggs /*
26ee73861SBen Skeggs  * Copyright 2007 Dave Airlied
36ee73861SBen Skeggs  * All Rights Reserved.
46ee73861SBen Skeggs  *
56ee73861SBen Skeggs  * Permission is hereby granted, free of charge, to any person obtaining a
66ee73861SBen Skeggs  * copy of this software and associated documentation files (the "Software"),
76ee73861SBen Skeggs  * to deal in the Software without restriction, including without limitation
86ee73861SBen Skeggs  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
96ee73861SBen Skeggs  * and/or sell copies of the Software, and to permit persons to whom the
106ee73861SBen Skeggs  * Software is furnished to do so, subject to the following conditions:
116ee73861SBen Skeggs  *
126ee73861SBen Skeggs  * The above copyright notice and this permission notice (including the next
136ee73861SBen Skeggs  * paragraph) shall be included in all copies or substantial portions of the
146ee73861SBen Skeggs  * Software.
156ee73861SBen Skeggs  *
166ee73861SBen Skeggs  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
176ee73861SBen Skeggs  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
186ee73861SBen Skeggs  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
196ee73861SBen Skeggs  * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
206ee73861SBen Skeggs  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
216ee73861SBen Skeggs  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
226ee73861SBen Skeggs  * OTHER DEALINGS IN THE SOFTWARE.
236ee73861SBen Skeggs  */
246ee73861SBen Skeggs /*
256ee73861SBen Skeggs  * Authors: Dave Airlied <airlied@linux.ie>
266ee73861SBen Skeggs  *	    Ben Skeggs   <darktama@iinet.net.au>
276ee73861SBen Skeggs  *	    Jeremy Kolb  <jkolb@brandeis.edu>
286ee73861SBen Skeggs  */
296ee73861SBen Skeggs 
30fdb751efSBen Skeggs #include <linux/dma-mapping.h>
31a3185f91SChristian König #include <drm/ttm/ttm_tt.h>
326ee73861SBen Skeggs 
334dc28134SBen Skeggs #include "nouveau_drv.h"
348b9d5d63SBen Skeggs #include "nouveau_chan.h"
35d375e7d5SBen Skeggs #include "nouveau_fence.h"
366ee73861SBen Skeggs 
37ebb945a9SBen Skeggs #include "nouveau_bo.h"
38ebb945a9SBen Skeggs #include "nouveau_ttm.h"
39ebb945a9SBen Skeggs #include "nouveau_gem.h"
409ce523ccSBen Skeggs #include "nouveau_mem.h"
4124e8375bSBen Skeggs #include "nouveau_vmm.h"
42a510604dSMaarten Maathuis 
43d7722134SBen Skeggs #include <nvif/class.h>
44d7722134SBen Skeggs #include <nvif/if500b.h>
45d7722134SBen Skeggs #include <nvif/if900b.h>
46d7722134SBen Skeggs 
478af8a109SChristian König static int nouveau_ttm_tt_bind(struct ttm_device *bdev, struct ttm_tt *ttm,
48cae515f4SDave Airlie 			       struct ttm_resource *reg);
498af8a109SChristian König static void nouveau_ttm_tt_unbind(struct ttm_device *bdev, struct ttm_tt *ttm);
50cae515f4SDave Airlie 
51bc9e7b9aSBen Skeggs /*
52bc9e7b9aSBen Skeggs  * NV10-NV40 tiling helpers
53bc9e7b9aSBen Skeggs  */
54bc9e7b9aSBen Skeggs 
55bc9e7b9aSBen Skeggs static void
nv10_bo_update_tile_region(struct drm_device * dev,struct nouveau_drm_tile * reg,u32 addr,u32 size,u32 pitch,u32 flags)56ebb945a9SBen Skeggs nv10_bo_update_tile_region(struct drm_device *dev, struct nouveau_drm_tile *reg,
57ebb945a9SBen Skeggs 			   u32 addr, u32 size, u32 pitch, u32 flags)
58bc9e7b9aSBen Skeggs {
5977145f1cSBen Skeggs 	struct nouveau_drm *drm = nouveau_drm(dev);
60ebb945a9SBen Skeggs 	int i = reg - drm->tile.reg;
61359088d5SBen Skeggs 	struct nvkm_fb *fb = nvxx_fb(&drm->client.device);
62b1e4553cSBen Skeggs 	struct nvkm_fb_tile *tile = &fb->tile.region[i];
63bc9e7b9aSBen Skeggs 
64ebb945a9SBen Skeggs 	nouveau_fence_unref(&reg->fence);
65bc9e7b9aSBen Skeggs 
66bc9e7b9aSBen Skeggs 	if (tile->pitch)
6703c8952fSBen Skeggs 		nvkm_fb_tile_fini(fb, i, tile);
68bc9e7b9aSBen Skeggs 
69bc9e7b9aSBen Skeggs 	if (pitch)
7003c8952fSBen Skeggs 		nvkm_fb_tile_init(fb, i, addr, size, pitch, flags, tile);
71bc9e7b9aSBen Skeggs 
7203c8952fSBen Skeggs 	nvkm_fb_tile_prog(fb, i, tile);
73bc9e7b9aSBen Skeggs }
74bc9e7b9aSBen Skeggs 
75ebb945a9SBen Skeggs static struct nouveau_drm_tile *
nv10_bo_get_tile_region(struct drm_device * dev,int i)76bc9e7b9aSBen Skeggs nv10_bo_get_tile_region(struct drm_device *dev, int i)
77bc9e7b9aSBen Skeggs {
7877145f1cSBen Skeggs 	struct nouveau_drm *drm = nouveau_drm(dev);
79ebb945a9SBen Skeggs 	struct nouveau_drm_tile *tile = &drm->tile.reg[i];
80bc9e7b9aSBen Skeggs 
81ebb945a9SBen Skeggs 	spin_lock(&drm->tile.lock);
82bc9e7b9aSBen Skeggs 
83bc9e7b9aSBen Skeggs 	if (!tile->used &&
84bc9e7b9aSBen Skeggs 	    (!tile->fence || nouveau_fence_done(tile->fence)))
85bc9e7b9aSBen Skeggs 		tile->used = true;
86bc9e7b9aSBen Skeggs 	else
87bc9e7b9aSBen Skeggs 		tile = NULL;
88bc9e7b9aSBen Skeggs 
89ebb945a9SBen Skeggs 	spin_unlock(&drm->tile.lock);
90bc9e7b9aSBen Skeggs 	return tile;
91bc9e7b9aSBen Skeggs }
92bc9e7b9aSBen Skeggs 
93bc9e7b9aSBen Skeggs static void
nv10_bo_put_tile_region(struct drm_device * dev,struct nouveau_drm_tile * tile,struct dma_fence * fence)94ebb945a9SBen Skeggs nv10_bo_put_tile_region(struct drm_device *dev, struct nouveau_drm_tile *tile,
95f54d1867SChris Wilson 			struct dma_fence *fence)
96bc9e7b9aSBen Skeggs {
9777145f1cSBen Skeggs 	struct nouveau_drm *drm = nouveau_drm(dev);
98bc9e7b9aSBen Skeggs 
99bc9e7b9aSBen Skeggs 	if (tile) {
100ebb945a9SBen Skeggs 		spin_lock(&drm->tile.lock);
101f54d1867SChris Wilson 		tile->fence = (struct nouveau_fence *)dma_fence_get(fence);
102bc9e7b9aSBen Skeggs 		tile->used = false;
103ebb945a9SBen Skeggs 		spin_unlock(&drm->tile.lock);
104bc9e7b9aSBen Skeggs 	}
105bc9e7b9aSBen Skeggs }
106bc9e7b9aSBen Skeggs 
107ebb945a9SBen Skeggs static struct nouveau_drm_tile *
nv10_bo_set_tiling(struct drm_device * dev,u32 addr,u32 size,u32 pitch,u32 zeta)108ebb945a9SBen Skeggs nv10_bo_set_tiling(struct drm_device *dev, u32 addr,
1097760a2e3SBen Skeggs 		   u32 size, u32 pitch, u32 zeta)
110bc9e7b9aSBen Skeggs {
11177145f1cSBen Skeggs 	struct nouveau_drm *drm = nouveau_drm(dev);
1121167c6bcSBen Skeggs 	struct nvkm_fb *fb = nvxx_fb(&drm->client.device);
113ebb945a9SBen Skeggs 	struct nouveau_drm_tile *tile, *found = NULL;
114bc9e7b9aSBen Skeggs 	int i;
115bc9e7b9aSBen Skeggs 
116b1e4553cSBen Skeggs 	for (i = 0; i < fb->tile.regions; i++) {
117bc9e7b9aSBen Skeggs 		tile = nv10_bo_get_tile_region(dev, i);
118bc9e7b9aSBen Skeggs 
119bc9e7b9aSBen Skeggs 		if (pitch && !found) {
120bc9e7b9aSBen Skeggs 			found = tile;
121bc9e7b9aSBen Skeggs 			continue;
122bc9e7b9aSBen Skeggs 
123b1e4553cSBen Skeggs 		} else if (tile && fb->tile.region[i].pitch) {
124bc9e7b9aSBen Skeggs 			/* Kill an unused tile region. */
125bc9e7b9aSBen Skeggs 			nv10_bo_update_tile_region(dev, tile, 0, 0, 0, 0);
126bc9e7b9aSBen Skeggs 		}
127bc9e7b9aSBen Skeggs 
128bc9e7b9aSBen Skeggs 		nv10_bo_put_tile_region(dev, tile, NULL);
129bc9e7b9aSBen Skeggs 	}
130bc9e7b9aSBen Skeggs 
131bc9e7b9aSBen Skeggs 	if (found)
1327760a2e3SBen Skeggs 		nv10_bo_update_tile_region(dev, found, addr, size, pitch, zeta);
133bc9e7b9aSBen Skeggs 	return found;
134bc9e7b9aSBen Skeggs }
135bc9e7b9aSBen Skeggs 
1366ee73861SBen Skeggs static void
nouveau_bo_del_ttm(struct ttm_buffer_object * bo)1376ee73861SBen Skeggs nouveau_bo_del_ttm(struct ttm_buffer_object *bo)
1386ee73861SBen Skeggs {
139ebb945a9SBen Skeggs 	struct nouveau_drm *drm = nouveau_bdev(bo->bdev);
140ebb945a9SBen Skeggs 	struct drm_device *dev = drm->dev;
1416ee73861SBen Skeggs 	struct nouveau_bo *nvbo = nouveau_bo(bo);
1426ee73861SBen Skeggs 
1436797cea1SChristian König 	WARN_ON(nvbo->bo.pin_count > 0);
144141b15e5SChristian König 	nouveau_bo_del_io_reserve_lru(bo);
145bc9e7b9aSBen Skeggs 	nv10_bo_put_tile_region(dev, nvbo->tile, NULL);
146641f53c0SThierry Reding 
147641f53c0SThierry Reding 	/*
148641f53c0SThierry Reding 	 * If nouveau_bo_new() allocated this buffer, the GEM object was never
149641f53c0SThierry Reding 	 * initialized, so don't attempt to release it.
150641f53c0SThierry Reding 	 */
151641f53c0SThierry Reding 	if (bo->base.dev)
152641f53c0SThierry Reding 		drm_gem_object_release(&bo->base);
153d098775eSChristian König 	else
154d098775eSChristian König 		dma_resv_fini(&bo->base._resv);
155641f53c0SThierry Reding 
1566ee73861SBen Skeggs 	kfree(nvbo);
1576ee73861SBen Skeggs }
1586ee73861SBen Skeggs 
1594d8b3d34SBen Skeggs static inline u64
roundup_64(u64 x,u32 y)1604d8b3d34SBen Skeggs roundup_64(u64 x, u32 y)
1614d8b3d34SBen Skeggs {
1624d8b3d34SBen Skeggs 	x += y - 1;
1634d8b3d34SBen Skeggs 	do_div(x, y);
1644d8b3d34SBen Skeggs 	return x * y;
1654d8b3d34SBen Skeggs }
1664d8b3d34SBen Skeggs 
167a0af9addSFrancisco Jerez static void
nouveau_bo_fixup_align(struct nouveau_bo * nvbo,int * align,u64 * size)16881b61579SChristian König nouveau_bo_fixup_align(struct nouveau_bo *nvbo, int *align, u64 *size)
169a0af9addSFrancisco Jerez {
170ebb945a9SBen Skeggs 	struct nouveau_drm *drm = nouveau_bdev(nvbo->bo.bdev);
1711167c6bcSBen Skeggs 	struct nvif_device *device = &drm->client.device;
172a0af9addSFrancisco Jerez 
173967e7bdeSBen Skeggs 	if (device->info.family < NV_DEVICE_INFO_V0_TESLA) {
1747760a2e3SBen Skeggs 		if (nvbo->mode) {
175967e7bdeSBen Skeggs 			if (device->info.chipset >= 0x40) {
176a0af9addSFrancisco Jerez 				*align = 65536;
1777760a2e3SBen Skeggs 				*size = roundup_64(*size, 64 * nvbo->mode);
178a0af9addSFrancisco Jerez 
179967e7bdeSBen Skeggs 			} else if (device->info.chipset >= 0x30) {
180a0af9addSFrancisco Jerez 				*align = 32768;
1817760a2e3SBen Skeggs 				*size = roundup_64(*size, 64 * nvbo->mode);
182a0af9addSFrancisco Jerez 
183967e7bdeSBen Skeggs 			} else if (device->info.chipset >= 0x20) {
184a0af9addSFrancisco Jerez 				*align = 16384;
1857760a2e3SBen Skeggs 				*size = roundup_64(*size, 64 * nvbo->mode);
186a0af9addSFrancisco Jerez 
187967e7bdeSBen Skeggs 			} else if (device->info.chipset >= 0x10) {
188a0af9addSFrancisco Jerez 				*align = 16384;
1897760a2e3SBen Skeggs 				*size = roundup_64(*size, 32 * nvbo->mode);
190a0af9addSFrancisco Jerez 			}
191a0af9addSFrancisco Jerez 		}
192bfd83acaSBen Skeggs 	} else {
1937760a2e3SBen Skeggs 		*size = roundup_64(*size, (1 << nvbo->page));
1947760a2e3SBen Skeggs 		*align = max((1 <<  nvbo->page), *align);
195a0af9addSFrancisco Jerez 	}
196bfd83acaSBen Skeggs 
1974d8b3d34SBen Skeggs 	*size = roundup_64(*size, PAGE_SIZE);
198a0af9addSFrancisco Jerez }
199a0af9addSFrancisco Jerez 
200019cbd4aSThierry Reding struct nouveau_bo *
nouveau_bo_alloc(struct nouveau_cli * cli,u64 * size,int * align,u32 domain,u32 tile_mode,u32 tile_flags,bool internal)20181b61579SChristian König nouveau_bo_alloc(struct nouveau_cli *cli, u64 *size, int *align, u32 domain,
202b88baab8SDanilo Krummrich 		 u32 tile_mode, u32 tile_flags, bool internal)
2036ee73861SBen Skeggs {
204e75c091bSBen Skeggs 	struct nouveau_drm *drm = cli->drm;
2056ee73861SBen Skeggs 	struct nouveau_bo *nvbo;
206a220dd73SBen Skeggs 	struct nvif_mmu *mmu = &cli->mmu;
2077b05a7c0SDanilo Krummrich 	struct nvif_vmm *vmm = &nouveau_cli_vmm(cli)->vmm;
208019cbd4aSThierry Reding 	int i, pi = -1;
20935095f75SMaarten Lankhorst 
2109ca7f796SThierry Reding 	if (!*size) {
2119ca7f796SThierry Reding 		NV_WARN(drm, "skipped size %016llx\n", *size);
212019cbd4aSThierry Reding 		return ERR_PTR(-EINVAL);
2130108bc80SMaarten Lankhorst 	}
21422b33e8eSDave Airlie 
2156ee73861SBen Skeggs 	nvbo = kzalloc(sizeof(struct nouveau_bo), GFP_KERNEL);
2166ee73861SBen Skeggs 	if (!nvbo)
217019cbd4aSThierry Reding 		return ERR_PTR(-ENOMEM);
218a7f7d13eSDanilo Krummrich 
2196ee73861SBen Skeggs 	INIT_LIST_HEAD(&nvbo->head);
2206ee73861SBen Skeggs 	INIT_LIST_HEAD(&nvbo->entry);
221fd2871afSBen Skeggs 	INIT_LIST_HEAD(&nvbo->vma_list);
222ebb945a9SBen Skeggs 	nvbo->bo.bdev = &drm->ttm.bdev;
2236ee73861SBen Skeggs 
224acb16cfaSBen Skeggs 	/* This is confusing, and doesn't actually mean we want an uncached
225acb16cfaSBen Skeggs 	 * mapping, but is what NOUVEAU_GEM_DOMAIN_COHERENT gets translated
226acb16cfaSBen Skeggs 	 * into in nouveau_gem_new().
227acb16cfaSBen Skeggs 	 */
22881b61579SChristian König 	if (domain & NOUVEAU_GEM_DOMAIN_COHERENT) {
229acb16cfaSBen Skeggs 		/* Determine if we can get a cache-coherent map, forcing
230acb16cfaSBen Skeggs 		 * uncached mapping if we can't.
231acb16cfaSBen Skeggs 		 */
23274a39954SBen Skeggs 		if (!nouveau_drm_use_coherent_gpu_mapping(drm))
233acb16cfaSBen Skeggs 			nvbo->force_coherent = true;
234acb16cfaSBen Skeggs 	}
235c3a0c771SAlexandre Courbot 
236b88baab8SDanilo Krummrich 	nvbo->contig = !(tile_flags & NOUVEAU_GEM_TILE_NONCONTIG);
2373652ac87SMohamed Ahmed 
2387760a2e3SBen Skeggs 	if (cli->device.info.family >= NV_DEVICE_INFO_V0_FERMI) {
2397760a2e3SBen Skeggs 		nvbo->kind = (tile_flags & 0x0000ff00) >> 8;
240a220dd73SBen Skeggs 		if (!nvif_mmu_kind_valid(mmu, nvbo->kind)) {
241a220dd73SBen Skeggs 			kfree(nvbo);
242019cbd4aSThierry Reding 			return ERR_PTR(-EINVAL);
243a220dd73SBen Skeggs 		}
244a220dd73SBen Skeggs 
245a220dd73SBen Skeggs 		nvbo->comp = mmu->kind[nvbo->kind] != nvbo->kind;
246b88baab8SDanilo Krummrich 	} else if (cli->device.info.family >= NV_DEVICE_INFO_V0_TESLA) {
2477760a2e3SBen Skeggs 		nvbo->kind = (tile_flags & 0x00007f00) >> 8;
2487760a2e3SBen Skeggs 		nvbo->comp = (tile_flags & 0x00030000) >> 16;
249a220dd73SBen Skeggs 		if (!nvif_mmu_kind_valid(mmu, nvbo->kind)) {
250a220dd73SBen Skeggs 			kfree(nvbo);
251019cbd4aSThierry Reding 			return ERR_PTR(-EINVAL);
252a220dd73SBen Skeggs 		}
2537760a2e3SBen Skeggs 	} else {
2547760a2e3SBen Skeggs 		nvbo->zeta = (tile_flags & 0x00000007);
2557760a2e3SBen Skeggs 	}
2567760a2e3SBen Skeggs 	nvbo->mode = tile_mode;
2577760a2e3SBen Skeggs 
2583652ac87SMohamed Ahmed 	if (!nouveau_cli_uvmm(cli) || internal) {
2597dc6a446SBen Skeggs 		/* Determine the desirable target GPU page size for the buffer. */
2607dc6a446SBen Skeggs 		for (i = 0; i < vmm->page_nr; i++) {
2617dc6a446SBen Skeggs 			/* Because we cannot currently allow VMM maps to fail
2627dc6a446SBen Skeggs 			 * during buffer migration, we need to determine page
2637dc6a446SBen Skeggs 			 * size for the buffer up-front, and pre-allocate its
2647dc6a446SBen Skeggs 			 * page tables.
2657dc6a446SBen Skeggs 			 *
2667dc6a446SBen Skeggs 			 * Skip page sizes that can't support needed domains.
2677dc6a446SBen Skeggs 			 */
2687dc6a446SBen Skeggs 			if (cli->device.info.family > NV_DEVICE_INFO_V0_CURIE &&
26981b61579SChristian König 			    (domain & NOUVEAU_GEM_DOMAIN_VRAM) && !vmm->page[i].vram)
2707dc6a446SBen Skeggs 				continue;
27181b61579SChristian König 			if ((domain & NOUVEAU_GEM_DOMAIN_GART) &&
272f29f18ebSBen Skeggs 			    (!vmm->page[i].host || vmm->page[i].shift > PAGE_SHIFT))
2737dc6a446SBen Skeggs 				continue;
2747dc6a446SBen Skeggs 
2757dc6a446SBen Skeggs 			/* Select this page size if it's the first that supports
2767dc6a446SBen Skeggs 			 * the potential memory domains, or when it's compatible
2777dc6a446SBen Skeggs 			 * with the requested compression settings.
2787dc6a446SBen Skeggs 			 */
2797dc6a446SBen Skeggs 			if (pi < 0 || !nvbo->comp || vmm->page[i].comp)
2807dc6a446SBen Skeggs 				pi = i;
2817dc6a446SBen Skeggs 
2827dc6a446SBen Skeggs 			/* Stop once the buffer is larger than the current page size. */
2839ca7f796SThierry Reding 			if (*size >= 1ULL << vmm->page[i].shift)
2847dc6a446SBen Skeggs 				break;
2857dc6a446SBen Skeggs 		}
2867dc6a446SBen Skeggs 
2876dc54874SJianglei Nie 		if (WARN_ON(pi < 0)) {
2886dc54874SJianglei Nie 			kfree(nvbo);
289019cbd4aSThierry Reding 			return ERR_PTR(-EINVAL);
2906dc54874SJianglei Nie 		}
2917dc6a446SBen Skeggs 
2927dc6a446SBen Skeggs 		/* Disable compression if suitable settings couldn't be found. */
2937dc6a446SBen Skeggs 		if (nvbo->comp && !vmm->page[pi].comp) {
2947dc6a446SBen Skeggs 			if (mmu->object.oclass >= NVIF_CLASS_MMU_GF100)
295a220dd73SBen Skeggs 				nvbo->kind = mmu->kind[nvbo->kind];
2967760a2e3SBen Skeggs 			nvbo->comp = 0;
2977760a2e3SBen Skeggs 		}
2987dc6a446SBen Skeggs 		nvbo->page = vmm->page[pi].shift;
299b88baab8SDanilo Krummrich 	} else {
300b88baab8SDanilo Krummrich 		/* Determine the desirable target GPU page size for the buffer. */
301b88baab8SDanilo Krummrich 		for (i = 0; i < vmm->page_nr; i++) {
302b88baab8SDanilo Krummrich 			/* Because we cannot currently allow VMM maps to fail
303b88baab8SDanilo Krummrich 			 * during buffer migration, we need to determine page
304b88baab8SDanilo Krummrich 			 * size for the buffer up-front, and pre-allocate its
305b88baab8SDanilo Krummrich 			 * page tables.
306b88baab8SDanilo Krummrich 			 *
307b88baab8SDanilo Krummrich 			 * Skip page sizes that can't support needed domains.
308b88baab8SDanilo Krummrich 			 */
309b88baab8SDanilo Krummrich 			if ((domain & NOUVEAU_GEM_DOMAIN_VRAM) && !vmm->page[i].vram)
310b88baab8SDanilo Krummrich 				continue;
311b88baab8SDanilo Krummrich 			if ((domain & NOUVEAU_GEM_DOMAIN_GART) &&
312b88baab8SDanilo Krummrich 			    (!vmm->page[i].host || vmm->page[i].shift > PAGE_SHIFT))
313b88baab8SDanilo Krummrich 				continue;
314b88baab8SDanilo Krummrich 
31559ae50ebSDave Airlie 			/* pick the last one as it will be smallest. */
316b88baab8SDanilo Krummrich 			pi = i;
31759ae50ebSDave Airlie 
318b88baab8SDanilo Krummrich 			/* Stop once the buffer is larger than the current page size. */
319b88baab8SDanilo Krummrich 			if (*size >= 1ULL << vmm->page[i].shift)
320b88baab8SDanilo Krummrich 				break;
321b88baab8SDanilo Krummrich 		}
322b88baab8SDanilo Krummrich 		if (WARN_ON(pi < 0)) {
323b88baab8SDanilo Krummrich 			kfree(nvbo);
324b88baab8SDanilo Krummrich 			return ERR_PTR(-EINVAL);
325b88baab8SDanilo Krummrich 		}
326b88baab8SDanilo Krummrich 		nvbo->page = vmm->page[pi].shift;
327b88baab8SDanilo Krummrich 	}
328f91bac5bSBen Skeggs 
32981b61579SChristian König 	nouveau_bo_fixup_align(nvbo, align, size);
3309ca7f796SThierry Reding 
331019cbd4aSThierry Reding 	return nvbo;
332019cbd4aSThierry Reding }
333019cbd4aSThierry Reding 
334019cbd4aSThierry Reding int
nouveau_bo_init(struct nouveau_bo * nvbo,u64 size,int align,u32 domain,struct sg_table * sg,struct dma_resv * robj)33581b61579SChristian König nouveau_bo_init(struct nouveau_bo *nvbo, u64 size, int align, u32 domain,
336019cbd4aSThierry Reding 		struct sg_table *sg, struct dma_resv *robj)
337019cbd4aSThierry Reding {
338019cbd4aSThierry Reding 	int type = sg ? ttm_bo_type_sg : ttm_bo_type_device;
339019cbd4aSThierry Reding 	int ret;
340b88baab8SDanilo Krummrich 	struct ttm_operation_ctx ctx = {
341b88baab8SDanilo Krummrich 		.interruptible = false,
342b88baab8SDanilo Krummrich 		.no_wait_gpu = false,
343b88baab8SDanilo Krummrich 		.resv = robj,
344b88baab8SDanilo Krummrich 	};
345019cbd4aSThierry Reding 
34681b61579SChristian König 	nouveau_bo_placement_set(nvbo, domain, 0);
347141b15e5SChristian König 	INIT_LIST_HEAD(&nvbo->io_reserve_lru);
3486ee73861SBen Skeggs 
349b88baab8SDanilo Krummrich 	ret = ttm_bo_init_reserved(nvbo->bo.bdev, &nvbo->bo, type,
350b88baab8SDanilo Krummrich 				   &nvbo->placement, align >> PAGE_SHIFT, &ctx,
351347987a2SChristian König 				   sg, robj, nouveau_bo_del_ttm);
3526ee73861SBen Skeggs 	if (ret) {
3536ee73861SBen Skeggs 		/* ttm will call nouveau_bo_del_ttm if it fails.. */
3546ee73861SBen Skeggs 		return ret;
3556ee73861SBen Skeggs 	}
3566ee73861SBen Skeggs 
357b88baab8SDanilo Krummrich 	if (!robj)
358b88baab8SDanilo Krummrich 		ttm_bo_unreserve(&nvbo->bo);
359b88baab8SDanilo Krummrich 
360019cbd4aSThierry Reding 	return 0;
361019cbd4aSThierry Reding }
362019cbd4aSThierry Reding 
363019cbd4aSThierry Reding 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)364019cbd4aSThierry Reding nouveau_bo_new(struct nouveau_cli *cli, u64 size, int align,
36581b61579SChristian König 	       uint32_t domain, uint32_t tile_mode, uint32_t tile_flags,
366019cbd4aSThierry Reding 	       struct sg_table *sg, struct dma_resv *robj,
367019cbd4aSThierry Reding 	       struct nouveau_bo **pnvbo)
368019cbd4aSThierry Reding {
369019cbd4aSThierry Reding 	struct nouveau_bo *nvbo;
370019cbd4aSThierry Reding 	int ret;
371019cbd4aSThierry Reding 
37281b61579SChristian König 	nvbo = nouveau_bo_alloc(cli, &size, &align, domain, tile_mode,
373b88baab8SDanilo Krummrich 				tile_flags, true);
374019cbd4aSThierry Reding 	if (IS_ERR(nvbo))
375019cbd4aSThierry Reding 		return PTR_ERR(nvbo);
376019cbd4aSThierry Reding 
377d098775eSChristian König 	nvbo->bo.base.size = size;
378d098775eSChristian König 	dma_resv_init(&nvbo->bo.base._resv);
379d098775eSChristian König 	drm_vma_node_reset(&nvbo->bo.base.vma_node);
380d098775eSChristian König 
381a7f7d13eSDanilo Krummrich 	/* This must be called before ttm_bo_init_reserved(). Subsequent
382a7f7d13eSDanilo Krummrich 	 * bo_move() callbacks might already iterate the GEMs GPUVA list.
383a7f7d13eSDanilo Krummrich 	 */
384a7f7d13eSDanilo Krummrich 	drm_gem_gpuva_init(&nvbo->bo.base);
385a7f7d13eSDanilo Krummrich 
38681b61579SChristian König 	ret = nouveau_bo_init(nvbo, size, align, domain, sg, robj);
387019cbd4aSThierry Reding 	if (ret)
388019cbd4aSThierry Reding 		return ret;
389019cbd4aSThierry Reding 
3906ee73861SBen Skeggs 	*pnvbo = nvbo;
3916ee73861SBen Skeggs 	return 0;
3926ee73861SBen Skeggs }
3936ee73861SBen Skeggs 
39478ad0f7bSFrancisco Jerez static void
set_placement_list(struct ttm_place * pl,unsigned * n,uint32_t domain)395ce65b874SChristian König set_placement_list(struct ttm_place *pl, unsigned *n, uint32_t domain)
3966ee73861SBen Skeggs {
39778ad0f7bSFrancisco Jerez 	*n = 0;
3986ee73861SBen Skeggs 
39948e07c23SChristian König 	if (domain & NOUVEAU_GEM_DOMAIN_VRAM) {
40048e07c23SChristian König 		pl[*n].mem_type = TTM_PL_VRAM;
401ce65b874SChristian König 		pl[*n].flags = 0;
4025839172fSChristian König 		(*n)++;
40348e07c23SChristian König 	}
40448e07c23SChristian König 	if (domain & NOUVEAU_GEM_DOMAIN_GART) {
40548e07c23SChristian König 		pl[*n].mem_type = TTM_PL_TT;
406ce65b874SChristian König 		pl[*n].flags = 0;
4075839172fSChristian König 		(*n)++;
40848e07c23SChristian König 	}
40948e07c23SChristian König 	if (domain & NOUVEAU_GEM_DOMAIN_CPU) {
41048e07c23SChristian König 		pl[*n].mem_type = TTM_PL_SYSTEM;
411ce65b874SChristian König 		pl[(*n)++].flags = 0;
41248e07c23SChristian König 	}
41337cb3e08SBen Skeggs }
41478ad0f7bSFrancisco Jerez 
415699ddfd9SFrancisco Jerez static void
set_placement_range(struct nouveau_bo * nvbo,uint32_t domain)41681b61579SChristian König set_placement_range(struct nouveau_bo *nvbo, uint32_t domain)
417699ddfd9SFrancisco Jerez {
418ebb945a9SBen Skeggs 	struct nouveau_drm *drm = nouveau_bdev(nvbo->bo.bdev);
419aeaf45c5SChristian König 	u64 vram_size = drm->client.device.info.ram_size;
420f1217ed0SChristian König 	unsigned i, fpfn, lpfn;
421699ddfd9SFrancisco Jerez 
4221167c6bcSBen Skeggs 	if (drm->client.device.info.family == NV_DEVICE_INFO_V0_CELSIUS &&
42381b61579SChristian König 	    nvbo->mode && (domain & NOUVEAU_GEM_DOMAIN_VRAM) &&
424aeaf45c5SChristian König 	    nvbo->bo.base.size < vram_size / 4) {
425699ddfd9SFrancisco Jerez 		/*
426699ddfd9SFrancisco Jerez 		 * Make sure that the color and depth buffers are handled
427699ddfd9SFrancisco Jerez 		 * by independent memory controller units. Up to a 9x
428699ddfd9SFrancisco Jerez 		 * speed up when alpha-blending and depth-test are enabled
429699ddfd9SFrancisco Jerez 		 * at the same time.
430699ddfd9SFrancisco Jerez 		 */
4317760a2e3SBen Skeggs 		if (nvbo->zeta) {
432aeaf45c5SChristian König 			fpfn = (vram_size / 2) >> PAGE_SHIFT;
433f1217ed0SChristian König 			lpfn = ~0;
434699ddfd9SFrancisco Jerez 		} else {
435f1217ed0SChristian König 			fpfn = 0;
436aeaf45c5SChristian König 			lpfn = (vram_size / 2) >> PAGE_SHIFT;
437f1217ed0SChristian König 		}
438f1217ed0SChristian König 		for (i = 0; i < nvbo->placement.num_placement; ++i) {
439f1217ed0SChristian König 			nvbo->placements[i].fpfn = fpfn;
440f1217ed0SChristian König 			nvbo->placements[i].lpfn = lpfn;
441f1217ed0SChristian König 		}
442f1217ed0SChristian König 		for (i = 0; i < nvbo->placement.num_busy_placement; ++i) {
443f1217ed0SChristian König 			nvbo->busy_placements[i].fpfn = fpfn;
444f1217ed0SChristian König 			nvbo->busy_placements[i].lpfn = lpfn;
445699ddfd9SFrancisco Jerez 		}
446699ddfd9SFrancisco Jerez 	}
447699ddfd9SFrancisco Jerez }
448699ddfd9SFrancisco Jerez 
44978ad0f7bSFrancisco Jerez void
nouveau_bo_placement_set(struct nouveau_bo * nvbo,uint32_t domain,uint32_t busy)45081b61579SChristian König nouveau_bo_placement_set(struct nouveau_bo *nvbo, uint32_t domain,
45181b61579SChristian König 			 uint32_t busy)
45278ad0f7bSFrancisco Jerez {
45378ad0f7bSFrancisco Jerez 	struct ttm_placement *pl = &nvbo->placement;
45478ad0f7bSFrancisco Jerez 
45578ad0f7bSFrancisco Jerez 	pl->placement = nvbo->placements;
456ce65b874SChristian König 	set_placement_list(nvbo->placements, &pl->num_placement, domain);
45778ad0f7bSFrancisco Jerez 
45878ad0f7bSFrancisco Jerez 	pl->busy_placement = nvbo->busy_placements;
459ce65b874SChristian König 	set_placement_list(nvbo->busy_placements, &pl->num_busy_placement,
460ce65b874SChristian König 			   domain | busy);
461699ddfd9SFrancisco Jerez 
46281b61579SChristian König 	set_placement_range(nvbo, domain);
4636ee73861SBen Skeggs }
4646ee73861SBen Skeggs 
4656ee73861SBen Skeggs int
nouveau_bo_pin(struct nouveau_bo * nvbo,uint32_t domain,bool contig)46681b61579SChristian König nouveau_bo_pin(struct nouveau_bo *nvbo, uint32_t domain, bool contig)
4676ee73861SBen Skeggs {
468ebb945a9SBen Skeggs 	struct nouveau_drm *drm = nouveau_bdev(nvbo->bo.bdev);
4696ee73861SBen Skeggs 	struct ttm_buffer_object *bo = &nvbo->bo;
470ad76b3f7SBen Skeggs 	bool force = false, evict = false;
47178ad0f7bSFrancisco Jerez 	int ret;
4726ee73861SBen Skeggs 
473dfd5e50eSChristian König 	ret = ttm_bo_reserve(bo, false, false, NULL);
4740ae6d7bcSDaniel Vetter 	if (ret)
47550ab2e52SBen Skeggs 		return ret;
4760ae6d7bcSDaniel Vetter 
4771167c6bcSBen Skeggs 	if (drm->client.device.info.family >= NV_DEVICE_INFO_V0_TESLA &&
47881b61579SChristian König 	    domain == NOUVEAU_GEM_DOMAIN_VRAM && contig) {
4797760a2e3SBen Skeggs 		if (!nvbo->contig) {
4807760a2e3SBen Skeggs 			nvbo->contig = true;
481ad76b3f7SBen Skeggs 			force = true;
4827760a2e3SBen Skeggs 			evict = true;
483ad76b3f7SBen Skeggs 		}
484ad76b3f7SBen Skeggs 	}
485ad76b3f7SBen Skeggs 
4866797cea1SChristian König 	if (nvbo->bo.pin_count) {
48781b61579SChristian König 		bool error = evict;
48881b61579SChristian König 
489d3116756SChristian König 		switch (bo->resource->mem_type) {
49081b61579SChristian König 		case TTM_PL_VRAM:
49181b61579SChristian König 			error |= !(domain & NOUVEAU_GEM_DOMAIN_VRAM);
49281b61579SChristian König 			break;
49381b61579SChristian König 		case TTM_PL_TT:
49481b61579SChristian König 			error |= !(domain & NOUVEAU_GEM_DOMAIN_GART);
495f49efb10SGustavo A. R. Silva 			break;
49681b61579SChristian König 		default:
49781b61579SChristian König 			break;
49881b61579SChristian König 		}
49981b61579SChristian König 
50081b61579SChristian König 		if (error) {
501ad76b3f7SBen Skeggs 			NV_ERROR(drm, "bo %p pinned elsewhere: "
502ad76b3f7SBen Skeggs 				      "0x%08x vs 0x%08x\n", bo,
503d3116756SChristian König 				 bo->resource->mem_type, domain);
504ad76b3f7SBen Skeggs 			ret = -EBUSY;
505ad76b3f7SBen Skeggs 		}
5066797cea1SChristian König 		ttm_bo_pin(&nvbo->bo);
5070ae6d7bcSDaniel Vetter 		goto out;
5086ee73861SBen Skeggs 	}
5096ee73861SBen Skeggs 
510ad76b3f7SBen Skeggs 	if (evict) {
51181b61579SChristian König 		nouveau_bo_placement_set(nvbo, NOUVEAU_GEM_DOMAIN_GART, 0);
512ad76b3f7SBen Skeggs 		ret = nouveau_bo_validate(nvbo, false, false);
513ad76b3f7SBen Skeggs 		if (ret)
51450ab2e52SBen Skeggs 			goto out;
515ad76b3f7SBen Skeggs 	}
5166ee73861SBen Skeggs 
51781b61579SChristian König 	nouveau_bo_placement_set(nvbo, domain, 0);
51897a875cbSMaarten Lankhorst 	ret = nouveau_bo_validate(nvbo, false, false);
5196aac6cedSBen Skeggs 	if (ret)
5206aac6cedSBen Skeggs 		goto out;
5216797cea1SChristian König 
5226797cea1SChristian König 	ttm_bo_pin(&nvbo->bo);
5236aac6cedSBen Skeggs 
524d3116756SChristian König 	switch (bo->resource->mem_type) {
5256ee73861SBen Skeggs 	case TTM_PL_VRAM:
526e11bfb99SChristian König 		drm->gem.vram_available -= bo->base.size;
5276ee73861SBen Skeggs 		break;
5286ee73861SBen Skeggs 	case TTM_PL_TT:
529e11bfb99SChristian König 		drm->gem.gart_available -= bo->base.size;
5306ee73861SBen Skeggs 		break;
5316ee73861SBen Skeggs 	default:
5326ee73861SBen Skeggs 		break;
5336ee73861SBen Skeggs 	}
5345be5a15aSAlexandre Courbot 
5356ee73861SBen Skeggs out:
536ad76b3f7SBen Skeggs 	if (force && ret)
5377760a2e3SBen Skeggs 		nvbo->contig = false;
5380ae6d7bcSDaniel Vetter 	ttm_bo_unreserve(bo);
5396ee73861SBen Skeggs 	return ret;
5406ee73861SBen Skeggs }
5416ee73861SBen Skeggs 
5426ee73861SBen Skeggs int
nouveau_bo_unpin(struct nouveau_bo * nvbo)5436ee73861SBen Skeggs nouveau_bo_unpin(struct nouveau_bo *nvbo)
5446ee73861SBen Skeggs {
545ebb945a9SBen Skeggs 	struct nouveau_drm *drm = nouveau_bdev(nvbo->bo.bdev);
5466ee73861SBen Skeggs 	struct ttm_buffer_object *bo = &nvbo->bo;
5476797cea1SChristian König 	int ret;
5486ee73861SBen Skeggs 
549dfd5e50eSChristian König 	ret = ttm_bo_reserve(bo, false, false, NULL);
5506ee73861SBen Skeggs 	if (ret)
5516ee73861SBen Skeggs 		return ret;
5526ee73861SBen Skeggs 
5536797cea1SChristian König 	ttm_bo_unpin(&nvbo->bo);
5546797cea1SChristian König 	if (!nvbo->bo.pin_count) {
555d3116756SChristian König 		switch (bo->resource->mem_type) {
5566ee73861SBen Skeggs 		case TTM_PL_VRAM:
557e11bfb99SChristian König 			drm->gem.vram_available += bo->base.size;
5586ee73861SBen Skeggs 			break;
5596ee73861SBen Skeggs 		case TTM_PL_TT:
560e11bfb99SChristian König 			drm->gem.gart_available += bo->base.size;
5616ee73861SBen Skeggs 			break;
5626ee73861SBen Skeggs 		default:
5636ee73861SBen Skeggs 			break;
5646ee73861SBen Skeggs 		}
5656ee73861SBen Skeggs 	}
5666ee73861SBen Skeggs 
5676ee73861SBen Skeggs 	ttm_bo_unreserve(bo);
5686797cea1SChristian König 	return 0;
5696ee73861SBen Skeggs }
5706ee73861SBen Skeggs 
5716ee73861SBen Skeggs int
nouveau_bo_map(struct nouveau_bo * nvbo)5726ee73861SBen Skeggs nouveau_bo_map(struct nouveau_bo *nvbo)
5736ee73861SBen Skeggs {
5746ee73861SBen Skeggs 	int ret;
5756ee73861SBen Skeggs 
576dfd5e50eSChristian König 	ret = ttm_bo_reserve(&nvbo->bo, false, false, NULL);
5776ee73861SBen Skeggs 	if (ret)
5786ee73861SBen Skeggs 		return ret;
5796ee73861SBen Skeggs 
580e3c92eb4SSomalapuram Amaranath 	ret = ttm_bo_kmap(&nvbo->bo, 0, PFN_UP(nvbo->bo.base.size), &nvbo->kmap);
581c3a0c771SAlexandre Courbot 
5826ee73861SBen Skeggs 	ttm_bo_unreserve(&nvbo->bo);
5836ee73861SBen Skeggs 	return ret;
5846ee73861SBen Skeggs }
5856ee73861SBen Skeggs 
5866ee73861SBen Skeggs void
nouveau_bo_unmap(struct nouveau_bo * nvbo)5876ee73861SBen Skeggs nouveau_bo_unmap(struct nouveau_bo *nvbo)
5886ee73861SBen Skeggs {
589c3a0c771SAlexandre Courbot 	if (!nvbo)
590c3a0c771SAlexandre Courbot 		return;
591c3a0c771SAlexandre Courbot 
5926ee73861SBen Skeggs 	ttm_bo_kunmap(&nvbo->kmap);
5936ee73861SBen Skeggs }
5946ee73861SBen Skeggs 
595b22870baSAlexandre Courbot void
nouveau_bo_sync_for_device(struct nouveau_bo * nvbo)596b22870baSAlexandre Courbot nouveau_bo_sync_for_device(struct nouveau_bo *nvbo)
597b22870baSAlexandre Courbot {
598b22870baSAlexandre Courbot 	struct nouveau_drm *drm = nouveau_bdev(nvbo->bo.bdev);
599e34b8feeSChristian König 	struct ttm_tt *ttm_dma = (struct ttm_tt *)nvbo->bo.ttm;
600f295c8cfSDave Airlie 	int i, j;
601b22870baSAlexandre Courbot 
602d3300991SChristian König 	if (!ttm_dma || !ttm_dma->dma_address)
603b22870baSAlexandre Courbot 		return;
604e94c55b8STobias Klausmann 	if (!ttm_dma->pages) {
605e94c55b8STobias Klausmann 		NV_DEBUG(drm, "ttm_dma 0x%p: pages NULL\n", ttm_dma);
606e94c55b8STobias Klausmann 		return;
607e94c55b8STobias Klausmann 	}
608b22870baSAlexandre Courbot 
609b22870baSAlexandre Courbot 	/* Don't waste time looping if the object is coherent */
610b22870baSAlexandre Courbot 	if (nvbo->force_coherent)
611b22870baSAlexandre Courbot 		return;
612b22870baSAlexandre Courbot 
6134042160cSDave Airlie 	i = 0;
6144042160cSDave Airlie 	while (i < ttm_dma->num_pages) {
615f295c8cfSDave Airlie 		struct page *p = ttm_dma->pages[i];
616f295c8cfSDave Airlie 		size_t num_pages = 1;
617f295c8cfSDave Airlie 
618f295c8cfSDave Airlie 		for (j = i + 1; j < ttm_dma->num_pages; ++j) {
619f295c8cfSDave Airlie 			if (++p != ttm_dma->pages[j])
620f295c8cfSDave Airlie 				break;
621f295c8cfSDave Airlie 
622f295c8cfSDave Airlie 			++num_pages;
623f295c8cfSDave Airlie 		}
624359088d5SBen Skeggs 		dma_sync_single_for_device(drm->dev->dev,
625359088d5SBen Skeggs 					   ttm_dma->dma_address[i],
626f295c8cfSDave Airlie 					   num_pages * PAGE_SIZE, DMA_TO_DEVICE);
627f295c8cfSDave Airlie 		i += num_pages;
628f295c8cfSDave Airlie 	}
629b22870baSAlexandre Courbot }
630b22870baSAlexandre Courbot 
631b22870baSAlexandre Courbot void
nouveau_bo_sync_for_cpu(struct nouveau_bo * nvbo)632b22870baSAlexandre Courbot nouveau_bo_sync_for_cpu(struct nouveau_bo *nvbo)
633b22870baSAlexandre Courbot {
634b22870baSAlexandre Courbot 	struct nouveau_drm *drm = nouveau_bdev(nvbo->bo.bdev);
635e34b8feeSChristian König 	struct ttm_tt *ttm_dma = (struct ttm_tt *)nvbo->bo.ttm;
636f295c8cfSDave Airlie 	int i, j;
637b22870baSAlexandre Courbot 
638d3300991SChristian König 	if (!ttm_dma || !ttm_dma->dma_address)
639b22870baSAlexandre Courbot 		return;
640e94c55b8STobias Klausmann 	if (!ttm_dma->pages) {
641e94c55b8STobias Klausmann 		NV_DEBUG(drm, "ttm_dma 0x%p: pages NULL\n", ttm_dma);
642e94c55b8STobias Klausmann 		return;
643e94c55b8STobias Klausmann 	}
644b22870baSAlexandre Courbot 
645b22870baSAlexandre Courbot 	/* Don't waste time looping if the object is coherent */
646b22870baSAlexandre Courbot 	if (nvbo->force_coherent)
647b22870baSAlexandre Courbot 		return;
648b22870baSAlexandre Courbot 
6494042160cSDave Airlie 	i = 0;
6504042160cSDave Airlie 	while (i < ttm_dma->num_pages) {
651f295c8cfSDave Airlie 		struct page *p = ttm_dma->pages[i];
652f295c8cfSDave Airlie 		size_t num_pages = 1;
653f295c8cfSDave Airlie 
654f295c8cfSDave Airlie 		for (j = i + 1; j < ttm_dma->num_pages; ++j) {
655f295c8cfSDave Airlie 			if (++p != ttm_dma->pages[j])
656f295c8cfSDave Airlie 				break;
657f295c8cfSDave Airlie 
658f295c8cfSDave Airlie 			++num_pages;
659f295c8cfSDave Airlie 		}
660f295c8cfSDave Airlie 
661359088d5SBen Skeggs 		dma_sync_single_for_cpu(drm->dev->dev, ttm_dma->dma_address[i],
662f295c8cfSDave Airlie 					num_pages * PAGE_SIZE, DMA_FROM_DEVICE);
663f295c8cfSDave Airlie 		i += num_pages;
664f295c8cfSDave Airlie 	}
665b22870baSAlexandre Courbot }
666b22870baSAlexandre Courbot 
nouveau_bo_add_io_reserve_lru(struct ttm_buffer_object * bo)667141b15e5SChristian König void nouveau_bo_add_io_reserve_lru(struct ttm_buffer_object *bo)
668141b15e5SChristian König {
669141b15e5SChristian König 	struct nouveau_drm *drm = nouveau_bdev(bo->bdev);
670141b15e5SChristian König 	struct nouveau_bo *nvbo = nouveau_bo(bo);
671141b15e5SChristian König 
672141b15e5SChristian König 	mutex_lock(&drm->ttm.io_reserve_mutex);
673141b15e5SChristian König 	list_move_tail(&nvbo->io_reserve_lru, &drm->ttm.io_reserve_lru);
674141b15e5SChristian König 	mutex_unlock(&drm->ttm.io_reserve_mutex);
675141b15e5SChristian König }
676141b15e5SChristian König 
nouveau_bo_del_io_reserve_lru(struct ttm_buffer_object * bo)677141b15e5SChristian König void nouveau_bo_del_io_reserve_lru(struct ttm_buffer_object *bo)
678141b15e5SChristian König {
679141b15e5SChristian König 	struct nouveau_drm *drm = nouveau_bdev(bo->bdev);
680141b15e5SChristian König 	struct nouveau_bo *nvbo = nouveau_bo(bo);
681141b15e5SChristian König 
682141b15e5SChristian König 	mutex_lock(&drm->ttm.io_reserve_mutex);
683141b15e5SChristian König 	list_del_init(&nvbo->io_reserve_lru);
684141b15e5SChristian König 	mutex_unlock(&drm->ttm.io_reserve_mutex);
685141b15e5SChristian König }
686141b15e5SChristian König 
6877a45d764SBen Skeggs int
nouveau_bo_validate(struct nouveau_bo * nvbo,bool interruptible,bool no_wait_gpu)6887a45d764SBen Skeggs nouveau_bo_validate(struct nouveau_bo *nvbo, bool interruptible,
68997a875cbSMaarten Lankhorst 		    bool no_wait_gpu)
6907a45d764SBen Skeggs {
69119be5570SChristian König 	struct ttm_operation_ctx ctx = { interruptible, no_wait_gpu };
6927a45d764SBen Skeggs 	int ret;
6937a45d764SBen Skeggs 
69419be5570SChristian König 	ret = ttm_bo_validate(&nvbo->bo, &nvbo->placement, &ctx);
6957a45d764SBen Skeggs 	if (ret)
6967a45d764SBen Skeggs 		return ret;
6977a45d764SBen Skeggs 
698b22870baSAlexandre Courbot 	nouveau_bo_sync_for_device(nvbo);
699b22870baSAlexandre Courbot 
7007a45d764SBen Skeggs 	return 0;
7017a45d764SBen Skeggs }
7027a45d764SBen Skeggs 
7036ee73861SBen Skeggs void
nouveau_bo_wr16(struct nouveau_bo * nvbo,unsigned index,u16 val)7046ee73861SBen Skeggs nouveau_bo_wr16(struct nouveau_bo *nvbo, unsigned index, u16 val)
7056ee73861SBen Skeggs {
7066ee73861SBen Skeggs 	bool is_iomem;
7076ee73861SBen Skeggs 	u16 *mem = ttm_kmap_obj_virtual(&nvbo->kmap, &is_iomem);
708c3a0c771SAlexandre Courbot 
70936a471baSAlexandre Courbot 	mem += index;
710c3a0c771SAlexandre Courbot 
7116ee73861SBen Skeggs 	if (is_iomem)
7126ee73861SBen Skeggs 		iowrite16_native(val, (void __force __iomem *)mem);
7136ee73861SBen Skeggs 	else
7146ee73861SBen Skeggs 		*mem = val;
7156ee73861SBen Skeggs }
7166ee73861SBen Skeggs 
7176ee73861SBen Skeggs u32
nouveau_bo_rd32(struct nouveau_bo * nvbo,unsigned index)7186ee73861SBen Skeggs nouveau_bo_rd32(struct nouveau_bo *nvbo, unsigned index)
7196ee73861SBen Skeggs {
7206ee73861SBen Skeggs 	bool is_iomem;
7216ee73861SBen Skeggs 	u32 *mem = ttm_kmap_obj_virtual(&nvbo->kmap, &is_iomem);
722c3a0c771SAlexandre Courbot 
72336a471baSAlexandre Courbot 	mem += index;
724c3a0c771SAlexandre Courbot 
7256ee73861SBen Skeggs 	if (is_iomem)
7266ee73861SBen Skeggs 		return ioread32_native((void __force __iomem *)mem);
7276ee73861SBen Skeggs 	else
7286ee73861SBen Skeggs 		return *mem;
7296ee73861SBen Skeggs }
7306ee73861SBen Skeggs 
7316ee73861SBen Skeggs void
nouveau_bo_wr32(struct nouveau_bo * nvbo,unsigned index,u32 val)7326ee73861SBen Skeggs nouveau_bo_wr32(struct nouveau_bo *nvbo, unsigned index, u32 val)
7336ee73861SBen Skeggs {
7346ee73861SBen Skeggs 	bool is_iomem;
7356ee73861SBen Skeggs 	u32 *mem = ttm_kmap_obj_virtual(&nvbo->kmap, &is_iomem);
736c3a0c771SAlexandre Courbot 
73736a471baSAlexandre Courbot 	mem += index;
738c3a0c771SAlexandre Courbot 
7396ee73861SBen Skeggs 	if (is_iomem)
7406ee73861SBen Skeggs 		iowrite32_native(val, (void __force __iomem *)mem);
7416ee73861SBen Skeggs 	else
7426ee73861SBen Skeggs 		*mem = val;
7436ee73861SBen Skeggs }
7446ee73861SBen Skeggs 
745649bf3caSJerome Glisse static struct ttm_tt *
nouveau_ttm_tt_create(struct ttm_buffer_object * bo,uint32_t page_flags)746dde5da23SChristian König nouveau_ttm_tt_create(struct ttm_buffer_object *bo, uint32_t page_flags)
7476ee73861SBen Skeggs {
748a7fb8a23SDaniel Vetter #if IS_ENABLED(CONFIG_AGP)
749dde5da23SChristian König 	struct nouveau_drm *drm = nouveau_bdev(bo->bdev);
7506ee73861SBen Skeggs 
751340b0e7cSBen Skeggs 	if (drm->agp.bridge) {
752dde5da23SChristian König 		return ttm_agp_tt_create(bo, drm->agp.bridge, page_flags);
7536ee73861SBen Skeggs 	}
754df1b4b91SMax Filippov #endif
7556ee73861SBen Skeggs 
756dde5da23SChristian König 	return nouveau_sgdma_create_ttm(bo, page_flags);
7576ee73861SBen Skeggs }
7586ee73861SBen Skeggs 
7598635784aSDave Airlie static int
nouveau_ttm_tt_bind(struct ttm_device * bdev,struct ttm_tt * ttm,struct ttm_resource * reg)7608af8a109SChristian König nouveau_ttm_tt_bind(struct ttm_device *bdev, struct ttm_tt *ttm,
7618635784aSDave Airlie 		    struct ttm_resource *reg)
7628635784aSDave Airlie {
7638635784aSDave Airlie #if IS_ENABLED(CONFIG_AGP)
7648635784aSDave Airlie 	struct nouveau_drm *drm = nouveau_bdev(bdev);
7650b988ca1SDave Airlie #endif
7660b988ca1SDave Airlie 	if (!reg)
7670b988ca1SDave Airlie 		return -EINVAL;
7680b988ca1SDave Airlie #if IS_ENABLED(CONFIG_AGP)
7698635784aSDave Airlie 	if (drm->agp.bridge)
77048efa57eSDave Airlie 		return ttm_agp_bind(ttm, reg);
7718635784aSDave Airlie #endif
7728635784aSDave Airlie 	return nouveau_sgdma_bind(bdev, ttm, reg);
7738635784aSDave Airlie }
7748635784aSDave Airlie 
7758635784aSDave Airlie static void
nouveau_ttm_tt_unbind(struct ttm_device * bdev,struct ttm_tt * ttm)7768af8a109SChristian König nouveau_ttm_tt_unbind(struct ttm_device *bdev, struct ttm_tt *ttm)
7778635784aSDave Airlie {
7788635784aSDave Airlie #if IS_ENABLED(CONFIG_AGP)
7798635784aSDave Airlie 	struct nouveau_drm *drm = nouveau_bdev(bdev);
7808635784aSDave Airlie 
7818635784aSDave Airlie 	if (drm->agp.bridge) {
78248efa57eSDave Airlie 		ttm_agp_unbind(ttm);
7838635784aSDave Airlie 		return;
7848635784aSDave Airlie 	}
7858635784aSDave Airlie #endif
7868635784aSDave Airlie 	nouveau_sgdma_unbind(bdev, ttm);
7878635784aSDave Airlie }
7888635784aSDave Airlie 
7896ee73861SBen Skeggs static void
nouveau_bo_evict_flags(struct ttm_buffer_object * bo,struct ttm_placement * pl)7906ee73861SBen Skeggs nouveau_bo_evict_flags(struct ttm_buffer_object *bo, struct ttm_placement *pl)
7916ee73861SBen Skeggs {
7926ee73861SBen Skeggs 	struct nouveau_bo *nvbo = nouveau_bo(bo);
7936ee73861SBen Skeggs 
794d3116756SChristian König 	switch (bo->resource->mem_type) {
79522fbd538SFrancisco Jerez 	case TTM_PL_VRAM:
79681b61579SChristian König 		nouveau_bo_placement_set(nvbo, NOUVEAU_GEM_DOMAIN_GART,
79781b61579SChristian König 					 NOUVEAU_GEM_DOMAIN_CPU);
79822fbd538SFrancisco Jerez 		break;
7996ee73861SBen Skeggs 	default:
80081b61579SChristian König 		nouveau_bo_placement_set(nvbo, NOUVEAU_GEM_DOMAIN_CPU, 0);
8016ee73861SBen Skeggs 		break;
8026ee73861SBen Skeggs 	}
80322fbd538SFrancisco Jerez 
80422fbd538SFrancisco Jerez 	*pl = nvbo->placement;
8056ee73861SBen Skeggs }
8066ee73861SBen Skeggs 
807f1ab0cc9SBen Skeggs static int
nouveau_bo_move_prep(struct nouveau_drm * drm,struct ttm_buffer_object * bo,struct ttm_resource * reg)8083c57d85dSBen Skeggs nouveau_bo_move_prep(struct nouveau_drm *drm, struct ttm_buffer_object *bo,
8092966141aSDave Airlie 		     struct ttm_resource *reg)
810d2f96666SBen Skeggs {
811d3116756SChristian König 	struct nouveau_mem *old_mem = nouveau_mem(bo->resource);
8129ce523ccSBen Skeggs 	struct nouveau_mem *new_mem = nouveau_mem(reg);
813d7722134SBen Skeggs 	struct nvif_vmm *vmm = &drm->client.vmm.vmm;
814d2f96666SBen Skeggs 	int ret;
815d2f96666SBen Skeggs 
816d7722134SBen Skeggs 	ret = nvif_vmm_get(vmm, LAZY, false, old_mem->mem.page, 0,
817d7722134SBen Skeggs 			   old_mem->mem.size, &old_mem->vma[0]);
818d2f96666SBen Skeggs 	if (ret)
819d2f96666SBen Skeggs 		return ret;
820d2f96666SBen Skeggs 
821d7722134SBen Skeggs 	ret = nvif_vmm_get(vmm, LAZY, false, new_mem->mem.page, 0,
822d7722134SBen Skeggs 			   new_mem->mem.size, &old_mem->vma[1]);
823d7722134SBen Skeggs 	if (ret)
824d7722134SBen Skeggs 		goto done;
8253c57d85dSBen Skeggs 
8269ce523ccSBen Skeggs 	ret = nouveau_mem_map(old_mem, vmm, &old_mem->vma[0]);
8279ce523ccSBen Skeggs 	if (ret)
8289ce523ccSBen Skeggs 		goto done;
8299ce523ccSBen Skeggs 
8309ce523ccSBen Skeggs 	ret = nouveau_mem_map(new_mem, vmm, &old_mem->vma[1]);
8319ce523ccSBen Skeggs done:
8329ce523ccSBen Skeggs 	if (ret) {
833d7722134SBen Skeggs 		nvif_vmm_put(vmm, &old_mem->vma[1]);
834d7722134SBen Skeggs 		nvif_vmm_put(vmm, &old_mem->vma[0]);
8359ce523ccSBen Skeggs 	}
836d2f96666SBen Skeggs 	return 0;
837d2f96666SBen Skeggs }
838d2f96666SBen Skeggs 
839d2f96666SBen Skeggs static int
nouveau_bo_move_m2mf(struct ttm_buffer_object * bo,int evict,struct ttm_operation_ctx * ctx,struct ttm_resource * new_reg)84054661867SDave Airlie nouveau_bo_move_m2mf(struct ttm_buffer_object *bo, int evict,
84154661867SDave Airlie 		     struct ttm_operation_ctx *ctx,
84254661867SDave Airlie 		     struct ttm_resource *new_reg)
843f1ab0cc9SBen Skeggs {
844ebb945a9SBen Skeggs 	struct nouveau_drm *drm = nouveau_bdev(bo->bdev);
8451934a2adSDave Jones 	struct nouveau_channel *chan = drm->ttm.chan;
846*0aac3fb6SBen Skeggs 	struct nouveau_cli *cli = chan->cli;
84735b8141bSBen Skeggs 	struct nouveau_fence *fence;
848f1ab0cc9SBen Skeggs 	int ret;
849f1ab0cc9SBen Skeggs 
850d2f96666SBen Skeggs 	/* create temporary vmas for the transfer and attach them to the
851be83cd4eSBen Skeggs 	 * old nvkm_mem node, these will get cleaned up after ttm has
8522966141aSDave Airlie 	 * destroyed the ttm_resource
8533425df48SBen Skeggs 	 */
8541167c6bcSBen Skeggs 	if (drm->client.device.info.family >= NV_DEVICE_INFO_V0_TESLA) {
855605f9ccdSBen Skeggs 		ret = nouveau_bo_move_prep(drm, bo, new_reg);
8563425df48SBen Skeggs 		if (ret)
8573c57d85dSBen Skeggs 			return ret;
8583425df48SBen Skeggs 	}
8593425df48SBen Skeggs 
860551620f2SDaniel Vetter 	if (drm_drv_uses_atomic_modeset(drm->dev))
861551620f2SDaniel Vetter 		mutex_lock(&cli->mutex);
862551620f2SDaniel Vetter 	else
8630ad72863SBen Skeggs 		mutex_lock_nested(&cli->mutex, SINGLE_DEPTH_NESTING);
8647f2a0b50SDanilo Krummrich 
86554661867SDave Airlie 	ret = nouveau_fence_sync(nouveau_bo(bo), chan, true, ctx->interruptible);
8667f2a0b50SDanilo Krummrich 	if (ret)
8677f2a0b50SDanilo Krummrich 		goto out_unlock;
8687f2a0b50SDanilo Krummrich 
869d3116756SChristian König 	ret = drm->ttm.move(chan, bo, bo->resource, new_reg);
8707f2a0b50SDanilo Krummrich 	if (ret)
8717f2a0b50SDanilo Krummrich 		goto out_unlock;
8727f2a0b50SDanilo Krummrich 
873978474dcSDanilo Krummrich 	ret = nouveau_fence_new(&fence, chan);
8747f2a0b50SDanilo Krummrich 	if (ret)
8757f2a0b50SDanilo Krummrich 		goto out_unlock;
8767f2a0b50SDanilo Krummrich 
8776b04ce96SKarol Herbst 	/* TODO: figure out a better solution here
8786b04ce96SKarol Herbst 	 *
8796b04ce96SKarol Herbst 	 * wait on the fence here explicitly as going through
8806b04ce96SKarol Herbst 	 * ttm_bo_move_accel_cleanup somehow doesn't seem to do it.
8816b04ce96SKarol Herbst 	 *
8826b04ce96SKarol Herbst 	 * Without this the operation can timeout and we'll fallback to a
8836b04ce96SKarol Herbst 	 * software copy, which might take several minutes to finish.
8846b04ce96SKarol Herbst 	 */
8856b04ce96SKarol Herbst 	nouveau_fence_wait(fence, false, false);
8867f2a0b50SDanilo Krummrich 	ret = ttm_bo_move_accel_cleanup(bo, &fence->base, evict, false,
887605f9ccdSBen Skeggs 					new_reg);
88835b8141bSBen Skeggs 	nouveau_fence_unref(&fence);
8897f2a0b50SDanilo Krummrich 
8907f2a0b50SDanilo Krummrich out_unlock:
8910ad72863SBen Skeggs 	mutex_unlock(&cli->mutex);
8926a6b73f2SBen Skeggs 	return ret;
8936ee73861SBen Skeggs }
8946ee73861SBen Skeggs 
895d1b167e1SBen Skeggs void
nouveau_bo_move_init(struct nouveau_drm * drm)89649981046SBen Skeggs nouveau_bo_move_init(struct nouveau_drm *drm)
897d1b167e1SBen Skeggs {
89872ecb0a6SJames Jones 	static const struct _method_table {
899d1b167e1SBen Skeggs 		const char *name;
9001a46098eSBen Skeggs 		int engine;
901315a8b2eSBen Skeggs 		s32 oclass;
902d1b167e1SBen Skeggs 		int (*exec)(struct nouveau_channel *,
903d1b167e1SBen Skeggs 			    struct ttm_buffer_object *,
9042966141aSDave Airlie 			    struct ttm_resource *, struct ttm_resource *);
905d1b167e1SBen Skeggs 		int (*init)(struct nouveau_channel *, u32 handle);
906d1b167e1SBen Skeggs 	} _methods[] = {
90749b2dfc0SBen Skeggs 		{  "COPY", 4, 0xc7b5, nve0_bo_move_copy, nve0_bo_move_init },
90805d271c3SBen Skeggs 		{  "GRCE", 0, 0xc7b5, nve0_bo_move_copy, nvc0_bo_move_init },
90905d271c3SBen Skeggs 		{  "COPY", 4, 0xc6b5, nve0_bo_move_copy, nve0_bo_move_init },
91005d271c3SBen Skeggs 		{  "GRCE", 0, 0xc6b5, nve0_bo_move_copy, nvc0_bo_move_init },
911c36322d2SBen Skeggs 		{  "COPY", 4, 0xc5b5, nve0_bo_move_copy, nve0_bo_move_init },
912c36322d2SBen Skeggs 		{  "GRCE", 0, 0xc5b5, nve0_bo_move_copy, nvc0_bo_move_init },
9136e1f34e3SBen Skeggs 		{  "COPY", 4, 0xc3b5, nve0_bo_move_copy, nve0_bo_move_init },
9146e1f34e3SBen Skeggs 		{  "GRCE", 0, 0xc3b5, nve0_bo_move_copy, nvc0_bo_move_init },
915146cfe24SBen Skeggs 		{  "COPY", 4, 0xc1b5, nve0_bo_move_copy, nve0_bo_move_init },
916146cfe24SBen Skeggs 		{  "GRCE", 0, 0xc1b5, nve0_bo_move_copy, nvc0_bo_move_init },
9178e7e1586SBen Skeggs 		{  "COPY", 4, 0xc0b5, nve0_bo_move_copy, nve0_bo_move_init },
9188e7e1586SBen Skeggs 		{  "GRCE", 0, 0xc0b5, nve0_bo_move_copy, nvc0_bo_move_init },
919990b4547SBen Skeggs 		{  "COPY", 4, 0xb0b5, nve0_bo_move_copy, nve0_bo_move_init },
920990b4547SBen Skeggs 		{  "GRCE", 0, 0xb0b5, nve0_bo_move_copy, nvc0_bo_move_init },
92100fc6f6fSBen Skeggs 		{  "COPY", 4, 0xa0b5, nve0_bo_move_copy, nve0_bo_move_init },
92249981046SBen Skeggs 		{  "GRCE", 0, 0xa0b5, nve0_bo_move_copy, nvc0_bo_move_init },
9231a46098eSBen Skeggs 		{ "COPY1", 5, 0x90b8, nvc0_bo_move_copy, nvc0_bo_move_init },
9241a46098eSBen Skeggs 		{ "COPY0", 4, 0x90b5, nvc0_bo_move_copy, nvc0_bo_move_init },
9251a46098eSBen Skeggs 		{  "COPY", 0, 0x85b5, nva3_bo_move_copy, nv50_bo_move_init },
9261a46098eSBen Skeggs 		{ "CRYPT", 0, 0x74c1, nv84_bo_move_exec, nv50_bo_move_init },
9271a46098eSBen Skeggs 		{  "M2MF", 0, 0x9039, nvc0_bo_move_m2mf, nvc0_bo_move_init },
9281a46098eSBen Skeggs 		{  "M2MF", 0, 0x5039, nv50_bo_move_m2mf, nv50_bo_move_init },
9291a46098eSBen Skeggs 		{  "M2MF", 0, 0x0039, nv04_bo_move_m2mf, nv04_bo_move_init },
9305490e5dfSBen Skeggs 		{},
93172ecb0a6SJames Jones 	};
93272ecb0a6SJames Jones 	const struct _method_table *mthd = _methods;
933d1b167e1SBen Skeggs 	const char *name = "CPU";
934d1b167e1SBen Skeggs 	int ret;
935d1b167e1SBen Skeggs 
936d1b167e1SBen Skeggs 	do {
93749981046SBen Skeggs 		struct nouveau_channel *chan;
938ebb945a9SBen Skeggs 
93900fc6f6fSBen Skeggs 		if (mthd->engine)
94049981046SBen Skeggs 			chan = drm->cechan;
94149981046SBen Skeggs 		else
94249981046SBen Skeggs 			chan = drm->channel;
94349981046SBen Skeggs 		if (chan == NULL)
94449981046SBen Skeggs 			continue;
94549981046SBen Skeggs 
9469ac596a4SBen Skeggs 		ret = nvif_object_ctor(&chan->user, "ttmBoMove",
9470ad72863SBen Skeggs 				       mthd->oclass | (mthd->engine << 16),
9480ad72863SBen Skeggs 				       mthd->oclass, NULL, 0,
9490ad72863SBen Skeggs 				       &drm->ttm.copy);
950d1b167e1SBen Skeggs 		if (ret == 0) {
9510ad72863SBen Skeggs 			ret = mthd->init(chan, drm->ttm.copy.handle);
952ebb945a9SBen Skeggs 			if (ret) {
9539ac596a4SBen Skeggs 				nvif_object_dtor(&drm->ttm.copy);
954ebb945a9SBen Skeggs 				continue;
955ebb945a9SBen Skeggs 			}
956ebb945a9SBen Skeggs 
957ebb945a9SBen Skeggs 			drm->ttm.move = mthd->exec;
9581bb3f6a2SBen Skeggs 			drm->ttm.chan = chan;
959d1b167e1SBen Skeggs 			name = mthd->name;
960d1b167e1SBen Skeggs 			break;
961d1b167e1SBen Skeggs 		}
962d1b167e1SBen Skeggs 	} while ((++mthd)->exec);
963d1b167e1SBen Skeggs 
964ebb945a9SBen Skeggs 	NV_INFO(drm, "MM: using %s for buffer copies\n", name);
965d1b167e1SBen Skeggs }
966d1b167e1SBen Skeggs 
nouveau_bo_move_ntfy(struct ttm_buffer_object * bo,struct ttm_resource * new_reg)9675ea143c3SChristian König static void nouveau_bo_move_ntfy(struct ttm_buffer_object *bo,
9682966141aSDave Airlie 				 struct ttm_resource *new_reg)
969a4154bbfSBen Skeggs {
9709ce523ccSBen Skeggs 	struct nouveau_mem *mem = new_reg ? nouveau_mem(new_reg) : NULL;
971a4154bbfSBen Skeggs 	struct nouveau_bo *nvbo = nouveau_bo(bo);
97224e8375bSBen Skeggs 	struct nouveau_vma *vma;
97341d351f2SChristian König 	long ret;
974a4154bbfSBen Skeggs 
9759f1feed2SBen Skeggs 	/* ttm can now (stupidly) pass the driver bos it didn't create... */
9769f1feed2SBen Skeggs 	if (bo->destroy != nouveau_bo_del_ttm)
9779f1feed2SBen Skeggs 		return;
9789f1feed2SBen Skeggs 
979141b15e5SChristian König 	nouveau_bo_del_io_reserve_lru(bo);
980141b15e5SChristian König 
981425b34f7SBen Skeggs 	if (mem && new_reg->mem_type != TTM_PL_SYSTEM &&
9829ce523ccSBen Skeggs 	    mem->mem.page == nvbo->page) {
983a48296abSBen Skeggs 		list_for_each_entry(vma, &nvbo->vma_list, head) {
98424e8375bSBen Skeggs 			nouveau_vma_map(vma, mem);
985a48296abSBen Skeggs 		}
986b88baab8SDanilo Krummrich 		nouveau_uvmm_bo_map_all(nvbo, mem);
987d2f96666SBen Skeggs 	} else {
988a48296abSBen Skeggs 		list_for_each_entry(vma, &nvbo->vma_list, head) {
98941d351f2SChristian König 			ret = dma_resv_wait_timeout(bo->base.resv,
99041d351f2SChristian König 						    DMA_RESV_USAGE_BOOKKEEP,
99141d351f2SChristian König 						    false, 15 * HZ);
99241d351f2SChristian König 			WARN_ON(ret <= 0);
99324e8375bSBen Skeggs 			nouveau_vma_unmap(vma);
994fd2871afSBen Skeggs 		}
995b88baab8SDanilo Krummrich 		nouveau_uvmm_bo_unmap_all(nvbo);
996a4154bbfSBen Skeggs 	}
9970dc9b286SNirmoy Das 
998cb1c8146SChristian König 	if (new_reg)
9990dc9b286SNirmoy Das 		nvbo->offset = (new_reg->start << PAGE_SHIFT);
10000dc9b286SNirmoy Das 
1001a4154bbfSBen Skeggs }
1002a4154bbfSBen Skeggs 
10036ee73861SBen Skeggs static int
nouveau_bo_vm_bind(struct ttm_buffer_object * bo,struct ttm_resource * new_reg,struct nouveau_drm_tile ** new_tile)10042966141aSDave Airlie nouveau_bo_vm_bind(struct ttm_buffer_object *bo, struct ttm_resource *new_reg,
1005ebb945a9SBen Skeggs 		   struct nouveau_drm_tile **new_tile)
10066ee73861SBen Skeggs {
1007ebb945a9SBen Skeggs 	struct nouveau_drm *drm = nouveau_bdev(bo->bdev);
1008ebb945a9SBen Skeggs 	struct drm_device *dev = drm->dev;
1009a0af9addSFrancisco Jerez 	struct nouveau_bo *nvbo = nouveau_bo(bo);
1010605f9ccdSBen Skeggs 	u64 offset = new_reg->start << PAGE_SHIFT;
10116ee73861SBen Skeggs 
1012a0af9addSFrancisco Jerez 	*new_tile = NULL;
1013605f9ccdSBen Skeggs 	if (new_reg->mem_type != TTM_PL_VRAM)
1014a0af9addSFrancisco Jerez 		return 0;
10156ee73861SBen Skeggs 
10161167c6bcSBen Skeggs 	if (drm->client.device.info.family >= NV_DEVICE_INFO_V0_CELSIUS) {
1017e11bfb99SChristian König 		*new_tile = nv10_bo_set_tiling(dev, offset, bo->base.size,
10187760a2e3SBen Skeggs 					       nvbo->mode, nvbo->zeta);
10196ee73861SBen Skeggs 	}
10206ee73861SBen Skeggs 
1021a0af9addSFrancisco Jerez 	return 0;
1022a0af9addSFrancisco Jerez }
10236ee73861SBen Skeggs 
1024a0af9addSFrancisco Jerez static void
nouveau_bo_vm_cleanup(struct ttm_buffer_object * bo,struct nouveau_drm_tile * new_tile,struct nouveau_drm_tile ** old_tile)1025a0af9addSFrancisco Jerez nouveau_bo_vm_cleanup(struct ttm_buffer_object *bo,
1026ebb945a9SBen Skeggs 		      struct nouveau_drm_tile *new_tile,
1027ebb945a9SBen Skeggs 		      struct nouveau_drm_tile **old_tile)
1028a0af9addSFrancisco Jerez {
1029ebb945a9SBen Skeggs 	struct nouveau_drm *drm = nouveau_bdev(bo->bdev);
1030ebb945a9SBen Skeggs 	struct drm_device *dev = drm->dev;
1031756cc94dSChristian König 	struct dma_fence *fence;
1032756cc94dSChristian König 	int ret;
1033756cc94dSChristian König 
10347bc80a54SChristian König 	ret = dma_resv_get_singleton(bo->base.resv, DMA_RESV_USAGE_WRITE,
10357bc80a54SChristian König 				     &fence);
1036756cc94dSChristian König 	if (ret)
10377bc80a54SChristian König 		dma_resv_wait_timeout(bo->base.resv, DMA_RESV_USAGE_WRITE,
10387bc80a54SChristian König 				      false, MAX_SCHEDULE_TIMEOUT);
1039a0af9addSFrancisco Jerez 
1040f2c24b83SMaarten Lankhorst 	nv10_bo_put_tile_region(dev, *old_tile, fence);
1041a0af9addSFrancisco Jerez 	*old_tile = new_tile;
1042a0af9addSFrancisco Jerez }
1043a0af9addSFrancisco Jerez 
1044a0af9addSFrancisco Jerez static int
nouveau_bo_move(struct ttm_buffer_object * bo,bool evict,struct ttm_operation_ctx * ctx,struct ttm_resource * new_reg,struct ttm_place * hop)10452823f4f0SChristian König nouveau_bo_move(struct ttm_buffer_object *bo, bool evict,
10462823f4f0SChristian König 		struct ttm_operation_ctx *ctx,
1047ebdf5651SDave Airlie 		struct ttm_resource *new_reg,
1048ebdf5651SDave Airlie 		struct ttm_place *hop)
1049a0af9addSFrancisco Jerez {
1050ebb945a9SBen Skeggs 	struct nouveau_drm *drm = nouveau_bdev(bo->bdev);
1051a0af9addSFrancisco Jerez 	struct nouveau_bo *nvbo = nouveau_bo(bo);
1052d3116756SChristian König 	struct ttm_resource *old_reg = bo->resource;
1053ebb945a9SBen Skeggs 	struct nouveau_drm_tile *new_tile = NULL;
1054a0af9addSFrancisco Jerez 	int ret = 0;
1055a0af9addSFrancisco Jerez 
10560c8c0659SDave Airlie 
1057bfe5e585SDave Airlie 	if (new_reg->mem_type == TTM_PL_TT) {
1058bfe5e585SDave Airlie 		ret = nouveau_ttm_tt_bind(bo->bdev, bo->ttm, new_reg);
105988932a7bSChristian König 		if (ret)
106088932a7bSChristian König 			return ret;
1061bfe5e585SDave Airlie 	}
106288932a7bSChristian König 
10635ea143c3SChristian König 	nouveau_bo_move_ntfy(bo, new_reg);
10640ef1ed81SDave Airlie 	ret = ttm_bo_wait_ctx(bo, ctx);
10655be5a15aSAlexandre Courbot 	if (ret)
10666d820003SDave Airlie 		goto out_ntfy;
1067967e7bdeSBen Skeggs 
10681167c6bcSBen Skeggs 	if (drm->client.device.info.family < NV_DEVICE_INFO_V0_TESLA) {
1069605f9ccdSBen Skeggs 		ret = nouveau_bo_vm_bind(bo, new_reg, &new_tile);
1070a0af9addSFrancisco Jerez 		if (ret)
10716d820003SDave Airlie 			goto out_ntfy;
1072a4154bbfSBen Skeggs 	}
1073a0af9addSFrancisco Jerez 
1074a0af9addSFrancisco Jerez 	/* Fake bo copy. */
107564e257f1SChristian König 	if (!old_reg || (old_reg->mem_type == TTM_PL_SYSTEM &&
107664e257f1SChristian König 			 !bo->ttm)) {
1077ecfe6953SDave Airlie 		ttm_bo_move_null(bo, new_reg);
1078a0af9addSFrancisco Jerez 		goto out;
10796ee73861SBen Skeggs 	}
10806ee73861SBen Skeggs 
108112b68474SDave Airlie 	if (old_reg->mem_type == TTM_PL_SYSTEM &&
108212b68474SDave Airlie 	    new_reg->mem_type == TTM_PL_TT) {
108312b68474SDave Airlie 		ttm_bo_move_null(bo, new_reg);
108412b68474SDave Airlie 		goto out;
108512b68474SDave Airlie 	}
108612b68474SDave Airlie 
108712b68474SDave Airlie 	if (old_reg->mem_type == TTM_PL_TT &&
108812b68474SDave Airlie 	    new_reg->mem_type == TTM_PL_SYSTEM) {
108929a1d482SDave Airlie 		nouveau_ttm_tt_unbind(bo->bdev, bo->ttm);
1090bfa3357eSChristian König 		ttm_resource_free(bo, &bo->resource);
1091c37d951cSDave Airlie 		ttm_bo_assign_mem(bo, new_reg);
109212b68474SDave Airlie 		goto out;
109312b68474SDave Airlie 	}
109412b68474SDave Airlie 
1095a0af9addSFrancisco Jerez 	/* Hardware assisted copy. */
1096cef9e99eSBen Skeggs 	if (drm->ttm.move) {
1097660a5995SDave Airlie 		if ((old_reg->mem_type == TTM_PL_SYSTEM &&
1098660a5995SDave Airlie 		     new_reg->mem_type == TTM_PL_VRAM) ||
1099660a5995SDave Airlie 		    (old_reg->mem_type == TTM_PL_VRAM &&
1100660a5995SDave Airlie 		     new_reg->mem_type == TTM_PL_SYSTEM)) {
1101660a5995SDave Airlie 			hop->fpfn = 0;
1102660a5995SDave Airlie 			hop->lpfn = 0;
1103660a5995SDave Airlie 			hop->mem_type = TTM_PL_TT;
1104660a5995SDave Airlie 			hop->flags = 0;
1105660a5995SDave Airlie 			return -EMULTIHOP;
1106660a5995SDave Airlie 		}
110754661867SDave Airlie 		ret = nouveau_bo_move_m2mf(bo, evict, ctx,
110854661867SDave Airlie 					   new_reg);
1109660a5995SDave Airlie 	} else
1110660a5995SDave Airlie 		ret = -ENODEV;
1111a0af9addSFrancisco Jerez 
1112660a5995SDave Airlie 	if (ret) {
1113a0af9addSFrancisco Jerez 		/* Fallback to software copy. */
11143e98d829SRoger He 		ret = ttm_bo_move_memcpy(bo, ctx, new_reg);
1115660a5995SDave Airlie 	}
1116a0af9addSFrancisco Jerez 
1117a0af9addSFrancisco Jerez out:
11181167c6bcSBen Skeggs 	if (drm->client.device.info.family < NV_DEVICE_INFO_V0_TESLA) {
1119a0af9addSFrancisco Jerez 		if (ret)
1120a0af9addSFrancisco Jerez 			nouveau_bo_vm_cleanup(bo, NULL, &new_tile);
1121a0af9addSFrancisco Jerez 		else
1122a0af9addSFrancisco Jerez 			nouveau_bo_vm_cleanup(bo, new_tile, &nvbo->tile);
1123a4154bbfSBen Skeggs 	}
11246d820003SDave Airlie out_ntfy:
11256d820003SDave Airlie 	if (ret) {
1126d3116756SChristian König 		nouveau_bo_move_ntfy(bo, bo->resource);
11276d820003SDave Airlie 	}
1128a0af9addSFrancisco Jerez 	return ret;
11296ee73861SBen Skeggs }
11306ee73861SBen Skeggs 
1131141b15e5SChristian König static void
nouveau_ttm_io_mem_free_locked(struct nouveau_drm * drm,struct ttm_resource * reg)1132141b15e5SChristian König nouveau_ttm_io_mem_free_locked(struct nouveau_drm *drm,
1133141b15e5SChristian König 			       struct ttm_resource *reg)
1134141b15e5SChristian König {
1135141b15e5SChristian König 	struct nouveau_mem *mem = nouveau_mem(reg);
1136141b15e5SChristian König 
1137141b15e5SChristian König 	if (drm->client.mem->oclass >= NVIF_CLASS_MEM_NV50) {
1138141b15e5SChristian König 		switch (reg->mem_type) {
1139141b15e5SChristian König 		case TTM_PL_TT:
1140141b15e5SChristian König 			if (mem->kind)
1141141b15e5SChristian König 				nvif_object_unmap_handle(&mem->mem.object);
1142141b15e5SChristian König 			break;
1143141b15e5SChristian König 		case TTM_PL_VRAM:
1144141b15e5SChristian König 			nvif_object_unmap_handle(&mem->mem.object);
1145141b15e5SChristian König 			break;
1146141b15e5SChristian König 		default:
1147141b15e5SChristian König 			break;
1148141b15e5SChristian König 		}
1149141b15e5SChristian König 	}
1150141b15e5SChristian König }
1151141b15e5SChristian König 
1152f32f02fdSJerome Glisse static int
nouveau_ttm_io_mem_reserve(struct ttm_device * bdev,struct ttm_resource * reg)11538af8a109SChristian König nouveau_ttm_io_mem_reserve(struct ttm_device *bdev, struct ttm_resource *reg)
1154f32f02fdSJerome Glisse {
1155ebb945a9SBen Skeggs 	struct nouveau_drm *drm = nouveau_bdev(bdev);
11561167c6bcSBen Skeggs 	struct nvkm_device *device = nvxx_device(&drm->client.device);
11579ce523ccSBen Skeggs 	struct nouveau_mem *mem = nouveau_mem(reg);
11581cf65c45SChristian König 	struct nvif_mmu *mmu = &drm->client.mmu;
1159141b15e5SChristian König 	int ret;
1160f32f02fdSJerome Glisse 
1161141b15e5SChristian König 	mutex_lock(&drm->ttm.io_reserve_mutex);
1162141b15e5SChristian König retry:
1163605f9ccdSBen Skeggs 	switch (reg->mem_type) {
1164f32f02fdSJerome Glisse 	case TTM_PL_SYSTEM:
1165f32f02fdSJerome Glisse 		/* System memory */
1166141b15e5SChristian König 		ret = 0;
1167141b15e5SChristian König 		goto out;
1168f32f02fdSJerome Glisse 	case TTM_PL_TT:
1169a7fb8a23SDaniel Vetter #if IS_ENABLED(CONFIG_AGP)
1170340b0e7cSBen Skeggs 		if (drm->agp.bridge) {
117154d04ea8SChristian König 			reg->bus.offset = (reg->start << PAGE_SHIFT) +
117254d04ea8SChristian König 				drm->agp.base;
1173605f9ccdSBen Skeggs 			reg->bus.is_iomem = !drm->agp.cma;
11741cf65c45SChristian König 			reg->bus.caching = ttm_write_combined;
1175f32f02fdSJerome Glisse 		}
1176f32f02fdSJerome Glisse #endif
1177141b15e5SChristian König 		if (drm->client.mem->oclass < NVIF_CLASS_MEM_NV50 ||
1178141b15e5SChristian König 		    !mem->kind) {
1179a5540906SMaarten Lankhorst 			/* untiled */
1180141b15e5SChristian König 			ret = 0;
1181f32f02fdSJerome Glisse 			break;
1182141b15e5SChristian König 		}
1183f6e7393eSGustavo A. R. Silva 		fallthrough;	/* tiled memory */
1184f32f02fdSJerome Glisse 	case TTM_PL_VRAM:
118554d04ea8SChristian König 		reg->bus.offset = (reg->start << PAGE_SHIFT) +
118654d04ea8SChristian König 			device->func->resource_addr(device, 1);
1187605f9ccdSBen Skeggs 		reg->bus.is_iomem = true;
11881cf65c45SChristian König 
11891cf65c45SChristian König 		/* Some BARs do not support being ioremapped WC */
11901cf65c45SChristian König 		if (drm->client.device.info.family >= NV_DEVICE_INFO_V0_TESLA &&
1191be323a4cSBen Skeggs 		    mmu->type[drm->ttm.type_vram].type & NVIF_MEM_UNCACHED)
11921cf65c45SChristian König 			reg->bus.caching = ttm_uncached;
11931cf65c45SChristian König 		else
11941cf65c45SChristian König 			reg->bus.caching = ttm_write_combined;
11951cf65c45SChristian König 
1196d7722134SBen Skeggs 		if (drm->client.mem->oclass >= NVIF_CLASS_MEM_NV50) {
1197d7722134SBen Skeggs 			union {
1198d7722134SBen Skeggs 				struct nv50_mem_map_v0 nv50;
1199d7722134SBen Skeggs 				struct gf100_mem_map_v0 gf100;
1200d7722134SBen Skeggs 			} args;
1201d7722134SBen Skeggs 			u64 handle, length;
1202d7722134SBen Skeggs 			u32 argc = 0;
1203f869ef88SBen Skeggs 
1204d7722134SBen Skeggs 			switch (mem->mem.object.oclass) {
1205d7722134SBen Skeggs 			case NVIF_CLASS_MEM_NV50:
1206d7722134SBen Skeggs 				args.nv50.version = 0;
1207d7722134SBen Skeggs 				args.nv50.ro = 0;
1208d7722134SBen Skeggs 				args.nv50.kind = mem->kind;
1209d7722134SBen Skeggs 				args.nv50.comp = mem->comp;
1210b554b12aSThierry Reding 				argc = sizeof(args.nv50);
1211d7722134SBen Skeggs 				break;
1212d7722134SBen Skeggs 			case NVIF_CLASS_MEM_GF100:
1213d7722134SBen Skeggs 				args.gf100.version = 0;
1214d7722134SBen Skeggs 				args.gf100.ro = 0;
1215d7722134SBen Skeggs 				args.gf100.kind = mem->kind;
1216b554b12aSThierry Reding 				argc = sizeof(args.gf100);
1217d7722134SBen Skeggs 				break;
1218d7722134SBen Skeggs 			default:
1219d7722134SBen Skeggs 				WARN_ON(1);
1220d7722134SBen Skeggs 				break;
1221d7722134SBen Skeggs 			}
1222f869ef88SBen Skeggs 
1223d7722134SBen Skeggs 			ret = nvif_object_map_handle(&mem->mem.object,
1224b554b12aSThierry Reding 						     &args, argc,
1225d7722134SBen Skeggs 						     &handle, &length);
12268a39db76SBen Skeggs 			if (ret != 1) {
12278a39db76SBen Skeggs 				if (WARN_ON(ret == 0))
1228141b15e5SChristian König 					ret = -EINVAL;
1229141b15e5SChristian König 				goto out;
12308a39db76SBen Skeggs 			}
1231d7722134SBen Skeggs 
1232d7722134SBen Skeggs 			reg->bus.offset = handle;
1233f869ef88SBen Skeggs 		}
1234aea656b0SChristian König 		ret = 0;
1235f869ef88SBen Skeggs 		break;
1236f32f02fdSJerome Glisse 	default:
1237141b15e5SChristian König 		ret = -EINVAL;
1238f32f02fdSJerome Glisse 	}
1239141b15e5SChristian König 
1240141b15e5SChristian König out:
1241141b15e5SChristian König 	if (ret == -ENOSPC) {
1242141b15e5SChristian König 		struct nouveau_bo *nvbo;
1243141b15e5SChristian König 
1244141b15e5SChristian König 		nvbo = list_first_entry_or_null(&drm->ttm.io_reserve_lru,
1245141b15e5SChristian König 						typeof(*nvbo),
1246141b15e5SChristian König 						io_reserve_lru);
1247141b15e5SChristian König 		if (nvbo) {
1248141b15e5SChristian König 			list_del_init(&nvbo->io_reserve_lru);
1249141b15e5SChristian König 			drm_vma_node_unmap(&nvbo->bo.base.vma_node,
1250141b15e5SChristian König 					   bdev->dev_mapping);
1251d3116756SChristian König 			nouveau_ttm_io_mem_free_locked(drm, nvbo->bo.resource);
1252123c3bccSDave Airlie 			nvbo->bo.resource->bus.offset = 0;
1253123c3bccSDave Airlie 			nvbo->bo.resource->bus.addr = NULL;
1254141b15e5SChristian König 			goto retry;
1255141b15e5SChristian König 		}
1256141b15e5SChristian König 
1257141b15e5SChristian König 	}
1258141b15e5SChristian König 	mutex_unlock(&drm->ttm.io_reserve_mutex);
1259141b15e5SChristian König 	return ret;
1260f32f02fdSJerome Glisse }
1261f32f02fdSJerome Glisse 
1262f32f02fdSJerome Glisse static void
nouveau_ttm_io_mem_free(struct ttm_device * bdev,struct ttm_resource * reg)12638af8a109SChristian König nouveau_ttm_io_mem_free(struct ttm_device *bdev, struct ttm_resource *reg)
1264f32f02fdSJerome Glisse {
1265d7722134SBen Skeggs 	struct nouveau_drm *drm = nouveau_bdev(bdev);
1266f869ef88SBen Skeggs 
1267141b15e5SChristian König 	mutex_lock(&drm->ttm.io_reserve_mutex);
1268141b15e5SChristian König 	nouveau_ttm_io_mem_free_locked(drm, reg);
1269141b15e5SChristian König 	mutex_unlock(&drm->ttm.io_reserve_mutex);
1270f32f02fdSJerome Glisse }
1271f32f02fdSJerome Glisse 
nouveau_ttm_fault_reserve_notify(struct ttm_buffer_object * bo)127276fe313aSChristian König vm_fault_t nouveau_ttm_fault_reserve_notify(struct ttm_buffer_object *bo)
1273f32f02fdSJerome Glisse {
1274ebb945a9SBen Skeggs 	struct nouveau_drm *drm = nouveau_bdev(bo->bdev);
1275e1429b4cSBen Skeggs 	struct nouveau_bo *nvbo = nouveau_bo(bo);
12761167c6bcSBen Skeggs 	struct nvkm_device *device = nvxx_device(&drm->client.device);
12777e8820feSBen Skeggs 	u32 mappable = device->func->resource_size(device, 1) >> PAGE_SHIFT;
1278f1217ed0SChristian König 	int i, ret;
1279e1429b4cSBen Skeggs 
1280e1429b4cSBen Skeggs 	/* as long as the bo isn't in vram, and isn't tiled, we've got
1281e1429b4cSBen Skeggs 	 * nothing to do here.
1282e1429b4cSBen Skeggs 	 */
1283d3116756SChristian König 	if (bo->resource->mem_type != TTM_PL_VRAM) {
12841167c6bcSBen Skeggs 		if (drm->client.device.info.family < NV_DEVICE_INFO_V0_TESLA ||
12857760a2e3SBen Skeggs 		    !nvbo->kind)
1286f32f02fdSJerome Glisse 			return 0;
1287a5540906SMaarten Lankhorst 
1288d3116756SChristian König 		if (bo->resource->mem_type != TTM_PL_SYSTEM)
1289a5540906SMaarten Lankhorst 			return 0;
1290f32f02fdSJerome Glisse 
129176fe313aSChristian König 		nouveau_bo_placement_set(nvbo, NOUVEAU_GEM_DOMAIN_GART, 0);
129276fe313aSChristian König 
129376fe313aSChristian König 	} else {
1294e1429b4cSBen Skeggs 		/* make sure bo is in mappable vram */
12951167c6bcSBen Skeggs 		if (drm->client.device.info.family >= NV_DEVICE_INFO_V0_TESLA ||
1296e3c92eb4SSomalapuram Amaranath 		    bo->resource->start + PFN_UP(bo->resource->size) < mappable)
1297e1429b4cSBen Skeggs 			return 0;
1298e1429b4cSBen Skeggs 
1299f1217ed0SChristian König 		for (i = 0; i < nvbo->placement.num_placement; ++i) {
1300f1217ed0SChristian König 			nvbo->placements[i].fpfn = 0;
1301f1217ed0SChristian König 			nvbo->placements[i].lpfn = mappable;
1302f1217ed0SChristian König 		}
1303e1429b4cSBen Skeggs 
1304f1217ed0SChristian König 		for (i = 0; i < nvbo->placement.num_busy_placement; ++i) {
1305f1217ed0SChristian König 			nvbo->busy_placements[i].fpfn = 0;
1306f1217ed0SChristian König 			nvbo->busy_placements[i].lpfn = mappable;
1307f1217ed0SChristian König 		}
1308f1217ed0SChristian König 
130981b61579SChristian König 		nouveau_bo_placement_set(nvbo, NOUVEAU_GEM_DOMAIN_VRAM, 0);
131076fe313aSChristian König 	}
131176fe313aSChristian König 
131276fe313aSChristian König 	ret = nouveau_bo_validate(nvbo, false, false);
131376fe313aSChristian König 	if (unlikely(ret == -EBUSY || ret == -ERESTARTSYS))
131476fe313aSChristian König 		return VM_FAULT_NOPAGE;
131576fe313aSChristian König 	else if (unlikely(ret))
131676fe313aSChristian König 		return VM_FAULT_SIGBUS;
131776fe313aSChristian König 
131876fe313aSChristian König 	ttm_bo_move_to_lru_tail_unlocked(bo);
131976fe313aSChristian König 	return 0;
1320e1429b4cSBen Skeggs }
1321e1429b4cSBen Skeggs 
13223230cfc3SKonrad Rzeszutek Wilk static int
nouveau_ttm_tt_populate(struct ttm_device * bdev,struct ttm_tt * ttm,struct ttm_operation_ctx * ctx)13238af8a109SChristian König nouveau_ttm_tt_populate(struct ttm_device *bdev,
13240a667b50SDave Airlie 			struct ttm_tt *ttm, struct ttm_operation_ctx *ctx)
13253230cfc3SKonrad Rzeszutek Wilk {
1326e34b8feeSChristian König 	struct ttm_tt *ttm_dma = (void *)ttm;
1327ebb945a9SBen Skeggs 	struct nouveau_drm *drm;
132843d46f0bSMatthew Auld 	bool slave = !!(ttm->page_flags & TTM_TT_FLAG_EXTERNAL);
13293230cfc3SKonrad Rzeszutek Wilk 
13307eec9151SDave Airlie 	if (ttm_tt_is_populated(ttm))
13313230cfc3SKonrad Rzeszutek Wilk 		return 0;
13323230cfc3SKonrad Rzeszutek Wilk 
133322b33e8eSDave Airlie 	if (slave && ttm->sg) {
1334c67e6279SChristian König 		drm_prime_sg_to_dma_addr_array(ttm->sg, ttm_dma->dma_address,
1335470cfe71SChristian König 					       ttm->num_pages);
133622b33e8eSDave Airlie 		return 0;
133722b33e8eSDave Airlie 	}
133822b33e8eSDave Airlie 
13390a667b50SDave Airlie 	drm = nouveau_bdev(bdev);
13403230cfc3SKonrad Rzeszutek Wilk 
1341461619f5SChristian König 	return ttm_pool_alloc(&drm->ttm.bdev.pool, ttm, ctx);
13423230cfc3SKonrad Rzeszutek Wilk }
13433230cfc3SKonrad Rzeszutek Wilk 
13443230cfc3SKonrad Rzeszutek Wilk static void
nouveau_ttm_tt_unpopulate(struct ttm_device * bdev,struct ttm_tt * ttm)13458af8a109SChristian König nouveau_ttm_tt_unpopulate(struct ttm_device *bdev,
13460a667b50SDave Airlie 			  struct ttm_tt *ttm)
13473230cfc3SKonrad Rzeszutek Wilk {
1348ebb945a9SBen Skeggs 	struct nouveau_drm *drm;
134943d46f0bSMatthew Auld 	bool slave = !!(ttm->page_flags & TTM_TT_FLAG_EXTERNAL);
135022b33e8eSDave Airlie 
135122b33e8eSDave Airlie 	if (slave)
135222b33e8eSDave Airlie 		return;
13533230cfc3SKonrad Rzeszutek Wilk 
135461a8736fSChristian König 	nouveau_ttm_tt_unbind(bdev, ttm);
135561a8736fSChristian König 
13560a667b50SDave Airlie 	drm = nouveau_bdev(bdev);
13573230cfc3SKonrad Rzeszutek Wilk 
1358461619f5SChristian König 	return ttm_pool_free(&drm->ttm.bdev.pool, ttm);
13593230cfc3SKonrad Rzeszutek Wilk }
13603230cfc3SKonrad Rzeszutek Wilk 
13618635784aSDave Airlie static void
nouveau_ttm_tt_destroy(struct ttm_device * bdev,struct ttm_tt * ttm)13628af8a109SChristian König nouveau_ttm_tt_destroy(struct ttm_device *bdev,
13638635784aSDave Airlie 		       struct ttm_tt *ttm)
13648635784aSDave Airlie {
13658635784aSDave Airlie #if IS_ENABLED(CONFIG_AGP)
13668635784aSDave Airlie 	struct nouveau_drm *drm = nouveau_bdev(bdev);
13678635784aSDave Airlie 	if (drm->agp.bridge) {
136848efa57eSDave Airlie 		ttm_agp_destroy(ttm);
13698635784aSDave Airlie 		return;
13708635784aSDave Airlie 	}
13718635784aSDave Airlie #endif
13728635784aSDave Airlie 	nouveau_sgdma_destroy(bdev, ttm);
13738635784aSDave Airlie }
13748635784aSDave Airlie 
1375dd7cfd64SMaarten Lankhorst void
nouveau_bo_fence(struct nouveau_bo * nvbo,struct nouveau_fence * fence,bool exclusive)1376809e9447SMaarten Lankhorst nouveau_bo_fence(struct nouveau_bo *nvbo, struct nouveau_fence *fence, bool exclusive)
1377dd7cfd64SMaarten Lankhorst {
137852791eeeSChristian König 	struct dma_resv *resv = nvbo->bo.base.resv;
1379dd7cfd64SMaarten Lankhorst 
138073511edfSChristian König 	if (!fence)
138173511edfSChristian König 		return;
138273511edfSChristian König 
138373511edfSChristian König 	dma_resv_add_fence(resv, &fence->base, exclusive ?
138473511edfSChristian König 			   DMA_RESV_USAGE_WRITE : DMA_RESV_USAGE_READ);
1385dd7cfd64SMaarten Lankhorst }
1386dd7cfd64SMaarten Lankhorst 
13876a6e5988SDave Airlie static void
nouveau_bo_delete_mem_notify(struct ttm_buffer_object * bo)13886a6e5988SDave Airlie nouveau_bo_delete_mem_notify(struct ttm_buffer_object *bo)
13896a6e5988SDave Airlie {
13905ea143c3SChristian König 	nouveau_bo_move_ntfy(bo, NULL);
13916a6e5988SDave Airlie }
13926a6e5988SDave Airlie 
13938af8a109SChristian König struct ttm_device_funcs nouveau_bo_driver = {
1394649bf3caSJerome Glisse 	.ttm_tt_create = &nouveau_ttm_tt_create,
13953230cfc3SKonrad Rzeszutek Wilk 	.ttm_tt_populate = &nouveau_ttm_tt_populate,
13963230cfc3SKonrad Rzeszutek Wilk 	.ttm_tt_unpopulate = &nouveau_ttm_tt_unpopulate,
13978635784aSDave Airlie 	.ttm_tt_destroy = &nouveau_ttm_tt_destroy,
1398a2ab19feSChristian König 	.eviction_valuable = ttm_bo_eviction_valuable,
13996ee73861SBen Skeggs 	.evict_flags = nouveau_bo_evict_flags,
14006a6e5988SDave Airlie 	.delete_mem_notify = nouveau_bo_delete_mem_notify,
14016ee73861SBen Skeggs 	.move = nouveau_bo_move,
1402f32f02fdSJerome Glisse 	.io_mem_reserve = &nouveau_ttm_io_mem_reserve,
1403f32f02fdSJerome Glisse 	.io_mem_free = &nouveau_ttm_io_mem_free,
14046ee73861SBen Skeggs };
1405