drm/atomic: Allow drivers to subclass drm_atomic_state, v3
Drivers may need to store the state of shared resources, such as PLLs or FIFO space, into the atomic state. Allow this by making it possible to subclass drm_atomic_state. Changes since v1: - Change member names for functions to atomic_state_(alloc,clear) - Change __drm_atomic_state_new to drm_atomic_state_init - Allow free function to be overridden too, in case extra memory is allocated in alloc. Changes since v2: - Rename *_default_free to default_release, to make clear it doesn't free the state object itself. Cc: dri-devel@lists.freedesktop.org Acked-by: Ander Conselvan de Oliveira <ander.conselvan.de.oliveira@intel.com> Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
This commit is contained in:
Родитель
744b058827
Коммит
036ef5733b
|
@ -30,7 +30,15 @@
|
||||||
#include <drm/drm_atomic.h>
|
#include <drm/drm_atomic.h>
|
||||||
#include <drm/drm_plane_helper.h>
|
#include <drm/drm_plane_helper.h>
|
||||||
|
|
||||||
static void kfree_state(struct drm_atomic_state *state)
|
/**
|
||||||
|
* drm_atomic_state_default_release -
|
||||||
|
* release memory initialized by drm_atomic_state_init
|
||||||
|
* @state: atomic state
|
||||||
|
*
|
||||||
|
* Free all the memory allocated by drm_atomic_state_init.
|
||||||
|
* This is useful for drivers that subclass the atomic state.
|
||||||
|
*/
|
||||||
|
void drm_atomic_state_default_release(struct drm_atomic_state *state)
|
||||||
{
|
{
|
||||||
kfree(state->connectors);
|
kfree(state->connectors);
|
||||||
kfree(state->connector_states);
|
kfree(state->connector_states);
|
||||||
|
@ -38,24 +46,20 @@ static void kfree_state(struct drm_atomic_state *state)
|
||||||
kfree(state->crtc_states);
|
kfree(state->crtc_states);
|
||||||
kfree(state->planes);
|
kfree(state->planes);
|
||||||
kfree(state->plane_states);
|
kfree(state->plane_states);
|
||||||
kfree(state);
|
|
||||||
}
|
}
|
||||||
|
EXPORT_SYMBOL(drm_atomic_state_default_release);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* drm_atomic_state_alloc - allocate atomic state
|
* drm_atomic_state_init - init new atomic state
|
||||||
* @dev: DRM device
|
* @dev: DRM device
|
||||||
|
* @state: atomic state
|
||||||
*
|
*
|
||||||
* This allocates an empty atomic state to track updates.
|
* Default implementation for filling in a new atomic state.
|
||||||
|
* This is useful for drivers that subclass the atomic state.
|
||||||
*/
|
*/
|
||||||
struct drm_atomic_state *
|
int
|
||||||
drm_atomic_state_alloc(struct drm_device *dev)
|
drm_atomic_state_init(struct drm_device *dev, struct drm_atomic_state *state)
|
||||||
{
|
{
|
||||||
struct drm_atomic_state *state;
|
|
||||||
|
|
||||||
state = kzalloc(sizeof(*state), GFP_KERNEL);
|
|
||||||
if (!state)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
/* TODO legacy paths should maybe do a better job about
|
/* TODO legacy paths should maybe do a better job about
|
||||||
* setting this appropriately?
|
* setting this appropriately?
|
||||||
*/
|
*/
|
||||||
|
@ -92,31 +96,50 @@ drm_atomic_state_alloc(struct drm_device *dev)
|
||||||
|
|
||||||
state->dev = dev;
|
state->dev = dev;
|
||||||
|
|
||||||
DRM_DEBUG_ATOMIC("Allocate atomic state %p\n", state);
|
DRM_DEBUG_ATOMIC("Allocated atomic state %p\n", state);
|
||||||
|
|
||||||
return state;
|
return 0;
|
||||||
fail:
|
fail:
|
||||||
kfree_state(state);
|
drm_atomic_state_default_release(state);
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(drm_atomic_state_init);
|
||||||
|
|
||||||
return NULL;
|
/**
|
||||||
|
* drm_atomic_state_alloc - allocate atomic state
|
||||||
|
* @dev: DRM device
|
||||||
|
*
|
||||||
|
* This allocates an empty atomic state to track updates.
|
||||||
|
*/
|
||||||
|
struct drm_atomic_state *
|
||||||
|
drm_atomic_state_alloc(struct drm_device *dev)
|
||||||
|
{
|
||||||
|
struct drm_mode_config *config = &dev->mode_config;
|
||||||
|
struct drm_atomic_state *state;
|
||||||
|
|
||||||
|
if (!config->funcs->atomic_state_alloc) {
|
||||||
|
state = kzalloc(sizeof(*state), GFP_KERNEL);
|
||||||
|
if (!state)
|
||||||
|
return NULL;
|
||||||
|
if (drm_atomic_state_init(dev, state) < 0) {
|
||||||
|
kfree(state);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
return config->funcs->atomic_state_alloc(dev);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(drm_atomic_state_alloc);
|
EXPORT_SYMBOL(drm_atomic_state_alloc);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* drm_atomic_state_clear - clear state object
|
* drm_atomic_state_default_clear - clear base atomic state
|
||||||
* @state: atomic state
|
* @state: atomic state
|
||||||
*
|
*
|
||||||
* When the w/w mutex algorithm detects a deadlock we need to back off and drop
|
* Default implementation for clearing atomic state.
|
||||||
* all locks. So someone else could sneak in and change the current modeset
|
* This is useful for drivers that subclass the atomic state.
|
||||||
* configuration. Which means that all the state assembled in @state is no
|
|
||||||
* longer an atomic update to the current state, but to some arbitrary earlier
|
|
||||||
* state. Which could break assumptions the driver's ->atomic_check likely
|
|
||||||
* relies on.
|
|
||||||
*
|
|
||||||
* Hence we must clear all cached state and completely start over, using this
|
|
||||||
* function.
|
|
||||||
*/
|
*/
|
||||||
void drm_atomic_state_clear(struct drm_atomic_state *state)
|
void drm_atomic_state_default_clear(struct drm_atomic_state *state)
|
||||||
{
|
{
|
||||||
struct drm_device *dev = state->dev;
|
struct drm_device *dev = state->dev;
|
||||||
struct drm_mode_config *config = &dev->mode_config;
|
struct drm_mode_config *config = &dev->mode_config;
|
||||||
|
@ -162,6 +185,32 @@ void drm_atomic_state_clear(struct drm_atomic_state *state)
|
||||||
state->plane_states[i] = NULL;
|
state->plane_states[i] = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
EXPORT_SYMBOL(drm_atomic_state_default_clear);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* drm_atomic_state_clear - clear state object
|
||||||
|
* @state: atomic state
|
||||||
|
*
|
||||||
|
* When the w/w mutex algorithm detects a deadlock we need to back off and drop
|
||||||
|
* all locks. So someone else could sneak in and change the current modeset
|
||||||
|
* configuration. Which means that all the state assembled in @state is no
|
||||||
|
* longer an atomic update to the current state, but to some arbitrary earlier
|
||||||
|
* state. Which could break assumptions the driver's ->atomic_check likely
|
||||||
|
* relies on.
|
||||||
|
*
|
||||||
|
* Hence we must clear all cached state and completely start over, using this
|
||||||
|
* function.
|
||||||
|
*/
|
||||||
|
void drm_atomic_state_clear(struct drm_atomic_state *state)
|
||||||
|
{
|
||||||
|
struct drm_device *dev = state->dev;
|
||||||
|
struct drm_mode_config *config = &dev->mode_config;
|
||||||
|
|
||||||
|
if (config->funcs->atomic_state_clear)
|
||||||
|
config->funcs->atomic_state_clear(state);
|
||||||
|
else
|
||||||
|
drm_atomic_state_default_clear(state);
|
||||||
|
}
|
||||||
EXPORT_SYMBOL(drm_atomic_state_clear);
|
EXPORT_SYMBOL(drm_atomic_state_clear);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -173,14 +222,25 @@ EXPORT_SYMBOL(drm_atomic_state_clear);
|
||||||
*/
|
*/
|
||||||
void drm_atomic_state_free(struct drm_atomic_state *state)
|
void drm_atomic_state_free(struct drm_atomic_state *state)
|
||||||
{
|
{
|
||||||
|
struct drm_device *dev;
|
||||||
|
struct drm_mode_config *config;
|
||||||
|
|
||||||
if (!state)
|
if (!state)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
dev = state->dev;
|
||||||
|
config = &dev->mode_config;
|
||||||
|
|
||||||
drm_atomic_state_clear(state);
|
drm_atomic_state_clear(state);
|
||||||
|
|
||||||
DRM_DEBUG_ATOMIC("Freeing atomic state %p\n", state);
|
DRM_DEBUG_ATOMIC("Freeing atomic state %p\n", state);
|
||||||
|
|
||||||
kfree_state(state);
|
if (config->funcs->atomic_state_free) {
|
||||||
|
config->funcs->atomic_state_free(state);
|
||||||
|
} else {
|
||||||
|
drm_atomic_state_default_release(state);
|
||||||
|
kfree(state);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(drm_atomic_state_free);
|
EXPORT_SYMBOL(drm_atomic_state_free);
|
||||||
|
|
||||||
|
|
|
@ -35,6 +35,11 @@ drm_atomic_state_alloc(struct drm_device *dev);
|
||||||
void drm_atomic_state_clear(struct drm_atomic_state *state);
|
void drm_atomic_state_clear(struct drm_atomic_state *state);
|
||||||
void drm_atomic_state_free(struct drm_atomic_state *state);
|
void drm_atomic_state_free(struct drm_atomic_state *state);
|
||||||
|
|
||||||
|
int __must_check
|
||||||
|
drm_atomic_state_init(struct drm_device *dev, struct drm_atomic_state *state);
|
||||||
|
void drm_atomic_state_default_clear(struct drm_atomic_state *state);
|
||||||
|
void drm_atomic_state_default_release(struct drm_atomic_state *state);
|
||||||
|
|
||||||
struct drm_crtc_state * __must_check
|
struct drm_crtc_state * __must_check
|
||||||
drm_atomic_get_crtc_state(struct drm_atomic_state *state,
|
drm_atomic_get_crtc_state(struct drm_atomic_state *state,
|
||||||
struct drm_crtc *crtc);
|
struct drm_crtc *crtc);
|
||||||
|
|
|
@ -979,6 +979,9 @@ struct drm_mode_set {
|
||||||
* @atomic_check: check whether a given atomic state update is possible
|
* @atomic_check: check whether a given atomic state update is possible
|
||||||
* @atomic_commit: commit an atomic state update previously verified with
|
* @atomic_commit: commit an atomic state update previously verified with
|
||||||
* atomic_check()
|
* atomic_check()
|
||||||
|
* @atomic_state_alloc: allocate a new atomic state
|
||||||
|
* @atomic_state_clear: clear the atomic state
|
||||||
|
* @atomic_state_free: free the atomic state
|
||||||
*
|
*
|
||||||
* Some global (i.e. not per-CRTC, connector, etc) mode setting functions that
|
* Some global (i.e. not per-CRTC, connector, etc) mode setting functions that
|
||||||
* involve drivers.
|
* involve drivers.
|
||||||
|
@ -994,6 +997,9 @@ struct drm_mode_config_funcs {
|
||||||
int (*atomic_commit)(struct drm_device *dev,
|
int (*atomic_commit)(struct drm_device *dev,
|
||||||
struct drm_atomic_state *a,
|
struct drm_atomic_state *a,
|
||||||
bool async);
|
bool async);
|
||||||
|
struct drm_atomic_state *(*atomic_state_alloc)(struct drm_device *dev);
|
||||||
|
void (*atomic_state_clear)(struct drm_atomic_state *state);
|
||||||
|
void (*atomic_state_free)(struct drm_atomic_state *state);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Загрузка…
Ссылка в новой задаче