@@ -73,6 +73,8 @@ static void amdgpu_flip_work_func(struct work_struct *__work)
7373 struct drm_crtc * crtc = & amdgpuCrtc -> base ;
7474 unsigned long flags ;
7575 unsigned i ;
76+ int vpos , hpos , stat , min_udelay ;
77+ struct drm_vblank_crtc * vblank = & crtc -> dev -> vblank [work -> crtc_id ];
7678
7779 amdgpu_flip_wait_fence (adev , & work -> excl );
7880 for (i = 0 ; i < work -> shared_count ; ++ i )
@@ -81,6 +83,41 @@ static void amdgpu_flip_work_func(struct work_struct *__work)
8183 /* We borrow the event spin lock for protecting flip_status */
8284 spin_lock_irqsave (& crtc -> dev -> event_lock , flags );
8385
86+ /* If this happens to execute within the "virtually extended" vblank
87+ * interval before the start of the real vblank interval then it needs
88+ * to delay programming the mmio flip until the real vblank is entered.
89+ * This prevents completing a flip too early due to the way we fudge
90+ * our vblank counter and vblank timestamps in order to work around the
91+ * problem that the hw fires vblank interrupts before actual start of
92+ * vblank (when line buffer refilling is done for a frame). It
93+ * complements the fudging logic in amdgpu_get_crtc_scanoutpos() for
94+ * timestamping and amdgpu_get_vblank_counter_kms() for vblank counts.
95+ *
96+ * In practice this won't execute very often unless on very fast
97+ * machines because the time window for this to happen is very small.
98+ */
99+ for (;;) {
100+ /* GET_DISTANCE_TO_VBLANKSTART returns distance to real vblank
101+ * start in hpos, and to the "fudged earlier" vblank start in
102+ * vpos.
103+ */
104+ stat = amdgpu_get_crtc_scanoutpos (adev -> ddev , work -> crtc_id ,
105+ GET_DISTANCE_TO_VBLANKSTART ,
106+ & vpos , & hpos , NULL , NULL ,
107+ & crtc -> hwmode );
108+
109+ if ((stat & (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE )) !=
110+ (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE ) ||
111+ !(vpos >= 0 && hpos <= 0 ))
112+ break ;
113+
114+ /* Sleep at least until estimated real start of hw vblank */
115+ spin_unlock_irqrestore (& crtc -> dev -> event_lock , flags );
116+ min_udelay = (- hpos + 1 ) * max (vblank -> linedur_ns / 1000 , 5 );
117+ usleep_range (min_udelay , 2 * min_udelay );
118+ spin_lock_irqsave (& crtc -> dev -> event_lock , flags );
119+ };
120+
84121 /* do the flip (mmio) */
85122 adev -> mode_info .funcs -> page_flip (adev , work -> crtc_id , work -> base );
86123 /* set the flip status */
@@ -109,7 +146,7 @@ static void amdgpu_unpin_work_func(struct work_struct *__work)
109146 } else
110147 DRM_ERROR ("failed to reserve buffer after flip\n" );
111148
112- drm_gem_object_unreference_unlocked (& work -> old_rbo -> gem_base );
149+ amdgpu_bo_unref (& work -> old_rbo );
113150 kfree (work -> shared );
114151 kfree (work );
115152}
@@ -148,8 +185,8 @@ int amdgpu_crtc_page_flip(struct drm_crtc *crtc,
148185 obj = old_amdgpu_fb -> obj ;
149186
150187 /* take a reference to the old object */
151- drm_gem_object_reference (obj );
152188 work -> old_rbo = gem_to_amdgpu_bo (obj );
189+ amdgpu_bo_ref (work -> old_rbo );
153190
154191 new_amdgpu_fb = to_amdgpu_framebuffer (fb );
155192 obj = new_amdgpu_fb -> obj ;
@@ -222,7 +259,7 @@ int amdgpu_crtc_page_flip(struct drm_crtc *crtc,
222259 amdgpu_bo_unreserve (new_rbo );
223260
224261cleanup :
225- drm_gem_object_unreference_unlocked (& work -> old_rbo -> gem_base );
262+ amdgpu_bo_unref (& work -> old_rbo );
226263 fence_put (work -> excl );
227264 for (i = 0 ; i < work -> shared_count ; ++ i )
228265 fence_put (work -> shared [i ]);
@@ -712,6 +749,15 @@ bool amdgpu_crtc_scaling_mode_fixup(struct drm_crtc *crtc,
712749 * \param dev Device to query.
713750 * \param pipe Crtc to query.
714751 * \param flags Flags from caller (DRM_CALLED_FROM_VBLIRQ or 0).
752+ * For driver internal use only also supports these flags:
753+ *
754+ * USE_REAL_VBLANKSTART to use the real start of vblank instead
755+ * of a fudged earlier start of vblank.
756+ *
757+ * GET_DISTANCE_TO_VBLANKSTART to return distance to the
758+ * fudged earlier start of vblank in *vpos and the distance
759+ * to true start of vblank in *hpos.
760+ *
715761 * \param *vpos Location where vertical scanout position should be stored.
716762 * \param *hpos Location where horizontal scanout position should go.
717763 * \param *stime Target location for timestamp taken immediately before
@@ -776,10 +822,40 @@ int amdgpu_get_crtc_scanoutpos(struct drm_device *dev, unsigned int pipe,
776822 vbl_end = 0 ;
777823 }
778824
825+ /* Called from driver internal vblank counter query code? */
826+ if (flags & GET_DISTANCE_TO_VBLANKSTART ) {
827+ /* Caller wants distance from real vbl_start in *hpos */
828+ * hpos = * vpos - vbl_start ;
829+ }
830+
831+ /* Fudge vblank to start a few scanlines earlier to handle the
832+ * problem that vblank irqs fire a few scanlines before start
833+ * of vblank. Some driver internal callers need the true vblank
834+ * start to be used and signal this via the USE_REAL_VBLANKSTART flag.
835+ *
836+ * The cause of the "early" vblank irq is that the irq is triggered
837+ * by the line buffer logic when the line buffer read position enters
838+ * the vblank, whereas our crtc scanout position naturally lags the
839+ * line buffer read position.
840+ */
841+ if (!(flags & USE_REAL_VBLANKSTART ))
842+ vbl_start -= adev -> mode_info .crtcs [pipe ]-> lb_vblank_lead_lines ;
843+
779844 /* Test scanout position against vblank region. */
780845 if ((* vpos < vbl_start ) && (* vpos >= vbl_end ))
781846 in_vbl = false;
782847
848+ /* In vblank? */
849+ if (in_vbl )
850+ ret |= DRM_SCANOUTPOS_IN_VBLANK ;
851+
852+ /* Called from driver internal vblank counter query code? */
853+ if (flags & GET_DISTANCE_TO_VBLANKSTART ) {
854+ /* Caller wants distance from fudged earlier vbl_start */
855+ * vpos -= vbl_start ;
856+ return ret ;
857+ }
858+
783859 /* Check if inside vblank area and apply corrective offsets:
784860 * vpos will then be >=0 in video scanout area, but negative
785861 * within vblank area, counting down the number of lines until
@@ -795,32 +871,6 @@ int amdgpu_get_crtc_scanoutpos(struct drm_device *dev, unsigned int pipe,
795871 /* Correct for shifted end of vbl at vbl_end. */
796872 * vpos = * vpos - vbl_end ;
797873
798- /* In vblank? */
799- if (in_vbl )
800- ret |= DRM_SCANOUTPOS_IN_VBLANK ;
801-
802- /* Is vpos outside nominal vblank area, but less than
803- * 1/100 of a frame height away from start of vblank?
804- * If so, assume this isn't a massively delayed vblank
805- * interrupt, but a vblank interrupt that fired a few
806- * microseconds before true start of vblank. Compensate
807- * by adding a full frame duration to the final timestamp.
808- * Happens, e.g., on ATI R500, R600.
809- *
810- * We only do this if DRM_CALLED_FROM_VBLIRQ.
811- */
812- if ((flags & DRM_CALLED_FROM_VBLIRQ ) && !in_vbl ) {
813- vbl_start = mode -> crtc_vdisplay ;
814- vtotal = mode -> crtc_vtotal ;
815-
816- if (vbl_start - * vpos < vtotal / 100 ) {
817- * vpos -= vtotal ;
818-
819- /* Signal this correction as "applied". */
820- ret |= 0x8 ;
821- }
822- }
823-
824874 return ret ;
825875}
826876
0 commit comments