1 /* 2 * Copyright 2018 Advanced Micro Devices, Inc. 3 * All Rights Reserved. 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining a 6 * copy of this software and associated documentation files (the 7 * "Software"), to deal in the Software without restriction, including 8 * without limitation the rights to use, copy, modify, merge, publish, 9 * distribute, sub license, and/or sell copies of the Software, and to 10 * permit persons to whom the Software is furnished to do so, subject to 11 * the following conditions: 12 * 13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 16 * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, 17 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 18 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 19 * USE OR OTHER DEALINGS IN THE SOFTWARE. 20 * 21 * The above copyright notice and this permission notice (including the 22 * next paragraph) shall be included in all copies or substantial portions 23 * of the Software. 24 * 25 */ 26 27 #include "amdgpu.h" 28 29 /** 30 * amdgpu_gmc_get_pde_for_bo - get the PDE for a BO 31 * 32 * @bo: the BO to get the PDE for 33 * @level: the level in the PD hirarchy 34 * @addr: resulting addr 35 * @flags: resulting flags 36 * 37 * Get the address and flags to be used for a PDE (Page Directory Entry). 38 */ 39 void amdgpu_gmc_get_pde_for_bo(struct amdgpu_bo *bo, int level, 40 uint64_t *addr, uint64_t *flags) 41 { 42 struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev); 43 struct ttm_dma_tt *ttm; 44 45 switch (bo->tbo.mem.mem_type) { 46 case TTM_PL_TT: 47 ttm = container_of(bo->tbo.ttm, struct ttm_dma_tt, ttm); 48 *addr = ttm->dma_address[0]; 49 break; 50 case TTM_PL_VRAM: 51 *addr = amdgpu_bo_gpu_offset(bo); 52 break; 53 default: 54 *addr = 0; 55 break; 56 } 57 *flags = amdgpu_ttm_tt_pde_flags(bo->tbo.ttm, &bo->tbo.mem); 58 amdgpu_gmc_get_vm_pde(adev, level, addr, flags); 59 } 60 61 /** 62 * amdgpu_gmc_pd_addr - return the address of the root directory 63 * 64 */ 65 uint64_t amdgpu_gmc_pd_addr(struct amdgpu_bo *bo) 66 { 67 struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev); 68 uint64_t pd_addr; 69 70 /* TODO: move that into ASIC specific code */ 71 if (adev->asic_type >= CHIP_VEGA10) { 72 uint64_t flags = AMDGPU_PTE_VALID; 73 74 amdgpu_gmc_get_pde_for_bo(bo, -1, &pd_addr, &flags); 75 pd_addr |= flags; 76 } else { 77 pd_addr = amdgpu_bo_gpu_offset(bo); 78 } 79 return pd_addr; 80 } 81 82 /** 83 * amdgpu_gmc_agp_addr - return the address in the AGP address space 84 * 85 * @tbo: TTM BO which needs the address, must be in GTT domain 86 * 87 * Tries to figure out how to access the BO through the AGP aperture. Returns 88 * AMDGPU_BO_INVALID_OFFSET if that is not possible. 89 */ 90 uint64_t amdgpu_gmc_agp_addr(struct ttm_buffer_object *bo) 91 { 92 struct amdgpu_device *adev = amdgpu_ttm_adev(bo->bdev); 93 struct ttm_dma_tt *ttm; 94 95 if (bo->num_pages != 1 || bo->ttm->caching_state == tt_cached) 96 return AMDGPU_BO_INVALID_OFFSET; 97 98 ttm = container_of(bo->ttm, struct ttm_dma_tt, ttm); 99 if (ttm->dma_address[0] + PAGE_SIZE >= adev->gmc.agp_size) 100 return AMDGPU_BO_INVALID_OFFSET; 101 102 return adev->gmc.agp_start + ttm->dma_address[0]; 103 } 104 105 /** 106 * amdgpu_gmc_vram_location - try to find VRAM location 107 * 108 * @adev: amdgpu device structure holding all necessary informations 109 * @mc: memory controller structure holding memory informations 110 * @base: base address at which to put VRAM 111 * 112 * Function will try to place VRAM at base address provided 113 * as parameter. 114 */ 115 void amdgpu_gmc_vram_location(struct amdgpu_device *adev, struct amdgpu_gmc *mc, 116 u64 base) 117 { 118 uint64_t limit = (uint64_t)amdgpu_vram_limit << 20; 119 120 mc->vram_start = base; 121 mc->vram_end = mc->vram_start + mc->mc_vram_size - 1; 122 if (limit && limit < mc->real_vram_size) 123 mc->real_vram_size = limit; 124 125 if (mc->xgmi.num_physical_nodes == 0) { 126 mc->fb_start = mc->vram_start; 127 mc->fb_end = mc->vram_end; 128 } 129 dev_info(adev->dev, "VRAM: %lluM 0x%016llX - 0x%016llX (%lluM used)\n", 130 mc->mc_vram_size >> 20, mc->vram_start, 131 mc->vram_end, mc->real_vram_size >> 20); 132 } 133 134 /** 135 * amdgpu_gmc_gart_location - try to find GART location 136 * 137 * @adev: amdgpu device structure holding all necessary informations 138 * @mc: memory controller structure holding memory informations 139 * 140 * Function will place try to place GART before or after VRAM. 141 * 142 * If GART size is bigger than space left then we ajust GART size. 143 * Thus function will never fails. 144 */ 145 void amdgpu_gmc_gart_location(struct amdgpu_device *adev, struct amdgpu_gmc *mc) 146 { 147 const uint64_t four_gb = 0x100000000ULL; 148 u64 size_af, size_bf; 149 /*To avoid the hole, limit the max mc address to AMDGPU_GMC_HOLE_START*/ 150 u64 max_mc_address = min(adev->gmc.mc_mask, AMDGPU_GMC_HOLE_START - 1); 151 152 mc->gart_size += adev->pm.smu_prv_buffer_size; 153 154 /* VCE doesn't like it when BOs cross a 4GB segment, so align 155 * the GART base on a 4GB boundary as well. 156 */ 157 size_bf = mc->fb_start; 158 size_af = max_mc_address + 1 - ALIGN(mc->fb_end + 1, four_gb); 159 160 if (mc->gart_size > max(size_bf, size_af)) { 161 dev_warn(adev->dev, "limiting GART\n"); 162 mc->gart_size = max(size_bf, size_af); 163 } 164 165 if ((size_bf >= mc->gart_size && size_bf < size_af) || 166 (size_af < mc->gart_size)) 167 mc->gart_start = 0; 168 else 169 mc->gart_start = max_mc_address - mc->gart_size + 1; 170 171 mc->gart_start &= ~(four_gb - 1); 172 mc->gart_end = mc->gart_start + mc->gart_size - 1; 173 dev_info(adev->dev, "GART: %lluM 0x%016llX - 0x%016llX\n", 174 mc->gart_size >> 20, mc->gart_start, mc->gart_end); 175 } 176 177 /** 178 * amdgpu_gmc_agp_location - try to find AGP location 179 * @adev: amdgpu device structure holding all necessary informations 180 * @mc: memory controller structure holding memory informations 181 * 182 * Function will place try to find a place for the AGP BAR in the MC address 183 * space. 184 * 185 * AGP BAR will be assigned the largest available hole in the address space. 186 * Should be called after VRAM and GART locations are setup. 187 */ 188 void amdgpu_gmc_agp_location(struct amdgpu_device *adev, struct amdgpu_gmc *mc) 189 { 190 const uint64_t sixteen_gb = 1ULL << 34; 191 const uint64_t sixteen_gb_mask = ~(sixteen_gb - 1); 192 u64 size_af, size_bf; 193 194 if (mc->fb_start > mc->gart_start) { 195 size_bf = (mc->fb_start & sixteen_gb_mask) - 196 ALIGN(mc->gart_end + 1, sixteen_gb); 197 size_af = mc->mc_mask + 1 - ALIGN(mc->fb_end + 1, sixteen_gb); 198 } else { 199 size_bf = mc->fb_start & sixteen_gb_mask; 200 size_af = (mc->gart_start & sixteen_gb_mask) - 201 ALIGN(mc->fb_end + 1, sixteen_gb); 202 } 203 204 if (size_bf > size_af) { 205 mc->agp_start = (mc->fb_start - size_bf) & sixteen_gb_mask; 206 mc->agp_size = size_bf; 207 } else { 208 mc->agp_start = ALIGN(mc->fb_end + 1, sixteen_gb); 209 mc->agp_size = size_af; 210 } 211 212 mc->agp_end = mc->agp_start + mc->agp_size - 1; 213 dev_info(adev->dev, "AGP: %lluM 0x%016llX - 0x%016llX\n", 214 mc->agp_size >> 20, mc->agp_start, mc->agp_end); 215 } 216