162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * Copyright 2008 Advanced Micro Devices, Inc. 362306a36Sopenharmony_ci * Copyright 2008 Red Hat Inc. 462306a36Sopenharmony_ci * Copyright 2009 Jerome Glisse. 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 762306a36Sopenharmony_ci * copy of this software and associated documentation files (the "Software"), 862306a36Sopenharmony_ci * to deal in the Software without restriction, including without limitation 962306a36Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense, 1062306a36Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the 1162306a36Sopenharmony_ci * Software is furnished to do so, subject to the following conditions: 1262306a36Sopenharmony_ci * 1362306a36Sopenharmony_ci * The above copyright notice and this permission notice shall be included in 1462306a36Sopenharmony_ci * all copies or substantial portions of the Software. 1562306a36Sopenharmony_ci * 1662306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1762306a36Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1862306a36Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 1962306a36Sopenharmony_ci * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 2062306a36Sopenharmony_ci * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 2162306a36Sopenharmony_ci * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 2262306a36Sopenharmony_ci * OTHER DEALINGS IN THE SOFTWARE. 2362306a36Sopenharmony_ci * 2462306a36Sopenharmony_ci * Authors: Dave Airlie 2562306a36Sopenharmony_ci * Alex Deucher 2662306a36Sopenharmony_ci * Jerome Glisse 2762306a36Sopenharmony_ci */ 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci#include <linux/iosys-map.h> 3062306a36Sopenharmony_ci#include <linux/pci.h> 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci#include <drm/drm_device.h> 3362306a36Sopenharmony_ci#include <drm/drm_file.h> 3462306a36Sopenharmony_ci#include <drm/drm_gem_ttm_helper.h> 3562306a36Sopenharmony_ci#include <drm/radeon_drm.h> 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci#include "radeon.h" 3862306a36Sopenharmony_ci#include "radeon_prime.h" 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_cistruct dma_buf *radeon_gem_prime_export(struct drm_gem_object *gobj, 4162306a36Sopenharmony_ci int flags); 4262306a36Sopenharmony_cistruct sg_table *radeon_gem_prime_get_sg_table(struct drm_gem_object *obj); 4362306a36Sopenharmony_ciint radeon_gem_prime_pin(struct drm_gem_object *obj); 4462306a36Sopenharmony_civoid radeon_gem_prime_unpin(struct drm_gem_object *obj); 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ciconst struct drm_gem_object_funcs radeon_gem_object_funcs; 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_cistatic vm_fault_t radeon_gem_fault(struct vm_fault *vmf) 4962306a36Sopenharmony_ci{ 5062306a36Sopenharmony_ci struct ttm_buffer_object *bo = vmf->vma->vm_private_data; 5162306a36Sopenharmony_ci struct radeon_device *rdev = radeon_get_rdev(bo->bdev); 5262306a36Sopenharmony_ci vm_fault_t ret; 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci down_read(&rdev->pm.mclk_lock); 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci ret = ttm_bo_vm_reserve(bo, vmf); 5762306a36Sopenharmony_ci if (ret) 5862306a36Sopenharmony_ci goto unlock_mclk; 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci ret = radeon_bo_fault_reserve_notify(bo); 6162306a36Sopenharmony_ci if (ret) 6262306a36Sopenharmony_ci goto unlock_resv; 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci ret = ttm_bo_vm_fault_reserved(vmf, vmf->vma->vm_page_prot, 6562306a36Sopenharmony_ci TTM_BO_VM_NUM_PREFAULT); 6662306a36Sopenharmony_ci if (ret == VM_FAULT_RETRY && !(vmf->flags & FAULT_FLAG_RETRY_NOWAIT)) 6762306a36Sopenharmony_ci goto unlock_mclk; 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ciunlock_resv: 7062306a36Sopenharmony_ci dma_resv_unlock(bo->base.resv); 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ciunlock_mclk: 7362306a36Sopenharmony_ci up_read(&rdev->pm.mclk_lock); 7462306a36Sopenharmony_ci return ret; 7562306a36Sopenharmony_ci} 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_cistatic const struct vm_operations_struct radeon_gem_vm_ops = { 7862306a36Sopenharmony_ci .fault = radeon_gem_fault, 7962306a36Sopenharmony_ci .open = ttm_bo_vm_open, 8062306a36Sopenharmony_ci .close = ttm_bo_vm_close, 8162306a36Sopenharmony_ci .access = ttm_bo_vm_access 8262306a36Sopenharmony_ci}; 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_cistatic void radeon_gem_object_free(struct drm_gem_object *gobj) 8562306a36Sopenharmony_ci{ 8662306a36Sopenharmony_ci struct radeon_bo *robj = gem_to_radeon_bo(gobj); 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci if (robj) { 8962306a36Sopenharmony_ci radeon_mn_unregister(robj); 9062306a36Sopenharmony_ci radeon_bo_unref(&robj); 9162306a36Sopenharmony_ci } 9262306a36Sopenharmony_ci} 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ciint radeon_gem_object_create(struct radeon_device *rdev, unsigned long size, 9562306a36Sopenharmony_ci int alignment, int initial_domain, 9662306a36Sopenharmony_ci u32 flags, bool kernel, 9762306a36Sopenharmony_ci struct drm_gem_object **obj) 9862306a36Sopenharmony_ci{ 9962306a36Sopenharmony_ci struct radeon_bo *robj; 10062306a36Sopenharmony_ci unsigned long max_size; 10162306a36Sopenharmony_ci int r; 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci *obj = NULL; 10462306a36Sopenharmony_ci /* At least align on page size */ 10562306a36Sopenharmony_ci if (alignment < PAGE_SIZE) { 10662306a36Sopenharmony_ci alignment = PAGE_SIZE; 10762306a36Sopenharmony_ci } 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci /* Maximum bo size is the unpinned gtt size since we use the gtt to 11062306a36Sopenharmony_ci * handle vram to system pool migrations. 11162306a36Sopenharmony_ci */ 11262306a36Sopenharmony_ci max_size = rdev->mc.gtt_size - rdev->gart_pin_size; 11362306a36Sopenharmony_ci if (size > max_size) { 11462306a36Sopenharmony_ci DRM_DEBUG("Allocation size %ldMb bigger than %ldMb limit\n", 11562306a36Sopenharmony_ci size >> 20, max_size >> 20); 11662306a36Sopenharmony_ci return -ENOMEM; 11762306a36Sopenharmony_ci } 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ciretry: 12062306a36Sopenharmony_ci r = radeon_bo_create(rdev, size, alignment, kernel, initial_domain, 12162306a36Sopenharmony_ci flags, NULL, NULL, &robj); 12262306a36Sopenharmony_ci if (r) { 12362306a36Sopenharmony_ci if (r != -ERESTARTSYS) { 12462306a36Sopenharmony_ci if (initial_domain == RADEON_GEM_DOMAIN_VRAM) { 12562306a36Sopenharmony_ci initial_domain |= RADEON_GEM_DOMAIN_GTT; 12662306a36Sopenharmony_ci goto retry; 12762306a36Sopenharmony_ci } 12862306a36Sopenharmony_ci DRM_ERROR("Failed to allocate GEM object (%ld, %d, %u, %d)\n", 12962306a36Sopenharmony_ci size, initial_domain, alignment, r); 13062306a36Sopenharmony_ci } 13162306a36Sopenharmony_ci return r; 13262306a36Sopenharmony_ci } 13362306a36Sopenharmony_ci *obj = &robj->tbo.base; 13462306a36Sopenharmony_ci (*obj)->funcs = &radeon_gem_object_funcs; 13562306a36Sopenharmony_ci robj->pid = task_pid_nr(current); 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci mutex_lock(&rdev->gem.mutex); 13862306a36Sopenharmony_ci list_add_tail(&robj->list, &rdev->gem.objects); 13962306a36Sopenharmony_ci mutex_unlock(&rdev->gem.mutex); 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci return 0; 14262306a36Sopenharmony_ci} 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_cistatic int radeon_gem_set_domain(struct drm_gem_object *gobj, 14562306a36Sopenharmony_ci uint32_t rdomain, uint32_t wdomain) 14662306a36Sopenharmony_ci{ 14762306a36Sopenharmony_ci struct radeon_bo *robj; 14862306a36Sopenharmony_ci uint32_t domain; 14962306a36Sopenharmony_ci long r; 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci /* FIXME: reeimplement */ 15262306a36Sopenharmony_ci robj = gem_to_radeon_bo(gobj); 15362306a36Sopenharmony_ci /* work out where to validate the buffer to */ 15462306a36Sopenharmony_ci domain = wdomain; 15562306a36Sopenharmony_ci if (!domain) { 15662306a36Sopenharmony_ci domain = rdomain; 15762306a36Sopenharmony_ci } 15862306a36Sopenharmony_ci if (!domain) { 15962306a36Sopenharmony_ci /* Do nothings */ 16062306a36Sopenharmony_ci pr_warn("Set domain without domain !\n"); 16162306a36Sopenharmony_ci return 0; 16262306a36Sopenharmony_ci } 16362306a36Sopenharmony_ci if (domain == RADEON_GEM_DOMAIN_CPU) { 16462306a36Sopenharmony_ci /* Asking for cpu access wait for object idle */ 16562306a36Sopenharmony_ci r = dma_resv_wait_timeout(robj->tbo.base.resv, 16662306a36Sopenharmony_ci DMA_RESV_USAGE_BOOKKEEP, 16762306a36Sopenharmony_ci true, 30 * HZ); 16862306a36Sopenharmony_ci if (!r) 16962306a36Sopenharmony_ci r = -EBUSY; 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci if (r < 0 && r != -EINTR) { 17262306a36Sopenharmony_ci pr_err("Failed to wait for object: %li\n", r); 17362306a36Sopenharmony_ci return r; 17462306a36Sopenharmony_ci } 17562306a36Sopenharmony_ci } 17662306a36Sopenharmony_ci if (domain == RADEON_GEM_DOMAIN_VRAM && robj->prime_shared_count) { 17762306a36Sopenharmony_ci /* A BO that is associated with a dma-buf cannot be sensibly migrated to VRAM */ 17862306a36Sopenharmony_ci return -EINVAL; 17962306a36Sopenharmony_ci } 18062306a36Sopenharmony_ci return 0; 18162306a36Sopenharmony_ci} 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ciint radeon_gem_init(struct radeon_device *rdev) 18462306a36Sopenharmony_ci{ 18562306a36Sopenharmony_ci INIT_LIST_HEAD(&rdev->gem.objects); 18662306a36Sopenharmony_ci return 0; 18762306a36Sopenharmony_ci} 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_civoid radeon_gem_fini(struct radeon_device *rdev) 19062306a36Sopenharmony_ci{ 19162306a36Sopenharmony_ci radeon_bo_force_delete(rdev); 19262306a36Sopenharmony_ci} 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci/* 19562306a36Sopenharmony_ci * Call from drm_gem_handle_create which appear in both new and open ioctl 19662306a36Sopenharmony_ci * case. 19762306a36Sopenharmony_ci */ 19862306a36Sopenharmony_cistatic int radeon_gem_object_open(struct drm_gem_object *obj, struct drm_file *file_priv) 19962306a36Sopenharmony_ci{ 20062306a36Sopenharmony_ci struct radeon_bo *rbo = gem_to_radeon_bo(obj); 20162306a36Sopenharmony_ci struct radeon_device *rdev = rbo->rdev; 20262306a36Sopenharmony_ci struct radeon_fpriv *fpriv = file_priv->driver_priv; 20362306a36Sopenharmony_ci struct radeon_vm *vm = &fpriv->vm; 20462306a36Sopenharmony_ci struct radeon_bo_va *bo_va; 20562306a36Sopenharmony_ci int r; 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci if ((rdev->family < CHIP_CAYMAN) || 20862306a36Sopenharmony_ci (!rdev->accel_working)) { 20962306a36Sopenharmony_ci return 0; 21062306a36Sopenharmony_ci } 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci r = radeon_bo_reserve(rbo, false); 21362306a36Sopenharmony_ci if (r) { 21462306a36Sopenharmony_ci return r; 21562306a36Sopenharmony_ci } 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci bo_va = radeon_vm_bo_find(vm, rbo); 21862306a36Sopenharmony_ci if (!bo_va) { 21962306a36Sopenharmony_ci bo_va = radeon_vm_bo_add(rdev, vm, rbo); 22062306a36Sopenharmony_ci } else { 22162306a36Sopenharmony_ci ++bo_va->ref_count; 22262306a36Sopenharmony_ci } 22362306a36Sopenharmony_ci radeon_bo_unreserve(rbo); 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci return 0; 22662306a36Sopenharmony_ci} 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_cistatic void radeon_gem_object_close(struct drm_gem_object *obj, 22962306a36Sopenharmony_ci struct drm_file *file_priv) 23062306a36Sopenharmony_ci{ 23162306a36Sopenharmony_ci struct radeon_bo *rbo = gem_to_radeon_bo(obj); 23262306a36Sopenharmony_ci struct radeon_device *rdev = rbo->rdev; 23362306a36Sopenharmony_ci struct radeon_fpriv *fpriv = file_priv->driver_priv; 23462306a36Sopenharmony_ci struct radeon_vm *vm = &fpriv->vm; 23562306a36Sopenharmony_ci struct radeon_bo_va *bo_va; 23662306a36Sopenharmony_ci int r; 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci if ((rdev->family < CHIP_CAYMAN) || 23962306a36Sopenharmony_ci (!rdev->accel_working)) { 24062306a36Sopenharmony_ci return; 24162306a36Sopenharmony_ci } 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci r = radeon_bo_reserve(rbo, true); 24462306a36Sopenharmony_ci if (r) { 24562306a36Sopenharmony_ci dev_err(rdev->dev, "leaking bo va because " 24662306a36Sopenharmony_ci "we fail to reserve bo (%d)\n", r); 24762306a36Sopenharmony_ci return; 24862306a36Sopenharmony_ci } 24962306a36Sopenharmony_ci bo_va = radeon_vm_bo_find(vm, rbo); 25062306a36Sopenharmony_ci if (bo_va) { 25162306a36Sopenharmony_ci if (--bo_va->ref_count == 0) { 25262306a36Sopenharmony_ci radeon_vm_bo_rmv(rdev, bo_va); 25362306a36Sopenharmony_ci } 25462306a36Sopenharmony_ci } 25562306a36Sopenharmony_ci radeon_bo_unreserve(rbo); 25662306a36Sopenharmony_ci} 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_cistatic int radeon_gem_handle_lockup(struct radeon_device *rdev, int r) 25962306a36Sopenharmony_ci{ 26062306a36Sopenharmony_ci if (r == -EDEADLK) { 26162306a36Sopenharmony_ci r = radeon_gpu_reset(rdev); 26262306a36Sopenharmony_ci if (!r) 26362306a36Sopenharmony_ci r = -EAGAIN; 26462306a36Sopenharmony_ci } 26562306a36Sopenharmony_ci return r; 26662306a36Sopenharmony_ci} 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_cistatic int radeon_gem_object_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma) 26962306a36Sopenharmony_ci{ 27062306a36Sopenharmony_ci struct radeon_bo *bo = gem_to_radeon_bo(obj); 27162306a36Sopenharmony_ci struct radeon_device *rdev = radeon_get_rdev(bo->tbo.bdev); 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci if (radeon_ttm_tt_has_userptr(rdev, bo->tbo.ttm)) 27462306a36Sopenharmony_ci return -EPERM; 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci return drm_gem_ttm_mmap(obj, vma); 27762306a36Sopenharmony_ci} 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ciconst struct drm_gem_object_funcs radeon_gem_object_funcs = { 28062306a36Sopenharmony_ci .free = radeon_gem_object_free, 28162306a36Sopenharmony_ci .open = radeon_gem_object_open, 28262306a36Sopenharmony_ci .close = radeon_gem_object_close, 28362306a36Sopenharmony_ci .export = radeon_gem_prime_export, 28462306a36Sopenharmony_ci .pin = radeon_gem_prime_pin, 28562306a36Sopenharmony_ci .unpin = radeon_gem_prime_unpin, 28662306a36Sopenharmony_ci .get_sg_table = radeon_gem_prime_get_sg_table, 28762306a36Sopenharmony_ci .vmap = drm_gem_ttm_vmap, 28862306a36Sopenharmony_ci .vunmap = drm_gem_ttm_vunmap, 28962306a36Sopenharmony_ci .mmap = radeon_gem_object_mmap, 29062306a36Sopenharmony_ci .vm_ops = &radeon_gem_vm_ops, 29162306a36Sopenharmony_ci}; 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci/* 29462306a36Sopenharmony_ci * GEM ioctls. 29562306a36Sopenharmony_ci */ 29662306a36Sopenharmony_ciint radeon_gem_info_ioctl(struct drm_device *dev, void *data, 29762306a36Sopenharmony_ci struct drm_file *filp) 29862306a36Sopenharmony_ci{ 29962306a36Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 30062306a36Sopenharmony_ci struct drm_radeon_gem_info *args = data; 30162306a36Sopenharmony_ci struct ttm_resource_manager *man; 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci man = ttm_manager_type(&rdev->mman.bdev, TTM_PL_VRAM); 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci args->vram_size = (u64)man->size << PAGE_SHIFT; 30662306a36Sopenharmony_ci args->vram_visible = rdev->mc.visible_vram_size; 30762306a36Sopenharmony_ci args->vram_visible -= rdev->vram_pin_size; 30862306a36Sopenharmony_ci args->gart_size = rdev->mc.gtt_size; 30962306a36Sopenharmony_ci args->gart_size -= rdev->gart_pin_size; 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci return 0; 31262306a36Sopenharmony_ci} 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ciint radeon_gem_create_ioctl(struct drm_device *dev, void *data, 31562306a36Sopenharmony_ci struct drm_file *filp) 31662306a36Sopenharmony_ci{ 31762306a36Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 31862306a36Sopenharmony_ci struct drm_radeon_gem_create *args = data; 31962306a36Sopenharmony_ci struct drm_gem_object *gobj; 32062306a36Sopenharmony_ci uint32_t handle; 32162306a36Sopenharmony_ci int r; 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci down_read(&rdev->exclusive_lock); 32462306a36Sopenharmony_ci /* create a gem object to contain this object in */ 32562306a36Sopenharmony_ci args->size = roundup(args->size, PAGE_SIZE); 32662306a36Sopenharmony_ci r = radeon_gem_object_create(rdev, args->size, args->alignment, 32762306a36Sopenharmony_ci args->initial_domain, args->flags, 32862306a36Sopenharmony_ci false, &gobj); 32962306a36Sopenharmony_ci if (r) { 33062306a36Sopenharmony_ci up_read(&rdev->exclusive_lock); 33162306a36Sopenharmony_ci r = radeon_gem_handle_lockup(rdev, r); 33262306a36Sopenharmony_ci return r; 33362306a36Sopenharmony_ci } 33462306a36Sopenharmony_ci r = drm_gem_handle_create(filp, gobj, &handle); 33562306a36Sopenharmony_ci /* drop reference from allocate - handle holds it now */ 33662306a36Sopenharmony_ci drm_gem_object_put(gobj); 33762306a36Sopenharmony_ci if (r) { 33862306a36Sopenharmony_ci up_read(&rdev->exclusive_lock); 33962306a36Sopenharmony_ci r = radeon_gem_handle_lockup(rdev, r); 34062306a36Sopenharmony_ci return r; 34162306a36Sopenharmony_ci } 34262306a36Sopenharmony_ci args->handle = handle; 34362306a36Sopenharmony_ci up_read(&rdev->exclusive_lock); 34462306a36Sopenharmony_ci return 0; 34562306a36Sopenharmony_ci} 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ciint radeon_gem_userptr_ioctl(struct drm_device *dev, void *data, 34862306a36Sopenharmony_ci struct drm_file *filp) 34962306a36Sopenharmony_ci{ 35062306a36Sopenharmony_ci struct ttm_operation_ctx ctx = { true, false }; 35162306a36Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 35262306a36Sopenharmony_ci struct drm_radeon_gem_userptr *args = data; 35362306a36Sopenharmony_ci struct drm_gem_object *gobj; 35462306a36Sopenharmony_ci struct radeon_bo *bo; 35562306a36Sopenharmony_ci uint32_t handle; 35662306a36Sopenharmony_ci int r; 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci args->addr = untagged_addr(args->addr); 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci if (offset_in_page(args->addr | args->size)) 36162306a36Sopenharmony_ci return -EINVAL; 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci /* reject unknown flag values */ 36462306a36Sopenharmony_ci if (args->flags & ~(RADEON_GEM_USERPTR_READONLY | 36562306a36Sopenharmony_ci RADEON_GEM_USERPTR_ANONONLY | RADEON_GEM_USERPTR_VALIDATE | 36662306a36Sopenharmony_ci RADEON_GEM_USERPTR_REGISTER)) 36762306a36Sopenharmony_ci return -EINVAL; 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci if (args->flags & RADEON_GEM_USERPTR_READONLY) { 37062306a36Sopenharmony_ci /* readonly pages not tested on older hardware */ 37162306a36Sopenharmony_ci if (rdev->family < CHIP_R600) 37262306a36Sopenharmony_ci return -EINVAL; 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci } else if (!(args->flags & RADEON_GEM_USERPTR_ANONONLY) || 37562306a36Sopenharmony_ci !(args->flags & RADEON_GEM_USERPTR_REGISTER)) { 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci /* if we want to write to it we must require anonymous 37862306a36Sopenharmony_ci memory and install a MMU notifier */ 37962306a36Sopenharmony_ci return -EACCES; 38062306a36Sopenharmony_ci } 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci down_read(&rdev->exclusive_lock); 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci /* create a gem object to contain this object in */ 38562306a36Sopenharmony_ci r = radeon_gem_object_create(rdev, args->size, 0, 38662306a36Sopenharmony_ci RADEON_GEM_DOMAIN_CPU, 0, 38762306a36Sopenharmony_ci false, &gobj); 38862306a36Sopenharmony_ci if (r) 38962306a36Sopenharmony_ci goto handle_lockup; 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci bo = gem_to_radeon_bo(gobj); 39262306a36Sopenharmony_ci r = radeon_ttm_tt_set_userptr(rdev, bo->tbo.ttm, args->addr, args->flags); 39362306a36Sopenharmony_ci if (r) 39462306a36Sopenharmony_ci goto release_object; 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci if (args->flags & RADEON_GEM_USERPTR_REGISTER) { 39762306a36Sopenharmony_ci r = radeon_mn_register(bo, args->addr); 39862306a36Sopenharmony_ci if (r) 39962306a36Sopenharmony_ci goto release_object; 40062306a36Sopenharmony_ci } 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci if (args->flags & RADEON_GEM_USERPTR_VALIDATE) { 40362306a36Sopenharmony_ci mmap_read_lock(current->mm); 40462306a36Sopenharmony_ci r = radeon_bo_reserve(bo, true); 40562306a36Sopenharmony_ci if (r) { 40662306a36Sopenharmony_ci mmap_read_unlock(current->mm); 40762306a36Sopenharmony_ci goto release_object; 40862306a36Sopenharmony_ci } 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci radeon_ttm_placement_from_domain(bo, RADEON_GEM_DOMAIN_GTT); 41162306a36Sopenharmony_ci r = ttm_bo_validate(&bo->tbo, &bo->placement, &ctx); 41262306a36Sopenharmony_ci radeon_bo_unreserve(bo); 41362306a36Sopenharmony_ci mmap_read_unlock(current->mm); 41462306a36Sopenharmony_ci if (r) 41562306a36Sopenharmony_ci goto release_object; 41662306a36Sopenharmony_ci } 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci r = drm_gem_handle_create(filp, gobj, &handle); 41962306a36Sopenharmony_ci /* drop reference from allocate - handle holds it now */ 42062306a36Sopenharmony_ci drm_gem_object_put(gobj); 42162306a36Sopenharmony_ci if (r) 42262306a36Sopenharmony_ci goto handle_lockup; 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci args->handle = handle; 42562306a36Sopenharmony_ci up_read(&rdev->exclusive_lock); 42662306a36Sopenharmony_ci return 0; 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_cirelease_object: 42962306a36Sopenharmony_ci drm_gem_object_put(gobj); 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_cihandle_lockup: 43262306a36Sopenharmony_ci up_read(&rdev->exclusive_lock); 43362306a36Sopenharmony_ci r = radeon_gem_handle_lockup(rdev, r); 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci return r; 43662306a36Sopenharmony_ci} 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ciint radeon_gem_set_domain_ioctl(struct drm_device *dev, void *data, 43962306a36Sopenharmony_ci struct drm_file *filp) 44062306a36Sopenharmony_ci{ 44162306a36Sopenharmony_ci /* transition the BO to a domain - 44262306a36Sopenharmony_ci * just validate the BO into a certain domain */ 44362306a36Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 44462306a36Sopenharmony_ci struct drm_radeon_gem_set_domain *args = data; 44562306a36Sopenharmony_ci struct drm_gem_object *gobj; 44662306a36Sopenharmony_ci int r; 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci /* for now if someone requests domain CPU - 44962306a36Sopenharmony_ci * just make sure the buffer is finished with */ 45062306a36Sopenharmony_ci down_read(&rdev->exclusive_lock); 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci /* just do a BO wait for now */ 45362306a36Sopenharmony_ci gobj = drm_gem_object_lookup(filp, args->handle); 45462306a36Sopenharmony_ci if (gobj == NULL) { 45562306a36Sopenharmony_ci up_read(&rdev->exclusive_lock); 45662306a36Sopenharmony_ci return -ENOENT; 45762306a36Sopenharmony_ci } 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci r = radeon_gem_set_domain(gobj, args->read_domains, args->write_domain); 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci drm_gem_object_put(gobj); 46262306a36Sopenharmony_ci up_read(&rdev->exclusive_lock); 46362306a36Sopenharmony_ci r = radeon_gem_handle_lockup(rdev, r); 46462306a36Sopenharmony_ci return r; 46562306a36Sopenharmony_ci} 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ciint radeon_mode_dumb_mmap(struct drm_file *filp, 46862306a36Sopenharmony_ci struct drm_device *dev, 46962306a36Sopenharmony_ci uint32_t handle, uint64_t *offset_p) 47062306a36Sopenharmony_ci{ 47162306a36Sopenharmony_ci struct drm_gem_object *gobj; 47262306a36Sopenharmony_ci struct radeon_bo *robj; 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci gobj = drm_gem_object_lookup(filp, handle); 47562306a36Sopenharmony_ci if (gobj == NULL) { 47662306a36Sopenharmony_ci return -ENOENT; 47762306a36Sopenharmony_ci } 47862306a36Sopenharmony_ci robj = gem_to_radeon_bo(gobj); 47962306a36Sopenharmony_ci if (radeon_ttm_tt_has_userptr(robj->rdev, robj->tbo.ttm)) { 48062306a36Sopenharmony_ci drm_gem_object_put(gobj); 48162306a36Sopenharmony_ci return -EPERM; 48262306a36Sopenharmony_ci } 48362306a36Sopenharmony_ci *offset_p = radeon_bo_mmap_offset(robj); 48462306a36Sopenharmony_ci drm_gem_object_put(gobj); 48562306a36Sopenharmony_ci return 0; 48662306a36Sopenharmony_ci} 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ciint radeon_gem_mmap_ioctl(struct drm_device *dev, void *data, 48962306a36Sopenharmony_ci struct drm_file *filp) 49062306a36Sopenharmony_ci{ 49162306a36Sopenharmony_ci struct drm_radeon_gem_mmap *args = data; 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci return radeon_mode_dumb_mmap(filp, dev, args->handle, &args->addr_ptr); 49462306a36Sopenharmony_ci} 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ciint radeon_gem_busy_ioctl(struct drm_device *dev, void *data, 49762306a36Sopenharmony_ci struct drm_file *filp) 49862306a36Sopenharmony_ci{ 49962306a36Sopenharmony_ci struct drm_radeon_gem_busy *args = data; 50062306a36Sopenharmony_ci struct drm_gem_object *gobj; 50162306a36Sopenharmony_ci struct radeon_bo *robj; 50262306a36Sopenharmony_ci int r; 50362306a36Sopenharmony_ci uint32_t cur_placement = 0; 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci gobj = drm_gem_object_lookup(filp, args->handle); 50662306a36Sopenharmony_ci if (gobj == NULL) { 50762306a36Sopenharmony_ci return -ENOENT; 50862306a36Sopenharmony_ci } 50962306a36Sopenharmony_ci robj = gem_to_radeon_bo(gobj); 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci r = dma_resv_test_signaled(robj->tbo.base.resv, DMA_RESV_USAGE_READ); 51262306a36Sopenharmony_ci if (r == 0) 51362306a36Sopenharmony_ci r = -EBUSY; 51462306a36Sopenharmony_ci else 51562306a36Sopenharmony_ci r = 0; 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci cur_placement = READ_ONCE(robj->tbo.resource->mem_type); 51862306a36Sopenharmony_ci args->domain = radeon_mem_type_to_domain(cur_placement); 51962306a36Sopenharmony_ci drm_gem_object_put(gobj); 52062306a36Sopenharmony_ci return r; 52162306a36Sopenharmony_ci} 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ciint radeon_gem_wait_idle_ioctl(struct drm_device *dev, void *data, 52462306a36Sopenharmony_ci struct drm_file *filp) 52562306a36Sopenharmony_ci{ 52662306a36Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 52762306a36Sopenharmony_ci struct drm_radeon_gem_wait_idle *args = data; 52862306a36Sopenharmony_ci struct drm_gem_object *gobj; 52962306a36Sopenharmony_ci struct radeon_bo *robj; 53062306a36Sopenharmony_ci int r = 0; 53162306a36Sopenharmony_ci uint32_t cur_placement = 0; 53262306a36Sopenharmony_ci long ret; 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci gobj = drm_gem_object_lookup(filp, args->handle); 53562306a36Sopenharmony_ci if (gobj == NULL) { 53662306a36Sopenharmony_ci return -ENOENT; 53762306a36Sopenharmony_ci } 53862306a36Sopenharmony_ci robj = gem_to_radeon_bo(gobj); 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci ret = dma_resv_wait_timeout(robj->tbo.base.resv, DMA_RESV_USAGE_READ, 54162306a36Sopenharmony_ci true, 30 * HZ); 54262306a36Sopenharmony_ci if (ret == 0) 54362306a36Sopenharmony_ci r = -EBUSY; 54462306a36Sopenharmony_ci else if (ret < 0) 54562306a36Sopenharmony_ci r = ret; 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci /* Flush HDP cache via MMIO if necessary */ 54862306a36Sopenharmony_ci cur_placement = READ_ONCE(robj->tbo.resource->mem_type); 54962306a36Sopenharmony_ci if (rdev->asic->mmio_hdp_flush && 55062306a36Sopenharmony_ci radeon_mem_type_to_domain(cur_placement) == RADEON_GEM_DOMAIN_VRAM) 55162306a36Sopenharmony_ci robj->rdev->asic->mmio_hdp_flush(rdev); 55262306a36Sopenharmony_ci drm_gem_object_put(gobj); 55362306a36Sopenharmony_ci r = radeon_gem_handle_lockup(rdev, r); 55462306a36Sopenharmony_ci return r; 55562306a36Sopenharmony_ci} 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ciint radeon_gem_set_tiling_ioctl(struct drm_device *dev, void *data, 55862306a36Sopenharmony_ci struct drm_file *filp) 55962306a36Sopenharmony_ci{ 56062306a36Sopenharmony_ci struct drm_radeon_gem_set_tiling *args = data; 56162306a36Sopenharmony_ci struct drm_gem_object *gobj; 56262306a36Sopenharmony_ci struct radeon_bo *robj; 56362306a36Sopenharmony_ci int r = 0; 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_ci DRM_DEBUG("%d \n", args->handle); 56662306a36Sopenharmony_ci gobj = drm_gem_object_lookup(filp, args->handle); 56762306a36Sopenharmony_ci if (gobj == NULL) 56862306a36Sopenharmony_ci return -ENOENT; 56962306a36Sopenharmony_ci robj = gem_to_radeon_bo(gobj); 57062306a36Sopenharmony_ci r = radeon_bo_set_tiling_flags(robj, args->tiling_flags, args->pitch); 57162306a36Sopenharmony_ci drm_gem_object_put(gobj); 57262306a36Sopenharmony_ci return r; 57362306a36Sopenharmony_ci} 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ciint radeon_gem_get_tiling_ioctl(struct drm_device *dev, void *data, 57662306a36Sopenharmony_ci struct drm_file *filp) 57762306a36Sopenharmony_ci{ 57862306a36Sopenharmony_ci struct drm_radeon_gem_get_tiling *args = data; 57962306a36Sopenharmony_ci struct drm_gem_object *gobj; 58062306a36Sopenharmony_ci struct radeon_bo *rbo; 58162306a36Sopenharmony_ci int r = 0; 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_ci DRM_DEBUG("\n"); 58462306a36Sopenharmony_ci gobj = drm_gem_object_lookup(filp, args->handle); 58562306a36Sopenharmony_ci if (gobj == NULL) 58662306a36Sopenharmony_ci return -ENOENT; 58762306a36Sopenharmony_ci rbo = gem_to_radeon_bo(gobj); 58862306a36Sopenharmony_ci r = radeon_bo_reserve(rbo, false); 58962306a36Sopenharmony_ci if (unlikely(r != 0)) 59062306a36Sopenharmony_ci goto out; 59162306a36Sopenharmony_ci radeon_bo_get_tiling_flags(rbo, &args->tiling_flags, &args->pitch); 59262306a36Sopenharmony_ci radeon_bo_unreserve(rbo); 59362306a36Sopenharmony_ciout: 59462306a36Sopenharmony_ci drm_gem_object_put(gobj); 59562306a36Sopenharmony_ci return r; 59662306a36Sopenharmony_ci} 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ci/** 59962306a36Sopenharmony_ci * radeon_gem_va_update_vm -update the bo_va in its VM 60062306a36Sopenharmony_ci * 60162306a36Sopenharmony_ci * @rdev: radeon_device pointer 60262306a36Sopenharmony_ci * @bo_va: bo_va to update 60362306a36Sopenharmony_ci * 60462306a36Sopenharmony_ci * Update the bo_va directly after setting it's address. Errors are not 60562306a36Sopenharmony_ci * vital here, so they are not reported back to userspace. 60662306a36Sopenharmony_ci */ 60762306a36Sopenharmony_cistatic void radeon_gem_va_update_vm(struct radeon_device *rdev, 60862306a36Sopenharmony_ci struct radeon_bo_va *bo_va) 60962306a36Sopenharmony_ci{ 61062306a36Sopenharmony_ci struct ttm_validate_buffer tv, *entry; 61162306a36Sopenharmony_ci struct radeon_bo_list *vm_bos; 61262306a36Sopenharmony_ci struct ww_acquire_ctx ticket; 61362306a36Sopenharmony_ci struct list_head list; 61462306a36Sopenharmony_ci unsigned domain; 61562306a36Sopenharmony_ci int r; 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_ci INIT_LIST_HEAD(&list); 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci tv.bo = &bo_va->bo->tbo; 62062306a36Sopenharmony_ci tv.num_shared = 1; 62162306a36Sopenharmony_ci list_add(&tv.head, &list); 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ci vm_bos = radeon_vm_get_bos(rdev, bo_va->vm, &list); 62462306a36Sopenharmony_ci if (!vm_bos) 62562306a36Sopenharmony_ci return; 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_ci r = ttm_eu_reserve_buffers(&ticket, &list, true, NULL); 62862306a36Sopenharmony_ci if (r) 62962306a36Sopenharmony_ci goto error_free; 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_ci list_for_each_entry(entry, &list, head) { 63262306a36Sopenharmony_ci domain = radeon_mem_type_to_domain(entry->bo->resource->mem_type); 63362306a36Sopenharmony_ci /* if anything is swapped out don't swap it in here, 63462306a36Sopenharmony_ci just abort and wait for the next CS */ 63562306a36Sopenharmony_ci if (domain == RADEON_GEM_DOMAIN_CPU) 63662306a36Sopenharmony_ci goto error_unreserve; 63762306a36Sopenharmony_ci } 63862306a36Sopenharmony_ci 63962306a36Sopenharmony_ci mutex_lock(&bo_va->vm->mutex); 64062306a36Sopenharmony_ci r = radeon_vm_clear_freed(rdev, bo_va->vm); 64162306a36Sopenharmony_ci if (r) 64262306a36Sopenharmony_ci goto error_unlock; 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci if (bo_va->it.start) 64562306a36Sopenharmony_ci r = radeon_vm_bo_update(rdev, bo_va, bo_va->bo->tbo.resource); 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_cierror_unlock: 64862306a36Sopenharmony_ci mutex_unlock(&bo_va->vm->mutex); 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_cierror_unreserve: 65162306a36Sopenharmony_ci ttm_eu_backoff_reservation(&ticket, &list); 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_cierror_free: 65462306a36Sopenharmony_ci kvfree(vm_bos); 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_ci if (r && r != -ERESTARTSYS) 65762306a36Sopenharmony_ci DRM_ERROR("Couldn't update BO_VA (%d)\n", r); 65862306a36Sopenharmony_ci} 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_ciint radeon_gem_va_ioctl(struct drm_device *dev, void *data, 66162306a36Sopenharmony_ci struct drm_file *filp) 66262306a36Sopenharmony_ci{ 66362306a36Sopenharmony_ci struct drm_radeon_gem_va *args = data; 66462306a36Sopenharmony_ci struct drm_gem_object *gobj; 66562306a36Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 66662306a36Sopenharmony_ci struct radeon_fpriv *fpriv = filp->driver_priv; 66762306a36Sopenharmony_ci struct radeon_bo *rbo; 66862306a36Sopenharmony_ci struct radeon_bo_va *bo_va; 66962306a36Sopenharmony_ci u32 invalid_flags; 67062306a36Sopenharmony_ci int r = 0; 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_ci if (!rdev->vm_manager.enabled) { 67362306a36Sopenharmony_ci args->operation = RADEON_VA_RESULT_ERROR; 67462306a36Sopenharmony_ci return -ENOTTY; 67562306a36Sopenharmony_ci } 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_ci /* !! DONT REMOVE !! 67862306a36Sopenharmony_ci * We don't support vm_id yet, to be sure we don't have broken 67962306a36Sopenharmony_ci * userspace, reject anyone trying to use non 0 value thus moving 68062306a36Sopenharmony_ci * forward we can use those fields without breaking existant userspace 68162306a36Sopenharmony_ci */ 68262306a36Sopenharmony_ci if (args->vm_id) { 68362306a36Sopenharmony_ci args->operation = RADEON_VA_RESULT_ERROR; 68462306a36Sopenharmony_ci return -EINVAL; 68562306a36Sopenharmony_ci } 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_ci if (args->offset < RADEON_VA_RESERVED_SIZE) { 68862306a36Sopenharmony_ci dev_err(dev->dev, 68962306a36Sopenharmony_ci "offset 0x%lX is in reserved area 0x%X\n", 69062306a36Sopenharmony_ci (unsigned long)args->offset, 69162306a36Sopenharmony_ci RADEON_VA_RESERVED_SIZE); 69262306a36Sopenharmony_ci args->operation = RADEON_VA_RESULT_ERROR; 69362306a36Sopenharmony_ci return -EINVAL; 69462306a36Sopenharmony_ci } 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_ci /* don't remove, we need to enforce userspace to set the snooped flag 69762306a36Sopenharmony_ci * otherwise we will endup with broken userspace and we won't be able 69862306a36Sopenharmony_ci * to enable this feature without adding new interface 69962306a36Sopenharmony_ci */ 70062306a36Sopenharmony_ci invalid_flags = RADEON_VM_PAGE_VALID | RADEON_VM_PAGE_SYSTEM; 70162306a36Sopenharmony_ci if ((args->flags & invalid_flags)) { 70262306a36Sopenharmony_ci dev_err(dev->dev, "invalid flags 0x%08X vs 0x%08X\n", 70362306a36Sopenharmony_ci args->flags, invalid_flags); 70462306a36Sopenharmony_ci args->operation = RADEON_VA_RESULT_ERROR; 70562306a36Sopenharmony_ci return -EINVAL; 70662306a36Sopenharmony_ci } 70762306a36Sopenharmony_ci 70862306a36Sopenharmony_ci switch (args->operation) { 70962306a36Sopenharmony_ci case RADEON_VA_MAP: 71062306a36Sopenharmony_ci case RADEON_VA_UNMAP: 71162306a36Sopenharmony_ci break; 71262306a36Sopenharmony_ci default: 71362306a36Sopenharmony_ci dev_err(dev->dev, "unsupported operation %d\n", 71462306a36Sopenharmony_ci args->operation); 71562306a36Sopenharmony_ci args->operation = RADEON_VA_RESULT_ERROR; 71662306a36Sopenharmony_ci return -EINVAL; 71762306a36Sopenharmony_ci } 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_ci gobj = drm_gem_object_lookup(filp, args->handle); 72062306a36Sopenharmony_ci if (gobj == NULL) { 72162306a36Sopenharmony_ci args->operation = RADEON_VA_RESULT_ERROR; 72262306a36Sopenharmony_ci return -ENOENT; 72362306a36Sopenharmony_ci } 72462306a36Sopenharmony_ci rbo = gem_to_radeon_bo(gobj); 72562306a36Sopenharmony_ci r = radeon_bo_reserve(rbo, false); 72662306a36Sopenharmony_ci if (r) { 72762306a36Sopenharmony_ci args->operation = RADEON_VA_RESULT_ERROR; 72862306a36Sopenharmony_ci drm_gem_object_put(gobj); 72962306a36Sopenharmony_ci return r; 73062306a36Sopenharmony_ci } 73162306a36Sopenharmony_ci bo_va = radeon_vm_bo_find(&fpriv->vm, rbo); 73262306a36Sopenharmony_ci if (!bo_va) { 73362306a36Sopenharmony_ci args->operation = RADEON_VA_RESULT_ERROR; 73462306a36Sopenharmony_ci radeon_bo_unreserve(rbo); 73562306a36Sopenharmony_ci drm_gem_object_put(gobj); 73662306a36Sopenharmony_ci return -ENOENT; 73762306a36Sopenharmony_ci } 73862306a36Sopenharmony_ci 73962306a36Sopenharmony_ci switch (args->operation) { 74062306a36Sopenharmony_ci case RADEON_VA_MAP: 74162306a36Sopenharmony_ci if (bo_va->it.start) { 74262306a36Sopenharmony_ci args->operation = RADEON_VA_RESULT_VA_EXIST; 74362306a36Sopenharmony_ci args->offset = bo_va->it.start * RADEON_GPU_PAGE_SIZE; 74462306a36Sopenharmony_ci radeon_bo_unreserve(rbo); 74562306a36Sopenharmony_ci goto out; 74662306a36Sopenharmony_ci } 74762306a36Sopenharmony_ci r = radeon_vm_bo_set_addr(rdev, bo_va, args->offset, args->flags); 74862306a36Sopenharmony_ci break; 74962306a36Sopenharmony_ci case RADEON_VA_UNMAP: 75062306a36Sopenharmony_ci r = radeon_vm_bo_set_addr(rdev, bo_va, 0, 0); 75162306a36Sopenharmony_ci break; 75262306a36Sopenharmony_ci default: 75362306a36Sopenharmony_ci break; 75462306a36Sopenharmony_ci } 75562306a36Sopenharmony_ci if (!r) 75662306a36Sopenharmony_ci radeon_gem_va_update_vm(rdev, bo_va); 75762306a36Sopenharmony_ci args->operation = RADEON_VA_RESULT_OK; 75862306a36Sopenharmony_ci if (r) { 75962306a36Sopenharmony_ci args->operation = RADEON_VA_RESULT_ERROR; 76062306a36Sopenharmony_ci } 76162306a36Sopenharmony_ciout: 76262306a36Sopenharmony_ci drm_gem_object_put(gobj); 76362306a36Sopenharmony_ci return r; 76462306a36Sopenharmony_ci} 76562306a36Sopenharmony_ci 76662306a36Sopenharmony_ciint radeon_gem_op_ioctl(struct drm_device *dev, void *data, 76762306a36Sopenharmony_ci struct drm_file *filp) 76862306a36Sopenharmony_ci{ 76962306a36Sopenharmony_ci struct drm_radeon_gem_op *args = data; 77062306a36Sopenharmony_ci struct drm_gem_object *gobj; 77162306a36Sopenharmony_ci struct radeon_bo *robj; 77262306a36Sopenharmony_ci int r; 77362306a36Sopenharmony_ci 77462306a36Sopenharmony_ci gobj = drm_gem_object_lookup(filp, args->handle); 77562306a36Sopenharmony_ci if (gobj == NULL) { 77662306a36Sopenharmony_ci return -ENOENT; 77762306a36Sopenharmony_ci } 77862306a36Sopenharmony_ci robj = gem_to_radeon_bo(gobj); 77962306a36Sopenharmony_ci 78062306a36Sopenharmony_ci r = -EPERM; 78162306a36Sopenharmony_ci if (radeon_ttm_tt_has_userptr(robj->rdev, robj->tbo.ttm)) 78262306a36Sopenharmony_ci goto out; 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_ci r = radeon_bo_reserve(robj, false); 78562306a36Sopenharmony_ci if (unlikely(r)) 78662306a36Sopenharmony_ci goto out; 78762306a36Sopenharmony_ci 78862306a36Sopenharmony_ci switch (args->op) { 78962306a36Sopenharmony_ci case RADEON_GEM_OP_GET_INITIAL_DOMAIN: 79062306a36Sopenharmony_ci args->value = robj->initial_domain; 79162306a36Sopenharmony_ci break; 79262306a36Sopenharmony_ci case RADEON_GEM_OP_SET_INITIAL_DOMAIN: 79362306a36Sopenharmony_ci robj->initial_domain = args->value & (RADEON_GEM_DOMAIN_VRAM | 79462306a36Sopenharmony_ci RADEON_GEM_DOMAIN_GTT | 79562306a36Sopenharmony_ci RADEON_GEM_DOMAIN_CPU); 79662306a36Sopenharmony_ci break; 79762306a36Sopenharmony_ci default: 79862306a36Sopenharmony_ci r = -EINVAL; 79962306a36Sopenharmony_ci } 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_ci radeon_bo_unreserve(robj); 80262306a36Sopenharmony_ciout: 80362306a36Sopenharmony_ci drm_gem_object_put(gobj); 80462306a36Sopenharmony_ci return r; 80562306a36Sopenharmony_ci} 80662306a36Sopenharmony_ci 80762306a36Sopenharmony_ciint radeon_align_pitch(struct radeon_device *rdev, int width, int cpp, bool tiled) 80862306a36Sopenharmony_ci{ 80962306a36Sopenharmony_ci int aligned = width; 81062306a36Sopenharmony_ci int align_large = (ASIC_IS_AVIVO(rdev)) || tiled; 81162306a36Sopenharmony_ci int pitch_mask = 0; 81262306a36Sopenharmony_ci 81362306a36Sopenharmony_ci switch (cpp) { 81462306a36Sopenharmony_ci case 1: 81562306a36Sopenharmony_ci pitch_mask = align_large ? 255 : 127; 81662306a36Sopenharmony_ci break; 81762306a36Sopenharmony_ci case 2: 81862306a36Sopenharmony_ci pitch_mask = align_large ? 127 : 31; 81962306a36Sopenharmony_ci break; 82062306a36Sopenharmony_ci case 3: 82162306a36Sopenharmony_ci case 4: 82262306a36Sopenharmony_ci pitch_mask = align_large ? 63 : 15; 82362306a36Sopenharmony_ci break; 82462306a36Sopenharmony_ci } 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_ci aligned += pitch_mask; 82762306a36Sopenharmony_ci aligned &= ~pitch_mask; 82862306a36Sopenharmony_ci return aligned * cpp; 82962306a36Sopenharmony_ci} 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_ciint radeon_mode_dumb_create(struct drm_file *file_priv, 83262306a36Sopenharmony_ci struct drm_device *dev, 83362306a36Sopenharmony_ci struct drm_mode_create_dumb *args) 83462306a36Sopenharmony_ci{ 83562306a36Sopenharmony_ci struct radeon_device *rdev = dev->dev_private; 83662306a36Sopenharmony_ci struct drm_gem_object *gobj; 83762306a36Sopenharmony_ci uint32_t handle; 83862306a36Sopenharmony_ci int r; 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_ci args->pitch = radeon_align_pitch(rdev, args->width, 84162306a36Sopenharmony_ci DIV_ROUND_UP(args->bpp, 8), 0); 84262306a36Sopenharmony_ci args->size = (u64)args->pitch * args->height; 84362306a36Sopenharmony_ci args->size = ALIGN(args->size, PAGE_SIZE); 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_ci r = radeon_gem_object_create(rdev, args->size, 0, 84662306a36Sopenharmony_ci RADEON_GEM_DOMAIN_VRAM, 0, 84762306a36Sopenharmony_ci false, &gobj); 84862306a36Sopenharmony_ci if (r) 84962306a36Sopenharmony_ci return -ENOMEM; 85062306a36Sopenharmony_ci 85162306a36Sopenharmony_ci r = drm_gem_handle_create(file_priv, gobj, &handle); 85262306a36Sopenharmony_ci /* drop reference from allocate - handle holds it now */ 85362306a36Sopenharmony_ci drm_gem_object_put(gobj); 85462306a36Sopenharmony_ci if (r) { 85562306a36Sopenharmony_ci return r; 85662306a36Sopenharmony_ci } 85762306a36Sopenharmony_ci args->handle = handle; 85862306a36Sopenharmony_ci return 0; 85962306a36Sopenharmony_ci} 86062306a36Sopenharmony_ci 86162306a36Sopenharmony_ci#if defined(CONFIG_DEBUG_FS) 86262306a36Sopenharmony_cistatic int radeon_debugfs_gem_info_show(struct seq_file *m, void *unused) 86362306a36Sopenharmony_ci{ 86462306a36Sopenharmony_ci struct radeon_device *rdev = m->private; 86562306a36Sopenharmony_ci struct radeon_bo *rbo; 86662306a36Sopenharmony_ci unsigned i = 0; 86762306a36Sopenharmony_ci 86862306a36Sopenharmony_ci mutex_lock(&rdev->gem.mutex); 86962306a36Sopenharmony_ci list_for_each_entry(rbo, &rdev->gem.objects, list) { 87062306a36Sopenharmony_ci unsigned domain; 87162306a36Sopenharmony_ci const char *placement; 87262306a36Sopenharmony_ci 87362306a36Sopenharmony_ci domain = radeon_mem_type_to_domain(rbo->tbo.resource->mem_type); 87462306a36Sopenharmony_ci switch (domain) { 87562306a36Sopenharmony_ci case RADEON_GEM_DOMAIN_VRAM: 87662306a36Sopenharmony_ci placement = "VRAM"; 87762306a36Sopenharmony_ci break; 87862306a36Sopenharmony_ci case RADEON_GEM_DOMAIN_GTT: 87962306a36Sopenharmony_ci placement = " GTT"; 88062306a36Sopenharmony_ci break; 88162306a36Sopenharmony_ci case RADEON_GEM_DOMAIN_CPU: 88262306a36Sopenharmony_ci default: 88362306a36Sopenharmony_ci placement = " CPU"; 88462306a36Sopenharmony_ci break; 88562306a36Sopenharmony_ci } 88662306a36Sopenharmony_ci seq_printf(m, "bo[0x%08x] %8ldkB %8ldMB %s pid %8ld\n", 88762306a36Sopenharmony_ci i, radeon_bo_size(rbo) >> 10, radeon_bo_size(rbo) >> 20, 88862306a36Sopenharmony_ci placement, (unsigned long)rbo->pid); 88962306a36Sopenharmony_ci i++; 89062306a36Sopenharmony_ci } 89162306a36Sopenharmony_ci mutex_unlock(&rdev->gem.mutex); 89262306a36Sopenharmony_ci return 0; 89362306a36Sopenharmony_ci} 89462306a36Sopenharmony_ci 89562306a36Sopenharmony_ciDEFINE_SHOW_ATTRIBUTE(radeon_debugfs_gem_info); 89662306a36Sopenharmony_ci#endif 89762306a36Sopenharmony_ci 89862306a36Sopenharmony_civoid radeon_gem_debugfs_init(struct radeon_device *rdev) 89962306a36Sopenharmony_ci{ 90062306a36Sopenharmony_ci#if defined(CONFIG_DEBUG_FS) 90162306a36Sopenharmony_ci struct dentry *root = rdev->ddev->primary->debugfs_root; 90262306a36Sopenharmony_ci 90362306a36Sopenharmony_ci debugfs_create_file("radeon_gem_info", 0444, root, rdev, 90462306a36Sopenharmony_ci &radeon_debugfs_gem_info_fops); 90562306a36Sopenharmony_ci 90662306a36Sopenharmony_ci#endif 90762306a36Sopenharmony_ci} 908