Flushing the fbdev's shadow buffer requires vmap'ing the BO memory, which
in turn requires pinning the BO. While being pinned, the BO cannot be moved
into VRAM for scanout. Consequently, a concurrent modeset operation that
involves the fbdev framebuffer would likely fail.

Resolve this problem be acquiring the modeset lock of the planes that use
the fbdev framebuffer. On non-atomic drivers, also acquire the mode-config
lock. This serializes the flushing of the framebuffer with concurrent
modeset operations.

Signed-off-by: Thomas Zimmermann <tzimmerm...@suse.de>
---
 drivers/gpu/drm/drm_fb_helper.c | 43 +++++++++++++++++++++++++++++++--
 1 file changed, 41 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index 5a22c744378c..af485c71a42a 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -394,20 +394,59 @@ static void drm_fb_helper_damage_blit_real(struct 
drm_fb_helper *fb_helper,
 static int drm_fb_helper_damage_blit(struct drm_fb_helper *fb_helper,
                                     struct drm_clip_rect *clip)
 {
+       struct drm_device *dev = fb_helper->dev;
+       struct drm_framebuffer *fb = fb_helper->fb;
        struct drm_client_buffer *buffer = fb_helper->buffer;
+       struct drm_modeset_acquire_ctx ctx;
+       struct drm_framebuffer *plane_fb;
+       struct drm_plane *plane;
        struct dma_buf_map map, dst;
        int ret;
 
+       if (!drm_drv_uses_atomic_modeset(dev))
+               mutex_lock(&dev->mode_config.mutex);
+
+       drm_modeset_acquire_init(&ctx, 0);
+
+retry:
+       drm_for_each_plane(plane, dev) {
+               ret = drm_modeset_lock(&plane->mutex, &ctx);
+               if (ret == -EDEADLK) {
+                       ret = drm_modeset_backoff(&ctx);
+                       if (!ret)
+                               goto retry;
+               } else if (ret) {
+                       goto out;
+               }
+
+               if (drm_drv_uses_atomic_modeset(dev))
+                       plane_fb = plane->state->fb;
+               else
+                       plane_fb = plane->fb;
+
+               if (plane_fb != fb) {
+                       drm_modeset_unlock(&plane->mutex);
+                       continue;
+               }
+       }
+
        ret = drm_client_buffer_vmap(buffer, &map);
        if (ret)
-               return ret;
+               goto out;
 
        dst = map;
        drm_fb_helper_damage_blit_real(fb_helper, clip, &dst);
 
        drm_client_buffer_vunmap(buffer);
 
-       return 0;
+out:
+       drm_modeset_drop_locks(&ctx);
+       drm_modeset_acquire_fini(&ctx);
+
+       if (!drm_drv_uses_atomic_modeset(dev))
+               mutex_unlock(&dev->mode_config.mutex);
+
+       return ret;
 }
 
 static void drm_fb_helper_damage_work(struct work_struct *work)
-- 
2.29.2

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

Reply via email to