static int radeon_debugfs_ring_info(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; int ridx = *(int*)node->info_ent->data; struct radeon_ring *ring = &rdev->ring[ridx]; uint32_t rptr, wptr, rptr_next; unsigned count, i, j; radeon_ring_free_size(rdev, ring); count = (ring->ring_size / 4) - ring->ring_free_dw; wptr = radeon_ring_get_wptr(rdev, ring); seq_printf(m, "wptr: 0x%08x [%5d]\n", wptr, wptr); rptr = radeon_ring_get_rptr(rdev, ring); seq_printf(m, "rptr: 0x%08x [%5d]\n", rptr, rptr); if (ring->rptr_save_reg) { rptr_next = RREG32(ring->rptr_save_reg); seq_printf(m, "rptr next(0x%04x): 0x%08x [%5d]\n", ring->rptr_save_reg, rptr_next, rptr_next); } else rptr_next = ~0; seq_printf(m, "driver's copy of the wptr: 0x%08x [%5d]\n", ring->wptr, ring->wptr); seq_printf(m, "last semaphore signal addr : 0x%016llx\n", ring->last_semaphore_signal_addr); seq_printf(m, "last semaphore wait addr : 0x%016llx\n", ring->last_semaphore_wait_addr); seq_printf(m, "%u free dwords in ring\n", ring->ring_free_dw); seq_printf(m, "%u dwords in ring\n", count); if (!ring->ready) return 0; /* print 8 dw before current rptr as often it's the last executed * packet that is the root issue */ i = (rptr + ring->ptr_mask + 1 - 32) & ring->ptr_mask; for (j = 0; j <= (count + 32); j++) { seq_printf(m, "r[%5d]=0x%08x", i, ring->ring[i]); if (rptr == i) seq_puts(m, " *"); if (rptr_next == i) seq_puts(m, " #"); seq_puts(m, "\n"); i = (i + 1) & ring->ptr_mask; } return 0; }
/** * radeon_ring_free_size - update the free size * * @rdev: radeon_device pointer * @ring: radeon_ring structure holding ring information * * Update the free dw slots in the ring buffer (all asics). */ void radeon_ring_free_size(struct radeon_device *rdev, struct radeon_ring *ring) { ring->rptr = radeon_ring_get_rptr(rdev, ring); /* This works because ring_size is a power of 2 */ ring->ring_free_dw = (ring->rptr + (ring->ring_size / 4)); ring->ring_free_dw -= ring->wptr; ring->ring_free_dw &= ring->ptr_mask; if (!ring->ring_free_dw) { ring->ring_free_dw = ring->ring_size / 4; } }
/** * radeon_ring_free_size - update the free size * * @rdev: radeon_device pointer * @ring: radeon_ring structure holding ring information * * Update the free dw slots in the ring buffer (all asics). */ void radeon_ring_free_size(struct radeon_device *rdev, struct radeon_ring *ring) { uint32_t rptr = radeon_ring_get_rptr(rdev, ring); /* This works because ring_size is a power of 2 */ ring->ring_free_dw = rptr + (ring->ring_size / 4); ring->ring_free_dw -= ring->wptr; ring->ring_free_dw &= ring->ptr_mask; if (!ring->ring_free_dw) { /* this is an empty ring */ ring->ring_free_dw = ring->ring_size / 4; /* update lockup info to avoid false positive */ radeon_ring_lockup_update(rdev, ring); } }
/** * radeon_ring_test_lockup() - check if ring is lockedup by recording information * @rdev: radeon device structure * @ring: radeon_ring structure holding ring information * */ bool radeon_ring_test_lockup(struct radeon_device *rdev, struct radeon_ring *ring) { uint32_t rptr = radeon_ring_get_rptr(rdev, ring); uint64_t last = atomic64_read(&ring->last_activity); uint64_t elapsed; if (rptr != atomic_read(&ring->last_rptr)) { /* ring is still working, no lockup */ radeon_ring_lockup_update(rdev, ring); return false; } elapsed = jiffies_to_msecs(jiffies_64 - last); if (radeon_lockup_timeout && elapsed >= radeon_lockup_timeout) { dev_err(rdev->dev, "ring %d stalled for more than %llumsec\n", ring->idx, elapsed); return true; } /* give a chance to the GPU ... */ return false; }
/** * radeon_ring_test_lockup() - check if ring is lockedup by recording information * @rdev: radeon device structure * @ring: radeon_ring structure holding ring information * * We don't need to initialize the lockup tracking information as we will either * have CP rptr to a different value of jiffies wrap around which will force * initialization of the lockup tracking informations. * * A possible false positivie is if we get call after while and last_cp_rptr == * the current CP rptr, even if it's unlikely it might happen. To avoid this * if the elapsed time since last call is bigger than 2 second than we return * false and update the tracking information. Due to this the caller must call * radeon_ring_test_lockup several time in less than 2sec for lockup to be reported * the fencing code should be cautious about that. * * Caller should write to the ring to force CP to do something so we don't get * false positive when CP is just gived nothing to do. * **/ bool radeon_ring_test_lockup(struct radeon_device *rdev, struct radeon_ring *ring) { unsigned long cjiffies, elapsed; cjiffies = jiffies; if (!time_after(cjiffies, ring->last_activity)) { /* likely a wrap around */ radeon_ring_lockup_update(ring); return false; } ring->rptr = radeon_ring_get_rptr(rdev, ring); if (ring->rptr != ring->last_rptr) { /* CP is still working no lockup */ radeon_ring_lockup_update(ring); return false; } elapsed = jiffies_to_msecs(cjiffies - ring->last_activity); if (radeon_lockup_timeout && elapsed >= radeon_lockup_timeout) { dev_err(rdev->dev, "GPU lockup CP stall for more than %lumsec\n", elapsed); return true; } /* give a chance to the GPU ... */ return false; }
/** * radeon_ring_lockup_update - update lockup variables * * @ring: radeon_ring structure holding ring information * * Update the last rptr value and timestamp (all asics). */ void radeon_ring_lockup_update(struct radeon_device *rdev, struct radeon_ring *ring) { atomic_set(&ring->last_rptr, radeon_ring_get_rptr(rdev, ring)); atomic64_set(&ring->last_activity, jiffies_64); }