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_device.h> 3162306a36Sopenharmony_ci#include <drm/drm_file.h> 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci#include "radeon.h" 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci/* 3662306a36Sopenharmony_ci * Rings 3762306a36Sopenharmony_ci * Most engines on the GPU are fed via ring buffers. Ring 3862306a36Sopenharmony_ci * buffers are areas of GPU accessible memory that the host 3962306a36Sopenharmony_ci * writes commands into and the GPU reads commands out of. 4062306a36Sopenharmony_ci * There is a rptr (read pointer) that determines where the 4162306a36Sopenharmony_ci * GPU is currently reading, and a wptr (write pointer) 4262306a36Sopenharmony_ci * which determines where the host has written. When the 4362306a36Sopenharmony_ci * pointers are equal, the ring is idle. When the host 4462306a36Sopenharmony_ci * writes commands to the ring buffer, it increments the 4562306a36Sopenharmony_ci * wptr. The GPU then starts fetching commands and executes 4662306a36Sopenharmony_ci * them until the pointers are equal again. 4762306a36Sopenharmony_ci */ 4862306a36Sopenharmony_cistatic void radeon_debugfs_ring_init(struct radeon_device *rdev, struct radeon_ring *ring); 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci/** 5162306a36Sopenharmony_ci * radeon_ring_supports_scratch_reg - check if the ring supports 5262306a36Sopenharmony_ci * writing to scratch registers 5362306a36Sopenharmony_ci * 5462306a36Sopenharmony_ci * @rdev: radeon_device pointer 5562306a36Sopenharmony_ci * @ring: radeon_ring structure holding ring information 5662306a36Sopenharmony_ci * 5762306a36Sopenharmony_ci * Check if a specific ring supports writing to scratch registers (all asics). 5862306a36Sopenharmony_ci * Returns true if the ring supports writing to scratch regs, false if not. 5962306a36Sopenharmony_ci */ 6062306a36Sopenharmony_cibool radeon_ring_supports_scratch_reg(struct radeon_device *rdev, 6162306a36Sopenharmony_ci struct radeon_ring *ring) 6262306a36Sopenharmony_ci{ 6362306a36Sopenharmony_ci switch (ring->idx) { 6462306a36Sopenharmony_ci case RADEON_RING_TYPE_GFX_INDEX: 6562306a36Sopenharmony_ci case CAYMAN_RING_TYPE_CP1_INDEX: 6662306a36Sopenharmony_ci case CAYMAN_RING_TYPE_CP2_INDEX: 6762306a36Sopenharmony_ci return true; 6862306a36Sopenharmony_ci default: 6962306a36Sopenharmony_ci return false; 7062306a36Sopenharmony_ci } 7162306a36Sopenharmony_ci} 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci/** 7462306a36Sopenharmony_ci * radeon_ring_free_size - update the free size 7562306a36Sopenharmony_ci * 7662306a36Sopenharmony_ci * @rdev: radeon_device pointer 7762306a36Sopenharmony_ci * @ring: radeon_ring structure holding ring information 7862306a36Sopenharmony_ci * 7962306a36Sopenharmony_ci * Update the free dw slots in the ring buffer (all asics). 8062306a36Sopenharmony_ci */ 8162306a36Sopenharmony_civoid radeon_ring_free_size(struct radeon_device *rdev, struct radeon_ring *ring) 8262306a36Sopenharmony_ci{ 8362306a36Sopenharmony_ci uint32_t rptr = radeon_ring_get_rptr(rdev, ring); 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci /* This works because ring_size is a power of 2 */ 8662306a36Sopenharmony_ci ring->ring_free_dw = rptr + (ring->ring_size / 4); 8762306a36Sopenharmony_ci ring->ring_free_dw -= ring->wptr; 8862306a36Sopenharmony_ci ring->ring_free_dw &= ring->ptr_mask; 8962306a36Sopenharmony_ci if (!ring->ring_free_dw) { 9062306a36Sopenharmony_ci /* this is an empty ring */ 9162306a36Sopenharmony_ci ring->ring_free_dw = ring->ring_size / 4; 9262306a36Sopenharmony_ci /* update lockup info to avoid false positive */ 9362306a36Sopenharmony_ci radeon_ring_lockup_update(rdev, ring); 9462306a36Sopenharmony_ci } 9562306a36Sopenharmony_ci} 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci/** 9862306a36Sopenharmony_ci * radeon_ring_alloc - allocate space on the ring buffer 9962306a36Sopenharmony_ci * 10062306a36Sopenharmony_ci * @rdev: radeon_device pointer 10162306a36Sopenharmony_ci * @ring: radeon_ring structure holding ring information 10262306a36Sopenharmony_ci * @ndw: number of dwords to allocate in the ring buffer 10362306a36Sopenharmony_ci * 10462306a36Sopenharmony_ci * Allocate @ndw dwords in the ring buffer (all asics). 10562306a36Sopenharmony_ci * Returns 0 on success, error on failure. 10662306a36Sopenharmony_ci */ 10762306a36Sopenharmony_ciint radeon_ring_alloc(struct radeon_device *rdev, struct radeon_ring *ring, unsigned ndw) 10862306a36Sopenharmony_ci{ 10962306a36Sopenharmony_ci int r; 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci /* make sure we aren't trying to allocate more space than there is on the ring */ 11262306a36Sopenharmony_ci if (ndw > (ring->ring_size / 4)) 11362306a36Sopenharmony_ci return -ENOMEM; 11462306a36Sopenharmony_ci /* Align requested size with padding so unlock_commit can 11562306a36Sopenharmony_ci * pad safely */ 11662306a36Sopenharmony_ci radeon_ring_free_size(rdev, ring); 11762306a36Sopenharmony_ci ndw = (ndw + ring->align_mask) & ~ring->align_mask; 11862306a36Sopenharmony_ci while (ndw > (ring->ring_free_dw - 1)) { 11962306a36Sopenharmony_ci radeon_ring_free_size(rdev, ring); 12062306a36Sopenharmony_ci if (ndw < ring->ring_free_dw) { 12162306a36Sopenharmony_ci break; 12262306a36Sopenharmony_ci } 12362306a36Sopenharmony_ci r = radeon_fence_wait_next(rdev, ring->idx); 12462306a36Sopenharmony_ci if (r) 12562306a36Sopenharmony_ci return r; 12662306a36Sopenharmony_ci } 12762306a36Sopenharmony_ci ring->count_dw = ndw; 12862306a36Sopenharmony_ci ring->wptr_old = ring->wptr; 12962306a36Sopenharmony_ci return 0; 13062306a36Sopenharmony_ci} 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci/** 13362306a36Sopenharmony_ci * radeon_ring_lock - lock the ring and allocate space on it 13462306a36Sopenharmony_ci * 13562306a36Sopenharmony_ci * @rdev: radeon_device pointer 13662306a36Sopenharmony_ci * @ring: radeon_ring structure holding ring information 13762306a36Sopenharmony_ci * @ndw: number of dwords to allocate in the ring buffer 13862306a36Sopenharmony_ci * 13962306a36Sopenharmony_ci * Lock the ring and allocate @ndw dwords in the ring buffer 14062306a36Sopenharmony_ci * (all asics). 14162306a36Sopenharmony_ci * Returns 0 on success, error on failure. 14262306a36Sopenharmony_ci */ 14362306a36Sopenharmony_ciint radeon_ring_lock(struct radeon_device *rdev, struct radeon_ring *ring, unsigned ndw) 14462306a36Sopenharmony_ci{ 14562306a36Sopenharmony_ci int r; 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci mutex_lock(&rdev->ring_lock); 14862306a36Sopenharmony_ci r = radeon_ring_alloc(rdev, ring, ndw); 14962306a36Sopenharmony_ci if (r) { 15062306a36Sopenharmony_ci mutex_unlock(&rdev->ring_lock); 15162306a36Sopenharmony_ci return r; 15262306a36Sopenharmony_ci } 15362306a36Sopenharmony_ci return 0; 15462306a36Sopenharmony_ci} 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci/** 15762306a36Sopenharmony_ci * radeon_ring_commit - tell the GPU to execute the new 15862306a36Sopenharmony_ci * commands on the ring buffer 15962306a36Sopenharmony_ci * 16062306a36Sopenharmony_ci * @rdev: radeon_device pointer 16162306a36Sopenharmony_ci * @ring: radeon_ring structure holding ring information 16262306a36Sopenharmony_ci * @hdp_flush: Whether or not to perform an HDP cache flush 16362306a36Sopenharmony_ci * 16462306a36Sopenharmony_ci * Update the wptr (write pointer) to tell the GPU to 16562306a36Sopenharmony_ci * execute new commands on the ring buffer (all asics). 16662306a36Sopenharmony_ci */ 16762306a36Sopenharmony_civoid radeon_ring_commit(struct radeon_device *rdev, struct radeon_ring *ring, 16862306a36Sopenharmony_ci bool hdp_flush) 16962306a36Sopenharmony_ci{ 17062306a36Sopenharmony_ci /* If we are emitting the HDP flush via the ring buffer, we need to 17162306a36Sopenharmony_ci * do it before padding. 17262306a36Sopenharmony_ci */ 17362306a36Sopenharmony_ci if (hdp_flush && rdev->asic->ring[ring->idx]->hdp_flush) 17462306a36Sopenharmony_ci rdev->asic->ring[ring->idx]->hdp_flush(rdev, ring); 17562306a36Sopenharmony_ci /* We pad to match fetch size */ 17662306a36Sopenharmony_ci while (ring->wptr & ring->align_mask) { 17762306a36Sopenharmony_ci radeon_ring_write(ring, ring->nop); 17862306a36Sopenharmony_ci } 17962306a36Sopenharmony_ci mb(); 18062306a36Sopenharmony_ci /* If we are emitting the HDP flush via MMIO, we need to do it after 18162306a36Sopenharmony_ci * all CPU writes to VRAM finished. 18262306a36Sopenharmony_ci */ 18362306a36Sopenharmony_ci if (hdp_flush && rdev->asic->mmio_hdp_flush) 18462306a36Sopenharmony_ci rdev->asic->mmio_hdp_flush(rdev); 18562306a36Sopenharmony_ci radeon_ring_set_wptr(rdev, ring); 18662306a36Sopenharmony_ci} 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci/** 18962306a36Sopenharmony_ci * radeon_ring_unlock_commit - tell the GPU to execute the new 19062306a36Sopenharmony_ci * commands on the ring buffer and unlock it 19162306a36Sopenharmony_ci * 19262306a36Sopenharmony_ci * @rdev: radeon_device pointer 19362306a36Sopenharmony_ci * @ring: radeon_ring structure holding ring information 19462306a36Sopenharmony_ci * @hdp_flush: Whether or not to perform an HDP cache flush 19562306a36Sopenharmony_ci * 19662306a36Sopenharmony_ci * Call radeon_ring_commit() then unlock the ring (all asics). 19762306a36Sopenharmony_ci */ 19862306a36Sopenharmony_civoid radeon_ring_unlock_commit(struct radeon_device *rdev, struct radeon_ring *ring, 19962306a36Sopenharmony_ci bool hdp_flush) 20062306a36Sopenharmony_ci{ 20162306a36Sopenharmony_ci radeon_ring_commit(rdev, ring, hdp_flush); 20262306a36Sopenharmony_ci mutex_unlock(&rdev->ring_lock); 20362306a36Sopenharmony_ci} 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci/** 20662306a36Sopenharmony_ci * radeon_ring_undo - reset the wptr 20762306a36Sopenharmony_ci * 20862306a36Sopenharmony_ci * @ring: radeon_ring structure holding ring information 20962306a36Sopenharmony_ci * 21062306a36Sopenharmony_ci * Reset the driver's copy of the wptr (all asics). 21162306a36Sopenharmony_ci */ 21262306a36Sopenharmony_civoid radeon_ring_undo(struct radeon_ring *ring) 21362306a36Sopenharmony_ci{ 21462306a36Sopenharmony_ci ring->wptr = ring->wptr_old; 21562306a36Sopenharmony_ci} 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci/** 21862306a36Sopenharmony_ci * radeon_ring_unlock_undo - reset the wptr and unlock the ring 21962306a36Sopenharmony_ci * 22062306a36Sopenharmony_ci * @rdev: radeon device structure 22162306a36Sopenharmony_ci * @ring: radeon_ring structure holding ring information 22262306a36Sopenharmony_ci * 22362306a36Sopenharmony_ci * Call radeon_ring_undo() then unlock the ring (all asics). 22462306a36Sopenharmony_ci */ 22562306a36Sopenharmony_civoid radeon_ring_unlock_undo(struct radeon_device *rdev, struct radeon_ring *ring) 22662306a36Sopenharmony_ci{ 22762306a36Sopenharmony_ci radeon_ring_undo(ring); 22862306a36Sopenharmony_ci mutex_unlock(&rdev->ring_lock); 22962306a36Sopenharmony_ci} 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci/** 23262306a36Sopenharmony_ci * radeon_ring_lockup_update - update lockup variables 23362306a36Sopenharmony_ci * 23462306a36Sopenharmony_ci * @rdev: radeon device structure 23562306a36Sopenharmony_ci * @ring: radeon_ring structure holding ring information 23662306a36Sopenharmony_ci * 23762306a36Sopenharmony_ci * Update the last rptr value and timestamp (all asics). 23862306a36Sopenharmony_ci */ 23962306a36Sopenharmony_civoid radeon_ring_lockup_update(struct radeon_device *rdev, 24062306a36Sopenharmony_ci struct radeon_ring *ring) 24162306a36Sopenharmony_ci{ 24262306a36Sopenharmony_ci atomic_set(&ring->last_rptr, radeon_ring_get_rptr(rdev, ring)); 24362306a36Sopenharmony_ci atomic64_set(&ring->last_activity, jiffies_64); 24462306a36Sopenharmony_ci} 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci/** 24762306a36Sopenharmony_ci * radeon_ring_test_lockup() - check if ring is lockedup by recording information 24862306a36Sopenharmony_ci * @rdev: radeon device structure 24962306a36Sopenharmony_ci * @ring: radeon_ring structure holding ring information 25062306a36Sopenharmony_ci * 25162306a36Sopenharmony_ci */ 25262306a36Sopenharmony_cibool radeon_ring_test_lockup(struct radeon_device *rdev, struct radeon_ring *ring) 25362306a36Sopenharmony_ci{ 25462306a36Sopenharmony_ci uint32_t rptr = radeon_ring_get_rptr(rdev, ring); 25562306a36Sopenharmony_ci uint64_t last = atomic64_read(&ring->last_activity); 25662306a36Sopenharmony_ci uint64_t elapsed; 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci if (rptr != atomic_read(&ring->last_rptr)) { 25962306a36Sopenharmony_ci /* ring is still working, no lockup */ 26062306a36Sopenharmony_ci radeon_ring_lockup_update(rdev, ring); 26162306a36Sopenharmony_ci return false; 26262306a36Sopenharmony_ci } 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci elapsed = jiffies_to_msecs(jiffies_64 - last); 26562306a36Sopenharmony_ci if (radeon_lockup_timeout && elapsed >= radeon_lockup_timeout) { 26662306a36Sopenharmony_ci dev_err(rdev->dev, "ring %d stalled for more than %llumsec\n", 26762306a36Sopenharmony_ci ring->idx, elapsed); 26862306a36Sopenharmony_ci return true; 26962306a36Sopenharmony_ci } 27062306a36Sopenharmony_ci /* give a chance to the GPU ... */ 27162306a36Sopenharmony_ci return false; 27262306a36Sopenharmony_ci} 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci/** 27562306a36Sopenharmony_ci * radeon_ring_backup - Back up the content of a ring 27662306a36Sopenharmony_ci * 27762306a36Sopenharmony_ci * @rdev: radeon_device pointer 27862306a36Sopenharmony_ci * @ring: the ring we want to back up 27962306a36Sopenharmony_ci * @data: placeholder for returned commit data 28062306a36Sopenharmony_ci * 28162306a36Sopenharmony_ci * Saves all unprocessed commits from a ring, returns the number of dwords saved. 28262306a36Sopenharmony_ci */ 28362306a36Sopenharmony_ciunsigned radeon_ring_backup(struct radeon_device *rdev, struct radeon_ring *ring, 28462306a36Sopenharmony_ci uint32_t **data) 28562306a36Sopenharmony_ci{ 28662306a36Sopenharmony_ci unsigned size, ptr, i; 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci /* just in case lock the ring */ 28962306a36Sopenharmony_ci mutex_lock(&rdev->ring_lock); 29062306a36Sopenharmony_ci *data = NULL; 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci if (ring->ring_obj == NULL) { 29362306a36Sopenharmony_ci mutex_unlock(&rdev->ring_lock); 29462306a36Sopenharmony_ci return 0; 29562306a36Sopenharmony_ci } 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci /* it doesn't make sense to save anything if all fences are signaled */ 29862306a36Sopenharmony_ci if (!radeon_fence_count_emitted(rdev, ring->idx)) { 29962306a36Sopenharmony_ci mutex_unlock(&rdev->ring_lock); 30062306a36Sopenharmony_ci return 0; 30162306a36Sopenharmony_ci } 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci /* calculate the number of dw on the ring */ 30462306a36Sopenharmony_ci if (ring->rptr_save_reg) 30562306a36Sopenharmony_ci ptr = RREG32(ring->rptr_save_reg); 30662306a36Sopenharmony_ci else if (rdev->wb.enabled) 30762306a36Sopenharmony_ci ptr = le32_to_cpu(*ring->next_rptr_cpu_addr); 30862306a36Sopenharmony_ci else { 30962306a36Sopenharmony_ci /* no way to read back the next rptr */ 31062306a36Sopenharmony_ci mutex_unlock(&rdev->ring_lock); 31162306a36Sopenharmony_ci return 0; 31262306a36Sopenharmony_ci } 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci size = ring->wptr + (ring->ring_size / 4); 31562306a36Sopenharmony_ci size -= ptr; 31662306a36Sopenharmony_ci size &= ring->ptr_mask; 31762306a36Sopenharmony_ci if (size == 0) { 31862306a36Sopenharmony_ci mutex_unlock(&rdev->ring_lock); 31962306a36Sopenharmony_ci return 0; 32062306a36Sopenharmony_ci } 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci /* and then save the content of the ring */ 32362306a36Sopenharmony_ci *data = kvmalloc_array(size, sizeof(uint32_t), GFP_KERNEL); 32462306a36Sopenharmony_ci if (!*data) { 32562306a36Sopenharmony_ci mutex_unlock(&rdev->ring_lock); 32662306a36Sopenharmony_ci return 0; 32762306a36Sopenharmony_ci } 32862306a36Sopenharmony_ci for (i = 0; i < size; ++i) { 32962306a36Sopenharmony_ci (*data)[i] = ring->ring[ptr++]; 33062306a36Sopenharmony_ci ptr &= ring->ptr_mask; 33162306a36Sopenharmony_ci } 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci mutex_unlock(&rdev->ring_lock); 33462306a36Sopenharmony_ci return size; 33562306a36Sopenharmony_ci} 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci/** 33862306a36Sopenharmony_ci * radeon_ring_restore - append saved commands to the ring again 33962306a36Sopenharmony_ci * 34062306a36Sopenharmony_ci * @rdev: radeon_device pointer 34162306a36Sopenharmony_ci * @ring: ring to append commands to 34262306a36Sopenharmony_ci * @size: number of dwords we want to write 34362306a36Sopenharmony_ci * @data: saved commands 34462306a36Sopenharmony_ci * 34562306a36Sopenharmony_ci * Allocates space on the ring and restore the previously saved commands. 34662306a36Sopenharmony_ci */ 34762306a36Sopenharmony_ciint radeon_ring_restore(struct radeon_device *rdev, struct radeon_ring *ring, 34862306a36Sopenharmony_ci unsigned size, uint32_t *data) 34962306a36Sopenharmony_ci{ 35062306a36Sopenharmony_ci int i, r; 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci if (!size || !data) 35362306a36Sopenharmony_ci return 0; 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci /* restore the saved ring content */ 35662306a36Sopenharmony_ci r = radeon_ring_lock(rdev, ring, size); 35762306a36Sopenharmony_ci if (r) 35862306a36Sopenharmony_ci return r; 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci for (i = 0; i < size; ++i) { 36162306a36Sopenharmony_ci radeon_ring_write(ring, data[i]); 36262306a36Sopenharmony_ci } 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci radeon_ring_unlock_commit(rdev, ring, false); 36562306a36Sopenharmony_ci kvfree(data); 36662306a36Sopenharmony_ci return 0; 36762306a36Sopenharmony_ci} 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci/** 37062306a36Sopenharmony_ci * radeon_ring_init - init driver ring struct. 37162306a36Sopenharmony_ci * 37262306a36Sopenharmony_ci * @rdev: radeon_device pointer 37362306a36Sopenharmony_ci * @ring: radeon_ring structure holding ring information 37462306a36Sopenharmony_ci * @ring_size: size of the ring 37562306a36Sopenharmony_ci * @rptr_offs: offset of the rptr writeback location in the WB buffer 37662306a36Sopenharmony_ci * @nop: nop packet for this ring 37762306a36Sopenharmony_ci * 37862306a36Sopenharmony_ci * Initialize the driver information for the selected ring (all asics). 37962306a36Sopenharmony_ci * Returns 0 on success, error on failure. 38062306a36Sopenharmony_ci */ 38162306a36Sopenharmony_ciint radeon_ring_init(struct radeon_device *rdev, struct radeon_ring *ring, unsigned ring_size, 38262306a36Sopenharmony_ci unsigned rptr_offs, u32 nop) 38362306a36Sopenharmony_ci{ 38462306a36Sopenharmony_ci int r; 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci ring->ring_size = ring_size; 38762306a36Sopenharmony_ci ring->rptr_offs = rptr_offs; 38862306a36Sopenharmony_ci ring->nop = nop; 38962306a36Sopenharmony_ci ring->rdev = rdev; 39062306a36Sopenharmony_ci /* Allocate ring buffer */ 39162306a36Sopenharmony_ci if (ring->ring_obj == NULL) { 39262306a36Sopenharmony_ci r = radeon_bo_create(rdev, ring->ring_size, PAGE_SIZE, true, 39362306a36Sopenharmony_ci RADEON_GEM_DOMAIN_GTT, 0, NULL, 39462306a36Sopenharmony_ci NULL, &ring->ring_obj); 39562306a36Sopenharmony_ci if (r) { 39662306a36Sopenharmony_ci dev_err(rdev->dev, "(%d) ring create failed\n", r); 39762306a36Sopenharmony_ci return r; 39862306a36Sopenharmony_ci } 39962306a36Sopenharmony_ci r = radeon_bo_reserve(ring->ring_obj, false); 40062306a36Sopenharmony_ci if (unlikely(r != 0)) 40162306a36Sopenharmony_ci return r; 40262306a36Sopenharmony_ci r = radeon_bo_pin(ring->ring_obj, RADEON_GEM_DOMAIN_GTT, 40362306a36Sopenharmony_ci &ring->gpu_addr); 40462306a36Sopenharmony_ci if (r) { 40562306a36Sopenharmony_ci radeon_bo_unreserve(ring->ring_obj); 40662306a36Sopenharmony_ci dev_err(rdev->dev, "(%d) ring pin failed\n", r); 40762306a36Sopenharmony_ci return r; 40862306a36Sopenharmony_ci } 40962306a36Sopenharmony_ci r = radeon_bo_kmap(ring->ring_obj, 41062306a36Sopenharmony_ci (void **)&ring->ring); 41162306a36Sopenharmony_ci radeon_bo_unreserve(ring->ring_obj); 41262306a36Sopenharmony_ci if (r) { 41362306a36Sopenharmony_ci dev_err(rdev->dev, "(%d) ring map failed\n", r); 41462306a36Sopenharmony_ci return r; 41562306a36Sopenharmony_ci } 41662306a36Sopenharmony_ci } 41762306a36Sopenharmony_ci ring->ptr_mask = (ring->ring_size / 4) - 1; 41862306a36Sopenharmony_ci ring->ring_free_dw = ring->ring_size / 4; 41962306a36Sopenharmony_ci if (rdev->wb.enabled) { 42062306a36Sopenharmony_ci u32 index = RADEON_WB_RING0_NEXT_RPTR + (ring->idx * 4); 42162306a36Sopenharmony_ci ring->next_rptr_gpu_addr = rdev->wb.gpu_addr + index; 42262306a36Sopenharmony_ci ring->next_rptr_cpu_addr = &rdev->wb.wb[index/4]; 42362306a36Sopenharmony_ci } 42462306a36Sopenharmony_ci radeon_debugfs_ring_init(rdev, ring); 42562306a36Sopenharmony_ci radeon_ring_lockup_update(rdev, ring); 42662306a36Sopenharmony_ci return 0; 42762306a36Sopenharmony_ci} 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci/** 43062306a36Sopenharmony_ci * radeon_ring_fini - tear down the driver ring struct. 43162306a36Sopenharmony_ci * 43262306a36Sopenharmony_ci * @rdev: radeon_device pointer 43362306a36Sopenharmony_ci * @ring: radeon_ring structure holding ring information 43462306a36Sopenharmony_ci * 43562306a36Sopenharmony_ci * Tear down the driver information for the selected ring (all asics). 43662306a36Sopenharmony_ci */ 43762306a36Sopenharmony_civoid radeon_ring_fini(struct radeon_device *rdev, struct radeon_ring *ring) 43862306a36Sopenharmony_ci{ 43962306a36Sopenharmony_ci int r; 44062306a36Sopenharmony_ci struct radeon_bo *ring_obj; 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci mutex_lock(&rdev->ring_lock); 44362306a36Sopenharmony_ci ring_obj = ring->ring_obj; 44462306a36Sopenharmony_ci ring->ready = false; 44562306a36Sopenharmony_ci ring->ring = NULL; 44662306a36Sopenharmony_ci ring->ring_obj = NULL; 44762306a36Sopenharmony_ci mutex_unlock(&rdev->ring_lock); 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci if (ring_obj) { 45062306a36Sopenharmony_ci r = radeon_bo_reserve(ring_obj, false); 45162306a36Sopenharmony_ci if (likely(r == 0)) { 45262306a36Sopenharmony_ci radeon_bo_kunmap(ring_obj); 45362306a36Sopenharmony_ci radeon_bo_unpin(ring_obj); 45462306a36Sopenharmony_ci radeon_bo_unreserve(ring_obj); 45562306a36Sopenharmony_ci } 45662306a36Sopenharmony_ci radeon_bo_unref(&ring_obj); 45762306a36Sopenharmony_ci } 45862306a36Sopenharmony_ci} 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci/* 46162306a36Sopenharmony_ci * Debugfs info 46262306a36Sopenharmony_ci */ 46362306a36Sopenharmony_ci#if defined(CONFIG_DEBUG_FS) 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_cistatic int radeon_debugfs_ring_info_show(struct seq_file *m, void *unused) 46662306a36Sopenharmony_ci{ 46762306a36Sopenharmony_ci struct radeon_ring *ring = m->private; 46862306a36Sopenharmony_ci struct radeon_device *rdev = ring->rdev; 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci uint32_t rptr, wptr, rptr_next; 47162306a36Sopenharmony_ci unsigned count, i, j; 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci radeon_ring_free_size(rdev, ring); 47462306a36Sopenharmony_ci count = (ring->ring_size / 4) - ring->ring_free_dw; 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci wptr = radeon_ring_get_wptr(rdev, ring); 47762306a36Sopenharmony_ci seq_printf(m, "wptr: 0x%08x [%5d]\n", 47862306a36Sopenharmony_ci wptr, wptr); 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_ci rptr = radeon_ring_get_rptr(rdev, ring); 48162306a36Sopenharmony_ci seq_printf(m, "rptr: 0x%08x [%5d]\n", 48262306a36Sopenharmony_ci rptr, rptr); 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ci if (ring->rptr_save_reg) { 48562306a36Sopenharmony_ci rptr_next = RREG32(ring->rptr_save_reg); 48662306a36Sopenharmony_ci seq_printf(m, "rptr next(0x%04x): 0x%08x [%5d]\n", 48762306a36Sopenharmony_ci ring->rptr_save_reg, rptr_next, rptr_next); 48862306a36Sopenharmony_ci } else 48962306a36Sopenharmony_ci rptr_next = ~0; 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci seq_printf(m, "driver's copy of the wptr: 0x%08x [%5d]\n", 49262306a36Sopenharmony_ci ring->wptr, ring->wptr); 49362306a36Sopenharmony_ci seq_printf(m, "last semaphore signal addr : 0x%016llx\n", 49462306a36Sopenharmony_ci ring->last_semaphore_signal_addr); 49562306a36Sopenharmony_ci seq_printf(m, "last semaphore wait addr : 0x%016llx\n", 49662306a36Sopenharmony_ci ring->last_semaphore_wait_addr); 49762306a36Sopenharmony_ci seq_printf(m, "%u free dwords in ring\n", ring->ring_free_dw); 49862306a36Sopenharmony_ci seq_printf(m, "%u dwords in ring\n", count); 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci if (!ring->ring) 50162306a36Sopenharmony_ci return 0; 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci /* print 8 dw before current rptr as often it's the last executed 50462306a36Sopenharmony_ci * packet that is the root issue 50562306a36Sopenharmony_ci */ 50662306a36Sopenharmony_ci i = (rptr + ring->ptr_mask + 1 - 32) & ring->ptr_mask; 50762306a36Sopenharmony_ci for (j = 0; j <= (count + 32); j++) { 50862306a36Sopenharmony_ci seq_printf(m, "r[%5d]=0x%08x", i, ring->ring[i]); 50962306a36Sopenharmony_ci if (rptr == i) 51062306a36Sopenharmony_ci seq_puts(m, " *"); 51162306a36Sopenharmony_ci if (rptr_next == i) 51262306a36Sopenharmony_ci seq_puts(m, " #"); 51362306a36Sopenharmony_ci seq_puts(m, "\n"); 51462306a36Sopenharmony_ci i = (i + 1) & ring->ptr_mask; 51562306a36Sopenharmony_ci } 51662306a36Sopenharmony_ci return 0; 51762306a36Sopenharmony_ci} 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ciDEFINE_SHOW_ATTRIBUTE(radeon_debugfs_ring_info); 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_cistatic const char *radeon_debugfs_ring_idx_to_name(uint32_t ridx) 52262306a36Sopenharmony_ci{ 52362306a36Sopenharmony_ci switch (ridx) { 52462306a36Sopenharmony_ci case RADEON_RING_TYPE_GFX_INDEX: 52562306a36Sopenharmony_ci return "radeon_ring_gfx"; 52662306a36Sopenharmony_ci case CAYMAN_RING_TYPE_CP1_INDEX: 52762306a36Sopenharmony_ci return "radeon_ring_cp1"; 52862306a36Sopenharmony_ci case CAYMAN_RING_TYPE_CP2_INDEX: 52962306a36Sopenharmony_ci return "radeon_ring_cp2"; 53062306a36Sopenharmony_ci case R600_RING_TYPE_DMA_INDEX: 53162306a36Sopenharmony_ci return "radeon_ring_dma1"; 53262306a36Sopenharmony_ci case CAYMAN_RING_TYPE_DMA1_INDEX: 53362306a36Sopenharmony_ci return "radeon_ring_dma2"; 53462306a36Sopenharmony_ci case R600_RING_TYPE_UVD_INDEX: 53562306a36Sopenharmony_ci return "radeon_ring_uvd"; 53662306a36Sopenharmony_ci case TN_RING_TYPE_VCE1_INDEX: 53762306a36Sopenharmony_ci return "radeon_ring_vce1"; 53862306a36Sopenharmony_ci case TN_RING_TYPE_VCE2_INDEX: 53962306a36Sopenharmony_ci return "radeon_ring_vce2"; 54062306a36Sopenharmony_ci default: 54162306a36Sopenharmony_ci return NULL; 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci } 54462306a36Sopenharmony_ci} 54562306a36Sopenharmony_ci#endif 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_cistatic void radeon_debugfs_ring_init(struct radeon_device *rdev, struct radeon_ring *ring) 54862306a36Sopenharmony_ci{ 54962306a36Sopenharmony_ci#if defined(CONFIG_DEBUG_FS) 55062306a36Sopenharmony_ci const char *ring_name = radeon_debugfs_ring_idx_to_name(ring->idx); 55162306a36Sopenharmony_ci struct dentry *root = rdev->ddev->primary->debugfs_root; 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_ci if (ring_name) 55462306a36Sopenharmony_ci debugfs_create_file(ring_name, 0444, root, ring, 55562306a36Sopenharmony_ci &radeon_debugfs_ring_info_fops); 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci#endif 55862306a36Sopenharmony_ci} 559