1fb4d8502Sjsg /* 2fb4d8502Sjsg * Copyright 2008 Advanced Micro Devices, Inc. 3fb4d8502Sjsg * Copyright 2008 Red Hat Inc. 4fb4d8502Sjsg * Copyright 2009 Jerome Glisse. 5fb4d8502Sjsg * 6fb4d8502Sjsg * Permission is hereby granted, free of charge, to any person obtaining a 7fb4d8502Sjsg * copy of this software and associated documentation files (the "Software"), 8fb4d8502Sjsg * to deal in the Software without restriction, including without limitation 9fb4d8502Sjsg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10fb4d8502Sjsg * and/or sell copies of the Software, and to permit persons to whom the 11fb4d8502Sjsg * Software is furnished to do so, subject to the following conditions: 12fb4d8502Sjsg * 13fb4d8502Sjsg * The above copyright notice and this permission notice shall be included in 14fb4d8502Sjsg * all copies or substantial portions of the Software. 15fb4d8502Sjsg * 16fb4d8502Sjsg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17fb4d8502Sjsg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18fb4d8502Sjsg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19fb4d8502Sjsg * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 20fb4d8502Sjsg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21fb4d8502Sjsg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22fb4d8502Sjsg * OTHER DEALINGS IN THE SOFTWARE. 23fb4d8502Sjsg * 24fb4d8502Sjsg * Authors: Dave Airlie 25fb4d8502Sjsg * Alex Deucher 26fb4d8502Sjsg * Jerome Glisse 27fb4d8502Sjsg */ 28fb4d8502Sjsg #include <linux/ktime.h> 29c349dbc7Sjsg #include <linux/module.h> 30fb4d8502Sjsg #include <linux/pagemap.h> 31c349dbc7Sjsg #include <linux/pci.h> 32ad8b1aafSjsg #include <linux/dma-buf.h> 33c349dbc7Sjsg 34fb4d8502Sjsg #include <drm/amdgpu_drm.h> 355ca02815Sjsg #include <drm/drm_drv.h> 36f005ef32Sjsg #include <drm/drm_exec.h> 375ca02815Sjsg #include <drm/drm_gem_ttm_helper.h> 38f005ef32Sjsg #include <drm/ttm/ttm_tt.h> 39c349dbc7Sjsg 40fb4d8502Sjsg #include "amdgpu.h" 41fb4d8502Sjsg #include "amdgpu_display.h" 425ca02815Sjsg #include "amdgpu_dma_buf.h" 43f005ef32Sjsg #include "amdgpu_hmm.h" 44c349dbc7Sjsg #include "amdgpu_xgmi.h" 45fb4d8502Sjsg 465ca02815Sjsg static const struct drm_gem_object_funcs amdgpu_gem_object_funcs; 475ca02815Sjsg 485ca02815Sjsg #ifdef __linux__ 495ca02815Sjsg static vm_fault_t amdgpu_gem_fault(struct vm_fault *vmf) 505ca02815Sjsg { 515ca02815Sjsg struct ttm_buffer_object *bo = vmf->vma->vm_private_data; 525ca02815Sjsg struct drm_device *ddev = bo->base.dev; 535ca02815Sjsg vm_fault_t ret; 545ca02815Sjsg int idx; 555ca02815Sjsg 565ca02815Sjsg ret = ttm_bo_vm_reserve(bo, vmf); 575ca02815Sjsg if (ret) 585ca02815Sjsg return ret; 595ca02815Sjsg 605ca02815Sjsg if (drm_dev_enter(ddev, &idx)) { 615ca02815Sjsg ret = amdgpu_bo_fault_reserve_notify(bo); 625ca02815Sjsg if (ret) { 635ca02815Sjsg drm_dev_exit(idx); 645ca02815Sjsg goto unlock; 655ca02815Sjsg } 665ca02815Sjsg 675ca02815Sjsg ret = ttm_bo_vm_fault_reserved(vmf, vmf->vma->vm_page_prot, 685ca02815Sjsg TTM_BO_VM_NUM_PREFAULT); 695ca02815Sjsg 705ca02815Sjsg drm_dev_exit(idx); 715ca02815Sjsg } else { 725ca02815Sjsg ret = ttm_bo_vm_dummy_page(vmf, vmf->vma->vm_page_prot); 735ca02815Sjsg } 745ca02815Sjsg if (ret == VM_FAULT_RETRY && !(vmf->flags & FAULT_FLAG_RETRY_NOWAIT)) 755ca02815Sjsg return ret; 765ca02815Sjsg 775ca02815Sjsg unlock: 785ca02815Sjsg dma_resv_unlock(bo->base.resv); 795ca02815Sjsg return ret; 805ca02815Sjsg } 815ca02815Sjsg 825ca02815Sjsg static const struct vm_operations_struct amdgpu_gem_vm_ops = { 835ca02815Sjsg .fault = amdgpu_gem_fault, 845ca02815Sjsg .open = ttm_bo_vm_open, 855ca02815Sjsg .close = ttm_bo_vm_close, 865ca02815Sjsg .access = ttm_bo_vm_access 875ca02815Sjsg }; 885ca02815Sjsg #else /* !__linux__ */ 895ca02815Sjsg int 905ca02815Sjsg amdgpu_gem_fault(struct uvm_faultinfo *ufi, vaddr_t vaddr, vm_page_t *pps, 915ca02815Sjsg int npages, int centeridx, vm_fault_t fault_type, 925ca02815Sjsg vm_prot_t access_type, int flags) 935ca02815Sjsg { 945ca02815Sjsg struct uvm_object *uobj = ufi->entry->object.uvm_obj; 955ca02815Sjsg struct ttm_buffer_object *bo = (struct ttm_buffer_object *)uobj; 965ca02815Sjsg struct drm_device *ddev = bo->base.dev; 975ca02815Sjsg vm_fault_t ret; 985ca02815Sjsg int idx; 995ca02815Sjsg 1005ca02815Sjsg ret = ttm_bo_vm_reserve(bo); 1015ca02815Sjsg if (ret) { 102*f46a341eSmpi goto out; 1035ca02815Sjsg } 1045ca02815Sjsg 1055ca02815Sjsg if (drm_dev_enter(ddev, &idx)) { 1065ca02815Sjsg ret = amdgpu_bo_fault_reserve_notify(bo); 1075ca02815Sjsg if (ret) { 1085ca02815Sjsg drm_dev_exit(idx); 1095ca02815Sjsg goto unlock; 1105ca02815Sjsg } 1115ca02815Sjsg 1125ca02815Sjsg ret = ttm_bo_vm_fault_reserved(ufi, vaddr, 1135ca02815Sjsg TTM_BO_VM_NUM_PREFAULT, 1); 1145ca02815Sjsg 1155ca02815Sjsg drm_dev_exit(idx); 1165ca02815Sjsg } else { 1175ca02815Sjsg STUB(); 1185ca02815Sjsg #ifdef notyet 1195ca02815Sjsg ret = ttm_bo_vm_dummy_page(vmf, vmf->vma->vm_page_prot); 1205ca02815Sjsg #endif 1215ca02815Sjsg } 1225ca02815Sjsg #ifdef __linux__ 1235ca02815Sjsg if (ret == VM_FAULT_RETRY && !(vmf->flags & FAULT_FLAG_RETRY_NOWAIT)) 1245ca02815Sjsg return ret; 1255ca02815Sjsg #endif 1265ca02815Sjsg 1275ca02815Sjsg unlock: 128*f46a341eSmpi dma_resv_unlock(bo->base.resv); 129*f46a341eSmpi out: 1305ca02815Sjsg switch (ret) { 1315ca02815Sjsg case VM_FAULT_NOPAGE: 132*f46a341eSmpi ret = 0; 1335ca02815Sjsg break; 1345ca02815Sjsg case VM_FAULT_RETRY: 135*f46a341eSmpi ret = ERESTART; 1365ca02815Sjsg break; 1375ca02815Sjsg default: 138*f46a341eSmpi ret = EACCES; 1395ca02815Sjsg break; 1405ca02815Sjsg } 1415ca02815Sjsg uvmfault_unlockall(ufi, NULL, uobj); 1425ca02815Sjsg return ret; 1435ca02815Sjsg } 1445ca02815Sjsg 1455ca02815Sjsg void 1465ca02815Sjsg amdgpu_gem_vm_reference(struct uvm_object *uobj) 1475ca02815Sjsg { 1485ca02815Sjsg struct ttm_buffer_object *bo = (struct ttm_buffer_object *)uobj; 1495ca02815Sjsg 1505ca02815Sjsg ttm_bo_get(bo); 1515ca02815Sjsg } 1525ca02815Sjsg 1535ca02815Sjsg void 1545ca02815Sjsg amdgpu_gem_vm_detach(struct uvm_object *uobj) 1555ca02815Sjsg { 1565ca02815Sjsg struct ttm_buffer_object *bo = (struct ttm_buffer_object *)uobj; 1575ca02815Sjsg 1585ca02815Sjsg ttm_bo_put(bo); 1595ca02815Sjsg } 1605ca02815Sjsg 1615ca02815Sjsg static const struct uvm_pagerops amdgpu_gem_vm_ops = { 1625ca02815Sjsg .pgo_fault = amdgpu_gem_fault, 1635ca02815Sjsg .pgo_reference = amdgpu_gem_vm_reference, 1645ca02815Sjsg .pgo_detach = amdgpu_gem_vm_detach 1655ca02815Sjsg }; 1665ca02815Sjsg #endif /* !__linux__ */ 1675ca02815Sjsg 1685ca02815Sjsg static void amdgpu_gem_object_free(struct drm_gem_object *gobj) 169fb4d8502Sjsg { 170fb4d8502Sjsg struct amdgpu_bo *robj = gem_to_amdgpu_bo(gobj); 171fb4d8502Sjsg 172fb4d8502Sjsg if (robj) { 173f005ef32Sjsg amdgpu_hmm_unregister(robj); 174fb4d8502Sjsg amdgpu_bo_unref(&robj); 175fb4d8502Sjsg } 176fb4d8502Sjsg } 177fb4d8502Sjsg 178fb4d8502Sjsg int amdgpu_gem_object_create(struct amdgpu_device *adev, unsigned long size, 179fb4d8502Sjsg int alignment, u32 initial_domain, 180fb4d8502Sjsg u64 flags, enum ttm_bo_type type, 181c349dbc7Sjsg struct dma_resv *resv, 182f005ef32Sjsg struct drm_gem_object **obj, int8_t xcp_id_plus1) 183fb4d8502Sjsg { 184fb4d8502Sjsg struct amdgpu_bo *bo; 1855ca02815Sjsg struct amdgpu_bo_user *ubo; 186fb4d8502Sjsg struct amdgpu_bo_param bp; 187fb4d8502Sjsg int r; 188fb4d8502Sjsg 189fb4d8502Sjsg memset(&bp, 0, sizeof(bp)); 190fb4d8502Sjsg *obj = NULL; 191fb4d8502Sjsg 192fb4d8502Sjsg bp.size = size; 193fb4d8502Sjsg bp.byte_align = alignment; 194fb4d8502Sjsg bp.type = type; 195fb4d8502Sjsg bp.resv = resv; 196fb4d8502Sjsg bp.preferred_domain = initial_domain; 197fb4d8502Sjsg bp.flags = flags; 198fb4d8502Sjsg bp.domain = initial_domain; 1995ca02815Sjsg bp.bo_ptr_size = sizeof(struct amdgpu_bo); 200f005ef32Sjsg bp.xcp_id_plus1 = xcp_id_plus1; 2015ca02815Sjsg 2025ca02815Sjsg r = amdgpu_bo_create_user(adev, &bp, &ubo); 203ad8b1aafSjsg if (r) 204fb4d8502Sjsg return r; 205ad8b1aafSjsg 2065ca02815Sjsg bo = &ubo->bo; 207c349dbc7Sjsg *obj = &bo->tbo.base; 2085ca02815Sjsg (*obj)->funcs = &amdgpu_gem_object_funcs; 209fb4d8502Sjsg 210fb4d8502Sjsg return 0; 211fb4d8502Sjsg } 212fb4d8502Sjsg 21364094178Sjsg int drm_file_cmp(struct drm_file *, struct drm_file *); 21464094178Sjsg SPLAY_PROTOTYPE(drm_file_tree, drm_file, link, drm_file_cmp); 21564094178Sjsg 216fb4d8502Sjsg void amdgpu_gem_force_release(struct amdgpu_device *adev) 217fb4d8502Sjsg { 218ad8b1aafSjsg struct drm_device *ddev = adev_to_drm(adev); 219fb4d8502Sjsg struct drm_file *file; 220fb4d8502Sjsg 221fb4d8502Sjsg mutex_lock(&ddev->filelist_mutex); 222fb4d8502Sjsg 2235ca02815Sjsg #ifdef __linux__ 2245ca02815Sjsg list_for_each_entry(file, &ddev->filelist, lhead) { 2255ca02815Sjsg #else 22664094178Sjsg SPLAY_FOREACH(file, drm_file_tree, &ddev->files) { 2275ca02815Sjsg #endif 228fb4d8502Sjsg struct drm_gem_object *gobj; 229fb4d8502Sjsg int handle; 230fb4d8502Sjsg 231fb4d8502Sjsg WARN_ONCE(1, "Still active user space clients!\n"); 232fb4d8502Sjsg spin_lock(&file->table_lock); 233fb4d8502Sjsg idr_for_each_entry(&file->object_idr, gobj, handle) { 234fb4d8502Sjsg WARN_ONCE(1, "And also active allocations!\n"); 235ad8b1aafSjsg drm_gem_object_put(gobj); 236fb4d8502Sjsg } 237fb4d8502Sjsg idr_destroy(&file->object_idr); 238fb4d8502Sjsg spin_unlock(&file->table_lock); 239fb4d8502Sjsg } 240fb4d8502Sjsg 241fb4d8502Sjsg mutex_unlock(&ddev->filelist_mutex); 242fb4d8502Sjsg } 243fb4d8502Sjsg 244fb4d8502Sjsg /* 245fb4d8502Sjsg * Call from drm_gem_handle_create which appear in both new and open ioctl 246fb4d8502Sjsg * case. 247fb4d8502Sjsg */ 2485ca02815Sjsg static int amdgpu_gem_object_open(struct drm_gem_object *obj, 249fb4d8502Sjsg struct drm_file *file_priv) 250fb4d8502Sjsg { 251fb4d8502Sjsg struct amdgpu_bo *abo = gem_to_amdgpu_bo(obj); 252fb4d8502Sjsg struct amdgpu_device *adev = amdgpu_ttm_adev(abo->tbo.bdev); 253fb4d8502Sjsg struct amdgpu_fpriv *fpriv = file_priv->driver_priv; 254fb4d8502Sjsg struct amdgpu_vm *vm = &fpriv->vm; 255fb4d8502Sjsg struct amdgpu_bo_va *bo_va; 256fb4d8502Sjsg #ifdef notyet 257fb4d8502Sjsg struct mm_struct *mm; 258fb4d8502Sjsg #endif 259fb4d8502Sjsg int r; 260fb4d8502Sjsg 261fb4d8502Sjsg #ifdef notyet 262fb4d8502Sjsg mm = amdgpu_ttm_tt_get_usermm(abo->tbo.ttm); 263fb4d8502Sjsg if (mm && mm != current->mm) 264fb4d8502Sjsg return -EPERM; 265fb4d8502Sjsg #endif 266fb4d8502Sjsg 267fb4d8502Sjsg if (abo->flags & AMDGPU_GEM_CREATE_VM_ALWAYS_VALID && 2685ca02815Sjsg abo->tbo.base.resv != vm->root.bo->tbo.base.resv) 269fb4d8502Sjsg return -EPERM; 270fb4d8502Sjsg 271fb4d8502Sjsg r = amdgpu_bo_reserve(abo, false); 272fb4d8502Sjsg if (r) 273fb4d8502Sjsg return r; 274fb4d8502Sjsg 275fb4d8502Sjsg bo_va = amdgpu_vm_bo_find(vm, abo); 276f005ef32Sjsg if (!bo_va) 277fb4d8502Sjsg bo_va = amdgpu_vm_bo_add(adev, vm, abo); 278f005ef32Sjsg else 279fb4d8502Sjsg ++bo_va->ref_count; 280fb4d8502Sjsg amdgpu_bo_unreserve(abo); 281fb4d8502Sjsg return 0; 282fb4d8502Sjsg } 283fb4d8502Sjsg 2845ca02815Sjsg static void amdgpu_gem_object_close(struct drm_gem_object *obj, 285fb4d8502Sjsg struct drm_file *file_priv) 286fb4d8502Sjsg { 287fb4d8502Sjsg struct amdgpu_bo *bo = gem_to_amdgpu_bo(obj); 288fb4d8502Sjsg struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev); 289fb4d8502Sjsg struct amdgpu_fpriv *fpriv = file_priv->driver_priv; 290fb4d8502Sjsg struct amdgpu_vm *vm = &fpriv->vm; 291fb4d8502Sjsg 292ede47e28Sjsg struct dma_fence *fence = NULL; 293fb4d8502Sjsg struct amdgpu_bo_va *bo_va; 294f005ef32Sjsg struct drm_exec exec; 295ede47e28Sjsg long r; 296fb4d8502Sjsg 297f005ef32Sjsg drm_exec_init(&exec, DRM_EXEC_IGNORE_DUPLICATES); 298f005ef32Sjsg drm_exec_until_all_locked(&exec) { 299f005ef32Sjsg r = drm_exec_prepare_obj(&exec, &bo->tbo.base, 1); 300f005ef32Sjsg drm_exec_retry_on_contention(&exec); 301f005ef32Sjsg if (unlikely(r)) 302f005ef32Sjsg goto out_unlock; 303fb4d8502Sjsg 304f005ef32Sjsg r = amdgpu_vm_lock_pd(vm, &exec, 0); 305f005ef32Sjsg drm_exec_retry_on_contention(&exec); 306f005ef32Sjsg if (unlikely(r)) 307f005ef32Sjsg goto out_unlock; 308fb4d8502Sjsg } 309f005ef32Sjsg 310fb4d8502Sjsg bo_va = amdgpu_vm_bo_find(vm, bo); 311ede47e28Sjsg if (!bo_va || --bo_va->ref_count) 312ede47e28Sjsg goto out_unlock; 313ede47e28Sjsg 3141bb76ff1Sjsg amdgpu_vm_bo_del(adev, bo_va); 315ede47e28Sjsg if (!amdgpu_vm_ready(vm)) 316ede47e28Sjsg goto out_unlock; 317fb4d8502Sjsg 318ede47e28Sjsg r = amdgpu_vm_clear_freed(adev, vm, &fence); 319f005ef32Sjsg if (unlikely(r < 0)) 320f005ef32Sjsg dev_err(adev->dev, "failed to clear page " 321f005ef32Sjsg "tables on GEM object close (%ld)\n", r); 322ede47e28Sjsg if (r || !fence) 323ede47e28Sjsg goto out_unlock; 324ede47e28Sjsg 325ede47e28Sjsg amdgpu_bo_fence(bo, fence, true); 326fb4d8502Sjsg dma_fence_put(fence); 327ede47e28Sjsg 328ede47e28Sjsg out_unlock: 329f005ef32Sjsg if (r) 330f005ef32Sjsg dev_err(adev->dev, "leaking bo va (%ld)\n", r); 331f005ef32Sjsg drm_exec_fini(&exec); 332fb4d8502Sjsg } 333fb4d8502Sjsg 3345ca02815Sjsg #ifdef __linux__ 3355ca02815Sjsg static int amdgpu_gem_object_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma) 3365ca02815Sjsg { 3375ca02815Sjsg struct amdgpu_bo *bo = gem_to_amdgpu_bo(obj); 3385ca02815Sjsg 3395ca02815Sjsg if (amdgpu_ttm_tt_get_usermm(bo->tbo.ttm)) 3405ca02815Sjsg return -EPERM; 3415ca02815Sjsg if (bo->flags & AMDGPU_GEM_CREATE_NO_CPU_ACCESS) 3425ca02815Sjsg return -EPERM; 3435ca02815Sjsg 3445ca02815Sjsg /* Workaround for Thunk bug creating PROT_NONE,MAP_PRIVATE mappings 3455ca02815Sjsg * for debugger access to invisible VRAM. Should have used MAP_SHARED 3465ca02815Sjsg * instead. Clearing VM_MAYWRITE prevents the mapping from ever 3475ca02815Sjsg * becoming writable and makes is_cow_mapping(vm_flags) false. 3485ca02815Sjsg */ 3495ca02815Sjsg if (is_cow_mapping(vma->vm_flags) && 350f005ef32Sjsg !(vma->vm_flags & VM_ACCESS_FLAGS)) 351f005ef32Sjsg vm_flags_clear(vma, VM_MAYWRITE); 3525ca02815Sjsg 3535ca02815Sjsg return drm_gem_ttm_mmap(obj, vma); 3545ca02815Sjsg } 3555ca02815Sjsg #else 3565ca02815Sjsg static int amdgpu_gem_object_mmap(struct drm_gem_object *obj, 3575ca02815Sjsg vm_prot_t accessprot, voff_t off, vsize_t size) 3585ca02815Sjsg { 3595ca02815Sjsg struct amdgpu_bo *bo = gem_to_amdgpu_bo(obj); 3605ca02815Sjsg 3615ca02815Sjsg if (amdgpu_ttm_tt_get_usermm(bo->tbo.ttm)) 3625ca02815Sjsg return -EPERM; 3635ca02815Sjsg if (bo->flags & AMDGPU_GEM_CREATE_NO_CPU_ACCESS) 3645ca02815Sjsg return -EPERM; 3655ca02815Sjsg 3665ca02815Sjsg /* Workaround for Thunk bug creating PROT_NONE,MAP_PRIVATE mappings 3675ca02815Sjsg * for debugger access to invisible VRAM. Should have used MAP_SHARED 3685ca02815Sjsg * instead. Clearing VM_MAYWRITE prevents the mapping from ever 3695ca02815Sjsg * becoming writable and makes is_cow_mapping(vm_flags) false. 3705ca02815Sjsg */ 3715ca02815Sjsg #ifdef notyet 3725ca02815Sjsg if (is_cow_mapping(vma->vm_flags) && 3735ca02815Sjsg !(vma->vm_flags & (VM_READ | VM_WRITE | VM_EXEC))) 3745ca02815Sjsg vma->vm_flags &= ~VM_MAYWRITE; 3755ca02815Sjsg #endif 3765ca02815Sjsg 3775ca02815Sjsg return drm_gem_ttm_mmap(obj, accessprot, off, size); 3785ca02815Sjsg } 3795ca02815Sjsg #endif 3805ca02815Sjsg 3815ca02815Sjsg static const struct drm_gem_object_funcs amdgpu_gem_object_funcs = { 3825ca02815Sjsg .free = amdgpu_gem_object_free, 3835ca02815Sjsg .open = amdgpu_gem_object_open, 3845ca02815Sjsg .close = amdgpu_gem_object_close, 3855ca02815Sjsg .export = amdgpu_gem_prime_export, 3865ca02815Sjsg .vmap = drm_gem_ttm_vmap, 3875ca02815Sjsg .vunmap = drm_gem_ttm_vunmap, 3885ca02815Sjsg .mmap = amdgpu_gem_object_mmap, 3895ca02815Sjsg .vm_ops = &amdgpu_gem_vm_ops, 3905ca02815Sjsg }; 3915ca02815Sjsg 392fb4d8502Sjsg /* 393fb4d8502Sjsg * GEM ioctls. 394fb4d8502Sjsg */ 395fb4d8502Sjsg int amdgpu_gem_create_ioctl(struct drm_device *dev, void *data, 396fb4d8502Sjsg struct drm_file *filp) 397fb4d8502Sjsg { 398ad8b1aafSjsg struct amdgpu_device *adev = drm_to_adev(dev); 399fb4d8502Sjsg struct amdgpu_fpriv *fpriv = filp->driver_priv; 400fb4d8502Sjsg struct amdgpu_vm *vm = &fpriv->vm; 401fb4d8502Sjsg union drm_amdgpu_gem_create *args = data; 402fb4d8502Sjsg uint64_t flags = args->in.domain_flags; 403fb4d8502Sjsg uint64_t size = args->in.bo_size; 404c349dbc7Sjsg struct dma_resv *resv = NULL; 405fb4d8502Sjsg struct drm_gem_object *gobj; 406ad8b1aafSjsg uint32_t handle, initial_domain; 407fb4d8502Sjsg int r; 408fb4d8502Sjsg 409f005ef32Sjsg /* reject DOORBELLs until userspace code to use it is available */ 410f005ef32Sjsg if (args->in.domains & AMDGPU_GEM_DOMAIN_DOORBELL) 411f005ef32Sjsg return -EINVAL; 412f005ef32Sjsg 413fb4d8502Sjsg /* reject invalid gem flags */ 414fb4d8502Sjsg if (flags & ~(AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED | 415fb4d8502Sjsg AMDGPU_GEM_CREATE_NO_CPU_ACCESS | 416fb4d8502Sjsg AMDGPU_GEM_CREATE_CPU_GTT_USWC | 417fb4d8502Sjsg AMDGPU_GEM_CREATE_VRAM_CLEARED | 418fb4d8502Sjsg AMDGPU_GEM_CREATE_VM_ALWAYS_VALID | 419ad8b1aafSjsg AMDGPU_GEM_CREATE_EXPLICIT_SYNC | 4201bb76ff1Sjsg AMDGPU_GEM_CREATE_ENCRYPTED | 4211bb76ff1Sjsg AMDGPU_GEM_CREATE_DISCARDABLE)) 422fb4d8502Sjsg return -EINVAL; 423fb4d8502Sjsg 424fb4d8502Sjsg /* reject invalid gem domains */ 425fb4d8502Sjsg if (args->in.domains & ~AMDGPU_GEM_DOMAIN_MASK) 426fb4d8502Sjsg return -EINVAL; 427fb4d8502Sjsg 428ad8b1aafSjsg if (!amdgpu_is_tmz(adev) && (flags & AMDGPU_GEM_CREATE_ENCRYPTED)) { 429ad8b1aafSjsg DRM_NOTE_ONCE("Cannot allocate secure buffer since TMZ is disabled\n"); 430ad8b1aafSjsg return -EINVAL; 431ad8b1aafSjsg } 432ad8b1aafSjsg 433fb4d8502Sjsg /* create a gem object to contain this object in */ 434fb4d8502Sjsg if (args->in.domains & (AMDGPU_GEM_DOMAIN_GDS | 435fb4d8502Sjsg AMDGPU_GEM_DOMAIN_GWS | AMDGPU_GEM_DOMAIN_OA)) { 436fb4d8502Sjsg if (flags & AMDGPU_GEM_CREATE_VM_ALWAYS_VALID) { 437fb4d8502Sjsg /* if gds bo is created from user space, it must be 438fb4d8502Sjsg * passed to bo list 439fb4d8502Sjsg */ 440fb4d8502Sjsg DRM_ERROR("GDS bo cannot be per-vm-bo\n"); 441fb4d8502Sjsg return -EINVAL; 442fb4d8502Sjsg } 443fb4d8502Sjsg flags |= AMDGPU_GEM_CREATE_NO_CPU_ACCESS; 444fb4d8502Sjsg } 445fb4d8502Sjsg 446fb4d8502Sjsg if (flags & AMDGPU_GEM_CREATE_VM_ALWAYS_VALID) { 4475ca02815Sjsg r = amdgpu_bo_reserve(vm->root.bo, false); 448fb4d8502Sjsg if (r) 449fb4d8502Sjsg return r; 450fb4d8502Sjsg 4515ca02815Sjsg resv = vm->root.bo->tbo.base.resv; 452fb4d8502Sjsg } 453fb4d8502Sjsg 454ad8b1aafSjsg initial_domain = (u32)(0xffffffff & args->in.domains); 4555ca02815Sjsg retry: 456fb4d8502Sjsg r = amdgpu_gem_object_create(adev, size, args->in.alignment, 457ad8b1aafSjsg initial_domain, 458f005ef32Sjsg flags, ttm_bo_type_device, resv, &gobj, fpriv->xcp_id + 1); 4595ca02815Sjsg if (r && r != -ERESTARTSYS) { 460ad8b1aafSjsg if (flags & AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED) { 461ad8b1aafSjsg flags &= ~AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED; 462ad8b1aafSjsg goto retry; 463ad8b1aafSjsg } 464ad8b1aafSjsg 465ad8b1aafSjsg if (initial_domain == AMDGPU_GEM_DOMAIN_VRAM) { 466ad8b1aafSjsg initial_domain |= AMDGPU_GEM_DOMAIN_GTT; 467ad8b1aafSjsg goto retry; 468ad8b1aafSjsg } 469ad8b1aafSjsg DRM_DEBUG("Failed to allocate GEM object (%llu, %d, %llu, %d)\n", 470ad8b1aafSjsg size, initial_domain, args->in.alignment, r); 471ad8b1aafSjsg } 472ad8b1aafSjsg 473fb4d8502Sjsg if (flags & AMDGPU_GEM_CREATE_VM_ALWAYS_VALID) { 474fb4d8502Sjsg if (!r) { 475fb4d8502Sjsg struct amdgpu_bo *abo = gem_to_amdgpu_bo(gobj); 476fb4d8502Sjsg 4775ca02815Sjsg abo->parent = amdgpu_bo_ref(vm->root.bo); 478fb4d8502Sjsg } 4795ca02815Sjsg amdgpu_bo_unreserve(vm->root.bo); 480fb4d8502Sjsg } 481fb4d8502Sjsg if (r) 482fb4d8502Sjsg return r; 483fb4d8502Sjsg 484fb4d8502Sjsg r = drm_gem_handle_create(filp, gobj, &handle); 485fb4d8502Sjsg /* drop reference from allocate - handle holds it now */ 486ad8b1aafSjsg drm_gem_object_put(gobj); 487fb4d8502Sjsg if (r) 488fb4d8502Sjsg return r; 489fb4d8502Sjsg 490fb4d8502Sjsg memset(args, 0, sizeof(*args)); 491fb4d8502Sjsg args->out.handle = handle; 492fb4d8502Sjsg return 0; 493fb4d8502Sjsg } 494fb4d8502Sjsg 495fb4d8502Sjsg int amdgpu_gem_userptr_ioctl(struct drm_device *dev, void *data, 496fb4d8502Sjsg struct drm_file *filp) 497fb4d8502Sjsg { 498fb4d8502Sjsg return -ENOSYS; 499c349dbc7Sjsg #ifdef notyet 500fb4d8502Sjsg struct ttm_operation_ctx ctx = { true, false }; 501ad8b1aafSjsg struct amdgpu_device *adev = drm_to_adev(dev); 502fb4d8502Sjsg struct drm_amdgpu_gem_userptr *args = data; 503f005ef32Sjsg struct amdgpu_fpriv *fpriv = filp->driver_priv; 504fb4d8502Sjsg struct drm_gem_object *gobj; 5051bb76ff1Sjsg struct hmm_range *range; 506fb4d8502Sjsg struct amdgpu_bo *bo; 507fb4d8502Sjsg uint32_t handle; 508fb4d8502Sjsg int r; 509fb4d8502Sjsg 510c349dbc7Sjsg args->addr = untagged_addr(args->addr); 511c349dbc7Sjsg 512fb4d8502Sjsg if (offset_in_page(args->addr | args->size)) 513fb4d8502Sjsg return -EINVAL; 514fb4d8502Sjsg 515fb4d8502Sjsg /* reject unknown flag values */ 516fb4d8502Sjsg if (args->flags & ~(AMDGPU_GEM_USERPTR_READONLY | 517fb4d8502Sjsg AMDGPU_GEM_USERPTR_ANONONLY | AMDGPU_GEM_USERPTR_VALIDATE | 518fb4d8502Sjsg AMDGPU_GEM_USERPTR_REGISTER)) 519fb4d8502Sjsg return -EINVAL; 520fb4d8502Sjsg 521fb4d8502Sjsg if (!(args->flags & AMDGPU_GEM_USERPTR_READONLY) && 522fb4d8502Sjsg !(args->flags & AMDGPU_GEM_USERPTR_REGISTER)) { 523fb4d8502Sjsg 524fb4d8502Sjsg /* if we want to write to it we must install a MMU notifier */ 525fb4d8502Sjsg return -EACCES; 526fb4d8502Sjsg } 527fb4d8502Sjsg 528fb4d8502Sjsg /* create a gem object to contain this object in */ 529fb4d8502Sjsg r = amdgpu_gem_object_create(adev, args->size, 0, AMDGPU_GEM_DOMAIN_CPU, 530f005ef32Sjsg 0, ttm_bo_type_device, NULL, &gobj, fpriv->xcp_id + 1); 531fb4d8502Sjsg if (r) 532fb4d8502Sjsg return r; 533fb4d8502Sjsg 534fb4d8502Sjsg bo = gem_to_amdgpu_bo(gobj); 535fb4d8502Sjsg bo->preferred_domains = AMDGPU_GEM_DOMAIN_GTT; 536fb4d8502Sjsg bo->allowed_domains = AMDGPU_GEM_DOMAIN_GTT; 537ad8b1aafSjsg r = amdgpu_ttm_tt_set_userptr(&bo->tbo, args->addr, args->flags); 538fb4d8502Sjsg if (r) 539fb4d8502Sjsg goto release_object; 540fb4d8502Sjsg 541f005ef32Sjsg r = amdgpu_hmm_register(bo, args->addr); 542fb4d8502Sjsg if (r) 543fb4d8502Sjsg goto release_object; 544fb4d8502Sjsg 545fb4d8502Sjsg if (args->flags & AMDGPU_GEM_USERPTR_VALIDATE) { 5461bb76ff1Sjsg r = amdgpu_ttm_tt_get_user_pages(bo, bo->tbo.ttm->pages, 5471bb76ff1Sjsg &range); 548fb4d8502Sjsg if (r) 549fb4d8502Sjsg goto release_object; 550fb4d8502Sjsg 551fb4d8502Sjsg r = amdgpu_bo_reserve(bo, true); 552fb4d8502Sjsg if (r) 553c349dbc7Sjsg goto user_pages_done; 554fb4d8502Sjsg 555fb4d8502Sjsg amdgpu_bo_placement_from_domain(bo, AMDGPU_GEM_DOMAIN_GTT); 556fb4d8502Sjsg r = ttm_bo_validate(&bo->tbo, &bo->placement, &ctx); 557fb4d8502Sjsg amdgpu_bo_unreserve(bo); 558fb4d8502Sjsg if (r) 559c349dbc7Sjsg goto user_pages_done; 560fb4d8502Sjsg } 561fb4d8502Sjsg 562fb4d8502Sjsg r = drm_gem_handle_create(filp, gobj, &handle); 563fb4d8502Sjsg if (r) 564c349dbc7Sjsg goto user_pages_done; 565fb4d8502Sjsg 566fb4d8502Sjsg args->handle = handle; 567fb4d8502Sjsg 568c349dbc7Sjsg user_pages_done: 569c349dbc7Sjsg if (args->flags & AMDGPU_GEM_USERPTR_VALIDATE) 5701bb76ff1Sjsg amdgpu_ttm_tt_get_user_pages_done(bo->tbo.ttm, range); 571fb4d8502Sjsg 572fb4d8502Sjsg release_object: 573ad8b1aafSjsg drm_gem_object_put(gobj); 574fb4d8502Sjsg 575fb4d8502Sjsg return r; 576fb4d8502Sjsg #endif 577fb4d8502Sjsg } 578fb4d8502Sjsg 579fb4d8502Sjsg int amdgpu_mode_dumb_mmap(struct drm_file *filp, 580fb4d8502Sjsg struct drm_device *dev, 581fb4d8502Sjsg uint32_t handle, uint64_t *offset_p) 582fb4d8502Sjsg { 583fb4d8502Sjsg struct drm_gem_object *gobj; 584fb4d8502Sjsg struct amdgpu_bo *robj; 585fb4d8502Sjsg 586fb4d8502Sjsg gobj = drm_gem_object_lookup(filp, handle); 587f005ef32Sjsg if (!gobj) 588fb4d8502Sjsg return -ENOENT; 589f005ef32Sjsg 590fb4d8502Sjsg robj = gem_to_amdgpu_bo(gobj); 591fb4d8502Sjsg if (amdgpu_ttm_tt_get_usermm(robj->tbo.ttm) || 592fb4d8502Sjsg (robj->flags & AMDGPU_GEM_CREATE_NO_CPU_ACCESS)) { 593ad8b1aafSjsg drm_gem_object_put(gobj); 594fb4d8502Sjsg return -EPERM; 595fb4d8502Sjsg } 596fb4d8502Sjsg *offset_p = amdgpu_bo_mmap_offset(robj); 597ad8b1aafSjsg drm_gem_object_put(gobj); 598fb4d8502Sjsg return 0; 599fb4d8502Sjsg } 600fb4d8502Sjsg 601fb4d8502Sjsg int amdgpu_gem_mmap_ioctl(struct drm_device *dev, void *data, 602fb4d8502Sjsg struct drm_file *filp) 603fb4d8502Sjsg { 604fb4d8502Sjsg union drm_amdgpu_gem_mmap *args = data; 605fb4d8502Sjsg uint32_t handle = args->in.handle; 606f005ef32Sjsg 607fb4d8502Sjsg memset(args, 0, sizeof(*args)); 608fb4d8502Sjsg return amdgpu_mode_dumb_mmap(filp, dev, handle, &args->out.addr_ptr); 609fb4d8502Sjsg } 610fb4d8502Sjsg 611fb4d8502Sjsg /** 612fb4d8502Sjsg * amdgpu_gem_timeout - calculate jiffies timeout from absolute value 613fb4d8502Sjsg * 614fb4d8502Sjsg * @timeout_ns: timeout in ns 615fb4d8502Sjsg * 616fb4d8502Sjsg * Calculate the timeout in jiffies from an absolute timeout in ns. 617fb4d8502Sjsg */ 618fb4d8502Sjsg unsigned long amdgpu_gem_timeout(uint64_t timeout_ns) 619fb4d8502Sjsg { 620fb4d8502Sjsg unsigned long timeout_jiffies; 621fb4d8502Sjsg ktime_t timeout; 622fb4d8502Sjsg 623fb4d8502Sjsg /* clamp timeout if it's to large */ 624fb4d8502Sjsg if (((int64_t)timeout_ns) < 0) 625fb4d8502Sjsg return MAX_SCHEDULE_TIMEOUT; 626fb4d8502Sjsg 627fb4d8502Sjsg timeout = ktime_sub(ns_to_ktime(timeout_ns), ktime_get()); 628fb4d8502Sjsg if (ktime_to_ns(timeout) < 0) 629fb4d8502Sjsg return 0; 630fb4d8502Sjsg 631fb4d8502Sjsg timeout_jiffies = nsecs_to_jiffies(ktime_to_ns(timeout)); 632fb4d8502Sjsg /* clamp timeout to avoid unsigned-> signed overflow */ 633fb4d8502Sjsg if (timeout_jiffies > MAX_SCHEDULE_TIMEOUT) 634fb4d8502Sjsg return MAX_SCHEDULE_TIMEOUT - 1; 635fb4d8502Sjsg 636fb4d8502Sjsg return timeout_jiffies; 637fb4d8502Sjsg } 638fb4d8502Sjsg 639fb4d8502Sjsg int amdgpu_gem_wait_idle_ioctl(struct drm_device *dev, void *data, 640fb4d8502Sjsg struct drm_file *filp) 641fb4d8502Sjsg { 642fb4d8502Sjsg union drm_amdgpu_gem_wait_idle *args = data; 643fb4d8502Sjsg struct drm_gem_object *gobj; 644fb4d8502Sjsg struct amdgpu_bo *robj; 645fb4d8502Sjsg uint32_t handle = args->in.handle; 646fb4d8502Sjsg unsigned long timeout = amdgpu_gem_timeout(args->in.timeout); 647fb4d8502Sjsg int r = 0; 648fb4d8502Sjsg long ret; 649fb4d8502Sjsg 650fb4d8502Sjsg gobj = drm_gem_object_lookup(filp, handle); 651f005ef32Sjsg if (!gobj) 652fb4d8502Sjsg return -ENOENT; 653f005ef32Sjsg 654fb4d8502Sjsg robj = gem_to_amdgpu_bo(gobj); 6551bb76ff1Sjsg ret = dma_resv_wait_timeout(robj->tbo.base.resv, DMA_RESV_USAGE_READ, 6561bb76ff1Sjsg true, timeout); 657fb4d8502Sjsg 658fb4d8502Sjsg /* ret == 0 means not signaled, 659fb4d8502Sjsg * ret > 0 means signaled 660fb4d8502Sjsg * ret < 0 means interrupted before timeout 661fb4d8502Sjsg */ 662fb4d8502Sjsg if (ret >= 0) { 663fb4d8502Sjsg memset(args, 0, sizeof(*args)); 664fb4d8502Sjsg args->out.status = (ret == 0); 665fb4d8502Sjsg } else 666fb4d8502Sjsg r = ret; 667fb4d8502Sjsg 668ad8b1aafSjsg drm_gem_object_put(gobj); 669fb4d8502Sjsg return r; 670fb4d8502Sjsg } 671fb4d8502Sjsg 672fb4d8502Sjsg int amdgpu_gem_metadata_ioctl(struct drm_device *dev, void *data, 673fb4d8502Sjsg struct drm_file *filp) 674fb4d8502Sjsg { 675fb4d8502Sjsg struct drm_amdgpu_gem_metadata *args = data; 676fb4d8502Sjsg struct drm_gem_object *gobj; 677fb4d8502Sjsg struct amdgpu_bo *robj; 678fb4d8502Sjsg int r = -1; 679fb4d8502Sjsg 680fb4d8502Sjsg DRM_DEBUG("%d\n", args->handle); 681fb4d8502Sjsg gobj = drm_gem_object_lookup(filp, args->handle); 682fb4d8502Sjsg if (gobj == NULL) 683fb4d8502Sjsg return -ENOENT; 684fb4d8502Sjsg robj = gem_to_amdgpu_bo(gobj); 685fb4d8502Sjsg 686fb4d8502Sjsg r = amdgpu_bo_reserve(robj, false); 687fb4d8502Sjsg if (unlikely(r != 0)) 688fb4d8502Sjsg goto out; 689fb4d8502Sjsg 690fb4d8502Sjsg if (args->op == AMDGPU_GEM_METADATA_OP_GET_METADATA) { 691fb4d8502Sjsg amdgpu_bo_get_tiling_flags(robj, &args->data.tiling_info); 692fb4d8502Sjsg r = amdgpu_bo_get_metadata(robj, args->data.data, 693fb4d8502Sjsg sizeof(args->data.data), 694fb4d8502Sjsg &args->data.data_size_bytes, 695fb4d8502Sjsg &args->data.flags); 696fb4d8502Sjsg } else if (args->op == AMDGPU_GEM_METADATA_OP_SET_METADATA) { 697fb4d8502Sjsg if (args->data.data_size_bytes > sizeof(args->data.data)) { 698fb4d8502Sjsg r = -EINVAL; 699fb4d8502Sjsg goto unreserve; 700fb4d8502Sjsg } 701fb4d8502Sjsg r = amdgpu_bo_set_tiling_flags(robj, args->data.tiling_info); 702fb4d8502Sjsg if (!r) 703fb4d8502Sjsg r = amdgpu_bo_set_metadata(robj, args->data.data, 704fb4d8502Sjsg args->data.data_size_bytes, 705fb4d8502Sjsg args->data.flags); 706fb4d8502Sjsg } 707fb4d8502Sjsg 708fb4d8502Sjsg unreserve: 709fb4d8502Sjsg amdgpu_bo_unreserve(robj); 710fb4d8502Sjsg out: 711ad8b1aafSjsg drm_gem_object_put(gobj); 712fb4d8502Sjsg return r; 713fb4d8502Sjsg } 714fb4d8502Sjsg 715fb4d8502Sjsg /** 716fb4d8502Sjsg * amdgpu_gem_va_update_vm -update the bo_va in its VM 717fb4d8502Sjsg * 718fb4d8502Sjsg * @adev: amdgpu_device pointer 719fb4d8502Sjsg * @vm: vm to update 720fb4d8502Sjsg * @bo_va: bo_va to update 721fb4d8502Sjsg * @operation: map, unmap or clear 722fb4d8502Sjsg * 723fb4d8502Sjsg * Update the bo_va directly after setting its address. Errors are not 724fb4d8502Sjsg * vital here, so they are not reported back to userspace. 725fb4d8502Sjsg */ 726fb4d8502Sjsg static void amdgpu_gem_va_update_vm(struct amdgpu_device *adev, 727fb4d8502Sjsg struct amdgpu_vm *vm, 728fb4d8502Sjsg struct amdgpu_bo_va *bo_va, 729fb4d8502Sjsg uint32_t operation) 730fb4d8502Sjsg { 731fb4d8502Sjsg int r; 732fb4d8502Sjsg 733fb4d8502Sjsg if (!amdgpu_vm_ready(vm)) 734fb4d8502Sjsg return; 735fb4d8502Sjsg 736fb4d8502Sjsg r = amdgpu_vm_clear_freed(adev, vm, NULL); 737fb4d8502Sjsg if (r) 738fb4d8502Sjsg goto error; 739fb4d8502Sjsg 740fb4d8502Sjsg if (operation == AMDGPU_VA_OP_MAP || 741fb4d8502Sjsg operation == AMDGPU_VA_OP_REPLACE) { 7421bb76ff1Sjsg r = amdgpu_vm_bo_update(adev, bo_va, false); 743fb4d8502Sjsg if (r) 744fb4d8502Sjsg goto error; 745fb4d8502Sjsg } 746fb4d8502Sjsg 747c349dbc7Sjsg r = amdgpu_vm_update_pdes(adev, vm, false); 748fb4d8502Sjsg 749fb4d8502Sjsg error: 750fb4d8502Sjsg if (r && r != -ERESTARTSYS) 751fb4d8502Sjsg DRM_ERROR("Couldn't update BO_VA (%d)\n", r); 752fb4d8502Sjsg } 753fb4d8502Sjsg 754c349dbc7Sjsg /** 755c349dbc7Sjsg * amdgpu_gem_va_map_flags - map GEM UAPI flags into hardware flags 756c349dbc7Sjsg * 757c349dbc7Sjsg * @adev: amdgpu_device pointer 758c349dbc7Sjsg * @flags: GEM UAPI flags 759c349dbc7Sjsg * 760c349dbc7Sjsg * Returns the GEM UAPI flags mapped into hardware for the ASIC. 761c349dbc7Sjsg */ 762c349dbc7Sjsg uint64_t amdgpu_gem_va_map_flags(struct amdgpu_device *adev, uint32_t flags) 763c349dbc7Sjsg { 764c349dbc7Sjsg uint64_t pte_flag = 0; 765c349dbc7Sjsg 766c349dbc7Sjsg if (flags & AMDGPU_VM_PAGE_EXECUTABLE) 767c349dbc7Sjsg pte_flag |= AMDGPU_PTE_EXECUTABLE; 768c349dbc7Sjsg if (flags & AMDGPU_VM_PAGE_READABLE) 769c349dbc7Sjsg pte_flag |= AMDGPU_PTE_READABLE; 770c349dbc7Sjsg if (flags & AMDGPU_VM_PAGE_WRITEABLE) 771c349dbc7Sjsg pte_flag |= AMDGPU_PTE_WRITEABLE; 772c349dbc7Sjsg if (flags & AMDGPU_VM_PAGE_PRT) 773c349dbc7Sjsg pte_flag |= AMDGPU_PTE_PRT; 7741bb76ff1Sjsg if (flags & AMDGPU_VM_PAGE_NOALLOC) 7751bb76ff1Sjsg pte_flag |= AMDGPU_PTE_NOALLOC; 776c349dbc7Sjsg 777c349dbc7Sjsg if (adev->gmc.gmc_funcs->map_mtype) 778c349dbc7Sjsg pte_flag |= amdgpu_gmc_map_mtype(adev, 779c349dbc7Sjsg flags & AMDGPU_VM_MTYPE_MASK); 780c349dbc7Sjsg 781c349dbc7Sjsg return pte_flag; 782c349dbc7Sjsg } 783c349dbc7Sjsg 784fb4d8502Sjsg int amdgpu_gem_va_ioctl(struct drm_device *dev, void *data, 785fb4d8502Sjsg struct drm_file *filp) 786fb4d8502Sjsg { 787fb4d8502Sjsg const uint32_t valid_flags = AMDGPU_VM_DELAY_UPDATE | 788fb4d8502Sjsg AMDGPU_VM_PAGE_READABLE | AMDGPU_VM_PAGE_WRITEABLE | 7891bb76ff1Sjsg AMDGPU_VM_PAGE_EXECUTABLE | AMDGPU_VM_MTYPE_MASK | 7901bb76ff1Sjsg AMDGPU_VM_PAGE_NOALLOC; 791fb4d8502Sjsg const uint32_t prt_flags = AMDGPU_VM_DELAY_UPDATE | 792fb4d8502Sjsg AMDGPU_VM_PAGE_PRT; 793fb4d8502Sjsg 794fb4d8502Sjsg struct drm_amdgpu_gem_va *args = data; 795fb4d8502Sjsg struct drm_gem_object *gobj; 796ad8b1aafSjsg struct amdgpu_device *adev = drm_to_adev(dev); 797fb4d8502Sjsg struct amdgpu_fpriv *fpriv = filp->driver_priv; 798fb4d8502Sjsg struct amdgpu_bo *abo; 799fb4d8502Sjsg struct amdgpu_bo_va *bo_va; 800f005ef32Sjsg struct drm_exec exec; 801fb4d8502Sjsg uint64_t va_flags; 802ad8b1aafSjsg uint64_t vm_size; 803fb4d8502Sjsg int r = 0; 804fb4d8502Sjsg 805fb4d8502Sjsg if (args->va_address < AMDGPU_VA_RESERVED_SIZE) { 8065ca02815Sjsg dev_dbg(dev->dev, 807f005ef32Sjsg "va_address 0x%llx is in reserved area 0x%llx\n", 808fb4d8502Sjsg args->va_address, AMDGPU_VA_RESERVED_SIZE); 809fb4d8502Sjsg return -EINVAL; 810fb4d8502Sjsg } 811fb4d8502Sjsg 812c349dbc7Sjsg if (args->va_address >= AMDGPU_GMC_HOLE_START && 813c349dbc7Sjsg args->va_address < AMDGPU_GMC_HOLE_END) { 8145ca02815Sjsg dev_dbg(dev->dev, 815f005ef32Sjsg "va_address 0x%llx is in VA hole 0x%llx-0x%llx\n", 816c349dbc7Sjsg args->va_address, AMDGPU_GMC_HOLE_START, 817c349dbc7Sjsg AMDGPU_GMC_HOLE_END); 818fb4d8502Sjsg return -EINVAL; 819fb4d8502Sjsg } 820fb4d8502Sjsg 821c349dbc7Sjsg args->va_address &= AMDGPU_GMC_HOLE_MASK; 822fb4d8502Sjsg 823ad8b1aafSjsg vm_size = adev->vm_manager.max_pfn * AMDGPU_GPU_PAGE_SIZE; 824ad8b1aafSjsg vm_size -= AMDGPU_VA_RESERVED_SIZE; 825ad8b1aafSjsg if (args->va_address + args->map_size > vm_size) { 8265ca02815Sjsg dev_dbg(dev->dev, 827ad8b1aafSjsg "va_address 0x%llx is in top reserved area 0x%llx\n", 828ad8b1aafSjsg args->va_address + args->map_size, vm_size); 829ad8b1aafSjsg return -EINVAL; 830ad8b1aafSjsg } 831ad8b1aafSjsg 832fb4d8502Sjsg if ((args->flags & ~valid_flags) && (args->flags & ~prt_flags)) { 8335ca02815Sjsg dev_dbg(dev->dev, "invalid flags combination 0x%08X\n", 834fb4d8502Sjsg args->flags); 835fb4d8502Sjsg return -EINVAL; 836fb4d8502Sjsg } 837fb4d8502Sjsg 838fb4d8502Sjsg switch (args->operation) { 839fb4d8502Sjsg case AMDGPU_VA_OP_MAP: 840fb4d8502Sjsg case AMDGPU_VA_OP_UNMAP: 841fb4d8502Sjsg case AMDGPU_VA_OP_CLEAR: 842fb4d8502Sjsg case AMDGPU_VA_OP_REPLACE: 843fb4d8502Sjsg break; 844fb4d8502Sjsg default: 8455ca02815Sjsg dev_dbg(dev->dev, "unsupported operation %d\n", 846fb4d8502Sjsg args->operation); 847fb4d8502Sjsg return -EINVAL; 848fb4d8502Sjsg } 849fb4d8502Sjsg 850fb4d8502Sjsg if ((args->operation != AMDGPU_VA_OP_CLEAR) && 851fb4d8502Sjsg !(args->flags & AMDGPU_VM_PAGE_PRT)) { 852fb4d8502Sjsg gobj = drm_gem_object_lookup(filp, args->handle); 853fb4d8502Sjsg if (gobj == NULL) 854fb4d8502Sjsg return -ENOENT; 855fb4d8502Sjsg abo = gem_to_amdgpu_bo(gobj); 856fb4d8502Sjsg } else { 857fb4d8502Sjsg gobj = NULL; 858fb4d8502Sjsg abo = NULL; 859fb4d8502Sjsg } 860fb4d8502Sjsg 861f005ef32Sjsg drm_exec_init(&exec, DRM_EXEC_INTERRUPTIBLE_WAIT | 862f005ef32Sjsg DRM_EXEC_IGNORE_DUPLICATES); 863f005ef32Sjsg drm_exec_until_all_locked(&exec) { 864f005ef32Sjsg if (gobj) { 865f005ef32Sjsg r = drm_exec_lock_obj(&exec, gobj); 866f005ef32Sjsg drm_exec_retry_on_contention(&exec); 867f005ef32Sjsg if (unlikely(r)) 868f005ef32Sjsg goto error; 869f005ef32Sjsg } 870fb4d8502Sjsg 871f005ef32Sjsg r = amdgpu_vm_lock_pd(&fpriv->vm, &exec, 2); 872f005ef32Sjsg drm_exec_retry_on_contention(&exec); 873f005ef32Sjsg if (unlikely(r)) 874f005ef32Sjsg goto error; 875f005ef32Sjsg } 876fb4d8502Sjsg 877fb4d8502Sjsg if (abo) { 878fb4d8502Sjsg bo_va = amdgpu_vm_bo_find(&fpriv->vm, abo); 879fb4d8502Sjsg if (!bo_va) { 880fb4d8502Sjsg r = -ENOENT; 881f005ef32Sjsg goto error; 882fb4d8502Sjsg } 883fb4d8502Sjsg } else if (args->operation != AMDGPU_VA_OP_CLEAR) { 884fb4d8502Sjsg bo_va = fpriv->prt_va; 885fb4d8502Sjsg } else { 886fb4d8502Sjsg bo_va = NULL; 887fb4d8502Sjsg } 888fb4d8502Sjsg 889fb4d8502Sjsg switch (args->operation) { 890fb4d8502Sjsg case AMDGPU_VA_OP_MAP: 891c349dbc7Sjsg va_flags = amdgpu_gem_va_map_flags(adev, args->flags); 892fb4d8502Sjsg r = amdgpu_vm_bo_map(adev, bo_va, args->va_address, 893fb4d8502Sjsg args->offset_in_bo, args->map_size, 894fb4d8502Sjsg va_flags); 895fb4d8502Sjsg break; 896fb4d8502Sjsg case AMDGPU_VA_OP_UNMAP: 897fb4d8502Sjsg r = amdgpu_vm_bo_unmap(adev, bo_va, args->va_address); 898fb4d8502Sjsg break; 899fb4d8502Sjsg 900fb4d8502Sjsg case AMDGPU_VA_OP_CLEAR: 901fb4d8502Sjsg r = amdgpu_vm_bo_clear_mappings(adev, &fpriv->vm, 902fb4d8502Sjsg args->va_address, 903fb4d8502Sjsg args->map_size); 904fb4d8502Sjsg break; 905fb4d8502Sjsg case AMDGPU_VA_OP_REPLACE: 906c349dbc7Sjsg va_flags = amdgpu_gem_va_map_flags(adev, args->flags); 907fb4d8502Sjsg r = amdgpu_vm_bo_replace_map(adev, bo_va, args->va_address, 908fb4d8502Sjsg args->offset_in_bo, args->map_size, 909fb4d8502Sjsg va_flags); 910fb4d8502Sjsg break; 911fb4d8502Sjsg default: 912fb4d8502Sjsg break; 913fb4d8502Sjsg } 914fb4d8502Sjsg if (!r && !(args->flags & AMDGPU_VM_DELAY_UPDATE) && !amdgpu_vm_debug) 915fb4d8502Sjsg amdgpu_gem_va_update_vm(adev, &fpriv->vm, bo_va, 916fb4d8502Sjsg args->operation); 917fb4d8502Sjsg 918f005ef32Sjsg error: 919f005ef32Sjsg drm_exec_fini(&exec); 920ad8b1aafSjsg drm_gem_object_put(gobj); 921fb4d8502Sjsg return r; 922fb4d8502Sjsg } 923fb4d8502Sjsg 924fb4d8502Sjsg int amdgpu_gem_op_ioctl(struct drm_device *dev, void *data, 925fb4d8502Sjsg struct drm_file *filp) 926fb4d8502Sjsg { 927ad8b1aafSjsg struct amdgpu_device *adev = drm_to_adev(dev); 928fb4d8502Sjsg struct drm_amdgpu_gem_op *args = data; 929fb4d8502Sjsg struct drm_gem_object *gobj; 930c349dbc7Sjsg struct amdgpu_vm_bo_base *base; 931fb4d8502Sjsg struct amdgpu_bo *robj; 932fb4d8502Sjsg int r; 933fb4d8502Sjsg 934fb4d8502Sjsg gobj = drm_gem_object_lookup(filp, args->handle); 935f005ef32Sjsg if (!gobj) 936fb4d8502Sjsg return -ENOENT; 937f005ef32Sjsg 938fb4d8502Sjsg robj = gem_to_amdgpu_bo(gobj); 939fb4d8502Sjsg 940fb4d8502Sjsg r = amdgpu_bo_reserve(robj, false); 941fb4d8502Sjsg if (unlikely(r)) 942fb4d8502Sjsg goto out; 943fb4d8502Sjsg 944fb4d8502Sjsg switch (args->op) { 945fb4d8502Sjsg case AMDGPU_GEM_OP_GET_GEM_CREATE_INFO: { 946fb4d8502Sjsg struct drm_amdgpu_gem_create_in info; 947fb4d8502Sjsg void __user *out = u64_to_user_ptr(args->value); 948fb4d8502Sjsg 949c349dbc7Sjsg info.bo_size = robj->tbo.base.size; 9505ca02815Sjsg info.alignment = robj->tbo.page_alignment << PAGE_SHIFT; 951fb4d8502Sjsg info.domains = robj->preferred_domains; 952fb4d8502Sjsg info.domain_flags = robj->flags; 953fb4d8502Sjsg amdgpu_bo_unreserve(robj); 954fb4d8502Sjsg if (copy_to_user(out, &info, sizeof(info))) 955fb4d8502Sjsg r = -EFAULT; 956fb4d8502Sjsg break; 957fb4d8502Sjsg } 958fb4d8502Sjsg case AMDGPU_GEM_OP_SET_PLACEMENT: 9595ca02815Sjsg if (robj->tbo.base.import_attach && 9605ca02815Sjsg args->value & AMDGPU_GEM_DOMAIN_VRAM) { 961fb4d8502Sjsg r = -EINVAL; 962fb4d8502Sjsg amdgpu_bo_unreserve(robj); 963fb4d8502Sjsg break; 964fb4d8502Sjsg } 965fb4d8502Sjsg if (amdgpu_ttm_tt_get_usermm(robj->tbo.ttm)) { 966fb4d8502Sjsg r = -EPERM; 967fb4d8502Sjsg amdgpu_bo_unreserve(robj); 968fb4d8502Sjsg break; 969fb4d8502Sjsg } 970c349dbc7Sjsg for (base = robj->vm_bo; base; base = base->next) 971c349dbc7Sjsg if (amdgpu_xgmi_same_hive(amdgpu_ttm_adev(robj->tbo.bdev), 9725ca02815Sjsg amdgpu_ttm_adev(base->vm->root.bo->tbo.bdev))) { 973c349dbc7Sjsg r = -EINVAL; 974c349dbc7Sjsg amdgpu_bo_unreserve(robj); 975c349dbc7Sjsg goto out; 976c349dbc7Sjsg } 977c349dbc7Sjsg 978c349dbc7Sjsg 979fb4d8502Sjsg robj->preferred_domains = args->value & (AMDGPU_GEM_DOMAIN_VRAM | 980fb4d8502Sjsg AMDGPU_GEM_DOMAIN_GTT | 981fb4d8502Sjsg AMDGPU_GEM_DOMAIN_CPU); 982fb4d8502Sjsg robj->allowed_domains = robj->preferred_domains; 983fb4d8502Sjsg if (robj->allowed_domains == AMDGPU_GEM_DOMAIN_VRAM) 984fb4d8502Sjsg robj->allowed_domains |= AMDGPU_GEM_DOMAIN_GTT; 985fb4d8502Sjsg 986fb4d8502Sjsg if (robj->flags & AMDGPU_GEM_CREATE_VM_ALWAYS_VALID) 987fb4d8502Sjsg amdgpu_vm_bo_invalidate(adev, robj, true); 988fb4d8502Sjsg 989fb4d8502Sjsg amdgpu_bo_unreserve(robj); 990fb4d8502Sjsg break; 991fb4d8502Sjsg default: 992fb4d8502Sjsg amdgpu_bo_unreserve(robj); 993fb4d8502Sjsg r = -EINVAL; 994fb4d8502Sjsg } 995fb4d8502Sjsg 996fb4d8502Sjsg out: 997ad8b1aafSjsg drm_gem_object_put(gobj); 998fb4d8502Sjsg return r; 999fb4d8502Sjsg } 1000fb4d8502Sjsg 10011bb76ff1Sjsg static int amdgpu_gem_align_pitch(struct amdgpu_device *adev, 10021bb76ff1Sjsg int width, 10031bb76ff1Sjsg int cpp, 10041bb76ff1Sjsg bool tiled) 10051bb76ff1Sjsg { 10061bb76ff1Sjsg int aligned = width; 10071bb76ff1Sjsg int pitch_mask = 0; 10081bb76ff1Sjsg 10091bb76ff1Sjsg switch (cpp) { 10101bb76ff1Sjsg case 1: 10111bb76ff1Sjsg pitch_mask = 255; 10121bb76ff1Sjsg break; 10131bb76ff1Sjsg case 2: 10141bb76ff1Sjsg pitch_mask = 127; 10151bb76ff1Sjsg break; 10161bb76ff1Sjsg case 3: 10171bb76ff1Sjsg case 4: 10181bb76ff1Sjsg pitch_mask = 63; 10191bb76ff1Sjsg break; 10201bb76ff1Sjsg } 10211bb76ff1Sjsg 10221bb76ff1Sjsg aligned += pitch_mask; 10231bb76ff1Sjsg aligned &= ~pitch_mask; 10241bb76ff1Sjsg return aligned * cpp; 10251bb76ff1Sjsg } 10261bb76ff1Sjsg 1027fb4d8502Sjsg int amdgpu_mode_dumb_create(struct drm_file *file_priv, 1028fb4d8502Sjsg struct drm_device *dev, 1029fb4d8502Sjsg struct drm_mode_create_dumb *args) 1030fb4d8502Sjsg { 1031ad8b1aafSjsg struct amdgpu_device *adev = drm_to_adev(dev); 1032f005ef32Sjsg struct amdgpu_fpriv *fpriv = file_priv->driver_priv; 1033fb4d8502Sjsg struct drm_gem_object *gobj; 1034fb4d8502Sjsg uint32_t handle; 1035c349dbc7Sjsg u64 flags = AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED | 10361bb76ff1Sjsg AMDGPU_GEM_CREATE_CPU_GTT_USWC | 10371bb76ff1Sjsg AMDGPU_GEM_CREATE_VRAM_CONTIGUOUS; 1038fb4d8502Sjsg u32 domain; 1039fb4d8502Sjsg int r; 1040fb4d8502Sjsg 1041c349dbc7Sjsg /* 1042c349dbc7Sjsg * The buffer returned from this function should be cleared, but 1043c349dbc7Sjsg * it can only be done if the ring is enabled or we'll fail to 1044c349dbc7Sjsg * create the buffer. 1045c349dbc7Sjsg */ 1046c349dbc7Sjsg if (adev->mman.buffer_funcs_enabled) 1047c349dbc7Sjsg flags |= AMDGPU_GEM_CREATE_VRAM_CLEARED; 1048c349dbc7Sjsg 10491bb76ff1Sjsg args->pitch = amdgpu_gem_align_pitch(adev, args->width, 1050fb4d8502Sjsg DIV_ROUND_UP(args->bpp, 8), 0); 1051fb4d8502Sjsg args->size = (u64)args->pitch * args->height; 1052f005ef32Sjsg args->size = ALIGN(args->size, PAGE_SIZE); 10535ca02815Sjsg domain = amdgpu_bo_get_preferred_domain(adev, 1054c349dbc7Sjsg amdgpu_display_supported_domains(adev, flags)); 1055c349dbc7Sjsg r = amdgpu_gem_object_create(adev, args->size, 0, domain, flags, 1056f005ef32Sjsg ttm_bo_type_device, NULL, &gobj, fpriv->xcp_id + 1); 1057fb4d8502Sjsg if (r) 1058fb4d8502Sjsg return -ENOMEM; 1059fb4d8502Sjsg 1060fb4d8502Sjsg r = drm_gem_handle_create(file_priv, gobj, &handle); 1061fb4d8502Sjsg /* drop reference from allocate - handle holds it now */ 1062ad8b1aafSjsg drm_gem_object_put(gobj); 1063f005ef32Sjsg if (r) 1064fb4d8502Sjsg return r; 1065f005ef32Sjsg 1066fb4d8502Sjsg args->handle = handle; 1067fb4d8502Sjsg return 0; 1068fb4d8502Sjsg } 1069fb4d8502Sjsg 1070fb4d8502Sjsg #if defined(CONFIG_DEBUG_FS) 10715ca02815Sjsg static int amdgpu_debugfs_gem_info_show(struct seq_file *m, void *unused) 1072fb4d8502Sjsg { 1073f005ef32Sjsg struct amdgpu_device *adev = m->private; 10745ca02815Sjsg struct drm_device *dev = adev_to_drm(adev); 1075fb4d8502Sjsg struct drm_file *file; 1076fb4d8502Sjsg int r; 1077fb4d8502Sjsg 1078fb4d8502Sjsg r = mutex_lock_interruptible(&dev->filelist_mutex); 1079fb4d8502Sjsg if (r) 1080fb4d8502Sjsg return r; 1081fb4d8502Sjsg 1082fb4d8502Sjsg list_for_each_entry(file, &dev->filelist, lhead) { 1083fb4d8502Sjsg struct task_struct *task; 10845ca02815Sjsg struct drm_gem_object *gobj; 1085f005ef32Sjsg struct pid *pid; 10865ca02815Sjsg int id; 1087fb4d8502Sjsg 1088fb4d8502Sjsg /* 1089fb4d8502Sjsg * Although we have a valid reference on file->pid, that does 1090fb4d8502Sjsg * not guarantee that the task_struct who called get_pid() is 1091fb4d8502Sjsg * still alive (e.g. get_pid(current) => fork() => exit()). 1092fb4d8502Sjsg * Therefore, we need to protect this ->comm access using RCU. 1093fb4d8502Sjsg */ 1094fb4d8502Sjsg rcu_read_lock(); 1095f005ef32Sjsg pid = rcu_dereference(file->pid); 1096f005ef32Sjsg task = pid_task(pid, PIDTYPE_TGID); 1097f005ef32Sjsg seq_printf(m, "pid %8d command %s:\n", pid_nr(pid), 1098fb4d8502Sjsg task ? task->comm : "<unknown>"); 1099fb4d8502Sjsg rcu_read_unlock(); 1100fb4d8502Sjsg 1101fb4d8502Sjsg spin_lock(&file->table_lock); 11025ca02815Sjsg idr_for_each_entry(&file->object_idr, gobj, id) { 11035ca02815Sjsg struct amdgpu_bo *bo = gem_to_amdgpu_bo(gobj); 11045ca02815Sjsg 11055ca02815Sjsg amdgpu_bo_print_info(id, bo, m); 11065ca02815Sjsg } 1107fb4d8502Sjsg spin_unlock(&file->table_lock); 1108fb4d8502Sjsg } 1109fb4d8502Sjsg 1110fb4d8502Sjsg mutex_unlock(&dev->filelist_mutex); 1111fb4d8502Sjsg return 0; 1112fb4d8502Sjsg } 1113fb4d8502Sjsg 11145ca02815Sjsg DEFINE_SHOW_ATTRIBUTE(amdgpu_debugfs_gem_info); 11155ca02815Sjsg 1116fb4d8502Sjsg #endif 1117fb4d8502Sjsg 11185ca02815Sjsg void amdgpu_debugfs_gem_init(struct amdgpu_device *adev) 1119fb4d8502Sjsg { 1120fb4d8502Sjsg #if defined(CONFIG_DEBUG_FS) 11215ca02815Sjsg struct drm_minor *minor = adev_to_drm(adev)->primary; 11225ca02815Sjsg struct dentry *root = minor->debugfs_root; 11235ca02815Sjsg 11245ca02815Sjsg debugfs_create_file("amdgpu_gem_info", 0444, root, adev, 11255ca02815Sjsg &amdgpu_debugfs_gem_info_fops); 1126fb4d8502Sjsg #endif 1127fb4d8502Sjsg } 1128