Skip to contentSkip to conversation

Prevent leak of scratch register on resume from suspend.

PATCH In review Simon Kitching 2 participants 2 messages Sep 20, 2012

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

PATCH 1/1 Prevent leak of scratch register on resume from suspend.

Cards typically have 5-7 scratch registers; one of these is reserved for rdev->rptr_save_reg. Unfortunately the reservation is done in function r100_cp_init, which is called by all drivers except r600 - and this function is also invoked on resume from suspend. After several resumes, no scratch registers are free and graphics acceleration is disabled.

Dmesg then reports either:
*ERROR* radeon: cp failed to get scratch reg (-22). *ERROR* radeon: cp isn't working(-22). radeon 0000:01:00.0: failed initializing CP (-22).
or:
*ERROR* radeon: failed to get scratch reg (-22). *ERROR* radeon: failed testing IB on GFX ring (-22). *ERROR* ib ring test failed (-22).

The chain of calls on boot for all except r600 is:
radeon_init -> ... -> (rXXX_init) -> rXXX_startup -> r100_cp_init

The chain of calls on resume for all except r600 is:
rXXX_resume -> rXXX_startup -> r100_cp_init.

R600 correctly allocates rptr_save_reg in r600_init (ie once only, not in resume). However moving the code into the init functions for all drivers means touching 4 drivers. So instead, this patch just adds a test in r100_cp_init to avoid reallocating on resume. As the rdev structure is allocated via kzalloc in radeon_driver_load_kms, and zero is not a valid registerid, zero safely implies not-yet-allocated.

This issue appears to have been introduced in c7eff978 (3.6.0-rcN)

---
 drivers/gpu/drm/radeon/r100.c |    3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/gpu/drm/radeon/r100.c +2 -1
index 8acb34f..2bc31f5 100644
@@ -1182,7 +1182,8 @@ int r100_cp_init(struct radeon_device *rdev, unsigned ring_size)
     ring->ready = true;
     radeon_ttm_set_active_vram_size(rdev, rdev->mc.real_vram_size);
 
-    if (radeon_ring_supports_scratch_reg(rdev, ring)) {
+    if (!ring->rptr_save_reg /* not resuming from suspend */
+        && radeon_ring_supports_scratch_reg(rdev, ring)) {
         r = radeon_scratch_get(rdev, &ring->rptr_save_reg);
         if (r) {
             DRM_ERROR("failed to get scratch reg for rptr save 

(%d).\n", r);

Signature · 1 line
1.7.9.5
#1 lore raw

Thanks! I've added this to my -fixes branch.

Alex

Quoted 59 lines · Simon Kitching

Cards typically have 5-7 scratch registers; one of these is reserved for rdev->rptr_save_reg. Unfortunately the reservation is done in function r100_cp_init, which is called by all drivers except r600 - and this function is also invoked on resume from suspend. After several resumes, no scratch registers are free and graphics acceleration is disabled.

Dmesg then reports either:
*ERROR* radeon: cp failed to get scratch reg (-22). *ERROR* radeon: cp isn't working(-22). radeon 0000:01:00.0: failed initializing CP (-22).
or:
*ERROR* radeon: failed to get scratch reg (-22). *ERROR* radeon: failed testing IB on GFX ring (-22). *ERROR* ib ring test failed (-22).

The chain of calls on boot for all except r600 is:
radeon_init -> ... -> (rXXX_init) -> rXXX_startup -> r100_cp_init

The chain of calls on resume for all except r600 is:
rXXX_resume -> rXXX_startup -> r100_cp_init.

R600 correctly allocates rptr_save_reg in r600_init (ie once only, not in resume). However moving the code into the init functions for all drivers means touching 4 drivers. So instead, this patch just adds a test in r100_cp_init to avoid reallocating on resume. As the rdev structure is allocated via kzalloc in radeon_driver_load_kms, and zero is not a valid registerid, zero safely implies not-yet-allocated.

This issue appears to have been introduced in c7eff978 (3.6.0-rcN)

---
 drivers/gpu/drm/radeon/r100.c |    3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/gpu/drm/radeon/r100.c +2 -1
index 8acb34f..2bc31f5 100644
@@ -1182,7 +1182,8 @@ int r100_cp_init(struct radeon_device *rdev, unsigned
 ring_size)
     ring->ready = true;
     radeon_ttm_set_active_vram_size(rdev, rdev->mc.real_vram_size);
 
-    if (radeon_ring_supports_scratch_reg(rdev, ring)) {
+    if (!ring->rptr_save_reg /* not resuming from suspend */
+        && radeon_ring_supports_scratch_reg(rdev, ring)) {
         r = radeon_scratch_get(rdev, &ring->rptr_save_reg);
         if (r) {

DRM_ERROR("failed to get scratch reg for rptr save (%d).\n",
r);
--
1.7.9.5

_______________________________________________
dri-devel mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/dri-devel