Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 325cbba1 authored by Michel Dänzer's avatar Michel Dänzer Committed by Alex Deucher
Browse files

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: default avatarChristian König <christian.koenig@amd.com>
Signed-off-by: default avatarMichel Dänzer <michel.daenzer@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent c229bfbb
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -730,10 +730,11 @@ void amdgpu_doorbell_get_kfd_info(struct amdgpu_device *adev,
 */

struct amdgpu_flip_work {
	struct work_struct		flip_work;
	struct delayed_work		flip_work;
	struct work_struct		unpin_work;
	struct amdgpu_device		*adev;
	int				crtc_id;
	u32				target_vblank;
	uint64_t			base;
	struct drm_pending_vblank_event *event;
	struct amdgpu_bo		*old_rbo;
+29 −67
Original line number Diff line number Diff line
@@ -41,7 +41,7 @@ static void amdgpu_flip_callback(struct fence *f, struct fence_cb *cb)
		container_of(cb, struct amdgpu_flip_work, cb);

	fence_put(f);
	schedule_work(&work->flip_work);
	schedule_work(&work->flip_work.work);
}

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,

static void amdgpu_flip_work_func(struct work_struct *__work)
{
	struct delayed_work *delayed_work =
		container_of(__work, struct delayed_work, work);
	struct amdgpu_flip_work *work =
		container_of(__work, struct amdgpu_flip_work, flip_work);
		container_of(delayed_work, struct amdgpu_flip_work, flip_work);
	struct amdgpu_device *adev = work->adev;
	struct amdgpu_crtc *amdgpuCrtc = adev->mode_info.crtcs[work->crtc_id];

	struct drm_crtc *crtc = &amdgpuCrtc->base;
	unsigned long flags;
	unsigned i, repcnt = 4;
	int vpos, hpos, stat, min_udelay = 0;
	struct drm_vblank_crtc *vblank = &crtc->dev->vblank[work->crtc_id];
	unsigned i;
	int vpos, hpos;

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

	/* We borrow the event spin lock for protecting flip_status */
	spin_lock_irqsave(&crtc->dev->event_lock, flags);

	/* If this happens to execute within the "virtually extended" vblank
	 * interval before the start of the real vblank interval then it needs
	 * to delay programming the mmio flip until the real vblank is entered.
	 * This prevents completing a flip too early due to the way we fudge
	 * our vblank counter and vblank timestamps in order to work around the
	 * problem that the hw fires vblank interrupts before actual start of
	 * vblank (when line buffer refilling is done for a frame). It
	 * complements the fudging logic in amdgpu_get_crtc_scanoutpos() for
	 * timestamping and amdgpu_get_vblank_counter_kms() for vblank counts.
	 *
	 * In practice this won't execute very often unless on very fast
	 * machines because the time window for this to happen is very small.
	 */
	while (amdgpuCrtc->enabled && --repcnt) {
		/* GET_DISTANCE_TO_VBLANKSTART returns distance to real vblank
		 * start in hpos, and to the "fudged earlier" vblank start in
		 * vpos.
	/* Wait until we're out of the vertical blank period before the one
	 * targeted by the flip
	 */
		stat = amdgpu_get_crtc_scanoutpos(adev->ddev, work->crtc_id,
						  GET_DISTANCE_TO_VBLANKSTART,
	if (amdgpuCrtc->enabled &&
	    (amdgpu_get_crtc_scanoutpos(adev->ddev, work->crtc_id, 0,
					&vpos, &hpos, NULL, NULL,
						  &crtc->hwmode);

		if ((stat & (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE)) !=
		    (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE) ||
		    !(vpos >= 0 && hpos <= 0))
			break;

		/* Sleep at least until estimated real start of hw vblank */
		min_udelay = (-hpos + 1) * max(vblank->linedur_ns / 1000, 5);
		if (min_udelay > vblank->framedur_ns / 2000) {
			/* Don't wait ridiculously long - something is wrong */
			repcnt = 0;
			break;
		}
		spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
		usleep_range(min_udelay, 2 * min_udelay);
		spin_lock_irqsave(&crtc->dev->event_lock, flags);
					&crtc->hwmode)
	     & (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_IN_VBLANK)) ==
	    (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_IN_VBLANK) &&
	    (int)(work->target_vblank -
		  amdgpu_get_vblank_counter_kms(adev->ddev, amdgpuCrtc->crtc_id)) > 0) {
		schedule_delayed_work(&work->flip_work, usecs_to_jiffies(1000));
		return;
	}

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

	/* Do the flip (mmio) */
	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)
	kfree(work);
}

int amdgpu_crtc_page_flip(struct drm_crtc *crtc,
int amdgpu_crtc_page_flip_target(struct drm_crtc *crtc,
				 struct drm_framebuffer *fb,
				 struct drm_pending_vblank_event *event,
			  uint32_t page_flip_flags)
				 uint32_t page_flip_flags, uint32_t target)
{
	struct drm_device *dev = crtc->dev;
	struct amdgpu_device *adev = dev->dev_private;
@@ -191,7 +160,7 @@ int amdgpu_crtc_page_flip(struct drm_crtc *crtc,
	if (work == NULL)
		return -ENOMEM;

	INIT_WORK(&work->flip_work, amdgpu_flip_work_func);
	INIT_DELAYED_WORK(&work->flip_work, amdgpu_flip_work_func);
	INIT_WORK(&work->unpin_work, amdgpu_unpin_work_func);

	work->event = event;
@@ -237,12 +206,8 @@ int amdgpu_crtc_page_flip(struct drm_crtc *crtc,
	amdgpu_bo_unreserve(new_rbo);

	work->base = base;

	r = drm_crtc_vblank_get(crtc);
	if (r) {
		DRM_ERROR("failed to get vblank before flip\n");
		goto pflip_cleanup;
	}
	work->target_vblank = target - drm_crtc_vblank_count(crtc) +
		amdgpu_get_vblank_counter_kms(dev, work->crtc_id);

	/* we borrow the event spin lock for protecting flip_wrok */
	spin_lock_irqsave(&crtc->dev->event_lock, flags);
@@ -250,7 +215,7 @@ int amdgpu_crtc_page_flip(struct drm_crtc *crtc,
		DRM_DEBUG_DRIVER("flip queue: crtc already busy\n");
		spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
		r = -EBUSY;
		goto vblank_cleanup;
		goto pflip_cleanup;
	}

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

vblank_cleanup:
	drm_crtc_vblank_put(crtc);

pflip_cleanup:
	if (unlikely(amdgpu_bo_reserve(new_rbo, false) != 0)) {
		DRM_ERROR("failed to reserve new rbo in error path\n");
+4 −4
Original line number Diff line number Diff line
@@ -591,10 +591,10 @@ int amdgpu_align_pitch(struct amdgpu_device *adev, int width, int bpp, bool tile
void amdgpu_print_display_setup(struct drm_device *dev);
int amdgpu_modeset_create_props(struct amdgpu_device *adev);
int amdgpu_crtc_set_config(struct drm_mode_set *set);
int amdgpu_crtc_page_flip(struct drm_crtc *crtc,
int amdgpu_crtc_page_flip_target(struct drm_crtc *crtc,
				 struct drm_framebuffer *fb,
				 struct drm_pending_vblank_event *event,
			  uint32_t page_flip_flags);
				 uint32_t page_flip_flags, uint32_t target);
extern const struct drm_mode_config_funcs amdgpu_mode_funcs;

#endif
+1 −1
Original line number Diff line number Diff line
@@ -2737,7 +2737,7 @@ static const struct drm_crtc_funcs dce_v10_0_crtc_funcs = {
	.gamma_set = dce_v10_0_crtc_gamma_set,
	.set_config = amdgpu_crtc_set_config,
	.destroy = dce_v10_0_crtc_destroy,
	.page_flip = amdgpu_crtc_page_flip,
	.page_flip_target = amdgpu_crtc_page_flip_target,
};

static void dce_v10_0_crtc_dpms(struct drm_crtc *crtc, int mode)
+1 −1
Original line number Diff line number Diff line
@@ -2755,7 +2755,7 @@ static const struct drm_crtc_funcs dce_v11_0_crtc_funcs = {
	.gamma_set = dce_v11_0_crtc_gamma_set,
	.set_config = amdgpu_crtc_set_config,
	.destroy = dce_v11_0_crtc_destroy,
	.page_flip = amdgpu_crtc_page_flip,
	.page_flip_target = amdgpu_crtc_page_flip_target,
};

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