aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMario Kleiner <mario.kleiner.de@gmail.com>2016-09-17 08:25:39 -0400
committerAlex Deucher <alexander.deucher@amd.com>2016-10-04 11:15:58 -0400
commit363926dc9ef65a3813fa778e85f85dd756c8652f (patch)
treea4fe5829125a874cb1d8c5ce8d49ce53e5231888
parent73d4c23f5361928b12e7827e872612273cc1175a (diff)
drm/radeon: Prevent races on pre DCE4 between flip submission and completion.
Pre DCE4 hw doesn't have reliable pageflip completion interrupts, so instead polling for flip completion is used from within the vblank irq handler to complete page flips. This causes a race if pageflip ioctl is called close to vblank: 1. pageflip ioctl queues execution of radeon_flip_work_func. 2. vblank irq fires, radeon_crtc_handle_vblank checks for flip_status == FLIP_SUBMITTED finds none, no-ops. 3. radeon_flip_work_func runs inside vblank, decides to set flip_status == FLIP_SUBMITTED and programs the flip into hw. 4. hw executes flip immediately (because in vblank), but as 2 already happened, the flip completion routine only emits the flip completion event one refresh later -> wrong vblank count/timestamp for completion and no performance gain, as instead of delaying the flip until next vblank, we now delay the next flip by 1 refresh while waiting for the delayed flip completion event. Given we often don't gain anything due to this race, but lose precision, prevent the programmed flip from executing in vblank on pre DCE4 asics to avoid this race. On pre-AVIVO hw we can't program the hw for edge-triggered flips, they always execute anywhere in vblank. Therefore delay the actual flip programming until after vblank on pre-AVIVO. Reviewed-by: Michel Dänzer <michel.daenzer@amd.com> Signed-off-by: Mario Kleiner <mario.kleiner.de@gmail.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
-rw-r--r--drivers/gpu/drm/radeon/atombios_crtc.c4
-rw-r--r--drivers/gpu/drm/radeon/radeon_display.c17
-rw-r--r--drivers/gpu/drm/radeon/rv515.c3
3 files changed, 14 insertions, 10 deletions
diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c
index a4e9f35da3a2..74f99bac08b1 100644
--- a/drivers/gpu/drm/radeon/atombios_crtc.c
+++ b/drivers/gpu/drm/radeon/atombios_crtc.c
@@ -1638,8 +1638,8 @@ static int avivo_crtc_do_set_base(struct drm_crtc *crtc,
1638 WREG32(AVIVO_D1MODE_VIEWPORT_SIZE + radeon_crtc->crtc_offset, 1638 WREG32(AVIVO_D1MODE_VIEWPORT_SIZE + radeon_crtc->crtc_offset,
1639 (viewport_w << 16) | viewport_h); 1639 (viewport_w << 16) | viewport_h);
1640 1640
1641 /* set pageflip to happen anywhere in vblank interval */ 1641 /* set pageflip to happen only at start of vblank interval (front porch) */
1642 WREG32(AVIVO_D1MODE_MASTER_UPDATE_MODE + radeon_crtc->crtc_offset, 0); 1642 WREG32(AVIVO_D1MODE_MASTER_UPDATE_MODE + radeon_crtc->crtc_offset, 3);
1643 1643
1644 if (!atomic && fb && fb != crtc->primary->fb) { 1644 if (!atomic && fb && fb != crtc->primary->fb) {
1645 radeon_fb = to_radeon_framebuffer(fb); 1645 radeon_fb = to_radeon_framebuffer(fb);
diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c
index 50706464d456..b8ab30a7dd6d 100644
--- a/drivers/gpu/drm/radeon/radeon_display.c
+++ b/drivers/gpu/drm/radeon/radeon_display.c
@@ -452,16 +452,19 @@ static void radeon_flip_work_func(struct work_struct *__work)
452 } 452 }
453 453
454 /* Wait until we're out of the vertical blank period before the one 454 /* Wait until we're out of the vertical blank period before the one
455 * targeted by the flip 455 * targeted by the flip. Always wait on pre DCE4 to avoid races with
456 * flip completion handling from vblank irq, as these old asics don't
457 * have reliable pageflip completion interrupts.
456 */ 458 */
457 while (radeon_crtc->enabled && 459 while (radeon_crtc->enabled &&
458 (radeon_get_crtc_scanoutpos(dev, work->crtc_id, 0, 460 (radeon_get_crtc_scanoutpos(dev, work->crtc_id, 0,
459 &vpos, &hpos, NULL, NULL, 461 &vpos, &hpos, NULL, NULL,
460 &crtc->hwmode) 462 &crtc->hwmode)
461 & (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_IN_VBLANK)) == 463 & (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_IN_VBLANK)) ==
462 (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_IN_VBLANK) && 464 (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_IN_VBLANK) &&
463 (int)(work->target_vblank - 465 (!ASIC_IS_AVIVO(rdev) ||
464 dev->driver->get_vblank_counter(dev, work->crtc_id)) > 0) 466 ((int) (work->target_vblank -
467 dev->driver->get_vblank_counter(dev, work->crtc_id)) > 0)))
465 usleep_range(1000, 2000); 468 usleep_range(1000, 2000);
466 469
467 /* We borrow the event spin lock for protecting flip_status */ 470 /* We borrow the event spin lock for protecting flip_status */
diff --git a/drivers/gpu/drm/radeon/rv515.c b/drivers/gpu/drm/radeon/rv515.c
index 76c55c5d11ec..c55d653aaf5f 100644
--- a/drivers/gpu/drm/radeon/rv515.c
+++ b/drivers/gpu/drm/radeon/rv515.c
@@ -406,8 +406,9 @@ void rv515_mc_resume(struct radeon_device *rdev, struct rv515_mc_save *save)
406 for (i = 0; i < rdev->num_crtc; i++) { 406 for (i = 0; i < rdev->num_crtc; i++) {
407 if (save->crtc_enabled[i]) { 407 if (save->crtc_enabled[i]) {
408 tmp = RREG32(AVIVO_D1MODE_MASTER_UPDATE_MODE + crtc_offsets[i]); 408 tmp = RREG32(AVIVO_D1MODE_MASTER_UPDATE_MODE + crtc_offsets[i]);
409 if ((tmp & 0x7) != 0) { 409 if ((tmp & 0x7) != 3) {
410 tmp &= ~0x7; 410 tmp &= ~0x7;
411 tmp |= 0x3;
411 WREG32(AVIVO_D1MODE_MASTER_UPDATE_MODE + crtc_offsets[i], tmp); 412 WREG32(AVIVO_D1MODE_MASTER_UPDATE_MODE + crtc_offsets[i], tmp);
412 } 413 }
413 tmp = RREG32(AVIVO_D1GRPH_UPDATE + crtc_offsets[i]); 414 tmp = RREG32(AVIVO_D1GRPH_UPDATE + crtc_offsets[i]);