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 3262306a36Sopenharmony_ci#include <linux/atomic.h> 3362306a36Sopenharmony_ci#include <linux/firmware.h> 3462306a36Sopenharmony_ci#include <linux/kref.h> 3562306a36Sopenharmony_ci#include <linux/sched/signal.h> 3662306a36Sopenharmony_ci#include <linux/seq_file.h> 3762306a36Sopenharmony_ci#include <linux/slab.h> 3862306a36Sopenharmony_ci#include <linux/wait.h> 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci#include <drm/drm_device.h> 4162306a36Sopenharmony_ci#include <drm/drm_file.h> 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci#include "radeon.h" 4462306a36Sopenharmony_ci#include "radeon_reg.h" 4562306a36Sopenharmony_ci#include "radeon_trace.h" 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci/* 4862306a36Sopenharmony_ci * Fences 4962306a36Sopenharmony_ci * Fences mark an event in the GPUs pipeline and are used 5062306a36Sopenharmony_ci * for GPU/CPU synchronization. When the fence is written, 5162306a36Sopenharmony_ci * it is expected that all buffers associated with that fence 5262306a36Sopenharmony_ci * are no longer in use by the associated ring on the GPU and 5362306a36Sopenharmony_ci * that the relevant GPU caches have been flushed. Whether 5462306a36Sopenharmony_ci * we use a scratch register or memory location depends on the asic 5562306a36Sopenharmony_ci * and whether writeback is enabled. 5662306a36Sopenharmony_ci */ 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci/** 5962306a36Sopenharmony_ci * radeon_fence_write - write a fence value 6062306a36Sopenharmony_ci * 6162306a36Sopenharmony_ci * @rdev: radeon_device pointer 6262306a36Sopenharmony_ci * @seq: sequence number to write 6362306a36Sopenharmony_ci * @ring: ring index the fence is associated with 6462306a36Sopenharmony_ci * 6562306a36Sopenharmony_ci * Writes a fence value to memory or a scratch register (all asics). 6662306a36Sopenharmony_ci */ 6762306a36Sopenharmony_cistatic void radeon_fence_write(struct radeon_device *rdev, u32 seq, int ring) 6862306a36Sopenharmony_ci{ 6962306a36Sopenharmony_ci struct radeon_fence_driver *drv = &rdev->fence_drv[ring]; 7062306a36Sopenharmony_ci if (likely(rdev->wb.enabled || !drv->scratch_reg)) { 7162306a36Sopenharmony_ci if (drv->cpu_addr) { 7262306a36Sopenharmony_ci *drv->cpu_addr = cpu_to_le32(seq); 7362306a36Sopenharmony_ci } 7462306a36Sopenharmony_ci } else { 7562306a36Sopenharmony_ci WREG32(drv->scratch_reg, seq); 7662306a36Sopenharmony_ci } 7762306a36Sopenharmony_ci} 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci/** 8062306a36Sopenharmony_ci * radeon_fence_read - read a fence value 8162306a36Sopenharmony_ci * 8262306a36Sopenharmony_ci * @rdev: radeon_device pointer 8362306a36Sopenharmony_ci * @ring: ring index the fence is associated with 8462306a36Sopenharmony_ci * 8562306a36Sopenharmony_ci * Reads a fence value from memory or a scratch register (all asics). 8662306a36Sopenharmony_ci * Returns the value of the fence read from memory or register. 8762306a36Sopenharmony_ci */ 8862306a36Sopenharmony_cistatic u32 radeon_fence_read(struct radeon_device *rdev, int ring) 8962306a36Sopenharmony_ci{ 9062306a36Sopenharmony_ci struct radeon_fence_driver *drv = &rdev->fence_drv[ring]; 9162306a36Sopenharmony_ci u32 seq = 0; 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci if (likely(rdev->wb.enabled || !drv->scratch_reg)) { 9462306a36Sopenharmony_ci if (drv->cpu_addr) { 9562306a36Sopenharmony_ci seq = le32_to_cpu(*drv->cpu_addr); 9662306a36Sopenharmony_ci } else { 9762306a36Sopenharmony_ci seq = lower_32_bits(atomic64_read(&drv->last_seq)); 9862306a36Sopenharmony_ci } 9962306a36Sopenharmony_ci } else { 10062306a36Sopenharmony_ci seq = RREG32(drv->scratch_reg); 10162306a36Sopenharmony_ci } 10262306a36Sopenharmony_ci return seq; 10362306a36Sopenharmony_ci} 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci/** 10662306a36Sopenharmony_ci * radeon_fence_schedule_check - schedule lockup check 10762306a36Sopenharmony_ci * 10862306a36Sopenharmony_ci * @rdev: radeon_device pointer 10962306a36Sopenharmony_ci * @ring: ring index we should work with 11062306a36Sopenharmony_ci * 11162306a36Sopenharmony_ci * Queues a delayed work item to check for lockups. 11262306a36Sopenharmony_ci */ 11362306a36Sopenharmony_cistatic void radeon_fence_schedule_check(struct radeon_device *rdev, int ring) 11462306a36Sopenharmony_ci{ 11562306a36Sopenharmony_ci /* 11662306a36Sopenharmony_ci * Do not reset the timer here with mod_delayed_work, 11762306a36Sopenharmony_ci * this can livelock in an interaction with TTM delayed destroy. 11862306a36Sopenharmony_ci */ 11962306a36Sopenharmony_ci queue_delayed_work(system_power_efficient_wq, 12062306a36Sopenharmony_ci &rdev->fence_drv[ring].lockup_work, 12162306a36Sopenharmony_ci RADEON_FENCE_JIFFIES_TIMEOUT); 12262306a36Sopenharmony_ci} 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci/** 12562306a36Sopenharmony_ci * radeon_fence_emit - emit a fence on the requested ring 12662306a36Sopenharmony_ci * 12762306a36Sopenharmony_ci * @rdev: radeon_device pointer 12862306a36Sopenharmony_ci * @fence: radeon fence object 12962306a36Sopenharmony_ci * @ring: ring index the fence is associated with 13062306a36Sopenharmony_ci * 13162306a36Sopenharmony_ci * Emits a fence command on the requested ring (all asics). 13262306a36Sopenharmony_ci * Returns 0 on success, -ENOMEM on failure. 13362306a36Sopenharmony_ci */ 13462306a36Sopenharmony_ciint radeon_fence_emit(struct radeon_device *rdev, 13562306a36Sopenharmony_ci struct radeon_fence **fence, 13662306a36Sopenharmony_ci int ring) 13762306a36Sopenharmony_ci{ 13862306a36Sopenharmony_ci u64 seq; 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci /* we are protected by the ring emission mutex */ 14162306a36Sopenharmony_ci *fence = kmalloc(sizeof(struct radeon_fence), GFP_KERNEL); 14262306a36Sopenharmony_ci if ((*fence) == NULL) { 14362306a36Sopenharmony_ci return -ENOMEM; 14462306a36Sopenharmony_ci } 14562306a36Sopenharmony_ci (*fence)->rdev = rdev; 14662306a36Sopenharmony_ci (*fence)->seq = seq = ++rdev->fence_drv[ring].sync_seq[ring]; 14762306a36Sopenharmony_ci (*fence)->ring = ring; 14862306a36Sopenharmony_ci (*fence)->is_vm_update = false; 14962306a36Sopenharmony_ci dma_fence_init(&(*fence)->base, &radeon_fence_ops, 15062306a36Sopenharmony_ci &rdev->fence_queue.lock, 15162306a36Sopenharmony_ci rdev->fence_context + ring, 15262306a36Sopenharmony_ci seq); 15362306a36Sopenharmony_ci radeon_fence_ring_emit(rdev, ring, *fence); 15462306a36Sopenharmony_ci trace_radeon_fence_emit(rdev->ddev, ring, (*fence)->seq); 15562306a36Sopenharmony_ci radeon_fence_schedule_check(rdev, ring); 15662306a36Sopenharmony_ci return 0; 15762306a36Sopenharmony_ci} 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci/* 16062306a36Sopenharmony_ci * radeon_fence_check_signaled - callback from fence_queue 16162306a36Sopenharmony_ci * 16262306a36Sopenharmony_ci * this function is called with fence_queue lock held, which is also used 16362306a36Sopenharmony_ci * for the fence locking itself, so unlocked variants are used for 16462306a36Sopenharmony_ci * fence_signal, and remove_wait_queue. 16562306a36Sopenharmony_ci */ 16662306a36Sopenharmony_cistatic int radeon_fence_check_signaled(wait_queue_entry_t *wait, unsigned mode, int flags, void *key) 16762306a36Sopenharmony_ci{ 16862306a36Sopenharmony_ci struct radeon_fence *fence; 16962306a36Sopenharmony_ci u64 seq; 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci fence = container_of(wait, struct radeon_fence, fence_wake); 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci /* 17462306a36Sopenharmony_ci * We cannot use radeon_fence_process here because we're already 17562306a36Sopenharmony_ci * in the waitqueue, in a call from wake_up_all. 17662306a36Sopenharmony_ci */ 17762306a36Sopenharmony_ci seq = atomic64_read(&fence->rdev->fence_drv[fence->ring].last_seq); 17862306a36Sopenharmony_ci if (seq >= fence->seq) { 17962306a36Sopenharmony_ci dma_fence_signal_locked(&fence->base); 18062306a36Sopenharmony_ci radeon_irq_kms_sw_irq_put(fence->rdev, fence->ring); 18162306a36Sopenharmony_ci __remove_wait_queue(&fence->rdev->fence_queue, &fence->fence_wake); 18262306a36Sopenharmony_ci dma_fence_put(&fence->base); 18362306a36Sopenharmony_ci } 18462306a36Sopenharmony_ci return 0; 18562306a36Sopenharmony_ci} 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci/** 18862306a36Sopenharmony_ci * radeon_fence_activity - check for fence activity 18962306a36Sopenharmony_ci * 19062306a36Sopenharmony_ci * @rdev: radeon_device pointer 19162306a36Sopenharmony_ci * @ring: ring index the fence is associated with 19262306a36Sopenharmony_ci * 19362306a36Sopenharmony_ci * Checks the current fence value and calculates the last 19462306a36Sopenharmony_ci * signalled fence value. Returns true if activity occured 19562306a36Sopenharmony_ci * on the ring, and the fence_queue should be waken up. 19662306a36Sopenharmony_ci */ 19762306a36Sopenharmony_cistatic bool radeon_fence_activity(struct radeon_device *rdev, int ring) 19862306a36Sopenharmony_ci{ 19962306a36Sopenharmony_ci uint64_t seq, last_seq, last_emitted; 20062306a36Sopenharmony_ci unsigned count_loop = 0; 20162306a36Sopenharmony_ci bool wake = false; 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci /* Note there is a scenario here for an infinite loop but it's 20462306a36Sopenharmony_ci * very unlikely to happen. For it to happen, the current polling 20562306a36Sopenharmony_ci * process need to be interrupted by another process and another 20662306a36Sopenharmony_ci * process needs to update the last_seq btw the atomic read and 20762306a36Sopenharmony_ci * xchg of the current process. 20862306a36Sopenharmony_ci * 20962306a36Sopenharmony_ci * More over for this to go in infinite loop there need to be 21062306a36Sopenharmony_ci * continuously new fence signaled ie radeon_fence_read needs 21162306a36Sopenharmony_ci * to return a different value each time for both the currently 21262306a36Sopenharmony_ci * polling process and the other process that xchg the last_seq 21362306a36Sopenharmony_ci * btw atomic read and xchg of the current process. And the 21462306a36Sopenharmony_ci * value the other process set as last seq must be higher than 21562306a36Sopenharmony_ci * the seq value we just read. Which means that current process 21662306a36Sopenharmony_ci * need to be interrupted after radeon_fence_read and before 21762306a36Sopenharmony_ci * atomic xchg. 21862306a36Sopenharmony_ci * 21962306a36Sopenharmony_ci * To be even more safe we count the number of time we loop and 22062306a36Sopenharmony_ci * we bail after 10 loop just accepting the fact that we might 22162306a36Sopenharmony_ci * have temporarly set the last_seq not to the true real last 22262306a36Sopenharmony_ci * seq but to an older one. 22362306a36Sopenharmony_ci */ 22462306a36Sopenharmony_ci last_seq = atomic64_read(&rdev->fence_drv[ring].last_seq); 22562306a36Sopenharmony_ci do { 22662306a36Sopenharmony_ci last_emitted = rdev->fence_drv[ring].sync_seq[ring]; 22762306a36Sopenharmony_ci seq = radeon_fence_read(rdev, ring); 22862306a36Sopenharmony_ci seq |= last_seq & 0xffffffff00000000LL; 22962306a36Sopenharmony_ci if (seq < last_seq) { 23062306a36Sopenharmony_ci seq &= 0xffffffff; 23162306a36Sopenharmony_ci seq |= last_emitted & 0xffffffff00000000LL; 23262306a36Sopenharmony_ci } 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci if (seq <= last_seq || seq > last_emitted) { 23562306a36Sopenharmony_ci break; 23662306a36Sopenharmony_ci } 23762306a36Sopenharmony_ci /* If we loop over we don't want to return without 23862306a36Sopenharmony_ci * checking if a fence is signaled as it means that the 23962306a36Sopenharmony_ci * seq we just read is different from the previous on. 24062306a36Sopenharmony_ci */ 24162306a36Sopenharmony_ci wake = true; 24262306a36Sopenharmony_ci last_seq = seq; 24362306a36Sopenharmony_ci if ((count_loop++) > 10) { 24462306a36Sopenharmony_ci /* We looped over too many time leave with the 24562306a36Sopenharmony_ci * fact that we might have set an older fence 24662306a36Sopenharmony_ci * seq then the current real last seq as signaled 24762306a36Sopenharmony_ci * by the hw. 24862306a36Sopenharmony_ci */ 24962306a36Sopenharmony_ci break; 25062306a36Sopenharmony_ci } 25162306a36Sopenharmony_ci } while (atomic64_xchg(&rdev->fence_drv[ring].last_seq, seq) > seq); 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci if (seq < last_emitted) 25462306a36Sopenharmony_ci radeon_fence_schedule_check(rdev, ring); 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci return wake; 25762306a36Sopenharmony_ci} 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci/** 26062306a36Sopenharmony_ci * radeon_fence_check_lockup - check for hardware lockup 26162306a36Sopenharmony_ci * 26262306a36Sopenharmony_ci * @work: delayed work item 26362306a36Sopenharmony_ci * 26462306a36Sopenharmony_ci * Checks for fence activity and if there is none probe 26562306a36Sopenharmony_ci * the hardware if a lockup occured. 26662306a36Sopenharmony_ci */ 26762306a36Sopenharmony_cistatic void radeon_fence_check_lockup(struct work_struct *work) 26862306a36Sopenharmony_ci{ 26962306a36Sopenharmony_ci struct radeon_fence_driver *fence_drv; 27062306a36Sopenharmony_ci struct radeon_device *rdev; 27162306a36Sopenharmony_ci int ring; 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci fence_drv = container_of(work, struct radeon_fence_driver, 27462306a36Sopenharmony_ci lockup_work.work); 27562306a36Sopenharmony_ci rdev = fence_drv->rdev; 27662306a36Sopenharmony_ci ring = fence_drv - &rdev->fence_drv[0]; 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci if (!down_read_trylock(&rdev->exclusive_lock)) { 27962306a36Sopenharmony_ci /* just reschedule the check if a reset is going on */ 28062306a36Sopenharmony_ci radeon_fence_schedule_check(rdev, ring); 28162306a36Sopenharmony_ci return; 28262306a36Sopenharmony_ci } 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci if (fence_drv->delayed_irq && rdev->irq.installed) { 28562306a36Sopenharmony_ci unsigned long irqflags; 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci fence_drv->delayed_irq = false; 28862306a36Sopenharmony_ci spin_lock_irqsave(&rdev->irq.lock, irqflags); 28962306a36Sopenharmony_ci radeon_irq_set(rdev); 29062306a36Sopenharmony_ci spin_unlock_irqrestore(&rdev->irq.lock, irqflags); 29162306a36Sopenharmony_ci } 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci if (radeon_fence_activity(rdev, ring)) 29462306a36Sopenharmony_ci wake_up_all(&rdev->fence_queue); 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci else if (radeon_ring_is_lockup(rdev, ring, &rdev->ring[ring])) { 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci /* good news we believe it's a lockup */ 29962306a36Sopenharmony_ci dev_warn(rdev->dev, "GPU lockup (current fence id " 30062306a36Sopenharmony_ci "0x%016llx last fence id 0x%016llx on ring %d)\n", 30162306a36Sopenharmony_ci (uint64_t)atomic64_read(&fence_drv->last_seq), 30262306a36Sopenharmony_ci fence_drv->sync_seq[ring], ring); 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci /* remember that we need an reset */ 30562306a36Sopenharmony_ci rdev->needs_reset = true; 30662306a36Sopenharmony_ci wake_up_all(&rdev->fence_queue); 30762306a36Sopenharmony_ci } 30862306a36Sopenharmony_ci up_read(&rdev->exclusive_lock); 30962306a36Sopenharmony_ci} 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci/** 31262306a36Sopenharmony_ci * radeon_fence_process - process a fence 31362306a36Sopenharmony_ci * 31462306a36Sopenharmony_ci * @rdev: radeon_device pointer 31562306a36Sopenharmony_ci * @ring: ring index the fence is associated with 31662306a36Sopenharmony_ci * 31762306a36Sopenharmony_ci * Checks the current fence value and wakes the fence queue 31862306a36Sopenharmony_ci * if the sequence number has increased (all asics). 31962306a36Sopenharmony_ci */ 32062306a36Sopenharmony_civoid radeon_fence_process(struct radeon_device *rdev, int ring) 32162306a36Sopenharmony_ci{ 32262306a36Sopenharmony_ci if (radeon_fence_activity(rdev, ring)) 32362306a36Sopenharmony_ci wake_up_all(&rdev->fence_queue); 32462306a36Sopenharmony_ci} 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci/** 32762306a36Sopenharmony_ci * radeon_fence_seq_signaled - check if a fence sequence number has signaled 32862306a36Sopenharmony_ci * 32962306a36Sopenharmony_ci * @rdev: radeon device pointer 33062306a36Sopenharmony_ci * @seq: sequence number 33162306a36Sopenharmony_ci * @ring: ring index the fence is associated with 33262306a36Sopenharmony_ci * 33362306a36Sopenharmony_ci * Check if the last signaled fence sequnce number is >= the requested 33462306a36Sopenharmony_ci * sequence number (all asics). 33562306a36Sopenharmony_ci * Returns true if the fence has signaled (current fence value 33662306a36Sopenharmony_ci * is >= requested value) or false if it has not (current fence 33762306a36Sopenharmony_ci * value is < the requested value. Helper function for 33862306a36Sopenharmony_ci * radeon_fence_signaled(). 33962306a36Sopenharmony_ci */ 34062306a36Sopenharmony_cistatic bool radeon_fence_seq_signaled(struct radeon_device *rdev, 34162306a36Sopenharmony_ci u64 seq, unsigned ring) 34262306a36Sopenharmony_ci{ 34362306a36Sopenharmony_ci if (atomic64_read(&rdev->fence_drv[ring].last_seq) >= seq) { 34462306a36Sopenharmony_ci return true; 34562306a36Sopenharmony_ci } 34662306a36Sopenharmony_ci /* poll new last sequence at least once */ 34762306a36Sopenharmony_ci radeon_fence_process(rdev, ring); 34862306a36Sopenharmony_ci if (atomic64_read(&rdev->fence_drv[ring].last_seq) >= seq) { 34962306a36Sopenharmony_ci return true; 35062306a36Sopenharmony_ci } 35162306a36Sopenharmony_ci return false; 35262306a36Sopenharmony_ci} 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_cistatic bool radeon_fence_is_signaled(struct dma_fence *f) 35562306a36Sopenharmony_ci{ 35662306a36Sopenharmony_ci struct radeon_fence *fence = to_radeon_fence(f); 35762306a36Sopenharmony_ci struct radeon_device *rdev = fence->rdev; 35862306a36Sopenharmony_ci unsigned ring = fence->ring; 35962306a36Sopenharmony_ci u64 seq = fence->seq; 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci if (atomic64_read(&rdev->fence_drv[ring].last_seq) >= seq) { 36262306a36Sopenharmony_ci return true; 36362306a36Sopenharmony_ci } 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci if (down_read_trylock(&rdev->exclusive_lock)) { 36662306a36Sopenharmony_ci radeon_fence_process(rdev, ring); 36762306a36Sopenharmony_ci up_read(&rdev->exclusive_lock); 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci if (atomic64_read(&rdev->fence_drv[ring].last_seq) >= seq) { 37062306a36Sopenharmony_ci return true; 37162306a36Sopenharmony_ci } 37262306a36Sopenharmony_ci } 37362306a36Sopenharmony_ci return false; 37462306a36Sopenharmony_ci} 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci/** 37762306a36Sopenharmony_ci * radeon_fence_enable_signaling - enable signalling on fence 37862306a36Sopenharmony_ci * @f: fence 37962306a36Sopenharmony_ci * 38062306a36Sopenharmony_ci * This function is called with fence_queue lock held, and adds a callback 38162306a36Sopenharmony_ci * to fence_queue that checks if this fence is signaled, and if so it 38262306a36Sopenharmony_ci * signals the fence and removes itself. 38362306a36Sopenharmony_ci */ 38462306a36Sopenharmony_cistatic bool radeon_fence_enable_signaling(struct dma_fence *f) 38562306a36Sopenharmony_ci{ 38662306a36Sopenharmony_ci struct radeon_fence *fence = to_radeon_fence(f); 38762306a36Sopenharmony_ci struct radeon_device *rdev = fence->rdev; 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci if (atomic64_read(&rdev->fence_drv[fence->ring].last_seq) >= fence->seq) 39062306a36Sopenharmony_ci return false; 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci if (down_read_trylock(&rdev->exclusive_lock)) { 39362306a36Sopenharmony_ci radeon_irq_kms_sw_irq_get(rdev, fence->ring); 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci if (radeon_fence_activity(rdev, fence->ring)) 39662306a36Sopenharmony_ci wake_up_all_locked(&rdev->fence_queue); 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci /* did fence get signaled after we enabled the sw irq? */ 39962306a36Sopenharmony_ci if (atomic64_read(&rdev->fence_drv[fence->ring].last_seq) >= fence->seq) { 40062306a36Sopenharmony_ci radeon_irq_kms_sw_irq_put(rdev, fence->ring); 40162306a36Sopenharmony_ci up_read(&rdev->exclusive_lock); 40262306a36Sopenharmony_ci return false; 40362306a36Sopenharmony_ci } 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci up_read(&rdev->exclusive_lock); 40662306a36Sopenharmony_ci } else { 40762306a36Sopenharmony_ci /* we're probably in a lockup, lets not fiddle too much */ 40862306a36Sopenharmony_ci if (radeon_irq_kms_sw_irq_get_delayed(rdev, fence->ring)) 40962306a36Sopenharmony_ci rdev->fence_drv[fence->ring].delayed_irq = true; 41062306a36Sopenharmony_ci radeon_fence_schedule_check(rdev, fence->ring); 41162306a36Sopenharmony_ci } 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci fence->fence_wake.flags = 0; 41462306a36Sopenharmony_ci fence->fence_wake.private = NULL; 41562306a36Sopenharmony_ci fence->fence_wake.func = radeon_fence_check_signaled; 41662306a36Sopenharmony_ci __add_wait_queue(&rdev->fence_queue, &fence->fence_wake); 41762306a36Sopenharmony_ci dma_fence_get(f); 41862306a36Sopenharmony_ci return true; 41962306a36Sopenharmony_ci} 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci/** 42262306a36Sopenharmony_ci * radeon_fence_signaled - check if a fence has signaled 42362306a36Sopenharmony_ci * 42462306a36Sopenharmony_ci * @fence: radeon fence object 42562306a36Sopenharmony_ci * 42662306a36Sopenharmony_ci * Check if the requested fence has signaled (all asics). 42762306a36Sopenharmony_ci * Returns true if the fence has signaled or false if it has not. 42862306a36Sopenharmony_ci */ 42962306a36Sopenharmony_cibool radeon_fence_signaled(struct radeon_fence *fence) 43062306a36Sopenharmony_ci{ 43162306a36Sopenharmony_ci if (!fence) 43262306a36Sopenharmony_ci return true; 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci if (radeon_fence_seq_signaled(fence->rdev, fence->seq, fence->ring)) { 43562306a36Sopenharmony_ci dma_fence_signal(&fence->base); 43662306a36Sopenharmony_ci return true; 43762306a36Sopenharmony_ci } 43862306a36Sopenharmony_ci return false; 43962306a36Sopenharmony_ci} 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci/** 44262306a36Sopenharmony_ci * radeon_fence_any_seq_signaled - check if any sequence number is signaled 44362306a36Sopenharmony_ci * 44462306a36Sopenharmony_ci * @rdev: radeon device pointer 44562306a36Sopenharmony_ci * @seq: sequence numbers 44662306a36Sopenharmony_ci * 44762306a36Sopenharmony_ci * Check if the last signaled fence sequnce number is >= the requested 44862306a36Sopenharmony_ci * sequence number (all asics). 44962306a36Sopenharmony_ci * Returns true if any has signaled (current value is >= requested value) 45062306a36Sopenharmony_ci * or false if it has not. Helper function for radeon_fence_wait_seq. 45162306a36Sopenharmony_ci */ 45262306a36Sopenharmony_cistatic bool radeon_fence_any_seq_signaled(struct radeon_device *rdev, u64 *seq) 45362306a36Sopenharmony_ci{ 45462306a36Sopenharmony_ci unsigned i; 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci for (i = 0; i < RADEON_NUM_RINGS; ++i) { 45762306a36Sopenharmony_ci if (seq[i] && radeon_fence_seq_signaled(rdev, seq[i], i)) 45862306a36Sopenharmony_ci return true; 45962306a36Sopenharmony_ci } 46062306a36Sopenharmony_ci return false; 46162306a36Sopenharmony_ci} 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci/** 46462306a36Sopenharmony_ci * radeon_fence_wait_seq_timeout - wait for a specific sequence numbers 46562306a36Sopenharmony_ci * 46662306a36Sopenharmony_ci * @rdev: radeon device pointer 46762306a36Sopenharmony_ci * @target_seq: sequence number(s) we want to wait for 46862306a36Sopenharmony_ci * @intr: use interruptable sleep 46962306a36Sopenharmony_ci * @timeout: maximum time to wait, or MAX_SCHEDULE_TIMEOUT for infinite wait 47062306a36Sopenharmony_ci * 47162306a36Sopenharmony_ci * Wait for the requested sequence number(s) to be written by any ring 47262306a36Sopenharmony_ci * (all asics). Sequnce number array is indexed by ring id. 47362306a36Sopenharmony_ci * @intr selects whether to use interruptable (true) or non-interruptable 47462306a36Sopenharmony_ci * (false) sleep when waiting for the sequence number. Helper function 47562306a36Sopenharmony_ci * for radeon_fence_wait_*(). 47662306a36Sopenharmony_ci * Returns remaining time if the sequence number has passed, 0 when 47762306a36Sopenharmony_ci * the wait timeout, or an error for all other cases. 47862306a36Sopenharmony_ci * -EDEADLK is returned when a GPU lockup has been detected. 47962306a36Sopenharmony_ci */ 48062306a36Sopenharmony_cistatic long radeon_fence_wait_seq_timeout(struct radeon_device *rdev, 48162306a36Sopenharmony_ci u64 *target_seq, bool intr, 48262306a36Sopenharmony_ci long timeout) 48362306a36Sopenharmony_ci{ 48462306a36Sopenharmony_ci long r; 48562306a36Sopenharmony_ci int i; 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci if (radeon_fence_any_seq_signaled(rdev, target_seq)) 48862306a36Sopenharmony_ci return timeout; 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci /* enable IRQs and tracing */ 49162306a36Sopenharmony_ci for (i = 0; i < RADEON_NUM_RINGS; ++i) { 49262306a36Sopenharmony_ci if (!target_seq[i]) 49362306a36Sopenharmony_ci continue; 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_ci trace_radeon_fence_wait_begin(rdev->ddev, i, target_seq[i]); 49662306a36Sopenharmony_ci radeon_irq_kms_sw_irq_get(rdev, i); 49762306a36Sopenharmony_ci } 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci if (intr) { 50062306a36Sopenharmony_ci r = wait_event_interruptible_timeout(rdev->fence_queue, ( 50162306a36Sopenharmony_ci radeon_fence_any_seq_signaled(rdev, target_seq) 50262306a36Sopenharmony_ci || rdev->needs_reset), timeout); 50362306a36Sopenharmony_ci } else { 50462306a36Sopenharmony_ci r = wait_event_timeout(rdev->fence_queue, ( 50562306a36Sopenharmony_ci radeon_fence_any_seq_signaled(rdev, target_seq) 50662306a36Sopenharmony_ci || rdev->needs_reset), timeout); 50762306a36Sopenharmony_ci } 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci if (rdev->needs_reset) 51062306a36Sopenharmony_ci r = -EDEADLK; 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci for (i = 0; i < RADEON_NUM_RINGS; ++i) { 51362306a36Sopenharmony_ci if (!target_seq[i]) 51462306a36Sopenharmony_ci continue; 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci radeon_irq_kms_sw_irq_put(rdev, i); 51762306a36Sopenharmony_ci trace_radeon_fence_wait_end(rdev->ddev, i, target_seq[i]); 51862306a36Sopenharmony_ci } 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci return r; 52162306a36Sopenharmony_ci} 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ci/** 52462306a36Sopenharmony_ci * radeon_fence_wait_timeout - wait for a fence to signal with timeout 52562306a36Sopenharmony_ci * 52662306a36Sopenharmony_ci * @fence: radeon fence object 52762306a36Sopenharmony_ci * @intr: use interruptible sleep 52862306a36Sopenharmony_ci * 52962306a36Sopenharmony_ci * Wait for the requested fence to signal (all asics). 53062306a36Sopenharmony_ci * @intr selects whether to use interruptable (true) or non-interruptable 53162306a36Sopenharmony_ci * (false) sleep when waiting for the fence. 53262306a36Sopenharmony_ci * @timeout: maximum time to wait, or MAX_SCHEDULE_TIMEOUT for infinite wait 53362306a36Sopenharmony_ci * Returns remaining time if the sequence number has passed, 0 when 53462306a36Sopenharmony_ci * the wait timeout, or an error for all other cases. 53562306a36Sopenharmony_ci */ 53662306a36Sopenharmony_cilong radeon_fence_wait_timeout(struct radeon_fence *fence, bool intr, long timeout) 53762306a36Sopenharmony_ci{ 53862306a36Sopenharmony_ci uint64_t seq[RADEON_NUM_RINGS] = {}; 53962306a36Sopenharmony_ci long r; 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci /* 54262306a36Sopenharmony_ci * This function should not be called on !radeon fences. 54362306a36Sopenharmony_ci * If this is the case, it would mean this function can 54462306a36Sopenharmony_ci * also be called on radeon fences belonging to another card. 54562306a36Sopenharmony_ci * exclusive_lock is not held in that case. 54662306a36Sopenharmony_ci */ 54762306a36Sopenharmony_ci if (WARN_ON_ONCE(!to_radeon_fence(&fence->base))) 54862306a36Sopenharmony_ci return dma_fence_wait(&fence->base, intr); 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci seq[fence->ring] = fence->seq; 55162306a36Sopenharmony_ci r = radeon_fence_wait_seq_timeout(fence->rdev, seq, intr, timeout); 55262306a36Sopenharmony_ci if (r <= 0) { 55362306a36Sopenharmony_ci return r; 55462306a36Sopenharmony_ci } 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci dma_fence_signal(&fence->base); 55762306a36Sopenharmony_ci return r; 55862306a36Sopenharmony_ci} 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci/** 56162306a36Sopenharmony_ci * radeon_fence_wait - wait for a fence to signal 56262306a36Sopenharmony_ci * 56362306a36Sopenharmony_ci * @fence: radeon fence object 56462306a36Sopenharmony_ci * @intr: use interruptible sleep 56562306a36Sopenharmony_ci * 56662306a36Sopenharmony_ci * Wait for the requested fence to signal (all asics). 56762306a36Sopenharmony_ci * @intr selects whether to use interruptable (true) or non-interruptable 56862306a36Sopenharmony_ci * (false) sleep when waiting for the fence. 56962306a36Sopenharmony_ci * Returns 0 if the fence has passed, error for all other cases. 57062306a36Sopenharmony_ci */ 57162306a36Sopenharmony_ciint radeon_fence_wait(struct radeon_fence *fence, bool intr) 57262306a36Sopenharmony_ci{ 57362306a36Sopenharmony_ci long r = radeon_fence_wait_timeout(fence, intr, MAX_SCHEDULE_TIMEOUT); 57462306a36Sopenharmony_ci if (r > 0) { 57562306a36Sopenharmony_ci return 0; 57662306a36Sopenharmony_ci } else { 57762306a36Sopenharmony_ci return r; 57862306a36Sopenharmony_ci } 57962306a36Sopenharmony_ci} 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci/** 58262306a36Sopenharmony_ci * radeon_fence_wait_any - wait for a fence to signal on any ring 58362306a36Sopenharmony_ci * 58462306a36Sopenharmony_ci * @rdev: radeon device pointer 58562306a36Sopenharmony_ci * @fences: radeon fence object(s) 58662306a36Sopenharmony_ci * @intr: use interruptable sleep 58762306a36Sopenharmony_ci * 58862306a36Sopenharmony_ci * Wait for any requested fence to signal (all asics). Fence 58962306a36Sopenharmony_ci * array is indexed by ring id. @intr selects whether to use 59062306a36Sopenharmony_ci * interruptable (true) or non-interruptable (false) sleep when 59162306a36Sopenharmony_ci * waiting for the fences. Used by the suballocator. 59262306a36Sopenharmony_ci * Returns 0 if any fence has passed, error for all other cases. 59362306a36Sopenharmony_ci */ 59462306a36Sopenharmony_ciint radeon_fence_wait_any(struct radeon_device *rdev, 59562306a36Sopenharmony_ci struct radeon_fence **fences, 59662306a36Sopenharmony_ci bool intr) 59762306a36Sopenharmony_ci{ 59862306a36Sopenharmony_ci uint64_t seq[RADEON_NUM_RINGS]; 59962306a36Sopenharmony_ci unsigned i, num_rings = 0; 60062306a36Sopenharmony_ci long r; 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_ci for (i = 0; i < RADEON_NUM_RINGS; ++i) { 60362306a36Sopenharmony_ci seq[i] = 0; 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_ci if (!fences[i]) { 60662306a36Sopenharmony_ci continue; 60762306a36Sopenharmony_ci } 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_ci seq[i] = fences[i]->seq; 61062306a36Sopenharmony_ci ++num_rings; 61162306a36Sopenharmony_ci } 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_ci /* nothing to wait for ? */ 61462306a36Sopenharmony_ci if (num_rings == 0) 61562306a36Sopenharmony_ci return -ENOENT; 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_ci r = radeon_fence_wait_seq_timeout(rdev, seq, intr, MAX_SCHEDULE_TIMEOUT); 61862306a36Sopenharmony_ci if (r < 0) { 61962306a36Sopenharmony_ci return r; 62062306a36Sopenharmony_ci } 62162306a36Sopenharmony_ci return 0; 62262306a36Sopenharmony_ci} 62362306a36Sopenharmony_ci 62462306a36Sopenharmony_ci/** 62562306a36Sopenharmony_ci * radeon_fence_wait_next - wait for the next fence to signal 62662306a36Sopenharmony_ci * 62762306a36Sopenharmony_ci * @rdev: radeon device pointer 62862306a36Sopenharmony_ci * @ring: ring index the fence is associated with 62962306a36Sopenharmony_ci * 63062306a36Sopenharmony_ci * Wait for the next fence on the requested ring to signal (all asics). 63162306a36Sopenharmony_ci * Returns 0 if the next fence has passed, error for all other cases. 63262306a36Sopenharmony_ci * Caller must hold ring lock. 63362306a36Sopenharmony_ci */ 63462306a36Sopenharmony_ciint radeon_fence_wait_next(struct radeon_device *rdev, int ring) 63562306a36Sopenharmony_ci{ 63662306a36Sopenharmony_ci uint64_t seq[RADEON_NUM_RINGS] = {}; 63762306a36Sopenharmony_ci long r; 63862306a36Sopenharmony_ci 63962306a36Sopenharmony_ci seq[ring] = atomic64_read(&rdev->fence_drv[ring].last_seq) + 1ULL; 64062306a36Sopenharmony_ci if (seq[ring] >= rdev->fence_drv[ring].sync_seq[ring]) { 64162306a36Sopenharmony_ci /* nothing to wait for, last_seq is 64262306a36Sopenharmony_ci already the last emited fence */ 64362306a36Sopenharmony_ci return -ENOENT; 64462306a36Sopenharmony_ci } 64562306a36Sopenharmony_ci r = radeon_fence_wait_seq_timeout(rdev, seq, false, MAX_SCHEDULE_TIMEOUT); 64662306a36Sopenharmony_ci if (r < 0) 64762306a36Sopenharmony_ci return r; 64862306a36Sopenharmony_ci return 0; 64962306a36Sopenharmony_ci} 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_ci/** 65262306a36Sopenharmony_ci * radeon_fence_wait_empty - wait for all fences to signal 65362306a36Sopenharmony_ci * 65462306a36Sopenharmony_ci * @rdev: radeon device pointer 65562306a36Sopenharmony_ci * @ring: ring index the fence is associated with 65662306a36Sopenharmony_ci * 65762306a36Sopenharmony_ci * Wait for all fences on the requested ring to signal (all asics). 65862306a36Sopenharmony_ci * Returns 0 if the fences have passed, error for all other cases. 65962306a36Sopenharmony_ci * Caller must hold ring lock. 66062306a36Sopenharmony_ci */ 66162306a36Sopenharmony_ciint radeon_fence_wait_empty(struct radeon_device *rdev, int ring) 66262306a36Sopenharmony_ci{ 66362306a36Sopenharmony_ci uint64_t seq[RADEON_NUM_RINGS] = {}; 66462306a36Sopenharmony_ci long r; 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci seq[ring] = rdev->fence_drv[ring].sync_seq[ring]; 66762306a36Sopenharmony_ci if (!seq[ring]) 66862306a36Sopenharmony_ci return 0; 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci r = radeon_fence_wait_seq_timeout(rdev, seq, false, MAX_SCHEDULE_TIMEOUT); 67162306a36Sopenharmony_ci if (r < 0) { 67262306a36Sopenharmony_ci if (r == -EDEADLK) 67362306a36Sopenharmony_ci return -EDEADLK; 67462306a36Sopenharmony_ci 67562306a36Sopenharmony_ci dev_err(rdev->dev, "error waiting for ring[%d] to become idle (%ld)\n", 67662306a36Sopenharmony_ci ring, r); 67762306a36Sopenharmony_ci } 67862306a36Sopenharmony_ci return 0; 67962306a36Sopenharmony_ci} 68062306a36Sopenharmony_ci 68162306a36Sopenharmony_ci/** 68262306a36Sopenharmony_ci * radeon_fence_ref - take a ref on a fence 68362306a36Sopenharmony_ci * 68462306a36Sopenharmony_ci * @fence: radeon fence object 68562306a36Sopenharmony_ci * 68662306a36Sopenharmony_ci * Take a reference on a fence (all asics). 68762306a36Sopenharmony_ci * Returns the fence. 68862306a36Sopenharmony_ci */ 68962306a36Sopenharmony_cistruct radeon_fence *radeon_fence_ref(struct radeon_fence *fence) 69062306a36Sopenharmony_ci{ 69162306a36Sopenharmony_ci dma_fence_get(&fence->base); 69262306a36Sopenharmony_ci return fence; 69362306a36Sopenharmony_ci} 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_ci/** 69662306a36Sopenharmony_ci * radeon_fence_unref - remove a ref on a fence 69762306a36Sopenharmony_ci * 69862306a36Sopenharmony_ci * @fence: radeon fence object 69962306a36Sopenharmony_ci * 70062306a36Sopenharmony_ci * Remove a reference on a fence (all asics). 70162306a36Sopenharmony_ci */ 70262306a36Sopenharmony_civoid radeon_fence_unref(struct radeon_fence **fence) 70362306a36Sopenharmony_ci{ 70462306a36Sopenharmony_ci struct radeon_fence *tmp = *fence; 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ci *fence = NULL; 70762306a36Sopenharmony_ci if (tmp) { 70862306a36Sopenharmony_ci dma_fence_put(&tmp->base); 70962306a36Sopenharmony_ci } 71062306a36Sopenharmony_ci} 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_ci/** 71362306a36Sopenharmony_ci * radeon_fence_count_emitted - get the count of emitted fences 71462306a36Sopenharmony_ci * 71562306a36Sopenharmony_ci * @rdev: radeon device pointer 71662306a36Sopenharmony_ci * @ring: ring index the fence is associated with 71762306a36Sopenharmony_ci * 71862306a36Sopenharmony_ci * Get the number of fences emitted on the requested ring (all asics). 71962306a36Sopenharmony_ci * Returns the number of emitted fences on the ring. Used by the 72062306a36Sopenharmony_ci * dynpm code to ring track activity. 72162306a36Sopenharmony_ci */ 72262306a36Sopenharmony_ciunsigned radeon_fence_count_emitted(struct radeon_device *rdev, int ring) 72362306a36Sopenharmony_ci{ 72462306a36Sopenharmony_ci uint64_t emitted; 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_ci /* We are not protected by ring lock when reading the last sequence 72762306a36Sopenharmony_ci * but it's ok to report slightly wrong fence count here. 72862306a36Sopenharmony_ci */ 72962306a36Sopenharmony_ci radeon_fence_process(rdev, ring); 73062306a36Sopenharmony_ci emitted = rdev->fence_drv[ring].sync_seq[ring] 73162306a36Sopenharmony_ci - atomic64_read(&rdev->fence_drv[ring].last_seq); 73262306a36Sopenharmony_ci /* to avoid 32bits warp around */ 73362306a36Sopenharmony_ci if (emitted > 0x10000000) { 73462306a36Sopenharmony_ci emitted = 0x10000000; 73562306a36Sopenharmony_ci } 73662306a36Sopenharmony_ci return (unsigned)emitted; 73762306a36Sopenharmony_ci} 73862306a36Sopenharmony_ci 73962306a36Sopenharmony_ci/** 74062306a36Sopenharmony_ci * radeon_fence_need_sync - do we need a semaphore 74162306a36Sopenharmony_ci * 74262306a36Sopenharmony_ci * @fence: radeon fence object 74362306a36Sopenharmony_ci * @dst_ring: which ring to check against 74462306a36Sopenharmony_ci * 74562306a36Sopenharmony_ci * Check if the fence needs to be synced against another ring 74662306a36Sopenharmony_ci * (all asics). If so, we need to emit a semaphore. 74762306a36Sopenharmony_ci * Returns true if we need to sync with another ring, false if 74862306a36Sopenharmony_ci * not. 74962306a36Sopenharmony_ci */ 75062306a36Sopenharmony_cibool radeon_fence_need_sync(struct radeon_fence *fence, int dst_ring) 75162306a36Sopenharmony_ci{ 75262306a36Sopenharmony_ci struct radeon_fence_driver *fdrv; 75362306a36Sopenharmony_ci 75462306a36Sopenharmony_ci if (!fence) { 75562306a36Sopenharmony_ci return false; 75662306a36Sopenharmony_ci } 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_ci if (fence->ring == dst_ring) { 75962306a36Sopenharmony_ci return false; 76062306a36Sopenharmony_ci } 76162306a36Sopenharmony_ci 76262306a36Sopenharmony_ci /* we are protected by the ring mutex */ 76362306a36Sopenharmony_ci fdrv = &fence->rdev->fence_drv[dst_ring]; 76462306a36Sopenharmony_ci if (fence->seq <= fdrv->sync_seq[fence->ring]) { 76562306a36Sopenharmony_ci return false; 76662306a36Sopenharmony_ci } 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_ci return true; 76962306a36Sopenharmony_ci} 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_ci/** 77262306a36Sopenharmony_ci * radeon_fence_note_sync - record the sync point 77362306a36Sopenharmony_ci * 77462306a36Sopenharmony_ci * @fence: radeon fence object 77562306a36Sopenharmony_ci * @dst_ring: which ring to check against 77662306a36Sopenharmony_ci * 77762306a36Sopenharmony_ci * Note the sequence number at which point the fence will 77862306a36Sopenharmony_ci * be synced with the requested ring (all asics). 77962306a36Sopenharmony_ci */ 78062306a36Sopenharmony_civoid radeon_fence_note_sync(struct radeon_fence *fence, int dst_ring) 78162306a36Sopenharmony_ci{ 78262306a36Sopenharmony_ci struct radeon_fence_driver *dst, *src; 78362306a36Sopenharmony_ci unsigned i; 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_ci if (!fence) { 78662306a36Sopenharmony_ci return; 78762306a36Sopenharmony_ci } 78862306a36Sopenharmony_ci 78962306a36Sopenharmony_ci if (fence->ring == dst_ring) { 79062306a36Sopenharmony_ci return; 79162306a36Sopenharmony_ci } 79262306a36Sopenharmony_ci 79362306a36Sopenharmony_ci /* we are protected by the ring mutex */ 79462306a36Sopenharmony_ci src = &fence->rdev->fence_drv[fence->ring]; 79562306a36Sopenharmony_ci dst = &fence->rdev->fence_drv[dst_ring]; 79662306a36Sopenharmony_ci for (i = 0; i < RADEON_NUM_RINGS; ++i) { 79762306a36Sopenharmony_ci if (i == dst_ring) { 79862306a36Sopenharmony_ci continue; 79962306a36Sopenharmony_ci } 80062306a36Sopenharmony_ci dst->sync_seq[i] = max(dst->sync_seq[i], src->sync_seq[i]); 80162306a36Sopenharmony_ci } 80262306a36Sopenharmony_ci} 80362306a36Sopenharmony_ci 80462306a36Sopenharmony_ci/** 80562306a36Sopenharmony_ci * radeon_fence_driver_start_ring - make the fence driver 80662306a36Sopenharmony_ci * ready for use on the requested ring. 80762306a36Sopenharmony_ci * 80862306a36Sopenharmony_ci * @rdev: radeon device pointer 80962306a36Sopenharmony_ci * @ring: ring index to start the fence driver on 81062306a36Sopenharmony_ci * 81162306a36Sopenharmony_ci * Make the fence driver ready for processing (all asics). 81262306a36Sopenharmony_ci * Not all asics have all rings, so each asic will only 81362306a36Sopenharmony_ci * start the fence driver on the rings it has. 81462306a36Sopenharmony_ci * Returns 0 for success, errors for failure. 81562306a36Sopenharmony_ci */ 81662306a36Sopenharmony_ciint radeon_fence_driver_start_ring(struct radeon_device *rdev, int ring) 81762306a36Sopenharmony_ci{ 81862306a36Sopenharmony_ci uint64_t index; 81962306a36Sopenharmony_ci int r; 82062306a36Sopenharmony_ci 82162306a36Sopenharmony_ci radeon_scratch_free(rdev, rdev->fence_drv[ring].scratch_reg); 82262306a36Sopenharmony_ci if (rdev->wb.use_event || !radeon_ring_supports_scratch_reg(rdev, &rdev->ring[ring])) { 82362306a36Sopenharmony_ci rdev->fence_drv[ring].scratch_reg = 0; 82462306a36Sopenharmony_ci if (ring != R600_RING_TYPE_UVD_INDEX) { 82562306a36Sopenharmony_ci index = R600_WB_EVENT_OFFSET + ring * 4; 82662306a36Sopenharmony_ci rdev->fence_drv[ring].cpu_addr = &rdev->wb.wb[index/4]; 82762306a36Sopenharmony_ci rdev->fence_drv[ring].gpu_addr = rdev->wb.gpu_addr + 82862306a36Sopenharmony_ci index; 82962306a36Sopenharmony_ci 83062306a36Sopenharmony_ci } else { 83162306a36Sopenharmony_ci /* put fence directly behind firmware */ 83262306a36Sopenharmony_ci index = ALIGN(rdev->uvd_fw->size, 8); 83362306a36Sopenharmony_ci rdev->fence_drv[ring].cpu_addr = rdev->uvd.cpu_addr + index; 83462306a36Sopenharmony_ci rdev->fence_drv[ring].gpu_addr = rdev->uvd.gpu_addr + index; 83562306a36Sopenharmony_ci } 83662306a36Sopenharmony_ci 83762306a36Sopenharmony_ci } else { 83862306a36Sopenharmony_ci r = radeon_scratch_get(rdev, &rdev->fence_drv[ring].scratch_reg); 83962306a36Sopenharmony_ci if (r) { 84062306a36Sopenharmony_ci dev_err(rdev->dev, "fence failed to get scratch register\n"); 84162306a36Sopenharmony_ci return r; 84262306a36Sopenharmony_ci } 84362306a36Sopenharmony_ci index = RADEON_WB_SCRATCH_OFFSET + 84462306a36Sopenharmony_ci rdev->fence_drv[ring].scratch_reg - 84562306a36Sopenharmony_ci rdev->scratch.reg_base; 84662306a36Sopenharmony_ci rdev->fence_drv[ring].cpu_addr = &rdev->wb.wb[index/4]; 84762306a36Sopenharmony_ci rdev->fence_drv[ring].gpu_addr = rdev->wb.gpu_addr + index; 84862306a36Sopenharmony_ci } 84962306a36Sopenharmony_ci radeon_fence_write(rdev, atomic64_read(&rdev->fence_drv[ring].last_seq), ring); 85062306a36Sopenharmony_ci rdev->fence_drv[ring].initialized = true; 85162306a36Sopenharmony_ci dev_info(rdev->dev, "fence driver on ring %d use gpu addr 0x%016llx\n", 85262306a36Sopenharmony_ci ring, rdev->fence_drv[ring].gpu_addr); 85362306a36Sopenharmony_ci return 0; 85462306a36Sopenharmony_ci} 85562306a36Sopenharmony_ci 85662306a36Sopenharmony_ci/** 85762306a36Sopenharmony_ci * radeon_fence_driver_init_ring - init the fence driver 85862306a36Sopenharmony_ci * for the requested ring. 85962306a36Sopenharmony_ci * 86062306a36Sopenharmony_ci * @rdev: radeon device pointer 86162306a36Sopenharmony_ci * @ring: ring index to start the fence driver on 86262306a36Sopenharmony_ci * 86362306a36Sopenharmony_ci * Init the fence driver for the requested ring (all asics). 86462306a36Sopenharmony_ci * Helper function for radeon_fence_driver_init(). 86562306a36Sopenharmony_ci */ 86662306a36Sopenharmony_cistatic void radeon_fence_driver_init_ring(struct radeon_device *rdev, int ring) 86762306a36Sopenharmony_ci{ 86862306a36Sopenharmony_ci int i; 86962306a36Sopenharmony_ci 87062306a36Sopenharmony_ci rdev->fence_drv[ring].scratch_reg = -1; 87162306a36Sopenharmony_ci rdev->fence_drv[ring].cpu_addr = NULL; 87262306a36Sopenharmony_ci rdev->fence_drv[ring].gpu_addr = 0; 87362306a36Sopenharmony_ci for (i = 0; i < RADEON_NUM_RINGS; ++i) 87462306a36Sopenharmony_ci rdev->fence_drv[ring].sync_seq[i] = 0; 87562306a36Sopenharmony_ci atomic64_set(&rdev->fence_drv[ring].last_seq, 0); 87662306a36Sopenharmony_ci rdev->fence_drv[ring].initialized = false; 87762306a36Sopenharmony_ci INIT_DELAYED_WORK(&rdev->fence_drv[ring].lockup_work, 87862306a36Sopenharmony_ci radeon_fence_check_lockup); 87962306a36Sopenharmony_ci rdev->fence_drv[ring].rdev = rdev; 88062306a36Sopenharmony_ci} 88162306a36Sopenharmony_ci 88262306a36Sopenharmony_ci/** 88362306a36Sopenharmony_ci * radeon_fence_driver_init - init the fence driver 88462306a36Sopenharmony_ci * for all possible rings. 88562306a36Sopenharmony_ci * 88662306a36Sopenharmony_ci * @rdev: radeon device pointer 88762306a36Sopenharmony_ci * 88862306a36Sopenharmony_ci * Init the fence driver for all possible rings (all asics). 88962306a36Sopenharmony_ci * Not all asics have all rings, so each asic will only 89062306a36Sopenharmony_ci * start the fence driver on the rings it has using 89162306a36Sopenharmony_ci * radeon_fence_driver_start_ring(). 89262306a36Sopenharmony_ci */ 89362306a36Sopenharmony_civoid radeon_fence_driver_init(struct radeon_device *rdev) 89462306a36Sopenharmony_ci{ 89562306a36Sopenharmony_ci int ring; 89662306a36Sopenharmony_ci 89762306a36Sopenharmony_ci init_waitqueue_head(&rdev->fence_queue); 89862306a36Sopenharmony_ci for (ring = 0; ring < RADEON_NUM_RINGS; ring++) { 89962306a36Sopenharmony_ci radeon_fence_driver_init_ring(rdev, ring); 90062306a36Sopenharmony_ci } 90162306a36Sopenharmony_ci 90262306a36Sopenharmony_ci radeon_debugfs_fence_init(rdev); 90362306a36Sopenharmony_ci} 90462306a36Sopenharmony_ci 90562306a36Sopenharmony_ci/** 90662306a36Sopenharmony_ci * radeon_fence_driver_fini - tear down the fence driver 90762306a36Sopenharmony_ci * for all possible rings. 90862306a36Sopenharmony_ci * 90962306a36Sopenharmony_ci * @rdev: radeon device pointer 91062306a36Sopenharmony_ci * 91162306a36Sopenharmony_ci * Tear down the fence driver for all possible rings (all asics). 91262306a36Sopenharmony_ci */ 91362306a36Sopenharmony_civoid radeon_fence_driver_fini(struct radeon_device *rdev) 91462306a36Sopenharmony_ci{ 91562306a36Sopenharmony_ci int ring, r; 91662306a36Sopenharmony_ci 91762306a36Sopenharmony_ci mutex_lock(&rdev->ring_lock); 91862306a36Sopenharmony_ci for (ring = 0; ring < RADEON_NUM_RINGS; ring++) { 91962306a36Sopenharmony_ci if (!rdev->fence_drv[ring].initialized) 92062306a36Sopenharmony_ci continue; 92162306a36Sopenharmony_ci r = radeon_fence_wait_empty(rdev, ring); 92262306a36Sopenharmony_ci if (r) { 92362306a36Sopenharmony_ci /* no need to trigger GPU reset as we are unloading */ 92462306a36Sopenharmony_ci radeon_fence_driver_force_completion(rdev, ring); 92562306a36Sopenharmony_ci } 92662306a36Sopenharmony_ci cancel_delayed_work_sync(&rdev->fence_drv[ring].lockup_work); 92762306a36Sopenharmony_ci wake_up_all(&rdev->fence_queue); 92862306a36Sopenharmony_ci radeon_scratch_free(rdev, rdev->fence_drv[ring].scratch_reg); 92962306a36Sopenharmony_ci rdev->fence_drv[ring].initialized = false; 93062306a36Sopenharmony_ci } 93162306a36Sopenharmony_ci mutex_unlock(&rdev->ring_lock); 93262306a36Sopenharmony_ci} 93362306a36Sopenharmony_ci 93462306a36Sopenharmony_ci/** 93562306a36Sopenharmony_ci * radeon_fence_driver_force_completion - force all fence waiter to complete 93662306a36Sopenharmony_ci * 93762306a36Sopenharmony_ci * @rdev: radeon device pointer 93862306a36Sopenharmony_ci * @ring: the ring to complete 93962306a36Sopenharmony_ci * 94062306a36Sopenharmony_ci * In case of GPU reset failure make sure no process keep waiting on fence 94162306a36Sopenharmony_ci * that will never complete. 94262306a36Sopenharmony_ci */ 94362306a36Sopenharmony_civoid radeon_fence_driver_force_completion(struct radeon_device *rdev, int ring) 94462306a36Sopenharmony_ci{ 94562306a36Sopenharmony_ci if (rdev->fence_drv[ring].initialized) { 94662306a36Sopenharmony_ci radeon_fence_write(rdev, rdev->fence_drv[ring].sync_seq[ring], ring); 94762306a36Sopenharmony_ci cancel_delayed_work_sync(&rdev->fence_drv[ring].lockup_work); 94862306a36Sopenharmony_ci } 94962306a36Sopenharmony_ci} 95062306a36Sopenharmony_ci 95162306a36Sopenharmony_ci 95262306a36Sopenharmony_ci/* 95362306a36Sopenharmony_ci * Fence debugfs 95462306a36Sopenharmony_ci */ 95562306a36Sopenharmony_ci#if defined(CONFIG_DEBUG_FS) 95662306a36Sopenharmony_cistatic int radeon_debugfs_fence_info_show(struct seq_file *m, void *data) 95762306a36Sopenharmony_ci{ 95862306a36Sopenharmony_ci struct radeon_device *rdev = m->private; 95962306a36Sopenharmony_ci int i, j; 96062306a36Sopenharmony_ci 96162306a36Sopenharmony_ci for (i = 0; i < RADEON_NUM_RINGS; ++i) { 96262306a36Sopenharmony_ci if (!rdev->fence_drv[i].initialized) 96362306a36Sopenharmony_ci continue; 96462306a36Sopenharmony_ci 96562306a36Sopenharmony_ci radeon_fence_process(rdev, i); 96662306a36Sopenharmony_ci 96762306a36Sopenharmony_ci seq_printf(m, "--- ring %d ---\n", i); 96862306a36Sopenharmony_ci seq_printf(m, "Last signaled fence 0x%016llx\n", 96962306a36Sopenharmony_ci (unsigned long long)atomic64_read(&rdev->fence_drv[i].last_seq)); 97062306a36Sopenharmony_ci seq_printf(m, "Last emitted 0x%016llx\n", 97162306a36Sopenharmony_ci rdev->fence_drv[i].sync_seq[i]); 97262306a36Sopenharmony_ci 97362306a36Sopenharmony_ci for (j = 0; j < RADEON_NUM_RINGS; ++j) { 97462306a36Sopenharmony_ci if (i != j && rdev->fence_drv[j].initialized) 97562306a36Sopenharmony_ci seq_printf(m, "Last sync to ring %d 0x%016llx\n", 97662306a36Sopenharmony_ci j, rdev->fence_drv[i].sync_seq[j]); 97762306a36Sopenharmony_ci } 97862306a36Sopenharmony_ci } 97962306a36Sopenharmony_ci return 0; 98062306a36Sopenharmony_ci} 98162306a36Sopenharmony_ci 98262306a36Sopenharmony_ci/* 98362306a36Sopenharmony_ci * radeon_debugfs_gpu_reset - manually trigger a gpu reset 98462306a36Sopenharmony_ci * 98562306a36Sopenharmony_ci * Manually trigger a gpu reset at the next fence wait. 98662306a36Sopenharmony_ci */ 98762306a36Sopenharmony_cistatic int radeon_debugfs_gpu_reset(void *data, u64 *val) 98862306a36Sopenharmony_ci{ 98962306a36Sopenharmony_ci struct radeon_device *rdev = (struct radeon_device *)data; 99062306a36Sopenharmony_ci 99162306a36Sopenharmony_ci down_read(&rdev->exclusive_lock); 99262306a36Sopenharmony_ci *val = rdev->needs_reset; 99362306a36Sopenharmony_ci rdev->needs_reset = true; 99462306a36Sopenharmony_ci wake_up_all(&rdev->fence_queue); 99562306a36Sopenharmony_ci up_read(&rdev->exclusive_lock); 99662306a36Sopenharmony_ci 99762306a36Sopenharmony_ci return 0; 99862306a36Sopenharmony_ci} 99962306a36Sopenharmony_ciDEFINE_SHOW_ATTRIBUTE(radeon_debugfs_fence_info); 100062306a36Sopenharmony_ciDEFINE_DEBUGFS_ATTRIBUTE(radeon_debugfs_gpu_reset_fops, 100162306a36Sopenharmony_ci radeon_debugfs_gpu_reset, NULL, "%lld\n"); 100262306a36Sopenharmony_ci#endif 100362306a36Sopenharmony_ci 100462306a36Sopenharmony_civoid radeon_debugfs_fence_init(struct radeon_device *rdev) 100562306a36Sopenharmony_ci{ 100662306a36Sopenharmony_ci#if defined(CONFIG_DEBUG_FS) 100762306a36Sopenharmony_ci struct dentry *root = rdev->ddev->primary->debugfs_root; 100862306a36Sopenharmony_ci 100962306a36Sopenharmony_ci debugfs_create_file("radeon_gpu_reset", 0444, root, rdev, 101062306a36Sopenharmony_ci &radeon_debugfs_gpu_reset_fops); 101162306a36Sopenharmony_ci debugfs_create_file("radeon_fence_info", 0444, root, rdev, 101262306a36Sopenharmony_ci &radeon_debugfs_fence_info_fops); 101362306a36Sopenharmony_ci 101462306a36Sopenharmony_ci 101562306a36Sopenharmony_ci#endif 101662306a36Sopenharmony_ci} 101762306a36Sopenharmony_ci 101862306a36Sopenharmony_cistatic const char *radeon_fence_get_driver_name(struct dma_fence *fence) 101962306a36Sopenharmony_ci{ 102062306a36Sopenharmony_ci return "radeon"; 102162306a36Sopenharmony_ci} 102262306a36Sopenharmony_ci 102362306a36Sopenharmony_cistatic const char *radeon_fence_get_timeline_name(struct dma_fence *f) 102462306a36Sopenharmony_ci{ 102562306a36Sopenharmony_ci struct radeon_fence *fence = to_radeon_fence(f); 102662306a36Sopenharmony_ci switch (fence->ring) { 102762306a36Sopenharmony_ci case RADEON_RING_TYPE_GFX_INDEX: return "radeon.gfx"; 102862306a36Sopenharmony_ci case CAYMAN_RING_TYPE_CP1_INDEX: return "radeon.cp1"; 102962306a36Sopenharmony_ci case CAYMAN_RING_TYPE_CP2_INDEX: return "radeon.cp2"; 103062306a36Sopenharmony_ci case R600_RING_TYPE_DMA_INDEX: return "radeon.dma"; 103162306a36Sopenharmony_ci case CAYMAN_RING_TYPE_DMA1_INDEX: return "radeon.dma1"; 103262306a36Sopenharmony_ci case R600_RING_TYPE_UVD_INDEX: return "radeon.uvd"; 103362306a36Sopenharmony_ci case TN_RING_TYPE_VCE1_INDEX: return "radeon.vce1"; 103462306a36Sopenharmony_ci case TN_RING_TYPE_VCE2_INDEX: return "radeon.vce2"; 103562306a36Sopenharmony_ci default: WARN_ON_ONCE(1); return "radeon.unk"; 103662306a36Sopenharmony_ci } 103762306a36Sopenharmony_ci} 103862306a36Sopenharmony_ci 103962306a36Sopenharmony_cistatic inline bool radeon_test_signaled(struct radeon_fence *fence) 104062306a36Sopenharmony_ci{ 104162306a36Sopenharmony_ci return test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->base.flags); 104262306a36Sopenharmony_ci} 104362306a36Sopenharmony_ci 104462306a36Sopenharmony_cistruct radeon_wait_cb { 104562306a36Sopenharmony_ci struct dma_fence_cb base; 104662306a36Sopenharmony_ci struct task_struct *task; 104762306a36Sopenharmony_ci}; 104862306a36Sopenharmony_ci 104962306a36Sopenharmony_cistatic void 105062306a36Sopenharmony_ciradeon_fence_wait_cb(struct dma_fence *fence, struct dma_fence_cb *cb) 105162306a36Sopenharmony_ci{ 105262306a36Sopenharmony_ci struct radeon_wait_cb *wait = 105362306a36Sopenharmony_ci container_of(cb, struct radeon_wait_cb, base); 105462306a36Sopenharmony_ci 105562306a36Sopenharmony_ci wake_up_process(wait->task); 105662306a36Sopenharmony_ci} 105762306a36Sopenharmony_ci 105862306a36Sopenharmony_cistatic signed long radeon_fence_default_wait(struct dma_fence *f, bool intr, 105962306a36Sopenharmony_ci signed long t) 106062306a36Sopenharmony_ci{ 106162306a36Sopenharmony_ci struct radeon_fence *fence = to_radeon_fence(f); 106262306a36Sopenharmony_ci struct radeon_device *rdev = fence->rdev; 106362306a36Sopenharmony_ci struct radeon_wait_cb cb; 106462306a36Sopenharmony_ci 106562306a36Sopenharmony_ci cb.task = current; 106662306a36Sopenharmony_ci 106762306a36Sopenharmony_ci if (dma_fence_add_callback(f, &cb.base, radeon_fence_wait_cb)) 106862306a36Sopenharmony_ci return t; 106962306a36Sopenharmony_ci 107062306a36Sopenharmony_ci while (t > 0) { 107162306a36Sopenharmony_ci if (intr) 107262306a36Sopenharmony_ci set_current_state(TASK_INTERRUPTIBLE); 107362306a36Sopenharmony_ci else 107462306a36Sopenharmony_ci set_current_state(TASK_UNINTERRUPTIBLE); 107562306a36Sopenharmony_ci 107662306a36Sopenharmony_ci /* 107762306a36Sopenharmony_ci * radeon_test_signaled must be called after 107862306a36Sopenharmony_ci * set_current_state to prevent a race with wake_up_process 107962306a36Sopenharmony_ci */ 108062306a36Sopenharmony_ci if (radeon_test_signaled(fence)) 108162306a36Sopenharmony_ci break; 108262306a36Sopenharmony_ci 108362306a36Sopenharmony_ci if (rdev->needs_reset) { 108462306a36Sopenharmony_ci t = -EDEADLK; 108562306a36Sopenharmony_ci break; 108662306a36Sopenharmony_ci } 108762306a36Sopenharmony_ci 108862306a36Sopenharmony_ci t = schedule_timeout(t); 108962306a36Sopenharmony_ci 109062306a36Sopenharmony_ci if (t > 0 && intr && signal_pending(current)) 109162306a36Sopenharmony_ci t = -ERESTARTSYS; 109262306a36Sopenharmony_ci } 109362306a36Sopenharmony_ci 109462306a36Sopenharmony_ci __set_current_state(TASK_RUNNING); 109562306a36Sopenharmony_ci dma_fence_remove_callback(f, &cb.base); 109662306a36Sopenharmony_ci 109762306a36Sopenharmony_ci return t; 109862306a36Sopenharmony_ci} 109962306a36Sopenharmony_ci 110062306a36Sopenharmony_ciconst struct dma_fence_ops radeon_fence_ops = { 110162306a36Sopenharmony_ci .get_driver_name = radeon_fence_get_driver_name, 110262306a36Sopenharmony_ci .get_timeline_name = radeon_fence_get_timeline_name, 110362306a36Sopenharmony_ci .enable_signaling = radeon_fence_enable_signaling, 110462306a36Sopenharmony_ci .signaled = radeon_fence_is_signaled, 110562306a36Sopenharmony_ci .wait = radeon_fence_default_wait, 110662306a36Sopenharmony_ci .release = NULL, 110762306a36Sopenharmony_ci}; 1108