Hi Maarten,
Thank you for the patch.
On Monday 16 Jan 2017 10:37:38 Maarten Lankhorst wrote:
Add for_each_(old)(new)_(plane,connector,crtc)_in_state iterators to replace the old for_each_xxx_in_state ones. This is useful for >1 flip depth and getting rid of all xxx->state dereferences.
This requires extra fixups done when committing a state after duplicating, which in general isn't valid but is used by suspend/resume. To handle these, introduce drm_atomic_helper_commit_duplicated_state which performs those fixups before checking & committing the state.
Changes since v1:
- Remove nonblock parameter for commit_duplicated_state.
Changes since v2:
- Use commit_duplicated_state for i915 load detection.
- Add WARN_ON(old_state != obj->state) before swapping.
Signed-off-by: Maarten Lankhorst maarten.lankhorst@linux.intel.com
drivers/gpu/drm/drm_atomic.c | 6 +++ drivers/gpu/drm/drm_atomic_helper.c | 65 +++++++++++++++++++++++++---- drivers/gpu/drm/i915/intel_display.c | 13 +++--- include/drm/drm_atomic.h | 81 +++++++++++++++++++++++++++++++-- include/drm/drm_atomic_helper.h | 2 + 5 files changed, 149 insertions(+), 18 deletions(-)
diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index 6414bcf7f41b..1c1cbf436717 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -275,6 +275,8 @@ drm_atomic_get_crtc_state(struct drm_atomic_state *state, return ERR_PTR(-ENOMEM);
state->crtcs[index].state = crtc_state;
- state->crtcs[index].old_state = crtc->state;
- state->crtcs[index].new_state = crtc_state; state->crtcs[index].ptr = crtc; crtc_state->state = state;
@@ -691,6 +693,8 @@ drm_atomic_get_plane_state(struct drm_atomic_state *state,
state->planes[index].state = plane_state; state->planes[index].ptr = plane;
state->planes[index].old_state = plane->state;
state->planes[index].new_state = plane_state; plane_state->state = state;
DRM_DEBUG_ATOMIC("Added [PLANE:%d:%s] %p state to %p\n",
@@ -1031,6 +1035,8 @@ drm_atomic_get_connector_state(struct drm_atomic_state *state,
drm_connector_reference(connector); state->connectors[index].state = connector_state;
- state->connectors[index].old_state = connector->state;
- state->connectors[index].new_state = connector_state; state->connectors[index].ptr = connector; connector_state->state = state;
diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index b26e3419027e..d153e8a72921 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -1971,11 +1971,11 @@ void drm_atomic_helper_swap_state(struct drm_atomic_state *state, int i; long ret; struct drm_connector *connector;
- struct drm_connector_state *conn_state;
- struct drm_connector_state *conn_state, *old_conn_state; struct drm_crtc *crtc;
- struct drm_crtc_state *crtc_state;
- struct drm_crtc_state *crtc_state, *old_crtc_state; struct drm_plane *plane;
- struct drm_plane_state *plane_state;
struct drm_plane_state *plane_state, *old_plane_state; struct drm_crtc_commit *commit;
if (stall) {
@@ -1999,13 +1999,17 @@ void drm_atomic_helper_swap_state(struct drm_atomic_state *state, } }
- for_each_connector_in_state(state, connector, conn_state, i) {
- for_each_oldnew_connector_in_state(state, connector, old_conn_state,
conn_state, i) {
WARN_ON(connector->state != old_conn_state);
- connector->state->state = state; swap(state->connectors[i].state, connector->state); connector->state->state = NULL; }
- for_each_crtc_in_state(state, crtc, crtc_state, i) {
- for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, crtc_state,
i) {
WARN_ON(crtc->state != old_crtc_state);
- crtc->state->state = state; swap(state->crtcs[i].state, crtc->state); crtc->state->state = NULL;
@@ -2020,7 +2024,9 @@ void drm_atomic_helper_swap_state(struct drm_atomic_state *state, } }
- for_each_plane_in_state(state, plane, plane_state, i) {
- for_each_oldnew_plane_in_state(state, plane, old_plane_state,
plane_state, i) {
WARN_ON(plane->state != old_plane_state);
- plane->state->state = state; swap(state->planes[i].state, plane->state); plane->state->state = NULL;
@@ -2471,7 +2477,7 @@ EXPORT_SYMBOL(drm_atomic_helper_disable_all);
- See also:
- drm_atomic_helper_duplicate_state(), drm_atomic_helper_disable_all(),
- drm_atomic_helper_resume()
*/
- drm_atomic_helper_resume(), drm_atomic_helper_commit_duplicated_state()
struct drm_atomic_state *drm_atomic_helper_suspend(struct drm_device *dev) { @@ -2512,6 +2518,47 @@ struct drm_atomic_state *drm_atomic_helper_suspend(struct drm_device *dev) EXPORT_SYMBOL(drm_atomic_helper_suspend);
/**
- drm_atomic_helper_commit_duplicated_state - commit duplicated state
- @state: duplicated atomic state to commit
- @ctx: pointer to acquire_ctx to use for commit.
- The state returned by drm_atomic_helper_duplicate_state() and
- drm_atomic_helper_suspend() is partially invalid, and needs to
- be fixed up before commit.
Can't you fix the state in drm_atomic_helper_suspend() to avoid the need for this function ?
Apart from this the patch looks good to me. I don't like the fact that we now have two sets of states though (state and old_state/new_state). I understand that you'd like to address this as part of a separate patch series, which I'm fine with to avoid delaying this one, but I think we should address this sooner rather than latter, or the API will become very confusing. Yes, that means mass-patching drivers I'm afraid. Could you confirm that this is your plan ?
- Returns:
- 0 on success or a negative error code on failure.
- See also:
- drm_atomic_helper_suspend()
- */
+int drm_atomic_helper_commit_duplicated_state(struct drm_atomic_state *state,
struct drm_modeset_acquire_ctx
*ctx) +{
- int i;
- struct drm_plane *plane;
- struct drm_plane_state *plane_state;
- struct drm_connector *connector;
- struct drm_connector_state *conn_state;
- struct drm_crtc *crtc;
- struct drm_crtc_state *crtc_state;
- state->acquire_ctx = ctx;
- for_each_new_plane_in_state(state, plane, plane_state, i)
state->planes[i].old_state = plane->state;
- for_each_new_crtc_in_state(state, crtc, crtc_state, i)
state->crtcs[i].old_state = crtc->state;
- for_each_new_connector_in_state(state, connector, conn_state, i)
state->connectors[i].old_state = connector->state;
- return drm_atomic_commit(state);
+} +EXPORT_SYMBOL(drm_atomic_helper_commit_duplicated_state);
+/**
- drm_atomic_helper_resume - subsystem-level resume helper
- @dev: DRM device
- @state: atomic state to resume to
@@ -2534,9 +2581,9 @@ int drm_atomic_helper_resume(struct drm_device *dev, int err;
drm_mode_config_reset(dev);
- drm_modeset_lock_all(dev);
- state->acquire_ctx = config->acquire_ctx;
- err = drm_atomic_commit(state);
- err = drm_atomic_helper_commit_duplicated_state(state,
config->acquire_ctx); drm_modeset_unlock_all(dev);
return err; diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index f523256ef77c..74da1c380b32 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3488,7 +3488,8 @@ static void intel_update_primary_planes(struct drm_device *dev)
static int __intel_display_resume(struct drm_device *dev,
struct drm_atomic_state *state)
struct drm_atomic_state *state,
struct drm_modeset_acquire_ctx *ctx)
{ struct drm_crtc_state *crtc_state; struct drm_crtc *crtc; @@ -3512,7 +3513,7 @@ __intel_display_resume(struct drm_device *dev, /* ignore any reset values/BIOS leftovers in the WM registers */ to_intel_atomic_state(state)->skip_intermediate_wm = true;
- ret = drm_atomic_commit(state);
ret = drm_atomic_helper_commit_duplicated_state(state, ctx);
WARN_ON(ret == -EDEADLK); return ret;
@@ -3606,7 +3607,7 @@ void intel_finish_reset(struct drm_i915_private *dev_priv) */ intel_update_primary_planes(dev); } else {
ret = __intel_display_resume(dev, state);
ret = __intel_display_resume(dev, state, ctx); if (ret) DRM_ERROR("Restoring old state failed with
%i\n", ret);
}
@@ -3626,7 +3627,7 @@ void intel_finish_reset(struct drm_i915_private *dev_priv) dev_priv->display.hpd_irq_setup(dev_priv); spin_unlock_irq(&dev_priv->irq_lock);
ret = __intel_display_resume(dev, state);
if (ret) DRM_ERROR("Restoring old state failed with %i\n",ret = __intel_display_resume(dev, state, ctx);
ret);
@@ -11327,7 +11328,7 @@ void intel_release_load_detect_pipe(struct drm_connector *connector, if (!state) return;
- ret = drm_atomic_commit(state);
- ret = drm_atomic_helper_commit_duplicated_state(state, ctx); if (ret) DRM_DEBUG_KMS("Couldn't release load detect pipe: %i\n", ret); drm_atomic_state_put(state);
@@ -17210,7 +17211,7 @@ void intel_display_resume(struct drm_device *dev) }
if (!ret)
ret = __intel_display_resume(dev, state);
ret = __intel_display_resume(dev, state, &ctx);
drm_modeset_drop_locks(&ctx); drm_modeset_acquire_fini(&ctx);
diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h index f96220ed4004..6062e7f27325 100644 --- a/include/drm/drm_atomic.h +++ b/include/drm/drm_atomic.h @@ -137,12 +137,12 @@ struct drm_crtc_commit {
struct __drm_planes_state { struct drm_plane *ptr;
- struct drm_plane_state *state;
- struct drm_plane_state *state, *old_state, *new_state;
};
struct __drm_crtcs_state { struct drm_crtc *ptr;
- struct drm_crtc_state *state;
- struct drm_crtc_state *state, *old_state, *new_state; struct drm_crtc_commit *commit; s64 __user *out_fence_ptr; unsigned last_vblank_count;
@@ -150,7 +150,7 @@ struct __drm_crtcs_state {
struct __drm_connnectors_state { struct drm_connector *ptr;
- struct drm_connector_state *state;
- struct drm_connector_state *state, *old_state, *new_state;
};
/** @@ -397,6 +397,31 @@ void drm_state_dump(struct drm_device *dev, struct drm_printer *p); (__i)++)
\
for_each_if (connector)
+#define for_each_oldnew_connector_in_state(__state, connector, old_connector_state, new_connector_state, __i) \
- for ((__i) = 0;
\
(__i) < (__state)->num_connector &&
\
((connector) = (__state)->connectors[__i].ptr,
\
(old_connector_state) = (__state)->connectors[__i].old_state,
\
(new_connector_state) = (__state)->connectors[__i].new_state, 1);
\
(__i)++) \
for_each_if (connector)
+#define for_each_old_connector_in_state(__state, connector, old_connector_state, __i) \ + for ((__i) = 0;
\
(__i) < (__state)->num_connector &&
\
((connector) = (__state)->connectors[__i].ptr,
\
(old_connector_state) = (__state)->connectors[__i].old_state, 1);
\
(__i)++) \
for_each_if (connector)
+#define for_each_new_connector_in_state(__state, connector, new_connector_state, __i) \ + for ((__i) = 0;
\
(__i) < (__state)->num_connector &&
\
((connector) = (__state)->connectors[__i].ptr,
\
(new_connector_state) = (__state)->connectors[__i].new_state, 1);
\
(__i)++) \
for_each_if (connector)
#define for_each_crtc_in_state(__state, crtc, crtc_state, __i) \ for ((__i) = 0; \ (__i) < (__state)->dev->mode_config.num_crtc && \ @@ -405,6 +430,31 @@ void drm_state_dump(struct drm_device *dev, struct drm_printer *p); (__i)++) \ for_each_if (crtc_state)
+#define for_each_oldnew_crtc_in_state(__state, crtc, old_crtc_state, new_crtc_state, __i) \ + for ((__i) = 0;
\
(__i) < (__state)->dev->mode_config.num_crtc && \
((crtc) = (__state)->crtcs[__i].ptr, \
(old_crtc_state) = (__state)->crtcs[__i].old_state, \
(new_crtc_state) = (__state)->crtcs[__i].new_state, 1); \
(__i)++) \
for_each_if (crtc)
+#define for_each_old_crtc_in_state(__state, crtc, old_crtc_state, __i)
\
- for ((__i) = 0; \
(__i) < (__state)->dev->mode_config.num_crtc && \
((crtc) = (__state)->crtcs[__i].ptr, \
(old_crtc_state) = (__state)->crtcs[__i].old_state, 1); \
(__i)++) \
for_each_if (crtc)
+#define for_each_new_crtc_in_state(__state, crtc, new_crtc_state, __i)
\
- for ((__i) = 0; \
(__i) < (__state)->dev->mode_config.num_crtc && \
((crtc) = (__state)->crtcs[__i].ptr, \
(new_crtc_state) = (__state)->crtcs[__i].new_state, 1); \
(__i)++) \
for_each_if (crtc)
#define for_each_plane_in_state(__state, plane, plane_state, __i)
\
for ((__i) = 0; \ (__i) < (__state)->dev->mode_config.num_total_plane && \ @@ -413,6 +463,31 @@ void drm_state_dump(struct drm_device *dev, struct drm_printer *p); (__i)++)
\
for_each_if (plane_state)
+#define for_each_oldnew_plane_in_state(__state, plane, old_plane_state, new_plane_state, __i) \ + for ((__i) = 0;
\
(__i) < (__state)->dev->mode_config.num_total_plane && \
((plane) = (__state)->planes[__i].ptr, \
(old_plane_state) = (__state)->planes[__i].old_state, \
(new_plane_state) = (__state)->planes[__i].new_state, 1); \
(__i)++) \
for_each_if (plane)
+#define for_each_old_plane_in_state(__state, plane, old_plane_state, __i) \
- for ((__i) = 0; \
(__i) < (__state)->dev->mode_config.num_total_plane && \
((plane) = (__state)->planes[__i].ptr, \
(old_plane_state) = (__state)->planes[__i].old_state, 1); \
(__i)++) \
for_each_if (plane)
+#define for_each_new_plane_in_state(__state, plane, new_plane_state, __i) \
- for ((__i) = 0; \
(__i) < (__state)->dev->mode_config.num_total_plane && \
((plane) = (__state)->planes[__i].ptr, \
(new_plane_state) = (__state)->planes[__i].new_state, 1); \
(__i)++) \
for_each_if (plane)
/**
- drm_atomic_crtc_needs_modeset - compute combined modeset need
- @state: &drm_crtc_state for the CRTC
diff --git a/include/drm/drm_atomic_helper.h b/include/drm/drm_atomic_helper.h index 9afcd3810785..2c4549e98c16 100644 --- a/include/drm/drm_atomic_helper.h +++ b/include/drm/drm_atomic_helper.h @@ -105,6 +105,8 @@ int __drm_atomic_helper_set_config(struct drm_mode_set *set, int drm_atomic_helper_disable_all(struct drm_device *dev, struct drm_modeset_acquire_ctx *ctx); struct drm_atomic_state *drm_atomic_helper_suspend(struct drm_device *dev); +int drm_atomic_helper_commit_duplicated_state(struct drm_atomic_state *state,
struct drm_modeset_acquire_ctx
*ctx); int drm_atomic_helper_resume(struct drm_device *dev, struct drm_atomic_state *state);