aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian König <deathsimple@vodafone.de>2012-07-09 05:52:44 -0400
committerChristian König <deathsimple@vodafone.de>2012-07-17 04:33:15 -0400
commit55d7c22192becd0ec827a6901899ff56fa985658 (patch)
tree2876d95b10e9bac71ef168dd998537c731d3222f
parent45df68035c4964d42ea3850980708ce8674f75b3 (diff)
drm/radeon: implement ring saving on reset v4
Try to save whatever is on the rings when we encounter an lockup. v2: Fix spelling error. Free saved ring data if reset fails. Add documentation for the new functions. v3: Some more spelling fixes v4: It doesn't make sense to save anything if all fences are signaled Signed-off-by: Christian König <deathsimple@vodafone.de> Reviewed-by: Michel Dänzer <michel.daenzer@amd.com> Reviewed-by: Alex Deucher <alexander.deucher@amd.com>
-rw-r--r--drivers/gpu/drm/radeon/radeon.h4
-rw-r--r--drivers/gpu/drm/radeon/radeon_device.c48
-rw-r--r--drivers/gpu/drm/radeon/radeon_ring.c82
3 files changed, 126 insertions, 8 deletions
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
index 64d39adaad91..6715e4c695fa 100644
--- a/drivers/gpu/drm/radeon/radeon.h
+++ b/drivers/gpu/drm/radeon/radeon.h
@@ -768,6 +768,10 @@ int radeon_ring_test(struct radeon_device *rdev, struct radeon_ring *cp);
768void radeon_ring_force_activity(struct radeon_device *rdev, struct radeon_ring *ring); 768void radeon_ring_force_activity(struct radeon_device *rdev, struct radeon_ring *ring);
769void radeon_ring_lockup_update(struct radeon_ring *ring); 769void radeon_ring_lockup_update(struct radeon_ring *ring);
770bool radeon_ring_test_lockup(struct radeon_device *rdev, struct radeon_ring *ring); 770bool radeon_ring_test_lockup(struct radeon_device *rdev, struct radeon_ring *ring);
771unsigned radeon_ring_backup(struct radeon_device *rdev, struct radeon_ring *ring,
772 uint32_t **data);
773int radeon_ring_restore(struct radeon_device *rdev, struct radeon_ring *ring,
774 unsigned size, uint32_t *data);
771int radeon_ring_init(struct radeon_device *rdev, struct radeon_ring *cp, unsigned ring_size, 775int radeon_ring_init(struct radeon_device *rdev, struct radeon_ring *cp, unsigned ring_size,
772 unsigned rptr_offs, unsigned rptr_reg, unsigned wptr_reg, 776 unsigned rptr_offs, unsigned rptr_reg, unsigned wptr_reg,
773 u32 ptr_reg_shift, u32 ptr_reg_mask, u32 nop); 777 u32 ptr_reg_shift, u32 ptr_reg_mask, u32 nop);
diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c
index bbd09718e956..0302a9f3e674 100644
--- a/drivers/gpu/drm/radeon/radeon_device.c
+++ b/drivers/gpu/drm/radeon/radeon_device.c
@@ -996,7 +996,12 @@ int radeon_resume_kms(struct drm_device *dev)
996 996
997int radeon_gpu_reset(struct radeon_device *rdev) 997int radeon_gpu_reset(struct radeon_device *rdev)
998{ 998{
999 int r; 999 unsigned ring_sizes[RADEON_NUM_RINGS];
1000 uint32_t *ring_data[RADEON_NUM_RINGS];
1001
1002 bool saved = false;
1003
1004 int i, r;
1000 int resched; 1005 int resched;
1001 1006
1002 down_write(&rdev->exclusive_lock); 1007 down_write(&rdev->exclusive_lock);
@@ -1005,20 +1010,47 @@ int radeon_gpu_reset(struct radeon_device *rdev)
1005 resched = ttm_bo_lock_delayed_workqueue(&rdev->mman.bdev); 1010 resched = ttm_bo_lock_delayed_workqueue(&rdev->mman.bdev);
1006 radeon_suspend(rdev); 1011 radeon_suspend(rdev);
1007 1012
1013 for (i = 0; i < RADEON_NUM_RINGS; ++i) {
1014 ring_sizes[i] = radeon_ring_backup(rdev, &rdev->ring[i],
1015 &ring_data[i]);
1016 if (ring_sizes[i]) {
1017 saved = true;
1018 dev_info(rdev->dev, "Saved %d dwords of commands "
1019 "on ring %d.\n", ring_sizes[i], i);
1020 }
1021 }
1022
1023retry:
1008 r = radeon_asic_reset(rdev); 1024 r = radeon_asic_reset(rdev);
1009 if (!r) { 1025 if (!r) {
1010 dev_info(rdev->dev, "GPU reset succeed\n"); 1026 dev_info(rdev->dev, "GPU reset succeeded, trying to resume\n");
1011 radeon_resume(rdev); 1027 radeon_resume(rdev);
1028 }
1012 1029
1013 r = radeon_ib_ring_tests(rdev); 1030 radeon_restore_bios_scratch_regs(rdev);
1014 if (r) 1031 drm_helper_resume_force_mode(rdev->ddev);
1015 DRM_ERROR("ib ring test failed (%d).\n", r);
1016 1032
1017 radeon_restore_bios_scratch_regs(rdev); 1033 if (!r) {
1018 drm_helper_resume_force_mode(rdev->ddev); 1034 for (i = 0; i < RADEON_NUM_RINGS; ++i) {
1019 ttm_bo_unlock_delayed_workqueue(&rdev->mman.bdev, resched); 1035 radeon_ring_restore(rdev, &rdev->ring[i],
1036 ring_sizes[i], ring_data[i]);
1037 }
1038
1039 r = radeon_ib_ring_tests(rdev);
1040 if (r) {
1041 dev_err(rdev->dev, "ib ring test failed (%d).\n", r);
1042 if (saved) {
1043 radeon_suspend(rdev);
1044 goto retry;
1045 }
1046 }
1047 } else {
1048 for (i = 0; i < RADEON_NUM_RINGS; ++i) {
1049 kfree(ring_data[i]);
1050 }
1020 } 1051 }
1021 1052
1053 ttm_bo_unlock_delayed_workqueue(&rdev->mman.bdev, resched);
1022 if (r) { 1054 if (r) {
1023 /* bad news, how to tell it to userspace ? */ 1055 /* bad news, how to tell it to userspace ? */
1024 dev_info(rdev->dev, "GPU reset failed\n"); 1056 dev_info(rdev->dev, "GPU reset failed\n");
diff --git a/drivers/gpu/drm/radeon/radeon_ring.c b/drivers/gpu/drm/radeon/radeon_ring.c
index ce8eb9d5af5d..75cbe4641138 100644
--- a/drivers/gpu/drm/radeon/radeon_ring.c
+++ b/drivers/gpu/drm/radeon/radeon_ring.c
@@ -362,6 +362,88 @@ bool radeon_ring_test_lockup(struct radeon_device *rdev, struct radeon_ring *rin
362 return false; 362 return false;
363} 363}
364 364
365/**
366 * radeon_ring_backup - Back up the content of a ring
367 *
368 * @rdev: radeon_device pointer
369 * @ring: the ring we want to back up
370 *
371 * Saves all unprocessed commits from a ring, returns the number of dwords saved.
372 */
373unsigned radeon_ring_backup(struct radeon_device *rdev, struct radeon_ring *ring,
374 uint32_t **data)
375{
376 unsigned size, ptr, i;
377 int ridx = radeon_ring_index(rdev, ring);
378
379 /* just in case lock the ring */
380 mutex_lock(&rdev->ring_lock);
381 *data = NULL;
382
383 if (ring->ring_obj == NULL || !ring->rptr_save_reg) {
384 mutex_unlock(&rdev->ring_lock);
385 return 0;
386 }
387
388 /* it doesn't make sense to save anything if all fences are signaled */
389 if (!radeon_fence_count_emitted(rdev, ridx)) {
390 mutex_unlock(&rdev->ring_lock);
391 return 0;
392 }
393
394 /* calculate the number of dw on the ring */
395 ptr = RREG32(ring->rptr_save_reg);
396 size = ring->wptr + (ring->ring_size / 4);
397 size -= ptr;
398 size &= ring->ptr_mask;
399 if (size == 0) {
400 mutex_unlock(&rdev->ring_lock);
401 return 0;
402 }
403
404 /* and then save the content of the ring */
405 *data = kmalloc(size * 4, GFP_KERNEL);
406 for (i = 0; i < size; ++i) {
407 (*data)[i] = ring->ring[ptr++];
408 ptr &= ring->ptr_mask;
409 }
410
411 mutex_unlock(&rdev->ring_lock);
412 return size;
413}
414
415/**
416 * radeon_ring_restore - append saved commands to the ring again
417 *
418 * @rdev: radeon_device pointer
419 * @ring: ring to append commands to
420 * @size: number of dwords we want to write
421 * @data: saved commands
422 *
423 * Allocates space on the ring and restore the previously saved commands.
424 */
425int radeon_ring_restore(struct radeon_device *rdev, struct radeon_ring *ring,
426 unsigned size, uint32_t *data)
427{
428 int i, r;
429
430 if (!size || !data)
431 return 0;
432
433 /* restore the saved ring content */
434 r = radeon_ring_lock(rdev, ring, size);
435 if (r)
436 return r;
437
438 for (i = 0; i < size; ++i) {
439 radeon_ring_write(ring, data[i]);
440 }
441
442 radeon_ring_unlock_commit(rdev, ring);
443 kfree(data);
444 return 0;
445}
446
365int radeon_ring_init(struct radeon_device *rdev, struct radeon_ring *ring, unsigned ring_size, 447int radeon_ring_init(struct radeon_device *rdev, struct radeon_ring *ring, unsigned ring_size,
366 unsigned rptr_offs, unsigned rptr_reg, unsigned wptr_reg, 448 unsigned rptr_offs, unsigned rptr_reg, unsigned wptr_reg,
367 u32 ptr_reg_shift, u32 ptr_reg_mask, u32 nop) 449 u32 ptr_reg_shift, u32 ptr_reg_mask, u32 nop)