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 * Christian König 2862306a36Sopenharmony_ci */ 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci#include <drm/drm_file.h> 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci#include "radeon.h" 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci/* 3562306a36Sopenharmony_ci * IB 3662306a36Sopenharmony_ci * IBs (Indirect Buffers) and areas of GPU accessible memory where 3762306a36Sopenharmony_ci * commands are stored. You can put a pointer to the IB in the 3862306a36Sopenharmony_ci * command ring and the hw will fetch the commands from the IB 3962306a36Sopenharmony_ci * and execute them. Generally userspace acceleration drivers 4062306a36Sopenharmony_ci * produce command buffers which are send to the kernel and 4162306a36Sopenharmony_ci * put in IBs for execution by the requested ring. 4262306a36Sopenharmony_ci */ 4362306a36Sopenharmony_cistatic void radeon_debugfs_sa_init(struct radeon_device *rdev); 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci/** 4662306a36Sopenharmony_ci * radeon_ib_get - request an IB (Indirect Buffer) 4762306a36Sopenharmony_ci * 4862306a36Sopenharmony_ci * @rdev: radeon_device pointer 4962306a36Sopenharmony_ci * @ring: ring index the IB is associated with 5062306a36Sopenharmony_ci * @vm: requested vm 5162306a36Sopenharmony_ci * @ib: IB object returned 5262306a36Sopenharmony_ci * @size: requested IB size 5362306a36Sopenharmony_ci * 5462306a36Sopenharmony_ci * Request an IB (all asics). IBs are allocated using the 5562306a36Sopenharmony_ci * suballocator. 5662306a36Sopenharmony_ci * Returns 0 on success, error on failure. 5762306a36Sopenharmony_ci */ 5862306a36Sopenharmony_ciint radeon_ib_get(struct radeon_device *rdev, int ring, 5962306a36Sopenharmony_ci struct radeon_ib *ib, struct radeon_vm *vm, 6062306a36Sopenharmony_ci unsigned size) 6162306a36Sopenharmony_ci{ 6262306a36Sopenharmony_ci int r; 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci r = radeon_sa_bo_new(&rdev->ring_tmp_bo, &ib->sa_bo, size, 256); 6562306a36Sopenharmony_ci if (r) { 6662306a36Sopenharmony_ci dev_err(rdev->dev, "failed to get a new IB (%d)\n", r); 6762306a36Sopenharmony_ci return r; 6862306a36Sopenharmony_ci } 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci radeon_sync_create(&ib->sync); 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci ib->ring = ring; 7362306a36Sopenharmony_ci ib->fence = NULL; 7462306a36Sopenharmony_ci ib->ptr = radeon_sa_bo_cpu_addr(ib->sa_bo); 7562306a36Sopenharmony_ci ib->vm = vm; 7662306a36Sopenharmony_ci if (vm) { 7762306a36Sopenharmony_ci /* ib pool is bound at RADEON_VA_IB_OFFSET in virtual address 7862306a36Sopenharmony_ci * space and soffset is the offset inside the pool bo 7962306a36Sopenharmony_ci */ 8062306a36Sopenharmony_ci ib->gpu_addr = drm_suballoc_soffset(ib->sa_bo) + RADEON_VA_IB_OFFSET; 8162306a36Sopenharmony_ci } else { 8262306a36Sopenharmony_ci ib->gpu_addr = radeon_sa_bo_gpu_addr(ib->sa_bo); 8362306a36Sopenharmony_ci } 8462306a36Sopenharmony_ci ib->is_const_ib = false; 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci return 0; 8762306a36Sopenharmony_ci} 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci/** 9062306a36Sopenharmony_ci * radeon_ib_free - free an IB (Indirect Buffer) 9162306a36Sopenharmony_ci * 9262306a36Sopenharmony_ci * @rdev: radeon_device pointer 9362306a36Sopenharmony_ci * @ib: IB object to free 9462306a36Sopenharmony_ci * 9562306a36Sopenharmony_ci * Free an IB (all asics). 9662306a36Sopenharmony_ci */ 9762306a36Sopenharmony_civoid radeon_ib_free(struct radeon_device *rdev, struct radeon_ib *ib) 9862306a36Sopenharmony_ci{ 9962306a36Sopenharmony_ci radeon_sync_free(rdev, &ib->sync, ib->fence); 10062306a36Sopenharmony_ci radeon_sa_bo_free(&ib->sa_bo, ib->fence); 10162306a36Sopenharmony_ci radeon_fence_unref(&ib->fence); 10262306a36Sopenharmony_ci} 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci/** 10562306a36Sopenharmony_ci * radeon_ib_schedule - schedule an IB (Indirect Buffer) on the ring 10662306a36Sopenharmony_ci * 10762306a36Sopenharmony_ci * @rdev: radeon_device pointer 10862306a36Sopenharmony_ci * @ib: IB object to schedule 10962306a36Sopenharmony_ci * @const_ib: Const IB to schedule (SI only) 11062306a36Sopenharmony_ci * @hdp_flush: Whether or not to perform an HDP cache flush 11162306a36Sopenharmony_ci * 11262306a36Sopenharmony_ci * Schedule an IB on the associated ring (all asics). 11362306a36Sopenharmony_ci * Returns 0 on success, error on failure. 11462306a36Sopenharmony_ci * 11562306a36Sopenharmony_ci * On SI, there are two parallel engines fed from the primary ring, 11662306a36Sopenharmony_ci * the CE (Constant Engine) and the DE (Drawing Engine). Since 11762306a36Sopenharmony_ci * resource descriptors have moved to memory, the CE allows you to 11862306a36Sopenharmony_ci * prime the caches while the DE is updating register state so that 11962306a36Sopenharmony_ci * the resource descriptors will be already in cache when the draw is 12062306a36Sopenharmony_ci * processed. To accomplish this, the userspace driver submits two 12162306a36Sopenharmony_ci * IBs, one for the CE and one for the DE. If there is a CE IB (called 12262306a36Sopenharmony_ci * a CONST_IB), it will be put on the ring prior to the DE IB. Prior 12362306a36Sopenharmony_ci * to SI there was just a DE IB. 12462306a36Sopenharmony_ci */ 12562306a36Sopenharmony_ciint radeon_ib_schedule(struct radeon_device *rdev, struct radeon_ib *ib, 12662306a36Sopenharmony_ci struct radeon_ib *const_ib, bool hdp_flush) 12762306a36Sopenharmony_ci{ 12862306a36Sopenharmony_ci struct radeon_ring *ring = &rdev->ring[ib->ring]; 12962306a36Sopenharmony_ci int r = 0; 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci if (!ib->length_dw || !ring->ready) { 13262306a36Sopenharmony_ci /* TODO: Nothings in the ib we should report. */ 13362306a36Sopenharmony_ci dev_err(rdev->dev, "couldn't schedule ib\n"); 13462306a36Sopenharmony_ci return -EINVAL; 13562306a36Sopenharmony_ci } 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci /* 64 dwords should be enough for fence too */ 13862306a36Sopenharmony_ci r = radeon_ring_lock(rdev, ring, 64 + RADEON_NUM_SYNCS * 8); 13962306a36Sopenharmony_ci if (r) { 14062306a36Sopenharmony_ci dev_err(rdev->dev, "scheduling IB failed (%d).\n", r); 14162306a36Sopenharmony_ci return r; 14262306a36Sopenharmony_ci } 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci /* grab a vm id if necessary */ 14562306a36Sopenharmony_ci if (ib->vm) { 14662306a36Sopenharmony_ci struct radeon_fence *vm_id_fence; 14762306a36Sopenharmony_ci vm_id_fence = radeon_vm_grab_id(rdev, ib->vm, ib->ring); 14862306a36Sopenharmony_ci radeon_sync_fence(&ib->sync, vm_id_fence); 14962306a36Sopenharmony_ci } 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci /* sync with other rings */ 15262306a36Sopenharmony_ci r = radeon_sync_rings(rdev, &ib->sync, ib->ring); 15362306a36Sopenharmony_ci if (r) { 15462306a36Sopenharmony_ci dev_err(rdev->dev, "failed to sync rings (%d)\n", r); 15562306a36Sopenharmony_ci radeon_ring_unlock_undo(rdev, ring); 15662306a36Sopenharmony_ci return r; 15762306a36Sopenharmony_ci } 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci if (ib->vm) 16062306a36Sopenharmony_ci radeon_vm_flush(rdev, ib->vm, ib->ring, 16162306a36Sopenharmony_ci ib->sync.last_vm_update); 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci if (const_ib) { 16462306a36Sopenharmony_ci radeon_ring_ib_execute(rdev, const_ib->ring, const_ib); 16562306a36Sopenharmony_ci radeon_sync_free(rdev, &const_ib->sync, NULL); 16662306a36Sopenharmony_ci } 16762306a36Sopenharmony_ci radeon_ring_ib_execute(rdev, ib->ring, ib); 16862306a36Sopenharmony_ci r = radeon_fence_emit(rdev, &ib->fence, ib->ring); 16962306a36Sopenharmony_ci if (r) { 17062306a36Sopenharmony_ci dev_err(rdev->dev, "failed to emit fence for new IB (%d)\n", r); 17162306a36Sopenharmony_ci radeon_ring_unlock_undo(rdev, ring); 17262306a36Sopenharmony_ci return r; 17362306a36Sopenharmony_ci } 17462306a36Sopenharmony_ci if (const_ib) { 17562306a36Sopenharmony_ci const_ib->fence = radeon_fence_ref(ib->fence); 17662306a36Sopenharmony_ci } 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci if (ib->vm) 17962306a36Sopenharmony_ci radeon_vm_fence(rdev, ib->vm, ib->fence); 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci radeon_ring_unlock_commit(rdev, ring, hdp_flush); 18262306a36Sopenharmony_ci return 0; 18362306a36Sopenharmony_ci} 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci/** 18662306a36Sopenharmony_ci * radeon_ib_pool_init - Init the IB (Indirect Buffer) pool 18762306a36Sopenharmony_ci * 18862306a36Sopenharmony_ci * @rdev: radeon_device pointer 18962306a36Sopenharmony_ci * 19062306a36Sopenharmony_ci * Initialize the suballocator to manage a pool of memory 19162306a36Sopenharmony_ci * for use as IBs (all asics). 19262306a36Sopenharmony_ci * Returns 0 on success, error on failure. 19362306a36Sopenharmony_ci */ 19462306a36Sopenharmony_ciint radeon_ib_pool_init(struct radeon_device *rdev) 19562306a36Sopenharmony_ci{ 19662306a36Sopenharmony_ci int r; 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci if (rdev->ib_pool_ready) { 19962306a36Sopenharmony_ci return 0; 20062306a36Sopenharmony_ci } 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci if (rdev->family >= CHIP_BONAIRE) { 20362306a36Sopenharmony_ci r = radeon_sa_bo_manager_init(rdev, &rdev->ring_tmp_bo, 20462306a36Sopenharmony_ci RADEON_IB_POOL_SIZE*64*1024, 256, 20562306a36Sopenharmony_ci RADEON_GEM_DOMAIN_GTT, 20662306a36Sopenharmony_ci RADEON_GEM_GTT_WC); 20762306a36Sopenharmony_ci } else { 20862306a36Sopenharmony_ci /* Before CIK, it's better to stick to cacheable GTT due 20962306a36Sopenharmony_ci * to the command stream checking 21062306a36Sopenharmony_ci */ 21162306a36Sopenharmony_ci r = radeon_sa_bo_manager_init(rdev, &rdev->ring_tmp_bo, 21262306a36Sopenharmony_ci RADEON_IB_POOL_SIZE*64*1024, 256, 21362306a36Sopenharmony_ci RADEON_GEM_DOMAIN_GTT, 0); 21462306a36Sopenharmony_ci } 21562306a36Sopenharmony_ci if (r) { 21662306a36Sopenharmony_ci return r; 21762306a36Sopenharmony_ci } 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci r = radeon_sa_bo_manager_start(rdev, &rdev->ring_tmp_bo); 22062306a36Sopenharmony_ci if (r) { 22162306a36Sopenharmony_ci return r; 22262306a36Sopenharmony_ci } 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci rdev->ib_pool_ready = true; 22562306a36Sopenharmony_ci radeon_debugfs_sa_init(rdev); 22662306a36Sopenharmony_ci return 0; 22762306a36Sopenharmony_ci} 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci/** 23062306a36Sopenharmony_ci * radeon_ib_pool_fini - Free the IB (Indirect Buffer) pool 23162306a36Sopenharmony_ci * 23262306a36Sopenharmony_ci * @rdev: radeon_device pointer 23362306a36Sopenharmony_ci * 23462306a36Sopenharmony_ci * Tear down the suballocator managing the pool of memory 23562306a36Sopenharmony_ci * for use as IBs (all asics). 23662306a36Sopenharmony_ci */ 23762306a36Sopenharmony_civoid radeon_ib_pool_fini(struct radeon_device *rdev) 23862306a36Sopenharmony_ci{ 23962306a36Sopenharmony_ci if (rdev->ib_pool_ready) { 24062306a36Sopenharmony_ci radeon_sa_bo_manager_suspend(rdev, &rdev->ring_tmp_bo); 24162306a36Sopenharmony_ci radeon_sa_bo_manager_fini(rdev, &rdev->ring_tmp_bo); 24262306a36Sopenharmony_ci rdev->ib_pool_ready = false; 24362306a36Sopenharmony_ci } 24462306a36Sopenharmony_ci} 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci/** 24762306a36Sopenharmony_ci * radeon_ib_ring_tests - test IBs on the rings 24862306a36Sopenharmony_ci * 24962306a36Sopenharmony_ci * @rdev: radeon_device pointer 25062306a36Sopenharmony_ci * 25162306a36Sopenharmony_ci * Test an IB (Indirect Buffer) on each ring. 25262306a36Sopenharmony_ci * If the test fails, disable the ring. 25362306a36Sopenharmony_ci * Returns 0 on success, error if the primary GFX ring 25462306a36Sopenharmony_ci * IB test fails. 25562306a36Sopenharmony_ci */ 25662306a36Sopenharmony_ciint radeon_ib_ring_tests(struct radeon_device *rdev) 25762306a36Sopenharmony_ci{ 25862306a36Sopenharmony_ci unsigned i; 25962306a36Sopenharmony_ci int r; 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci for (i = 0; i < RADEON_NUM_RINGS; ++i) { 26262306a36Sopenharmony_ci struct radeon_ring *ring = &rdev->ring[i]; 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci if (!ring->ready) 26562306a36Sopenharmony_ci continue; 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci r = radeon_ib_test(rdev, i, ring); 26862306a36Sopenharmony_ci if (r) { 26962306a36Sopenharmony_ci radeon_fence_driver_force_completion(rdev, i); 27062306a36Sopenharmony_ci ring->ready = false; 27162306a36Sopenharmony_ci rdev->needs_reset = false; 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci if (i == RADEON_RING_TYPE_GFX_INDEX) { 27462306a36Sopenharmony_ci /* oh, oh, that's really bad */ 27562306a36Sopenharmony_ci DRM_ERROR("radeon: failed testing IB on GFX ring (%d).\n", r); 27662306a36Sopenharmony_ci rdev->accel_working = false; 27762306a36Sopenharmony_ci return r; 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci } else { 28062306a36Sopenharmony_ci /* still not good, but we can live with it */ 28162306a36Sopenharmony_ci DRM_ERROR("radeon: failed testing IB on ring %d (%d).\n", i, r); 28262306a36Sopenharmony_ci } 28362306a36Sopenharmony_ci } 28462306a36Sopenharmony_ci } 28562306a36Sopenharmony_ci return 0; 28662306a36Sopenharmony_ci} 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci/* 28962306a36Sopenharmony_ci * Debugfs info 29062306a36Sopenharmony_ci */ 29162306a36Sopenharmony_ci#if defined(CONFIG_DEBUG_FS) 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_cistatic int radeon_debugfs_sa_info_show(struct seq_file *m, void *unused) 29462306a36Sopenharmony_ci{ 29562306a36Sopenharmony_ci struct radeon_device *rdev = m->private; 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci radeon_sa_bo_dump_debug_info(&rdev->ring_tmp_bo, m); 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci return 0; 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci} 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ciDEFINE_SHOW_ATTRIBUTE(radeon_debugfs_sa_info); 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci#endif 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_cistatic void radeon_debugfs_sa_init(struct radeon_device *rdev) 30862306a36Sopenharmony_ci{ 30962306a36Sopenharmony_ci#if defined(CONFIG_DEBUG_FS) 31062306a36Sopenharmony_ci struct dentry *root = rdev->ddev->primary->debugfs_root; 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci debugfs_create_file("radeon_sa_info", 0444, root, rdev, 31362306a36Sopenharmony_ci &radeon_debugfs_sa_info_fops); 31462306a36Sopenharmony_ci#endif 31562306a36Sopenharmony_ci} 316