radeon: workaround pinning failure on low ram gpu
authorJerome Glisse <jglisse@redhat.com>
Tue, 12 Nov 2013 15:51:16 +0000 (10:51 -0500)
committerAlex Deucher <alexander.deucher@amd.com>
Fri, 15 Nov 2013 20:29:33 +0000 (15:29 -0500)
GPU with low amount of ram can fails at pinning new framebuffer before
unpinning old one. On such failure, retry with unpinning old one before
pinning new one allowing to work around the issue. This is somewhat
ugly but only affect those old GPU we care about.

Signed-off-by: Jerome Glisse <jglisse@redhat.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Cc: stable@vger.kernel.org
drivers/gpu/drm/radeon/radeon_legacy_crtc.c

index 0c7b8c66301bdd0c1020bd8d5009610e5f817795..0b158f98d287136df1a4c3db11724798d2973d9f 100644 (file)
@@ -422,6 +422,7 @@ int radeon_crtc_do_set_base(struct drm_crtc *crtc,
        /* Pin framebuffer & get tilling informations */
        obj = radeon_fb->obj;
        rbo = gem_to_radeon_bo(obj);
+retry:
        r = radeon_bo_reserve(rbo, false);
        if (unlikely(r != 0))
                return r;
@@ -430,6 +431,33 @@ int radeon_crtc_do_set_base(struct drm_crtc *crtc,
                                     &base);
        if (unlikely(r != 0)) {
                radeon_bo_unreserve(rbo);
+
+               /* On old GPU like RN50 with little vram pining can fails because
+                * current fb is taking all space needed. So instead of unpining
+                * the old buffer after pining the new one, first unpin old one
+                * and then retry pining new one.
+                *
+                * As only master can set mode only master can pin and it is
+                * unlikely the master client will race with itself especialy
+                * on those old gpu with single crtc.
+                *
+                * We don't shutdown the display controller because new buffer
+                * will end up in same spot.
+                */
+               if (!atomic && fb && fb != crtc->fb) {
+                       struct radeon_bo *old_rbo;
+                       unsigned long nsize, osize;
+
+                       old_rbo = gem_to_radeon_bo(to_radeon_framebuffer(fb)->obj);
+                       osize = radeon_bo_size(old_rbo);
+                       nsize = radeon_bo_size(rbo);
+                       if (nsize <= osize && !radeon_bo_reserve(old_rbo, false)) {
+                               radeon_bo_unpin(old_rbo);
+                               radeon_bo_unreserve(old_rbo);
+                               fb = NULL;
+                               goto retry;
+                       }
+               }
                return -EINVAL;
        }
        radeon_bo_get_tiling_flags(rbo, &tiling_flags, NULL);
This page took 0.02751 seconds and 5 git commands to generate.