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/dma-mapping.h>
348c2ecf20Sopenharmony_ci#include <linux/pagemap.h>
358c2ecf20Sopenharmony_ci#include <linux/pci.h>
368c2ecf20Sopenharmony_ci#include <linux/seq_file.h>
378c2ecf20Sopenharmony_ci#include <linux/slab.h>
388c2ecf20Sopenharmony_ci#include <linux/swap.h>
398c2ecf20Sopenharmony_ci#include <linux/swiotlb.h>
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci#include <drm/drm_agpsupport.h>
428c2ecf20Sopenharmony_ci#include <drm/drm_debugfs.h>
438c2ecf20Sopenharmony_ci#include <drm/drm_device.h>
448c2ecf20Sopenharmony_ci#include <drm/drm_file.h>
458c2ecf20Sopenharmony_ci#include <drm/drm_prime.h>
468c2ecf20Sopenharmony_ci#include <drm/radeon_drm.h>
478c2ecf20Sopenharmony_ci#include <drm/ttm/ttm_bo_api.h>
488c2ecf20Sopenharmony_ci#include <drm/ttm/ttm_bo_driver.h>
498c2ecf20Sopenharmony_ci#include <drm/ttm/ttm_module.h>
508c2ecf20Sopenharmony_ci#include <drm/ttm/ttm_page_alloc.h>
518c2ecf20Sopenharmony_ci#include <drm/ttm/ttm_placement.h>
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci#include "radeon_reg.h"
548c2ecf20Sopenharmony_ci#include "radeon.h"
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_cistatic int radeon_ttm_debugfs_init(struct radeon_device *rdev);
578c2ecf20Sopenharmony_cistatic void radeon_ttm_debugfs_fini(struct radeon_device *rdev);
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_cistatic int radeon_ttm_tt_bind(struct ttm_bo_device *bdev,
608c2ecf20Sopenharmony_ci			      struct ttm_tt *ttm,
618c2ecf20Sopenharmony_ci			      struct ttm_resource *bo_mem);
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_cistruct radeon_device *radeon_get_rdev(struct ttm_bo_device *bdev)
648c2ecf20Sopenharmony_ci{
658c2ecf20Sopenharmony_ci	struct radeon_mman *mman;
668c2ecf20Sopenharmony_ci	struct radeon_device *rdev;
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci	mman = container_of(bdev, struct radeon_mman, bdev);
698c2ecf20Sopenharmony_ci	rdev = container_of(mman, struct radeon_device, mman);
708c2ecf20Sopenharmony_ci	return rdev;
718c2ecf20Sopenharmony_ci}
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_cistatic int radeon_ttm_init_vram(struct radeon_device *rdev)
748c2ecf20Sopenharmony_ci{
758c2ecf20Sopenharmony_ci	return ttm_range_man_init(&rdev->mman.bdev, TTM_PL_VRAM,
768c2ecf20Sopenharmony_ci				  false, rdev->mc.real_vram_size >> PAGE_SHIFT);
778c2ecf20Sopenharmony_ci}
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_cistatic int radeon_ttm_init_gtt(struct radeon_device *rdev)
808c2ecf20Sopenharmony_ci{
818c2ecf20Sopenharmony_ci	return ttm_range_man_init(&rdev->mman.bdev, TTM_PL_TT,
828c2ecf20Sopenharmony_ci				  true, rdev->mc.gtt_size >> PAGE_SHIFT);
838c2ecf20Sopenharmony_ci}
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_cistatic void radeon_evict_flags(struct ttm_buffer_object *bo,
868c2ecf20Sopenharmony_ci				struct ttm_placement *placement)
878c2ecf20Sopenharmony_ci{
888c2ecf20Sopenharmony_ci	static const struct ttm_place placements = {
898c2ecf20Sopenharmony_ci		.fpfn = 0,
908c2ecf20Sopenharmony_ci		.lpfn = 0,
918c2ecf20Sopenharmony_ci		.mem_type = TTM_PL_SYSTEM,
928c2ecf20Sopenharmony_ci		.flags = TTM_PL_MASK_CACHING
938c2ecf20Sopenharmony_ci	};
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci	struct radeon_bo *rbo;
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci	if (!radeon_ttm_bo_is_radeon_bo(bo)) {
988c2ecf20Sopenharmony_ci		placement->placement = &placements;
998c2ecf20Sopenharmony_ci		placement->busy_placement = &placements;
1008c2ecf20Sopenharmony_ci		placement->num_placement = 1;
1018c2ecf20Sopenharmony_ci		placement->num_busy_placement = 1;
1028c2ecf20Sopenharmony_ci		return;
1038c2ecf20Sopenharmony_ci	}
1048c2ecf20Sopenharmony_ci	rbo = container_of(bo, struct radeon_bo, tbo);
1058c2ecf20Sopenharmony_ci	switch (bo->mem.mem_type) {
1068c2ecf20Sopenharmony_ci	case TTM_PL_VRAM:
1078c2ecf20Sopenharmony_ci		if (rbo->rdev->ring[radeon_copy_ring_index(rbo->rdev)].ready == false)
1088c2ecf20Sopenharmony_ci			radeon_ttm_placement_from_domain(rbo, RADEON_GEM_DOMAIN_CPU);
1098c2ecf20Sopenharmony_ci		else if (rbo->rdev->mc.visible_vram_size < rbo->rdev->mc.real_vram_size &&
1108c2ecf20Sopenharmony_ci			 bo->mem.start < (rbo->rdev->mc.visible_vram_size >> PAGE_SHIFT)) {
1118c2ecf20Sopenharmony_ci			unsigned fpfn = rbo->rdev->mc.visible_vram_size >> PAGE_SHIFT;
1128c2ecf20Sopenharmony_ci			int i;
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci			/* Try evicting to the CPU inaccessible part of VRAM
1158c2ecf20Sopenharmony_ci			 * first, but only set GTT as busy placement, so this
1168c2ecf20Sopenharmony_ci			 * BO will be evicted to GTT rather than causing other
1178c2ecf20Sopenharmony_ci			 * BOs to be evicted from VRAM
1188c2ecf20Sopenharmony_ci			 */
1198c2ecf20Sopenharmony_ci			radeon_ttm_placement_from_domain(rbo, RADEON_GEM_DOMAIN_VRAM |
1208c2ecf20Sopenharmony_ci							 RADEON_GEM_DOMAIN_GTT);
1218c2ecf20Sopenharmony_ci			rbo->placement.num_busy_placement = 0;
1228c2ecf20Sopenharmony_ci			for (i = 0; i < rbo->placement.num_placement; i++) {
1238c2ecf20Sopenharmony_ci				if (rbo->placements[i].mem_type == TTM_PL_VRAM) {
1248c2ecf20Sopenharmony_ci					if (rbo->placements[i].fpfn < fpfn)
1258c2ecf20Sopenharmony_ci						rbo->placements[i].fpfn = fpfn;
1268c2ecf20Sopenharmony_ci				} else {
1278c2ecf20Sopenharmony_ci					rbo->placement.busy_placement =
1288c2ecf20Sopenharmony_ci						&rbo->placements[i];
1298c2ecf20Sopenharmony_ci					rbo->placement.num_busy_placement = 1;
1308c2ecf20Sopenharmony_ci				}
1318c2ecf20Sopenharmony_ci			}
1328c2ecf20Sopenharmony_ci		} else
1338c2ecf20Sopenharmony_ci			radeon_ttm_placement_from_domain(rbo, RADEON_GEM_DOMAIN_GTT);
1348c2ecf20Sopenharmony_ci		break;
1358c2ecf20Sopenharmony_ci	case TTM_PL_TT:
1368c2ecf20Sopenharmony_ci	default:
1378c2ecf20Sopenharmony_ci		radeon_ttm_placement_from_domain(rbo, RADEON_GEM_DOMAIN_CPU);
1388c2ecf20Sopenharmony_ci	}
1398c2ecf20Sopenharmony_ci	*placement = rbo->placement;
1408c2ecf20Sopenharmony_ci}
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_cistatic int radeon_verify_access(struct ttm_buffer_object *bo, struct file *filp)
1438c2ecf20Sopenharmony_ci{
1448c2ecf20Sopenharmony_ci	struct radeon_bo *rbo = container_of(bo, struct radeon_bo, tbo);
1458c2ecf20Sopenharmony_ci	struct radeon_device *rdev = radeon_get_rdev(bo->bdev);
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ci	if (radeon_ttm_tt_has_userptr(rdev, bo->ttm))
1488c2ecf20Sopenharmony_ci		return -EPERM;
1498c2ecf20Sopenharmony_ci	return drm_vma_node_verify_access(&rbo->tbo.base.vma_node,
1508c2ecf20Sopenharmony_ci					  filp->private_data);
1518c2ecf20Sopenharmony_ci}
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_cistatic int radeon_move_blit(struct ttm_buffer_object *bo,
1548c2ecf20Sopenharmony_ci			bool evict, bool no_wait_gpu,
1558c2ecf20Sopenharmony_ci			struct ttm_resource *new_mem,
1568c2ecf20Sopenharmony_ci			struct ttm_resource *old_mem)
1578c2ecf20Sopenharmony_ci{
1588c2ecf20Sopenharmony_ci	struct radeon_device *rdev;
1598c2ecf20Sopenharmony_ci	uint64_t old_start, new_start;
1608c2ecf20Sopenharmony_ci	struct radeon_fence *fence;
1618c2ecf20Sopenharmony_ci	unsigned num_pages;
1628c2ecf20Sopenharmony_ci	int r, ridx;
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_ci	rdev = radeon_get_rdev(bo->bdev);
1658c2ecf20Sopenharmony_ci	ridx = radeon_copy_ring_index(rdev);
1668c2ecf20Sopenharmony_ci	old_start = (u64)old_mem->start << PAGE_SHIFT;
1678c2ecf20Sopenharmony_ci	new_start = (u64)new_mem->start << PAGE_SHIFT;
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci	switch (old_mem->mem_type) {
1708c2ecf20Sopenharmony_ci	case TTM_PL_VRAM:
1718c2ecf20Sopenharmony_ci		old_start += rdev->mc.vram_start;
1728c2ecf20Sopenharmony_ci		break;
1738c2ecf20Sopenharmony_ci	case TTM_PL_TT:
1748c2ecf20Sopenharmony_ci		old_start += rdev->mc.gtt_start;
1758c2ecf20Sopenharmony_ci		break;
1768c2ecf20Sopenharmony_ci	default:
1778c2ecf20Sopenharmony_ci		DRM_ERROR("Unknown placement %d\n", old_mem->mem_type);
1788c2ecf20Sopenharmony_ci		return -EINVAL;
1798c2ecf20Sopenharmony_ci	}
1808c2ecf20Sopenharmony_ci	switch (new_mem->mem_type) {
1818c2ecf20Sopenharmony_ci	case TTM_PL_VRAM:
1828c2ecf20Sopenharmony_ci		new_start += rdev->mc.vram_start;
1838c2ecf20Sopenharmony_ci		break;
1848c2ecf20Sopenharmony_ci	case TTM_PL_TT:
1858c2ecf20Sopenharmony_ci		new_start += rdev->mc.gtt_start;
1868c2ecf20Sopenharmony_ci		break;
1878c2ecf20Sopenharmony_ci	default:
1888c2ecf20Sopenharmony_ci		DRM_ERROR("Unknown placement %d\n", old_mem->mem_type);
1898c2ecf20Sopenharmony_ci		return -EINVAL;
1908c2ecf20Sopenharmony_ci	}
1918c2ecf20Sopenharmony_ci	if (!rdev->ring[ridx].ready) {
1928c2ecf20Sopenharmony_ci		DRM_ERROR("Trying to move memory with ring turned off.\n");
1938c2ecf20Sopenharmony_ci		return -EINVAL;
1948c2ecf20Sopenharmony_ci	}
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_ci	BUILD_BUG_ON((PAGE_SIZE % RADEON_GPU_PAGE_SIZE) != 0);
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ci	num_pages = new_mem->num_pages * (PAGE_SIZE / RADEON_GPU_PAGE_SIZE);
1998c2ecf20Sopenharmony_ci	fence = radeon_copy(rdev, old_start, new_start, num_pages, bo->base.resv);
2008c2ecf20Sopenharmony_ci	if (IS_ERR(fence))
2018c2ecf20Sopenharmony_ci		return PTR_ERR(fence);
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci	r = ttm_bo_move_accel_cleanup(bo, &fence->base, evict, false, new_mem);
2048c2ecf20Sopenharmony_ci	radeon_fence_unref(&fence);
2058c2ecf20Sopenharmony_ci	return r;
2068c2ecf20Sopenharmony_ci}
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_cistatic int radeon_move_vram_ram(struct ttm_buffer_object *bo,
2098c2ecf20Sopenharmony_ci				bool evict, bool interruptible,
2108c2ecf20Sopenharmony_ci				bool no_wait_gpu,
2118c2ecf20Sopenharmony_ci				struct ttm_resource *new_mem)
2128c2ecf20Sopenharmony_ci{
2138c2ecf20Sopenharmony_ci	struct ttm_operation_ctx ctx = { interruptible, no_wait_gpu };
2148c2ecf20Sopenharmony_ci	struct ttm_resource *old_mem = &bo->mem;
2158c2ecf20Sopenharmony_ci	struct ttm_resource tmp_mem;
2168c2ecf20Sopenharmony_ci	struct ttm_place placements;
2178c2ecf20Sopenharmony_ci	struct ttm_placement placement;
2188c2ecf20Sopenharmony_ci	int r;
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ci	tmp_mem = *new_mem;
2218c2ecf20Sopenharmony_ci	tmp_mem.mm_node = NULL;
2228c2ecf20Sopenharmony_ci	placement.num_placement = 1;
2238c2ecf20Sopenharmony_ci	placement.placement = &placements;
2248c2ecf20Sopenharmony_ci	placement.num_busy_placement = 1;
2258c2ecf20Sopenharmony_ci	placement.busy_placement = &placements;
2268c2ecf20Sopenharmony_ci	placements.fpfn = 0;
2278c2ecf20Sopenharmony_ci	placements.lpfn = 0;
2288c2ecf20Sopenharmony_ci	placements.mem_type = TTM_PL_TT;
2298c2ecf20Sopenharmony_ci	placements.flags = TTM_PL_MASK_CACHING;
2308c2ecf20Sopenharmony_ci	r = ttm_bo_mem_space(bo, &placement, &tmp_mem, &ctx);
2318c2ecf20Sopenharmony_ci	if (unlikely(r)) {
2328c2ecf20Sopenharmony_ci		return r;
2338c2ecf20Sopenharmony_ci	}
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_ci	r = ttm_tt_set_placement_caching(bo->ttm, tmp_mem.placement);
2368c2ecf20Sopenharmony_ci	if (unlikely(r)) {
2378c2ecf20Sopenharmony_ci		goto out_cleanup;
2388c2ecf20Sopenharmony_ci	}
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_ci	r = ttm_tt_populate(bo->bdev, bo->ttm, &ctx);
2418c2ecf20Sopenharmony_ci	if (unlikely(r)) {
2428c2ecf20Sopenharmony_ci		goto out_cleanup;
2438c2ecf20Sopenharmony_ci	}
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_ci	r = radeon_ttm_tt_bind(bo->bdev, bo->ttm, &tmp_mem);
2468c2ecf20Sopenharmony_ci	if (unlikely(r)) {
2478c2ecf20Sopenharmony_ci		goto out_cleanup;
2488c2ecf20Sopenharmony_ci	}
2498c2ecf20Sopenharmony_ci	r = radeon_move_blit(bo, true, no_wait_gpu, &tmp_mem, old_mem);
2508c2ecf20Sopenharmony_ci	if (unlikely(r)) {
2518c2ecf20Sopenharmony_ci		goto out_cleanup;
2528c2ecf20Sopenharmony_ci	}
2538c2ecf20Sopenharmony_ci	r = ttm_bo_move_ttm(bo, &ctx, new_mem);
2548c2ecf20Sopenharmony_ciout_cleanup:
2558c2ecf20Sopenharmony_ci	ttm_resource_free(bo, &tmp_mem);
2568c2ecf20Sopenharmony_ci	return r;
2578c2ecf20Sopenharmony_ci}
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_cistatic int radeon_move_ram_vram(struct ttm_buffer_object *bo,
2608c2ecf20Sopenharmony_ci				bool evict, bool interruptible,
2618c2ecf20Sopenharmony_ci				bool no_wait_gpu,
2628c2ecf20Sopenharmony_ci				struct ttm_resource *new_mem)
2638c2ecf20Sopenharmony_ci{
2648c2ecf20Sopenharmony_ci	struct ttm_operation_ctx ctx = { interruptible, no_wait_gpu };
2658c2ecf20Sopenharmony_ci	struct ttm_resource *old_mem = &bo->mem;
2668c2ecf20Sopenharmony_ci	struct ttm_resource tmp_mem;
2678c2ecf20Sopenharmony_ci	struct ttm_placement placement;
2688c2ecf20Sopenharmony_ci	struct ttm_place placements;
2698c2ecf20Sopenharmony_ci	int r;
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_ci	tmp_mem = *new_mem;
2728c2ecf20Sopenharmony_ci	tmp_mem.mm_node = NULL;
2738c2ecf20Sopenharmony_ci	placement.num_placement = 1;
2748c2ecf20Sopenharmony_ci	placement.placement = &placements;
2758c2ecf20Sopenharmony_ci	placement.num_busy_placement = 1;
2768c2ecf20Sopenharmony_ci	placement.busy_placement = &placements;
2778c2ecf20Sopenharmony_ci	placements.fpfn = 0;
2788c2ecf20Sopenharmony_ci	placements.lpfn = 0;
2798c2ecf20Sopenharmony_ci	placements.mem_type = TTM_PL_TT;
2808c2ecf20Sopenharmony_ci	placements.flags = TTM_PL_MASK_CACHING;
2818c2ecf20Sopenharmony_ci	r = ttm_bo_mem_space(bo, &placement, &tmp_mem, &ctx);
2828c2ecf20Sopenharmony_ci	if (unlikely(r)) {
2838c2ecf20Sopenharmony_ci		return r;
2848c2ecf20Sopenharmony_ci	}
2858c2ecf20Sopenharmony_ci	r = ttm_bo_move_ttm(bo, &ctx, &tmp_mem);
2868c2ecf20Sopenharmony_ci	if (unlikely(r)) {
2878c2ecf20Sopenharmony_ci		goto out_cleanup;
2888c2ecf20Sopenharmony_ci	}
2898c2ecf20Sopenharmony_ci	r = radeon_move_blit(bo, true, no_wait_gpu, new_mem, old_mem);
2908c2ecf20Sopenharmony_ci	if (unlikely(r)) {
2918c2ecf20Sopenharmony_ci		goto out_cleanup;
2928c2ecf20Sopenharmony_ci	}
2938c2ecf20Sopenharmony_ciout_cleanup:
2948c2ecf20Sopenharmony_ci	ttm_resource_free(bo, &tmp_mem);
2958c2ecf20Sopenharmony_ci	return r;
2968c2ecf20Sopenharmony_ci}
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_cistatic int radeon_bo_move(struct ttm_buffer_object *bo, bool evict,
2998c2ecf20Sopenharmony_ci			  struct ttm_operation_ctx *ctx,
3008c2ecf20Sopenharmony_ci			  struct ttm_resource *new_mem)
3018c2ecf20Sopenharmony_ci{
3028c2ecf20Sopenharmony_ci	struct radeon_device *rdev;
3038c2ecf20Sopenharmony_ci	struct radeon_bo *rbo;
3048c2ecf20Sopenharmony_ci	struct ttm_resource *old_mem = &bo->mem;
3058c2ecf20Sopenharmony_ci	int r;
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_ci	r = ttm_bo_wait(bo, ctx->interruptible, ctx->no_wait_gpu);
3088c2ecf20Sopenharmony_ci	if (r)
3098c2ecf20Sopenharmony_ci		return r;
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_ci	/* Can't move a pinned BO */
3128c2ecf20Sopenharmony_ci	rbo = container_of(bo, struct radeon_bo, tbo);
3138c2ecf20Sopenharmony_ci	if (WARN_ON_ONCE(rbo->pin_count > 0))
3148c2ecf20Sopenharmony_ci		return -EINVAL;
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_ci	rdev = radeon_get_rdev(bo->bdev);
3178c2ecf20Sopenharmony_ci	if (old_mem->mem_type == TTM_PL_SYSTEM && bo->ttm == NULL) {
3188c2ecf20Sopenharmony_ci		ttm_bo_move_null(bo, new_mem);
3198c2ecf20Sopenharmony_ci		return 0;
3208c2ecf20Sopenharmony_ci	}
3218c2ecf20Sopenharmony_ci	if ((old_mem->mem_type == TTM_PL_TT &&
3228c2ecf20Sopenharmony_ci	     new_mem->mem_type == TTM_PL_SYSTEM) ||
3238c2ecf20Sopenharmony_ci	    (old_mem->mem_type == TTM_PL_SYSTEM &&
3248c2ecf20Sopenharmony_ci	     new_mem->mem_type == TTM_PL_TT)) {
3258c2ecf20Sopenharmony_ci		/* bind is enough */
3268c2ecf20Sopenharmony_ci		ttm_bo_move_null(bo, new_mem);
3278c2ecf20Sopenharmony_ci		return 0;
3288c2ecf20Sopenharmony_ci	}
3298c2ecf20Sopenharmony_ci	if (!rdev->ring[radeon_copy_ring_index(rdev)].ready ||
3308c2ecf20Sopenharmony_ci	    rdev->asic->copy.copy == NULL) {
3318c2ecf20Sopenharmony_ci		/* use memcpy */
3328c2ecf20Sopenharmony_ci		goto memcpy;
3338c2ecf20Sopenharmony_ci	}
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_ci	if (old_mem->mem_type == TTM_PL_VRAM &&
3368c2ecf20Sopenharmony_ci	    new_mem->mem_type == TTM_PL_SYSTEM) {
3378c2ecf20Sopenharmony_ci		r = radeon_move_vram_ram(bo, evict, ctx->interruptible,
3388c2ecf20Sopenharmony_ci					ctx->no_wait_gpu, new_mem);
3398c2ecf20Sopenharmony_ci	} else if (old_mem->mem_type == TTM_PL_SYSTEM &&
3408c2ecf20Sopenharmony_ci		   new_mem->mem_type == TTM_PL_VRAM) {
3418c2ecf20Sopenharmony_ci		r = radeon_move_ram_vram(bo, evict, ctx->interruptible,
3428c2ecf20Sopenharmony_ci					    ctx->no_wait_gpu, new_mem);
3438c2ecf20Sopenharmony_ci	} else {
3448c2ecf20Sopenharmony_ci		r = radeon_move_blit(bo, evict, ctx->no_wait_gpu,
3458c2ecf20Sopenharmony_ci				     new_mem, old_mem);
3468c2ecf20Sopenharmony_ci	}
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_ci	if (r) {
3498c2ecf20Sopenharmony_cimemcpy:
3508c2ecf20Sopenharmony_ci		r = ttm_bo_move_memcpy(bo, ctx, new_mem);
3518c2ecf20Sopenharmony_ci		if (r) {
3528c2ecf20Sopenharmony_ci			return r;
3538c2ecf20Sopenharmony_ci		}
3548c2ecf20Sopenharmony_ci	}
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_ci	/* update statistics */
3578c2ecf20Sopenharmony_ci	atomic64_add((u64)bo->num_pages << PAGE_SHIFT, &rdev->num_bytes_moved);
3588c2ecf20Sopenharmony_ci	return 0;
3598c2ecf20Sopenharmony_ci}
3608c2ecf20Sopenharmony_ci
3618c2ecf20Sopenharmony_cistatic int radeon_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_resource *mem)
3628c2ecf20Sopenharmony_ci{
3638c2ecf20Sopenharmony_ci	struct radeon_device *rdev = radeon_get_rdev(bdev);
3648c2ecf20Sopenharmony_ci	size_t bus_size = (size_t)mem->num_pages << PAGE_SHIFT;
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_ci	switch (mem->mem_type) {
3678c2ecf20Sopenharmony_ci	case TTM_PL_SYSTEM:
3688c2ecf20Sopenharmony_ci		/* system memory */
3698c2ecf20Sopenharmony_ci		return 0;
3708c2ecf20Sopenharmony_ci	case TTM_PL_TT:
3718c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_AGP)
3728c2ecf20Sopenharmony_ci		if (rdev->flags & RADEON_IS_AGP) {
3738c2ecf20Sopenharmony_ci			/* RADEON_IS_AGP is set only if AGP is active */
3748c2ecf20Sopenharmony_ci			mem->bus.offset = (mem->start << PAGE_SHIFT) +
3758c2ecf20Sopenharmony_ci				rdev->mc.agp_base;
3768c2ecf20Sopenharmony_ci			mem->bus.is_iomem = !rdev->ddev->agp->cant_use_aperture;
3778c2ecf20Sopenharmony_ci		}
3788c2ecf20Sopenharmony_ci#endif
3798c2ecf20Sopenharmony_ci		break;
3808c2ecf20Sopenharmony_ci	case TTM_PL_VRAM:
3818c2ecf20Sopenharmony_ci		mem->bus.offset = mem->start << PAGE_SHIFT;
3828c2ecf20Sopenharmony_ci		/* check if it's visible */
3838c2ecf20Sopenharmony_ci		if ((mem->bus.offset + bus_size) > rdev->mc.visible_vram_size)
3848c2ecf20Sopenharmony_ci			return -EINVAL;
3858c2ecf20Sopenharmony_ci		mem->bus.offset += rdev->mc.aper_base;
3868c2ecf20Sopenharmony_ci		mem->bus.is_iomem = true;
3878c2ecf20Sopenharmony_ci#ifdef __alpha__
3888c2ecf20Sopenharmony_ci		/*
3898c2ecf20Sopenharmony_ci		 * Alpha: use bus.addr to hold the ioremap() return,
3908c2ecf20Sopenharmony_ci		 * so we can modify bus.base below.
3918c2ecf20Sopenharmony_ci		 */
3928c2ecf20Sopenharmony_ci		if (mem->placement & TTM_PL_FLAG_WC)
3938c2ecf20Sopenharmony_ci			mem->bus.addr =
3948c2ecf20Sopenharmony_ci				ioremap_wc(mem->bus.offset, bus_size);
3958c2ecf20Sopenharmony_ci		else
3968c2ecf20Sopenharmony_ci			mem->bus.addr =
3978c2ecf20Sopenharmony_ci				ioremap(mem->bus.offset, bus_size);
3988c2ecf20Sopenharmony_ci		if (!mem->bus.addr)
3998c2ecf20Sopenharmony_ci			return -ENOMEM;
4008c2ecf20Sopenharmony_ci
4018c2ecf20Sopenharmony_ci		/*
4028c2ecf20Sopenharmony_ci		 * Alpha: Use just the bus offset plus
4038c2ecf20Sopenharmony_ci		 * the hose/domain memory base for bus.base.
4048c2ecf20Sopenharmony_ci		 * It then can be used to build PTEs for VRAM
4058c2ecf20Sopenharmony_ci		 * access, as done in ttm_bo_vm_fault().
4068c2ecf20Sopenharmony_ci		 */
4078c2ecf20Sopenharmony_ci		mem->bus.offset = (mem->bus.offset & 0x0ffffffffUL) +
4088c2ecf20Sopenharmony_ci			rdev->ddev->hose->dense_mem_base;
4098c2ecf20Sopenharmony_ci#endif
4108c2ecf20Sopenharmony_ci		break;
4118c2ecf20Sopenharmony_ci	default:
4128c2ecf20Sopenharmony_ci		return -EINVAL;
4138c2ecf20Sopenharmony_ci	}
4148c2ecf20Sopenharmony_ci	return 0;
4158c2ecf20Sopenharmony_ci}
4168c2ecf20Sopenharmony_ci
4178c2ecf20Sopenharmony_ci/*
4188c2ecf20Sopenharmony_ci * TTM backend functions.
4198c2ecf20Sopenharmony_ci */
4208c2ecf20Sopenharmony_cistruct radeon_ttm_tt {
4218c2ecf20Sopenharmony_ci	struct ttm_dma_tt		ttm;
4228c2ecf20Sopenharmony_ci	u64				offset;
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_ci	uint64_t			userptr;
4258c2ecf20Sopenharmony_ci	struct mm_struct		*usermm;
4268c2ecf20Sopenharmony_ci	uint32_t			userflags;
4278c2ecf20Sopenharmony_ci	bool bound;
4288c2ecf20Sopenharmony_ci};
4298c2ecf20Sopenharmony_ci
4308c2ecf20Sopenharmony_ci/* prepare the sg table with the user pages */
4318c2ecf20Sopenharmony_cistatic int radeon_ttm_tt_pin_userptr(struct ttm_bo_device *bdev, struct ttm_tt *ttm)
4328c2ecf20Sopenharmony_ci{
4338c2ecf20Sopenharmony_ci	struct radeon_device *rdev = radeon_get_rdev(bdev);
4348c2ecf20Sopenharmony_ci	struct radeon_ttm_tt *gtt = (void *)ttm;
4358c2ecf20Sopenharmony_ci	unsigned pinned = 0;
4368c2ecf20Sopenharmony_ci	int r;
4378c2ecf20Sopenharmony_ci
4388c2ecf20Sopenharmony_ci	int write = !(gtt->userflags & RADEON_GEM_USERPTR_READONLY);
4398c2ecf20Sopenharmony_ci	enum dma_data_direction direction = write ?
4408c2ecf20Sopenharmony_ci		DMA_BIDIRECTIONAL : DMA_TO_DEVICE;
4418c2ecf20Sopenharmony_ci
4428c2ecf20Sopenharmony_ci	if (current->mm != gtt->usermm)
4438c2ecf20Sopenharmony_ci		return -EPERM;
4448c2ecf20Sopenharmony_ci
4458c2ecf20Sopenharmony_ci	if (gtt->userflags & RADEON_GEM_USERPTR_ANONONLY) {
4468c2ecf20Sopenharmony_ci		/* check that we only pin down anonymous memory
4478c2ecf20Sopenharmony_ci		   to prevent problems with writeback */
4488c2ecf20Sopenharmony_ci		unsigned long end = gtt->userptr + ttm->num_pages * PAGE_SIZE;
4498c2ecf20Sopenharmony_ci		struct vm_area_struct *vma;
4508c2ecf20Sopenharmony_ci		vma = find_vma(gtt->usermm, gtt->userptr);
4518c2ecf20Sopenharmony_ci		if (!vma || vma->vm_file || vma->vm_end < end)
4528c2ecf20Sopenharmony_ci			return -EPERM;
4538c2ecf20Sopenharmony_ci	}
4548c2ecf20Sopenharmony_ci
4558c2ecf20Sopenharmony_ci	do {
4568c2ecf20Sopenharmony_ci		unsigned num_pages = ttm->num_pages - pinned;
4578c2ecf20Sopenharmony_ci		uint64_t userptr = gtt->userptr + pinned * PAGE_SIZE;
4588c2ecf20Sopenharmony_ci		struct page **pages = ttm->pages + pinned;
4598c2ecf20Sopenharmony_ci
4608c2ecf20Sopenharmony_ci		r = get_user_pages(userptr, num_pages, write ? FOLL_WRITE : 0,
4618c2ecf20Sopenharmony_ci				   pages, NULL);
4628c2ecf20Sopenharmony_ci		if (r < 0)
4638c2ecf20Sopenharmony_ci			goto release_pages;
4648c2ecf20Sopenharmony_ci
4658c2ecf20Sopenharmony_ci		pinned += r;
4668c2ecf20Sopenharmony_ci
4678c2ecf20Sopenharmony_ci	} while (pinned < ttm->num_pages);
4688c2ecf20Sopenharmony_ci
4698c2ecf20Sopenharmony_ci	r = sg_alloc_table_from_pages(ttm->sg, ttm->pages, ttm->num_pages, 0,
4708c2ecf20Sopenharmony_ci				      ttm->num_pages << PAGE_SHIFT,
4718c2ecf20Sopenharmony_ci				      GFP_KERNEL);
4728c2ecf20Sopenharmony_ci	if (r)
4738c2ecf20Sopenharmony_ci		goto release_sg;
4748c2ecf20Sopenharmony_ci
4758c2ecf20Sopenharmony_ci	r = dma_map_sgtable(rdev->dev, ttm->sg, direction, 0);
4768c2ecf20Sopenharmony_ci	if (r)
4778c2ecf20Sopenharmony_ci		goto release_sg;
4788c2ecf20Sopenharmony_ci
4798c2ecf20Sopenharmony_ci	drm_prime_sg_to_page_addr_arrays(ttm->sg, ttm->pages,
4808c2ecf20Sopenharmony_ci					 gtt->ttm.dma_address, ttm->num_pages);
4818c2ecf20Sopenharmony_ci
4828c2ecf20Sopenharmony_ci	return 0;
4838c2ecf20Sopenharmony_ci
4848c2ecf20Sopenharmony_cirelease_sg:
4858c2ecf20Sopenharmony_ci	kfree(ttm->sg);
4868c2ecf20Sopenharmony_ci
4878c2ecf20Sopenharmony_cirelease_pages:
4888c2ecf20Sopenharmony_ci	release_pages(ttm->pages, pinned);
4898c2ecf20Sopenharmony_ci	return r;
4908c2ecf20Sopenharmony_ci}
4918c2ecf20Sopenharmony_ci
4928c2ecf20Sopenharmony_cistatic void radeon_ttm_tt_unpin_userptr(struct ttm_bo_device *bdev, struct ttm_tt *ttm)
4938c2ecf20Sopenharmony_ci{
4948c2ecf20Sopenharmony_ci	struct radeon_device *rdev = radeon_get_rdev(bdev);
4958c2ecf20Sopenharmony_ci	struct radeon_ttm_tt *gtt = (void *)ttm;
4968c2ecf20Sopenharmony_ci	struct sg_page_iter sg_iter;
4978c2ecf20Sopenharmony_ci
4988c2ecf20Sopenharmony_ci	int write = !(gtt->userflags & RADEON_GEM_USERPTR_READONLY);
4998c2ecf20Sopenharmony_ci	enum dma_data_direction direction = write ?
5008c2ecf20Sopenharmony_ci		DMA_BIDIRECTIONAL : DMA_TO_DEVICE;
5018c2ecf20Sopenharmony_ci
5028c2ecf20Sopenharmony_ci	/* double check that we don't free the table twice */
5038c2ecf20Sopenharmony_ci	if (!ttm->sg->sgl)
5048c2ecf20Sopenharmony_ci		return;
5058c2ecf20Sopenharmony_ci
5068c2ecf20Sopenharmony_ci	/* free the sg table and pages again */
5078c2ecf20Sopenharmony_ci	dma_unmap_sgtable(rdev->dev, ttm->sg, direction, 0);
5088c2ecf20Sopenharmony_ci
5098c2ecf20Sopenharmony_ci	for_each_sgtable_page(ttm->sg, &sg_iter, 0) {
5108c2ecf20Sopenharmony_ci		struct page *page = sg_page_iter_page(&sg_iter);
5118c2ecf20Sopenharmony_ci		if (!(gtt->userflags & RADEON_GEM_USERPTR_READONLY))
5128c2ecf20Sopenharmony_ci			set_page_dirty(page);
5138c2ecf20Sopenharmony_ci
5148c2ecf20Sopenharmony_ci		mark_page_accessed(page);
5158c2ecf20Sopenharmony_ci		put_page(page);
5168c2ecf20Sopenharmony_ci	}
5178c2ecf20Sopenharmony_ci
5188c2ecf20Sopenharmony_ci	sg_free_table(ttm->sg);
5198c2ecf20Sopenharmony_ci}
5208c2ecf20Sopenharmony_ci
5218c2ecf20Sopenharmony_cistatic bool radeon_ttm_backend_is_bound(struct ttm_tt *ttm)
5228c2ecf20Sopenharmony_ci{
5238c2ecf20Sopenharmony_ci	struct radeon_ttm_tt *gtt = (void*)ttm;
5248c2ecf20Sopenharmony_ci
5258c2ecf20Sopenharmony_ci	return (gtt->bound);
5268c2ecf20Sopenharmony_ci}
5278c2ecf20Sopenharmony_ci
5288c2ecf20Sopenharmony_cistatic int radeon_ttm_backend_bind(struct ttm_bo_device *bdev,
5298c2ecf20Sopenharmony_ci				   struct ttm_tt *ttm,
5308c2ecf20Sopenharmony_ci				   struct ttm_resource *bo_mem)
5318c2ecf20Sopenharmony_ci{
5328c2ecf20Sopenharmony_ci	struct radeon_ttm_tt *gtt = (void*)ttm;
5338c2ecf20Sopenharmony_ci	struct radeon_device *rdev = radeon_get_rdev(bdev);
5348c2ecf20Sopenharmony_ci	uint32_t flags = RADEON_GART_PAGE_VALID | RADEON_GART_PAGE_READ |
5358c2ecf20Sopenharmony_ci		RADEON_GART_PAGE_WRITE;
5368c2ecf20Sopenharmony_ci	int r;
5378c2ecf20Sopenharmony_ci
5388c2ecf20Sopenharmony_ci	if (gtt->bound)
5398c2ecf20Sopenharmony_ci		return 0;
5408c2ecf20Sopenharmony_ci
5418c2ecf20Sopenharmony_ci	if (gtt->userptr) {
5428c2ecf20Sopenharmony_ci		radeon_ttm_tt_pin_userptr(bdev, ttm);
5438c2ecf20Sopenharmony_ci		flags &= ~RADEON_GART_PAGE_WRITE;
5448c2ecf20Sopenharmony_ci	}
5458c2ecf20Sopenharmony_ci
5468c2ecf20Sopenharmony_ci	gtt->offset = (unsigned long)(bo_mem->start << PAGE_SHIFT);
5478c2ecf20Sopenharmony_ci	if (!ttm->num_pages) {
5488c2ecf20Sopenharmony_ci		WARN(1, "nothing to bind %lu pages for mreg %p back %p!\n",
5498c2ecf20Sopenharmony_ci		     ttm->num_pages, bo_mem, ttm);
5508c2ecf20Sopenharmony_ci	}
5518c2ecf20Sopenharmony_ci	if (ttm->caching_state == tt_cached)
5528c2ecf20Sopenharmony_ci		flags |= RADEON_GART_PAGE_SNOOP;
5538c2ecf20Sopenharmony_ci	r = radeon_gart_bind(rdev, gtt->offset, ttm->num_pages,
5548c2ecf20Sopenharmony_ci			     ttm->pages, gtt->ttm.dma_address, flags);
5558c2ecf20Sopenharmony_ci	if (r) {
5568c2ecf20Sopenharmony_ci		DRM_ERROR("failed to bind %lu pages at 0x%08X\n",
5578c2ecf20Sopenharmony_ci			  ttm->num_pages, (unsigned)gtt->offset);
5588c2ecf20Sopenharmony_ci		return r;
5598c2ecf20Sopenharmony_ci	}
5608c2ecf20Sopenharmony_ci	gtt->bound = true;
5618c2ecf20Sopenharmony_ci	return 0;
5628c2ecf20Sopenharmony_ci}
5638c2ecf20Sopenharmony_ci
5648c2ecf20Sopenharmony_cistatic void radeon_ttm_backend_unbind(struct ttm_bo_device *bdev, struct ttm_tt *ttm)
5658c2ecf20Sopenharmony_ci{
5668c2ecf20Sopenharmony_ci	struct radeon_ttm_tt *gtt = (void *)ttm;
5678c2ecf20Sopenharmony_ci	struct radeon_device *rdev = radeon_get_rdev(bdev);
5688c2ecf20Sopenharmony_ci
5698c2ecf20Sopenharmony_ci	if (gtt->userptr)
5708c2ecf20Sopenharmony_ci		radeon_ttm_tt_unpin_userptr(bdev, ttm);
5718c2ecf20Sopenharmony_ci
5728c2ecf20Sopenharmony_ci	if (!gtt->bound)
5738c2ecf20Sopenharmony_ci		return;
5748c2ecf20Sopenharmony_ci
5758c2ecf20Sopenharmony_ci	radeon_gart_unbind(rdev, gtt->offset, ttm->num_pages);
5768c2ecf20Sopenharmony_ci
5778c2ecf20Sopenharmony_ci	gtt->bound = false;
5788c2ecf20Sopenharmony_ci}
5798c2ecf20Sopenharmony_ci
5808c2ecf20Sopenharmony_cistatic void radeon_ttm_backend_destroy(struct ttm_bo_device *bdev, struct ttm_tt *ttm)
5818c2ecf20Sopenharmony_ci{
5828c2ecf20Sopenharmony_ci	struct radeon_ttm_tt *gtt = (void *)ttm;
5838c2ecf20Sopenharmony_ci
5848c2ecf20Sopenharmony_ci	radeon_ttm_backend_unbind(bdev, ttm);
5858c2ecf20Sopenharmony_ci	ttm_tt_destroy_common(bdev, ttm);
5868c2ecf20Sopenharmony_ci
5878c2ecf20Sopenharmony_ci	ttm_dma_tt_fini(&gtt->ttm);
5888c2ecf20Sopenharmony_ci	kfree(gtt);
5898c2ecf20Sopenharmony_ci}
5908c2ecf20Sopenharmony_ci
5918c2ecf20Sopenharmony_cistatic struct ttm_tt *radeon_ttm_tt_create(struct ttm_buffer_object *bo,
5928c2ecf20Sopenharmony_ci					   uint32_t page_flags)
5938c2ecf20Sopenharmony_ci{
5948c2ecf20Sopenharmony_ci	struct radeon_device *rdev;
5958c2ecf20Sopenharmony_ci	struct radeon_ttm_tt *gtt;
5968c2ecf20Sopenharmony_ci
5978c2ecf20Sopenharmony_ci	rdev = radeon_get_rdev(bo->bdev);
5988c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_AGP)
5998c2ecf20Sopenharmony_ci	if (rdev->flags & RADEON_IS_AGP) {
6008c2ecf20Sopenharmony_ci		return ttm_agp_tt_create(bo, rdev->ddev->agp->bridge,
6018c2ecf20Sopenharmony_ci					 page_flags);
6028c2ecf20Sopenharmony_ci	}
6038c2ecf20Sopenharmony_ci#endif
6048c2ecf20Sopenharmony_ci
6058c2ecf20Sopenharmony_ci	gtt = kzalloc(sizeof(struct radeon_ttm_tt), GFP_KERNEL);
6068c2ecf20Sopenharmony_ci	if (gtt == NULL) {
6078c2ecf20Sopenharmony_ci		return NULL;
6088c2ecf20Sopenharmony_ci	}
6098c2ecf20Sopenharmony_ci	if (ttm_dma_tt_init(&gtt->ttm, bo, page_flags)) {
6108c2ecf20Sopenharmony_ci		kfree(gtt);
6118c2ecf20Sopenharmony_ci		return NULL;
6128c2ecf20Sopenharmony_ci	}
6138c2ecf20Sopenharmony_ci	return &gtt->ttm.ttm;
6148c2ecf20Sopenharmony_ci}
6158c2ecf20Sopenharmony_ci
6168c2ecf20Sopenharmony_cistatic struct radeon_ttm_tt *radeon_ttm_tt_to_gtt(struct radeon_device *rdev,
6178c2ecf20Sopenharmony_ci						  struct ttm_tt *ttm)
6188c2ecf20Sopenharmony_ci{
6198c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_AGP)
6208c2ecf20Sopenharmony_ci	if (rdev->flags & RADEON_IS_AGP)
6218c2ecf20Sopenharmony_ci		return NULL;
6228c2ecf20Sopenharmony_ci#endif
6238c2ecf20Sopenharmony_ci
6248c2ecf20Sopenharmony_ci	if (!ttm)
6258c2ecf20Sopenharmony_ci		return NULL;
6268c2ecf20Sopenharmony_ci	return container_of(ttm, struct radeon_ttm_tt, ttm.ttm);
6278c2ecf20Sopenharmony_ci}
6288c2ecf20Sopenharmony_ci
6298c2ecf20Sopenharmony_cistatic int radeon_ttm_tt_populate(struct ttm_bo_device *bdev,
6308c2ecf20Sopenharmony_ci				  struct ttm_tt *ttm,
6318c2ecf20Sopenharmony_ci				  struct ttm_operation_ctx *ctx)
6328c2ecf20Sopenharmony_ci{
6338c2ecf20Sopenharmony_ci	struct radeon_device *rdev = radeon_get_rdev(bdev);
6348c2ecf20Sopenharmony_ci	struct radeon_ttm_tt *gtt = radeon_ttm_tt_to_gtt(rdev, ttm);
6358c2ecf20Sopenharmony_ci	bool slave = !!(ttm->page_flags & TTM_PAGE_FLAG_SG);
6368c2ecf20Sopenharmony_ci
6378c2ecf20Sopenharmony_ci	if (gtt && gtt->userptr) {
6388c2ecf20Sopenharmony_ci		ttm->sg = kzalloc(sizeof(struct sg_table), GFP_KERNEL);
6398c2ecf20Sopenharmony_ci		if (!ttm->sg)
6408c2ecf20Sopenharmony_ci			return -ENOMEM;
6418c2ecf20Sopenharmony_ci
6428c2ecf20Sopenharmony_ci		ttm->page_flags |= TTM_PAGE_FLAG_SG;
6438c2ecf20Sopenharmony_ci		ttm_tt_set_populated(ttm);
6448c2ecf20Sopenharmony_ci		return 0;
6458c2ecf20Sopenharmony_ci	}
6468c2ecf20Sopenharmony_ci
6478c2ecf20Sopenharmony_ci	if (slave && ttm->sg) {
6488c2ecf20Sopenharmony_ci		drm_prime_sg_to_page_addr_arrays(ttm->sg, ttm->pages,
6498c2ecf20Sopenharmony_ci						 gtt->ttm.dma_address, ttm->num_pages);
6508c2ecf20Sopenharmony_ci		ttm_tt_set_populated(ttm);
6518c2ecf20Sopenharmony_ci		return 0;
6528c2ecf20Sopenharmony_ci	}
6538c2ecf20Sopenharmony_ci
6548c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_AGP)
6558c2ecf20Sopenharmony_ci	if (rdev->flags & RADEON_IS_AGP) {
6568c2ecf20Sopenharmony_ci		return ttm_pool_populate(ttm, ctx);
6578c2ecf20Sopenharmony_ci	}
6588c2ecf20Sopenharmony_ci#endif
6598c2ecf20Sopenharmony_ci
6608c2ecf20Sopenharmony_ci#ifdef CONFIG_SWIOTLB
6618c2ecf20Sopenharmony_ci	if (rdev->need_swiotlb && swiotlb_nr_tbl()) {
6628c2ecf20Sopenharmony_ci		return ttm_dma_populate(&gtt->ttm, rdev->dev, ctx);
6638c2ecf20Sopenharmony_ci	}
6648c2ecf20Sopenharmony_ci#endif
6658c2ecf20Sopenharmony_ci
6668c2ecf20Sopenharmony_ci	return ttm_populate_and_map_pages(rdev->dev, &gtt->ttm, ctx);
6678c2ecf20Sopenharmony_ci}
6688c2ecf20Sopenharmony_ci
6698c2ecf20Sopenharmony_cistatic void radeon_ttm_tt_unpopulate(struct ttm_bo_device *bdev, struct ttm_tt *ttm)
6708c2ecf20Sopenharmony_ci{
6718c2ecf20Sopenharmony_ci	struct radeon_device *rdev = radeon_get_rdev(bdev);
6728c2ecf20Sopenharmony_ci	struct radeon_ttm_tt *gtt = radeon_ttm_tt_to_gtt(rdev, ttm);
6738c2ecf20Sopenharmony_ci	bool slave = !!(ttm->page_flags & TTM_PAGE_FLAG_SG);
6748c2ecf20Sopenharmony_ci
6758c2ecf20Sopenharmony_ci	if (gtt && gtt->userptr) {
6768c2ecf20Sopenharmony_ci		kfree(ttm->sg);
6778c2ecf20Sopenharmony_ci		ttm->page_flags &= ~TTM_PAGE_FLAG_SG;
6788c2ecf20Sopenharmony_ci		return;
6798c2ecf20Sopenharmony_ci	}
6808c2ecf20Sopenharmony_ci
6818c2ecf20Sopenharmony_ci	if (slave)
6828c2ecf20Sopenharmony_ci		return;
6838c2ecf20Sopenharmony_ci
6848c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_AGP)
6858c2ecf20Sopenharmony_ci	if (rdev->flags & RADEON_IS_AGP) {
6868c2ecf20Sopenharmony_ci		ttm_pool_unpopulate(ttm);
6878c2ecf20Sopenharmony_ci		return;
6888c2ecf20Sopenharmony_ci	}
6898c2ecf20Sopenharmony_ci#endif
6908c2ecf20Sopenharmony_ci
6918c2ecf20Sopenharmony_ci#ifdef CONFIG_SWIOTLB
6928c2ecf20Sopenharmony_ci	if (rdev->need_swiotlb && swiotlb_nr_tbl()) {
6938c2ecf20Sopenharmony_ci		ttm_dma_unpopulate(&gtt->ttm, rdev->dev);
6948c2ecf20Sopenharmony_ci		return;
6958c2ecf20Sopenharmony_ci	}
6968c2ecf20Sopenharmony_ci#endif
6978c2ecf20Sopenharmony_ci
6988c2ecf20Sopenharmony_ci	ttm_unmap_and_unpopulate_pages(rdev->dev, &gtt->ttm);
6998c2ecf20Sopenharmony_ci}
7008c2ecf20Sopenharmony_ci
7018c2ecf20Sopenharmony_ciint radeon_ttm_tt_set_userptr(struct radeon_device *rdev,
7028c2ecf20Sopenharmony_ci			      struct ttm_tt *ttm, uint64_t addr,
7038c2ecf20Sopenharmony_ci			      uint32_t flags)
7048c2ecf20Sopenharmony_ci{
7058c2ecf20Sopenharmony_ci	struct radeon_ttm_tt *gtt = radeon_ttm_tt_to_gtt(rdev, ttm);
7068c2ecf20Sopenharmony_ci
7078c2ecf20Sopenharmony_ci	if (gtt == NULL)
7088c2ecf20Sopenharmony_ci		return -EINVAL;
7098c2ecf20Sopenharmony_ci
7108c2ecf20Sopenharmony_ci	gtt->userptr = addr;
7118c2ecf20Sopenharmony_ci	gtt->usermm = current->mm;
7128c2ecf20Sopenharmony_ci	gtt->userflags = flags;
7138c2ecf20Sopenharmony_ci	return 0;
7148c2ecf20Sopenharmony_ci}
7158c2ecf20Sopenharmony_ci
7168c2ecf20Sopenharmony_cibool radeon_ttm_tt_is_bound(struct ttm_bo_device *bdev,
7178c2ecf20Sopenharmony_ci			    struct ttm_tt *ttm)
7188c2ecf20Sopenharmony_ci{
7198c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_AGP)
7208c2ecf20Sopenharmony_ci	struct radeon_device *rdev = radeon_get_rdev(bdev);
7218c2ecf20Sopenharmony_ci	if (rdev->flags & RADEON_IS_AGP)
7228c2ecf20Sopenharmony_ci		return ttm_agp_is_bound(ttm);
7238c2ecf20Sopenharmony_ci#endif
7248c2ecf20Sopenharmony_ci	return radeon_ttm_backend_is_bound(ttm);
7258c2ecf20Sopenharmony_ci}
7268c2ecf20Sopenharmony_ci
7278c2ecf20Sopenharmony_cistatic int radeon_ttm_tt_bind(struct ttm_bo_device *bdev,
7288c2ecf20Sopenharmony_ci			      struct ttm_tt *ttm,
7298c2ecf20Sopenharmony_ci			      struct ttm_resource *bo_mem)
7308c2ecf20Sopenharmony_ci{
7318c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_AGP)
7328c2ecf20Sopenharmony_ci	struct radeon_device *rdev = radeon_get_rdev(bdev);
7338c2ecf20Sopenharmony_ci#endif
7348c2ecf20Sopenharmony_ci
7358c2ecf20Sopenharmony_ci	if (!bo_mem)
7368c2ecf20Sopenharmony_ci		return -EINVAL;
7378c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_AGP)
7388c2ecf20Sopenharmony_ci	if (rdev->flags & RADEON_IS_AGP)
7398c2ecf20Sopenharmony_ci		return ttm_agp_bind(ttm, bo_mem);
7408c2ecf20Sopenharmony_ci#endif
7418c2ecf20Sopenharmony_ci
7428c2ecf20Sopenharmony_ci	return radeon_ttm_backend_bind(bdev, ttm, bo_mem);
7438c2ecf20Sopenharmony_ci}
7448c2ecf20Sopenharmony_ci
7458c2ecf20Sopenharmony_cistatic void radeon_ttm_tt_unbind(struct ttm_bo_device *bdev,
7468c2ecf20Sopenharmony_ci				 struct ttm_tt *ttm)
7478c2ecf20Sopenharmony_ci{
7488c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_AGP)
7498c2ecf20Sopenharmony_ci	struct radeon_device *rdev = radeon_get_rdev(bdev);
7508c2ecf20Sopenharmony_ci
7518c2ecf20Sopenharmony_ci	if (rdev->flags & RADEON_IS_AGP) {
7528c2ecf20Sopenharmony_ci		ttm_agp_unbind(ttm);
7538c2ecf20Sopenharmony_ci		return;
7548c2ecf20Sopenharmony_ci	}
7558c2ecf20Sopenharmony_ci#endif
7568c2ecf20Sopenharmony_ci	radeon_ttm_backend_unbind(bdev, ttm);
7578c2ecf20Sopenharmony_ci}
7588c2ecf20Sopenharmony_ci
7598c2ecf20Sopenharmony_cistatic void radeon_ttm_tt_destroy(struct ttm_bo_device *bdev,
7608c2ecf20Sopenharmony_ci				  struct ttm_tt *ttm)
7618c2ecf20Sopenharmony_ci{
7628c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_AGP)
7638c2ecf20Sopenharmony_ci	struct radeon_device *rdev = radeon_get_rdev(bdev);
7648c2ecf20Sopenharmony_ci
7658c2ecf20Sopenharmony_ci	if (rdev->flags & RADEON_IS_AGP) {
7668c2ecf20Sopenharmony_ci		ttm_agp_unbind(ttm);
7678c2ecf20Sopenharmony_ci		ttm_tt_destroy_common(bdev, ttm);
7688c2ecf20Sopenharmony_ci		ttm_agp_destroy(ttm);
7698c2ecf20Sopenharmony_ci		return;
7708c2ecf20Sopenharmony_ci	}
7718c2ecf20Sopenharmony_ci#endif
7728c2ecf20Sopenharmony_ci	radeon_ttm_backend_destroy(bdev, ttm);
7738c2ecf20Sopenharmony_ci}
7748c2ecf20Sopenharmony_ci
7758c2ecf20Sopenharmony_cibool radeon_ttm_tt_has_userptr(struct radeon_device *rdev,
7768c2ecf20Sopenharmony_ci			       struct ttm_tt *ttm)
7778c2ecf20Sopenharmony_ci{
7788c2ecf20Sopenharmony_ci	struct radeon_ttm_tt *gtt = radeon_ttm_tt_to_gtt(rdev, ttm);
7798c2ecf20Sopenharmony_ci
7808c2ecf20Sopenharmony_ci	if (gtt == NULL)
7818c2ecf20Sopenharmony_ci		return false;
7828c2ecf20Sopenharmony_ci
7838c2ecf20Sopenharmony_ci	return !!gtt->userptr;
7848c2ecf20Sopenharmony_ci}
7858c2ecf20Sopenharmony_ci
7868c2ecf20Sopenharmony_cibool radeon_ttm_tt_is_readonly(struct radeon_device *rdev,
7878c2ecf20Sopenharmony_ci			       struct ttm_tt *ttm)
7888c2ecf20Sopenharmony_ci{
7898c2ecf20Sopenharmony_ci	struct radeon_ttm_tt *gtt = radeon_ttm_tt_to_gtt(rdev, ttm);
7908c2ecf20Sopenharmony_ci
7918c2ecf20Sopenharmony_ci	if (gtt == NULL)
7928c2ecf20Sopenharmony_ci		return false;
7938c2ecf20Sopenharmony_ci
7948c2ecf20Sopenharmony_ci	return !!(gtt->userflags & RADEON_GEM_USERPTR_READONLY);
7958c2ecf20Sopenharmony_ci}
7968c2ecf20Sopenharmony_ci
7978c2ecf20Sopenharmony_cistatic struct ttm_bo_driver radeon_bo_driver = {
7988c2ecf20Sopenharmony_ci	.ttm_tt_create = &radeon_ttm_tt_create,
7998c2ecf20Sopenharmony_ci	.ttm_tt_populate = &radeon_ttm_tt_populate,
8008c2ecf20Sopenharmony_ci	.ttm_tt_unpopulate = &radeon_ttm_tt_unpopulate,
8018c2ecf20Sopenharmony_ci	.ttm_tt_bind = &radeon_ttm_tt_bind,
8028c2ecf20Sopenharmony_ci	.ttm_tt_unbind = &radeon_ttm_tt_unbind,
8038c2ecf20Sopenharmony_ci	.ttm_tt_destroy = &radeon_ttm_tt_destroy,
8048c2ecf20Sopenharmony_ci	.eviction_valuable = ttm_bo_eviction_valuable,
8058c2ecf20Sopenharmony_ci	.evict_flags = &radeon_evict_flags,
8068c2ecf20Sopenharmony_ci	.move = &radeon_bo_move,
8078c2ecf20Sopenharmony_ci	.verify_access = &radeon_verify_access,
8088c2ecf20Sopenharmony_ci	.move_notify = &radeon_bo_move_notify,
8098c2ecf20Sopenharmony_ci	.fault_reserve_notify = &radeon_bo_fault_reserve_notify,
8108c2ecf20Sopenharmony_ci	.io_mem_reserve = &radeon_ttm_io_mem_reserve,
8118c2ecf20Sopenharmony_ci};
8128c2ecf20Sopenharmony_ci
8138c2ecf20Sopenharmony_ciint radeon_ttm_init(struct radeon_device *rdev)
8148c2ecf20Sopenharmony_ci{
8158c2ecf20Sopenharmony_ci	int r;
8168c2ecf20Sopenharmony_ci
8178c2ecf20Sopenharmony_ci	/* No others user of address space so set it to 0 */
8188c2ecf20Sopenharmony_ci	r = ttm_bo_device_init(&rdev->mman.bdev,
8198c2ecf20Sopenharmony_ci			       &radeon_bo_driver,
8208c2ecf20Sopenharmony_ci			       rdev->ddev->anon_inode->i_mapping,
8218c2ecf20Sopenharmony_ci			       rdev->ddev->vma_offset_manager,
8228c2ecf20Sopenharmony_ci			       dma_addressing_limited(&rdev->pdev->dev));
8238c2ecf20Sopenharmony_ci	if (r) {
8248c2ecf20Sopenharmony_ci		DRM_ERROR("failed initializing buffer object driver(%d).\n", r);
8258c2ecf20Sopenharmony_ci		return r;
8268c2ecf20Sopenharmony_ci	}
8278c2ecf20Sopenharmony_ci	rdev->mman.initialized = true;
8288c2ecf20Sopenharmony_ci
8298c2ecf20Sopenharmony_ci	r = radeon_ttm_init_vram(rdev);
8308c2ecf20Sopenharmony_ci	if (r) {
8318c2ecf20Sopenharmony_ci		DRM_ERROR("Failed initializing VRAM heap.\n");
8328c2ecf20Sopenharmony_ci		return r;
8338c2ecf20Sopenharmony_ci	}
8348c2ecf20Sopenharmony_ci	/* Change the size here instead of the init above so only lpfn is affected */
8358c2ecf20Sopenharmony_ci	radeon_ttm_set_active_vram_size(rdev, rdev->mc.visible_vram_size);
8368c2ecf20Sopenharmony_ci
8378c2ecf20Sopenharmony_ci	r = radeon_bo_create(rdev, 256 * 1024, PAGE_SIZE, true,
8388c2ecf20Sopenharmony_ci			     RADEON_GEM_DOMAIN_VRAM, 0, NULL,
8398c2ecf20Sopenharmony_ci			     NULL, &rdev->stolen_vga_memory);
8408c2ecf20Sopenharmony_ci	if (r) {
8418c2ecf20Sopenharmony_ci		return r;
8428c2ecf20Sopenharmony_ci	}
8438c2ecf20Sopenharmony_ci	r = radeon_bo_reserve(rdev->stolen_vga_memory, false);
8448c2ecf20Sopenharmony_ci	if (r)
8458c2ecf20Sopenharmony_ci		return r;
8468c2ecf20Sopenharmony_ci	r = radeon_bo_pin(rdev->stolen_vga_memory, RADEON_GEM_DOMAIN_VRAM, NULL);
8478c2ecf20Sopenharmony_ci	radeon_bo_unreserve(rdev->stolen_vga_memory);
8488c2ecf20Sopenharmony_ci	if (r) {
8498c2ecf20Sopenharmony_ci		radeon_bo_unref(&rdev->stolen_vga_memory);
8508c2ecf20Sopenharmony_ci		return r;
8518c2ecf20Sopenharmony_ci	}
8528c2ecf20Sopenharmony_ci	DRM_INFO("radeon: %uM of VRAM memory ready\n",
8538c2ecf20Sopenharmony_ci		 (unsigned) (rdev->mc.real_vram_size / (1024 * 1024)));
8548c2ecf20Sopenharmony_ci
8558c2ecf20Sopenharmony_ci	r = radeon_ttm_init_gtt(rdev);
8568c2ecf20Sopenharmony_ci	if (r) {
8578c2ecf20Sopenharmony_ci		DRM_ERROR("Failed initializing GTT heap.\n");
8588c2ecf20Sopenharmony_ci		return r;
8598c2ecf20Sopenharmony_ci	}
8608c2ecf20Sopenharmony_ci	DRM_INFO("radeon: %uM of GTT memory ready.\n",
8618c2ecf20Sopenharmony_ci		 (unsigned)(rdev->mc.gtt_size / (1024 * 1024)));
8628c2ecf20Sopenharmony_ci
8638c2ecf20Sopenharmony_ci	r = radeon_ttm_debugfs_init(rdev);
8648c2ecf20Sopenharmony_ci	if (r) {
8658c2ecf20Sopenharmony_ci		DRM_ERROR("Failed to init debugfs\n");
8668c2ecf20Sopenharmony_ci		return r;
8678c2ecf20Sopenharmony_ci	}
8688c2ecf20Sopenharmony_ci	return 0;
8698c2ecf20Sopenharmony_ci}
8708c2ecf20Sopenharmony_ci
8718c2ecf20Sopenharmony_civoid radeon_ttm_fini(struct radeon_device *rdev)
8728c2ecf20Sopenharmony_ci{
8738c2ecf20Sopenharmony_ci	int r;
8748c2ecf20Sopenharmony_ci
8758c2ecf20Sopenharmony_ci	if (!rdev->mman.initialized)
8768c2ecf20Sopenharmony_ci		return;
8778c2ecf20Sopenharmony_ci	radeon_ttm_debugfs_fini(rdev);
8788c2ecf20Sopenharmony_ci	if (rdev->stolen_vga_memory) {
8798c2ecf20Sopenharmony_ci		r = radeon_bo_reserve(rdev->stolen_vga_memory, false);
8808c2ecf20Sopenharmony_ci		if (r == 0) {
8818c2ecf20Sopenharmony_ci			radeon_bo_unpin(rdev->stolen_vga_memory);
8828c2ecf20Sopenharmony_ci			radeon_bo_unreserve(rdev->stolen_vga_memory);
8838c2ecf20Sopenharmony_ci		}
8848c2ecf20Sopenharmony_ci		radeon_bo_unref(&rdev->stolen_vga_memory);
8858c2ecf20Sopenharmony_ci	}
8868c2ecf20Sopenharmony_ci	ttm_range_man_fini(&rdev->mman.bdev, TTM_PL_VRAM);
8878c2ecf20Sopenharmony_ci	ttm_range_man_fini(&rdev->mman.bdev, TTM_PL_TT);
8888c2ecf20Sopenharmony_ci	ttm_bo_device_release(&rdev->mman.bdev);
8898c2ecf20Sopenharmony_ci	radeon_gart_fini(rdev);
8908c2ecf20Sopenharmony_ci	rdev->mman.initialized = false;
8918c2ecf20Sopenharmony_ci	DRM_INFO("radeon: ttm finalized\n");
8928c2ecf20Sopenharmony_ci}
8938c2ecf20Sopenharmony_ci
8948c2ecf20Sopenharmony_ci/* this should only be called at bootup or when userspace
8958c2ecf20Sopenharmony_ci * isn't running */
8968c2ecf20Sopenharmony_civoid radeon_ttm_set_active_vram_size(struct radeon_device *rdev, u64 size)
8978c2ecf20Sopenharmony_ci{
8988c2ecf20Sopenharmony_ci	struct ttm_resource_manager *man;
8998c2ecf20Sopenharmony_ci
9008c2ecf20Sopenharmony_ci	if (!rdev->mman.initialized)
9018c2ecf20Sopenharmony_ci		return;
9028c2ecf20Sopenharmony_ci
9038c2ecf20Sopenharmony_ci	man = ttm_manager_type(&rdev->mman.bdev, TTM_PL_VRAM);
9048c2ecf20Sopenharmony_ci	/* this just adjusts TTM size idea, which sets lpfn to the correct value */
9058c2ecf20Sopenharmony_ci	man->size = size >> PAGE_SHIFT;
9068c2ecf20Sopenharmony_ci}
9078c2ecf20Sopenharmony_ci
9088c2ecf20Sopenharmony_cistatic vm_fault_t radeon_ttm_fault(struct vm_fault *vmf)
9098c2ecf20Sopenharmony_ci{
9108c2ecf20Sopenharmony_ci	struct ttm_buffer_object *bo;
9118c2ecf20Sopenharmony_ci	struct radeon_device *rdev;
9128c2ecf20Sopenharmony_ci	vm_fault_t ret;
9138c2ecf20Sopenharmony_ci
9148c2ecf20Sopenharmony_ci	bo = (struct ttm_buffer_object *)vmf->vma->vm_private_data;
9158c2ecf20Sopenharmony_ci	if (bo == NULL)
9168c2ecf20Sopenharmony_ci		return VM_FAULT_NOPAGE;
9178c2ecf20Sopenharmony_ci
9188c2ecf20Sopenharmony_ci	rdev = radeon_get_rdev(bo->bdev);
9198c2ecf20Sopenharmony_ci	down_read(&rdev->pm.mclk_lock);
9208c2ecf20Sopenharmony_ci	ret = ttm_bo_vm_fault(vmf);
9218c2ecf20Sopenharmony_ci	up_read(&rdev->pm.mclk_lock);
9228c2ecf20Sopenharmony_ci	return ret;
9238c2ecf20Sopenharmony_ci}
9248c2ecf20Sopenharmony_ci
9258c2ecf20Sopenharmony_cistatic struct vm_operations_struct radeon_ttm_vm_ops = {
9268c2ecf20Sopenharmony_ci	.fault = radeon_ttm_fault,
9278c2ecf20Sopenharmony_ci	.open = ttm_bo_vm_open,
9288c2ecf20Sopenharmony_ci	.close = ttm_bo_vm_close,
9298c2ecf20Sopenharmony_ci	.access = ttm_bo_vm_access
9308c2ecf20Sopenharmony_ci};
9318c2ecf20Sopenharmony_ci
9328c2ecf20Sopenharmony_ciint radeon_mmap(struct file *filp, struct vm_area_struct *vma)
9338c2ecf20Sopenharmony_ci{
9348c2ecf20Sopenharmony_ci	int r;
9358c2ecf20Sopenharmony_ci	struct drm_file *file_priv = filp->private_data;
9368c2ecf20Sopenharmony_ci	struct radeon_device *rdev = file_priv->minor->dev->dev_private;
9378c2ecf20Sopenharmony_ci
9388c2ecf20Sopenharmony_ci	if (rdev == NULL)
9398c2ecf20Sopenharmony_ci		return -EINVAL;
9408c2ecf20Sopenharmony_ci
9418c2ecf20Sopenharmony_ci	r = ttm_bo_mmap(filp, vma, &rdev->mman.bdev);
9428c2ecf20Sopenharmony_ci	if (unlikely(r != 0))
9438c2ecf20Sopenharmony_ci		return r;
9448c2ecf20Sopenharmony_ci
9458c2ecf20Sopenharmony_ci	vma->vm_ops = &radeon_ttm_vm_ops;
9468c2ecf20Sopenharmony_ci	return 0;
9478c2ecf20Sopenharmony_ci}
9488c2ecf20Sopenharmony_ci
9498c2ecf20Sopenharmony_ci#if defined(CONFIG_DEBUG_FS)
9508c2ecf20Sopenharmony_ci
9518c2ecf20Sopenharmony_cistatic int radeon_mm_dump_table(struct seq_file *m, void *data)
9528c2ecf20Sopenharmony_ci{
9538c2ecf20Sopenharmony_ci	struct drm_info_node *node = (struct drm_info_node *)m->private;
9548c2ecf20Sopenharmony_ci	unsigned ttm_pl = *(int*)node->info_ent->data;
9558c2ecf20Sopenharmony_ci	struct drm_device *dev = node->minor->dev;
9568c2ecf20Sopenharmony_ci	struct radeon_device *rdev = dev->dev_private;
9578c2ecf20Sopenharmony_ci	struct ttm_resource_manager *man = ttm_manager_type(&rdev->mman.bdev, ttm_pl);
9588c2ecf20Sopenharmony_ci	struct drm_printer p = drm_seq_file_printer(m);
9598c2ecf20Sopenharmony_ci
9608c2ecf20Sopenharmony_ci	man->func->debug(man, &p);
9618c2ecf20Sopenharmony_ci	return 0;
9628c2ecf20Sopenharmony_ci}
9638c2ecf20Sopenharmony_ci
9648c2ecf20Sopenharmony_ci
9658c2ecf20Sopenharmony_cistatic int ttm_pl_vram = TTM_PL_VRAM;
9668c2ecf20Sopenharmony_cistatic int ttm_pl_tt = TTM_PL_TT;
9678c2ecf20Sopenharmony_ci
9688c2ecf20Sopenharmony_cistatic struct drm_info_list radeon_ttm_debugfs_list[] = {
9698c2ecf20Sopenharmony_ci	{"radeon_vram_mm", radeon_mm_dump_table, 0, &ttm_pl_vram},
9708c2ecf20Sopenharmony_ci	{"radeon_gtt_mm", radeon_mm_dump_table, 0, &ttm_pl_tt},
9718c2ecf20Sopenharmony_ci	{"ttm_page_pool", ttm_page_alloc_debugfs, 0, NULL},
9728c2ecf20Sopenharmony_ci#ifdef CONFIG_SWIOTLB
9738c2ecf20Sopenharmony_ci	{"ttm_dma_page_pool", ttm_dma_page_alloc_debugfs, 0, NULL}
9748c2ecf20Sopenharmony_ci#endif
9758c2ecf20Sopenharmony_ci};
9768c2ecf20Sopenharmony_ci
9778c2ecf20Sopenharmony_cistatic int radeon_ttm_vram_open(struct inode *inode, struct file *filep)
9788c2ecf20Sopenharmony_ci{
9798c2ecf20Sopenharmony_ci	struct radeon_device *rdev = inode->i_private;
9808c2ecf20Sopenharmony_ci	i_size_write(inode, rdev->mc.mc_vram_size);
9818c2ecf20Sopenharmony_ci	filep->private_data = inode->i_private;
9828c2ecf20Sopenharmony_ci	return 0;
9838c2ecf20Sopenharmony_ci}
9848c2ecf20Sopenharmony_ci
9858c2ecf20Sopenharmony_cistatic ssize_t radeon_ttm_vram_read(struct file *f, char __user *buf,
9868c2ecf20Sopenharmony_ci				    size_t size, loff_t *pos)
9878c2ecf20Sopenharmony_ci{
9888c2ecf20Sopenharmony_ci	struct radeon_device *rdev = f->private_data;
9898c2ecf20Sopenharmony_ci	ssize_t result = 0;
9908c2ecf20Sopenharmony_ci	int r;
9918c2ecf20Sopenharmony_ci
9928c2ecf20Sopenharmony_ci	if (size & 0x3 || *pos & 0x3)
9938c2ecf20Sopenharmony_ci		return -EINVAL;
9948c2ecf20Sopenharmony_ci
9958c2ecf20Sopenharmony_ci	while (size) {
9968c2ecf20Sopenharmony_ci		unsigned long flags;
9978c2ecf20Sopenharmony_ci		uint32_t value;
9988c2ecf20Sopenharmony_ci
9998c2ecf20Sopenharmony_ci		if (*pos >= rdev->mc.mc_vram_size)
10008c2ecf20Sopenharmony_ci			return result;
10018c2ecf20Sopenharmony_ci
10028c2ecf20Sopenharmony_ci		spin_lock_irqsave(&rdev->mmio_idx_lock, flags);
10038c2ecf20Sopenharmony_ci		WREG32(RADEON_MM_INDEX, ((uint32_t)*pos) | 0x80000000);
10048c2ecf20Sopenharmony_ci		if (rdev->family >= CHIP_CEDAR)
10058c2ecf20Sopenharmony_ci			WREG32(EVERGREEN_MM_INDEX_HI, *pos >> 31);
10068c2ecf20Sopenharmony_ci		value = RREG32(RADEON_MM_DATA);
10078c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&rdev->mmio_idx_lock, flags);
10088c2ecf20Sopenharmony_ci
10098c2ecf20Sopenharmony_ci		r = put_user(value, (uint32_t *)buf);
10108c2ecf20Sopenharmony_ci		if (r)
10118c2ecf20Sopenharmony_ci			return r;
10128c2ecf20Sopenharmony_ci
10138c2ecf20Sopenharmony_ci		result += 4;
10148c2ecf20Sopenharmony_ci		buf += 4;
10158c2ecf20Sopenharmony_ci		*pos += 4;
10168c2ecf20Sopenharmony_ci		size -= 4;
10178c2ecf20Sopenharmony_ci	}
10188c2ecf20Sopenharmony_ci
10198c2ecf20Sopenharmony_ci	return result;
10208c2ecf20Sopenharmony_ci}
10218c2ecf20Sopenharmony_ci
10228c2ecf20Sopenharmony_cistatic const struct file_operations radeon_ttm_vram_fops = {
10238c2ecf20Sopenharmony_ci	.owner = THIS_MODULE,
10248c2ecf20Sopenharmony_ci	.open = radeon_ttm_vram_open,
10258c2ecf20Sopenharmony_ci	.read = radeon_ttm_vram_read,
10268c2ecf20Sopenharmony_ci	.llseek = default_llseek
10278c2ecf20Sopenharmony_ci};
10288c2ecf20Sopenharmony_ci
10298c2ecf20Sopenharmony_cistatic int radeon_ttm_gtt_open(struct inode *inode, struct file *filep)
10308c2ecf20Sopenharmony_ci{
10318c2ecf20Sopenharmony_ci	struct radeon_device *rdev = inode->i_private;
10328c2ecf20Sopenharmony_ci	i_size_write(inode, rdev->mc.gtt_size);
10338c2ecf20Sopenharmony_ci	filep->private_data = inode->i_private;
10348c2ecf20Sopenharmony_ci	return 0;
10358c2ecf20Sopenharmony_ci}
10368c2ecf20Sopenharmony_ci
10378c2ecf20Sopenharmony_cistatic ssize_t radeon_ttm_gtt_read(struct file *f, char __user *buf,
10388c2ecf20Sopenharmony_ci				   size_t size, loff_t *pos)
10398c2ecf20Sopenharmony_ci{
10408c2ecf20Sopenharmony_ci	struct radeon_device *rdev = f->private_data;
10418c2ecf20Sopenharmony_ci	ssize_t result = 0;
10428c2ecf20Sopenharmony_ci	int r;
10438c2ecf20Sopenharmony_ci
10448c2ecf20Sopenharmony_ci	while (size) {
10458c2ecf20Sopenharmony_ci		loff_t p = *pos / PAGE_SIZE;
10468c2ecf20Sopenharmony_ci		unsigned off = *pos & ~PAGE_MASK;
10478c2ecf20Sopenharmony_ci		size_t cur_size = min_t(size_t, size, PAGE_SIZE - off);
10488c2ecf20Sopenharmony_ci		struct page *page;
10498c2ecf20Sopenharmony_ci		void *ptr;
10508c2ecf20Sopenharmony_ci
10518c2ecf20Sopenharmony_ci		if (p >= rdev->gart.num_cpu_pages)
10528c2ecf20Sopenharmony_ci			return result;
10538c2ecf20Sopenharmony_ci
10548c2ecf20Sopenharmony_ci		page = rdev->gart.pages[p];
10558c2ecf20Sopenharmony_ci		if (page) {
10568c2ecf20Sopenharmony_ci			ptr = kmap(page);
10578c2ecf20Sopenharmony_ci			ptr += off;
10588c2ecf20Sopenharmony_ci
10598c2ecf20Sopenharmony_ci			r = copy_to_user(buf, ptr, cur_size);
10608c2ecf20Sopenharmony_ci			kunmap(rdev->gart.pages[p]);
10618c2ecf20Sopenharmony_ci		} else
10628c2ecf20Sopenharmony_ci			r = clear_user(buf, cur_size);
10638c2ecf20Sopenharmony_ci
10648c2ecf20Sopenharmony_ci		if (r)
10658c2ecf20Sopenharmony_ci			return -EFAULT;
10668c2ecf20Sopenharmony_ci
10678c2ecf20Sopenharmony_ci		result += cur_size;
10688c2ecf20Sopenharmony_ci		buf += cur_size;
10698c2ecf20Sopenharmony_ci		*pos += cur_size;
10708c2ecf20Sopenharmony_ci		size -= cur_size;
10718c2ecf20Sopenharmony_ci	}
10728c2ecf20Sopenharmony_ci
10738c2ecf20Sopenharmony_ci	return result;
10748c2ecf20Sopenharmony_ci}
10758c2ecf20Sopenharmony_ci
10768c2ecf20Sopenharmony_cistatic const struct file_operations radeon_ttm_gtt_fops = {
10778c2ecf20Sopenharmony_ci	.owner = THIS_MODULE,
10788c2ecf20Sopenharmony_ci	.open = radeon_ttm_gtt_open,
10798c2ecf20Sopenharmony_ci	.read = radeon_ttm_gtt_read,
10808c2ecf20Sopenharmony_ci	.llseek = default_llseek
10818c2ecf20Sopenharmony_ci};
10828c2ecf20Sopenharmony_ci
10838c2ecf20Sopenharmony_ci#endif
10848c2ecf20Sopenharmony_ci
10858c2ecf20Sopenharmony_cistatic int radeon_ttm_debugfs_init(struct radeon_device *rdev)
10868c2ecf20Sopenharmony_ci{
10878c2ecf20Sopenharmony_ci#if defined(CONFIG_DEBUG_FS)
10888c2ecf20Sopenharmony_ci	unsigned count;
10898c2ecf20Sopenharmony_ci
10908c2ecf20Sopenharmony_ci	struct drm_minor *minor = rdev->ddev->primary;
10918c2ecf20Sopenharmony_ci	struct dentry *root = minor->debugfs_root;
10928c2ecf20Sopenharmony_ci
10938c2ecf20Sopenharmony_ci	rdev->mman.vram = debugfs_create_file("radeon_vram", S_IFREG | S_IRUGO,
10948c2ecf20Sopenharmony_ci					      root, rdev,
10958c2ecf20Sopenharmony_ci					      &radeon_ttm_vram_fops);
10968c2ecf20Sopenharmony_ci
10978c2ecf20Sopenharmony_ci	rdev->mman.gtt = debugfs_create_file("radeon_gtt", S_IFREG | S_IRUGO,
10988c2ecf20Sopenharmony_ci					     root, rdev, &radeon_ttm_gtt_fops);
10998c2ecf20Sopenharmony_ci
11008c2ecf20Sopenharmony_ci	count = ARRAY_SIZE(radeon_ttm_debugfs_list);
11018c2ecf20Sopenharmony_ci
11028c2ecf20Sopenharmony_ci#ifdef CONFIG_SWIOTLB
11038c2ecf20Sopenharmony_ci	if (!(rdev->need_swiotlb && swiotlb_nr_tbl()))
11048c2ecf20Sopenharmony_ci		--count;
11058c2ecf20Sopenharmony_ci#endif
11068c2ecf20Sopenharmony_ci
11078c2ecf20Sopenharmony_ci	return radeon_debugfs_add_files(rdev, radeon_ttm_debugfs_list, count);
11088c2ecf20Sopenharmony_ci#else
11098c2ecf20Sopenharmony_ci
11108c2ecf20Sopenharmony_ci	return 0;
11118c2ecf20Sopenharmony_ci#endif
11128c2ecf20Sopenharmony_ci}
11138c2ecf20Sopenharmony_ci
11148c2ecf20Sopenharmony_cistatic void radeon_ttm_debugfs_fini(struct radeon_device *rdev)
11158c2ecf20Sopenharmony_ci{
11168c2ecf20Sopenharmony_ci#if defined(CONFIG_DEBUG_FS)
11178c2ecf20Sopenharmony_ci
11188c2ecf20Sopenharmony_ci	debugfs_remove(rdev->mman.vram);
11198c2ecf20Sopenharmony_ci	rdev->mman.vram = NULL;
11208c2ecf20Sopenharmony_ci
11218c2ecf20Sopenharmony_ci	debugfs_remove(rdev->mman.gtt);
11228c2ecf20Sopenharmony_ci	rdev->mman.gtt = NULL;
11238c2ecf20Sopenharmony_ci#endif
11248c2ecf20Sopenharmony_ci}
1125