Skip to content

Commit 32b7eee

Browse files
mattropedanvet
authored andcommitted
drm/i915: Refactor work that can sleep out of commit (v7)
Once we integrate our work into the atomic pipeline, plane commit operations will need to happen with interrupts disabled, due to vblank evasion. Our commit functions today include sleepable work, so those operations need to be split out and run either before or after the atomic register programming. The solution here calculates which of those operations will need to be performed during the 'check' phase and sets flags in an intel_crtc sub-struct. New intel_begin_crtc_commit() and intel_finish_crtc_commit() functions are added before and after the actual register programming; these will eventually be called from the atomic plane helper's .atomic_begin() and .atomic_end() entrypoints. v2: Fix broken sprite code split v3: Make the pre/post commit work crtc-based to match how we eventually want this to be called from the atomic plane helpers. v4: Some platforms that haven't had their watermark code reworked were waiting for vblank, then calling update_sprite_watermarks in their platform-specific disable code. These also need to be flagged out of the critical section. v5: Sprite plane test for primary show/hide should just set the flag to wait for pending flips, not actually perform the wait. (Ander) v6: - Rebase onto latest di-nightly; picks up an important runtime PM fix. - Handle 'wait_for_flips' flag in intel_begin_crtc_commit(). (Ander) - Use wait_for_flips flag for primary plane update rather than performing the wait in the check routine. - Added kerneldoc to pre_disable/post_enable functions that are no longer static. (Ander) - Replace assert_pipe_enabled() in intel_disable_primary_hw_plane() with an intel_crtc->active test; it turns out assert_pipe_enabled() grabs some mutexes and can sleep, which we can't do with interrupts disabled. v7: - Check for fb != NULL when deciding whether the sprite plane hides the primary plane during a sprite update. (PRTS) Signed-off-by: Matt Roper <matthew.d.roper@intel.com> Reviewed-by: Ander Conselvan de Oliveira <conselvan2@gmail.com> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
1 parent 2f3408c commit 32b7eee

File tree

3 files changed

+209
-119
lines changed

3 files changed

+209
-119
lines changed

drivers/gpu/drm/i915/intel_display.c

Lines changed: 127 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -2165,7 +2165,8 @@ static void intel_disable_primary_hw_plane(struct drm_plane *plane,
21652165
struct drm_i915_private *dev_priv = dev->dev_private;
21662166
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
21672167

2168-
assert_pipe_enabled(dev_priv, intel_crtc->pipe);
2168+
if (WARN_ON(!intel_crtc->active))
2169+
return;
21692170

21702171
if (!intel_crtc->primary_enabled)
21712172
return;
@@ -11737,7 +11738,11 @@ static int
1173711738
intel_check_primary_plane(struct drm_plane *plane,
1173811739
struct intel_plane_state *state)
1173911740
{
11741+
struct drm_device *dev = plane->dev;
11742+
struct drm_i915_private *dev_priv = dev->dev_private;
1174011743
struct drm_crtc *crtc = state->base.crtc;
11744+
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
11745+
struct intel_plane *intel_plane = to_intel_plane(plane);
1174111746
struct drm_framebuffer *fb = state->base.fb;
1174211747
struct drm_rect *dest = &state->dst;
1174311748
struct drm_rect *src = &state->src;
@@ -11752,10 +11757,40 @@ intel_check_primary_plane(struct drm_plane *plane,
1175211757
if (ret)
1175311758
return ret;
1175411759

11755-
intel_crtc_wait_for_pending_flips(crtc);
11756-
if (intel_crtc_has_pending_flip(crtc)) {
11757-
DRM_ERROR("pipe is still busy with an old pageflip\n");
11758-
return -EBUSY;
11760+
if (intel_crtc->active) {
11761+
intel_crtc->atomic.wait_for_flips = true;
11762+
11763+
/*
11764+
* FBC does not work on some platforms for rotated
11765+
* planes, so disable it when rotation is not 0 and
11766+
* update it when rotation is set back to 0.
11767+
*
11768+
* FIXME: This is redundant with the fbc update done in
11769+
* the primary plane enable function except that that
11770+
* one is done too late. We eventually need to unify
11771+
* this.
11772+
*/
11773+
if (intel_crtc->primary_enabled &&
11774+
INTEL_INFO(dev)->gen <= 4 && !IS_G4X(dev) &&
11775+
dev_priv->fbc.plane == intel_crtc->plane &&
11776+
intel_plane->rotation != BIT(DRM_ROTATE_0)) {
11777+
intel_crtc->atomic.disable_fbc = true;
11778+
}
11779+
11780+
if (state->visible) {
11781+
/*
11782+
* BDW signals flip done immediately if the plane
11783+
* is disabled, even if the plane enable is already
11784+
* armed to occur at the next vblank :(
11785+
*/
11786+
if (IS_BROADWELL(dev) && !intel_crtc->primary_enabled)
11787+
intel_crtc->atomic.wait_vblank = true;
11788+
}
11789+
11790+
intel_crtc->atomic.fb_bits |=
11791+
INTEL_FRONTBUFFER_PRIMARY(intel_crtc->pipe);
11792+
11793+
intel_crtc->atomic.update_fbc = true;
1175911794
}
1176011795

1176111796
return 0;
@@ -11773,18 +11808,6 @@ intel_commit_primary_plane(struct drm_plane *plane,
1177311808
struct drm_i915_gem_object *obj = intel_fb_obj(fb);
1177411809
struct intel_plane *intel_plane = to_intel_plane(plane);
1177511810
struct drm_rect *src = &state->src;
11776-
enum pipe pipe = intel_plane->pipe;
11777-
11778-
if (!fb) {
11779-
/*
11780-
* 'prepare' is never called when plane is being disabled, so
11781-
* we need to handle frontbuffer tracking here
11782-
*/
11783-
mutex_lock(&dev->struct_mutex);
11784-
i915_gem_track_fb(intel_fb_obj(plane->fb), NULL,
11785-
INTEL_FRONTBUFFER_PRIMARY(pipe));
11786-
mutex_unlock(&dev->struct_mutex);
11787-
}
1178811811

1178911812
plane->fb = fb;
1179011813
crtc->x = src->x1 >> 16;
@@ -11801,41 +11824,14 @@ intel_commit_primary_plane(struct drm_plane *plane,
1180111824
intel_plane->obj = obj;
1180211825

1180311826
if (intel_crtc->active) {
11804-
/*
11805-
* FBC does not work on some platforms for rotated
11806-
* planes, so disable it when rotation is not 0 and
11807-
* update it when rotation is set back to 0.
11808-
*
11809-
* FIXME: This is redundant with the fbc update done in
11810-
* the primary plane enable function except that that
11811-
* one is done too late. We eventually need to unify
11812-
* this.
11813-
*/
11814-
if (intel_crtc->primary_enabled &&
11815-
INTEL_INFO(dev)->gen <= 4 && !IS_G4X(dev) &&
11816-
dev_priv->fbc.plane == intel_crtc->plane &&
11817-
intel_plane->rotation != BIT(DRM_ROTATE_0)) {
11818-
intel_fbc_disable(dev);
11819-
}
11820-
1182111827
if (state->visible) {
11822-
bool was_enabled = intel_crtc->primary_enabled;
11823-
1182411828
/* FIXME: kill this fastboot hack */
1182511829
intel_update_pipe_size(intel_crtc);
1182611830

1182711831
intel_crtc->primary_enabled = true;
1182811832

1182911833
dev_priv->display.update_primary_plane(crtc, plane->fb,
1183011834
crtc->x, crtc->y);
11831-
11832-
/*
11833-
* BDW signals flip done immediately if the plane
11834-
* is disabled, even if the plane enable is already
11835-
* armed to occur at the next vblank :(
11836-
*/
11837-
if (IS_BROADWELL(dev) && !was_enabled)
11838-
intel_wait_for_vblank(dev, intel_crtc->pipe);
1183911835
} else {
1184011836
/*
1184111837
* If clipping results in a non-visible primary plane,
@@ -11846,13 +11842,59 @@ intel_commit_primary_plane(struct drm_plane *plane,
1184611842
*/
1184711843
intel_disable_primary_hw_plane(plane, crtc);
1184811844
}
11845+
}
11846+
}
11847+
11848+
static void intel_begin_crtc_commit(struct drm_crtc *crtc)
11849+
{
11850+
struct drm_device *dev = crtc->dev;
11851+
struct drm_i915_private *dev_priv = dev->dev_private;
11852+
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
1184911853

11850-
intel_frontbuffer_flip(dev, INTEL_FRONTBUFFER_PRIMARY(pipe));
11854+
if (intel_crtc->atomic.wait_for_flips)
11855+
intel_crtc_wait_for_pending_flips(crtc);
1185111856

11857+
if (intel_crtc->atomic.disable_fbc)
11858+
intel_fbc_disable(dev);
11859+
11860+
if (intel_crtc->atomic.pre_disable_primary)
11861+
intel_pre_disable_primary(crtc);
11862+
11863+
if (intel_crtc->atomic.update_wm)
11864+
intel_update_watermarks(crtc);
11865+
11866+
intel_runtime_pm_get(dev_priv);
11867+
}
11868+
11869+
static void intel_finish_crtc_commit(struct drm_crtc *crtc)
11870+
{
11871+
struct drm_device *dev = crtc->dev;
11872+
struct drm_i915_private *dev_priv = dev->dev_private;
11873+
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
11874+
struct drm_plane *p;
11875+
11876+
intel_runtime_pm_put(dev_priv);
11877+
11878+
if (intel_crtc->atomic.wait_vblank)
11879+
intel_wait_for_vblank(dev, intel_crtc->pipe);
11880+
11881+
intel_frontbuffer_flip(dev, intel_crtc->atomic.fb_bits);
11882+
11883+
if (intel_crtc->atomic.update_fbc) {
1185211884
mutex_lock(&dev->struct_mutex);
1185311885
intel_fbc_update(dev);
1185411886
mutex_unlock(&dev->struct_mutex);
1185511887
}
11888+
11889+
if (intel_crtc->atomic.post_enable_primary)
11890+
intel_post_enable_primary(crtc);
11891+
11892+
drm_for_each_legacy_plane(p, &dev->mode_config.plane_list)
11893+
if (intel_crtc->atomic.update_sprite_watermarks & drm_plane_index(p))
11894+
intel_update_sprite_watermarks(p, crtc, 0, 0, 0,
11895+
false, false);
11896+
11897+
memset(&intel_crtc->atomic, 0, sizeof(intel_crtc->atomic));
1185611898
}
1185711899

1185811900
int
@@ -11863,9 +11905,8 @@ intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
1186311905
uint32_t src_w, uint32_t src_h)
1186411906
{
1186511907
struct drm_device *dev = plane->dev;
11866-
struct drm_i915_private *dev_priv = dev->dev_private;
1186711908
struct drm_framebuffer *old_fb = plane->fb;
11868-
struct intel_plane_state state;
11909+
struct intel_plane_state state = {{ 0 }};
1186911910
struct intel_plane *intel_plane = to_intel_plane(plane);
1187011911
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
1187111912
int ret;
@@ -11903,9 +11944,33 @@ intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
1190311944
return ret;
1190411945
}
1190511946

11906-
intel_runtime_pm_get(dev_priv);
11947+
if (!state.base.fb) {
11948+
unsigned fb_bits = 0;
11949+
11950+
switch (plane->type) {
11951+
case DRM_PLANE_TYPE_PRIMARY:
11952+
fb_bits = INTEL_FRONTBUFFER_PRIMARY(intel_plane->pipe);
11953+
break;
11954+
case DRM_PLANE_TYPE_CURSOR:
11955+
fb_bits = INTEL_FRONTBUFFER_CURSOR(intel_plane->pipe);
11956+
break;
11957+
case DRM_PLANE_TYPE_OVERLAY:
11958+
fb_bits = INTEL_FRONTBUFFER_SPRITE(intel_plane->pipe);
11959+
break;
11960+
}
11961+
11962+
/*
11963+
* 'prepare' is never called when plane is being disabled, so
11964+
* we need to handle frontbuffer tracking here
11965+
*/
11966+
mutex_lock(&dev->struct_mutex);
11967+
i915_gem_track_fb(intel_fb_obj(plane->fb), NULL, fb_bits);
11968+
mutex_unlock(&dev->struct_mutex);
11969+
}
11970+
11971+
intel_begin_crtc_commit(crtc);
1190711972
intel_plane->commit_plane(plane, &state);
11908-
intel_runtime_pm_put(dev_priv);
11973+
intel_finish_crtc_commit(crtc);
1190911974

1191011975
if (fb != old_fb && old_fb) {
1191111976
if (intel_crtc->active)
@@ -12012,6 +12077,7 @@ intel_check_cursor_plane(struct drm_plane *plane,
1201212077
struct drm_rect *src = &state->src;
1201312078
const struct drm_rect *clip = &state->clip;
1201412079
struct drm_i915_gem_object *obj = intel_fb_obj(fb);
12080+
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
1201512081
int crtc_w, crtc_h;
1201612082
unsigned stride;
1201712083
int ret;
@@ -12027,7 +12093,7 @@ intel_check_cursor_plane(struct drm_plane *plane,
1202712093

1202812094
/* if we want to turn off the cursor ignore width and height */
1202912095
if (!obj)
12030-
return 0;
12096+
goto finish;
1203112097

1203212098
/* Check for which cursor types we support */
1203312099
crtc_w = drm_rect_width(&state->orig_dst);
@@ -12054,6 +12120,16 @@ intel_check_cursor_plane(struct drm_plane *plane,
1205412120
}
1205512121
mutex_unlock(&dev->struct_mutex);
1205612122

12123+
finish:
12124+
if (intel_crtc->active) {
12125+
if (intel_crtc->cursor_width !=
12126+
drm_rect_width(&state->orig_dst))
12127+
intel_crtc->atomic.update_wm = true;
12128+
12129+
intel_crtc->atomic.fb_bits |=
12130+
INTEL_FRONTBUFFER_CURSOR(intel_crtc->pipe);
12131+
}
12132+
1205712133
return ret;
1205812134
}
1205912135

@@ -12066,9 +12142,6 @@ intel_commit_cursor_plane(struct drm_plane *plane,
1206612142
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
1206712143
struct intel_plane *intel_plane = to_intel_plane(plane);
1206812144
struct drm_i915_gem_object *obj = intel_fb_obj(state->base.fb);
12069-
struct drm_i915_gem_object *old_obj = intel_fb_obj(plane->fb);
12070-
enum pipe pipe = intel_crtc->pipe;
12071-
unsigned old_width;
1207212145
uint32_t addr;
1207312146

1207412147
plane->fb = state->base.fb;
@@ -12088,17 +12161,6 @@ intel_commit_cursor_plane(struct drm_plane *plane,
1208812161
if (intel_crtc->cursor_bo == obj)
1208912162
goto update;
1209012163

12091-
/*
12092-
* 'prepare' is only called when fb != NULL; we still need to update
12093-
* frontbuffer tracking for the 'disable' case here.
12094-
*/
12095-
if (!obj) {
12096-
mutex_lock(&dev->struct_mutex);
12097-
i915_gem_track_fb(old_obj, NULL,
12098-
INTEL_FRONTBUFFER_CURSOR(pipe));
12099-
mutex_unlock(&dev->struct_mutex);
12100-
}
12101-
1210212164
if (!obj)
1210312165
addr = 0;
1210412166
else if (!INTEL_INFO(dev)->cursor_needs_physical)
@@ -12109,18 +12171,11 @@ intel_commit_cursor_plane(struct drm_plane *plane,
1210912171
intel_crtc->cursor_addr = addr;
1211012172
intel_crtc->cursor_bo = obj;
1211112173
update:
12112-
old_width = intel_crtc->cursor_width;
12113-
1211412174
intel_crtc->cursor_width = drm_rect_width(&state->orig_dst);
1211512175
intel_crtc->cursor_height = drm_rect_height(&state->orig_dst);
1211612176

12117-
if (intel_crtc->active) {
12118-
if (old_width != intel_crtc->cursor_width)
12119-
intel_update_watermarks(crtc);
12177+
if (intel_crtc->active)
1212012178
intel_crtc_update_cursor(crtc, state->visible);
12121-
12122-
intel_frontbuffer_flip(dev, INTEL_FRONTBUFFER_CURSOR(pipe));
12123-
}
1212412179
}
1212512180

1212612181
static const struct drm_plane_funcs intel_cursor_plane_funcs = {

drivers/gpu/drm/i915/intel_drv.h

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,12 @@ struct intel_plane_state {
251251
struct drm_rect orig_src;
252252
struct drm_rect orig_dst;
253253
bool visible;
254+
255+
/*
256+
* used only for sprite planes to determine when to implicitly
257+
* enable/disable the primary plane
258+
*/
259+
bool hides_primary;
254260
};
255261

256262
struct intel_plane_config {
@@ -415,6 +421,27 @@ struct skl_pipe_wm {
415421
uint32_t linetime;
416422
};
417423

424+
/*
425+
* Tracking of operations that need to be performed at the beginning/end of an
426+
* atomic commit, outside the atomic section where interrupts are disabled.
427+
* These are generally operations that grab mutexes or might otherwise sleep
428+
* and thus can't be run with interrupts disabled.
429+
*/
430+
struct intel_crtc_atomic_commit {
431+
/* Sleepable operations to perform before commit */
432+
bool wait_for_flips;
433+
bool disable_fbc;
434+
bool pre_disable_primary;
435+
bool update_wm;
436+
437+
/* Sleepable operations to perform after commit */
438+
unsigned fb_bits;
439+
bool wait_vblank;
440+
bool update_fbc;
441+
bool post_enable_primary;
442+
unsigned update_sprite_watermarks;
443+
};
444+
418445
struct intel_crtc {
419446
struct drm_crtc base;
420447
enum pipe pipe;
@@ -468,6 +495,8 @@ struct intel_crtc {
468495

469496
int scanline_offset;
470497
struct intel_mmio_flip mmio_flip;
498+
499+
struct intel_crtc_atomic_commit atomic;
471500
};
472501

473502
struct intel_plane_wm_parameters {
@@ -1215,6 +1244,8 @@ int intel_sprite_get_colorkey(struct drm_device *dev, void *data,
12151244
bool intel_pipe_update_start(struct intel_crtc *crtc,
12161245
uint32_t *start_vbl_count);
12171246
void intel_pipe_update_end(struct intel_crtc *crtc, u32 start_vbl_count);
1247+
void intel_post_enable_primary(struct drm_crtc *crtc);
1248+
void intel_pre_disable_primary(struct drm_crtc *crtc);
12181249

12191250
/* intel_tv.c */
12201251
void intel_tv_init(struct drm_device *dev);

0 commit comments

Comments
 (0)