![Daniel Vetter](/assets/img/avatar_default.png)
All collected together to provide a consistent story in one patch, instead of the somewhat bumpy refactor-evolution leading to this. Also some thoughts on what the next steps could be: - Create a macro called devm_drm_dev_alloc() which essentially wraps the kzalloc(); devm_drm_dev_init(); drmm_add_final_kfree() combo. Needs to be a macro since we'll have to do some typeof trickery and casting to make this fully generic for all drivers that embed struct drm_device into their own thing. - A lot of the simple drivers now have essentially just drm_dev_unplug(); drm_atomic_helper_shutdown(); as their $bus_driver->remove hook. We could create a devm_mode_config_reset which sets drm_atomic_helper_shutdown as it's cleanup action, and a devm_drm_dev_register with drm_dev_unplug as it's cleanup action, and simple drivers wouldn't have a need for a ->remove function at all, and we could delete them. - For more complicated drivers we need drmm_ versions of a _lot_ more things. All the userspace visible objects (crtc, plane, encoder, crtc), anything else hanging of those (maybe a drmm_get_edid, at least for panels and other built-in stuff). Also some more thoughts on why we're not reusing devm_ with maybe a fake struct device embedded into the drm_device (we can't use the kdev, since that's in each drm_minor). - Code review gets extremely tricky, since every time you see a devm_ you need to carefully check whether the fake device (with the drm_device lifetim) or the real device (with the lifetim of the underlying physical device and driver binding) are used. That's not going to help at all, and we have enormous amounts of drivers who use devm_ where they really shouldn't. Having different types makes sure the compiler type checks this for us and ensures correctness. - The set of functions are very much non-overlapping. E.g. devm_ioremap makes total sense, drmm_ioremap has the wrong lifetime, since hw resources need to be cleaned out at driver unbind and wont outlive that like a drm_device. Similar, but other way round for drmm_connector_init (which is the only correct version, devm_ for drm_connector is just buggy). Simply not having the wrong version again prevents bugs. Finally I guess this opens a huge todo for all the drivers. I'm semi-tempted to do a tree-wide s/devm_kzalloc/drmm_kzalloc/ since most likely that'll fix an enormous amount of bugs and most likely not cause any issues at all (aside from maybe holding onto memory slightly too long). v2: - Doc improvements from Laurent. - Also add kerneldoc for the new drmm_add_action_or_reset. v3: - Remove kerneldoc for drmm_remove_action. Reviewed-by: Sam Ravnborg <sam@ravnborg.org> Cc: Sam Ravnborg <sam@ravnborg.org> Cc: Jonathan Corbet <corbet@lwn.net> Cc: linux-doc@vger.kernel.org Cc: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Cc: "Rafael J. Wysocki" <rafael@kernel.org> Signed-off-by: Daniel Vetter <daniel.vetter@intel.com> fixup docs Link: https://patchwork.freedesktop.org/patch/msgid/20200323144950.3018436-52-daniel.vetter@ffwll.ch
110 lines
3.4 KiB
C
110 lines
3.4 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
|
|
#ifndef _DRM_MANAGED_H_
|
|
#define _DRM_MANAGED_H_
|
|
|
|
#include <linux/gfp.h>
|
|
#include <linux/overflow.h>
|
|
#include <linux/types.h>
|
|
|
|
struct drm_device;
|
|
|
|
typedef void (*drmres_release_t)(struct drm_device *dev, void *res);
|
|
|
|
/**
|
|
* drmm_add_action - add a managed release action to a &drm_device
|
|
* @dev: DRM device
|
|
* @action: function which should be called when @dev is released
|
|
* @data: opaque pointer, passed to @action
|
|
*
|
|
* This function adds the @release action with optional parameter @data to the
|
|
* list of cleanup actions for @dev. The cleanup actions will be run in reverse
|
|
* order in the final drm_dev_put() call for @dev.
|
|
*/
|
|
#define drmm_add_action(dev, action, data) \
|
|
__drmm_add_action(dev, action, data, #action)
|
|
|
|
int __must_check __drmm_add_action(struct drm_device *dev,
|
|
drmres_release_t action,
|
|
void *data, const char *name);
|
|
|
|
/**
|
|
* drmm_add_action_or_reset - add a managed release action to a &drm_device
|
|
* @dev: DRM device
|
|
* @action: function which should be called when @dev is released
|
|
* @data: opaque pointer, passed to @action
|
|
*
|
|
* Similar to drmm_add_action(), with the only difference that upon failure
|
|
* @action is directly called for any cleanup work necessary on failures.
|
|
*/
|
|
#define drmm_add_action_or_reset(dev, action, data) \
|
|
__drmm_add_action_or_reset(dev, action, data, #action)
|
|
|
|
int __must_check __drmm_add_action_or_reset(struct drm_device *dev,
|
|
drmres_release_t action,
|
|
void *data, const char *name);
|
|
|
|
void drmm_add_final_kfree(struct drm_device *dev, void *container);
|
|
|
|
void *drmm_kmalloc(struct drm_device *dev, size_t size, gfp_t gfp) __malloc;
|
|
|
|
/**
|
|
* drmm_kzalloc - &drm_device managed kzalloc()
|
|
* @dev: DRM device
|
|
* @size: size of the memory allocation
|
|
* @gfp: GFP allocation flags
|
|
*
|
|
* This is a &drm_device managed version of kzalloc(). The allocated memory is
|
|
* automatically freed on the final drm_dev_put(). Memory can also be freed
|
|
* before the final drm_dev_put() by calling drmm_kfree().
|
|
*/
|
|
static inline void *drmm_kzalloc(struct drm_device *dev, size_t size, gfp_t gfp)
|
|
{
|
|
return drmm_kmalloc(dev, size, gfp | __GFP_ZERO);
|
|
}
|
|
|
|
/**
|
|
* drmm_kmalloc_array - &drm_device managed kmalloc_array()
|
|
* @dev: DRM device
|
|
* @n: number of array elements to allocate
|
|
* @size: size of array member
|
|
* @flags: GFP allocation flags
|
|
*
|
|
* This is a &drm_device managed version of kmalloc_array(). The allocated
|
|
* memory is automatically freed on the final drm_dev_put() and works exactly
|
|
* like a memory allocation obtained by drmm_kmalloc().
|
|
*/
|
|
static inline void *drmm_kmalloc_array(struct drm_device *dev,
|
|
size_t n, size_t size, gfp_t flags)
|
|
{
|
|
size_t bytes;
|
|
|
|
if (unlikely(check_mul_overflow(n, size, &bytes)))
|
|
return NULL;
|
|
|
|
return drmm_kmalloc(dev, bytes, flags);
|
|
}
|
|
|
|
/**
|
|
* drmm_kcalloc - &drm_device managed kcalloc()
|
|
* @dev: DRM device
|
|
* @n: number of array elements to allocate
|
|
* @size: size of array member
|
|
* @flags: GFP allocation flags
|
|
*
|
|
* This is a &drm_device managed version of kcalloc(). The allocated memory is
|
|
* automatically freed on the final drm_dev_put() and works exactly like a
|
|
* memory allocation obtained by drmm_kmalloc().
|
|
*/
|
|
static inline void *drmm_kcalloc(struct drm_device *dev,
|
|
size_t n, size_t size, gfp_t flags)
|
|
{
|
|
return drmm_kmalloc_array(dev, n, size, flags | __GFP_ZERO);
|
|
}
|
|
|
|
char *drmm_kstrdup(struct drm_device *dev, const char *s, gfp_t gfp);
|
|
|
|
void drmm_kfree(struct drm_device *dev, void *data);
|
|
|
|
#endif
|