Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm/radeon: 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
radeon_flip_work_func considerably.

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>

authored by

Michel Dänzer and committed by
Alex Deucher
b8fc75cf 3fd4b751

+25 -65
+1
drivers/gpu/drm/radeon/radeon.h
··· 742 742 struct work_struct unpin_work; 743 743 struct radeon_device *rdev; 744 744 int crtc_id; 745 + u32 target_vblank; 745 746 uint64_t base; 746 747 struct drm_pending_vblank_event *event; 747 748 struct radeon_bo *old_rbo;
+24 -65
drivers/gpu/drm/radeon/radeon_display.c
··· 400 400 struct radeon_flip_work *work = 401 401 container_of(__work, struct radeon_flip_work, flip_work); 402 402 struct radeon_device *rdev = work->rdev; 403 + struct drm_device *dev = rdev->ddev; 403 404 struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[work->crtc_id]; 404 405 405 406 struct drm_crtc *crtc = &radeon_crtc->base; 406 407 unsigned long flags; 407 408 int r; 408 - int vpos, hpos, stat, min_udelay = 0; 409 - unsigned repcnt = 4; 410 - struct drm_vblank_crtc *vblank = &crtc->dev->vblank[work->crtc_id]; 409 + int vpos, hpos; 411 410 412 411 down_read(&rdev->exclusive_lock); 413 412 if (work->fence) { ··· 437 438 work->fence = NULL; 438 439 } 439 440 441 + /* Wait until we're out of the vertical blank period before the one 442 + * targeted by the flip 443 + */ 444 + while (radeon_crtc->enabled && 445 + (radeon_get_crtc_scanoutpos(dev, work->crtc_id, 0, 446 + &vpos, &hpos, NULL, NULL, 447 + &crtc->hwmode) 448 + & (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_IN_VBLANK)) == 449 + (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_IN_VBLANK) && 450 + (int)(work->target_vblank - 451 + dev->driver->get_vblank_counter(dev, work->crtc_id)) > 0) 452 + usleep_range(1000, 2000); 453 + 440 454 /* We borrow the event spin lock for protecting flip_status */ 441 455 spin_lock_irqsave(&crtc->dev->event_lock, flags); 442 456 443 457 /* set the proper interrupt */ 444 458 radeon_irq_kms_pflip_irq_get(rdev, radeon_crtc->crtc_id); 445 - 446 - /* If this happens to execute within the "virtually extended" vblank 447 - * interval before the start of the real vblank interval then it needs 448 - * to delay programming the mmio flip until the real vblank is entered. 449 - * This prevents completing a flip too early due to the way we fudge 450 - * our vblank counter and vblank timestamps in order to work around the 451 - * problem that the hw fires vblank interrupts before actual start of 452 - * vblank (when line buffer refilling is done for a frame). It 453 - * complements the fudging logic in radeon_get_crtc_scanoutpos() for 454 - * timestamping and radeon_get_vblank_counter_kms() for vblank counts. 455 - * 456 - * In practice this won't execute very often unless on very fast 457 - * machines because the time window for this to happen is very small. 458 - */ 459 - while (radeon_crtc->enabled && --repcnt) { 460 - /* GET_DISTANCE_TO_VBLANKSTART returns distance to real vblank 461 - * start in hpos, and to the "fudged earlier" vblank start in 462 - * vpos. 463 - */ 464 - stat = radeon_get_crtc_scanoutpos(rdev->ddev, work->crtc_id, 465 - GET_DISTANCE_TO_VBLANKSTART, 466 - &vpos, &hpos, NULL, NULL, 467 - &crtc->hwmode); 468 - 469 - if ((stat & (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE)) != 470 - (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE) || 471 - !(vpos >= 0 && hpos <= 0)) 472 - break; 473 - 474 - /* Sleep at least until estimated real start of hw vblank */ 475 - min_udelay = (-hpos + 1) * max(vblank->linedur_ns / 1000, 5); 476 - if (min_udelay > vblank->framedur_ns / 2000) { 477 - /* Don't wait ridiculously long - something is wrong */ 478 - repcnt = 0; 479 - break; 480 - } 481 - spin_unlock_irqrestore(&crtc->dev->event_lock, flags); 482 - usleep_range(min_udelay, 2 * min_udelay); 483 - spin_lock_irqsave(&crtc->dev->event_lock, flags); 484 - }; 485 - 486 - if (!repcnt) 487 - DRM_DEBUG_DRIVER("Delay problem on crtc %d: min_udelay %d, " 488 - "framedur %d, linedur %d, stat %d, vpos %d, " 489 - "hpos %d\n", work->crtc_id, min_udelay, 490 - vblank->framedur_ns / 1000, 491 - vblank->linedur_ns / 1000, stat, vpos, hpos); 492 459 493 460 /* do the flip (mmio) */ 494 461 radeon_page_flip(rdev, radeon_crtc->crtc_id, work->base, work->async); ··· 464 499 up_read(&rdev->exclusive_lock); 465 500 } 466 501 467 - static int radeon_crtc_page_flip(struct drm_crtc *crtc, 468 - struct drm_framebuffer *fb, 469 - struct drm_pending_vblank_event *event, 470 - uint32_t page_flip_flags) 502 + static int radeon_crtc_page_flip_target(struct drm_crtc *crtc, 503 + struct drm_framebuffer *fb, 504 + struct drm_pending_vblank_event *event, 505 + uint32_t page_flip_flags, 506 + uint32_t target) 471 507 { 472 508 struct drm_device *dev = crtc->dev; 473 509 struct radeon_device *rdev = dev->dev_private; ··· 565 599 base &= ~7; 566 600 } 567 601 work->base = base; 568 - 569 - r = drm_crtc_vblank_get(crtc); 570 - if (r) { 571 - DRM_ERROR("failed to get vblank before flip\n"); 572 - goto pflip_cleanup; 573 - } 602 + work->target_vblank = target - drm_crtc_vblank_count(crtc) + 603 + dev->driver->get_vblank_counter(dev, work->crtc_id); 574 604 575 605 /* We borrow the event spin lock for protecting flip_work */ 576 606 spin_lock_irqsave(&crtc->dev->event_lock, flags); ··· 575 613 DRM_DEBUG_DRIVER("flip queue: crtc already busy\n"); 576 614 spin_unlock_irqrestore(&crtc->dev->event_lock, flags); 577 615 r = -EBUSY; 578 - goto vblank_cleanup; 616 + goto pflip_cleanup; 579 617 } 580 618 radeon_crtc->flip_status = RADEON_FLIP_PENDING; 581 619 radeon_crtc->flip_work = work; ··· 587 625 588 626 queue_work(radeon_crtc->flip_queue, &work->flip_work); 589 627 return 0; 590 - 591 - vblank_cleanup: 592 - drm_crtc_vblank_put(crtc); 593 628 594 629 pflip_cleanup: 595 630 if (unlikely(radeon_bo_reserve(new_rbo, false) != 0)) { ··· 656 697 .gamma_set = radeon_crtc_gamma_set, 657 698 .set_config = radeon_crtc_set_config, 658 699 .destroy = radeon_crtc_destroy, 659 - .page_flip = radeon_crtc_page_flip, 700 + .page_flip_target = radeon_crtc_page_flip_target, 660 701 }; 661 702 662 703 static void radeon_crtc_init(struct drm_device *dev, int index)