1d38ceaf9SAlex Deucher /*
2d38ceaf9SAlex Deucher * Copyright 2009 Jerome Glisse.
3d38ceaf9SAlex Deucher * All Rights Reserved.
4d38ceaf9SAlex Deucher *
5d38ceaf9SAlex Deucher * Permission is hereby granted, free of charge, to any person obtaining a
6d38ceaf9SAlex Deucher * copy of this software and associated documentation files (the
7d38ceaf9SAlex Deucher * "Software"), to deal in the Software without restriction, including
8d38ceaf9SAlex Deucher * without limitation the rights to use, copy, modify, merge, publish,
9d38ceaf9SAlex Deucher * distribute, sub license, and/or sell copies of the Software, and to
10d38ceaf9SAlex Deucher * permit persons to whom the Software is furnished to do so, subject to
11d38ceaf9SAlex Deucher * the following conditions:
12d38ceaf9SAlex Deucher *
13d38ceaf9SAlex Deucher * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14d38ceaf9SAlex Deucher * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15d38ceaf9SAlex Deucher * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
16d38ceaf9SAlex Deucher * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
17d38ceaf9SAlex Deucher * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
18d38ceaf9SAlex Deucher * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
19d38ceaf9SAlex Deucher * USE OR OTHER DEALINGS IN THE SOFTWARE.
20d38ceaf9SAlex Deucher *
21d38ceaf9SAlex Deucher * The above copyright notice and this permission notice (including the
22d38ceaf9SAlex Deucher * next paragraph) shall be included in all copies or substantial portions
23d38ceaf9SAlex Deucher * of the Software.
24d38ceaf9SAlex Deucher *
25d38ceaf9SAlex Deucher */
26d38ceaf9SAlex Deucher /*
27d38ceaf9SAlex Deucher * Authors:
28d38ceaf9SAlex Deucher * Jerome Glisse <glisse@freedesktop.org>
29d38ceaf9SAlex Deucher * Thomas Hellstrom <thomas-at-tungstengraphics-dot-com>
30d38ceaf9SAlex Deucher * Dave Airlie
31d38ceaf9SAlex Deucher */
32d38ceaf9SAlex Deucher #include <linux/list.h>
33d38ceaf9SAlex Deucher #include <linux/slab.h>
342d4dad27SChristian König #include <linux/dma-buf.h>
35fdf2f6c5SSam Ravnborg
3662d5f9f7SLeslie Shi #include <drm/drm_drv.h>
37d38ceaf9SAlex Deucher #include <drm/amdgpu_drm.h>
38a187f17fSOded Gabbay #include <drm/drm_cache.h>
39d38ceaf9SAlex Deucher #include "amdgpu.h"
40d38ceaf9SAlex Deucher #include "amdgpu_trace.h"
41a46a2cd1SFelix Kuehling #include "amdgpu_amdkfd.h"
42d38ceaf9SAlex Deucher
436f4e8d6eSSamuel Li /**
446f4e8d6eSSamuel Li * DOC: amdgpu_object
456f4e8d6eSSamuel Li *
466f4e8d6eSSamuel Li * This defines the interfaces to operate on an &amdgpu_bo buffer object which
476f4e8d6eSSamuel Li * represents memory used by driver (VRAM, system memory, etc.). The driver
486f4e8d6eSSamuel Li * provides DRM/GEM APIs to userspace. DRM/GEM APIs then use these interfaces
496f4e8d6eSSamuel Li * to create/destroy/set buffer object which are then managed by the kernel TTM
506f4e8d6eSSamuel Li * memory manager.
516f4e8d6eSSamuel Li * The interfaces are also used internally by kernel clients, including gfx,
526f4e8d6eSSamuel Li * uvd, etc. for kernel managed allocations used by the GPU.
536f4e8d6eSSamuel Li *
546f4e8d6eSSamuel Li */
556f4e8d6eSSamuel Li
amdgpu_bo_destroy(struct ttm_buffer_object * tbo)56c704ab18SChristian König static void amdgpu_bo_destroy(struct ttm_buffer_object *tbo)
57d38ceaf9SAlex Deucher {
58b82485fdSAndres Rodriguez struct amdgpu_bo *bo = ttm_to_amdgpu_bo(tbo);
59d38ceaf9SAlex Deucher
606375bbb4SChristian König amdgpu_bo_kunmap(bo);
61d38ceaf9SAlex Deucher
62c105de28SGerd Hoffmann if (bo->tbo.base.import_attach)
63c105de28SGerd Hoffmann drm_prime_gem_destroy(&bo->tbo.base, bo->tbo.sg);
64c105de28SGerd Hoffmann drm_gem_object_release(&bo->tbo.base);
6523e24fbbSNirmoy Das amdgpu_bo_unref(&bo->parent);
6623e24fbbSNirmoy Das kvfree(bo);
6723e24fbbSNirmoy Das }
6823e24fbbSNirmoy Das
amdgpu_bo_user_destroy(struct ttm_buffer_object * tbo)6923e24fbbSNirmoy Das static void amdgpu_bo_user_destroy(struct ttm_buffer_object *tbo)
7023e24fbbSNirmoy Das {
7123e24fbbSNirmoy Das struct amdgpu_bo *bo = ttm_to_amdgpu_bo(tbo);
7223e24fbbSNirmoy Das struct amdgpu_bo_user *ubo;
7323e24fbbSNirmoy Das
7423e24fbbSNirmoy Das ubo = to_amdgpu_bo_user(bo);
7523e24fbbSNirmoy Das kfree(ubo->metadata);
7623e24fbbSNirmoy Das amdgpu_bo_destroy(tbo);
7723e24fbbSNirmoy Das }
7823e24fbbSNirmoy Das
amdgpu_bo_vm_destroy(struct ttm_buffer_object * tbo)7923e24fbbSNirmoy Das static void amdgpu_bo_vm_destroy(struct ttm_buffer_object *tbo)
8023e24fbbSNirmoy Das {
8123e24fbbSNirmoy Das struct amdgpu_device *adev = amdgpu_ttm_adev(tbo->bdev);
82cbb63eccSHoratio Zhang struct amdgpu_bo *shadow_bo = ttm_to_amdgpu_bo(tbo), *bo;
83e18aaea7SNirmoy Das struct amdgpu_bo_vm *vmbo;
8423e24fbbSNirmoy Das
85cbb63eccSHoratio Zhang bo = shadow_bo->parent;
86e18aaea7SNirmoy Das vmbo = to_amdgpu_bo_vm(bo);
8736e499b2Swentalou /* in case amdgpu_device_recover_vram got NULL of bo->parent */
88e18aaea7SNirmoy Das if (!list_empty(&vmbo->shadow_list)) {
89a7d64de6SChristian König mutex_lock(&adev->shadow_list_lock);
90e18aaea7SNirmoy Das list_del_init(&vmbo->shadow_list);
91a7d64de6SChristian König mutex_unlock(&adev->shadow_list_lock);
920c4e7fa5SChunming Zhou }
9336e499b2Swentalou
9423e24fbbSNirmoy Das amdgpu_bo_destroy(tbo);
95d38ceaf9SAlex Deucher }
96d38ceaf9SAlex Deucher
976f4e8d6eSSamuel Li /**
98c704ab18SChristian König * amdgpu_bo_is_amdgpu_bo - check if the buffer object is an &amdgpu_bo
996f4e8d6eSSamuel Li * @bo: buffer object to be checked
1006f4e8d6eSSamuel Li *
1016f4e8d6eSSamuel Li * Uses destroy function associated with the object to determine if this is
1026f4e8d6eSSamuel Li * an &amdgpu_bo.
1036f4e8d6eSSamuel Li *
1042472e11bSMichel Dänzer * Returns:
1052472e11bSMichel Dänzer * true if the object belongs to &amdgpu_bo, false if not.
1066f4e8d6eSSamuel Li */
amdgpu_bo_is_amdgpu_bo(struct ttm_buffer_object * bo)107c704ab18SChristian König bool amdgpu_bo_is_amdgpu_bo(struct ttm_buffer_object *bo)
108d38ceaf9SAlex Deucher {
10923e24fbbSNirmoy Das if (bo->destroy == &amdgpu_bo_destroy ||
11023e24fbbSNirmoy Das bo->destroy == &amdgpu_bo_user_destroy ||
11123e24fbbSNirmoy Das bo->destroy == &amdgpu_bo_vm_destroy)
112d38ceaf9SAlex Deucher return true;
11323e24fbbSNirmoy Das
114d38ceaf9SAlex Deucher return false;
115d38ceaf9SAlex Deucher }
116d38ceaf9SAlex Deucher
1176f4e8d6eSSamuel Li /**
118c704ab18SChristian König * amdgpu_bo_placement_from_domain - set buffer's placement
1196f4e8d6eSSamuel Li * @abo: &amdgpu_bo buffer object whose placement is to be set
1206f4e8d6eSSamuel Li * @domain: requested domain
1216f4e8d6eSSamuel Li *
1226f4e8d6eSSamuel Li * Sets buffer's placement according to requested domain and the buffer's
1236f4e8d6eSSamuel Li * flags.
1246f4e8d6eSSamuel Li */
amdgpu_bo_placement_from_domain(struct amdgpu_bo * abo,u32 domain)125c704ab18SChristian König void amdgpu_bo_placement_from_domain(struct amdgpu_bo *abo, u32 domain)
126d38ceaf9SAlex Deucher {
127c09312a6SChristian König struct amdgpu_device *adev = amdgpu_ttm_adev(abo->tbo.bdev);
128c09312a6SChristian König struct ttm_placement *placement = &abo->placement;
129c09312a6SChristian König struct ttm_place *places = abo->placements;
130c09312a6SChristian König u64 flags = abo->flags;
1316369f6f1SChristian König u32 c = 0;
1327e5a547fSChunming Zhou
133d38ceaf9SAlex Deucher if (domain & AMDGPU_GEM_DOMAIN_VRAM) {
1341d6ecab1SSrinivasan Shanmugam unsigned int visible_pfn = adev->gmc.visible_vram_size >> PAGE_SHIFT;
1353ebfd221SPhilip Yang int8_t mem_id = KFD_XCP_MEM_ID(adev, abo->xcp_id);
136faceaf6aSChristian König
1373ebfd221SPhilip Yang if (adev->gmc.mem_partitions && mem_id >= 0) {
1383ebfd221SPhilip Yang places[c].fpfn = adev->gmc.mem_partitions[mem_id].range.fpfn;
1396cfba94aSPhilip Yang /*
1406cfba94aSPhilip Yang * memory partition range lpfn is inclusive start + size - 1
1416cfba94aSPhilip Yang * TTM place lpfn is exclusive start + size
1426cfba94aSPhilip Yang */
1433ebfd221SPhilip Yang places[c].lpfn = adev->gmc.mem_partitions[mem_id].range.lpfn + 1;
1447f6db894SPhilip Yang } else {
145faceaf6aSChristian König places[c].fpfn = 0;
14689bb5752SChristian König places[c].lpfn = 0;
1477f6db894SPhilip Yang }
14848e07c23SChristian König places[c].mem_type = TTM_PL_VRAM;
149ce65b874SChristian König places[c].flags = 0;
15089bb5752SChristian König
151faceaf6aSChristian König if (flags & AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED)
1527f6db894SPhilip Yang places[c].lpfn = min_not_zero(places[c].lpfn, visible_pfn);
15359eddd4eSArunpravin Paneer Selvam else
154faceaf6aSChristian König places[c].flags |= TTM_PL_FLAG_TOPDOWN;
15589bb5752SChristian König
15689bb5752SChristian König if (flags & AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS)
15789bb5752SChristian König places[c].flags |= TTM_PL_FLAG_CONTIGUOUS;
158faceaf6aSChristian König c++;
159d38ceaf9SAlex Deucher }
160d38ceaf9SAlex Deucher
161dc3499c7SAlex Deucher if (domain & AMDGPU_GEM_DOMAIN_DOORBELL) {
162dc3499c7SAlex Deucher places[c].fpfn = 0;
163dc3499c7SAlex Deucher places[c].lpfn = 0;
164dc3499c7SAlex Deucher places[c].mem_type = AMDGPU_PL_DOORBELL;
165dc3499c7SAlex Deucher places[c].flags = 0;
166dc3499c7SAlex Deucher c++;
167dc3499c7SAlex Deucher }
168dc3499c7SAlex Deucher
169d38ceaf9SAlex Deucher if (domain & AMDGPU_GEM_DOMAIN_GTT) {
170faceaf6aSChristian König places[c].fpfn = 0;
171faceaf6aSChristian König places[c].lpfn = 0;
172b453e42aSFelix Kuehling places[c].mem_type =
173b453e42aSFelix Kuehling abo->flags & AMDGPU_GEM_CREATE_PREEMPTIBLE ?
174b453e42aSFelix Kuehling AMDGPU_PL_PREEMPT : TTM_PL_TT;
17548e07c23SChristian König places[c].flags = 0;
176faceaf6aSChristian König c++;
177d38ceaf9SAlex Deucher }
178d38ceaf9SAlex Deucher
179d38ceaf9SAlex Deucher if (domain & AMDGPU_GEM_DOMAIN_CPU) {
180faceaf6aSChristian König places[c].fpfn = 0;
181faceaf6aSChristian König places[c].lpfn = 0;
18248e07c23SChristian König places[c].mem_type = TTM_PL_SYSTEM;
18348e07c23SChristian König places[c].flags = 0;
184faceaf6aSChristian König c++;
185d38ceaf9SAlex Deucher }
186d38ceaf9SAlex Deucher
187d38ceaf9SAlex Deucher if (domain & AMDGPU_GEM_DOMAIN_GDS) {
188faceaf6aSChristian König places[c].fpfn = 0;
189faceaf6aSChristian König places[c].lpfn = 0;
19048e07c23SChristian König places[c].mem_type = AMDGPU_PL_GDS;
191ce65b874SChristian König places[c].flags = 0;
192faceaf6aSChristian König c++;
193d38ceaf9SAlex Deucher }
194faceaf6aSChristian König
195d38ceaf9SAlex Deucher if (domain & AMDGPU_GEM_DOMAIN_GWS) {
196faceaf6aSChristian König places[c].fpfn = 0;
197faceaf6aSChristian König places[c].lpfn = 0;
19848e07c23SChristian König places[c].mem_type = AMDGPU_PL_GWS;
199ce65b874SChristian König places[c].flags = 0;
200faceaf6aSChristian König c++;
201d38ceaf9SAlex Deucher }
202faceaf6aSChristian König
203d38ceaf9SAlex Deucher if (domain & AMDGPU_GEM_DOMAIN_OA) {
204faceaf6aSChristian König places[c].fpfn = 0;
205faceaf6aSChristian König places[c].lpfn = 0;
20648e07c23SChristian König places[c].mem_type = AMDGPU_PL_OA;
207ce65b874SChristian König places[c].flags = 0;
208faceaf6aSChristian König c++;
209d38ceaf9SAlex Deucher }
210d38ceaf9SAlex Deucher
211d38ceaf9SAlex Deucher if (!c) {
212faceaf6aSChristian König places[c].fpfn = 0;
213faceaf6aSChristian König places[c].lpfn = 0;
21448e07c23SChristian König places[c].mem_type = TTM_PL_SYSTEM;
215ce65b874SChristian König places[c].flags = 0;
216faceaf6aSChristian König c++;
217d38ceaf9SAlex Deucher }
218d38ceaf9SAlex Deucher
219ea7acd7cSAndrey Grodzovsky BUG_ON(c > AMDGPU_BO_MAX_PLACEMENTS);
220bf314ca3SChristian König
221faceaf6aSChristian König placement->num_placement = c;
222faceaf6aSChristian König placement->placement = places;
223faceaf6aSChristian König
224faceaf6aSChristian König placement->num_busy_placement = c;
225faceaf6aSChristian König placement->busy_placement = places;
226d38ceaf9SAlex Deucher }
227d38ceaf9SAlex Deucher
2287c204889SChristian König /**
2299d903cbdSChristian König * amdgpu_bo_create_reserved - create reserved BO for kernel use
2307c204889SChristian König *
2317c204889SChristian König * @adev: amdgpu device object
2327c204889SChristian König * @size: size for the new BO
2337c204889SChristian König * @align: alignment for the new BO
2347c204889SChristian König * @domain: where to place it
23564350f1bSAndrey Grodzovsky * @bo_ptr: used to initialize BOs in structures
2367c204889SChristian König * @gpu_addr: GPU addr of the pinned BO
2377c204889SChristian König * @cpu_addr: optional CPU address mapping
2387c204889SChristian König *
2399d903cbdSChristian König * Allocates and pins a BO for kernel internal use, and returns it still
2409d903cbdSChristian König * reserved.
2417c204889SChristian König *
24264350f1bSAndrey Grodzovsky * Note: For bo_ptr new BO is only created if bo_ptr points to NULL.
24364350f1bSAndrey Grodzovsky *
2442472e11bSMichel Dänzer * Returns:
2452472e11bSMichel Dänzer * 0 on success, negative error code otherwise.
2467c204889SChristian König */
amdgpu_bo_create_reserved(struct amdgpu_device * adev,unsigned long size,int align,u32 domain,struct amdgpu_bo ** bo_ptr,u64 * gpu_addr,void ** cpu_addr)2479d903cbdSChristian König int amdgpu_bo_create_reserved(struct amdgpu_device *adev,
2487c204889SChristian König unsigned long size, int align,
2497c204889SChristian König u32 domain, struct amdgpu_bo **bo_ptr,
2507c204889SChristian König u64 *gpu_addr, void **cpu_addr)
2517c204889SChristian König {
2523216c6b7SChunming Zhou struct amdgpu_bo_param bp;
25353766e5aSChristian König bool free = false;
2547c204889SChristian König int r;
2557c204889SChristian König
25621a7e77fSChristian König if (!size) {
25721a7e77fSChristian König amdgpu_bo_unref(bo_ptr);
25821a7e77fSChristian König return 0;
25921a7e77fSChristian König }
26021a7e77fSChristian König
2613216c6b7SChunming Zhou memset(&bp, 0, sizeof(bp));
2623216c6b7SChunming Zhou bp.size = size;
2633216c6b7SChunming Zhou bp.byte_align = align;
2643216c6b7SChunming Zhou bp.domain = domain;
265828d6fdeSTianci.Yin bp.flags = cpu_addr ? AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED
266828d6fdeSTianci.Yin : AMDGPU_GEM_CREATE_NO_CPU_ACCESS;
267828d6fdeSTianci.Yin bp.flags |= AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS;
2683216c6b7SChunming Zhou bp.type = ttm_bo_type_kernel;
2693216c6b7SChunming Zhou bp.resv = NULL;
2709fd5543eSNirmoy Das bp.bo_ptr_size = sizeof(struct amdgpu_bo);
2713216c6b7SChunming Zhou
27253766e5aSChristian König if (!*bo_ptr) {
2733216c6b7SChunming Zhou r = amdgpu_bo_create(adev, &bp, bo_ptr);
2747c204889SChristian König if (r) {
27553766e5aSChristian König dev_err(adev->dev, "(%d) failed to allocate kernel bo\n",
27653766e5aSChristian König r);
2777c204889SChristian König return r;
2787c204889SChristian König }
27953766e5aSChristian König free = true;
28053766e5aSChristian König }
2817c204889SChristian König
2827c204889SChristian König r = amdgpu_bo_reserve(*bo_ptr, false);
2837c204889SChristian König if (r) {
2847c204889SChristian König dev_err(adev->dev, "(%d) failed to reserve kernel bo\n", r);
2857c204889SChristian König goto error_free;
2867c204889SChristian König }
2877c204889SChristian König
2887b7c6c81SJunwei Zhang r = amdgpu_bo_pin(*bo_ptr, domain);
2897c204889SChristian König if (r) {
2907c204889SChristian König dev_err(adev->dev, "(%d) kernel bo pin failed\n", r);
2917c204889SChristian König goto error_unreserve;
2927c204889SChristian König }
293bb812f1eSJunwei Zhang
294bb812f1eSJunwei Zhang r = amdgpu_ttm_alloc_gart(&(*bo_ptr)->tbo);
295bb812f1eSJunwei Zhang if (r) {
296bb812f1eSJunwei Zhang dev_err(adev->dev, "%p bind failed\n", *bo_ptr);
297bb812f1eSJunwei Zhang goto error_unpin;
298bb812f1eSJunwei Zhang }
299bb812f1eSJunwei Zhang
3007b7c6c81SJunwei Zhang if (gpu_addr)
3017b7c6c81SJunwei Zhang *gpu_addr = amdgpu_bo_gpu_offset(*bo_ptr);
3027c204889SChristian König
3037c204889SChristian König if (cpu_addr) {
3047c204889SChristian König r = amdgpu_bo_kmap(*bo_ptr, cpu_addr);
3057c204889SChristian König if (r) {
3067c204889SChristian König dev_err(adev->dev, "(%d) kernel bo map failed\n", r);
307dc407ee0SJunwei Zhang goto error_unpin;
3087c204889SChristian König }
3097c204889SChristian König }
3107c204889SChristian König
3117c204889SChristian König return 0;
3127c204889SChristian König
313bb812f1eSJunwei Zhang error_unpin:
314bb812f1eSJunwei Zhang amdgpu_bo_unpin(*bo_ptr);
3157c204889SChristian König error_unreserve:
3167c204889SChristian König amdgpu_bo_unreserve(*bo_ptr);
3177c204889SChristian König
3187c204889SChristian König error_free:
31953766e5aSChristian König if (free)
3207c204889SChristian König amdgpu_bo_unref(bo_ptr);
3217c204889SChristian König
3227c204889SChristian König return r;
3237c204889SChristian König }
3247c204889SChristian König
325aa1d562eSJunwei Zhang /**
3269d903cbdSChristian König * amdgpu_bo_create_kernel - create BO for kernel use
3279d903cbdSChristian König *
3289d903cbdSChristian König * @adev: amdgpu device object
3299d903cbdSChristian König * @size: size for the new BO
3309d903cbdSChristian König * @align: alignment for the new BO
3319d903cbdSChristian König * @domain: where to place it
33264350f1bSAndrey Grodzovsky * @bo_ptr: used to initialize BOs in structures
3339d903cbdSChristian König * @gpu_addr: GPU addr of the pinned BO
3349d903cbdSChristian König * @cpu_addr: optional CPU address mapping
3359d903cbdSChristian König *
3369d903cbdSChristian König * Allocates and pins a BO for kernel internal use.
3379d903cbdSChristian König *
33864350f1bSAndrey Grodzovsky * Note: For bo_ptr new BO is only created if bo_ptr points to NULL.
33964350f1bSAndrey Grodzovsky *
3402472e11bSMichel Dänzer * Returns:
3412472e11bSMichel Dänzer * 0 on success, negative error code otherwise.
3429d903cbdSChristian König */
amdgpu_bo_create_kernel(struct amdgpu_device * adev,unsigned long size,int align,u32 domain,struct amdgpu_bo ** bo_ptr,u64 * gpu_addr,void ** cpu_addr)3439d903cbdSChristian König int amdgpu_bo_create_kernel(struct amdgpu_device *adev,
3449d903cbdSChristian König unsigned long size, int align,
3459d903cbdSChristian König u32 domain, struct amdgpu_bo **bo_ptr,
3469d903cbdSChristian König u64 *gpu_addr, void **cpu_addr)
3479d903cbdSChristian König {
3489d903cbdSChristian König int r;
3499d903cbdSChristian König
3509d903cbdSChristian König r = amdgpu_bo_create_reserved(adev, size, align, domain, bo_ptr,
3519d903cbdSChristian König gpu_addr, cpu_addr);
3529d903cbdSChristian König
3539d903cbdSChristian König if (r)
3549d903cbdSChristian König return r;
3559d903cbdSChristian König
356ddaf5013STom St Denis if (*bo_ptr)
3579d903cbdSChristian König amdgpu_bo_unreserve(*bo_ptr);
3589d903cbdSChristian König
3599d903cbdSChristian König return 0;
3609d903cbdSChristian König }
3619d903cbdSChristian König
3629d903cbdSChristian König /**
363de7b45baSChristian König * amdgpu_bo_create_kernel_at - create BO for kernel use at specific location
364de7b45baSChristian König *
365de7b45baSChristian König * @adev: amdgpu device object
366de7b45baSChristian König * @offset: offset of the BO
367de7b45baSChristian König * @size: size of the BO
368de7b45baSChristian König * @bo_ptr: used to initialize BOs in structures
369de7b45baSChristian König * @cpu_addr: optional CPU address mapping
370de7b45baSChristian König *
3713273f116SLuben Tuikov * Creates a kernel BO at a specific offset in VRAM.
372de7b45baSChristian König *
373de7b45baSChristian König * Returns:
374de7b45baSChristian König * 0 on success, negative error code otherwise.
375de7b45baSChristian König */
amdgpu_bo_create_kernel_at(struct amdgpu_device * adev,uint64_t offset,uint64_t size,struct amdgpu_bo ** bo_ptr,void ** cpu_addr)376de7b45baSChristian König int amdgpu_bo_create_kernel_at(struct amdgpu_device *adev,
3773273f116SLuben Tuikov uint64_t offset, uint64_t size,
378de7b45baSChristian König struct amdgpu_bo **bo_ptr, void **cpu_addr)
379de7b45baSChristian König {
380de7b45baSChristian König struct ttm_operation_ctx ctx = { false, false };
381de7b45baSChristian König unsigned int i;
382de7b45baSChristian König int r;
383de7b45baSChristian König
384de7b45baSChristian König offset &= PAGE_MASK;
385de7b45baSChristian König size = ALIGN(size, PAGE_SIZE);
386de7b45baSChristian König
3873273f116SLuben Tuikov r = amdgpu_bo_create_reserved(adev, size, PAGE_SIZE,
3883273f116SLuben Tuikov AMDGPU_GEM_DOMAIN_VRAM, bo_ptr, NULL,
3893273f116SLuben Tuikov cpu_addr);
390de7b45baSChristian König if (r)
391de7b45baSChristian König return r;
392de7b45baSChristian König
39337912e96SAlex Deucher if ((*bo_ptr) == NULL)
39437912e96SAlex Deucher return 0;
39537912e96SAlex Deucher
396de7b45baSChristian König /*
397de7b45baSChristian König * Remove the original mem node and create a new one at the request
398de7b45baSChristian König * position.
399de7b45baSChristian König */
4004a246528SChristian König if (cpu_addr)
4014a246528SChristian König amdgpu_bo_kunmap(*bo_ptr);
4024a246528SChristian König
403bfa3357eSChristian König ttm_resource_free(&(*bo_ptr)->tbo, &(*bo_ptr)->tbo.resource);
4044a246528SChristian König
405de7b45baSChristian König for (i = 0; i < (*bo_ptr)->placement.num_placement; ++i) {
406de7b45baSChristian König (*bo_ptr)->placements[i].fpfn = offset >> PAGE_SHIFT;
407de7b45baSChristian König (*bo_ptr)->placements[i].lpfn = (offset + size) >> PAGE_SHIFT;
408de7b45baSChristian König }
409de7b45baSChristian König r = ttm_bo_mem_space(&(*bo_ptr)->tbo, &(*bo_ptr)->placement,
410bfa3357eSChristian König &(*bo_ptr)->tbo.resource, &ctx);
411de7b45baSChristian König if (r)
412de7b45baSChristian König goto error;
413de7b45baSChristian König
414de7b45baSChristian König if (cpu_addr) {
415de7b45baSChristian König r = amdgpu_bo_kmap(*bo_ptr, cpu_addr);
416de7b45baSChristian König if (r)
417de7b45baSChristian König goto error;
418de7b45baSChristian König }
419de7b45baSChristian König
420de7b45baSChristian König amdgpu_bo_unreserve(*bo_ptr);
421de7b45baSChristian König return 0;
422de7b45baSChristian König
423de7b45baSChristian König error:
424de7b45baSChristian König amdgpu_bo_unreserve(*bo_ptr);
425de7b45baSChristian König amdgpu_bo_unref(bo_ptr);
426de7b45baSChristian König return r;
427de7b45baSChristian König }
428de7b45baSChristian König
429de7b45baSChristian König /**
430aa1d562eSJunwei Zhang * amdgpu_bo_free_kernel - free BO for kernel use
431aa1d562eSJunwei Zhang *
432aa1d562eSJunwei Zhang * @bo: amdgpu BO to free
4332472e11bSMichel Dänzer * @gpu_addr: pointer to where the BO's GPU memory space address was stored
4342472e11bSMichel Dänzer * @cpu_addr: pointer to where the BO's CPU memory space address was stored
435aa1d562eSJunwei Zhang *
436aa1d562eSJunwei Zhang * unmaps and unpin a BO for kernel internal use.
437aa1d562eSJunwei Zhang */
amdgpu_bo_free_kernel(struct amdgpu_bo ** bo,u64 * gpu_addr,void ** cpu_addr)438aa1d562eSJunwei Zhang void amdgpu_bo_free_kernel(struct amdgpu_bo **bo, u64 *gpu_addr,
439aa1d562eSJunwei Zhang void **cpu_addr)
440aa1d562eSJunwei Zhang {
441aa1d562eSJunwei Zhang if (*bo == NULL)
442aa1d562eSJunwei Zhang return;
443aa1d562eSJunwei Zhang
4444d2ccd96SChristian König WARN_ON(amdgpu_ttm_adev((*bo)->tbo.bdev)->in_suspend);
4454d2ccd96SChristian König
446f3aa745eSAlex Xie if (likely(amdgpu_bo_reserve(*bo, true) == 0)) {
447aa1d562eSJunwei Zhang if (cpu_addr)
448aa1d562eSJunwei Zhang amdgpu_bo_kunmap(*bo);
449aa1d562eSJunwei Zhang
450aa1d562eSJunwei Zhang amdgpu_bo_unpin(*bo);
451aa1d562eSJunwei Zhang amdgpu_bo_unreserve(*bo);
452aa1d562eSJunwei Zhang }
453aa1d562eSJunwei Zhang amdgpu_bo_unref(bo);
454aa1d562eSJunwei Zhang
455aa1d562eSJunwei Zhang if (gpu_addr)
456aa1d562eSJunwei Zhang *gpu_addr = 0;
457aa1d562eSJunwei Zhang
458aa1d562eSJunwei Zhang if (cpu_addr)
459aa1d562eSJunwei Zhang *cpu_addr = NULL;
460aa1d562eSJunwei Zhang }
461aa1d562eSJunwei Zhang
46279c63123SAndrey Grodzovsky /* Validate bo size is bit bigger then the request domain */
amdgpu_bo_validate_size(struct amdgpu_device * adev,unsigned long size,u32 domain)46379c63123SAndrey Grodzovsky static bool amdgpu_bo_validate_size(struct amdgpu_device *adev,
46479c63123SAndrey Grodzovsky unsigned long size, u32 domain)
46579c63123SAndrey Grodzovsky {
4669de59bc2SDave Airlie struct ttm_resource_manager *man = NULL;
46779c63123SAndrey Grodzovsky
46879c63123SAndrey Grodzovsky /*
46979c63123SAndrey Grodzovsky * If GTT is part of requested domains the check must succeed to
4707554886dSLuben Tuikov * allow fall back to GTT.
47179c63123SAndrey Grodzovsky */
47279c63123SAndrey Grodzovsky if (domain & AMDGPU_GEM_DOMAIN_GTT) {
4736c28aed6SDave Airlie man = ttm_manager_type(&adev->mman.bdev, TTM_PL_TT);
47479c63123SAndrey Grodzovsky
4757554886dSLuben Tuikov if (man && size < man->size)
47679c63123SAndrey Grodzovsky return true;
4777554886dSLuben Tuikov else if (!man)
4787554886dSLuben Tuikov WARN_ON_ONCE("GTT domain requested but GTT mem manager uninitialized");
47979c63123SAndrey Grodzovsky goto fail;
4807554886dSLuben Tuikov } else if (domain & AMDGPU_GEM_DOMAIN_VRAM) {
4816c28aed6SDave Airlie man = ttm_manager_type(&adev->mman.bdev, TTM_PL_VRAM);
48279c63123SAndrey Grodzovsky
4837554886dSLuben Tuikov if (man && size < man->size)
48479c63123SAndrey Grodzovsky return true;
48579c63123SAndrey Grodzovsky goto fail;
48679c63123SAndrey Grodzovsky }
48779c63123SAndrey Grodzovsky
488dc3499c7SAlex Deucher /* TODO add more domains checks, such as AMDGPU_GEM_DOMAIN_CPU, _DOMAIN_DOORBELL */
48979c63123SAndrey Grodzovsky return true;
49079c63123SAndrey Grodzovsky
49179c63123SAndrey Grodzovsky fail:
49208e60facSLuben Tuikov if (man)
493299c776cSMichel Dänzer DRM_DEBUG("BO size %lu > total memory in domain: %llu\n", size,
4944499c90eSChristian König man->size);
49579c63123SAndrey Grodzovsky return false;
49679c63123SAndrey Grodzovsky }
49779c63123SAndrey Grodzovsky
amdgpu_bo_support_uswc(u64 bo_flags)4983d1b8ec7SAndrey Grodzovsky bool amdgpu_bo_support_uswc(u64 bo_flags)
4993d1b8ec7SAndrey Grodzovsky {
5003d1b8ec7SAndrey Grodzovsky
5013d1b8ec7SAndrey Grodzovsky #ifdef CONFIG_X86_32
5023d1b8ec7SAndrey Grodzovsky /* XXX: Write-combined CPU mappings of GTT seem broken on 32-bit
5033d1b8ec7SAndrey Grodzovsky * See https://bugs.freedesktop.org/show_bug.cgi?id=84627
5043d1b8ec7SAndrey Grodzovsky */
5053d1b8ec7SAndrey Grodzovsky return false;
5063d1b8ec7SAndrey Grodzovsky #elif defined(CONFIG_X86) && !defined(CONFIG_X86_PAT)
5073d1b8ec7SAndrey Grodzovsky /* Don't try to enable write-combining when it can't work, or things
5083d1b8ec7SAndrey Grodzovsky * may be slow
5093d1b8ec7SAndrey Grodzovsky * See https://bugs.freedesktop.org/show_bug.cgi?id=88758
5103d1b8ec7SAndrey Grodzovsky */
5113d1b8ec7SAndrey Grodzovsky
5123d1b8ec7SAndrey Grodzovsky #ifndef CONFIG_COMPILE_TEST
5133d1b8ec7SAndrey Grodzovsky #warning Please enable CONFIG_MTRR and CONFIG_X86_PAT for better performance \
5143d1b8ec7SAndrey Grodzovsky thanks to write-combining
5153d1b8ec7SAndrey Grodzovsky #endif
5163d1b8ec7SAndrey Grodzovsky
5173d1b8ec7SAndrey Grodzovsky if (bo_flags & AMDGPU_GEM_CREATE_CPU_GTT_USWC)
5183d1b8ec7SAndrey Grodzovsky DRM_INFO_ONCE("Please enable CONFIG_MTRR and CONFIG_X86_PAT for "
5193d1b8ec7SAndrey Grodzovsky "better performance thanks to write-combining\n");
5203d1b8ec7SAndrey Grodzovsky return false;
5213d1b8ec7SAndrey Grodzovsky #else
5223d1b8ec7SAndrey Grodzovsky /* For architectures that don't support WC memory,
5233d1b8ec7SAndrey Grodzovsky * mask out the WC flag from the BO
5243d1b8ec7SAndrey Grodzovsky */
5253d1b8ec7SAndrey Grodzovsky if (!drm_arch_can_wc_memory())
5263d1b8ec7SAndrey Grodzovsky return false;
5273d1b8ec7SAndrey Grodzovsky
5283d1b8ec7SAndrey Grodzovsky return true;
5293d1b8ec7SAndrey Grodzovsky #endif
5303d1b8ec7SAndrey Grodzovsky }
5313d1b8ec7SAndrey Grodzovsky
532cd2454d6SNirmoy Das /**
533cd2454d6SNirmoy Das * amdgpu_bo_create - create an &amdgpu_bo buffer object
534cd2454d6SNirmoy Das * @adev: amdgpu device object
535cd2454d6SNirmoy Das * @bp: parameters to be used for the buffer object
536cd2454d6SNirmoy Das * @bo_ptr: pointer to the buffer object pointer
537cd2454d6SNirmoy Das *
538cd2454d6SNirmoy Das * Creates an &amdgpu_bo buffer object.
539cd2454d6SNirmoy Das *
540cd2454d6SNirmoy Das * Returns:
541cd2454d6SNirmoy Das * 0 for success or a negative error code on failure.
542cd2454d6SNirmoy Das */
amdgpu_bo_create(struct amdgpu_device * adev,struct amdgpu_bo_param * bp,struct amdgpu_bo ** bo_ptr)543cd2454d6SNirmoy Das int amdgpu_bo_create(struct amdgpu_device *adev,
544a906dbb1SChunming Zhou struct amdgpu_bo_param *bp,
5457e5a547fSChunming Zhou struct amdgpu_bo **bo_ptr)
546d38ceaf9SAlex Deucher {
5479251859aSRoger He struct ttm_operation_ctx ctx = {
548a906dbb1SChunming Zhou .interruptible = (bp->type != ttm_bo_type_kernel),
549061468c4SChristian König .no_wait_gpu = bp->no_wait_gpu,
550586052b0SChristian König /* We opt to avoid OOM on system pages allocations */
551586052b0SChristian König .gfp_retry_mayfail = true,
552c44dfe4dSChristian König .allow_res_evict = bp->type != ttm_bo_type_kernel,
553c44dfe4dSChristian König .resv = bp->resv
5549251859aSRoger He };
555d38ceaf9SAlex Deucher struct amdgpu_bo *bo;
556a906dbb1SChunming Zhou unsigned long page_align, size = bp->size;
557d38ceaf9SAlex Deucher int r;
558d38ceaf9SAlex Deucher
559fe57085aSMarek Olšák /* Note that GDS/GWS/OA allocates 1 page per byte/resource. */
560fe57085aSMarek Olšák if (bp->domain & (AMDGPU_GEM_DOMAIN_GWS | AMDGPU_GEM_DOMAIN_OA)) {
561fe57085aSMarek Olšák /* GWS and OA don't need any alignment. */
562fe57085aSMarek Olšák page_align = bp->byte_align;
56377a2faa5SChristian König size <<= PAGE_SHIFT;
564e3c92eb4SSomalapuram Amaranath
565fe57085aSMarek Olšák } else if (bp->domain & AMDGPU_GEM_DOMAIN_GDS) {
566fe57085aSMarek Olšák /* Both size and alignment must be a multiple of 4. */
567fe57085aSMarek Olšák page_align = ALIGN(bp->byte_align, 4);
568fe57085aSMarek Olšák size = ALIGN(size, 4) << PAGE_SHIFT;
569fe57085aSMarek Olšák } else {
570fe57085aSMarek Olšák /* Memory should be aligned at least to a page size. */
571fe57085aSMarek Olšák page_align = ALIGN(bp->byte_align, PAGE_SIZE) >> PAGE_SHIFT;
572d38ceaf9SAlex Deucher size = ALIGN(size, PAGE_SIZE);
573fe57085aSMarek Olšák }
574d38ceaf9SAlex Deucher
575a906dbb1SChunming Zhou if (!amdgpu_bo_validate_size(adev, size, bp->domain))
57679c63123SAndrey Grodzovsky return -ENOMEM;
57779c63123SAndrey Grodzovsky
5789fd5543eSNirmoy Das BUG_ON(bp->bo_ptr_size < sizeof(struct amdgpu_bo));
579d38ceaf9SAlex Deucher
5809fd5543eSNirmoy Das *bo_ptr = NULL;
58131c759bbSChangfeng bo = kvzalloc(bp->bo_ptr_size, GFP_KERNEL);
582d38ceaf9SAlex Deucher if (bo == NULL)
583d38ceaf9SAlex Deucher return -ENOMEM;
5844a580877SLuben Tuikov drm_gem_private_object_init(adev_to_drm(adev), &bo->tbo.base, size);
585646b9025SChristian König bo->vm_bo = NULL;
5863f188453SChunming Zhou bo->preferred_domains = bp->preferred_domain ? bp->preferred_domain :
587aa2b2e28SChunming Zhou bp->domain;
58808082104SChristian König bo->allowed_domains = bo->preferred_domains;
589a906dbb1SChunming Zhou if (bp->type != ttm_bo_type_kernel &&
590fab2cc83SChristian König !(bp->flags & AMDGPU_GEM_CREATE_DISCARDABLE) &&
59108082104SChristian König bo->allowed_domains == AMDGPU_GEM_DOMAIN_VRAM)
59208082104SChristian König bo->allowed_domains |= AMDGPU_GEM_DOMAIN_GTT;
593d38ceaf9SAlex Deucher
594a906dbb1SChunming Zhou bo->flags = bp->flags;
595a187f17fSOded Gabbay
5963ebfd221SPhilip Yang if (adev->gmc.mem_partitions)
5973ebfd221SPhilip Yang /* For GPUs with spatial partitioning, bo->xcp_id=-1 means any partition */
5983ebfd221SPhilip Yang bo->xcp_id = bp->xcp_id_plus1 - 1;
5993ebfd221SPhilip Yang else
6003ebfd221SPhilip Yang /* For GPUs without spatial partitioning */
6013ebfd221SPhilip Yang bo->xcp_id = 0;
602f24e924bSPhilip Yang
6033d1b8ec7SAndrey Grodzovsky if (!amdgpu_bo_support_uswc(bo->flags))
604a2e2f299SNils Holland bo->flags &= ~AMDGPU_GEM_CREATE_CPU_GTT_USWC;
605a187f17fSOded Gabbay
606fc6ea4beSFelix Kuehling if (adev->ras_enabled)
607fc6ea4beSFelix Kuehling bo->flags |= AMDGPU_GEM_CREATE_VRAM_WIPE_ON_RELEASE;
608fc6ea4beSFelix Kuehling
609c09312a6SChristian König bo->tbo.bdev = &adev->mman.bdev;
61047722220SChristian König if (bp->domain & (AMDGPU_GEM_DOMAIN_GWS | AMDGPU_GEM_DOMAIN_OA |
61147722220SChristian König AMDGPU_GEM_DOMAIN_GDS))
61247722220SChristian König amdgpu_bo_placement_from_domain(bo, AMDGPU_GEM_DOMAIN_CPU);
61347722220SChristian König else
614c704ab18SChristian König amdgpu_bo_placement_from_domain(bo, bp->domain);
615a50cb948SJunwei Zhang if (bp->type == ttm_bo_type_kernel)
616*04cf241fSFelix Kuehling bo->tbo.priority = 2;
617*04cf241fSFelix Kuehling else if (!(bp->flags & AMDGPU_GEM_CREATE_DISCARDABLE))
618a50cb948SJunwei Zhang bo->tbo.priority = 1;
61908082104SChristian König
62023e24fbbSNirmoy Das if (!bp->destroy)
62123e24fbbSNirmoy Das bp->destroy = &amdgpu_bo_destroy;
62223e24fbbSNirmoy Das
623347987a2SChristian König r = ttm_bo_init_reserved(&adev->mman.bdev, &bo->tbo, bp->type,
624f07069daSChristian König &bo->placement, page_align, &ctx, NULL,
62523e24fbbSNirmoy Das bp->resv, bp->destroy);
62608082104SChristian König if (unlikely(r != 0))
627a695e437SChristian König return r;
628a695e437SChristian König
629c8c5e569SAndrey Grodzovsky if (!amdgpu_gmc_vram_full_visible(&adev->gmc) &&
6304c5eaf0cSChristian König amdgpu_res_cpu_visible(adev, bo->tbo.resource))
6316af046d2SChristian König amdgpu_cs_report_moved_bytes(adev, ctx.bytes_moved,
6326af046d2SChristian König ctx.bytes_moved);
63300f06b24SJohn Brooks else
6346af046d2SChristian König amdgpu_cs_report_moved_bytes(adev, ctx.bytes_moved, 0);
635fad06127SSamuel Pitoiset
636a906dbb1SChunming Zhou if (bp->flags & AMDGPU_GEM_CREATE_VRAM_CLEARED &&
637d3116756SChristian König bo->tbo.resource->mem_type == TTM_PL_VRAM) {
638f54d1867SChris Wilson struct dma_fence *fence;
6394fea83ffSFlora Cui
640c3aaca43SMukul Joshi r = amdgpu_fill_buffer(bo, 0, bo->tbo.base.resv, &fence, true);
641c3af1258SChristian König if (unlikely(r))
642c3af1258SChristian König goto fail_unreserve;
643c3af1258SChristian König
6448bb31587SChristian König dma_resv_add_fence(bo->tbo.base.resv, fence,
6458bb31587SChristian König DMA_RESV_USAGE_KERNEL);
646f54d1867SChris Wilson dma_fence_put(fence);
6474fea83ffSFlora Cui }
648a906dbb1SChunming Zhou if (!bp->resv)
64959c66c91SNicolai Hähnle amdgpu_bo_unreserve(bo);
650d38ceaf9SAlex Deucher *bo_ptr = bo;
651d38ceaf9SAlex Deucher
652d38ceaf9SAlex Deucher trace_amdgpu_bo_create(bo);
653d38ceaf9SAlex Deucher
65496cf8271SJohn Brooks /* Treat CPU_ACCESS_REQUIRED only as a hint if given by UMD */
655a906dbb1SChunming Zhou if (bp->type == ttm_bo_type_device)
65696cf8271SJohn Brooks bo->flags &= ~AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED;
65796cf8271SJohn Brooks
658d38ceaf9SAlex Deucher return 0;
6594fea83ffSFlora Cui
6604fea83ffSFlora Cui fail_unreserve:
661a906dbb1SChunming Zhou if (!bp->resv)
66252791eeeSChristian König dma_resv_unlock(bo->tbo.base.resv);
6634fea83ffSFlora Cui amdgpu_bo_unref(&bo);
6644fea83ffSFlora Cui return r;
665d38ceaf9SAlex Deucher }
666d38ceaf9SAlex Deucher
6676f4e8d6eSSamuel Li /**
6689ad0d033SNirmoy Das * amdgpu_bo_create_user - create an &amdgpu_bo_user buffer object
6699ad0d033SNirmoy Das * @adev: amdgpu device object
6709ad0d033SNirmoy Das * @bp: parameters to be used for the buffer object
6719ad0d033SNirmoy Das * @ubo_ptr: pointer to the buffer object pointer
6729ad0d033SNirmoy Das *
6739ad0d033SNirmoy Das * Create a BO to be used by user application;
6749ad0d033SNirmoy Das *
6759ad0d033SNirmoy Das * Returns:
6769ad0d033SNirmoy Das * 0 for success or a negative error code on failure.
6779ad0d033SNirmoy Das */
6789ad0d033SNirmoy Das
amdgpu_bo_create_user(struct amdgpu_device * adev,struct amdgpu_bo_param * bp,struct amdgpu_bo_user ** ubo_ptr)6799ad0d033SNirmoy Das int amdgpu_bo_create_user(struct amdgpu_device *adev,
6809ad0d033SNirmoy Das struct amdgpu_bo_param *bp,
6819ad0d033SNirmoy Das struct amdgpu_bo_user **ubo_ptr)
6829ad0d033SNirmoy Das {
6839ad0d033SNirmoy Das struct amdgpu_bo *bo_ptr;
6849ad0d033SNirmoy Das int r;
6859ad0d033SNirmoy Das
6869ad0d033SNirmoy Das bp->bo_ptr_size = sizeof(struct amdgpu_bo_user);
68723e24fbbSNirmoy Das bp->destroy = &amdgpu_bo_user_destroy;
688cd2454d6SNirmoy Das r = amdgpu_bo_create(adev, bp, &bo_ptr);
6899ad0d033SNirmoy Das if (r)
6909ad0d033SNirmoy Das return r;
6919ad0d033SNirmoy Das
6929ad0d033SNirmoy Das *ubo_ptr = to_amdgpu_bo_user(bo_ptr);
6939ad0d033SNirmoy Das return r;
6949ad0d033SNirmoy Das }
6956fdd6f4aSNirmoy Das
6966fdd6f4aSNirmoy Das /**
6976fdd6f4aSNirmoy Das * amdgpu_bo_create_vm - create an &amdgpu_bo_vm buffer object
6986fdd6f4aSNirmoy Das * @adev: amdgpu device object
6996fdd6f4aSNirmoy Das * @bp: parameters to be used for the buffer object
7006fdd6f4aSNirmoy Das * @vmbo_ptr: pointer to the buffer object pointer
7016fdd6f4aSNirmoy Das *
7026fdd6f4aSNirmoy Das * Create a BO to be for GPUVM.
7036fdd6f4aSNirmoy Das *
7046fdd6f4aSNirmoy Das * Returns:
7056fdd6f4aSNirmoy Das * 0 for success or a negative error code on failure.
7066fdd6f4aSNirmoy Das */
7076fdd6f4aSNirmoy Das
amdgpu_bo_create_vm(struct amdgpu_device * adev,struct amdgpu_bo_param * bp,struct amdgpu_bo_vm ** vmbo_ptr)7086fdd6f4aSNirmoy Das int amdgpu_bo_create_vm(struct amdgpu_device *adev,
7096fdd6f4aSNirmoy Das struct amdgpu_bo_param *bp,
7106fdd6f4aSNirmoy Das struct amdgpu_bo_vm **vmbo_ptr)
7116fdd6f4aSNirmoy Das {
7126fdd6f4aSNirmoy Das struct amdgpu_bo *bo_ptr;
7136fdd6f4aSNirmoy Das int r;
7146fdd6f4aSNirmoy Das
7156fdd6f4aSNirmoy Das /* bo_ptr_size will be determined by the caller and it depends on
7166fdd6f4aSNirmoy Das * num of amdgpu_vm_pt entries.
7176fdd6f4aSNirmoy Das */
7186fdd6f4aSNirmoy Das BUG_ON(bp->bo_ptr_size < sizeof(struct amdgpu_bo_vm));
7196fdd6f4aSNirmoy Das r = amdgpu_bo_create(adev, bp, &bo_ptr);
7206fdd6f4aSNirmoy Das if (r)
7216fdd6f4aSNirmoy Das return r;
7226fdd6f4aSNirmoy Das
7236fdd6f4aSNirmoy Das *vmbo_ptr = to_amdgpu_bo_vm(bo_ptr);
7246fdd6f4aSNirmoy Das return r;
7256fdd6f4aSNirmoy Das }
7266fdd6f4aSNirmoy Das
7279ad0d033SNirmoy Das /**
7281fdc79f6SNirmoy Das * amdgpu_bo_add_to_shadow_list - add a BO to the shadow list
7291fdc79f6SNirmoy Das *
730d8c33180SAnson Jacob * @vmbo: BO that will be inserted into the shadow list
7311fdc79f6SNirmoy Das *
7321fdc79f6SNirmoy Das * Insert a BO to the shadow list.
7331fdc79f6SNirmoy Das */
amdgpu_bo_add_to_shadow_list(struct amdgpu_bo_vm * vmbo)734e18aaea7SNirmoy Das void amdgpu_bo_add_to_shadow_list(struct amdgpu_bo_vm *vmbo)
7351fdc79f6SNirmoy Das {
736e18aaea7SNirmoy Das struct amdgpu_device *adev = amdgpu_ttm_adev(vmbo->bo.tbo.bdev);
7371fdc79f6SNirmoy Das
7381fdc79f6SNirmoy Das mutex_lock(&adev->shadow_list_lock);
739e18aaea7SNirmoy Das list_add_tail(&vmbo->shadow_list, &adev->shadow_list);
740cbb63eccSHoratio Zhang vmbo->shadow->parent = amdgpu_bo_ref(&vmbo->bo);
741cbb63eccSHoratio Zhang vmbo->shadow->tbo.destroy = &amdgpu_bo_vm_destroy;
7421fdc79f6SNirmoy Das mutex_unlock(&adev->shadow_list_lock);
7431fdc79f6SNirmoy Das }
7441fdc79f6SNirmoy Das
7451fdc79f6SNirmoy Das /**
746403009bfSChristian König * amdgpu_bo_restore_shadow - restore an &amdgpu_bo shadow
747403009bfSChristian König *
748403009bfSChristian König * @shadow: &amdgpu_bo shadow to be restored
7496f4e8d6eSSamuel Li * @fence: dma_fence associated with the operation
7506f4e8d6eSSamuel Li *
7516f4e8d6eSSamuel Li * Copies a buffer object's shadow content back to the object.
7526f4e8d6eSSamuel Li * This is used for recovering a buffer from its shadow in case of a gpu
7536f4e8d6eSSamuel Li * reset where vram context may be lost.
7546f4e8d6eSSamuel Li *
7552472e11bSMichel Dänzer * Returns:
7562472e11bSMichel Dänzer * 0 for success or a negative error code on failure.
7576f4e8d6eSSamuel Li */
amdgpu_bo_restore_shadow(struct amdgpu_bo * shadow,struct dma_fence ** fence)758403009bfSChristian König int amdgpu_bo_restore_shadow(struct amdgpu_bo *shadow, struct dma_fence **fence)
75920f4eff1SChunming Zhou
76020f4eff1SChunming Zhou {
761403009bfSChristian König struct amdgpu_device *adev = amdgpu_ttm_adev(shadow->tbo.bdev);
762403009bfSChristian König struct amdgpu_ring *ring = adev->mman.buffer_funcs_ring;
763403009bfSChristian König uint64_t shadow_addr, parent_addr;
76420f4eff1SChunming Zhou
765403009bfSChristian König shadow_addr = amdgpu_bo_gpu_offset(shadow);
766403009bfSChristian König parent_addr = amdgpu_bo_gpu_offset(shadow->parent);
76720f4eff1SChunming Zhou
768403009bfSChristian König return amdgpu_copy_buffer(ring, shadow_addr, parent_addr,
769403009bfSChristian König amdgpu_bo_size(shadow), NULL, fence,
770c9dc9cfeSAaron Liu true, false, false);
77120f4eff1SChunming Zhou }
77220f4eff1SChunming Zhou
7736f4e8d6eSSamuel Li /**
7746f4e8d6eSSamuel Li * amdgpu_bo_kmap - map an &amdgpu_bo buffer object
7756f4e8d6eSSamuel Li * @bo: &amdgpu_bo buffer object to be mapped
7766f4e8d6eSSamuel Li * @ptr: kernel virtual address to be returned
7776f4e8d6eSSamuel Li *
7786f4e8d6eSSamuel Li * Calls ttm_bo_kmap() to set up the kernel virtual mapping; calls
7796f4e8d6eSSamuel Li * amdgpu_bo_kptr() to get the kernel virtual address.
7806f4e8d6eSSamuel Li *
7812472e11bSMichel Dänzer * Returns:
7822472e11bSMichel Dänzer * 0 for success or a negative error code on failure.
7836f4e8d6eSSamuel Li */
amdgpu_bo_kmap(struct amdgpu_bo * bo,void ** ptr)784d38ceaf9SAlex Deucher int amdgpu_bo_kmap(struct amdgpu_bo *bo, void **ptr)
785d38ceaf9SAlex Deucher {
786f5e1c740SChristian König void *kptr;
787587f3c70SChristian König long r;
788d38ceaf9SAlex Deucher
789271c8125SChristian König if (bo->flags & AMDGPU_GEM_CREATE_NO_CPU_ACCESS)
790271c8125SChristian König return -EPERM;
791271c8125SChristian König
792c35fcfa3SChristian König r = dma_resv_wait_timeout(bo->tbo.base.resv, DMA_RESV_USAGE_KERNEL,
793c35fcfa3SChristian König false, MAX_SCHEDULE_TIMEOUT);
794c35fcfa3SChristian König if (r < 0)
795c35fcfa3SChristian König return r;
796c35fcfa3SChristian König
797f5e1c740SChristian König kptr = amdgpu_bo_kptr(bo);
798f5e1c740SChristian König if (kptr) {
799f5e1c740SChristian König if (ptr)
800f5e1c740SChristian König *ptr = kptr;
801d38ceaf9SAlex Deucher return 0;
802d38ceaf9SAlex Deucher }
803587f3c70SChristian König
804e3c92eb4SSomalapuram Amaranath r = ttm_bo_kmap(&bo->tbo, 0, PFN_UP(bo->tbo.base.size), &bo->kmap);
805587f3c70SChristian König if (r)
806587f3c70SChristian König return r;
807587f3c70SChristian König
808587f3c70SChristian König if (ptr)
809f5e1c740SChristian König *ptr = amdgpu_bo_kptr(bo);
810587f3c70SChristian König
811d38ceaf9SAlex Deucher return 0;
812d38ceaf9SAlex Deucher }
813d38ceaf9SAlex Deucher
8146f4e8d6eSSamuel Li /**
8156f4e8d6eSSamuel Li * amdgpu_bo_kptr - returns a kernel virtual address of the buffer object
8166f4e8d6eSSamuel Li * @bo: &amdgpu_bo buffer object
8176f4e8d6eSSamuel Li *
8186f4e8d6eSSamuel Li * Calls ttm_kmap_obj_virtual() to get the kernel virtual address
8196f4e8d6eSSamuel Li *
8202472e11bSMichel Dänzer * Returns:
8212472e11bSMichel Dänzer * the virtual address of a buffer object area.
8226f4e8d6eSSamuel Li */
amdgpu_bo_kptr(struct amdgpu_bo * bo)823f5e1c740SChristian König void *amdgpu_bo_kptr(struct amdgpu_bo *bo)
824f5e1c740SChristian König {
825f5e1c740SChristian König bool is_iomem;
826f5e1c740SChristian König
827f5e1c740SChristian König return ttm_kmap_obj_virtual(&bo->kmap, &is_iomem);
828f5e1c740SChristian König }
829f5e1c740SChristian König
8306f4e8d6eSSamuel Li /**
8316f4e8d6eSSamuel Li * amdgpu_bo_kunmap - unmap an &amdgpu_bo buffer object
8326f4e8d6eSSamuel Li * @bo: &amdgpu_bo buffer object to be unmapped
8336f4e8d6eSSamuel Li *
8346f4e8d6eSSamuel Li * Unmaps a kernel map set up by amdgpu_bo_kmap().
8356f4e8d6eSSamuel Li */
amdgpu_bo_kunmap(struct amdgpu_bo * bo)836d38ceaf9SAlex Deucher void amdgpu_bo_kunmap(struct amdgpu_bo *bo)
837d38ceaf9SAlex Deucher {
838f5e1c740SChristian König if (bo->kmap.bo)
839d38ceaf9SAlex Deucher ttm_bo_kunmap(&bo->kmap);
840d38ceaf9SAlex Deucher }
841d38ceaf9SAlex Deucher
8426f4e8d6eSSamuel Li /**
8436f4e8d6eSSamuel Li * amdgpu_bo_ref - reference an &amdgpu_bo buffer object
8446f4e8d6eSSamuel Li * @bo: &amdgpu_bo buffer object
8456f4e8d6eSSamuel Li *
8466f4e8d6eSSamuel Li * References the contained &ttm_buffer_object.
8476f4e8d6eSSamuel Li *
8482472e11bSMichel Dänzer * Returns:
8492472e11bSMichel Dänzer * a refcounted pointer to the &amdgpu_bo buffer object.
8506f4e8d6eSSamuel Li */
amdgpu_bo_ref(struct amdgpu_bo * bo)851d38ceaf9SAlex Deucher struct amdgpu_bo *amdgpu_bo_ref(struct amdgpu_bo *bo)
852d38ceaf9SAlex Deucher {
853d38ceaf9SAlex Deucher if (bo == NULL)
854d38ceaf9SAlex Deucher return NULL;
855d38ceaf9SAlex Deucher
85671d5ef11SThomas Zimmermann ttm_bo_get(&bo->tbo);
857d38ceaf9SAlex Deucher return bo;
858d38ceaf9SAlex Deucher }
859d38ceaf9SAlex Deucher
8606f4e8d6eSSamuel Li /**
8616f4e8d6eSSamuel Li * amdgpu_bo_unref - unreference an &amdgpu_bo buffer object
8626f4e8d6eSSamuel Li * @bo: &amdgpu_bo buffer object
8636f4e8d6eSSamuel Li *
8646f4e8d6eSSamuel Li * Unreferences the contained &ttm_buffer_object and clear the pointer
8656f4e8d6eSSamuel Li */
amdgpu_bo_unref(struct amdgpu_bo ** bo)866d38ceaf9SAlex Deucher void amdgpu_bo_unref(struct amdgpu_bo **bo)
867d38ceaf9SAlex Deucher {
868d38ceaf9SAlex Deucher struct ttm_buffer_object *tbo;
869d38ceaf9SAlex Deucher
870d38ceaf9SAlex Deucher if ((*bo) == NULL)
871d38ceaf9SAlex Deucher return;
872d38ceaf9SAlex Deucher
873d38ceaf9SAlex Deucher tbo = &((*bo)->tbo);
874fea872b2SThomas Zimmermann ttm_bo_put(tbo);
875d38ceaf9SAlex Deucher *bo = NULL;
876d38ceaf9SAlex Deucher }
877d38ceaf9SAlex Deucher
8786f4e8d6eSSamuel Li /**
8796f4e8d6eSSamuel Li * amdgpu_bo_pin_restricted - pin an &amdgpu_bo buffer object
8806f4e8d6eSSamuel Li * @bo: &amdgpu_bo buffer object to be pinned
8816f4e8d6eSSamuel Li * @domain: domain to be pinned to
8826f4e8d6eSSamuel Li * @min_offset: the start of requested address range
8836f4e8d6eSSamuel Li * @max_offset: the end of requested address range
8846f4e8d6eSSamuel Li *
8856f4e8d6eSSamuel Li * Pins the buffer object according to requested domain and address range. If
8866f4e8d6eSSamuel Li * the memory is unbound gart memory, binds the pages into gart table. Adjusts
8876f4e8d6eSSamuel Li * pin_count and pin_size accordingly.
8886f4e8d6eSSamuel Li *
8896f4e8d6eSSamuel Li * Pinning means to lock pages in memory along with keeping them at a fixed
8906f4e8d6eSSamuel Li * offset. It is required when a buffer can not be moved, for example, when
8916f4e8d6eSSamuel Li * a display buffer is being scanned out.
8926f4e8d6eSSamuel Li *
8936f4e8d6eSSamuel Li * Compared with amdgpu_bo_pin(), this function gives more flexibility on
8946f4e8d6eSSamuel Li * where to pin a buffer if there are specific restrictions on where a buffer
8956f4e8d6eSSamuel Li * must be located.
8966f4e8d6eSSamuel Li *
8972472e11bSMichel Dänzer * Returns:
8982472e11bSMichel Dänzer * 0 for success or a negative error code on failure.
8996f4e8d6eSSamuel Li */
amdgpu_bo_pin_restricted(struct amdgpu_bo * bo,u32 domain,u64 min_offset,u64 max_offset)9007e5a547fSChunming Zhou int amdgpu_bo_pin_restricted(struct amdgpu_bo *bo, u32 domain,
9017b7c6c81SJunwei Zhang u64 min_offset, u64 max_offset)
902d38ceaf9SAlex Deucher {
903a7d64de6SChristian König struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev);
90419be5570SChristian König struct ttm_operation_ctx ctx = { false, false };
905d38ceaf9SAlex Deucher int r, i;
906d38ceaf9SAlex Deucher
907cc325d19SChristian König if (amdgpu_ttm_tt_get_usermm(bo->tbo.ttm))
908d38ceaf9SAlex Deucher return -EPERM;
909d38ceaf9SAlex Deucher
9107e5a547fSChunming Zhou if (WARN_ON_ONCE(min_offset > max_offset))
9117e5a547fSChunming Zhou return -EINVAL;
9127e5a547fSChunming Zhou
913f5ba1404SLeo Li /* Check domain to be pinned to against preferred domains */
914f5ba1404SLeo Li if (bo->preferred_domains & domain)
915f5ba1404SLeo Li domain = bo->preferred_domains & domain;
916f5ba1404SLeo Li
917803d89adSChristopher James Halse Rogers /* A shared bo cannot be migrated to VRAM */
9188c505bdcSChristian König if (bo->tbo.base.import_attach) {
9199b3f217fSSamuel Li if (domain & AMDGPU_GEM_DOMAIN_GTT)
9209b3f217fSSamuel Li domain = AMDGPU_GEM_DOMAIN_GTT;
9219b3f217fSSamuel Li else
922803d89adSChristopher James Halse Rogers return -EINVAL;
9239b3f217fSSamuel Li }
924803d89adSChristopher James Halse Rogers
9254671078eSChristian König if (bo->tbo.pin_count) {
926d3116756SChristian König uint32_t mem_type = bo->tbo.resource->mem_type;
927d3116756SChristian König uint32_t mem_flags = bo->tbo.resource->placement;
928408778e8SFlora Cui
929f5318959SChristian König if (!(domain & amdgpu_mem_type_to_domain(mem_type)))
930408778e8SFlora Cui return -EINVAL;
931408778e8SFlora Cui
932e1a4b67aSxinhui pan if ((mem_type == TTM_PL_VRAM) &&
933e1a4b67aSxinhui pan (bo->flags & AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS) &&
934eda1068dSFelix Kuehling !(mem_flags & TTM_PL_FLAG_CONTIGUOUS))
935eda1068dSFelix Kuehling return -EINVAL;
936eda1068dSFelix Kuehling
9374671078eSChristian König ttm_bo_pin(&bo->tbo);
938d38ceaf9SAlex Deucher
939d38ceaf9SAlex Deucher if (max_offset != 0) {
940b1a8ef95SNirmoy Das u64 domain_start = amdgpu_ttm_domain_start(adev,
941b1a8ef95SNirmoy Das mem_type);
942d38ceaf9SAlex Deucher WARN_ON_ONCE(max_offset <
943d38ceaf9SAlex Deucher (amdgpu_bo_gpu_offset(bo) - domain_start));
944d38ceaf9SAlex Deucher }
945d38ceaf9SAlex Deucher
946d38ceaf9SAlex Deucher return 0;
947d38ceaf9SAlex Deucher }
94803f48dd5SChristian König
9499deb0b3dSChristian König /* This assumes only APU display buffers are pinned with (VRAM|GTT).
9509deb0b3dSChristian König * See function amdgpu_display_supported_domains()
9519deb0b3dSChristian König */
952d035f84dSYifan Zhang domain = amdgpu_bo_get_preferred_domain(adev, domain);
9539deb0b3dSChristian König
954a448cb00SChristian König if (bo->tbo.base.import_attach)
955a448cb00SChristian König dma_buf_pin(bo->tbo.base.import_attach);
956a448cb00SChristian König
957e9c7577cSChristian König /* force to pin into visible video ram */
958e9c7577cSChristian König if (!(bo->flags & AMDGPU_GEM_CREATE_NO_CPU_ACCESS))
959e9c7577cSChristian König bo->flags |= AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED;
960c704ab18SChristian König amdgpu_bo_placement_from_domain(bo, domain);
961d38ceaf9SAlex Deucher for (i = 0; i < bo->placement.num_placement; i++) {
9621d6ecab1SSrinivasan Shanmugam unsigned int fpfn, lpfn;
963e9c7577cSChristian König
9647e5a547fSChunming Zhou fpfn = min_offset >> PAGE_SHIFT;
9657e5a547fSChunming Zhou lpfn = max_offset >> PAGE_SHIFT;
966e9c7577cSChristian König
9677e5a547fSChunming Zhou if (fpfn > bo->placements[i].fpfn)
9687e5a547fSChunming Zhou bo->placements[i].fpfn = fpfn;
96978d0e182SChristian König if (!bo->placements[i].lpfn ||
97078d0e182SChristian König (lpfn && lpfn < bo->placements[i].lpfn))
9717e5a547fSChunming Zhou bo->placements[i].lpfn = lpfn;
972d38ceaf9SAlex Deucher }
973d38ceaf9SAlex Deucher
97419be5570SChristian König r = ttm_bo_validate(&bo->tbo, &bo->placement, &ctx);
9756681c5ebSChristian König if (unlikely(r)) {
976a7d64de6SChristian König dev_err(adev->dev, "%p pin failed\n", bo);
9776681c5ebSChristian König goto error;
9786681c5ebSChristian König }
97907306b4fSChunming Zhou
9804671078eSChristian König ttm_bo_pin(&bo->tbo);
9815e91fb57SChristian König
982d3116756SChristian König domain = amdgpu_mem_type_to_domain(bo->tbo.resource->mem_type);
983e131b914SChunming Zhou if (domain == AMDGPU_GEM_DOMAIN_VRAM) {
984a5ccfe5cSMichel Dänzer atomic64_add(amdgpu_bo_size(bo), &adev->vram_pin_size);
985a5ccfe5cSMichel Dänzer atomic64_add(amdgpu_vram_mgr_bo_visible_size(bo),
986a5ccfe5cSMichel Dänzer &adev->visible_pin_size);
98732ab75f0SFlora Cui } else if (domain == AMDGPU_GEM_DOMAIN_GTT) {
988a5ccfe5cSMichel Dänzer atomic64_add(amdgpu_bo_size(bo), &adev->gart_pin_size);
989d38ceaf9SAlex Deucher }
9906681c5ebSChristian König
9916681c5ebSChristian König error:
992d38ceaf9SAlex Deucher return r;
993d38ceaf9SAlex Deucher }
994d38ceaf9SAlex Deucher
9956f4e8d6eSSamuel Li /**
9966f4e8d6eSSamuel Li * amdgpu_bo_pin - pin an &amdgpu_bo buffer object
9976f4e8d6eSSamuel Li * @bo: &amdgpu_bo buffer object to be pinned
9986f4e8d6eSSamuel Li * @domain: domain to be pinned to
9996f4e8d6eSSamuel Li *
10006f4e8d6eSSamuel Li * A simple wrapper to amdgpu_bo_pin_restricted().
10016f4e8d6eSSamuel Li * Provides a simpler API for buffers that do not have any strict restrictions
10026f4e8d6eSSamuel Li * on where a buffer must be located.
10036f4e8d6eSSamuel Li *
10042472e11bSMichel Dänzer * Returns:
10052472e11bSMichel Dänzer * 0 for success or a negative error code on failure.
10066f4e8d6eSSamuel Li */
amdgpu_bo_pin(struct amdgpu_bo * bo,u32 domain)10077b7c6c81SJunwei Zhang int amdgpu_bo_pin(struct amdgpu_bo *bo, u32 domain)
1008d38ceaf9SAlex Deucher {
1009eda1068dSFelix Kuehling bo->flags |= AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS;
10107b7c6c81SJunwei Zhang return amdgpu_bo_pin_restricted(bo, domain, 0, 0);
1011d38ceaf9SAlex Deucher }
1012d38ceaf9SAlex Deucher
10136f4e8d6eSSamuel Li /**
10146f4e8d6eSSamuel Li * amdgpu_bo_unpin - unpin an &amdgpu_bo buffer object
10156f4e8d6eSSamuel Li * @bo: &amdgpu_bo buffer object to be unpinned
10166f4e8d6eSSamuel Li *
10176f4e8d6eSSamuel Li * Decreases the pin_count, and clears the flags if pin_count reaches 0.
10186f4e8d6eSSamuel Li * Changes placement and pin size accordingly.
10196f4e8d6eSSamuel Li *
10202472e11bSMichel Dänzer * Returns:
10212472e11bSMichel Dänzer * 0 for success or a negative error code on failure.
10226f4e8d6eSSamuel Li */
amdgpu_bo_unpin(struct amdgpu_bo * bo)10234671078eSChristian König void amdgpu_bo_unpin(struct amdgpu_bo *bo)
1024d38ceaf9SAlex Deucher {
1025e2ac8531SChristian König struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev);
1026e2ac8531SChristian König
10274671078eSChristian König ttm_bo_unpin(&bo->tbo);
10284671078eSChristian König if (bo->tbo.pin_count)
10294671078eSChristian König return;
10306681c5ebSChristian König
1031a448cb00SChristian König if (bo->tbo.base.import_attach)
1032a448cb00SChristian König dma_buf_unpin(bo->tbo.base.import_attach);
1033e2ac8531SChristian König
1034d3116756SChristian König if (bo->tbo.resource->mem_type == TTM_PL_VRAM) {
1035e2ac8531SChristian König atomic64_sub(amdgpu_bo_size(bo), &adev->vram_pin_size);
1036e2ac8531SChristian König atomic64_sub(amdgpu_vram_mgr_bo_visible_size(bo),
1037e2ac8531SChristian König &adev->visible_pin_size);
1038d3116756SChristian König } else if (bo->tbo.resource->mem_type == TTM_PL_TT) {
1039e2ac8531SChristian König atomic64_sub(amdgpu_bo_size(bo), &adev->gart_pin_size);
1040e2ac8531SChristian König }
1041dc3499c7SAlex Deucher
1042d38ceaf9SAlex Deucher }
1043d38ceaf9SAlex Deucher
10441d6ecab1SSrinivasan Shanmugam static const char * const amdgpu_vram_names[] = {
10451f8628c7SAlex Deucher "UNKNOWN",
10461f8628c7SAlex Deucher "GDDR1",
10471f8628c7SAlex Deucher "DDR2",
10481f8628c7SAlex Deucher "GDDR3",
10491f8628c7SAlex Deucher "GDDR4",
10501f8628c7SAlex Deucher "GDDR5",
10511f8628c7SAlex Deucher "HBM",
1052bc227cfaSTom St Denis "DDR3",
1053bc227cfaSTom St Denis "DDR4",
10545228fe30SHawking Zhang "GDDR6",
1055d534ca71SAlex Deucher "DDR5",
1056d534ca71SAlex Deucher "LPDDR4",
1057d534ca71SAlex Deucher "LPDDR5"
10581f8628c7SAlex Deucher };
10591f8628c7SAlex Deucher
10606f4e8d6eSSamuel Li /**
10616f4e8d6eSSamuel Li * amdgpu_bo_init - initialize memory manager
10626f4e8d6eSSamuel Li * @adev: amdgpu device object
10636f4e8d6eSSamuel Li *
10646f4e8d6eSSamuel Li * Calls amdgpu_ttm_init() to initialize amdgpu memory manager.
10656f4e8d6eSSamuel Li *
10662472e11bSMichel Dänzer * Returns:
10672472e11bSMichel Dänzer * 0 for success or a negative error code on failure.
10686f4e8d6eSSamuel Li */
amdgpu_bo_init(struct amdgpu_device * adev)1069d38ceaf9SAlex Deucher int amdgpu_bo_init(struct amdgpu_device *adev)
1070d38ceaf9SAlex Deucher {
107135d5f224SOak Zeng /* On A+A platform, VRAM can be mapped as WB */
1072228ce176SRajneesh Bhardwaj if (!adev->gmc.xgmi.connected_to_cpu && !adev->gmc.is_app_apu) {
10737cf321d1SDave Airlie /* reserve PAT memory space to WC for VRAM */
107426db557eSNirmoy Das int r = arch_io_reserve_memtype_wc(adev->gmc.aper_base,
1075770d13b1SChristian König adev->gmc.aper_size);
10767cf321d1SDave Airlie
107726db557eSNirmoy Das if (r) {
107826db557eSNirmoy Das DRM_ERROR("Unable to set WC memtype for the aperture base\n");
107926db557eSNirmoy Das return r;
108026db557eSNirmoy Das }
108126db557eSNirmoy Das
1082d38ceaf9SAlex Deucher /* Add an MTRR for the VRAM */
1083770d13b1SChristian König adev->gmc.vram_mtrr = arch_phys_wc_add(adev->gmc.aper_base,
1084770d13b1SChristian König adev->gmc.aper_size);
108535d5f224SOak Zeng }
108635d5f224SOak Zeng
1087d38ceaf9SAlex Deucher DRM_INFO("Detected VRAM RAM=%lluM, BAR=%lluM\n",
1088770d13b1SChristian König adev->gmc.mc_vram_size >> 20,
1089770d13b1SChristian König (unsigned long long)adev->gmc.aper_size >> 20);
10901f8628c7SAlex Deucher DRM_INFO("RAM width %dbits %s\n",
1091770d13b1SChristian König adev->gmc.vram_width, amdgpu_vram_names[adev->gmc.vram_type]);
1092d38ceaf9SAlex Deucher return amdgpu_ttm_init(adev);
1093d38ceaf9SAlex Deucher }
1094d38ceaf9SAlex Deucher
10956f4e8d6eSSamuel Li /**
10966f4e8d6eSSamuel Li * amdgpu_bo_fini - tear down memory manager
10976f4e8d6eSSamuel Li * @adev: amdgpu device object
10986f4e8d6eSSamuel Li *
10996f4e8d6eSSamuel Li * Reverses amdgpu_bo_init() to tear down memory manager.
11006f4e8d6eSSamuel Li */
amdgpu_bo_fini(struct amdgpu_device * adev)1101d38ceaf9SAlex Deucher void amdgpu_bo_fini(struct amdgpu_device *adev)
1102d38ceaf9SAlex Deucher {
110362d5f9f7SLeslie Shi int idx;
110462d5f9f7SLeslie Shi
1105d38ceaf9SAlex Deucher amdgpu_ttm_fini(adev);
110662d5f9f7SLeslie Shi
110762d5f9f7SLeslie Shi if (drm_dev_enter(adev_to_drm(adev), &idx)) {
1108a0ba1279SLijo Lazar if (!adev->gmc.xgmi.connected_to_cpu && !adev->gmc.is_app_apu) {
110962d5f9f7SLeslie Shi arch_phys_wc_del(adev->gmc.vram_mtrr);
111062d5f9f7SLeslie Shi arch_io_free_memtype_wc(adev->gmc.aper_base, adev->gmc.aper_size);
111162d5f9f7SLeslie Shi }
111262d5f9f7SLeslie Shi drm_dev_exit(idx);
111362d5f9f7SLeslie Shi }
1114d38ceaf9SAlex Deucher }
1115d38ceaf9SAlex Deucher
11166f4e8d6eSSamuel Li /**
11176f4e8d6eSSamuel Li * amdgpu_bo_set_tiling_flags - set tiling flags
11186f4e8d6eSSamuel Li * @bo: &amdgpu_bo buffer object
11196f4e8d6eSSamuel Li * @tiling_flags: new flags
11206f4e8d6eSSamuel Li *
11216f4e8d6eSSamuel Li * Sets buffer object's tiling flags with the new one. Used by GEM ioctl or
11226f4e8d6eSSamuel Li * kernel driver to set the tiling flags on a buffer.
11236f4e8d6eSSamuel Li *
11242472e11bSMichel Dänzer * Returns:
11252472e11bSMichel Dänzer * 0 for success or a negative error code on failure.
11266f4e8d6eSSamuel Li */
amdgpu_bo_set_tiling_flags(struct amdgpu_bo * bo,u64 tiling_flags)1127d38ceaf9SAlex Deucher int amdgpu_bo_set_tiling_flags(struct amdgpu_bo *bo, u64 tiling_flags)
1128d38ceaf9SAlex Deucher {
11299079ac76SMarek Olšák struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev);
1130cc1bcf85SNirmoy Das struct amdgpu_bo_user *ubo;
11319079ac76SMarek Olšák
1132030bb4adSNirmoy Das BUG_ON(bo->tbo.type == ttm_bo_type_kernel);
11339079ac76SMarek Olšák if (adev->family <= AMDGPU_FAMILY_CZ &&
11349079ac76SMarek Olšák AMDGPU_TILING_GET(tiling_flags, TILE_SPLIT) > 6)
1135d38ceaf9SAlex Deucher return -EINVAL;
1136d38ceaf9SAlex Deucher
1137cc1bcf85SNirmoy Das ubo = to_amdgpu_bo_user(bo);
1138cc1bcf85SNirmoy Das ubo->tiling_flags = tiling_flags;
1139d38ceaf9SAlex Deucher return 0;
1140d38ceaf9SAlex Deucher }
1141d38ceaf9SAlex Deucher
11426f4e8d6eSSamuel Li /**
11436f4e8d6eSSamuel Li * amdgpu_bo_get_tiling_flags - get tiling flags
11446f4e8d6eSSamuel Li * @bo: &amdgpu_bo buffer object
11456f4e8d6eSSamuel Li * @tiling_flags: returned flags
11466f4e8d6eSSamuel Li *
11476f4e8d6eSSamuel Li * Gets buffer object's tiling flags. Used by GEM ioctl or kernel driver to
11486f4e8d6eSSamuel Li * set the tiling flags on a buffer.
11496f4e8d6eSSamuel Li */
amdgpu_bo_get_tiling_flags(struct amdgpu_bo * bo,u64 * tiling_flags)1150d38ceaf9SAlex Deucher void amdgpu_bo_get_tiling_flags(struct amdgpu_bo *bo, u64 *tiling_flags)
1151d38ceaf9SAlex Deucher {
1152cc1bcf85SNirmoy Das struct amdgpu_bo_user *ubo;
1153cc1bcf85SNirmoy Das
1154030bb4adSNirmoy Das BUG_ON(bo->tbo.type == ttm_bo_type_kernel);
115552791eeeSChristian König dma_resv_assert_held(bo->tbo.base.resv);
1156cc1bcf85SNirmoy Das ubo = to_amdgpu_bo_user(bo);
1157d38ceaf9SAlex Deucher
1158d38ceaf9SAlex Deucher if (tiling_flags)
1159cc1bcf85SNirmoy Das *tiling_flags = ubo->tiling_flags;
1160d38ceaf9SAlex Deucher }
1161d38ceaf9SAlex Deucher
11626f4e8d6eSSamuel Li /**
11636f4e8d6eSSamuel Li * amdgpu_bo_set_metadata - set metadata
11646f4e8d6eSSamuel Li * @bo: &amdgpu_bo buffer object
11656f4e8d6eSSamuel Li * @metadata: new metadata
11666f4e8d6eSSamuel Li * @metadata_size: size of the new metadata
11676f4e8d6eSSamuel Li * @flags: flags of the new metadata
11686f4e8d6eSSamuel Li *
11696f4e8d6eSSamuel Li * Sets buffer object's metadata, its size and flags.
11706f4e8d6eSSamuel Li * Used via GEM ioctl.
11716f4e8d6eSSamuel Li *
11722472e11bSMichel Dänzer * Returns:
11732472e11bSMichel Dänzer * 0 for success or a negative error code on failure.
11746f4e8d6eSSamuel Li */
amdgpu_bo_set_metadata(struct amdgpu_bo * bo,void * metadata,u32 metadata_size,uint64_t flags)1175d38ceaf9SAlex Deucher int amdgpu_bo_set_metadata(struct amdgpu_bo *bo, void *metadata,
11761d6ecab1SSrinivasan Shanmugam u32 metadata_size, uint64_t flags)
1177d38ceaf9SAlex Deucher {
1178cc1bcf85SNirmoy Das struct amdgpu_bo_user *ubo;
1179d38ceaf9SAlex Deucher void *buffer;
1180d38ceaf9SAlex Deucher
1181030bb4adSNirmoy Das BUG_ON(bo->tbo.type == ttm_bo_type_kernel);
1182cc1bcf85SNirmoy Das ubo = to_amdgpu_bo_user(bo);
1183d38ceaf9SAlex Deucher if (!metadata_size) {
1184cc1bcf85SNirmoy Das if (ubo->metadata_size) {
1185cc1bcf85SNirmoy Das kfree(ubo->metadata);
1186cc1bcf85SNirmoy Das ubo->metadata = NULL;
1187cc1bcf85SNirmoy Das ubo->metadata_size = 0;
1188d38ceaf9SAlex Deucher }
1189d38ceaf9SAlex Deucher return 0;
1190d38ceaf9SAlex Deucher }
1191d38ceaf9SAlex Deucher
1192d38ceaf9SAlex Deucher if (metadata == NULL)
1193d38ceaf9SAlex Deucher return -EINVAL;
1194d38ceaf9SAlex Deucher
119571affda5SAndrzej Hajda buffer = kmemdup(metadata, metadata_size, GFP_KERNEL);
1196d38ceaf9SAlex Deucher if (buffer == NULL)
1197d38ceaf9SAlex Deucher return -ENOMEM;
1198d38ceaf9SAlex Deucher
1199cc1bcf85SNirmoy Das kfree(ubo->metadata);
1200cc1bcf85SNirmoy Das ubo->metadata_flags = flags;
1201cc1bcf85SNirmoy Das ubo->metadata = buffer;
1202cc1bcf85SNirmoy Das ubo->metadata_size = metadata_size;
1203d38ceaf9SAlex Deucher
1204d38ceaf9SAlex Deucher return 0;
1205d38ceaf9SAlex Deucher }
1206d38ceaf9SAlex Deucher
12076f4e8d6eSSamuel Li /**
12086f4e8d6eSSamuel Li * amdgpu_bo_get_metadata - get metadata
12096f4e8d6eSSamuel Li * @bo: &amdgpu_bo buffer object
12106f4e8d6eSSamuel Li * @buffer: returned metadata
12116f4e8d6eSSamuel Li * @buffer_size: size of the buffer
12126f4e8d6eSSamuel Li * @metadata_size: size of the returned metadata
12136f4e8d6eSSamuel Li * @flags: flags of the returned metadata
12146f4e8d6eSSamuel Li *
12156f4e8d6eSSamuel Li * Gets buffer object's metadata, its size and flags. buffer_size shall not be
12166f4e8d6eSSamuel Li * less than metadata_size.
12176f4e8d6eSSamuel Li * Used via GEM ioctl.
12186f4e8d6eSSamuel Li *
12192472e11bSMichel Dänzer * Returns:
12202472e11bSMichel Dänzer * 0 for success or a negative error code on failure.
12216f4e8d6eSSamuel Li */
amdgpu_bo_get_metadata(struct amdgpu_bo * bo,void * buffer,size_t buffer_size,uint32_t * metadata_size,uint64_t * flags)1222d38ceaf9SAlex Deucher int amdgpu_bo_get_metadata(struct amdgpu_bo *bo, void *buffer,
1223d38ceaf9SAlex Deucher size_t buffer_size, uint32_t *metadata_size,
1224d38ceaf9SAlex Deucher uint64_t *flags)
1225d38ceaf9SAlex Deucher {
1226cc1bcf85SNirmoy Das struct amdgpu_bo_user *ubo;
1227cc1bcf85SNirmoy Das
1228d38ceaf9SAlex Deucher if (!buffer && !metadata_size)
1229d38ceaf9SAlex Deucher return -EINVAL;
1230d38ceaf9SAlex Deucher
1231030bb4adSNirmoy Das BUG_ON(bo->tbo.type == ttm_bo_type_kernel);
1232cc1bcf85SNirmoy Das ubo = to_amdgpu_bo_user(bo);
1233eba98523SShiwu Zhang if (metadata_size)
1234eba98523SShiwu Zhang *metadata_size = ubo->metadata_size;
1235eba98523SShiwu Zhang
1236d38ceaf9SAlex Deucher if (buffer) {
1237cc1bcf85SNirmoy Das if (buffer_size < ubo->metadata_size)
1238d38ceaf9SAlex Deucher return -EINVAL;
1239d38ceaf9SAlex Deucher
1240cc1bcf85SNirmoy Das if (ubo->metadata_size)
1241cc1bcf85SNirmoy Das memcpy(buffer, ubo->metadata, ubo->metadata_size);
1242d38ceaf9SAlex Deucher }
1243d38ceaf9SAlex Deucher
1244d38ceaf9SAlex Deucher if (flags)
1245cc1bcf85SNirmoy Das *flags = ubo->metadata_flags;
1246d38ceaf9SAlex Deucher
1247d38ceaf9SAlex Deucher return 0;
1248d38ceaf9SAlex Deucher }
1249d38ceaf9SAlex Deucher
12506f4e8d6eSSamuel Li /**
12516f4e8d6eSSamuel Li * amdgpu_bo_move_notify - notification about a memory move
12526f4e8d6eSSamuel Li * @bo: pointer to a buffer object
12536f4e8d6eSSamuel Li * @evict: if this move is evicting the buffer from the graphics address space
12540c7ed3edSChristian König * @new_mem: new resource for backing the BO
12556f4e8d6eSSamuel Li *
12566f4e8d6eSSamuel Li * Marks the corresponding &amdgpu_bo buffer object as invalid, also performs
12576f4e8d6eSSamuel Li * bookkeeping.
12586f4e8d6eSSamuel Li * TTM driver callback which is called when ttm moves a buffer.
12596f4e8d6eSSamuel Li */
amdgpu_bo_move_notify(struct ttm_buffer_object * bo,bool evict,struct ttm_resource * new_mem)12600c7ed3edSChristian König void amdgpu_bo_move_notify(struct ttm_buffer_object *bo,
12610c7ed3edSChristian König bool evict,
12620c7ed3edSChristian König struct ttm_resource *new_mem)
1263d38ceaf9SAlex Deucher {
1264a7d64de6SChristian König struct amdgpu_device *adev = amdgpu_ttm_adev(bo->bdev);
12650c7ed3edSChristian König struct ttm_resource *old_mem = bo->resource;
1266765e7fbfSChristian König struct amdgpu_bo *abo;
1267d38ceaf9SAlex Deucher
1268c704ab18SChristian König if (!amdgpu_bo_is_amdgpu_bo(bo))
1269d38ceaf9SAlex Deucher return;
1270d38ceaf9SAlex Deucher
1271b82485fdSAndres Rodriguez abo = ttm_to_amdgpu_bo(bo);
12723f3333f8SChristian König amdgpu_vm_bo_invalidate(adev, abo, evict);
1273d38ceaf9SAlex Deucher
12746375bbb4SChristian König amdgpu_bo_kunmap(abo);
12756375bbb4SChristian König
12762d4dad27SChristian König if (abo->tbo.base.dma_buf && !abo->tbo.base.import_attach &&
12770c7ed3edSChristian König old_mem && old_mem->mem_type != TTM_PL_SYSTEM)
12782d4dad27SChristian König dma_buf_move_notify(abo->tbo.base.dma_buf);
12792d4dad27SChristian König
12800c7ed3edSChristian König /* move_notify is called before move happens */
12810c7ed3edSChristian König trace_amdgpu_bo_move(abo, new_mem ? new_mem->mem_type : -1,
12820c7ed3edSChristian König old_mem ? old_mem->mem_type : -1);
1283d38ceaf9SAlex Deucher }
1284d38ceaf9SAlex Deucher
amdgpu_bo_get_memory(struct amdgpu_bo * bo,struct amdgpu_mem_stats * stats)1285d6530c33SMarek Olšák void amdgpu_bo_get_memory(struct amdgpu_bo *bo,
1286d6530c33SMarek Olšák struct amdgpu_mem_stats *stats)
128787444254SRoy Sun {
12884c5eaf0cSChristian König struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev);
12894c5eaf0cSChristian König struct ttm_resource *res = bo->tbo.resource;
1290d6530c33SMarek Olšák uint64_t size = amdgpu_bo_size(bo);
1291f85a55fbSAlex Deucher struct drm_gem_object *obj;
1292ca0b954aSChristian König unsigned int domain;
1293f85a55fbSAlex Deucher bool shared;
1294ca0b954aSChristian König
1295ca0b954aSChristian König /* Abort if the BO doesn't currently have a backing store */
12964c5eaf0cSChristian König if (!res)
1297ca0b954aSChristian König return;
129887444254SRoy Sun
1299f85a55fbSAlex Deucher obj = &bo->tbo.base;
1300f85a55fbSAlex Deucher shared = drm_gem_object_is_shared_for_memory_stats(obj);
1301f85a55fbSAlex Deucher
13024c5eaf0cSChristian König domain = amdgpu_mem_type_to_domain(res->mem_type);
130387444254SRoy Sun switch (domain) {
130487444254SRoy Sun case AMDGPU_GEM_DOMAIN_VRAM:
1305d6530c33SMarek Olšák stats->vram += size;
13064c5eaf0cSChristian König if (amdgpu_res_cpu_visible(adev, bo->tbo.resource))
1307d6530c33SMarek Olšák stats->visible_vram += size;
1308f85a55fbSAlex Deucher if (shared)
1309f85a55fbSAlex Deucher stats->vram_shared += size;
131087444254SRoy Sun break;
131187444254SRoy Sun case AMDGPU_GEM_DOMAIN_GTT:
1312d6530c33SMarek Olšák stats->gtt += size;
1313f85a55fbSAlex Deucher if (shared)
1314f85a55fbSAlex Deucher stats->gtt_shared += size;
131587444254SRoy Sun break;
131687444254SRoy Sun case AMDGPU_GEM_DOMAIN_CPU:
131787444254SRoy Sun default:
1318d6530c33SMarek Olšák stats->cpu += size;
1319f85a55fbSAlex Deucher if (shared)
1320f85a55fbSAlex Deucher stats->cpu_shared += size;
132187444254SRoy Sun break;
132287444254SRoy Sun }
1323d6530c33SMarek Olšák
1324d6530c33SMarek Olšák if (bo->preferred_domains & AMDGPU_GEM_DOMAIN_VRAM) {
1325d6530c33SMarek Olšák stats->requested_vram += size;
1326d6530c33SMarek Olšák if (bo->flags & AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED)
1327d6530c33SMarek Olšák stats->requested_visible_vram += size;
1328d6530c33SMarek Olšák
1329d6530c33SMarek Olšák if (domain != AMDGPU_GEM_DOMAIN_VRAM) {
1330d6530c33SMarek Olšák stats->evicted_vram += size;
1331d6530c33SMarek Olšák if (bo->flags & AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED)
1332d6530c33SMarek Olšák stats->evicted_visible_vram += size;
1333d6530c33SMarek Olšák }
1334d6530c33SMarek Olšák } else if (bo->preferred_domains & AMDGPU_GEM_DOMAIN_GTT) {
1335d6530c33SMarek Olšák stats->requested_gtt += size;
1336d6530c33SMarek Olšák }
133787444254SRoy Sun }
133887444254SRoy Sun
13396f4e8d6eSSamuel Li /**
1340736b1729SKevin Wang * amdgpu_bo_release_notify - notification about a BO being released
1341ab2f7a5cSFelix Kuehling * @bo: pointer to a buffer object
1342ab2f7a5cSFelix Kuehling *
1343ab2f7a5cSFelix Kuehling * Wipes VRAM buffers whose contents should not be leaked before the
1344ab2f7a5cSFelix Kuehling * memory is released.
1345ab2f7a5cSFelix Kuehling */
amdgpu_bo_release_notify(struct ttm_buffer_object * bo)1346ab2f7a5cSFelix Kuehling void amdgpu_bo_release_notify(struct ttm_buffer_object *bo)
1347ab2f7a5cSFelix Kuehling {
134832f90e65SGuchun Chen struct amdgpu_device *adev = amdgpu_ttm_adev(bo->bdev);
1349ab2f7a5cSFelix Kuehling struct dma_fence *fence = NULL;
1350ab2f7a5cSFelix Kuehling struct amdgpu_bo *abo;
1351ab2f7a5cSFelix Kuehling int r;
1352ab2f7a5cSFelix Kuehling
1353ab2f7a5cSFelix Kuehling if (!amdgpu_bo_is_amdgpu_bo(bo))
1354ab2f7a5cSFelix Kuehling return;
1355ab2f7a5cSFelix Kuehling
1356ab2f7a5cSFelix Kuehling abo = ttm_to_amdgpu_bo(bo);
1357ab2f7a5cSFelix Kuehling
1358ab2f7a5cSFelix Kuehling if (abo->kfd_bo)
13595702d052SFelix Kuehling amdgpu_amdkfd_release_notify(abo);
1360ab2f7a5cSFelix Kuehling
1361f4a3c42bSxinhui pan /* We only remove the fence if the resv has individualized. */
13629fe58d0bSxinhui pan WARN_ON_ONCE(bo->type == ttm_bo_type_kernel
13639fe58d0bSxinhui pan && bo->base.resv != &bo->base._resv);
1364f4a3c42bSxinhui pan if (bo->base.resv == &bo->base._resv)
1365f4a3c42bSxinhui pan amdgpu_amdkfd_remove_fence_on_pt_pd_bos(abo);
1366f4a3c42bSxinhui pan
136763af82cfSChristian König if (!bo->resource || bo->resource->mem_type != TTM_PL_VRAM ||
136832f90e65SGuchun Chen !(abo->flags & AMDGPU_GEM_CREATE_VRAM_WIPE_ON_RELEASE) ||
136993bb18d2Slyndonli adev->in_suspend || drm_dev_is_unplugged(adev_to_drm(adev)))
1370ab2f7a5cSFelix Kuehling return;
1371ab2f7a5cSFelix Kuehling
1372447c7997SRajneesh Bhardwaj if (WARN_ON_ONCE(!dma_resv_trylock(bo->base.resv)))
1373447c7997SRajneesh Bhardwaj return;
1374ab2f7a5cSFelix Kuehling
1375c3aaca43SMukul Joshi r = amdgpu_fill_buffer(abo, AMDGPU_POISON, bo->base.resv, &fence, true);
1376ab2f7a5cSFelix Kuehling if (!WARN_ON(r)) {
1377ab2f7a5cSFelix Kuehling amdgpu_bo_fence(abo, fence, false);
1378ab2f7a5cSFelix Kuehling dma_fence_put(fence);
1379ab2f7a5cSFelix Kuehling }
1380ab2f7a5cSFelix Kuehling
13815f680625SDave Airlie dma_resv_unlock(bo->base.resv);
1382ab2f7a5cSFelix Kuehling }
1383ab2f7a5cSFelix Kuehling
1384ab2f7a5cSFelix Kuehling /**
13856f4e8d6eSSamuel Li * amdgpu_bo_fault_reserve_notify - notification about a memory fault
13866f4e8d6eSSamuel Li * @bo: pointer to a buffer object
13876f4e8d6eSSamuel Li *
13886f4e8d6eSSamuel Li * Notifies the driver we are taking a fault on this BO and have reserved it,
13896f4e8d6eSSamuel Li * also performs bookkeeping.
13906f4e8d6eSSamuel Li * TTM driver callback for dealing with vm faults.
13916f4e8d6eSSamuel Li *
13922472e11bSMichel Dänzer * Returns:
13932472e11bSMichel Dänzer * 0 for success or a negative error code on failure.
13946f4e8d6eSSamuel Li */
amdgpu_bo_fault_reserve_notify(struct ttm_buffer_object * bo)1395d3ef581aSChristian König vm_fault_t amdgpu_bo_fault_reserve_notify(struct ttm_buffer_object *bo)
1396d38ceaf9SAlex Deucher {
1397a7d64de6SChristian König struct amdgpu_device *adev = amdgpu_ttm_adev(bo->bdev);
139819be5570SChristian König struct ttm_operation_ctx ctx = { false, false };
1399d3ef581aSChristian König struct amdgpu_bo *abo = ttm_to_amdgpu_bo(bo);
140096cf8271SJohn Brooks int r;
1401d38ceaf9SAlex Deucher
140296cf8271SJohn Brooks /* Remember that this BO was accessed by the CPU */
140396cf8271SJohn Brooks abo->flags |= AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED;
140496cf8271SJohn Brooks
14054c5eaf0cSChristian König if (amdgpu_res_cpu_visible(adev, bo->resource))
14065fb1941dSChristian König return 0;
14075fb1941dSChristian König
1408104ece97SMichel Dänzer /* Can't move a pinned BO to visible VRAM */
14094671078eSChristian König if (abo->tbo.pin_count > 0)
1410d3ef581aSChristian König return VM_FAULT_SIGBUS;
1411104ece97SMichel Dänzer
1412d38ceaf9SAlex Deucher /* hurrah the memory is not visible ! */
141368e2c5ffSMarek Olšák atomic64_inc(&adev->num_vram_cpu_page_faults);
1414c704ab18SChristian König amdgpu_bo_placement_from_domain(abo, AMDGPU_GEM_DOMAIN_VRAM |
141541d9a6a7SJohn Brooks AMDGPU_GEM_DOMAIN_GTT);
141641d9a6a7SJohn Brooks
141741d9a6a7SJohn Brooks /* Avoid costly evictions; only set GTT as a busy placement */
141841d9a6a7SJohn Brooks abo->placement.num_busy_placement = 1;
141941d9a6a7SJohn Brooks abo->placement.busy_placement = &abo->placements[1];
142041d9a6a7SJohn Brooks
142119be5570SChristian König r = ttm_bo_validate(bo, &abo->placement, &ctx);
1422d3ef581aSChristian König if (unlikely(r == -EBUSY || r == -ERESTARTSYS))
1423d3ef581aSChristian König return VM_FAULT_NOPAGE;
1424d3ef581aSChristian König else if (unlikely(r))
1425d3ef581aSChristian König return VM_FAULT_SIGBUS;
14265fb1941dSChristian König
14275fb1941dSChristian König /* this should never happen */
1428d3116756SChristian König if (bo->resource->mem_type == TTM_PL_VRAM &&
14294c5eaf0cSChristian König !amdgpu_res_cpu_visible(adev, bo->resource))
1430d3ef581aSChristian König return VM_FAULT_SIGBUS;
14315fb1941dSChristian König
1432d3ef581aSChristian König ttm_bo_move_to_lru_tail_unlocked(bo);
1433d38ceaf9SAlex Deucher return 0;
1434d38ceaf9SAlex Deucher }
1435d38ceaf9SAlex Deucher
1436d38ceaf9SAlex Deucher /**
1437d38ceaf9SAlex Deucher * amdgpu_bo_fence - add fence to buffer object
1438d38ceaf9SAlex Deucher *
1439d38ceaf9SAlex Deucher * @bo: buffer object in question
1440d38ceaf9SAlex Deucher * @fence: fence to add
1441d38ceaf9SAlex Deucher * @shared: true if fence should be added shared
1442d38ceaf9SAlex Deucher *
1443d38ceaf9SAlex Deucher */
amdgpu_bo_fence(struct amdgpu_bo * bo,struct dma_fence * fence,bool shared)1444f54d1867SChris Wilson void amdgpu_bo_fence(struct amdgpu_bo *bo, struct dma_fence *fence,
1445d38ceaf9SAlex Deucher bool shared)
1446d38ceaf9SAlex Deucher {
144752791eeeSChristian König struct dma_resv *resv = bo->tbo.base.resv;
1448c8d4c18bSChristian König int r;
1449c8d4c18bSChristian König
1450c8d4c18bSChristian König r = dma_resv_reserve_fences(resv, 1);
1451c8d4c18bSChristian König if (r) {
1452c8d4c18bSChristian König /* As last resort on OOM we block for the fence */
1453c8d4c18bSChristian König dma_fence_wait(fence, false);
1454c8d4c18bSChristian König return;
1455c8d4c18bSChristian König }
1456d38ceaf9SAlex Deucher
145773511edfSChristian König dma_resv_add_fence(resv, fence, shared ? DMA_RESV_USAGE_READ :
145873511edfSChristian König DMA_RESV_USAGE_WRITE);
1459d38ceaf9SAlex Deucher }
1460cdb7e8f2SChristian König
1461cdb7e8f2SChristian König /**
14629f3cc18dSChristian König * amdgpu_bo_sync_wait_resv - Wait for BO reservation fences
1463e8e32426SFelix Kuehling *
14649f3cc18dSChristian König * @adev: amdgpu device pointer
14659f3cc18dSChristian König * @resv: reservation object to sync to
14669f3cc18dSChristian König * @sync_mode: synchronization mode
1467e8e32426SFelix Kuehling * @owner: fence owner
1468e8e32426SFelix Kuehling * @intr: Whether the wait is interruptible
1469e8e32426SFelix Kuehling *
14709f3cc18dSChristian König * Extract the fences from the reservation object and waits for them to finish.
14719f3cc18dSChristian König *
14729f3cc18dSChristian König * Returns:
14739f3cc18dSChristian König * 0 on success, errno otherwise.
14749f3cc18dSChristian König */
amdgpu_bo_sync_wait_resv(struct amdgpu_device * adev,struct dma_resv * resv,enum amdgpu_sync_mode sync_mode,void * owner,bool intr)14759f3cc18dSChristian König int amdgpu_bo_sync_wait_resv(struct amdgpu_device *adev, struct dma_resv *resv,
14769f3cc18dSChristian König enum amdgpu_sync_mode sync_mode, void *owner,
14779f3cc18dSChristian König bool intr)
14789f3cc18dSChristian König {
14799f3cc18dSChristian König struct amdgpu_sync sync;
14809f3cc18dSChristian König int r;
14819f3cc18dSChristian König
14829f3cc18dSChristian König amdgpu_sync_create(&sync);
14839f3cc18dSChristian König amdgpu_sync_resv(adev, &sync, resv, sync_mode, owner);
14849f3cc18dSChristian König r = amdgpu_sync_wait(&sync, intr);
14859f3cc18dSChristian König amdgpu_sync_free(&sync);
14869f3cc18dSChristian König return r;
14879f3cc18dSChristian König }
14889f3cc18dSChristian König
14899f3cc18dSChristian König /**
14909f3cc18dSChristian König * amdgpu_bo_sync_wait - Wrapper for amdgpu_bo_sync_wait_resv
14919f3cc18dSChristian König * @bo: buffer object to wait for
14929f3cc18dSChristian König * @owner: fence owner
14939f3cc18dSChristian König * @intr: Whether the wait is interruptible
14949f3cc18dSChristian König *
14959f3cc18dSChristian König * Wrapper to wait for fences in a BO.
1496e8e32426SFelix Kuehling * Returns:
1497e8e32426SFelix Kuehling * 0 on success, errno otherwise.
1498e8e32426SFelix Kuehling */
amdgpu_bo_sync_wait(struct amdgpu_bo * bo,void * owner,bool intr)1499e8e32426SFelix Kuehling int amdgpu_bo_sync_wait(struct amdgpu_bo *bo, void *owner, bool intr)
1500e8e32426SFelix Kuehling {
1501e8e32426SFelix Kuehling struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev);
1502e8e32426SFelix Kuehling
15039f3cc18dSChristian König return amdgpu_bo_sync_wait_resv(adev, bo->tbo.base.resv,
15049f3cc18dSChristian König AMDGPU_SYNC_NE_OWNER, owner, intr);
1505e8e32426SFelix Kuehling }
1506e8e32426SFelix Kuehling
1507e8e32426SFelix Kuehling /**
1508cdb7e8f2SChristian König * amdgpu_bo_gpu_offset - return GPU offset of bo
1509cdb7e8f2SChristian König * @bo: amdgpu object for which we query the offset
1510cdb7e8f2SChristian König *
1511cdb7e8f2SChristian König * Note: object should either be pinned or reserved when calling this
1512cdb7e8f2SChristian König * function, it might be useful to add check for this for debugging.
15132472e11bSMichel Dänzer *
15142472e11bSMichel Dänzer * Returns:
15152472e11bSMichel Dänzer * current GPU offset of the object.
1516cdb7e8f2SChristian König */
amdgpu_bo_gpu_offset(struct amdgpu_bo * bo)1517cdb7e8f2SChristian König u64 amdgpu_bo_gpu_offset(struct amdgpu_bo *bo)
1518cdb7e8f2SChristian König {
1519d3116756SChristian König WARN_ON_ONCE(bo->tbo.resource->mem_type == TTM_PL_SYSTEM);
152052791eeeSChristian König WARN_ON_ONCE(!dma_resv_is_locked(bo->tbo.base.resv) &&
15214671078eSChristian König !bo->tbo.pin_count && bo->tbo.type != ttm_bo_type_kernel);
1522d3116756SChristian König WARN_ON_ONCE(bo->tbo.resource->start == AMDGPU_BO_INVALID_OFFSET);
1523d3116756SChristian König WARN_ON_ONCE(bo->tbo.resource->mem_type == TTM_PL_VRAM &&
152403f48dd5SChristian König !(bo->flags & AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS));
1525cdb7e8f2SChristian König
1526b1a8ef95SNirmoy Das return amdgpu_bo_gpu_offset_no_check(bo);
1527b1a8ef95SNirmoy Das }
1528b1a8ef95SNirmoy Das
1529b1a8ef95SNirmoy Das /**
1530b1a8ef95SNirmoy Das * amdgpu_bo_gpu_offset_no_check - return GPU offset of bo
1531b1a8ef95SNirmoy Das * @bo: amdgpu object for which we query the offset
1532b1a8ef95SNirmoy Das *
1533b1a8ef95SNirmoy Das * Returns:
1534b1a8ef95SNirmoy Das * current GPU offset of the object without raising warnings.
1535b1a8ef95SNirmoy Das */
amdgpu_bo_gpu_offset_no_check(struct amdgpu_bo * bo)1536b1a8ef95SNirmoy Das u64 amdgpu_bo_gpu_offset_no_check(struct amdgpu_bo *bo)
1537b1a8ef95SNirmoy Das {
1538b1a8ef95SNirmoy Das struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev);
1539b1a8ef95SNirmoy Das uint64_t offset;
1540b1a8ef95SNirmoy Das
1541d3116756SChristian König offset = (bo->tbo.resource->start << PAGE_SHIFT) +
1542d3116756SChristian König amdgpu_ttm_domain_start(adev, bo->tbo.resource->mem_type);
1543b1a8ef95SNirmoy Das
1544b1a8ef95SNirmoy Das return amdgpu_gmc_sign_extend(offset);
1545cdb7e8f2SChristian König }
154684b74608SDeepak Sharma
15472472e11bSMichel Dänzer /**
1548d035f84dSYifan Zhang * amdgpu_bo_get_preferred_domain - get preferred domain
15492472e11bSMichel Dänzer * @adev: amdgpu device object
15502472e11bSMichel Dänzer * @domain: allowed :ref:`memory domains <amdgpu_memory_domains>`
15512472e11bSMichel Dänzer *
15522472e11bSMichel Dänzer * Returns:
1553d035f84dSYifan Zhang * Which of the allowed domains is preferred for allocating the BO.
15542472e11bSMichel Dänzer */
amdgpu_bo_get_preferred_domain(struct amdgpu_device * adev,uint32_t domain)1555d035f84dSYifan Zhang uint32_t amdgpu_bo_get_preferred_domain(struct amdgpu_device *adev,
155684b74608SDeepak Sharma uint32_t domain)
155784b74608SDeepak Sharma {
155881d0bcf9SAlex Deucher if ((domain == (AMDGPU_GEM_DOMAIN_VRAM | AMDGPU_GEM_DOMAIN_GTT)) &&
155981d0bcf9SAlex Deucher ((adev->asic_type == CHIP_CARRIZO) || (adev->asic_type == CHIP_STONEY))) {
156084b74608SDeepak Sharma domain = AMDGPU_GEM_DOMAIN_VRAM;
156184b74608SDeepak Sharma if (adev->gmc.real_vram_size <= AMDGPU_SG_THRESHOLD)
156284b74608SDeepak Sharma domain = AMDGPU_GEM_DOMAIN_GTT;
156384b74608SDeepak Sharma }
156484b74608SDeepak Sharma return domain;
156584b74608SDeepak Sharma }
1566ff72bc40SMihir Bhogilal Patel
1567ff72bc40SMihir Bhogilal Patel #if defined(CONFIG_DEBUG_FS)
1568ff72bc40SMihir Bhogilal Patel #define amdgpu_bo_print_flag(m, bo, flag) \
1569ff72bc40SMihir Bhogilal Patel do { \
1570ff72bc40SMihir Bhogilal Patel if (bo->flags & (AMDGPU_GEM_CREATE_ ## flag)) { \
1571ff72bc40SMihir Bhogilal Patel seq_printf((m), " " #flag); \
1572ff72bc40SMihir Bhogilal Patel } \
1573ff72bc40SMihir Bhogilal Patel } while (0)
1574ff72bc40SMihir Bhogilal Patel
1575ff72bc40SMihir Bhogilal Patel /**
157625dd7a44SMauro Carvalho Chehab * amdgpu_bo_print_info - print BO info in debugfs file
1577ff72bc40SMihir Bhogilal Patel *
1578ff72bc40SMihir Bhogilal Patel * @id: Index or Id of the BO
1579ff72bc40SMihir Bhogilal Patel * @bo: Requested BO for printing info
1580ff72bc40SMihir Bhogilal Patel * @m: debugfs file
1581ff72bc40SMihir Bhogilal Patel *
1582ff72bc40SMihir Bhogilal Patel * Print BO information in debugfs file
1583ff72bc40SMihir Bhogilal Patel *
1584ff72bc40SMihir Bhogilal Patel * Returns:
1585ff72bc40SMihir Bhogilal Patel * Size of the BO in bytes.
1586ff72bc40SMihir Bhogilal Patel */
amdgpu_bo_print_info(int id,struct amdgpu_bo * bo,struct seq_file * m)1587ff72bc40SMihir Bhogilal Patel u64 amdgpu_bo_print_info(int id, struct amdgpu_bo *bo, struct seq_file *m)
1588ff72bc40SMihir Bhogilal Patel {
15894c5eaf0cSChristian König struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev);
1590ff72bc40SMihir Bhogilal Patel struct dma_buf_attachment *attachment;
1591ff72bc40SMihir Bhogilal Patel struct dma_buf *dma_buf;
1592ff72bc40SMihir Bhogilal Patel const char *placement;
1593ff72bc40SMihir Bhogilal Patel unsigned int pin_count;
1594ff72bc40SMihir Bhogilal Patel u64 size;
1595ff72bc40SMihir Bhogilal Patel
1596818c158fSPierre-Eric Pelloux-Prayer if (dma_resv_trylock(bo->tbo.base.resv)) {
1597818c158fSPierre-Eric Pelloux-Prayer unsigned int domain;
15984c5eaf0cSChristian König
1599d3116756SChristian König domain = amdgpu_mem_type_to_domain(bo->tbo.resource->mem_type);
1600ff72bc40SMihir Bhogilal Patel switch (domain) {
1601ff72bc40SMihir Bhogilal Patel case AMDGPU_GEM_DOMAIN_VRAM:
16024c5eaf0cSChristian König if (amdgpu_res_cpu_visible(adev, bo->tbo.resource))
1603818c158fSPierre-Eric Pelloux-Prayer placement = "VRAM VISIBLE";
1604818c158fSPierre-Eric Pelloux-Prayer else
1605ff72bc40SMihir Bhogilal Patel placement = "VRAM";
1606ff72bc40SMihir Bhogilal Patel break;
1607ff72bc40SMihir Bhogilal Patel case AMDGPU_GEM_DOMAIN_GTT:
1608ff72bc40SMihir Bhogilal Patel placement = "GTT";
1609ff72bc40SMihir Bhogilal Patel break;
1610ff72bc40SMihir Bhogilal Patel case AMDGPU_GEM_DOMAIN_CPU:
1611ff72bc40SMihir Bhogilal Patel default:
1612ff72bc40SMihir Bhogilal Patel placement = "CPU";
1613ff72bc40SMihir Bhogilal Patel break;
1614ff72bc40SMihir Bhogilal Patel }
1615818c158fSPierre-Eric Pelloux-Prayer dma_resv_unlock(bo->tbo.base.resv);
1616818c158fSPierre-Eric Pelloux-Prayer } else {
1617818c158fSPierre-Eric Pelloux-Prayer placement = "UNKNOWN";
1618818c158fSPierre-Eric Pelloux-Prayer }
1619ff72bc40SMihir Bhogilal Patel
1620ff72bc40SMihir Bhogilal Patel size = amdgpu_bo_size(bo);
1621ff72bc40SMihir Bhogilal Patel seq_printf(m, "\t\t0x%08x: %12lld byte %s",
1622ff72bc40SMihir Bhogilal Patel id, size, placement);
1623ff72bc40SMihir Bhogilal Patel
16245b8c5969SDave Airlie pin_count = READ_ONCE(bo->tbo.pin_count);
1625ff72bc40SMihir Bhogilal Patel if (pin_count)
1626ff72bc40SMihir Bhogilal Patel seq_printf(m, " pin count %d", pin_count);
1627ff72bc40SMihir Bhogilal Patel
1628ff72bc40SMihir Bhogilal Patel dma_buf = READ_ONCE(bo->tbo.base.dma_buf);
1629ff72bc40SMihir Bhogilal Patel attachment = READ_ONCE(bo->tbo.base.import_attach);
1630ff72bc40SMihir Bhogilal Patel
1631ff72bc40SMihir Bhogilal Patel if (attachment)
163226fd808bSPierre-Eric Pelloux-Prayer seq_printf(m, " imported from ino:%lu", file_inode(dma_buf->file)->i_ino);
1633ff72bc40SMihir Bhogilal Patel else if (dma_buf)
163426fd808bSPierre-Eric Pelloux-Prayer seq_printf(m, " exported as ino:%lu", file_inode(dma_buf->file)->i_ino);
1635ff72bc40SMihir Bhogilal Patel
1636ff72bc40SMihir Bhogilal Patel amdgpu_bo_print_flag(m, bo, CPU_ACCESS_REQUIRED);
1637ff72bc40SMihir Bhogilal Patel amdgpu_bo_print_flag(m, bo, NO_CPU_ACCESS);
1638ff72bc40SMihir Bhogilal Patel amdgpu_bo_print_flag(m, bo, CPU_GTT_USWC);
1639ff72bc40SMihir Bhogilal Patel amdgpu_bo_print_flag(m, bo, VRAM_CLEARED);
1640ff72bc40SMihir Bhogilal Patel amdgpu_bo_print_flag(m, bo, VRAM_CONTIGUOUS);
1641ff72bc40SMihir Bhogilal Patel amdgpu_bo_print_flag(m, bo, VM_ALWAYS_VALID);
1642ff72bc40SMihir Bhogilal Patel amdgpu_bo_print_flag(m, bo, EXPLICIT_SYNC);
1643ff72bc40SMihir Bhogilal Patel
1644ff72bc40SMihir Bhogilal Patel seq_puts(m, "\n");
1645ff72bc40SMihir Bhogilal Patel
1646ff72bc40SMihir Bhogilal Patel return size;
1647ff72bc40SMihir Bhogilal Patel }
1648ff72bc40SMihir Bhogilal Patel #endif
1649