Skip to content

Commit 325cbba

Browse files
Michel Dänzeralexdeucher
authored andcommitted
drm/amdgpu: Provide page_flip_target hook
Now we can program a flip during a vertical blank period, if it's the one targeted by the flip (or a later one). This allows simplifying amdgpu_flip_work_func considerably. agd: update dce_virtual.c as well. Acked-by: Christian König <christian.koenig@amd.com> Signed-off-by: Michel Dänzer <michel.daenzer@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
1 parent c229bfb commit 325cbba

File tree

7 files changed

+39
-76
lines changed

7 files changed

+39
-76
lines changed

drivers/gpu/drm/amd/amdgpu/amdgpu.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -730,10 +730,11 @@ void amdgpu_doorbell_get_kfd_info(struct amdgpu_device *adev,
730730
*/
731731

732732
struct amdgpu_flip_work {
733-
struct work_struct flip_work;
733+
struct delayed_work flip_work;
734734
struct work_struct unpin_work;
735735
struct amdgpu_device *adev;
736736
int crtc_id;
737+
u32 target_vblank;
737738
uint64_t base;
738739
struct drm_pending_vblank_event *event;
739740
struct amdgpu_bo *old_rbo;

drivers/gpu/drm/amd/amdgpu/amdgpu_display.c

Lines changed: 29 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ static void amdgpu_flip_callback(struct fence *f, struct fence_cb *cb)
4141
container_of(cb, struct amdgpu_flip_work, cb);
4242

4343
fence_put(f);
44-
schedule_work(&work->flip_work);
44+
schedule_work(&work->flip_work.work);
4545
}
4646

4747
static bool amdgpu_flip_handle_fence(struct amdgpu_flip_work *work,
@@ -63,16 +63,17 @@ static bool amdgpu_flip_handle_fence(struct amdgpu_flip_work *work,
6363

6464
static void amdgpu_flip_work_func(struct work_struct *__work)
6565
{
66+
struct delayed_work *delayed_work =
67+
container_of(__work, struct delayed_work, work);
6668
struct amdgpu_flip_work *work =
67-
container_of(__work, struct amdgpu_flip_work, flip_work);
69+
container_of(delayed_work, struct amdgpu_flip_work, flip_work);
6870
struct amdgpu_device *adev = work->adev;
6971
struct amdgpu_crtc *amdgpuCrtc = adev->mode_info.crtcs[work->crtc_id];
7072

7173
struct drm_crtc *crtc = &amdgpuCrtc->base;
7274
unsigned long flags;
73-
unsigned i, repcnt = 4;
74-
int vpos, hpos, stat, min_udelay = 0;
75-
struct drm_vblank_crtc *vblank = &crtc->dev->vblank[work->crtc_id];
75+
unsigned i;
76+
int vpos, hpos;
7677

7778
if (amdgpu_flip_handle_fence(work, &work->excl))
7879
return;
@@ -81,55 +82,23 @@ static void amdgpu_flip_work_func(struct work_struct *__work)
8182
if (amdgpu_flip_handle_fence(work, &work->shared[i]))
8283
return;
8384

84-
/* We borrow the event spin lock for protecting flip_status */
85-
spin_lock_irqsave(&crtc->dev->event_lock, flags);
86-
87-
/* If this happens to execute within the "virtually extended" vblank
88-
* interval before the start of the real vblank interval then it needs
89-
* to delay programming the mmio flip until the real vblank is entered.
90-
* This prevents completing a flip too early due to the way we fudge
91-
* our vblank counter and vblank timestamps in order to work around the
92-
* problem that the hw fires vblank interrupts before actual start of
93-
* vblank (when line buffer refilling is done for a frame). It
94-
* complements the fudging logic in amdgpu_get_crtc_scanoutpos() for
95-
* timestamping and amdgpu_get_vblank_counter_kms() for vblank counts.
96-
*
97-
* In practice this won't execute very often unless on very fast
98-
* machines because the time window for this to happen is very small.
85+
/* Wait until we're out of the vertical blank period before the one
86+
* targeted by the flip
9987
*/
100-
while (amdgpuCrtc->enabled && --repcnt) {
101-
/* GET_DISTANCE_TO_VBLANKSTART returns distance to real vblank
102-
* start in hpos, and to the "fudged earlier" vblank start in
103-
* vpos.
104-
*/
105-
stat = amdgpu_get_crtc_scanoutpos(adev->ddev, work->crtc_id,
106-
GET_DISTANCE_TO_VBLANKSTART,
107-
&vpos, &hpos, NULL, NULL,
108-
&crtc->hwmode);
109-
110-
if ((stat & (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE)) !=
111-
(DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE) ||
112-
!(vpos >= 0 && hpos <= 0))
113-
break;
114-
115-
/* Sleep at least until estimated real start of hw vblank */
116-
min_udelay = (-hpos + 1) * max(vblank->linedur_ns / 1000, 5);
117-
if (min_udelay > vblank->framedur_ns / 2000) {
118-
/* Don't wait ridiculously long - something is wrong */
119-
repcnt = 0;
120-
break;
121-
}
122-
spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
123-
usleep_range(min_udelay, 2 * min_udelay);
124-
spin_lock_irqsave(&crtc->dev->event_lock, flags);
88+
if (amdgpuCrtc->enabled &&
89+
(amdgpu_get_crtc_scanoutpos(adev->ddev, work->crtc_id, 0,
90+
&vpos, &hpos, NULL, NULL,
91+
&crtc->hwmode)
92+
& (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_IN_VBLANK)) ==
93+
(DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_IN_VBLANK) &&
94+
(int)(work->target_vblank -
95+
amdgpu_get_vblank_counter_kms(adev->ddev, amdgpuCrtc->crtc_id)) > 0) {
96+
schedule_delayed_work(&work->flip_work, usecs_to_jiffies(1000));
97+
return;
12598
}
12699

127-
if (!repcnt)
128-
DRM_DEBUG_DRIVER("Delay problem on crtc %d: min_udelay %d, "
129-
"framedur %d, linedur %d, stat %d, vpos %d, "
130-
"hpos %d\n", work->crtc_id, min_udelay,
131-
vblank->framedur_ns / 1000,
132-
vblank->linedur_ns / 1000, stat, vpos, hpos);
100+
/* We borrow the event spin lock for protecting flip_status */
101+
spin_lock_irqsave(&crtc->dev->event_lock, flags);
133102

134103
/* Do the flip (mmio) */
135104
adev->mode_info.funcs->page_flip(adev, work->crtc_id, work->base, work->async);
@@ -169,10 +138,10 @@ static void amdgpu_unpin_work_func(struct work_struct *__work)
169138
kfree(work);
170139
}
171140

172-
int amdgpu_crtc_page_flip(struct drm_crtc *crtc,
173-
struct drm_framebuffer *fb,
174-
struct drm_pending_vblank_event *event,
175-
uint32_t page_flip_flags)
141+
int amdgpu_crtc_page_flip_target(struct drm_crtc *crtc,
142+
struct drm_framebuffer *fb,
143+
struct drm_pending_vblank_event *event,
144+
uint32_t page_flip_flags, uint32_t target)
176145
{
177146
struct drm_device *dev = crtc->dev;
178147
struct amdgpu_device *adev = dev->dev_private;
@@ -191,7 +160,7 @@ int amdgpu_crtc_page_flip(struct drm_crtc *crtc,
191160
if (work == NULL)
192161
return -ENOMEM;
193162

194-
INIT_WORK(&work->flip_work, amdgpu_flip_work_func);
163+
INIT_DELAYED_WORK(&work->flip_work, amdgpu_flip_work_func);
195164
INIT_WORK(&work->unpin_work, amdgpu_unpin_work_func);
196165

197166
work->event = event;
@@ -237,20 +206,16 @@ int amdgpu_crtc_page_flip(struct drm_crtc *crtc,
237206
amdgpu_bo_unreserve(new_rbo);
238207

239208
work->base = base;
240-
241-
r = drm_crtc_vblank_get(crtc);
242-
if (r) {
243-
DRM_ERROR("failed to get vblank before flip\n");
244-
goto pflip_cleanup;
245-
}
209+
work->target_vblank = target - drm_crtc_vblank_count(crtc) +
210+
amdgpu_get_vblank_counter_kms(dev, work->crtc_id);
246211

247212
/* we borrow the event spin lock for protecting flip_wrok */
248213
spin_lock_irqsave(&crtc->dev->event_lock, flags);
249214
if (amdgpu_crtc->pflip_status != AMDGPU_FLIP_NONE) {
250215
DRM_DEBUG_DRIVER("flip queue: crtc already busy\n");
251216
spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
252217
r = -EBUSY;
253-
goto vblank_cleanup;
218+
goto pflip_cleanup;
254219
}
255220

256221
amdgpu_crtc->pflip_status = AMDGPU_FLIP_PENDING;
@@ -262,12 +227,9 @@ int amdgpu_crtc_page_flip(struct drm_crtc *crtc,
262227
/* update crtc fb */
263228
crtc->primary->fb = fb;
264229
spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
265-
amdgpu_flip_work_func(&work->flip_work);
230+
amdgpu_flip_work_func(&work->flip_work.work);
266231
return 0;
267232

268-
vblank_cleanup:
269-
drm_crtc_vblank_put(crtc);
270-
271233
pflip_cleanup:
272234
if (unlikely(amdgpu_bo_reserve(new_rbo, false) != 0)) {
273235
DRM_ERROR("failed to reserve new rbo in error path\n");

drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -591,10 +591,10 @@ int amdgpu_align_pitch(struct amdgpu_device *adev, int width, int bpp, bool tile
591591
void amdgpu_print_display_setup(struct drm_device *dev);
592592
int amdgpu_modeset_create_props(struct amdgpu_device *adev);
593593
int amdgpu_crtc_set_config(struct drm_mode_set *set);
594-
int amdgpu_crtc_page_flip(struct drm_crtc *crtc,
595-
struct drm_framebuffer *fb,
596-
struct drm_pending_vblank_event *event,
597-
uint32_t page_flip_flags);
594+
int amdgpu_crtc_page_flip_target(struct drm_crtc *crtc,
595+
struct drm_framebuffer *fb,
596+
struct drm_pending_vblank_event *event,
597+
uint32_t page_flip_flags, uint32_t target);
598598
extern const struct drm_mode_config_funcs amdgpu_mode_funcs;
599599

600600
#endif

drivers/gpu/drm/amd/amdgpu/dce_v10_0.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2737,7 +2737,7 @@ static const struct drm_crtc_funcs dce_v10_0_crtc_funcs = {
27372737
.gamma_set = dce_v10_0_crtc_gamma_set,
27382738
.set_config = amdgpu_crtc_set_config,
27392739
.destroy = dce_v10_0_crtc_destroy,
2740-
.page_flip = amdgpu_crtc_page_flip,
2740+
.page_flip_target = amdgpu_crtc_page_flip_target,
27412741
};
27422742

27432743
static void dce_v10_0_crtc_dpms(struct drm_crtc *crtc, int mode)

drivers/gpu/drm/amd/amdgpu/dce_v11_0.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2755,7 +2755,7 @@ static const struct drm_crtc_funcs dce_v11_0_crtc_funcs = {
27552755
.gamma_set = dce_v11_0_crtc_gamma_set,
27562756
.set_config = amdgpu_crtc_set_config,
27572757
.destroy = dce_v11_0_crtc_destroy,
2758-
.page_flip = amdgpu_crtc_page_flip,
2758+
.page_flip_target = amdgpu_crtc_page_flip_target,
27592759
};
27602760

27612761
static void dce_v11_0_crtc_dpms(struct drm_crtc *crtc, int mode)

drivers/gpu/drm/amd/amdgpu/dce_v8_0.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2598,7 +2598,7 @@ static const struct drm_crtc_funcs dce_v8_0_crtc_funcs = {
25982598
.gamma_set = dce_v8_0_crtc_gamma_set,
25992599
.set_config = amdgpu_crtc_set_config,
26002600
.destroy = dce_v8_0_crtc_destroy,
2601-
.page_flip = amdgpu_crtc_page_flip,
2601+
.page_flip_target = amdgpu_crtc_page_flip_target,
26022602
};
26032603

26042604
static void dce_v8_0_crtc_dpms(struct drm_crtc *crtc, int mode)

drivers/gpu/drm/amd/amdgpu/dce_virtual.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ static const struct drm_crtc_funcs dce_virtual_crtc_funcs = {
188188
.gamma_set = dce_virtual_crtc_gamma_set,
189189
.set_config = amdgpu_crtc_set_config,
190190
.destroy = dce_virtual_crtc_destroy,
191-
.page_flip = amdgpu_crtc_page_flip,
191+
.page_flip_target = amdgpu_crtc_page_flip_target,
192192
};
193193

194194
static void dce_virtual_crtc_dpms(struct drm_crtc *crtc, int mode)

0 commit comments

Comments
 (0)