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 | |