aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Vetter <daniel.vetter@ffwll.ch>2016-10-03 04:28:27 -0400
committerDave Airlie <airlied@redhat.com>2016-10-03 22:53:12 -0400
commit2adb29b18ea7dc9503a397eb9995a5f3e6754b9e (patch)
treec6d5dbe6d2ee16a79df30dc0a2627a057810ca4f
parente86fa21b77f4ef840213ecd33230c7c16879a4ac (diff)
drm: Undo damage to page_flip_ioctl
I screwed up rebasing of my patch in commit 43968d7b806d7a7e021261294c583a216fddf0e5 Author: Daniel Vetter <daniel.vetter@ffwll.ch> Date: Wed Sep 21 10:59:24 2016 +0200 drm: Extract drm_plane.[hc] which meant on error paths drm_crtc_vblank_put could be called without a get, leading to an underrun of the refcount. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=98020 Reported-and-tested-by: Andy Furniss <adf.lists@gmail.com> Cc: Sean Paul <seanpaul@chromium.org> Cc: Michel Dänzer <michel@daenzer.net> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch> Link: http://patchwork.freedesktop.org/patch/msgid/20161003082827.11586-1-daniel.vetter@ffwll.ch Signed-off-by: Dave Airlie <airlied@redhat.com>
-rw-r--r--drivers/gpu/drm/drm_plane.c81
1 files changed, 39 insertions, 42 deletions
diff --git a/drivers/gpu/drm/drm_plane.c b/drivers/gpu/drm/drm_plane.c
index 783aef8acab7..249c0ae52c6d 100644
--- a/drivers/gpu/drm/drm_plane.c
+++ b/drivers/gpu/drm/drm_plane.c
@@ -783,6 +783,45 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
783 if (!crtc) 783 if (!crtc)
784 return -ENOENT; 784 return -ENOENT;
785 785
786 if (crtc->funcs->page_flip_target) {
787 u32 current_vblank;
788 int r;
789
790 r = drm_crtc_vblank_get(crtc);
791 if (r)
792 return r;
793
794 current_vblank = drm_crtc_vblank_count(crtc);
795
796 switch (page_flip->flags & DRM_MODE_PAGE_FLIP_TARGET) {
797 case DRM_MODE_PAGE_FLIP_TARGET_ABSOLUTE:
798 if ((int)(target_vblank - current_vblank) > 1) {
799 DRM_DEBUG("Invalid absolute flip target %u, "
800 "must be <= %u\n", target_vblank,
801 current_vblank + 1);
802 drm_crtc_vblank_put(crtc);
803 return -EINVAL;
804 }
805 break;
806 case DRM_MODE_PAGE_FLIP_TARGET_RELATIVE:
807 if (target_vblank != 0 && target_vblank != 1) {
808 DRM_DEBUG("Invalid relative flip target %u, "
809 "must be 0 or 1\n", target_vblank);
810 drm_crtc_vblank_put(crtc);
811 return -EINVAL;
812 }
813 target_vblank += current_vblank;
814 break;
815 default:
816 target_vblank = current_vblank +
817 !(page_flip->flags & DRM_MODE_PAGE_FLIP_ASYNC);
818 break;
819 }
820 } else if (crtc->funcs->page_flip == NULL ||
821 (page_flip->flags & DRM_MODE_PAGE_FLIP_TARGET)) {
822 return -EINVAL;
823 }
824
786 drm_modeset_lock_crtc(crtc, crtc->primary); 825 drm_modeset_lock_crtc(crtc, crtc->primary);
787 if (crtc->primary->fb == NULL) { 826 if (crtc->primary->fb == NULL) {
788 /* The framebuffer is currently unbound, presumably 827 /* The framebuffer is currently unbound, presumably
@@ -793,9 +832,6 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
793 goto out; 832 goto out;
794 } 833 }
795 834
796 if (crtc->funcs->page_flip == NULL)
797 goto out;
798
799 fb = drm_framebuffer_lookup(dev, page_flip->fb_id); 835 fb = drm_framebuffer_lookup(dev, page_flip->fb_id);
800 if (!fb) { 836 if (!fb) {
801 ret = -ENOENT; 837 ret = -ENOENT;
@@ -839,45 +875,6 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
839 } 875 }
840 876
841 crtc->primary->old_fb = crtc->primary->fb; 877 crtc->primary->old_fb = crtc->primary->fb;
842 if (crtc->funcs->page_flip_target) {
843 u32 current_vblank;
844 int r;
845
846 r = drm_crtc_vblank_get(crtc);
847 if (r)
848 return r;
849
850 current_vblank = drm_crtc_vblank_count(crtc);
851
852 switch (page_flip->flags & DRM_MODE_PAGE_FLIP_TARGET) {
853 case DRM_MODE_PAGE_FLIP_TARGET_ABSOLUTE:
854 if ((int)(target_vblank - current_vblank) > 1) {
855 DRM_DEBUG("Invalid absolute flip target %u, "
856 "must be <= %u\n", target_vblank,
857 current_vblank + 1);
858 drm_crtc_vblank_put(crtc);
859 return -EINVAL;
860 }
861 break;
862 case DRM_MODE_PAGE_FLIP_TARGET_RELATIVE:
863 if (target_vblank != 0 && target_vblank != 1) {
864 DRM_DEBUG("Invalid relative flip target %u, "
865 "must be 0 or 1\n", target_vblank);
866 drm_crtc_vblank_put(crtc);
867 return -EINVAL;
868 }
869 target_vblank += current_vblank;
870 break;
871 default:
872 target_vblank = current_vblank +
873 !(page_flip->flags & DRM_MODE_PAGE_FLIP_ASYNC);
874 break;
875 }
876 } else if (crtc->funcs->page_flip == NULL ||
877 (page_flip->flags & DRM_MODE_PAGE_FLIP_TARGET)) {
878 return -EINVAL;
879 }
880
881 if (crtc->funcs->page_flip_target) 878 if (crtc->funcs->page_flip_target)
882 ret = crtc->funcs->page_flip_target(crtc, fb, e, 879 ret = crtc->funcs->page_flip_target(crtc, fb, e,
883 page_flip->flags, 880 page_flip->flags,