162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * Copyright 2018 Advanced Micro Devices, Inc. 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#include <linux/io-64-nonatomic-lo-hi.h> 2862306a36Sopenharmony_ci#ifdef CONFIG_X86 2962306a36Sopenharmony_ci#include <asm/hypervisor.h> 3062306a36Sopenharmony_ci#endif 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci#include "amdgpu.h" 3362306a36Sopenharmony_ci#include "amdgpu_gmc.h" 3462306a36Sopenharmony_ci#include "amdgpu_ras.h" 3562306a36Sopenharmony_ci#include "amdgpu_xgmi.h" 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci#include <drm/drm_drv.h> 3862306a36Sopenharmony_ci#include <drm/ttm/ttm_tt.h> 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci/** 4162306a36Sopenharmony_ci * amdgpu_gmc_pdb0_alloc - allocate vram for pdb0 4262306a36Sopenharmony_ci * 4362306a36Sopenharmony_ci * @adev: amdgpu_device pointer 4462306a36Sopenharmony_ci * 4562306a36Sopenharmony_ci * Allocate video memory for pdb0 and map it for CPU access 4662306a36Sopenharmony_ci * Returns 0 for success, error for failure. 4762306a36Sopenharmony_ci */ 4862306a36Sopenharmony_ciint amdgpu_gmc_pdb0_alloc(struct amdgpu_device *adev) 4962306a36Sopenharmony_ci{ 5062306a36Sopenharmony_ci int r; 5162306a36Sopenharmony_ci struct amdgpu_bo_param bp; 5262306a36Sopenharmony_ci u64 vram_size = adev->gmc.xgmi.node_segment_size * adev->gmc.xgmi.num_physical_nodes; 5362306a36Sopenharmony_ci uint32_t pde0_page_shift = adev->gmc.vmid0_page_table_block_size + 21; 5462306a36Sopenharmony_ci uint32_t npdes = (vram_size + (1ULL << pde0_page_shift) -1) >> pde0_page_shift; 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci memset(&bp, 0, sizeof(bp)); 5762306a36Sopenharmony_ci bp.size = PAGE_ALIGN((npdes + 1) * 8); 5862306a36Sopenharmony_ci bp.byte_align = PAGE_SIZE; 5962306a36Sopenharmony_ci bp.domain = AMDGPU_GEM_DOMAIN_VRAM; 6062306a36Sopenharmony_ci bp.flags = AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED | 6162306a36Sopenharmony_ci AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS; 6262306a36Sopenharmony_ci bp.type = ttm_bo_type_kernel; 6362306a36Sopenharmony_ci bp.resv = NULL; 6462306a36Sopenharmony_ci bp.bo_ptr_size = sizeof(struct amdgpu_bo); 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci r = amdgpu_bo_create(adev, &bp, &adev->gmc.pdb0_bo); 6762306a36Sopenharmony_ci if (r) 6862306a36Sopenharmony_ci return r; 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci r = amdgpu_bo_reserve(adev->gmc.pdb0_bo, false); 7162306a36Sopenharmony_ci if (unlikely(r != 0)) 7262306a36Sopenharmony_ci goto bo_reserve_failure; 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci r = amdgpu_bo_pin(adev->gmc.pdb0_bo, AMDGPU_GEM_DOMAIN_VRAM); 7562306a36Sopenharmony_ci if (r) 7662306a36Sopenharmony_ci goto bo_pin_failure; 7762306a36Sopenharmony_ci r = amdgpu_bo_kmap(adev->gmc.pdb0_bo, &adev->gmc.ptr_pdb0); 7862306a36Sopenharmony_ci if (r) 7962306a36Sopenharmony_ci goto bo_kmap_failure; 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci amdgpu_bo_unreserve(adev->gmc.pdb0_bo); 8262306a36Sopenharmony_ci return 0; 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_cibo_kmap_failure: 8562306a36Sopenharmony_ci amdgpu_bo_unpin(adev->gmc.pdb0_bo); 8662306a36Sopenharmony_cibo_pin_failure: 8762306a36Sopenharmony_ci amdgpu_bo_unreserve(adev->gmc.pdb0_bo); 8862306a36Sopenharmony_cibo_reserve_failure: 8962306a36Sopenharmony_ci amdgpu_bo_unref(&adev->gmc.pdb0_bo); 9062306a36Sopenharmony_ci return r; 9162306a36Sopenharmony_ci} 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci/** 9462306a36Sopenharmony_ci * amdgpu_gmc_get_pde_for_bo - get the PDE for a BO 9562306a36Sopenharmony_ci * 9662306a36Sopenharmony_ci * @bo: the BO to get the PDE for 9762306a36Sopenharmony_ci * @level: the level in the PD hirarchy 9862306a36Sopenharmony_ci * @addr: resulting addr 9962306a36Sopenharmony_ci * @flags: resulting flags 10062306a36Sopenharmony_ci * 10162306a36Sopenharmony_ci * Get the address and flags to be used for a PDE (Page Directory Entry). 10262306a36Sopenharmony_ci */ 10362306a36Sopenharmony_civoid amdgpu_gmc_get_pde_for_bo(struct amdgpu_bo *bo, int level, 10462306a36Sopenharmony_ci uint64_t *addr, uint64_t *flags) 10562306a36Sopenharmony_ci{ 10662306a36Sopenharmony_ci struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev); 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci switch (bo->tbo.resource->mem_type) { 10962306a36Sopenharmony_ci case TTM_PL_TT: 11062306a36Sopenharmony_ci *addr = bo->tbo.ttm->dma_address[0]; 11162306a36Sopenharmony_ci break; 11262306a36Sopenharmony_ci case TTM_PL_VRAM: 11362306a36Sopenharmony_ci *addr = amdgpu_bo_gpu_offset(bo); 11462306a36Sopenharmony_ci break; 11562306a36Sopenharmony_ci default: 11662306a36Sopenharmony_ci *addr = 0; 11762306a36Sopenharmony_ci break; 11862306a36Sopenharmony_ci } 11962306a36Sopenharmony_ci *flags = amdgpu_ttm_tt_pde_flags(bo->tbo.ttm, bo->tbo.resource); 12062306a36Sopenharmony_ci amdgpu_gmc_get_vm_pde(adev, level, addr, flags); 12162306a36Sopenharmony_ci} 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci/* 12462306a36Sopenharmony_ci * amdgpu_gmc_pd_addr - return the address of the root directory 12562306a36Sopenharmony_ci */ 12662306a36Sopenharmony_ciuint64_t amdgpu_gmc_pd_addr(struct amdgpu_bo *bo) 12762306a36Sopenharmony_ci{ 12862306a36Sopenharmony_ci struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev); 12962306a36Sopenharmony_ci uint64_t pd_addr; 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci /* TODO: move that into ASIC specific code */ 13262306a36Sopenharmony_ci if (adev->asic_type >= CHIP_VEGA10) { 13362306a36Sopenharmony_ci uint64_t flags = AMDGPU_PTE_VALID; 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci amdgpu_gmc_get_pde_for_bo(bo, -1, &pd_addr, &flags); 13662306a36Sopenharmony_ci pd_addr |= flags; 13762306a36Sopenharmony_ci } else { 13862306a36Sopenharmony_ci pd_addr = amdgpu_bo_gpu_offset(bo); 13962306a36Sopenharmony_ci } 14062306a36Sopenharmony_ci return pd_addr; 14162306a36Sopenharmony_ci} 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci/** 14462306a36Sopenharmony_ci * amdgpu_gmc_set_pte_pde - update the page tables using CPU 14562306a36Sopenharmony_ci * 14662306a36Sopenharmony_ci * @adev: amdgpu_device pointer 14762306a36Sopenharmony_ci * @cpu_pt_addr: cpu address of the page table 14862306a36Sopenharmony_ci * @gpu_page_idx: entry in the page table to update 14962306a36Sopenharmony_ci * @addr: dst addr to write into pte/pde 15062306a36Sopenharmony_ci * @flags: access flags 15162306a36Sopenharmony_ci * 15262306a36Sopenharmony_ci * Update the page tables using CPU. 15362306a36Sopenharmony_ci */ 15462306a36Sopenharmony_ciint amdgpu_gmc_set_pte_pde(struct amdgpu_device *adev, void *cpu_pt_addr, 15562306a36Sopenharmony_ci uint32_t gpu_page_idx, uint64_t addr, 15662306a36Sopenharmony_ci uint64_t flags) 15762306a36Sopenharmony_ci{ 15862306a36Sopenharmony_ci void __iomem *ptr = (void *)cpu_pt_addr; 15962306a36Sopenharmony_ci uint64_t value; 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci /* 16262306a36Sopenharmony_ci * The following is for PTE only. GART does not have PDEs. 16362306a36Sopenharmony_ci */ 16462306a36Sopenharmony_ci value = addr & 0x0000FFFFFFFFF000ULL; 16562306a36Sopenharmony_ci value |= flags; 16662306a36Sopenharmony_ci writeq(value, ptr + (gpu_page_idx * 8)); 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci return 0; 16962306a36Sopenharmony_ci} 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci/** 17262306a36Sopenharmony_ci * amdgpu_gmc_agp_addr - return the address in the AGP address space 17362306a36Sopenharmony_ci * 17462306a36Sopenharmony_ci * @bo: TTM BO which needs the address, must be in GTT domain 17562306a36Sopenharmony_ci * 17662306a36Sopenharmony_ci * Tries to figure out how to access the BO through the AGP aperture. Returns 17762306a36Sopenharmony_ci * AMDGPU_BO_INVALID_OFFSET if that is not possible. 17862306a36Sopenharmony_ci */ 17962306a36Sopenharmony_ciuint64_t amdgpu_gmc_agp_addr(struct ttm_buffer_object *bo) 18062306a36Sopenharmony_ci{ 18162306a36Sopenharmony_ci struct amdgpu_device *adev = amdgpu_ttm_adev(bo->bdev); 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci if (bo->ttm->num_pages != 1 || bo->ttm->caching == ttm_cached) 18462306a36Sopenharmony_ci return AMDGPU_BO_INVALID_OFFSET; 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci if (bo->ttm->dma_address[0] + PAGE_SIZE >= adev->gmc.agp_size) 18762306a36Sopenharmony_ci return AMDGPU_BO_INVALID_OFFSET; 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci return adev->gmc.agp_start + bo->ttm->dma_address[0]; 19062306a36Sopenharmony_ci} 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci/** 19362306a36Sopenharmony_ci * amdgpu_gmc_vram_location - try to find VRAM location 19462306a36Sopenharmony_ci * 19562306a36Sopenharmony_ci * @adev: amdgpu device structure holding all necessary information 19662306a36Sopenharmony_ci * @mc: memory controller structure holding memory information 19762306a36Sopenharmony_ci * @base: base address at which to put VRAM 19862306a36Sopenharmony_ci * 19962306a36Sopenharmony_ci * Function will try to place VRAM at base address provided 20062306a36Sopenharmony_ci * as parameter. 20162306a36Sopenharmony_ci */ 20262306a36Sopenharmony_civoid amdgpu_gmc_vram_location(struct amdgpu_device *adev, struct amdgpu_gmc *mc, 20362306a36Sopenharmony_ci u64 base) 20462306a36Sopenharmony_ci{ 20562306a36Sopenharmony_ci uint64_t vis_limit = (uint64_t)amdgpu_vis_vram_limit << 20; 20662306a36Sopenharmony_ci uint64_t limit = (uint64_t)amdgpu_vram_limit << 20; 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci mc->vram_start = base; 20962306a36Sopenharmony_ci mc->vram_end = mc->vram_start + mc->mc_vram_size - 1; 21062306a36Sopenharmony_ci if (limit < mc->real_vram_size) 21162306a36Sopenharmony_ci mc->real_vram_size = limit; 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci if (vis_limit && vis_limit < mc->visible_vram_size) 21462306a36Sopenharmony_ci mc->visible_vram_size = vis_limit; 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci if (mc->real_vram_size < mc->visible_vram_size) 21762306a36Sopenharmony_ci mc->visible_vram_size = mc->real_vram_size; 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci if (mc->xgmi.num_physical_nodes == 0) { 22062306a36Sopenharmony_ci mc->fb_start = mc->vram_start; 22162306a36Sopenharmony_ci mc->fb_end = mc->vram_end; 22262306a36Sopenharmony_ci } 22362306a36Sopenharmony_ci dev_info(adev->dev, "VRAM: %lluM 0x%016llX - 0x%016llX (%lluM used)\n", 22462306a36Sopenharmony_ci mc->mc_vram_size >> 20, mc->vram_start, 22562306a36Sopenharmony_ci mc->vram_end, mc->real_vram_size >> 20); 22662306a36Sopenharmony_ci} 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci/** amdgpu_gmc_sysvm_location - place vram and gart in sysvm aperture 22962306a36Sopenharmony_ci * 23062306a36Sopenharmony_ci * @adev: amdgpu device structure holding all necessary information 23162306a36Sopenharmony_ci * @mc: memory controller structure holding memory information 23262306a36Sopenharmony_ci * 23362306a36Sopenharmony_ci * This function is only used if use GART for FB translation. In such 23462306a36Sopenharmony_ci * case, we use sysvm aperture (vmid0 page tables) for both vram 23562306a36Sopenharmony_ci * and gart (aka system memory) access. 23662306a36Sopenharmony_ci * 23762306a36Sopenharmony_ci * GPUVM (and our organization of vmid0 page tables) require sysvm 23862306a36Sopenharmony_ci * aperture to be placed at a location aligned with 8 times of native 23962306a36Sopenharmony_ci * page size. For example, if vm_context0_cntl.page_table_block_size 24062306a36Sopenharmony_ci * is 12, then native page size is 8G (2M*2^12), sysvm should start 24162306a36Sopenharmony_ci * with a 64G aligned address. For simplicity, we just put sysvm at 24262306a36Sopenharmony_ci * address 0. So vram start at address 0 and gart is right after vram. 24362306a36Sopenharmony_ci */ 24462306a36Sopenharmony_civoid amdgpu_gmc_sysvm_location(struct amdgpu_device *adev, struct amdgpu_gmc *mc) 24562306a36Sopenharmony_ci{ 24662306a36Sopenharmony_ci u64 hive_vram_start = 0; 24762306a36Sopenharmony_ci u64 hive_vram_end = mc->xgmi.node_segment_size * mc->xgmi.num_physical_nodes - 1; 24862306a36Sopenharmony_ci mc->vram_start = mc->xgmi.node_segment_size * mc->xgmi.physical_node_id; 24962306a36Sopenharmony_ci mc->vram_end = mc->vram_start + mc->xgmi.node_segment_size - 1; 25062306a36Sopenharmony_ci mc->gart_start = hive_vram_end + 1; 25162306a36Sopenharmony_ci mc->gart_end = mc->gart_start + mc->gart_size - 1; 25262306a36Sopenharmony_ci mc->fb_start = hive_vram_start; 25362306a36Sopenharmony_ci mc->fb_end = hive_vram_end; 25462306a36Sopenharmony_ci dev_info(adev->dev, "VRAM: %lluM 0x%016llX - 0x%016llX (%lluM used)\n", 25562306a36Sopenharmony_ci mc->mc_vram_size >> 20, mc->vram_start, 25662306a36Sopenharmony_ci mc->vram_end, mc->real_vram_size >> 20); 25762306a36Sopenharmony_ci dev_info(adev->dev, "GART: %lluM 0x%016llX - 0x%016llX\n", 25862306a36Sopenharmony_ci mc->gart_size >> 20, mc->gart_start, mc->gart_end); 25962306a36Sopenharmony_ci} 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci/** 26262306a36Sopenharmony_ci * amdgpu_gmc_gart_location - try to find GART location 26362306a36Sopenharmony_ci * 26462306a36Sopenharmony_ci * @adev: amdgpu device structure holding all necessary information 26562306a36Sopenharmony_ci * @mc: memory controller structure holding memory information 26662306a36Sopenharmony_ci * 26762306a36Sopenharmony_ci * Function will place try to place GART before or after VRAM. 26862306a36Sopenharmony_ci * If GART size is bigger than space left then we ajust GART size. 26962306a36Sopenharmony_ci * Thus function will never fails. 27062306a36Sopenharmony_ci */ 27162306a36Sopenharmony_civoid amdgpu_gmc_gart_location(struct amdgpu_device *adev, struct amdgpu_gmc *mc) 27262306a36Sopenharmony_ci{ 27362306a36Sopenharmony_ci const uint64_t four_gb = 0x100000000ULL; 27462306a36Sopenharmony_ci u64 size_af, size_bf; 27562306a36Sopenharmony_ci /*To avoid the hole, limit the max mc address to AMDGPU_GMC_HOLE_START*/ 27662306a36Sopenharmony_ci u64 max_mc_address = min(adev->gmc.mc_mask, AMDGPU_GMC_HOLE_START - 1); 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci /* VCE doesn't like it when BOs cross a 4GB segment, so align 27962306a36Sopenharmony_ci * the GART base on a 4GB boundary as well. 28062306a36Sopenharmony_ci */ 28162306a36Sopenharmony_ci size_bf = mc->fb_start; 28262306a36Sopenharmony_ci size_af = max_mc_address + 1 - ALIGN(mc->fb_end + 1, four_gb); 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci if (mc->gart_size > max(size_bf, size_af)) { 28562306a36Sopenharmony_ci dev_warn(adev->dev, "limiting GART\n"); 28662306a36Sopenharmony_ci mc->gart_size = max(size_bf, size_af); 28762306a36Sopenharmony_ci } 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci if ((size_bf >= mc->gart_size && size_bf < size_af) || 29062306a36Sopenharmony_ci (size_af < mc->gart_size)) 29162306a36Sopenharmony_ci mc->gart_start = 0; 29262306a36Sopenharmony_ci else 29362306a36Sopenharmony_ci mc->gart_start = max_mc_address - mc->gart_size + 1; 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci mc->gart_start &= ~(four_gb - 1); 29662306a36Sopenharmony_ci mc->gart_end = mc->gart_start + mc->gart_size - 1; 29762306a36Sopenharmony_ci dev_info(adev->dev, "GART: %lluM 0x%016llX - 0x%016llX\n", 29862306a36Sopenharmony_ci mc->gart_size >> 20, mc->gart_start, mc->gart_end); 29962306a36Sopenharmony_ci} 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci/** 30262306a36Sopenharmony_ci * amdgpu_gmc_agp_location - try to find AGP location 30362306a36Sopenharmony_ci * @adev: amdgpu device structure holding all necessary information 30462306a36Sopenharmony_ci * @mc: memory controller structure holding memory information 30562306a36Sopenharmony_ci * 30662306a36Sopenharmony_ci * Function will place try to find a place for the AGP BAR in the MC address 30762306a36Sopenharmony_ci * space. 30862306a36Sopenharmony_ci * 30962306a36Sopenharmony_ci * AGP BAR will be assigned the largest available hole in the address space. 31062306a36Sopenharmony_ci * Should be called after VRAM and GART locations are setup. 31162306a36Sopenharmony_ci */ 31262306a36Sopenharmony_civoid amdgpu_gmc_agp_location(struct amdgpu_device *adev, struct amdgpu_gmc *mc) 31362306a36Sopenharmony_ci{ 31462306a36Sopenharmony_ci const uint64_t sixteen_gb = 1ULL << 34; 31562306a36Sopenharmony_ci const uint64_t sixteen_gb_mask = ~(sixteen_gb - 1); 31662306a36Sopenharmony_ci u64 size_af, size_bf; 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci if (amdgpu_sriov_vf(adev)) { 31962306a36Sopenharmony_ci mc->agp_start = 0xffffffffffff; 32062306a36Sopenharmony_ci mc->agp_end = 0x0; 32162306a36Sopenharmony_ci mc->agp_size = 0; 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci return; 32462306a36Sopenharmony_ci } 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci if (mc->fb_start > mc->gart_start) { 32762306a36Sopenharmony_ci size_bf = (mc->fb_start & sixteen_gb_mask) - 32862306a36Sopenharmony_ci ALIGN(mc->gart_end + 1, sixteen_gb); 32962306a36Sopenharmony_ci size_af = mc->mc_mask + 1 - ALIGN(mc->fb_end + 1, sixteen_gb); 33062306a36Sopenharmony_ci } else { 33162306a36Sopenharmony_ci size_bf = mc->fb_start & sixteen_gb_mask; 33262306a36Sopenharmony_ci size_af = (mc->gart_start & sixteen_gb_mask) - 33362306a36Sopenharmony_ci ALIGN(mc->fb_end + 1, sixteen_gb); 33462306a36Sopenharmony_ci } 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci if (size_bf > size_af) { 33762306a36Sopenharmony_ci mc->agp_start = (mc->fb_start - size_bf) & sixteen_gb_mask; 33862306a36Sopenharmony_ci mc->agp_size = size_bf; 33962306a36Sopenharmony_ci } else { 34062306a36Sopenharmony_ci mc->agp_start = ALIGN(mc->fb_end + 1, sixteen_gb); 34162306a36Sopenharmony_ci mc->agp_size = size_af; 34262306a36Sopenharmony_ci } 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci mc->agp_end = mc->agp_start + mc->agp_size - 1; 34562306a36Sopenharmony_ci dev_info(adev->dev, "AGP: %lluM 0x%016llX - 0x%016llX\n", 34662306a36Sopenharmony_ci mc->agp_size >> 20, mc->agp_start, mc->agp_end); 34762306a36Sopenharmony_ci} 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci/** 35062306a36Sopenharmony_ci * amdgpu_gmc_fault_key - get hask key from vm fault address and pasid 35162306a36Sopenharmony_ci * 35262306a36Sopenharmony_ci * @addr: 48 bit physical address, page aligned (36 significant bits) 35362306a36Sopenharmony_ci * @pasid: 16 bit process address space identifier 35462306a36Sopenharmony_ci */ 35562306a36Sopenharmony_cistatic inline uint64_t amdgpu_gmc_fault_key(uint64_t addr, uint16_t pasid) 35662306a36Sopenharmony_ci{ 35762306a36Sopenharmony_ci return addr << 4 | pasid; 35862306a36Sopenharmony_ci} 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci/** 36162306a36Sopenharmony_ci * amdgpu_gmc_filter_faults - filter VM faults 36262306a36Sopenharmony_ci * 36362306a36Sopenharmony_ci * @adev: amdgpu device structure 36462306a36Sopenharmony_ci * @ih: interrupt ring that the fault received from 36562306a36Sopenharmony_ci * @addr: address of the VM fault 36662306a36Sopenharmony_ci * @pasid: PASID of the process causing the fault 36762306a36Sopenharmony_ci * @timestamp: timestamp of the fault 36862306a36Sopenharmony_ci * 36962306a36Sopenharmony_ci * Returns: 37062306a36Sopenharmony_ci * True if the fault was filtered and should not be processed further. 37162306a36Sopenharmony_ci * False if the fault is a new one and needs to be handled. 37262306a36Sopenharmony_ci */ 37362306a36Sopenharmony_cibool amdgpu_gmc_filter_faults(struct amdgpu_device *adev, 37462306a36Sopenharmony_ci struct amdgpu_ih_ring *ih, uint64_t addr, 37562306a36Sopenharmony_ci uint16_t pasid, uint64_t timestamp) 37662306a36Sopenharmony_ci{ 37762306a36Sopenharmony_ci struct amdgpu_gmc *gmc = &adev->gmc; 37862306a36Sopenharmony_ci uint64_t stamp, key = amdgpu_gmc_fault_key(addr, pasid); 37962306a36Sopenharmony_ci struct amdgpu_gmc_fault *fault; 38062306a36Sopenharmony_ci uint32_t hash; 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci /* Stale retry fault if timestamp goes backward */ 38362306a36Sopenharmony_ci if (amdgpu_ih_ts_after(timestamp, ih->processed_timestamp)) 38462306a36Sopenharmony_ci return true; 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci /* If we don't have space left in the ring buffer return immediately */ 38762306a36Sopenharmony_ci stamp = max(timestamp, AMDGPU_GMC_FAULT_TIMEOUT + 1) - 38862306a36Sopenharmony_ci AMDGPU_GMC_FAULT_TIMEOUT; 38962306a36Sopenharmony_ci if (gmc->fault_ring[gmc->last_fault].timestamp >= stamp) 39062306a36Sopenharmony_ci return true; 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci /* Try to find the fault in the hash */ 39362306a36Sopenharmony_ci hash = hash_64(key, AMDGPU_GMC_FAULT_HASH_ORDER); 39462306a36Sopenharmony_ci fault = &gmc->fault_ring[gmc->fault_hash[hash].idx]; 39562306a36Sopenharmony_ci while (fault->timestamp >= stamp) { 39662306a36Sopenharmony_ci uint64_t tmp; 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci if (atomic64_read(&fault->key) == key) { 39962306a36Sopenharmony_ci /* 40062306a36Sopenharmony_ci * if we get a fault which is already present in 40162306a36Sopenharmony_ci * the fault_ring and the timestamp of 40262306a36Sopenharmony_ci * the fault is after the expired timestamp, 40362306a36Sopenharmony_ci * then this is a new fault that needs to be added 40462306a36Sopenharmony_ci * into the fault ring. 40562306a36Sopenharmony_ci */ 40662306a36Sopenharmony_ci if (fault->timestamp_expiry != 0 && 40762306a36Sopenharmony_ci amdgpu_ih_ts_after(fault->timestamp_expiry, 40862306a36Sopenharmony_ci timestamp)) 40962306a36Sopenharmony_ci break; 41062306a36Sopenharmony_ci else 41162306a36Sopenharmony_ci return true; 41262306a36Sopenharmony_ci } 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci tmp = fault->timestamp; 41562306a36Sopenharmony_ci fault = &gmc->fault_ring[fault->next]; 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci /* Check if the entry was reused */ 41862306a36Sopenharmony_ci if (fault->timestamp >= tmp) 41962306a36Sopenharmony_ci break; 42062306a36Sopenharmony_ci } 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci /* Add the fault to the ring */ 42362306a36Sopenharmony_ci fault = &gmc->fault_ring[gmc->last_fault]; 42462306a36Sopenharmony_ci atomic64_set(&fault->key, key); 42562306a36Sopenharmony_ci fault->timestamp = timestamp; 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci /* And update the hash */ 42862306a36Sopenharmony_ci fault->next = gmc->fault_hash[hash].idx; 42962306a36Sopenharmony_ci gmc->fault_hash[hash].idx = gmc->last_fault++; 43062306a36Sopenharmony_ci return false; 43162306a36Sopenharmony_ci} 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci/** 43462306a36Sopenharmony_ci * amdgpu_gmc_filter_faults_remove - remove address from VM faults filter 43562306a36Sopenharmony_ci * 43662306a36Sopenharmony_ci * @adev: amdgpu device structure 43762306a36Sopenharmony_ci * @addr: address of the VM fault 43862306a36Sopenharmony_ci * @pasid: PASID of the process causing the fault 43962306a36Sopenharmony_ci * 44062306a36Sopenharmony_ci * Remove the address from fault filter, then future vm fault on this address 44162306a36Sopenharmony_ci * will pass to retry fault handler to recover. 44262306a36Sopenharmony_ci */ 44362306a36Sopenharmony_civoid amdgpu_gmc_filter_faults_remove(struct amdgpu_device *adev, uint64_t addr, 44462306a36Sopenharmony_ci uint16_t pasid) 44562306a36Sopenharmony_ci{ 44662306a36Sopenharmony_ci struct amdgpu_gmc *gmc = &adev->gmc; 44762306a36Sopenharmony_ci uint64_t key = amdgpu_gmc_fault_key(addr, pasid); 44862306a36Sopenharmony_ci struct amdgpu_ih_ring *ih; 44962306a36Sopenharmony_ci struct amdgpu_gmc_fault *fault; 45062306a36Sopenharmony_ci uint32_t last_wptr; 45162306a36Sopenharmony_ci uint64_t last_ts; 45262306a36Sopenharmony_ci uint32_t hash; 45362306a36Sopenharmony_ci uint64_t tmp; 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci ih = adev->irq.retry_cam_enabled ? &adev->irq.ih_soft : &adev->irq.ih1; 45662306a36Sopenharmony_ci /* Get the WPTR of the last entry in IH ring */ 45762306a36Sopenharmony_ci last_wptr = amdgpu_ih_get_wptr(adev, ih); 45862306a36Sopenharmony_ci /* Order wptr with ring data. */ 45962306a36Sopenharmony_ci rmb(); 46062306a36Sopenharmony_ci /* Get the timetamp of the last entry in IH ring */ 46162306a36Sopenharmony_ci last_ts = amdgpu_ih_decode_iv_ts(adev, ih, last_wptr, -1); 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci hash = hash_64(key, AMDGPU_GMC_FAULT_HASH_ORDER); 46462306a36Sopenharmony_ci fault = &gmc->fault_ring[gmc->fault_hash[hash].idx]; 46562306a36Sopenharmony_ci do { 46662306a36Sopenharmony_ci if (atomic64_read(&fault->key) == key) { 46762306a36Sopenharmony_ci /* 46862306a36Sopenharmony_ci * Update the timestamp when this fault 46962306a36Sopenharmony_ci * expired. 47062306a36Sopenharmony_ci */ 47162306a36Sopenharmony_ci fault->timestamp_expiry = last_ts; 47262306a36Sopenharmony_ci break; 47362306a36Sopenharmony_ci } 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci tmp = fault->timestamp; 47662306a36Sopenharmony_ci fault = &gmc->fault_ring[fault->next]; 47762306a36Sopenharmony_ci } while (fault->timestamp < tmp); 47862306a36Sopenharmony_ci} 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_ciint amdgpu_gmc_ras_sw_init(struct amdgpu_device *adev) 48162306a36Sopenharmony_ci{ 48262306a36Sopenharmony_ci int r; 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ci /* umc ras block */ 48562306a36Sopenharmony_ci r = amdgpu_umc_ras_sw_init(adev); 48662306a36Sopenharmony_ci if (r) 48762306a36Sopenharmony_ci return r; 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci /* mmhub ras block */ 49062306a36Sopenharmony_ci r = amdgpu_mmhub_ras_sw_init(adev); 49162306a36Sopenharmony_ci if (r) 49262306a36Sopenharmony_ci return r; 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci /* hdp ras block */ 49562306a36Sopenharmony_ci r = amdgpu_hdp_ras_sw_init(adev); 49662306a36Sopenharmony_ci if (r) 49762306a36Sopenharmony_ci return r; 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci /* mca.x ras block */ 50062306a36Sopenharmony_ci r = amdgpu_mca_mp0_ras_sw_init(adev); 50162306a36Sopenharmony_ci if (r) 50262306a36Sopenharmony_ci return r; 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci r = amdgpu_mca_mp1_ras_sw_init(adev); 50562306a36Sopenharmony_ci if (r) 50662306a36Sopenharmony_ci return r; 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci r = amdgpu_mca_mpio_ras_sw_init(adev); 50962306a36Sopenharmony_ci if (r) 51062306a36Sopenharmony_ci return r; 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci /* xgmi ras block */ 51362306a36Sopenharmony_ci r = amdgpu_xgmi_ras_sw_init(adev); 51462306a36Sopenharmony_ci if (r) 51562306a36Sopenharmony_ci return r; 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci return 0; 51862306a36Sopenharmony_ci} 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ciint amdgpu_gmc_ras_late_init(struct amdgpu_device *adev) 52162306a36Sopenharmony_ci{ 52262306a36Sopenharmony_ci return 0; 52362306a36Sopenharmony_ci} 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_civoid amdgpu_gmc_ras_fini(struct amdgpu_device *adev) 52662306a36Sopenharmony_ci{ 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci} 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ci /* 53162306a36Sopenharmony_ci * The latest engine allocation on gfx9/10 is: 53262306a36Sopenharmony_ci * Engine 2, 3: firmware 53362306a36Sopenharmony_ci * Engine 0, 1, 4~16: amdgpu ring, 53462306a36Sopenharmony_ci * subject to change when ring number changes 53562306a36Sopenharmony_ci * Engine 17: Gart flushes 53662306a36Sopenharmony_ci */ 53762306a36Sopenharmony_ci#define AMDGPU_VMHUB_INV_ENG_BITMAP 0x1FFF3 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ciint amdgpu_gmc_allocate_vm_inv_eng(struct amdgpu_device *adev) 54062306a36Sopenharmony_ci{ 54162306a36Sopenharmony_ci struct amdgpu_ring *ring; 54262306a36Sopenharmony_ci unsigned vm_inv_engs[AMDGPU_MAX_VMHUBS] = {0}; 54362306a36Sopenharmony_ci unsigned i; 54462306a36Sopenharmony_ci unsigned vmhub, inv_eng; 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_ci /* init the vm inv eng for all vmhubs */ 54762306a36Sopenharmony_ci for_each_set_bit(i, adev->vmhubs_mask, AMDGPU_MAX_VMHUBS) { 54862306a36Sopenharmony_ci vm_inv_engs[i] = AMDGPU_VMHUB_INV_ENG_BITMAP; 54962306a36Sopenharmony_ci /* reserve engine 5 for firmware */ 55062306a36Sopenharmony_ci if (adev->enable_mes) 55162306a36Sopenharmony_ci vm_inv_engs[i] &= ~(1 << 5); 55262306a36Sopenharmony_ci } 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci for (i = 0; i < adev->num_rings; ++i) { 55562306a36Sopenharmony_ci ring = adev->rings[i]; 55662306a36Sopenharmony_ci vmhub = ring->vm_hub; 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci if (ring == &adev->mes.ring) 55962306a36Sopenharmony_ci continue; 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci inv_eng = ffs(vm_inv_engs[vmhub]); 56262306a36Sopenharmony_ci if (!inv_eng) { 56362306a36Sopenharmony_ci dev_err(adev->dev, "no VM inv eng for ring %s\n", 56462306a36Sopenharmony_ci ring->name); 56562306a36Sopenharmony_ci return -EINVAL; 56662306a36Sopenharmony_ci } 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci ring->vm_inv_eng = inv_eng - 1; 56962306a36Sopenharmony_ci vm_inv_engs[vmhub] &= ~(1 << ring->vm_inv_eng); 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci dev_info(adev->dev, "ring %s uses VM inv eng %u on hub %u\n", 57262306a36Sopenharmony_ci ring->name, ring->vm_inv_eng, ring->vm_hub); 57362306a36Sopenharmony_ci } 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci return 0; 57662306a36Sopenharmony_ci} 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_ci/** 57962306a36Sopenharmony_ci * amdgpu_gmc_tmz_set -- check and set if a device supports TMZ 58062306a36Sopenharmony_ci * @adev: amdgpu_device pointer 58162306a36Sopenharmony_ci * 58262306a36Sopenharmony_ci * Check and set if an the device @adev supports Trusted Memory 58362306a36Sopenharmony_ci * Zones (TMZ). 58462306a36Sopenharmony_ci */ 58562306a36Sopenharmony_civoid amdgpu_gmc_tmz_set(struct amdgpu_device *adev) 58662306a36Sopenharmony_ci{ 58762306a36Sopenharmony_ci switch (adev->ip_versions[GC_HWIP][0]) { 58862306a36Sopenharmony_ci /* RAVEN */ 58962306a36Sopenharmony_ci case IP_VERSION(9, 2, 2): 59062306a36Sopenharmony_ci case IP_VERSION(9, 1, 0): 59162306a36Sopenharmony_ci /* RENOIR looks like RAVEN */ 59262306a36Sopenharmony_ci case IP_VERSION(9, 3, 0): 59362306a36Sopenharmony_ci /* GC 10.3.7 */ 59462306a36Sopenharmony_ci case IP_VERSION(10, 3, 7): 59562306a36Sopenharmony_ci /* GC 11.0.1 */ 59662306a36Sopenharmony_ci case IP_VERSION(11, 0, 1): 59762306a36Sopenharmony_ci if (amdgpu_tmz == 0) { 59862306a36Sopenharmony_ci adev->gmc.tmz_enabled = false; 59962306a36Sopenharmony_ci dev_info(adev->dev, 60062306a36Sopenharmony_ci "Trusted Memory Zone (TMZ) feature disabled (cmd line)\n"); 60162306a36Sopenharmony_ci } else { 60262306a36Sopenharmony_ci adev->gmc.tmz_enabled = true; 60362306a36Sopenharmony_ci dev_info(adev->dev, 60462306a36Sopenharmony_ci "Trusted Memory Zone (TMZ) feature enabled\n"); 60562306a36Sopenharmony_ci } 60662306a36Sopenharmony_ci break; 60762306a36Sopenharmony_ci case IP_VERSION(10, 1, 10): 60862306a36Sopenharmony_ci case IP_VERSION(10, 1, 1): 60962306a36Sopenharmony_ci case IP_VERSION(10, 1, 2): 61062306a36Sopenharmony_ci case IP_VERSION(10, 1, 3): 61162306a36Sopenharmony_ci case IP_VERSION(10, 3, 0): 61262306a36Sopenharmony_ci case IP_VERSION(10, 3, 2): 61362306a36Sopenharmony_ci case IP_VERSION(10, 3, 4): 61462306a36Sopenharmony_ci case IP_VERSION(10, 3, 5): 61562306a36Sopenharmony_ci case IP_VERSION(10, 3, 6): 61662306a36Sopenharmony_ci /* VANGOGH */ 61762306a36Sopenharmony_ci case IP_VERSION(10, 3, 1): 61862306a36Sopenharmony_ci /* YELLOW_CARP*/ 61962306a36Sopenharmony_ci case IP_VERSION(10, 3, 3): 62062306a36Sopenharmony_ci case IP_VERSION(11, 0, 4): 62162306a36Sopenharmony_ci /* Don't enable it by default yet. 62262306a36Sopenharmony_ci */ 62362306a36Sopenharmony_ci if (amdgpu_tmz < 1) { 62462306a36Sopenharmony_ci adev->gmc.tmz_enabled = false; 62562306a36Sopenharmony_ci dev_info(adev->dev, 62662306a36Sopenharmony_ci "Trusted Memory Zone (TMZ) feature disabled as experimental (default)\n"); 62762306a36Sopenharmony_ci } else { 62862306a36Sopenharmony_ci adev->gmc.tmz_enabled = true; 62962306a36Sopenharmony_ci dev_info(adev->dev, 63062306a36Sopenharmony_ci "Trusted Memory Zone (TMZ) feature enabled as experimental (cmd line)\n"); 63162306a36Sopenharmony_ci } 63262306a36Sopenharmony_ci break; 63362306a36Sopenharmony_ci default: 63462306a36Sopenharmony_ci adev->gmc.tmz_enabled = false; 63562306a36Sopenharmony_ci dev_info(adev->dev, 63662306a36Sopenharmony_ci "Trusted Memory Zone (TMZ) feature not supported\n"); 63762306a36Sopenharmony_ci break; 63862306a36Sopenharmony_ci } 63962306a36Sopenharmony_ci} 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci/** 64262306a36Sopenharmony_ci * amdgpu_gmc_noretry_set -- set per asic noretry defaults 64362306a36Sopenharmony_ci * @adev: amdgpu_device pointer 64462306a36Sopenharmony_ci * 64562306a36Sopenharmony_ci * Set a per asic default for the no-retry parameter. 64662306a36Sopenharmony_ci * 64762306a36Sopenharmony_ci */ 64862306a36Sopenharmony_civoid amdgpu_gmc_noretry_set(struct amdgpu_device *adev) 64962306a36Sopenharmony_ci{ 65062306a36Sopenharmony_ci struct amdgpu_gmc *gmc = &adev->gmc; 65162306a36Sopenharmony_ci uint32_t gc_ver = adev->ip_versions[GC_HWIP][0]; 65262306a36Sopenharmony_ci bool noretry_default = (gc_ver == IP_VERSION(9, 0, 1) || 65362306a36Sopenharmony_ci gc_ver == IP_VERSION(9, 3, 0) || 65462306a36Sopenharmony_ci gc_ver == IP_VERSION(9, 4, 0) || 65562306a36Sopenharmony_ci gc_ver == IP_VERSION(9, 4, 1) || 65662306a36Sopenharmony_ci gc_ver == IP_VERSION(9, 4, 2) || 65762306a36Sopenharmony_ci gc_ver == IP_VERSION(9, 4, 3) || 65862306a36Sopenharmony_ci gc_ver >= IP_VERSION(10, 3, 0)); 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_ci gmc->noretry = (amdgpu_noretry == -1) ? noretry_default : amdgpu_noretry; 66162306a36Sopenharmony_ci} 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_civoid amdgpu_gmc_set_vm_fault_masks(struct amdgpu_device *adev, int hub_type, 66462306a36Sopenharmony_ci bool enable) 66562306a36Sopenharmony_ci{ 66662306a36Sopenharmony_ci struct amdgpu_vmhub *hub; 66762306a36Sopenharmony_ci u32 tmp, reg, i; 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_ci hub = &adev->vmhub[hub_type]; 67062306a36Sopenharmony_ci for (i = 0; i < 16; i++) { 67162306a36Sopenharmony_ci reg = hub->vm_context0_cntl + hub->ctx_distance * i; 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_ci tmp = (hub_type == AMDGPU_GFXHUB(0)) ? 67462306a36Sopenharmony_ci RREG32_SOC15_IP(GC, reg) : 67562306a36Sopenharmony_ci RREG32_SOC15_IP(MMHUB, reg); 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_ci if (enable) 67862306a36Sopenharmony_ci tmp |= hub->vm_cntx_cntl_vm_fault; 67962306a36Sopenharmony_ci else 68062306a36Sopenharmony_ci tmp &= ~hub->vm_cntx_cntl_vm_fault; 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_ci (hub_type == AMDGPU_GFXHUB(0)) ? 68362306a36Sopenharmony_ci WREG32_SOC15_IP(GC, reg, tmp) : 68462306a36Sopenharmony_ci WREG32_SOC15_IP(MMHUB, reg, tmp); 68562306a36Sopenharmony_ci } 68662306a36Sopenharmony_ci} 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_civoid amdgpu_gmc_get_vbios_allocations(struct amdgpu_device *adev) 68962306a36Sopenharmony_ci{ 69062306a36Sopenharmony_ci unsigned size; 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_ci /* 69362306a36Sopenharmony_ci * Some ASICs need to reserve a region of video memory to avoid access 69462306a36Sopenharmony_ci * from driver 69562306a36Sopenharmony_ci */ 69662306a36Sopenharmony_ci adev->mman.stolen_reserved_offset = 0; 69762306a36Sopenharmony_ci adev->mman.stolen_reserved_size = 0; 69862306a36Sopenharmony_ci 69962306a36Sopenharmony_ci /* 70062306a36Sopenharmony_ci * TODO: 70162306a36Sopenharmony_ci * Currently there is a bug where some memory client outside 70262306a36Sopenharmony_ci * of the driver writes to first 8M of VRAM on S3 resume, 70362306a36Sopenharmony_ci * this overrides GART which by default gets placed in first 8M and 70462306a36Sopenharmony_ci * causes VM_FAULTS once GTT is accessed. 70562306a36Sopenharmony_ci * Keep the stolen memory reservation until the while this is not solved. 70662306a36Sopenharmony_ci */ 70762306a36Sopenharmony_ci switch (adev->asic_type) { 70862306a36Sopenharmony_ci case CHIP_VEGA10: 70962306a36Sopenharmony_ci adev->mman.keep_stolen_vga_memory = true; 71062306a36Sopenharmony_ci /* 71162306a36Sopenharmony_ci * VEGA10 SRIOV VF with MS_HYPERV host needs some firmware reserved area. 71262306a36Sopenharmony_ci */ 71362306a36Sopenharmony_ci#ifdef CONFIG_X86 71462306a36Sopenharmony_ci if (amdgpu_sriov_vf(adev) && hypervisor_is_type(X86_HYPER_MS_HYPERV)) { 71562306a36Sopenharmony_ci adev->mman.stolen_reserved_offset = 0x500000; 71662306a36Sopenharmony_ci adev->mman.stolen_reserved_size = 0x200000; 71762306a36Sopenharmony_ci } 71862306a36Sopenharmony_ci#endif 71962306a36Sopenharmony_ci break; 72062306a36Sopenharmony_ci case CHIP_RAVEN: 72162306a36Sopenharmony_ci case CHIP_RENOIR: 72262306a36Sopenharmony_ci adev->mman.keep_stolen_vga_memory = true; 72362306a36Sopenharmony_ci break; 72462306a36Sopenharmony_ci case CHIP_YELLOW_CARP: 72562306a36Sopenharmony_ci if (amdgpu_discovery == 0) { 72662306a36Sopenharmony_ci adev->mman.stolen_reserved_offset = 0x1ffb0000; 72762306a36Sopenharmony_ci adev->mman.stolen_reserved_size = 64 * PAGE_SIZE; 72862306a36Sopenharmony_ci } 72962306a36Sopenharmony_ci break; 73062306a36Sopenharmony_ci default: 73162306a36Sopenharmony_ci adev->mman.keep_stolen_vga_memory = false; 73262306a36Sopenharmony_ci break; 73362306a36Sopenharmony_ci } 73462306a36Sopenharmony_ci 73562306a36Sopenharmony_ci if (amdgpu_sriov_vf(adev) || 73662306a36Sopenharmony_ci !amdgpu_device_has_display_hardware(adev)) { 73762306a36Sopenharmony_ci size = 0; 73862306a36Sopenharmony_ci } else { 73962306a36Sopenharmony_ci size = amdgpu_gmc_get_vbios_fb_size(adev); 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_ci if (adev->mman.keep_stolen_vga_memory) 74262306a36Sopenharmony_ci size = max(size, (unsigned)AMDGPU_VBIOS_VGA_ALLOCATION); 74362306a36Sopenharmony_ci } 74462306a36Sopenharmony_ci 74562306a36Sopenharmony_ci /* set to 0 if the pre-OS buffer uses up most of vram */ 74662306a36Sopenharmony_ci if ((adev->gmc.real_vram_size - size) < (8 * 1024 * 1024)) 74762306a36Sopenharmony_ci size = 0; 74862306a36Sopenharmony_ci 74962306a36Sopenharmony_ci if (size > AMDGPU_VBIOS_VGA_ALLOCATION) { 75062306a36Sopenharmony_ci adev->mman.stolen_vga_size = AMDGPU_VBIOS_VGA_ALLOCATION; 75162306a36Sopenharmony_ci adev->mman.stolen_extended_size = size - adev->mman.stolen_vga_size; 75262306a36Sopenharmony_ci } else { 75362306a36Sopenharmony_ci adev->mman.stolen_vga_size = size; 75462306a36Sopenharmony_ci adev->mman.stolen_extended_size = 0; 75562306a36Sopenharmony_ci } 75662306a36Sopenharmony_ci} 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_ci/** 75962306a36Sopenharmony_ci * amdgpu_gmc_init_pdb0 - initialize PDB0 76062306a36Sopenharmony_ci * 76162306a36Sopenharmony_ci * @adev: amdgpu_device pointer 76262306a36Sopenharmony_ci * 76362306a36Sopenharmony_ci * This function is only used when GART page table is used 76462306a36Sopenharmony_ci * for FB address translatioin. In such a case, we construct 76562306a36Sopenharmony_ci * a 2-level system VM page table: PDB0->PTB, to cover both 76662306a36Sopenharmony_ci * VRAM of the hive and system memory. 76762306a36Sopenharmony_ci * 76862306a36Sopenharmony_ci * PDB0 is static, initialized once on driver initialization. 76962306a36Sopenharmony_ci * The first n entries of PDB0 are used as PTE by setting 77062306a36Sopenharmony_ci * P bit to 1, pointing to VRAM. The n+1'th entry points 77162306a36Sopenharmony_ci * to a big PTB covering system memory. 77262306a36Sopenharmony_ci * 77362306a36Sopenharmony_ci */ 77462306a36Sopenharmony_civoid amdgpu_gmc_init_pdb0(struct amdgpu_device *adev) 77562306a36Sopenharmony_ci{ 77662306a36Sopenharmony_ci int i; 77762306a36Sopenharmony_ci uint64_t flags = adev->gart.gart_pte_flags; //TODO it is UC. explore NC/RW? 77862306a36Sopenharmony_ci /* Each PDE0 (used as PTE) covers (2^vmid0_page_table_block_size)*2M 77962306a36Sopenharmony_ci */ 78062306a36Sopenharmony_ci u64 vram_size = adev->gmc.xgmi.node_segment_size * adev->gmc.xgmi.num_physical_nodes; 78162306a36Sopenharmony_ci u64 pde0_page_size = (1ULL<<adev->gmc.vmid0_page_table_block_size)<<21; 78262306a36Sopenharmony_ci u64 vram_addr = adev->vm_manager.vram_base_offset - 78362306a36Sopenharmony_ci adev->gmc.xgmi.physical_node_id * adev->gmc.xgmi.node_segment_size; 78462306a36Sopenharmony_ci u64 vram_end = vram_addr + vram_size; 78562306a36Sopenharmony_ci u64 gart_ptb_gpu_pa = amdgpu_gmc_vram_pa(adev, adev->gart.bo); 78662306a36Sopenharmony_ci int idx; 78762306a36Sopenharmony_ci 78862306a36Sopenharmony_ci if (!drm_dev_enter(adev_to_drm(adev), &idx)) 78962306a36Sopenharmony_ci return; 79062306a36Sopenharmony_ci 79162306a36Sopenharmony_ci flags |= AMDGPU_PTE_VALID | AMDGPU_PTE_READABLE; 79262306a36Sopenharmony_ci flags |= AMDGPU_PTE_WRITEABLE; 79362306a36Sopenharmony_ci flags |= AMDGPU_PTE_SNOOPED; 79462306a36Sopenharmony_ci flags |= AMDGPU_PTE_FRAG((adev->gmc.vmid0_page_table_block_size + 9*1)); 79562306a36Sopenharmony_ci flags |= AMDGPU_PDE_PTE; 79662306a36Sopenharmony_ci 79762306a36Sopenharmony_ci /* The first n PDE0 entries are used as PTE, 79862306a36Sopenharmony_ci * pointing to vram 79962306a36Sopenharmony_ci */ 80062306a36Sopenharmony_ci for (i = 0; vram_addr < vram_end; i++, vram_addr += pde0_page_size) 80162306a36Sopenharmony_ci amdgpu_gmc_set_pte_pde(adev, adev->gmc.ptr_pdb0, i, vram_addr, flags); 80262306a36Sopenharmony_ci 80362306a36Sopenharmony_ci /* The n+1'th PDE0 entry points to a huge 80462306a36Sopenharmony_ci * PTB who has more than 512 entries each 80562306a36Sopenharmony_ci * pointing to a 4K system page 80662306a36Sopenharmony_ci */ 80762306a36Sopenharmony_ci flags = AMDGPU_PTE_VALID; 80862306a36Sopenharmony_ci flags |= AMDGPU_PDE_BFS(0) | AMDGPU_PTE_SNOOPED; 80962306a36Sopenharmony_ci /* Requires gart_ptb_gpu_pa to be 4K aligned */ 81062306a36Sopenharmony_ci amdgpu_gmc_set_pte_pde(adev, adev->gmc.ptr_pdb0, i, gart_ptb_gpu_pa, flags); 81162306a36Sopenharmony_ci drm_dev_exit(idx); 81262306a36Sopenharmony_ci} 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_ci/** 81562306a36Sopenharmony_ci * amdgpu_gmc_vram_mc2pa - calculate vram buffer's physical address from MC 81662306a36Sopenharmony_ci * address 81762306a36Sopenharmony_ci * 81862306a36Sopenharmony_ci * @adev: amdgpu_device pointer 81962306a36Sopenharmony_ci * @mc_addr: MC address of buffer 82062306a36Sopenharmony_ci */ 82162306a36Sopenharmony_ciuint64_t amdgpu_gmc_vram_mc2pa(struct amdgpu_device *adev, uint64_t mc_addr) 82262306a36Sopenharmony_ci{ 82362306a36Sopenharmony_ci return mc_addr - adev->gmc.vram_start + adev->vm_manager.vram_base_offset; 82462306a36Sopenharmony_ci} 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_ci/** 82762306a36Sopenharmony_ci * amdgpu_gmc_vram_pa - calculate vram buffer object's physical address from 82862306a36Sopenharmony_ci * GPU's view 82962306a36Sopenharmony_ci * 83062306a36Sopenharmony_ci * @adev: amdgpu_device pointer 83162306a36Sopenharmony_ci * @bo: amdgpu buffer object 83262306a36Sopenharmony_ci */ 83362306a36Sopenharmony_ciuint64_t amdgpu_gmc_vram_pa(struct amdgpu_device *adev, struct amdgpu_bo *bo) 83462306a36Sopenharmony_ci{ 83562306a36Sopenharmony_ci return amdgpu_gmc_vram_mc2pa(adev, amdgpu_bo_gpu_offset(bo)); 83662306a36Sopenharmony_ci} 83762306a36Sopenharmony_ci 83862306a36Sopenharmony_ci/** 83962306a36Sopenharmony_ci * amdgpu_gmc_vram_cpu_pa - calculate vram buffer object's physical address 84062306a36Sopenharmony_ci * from CPU's view 84162306a36Sopenharmony_ci * 84262306a36Sopenharmony_ci * @adev: amdgpu_device pointer 84362306a36Sopenharmony_ci * @bo: amdgpu buffer object 84462306a36Sopenharmony_ci */ 84562306a36Sopenharmony_ciuint64_t amdgpu_gmc_vram_cpu_pa(struct amdgpu_device *adev, struct amdgpu_bo *bo) 84662306a36Sopenharmony_ci{ 84762306a36Sopenharmony_ci return amdgpu_bo_gpu_offset(bo) - adev->gmc.vram_start + adev->gmc.aper_base; 84862306a36Sopenharmony_ci} 84962306a36Sopenharmony_ci 85062306a36Sopenharmony_ciint amdgpu_gmc_vram_checking(struct amdgpu_device *adev) 85162306a36Sopenharmony_ci{ 85262306a36Sopenharmony_ci struct amdgpu_bo *vram_bo = NULL; 85362306a36Sopenharmony_ci uint64_t vram_gpu = 0; 85462306a36Sopenharmony_ci void *vram_ptr = NULL; 85562306a36Sopenharmony_ci 85662306a36Sopenharmony_ci int ret, size = 0x100000; 85762306a36Sopenharmony_ci uint8_t cptr[10]; 85862306a36Sopenharmony_ci 85962306a36Sopenharmony_ci ret = amdgpu_bo_create_kernel(adev, size, PAGE_SIZE, 86062306a36Sopenharmony_ci AMDGPU_GEM_DOMAIN_VRAM, 86162306a36Sopenharmony_ci &vram_bo, 86262306a36Sopenharmony_ci &vram_gpu, 86362306a36Sopenharmony_ci &vram_ptr); 86462306a36Sopenharmony_ci if (ret) 86562306a36Sopenharmony_ci return ret; 86662306a36Sopenharmony_ci 86762306a36Sopenharmony_ci memset(vram_ptr, 0x86, size); 86862306a36Sopenharmony_ci memset(cptr, 0x86, 10); 86962306a36Sopenharmony_ci 87062306a36Sopenharmony_ci /** 87162306a36Sopenharmony_ci * Check the start, the mid, and the end of the memory if the content of 87262306a36Sopenharmony_ci * each byte is the pattern "0x86". If yes, we suppose the vram bo is 87362306a36Sopenharmony_ci * workable. 87462306a36Sopenharmony_ci * 87562306a36Sopenharmony_ci * Note: If check the each byte of whole 1M bo, it will cost too many 87662306a36Sopenharmony_ci * seconds, so here, we just pick up three parts for emulation. 87762306a36Sopenharmony_ci */ 87862306a36Sopenharmony_ci ret = memcmp(vram_ptr, cptr, 10); 87962306a36Sopenharmony_ci if (ret) { 88062306a36Sopenharmony_ci ret = -EIO; 88162306a36Sopenharmony_ci goto release_buffer; 88262306a36Sopenharmony_ci } 88362306a36Sopenharmony_ci 88462306a36Sopenharmony_ci ret = memcmp(vram_ptr + (size / 2), cptr, 10); 88562306a36Sopenharmony_ci if (ret) { 88662306a36Sopenharmony_ci ret = -EIO; 88762306a36Sopenharmony_ci goto release_buffer; 88862306a36Sopenharmony_ci } 88962306a36Sopenharmony_ci 89062306a36Sopenharmony_ci ret = memcmp(vram_ptr + size - 10, cptr, 10); 89162306a36Sopenharmony_ci if (ret) { 89262306a36Sopenharmony_ci ret = -EIO; 89362306a36Sopenharmony_ci goto release_buffer; 89462306a36Sopenharmony_ci } 89562306a36Sopenharmony_ci 89662306a36Sopenharmony_cirelease_buffer: 89762306a36Sopenharmony_ci amdgpu_bo_free_kernel(&vram_bo, &vram_gpu, 89862306a36Sopenharmony_ci &vram_ptr); 89962306a36Sopenharmony_ci 90062306a36Sopenharmony_ci return ret; 90162306a36Sopenharmony_ci} 90262306a36Sopenharmony_ci 90362306a36Sopenharmony_cistatic ssize_t current_memory_partition_show( 90462306a36Sopenharmony_ci struct device *dev, struct device_attribute *addr, char *buf) 90562306a36Sopenharmony_ci{ 90662306a36Sopenharmony_ci struct drm_device *ddev = dev_get_drvdata(dev); 90762306a36Sopenharmony_ci struct amdgpu_device *adev = drm_to_adev(ddev); 90862306a36Sopenharmony_ci enum amdgpu_memory_partition mode; 90962306a36Sopenharmony_ci 91062306a36Sopenharmony_ci mode = adev->gmc.gmc_funcs->query_mem_partition_mode(adev); 91162306a36Sopenharmony_ci switch (mode) { 91262306a36Sopenharmony_ci case AMDGPU_NPS1_PARTITION_MODE: 91362306a36Sopenharmony_ci return sysfs_emit(buf, "NPS1\n"); 91462306a36Sopenharmony_ci case AMDGPU_NPS2_PARTITION_MODE: 91562306a36Sopenharmony_ci return sysfs_emit(buf, "NPS2\n"); 91662306a36Sopenharmony_ci case AMDGPU_NPS3_PARTITION_MODE: 91762306a36Sopenharmony_ci return sysfs_emit(buf, "NPS3\n"); 91862306a36Sopenharmony_ci case AMDGPU_NPS4_PARTITION_MODE: 91962306a36Sopenharmony_ci return sysfs_emit(buf, "NPS4\n"); 92062306a36Sopenharmony_ci case AMDGPU_NPS6_PARTITION_MODE: 92162306a36Sopenharmony_ci return sysfs_emit(buf, "NPS6\n"); 92262306a36Sopenharmony_ci case AMDGPU_NPS8_PARTITION_MODE: 92362306a36Sopenharmony_ci return sysfs_emit(buf, "NPS8\n"); 92462306a36Sopenharmony_ci default: 92562306a36Sopenharmony_ci return sysfs_emit(buf, "UNKNOWN\n"); 92662306a36Sopenharmony_ci } 92762306a36Sopenharmony_ci 92862306a36Sopenharmony_ci return sysfs_emit(buf, "UNKNOWN\n"); 92962306a36Sopenharmony_ci} 93062306a36Sopenharmony_ci 93162306a36Sopenharmony_cistatic DEVICE_ATTR_RO(current_memory_partition); 93262306a36Sopenharmony_ci 93362306a36Sopenharmony_ciint amdgpu_gmc_sysfs_init(struct amdgpu_device *adev) 93462306a36Sopenharmony_ci{ 93562306a36Sopenharmony_ci if (!adev->gmc.gmc_funcs->query_mem_partition_mode) 93662306a36Sopenharmony_ci return 0; 93762306a36Sopenharmony_ci 93862306a36Sopenharmony_ci return device_create_file(adev->dev, 93962306a36Sopenharmony_ci &dev_attr_current_memory_partition); 94062306a36Sopenharmony_ci} 94162306a36Sopenharmony_ci 94262306a36Sopenharmony_civoid amdgpu_gmc_sysfs_fini(struct amdgpu_device *adev) 94362306a36Sopenharmony_ci{ 94462306a36Sopenharmony_ci device_remove_file(adev->dev, &dev_attr_current_memory_partition); 94562306a36Sopenharmony_ci} 946