Commit 6ddd388a authored by Rob Clark's avatar Rob Clark Committed by Daniel Vetter

drm/atomic: track bitmask of planes attached to crtc

Chasing plane->state->crtc of planes that are *not* part of the same
atomic update is racy, making it incredibly awkward (or impossible) to
do something simple like iterate over all planes and figure out which
ones are attached to a crtc.

Solve this by adding a bitmask of currently attached planes in the
crtc-state.

Note that the transitional helpers do not maintain the plane_mask.  But
they only support the legacy ioctls, which have sufficient brute-force
locking around plane updates that they can continue to loop over all
planes to see what is attached to a crtc the old way.
Signed-off-by: default avatarRob Clark <robdclark@gmail.com>
[danvet:
- Drop comments about locking in set_crtc_for_plane since they're a
  bit misleading - we already should hold lock for the current crtc.
- Also WARN_ON if get_state on the old crtc fails since that should
  have been done already.
- Squash in fixup to check get_plane_state return value, reported by
  Dan Carpenter and acked by Rob Clark.]
Signed-off-by: default avatarDaniel Vetter <daniel.vetter@ffwll.ch>
parent 3009c037
...@@ -344,7 +344,8 @@ EXPORT_SYMBOL(drm_atomic_get_connector_state); ...@@ -344,7 +344,8 @@ EXPORT_SYMBOL(drm_atomic_get_connector_state);
/** /**
* drm_atomic_set_crtc_for_plane - set crtc for plane * drm_atomic_set_crtc_for_plane - set crtc for plane
* @plane_state: atomic state object for the plane * @state: the incoming atomic state
* @plane: the plane whose incoming state to update
* @crtc: crtc to use for the plane * @crtc: crtc to use for the plane
* *
* Changing the assigned crtc for a plane requires us to grab the lock and state * Changing the assigned crtc for a plane requires us to grab the lock and state
...@@ -357,20 +358,35 @@ EXPORT_SYMBOL(drm_atomic_get_connector_state); ...@@ -357,20 +358,35 @@ EXPORT_SYMBOL(drm_atomic_get_connector_state);
* sequence must be restarted. All other errors are fatal. * sequence must be restarted. All other errors are fatal.
*/ */
int int
drm_atomic_set_crtc_for_plane(struct drm_plane_state *plane_state, drm_atomic_set_crtc_for_plane(struct drm_atomic_state *state,
struct drm_crtc *crtc) struct drm_plane *plane, struct drm_crtc *crtc)
{ {
struct drm_plane_state *plane_state =
drm_atomic_get_plane_state(state, plane);
struct drm_crtc_state *crtc_state; struct drm_crtc_state *crtc_state;
if (WARN_ON(IS_ERR(plane_state)))
return PTR_ERR(plane_state);
if (plane_state->crtc) {
crtc_state = drm_atomic_get_crtc_state(plane_state->state,
plane_state->crtc);
if (WARN_ON(IS_ERR(crtc_state)))
return PTR_ERR(crtc_state);
crtc_state->plane_mask &= ~(1 << drm_plane_index(plane));
}
plane_state->crtc = crtc;
if (crtc) { if (crtc) {
crtc_state = drm_atomic_get_crtc_state(plane_state->state, crtc_state = drm_atomic_get_crtc_state(plane_state->state,
crtc); crtc);
if (IS_ERR(crtc_state)) if (IS_ERR(crtc_state))
return PTR_ERR(crtc_state); return PTR_ERR(crtc_state);
crtc_state->plane_mask |= (1 << drm_plane_index(plane));
} }
plane_state->crtc = crtc;
if (crtc) if (crtc)
DRM_DEBUG_KMS("Link plane state %p to [CRTC:%d]\n", DRM_DEBUG_KMS("Link plane state %p to [CRTC:%d]\n",
plane_state, crtc->base.id); plane_state, crtc->base.id);
......
...@@ -1222,7 +1222,7 @@ int drm_atomic_helper_update_plane(struct drm_plane *plane, ...@@ -1222,7 +1222,7 @@ int drm_atomic_helper_update_plane(struct drm_plane *plane,
goto fail; goto fail;
} }
ret = drm_atomic_set_crtc_for_plane(plane_state, crtc); ret = drm_atomic_set_crtc_for_plane(state, plane, crtc);
if (ret != 0) if (ret != 0)
goto fail; goto fail;
drm_atomic_set_fb_for_plane(plane_state, fb); drm_atomic_set_fb_for_plane(plane_state, fb);
...@@ -1301,7 +1301,7 @@ int drm_atomic_helper_disable_plane(struct drm_plane *plane) ...@@ -1301,7 +1301,7 @@ int drm_atomic_helper_disable_plane(struct drm_plane *plane)
goto fail; goto fail;
} }
ret = drm_atomic_set_crtc_for_plane(plane_state, NULL); ret = drm_atomic_set_crtc_for_plane(state, plane, NULL);
if (ret != 0) if (ret != 0)
goto fail; goto fail;
drm_atomic_set_fb_for_plane(plane_state, NULL); drm_atomic_set_fb_for_plane(plane_state, NULL);
...@@ -1472,7 +1472,7 @@ int drm_atomic_helper_set_config(struct drm_mode_set *set) ...@@ -1472,7 +1472,7 @@ int drm_atomic_helper_set_config(struct drm_mode_set *set)
goto fail; goto fail;
} }
ret = drm_atomic_set_crtc_for_plane(primary_state, crtc); ret = drm_atomic_set_crtc_for_plane(state, crtc->primary, crtc);
if (ret != 0) if (ret != 0)
goto fail; goto fail;
drm_atomic_set_fb_for_plane(primary_state, set->fb); drm_atomic_set_fb_for_plane(primary_state, set->fb);
...@@ -1744,7 +1744,7 @@ int drm_atomic_helper_page_flip(struct drm_crtc *crtc, ...@@ -1744,7 +1744,7 @@ int drm_atomic_helper_page_flip(struct drm_crtc *crtc,
goto fail; goto fail;
} }
ret = drm_atomic_set_crtc_for_plane(plane_state, crtc); ret = drm_atomic_set_crtc_for_plane(state, plane, crtc);
if (ret != 0) if (ret != 0)
goto fail; goto fail;
drm_atomic_set_fb_for_plane(plane_state, fb); drm_atomic_set_fb_for_plane(plane_state, fb);
......
...@@ -46,8 +46,8 @@ drm_atomic_get_connector_state(struct drm_atomic_state *state, ...@@ -46,8 +46,8 @@ drm_atomic_get_connector_state(struct drm_atomic_state *state,
struct drm_connector *connector); struct drm_connector *connector);
int __must_check int __must_check
drm_atomic_set_crtc_for_plane(struct drm_plane_state *plane_state, drm_atomic_set_crtc_for_plane(struct drm_atomic_state *state,
struct drm_crtc *crtc); struct drm_plane *plane, struct drm_crtc *crtc);
void drm_atomic_set_fb_for_plane(struct drm_plane_state *plane_state, void drm_atomic_set_fb_for_plane(struct drm_plane_state *plane_state,
struct drm_framebuffer *fb); struct drm_framebuffer *fb);
int __must_check int __must_check
......
...@@ -231,6 +231,7 @@ struct drm_atomic_state; ...@@ -231,6 +231,7 @@ struct drm_atomic_state;
* struct drm_crtc_state - mutable CRTC state * struct drm_crtc_state - mutable CRTC state
* @enable: whether the CRTC should be enabled, gates all other state * @enable: whether the CRTC should be enabled, gates all other state
* @mode_changed: for use by helpers and drivers when computing state updates * @mode_changed: for use by helpers and drivers when computing state updates
* @plane_mask: bitmask of (1 << drm_plane_index(plane)) of attached planes
* @last_vblank_count: for helpers and drivers to capture the vblank of the * @last_vblank_count: for helpers and drivers to capture the vblank of the
* update to ensure framebuffer cleanup isn't done too early * update to ensure framebuffer cleanup isn't done too early
* @planes_changed: for use by helpers and drivers when computing state updates * @planes_changed: for use by helpers and drivers when computing state updates
...@@ -247,6 +248,13 @@ struct drm_crtc_state { ...@@ -247,6 +248,13 @@ struct drm_crtc_state {
bool planes_changed : 1; bool planes_changed : 1;
bool mode_changed : 1; bool mode_changed : 1;
/* attached planes bitmask:
* WARNING: transitional helpers do not maintain plane_mask so
* drivers not converted over to atomic helpers should not rely
* on plane_mask being accurate!
*/
u32 plane_mask;
/* last_vblank_count: for vblank waits before cleanup */ /* last_vblank_count: for vblank waits before cleanup */
u32 last_vblank_count; u32 last_vblank_count;
...@@ -438,7 +446,7 @@ struct drm_crtc { ...@@ -438,7 +446,7 @@ struct drm_crtc {
* @state: backpointer to global drm_atomic_state * @state: backpointer to global drm_atomic_state
*/ */
struct drm_connector_state { struct drm_connector_state {
struct drm_crtc *crtc; struct drm_crtc *crtc; /* do not write directly, use drm_atomic_set_crtc_for_connector() */
struct drm_encoder *best_encoder; struct drm_encoder *best_encoder;
...@@ -673,8 +681,8 @@ struct drm_connector { ...@@ -673,8 +681,8 @@ struct drm_connector {
* @state: backpointer to global drm_atomic_state * @state: backpointer to global drm_atomic_state
*/ */
struct drm_plane_state { struct drm_plane_state {
struct drm_crtc *crtc; struct drm_crtc *crtc; /* do not write directly, use drm_atomic_set_crtc_for_plane() */
struct drm_framebuffer *fb; struct drm_framebuffer *fb; /* do not write directly, use drm_atomic_set_fb_for_plane() */
struct fence *fence; struct fence *fence;
/* Signed dest location allows it to be partially off screen */ /* Signed dest location allows it to be partially off screen */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment