diff mbox

Prevent leak of scratch register on resume from suspend.

Message ID 505AE3E5.10100@vonos.net (mailing list archive)
State New, archived
Headers show

Commit Message

Simon Kitching Sept. 20, 2012, 9:37 a.m. UTC
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)

Signed-off-by: Simon Kitching <skitching@vonos.net>
---
  drivers/gpu/drm/radeon/r100.c |    3 ++-
  1 file changed, 2 insertions(+), 1 deletion(-)

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

Comments

Alex Deucher Sept. 20, 2012, 5:03 p.m. UTC | #1
Thanks!  I've added this to my -fixes branch.

Alex

On Thu, Sep 20, 2012 at 5:37 AM, Simon Kitching <skitching@vonos.net> wrote:
> 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)
>
> Signed-off-by: Simon Kitching <skitching@vonos.net>
> ---
>  drivers/gpu/drm/radeon/r100.c |    3 ++-
>  1 file changed, 2 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c
> index 8acb34f..2bc31f5 100644
> --- a/drivers/gpu/drm/radeon/r100.c
> +++ b/drivers/gpu/drm/radeon/r100.c
> @@ -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
> dri-devel@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel
diff mbox

Patch

diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c
index 8acb34f..2bc31f5 100644
--- a/drivers/gpu/drm/radeon/r100.c
+++ b/drivers/gpu/drm/radeon/r100.c
@@ -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) {