/** * amdgpu_fence_process - check for fence activity * * @ring: pointer to struct amdgpu_ring * * Checks the current fence value and calculates the last * signalled fence value. Wakes the fence queue if the * sequence number has increased. */ void amdgpu_fence_process(struct amdgpu_ring *ring) { struct amdgpu_fence_driver *drv = &ring->fence_drv; uint32_t seq, last_seq; int r; do { last_seq = atomic_read(&ring->fence_drv.last_seq); seq = amdgpu_fence_read(ring); } while (atomic_cmpxchg(&drv->last_seq, last_seq, seq) != last_seq); if (seq != ring->fence_drv.sync_seq) amdgpu_fence_schedule_fallback(ring); while (last_seq != seq) { struct fence *fence, **ptr; ptr = &drv->fences[++last_seq & drv->num_fences_mask]; /* There is always exactly one thread signaling this fence slot */ fence = rcu_dereference_protected(*ptr, 1); RCU_INIT_POINTER(*ptr, NULL); BUG_ON(!fence); r = fence_signal(fence); if (!r) FENCE_TRACE(fence, "signaled from irq context\n"); else BUG(); fence_put(fence); } }
/** * radeon_fence_wait - wait for a fence to signal * * @fence: radeon fence object * @intr: use interruptible sleep * * Wait for the requested fence to signal (all asics). * @intr selects whether to use interruptable (true) or non-interruptable * (false) sleep when waiting for the fence. * Returns 0 if the fence has passed, error for all other cases. */ int radeon_fence_wait(struct radeon_fence *fence, bool intr) { uint64_t seq[RADEON_NUM_RINGS] = {}; long r; /* * This function should not be called on !radeon fences. * If this is the case, it would mean this function can * also be called on radeon fences belonging to another card. * exclusive_lock is not held in that case. */ if (WARN_ON_ONCE(!to_radeon_fence(&fence->base))) return fence_wait(&fence->base, intr); seq[fence->ring] = fence->seq; r = radeon_fence_wait_seq_timeout(fence->rdev, seq, intr, MAX_SCHEDULE_TIMEOUT); if (r < 0) { return r; } r = fence_signal(&fence->base); if (!r) FENCE_TRACE(&fence->base, "signaled from fence_wait\n"); return 0; }
/** * radeon_fence_signaled - check if a fence has signaled * * @fence: radeon fence object * * Check if the requested fence has signaled (all asics). * Returns true if the fence has signaled or false if it has not. */ bool radeon_fence_signaled(struct radeon_fence *fence) { if (!fence) return true; if (radeon_fence_seq_signaled(fence->rdev, fence->seq, fence->ring)) { int ret; ret = fence_signal(&fence->base); if (!ret) FENCE_TRACE(&fence->base, "signaled from radeon_fence_signaled\n"); return true; } return false; }
/* * Hangcheck detection for locked gpu: */ static void recover_worker(struct work_struct *work) { struct etnaviv_gpu *gpu = container_of(work, struct etnaviv_gpu, recover_work); unsigned long flags; unsigned int i; dev_err(gpu->dev, "hangcheck recover!\n"); if (pm_runtime_get_sync(gpu->dev) < 0) return; mutex_lock(&gpu->lock); /* Only catch the first event, or when manually re-armed */ if (etnaviv_dump_core) { etnaviv_core_dump(gpu); etnaviv_dump_core = false; } etnaviv_hw_reset(gpu); /* complete all events, the GPU won't do it after the reset */ spin_lock_irqsave(&gpu->event_spinlock, flags); for (i = 0; i < ARRAY_SIZE(gpu->event); i++) { if (!gpu->event[i].used) continue; fence_signal(gpu->event[i].fence); gpu->event[i].fence = NULL; gpu->event[i].used = false; complete(&gpu->event_free); } spin_unlock_irqrestore(&gpu->event_spinlock, flags); gpu->completed_fence = gpu->active_fence; etnaviv_gpu_hw_init(gpu); gpu->switch_context = true; gpu->exec_state = -1; mutex_unlock(&gpu->lock); pm_runtime_mark_last_busy(gpu->dev); pm_runtime_put_autosuspend(gpu->dev); /* Retire the buffer objects in a work */ etnaviv_queue_work(gpu->drm, &gpu->retire_work); }