Subversion Repositories Kolibri OS

Compare Revisions

Regard whitespace Rev 5077 → Rev 5078

/drivers/video/drm/radeon/radeon_fence.c
37,6 → 37,7
#include <drm/drmP.h>
#include "radeon_reg.h"
#include "radeon.h"
#include "radeon_trace.h"
 
/*
* Fences
120,7 → 121,7
(*fence)->seq = ++rdev->fence_drv[ring].sync_seq[ring];
(*fence)->ring = ring;
radeon_fence_ring_emit(rdev, ring, *fence);
// trace_radeon_fence_emit(rdev->ddev, (*fence)->seq);
trace_radeon_fence_emit(rdev->ddev, ring, (*fence)->seq);
return 0;
}
 
189,11 → 190,9
}
} while (atomic64_xchg(&rdev->fence_drv[ring].last_seq, seq) > seq);
 
if (wake) {
rdev->fence_drv[ring].last_activity = GetTimerTicks();
if (wake)
wake_up_all(&rdev->fence_queue);
}
}
 
/**
* radeon_fence_destroy - destroy a fence
211,13 → 210,13
}
 
/**
* radeon_fence_seq_signaled - check if a fence sequeuce number has signaled
* radeon_fence_seq_signaled - check if a fence sequence number has signaled
*
* @rdev: radeon device pointer
* @seq: sequence number
* @ring: ring index the fence is associated with
*
* Check if the last singled fence sequnce number is >= the requested
* Check if the last signaled fence sequnce number is >= the requested
* sequence number (all asics).
* Returns true if the fence has signaled (current fence value
* is >= requested value) or false if it has not (current fence
262,115 → 261,124
}
 
/**
* radeon_fence_wait_seq - wait for a specific sequence number
* radeon_fence_any_seq_signaled - check if any sequence number is signaled
*
* @rdev: radeon device pointer
* @target_seq: sequence number we want to wait for
* @ring: ring index the fence is associated with
* @seq: sequence numbers
*
* Check if the last signaled fence sequnce number is >= the requested
* sequence number (all asics).
* Returns true if any has signaled (current value is >= requested value)
* or false if it has not. Helper function for radeon_fence_wait_seq.
*/
static bool radeon_fence_any_seq_signaled(struct radeon_device *rdev, u64 *seq)
{
unsigned i;
 
for (i = 0; i < RADEON_NUM_RINGS; ++i) {
if (seq[i] && radeon_fence_seq_signaled(rdev, seq[i], i))
return true;
}
return false;
}
 
/**
* radeon_fence_wait_seq - wait for a specific sequence numbers
*
* @rdev: radeon device pointer
* @target_seq: sequence number(s) we want to wait for
* @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).
* Wait for the requested sequence number(s) to be written by any ring
* (all asics). Sequnce number array is indexed by ring id.
* @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.
* for radeon_fence_wait_*().
* 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.
* -EDEADLK is returned when a GPU lockup has been detected.
*/
static int radeon_fence_wait_seq(struct radeon_device *rdev, u64 target_seq,
unsigned ring, bool intr, bool lock_ring)
static int radeon_fence_wait_seq(struct radeon_device *rdev, u64 *target_seq,
bool intr)
{
unsigned long timeout, last_activity;
uint64_t seq;
unsigned i;
uint64_t last_seq[RADEON_NUM_RINGS];
bool signaled;
int r;
int i, r;
 
while (target_seq > atomic64_read(&rdev->fence_drv[ring].last_seq)) {
if (!rdev->ring[ring].ready) {
return -EBUSY;
}
while (!radeon_fence_any_seq_signaled(rdev, target_seq)) {
 
timeout = GetTimerTicks() - RADEON_FENCE_JIFFIES_TIMEOUT;
if (time_after(rdev->fence_drv[ring].last_activity, timeout)) {
/* the normal case, timeout is somewhere before last_activity */
timeout = rdev->fence_drv[ring].last_activity - timeout;
} else {
/* 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
*/
timeout = 1;
/* Save current sequence values, used to check for GPU lockups */
for (i = 0; i < RADEON_NUM_RINGS; ++i) {
if (!target_seq[i])
continue;
 
last_seq[i] = atomic64_read(&rdev->fence_drv[i].last_seq);
trace_radeon_fence_wait_begin(rdev->ddev, i, target_seq[i]);
radeon_irq_kms_sw_irq_get(rdev, i);
}
seq = atomic64_read(&rdev->fence_drv[ring].last_seq);
/* Save current last activity valuee, used to check for GPU lockups */
last_activity = rdev->fence_drv[ring].last_activity;
 
// trace_radeon_fence_wait_begin(rdev->ddev, seq);
radeon_irq_kms_sw_irq_get(rdev, ring);
if (intr) {
r = wait_event_interruptible_timeout(rdev->fence_queue,
(signaled = radeon_fence_seq_signaled(rdev, target_seq, ring)),
timeout);
r = wait_event_interruptible_timeout(rdev->fence_queue, (
(signaled = radeon_fence_any_seq_signaled(rdev, target_seq))
|| rdev->needs_reset), RADEON_FENCE_JIFFIES_TIMEOUT);
} else {
r = wait_event_timeout(rdev->fence_queue,
(signaled = radeon_fence_seq_signaled(rdev, target_seq, ring)),
timeout);
r = wait_event_timeout(rdev->fence_queue, (
(signaled = radeon_fence_any_seq_signaled(rdev, target_seq))
|| rdev->needs_reset), RADEON_FENCE_JIFFIES_TIMEOUT);
}
radeon_irq_kms_sw_irq_put(rdev, ring);
if (unlikely(r < 0)) {
return r;
 
for (i = 0; i < RADEON_NUM_RINGS; ++i) {
if (!target_seq[i])
continue;
 
radeon_irq_kms_sw_irq_put(rdev, i);
trace_radeon_fence_wait_end(rdev->ddev, i, target_seq[i]);
}
// trace_radeon_fence_wait_end(rdev->ddev, seq);
 
if (unlikely(r < 0))
return r;
 
if (unlikely(!signaled)) {
if (rdev->needs_reset)
return -EDEADLK;
 
/* we were interrupted for some reason and fence
* isn't signaled yet, resume waiting */
if (r) {
if (r)
continue;
}
 
/* check if sequence value has changed since last_activity */
if (seq != atomic64_read(&rdev->fence_drv[ring].last_seq)) {
for (i = 0; i < RADEON_NUM_RINGS; ++i) {
if (!target_seq[i])
continue;
}
 
if (lock_ring) {
mutex_lock(&rdev->ring_lock);
if (last_seq[i] != atomic64_read(&rdev->fence_drv[i].last_seq))
break;
}
 
/* test if somebody else has already decided that this is a lockup */
if (last_activity != rdev->fence_drv[ring].last_activity) {
if (lock_ring) {
mutex_unlock(&rdev->ring_lock);
}
if (i != RADEON_NUM_RINGS)
continue;
 
for (i = 0; i < RADEON_NUM_RINGS; ++i) {
if (!target_seq[i])
continue;
 
if (radeon_ring_is_lockup(rdev, i, &rdev->ring[i]))
break;
}
 
if (radeon_ring_is_lockup(rdev, ring, &rdev->ring[ring])) {
if (i < RADEON_NUM_RINGS) {
/* good news we believe it's a lockup */
dev_warn(rdev->dev, "GPU lockup (waiting for 0x%016llx last fence id 0x%016llx)\n",
target_seq, seq);
dev_warn(rdev->dev, "GPU lockup (waiting for "
"0x%016llx last fence id 0x%016llx on"
" ring %d)\n",
target_seq[i], last_seq[i], i);
 
/* change last activity so nobody else think there is a lockup */
for (i = 0; i < RADEON_NUM_RINGS; ++i) {
rdev->fence_drv[i].last_activity = GetTimerTicks();
}
 
/* mark the ring as not ready any more */
rdev->ring[ring].ready = false;
if (lock_ring) {
mutex_unlock(&rdev->ring_lock);
}
/* remember that we need an reset */
rdev->needs_reset = true;
wake_up_all(&rdev->fence_queue);
return -EDEADLK;
}
 
if (lock_ring) {
mutex_unlock(&rdev->ring_lock);
}
}
}
return 0;
}
 
387,6 → 395,7
*/
int radeon_fence_wait(struct radeon_fence *fence, bool intr)
{
uint64_t seq[RADEON_NUM_RINGS] = {};
int r;
 
if (fence == NULL) {
394,147 → 403,15
return -EINVAL;
}
 
r = radeon_fence_wait_seq(fence->rdev, fence->seq,
fence->ring, intr, true);
if (r) {
return r;
}
fence->seq = RADEON_FENCE_SIGNALED_SEQ;
seq[fence->ring] = fence->seq;
if (seq[fence->ring] == RADEON_FENCE_SIGNALED_SEQ)
return 0;
}
 
static bool radeon_fence_any_seq_signaled(struct radeon_device *rdev, u64 *seq)
{
unsigned i;
 
for (i = 0; i < RADEON_NUM_RINGS; ++i) {
if (seq[i] && radeon_fence_seq_signaled(rdev, seq[i], i)) {
return true;
}
}
return false;
}
 
/**
* radeon_fence_wait_any_seq - wait for a sequence number on any ring
*
* @rdev: radeon device pointer
* @target_seq: sequence number(s) we want to wait for
* @intr: use interruptable sleep
*
* Wait for the requested sequence number(s) to be written by any ring
* (all asics). Sequnce number array is indexed by ring id.
* @intr selects whether to use interruptable (true) or non-interruptable
* (false) sleep when waiting for the sequence number. Helper function
* for radeon_fence_wait_any(), et al.
* Returns 0 if the sequence number has passed, error for all other cases.
*/
static int radeon_fence_wait_any_seq(struct radeon_device *rdev,
u64 *target_seq, bool intr)
{
unsigned long timeout, last_activity, tmp;
unsigned i, ring = RADEON_NUM_RINGS;
bool signaled;
int r;
 
for (i = 0, last_activity = 0; i < RADEON_NUM_RINGS; ++i) {
if (!target_seq[i]) {
continue;
}
 
/* use the most recent one as indicator */
if (time_after(rdev->fence_drv[i].last_activity, last_activity)) {
last_activity = rdev->fence_drv[i].last_activity;
}
 
/* For lockup detection just pick the lowest ring we are
* actively waiting for
*/
if (i < ring) {
ring = i;
}
}
 
/* nothing to wait for ? */
if (ring == RADEON_NUM_RINGS) {
return -ENOENT;
}
 
while (!radeon_fence_any_seq_signaled(rdev, target_seq)) {
timeout = GetTimerTicks() - RADEON_FENCE_JIFFIES_TIMEOUT;
if (time_after(last_activity, timeout)) {
/* the normal case, timeout is somewhere before last_activity */
timeout = last_activity - timeout;
} else {
/* 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
*/
timeout = 1;
}
 
// trace_radeon_fence_wait_begin(rdev->ddev, target_seq[ring]);
for (i = 0; i < RADEON_NUM_RINGS; ++i) {
if (target_seq[i]) {
radeon_irq_kms_sw_irq_get(rdev, i);
}
}
if (intr) {
r = wait_event_interruptible_timeout(rdev->fence_queue,
(signaled = radeon_fence_any_seq_signaled(rdev, target_seq)),
timeout);
} else {
r = wait_event_timeout(rdev->fence_queue,
(signaled = radeon_fence_any_seq_signaled(rdev, target_seq)),
timeout);
}
for (i = 0; i < RADEON_NUM_RINGS; ++i) {
if (target_seq[i]) {
radeon_irq_kms_sw_irq_put(rdev, i);
}
}
if (unlikely(r < 0)) {
r = radeon_fence_wait_seq(fence->rdev, seq, intr);
if (r)
return r;
}
// trace_radeon_fence_wait_end(rdev->ddev, seq);
 
if (unlikely(!signaled)) {
/* we were interrupted for some reason and fence
* isn't signaled yet, resume waiting */
if (r) {
continue;
}
 
mutex_lock(&rdev->ring_lock);
for (i = 0, tmp = 0; i < RADEON_NUM_RINGS; ++i) {
if (time_after(rdev->fence_drv[i].last_activity, tmp)) {
tmp = rdev->fence_drv[i].last_activity;
}
}
/* test if somebody else has already decided that this is a lockup */
if (last_activity != tmp) {
last_activity = tmp;
mutex_unlock(&rdev->ring_lock);
continue;
}
 
if (radeon_ring_is_lockup(rdev, ring, &rdev->ring[ring])) {
/* good news we believe it's a lockup */
dev_warn(rdev->dev, "GPU lockup (waiting for 0x%016llx)\n",
target_seq[ring]);
 
/* change last activity so nobody else think there is a lockup */
for (i = 0; i < RADEON_NUM_RINGS; ++i) {
rdev->fence_drv[i].last_activity = GetTimerTicks();
}
 
/* mark the ring as not ready any more */
rdev->ring[ring].ready = false;
mutex_unlock(&rdev->ring_lock);
return -EDEADLK;
}
mutex_unlock(&rdev->ring_lock);
}
}
fence->seq = RADEON_FENCE_SIGNALED_SEQ;
return 0;
}
 
556,7 → 433,7
bool intr)
{
uint64_t seq[RADEON_NUM_RINGS];
unsigned i;
unsigned i, num_rings = 0;
int r;
 
for (i = 0; i < RADEON_NUM_RINGS; ++i) {
566,15 → 443,19
continue;
}
 
if (fences[i]->seq == RADEON_FENCE_SIGNALED_SEQ) {
/* something was allready signaled */
seq[i] = fences[i]->seq;
++num_rings;
 
/* test if something was allready signaled */
if (seq[i] == RADEON_FENCE_SIGNALED_SEQ)
return 0;
}
 
seq[i] = fences[i]->seq;
}
/* nothing to wait for ? */
if (num_rings == 0)
return -ENOENT;
 
r = radeon_fence_wait_any_seq(rdev, seq, intr);
r = radeon_fence_wait_seq(rdev, seq, intr);
if (r) {
return r;
}
582,7 → 463,7
}
 
/**
* radeon_fence_wait_next_locked - wait for the next fence to signal
* radeon_fence_wait_next - wait for the next fence to signal
*
* @rdev: radeon device pointer
* @ring: ring index the fence is associated with
591,21 → 472,21
* Returns 0 if the next fence has passed, error for all other cases.
* Caller must hold ring lock.
*/
int radeon_fence_wait_next_locked(struct radeon_device *rdev, int ring)
int radeon_fence_wait_next(struct radeon_device *rdev, int ring)
{
uint64_t seq;
uint64_t seq[RADEON_NUM_RINGS] = {};
 
seq = atomic64_read(&rdev->fence_drv[ring].last_seq) + 1ULL;
if (seq >= rdev->fence_drv[ring].sync_seq[ring]) {
seq[ring] = atomic64_read(&rdev->fence_drv[ring].last_seq) + 1ULL;
if (seq[ring] >= rdev->fence_drv[ring].sync_seq[ring]) {
/* nothing to wait for, last_seq is
already the last emited fence */
return -ENOENT;
}
return radeon_fence_wait_seq(rdev, seq, ring, false, false);
return radeon_fence_wait_seq(rdev, seq, false);
}
 
/**
* radeon_fence_wait_empty_locked - wait for all fences to signal
* radeon_fence_wait_empty - wait for all fences to signal
*
* @rdev: radeon device pointer
* @ring: ring index the fence is associated with
614,16 → 495,20
* Returns 0 if the fences have passed, error for all other cases.
* Caller must hold ring lock.
*/
int radeon_fence_wait_empty_locked(struct radeon_device *rdev, int ring)
int radeon_fence_wait_empty(struct radeon_device *rdev, int ring)
{
uint64_t seq = rdev->fence_drv[ring].sync_seq[ring];
uint64_t seq[RADEON_NUM_RINGS] = {};
int r;
 
r = radeon_fence_wait_seq(rdev, seq, ring, false, false);
seq[ring] = rdev->fence_drv[ring].sync_seq[ring];
if (!seq[ring])
return 0;
 
r = radeon_fence_wait_seq(rdev, seq, false);
if (r) {
if (r == -EDEADLK) {
if (r == -EDEADLK)
return -EDEADLK;
}
 
dev_err(rdev->dev, "error waiting for ring[%d] to become idle (%d)\n",
ring, r);
}
825,7 → 710,6
for (i = 0; i < RADEON_NUM_RINGS; ++i)
rdev->fence_drv[ring].sync_seq[i] = 0;
atomic64_set(&rdev->fence_drv[ring].last_seq, 0);
rdev->fence_drv[ring].last_activity = GetTimerTicks();
rdev->fence_drv[ring].initialized = false;
}
 
871,7 → 755,7
for (ring = 0; ring < RADEON_NUM_RINGS; ring++) {
if (!rdev->fence_drv[ring].initialized)
continue;
r = radeon_fence_wait_empty_locked(rdev, ring);
r = radeon_fence_wait_empty(rdev, ring);
if (r) {
/* no need to trigger GPU reset as we are unloading */
radeon_fence_driver_force_completion(rdev);
918,6 → 802,8
if (!rdev->fence_drv[i].initialized)
continue;
 
radeon_fence_process(rdev, i);
 
seq_printf(m, "--- ring %d ---\n", i);
seq_printf(m, "Last signaled fence 0x%016llx\n",
(unsigned long long)atomic64_read(&rdev->fence_drv[i].last_seq));
933,8 → 819,28
return 0;
}
 
/**
* radeon_debugfs_gpu_reset - manually trigger a gpu reset
*
* Manually trigger a gpu reset at the next fence wait.
*/
static int radeon_debugfs_gpu_reset(struct seq_file *m, void *data)
{
struct drm_info_node *node = (struct drm_info_node *) m->private;
struct drm_device *dev = node->minor->dev;
struct radeon_device *rdev = dev->dev_private;
 
down_read(&rdev->exclusive_lock);
seq_printf(m, "%d\n", rdev->needs_reset);
rdev->needs_reset = true;
up_read(&rdev->exclusive_lock);
 
return 0;
}
 
static struct drm_info_list radeon_debugfs_fence_list[] = {
{"radeon_fence_info", &radeon_debugfs_fence_info, 0, NULL},
{"radeon_gpu_reset", &radeon_debugfs_gpu_reset, 0, NULL}
};
#endif
 
941,7 → 847,7
int radeon_debugfs_fence_init(struct radeon_device *rdev)
{
#if defined(CONFIG_DEBUG_FS)
return radeon_debugfs_add_files(rdev, radeon_debugfs_fence_list, 1);
return radeon_debugfs_add_files(rdev, radeon_debugfs_fence_list, 2);
#else
return 0;
#endif