diff options
Diffstat (limited to 'drivers/gpu/drm/drm_managed.c')
| -rw-r--r-- | drivers/gpu/drm/drm_managed.c | 82 |
1 files changed, 64 insertions, 18 deletions
diff --git a/drivers/gpu/drm/drm_managed.c b/drivers/gpu/drm/drm_managed.c index 9cebfe370a65..247f468731de 100644 --- a/drivers/gpu/drm/drm_managed.c +++ b/drivers/gpu/drm/drm_managed.c @@ -7,13 +7,17 @@ #include <drm/drm_managed.h> +#include <linux/export.h> #include <linux/list.h> +#include <linux/mutex.h> #include <linux/slab.h> #include <linux/spinlock.h> #include <drm/drm_device.h> #include <drm/drm_print.h> +#include "drm_internal.h" + /** * DOC: managed resources * @@ -25,7 +29,7 @@ * be done directly with drmm_kmalloc() and the related functions. Everything * will be released on the final drm_dev_put() in reverse order of how the * release actions have been added and memory has been allocated since driver - * loading started with drm_dev_init(). + * loading started with devm_drm_dev_alloc(). * * Note that release actions and managed memory can also be added and removed * during the lifetime of the driver, all the functions are fully concurrent @@ -46,10 +50,10 @@ struct drmres { * Some archs want to perform DMA into kmalloc caches * and need a guaranteed alignment larger than * the alignment of a 64-bit integer. - * Thus we use ARCH_KMALLOC_MINALIGN here and get exactly the same - * buffer alignment as if it was allocated by plain kmalloc(). + * Thus we use ARCH_DMA_MINALIGN for data[] which will force the same + * alignment for struct drmres when allocated by kmalloc(). */ - u8 __aligned(ARCH_KMALLOC_MINALIGN) data[]; + u8 __aligned(ARCH_DMA_MINALIGN) data[]; }; static void free_dr(struct drmres *dr) @@ -123,18 +127,6 @@ static void add_dr(struct drm_device *dev, struct drmres *dr) dr, dr->node.name, (unsigned long) dr->node.size); } -/** - * drmm_add_final_kfree - add release action for the final kfree() - * @dev: DRM device - * @container: pointer to the kmalloc allocation containing @dev - * - * Since the allocation containing the struct &drm_device must be allocated - * before it can be initialized with drm_dev_init() there's no way to allocate - * that memory with drmm_kmalloc(). To side-step this chicken-egg problem the - * pointer for this final kfree() must be specified by calling this function. It - * will be released in the final drm_dev_put() for @dev, after all other release - * actions installed through drmm_add_action() have been processed. - */ void drmm_add_final_kfree(struct drm_device *dev, void *container) { WARN_ON(dev->managed.final_kfree); @@ -142,7 +134,6 @@ void drmm_add_final_kfree(struct drm_device *dev, void *container) WARN_ON(dev + 1 > (struct drm_device *) (container + ksize(container))); dev->managed.final_kfree = container; } -EXPORT_SYMBOL(drmm_add_final_kfree); int __drmm_add_action(struct drm_device *dev, drmres_release_t action, @@ -187,6 +178,45 @@ int __drmm_add_action_or_reset(struct drm_device *dev, EXPORT_SYMBOL(__drmm_add_action_or_reset); /** + * drmm_release_action - release a managed action from a &drm_device + * @dev: DRM device + * @action: function which would be called when @dev is released + * @data: opaque pointer, passed to @action + * + * This function calls the @action previously added by drmm_add_action() + * immediately. + * The @action is removed from the list of cleanup actions for @dev, + * which means that it won't be called in the final drm_dev_put(). + */ +void drmm_release_action(struct drm_device *dev, + drmres_release_t action, + void *data) +{ + struct drmres *dr_match = NULL, *dr; + unsigned long flags; + + spin_lock_irqsave(&dev->managed.lock, flags); + list_for_each_entry_reverse(dr, &dev->managed.resources, node.entry) { + if (dr->node.release == action) { + if (!data || *(void **)dr->data == data) { + dr_match = dr; + del_dr(dev, dr_match); + break; + } + } + } + spin_unlock_irqrestore(&dev->managed.lock, flags); + + if (WARN_ON(!dr_match)) + return; + + action(dev, data); + + free_dr(dr_match); +} +EXPORT_SYMBOL(drmm_release_action); + +/** * drmm_kmalloc - &drm_device managed kmalloc() * @dev: DRM device * @size: size of the memory allocation @@ -206,7 +236,7 @@ void *drmm_kmalloc(struct drm_device *dev, size_t size, gfp_t gfp) size, gfp); return NULL; } - dr->node.name = kstrdup_const("kmalloc", GFP_KERNEL); + dr->node.name = kstrdup_const("kmalloc", gfp); add_dr(dev, dr); @@ -273,3 +303,19 @@ void drmm_kfree(struct drm_device *dev, void *data) free_dr(dr_match); } EXPORT_SYMBOL(drmm_kfree); + +void __drmm_mutex_release(struct drm_device *dev, void *res) +{ + struct mutex *lock = res; + + mutex_destroy(lock); +} +EXPORT_SYMBOL(__drmm_mutex_release); + +void __drmm_workqueue_release(struct drm_device *device, void *res) +{ + struct workqueue_struct *wq = res; + + destroy_workqueue(wq); +} +EXPORT_SYMBOL(__drmm_workqueue_release); |
