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