1 | /* |
2 | * Copyright 2009 Jerome Glisse. |
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 | * Authors: |
28 | * Jerome Glisse <glisse@freedesktop.org> |
29 | * Thomas Hellstrom <thomas-at-tungstengraphics-dot-com> |
30 | * Dave Airlie |
31 | */ |
32 | #include <linux/list.h> |
33 | #include <linux/slab.h> |
34 | #include <drm/drmP.h> |
35 | #include <drm/amdgpu_drm.h> |
36 | #include <drm/drm_cache.h> |
37 | #include "amdgpu.h" |
38 | #include "amdgpu_trace.h" |
39 | #include "amdgpu_amdkfd.h" |
40 | |
41 | /** |
42 | * DOC: amdgpu_object |
43 | * |
44 | * This defines the interfaces to operate on an &amdgpu_bo buffer object which |
45 | * represents memory used by driver (VRAM, system memory, etc.). The driver |
46 | * provides DRM/GEM APIs to userspace. DRM/GEM APIs then use these interfaces |
47 | * to create/destroy/set buffer object which are then managed by the kernel TTM |
48 | * memory manager. |
49 | * The interfaces are also used internally by kernel clients, including gfx, |
50 | * uvd, etc. for kernel managed allocations used by the GPU. |
51 | * |
52 | */ |
53 | |
54 | /** |
55 | * amdgpu_bo_subtract_pin_size - Remove BO from pin_size accounting |
56 | * |
57 | * @bo: &amdgpu_bo buffer object |
58 | * |
59 | * This function is called when a BO stops being pinned, and updates the |
60 | * &amdgpu_device pin_size values accordingly. |
61 | */ |
62 | static void amdgpu_bo_subtract_pin_size(struct amdgpu_bo *bo) |
63 | { |
64 | struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev); |
65 | |
66 | if (bo->tbo.mem.mem_type == TTM_PL_VRAM) { |
67 | atomic64_sub(amdgpu_bo_size(bo), &adev->vram_pin_size); |
68 | atomic64_sub(amdgpu_vram_mgr_bo_visible_size(bo), |
69 | &adev->visible_pin_size); |
70 | } else if (bo->tbo.mem.mem_type == TTM_PL_TT) { |
71 | atomic64_sub(amdgpu_bo_size(bo), &adev->gart_pin_size); |
72 | } |
73 | } |
74 | |
75 | static void amdgpu_bo_destroy(struct ttm_buffer_object *tbo) |
76 | { |
77 | struct amdgpu_device *adev = amdgpu_ttm_adev(tbo->bdev); |
78 | struct amdgpu_bo *bo = ttm_to_amdgpu_bo(tbo); |
79 | |
80 | if (bo->pin_count > 0) |
81 | amdgpu_bo_subtract_pin_size(bo); |
82 | |
83 | if (bo->kfd_bo) |
84 | amdgpu_amdkfd_unreserve_memory_limit(bo); |
85 | |
86 | amdgpu_bo_kunmap(bo); |
87 | |
88 | if (bo->gem_base.import_attach) |
89 | drm_prime_gem_destroy(&bo->gem_base, bo->tbo.sg); |
90 | drm_gem_object_release(&bo->gem_base); |
91 | amdgpu_bo_unref(&bo->parent); |
92 | if (!list_empty(&bo->shadow_list)) { |
93 | mutex_lock(&adev->shadow_list_lock); |
94 | list_del_init(&bo->shadow_list); |
95 | mutex_unlock(&adev->shadow_list_lock); |
96 | } |
97 | kfree(bo->metadata); |
98 | kfree(bo); |
99 | } |
100 | |
101 | /** |
102 | * amdgpu_bo_is_amdgpu_bo - check if the buffer object is an &amdgpu_bo |
103 | * @bo: buffer object to be checked |
104 | * |
105 | * Uses destroy function associated with the object to determine if this is |
106 | * an &amdgpu_bo. |
107 | * |
108 | * Returns: |
109 | * true if the object belongs to &amdgpu_bo, false if not. |
110 | */ |
111 | bool amdgpu_bo_is_amdgpu_bo(struct ttm_buffer_object *bo) |
112 | { |
113 | if (bo->destroy == &amdgpu_bo_destroy) |
114 | return true; |
115 | return false; |
116 | } |
117 | |
118 | /** |
119 | * amdgpu_bo_placement_from_domain - set buffer's placement |
120 | * @abo: &amdgpu_bo buffer object whose placement is to be set |
121 | * @domain: requested domain |
122 | * |
123 | * Sets buffer's placement according to requested domain and the buffer's |
124 | * flags. |
125 | */ |
126 | void amdgpu_bo_placement_from_domain(struct amdgpu_bo *abo, u32 domain) |
127 | { |
128 | struct amdgpu_device *adev = amdgpu_ttm_adev(abo->tbo.bdev); |
129 | struct ttm_placement *placement = &abo->placement; |
130 | struct ttm_place *places = abo->placements; |
131 | u64 flags = abo->flags; |
132 | u32 c = 0; |
133 | |
134 | if (domain & AMDGPU_GEM_DOMAIN_VRAM) { |
135 | unsigned visible_pfn = adev->gmc.visible_vram_size >> PAGE_SHIFT; |
136 | |
137 | places[c].fpfn = 0; |
138 | places[c].lpfn = 0; |
139 | places[c].flags = TTM_PL_FLAG_WC | TTM_PL_FLAG_UNCACHED | |
140 | TTM_PL_FLAG_VRAM; |
141 | |
142 | if (flags & AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED) |
143 | places[c].lpfn = visible_pfn; |
144 | else |
145 | places[c].flags |= TTM_PL_FLAG_TOPDOWN; |
146 | |
147 | if (flags & AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS) |
148 | places[c].flags |= TTM_PL_FLAG_CONTIGUOUS; |
149 | c++; |
150 | } |
151 | |
152 | if (domain & AMDGPU_GEM_DOMAIN_GTT) { |
153 | places[c].fpfn = 0; |
154 | places[c].lpfn = 0; |
155 | places[c].flags = TTM_PL_FLAG_TT; |
156 | if (flags & AMDGPU_GEM_CREATE_CPU_GTT_USWC) |
157 | places[c].flags |= TTM_PL_FLAG_WC | |
158 | TTM_PL_FLAG_UNCACHED; |
159 | else |
160 | places[c].flags |= TTM_PL_FLAG_CACHED; |
161 | c++; |
162 | } |
163 | |
164 | if (domain & AMDGPU_GEM_DOMAIN_CPU) { |
165 | places[c].fpfn = 0; |
166 | places[c].lpfn = 0; |
167 | places[c].flags = TTM_PL_FLAG_SYSTEM; |
168 | if (flags & AMDGPU_GEM_CREATE_CPU_GTT_USWC) |
169 | places[c].flags |= TTM_PL_FLAG_WC | |
170 | TTM_PL_FLAG_UNCACHED; |
171 | else |
172 | places[c].flags |= TTM_PL_FLAG_CACHED; |
173 | c++; |
174 | } |
175 | |
176 | if (domain & AMDGPU_GEM_DOMAIN_GDS) { |
177 | places[c].fpfn = 0; |
178 | places[c].lpfn = 0; |
179 | places[c].flags = TTM_PL_FLAG_UNCACHED | AMDGPU_PL_FLAG_GDS; |
180 | c++; |
181 | } |
182 | |
183 | if (domain & AMDGPU_GEM_DOMAIN_GWS) { |
184 | places[c].fpfn = 0; |
185 | places[c].lpfn = 0; |
186 | places[c].flags = TTM_PL_FLAG_UNCACHED | AMDGPU_PL_FLAG_GWS; |
187 | c++; |
188 | } |
189 | |
190 | if (domain & AMDGPU_GEM_DOMAIN_OA) { |
191 | places[c].fpfn = 0; |
192 | places[c].lpfn = 0; |
193 | places[c].flags = TTM_PL_FLAG_UNCACHED | AMDGPU_PL_FLAG_OA; |
194 | c++; |
195 | } |
196 | |
197 | if (!c) { |
198 | places[c].fpfn = 0; |
199 | places[c].lpfn = 0; |
200 | places[c].flags = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM; |
201 | c++; |
202 | } |
203 | |
204 | BUG_ON(c >= AMDGPU_BO_MAX_PLACEMENTS); |
205 | |
206 | placement->num_placement = c; |
207 | placement->placement = places; |
208 | |
209 | placement->num_busy_placement = c; |
210 | placement->busy_placement = places; |
211 | } |
212 | |
213 | /** |
214 | * amdgpu_bo_create_reserved - create reserved BO for kernel use |
215 | * |
216 | * @adev: amdgpu device object |
217 | * @size: size for the new BO |
218 | * @align: alignment for the new BO |
219 | * @domain: where to place it |
220 | * @bo_ptr: used to initialize BOs in structures |
221 | * @gpu_addr: GPU addr of the pinned BO |
222 | * @cpu_addr: optional CPU address mapping |
223 | * |
224 | * Allocates and pins a BO for kernel internal use, and returns it still |
225 | * reserved. |
226 | * |
227 | * Note: For bo_ptr new BO is only created if bo_ptr points to NULL. |
228 | * |
229 | * Returns: |
230 | * 0 on success, negative error code otherwise. |
231 | */ |
232 | int amdgpu_bo_create_reserved(struct amdgpu_device *adev, |
233 | unsigned long size, int align, |
234 | u32 domain, struct amdgpu_bo **bo_ptr, |
235 | u64 *gpu_addr, void **cpu_addr) |
236 | { |
237 | struct amdgpu_bo_param bp; |
238 | bool free = false; |
239 | int r; |
240 | |
241 | if (!size) { |
242 | amdgpu_bo_unref(bo_ptr); |
243 | return 0; |
244 | } |
245 | |
246 | memset(&bp, 0, sizeof(bp)); |
247 | bp.size = size; |
248 | bp.byte_align = align; |
249 | bp.domain = domain; |
250 | bp.flags = AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED | |
251 | AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS; |
252 | bp.type = ttm_bo_type_kernel; |
253 | bp.resv = NULL; |
254 | |
255 | if (!*bo_ptr) { |
256 | r = amdgpu_bo_create(adev, &bp, bo_ptr); |
257 | if (r) { |
258 | dev_err(adev->dev, "(%d) failed to allocate kernel bo\n" , |
259 | r); |
260 | return r; |
261 | } |
262 | free = true; |
263 | } |
264 | |
265 | r = amdgpu_bo_reserve(*bo_ptr, false); |
266 | if (r) { |
267 | dev_err(adev->dev, "(%d) failed to reserve kernel bo\n" , r); |
268 | goto error_free; |
269 | } |
270 | |
271 | r = amdgpu_bo_pin(*bo_ptr, domain); |
272 | if (r) { |
273 | dev_err(adev->dev, "(%d) kernel bo pin failed\n" , r); |
274 | goto error_unreserve; |
275 | } |
276 | |
277 | r = amdgpu_ttm_alloc_gart(&(*bo_ptr)->tbo); |
278 | if (r) { |
279 | dev_err(adev->dev, "%p bind failed\n" , *bo_ptr); |
280 | goto error_unpin; |
281 | } |
282 | |
283 | if (gpu_addr) |
284 | *gpu_addr = amdgpu_bo_gpu_offset(*bo_ptr); |
285 | |
286 | if (cpu_addr) { |
287 | r = amdgpu_bo_kmap(*bo_ptr, cpu_addr); |
288 | if (r) { |
289 | dev_err(adev->dev, "(%d) kernel bo map failed\n" , r); |
290 | goto error_unpin; |
291 | } |
292 | } |
293 | |
294 | return 0; |
295 | |
296 | error_unpin: |
297 | amdgpu_bo_unpin(*bo_ptr); |
298 | error_unreserve: |
299 | amdgpu_bo_unreserve(*bo_ptr); |
300 | |
301 | error_free: |
302 | if (free) |
303 | amdgpu_bo_unref(bo_ptr); |
304 | |
305 | return r; |
306 | } |
307 | |
308 | /** |
309 | * amdgpu_bo_create_kernel - create BO for kernel use |
310 | * |
311 | * @adev: amdgpu device object |
312 | * @size: size for the new BO |
313 | * @align: alignment for the new BO |
314 | * @domain: where to place it |
315 | * @bo_ptr: used to initialize BOs in structures |
316 | * @gpu_addr: GPU addr of the pinned BO |
317 | * @cpu_addr: optional CPU address mapping |
318 | * |
319 | * Allocates and pins a BO for kernel internal use. |
320 | * |
321 | * Note: For bo_ptr new BO is only created if bo_ptr points to NULL. |
322 | * |
323 | * Returns: |
324 | * 0 on success, negative error code otherwise. |
325 | */ |
326 | int amdgpu_bo_create_kernel(struct amdgpu_device *adev, |
327 | unsigned long size, int align, |
328 | u32 domain, struct amdgpu_bo **bo_ptr, |
329 | u64 *gpu_addr, void **cpu_addr) |
330 | { |
331 | int r; |
332 | |
333 | r = amdgpu_bo_create_reserved(adev, size, align, domain, bo_ptr, |
334 | gpu_addr, cpu_addr); |
335 | |
336 | if (r) |
337 | return r; |
338 | |
339 | if (*bo_ptr) |
340 | amdgpu_bo_unreserve(*bo_ptr); |
341 | |
342 | return 0; |
343 | } |
344 | |
345 | /** |
346 | * amdgpu_bo_free_kernel - free BO for kernel use |
347 | * |
348 | * @bo: amdgpu BO to free |
349 | * @gpu_addr: pointer to where the BO's GPU memory space address was stored |
350 | * @cpu_addr: pointer to where the BO's CPU memory space address was stored |
351 | * |
352 | * unmaps and unpin a BO for kernel internal use. |
353 | */ |
354 | void amdgpu_bo_free_kernel(struct amdgpu_bo **bo, u64 *gpu_addr, |
355 | void **cpu_addr) |
356 | { |
357 | if (*bo == NULL) |
358 | return; |
359 | |
360 | if (likely(amdgpu_bo_reserve(*bo, true) == 0)) { |
361 | if (cpu_addr) |
362 | amdgpu_bo_kunmap(*bo); |
363 | |
364 | amdgpu_bo_unpin(*bo); |
365 | amdgpu_bo_unreserve(*bo); |
366 | } |
367 | amdgpu_bo_unref(bo); |
368 | |
369 | if (gpu_addr) |
370 | *gpu_addr = 0; |
371 | |
372 | if (cpu_addr) |
373 | *cpu_addr = NULL; |
374 | } |
375 | |
376 | /* Validate bo size is bit bigger then the request domain */ |
377 | static bool amdgpu_bo_validate_size(struct amdgpu_device *adev, |
378 | unsigned long size, u32 domain) |
379 | { |
380 | struct ttm_mem_type_manager *man = NULL; |
381 | |
382 | /* |
383 | * If GTT is part of requested domains the check must succeed to |
384 | * allow fall back to GTT |
385 | */ |
386 | if (domain & AMDGPU_GEM_DOMAIN_GTT) { |
387 | man = &adev->mman.bdev.man[TTM_PL_TT]; |
388 | |
389 | if (size < (man->size << PAGE_SHIFT)) |
390 | return true; |
391 | else |
392 | goto fail; |
393 | } |
394 | |
395 | if (domain & AMDGPU_GEM_DOMAIN_VRAM) { |
396 | man = &adev->mman.bdev.man[TTM_PL_VRAM]; |
397 | |
398 | if (size < (man->size << PAGE_SHIFT)) |
399 | return true; |
400 | else |
401 | goto fail; |
402 | } |
403 | |
404 | |
405 | /* TODO add more domains checks, such as AMDGPU_GEM_DOMAIN_CPU */ |
406 | return true; |
407 | |
408 | fail: |
409 | DRM_DEBUG("BO size %lu > total memory in domain: %llu\n" , size, |
410 | man->size << PAGE_SHIFT); |
411 | return false; |
412 | } |
413 | |
414 | static int amdgpu_bo_do_create(struct amdgpu_device *adev, |
415 | struct amdgpu_bo_param *bp, |
416 | struct amdgpu_bo **bo_ptr) |
417 | { |
418 | struct ttm_operation_ctx ctx = { |
419 | .interruptible = (bp->type != ttm_bo_type_kernel), |
420 | .no_wait_gpu = false, |
421 | .resv = bp->resv, |
422 | .flags = TTM_OPT_FLAG_ALLOW_RES_EVICT |
423 | }; |
424 | struct amdgpu_bo *bo; |
425 | unsigned long page_align, size = bp->size; |
426 | size_t acc_size; |
427 | int r; |
428 | |
429 | /* Note that GDS/GWS/OA allocates 1 page per byte/resource. */ |
430 | if (bp->domain & (AMDGPU_GEM_DOMAIN_GWS | AMDGPU_GEM_DOMAIN_OA)) { |
431 | /* GWS and OA don't need any alignment. */ |
432 | page_align = bp->byte_align; |
433 | size <<= PAGE_SHIFT; |
434 | } else if (bp->domain & AMDGPU_GEM_DOMAIN_GDS) { |
435 | /* Both size and alignment must be a multiple of 4. */ |
436 | page_align = ALIGN(bp->byte_align, 4); |
437 | size = ALIGN(size, 4) << PAGE_SHIFT; |
438 | } else { |
439 | /* Memory should be aligned at least to a page size. */ |
440 | page_align = ALIGN(bp->byte_align, PAGE_SIZE) >> PAGE_SHIFT; |
441 | size = ALIGN(size, PAGE_SIZE); |
442 | } |
443 | |
444 | if (!amdgpu_bo_validate_size(adev, size, bp->domain)) |
445 | return -ENOMEM; |
446 | |
447 | *bo_ptr = NULL; |
448 | |
449 | acc_size = ttm_bo_dma_acc_size(&adev->mman.bdev, size, |
450 | sizeof(struct amdgpu_bo)); |
451 | |
452 | bo = kzalloc(sizeof(struct amdgpu_bo), GFP_KERNEL); |
453 | if (bo == NULL) |
454 | return -ENOMEM; |
455 | drm_gem_private_object_init(adev->ddev, &bo->gem_base, size); |
456 | INIT_LIST_HEAD(&bo->shadow_list); |
457 | bo->vm_bo = NULL; |
458 | bo->preferred_domains = bp->preferred_domain ? bp->preferred_domain : |
459 | bp->domain; |
460 | bo->allowed_domains = bo->preferred_domains; |
461 | if (bp->type != ttm_bo_type_kernel && |
462 | bo->allowed_domains == AMDGPU_GEM_DOMAIN_VRAM) |
463 | bo->allowed_domains |= AMDGPU_GEM_DOMAIN_GTT; |
464 | |
465 | bo->flags = bp->flags; |
466 | |
467 | #ifdef CONFIG_X86_32 |
468 | /* XXX: Write-combined CPU mappings of GTT seem broken on 32-bit |
469 | * See https://bugs.freedesktop.org/show_bug.cgi?id=84627 |
470 | */ |
471 | bo->flags &= ~AMDGPU_GEM_CREATE_CPU_GTT_USWC; |
472 | #elif defined(CONFIG_X86) && !defined(CONFIG_X86_PAT) |
473 | /* Don't try to enable write-combining when it can't work, or things |
474 | * may be slow |
475 | * See https://bugs.freedesktop.org/show_bug.cgi?id=88758 |
476 | */ |
477 | |
478 | #ifndef CONFIG_COMPILE_TEST |
479 | #warning Please enable CONFIG_MTRR and CONFIG_X86_PAT for better performance \ |
480 | thanks to write-combining |
481 | #endif |
482 | |
483 | if (bo->flags & AMDGPU_GEM_CREATE_CPU_GTT_USWC) |
484 | DRM_INFO_ONCE("Please enable CONFIG_MTRR and CONFIG_X86_PAT for " |
485 | "better performance thanks to write-combining\n" ); |
486 | bo->flags &= ~AMDGPU_GEM_CREATE_CPU_GTT_USWC; |
487 | #else |
488 | /* For architectures that don't support WC memory, |
489 | * mask out the WC flag from the BO |
490 | */ |
491 | if (!drm_arch_can_wc_memory()) |
492 | bo->flags &= ~AMDGPU_GEM_CREATE_CPU_GTT_USWC; |
493 | #endif |
494 | |
495 | bo->tbo.bdev = &adev->mman.bdev; |
496 | amdgpu_bo_placement_from_domain(bo, bp->domain); |
497 | if (bp->type == ttm_bo_type_kernel) |
498 | bo->tbo.priority = 1; |
499 | |
500 | r = ttm_bo_init_reserved(&adev->mman.bdev, &bo->tbo, size, bp->type, |
501 | &bo->placement, page_align, &ctx, acc_size, |
502 | NULL, bp->resv, &amdgpu_bo_destroy); |
503 | if (unlikely(r != 0)) |
504 | return r; |
505 | |
506 | if (!amdgpu_gmc_vram_full_visible(&adev->gmc) && |
507 | bo->tbo.mem.mem_type == TTM_PL_VRAM && |
508 | bo->tbo.mem.start < adev->gmc.visible_vram_size >> PAGE_SHIFT) |
509 | amdgpu_cs_report_moved_bytes(adev, ctx.bytes_moved, |
510 | ctx.bytes_moved); |
511 | else |
512 | amdgpu_cs_report_moved_bytes(adev, ctx.bytes_moved, 0); |
513 | |
514 | if (bp->flags & AMDGPU_GEM_CREATE_VRAM_CLEARED && |
515 | bo->tbo.mem.placement & TTM_PL_FLAG_VRAM) { |
516 | struct dma_fence *fence; |
517 | |
518 | r = amdgpu_fill_buffer(bo, 0, bo->tbo.resv, &fence); |
519 | if (unlikely(r)) |
520 | goto fail_unreserve; |
521 | |
522 | amdgpu_bo_fence(bo, fence, false); |
523 | dma_fence_put(bo->tbo.moving); |
524 | bo->tbo.moving = dma_fence_get(fence); |
525 | dma_fence_put(fence); |
526 | } |
527 | if (!bp->resv) |
528 | amdgpu_bo_unreserve(bo); |
529 | *bo_ptr = bo; |
530 | |
531 | trace_amdgpu_bo_create(bo); |
532 | |
533 | /* Treat CPU_ACCESS_REQUIRED only as a hint if given by UMD */ |
534 | if (bp->type == ttm_bo_type_device) |
535 | bo->flags &= ~AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED; |
536 | |
537 | return 0; |
538 | |
539 | fail_unreserve: |
540 | if (!bp->resv) |
541 | ww_mutex_unlock(&bo->tbo.resv->lock); |
542 | amdgpu_bo_unref(&bo); |
543 | return r; |
544 | } |
545 | |
546 | static int amdgpu_bo_create_shadow(struct amdgpu_device *adev, |
547 | unsigned long size, |
548 | struct amdgpu_bo *bo) |
549 | { |
550 | struct amdgpu_bo_param bp; |
551 | int r; |
552 | |
553 | if (bo->shadow) |
554 | return 0; |
555 | |
556 | memset(&bp, 0, sizeof(bp)); |
557 | bp.size = size; |
558 | bp.domain = AMDGPU_GEM_DOMAIN_GTT; |
559 | bp.flags = AMDGPU_GEM_CREATE_CPU_GTT_USWC | |
560 | AMDGPU_GEM_CREATE_SHADOW; |
561 | bp.type = ttm_bo_type_kernel; |
562 | bp.resv = bo->tbo.resv; |
563 | |
564 | r = amdgpu_bo_do_create(adev, &bp, &bo->shadow); |
565 | if (!r) { |
566 | bo->shadow->parent = amdgpu_bo_ref(bo); |
567 | mutex_lock(&adev->shadow_list_lock); |
568 | list_add_tail(&bo->shadow->shadow_list, &adev->shadow_list); |
569 | mutex_unlock(&adev->shadow_list_lock); |
570 | } |
571 | |
572 | return r; |
573 | } |
574 | |
575 | /** |
576 | * amdgpu_bo_create - create an &amdgpu_bo buffer object |
577 | * @adev: amdgpu device object |
578 | * @bp: parameters to be used for the buffer object |
579 | * @bo_ptr: pointer to the buffer object pointer |
580 | * |
581 | * Creates an &amdgpu_bo buffer object; and if requested, also creates a |
582 | * shadow object. |
583 | * Shadow object is used to backup the original buffer object, and is always |
584 | * in GTT. |
585 | * |
586 | * Returns: |
587 | * 0 for success or a negative error code on failure. |
588 | */ |
589 | int amdgpu_bo_create(struct amdgpu_device *adev, |
590 | struct amdgpu_bo_param *bp, |
591 | struct amdgpu_bo **bo_ptr) |
592 | { |
593 | u64 flags = bp->flags; |
594 | int r; |
595 | |
596 | bp->flags = bp->flags & ~AMDGPU_GEM_CREATE_SHADOW; |
597 | r = amdgpu_bo_do_create(adev, bp, bo_ptr); |
598 | if (r) |
599 | return r; |
600 | |
601 | if ((flags & AMDGPU_GEM_CREATE_SHADOW) && !(adev->flags & AMD_IS_APU)) { |
602 | if (!bp->resv) |
603 | WARN_ON(reservation_object_lock((*bo_ptr)->tbo.resv, |
604 | NULL)); |
605 | |
606 | r = amdgpu_bo_create_shadow(adev, bp->size, *bo_ptr); |
607 | |
608 | if (!bp->resv) |
609 | reservation_object_unlock((*bo_ptr)->tbo.resv); |
610 | |
611 | if (r) |
612 | amdgpu_bo_unref(bo_ptr); |
613 | } |
614 | |
615 | return r; |
616 | } |
617 | |
618 | /** |
619 | * amdgpu_bo_validate - validate an &amdgpu_bo buffer object |
620 | * @bo: pointer to the buffer object |
621 | * |
622 | * Sets placement according to domain; and changes placement and caching |
623 | * policy of the buffer object according to the placement. |
624 | * This is used for validating shadow bos. It calls ttm_bo_validate() to |
625 | * make sure the buffer is resident where it needs to be. |
626 | * |
627 | * Returns: |
628 | * 0 for success or a negative error code on failure. |
629 | */ |
630 | int amdgpu_bo_validate(struct amdgpu_bo *bo) |
631 | { |
632 | struct ttm_operation_ctx ctx = { false, false }; |
633 | uint32_t domain; |
634 | int r; |
635 | |
636 | if (bo->pin_count) |
637 | return 0; |
638 | |
639 | domain = bo->preferred_domains; |
640 | |
641 | retry: |
642 | amdgpu_bo_placement_from_domain(bo, domain); |
643 | r = ttm_bo_validate(&bo->tbo, &bo->placement, &ctx); |
644 | if (unlikely(r == -ENOMEM) && domain != bo->allowed_domains) { |
645 | domain = bo->allowed_domains; |
646 | goto retry; |
647 | } |
648 | |
649 | return r; |
650 | } |
651 | |
652 | /** |
653 | * amdgpu_bo_restore_shadow - restore an &amdgpu_bo shadow |
654 | * |
655 | * @shadow: &amdgpu_bo shadow to be restored |
656 | * @fence: dma_fence associated with the operation |
657 | * |
658 | * Copies a buffer object's shadow content back to the object. |
659 | * This is used for recovering a buffer from its shadow in case of a gpu |
660 | * reset where vram context may be lost. |
661 | * |
662 | * Returns: |
663 | * 0 for success or a negative error code on failure. |
664 | */ |
665 | int amdgpu_bo_restore_shadow(struct amdgpu_bo *shadow, struct dma_fence **fence) |
666 | |
667 | { |
668 | struct amdgpu_device *adev = amdgpu_ttm_adev(shadow->tbo.bdev); |
669 | struct amdgpu_ring *ring = adev->mman.buffer_funcs_ring; |
670 | uint64_t shadow_addr, parent_addr; |
671 | |
672 | shadow_addr = amdgpu_bo_gpu_offset(shadow); |
673 | parent_addr = amdgpu_bo_gpu_offset(shadow->parent); |
674 | |
675 | return amdgpu_copy_buffer(ring, shadow_addr, parent_addr, |
676 | amdgpu_bo_size(shadow), NULL, fence, |
677 | true, false); |
678 | } |
679 | |
680 | /** |
681 | * amdgpu_bo_kmap - map an &amdgpu_bo buffer object |
682 | * @bo: &amdgpu_bo buffer object to be mapped |
683 | * @ptr: kernel virtual address to be returned |
684 | * |
685 | * Calls ttm_bo_kmap() to set up the kernel virtual mapping; calls |
686 | * amdgpu_bo_kptr() to get the kernel virtual address. |
687 | * |
688 | * Returns: |
689 | * 0 for success or a negative error code on failure. |
690 | */ |
691 | int amdgpu_bo_kmap(struct amdgpu_bo *bo, void **ptr) |
692 | { |
693 | void *kptr; |
694 | long r; |
695 | |
696 | if (bo->flags & AMDGPU_GEM_CREATE_NO_CPU_ACCESS) |
697 | return -EPERM; |
698 | |
699 | kptr = amdgpu_bo_kptr(bo); |
700 | if (kptr) { |
701 | if (ptr) |
702 | *ptr = kptr; |
703 | return 0; |
704 | } |
705 | |
706 | r = reservation_object_wait_timeout_rcu(bo->tbo.resv, false, false, |
707 | MAX_SCHEDULE_TIMEOUT); |
708 | if (r < 0) |
709 | return r; |
710 | |
711 | r = ttm_bo_kmap(&bo->tbo, 0, bo->tbo.num_pages, &bo->kmap); |
712 | if (r) |
713 | return r; |
714 | |
715 | if (ptr) |
716 | *ptr = amdgpu_bo_kptr(bo); |
717 | |
718 | return 0; |
719 | } |
720 | |
721 | /** |
722 | * amdgpu_bo_kptr - returns a kernel virtual address of the buffer object |
723 | * @bo: &amdgpu_bo buffer object |
724 | * |
725 | * Calls ttm_kmap_obj_virtual() to get the kernel virtual address |
726 | * |
727 | * Returns: |
728 | * the virtual address of a buffer object area. |
729 | */ |
730 | void *amdgpu_bo_kptr(struct amdgpu_bo *bo) |
731 | { |
732 | bool is_iomem; |
733 | |
734 | return ttm_kmap_obj_virtual(&bo->kmap, &is_iomem); |
735 | } |
736 | |
737 | /** |
738 | * amdgpu_bo_kunmap - unmap an &amdgpu_bo buffer object |
739 | * @bo: &amdgpu_bo buffer object to be unmapped |
740 | * |
741 | * Unmaps a kernel map set up by amdgpu_bo_kmap(). |
742 | */ |
743 | void amdgpu_bo_kunmap(struct amdgpu_bo *bo) |
744 | { |
745 | if (bo->kmap.bo) |
746 | ttm_bo_kunmap(&bo->kmap); |
747 | } |
748 | |
749 | /** |
750 | * amdgpu_bo_ref - reference an &amdgpu_bo buffer object |
751 | * @bo: &amdgpu_bo buffer object |
752 | * |
753 | * References the contained &ttm_buffer_object. |
754 | * |
755 | * Returns: |
756 | * a refcounted pointer to the &amdgpu_bo buffer object. |
757 | */ |
758 | struct amdgpu_bo *amdgpu_bo_ref(struct amdgpu_bo *bo) |
759 | { |
760 | if (bo == NULL) |
761 | return NULL; |
762 | |
763 | ttm_bo_get(&bo->tbo); |
764 | return bo; |
765 | } |
766 | |
767 | /** |
768 | * amdgpu_bo_unref - unreference an &amdgpu_bo buffer object |
769 | * @bo: &amdgpu_bo buffer object |
770 | * |
771 | * Unreferences the contained &ttm_buffer_object and clear the pointer |
772 | */ |
773 | void amdgpu_bo_unref(struct amdgpu_bo **bo) |
774 | { |
775 | struct ttm_buffer_object *tbo; |
776 | |
777 | if ((*bo) == NULL) |
778 | return; |
779 | |
780 | tbo = &((*bo)->tbo); |
781 | ttm_bo_put(tbo); |
782 | *bo = NULL; |
783 | } |
784 | |
785 | /** |
786 | * amdgpu_bo_pin_restricted - pin an &amdgpu_bo buffer object |
787 | * @bo: &amdgpu_bo buffer object to be pinned |
788 | * @domain: domain to be pinned to |
789 | * @min_offset: the start of requested address range |
790 | * @max_offset: the end of requested address range |
791 | * |
792 | * Pins the buffer object according to requested domain and address range. If |
793 | * the memory is unbound gart memory, binds the pages into gart table. Adjusts |
794 | * pin_count and pin_size accordingly. |
795 | * |
796 | * Pinning means to lock pages in memory along with keeping them at a fixed |
797 | * offset. It is required when a buffer can not be moved, for example, when |
798 | * a display buffer is being scanned out. |
799 | * |
800 | * Compared with amdgpu_bo_pin(), this function gives more flexibility on |
801 | * where to pin a buffer if there are specific restrictions on where a buffer |
802 | * must be located. |
803 | * |
804 | * Returns: |
805 | * 0 for success or a negative error code on failure. |
806 | */ |
807 | int amdgpu_bo_pin_restricted(struct amdgpu_bo *bo, u32 domain, |
808 | u64 min_offset, u64 max_offset) |
809 | { |
810 | struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev); |
811 | struct ttm_operation_ctx ctx = { false, false }; |
812 | int r, i; |
813 | |
814 | if (amdgpu_ttm_tt_get_usermm(bo->tbo.ttm)) |
815 | return -EPERM; |
816 | |
817 | if (WARN_ON_ONCE(min_offset > max_offset)) |
818 | return -EINVAL; |
819 | |
820 | /* A shared bo cannot be migrated to VRAM */ |
821 | if (bo->prime_shared_count) { |
822 | if (domain & AMDGPU_GEM_DOMAIN_GTT) |
823 | domain = AMDGPU_GEM_DOMAIN_GTT; |
824 | else |
825 | return -EINVAL; |
826 | } |
827 | |
828 | /* This assumes only APU display buffers are pinned with (VRAM|GTT). |
829 | * See function amdgpu_display_supported_domains() |
830 | */ |
831 | domain = amdgpu_bo_get_preferred_pin_domain(adev, domain); |
832 | |
833 | if (bo->pin_count) { |
834 | uint32_t mem_type = bo->tbo.mem.mem_type; |
835 | |
836 | if (!(domain & amdgpu_mem_type_to_domain(mem_type))) |
837 | return -EINVAL; |
838 | |
839 | bo->pin_count++; |
840 | |
841 | if (max_offset != 0) { |
842 | u64 domain_start = bo->tbo.bdev->man[mem_type].gpu_offset; |
843 | WARN_ON_ONCE(max_offset < |
844 | (amdgpu_bo_gpu_offset(bo) - domain_start)); |
845 | } |
846 | |
847 | return 0; |
848 | } |
849 | |
850 | bo->flags |= AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS; |
851 | /* force to pin into visible video ram */ |
852 | if (!(bo->flags & AMDGPU_GEM_CREATE_NO_CPU_ACCESS)) |
853 | bo->flags |= AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED; |
854 | amdgpu_bo_placement_from_domain(bo, domain); |
855 | for (i = 0; i < bo->placement.num_placement; i++) { |
856 | unsigned fpfn, lpfn; |
857 | |
858 | fpfn = min_offset >> PAGE_SHIFT; |
859 | lpfn = max_offset >> PAGE_SHIFT; |
860 | |
861 | if (fpfn > bo->placements[i].fpfn) |
862 | bo->placements[i].fpfn = fpfn; |
863 | if (!bo->placements[i].lpfn || |
864 | (lpfn && lpfn < bo->placements[i].lpfn)) |
865 | bo->placements[i].lpfn = lpfn; |
866 | bo->placements[i].flags |= TTM_PL_FLAG_NO_EVICT; |
867 | } |
868 | |
869 | r = ttm_bo_validate(&bo->tbo, &bo->placement, &ctx); |
870 | if (unlikely(r)) { |
871 | dev_err(adev->dev, "%p pin failed\n" , bo); |
872 | goto error; |
873 | } |
874 | |
875 | bo->pin_count = 1; |
876 | |
877 | domain = amdgpu_mem_type_to_domain(bo->tbo.mem.mem_type); |
878 | if (domain == AMDGPU_GEM_DOMAIN_VRAM) { |
879 | atomic64_add(amdgpu_bo_size(bo), &adev->vram_pin_size); |
880 | atomic64_add(amdgpu_vram_mgr_bo_visible_size(bo), |
881 | &adev->visible_pin_size); |
882 | } else if (domain == AMDGPU_GEM_DOMAIN_GTT) { |
883 | atomic64_add(amdgpu_bo_size(bo), &adev->gart_pin_size); |
884 | } |
885 | |
886 | error: |
887 | return r; |
888 | } |
889 | |
890 | /** |
891 | * amdgpu_bo_pin - pin an &amdgpu_bo buffer object |
892 | * @bo: &amdgpu_bo buffer object to be pinned |
893 | * @domain: domain to be pinned to |
894 | * |
895 | * A simple wrapper to amdgpu_bo_pin_restricted(). |
896 | * Provides a simpler API for buffers that do not have any strict restrictions |
897 | * on where a buffer must be located. |
898 | * |
899 | * Returns: |
900 | * 0 for success or a negative error code on failure. |
901 | */ |
902 | int amdgpu_bo_pin(struct amdgpu_bo *bo, u32 domain) |
903 | { |
904 | return amdgpu_bo_pin_restricted(bo, domain, 0, 0); |
905 | } |
906 | |
907 | /** |
908 | * amdgpu_bo_unpin - unpin an &amdgpu_bo buffer object |
909 | * @bo: &amdgpu_bo buffer object to be unpinned |
910 | * |
911 | * Decreases the pin_count, and clears the flags if pin_count reaches 0. |
912 | * Changes placement and pin size accordingly. |
913 | * |
914 | * Returns: |
915 | * 0 for success or a negative error code on failure. |
916 | */ |
917 | int amdgpu_bo_unpin(struct amdgpu_bo *bo) |
918 | { |
919 | struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev); |
920 | struct ttm_operation_ctx ctx = { false, false }; |
921 | int r, i; |
922 | |
923 | if (WARN_ON_ONCE(!bo->pin_count)) { |
924 | dev_warn(adev->dev, "%p unpin not necessary\n" , bo); |
925 | return 0; |
926 | } |
927 | bo->pin_count--; |
928 | if (bo->pin_count) |
929 | return 0; |
930 | |
931 | amdgpu_bo_subtract_pin_size(bo); |
932 | |
933 | for (i = 0; i < bo->placement.num_placement; i++) { |
934 | bo->placements[i].lpfn = 0; |
935 | bo->placements[i].flags &= ~TTM_PL_FLAG_NO_EVICT; |
936 | } |
937 | r = ttm_bo_validate(&bo->tbo, &bo->placement, &ctx); |
938 | if (unlikely(r)) |
939 | dev_err(adev->dev, "%p validate failed for unpin\n" , bo); |
940 | |
941 | return r; |
942 | } |
943 | |
944 | /** |
945 | * amdgpu_bo_evict_vram - evict VRAM buffers |
946 | * @adev: amdgpu device object |
947 | * |
948 | * Evicts all VRAM buffers on the lru list of the memory type. |
949 | * Mainly used for evicting vram at suspend time. |
950 | * |
951 | * Returns: |
952 | * 0 for success or a negative error code on failure. |
953 | */ |
954 | int amdgpu_bo_evict_vram(struct amdgpu_device *adev) |
955 | { |
956 | /* late 2.6.33 fix IGP hibernate - we need pm ops to do this correct */ |
957 | #ifndef CONFIG_HIBERNATION |
958 | if (adev->flags & AMD_IS_APU) { |
959 | /* Useless to evict on IGP chips */ |
960 | return 0; |
961 | } |
962 | #endif |
963 | return ttm_bo_evict_mm(&adev->mman.bdev, TTM_PL_VRAM); |
964 | } |
965 | |
966 | static const char *amdgpu_vram_names[] = { |
967 | "UNKNOWN" , |
968 | "GDDR1" , |
969 | "DDR2" , |
970 | "GDDR3" , |
971 | "GDDR4" , |
972 | "GDDR5" , |
973 | "HBM" , |
974 | "DDR3" , |
975 | "DDR4" , |
976 | }; |
977 | |
978 | /** |
979 | * amdgpu_bo_init - initialize memory manager |
980 | * @adev: amdgpu device object |
981 | * |
982 | * Calls amdgpu_ttm_init() to initialize amdgpu memory manager. |
983 | * |
984 | * Returns: |
985 | * 0 for success or a negative error code on failure. |
986 | */ |
987 | int amdgpu_bo_init(struct amdgpu_device *adev) |
988 | { |
989 | /* reserve PAT memory space to WC for VRAM */ |
990 | arch_io_reserve_memtype_wc(adev->gmc.aper_base, |
991 | adev->gmc.aper_size); |
992 | |
993 | /* Add an MTRR for the VRAM */ |
994 | adev->gmc.vram_mtrr = arch_phys_wc_add(adev->gmc.aper_base, |
995 | adev->gmc.aper_size); |
996 | DRM_INFO("Detected VRAM RAM=%lluM, BAR=%lluM\n" , |
997 | adev->gmc.mc_vram_size >> 20, |
998 | (unsigned long long)adev->gmc.aper_size >> 20); |
999 | DRM_INFO("RAM width %dbits %s\n" , |
1000 | adev->gmc.vram_width, amdgpu_vram_names[adev->gmc.vram_type]); |
1001 | return amdgpu_ttm_init(adev); |
1002 | } |
1003 | |
1004 | /** |
1005 | * amdgpu_bo_late_init - late init |
1006 | * @adev: amdgpu device object |
1007 | * |
1008 | * Calls amdgpu_ttm_late_init() to free resources used earlier during |
1009 | * initialization. |
1010 | * |
1011 | * Returns: |
1012 | * 0 for success or a negative error code on failure. |
1013 | */ |
1014 | int amdgpu_bo_late_init(struct amdgpu_device *adev) |
1015 | { |
1016 | amdgpu_ttm_late_init(adev); |
1017 | |
1018 | return 0; |
1019 | } |
1020 | |
1021 | /** |
1022 | * amdgpu_bo_fini - tear down memory manager |
1023 | * @adev: amdgpu device object |
1024 | * |
1025 | * Reverses amdgpu_bo_init() to tear down memory manager. |
1026 | */ |
1027 | void amdgpu_bo_fini(struct amdgpu_device *adev) |
1028 | { |
1029 | amdgpu_ttm_fini(adev); |
1030 | arch_phys_wc_del(adev->gmc.vram_mtrr); |
1031 | arch_io_free_memtype_wc(adev->gmc.aper_base, adev->gmc.aper_size); |
1032 | } |
1033 | |
1034 | /** |
1035 | * amdgpu_bo_fbdev_mmap - mmap fbdev memory |
1036 | * @bo: &amdgpu_bo buffer object |
1037 | * @vma: vma as input from the fbdev mmap method |
1038 | * |
1039 | * Calls ttm_fbdev_mmap() to mmap fbdev memory if it is backed by a bo. |
1040 | * |
1041 | * Returns: |
1042 | * 0 for success or a negative error code on failure. |
1043 | */ |
1044 | int amdgpu_bo_fbdev_mmap(struct amdgpu_bo *bo, |
1045 | struct vm_area_struct *vma) |
1046 | { |
1047 | return ttm_fbdev_mmap(vma, &bo->tbo); |
1048 | } |
1049 | |
1050 | /** |
1051 | * amdgpu_bo_set_tiling_flags - set tiling flags |
1052 | * @bo: &amdgpu_bo buffer object |
1053 | * @tiling_flags: new flags |
1054 | * |
1055 | * Sets buffer object's tiling flags with the new one. Used by GEM ioctl or |
1056 | * kernel driver to set the tiling flags on a buffer. |
1057 | * |
1058 | * Returns: |
1059 | * 0 for success or a negative error code on failure. |
1060 | */ |
1061 | int amdgpu_bo_set_tiling_flags(struct amdgpu_bo *bo, u64 tiling_flags) |
1062 | { |
1063 | struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev); |
1064 | |
1065 | if (adev->family <= AMDGPU_FAMILY_CZ && |
1066 | AMDGPU_TILING_GET(tiling_flags, TILE_SPLIT) > 6) |
1067 | return -EINVAL; |
1068 | |
1069 | bo->tiling_flags = tiling_flags; |
1070 | return 0; |
1071 | } |
1072 | |
1073 | /** |
1074 | * amdgpu_bo_get_tiling_flags - get tiling flags |
1075 | * @bo: &amdgpu_bo buffer object |
1076 | * @tiling_flags: returned flags |
1077 | * |
1078 | * Gets buffer object's tiling flags. Used by GEM ioctl or kernel driver to |
1079 | * set the tiling flags on a buffer. |
1080 | */ |
1081 | void amdgpu_bo_get_tiling_flags(struct amdgpu_bo *bo, u64 *tiling_flags) |
1082 | { |
1083 | lockdep_assert_held(&bo->tbo.resv->lock.base); |
1084 | |
1085 | if (tiling_flags) |
1086 | *tiling_flags = bo->tiling_flags; |
1087 | } |
1088 | |
1089 | /** |
1090 | * amdgpu_bo_set_metadata - set metadata |
1091 | * @bo: &amdgpu_bo buffer object |
1092 | * @metadata: new metadata |
1093 | * @metadata_size: size of the new metadata |
1094 | * @flags: flags of the new metadata |
1095 | * |
1096 | * Sets buffer object's metadata, its size and flags. |
1097 | * Used via GEM ioctl. |
1098 | * |
1099 | * Returns: |
1100 | * 0 for success or a negative error code on failure. |
1101 | */ |
1102 | int amdgpu_bo_set_metadata (struct amdgpu_bo *bo, void *metadata, |
1103 | uint32_t metadata_size, uint64_t flags) |
1104 | { |
1105 | void *buffer; |
1106 | |
1107 | if (!metadata_size) { |
1108 | if (bo->metadata_size) { |
1109 | kfree(bo->metadata); |
1110 | bo->metadata = NULL; |
1111 | bo->metadata_size = 0; |
1112 | } |
1113 | return 0; |
1114 | } |
1115 | |
1116 | if (metadata == NULL) |
1117 | return -EINVAL; |
1118 | |
1119 | buffer = kmemdup(metadata, metadata_size, GFP_KERNEL); |
1120 | if (buffer == NULL) |
1121 | return -ENOMEM; |
1122 | |
1123 | kfree(bo->metadata); |
1124 | bo->metadata_flags = flags; |
1125 | bo->metadata = buffer; |
1126 | bo->metadata_size = metadata_size; |
1127 | |
1128 | return 0; |
1129 | } |
1130 | |
1131 | /** |
1132 | * amdgpu_bo_get_metadata - get metadata |
1133 | * @bo: &amdgpu_bo buffer object |
1134 | * @buffer: returned metadata |
1135 | * @buffer_size: size of the buffer |
1136 | * @metadata_size: size of the returned metadata |
1137 | * @flags: flags of the returned metadata |
1138 | * |
1139 | * Gets buffer object's metadata, its size and flags. buffer_size shall not be |
1140 | * less than metadata_size. |
1141 | * Used via GEM ioctl. |
1142 | * |
1143 | * Returns: |
1144 | * 0 for success or a negative error code on failure. |
1145 | */ |
1146 | int amdgpu_bo_get_metadata(struct amdgpu_bo *bo, void *buffer, |
1147 | size_t buffer_size, uint32_t *metadata_size, |
1148 | uint64_t *flags) |
1149 | { |
1150 | if (!buffer && !metadata_size) |
1151 | return -EINVAL; |
1152 | |
1153 | if (buffer) { |
1154 | if (buffer_size < bo->metadata_size) |
1155 | return -EINVAL; |
1156 | |
1157 | if (bo->metadata_size) |
1158 | memcpy(buffer, bo->metadata, bo->metadata_size); |
1159 | } |
1160 | |
1161 | if (metadata_size) |
1162 | *metadata_size = bo->metadata_size; |
1163 | if (flags) |
1164 | *flags = bo->metadata_flags; |
1165 | |
1166 | return 0; |
1167 | } |
1168 | |
1169 | /** |
1170 | * amdgpu_bo_move_notify - notification about a memory move |
1171 | * @bo: pointer to a buffer object |
1172 | * @evict: if this move is evicting the buffer from the graphics address space |
1173 | * @new_mem: new information of the bufer object |
1174 | * |
1175 | * Marks the corresponding &amdgpu_bo buffer object as invalid, also performs |
1176 | * bookkeeping. |
1177 | * TTM driver callback which is called when ttm moves a buffer. |
1178 | */ |
1179 | void amdgpu_bo_move_notify(struct ttm_buffer_object *bo, |
1180 | bool evict, |
1181 | struct ttm_mem_reg *new_mem) |
1182 | { |
1183 | struct amdgpu_device *adev = amdgpu_ttm_adev(bo->bdev); |
1184 | struct amdgpu_bo *abo; |
1185 | struct ttm_mem_reg *old_mem = &bo->mem; |
1186 | |
1187 | if (!amdgpu_bo_is_amdgpu_bo(bo)) |
1188 | return; |
1189 | |
1190 | abo = ttm_to_amdgpu_bo(bo); |
1191 | amdgpu_vm_bo_invalidate(adev, abo, evict); |
1192 | |
1193 | amdgpu_bo_kunmap(abo); |
1194 | |
1195 | /* remember the eviction */ |
1196 | if (evict) |
1197 | atomic64_inc(&adev->num_evictions); |
1198 | |
1199 | /* update statistics */ |
1200 | if (!new_mem) |
1201 | return; |
1202 | |
1203 | /* move_notify is called before move happens */ |
1204 | trace_amdgpu_bo_move(abo, new_mem->mem_type, old_mem->mem_type); |
1205 | } |
1206 | |
1207 | /** |
1208 | * amdgpu_bo_fault_reserve_notify - notification about a memory fault |
1209 | * @bo: pointer to a buffer object |
1210 | * |
1211 | * Notifies the driver we are taking a fault on this BO and have reserved it, |
1212 | * also performs bookkeeping. |
1213 | * TTM driver callback for dealing with vm faults. |
1214 | * |
1215 | * Returns: |
1216 | * 0 for success or a negative error code on failure. |
1217 | */ |
1218 | int amdgpu_bo_fault_reserve_notify(struct ttm_buffer_object *bo) |
1219 | { |
1220 | struct amdgpu_device *adev = amdgpu_ttm_adev(bo->bdev); |
1221 | struct ttm_operation_ctx ctx = { false, false }; |
1222 | struct amdgpu_bo *abo; |
1223 | unsigned long offset, size; |
1224 | int r; |
1225 | |
1226 | if (!amdgpu_bo_is_amdgpu_bo(bo)) |
1227 | return 0; |
1228 | |
1229 | abo = ttm_to_amdgpu_bo(bo); |
1230 | |
1231 | /* Remember that this BO was accessed by the CPU */ |
1232 | abo->flags |= AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED; |
1233 | |
1234 | if (bo->mem.mem_type != TTM_PL_VRAM) |
1235 | return 0; |
1236 | |
1237 | size = bo->mem.num_pages << PAGE_SHIFT; |
1238 | offset = bo->mem.start << PAGE_SHIFT; |
1239 | if ((offset + size) <= adev->gmc.visible_vram_size) |
1240 | return 0; |
1241 | |
1242 | /* Can't move a pinned BO to visible VRAM */ |
1243 | if (abo->pin_count > 0) |
1244 | return -EINVAL; |
1245 | |
1246 | /* hurrah the memory is not visible ! */ |
1247 | atomic64_inc(&adev->num_vram_cpu_page_faults); |
1248 | amdgpu_bo_placement_from_domain(abo, AMDGPU_GEM_DOMAIN_VRAM | |
1249 | AMDGPU_GEM_DOMAIN_GTT); |
1250 | |
1251 | /* Avoid costly evictions; only set GTT as a busy placement */ |
1252 | abo->placement.num_busy_placement = 1; |
1253 | abo->placement.busy_placement = &abo->placements[1]; |
1254 | |
1255 | r = ttm_bo_validate(bo, &abo->placement, &ctx); |
1256 | if (unlikely(r != 0)) |
1257 | return r; |
1258 | |
1259 | offset = bo->mem.start << PAGE_SHIFT; |
1260 | /* this should never happen */ |
1261 | if (bo->mem.mem_type == TTM_PL_VRAM && |
1262 | (offset + size) > adev->gmc.visible_vram_size) |
1263 | return -EINVAL; |
1264 | |
1265 | return 0; |
1266 | } |
1267 | |
1268 | /** |
1269 | * amdgpu_bo_fence - add fence to buffer object |
1270 | * |
1271 | * @bo: buffer object in question |
1272 | * @fence: fence to add |
1273 | * @shared: true if fence should be added shared |
1274 | * |
1275 | */ |
1276 | void amdgpu_bo_fence(struct amdgpu_bo *bo, struct dma_fence *fence, |
1277 | bool shared) |
1278 | { |
1279 | struct reservation_object *resv = bo->tbo.resv; |
1280 | |
1281 | if (shared) |
1282 | reservation_object_add_shared_fence(resv, fence); |
1283 | else |
1284 | reservation_object_add_excl_fence(resv, fence); |
1285 | } |
1286 | |
1287 | /** |
1288 | * amdgpu_sync_wait_resv - Wait for BO reservation fences |
1289 | * |
1290 | * @bo: buffer object |
1291 | * @owner: fence owner |
1292 | * @intr: Whether the wait is interruptible |
1293 | * |
1294 | * Returns: |
1295 | * 0 on success, errno otherwise. |
1296 | */ |
1297 | int amdgpu_bo_sync_wait(struct amdgpu_bo *bo, void *owner, bool intr) |
1298 | { |
1299 | struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev); |
1300 | struct amdgpu_sync sync; |
1301 | int r; |
1302 | |
1303 | amdgpu_sync_create(&sync); |
1304 | amdgpu_sync_resv(adev, &sync, bo->tbo.resv, owner, false); |
1305 | r = amdgpu_sync_wait(&sync, intr); |
1306 | amdgpu_sync_free(&sync); |
1307 | |
1308 | return r; |
1309 | } |
1310 | |
1311 | /** |
1312 | * amdgpu_bo_gpu_offset - return GPU offset of bo |
1313 | * @bo: amdgpu object for which we query the offset |
1314 | * |
1315 | * Note: object should either be pinned or reserved when calling this |
1316 | * function, it might be useful to add check for this for debugging. |
1317 | * |
1318 | * Returns: |
1319 | * current GPU offset of the object. |
1320 | */ |
1321 | u64 amdgpu_bo_gpu_offset(struct amdgpu_bo *bo) |
1322 | { |
1323 | WARN_ON_ONCE(bo->tbo.mem.mem_type == TTM_PL_SYSTEM); |
1324 | WARN_ON_ONCE(!ww_mutex_is_locked(&bo->tbo.resv->lock) && |
1325 | !bo->pin_count && bo->tbo.type != ttm_bo_type_kernel); |
1326 | WARN_ON_ONCE(bo->tbo.mem.start == AMDGPU_BO_INVALID_OFFSET); |
1327 | WARN_ON_ONCE(bo->tbo.mem.mem_type == TTM_PL_VRAM && |
1328 | !(bo->flags & AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS)); |
1329 | |
1330 | return amdgpu_gmc_sign_extend(bo->tbo.offset); |
1331 | } |
1332 | |
1333 | /** |
1334 | * amdgpu_bo_get_preferred_pin_domain - get preferred domain for scanout |
1335 | * @adev: amdgpu device object |
1336 | * @domain: allowed :ref:`memory domains <amdgpu_memory_domains>` |
1337 | * |
1338 | * Returns: |
1339 | * Which of the allowed domains is preferred for pinning the BO for scanout. |
1340 | */ |
1341 | uint32_t amdgpu_bo_get_preferred_pin_domain(struct amdgpu_device *adev, |
1342 | uint32_t domain) |
1343 | { |
1344 | if (domain == (AMDGPU_GEM_DOMAIN_VRAM | AMDGPU_GEM_DOMAIN_GTT)) { |
1345 | domain = AMDGPU_GEM_DOMAIN_VRAM; |
1346 | if (adev->gmc.real_vram_size <= AMDGPU_SG_THRESHOLD) |
1347 | domain = AMDGPU_GEM_DOMAIN_GTT; |
1348 | } |
1349 | return domain; |
1350 | } |
1351 | |