162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * Copyright 2009 Jerome Glisse.
362306a36Sopenharmony_ci * All Rights Reserved.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
662306a36Sopenharmony_ci * copy of this software and associated documentation files (the
762306a36Sopenharmony_ci * "Software"), to deal in the Software without restriction, including
862306a36Sopenharmony_ci * without limitation the rights to use, copy, modify, merge, publish,
962306a36Sopenharmony_ci * distribute, sub license, and/or sell copies of the Software, and to
1062306a36Sopenharmony_ci * permit persons to whom the Software is furnished to do so, subject to
1162306a36Sopenharmony_ci * the following conditions:
1262306a36Sopenharmony_ci *
1362306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1462306a36Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1562306a36Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
1662306a36Sopenharmony_ci * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
1762306a36Sopenharmony_ci * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
1862306a36Sopenharmony_ci * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
1962306a36Sopenharmony_ci * USE OR OTHER DEALINGS IN THE SOFTWARE.
2062306a36Sopenharmony_ci *
2162306a36Sopenharmony_ci * The above copyright notice and this permission notice (including the
2262306a36Sopenharmony_ci * next paragraph) shall be included in all copies or substantial portions
2362306a36Sopenharmony_ci * of the Software.
2462306a36Sopenharmony_ci *
2562306a36Sopenharmony_ci */
2662306a36Sopenharmony_ci/*
2762306a36Sopenharmony_ci * Authors:
2862306a36Sopenharmony_ci *    Jerome Glisse <glisse@freedesktop.org>
2962306a36Sopenharmony_ci *    Thomas Hellstrom <thomas-at-tungstengraphics-dot-com>
3062306a36Sopenharmony_ci *    Dave Airlie
3162306a36Sopenharmony_ci */
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci#include <linux/io.h>
3462306a36Sopenharmony_ci#include <linux/list.h>
3562306a36Sopenharmony_ci#include <linux/slab.h>
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci#include <drm/drm_cache.h>
3862306a36Sopenharmony_ci#include <drm/drm_prime.h>
3962306a36Sopenharmony_ci#include <drm/radeon_drm.h>
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci#include "radeon.h"
4262306a36Sopenharmony_ci#include "radeon_trace.h"
4362306a36Sopenharmony_ci#include "radeon_ttm.h"
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_cistatic void radeon_bo_clear_surface_reg(struct radeon_bo *bo);
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci/*
4862306a36Sopenharmony_ci * To exclude mutual BO access we rely on bo_reserve exclusion, as all
4962306a36Sopenharmony_ci * function are calling it.
5062306a36Sopenharmony_ci */
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_cistatic void radeon_ttm_bo_destroy(struct ttm_buffer_object *tbo)
5362306a36Sopenharmony_ci{
5462306a36Sopenharmony_ci	struct radeon_bo *bo;
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci	bo = container_of(tbo, struct radeon_bo, tbo);
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci	mutex_lock(&bo->rdev->gem.mutex);
5962306a36Sopenharmony_ci	list_del_init(&bo->list);
6062306a36Sopenharmony_ci	mutex_unlock(&bo->rdev->gem.mutex);
6162306a36Sopenharmony_ci	radeon_bo_clear_surface_reg(bo);
6262306a36Sopenharmony_ci	WARN_ON_ONCE(!list_empty(&bo->va));
6362306a36Sopenharmony_ci	if (bo->tbo.base.import_attach)
6462306a36Sopenharmony_ci		drm_prime_gem_destroy(&bo->tbo.base, bo->tbo.sg);
6562306a36Sopenharmony_ci	drm_gem_object_release(&bo->tbo.base);
6662306a36Sopenharmony_ci	kfree(bo);
6762306a36Sopenharmony_ci}
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_cibool radeon_ttm_bo_is_radeon_bo(struct ttm_buffer_object *bo)
7062306a36Sopenharmony_ci{
7162306a36Sopenharmony_ci	if (bo->destroy == &radeon_ttm_bo_destroy)
7262306a36Sopenharmony_ci		return true;
7362306a36Sopenharmony_ci	return false;
7462306a36Sopenharmony_ci}
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_civoid radeon_ttm_placement_from_domain(struct radeon_bo *rbo, u32 domain)
7762306a36Sopenharmony_ci{
7862306a36Sopenharmony_ci	u32 c = 0, i;
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci	rbo->placement.placement = rbo->placements;
8162306a36Sopenharmony_ci	rbo->placement.busy_placement = rbo->placements;
8262306a36Sopenharmony_ci	if (domain & RADEON_GEM_DOMAIN_VRAM) {
8362306a36Sopenharmony_ci		/* Try placing BOs which don't need CPU access outside of the
8462306a36Sopenharmony_ci		 * CPU accessible part of VRAM
8562306a36Sopenharmony_ci		 */
8662306a36Sopenharmony_ci		if ((rbo->flags & RADEON_GEM_NO_CPU_ACCESS) &&
8762306a36Sopenharmony_ci		    rbo->rdev->mc.visible_vram_size < rbo->rdev->mc.real_vram_size) {
8862306a36Sopenharmony_ci			rbo->placements[c].fpfn =
8962306a36Sopenharmony_ci				rbo->rdev->mc.visible_vram_size >> PAGE_SHIFT;
9062306a36Sopenharmony_ci			rbo->placements[c].mem_type = TTM_PL_VRAM;
9162306a36Sopenharmony_ci			rbo->placements[c++].flags = 0;
9262306a36Sopenharmony_ci		}
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci		rbo->placements[c].fpfn = 0;
9562306a36Sopenharmony_ci		rbo->placements[c].mem_type = TTM_PL_VRAM;
9662306a36Sopenharmony_ci		rbo->placements[c++].flags = 0;
9762306a36Sopenharmony_ci	}
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci	if (domain & RADEON_GEM_DOMAIN_GTT) {
10062306a36Sopenharmony_ci		rbo->placements[c].fpfn = 0;
10162306a36Sopenharmony_ci		rbo->placements[c].mem_type = TTM_PL_TT;
10262306a36Sopenharmony_ci		rbo->placements[c++].flags = 0;
10362306a36Sopenharmony_ci	}
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci	if (domain & RADEON_GEM_DOMAIN_CPU) {
10662306a36Sopenharmony_ci		rbo->placements[c].fpfn = 0;
10762306a36Sopenharmony_ci		rbo->placements[c].mem_type = TTM_PL_SYSTEM;
10862306a36Sopenharmony_ci		rbo->placements[c++].flags = 0;
10962306a36Sopenharmony_ci	}
11062306a36Sopenharmony_ci	if (!c) {
11162306a36Sopenharmony_ci		rbo->placements[c].fpfn = 0;
11262306a36Sopenharmony_ci		rbo->placements[c].mem_type = TTM_PL_SYSTEM;
11362306a36Sopenharmony_ci		rbo->placements[c++].flags = 0;
11462306a36Sopenharmony_ci	}
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	rbo->placement.num_placement = c;
11762306a36Sopenharmony_ci	rbo->placement.num_busy_placement = c;
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci	for (i = 0; i < c; ++i) {
12062306a36Sopenharmony_ci		if ((rbo->flags & RADEON_GEM_CPU_ACCESS) &&
12162306a36Sopenharmony_ci		    (rbo->placements[i].mem_type == TTM_PL_VRAM) &&
12262306a36Sopenharmony_ci		    !rbo->placements[i].fpfn)
12362306a36Sopenharmony_ci			rbo->placements[i].lpfn =
12462306a36Sopenharmony_ci				rbo->rdev->mc.visible_vram_size >> PAGE_SHIFT;
12562306a36Sopenharmony_ci		else
12662306a36Sopenharmony_ci			rbo->placements[i].lpfn = 0;
12762306a36Sopenharmony_ci	}
12862306a36Sopenharmony_ci}
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ciint radeon_bo_create(struct radeon_device *rdev,
13162306a36Sopenharmony_ci		     unsigned long size, int byte_align, bool kernel,
13262306a36Sopenharmony_ci		     u32 domain, u32 flags, struct sg_table *sg,
13362306a36Sopenharmony_ci		     struct dma_resv *resv,
13462306a36Sopenharmony_ci		     struct radeon_bo **bo_ptr)
13562306a36Sopenharmony_ci{
13662306a36Sopenharmony_ci	struct radeon_bo *bo;
13762306a36Sopenharmony_ci	enum ttm_bo_type type;
13862306a36Sopenharmony_ci	unsigned long page_align = roundup(byte_align, PAGE_SIZE) >> PAGE_SHIFT;
13962306a36Sopenharmony_ci	int r;
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci	size = ALIGN(size, PAGE_SIZE);
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci	if (kernel) {
14462306a36Sopenharmony_ci		type = ttm_bo_type_kernel;
14562306a36Sopenharmony_ci	} else if (sg) {
14662306a36Sopenharmony_ci		type = ttm_bo_type_sg;
14762306a36Sopenharmony_ci	} else {
14862306a36Sopenharmony_ci		type = ttm_bo_type_device;
14962306a36Sopenharmony_ci	}
15062306a36Sopenharmony_ci	*bo_ptr = NULL;
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci	bo = kzalloc(sizeof(struct radeon_bo), GFP_KERNEL);
15362306a36Sopenharmony_ci	if (bo == NULL)
15462306a36Sopenharmony_ci		return -ENOMEM;
15562306a36Sopenharmony_ci	drm_gem_private_object_init(rdev->ddev, &bo->tbo.base, size);
15662306a36Sopenharmony_ci	bo->rdev = rdev;
15762306a36Sopenharmony_ci	bo->surface_reg = -1;
15862306a36Sopenharmony_ci	INIT_LIST_HEAD(&bo->list);
15962306a36Sopenharmony_ci	INIT_LIST_HEAD(&bo->va);
16062306a36Sopenharmony_ci	bo->initial_domain = domain & (RADEON_GEM_DOMAIN_VRAM |
16162306a36Sopenharmony_ci				       RADEON_GEM_DOMAIN_GTT |
16262306a36Sopenharmony_ci				       RADEON_GEM_DOMAIN_CPU);
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci	bo->flags = flags;
16562306a36Sopenharmony_ci	/* PCI GART is always snooped */
16662306a36Sopenharmony_ci	if (!(rdev->flags & RADEON_IS_PCIE))
16762306a36Sopenharmony_ci		bo->flags &= ~(RADEON_GEM_GTT_WC | RADEON_GEM_GTT_UC);
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_ci	/* Write-combined CPU mappings of GTT cause GPU hangs with RV6xx
17062306a36Sopenharmony_ci	 * See https://bugs.freedesktop.org/show_bug.cgi?id=91268
17162306a36Sopenharmony_ci	 */
17262306a36Sopenharmony_ci	if (rdev->family >= CHIP_RV610 && rdev->family <= CHIP_RV635)
17362306a36Sopenharmony_ci		bo->flags &= ~(RADEON_GEM_GTT_WC | RADEON_GEM_GTT_UC);
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci#ifdef CONFIG_X86_32
17662306a36Sopenharmony_ci	/* XXX: Write-combined CPU mappings of GTT seem broken on 32-bit
17762306a36Sopenharmony_ci	 * See https://bugs.freedesktop.org/show_bug.cgi?id=84627
17862306a36Sopenharmony_ci	 */
17962306a36Sopenharmony_ci	bo->flags &= ~(RADEON_GEM_GTT_WC | RADEON_GEM_GTT_UC);
18062306a36Sopenharmony_ci#elif defined(CONFIG_X86) && !defined(CONFIG_X86_PAT)
18162306a36Sopenharmony_ci	/* Don't try to enable write-combining when it can't work, or things
18262306a36Sopenharmony_ci	 * may be slow
18362306a36Sopenharmony_ci	 * See https://bugs.freedesktop.org/show_bug.cgi?id=88758
18462306a36Sopenharmony_ci	 */
18562306a36Sopenharmony_ci#ifndef CONFIG_COMPILE_TEST
18662306a36Sopenharmony_ci#warning Please enable CONFIG_MTRR and CONFIG_X86_PAT for better performance \
18762306a36Sopenharmony_ci	 thanks to write-combining
18862306a36Sopenharmony_ci#endif
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci	if (bo->flags & RADEON_GEM_GTT_WC)
19162306a36Sopenharmony_ci		DRM_INFO_ONCE("Please enable CONFIG_MTRR and CONFIG_X86_PAT for "
19262306a36Sopenharmony_ci			      "better performance thanks to write-combining\n");
19362306a36Sopenharmony_ci	bo->flags &= ~(RADEON_GEM_GTT_WC | RADEON_GEM_GTT_UC);
19462306a36Sopenharmony_ci#else
19562306a36Sopenharmony_ci	/* For architectures that don't support WC memory,
19662306a36Sopenharmony_ci	 * mask out the WC flag from the BO
19762306a36Sopenharmony_ci	 */
19862306a36Sopenharmony_ci	if (!drm_arch_can_wc_memory())
19962306a36Sopenharmony_ci		bo->flags &= ~RADEON_GEM_GTT_WC;
20062306a36Sopenharmony_ci#endif
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci	radeon_ttm_placement_from_domain(bo, domain);
20362306a36Sopenharmony_ci	/* Kernel allocation are uninterruptible */
20462306a36Sopenharmony_ci	down_read(&rdev->pm.mclk_lock);
20562306a36Sopenharmony_ci	r = ttm_bo_init_validate(&rdev->mman.bdev, &bo->tbo, type,
20662306a36Sopenharmony_ci				 &bo->placement, page_align, !kernel, sg, resv,
20762306a36Sopenharmony_ci				 &radeon_ttm_bo_destroy);
20862306a36Sopenharmony_ci	up_read(&rdev->pm.mclk_lock);
20962306a36Sopenharmony_ci	if (unlikely(r != 0)) {
21062306a36Sopenharmony_ci		return r;
21162306a36Sopenharmony_ci	}
21262306a36Sopenharmony_ci	*bo_ptr = bo;
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci	trace_radeon_bo_create(bo);
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci	return 0;
21762306a36Sopenharmony_ci}
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ciint radeon_bo_kmap(struct radeon_bo *bo, void **ptr)
22062306a36Sopenharmony_ci{
22162306a36Sopenharmony_ci	bool is_iomem;
22262306a36Sopenharmony_ci	long r;
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_ci	r = dma_resv_wait_timeout(bo->tbo.base.resv, DMA_RESV_USAGE_KERNEL,
22562306a36Sopenharmony_ci				  false, MAX_SCHEDULE_TIMEOUT);
22662306a36Sopenharmony_ci	if (r < 0)
22762306a36Sopenharmony_ci		return r;
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci	if (bo->kptr) {
23062306a36Sopenharmony_ci		if (ptr) {
23162306a36Sopenharmony_ci			*ptr = bo->kptr;
23262306a36Sopenharmony_ci		}
23362306a36Sopenharmony_ci		return 0;
23462306a36Sopenharmony_ci	}
23562306a36Sopenharmony_ci	r = ttm_bo_kmap(&bo->tbo, 0, PFN_UP(bo->tbo.base.size), &bo->kmap);
23662306a36Sopenharmony_ci	if (r) {
23762306a36Sopenharmony_ci		return r;
23862306a36Sopenharmony_ci	}
23962306a36Sopenharmony_ci	bo->kptr = ttm_kmap_obj_virtual(&bo->kmap, &is_iomem);
24062306a36Sopenharmony_ci	if (ptr) {
24162306a36Sopenharmony_ci		*ptr = bo->kptr;
24262306a36Sopenharmony_ci	}
24362306a36Sopenharmony_ci	radeon_bo_check_tiling(bo, 0, 0);
24462306a36Sopenharmony_ci	return 0;
24562306a36Sopenharmony_ci}
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_civoid radeon_bo_kunmap(struct radeon_bo *bo)
24862306a36Sopenharmony_ci{
24962306a36Sopenharmony_ci	if (bo->kptr == NULL)
25062306a36Sopenharmony_ci		return;
25162306a36Sopenharmony_ci	bo->kptr = NULL;
25262306a36Sopenharmony_ci	radeon_bo_check_tiling(bo, 0, 0);
25362306a36Sopenharmony_ci	ttm_bo_kunmap(&bo->kmap);
25462306a36Sopenharmony_ci}
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_cistruct radeon_bo *radeon_bo_ref(struct radeon_bo *bo)
25762306a36Sopenharmony_ci{
25862306a36Sopenharmony_ci	if (bo == NULL)
25962306a36Sopenharmony_ci		return NULL;
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci	ttm_bo_get(&bo->tbo);
26262306a36Sopenharmony_ci	return bo;
26362306a36Sopenharmony_ci}
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_civoid radeon_bo_unref(struct radeon_bo **bo)
26662306a36Sopenharmony_ci{
26762306a36Sopenharmony_ci	struct ttm_buffer_object *tbo;
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci	if ((*bo) == NULL)
27062306a36Sopenharmony_ci		return;
27162306a36Sopenharmony_ci	tbo = &((*bo)->tbo);
27262306a36Sopenharmony_ci	ttm_bo_put(tbo);
27362306a36Sopenharmony_ci	*bo = NULL;
27462306a36Sopenharmony_ci}
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ciint radeon_bo_pin_restricted(struct radeon_bo *bo, u32 domain, u64 max_offset,
27762306a36Sopenharmony_ci			     u64 *gpu_addr)
27862306a36Sopenharmony_ci{
27962306a36Sopenharmony_ci	struct ttm_operation_ctx ctx = { false, false };
28062306a36Sopenharmony_ci	int r, i;
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci	if (radeon_ttm_tt_has_userptr(bo->rdev, bo->tbo.ttm))
28362306a36Sopenharmony_ci		return -EPERM;
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci	if (bo->tbo.pin_count) {
28662306a36Sopenharmony_ci		ttm_bo_pin(&bo->tbo);
28762306a36Sopenharmony_ci		if (gpu_addr)
28862306a36Sopenharmony_ci			*gpu_addr = radeon_bo_gpu_offset(bo);
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci		if (max_offset != 0) {
29162306a36Sopenharmony_ci			u64 domain_start;
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_ci			if (domain == RADEON_GEM_DOMAIN_VRAM)
29462306a36Sopenharmony_ci				domain_start = bo->rdev->mc.vram_start;
29562306a36Sopenharmony_ci			else
29662306a36Sopenharmony_ci				domain_start = bo->rdev->mc.gtt_start;
29762306a36Sopenharmony_ci			WARN_ON_ONCE(max_offset <
29862306a36Sopenharmony_ci				     (radeon_bo_gpu_offset(bo) - domain_start));
29962306a36Sopenharmony_ci		}
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci		return 0;
30262306a36Sopenharmony_ci	}
30362306a36Sopenharmony_ci	if (bo->prime_shared_count && domain == RADEON_GEM_DOMAIN_VRAM) {
30462306a36Sopenharmony_ci		/* A BO shared as a dma-buf cannot be sensibly migrated to VRAM */
30562306a36Sopenharmony_ci		return -EINVAL;
30662306a36Sopenharmony_ci	}
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci	radeon_ttm_placement_from_domain(bo, domain);
30962306a36Sopenharmony_ci	for (i = 0; i < bo->placement.num_placement; i++) {
31062306a36Sopenharmony_ci		/* force to pin into visible video ram */
31162306a36Sopenharmony_ci		if ((bo->placements[i].mem_type == TTM_PL_VRAM) &&
31262306a36Sopenharmony_ci		    !(bo->flags & RADEON_GEM_NO_CPU_ACCESS) &&
31362306a36Sopenharmony_ci		    (!max_offset || max_offset > bo->rdev->mc.visible_vram_size))
31462306a36Sopenharmony_ci			bo->placements[i].lpfn =
31562306a36Sopenharmony_ci				bo->rdev->mc.visible_vram_size >> PAGE_SHIFT;
31662306a36Sopenharmony_ci		else
31762306a36Sopenharmony_ci			bo->placements[i].lpfn = max_offset >> PAGE_SHIFT;
31862306a36Sopenharmony_ci	}
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ci	r = ttm_bo_validate(&bo->tbo, &bo->placement, &ctx);
32162306a36Sopenharmony_ci	if (likely(r == 0)) {
32262306a36Sopenharmony_ci		ttm_bo_pin(&bo->tbo);
32362306a36Sopenharmony_ci		if (gpu_addr != NULL)
32462306a36Sopenharmony_ci			*gpu_addr = radeon_bo_gpu_offset(bo);
32562306a36Sopenharmony_ci		if (domain == RADEON_GEM_DOMAIN_VRAM)
32662306a36Sopenharmony_ci			bo->rdev->vram_pin_size += radeon_bo_size(bo);
32762306a36Sopenharmony_ci		else
32862306a36Sopenharmony_ci			bo->rdev->gart_pin_size += radeon_bo_size(bo);
32962306a36Sopenharmony_ci	} else {
33062306a36Sopenharmony_ci		dev_err(bo->rdev->dev, "%p pin failed\n", bo);
33162306a36Sopenharmony_ci	}
33262306a36Sopenharmony_ci	return r;
33362306a36Sopenharmony_ci}
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_ciint radeon_bo_pin(struct radeon_bo *bo, u32 domain, u64 *gpu_addr)
33662306a36Sopenharmony_ci{
33762306a36Sopenharmony_ci	return radeon_bo_pin_restricted(bo, domain, 0, gpu_addr);
33862306a36Sopenharmony_ci}
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_civoid radeon_bo_unpin(struct radeon_bo *bo)
34162306a36Sopenharmony_ci{
34262306a36Sopenharmony_ci	ttm_bo_unpin(&bo->tbo);
34362306a36Sopenharmony_ci	if (!bo->tbo.pin_count) {
34462306a36Sopenharmony_ci		if (bo->tbo.resource->mem_type == TTM_PL_VRAM)
34562306a36Sopenharmony_ci			bo->rdev->vram_pin_size -= radeon_bo_size(bo);
34662306a36Sopenharmony_ci		else
34762306a36Sopenharmony_ci			bo->rdev->gart_pin_size -= radeon_bo_size(bo);
34862306a36Sopenharmony_ci	}
34962306a36Sopenharmony_ci}
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ciint radeon_bo_evict_vram(struct radeon_device *rdev)
35262306a36Sopenharmony_ci{
35362306a36Sopenharmony_ci	struct ttm_device *bdev = &rdev->mman.bdev;
35462306a36Sopenharmony_ci	struct ttm_resource_manager *man;
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci	/* late 2.6.33 fix IGP hibernate - we need pm ops to do this correct */
35762306a36Sopenharmony_ci#ifndef CONFIG_HIBERNATION
35862306a36Sopenharmony_ci	if (rdev->flags & RADEON_IS_IGP) {
35962306a36Sopenharmony_ci		if (rdev->mc.igp_sideport_enabled == false)
36062306a36Sopenharmony_ci			/* Useless to evict on IGP chips */
36162306a36Sopenharmony_ci			return 0;
36262306a36Sopenharmony_ci	}
36362306a36Sopenharmony_ci#endif
36462306a36Sopenharmony_ci	man = ttm_manager_type(bdev, TTM_PL_VRAM);
36562306a36Sopenharmony_ci	if (!man)
36662306a36Sopenharmony_ci		return 0;
36762306a36Sopenharmony_ci	return ttm_resource_manager_evict_all(bdev, man);
36862306a36Sopenharmony_ci}
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_civoid radeon_bo_force_delete(struct radeon_device *rdev)
37162306a36Sopenharmony_ci{
37262306a36Sopenharmony_ci	struct radeon_bo *bo, *n;
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ci	if (list_empty(&rdev->gem.objects)) {
37562306a36Sopenharmony_ci		return;
37662306a36Sopenharmony_ci	}
37762306a36Sopenharmony_ci	dev_err(rdev->dev, "Userspace still has active objects !\n");
37862306a36Sopenharmony_ci	list_for_each_entry_safe(bo, n, &rdev->gem.objects, list) {
37962306a36Sopenharmony_ci		dev_err(rdev->dev, "%p %p %lu %lu force free\n",
38062306a36Sopenharmony_ci			&bo->tbo.base, bo, (unsigned long)bo->tbo.base.size,
38162306a36Sopenharmony_ci			*((unsigned long *)&bo->tbo.base.refcount));
38262306a36Sopenharmony_ci		mutex_lock(&bo->rdev->gem.mutex);
38362306a36Sopenharmony_ci		list_del_init(&bo->list);
38462306a36Sopenharmony_ci		mutex_unlock(&bo->rdev->gem.mutex);
38562306a36Sopenharmony_ci		/* this should unref the ttm bo */
38662306a36Sopenharmony_ci		drm_gem_object_put(&bo->tbo.base);
38762306a36Sopenharmony_ci	}
38862306a36Sopenharmony_ci}
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ciint radeon_bo_init(struct radeon_device *rdev)
39162306a36Sopenharmony_ci{
39262306a36Sopenharmony_ci	/* reserve PAT memory space to WC for VRAM */
39362306a36Sopenharmony_ci	arch_io_reserve_memtype_wc(rdev->mc.aper_base,
39462306a36Sopenharmony_ci				   rdev->mc.aper_size);
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci	/* Add an MTRR for the VRAM */
39762306a36Sopenharmony_ci	if (!rdev->fastfb_working) {
39862306a36Sopenharmony_ci		rdev->mc.vram_mtrr = arch_phys_wc_add(rdev->mc.aper_base,
39962306a36Sopenharmony_ci						      rdev->mc.aper_size);
40062306a36Sopenharmony_ci	}
40162306a36Sopenharmony_ci	DRM_INFO("Detected VRAM RAM=%lluM, BAR=%lluM\n",
40262306a36Sopenharmony_ci		rdev->mc.mc_vram_size >> 20,
40362306a36Sopenharmony_ci		(unsigned long long)rdev->mc.aper_size >> 20);
40462306a36Sopenharmony_ci	DRM_INFO("RAM width %dbits %cDR\n",
40562306a36Sopenharmony_ci			rdev->mc.vram_width, rdev->mc.vram_is_ddr ? 'D' : 'S');
40662306a36Sopenharmony_ci	return radeon_ttm_init(rdev);
40762306a36Sopenharmony_ci}
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_civoid radeon_bo_fini(struct radeon_device *rdev)
41062306a36Sopenharmony_ci{
41162306a36Sopenharmony_ci	radeon_ttm_fini(rdev);
41262306a36Sopenharmony_ci	arch_phys_wc_del(rdev->mc.vram_mtrr);
41362306a36Sopenharmony_ci	arch_io_free_memtype_wc(rdev->mc.aper_base, rdev->mc.aper_size);
41462306a36Sopenharmony_ci}
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_ci/* Returns how many bytes TTM can move per IB.
41762306a36Sopenharmony_ci */
41862306a36Sopenharmony_cistatic u64 radeon_bo_get_threshold_for_moves(struct radeon_device *rdev)
41962306a36Sopenharmony_ci{
42062306a36Sopenharmony_ci	u64 real_vram_size = rdev->mc.real_vram_size;
42162306a36Sopenharmony_ci	struct ttm_resource_manager *man =
42262306a36Sopenharmony_ci		ttm_manager_type(&rdev->mman.bdev, TTM_PL_VRAM);
42362306a36Sopenharmony_ci	u64 vram_usage = ttm_resource_manager_usage(man);
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_ci	/* This function is based on the current VRAM usage.
42662306a36Sopenharmony_ci	 *
42762306a36Sopenharmony_ci	 * - If all of VRAM is free, allow relocating the number of bytes that
42862306a36Sopenharmony_ci	 *   is equal to 1/4 of the size of VRAM for this IB.
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_ci	 * - If more than one half of VRAM is occupied, only allow relocating
43162306a36Sopenharmony_ci	 *   1 MB of data for this IB.
43262306a36Sopenharmony_ci	 *
43362306a36Sopenharmony_ci	 * - From 0 to one half of used VRAM, the threshold decreases
43462306a36Sopenharmony_ci	 *   linearly.
43562306a36Sopenharmony_ci	 *         __________________
43662306a36Sopenharmony_ci	 * 1/4 of -|\               |
43762306a36Sopenharmony_ci	 * VRAM    | \              |
43862306a36Sopenharmony_ci	 *         |  \             |
43962306a36Sopenharmony_ci	 *         |   \            |
44062306a36Sopenharmony_ci	 *         |    \           |
44162306a36Sopenharmony_ci	 *         |     \          |
44262306a36Sopenharmony_ci	 *         |      \         |
44362306a36Sopenharmony_ci	 *         |       \________|1 MB
44462306a36Sopenharmony_ci	 *         |----------------|
44562306a36Sopenharmony_ci	 *    VRAM 0 %             100 %
44662306a36Sopenharmony_ci	 *         used            used
44762306a36Sopenharmony_ci	 *
44862306a36Sopenharmony_ci	 * Note: It's a threshold, not a limit. The threshold must be crossed
44962306a36Sopenharmony_ci	 * for buffer relocations to stop, so any buffer of an arbitrary size
45062306a36Sopenharmony_ci	 * can be moved as long as the threshold isn't crossed before
45162306a36Sopenharmony_ci	 * the relocation takes place. We don't want to disable buffer
45262306a36Sopenharmony_ci	 * relocations completely.
45362306a36Sopenharmony_ci	 *
45462306a36Sopenharmony_ci	 * The idea is that buffers should be placed in VRAM at creation time
45562306a36Sopenharmony_ci	 * and TTM should only do a minimum number of relocations during
45662306a36Sopenharmony_ci	 * command submission. In practice, you need to submit at least
45762306a36Sopenharmony_ci	 * a dozen IBs to move all buffers to VRAM if they are in GTT.
45862306a36Sopenharmony_ci	 *
45962306a36Sopenharmony_ci	 * Also, things can get pretty crazy under memory pressure and actual
46062306a36Sopenharmony_ci	 * VRAM usage can change a lot, so playing safe even at 50% does
46162306a36Sopenharmony_ci	 * consistently increase performance.
46262306a36Sopenharmony_ci	 */
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_ci	u64 half_vram = real_vram_size >> 1;
46562306a36Sopenharmony_ci	u64 half_free_vram = vram_usage >= half_vram ? 0 : half_vram - vram_usage;
46662306a36Sopenharmony_ci	u64 bytes_moved_threshold = half_free_vram >> 1;
46762306a36Sopenharmony_ci	return max(bytes_moved_threshold, 1024*1024ull);
46862306a36Sopenharmony_ci}
46962306a36Sopenharmony_ci
47062306a36Sopenharmony_ciint radeon_bo_list_validate(struct radeon_device *rdev,
47162306a36Sopenharmony_ci			    struct ww_acquire_ctx *ticket,
47262306a36Sopenharmony_ci			    struct list_head *head, int ring)
47362306a36Sopenharmony_ci{
47462306a36Sopenharmony_ci	struct ttm_operation_ctx ctx = { true, false };
47562306a36Sopenharmony_ci	struct radeon_bo_list *lobj;
47662306a36Sopenharmony_ci	struct list_head duplicates;
47762306a36Sopenharmony_ci	int r;
47862306a36Sopenharmony_ci	u64 bytes_moved = 0, initial_bytes_moved;
47962306a36Sopenharmony_ci	u64 bytes_moved_threshold = radeon_bo_get_threshold_for_moves(rdev);
48062306a36Sopenharmony_ci
48162306a36Sopenharmony_ci	INIT_LIST_HEAD(&duplicates);
48262306a36Sopenharmony_ci	r = ttm_eu_reserve_buffers(ticket, head, true, &duplicates);
48362306a36Sopenharmony_ci	if (unlikely(r != 0)) {
48462306a36Sopenharmony_ci		return r;
48562306a36Sopenharmony_ci	}
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_ci	list_for_each_entry(lobj, head, tv.head) {
48862306a36Sopenharmony_ci		struct radeon_bo *bo = lobj->robj;
48962306a36Sopenharmony_ci		if (!bo->tbo.pin_count) {
49062306a36Sopenharmony_ci			u32 domain = lobj->preferred_domains;
49162306a36Sopenharmony_ci			u32 allowed = lobj->allowed_domains;
49262306a36Sopenharmony_ci			u32 current_domain =
49362306a36Sopenharmony_ci				radeon_mem_type_to_domain(bo->tbo.resource->mem_type);
49462306a36Sopenharmony_ci
49562306a36Sopenharmony_ci			/* Check if this buffer will be moved and don't move it
49662306a36Sopenharmony_ci			 * if we have moved too many buffers for this IB already.
49762306a36Sopenharmony_ci			 *
49862306a36Sopenharmony_ci			 * Note that this allows moving at least one buffer of
49962306a36Sopenharmony_ci			 * any size, because it doesn't take the current "bo"
50062306a36Sopenharmony_ci			 * into account. We don't want to disallow buffer moves
50162306a36Sopenharmony_ci			 * completely.
50262306a36Sopenharmony_ci			 */
50362306a36Sopenharmony_ci			if ((allowed & current_domain) != 0 &&
50462306a36Sopenharmony_ci			    (domain & current_domain) == 0 && /* will be moved */
50562306a36Sopenharmony_ci			    bytes_moved > bytes_moved_threshold) {
50662306a36Sopenharmony_ci				/* don't move it */
50762306a36Sopenharmony_ci				domain = current_domain;
50862306a36Sopenharmony_ci			}
50962306a36Sopenharmony_ci
51062306a36Sopenharmony_ci		retry:
51162306a36Sopenharmony_ci			radeon_ttm_placement_from_domain(bo, domain);
51262306a36Sopenharmony_ci			if (ring == R600_RING_TYPE_UVD_INDEX)
51362306a36Sopenharmony_ci				radeon_uvd_force_into_uvd_segment(bo, allowed);
51462306a36Sopenharmony_ci
51562306a36Sopenharmony_ci			initial_bytes_moved = atomic64_read(&rdev->num_bytes_moved);
51662306a36Sopenharmony_ci			r = ttm_bo_validate(&bo->tbo, &bo->placement, &ctx);
51762306a36Sopenharmony_ci			bytes_moved += atomic64_read(&rdev->num_bytes_moved) -
51862306a36Sopenharmony_ci				       initial_bytes_moved;
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_ci			if (unlikely(r)) {
52162306a36Sopenharmony_ci				if (r != -ERESTARTSYS &&
52262306a36Sopenharmony_ci				    domain != lobj->allowed_domains) {
52362306a36Sopenharmony_ci					domain = lobj->allowed_domains;
52462306a36Sopenharmony_ci					goto retry;
52562306a36Sopenharmony_ci				}
52662306a36Sopenharmony_ci				ttm_eu_backoff_reservation(ticket, head);
52762306a36Sopenharmony_ci				return r;
52862306a36Sopenharmony_ci			}
52962306a36Sopenharmony_ci		}
53062306a36Sopenharmony_ci		lobj->gpu_offset = radeon_bo_gpu_offset(bo);
53162306a36Sopenharmony_ci		lobj->tiling_flags = bo->tiling_flags;
53262306a36Sopenharmony_ci	}
53362306a36Sopenharmony_ci
53462306a36Sopenharmony_ci	list_for_each_entry(lobj, &duplicates, tv.head) {
53562306a36Sopenharmony_ci		lobj->gpu_offset = radeon_bo_gpu_offset(lobj->robj);
53662306a36Sopenharmony_ci		lobj->tiling_flags = lobj->robj->tiling_flags;
53762306a36Sopenharmony_ci	}
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_ci	return 0;
54062306a36Sopenharmony_ci}
54162306a36Sopenharmony_ci
54262306a36Sopenharmony_ciint radeon_bo_get_surface_reg(struct radeon_bo *bo)
54362306a36Sopenharmony_ci{
54462306a36Sopenharmony_ci	struct radeon_device *rdev = bo->rdev;
54562306a36Sopenharmony_ci	struct radeon_surface_reg *reg;
54662306a36Sopenharmony_ci	struct radeon_bo *old_object;
54762306a36Sopenharmony_ci	int steal;
54862306a36Sopenharmony_ci	int i;
54962306a36Sopenharmony_ci
55062306a36Sopenharmony_ci	dma_resv_assert_held(bo->tbo.base.resv);
55162306a36Sopenharmony_ci
55262306a36Sopenharmony_ci	if (!bo->tiling_flags)
55362306a36Sopenharmony_ci		return 0;
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_ci	if (bo->surface_reg >= 0) {
55662306a36Sopenharmony_ci		i = bo->surface_reg;
55762306a36Sopenharmony_ci		goto out;
55862306a36Sopenharmony_ci	}
55962306a36Sopenharmony_ci
56062306a36Sopenharmony_ci	steal = -1;
56162306a36Sopenharmony_ci	for (i = 0; i < RADEON_GEM_MAX_SURFACES; i++) {
56262306a36Sopenharmony_ci
56362306a36Sopenharmony_ci		reg = &rdev->surface_regs[i];
56462306a36Sopenharmony_ci		if (!reg->bo)
56562306a36Sopenharmony_ci			break;
56662306a36Sopenharmony_ci
56762306a36Sopenharmony_ci		old_object = reg->bo;
56862306a36Sopenharmony_ci		if (old_object->tbo.pin_count == 0)
56962306a36Sopenharmony_ci			steal = i;
57062306a36Sopenharmony_ci	}
57162306a36Sopenharmony_ci
57262306a36Sopenharmony_ci	/* if we are all out */
57362306a36Sopenharmony_ci	if (i == RADEON_GEM_MAX_SURFACES) {
57462306a36Sopenharmony_ci		if (steal == -1)
57562306a36Sopenharmony_ci			return -ENOMEM;
57662306a36Sopenharmony_ci		/* find someone with a surface reg and nuke their BO */
57762306a36Sopenharmony_ci		reg = &rdev->surface_regs[steal];
57862306a36Sopenharmony_ci		old_object = reg->bo;
57962306a36Sopenharmony_ci		/* blow away the mapping */
58062306a36Sopenharmony_ci		DRM_DEBUG("stealing surface reg %d from %p\n", steal, old_object);
58162306a36Sopenharmony_ci		ttm_bo_unmap_virtual(&old_object->tbo);
58262306a36Sopenharmony_ci		old_object->surface_reg = -1;
58362306a36Sopenharmony_ci		i = steal;
58462306a36Sopenharmony_ci	}
58562306a36Sopenharmony_ci
58662306a36Sopenharmony_ci	bo->surface_reg = i;
58762306a36Sopenharmony_ci	reg->bo = bo;
58862306a36Sopenharmony_ci
58962306a36Sopenharmony_ciout:
59062306a36Sopenharmony_ci	radeon_set_surface_reg(rdev, i, bo->tiling_flags, bo->pitch,
59162306a36Sopenharmony_ci			       bo->tbo.resource->start << PAGE_SHIFT,
59262306a36Sopenharmony_ci			       bo->tbo.base.size);
59362306a36Sopenharmony_ci	return 0;
59462306a36Sopenharmony_ci}
59562306a36Sopenharmony_ci
59662306a36Sopenharmony_cistatic void radeon_bo_clear_surface_reg(struct radeon_bo *bo)
59762306a36Sopenharmony_ci{
59862306a36Sopenharmony_ci	struct radeon_device *rdev = bo->rdev;
59962306a36Sopenharmony_ci	struct radeon_surface_reg *reg;
60062306a36Sopenharmony_ci
60162306a36Sopenharmony_ci	if (bo->surface_reg == -1)
60262306a36Sopenharmony_ci		return;
60362306a36Sopenharmony_ci
60462306a36Sopenharmony_ci	reg = &rdev->surface_regs[bo->surface_reg];
60562306a36Sopenharmony_ci	radeon_clear_surface_reg(rdev, bo->surface_reg);
60662306a36Sopenharmony_ci
60762306a36Sopenharmony_ci	reg->bo = NULL;
60862306a36Sopenharmony_ci	bo->surface_reg = -1;
60962306a36Sopenharmony_ci}
61062306a36Sopenharmony_ci
61162306a36Sopenharmony_ciint radeon_bo_set_tiling_flags(struct radeon_bo *bo,
61262306a36Sopenharmony_ci				uint32_t tiling_flags, uint32_t pitch)
61362306a36Sopenharmony_ci{
61462306a36Sopenharmony_ci	struct radeon_device *rdev = bo->rdev;
61562306a36Sopenharmony_ci	int r;
61662306a36Sopenharmony_ci
61762306a36Sopenharmony_ci	if (rdev->family >= CHIP_CEDAR) {
61862306a36Sopenharmony_ci		unsigned bankw, bankh, mtaspect, tilesplit, stilesplit;
61962306a36Sopenharmony_ci
62062306a36Sopenharmony_ci		bankw = (tiling_flags >> RADEON_TILING_EG_BANKW_SHIFT) & RADEON_TILING_EG_BANKW_MASK;
62162306a36Sopenharmony_ci		bankh = (tiling_flags >> RADEON_TILING_EG_BANKH_SHIFT) & RADEON_TILING_EG_BANKH_MASK;
62262306a36Sopenharmony_ci		mtaspect = (tiling_flags >> RADEON_TILING_EG_MACRO_TILE_ASPECT_SHIFT) & RADEON_TILING_EG_MACRO_TILE_ASPECT_MASK;
62362306a36Sopenharmony_ci		tilesplit = (tiling_flags >> RADEON_TILING_EG_TILE_SPLIT_SHIFT) & RADEON_TILING_EG_TILE_SPLIT_MASK;
62462306a36Sopenharmony_ci		stilesplit = (tiling_flags >> RADEON_TILING_EG_STENCIL_TILE_SPLIT_SHIFT) & RADEON_TILING_EG_STENCIL_TILE_SPLIT_MASK;
62562306a36Sopenharmony_ci		switch (bankw) {
62662306a36Sopenharmony_ci		case 0:
62762306a36Sopenharmony_ci		case 1:
62862306a36Sopenharmony_ci		case 2:
62962306a36Sopenharmony_ci		case 4:
63062306a36Sopenharmony_ci		case 8:
63162306a36Sopenharmony_ci			break;
63262306a36Sopenharmony_ci		default:
63362306a36Sopenharmony_ci			return -EINVAL;
63462306a36Sopenharmony_ci		}
63562306a36Sopenharmony_ci		switch (bankh) {
63662306a36Sopenharmony_ci		case 0:
63762306a36Sopenharmony_ci		case 1:
63862306a36Sopenharmony_ci		case 2:
63962306a36Sopenharmony_ci		case 4:
64062306a36Sopenharmony_ci		case 8:
64162306a36Sopenharmony_ci			break;
64262306a36Sopenharmony_ci		default:
64362306a36Sopenharmony_ci			return -EINVAL;
64462306a36Sopenharmony_ci		}
64562306a36Sopenharmony_ci		switch (mtaspect) {
64662306a36Sopenharmony_ci		case 0:
64762306a36Sopenharmony_ci		case 1:
64862306a36Sopenharmony_ci		case 2:
64962306a36Sopenharmony_ci		case 4:
65062306a36Sopenharmony_ci		case 8:
65162306a36Sopenharmony_ci			break;
65262306a36Sopenharmony_ci		default:
65362306a36Sopenharmony_ci			return -EINVAL;
65462306a36Sopenharmony_ci		}
65562306a36Sopenharmony_ci		if (tilesplit > 6) {
65662306a36Sopenharmony_ci			return -EINVAL;
65762306a36Sopenharmony_ci		}
65862306a36Sopenharmony_ci		if (stilesplit > 6) {
65962306a36Sopenharmony_ci			return -EINVAL;
66062306a36Sopenharmony_ci		}
66162306a36Sopenharmony_ci	}
66262306a36Sopenharmony_ci	r = radeon_bo_reserve(bo, false);
66362306a36Sopenharmony_ci	if (unlikely(r != 0))
66462306a36Sopenharmony_ci		return r;
66562306a36Sopenharmony_ci	bo->tiling_flags = tiling_flags;
66662306a36Sopenharmony_ci	bo->pitch = pitch;
66762306a36Sopenharmony_ci	radeon_bo_unreserve(bo);
66862306a36Sopenharmony_ci	return 0;
66962306a36Sopenharmony_ci}
67062306a36Sopenharmony_ci
67162306a36Sopenharmony_civoid radeon_bo_get_tiling_flags(struct radeon_bo *bo,
67262306a36Sopenharmony_ci				uint32_t *tiling_flags,
67362306a36Sopenharmony_ci				uint32_t *pitch)
67462306a36Sopenharmony_ci{
67562306a36Sopenharmony_ci	dma_resv_assert_held(bo->tbo.base.resv);
67662306a36Sopenharmony_ci
67762306a36Sopenharmony_ci	if (tiling_flags)
67862306a36Sopenharmony_ci		*tiling_flags = bo->tiling_flags;
67962306a36Sopenharmony_ci	if (pitch)
68062306a36Sopenharmony_ci		*pitch = bo->pitch;
68162306a36Sopenharmony_ci}
68262306a36Sopenharmony_ci
68362306a36Sopenharmony_ciint radeon_bo_check_tiling(struct radeon_bo *bo, bool has_moved,
68462306a36Sopenharmony_ci				bool force_drop)
68562306a36Sopenharmony_ci{
68662306a36Sopenharmony_ci	if (!force_drop)
68762306a36Sopenharmony_ci		dma_resv_assert_held(bo->tbo.base.resv);
68862306a36Sopenharmony_ci
68962306a36Sopenharmony_ci	if (!(bo->tiling_flags & RADEON_TILING_SURFACE))
69062306a36Sopenharmony_ci		return 0;
69162306a36Sopenharmony_ci
69262306a36Sopenharmony_ci	if (force_drop) {
69362306a36Sopenharmony_ci		radeon_bo_clear_surface_reg(bo);
69462306a36Sopenharmony_ci		return 0;
69562306a36Sopenharmony_ci	}
69662306a36Sopenharmony_ci
69762306a36Sopenharmony_ci	if (bo->tbo.resource->mem_type != TTM_PL_VRAM) {
69862306a36Sopenharmony_ci		if (!has_moved)
69962306a36Sopenharmony_ci			return 0;
70062306a36Sopenharmony_ci
70162306a36Sopenharmony_ci		if (bo->surface_reg >= 0)
70262306a36Sopenharmony_ci			radeon_bo_clear_surface_reg(bo);
70362306a36Sopenharmony_ci		return 0;
70462306a36Sopenharmony_ci	}
70562306a36Sopenharmony_ci
70662306a36Sopenharmony_ci	if ((bo->surface_reg >= 0) && !has_moved)
70762306a36Sopenharmony_ci		return 0;
70862306a36Sopenharmony_ci
70962306a36Sopenharmony_ci	return radeon_bo_get_surface_reg(bo);
71062306a36Sopenharmony_ci}
71162306a36Sopenharmony_ci
71262306a36Sopenharmony_civoid radeon_bo_move_notify(struct ttm_buffer_object *bo)
71362306a36Sopenharmony_ci{
71462306a36Sopenharmony_ci	struct radeon_bo *rbo;
71562306a36Sopenharmony_ci
71662306a36Sopenharmony_ci	if (!radeon_ttm_bo_is_radeon_bo(bo))
71762306a36Sopenharmony_ci		return;
71862306a36Sopenharmony_ci
71962306a36Sopenharmony_ci	rbo = container_of(bo, struct radeon_bo, tbo);
72062306a36Sopenharmony_ci	radeon_bo_check_tiling(rbo, 0, 1);
72162306a36Sopenharmony_ci	radeon_vm_bo_invalidate(rbo->rdev, rbo);
72262306a36Sopenharmony_ci}
72362306a36Sopenharmony_ci
72462306a36Sopenharmony_civm_fault_t radeon_bo_fault_reserve_notify(struct ttm_buffer_object *bo)
72562306a36Sopenharmony_ci{
72662306a36Sopenharmony_ci	struct ttm_operation_ctx ctx = { false, false };
72762306a36Sopenharmony_ci	struct radeon_device *rdev;
72862306a36Sopenharmony_ci	struct radeon_bo *rbo;
72962306a36Sopenharmony_ci	unsigned long offset, size, lpfn;
73062306a36Sopenharmony_ci	int i, r;
73162306a36Sopenharmony_ci
73262306a36Sopenharmony_ci	if (!radeon_ttm_bo_is_radeon_bo(bo))
73362306a36Sopenharmony_ci		return 0;
73462306a36Sopenharmony_ci	rbo = container_of(bo, struct radeon_bo, tbo);
73562306a36Sopenharmony_ci	radeon_bo_check_tiling(rbo, 0, 0);
73662306a36Sopenharmony_ci	rdev = rbo->rdev;
73762306a36Sopenharmony_ci	if (bo->resource->mem_type != TTM_PL_VRAM)
73862306a36Sopenharmony_ci		return 0;
73962306a36Sopenharmony_ci
74062306a36Sopenharmony_ci	size = bo->resource->size;
74162306a36Sopenharmony_ci	offset = bo->resource->start << PAGE_SHIFT;
74262306a36Sopenharmony_ci	if ((offset + size) <= rdev->mc.visible_vram_size)
74362306a36Sopenharmony_ci		return 0;
74462306a36Sopenharmony_ci
74562306a36Sopenharmony_ci	/* Can't move a pinned BO to visible VRAM */
74662306a36Sopenharmony_ci	if (rbo->tbo.pin_count > 0)
74762306a36Sopenharmony_ci		return VM_FAULT_SIGBUS;
74862306a36Sopenharmony_ci
74962306a36Sopenharmony_ci	/* hurrah the memory is not visible ! */
75062306a36Sopenharmony_ci	radeon_ttm_placement_from_domain(rbo, RADEON_GEM_DOMAIN_VRAM);
75162306a36Sopenharmony_ci	lpfn =	rdev->mc.visible_vram_size >> PAGE_SHIFT;
75262306a36Sopenharmony_ci	for (i = 0; i < rbo->placement.num_placement; i++) {
75362306a36Sopenharmony_ci		/* Force into visible VRAM */
75462306a36Sopenharmony_ci		if ((rbo->placements[i].mem_type == TTM_PL_VRAM) &&
75562306a36Sopenharmony_ci		    (!rbo->placements[i].lpfn || rbo->placements[i].lpfn > lpfn))
75662306a36Sopenharmony_ci			rbo->placements[i].lpfn = lpfn;
75762306a36Sopenharmony_ci	}
75862306a36Sopenharmony_ci	r = ttm_bo_validate(bo, &rbo->placement, &ctx);
75962306a36Sopenharmony_ci	if (unlikely(r == -ENOMEM)) {
76062306a36Sopenharmony_ci		radeon_ttm_placement_from_domain(rbo, RADEON_GEM_DOMAIN_GTT);
76162306a36Sopenharmony_ci		r = ttm_bo_validate(bo, &rbo->placement, &ctx);
76262306a36Sopenharmony_ci	} else if (likely(!r)) {
76362306a36Sopenharmony_ci		offset = bo->resource->start << PAGE_SHIFT;
76462306a36Sopenharmony_ci		/* this should never happen */
76562306a36Sopenharmony_ci		if ((offset + size) > rdev->mc.visible_vram_size)
76662306a36Sopenharmony_ci			return VM_FAULT_SIGBUS;
76762306a36Sopenharmony_ci	}
76862306a36Sopenharmony_ci
76962306a36Sopenharmony_ci	if (unlikely(r == -EBUSY || r == -ERESTARTSYS))
77062306a36Sopenharmony_ci		return VM_FAULT_NOPAGE;
77162306a36Sopenharmony_ci	else if (unlikely(r))
77262306a36Sopenharmony_ci		return VM_FAULT_SIGBUS;
77362306a36Sopenharmony_ci
77462306a36Sopenharmony_ci	ttm_bo_move_to_lru_tail_unlocked(bo);
77562306a36Sopenharmony_ci	return 0;
77662306a36Sopenharmony_ci}
77762306a36Sopenharmony_ci
77862306a36Sopenharmony_ci/**
77962306a36Sopenharmony_ci * radeon_bo_fence - add fence to buffer object
78062306a36Sopenharmony_ci *
78162306a36Sopenharmony_ci * @bo: buffer object in question
78262306a36Sopenharmony_ci * @fence: fence to add
78362306a36Sopenharmony_ci * @shared: true if fence should be added shared
78462306a36Sopenharmony_ci *
78562306a36Sopenharmony_ci */
78662306a36Sopenharmony_civoid radeon_bo_fence(struct radeon_bo *bo, struct radeon_fence *fence,
78762306a36Sopenharmony_ci		     bool shared)
78862306a36Sopenharmony_ci{
78962306a36Sopenharmony_ci	struct dma_resv *resv = bo->tbo.base.resv;
79062306a36Sopenharmony_ci	int r;
79162306a36Sopenharmony_ci
79262306a36Sopenharmony_ci	r = dma_resv_reserve_fences(resv, 1);
79362306a36Sopenharmony_ci	if (r) {
79462306a36Sopenharmony_ci		/* As last resort on OOM we block for the fence */
79562306a36Sopenharmony_ci		dma_fence_wait(&fence->base, false);
79662306a36Sopenharmony_ci		return;
79762306a36Sopenharmony_ci	}
79862306a36Sopenharmony_ci
79962306a36Sopenharmony_ci	dma_resv_add_fence(resv, &fence->base, shared ?
80062306a36Sopenharmony_ci			   DMA_RESV_USAGE_READ : DMA_RESV_USAGE_WRITE);
80162306a36Sopenharmony_ci}
802