162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * Copyright 2009 Jerome Glisse.
362306a36Sopenharmony_ci * All Rights Reserved.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
662306a36Sopenharmony_ci * copy of this software and associated documentation files (the
762306a36Sopenharmony_ci * "Software"), to deal in the Software without restriction, including
862306a36Sopenharmony_ci * without limitation the rights to use, copy, modify, merge, publish,
962306a36Sopenharmony_ci * distribute, sub license, and/or sell copies of the Software, and to
1062306a36Sopenharmony_ci * permit persons to whom the Software is furnished to do so, subject to
1162306a36Sopenharmony_ci * the following conditions:
1262306a36Sopenharmony_ci *
1362306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1462306a36Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1562306a36Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
1662306a36Sopenharmony_ci * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
1762306a36Sopenharmony_ci * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
1862306a36Sopenharmony_ci * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
1962306a36Sopenharmony_ci * USE OR OTHER DEALINGS IN THE SOFTWARE.
2062306a36Sopenharmony_ci *
2162306a36Sopenharmony_ci * The above copyright notice and this permission notice (including the
2262306a36Sopenharmony_ci * next paragraph) shall be included in all copies or substantial portions
2362306a36Sopenharmony_ci * of the Software.
2462306a36Sopenharmony_ci *
2562306a36Sopenharmony_ci */
2662306a36Sopenharmony_ci/*
2762306a36Sopenharmony_ci * Authors:
2862306a36Sopenharmony_ci *    Jerome Glisse <glisse@freedesktop.org>
2962306a36Sopenharmony_ci *    Thomas Hellstrom <thomas-at-tungstengraphics-dot-com>
3062306a36Sopenharmony_ci *    Dave Airlie
3162306a36Sopenharmony_ci */
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci#include <linux/dma-mapping.h>
3462306a36Sopenharmony_ci#include <linux/iommu.h>
3562306a36Sopenharmony_ci#include <linux/pagemap.h>
3662306a36Sopenharmony_ci#include <linux/sched/task.h>
3762306a36Sopenharmony_ci#include <linux/sched/mm.h>
3862306a36Sopenharmony_ci#include <linux/seq_file.h>
3962306a36Sopenharmony_ci#include <linux/slab.h>
4062306a36Sopenharmony_ci#include <linux/swap.h>
4162306a36Sopenharmony_ci#include <linux/dma-buf.h>
4262306a36Sopenharmony_ci#include <linux/sizes.h>
4362306a36Sopenharmony_ci#include <linux/module.h>
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci#include <drm/drm_drv.h>
4662306a36Sopenharmony_ci#include <drm/ttm/ttm_bo.h>
4762306a36Sopenharmony_ci#include <drm/ttm/ttm_placement.h>
4862306a36Sopenharmony_ci#include <drm/ttm/ttm_range_manager.h>
4962306a36Sopenharmony_ci#include <drm/ttm/ttm_tt.h>
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci#include <drm/amdgpu_drm.h>
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci#include "amdgpu.h"
5462306a36Sopenharmony_ci#include "amdgpu_object.h"
5562306a36Sopenharmony_ci#include "amdgpu_trace.h"
5662306a36Sopenharmony_ci#include "amdgpu_amdkfd.h"
5762306a36Sopenharmony_ci#include "amdgpu_sdma.h"
5862306a36Sopenharmony_ci#include "amdgpu_ras.h"
5962306a36Sopenharmony_ci#include "amdgpu_hmm.h"
6062306a36Sopenharmony_ci#include "amdgpu_atomfirmware.h"
6162306a36Sopenharmony_ci#include "amdgpu_res_cursor.h"
6262306a36Sopenharmony_ci#include "bif/bif_4_1_d.h"
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ciMODULE_IMPORT_NS(DMA_BUF);
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci#define AMDGPU_TTM_VRAM_MAX_DW_READ	((size_t)128)
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_cistatic int amdgpu_ttm_backend_bind(struct ttm_device *bdev,
6962306a36Sopenharmony_ci				   struct ttm_tt *ttm,
7062306a36Sopenharmony_ci				   struct ttm_resource *bo_mem);
7162306a36Sopenharmony_cistatic void amdgpu_ttm_backend_unbind(struct ttm_device *bdev,
7262306a36Sopenharmony_ci				      struct ttm_tt *ttm);
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_cistatic int amdgpu_ttm_init_on_chip(struct amdgpu_device *adev,
7562306a36Sopenharmony_ci				    unsigned int type,
7662306a36Sopenharmony_ci				    uint64_t size_in_page)
7762306a36Sopenharmony_ci{
7862306a36Sopenharmony_ci	return ttm_range_man_init(&adev->mman.bdev, type,
7962306a36Sopenharmony_ci				  false, size_in_page);
8062306a36Sopenharmony_ci}
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci/**
8362306a36Sopenharmony_ci * amdgpu_evict_flags - Compute placement flags
8462306a36Sopenharmony_ci *
8562306a36Sopenharmony_ci * @bo: The buffer object to evict
8662306a36Sopenharmony_ci * @placement: Possible destination(s) for evicted BO
8762306a36Sopenharmony_ci *
8862306a36Sopenharmony_ci * Fill in placement data when ttm_bo_evict() is called
8962306a36Sopenharmony_ci */
9062306a36Sopenharmony_cistatic void amdgpu_evict_flags(struct ttm_buffer_object *bo,
9162306a36Sopenharmony_ci				struct ttm_placement *placement)
9262306a36Sopenharmony_ci{
9362306a36Sopenharmony_ci	struct amdgpu_device *adev = amdgpu_ttm_adev(bo->bdev);
9462306a36Sopenharmony_ci	struct amdgpu_bo *abo;
9562306a36Sopenharmony_ci	static const struct ttm_place placements = {
9662306a36Sopenharmony_ci		.fpfn = 0,
9762306a36Sopenharmony_ci		.lpfn = 0,
9862306a36Sopenharmony_ci		.mem_type = TTM_PL_SYSTEM,
9962306a36Sopenharmony_ci		.flags = 0
10062306a36Sopenharmony_ci	};
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci	/* Don't handle scatter gather BOs */
10362306a36Sopenharmony_ci	if (bo->type == ttm_bo_type_sg) {
10462306a36Sopenharmony_ci		placement->num_placement = 0;
10562306a36Sopenharmony_ci		placement->num_busy_placement = 0;
10662306a36Sopenharmony_ci		return;
10762306a36Sopenharmony_ci	}
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci	/* Object isn't an AMDGPU object so ignore */
11062306a36Sopenharmony_ci	if (!amdgpu_bo_is_amdgpu_bo(bo)) {
11162306a36Sopenharmony_ci		placement->placement = &placements;
11262306a36Sopenharmony_ci		placement->busy_placement = &placements;
11362306a36Sopenharmony_ci		placement->num_placement = 1;
11462306a36Sopenharmony_ci		placement->num_busy_placement = 1;
11562306a36Sopenharmony_ci		return;
11662306a36Sopenharmony_ci	}
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci	abo = ttm_to_amdgpu_bo(bo);
11962306a36Sopenharmony_ci	if (abo->flags & AMDGPU_GEM_CREATE_DISCARDABLE) {
12062306a36Sopenharmony_ci		placement->num_placement = 0;
12162306a36Sopenharmony_ci		placement->num_busy_placement = 0;
12262306a36Sopenharmony_ci		return;
12362306a36Sopenharmony_ci	}
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci	switch (bo->resource->mem_type) {
12662306a36Sopenharmony_ci	case AMDGPU_PL_GDS:
12762306a36Sopenharmony_ci	case AMDGPU_PL_GWS:
12862306a36Sopenharmony_ci	case AMDGPU_PL_OA:
12962306a36Sopenharmony_ci	case AMDGPU_PL_DOORBELL:
13062306a36Sopenharmony_ci		placement->num_placement = 0;
13162306a36Sopenharmony_ci		placement->num_busy_placement = 0;
13262306a36Sopenharmony_ci		return;
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci	case TTM_PL_VRAM:
13562306a36Sopenharmony_ci		if (!adev->mman.buffer_funcs_enabled) {
13662306a36Sopenharmony_ci			/* Move to system memory */
13762306a36Sopenharmony_ci			amdgpu_bo_placement_from_domain(abo, AMDGPU_GEM_DOMAIN_CPU);
13862306a36Sopenharmony_ci		} else if (!amdgpu_gmc_vram_full_visible(&adev->gmc) &&
13962306a36Sopenharmony_ci			   !(abo->flags & AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED) &&
14062306a36Sopenharmony_ci			   amdgpu_bo_in_cpu_visible_vram(abo)) {
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci			/* Try evicting to the CPU inaccessible part of VRAM
14362306a36Sopenharmony_ci			 * first, but only set GTT as busy placement, so this
14462306a36Sopenharmony_ci			 * BO will be evicted to GTT rather than causing other
14562306a36Sopenharmony_ci			 * BOs to be evicted from VRAM
14662306a36Sopenharmony_ci			 */
14762306a36Sopenharmony_ci			amdgpu_bo_placement_from_domain(abo, AMDGPU_GEM_DOMAIN_VRAM |
14862306a36Sopenharmony_ci							AMDGPU_GEM_DOMAIN_GTT |
14962306a36Sopenharmony_ci							AMDGPU_GEM_DOMAIN_CPU);
15062306a36Sopenharmony_ci			abo->placements[0].fpfn = adev->gmc.visible_vram_size >> PAGE_SHIFT;
15162306a36Sopenharmony_ci			abo->placements[0].lpfn = 0;
15262306a36Sopenharmony_ci			abo->placement.busy_placement = &abo->placements[1];
15362306a36Sopenharmony_ci			abo->placement.num_busy_placement = 1;
15462306a36Sopenharmony_ci		} else {
15562306a36Sopenharmony_ci			/* Move to GTT memory */
15662306a36Sopenharmony_ci			amdgpu_bo_placement_from_domain(abo, AMDGPU_GEM_DOMAIN_GTT |
15762306a36Sopenharmony_ci							AMDGPU_GEM_DOMAIN_CPU);
15862306a36Sopenharmony_ci		}
15962306a36Sopenharmony_ci		break;
16062306a36Sopenharmony_ci	case TTM_PL_TT:
16162306a36Sopenharmony_ci	case AMDGPU_PL_PREEMPT:
16262306a36Sopenharmony_ci	default:
16362306a36Sopenharmony_ci		amdgpu_bo_placement_from_domain(abo, AMDGPU_GEM_DOMAIN_CPU);
16462306a36Sopenharmony_ci		break;
16562306a36Sopenharmony_ci	}
16662306a36Sopenharmony_ci	*placement = abo->placement;
16762306a36Sopenharmony_ci}
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_ci/**
17062306a36Sopenharmony_ci * amdgpu_ttm_map_buffer - Map memory into the GART windows
17162306a36Sopenharmony_ci * @bo: buffer object to map
17262306a36Sopenharmony_ci * @mem: memory object to map
17362306a36Sopenharmony_ci * @mm_cur: range to map
17462306a36Sopenharmony_ci * @window: which GART window to use
17562306a36Sopenharmony_ci * @ring: DMA ring to use for the copy
17662306a36Sopenharmony_ci * @tmz: if we should setup a TMZ enabled mapping
17762306a36Sopenharmony_ci * @size: in number of bytes to map, out number of bytes mapped
17862306a36Sopenharmony_ci * @addr: resulting address inside the MC address space
17962306a36Sopenharmony_ci *
18062306a36Sopenharmony_ci * Setup one of the GART windows to access a specific piece of memory or return
18162306a36Sopenharmony_ci * the physical address for local memory.
18262306a36Sopenharmony_ci */
18362306a36Sopenharmony_cistatic int amdgpu_ttm_map_buffer(struct ttm_buffer_object *bo,
18462306a36Sopenharmony_ci				 struct ttm_resource *mem,
18562306a36Sopenharmony_ci				 struct amdgpu_res_cursor *mm_cur,
18662306a36Sopenharmony_ci				 unsigned int window, struct amdgpu_ring *ring,
18762306a36Sopenharmony_ci				 bool tmz, uint64_t *size, uint64_t *addr)
18862306a36Sopenharmony_ci{
18962306a36Sopenharmony_ci	struct amdgpu_device *adev = ring->adev;
19062306a36Sopenharmony_ci	unsigned int offset, num_pages, num_dw, num_bytes;
19162306a36Sopenharmony_ci	uint64_t src_addr, dst_addr;
19262306a36Sopenharmony_ci	struct amdgpu_job *job;
19362306a36Sopenharmony_ci	void *cpu_addr;
19462306a36Sopenharmony_ci	uint64_t flags;
19562306a36Sopenharmony_ci	unsigned int i;
19662306a36Sopenharmony_ci	int r;
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci	BUG_ON(adev->mman.buffer_funcs->copy_max_bytes <
19962306a36Sopenharmony_ci	       AMDGPU_GTT_MAX_TRANSFER_SIZE * 8);
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci	if (WARN_ON(mem->mem_type == AMDGPU_PL_PREEMPT))
20262306a36Sopenharmony_ci		return -EINVAL;
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	/* Map only what can't be accessed directly */
20562306a36Sopenharmony_ci	if (!tmz && mem->start != AMDGPU_BO_INVALID_OFFSET) {
20662306a36Sopenharmony_ci		*addr = amdgpu_ttm_domain_start(adev, mem->mem_type) +
20762306a36Sopenharmony_ci			mm_cur->start;
20862306a36Sopenharmony_ci		return 0;
20962306a36Sopenharmony_ci	}
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci	/*
21362306a36Sopenharmony_ci	 * If start begins at an offset inside the page, then adjust the size
21462306a36Sopenharmony_ci	 * and addr accordingly
21562306a36Sopenharmony_ci	 */
21662306a36Sopenharmony_ci	offset = mm_cur->start & ~PAGE_MASK;
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_ci	num_pages = PFN_UP(*size + offset);
21962306a36Sopenharmony_ci	num_pages = min_t(uint32_t, num_pages, AMDGPU_GTT_MAX_TRANSFER_SIZE);
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ci	*size = min(*size, (uint64_t)num_pages * PAGE_SIZE - offset);
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ci	*addr = adev->gmc.gart_start;
22462306a36Sopenharmony_ci	*addr += (u64)window * AMDGPU_GTT_MAX_TRANSFER_SIZE *
22562306a36Sopenharmony_ci		AMDGPU_GPU_PAGE_SIZE;
22662306a36Sopenharmony_ci	*addr += offset;
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci	num_dw = ALIGN(adev->mman.buffer_funcs->copy_num_dw, 8);
22962306a36Sopenharmony_ci	num_bytes = num_pages * 8 * AMDGPU_GPU_PAGES_IN_CPU_PAGE;
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci	r = amdgpu_job_alloc_with_ib(adev, &adev->mman.high_pr,
23262306a36Sopenharmony_ci				     AMDGPU_FENCE_OWNER_UNDEFINED,
23362306a36Sopenharmony_ci				     num_dw * 4 + num_bytes,
23462306a36Sopenharmony_ci				     AMDGPU_IB_POOL_DELAYED, &job);
23562306a36Sopenharmony_ci	if (r)
23662306a36Sopenharmony_ci		return r;
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci	src_addr = num_dw * 4;
23962306a36Sopenharmony_ci	src_addr += job->ibs[0].gpu_addr;
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci	dst_addr = amdgpu_bo_gpu_offset(adev->gart.bo);
24262306a36Sopenharmony_ci	dst_addr += window * AMDGPU_GTT_MAX_TRANSFER_SIZE * 8;
24362306a36Sopenharmony_ci	amdgpu_emit_copy_buffer(adev, &job->ibs[0], src_addr,
24462306a36Sopenharmony_ci				dst_addr, num_bytes, false);
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ci	amdgpu_ring_pad_ib(ring, &job->ibs[0]);
24762306a36Sopenharmony_ci	WARN_ON(job->ibs[0].length_dw > num_dw);
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci	flags = amdgpu_ttm_tt_pte_flags(adev, bo->ttm, mem);
25062306a36Sopenharmony_ci	if (tmz)
25162306a36Sopenharmony_ci		flags |= AMDGPU_PTE_TMZ;
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci	cpu_addr = &job->ibs[0].ptr[num_dw];
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci	if (mem->mem_type == TTM_PL_TT) {
25662306a36Sopenharmony_ci		dma_addr_t *dma_addr;
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_ci		dma_addr = &bo->ttm->dma_address[mm_cur->start >> PAGE_SHIFT];
25962306a36Sopenharmony_ci		amdgpu_gart_map(adev, 0, num_pages, dma_addr, flags, cpu_addr);
26062306a36Sopenharmony_ci	} else {
26162306a36Sopenharmony_ci		dma_addr_t dma_address;
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci		dma_address = mm_cur->start;
26462306a36Sopenharmony_ci		dma_address += adev->vm_manager.vram_base_offset;
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ci		for (i = 0; i < num_pages; ++i) {
26762306a36Sopenharmony_ci			amdgpu_gart_map(adev, i << PAGE_SHIFT, 1, &dma_address,
26862306a36Sopenharmony_ci					flags, cpu_addr);
26962306a36Sopenharmony_ci			dma_address += PAGE_SIZE;
27062306a36Sopenharmony_ci		}
27162306a36Sopenharmony_ci	}
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci	dma_fence_put(amdgpu_job_submit(job));
27462306a36Sopenharmony_ci	return 0;
27562306a36Sopenharmony_ci}
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_ci/**
27862306a36Sopenharmony_ci * amdgpu_ttm_copy_mem_to_mem - Helper function for copy
27962306a36Sopenharmony_ci * @adev: amdgpu device
28062306a36Sopenharmony_ci * @src: buffer/address where to read from
28162306a36Sopenharmony_ci * @dst: buffer/address where to write to
28262306a36Sopenharmony_ci * @size: number of bytes to copy
28362306a36Sopenharmony_ci * @tmz: if a secure copy should be used
28462306a36Sopenharmony_ci * @resv: resv object to sync to
28562306a36Sopenharmony_ci * @f: Returns the last fence if multiple jobs are submitted.
28662306a36Sopenharmony_ci *
28762306a36Sopenharmony_ci * The function copies @size bytes from {src->mem + src->offset} to
28862306a36Sopenharmony_ci * {dst->mem + dst->offset}. src->bo and dst->bo could be same BO for a
28962306a36Sopenharmony_ci * move and different for a BO to BO copy.
29062306a36Sopenharmony_ci *
29162306a36Sopenharmony_ci */
29262306a36Sopenharmony_ciint amdgpu_ttm_copy_mem_to_mem(struct amdgpu_device *adev,
29362306a36Sopenharmony_ci			       const struct amdgpu_copy_mem *src,
29462306a36Sopenharmony_ci			       const struct amdgpu_copy_mem *dst,
29562306a36Sopenharmony_ci			       uint64_t size, bool tmz,
29662306a36Sopenharmony_ci			       struct dma_resv *resv,
29762306a36Sopenharmony_ci			       struct dma_fence **f)
29862306a36Sopenharmony_ci{
29962306a36Sopenharmony_ci	struct amdgpu_ring *ring = adev->mman.buffer_funcs_ring;
30062306a36Sopenharmony_ci	struct amdgpu_res_cursor src_mm, dst_mm;
30162306a36Sopenharmony_ci	struct dma_fence *fence = NULL;
30262306a36Sopenharmony_ci	int r = 0;
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci	if (!adev->mman.buffer_funcs_enabled) {
30562306a36Sopenharmony_ci		DRM_ERROR("Trying to move memory with ring turned off.\n");
30662306a36Sopenharmony_ci		return -EINVAL;
30762306a36Sopenharmony_ci	}
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci	amdgpu_res_first(src->mem, src->offset, size, &src_mm);
31062306a36Sopenharmony_ci	amdgpu_res_first(dst->mem, dst->offset, size, &dst_mm);
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci	mutex_lock(&adev->mman.gtt_window_lock);
31362306a36Sopenharmony_ci	while (src_mm.remaining) {
31462306a36Sopenharmony_ci		uint64_t from, to, cur_size;
31562306a36Sopenharmony_ci		struct dma_fence *next;
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci		/* Never copy more than 256MiB at once to avoid a timeout */
31862306a36Sopenharmony_ci		cur_size = min3(src_mm.size, dst_mm.size, 256ULL << 20);
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ci		/* Map src to window 0 and dst to window 1. */
32162306a36Sopenharmony_ci		r = amdgpu_ttm_map_buffer(src->bo, src->mem, &src_mm,
32262306a36Sopenharmony_ci					  0, ring, tmz, &cur_size, &from);
32362306a36Sopenharmony_ci		if (r)
32462306a36Sopenharmony_ci			goto error;
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ci		r = amdgpu_ttm_map_buffer(dst->bo, dst->mem, &dst_mm,
32762306a36Sopenharmony_ci					  1, ring, tmz, &cur_size, &to);
32862306a36Sopenharmony_ci		if (r)
32962306a36Sopenharmony_ci			goto error;
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_ci		r = amdgpu_copy_buffer(ring, from, to, cur_size,
33262306a36Sopenharmony_ci				       resv, &next, false, true, tmz);
33362306a36Sopenharmony_ci		if (r)
33462306a36Sopenharmony_ci			goto error;
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ci		dma_fence_put(fence);
33762306a36Sopenharmony_ci		fence = next;
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_ci		amdgpu_res_next(&src_mm, cur_size);
34062306a36Sopenharmony_ci		amdgpu_res_next(&dst_mm, cur_size);
34162306a36Sopenharmony_ci	}
34262306a36Sopenharmony_cierror:
34362306a36Sopenharmony_ci	mutex_unlock(&adev->mman.gtt_window_lock);
34462306a36Sopenharmony_ci	if (f)
34562306a36Sopenharmony_ci		*f = dma_fence_get(fence);
34662306a36Sopenharmony_ci	dma_fence_put(fence);
34762306a36Sopenharmony_ci	return r;
34862306a36Sopenharmony_ci}
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci/*
35162306a36Sopenharmony_ci * amdgpu_move_blit - Copy an entire buffer to another buffer
35262306a36Sopenharmony_ci *
35362306a36Sopenharmony_ci * This is a helper called by amdgpu_bo_move() and amdgpu_move_vram_ram() to
35462306a36Sopenharmony_ci * help move buffers to and from VRAM.
35562306a36Sopenharmony_ci */
35662306a36Sopenharmony_cistatic int amdgpu_move_blit(struct ttm_buffer_object *bo,
35762306a36Sopenharmony_ci			    bool evict,
35862306a36Sopenharmony_ci			    struct ttm_resource *new_mem,
35962306a36Sopenharmony_ci			    struct ttm_resource *old_mem)
36062306a36Sopenharmony_ci{
36162306a36Sopenharmony_ci	struct amdgpu_device *adev = amdgpu_ttm_adev(bo->bdev);
36262306a36Sopenharmony_ci	struct amdgpu_bo *abo = ttm_to_amdgpu_bo(bo);
36362306a36Sopenharmony_ci	struct amdgpu_copy_mem src, dst;
36462306a36Sopenharmony_ci	struct dma_fence *fence = NULL;
36562306a36Sopenharmony_ci	int r;
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci	src.bo = bo;
36862306a36Sopenharmony_ci	dst.bo = bo;
36962306a36Sopenharmony_ci	src.mem = old_mem;
37062306a36Sopenharmony_ci	dst.mem = new_mem;
37162306a36Sopenharmony_ci	src.offset = 0;
37262306a36Sopenharmony_ci	dst.offset = 0;
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ci	r = amdgpu_ttm_copy_mem_to_mem(adev, &src, &dst,
37562306a36Sopenharmony_ci				       new_mem->size,
37662306a36Sopenharmony_ci				       amdgpu_bo_encrypted(abo),
37762306a36Sopenharmony_ci				       bo->base.resv, &fence);
37862306a36Sopenharmony_ci	if (r)
37962306a36Sopenharmony_ci		goto error;
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_ci	/* clear the space being freed */
38262306a36Sopenharmony_ci	if (old_mem->mem_type == TTM_PL_VRAM &&
38362306a36Sopenharmony_ci	    (abo->flags & AMDGPU_GEM_CREATE_VRAM_WIPE_ON_RELEASE)) {
38462306a36Sopenharmony_ci		struct dma_fence *wipe_fence = NULL;
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ci		r = amdgpu_fill_buffer(abo, AMDGPU_POISON, NULL, &wipe_fence,
38762306a36Sopenharmony_ci					false);
38862306a36Sopenharmony_ci		if (r) {
38962306a36Sopenharmony_ci			goto error;
39062306a36Sopenharmony_ci		} else if (wipe_fence) {
39162306a36Sopenharmony_ci			dma_fence_put(fence);
39262306a36Sopenharmony_ci			fence = wipe_fence;
39362306a36Sopenharmony_ci		}
39462306a36Sopenharmony_ci	}
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci	/* Always block for VM page tables before committing the new location */
39762306a36Sopenharmony_ci	if (bo->type == ttm_bo_type_kernel)
39862306a36Sopenharmony_ci		r = ttm_bo_move_accel_cleanup(bo, fence, true, false, new_mem);
39962306a36Sopenharmony_ci	else
40062306a36Sopenharmony_ci		r = ttm_bo_move_accel_cleanup(bo, fence, evict, true, new_mem);
40162306a36Sopenharmony_ci	dma_fence_put(fence);
40262306a36Sopenharmony_ci	return r;
40362306a36Sopenharmony_ci
40462306a36Sopenharmony_cierror:
40562306a36Sopenharmony_ci	if (fence)
40662306a36Sopenharmony_ci		dma_fence_wait(fence, false);
40762306a36Sopenharmony_ci	dma_fence_put(fence);
40862306a36Sopenharmony_ci	return r;
40962306a36Sopenharmony_ci}
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_ci/*
41262306a36Sopenharmony_ci * amdgpu_mem_visible - Check that memory can be accessed by ttm_bo_move_memcpy
41362306a36Sopenharmony_ci *
41462306a36Sopenharmony_ci * Called by amdgpu_bo_move()
41562306a36Sopenharmony_ci */
41662306a36Sopenharmony_cistatic bool amdgpu_mem_visible(struct amdgpu_device *adev,
41762306a36Sopenharmony_ci			       struct ttm_resource *mem)
41862306a36Sopenharmony_ci{
41962306a36Sopenharmony_ci	u64 mem_size = (u64)mem->size;
42062306a36Sopenharmony_ci	struct amdgpu_res_cursor cursor;
42162306a36Sopenharmony_ci	u64 end;
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci	if (mem->mem_type == TTM_PL_SYSTEM ||
42462306a36Sopenharmony_ci	    mem->mem_type == TTM_PL_TT)
42562306a36Sopenharmony_ci		return true;
42662306a36Sopenharmony_ci	if (mem->mem_type != TTM_PL_VRAM)
42762306a36Sopenharmony_ci		return false;
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_ci	amdgpu_res_first(mem, 0, mem_size, &cursor);
43062306a36Sopenharmony_ci	end = cursor.start + cursor.size;
43162306a36Sopenharmony_ci	while (cursor.remaining) {
43262306a36Sopenharmony_ci		amdgpu_res_next(&cursor, cursor.size);
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci		if (!cursor.remaining)
43562306a36Sopenharmony_ci			break;
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ci		/* ttm_resource_ioremap only supports contiguous memory */
43862306a36Sopenharmony_ci		if (end != cursor.start)
43962306a36Sopenharmony_ci			return false;
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_ci		end = cursor.start + cursor.size;
44262306a36Sopenharmony_ci	}
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_ci	return end <= adev->gmc.visible_vram_size;
44562306a36Sopenharmony_ci}
44662306a36Sopenharmony_ci
44762306a36Sopenharmony_ci/*
44862306a36Sopenharmony_ci * amdgpu_bo_move - Move a buffer object to a new memory location
44962306a36Sopenharmony_ci *
45062306a36Sopenharmony_ci * Called by ttm_bo_handle_move_mem()
45162306a36Sopenharmony_ci */
45262306a36Sopenharmony_cistatic int amdgpu_bo_move(struct ttm_buffer_object *bo, bool evict,
45362306a36Sopenharmony_ci			  struct ttm_operation_ctx *ctx,
45462306a36Sopenharmony_ci			  struct ttm_resource *new_mem,
45562306a36Sopenharmony_ci			  struct ttm_place *hop)
45662306a36Sopenharmony_ci{
45762306a36Sopenharmony_ci	struct amdgpu_device *adev;
45862306a36Sopenharmony_ci	struct amdgpu_bo *abo;
45962306a36Sopenharmony_ci	struct ttm_resource *old_mem = bo->resource;
46062306a36Sopenharmony_ci	int r;
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_ci	if (new_mem->mem_type == TTM_PL_TT ||
46362306a36Sopenharmony_ci	    new_mem->mem_type == AMDGPU_PL_PREEMPT) {
46462306a36Sopenharmony_ci		r = amdgpu_ttm_backend_bind(bo->bdev, bo->ttm, new_mem);
46562306a36Sopenharmony_ci		if (r)
46662306a36Sopenharmony_ci			return r;
46762306a36Sopenharmony_ci	}
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_ci	abo = ttm_to_amdgpu_bo(bo);
47062306a36Sopenharmony_ci	adev = amdgpu_ttm_adev(bo->bdev);
47162306a36Sopenharmony_ci
47262306a36Sopenharmony_ci	if (!old_mem || (old_mem->mem_type == TTM_PL_SYSTEM &&
47362306a36Sopenharmony_ci			 bo->ttm == NULL)) {
47462306a36Sopenharmony_ci		ttm_bo_move_null(bo, new_mem);
47562306a36Sopenharmony_ci		goto out;
47662306a36Sopenharmony_ci	}
47762306a36Sopenharmony_ci	if (old_mem->mem_type == TTM_PL_SYSTEM &&
47862306a36Sopenharmony_ci	    (new_mem->mem_type == TTM_PL_TT ||
47962306a36Sopenharmony_ci	     new_mem->mem_type == AMDGPU_PL_PREEMPT)) {
48062306a36Sopenharmony_ci		ttm_bo_move_null(bo, new_mem);
48162306a36Sopenharmony_ci		goto out;
48262306a36Sopenharmony_ci	}
48362306a36Sopenharmony_ci	if ((old_mem->mem_type == TTM_PL_TT ||
48462306a36Sopenharmony_ci	     old_mem->mem_type == AMDGPU_PL_PREEMPT) &&
48562306a36Sopenharmony_ci	    new_mem->mem_type == TTM_PL_SYSTEM) {
48662306a36Sopenharmony_ci		r = ttm_bo_wait_ctx(bo, ctx);
48762306a36Sopenharmony_ci		if (r)
48862306a36Sopenharmony_ci			return r;
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci		amdgpu_ttm_backend_unbind(bo->bdev, bo->ttm);
49162306a36Sopenharmony_ci		ttm_resource_free(bo, &bo->resource);
49262306a36Sopenharmony_ci		ttm_bo_assign_mem(bo, new_mem);
49362306a36Sopenharmony_ci		goto out;
49462306a36Sopenharmony_ci	}
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_ci	if (old_mem->mem_type == AMDGPU_PL_GDS ||
49762306a36Sopenharmony_ci	    old_mem->mem_type == AMDGPU_PL_GWS ||
49862306a36Sopenharmony_ci	    old_mem->mem_type == AMDGPU_PL_OA ||
49962306a36Sopenharmony_ci	    old_mem->mem_type == AMDGPU_PL_DOORBELL ||
50062306a36Sopenharmony_ci	    new_mem->mem_type == AMDGPU_PL_GDS ||
50162306a36Sopenharmony_ci	    new_mem->mem_type == AMDGPU_PL_GWS ||
50262306a36Sopenharmony_ci	    new_mem->mem_type == AMDGPU_PL_OA ||
50362306a36Sopenharmony_ci	    new_mem->mem_type == AMDGPU_PL_DOORBELL) {
50462306a36Sopenharmony_ci		/* Nothing to save here */
50562306a36Sopenharmony_ci		ttm_bo_move_null(bo, new_mem);
50662306a36Sopenharmony_ci		goto out;
50762306a36Sopenharmony_ci	}
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_ci	if (bo->type == ttm_bo_type_device &&
51062306a36Sopenharmony_ci	    new_mem->mem_type == TTM_PL_VRAM &&
51162306a36Sopenharmony_ci	    old_mem->mem_type != TTM_PL_VRAM) {
51262306a36Sopenharmony_ci		/* amdgpu_bo_fault_reserve_notify will re-set this if the CPU
51362306a36Sopenharmony_ci		 * accesses the BO after it's moved.
51462306a36Sopenharmony_ci		 */
51562306a36Sopenharmony_ci		abo->flags &= ~AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED;
51662306a36Sopenharmony_ci	}
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_ci	if (adev->mman.buffer_funcs_enabled) {
51962306a36Sopenharmony_ci		if (((old_mem->mem_type == TTM_PL_SYSTEM &&
52062306a36Sopenharmony_ci		      new_mem->mem_type == TTM_PL_VRAM) ||
52162306a36Sopenharmony_ci		     (old_mem->mem_type == TTM_PL_VRAM &&
52262306a36Sopenharmony_ci		      new_mem->mem_type == TTM_PL_SYSTEM))) {
52362306a36Sopenharmony_ci			hop->fpfn = 0;
52462306a36Sopenharmony_ci			hop->lpfn = 0;
52562306a36Sopenharmony_ci			hop->mem_type = TTM_PL_TT;
52662306a36Sopenharmony_ci			hop->flags = TTM_PL_FLAG_TEMPORARY;
52762306a36Sopenharmony_ci			return -EMULTIHOP;
52862306a36Sopenharmony_ci		}
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_ci		r = amdgpu_move_blit(bo, evict, new_mem, old_mem);
53162306a36Sopenharmony_ci	} else {
53262306a36Sopenharmony_ci		r = -ENODEV;
53362306a36Sopenharmony_ci	}
53462306a36Sopenharmony_ci
53562306a36Sopenharmony_ci	if (r) {
53662306a36Sopenharmony_ci		/* Check that all memory is CPU accessible */
53762306a36Sopenharmony_ci		if (!amdgpu_mem_visible(adev, old_mem) ||
53862306a36Sopenharmony_ci		    !amdgpu_mem_visible(adev, new_mem)) {
53962306a36Sopenharmony_ci			pr_err("Move buffer fallback to memcpy unavailable\n");
54062306a36Sopenharmony_ci			return r;
54162306a36Sopenharmony_ci		}
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_ci		r = ttm_bo_move_memcpy(bo, ctx, new_mem);
54462306a36Sopenharmony_ci		if (r)
54562306a36Sopenharmony_ci			return r;
54662306a36Sopenharmony_ci	}
54762306a36Sopenharmony_ci
54862306a36Sopenharmony_ci	trace_amdgpu_bo_move(abo, new_mem->mem_type, old_mem->mem_type);
54962306a36Sopenharmony_ciout:
55062306a36Sopenharmony_ci	/* update statistics */
55162306a36Sopenharmony_ci	atomic64_add(bo->base.size, &adev->num_bytes_moved);
55262306a36Sopenharmony_ci	amdgpu_bo_move_notify(bo, evict);
55362306a36Sopenharmony_ci	return 0;
55462306a36Sopenharmony_ci}
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_ci/*
55762306a36Sopenharmony_ci * amdgpu_ttm_io_mem_reserve - Reserve a block of memory during a fault
55862306a36Sopenharmony_ci *
55962306a36Sopenharmony_ci * Called by ttm_mem_io_reserve() ultimately via ttm_bo_vm_fault()
56062306a36Sopenharmony_ci */
56162306a36Sopenharmony_cistatic int amdgpu_ttm_io_mem_reserve(struct ttm_device *bdev,
56262306a36Sopenharmony_ci				     struct ttm_resource *mem)
56362306a36Sopenharmony_ci{
56462306a36Sopenharmony_ci	struct amdgpu_device *adev = amdgpu_ttm_adev(bdev);
56562306a36Sopenharmony_ci	size_t bus_size = (size_t)mem->size;
56662306a36Sopenharmony_ci
56762306a36Sopenharmony_ci	switch (mem->mem_type) {
56862306a36Sopenharmony_ci	case TTM_PL_SYSTEM:
56962306a36Sopenharmony_ci		/* system memory */
57062306a36Sopenharmony_ci		return 0;
57162306a36Sopenharmony_ci	case TTM_PL_TT:
57262306a36Sopenharmony_ci	case AMDGPU_PL_PREEMPT:
57362306a36Sopenharmony_ci		break;
57462306a36Sopenharmony_ci	case TTM_PL_VRAM:
57562306a36Sopenharmony_ci		mem->bus.offset = mem->start << PAGE_SHIFT;
57662306a36Sopenharmony_ci		/* check if it's visible */
57762306a36Sopenharmony_ci		if ((mem->bus.offset + bus_size) > adev->gmc.visible_vram_size)
57862306a36Sopenharmony_ci			return -EINVAL;
57962306a36Sopenharmony_ci
58062306a36Sopenharmony_ci		if (adev->mman.aper_base_kaddr &&
58162306a36Sopenharmony_ci		    mem->placement & TTM_PL_FLAG_CONTIGUOUS)
58262306a36Sopenharmony_ci			mem->bus.addr = (u8 *)adev->mman.aper_base_kaddr +
58362306a36Sopenharmony_ci					mem->bus.offset;
58462306a36Sopenharmony_ci
58562306a36Sopenharmony_ci		mem->bus.offset += adev->gmc.aper_base;
58662306a36Sopenharmony_ci		mem->bus.is_iomem = true;
58762306a36Sopenharmony_ci		break;
58862306a36Sopenharmony_ci	case AMDGPU_PL_DOORBELL:
58962306a36Sopenharmony_ci		mem->bus.offset = mem->start << PAGE_SHIFT;
59062306a36Sopenharmony_ci		mem->bus.offset += adev->doorbell.base;
59162306a36Sopenharmony_ci		mem->bus.is_iomem = true;
59262306a36Sopenharmony_ci		mem->bus.caching = ttm_uncached;
59362306a36Sopenharmony_ci		break;
59462306a36Sopenharmony_ci	default:
59562306a36Sopenharmony_ci		return -EINVAL;
59662306a36Sopenharmony_ci	}
59762306a36Sopenharmony_ci	return 0;
59862306a36Sopenharmony_ci}
59962306a36Sopenharmony_ci
60062306a36Sopenharmony_cistatic unsigned long amdgpu_ttm_io_mem_pfn(struct ttm_buffer_object *bo,
60162306a36Sopenharmony_ci					   unsigned long page_offset)
60262306a36Sopenharmony_ci{
60362306a36Sopenharmony_ci	struct amdgpu_device *adev = amdgpu_ttm_adev(bo->bdev);
60462306a36Sopenharmony_ci	struct amdgpu_res_cursor cursor;
60562306a36Sopenharmony_ci
60662306a36Sopenharmony_ci	amdgpu_res_first(bo->resource, (u64)page_offset << PAGE_SHIFT, 0,
60762306a36Sopenharmony_ci			 &cursor);
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_ci	if (bo->resource->mem_type == AMDGPU_PL_DOORBELL)
61062306a36Sopenharmony_ci		return ((uint64_t)(adev->doorbell.base + cursor.start)) >> PAGE_SHIFT;
61162306a36Sopenharmony_ci
61262306a36Sopenharmony_ci	return (adev->gmc.aper_base + cursor.start) >> PAGE_SHIFT;
61362306a36Sopenharmony_ci}
61462306a36Sopenharmony_ci
61562306a36Sopenharmony_ci/**
61662306a36Sopenharmony_ci * amdgpu_ttm_domain_start - Returns GPU start address
61762306a36Sopenharmony_ci * @adev: amdgpu device object
61862306a36Sopenharmony_ci * @type: type of the memory
61962306a36Sopenharmony_ci *
62062306a36Sopenharmony_ci * Returns:
62162306a36Sopenharmony_ci * GPU start address of a memory domain
62262306a36Sopenharmony_ci */
62362306a36Sopenharmony_ci
62462306a36Sopenharmony_ciuint64_t amdgpu_ttm_domain_start(struct amdgpu_device *adev, uint32_t type)
62562306a36Sopenharmony_ci{
62662306a36Sopenharmony_ci	switch (type) {
62762306a36Sopenharmony_ci	case TTM_PL_TT:
62862306a36Sopenharmony_ci		return adev->gmc.gart_start;
62962306a36Sopenharmony_ci	case TTM_PL_VRAM:
63062306a36Sopenharmony_ci		return adev->gmc.vram_start;
63162306a36Sopenharmony_ci	}
63262306a36Sopenharmony_ci
63362306a36Sopenharmony_ci	return 0;
63462306a36Sopenharmony_ci}
63562306a36Sopenharmony_ci
63662306a36Sopenharmony_ci/*
63762306a36Sopenharmony_ci * TTM backend functions.
63862306a36Sopenharmony_ci */
63962306a36Sopenharmony_cistruct amdgpu_ttm_tt {
64062306a36Sopenharmony_ci	struct ttm_tt	ttm;
64162306a36Sopenharmony_ci	struct drm_gem_object	*gobj;
64262306a36Sopenharmony_ci	u64			offset;
64362306a36Sopenharmony_ci	uint64_t		userptr;
64462306a36Sopenharmony_ci	struct task_struct	*usertask;
64562306a36Sopenharmony_ci	uint32_t		userflags;
64662306a36Sopenharmony_ci	bool			bound;
64762306a36Sopenharmony_ci	int32_t			pool_id;
64862306a36Sopenharmony_ci};
64962306a36Sopenharmony_ci
65062306a36Sopenharmony_ci#define ttm_to_amdgpu_ttm_tt(ptr)	container_of(ptr, struct amdgpu_ttm_tt, ttm)
65162306a36Sopenharmony_ci
65262306a36Sopenharmony_ci#ifdef CONFIG_DRM_AMDGPU_USERPTR
65362306a36Sopenharmony_ci/*
65462306a36Sopenharmony_ci * amdgpu_ttm_tt_get_user_pages - get device accessible pages that back user
65562306a36Sopenharmony_ci * memory and start HMM tracking CPU page table update
65662306a36Sopenharmony_ci *
65762306a36Sopenharmony_ci * Calling function must call amdgpu_ttm_tt_userptr_range_done() once and only
65862306a36Sopenharmony_ci * once afterwards to stop HMM tracking
65962306a36Sopenharmony_ci */
66062306a36Sopenharmony_ciint amdgpu_ttm_tt_get_user_pages(struct amdgpu_bo *bo, struct page **pages,
66162306a36Sopenharmony_ci				 struct hmm_range **range)
66262306a36Sopenharmony_ci{
66362306a36Sopenharmony_ci	struct ttm_tt *ttm = bo->tbo.ttm;
66462306a36Sopenharmony_ci	struct amdgpu_ttm_tt *gtt = ttm_to_amdgpu_ttm_tt(ttm);
66562306a36Sopenharmony_ci	unsigned long start = gtt->userptr;
66662306a36Sopenharmony_ci	struct vm_area_struct *vma;
66762306a36Sopenharmony_ci	struct mm_struct *mm;
66862306a36Sopenharmony_ci	bool readonly;
66962306a36Sopenharmony_ci	int r = 0;
67062306a36Sopenharmony_ci
67162306a36Sopenharmony_ci	/* Make sure get_user_pages_done() can cleanup gracefully */
67262306a36Sopenharmony_ci	*range = NULL;
67362306a36Sopenharmony_ci
67462306a36Sopenharmony_ci	mm = bo->notifier.mm;
67562306a36Sopenharmony_ci	if (unlikely(!mm)) {
67662306a36Sopenharmony_ci		DRM_DEBUG_DRIVER("BO is not registered?\n");
67762306a36Sopenharmony_ci		return -EFAULT;
67862306a36Sopenharmony_ci	}
67962306a36Sopenharmony_ci
68062306a36Sopenharmony_ci	if (!mmget_not_zero(mm)) /* Happens during process shutdown */
68162306a36Sopenharmony_ci		return -ESRCH;
68262306a36Sopenharmony_ci
68362306a36Sopenharmony_ci	mmap_read_lock(mm);
68462306a36Sopenharmony_ci	vma = vma_lookup(mm, start);
68562306a36Sopenharmony_ci	if (unlikely(!vma)) {
68662306a36Sopenharmony_ci		r = -EFAULT;
68762306a36Sopenharmony_ci		goto out_unlock;
68862306a36Sopenharmony_ci	}
68962306a36Sopenharmony_ci	if (unlikely((gtt->userflags & AMDGPU_GEM_USERPTR_ANONONLY) &&
69062306a36Sopenharmony_ci		vma->vm_file)) {
69162306a36Sopenharmony_ci		r = -EPERM;
69262306a36Sopenharmony_ci		goto out_unlock;
69362306a36Sopenharmony_ci	}
69462306a36Sopenharmony_ci
69562306a36Sopenharmony_ci	readonly = amdgpu_ttm_tt_is_readonly(ttm);
69662306a36Sopenharmony_ci	r = amdgpu_hmm_range_get_pages(&bo->notifier, start, ttm->num_pages,
69762306a36Sopenharmony_ci				       readonly, NULL, pages, range);
69862306a36Sopenharmony_ciout_unlock:
69962306a36Sopenharmony_ci	mmap_read_unlock(mm);
70062306a36Sopenharmony_ci	if (r)
70162306a36Sopenharmony_ci		pr_debug("failed %d to get user pages 0x%lx\n", r, start);
70262306a36Sopenharmony_ci
70362306a36Sopenharmony_ci	mmput(mm);
70462306a36Sopenharmony_ci
70562306a36Sopenharmony_ci	return r;
70662306a36Sopenharmony_ci}
70762306a36Sopenharmony_ci
70862306a36Sopenharmony_ci/* amdgpu_ttm_tt_discard_user_pages - Discard range and pfn array allocations
70962306a36Sopenharmony_ci */
71062306a36Sopenharmony_civoid amdgpu_ttm_tt_discard_user_pages(struct ttm_tt *ttm,
71162306a36Sopenharmony_ci				      struct hmm_range *range)
71262306a36Sopenharmony_ci{
71362306a36Sopenharmony_ci	struct amdgpu_ttm_tt *gtt = (void *)ttm;
71462306a36Sopenharmony_ci
71562306a36Sopenharmony_ci	if (gtt && gtt->userptr && range)
71662306a36Sopenharmony_ci		amdgpu_hmm_range_get_pages_done(range);
71762306a36Sopenharmony_ci}
71862306a36Sopenharmony_ci
71962306a36Sopenharmony_ci/*
72062306a36Sopenharmony_ci * amdgpu_ttm_tt_get_user_pages_done - stop HMM track the CPU page table change
72162306a36Sopenharmony_ci * Check if the pages backing this ttm range have been invalidated
72262306a36Sopenharmony_ci *
72362306a36Sopenharmony_ci * Returns: true if pages are still valid
72462306a36Sopenharmony_ci */
72562306a36Sopenharmony_cibool amdgpu_ttm_tt_get_user_pages_done(struct ttm_tt *ttm,
72662306a36Sopenharmony_ci				       struct hmm_range *range)
72762306a36Sopenharmony_ci{
72862306a36Sopenharmony_ci	struct amdgpu_ttm_tt *gtt = ttm_to_amdgpu_ttm_tt(ttm);
72962306a36Sopenharmony_ci
73062306a36Sopenharmony_ci	if (!gtt || !gtt->userptr || !range)
73162306a36Sopenharmony_ci		return false;
73262306a36Sopenharmony_ci
73362306a36Sopenharmony_ci	DRM_DEBUG_DRIVER("user_pages_done 0x%llx pages 0x%x\n",
73462306a36Sopenharmony_ci		gtt->userptr, ttm->num_pages);
73562306a36Sopenharmony_ci
73662306a36Sopenharmony_ci	WARN_ONCE(!range->hmm_pfns, "No user pages to check\n");
73762306a36Sopenharmony_ci
73862306a36Sopenharmony_ci	return !amdgpu_hmm_range_get_pages_done(range);
73962306a36Sopenharmony_ci}
74062306a36Sopenharmony_ci#endif
74162306a36Sopenharmony_ci
74262306a36Sopenharmony_ci/*
74362306a36Sopenharmony_ci * amdgpu_ttm_tt_set_user_pages - Copy pages in, putting old pages as necessary.
74462306a36Sopenharmony_ci *
74562306a36Sopenharmony_ci * Called by amdgpu_cs_list_validate(). This creates the page list
74662306a36Sopenharmony_ci * that backs user memory and will ultimately be mapped into the device
74762306a36Sopenharmony_ci * address space.
74862306a36Sopenharmony_ci */
74962306a36Sopenharmony_civoid amdgpu_ttm_tt_set_user_pages(struct ttm_tt *ttm, struct page **pages)
75062306a36Sopenharmony_ci{
75162306a36Sopenharmony_ci	unsigned long i;
75262306a36Sopenharmony_ci
75362306a36Sopenharmony_ci	for (i = 0; i < ttm->num_pages; ++i)
75462306a36Sopenharmony_ci		ttm->pages[i] = pages ? pages[i] : NULL;
75562306a36Sopenharmony_ci}
75662306a36Sopenharmony_ci
75762306a36Sopenharmony_ci/*
75862306a36Sopenharmony_ci * amdgpu_ttm_tt_pin_userptr - prepare the sg table with the user pages
75962306a36Sopenharmony_ci *
76062306a36Sopenharmony_ci * Called by amdgpu_ttm_backend_bind()
76162306a36Sopenharmony_ci **/
76262306a36Sopenharmony_cistatic int amdgpu_ttm_tt_pin_userptr(struct ttm_device *bdev,
76362306a36Sopenharmony_ci				     struct ttm_tt *ttm)
76462306a36Sopenharmony_ci{
76562306a36Sopenharmony_ci	struct amdgpu_device *adev = amdgpu_ttm_adev(bdev);
76662306a36Sopenharmony_ci	struct amdgpu_ttm_tt *gtt = ttm_to_amdgpu_ttm_tt(ttm);
76762306a36Sopenharmony_ci	int write = !(gtt->userflags & AMDGPU_GEM_USERPTR_READONLY);
76862306a36Sopenharmony_ci	enum dma_data_direction direction = write ?
76962306a36Sopenharmony_ci		DMA_BIDIRECTIONAL : DMA_TO_DEVICE;
77062306a36Sopenharmony_ci	int r;
77162306a36Sopenharmony_ci
77262306a36Sopenharmony_ci	/* Allocate an SG array and squash pages into it */
77362306a36Sopenharmony_ci	r = sg_alloc_table_from_pages(ttm->sg, ttm->pages, ttm->num_pages, 0,
77462306a36Sopenharmony_ci				      (u64)ttm->num_pages << PAGE_SHIFT,
77562306a36Sopenharmony_ci				      GFP_KERNEL);
77662306a36Sopenharmony_ci	if (r)
77762306a36Sopenharmony_ci		goto release_sg;
77862306a36Sopenharmony_ci
77962306a36Sopenharmony_ci	/* Map SG to device */
78062306a36Sopenharmony_ci	r = dma_map_sgtable(adev->dev, ttm->sg, direction, 0);
78162306a36Sopenharmony_ci	if (r)
78262306a36Sopenharmony_ci		goto release_sg;
78362306a36Sopenharmony_ci
78462306a36Sopenharmony_ci	/* convert SG to linear array of pages and dma addresses */
78562306a36Sopenharmony_ci	drm_prime_sg_to_dma_addr_array(ttm->sg, gtt->ttm.dma_address,
78662306a36Sopenharmony_ci				       ttm->num_pages);
78762306a36Sopenharmony_ci
78862306a36Sopenharmony_ci	return 0;
78962306a36Sopenharmony_ci
79062306a36Sopenharmony_cirelease_sg:
79162306a36Sopenharmony_ci	kfree(ttm->sg);
79262306a36Sopenharmony_ci	ttm->sg = NULL;
79362306a36Sopenharmony_ci	return r;
79462306a36Sopenharmony_ci}
79562306a36Sopenharmony_ci
79662306a36Sopenharmony_ci/*
79762306a36Sopenharmony_ci * amdgpu_ttm_tt_unpin_userptr - Unpin and unmap userptr pages
79862306a36Sopenharmony_ci */
79962306a36Sopenharmony_cistatic void amdgpu_ttm_tt_unpin_userptr(struct ttm_device *bdev,
80062306a36Sopenharmony_ci					struct ttm_tt *ttm)
80162306a36Sopenharmony_ci{
80262306a36Sopenharmony_ci	struct amdgpu_device *adev = amdgpu_ttm_adev(bdev);
80362306a36Sopenharmony_ci	struct amdgpu_ttm_tt *gtt = ttm_to_amdgpu_ttm_tt(ttm);
80462306a36Sopenharmony_ci	int write = !(gtt->userflags & AMDGPU_GEM_USERPTR_READONLY);
80562306a36Sopenharmony_ci	enum dma_data_direction direction = write ?
80662306a36Sopenharmony_ci		DMA_BIDIRECTIONAL : DMA_TO_DEVICE;
80762306a36Sopenharmony_ci
80862306a36Sopenharmony_ci	/* double check that we don't free the table twice */
80962306a36Sopenharmony_ci	if (!ttm->sg || !ttm->sg->sgl)
81062306a36Sopenharmony_ci		return;
81162306a36Sopenharmony_ci
81262306a36Sopenharmony_ci	/* unmap the pages mapped to the device */
81362306a36Sopenharmony_ci	dma_unmap_sgtable(adev->dev, ttm->sg, direction, 0);
81462306a36Sopenharmony_ci	sg_free_table(ttm->sg);
81562306a36Sopenharmony_ci}
81662306a36Sopenharmony_ci
81762306a36Sopenharmony_ci/*
81862306a36Sopenharmony_ci * total_pages is constructed as MQD0+CtrlStack0 + MQD1+CtrlStack1 + ...
81962306a36Sopenharmony_ci * MQDn+CtrlStackn where n is the number of XCCs per partition.
82062306a36Sopenharmony_ci * pages_per_xcc is the size of one MQD+CtrlStack. The first page is MQD
82162306a36Sopenharmony_ci * and uses memory type default, UC. The rest of pages_per_xcc are
82262306a36Sopenharmony_ci * Ctrl stack and modify their memory type to NC.
82362306a36Sopenharmony_ci */
82462306a36Sopenharmony_cistatic void amdgpu_ttm_gart_bind_gfx9_mqd(struct amdgpu_device *adev,
82562306a36Sopenharmony_ci				struct ttm_tt *ttm, uint64_t flags)
82662306a36Sopenharmony_ci{
82762306a36Sopenharmony_ci	struct amdgpu_ttm_tt *gtt = (void *)ttm;
82862306a36Sopenharmony_ci	uint64_t total_pages = ttm->num_pages;
82962306a36Sopenharmony_ci	int num_xcc = max(1U, adev->gfx.num_xcc_per_xcp);
83062306a36Sopenharmony_ci	uint64_t page_idx, pages_per_xcc;
83162306a36Sopenharmony_ci	int i;
83262306a36Sopenharmony_ci	uint64_t ctrl_flags = (flags & ~AMDGPU_PTE_MTYPE_VG10_MASK) |
83362306a36Sopenharmony_ci			AMDGPU_PTE_MTYPE_VG10(AMDGPU_MTYPE_NC);
83462306a36Sopenharmony_ci
83562306a36Sopenharmony_ci	pages_per_xcc = total_pages;
83662306a36Sopenharmony_ci	do_div(pages_per_xcc, num_xcc);
83762306a36Sopenharmony_ci
83862306a36Sopenharmony_ci	for (i = 0, page_idx = 0; i < num_xcc; i++, page_idx += pages_per_xcc) {
83962306a36Sopenharmony_ci		/* MQD page: use default flags */
84062306a36Sopenharmony_ci		amdgpu_gart_bind(adev,
84162306a36Sopenharmony_ci				gtt->offset + (page_idx << PAGE_SHIFT),
84262306a36Sopenharmony_ci				1, &gtt->ttm.dma_address[page_idx], flags);
84362306a36Sopenharmony_ci		/*
84462306a36Sopenharmony_ci		 * Ctrl pages - modify the memory type to NC (ctrl_flags) from
84562306a36Sopenharmony_ci		 * the second page of the BO onward.
84662306a36Sopenharmony_ci		 */
84762306a36Sopenharmony_ci		amdgpu_gart_bind(adev,
84862306a36Sopenharmony_ci				gtt->offset + ((page_idx + 1) << PAGE_SHIFT),
84962306a36Sopenharmony_ci				pages_per_xcc - 1,
85062306a36Sopenharmony_ci				&gtt->ttm.dma_address[page_idx + 1],
85162306a36Sopenharmony_ci				ctrl_flags);
85262306a36Sopenharmony_ci	}
85362306a36Sopenharmony_ci}
85462306a36Sopenharmony_ci
85562306a36Sopenharmony_cistatic void amdgpu_ttm_gart_bind(struct amdgpu_device *adev,
85662306a36Sopenharmony_ci				 struct ttm_buffer_object *tbo,
85762306a36Sopenharmony_ci				 uint64_t flags)
85862306a36Sopenharmony_ci{
85962306a36Sopenharmony_ci	struct amdgpu_bo *abo = ttm_to_amdgpu_bo(tbo);
86062306a36Sopenharmony_ci	struct ttm_tt *ttm = tbo->ttm;
86162306a36Sopenharmony_ci	struct amdgpu_ttm_tt *gtt = ttm_to_amdgpu_ttm_tt(ttm);
86262306a36Sopenharmony_ci
86362306a36Sopenharmony_ci	if (amdgpu_bo_encrypted(abo))
86462306a36Sopenharmony_ci		flags |= AMDGPU_PTE_TMZ;
86562306a36Sopenharmony_ci
86662306a36Sopenharmony_ci	if (abo->flags & AMDGPU_GEM_CREATE_CP_MQD_GFX9) {
86762306a36Sopenharmony_ci		amdgpu_ttm_gart_bind_gfx9_mqd(adev, ttm, flags);
86862306a36Sopenharmony_ci	} else {
86962306a36Sopenharmony_ci		amdgpu_gart_bind(adev, gtt->offset, ttm->num_pages,
87062306a36Sopenharmony_ci				 gtt->ttm.dma_address, flags);
87162306a36Sopenharmony_ci	}
87262306a36Sopenharmony_ci}
87362306a36Sopenharmony_ci
87462306a36Sopenharmony_ci/*
87562306a36Sopenharmony_ci * amdgpu_ttm_backend_bind - Bind GTT memory
87662306a36Sopenharmony_ci *
87762306a36Sopenharmony_ci * Called by ttm_tt_bind() on behalf of ttm_bo_handle_move_mem().
87862306a36Sopenharmony_ci * This handles binding GTT memory to the device address space.
87962306a36Sopenharmony_ci */
88062306a36Sopenharmony_cistatic int amdgpu_ttm_backend_bind(struct ttm_device *bdev,
88162306a36Sopenharmony_ci				   struct ttm_tt *ttm,
88262306a36Sopenharmony_ci				   struct ttm_resource *bo_mem)
88362306a36Sopenharmony_ci{
88462306a36Sopenharmony_ci	struct amdgpu_device *adev = amdgpu_ttm_adev(bdev);
88562306a36Sopenharmony_ci	struct amdgpu_ttm_tt *gtt = ttm_to_amdgpu_ttm_tt(ttm);
88662306a36Sopenharmony_ci	uint64_t flags;
88762306a36Sopenharmony_ci	int r;
88862306a36Sopenharmony_ci
88962306a36Sopenharmony_ci	if (!bo_mem)
89062306a36Sopenharmony_ci		return -EINVAL;
89162306a36Sopenharmony_ci
89262306a36Sopenharmony_ci	if (gtt->bound)
89362306a36Sopenharmony_ci		return 0;
89462306a36Sopenharmony_ci
89562306a36Sopenharmony_ci	if (gtt->userptr) {
89662306a36Sopenharmony_ci		r = amdgpu_ttm_tt_pin_userptr(bdev, ttm);
89762306a36Sopenharmony_ci		if (r) {
89862306a36Sopenharmony_ci			DRM_ERROR("failed to pin userptr\n");
89962306a36Sopenharmony_ci			return r;
90062306a36Sopenharmony_ci		}
90162306a36Sopenharmony_ci	} else if (ttm->page_flags & TTM_TT_FLAG_EXTERNAL) {
90262306a36Sopenharmony_ci		if (!ttm->sg) {
90362306a36Sopenharmony_ci			struct dma_buf_attachment *attach;
90462306a36Sopenharmony_ci			struct sg_table *sgt;
90562306a36Sopenharmony_ci
90662306a36Sopenharmony_ci			attach = gtt->gobj->import_attach;
90762306a36Sopenharmony_ci			sgt = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL);
90862306a36Sopenharmony_ci			if (IS_ERR(sgt))
90962306a36Sopenharmony_ci				return PTR_ERR(sgt);
91062306a36Sopenharmony_ci
91162306a36Sopenharmony_ci			ttm->sg = sgt;
91262306a36Sopenharmony_ci		}
91362306a36Sopenharmony_ci
91462306a36Sopenharmony_ci		drm_prime_sg_to_dma_addr_array(ttm->sg, gtt->ttm.dma_address,
91562306a36Sopenharmony_ci					       ttm->num_pages);
91662306a36Sopenharmony_ci	}
91762306a36Sopenharmony_ci
91862306a36Sopenharmony_ci	if (!ttm->num_pages) {
91962306a36Sopenharmony_ci		WARN(1, "nothing to bind %u pages for mreg %p back %p!\n",
92062306a36Sopenharmony_ci		     ttm->num_pages, bo_mem, ttm);
92162306a36Sopenharmony_ci	}
92262306a36Sopenharmony_ci
92362306a36Sopenharmony_ci	if (bo_mem->mem_type != TTM_PL_TT ||
92462306a36Sopenharmony_ci	    !amdgpu_gtt_mgr_has_gart_addr(bo_mem)) {
92562306a36Sopenharmony_ci		gtt->offset = AMDGPU_BO_INVALID_OFFSET;
92662306a36Sopenharmony_ci		return 0;
92762306a36Sopenharmony_ci	}
92862306a36Sopenharmony_ci
92962306a36Sopenharmony_ci	/* compute PTE flags relevant to this BO memory */
93062306a36Sopenharmony_ci	flags = amdgpu_ttm_tt_pte_flags(adev, ttm, bo_mem);
93162306a36Sopenharmony_ci
93262306a36Sopenharmony_ci	/* bind pages into GART page tables */
93362306a36Sopenharmony_ci	gtt->offset = (u64)bo_mem->start << PAGE_SHIFT;
93462306a36Sopenharmony_ci	amdgpu_gart_bind(adev, gtt->offset, ttm->num_pages,
93562306a36Sopenharmony_ci			 gtt->ttm.dma_address, flags);
93662306a36Sopenharmony_ci	gtt->bound = true;
93762306a36Sopenharmony_ci	return 0;
93862306a36Sopenharmony_ci}
93962306a36Sopenharmony_ci
94062306a36Sopenharmony_ci/*
94162306a36Sopenharmony_ci * amdgpu_ttm_alloc_gart - Make sure buffer object is accessible either
94262306a36Sopenharmony_ci * through AGP or GART aperture.
94362306a36Sopenharmony_ci *
94462306a36Sopenharmony_ci * If bo is accessible through AGP aperture, then use AGP aperture
94562306a36Sopenharmony_ci * to access bo; otherwise allocate logical space in GART aperture
94662306a36Sopenharmony_ci * and map bo to GART aperture.
94762306a36Sopenharmony_ci */
94862306a36Sopenharmony_ciint amdgpu_ttm_alloc_gart(struct ttm_buffer_object *bo)
94962306a36Sopenharmony_ci{
95062306a36Sopenharmony_ci	struct amdgpu_device *adev = amdgpu_ttm_adev(bo->bdev);
95162306a36Sopenharmony_ci	struct ttm_operation_ctx ctx = { false, false };
95262306a36Sopenharmony_ci	struct amdgpu_ttm_tt *gtt = ttm_to_amdgpu_ttm_tt(bo->ttm);
95362306a36Sopenharmony_ci	struct ttm_placement placement;
95462306a36Sopenharmony_ci	struct ttm_place placements;
95562306a36Sopenharmony_ci	struct ttm_resource *tmp;
95662306a36Sopenharmony_ci	uint64_t addr, flags;
95762306a36Sopenharmony_ci	int r;
95862306a36Sopenharmony_ci
95962306a36Sopenharmony_ci	if (bo->resource->start != AMDGPU_BO_INVALID_OFFSET)
96062306a36Sopenharmony_ci		return 0;
96162306a36Sopenharmony_ci
96262306a36Sopenharmony_ci	addr = amdgpu_gmc_agp_addr(bo);
96362306a36Sopenharmony_ci	if (addr != AMDGPU_BO_INVALID_OFFSET) {
96462306a36Sopenharmony_ci		bo->resource->start = addr >> PAGE_SHIFT;
96562306a36Sopenharmony_ci		return 0;
96662306a36Sopenharmony_ci	}
96762306a36Sopenharmony_ci
96862306a36Sopenharmony_ci	/* allocate GART space */
96962306a36Sopenharmony_ci	placement.num_placement = 1;
97062306a36Sopenharmony_ci	placement.placement = &placements;
97162306a36Sopenharmony_ci	placement.num_busy_placement = 1;
97262306a36Sopenharmony_ci	placement.busy_placement = &placements;
97362306a36Sopenharmony_ci	placements.fpfn = 0;
97462306a36Sopenharmony_ci	placements.lpfn = adev->gmc.gart_size >> PAGE_SHIFT;
97562306a36Sopenharmony_ci	placements.mem_type = TTM_PL_TT;
97662306a36Sopenharmony_ci	placements.flags = bo->resource->placement;
97762306a36Sopenharmony_ci
97862306a36Sopenharmony_ci	r = ttm_bo_mem_space(bo, &placement, &tmp, &ctx);
97962306a36Sopenharmony_ci	if (unlikely(r))
98062306a36Sopenharmony_ci		return r;
98162306a36Sopenharmony_ci
98262306a36Sopenharmony_ci	/* compute PTE flags for this buffer object */
98362306a36Sopenharmony_ci	flags = amdgpu_ttm_tt_pte_flags(adev, bo->ttm, tmp);
98462306a36Sopenharmony_ci
98562306a36Sopenharmony_ci	/* Bind pages */
98662306a36Sopenharmony_ci	gtt->offset = (u64)tmp->start << PAGE_SHIFT;
98762306a36Sopenharmony_ci	amdgpu_ttm_gart_bind(adev, bo, flags);
98862306a36Sopenharmony_ci	amdgpu_gart_invalidate_tlb(adev);
98962306a36Sopenharmony_ci	ttm_resource_free(bo, &bo->resource);
99062306a36Sopenharmony_ci	ttm_bo_assign_mem(bo, tmp);
99162306a36Sopenharmony_ci
99262306a36Sopenharmony_ci	return 0;
99362306a36Sopenharmony_ci}
99462306a36Sopenharmony_ci
99562306a36Sopenharmony_ci/*
99662306a36Sopenharmony_ci * amdgpu_ttm_recover_gart - Rebind GTT pages
99762306a36Sopenharmony_ci *
99862306a36Sopenharmony_ci * Called by amdgpu_gtt_mgr_recover() from amdgpu_device_reset() to
99962306a36Sopenharmony_ci * rebind GTT pages during a GPU reset.
100062306a36Sopenharmony_ci */
100162306a36Sopenharmony_civoid amdgpu_ttm_recover_gart(struct ttm_buffer_object *tbo)
100262306a36Sopenharmony_ci{
100362306a36Sopenharmony_ci	struct amdgpu_device *adev = amdgpu_ttm_adev(tbo->bdev);
100462306a36Sopenharmony_ci	uint64_t flags;
100562306a36Sopenharmony_ci
100662306a36Sopenharmony_ci	if (!tbo->ttm)
100762306a36Sopenharmony_ci		return;
100862306a36Sopenharmony_ci
100962306a36Sopenharmony_ci	flags = amdgpu_ttm_tt_pte_flags(adev, tbo->ttm, tbo->resource);
101062306a36Sopenharmony_ci	amdgpu_ttm_gart_bind(adev, tbo, flags);
101162306a36Sopenharmony_ci}
101262306a36Sopenharmony_ci
101362306a36Sopenharmony_ci/*
101462306a36Sopenharmony_ci * amdgpu_ttm_backend_unbind - Unbind GTT mapped pages
101562306a36Sopenharmony_ci *
101662306a36Sopenharmony_ci * Called by ttm_tt_unbind() on behalf of ttm_bo_move_ttm() and
101762306a36Sopenharmony_ci * ttm_tt_destroy().
101862306a36Sopenharmony_ci */
101962306a36Sopenharmony_cistatic void amdgpu_ttm_backend_unbind(struct ttm_device *bdev,
102062306a36Sopenharmony_ci				      struct ttm_tt *ttm)
102162306a36Sopenharmony_ci{
102262306a36Sopenharmony_ci	struct amdgpu_device *adev = amdgpu_ttm_adev(bdev);
102362306a36Sopenharmony_ci	struct amdgpu_ttm_tt *gtt = ttm_to_amdgpu_ttm_tt(ttm);
102462306a36Sopenharmony_ci
102562306a36Sopenharmony_ci	/* if the pages have userptr pinning then clear that first */
102662306a36Sopenharmony_ci	if (gtt->userptr) {
102762306a36Sopenharmony_ci		amdgpu_ttm_tt_unpin_userptr(bdev, ttm);
102862306a36Sopenharmony_ci	} else if (ttm->sg && gtt->gobj->import_attach) {
102962306a36Sopenharmony_ci		struct dma_buf_attachment *attach;
103062306a36Sopenharmony_ci
103162306a36Sopenharmony_ci		attach = gtt->gobj->import_attach;
103262306a36Sopenharmony_ci		dma_buf_unmap_attachment(attach, ttm->sg, DMA_BIDIRECTIONAL);
103362306a36Sopenharmony_ci		ttm->sg = NULL;
103462306a36Sopenharmony_ci	}
103562306a36Sopenharmony_ci
103662306a36Sopenharmony_ci	if (!gtt->bound)
103762306a36Sopenharmony_ci		return;
103862306a36Sopenharmony_ci
103962306a36Sopenharmony_ci	if (gtt->offset == AMDGPU_BO_INVALID_OFFSET)
104062306a36Sopenharmony_ci		return;
104162306a36Sopenharmony_ci
104262306a36Sopenharmony_ci	/* unbind shouldn't be done for GDS/GWS/OA in ttm_bo_clean_mm */
104362306a36Sopenharmony_ci	amdgpu_gart_unbind(adev, gtt->offset, ttm->num_pages);
104462306a36Sopenharmony_ci	gtt->bound = false;
104562306a36Sopenharmony_ci}
104662306a36Sopenharmony_ci
104762306a36Sopenharmony_cistatic void amdgpu_ttm_backend_destroy(struct ttm_device *bdev,
104862306a36Sopenharmony_ci				       struct ttm_tt *ttm)
104962306a36Sopenharmony_ci{
105062306a36Sopenharmony_ci	struct amdgpu_ttm_tt *gtt = ttm_to_amdgpu_ttm_tt(ttm);
105162306a36Sopenharmony_ci
105262306a36Sopenharmony_ci	if (gtt->usertask)
105362306a36Sopenharmony_ci		put_task_struct(gtt->usertask);
105462306a36Sopenharmony_ci
105562306a36Sopenharmony_ci	ttm_tt_fini(&gtt->ttm);
105662306a36Sopenharmony_ci	kfree(gtt);
105762306a36Sopenharmony_ci}
105862306a36Sopenharmony_ci
105962306a36Sopenharmony_ci/**
106062306a36Sopenharmony_ci * amdgpu_ttm_tt_create - Create a ttm_tt object for a given BO
106162306a36Sopenharmony_ci *
106262306a36Sopenharmony_ci * @bo: The buffer object to create a GTT ttm_tt object around
106362306a36Sopenharmony_ci * @page_flags: Page flags to be added to the ttm_tt object
106462306a36Sopenharmony_ci *
106562306a36Sopenharmony_ci * Called by ttm_tt_create().
106662306a36Sopenharmony_ci */
106762306a36Sopenharmony_cistatic struct ttm_tt *amdgpu_ttm_tt_create(struct ttm_buffer_object *bo,
106862306a36Sopenharmony_ci					   uint32_t page_flags)
106962306a36Sopenharmony_ci{
107062306a36Sopenharmony_ci	struct amdgpu_device *adev = amdgpu_ttm_adev(bo->bdev);
107162306a36Sopenharmony_ci	struct amdgpu_bo *abo = ttm_to_amdgpu_bo(bo);
107262306a36Sopenharmony_ci	struct amdgpu_ttm_tt *gtt;
107362306a36Sopenharmony_ci	enum ttm_caching caching;
107462306a36Sopenharmony_ci
107562306a36Sopenharmony_ci	gtt = kzalloc(sizeof(struct amdgpu_ttm_tt), GFP_KERNEL);
107662306a36Sopenharmony_ci	if (!gtt)
107762306a36Sopenharmony_ci		return NULL;
107862306a36Sopenharmony_ci
107962306a36Sopenharmony_ci	gtt->gobj = &bo->base;
108062306a36Sopenharmony_ci	if (adev->gmc.mem_partitions && abo->xcp_id >= 0)
108162306a36Sopenharmony_ci		gtt->pool_id = KFD_XCP_MEM_ID(adev, abo->xcp_id);
108262306a36Sopenharmony_ci	else
108362306a36Sopenharmony_ci		gtt->pool_id = abo->xcp_id;
108462306a36Sopenharmony_ci
108562306a36Sopenharmony_ci	if (abo->flags & AMDGPU_GEM_CREATE_CPU_GTT_USWC)
108662306a36Sopenharmony_ci		caching = ttm_write_combined;
108762306a36Sopenharmony_ci	else
108862306a36Sopenharmony_ci		caching = ttm_cached;
108962306a36Sopenharmony_ci
109062306a36Sopenharmony_ci	/* allocate space for the uninitialized page entries */
109162306a36Sopenharmony_ci	if (ttm_sg_tt_init(&gtt->ttm, bo, page_flags, caching)) {
109262306a36Sopenharmony_ci		kfree(gtt);
109362306a36Sopenharmony_ci		return NULL;
109462306a36Sopenharmony_ci	}
109562306a36Sopenharmony_ci	return &gtt->ttm;
109662306a36Sopenharmony_ci}
109762306a36Sopenharmony_ci
109862306a36Sopenharmony_ci/*
109962306a36Sopenharmony_ci * amdgpu_ttm_tt_populate - Map GTT pages visible to the device
110062306a36Sopenharmony_ci *
110162306a36Sopenharmony_ci * Map the pages of a ttm_tt object to an address space visible
110262306a36Sopenharmony_ci * to the underlying device.
110362306a36Sopenharmony_ci */
110462306a36Sopenharmony_cistatic int amdgpu_ttm_tt_populate(struct ttm_device *bdev,
110562306a36Sopenharmony_ci				  struct ttm_tt *ttm,
110662306a36Sopenharmony_ci				  struct ttm_operation_ctx *ctx)
110762306a36Sopenharmony_ci{
110862306a36Sopenharmony_ci	struct amdgpu_device *adev = amdgpu_ttm_adev(bdev);
110962306a36Sopenharmony_ci	struct amdgpu_ttm_tt *gtt = ttm_to_amdgpu_ttm_tt(ttm);
111062306a36Sopenharmony_ci	struct ttm_pool *pool;
111162306a36Sopenharmony_ci	pgoff_t i;
111262306a36Sopenharmony_ci	int ret;
111362306a36Sopenharmony_ci
111462306a36Sopenharmony_ci	/* user pages are bound by amdgpu_ttm_tt_pin_userptr() */
111562306a36Sopenharmony_ci	if (gtt->userptr) {
111662306a36Sopenharmony_ci		ttm->sg = kzalloc(sizeof(struct sg_table), GFP_KERNEL);
111762306a36Sopenharmony_ci		if (!ttm->sg)
111862306a36Sopenharmony_ci			return -ENOMEM;
111962306a36Sopenharmony_ci		return 0;
112062306a36Sopenharmony_ci	}
112162306a36Sopenharmony_ci
112262306a36Sopenharmony_ci	if (ttm->page_flags & TTM_TT_FLAG_EXTERNAL)
112362306a36Sopenharmony_ci		return 0;
112462306a36Sopenharmony_ci
112562306a36Sopenharmony_ci	if (adev->mman.ttm_pools && gtt->pool_id >= 0)
112662306a36Sopenharmony_ci		pool = &adev->mman.ttm_pools[gtt->pool_id];
112762306a36Sopenharmony_ci	else
112862306a36Sopenharmony_ci		pool = &adev->mman.bdev.pool;
112962306a36Sopenharmony_ci	ret = ttm_pool_alloc(pool, ttm, ctx);
113062306a36Sopenharmony_ci	if (ret)
113162306a36Sopenharmony_ci		return ret;
113262306a36Sopenharmony_ci
113362306a36Sopenharmony_ci	for (i = 0; i < ttm->num_pages; ++i)
113462306a36Sopenharmony_ci		ttm->pages[i]->mapping = bdev->dev_mapping;
113562306a36Sopenharmony_ci
113662306a36Sopenharmony_ci	return 0;
113762306a36Sopenharmony_ci}
113862306a36Sopenharmony_ci
113962306a36Sopenharmony_ci/*
114062306a36Sopenharmony_ci * amdgpu_ttm_tt_unpopulate - unmap GTT pages and unpopulate page arrays
114162306a36Sopenharmony_ci *
114262306a36Sopenharmony_ci * Unmaps pages of a ttm_tt object from the device address space and
114362306a36Sopenharmony_ci * unpopulates the page array backing it.
114462306a36Sopenharmony_ci */
114562306a36Sopenharmony_cistatic void amdgpu_ttm_tt_unpopulate(struct ttm_device *bdev,
114662306a36Sopenharmony_ci				     struct ttm_tt *ttm)
114762306a36Sopenharmony_ci{
114862306a36Sopenharmony_ci	struct amdgpu_ttm_tt *gtt = ttm_to_amdgpu_ttm_tt(ttm);
114962306a36Sopenharmony_ci	struct amdgpu_device *adev;
115062306a36Sopenharmony_ci	struct ttm_pool *pool;
115162306a36Sopenharmony_ci	pgoff_t i;
115262306a36Sopenharmony_ci
115362306a36Sopenharmony_ci	amdgpu_ttm_backend_unbind(bdev, ttm);
115462306a36Sopenharmony_ci
115562306a36Sopenharmony_ci	if (gtt->userptr) {
115662306a36Sopenharmony_ci		amdgpu_ttm_tt_set_user_pages(ttm, NULL);
115762306a36Sopenharmony_ci		kfree(ttm->sg);
115862306a36Sopenharmony_ci		ttm->sg = NULL;
115962306a36Sopenharmony_ci		return;
116062306a36Sopenharmony_ci	}
116162306a36Sopenharmony_ci
116262306a36Sopenharmony_ci	if (ttm->page_flags & TTM_TT_FLAG_EXTERNAL)
116362306a36Sopenharmony_ci		return;
116462306a36Sopenharmony_ci
116562306a36Sopenharmony_ci	for (i = 0; i < ttm->num_pages; ++i)
116662306a36Sopenharmony_ci		ttm->pages[i]->mapping = NULL;
116762306a36Sopenharmony_ci
116862306a36Sopenharmony_ci	adev = amdgpu_ttm_adev(bdev);
116962306a36Sopenharmony_ci
117062306a36Sopenharmony_ci	if (adev->mman.ttm_pools && gtt->pool_id >= 0)
117162306a36Sopenharmony_ci		pool = &adev->mman.ttm_pools[gtt->pool_id];
117262306a36Sopenharmony_ci	else
117362306a36Sopenharmony_ci		pool = &adev->mman.bdev.pool;
117462306a36Sopenharmony_ci
117562306a36Sopenharmony_ci	return ttm_pool_free(pool, ttm);
117662306a36Sopenharmony_ci}
117762306a36Sopenharmony_ci
117862306a36Sopenharmony_ci/**
117962306a36Sopenharmony_ci * amdgpu_ttm_tt_get_userptr - Return the userptr GTT ttm_tt for the current
118062306a36Sopenharmony_ci * task
118162306a36Sopenharmony_ci *
118262306a36Sopenharmony_ci * @tbo: The ttm_buffer_object that contains the userptr
118362306a36Sopenharmony_ci * @user_addr:  The returned value
118462306a36Sopenharmony_ci */
118562306a36Sopenharmony_ciint amdgpu_ttm_tt_get_userptr(const struct ttm_buffer_object *tbo,
118662306a36Sopenharmony_ci			      uint64_t *user_addr)
118762306a36Sopenharmony_ci{
118862306a36Sopenharmony_ci	struct amdgpu_ttm_tt *gtt;
118962306a36Sopenharmony_ci
119062306a36Sopenharmony_ci	if (!tbo->ttm)
119162306a36Sopenharmony_ci		return -EINVAL;
119262306a36Sopenharmony_ci
119362306a36Sopenharmony_ci	gtt = (void *)tbo->ttm;
119462306a36Sopenharmony_ci	*user_addr = gtt->userptr;
119562306a36Sopenharmony_ci	return 0;
119662306a36Sopenharmony_ci}
119762306a36Sopenharmony_ci
119862306a36Sopenharmony_ci/**
119962306a36Sopenharmony_ci * amdgpu_ttm_tt_set_userptr - Initialize userptr GTT ttm_tt for the current
120062306a36Sopenharmony_ci * task
120162306a36Sopenharmony_ci *
120262306a36Sopenharmony_ci * @bo: The ttm_buffer_object to bind this userptr to
120362306a36Sopenharmony_ci * @addr:  The address in the current tasks VM space to use
120462306a36Sopenharmony_ci * @flags: Requirements of userptr object.
120562306a36Sopenharmony_ci *
120662306a36Sopenharmony_ci * Called by amdgpu_gem_userptr_ioctl() and kfd_ioctl_alloc_memory_of_gpu() to
120762306a36Sopenharmony_ci * bind userptr pages to current task and by kfd_ioctl_acquire_vm() to
120862306a36Sopenharmony_ci * initialize GPU VM for a KFD process.
120962306a36Sopenharmony_ci */
121062306a36Sopenharmony_ciint amdgpu_ttm_tt_set_userptr(struct ttm_buffer_object *bo,
121162306a36Sopenharmony_ci			      uint64_t addr, uint32_t flags)
121262306a36Sopenharmony_ci{
121362306a36Sopenharmony_ci	struct amdgpu_ttm_tt *gtt;
121462306a36Sopenharmony_ci
121562306a36Sopenharmony_ci	if (!bo->ttm) {
121662306a36Sopenharmony_ci		/* TODO: We want a separate TTM object type for userptrs */
121762306a36Sopenharmony_ci		bo->ttm = amdgpu_ttm_tt_create(bo, 0);
121862306a36Sopenharmony_ci		if (bo->ttm == NULL)
121962306a36Sopenharmony_ci			return -ENOMEM;
122062306a36Sopenharmony_ci	}
122162306a36Sopenharmony_ci
122262306a36Sopenharmony_ci	/* Set TTM_TT_FLAG_EXTERNAL before populate but after create. */
122362306a36Sopenharmony_ci	bo->ttm->page_flags |= TTM_TT_FLAG_EXTERNAL;
122462306a36Sopenharmony_ci
122562306a36Sopenharmony_ci	gtt = ttm_to_amdgpu_ttm_tt(bo->ttm);
122662306a36Sopenharmony_ci	gtt->userptr = addr;
122762306a36Sopenharmony_ci	gtt->userflags = flags;
122862306a36Sopenharmony_ci
122962306a36Sopenharmony_ci	if (gtt->usertask)
123062306a36Sopenharmony_ci		put_task_struct(gtt->usertask);
123162306a36Sopenharmony_ci	gtt->usertask = current->group_leader;
123262306a36Sopenharmony_ci	get_task_struct(gtt->usertask);
123362306a36Sopenharmony_ci
123462306a36Sopenharmony_ci	return 0;
123562306a36Sopenharmony_ci}
123662306a36Sopenharmony_ci
123762306a36Sopenharmony_ci/*
123862306a36Sopenharmony_ci * amdgpu_ttm_tt_get_usermm - Return memory manager for ttm_tt object
123962306a36Sopenharmony_ci */
124062306a36Sopenharmony_cistruct mm_struct *amdgpu_ttm_tt_get_usermm(struct ttm_tt *ttm)
124162306a36Sopenharmony_ci{
124262306a36Sopenharmony_ci	struct amdgpu_ttm_tt *gtt = ttm_to_amdgpu_ttm_tt(ttm);
124362306a36Sopenharmony_ci
124462306a36Sopenharmony_ci	if (gtt == NULL)
124562306a36Sopenharmony_ci		return NULL;
124662306a36Sopenharmony_ci
124762306a36Sopenharmony_ci	if (gtt->usertask == NULL)
124862306a36Sopenharmony_ci		return NULL;
124962306a36Sopenharmony_ci
125062306a36Sopenharmony_ci	return gtt->usertask->mm;
125162306a36Sopenharmony_ci}
125262306a36Sopenharmony_ci
125362306a36Sopenharmony_ci/*
125462306a36Sopenharmony_ci * amdgpu_ttm_tt_affect_userptr - Determine if a ttm_tt object lays inside an
125562306a36Sopenharmony_ci * address range for the current task.
125662306a36Sopenharmony_ci *
125762306a36Sopenharmony_ci */
125862306a36Sopenharmony_cibool amdgpu_ttm_tt_affect_userptr(struct ttm_tt *ttm, unsigned long start,
125962306a36Sopenharmony_ci				  unsigned long end, unsigned long *userptr)
126062306a36Sopenharmony_ci{
126162306a36Sopenharmony_ci	struct amdgpu_ttm_tt *gtt = ttm_to_amdgpu_ttm_tt(ttm);
126262306a36Sopenharmony_ci	unsigned long size;
126362306a36Sopenharmony_ci
126462306a36Sopenharmony_ci	if (gtt == NULL || !gtt->userptr)
126562306a36Sopenharmony_ci		return false;
126662306a36Sopenharmony_ci
126762306a36Sopenharmony_ci	/* Return false if no part of the ttm_tt object lies within
126862306a36Sopenharmony_ci	 * the range
126962306a36Sopenharmony_ci	 */
127062306a36Sopenharmony_ci	size = (unsigned long)gtt->ttm.num_pages * PAGE_SIZE;
127162306a36Sopenharmony_ci	if (gtt->userptr > end || gtt->userptr + size <= start)
127262306a36Sopenharmony_ci		return false;
127362306a36Sopenharmony_ci
127462306a36Sopenharmony_ci	if (userptr)
127562306a36Sopenharmony_ci		*userptr = gtt->userptr;
127662306a36Sopenharmony_ci	return true;
127762306a36Sopenharmony_ci}
127862306a36Sopenharmony_ci
127962306a36Sopenharmony_ci/*
128062306a36Sopenharmony_ci * amdgpu_ttm_tt_is_userptr - Have the pages backing by userptr?
128162306a36Sopenharmony_ci */
128262306a36Sopenharmony_cibool amdgpu_ttm_tt_is_userptr(struct ttm_tt *ttm)
128362306a36Sopenharmony_ci{
128462306a36Sopenharmony_ci	struct amdgpu_ttm_tt *gtt = ttm_to_amdgpu_ttm_tt(ttm);
128562306a36Sopenharmony_ci
128662306a36Sopenharmony_ci	if (gtt == NULL || !gtt->userptr)
128762306a36Sopenharmony_ci		return false;
128862306a36Sopenharmony_ci
128962306a36Sopenharmony_ci	return true;
129062306a36Sopenharmony_ci}
129162306a36Sopenharmony_ci
129262306a36Sopenharmony_ci/*
129362306a36Sopenharmony_ci * amdgpu_ttm_tt_is_readonly - Is the ttm_tt object read only?
129462306a36Sopenharmony_ci */
129562306a36Sopenharmony_cibool amdgpu_ttm_tt_is_readonly(struct ttm_tt *ttm)
129662306a36Sopenharmony_ci{
129762306a36Sopenharmony_ci	struct amdgpu_ttm_tt *gtt = ttm_to_amdgpu_ttm_tt(ttm);
129862306a36Sopenharmony_ci
129962306a36Sopenharmony_ci	if (gtt == NULL)
130062306a36Sopenharmony_ci		return false;
130162306a36Sopenharmony_ci
130262306a36Sopenharmony_ci	return !!(gtt->userflags & AMDGPU_GEM_USERPTR_READONLY);
130362306a36Sopenharmony_ci}
130462306a36Sopenharmony_ci
130562306a36Sopenharmony_ci/**
130662306a36Sopenharmony_ci * amdgpu_ttm_tt_pde_flags - Compute PDE flags for ttm_tt object
130762306a36Sopenharmony_ci *
130862306a36Sopenharmony_ci * @ttm: The ttm_tt object to compute the flags for
130962306a36Sopenharmony_ci * @mem: The memory registry backing this ttm_tt object
131062306a36Sopenharmony_ci *
131162306a36Sopenharmony_ci * Figure out the flags to use for a VM PDE (Page Directory Entry).
131262306a36Sopenharmony_ci */
131362306a36Sopenharmony_ciuint64_t amdgpu_ttm_tt_pde_flags(struct ttm_tt *ttm, struct ttm_resource *mem)
131462306a36Sopenharmony_ci{
131562306a36Sopenharmony_ci	uint64_t flags = 0;
131662306a36Sopenharmony_ci
131762306a36Sopenharmony_ci	if (mem && mem->mem_type != TTM_PL_SYSTEM)
131862306a36Sopenharmony_ci		flags |= AMDGPU_PTE_VALID;
131962306a36Sopenharmony_ci
132062306a36Sopenharmony_ci	if (mem && (mem->mem_type == TTM_PL_TT ||
132162306a36Sopenharmony_ci		    mem->mem_type == AMDGPU_PL_DOORBELL ||
132262306a36Sopenharmony_ci		    mem->mem_type == AMDGPU_PL_PREEMPT)) {
132362306a36Sopenharmony_ci		flags |= AMDGPU_PTE_SYSTEM;
132462306a36Sopenharmony_ci
132562306a36Sopenharmony_ci		if (ttm->caching == ttm_cached)
132662306a36Sopenharmony_ci			flags |= AMDGPU_PTE_SNOOPED;
132762306a36Sopenharmony_ci	}
132862306a36Sopenharmony_ci
132962306a36Sopenharmony_ci	if (mem && mem->mem_type == TTM_PL_VRAM &&
133062306a36Sopenharmony_ci			mem->bus.caching == ttm_cached)
133162306a36Sopenharmony_ci		flags |= AMDGPU_PTE_SNOOPED;
133262306a36Sopenharmony_ci
133362306a36Sopenharmony_ci	return flags;
133462306a36Sopenharmony_ci}
133562306a36Sopenharmony_ci
133662306a36Sopenharmony_ci/**
133762306a36Sopenharmony_ci * amdgpu_ttm_tt_pte_flags - Compute PTE flags for ttm_tt object
133862306a36Sopenharmony_ci *
133962306a36Sopenharmony_ci * @adev: amdgpu_device pointer
134062306a36Sopenharmony_ci * @ttm: The ttm_tt object to compute the flags for
134162306a36Sopenharmony_ci * @mem: The memory registry backing this ttm_tt object
134262306a36Sopenharmony_ci *
134362306a36Sopenharmony_ci * Figure out the flags to use for a VM PTE (Page Table Entry).
134462306a36Sopenharmony_ci */
134562306a36Sopenharmony_ciuint64_t amdgpu_ttm_tt_pte_flags(struct amdgpu_device *adev, struct ttm_tt *ttm,
134662306a36Sopenharmony_ci				 struct ttm_resource *mem)
134762306a36Sopenharmony_ci{
134862306a36Sopenharmony_ci	uint64_t flags = amdgpu_ttm_tt_pde_flags(ttm, mem);
134962306a36Sopenharmony_ci
135062306a36Sopenharmony_ci	flags |= adev->gart.gart_pte_flags;
135162306a36Sopenharmony_ci	flags |= AMDGPU_PTE_READABLE;
135262306a36Sopenharmony_ci
135362306a36Sopenharmony_ci	if (!amdgpu_ttm_tt_is_readonly(ttm))
135462306a36Sopenharmony_ci		flags |= AMDGPU_PTE_WRITEABLE;
135562306a36Sopenharmony_ci
135662306a36Sopenharmony_ci	return flags;
135762306a36Sopenharmony_ci}
135862306a36Sopenharmony_ci
135962306a36Sopenharmony_ci/*
136062306a36Sopenharmony_ci * amdgpu_ttm_bo_eviction_valuable - Check to see if we can evict a buffer
136162306a36Sopenharmony_ci * object.
136262306a36Sopenharmony_ci *
136362306a36Sopenharmony_ci * Return true if eviction is sensible. Called by ttm_mem_evict_first() on
136462306a36Sopenharmony_ci * behalf of ttm_bo_mem_force_space() which tries to evict buffer objects until
136562306a36Sopenharmony_ci * it can find space for a new object and by ttm_bo_force_list_clean() which is
136662306a36Sopenharmony_ci * used to clean out a memory space.
136762306a36Sopenharmony_ci */
136862306a36Sopenharmony_cistatic bool amdgpu_ttm_bo_eviction_valuable(struct ttm_buffer_object *bo,
136962306a36Sopenharmony_ci					    const struct ttm_place *place)
137062306a36Sopenharmony_ci{
137162306a36Sopenharmony_ci	struct dma_resv_iter resv_cursor;
137262306a36Sopenharmony_ci	struct dma_fence *f;
137362306a36Sopenharmony_ci
137462306a36Sopenharmony_ci	if (!amdgpu_bo_is_amdgpu_bo(bo))
137562306a36Sopenharmony_ci		return ttm_bo_eviction_valuable(bo, place);
137662306a36Sopenharmony_ci
137762306a36Sopenharmony_ci	/* Swapout? */
137862306a36Sopenharmony_ci	if (bo->resource->mem_type == TTM_PL_SYSTEM)
137962306a36Sopenharmony_ci		return true;
138062306a36Sopenharmony_ci
138162306a36Sopenharmony_ci	if (bo->type == ttm_bo_type_kernel &&
138262306a36Sopenharmony_ci	    !amdgpu_vm_evictable(ttm_to_amdgpu_bo(bo)))
138362306a36Sopenharmony_ci		return false;
138462306a36Sopenharmony_ci
138562306a36Sopenharmony_ci	/* If bo is a KFD BO, check if the bo belongs to the current process.
138662306a36Sopenharmony_ci	 * If true, then return false as any KFD process needs all its BOs to
138762306a36Sopenharmony_ci	 * be resident to run successfully
138862306a36Sopenharmony_ci	 */
138962306a36Sopenharmony_ci	dma_resv_for_each_fence(&resv_cursor, bo->base.resv,
139062306a36Sopenharmony_ci				DMA_RESV_USAGE_BOOKKEEP, f) {
139162306a36Sopenharmony_ci		if (amdkfd_fence_check_mm(f, current->mm))
139262306a36Sopenharmony_ci			return false;
139362306a36Sopenharmony_ci	}
139462306a36Sopenharmony_ci
139562306a36Sopenharmony_ci	/* Preemptible BOs don't own system resources managed by the
139662306a36Sopenharmony_ci	 * driver (pages, VRAM, GART space). They point to resources
139762306a36Sopenharmony_ci	 * owned by someone else (e.g. pageable memory in user mode
139862306a36Sopenharmony_ci	 * or a DMABuf). They are used in a preemptible context so we
139962306a36Sopenharmony_ci	 * can guarantee no deadlocks and good QoS in case of MMU
140062306a36Sopenharmony_ci	 * notifiers or DMABuf move notifiers from the resource owner.
140162306a36Sopenharmony_ci	 */
140262306a36Sopenharmony_ci	if (bo->resource->mem_type == AMDGPU_PL_PREEMPT)
140362306a36Sopenharmony_ci		return false;
140462306a36Sopenharmony_ci
140562306a36Sopenharmony_ci	if (bo->resource->mem_type == TTM_PL_TT &&
140662306a36Sopenharmony_ci	    amdgpu_bo_encrypted(ttm_to_amdgpu_bo(bo)))
140762306a36Sopenharmony_ci		return false;
140862306a36Sopenharmony_ci
140962306a36Sopenharmony_ci	return ttm_bo_eviction_valuable(bo, place);
141062306a36Sopenharmony_ci}
141162306a36Sopenharmony_ci
141262306a36Sopenharmony_cistatic void amdgpu_ttm_vram_mm_access(struct amdgpu_device *adev, loff_t pos,
141362306a36Sopenharmony_ci				      void *buf, size_t size, bool write)
141462306a36Sopenharmony_ci{
141562306a36Sopenharmony_ci	while (size) {
141662306a36Sopenharmony_ci		uint64_t aligned_pos = ALIGN_DOWN(pos, 4);
141762306a36Sopenharmony_ci		uint64_t bytes = 4 - (pos & 0x3);
141862306a36Sopenharmony_ci		uint32_t shift = (pos & 0x3) * 8;
141962306a36Sopenharmony_ci		uint32_t mask = 0xffffffff << shift;
142062306a36Sopenharmony_ci		uint32_t value = 0;
142162306a36Sopenharmony_ci
142262306a36Sopenharmony_ci		if (size < bytes) {
142362306a36Sopenharmony_ci			mask &= 0xffffffff >> (bytes - size) * 8;
142462306a36Sopenharmony_ci			bytes = size;
142562306a36Sopenharmony_ci		}
142662306a36Sopenharmony_ci
142762306a36Sopenharmony_ci		if (mask != 0xffffffff) {
142862306a36Sopenharmony_ci			amdgpu_device_mm_access(adev, aligned_pos, &value, 4, false);
142962306a36Sopenharmony_ci			if (write) {
143062306a36Sopenharmony_ci				value &= ~mask;
143162306a36Sopenharmony_ci				value |= (*(uint32_t *)buf << shift) & mask;
143262306a36Sopenharmony_ci				amdgpu_device_mm_access(adev, aligned_pos, &value, 4, true);
143362306a36Sopenharmony_ci			} else {
143462306a36Sopenharmony_ci				value = (value & mask) >> shift;
143562306a36Sopenharmony_ci				memcpy(buf, &value, bytes);
143662306a36Sopenharmony_ci			}
143762306a36Sopenharmony_ci		} else {
143862306a36Sopenharmony_ci			amdgpu_device_mm_access(adev, aligned_pos, buf, 4, write);
143962306a36Sopenharmony_ci		}
144062306a36Sopenharmony_ci
144162306a36Sopenharmony_ci		pos += bytes;
144262306a36Sopenharmony_ci		buf += bytes;
144362306a36Sopenharmony_ci		size -= bytes;
144462306a36Sopenharmony_ci	}
144562306a36Sopenharmony_ci}
144662306a36Sopenharmony_ci
144762306a36Sopenharmony_cistatic int amdgpu_ttm_access_memory_sdma(struct ttm_buffer_object *bo,
144862306a36Sopenharmony_ci					unsigned long offset, void *buf,
144962306a36Sopenharmony_ci					int len, int write)
145062306a36Sopenharmony_ci{
145162306a36Sopenharmony_ci	struct amdgpu_bo *abo = ttm_to_amdgpu_bo(bo);
145262306a36Sopenharmony_ci	struct amdgpu_device *adev = amdgpu_ttm_adev(abo->tbo.bdev);
145362306a36Sopenharmony_ci	struct amdgpu_res_cursor src_mm;
145462306a36Sopenharmony_ci	struct amdgpu_job *job;
145562306a36Sopenharmony_ci	struct dma_fence *fence;
145662306a36Sopenharmony_ci	uint64_t src_addr, dst_addr;
145762306a36Sopenharmony_ci	unsigned int num_dw;
145862306a36Sopenharmony_ci	int r, idx;
145962306a36Sopenharmony_ci
146062306a36Sopenharmony_ci	if (len != PAGE_SIZE)
146162306a36Sopenharmony_ci		return -EINVAL;
146262306a36Sopenharmony_ci
146362306a36Sopenharmony_ci	if (!adev->mman.sdma_access_ptr)
146462306a36Sopenharmony_ci		return -EACCES;
146562306a36Sopenharmony_ci
146662306a36Sopenharmony_ci	if (!drm_dev_enter(adev_to_drm(adev), &idx))
146762306a36Sopenharmony_ci		return -ENODEV;
146862306a36Sopenharmony_ci
146962306a36Sopenharmony_ci	if (write)
147062306a36Sopenharmony_ci		memcpy(adev->mman.sdma_access_ptr, buf, len);
147162306a36Sopenharmony_ci
147262306a36Sopenharmony_ci	num_dw = ALIGN(adev->mman.buffer_funcs->copy_num_dw, 8);
147362306a36Sopenharmony_ci	r = amdgpu_job_alloc_with_ib(adev, &adev->mman.high_pr,
147462306a36Sopenharmony_ci				     AMDGPU_FENCE_OWNER_UNDEFINED,
147562306a36Sopenharmony_ci				     num_dw * 4, AMDGPU_IB_POOL_DELAYED,
147662306a36Sopenharmony_ci				     &job);
147762306a36Sopenharmony_ci	if (r)
147862306a36Sopenharmony_ci		goto out;
147962306a36Sopenharmony_ci
148062306a36Sopenharmony_ci	amdgpu_res_first(abo->tbo.resource, offset, len, &src_mm);
148162306a36Sopenharmony_ci	src_addr = amdgpu_ttm_domain_start(adev, bo->resource->mem_type) +
148262306a36Sopenharmony_ci		src_mm.start;
148362306a36Sopenharmony_ci	dst_addr = amdgpu_bo_gpu_offset(adev->mman.sdma_access_bo);
148462306a36Sopenharmony_ci	if (write)
148562306a36Sopenharmony_ci		swap(src_addr, dst_addr);
148662306a36Sopenharmony_ci
148762306a36Sopenharmony_ci	amdgpu_emit_copy_buffer(adev, &job->ibs[0], src_addr, dst_addr,
148862306a36Sopenharmony_ci				PAGE_SIZE, false);
148962306a36Sopenharmony_ci
149062306a36Sopenharmony_ci	amdgpu_ring_pad_ib(adev->mman.buffer_funcs_ring, &job->ibs[0]);
149162306a36Sopenharmony_ci	WARN_ON(job->ibs[0].length_dw > num_dw);
149262306a36Sopenharmony_ci
149362306a36Sopenharmony_ci	fence = amdgpu_job_submit(job);
149462306a36Sopenharmony_ci
149562306a36Sopenharmony_ci	if (!dma_fence_wait_timeout(fence, false, adev->sdma_timeout))
149662306a36Sopenharmony_ci		r = -ETIMEDOUT;
149762306a36Sopenharmony_ci	dma_fence_put(fence);
149862306a36Sopenharmony_ci
149962306a36Sopenharmony_ci	if (!(r || write))
150062306a36Sopenharmony_ci		memcpy(buf, adev->mman.sdma_access_ptr, len);
150162306a36Sopenharmony_ciout:
150262306a36Sopenharmony_ci	drm_dev_exit(idx);
150362306a36Sopenharmony_ci	return r;
150462306a36Sopenharmony_ci}
150562306a36Sopenharmony_ci
150662306a36Sopenharmony_ci/**
150762306a36Sopenharmony_ci * amdgpu_ttm_access_memory - Read or Write memory that backs a buffer object.
150862306a36Sopenharmony_ci *
150962306a36Sopenharmony_ci * @bo:  The buffer object to read/write
151062306a36Sopenharmony_ci * @offset:  Offset into buffer object
151162306a36Sopenharmony_ci * @buf:  Secondary buffer to write/read from
151262306a36Sopenharmony_ci * @len: Length in bytes of access
151362306a36Sopenharmony_ci * @write:  true if writing
151462306a36Sopenharmony_ci *
151562306a36Sopenharmony_ci * This is used to access VRAM that backs a buffer object via MMIO
151662306a36Sopenharmony_ci * access for debugging purposes.
151762306a36Sopenharmony_ci */
151862306a36Sopenharmony_cistatic int amdgpu_ttm_access_memory(struct ttm_buffer_object *bo,
151962306a36Sopenharmony_ci				    unsigned long offset, void *buf, int len,
152062306a36Sopenharmony_ci				    int write)
152162306a36Sopenharmony_ci{
152262306a36Sopenharmony_ci	struct amdgpu_bo *abo = ttm_to_amdgpu_bo(bo);
152362306a36Sopenharmony_ci	struct amdgpu_device *adev = amdgpu_ttm_adev(abo->tbo.bdev);
152462306a36Sopenharmony_ci	struct amdgpu_res_cursor cursor;
152562306a36Sopenharmony_ci	int ret = 0;
152662306a36Sopenharmony_ci
152762306a36Sopenharmony_ci	if (bo->resource->mem_type != TTM_PL_VRAM)
152862306a36Sopenharmony_ci		return -EIO;
152962306a36Sopenharmony_ci
153062306a36Sopenharmony_ci	if (amdgpu_device_has_timeouts_enabled(adev) &&
153162306a36Sopenharmony_ci			!amdgpu_ttm_access_memory_sdma(bo, offset, buf, len, write))
153262306a36Sopenharmony_ci		return len;
153362306a36Sopenharmony_ci
153462306a36Sopenharmony_ci	amdgpu_res_first(bo->resource, offset, len, &cursor);
153562306a36Sopenharmony_ci	while (cursor.remaining) {
153662306a36Sopenharmony_ci		size_t count, size = cursor.size;
153762306a36Sopenharmony_ci		loff_t pos = cursor.start;
153862306a36Sopenharmony_ci
153962306a36Sopenharmony_ci		count = amdgpu_device_aper_access(adev, pos, buf, size, write);
154062306a36Sopenharmony_ci		size -= count;
154162306a36Sopenharmony_ci		if (size) {
154262306a36Sopenharmony_ci			/* using MM to access rest vram and handle un-aligned address */
154362306a36Sopenharmony_ci			pos += count;
154462306a36Sopenharmony_ci			buf += count;
154562306a36Sopenharmony_ci			amdgpu_ttm_vram_mm_access(adev, pos, buf, size, write);
154662306a36Sopenharmony_ci		}
154762306a36Sopenharmony_ci
154862306a36Sopenharmony_ci		ret += cursor.size;
154962306a36Sopenharmony_ci		buf += cursor.size;
155062306a36Sopenharmony_ci		amdgpu_res_next(&cursor, cursor.size);
155162306a36Sopenharmony_ci	}
155262306a36Sopenharmony_ci
155362306a36Sopenharmony_ci	return ret;
155462306a36Sopenharmony_ci}
155562306a36Sopenharmony_ci
155662306a36Sopenharmony_cistatic void
155762306a36Sopenharmony_ciamdgpu_bo_delete_mem_notify(struct ttm_buffer_object *bo)
155862306a36Sopenharmony_ci{
155962306a36Sopenharmony_ci	amdgpu_bo_move_notify(bo, false);
156062306a36Sopenharmony_ci}
156162306a36Sopenharmony_ci
156262306a36Sopenharmony_cistatic struct ttm_device_funcs amdgpu_bo_driver = {
156362306a36Sopenharmony_ci	.ttm_tt_create = &amdgpu_ttm_tt_create,
156462306a36Sopenharmony_ci	.ttm_tt_populate = &amdgpu_ttm_tt_populate,
156562306a36Sopenharmony_ci	.ttm_tt_unpopulate = &amdgpu_ttm_tt_unpopulate,
156662306a36Sopenharmony_ci	.ttm_tt_destroy = &amdgpu_ttm_backend_destroy,
156762306a36Sopenharmony_ci	.eviction_valuable = amdgpu_ttm_bo_eviction_valuable,
156862306a36Sopenharmony_ci	.evict_flags = &amdgpu_evict_flags,
156962306a36Sopenharmony_ci	.move = &amdgpu_bo_move,
157062306a36Sopenharmony_ci	.delete_mem_notify = &amdgpu_bo_delete_mem_notify,
157162306a36Sopenharmony_ci	.release_notify = &amdgpu_bo_release_notify,
157262306a36Sopenharmony_ci	.io_mem_reserve = &amdgpu_ttm_io_mem_reserve,
157362306a36Sopenharmony_ci	.io_mem_pfn = amdgpu_ttm_io_mem_pfn,
157462306a36Sopenharmony_ci	.access_memory = &amdgpu_ttm_access_memory,
157562306a36Sopenharmony_ci};
157662306a36Sopenharmony_ci
157762306a36Sopenharmony_ci/*
157862306a36Sopenharmony_ci * Firmware Reservation functions
157962306a36Sopenharmony_ci */
158062306a36Sopenharmony_ci/**
158162306a36Sopenharmony_ci * amdgpu_ttm_fw_reserve_vram_fini - free fw reserved vram
158262306a36Sopenharmony_ci *
158362306a36Sopenharmony_ci * @adev: amdgpu_device pointer
158462306a36Sopenharmony_ci *
158562306a36Sopenharmony_ci * free fw reserved vram if it has been reserved.
158662306a36Sopenharmony_ci */
158762306a36Sopenharmony_cistatic void amdgpu_ttm_fw_reserve_vram_fini(struct amdgpu_device *adev)
158862306a36Sopenharmony_ci{
158962306a36Sopenharmony_ci	amdgpu_bo_free_kernel(&adev->mman.fw_vram_usage_reserved_bo,
159062306a36Sopenharmony_ci		NULL, &adev->mman.fw_vram_usage_va);
159162306a36Sopenharmony_ci}
159262306a36Sopenharmony_ci
159362306a36Sopenharmony_ci/*
159462306a36Sopenharmony_ci * Driver Reservation functions
159562306a36Sopenharmony_ci */
159662306a36Sopenharmony_ci/**
159762306a36Sopenharmony_ci * amdgpu_ttm_drv_reserve_vram_fini - free drv reserved vram
159862306a36Sopenharmony_ci *
159962306a36Sopenharmony_ci * @adev: amdgpu_device pointer
160062306a36Sopenharmony_ci *
160162306a36Sopenharmony_ci * free drv reserved vram if it has been reserved.
160262306a36Sopenharmony_ci */
160362306a36Sopenharmony_cistatic void amdgpu_ttm_drv_reserve_vram_fini(struct amdgpu_device *adev)
160462306a36Sopenharmony_ci{
160562306a36Sopenharmony_ci	amdgpu_bo_free_kernel(&adev->mman.drv_vram_usage_reserved_bo,
160662306a36Sopenharmony_ci						  NULL,
160762306a36Sopenharmony_ci						  &adev->mman.drv_vram_usage_va);
160862306a36Sopenharmony_ci}
160962306a36Sopenharmony_ci
161062306a36Sopenharmony_ci/**
161162306a36Sopenharmony_ci * amdgpu_ttm_fw_reserve_vram_init - create bo vram reservation from fw
161262306a36Sopenharmony_ci *
161362306a36Sopenharmony_ci * @adev: amdgpu_device pointer
161462306a36Sopenharmony_ci *
161562306a36Sopenharmony_ci * create bo vram reservation from fw.
161662306a36Sopenharmony_ci */
161762306a36Sopenharmony_cistatic int amdgpu_ttm_fw_reserve_vram_init(struct amdgpu_device *adev)
161862306a36Sopenharmony_ci{
161962306a36Sopenharmony_ci	uint64_t vram_size = adev->gmc.visible_vram_size;
162062306a36Sopenharmony_ci
162162306a36Sopenharmony_ci	adev->mman.fw_vram_usage_va = NULL;
162262306a36Sopenharmony_ci	adev->mman.fw_vram_usage_reserved_bo = NULL;
162362306a36Sopenharmony_ci
162462306a36Sopenharmony_ci	if (adev->mman.fw_vram_usage_size == 0 ||
162562306a36Sopenharmony_ci	    adev->mman.fw_vram_usage_size > vram_size)
162662306a36Sopenharmony_ci		return 0;
162762306a36Sopenharmony_ci
162862306a36Sopenharmony_ci	return amdgpu_bo_create_kernel_at(adev,
162962306a36Sopenharmony_ci					  adev->mman.fw_vram_usage_start_offset,
163062306a36Sopenharmony_ci					  adev->mman.fw_vram_usage_size,
163162306a36Sopenharmony_ci					  &adev->mman.fw_vram_usage_reserved_bo,
163262306a36Sopenharmony_ci					  &adev->mman.fw_vram_usage_va);
163362306a36Sopenharmony_ci}
163462306a36Sopenharmony_ci
163562306a36Sopenharmony_ci/**
163662306a36Sopenharmony_ci * amdgpu_ttm_drv_reserve_vram_init - create bo vram reservation from driver
163762306a36Sopenharmony_ci *
163862306a36Sopenharmony_ci * @adev: amdgpu_device pointer
163962306a36Sopenharmony_ci *
164062306a36Sopenharmony_ci * create bo vram reservation from drv.
164162306a36Sopenharmony_ci */
164262306a36Sopenharmony_cistatic int amdgpu_ttm_drv_reserve_vram_init(struct amdgpu_device *adev)
164362306a36Sopenharmony_ci{
164462306a36Sopenharmony_ci	u64 vram_size = adev->gmc.visible_vram_size;
164562306a36Sopenharmony_ci
164662306a36Sopenharmony_ci	adev->mman.drv_vram_usage_va = NULL;
164762306a36Sopenharmony_ci	adev->mman.drv_vram_usage_reserved_bo = NULL;
164862306a36Sopenharmony_ci
164962306a36Sopenharmony_ci	if (adev->mman.drv_vram_usage_size == 0 ||
165062306a36Sopenharmony_ci	    adev->mman.drv_vram_usage_size > vram_size)
165162306a36Sopenharmony_ci		return 0;
165262306a36Sopenharmony_ci
165362306a36Sopenharmony_ci	return amdgpu_bo_create_kernel_at(adev,
165462306a36Sopenharmony_ci					  adev->mman.drv_vram_usage_start_offset,
165562306a36Sopenharmony_ci					  adev->mman.drv_vram_usage_size,
165662306a36Sopenharmony_ci					  &adev->mman.drv_vram_usage_reserved_bo,
165762306a36Sopenharmony_ci					  &adev->mman.drv_vram_usage_va);
165862306a36Sopenharmony_ci}
165962306a36Sopenharmony_ci
166062306a36Sopenharmony_ci/*
166162306a36Sopenharmony_ci * Memoy training reservation functions
166262306a36Sopenharmony_ci */
166362306a36Sopenharmony_ci
166462306a36Sopenharmony_ci/**
166562306a36Sopenharmony_ci * amdgpu_ttm_training_reserve_vram_fini - free memory training reserved vram
166662306a36Sopenharmony_ci *
166762306a36Sopenharmony_ci * @adev: amdgpu_device pointer
166862306a36Sopenharmony_ci *
166962306a36Sopenharmony_ci * free memory training reserved vram if it has been reserved.
167062306a36Sopenharmony_ci */
167162306a36Sopenharmony_cistatic int amdgpu_ttm_training_reserve_vram_fini(struct amdgpu_device *adev)
167262306a36Sopenharmony_ci{
167362306a36Sopenharmony_ci	struct psp_memory_training_context *ctx = &adev->psp.mem_train_ctx;
167462306a36Sopenharmony_ci
167562306a36Sopenharmony_ci	ctx->init = PSP_MEM_TRAIN_NOT_SUPPORT;
167662306a36Sopenharmony_ci	amdgpu_bo_free_kernel(&ctx->c2p_bo, NULL, NULL);
167762306a36Sopenharmony_ci	ctx->c2p_bo = NULL;
167862306a36Sopenharmony_ci
167962306a36Sopenharmony_ci	return 0;
168062306a36Sopenharmony_ci}
168162306a36Sopenharmony_ci
168262306a36Sopenharmony_cistatic void amdgpu_ttm_training_data_block_init(struct amdgpu_device *adev,
168362306a36Sopenharmony_ci						uint32_t reserve_size)
168462306a36Sopenharmony_ci{
168562306a36Sopenharmony_ci	struct psp_memory_training_context *ctx = &adev->psp.mem_train_ctx;
168662306a36Sopenharmony_ci
168762306a36Sopenharmony_ci	memset(ctx, 0, sizeof(*ctx));
168862306a36Sopenharmony_ci
168962306a36Sopenharmony_ci	ctx->c2p_train_data_offset =
169062306a36Sopenharmony_ci		ALIGN((adev->gmc.mc_vram_size - reserve_size - SZ_1M), SZ_1M);
169162306a36Sopenharmony_ci	ctx->p2c_train_data_offset =
169262306a36Sopenharmony_ci		(adev->gmc.mc_vram_size - GDDR6_MEM_TRAINING_OFFSET);
169362306a36Sopenharmony_ci	ctx->train_data_size =
169462306a36Sopenharmony_ci		GDDR6_MEM_TRAINING_DATA_SIZE_IN_BYTES;
169562306a36Sopenharmony_ci
169662306a36Sopenharmony_ci	DRM_DEBUG("train_data_size:%llx,p2c_train_data_offset:%llx,c2p_train_data_offset:%llx.\n",
169762306a36Sopenharmony_ci			ctx->train_data_size,
169862306a36Sopenharmony_ci			ctx->p2c_train_data_offset,
169962306a36Sopenharmony_ci			ctx->c2p_train_data_offset);
170062306a36Sopenharmony_ci}
170162306a36Sopenharmony_ci
170262306a36Sopenharmony_ci/*
170362306a36Sopenharmony_ci * reserve TMR memory at the top of VRAM which holds
170462306a36Sopenharmony_ci * IP Discovery data and is protected by PSP.
170562306a36Sopenharmony_ci */
170662306a36Sopenharmony_cistatic int amdgpu_ttm_reserve_tmr(struct amdgpu_device *adev)
170762306a36Sopenharmony_ci{
170862306a36Sopenharmony_ci	struct psp_memory_training_context *ctx = &adev->psp.mem_train_ctx;
170962306a36Sopenharmony_ci	bool mem_train_support = false;
171062306a36Sopenharmony_ci	uint32_t reserve_size = 0;
171162306a36Sopenharmony_ci	int ret;
171262306a36Sopenharmony_ci
171362306a36Sopenharmony_ci	if (adev->bios && !amdgpu_sriov_vf(adev)) {
171462306a36Sopenharmony_ci		if (amdgpu_atomfirmware_mem_training_supported(adev))
171562306a36Sopenharmony_ci			mem_train_support = true;
171662306a36Sopenharmony_ci		else
171762306a36Sopenharmony_ci			DRM_DEBUG("memory training does not support!\n");
171862306a36Sopenharmony_ci	}
171962306a36Sopenharmony_ci
172062306a36Sopenharmony_ci	/*
172162306a36Sopenharmony_ci	 * Query reserved tmr size through atom firmwareinfo for Sienna_Cichlid and onwards for all
172262306a36Sopenharmony_ci	 * the use cases (IP discovery/G6 memory training/profiling/diagnostic data.etc)
172362306a36Sopenharmony_ci	 *
172462306a36Sopenharmony_ci	 * Otherwise, fallback to legacy approach to check and reserve tmr block for ip
172562306a36Sopenharmony_ci	 * discovery data and G6 memory training data respectively
172662306a36Sopenharmony_ci	 */
172762306a36Sopenharmony_ci	if (adev->bios)
172862306a36Sopenharmony_ci		reserve_size =
172962306a36Sopenharmony_ci			amdgpu_atomfirmware_get_fw_reserved_fb_size(adev);
173062306a36Sopenharmony_ci
173162306a36Sopenharmony_ci	if (!adev->bios && adev->ip_versions[GC_HWIP][0] == IP_VERSION(9, 4, 3))
173262306a36Sopenharmony_ci		reserve_size = max(reserve_size, (uint32_t)280 << 20);
173362306a36Sopenharmony_ci	else if (!reserve_size)
173462306a36Sopenharmony_ci		reserve_size = DISCOVERY_TMR_OFFSET;
173562306a36Sopenharmony_ci
173662306a36Sopenharmony_ci	if (mem_train_support) {
173762306a36Sopenharmony_ci		/* reserve vram for mem train according to TMR location */
173862306a36Sopenharmony_ci		amdgpu_ttm_training_data_block_init(adev, reserve_size);
173962306a36Sopenharmony_ci		ret = amdgpu_bo_create_kernel_at(adev,
174062306a36Sopenharmony_ci						 ctx->c2p_train_data_offset,
174162306a36Sopenharmony_ci						 ctx->train_data_size,
174262306a36Sopenharmony_ci						 &ctx->c2p_bo,
174362306a36Sopenharmony_ci						 NULL);
174462306a36Sopenharmony_ci		if (ret) {
174562306a36Sopenharmony_ci			DRM_ERROR("alloc c2p_bo failed(%d)!\n", ret);
174662306a36Sopenharmony_ci			amdgpu_ttm_training_reserve_vram_fini(adev);
174762306a36Sopenharmony_ci			return ret;
174862306a36Sopenharmony_ci		}
174962306a36Sopenharmony_ci		ctx->init = PSP_MEM_TRAIN_RESERVE_SUCCESS;
175062306a36Sopenharmony_ci	}
175162306a36Sopenharmony_ci
175262306a36Sopenharmony_ci	if (!adev->gmc.is_app_apu) {
175362306a36Sopenharmony_ci		ret = amdgpu_bo_create_kernel_at(
175462306a36Sopenharmony_ci			adev, adev->gmc.real_vram_size - reserve_size,
175562306a36Sopenharmony_ci			reserve_size, &adev->mman.fw_reserved_memory, NULL);
175662306a36Sopenharmony_ci		if (ret) {
175762306a36Sopenharmony_ci			DRM_ERROR("alloc tmr failed(%d)!\n", ret);
175862306a36Sopenharmony_ci			amdgpu_bo_free_kernel(&adev->mman.fw_reserved_memory,
175962306a36Sopenharmony_ci					      NULL, NULL);
176062306a36Sopenharmony_ci			return ret;
176162306a36Sopenharmony_ci		}
176262306a36Sopenharmony_ci	} else {
176362306a36Sopenharmony_ci		DRM_DEBUG_DRIVER("backdoor fw loading path for PSP TMR, no reservation needed\n");
176462306a36Sopenharmony_ci	}
176562306a36Sopenharmony_ci
176662306a36Sopenharmony_ci	return 0;
176762306a36Sopenharmony_ci}
176862306a36Sopenharmony_ci
176962306a36Sopenharmony_cistatic int amdgpu_ttm_pools_init(struct amdgpu_device *adev)
177062306a36Sopenharmony_ci{
177162306a36Sopenharmony_ci	int i;
177262306a36Sopenharmony_ci
177362306a36Sopenharmony_ci	if (!adev->gmc.is_app_apu || !adev->gmc.num_mem_partitions)
177462306a36Sopenharmony_ci		return 0;
177562306a36Sopenharmony_ci
177662306a36Sopenharmony_ci	adev->mman.ttm_pools = kcalloc(adev->gmc.num_mem_partitions,
177762306a36Sopenharmony_ci				       sizeof(*adev->mman.ttm_pools),
177862306a36Sopenharmony_ci				       GFP_KERNEL);
177962306a36Sopenharmony_ci	if (!adev->mman.ttm_pools)
178062306a36Sopenharmony_ci		return -ENOMEM;
178162306a36Sopenharmony_ci
178262306a36Sopenharmony_ci	for (i = 0; i < adev->gmc.num_mem_partitions; i++) {
178362306a36Sopenharmony_ci		ttm_pool_init(&adev->mman.ttm_pools[i], adev->dev,
178462306a36Sopenharmony_ci			      adev->gmc.mem_partitions[i].numa.node,
178562306a36Sopenharmony_ci			      false, false);
178662306a36Sopenharmony_ci	}
178762306a36Sopenharmony_ci	return 0;
178862306a36Sopenharmony_ci}
178962306a36Sopenharmony_ci
179062306a36Sopenharmony_cistatic void amdgpu_ttm_pools_fini(struct amdgpu_device *adev)
179162306a36Sopenharmony_ci{
179262306a36Sopenharmony_ci	int i;
179362306a36Sopenharmony_ci
179462306a36Sopenharmony_ci	if (!adev->gmc.is_app_apu || !adev->mman.ttm_pools)
179562306a36Sopenharmony_ci		return;
179662306a36Sopenharmony_ci
179762306a36Sopenharmony_ci	for (i = 0; i < adev->gmc.num_mem_partitions; i++)
179862306a36Sopenharmony_ci		ttm_pool_fini(&adev->mman.ttm_pools[i]);
179962306a36Sopenharmony_ci
180062306a36Sopenharmony_ci	kfree(adev->mman.ttm_pools);
180162306a36Sopenharmony_ci	adev->mman.ttm_pools = NULL;
180262306a36Sopenharmony_ci}
180362306a36Sopenharmony_ci
180462306a36Sopenharmony_ci/*
180562306a36Sopenharmony_ci * amdgpu_ttm_init - Init the memory management (ttm) as well as various
180662306a36Sopenharmony_ci * gtt/vram related fields.
180762306a36Sopenharmony_ci *
180862306a36Sopenharmony_ci * This initializes all of the memory space pools that the TTM layer
180962306a36Sopenharmony_ci * will need such as the GTT space (system memory mapped to the device),
181062306a36Sopenharmony_ci * VRAM (on-board memory), and on-chip memories (GDS, GWS, OA) which
181162306a36Sopenharmony_ci * can be mapped per VMID.
181262306a36Sopenharmony_ci */
181362306a36Sopenharmony_ciint amdgpu_ttm_init(struct amdgpu_device *adev)
181462306a36Sopenharmony_ci{
181562306a36Sopenharmony_ci	uint64_t gtt_size;
181662306a36Sopenharmony_ci	int r;
181762306a36Sopenharmony_ci
181862306a36Sopenharmony_ci	mutex_init(&adev->mman.gtt_window_lock);
181962306a36Sopenharmony_ci
182062306a36Sopenharmony_ci	/* No others user of address space so set it to 0 */
182162306a36Sopenharmony_ci	r = ttm_device_init(&adev->mman.bdev, &amdgpu_bo_driver, adev->dev,
182262306a36Sopenharmony_ci			       adev_to_drm(adev)->anon_inode->i_mapping,
182362306a36Sopenharmony_ci			       adev_to_drm(adev)->vma_offset_manager,
182462306a36Sopenharmony_ci			       adev->need_swiotlb,
182562306a36Sopenharmony_ci			       dma_addressing_limited(adev->dev));
182662306a36Sopenharmony_ci	if (r) {
182762306a36Sopenharmony_ci		DRM_ERROR("failed initializing buffer object driver(%d).\n", r);
182862306a36Sopenharmony_ci		return r;
182962306a36Sopenharmony_ci	}
183062306a36Sopenharmony_ci
183162306a36Sopenharmony_ci	r = amdgpu_ttm_pools_init(adev);
183262306a36Sopenharmony_ci	if (r) {
183362306a36Sopenharmony_ci		DRM_ERROR("failed to init ttm pools(%d).\n", r);
183462306a36Sopenharmony_ci		return r;
183562306a36Sopenharmony_ci	}
183662306a36Sopenharmony_ci	adev->mman.initialized = true;
183762306a36Sopenharmony_ci
183862306a36Sopenharmony_ci	/* Initialize VRAM pool with all of VRAM divided into pages */
183962306a36Sopenharmony_ci	r = amdgpu_vram_mgr_init(adev);
184062306a36Sopenharmony_ci	if (r) {
184162306a36Sopenharmony_ci		DRM_ERROR("Failed initializing VRAM heap.\n");
184262306a36Sopenharmony_ci		return r;
184362306a36Sopenharmony_ci	}
184462306a36Sopenharmony_ci
184562306a36Sopenharmony_ci	/* Change the size here instead of the init above so only lpfn is affected */
184662306a36Sopenharmony_ci	amdgpu_ttm_set_buffer_funcs_status(adev, false);
184762306a36Sopenharmony_ci#ifdef CONFIG_64BIT
184862306a36Sopenharmony_ci#ifdef CONFIG_X86
184962306a36Sopenharmony_ci	if (adev->gmc.xgmi.connected_to_cpu)
185062306a36Sopenharmony_ci		adev->mman.aper_base_kaddr = ioremap_cache(adev->gmc.aper_base,
185162306a36Sopenharmony_ci				adev->gmc.visible_vram_size);
185262306a36Sopenharmony_ci
185362306a36Sopenharmony_ci	else if (adev->gmc.is_app_apu)
185462306a36Sopenharmony_ci		DRM_DEBUG_DRIVER(
185562306a36Sopenharmony_ci			"No need to ioremap when real vram size is 0\n");
185662306a36Sopenharmony_ci	else
185762306a36Sopenharmony_ci#endif
185862306a36Sopenharmony_ci		adev->mman.aper_base_kaddr = ioremap_wc(adev->gmc.aper_base,
185962306a36Sopenharmony_ci				adev->gmc.visible_vram_size);
186062306a36Sopenharmony_ci#endif
186162306a36Sopenharmony_ci
186262306a36Sopenharmony_ci	/*
186362306a36Sopenharmony_ci	 *The reserved vram for firmware must be pinned to the specified
186462306a36Sopenharmony_ci	 *place on the VRAM, so reserve it early.
186562306a36Sopenharmony_ci	 */
186662306a36Sopenharmony_ci	r = amdgpu_ttm_fw_reserve_vram_init(adev);
186762306a36Sopenharmony_ci	if (r)
186862306a36Sopenharmony_ci		return r;
186962306a36Sopenharmony_ci
187062306a36Sopenharmony_ci	/*
187162306a36Sopenharmony_ci	 *The reserved vram for driver must be pinned to the specified
187262306a36Sopenharmony_ci	 *place on the VRAM, so reserve it early.
187362306a36Sopenharmony_ci	 */
187462306a36Sopenharmony_ci	r = amdgpu_ttm_drv_reserve_vram_init(adev);
187562306a36Sopenharmony_ci	if (r)
187662306a36Sopenharmony_ci		return r;
187762306a36Sopenharmony_ci
187862306a36Sopenharmony_ci	/*
187962306a36Sopenharmony_ci	 * only NAVI10 and onwards ASIC support for IP discovery.
188062306a36Sopenharmony_ci	 * If IP discovery enabled, a block of memory should be
188162306a36Sopenharmony_ci	 * reserved for IP discovey.
188262306a36Sopenharmony_ci	 */
188362306a36Sopenharmony_ci	if (adev->mman.discovery_bin) {
188462306a36Sopenharmony_ci		r = amdgpu_ttm_reserve_tmr(adev);
188562306a36Sopenharmony_ci		if (r)
188662306a36Sopenharmony_ci			return r;
188762306a36Sopenharmony_ci	}
188862306a36Sopenharmony_ci
188962306a36Sopenharmony_ci	/* allocate memory as required for VGA
189062306a36Sopenharmony_ci	 * This is used for VGA emulation and pre-OS scanout buffers to
189162306a36Sopenharmony_ci	 * avoid display artifacts while transitioning between pre-OS
189262306a36Sopenharmony_ci	 * and driver.
189362306a36Sopenharmony_ci	 */
189462306a36Sopenharmony_ci	if (!adev->gmc.is_app_apu) {
189562306a36Sopenharmony_ci		r = amdgpu_bo_create_kernel_at(adev, 0,
189662306a36Sopenharmony_ci					       adev->mman.stolen_vga_size,
189762306a36Sopenharmony_ci					       &adev->mman.stolen_vga_memory,
189862306a36Sopenharmony_ci					       NULL);
189962306a36Sopenharmony_ci		if (r)
190062306a36Sopenharmony_ci			return r;
190162306a36Sopenharmony_ci
190262306a36Sopenharmony_ci		r = amdgpu_bo_create_kernel_at(adev, adev->mman.stolen_vga_size,
190362306a36Sopenharmony_ci					       adev->mman.stolen_extended_size,
190462306a36Sopenharmony_ci					       &adev->mman.stolen_extended_memory,
190562306a36Sopenharmony_ci					       NULL);
190662306a36Sopenharmony_ci
190762306a36Sopenharmony_ci		if (r)
190862306a36Sopenharmony_ci			return r;
190962306a36Sopenharmony_ci
191062306a36Sopenharmony_ci		r = amdgpu_bo_create_kernel_at(adev,
191162306a36Sopenharmony_ci					       adev->mman.stolen_reserved_offset,
191262306a36Sopenharmony_ci					       adev->mman.stolen_reserved_size,
191362306a36Sopenharmony_ci					       &adev->mman.stolen_reserved_memory,
191462306a36Sopenharmony_ci					       NULL);
191562306a36Sopenharmony_ci		if (r)
191662306a36Sopenharmony_ci			return r;
191762306a36Sopenharmony_ci	} else {
191862306a36Sopenharmony_ci		DRM_DEBUG_DRIVER("Skipped stolen memory reservation\n");
191962306a36Sopenharmony_ci	}
192062306a36Sopenharmony_ci
192162306a36Sopenharmony_ci	DRM_INFO("amdgpu: %uM of VRAM memory ready\n",
192262306a36Sopenharmony_ci		 (unsigned int)(adev->gmc.real_vram_size / (1024 * 1024)));
192362306a36Sopenharmony_ci
192462306a36Sopenharmony_ci	/* Compute GTT size, either based on TTM limit
192562306a36Sopenharmony_ci	 * or whatever the user passed on module init.
192662306a36Sopenharmony_ci	 */
192762306a36Sopenharmony_ci	if (amdgpu_gtt_size == -1)
192862306a36Sopenharmony_ci		gtt_size = ttm_tt_pages_limit() << PAGE_SHIFT;
192962306a36Sopenharmony_ci	else
193062306a36Sopenharmony_ci		gtt_size = (uint64_t)amdgpu_gtt_size << 20;
193162306a36Sopenharmony_ci
193262306a36Sopenharmony_ci	/* Initialize GTT memory pool */
193362306a36Sopenharmony_ci	r = amdgpu_gtt_mgr_init(adev, gtt_size);
193462306a36Sopenharmony_ci	if (r) {
193562306a36Sopenharmony_ci		DRM_ERROR("Failed initializing GTT heap.\n");
193662306a36Sopenharmony_ci		return r;
193762306a36Sopenharmony_ci	}
193862306a36Sopenharmony_ci	DRM_INFO("amdgpu: %uM of GTT memory ready.\n",
193962306a36Sopenharmony_ci		 (unsigned int)(gtt_size / (1024 * 1024)));
194062306a36Sopenharmony_ci
194162306a36Sopenharmony_ci	/* Initiailize doorbell pool on PCI BAR */
194262306a36Sopenharmony_ci	r = amdgpu_ttm_init_on_chip(adev, AMDGPU_PL_DOORBELL, adev->doorbell.size / PAGE_SIZE);
194362306a36Sopenharmony_ci	if (r) {
194462306a36Sopenharmony_ci		DRM_ERROR("Failed initializing doorbell heap.\n");
194562306a36Sopenharmony_ci		return r;
194662306a36Sopenharmony_ci	}
194762306a36Sopenharmony_ci
194862306a36Sopenharmony_ci	/* Create a boorbell page for kernel usages */
194962306a36Sopenharmony_ci	r = amdgpu_doorbell_create_kernel_doorbells(adev);
195062306a36Sopenharmony_ci	if (r) {
195162306a36Sopenharmony_ci		DRM_ERROR("Failed to initialize kernel doorbells.\n");
195262306a36Sopenharmony_ci		return r;
195362306a36Sopenharmony_ci	}
195462306a36Sopenharmony_ci
195562306a36Sopenharmony_ci	/* Initialize preemptible memory pool */
195662306a36Sopenharmony_ci	r = amdgpu_preempt_mgr_init(adev);
195762306a36Sopenharmony_ci	if (r) {
195862306a36Sopenharmony_ci		DRM_ERROR("Failed initializing PREEMPT heap.\n");
195962306a36Sopenharmony_ci		return r;
196062306a36Sopenharmony_ci	}
196162306a36Sopenharmony_ci
196262306a36Sopenharmony_ci	/* Initialize various on-chip memory pools */
196362306a36Sopenharmony_ci	r = amdgpu_ttm_init_on_chip(adev, AMDGPU_PL_GDS, adev->gds.gds_size);
196462306a36Sopenharmony_ci	if (r) {
196562306a36Sopenharmony_ci		DRM_ERROR("Failed initializing GDS heap.\n");
196662306a36Sopenharmony_ci		return r;
196762306a36Sopenharmony_ci	}
196862306a36Sopenharmony_ci
196962306a36Sopenharmony_ci	r = amdgpu_ttm_init_on_chip(adev, AMDGPU_PL_GWS, adev->gds.gws_size);
197062306a36Sopenharmony_ci	if (r) {
197162306a36Sopenharmony_ci		DRM_ERROR("Failed initializing gws heap.\n");
197262306a36Sopenharmony_ci		return r;
197362306a36Sopenharmony_ci	}
197462306a36Sopenharmony_ci
197562306a36Sopenharmony_ci	r = amdgpu_ttm_init_on_chip(adev, AMDGPU_PL_OA, adev->gds.oa_size);
197662306a36Sopenharmony_ci	if (r) {
197762306a36Sopenharmony_ci		DRM_ERROR("Failed initializing oa heap.\n");
197862306a36Sopenharmony_ci		return r;
197962306a36Sopenharmony_ci	}
198062306a36Sopenharmony_ci	if (amdgpu_bo_create_kernel(adev, PAGE_SIZE, PAGE_SIZE,
198162306a36Sopenharmony_ci				AMDGPU_GEM_DOMAIN_GTT,
198262306a36Sopenharmony_ci				&adev->mman.sdma_access_bo, NULL,
198362306a36Sopenharmony_ci				&adev->mman.sdma_access_ptr))
198462306a36Sopenharmony_ci		DRM_WARN("Debug VRAM access will use slowpath MM access\n");
198562306a36Sopenharmony_ci
198662306a36Sopenharmony_ci	return 0;
198762306a36Sopenharmony_ci}
198862306a36Sopenharmony_ci
198962306a36Sopenharmony_ci/*
199062306a36Sopenharmony_ci * amdgpu_ttm_fini - De-initialize the TTM memory pools
199162306a36Sopenharmony_ci */
199262306a36Sopenharmony_civoid amdgpu_ttm_fini(struct amdgpu_device *adev)
199362306a36Sopenharmony_ci{
199462306a36Sopenharmony_ci	int idx;
199562306a36Sopenharmony_ci
199662306a36Sopenharmony_ci	if (!adev->mman.initialized)
199762306a36Sopenharmony_ci		return;
199862306a36Sopenharmony_ci
199962306a36Sopenharmony_ci	amdgpu_ttm_pools_fini(adev);
200062306a36Sopenharmony_ci
200162306a36Sopenharmony_ci	amdgpu_ttm_training_reserve_vram_fini(adev);
200262306a36Sopenharmony_ci	/* return the stolen vga memory back to VRAM */
200362306a36Sopenharmony_ci	if (!adev->gmc.is_app_apu) {
200462306a36Sopenharmony_ci		amdgpu_bo_free_kernel(&adev->mman.stolen_vga_memory, NULL, NULL);
200562306a36Sopenharmony_ci		amdgpu_bo_free_kernel(&adev->mman.stolen_extended_memory, NULL, NULL);
200662306a36Sopenharmony_ci		/* return the FW reserved memory back to VRAM */
200762306a36Sopenharmony_ci		amdgpu_bo_free_kernel(&adev->mman.fw_reserved_memory, NULL,
200862306a36Sopenharmony_ci				      NULL);
200962306a36Sopenharmony_ci		if (adev->mman.stolen_reserved_size)
201062306a36Sopenharmony_ci			amdgpu_bo_free_kernel(&adev->mman.stolen_reserved_memory,
201162306a36Sopenharmony_ci					      NULL, NULL);
201262306a36Sopenharmony_ci	}
201362306a36Sopenharmony_ci	amdgpu_bo_free_kernel(&adev->mman.sdma_access_bo, NULL,
201462306a36Sopenharmony_ci					&adev->mman.sdma_access_ptr);
201562306a36Sopenharmony_ci	amdgpu_ttm_fw_reserve_vram_fini(adev);
201662306a36Sopenharmony_ci	amdgpu_ttm_drv_reserve_vram_fini(adev);
201762306a36Sopenharmony_ci
201862306a36Sopenharmony_ci	if (drm_dev_enter(adev_to_drm(adev), &idx)) {
201962306a36Sopenharmony_ci
202062306a36Sopenharmony_ci		if (adev->mman.aper_base_kaddr)
202162306a36Sopenharmony_ci			iounmap(adev->mman.aper_base_kaddr);
202262306a36Sopenharmony_ci		adev->mman.aper_base_kaddr = NULL;
202362306a36Sopenharmony_ci
202462306a36Sopenharmony_ci		drm_dev_exit(idx);
202562306a36Sopenharmony_ci	}
202662306a36Sopenharmony_ci
202762306a36Sopenharmony_ci	amdgpu_vram_mgr_fini(adev);
202862306a36Sopenharmony_ci	amdgpu_gtt_mgr_fini(adev);
202962306a36Sopenharmony_ci	amdgpu_preempt_mgr_fini(adev);
203062306a36Sopenharmony_ci	ttm_range_man_fini(&adev->mman.bdev, AMDGPU_PL_GDS);
203162306a36Sopenharmony_ci	ttm_range_man_fini(&adev->mman.bdev, AMDGPU_PL_GWS);
203262306a36Sopenharmony_ci	ttm_range_man_fini(&adev->mman.bdev, AMDGPU_PL_OA);
203362306a36Sopenharmony_ci	ttm_device_fini(&adev->mman.bdev);
203462306a36Sopenharmony_ci	adev->mman.initialized = false;
203562306a36Sopenharmony_ci	DRM_INFO("amdgpu: ttm finalized\n");
203662306a36Sopenharmony_ci}
203762306a36Sopenharmony_ci
203862306a36Sopenharmony_ci/**
203962306a36Sopenharmony_ci * amdgpu_ttm_set_buffer_funcs_status - enable/disable use of buffer functions
204062306a36Sopenharmony_ci *
204162306a36Sopenharmony_ci * @adev: amdgpu_device pointer
204262306a36Sopenharmony_ci * @enable: true when we can use buffer functions.
204362306a36Sopenharmony_ci *
204462306a36Sopenharmony_ci * Enable/disable use of buffer functions during suspend/resume. This should
204562306a36Sopenharmony_ci * only be called at bootup or when userspace isn't running.
204662306a36Sopenharmony_ci */
204762306a36Sopenharmony_civoid amdgpu_ttm_set_buffer_funcs_status(struct amdgpu_device *adev, bool enable)
204862306a36Sopenharmony_ci{
204962306a36Sopenharmony_ci	struct ttm_resource_manager *man = ttm_manager_type(&adev->mman.bdev, TTM_PL_VRAM);
205062306a36Sopenharmony_ci	uint64_t size;
205162306a36Sopenharmony_ci	int r;
205262306a36Sopenharmony_ci
205362306a36Sopenharmony_ci	if (!adev->mman.initialized || amdgpu_in_reset(adev) ||
205462306a36Sopenharmony_ci	    adev->mman.buffer_funcs_enabled == enable || adev->gmc.is_app_apu)
205562306a36Sopenharmony_ci		return;
205662306a36Sopenharmony_ci
205762306a36Sopenharmony_ci	if (enable) {
205862306a36Sopenharmony_ci		struct amdgpu_ring *ring;
205962306a36Sopenharmony_ci		struct drm_gpu_scheduler *sched;
206062306a36Sopenharmony_ci
206162306a36Sopenharmony_ci		ring = adev->mman.buffer_funcs_ring;
206262306a36Sopenharmony_ci		sched = &ring->sched;
206362306a36Sopenharmony_ci		r = drm_sched_entity_init(&adev->mman.high_pr,
206462306a36Sopenharmony_ci					  DRM_SCHED_PRIORITY_KERNEL, &sched,
206562306a36Sopenharmony_ci					  1, NULL);
206662306a36Sopenharmony_ci		if (r) {
206762306a36Sopenharmony_ci			DRM_ERROR("Failed setting up TTM BO move entity (%d)\n",
206862306a36Sopenharmony_ci				  r);
206962306a36Sopenharmony_ci			return;
207062306a36Sopenharmony_ci		}
207162306a36Sopenharmony_ci
207262306a36Sopenharmony_ci		r = drm_sched_entity_init(&adev->mman.low_pr,
207362306a36Sopenharmony_ci					  DRM_SCHED_PRIORITY_NORMAL, &sched,
207462306a36Sopenharmony_ci					  1, NULL);
207562306a36Sopenharmony_ci		if (r) {
207662306a36Sopenharmony_ci			DRM_ERROR("Failed setting up TTM BO move entity (%d)\n",
207762306a36Sopenharmony_ci				  r);
207862306a36Sopenharmony_ci			goto error_free_entity;
207962306a36Sopenharmony_ci		}
208062306a36Sopenharmony_ci	} else {
208162306a36Sopenharmony_ci		drm_sched_entity_destroy(&adev->mman.high_pr);
208262306a36Sopenharmony_ci		drm_sched_entity_destroy(&adev->mman.low_pr);
208362306a36Sopenharmony_ci		dma_fence_put(man->move);
208462306a36Sopenharmony_ci		man->move = NULL;
208562306a36Sopenharmony_ci	}
208662306a36Sopenharmony_ci
208762306a36Sopenharmony_ci	/* this just adjusts TTM size idea, which sets lpfn to the correct value */
208862306a36Sopenharmony_ci	if (enable)
208962306a36Sopenharmony_ci		size = adev->gmc.real_vram_size;
209062306a36Sopenharmony_ci	else
209162306a36Sopenharmony_ci		size = adev->gmc.visible_vram_size;
209262306a36Sopenharmony_ci	man->size = size;
209362306a36Sopenharmony_ci	adev->mman.buffer_funcs_enabled = enable;
209462306a36Sopenharmony_ci
209562306a36Sopenharmony_ci	return;
209662306a36Sopenharmony_ci
209762306a36Sopenharmony_cierror_free_entity:
209862306a36Sopenharmony_ci	drm_sched_entity_destroy(&adev->mman.high_pr);
209962306a36Sopenharmony_ci}
210062306a36Sopenharmony_ci
210162306a36Sopenharmony_cistatic int amdgpu_ttm_prepare_job(struct amdgpu_device *adev,
210262306a36Sopenharmony_ci				  bool direct_submit,
210362306a36Sopenharmony_ci				  unsigned int num_dw,
210462306a36Sopenharmony_ci				  struct dma_resv *resv,
210562306a36Sopenharmony_ci				  bool vm_needs_flush,
210662306a36Sopenharmony_ci				  struct amdgpu_job **job,
210762306a36Sopenharmony_ci				  bool delayed)
210862306a36Sopenharmony_ci{
210962306a36Sopenharmony_ci	enum amdgpu_ib_pool_type pool = direct_submit ?
211062306a36Sopenharmony_ci		AMDGPU_IB_POOL_DIRECT :
211162306a36Sopenharmony_ci		AMDGPU_IB_POOL_DELAYED;
211262306a36Sopenharmony_ci	int r;
211362306a36Sopenharmony_ci	struct drm_sched_entity *entity = delayed ? &adev->mman.low_pr :
211462306a36Sopenharmony_ci						    &adev->mman.high_pr;
211562306a36Sopenharmony_ci	r = amdgpu_job_alloc_with_ib(adev, entity,
211662306a36Sopenharmony_ci				     AMDGPU_FENCE_OWNER_UNDEFINED,
211762306a36Sopenharmony_ci				     num_dw * 4, pool, job);
211862306a36Sopenharmony_ci	if (r)
211962306a36Sopenharmony_ci		return r;
212062306a36Sopenharmony_ci
212162306a36Sopenharmony_ci	if (vm_needs_flush) {
212262306a36Sopenharmony_ci		(*job)->vm_pd_addr = amdgpu_gmc_pd_addr(adev->gmc.pdb0_bo ?
212362306a36Sopenharmony_ci							adev->gmc.pdb0_bo :
212462306a36Sopenharmony_ci							adev->gart.bo);
212562306a36Sopenharmony_ci		(*job)->vm_needs_flush = true;
212662306a36Sopenharmony_ci	}
212762306a36Sopenharmony_ci	if (!resv)
212862306a36Sopenharmony_ci		return 0;
212962306a36Sopenharmony_ci
213062306a36Sopenharmony_ci	return drm_sched_job_add_resv_dependencies(&(*job)->base, resv,
213162306a36Sopenharmony_ci						   DMA_RESV_USAGE_BOOKKEEP);
213262306a36Sopenharmony_ci}
213362306a36Sopenharmony_ci
213462306a36Sopenharmony_ciint amdgpu_copy_buffer(struct amdgpu_ring *ring, uint64_t src_offset,
213562306a36Sopenharmony_ci		       uint64_t dst_offset, uint32_t byte_count,
213662306a36Sopenharmony_ci		       struct dma_resv *resv,
213762306a36Sopenharmony_ci		       struct dma_fence **fence, bool direct_submit,
213862306a36Sopenharmony_ci		       bool vm_needs_flush, bool tmz)
213962306a36Sopenharmony_ci{
214062306a36Sopenharmony_ci	struct amdgpu_device *adev = ring->adev;
214162306a36Sopenharmony_ci	unsigned int num_loops, num_dw;
214262306a36Sopenharmony_ci	struct amdgpu_job *job;
214362306a36Sopenharmony_ci	uint32_t max_bytes;
214462306a36Sopenharmony_ci	unsigned int i;
214562306a36Sopenharmony_ci	int r;
214662306a36Sopenharmony_ci
214762306a36Sopenharmony_ci	if (!direct_submit && !ring->sched.ready) {
214862306a36Sopenharmony_ci		DRM_ERROR("Trying to move memory with ring turned off.\n");
214962306a36Sopenharmony_ci		return -EINVAL;
215062306a36Sopenharmony_ci	}
215162306a36Sopenharmony_ci
215262306a36Sopenharmony_ci	max_bytes = adev->mman.buffer_funcs->copy_max_bytes;
215362306a36Sopenharmony_ci	num_loops = DIV_ROUND_UP(byte_count, max_bytes);
215462306a36Sopenharmony_ci	num_dw = ALIGN(num_loops * adev->mman.buffer_funcs->copy_num_dw, 8);
215562306a36Sopenharmony_ci	r = amdgpu_ttm_prepare_job(adev, direct_submit, num_dw,
215662306a36Sopenharmony_ci				   resv, vm_needs_flush, &job, false);
215762306a36Sopenharmony_ci	if (r)
215862306a36Sopenharmony_ci		return r;
215962306a36Sopenharmony_ci
216062306a36Sopenharmony_ci	for (i = 0; i < num_loops; i++) {
216162306a36Sopenharmony_ci		uint32_t cur_size_in_bytes = min(byte_count, max_bytes);
216262306a36Sopenharmony_ci
216362306a36Sopenharmony_ci		amdgpu_emit_copy_buffer(adev, &job->ibs[0], src_offset,
216462306a36Sopenharmony_ci					dst_offset, cur_size_in_bytes, tmz);
216562306a36Sopenharmony_ci
216662306a36Sopenharmony_ci		src_offset += cur_size_in_bytes;
216762306a36Sopenharmony_ci		dst_offset += cur_size_in_bytes;
216862306a36Sopenharmony_ci		byte_count -= cur_size_in_bytes;
216962306a36Sopenharmony_ci	}
217062306a36Sopenharmony_ci
217162306a36Sopenharmony_ci	amdgpu_ring_pad_ib(ring, &job->ibs[0]);
217262306a36Sopenharmony_ci	WARN_ON(job->ibs[0].length_dw > num_dw);
217362306a36Sopenharmony_ci	if (direct_submit)
217462306a36Sopenharmony_ci		r = amdgpu_job_submit_direct(job, ring, fence);
217562306a36Sopenharmony_ci	else
217662306a36Sopenharmony_ci		*fence = amdgpu_job_submit(job);
217762306a36Sopenharmony_ci	if (r)
217862306a36Sopenharmony_ci		goto error_free;
217962306a36Sopenharmony_ci
218062306a36Sopenharmony_ci	return r;
218162306a36Sopenharmony_ci
218262306a36Sopenharmony_cierror_free:
218362306a36Sopenharmony_ci	amdgpu_job_free(job);
218462306a36Sopenharmony_ci	DRM_ERROR("Error scheduling IBs (%d)\n", r);
218562306a36Sopenharmony_ci	return r;
218662306a36Sopenharmony_ci}
218762306a36Sopenharmony_ci
218862306a36Sopenharmony_cistatic int amdgpu_ttm_fill_mem(struct amdgpu_ring *ring, uint32_t src_data,
218962306a36Sopenharmony_ci			       uint64_t dst_addr, uint32_t byte_count,
219062306a36Sopenharmony_ci			       struct dma_resv *resv,
219162306a36Sopenharmony_ci			       struct dma_fence **fence,
219262306a36Sopenharmony_ci			       bool vm_needs_flush, bool delayed)
219362306a36Sopenharmony_ci{
219462306a36Sopenharmony_ci	struct amdgpu_device *adev = ring->adev;
219562306a36Sopenharmony_ci	unsigned int num_loops, num_dw;
219662306a36Sopenharmony_ci	struct amdgpu_job *job;
219762306a36Sopenharmony_ci	uint32_t max_bytes;
219862306a36Sopenharmony_ci	unsigned int i;
219962306a36Sopenharmony_ci	int r;
220062306a36Sopenharmony_ci
220162306a36Sopenharmony_ci	max_bytes = adev->mman.buffer_funcs->fill_max_bytes;
220262306a36Sopenharmony_ci	num_loops = DIV_ROUND_UP_ULL(byte_count, max_bytes);
220362306a36Sopenharmony_ci	num_dw = ALIGN(num_loops * adev->mman.buffer_funcs->fill_num_dw, 8);
220462306a36Sopenharmony_ci	r = amdgpu_ttm_prepare_job(adev, false, num_dw, resv, vm_needs_flush,
220562306a36Sopenharmony_ci				   &job, delayed);
220662306a36Sopenharmony_ci	if (r)
220762306a36Sopenharmony_ci		return r;
220862306a36Sopenharmony_ci
220962306a36Sopenharmony_ci	for (i = 0; i < num_loops; i++) {
221062306a36Sopenharmony_ci		uint32_t cur_size = min(byte_count, max_bytes);
221162306a36Sopenharmony_ci
221262306a36Sopenharmony_ci		amdgpu_emit_fill_buffer(adev, &job->ibs[0], src_data, dst_addr,
221362306a36Sopenharmony_ci					cur_size);
221462306a36Sopenharmony_ci
221562306a36Sopenharmony_ci		dst_addr += cur_size;
221662306a36Sopenharmony_ci		byte_count -= cur_size;
221762306a36Sopenharmony_ci	}
221862306a36Sopenharmony_ci
221962306a36Sopenharmony_ci	amdgpu_ring_pad_ib(ring, &job->ibs[0]);
222062306a36Sopenharmony_ci	WARN_ON(job->ibs[0].length_dw > num_dw);
222162306a36Sopenharmony_ci	*fence = amdgpu_job_submit(job);
222262306a36Sopenharmony_ci	return 0;
222362306a36Sopenharmony_ci}
222462306a36Sopenharmony_ci
222562306a36Sopenharmony_ciint amdgpu_fill_buffer(struct amdgpu_bo *bo,
222662306a36Sopenharmony_ci			uint32_t src_data,
222762306a36Sopenharmony_ci			struct dma_resv *resv,
222862306a36Sopenharmony_ci			struct dma_fence **f,
222962306a36Sopenharmony_ci			bool delayed)
223062306a36Sopenharmony_ci{
223162306a36Sopenharmony_ci	struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev);
223262306a36Sopenharmony_ci	struct amdgpu_ring *ring = adev->mman.buffer_funcs_ring;
223362306a36Sopenharmony_ci	struct dma_fence *fence = NULL;
223462306a36Sopenharmony_ci	struct amdgpu_res_cursor dst;
223562306a36Sopenharmony_ci	int r;
223662306a36Sopenharmony_ci
223762306a36Sopenharmony_ci	if (!adev->mman.buffer_funcs_enabled) {
223862306a36Sopenharmony_ci		DRM_ERROR("Trying to clear memory with ring turned off.\n");
223962306a36Sopenharmony_ci		return -EINVAL;
224062306a36Sopenharmony_ci	}
224162306a36Sopenharmony_ci
224262306a36Sopenharmony_ci	amdgpu_res_first(bo->tbo.resource, 0, amdgpu_bo_size(bo), &dst);
224362306a36Sopenharmony_ci
224462306a36Sopenharmony_ci	mutex_lock(&adev->mman.gtt_window_lock);
224562306a36Sopenharmony_ci	while (dst.remaining) {
224662306a36Sopenharmony_ci		struct dma_fence *next;
224762306a36Sopenharmony_ci		uint64_t cur_size, to;
224862306a36Sopenharmony_ci
224962306a36Sopenharmony_ci		/* Never fill more than 256MiB at once to avoid timeouts */
225062306a36Sopenharmony_ci		cur_size = min(dst.size, 256ULL << 20);
225162306a36Sopenharmony_ci
225262306a36Sopenharmony_ci		r = amdgpu_ttm_map_buffer(&bo->tbo, bo->tbo.resource, &dst,
225362306a36Sopenharmony_ci					  1, ring, false, &cur_size, &to);
225462306a36Sopenharmony_ci		if (r)
225562306a36Sopenharmony_ci			goto error;
225662306a36Sopenharmony_ci
225762306a36Sopenharmony_ci		r = amdgpu_ttm_fill_mem(ring, src_data, to, cur_size, resv,
225862306a36Sopenharmony_ci					&next, true, delayed);
225962306a36Sopenharmony_ci		if (r)
226062306a36Sopenharmony_ci			goto error;
226162306a36Sopenharmony_ci
226262306a36Sopenharmony_ci		dma_fence_put(fence);
226362306a36Sopenharmony_ci		fence = next;
226462306a36Sopenharmony_ci
226562306a36Sopenharmony_ci		amdgpu_res_next(&dst, cur_size);
226662306a36Sopenharmony_ci	}
226762306a36Sopenharmony_cierror:
226862306a36Sopenharmony_ci	mutex_unlock(&adev->mman.gtt_window_lock);
226962306a36Sopenharmony_ci	if (f)
227062306a36Sopenharmony_ci		*f = dma_fence_get(fence);
227162306a36Sopenharmony_ci	dma_fence_put(fence);
227262306a36Sopenharmony_ci	return r;
227362306a36Sopenharmony_ci}
227462306a36Sopenharmony_ci
227562306a36Sopenharmony_ci/**
227662306a36Sopenharmony_ci * amdgpu_ttm_evict_resources - evict memory buffers
227762306a36Sopenharmony_ci * @adev: amdgpu device object
227862306a36Sopenharmony_ci * @mem_type: evicted BO's memory type
227962306a36Sopenharmony_ci *
228062306a36Sopenharmony_ci * Evicts all @mem_type buffers on the lru list of the memory type.
228162306a36Sopenharmony_ci *
228262306a36Sopenharmony_ci * Returns:
228362306a36Sopenharmony_ci * 0 for success or a negative error code on failure.
228462306a36Sopenharmony_ci */
228562306a36Sopenharmony_ciint amdgpu_ttm_evict_resources(struct amdgpu_device *adev, int mem_type)
228662306a36Sopenharmony_ci{
228762306a36Sopenharmony_ci	struct ttm_resource_manager *man;
228862306a36Sopenharmony_ci
228962306a36Sopenharmony_ci	switch (mem_type) {
229062306a36Sopenharmony_ci	case TTM_PL_VRAM:
229162306a36Sopenharmony_ci	case TTM_PL_TT:
229262306a36Sopenharmony_ci	case AMDGPU_PL_GWS:
229362306a36Sopenharmony_ci	case AMDGPU_PL_GDS:
229462306a36Sopenharmony_ci	case AMDGPU_PL_OA:
229562306a36Sopenharmony_ci		man = ttm_manager_type(&adev->mman.bdev, mem_type);
229662306a36Sopenharmony_ci		break;
229762306a36Sopenharmony_ci	default:
229862306a36Sopenharmony_ci		DRM_ERROR("Trying to evict invalid memory type\n");
229962306a36Sopenharmony_ci		return -EINVAL;
230062306a36Sopenharmony_ci	}
230162306a36Sopenharmony_ci
230262306a36Sopenharmony_ci	return ttm_resource_manager_evict_all(&adev->mman.bdev, man);
230362306a36Sopenharmony_ci}
230462306a36Sopenharmony_ci
230562306a36Sopenharmony_ci#if defined(CONFIG_DEBUG_FS)
230662306a36Sopenharmony_ci
230762306a36Sopenharmony_cistatic int amdgpu_ttm_page_pool_show(struct seq_file *m, void *unused)
230862306a36Sopenharmony_ci{
230962306a36Sopenharmony_ci	struct amdgpu_device *adev = m->private;
231062306a36Sopenharmony_ci
231162306a36Sopenharmony_ci	return ttm_pool_debugfs(&adev->mman.bdev.pool, m);
231262306a36Sopenharmony_ci}
231362306a36Sopenharmony_ci
231462306a36Sopenharmony_ciDEFINE_SHOW_ATTRIBUTE(amdgpu_ttm_page_pool);
231562306a36Sopenharmony_ci
231662306a36Sopenharmony_ci/*
231762306a36Sopenharmony_ci * amdgpu_ttm_vram_read - Linear read access to VRAM
231862306a36Sopenharmony_ci *
231962306a36Sopenharmony_ci * Accesses VRAM via MMIO for debugging purposes.
232062306a36Sopenharmony_ci */
232162306a36Sopenharmony_cistatic ssize_t amdgpu_ttm_vram_read(struct file *f, char __user *buf,
232262306a36Sopenharmony_ci				    size_t size, loff_t *pos)
232362306a36Sopenharmony_ci{
232462306a36Sopenharmony_ci	struct amdgpu_device *adev = file_inode(f)->i_private;
232562306a36Sopenharmony_ci	ssize_t result = 0;
232662306a36Sopenharmony_ci
232762306a36Sopenharmony_ci	if (size & 0x3 || *pos & 0x3)
232862306a36Sopenharmony_ci		return -EINVAL;
232962306a36Sopenharmony_ci
233062306a36Sopenharmony_ci	if (*pos >= adev->gmc.mc_vram_size)
233162306a36Sopenharmony_ci		return -ENXIO;
233262306a36Sopenharmony_ci
233362306a36Sopenharmony_ci	size = min(size, (size_t)(adev->gmc.mc_vram_size - *pos));
233462306a36Sopenharmony_ci	while (size) {
233562306a36Sopenharmony_ci		size_t bytes = min(size, AMDGPU_TTM_VRAM_MAX_DW_READ * 4);
233662306a36Sopenharmony_ci		uint32_t value[AMDGPU_TTM_VRAM_MAX_DW_READ];
233762306a36Sopenharmony_ci
233862306a36Sopenharmony_ci		amdgpu_device_vram_access(adev, *pos, value, bytes, false);
233962306a36Sopenharmony_ci		if (copy_to_user(buf, value, bytes))
234062306a36Sopenharmony_ci			return -EFAULT;
234162306a36Sopenharmony_ci
234262306a36Sopenharmony_ci		result += bytes;
234362306a36Sopenharmony_ci		buf += bytes;
234462306a36Sopenharmony_ci		*pos += bytes;
234562306a36Sopenharmony_ci		size -= bytes;
234662306a36Sopenharmony_ci	}
234762306a36Sopenharmony_ci
234862306a36Sopenharmony_ci	return result;
234962306a36Sopenharmony_ci}
235062306a36Sopenharmony_ci
235162306a36Sopenharmony_ci/*
235262306a36Sopenharmony_ci * amdgpu_ttm_vram_write - Linear write access to VRAM
235362306a36Sopenharmony_ci *
235462306a36Sopenharmony_ci * Accesses VRAM via MMIO for debugging purposes.
235562306a36Sopenharmony_ci */
235662306a36Sopenharmony_cistatic ssize_t amdgpu_ttm_vram_write(struct file *f, const char __user *buf,
235762306a36Sopenharmony_ci				    size_t size, loff_t *pos)
235862306a36Sopenharmony_ci{
235962306a36Sopenharmony_ci	struct amdgpu_device *adev = file_inode(f)->i_private;
236062306a36Sopenharmony_ci	ssize_t result = 0;
236162306a36Sopenharmony_ci	int r;
236262306a36Sopenharmony_ci
236362306a36Sopenharmony_ci	if (size & 0x3 || *pos & 0x3)
236462306a36Sopenharmony_ci		return -EINVAL;
236562306a36Sopenharmony_ci
236662306a36Sopenharmony_ci	if (*pos >= adev->gmc.mc_vram_size)
236762306a36Sopenharmony_ci		return -ENXIO;
236862306a36Sopenharmony_ci
236962306a36Sopenharmony_ci	while (size) {
237062306a36Sopenharmony_ci		uint32_t value;
237162306a36Sopenharmony_ci
237262306a36Sopenharmony_ci		if (*pos >= adev->gmc.mc_vram_size)
237362306a36Sopenharmony_ci			return result;
237462306a36Sopenharmony_ci
237562306a36Sopenharmony_ci		r = get_user(value, (uint32_t *)buf);
237662306a36Sopenharmony_ci		if (r)
237762306a36Sopenharmony_ci			return r;
237862306a36Sopenharmony_ci
237962306a36Sopenharmony_ci		amdgpu_device_mm_access(adev, *pos, &value, 4, true);
238062306a36Sopenharmony_ci
238162306a36Sopenharmony_ci		result += 4;
238262306a36Sopenharmony_ci		buf += 4;
238362306a36Sopenharmony_ci		*pos += 4;
238462306a36Sopenharmony_ci		size -= 4;
238562306a36Sopenharmony_ci	}
238662306a36Sopenharmony_ci
238762306a36Sopenharmony_ci	return result;
238862306a36Sopenharmony_ci}
238962306a36Sopenharmony_ci
239062306a36Sopenharmony_cistatic const struct file_operations amdgpu_ttm_vram_fops = {
239162306a36Sopenharmony_ci	.owner = THIS_MODULE,
239262306a36Sopenharmony_ci	.read = amdgpu_ttm_vram_read,
239362306a36Sopenharmony_ci	.write = amdgpu_ttm_vram_write,
239462306a36Sopenharmony_ci	.llseek = default_llseek,
239562306a36Sopenharmony_ci};
239662306a36Sopenharmony_ci
239762306a36Sopenharmony_ci/*
239862306a36Sopenharmony_ci * amdgpu_iomem_read - Virtual read access to GPU mapped memory
239962306a36Sopenharmony_ci *
240062306a36Sopenharmony_ci * This function is used to read memory that has been mapped to the
240162306a36Sopenharmony_ci * GPU and the known addresses are not physical addresses but instead
240262306a36Sopenharmony_ci * bus addresses (e.g., what you'd put in an IB or ring buffer).
240362306a36Sopenharmony_ci */
240462306a36Sopenharmony_cistatic ssize_t amdgpu_iomem_read(struct file *f, char __user *buf,
240562306a36Sopenharmony_ci				 size_t size, loff_t *pos)
240662306a36Sopenharmony_ci{
240762306a36Sopenharmony_ci	struct amdgpu_device *adev = file_inode(f)->i_private;
240862306a36Sopenharmony_ci	struct iommu_domain *dom;
240962306a36Sopenharmony_ci	ssize_t result = 0;
241062306a36Sopenharmony_ci	int r;
241162306a36Sopenharmony_ci
241262306a36Sopenharmony_ci	/* retrieve the IOMMU domain if any for this device */
241362306a36Sopenharmony_ci	dom = iommu_get_domain_for_dev(adev->dev);
241462306a36Sopenharmony_ci
241562306a36Sopenharmony_ci	while (size) {
241662306a36Sopenharmony_ci		phys_addr_t addr = *pos & PAGE_MASK;
241762306a36Sopenharmony_ci		loff_t off = *pos & ~PAGE_MASK;
241862306a36Sopenharmony_ci		size_t bytes = PAGE_SIZE - off;
241962306a36Sopenharmony_ci		unsigned long pfn;
242062306a36Sopenharmony_ci		struct page *p;
242162306a36Sopenharmony_ci		void *ptr;
242262306a36Sopenharmony_ci
242362306a36Sopenharmony_ci		bytes = min(bytes, size);
242462306a36Sopenharmony_ci
242562306a36Sopenharmony_ci		/* Translate the bus address to a physical address.  If
242662306a36Sopenharmony_ci		 * the domain is NULL it means there is no IOMMU active
242762306a36Sopenharmony_ci		 * and the address translation is the identity
242862306a36Sopenharmony_ci		 */
242962306a36Sopenharmony_ci		addr = dom ? iommu_iova_to_phys(dom, addr) : addr;
243062306a36Sopenharmony_ci
243162306a36Sopenharmony_ci		pfn = addr >> PAGE_SHIFT;
243262306a36Sopenharmony_ci		if (!pfn_valid(pfn))
243362306a36Sopenharmony_ci			return -EPERM;
243462306a36Sopenharmony_ci
243562306a36Sopenharmony_ci		p = pfn_to_page(pfn);
243662306a36Sopenharmony_ci		if (p->mapping != adev->mman.bdev.dev_mapping)
243762306a36Sopenharmony_ci			return -EPERM;
243862306a36Sopenharmony_ci
243962306a36Sopenharmony_ci		ptr = kmap_local_page(p);
244062306a36Sopenharmony_ci		r = copy_to_user(buf, ptr + off, bytes);
244162306a36Sopenharmony_ci		kunmap_local(ptr);
244262306a36Sopenharmony_ci		if (r)
244362306a36Sopenharmony_ci			return -EFAULT;
244462306a36Sopenharmony_ci
244562306a36Sopenharmony_ci		size -= bytes;
244662306a36Sopenharmony_ci		*pos += bytes;
244762306a36Sopenharmony_ci		result += bytes;
244862306a36Sopenharmony_ci	}
244962306a36Sopenharmony_ci
245062306a36Sopenharmony_ci	return result;
245162306a36Sopenharmony_ci}
245262306a36Sopenharmony_ci
245362306a36Sopenharmony_ci/*
245462306a36Sopenharmony_ci * amdgpu_iomem_write - Virtual write access to GPU mapped memory
245562306a36Sopenharmony_ci *
245662306a36Sopenharmony_ci * This function is used to write memory that has been mapped to the
245762306a36Sopenharmony_ci * GPU and the known addresses are not physical addresses but instead
245862306a36Sopenharmony_ci * bus addresses (e.g., what you'd put in an IB or ring buffer).
245962306a36Sopenharmony_ci */
246062306a36Sopenharmony_cistatic ssize_t amdgpu_iomem_write(struct file *f, const char __user *buf,
246162306a36Sopenharmony_ci				 size_t size, loff_t *pos)
246262306a36Sopenharmony_ci{
246362306a36Sopenharmony_ci	struct amdgpu_device *adev = file_inode(f)->i_private;
246462306a36Sopenharmony_ci	struct iommu_domain *dom;
246562306a36Sopenharmony_ci	ssize_t result = 0;
246662306a36Sopenharmony_ci	int r;
246762306a36Sopenharmony_ci
246862306a36Sopenharmony_ci	dom = iommu_get_domain_for_dev(adev->dev);
246962306a36Sopenharmony_ci
247062306a36Sopenharmony_ci	while (size) {
247162306a36Sopenharmony_ci		phys_addr_t addr = *pos & PAGE_MASK;
247262306a36Sopenharmony_ci		loff_t off = *pos & ~PAGE_MASK;
247362306a36Sopenharmony_ci		size_t bytes = PAGE_SIZE - off;
247462306a36Sopenharmony_ci		unsigned long pfn;
247562306a36Sopenharmony_ci		struct page *p;
247662306a36Sopenharmony_ci		void *ptr;
247762306a36Sopenharmony_ci
247862306a36Sopenharmony_ci		bytes = min(bytes, size);
247962306a36Sopenharmony_ci
248062306a36Sopenharmony_ci		addr = dom ? iommu_iova_to_phys(dom, addr) : addr;
248162306a36Sopenharmony_ci
248262306a36Sopenharmony_ci		pfn = addr >> PAGE_SHIFT;
248362306a36Sopenharmony_ci		if (!pfn_valid(pfn))
248462306a36Sopenharmony_ci			return -EPERM;
248562306a36Sopenharmony_ci
248662306a36Sopenharmony_ci		p = pfn_to_page(pfn);
248762306a36Sopenharmony_ci		if (p->mapping != adev->mman.bdev.dev_mapping)
248862306a36Sopenharmony_ci			return -EPERM;
248962306a36Sopenharmony_ci
249062306a36Sopenharmony_ci		ptr = kmap_local_page(p);
249162306a36Sopenharmony_ci		r = copy_from_user(ptr + off, buf, bytes);
249262306a36Sopenharmony_ci		kunmap_local(ptr);
249362306a36Sopenharmony_ci		if (r)
249462306a36Sopenharmony_ci			return -EFAULT;
249562306a36Sopenharmony_ci
249662306a36Sopenharmony_ci		size -= bytes;
249762306a36Sopenharmony_ci		*pos += bytes;
249862306a36Sopenharmony_ci		result += bytes;
249962306a36Sopenharmony_ci	}
250062306a36Sopenharmony_ci
250162306a36Sopenharmony_ci	return result;
250262306a36Sopenharmony_ci}
250362306a36Sopenharmony_ci
250462306a36Sopenharmony_cistatic const struct file_operations amdgpu_ttm_iomem_fops = {
250562306a36Sopenharmony_ci	.owner = THIS_MODULE,
250662306a36Sopenharmony_ci	.read = amdgpu_iomem_read,
250762306a36Sopenharmony_ci	.write = amdgpu_iomem_write,
250862306a36Sopenharmony_ci	.llseek = default_llseek
250962306a36Sopenharmony_ci};
251062306a36Sopenharmony_ci
251162306a36Sopenharmony_ci#endif
251262306a36Sopenharmony_ci
251362306a36Sopenharmony_civoid amdgpu_ttm_debugfs_init(struct amdgpu_device *adev)
251462306a36Sopenharmony_ci{
251562306a36Sopenharmony_ci#if defined(CONFIG_DEBUG_FS)
251662306a36Sopenharmony_ci	struct drm_minor *minor = adev_to_drm(adev)->primary;
251762306a36Sopenharmony_ci	struct dentry *root = minor->debugfs_root;
251862306a36Sopenharmony_ci
251962306a36Sopenharmony_ci	debugfs_create_file_size("amdgpu_vram", 0444, root, adev,
252062306a36Sopenharmony_ci				 &amdgpu_ttm_vram_fops, adev->gmc.mc_vram_size);
252162306a36Sopenharmony_ci	debugfs_create_file("amdgpu_iomem", 0444, root, adev,
252262306a36Sopenharmony_ci			    &amdgpu_ttm_iomem_fops);
252362306a36Sopenharmony_ci	debugfs_create_file("ttm_page_pool", 0444, root, adev,
252462306a36Sopenharmony_ci			    &amdgpu_ttm_page_pool_fops);
252562306a36Sopenharmony_ci	ttm_resource_manager_create_debugfs(ttm_manager_type(&adev->mman.bdev,
252662306a36Sopenharmony_ci							     TTM_PL_VRAM),
252762306a36Sopenharmony_ci					    root, "amdgpu_vram_mm");
252862306a36Sopenharmony_ci	ttm_resource_manager_create_debugfs(ttm_manager_type(&adev->mman.bdev,
252962306a36Sopenharmony_ci							     TTM_PL_TT),
253062306a36Sopenharmony_ci					    root, "amdgpu_gtt_mm");
253162306a36Sopenharmony_ci	ttm_resource_manager_create_debugfs(ttm_manager_type(&adev->mman.bdev,
253262306a36Sopenharmony_ci							     AMDGPU_PL_GDS),
253362306a36Sopenharmony_ci					    root, "amdgpu_gds_mm");
253462306a36Sopenharmony_ci	ttm_resource_manager_create_debugfs(ttm_manager_type(&adev->mman.bdev,
253562306a36Sopenharmony_ci							     AMDGPU_PL_GWS),
253662306a36Sopenharmony_ci					    root, "amdgpu_gws_mm");
253762306a36Sopenharmony_ci	ttm_resource_manager_create_debugfs(ttm_manager_type(&adev->mman.bdev,
253862306a36Sopenharmony_ci							     AMDGPU_PL_OA),
253962306a36Sopenharmony_ci					    root, "amdgpu_oa_mm");
254062306a36Sopenharmony_ci
254162306a36Sopenharmony_ci#endif
254262306a36Sopenharmony_ci}
2543