[v2,02/17] drm/atomic: Allow drivers to subclass drm_atomic_state, v3
diff mbox

Message ID 55599D90.7070601@linux.intel.com
State New
Headers show

Commit Message

Maarten Lankhorst May 18, 2015, 8:06 a.m. UTC
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>

Comments

Daniel Vetter May 18, 2015, 2:40 p.m. UTC | #1
On Mon, May 18, 2015 at 10:06:40AM +0200, Maarten Lankhorst wrote:
> 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.

I'd have gone with just _release since we don't have a ->release hook nor
a drm_atomic_helper_state_release wrapper. But that's really a bikeshed
now ;-)

> 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>

Applied to topic/drm-misc, thanks.
-Daniel

> 
> diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
> index c6277a4a1f2f..cd1b16b25716 100644
> --- a/drivers/gpu/drm/drm_atomic.c
> +++ b/drivers/gpu/drm/drm_atomic.c
> @@ -30,7 +30,15 @@
>  #include <drm/drm_atomic.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->connector_states);
> @@ -38,24 +46,20 @@ static void kfree_state(struct drm_atomic_state *state)
>  	kfree(state->crtc_states);
>  	kfree(state->planes);
>  	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
> + * @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 *
> -drm_atomic_state_alloc(struct drm_device *dev)
> +int
> +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
>  	 * setting this appropriately?
>  	 */
> @@ -92,31 +96,50 @@ drm_atomic_state_alloc(struct drm_device *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:
> -	kfree_state(state);
> +	drm_atomic_state_default_release(state);
> +	return -ENOMEM;
> +}
> +EXPORT_SYMBOL(drm_atomic_state_init);
> +
> +/**
> + * 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 NULL;
> +	return config->funcs->atomic_state_alloc(dev);
>  }
>  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
>   *
> - * 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.
> + * Default implementation for clearing atomic state.
> + * This is useful for drivers that subclass the atomic state.
>   */
> -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_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;
>  	}
>  }
> +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);
>  
>  /**
> @@ -173,14 +222,25 @@ EXPORT_SYMBOL(drm_atomic_state_clear);
>   */
>  void drm_atomic_state_free(struct drm_atomic_state *state)
>  {
> +	struct drm_device *dev;
> +	struct drm_mode_config *config;
> +
>  	if (!state)
>  		return;
>  
> +	dev = state->dev;
> +	config = &dev->mode_config;
> +
>  	drm_atomic_state_clear(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);
>  
> diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h
> index d78543067700..f0d3a7387d99 100644
> --- a/include/drm/drm_atomic.h
> +++ b/include/drm/drm_atomic.h
> @@ -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_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
>  drm_atomic_get_crtc_state(struct drm_atomic_state *state,
>  			  struct drm_crtc *crtc);
> diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
> index 840e9e62878c..bff25b0cada9 100644
> --- a/include/drm/drm_crtc.h
> +++ b/include/drm/drm_crtc.h
> @@ -985,6 +985,9 @@ struct drm_mode_set {
>   * @atomic_check: check whether a given atomic state update is possible
>   * @atomic_commit: commit an atomic state update previously verified with
>   * 	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
>   * involve drivers.
> @@ -1000,6 +1003,9 @@ struct drm_mode_config_funcs {
>  	int (*atomic_commit)(struct drm_device *dev,
>  			     struct drm_atomic_state *a,
>  			     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);
>  };
>  
>  /**
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/intel-gfx

Patch
diff mbox

diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
index c6277a4a1f2f..cd1b16b25716 100644
--- a/drivers/gpu/drm/drm_atomic.c
+++ b/drivers/gpu/drm/drm_atomic.c
@@ -30,7 +30,15 @@ 
 #include <drm/drm_atomic.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->connector_states);
@@ -38,24 +46,20 @@  static void kfree_state(struct drm_atomic_state *state)
 	kfree(state->crtc_states);
 	kfree(state->planes);
 	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
+ * @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 *
-drm_atomic_state_alloc(struct drm_device *dev)
+int
+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
 	 * setting this appropriately?
 	 */
@@ -92,31 +96,50 @@  drm_atomic_state_alloc(struct drm_device *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:
-	kfree_state(state);
+	drm_atomic_state_default_release(state);
+	return -ENOMEM;
+}
+EXPORT_SYMBOL(drm_atomic_state_init);
+
+/**
+ * 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 NULL;
+	return config->funcs->atomic_state_alloc(dev);
 }
 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
  *
- * 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.
+ * Default implementation for clearing atomic state.
+ * This is useful for drivers that subclass the atomic state.
  */
-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_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;
 	}
 }
+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);
 
 /**
@@ -173,14 +222,25 @@  EXPORT_SYMBOL(drm_atomic_state_clear);
  */
 void drm_atomic_state_free(struct drm_atomic_state *state)
 {
+	struct drm_device *dev;
+	struct drm_mode_config *config;
+
 	if (!state)
 		return;
 
+	dev = state->dev;
+	config = &dev->mode_config;
+
 	drm_atomic_state_clear(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);
 
diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h
index d78543067700..f0d3a7387d99 100644
--- a/include/drm/drm_atomic.h
+++ b/include/drm/drm_atomic.h
@@ -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_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
 drm_atomic_get_crtc_state(struct drm_atomic_state *state,
 			  struct drm_crtc *crtc);
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index 840e9e62878c..bff25b0cada9 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -985,6 +985,9 @@  struct drm_mode_set {
  * @atomic_check: check whether a given atomic state update is possible
  * @atomic_commit: commit an atomic state update previously verified with
  * 	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
  * involve drivers.
@@ -1000,6 +1003,9 @@  struct drm_mode_config_funcs {
 	int (*atomic_commit)(struct drm_device *dev,
 			     struct drm_atomic_state *a,
 			     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);
 };
 
 /**