[PATCH 5/5] drm/atomic: Make private objs proper objects
Daniel Vetter
daniel at ffwll.ch
Mon Jul 3 17:00:03 UTC 2017
On Mon, Jul 03, 2017 at 04:43:37PM +0300, ville.syrjala at linux.intel.com wrote:
> From: Ville Syrjälä <ville.syrjala at linux.intel.com>
>
> Make the atomic private object stuff less special by introducing proper
> base classes for the object and its state. Drivers can embed these in
> their own appropriate objects, after which these things will work
> exactly like the plane/crtc/connector states during atomic operations.
>
> Cc: Dhinakaran Pandiyan <dhinakaran.pandiyan at intel.com>
> Signed-off-by: Ville Syrjälä <ville.syrjala at linux.intel.com>
Won't apply without 1&4, but glossing over that detail I kinda like this.
Reviewed-by: Daniel Vetter <daniel.vetter at ffwll.ch>
> ---
> drivers/gpu/drm/drm_atomic.c | 78 +++++++++++++++------
> drivers/gpu/drm/drm_atomic_helper.c | 30 +++++++--
> drivers/gpu/drm/drm_dp_mst_topology.c | 63 +++++++++--------
> include/drm/drm_atomic.h | 123 +++++++++++++++++++++-------------
> include/drm/drm_atomic_helper.h | 4 ++
> include/drm/drm_dp_mst_helper.h | 10 +++
> 6 files changed, 206 insertions(+), 102 deletions(-)
>
> diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
> index 5eb14c73c0fb..da7752230e4c 100644
> --- a/drivers/gpu/drm/drm_atomic.c
> +++ b/drivers/gpu/drm/drm_atomic.c
> @@ -197,12 +197,14 @@ void drm_atomic_state_default_clear(struct drm_atomic_state *state)
> for (i = 0; i < state->num_private_objs; i++) {
> struct __drm_private_objs_state *p =
> __drm_atomic_state_private_obj(state, i);
> - void *obj_state = p->obj_state;
> + struct drm_private_obj *obj = p->ptr;
>
> - p->funcs->destroy_state(obj_state);
> - p->obj = NULL;
> - p->obj_state = NULL;
> - p->funcs = NULL;
> + if (WARN_ON(!obj))
> + continue;
> +
> + obj->funcs->atomic_destroy_state(obj, p->state);
> + p->ptr = NULL;
> + p->state = NULL;
> }
> state->num_private_objs = 0;
>
> @@ -1000,11 +1002,44 @@ static void drm_atomic_plane_print_state(struct drm_printer *p,
> }
>
> /**
> + * drm_atomic_private_obj_init - initialize private object
> + * @obj: private object
> + * @state: initial private object state
> + * @funcs: pointer to the struct of function pointers that identify the object
> + * type
> + *
> + * Initialize the private object, which can be embedded into any
> + * driver private object that needs its own atomic state.
> + */
> +void
> +drm_atomic_private_obj_init(struct drm_private_obj *obj,
> + struct drm_private_state *state,
> + const struct drm_private_state_funcs *funcs)
> +{
> + memset(obj, 0, sizeof(*obj));
> +
> + obj->state = state;
> + obj->funcs = funcs;
> +}
> +EXPORT_SYMBOL(drm_atomic_private_obj_init);
> +
> +/**
> + * drm_atomic_private_obj_fini - finalize private object
> + * @obj: private object
> + *
> + * Finalize the private object.
> + */
> +void
> +drm_atomic_private_obj_fini(struct drm_private_obj *obj)
> +{
> + obj->funcs->atomic_destroy_state(obj, obj->state);
> +}
> +EXPORT_SYMBOL(drm_atomic_private_obj_fini);
> +
> +/**
> * drm_atomic_get_private_obj_state - get private object state
> * @state: global atomic state
> * @obj: private object to get the state for
> - * @funcs: pointer to the struct of function pointers that identify the object
> - * type
> *
> * This function returns the private object state for the given private object,
> * allocating the state if needed. It does not grab any locks as the caller is
> @@ -1014,19 +1049,21 @@ static void drm_atomic_plane_print_state(struct drm_printer *p,
> *
> * Either the allocated state or the error code encoded into a pointer.
> */
> -void *
> -drm_atomic_get_private_obj_state(struct drm_atomic_state *state, void *obj,
> - const struct drm_private_state_funcs *funcs)
> +struct drm_private_state *
> +drm_atomic_get_private_obj_state(struct drm_atomic_state *state,
> + struct drm_private_obj *obj)
> {
> + const struct drm_private_state_funcs *funcs = obj->funcs;
> struct __drm_private_objs_state *p;
> + struct drm_private_state *obj_state;
> int index = state->num_private_objs;
> int ret, i;
>
> for (i = 0; i < state->num_private_objs; i++) {
> p = __drm_atomic_state_private_obj(state, i);
>
> - if (obj == p->obj)
> - return p->obj_state;
> + if (obj == p->ptr)
> + return p->state;
> }
>
> ret = drm_dynarray_reserve(&state->private_objs, index);
> @@ -1035,19 +1072,22 @@ drm_atomic_get_private_obj_state(struct drm_atomic_state *state, void *obj,
>
> p = __drm_atomic_state_private_obj(state, index);
>
> - p->obj_state = funcs->duplicate_state(state, obj);
> - if (!p->obj_state)
> + obj_state = funcs->atomic_duplicate_state(obj);
> + if (!obj_state)
> return ERR_PTR(-ENOMEM);
>
> - p->obj = obj;
> - p->funcs = funcs;
> + p->state = obj_state;
> + p->old_state = obj->state;
> + p->new_state = obj_state;
> + p->ptr = obj;
> + obj_state->state = state;
>
> state->num_private_objs = index + 1;
>
> - DRM_DEBUG_ATOMIC("Added new private object state %p to %p\n",
> - p->obj_state, state);
> + DRM_DEBUG_ATOMIC("Added new private object [%p] state %p to %p\n",
> + obj, obj_state, state);
>
> - return p->obj_state;
> + return obj_state;
> }
> EXPORT_SYMBOL(drm_atomic_get_private_obj_state);
>
> diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
> index 5cd93c6d691e..78f0ff1ad982 100644
> --- a/drivers/gpu/drm/drm_atomic_helper.c
> +++ b/drivers/gpu/drm/drm_atomic_helper.c
> @@ -2267,8 +2267,8 @@ void drm_atomic_helper_swap_state(struct drm_atomic_state *state,
> struct drm_plane *plane;
> struct drm_plane_state *old_plane_state, *new_plane_state;
> struct drm_crtc_commit *commit;
> - void *obj, *obj_state;
> - const struct drm_private_state_funcs *funcs;
> + struct drm_private_obj *obj;
> + struct drm_private_state *old_obj_state, *new_obj_state;
>
> if (stall) {
> for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) {
> @@ -2330,8 +2330,15 @@ void drm_atomic_helper_swap_state(struct drm_atomic_state *state,
> plane->state = new_plane_state;
> }
>
> - __for_each_private_obj(state, obj, obj_state, i, funcs)
> - funcs->swap_state(obj, &__drm_atomic_state_private_obj(state, i)->obj_state);
> + for_each_oldnew_private_obj_in_state(state, obj, old_obj_state, new_obj_state, i) {
> + WARN_ON(obj->state != old_obj_state);
> +
> + old_obj_state->state = state;
> + new_obj_state->state = NULL;
> +
> + __drm_atomic_state_private_obj(state, i)->state = old_obj_state;
> + obj->state = new_obj_state;
> + }
> }
> EXPORT_SYMBOL(drm_atomic_helper_swap_state);
>
> @@ -3830,3 +3837,18 @@ int drm_atomic_helper_legacy_gamma_set(struct drm_crtc *crtc,
> return ret;
> }
> EXPORT_SYMBOL(drm_atomic_helper_legacy_gamma_set);
> +
> +/**
> + * __drm_atomic_helper_private_duplicate_state - copy atomic private state
> + * @obj: CRTC object
> + * @state: new private object state
> + *
> + * Copies atomic state from a private objects's current state and resets inferred values.
> + * This is useful for drivers that subclass the private state.
> + */
> +void __drm_atomic_helper_private_obj_duplicate_state(struct drm_private_obj *obj,
> + struct drm_private_state *state)
> +{
> + memcpy(state, obj->state, sizeof(*state));
> +}
> +EXPORT_SYMBOL(__drm_atomic_helper_private_obj_duplicate_state);
> diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c b/drivers/gpu/drm/drm_dp_mst_topology.c
> index bfd237c15e76..91510098f60e 100644
> --- a/drivers/gpu/drm/drm_dp_mst_topology.c
> +++ b/drivers/gpu/drm/drm_dp_mst_topology.c
> @@ -31,6 +31,8 @@
> #include <drm/drmP.h>
>
> #include <drm/drm_fixed.h>
> +#include <drm/drm_atomic.h>
> +#include <drm/drm_atomic_helper.h>
>
> /**
> * DOC: dp mst helper
> @@ -2992,41 +2994,32 @@ static void drm_dp_destroy_connector_work(struct work_struct *work)
> (*mgr->cbs->hotplug)(mgr);
> }
>
> -void *drm_dp_mst_duplicate_state(struct drm_atomic_state *state, void *obj)
> +static struct drm_private_state *
> +drm_dp_mst_duplicate_state(struct drm_private_obj *obj)
> {
> - struct drm_dp_mst_topology_mgr *mgr = obj;
> - struct drm_dp_mst_topology_state *new_mst_state;
> + struct drm_dp_mst_topology_state *state;
>
> - if (WARN_ON(!mgr->state))
> + state = kmemdup(obj->state, sizeof(*state), GFP_KERNEL);
> + if (!state)
> return NULL;
>
> - new_mst_state = kmemdup(mgr->state, sizeof(*new_mst_state), GFP_KERNEL);
> - if (new_mst_state)
> - new_mst_state->state = state;
> - return new_mst_state;
> -}
> -
> -void drm_dp_mst_swap_state(void *obj, void **obj_state_ptr)
> -{
> - struct drm_dp_mst_topology_mgr *mgr = obj;
> - struct drm_dp_mst_topology_state **topology_state_ptr;
> -
> - topology_state_ptr = (struct drm_dp_mst_topology_state **)obj_state_ptr;
> + __drm_atomic_helper_private_obj_duplicate_state(obj, &state->base);
>
> - mgr->state->state = (*topology_state_ptr)->state;
> - swap(*topology_state_ptr, mgr->state);
> - mgr->state->state = NULL;
> + return &state->base;
> }
>
> -void drm_dp_mst_destroy_state(void *obj_state)
> +static void drm_dp_mst_destroy_state(struct drm_private_obj *obj,
> + struct drm_private_state *state)
> {
> - kfree(obj_state);
> + struct drm_dp_mst_topology_state *mst_state =
> + to_dp_mst_topology_state(state);
> +
> + kfree(mst_state);
> }
>
> static const struct drm_private_state_funcs mst_state_funcs = {
> - .duplicate_state = drm_dp_mst_duplicate_state,
> - .swap_state = drm_dp_mst_swap_state,
> - .destroy_state = drm_dp_mst_destroy_state,
> + .atomic_duplicate_state = drm_dp_mst_duplicate_state,
> + .atomic_destroy_state = drm_dp_mst_destroy_state,
> };
>
> /**
> @@ -3050,8 +3043,7 @@ struct drm_dp_mst_topology_state *drm_atomic_get_mst_topology_state(struct drm_a
> struct drm_device *dev = mgr->dev;
>
> WARN_ON(!drm_modeset_is_locked(&dev->mode_config.connection_mutex));
> - return drm_atomic_get_private_obj_state(state, mgr,
> - &mst_state_funcs);
> + return to_dp_mst_topology_state(drm_atomic_get_private_obj_state(state, &mgr->base));
> }
> EXPORT_SYMBOL(drm_atomic_get_mst_topology_state);
>
> @@ -3071,6 +3063,8 @@ int drm_dp_mst_topology_mgr_init(struct drm_dp_mst_topology_mgr *mgr,
> int max_dpcd_transaction_bytes,
> int max_payloads, int conn_base_id)
> {
> + struct drm_dp_mst_topology_state *mst_state;
> +
> mutex_init(&mgr->lock);
> mutex_init(&mgr->qlock);
> mutex_init(&mgr->payload_lock);
> @@ -3099,14 +3093,18 @@ int drm_dp_mst_topology_mgr_init(struct drm_dp_mst_topology_mgr *mgr,
> if (test_calc_pbn_mode() < 0)
> DRM_ERROR("MST PBN self-test failed\n");
>
> - mgr->state = kzalloc(sizeof(*mgr->state), GFP_KERNEL);
> - if (mgr->state == NULL)
> + mst_state = kzalloc(sizeof(*mst_state), GFP_KERNEL);
> + if (mst_state == NULL)
> return -ENOMEM;
> - mgr->state->mgr = mgr;
> +
> + mst_state->mgr = mgr;
>
> /* max. time slots - one slot for MTP header */
> - mgr->state->avail_slots = 63;
> - mgr->funcs = &mst_state_funcs;
> + mst_state->avail_slots = 63;
> +
> + drm_atomic_private_obj_init(&mgr->base,
> + &mst_state->base,
> + &mst_state_funcs);
>
> return 0;
> }
> @@ -3128,8 +3126,7 @@ void drm_dp_mst_topology_mgr_destroy(struct drm_dp_mst_topology_mgr *mgr)
> mutex_unlock(&mgr->payload_lock);
> mgr->dev = NULL;
> mgr->aux = NULL;
> - kfree(mgr->state);
> - mgr->state = NULL;
> + drm_atomic_private_obj_fini(&mgr->base);
> mgr->funcs = NULL;
> }
> EXPORT_SYMBOL(drm_dp_mst_topology_mgr_destroy);
> diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h
> index 809e8b4c3719..addec49a14bf 100644
> --- a/include/drm/drm_atomic.h
> +++ b/include/drm/drm_atomic.h
> @@ -155,6 +155,9 @@ struct __drm_connectors_state {
> struct drm_connector_state *state, *old_state, *new_state;
> };
>
> +struct drm_private_obj;
> +struct drm_private_state;
> +
> /**
> * struct drm_private_state_funcs - atomic state functions for private objects
> *
> @@ -167,7 +170,7 @@ struct __drm_connectors_state {
> */
> struct drm_private_state_funcs {
> /**
> - * @duplicate_state:
> + * @atomic_duplicate_state:
> *
> * Duplicate the current state of the private object and return it. It
> * is an error to call this before obj->state has been initialized.
> @@ -177,29 +180,30 @@ struct drm_private_state_funcs {
> * Duplicated atomic state or NULL when obj->state is not
> * initialized or allocation failed.
> */
> - void *(*duplicate_state)(struct drm_atomic_state *state, void *obj);
> + struct drm_private_state *(*atomic_duplicate_state)(struct drm_private_obj *obj);
>
> /**
> - * @swap_state:
> + * @atomic_destroy_state:
> *
> - * This function swaps the existing state of a private object @obj with
> - * it's newly created state, the pointer to which is passed as
> - * @obj_state_ptr.
> + * Frees the private object state created with @atomic_duplicate_state.
> */
> - void (*swap_state)(void *obj, void **obj_state_ptr);
> + void (*atomic_destroy_state)(struct drm_private_obj *obj,
> + struct drm_private_state *state);
> +};
>
> - /**
> - * @destroy_state:
> - *
> - * Frees the private object state created with @duplicate_state.
> - */
> - void (*destroy_state)(void *obj_state);
> +struct drm_private_obj {
> + struct drm_private_state *state;
> +
> + const struct drm_private_state_funcs *funcs;
> +};
> +
> +struct drm_private_state {
> + struct drm_atomic_state *state;
> };
>
> struct __drm_private_objs_state {
> - void *obj;
> - void *obj_state;
> - const struct drm_private_state_funcs *funcs;
> + struct drm_private_obj *ptr;
> + struct drm_private_state *state, *old_state, *new_state;
> };
>
> /**
> @@ -336,10 +340,14 @@ int drm_atomic_connector_set_property(struct drm_connector *connector,
> struct drm_connector_state *state, struct drm_property *property,
> uint64_t val);
>
> -void * __must_check
> +void drm_atomic_private_obj_init(struct drm_private_obj *obj,
> + struct drm_private_state *state,
> + const struct drm_private_state_funcs *funcs);
> +void drm_atomic_private_obj_fini(struct drm_private_obj *obj);
> +
> +struct drm_private_state * __must_check
> drm_atomic_get_private_obj_state(struct drm_atomic_state *state,
> - void *obj,
> - const struct drm_private_state_funcs *funcs);
> + struct drm_private_obj *obj);
>
> /**
> * drm_atomic_get_existing_crtc_state - get crtc state, if it exists
> @@ -826,43 +834,66 @@ void drm_state_dump(struct drm_device *dev, struct drm_printer *p);
> for_each_if (plane)
>
> /**
> - * __for_each_private_obj - iterate over all private objects
> + * for_each_oldnew_private_obj_in_state - iterate over all private objects in an atomic update
> * @__state: &struct drm_atomic_state pointer
> - * @obj: private object iteration cursor
> - * @obj_state: private object state iteration cursor
> + * @obj: &struct drm_private_obj iteration cursor
> + * @old_obj_state: &struct drm_private_state iteration cursor for the old state
> + * @new_obj_state: &struct drm_private_state iteration cursor for the new state
> * @__i: int iteration cursor, for macro-internal use
> - * @__funcs: &struct drm_private_state_funcs iteration cursor
> *
> - * This macro iterates over the array containing private object data in atomic
> - * state
> + * This iterates over all private objects in an atomic update, tracking both
> + * old and new state. This is useful in places where the state delta needs
> + * to be considered, for example in atomic check functions.
> */
> -#define __for_each_private_obj(__state, obj, obj_state, __i, __funcs) \
> - for ((__i) = 0; \
> - (__i) < (__state)->num_private_objs && \
> - ((obj) = __drm_atomic_state_private_obj(__state, __i)->obj, \
> - (__funcs) = __drm_atomic_state_private_obj(__state, __i)->funcs, \
> - (obj_state) = __drm_atomic_state_private_obj(__state, __i)->obj_state, \
> - 1); \
> - (__i)++) \
> +#define for_each_oldnew_private_obj_in_state(__state, obj, old_obj_state, new_obj_state, __i) \
> + for ((__i) = 0; \
> + (__i) < (__state)->num_private_objs && \
> + ((obj) = __drm_atomic_state_private_obj(__state, __i)->ptr, \
> + (old_obj_state) = __drm_atomic_state_private_obj(__state, __i)->old_state, \
> + (new_obj_state) = __drm_atomic_state_private_obj(__state, __i)->new_state, 1); \
> + (__i)++) \
> + for_each_if (obj)
> +
>
> /**
> - * for_each_private_obj - iterate over a specify type of private object
> + * for_each_old_private_obj_in_state - iterate over all private objects in an atomic update
> * @__state: &struct drm_atomic_state pointer
> - * @obj_funcs: &struct drm_private_state_funcs function table to filter
> - * private objects
> - * @obj: private object iteration cursor
> - * @obj_state: private object state iteration cursor
> + * @obj: &struct drm_private_obj iteration cursor
> + * @old_obj_state: &struct drm_private_state iteration cursor for the old state
> * @__i: int iteration cursor, for macro-internal use
> - * @__funcs: &struct drm_private_state_funcs iteration cursor
> *
> - * This macro iterates over the private objects state array while filtering the
> - * objects based on the vfunc table that is passed as @obj_funcs. New macros
> - * can be created by passing in the vfunc table associated with a specific
> - * private object.
> + * This iterates over all private objects in an atomic update, tracking only
> + * the old state. This is useful in disable functions, where we need the old
> + * state the hardware is still in.
> */
> -#define for_each_private_obj(__state, obj_funcs, obj, obj_state, __i, __funcs) \
> - __for_each_private_obj(__state, obj, obj_state, __i, __funcs) \
> - for_each_if (__funcs == obj_funcs)
> +#define for_each_old_private_obj_in_state(__state, obj, old_obj_state, __i) \
> + for ((__i) = 0; \
> + (__i) < (__state)->num_private_objs && \
> + ((obj) = __drm_atomic_state_private_obj(__state, __i)->ptr, \
> + (old_obj_state) = __drm_atomic_state_private_obj(__state, __i)->old_state, 1); \
> + (__i)++) \
> + for_each_if (obj)
> +
> +
> +/**
> + * for_each_new_private_obj_in_state - iterate over all private objects in an atomic update
> + * @__state: &struct drm_atomic_state pointer
> + * @obj: &struct drm_private_obj iteration cursor
> + * @new_obj_state: &struct drm_private_state iteration cursor for the new state
> + * @__i: int iteration cursor, for macro-internal use
> + *
> + * This iterates over all private objects in an atomic update, tracking only
> + * the new state. This is useful in enable functions, where we need the new state the
> + * hardware should be in when the atomic commit operation has completed.
> + */
> +#define for_each_new_private_obj_in_state(__state, obj, new_obj_state, __i) \
> + for ((__i) = 0; \
> + (__i) < (__state)->num_private_objs && \
> + ((obj) = __drm_atomic_state_private_obj(__state, __i)->ptr, \
> + (new_obj_state) = __drm_atomic_state_private_obj(__state, __i)->new_state, 1); \
> + (__i)++) \
> + for_each_if (obj)
> +
>
> /**
> * drm_atomic_crtc_needs_modeset - compute combined modeset need
> diff --git a/include/drm/drm_atomic_helper.h b/include/drm/drm_atomic_helper.h
> index dd196cc0afd7..7db3438ff735 100644
> --- a/include/drm/drm_atomic_helper.h
> +++ b/include/drm/drm_atomic_helper.h
> @@ -33,6 +33,8 @@
> #include <drm/drm_modeset_helper.h>
>
> struct drm_atomic_state;
> +struct drm_private_obj;
> +struct drm_private_state;
>
> int drm_atomic_helper_check_modeset(struct drm_device *dev,
> struct drm_atomic_state *state);
> @@ -185,6 +187,8 @@ int drm_atomic_helper_legacy_gamma_set(struct drm_crtc *crtc,
> u16 *red, u16 *green, u16 *blue,
> uint32_t size,
> struct drm_modeset_acquire_ctx *ctx);
> +void __drm_atomic_helper_private_obj_duplicate_state(struct drm_private_obj *obj,
> + struct drm_private_state *state);
>
> /**
> * drm_atomic_crtc_for_each_plane - iterate over planes currently attached to CRTC
> diff --git a/include/drm/drm_dp_mst_helper.h b/include/drm/drm_dp_mst_helper.h
> index 177ab6f86855..d55abb75f29a 100644
> --- a/include/drm/drm_dp_mst_helper.h
> +++ b/include/drm/drm_dp_mst_helper.h
> @@ -404,12 +404,17 @@ struct drm_dp_payload {
> int vcpi;
> };
>
> +#define to_dp_mst_topology_state(x) container_of(x, struct drm_dp_mst_topology_state, base)
> +
> struct drm_dp_mst_topology_state {
> + struct drm_private_state base;
> int avail_slots;
> struct drm_atomic_state *state;
> struct drm_dp_mst_topology_mgr *mgr;
> };
>
> +#define to_dp_mst_topology_mgr(x) container_of(x, struct drm_dp_mst_topology_mgr, base)
> +
> /**
> * struct drm_dp_mst_topology_mgr - DisplayPort MST manager
> *
> @@ -419,6 +424,11 @@ struct drm_dp_mst_topology_state {
> */
> struct drm_dp_mst_topology_mgr {
> /**
> + * @base: Base private object for atomic
> + */
> + struct drm_private_obj base;
> +
> + /**
> * @dev: device pointer for adding i2c devices etc.
> */
> struct drm_device *dev;
> --
> 2.13.0
>
> _______________________________________________
> dri-devel mailing list
> dri-devel at lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel
--
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
More information about the dri-devel
mailing list