diff options
author | Jiri Kosina <jkosina@suse.cz> | 2015-09-01 09:35:24 -0400 |
---|---|---|
committer | Jiri Kosina <jkosina@suse.cz> | 2015-09-01 09:35:24 -0400 |
commit | 067e2601d3c076abbf45db91261f9065eaa879b2 (patch) | |
tree | 86c8d4b913873dbd3b4ff23562a3a8597984b4df /drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c | |
parent | 3e097d1271ecdff2f251a54ddfc5eaa1f9821e96 (diff) | |
parent | 931830aa5c251e0803523213428f777a48bde254 (diff) |
Merge branch 'for-4.3/gembird' into for-linus
Diffstat (limited to 'drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c')
-rw-r--r-- | drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c | 371 |
1 files changed, 371 insertions, 0 deletions
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c new file mode 100644 index 000000000000..e02db0b2e839 --- /dev/null +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c | |||
@@ -0,0 +1,371 @@ | |||
1 | /* | ||
2 | * Copyright 2008 Advanced Micro Devices, Inc. | ||
3 | * Copyright 2008 Red Hat Inc. | ||
4 | * Copyright 2009 Jerome Glisse. | ||
5 | * | ||
6 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
7 | * copy of this software and associated documentation files (the "Software"), | ||
8 | * to deal in the Software without restriction, including without limitation | ||
9 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
10 | * and/or sell copies of the Software, and to permit persons to whom the | ||
11 | * Software is furnished to do so, subject to the following conditions: | ||
12 | * | ||
13 | * The above copyright notice and this permission notice shall be included in | ||
14 | * all copies or substantial portions of the Software. | ||
15 | * | ||
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
19 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR | ||
20 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | ||
21 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||
22 | * OTHER DEALINGS IN THE SOFTWARE. | ||
23 | * | ||
24 | * Authors: Dave Airlie | ||
25 | * Alex Deucher | ||
26 | * Jerome Glisse | ||
27 | */ | ||
28 | #include <drm/drmP.h> | ||
29 | #include <drm/amdgpu_drm.h> | ||
30 | #include "amdgpu.h" | ||
31 | |||
32 | /* | ||
33 | * GART | ||
34 | * The GART (Graphics Aperture Remapping Table) is an aperture | ||
35 | * in the GPU's address space. System pages can be mapped into | ||
36 | * the aperture and look like contiguous pages from the GPU's | ||
37 | * perspective. A page table maps the pages in the aperture | ||
38 | * to the actual backing pages in system memory. | ||
39 | * | ||
40 | * Radeon GPUs support both an internal GART, as described above, | ||
41 | * and AGP. AGP works similarly, but the GART table is configured | ||
42 | * and maintained by the northbridge rather than the driver. | ||
43 | * Radeon hw has a separate AGP aperture that is programmed to | ||
44 | * point to the AGP aperture provided by the northbridge and the | ||
45 | * requests are passed through to the northbridge aperture. | ||
46 | * Both AGP and internal GART can be used at the same time, however | ||
47 | * that is not currently supported by the driver. | ||
48 | * | ||
49 | * This file handles the common internal GART management. | ||
50 | */ | ||
51 | |||
52 | /* | ||
53 | * Common GART table functions. | ||
54 | */ | ||
55 | /** | ||
56 | * amdgpu_gart_table_ram_alloc - allocate system ram for gart page table | ||
57 | * | ||
58 | * @adev: amdgpu_device pointer | ||
59 | * | ||
60 | * Allocate system memory for GART page table | ||
61 | * (r1xx-r3xx, non-pcie r4xx, rs400). These asics require the | ||
62 | * gart table to be in system memory. | ||
63 | * Returns 0 for success, -ENOMEM for failure. | ||
64 | */ | ||
65 | int amdgpu_gart_table_ram_alloc(struct amdgpu_device *adev) | ||
66 | { | ||
67 | void *ptr; | ||
68 | |||
69 | ptr = pci_alloc_consistent(adev->pdev, adev->gart.table_size, | ||
70 | &adev->gart.table_addr); | ||
71 | if (ptr == NULL) { | ||
72 | return -ENOMEM; | ||
73 | } | ||
74 | #ifdef CONFIG_X86 | ||
75 | if (0) { | ||
76 | set_memory_uc((unsigned long)ptr, | ||
77 | adev->gart.table_size >> PAGE_SHIFT); | ||
78 | } | ||
79 | #endif | ||
80 | adev->gart.ptr = ptr; | ||
81 | memset((void *)adev->gart.ptr, 0, adev->gart.table_size); | ||
82 | return 0; | ||
83 | } | ||
84 | |||
85 | /** | ||
86 | * amdgpu_gart_table_ram_free - free system ram for gart page table | ||
87 | * | ||
88 | * @adev: amdgpu_device pointer | ||
89 | * | ||
90 | * Free system memory for GART page table | ||
91 | * (r1xx-r3xx, non-pcie r4xx, rs400). These asics require the | ||
92 | * gart table to be in system memory. | ||
93 | */ | ||
94 | void amdgpu_gart_table_ram_free(struct amdgpu_device *adev) | ||
95 | { | ||
96 | if (adev->gart.ptr == NULL) { | ||
97 | return; | ||
98 | } | ||
99 | #ifdef CONFIG_X86 | ||
100 | if (0) { | ||
101 | set_memory_wb((unsigned long)adev->gart.ptr, | ||
102 | adev->gart.table_size >> PAGE_SHIFT); | ||
103 | } | ||
104 | #endif | ||
105 | pci_free_consistent(adev->pdev, adev->gart.table_size, | ||
106 | (void *)adev->gart.ptr, | ||
107 | adev->gart.table_addr); | ||
108 | adev->gart.ptr = NULL; | ||
109 | adev->gart.table_addr = 0; | ||
110 | } | ||
111 | |||
112 | /** | ||
113 | * amdgpu_gart_table_vram_alloc - allocate vram for gart page table | ||
114 | * | ||
115 | * @adev: amdgpu_device pointer | ||
116 | * | ||
117 | * Allocate video memory for GART page table | ||
118 | * (pcie r4xx, r5xx+). These asics require the | ||
119 | * gart table to be in video memory. | ||
120 | * Returns 0 for success, error for failure. | ||
121 | */ | ||
122 | int amdgpu_gart_table_vram_alloc(struct amdgpu_device *adev) | ||
123 | { | ||
124 | int r; | ||
125 | |||
126 | if (adev->gart.robj == NULL) { | ||
127 | r = amdgpu_bo_create(adev, adev->gart.table_size, | ||
128 | PAGE_SIZE, true, AMDGPU_GEM_DOMAIN_VRAM, 0, | ||
129 | NULL, &adev->gart.robj); | ||
130 | if (r) { | ||
131 | return r; | ||
132 | } | ||
133 | } | ||
134 | return 0; | ||
135 | } | ||
136 | |||
137 | /** | ||
138 | * amdgpu_gart_table_vram_pin - pin gart page table in vram | ||
139 | * | ||
140 | * @adev: amdgpu_device pointer | ||
141 | * | ||
142 | * Pin the GART page table in vram so it will not be moved | ||
143 | * by the memory manager (pcie r4xx, r5xx+). These asics require the | ||
144 | * gart table to be in video memory. | ||
145 | * Returns 0 for success, error for failure. | ||
146 | */ | ||
147 | int amdgpu_gart_table_vram_pin(struct amdgpu_device *adev) | ||
148 | { | ||
149 | uint64_t gpu_addr; | ||
150 | int r; | ||
151 | |||
152 | r = amdgpu_bo_reserve(adev->gart.robj, false); | ||
153 | if (unlikely(r != 0)) | ||
154 | return r; | ||
155 | r = amdgpu_bo_pin(adev->gart.robj, | ||
156 | AMDGPU_GEM_DOMAIN_VRAM, &gpu_addr); | ||
157 | if (r) { | ||
158 | amdgpu_bo_unreserve(adev->gart.robj); | ||
159 | return r; | ||
160 | } | ||
161 | r = amdgpu_bo_kmap(adev->gart.robj, &adev->gart.ptr); | ||
162 | if (r) | ||
163 | amdgpu_bo_unpin(adev->gart.robj); | ||
164 | amdgpu_bo_unreserve(adev->gart.robj); | ||
165 | adev->gart.table_addr = gpu_addr; | ||
166 | return r; | ||
167 | } | ||
168 | |||
169 | /** | ||
170 | * amdgpu_gart_table_vram_unpin - unpin gart page table in vram | ||
171 | * | ||
172 | * @adev: amdgpu_device pointer | ||
173 | * | ||
174 | * Unpin the GART page table in vram (pcie r4xx, r5xx+). | ||
175 | * These asics require the gart table to be in video memory. | ||
176 | */ | ||
177 | void amdgpu_gart_table_vram_unpin(struct amdgpu_device *adev) | ||
178 | { | ||
179 | int r; | ||
180 | |||
181 | if (adev->gart.robj == NULL) { | ||
182 | return; | ||
183 | } | ||
184 | r = amdgpu_bo_reserve(adev->gart.robj, false); | ||
185 | if (likely(r == 0)) { | ||
186 | amdgpu_bo_kunmap(adev->gart.robj); | ||
187 | amdgpu_bo_unpin(adev->gart.robj); | ||
188 | amdgpu_bo_unreserve(adev->gart.robj); | ||
189 | adev->gart.ptr = NULL; | ||
190 | } | ||
191 | } | ||
192 | |||
193 | /** | ||
194 | * amdgpu_gart_table_vram_free - free gart page table vram | ||
195 | * | ||
196 | * @adev: amdgpu_device pointer | ||
197 | * | ||
198 | * Free the video memory used for the GART page table | ||
199 | * (pcie r4xx, r5xx+). These asics require the gart table to | ||
200 | * be in video memory. | ||
201 | */ | ||
202 | void amdgpu_gart_table_vram_free(struct amdgpu_device *adev) | ||
203 | { | ||
204 | if (adev->gart.robj == NULL) { | ||
205 | return; | ||
206 | } | ||
207 | amdgpu_bo_unref(&adev->gart.robj); | ||
208 | } | ||
209 | |||
210 | /* | ||
211 | * Common gart functions. | ||
212 | */ | ||
213 | /** | ||
214 | * amdgpu_gart_unbind - unbind pages from the gart page table | ||
215 | * | ||
216 | * @adev: amdgpu_device pointer | ||
217 | * @offset: offset into the GPU's gart aperture | ||
218 | * @pages: number of pages to unbind | ||
219 | * | ||
220 | * Unbinds the requested pages from the gart page table and | ||
221 | * replaces them with the dummy page (all asics). | ||
222 | */ | ||
223 | void amdgpu_gart_unbind(struct amdgpu_device *adev, unsigned offset, | ||
224 | int pages) | ||
225 | { | ||
226 | unsigned t; | ||
227 | unsigned p; | ||
228 | int i, j; | ||
229 | u64 page_base; | ||
230 | uint32_t flags = AMDGPU_PTE_SYSTEM; | ||
231 | |||
232 | if (!adev->gart.ready) { | ||
233 | WARN(1, "trying to unbind memory from uninitialized GART !\n"); | ||
234 | return; | ||
235 | } | ||
236 | |||
237 | t = offset / AMDGPU_GPU_PAGE_SIZE; | ||
238 | p = t / (PAGE_SIZE / AMDGPU_GPU_PAGE_SIZE); | ||
239 | for (i = 0; i < pages; i++, p++) { | ||
240 | if (adev->gart.pages[p]) { | ||
241 | adev->gart.pages[p] = NULL; | ||
242 | adev->gart.pages_addr[p] = adev->dummy_page.addr; | ||
243 | page_base = adev->gart.pages_addr[p]; | ||
244 | if (!adev->gart.ptr) | ||
245 | continue; | ||
246 | |||
247 | for (j = 0; j < (PAGE_SIZE / AMDGPU_GPU_PAGE_SIZE); j++, t++) { | ||
248 | amdgpu_gart_set_pte_pde(adev, adev->gart.ptr, | ||
249 | t, page_base, flags); | ||
250 | page_base += AMDGPU_GPU_PAGE_SIZE; | ||
251 | } | ||
252 | } | ||
253 | } | ||
254 | mb(); | ||
255 | amdgpu_gart_flush_gpu_tlb(adev, 0); | ||
256 | } | ||
257 | |||
258 | /** | ||
259 | * amdgpu_gart_bind - bind pages into the gart page table | ||
260 | * | ||
261 | * @adev: amdgpu_device pointer | ||
262 | * @offset: offset into the GPU's gart aperture | ||
263 | * @pages: number of pages to bind | ||
264 | * @pagelist: pages to bind | ||
265 | * @dma_addr: DMA addresses of pages | ||
266 | * | ||
267 | * Binds the requested pages to the gart page table | ||
268 | * (all asics). | ||
269 | * Returns 0 for success, -EINVAL for failure. | ||
270 | */ | ||
271 | int amdgpu_gart_bind(struct amdgpu_device *adev, unsigned offset, | ||
272 | int pages, struct page **pagelist, dma_addr_t *dma_addr, | ||
273 | uint32_t flags) | ||
274 | { | ||
275 | unsigned t; | ||
276 | unsigned p; | ||
277 | uint64_t page_base; | ||
278 | int i, j; | ||
279 | |||
280 | if (!adev->gart.ready) { | ||
281 | WARN(1, "trying to bind memory to uninitialized GART !\n"); | ||
282 | return -EINVAL; | ||
283 | } | ||
284 | |||
285 | t = offset / AMDGPU_GPU_PAGE_SIZE; | ||
286 | p = t / (PAGE_SIZE / AMDGPU_GPU_PAGE_SIZE); | ||
287 | |||
288 | for (i = 0; i < pages; i++, p++) { | ||
289 | adev->gart.pages_addr[p] = dma_addr[i]; | ||
290 | adev->gart.pages[p] = pagelist[i]; | ||
291 | if (adev->gart.ptr) { | ||
292 | page_base = adev->gart.pages_addr[p]; | ||
293 | for (j = 0; j < (PAGE_SIZE / AMDGPU_GPU_PAGE_SIZE); j++, t++) { | ||
294 | amdgpu_gart_set_pte_pde(adev, adev->gart.ptr, t, page_base, flags); | ||
295 | page_base += AMDGPU_GPU_PAGE_SIZE; | ||
296 | } | ||
297 | } | ||
298 | } | ||
299 | mb(); | ||
300 | amdgpu_gart_flush_gpu_tlb(adev, 0); | ||
301 | return 0; | ||
302 | } | ||
303 | |||
304 | /** | ||
305 | * amdgpu_gart_init - init the driver info for managing the gart | ||
306 | * | ||
307 | * @adev: amdgpu_device pointer | ||
308 | * | ||
309 | * Allocate the dummy page and init the gart driver info (all asics). | ||
310 | * Returns 0 for success, error for failure. | ||
311 | */ | ||
312 | int amdgpu_gart_init(struct amdgpu_device *adev) | ||
313 | { | ||
314 | int r, i; | ||
315 | |||
316 | if (adev->gart.pages) { | ||
317 | return 0; | ||
318 | } | ||
319 | /* We need PAGE_SIZE >= AMDGPU_GPU_PAGE_SIZE */ | ||
320 | if (PAGE_SIZE < AMDGPU_GPU_PAGE_SIZE) { | ||
321 | DRM_ERROR("Page size is smaller than GPU page size!\n"); | ||
322 | return -EINVAL; | ||
323 | } | ||
324 | r = amdgpu_dummy_page_init(adev); | ||
325 | if (r) | ||
326 | return r; | ||
327 | /* Compute table size */ | ||
328 | adev->gart.num_cpu_pages = adev->mc.gtt_size / PAGE_SIZE; | ||
329 | adev->gart.num_gpu_pages = adev->mc.gtt_size / AMDGPU_GPU_PAGE_SIZE; | ||
330 | DRM_INFO("GART: num cpu pages %u, num gpu pages %u\n", | ||
331 | adev->gart.num_cpu_pages, adev->gart.num_gpu_pages); | ||
332 | /* Allocate pages table */ | ||
333 | adev->gart.pages = vzalloc(sizeof(void *) * adev->gart.num_cpu_pages); | ||
334 | if (adev->gart.pages == NULL) { | ||
335 | amdgpu_gart_fini(adev); | ||
336 | return -ENOMEM; | ||
337 | } | ||
338 | adev->gart.pages_addr = vzalloc(sizeof(dma_addr_t) * | ||
339 | adev->gart.num_cpu_pages); | ||
340 | if (adev->gart.pages_addr == NULL) { | ||
341 | amdgpu_gart_fini(adev); | ||
342 | return -ENOMEM; | ||
343 | } | ||
344 | /* set GART entry to point to the dummy page by default */ | ||
345 | for (i = 0; i < adev->gart.num_cpu_pages; i++) { | ||
346 | adev->gart.pages_addr[i] = adev->dummy_page.addr; | ||
347 | } | ||
348 | return 0; | ||
349 | } | ||
350 | |||
351 | /** | ||
352 | * amdgpu_gart_fini - tear down the driver info for managing the gart | ||
353 | * | ||
354 | * @adev: amdgpu_device pointer | ||
355 | * | ||
356 | * Tear down the gart driver info and free the dummy page (all asics). | ||
357 | */ | ||
358 | void amdgpu_gart_fini(struct amdgpu_device *adev) | ||
359 | { | ||
360 | if (adev->gart.pages && adev->gart.pages_addr && adev->gart.ready) { | ||
361 | /* unbind pages */ | ||
362 | amdgpu_gart_unbind(adev, 0, adev->gart.num_cpu_pages); | ||
363 | } | ||
364 | adev->gart.ready = false; | ||
365 | vfree(adev->gart.pages); | ||
366 | vfree(adev->gart.pages_addr); | ||
367 | adev->gart.pages = NULL; | ||
368 | adev->gart.pages_addr = NULL; | ||
369 | |||
370 | amdgpu_dummy_page_fini(adev); | ||
371 | } | ||