[PATCH 2/3] drm/i915: Rework global state serializaiton

Lisovskiy, Stanislav stanislav.lisovskiy at intel.com
Thu Feb 1 08:48:11 UTC 2024


On Tue, Dec 19, 2023 at 03:07:55PM +0200, Ville Syrjala wrote:
> From: Ville Syrjälä <ville.syrjala at linux.intel.com>
> 
> Instead of injecting extra crtc commits to serialize the global
> state let's hand roll a but of commit machinery to take care of
> the hardware synchronization.
> 
> Rather than basing everything on the crtc commits we track these
> as their own thing. I think this makes more sense as the hardware
> blocks we are working with are not in any way tied to the pipes,
> so the completion should not be tied in with the vblank machinery
> either.
> 
> The difference to the old behaviour is that:
> - we no longer pull extra crtcs into the commit which should
>   make drm_atomic_check_only() happier
> - since those crtcs don't get pulled in we also don't end up
>   reprogamming them and thus don't need to wait their vblanks
>   to pass/etc. So this should be tad faster as well.
> 
> TODO: perhaps have each global object complete its own commit
> once the post-plane update phase is done?
> 
> Closes: https://gitlab.freedesktop.org/drm/intel/-/issues/6728
> Signed-off-by: Ville Syrjälä <ville.syrjala at linux.intel.com>

Reviewed-by: Stanislav Lisovskiy <stanislav.lisovskiy at intel.com>

> ---
>  drivers/gpu/drm/i915/display/intel_display.c  |  19 ++-
>  .../gpu/drm/i915/display/intel_global_state.c | 137 ++++++++++++++++--
>  .../gpu/drm/i915/display/intel_global_state.h |   9 +-
>  3 files changed, 152 insertions(+), 13 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c
> index b10aad15a63d..46eff0ee5519 100644
> --- a/drivers/gpu/drm/i915/display/intel_display.c
> +++ b/drivers/gpu/drm/i915/display/intel_display.c
> @@ -7068,6 +7068,7 @@ static void intel_atomic_commit_tail(struct intel_atomic_state *state)
>  
>  	drm_atomic_helper_wait_for_dependencies(&state->base);
>  	drm_dp_mst_atomic_wait_for_dependencies(&state->base);
> +	intel_atomic_global_state_wait_for_dependencies(state);
>  
>  	/*
>  	 * During full modesets we write a lot of registers, wait
> @@ -7244,6 +7245,7 @@ static void intel_atomic_commit_tail(struct intel_atomic_state *state)
>  	intel_pmdemand_post_plane_update(state);
>  
>  	drm_atomic_helper_commit_hw_done(&state->base);
> +	intel_atomic_global_state_commit_done(state);
>  
>  	if (state->modeset) {
>  		/* As one of the primary mmio accessors, KMS has a high
> @@ -7294,6 +7296,21 @@ static void intel_atomic_track_fbs(struct intel_atomic_state *state)
>  					plane->frontbuffer_bit);
>  }
>  
> +static int intel_atomic_setup_commit(struct intel_atomic_state *state, bool nonblock)
> +{
> +	int ret;
> +
> +	ret = drm_atomic_helper_setup_commit(&state->base, nonblock);
> +	if (ret)
> +		return ret;
> +
> +	ret = intel_atomic_global_state_setup_commit(state);
> +	if (ret)
> +		return ret;
> +
> +	return 0;
> +}
> +
>  int intel_atomic_commit(struct drm_device *dev, struct drm_atomic_state *_state,
>  			bool nonblock)
>  {
> @@ -7339,7 +7356,7 @@ int intel_atomic_commit(struct drm_device *dev, struct drm_atomic_state *_state,
>  		return ret;
>  	}
>  
> -	ret = drm_atomic_helper_setup_commit(&state->base, nonblock);
> +	ret = intel_atomic_setup_commit(state, nonblock);
>  	if (!ret)
>  		ret = drm_atomic_helper_swap_state(&state->base, true);
>  	if (!ret)
> diff --git a/drivers/gpu/drm/i915/display/intel_global_state.c b/drivers/gpu/drm/i915/display/intel_global_state.c
> index e8e8be54143b..cbcd1e91b7be 100644
> --- a/drivers/gpu/drm/i915/display/intel_global_state.c
> +++ b/drivers/gpu/drm/i915/display/intel_global_state.c
> @@ -10,12 +10,55 @@
>  #include "intel_display_types.h"
>  #include "intel_global_state.h"
>  
> +struct intel_global_commit {
> +	struct kref ref;
> +	struct completion done;
> +};
> +
> +static struct intel_global_commit *commit_new(void)
> +{
> +	struct intel_global_commit *commit;
> +
> +	commit = kzalloc(sizeof(*commit), GFP_KERNEL);
> +	if (!commit)
> +		return NULL;
> +
> +	init_completion(&commit->done);
> +	kref_init(&commit->ref);
> +
> +	return commit;
> +}
> +
> +static void __commit_free(struct kref *kref)
> +{
> +	struct intel_global_commit *commit =
> +		container_of(kref, typeof(*commit), ref);
> +
> +	kfree(commit);
> +}
> +
> +static struct intel_global_commit *commit_get(struct intel_global_commit *commit)
> +{
> +	if (commit)
> +		kref_get(&commit->ref);
> +
> +	return commit;
> +}
> +
> +static void commit_put(struct intel_global_commit *commit)
> +{
> +	if (commit)
> +		kref_put(&commit->ref, __commit_free);
> +}
> +
>  static void __intel_atomic_global_state_free(struct kref *kref)
>  {
>  	struct intel_global_state *obj_state =
>  		container_of(kref, struct intel_global_state, ref);
>  	struct intel_global_obj *obj = obj_state->obj;
>  
> +	commit_put(obj_state->commit);
> +
>  	obj->funcs->atomic_destroy_state(obj, obj_state);
>  }
>  
> @@ -127,6 +170,8 @@ intel_atomic_get_global_obj_state(struct intel_atomic_state *state,
>  
>  	obj_state->obj = obj;
>  	obj_state->changed = false;
> +	obj_state->serialized = false;
> +	obj_state->commit = NULL;
>  
>  	kref_init(&obj_state->ref);
>  
> @@ -239,19 +284,13 @@ int intel_atomic_lock_global_state(struct intel_global_state *obj_state)
>  
>  int intel_atomic_serialize_global_state(struct intel_global_state *obj_state)
>  {
> -	struct intel_atomic_state *state = obj_state->state;
> -	struct drm_i915_private *dev_priv = to_i915(state->base.dev);
> -	struct intel_crtc *crtc;
> +	int ret;
>  
> -	for_each_intel_crtc(&dev_priv->drm, crtc) {
> -		struct intel_crtc_state *crtc_state;
> +	ret = intel_atomic_lock_global_state(obj_state);
> +	if (ret)
> +		return ret;
>  
> -		crtc_state = intel_atomic_get_crtc_state(&state->base, crtc);
> -		if (IS_ERR(crtc_state))
> -			return PTR_ERR(crtc_state);
> -	}
> -
> -	obj_state->changed = true;
> +	obj_state->serialized = true;
>  
>  	return 0;
>  }
> @@ -267,3 +306,79 @@ intel_atomic_global_state_is_serialized(struct intel_atomic_state *state)
>  			return false;
>  	return true;
>  }
> +
> +int
> +intel_atomic_global_state_setup_commit(struct intel_atomic_state *state)
> +{
> +	const struct intel_global_state *old_obj_state;
> +	struct intel_global_state *new_obj_state;
> +	struct intel_global_obj *obj;
> +	int i;
> +
> +	for_each_oldnew_global_obj_in_state(state, obj, old_obj_state,
> +					    new_obj_state, i) {
> +		struct intel_global_commit *commit = NULL;
> +
> +		if (new_obj_state->serialized) {
> +			/*
> +			 * New commit which is going to be completed
> +			 * after the hardware reprogramming is done.
> +			 */
> +			commit = commit_new();
> +			if (!commit)
> +				return -ENOMEM;
> +		} else if (new_obj_state->changed) {
> +			/*
> +			 * We're going to swap to this state, so carry the
> +			 * previous commit along, in case it's not yet done.
> +			 */
> +			commit = commit_get(old_obj_state->commit);
> +		}
> +
> +		new_obj_state->commit = commit;
> +	}
> +
> +	return 0;
> +}
> +
> +int
> +intel_atomic_global_state_wait_for_dependencies(struct intel_atomic_state *state)
> +{
> +	struct drm_i915_private *i915 = to_i915(state->base.dev);
> +	const struct intel_global_state *old_obj_state;
> +	struct intel_global_obj *obj;
> +	int i;
> +
> +	for_each_old_global_obj_in_state(state, obj, old_obj_state, i) {
> +		struct intel_global_commit *commit = old_obj_state->commit;
> +		long ret;
> +
> +		if (!commit)
> +			continue;
> +
> +		ret = wait_for_completion_timeout(&commit->done, 10 * HZ);
> +		if (ret == 0) {
> +			drm_err(&i915->drm, "global state timed out\n");
> +			return -ETIMEDOUT;
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +void
> +intel_atomic_global_state_commit_done(struct intel_atomic_state *state)
> +{
> +	const struct intel_global_state *new_obj_state;
> +	struct intel_global_obj *obj;
> +	int i;
> +
> +	for_each_new_global_obj_in_state(state, obj, new_obj_state, i) {
> +		struct intel_global_commit *commit = new_obj_state->commit;
> +
> +		if (!new_obj_state->serialized)
> +			continue;
> +
> +		complete_all(&commit->done);
> +	}
> +}
> diff --git a/drivers/gpu/drm/i915/display/intel_global_state.h b/drivers/gpu/drm/i915/display/intel_global_state.h
> index 5477de8f0b30..5c8545d7a76a 100644
> --- a/drivers/gpu/drm/i915/display/intel_global_state.h
> +++ b/drivers/gpu/drm/i915/display/intel_global_state.h
> @@ -54,11 +54,14 @@ struct intel_global_obj {
>  	     (__i)++) \
>  		for_each_if(obj)
>  
> +struct intel_global_commit;
> +
>  struct intel_global_state {
>  	struct intel_global_obj *obj;
>  	struct intel_atomic_state *state;
> +	struct intel_global_commit *commit;
>  	struct kref ref;
> -	bool changed;
> +	bool changed, serialized;
>  };
>  
>  struct __intel_global_objs_state {
> @@ -87,6 +90,10 @@ void intel_atomic_clear_global_state(struct intel_atomic_state *state);
>  int intel_atomic_lock_global_state(struct intel_global_state *obj_state);
>  int intel_atomic_serialize_global_state(struct intel_global_state *obj_state);
>  
> +int intel_atomic_global_state_setup_commit(struct intel_atomic_state *state);
> +void intel_atomic_global_state_commit_done(struct intel_atomic_state *state);
> +int intel_atomic_global_state_wait_for_dependencies(struct intel_atomic_state *state);
> +
>  bool intel_atomic_global_state_is_serialized(struct intel_atomic_state *state);
>  
>  #endif
> -- 
> 2.41.0
> 


More information about the Intel-gfx mailing list