nouveau_bo.c 41.1 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
/*
 * Copyright 2007 Dave Airlied
 * All Rights Reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice (including the next
 * paragraph) shall be included in all copies or substantial portions of the
 * Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 */
/*
 * Authors: Dave Airlied <airlied@linux.ie>
 *	    Ben Skeggs   <darktama@iinet.net.au>
 *	    Jeremy Kolb  <jkolb@brandeis.edu>
 */

30
#include <linux/dma-mapping.h>
31
#include <linux/swiotlb.h>
32

33
#include "nouveau_drv.h"
34
#include "nouveau_dma.h"
35
#include "nouveau_fence.h"
36

37 38 39
#include "nouveau_bo.h"
#include "nouveau_ttm.h"
#include "nouveau_gem.h"
40
#include "nouveau_mem.h"
41
#include "nouveau_vmm.h"
42

43 44 45 46
#include <nvif/class.h>
#include <nvif/if500b.h>
#include <nvif/if900b.h>

47 48 49 50 51
/*
 * NV10-NV40 tiling helpers
 */

static void
52 53
nv10_bo_update_tile_region(struct drm_device *dev, struct nouveau_drm_tile *reg,
			   u32 addr, u32 size, u32 pitch, u32 flags)
54
{
55
	struct nouveau_drm *drm = nouveau_drm(dev);
56
	int i = reg - drm->tile.reg;
57
	struct nvkm_fb *fb = nvxx_fb(&drm->client.device);
B
Ben Skeggs 已提交
58
	struct nvkm_fb_tile *tile = &fb->tile.region[i];
59

60
	nouveau_fence_unref(&reg->fence);
61 62

	if (tile->pitch)
63
		nvkm_fb_tile_fini(fb, i, tile);
64 65

	if (pitch)
66
		nvkm_fb_tile_init(fb, i, addr, size, pitch, flags, tile);
67

68
	nvkm_fb_tile_prog(fb, i, tile);
69 70
}

71
static struct nouveau_drm_tile *
72 73
nv10_bo_get_tile_region(struct drm_device *dev, int i)
{
74
	struct nouveau_drm *drm = nouveau_drm(dev);
75
	struct nouveau_drm_tile *tile = &drm->tile.reg[i];
76

77
	spin_lock(&drm->tile.lock);
78 79 80 81 82 83 84

	if (!tile->used &&
	    (!tile->fence || nouveau_fence_done(tile->fence)))
		tile->used = true;
	else
		tile = NULL;

85
	spin_unlock(&drm->tile.lock);
86 87 88 89
	return tile;
}

static void
90
nv10_bo_put_tile_region(struct drm_device *dev, struct nouveau_drm_tile *tile,
91
			struct dma_fence *fence)
92
{
93
	struct nouveau_drm *drm = nouveau_drm(dev);
94 95

	if (tile) {
96
		spin_lock(&drm->tile.lock);
97
		tile->fence = (struct nouveau_fence *)dma_fence_get(fence);
98
		tile->used = false;
99
		spin_unlock(&drm->tile.lock);
100 101 102
	}
}

103 104
static struct nouveau_drm_tile *
nv10_bo_set_tiling(struct drm_device *dev, u32 addr,
105
		   u32 size, u32 pitch, u32 zeta)
106
{
107
	struct nouveau_drm *drm = nouveau_drm(dev);
108
	struct nvkm_fb *fb = nvxx_fb(&drm->client.device);
109
	struct nouveau_drm_tile *tile, *found = NULL;
110 111
	int i;

B
Ben Skeggs 已提交
112
	for (i = 0; i < fb->tile.regions; i++) {
113 114 115 116 117 118
		tile = nv10_bo_get_tile_region(dev, i);

		if (pitch && !found) {
			found = tile;
			continue;

B
Ben Skeggs 已提交
119
		} else if (tile && fb->tile.region[i].pitch) {
120 121 122 123 124 125 126 127
			/* Kill an unused tile region. */
			nv10_bo_update_tile_region(dev, tile, 0, 0, 0, 0);
		}

		nv10_bo_put_tile_region(dev, tile, NULL);
	}

	if (found)
128
		nv10_bo_update_tile_region(dev, found, addr, size, pitch, zeta);
129 130 131
	return found;
}

132 133 134
static void
nouveau_bo_del_ttm(struct ttm_buffer_object *bo)
{
135 136
	struct nouveau_drm *drm = nouveau_bdev(bo->bdev);
	struct drm_device *dev = drm->dev;
137 138
	struct nouveau_bo *nvbo = nouveau_bo(bo);

139
	if (unlikely(nvbo->gem.filp))
140
		DRM_ERROR("bo %p still attached to GEM object\n", bo);
141
	WARN_ON(nvbo->pin_refcnt > 0);
142
	nv10_bo_put_tile_region(dev, nvbo->tile, NULL);
143 144 145
	kfree(nvbo);
}

B
Ben Skeggs 已提交
146 147 148 149 150 151 152 153
static inline u64
roundup_64(u64 x, u32 y)
{
	x += y - 1;
	do_div(x, y);
	return x * y;
}

154
static void
155
nouveau_bo_fixup_align(struct nouveau_bo *nvbo, u32 flags,
B
Ben Skeggs 已提交
156
		       int *align, u64 *size)
157
{
158
	struct nouveau_drm *drm = nouveau_bdev(nvbo->bo.bdev);
159
	struct nvif_device *device = &drm->client.device;
160

161
	if (device->info.family < NV_DEVICE_INFO_V0_TESLA) {
162
		if (nvbo->mode) {
163
			if (device->info.chipset >= 0x40) {
164
				*align = 65536;
165
				*size = roundup_64(*size, 64 * nvbo->mode);
166

167
			} else if (device->info.chipset >= 0x30) {
168
				*align = 32768;
169
				*size = roundup_64(*size, 64 * nvbo->mode);
170

171
			} else if (device->info.chipset >= 0x20) {
172
				*align = 16384;
173
				*size = roundup_64(*size, 64 * nvbo->mode);
174

175
			} else if (device->info.chipset >= 0x10) {
176
				*align = 16384;
177
				*size = roundup_64(*size, 32 * nvbo->mode);
178 179
			}
		}
180
	} else {
181 182
		*size = roundup_64(*size, (1 << nvbo->page));
		*align = max((1 <<  nvbo->page), *align);
183 184
	}

B
Ben Skeggs 已提交
185
	*size = roundup_64(*size, PAGE_SIZE);
186 187
}

188
int
B
Ben Skeggs 已提交
189
nouveau_bo_new(struct nouveau_cli *cli, u64 size, int align,
190
	       uint32_t flags, uint32_t tile_mode, uint32_t tile_flags,
191
	       struct sg_table *sg, struct reservation_object *robj,
192
	       struct nouveau_bo **pnvbo)
193
{
194
	struct nouveau_drm *drm = cli->drm;
195
	struct nouveau_bo *nvbo;
196
	struct nvif_mmu *mmu = &cli->mmu;
197
	size_t acc_size;
198
	int ret;
D
Dave Airlie 已提交
199
	int type = ttm_bo_type_device;
200

B
Ben Skeggs 已提交
201 202
	if (!size) {
		NV_WARN(drm, "skipped size %016llx\n", size);
203 204
		return -EINVAL;
	}
D
Dave Airlie 已提交
205 206 207

	if (sg)
		type = ttm_bo_type_sg;
208 209 210 211 212 213

	nvbo = kzalloc(sizeof(struct nouveau_bo), GFP_KERNEL);
	if (!nvbo)
		return -ENOMEM;
	INIT_LIST_HEAD(&nvbo->head);
	INIT_LIST_HEAD(&nvbo->entry);
214
	INIT_LIST_HEAD(&nvbo->vma_list);
215
	nvbo->bo.bdev = &drm->ttm.bdev;
216
	nvbo->cli = cli;
217

218 219 220 221 222 223 224 225 226 227 228
	/* This is confusing, and doesn't actually mean we want an uncached
	 * mapping, but is what NOUVEAU_GEM_DOMAIN_COHERENT gets translated
	 * into in nouveau_gem_new().
	 */
	if (flags & TTM_PL_FLAG_UNCACHED) {
		/* Determine if we can get a cache-coherent map, forcing
		 * uncached mapping if we can't.
		 */
		if (mmu->type[drm->ttm.type_host].type & NVIF_MEM_UNCACHED)
			nvbo->force_coherent = true;
	}
229

230 231
	if (cli->device.info.family >= NV_DEVICE_INFO_V0_FERMI) {
		nvbo->kind = (tile_flags & 0x0000ff00) >> 8;
232 233 234 235 236 237
		if (!nvif_mmu_kind_valid(mmu, nvbo->kind)) {
			kfree(nvbo);
			return -EINVAL;
		}

		nvbo->comp = mmu->kind[nvbo->kind] != nvbo->kind;
238 239 240 241
	} else
	if (cli->device.info.family >= NV_DEVICE_INFO_V0_TESLA) {
		nvbo->kind = (tile_flags & 0x00007f00) >> 8;
		nvbo->comp = (tile_flags & 0x00030000) >> 16;
242 243 244 245
		if (!nvif_mmu_kind_valid(mmu, nvbo->kind)) {
			kfree(nvbo);
			return -EINVAL;
		}
246 247 248 249 250 251 252
	} else {
		nvbo->zeta = (tile_flags & 0x00000007);
	}
	nvbo->mode = tile_mode;
	nvbo->contig = !(tile_flags & NOUVEAU_GEM_TILE_NONCONTIG);

	nvbo->page = 12;
253
	if (drm->client.vm) {
254
		if (!(flags & TTM_PL_FLAG_TT) && size > 256 * 1024)
255 256 257
			nvbo->page = drm->client.vm->mmu->lpg_shift;
		else {
			if (cli->device.info.family >= NV_DEVICE_INFO_V0_FERMI)
258
				nvbo->kind = mmu->kind[nvbo->kind];
259 260
			nvbo->comp = 0;
		}
261 262 263
	}

	nouveau_bo_fixup_align(nvbo, flags, &align, &size);
264 265
	nvbo->bo.mem.num_pages = size >> PAGE_SHIFT;
	nouveau_bo_placement_set(nvbo, flags, 0);
266

267
	acc_size = ttm_bo_dma_acc_size(&drm->ttm.bdev, size,
268 269
				       sizeof(struct nouveau_bo));

270
	ret = ttm_bo_init(&drm->ttm.bdev, &nvbo->bo, size,
D
Dave Airlie 已提交
271
			  type, &nvbo->placement,
272
			  align >> PAGE_SHIFT, false, NULL, acc_size, sg,
273
			  robj, nouveau_bo_del_ttm);
274 275 276 277 278 279 280 281 282
	if (ret) {
		/* ttm will call nouveau_bo_del_ttm if it fails.. */
		return ret;
	}

	*pnvbo = nvbo;
	return 0;
}

283
static void
284
set_placement_list(struct ttm_place *pl, unsigned *n, uint32_t type, uint32_t flags)
285 286 287 288
{
	*n = 0;

	if (type & TTM_PL_FLAG_VRAM)
289
		pl[(*n)++].flags = TTM_PL_FLAG_VRAM | flags;
290
	if (type & TTM_PL_FLAG_TT)
291
		pl[(*n)++].flags = TTM_PL_FLAG_TT | flags;
292
	if (type & TTM_PL_FLAG_SYSTEM)
293
		pl[(*n)++].flags = TTM_PL_FLAG_SYSTEM | flags;
294 295
}

296 297 298
static void
set_placement_range(struct nouveau_bo *nvbo, uint32_t type)
{
299
	struct nouveau_drm *drm = nouveau_bdev(nvbo->bo.bdev);
300
	u32 vram_pages = drm->client.device.info.ram_size >> PAGE_SHIFT;
301
	unsigned i, fpfn, lpfn;
302

303
	if (drm->client.device.info.family == NV_DEVICE_INFO_V0_CELSIUS &&
304
	    nvbo->mode && (type & TTM_PL_FLAG_VRAM) &&
305
	    nvbo->bo.mem.num_pages < vram_pages / 4) {
306 307 308 309 310 311
		/*
		 * Make sure that the color and depth buffers are handled
		 * by independent memory controller units. Up to a 9x
		 * speed up when alpha-blending and depth-test are enabled
		 * at the same time.
		 */
312
		if (nvbo->zeta) {
313 314
			fpfn = vram_pages / 2;
			lpfn = ~0;
315
		} else {
316 317 318 319 320 321 322 323 324 325
			fpfn = 0;
			lpfn = vram_pages / 2;
		}
		for (i = 0; i < nvbo->placement.num_placement; ++i) {
			nvbo->placements[i].fpfn = fpfn;
			nvbo->placements[i].lpfn = lpfn;
		}
		for (i = 0; i < nvbo->placement.num_busy_placement; ++i) {
			nvbo->busy_placements[i].fpfn = fpfn;
			nvbo->busy_placements[i].lpfn = lpfn;
326 327 328 329
		}
	}
}

330
void
331
nouveau_bo_placement_set(struct nouveau_bo *nvbo, uint32_t type, uint32_t busy)
332
{
333
	struct ttm_placement *pl = &nvbo->placement;
334 335 336
	uint32_t flags = (nvbo->force_coherent ? TTM_PL_FLAG_UNCACHED :
						 TTM_PL_MASK_CACHING) |
			 (nvbo->pin_refcnt ? TTM_PL_FLAG_NO_EVICT : 0);
337 338 339 340 341 342 343 344

	pl->placement = nvbo->placements;
	set_placement_list(nvbo->placements, &pl->num_placement,
			   type, flags);

	pl->busy_placement = nvbo->busy_placements;
	set_placement_list(nvbo->busy_placements, &pl->num_busy_placement,
			   type | busy, flags);
345 346

	set_placement_range(nvbo, type);
347 348 349
}

int
350
nouveau_bo_pin(struct nouveau_bo *nvbo, uint32_t memtype, bool contig)
351
{
352
	struct nouveau_drm *drm = nouveau_bdev(nvbo->bo.bdev);
353
	struct ttm_buffer_object *bo = &nvbo->bo;
354
	bool force = false, evict = false;
355
	int ret;
356

357
	ret = ttm_bo_reserve(bo, false, false, NULL);
358
	if (ret)
359
		return ret;
360

361
	if (drm->client.device.info.family >= NV_DEVICE_INFO_V0_TESLA &&
362
	    memtype == TTM_PL_FLAG_VRAM && contig) {
363 364
		if (!nvbo->contig) {
			nvbo->contig = true;
365
			force = true;
366
			evict = true;
367
		}
368 369
	}

370 371 372 373 374 375 376 377
	if (nvbo->pin_refcnt) {
		if (!(memtype & (1 << bo->mem.mem_type)) || evict) {
			NV_ERROR(drm, "bo %p pinned elsewhere: "
				      "0x%08x vs 0x%08x\n", bo,
				 1 << bo->mem.mem_type, memtype);
			ret = -EBUSY;
		}
		nvbo->pin_refcnt++;
378
		goto out;
379 380 381 382 383 384 385 386
	}

	if (evict) {
		nouveau_bo_placement_set(nvbo, TTM_PL_FLAG_TT, 0);
		ret = nouveau_bo_validate(nvbo, false, false);
		if (ret)
			goto out;
	}
387

388
	nvbo->pin_refcnt++;
389
	nouveau_bo_placement_set(nvbo, memtype, 0);
390

391 392 393 394 395
	/* drop pin_refcnt temporarily, so we don't trip the assertion
	 * in nouveau_bo_move() that makes sure we're not trying to
	 * move a pinned buffer
	 */
	nvbo->pin_refcnt--;
396
	ret = nouveau_bo_validate(nvbo, false, false);
397 398
	if (ret)
		goto out;
399
	nvbo->pin_refcnt++;
400 401 402 403 404 405 406 407 408 409

	switch (bo->mem.mem_type) {
	case TTM_PL_VRAM:
		drm->gem.vram_available -= bo->mem.size;
		break;
	case TTM_PL_TT:
		drm->gem.gart_available -= bo->mem.size;
		break;
	default:
		break;
410
	}
411

412
out:
413
	if (force && ret)
414
		nvbo->contig = false;
415
	ttm_bo_unreserve(bo);
416 417 418 419 420 421
	return ret;
}

int
nouveau_bo_unpin(struct nouveau_bo *nvbo)
{
422
	struct nouveau_drm *drm = nouveau_bdev(nvbo->bo.bdev);
423
	struct ttm_buffer_object *bo = &nvbo->bo;
424
	int ret, ref;
425

426
	ret = ttm_bo_reserve(bo, false, false, NULL);
427 428 429
	if (ret)
		return ret;

430 431 432
	ref = --nvbo->pin_refcnt;
	WARN_ON_ONCE(ref < 0);
	if (ref)
433 434
		goto out;

435
	nouveau_bo_placement_set(nvbo, bo->mem.placement, 0);
436

437
	ret = nouveau_bo_validate(nvbo, false, false);
438 439 440
	if (ret == 0) {
		switch (bo->mem.mem_type) {
		case TTM_PL_VRAM:
441
			drm->gem.vram_available += bo->mem.size;
442 443
			break;
		case TTM_PL_TT:
444
			drm->gem.gart_available += bo->mem.size;
445 446 447 448 449 450
			break;
		default:
			break;
		}
	}

451
out:
452 453 454 455 456 457 458 459 460
	ttm_bo_unreserve(bo);
	return ret;
}

int
nouveau_bo_map(struct nouveau_bo *nvbo)
{
	int ret;

461
	ret = ttm_bo_reserve(&nvbo->bo, false, false, NULL);
462 463 464
	if (ret)
		return ret;

465
	ret = ttm_bo_kmap(&nvbo->bo, 0, nvbo->bo.mem.num_pages, &nvbo->kmap);
466

467 468 469 470 471 472 473
	ttm_bo_unreserve(&nvbo->bo);
	return ret;
}

void
nouveau_bo_unmap(struct nouveau_bo *nvbo)
{
474 475 476
	if (!nvbo)
		return;

477
	ttm_bo_kunmap(&nvbo->kmap);
478 479
}

480 481 482 483 484 485 486 487 488 489 490 491 492 493 494
void
nouveau_bo_sync_for_device(struct nouveau_bo *nvbo)
{
	struct nouveau_drm *drm = nouveau_bdev(nvbo->bo.bdev);
	struct ttm_dma_tt *ttm_dma = (struct ttm_dma_tt *)nvbo->bo.ttm;
	int i;

	if (!ttm_dma)
		return;

	/* Don't waste time looping if the object is coherent */
	if (nvbo->force_coherent)
		return;

	for (i = 0; i < ttm_dma->ttm.num_pages; i++)
495 496
		dma_sync_single_for_device(drm->dev->dev,
					   ttm_dma->dma_address[i],
497
					   PAGE_SIZE, DMA_TO_DEVICE);
498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514
}

void
nouveau_bo_sync_for_cpu(struct nouveau_bo *nvbo)
{
	struct nouveau_drm *drm = nouveau_bdev(nvbo->bo.bdev);
	struct ttm_dma_tt *ttm_dma = (struct ttm_dma_tt *)nvbo->bo.ttm;
	int i;

	if (!ttm_dma)
		return;

	/* Don't waste time looping if the object is coherent */
	if (nvbo->force_coherent)
		return;

	for (i = 0; i < ttm_dma->ttm.num_pages; i++)
515
		dma_sync_single_for_cpu(drm->dev->dev, ttm_dma->dma_address[i],
516
					PAGE_SIZE, DMA_FROM_DEVICE);
517 518
}

519 520
int
nouveau_bo_validate(struct nouveau_bo *nvbo, bool interruptible,
521
		    bool no_wait_gpu)
522 523 524
{
	int ret;

525 526
	ret = ttm_bo_validate(&nvbo->bo, &nvbo->placement,
			      interruptible, no_wait_gpu);
527 528 529
	if (ret)
		return ret;

530 531
	nouveau_bo_sync_for_device(nvbo);

532 533 534
	return 0;
}

535 536 537 538 539
void
nouveau_bo_wr16(struct nouveau_bo *nvbo, unsigned index, u16 val)
{
	bool is_iomem;
	u16 *mem = ttm_kmap_obj_virtual(&nvbo->kmap, &is_iomem);
540

541
	mem += index;
542

543 544 545 546 547 548 549 550 551 552 553
	if (is_iomem)
		iowrite16_native(val, (void __force __iomem *)mem);
	else
		*mem = val;
}

u32
nouveau_bo_rd32(struct nouveau_bo *nvbo, unsigned index)
{
	bool is_iomem;
	u32 *mem = ttm_kmap_obj_virtual(&nvbo->kmap, &is_iomem);
554

555
	mem += index;
556

557 558 559 560 561 562 563 564 565 566 567
	if (is_iomem)
		return ioread32_native((void __force __iomem *)mem);
	else
		return *mem;
}

void
nouveau_bo_wr32(struct nouveau_bo *nvbo, unsigned index, u32 val)
{
	bool is_iomem;
	u32 *mem = ttm_kmap_obj_virtual(&nvbo->kmap, &is_iomem);
568

569
	mem += index;
570

571 572 573 574 575 576
	if (is_iomem)
		iowrite32_native(val, (void __force __iomem *)mem);
	else
		*mem = val;
}

577
static struct ttm_tt *
578 579
nouveau_ttm_tt_create(struct ttm_bo_device *bdev, unsigned long size,
		      uint32_t page_flags, struct page *dummy_read)
580
{
D
Daniel Vetter 已提交
581
#if IS_ENABLED(CONFIG_AGP)
582
	struct nouveau_drm *drm = nouveau_bdev(bdev);
583

584 585
	if (drm->agp.bridge) {
		return ttm_agp_tt_create(bdev, drm->agp.bridge, size,
586
					 page_flags, dummy_read);
587
	}
588
#endif
589

590
	return nouveau_sgdma_create_ttm(bdev, size, page_flags, dummy_read);
591 592 593 594 595 596 597 598 599 600 601 602 603
}

static int
nouveau_bo_invalidate_caches(struct ttm_bo_device *bdev, uint32_t flags)
{
	/* We'll do this from user space. */
	return 0;
}

static int
nouveau_bo_init_mem_type(struct ttm_bo_device *bdev, uint32_t type,
			 struct ttm_mem_type_manager *man)
{
604
	struct nouveau_drm *drm = nouveau_bdev(bdev);
605
	struct nvif_mmu *mmu = &drm->client.mmu;
606 607 608 609 610 611 612 613

	switch (type) {
	case TTM_PL_SYSTEM:
		man->flags = TTM_MEMTYPE_FLAG_MAPPABLE;
		man->available_caching = TTM_PL_MASK_CACHING;
		man->default_caching = TTM_PL_FLAG_CACHED;
		break;
	case TTM_PL_VRAM:
614 615 616 617 618 619
		man->flags = TTM_MEMTYPE_FLAG_FIXED |
			     TTM_MEMTYPE_FLAG_MAPPABLE;
		man->available_caching = TTM_PL_FLAG_UNCACHED |
					 TTM_PL_FLAG_WC;
		man->default_caching = TTM_PL_FLAG_WC;

620
		if (drm->client.device.info.family >= NV_DEVICE_INFO_V0_TESLA) {
621
			/* Some BARs do not support being ioremapped WC */
622 623
			const u8 type = mmu->type[drm->ttm.type_vram].type;
			if (type & NVIF_MEM_UNCACHED) {
624 625 626 627
				man->available_caching = TTM_PL_FLAG_UNCACHED;
				man->default_caching = TTM_PL_FLAG_UNCACHED;
			}

B
Ben Skeggs 已提交
628
			man->func = &nouveau_vram_manager;
629 630 631
			man->io_reserve_fastpath = false;
			man->use_io_reserve_lru = true;
		} else {
B
Ben Skeggs 已提交
632
			man->func = &ttm_bo_manager_func;
633
		}
634 635
		break;
	case TTM_PL_TT:
636
		if (drm->client.device.info.family >= NV_DEVICE_INFO_V0_TESLA)
637
			man->func = &nouveau_gart_manager;
638
		else
639
		if (!drm->agp.bridge)
640
			man->func = &nv04_gart_manager;
641 642
		else
			man->func = &ttm_bo_manager_func;
643

644
		if (drm->agp.bridge) {
645
			man->flags = TTM_MEMTYPE_FLAG_MAPPABLE;
646 647 648
			man->available_caching = TTM_PL_FLAG_UNCACHED |
				TTM_PL_FLAG_WC;
			man->default_caching = TTM_PL_FLAG_WC;
649
		} else {
650 651 652 653 654
			man->flags = TTM_MEMTYPE_FLAG_MAPPABLE |
				     TTM_MEMTYPE_FLAG_CMA;
			man->available_caching = TTM_PL_MASK_CACHING;
			man->default_caching = TTM_PL_FLAG_CACHED;
		}
655

656 657 658 659 660 661 662 663 664 665 666 667 668
		break;
	default:
		return -EINVAL;
	}
	return 0;
}

static void
nouveau_bo_evict_flags(struct ttm_buffer_object *bo, struct ttm_placement *pl)
{
	struct nouveau_bo *nvbo = nouveau_bo(bo);

	switch (bo->mem.mem_type) {
669
	case TTM_PL_VRAM:
670 671
		nouveau_bo_placement_set(nvbo, TTM_PL_FLAG_TT,
					 TTM_PL_FLAG_SYSTEM);
672
		break;
673
	default:
674
		nouveau_bo_placement_set(nvbo, TTM_PL_FLAG_SYSTEM, 0);
675 676
		break;
	}
677 678

	*pl = nvbo->placement;
679 680 681
}


682 683 684 685 686 687
static int
nve0_bo_move_init(struct nouveau_channel *chan, u32 handle)
{
	int ret = RING_SPACE(chan, 2);
	if (ret == 0) {
		BEGIN_NVC0(chan, NvSubCopy, 0x0000, 1);
688
		OUT_RING  (chan, handle & 0x0000ffff);
689 690 691 692 693
		FIRE_RING (chan);
	}
	return ret;
}

694 695
static int
nve0_bo_move_copy(struct nouveau_channel *chan, struct ttm_buffer_object *bo,
696
		  struct ttm_mem_reg *old_reg, struct ttm_mem_reg *new_reg)
697
{
698
	struct nouveau_mem *mem = nouveau_mem(old_reg);
699 700
	int ret = RING_SPACE(chan, 10);
	if (ret == 0) {
701
		BEGIN_NVC0(chan, NvSubCopy, 0x0400, 8);
702 703 704 705
		OUT_RING  (chan, upper_32_bits(mem->vma[0].addr));
		OUT_RING  (chan, lower_32_bits(mem->vma[0].addr));
		OUT_RING  (chan, upper_32_bits(mem->vma[1].addr));
		OUT_RING  (chan, lower_32_bits(mem->vma[1].addr));
706 707 708
		OUT_RING  (chan, PAGE_SIZE);
		OUT_RING  (chan, PAGE_SIZE);
		OUT_RING  (chan, PAGE_SIZE);
709
		OUT_RING  (chan, new_reg->num_pages);
710
		BEGIN_IMC0(chan, NvSubCopy, 0x0300, 0x0386);
711 712 713 714
	}
	return ret;
}

715 716 717 718 719 720 721 722 723 724 725
static int
nvc0_bo_move_init(struct nouveau_channel *chan, u32 handle)
{
	int ret = RING_SPACE(chan, 2);
	if (ret == 0) {
		BEGIN_NVC0(chan, NvSubCopy, 0x0000, 1);
		OUT_RING  (chan, handle);
	}
	return ret;
}

726 727
static int
nvc0_bo_move_copy(struct nouveau_channel *chan, struct ttm_buffer_object *bo,
728
		  struct ttm_mem_reg *old_reg, struct ttm_mem_reg *new_reg)
729
{
730 731 732
	struct nouveau_mem *mem = nouveau_mem(old_reg);
	u64 src_offset = mem->vma[0].addr;
	u64 dst_offset = mem->vma[1].addr;
733
	u32 page_count = new_reg->num_pages;
734 735
	int ret;

736
	page_count = new_reg->num_pages;
737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763
	while (page_count) {
		int line_count = (page_count > 8191) ? 8191 : page_count;

		ret = RING_SPACE(chan, 11);
		if (ret)
			return ret;

		BEGIN_NVC0(chan, NvSubCopy, 0x030c, 8);
		OUT_RING  (chan, upper_32_bits(src_offset));
		OUT_RING  (chan, lower_32_bits(src_offset));
		OUT_RING  (chan, upper_32_bits(dst_offset));
		OUT_RING  (chan, lower_32_bits(dst_offset));
		OUT_RING  (chan, PAGE_SIZE);
		OUT_RING  (chan, PAGE_SIZE);
		OUT_RING  (chan, PAGE_SIZE);
		OUT_RING  (chan, line_count);
		BEGIN_NVC0(chan, NvSubCopy, 0x0300, 1);
		OUT_RING  (chan, 0x00000110);

		page_count -= line_count;
		src_offset += (PAGE_SIZE * line_count);
		dst_offset += (PAGE_SIZE * line_count);
	}

	return 0;
}

B
Ben Skeggs 已提交
764 765
static int
nvc0_bo_move_m2mf(struct nouveau_channel *chan, struct ttm_buffer_object *bo,
766
		  struct ttm_mem_reg *old_reg, struct ttm_mem_reg *new_reg)
B
Ben Skeggs 已提交
767
{
768 769 770
	struct nouveau_mem *mem = nouveau_mem(old_reg);
	u64 src_offset = mem->vma[0].addr;
	u64 dst_offset = mem->vma[1].addr;
771
	u32 page_count = new_reg->num_pages;
B
Ben Skeggs 已提交
772 773
	int ret;

774
	page_count = new_reg->num_pages;
B
Ben Skeggs 已提交
775 776 777 778 779 780 781
	while (page_count) {
		int line_count = (page_count > 2047) ? 2047 : page_count;

		ret = RING_SPACE(chan, 12);
		if (ret)
			return ret;

782
		BEGIN_NVC0(chan, NvSubCopy, 0x0238, 2);
B
Ben Skeggs 已提交
783 784
		OUT_RING  (chan, upper_32_bits(dst_offset));
		OUT_RING  (chan, lower_32_bits(dst_offset));
785
		BEGIN_NVC0(chan, NvSubCopy, 0x030c, 6);
B
Ben Skeggs 已提交
786 787 788 789 790 791
		OUT_RING  (chan, upper_32_bits(src_offset));
		OUT_RING  (chan, lower_32_bits(src_offset));
		OUT_RING  (chan, PAGE_SIZE); /* src_pitch */
		OUT_RING  (chan, PAGE_SIZE); /* dst_pitch */
		OUT_RING  (chan, PAGE_SIZE); /* line_length */
		OUT_RING  (chan, line_count);
792
		BEGIN_NVC0(chan, NvSubCopy, 0x0300, 1);
B
Ben Skeggs 已提交
793 794 795 796 797 798 799 800 801 802
		OUT_RING  (chan, 0x00100110);

		page_count -= line_count;
		src_offset += (PAGE_SIZE * line_count);
		dst_offset += (PAGE_SIZE * line_count);
	}

	return 0;
}

803 804
static int
nva3_bo_move_copy(struct nouveau_channel *chan, struct ttm_buffer_object *bo,
805
		  struct ttm_mem_reg *old_reg, struct ttm_mem_reg *new_reg)
806
{
807 808 809
	struct nouveau_mem *mem = nouveau_mem(old_reg);
	u64 src_offset = mem->vma[0].addr;
	u64 dst_offset = mem->vma[1].addr;
810
	u32 page_count = new_reg->num_pages;
811 812
	int ret;

813
	page_count = new_reg->num_pages;
814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840
	while (page_count) {
		int line_count = (page_count > 8191) ? 8191 : page_count;

		ret = RING_SPACE(chan, 11);
		if (ret)
			return ret;

		BEGIN_NV04(chan, NvSubCopy, 0x030c, 8);
		OUT_RING  (chan, upper_32_bits(src_offset));
		OUT_RING  (chan, lower_32_bits(src_offset));
		OUT_RING  (chan, upper_32_bits(dst_offset));
		OUT_RING  (chan, lower_32_bits(dst_offset));
		OUT_RING  (chan, PAGE_SIZE);
		OUT_RING  (chan, PAGE_SIZE);
		OUT_RING  (chan, PAGE_SIZE);
		OUT_RING  (chan, line_count);
		BEGIN_NV04(chan, NvSubCopy, 0x0300, 1);
		OUT_RING  (chan, 0x00000110);

		page_count -= line_count;
		src_offset += (PAGE_SIZE * line_count);
		dst_offset += (PAGE_SIZE * line_count);
	}

	return 0;
}

841 842
static int
nv98_bo_move_exec(struct nouveau_channel *chan, struct ttm_buffer_object *bo,
843
		  struct ttm_mem_reg *old_reg, struct ttm_mem_reg *new_reg)
844
{
845
	struct nouveau_mem *mem = nouveau_mem(old_reg);
846 847 848
	int ret = RING_SPACE(chan, 7);
	if (ret == 0) {
		BEGIN_NV04(chan, NvSubCopy, 0x0320, 6);
849 850 851 852
		OUT_RING  (chan, upper_32_bits(mem->vma[0].addr));
		OUT_RING  (chan, lower_32_bits(mem->vma[0].addr));
		OUT_RING  (chan, upper_32_bits(mem->vma[1].addr));
		OUT_RING  (chan, lower_32_bits(mem->vma[1].addr));
853
		OUT_RING  (chan, 0x00000000 /* COPY */);
854
		OUT_RING  (chan, new_reg->num_pages << PAGE_SHIFT);
855 856 857 858
	}
	return ret;
}

859 860
static int
nv84_bo_move_exec(struct nouveau_channel *chan, struct ttm_buffer_object *bo,
861
		  struct ttm_mem_reg *old_reg, struct ttm_mem_reg *new_reg)
862
{
863
	struct nouveau_mem *mem = nouveau_mem(old_reg);
864 865 866
	int ret = RING_SPACE(chan, 7);
	if (ret == 0) {
		BEGIN_NV04(chan, NvSubCopy, 0x0304, 6);
867
		OUT_RING  (chan, new_reg->num_pages << PAGE_SHIFT);
868 869 870 871
		OUT_RING  (chan, upper_32_bits(mem->vma[0].addr));
		OUT_RING  (chan, lower_32_bits(mem->vma[0].addr));
		OUT_RING  (chan, upper_32_bits(mem->vma[1].addr));
		OUT_RING  (chan, lower_32_bits(mem->vma[1].addr));
872 873 874 875 876
		OUT_RING  (chan, 0x00000000 /* MODE_COPY, QUERY_NONE */);
	}
	return ret;
}

877 878 879
static int
nv50_bo_move_init(struct nouveau_channel *chan, u32 handle)
{
880
	int ret = RING_SPACE(chan, 6);
881
	if (ret == 0) {
882 883 884
		BEGIN_NV04(chan, NvSubCopy, 0x0000, 1);
		OUT_RING  (chan, handle);
		BEGIN_NV04(chan, NvSubCopy, 0x0180, 3);
885 886 887
		OUT_RING  (chan, chan->drm->ntfy.handle);
		OUT_RING  (chan, chan->vram.handle);
		OUT_RING  (chan, chan->vram.handle);
888 889 890 891 892
	}

	return ret;
}

893
static int
894
nv50_bo_move_m2mf(struct nouveau_channel *chan, struct ttm_buffer_object *bo,
895
		  struct ttm_mem_reg *old_reg, struct ttm_mem_reg *new_reg)
896
{
897
	struct nouveau_mem *mem = nouveau_mem(old_reg);
898
	u64 length = (new_reg->num_pages << PAGE_SHIFT);
899 900 901 902
	u64 src_offset = mem->vma[0].addr;
	u64 dst_offset = mem->vma[1].addr;
	int src_tiled = !!mem->kind;
	int dst_tiled = !!nouveau_mem(new_reg)->kind;
903 904
	int ret;

905 906 907
	while (length) {
		u32 amount, stride, height;

908 909 910 911
		ret = RING_SPACE(chan, 18 + 6 * (src_tiled + dst_tiled));
		if (ret)
			return ret;

912 913
		amount  = min(length, (u64)(4 * 1024 * 1024));
		stride  = 16 * 4;
914 915
		height  = amount / stride;

916
		if (src_tiled) {
917
			BEGIN_NV04(chan, NvSubCopy, 0x0200, 7);
918
			OUT_RING  (chan, 0);
919
			OUT_RING  (chan, 0);
920 921 922 923 924 925
			OUT_RING  (chan, stride);
			OUT_RING  (chan, height);
			OUT_RING  (chan, 1);
			OUT_RING  (chan, 0);
			OUT_RING  (chan, 0);
		} else {
926
			BEGIN_NV04(chan, NvSubCopy, 0x0200, 1);
927 928
			OUT_RING  (chan, 1);
		}
929
		if (dst_tiled) {
930
			BEGIN_NV04(chan, NvSubCopy, 0x021c, 7);
931
			OUT_RING  (chan, 0);
932
			OUT_RING  (chan, 0);
933 934 935 936 937 938
			OUT_RING  (chan, stride);
			OUT_RING  (chan, height);
			OUT_RING  (chan, 1);
			OUT_RING  (chan, 0);
			OUT_RING  (chan, 0);
		} else {
939
			BEGIN_NV04(chan, NvSubCopy, 0x021c, 1);
940 941 942
			OUT_RING  (chan, 1);
		}

943
		BEGIN_NV04(chan, NvSubCopy, 0x0238, 2);
944 945
		OUT_RING  (chan, upper_32_bits(src_offset));
		OUT_RING  (chan, upper_32_bits(dst_offset));
946
		BEGIN_NV04(chan, NvSubCopy, 0x030c, 8);
947 948 949 950 951 952 953 954
		OUT_RING  (chan, lower_32_bits(src_offset));
		OUT_RING  (chan, lower_32_bits(dst_offset));
		OUT_RING  (chan, stride);
		OUT_RING  (chan, stride);
		OUT_RING  (chan, stride);
		OUT_RING  (chan, height);
		OUT_RING  (chan, 0x00000101);
		OUT_RING  (chan, 0x00000000);
955
		BEGIN_NV04(chan, NvSubCopy, NV_MEMORY_TO_MEMORY_FORMAT_NOP, 1);
956 957 958 959 960
		OUT_RING  (chan, 0);

		length -= amount;
		src_offset += amount;
		dst_offset += amount;
961 962
	}

963 964 965
	return 0;
}

966 967 968
static int
nv04_bo_move_init(struct nouveau_channel *chan, u32 handle)
{
969
	int ret = RING_SPACE(chan, 4);
970
	if (ret == 0) {
971 972 973
		BEGIN_NV04(chan, NvSubCopy, 0x0000, 1);
		OUT_RING  (chan, handle);
		BEGIN_NV04(chan, NvSubCopy, 0x0180, 1);
974
		OUT_RING  (chan, chan->drm->ntfy.handle);
975 976 977 978 979
	}

	return ret;
}

980 981
static inline uint32_t
nouveau_bo_mem_ctxdma(struct ttm_buffer_object *bo,
982
		      struct nouveau_channel *chan, struct ttm_mem_reg *reg)
983
{
984
	if (reg->mem_type == TTM_PL_TT)
985
		return NvDmaTT;
986
	return chan->vram.handle;
987 988
}

989 990
static int
nv04_bo_move_m2mf(struct nouveau_channel *chan, struct ttm_buffer_object *bo,
991
		  struct ttm_mem_reg *old_reg, struct ttm_mem_reg *new_reg)
992
{
993 994 995
	u32 src_offset = old_reg->start << PAGE_SHIFT;
	u32 dst_offset = new_reg->start << PAGE_SHIFT;
	u32 page_count = new_reg->num_pages;
996 997 998 999 1000 1001
	int ret;

	ret = RING_SPACE(chan, 3);
	if (ret)
		return ret;

1002
	BEGIN_NV04(chan, NvSubCopy, NV_MEMORY_TO_MEMORY_FORMAT_DMA_SOURCE, 2);
1003 1004
	OUT_RING  (chan, nouveau_bo_mem_ctxdma(bo, chan, old_reg));
	OUT_RING  (chan, nouveau_bo_mem_ctxdma(bo, chan, new_reg));
1005

1006
	page_count = new_reg->num_pages;
1007 1008 1009 1010 1011 1012
	while (page_count) {
		int line_count = (page_count > 2047) ? 2047 : page_count;

		ret = RING_SPACE(chan, 11);
		if (ret)
			return ret;
1013

1014
		BEGIN_NV04(chan, NvSubCopy,
1015
				 NV_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN, 8);
1016 1017 1018 1019 1020 1021 1022 1023
		OUT_RING  (chan, src_offset);
		OUT_RING  (chan, dst_offset);
		OUT_RING  (chan, PAGE_SIZE); /* src_pitch */
		OUT_RING  (chan, PAGE_SIZE); /* dst_pitch */
		OUT_RING  (chan, PAGE_SIZE); /* line_length */
		OUT_RING  (chan, line_count);
		OUT_RING  (chan, 0x00000101);
		OUT_RING  (chan, 0x00000000);
1024
		BEGIN_NV04(chan, NvSubCopy, NV_MEMORY_TO_MEMORY_FORMAT_NOP, 1);
1025
		OUT_RING  (chan, 0);
1026 1027 1028 1029 1030 1031

		page_count -= line_count;
		src_offset += (PAGE_SIZE * line_count);
		dst_offset += (PAGE_SIZE * line_count);
	}

1032 1033 1034
	return 0;
}

1035
static int
1036
nouveau_bo_move_prep(struct nouveau_drm *drm, struct ttm_buffer_object *bo,
1037
		     struct ttm_mem_reg *reg)
1038
{
1039 1040
	struct nouveau_mem *old_mem = nouveau_mem(&bo->mem);
	struct nouveau_mem *new_mem = nouveau_mem(reg);
1041
	struct nvif_vmm *vmm = &drm->client.vmm.vmm;
1042 1043
	int ret;

1044 1045
	ret = nvif_vmm_get(vmm, LAZY, false, old_mem->mem.page, 0,
			   old_mem->mem.size, &old_mem->vma[0]);
1046 1047 1048
	if (ret)
		return ret;

1049 1050 1051 1052
	ret = nvif_vmm_get(vmm, LAZY, false, new_mem->mem.page, 0,
			   new_mem->mem.size, &old_mem->vma[1]);
	if (ret)
		goto done;
1053

1054 1055 1056 1057 1058 1059 1060
	ret = nouveau_mem_map(old_mem, vmm, &old_mem->vma[0]);
	if (ret)
		goto done;

	ret = nouveau_mem_map(new_mem, vmm, &old_mem->vma[1]);
done:
	if (ret) {
1061 1062
		nvif_vmm_put(vmm, &old_mem->vma[1]);
		nvif_vmm_put(vmm, &old_mem->vma[0]);
1063
	}
1064 1065 1066
	return 0;
}

1067 1068
static int
nouveau_bo_move_m2mf(struct ttm_buffer_object *bo, int evict, bool intr,
1069
		     bool no_wait_gpu, struct ttm_mem_reg *new_reg)
1070
{
1071
	struct nouveau_drm *drm = nouveau_bdev(bo->bdev);
1072
	struct nouveau_channel *chan = drm->ttm.chan;
1073
	struct nouveau_cli *cli = (void *)chan->user.client;
1074
	struct nouveau_fence *fence;
1075 1076
	int ret;

1077
	/* create temporary vmas for the transfer and attach them to the
1078
	 * old nvkm_mem node, these will get cleaned up after ttm has
1079
	 * destroyed the ttm_mem_reg
1080
	 */
1081
	if (drm->client.device.info.family >= NV_DEVICE_INFO_V0_TESLA) {
1082
		ret = nouveau_bo_move_prep(drm, bo, new_reg);
1083
		if (ret)
1084
			return ret;
1085 1086
	}

1087
	mutex_lock_nested(&cli->mutex, SINGLE_DEPTH_NESTING);
1088
	ret = nouveau_fence_sync(nouveau_bo(bo), chan, true, intr);
1089
	if (ret == 0) {
1090
		ret = drm->ttm.move(chan, bo, &bo->mem, new_reg);
1091 1092 1093
		if (ret == 0) {
			ret = nouveau_fence_new(chan, false, &fence);
			if (ret == 0) {
1094 1095
				ret = ttm_bo_move_accel_cleanup(bo,
								&fence->base,
1096
								evict,
1097
								new_reg);
1098 1099 1100
				nouveau_fence_unref(&fence);
			}
		}
1101
	}
1102
	mutex_unlock(&cli->mutex);
1103
	return ret;
1104 1105
}

1106
void
1107
nouveau_bo_move_init(struct nouveau_drm *drm)
1108 1109 1110
{
	static const struct {
		const char *name;
1111
		int engine;
1112
		s32 oclass;
1113 1114 1115 1116 1117
		int (*exec)(struct nouveau_channel *,
			    struct ttm_buffer_object *,
			    struct ttm_mem_reg *, struct ttm_mem_reg *);
		int (*init)(struct nouveau_channel *, u32 handle);
	} _methods[] = {
1118 1119
		{  "COPY", 4, 0xc1b5, nve0_bo_move_copy, nve0_bo_move_init },
		{  "GRCE", 0, 0xc1b5, nve0_bo_move_copy, nvc0_bo_move_init },
1120 1121
		{  "COPY", 4, 0xc0b5, nve0_bo_move_copy, nve0_bo_move_init },
		{  "GRCE", 0, 0xc0b5, nve0_bo_move_copy, nvc0_bo_move_init },
1122 1123
		{  "COPY", 4, 0xb0b5, nve0_bo_move_copy, nve0_bo_move_init },
		{  "GRCE", 0, 0xb0b5, nve0_bo_move_copy, nvc0_bo_move_init },
1124
		{  "COPY", 4, 0xa0b5, nve0_bo_move_copy, nve0_bo_move_init },
1125
		{  "GRCE", 0, 0xa0b5, nve0_bo_move_copy, nvc0_bo_move_init },
1126 1127 1128 1129 1130 1131 1132
		{ "COPY1", 5, 0x90b8, nvc0_bo_move_copy, nvc0_bo_move_init },
		{ "COPY0", 4, 0x90b5, nvc0_bo_move_copy, nvc0_bo_move_init },
		{  "COPY", 0, 0x85b5, nva3_bo_move_copy, nv50_bo_move_init },
		{ "CRYPT", 0, 0x74c1, nv84_bo_move_exec, nv50_bo_move_init },
		{  "M2MF", 0, 0x9039, nvc0_bo_move_m2mf, nvc0_bo_move_init },
		{  "M2MF", 0, 0x5039, nv50_bo_move_m2mf, nv50_bo_move_init },
		{  "M2MF", 0, 0x0039, nv04_bo_move_m2mf, nv04_bo_move_init },
1133
		{},
1134
		{ "CRYPT", 0, 0x88b4, nv98_bo_move_exec, nv50_bo_move_init },
1135 1136 1137 1138 1139
	}, *mthd = _methods;
	const char *name = "CPU";
	int ret;

	do {
1140
		struct nouveau_channel *chan;
1141

1142
		if (mthd->engine)
1143 1144 1145 1146 1147 1148
			chan = drm->cechan;
		else
			chan = drm->channel;
		if (chan == NULL)
			continue;

1149
		ret = nvif_object_init(&chan->user,
1150 1151 1152
				       mthd->oclass | (mthd->engine << 16),
				       mthd->oclass, NULL, 0,
				       &drm->ttm.copy);
1153
		if (ret == 0) {
1154
			ret = mthd->init(chan, drm->ttm.copy.handle);
1155
			if (ret) {
1156
				nvif_object_fini(&drm->ttm.copy);
1157
				continue;
1158
			}
1159 1160

			drm->ttm.move = mthd->exec;
1161
			drm->ttm.chan = chan;
1162 1163
			name = mthd->name;
			break;
1164 1165 1166
		}
	} while ((++mthd)->exec);

1167
	NV_INFO(drm, "MM: using %s for buffer copies\n", name);
1168 1169
}

1170 1171
static int
nouveau_bo_move_flipd(struct ttm_buffer_object *bo, bool evict, bool intr,
1172
		      bool no_wait_gpu, struct ttm_mem_reg *new_reg)
1173
{
1174 1175 1176 1177 1178
	struct ttm_place placement_memtype = {
		.fpfn = 0,
		.lpfn = 0,
		.flags = TTM_PL_FLAG_TT | TTM_PL_MASK_CACHING
	};
1179
	struct ttm_placement placement;
1180
	struct ttm_mem_reg tmp_reg;
1181 1182 1183
	int ret;

	placement.num_placement = placement.num_busy_placement = 1;
1184
	placement.placement = placement.busy_placement = &placement_memtype;
1185

1186 1187 1188
	tmp_reg = *new_reg;
	tmp_reg.mm_node = NULL;
	ret = ttm_bo_mem_space(bo, &placement, &tmp_reg, intr, no_wait_gpu);
1189 1190 1191
	if (ret)
		return ret;

1192
	ret = ttm_tt_bind(bo->ttm, &tmp_reg);
1193 1194 1195
	if (ret)
		goto out;

1196
	ret = nouveau_bo_move_m2mf(bo, true, intr, no_wait_gpu, &tmp_reg);
1197 1198 1199
	if (ret)
		goto out;

1200
	ret = ttm_bo_move_ttm(bo, intr, no_wait_gpu, new_reg);
1201
out:
1202
	ttm_bo_mem_put(bo, &tmp_reg);
1203 1204 1205 1206 1207
	return ret;
}

static int
nouveau_bo_move_flips(struct ttm_buffer_object *bo, bool evict, bool intr,
1208
		      bool no_wait_gpu, struct ttm_mem_reg *new_reg)
1209
{
1210 1211 1212 1213 1214
	struct ttm_place placement_memtype = {
		.fpfn = 0,
		.lpfn = 0,
		.flags = TTM_PL_FLAG_TT | TTM_PL_MASK_CACHING
	};
1215
	struct ttm_placement placement;
1216
	struct ttm_mem_reg tmp_reg;
1217 1218 1219
	int ret;

	placement.num_placement = placement.num_busy_placement = 1;
1220
	placement.placement = placement.busy_placement = &placement_memtype;
1221

1222 1223 1224
	tmp_reg = *new_reg;
	tmp_reg.mm_node = NULL;
	ret = ttm_bo_mem_space(bo, &placement, &tmp_reg, intr, no_wait_gpu);
1225 1226 1227
	if (ret)
		return ret;

1228
	ret = ttm_bo_move_ttm(bo, intr, no_wait_gpu, &tmp_reg);
1229 1230 1231
	if (ret)
		goto out;

1232
	ret = nouveau_bo_move_m2mf(bo, true, intr, no_wait_gpu, new_reg);
1233 1234 1235 1236
	if (ret)
		goto out;

out:
1237
	ttm_bo_mem_put(bo, &tmp_reg);
1238 1239 1240
	return ret;
}

1241
static void
1242
nouveau_bo_move_ntfy(struct ttm_buffer_object *bo, bool evict,
1243
		     struct ttm_mem_reg *new_reg)
1244
{
1245
	struct nouveau_mem *mem = new_reg ? nouveau_mem(new_reg) : NULL;
1246
	struct nouveau_bo *nvbo = nouveau_bo(bo);
1247
	struct nouveau_vma *vma;
1248

1249 1250 1251 1252
	/* ttm can now (stupidly) pass the driver bos it didn't create... */
	if (bo->destroy != nouveau_bo_del_ttm)
		return;

1253
	if (mem && new_reg->mem_type != TTM_PL_SYSTEM &&
1254
	    mem->mem.page == nvbo->page) {
1255
		list_for_each_entry(vma, &nvbo->vma_list, head) {
1256
			nouveau_vma_map(vma, mem);
1257 1258 1259
		}
	} else {
		list_for_each_entry(vma, &nvbo->vma_list, head) {
1260
			WARN_ON(ttm_bo_wait(bo, false, false));
1261
			nouveau_vma_unmap(vma);
1262
		}
1263 1264 1265
	}
}

1266
static int
1267
nouveau_bo_vm_bind(struct ttm_buffer_object *bo, struct ttm_mem_reg *new_reg,
1268
		   struct nouveau_drm_tile **new_tile)
1269
{
1270 1271
	struct nouveau_drm *drm = nouveau_bdev(bo->bdev);
	struct drm_device *dev = drm->dev;
1272
	struct nouveau_bo *nvbo = nouveau_bo(bo);
1273
	u64 offset = new_reg->start << PAGE_SHIFT;
1274

1275
	*new_tile = NULL;
1276
	if (new_reg->mem_type != TTM_PL_VRAM)
1277 1278
		return 0;

1279
	if (drm->client.device.info.family >= NV_DEVICE_INFO_V0_CELSIUS) {
1280
		*new_tile = nv10_bo_set_tiling(dev, offset, new_reg->size,
1281
					       nvbo->mode, nvbo->zeta);
1282 1283
	}

1284 1285 1286 1287 1288
	return 0;
}

static void
nouveau_bo_vm_cleanup(struct ttm_buffer_object *bo,
1289 1290
		      struct nouveau_drm_tile *new_tile,
		      struct nouveau_drm_tile **old_tile)
1291
{
1292 1293
	struct nouveau_drm *drm = nouveau_bdev(bo->bdev);
	struct drm_device *dev = drm->dev;
1294
	struct dma_fence *fence = reservation_object_get_excl(bo->resv);
1295

1296
	nv10_bo_put_tile_region(dev, *old_tile, fence);
1297
	*old_tile = new_tile;
1298 1299 1300 1301
}

static int
nouveau_bo_move(struct ttm_buffer_object *bo, bool evict, bool intr,
1302
		bool no_wait_gpu, struct ttm_mem_reg *new_reg)
1303
{
1304
	struct nouveau_drm *drm = nouveau_bdev(bo->bdev);
1305
	struct nouveau_bo *nvbo = nouveau_bo(bo);
1306
	struct ttm_mem_reg *old_reg = &bo->mem;
1307
	struct nouveau_drm_tile *new_tile = NULL;
1308 1309
	int ret = 0;

1310 1311 1312 1313
	ret = ttm_bo_wait(bo, intr, no_wait_gpu);
	if (ret)
		return ret;

1314 1315 1316
	if (nvbo->pin_refcnt)
		NV_WARN(drm, "Moving pinned object %p!\n", nvbo);

1317
	if (drm->client.device.info.family < NV_DEVICE_INFO_V0_TESLA) {
1318
		ret = nouveau_bo_vm_bind(bo, new_reg, &new_tile);
1319 1320 1321
		if (ret)
			return ret;
	}
1322 1323

	/* Fake bo copy. */
1324
	if (old_reg->mem_type == TTM_PL_SYSTEM && !bo->ttm) {
1325
		BUG_ON(bo->mem.mm_node != NULL);
1326 1327
		bo->mem = *new_reg;
		new_reg->mm_node = NULL;
1328
		goto out;
1329 1330
	}

1331
	/* Hardware assisted copy. */
1332
	if (drm->ttm.move) {
1333
		if (new_reg->mem_type == TTM_PL_SYSTEM)
1334
			ret = nouveau_bo_move_flipd(bo, evict, intr,
1335 1336
						    no_wait_gpu, new_reg);
		else if (old_reg->mem_type == TTM_PL_SYSTEM)
1337
			ret = nouveau_bo_move_flips(bo, evict, intr,
1338
						    no_wait_gpu, new_reg);
1339 1340
		else
			ret = nouveau_bo_move_m2mf(bo, evict, intr,
1341
						   no_wait_gpu, new_reg);
1342 1343 1344
		if (!ret)
			goto out;
	}
1345 1346

	/* Fallback to software copy. */
1347
	ret = ttm_bo_wait(bo, intr, no_wait_gpu);
1348
	if (ret == 0)
1349
		ret = ttm_bo_move_memcpy(bo, intr, no_wait_gpu, new_reg);
1350 1351

out:
1352
	if (drm->client.device.info.family < NV_DEVICE_INFO_V0_TESLA) {
1353 1354 1355 1356 1357
		if (ret)
			nouveau_bo_vm_cleanup(bo, NULL, &new_tile);
		else
			nouveau_bo_vm_cleanup(bo, new_tile, &nvbo->tile);
	}
1358 1359

	return ret;
1360 1361 1362 1363 1364
}

static int
nouveau_bo_verify_access(struct ttm_buffer_object *bo, struct file *filp)
{
1365 1366
	struct nouveau_bo *nvbo = nouveau_bo(bo);

D
David Herrmann 已提交
1367 1368
	return drm_vma_node_verify_access(&nvbo->gem.vma_node,
					  filp->private_data);
1369 1370
}

1371
static int
1372
nouveau_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_reg *reg)
1373
{
1374
	struct ttm_mem_type_manager *man = &bdev->man[reg->mem_type];
1375
	struct nouveau_drm *drm = nouveau_bdev(bdev);
1376
	struct nvkm_device *device = nvxx_device(&drm->client.device);
1377
	struct nouveau_mem *mem = nouveau_mem(reg);
1378

1379 1380 1381 1382 1383
	reg->bus.addr = NULL;
	reg->bus.offset = 0;
	reg->bus.size = reg->num_pages << PAGE_SHIFT;
	reg->bus.base = 0;
	reg->bus.is_iomem = false;
1384 1385
	if (!(man->flags & TTM_MEMTYPE_FLAG_MAPPABLE))
		return -EINVAL;
1386
	switch (reg->mem_type) {
1387 1388 1389 1390
	case TTM_PL_SYSTEM:
		/* System memory */
		return 0;
	case TTM_PL_TT:
D
Daniel Vetter 已提交
1391
#if IS_ENABLED(CONFIG_AGP)
1392
		if (drm->agp.bridge) {
1393 1394 1395
			reg->bus.offset = reg->start << PAGE_SHIFT;
			reg->bus.base = drm->agp.base;
			reg->bus.is_iomem = !drm->agp.cma;
1396 1397
		}
#endif
1398
		if (drm->client.mem->oclass < NVIF_CLASS_MEM_NV50 || !mem->kind)
1399 1400 1401
			/* untiled */
			break;
		/* fallthrough, tiled memory */
1402
	case TTM_PL_VRAM:
1403 1404 1405
		reg->bus.offset = reg->start << PAGE_SHIFT;
		reg->bus.base = device->func->resource_addr(device, 1);
		reg->bus.is_iomem = true;
1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439
		if (drm->client.mem->oclass >= NVIF_CLASS_MEM_NV50) {
			union {
				struct nv50_mem_map_v0 nv50;
				struct gf100_mem_map_v0 gf100;
			} args;
			u64 handle, length;
			u32 argc = 0;
			int ret;

			switch (mem->mem.object.oclass) {
			case NVIF_CLASS_MEM_NV50:
				args.nv50.version = 0;
				args.nv50.ro = 0;
				args.nv50.kind = mem->kind;
				args.nv50.comp = mem->comp;
				break;
			case NVIF_CLASS_MEM_GF100:
				args.gf100.version = 0;
				args.gf100.ro = 0;
				args.gf100.kind = mem->kind;
				break;
			default:
				WARN_ON(1);
				break;
			}

			ret = nvif_object_map_handle(&mem->mem.object,
						     &argc, argc,
						     &handle, &length);
			if (ret != 1)
				return ret ? ret : -EINVAL;

			reg->bus.base = 0;
			reg->bus.offset = handle;
1440
		}
1441 1442 1443 1444 1445 1446 1447 1448
		break;
	default:
		return -EINVAL;
	}
	return 0;
}

static void
1449
nouveau_ttm_io_mem_free(struct ttm_bo_device *bdev, struct ttm_mem_reg *reg)
1450
{
1451
	struct nouveau_drm *drm = nouveau_bdev(bdev);
1452
	struct nouveau_mem *mem = nouveau_mem(reg);
1453

1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466
	if (drm->client.mem->oclass >= NVIF_CLASS_MEM_NV50) {
		switch (reg->mem_type) {
		case TTM_PL_TT:
			if (mem->kind)
				nvif_object_unmap_handle(&mem->mem.object);
			break;
		case TTM_PL_VRAM:
			nvif_object_unmap_handle(&mem->mem.object);
			break;
		default:
			break;
		}
	}
1467 1468 1469 1470 1471
}

static int
nouveau_ttm_fault_reserve_notify(struct ttm_buffer_object *bo)
{
1472
	struct nouveau_drm *drm = nouveau_bdev(bo->bdev);
1473
	struct nouveau_bo *nvbo = nouveau_bo(bo);
1474
	struct nvkm_device *device = nvxx_device(&drm->client.device);
1475
	u32 mappable = device->func->resource_size(device, 1) >> PAGE_SHIFT;
1476
	int i, ret;
1477 1478 1479 1480 1481

	/* as long as the bo isn't in vram, and isn't tiled, we've got
	 * nothing to do here.
	 */
	if (bo->mem.mem_type != TTM_PL_VRAM) {
1482
		if (drm->client.device.info.family < NV_DEVICE_INFO_V0_TESLA ||
1483
		    !nvbo->kind)
1484
			return 0;
1485 1486 1487 1488 1489 1490 1491 1492 1493

		if (bo->mem.mem_type == TTM_PL_SYSTEM) {
			nouveau_bo_placement_set(nvbo, TTM_PL_TT, 0);

			ret = nouveau_bo_validate(nvbo, false, false);
			if (ret)
				return ret;
		}
		return 0;
1494 1495 1496
	}

	/* make sure bo is in mappable vram */
1497
	if (drm->client.device.info.family >= NV_DEVICE_INFO_V0_TESLA ||
1498
	    bo->mem.start + bo->mem.num_pages < mappable)
1499 1500
		return 0;

1501 1502 1503 1504 1505 1506 1507 1508 1509
	for (i = 0; i < nvbo->placement.num_placement; ++i) {
		nvbo->placements[i].fpfn = 0;
		nvbo->placements[i].lpfn = mappable;
	}

	for (i = 0; i < nvbo->placement.num_busy_placement; ++i) {
		nvbo->busy_placements[i].fpfn = 0;
		nvbo->busy_placements[i].lpfn = mappable;
	}
1510

1511
	nouveau_bo_placement_set(nvbo, TTM_PL_FLAG_VRAM, 0);
1512
	return nouveau_bo_validate(nvbo, false, false);
1513 1514
}

1515 1516 1517
static int
nouveau_ttm_tt_populate(struct ttm_tt *ttm)
{
1518
	struct ttm_dma_tt *ttm_dma = (void *)ttm;
1519
	struct nouveau_drm *drm;
1520
	struct device *dev;
1521 1522
	unsigned i;
	int r;
D
Dave Airlie 已提交
1523
	bool slave = !!(ttm->page_flags & TTM_PAGE_FLAG_SG);
1524 1525 1526 1527

	if (ttm->state != tt_unpopulated)
		return 0;

D
Dave Airlie 已提交
1528 1529 1530 1531 1532 1533 1534 1535
	if (slave && ttm->sg) {
		/* make userspace faulting work */
		drm_prime_sg_to_page_addr_arrays(ttm->sg, ttm->pages,
						 ttm_dma->dma_address, ttm->num_pages);
		ttm->state = tt_unbound;
		return 0;
	}

1536
	drm = nouveau_bdev(ttm->bdev);
1537
	dev = drm->dev->dev;
1538

D
Daniel Vetter 已提交
1539
#if IS_ENABLED(CONFIG_AGP)
1540
	if (drm->agp.bridge) {
J
Jerome Glisse 已提交
1541 1542 1543 1544
		return ttm_agp_tt_populate(ttm);
	}
#endif

1545
#if IS_ENABLED(CONFIG_SWIOTLB) && IS_ENABLED(CONFIG_X86)
1546
	if (swiotlb_nr_tbl()) {
1547
		return ttm_dma_populate((void *)ttm, dev);
1548 1549 1550 1551 1552 1553 1554 1555 1556
	}
#endif

	r = ttm_pool_populate(ttm);
	if (r) {
		return r;
	}

	for (i = 0; i < ttm->num_pages; i++) {
1557 1558
		dma_addr_t addr;

1559
		addr = dma_map_page(dev, ttm->pages[i], 0, PAGE_SIZE,
1560 1561
				    DMA_BIDIRECTIONAL);

1562
		if (dma_mapping_error(dev, addr)) {
1563
			while (i--) {
1564
				dma_unmap_page(dev, ttm_dma->dma_address[i],
1565
					       PAGE_SIZE, DMA_BIDIRECTIONAL);
1566
				ttm_dma->dma_address[i] = 0;
1567 1568 1569 1570
			}
			ttm_pool_unpopulate(ttm);
			return -EFAULT;
		}
1571 1572

		ttm_dma->dma_address[i] = addr;
1573 1574 1575 1576 1577 1578 1579
	}
	return 0;
}

static void
nouveau_ttm_tt_unpopulate(struct ttm_tt *ttm)
{
1580
	struct ttm_dma_tt *ttm_dma = (void *)ttm;
1581
	struct nouveau_drm *drm;
1582
	struct device *dev;
1583
	unsigned i;
D
Dave Airlie 已提交
1584 1585 1586 1587
	bool slave = !!(ttm->page_flags & TTM_PAGE_FLAG_SG);

	if (slave)
		return;
1588

1589
	drm = nouveau_bdev(ttm->bdev);
1590
	dev = drm->dev->dev;
1591

D
Daniel Vetter 已提交
1592
#if IS_ENABLED(CONFIG_AGP)
1593
	if (drm->agp.bridge) {
J
Jerome Glisse 已提交
1594 1595 1596 1597 1598
		ttm_agp_tt_unpopulate(ttm);
		return;
	}
#endif

1599
#if IS_ENABLED(CONFIG_SWIOTLB) && IS_ENABLED(CONFIG_X86)
1600
	if (swiotlb_nr_tbl()) {
1601
		ttm_dma_unpopulate((void *)ttm, dev);
1602 1603 1604 1605 1606
		return;
	}
#endif

	for (i = 0; i < ttm->num_pages; i++) {
1607
		if (ttm_dma->dma_address[i]) {
1608
			dma_unmap_page(dev, ttm_dma->dma_address[i], PAGE_SIZE,
1609
				       DMA_BIDIRECTIONAL);
1610 1611 1612 1613 1614 1615
		}
	}

	ttm_pool_unpopulate(ttm);
}

1616
void
1617
nouveau_bo_fence(struct nouveau_bo *nvbo, struct nouveau_fence *fence, bool exclusive)
1618
{
1619
	struct reservation_object *resv = nvbo->bo.resv;
1620

1621 1622 1623 1624
	if (exclusive)
		reservation_object_add_excl_fence(resv, &fence->base);
	else if (fence)
		reservation_object_add_shared_fence(resv, &fence->base);
1625 1626
}

1627
struct ttm_bo_driver nouveau_bo_driver = {
1628
	.ttm_tt_create = &nouveau_ttm_tt_create,
1629 1630
	.ttm_tt_populate = &nouveau_ttm_tt_populate,
	.ttm_tt_unpopulate = &nouveau_ttm_tt_unpopulate,
1631 1632
	.invalidate_caches = nouveau_bo_invalidate_caches,
	.init_mem_type = nouveau_bo_init_mem_type,
1633
	.eviction_valuable = ttm_bo_eviction_valuable,
1634
	.evict_flags = nouveau_bo_evict_flags,
1635
	.move_notify = nouveau_bo_move_ntfy,
1636 1637
	.move = nouveau_bo_move,
	.verify_access = nouveau_bo_verify_access,
1638 1639 1640
	.fault_reserve_notify = &nouveau_ttm_fault_reserve_notify,
	.io_mem_reserve = &nouveau_ttm_io_mem_reserve,
	.io_mem_free = &nouveau_ttm_io_mem_free,
1641
	.io_mem_pfn = ttm_bo_default_io_mem_pfn,
1642
};