1d38ceaf9SAlex Deucher /*
2d38ceaf9SAlex Deucher * Copyright 2009 Jerome Glisse.
3d38ceaf9SAlex Deucher * All Rights Reserved.
4d38ceaf9SAlex Deucher *
5d38ceaf9SAlex Deucher * Permission is hereby granted, free of charge, to any person obtaining a
6d38ceaf9SAlex Deucher * copy of this software and associated documentation files (the
7d38ceaf9SAlex Deucher * "Software"), to deal in the Software without restriction, including
8d38ceaf9SAlex Deucher * without limitation the rights to use, copy, modify, merge, publish,
9d38ceaf9SAlex Deucher * distribute, sub license, and/or sell copies of the Software, and to
10d38ceaf9SAlex Deucher * permit persons to whom the Software is furnished to do so, subject to
11d38ceaf9SAlex Deucher * the following conditions:
12d38ceaf9SAlex Deucher *
13d38ceaf9SAlex Deucher * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14d38ceaf9SAlex Deucher * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15d38ceaf9SAlex Deucher * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
16d38ceaf9SAlex Deucher * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
17d38ceaf9SAlex Deucher * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
18d38ceaf9SAlex Deucher * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
19d38ceaf9SAlex Deucher * USE OR OTHER DEALINGS IN THE SOFTWARE.
20d38ceaf9SAlex Deucher *
21d38ceaf9SAlex Deucher * The above copyright notice and this permission notice (including the
22d38ceaf9SAlex Deucher * next paragraph) shall be included in all copies or substantial portions
23d38ceaf9SAlex Deucher * of the Software.
24d38ceaf9SAlex Deucher *
25d38ceaf9SAlex Deucher */
26d38ceaf9SAlex Deucher /*
27d38ceaf9SAlex Deucher * Authors:
28d38ceaf9SAlex Deucher * Jerome Glisse <glisse@freedesktop.org>
29d38ceaf9SAlex Deucher * Thomas Hellstrom <thomas-at-tungstengraphics-dot-com>
30d38ceaf9SAlex Deucher * Dave Airlie
31d38ceaf9SAlex Deucher */
32c366be54SSam Ravnborg
33fdf2f6c5SSam Ravnborg #include <linux/dma-mapping.h>
34c366be54SSam Ravnborg #include <linux/iommu.h>
35c366be54SSam Ravnborg #include <linux/pagemap.h>
36c366be54SSam Ravnborg #include <linux/sched/task.h>
37a9ae8731SJason Gunthorpe #include <linux/sched/mm.h>
38c366be54SSam Ravnborg #include <linux/seq_file.h>
39c366be54SSam Ravnborg #include <linux/slab.h>
40c366be54SSam Ravnborg #include <linux/swap.h>
41a3941471SChristian König #include <linux/dma-buf.h>
42f81110b8SFlora Cui #include <linux/sizes.h>
4316b0314aSGreg Kroah-Hartman #include <linux/module.h>
44c366be54SSam Ravnborg
4562d5f9f7SLeslie Shi #include <drm/drm_drv.h>
46a3185f91SChristian König #include <drm/ttm/ttm_bo.h>
47248a1d6fSMasahiro Yamada #include <drm/ttm/ttm_placement.h>
483eb7d96eSChristian König #include <drm/ttm/ttm_range_manager.h>
49a3185f91SChristian König #include <drm/ttm/ttm_tt.h>
50fdf2f6c5SSam Ravnborg
51d38ceaf9SAlex Deucher #include <drm/amdgpu_drm.h>
522454fceaSDaniel Vetter
53d38ceaf9SAlex Deucher #include "amdgpu.h"
54b82485fdSAndres Rodriguez #include "amdgpu_object.h"
55aca81718STom St Denis #include "amdgpu_trace.h"
56d8d019ccSFelix Kuehling #include "amdgpu_amdkfd.h"
57bb7743bcSHuang Rui #include "amdgpu_sdma.h"
581a6fc071STao Zhou #include "amdgpu_ras.h"
59d9483ecdSChristian König #include "amdgpu_hmm.h"
6087ba7feaSHawking Zhang #include "amdgpu_atomfirmware.h"
61be956c57SChristian König #include "amdgpu_res_cursor.h"
62d38ceaf9SAlex Deucher #include "bif/bif_4_1_d.h"
63d38ceaf9SAlex Deucher
6416b0314aSGreg Kroah-Hartman MODULE_IMPORT_NS(DMA_BUF);
6516b0314aSGreg Kroah-Hartman
6601c3f464SSrinivasan Shanmugam #define AMDGPU_TTM_VRAM_MAX_DW_READ ((size_t)128)
67030d5b97SChristian König
688af8a109SChristian König static int amdgpu_ttm_backend_bind(struct ttm_device *bdev,
69cae515f4SDave Airlie struct ttm_tt *ttm,
70cae515f4SDave Airlie struct ttm_resource *bo_mem);
718af8a109SChristian König static void amdgpu_ttm_backend_unbind(struct ttm_device *bdev,
7229a1d482SDave Airlie struct ttm_tt *ttm);
73cae515f4SDave Airlie
amdgpu_ttm_init_on_chip(struct amdgpu_device * adev,unsigned int type,uint64_t size_in_page)7447363354SChristian König static int amdgpu_ttm_init_on_chip(struct amdgpu_device *adev,
7547363354SChristian König unsigned int type,
76d836917dSxinhui pan uint64_t size_in_page)
7747363354SChristian König {
7837205891SDave Airlie return ttm_range_man_init(&adev->mman.bdev, type,
79d836917dSxinhui pan false, size_in_page);
80d38ceaf9SAlex Deucher }
81d38ceaf9SAlex Deucher
8250da5174STom St Denis /**
8350da5174STom St Denis * amdgpu_evict_flags - Compute placement flags
8450da5174STom St Denis *
8550da5174STom St Denis * @bo: The buffer object to evict
8650da5174STom St Denis * @placement: Possible destination(s) for evicted BO
8750da5174STom St Denis *
8850da5174STom St Denis * Fill in placement data when ttm_bo_evict() is called
8950da5174STom St Denis */
amdgpu_evict_flags(struct ttm_buffer_object * bo,struct ttm_placement * placement)90d38ceaf9SAlex Deucher static void amdgpu_evict_flags(struct ttm_buffer_object *bo,
91d38ceaf9SAlex Deucher struct ttm_placement *placement)
92d38ceaf9SAlex Deucher {
93a7d64de6SChristian König struct amdgpu_device *adev = amdgpu_ttm_adev(bo->bdev);
94765e7fbfSChristian König struct amdgpu_bo *abo;
951aaa5602SArvind Yadav static const struct ttm_place placements = {
96d38ceaf9SAlex Deucher .fpfn = 0,
97d38ceaf9SAlex Deucher .lpfn = 0,
9848e07c23SChristian König .mem_type = TTM_PL_SYSTEM,
99ce65b874SChristian König .flags = 0
100d38ceaf9SAlex Deucher };
101d38ceaf9SAlex Deucher
10250da5174STom St Denis /* Don't handle scatter gather BOs */
10382dee241SChristian König if (bo->type == ttm_bo_type_sg) {
10482dee241SChristian König placement->num_placement = 0;
10582dee241SChristian König placement->num_busy_placement = 0;
10682dee241SChristian König return;
10782dee241SChristian König }
10882dee241SChristian König
10950da5174STom St Denis /* Object isn't an AMDGPU object so ignore */
110c704ab18SChristian König if (!amdgpu_bo_is_amdgpu_bo(bo)) {
111d38ceaf9SAlex Deucher placement->placement = &placements;
112d38ceaf9SAlex Deucher placement->busy_placement = &placements;
113d38ceaf9SAlex Deucher placement->num_placement = 1;
114d38ceaf9SAlex Deucher placement->num_busy_placement = 1;
115d38ceaf9SAlex Deucher return;
116d38ceaf9SAlex Deucher }
11750da5174STom St Denis
118b82485fdSAndres Rodriguez abo = ttm_to_amdgpu_bo(bo);
119fab2cc83SChristian König if (abo->flags & AMDGPU_GEM_CREATE_DISCARDABLE) {
1205f319c5cSAlex Sierra placement->num_placement = 0;
1215f319c5cSAlex Sierra placement->num_busy_placement = 0;
1225f319c5cSAlex Sierra return;
1235f319c5cSAlex Sierra }
124d3116756SChristian König
125d3116756SChristian König switch (bo->resource->mem_type) {
1263b2de699SChristian König case AMDGPU_PL_GDS:
1273b2de699SChristian König case AMDGPU_PL_GWS:
1283b2de699SChristian König case AMDGPU_PL_OA:
129dc3499c7SAlex Deucher case AMDGPU_PL_DOORBELL:
1303b2de699SChristian König placement->num_placement = 0;
1313b2de699SChristian König placement->num_busy_placement = 0;
1323b2de699SChristian König return;
1333b2de699SChristian König
134d38ceaf9SAlex Deucher case TTM_PL_VRAM:
13581988f9cSChristian König if (!adev->mman.buffer_funcs_enabled) {
13650da5174STom St Denis /* Move to system memory */
137c704ab18SChristian König amdgpu_bo_placement_from_domain(abo, AMDGPU_GEM_DOMAIN_CPU);
138c8c5e569SAndrey Grodzovsky } else if (!amdgpu_gmc_vram_full_visible(&adev->gmc) &&
1395422a28fSChristian König !(abo->flags & AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED) &&
1404c5eaf0cSChristian König amdgpu_res_cpu_visible(adev, bo->resource)) {
141cb2dd1a6SMichel Dänzer
142cb2dd1a6SMichel Dänzer /* Try evicting to the CPU inaccessible part of VRAM
143cb2dd1a6SMichel Dänzer * first, but only set GTT as busy placement, so this
144cb2dd1a6SMichel Dänzer * BO will be evicted to GTT rather than causing other
145cb2dd1a6SMichel Dänzer * BOs to be evicted from VRAM
146cb2dd1a6SMichel Dänzer */
147c704ab18SChristian König amdgpu_bo_placement_from_domain(abo, AMDGPU_GEM_DOMAIN_VRAM |
1489a22149eSChristian König AMDGPU_GEM_DOMAIN_GTT |
1499a22149eSChristian König AMDGPU_GEM_DOMAIN_CPU);
1505422a28fSChristian König abo->placements[0].fpfn = adev->gmc.visible_vram_size >> PAGE_SHIFT;
151cb2dd1a6SMichel Dänzer abo->placements[0].lpfn = 0;
152cb2dd1a6SMichel Dänzer abo->placement.busy_placement = &abo->placements[1];
153cb2dd1a6SMichel Dänzer abo->placement.num_busy_placement = 1;
15408291c5cSChristian König } else {
15550da5174STom St Denis /* Move to GTT memory */
1569a22149eSChristian König amdgpu_bo_placement_from_domain(abo, AMDGPU_GEM_DOMAIN_GTT |
1579a22149eSChristian König AMDGPU_GEM_DOMAIN_CPU);
15808291c5cSChristian König }
159d38ceaf9SAlex Deucher break;
160d38ceaf9SAlex Deucher case TTM_PL_TT:
161b453e42aSFelix Kuehling case AMDGPU_PL_PREEMPT:
162d38ceaf9SAlex Deucher default:
163c704ab18SChristian König amdgpu_bo_placement_from_domain(abo, AMDGPU_GEM_DOMAIN_CPU);
1643b2de699SChristian König break;
165d38ceaf9SAlex Deucher }
166765e7fbfSChristian König *placement = abo->placement;
167d38ceaf9SAlex Deucher }
168d38ceaf9SAlex Deucher
16950da5174STom St Denis /**
170f0ee63cbSChristian König * amdgpu_ttm_map_buffer - Map memory into the GART windows
171f0ee63cbSChristian König * @bo: buffer object to map
172f0ee63cbSChristian König * @mem: memory object to map
173be956c57SChristian König * @mm_cur: range to map
174f0ee63cbSChristian König * @window: which GART window to use
175f0ee63cbSChristian König * @ring: DMA ring to use for the copy
176f0ee63cbSChristian König * @tmz: if we should setup a TMZ enabled mapping
1776927913dSChristian König * @size: in number of bytes to map, out number of bytes mapped
178f0ee63cbSChristian König * @addr: resulting address inside the MC address space
179f0ee63cbSChristian König *
180f0ee63cbSChristian König * Setup one of the GART windows to access a specific piece of memory or return
181f0ee63cbSChristian König * the physical address for local memory.
182f0ee63cbSChristian König */
amdgpu_ttm_map_buffer(struct ttm_buffer_object * bo,struct ttm_resource * mem,struct amdgpu_res_cursor * mm_cur,unsigned int window,struct amdgpu_ring * ring,bool tmz,uint64_t * size,uint64_t * addr)183f0ee63cbSChristian König static int amdgpu_ttm_map_buffer(struct ttm_buffer_object *bo,
1842966141aSDave Airlie struct ttm_resource *mem,
185be956c57SChristian König struct amdgpu_res_cursor *mm_cur,
18601c3f464SSrinivasan Shanmugam unsigned int window, struct amdgpu_ring *ring,
1876927913dSChristian König bool tmz, uint64_t *size, uint64_t *addr)
188f0ee63cbSChristian König {
189f0ee63cbSChristian König struct amdgpu_device *adev = ring->adev;
19001c3f464SSrinivasan Shanmugam unsigned int offset, num_pages, num_dw, num_bytes;
191f0ee63cbSChristian König uint64_t src_addr, dst_addr;
1926927913dSChristian König struct amdgpu_job *job;
19395045783SChristian König void *cpu_addr;
194f0ee63cbSChristian König uint64_t flags;
19595045783SChristian König unsigned int i;
196f0ee63cbSChristian König int r;
197f0ee63cbSChristian König
198f0ee63cbSChristian König BUG_ON(adev->mman.buffer_funcs->copy_max_bytes <
199f0ee63cbSChristian König AMDGPU_GTT_MAX_TRANSFER_SIZE * 8);
200e0a4459dSChristian König
201e0a4459dSChristian König if (WARN_ON(mem->mem_type == AMDGPU_PL_PREEMPT))
202e0a4459dSChristian König return -EINVAL;
203f0ee63cbSChristian König
204f0ee63cbSChristian König /* Map only what can't be accessed directly */
20595045783SChristian König if (!tmz && mem->start != AMDGPU_BO_INVALID_OFFSET) {
206be956c57SChristian König *addr = amdgpu_ttm_domain_start(adev, mem->mem_type) +
207be956c57SChristian König mm_cur->start;
208f0ee63cbSChristian König return 0;
209f0ee63cbSChristian König }
210f0ee63cbSChristian König
2116927913dSChristian König
2126927913dSChristian König /*
2136927913dSChristian König * If start begins at an offset inside the page, then adjust the size
2146927913dSChristian König * and addr accordingly
2156927913dSChristian König */
2166927913dSChristian König offset = mm_cur->start & ~PAGE_MASK;
2176927913dSChristian König
2186927913dSChristian König num_pages = PFN_UP(*size + offset);
2196927913dSChristian König num_pages = min_t(uint32_t, num_pages, AMDGPU_GTT_MAX_TRANSFER_SIZE);
2206927913dSChristian König
2216927913dSChristian König *size = min(*size, (uint64_t)num_pages * PAGE_SIZE - offset);
2226927913dSChristian König
223f0ee63cbSChristian König *addr = adev->gmc.gart_start;
224f0ee63cbSChristian König *addr += (u64)window * AMDGPU_GTT_MAX_TRANSFER_SIZE *
225f0ee63cbSChristian König AMDGPU_GPU_PAGE_SIZE;
2266927913dSChristian König *addr += offset;
227f0ee63cbSChristian König
228f0ee63cbSChristian König num_dw = ALIGN(adev->mman.buffer_funcs->copy_num_dw, 8);
229d5375156SYi Li num_bytes = num_pages * 8 * AMDGPU_GPU_PAGES_IN_CPU_PAGE;
230f0ee63cbSChristian König
23141ce6d6dSMukul Joshi r = amdgpu_job_alloc_with_ib(adev, &adev->mman.high_pr,
232f7d66fb2SChristian König AMDGPU_FENCE_OWNER_UNDEFINED,
233f7d66fb2SChristian König num_dw * 4 + num_bytes,
2349ecefb19SChristian König AMDGPU_IB_POOL_DELAYED, &job);
235f0ee63cbSChristian König if (r)
236f0ee63cbSChristian König return r;
237f0ee63cbSChristian König
238f0ee63cbSChristian König src_addr = num_dw * 4;
239f0ee63cbSChristian König src_addr += job->ibs[0].gpu_addr;
240f0ee63cbSChristian König
241f0ee63cbSChristian König dst_addr = amdgpu_bo_gpu_offset(adev->gart.bo);
242f0ee63cbSChristian König dst_addr += window * AMDGPU_GTT_MAX_TRANSFER_SIZE * 8;
243f0ee63cbSChristian König amdgpu_emit_copy_buffer(adev, &job->ibs[0], src_addr,
244f0ee63cbSChristian König dst_addr, num_bytes, false);
245f0ee63cbSChristian König
246f0ee63cbSChristian König amdgpu_ring_pad_ib(ring, &job->ibs[0]);
247f0ee63cbSChristian König WARN_ON(job->ibs[0].length_dw > num_dw);
248f0ee63cbSChristian König
249f0ee63cbSChristian König flags = amdgpu_ttm_tt_pte_flags(adev, bo->ttm, mem);
250f0ee63cbSChristian König if (tmz)
251f0ee63cbSChristian König flags |= AMDGPU_PTE_TMZ;
252f0ee63cbSChristian König
25395045783SChristian König cpu_addr = &job->ibs[0].ptr[num_dw];
25495045783SChristian König
25595045783SChristian König if (mem->mem_type == TTM_PL_TT) {
256be956c57SChristian König dma_addr_t *dma_addr;
25795045783SChristian König
258be956c57SChristian König dma_addr = &bo->ttm->dma_address[mm_cur->start >> PAGE_SHIFT];
2591b08dfb8SChristian König amdgpu_gart_map(adev, 0, num_pages, dma_addr, flags, cpu_addr);
26095045783SChristian König } else {
26195045783SChristian König dma_addr_t dma_address;
26295045783SChristian König
263be956c57SChristian König dma_address = mm_cur->start;
26495045783SChristian König dma_address += adev->vm_manager.vram_base_offset;
26595045783SChristian König
26695045783SChristian König for (i = 0; i < num_pages; ++i) {
2671b08dfb8SChristian König amdgpu_gart_map(adev, i << PAGE_SHIFT, 1, &dma_address,
2681b08dfb8SChristian König flags, cpu_addr);
26995045783SChristian König dma_address += PAGE_SIZE;
27095045783SChristian König }
27195045783SChristian König }
272f0ee63cbSChristian König
273f7d66fb2SChristian König dma_fence_put(amdgpu_job_submit(job));
274f7d66fb2SChristian König return 0;
275f0ee63cbSChristian König }
276f0ee63cbSChristian König
277f0ee63cbSChristian König /**
27827aa4a69SLee Jones * amdgpu_ttm_copy_mem_to_mem - Helper function for copy
279effb97ccSChristian König * @adev: amdgpu device
280effb97ccSChristian König * @src: buffer/address where to read from
281effb97ccSChristian König * @dst: buffer/address where to write to
282effb97ccSChristian König * @size: number of bytes to copy
283effb97ccSChristian König * @tmz: if a secure copy should be used
284effb97ccSChristian König * @resv: resv object to sync to
285effb97ccSChristian König * @f: Returns the last fence if multiple jobs are submitted.
2861eca5a53SHarish Kasiviswanathan *
2871eca5a53SHarish Kasiviswanathan * The function copies @size bytes from {src->mem + src->offset} to
2881eca5a53SHarish Kasiviswanathan * {dst->mem + dst->offset}. src->bo and dst->bo could be same BO for a
2891eca5a53SHarish Kasiviswanathan * move and different for a BO to BO copy.
2901eca5a53SHarish Kasiviswanathan *
2911eca5a53SHarish Kasiviswanathan */
amdgpu_ttm_copy_mem_to_mem(struct amdgpu_device * adev,const struct amdgpu_copy_mem * src,const struct amdgpu_copy_mem * dst,uint64_t size,bool tmz,struct dma_resv * resv,struct dma_fence ** f)2921eca5a53SHarish Kasiviswanathan int amdgpu_ttm_copy_mem_to_mem(struct amdgpu_device *adev,
293f0ee63cbSChristian König const struct amdgpu_copy_mem *src,
294f0ee63cbSChristian König const struct amdgpu_copy_mem *dst,
295effb97ccSChristian König uint64_t size, bool tmz,
29652791eeeSChristian König struct dma_resv *resv,
2971eca5a53SHarish Kasiviswanathan struct dma_fence **f)
298d38ceaf9SAlex Deucher {
2998892f153SChristian König struct amdgpu_ring *ring = adev->mman.buffer_funcs_ring;
300be956c57SChristian König struct amdgpu_res_cursor src_mm, dst_mm;
301220196b3SDave Airlie struct dma_fence *fence = NULL;
3021eca5a53SHarish Kasiviswanathan int r = 0;
303d38ceaf9SAlex Deucher
30481988f9cSChristian König if (!adev->mman.buffer_funcs_enabled) {
305d38ceaf9SAlex Deucher DRM_ERROR("Trying to move memory with ring turned off.\n");
306d38ceaf9SAlex Deucher return -EINVAL;
307d38ceaf9SAlex Deucher }
308d38ceaf9SAlex Deucher
309be956c57SChristian König amdgpu_res_first(src->mem, src->offset, size, &src_mm);
310be956c57SChristian König amdgpu_res_first(dst->mem, dst->offset, size, &dst_mm);
3118892f153SChristian König
312abca90f1SChristian König mutex_lock(&adev->mman.gtt_window_lock);
313be956c57SChristian König while (src_mm.remaining) {
3146927913dSChristian König uint64_t from, to, cur_size;
315220196b3SDave Airlie struct dma_fence *next;
3168892f153SChristian König
3176927913dSChristian König /* Never copy more than 256MiB at once to avoid a timeout */
3186927913dSChristian König cur_size = min3(src_mm.size, dst_mm.size, 256ULL << 20);
3191eca5a53SHarish Kasiviswanathan
320f0ee63cbSChristian König /* Map src to window 0 and dst to window 1. */
321be956c57SChristian König r = amdgpu_ttm_map_buffer(src->bo, src->mem, &src_mm,
3226927913dSChristian König 0, ring, tmz, &cur_size, &from);
323abca90f1SChristian König if (r)
324abca90f1SChristian König goto error;
325abca90f1SChristian König
326be956c57SChristian König r = amdgpu_ttm_map_buffer(dst->bo, dst->mem, &dst_mm,
3276927913dSChristian König 1, ring, tmz, &cur_size, &to);
328abca90f1SChristian König if (r)
329abca90f1SChristian König goto error;
330abca90f1SChristian König
3311eca5a53SHarish Kasiviswanathan r = amdgpu_copy_buffer(ring, from, to, cur_size,
332effb97ccSChristian König resv, &next, false, true, tmz);
3338892f153SChristian König if (r)
3348892f153SChristian König goto error;
3358892f153SChristian König
336220196b3SDave Airlie dma_fence_put(fence);
3378892f153SChristian König fence = next;
3388892f153SChristian König
339be956c57SChristian König amdgpu_res_next(&src_mm, cur_size);
340be956c57SChristian König amdgpu_res_next(&dst_mm, cur_size);
3411eca5a53SHarish Kasiviswanathan }
3421eca5a53SHarish Kasiviswanathan error:
3431eca5a53SHarish Kasiviswanathan mutex_unlock(&adev->mman.gtt_window_lock);
3441eca5a53SHarish Kasiviswanathan if (f)
3451eca5a53SHarish Kasiviswanathan *f = dma_fence_get(fence);
3461eca5a53SHarish Kasiviswanathan dma_fence_put(fence);
3471eca5a53SHarish Kasiviswanathan return r;
3488892f153SChristian König }
3498892f153SChristian König
35075501872SLee Jones /*
35150da5174STom St Denis * amdgpu_move_blit - Copy an entire buffer to another buffer
35250da5174STom St Denis *
3532e603d04SHuang Rui * This is a helper called by amdgpu_bo_move() and amdgpu_move_vram_ram() to
3542e603d04SHuang Rui * help move buffers to and from VRAM.
35550da5174STom St Denis */
amdgpu_move_blit(struct ttm_buffer_object * bo,bool evict,struct ttm_resource * new_mem,struct ttm_resource * old_mem)3561eca5a53SHarish Kasiviswanathan static int amdgpu_move_blit(struct ttm_buffer_object *bo,
35705010c1eSDave Airlie bool evict,
3582966141aSDave Airlie struct ttm_resource *new_mem,
3592966141aSDave Airlie struct ttm_resource *old_mem)
3601eca5a53SHarish Kasiviswanathan {
3611eca5a53SHarish Kasiviswanathan struct amdgpu_device *adev = amdgpu_ttm_adev(bo->bdev);
362effb97ccSChristian König struct amdgpu_bo *abo = ttm_to_amdgpu_bo(bo);
3631eca5a53SHarish Kasiviswanathan struct amdgpu_copy_mem src, dst;
3641eca5a53SHarish Kasiviswanathan struct dma_fence *fence = NULL;
3651eca5a53SHarish Kasiviswanathan int r;
3661eca5a53SHarish Kasiviswanathan
3671eca5a53SHarish Kasiviswanathan src.bo = bo;
3681eca5a53SHarish Kasiviswanathan dst.bo = bo;
3691eca5a53SHarish Kasiviswanathan src.mem = old_mem;
3701eca5a53SHarish Kasiviswanathan dst.mem = new_mem;
3711eca5a53SHarish Kasiviswanathan src.offset = 0;
3721eca5a53SHarish Kasiviswanathan dst.offset = 0;
3731eca5a53SHarish Kasiviswanathan
3741eca5a53SHarish Kasiviswanathan r = amdgpu_ttm_copy_mem_to_mem(adev, &src, &dst,
375e3c92eb4SSomalapuram Amaranath new_mem->size,
376effb97ccSChristian König amdgpu_bo_encrypted(abo),
3775a5011a7SGerd Hoffmann bo->base.resv, &fence);
3781eca5a53SHarish Kasiviswanathan if (r)
3791eca5a53SHarish Kasiviswanathan goto error;
380ce64bc25SChristian König
381ab2f7a5cSFelix Kuehling /* clear the space being freed */
382ab2f7a5cSFelix Kuehling if (old_mem->mem_type == TTM_PL_VRAM &&
383effb97ccSChristian König (abo->flags & AMDGPU_GEM_CREATE_VRAM_WIPE_ON_RELEASE)) {
384ab2f7a5cSFelix Kuehling struct dma_fence *wipe_fence = NULL;
385ab2f7a5cSFelix Kuehling
386c3aaca43SMukul Joshi r = amdgpu_fill_buffer(abo, AMDGPU_POISON, NULL, &wipe_fence,
387c3aaca43SMukul Joshi false);
388ab2f7a5cSFelix Kuehling if (r) {
389ab2f7a5cSFelix Kuehling goto error;
390ab2f7a5cSFelix Kuehling } else if (wipe_fence) {
391ab2f7a5cSFelix Kuehling dma_fence_put(fence);
392ab2f7a5cSFelix Kuehling fence = wipe_fence;
393ab2f7a5cSFelix Kuehling }
394ab2f7a5cSFelix Kuehling }
395ab2f7a5cSFelix Kuehling
3964947b2f2SChristian König /* Always block for VM page tables before committing the new location */
3974947b2f2SChristian König if (bo->type == ttm_bo_type_kernel)
398e46f468fSDave Airlie r = ttm_bo_move_accel_cleanup(bo, fence, true, false, new_mem);
3994947b2f2SChristian König else
400e46f468fSDave Airlie r = ttm_bo_move_accel_cleanup(bo, fence, evict, true, new_mem);
401f54d1867SChris Wilson dma_fence_put(fence);
402d38ceaf9SAlex Deucher return r;
4038892f153SChristian König
4048892f153SChristian König error:
4058892f153SChristian König if (fence)
406220196b3SDave Airlie dma_fence_wait(fence, false);
407220196b3SDave Airlie dma_fence_put(fence);
4088892f153SChristian König return r;
409d38ceaf9SAlex Deucher }
410d38ceaf9SAlex Deucher
4114c5eaf0cSChristian König /**
4124c5eaf0cSChristian König * amdgpu_res_cpu_visible - Check that resource can be accessed by CPU
4134c5eaf0cSChristian König * @adev: amdgpu device
4144c5eaf0cSChristian König * @res: the resource to check
4154c5eaf0cSChristian König *
4164c5eaf0cSChristian König * Returns: true if the full resource is CPU visible, false otherwise.
4174c5eaf0cSChristian König */
amdgpu_res_cpu_visible(struct amdgpu_device * adev,struct ttm_resource * res)4184c5eaf0cSChristian König bool amdgpu_res_cpu_visible(struct amdgpu_device *adev,
4194c5eaf0cSChristian König struct ttm_resource *res)
4204c5eaf0cSChristian König {
4214c5eaf0cSChristian König struct amdgpu_res_cursor cursor;
4224c5eaf0cSChristian König
4234c5eaf0cSChristian König if (!res)
4244c5eaf0cSChristian König return false;
4254c5eaf0cSChristian König
4264c5eaf0cSChristian König if (res->mem_type == TTM_PL_SYSTEM || res->mem_type == TTM_PL_TT ||
4274fd8cd41SShashank Sharma res->mem_type == AMDGPU_PL_PREEMPT || res->mem_type == AMDGPU_PL_DOORBELL)
4284c5eaf0cSChristian König return true;
4294c5eaf0cSChristian König
4304c5eaf0cSChristian König if (res->mem_type != TTM_PL_VRAM)
4314c5eaf0cSChristian König return false;
4324c5eaf0cSChristian König
4334c5eaf0cSChristian König amdgpu_res_first(res, 0, res->size, &cursor);
4344c5eaf0cSChristian König while (cursor.remaining) {
43552c1af38SMichel Dänzer if ((cursor.start + cursor.size) > adev->gmc.visible_vram_size)
4364c5eaf0cSChristian König return false;
4374c5eaf0cSChristian König amdgpu_res_next(&cursor, cursor.size);
4384c5eaf0cSChristian König }
4394c5eaf0cSChristian König
4404c5eaf0cSChristian König return true;
4414c5eaf0cSChristian König }
4424c5eaf0cSChristian König
44375501872SLee Jones /*
4444c5eaf0cSChristian König * amdgpu_res_copyable - Check that memory can be accessed by ttm_bo_move_memcpy
44567adb569SFelix Kuehling *
44667adb569SFelix Kuehling * Called by amdgpu_bo_move()
44767adb569SFelix Kuehling */
amdgpu_res_copyable(struct amdgpu_device * adev,struct ttm_resource * mem)4484c5eaf0cSChristian König static bool amdgpu_res_copyable(struct amdgpu_device *adev,
4492966141aSDave Airlie struct ttm_resource *mem)
45067adb569SFelix Kuehling {
4514c5eaf0cSChristian König if (!amdgpu_res_cpu_visible(adev, mem))
45267adb569SFelix Kuehling return false;
45367adb569SFelix Kuehling
4542966141aSDave Airlie /* ttm_resource_ioremap only supports contiguous memory */
4554c5eaf0cSChristian König if (mem->mem_type == TTM_PL_VRAM &&
4564c5eaf0cSChristian König !(mem->placement & TTM_PL_FLAG_CONTIGUOUS))
45767adb569SFelix Kuehling return false;
45867adb569SFelix Kuehling
4594c5eaf0cSChristian König return true;
46067adb569SFelix Kuehling }
46167adb569SFelix Kuehling
46275501872SLee Jones /*
46350da5174STom St Denis * amdgpu_bo_move - Move a buffer object to a new memory location
46450da5174STom St Denis *
46550da5174STom St Denis * Called by ttm_bo_handle_move_mem()
46650da5174STom St Denis */
amdgpu_bo_move(struct ttm_buffer_object * bo,bool evict,struct ttm_operation_ctx * ctx,struct ttm_resource * new_mem,struct ttm_place * hop)4672823f4f0SChristian König static int amdgpu_bo_move(struct ttm_buffer_object *bo, bool evict,
4682823f4f0SChristian König struct ttm_operation_ctx *ctx,
469ebdf5651SDave Airlie struct ttm_resource *new_mem,
470ebdf5651SDave Airlie struct ttm_place *hop)
471d38ceaf9SAlex Deucher {
472d38ceaf9SAlex Deucher struct amdgpu_device *adev;
473104ece97SMichel Dänzer struct amdgpu_bo *abo;
474d3116756SChristian König struct ttm_resource *old_mem = bo->resource;
475d38ceaf9SAlex Deucher int r;
476d38ceaf9SAlex Deucher
477b453e42aSFelix Kuehling if (new_mem->mem_type == TTM_PL_TT ||
478b453e42aSFelix Kuehling new_mem->mem_type == AMDGPU_PL_PREEMPT) {
479bfe5e585SDave Airlie r = amdgpu_ttm_backend_bind(bo->bdev, bo->ttm, new_mem);
480bfe5e585SDave Airlie if (r)
481bfe5e585SDave Airlie return r;
482bfe5e585SDave Airlie }
483bfe5e585SDave Airlie
484b82485fdSAndres Rodriguez abo = ttm_to_amdgpu_bo(bo);
485a7d64de6SChristian König adev = amdgpu_ttm_adev(bo->bdev);
486dbd5ed60SChristian König
48763af82cfSChristian König if (!old_mem || (old_mem->mem_type == TTM_PL_SYSTEM &&
48863af82cfSChristian König bo->ttm == NULL)) {
4890c7ed3edSChristian König amdgpu_bo_move_notify(bo, evict, new_mem);
490ecfe6953SDave Airlie ttm_bo_move_null(bo, new_mem);
4910c7ed3edSChristian König return 0;
492d38ceaf9SAlex Deucher }
4933a08446bSDave Airlie if (old_mem->mem_type == TTM_PL_SYSTEM &&
494b453e42aSFelix Kuehling (new_mem->mem_type == TTM_PL_TT ||
495b453e42aSFelix Kuehling new_mem->mem_type == AMDGPU_PL_PREEMPT)) {
4960c7ed3edSChristian König amdgpu_bo_move_notify(bo, evict, new_mem);
497ecfe6953SDave Airlie ttm_bo_move_null(bo, new_mem);
4980c7ed3edSChristian König return 0;
499d38ceaf9SAlex Deucher }
500b453e42aSFelix Kuehling if ((old_mem->mem_type == TTM_PL_TT ||
501b453e42aSFelix Kuehling old_mem->mem_type == AMDGPU_PL_PREEMPT) &&
502c37d951cSDave Airlie new_mem->mem_type == TTM_PL_SYSTEM) {
50329a1d482SDave Airlie r = ttm_bo_wait_ctx(bo, ctx);
504c37d951cSDave Airlie if (r)
505aefec409SChristian König return r;
50629a1d482SDave Airlie
50729a1d482SDave Airlie amdgpu_ttm_backend_unbind(bo->bdev, bo->ttm);
5080c7ed3edSChristian König amdgpu_bo_move_notify(bo, evict, new_mem);
509bfa3357eSChristian König ttm_resource_free(bo, &bo->resource);
510c37d951cSDave Airlie ttm_bo_assign_mem(bo, new_mem);
5110c7ed3edSChristian König return 0;
512c37d951cSDave Airlie }
5133a08446bSDave Airlie
5143b2de699SChristian König if (old_mem->mem_type == AMDGPU_PL_GDS ||
5153b2de699SChristian König old_mem->mem_type == AMDGPU_PL_GWS ||
5163b2de699SChristian König old_mem->mem_type == AMDGPU_PL_OA ||
517dc3499c7SAlex Deucher old_mem->mem_type == AMDGPU_PL_DOORBELL ||
5183b2de699SChristian König new_mem->mem_type == AMDGPU_PL_GDS ||
5193b2de699SChristian König new_mem->mem_type == AMDGPU_PL_GWS ||
520dc3499c7SAlex Deucher new_mem->mem_type == AMDGPU_PL_OA ||
521dc3499c7SAlex Deucher new_mem->mem_type == AMDGPU_PL_DOORBELL) {
5223b2de699SChristian König /* Nothing to save here */
5230c7ed3edSChristian König amdgpu_bo_move_notify(bo, evict, new_mem);
524ecfe6953SDave Airlie ttm_bo_move_null(bo, new_mem);
5250c7ed3edSChristian König return 0;
5263b2de699SChristian König }
52781988f9cSChristian König
528c92db8d6SChristian König if (bo->type == ttm_bo_type_device &&
529c92db8d6SChristian König new_mem->mem_type == TTM_PL_VRAM &&
530c92db8d6SChristian König old_mem->mem_type != TTM_PL_VRAM) {
531c92db8d6SChristian König /* amdgpu_bo_fault_reserve_notify will re-set this if the CPU
532c92db8d6SChristian König * accesses the BO after it's moved.
533c92db8d6SChristian König */
534c92db8d6SChristian König abo->flags &= ~AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED;
535c92db8d6SChristian König }
536c92db8d6SChristian König
5370c7ed3edSChristian König if (adev->mman.buffer_funcs_enabled &&
5380c7ed3edSChristian König ((old_mem->mem_type == TTM_PL_SYSTEM &&
539aefec409SChristian König new_mem->mem_type == TTM_PL_VRAM) ||
540aefec409SChristian König (old_mem->mem_type == TTM_PL_VRAM &&
541aefec409SChristian König new_mem->mem_type == TTM_PL_SYSTEM))) {
542aefec409SChristian König hop->fpfn = 0;
543aefec409SChristian König hop->lpfn = 0;
544aefec409SChristian König hop->mem_type = TTM_PL_TT;
5453e640f1bSLang Yu hop->flags = TTM_PL_FLAG_TEMPORARY;
546aefec409SChristian König return -EMULTIHOP;
54767adb569SFelix Kuehling }
548d38ceaf9SAlex Deucher
5490c7ed3edSChristian König amdgpu_bo_move_notify(bo, evict, new_mem);
5500c7ed3edSChristian König if (adev->mman.buffer_funcs_enabled)
551f5a89a5cSDave Airlie r = amdgpu_move_blit(bo, evict, new_mem, old_mem);
5520c7ed3edSChristian König else
553aefec409SChristian König r = -ENODEV;
554aefec409SChristian König
555d38ceaf9SAlex Deucher if (r) {
55667adb569SFelix Kuehling /* Check that all memory is CPU accessible */
5574c5eaf0cSChristian König if (!amdgpu_res_copyable(adev, old_mem) ||
5584c5eaf0cSChristian König !amdgpu_res_copyable(adev, new_mem)) {
55967adb569SFelix Kuehling pr_err("Move buffer fallback to memcpy unavailable\n");
560aefec409SChristian König return r;
561d38ceaf9SAlex Deucher }
56267adb569SFelix Kuehling
56367adb569SFelix Kuehling r = ttm_bo_move_memcpy(bo, ctx, new_mem);
56467adb569SFelix Kuehling if (r)
565aefec409SChristian König return r;
566d38ceaf9SAlex Deucher }
567d38ceaf9SAlex Deucher
5680c7ed3edSChristian König /* update statistics after the move */
5690c7ed3edSChristian König if (evict)
5700c7ed3edSChristian König atomic64_inc(&adev->num_evictions);
571e11bfb99SChristian König atomic64_add(bo->base.size, &adev->num_bytes_moved);
572d38ceaf9SAlex Deucher return 0;
573d38ceaf9SAlex Deucher }
574d38ceaf9SAlex Deucher
57575501872SLee Jones /*
57650da5174STom St Denis * amdgpu_ttm_io_mem_reserve - Reserve a block of memory during a fault
57750da5174STom St Denis *
57850da5174STom St Denis * Called by ttm_mem_io_reserve() ultimately via ttm_bo_vm_fault()
57950da5174STom St Denis */
amdgpu_ttm_io_mem_reserve(struct ttm_device * bdev,struct ttm_resource * mem)580dfffdf5eSChristian König static int amdgpu_ttm_io_mem_reserve(struct ttm_device *bdev,
581dfffdf5eSChristian König struct ttm_resource *mem)
582d38ceaf9SAlex Deucher {
583a7d64de6SChristian König struct amdgpu_device *adev = amdgpu_ttm_adev(bdev);
584d38ceaf9SAlex Deucher
585d38ceaf9SAlex Deucher switch (mem->mem_type) {
586d38ceaf9SAlex Deucher case TTM_PL_SYSTEM:
587d38ceaf9SAlex Deucher /* system memory */
588d38ceaf9SAlex Deucher return 0;
589d38ceaf9SAlex Deucher case TTM_PL_TT:
590b453e42aSFelix Kuehling case AMDGPU_PL_PREEMPT:
591d38ceaf9SAlex Deucher break;
592d38ceaf9SAlex Deucher case TTM_PL_VRAM:
593d38ceaf9SAlex Deucher mem->bus.offset = mem->start << PAGE_SHIFT;
594dfffdf5eSChristian König
595f8f4b9a6SAmber Lin if (adev->mman.aper_base_kaddr &&
596dfffdf5eSChristian König mem->placement & TTM_PL_FLAG_CONTIGUOUS)
597f8f4b9a6SAmber Lin mem->bus.addr = (u8 *)adev->mman.aper_base_kaddr +
598f8f4b9a6SAmber Lin mem->bus.offset;
599f8f4b9a6SAmber Lin
60054d04ea8SChristian König mem->bus.offset += adev->gmc.aper_base;
601d38ceaf9SAlex Deucher mem->bus.is_iomem = true;
602d38ceaf9SAlex Deucher break;
603dc3499c7SAlex Deucher case AMDGPU_PL_DOORBELL:
604dc3499c7SAlex Deucher mem->bus.offset = mem->start << PAGE_SHIFT;
605dc3499c7SAlex Deucher mem->bus.offset += adev->doorbell.base;
606dc3499c7SAlex Deucher mem->bus.is_iomem = true;
607dc3499c7SAlex Deucher mem->bus.caching = ttm_uncached;
608dc3499c7SAlex Deucher break;
609d38ceaf9SAlex Deucher default:
610d38ceaf9SAlex Deucher return -EINVAL;
611d38ceaf9SAlex Deucher }
612d38ceaf9SAlex Deucher return 0;
613d38ceaf9SAlex Deucher }
614d38ceaf9SAlex Deucher
amdgpu_ttm_io_mem_pfn(struct ttm_buffer_object * bo,unsigned long page_offset)6159bbdcc0fSChristian König static unsigned long amdgpu_ttm_io_mem_pfn(struct ttm_buffer_object *bo,
6169bbdcc0fSChristian König unsigned long page_offset)
6179bbdcc0fSChristian König {
61854d04ea8SChristian König struct amdgpu_device *adev = amdgpu_ttm_adev(bo->bdev);
61910ebcd95SChristian König struct amdgpu_res_cursor cursor;
6209bbdcc0fSChristian König
621d3116756SChristian König amdgpu_res_first(bo->resource, (u64)page_offset << PAGE_SHIFT, 0,
622d3116756SChristian König &cursor);
623dc3499c7SAlex Deucher
624dc3499c7SAlex Deucher if (bo->resource->mem_type == AMDGPU_PL_DOORBELL)
625dc3499c7SAlex Deucher return ((uint64_t)(adev->doorbell.base + cursor.start)) >> PAGE_SHIFT;
626dc3499c7SAlex Deucher
62710ebcd95SChristian König return (adev->gmc.aper_base + cursor.start) >> PAGE_SHIFT;
6289bbdcc0fSChristian König }
6299bbdcc0fSChristian König
630b1a8ef95SNirmoy Das /**
631b1a8ef95SNirmoy Das * amdgpu_ttm_domain_start - Returns GPU start address
632b1a8ef95SNirmoy Das * @adev: amdgpu device object
633b1a8ef95SNirmoy Das * @type: type of the memory
634b1a8ef95SNirmoy Das *
635b1a8ef95SNirmoy Das * Returns:
636b1a8ef95SNirmoy Das * GPU start address of a memory domain
637b1a8ef95SNirmoy Das */
638b1a8ef95SNirmoy Das
amdgpu_ttm_domain_start(struct amdgpu_device * adev,uint32_t type)639b1a8ef95SNirmoy Das uint64_t amdgpu_ttm_domain_start(struct amdgpu_device *adev, uint32_t type)
640b1a8ef95SNirmoy Das {
641b1a8ef95SNirmoy Das switch (type) {
642b1a8ef95SNirmoy Das case TTM_PL_TT:
643b1a8ef95SNirmoy Das return adev->gmc.gart_start;
644b1a8ef95SNirmoy Das case TTM_PL_VRAM:
645b1a8ef95SNirmoy Das return adev->gmc.vram_start;
646b1a8ef95SNirmoy Das }
647b1a8ef95SNirmoy Das
648b1a8ef95SNirmoy Das return 0;
649b1a8ef95SNirmoy Das }
650b1a8ef95SNirmoy Das
651d38ceaf9SAlex Deucher /*
652d38ceaf9SAlex Deucher * TTM backend functions.
653d38ceaf9SAlex Deucher */
654d38ceaf9SAlex Deucher struct amdgpu_ttm_tt {
655e34b8feeSChristian König struct ttm_tt ttm;
656a3941471SChristian König struct drm_gem_object *gobj;
657d38ceaf9SAlex Deucher u64 offset;
658d38ceaf9SAlex Deucher uint64_t userptr;
6590919195fSFelix Kuehling struct task_struct *usertask;
660d38ceaf9SAlex Deucher uint32_t userflags;
6610b988ca1SDave Airlie bool bound;
6621e03322cSPhilip Yang int32_t pool_id;
663d38ceaf9SAlex Deucher };
664d38ceaf9SAlex Deucher
665c4c10a68SRajneesh Bhardwaj #define ttm_to_amdgpu_ttm_tt(ptr) container_of(ptr, struct amdgpu_ttm_tt, ttm)
666c4c10a68SRajneesh Bhardwaj
66781fa1af3SJason Gunthorpe #ifdef CONFIG_DRM_AMDGPU_USERPTR
66875501872SLee Jones /*
669899fbde1SPhilip Yang * amdgpu_ttm_tt_get_user_pages - get device accessible pages that back user
670899fbde1SPhilip Yang * memory and start HMM tracking CPU page table update
67150da5174STom St Denis *
672899fbde1SPhilip Yang * Calling function must call amdgpu_ttm_tt_userptr_range_done() once and only
673899fbde1SPhilip Yang * once afterwards to stop HMM tracking
67450da5174STom St Denis */
amdgpu_ttm_tt_get_user_pages(struct amdgpu_bo * bo,struct page ** pages,struct hmm_range ** range)675fec8fdb5SChristian König int amdgpu_ttm_tt_get_user_pages(struct amdgpu_bo *bo, struct page **pages,
676fec8fdb5SChristian König struct hmm_range **range)
677d38ceaf9SAlex Deucher {
678e5eaa7ccSPhilip Yang struct ttm_tt *ttm = bo->tbo.ttm;
679c4c10a68SRajneesh Bhardwaj struct amdgpu_ttm_tt *gtt = ttm_to_amdgpu_ttm_tt(ttm);
6806826cb3bSPhilip Yang unsigned long start = gtt->userptr;
68166c45500SPhilip Yang struct vm_area_struct *vma;
68281fa1af3SJason Gunthorpe struct mm_struct *mm;
68304d8d73dSPhilip Yang bool readonly;
6841986a3b0SFelix Kuehling int r = 0;
685d38ceaf9SAlex Deucher
686fec8fdb5SChristian König /* Make sure get_user_pages_done() can cleanup gracefully */
687fec8fdb5SChristian König *range = NULL;
688fec8fdb5SChristian König
68981fa1af3SJason Gunthorpe mm = bo->notifier.mm;
69081fa1af3SJason Gunthorpe if (unlikely(!mm)) {
69181fa1af3SJason Gunthorpe DRM_DEBUG_DRIVER("BO is not registered?\n");
692a9ae8731SJason Gunthorpe return -EFAULT;
693e5eaa7ccSPhilip Yang }
694e5eaa7ccSPhilip Yang
695a9ae8731SJason Gunthorpe if (!mmget_not_zero(mm)) /* Happens during process shutdown */
6960919195fSFelix Kuehling return -ESRCH;
6970919195fSFelix Kuehling
698d8ed45c5SMichel Lespinasse mmap_read_lock(mm);
699da68547dSLiam Howlett vma = vma_lookup(mm, start);
700da68547dSLiam Howlett if (unlikely(!vma)) {
701a9ae8731SJason Gunthorpe r = -EFAULT;
702a9ae8731SJason Gunthorpe goto out_unlock;
703a9ae8731SJason Gunthorpe }
704a9ae8731SJason Gunthorpe if (unlikely((gtt->userflags & AMDGPU_GEM_USERPTR_ANONONLY) &&
705a9ae8731SJason Gunthorpe vma->vm_file)) {
706a9ae8731SJason Gunthorpe r = -EPERM;
707a9ae8731SJason Gunthorpe goto out_unlock;
708a9ae8731SJason Gunthorpe }
7096826cb3bSPhilip Yang
71004d8d73dSPhilip Yang readonly = amdgpu_ttm_tt_is_readonly(ttm);
711d4cbff46SChristian König r = amdgpu_hmm_range_get_pages(&bo->notifier, start, ttm->num_pages,
712d4cbff46SChristian König readonly, NULL, pages, range);
713a9ae8731SJason Gunthorpe out_unlock:
714d8ed45c5SMichel Lespinasse mmap_read_unlock(mm);
7153b8a23aeSPhilip Yang if (r)
7163b8a23aeSPhilip Yang pr_debug("failed %d to get user pages 0x%lx\n", r, start);
7173b8a23aeSPhilip Yang
718a9ae8731SJason Gunthorpe mmput(mm);
71966c45500SPhilip Yang
7202f568dbdSChristian König return r;
7212f568dbdSChristian König }
7222f568dbdSChristian König
723f95f51a4SFelix Kuehling /* amdgpu_ttm_tt_discard_user_pages - Discard range and pfn array allocations
724f95f51a4SFelix Kuehling */
amdgpu_ttm_tt_discard_user_pages(struct ttm_tt * ttm,struct hmm_range * range)725f95f51a4SFelix Kuehling void amdgpu_ttm_tt_discard_user_pages(struct ttm_tt *ttm,
726f95f51a4SFelix Kuehling struct hmm_range *range)
727f95f51a4SFelix Kuehling {
728f95f51a4SFelix Kuehling struct amdgpu_ttm_tt *gtt = (void *)ttm;
729f95f51a4SFelix Kuehling
730f95f51a4SFelix Kuehling if (gtt && gtt->userptr && range)
731f95f51a4SFelix Kuehling amdgpu_hmm_range_get_pages_done(range);
732f95f51a4SFelix Kuehling }
733f95f51a4SFelix Kuehling
73475501872SLee Jones /*
735f95f51a4SFelix Kuehling * amdgpu_ttm_tt_get_user_pages_done - stop HMM track the CPU page table change
736899fbde1SPhilip Yang * Check if the pages backing this ttm range have been invalidated
737899fbde1SPhilip Yang *
738899fbde1SPhilip Yang * Returns: true if pages are still valid
739899fbde1SPhilip Yang */
amdgpu_ttm_tt_get_user_pages_done(struct ttm_tt * ttm,struct hmm_range * range)740fec8fdb5SChristian König bool amdgpu_ttm_tt_get_user_pages_done(struct ttm_tt *ttm,
741fec8fdb5SChristian König struct hmm_range *range)
742899fbde1SPhilip Yang {
743c4c10a68SRajneesh Bhardwaj struct amdgpu_ttm_tt *gtt = ttm_to_amdgpu_ttm_tt(ttm);
744899fbde1SPhilip Yang
745fec8fdb5SChristian König if (!gtt || !gtt->userptr || !range)
746899fbde1SPhilip Yang return false;
747899fbde1SPhilip Yang
748230c079fSChristian König DRM_DEBUG_DRIVER("user_pages_done 0x%llx pages 0x%x\n",
74966c45500SPhilip Yang gtt->userptr, ttm->num_pages);
7506826cb3bSPhilip Yang
751fec8fdb5SChristian König WARN_ONCE(!range->hmm_pfns, "No user pages to check\n");
7526826cb3bSPhilip Yang
753fec8fdb5SChristian König return !amdgpu_hmm_range_get_pages_done(range);
754899fbde1SPhilip Yang }
755ad595b86SPhilip Yang #endif
756899fbde1SPhilip Yang
75775501872SLee Jones /*
7582e603d04SHuang Rui * amdgpu_ttm_tt_set_user_pages - Copy pages in, putting old pages as necessary.
75950da5174STom St Denis *
76050da5174STom St Denis * Called by amdgpu_cs_list_validate(). This creates the page list
76150da5174STom St Denis * that backs user memory and will ultimately be mapped into the device
76250da5174STom St Denis * address space.
76350da5174STom St Denis */
amdgpu_ttm_tt_set_user_pages(struct ttm_tt * ttm,struct page ** pages)764a216ab09SChristian König void amdgpu_ttm_tt_set_user_pages(struct ttm_tt *ttm, struct page **pages)
765aca81718STom St Denis {
7661986a3b0SFelix Kuehling unsigned long i;
767aca81718STom St Denis
768899fbde1SPhilip Yang for (i = 0; i < ttm->num_pages; ++i)
769a216ab09SChristian König ttm->pages[i] = pages ? pages[i] : NULL;
770aca81718STom St Denis }
7718944042dSAlex Deucher
77275501872SLee Jones /*
7732e603d04SHuang Rui * amdgpu_ttm_tt_pin_userptr - prepare the sg table with the user pages
77450da5174STom St Denis *
77550da5174STom St Denis * Called by amdgpu_ttm_backend_bind()
77650da5174STom St Denis **/
amdgpu_ttm_tt_pin_userptr(struct ttm_device * bdev,struct ttm_tt * ttm)7778af8a109SChristian König static int amdgpu_ttm_tt_pin_userptr(struct ttm_device *bdev,
7780a667b50SDave Airlie struct ttm_tt *ttm)
7792f568dbdSChristian König {
7800a667b50SDave Airlie struct amdgpu_device *adev = amdgpu_ttm_adev(bdev);
781c4c10a68SRajneesh Bhardwaj struct amdgpu_ttm_tt *gtt = ttm_to_amdgpu_ttm_tt(ttm);
7822f568dbdSChristian König int write = !(gtt->userflags & AMDGPU_GEM_USERPTR_READONLY);
7832f568dbdSChristian König enum dma_data_direction direction = write ?
7842f568dbdSChristian König DMA_BIDIRECTIONAL : DMA_TO_DEVICE;
7859973de10SGuchun Chen int r;
7862f568dbdSChristian König
78750da5174STom St Denis /* Allocate an SG array and squash pages into it */
788d38ceaf9SAlex Deucher r = sg_alloc_table_from_pages(ttm->sg, ttm->pages, ttm->num_pages, 0,
789b16e6857Sxinhui pan (u64)ttm->num_pages << PAGE_SHIFT,
790d38ceaf9SAlex Deucher GFP_KERNEL);
791d38ceaf9SAlex Deucher if (r)
792d38ceaf9SAlex Deucher goto release_sg;
793d38ceaf9SAlex Deucher
79450da5174STom St Denis /* Map SG to device */
79539913934SMarek Szyprowski r = dma_map_sgtable(adev->dev, ttm->sg, direction, 0);
79639913934SMarek Szyprowski if (r)
797efb05475SLang Yu goto release_sg_table;
798d38ceaf9SAlex Deucher
79950da5174STom St Denis /* convert SG to linear array of pages and dma addresses */
800c67e6279SChristian König drm_prime_sg_to_dma_addr_array(ttm->sg, gtt->ttm.dma_address,
8014e7b9000SChristian König ttm->num_pages);
802d38ceaf9SAlex Deucher
803d38ceaf9SAlex Deucher return 0;
804d38ceaf9SAlex Deucher
805efb05475SLang Yu release_sg_table:
806efb05475SLang Yu sg_free_table(ttm->sg);
807d38ceaf9SAlex Deucher release_sg:
808d38ceaf9SAlex Deucher kfree(ttm->sg);
809c8e74b17SPhilip Yang ttm->sg = NULL;
810d38ceaf9SAlex Deucher return r;
811d38ceaf9SAlex Deucher }
812d38ceaf9SAlex Deucher
81375501872SLee Jones /*
81450da5174STom St Denis * amdgpu_ttm_tt_unpin_userptr - Unpin and unmap userptr pages
81550da5174STom St Denis */
amdgpu_ttm_tt_unpin_userptr(struct ttm_device * bdev,struct ttm_tt * ttm)8168af8a109SChristian König static void amdgpu_ttm_tt_unpin_userptr(struct ttm_device *bdev,
8170a667b50SDave Airlie struct ttm_tt *ttm)
818d38ceaf9SAlex Deucher {
8190a667b50SDave Airlie struct amdgpu_device *adev = amdgpu_ttm_adev(bdev);
820c4c10a68SRajneesh Bhardwaj struct amdgpu_ttm_tt *gtt = ttm_to_amdgpu_ttm_tt(ttm);
821d38ceaf9SAlex Deucher int write = !(gtt->userflags & AMDGPU_GEM_USERPTR_READONLY);
822d38ceaf9SAlex Deucher enum dma_data_direction direction = write ?
823d38ceaf9SAlex Deucher DMA_BIDIRECTIONAL : DMA_TO_DEVICE;
824d38ceaf9SAlex Deucher
825d38ceaf9SAlex Deucher /* double check that we don't free the table twice */
8263c3dc654SGuchun Chen if (!ttm->sg || !ttm->sg->sgl)
827d38ceaf9SAlex Deucher return;
828d38ceaf9SAlex Deucher
82950da5174STom St Denis /* unmap the pages mapped to the device */
83039913934SMarek Szyprowski dma_unmap_sgtable(adev->dev, ttm->sg, direction, 0);
831318c3f4bSAlex Deucher sg_free_table(ttm->sg);
832d38ceaf9SAlex Deucher }
833d38ceaf9SAlex Deucher
8342f77b9a2SMukul Joshi /*
8352f77b9a2SMukul Joshi * total_pages is constructed as MQD0+CtrlStack0 + MQD1+CtrlStack1 + ...
8362f77b9a2SMukul Joshi * MQDn+CtrlStackn where n is the number of XCCs per partition.
8372f77b9a2SMukul Joshi * pages_per_xcc is the size of one MQD+CtrlStack. The first page is MQD
8382f77b9a2SMukul Joshi * and uses memory type default, UC. The rest of pages_per_xcc are
8392f77b9a2SMukul Joshi * Ctrl stack and modify their memory type to NC.
8402f77b9a2SMukul Joshi */
amdgpu_ttm_gart_bind_gfx9_mqd(struct amdgpu_device * adev,struct ttm_tt * ttm,uint64_t flags)8412f77b9a2SMukul Joshi static void amdgpu_ttm_gart_bind_gfx9_mqd(struct amdgpu_device *adev,
8422f77b9a2SMukul Joshi struct ttm_tt *ttm, uint64_t flags)
8432f77b9a2SMukul Joshi {
8442f77b9a2SMukul Joshi struct amdgpu_ttm_tt *gtt = (void *)ttm;
8452f77b9a2SMukul Joshi uint64_t total_pages = ttm->num_pages;
8462f77b9a2SMukul Joshi int num_xcc = max(1U, adev->gfx.num_xcc_per_xcp);
84745b3a914SAlex Deucher uint64_t page_idx, pages_per_xcc;
8482f77b9a2SMukul Joshi int i;
8492f77b9a2SMukul Joshi uint64_t ctrl_flags = (flags & ~AMDGPU_PTE_MTYPE_VG10_MASK) |
8502f77b9a2SMukul Joshi AMDGPU_PTE_MTYPE_VG10(AMDGPU_MTYPE_NC);
8512f77b9a2SMukul Joshi
85245b3a914SAlex Deucher pages_per_xcc = total_pages;
85345b3a914SAlex Deucher do_div(pages_per_xcc, num_xcc);
85445b3a914SAlex Deucher
8552f77b9a2SMukul Joshi for (i = 0, page_idx = 0; i < num_xcc; i++, page_idx += pages_per_xcc) {
8562f77b9a2SMukul Joshi /* MQD page: use default flags */
8572f77b9a2SMukul Joshi amdgpu_gart_bind(adev,
8582f77b9a2SMukul Joshi gtt->offset + (page_idx << PAGE_SHIFT),
8592f77b9a2SMukul Joshi 1, >t->ttm.dma_address[page_idx], flags);
8602f77b9a2SMukul Joshi /*
8612f77b9a2SMukul Joshi * Ctrl pages - modify the memory type to NC (ctrl_flags) from
8622f77b9a2SMukul Joshi * the second page of the BO onward.
8632f77b9a2SMukul Joshi */
8642f77b9a2SMukul Joshi amdgpu_gart_bind(adev,
8652f77b9a2SMukul Joshi gtt->offset + ((page_idx + 1) << PAGE_SHIFT),
8662f77b9a2SMukul Joshi pages_per_xcc - 1,
8672f77b9a2SMukul Joshi >t->ttm.dma_address[page_idx + 1],
8682f77b9a2SMukul Joshi ctrl_flags);
8692f77b9a2SMukul Joshi }
8702f77b9a2SMukul Joshi }
8712f77b9a2SMukul Joshi
amdgpu_ttm_gart_bind(struct amdgpu_device * adev,struct ttm_buffer_object * tbo,uint64_t flags)8721b08dfb8SChristian König static void amdgpu_ttm_gart_bind(struct amdgpu_device *adev,
873959a2091SYong Zhao struct ttm_buffer_object *tbo,
874959a2091SYong Zhao uint64_t flags)
875959a2091SYong Zhao {
876959a2091SYong Zhao struct amdgpu_bo *abo = ttm_to_amdgpu_bo(tbo);
877959a2091SYong Zhao struct ttm_tt *ttm = tbo->ttm;
878c4c10a68SRajneesh Bhardwaj struct amdgpu_ttm_tt *gtt = ttm_to_amdgpu_ttm_tt(ttm);
879959a2091SYong Zhao
880bffc8c5cSChristian König if (amdgpu_bo_encrypted(abo))
881bffc8c5cSChristian König flags |= AMDGPU_PTE_TMZ;
882bffc8c5cSChristian König
883fa5bde80SYong Zhao if (abo->flags & AMDGPU_GEM_CREATE_CP_MQD_GFX9) {
8842f77b9a2SMukul Joshi amdgpu_ttm_gart_bind_gfx9_mqd(adev, ttm, flags);
885959a2091SYong Zhao } else {
8861b08dfb8SChristian König amdgpu_gart_bind(adev, gtt->offset, ttm->num_pages,
887942ab769SYifan Zhang gtt->ttm.dma_address, flags);
888959a2091SYong Zhao }
8896fcd12cbSPhilip Yang gtt->bound = true;
890959a2091SYong Zhao }
891959a2091SYong Zhao
89275501872SLee Jones /*
89350da5174STom St Denis * amdgpu_ttm_backend_bind - Bind GTT memory
89450da5174STom St Denis *
89550da5174STom St Denis * Called by ttm_tt_bind() on behalf of ttm_bo_handle_move_mem().
89650da5174STom St Denis * This handles binding GTT memory to the device address space.
89750da5174STom St Denis */
amdgpu_ttm_backend_bind(struct ttm_device * bdev,struct ttm_tt * ttm,struct ttm_resource * bo_mem)8988af8a109SChristian König static int amdgpu_ttm_backend_bind(struct ttm_device *bdev,
8990a667b50SDave Airlie struct ttm_tt *ttm,
9002966141aSDave Airlie struct ttm_resource *bo_mem)
901d38ceaf9SAlex Deucher {
9020a667b50SDave Airlie struct amdgpu_device *adev = amdgpu_ttm_adev(bdev);
903c4c10a68SRajneesh Bhardwaj struct amdgpu_ttm_tt *gtt = ttm_to_amdgpu_ttm_tt(ttm);
904ac7afe6bSChristian König uint64_t flags;
9051b08dfb8SChristian König int r;
906d38ceaf9SAlex Deucher
9070b988ca1SDave Airlie if (!bo_mem)
9080b988ca1SDave Airlie return -EINVAL;
9090b988ca1SDave Airlie
9100b988ca1SDave Airlie if (gtt->bound)
9110b988ca1SDave Airlie return 0;
9120b988ca1SDave Airlie
913e2f784faSChunming Zhou if (gtt->userptr) {
9140a667b50SDave Airlie r = amdgpu_ttm_tt_pin_userptr(bdev, ttm);
915e2f784faSChunming Zhou if (r) {
916e2f784faSChunming Zhou DRM_ERROR("failed to pin userptr\n");
917e2f784faSChunming Zhou return r;
918e2f784faSChunming Zhou }
91943d46f0bSMatthew Auld } else if (ttm->page_flags & TTM_TT_FLAG_EXTERNAL) {
920e552ee40SFelix Kuehling if (!ttm->sg) {
921e552ee40SFelix Kuehling struct dma_buf_attachment *attach;
922e552ee40SFelix Kuehling struct sg_table *sgt;
923e552ee40SFelix Kuehling
924e552ee40SFelix Kuehling attach = gtt->gobj->import_attach;
925e552ee40SFelix Kuehling sgt = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL);
926e552ee40SFelix Kuehling if (IS_ERR(sgt))
927e552ee40SFelix Kuehling return PTR_ERR(sgt);
928e552ee40SFelix Kuehling
929e552ee40SFelix Kuehling ttm->sg = sgt;
930e2f784faSChunming Zhou }
931e552ee40SFelix Kuehling
932e552ee40SFelix Kuehling drm_prime_sg_to_dma_addr_array(ttm->sg, gtt->ttm.dma_address,
933e552ee40SFelix Kuehling ttm->num_pages);
934e552ee40SFelix Kuehling }
935e552ee40SFelix Kuehling
936d38ceaf9SAlex Deucher if (!ttm->num_pages) {
937230c079fSChristian König WARN(1, "nothing to bind %u pages for mreg %p back %p!\n",
938d38ceaf9SAlex Deucher ttm->num_pages, bo_mem, ttm);
939d38ceaf9SAlex Deucher }
940d38ceaf9SAlex Deucher
941ba2472eaSNirmoy Das if (bo_mem->mem_type != TTM_PL_TT ||
942ba2472eaSNirmoy Das !amdgpu_gtt_mgr_has_gart_addr(bo_mem)) {
9433da917b6SChristian König gtt->offset = AMDGPU_BO_INVALID_OFFSET;
944ac7afe6bSChristian König return 0;
9453da917b6SChristian König }
94698a7f88cSChristian König
94750da5174STom St Denis /* compute PTE flags relevant to this BO memory */
948d9a13766SChristian König flags = amdgpu_ttm_tt_pte_flags(adev, ttm, bo_mem);
94950da5174STom St Denis
95050da5174STom St Denis /* bind pages into GART page tables */
9510957dc70SChristian König gtt->offset = (u64)bo_mem->start << PAGE_SHIFT;
9521b08dfb8SChristian König amdgpu_gart_bind(adev, gtt->offset, ttm->num_pages,
953942ab769SYifan Zhang gtt->ttm.dma_address, flags);
9540b988ca1SDave Airlie gtt->bound = true;
9551b08dfb8SChristian König return 0;
956c855e250SChristian König }
957c855e250SChristian König
95875501872SLee Jones /*
95991b59005SOak Zeng * amdgpu_ttm_alloc_gart - Make sure buffer object is accessible either
96091b59005SOak Zeng * through AGP or GART aperture.
96191b59005SOak Zeng *
96291b59005SOak Zeng * If bo is accessible through AGP aperture, then use AGP aperture
96391b59005SOak Zeng * to access bo; otherwise allocate logical space in GART aperture
96491b59005SOak Zeng * and map bo to GART aperture.
96550da5174STom St Denis */
amdgpu_ttm_alloc_gart(struct ttm_buffer_object * bo)966c5835bbbSChristian König int amdgpu_ttm_alloc_gart(struct ttm_buffer_object *bo)
967c855e250SChristian König {
9681d00402bSChristian König struct amdgpu_device *adev = amdgpu_ttm_adev(bo->bdev);
969c13c55d6SChristian König struct ttm_operation_ctx ctx = { false, false };
970c4c10a68SRajneesh Bhardwaj struct amdgpu_ttm_tt *gtt = ttm_to_amdgpu_ttm_tt(bo->ttm);
9711d00402bSChristian König struct ttm_placement placement;
9721d00402bSChristian König struct ttm_place placements;
973bfa3357eSChristian König struct ttm_resource *tmp;
974485fc361SChristian König uint64_t addr, flags;
975c855e250SChristian König int r;
976c855e250SChristian König
977d3116756SChristian König if (bo->resource->start != AMDGPU_BO_INVALID_OFFSET)
978c855e250SChristian König return 0;
979c855e250SChristian König
980485fc361SChristian König addr = amdgpu_gmc_agp_addr(bo);
981485fc361SChristian König if (addr != AMDGPU_BO_INVALID_OFFSET) {
982d3116756SChristian König bo->resource->start = addr >> PAGE_SHIFT;
983bfa3357eSChristian König return 0;
984bfa3357eSChristian König }
985485fc361SChristian König
9860e33495dSChristian König /* allocate GART space */
9871d00402bSChristian König placement.num_placement = 1;
9881d00402bSChristian König placement.placement = &placements;
9891d00402bSChristian König placement.num_busy_placement = 1;
9901d00402bSChristian König placement.busy_placement = &placements;
9911d00402bSChristian König placements.fpfn = 0;
992770d13b1SChristian König placements.lpfn = adev->gmc.gart_size >> PAGE_SHIFT;
99348e07c23SChristian König placements.mem_type = TTM_PL_TT;
994d3116756SChristian König placements.flags = bo->resource->placement;
995bb990bb0SChristian König
996c13c55d6SChristian König r = ttm_bo_mem_space(bo, &placement, &tmp, &ctx);
9971d00402bSChristian König if (unlikely(r))
9981d00402bSChristian König return r;
9991d00402bSChristian König
100050da5174STom St Denis /* compute PTE flags for this buffer object */
1001bfa3357eSChristian König flags = amdgpu_ttm_tt_pte_flags(adev, bo->ttm, tmp);
100250da5174STom St Denis
100350da5174STom St Denis /* Bind pages */
1004bfa3357eSChristian König gtt->offset = (u64)tmp->start << PAGE_SHIFT;
10051b08dfb8SChristian König amdgpu_ttm_gart_bind(adev, bo, flags);
100619a1d935SNirmoy Das amdgpu_gart_invalidate_tlb(adev);
1007bfa3357eSChristian König ttm_resource_free(bo, &bo->resource);
1008bfa3357eSChristian König ttm_bo_assign_mem(bo, tmp);
1009485fc361SChristian König
101040575732SChristian König return 0;
1011d38ceaf9SAlex Deucher }
1012d38ceaf9SAlex Deucher
101375501872SLee Jones /*
101450da5174STom St Denis * amdgpu_ttm_recover_gart - Rebind GTT pages
101550da5174STom St Denis *
101650da5174STom St Denis * Called by amdgpu_gtt_mgr_recover() from amdgpu_device_reset() to
101750da5174STom St Denis * rebind GTT pages during a GPU reset.
101850da5174STom St Denis */
amdgpu_ttm_recover_gart(struct ttm_buffer_object * tbo)10191b08dfb8SChristian König void amdgpu_ttm_recover_gart(struct ttm_buffer_object *tbo)
10202c0d7318SChunming Zhou {
1021c1c7ce8fSChristian König struct amdgpu_device *adev = amdgpu_ttm_adev(tbo->bdev);
10221d1a2cd5SMonk Liu uint64_t flags;
10232c0d7318SChunming Zhou
1024959a2091SYong Zhao if (!tbo->ttm)
10251b08dfb8SChristian König return;
1026c1c7ce8fSChristian König
1027d3116756SChristian König flags = amdgpu_ttm_tt_pte_flags(adev, tbo->ttm, tbo->resource);
10281b08dfb8SChristian König amdgpu_ttm_gart_bind(adev, tbo, flags);
10292c0d7318SChunming Zhou }
10302c0d7318SChunming Zhou
103175501872SLee Jones /*
103250da5174STom St Denis * amdgpu_ttm_backend_unbind - Unbind GTT mapped pages
103350da5174STom St Denis *
103450da5174STom St Denis * Called by ttm_tt_unbind() on behalf of ttm_bo_move_ttm() and
103550da5174STom St Denis * ttm_tt_destroy().
103650da5174STom St Denis */
amdgpu_ttm_backend_unbind(struct ttm_device * bdev,struct ttm_tt * ttm)10378af8a109SChristian König static void amdgpu_ttm_backend_unbind(struct ttm_device *bdev,
10380a667b50SDave Airlie struct ttm_tt *ttm)
1039d38ceaf9SAlex Deucher {
10400a667b50SDave Airlie struct amdgpu_device *adev = amdgpu_ttm_adev(bdev);
1041c4c10a68SRajneesh Bhardwaj struct amdgpu_ttm_tt *gtt = ttm_to_amdgpu_ttm_tt(ttm);
1042d38ceaf9SAlex Deucher
104350da5174STom St Denis /* if the pages have userptr pinning then clear that first */
1044e552ee40SFelix Kuehling if (gtt->userptr) {
10450a667b50SDave Airlie amdgpu_ttm_tt_unpin_userptr(bdev, ttm);
1046e552ee40SFelix Kuehling } else if (ttm->sg && gtt->gobj->import_attach) {
1047e552ee40SFelix Kuehling struct dma_buf_attachment *attach;
1048e552ee40SFelix Kuehling
1049e552ee40SFelix Kuehling attach = gtt->gobj->import_attach;
1050e552ee40SFelix Kuehling dma_buf_unmap_attachment(attach, ttm->sg, DMA_BIDIRECTIONAL);
1051e552ee40SFelix Kuehling ttm->sg = NULL;
1052e552ee40SFelix Kuehling }
105385a4b579SChristian König
10540f6f9dd4SDaniel Gomez if (!gtt->bound)
10550f6f9dd4SDaniel Gomez return;
10560f6f9dd4SDaniel Gomez
10573da917b6SChristian König if (gtt->offset == AMDGPU_BO_INVALID_OFFSET)
105808bb88cfSDave Airlie return;
105978ab0a38SChristian König
1060d38ceaf9SAlex Deucher /* unbind shouldn't be done for GDS/GWS/OA in ttm_bo_clean_mm */
10611b08dfb8SChristian König amdgpu_gart_unbind(adev, gtt->offset, ttm->num_pages);
10620b988ca1SDave Airlie gtt->bound = false;
1063d38ceaf9SAlex Deucher }
1064d38ceaf9SAlex Deucher
amdgpu_ttm_backend_destroy(struct ttm_device * bdev,struct ttm_tt * ttm)10658af8a109SChristian König static void amdgpu_ttm_backend_destroy(struct ttm_device *bdev,
10660a667b50SDave Airlie struct ttm_tt *ttm)
1067d38ceaf9SAlex Deucher {
1068c4c10a68SRajneesh Bhardwaj struct amdgpu_ttm_tt *gtt = ttm_to_amdgpu_ttm_tt(ttm);
1069d38ceaf9SAlex Deucher
10700919195fSFelix Kuehling if (gtt->usertask)
10710919195fSFelix Kuehling put_task_struct(gtt->usertask);
10720919195fSFelix Kuehling
1073e34b8feeSChristian König ttm_tt_fini(>t->ttm);
1074d38ceaf9SAlex Deucher kfree(gtt);
1075d38ceaf9SAlex Deucher }
1076d38ceaf9SAlex Deucher
107750da5174STom St Denis /**
107850da5174STom St Denis * amdgpu_ttm_tt_create - Create a ttm_tt object for a given BO
107950da5174STom St Denis *
108050da5174STom St Denis * @bo: The buffer object to create a GTT ttm_tt object around
10816abc3f97SLee Jones * @page_flags: Page flags to be added to the ttm_tt object
108250da5174STom St Denis *
108350da5174STom St Denis * Called by ttm_tt_create().
108450da5174STom St Denis */
amdgpu_ttm_tt_create(struct ttm_buffer_object * bo,uint32_t page_flags)1085dde5da23SChristian König static struct ttm_tt *amdgpu_ttm_tt_create(struct ttm_buffer_object *bo,
1086dde5da23SChristian König uint32_t page_flags)
1087d38ceaf9SAlex Deucher {
10883ebfd221SPhilip Yang struct amdgpu_device *adev = amdgpu_ttm_adev(bo->bdev);
10891b4ea4c5SChristian König struct amdgpu_bo *abo = ttm_to_amdgpu_bo(bo);
1090d38ceaf9SAlex Deucher struct amdgpu_ttm_tt *gtt;
10911b4ea4c5SChristian König enum ttm_caching caching;
1092d38ceaf9SAlex Deucher
1093d38ceaf9SAlex Deucher gtt = kzalloc(sizeof(struct amdgpu_ttm_tt), GFP_KERNEL);
109401c3f464SSrinivasan Shanmugam if (!gtt)
1095d38ceaf9SAlex Deucher return NULL;
109601c3f464SSrinivasan Shanmugam
1097a3941471SChristian König gtt->gobj = &bo->base;
10983ebfd221SPhilip Yang if (adev->gmc.mem_partitions && abo->xcp_id >= 0)
10993ebfd221SPhilip Yang gtt->pool_id = KFD_XCP_MEM_ID(adev, abo->xcp_id);
11003ebfd221SPhilip Yang else
11013ebfd221SPhilip Yang gtt->pool_id = abo->xcp_id;
110250da5174STom St Denis
11031b4ea4c5SChristian König if (abo->flags & AMDGPU_GEM_CREATE_CPU_GTT_USWC)
11041b4ea4c5SChristian König caching = ttm_write_combined;
11051b4ea4c5SChristian König else
11061b4ea4c5SChristian König caching = ttm_cached;
11071b4ea4c5SChristian König
110850da5174STom St Denis /* allocate space for the uninitialized page entries */
11091b4ea4c5SChristian König if (ttm_sg_tt_init(>t->ttm, bo, page_flags, caching)) {
1110d38ceaf9SAlex Deucher kfree(gtt);
1111d38ceaf9SAlex Deucher return NULL;
1112d38ceaf9SAlex Deucher }
1113e34b8feeSChristian König return >t->ttm;
1114d38ceaf9SAlex Deucher }
1115d38ceaf9SAlex Deucher
111675501872SLee Jones /*
111750da5174STom St Denis * amdgpu_ttm_tt_populate - Map GTT pages visible to the device
111850da5174STom St Denis *
111950da5174STom St Denis * Map the pages of a ttm_tt object to an address space visible
112050da5174STom St Denis * to the underlying device.
112150da5174STom St Denis */
amdgpu_ttm_tt_populate(struct ttm_device * bdev,struct ttm_tt * ttm,struct ttm_operation_ctx * ctx)11228af8a109SChristian König static int amdgpu_ttm_tt_populate(struct ttm_device *bdev,
11230a667b50SDave Airlie struct ttm_tt *ttm,
1124d0cef9faSRoger He struct ttm_operation_ctx *ctx)
1125d38ceaf9SAlex Deucher {
11260a667b50SDave Airlie struct amdgpu_device *adev = amdgpu_ttm_adev(bdev);
1127c4c10a68SRajneesh Bhardwaj struct amdgpu_ttm_tt *gtt = ttm_to_amdgpu_ttm_tt(ttm);
11281e03322cSPhilip Yang struct ttm_pool *pool;
112921856e1eSMatthew Auld pgoff_t i;
113021856e1eSMatthew Auld int ret;
1131d38ceaf9SAlex Deucher
113250da5174STom St Denis /* user pages are bound by amdgpu_ttm_tt_pin_userptr() */
1133a204ea8cSTuo Li if (gtt->userptr) {
11345f0b34ccSManinder Singh ttm->sg = kzalloc(sizeof(struct sg_table), GFP_KERNEL);
1135d38ceaf9SAlex Deucher if (!ttm->sg)
1136d38ceaf9SAlex Deucher return -ENOMEM;
1137d38ceaf9SAlex Deucher return 0;
1138d38ceaf9SAlex Deucher }
1139d38ceaf9SAlex Deucher
114043d46f0bSMatthew Auld if (ttm->page_flags & TTM_TT_FLAG_EXTERNAL)
114179ba2800STom St Denis return 0;
1142d38ceaf9SAlex Deucher
11431e03322cSPhilip Yang if (adev->mman.ttm_pools && gtt->pool_id >= 0)
11441e03322cSPhilip Yang pool = &adev->mman.ttm_pools[gtt->pool_id];
11451e03322cSPhilip Yang else
11461e03322cSPhilip Yang pool = &adev->mman.bdev.pool;
11471e03322cSPhilip Yang ret = ttm_pool_alloc(pool, ttm, ctx);
114821856e1eSMatthew Auld if (ret)
114921856e1eSMatthew Auld return ret;
115021856e1eSMatthew Auld
115121856e1eSMatthew Auld for (i = 0; i < ttm->num_pages; ++i)
115221856e1eSMatthew Auld ttm->pages[i]->mapping = bdev->dev_mapping;
115321856e1eSMatthew Auld
115421856e1eSMatthew Auld return 0;
1155d38ceaf9SAlex Deucher }
1156d38ceaf9SAlex Deucher
115775501872SLee Jones /*
115850da5174STom St Denis * amdgpu_ttm_tt_unpopulate - unmap GTT pages and unpopulate page arrays
115950da5174STom St Denis *
116050da5174STom St Denis * Unmaps pages of a ttm_tt object from the device address space and
116150da5174STom St Denis * unpopulates the page array backing it.
116250da5174STom St Denis */
amdgpu_ttm_tt_unpopulate(struct ttm_device * bdev,struct ttm_tt * ttm)11638af8a109SChristian König static void amdgpu_ttm_tt_unpopulate(struct ttm_device *bdev,
1164e93b2da9SChristian König struct ttm_tt *ttm)
1165d38ceaf9SAlex Deucher {
1166c4c10a68SRajneesh Bhardwaj struct amdgpu_ttm_tt *gtt = ttm_to_amdgpu_ttm_tt(ttm);
1167a3941471SChristian König struct amdgpu_device *adev;
11681e03322cSPhilip Yang struct ttm_pool *pool;
116921856e1eSMatthew Auld pgoff_t i;
1170d38ceaf9SAlex Deucher
1171b7e8b086SChristian König amdgpu_ttm_backend_unbind(bdev, ttm);
1172b7e8b086SChristian König
1173a204ea8cSTuo Li if (gtt->userptr) {
1174a216ab09SChristian König amdgpu_ttm_tt_set_user_pages(ttm, NULL);
1175d38ceaf9SAlex Deucher kfree(ttm->sg);
11761e5c3738Sxinhui pan ttm->sg = NULL;
1177a3941471SChristian König return;
1178a3941471SChristian König }
1179a3941471SChristian König
118043d46f0bSMatthew Auld if (ttm->page_flags & TTM_TT_FLAG_EXTERNAL)
1181d38ceaf9SAlex Deucher return;
1182d38ceaf9SAlex Deucher
118321856e1eSMatthew Auld for (i = 0; i < ttm->num_pages; ++i)
118421856e1eSMatthew Auld ttm->pages[i]->mapping = NULL;
118521856e1eSMatthew Auld
11860a667b50SDave Airlie adev = amdgpu_ttm_adev(bdev);
11871e03322cSPhilip Yang
11881e03322cSPhilip Yang if (adev->mman.ttm_pools && gtt->pool_id >= 0)
11891e03322cSPhilip Yang pool = &adev->mman.ttm_pools[gtt->pool_id];
11901e03322cSPhilip Yang else
11911e03322cSPhilip Yang pool = &adev->mman.bdev.pool;
11921e03322cSPhilip Yang
11931e03322cSPhilip Yang return ttm_pool_free(pool, ttm);
1194d38ceaf9SAlex Deucher }
1195d38ceaf9SAlex Deucher
119650da5174STom St Denis /**
11975ccbb057SRajneesh Bhardwaj * amdgpu_ttm_tt_get_userptr - Return the userptr GTT ttm_tt for the current
11985ccbb057SRajneesh Bhardwaj * task
11995ccbb057SRajneesh Bhardwaj *
12005ccbb057SRajneesh Bhardwaj * @tbo: The ttm_buffer_object that contains the userptr
12015ccbb057SRajneesh Bhardwaj * @user_addr: The returned value
12025ccbb057SRajneesh Bhardwaj */
amdgpu_ttm_tt_get_userptr(const struct ttm_buffer_object * tbo,uint64_t * user_addr)12035ccbb057SRajneesh Bhardwaj int amdgpu_ttm_tt_get_userptr(const struct ttm_buffer_object *tbo,
12045ccbb057SRajneesh Bhardwaj uint64_t *user_addr)
12055ccbb057SRajneesh Bhardwaj {
12065ccbb057SRajneesh Bhardwaj struct amdgpu_ttm_tt *gtt;
12075ccbb057SRajneesh Bhardwaj
12085ccbb057SRajneesh Bhardwaj if (!tbo->ttm)
12095ccbb057SRajneesh Bhardwaj return -EINVAL;
12105ccbb057SRajneesh Bhardwaj
12115ccbb057SRajneesh Bhardwaj gtt = (void *)tbo->ttm;
12125ccbb057SRajneesh Bhardwaj *user_addr = gtt->userptr;
12135ccbb057SRajneesh Bhardwaj return 0;
12145ccbb057SRajneesh Bhardwaj }
12155ccbb057SRajneesh Bhardwaj
12165ccbb057SRajneesh Bhardwaj /**
12172e603d04SHuang Rui * amdgpu_ttm_tt_set_userptr - Initialize userptr GTT ttm_tt for the current
12182e603d04SHuang Rui * task
121950da5174STom St Denis *
122077f47d23SChristian König * @bo: The ttm_buffer_object to bind this userptr to
122150da5174STom St Denis * @addr: The address in the current tasks VM space to use
122250da5174STom St Denis * @flags: Requirements of userptr object.
122350da5174STom St Denis *
1224adf65dffSRajneesh Bhardwaj * Called by amdgpu_gem_userptr_ioctl() and kfd_ioctl_alloc_memory_of_gpu() to
1225adf65dffSRajneesh Bhardwaj * bind userptr pages to current task and by kfd_ioctl_acquire_vm() to
1226adf65dffSRajneesh Bhardwaj * initialize GPU VM for a KFD process.
122750da5174STom St Denis */
amdgpu_ttm_tt_set_userptr(struct ttm_buffer_object * bo,uint64_t addr,uint32_t flags)122877f47d23SChristian König int amdgpu_ttm_tt_set_userptr(struct ttm_buffer_object *bo,
122977f47d23SChristian König uint64_t addr, uint32_t flags)
1230d38ceaf9SAlex Deucher {
123177f47d23SChristian König struct amdgpu_ttm_tt *gtt;
1232d38ceaf9SAlex Deucher
123377f47d23SChristian König if (!bo->ttm) {
123477f47d23SChristian König /* TODO: We want a separate TTM object type for userptrs */
123577f47d23SChristian König bo->ttm = amdgpu_ttm_tt_create(bo, 0);
123677f47d23SChristian König if (bo->ttm == NULL)
123777f47d23SChristian König return -ENOMEM;
123877f47d23SChristian König }
1239d38ceaf9SAlex Deucher
124043d46f0bSMatthew Auld /* Set TTM_TT_FLAG_EXTERNAL before populate but after create. */
124143d46f0bSMatthew Auld bo->ttm->page_flags |= TTM_TT_FLAG_EXTERNAL;
124284408d5fSxinhui pan
1243c4c10a68SRajneesh Bhardwaj gtt = ttm_to_amdgpu_ttm_tt(bo->ttm);
1244d38ceaf9SAlex Deucher gtt->userptr = addr;
1245d38ceaf9SAlex Deucher gtt->userflags = flags;
12460919195fSFelix Kuehling
12470919195fSFelix Kuehling if (gtt->usertask)
12480919195fSFelix Kuehling put_task_struct(gtt->usertask);
12490919195fSFelix Kuehling gtt->usertask = current->group_leader;
12500919195fSFelix Kuehling get_task_struct(gtt->usertask);
12510919195fSFelix Kuehling
1252d38ceaf9SAlex Deucher return 0;
1253d38ceaf9SAlex Deucher }
1254d38ceaf9SAlex Deucher
125575501872SLee Jones /*
125650da5174STom St Denis * amdgpu_ttm_tt_get_usermm - Return memory manager for ttm_tt object
125750da5174STom St Denis */
amdgpu_ttm_tt_get_usermm(struct ttm_tt * ttm)1258cc325d19SChristian König struct mm_struct *amdgpu_ttm_tt_get_usermm(struct ttm_tt *ttm)
1259d38ceaf9SAlex Deucher {
1260c4c10a68SRajneesh Bhardwaj struct amdgpu_ttm_tt *gtt = ttm_to_amdgpu_ttm_tt(ttm);
1261d38ceaf9SAlex Deucher
1262d38ceaf9SAlex Deucher if (gtt == NULL)
1263cc325d19SChristian König return NULL;
1264d38ceaf9SAlex Deucher
12650919195fSFelix Kuehling if (gtt->usertask == NULL)
12660919195fSFelix Kuehling return NULL;
12670919195fSFelix Kuehling
12680919195fSFelix Kuehling return gtt->usertask->mm;
1269d38ceaf9SAlex Deucher }
1270d38ceaf9SAlex Deucher
127175501872SLee Jones /*
12722e603d04SHuang Rui * amdgpu_ttm_tt_affect_userptr - Determine if a ttm_tt object lays inside an
12732e603d04SHuang Rui * address range for the current task.
127450da5174STom St Denis *
127550da5174STom St Denis */
amdgpu_ttm_tt_affect_userptr(struct ttm_tt * ttm,unsigned long start,unsigned long end,unsigned long * userptr)1276cc1de6e8SChristian König bool amdgpu_ttm_tt_affect_userptr(struct ttm_tt *ttm, unsigned long start,
127743fc10c1SPhilip Yang unsigned long end, unsigned long *userptr)
1278cc1de6e8SChristian König {
1279c4c10a68SRajneesh Bhardwaj struct amdgpu_ttm_tt *gtt = ttm_to_amdgpu_ttm_tt(ttm);
1280cc1de6e8SChristian König unsigned long size;
1281cc1de6e8SChristian König
1282637dd3b5SChristian König if (gtt == NULL || !gtt->userptr)
1283cc1de6e8SChristian König return false;
1284cc1de6e8SChristian König
128550da5174STom St Denis /* Return false if no part of the ttm_tt object lies within
128650da5174STom St Denis * the range
128750da5174STom St Denis */
1288e34b8feeSChristian König size = (unsigned long)gtt->ttm.num_pages * PAGE_SIZE;
1289cc1de6e8SChristian König if (gtt->userptr > end || gtt->userptr + size <= start)
1290cc1de6e8SChristian König return false;
1291cc1de6e8SChristian König
129243fc10c1SPhilip Yang if (userptr)
129343fc10c1SPhilip Yang *userptr = gtt->userptr;
1294cc1de6e8SChristian König return true;
1295cc1de6e8SChristian König }
1296cc1de6e8SChristian König
129775501872SLee Jones /*
1298899fbde1SPhilip Yang * amdgpu_ttm_tt_is_userptr - Have the pages backing by userptr?
129950da5174STom St Denis */
amdgpu_ttm_tt_is_userptr(struct ttm_tt * ttm)1300899fbde1SPhilip Yang bool amdgpu_ttm_tt_is_userptr(struct ttm_tt *ttm)
1301ca666a3cSChristian König {
1302c4c10a68SRajneesh Bhardwaj struct amdgpu_ttm_tt *gtt = ttm_to_amdgpu_ttm_tt(ttm);
1303ca666a3cSChristian König
1304ca666a3cSChristian König if (gtt == NULL || !gtt->userptr)
1305ca666a3cSChristian König return false;
1306ca666a3cSChristian König
1307899fbde1SPhilip Yang return true;
1308ca666a3cSChristian König }
1309ca666a3cSChristian König
131075501872SLee Jones /*
131150da5174STom St Denis * amdgpu_ttm_tt_is_readonly - Is the ttm_tt object read only?
131250da5174STom St Denis */
amdgpu_ttm_tt_is_readonly(struct ttm_tt * ttm)1313d38ceaf9SAlex Deucher bool amdgpu_ttm_tt_is_readonly(struct ttm_tt *ttm)
1314d38ceaf9SAlex Deucher {
1315c4c10a68SRajneesh Bhardwaj struct amdgpu_ttm_tt *gtt = ttm_to_amdgpu_ttm_tt(ttm);
1316d38ceaf9SAlex Deucher
1317d38ceaf9SAlex Deucher if (gtt == NULL)
1318d38ceaf9SAlex Deucher return false;
1319d38ceaf9SAlex Deucher
1320d38ceaf9SAlex Deucher return !!(gtt->userflags & AMDGPU_GEM_USERPTR_READONLY);
1321d38ceaf9SAlex Deucher }
1322d38ceaf9SAlex Deucher
132350da5174STom St Denis /**
132424a8d289SChristian König * amdgpu_ttm_tt_pde_flags - Compute PDE flags for ttm_tt object
132550da5174STom St Denis *
132650da5174STom St Denis * @ttm: The ttm_tt object to compute the flags for
132750da5174STom St Denis * @mem: The memory registry backing this ttm_tt object
132824a8d289SChristian König *
132924a8d289SChristian König * Figure out the flags to use for a VM PDE (Page Directory Entry).
133050da5174STom St Denis */
amdgpu_ttm_tt_pde_flags(struct ttm_tt * ttm,struct ttm_resource * mem)13312966141aSDave Airlie uint64_t amdgpu_ttm_tt_pde_flags(struct ttm_tt *ttm, struct ttm_resource *mem)
1332d38ceaf9SAlex Deucher {
13336b777607SChunming Zhou uint64_t flags = 0;
1334d38ceaf9SAlex Deucher
1335d38ceaf9SAlex Deucher if (mem && mem->mem_type != TTM_PL_SYSTEM)
1336d38ceaf9SAlex Deucher flags |= AMDGPU_PTE_VALID;
1337d38ceaf9SAlex Deucher
1338b453e42aSFelix Kuehling if (mem && (mem->mem_type == TTM_PL_TT ||
1339dc3499c7SAlex Deucher mem->mem_type == AMDGPU_PL_DOORBELL ||
1340b453e42aSFelix Kuehling mem->mem_type == AMDGPU_PL_PREEMPT)) {
1341d38ceaf9SAlex Deucher flags |= AMDGPU_PTE_SYSTEM;
1342d38ceaf9SAlex Deucher
13431b4ea4c5SChristian König if (ttm->caching == ttm_cached)
1344d38ceaf9SAlex Deucher flags |= AMDGPU_PTE_SNOOPED;
13456d99905aSChristian König }
1346d38ceaf9SAlex Deucher
13472e2f197fSEric Huang if (mem && mem->mem_type == TTM_PL_VRAM &&
13482e2f197fSEric Huang mem->bus.caching == ttm_cached)
13492e2f197fSEric Huang flags |= AMDGPU_PTE_SNOOPED;
13502e2f197fSEric Huang
135124a8d289SChristian König return flags;
135224a8d289SChristian König }
135324a8d289SChristian König
135424a8d289SChristian König /**
135524a8d289SChristian König * amdgpu_ttm_tt_pte_flags - Compute PTE flags for ttm_tt object
135624a8d289SChristian König *
135775501872SLee Jones * @adev: amdgpu_device pointer
135824a8d289SChristian König * @ttm: The ttm_tt object to compute the flags for
135924a8d289SChristian König * @mem: The memory registry backing this ttm_tt object
136075501872SLee Jones *
136124a8d289SChristian König * Figure out the flags to use for a VM PTE (Page Table Entry).
136224a8d289SChristian König */
amdgpu_ttm_tt_pte_flags(struct amdgpu_device * adev,struct ttm_tt * ttm,struct ttm_resource * mem)136324a8d289SChristian König uint64_t amdgpu_ttm_tt_pte_flags(struct amdgpu_device *adev, struct ttm_tt *ttm,
13642966141aSDave Airlie struct ttm_resource *mem)
136524a8d289SChristian König {
136624a8d289SChristian König uint64_t flags = amdgpu_ttm_tt_pde_flags(ttm, mem);
136724a8d289SChristian König
13684b98e0c4SAlex Xie flags |= adev->gart.gart_pte_flags;
1369d38ceaf9SAlex Deucher flags |= AMDGPU_PTE_READABLE;
1370d38ceaf9SAlex Deucher
1371d38ceaf9SAlex Deucher if (!amdgpu_ttm_tt_is_readonly(ttm))
1372d38ceaf9SAlex Deucher flags |= AMDGPU_PTE_WRITEABLE;
1373d38ceaf9SAlex Deucher
1374d38ceaf9SAlex Deucher return flags;
1375d38ceaf9SAlex Deucher }
1376d38ceaf9SAlex Deucher
137775501872SLee Jones /*
13782e603d04SHuang Rui * amdgpu_ttm_bo_eviction_valuable - Check to see if we can evict a buffer
13792e603d04SHuang Rui * object.
138050da5174STom St Denis *
13812e603d04SHuang Rui * Return true if eviction is sensible. Called by ttm_mem_evict_first() on
13822e603d04SHuang Rui * behalf of ttm_bo_mem_force_space() which tries to evict buffer objects until
13832e603d04SHuang Rui * it can find space for a new object and by ttm_bo_force_list_clean() which is
138450da5174STom St Denis * used to clean out a memory space.
138550da5174STom St Denis */
amdgpu_ttm_bo_eviction_valuable(struct ttm_buffer_object * bo,const struct ttm_place * place)13869982ca68SChristian König static bool amdgpu_ttm_bo_eviction_valuable(struct ttm_buffer_object *bo,
13879982ca68SChristian König const struct ttm_place *place)
13889982ca68SChristian König {
138925b8a14eSChristian König struct dma_resv_iter resv_cursor;
1390d8d019ccSFelix Kuehling struct dma_fence *f;
1391d8d019ccSFelix Kuehling
13926d3c900cSArunpravin Paneer Selvam if (!amdgpu_bo_is_amdgpu_bo(bo))
13936d3c900cSArunpravin Paneer Selvam return ttm_bo_eviction_valuable(bo, place);
13946d3c900cSArunpravin Paneer Selvam
1395abb50d67SThomas Hellström /* Swapout? */
1396abb50d67SThomas Hellström if (bo->resource->mem_type == TTM_PL_SYSTEM)
1397abb50d67SThomas Hellström return true;
1398abb50d67SThomas Hellström
13991bd4e4caSChristian König if (bo->type == ttm_bo_type_kernel &&
14006ceeb144SChristian König !amdgpu_vm_evictable(ttm_to_amdgpu_bo(bo)))
14011bd4e4caSChristian König return false;
14021bd4e4caSChristian König
1403d8d019ccSFelix Kuehling /* If bo is a KFD BO, check if the bo belongs to the current process.
1404d8d019ccSFelix Kuehling * If true, then return false as any KFD process needs all its BOs to
1405d8d019ccSFelix Kuehling * be resident to run successfully
1406d8d019ccSFelix Kuehling */
14077bc80a54SChristian König dma_resv_for_each_fence(&resv_cursor, bo->base.resv,
14080cc848a7SChristian König DMA_RESV_USAGE_BOOKKEEP, f) {
1409d8d019ccSFelix Kuehling if (amdkfd_fence_check_mm(f, current->mm))
1410d8d019ccSFelix Kuehling return false;
1411d8d019ccSFelix Kuehling }
14129982ca68SChristian König
1413b453e42aSFelix Kuehling /* Preemptible BOs don't own system resources managed by the
1414b453e42aSFelix Kuehling * driver (pages, VRAM, GART space). They point to resources
1415b453e42aSFelix Kuehling * owned by someone else (e.g. pageable memory in user mode
1416b453e42aSFelix Kuehling * or a DMABuf). They are used in a preemptible context so we
1417b453e42aSFelix Kuehling * can guarantee no deadlocks and good QoS in case of MMU
1418b453e42aSFelix Kuehling * notifiers or DMABuf move notifiers from the resource owner.
1419b453e42aSFelix Kuehling */
14206d3c900cSArunpravin Paneer Selvam if (bo->resource->mem_type == AMDGPU_PL_PREEMPT)
1421b453e42aSFelix Kuehling return false;
14226d3c900cSArunpravin Paneer Selvam
14236d3c900cSArunpravin Paneer Selvam if (bo->resource->mem_type == TTM_PL_TT &&
1424218c0b7fSChristian König amdgpu_bo_encrypted(ttm_to_amdgpu_bo(bo)))
1425218c0b7fSChristian König return false;
14269982ca68SChristian König
14279982ca68SChristian König return ttm_bo_eviction_valuable(bo, place);
14289982ca68SChristian König }
14299982ca68SChristian König
amdgpu_ttm_vram_mm_access(struct amdgpu_device * adev,loff_t pos,void * buf,size_t size,bool write)143003373e2bSKevin Wang static void amdgpu_ttm_vram_mm_access(struct amdgpu_device *adev, loff_t pos,
143103373e2bSKevin Wang void *buf, size_t size, bool write)
143203373e2bSKevin Wang {
143303373e2bSKevin Wang while (size) {
143403373e2bSKevin Wang uint64_t aligned_pos = ALIGN_DOWN(pos, 4);
143503373e2bSKevin Wang uint64_t bytes = 4 - (pos & 0x3);
143603373e2bSKevin Wang uint32_t shift = (pos & 0x3) * 8;
143703373e2bSKevin Wang uint32_t mask = 0xffffffff << shift;
143803373e2bSKevin Wang uint32_t value = 0;
143903373e2bSKevin Wang
144003373e2bSKevin Wang if (size < bytes) {
144103373e2bSKevin Wang mask &= 0xffffffff >> (bytes - size) * 8;
144203373e2bSKevin Wang bytes = size;
144303373e2bSKevin Wang }
144403373e2bSKevin Wang
144503373e2bSKevin Wang if (mask != 0xffffffff) {
144603373e2bSKevin Wang amdgpu_device_mm_access(adev, aligned_pos, &value, 4, false);
144703373e2bSKevin Wang if (write) {
144803373e2bSKevin Wang value &= ~mask;
144903373e2bSKevin Wang value |= (*(uint32_t *)buf << shift) & mask;
145003373e2bSKevin Wang amdgpu_device_mm_access(adev, aligned_pos, &value, 4, true);
145103373e2bSKevin Wang } else {
145203373e2bSKevin Wang value = (value & mask) >> shift;
145303373e2bSKevin Wang memcpy(buf, &value, bytes);
145403373e2bSKevin Wang }
145503373e2bSKevin Wang } else {
145603373e2bSKevin Wang amdgpu_device_mm_access(adev, aligned_pos, buf, 4, write);
145703373e2bSKevin Wang }
145803373e2bSKevin Wang
145903373e2bSKevin Wang pos += bytes;
146003373e2bSKevin Wang buf += bytes;
146103373e2bSKevin Wang size -= bytes;
146203373e2bSKevin Wang }
146303373e2bSKevin Wang }
146403373e2bSKevin Wang
amdgpu_ttm_access_memory_sdma(struct ttm_buffer_object * bo,unsigned long offset,void * buf,int len,int write)1465cb5cc4f5SJonathan Kim static int amdgpu_ttm_access_memory_sdma(struct ttm_buffer_object *bo,
1466f7d66fb2SChristian König unsigned long offset, void *buf,
1467f7d66fb2SChristian König int len, int write)
1468cb5cc4f5SJonathan Kim {
1469cb5cc4f5SJonathan Kim struct amdgpu_bo *abo = ttm_to_amdgpu_bo(bo);
1470cb5cc4f5SJonathan Kim struct amdgpu_device *adev = amdgpu_ttm_adev(abo->tbo.bdev);
1471590e86feSJonathan Kim struct amdgpu_res_cursor src_mm;
1472cb5cc4f5SJonathan Kim struct amdgpu_job *job;
1473cb5cc4f5SJonathan Kim struct dma_fence *fence;
1474cb5cc4f5SJonathan Kim uint64_t src_addr, dst_addr;
1475cb5cc4f5SJonathan Kim unsigned int num_dw;
1476cb5cc4f5SJonathan Kim int r, idx;
1477cb5cc4f5SJonathan Kim
1478cb5cc4f5SJonathan Kim if (len != PAGE_SIZE)
1479cb5cc4f5SJonathan Kim return -EINVAL;
1480cb5cc4f5SJonathan Kim
1481cb5cc4f5SJonathan Kim if (!adev->mman.sdma_access_ptr)
1482cb5cc4f5SJonathan Kim return -EACCES;
1483cb5cc4f5SJonathan Kim
1484590e86feSJonathan Kim if (!drm_dev_enter(adev_to_drm(adev), &idx))
1485590e86feSJonathan Kim return -ENODEV;
1486cb5cc4f5SJonathan Kim
1487cb5cc4f5SJonathan Kim if (write)
1488cb5cc4f5SJonathan Kim memcpy(adev->mman.sdma_access_ptr, buf, len);
1489cb5cc4f5SJonathan Kim
1490cb5cc4f5SJonathan Kim num_dw = ALIGN(adev->mman.buffer_funcs->copy_num_dw, 8);
149141ce6d6dSMukul Joshi r = amdgpu_job_alloc_with_ib(adev, &adev->mman.high_pr,
1492f7d66fb2SChristian König AMDGPU_FENCE_OWNER_UNDEFINED,
1493f7d66fb2SChristian König num_dw * 4, AMDGPU_IB_POOL_DELAYED,
1494f7d66fb2SChristian König &job);
1495cb5cc4f5SJonathan Kim if (r)
1496cb5cc4f5SJonathan Kim goto out;
1497cb5cc4f5SJonathan Kim
1498590e86feSJonathan Kim amdgpu_res_first(abo->tbo.resource, offset, len, &src_mm);
1499f7d66fb2SChristian König src_addr = amdgpu_ttm_domain_start(adev, bo->resource->mem_type) +
1500f7d66fb2SChristian König src_mm.start;
1501400ef298SJonathan Kim dst_addr = amdgpu_bo_gpu_offset(adev->mman.sdma_access_bo);
1502400ef298SJonathan Kim if (write)
1503400ef298SJonathan Kim swap(src_addr, dst_addr);
1504400ef298SJonathan Kim
1505f7d66fb2SChristian König amdgpu_emit_copy_buffer(adev, &job->ibs[0], src_addr, dst_addr,
1506f7d66fb2SChristian König PAGE_SIZE, false);
1507cb5cc4f5SJonathan Kim
1508cb5cc4f5SJonathan Kim amdgpu_ring_pad_ib(adev->mman.buffer_funcs_ring, &job->ibs[0]);
1509cb5cc4f5SJonathan Kim WARN_ON(job->ibs[0].length_dw > num_dw);
1510cb5cc4f5SJonathan Kim
1511f7d66fb2SChristian König fence = amdgpu_job_submit(job);
1512cb5cc4f5SJonathan Kim
1513cb5cc4f5SJonathan Kim if (!dma_fence_wait_timeout(fence, false, adev->sdma_timeout))
1514cb5cc4f5SJonathan Kim r = -ETIMEDOUT;
1515cb5cc4f5SJonathan Kim dma_fence_put(fence);
1516cb5cc4f5SJonathan Kim
1517cb5cc4f5SJonathan Kim if (!(r || write))
1518cb5cc4f5SJonathan Kim memcpy(buf, adev->mman.sdma_access_ptr, len);
1519cb5cc4f5SJonathan Kim out:
1520cb5cc4f5SJonathan Kim drm_dev_exit(idx);
1521cb5cc4f5SJonathan Kim return r;
1522cb5cc4f5SJonathan Kim }
1523cb5cc4f5SJonathan Kim
152450da5174STom St Denis /**
15252e603d04SHuang Rui * amdgpu_ttm_access_memory - Read or Write memory that backs a buffer object.
152650da5174STom St Denis *
152750da5174STom St Denis * @bo: The buffer object to read/write
152850da5174STom St Denis * @offset: Offset into buffer object
152950da5174STom St Denis * @buf: Secondary buffer to write/read from
153050da5174STom St Denis * @len: Length in bytes of access
153150da5174STom St Denis * @write: true if writing
153250da5174STom St Denis *
153350da5174STom St Denis * This is used to access VRAM that backs a buffer object via MMIO
153450da5174STom St Denis * access for debugging purposes.
153550da5174STom St Denis */
amdgpu_ttm_access_memory(struct ttm_buffer_object * bo,unsigned long offset,void * buf,int len,int write)1536e342610cSFelix Kuehling static int amdgpu_ttm_access_memory(struct ttm_buffer_object *bo,
1537498ad8ecSChristian König unsigned long offset, void *buf, int len,
1538498ad8ecSChristian König int write)
1539e342610cSFelix Kuehling {
1540b82485fdSAndres Rodriguez struct amdgpu_bo *abo = ttm_to_amdgpu_bo(bo);
1541e342610cSFelix Kuehling struct amdgpu_device *adev = amdgpu_ttm_adev(abo->tbo.bdev);
1542498ad8ecSChristian König struct amdgpu_res_cursor cursor;
1543e342610cSFelix Kuehling int ret = 0;
1544e342610cSFelix Kuehling
1545d3116756SChristian König if (bo->resource->mem_type != TTM_PL_VRAM)
1546e342610cSFelix Kuehling return -EIO;
1547e342610cSFelix Kuehling
1548400ef298SJonathan Kim if (amdgpu_device_has_timeouts_enabled(adev) &&
1549cb5cc4f5SJonathan Kim !amdgpu_ttm_access_memory_sdma(bo, offset, buf, len, write))
1550cb5cc4f5SJonathan Kim return len;
1551cb5cc4f5SJonathan Kim
1552d3116756SChristian König amdgpu_res_first(bo->resource, offset, len, &cursor);
1553498ad8ecSChristian König while (cursor.remaining) {
155403373e2bSKevin Wang size_t count, size = cursor.size;
155503373e2bSKevin Wang loff_t pos = cursor.start;
1556e342610cSFelix Kuehling
155703373e2bSKevin Wang count = amdgpu_device_aper_access(adev, pos, buf, size, write);
155803373e2bSKevin Wang size -= count;
155903373e2bSKevin Wang if (size) {
156003373e2bSKevin Wang /* using MM to access rest vram and handle un-aligned address */
156103373e2bSKevin Wang pos += count;
156203373e2bSKevin Wang buf += count;
156303373e2bSKevin Wang amdgpu_ttm_vram_mm_access(adev, pos, buf, size, write);
1564e342610cSFelix Kuehling }
1565e342610cSFelix Kuehling
156603373e2bSKevin Wang ret += cursor.size;
156703373e2bSKevin Wang buf += cursor.size;
156803373e2bSKevin Wang amdgpu_res_next(&cursor, cursor.size);
1569e342610cSFelix Kuehling }
1570e342610cSFelix Kuehling
1571e342610cSFelix Kuehling return ret;
1572e342610cSFelix Kuehling }
1573e342610cSFelix Kuehling
15746a6e5988SDave Airlie static void
amdgpu_bo_delete_mem_notify(struct ttm_buffer_object * bo)15756a6e5988SDave Airlie amdgpu_bo_delete_mem_notify(struct ttm_buffer_object *bo)
15766a6e5988SDave Airlie {
15770c7ed3edSChristian König amdgpu_bo_move_notify(bo, false, NULL);
15786a6e5988SDave Airlie }
15796a6e5988SDave Airlie
15808af8a109SChristian König static struct ttm_device_funcs amdgpu_bo_driver = {
1581d38ceaf9SAlex Deucher .ttm_tt_create = &amdgpu_ttm_tt_create,
1582d38ceaf9SAlex Deucher .ttm_tt_populate = &amdgpu_ttm_tt_populate,
1583d38ceaf9SAlex Deucher .ttm_tt_unpopulate = &amdgpu_ttm_tt_unpopulate,
15845d26eba9SDave Airlie .ttm_tt_destroy = &amdgpu_ttm_backend_destroy,
15859982ca68SChristian König .eviction_valuable = amdgpu_ttm_bo_eviction_valuable,
1586d38ceaf9SAlex Deucher .evict_flags = &amdgpu_evict_flags,
1587d38ceaf9SAlex Deucher .move = &amdgpu_bo_move,
15886a6e5988SDave Airlie .delete_mem_notify = &amdgpu_bo_delete_mem_notify,
1589ab2f7a5cSFelix Kuehling .release_notify = &amdgpu_bo_release_notify,
1590d38ceaf9SAlex Deucher .io_mem_reserve = &amdgpu_ttm_io_mem_reserve,
15919bbdcc0fSChristian König .io_mem_pfn = amdgpu_ttm_io_mem_pfn,
1592b61857b5SChunming Zhou .access_memory = &amdgpu_ttm_access_memory,
1593d38ceaf9SAlex Deucher };
1594d38ceaf9SAlex Deucher
1595f5ec697eSAlex Deucher /*
1596f5ec697eSAlex Deucher * Firmware Reservation functions
1597f5ec697eSAlex Deucher */
1598f5ec697eSAlex Deucher /**
1599f5ec697eSAlex Deucher * amdgpu_ttm_fw_reserve_vram_fini - free fw reserved vram
1600f5ec697eSAlex Deucher *
1601f5ec697eSAlex Deucher * @adev: amdgpu_device pointer
1602f5ec697eSAlex Deucher *
1603f5ec697eSAlex Deucher * free fw reserved vram if it has been reserved.
1604f5ec697eSAlex Deucher */
amdgpu_ttm_fw_reserve_vram_fini(struct amdgpu_device * adev)1605f5ec697eSAlex Deucher static void amdgpu_ttm_fw_reserve_vram_fini(struct amdgpu_device *adev)
1606f5ec697eSAlex Deucher {
160787ded5caSAlex Deucher amdgpu_bo_free_kernel(&adev->mman.fw_vram_usage_reserved_bo,
160887ded5caSAlex Deucher NULL, &adev->mman.fw_vram_usage_va);
1609f5ec697eSAlex Deucher }
1610f5ec697eSAlex Deucher
16114864f2eeSTong Liu01 /*
16124864f2eeSTong Liu01 * Driver Reservation functions
16134864f2eeSTong Liu01 */
16144864f2eeSTong Liu01 /**
16154864f2eeSTong Liu01 * amdgpu_ttm_drv_reserve_vram_fini - free drv reserved vram
16164864f2eeSTong Liu01 *
16174864f2eeSTong Liu01 * @adev: amdgpu_device pointer
16184864f2eeSTong Liu01 *
16194864f2eeSTong Liu01 * free drv reserved vram if it has been reserved.
16204864f2eeSTong Liu01 */
amdgpu_ttm_drv_reserve_vram_fini(struct amdgpu_device * adev)16214864f2eeSTong Liu01 static void amdgpu_ttm_drv_reserve_vram_fini(struct amdgpu_device *adev)
16224864f2eeSTong Liu01 {
16234864f2eeSTong Liu01 amdgpu_bo_free_kernel(&adev->mman.drv_vram_usage_reserved_bo,
16244864f2eeSTong Liu01 NULL,
16256d96ced7STong Liu01 &adev->mman.drv_vram_usage_va);
16264864f2eeSTong Liu01 }
16274864f2eeSTong Liu01
1628f5ec697eSAlex Deucher /**
1629f5ec697eSAlex Deucher * amdgpu_ttm_fw_reserve_vram_init - create bo vram reservation from fw
1630f5ec697eSAlex Deucher *
1631f5ec697eSAlex Deucher * @adev: amdgpu_device pointer
1632f5ec697eSAlex Deucher *
1633f5ec697eSAlex Deucher * create bo vram reservation from fw.
1634f5ec697eSAlex Deucher */
amdgpu_ttm_fw_reserve_vram_init(struct amdgpu_device * adev)1635f5ec697eSAlex Deucher static int amdgpu_ttm_fw_reserve_vram_init(struct amdgpu_device *adev)
1636f5ec697eSAlex Deucher {
1637de7b45baSChristian König uint64_t vram_size = adev->gmc.visible_vram_size;
1638f5ec697eSAlex Deucher
163987ded5caSAlex Deucher adev->mman.fw_vram_usage_va = NULL;
164087ded5caSAlex Deucher adev->mman.fw_vram_usage_reserved_bo = NULL;
1641f5ec697eSAlex Deucher
164287ded5caSAlex Deucher if (adev->mman.fw_vram_usage_size == 0 ||
164387ded5caSAlex Deucher adev->mman.fw_vram_usage_size > vram_size)
1644de7b45baSChristian König return 0;
1645f5ec697eSAlex Deucher
1646de7b45baSChristian König return amdgpu_bo_create_kernel_at(adev,
164787ded5caSAlex Deucher adev->mman.fw_vram_usage_start_offset,
164887ded5caSAlex Deucher adev->mman.fw_vram_usage_size,
164987ded5caSAlex Deucher &adev->mman.fw_vram_usage_reserved_bo,
165087ded5caSAlex Deucher &adev->mman.fw_vram_usage_va);
1651f5ec697eSAlex Deucher }
1652f5ec697eSAlex Deucher
16534864f2eeSTong Liu01 /**
16544864f2eeSTong Liu01 * amdgpu_ttm_drv_reserve_vram_init - create bo vram reservation from driver
16554864f2eeSTong Liu01 *
16564864f2eeSTong Liu01 * @adev: amdgpu_device pointer
16574864f2eeSTong Liu01 *
16584864f2eeSTong Liu01 * create bo vram reservation from drv.
16594864f2eeSTong Liu01 */
amdgpu_ttm_drv_reserve_vram_init(struct amdgpu_device * adev)16604864f2eeSTong Liu01 static int amdgpu_ttm_drv_reserve_vram_init(struct amdgpu_device *adev)
16614864f2eeSTong Liu01 {
16626d96ced7STong Liu01 u64 vram_size = adev->gmc.visible_vram_size;
16634864f2eeSTong Liu01
16646d96ced7STong Liu01 adev->mman.drv_vram_usage_va = NULL;
16654864f2eeSTong Liu01 adev->mman.drv_vram_usage_reserved_bo = NULL;
16664864f2eeSTong Liu01
16674864f2eeSTong Liu01 if (adev->mman.drv_vram_usage_size == 0 ||
16684864f2eeSTong Liu01 adev->mman.drv_vram_usage_size > vram_size)
16694864f2eeSTong Liu01 return 0;
16704864f2eeSTong Liu01
16714864f2eeSTong Liu01 return amdgpu_bo_create_kernel_at(adev,
16724864f2eeSTong Liu01 adev->mman.drv_vram_usage_start_offset,
16734864f2eeSTong Liu01 adev->mman.drv_vram_usage_size,
16744864f2eeSTong Liu01 &adev->mman.drv_vram_usage_reserved_bo,
16756d96ced7STong Liu01 &adev->mman.drv_vram_usage_va);
16764864f2eeSTong Liu01 }
16774864f2eeSTong Liu01
1678778e8c42STianci.Yin /*
1679778e8c42STianci.Yin * Memoy training reservation functions
1680778e8c42STianci.Yin */
1681778e8c42STianci.Yin
1682778e8c42STianci.Yin /**
1683778e8c42STianci.Yin * amdgpu_ttm_training_reserve_vram_fini - free memory training reserved vram
1684778e8c42STianci.Yin *
1685778e8c42STianci.Yin * @adev: amdgpu_device pointer
1686778e8c42STianci.Yin *
1687778e8c42STianci.Yin * free memory training reserved vram if it has been reserved.
1688778e8c42STianci.Yin */
amdgpu_ttm_training_reserve_vram_fini(struct amdgpu_device * adev)1689778e8c42STianci.Yin static int amdgpu_ttm_training_reserve_vram_fini(struct amdgpu_device *adev)
1690778e8c42STianci.Yin {
1691778e8c42STianci.Yin struct psp_memory_training_context *ctx = &adev->psp.mem_train_ctx;
1692778e8c42STianci.Yin
1693778e8c42STianci.Yin ctx->init = PSP_MEM_TRAIN_NOT_SUPPORT;
1694778e8c42STianci.Yin amdgpu_bo_free_kernel(&ctx->c2p_bo, NULL, NULL);
1695778e8c42STianci.Yin ctx->c2p_bo = NULL;
1696778e8c42STianci.Yin
1697778e8c42STianci.Yin return 0;
1698778e8c42STianci.Yin }
1699778e8c42STianci.Yin
amdgpu_ttm_training_data_block_init(struct amdgpu_device * adev,uint32_t reserve_size)1700db3b5cb6SLijo Lazar static void amdgpu_ttm_training_data_block_init(struct amdgpu_device *adev,
1701db3b5cb6SLijo Lazar uint32_t reserve_size)
17028d40002fSTianci.Yin {
1703778e8c42STianci.Yin struct psp_memory_training_context *ctx = &adev->psp.mem_train_ctx;
1704778e8c42STianci.Yin
1705778e8c42STianci.Yin memset(ctx, 0, sizeof(*ctx));
1706778e8c42STianci.Yin
170783d7f66aSLikun Gao ctx->c2p_train_data_offset =
1708db3b5cb6SLijo Lazar ALIGN((adev->gmc.mc_vram_size - reserve_size - SZ_1M), SZ_1M);
170983d7f66aSLikun Gao ctx->p2c_train_data_offset =
171083d7f66aSLikun Gao (adev->gmc.mc_vram_size - GDDR6_MEM_TRAINING_OFFSET);
171183d7f66aSLikun Gao ctx->train_data_size =
171283d7f66aSLikun Gao GDDR6_MEM_TRAINING_DATA_SIZE_IN_BYTES;
1713778e8c42STianci.Yin
1714778e8c42STianci.Yin DRM_DEBUG("train_data_size:%llx,p2c_train_data_offset:%llx,c2p_train_data_offset:%llx.\n",
1715778e8c42STianci.Yin ctx->train_data_size,
1716778e8c42STianci.Yin ctx->p2c_train_data_offset,
1717778e8c42STianci.Yin ctx->c2p_train_data_offset);
171883d7f66aSLikun Gao }
1719778e8c42STianci.Yin
172083d7f66aSLikun Gao /*
172183d7f66aSLikun Gao * reserve TMR memory at the top of VRAM which holds
172283d7f66aSLikun Gao * IP Discovery data and is protected by PSP.
172383d7f66aSLikun Gao */
amdgpu_ttm_reserve_tmr(struct amdgpu_device * adev)172483d7f66aSLikun Gao static int amdgpu_ttm_reserve_tmr(struct amdgpu_device *adev)
172583d7f66aSLikun Gao {
172683d7f66aSLikun Gao struct psp_memory_training_context *ctx = &adev->psp.mem_train_ctx;
172783d7f66aSLikun Gao bool mem_train_support = false;
1728db3b5cb6SLijo Lazar uint32_t reserve_size = 0;
1729db3b5cb6SLijo Lazar int ret;
173083d7f66aSLikun Gao
17319535a86aSShiwu Zhang if (adev->bios && !amdgpu_sriov_vf(adev)) {
173282a52030SHawking Zhang if (amdgpu_atomfirmware_mem_training_supported(adev))
173383d7f66aSLikun Gao mem_train_support = true;
173472d208c2SLikun Gao else
173583d7f66aSLikun Gao DRM_DEBUG("memory training does not support!\n");
173683d7f66aSLikun Gao }
173783d7f66aSLikun Gao
173883d7f66aSLikun Gao /*
173983d7f66aSLikun Gao * Query reserved tmr size through atom firmwareinfo for Sienna_Cichlid and onwards for all
174083d7f66aSLikun Gao * the use cases (IP discovery/G6 memory training/profiling/diagnostic data.etc)
174183d7f66aSLikun Gao *
174283d7f66aSLikun Gao * Otherwise, fallback to legacy approach to check and reserve tmr block for ip
174383d7f66aSLikun Gao * discovery data and G6 memory training data respectively
174483d7f66aSLikun Gao */
1745db3b5cb6SLijo Lazar if (adev->bios)
1746db3b5cb6SLijo Lazar reserve_size =
174783d7f66aSLikun Gao amdgpu_atomfirmware_get_fw_reserved_fb_size(adev);
17489535a86aSShiwu Zhang
17499535a86aSShiwu Zhang if (!adev->bios && adev->ip_versions[GC_HWIP][0] == IP_VERSION(9, 4, 3))
17509535a86aSShiwu Zhang reserve_size = max(reserve_size, (uint32_t)280 << 20);
17519535a86aSShiwu Zhang else if (!reserve_size)
1752db3b5cb6SLijo Lazar reserve_size = DISCOVERY_TMR_OFFSET;
17532c6e83a1SLikun Gao
175483d7f66aSLikun Gao if (mem_train_support) {
17552c6e83a1SLikun Gao /* reserve vram for mem train according to TMR location */
1756db3b5cb6SLijo Lazar amdgpu_ttm_training_data_block_init(adev, reserve_size);
1757778e8c42STianci.Yin ret = amdgpu_bo_create_kernel_at(adev,
1758778e8c42STianci.Yin ctx->c2p_train_data_offset,
1759778e8c42STianci.Yin ctx->train_data_size,
1760778e8c42STianci.Yin &ctx->c2p_bo,
1761778e8c42STianci.Yin NULL);
1762778e8c42STianci.Yin if (ret) {
1763778e8c42STianci.Yin DRM_ERROR("alloc c2p_bo failed(%d)!\n", ret);
176433a9a5abSTianci.Yin amdgpu_ttm_training_reserve_vram_fini(adev);
176533a9a5abSTianci.Yin return ret;
1766778e8c42STianci.Yin }
1767778e8c42STianci.Yin ctx->init = PSP_MEM_TRAIN_RESERVE_SUCCESS;
176883d7f66aSLikun Gao }
1769778e8c42STianci.Yin
1770228ce176SRajneesh Bhardwaj if (!adev->gmc.is_app_apu) {
1771db3b5cb6SLijo Lazar ret = amdgpu_bo_create_kernel_at(
1772db3b5cb6SLijo Lazar adev, adev->gmc.real_vram_size - reserve_size,
1773db3b5cb6SLijo Lazar reserve_size, &adev->mman.fw_reserved_memory, NULL);
177483d7f66aSLikun Gao if (ret) {
177583d7f66aSLikun Gao DRM_ERROR("alloc tmr failed(%d)!\n", ret);
1776db3b5cb6SLijo Lazar amdgpu_bo_free_kernel(&adev->mman.fw_reserved_memory,
1777db3b5cb6SLijo Lazar NULL, NULL);
177883d7f66aSLikun Gao return ret;
177983d7f66aSLikun Gao }
1780228ce176SRajneesh Bhardwaj } else {
1781228ce176SRajneesh Bhardwaj DRM_DEBUG_DRIVER("backdoor fw loading path for PSP TMR, no reservation needed\n");
1782228ce176SRajneesh Bhardwaj }
178383d7f66aSLikun Gao
1784778e8c42STianci.Yin return 0;
1785778e8c42STianci.Yin }
1786778e8c42STianci.Yin
amdgpu_ttm_pools_init(struct amdgpu_device * adev)17871e03322cSPhilip Yang static int amdgpu_ttm_pools_init(struct amdgpu_device *adev)
17881e03322cSPhilip Yang {
17891e03322cSPhilip Yang int i;
17901e03322cSPhilip Yang
17911e03322cSPhilip Yang if (!adev->gmc.is_app_apu || !adev->gmc.num_mem_partitions)
17921e03322cSPhilip Yang return 0;
17931e03322cSPhilip Yang
17941e03322cSPhilip Yang adev->mman.ttm_pools = kcalloc(adev->gmc.num_mem_partitions,
17951e03322cSPhilip Yang sizeof(*adev->mman.ttm_pools),
17961e03322cSPhilip Yang GFP_KERNEL);
17971e03322cSPhilip Yang if (!adev->mman.ttm_pools)
17981e03322cSPhilip Yang return -ENOMEM;
17991e03322cSPhilip Yang
18001e03322cSPhilip Yang for (i = 0; i < adev->gmc.num_mem_partitions; i++) {
18011e03322cSPhilip Yang ttm_pool_init(&adev->mman.ttm_pools[i], adev->dev,
18021e03322cSPhilip Yang adev->gmc.mem_partitions[i].numa.node,
18031e03322cSPhilip Yang false, false);
18041e03322cSPhilip Yang }
18051e03322cSPhilip Yang return 0;
18061e03322cSPhilip Yang }
18071e03322cSPhilip Yang
amdgpu_ttm_pools_fini(struct amdgpu_device * adev)18081e03322cSPhilip Yang static void amdgpu_ttm_pools_fini(struct amdgpu_device *adev)
18091e03322cSPhilip Yang {
18101e03322cSPhilip Yang int i;
18111e03322cSPhilip Yang
18121e03322cSPhilip Yang if (!adev->gmc.is_app_apu || !adev->mman.ttm_pools)
18131e03322cSPhilip Yang return;
18141e03322cSPhilip Yang
18151e03322cSPhilip Yang for (i = 0; i < adev->gmc.num_mem_partitions; i++)
18161e03322cSPhilip Yang ttm_pool_fini(&adev->mman.ttm_pools[i]);
18171e03322cSPhilip Yang
18181e03322cSPhilip Yang kfree(adev->mman.ttm_pools);
18191e03322cSPhilip Yang adev->mman.ttm_pools = NULL;
18201e03322cSPhilip Yang }
18211e03322cSPhilip Yang
182275501872SLee Jones /*
18232e603d04SHuang Rui * amdgpu_ttm_init - Init the memory management (ttm) as well as various
18242e603d04SHuang Rui * gtt/vram related fields.
182550da5174STom St Denis *
182650da5174STom St Denis * This initializes all of the memory space pools that the TTM layer
182750da5174STom St Denis * will need such as the GTT space (system memory mapped to the device),
182850da5174STom St Denis * VRAM (on-board memory), and on-chip memories (GDS, GWS, OA) which
182950da5174STom St Denis * can be mapped per VMID.
183050da5174STom St Denis */
amdgpu_ttm_init(struct amdgpu_device * adev)1831d38ceaf9SAlex Deucher int amdgpu_ttm_init(struct amdgpu_device *adev)
1832d38ceaf9SAlex Deucher {
183336d38372SChristian König uint64_t gtt_size;
1834d38ceaf9SAlex Deucher int r;
1835d38ceaf9SAlex Deucher
1836a64f784bSChristian König mutex_init(&adev->mman.gtt_window_lock);
1837a64f784bSChristian König
1838b9e52a96SPrike Liang dma_set_max_seg_size(adev->dev, UINT_MAX);
1839d38ceaf9SAlex Deucher /* No others user of address space so set it to 0 */
18408af8a109SChristian König r = ttm_device_init(&adev->mman.bdev, &amdgpu_bo_driver, adev->dev,
18414a580877SLuben Tuikov adev_to_drm(adev)->anon_inode->i_mapping,
18424a580877SLuben Tuikov adev_to_drm(adev)->vma_offset_manager,
1843ee5d2a8eSChristian König adev->need_swiotlb,
184490489ce1SChristoph Hellwig dma_addressing_limited(adev->dev));
1845d38ceaf9SAlex Deucher if (r) {
1846d38ceaf9SAlex Deucher DRM_ERROR("failed initializing buffer object driver(%d).\n", r);
1847d38ceaf9SAlex Deucher return r;
1848d38ceaf9SAlex Deucher }
18491e03322cSPhilip Yang
18501e03322cSPhilip Yang r = amdgpu_ttm_pools_init(adev);
18511e03322cSPhilip Yang if (r) {
18521e03322cSPhilip Yang DRM_ERROR("failed to init ttm pools(%d).\n", r);
18531e03322cSPhilip Yang return r;
18541e03322cSPhilip Yang }
1855d38ceaf9SAlex Deucher adev->mman.initialized = true;
18567cce9584SAndrey Grodzovsky
185750da5174STom St Denis /* Initialize VRAM pool with all of VRAM divided into pages */
1858158d20d1SDave Airlie r = amdgpu_vram_mgr_init(adev);
1859d38ceaf9SAlex Deucher if (r) {
1860d38ceaf9SAlex Deucher DRM_ERROR("Failed initializing VRAM heap.\n");
1861d38ceaf9SAlex Deucher return r;
1862d38ceaf9SAlex Deucher }
1863218b5dcdSJohn Brooks
1864d38ceaf9SAlex Deucher /* Change the size here instead of the init above so only lpfn is affected */
186557adc4ceSChristian König amdgpu_ttm_set_buffer_funcs_status(adev, false);
1866f8f4b9a6SAmber Lin #ifdef CONFIG_64BIT
1867f1008370SOak Zeng #ifdef CONFIG_X86
18689d0af8b4SOak Zeng if (adev->gmc.xgmi.connected_to_cpu)
18699d0af8b4SOak Zeng adev->mman.aper_base_kaddr = ioremap_cache(adev->gmc.aper_base,
18709d0af8b4SOak Zeng adev->gmc.visible_vram_size);
18719d0af8b4SOak Zeng
1872a0ba1279SLijo Lazar else if (adev->gmc.is_app_apu)
1873a0ba1279SLijo Lazar DRM_DEBUG_DRIVER(
1874a0ba1279SLijo Lazar "No need to ioremap when real vram size is 0\n");
1875a0ba1279SLijo Lazar else
1876f1008370SOak Zeng #endif
1877f8f4b9a6SAmber Lin adev->mman.aper_base_kaddr = ioremap_wc(adev->gmc.aper_base,
1878f8f4b9a6SAmber Lin adev->gmc.visible_vram_size);
1879f8f4b9a6SAmber Lin #endif
1880d38ceaf9SAlex Deucher
1881a05502e5SHorace Chen /*
1882a05502e5SHorace Chen *The reserved vram for firmware must be pinned to the specified
1883a05502e5SHorace Chen *place on the VRAM, so reserve it early.
1884a05502e5SHorace Chen */
1885f5ec697eSAlex Deucher r = amdgpu_ttm_fw_reserve_vram_init(adev);
188601c3f464SSrinivasan Shanmugam if (r)
1887a05502e5SHorace Chen return r;
1888a05502e5SHorace Chen
1889778e8c42STianci.Yin /*
18904864f2eeSTong Liu01 *The reserved vram for driver must be pinned to the specified
18914864f2eeSTong Liu01 *place on the VRAM, so reserve it early.
18924864f2eeSTong Liu01 */
18934864f2eeSTong Liu01 r = amdgpu_ttm_drv_reserve_vram_init(adev);
18944864f2eeSTong Liu01 if (r)
18954864f2eeSTong Liu01 return r;
18964864f2eeSTong Liu01
18974864f2eeSTong Liu01 /*
189883d7f66aSLikun Gao * only NAVI10 and onwards ASIC support for IP discovery.
189983d7f66aSLikun Gao * If IP discovery enabled, a block of memory should be
190083d7f66aSLikun Gao * reserved for IP discovey.
1901778e8c42STianci.Yin */
190272de33f8SAlex Deucher if (adev->mman.discovery_bin) {
190383d7f66aSLikun Gao r = amdgpu_ttm_reserve_tmr(adev);
1904778e8c42STianci.Yin if (r)
1905778e8c42STianci.Yin return r;
1906e862b08bSMonk Liu }
1907778e8c42STianci.Yin
190850da5174STom St Denis /* allocate memory as required for VGA
190950da5174STom St Denis * This is used for VGA emulation and pre-OS scanout buffers to
191050da5174STom St Denis * avoid display artifacts while transitioning between pre-OS
191101c3f464SSrinivasan Shanmugam * and driver.
191201c3f464SSrinivasan Shanmugam */
1913228ce176SRajneesh Bhardwaj if (!adev->gmc.is_app_apu) {
1914228ce176SRajneesh Bhardwaj r = amdgpu_bo_create_kernel_at(adev, 0,
1915228ce176SRajneesh Bhardwaj adev->mman.stolen_vga_size,
1916cacbbe7cSAlex Deucher &adev->mman.stolen_vga_memory,
191714b18937SAlex Deucher NULL);
1918d38ceaf9SAlex Deucher if (r)
1919d38ceaf9SAlex Deucher return r;
1920228ce176SRajneesh Bhardwaj
1921cacbbe7cSAlex Deucher r = amdgpu_bo_create_kernel_at(adev, adev->mman.stolen_vga_size,
1922cacbbe7cSAlex Deucher adev->mman.stolen_extended_size,
1923cacbbe7cSAlex Deucher &adev->mman.stolen_extended_memory,
192414b18937SAlex Deucher NULL);
1925228ce176SRajneesh Bhardwaj
1926d38ceaf9SAlex Deucher if (r)
1927d38ceaf9SAlex Deucher return r;
1928228ce176SRajneesh Bhardwaj
1929228ce176SRajneesh Bhardwaj r = amdgpu_bo_create_kernel_at(adev,
1930228ce176SRajneesh Bhardwaj adev->mman.stolen_reserved_offset,
1931e15a5fb9SHuang Rui adev->mman.stolen_reserved_size,
1932e15a5fb9SHuang Rui &adev->mman.stolen_reserved_memory,
1933e15a5fb9SHuang Rui NULL);
1934e15a5fb9SHuang Rui if (r)
1935e15a5fb9SHuang Rui return r;
1936228ce176SRajneesh Bhardwaj } else {
1937228ce176SRajneesh Bhardwaj DRM_DEBUG_DRIVER("Skipped stolen memory reservation\n");
1938228ce176SRajneesh Bhardwaj }
19395f6a556fSXiaojie Yuan
1940d38ceaf9SAlex Deucher DRM_INFO("amdgpu: %uM of VRAM memory ready\n",
194101c3f464SSrinivasan Shanmugam (unsigned int)(adev->gmc.real_vram_size / (1024 * 1024)));
194236d38372SChristian König
1943f1f6f48aSMukul Joshi /* Compute GTT size, either based on TTM limit
1944f1f6f48aSMukul Joshi * or whatever the user passed on module init.
1945f7ba887fSAlex Deucher */
1946f1f6f48aSMukul Joshi if (amdgpu_gtt_size == -1)
1947f1f6f48aSMukul Joshi gtt_size = ttm_tt_pages_limit() << PAGE_SHIFT;
1948f1f6f48aSMukul Joshi else
194936d38372SChristian König gtt_size = (uint64_t)amdgpu_gtt_size << 20;
195050da5174STom St Denis
195150da5174STom St Denis /* Initialize GTT memory pool */
1952158d20d1SDave Airlie r = amdgpu_gtt_mgr_init(adev, gtt_size);
1953d38ceaf9SAlex Deucher if (r) {
1954d38ceaf9SAlex Deucher DRM_ERROR("Failed initializing GTT heap.\n");
1955d38ceaf9SAlex Deucher return r;
1956d38ceaf9SAlex Deucher }
1957d38ceaf9SAlex Deucher DRM_INFO("amdgpu: %uM of GTT memory ready.\n",
195801c3f464SSrinivasan Shanmugam (unsigned int)(gtt_size / (1024 * 1024)));
1959d38ceaf9SAlex Deucher
1960792b84fbSShashank Sharma /* Initiailize doorbell pool on PCI BAR */
1961792b84fbSShashank Sharma r = amdgpu_ttm_init_on_chip(adev, AMDGPU_PL_DOORBELL, adev->doorbell.size / PAGE_SIZE);
1962792b84fbSShashank Sharma if (r) {
1963792b84fbSShashank Sharma DRM_ERROR("Failed initializing doorbell heap.\n");
1964792b84fbSShashank Sharma return r;
1965792b84fbSShashank Sharma }
1966792b84fbSShashank Sharma
196754c30d2aSShashank Sharma /* Create a boorbell page for kernel usages */
196854c30d2aSShashank Sharma r = amdgpu_doorbell_create_kernel_doorbells(adev);
196954c30d2aSShashank Sharma if (r) {
197054c30d2aSShashank Sharma DRM_ERROR("Failed to initialize kernel doorbells.\n");
197154c30d2aSShashank Sharma return r;
197254c30d2aSShashank Sharma }
197354c30d2aSShashank Sharma
1974b453e42aSFelix Kuehling /* Initialize preemptible memory pool */
1975b453e42aSFelix Kuehling r = amdgpu_preempt_mgr_init(adev);
1976b453e42aSFelix Kuehling if (r) {
1977b453e42aSFelix Kuehling DRM_ERROR("Failed initializing PREEMPT heap.\n");
1978b453e42aSFelix Kuehling return r;
1979b453e42aSFelix Kuehling }
1980b453e42aSFelix Kuehling
198150da5174STom St Denis /* Initialize various on-chip memory pools */
198247363354SChristian König r = amdgpu_ttm_init_on_chip(adev, AMDGPU_PL_GDS, adev->gds.gds_size);
1983d38ceaf9SAlex Deucher if (r) {
1984d38ceaf9SAlex Deucher DRM_ERROR("Failed initializing GDS heap.\n");
1985d38ceaf9SAlex Deucher return r;
1986d38ceaf9SAlex Deucher }
1987d38ceaf9SAlex Deucher
198847363354SChristian König r = amdgpu_ttm_init_on_chip(adev, AMDGPU_PL_GWS, adev->gds.gws_size);
1989d38ceaf9SAlex Deucher if (r) {
1990d38ceaf9SAlex Deucher DRM_ERROR("Failed initializing gws heap.\n");
1991d38ceaf9SAlex Deucher return r;
1992d38ceaf9SAlex Deucher }
1993d38ceaf9SAlex Deucher
199447363354SChristian König r = amdgpu_ttm_init_on_chip(adev, AMDGPU_PL_OA, adev->gds.oa_size);
1995d38ceaf9SAlex Deucher if (r) {
1996d38ceaf9SAlex Deucher DRM_ERROR("Failed initializing oa heap.\n");
1997d38ceaf9SAlex Deucher return r;
1998d38ceaf9SAlex Deucher }
1999cb5cc4f5SJonathan Kim if (amdgpu_bo_create_kernel(adev, PAGE_SIZE, PAGE_SIZE,
2000cb5cc4f5SJonathan Kim AMDGPU_GEM_DOMAIN_GTT,
2001cb5cc4f5SJonathan Kim &adev->mman.sdma_access_bo, NULL,
2002590e86feSJonathan Kim &adev->mman.sdma_access_ptr))
2003cb5cc4f5SJonathan Kim DRM_WARN("Debug VRAM access will use slowpath MM access\n");
2004cb5cc4f5SJonathan Kim
2005d38ceaf9SAlex Deucher return 0;
2006d38ceaf9SAlex Deucher }
2007d38ceaf9SAlex Deucher
200875501872SLee Jones /*
200950da5174STom St Denis * amdgpu_ttm_fini - De-initialize the TTM memory pools
201050da5174STom St Denis */
amdgpu_ttm_fini(struct amdgpu_device * adev)2011d38ceaf9SAlex Deucher void amdgpu_ttm_fini(struct amdgpu_device *adev)
2012d38ceaf9SAlex Deucher {
201362d5f9f7SLeslie Shi int idx;
201401c3f464SSrinivasan Shanmugam
2015d38ceaf9SAlex Deucher if (!adev->mman.initialized)
2016d38ceaf9SAlex Deucher return;
201711c6b82aSMonk Liu
20181e03322cSPhilip Yang amdgpu_ttm_pools_fini(adev);
20191e03322cSPhilip Yang
2020778e8c42STianci.Yin amdgpu_ttm_training_reserve_vram_fini(adev);
20215db62dc8SAlex Deucher /* return the stolen vga memory back to VRAM */
2022228ce176SRajneesh Bhardwaj if (!adev->gmc.is_app_apu) {
2023cacbbe7cSAlex Deucher amdgpu_bo_free_kernel(&adev->mman.stolen_vga_memory, NULL, NULL);
20245f6fab24SAlex Deucher amdgpu_bo_free_kernel(&adev->mman.stolen_extended_memory, NULL, NULL);
2025db3b5cb6SLijo Lazar /* return the FW reserved memory back to VRAM */
2026db3b5cb6SLijo Lazar amdgpu_bo_free_kernel(&adev->mman.fw_reserved_memory, NULL,
2027db3b5cb6SLijo Lazar NULL);
2028e15a5fb9SHuang Rui if (adev->mman.stolen_reserved_size)
2029e15a5fb9SHuang Rui amdgpu_bo_free_kernel(&adev->mman.stolen_reserved_memory,
2030e15a5fb9SHuang Rui NULL, NULL);
2031228ce176SRajneesh Bhardwaj }
2032590e86feSJonathan Kim amdgpu_bo_free_kernel(&adev->mman.sdma_access_bo, NULL,
2033590e86feSJonathan Kim &adev->mman.sdma_access_ptr);
2034f5ec697eSAlex Deucher amdgpu_ttm_fw_reserve_vram_fini(adev);
20354864f2eeSTong Liu01 amdgpu_ttm_drv_reserve_vram_fini(adev);
2036224f82e5SEmily Deng
203762d5f9f7SLeslie Shi if (drm_dev_enter(adev_to_drm(adev), &idx)) {
203862d5f9f7SLeslie Shi
203962d5f9f7SLeslie Shi if (adev->mman.aper_base_kaddr)
204062d5f9f7SLeslie Shi iounmap(adev->mman.aper_base_kaddr);
204162d5f9f7SLeslie Shi adev->mman.aper_base_kaddr = NULL;
204262d5f9f7SLeslie Shi
204362d5f9f7SLeslie Shi drm_dev_exit(idx);
204462d5f9f7SLeslie Shi }
204562d5f9f7SLeslie Shi
20466fe1c543SDave Airlie amdgpu_vram_mgr_fini(adev);
20476fe1c543SDave Airlie amdgpu_gtt_mgr_fini(adev);
2048b453e42aSFelix Kuehling amdgpu_preempt_mgr_fini(adev);
204937205891SDave Airlie ttm_range_man_fini(&adev->mman.bdev, AMDGPU_PL_GDS);
205037205891SDave Airlie ttm_range_man_fini(&adev->mman.bdev, AMDGPU_PL_GWS);
205137205891SDave Airlie ttm_range_man_fini(&adev->mman.bdev, AMDGPU_PL_OA);
2052*c9d24e47SJiang Liu ttm_range_man_fini(&adev->mman.bdev, AMDGPU_PL_DOORBELL);
20538af8a109SChristian König ttm_device_fini(&adev->mman.bdev);
2054d38ceaf9SAlex Deucher adev->mman.initialized = false;
2055d38ceaf9SAlex Deucher DRM_INFO("amdgpu: ttm finalized\n");
2056d38ceaf9SAlex Deucher }
2057d38ceaf9SAlex Deucher
205857adc4ceSChristian König /**
205957adc4ceSChristian König * amdgpu_ttm_set_buffer_funcs_status - enable/disable use of buffer functions
206057adc4ceSChristian König *
206157adc4ceSChristian König * @adev: amdgpu_device pointer
206257adc4ceSChristian König * @enable: true when we can use buffer functions.
206357adc4ceSChristian König *
206457adc4ceSChristian König * Enable/disable use of buffer functions during suspend/resume. This should
206557adc4ceSChristian König * only be called at bootup or when userspace isn't running.
206657adc4ceSChristian König */
amdgpu_ttm_set_buffer_funcs_status(struct amdgpu_device * adev,bool enable)206757adc4ceSChristian König void amdgpu_ttm_set_buffer_funcs_status(struct amdgpu_device *adev, bool enable)
2068d38ceaf9SAlex Deucher {
20699de59bc2SDave Airlie struct ttm_resource_manager *man = ttm_manager_type(&adev->mman.bdev, TTM_PL_VRAM);
207057adc4ceSChristian König uint64_t size;
2071b7d85e1dSChristian König int r;
2072d38ceaf9SAlex Deucher
207353b3f8f4SDennis Li if (!adev->mman.initialized || amdgpu_in_reset(adev) ||
2074228ce176SRajneesh Bhardwaj adev->mman.buffer_funcs_enabled == enable || adev->gmc.is_app_apu)
2075d38ceaf9SAlex Deucher return;
2076d38ceaf9SAlex Deucher
2077b7d85e1dSChristian König if (enable) {
2078b7d85e1dSChristian König struct amdgpu_ring *ring;
2079b3ac1766SNirmoy Das struct drm_gpu_scheduler *sched;
2080b7d85e1dSChristian König
2081b7d85e1dSChristian König ring = adev->mman.buffer_funcs_ring;
2082b3ac1766SNirmoy Das sched = &ring->sched;
208341ce6d6dSMukul Joshi r = drm_sched_entity_init(&adev->mman.high_pr,
2084b3ac1766SNirmoy Das DRM_SCHED_PRIORITY_KERNEL, &sched,
2085b3ac1766SNirmoy Das 1, NULL);
2086b7d85e1dSChristian König if (r) {
2087b7d85e1dSChristian König DRM_ERROR("Failed setting up TTM BO move entity (%d)\n",
2088b7d85e1dSChristian König r);
2089b7d85e1dSChristian König return;
2090b7d85e1dSChristian König }
2091c3aaca43SMukul Joshi
209241ce6d6dSMukul Joshi r = drm_sched_entity_init(&adev->mman.low_pr,
2093c3aaca43SMukul Joshi DRM_SCHED_PRIORITY_NORMAL, &sched,
2094c3aaca43SMukul Joshi 1, NULL);
2095c3aaca43SMukul Joshi if (r) {
2096c3aaca43SMukul Joshi DRM_ERROR("Failed setting up TTM BO move entity (%d)\n",
2097c3aaca43SMukul Joshi r);
2098c3aaca43SMukul Joshi goto error_free_entity;
2099c3aaca43SMukul Joshi }
2100b7d85e1dSChristian König } else {
210141ce6d6dSMukul Joshi drm_sched_entity_destroy(&adev->mman.high_pr);
210241ce6d6dSMukul Joshi drm_sched_entity_destroy(&adev->mman.low_pr);
21037766484bSAndrey Grodzovsky dma_fence_put(man->move);
21047766484bSAndrey Grodzovsky man->move = NULL;
2105b7d85e1dSChristian König }
2106b7d85e1dSChristian König
2107d38ceaf9SAlex Deucher /* this just adjusts TTM size idea, which sets lpfn to the correct value */
210857adc4ceSChristian König if (enable)
210957adc4ceSChristian König size = adev->gmc.real_vram_size;
211057adc4ceSChristian König else
211157adc4ceSChristian König size = adev->gmc.visible_vram_size;
21127db47b83SChristian König man->size = size;
211381988f9cSChristian König adev->mman.buffer_funcs_enabled = enable;
2114c3aaca43SMukul Joshi
2115c3aaca43SMukul Joshi return;
2116c3aaca43SMukul Joshi
2117c3aaca43SMukul Joshi error_free_entity:
211841ce6d6dSMukul Joshi drm_sched_entity_destroy(&adev->mman.high_pr);
2119d38ceaf9SAlex Deucher }
2120d38ceaf9SAlex Deucher
amdgpu_ttm_prepare_job(struct amdgpu_device * adev,bool direct_submit,unsigned int num_dw,struct dma_resv * resv,bool vm_needs_flush,struct amdgpu_job ** job,bool delayed)212122f7cc75SChristian König static int amdgpu_ttm_prepare_job(struct amdgpu_device *adev,
212222f7cc75SChristian König bool direct_submit,
212322f7cc75SChristian König unsigned int num_dw,
212422f7cc75SChristian König struct dma_resv *resv,
212522f7cc75SChristian König bool vm_needs_flush,
2126c3aaca43SMukul Joshi struct amdgpu_job **job,
2127c3aaca43SMukul Joshi bool delayed)
212822f7cc75SChristian König {
212922f7cc75SChristian König enum amdgpu_ib_pool_type pool = direct_submit ?
213022f7cc75SChristian König AMDGPU_IB_POOL_DIRECT :
213122f7cc75SChristian König AMDGPU_IB_POOL_DELAYED;
213222f7cc75SChristian König int r;
213341ce6d6dSMukul Joshi struct drm_sched_entity *entity = delayed ? &adev->mman.low_pr :
213441ce6d6dSMukul Joshi &adev->mman.high_pr;
2135c3aaca43SMukul Joshi r = amdgpu_job_alloc_with_ib(adev, entity,
2136f7d66fb2SChristian König AMDGPU_FENCE_OWNER_UNDEFINED,
2137f7d66fb2SChristian König num_dw * 4, pool, job);
213822f7cc75SChristian König if (r)
213922f7cc75SChristian König return r;
214022f7cc75SChristian König
214122f7cc75SChristian König if (vm_needs_flush) {
214222f7cc75SChristian König (*job)->vm_pd_addr = amdgpu_gmc_pd_addr(adev->gmc.pdb0_bo ?
214322f7cc75SChristian König adev->gmc.pdb0_bo :
214422f7cc75SChristian König adev->gart.bo);
214522f7cc75SChristian König (*job)->vm_needs_flush = true;
214622f7cc75SChristian König }
21474f91790bSChristian König if (!resv)
214822f7cc75SChristian König return 0;
21494f91790bSChristian König
21504f91790bSChristian König return drm_sched_job_add_resv_dependencies(&(*job)->base, resv,
21514f91790bSChristian König DMA_RESV_USAGE_BOOKKEEP);
215222f7cc75SChristian König }
215322f7cc75SChristian König
amdgpu_copy_buffer(struct amdgpu_ring * ring,uint64_t src_offset,uint64_t dst_offset,uint32_t byte_count,struct dma_resv * resv,struct dma_fence ** fence,bool direct_submit,bool vm_needs_flush,bool tmz)2154fc9c8f54SChristian König int amdgpu_copy_buffer(struct amdgpu_ring *ring, uint64_t src_offset,
2155fc9c8f54SChristian König uint64_t dst_offset, uint32_t byte_count,
215652791eeeSChristian König struct dma_resv *resv,
2157fc9c8f54SChristian König struct dma_fence **fence, bool direct_submit,
2158c9dc9cfeSAaron Liu bool vm_needs_flush, bool tmz)
2159d38ceaf9SAlex Deucher {
2160d38ceaf9SAlex Deucher struct amdgpu_device *adev = ring->adev;
216101c3f464SSrinivasan Shanmugam unsigned int num_loops, num_dw;
216222f7cc75SChristian König struct amdgpu_job *job;
216322f7cc75SChristian König uint32_t max_bytes;
216401c3f464SSrinivasan Shanmugam unsigned int i;
2165d38ceaf9SAlex Deucher int r;
2166d38ceaf9SAlex Deucher
2167fcd6b0e2SChristian König if (!direct_submit && !ring->sched.ready) {
216881988f9cSChristian König DRM_ERROR("Trying to move memory with ring turned off.\n");
216981988f9cSChristian König return -EINVAL;
217081988f9cSChristian König }
217181988f9cSChristian König
2172d38ceaf9SAlex Deucher max_bytes = adev->mman.buffer_funcs->copy_max_bytes;
2173d38ceaf9SAlex Deucher num_loops = DIV_ROUND_UP(byte_count, max_bytes);
21744e930d96SLuben Tuikov num_dw = ALIGN(num_loops * adev->mman.buffer_funcs->copy_num_dw, 8);
217522f7cc75SChristian König r = amdgpu_ttm_prepare_job(adev, direct_submit, num_dw,
2176c3aaca43SMukul Joshi resv, vm_needs_flush, &job, false);
2177d71518b5SChristian König if (r)
21789066b0c3SChunming Zhou return r;
2179c7ae72c0SChunming Zhou
2180d38ceaf9SAlex Deucher for (i = 0; i < num_loops; i++) {
2181d38ceaf9SAlex Deucher uint32_t cur_size_in_bytes = min(byte_count, max_bytes);
2182d38ceaf9SAlex Deucher
2183d71518b5SChristian König amdgpu_emit_copy_buffer(adev, &job->ibs[0], src_offset,
2184c9dc9cfeSAaron Liu dst_offset, cur_size_in_bytes, tmz);
2185d38ceaf9SAlex Deucher
2186d38ceaf9SAlex Deucher src_offset += cur_size_in_bytes;
2187d38ceaf9SAlex Deucher dst_offset += cur_size_in_bytes;
2188d38ceaf9SAlex Deucher byte_count -= cur_size_in_bytes;
2189d38ceaf9SAlex Deucher }
2190d38ceaf9SAlex Deucher
2191d71518b5SChristian König amdgpu_ring_pad_ib(ring, &job->ibs[0]);
2192d71518b5SChristian König WARN_ON(job->ibs[0].length_dw > num_dw);
2193ee913fd9SChristian König if (direct_submit)
2194ee913fd9SChristian König r = amdgpu_job_submit_direct(job, ring, fence);
2195ee913fd9SChristian König else
2196f7d66fb2SChristian König *fence = amdgpu_job_submit(job);
2197c7ae72c0SChunming Zhou if (r)
2198c7ae72c0SChunming Zhou goto error_free;
2199c7ae72c0SChunming Zhou
2200e24db985SChunming Zhou return r;
2201d71518b5SChristian König
2202c7ae72c0SChunming Zhou error_free:
2203d71518b5SChristian König amdgpu_job_free(job);
2204ee913fd9SChristian König DRM_ERROR("Error scheduling IBs (%d)\n", r);
2205c7ae72c0SChunming Zhou return r;
2206d38ceaf9SAlex Deucher }
2207d38ceaf9SAlex Deucher
amdgpu_ttm_fill_mem(struct amdgpu_ring * ring,uint32_t src_data,uint64_t dst_addr,uint32_t byte_count,struct dma_resv * resv,struct dma_fence ** fence,bool vm_needs_flush,bool delayed)220822f7cc75SChristian König static int amdgpu_ttm_fill_mem(struct amdgpu_ring *ring, uint32_t src_data,
220922f7cc75SChristian König uint64_t dst_addr, uint32_t byte_count,
221052791eeeSChristian König struct dma_resv *resv,
221122f7cc75SChristian König struct dma_fence **fence,
2212c3aaca43SMukul Joshi bool vm_needs_flush, bool delayed)
221359b4a977SFlora Cui {
221422f7cc75SChristian König struct amdgpu_device *adev = ring->adev;
221559b4a977SFlora Cui unsigned int num_loops, num_dw;
2216f29224a6SChristian König struct amdgpu_job *job;
221722f7cc75SChristian König uint32_t max_bytes;
221822f7cc75SChristian König unsigned int i;
221959b4a977SFlora Cui int r;
222059b4a977SFlora Cui
222122f7cc75SChristian König max_bytes = adev->mman.buffer_funcs->fill_max_bytes;
222222f7cc75SChristian König num_loops = DIV_ROUND_UP_ULL(byte_count, max_bytes);
222322f7cc75SChristian König num_dw = ALIGN(num_loops * adev->mman.buffer_funcs->fill_num_dw, 8);
222422f7cc75SChristian König r = amdgpu_ttm_prepare_job(adev, false, num_dw, resv, vm_needs_flush,
2225c3aaca43SMukul Joshi &job, delayed);
222659b4a977SFlora Cui if (r)
222759b4a977SFlora Cui return r;
222859b4a977SFlora Cui
222922f7cc75SChristian König for (i = 0; i < num_loops; i++) {
223022f7cc75SChristian König uint32_t cur_size = min(byte_count, max_bytes);
223159b4a977SFlora Cui
2232596ee296SChristian König amdgpu_emit_fill_buffer(adev, &job->ibs[0], src_data, dst_addr,
2233596ee296SChristian König cur_size);
2234f29224a6SChristian König
223522f7cc75SChristian König dst_addr += cur_size;
223622f7cc75SChristian König byte_count -= cur_size;
2237f29224a6SChristian König }
2238f29224a6SChristian König
223959b4a977SFlora Cui amdgpu_ring_pad_ib(ring, &job->ibs[0]);
224059b4a977SFlora Cui WARN_ON(job->ibs[0].length_dw > num_dw);
2241f7d66fb2SChristian König *fence = amdgpu_job_submit(job);
224259b4a977SFlora Cui return 0;
224359b4a977SFlora Cui }
224459b4a977SFlora Cui
amdgpu_fill_buffer(struct amdgpu_bo * bo,uint32_t src_data,struct dma_resv * resv,struct dma_fence ** f,bool delayed)224522f7cc75SChristian König int amdgpu_fill_buffer(struct amdgpu_bo *bo,
224622f7cc75SChristian König uint32_t src_data,
224722f7cc75SChristian König struct dma_resv *resv,
2248c3aaca43SMukul Joshi struct dma_fence **f,
2249c3aaca43SMukul Joshi bool delayed)
225022f7cc75SChristian König {
225122f7cc75SChristian König struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev);
225222f7cc75SChristian König struct amdgpu_ring *ring = adev->mman.buffer_funcs_ring;
225322f7cc75SChristian König struct dma_fence *fence = NULL;
225422f7cc75SChristian König struct amdgpu_res_cursor dst;
225522f7cc75SChristian König int r;
225622f7cc75SChristian König
225722f7cc75SChristian König if (!adev->mman.buffer_funcs_enabled) {
225822f7cc75SChristian König DRM_ERROR("Trying to clear memory with ring turned off.\n");
225922f7cc75SChristian König return -EINVAL;
226022f7cc75SChristian König }
226122f7cc75SChristian König
226222f7cc75SChristian König amdgpu_res_first(bo->tbo.resource, 0, amdgpu_bo_size(bo), &dst);
226322f7cc75SChristian König
226422f7cc75SChristian König mutex_lock(&adev->mman.gtt_window_lock);
226522f7cc75SChristian König while (dst.remaining) {
226622f7cc75SChristian König struct dma_fence *next;
226722f7cc75SChristian König uint64_t cur_size, to;
226822f7cc75SChristian König
226922f7cc75SChristian König /* Never fill more than 256MiB at once to avoid timeouts */
227022f7cc75SChristian König cur_size = min(dst.size, 256ULL << 20);
227122f7cc75SChristian König
227222f7cc75SChristian König r = amdgpu_ttm_map_buffer(&bo->tbo, bo->tbo.resource, &dst,
227322f7cc75SChristian König 1, ring, false, &cur_size, &to);
227422f7cc75SChristian König if (r)
227522f7cc75SChristian König goto error;
227622f7cc75SChristian König
227722f7cc75SChristian König r = amdgpu_ttm_fill_mem(ring, src_data, to, cur_size, resv,
2278c3aaca43SMukul Joshi &next, true, delayed);
227922f7cc75SChristian König if (r)
228022f7cc75SChristian König goto error;
228122f7cc75SChristian König
228222f7cc75SChristian König dma_fence_put(fence);
228322f7cc75SChristian König fence = next;
228422f7cc75SChristian König
228522f7cc75SChristian König amdgpu_res_next(&dst, cur_size);
228622f7cc75SChristian König }
228722f7cc75SChristian König error:
228822f7cc75SChristian König mutex_unlock(&adev->mman.gtt_window_lock);
228922f7cc75SChristian König if (f)
229022f7cc75SChristian König *f = dma_fence_get(fence);
229122f7cc75SChristian König dma_fence_put(fence);
229222f7cc75SChristian König return r;
229322f7cc75SChristian König }
229422f7cc75SChristian König
229558144d28SNirmoy Das /**
229658144d28SNirmoy Das * amdgpu_ttm_evict_resources - evict memory buffers
229758144d28SNirmoy Das * @adev: amdgpu device object
229858144d28SNirmoy Das * @mem_type: evicted BO's memory type
229958144d28SNirmoy Das *
230058144d28SNirmoy Das * Evicts all @mem_type buffers on the lru list of the memory type.
230158144d28SNirmoy Das *
230258144d28SNirmoy Das * Returns:
230358144d28SNirmoy Das * 0 for success or a negative error code on failure.
230458144d28SNirmoy Das */
amdgpu_ttm_evict_resources(struct amdgpu_device * adev,int mem_type)230558144d28SNirmoy Das int amdgpu_ttm_evict_resources(struct amdgpu_device *adev, int mem_type)
230658144d28SNirmoy Das {
230758144d28SNirmoy Das struct ttm_resource_manager *man;
230858144d28SNirmoy Das
230958144d28SNirmoy Das switch (mem_type) {
231058144d28SNirmoy Das case TTM_PL_VRAM:
231158144d28SNirmoy Das case TTM_PL_TT:
231258144d28SNirmoy Das case AMDGPU_PL_GWS:
231358144d28SNirmoy Das case AMDGPU_PL_GDS:
231458144d28SNirmoy Das case AMDGPU_PL_OA:
231558144d28SNirmoy Das man = ttm_manager_type(&adev->mman.bdev, mem_type);
231658144d28SNirmoy Das break;
231758144d28SNirmoy Das default:
231858144d28SNirmoy Das DRM_ERROR("Trying to evict invalid memory type\n");
231958144d28SNirmoy Das return -EINVAL;
232058144d28SNirmoy Das }
232158144d28SNirmoy Das
232258144d28SNirmoy Das return ttm_resource_manager_evict_all(&adev->mman.bdev, man);
232358144d28SNirmoy Das }
232458144d28SNirmoy Das
2325d38ceaf9SAlex Deucher #if defined(CONFIG_DEBUG_FS)
2326d38ceaf9SAlex Deucher
amdgpu_ttm_page_pool_show(struct seq_file * m,void * unused)232798d28ac2SNirmoy Das static int amdgpu_ttm_page_pool_show(struct seq_file *m, void *unused)
2328e93b2da9SChristian König {
2329109b4d8cSSu Hui struct amdgpu_device *adev = m->private;
2330e93b2da9SChristian König
2331e93b2da9SChristian König return ttm_pool_debugfs(&adev->mman.bdev.pool, m);
2332e93b2da9SChristian König }
2333e93b2da9SChristian König
233498d28ac2SNirmoy Das DEFINE_SHOW_ATTRIBUTE(amdgpu_ttm_page_pool);
2335d38ceaf9SAlex Deucher
233675501872SLee Jones /*
233750da5174STom St Denis * amdgpu_ttm_vram_read - Linear read access to VRAM
233850da5174STom St Denis *
233950da5174STom St Denis * Accesses VRAM via MMIO for debugging purposes.
234050da5174STom St Denis */
amdgpu_ttm_vram_read(struct file * f,char __user * buf,size_t size,loff_t * pos)2341d38ceaf9SAlex Deucher static ssize_t amdgpu_ttm_vram_read(struct file *f, char __user *buf,
2342d38ceaf9SAlex Deucher size_t size, loff_t *pos)
2343d38ceaf9SAlex Deucher {
234445063097SAl Viro struct amdgpu_device *adev = file_inode(f)->i_private;
2345d38ceaf9SAlex Deucher ssize_t result = 0;
2346d38ceaf9SAlex Deucher
2347d38ceaf9SAlex Deucher if (size & 0x3 || *pos & 0x3)
2348d38ceaf9SAlex Deucher return -EINVAL;
2349d38ceaf9SAlex Deucher
2350770d13b1SChristian König if (*pos >= adev->gmc.mc_vram_size)
23519156e723STom St Denis return -ENXIO;
23529156e723STom St Denis
2353030d5b97SChristian König size = min(size, (size_t)(adev->gmc.mc_vram_size - *pos));
2354d38ceaf9SAlex Deucher while (size) {
2355030d5b97SChristian König size_t bytes = min(size, AMDGPU_TTM_VRAM_MAX_DW_READ * 4);
2356030d5b97SChristian König uint32_t value[AMDGPU_TTM_VRAM_MAX_DW_READ];
2357d38ceaf9SAlex Deucher
2358030d5b97SChristian König amdgpu_device_vram_access(adev, *pos, value, bytes, false);
2359434cbcb1SDan Carpenter if (copy_to_user(buf, value, bytes))
2360434cbcb1SDan Carpenter return -EFAULT;
2361d38ceaf9SAlex Deucher
2362030d5b97SChristian König result += bytes;
2363030d5b97SChristian König buf += bytes;
2364030d5b97SChristian König *pos += bytes;
2365030d5b97SChristian König size -= bytes;
2366d38ceaf9SAlex Deucher }
2367d38ceaf9SAlex Deucher
2368d38ceaf9SAlex Deucher return result;
2369d38ceaf9SAlex Deucher }
2370d38ceaf9SAlex Deucher
237175501872SLee Jones /*
237250da5174STom St Denis * amdgpu_ttm_vram_write - Linear write access to VRAM
237350da5174STom St Denis *
237450da5174STom St Denis * Accesses VRAM via MMIO for debugging purposes.
237550da5174STom St Denis */
amdgpu_ttm_vram_write(struct file * f,const char __user * buf,size_t size,loff_t * pos)237608cab989STom St Denis static ssize_t amdgpu_ttm_vram_write(struct file *f, const char __user *buf,
237708cab989STom St Denis size_t size, loff_t *pos)
237808cab989STom St Denis {
237908cab989STom St Denis struct amdgpu_device *adev = file_inode(f)->i_private;
238008cab989STom St Denis ssize_t result = 0;
238108cab989STom St Denis int r;
238208cab989STom St Denis
238308cab989STom St Denis if (size & 0x3 || *pos & 0x3)
238408cab989STom St Denis return -EINVAL;
238508cab989STom St Denis
2386770d13b1SChristian König if (*pos >= adev->gmc.mc_vram_size)
238708cab989STom St Denis return -ENXIO;
238808cab989STom St Denis
238908cab989STom St Denis while (size) {
239008cab989STom St Denis uint32_t value;
239108cab989STom St Denis
2392770d13b1SChristian König if (*pos >= adev->gmc.mc_vram_size)
239308cab989STom St Denis return result;
239408cab989STom St Denis
239508cab989STom St Denis r = get_user(value, (uint32_t *)buf);
239608cab989STom St Denis if (r)
239708cab989STom St Denis return r;
239808cab989STom St Denis
23995fb95aa7SKevin Wang amdgpu_device_mm_access(adev, *pos, &value, 4, true);
240008cab989STom St Denis
240108cab989STom St Denis result += 4;
240208cab989STom St Denis buf += 4;
240308cab989STom St Denis *pos += 4;
240408cab989STom St Denis size -= 4;
240508cab989STom St Denis }
240608cab989STom St Denis
240708cab989STom St Denis return result;
240808cab989STom St Denis }
240908cab989STom St Denis
2410d38ceaf9SAlex Deucher static const struct file_operations amdgpu_ttm_vram_fops = {
2411d38ceaf9SAlex Deucher .owner = THIS_MODULE,
2412d38ceaf9SAlex Deucher .read = amdgpu_ttm_vram_read,
241308cab989STom St Denis .write = amdgpu_ttm_vram_write,
241408cab989STom St Denis .llseek = default_llseek,
2415d38ceaf9SAlex Deucher };
2416d38ceaf9SAlex Deucher
241775501872SLee Jones /*
241850da5174STom St Denis * amdgpu_iomem_read - Virtual read access to GPU mapped memory
241950da5174STom St Denis *
242050da5174STom St Denis * This function is used to read memory that has been mapped to the
242150da5174STom St Denis * GPU and the known addresses are not physical addresses but instead
242250da5174STom St Denis * bus addresses (e.g., what you'd put in an IB or ring buffer).
242350da5174STom St Denis */
amdgpu_iomem_read(struct file * f,char __user * buf,size_t size,loff_t * pos)2424ebb043f2STom St Denis static ssize_t amdgpu_iomem_read(struct file *f, char __user *buf,
242538290b2cSTom St Denis size_t size, loff_t *pos)
242638290b2cSTom St Denis {
242738290b2cSTom St Denis struct amdgpu_device *adev = file_inode(f)->i_private;
242838290b2cSTom St Denis struct iommu_domain *dom;
2429ebb043f2STom St Denis ssize_t result = 0;
2430ebb043f2STom St Denis int r;
243110cfafd6STom St Denis
243250da5174STom St Denis /* retrieve the IOMMU domain if any for this device */
243338290b2cSTom St Denis dom = iommu_get_domain_for_dev(adev->dev);
243438290b2cSTom St Denis
2435ebb043f2STom St Denis while (size) {
2436ebb043f2STom St Denis phys_addr_t addr = *pos & PAGE_MASK;
2437ebb043f2STom St Denis loff_t off = *pos & ~PAGE_MASK;
2438ebb043f2STom St Denis size_t bytes = PAGE_SIZE - off;
2439ebb043f2STom St Denis unsigned long pfn;
2440ebb043f2STom St Denis struct page *p;
2441ebb043f2STom St Denis void *ptr;
2442ebb043f2STom St Denis
244344fd83e9SSrinivasan Shanmugam bytes = min(bytes, size);
2444ebb043f2STom St Denis
244550da5174STom St Denis /* Translate the bus address to a physical address. If
244650da5174STom St Denis * the domain is NULL it means there is no IOMMU active
244750da5174STom St Denis * and the address translation is the identity
244850da5174STom St Denis */
2449ebb043f2STom St Denis addr = dom ? iommu_iova_to_phys(dom, addr) : addr;
2450ebb043f2STom St Denis
2451ebb043f2STom St Denis pfn = addr >> PAGE_SHIFT;
2452ebb043f2STom St Denis if (!pfn_valid(pfn))
2453ebb043f2STom St Denis return -EPERM;
2454ebb043f2STom St Denis
2455ebb043f2STom St Denis p = pfn_to_page(pfn);
2456ebb043f2STom St Denis if (p->mapping != adev->mman.bdev.dev_mapping)
2457ebb043f2STom St Denis return -EPERM;
2458ebb043f2STom St Denis
2459a2c55426SFabio M. De Francesco ptr = kmap_local_page(p);
2460864917a3STom St Denis r = copy_to_user(buf, ptr + off, bytes);
2461a2c55426SFabio M. De Francesco kunmap_local(ptr);
246238290b2cSTom St Denis if (r)
246338290b2cSTom St Denis return -EFAULT;
246438290b2cSTom St Denis
2465ebb043f2STom St Denis size -= bytes;
2466ebb043f2STom St Denis *pos += bytes;
2467ebb043f2STom St Denis result += bytes;
246838290b2cSTom St Denis }
246938290b2cSTom St Denis
2470ebb043f2STom St Denis return result;
2471ebb043f2STom St Denis }
2472ebb043f2STom St Denis
247375501872SLee Jones /*
247450da5174STom St Denis * amdgpu_iomem_write - Virtual write access to GPU mapped memory
247550da5174STom St Denis *
247650da5174STom St Denis * This function is used to write memory that has been mapped to the
247750da5174STom St Denis * GPU and the known addresses are not physical addresses but instead
247850da5174STom St Denis * bus addresses (e.g., what you'd put in an IB or ring buffer).
247950da5174STom St Denis */
amdgpu_iomem_write(struct file * f,const char __user * buf,size_t size,loff_t * pos)2480ebb043f2STom St Denis static ssize_t amdgpu_iomem_write(struct file *f, const char __user *buf,
2481ebb043f2STom St Denis size_t size, loff_t *pos)
2482ebb043f2STom St Denis {
2483ebb043f2STom St Denis struct amdgpu_device *adev = file_inode(f)->i_private;
2484ebb043f2STom St Denis struct iommu_domain *dom;
2485ebb043f2STom St Denis ssize_t result = 0;
2486ebb043f2STom St Denis int r;
2487ebb043f2STom St Denis
2488ebb043f2STom St Denis dom = iommu_get_domain_for_dev(adev->dev);
2489ebb043f2STom St Denis
2490ebb043f2STom St Denis while (size) {
2491ebb043f2STom St Denis phys_addr_t addr = *pos & PAGE_MASK;
2492ebb043f2STom St Denis loff_t off = *pos & ~PAGE_MASK;
2493ebb043f2STom St Denis size_t bytes = PAGE_SIZE - off;
2494ebb043f2STom St Denis unsigned long pfn;
2495ebb043f2STom St Denis struct page *p;
2496ebb043f2STom St Denis void *ptr;
2497ebb043f2STom St Denis
2498b828e100SSrinivasan Shanmugam bytes = min(bytes, size);
2499ebb043f2STom St Denis
2500ebb043f2STom St Denis addr = dom ? iommu_iova_to_phys(dom, addr) : addr;
2501ebb043f2STom St Denis
2502ebb043f2STom St Denis pfn = addr >> PAGE_SHIFT;
2503ebb043f2STom St Denis if (!pfn_valid(pfn))
2504ebb043f2STom St Denis return -EPERM;
2505ebb043f2STom St Denis
2506ebb043f2STom St Denis p = pfn_to_page(pfn);
2507ebb043f2STom St Denis if (p->mapping != adev->mman.bdev.dev_mapping)
2508ebb043f2STom St Denis return -EPERM;
2509ebb043f2STom St Denis
2510a2c55426SFabio M. De Francesco ptr = kmap_local_page(p);
2511864917a3STom St Denis r = copy_from_user(ptr + off, buf, bytes);
2512a2c55426SFabio M. De Francesco kunmap_local(ptr);
2513ebb043f2STom St Denis if (r)
2514ebb043f2STom St Denis return -EFAULT;
2515ebb043f2STom St Denis
2516ebb043f2STom St Denis size -= bytes;
2517ebb043f2STom St Denis *pos += bytes;
2518ebb043f2STom St Denis result += bytes;
2519ebb043f2STom St Denis }
2520ebb043f2STom St Denis
2521ebb043f2STom St Denis return result;
2522ebb043f2STom St Denis }
2523ebb043f2STom St Denis
2524ebb043f2STom St Denis static const struct file_operations amdgpu_ttm_iomem_fops = {
252538290b2cSTom St Denis .owner = THIS_MODULE,
2526ebb043f2STom St Denis .read = amdgpu_iomem_read,
2527ebb043f2STom St Denis .write = amdgpu_iomem_write,
252838290b2cSTom St Denis .llseek = default_llseek
252938290b2cSTom St Denis };
2530a40cfa0bSTom St Denis
2531a1d29476SChristian König #endif
2532a1d29476SChristian König
amdgpu_ttm_debugfs_init(struct amdgpu_device * adev)253398d28ac2SNirmoy Das void amdgpu_ttm_debugfs_init(struct amdgpu_device *adev)
2534d38ceaf9SAlex Deucher {
2535d38ceaf9SAlex Deucher #if defined(CONFIG_DEBUG_FS)
25364a580877SLuben Tuikov struct drm_minor *minor = adev_to_drm(adev)->primary;
253788293c03SNirmoy Das struct dentry *root = minor->debugfs_root;
2538d38ceaf9SAlex Deucher
253998d28ac2SNirmoy Das debugfs_create_file_size("amdgpu_vram", 0444, root, adev,
254088293c03SNirmoy Das &amdgpu_ttm_vram_fops, adev->gmc.mc_vram_size);
254198d28ac2SNirmoy Das debugfs_create_file("amdgpu_iomem", 0444, root, adev,
254288293c03SNirmoy Das &amdgpu_ttm_iomem_fops);
254398d28ac2SNirmoy Das debugfs_create_file("ttm_page_pool", 0444, root, adev,
254498d28ac2SNirmoy Das &amdgpu_ttm_page_pool_fops);
25457212d24cSZack Rusin ttm_resource_manager_create_debugfs(ttm_manager_type(&adev->mman.bdev,
25467212d24cSZack Rusin TTM_PL_VRAM),
25477212d24cSZack Rusin root, "amdgpu_vram_mm");
25487212d24cSZack Rusin ttm_resource_manager_create_debugfs(ttm_manager_type(&adev->mman.bdev,
25497212d24cSZack Rusin TTM_PL_TT),
25507212d24cSZack Rusin root, "amdgpu_gtt_mm");
25517212d24cSZack Rusin ttm_resource_manager_create_debugfs(ttm_manager_type(&adev->mman.bdev,
25527212d24cSZack Rusin AMDGPU_PL_GDS),
25537212d24cSZack Rusin root, "amdgpu_gds_mm");
25547212d24cSZack Rusin ttm_resource_manager_create_debugfs(ttm_manager_type(&adev->mman.bdev,
25557212d24cSZack Rusin AMDGPU_PL_GWS),
25567212d24cSZack Rusin root, "amdgpu_gws_mm");
25577212d24cSZack Rusin ttm_resource_manager_create_debugfs(ttm_manager_type(&adev->mman.bdev,
25587212d24cSZack Rusin AMDGPU_PL_OA),
25597212d24cSZack Rusin root, "amdgpu_oa_mm");
25607212d24cSZack Rusin
2561d38ceaf9SAlex Deucher #endif
2562d38ceaf9SAlex Deucher }
2563