FreeBSD/sys/dev/drm2/radeon/radeon_fence.c
/**
 * radeon_fence_wait_seq - wait for a specific sequence number
 *
 * @rdev: radeon device pointer
 * @target_seq: sequence number we want to wait for
 * @ring: ring index the fence is associated with
 * @intr: use interruptable sleep
 * @lock_ring: whether the ring should be locked or not
 *
 * Wait for the requested sequence number to be written (all asics).
 * @intr selects whether to use interruptable (true) or non-interruptable
 * (false) sleep when waiting for the sequence number.  Helper function
 * for radeon_fence_wait(), et al.
 * Returns 0 if the sequence number has passed, error for all other cases.
 * -EDEADLK is returned when a GPU lockup has been detected and the ring is
 * marked as not ready so no further jobs get scheduled until a successful
 * reset.
 */


Wait for the requested sequence number to be written (all asics).
@intr selects whether to use interruptable (true) or non-interruptable
(false) sleep when waiting for the sequence number.  Helper function
for radeon_fence_wait(), et al.
Returns 0 if the sequence number has passed, error for all other cases.
-EDEADLK is returned when a GPU lockup has been detected and the ring is
marked as not ready so no further jobs get scheduled until a successful
reset.
Wait for the requested sequence number to be written ( all asics ) . @intr selects whether to use interruptable ( true ) or non - interruptable ( false ) sleep when waiting for the sequence number . Helper function for radeon_fence_wait () et al . Returns 0 if the sequence number has passed error for all other cases . - EDEADLK is returned when a GPU lockup has been detected and the ring is marked as not ready so no further jobs get scheduled until a successful reset .
static int radeon_fence_wait_seq(struct radeon_device *rdev, u64 target_seq,
				 unsigned ring, bool intr, bool lock_ring)
{
	unsigned long timeout, last_activity;
	uint64_t seq;
	unsigned i;
	bool signaled, fence_queue_locked;
	int r;
	while (target_seq > atomic64_read(&rdev->fence_drv[ring].last_seq)) {
		if (!rdev->ring[ring].ready) {
			return -EBUSY;
		}
		timeout = jiffies - RADEON_FENCE_JIFFIES_TIMEOUT;
		if (time_after(rdev->fence_drv[ring].last_activity, timeout)) {
			timeout = rdev->fence_drv[ring].last_activity - timeout;
		} else {
			timeout = 1;
		}
		seq = atomic64_read(&rdev->fence_drv[ring].last_seq);
		last_activity = rdev->fence_drv[ring].last_activity;
		CTR2(KTR_DRM, "radeon fence: wait begin (ring=%d, seq=%d)",
		    ring, seq);
		radeon_irq_kms_sw_irq_get(rdev, ring);
		fence_queue_locked = false;
		r = 0;
		while (!(signaled = radeon_fence_seq_signaled(rdev,
		    target_seq, ring))) {
			if (!fence_queue_locked) {
				mtx_lock(&rdev->fence_queue_mtx);
				fence_queue_locked = true;
			}
			if (intr) {
				r = cv_timedwait_sig(&rdev->fence_queue,
				    &rdev->fence_queue_mtx,
				    timeout);
			} else {
				r = cv_timedwait(&rdev->fence_queue,
				    &rdev->fence_queue_mtx,
				    timeout);
			}
			if (r == EINTR)
				r = ERESTARTSYS;
			if (r != 0) {
				if (r == EWOULDBLOCK) {
					signaled =
					    radeon_fence_seq_signaled(
						rdev, target_seq, ring);
				}
				break;
			}
		}
		if (fence_queue_locked) {
			mtx_unlock(&rdev->fence_queue_mtx);
		}
		radeon_irq_kms_sw_irq_put(rdev, ring);
		if (unlikely(r == ERESTARTSYS)) {
			return -r;
		}
		CTR2(KTR_DRM, "radeon fence: wait end (ring=%d, seq=%d)",
		    ring, seq);
		if (unlikely(!signaled)) {
#ifndef __FreeBSD__
			if (r) {
				continue;
			}
#endif
			if (seq != atomic64_read(&rdev->fence_drv[ring].last_seq)) {
				continue;
			}
			if (lock_ring) {
				sx_xlock(&rdev->ring_lock);
			}
			if (last_activity != rdev->fence_drv[ring].last_activity) {
				if (lock_ring) {
					sx_xunlock(&rdev->ring_lock);
				}
				continue;
			}
			if (radeon_ring_is_lockup(rdev, ring, &rdev->ring[ring])) {
				dev_warn(rdev->dev, "GPU lockup (waiting for 0x%016jx last fence id 0x%016jx)\n",
					 (uintmax_t)target_seq, (uintmax_t)seq);
				for (i = 0; i < RADEON_NUM_RINGS; ++i) {
					rdev->fence_drv[i].last_activity = jiffies;
				}
				rdev->ring[ring].ready = false;
				if (lock_ring) {
					sx_xunlock(&rdev->ring_lock);
				}
				return -EDEADLK;
			}
			if (lock_ring) {
				sx_xunlock(&rdev->ring_lock);
			}
		}
	}
	return 0;
}
static int radeon_fence_wait_seq ( struct radeon_device * rdev , u64 target_seq , unsigned ring , bool intr , bool lock_ring ) { unsigned long timeout , last_activity ; uint64_t seq ; unsigned i ; bool signaled , fence_queue_locked ; int r ; while ( target_seq > atomic64_read ( & rdev -> fence_drv [ ring ] . last_seq ) ) { if ( ! rdev -> ring [ ring ] . ready ) { return - EBUSY ; } timeout = jiffies - RADEON_FENCE_JIFFIES_TIMEOUT ; if ( time_after ( rdev -> fence_drv [ ring ] . last_activity , timeout ) ) { timeout = rdev -> fence_drv [ ring ] . last_activity - timeout ; } else { timeout = 1 ; } seq = atomic64_read ( & rdev -> fence_drv [ ring ] . last_seq ) ; last_activity = rdev -> fence_drv [ ring ] . last_activity ; CTR2 ( KTR_DRM , " " , ring , seq ) ; radeon_irq_kms_sw_irq_get ( rdev , ring ) ; fence_queue_locked = false ; r = 0 ; while ( ! ( signaled = radeon_fence_seq_signaled ( rdev , target_seq , ring ) ) ) { if ( ! fence_queue_locked ) { mtx_lock ( & rdev -> fence_queue_mtx ) ; fence_queue_locked = true ; } if ( intr ) { r = cv_timedwait_sig ( & rdev -> fence_queue , & rdev -> fence_queue_mtx , timeout ) ; } else { r = cv_timedwait ( & rdev -> fence_queue , & rdev -> fence_queue_mtx , timeout ) ; } if ( r == EINTR ) r = ERESTARTSYS ; if ( r != 0 ) { if ( r == EWOULDBLOCK ) { signaled = radeon_fence_seq_signaled ( rdev , target_seq , ring ) ; } break ; } } if ( fence_queue_locked ) { mtx_unlock ( & rdev -> fence_queue_mtx ) ; } radeon_irq_kms_sw_irq_put ( rdev , ring ) ; if ( unlikely ( r == ERESTARTSYS ) ) { return - r ; } CTR2 ( KTR_DRM , " " , ring , seq ) ; if ( unlikely ( ! signaled ) ) { #ifndef __FreeBSD__ if ( r ) { continue ; } #endif if ( seq != atomic64_read ( & rdev -> fence_drv [ ring ] . last_seq ) ) { continue ; } if ( lock_ring ) { sx_xlock ( & rdev -> ring_lock ) ; } if ( last_activity != rdev -> fence_drv [ ring ] . last_activity ) { if ( lock_ring ) { sx_xunlock ( & rdev -> ring_lock ) ; } continue ; } if ( radeon_ring_is_lockup ( rdev , ring , & rdev -> ring [ ring ] ) ) { dev_warn ( rdev -> dev , " \n " , ( uintmax_t ) target_seq , ( uintmax_t ) seq ) ; for ( i = 0 ; i < RADEON_NUM_RINGS ; ++ i ) { rdev -> fence_drv [ i ] . last_activity = jiffies ; } rdev -> ring [ ring ] . ready = false ; if ( lock_ring ) { sx_xunlock ( & rdev -> ring_lock ) ; } return - EDEADLK ; } if ( lock_ring ) { sx_xunlock ( & rdev -> ring_lock ) ; } } } return 0 ; }
radeon_fence_wait_seq - wait for a specific sequence number
 @rdev: radeon device pointer
 @target_seq: sequence number we want to wait for
 @ring: ring index the fence is associated with
 @intr: use interruptable sleep
 @lock_ring: whether the ring should be locked or not
radeon_fence_wait_seq - wait for a specific sequence number @rdev : radeon device pointer @target_seq : sequence number we want to wait for @ring : ring index the fence is associated with @intr : use interruptable sleep @lock_ring : whether the ring should be locked or not
/* the normal case, timeout is somewhere before last_activity */ /* either jiffies wrapped around, or no fence was signaled in the last 500ms
			 * anyway we will just wait for the minimum amount and then check for a lockup
			 */ /* Save current last activity valuee, used to check for GPU lockups */ /* we were interrupted for some reason and fence
			 * isn't signaled yet, resume waiting */ /* check if sequence value has changed since last_activity */ /* test if somebody else has already decided that this is a lockup */ /* good news we believe it's a lockup */ /* change last activity so nobody else think there is a lockup */ /* mark the ring as not ready any more */