From: Andrey Grodzovsky <Andrey.Grodzovsky@amd.com>
Date: Wed, 7 Jun 2017 18:28:43 -0400
Subject: drm/amd/display: Handle commit plane with no FB.
Git-commit: 1159898a88db33877bd8378714c6f647afab7f9b
Patch-mainline: v4.15-rc1
References: FATE#326289 FATE#326079 FATE#326049 FATE#322398 FATE#326166
1) Always call flip ISR, for any surface comit, not only for page flip.
2) For events not signaled in flip ISR, handle them in end of commit_tail.
3)Fix race condition between subsequent atomic calls by removing
current state access AFTER drm_atomic_helper_commit_hw_done
was called. After this call a pending next commit will
swap in his own state into objects and proceed.
Signed-off-by: Andrey Grodzovsky <Andrey.Grodzovsky@amd.com>
Reviewed-by: Harry Wentland <Harry.Wentland@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Acked-by: Petr Tesarik <ptesarik@suse.com>
---
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 6
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_types.c | 127 ++++++++--------
2 files changed, 70 insertions(+), 63 deletions(-)
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -222,15 +222,15 @@ static void dm_pflip_high_irq(void *inte
/* wakeup usersapce */
- if (amdgpu_crtc->event
- && amdgpu_crtc->event->event.base.type
- == DRM_EVENT_FLIP_COMPLETE) {
+ if (amdgpu_crtc->event) {
/* Update to correct count/ts if racing with vblank irq */
drm_crtc_accurate_vblank_count(&amdgpu_crtc->base);
drm_crtc_send_vblank_event(&amdgpu_crtc->base, amdgpu_crtc->event);
+
/* page flip completed. clean up */
amdgpu_crtc->event = NULL;
+
} else
WARN_ON(1);
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_types.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_types.c
@@ -2180,6 +2180,24 @@ static void handle_cursor_update(
}
+static void prepare_flip_isr(struct amdgpu_crtc *acrtc)
+{
+
+ assert_spin_locked(&acrtc->base.dev->event_lock);
+ WARN_ON(acrtc->event);
+
+ acrtc->event = acrtc->base.state->event;
+
+ /* Set the flip status */
+ acrtc->pflip_status = AMDGPU_FLIP_SUBMITTED;
+
+ /* Mark this event as consumed */
+ acrtc->base.state->event = NULL;
+
+ DRM_DEBUG_DRIVER("crtc:%d, pflip_stat:AMDGPU_FLIP_SUBMITTED\n",
+ acrtc->crtc_id);
+}
+
/*
* Executes flip
*
@@ -2249,17 +2267,8 @@ static void amdgpu_dm_do_flip(
addr.flip_immediate = async_flip;
- if (acrtc->base.state->event &&
- acrtc->base.state->event->event.base.type ==
- DRM_EVENT_FLIP_COMPLETE) {
- acrtc->event = acrtc->base.state->event;
-
- /* Set the flip status */
- acrtc->pflip_status = AMDGPU_FLIP_SUBMITTED;
-
- /* Mark this event as consumed */
- acrtc->base.state->event = NULL;
- }
+ if (acrtc->base.state->event)
+ prepare_flip_isr(acrtc);
surface_updates->surface = dc_stream_get_status(acrtc->stream)->surfaces[0];
surface_updates->flip_addr = &addr;
@@ -2274,8 +2283,6 @@ static void amdgpu_dm_do_flip(
spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
- DRM_DEBUG_DRIVER("crtc:%d, pflip_stat:AMDGPU_FLIP_SUBMITTED\n",
- acrtc->crtc_id);
}
static void amdgpu_dm_commit_surfaces(struct drm_atomic_state *state,
@@ -2289,13 +2296,13 @@ static void amdgpu_dm_commit_surfaces(st
struct drm_plane_state *old_plane_state;
const struct dc_stream *dc_stream_attach;
const struct dc_surface *dc_surfaces_constructed[MAX_SURFACES];
+ struct amdgpu_crtc *acrtc_attach = to_amdgpu_crtc(pcrtc);
int planes_count = 0;
/* update planes when needed */
for_each_plane_in_state(state, plane, old_plane_state, i) {
struct drm_plane_state *plane_state = plane->state;
struct drm_crtc *crtc = plane_state->crtc;
- struct amdgpu_crtc *acrtc_attach = to_amdgpu_crtc(crtc);
struct drm_framebuffer *fb = plane_state->fb;
struct drm_connector *connector;
struct dm_connector_state *con_state = NULL;
@@ -2306,7 +2313,7 @@ static void amdgpu_dm_commit_surfaces(st
continue;
}
- if (!fb || !crtc || !crtc->state->active)
+ if (!fb || !crtc || pcrtc != crtc || !crtc->state->active)
continue;
pflip_needed = !state->allow_modeset;
@@ -2339,17 +2346,21 @@ static void amdgpu_dm_commit_surfaces(st
continue;
- if (crtc == pcrtc) {
- add_surface(dm->dc, crtc, plane,
- &dc_surfaces_constructed[planes_count]);
- if (dc_surfaces_constructed[planes_count] == NULL) {
- dm_error("%s: Failed to add surface!\n", __func__);
- continue;
- }
- dc_stream_attach = acrtc_attach->stream;
- planes_count++;
+
+ add_surface(dm->dc, crtc, plane,
+ &dc_surfaces_constructed[planes_count]);
+ if (dc_surfaces_constructed[planes_count] == NULL) {
+ dm_error("%s: Failed to add surface!\n", __func__);
+ continue;
}
+ dc_stream_attach = acrtc_attach->stream;
+ planes_count++;
+
} else if (crtc->state->planes_changed) {
+ /* Assume even ONE crtc with immediate flip means
+ * entire can't wait for VBLANK
+ * TODO Check if it's correct
+ */
*wait_for_vblank =
acrtc_attach->flip_flags & DRM_MODE_PAGE_FLIP_ASYNC ?
false : true;
@@ -2359,6 +2370,8 @@ static void amdgpu_dm_commit_surfaces(st
fb,
drm_crtc_vblank_count(crtc) + *wait_for_vblank);
+ /*TODO BUG remove ASAP in 4.12 to avoid race between worker and flip IOCTL */
+
/*clean up the flags for next usage*/
acrtc_attach->flip_flags = 0;
}
@@ -2366,15 +2379,27 @@ static void amdgpu_dm_commit_surfaces(st
}
if (planes_count) {
+ unsigned long flags;
+
+ if (pcrtc->state->event) {
+
+ drm_crtc_vblank_get(pcrtc);
+
+ spin_lock_irqsave(&pcrtc->dev->event_lock, flags);
+ prepare_flip_isr(acrtc_attach);
+ spin_unlock_irqrestore(&pcrtc->dev->event_lock, flags);
+ }
+
if (false == dc_commit_surfaces_to_stream(dm->dc,
dc_surfaces_constructed,
planes_count,
- dc_stream_attach)) {
+ dc_stream_attach))
dm_error("%s: Failed to attach surface!\n", __func__);
- return;
- }
+
for (i = 0; i < planes_count; i++)
dc_surface_release(dc_surfaces_constructed[i]);
+ } else {
+ /*TODO BUG Here should go disable planes on CRTC. */
}
}
@@ -2405,7 +2430,6 @@ void amdgpu_dm_atomic_commit_tail(
struct drm_crtc_state *new_state = crtc->state;
acrtc = to_amdgpu_crtc(crtc);
-
aconnector =
amdgpu_dm_find_first_crct_matching_connector(
state,
@@ -2571,14 +2595,6 @@ void amdgpu_dm_atomic_commit_tail(
dc_stream_get_status(acrtc->stream)->primary_otg_inst;
}
- /* update planes when needed per crtc*/
- for_each_crtc_in_state(state, pcrtc, old_crtc_state, j) {
- struct amdgpu_crtc *acrtc = to_amdgpu_crtc(pcrtc);
-
- if (acrtc->stream)
- amdgpu_dm_commit_surfaces(state, dev, dm, pcrtc, &wait_for_vblank);
- }
-
for (i = 0; i < new_crtcs_count; i++) {
/*
* loop to enable interrupts on newly arrived crtc
@@ -2592,19 +2608,27 @@ void amdgpu_dm_atomic_commit_tail(
manage_dm_interrupts(adev, acrtc, true);
}
+ /* update planes when needed per crtc*/
+ for_each_crtc_in_state(state, pcrtc, old_crtc_state, j) {
+ struct amdgpu_crtc *acrtc = to_amdgpu_crtc(pcrtc);
+
+ if (acrtc->stream)
+ amdgpu_dm_commit_surfaces(state, dev, dm, pcrtc, &wait_for_vblank);
+ }
- /*TODO mark consumed event on all crtc assigned event
- * in drm_atomic_helper_setup_commit just to signal completion
+
+ /*
+ * send vblank event on all events not handled in flip and
+ * mark consumed event for drm_atomic_helper_commit_hw_done
*/
spin_lock_irqsave(&adev->ddev->event_lock, flags);
for_each_crtc_in_state(state, crtc, old_crtc_state, i) {
struct amdgpu_crtc *acrtc = to_amdgpu_crtc(crtc);
- if (acrtc->base.state->event &&
- acrtc->base.state->event->event.base.type != DRM_EVENT_FLIP_COMPLETE) {
- acrtc->event = acrtc->base.state->event;
- acrtc->base.state->event = NULL;
- }
+ if (acrtc->base.state->event)
+ drm_send_event_locked(dev, &crtc->state->event->base);
+
+ acrtc->base.state->event = NULL;
}
spin_unlock_irqrestore(&adev->ddev->event_lock, flags);
@@ -2614,23 +2638,6 @@ void amdgpu_dm_atomic_commit_tail(
if (wait_for_vblank)
drm_atomic_helper_wait_for_vblanks(dev, state);
- /*TODO send vblank event on all crtc assigned event
- * in drm_atomic_helper_setup_commit just to signal completion
- */
- spin_lock_irqsave(&adev->ddev->event_lock, flags);
- for_each_crtc_in_state(state, crtc, old_crtc_state, i) {
- struct amdgpu_crtc *acrtc = to_amdgpu_crtc(crtc);
-
- if (acrtc->event &&
- acrtc->event->event.base.type != DRM_EVENT_FLIP_COMPLETE) {
- drm_send_event_locked(dev, &acrtc->event->base);
- acrtc->event = NULL;
- }
- }
- spin_unlock_irqrestore(&adev->ddev->event_lock, flags);
-
- /*TODO Is it to early if actual flip haven't happened yet ?*/
- /* Release old FB */
drm_atomic_helper_cleanup_planes(dev, state);
}