diff options
-rw-r--r-- | drivers/gpu/drm/vc4/vc4_crtc.c | 46 |
1 files changed, 45 insertions, 1 deletions
diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c index bf4667481935..c61dff594195 100644 --- a/drivers/gpu/drm/vc4/vc4_crtc.c +++ b/drivers/gpu/drm/vc4/vc4_crtc.c | |||
@@ -760,6 +760,7 @@ static irqreturn_t vc4_crtc_irq_handler(int irq, void *data) | |||
760 | struct vc4_async_flip_state { | 760 | struct vc4_async_flip_state { |
761 | struct drm_crtc *crtc; | 761 | struct drm_crtc *crtc; |
762 | struct drm_framebuffer *fb; | 762 | struct drm_framebuffer *fb; |
763 | struct drm_framebuffer *old_fb; | ||
763 | struct drm_pending_vblank_event *event; | 764 | struct drm_pending_vblank_event *event; |
764 | 765 | ||
765 | struct vc4_seqno_cb cb; | 766 | struct vc4_seqno_cb cb; |
@@ -789,6 +790,23 @@ vc4_async_page_flip_complete(struct vc4_seqno_cb *cb) | |||
789 | 790 | ||
790 | drm_crtc_vblank_put(crtc); | 791 | drm_crtc_vblank_put(crtc); |
791 | drm_framebuffer_put(flip_state->fb); | 792 | drm_framebuffer_put(flip_state->fb); |
793 | |||
794 | /* Decrement the BO usecnt in order to keep the inc/dec calls balanced | ||
795 | * when the planes are updated through the async update path. | ||
796 | * FIXME: we should move to generic async-page-flip when it's | ||
797 | * available, so that we can get rid of this hand-made cleanup_fb() | ||
798 | * logic. | ||
799 | */ | ||
800 | if (flip_state->old_fb) { | ||
801 | struct drm_gem_cma_object *cma_bo; | ||
802 | struct vc4_bo *bo; | ||
803 | |||
804 | cma_bo = drm_fb_cma_get_gem_obj(flip_state->old_fb, 0); | ||
805 | bo = to_vc4_bo(&cma_bo->base); | ||
806 | vc4_bo_dec_usecnt(bo); | ||
807 | drm_framebuffer_put(flip_state->old_fb); | ||
808 | } | ||
809 | |||
792 | kfree(flip_state); | 810 | kfree(flip_state); |
793 | 811 | ||
794 | up(&vc4->async_modeset); | 812 | up(&vc4->async_modeset); |
@@ -813,9 +831,22 @@ static int vc4_async_page_flip(struct drm_crtc *crtc, | |||
813 | struct drm_gem_cma_object *cma_bo = drm_fb_cma_get_gem_obj(fb, 0); | 831 | struct drm_gem_cma_object *cma_bo = drm_fb_cma_get_gem_obj(fb, 0); |
814 | struct vc4_bo *bo = to_vc4_bo(&cma_bo->base); | 832 | struct vc4_bo *bo = to_vc4_bo(&cma_bo->base); |
815 | 833 | ||
834 | /* Increment the BO usecnt here, so that we never end up with an | ||
835 | * unbalanced number of vc4_bo_{dec,inc}_usecnt() calls when the | ||
836 | * plane is later updated through the non-async path. | ||
837 | * FIXME: we should move to generic async-page-flip when it's | ||
838 | * available, so that we can get rid of this hand-made prepare_fb() | ||
839 | * logic. | ||
840 | */ | ||
841 | ret = vc4_bo_inc_usecnt(bo); | ||
842 | if (ret) | ||
843 | return ret; | ||
844 | |||
816 | flip_state = kzalloc(sizeof(*flip_state), GFP_KERNEL); | 845 | flip_state = kzalloc(sizeof(*flip_state), GFP_KERNEL); |
817 | if (!flip_state) | 846 | if (!flip_state) { |
847 | vc4_bo_dec_usecnt(bo); | ||
818 | return -ENOMEM; | 848 | return -ENOMEM; |
849 | } | ||
819 | 850 | ||
820 | drm_framebuffer_get(fb); | 851 | drm_framebuffer_get(fb); |
821 | flip_state->fb = fb; | 852 | flip_state->fb = fb; |
@@ -826,10 +857,23 @@ static int vc4_async_page_flip(struct drm_crtc *crtc, | |||
826 | ret = down_interruptible(&vc4->async_modeset); | 857 | ret = down_interruptible(&vc4->async_modeset); |
827 | if (ret) { | 858 | if (ret) { |
828 | drm_framebuffer_put(fb); | 859 | drm_framebuffer_put(fb); |
860 | vc4_bo_dec_usecnt(bo); | ||
829 | kfree(flip_state); | 861 | kfree(flip_state); |
830 | return ret; | 862 | return ret; |
831 | } | 863 | } |
832 | 864 | ||
865 | /* Save the current FB before it's replaced by the new one in | ||
866 | * drm_atomic_set_fb_for_plane(). We'll need the old FB in | ||
867 | * vc4_async_page_flip_complete() to decrement the BO usecnt and keep | ||
868 | * it consistent. | ||
869 | * FIXME: we should move to generic async-page-flip when it's | ||
870 | * available, so that we can get rid of this hand-made cleanup_fb() | ||
871 | * logic. | ||
872 | */ | ||
873 | flip_state->old_fb = plane->state->fb; | ||
874 | if (flip_state->old_fb) | ||
875 | drm_framebuffer_get(flip_state->old_fb); | ||
876 | |||
833 | WARN_ON(drm_crtc_vblank_get(crtc) != 0); | 877 | WARN_ON(drm_crtc_vblank_get(crtc) != 0); |
834 | 878 | ||
835 | /* Immediately update the plane's legacy fb pointer, so that later | 879 | /* Immediately update the plane's legacy fb pointer, so that later |