|
@@ -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);
|