18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * Copyright 2009 Jerome Glisse.
38c2ecf20Sopenharmony_ci * All Rights Reserved.
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
68c2ecf20Sopenharmony_ci * copy of this software and associated documentation files (the
78c2ecf20Sopenharmony_ci * "Software"), to deal in the Software without restriction, including
88c2ecf20Sopenharmony_ci * without limitation the rights to use, copy, modify, merge, publish,
98c2ecf20Sopenharmony_ci * distribute, sub license, and/or sell copies of the Software, and to
108c2ecf20Sopenharmony_ci * permit persons to whom the Software is furnished to do so, subject to
118c2ecf20Sopenharmony_ci * the following conditions:
128c2ecf20Sopenharmony_ci *
138c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
148c2ecf20Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
158c2ecf20Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
168c2ecf20Sopenharmony_ci * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
178c2ecf20Sopenharmony_ci * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
188c2ecf20Sopenharmony_ci * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
198c2ecf20Sopenharmony_ci * USE OR OTHER DEALINGS IN THE SOFTWARE.
208c2ecf20Sopenharmony_ci *
218c2ecf20Sopenharmony_ci * The above copyright notice and this permission notice (including the
228c2ecf20Sopenharmony_ci * next paragraph) shall be included in all copies or substantial portions
238c2ecf20Sopenharmony_ci * of the Software.
248c2ecf20Sopenharmony_ci *
258c2ecf20Sopenharmony_ci */
268c2ecf20Sopenharmony_ci/*
278c2ecf20Sopenharmony_ci * Authors:
288c2ecf20Sopenharmony_ci *    Jerome Glisse <glisse@freedesktop.org>
298c2ecf20Sopenharmony_ci *    Thomas Hellstrom <thomas-at-tungstengraphics-dot-com>
308c2ecf20Sopenharmony_ci *    Dave Airlie
318c2ecf20Sopenharmony_ci */
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci#include <linux/io.h>
348c2ecf20Sopenharmony_ci#include <linux/list.h>
358c2ecf20Sopenharmony_ci#include <linux/slab.h>
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ci#include <drm/drm_cache.h>
388c2ecf20Sopenharmony_ci#include <drm/drm_prime.h>
398c2ecf20Sopenharmony_ci#include <drm/radeon_drm.h>
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci#include "radeon.h"
428c2ecf20Sopenharmony_ci#include "radeon_trace.h"
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ciint radeon_ttm_init(struct radeon_device *rdev);
458c2ecf20Sopenharmony_civoid radeon_ttm_fini(struct radeon_device *rdev);
468c2ecf20Sopenharmony_cistatic void radeon_bo_clear_surface_reg(struct radeon_bo *bo);
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci/*
498c2ecf20Sopenharmony_ci * To exclude mutual BO access we rely on bo_reserve exclusion, as all
508c2ecf20Sopenharmony_ci * function are calling it.
518c2ecf20Sopenharmony_ci */
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_cistatic void radeon_update_memory_usage(struct radeon_bo *bo,
548c2ecf20Sopenharmony_ci				       unsigned mem_type, int sign)
558c2ecf20Sopenharmony_ci{
568c2ecf20Sopenharmony_ci	struct radeon_device *rdev = bo->rdev;
578c2ecf20Sopenharmony_ci	u64 size = (u64)bo->tbo.num_pages << PAGE_SHIFT;
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci	switch (mem_type) {
608c2ecf20Sopenharmony_ci	case TTM_PL_TT:
618c2ecf20Sopenharmony_ci		if (sign > 0)
628c2ecf20Sopenharmony_ci			atomic64_add(size, &rdev->gtt_usage);
638c2ecf20Sopenharmony_ci		else
648c2ecf20Sopenharmony_ci			atomic64_sub(size, &rdev->gtt_usage);
658c2ecf20Sopenharmony_ci		break;
668c2ecf20Sopenharmony_ci	case TTM_PL_VRAM:
678c2ecf20Sopenharmony_ci		if (sign > 0)
688c2ecf20Sopenharmony_ci			atomic64_add(size, &rdev->vram_usage);
698c2ecf20Sopenharmony_ci		else
708c2ecf20Sopenharmony_ci			atomic64_sub(size, &rdev->vram_usage);
718c2ecf20Sopenharmony_ci		break;
728c2ecf20Sopenharmony_ci	}
738c2ecf20Sopenharmony_ci}
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_cistatic void radeon_ttm_bo_destroy(struct ttm_buffer_object *tbo)
768c2ecf20Sopenharmony_ci{
778c2ecf20Sopenharmony_ci	struct radeon_bo *bo;
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci	bo = container_of(tbo, struct radeon_bo, tbo);
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci	radeon_update_memory_usage(bo, bo->tbo.mem.mem_type, -1);
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci	mutex_lock(&bo->rdev->gem.mutex);
848c2ecf20Sopenharmony_ci	list_del_init(&bo->list);
858c2ecf20Sopenharmony_ci	mutex_unlock(&bo->rdev->gem.mutex);
868c2ecf20Sopenharmony_ci	radeon_bo_clear_surface_reg(bo);
878c2ecf20Sopenharmony_ci	WARN_ON_ONCE(!list_empty(&bo->va));
888c2ecf20Sopenharmony_ci	if (bo->tbo.base.import_attach)
898c2ecf20Sopenharmony_ci		drm_prime_gem_destroy(&bo->tbo.base, bo->tbo.sg);
908c2ecf20Sopenharmony_ci	drm_gem_object_release(&bo->tbo.base);
918c2ecf20Sopenharmony_ci	kfree(bo);
928c2ecf20Sopenharmony_ci}
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_cibool radeon_ttm_bo_is_radeon_bo(struct ttm_buffer_object *bo)
958c2ecf20Sopenharmony_ci{
968c2ecf20Sopenharmony_ci	if (bo->destroy == &radeon_ttm_bo_destroy)
978c2ecf20Sopenharmony_ci		return true;
988c2ecf20Sopenharmony_ci	return false;
998c2ecf20Sopenharmony_ci}
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_civoid radeon_ttm_placement_from_domain(struct radeon_bo *rbo, u32 domain)
1028c2ecf20Sopenharmony_ci{
1038c2ecf20Sopenharmony_ci	u32 c = 0, i;
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci	rbo->placement.placement = rbo->placements;
1068c2ecf20Sopenharmony_ci	rbo->placement.busy_placement = rbo->placements;
1078c2ecf20Sopenharmony_ci	if (domain & RADEON_GEM_DOMAIN_VRAM) {
1088c2ecf20Sopenharmony_ci		/* Try placing BOs which don't need CPU access outside of the
1098c2ecf20Sopenharmony_ci		 * CPU accessible part of VRAM
1108c2ecf20Sopenharmony_ci		 */
1118c2ecf20Sopenharmony_ci		if ((rbo->flags & RADEON_GEM_NO_CPU_ACCESS) &&
1128c2ecf20Sopenharmony_ci		    rbo->rdev->mc.visible_vram_size < rbo->rdev->mc.real_vram_size) {
1138c2ecf20Sopenharmony_ci			rbo->placements[c].fpfn =
1148c2ecf20Sopenharmony_ci				rbo->rdev->mc.visible_vram_size >> PAGE_SHIFT;
1158c2ecf20Sopenharmony_ci			rbo->placements[c].mem_type = TTM_PL_VRAM;
1168c2ecf20Sopenharmony_ci			rbo->placements[c++].flags = TTM_PL_FLAG_WC |
1178c2ecf20Sopenharmony_ci						     TTM_PL_FLAG_UNCACHED;
1188c2ecf20Sopenharmony_ci		}
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci		rbo->placements[c].fpfn = 0;
1218c2ecf20Sopenharmony_ci		rbo->placements[c].mem_type = TTM_PL_VRAM;
1228c2ecf20Sopenharmony_ci		rbo->placements[c++].flags = TTM_PL_FLAG_WC |
1238c2ecf20Sopenharmony_ci					     TTM_PL_FLAG_UNCACHED;
1248c2ecf20Sopenharmony_ci	}
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ci	if (domain & RADEON_GEM_DOMAIN_GTT) {
1278c2ecf20Sopenharmony_ci		if (rbo->flags & RADEON_GEM_GTT_UC) {
1288c2ecf20Sopenharmony_ci			rbo->placements[c].fpfn = 0;
1298c2ecf20Sopenharmony_ci			rbo->placements[c].mem_type = TTM_PL_TT;
1308c2ecf20Sopenharmony_ci			rbo->placements[c++].flags = TTM_PL_FLAG_UNCACHED;
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci		} else if ((rbo->flags & RADEON_GEM_GTT_WC) ||
1338c2ecf20Sopenharmony_ci			   (rbo->rdev->flags & RADEON_IS_AGP)) {
1348c2ecf20Sopenharmony_ci			rbo->placements[c].fpfn = 0;
1358c2ecf20Sopenharmony_ci			rbo->placements[c].mem_type = TTM_PL_TT;
1368c2ecf20Sopenharmony_ci			rbo->placements[c++].flags = TTM_PL_FLAG_WC |
1378c2ecf20Sopenharmony_ci				TTM_PL_FLAG_UNCACHED;
1388c2ecf20Sopenharmony_ci		} else {
1398c2ecf20Sopenharmony_ci			rbo->placements[c].fpfn = 0;
1408c2ecf20Sopenharmony_ci			rbo->placements[c].mem_type = TTM_PL_TT;
1418c2ecf20Sopenharmony_ci			rbo->placements[c++].flags = TTM_PL_FLAG_CACHED;
1428c2ecf20Sopenharmony_ci		}
1438c2ecf20Sopenharmony_ci	}
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ci	if (domain & RADEON_GEM_DOMAIN_CPU) {
1468c2ecf20Sopenharmony_ci		if (rbo->flags & RADEON_GEM_GTT_UC) {
1478c2ecf20Sopenharmony_ci			rbo->placements[c].fpfn = 0;
1488c2ecf20Sopenharmony_ci			rbo->placements[c].mem_type = TTM_PL_SYSTEM;
1498c2ecf20Sopenharmony_ci			rbo->placements[c++].flags = TTM_PL_FLAG_UNCACHED;
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci		} else if ((rbo->flags & RADEON_GEM_GTT_WC) ||
1528c2ecf20Sopenharmony_ci		    rbo->rdev->flags & RADEON_IS_AGP) {
1538c2ecf20Sopenharmony_ci			rbo->placements[c].fpfn = 0;
1548c2ecf20Sopenharmony_ci			rbo->placements[c].mem_type = TTM_PL_SYSTEM;
1558c2ecf20Sopenharmony_ci			rbo->placements[c++].flags = TTM_PL_FLAG_WC |
1568c2ecf20Sopenharmony_ci				TTM_PL_FLAG_UNCACHED;
1578c2ecf20Sopenharmony_ci		} else {
1588c2ecf20Sopenharmony_ci			rbo->placements[c].fpfn = 0;
1598c2ecf20Sopenharmony_ci			rbo->placements[c].mem_type = TTM_PL_SYSTEM;
1608c2ecf20Sopenharmony_ci			rbo->placements[c++].flags = TTM_PL_FLAG_CACHED;
1618c2ecf20Sopenharmony_ci		}
1628c2ecf20Sopenharmony_ci	}
1638c2ecf20Sopenharmony_ci	if (!c) {
1648c2ecf20Sopenharmony_ci		rbo->placements[c].fpfn = 0;
1658c2ecf20Sopenharmony_ci		rbo->placements[c].mem_type = TTM_PL_SYSTEM;
1668c2ecf20Sopenharmony_ci		rbo->placements[c++].flags = TTM_PL_MASK_CACHING;
1678c2ecf20Sopenharmony_ci	}
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci	rbo->placement.num_placement = c;
1708c2ecf20Sopenharmony_ci	rbo->placement.num_busy_placement = c;
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ci	for (i = 0; i < c; ++i) {
1738c2ecf20Sopenharmony_ci		if ((rbo->flags & RADEON_GEM_CPU_ACCESS) &&
1748c2ecf20Sopenharmony_ci		    (rbo->placements[i].mem_type == TTM_PL_VRAM) &&
1758c2ecf20Sopenharmony_ci		    !rbo->placements[i].fpfn)
1768c2ecf20Sopenharmony_ci			rbo->placements[i].lpfn =
1778c2ecf20Sopenharmony_ci				rbo->rdev->mc.visible_vram_size >> PAGE_SHIFT;
1788c2ecf20Sopenharmony_ci		else
1798c2ecf20Sopenharmony_ci			rbo->placements[i].lpfn = 0;
1808c2ecf20Sopenharmony_ci	}
1818c2ecf20Sopenharmony_ci}
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_ciint radeon_bo_create(struct radeon_device *rdev,
1848c2ecf20Sopenharmony_ci		     unsigned long size, int byte_align, bool kernel,
1858c2ecf20Sopenharmony_ci		     u32 domain, u32 flags, struct sg_table *sg,
1868c2ecf20Sopenharmony_ci		     struct dma_resv *resv,
1878c2ecf20Sopenharmony_ci		     struct radeon_bo **bo_ptr)
1888c2ecf20Sopenharmony_ci{
1898c2ecf20Sopenharmony_ci	struct radeon_bo *bo;
1908c2ecf20Sopenharmony_ci	enum ttm_bo_type type;
1918c2ecf20Sopenharmony_ci	unsigned long page_align = roundup(byte_align, PAGE_SIZE) >> PAGE_SHIFT;
1928c2ecf20Sopenharmony_ci	size_t acc_size;
1938c2ecf20Sopenharmony_ci	int r;
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci	size = ALIGN(size, PAGE_SIZE);
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_ci	if (kernel) {
1988c2ecf20Sopenharmony_ci		type = ttm_bo_type_kernel;
1998c2ecf20Sopenharmony_ci	} else if (sg) {
2008c2ecf20Sopenharmony_ci		type = ttm_bo_type_sg;
2018c2ecf20Sopenharmony_ci	} else {
2028c2ecf20Sopenharmony_ci		type = ttm_bo_type_device;
2038c2ecf20Sopenharmony_ci	}
2048c2ecf20Sopenharmony_ci	*bo_ptr = NULL;
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_ci	acc_size = ttm_bo_dma_acc_size(&rdev->mman.bdev, size,
2078c2ecf20Sopenharmony_ci				       sizeof(struct radeon_bo));
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ci	bo = kzalloc(sizeof(struct radeon_bo), GFP_KERNEL);
2108c2ecf20Sopenharmony_ci	if (bo == NULL)
2118c2ecf20Sopenharmony_ci		return -ENOMEM;
2128c2ecf20Sopenharmony_ci	drm_gem_private_object_init(rdev->ddev, &bo->tbo.base, size);
2138c2ecf20Sopenharmony_ci	bo->rdev = rdev;
2148c2ecf20Sopenharmony_ci	bo->surface_reg = -1;
2158c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&bo->list);
2168c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&bo->va);
2178c2ecf20Sopenharmony_ci	bo->initial_domain = domain & (RADEON_GEM_DOMAIN_VRAM |
2188c2ecf20Sopenharmony_ci				       RADEON_GEM_DOMAIN_GTT |
2198c2ecf20Sopenharmony_ci				       RADEON_GEM_DOMAIN_CPU);
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_ci	bo->flags = flags;
2228c2ecf20Sopenharmony_ci	/* PCI GART is always snooped */
2238c2ecf20Sopenharmony_ci	if (!(rdev->flags & RADEON_IS_PCIE))
2248c2ecf20Sopenharmony_ci		bo->flags &= ~(RADEON_GEM_GTT_WC | RADEON_GEM_GTT_UC);
2258c2ecf20Sopenharmony_ci
2268c2ecf20Sopenharmony_ci	/* Write-combined CPU mappings of GTT cause GPU hangs with RV6xx
2278c2ecf20Sopenharmony_ci	 * See https://bugs.freedesktop.org/show_bug.cgi?id=91268
2288c2ecf20Sopenharmony_ci	 */
2298c2ecf20Sopenharmony_ci	if (rdev->family >= CHIP_RV610 && rdev->family <= CHIP_RV635)
2308c2ecf20Sopenharmony_ci		bo->flags &= ~(RADEON_GEM_GTT_WC | RADEON_GEM_GTT_UC);
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_ci#ifdef CONFIG_X86_32
2338c2ecf20Sopenharmony_ci	/* XXX: Write-combined CPU mappings of GTT seem broken on 32-bit
2348c2ecf20Sopenharmony_ci	 * See https://bugs.freedesktop.org/show_bug.cgi?id=84627
2358c2ecf20Sopenharmony_ci	 */
2368c2ecf20Sopenharmony_ci	bo->flags &= ~(RADEON_GEM_GTT_WC | RADEON_GEM_GTT_UC);
2378c2ecf20Sopenharmony_ci#elif defined(CONFIG_X86) && !defined(CONFIG_X86_PAT)
2388c2ecf20Sopenharmony_ci	/* Don't try to enable write-combining when it can't work, or things
2398c2ecf20Sopenharmony_ci	 * may be slow
2408c2ecf20Sopenharmony_ci	 * See https://bugs.freedesktop.org/show_bug.cgi?id=88758
2418c2ecf20Sopenharmony_ci	 */
2428c2ecf20Sopenharmony_ci#ifndef CONFIG_COMPILE_TEST
2438c2ecf20Sopenharmony_ci#warning Please enable CONFIG_MTRR and CONFIG_X86_PAT for better performance \
2448c2ecf20Sopenharmony_ci	 thanks to write-combining
2458c2ecf20Sopenharmony_ci#endif
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci	if (bo->flags & RADEON_GEM_GTT_WC)
2488c2ecf20Sopenharmony_ci		DRM_INFO_ONCE("Please enable CONFIG_MTRR and CONFIG_X86_PAT for "
2498c2ecf20Sopenharmony_ci			      "better performance thanks to write-combining\n");
2508c2ecf20Sopenharmony_ci	bo->flags &= ~(RADEON_GEM_GTT_WC | RADEON_GEM_GTT_UC);
2518c2ecf20Sopenharmony_ci#else
2528c2ecf20Sopenharmony_ci	/* For architectures that don't support WC memory,
2538c2ecf20Sopenharmony_ci	 * mask out the WC flag from the BO
2548c2ecf20Sopenharmony_ci	 */
2558c2ecf20Sopenharmony_ci	if (!drm_arch_can_wc_memory())
2568c2ecf20Sopenharmony_ci		bo->flags &= ~RADEON_GEM_GTT_WC;
2578c2ecf20Sopenharmony_ci#endif
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_ci	radeon_ttm_placement_from_domain(bo, domain);
2608c2ecf20Sopenharmony_ci	/* Kernel allocation are uninterruptible */
2618c2ecf20Sopenharmony_ci	down_read(&rdev->pm.mclk_lock);
2628c2ecf20Sopenharmony_ci	r = ttm_bo_init(&rdev->mman.bdev, &bo->tbo, size, type,
2638c2ecf20Sopenharmony_ci			&bo->placement, page_align, !kernel, acc_size,
2648c2ecf20Sopenharmony_ci			sg, resv, &radeon_ttm_bo_destroy);
2658c2ecf20Sopenharmony_ci	up_read(&rdev->pm.mclk_lock);
2668c2ecf20Sopenharmony_ci	if (unlikely(r != 0)) {
2678c2ecf20Sopenharmony_ci		return r;
2688c2ecf20Sopenharmony_ci	}
2698c2ecf20Sopenharmony_ci	*bo_ptr = bo;
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_ci	trace_radeon_bo_create(bo);
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_ci	return 0;
2748c2ecf20Sopenharmony_ci}
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_ciint radeon_bo_kmap(struct radeon_bo *bo, void **ptr)
2778c2ecf20Sopenharmony_ci{
2788c2ecf20Sopenharmony_ci	bool is_iomem;
2798c2ecf20Sopenharmony_ci	int r;
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_ci	if (bo->kptr) {
2828c2ecf20Sopenharmony_ci		if (ptr) {
2838c2ecf20Sopenharmony_ci			*ptr = bo->kptr;
2848c2ecf20Sopenharmony_ci		}
2858c2ecf20Sopenharmony_ci		return 0;
2868c2ecf20Sopenharmony_ci	}
2878c2ecf20Sopenharmony_ci	r = ttm_bo_kmap(&bo->tbo, 0, bo->tbo.num_pages, &bo->kmap);
2888c2ecf20Sopenharmony_ci	if (r) {
2898c2ecf20Sopenharmony_ci		return r;
2908c2ecf20Sopenharmony_ci	}
2918c2ecf20Sopenharmony_ci	bo->kptr = ttm_kmap_obj_virtual(&bo->kmap, &is_iomem);
2928c2ecf20Sopenharmony_ci	if (ptr) {
2938c2ecf20Sopenharmony_ci		*ptr = bo->kptr;
2948c2ecf20Sopenharmony_ci	}
2958c2ecf20Sopenharmony_ci	radeon_bo_check_tiling(bo, 0, 0);
2968c2ecf20Sopenharmony_ci	return 0;
2978c2ecf20Sopenharmony_ci}
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_civoid radeon_bo_kunmap(struct radeon_bo *bo)
3008c2ecf20Sopenharmony_ci{
3018c2ecf20Sopenharmony_ci	if (bo->kptr == NULL)
3028c2ecf20Sopenharmony_ci		return;
3038c2ecf20Sopenharmony_ci	bo->kptr = NULL;
3048c2ecf20Sopenharmony_ci	radeon_bo_check_tiling(bo, 0, 0);
3058c2ecf20Sopenharmony_ci	ttm_bo_kunmap(&bo->kmap);
3068c2ecf20Sopenharmony_ci}
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_cistruct radeon_bo *radeon_bo_ref(struct radeon_bo *bo)
3098c2ecf20Sopenharmony_ci{
3108c2ecf20Sopenharmony_ci	if (bo == NULL)
3118c2ecf20Sopenharmony_ci		return NULL;
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_ci	ttm_bo_get(&bo->tbo);
3148c2ecf20Sopenharmony_ci	return bo;
3158c2ecf20Sopenharmony_ci}
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_civoid radeon_bo_unref(struct radeon_bo **bo)
3188c2ecf20Sopenharmony_ci{
3198c2ecf20Sopenharmony_ci	struct ttm_buffer_object *tbo;
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_ci	if ((*bo) == NULL)
3228c2ecf20Sopenharmony_ci		return;
3238c2ecf20Sopenharmony_ci	tbo = &((*bo)->tbo);
3248c2ecf20Sopenharmony_ci	ttm_bo_put(tbo);
3258c2ecf20Sopenharmony_ci	*bo = NULL;
3268c2ecf20Sopenharmony_ci}
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ciint radeon_bo_pin_restricted(struct radeon_bo *bo, u32 domain, u64 max_offset,
3298c2ecf20Sopenharmony_ci			     u64 *gpu_addr)
3308c2ecf20Sopenharmony_ci{
3318c2ecf20Sopenharmony_ci	struct ttm_operation_ctx ctx = { false, false };
3328c2ecf20Sopenharmony_ci	int r, i;
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ci	if (radeon_ttm_tt_has_userptr(bo->rdev, bo->tbo.ttm))
3358c2ecf20Sopenharmony_ci		return -EPERM;
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_ci	if (bo->pin_count) {
3388c2ecf20Sopenharmony_ci		bo->pin_count++;
3398c2ecf20Sopenharmony_ci		if (gpu_addr)
3408c2ecf20Sopenharmony_ci			*gpu_addr = radeon_bo_gpu_offset(bo);
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_ci		if (max_offset != 0) {
3438c2ecf20Sopenharmony_ci			u64 domain_start;
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_ci			if (domain == RADEON_GEM_DOMAIN_VRAM)
3468c2ecf20Sopenharmony_ci				domain_start = bo->rdev->mc.vram_start;
3478c2ecf20Sopenharmony_ci			else
3488c2ecf20Sopenharmony_ci				domain_start = bo->rdev->mc.gtt_start;
3498c2ecf20Sopenharmony_ci			WARN_ON_ONCE(max_offset <
3508c2ecf20Sopenharmony_ci				     (radeon_bo_gpu_offset(bo) - domain_start));
3518c2ecf20Sopenharmony_ci		}
3528c2ecf20Sopenharmony_ci
3538c2ecf20Sopenharmony_ci		return 0;
3548c2ecf20Sopenharmony_ci	}
3558c2ecf20Sopenharmony_ci	if (bo->prime_shared_count && domain == RADEON_GEM_DOMAIN_VRAM) {
3568c2ecf20Sopenharmony_ci		/* A BO shared as a dma-buf cannot be sensibly migrated to VRAM */
3578c2ecf20Sopenharmony_ci		return -EINVAL;
3588c2ecf20Sopenharmony_ci	}
3598c2ecf20Sopenharmony_ci
3608c2ecf20Sopenharmony_ci	radeon_ttm_placement_from_domain(bo, domain);
3618c2ecf20Sopenharmony_ci	for (i = 0; i < bo->placement.num_placement; i++) {
3628c2ecf20Sopenharmony_ci		/* force to pin into visible video ram */
3638c2ecf20Sopenharmony_ci		if ((bo->placements[i].mem_type == TTM_PL_VRAM) &&
3648c2ecf20Sopenharmony_ci		    !(bo->flags & RADEON_GEM_NO_CPU_ACCESS) &&
3658c2ecf20Sopenharmony_ci		    (!max_offset || max_offset > bo->rdev->mc.visible_vram_size))
3668c2ecf20Sopenharmony_ci			bo->placements[i].lpfn =
3678c2ecf20Sopenharmony_ci				bo->rdev->mc.visible_vram_size >> PAGE_SHIFT;
3688c2ecf20Sopenharmony_ci		else
3698c2ecf20Sopenharmony_ci			bo->placements[i].lpfn = max_offset >> PAGE_SHIFT;
3708c2ecf20Sopenharmony_ci
3718c2ecf20Sopenharmony_ci		bo->placements[i].flags |= TTM_PL_FLAG_NO_EVICT;
3728c2ecf20Sopenharmony_ci	}
3738c2ecf20Sopenharmony_ci
3748c2ecf20Sopenharmony_ci	r = ttm_bo_validate(&bo->tbo, &bo->placement, &ctx);
3758c2ecf20Sopenharmony_ci	if (likely(r == 0)) {
3768c2ecf20Sopenharmony_ci		bo->pin_count = 1;
3778c2ecf20Sopenharmony_ci		if (gpu_addr != NULL)
3788c2ecf20Sopenharmony_ci			*gpu_addr = radeon_bo_gpu_offset(bo);
3798c2ecf20Sopenharmony_ci		if (domain == RADEON_GEM_DOMAIN_VRAM)
3808c2ecf20Sopenharmony_ci			bo->rdev->vram_pin_size += radeon_bo_size(bo);
3818c2ecf20Sopenharmony_ci		else
3828c2ecf20Sopenharmony_ci			bo->rdev->gart_pin_size += radeon_bo_size(bo);
3838c2ecf20Sopenharmony_ci	} else {
3848c2ecf20Sopenharmony_ci		dev_err(bo->rdev->dev, "%p pin failed\n", bo);
3858c2ecf20Sopenharmony_ci	}
3868c2ecf20Sopenharmony_ci	return r;
3878c2ecf20Sopenharmony_ci}
3888c2ecf20Sopenharmony_ci
3898c2ecf20Sopenharmony_ciint radeon_bo_pin(struct radeon_bo *bo, u32 domain, u64 *gpu_addr)
3908c2ecf20Sopenharmony_ci{
3918c2ecf20Sopenharmony_ci	return radeon_bo_pin_restricted(bo, domain, 0, gpu_addr);
3928c2ecf20Sopenharmony_ci}
3938c2ecf20Sopenharmony_ci
3948c2ecf20Sopenharmony_ciint radeon_bo_unpin(struct radeon_bo *bo)
3958c2ecf20Sopenharmony_ci{
3968c2ecf20Sopenharmony_ci	struct ttm_operation_ctx ctx = { false, false };
3978c2ecf20Sopenharmony_ci	int r, i;
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_ci	if (!bo->pin_count) {
4008c2ecf20Sopenharmony_ci		dev_warn(bo->rdev->dev, "%p unpin not necessary\n", bo);
4018c2ecf20Sopenharmony_ci		return 0;
4028c2ecf20Sopenharmony_ci	}
4038c2ecf20Sopenharmony_ci	bo->pin_count--;
4048c2ecf20Sopenharmony_ci	if (bo->pin_count)
4058c2ecf20Sopenharmony_ci		return 0;
4068c2ecf20Sopenharmony_ci	for (i = 0; i < bo->placement.num_placement; i++) {
4078c2ecf20Sopenharmony_ci		bo->placements[i].lpfn = 0;
4088c2ecf20Sopenharmony_ci		bo->placements[i].flags &= ~TTM_PL_FLAG_NO_EVICT;
4098c2ecf20Sopenharmony_ci	}
4108c2ecf20Sopenharmony_ci	r = ttm_bo_validate(&bo->tbo, &bo->placement, &ctx);
4118c2ecf20Sopenharmony_ci	if (likely(r == 0)) {
4128c2ecf20Sopenharmony_ci		if (bo->tbo.mem.mem_type == TTM_PL_VRAM)
4138c2ecf20Sopenharmony_ci			bo->rdev->vram_pin_size -= radeon_bo_size(bo);
4148c2ecf20Sopenharmony_ci		else
4158c2ecf20Sopenharmony_ci			bo->rdev->gart_pin_size -= radeon_bo_size(bo);
4168c2ecf20Sopenharmony_ci	} else {
4178c2ecf20Sopenharmony_ci		dev_err(bo->rdev->dev, "%p validate failed for unpin\n", bo);
4188c2ecf20Sopenharmony_ci	}
4198c2ecf20Sopenharmony_ci	return r;
4208c2ecf20Sopenharmony_ci}
4218c2ecf20Sopenharmony_ci
4228c2ecf20Sopenharmony_ciint radeon_bo_evict_vram(struct radeon_device *rdev)
4238c2ecf20Sopenharmony_ci{
4248c2ecf20Sopenharmony_ci	/* late 2.6.33 fix IGP hibernate - we need pm ops to do this correct */
4258c2ecf20Sopenharmony_ci#ifndef CONFIG_HIBERNATION
4268c2ecf20Sopenharmony_ci	if (rdev->flags & RADEON_IS_IGP) {
4278c2ecf20Sopenharmony_ci		if (rdev->mc.igp_sideport_enabled == false)
4288c2ecf20Sopenharmony_ci			/* Useless to evict on IGP chips */
4298c2ecf20Sopenharmony_ci			return 0;
4308c2ecf20Sopenharmony_ci	}
4318c2ecf20Sopenharmony_ci#endif
4328c2ecf20Sopenharmony_ci	return ttm_bo_evict_mm(&rdev->mman.bdev, TTM_PL_VRAM);
4338c2ecf20Sopenharmony_ci}
4348c2ecf20Sopenharmony_ci
4358c2ecf20Sopenharmony_civoid radeon_bo_force_delete(struct radeon_device *rdev)
4368c2ecf20Sopenharmony_ci{
4378c2ecf20Sopenharmony_ci	struct radeon_bo *bo, *n;
4388c2ecf20Sopenharmony_ci
4398c2ecf20Sopenharmony_ci	if (list_empty(&rdev->gem.objects)) {
4408c2ecf20Sopenharmony_ci		return;
4418c2ecf20Sopenharmony_ci	}
4428c2ecf20Sopenharmony_ci	dev_err(rdev->dev, "Userspace still has active objects !\n");
4438c2ecf20Sopenharmony_ci	list_for_each_entry_safe(bo, n, &rdev->gem.objects, list) {
4448c2ecf20Sopenharmony_ci		dev_err(rdev->dev, "%p %p %lu %lu force free\n",
4458c2ecf20Sopenharmony_ci			&bo->tbo.base, bo, (unsigned long)bo->tbo.base.size,
4468c2ecf20Sopenharmony_ci			*((unsigned long *)&bo->tbo.base.refcount));
4478c2ecf20Sopenharmony_ci		mutex_lock(&bo->rdev->gem.mutex);
4488c2ecf20Sopenharmony_ci		list_del_init(&bo->list);
4498c2ecf20Sopenharmony_ci		mutex_unlock(&bo->rdev->gem.mutex);
4508c2ecf20Sopenharmony_ci		/* this should unref the ttm bo */
4518c2ecf20Sopenharmony_ci		drm_gem_object_put(&bo->tbo.base);
4528c2ecf20Sopenharmony_ci	}
4538c2ecf20Sopenharmony_ci}
4548c2ecf20Sopenharmony_ci
4558c2ecf20Sopenharmony_ciint radeon_bo_init(struct radeon_device *rdev)
4568c2ecf20Sopenharmony_ci{
4578c2ecf20Sopenharmony_ci	/* reserve PAT memory space to WC for VRAM */
4588c2ecf20Sopenharmony_ci	arch_io_reserve_memtype_wc(rdev->mc.aper_base,
4598c2ecf20Sopenharmony_ci				   rdev->mc.aper_size);
4608c2ecf20Sopenharmony_ci
4618c2ecf20Sopenharmony_ci	/* Add an MTRR for the VRAM */
4628c2ecf20Sopenharmony_ci	if (!rdev->fastfb_working) {
4638c2ecf20Sopenharmony_ci		rdev->mc.vram_mtrr = arch_phys_wc_add(rdev->mc.aper_base,
4648c2ecf20Sopenharmony_ci						      rdev->mc.aper_size);
4658c2ecf20Sopenharmony_ci	}
4668c2ecf20Sopenharmony_ci	DRM_INFO("Detected VRAM RAM=%lluM, BAR=%lluM\n",
4678c2ecf20Sopenharmony_ci		rdev->mc.mc_vram_size >> 20,
4688c2ecf20Sopenharmony_ci		(unsigned long long)rdev->mc.aper_size >> 20);
4698c2ecf20Sopenharmony_ci	DRM_INFO("RAM width %dbits %cDR\n",
4708c2ecf20Sopenharmony_ci			rdev->mc.vram_width, rdev->mc.vram_is_ddr ? 'D' : 'S');
4718c2ecf20Sopenharmony_ci	return radeon_ttm_init(rdev);
4728c2ecf20Sopenharmony_ci}
4738c2ecf20Sopenharmony_ci
4748c2ecf20Sopenharmony_civoid radeon_bo_fini(struct radeon_device *rdev)
4758c2ecf20Sopenharmony_ci{
4768c2ecf20Sopenharmony_ci	radeon_ttm_fini(rdev);
4778c2ecf20Sopenharmony_ci	arch_phys_wc_del(rdev->mc.vram_mtrr);
4788c2ecf20Sopenharmony_ci	arch_io_free_memtype_wc(rdev->mc.aper_base, rdev->mc.aper_size);
4798c2ecf20Sopenharmony_ci}
4808c2ecf20Sopenharmony_ci
4818c2ecf20Sopenharmony_ci/* Returns how many bytes TTM can move per IB.
4828c2ecf20Sopenharmony_ci */
4838c2ecf20Sopenharmony_cistatic u64 radeon_bo_get_threshold_for_moves(struct radeon_device *rdev)
4848c2ecf20Sopenharmony_ci{
4858c2ecf20Sopenharmony_ci	u64 real_vram_size = rdev->mc.real_vram_size;
4868c2ecf20Sopenharmony_ci	u64 vram_usage = atomic64_read(&rdev->vram_usage);
4878c2ecf20Sopenharmony_ci
4888c2ecf20Sopenharmony_ci	/* This function is based on the current VRAM usage.
4898c2ecf20Sopenharmony_ci	 *
4908c2ecf20Sopenharmony_ci	 * - If all of VRAM is free, allow relocating the number of bytes that
4918c2ecf20Sopenharmony_ci	 *   is equal to 1/4 of the size of VRAM for this IB.
4928c2ecf20Sopenharmony_ci
4938c2ecf20Sopenharmony_ci	 * - If more than one half of VRAM is occupied, only allow relocating
4948c2ecf20Sopenharmony_ci	 *   1 MB of data for this IB.
4958c2ecf20Sopenharmony_ci	 *
4968c2ecf20Sopenharmony_ci	 * - From 0 to one half of used VRAM, the threshold decreases
4978c2ecf20Sopenharmony_ci	 *   linearly.
4988c2ecf20Sopenharmony_ci	 *         __________________
4998c2ecf20Sopenharmony_ci	 * 1/4 of -|\               |
5008c2ecf20Sopenharmony_ci	 * VRAM    | \              |
5018c2ecf20Sopenharmony_ci	 *         |  \             |
5028c2ecf20Sopenharmony_ci	 *         |   \            |
5038c2ecf20Sopenharmony_ci	 *         |    \           |
5048c2ecf20Sopenharmony_ci	 *         |     \          |
5058c2ecf20Sopenharmony_ci	 *         |      \         |
5068c2ecf20Sopenharmony_ci	 *         |       \________|1 MB
5078c2ecf20Sopenharmony_ci	 *         |----------------|
5088c2ecf20Sopenharmony_ci	 *    VRAM 0 %             100 %
5098c2ecf20Sopenharmony_ci	 *         used            used
5108c2ecf20Sopenharmony_ci	 *
5118c2ecf20Sopenharmony_ci	 * Note: It's a threshold, not a limit. The threshold must be crossed
5128c2ecf20Sopenharmony_ci	 * for buffer relocations to stop, so any buffer of an arbitrary size
5138c2ecf20Sopenharmony_ci	 * can be moved as long as the threshold isn't crossed before
5148c2ecf20Sopenharmony_ci	 * the relocation takes place. We don't want to disable buffer
5158c2ecf20Sopenharmony_ci	 * relocations completely.
5168c2ecf20Sopenharmony_ci	 *
5178c2ecf20Sopenharmony_ci	 * The idea is that buffers should be placed in VRAM at creation time
5188c2ecf20Sopenharmony_ci	 * and TTM should only do a minimum number of relocations during
5198c2ecf20Sopenharmony_ci	 * command submission. In practice, you need to submit at least
5208c2ecf20Sopenharmony_ci	 * a dozen IBs to move all buffers to VRAM if they are in GTT.
5218c2ecf20Sopenharmony_ci	 *
5228c2ecf20Sopenharmony_ci	 * Also, things can get pretty crazy under memory pressure and actual
5238c2ecf20Sopenharmony_ci	 * VRAM usage can change a lot, so playing safe even at 50% does
5248c2ecf20Sopenharmony_ci	 * consistently increase performance.
5258c2ecf20Sopenharmony_ci	 */
5268c2ecf20Sopenharmony_ci
5278c2ecf20Sopenharmony_ci	u64 half_vram = real_vram_size >> 1;
5288c2ecf20Sopenharmony_ci	u64 half_free_vram = vram_usage >= half_vram ? 0 : half_vram - vram_usage;
5298c2ecf20Sopenharmony_ci	u64 bytes_moved_threshold = half_free_vram >> 1;
5308c2ecf20Sopenharmony_ci	return max(bytes_moved_threshold, 1024*1024ull);
5318c2ecf20Sopenharmony_ci}
5328c2ecf20Sopenharmony_ci
5338c2ecf20Sopenharmony_ciint radeon_bo_list_validate(struct radeon_device *rdev,
5348c2ecf20Sopenharmony_ci			    struct ww_acquire_ctx *ticket,
5358c2ecf20Sopenharmony_ci			    struct list_head *head, int ring)
5368c2ecf20Sopenharmony_ci{
5378c2ecf20Sopenharmony_ci	struct ttm_operation_ctx ctx = { true, false };
5388c2ecf20Sopenharmony_ci	struct radeon_bo_list *lobj;
5398c2ecf20Sopenharmony_ci	struct list_head duplicates;
5408c2ecf20Sopenharmony_ci	int r;
5418c2ecf20Sopenharmony_ci	u64 bytes_moved = 0, initial_bytes_moved;
5428c2ecf20Sopenharmony_ci	u64 bytes_moved_threshold = radeon_bo_get_threshold_for_moves(rdev);
5438c2ecf20Sopenharmony_ci
5448c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&duplicates);
5458c2ecf20Sopenharmony_ci	r = ttm_eu_reserve_buffers(ticket, head, true, &duplicates);
5468c2ecf20Sopenharmony_ci	if (unlikely(r != 0)) {
5478c2ecf20Sopenharmony_ci		return r;
5488c2ecf20Sopenharmony_ci	}
5498c2ecf20Sopenharmony_ci
5508c2ecf20Sopenharmony_ci	list_for_each_entry(lobj, head, tv.head) {
5518c2ecf20Sopenharmony_ci		struct radeon_bo *bo = lobj->robj;
5528c2ecf20Sopenharmony_ci		if (!bo->pin_count) {
5538c2ecf20Sopenharmony_ci			u32 domain = lobj->preferred_domains;
5548c2ecf20Sopenharmony_ci			u32 allowed = lobj->allowed_domains;
5558c2ecf20Sopenharmony_ci			u32 current_domain =
5568c2ecf20Sopenharmony_ci				radeon_mem_type_to_domain(bo->tbo.mem.mem_type);
5578c2ecf20Sopenharmony_ci
5588c2ecf20Sopenharmony_ci			/* Check if this buffer will be moved and don't move it
5598c2ecf20Sopenharmony_ci			 * if we have moved too many buffers for this IB already.
5608c2ecf20Sopenharmony_ci			 *
5618c2ecf20Sopenharmony_ci			 * Note that this allows moving at least one buffer of
5628c2ecf20Sopenharmony_ci			 * any size, because it doesn't take the current "bo"
5638c2ecf20Sopenharmony_ci			 * into account. We don't want to disallow buffer moves
5648c2ecf20Sopenharmony_ci			 * completely.
5658c2ecf20Sopenharmony_ci			 */
5668c2ecf20Sopenharmony_ci			if ((allowed & current_domain) != 0 &&
5678c2ecf20Sopenharmony_ci			    (domain & current_domain) == 0 && /* will be moved */
5688c2ecf20Sopenharmony_ci			    bytes_moved > bytes_moved_threshold) {
5698c2ecf20Sopenharmony_ci				/* don't move it */
5708c2ecf20Sopenharmony_ci				domain = current_domain;
5718c2ecf20Sopenharmony_ci			}
5728c2ecf20Sopenharmony_ci
5738c2ecf20Sopenharmony_ci		retry:
5748c2ecf20Sopenharmony_ci			radeon_ttm_placement_from_domain(bo, domain);
5758c2ecf20Sopenharmony_ci			if (ring == R600_RING_TYPE_UVD_INDEX)
5768c2ecf20Sopenharmony_ci				radeon_uvd_force_into_uvd_segment(bo, allowed);
5778c2ecf20Sopenharmony_ci
5788c2ecf20Sopenharmony_ci			initial_bytes_moved = atomic64_read(&rdev->num_bytes_moved);
5798c2ecf20Sopenharmony_ci			r = ttm_bo_validate(&bo->tbo, &bo->placement, &ctx);
5808c2ecf20Sopenharmony_ci			bytes_moved += atomic64_read(&rdev->num_bytes_moved) -
5818c2ecf20Sopenharmony_ci				       initial_bytes_moved;
5828c2ecf20Sopenharmony_ci
5838c2ecf20Sopenharmony_ci			if (unlikely(r)) {
5848c2ecf20Sopenharmony_ci				if (r != -ERESTARTSYS &&
5858c2ecf20Sopenharmony_ci				    domain != lobj->allowed_domains) {
5868c2ecf20Sopenharmony_ci					domain = lobj->allowed_domains;
5878c2ecf20Sopenharmony_ci					goto retry;
5888c2ecf20Sopenharmony_ci				}
5898c2ecf20Sopenharmony_ci				ttm_eu_backoff_reservation(ticket, head);
5908c2ecf20Sopenharmony_ci				return r;
5918c2ecf20Sopenharmony_ci			}
5928c2ecf20Sopenharmony_ci		}
5938c2ecf20Sopenharmony_ci		lobj->gpu_offset = radeon_bo_gpu_offset(bo);
5948c2ecf20Sopenharmony_ci		lobj->tiling_flags = bo->tiling_flags;
5958c2ecf20Sopenharmony_ci	}
5968c2ecf20Sopenharmony_ci
5978c2ecf20Sopenharmony_ci	list_for_each_entry(lobj, &duplicates, tv.head) {
5988c2ecf20Sopenharmony_ci		lobj->gpu_offset = radeon_bo_gpu_offset(lobj->robj);
5998c2ecf20Sopenharmony_ci		lobj->tiling_flags = lobj->robj->tiling_flags;
6008c2ecf20Sopenharmony_ci	}
6018c2ecf20Sopenharmony_ci
6028c2ecf20Sopenharmony_ci	return 0;
6038c2ecf20Sopenharmony_ci}
6048c2ecf20Sopenharmony_ci
6058c2ecf20Sopenharmony_ciint radeon_bo_get_surface_reg(struct radeon_bo *bo)
6068c2ecf20Sopenharmony_ci{
6078c2ecf20Sopenharmony_ci	struct radeon_device *rdev = bo->rdev;
6088c2ecf20Sopenharmony_ci	struct radeon_surface_reg *reg;
6098c2ecf20Sopenharmony_ci	struct radeon_bo *old_object;
6108c2ecf20Sopenharmony_ci	int steal;
6118c2ecf20Sopenharmony_ci	int i;
6128c2ecf20Sopenharmony_ci
6138c2ecf20Sopenharmony_ci	dma_resv_assert_held(bo->tbo.base.resv);
6148c2ecf20Sopenharmony_ci
6158c2ecf20Sopenharmony_ci	if (!bo->tiling_flags)
6168c2ecf20Sopenharmony_ci		return 0;
6178c2ecf20Sopenharmony_ci
6188c2ecf20Sopenharmony_ci	if (bo->surface_reg >= 0) {
6198c2ecf20Sopenharmony_ci		reg = &rdev->surface_regs[bo->surface_reg];
6208c2ecf20Sopenharmony_ci		i = bo->surface_reg;
6218c2ecf20Sopenharmony_ci		goto out;
6228c2ecf20Sopenharmony_ci	}
6238c2ecf20Sopenharmony_ci
6248c2ecf20Sopenharmony_ci	steal = -1;
6258c2ecf20Sopenharmony_ci	for (i = 0; i < RADEON_GEM_MAX_SURFACES; i++) {
6268c2ecf20Sopenharmony_ci
6278c2ecf20Sopenharmony_ci		reg = &rdev->surface_regs[i];
6288c2ecf20Sopenharmony_ci		if (!reg->bo)
6298c2ecf20Sopenharmony_ci			break;
6308c2ecf20Sopenharmony_ci
6318c2ecf20Sopenharmony_ci		old_object = reg->bo;
6328c2ecf20Sopenharmony_ci		if (old_object->pin_count == 0)
6338c2ecf20Sopenharmony_ci			steal = i;
6348c2ecf20Sopenharmony_ci	}
6358c2ecf20Sopenharmony_ci
6368c2ecf20Sopenharmony_ci	/* if we are all out */
6378c2ecf20Sopenharmony_ci	if (i == RADEON_GEM_MAX_SURFACES) {
6388c2ecf20Sopenharmony_ci		if (steal == -1)
6398c2ecf20Sopenharmony_ci			return -ENOMEM;
6408c2ecf20Sopenharmony_ci		/* find someone with a surface reg and nuke their BO */
6418c2ecf20Sopenharmony_ci		reg = &rdev->surface_regs[steal];
6428c2ecf20Sopenharmony_ci		old_object = reg->bo;
6438c2ecf20Sopenharmony_ci		/* blow away the mapping */
6448c2ecf20Sopenharmony_ci		DRM_DEBUG("stealing surface reg %d from %p\n", steal, old_object);
6458c2ecf20Sopenharmony_ci		ttm_bo_unmap_virtual(&old_object->tbo);
6468c2ecf20Sopenharmony_ci		old_object->surface_reg = -1;
6478c2ecf20Sopenharmony_ci		i = steal;
6488c2ecf20Sopenharmony_ci	}
6498c2ecf20Sopenharmony_ci
6508c2ecf20Sopenharmony_ci	bo->surface_reg = i;
6518c2ecf20Sopenharmony_ci	reg->bo = bo;
6528c2ecf20Sopenharmony_ci
6538c2ecf20Sopenharmony_ciout:
6548c2ecf20Sopenharmony_ci	radeon_set_surface_reg(rdev, i, bo->tiling_flags, bo->pitch,
6558c2ecf20Sopenharmony_ci			       bo->tbo.mem.start << PAGE_SHIFT,
6568c2ecf20Sopenharmony_ci			       bo->tbo.num_pages << PAGE_SHIFT);
6578c2ecf20Sopenharmony_ci	return 0;
6588c2ecf20Sopenharmony_ci}
6598c2ecf20Sopenharmony_ci
6608c2ecf20Sopenharmony_cistatic void radeon_bo_clear_surface_reg(struct radeon_bo *bo)
6618c2ecf20Sopenharmony_ci{
6628c2ecf20Sopenharmony_ci	struct radeon_device *rdev = bo->rdev;
6638c2ecf20Sopenharmony_ci	struct radeon_surface_reg *reg;
6648c2ecf20Sopenharmony_ci
6658c2ecf20Sopenharmony_ci	if (bo->surface_reg == -1)
6668c2ecf20Sopenharmony_ci		return;
6678c2ecf20Sopenharmony_ci
6688c2ecf20Sopenharmony_ci	reg = &rdev->surface_regs[bo->surface_reg];
6698c2ecf20Sopenharmony_ci	radeon_clear_surface_reg(rdev, bo->surface_reg);
6708c2ecf20Sopenharmony_ci
6718c2ecf20Sopenharmony_ci	reg->bo = NULL;
6728c2ecf20Sopenharmony_ci	bo->surface_reg = -1;
6738c2ecf20Sopenharmony_ci}
6748c2ecf20Sopenharmony_ci
6758c2ecf20Sopenharmony_ciint radeon_bo_set_tiling_flags(struct radeon_bo *bo,
6768c2ecf20Sopenharmony_ci				uint32_t tiling_flags, uint32_t pitch)
6778c2ecf20Sopenharmony_ci{
6788c2ecf20Sopenharmony_ci	struct radeon_device *rdev = bo->rdev;
6798c2ecf20Sopenharmony_ci	int r;
6808c2ecf20Sopenharmony_ci
6818c2ecf20Sopenharmony_ci	if (rdev->family >= CHIP_CEDAR) {
6828c2ecf20Sopenharmony_ci		unsigned bankw, bankh, mtaspect, tilesplit, stilesplit;
6838c2ecf20Sopenharmony_ci
6848c2ecf20Sopenharmony_ci		bankw = (tiling_flags >> RADEON_TILING_EG_BANKW_SHIFT) & RADEON_TILING_EG_BANKW_MASK;
6858c2ecf20Sopenharmony_ci		bankh = (tiling_flags >> RADEON_TILING_EG_BANKH_SHIFT) & RADEON_TILING_EG_BANKH_MASK;
6868c2ecf20Sopenharmony_ci		mtaspect = (tiling_flags >> RADEON_TILING_EG_MACRO_TILE_ASPECT_SHIFT) & RADEON_TILING_EG_MACRO_TILE_ASPECT_MASK;
6878c2ecf20Sopenharmony_ci		tilesplit = (tiling_flags >> RADEON_TILING_EG_TILE_SPLIT_SHIFT) & RADEON_TILING_EG_TILE_SPLIT_MASK;
6888c2ecf20Sopenharmony_ci		stilesplit = (tiling_flags >> RADEON_TILING_EG_STENCIL_TILE_SPLIT_SHIFT) & RADEON_TILING_EG_STENCIL_TILE_SPLIT_MASK;
6898c2ecf20Sopenharmony_ci		switch (bankw) {
6908c2ecf20Sopenharmony_ci		case 0:
6918c2ecf20Sopenharmony_ci		case 1:
6928c2ecf20Sopenharmony_ci		case 2:
6938c2ecf20Sopenharmony_ci		case 4:
6948c2ecf20Sopenharmony_ci		case 8:
6958c2ecf20Sopenharmony_ci			break;
6968c2ecf20Sopenharmony_ci		default:
6978c2ecf20Sopenharmony_ci			return -EINVAL;
6988c2ecf20Sopenharmony_ci		}
6998c2ecf20Sopenharmony_ci		switch (bankh) {
7008c2ecf20Sopenharmony_ci		case 0:
7018c2ecf20Sopenharmony_ci		case 1:
7028c2ecf20Sopenharmony_ci		case 2:
7038c2ecf20Sopenharmony_ci		case 4:
7048c2ecf20Sopenharmony_ci		case 8:
7058c2ecf20Sopenharmony_ci			break;
7068c2ecf20Sopenharmony_ci		default:
7078c2ecf20Sopenharmony_ci			return -EINVAL;
7088c2ecf20Sopenharmony_ci		}
7098c2ecf20Sopenharmony_ci		switch (mtaspect) {
7108c2ecf20Sopenharmony_ci		case 0:
7118c2ecf20Sopenharmony_ci		case 1:
7128c2ecf20Sopenharmony_ci		case 2:
7138c2ecf20Sopenharmony_ci		case 4:
7148c2ecf20Sopenharmony_ci		case 8:
7158c2ecf20Sopenharmony_ci			break;
7168c2ecf20Sopenharmony_ci		default:
7178c2ecf20Sopenharmony_ci			return -EINVAL;
7188c2ecf20Sopenharmony_ci		}
7198c2ecf20Sopenharmony_ci		if (tilesplit > 6) {
7208c2ecf20Sopenharmony_ci			return -EINVAL;
7218c2ecf20Sopenharmony_ci		}
7228c2ecf20Sopenharmony_ci		if (stilesplit > 6) {
7238c2ecf20Sopenharmony_ci			return -EINVAL;
7248c2ecf20Sopenharmony_ci		}
7258c2ecf20Sopenharmony_ci	}
7268c2ecf20Sopenharmony_ci	r = radeon_bo_reserve(bo, false);
7278c2ecf20Sopenharmony_ci	if (unlikely(r != 0))
7288c2ecf20Sopenharmony_ci		return r;
7298c2ecf20Sopenharmony_ci	bo->tiling_flags = tiling_flags;
7308c2ecf20Sopenharmony_ci	bo->pitch = pitch;
7318c2ecf20Sopenharmony_ci	radeon_bo_unreserve(bo);
7328c2ecf20Sopenharmony_ci	return 0;
7338c2ecf20Sopenharmony_ci}
7348c2ecf20Sopenharmony_ci
7358c2ecf20Sopenharmony_civoid radeon_bo_get_tiling_flags(struct radeon_bo *bo,
7368c2ecf20Sopenharmony_ci				uint32_t *tiling_flags,
7378c2ecf20Sopenharmony_ci				uint32_t *pitch)
7388c2ecf20Sopenharmony_ci{
7398c2ecf20Sopenharmony_ci	dma_resv_assert_held(bo->tbo.base.resv);
7408c2ecf20Sopenharmony_ci
7418c2ecf20Sopenharmony_ci	if (tiling_flags)
7428c2ecf20Sopenharmony_ci		*tiling_flags = bo->tiling_flags;
7438c2ecf20Sopenharmony_ci	if (pitch)
7448c2ecf20Sopenharmony_ci		*pitch = bo->pitch;
7458c2ecf20Sopenharmony_ci}
7468c2ecf20Sopenharmony_ci
7478c2ecf20Sopenharmony_ciint radeon_bo_check_tiling(struct radeon_bo *bo, bool has_moved,
7488c2ecf20Sopenharmony_ci				bool force_drop)
7498c2ecf20Sopenharmony_ci{
7508c2ecf20Sopenharmony_ci	if (!force_drop)
7518c2ecf20Sopenharmony_ci		dma_resv_assert_held(bo->tbo.base.resv);
7528c2ecf20Sopenharmony_ci
7538c2ecf20Sopenharmony_ci	if (!(bo->tiling_flags & RADEON_TILING_SURFACE))
7548c2ecf20Sopenharmony_ci		return 0;
7558c2ecf20Sopenharmony_ci
7568c2ecf20Sopenharmony_ci	if (force_drop) {
7578c2ecf20Sopenharmony_ci		radeon_bo_clear_surface_reg(bo);
7588c2ecf20Sopenharmony_ci		return 0;
7598c2ecf20Sopenharmony_ci	}
7608c2ecf20Sopenharmony_ci
7618c2ecf20Sopenharmony_ci	if (bo->tbo.mem.mem_type != TTM_PL_VRAM) {
7628c2ecf20Sopenharmony_ci		if (!has_moved)
7638c2ecf20Sopenharmony_ci			return 0;
7648c2ecf20Sopenharmony_ci
7658c2ecf20Sopenharmony_ci		if (bo->surface_reg >= 0)
7668c2ecf20Sopenharmony_ci			radeon_bo_clear_surface_reg(bo);
7678c2ecf20Sopenharmony_ci		return 0;
7688c2ecf20Sopenharmony_ci	}
7698c2ecf20Sopenharmony_ci
7708c2ecf20Sopenharmony_ci	if ((bo->surface_reg >= 0) && !has_moved)
7718c2ecf20Sopenharmony_ci		return 0;
7728c2ecf20Sopenharmony_ci
7738c2ecf20Sopenharmony_ci	return radeon_bo_get_surface_reg(bo);
7748c2ecf20Sopenharmony_ci}
7758c2ecf20Sopenharmony_ci
7768c2ecf20Sopenharmony_civoid radeon_bo_move_notify(struct ttm_buffer_object *bo,
7778c2ecf20Sopenharmony_ci			   bool evict,
7788c2ecf20Sopenharmony_ci			   struct ttm_resource *new_mem)
7798c2ecf20Sopenharmony_ci{
7808c2ecf20Sopenharmony_ci	struct radeon_bo *rbo;
7818c2ecf20Sopenharmony_ci
7828c2ecf20Sopenharmony_ci	if (!radeon_ttm_bo_is_radeon_bo(bo))
7838c2ecf20Sopenharmony_ci		return;
7848c2ecf20Sopenharmony_ci
7858c2ecf20Sopenharmony_ci	rbo = container_of(bo, struct radeon_bo, tbo);
7868c2ecf20Sopenharmony_ci	radeon_bo_check_tiling(rbo, 0, 1);
7878c2ecf20Sopenharmony_ci	radeon_vm_bo_invalidate(rbo->rdev, rbo);
7888c2ecf20Sopenharmony_ci
7898c2ecf20Sopenharmony_ci	/* update statistics */
7908c2ecf20Sopenharmony_ci	if (!new_mem)
7918c2ecf20Sopenharmony_ci		return;
7928c2ecf20Sopenharmony_ci
7938c2ecf20Sopenharmony_ci	radeon_update_memory_usage(rbo, bo->mem.mem_type, -1);
7948c2ecf20Sopenharmony_ci	radeon_update_memory_usage(rbo, new_mem->mem_type, 1);
7958c2ecf20Sopenharmony_ci}
7968c2ecf20Sopenharmony_ci
7978c2ecf20Sopenharmony_ciint radeon_bo_fault_reserve_notify(struct ttm_buffer_object *bo)
7988c2ecf20Sopenharmony_ci{
7998c2ecf20Sopenharmony_ci	struct ttm_operation_ctx ctx = { false, false };
8008c2ecf20Sopenharmony_ci	struct radeon_device *rdev;
8018c2ecf20Sopenharmony_ci	struct radeon_bo *rbo;
8028c2ecf20Sopenharmony_ci	unsigned long offset, size, lpfn;
8038c2ecf20Sopenharmony_ci	int i, r;
8048c2ecf20Sopenharmony_ci
8058c2ecf20Sopenharmony_ci	if (!radeon_ttm_bo_is_radeon_bo(bo))
8068c2ecf20Sopenharmony_ci		return 0;
8078c2ecf20Sopenharmony_ci	rbo = container_of(bo, struct radeon_bo, tbo);
8088c2ecf20Sopenharmony_ci	radeon_bo_check_tiling(rbo, 0, 0);
8098c2ecf20Sopenharmony_ci	rdev = rbo->rdev;
8108c2ecf20Sopenharmony_ci	if (bo->mem.mem_type != TTM_PL_VRAM)
8118c2ecf20Sopenharmony_ci		return 0;
8128c2ecf20Sopenharmony_ci
8138c2ecf20Sopenharmony_ci	size = bo->mem.num_pages << PAGE_SHIFT;
8148c2ecf20Sopenharmony_ci	offset = bo->mem.start << PAGE_SHIFT;
8158c2ecf20Sopenharmony_ci	if ((offset + size) <= rdev->mc.visible_vram_size)
8168c2ecf20Sopenharmony_ci		return 0;
8178c2ecf20Sopenharmony_ci
8188c2ecf20Sopenharmony_ci	/* Can't move a pinned BO to visible VRAM */
8198c2ecf20Sopenharmony_ci	if (rbo->pin_count > 0)
8208c2ecf20Sopenharmony_ci		return -EINVAL;
8218c2ecf20Sopenharmony_ci
8228c2ecf20Sopenharmony_ci	/* hurrah the memory is not visible ! */
8238c2ecf20Sopenharmony_ci	radeon_ttm_placement_from_domain(rbo, RADEON_GEM_DOMAIN_VRAM);
8248c2ecf20Sopenharmony_ci	lpfn =	rdev->mc.visible_vram_size >> PAGE_SHIFT;
8258c2ecf20Sopenharmony_ci	for (i = 0; i < rbo->placement.num_placement; i++) {
8268c2ecf20Sopenharmony_ci		/* Force into visible VRAM */
8278c2ecf20Sopenharmony_ci		if ((rbo->placements[i].mem_type == TTM_PL_VRAM) &&
8288c2ecf20Sopenharmony_ci		    (!rbo->placements[i].lpfn || rbo->placements[i].lpfn > lpfn))
8298c2ecf20Sopenharmony_ci			rbo->placements[i].lpfn = lpfn;
8308c2ecf20Sopenharmony_ci	}
8318c2ecf20Sopenharmony_ci	r = ttm_bo_validate(bo, &rbo->placement, &ctx);
8328c2ecf20Sopenharmony_ci	if (unlikely(r == -ENOMEM)) {
8338c2ecf20Sopenharmony_ci		radeon_ttm_placement_from_domain(rbo, RADEON_GEM_DOMAIN_GTT);
8348c2ecf20Sopenharmony_ci		return ttm_bo_validate(bo, &rbo->placement, &ctx);
8358c2ecf20Sopenharmony_ci	} else if (unlikely(r != 0)) {
8368c2ecf20Sopenharmony_ci		return r;
8378c2ecf20Sopenharmony_ci	}
8388c2ecf20Sopenharmony_ci
8398c2ecf20Sopenharmony_ci	offset = bo->mem.start << PAGE_SHIFT;
8408c2ecf20Sopenharmony_ci	/* this should never happen */
8418c2ecf20Sopenharmony_ci	if ((offset + size) > rdev->mc.visible_vram_size)
8428c2ecf20Sopenharmony_ci		return -EINVAL;
8438c2ecf20Sopenharmony_ci
8448c2ecf20Sopenharmony_ci	return 0;
8458c2ecf20Sopenharmony_ci}
8468c2ecf20Sopenharmony_ci
8478c2ecf20Sopenharmony_ciint radeon_bo_wait(struct radeon_bo *bo, u32 *mem_type, bool no_wait)
8488c2ecf20Sopenharmony_ci{
8498c2ecf20Sopenharmony_ci	int r;
8508c2ecf20Sopenharmony_ci
8518c2ecf20Sopenharmony_ci	r = ttm_bo_reserve(&bo->tbo, true, no_wait, NULL);
8528c2ecf20Sopenharmony_ci	if (unlikely(r != 0))
8538c2ecf20Sopenharmony_ci		return r;
8548c2ecf20Sopenharmony_ci	if (mem_type)
8558c2ecf20Sopenharmony_ci		*mem_type = bo->tbo.mem.mem_type;
8568c2ecf20Sopenharmony_ci
8578c2ecf20Sopenharmony_ci	r = ttm_bo_wait(&bo->tbo, true, no_wait);
8588c2ecf20Sopenharmony_ci	ttm_bo_unreserve(&bo->tbo);
8598c2ecf20Sopenharmony_ci	return r;
8608c2ecf20Sopenharmony_ci}
8618c2ecf20Sopenharmony_ci
8628c2ecf20Sopenharmony_ci/**
8638c2ecf20Sopenharmony_ci * radeon_bo_fence - add fence to buffer object
8648c2ecf20Sopenharmony_ci *
8658c2ecf20Sopenharmony_ci * @bo: buffer object in question
8668c2ecf20Sopenharmony_ci * @fence: fence to add
8678c2ecf20Sopenharmony_ci * @shared: true if fence should be added shared
8688c2ecf20Sopenharmony_ci *
8698c2ecf20Sopenharmony_ci */
8708c2ecf20Sopenharmony_civoid radeon_bo_fence(struct radeon_bo *bo, struct radeon_fence *fence,
8718c2ecf20Sopenharmony_ci		     bool shared)
8728c2ecf20Sopenharmony_ci{
8738c2ecf20Sopenharmony_ci	struct dma_resv *resv = bo->tbo.base.resv;
8748c2ecf20Sopenharmony_ci
8758c2ecf20Sopenharmony_ci	if (shared)
8768c2ecf20Sopenharmony_ci		dma_resv_add_shared_fence(resv, &fence->base);
8778c2ecf20Sopenharmony_ci	else
8788c2ecf20Sopenharmony_ci		dma_resv_add_excl_fence(resv, &fence->base);
8798c2ecf20Sopenharmony_ci}
880