VIGS: Fix pageflip race
authorStanislav Vorobiov <s.vorobiov@samsung.com>
Tue, 10 Dec 2013 16:52:54 +0000 (20:52 +0400)
committerSeokYeon Hwang <syeon.hwang@samsung.com>
Wed, 9 Apr 2014 05:42:27 +0000 (14:42 +0900)
Must use event_lock, since it's being used
in vigs_finish_pageflips to lock pageflip_event_list.

Also, by the time we call drm_vblank_put the event might already
be processed, so check for that

Change-Id: I9c5de98452353c6d4f09e4e4fbd92176cfd8ee40

drivers/gpu/drm/vigs/vigs_crtc.c
drivers/gpu/drm/vigs/vigs_framebuffer.c

index 9c414e9..9989ae6 100644 (file)
@@ -197,6 +197,7 @@ static int vigs_crtc_page_flip(struct drm_crtc *crtc,
                                struct drm_framebuffer *fb,
                                struct drm_pending_vblank_event *event)
 {
+    unsigned long flags;
     struct vigs_device *vigs_dev = crtc->dev->dev_private;
     struct drm_framebuffer *old_fb = crtc->fb;
     int ret = -EINVAL;
@@ -210,19 +211,27 @@ static int vigs_crtc_page_flip(struct drm_crtc *crtc,
 
         if (ret != 0) {
             DRM_ERROR("failed to acquire vblank counter\n");
-            list_del(&event->base.link);
             goto out;
         }
 
+        spin_lock_irqsave(&vigs_dev->drm_dev->event_lock, flags);
         list_add_tail(&event->base.link,
                       &vigs_dev->pageflip_event_list);
+        spin_unlock_irqrestore(&vigs_dev->drm_dev->event_lock, flags);
 
         crtc->fb = fb;
         ret = vigs_crtc_update(crtc, old_fb);
         if (ret != 0) {
             crtc->fb = old_fb;
-            drm_vblank_put(vigs_dev->drm_dev, 0);
-            list_del(&event->base.link);
+            spin_lock_irqsave(&vigs_dev->drm_dev->event_lock, flags);
+            if (atomic_read(&vigs_dev->drm_dev->vblank_refcount[0]) > 0) {
+                /*
+                 * Only do this if event wasn't already processed.
+                 */
+                drm_vblank_put(vigs_dev->drm_dev, 0);
+                list_del(&event->base.link);
+            }
+            spin_unlock_irqrestore(&vigs_dev->drm_dev->event_lock, flags);
             goto out;
         }
     }
index d0a1f50..712f23d 100644 (file)
@@ -191,14 +191,9 @@ int vigs_framebuffer_pin(struct vigs_framebuffer *vigs_fb)
 
     ret = vigs_gem_pin(&vigs_fb->fb_sfc->gem);
 
-    if (ret != 0) {
-        vigs_gem_unreserve(&vigs_fb->fb_sfc->gem);
-        return ret;
-    }
-
     vigs_gem_unreserve(&vigs_fb->fb_sfc->gem);
 
-    return 0;
+    return ret;
 }
 
 void vigs_framebuffer_unpin(struct vigs_framebuffer *vigs_fb)