162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * Copyright 2009 Jerome Glisse. 362306a36Sopenharmony_ci * All Rights Reserved. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 662306a36Sopenharmony_ci * copy of this software and associated documentation files (the 762306a36Sopenharmony_ci * "Software"), to deal in the Software without restriction, including 862306a36Sopenharmony_ci * without limitation the rights to use, copy, modify, merge, publish, 962306a36Sopenharmony_ci * distribute, sub license, and/or sell copies of the Software, and to 1062306a36Sopenharmony_ci * permit persons to whom the Software is furnished to do so, subject to 1162306a36Sopenharmony_ci * the following conditions: 1262306a36Sopenharmony_ci * 1362306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1462306a36Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1562306a36Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL 1662306a36Sopenharmony_ci * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, 1762306a36Sopenharmony_ci * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 1862306a36Sopenharmony_ci * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 1962306a36Sopenharmony_ci * USE OR OTHER DEALINGS IN THE SOFTWARE. 2062306a36Sopenharmony_ci * 2162306a36Sopenharmony_ci * The above copyright notice and this permission notice (including the 2262306a36Sopenharmony_ci * next paragraph) shall be included in all copies or substantial portions 2362306a36Sopenharmony_ci * of the Software. 2462306a36Sopenharmony_ci * 2562306a36Sopenharmony_ci */ 2662306a36Sopenharmony_ci/* 2762306a36Sopenharmony_ci * Authors: 2862306a36Sopenharmony_ci * Jerome Glisse <glisse@freedesktop.org> 2962306a36Sopenharmony_ci * Dave Airlie 3062306a36Sopenharmony_ci */ 3162306a36Sopenharmony_ci#include <linux/seq_file.h> 3262306a36Sopenharmony_ci#include <linux/atomic.h> 3362306a36Sopenharmony_ci#include <linux/wait.h> 3462306a36Sopenharmony_ci#include <linux/kref.h> 3562306a36Sopenharmony_ci#include <linux/slab.h> 3662306a36Sopenharmony_ci#include <linux/firmware.h> 3762306a36Sopenharmony_ci#include <linux/pm_runtime.h> 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci#include <drm/drm_drv.h> 4062306a36Sopenharmony_ci#include "amdgpu.h" 4162306a36Sopenharmony_ci#include "amdgpu_trace.h" 4262306a36Sopenharmony_ci#include "amdgpu_reset.h" 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci/* 4562306a36Sopenharmony_ci * Fences mark an event in the GPUs pipeline and are used 4662306a36Sopenharmony_ci * for GPU/CPU synchronization. When the fence is written, 4762306a36Sopenharmony_ci * it is expected that all buffers associated with that fence 4862306a36Sopenharmony_ci * are no longer in use by the associated ring on the GPU and 4962306a36Sopenharmony_ci * that the relevant GPU caches have been flushed. 5062306a36Sopenharmony_ci */ 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_cistruct amdgpu_fence { 5362306a36Sopenharmony_ci struct dma_fence base; 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci /* RB, DMA, etc. */ 5662306a36Sopenharmony_ci struct amdgpu_ring *ring; 5762306a36Sopenharmony_ci ktime_t start_timestamp; 5862306a36Sopenharmony_ci}; 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_cistatic struct kmem_cache *amdgpu_fence_slab; 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ciint amdgpu_fence_slab_init(void) 6362306a36Sopenharmony_ci{ 6462306a36Sopenharmony_ci amdgpu_fence_slab = kmem_cache_create( 6562306a36Sopenharmony_ci "amdgpu_fence", sizeof(struct amdgpu_fence), 0, 6662306a36Sopenharmony_ci SLAB_HWCACHE_ALIGN, NULL); 6762306a36Sopenharmony_ci if (!amdgpu_fence_slab) 6862306a36Sopenharmony_ci return -ENOMEM; 6962306a36Sopenharmony_ci return 0; 7062306a36Sopenharmony_ci} 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_civoid amdgpu_fence_slab_fini(void) 7362306a36Sopenharmony_ci{ 7462306a36Sopenharmony_ci rcu_barrier(); 7562306a36Sopenharmony_ci kmem_cache_destroy(amdgpu_fence_slab); 7662306a36Sopenharmony_ci} 7762306a36Sopenharmony_ci/* 7862306a36Sopenharmony_ci * Cast helper 7962306a36Sopenharmony_ci */ 8062306a36Sopenharmony_cistatic const struct dma_fence_ops amdgpu_fence_ops; 8162306a36Sopenharmony_cistatic const struct dma_fence_ops amdgpu_job_fence_ops; 8262306a36Sopenharmony_cistatic inline struct amdgpu_fence *to_amdgpu_fence(struct dma_fence *f) 8362306a36Sopenharmony_ci{ 8462306a36Sopenharmony_ci struct amdgpu_fence *__f = container_of(f, struct amdgpu_fence, base); 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci if (__f->base.ops == &amdgpu_fence_ops || 8762306a36Sopenharmony_ci __f->base.ops == &amdgpu_job_fence_ops) 8862306a36Sopenharmony_ci return __f; 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci return NULL; 9162306a36Sopenharmony_ci} 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci/** 9462306a36Sopenharmony_ci * amdgpu_fence_write - write a fence value 9562306a36Sopenharmony_ci * 9662306a36Sopenharmony_ci * @ring: ring the fence is associated with 9762306a36Sopenharmony_ci * @seq: sequence number to write 9862306a36Sopenharmony_ci * 9962306a36Sopenharmony_ci * Writes a fence value to memory (all asics). 10062306a36Sopenharmony_ci */ 10162306a36Sopenharmony_cistatic void amdgpu_fence_write(struct amdgpu_ring *ring, u32 seq) 10262306a36Sopenharmony_ci{ 10362306a36Sopenharmony_ci struct amdgpu_fence_driver *drv = &ring->fence_drv; 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci if (drv->cpu_addr) 10662306a36Sopenharmony_ci *drv->cpu_addr = cpu_to_le32(seq); 10762306a36Sopenharmony_ci} 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci/** 11062306a36Sopenharmony_ci * amdgpu_fence_read - read a fence value 11162306a36Sopenharmony_ci * 11262306a36Sopenharmony_ci * @ring: ring the fence is associated with 11362306a36Sopenharmony_ci * 11462306a36Sopenharmony_ci * Reads a fence value from memory (all asics). 11562306a36Sopenharmony_ci * Returns the value of the fence read from memory. 11662306a36Sopenharmony_ci */ 11762306a36Sopenharmony_cistatic u32 amdgpu_fence_read(struct amdgpu_ring *ring) 11862306a36Sopenharmony_ci{ 11962306a36Sopenharmony_ci struct amdgpu_fence_driver *drv = &ring->fence_drv; 12062306a36Sopenharmony_ci u32 seq = 0; 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci if (drv->cpu_addr) 12362306a36Sopenharmony_ci seq = le32_to_cpu(*drv->cpu_addr); 12462306a36Sopenharmony_ci else 12562306a36Sopenharmony_ci seq = atomic_read(&drv->last_seq); 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci return seq; 12862306a36Sopenharmony_ci} 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci/** 13162306a36Sopenharmony_ci * amdgpu_fence_emit - emit a fence on the requested ring 13262306a36Sopenharmony_ci * 13362306a36Sopenharmony_ci * @ring: ring the fence is associated with 13462306a36Sopenharmony_ci * @f: resulting fence object 13562306a36Sopenharmony_ci * @job: job the fence is embedded in 13662306a36Sopenharmony_ci * @flags: flags to pass into the subordinate .emit_fence() call 13762306a36Sopenharmony_ci * 13862306a36Sopenharmony_ci * Emits a fence command on the requested ring (all asics). 13962306a36Sopenharmony_ci * Returns 0 on success, -ENOMEM on failure. 14062306a36Sopenharmony_ci */ 14162306a36Sopenharmony_ciint amdgpu_fence_emit(struct amdgpu_ring *ring, struct dma_fence **f, struct amdgpu_job *job, 14262306a36Sopenharmony_ci unsigned int flags) 14362306a36Sopenharmony_ci{ 14462306a36Sopenharmony_ci struct amdgpu_device *adev = ring->adev; 14562306a36Sopenharmony_ci struct dma_fence *fence; 14662306a36Sopenharmony_ci struct amdgpu_fence *am_fence; 14762306a36Sopenharmony_ci struct dma_fence __rcu **ptr; 14862306a36Sopenharmony_ci uint32_t seq; 14962306a36Sopenharmony_ci int r; 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci if (job == NULL) { 15262306a36Sopenharmony_ci /* create a sperate hw fence */ 15362306a36Sopenharmony_ci am_fence = kmem_cache_alloc(amdgpu_fence_slab, GFP_ATOMIC); 15462306a36Sopenharmony_ci if (am_fence == NULL) 15562306a36Sopenharmony_ci return -ENOMEM; 15662306a36Sopenharmony_ci fence = &am_fence->base; 15762306a36Sopenharmony_ci am_fence->ring = ring; 15862306a36Sopenharmony_ci } else { 15962306a36Sopenharmony_ci /* take use of job-embedded fence */ 16062306a36Sopenharmony_ci fence = &job->hw_fence; 16162306a36Sopenharmony_ci } 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci seq = ++ring->fence_drv.sync_seq; 16462306a36Sopenharmony_ci if (job && job->job_run_counter) { 16562306a36Sopenharmony_ci /* reinit seq for resubmitted jobs */ 16662306a36Sopenharmony_ci fence->seqno = seq; 16762306a36Sopenharmony_ci /* TO be inline with external fence creation and other drivers */ 16862306a36Sopenharmony_ci dma_fence_get(fence); 16962306a36Sopenharmony_ci } else { 17062306a36Sopenharmony_ci if (job) { 17162306a36Sopenharmony_ci dma_fence_init(fence, &amdgpu_job_fence_ops, 17262306a36Sopenharmony_ci &ring->fence_drv.lock, 17362306a36Sopenharmony_ci adev->fence_context + ring->idx, seq); 17462306a36Sopenharmony_ci /* Against remove in amdgpu_job_{free, free_cb} */ 17562306a36Sopenharmony_ci dma_fence_get(fence); 17662306a36Sopenharmony_ci } else { 17762306a36Sopenharmony_ci dma_fence_init(fence, &amdgpu_fence_ops, 17862306a36Sopenharmony_ci &ring->fence_drv.lock, 17962306a36Sopenharmony_ci adev->fence_context + ring->idx, seq); 18062306a36Sopenharmony_ci } 18162306a36Sopenharmony_ci } 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci amdgpu_ring_emit_fence(ring, ring->fence_drv.gpu_addr, 18462306a36Sopenharmony_ci seq, flags | AMDGPU_FENCE_FLAG_INT); 18562306a36Sopenharmony_ci pm_runtime_get_noresume(adev_to_drm(adev)->dev); 18662306a36Sopenharmony_ci ptr = &ring->fence_drv.fences[seq & ring->fence_drv.num_fences_mask]; 18762306a36Sopenharmony_ci if (unlikely(rcu_dereference_protected(*ptr, 1))) { 18862306a36Sopenharmony_ci struct dma_fence *old; 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci rcu_read_lock(); 19162306a36Sopenharmony_ci old = dma_fence_get_rcu_safe(ptr); 19262306a36Sopenharmony_ci rcu_read_unlock(); 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci if (old) { 19562306a36Sopenharmony_ci r = dma_fence_wait(old, false); 19662306a36Sopenharmony_ci dma_fence_put(old); 19762306a36Sopenharmony_ci if (r) 19862306a36Sopenharmony_ci return r; 19962306a36Sopenharmony_ci } 20062306a36Sopenharmony_ci } 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci to_amdgpu_fence(fence)->start_timestamp = ktime_get(); 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci /* This function can't be called concurrently anyway, otherwise 20562306a36Sopenharmony_ci * emitting the fence would mess up the hardware ring buffer. 20662306a36Sopenharmony_ci */ 20762306a36Sopenharmony_ci rcu_assign_pointer(*ptr, dma_fence_get(fence)); 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci *f = fence; 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci return 0; 21262306a36Sopenharmony_ci} 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci/** 21562306a36Sopenharmony_ci * amdgpu_fence_emit_polling - emit a fence on the requeste ring 21662306a36Sopenharmony_ci * 21762306a36Sopenharmony_ci * @ring: ring the fence is associated with 21862306a36Sopenharmony_ci * @s: resulting sequence number 21962306a36Sopenharmony_ci * @timeout: the timeout for waiting in usecs 22062306a36Sopenharmony_ci * 22162306a36Sopenharmony_ci * Emits a fence command on the requested ring (all asics). 22262306a36Sopenharmony_ci * Used For polling fence. 22362306a36Sopenharmony_ci * Returns 0 on success, -ENOMEM on failure. 22462306a36Sopenharmony_ci */ 22562306a36Sopenharmony_ciint amdgpu_fence_emit_polling(struct amdgpu_ring *ring, uint32_t *s, 22662306a36Sopenharmony_ci uint32_t timeout) 22762306a36Sopenharmony_ci{ 22862306a36Sopenharmony_ci uint32_t seq; 22962306a36Sopenharmony_ci signed long r; 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci if (!s) 23262306a36Sopenharmony_ci return -EINVAL; 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci seq = ++ring->fence_drv.sync_seq; 23562306a36Sopenharmony_ci r = amdgpu_fence_wait_polling(ring, 23662306a36Sopenharmony_ci seq - ring->fence_drv.num_fences_mask, 23762306a36Sopenharmony_ci timeout); 23862306a36Sopenharmony_ci if (r < 1) 23962306a36Sopenharmony_ci return -ETIMEDOUT; 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci amdgpu_ring_emit_fence(ring, ring->fence_drv.gpu_addr, 24262306a36Sopenharmony_ci seq, 0); 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci *s = seq; 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci return 0; 24762306a36Sopenharmony_ci} 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci/** 25062306a36Sopenharmony_ci * amdgpu_fence_schedule_fallback - schedule fallback check 25162306a36Sopenharmony_ci * 25262306a36Sopenharmony_ci * @ring: pointer to struct amdgpu_ring 25362306a36Sopenharmony_ci * 25462306a36Sopenharmony_ci * Start a timer as fallback to our interrupts. 25562306a36Sopenharmony_ci */ 25662306a36Sopenharmony_cistatic void amdgpu_fence_schedule_fallback(struct amdgpu_ring *ring) 25762306a36Sopenharmony_ci{ 25862306a36Sopenharmony_ci mod_timer(&ring->fence_drv.fallback_timer, 25962306a36Sopenharmony_ci jiffies + AMDGPU_FENCE_JIFFIES_TIMEOUT); 26062306a36Sopenharmony_ci} 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci/** 26362306a36Sopenharmony_ci * amdgpu_fence_process - check for fence activity 26462306a36Sopenharmony_ci * 26562306a36Sopenharmony_ci * @ring: pointer to struct amdgpu_ring 26662306a36Sopenharmony_ci * 26762306a36Sopenharmony_ci * Checks the current fence value and calculates the last 26862306a36Sopenharmony_ci * signalled fence value. Wakes the fence queue if the 26962306a36Sopenharmony_ci * sequence number has increased. 27062306a36Sopenharmony_ci * 27162306a36Sopenharmony_ci * Returns true if fence was processed 27262306a36Sopenharmony_ci */ 27362306a36Sopenharmony_cibool amdgpu_fence_process(struct amdgpu_ring *ring) 27462306a36Sopenharmony_ci{ 27562306a36Sopenharmony_ci struct amdgpu_fence_driver *drv = &ring->fence_drv; 27662306a36Sopenharmony_ci struct amdgpu_device *adev = ring->adev; 27762306a36Sopenharmony_ci uint32_t seq, last_seq; 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci do { 28062306a36Sopenharmony_ci last_seq = atomic_read(&ring->fence_drv.last_seq); 28162306a36Sopenharmony_ci seq = amdgpu_fence_read(ring); 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci } while (atomic_cmpxchg(&drv->last_seq, last_seq, seq) != last_seq); 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci if (del_timer(&ring->fence_drv.fallback_timer) && 28662306a36Sopenharmony_ci seq != ring->fence_drv.sync_seq) 28762306a36Sopenharmony_ci amdgpu_fence_schedule_fallback(ring); 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci if (unlikely(seq == last_seq)) 29062306a36Sopenharmony_ci return false; 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci last_seq &= drv->num_fences_mask; 29362306a36Sopenharmony_ci seq &= drv->num_fences_mask; 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci do { 29662306a36Sopenharmony_ci struct dma_fence *fence, **ptr; 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci ++last_seq; 29962306a36Sopenharmony_ci last_seq &= drv->num_fences_mask; 30062306a36Sopenharmony_ci ptr = &drv->fences[last_seq]; 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci /* There is always exactly one thread signaling this fence slot */ 30362306a36Sopenharmony_ci fence = rcu_dereference_protected(*ptr, 1); 30462306a36Sopenharmony_ci RCU_INIT_POINTER(*ptr, NULL); 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci if (!fence) 30762306a36Sopenharmony_ci continue; 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci dma_fence_signal(fence); 31062306a36Sopenharmony_ci dma_fence_put(fence); 31162306a36Sopenharmony_ci pm_runtime_mark_last_busy(adev_to_drm(adev)->dev); 31262306a36Sopenharmony_ci pm_runtime_put_autosuspend(adev_to_drm(adev)->dev); 31362306a36Sopenharmony_ci } while (last_seq != seq); 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci return true; 31662306a36Sopenharmony_ci} 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci/** 31962306a36Sopenharmony_ci * amdgpu_fence_fallback - fallback for hardware interrupts 32062306a36Sopenharmony_ci * 32162306a36Sopenharmony_ci * @t: timer context used to obtain the pointer to ring structure 32262306a36Sopenharmony_ci * 32362306a36Sopenharmony_ci * Checks for fence activity. 32462306a36Sopenharmony_ci */ 32562306a36Sopenharmony_cistatic void amdgpu_fence_fallback(struct timer_list *t) 32662306a36Sopenharmony_ci{ 32762306a36Sopenharmony_ci struct amdgpu_ring *ring = from_timer(ring, t, 32862306a36Sopenharmony_ci fence_drv.fallback_timer); 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci if (amdgpu_fence_process(ring)) 33162306a36Sopenharmony_ci DRM_WARN("Fence fallback timer expired on ring %s\n", ring->name); 33262306a36Sopenharmony_ci} 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci/** 33562306a36Sopenharmony_ci * amdgpu_fence_wait_empty - wait for all fences to signal 33662306a36Sopenharmony_ci * 33762306a36Sopenharmony_ci * @ring: ring index the fence is associated with 33862306a36Sopenharmony_ci * 33962306a36Sopenharmony_ci * Wait for all fences on the requested ring to signal (all asics). 34062306a36Sopenharmony_ci * Returns 0 if the fences have passed, error for all other cases. 34162306a36Sopenharmony_ci */ 34262306a36Sopenharmony_ciint amdgpu_fence_wait_empty(struct amdgpu_ring *ring) 34362306a36Sopenharmony_ci{ 34462306a36Sopenharmony_ci uint64_t seq = READ_ONCE(ring->fence_drv.sync_seq); 34562306a36Sopenharmony_ci struct dma_fence *fence, **ptr; 34662306a36Sopenharmony_ci int r; 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci if (!seq) 34962306a36Sopenharmony_ci return 0; 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci ptr = &ring->fence_drv.fences[seq & ring->fence_drv.num_fences_mask]; 35262306a36Sopenharmony_ci rcu_read_lock(); 35362306a36Sopenharmony_ci fence = rcu_dereference(*ptr); 35462306a36Sopenharmony_ci if (!fence || !dma_fence_get_rcu(fence)) { 35562306a36Sopenharmony_ci rcu_read_unlock(); 35662306a36Sopenharmony_ci return 0; 35762306a36Sopenharmony_ci } 35862306a36Sopenharmony_ci rcu_read_unlock(); 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci r = dma_fence_wait(fence, false); 36162306a36Sopenharmony_ci dma_fence_put(fence); 36262306a36Sopenharmony_ci return r; 36362306a36Sopenharmony_ci} 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci/** 36662306a36Sopenharmony_ci * amdgpu_fence_wait_polling - busy wait for givn sequence number 36762306a36Sopenharmony_ci * 36862306a36Sopenharmony_ci * @ring: ring index the fence is associated with 36962306a36Sopenharmony_ci * @wait_seq: sequence number to wait 37062306a36Sopenharmony_ci * @timeout: the timeout for waiting in usecs 37162306a36Sopenharmony_ci * 37262306a36Sopenharmony_ci * Wait for all fences on the requested ring to signal (all asics). 37362306a36Sopenharmony_ci * Returns left time if no timeout, 0 or minus if timeout. 37462306a36Sopenharmony_ci */ 37562306a36Sopenharmony_cisigned long amdgpu_fence_wait_polling(struct amdgpu_ring *ring, 37662306a36Sopenharmony_ci uint32_t wait_seq, 37762306a36Sopenharmony_ci signed long timeout) 37862306a36Sopenharmony_ci{ 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci while ((int32_t)(wait_seq - amdgpu_fence_read(ring)) > 0 && timeout > 0) { 38162306a36Sopenharmony_ci udelay(2); 38262306a36Sopenharmony_ci timeout -= 2; 38362306a36Sopenharmony_ci } 38462306a36Sopenharmony_ci return timeout > 0 ? timeout : 0; 38562306a36Sopenharmony_ci} 38662306a36Sopenharmony_ci/** 38762306a36Sopenharmony_ci * amdgpu_fence_count_emitted - get the count of emitted fences 38862306a36Sopenharmony_ci * 38962306a36Sopenharmony_ci * @ring: ring the fence is associated with 39062306a36Sopenharmony_ci * 39162306a36Sopenharmony_ci * Get the number of fences emitted on the requested ring (all asics). 39262306a36Sopenharmony_ci * Returns the number of emitted fences on the ring. Used by the 39362306a36Sopenharmony_ci * dynpm code to ring track activity. 39462306a36Sopenharmony_ci */ 39562306a36Sopenharmony_ciunsigned int amdgpu_fence_count_emitted(struct amdgpu_ring *ring) 39662306a36Sopenharmony_ci{ 39762306a36Sopenharmony_ci uint64_t emitted; 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci /* We are not protected by ring lock when reading the last sequence 40062306a36Sopenharmony_ci * but it's ok to report slightly wrong fence count here. 40162306a36Sopenharmony_ci */ 40262306a36Sopenharmony_ci emitted = 0x100000000ull; 40362306a36Sopenharmony_ci emitted -= atomic_read(&ring->fence_drv.last_seq); 40462306a36Sopenharmony_ci emitted += READ_ONCE(ring->fence_drv.sync_seq); 40562306a36Sopenharmony_ci return lower_32_bits(emitted); 40662306a36Sopenharmony_ci} 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci/** 40962306a36Sopenharmony_ci * amdgpu_fence_last_unsignaled_time_us - the time fence emitted until now 41062306a36Sopenharmony_ci * @ring: ring the fence is associated with 41162306a36Sopenharmony_ci * 41262306a36Sopenharmony_ci * Find the earliest fence unsignaled until now, calculate the time delta 41362306a36Sopenharmony_ci * between the time fence emitted and now. 41462306a36Sopenharmony_ci */ 41562306a36Sopenharmony_ciu64 amdgpu_fence_last_unsignaled_time_us(struct amdgpu_ring *ring) 41662306a36Sopenharmony_ci{ 41762306a36Sopenharmony_ci struct amdgpu_fence_driver *drv = &ring->fence_drv; 41862306a36Sopenharmony_ci struct dma_fence *fence; 41962306a36Sopenharmony_ci uint32_t last_seq, sync_seq; 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci last_seq = atomic_read(&ring->fence_drv.last_seq); 42262306a36Sopenharmony_ci sync_seq = READ_ONCE(ring->fence_drv.sync_seq); 42362306a36Sopenharmony_ci if (last_seq == sync_seq) 42462306a36Sopenharmony_ci return 0; 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci ++last_seq; 42762306a36Sopenharmony_ci last_seq &= drv->num_fences_mask; 42862306a36Sopenharmony_ci fence = drv->fences[last_seq]; 42962306a36Sopenharmony_ci if (!fence) 43062306a36Sopenharmony_ci return 0; 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci return ktime_us_delta(ktime_get(), 43362306a36Sopenharmony_ci to_amdgpu_fence(fence)->start_timestamp); 43462306a36Sopenharmony_ci} 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci/** 43762306a36Sopenharmony_ci * amdgpu_fence_update_start_timestamp - update the timestamp of the fence 43862306a36Sopenharmony_ci * @ring: ring the fence is associated with 43962306a36Sopenharmony_ci * @seq: the fence seq number to update. 44062306a36Sopenharmony_ci * @timestamp: the start timestamp to update. 44162306a36Sopenharmony_ci * 44262306a36Sopenharmony_ci * The function called at the time the fence and related ib is about to 44362306a36Sopenharmony_ci * resubmit to gpu in MCBP scenario. Thus we do not consider race condition 44462306a36Sopenharmony_ci * with amdgpu_fence_process to modify the same fence. 44562306a36Sopenharmony_ci */ 44662306a36Sopenharmony_civoid amdgpu_fence_update_start_timestamp(struct amdgpu_ring *ring, uint32_t seq, ktime_t timestamp) 44762306a36Sopenharmony_ci{ 44862306a36Sopenharmony_ci struct amdgpu_fence_driver *drv = &ring->fence_drv; 44962306a36Sopenharmony_ci struct dma_fence *fence; 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci seq &= drv->num_fences_mask; 45262306a36Sopenharmony_ci fence = drv->fences[seq]; 45362306a36Sopenharmony_ci if (!fence) 45462306a36Sopenharmony_ci return; 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci to_amdgpu_fence(fence)->start_timestamp = timestamp; 45762306a36Sopenharmony_ci} 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci/** 46062306a36Sopenharmony_ci * amdgpu_fence_driver_start_ring - make the fence driver 46162306a36Sopenharmony_ci * ready for use on the requested ring. 46262306a36Sopenharmony_ci * 46362306a36Sopenharmony_ci * @ring: ring to start the fence driver on 46462306a36Sopenharmony_ci * @irq_src: interrupt source to use for this ring 46562306a36Sopenharmony_ci * @irq_type: interrupt type to use for this ring 46662306a36Sopenharmony_ci * 46762306a36Sopenharmony_ci * Make the fence driver ready for processing (all asics). 46862306a36Sopenharmony_ci * Not all asics have all rings, so each asic will only 46962306a36Sopenharmony_ci * start the fence driver on the rings it has. 47062306a36Sopenharmony_ci * Returns 0 for success, errors for failure. 47162306a36Sopenharmony_ci */ 47262306a36Sopenharmony_ciint amdgpu_fence_driver_start_ring(struct amdgpu_ring *ring, 47362306a36Sopenharmony_ci struct amdgpu_irq_src *irq_src, 47462306a36Sopenharmony_ci unsigned int irq_type) 47562306a36Sopenharmony_ci{ 47662306a36Sopenharmony_ci struct amdgpu_device *adev = ring->adev; 47762306a36Sopenharmony_ci uint64_t index; 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci if (ring->funcs->type != AMDGPU_RING_TYPE_UVD) { 48062306a36Sopenharmony_ci ring->fence_drv.cpu_addr = ring->fence_cpu_addr; 48162306a36Sopenharmony_ci ring->fence_drv.gpu_addr = ring->fence_gpu_addr; 48262306a36Sopenharmony_ci } else { 48362306a36Sopenharmony_ci /* put fence directly behind firmware */ 48462306a36Sopenharmony_ci index = ALIGN(adev->uvd.fw->size, 8); 48562306a36Sopenharmony_ci ring->fence_drv.cpu_addr = adev->uvd.inst[ring->me].cpu_addr + index; 48662306a36Sopenharmony_ci ring->fence_drv.gpu_addr = adev->uvd.inst[ring->me].gpu_addr + index; 48762306a36Sopenharmony_ci } 48862306a36Sopenharmony_ci amdgpu_fence_write(ring, atomic_read(&ring->fence_drv.last_seq)); 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci ring->fence_drv.irq_src = irq_src; 49162306a36Sopenharmony_ci ring->fence_drv.irq_type = irq_type; 49262306a36Sopenharmony_ci ring->fence_drv.initialized = true; 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci DRM_DEV_DEBUG(adev->dev, "fence driver on ring %s use gpu addr 0x%016llx\n", 49562306a36Sopenharmony_ci ring->name, ring->fence_drv.gpu_addr); 49662306a36Sopenharmony_ci return 0; 49762306a36Sopenharmony_ci} 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci/** 50062306a36Sopenharmony_ci * amdgpu_fence_driver_init_ring - init the fence driver 50162306a36Sopenharmony_ci * for the requested ring. 50262306a36Sopenharmony_ci * 50362306a36Sopenharmony_ci * @ring: ring to init the fence driver on 50462306a36Sopenharmony_ci * 50562306a36Sopenharmony_ci * Init the fence driver for the requested ring (all asics). 50662306a36Sopenharmony_ci * Helper function for amdgpu_fence_driver_init(). 50762306a36Sopenharmony_ci */ 50862306a36Sopenharmony_ciint amdgpu_fence_driver_init_ring(struct amdgpu_ring *ring) 50962306a36Sopenharmony_ci{ 51062306a36Sopenharmony_ci struct amdgpu_device *adev = ring->adev; 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci if (!adev) 51362306a36Sopenharmony_ci return -EINVAL; 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci if (!is_power_of_2(ring->num_hw_submission)) 51662306a36Sopenharmony_ci return -EINVAL; 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci ring->fence_drv.cpu_addr = NULL; 51962306a36Sopenharmony_ci ring->fence_drv.gpu_addr = 0; 52062306a36Sopenharmony_ci ring->fence_drv.sync_seq = 0; 52162306a36Sopenharmony_ci atomic_set(&ring->fence_drv.last_seq, 0); 52262306a36Sopenharmony_ci ring->fence_drv.initialized = false; 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci timer_setup(&ring->fence_drv.fallback_timer, amdgpu_fence_fallback, 0); 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci ring->fence_drv.num_fences_mask = ring->num_hw_submission * 2 - 1; 52762306a36Sopenharmony_ci spin_lock_init(&ring->fence_drv.lock); 52862306a36Sopenharmony_ci ring->fence_drv.fences = kcalloc(ring->num_hw_submission * 2, sizeof(void *), 52962306a36Sopenharmony_ci GFP_KERNEL); 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci if (!ring->fence_drv.fences) 53262306a36Sopenharmony_ci return -ENOMEM; 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci return 0; 53562306a36Sopenharmony_ci} 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_ci/** 53862306a36Sopenharmony_ci * amdgpu_fence_driver_sw_init - init the fence driver 53962306a36Sopenharmony_ci * for all possible rings. 54062306a36Sopenharmony_ci * 54162306a36Sopenharmony_ci * @adev: amdgpu device pointer 54262306a36Sopenharmony_ci * 54362306a36Sopenharmony_ci * Init the fence driver for all possible rings (all asics). 54462306a36Sopenharmony_ci * Not all asics have all rings, so each asic will only 54562306a36Sopenharmony_ci * start the fence driver on the rings it has using 54662306a36Sopenharmony_ci * amdgpu_fence_driver_start_ring(). 54762306a36Sopenharmony_ci * Returns 0 for success. 54862306a36Sopenharmony_ci */ 54962306a36Sopenharmony_ciint amdgpu_fence_driver_sw_init(struct amdgpu_device *adev) 55062306a36Sopenharmony_ci{ 55162306a36Sopenharmony_ci return 0; 55262306a36Sopenharmony_ci} 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci/** 55562306a36Sopenharmony_ci * amdgpu_fence_need_ring_interrupt_restore - helper function to check whether 55662306a36Sopenharmony_ci * fence driver interrupts need to be restored. 55762306a36Sopenharmony_ci * 55862306a36Sopenharmony_ci * @ring: ring that to be checked 55962306a36Sopenharmony_ci * 56062306a36Sopenharmony_ci * Interrupts for rings that belong to GFX IP don't need to be restored 56162306a36Sopenharmony_ci * when the target power state is s0ix. 56262306a36Sopenharmony_ci * 56362306a36Sopenharmony_ci * Return true if need to restore interrupts, false otherwise. 56462306a36Sopenharmony_ci */ 56562306a36Sopenharmony_cistatic bool amdgpu_fence_need_ring_interrupt_restore(struct amdgpu_ring *ring) 56662306a36Sopenharmony_ci{ 56762306a36Sopenharmony_ci struct amdgpu_device *adev = ring->adev; 56862306a36Sopenharmony_ci bool is_gfx_power_domain = false; 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_ci switch (ring->funcs->type) { 57162306a36Sopenharmony_ci case AMDGPU_RING_TYPE_SDMA: 57262306a36Sopenharmony_ci /* SDMA 5.x+ is part of GFX power domain so it's covered by GFXOFF */ 57362306a36Sopenharmony_ci if (adev->ip_versions[SDMA0_HWIP][0] >= IP_VERSION(5, 0, 0)) 57462306a36Sopenharmony_ci is_gfx_power_domain = true; 57562306a36Sopenharmony_ci break; 57662306a36Sopenharmony_ci case AMDGPU_RING_TYPE_GFX: 57762306a36Sopenharmony_ci case AMDGPU_RING_TYPE_COMPUTE: 57862306a36Sopenharmony_ci case AMDGPU_RING_TYPE_KIQ: 57962306a36Sopenharmony_ci case AMDGPU_RING_TYPE_MES: 58062306a36Sopenharmony_ci is_gfx_power_domain = true; 58162306a36Sopenharmony_ci break; 58262306a36Sopenharmony_ci default: 58362306a36Sopenharmony_ci break; 58462306a36Sopenharmony_ci } 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_ci return !(adev->in_s0ix && is_gfx_power_domain); 58762306a36Sopenharmony_ci} 58862306a36Sopenharmony_ci 58962306a36Sopenharmony_ci/** 59062306a36Sopenharmony_ci * amdgpu_fence_driver_hw_fini - tear down the fence driver 59162306a36Sopenharmony_ci * for all possible rings. 59262306a36Sopenharmony_ci * 59362306a36Sopenharmony_ci * @adev: amdgpu device pointer 59462306a36Sopenharmony_ci * 59562306a36Sopenharmony_ci * Tear down the fence driver for all possible rings (all asics). 59662306a36Sopenharmony_ci */ 59762306a36Sopenharmony_civoid amdgpu_fence_driver_hw_fini(struct amdgpu_device *adev) 59862306a36Sopenharmony_ci{ 59962306a36Sopenharmony_ci int i, r; 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci for (i = 0; i < AMDGPU_MAX_RINGS; i++) { 60262306a36Sopenharmony_ci struct amdgpu_ring *ring = adev->rings[i]; 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_ci if (!ring || !ring->fence_drv.initialized) 60562306a36Sopenharmony_ci continue; 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ci /* You can't wait for HW to signal if it's gone */ 60862306a36Sopenharmony_ci if (!drm_dev_is_unplugged(adev_to_drm(adev))) 60962306a36Sopenharmony_ci r = amdgpu_fence_wait_empty(ring); 61062306a36Sopenharmony_ci else 61162306a36Sopenharmony_ci r = -ENODEV; 61262306a36Sopenharmony_ci /* no need to trigger GPU reset as we are unloading */ 61362306a36Sopenharmony_ci if (r) 61462306a36Sopenharmony_ci amdgpu_fence_driver_force_completion(ring); 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_ci if (!drm_dev_is_unplugged(adev_to_drm(adev)) && 61762306a36Sopenharmony_ci ring->fence_drv.irq_src && 61862306a36Sopenharmony_ci amdgpu_fence_need_ring_interrupt_restore(ring)) 61962306a36Sopenharmony_ci amdgpu_irq_put(adev, ring->fence_drv.irq_src, 62062306a36Sopenharmony_ci ring->fence_drv.irq_type); 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci del_timer_sync(&ring->fence_drv.fallback_timer); 62362306a36Sopenharmony_ci } 62462306a36Sopenharmony_ci} 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_ci/* Will either stop and flush handlers for amdgpu interrupt or reanble it */ 62762306a36Sopenharmony_civoid amdgpu_fence_driver_isr_toggle(struct amdgpu_device *adev, bool stop) 62862306a36Sopenharmony_ci{ 62962306a36Sopenharmony_ci int i; 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_ci for (i = 0; i < AMDGPU_MAX_RINGS; i++) { 63262306a36Sopenharmony_ci struct amdgpu_ring *ring = adev->rings[i]; 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci if (!ring || !ring->fence_drv.initialized || !ring->fence_drv.irq_src) 63562306a36Sopenharmony_ci continue; 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_ci if (stop) 63862306a36Sopenharmony_ci disable_irq(adev->irq.irq); 63962306a36Sopenharmony_ci else 64062306a36Sopenharmony_ci enable_irq(adev->irq.irq); 64162306a36Sopenharmony_ci } 64262306a36Sopenharmony_ci} 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_civoid amdgpu_fence_driver_sw_fini(struct amdgpu_device *adev) 64562306a36Sopenharmony_ci{ 64662306a36Sopenharmony_ci unsigned int i, j; 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ci for (i = 0; i < AMDGPU_MAX_RINGS; i++) { 64962306a36Sopenharmony_ci struct amdgpu_ring *ring = adev->rings[i]; 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_ci if (!ring || !ring->fence_drv.initialized) 65262306a36Sopenharmony_ci continue; 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_ci /* 65562306a36Sopenharmony_ci * Notice we check for sched.ops since there's some 65662306a36Sopenharmony_ci * override on the meaning of sched.ready by amdgpu. 65762306a36Sopenharmony_ci * The natural check would be sched.ready, which is 65862306a36Sopenharmony_ci * set as drm_sched_init() finishes... 65962306a36Sopenharmony_ci */ 66062306a36Sopenharmony_ci if (ring->sched.ops) 66162306a36Sopenharmony_ci drm_sched_fini(&ring->sched); 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci for (j = 0; j <= ring->fence_drv.num_fences_mask; ++j) 66462306a36Sopenharmony_ci dma_fence_put(ring->fence_drv.fences[j]); 66562306a36Sopenharmony_ci kfree(ring->fence_drv.fences); 66662306a36Sopenharmony_ci ring->fence_drv.fences = NULL; 66762306a36Sopenharmony_ci ring->fence_drv.initialized = false; 66862306a36Sopenharmony_ci } 66962306a36Sopenharmony_ci} 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_ci/** 67262306a36Sopenharmony_ci * amdgpu_fence_driver_hw_init - enable the fence driver 67362306a36Sopenharmony_ci * for all possible rings. 67462306a36Sopenharmony_ci * 67562306a36Sopenharmony_ci * @adev: amdgpu device pointer 67662306a36Sopenharmony_ci * 67762306a36Sopenharmony_ci * Enable the fence driver for all possible rings (all asics). 67862306a36Sopenharmony_ci * Not all asics have all rings, so each asic will only 67962306a36Sopenharmony_ci * start the fence driver on the rings it has using 68062306a36Sopenharmony_ci * amdgpu_fence_driver_start_ring(). 68162306a36Sopenharmony_ci * Returns 0 for success. 68262306a36Sopenharmony_ci */ 68362306a36Sopenharmony_civoid amdgpu_fence_driver_hw_init(struct amdgpu_device *adev) 68462306a36Sopenharmony_ci{ 68562306a36Sopenharmony_ci int i; 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_ci for (i = 0; i < AMDGPU_MAX_RINGS; i++) { 68862306a36Sopenharmony_ci struct amdgpu_ring *ring = adev->rings[i]; 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_ci if (!ring || !ring->fence_drv.initialized) 69162306a36Sopenharmony_ci continue; 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_ci /* enable the interrupt */ 69462306a36Sopenharmony_ci if (ring->fence_drv.irq_src && 69562306a36Sopenharmony_ci amdgpu_fence_need_ring_interrupt_restore(ring)) 69662306a36Sopenharmony_ci amdgpu_irq_get(adev, ring->fence_drv.irq_src, 69762306a36Sopenharmony_ci ring->fence_drv.irq_type); 69862306a36Sopenharmony_ci } 69962306a36Sopenharmony_ci} 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_ci/** 70262306a36Sopenharmony_ci * amdgpu_fence_driver_clear_job_fences - clear job embedded fences of ring 70362306a36Sopenharmony_ci * 70462306a36Sopenharmony_ci * @ring: fence of the ring to be cleared 70562306a36Sopenharmony_ci * 70662306a36Sopenharmony_ci */ 70762306a36Sopenharmony_civoid amdgpu_fence_driver_clear_job_fences(struct amdgpu_ring *ring) 70862306a36Sopenharmony_ci{ 70962306a36Sopenharmony_ci int i; 71062306a36Sopenharmony_ci struct dma_fence *old, **ptr; 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_ci for (i = 0; i <= ring->fence_drv.num_fences_mask; i++) { 71362306a36Sopenharmony_ci ptr = &ring->fence_drv.fences[i]; 71462306a36Sopenharmony_ci old = rcu_dereference_protected(*ptr, 1); 71562306a36Sopenharmony_ci if (old && old->ops == &amdgpu_job_fence_ops) { 71662306a36Sopenharmony_ci struct amdgpu_job *job; 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ci /* For non-scheduler bad job, i.e. failed ib test, we need to signal 71962306a36Sopenharmony_ci * it right here or we won't be able to track them in fence_drv 72062306a36Sopenharmony_ci * and they will remain unsignaled during sa_bo free. 72162306a36Sopenharmony_ci */ 72262306a36Sopenharmony_ci job = container_of(old, struct amdgpu_job, hw_fence); 72362306a36Sopenharmony_ci if (!job->base.s_fence && !dma_fence_is_signaled(old)) 72462306a36Sopenharmony_ci dma_fence_signal(old); 72562306a36Sopenharmony_ci RCU_INIT_POINTER(*ptr, NULL); 72662306a36Sopenharmony_ci dma_fence_put(old); 72762306a36Sopenharmony_ci } 72862306a36Sopenharmony_ci } 72962306a36Sopenharmony_ci} 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_ci/** 73262306a36Sopenharmony_ci * amdgpu_fence_driver_set_error - set error code on fences 73362306a36Sopenharmony_ci * @ring: the ring which contains the fences 73462306a36Sopenharmony_ci * @error: the error code to set 73562306a36Sopenharmony_ci * 73662306a36Sopenharmony_ci * Set an error code to all the fences pending on the ring. 73762306a36Sopenharmony_ci */ 73862306a36Sopenharmony_civoid amdgpu_fence_driver_set_error(struct amdgpu_ring *ring, int error) 73962306a36Sopenharmony_ci{ 74062306a36Sopenharmony_ci struct amdgpu_fence_driver *drv = &ring->fence_drv; 74162306a36Sopenharmony_ci unsigned long flags; 74262306a36Sopenharmony_ci 74362306a36Sopenharmony_ci spin_lock_irqsave(&drv->lock, flags); 74462306a36Sopenharmony_ci for (unsigned int i = 0; i <= drv->num_fences_mask; ++i) { 74562306a36Sopenharmony_ci struct dma_fence *fence; 74662306a36Sopenharmony_ci 74762306a36Sopenharmony_ci fence = rcu_dereference_protected(drv->fences[i], 74862306a36Sopenharmony_ci lockdep_is_held(&drv->lock)); 74962306a36Sopenharmony_ci if (fence && !dma_fence_is_signaled_locked(fence)) 75062306a36Sopenharmony_ci dma_fence_set_error(fence, error); 75162306a36Sopenharmony_ci } 75262306a36Sopenharmony_ci spin_unlock_irqrestore(&drv->lock, flags); 75362306a36Sopenharmony_ci} 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_ci/** 75662306a36Sopenharmony_ci * amdgpu_fence_driver_force_completion - force signal latest fence of ring 75762306a36Sopenharmony_ci * 75862306a36Sopenharmony_ci * @ring: fence of the ring to signal 75962306a36Sopenharmony_ci * 76062306a36Sopenharmony_ci */ 76162306a36Sopenharmony_civoid amdgpu_fence_driver_force_completion(struct amdgpu_ring *ring) 76262306a36Sopenharmony_ci{ 76362306a36Sopenharmony_ci amdgpu_fence_driver_set_error(ring, -ECANCELED); 76462306a36Sopenharmony_ci amdgpu_fence_write(ring, ring->fence_drv.sync_seq); 76562306a36Sopenharmony_ci amdgpu_fence_process(ring); 76662306a36Sopenharmony_ci} 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_ci/* 76962306a36Sopenharmony_ci * Common fence implementation 77062306a36Sopenharmony_ci */ 77162306a36Sopenharmony_ci 77262306a36Sopenharmony_cistatic const char *amdgpu_fence_get_driver_name(struct dma_fence *fence) 77362306a36Sopenharmony_ci{ 77462306a36Sopenharmony_ci return "amdgpu"; 77562306a36Sopenharmony_ci} 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_cistatic const char *amdgpu_fence_get_timeline_name(struct dma_fence *f) 77862306a36Sopenharmony_ci{ 77962306a36Sopenharmony_ci return (const char *)to_amdgpu_fence(f)->ring->name; 78062306a36Sopenharmony_ci} 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_cistatic const char *amdgpu_job_fence_get_timeline_name(struct dma_fence *f) 78362306a36Sopenharmony_ci{ 78462306a36Sopenharmony_ci struct amdgpu_job *job = container_of(f, struct amdgpu_job, hw_fence); 78562306a36Sopenharmony_ci 78662306a36Sopenharmony_ci return (const char *)to_amdgpu_ring(job->base.sched)->name; 78762306a36Sopenharmony_ci} 78862306a36Sopenharmony_ci 78962306a36Sopenharmony_ci/** 79062306a36Sopenharmony_ci * amdgpu_fence_enable_signaling - enable signalling on fence 79162306a36Sopenharmony_ci * @f: fence 79262306a36Sopenharmony_ci * 79362306a36Sopenharmony_ci * This function is called with fence_queue lock held, and adds a callback 79462306a36Sopenharmony_ci * to fence_queue that checks if this fence is signaled, and if so it 79562306a36Sopenharmony_ci * signals the fence and removes itself. 79662306a36Sopenharmony_ci */ 79762306a36Sopenharmony_cistatic bool amdgpu_fence_enable_signaling(struct dma_fence *f) 79862306a36Sopenharmony_ci{ 79962306a36Sopenharmony_ci if (!timer_pending(&to_amdgpu_fence(f)->ring->fence_drv.fallback_timer)) 80062306a36Sopenharmony_ci amdgpu_fence_schedule_fallback(to_amdgpu_fence(f)->ring); 80162306a36Sopenharmony_ci 80262306a36Sopenharmony_ci return true; 80362306a36Sopenharmony_ci} 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_ci/** 80662306a36Sopenharmony_ci * amdgpu_job_fence_enable_signaling - enable signalling on job fence 80762306a36Sopenharmony_ci * @f: fence 80862306a36Sopenharmony_ci * 80962306a36Sopenharmony_ci * This is the simliar function with amdgpu_fence_enable_signaling above, it 81062306a36Sopenharmony_ci * only handles the job embedded fence. 81162306a36Sopenharmony_ci */ 81262306a36Sopenharmony_cistatic bool amdgpu_job_fence_enable_signaling(struct dma_fence *f) 81362306a36Sopenharmony_ci{ 81462306a36Sopenharmony_ci struct amdgpu_job *job = container_of(f, struct amdgpu_job, hw_fence); 81562306a36Sopenharmony_ci 81662306a36Sopenharmony_ci if (!timer_pending(&to_amdgpu_ring(job->base.sched)->fence_drv.fallback_timer)) 81762306a36Sopenharmony_ci amdgpu_fence_schedule_fallback(to_amdgpu_ring(job->base.sched)); 81862306a36Sopenharmony_ci 81962306a36Sopenharmony_ci return true; 82062306a36Sopenharmony_ci} 82162306a36Sopenharmony_ci 82262306a36Sopenharmony_ci/** 82362306a36Sopenharmony_ci * amdgpu_fence_free - free up the fence memory 82462306a36Sopenharmony_ci * 82562306a36Sopenharmony_ci * @rcu: RCU callback head 82662306a36Sopenharmony_ci * 82762306a36Sopenharmony_ci * Free up the fence memory after the RCU grace period. 82862306a36Sopenharmony_ci */ 82962306a36Sopenharmony_cistatic void amdgpu_fence_free(struct rcu_head *rcu) 83062306a36Sopenharmony_ci{ 83162306a36Sopenharmony_ci struct dma_fence *f = container_of(rcu, struct dma_fence, rcu); 83262306a36Sopenharmony_ci 83362306a36Sopenharmony_ci /* free fence_slab if it's separated fence*/ 83462306a36Sopenharmony_ci kmem_cache_free(amdgpu_fence_slab, to_amdgpu_fence(f)); 83562306a36Sopenharmony_ci} 83662306a36Sopenharmony_ci 83762306a36Sopenharmony_ci/** 83862306a36Sopenharmony_ci * amdgpu_job_fence_free - free up the job with embedded fence 83962306a36Sopenharmony_ci * 84062306a36Sopenharmony_ci * @rcu: RCU callback head 84162306a36Sopenharmony_ci * 84262306a36Sopenharmony_ci * Free up the job with embedded fence after the RCU grace period. 84362306a36Sopenharmony_ci */ 84462306a36Sopenharmony_cistatic void amdgpu_job_fence_free(struct rcu_head *rcu) 84562306a36Sopenharmony_ci{ 84662306a36Sopenharmony_ci struct dma_fence *f = container_of(rcu, struct dma_fence, rcu); 84762306a36Sopenharmony_ci 84862306a36Sopenharmony_ci /* free job if fence has a parent job */ 84962306a36Sopenharmony_ci kfree(container_of(f, struct amdgpu_job, hw_fence)); 85062306a36Sopenharmony_ci} 85162306a36Sopenharmony_ci 85262306a36Sopenharmony_ci/** 85362306a36Sopenharmony_ci * amdgpu_fence_release - callback that fence can be freed 85462306a36Sopenharmony_ci * 85562306a36Sopenharmony_ci * @f: fence 85662306a36Sopenharmony_ci * 85762306a36Sopenharmony_ci * This function is called when the reference count becomes zero. 85862306a36Sopenharmony_ci * It just RCU schedules freeing up the fence. 85962306a36Sopenharmony_ci */ 86062306a36Sopenharmony_cistatic void amdgpu_fence_release(struct dma_fence *f) 86162306a36Sopenharmony_ci{ 86262306a36Sopenharmony_ci call_rcu(&f->rcu, amdgpu_fence_free); 86362306a36Sopenharmony_ci} 86462306a36Sopenharmony_ci 86562306a36Sopenharmony_ci/** 86662306a36Sopenharmony_ci * amdgpu_job_fence_release - callback that job embedded fence can be freed 86762306a36Sopenharmony_ci * 86862306a36Sopenharmony_ci * @f: fence 86962306a36Sopenharmony_ci * 87062306a36Sopenharmony_ci * This is the simliar function with amdgpu_fence_release above, it 87162306a36Sopenharmony_ci * only handles the job embedded fence. 87262306a36Sopenharmony_ci */ 87362306a36Sopenharmony_cistatic void amdgpu_job_fence_release(struct dma_fence *f) 87462306a36Sopenharmony_ci{ 87562306a36Sopenharmony_ci call_rcu(&f->rcu, amdgpu_job_fence_free); 87662306a36Sopenharmony_ci} 87762306a36Sopenharmony_ci 87862306a36Sopenharmony_cistatic const struct dma_fence_ops amdgpu_fence_ops = { 87962306a36Sopenharmony_ci .get_driver_name = amdgpu_fence_get_driver_name, 88062306a36Sopenharmony_ci .get_timeline_name = amdgpu_fence_get_timeline_name, 88162306a36Sopenharmony_ci .enable_signaling = amdgpu_fence_enable_signaling, 88262306a36Sopenharmony_ci .release = amdgpu_fence_release, 88362306a36Sopenharmony_ci}; 88462306a36Sopenharmony_ci 88562306a36Sopenharmony_cistatic const struct dma_fence_ops amdgpu_job_fence_ops = { 88662306a36Sopenharmony_ci .get_driver_name = amdgpu_fence_get_driver_name, 88762306a36Sopenharmony_ci .get_timeline_name = amdgpu_job_fence_get_timeline_name, 88862306a36Sopenharmony_ci .enable_signaling = amdgpu_job_fence_enable_signaling, 88962306a36Sopenharmony_ci .release = amdgpu_job_fence_release, 89062306a36Sopenharmony_ci}; 89162306a36Sopenharmony_ci 89262306a36Sopenharmony_ci/* 89362306a36Sopenharmony_ci * Fence debugfs 89462306a36Sopenharmony_ci */ 89562306a36Sopenharmony_ci#if defined(CONFIG_DEBUG_FS) 89662306a36Sopenharmony_cistatic int amdgpu_debugfs_fence_info_show(struct seq_file *m, void *unused) 89762306a36Sopenharmony_ci{ 89862306a36Sopenharmony_ci struct amdgpu_device *adev = m->private; 89962306a36Sopenharmony_ci int i; 90062306a36Sopenharmony_ci 90162306a36Sopenharmony_ci for (i = 0; i < AMDGPU_MAX_RINGS; ++i) { 90262306a36Sopenharmony_ci struct amdgpu_ring *ring = adev->rings[i]; 90362306a36Sopenharmony_ci 90462306a36Sopenharmony_ci if (!ring || !ring->fence_drv.initialized) 90562306a36Sopenharmony_ci continue; 90662306a36Sopenharmony_ci 90762306a36Sopenharmony_ci amdgpu_fence_process(ring); 90862306a36Sopenharmony_ci 90962306a36Sopenharmony_ci seq_printf(m, "--- ring %d (%s) ---\n", i, ring->name); 91062306a36Sopenharmony_ci seq_printf(m, "Last signaled fence 0x%08x\n", 91162306a36Sopenharmony_ci atomic_read(&ring->fence_drv.last_seq)); 91262306a36Sopenharmony_ci seq_printf(m, "Last emitted 0x%08x\n", 91362306a36Sopenharmony_ci ring->fence_drv.sync_seq); 91462306a36Sopenharmony_ci 91562306a36Sopenharmony_ci if (ring->funcs->type == AMDGPU_RING_TYPE_GFX || 91662306a36Sopenharmony_ci ring->funcs->type == AMDGPU_RING_TYPE_SDMA) { 91762306a36Sopenharmony_ci seq_printf(m, "Last signaled trailing fence 0x%08x\n", 91862306a36Sopenharmony_ci le32_to_cpu(*ring->trail_fence_cpu_addr)); 91962306a36Sopenharmony_ci seq_printf(m, "Last emitted 0x%08x\n", 92062306a36Sopenharmony_ci ring->trail_seq); 92162306a36Sopenharmony_ci } 92262306a36Sopenharmony_ci 92362306a36Sopenharmony_ci if (ring->funcs->type != AMDGPU_RING_TYPE_GFX) 92462306a36Sopenharmony_ci continue; 92562306a36Sopenharmony_ci 92662306a36Sopenharmony_ci /* set in CP_VMID_PREEMPT and preemption occurred */ 92762306a36Sopenharmony_ci seq_printf(m, "Last preempted 0x%08x\n", 92862306a36Sopenharmony_ci le32_to_cpu(*(ring->fence_drv.cpu_addr + 2))); 92962306a36Sopenharmony_ci /* set in CP_VMID_RESET and reset occurred */ 93062306a36Sopenharmony_ci seq_printf(m, "Last reset 0x%08x\n", 93162306a36Sopenharmony_ci le32_to_cpu(*(ring->fence_drv.cpu_addr + 4))); 93262306a36Sopenharmony_ci /* Both preemption and reset occurred */ 93362306a36Sopenharmony_ci seq_printf(m, "Last both 0x%08x\n", 93462306a36Sopenharmony_ci le32_to_cpu(*(ring->fence_drv.cpu_addr + 6))); 93562306a36Sopenharmony_ci } 93662306a36Sopenharmony_ci return 0; 93762306a36Sopenharmony_ci} 93862306a36Sopenharmony_ci 93962306a36Sopenharmony_ci/* 94062306a36Sopenharmony_ci * amdgpu_debugfs_gpu_recover - manually trigger a gpu reset & recover 94162306a36Sopenharmony_ci * 94262306a36Sopenharmony_ci * Manually trigger a gpu reset at the next fence wait. 94362306a36Sopenharmony_ci */ 94462306a36Sopenharmony_cistatic int gpu_recover_get(void *data, u64 *val) 94562306a36Sopenharmony_ci{ 94662306a36Sopenharmony_ci struct amdgpu_device *adev = (struct amdgpu_device *)data; 94762306a36Sopenharmony_ci struct drm_device *dev = adev_to_drm(adev); 94862306a36Sopenharmony_ci int r; 94962306a36Sopenharmony_ci 95062306a36Sopenharmony_ci r = pm_runtime_get_sync(dev->dev); 95162306a36Sopenharmony_ci if (r < 0) { 95262306a36Sopenharmony_ci pm_runtime_put_autosuspend(dev->dev); 95362306a36Sopenharmony_ci return 0; 95462306a36Sopenharmony_ci } 95562306a36Sopenharmony_ci 95662306a36Sopenharmony_ci if (amdgpu_reset_domain_schedule(adev->reset_domain, &adev->reset_work)) 95762306a36Sopenharmony_ci flush_work(&adev->reset_work); 95862306a36Sopenharmony_ci 95962306a36Sopenharmony_ci *val = atomic_read(&adev->reset_domain->reset_res); 96062306a36Sopenharmony_ci 96162306a36Sopenharmony_ci pm_runtime_mark_last_busy(dev->dev); 96262306a36Sopenharmony_ci pm_runtime_put_autosuspend(dev->dev); 96362306a36Sopenharmony_ci 96462306a36Sopenharmony_ci return 0; 96562306a36Sopenharmony_ci} 96662306a36Sopenharmony_ci 96762306a36Sopenharmony_ciDEFINE_SHOW_ATTRIBUTE(amdgpu_debugfs_fence_info); 96862306a36Sopenharmony_ciDEFINE_DEBUGFS_ATTRIBUTE(amdgpu_debugfs_gpu_recover_fops, gpu_recover_get, NULL, 96962306a36Sopenharmony_ci "%lld\n"); 97062306a36Sopenharmony_ci 97162306a36Sopenharmony_cistatic void amdgpu_debugfs_reset_work(struct work_struct *work) 97262306a36Sopenharmony_ci{ 97362306a36Sopenharmony_ci struct amdgpu_device *adev = container_of(work, struct amdgpu_device, 97462306a36Sopenharmony_ci reset_work); 97562306a36Sopenharmony_ci 97662306a36Sopenharmony_ci struct amdgpu_reset_context reset_context; 97762306a36Sopenharmony_ci 97862306a36Sopenharmony_ci memset(&reset_context, 0, sizeof(reset_context)); 97962306a36Sopenharmony_ci 98062306a36Sopenharmony_ci reset_context.method = AMD_RESET_METHOD_NONE; 98162306a36Sopenharmony_ci reset_context.reset_req_dev = adev; 98262306a36Sopenharmony_ci set_bit(AMDGPU_NEED_FULL_RESET, &reset_context.flags); 98362306a36Sopenharmony_ci 98462306a36Sopenharmony_ci amdgpu_device_gpu_recover(adev, NULL, &reset_context); 98562306a36Sopenharmony_ci} 98662306a36Sopenharmony_ci 98762306a36Sopenharmony_ci#endif 98862306a36Sopenharmony_ci 98962306a36Sopenharmony_civoid amdgpu_debugfs_fence_init(struct amdgpu_device *adev) 99062306a36Sopenharmony_ci{ 99162306a36Sopenharmony_ci#if defined(CONFIG_DEBUG_FS) 99262306a36Sopenharmony_ci struct drm_minor *minor = adev_to_drm(adev)->primary; 99362306a36Sopenharmony_ci struct dentry *root = minor->debugfs_root; 99462306a36Sopenharmony_ci 99562306a36Sopenharmony_ci debugfs_create_file("amdgpu_fence_info", 0444, root, adev, 99662306a36Sopenharmony_ci &amdgpu_debugfs_fence_info_fops); 99762306a36Sopenharmony_ci 99862306a36Sopenharmony_ci if (!amdgpu_sriov_vf(adev)) { 99962306a36Sopenharmony_ci 100062306a36Sopenharmony_ci INIT_WORK(&adev->reset_work, amdgpu_debugfs_reset_work); 100162306a36Sopenharmony_ci debugfs_create_file("amdgpu_gpu_recover", 0444, root, adev, 100262306a36Sopenharmony_ci &amdgpu_debugfs_gpu_recover_fops); 100362306a36Sopenharmony_ci } 100462306a36Sopenharmony_ci#endif 100562306a36Sopenharmony_ci} 100662306a36Sopenharmony_ci 1007