diff mbox series

[2/3] drm/i915/display: Add infra to reduce global state funcs boilerplate

Message ID 20241219214909.104869-3-gustavo.sousa@intel.com (mailing list archive)
State New
Headers show
Series drm/i915/display: Reduce global state funcs boilerplate | expand

Commit Message

Gustavo Sousa Dec. 19, 2024, 9:48 p.m. UTC
If we look at how the members of struct intel_global_state_funcs, we see
a common pattern repeating itself. Let's add the necessary
infra-structure to allow reducing the boilerplate. We do that by
adding common generic implementations for each member and adding a macro
INTEL_GLOBAL_STATE_DEFAULTS() to be used when initializing an instance
of struct intel_global_state_funcs.

That way, a global state that does not need custom behavior can have
its funcs structure be initialized as in the following example,

    static const struct intel_global_state_funcs <prefix>_funcs = {
           INTEL_GLOBAL_STATE_DEFAULTS(struct <prefix>_state, <base_member_name>),
    };

, without the need to implementing the functions.

That doesn't come without cost - we will need to store two size_t
members -, but that cost is arguably justified by the simplification
gained.

In an upcoming change we will put that infra into action on existing
users.

Signed-off-by: Gustavo Sousa <gustavo.sousa@intel.com>
---
 .../gpu/drm/i915/display/intel_global_state.c | 41 ++++++++++++++++++-
 .../gpu/drm/i915/display/intel_global_state.h | 15 +++++++
 2 files changed, 54 insertions(+), 2 deletions(-)

Comments

Cavitt, Jonathan Dec. 19, 2024, 10:44 p.m. UTC | #1
-----Original Message-----
From: Intel-gfx <intel-gfx-bounces@lists.freedesktop.org> On Behalf Of Gustavo Sousa
Sent: Thursday, December 19, 2024 1:49 PM
To: intel-gfx@lists.freedesktop.org; intel-xe@lists.freedesktop.org
Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>; Nikula, Jani <jani.nikula@intel.com>
Subject: [PATCH 2/3] drm/i915/display: Add infra to reduce global state funcs boilerplate
> 
> If we look at how the members of struct intel_global_state_funcs, we see
> a common pattern repeating itself. Let's add the necessary
> infra-structure to allow reducing the boilerplate. We do that by
> adding common generic implementations for each member and adding a macro
> INTEL_GLOBAL_STATE_DEFAULTS() to be used when initializing an instance
> of struct intel_global_state_funcs.
> 
> That way, a global state that does not need custom behavior can have
> its funcs structure be initialized as in the following example,
> 
>     static const struct intel_global_state_funcs <prefix>_funcs = {
>            INTEL_GLOBAL_STATE_DEFAULTS(struct <prefix>_state, <base_member_name>),
>     };
> 
> , without the need to implementing the functions.
> 
> That doesn't come without cost - we will need to store two size_t
> members -, but that cost is arguably justified by the simplification
> gained.
> 
> In an upcoming change we will put that infra into action on existing
> users.
> 
> Signed-off-by: Gustavo Sousa <gustavo.sousa@intel.com>
> ---
>  .../gpu/drm/i915/display/intel_global_state.c | 41 ++++++++++++++++++-
>  .../gpu/drm/i915/display/intel_global_state.h | 15 +++++++
>  2 files changed, 54 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/display/intel_global_state.c b/drivers/gpu/drm/i915/display/intel_global_state.c
> index cbcd1e91b7be..4b4c33fa99fb 100644
> --- a/drivers/gpu/drm/i915/display/intel_global_state.c
> +++ b/drivers/gpu/drm/i915/display/intel_global_state.c
> @@ -59,7 +59,10 @@ static void __intel_atomic_global_state_free(struct kref *kref)
>  
>  	commit_put(obj_state->commit);
>  
> -	obj->funcs->atomic_destroy_state(obj, obj_state);
> +	if (obj->funcs->atomic_destroy_state)

This is good, though I think it's standard practice as a part of
these kinds of sanity checks to assert that the functions pointer
also exists before attempting to dereference into a function itself.

Or, in simpler terms, I think we want to check obj->funcs here,
in addition to the atomic_destroy_state:
"""
	If (obj->funcs && obj->funcs->atomic_destroy_state)
"""
Though maybe obj->funcs has some guarantee associated with
it that ensures it always exists, making this sanity check unnecessary?
Much like the guarantee obj exists?  I'm not familiar enough with the
display driver one way or the other to make that declaration, so I
won't block on this.

> +		obj->funcs->atomic_destroy_state(obj, obj_state);
> +	else
> +		intel_atomic_global_destroy_state_common(obj, obj_state);
>  }
>  
>  static void intel_atomic_global_state_put(struct intel_global_state *obj_state)
> @@ -164,7 +167,11 @@ intel_atomic_get_global_obj_state(struct intel_atomic_state *state,
>  	index = state->num_global_objs;
>  	memset(&state->global_objs[index], 0, sizeof(*state->global_objs));
>  
> -	obj_state = obj->funcs->atomic_duplicate_state(obj);
> +	if (obj->funcs->atomic_duplicate_state)

Same comment as above, except with atomic_duplicate_state
instead of atomic_destroy_state.

> +		obj_state = obj->funcs->atomic_duplicate_state(obj);
> +	else
> +		obj_state = intel_atomic_global_duplicate_state_common(obj);
> +
>  	if (!obj_state)
>  		return ERR_PTR(-ENOMEM);
>  
> @@ -382,3 +389,33 @@ intel_atomic_global_state_commit_done(struct intel_atomic_state *state)
>  		complete_all(&commit->done);
>  	}
>  }
> +
> +struct intel_global_state *
> +intel_atomic_global_duplicate_state_common(struct intel_global_obj *obj)

I personally prefer these kinds of functions to be defined before their
first usage when possible, as it mirrors how we need to define static
functions before their first uses.  However, I recognize that because
this function is defined in intel_global_state.h, it's not necessary to
maintain that kind of function ordering and, in fact, it's more
important to maintain function ordering parity with the header
file.  So I'll leave that kind of change to your discretion.

> +{
> +	void *state_wrapper;
> +
> +	if (WARN_ON(obj->funcs->state_size == 0))
> +		return NULL;
> +
> +	state_wrapper = (void *)obj->state - obj->funcs->base_offset;
> +
> +	state_wrapper = kmemdup(state_wrapper, obj->funcs->state_size, GFP_KERNEL);
> +	if (!state_wrapper)
> +		return NULL;
> +
> +	return state_wrapper + obj->funcs->base_offset;
> +}
> +
> +void intel_atomic_global_destroy_state_common(struct intel_global_obj *obj,
> +					      struct intel_global_state *state)
> +{
> +	void *state_wrapper;
> +
> +	if (WARN_ON(obj->funcs->state_size == 0))
> +		return;
> +
> +	state_wrapper = (void *)state - obj->funcs->base_offset;
> +
> +	kfree(state_wrapper);
> +}
> diff --git a/drivers/gpu/drm/i915/display/intel_global_state.h b/drivers/gpu/drm/i915/display/intel_global_state.h
> index 6506a8e32972..e47e007225cc 100644
> --- a/drivers/gpu/drm/i915/display/intel_global_state.h
> +++ b/drivers/gpu/drm/i915/display/intel_global_state.h
> @@ -8,6 +8,8 @@
>  
>  #include <linux/kref.h>
>  #include <linux/list.h>
> +#include <linux/stddef.h>
> +#include <linux/types.h>
>  
>  struct drm_i915_private;
>  struct intel_atomic_state;
> @@ -15,6 +17,10 @@ struct intel_global_obj;
>  struct intel_global_state;
>  
>  struct intel_global_state_funcs {
> +	/* state_size and base_offset are initialized by INTEL_GLOBAL_STATE_DEFAULTS() */
> +	size_t state_size;
> +	size_t base_offset;
> +
>  	struct intel_global_state *(*atomic_duplicate_state)(struct intel_global_obj *obj);
>  	void (*atomic_destroy_state)(struct intel_global_obj *obj,
>  				     struct intel_global_state *state);
> @@ -26,6 +32,10 @@ struct intel_global_obj {
>  	const struct intel_global_state_funcs *funcs;
>  };
>  
> +#define INTEL_GLOBAL_STATE_DEFAULTS(type, base_member) \
> +	.state_size = sizeof(type), \
> +	.base_offset = offsetof(type, base_member)
> +
>  #define intel_for_each_global_obj(obj, dev_priv) \
>  	list_for_each_entry(obj, &(dev_priv)->display.global.obj_list, head)
>  
> @@ -96,4 +106,9 @@ int intel_atomic_global_state_wait_for_dependencies(struct intel_atomic_state *s
>  
>  bool intel_atomic_global_state_is_serialized(struct intel_atomic_state *state);
>  
> +struct intel_global_state *
> +intel_atomic_global_duplicate_state_common(struct intel_global_obj *obj);
> +void intel_atomic_global_destroy_state_common(struct intel_global_obj *obj,
> +					      struct intel_global_state *state);
> +

I have no major complaints.  Just some notes above.
Reviewed-by: Jonathan Cavitt <jonathan.cavitt@intel.com>
-Jonathan Cavitt

>  #endif
> -- 
> 2.47.1
> 
>
Jani Nikula Dec. 20, 2024, 8:50 a.m. UTC | #2
On Thu, 19 Dec 2024, Gustavo Sousa <gustavo.sousa@intel.com> wrote:
> If we look at how the members of struct intel_global_state_funcs, we see
> a common pattern repeating itself. Let's add the necessary
> infra-structure to allow reducing the boilerplate. We do that by
> adding common generic implementations for each member and adding a macro
> INTEL_GLOBAL_STATE_DEFAULTS() to be used when initializing an instance
> of struct intel_global_state_funcs.
>
> That way, a global state that does not need custom behavior can have
> its funcs structure be initialized as in the following example,
>
>     static const struct intel_global_state_funcs <prefix>_funcs = {
>            INTEL_GLOBAL_STATE_DEFAULTS(struct <prefix>_state, <base_member_name>),
>     };
>
> , without the need to implementing the functions.
>
> That doesn't come without cost - we will need to store two size_t
> members -, but that cost is arguably justified by the simplification
> gained.
>
> In an upcoming change we will put that infra into action on existing
> users.
>
> Signed-off-by: Gustavo Sousa <gustavo.sousa@intel.com>
> ---
>  .../gpu/drm/i915/display/intel_global_state.c | 41 ++++++++++++++++++-
>  .../gpu/drm/i915/display/intel_global_state.h | 15 +++++++
>  2 files changed, 54 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/gpu/drm/i915/display/intel_global_state.c b/drivers/gpu/drm/i915/display/intel_global_state.c
> index cbcd1e91b7be..4b4c33fa99fb 100644
> --- a/drivers/gpu/drm/i915/display/intel_global_state.c
> +++ b/drivers/gpu/drm/i915/display/intel_global_state.c
> @@ -59,7 +59,10 @@ static void __intel_atomic_global_state_free(struct kref *kref)
>  
>  	commit_put(obj_state->commit);
>  
> -	obj->funcs->atomic_destroy_state(obj, obj_state);
> +	if (obj->funcs->atomic_destroy_state)
> +		obj->funcs->atomic_destroy_state(obj, obj_state);
> +	else
> +		intel_atomic_global_destroy_state_common(obj, obj_state);
>  }
>  
>  static void intel_atomic_global_state_put(struct intel_global_state *obj_state)
> @@ -164,7 +167,11 @@ intel_atomic_get_global_obj_state(struct intel_atomic_state *state,
>  	index = state->num_global_objs;
>  	memset(&state->global_objs[index], 0, sizeof(*state->global_objs));
>  
> -	obj_state = obj->funcs->atomic_duplicate_state(obj);
> +	if (obj->funcs->atomic_duplicate_state)
> +		obj_state = obj->funcs->atomic_duplicate_state(obj);
> +	else
> +		obj_state = intel_atomic_global_duplicate_state_common(obj);
> +
>  	if (!obj_state)
>  		return ERR_PTR(-ENOMEM);
>  
> @@ -382,3 +389,33 @@ intel_atomic_global_state_commit_done(struct intel_atomic_state *state)
>  		complete_all(&commit->done);
>  	}
>  }
> +
> +struct intel_global_state *
> +intel_atomic_global_duplicate_state_common(struct intel_global_obj *obj)
> +{
> +	void *state_wrapper;
> +
> +	if (WARN_ON(obj->funcs->state_size == 0))
> +		return NULL;
> +
> +	state_wrapper = (void *)obj->state - obj->funcs->base_offset;
> +
> +	state_wrapper = kmemdup(state_wrapper, obj->funcs->state_size, GFP_KERNEL);
> +	if (!state_wrapper)
> +		return NULL;
> +
> +	return state_wrapper + obj->funcs->base_offset;
> +}
> +
> +void intel_atomic_global_destroy_state_common(struct intel_global_obj *obj,
> +					      struct intel_global_state *state)
> +{
> +	void *state_wrapper;
> +
> +	if (WARN_ON(obj->funcs->state_size == 0))
> +		return;
> +
> +	state_wrapper = (void *)state - obj->funcs->base_offset;
> +
> +	kfree(state_wrapper);
> +}
> diff --git a/drivers/gpu/drm/i915/display/intel_global_state.h b/drivers/gpu/drm/i915/display/intel_global_state.h
> index 6506a8e32972..e47e007225cc 100644
> --- a/drivers/gpu/drm/i915/display/intel_global_state.h
> +++ b/drivers/gpu/drm/i915/display/intel_global_state.h
> @@ -8,6 +8,8 @@
>  
>  #include <linux/kref.h>
>  #include <linux/list.h>
> +#include <linux/stddef.h>
> +#include <linux/types.h>
>  
>  struct drm_i915_private;
>  struct intel_atomic_state;
> @@ -15,6 +17,10 @@ struct intel_global_obj;
>  struct intel_global_state;
>  
>  struct intel_global_state_funcs {
> +	/* state_size and base_offset are initialized by INTEL_GLOBAL_STATE_DEFAULTS() */
> +	size_t state_size;
> +	size_t base_offset;
> +

Gut feeling says these should be part of struct intel_global_state
rather than struct intel_global_state_funcs. Keyword being "funcs".

They would have to be passed to intel_atomic_global_obj_init() and
initialized runtime. That's a downside. But then you could do away with
the funcs struct altogether when defaults are used, and pass NULL.

And you could also drop INTEL_GLOBAL_STATE_DEFAULTS() which I don't find
particularly pretty.

BR,
Jani.

>  	struct intel_global_state *(*atomic_duplicate_state)(struct intel_global_obj *obj);
>  	void (*atomic_destroy_state)(struct intel_global_obj *obj,
>  				     struct intel_global_state *state);
> @@ -26,6 +32,10 @@ struct intel_global_obj {
>  	const struct intel_global_state_funcs *funcs;
>  };
>  
> +#define INTEL_GLOBAL_STATE_DEFAULTS(type, base_member) \
> +	.state_size = sizeof(type), \
> +	.base_offset = offsetof(type, base_member)
> +
>  #define intel_for_each_global_obj(obj, dev_priv) \
>  	list_for_each_entry(obj, &(dev_priv)->display.global.obj_list, head)
>  
> @@ -96,4 +106,9 @@ int intel_atomic_global_state_wait_for_dependencies(struct intel_atomic_state *s
>  
>  bool intel_atomic_global_state_is_serialized(struct intel_atomic_state *state);
>  
> +struct intel_global_state *
> +intel_atomic_global_duplicate_state_common(struct intel_global_obj *obj);
> +void intel_atomic_global_destroy_state_common(struct intel_global_obj *obj,
> +					      struct intel_global_state *state);
> +
>  #endif
Jani Nikula Dec. 20, 2024, 8:51 a.m. UTC | #3
On Thu, 19 Dec 2024, Gustavo Sousa <gustavo.sousa@intel.com> wrote:
> diff --git a/drivers/gpu/drm/i915/display/intel_global_state.h b/drivers/gpu/drm/i915/display/intel_global_state.h
> index 6506a8e32972..e47e007225cc 100644
> --- a/drivers/gpu/drm/i915/display/intel_global_state.h
> +++ b/drivers/gpu/drm/i915/display/intel_global_state.h
> @@ -8,6 +8,8 @@
>  
>  #include <linux/kref.h>
>  #include <linux/list.h>
> +#include <linux/stddef.h>

What do you need this for?

> +#include <linux/types.h>
>  
>  struct drm_i915_private;
>  struct intel_atomic_state;
> @@ -15,6 +17,10 @@ struct intel_global_obj;
>  struct intel_global_state;
>  
>  struct intel_global_state_funcs {
> +	/* state_size and base_offset are initialized by INTEL_GLOBAL_STATE_DEFAULTS() */
> +	size_t state_size;
> +	size_t base_offset;
> +
>  	struct intel_global_state *(*atomic_duplicate_state)(struct intel_global_obj *obj);
>  	void (*atomic_destroy_state)(struct intel_global_obj *obj,
>  				     struct intel_global_state *state);
> @@ -26,6 +32,10 @@ struct intel_global_obj {
>  	const struct intel_global_state_funcs *funcs;
>  };
>  
> +#define INTEL_GLOBAL_STATE_DEFAULTS(type, base_member) \
> +	.state_size = sizeof(type), \
> +	.base_offset = offsetof(type, base_member)
> +
>  #define intel_for_each_global_obj(obj, dev_priv) \
>  	list_for_each_entry(obj, &(dev_priv)->display.global.obj_list, head)
>  
> @@ -96,4 +106,9 @@ int intel_atomic_global_state_wait_for_dependencies(struct intel_atomic_state *s
>  
>  bool intel_atomic_global_state_is_serialized(struct intel_atomic_state *state);
>  
> +struct intel_global_state *
> +intel_atomic_global_duplicate_state_common(struct intel_global_obj *obj);
> +void intel_atomic_global_destroy_state_common(struct intel_global_obj *obj,
> +					      struct intel_global_state *state);
> +
>  #endif
Ville Syrjälä Dec. 20, 2024, 9:23 a.m. UTC | #4
On Thu, Dec 19, 2024 at 06:48:37PM -0300, Gustavo Sousa wrote:
> If we look at how the members of struct intel_global_state_funcs, we see
> a common pattern repeating itself. Let's add the necessary
> infra-structure to allow reducing the boilerplate. We do that by
> adding common generic implementations for each member and adding a macro
> INTEL_GLOBAL_STATE_DEFAULTS() to be used when initializing an instance
> of struct intel_global_state_funcs.
> 
> That way, a global state that does not need custom behavior can have
> its funcs structure be initialized as in the following example,
> 
>     static const struct intel_global_state_funcs <prefix>_funcs = {
>            INTEL_GLOBAL_STATE_DEFAULTS(struct <prefix>_state, <base_member_name>),
>     };
> 
> , without the need to implementing the functions.
> 
> That doesn't come without cost - we will need to store two size_t
> members -, but that cost is arguably justified by the simplification
> gained.
> 
> In an upcoming change we will put that infra into action on existing
> users.
> 
> Signed-off-by: Gustavo Sousa <gustavo.sousa@intel.com>
> ---
>  .../gpu/drm/i915/display/intel_global_state.c | 41 ++++++++++++++++++-
>  .../gpu/drm/i915/display/intel_global_state.h | 15 +++++++
>  2 files changed, 54 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/display/intel_global_state.c b/drivers/gpu/drm/i915/display/intel_global_state.c
> index cbcd1e91b7be..4b4c33fa99fb 100644
> --- a/drivers/gpu/drm/i915/display/intel_global_state.c
> +++ b/drivers/gpu/drm/i915/display/intel_global_state.c
> @@ -59,7 +59,10 @@ static void __intel_atomic_global_state_free(struct kref *kref)
>  
>  	commit_put(obj_state->commit);
>  
> -	obj->funcs->atomic_destroy_state(obj, obj_state);
> +	if (obj->funcs->atomic_destroy_state)
> +		obj->funcs->atomic_destroy_state(obj, obj_state);
> +	else
> +		intel_atomic_global_destroy_state_common(obj, obj_state);
>  }
>  
>  static void intel_atomic_global_state_put(struct intel_global_state *obj_state)
> @@ -164,7 +167,11 @@ intel_atomic_get_global_obj_state(struct intel_atomic_state *state,
>  	index = state->num_global_objs;
>  	memset(&state->global_objs[index], 0, sizeof(*state->global_objs));
>  
> -	obj_state = obj->funcs->atomic_duplicate_state(obj);
> +	if (obj->funcs->atomic_duplicate_state)
> +		obj_state = obj->funcs->atomic_duplicate_state(obj);
> +	else
> +		obj_state = intel_atomic_global_duplicate_state_common(obj);
> +
>  	if (!obj_state)
>  		return ERR_PTR(-ENOMEM);
>  
> @@ -382,3 +389,33 @@ intel_atomic_global_state_commit_done(struct intel_atomic_state *state)
>  		complete_all(&commit->done);
>  	}
>  }
> +
> +struct intel_global_state *
> +intel_atomic_global_duplicate_state_common(struct intel_global_obj *obj)
> +{
> +	void *state_wrapper;
> +
> +	if (WARN_ON(obj->funcs->state_size == 0))
> +		return NULL;
> +
> +	state_wrapper = (void *)obj->state - obj->funcs->base_offset;
> +
> +	state_wrapper = kmemdup(state_wrapper, obj->funcs->state_size, GFP_KERNEL);
> +	if (!state_wrapper)
> +		return NULL;
> +
> +	return state_wrapper + obj->funcs->base_offset;

I'm not really a fan. What was obvious code before now looks 
complicated.

Also this no longer matches how any of the standard kms object
types work, which I don't think is a good idea. IMO if we
want to do something like this then it should probably try to
cover all kms object types.

> +}
> +
> +void intel_atomic_global_destroy_state_common(struct intel_global_obj *obj,
> +					      struct intel_global_state *state)
> +{
> +	void *state_wrapper;
> +
> +	if (WARN_ON(obj->funcs->state_size == 0))
> +		return;
> +
> +	state_wrapper = (void *)state - obj->funcs->base_offset;
> +
> +	kfree(state_wrapper);
> +}
> diff --git a/drivers/gpu/drm/i915/display/intel_global_state.h b/drivers/gpu/drm/i915/display/intel_global_state.h
> index 6506a8e32972..e47e007225cc 100644
> --- a/drivers/gpu/drm/i915/display/intel_global_state.h
> +++ b/drivers/gpu/drm/i915/display/intel_global_state.h
> @@ -8,6 +8,8 @@
>  
>  #include <linux/kref.h>
>  #include <linux/list.h>
> +#include <linux/stddef.h>
> +#include <linux/types.h>
>  
>  struct drm_i915_private;
>  struct intel_atomic_state;
> @@ -15,6 +17,10 @@ struct intel_global_obj;
>  struct intel_global_state;
>  
>  struct intel_global_state_funcs {
> +	/* state_size and base_offset are initialized by INTEL_GLOBAL_STATE_DEFAULTS() */
> +	size_t state_size;
> +	size_t base_offset;
> +
>  	struct intel_global_state *(*atomic_duplicate_state)(struct intel_global_obj *obj);
>  	void (*atomic_destroy_state)(struct intel_global_obj *obj,
>  				     struct intel_global_state *state);
> @@ -26,6 +32,10 @@ struct intel_global_obj {
>  	const struct intel_global_state_funcs *funcs;
>  };
>  
> +#define INTEL_GLOBAL_STATE_DEFAULTS(type, base_member) \
> +	.state_size = sizeof(type), \
> +	.base_offset = offsetof(type, base_member)
> +
>  #define intel_for_each_global_obj(obj, dev_priv) \
>  	list_for_each_entry(obj, &(dev_priv)->display.global.obj_list, head)
>  
> @@ -96,4 +106,9 @@ int intel_atomic_global_state_wait_for_dependencies(struct intel_atomic_state *s
>  
>  bool intel_atomic_global_state_is_serialized(struct intel_atomic_state *state);
>  
> +struct intel_global_state *
> +intel_atomic_global_duplicate_state_common(struct intel_global_obj *obj);
> +void intel_atomic_global_destroy_state_common(struct intel_global_obj *obj,
> +					      struct intel_global_state *state);
> +
>  #endif
> -- 
> 2.47.1
Gustavo Sousa Dec. 20, 2024, 1:43 p.m. UTC | #5
Quoting Cavitt, Jonathan (2024-12-19 19:44:12-03:00)
>-----Original Message-----
>From: Intel-gfx <intel-gfx-bounces@lists.freedesktop.org> On Behalf Of Gustavo Sousa
>Sent: Thursday, December 19, 2024 1:49 PM
>To: intel-gfx@lists.freedesktop.org; intel-xe@lists.freedesktop.org
>Cc: Ville Syrj�l� <ville.syrjala@linux.intel.com>; Nikula, Jani <jani.nikula@intel.com>
>Subject: [PATCH 2/3] drm/i915/display: Add infra to reduce global state funcs boilerplate
>> 
>> If we look at how the members of struct intel_global_state_funcs, we see
>> a common pattern repeating itself. Let's add the necessary
>> infra-structure to allow reducing the boilerplate. We do that by
>> adding common generic implementations for each member and adding a macro
>> INTEL_GLOBAL_STATE_DEFAULTS() to be used when initializing an instance
>> of struct intel_global_state_funcs.
>> 
>> That way, a global state that does not need custom behavior can have
>> its funcs structure be initialized as in the following example,
>> 
>>     static const struct intel_global_state_funcs <prefix>_funcs = {
>>            INTEL_GLOBAL_STATE_DEFAULTS(struct <prefix>_state, <base_member_name>),
>>     };
>> 
>> , without the need to implementing the functions.
>> 
>> That doesn't come without cost - we will need to store two size_t
>> members -, but that cost is arguably justified by the simplification
>> gained.
>> 
>> In an upcoming change we will put that infra into action on existing
>> users.
>> 
>> Signed-off-by: Gustavo Sousa <gustavo.sousa@intel.com>
>> ---
>>  .../gpu/drm/i915/display/intel_global_state.c | 41 ++++++++++++++++++-
>>  .../gpu/drm/i915/display/intel_global_state.h | 15 +++++++
>>  2 files changed, 54 insertions(+), 2 deletions(-)
>> 
>> diff --git a/drivers/gpu/drm/i915/display/intel_global_state.c b/drivers/gpu/drm/i915/display/intel_global_state.c
>> index cbcd1e91b7be..4b4c33fa99fb 100644
>> --- a/drivers/gpu/drm/i915/display/intel_global_state.c
>> +++ b/drivers/gpu/drm/i915/display/intel_global_state.c
>> @@ -59,7 +59,10 @@ static void __intel_atomic_global_state_free(struct kref *kref)
>>  
>>          commit_put(obj_state->commit);
>>  
>> -        obj->funcs->atomic_destroy_state(obj, obj_state);
>> +        if (obj->funcs->atomic_destroy_state)
>
>This is good, though I think it's standard practice as a part of
>these kinds of sanity checks to assert that the functions pointer
>also exists before attempting to dereference into a function itself.
>
>Or, in simpler terms, I think we want to check obj->funcs here,
>in addition to the atomic_destroy_state:
>"""
>        If (obj->funcs && obj->funcs->atomic_destroy_state)
>"""
>Though maybe obj->funcs has some guarantee associated with
>it that ensures it always exists, making this sanity check unnecessary?
>Much like the guarantee obj exists?  I'm not familiar enough with the
>display driver one way or the other to make that declaration, so I
>won't block on this.

It is a bug obj->funcs to be NULL. The funcs member is initialized
with intel_atomic_global_obj_init(), which must be called for every
tracked global object.

Furthermore, checking (obj->funcs && obj->funcs->atomic_destroy_state)
would be problematic because
intel_atomic_global_duplicate_state_common() relies on obj->funcs being
a valid pointer (as does all of the global state logic).

--
Gustavo Sousa

>
>> +                obj->funcs->atomic_destroy_state(obj, obj_state);
>> +        else
>> +                intel_atomic_global_destroy_state_common(obj, obj_state);
>>  }
>>  
>>  static void intel_atomic_global_state_put(struct intel_global_state *obj_state)
>> @@ -164,7 +167,11 @@ intel_atomic_get_global_obj_state(struct intel_atomic_state *state,
>>          index = state->num_global_objs;
>>          memset(&state->global_objs[index], 0, sizeof(*state->global_objs));
>>  
>> -        obj_state = obj->funcs->atomic_duplicate_state(obj);
>> +        if (obj->funcs->atomic_duplicate_state)
>
>Same comment as above, except with atomic_duplicate_state
>instead of atomic_destroy_state.
>
>> +                obj_state = obj->funcs->atomic_duplicate_state(obj);
>> +        else
>> +                obj_state = intel_atomic_global_duplicate_state_common(obj);
>> +
>>          if (!obj_state)
>>                  return ERR_PTR(-ENOMEM);
>>  
>> @@ -382,3 +389,33 @@ intel_atomic_global_state_commit_done(struct intel_atomic_state *state)
>>                  complete_all(&commit->done);
>>          }
>>  }
>> +
>> +struct intel_global_state *
>> +intel_atomic_global_duplicate_state_common(struct intel_global_obj *obj)
>
>I personally prefer these kinds of functions to be defined before their
>first usage when possible, as it mirrors how we need to define static
>functions before their first uses.  However, I recognize that because
>this function is defined in intel_global_state.h, it's not necessary to
>maintain that kind of function ordering and, in fact, it's more
>important to maintain function ordering parity with the header
>file.  So I'll leave that kind of change to your discretion.
>
>> +{
>> +        void *state_wrapper;
>> +
>> +        if (WARN_ON(obj->funcs->state_size == 0))
>> +                return NULL;
>> +
>> +        state_wrapper = (void *)obj->state - obj->funcs->base_offset;
>> +
>> +        state_wrapper = kmemdup(state_wrapper, obj->funcs->state_size, GFP_KERNEL);
>> +        if (!state_wrapper)
>> +                return NULL;
>> +
>> +        return state_wrapper + obj->funcs->base_offset;
>> +}
>> +
>> +void intel_atomic_global_destroy_state_common(struct intel_global_obj *obj,
>> +                                              struct intel_global_state *state)
>> +{
>> +        void *state_wrapper;
>> +
>> +        if (WARN_ON(obj->funcs->state_size == 0))
>> +                return;
>> +
>> +        state_wrapper = (void *)state - obj->funcs->base_offset;
>> +
>> +        kfree(state_wrapper);
>> +}
>> diff --git a/drivers/gpu/drm/i915/display/intel_global_state.h b/drivers/gpu/drm/i915/display/intel_global_state.h
>> index 6506a8e32972..e47e007225cc 100644
>> --- a/drivers/gpu/drm/i915/display/intel_global_state.h
>> +++ b/drivers/gpu/drm/i915/display/intel_global_state.h
>> @@ -8,6 +8,8 @@
>>  
>>  #include <linux/kref.h>
>>  #include <linux/list.h>
>> +#include <linux/stddef.h>
>> +#include <linux/types.h>
>>  
>>  struct drm_i915_private;
>>  struct intel_atomic_state;
>> @@ -15,6 +17,10 @@ struct intel_global_obj;
>>  struct intel_global_state;
>>  
>>  struct intel_global_state_funcs {
>> +        /* state_size and base_offset are initialized by INTEL_GLOBAL_STATE_DEFAULTS() */
>> +        size_t state_size;
>> +        size_t base_offset;
>> +
>>          struct intel_global_state *(*atomic_duplicate_state)(struct intel_global_obj *obj);
>>          void (*atomic_destroy_state)(struct intel_global_obj *obj,
>>                                       struct intel_global_state *state);
>> @@ -26,6 +32,10 @@ struct intel_global_obj {
>>          const struct intel_global_state_funcs *funcs;
>>  };
>>  
>> +#define INTEL_GLOBAL_STATE_DEFAULTS(type, base_member) \
>> +        .state_size = sizeof(type), \
>> +        .base_offset = offsetof(type, base_member)
>> +
>>  #define intel_for_each_global_obj(obj, dev_priv) \
>>          list_for_each_entry(obj, &(dev_priv)->display.global.obj_list, head)
>>  
>> @@ -96,4 +106,9 @@ int intel_atomic_global_state_wait_for_dependencies(struct intel_atomic_state *s
>>  
>>  bool intel_atomic_global_state_is_serialized(struct intel_atomic_state *state);
>>  
>> +struct intel_global_state *
>> +intel_atomic_global_duplicate_state_common(struct intel_global_obj *obj);
>> +void intel_atomic_global_destroy_state_common(struct intel_global_obj *obj,
>> +                                              struct intel_global_state *state);
>> +
>
>I have no major complaints.  Just some notes above.
>Reviewed-by: Jonathan Cavitt <jonathan.cavitt@intel.com>
>-Jonathan Cavitt
>
>>  #endif
>> -- 
>> 2.47.1
>> 
>>
Gustavo Sousa Dec. 20, 2024, 1:54 p.m. UTC | #6
Quoting Jani Nikula (2024-12-20 05:50:05-03:00)
>On Thu, 19 Dec 2024, Gustavo Sousa <gustavo.sousa@intel.com> wrote:
>> If we look at how the members of struct intel_global_state_funcs, we see
>> a common pattern repeating itself. Let's add the necessary
>> infra-structure to allow reducing the boilerplate. We do that by
>> adding common generic implementations for each member and adding a macro
>> INTEL_GLOBAL_STATE_DEFAULTS() to be used when initializing an instance
>> of struct intel_global_state_funcs.
>>
>> That way, a global state that does not need custom behavior can have
>> its funcs structure be initialized as in the following example,
>>
>>     static const struct intel_global_state_funcs <prefix>_funcs = {
>>            INTEL_GLOBAL_STATE_DEFAULTS(struct <prefix>_state, <base_member_name>),
>>     };
>>
>> , without the need to implementing the functions.
>>
>> That doesn't come without cost - we will need to store two size_t
>> members -, but that cost is arguably justified by the simplification
>> gained.
>>
>> In an upcoming change we will put that infra into action on existing
>> users.
>>
>> Signed-off-by: Gustavo Sousa <gustavo.sousa@intel.com>
>> ---
>>  .../gpu/drm/i915/display/intel_global_state.c | 41 ++++++++++++++++++-
>>  .../gpu/drm/i915/display/intel_global_state.h | 15 +++++++
>>  2 files changed, 54 insertions(+), 2 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/i915/display/intel_global_state.c b/drivers/gpu/drm/i915/display/intel_global_state.c
>> index cbcd1e91b7be..4b4c33fa99fb 100644
>> --- a/drivers/gpu/drm/i915/display/intel_global_state.c
>> +++ b/drivers/gpu/drm/i915/display/intel_global_state.c
>> @@ -59,7 +59,10 @@ static void __intel_atomic_global_state_free(struct kref *kref)
>>  
>>          commit_put(obj_state->commit);
>>  
>> -        obj->funcs->atomic_destroy_state(obj, obj_state);
>> +        if (obj->funcs->atomic_destroy_state)
>> +                obj->funcs->atomic_destroy_state(obj, obj_state);
>> +        else
>> +                intel_atomic_global_destroy_state_common(obj, obj_state);
>>  }
>>  
>>  static void intel_atomic_global_state_put(struct intel_global_state *obj_state)
>> @@ -164,7 +167,11 @@ intel_atomic_get_global_obj_state(struct intel_atomic_state *state,
>>          index = state->num_global_objs;
>>          memset(&state->global_objs[index], 0, sizeof(*state->global_objs));
>>  
>> -        obj_state = obj->funcs->atomic_duplicate_state(obj);
>> +        if (obj->funcs->atomic_duplicate_state)
>> +                obj_state = obj->funcs->atomic_duplicate_state(obj);
>> +        else
>> +                obj_state = intel_atomic_global_duplicate_state_common(obj);
>> +
>>          if (!obj_state)
>>                  return ERR_PTR(-ENOMEM);
>>  
>> @@ -382,3 +389,33 @@ intel_atomic_global_state_commit_done(struct intel_atomic_state *state)
>>                  complete_all(&commit->done);
>>          }
>>  }
>> +
>> +struct intel_global_state *
>> +intel_atomic_global_duplicate_state_common(struct intel_global_obj *obj)
>> +{
>> +        void *state_wrapper;
>> +
>> +        if (WARN_ON(obj->funcs->state_size == 0))
>> +                return NULL;
>> +
>> +        state_wrapper = (void *)obj->state - obj->funcs->base_offset;
>> +
>> +        state_wrapper = kmemdup(state_wrapper, obj->funcs->state_size, GFP_KERNEL);
>> +        if (!state_wrapper)
>> +                return NULL;
>> +
>> +        return state_wrapper + obj->funcs->base_offset;
>> +}
>> +
>> +void intel_atomic_global_destroy_state_common(struct intel_global_obj *obj,
>> +                                              struct intel_global_state *state)
>> +{
>> +        void *state_wrapper;
>> +
>> +        if (WARN_ON(obj->funcs->state_size == 0))
>> +                return;
>> +
>> +        state_wrapper = (void *)state - obj->funcs->base_offset;
>> +
>> +        kfree(state_wrapper);
>> +}
>> diff --git a/drivers/gpu/drm/i915/display/intel_global_state.h b/drivers/gpu/drm/i915/display/intel_global_state.h
>> index 6506a8e32972..e47e007225cc 100644
>> --- a/drivers/gpu/drm/i915/display/intel_global_state.h
>> +++ b/drivers/gpu/drm/i915/display/intel_global_state.h
>> @@ -8,6 +8,8 @@
>>  
>>  #include <linux/kref.h>
>>  #include <linux/list.h>
>> +#include <linux/stddef.h>
>> +#include <linux/types.h>
>>  
>>  struct drm_i915_private;
>>  struct intel_atomic_state;
>> @@ -15,6 +17,10 @@ struct intel_global_obj;
>>  struct intel_global_state;
>>  
>>  struct intel_global_state_funcs {
>> +        /* state_size and base_offset are initialized by INTEL_GLOBAL_STATE_DEFAULTS() */
>> +        size_t state_size;
>> +        size_t base_offset;
>> +
>
>Gut feeling says these should be part of struct intel_global_state
>rather than struct intel_global_state_funcs. Keyword being "funcs".

Yeah, I kept wondering about this and even considered a possible rename
of the struct type, but thought that would be probably too much just
because of two fields that should be considered private.

>
>They would have to be passed to intel_atomic_global_obj_init() and
>initialized runtime. That's a downside.

That sounds okay to me, although I would prefer something that
would not require explicit calls to sizeof() and offsetof().

> But then you could do away with
>the funcs struct altogether when defaults are used, and pass NULL.
>
>And you could also drop INTEL_GLOBAL_STATE_DEFAULTS() which I don't find
>particularly pretty.

Yeah, passing NULL seems like a good idea as it allows one to even skip
defining the funcs structure, but I think dropping
INTEL_GLOBAL_STATE_DEFAULTS() would make this an "all or nothing" type
of stuff: if you just need to customize one behavior, you will need to
define the whole structure explicitly.

--
Gustavo Sousa

>
>BR,
>Jani.
>
>>          struct intel_global_state *(*atomic_duplicate_state)(struct intel_global_obj *obj);
>>          void (*atomic_destroy_state)(struct intel_global_obj *obj,
>>                                       struct intel_global_state *state);
>> @@ -26,6 +32,10 @@ struct intel_global_obj {
>>          const struct intel_global_state_funcs *funcs;
>>  };
>>  
>> +#define INTEL_GLOBAL_STATE_DEFAULTS(type, base_member) \
>> +        .state_size = sizeof(type), \
>> +        .base_offset = offsetof(type, base_member)
>> +
>>  #define intel_for_each_global_obj(obj, dev_priv) \
>>          list_for_each_entry(obj, &(dev_priv)->display.global.obj_list, head)
>>  
>> @@ -96,4 +106,9 @@ int intel_atomic_global_state_wait_for_dependencies(struct intel_atomic_state *s
>>  
>>  bool intel_atomic_global_state_is_serialized(struct intel_atomic_state *state);
>>  
>> +struct intel_global_state *
>> +intel_atomic_global_duplicate_state_common(struct intel_global_obj *obj);
>> +void intel_atomic_global_destroy_state_common(struct intel_global_obj *obj,
>> +                                              struct intel_global_state *state);
>> +
>>  #endif
>
>-- 
>Jani Nikula, Intel
Gustavo Sousa Dec. 20, 2024, 1:56 p.m. UTC | #7
Quoting Jani Nikula (2024-12-20 05:51:51-03:00)
>On Thu, 19 Dec 2024, Gustavo Sousa <gustavo.sousa@intel.com> wrote:
>> diff --git a/drivers/gpu/drm/i915/display/intel_global_state.h b/drivers/gpu/drm/i915/display/intel_global_state.h
>> index 6506a8e32972..e47e007225cc 100644
>> --- a/drivers/gpu/drm/i915/display/intel_global_state.h
>> +++ b/drivers/gpu/drm/i915/display/intel_global_state.h
>> @@ -8,6 +8,8 @@
>>  
>>  #include <linux/kref.h>
>>  #include <linux/list.h>
>> +#include <linux/stddef.h>
>
>What do you need this for?

Because of offsetof().

--
Gustavo Sousa

>
>> +#include <linux/types.h>
>>  
>>  struct drm_i915_private;
>>  struct intel_atomic_state;
>> @@ -15,6 +17,10 @@ struct intel_global_obj;
>>  struct intel_global_state;
>>  
>>  struct intel_global_state_funcs {
>> +        /* state_size and base_offset are initialized by INTEL_GLOBAL_STATE_DEFAULTS() */
>> +        size_t state_size;
>> +        size_t base_offset;
>> +
>>          struct intel_global_state *(*atomic_duplicate_state)(struct intel_global_obj *obj);
>>          void (*atomic_destroy_state)(struct intel_global_obj *obj,
>>                                       struct intel_global_state *state);
>> @@ -26,6 +32,10 @@ struct intel_global_obj {
>>          const struct intel_global_state_funcs *funcs;
>>  };
>>  
>> +#define INTEL_GLOBAL_STATE_DEFAULTS(type, base_member) \
>> +        .state_size = sizeof(type), \
>> +        .base_offset = offsetof(type, base_member)
>> +
>>  #define intel_for_each_global_obj(obj, dev_priv) \
>>          list_for_each_entry(obj, &(dev_priv)->display.global.obj_list, head)
>>  
>> @@ -96,4 +106,9 @@ int intel_atomic_global_state_wait_for_dependencies(struct intel_atomic_state *s
>>  
>>  bool intel_atomic_global_state_is_serialized(struct intel_atomic_state *state);
>>  
>> +struct intel_global_state *
>> +intel_atomic_global_duplicate_state_common(struct intel_global_obj *obj);
>> +void intel_atomic_global_destroy_state_common(struct intel_global_obj *obj,
>> +                                              struct intel_global_state *state);
>> +
>>  #endif
>
>-- 
>Jani Nikula, Intel
Gustavo Sousa Dec. 20, 2024, 2:02 p.m. UTC | #8
Quoting Ville Syrjälä (2024-12-20 06:23:24-03:00)
>On Thu, Dec 19, 2024 at 06:48:37PM -0300, Gustavo Sousa wrote:
>> If we look at how the members of struct intel_global_state_funcs, we see
>> a common pattern repeating itself. Let's add the necessary
>> infra-structure to allow reducing the boilerplate. We do that by
>> adding common generic implementations for each member and adding a macro
>> INTEL_GLOBAL_STATE_DEFAULTS() to be used when initializing an instance
>> of struct intel_global_state_funcs.
>> 
>> That way, a global state that does not need custom behavior can have
>> its funcs structure be initialized as in the following example,
>> 
>>     static const struct intel_global_state_funcs <prefix>_funcs = {
>>            INTEL_GLOBAL_STATE_DEFAULTS(struct <prefix>_state, <base_member_name>),
>>     };
>> 
>> , without the need to implementing the functions.
>> 
>> That doesn't come without cost - we will need to store two size_t
>> members -, but that cost is arguably justified by the simplification
>> gained.
>> 
>> In an upcoming change we will put that infra into action on existing
>> users.
>> 
>> Signed-off-by: Gustavo Sousa <gustavo.sousa@intel.com>
>> ---
>>  .../gpu/drm/i915/display/intel_global_state.c | 41 ++++++++++++++++++-
>>  .../gpu/drm/i915/display/intel_global_state.h | 15 +++++++
>>  2 files changed, 54 insertions(+), 2 deletions(-)
>> 
>> diff --git a/drivers/gpu/drm/i915/display/intel_global_state.c b/drivers/gpu/drm/i915/display/intel_global_state.c
>> index cbcd1e91b7be..4b4c33fa99fb 100644
>> --- a/drivers/gpu/drm/i915/display/intel_global_state.c
>> +++ b/drivers/gpu/drm/i915/display/intel_global_state.c
>> @@ -59,7 +59,10 @@ static void __intel_atomic_global_state_free(struct kref *kref)
>>  
>>          commit_put(obj_state->commit);
>>  
>> -        obj->funcs->atomic_destroy_state(obj, obj_state);
>> +        if (obj->funcs->atomic_destroy_state)
>> +                obj->funcs->atomic_destroy_state(obj, obj_state);
>> +        else
>> +                intel_atomic_global_destroy_state_common(obj, obj_state);
>>  }
>>  
>>  static void intel_atomic_global_state_put(struct intel_global_state *obj_state)
>> @@ -164,7 +167,11 @@ intel_atomic_get_global_obj_state(struct intel_atomic_state *state,
>>          index = state->num_global_objs;
>>          memset(&state->global_objs[index], 0, sizeof(*state->global_objs));
>>  
>> -        obj_state = obj->funcs->atomic_duplicate_state(obj);
>> +        if (obj->funcs->atomic_duplicate_state)
>> +                obj_state = obj->funcs->atomic_duplicate_state(obj);
>> +        else
>> +                obj_state = intel_atomic_global_duplicate_state_common(obj);
>> +
>>          if (!obj_state)
>>                  return ERR_PTR(-ENOMEM);
>>  
>> @@ -382,3 +389,33 @@ intel_atomic_global_state_commit_done(struct intel_atomic_state *state)
>>                  complete_all(&commit->done);
>>          }
>>  }
>> +
>> +struct intel_global_state *
>> +intel_atomic_global_duplicate_state_common(struct intel_global_obj *obj)
>> +{
>> +        void *state_wrapper;
>> +
>> +        if (WARN_ON(obj->funcs->state_size == 0))
>> +                return NULL;
>> +
>> +        state_wrapper = (void *)obj->state - obj->funcs->base_offset;
>> +
>> +        state_wrapper = kmemdup(state_wrapper, obj->funcs->state_size, GFP_KERNEL);
>> +        if (!state_wrapper)
>> +                return NULL;
>> +
>> +        return state_wrapper + obj->funcs->base_offset;
>
>I'm not really a fan. What was obvious code before now looks 
>complicated.

Well it is 1 somewhat complication here to simplify N cases in the
subclasses. Maybe that's worth it?

>
>Also this no longer matches how any of the standard kms object
>types work, which I don't think is a good idea. IMO if we
>want to do something like this then it should probably try to
>cover all kms object types.

Do you mean to try to implement this on the DRM layer? In that case, we
would also endup having to implement this here right? Because we have
our own thing. Unless I interpreted your comment above wrong...

--
Gustavo Sousa
>
>> +}
>> +
>> +void intel_atomic_global_destroy_state_common(struct intel_global_obj *obj,
>> +                                              struct intel_global_state *state)
>> +{
>> +        void *state_wrapper;
>> +
>> +        if (WARN_ON(obj->funcs->state_size == 0))
>> +                return;
>> +
>> +        state_wrapper = (void *)state - obj->funcs->base_offset;
>> +
>> +        kfree(state_wrapper);
>> +}
>> diff --git a/drivers/gpu/drm/i915/display/intel_global_state.h b/drivers/gpu/drm/i915/display/intel_global_state.h
>> index 6506a8e32972..e47e007225cc 100644
>> --- a/drivers/gpu/drm/i915/display/intel_global_state.h
>> +++ b/drivers/gpu/drm/i915/display/intel_global_state.h
>> @@ -8,6 +8,8 @@
>>  
>>  #include <linux/kref.h>
>>  #include <linux/list.h>
>> +#include <linux/stddef.h>
>> +#include <linux/types.h>
>>  
>>  struct drm_i915_private;
>>  struct intel_atomic_state;
>> @@ -15,6 +17,10 @@ struct intel_global_obj;
>>  struct intel_global_state;
>>  
>>  struct intel_global_state_funcs {
>> +        /* state_size and base_offset are initialized by INTEL_GLOBAL_STATE_DEFAULTS() */
>> +        size_t state_size;
>> +        size_t base_offset;
>> +
>>          struct intel_global_state *(*atomic_duplicate_state)(struct intel_global_obj *obj);
>>          void (*atomic_destroy_state)(struct intel_global_obj *obj,
>>                                       struct intel_global_state *state);
>> @@ -26,6 +32,10 @@ struct intel_global_obj {
>>          const struct intel_global_state_funcs *funcs;
>>  };
>>  
>> +#define INTEL_GLOBAL_STATE_DEFAULTS(type, base_member) \
>> +        .state_size = sizeof(type), \
>> +        .base_offset = offsetof(type, base_member)
>> +
>>  #define intel_for_each_global_obj(obj, dev_priv) \
>>          list_for_each_entry(obj, &(dev_priv)->display.global.obj_list, head)
>>  
>> @@ -96,4 +106,9 @@ int intel_atomic_global_state_wait_for_dependencies(struct intel_atomic_state *s
>>  
>>  bool intel_atomic_global_state_is_serialized(struct intel_atomic_state *state);
>>  
>> +struct intel_global_state *
>> +intel_atomic_global_duplicate_state_common(struct intel_global_obj *obj);
>> +void intel_atomic_global_destroy_state_common(struct intel_global_obj *obj,
>> +                                              struct intel_global_state *state);
>> +
>>  #endif
>> -- 
>> 2.47.1
>
>-- 
>Ville Syrjälä
>Intel
diff mbox series

Patch

diff --git a/drivers/gpu/drm/i915/display/intel_global_state.c b/drivers/gpu/drm/i915/display/intel_global_state.c
index cbcd1e91b7be..4b4c33fa99fb 100644
--- a/drivers/gpu/drm/i915/display/intel_global_state.c
+++ b/drivers/gpu/drm/i915/display/intel_global_state.c
@@ -59,7 +59,10 @@  static void __intel_atomic_global_state_free(struct kref *kref)
 
 	commit_put(obj_state->commit);
 
-	obj->funcs->atomic_destroy_state(obj, obj_state);
+	if (obj->funcs->atomic_destroy_state)
+		obj->funcs->atomic_destroy_state(obj, obj_state);
+	else
+		intel_atomic_global_destroy_state_common(obj, obj_state);
 }
 
 static void intel_atomic_global_state_put(struct intel_global_state *obj_state)
@@ -164,7 +167,11 @@  intel_atomic_get_global_obj_state(struct intel_atomic_state *state,
 	index = state->num_global_objs;
 	memset(&state->global_objs[index], 0, sizeof(*state->global_objs));
 
-	obj_state = obj->funcs->atomic_duplicate_state(obj);
+	if (obj->funcs->atomic_duplicate_state)
+		obj_state = obj->funcs->atomic_duplicate_state(obj);
+	else
+		obj_state = intel_atomic_global_duplicate_state_common(obj);
+
 	if (!obj_state)
 		return ERR_PTR(-ENOMEM);
 
@@ -382,3 +389,33 @@  intel_atomic_global_state_commit_done(struct intel_atomic_state *state)
 		complete_all(&commit->done);
 	}
 }
+
+struct intel_global_state *
+intel_atomic_global_duplicate_state_common(struct intel_global_obj *obj)
+{
+	void *state_wrapper;
+
+	if (WARN_ON(obj->funcs->state_size == 0))
+		return NULL;
+
+	state_wrapper = (void *)obj->state - obj->funcs->base_offset;
+
+	state_wrapper = kmemdup(state_wrapper, obj->funcs->state_size, GFP_KERNEL);
+	if (!state_wrapper)
+		return NULL;
+
+	return state_wrapper + obj->funcs->base_offset;
+}
+
+void intel_atomic_global_destroy_state_common(struct intel_global_obj *obj,
+					      struct intel_global_state *state)
+{
+	void *state_wrapper;
+
+	if (WARN_ON(obj->funcs->state_size == 0))
+		return;
+
+	state_wrapper = (void *)state - obj->funcs->base_offset;
+
+	kfree(state_wrapper);
+}
diff --git a/drivers/gpu/drm/i915/display/intel_global_state.h b/drivers/gpu/drm/i915/display/intel_global_state.h
index 6506a8e32972..e47e007225cc 100644
--- a/drivers/gpu/drm/i915/display/intel_global_state.h
+++ b/drivers/gpu/drm/i915/display/intel_global_state.h
@@ -8,6 +8,8 @@ 
 
 #include <linux/kref.h>
 #include <linux/list.h>
+#include <linux/stddef.h>
+#include <linux/types.h>
 
 struct drm_i915_private;
 struct intel_atomic_state;
@@ -15,6 +17,10 @@  struct intel_global_obj;
 struct intel_global_state;
 
 struct intel_global_state_funcs {
+	/* state_size and base_offset are initialized by INTEL_GLOBAL_STATE_DEFAULTS() */
+	size_t state_size;
+	size_t base_offset;
+
 	struct intel_global_state *(*atomic_duplicate_state)(struct intel_global_obj *obj);
 	void (*atomic_destroy_state)(struct intel_global_obj *obj,
 				     struct intel_global_state *state);
@@ -26,6 +32,10 @@  struct intel_global_obj {
 	const struct intel_global_state_funcs *funcs;
 };
 
+#define INTEL_GLOBAL_STATE_DEFAULTS(type, base_member) \
+	.state_size = sizeof(type), \
+	.base_offset = offsetof(type, base_member)
+
 #define intel_for_each_global_obj(obj, dev_priv) \
 	list_for_each_entry(obj, &(dev_priv)->display.global.obj_list, head)
 
@@ -96,4 +106,9 @@  int intel_atomic_global_state_wait_for_dependencies(struct intel_atomic_state *s
 
 bool intel_atomic_global_state_is_serialized(struct intel_atomic_state *state);
 
+struct intel_global_state *
+intel_atomic_global_duplicate_state_common(struct intel_global_obj *obj);
+void intel_atomic_global_destroy_state_common(struct intel_global_obj *obj,
+					      struct intel_global_state *state);
+
 #endif