@@ -73,6 +73,8 @@ static void amdgpu_flip_work_func(struct work_struct *__work)
73
73
struct drm_crtc * crtc = & amdgpuCrtc -> base ;
74
74
unsigned long flags ;
75
75
unsigned i ;
76
+ int vpos , hpos , stat , min_udelay ;
77
+ struct drm_vblank_crtc * vblank = & crtc -> dev -> vblank [work -> crtc_id ];
76
78
77
79
amdgpu_flip_wait_fence (adev , & work -> excl );
78
80
for (i = 0 ; i < work -> shared_count ; ++ i )
@@ -81,6 +83,41 @@ static void amdgpu_flip_work_func(struct work_struct *__work)
81
83
/* We borrow the event spin lock for protecting flip_status */
82
84
spin_lock_irqsave (& crtc -> dev -> event_lock , flags );
83
85
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
+
84
121
/* do the flip (mmio) */
85
122
adev -> mode_info .funcs -> page_flip (adev , work -> crtc_id , work -> base );
86
123
/* set the flip status */
@@ -109,7 +146,7 @@ static void amdgpu_unpin_work_func(struct work_struct *__work)
109
146
} else
110
147
DRM_ERROR ("failed to reserve buffer after flip\n" );
111
148
112
- drm_gem_object_unreference_unlocked (& work -> old_rbo -> gem_base );
149
+ amdgpu_bo_unref (& work -> old_rbo );
113
150
kfree (work -> shared );
114
151
kfree (work );
115
152
}
@@ -148,8 +185,8 @@ int amdgpu_crtc_page_flip(struct drm_crtc *crtc,
148
185
obj = old_amdgpu_fb -> obj ;
149
186
150
187
/* take a reference to the old object */
151
- drm_gem_object_reference (obj );
152
188
work -> old_rbo = gem_to_amdgpu_bo (obj );
189
+ amdgpu_bo_ref (work -> old_rbo );
153
190
154
191
new_amdgpu_fb = to_amdgpu_framebuffer (fb );
155
192
obj = new_amdgpu_fb -> obj ;
@@ -222,7 +259,7 @@ int amdgpu_crtc_page_flip(struct drm_crtc *crtc,
222
259
amdgpu_bo_unreserve (new_rbo );
223
260
224
261
cleanup :
225
- drm_gem_object_unreference_unlocked (& work -> old_rbo -> gem_base );
262
+ amdgpu_bo_unref (& work -> old_rbo );
226
263
fence_put (work -> excl );
227
264
for (i = 0 ; i < work -> shared_count ; ++ i )
228
265
fence_put (work -> shared [i ]);
@@ -712,6 +749,15 @@ bool amdgpu_crtc_scaling_mode_fixup(struct drm_crtc *crtc,
712
749
* \param dev Device to query.
713
750
* \param pipe Crtc to query.
714
751
* \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
+ *
715
761
* \param *vpos Location where vertical scanout position should be stored.
716
762
* \param *hpos Location where horizontal scanout position should go.
717
763
* \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,
776
822
vbl_end = 0 ;
777
823
}
778
824
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
+
779
844
/* Test scanout position against vblank region. */
780
845
if ((* vpos < vbl_start ) && (* vpos >= vbl_end ))
781
846
in_vbl = false;
782
847
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
+
783
859
/* Check if inside vblank area and apply corrective offsets:
784
860
* vpos will then be >=0 in video scanout area, but negative
785
861
* 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,
795
871
/* Correct for shifted end of vbl at vbl_end. */
796
872
* vpos = * vpos - vbl_end ;
797
873
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
-
824
874
return ret ;
825
875
}
826
876
0 commit comments