From 55f7f72753abdd46f35d027a25b43969dba56fac Mon Sep 17 00:00:00 2001 From: Andrzej Pietrasiewicz Date: Wed, 11 Mar 2020 15:55:37 +0100 Subject: drm/core: Add drm_afbc_framebuffer and a corresponding helper The new struct contains afbc-specific data. The new function can be used by drivers which support afbc to complete the preparation of struct drm_afbc_framebuffer. It must be called after allocating the said struct and calling drm_gem_fb_init_with_funcs(). Signed-off-by: Andrzej Pietrasiewicz Reviewed-by: Emil Velikov Reviewed-by: James Qian Wang Acked-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/20200311145541.29186-3-andrzej.p@collabora.com --- Documentation/gpu/todo.rst | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'Documentation/gpu') diff --git a/Documentation/gpu/todo.rst b/Documentation/gpu/todo.rst index 439656f55c5d..37a3a023c114 100644 --- a/Documentation/gpu/todo.rst +++ b/Documentation/gpu/todo.rst @@ -404,6 +404,21 @@ Contact: Laurent Pinchart, respective driver maintainers Level: Intermediate +Encode cpp properly in malidp +----------------------------- + +cpp (chars per pixel) is not encoded properly in malidp, zero is +used instead. afbc implementation needs bpp or cpp, but if it is +zero it needs to be provided elsewhere, and so the bpp field exists +in struct drm_afbc_framebuffer. + +Properly encode cpp in malidp and remove the bpp field in struct +drm_afbc_framebuffer. + +Contact: malidp maintainers + +Level: Intermediate + Core refactorings ================= -- cgit v1.2.3 From c6603c740e0e3492c9c95fdab833375bf7117b6b Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 24 Mar 2020 13:45:40 +0100 Subject: drm: add managed resources tied to drm_device We have lots of these. And the cleanup code tends to be of dubious quality. The biggest wrong pattern is that developers use devm_, which ties the release action to the underlying struct device, whereas all the userspace visible stuff attached to a drm_device can long outlive that one (e.g. after a hotunplug while userspace has open files and mmap'ed buffers). Give people what they want, but with more correctness. Mostly copied from devres.c, with types adjusted to fit drm_device and a few simplifications - I didn't (yet) copy over everything. Since the types don't match code sharing looked like a hopeless endeavour. For now it's only super simplified, no groups, you can't remove actions (but kfree exists, we'll need that soon). Plus all specific to drm_device ofc, including the logging. Which I didn't bother to make compile-time optional, since none of the other drm logging is compile time optional either. One tricky bit here is the chicken&egg between allocating your drm_device structure and initiliazing it with drm_dev_init. For perfect onion unwinding we'd need to have the action to kfree the allocation registered before drm_dev_init registers any of its own release handlers. But drm_dev_init doesn't know where exactly the drm_device is emebedded into the overall structure, and by the time it returns it'll all be too late. And forcing drivers to be able clean up everything except the one kzalloc is silly. Work around this by having a very special final_kfree pointer. This also avoids troubles with the list head possibly disappearing from underneath us when we release all resources attached to the drm_device. v2: Do all the kerneldoc at the end, to avoid lots of fairly pointless shuffling while getting everything into shape. v3: Add static to add/del_dr (Neil) Move typo fix to the right patch (Neil) v4: Enforce contract for drmm_add_final_kfree: Use ksize() to check that the drm_device is indeed contained somewhere in the final kfree(). Because we need that or the entire managed release logic blows up in a pile of use-after-frees. Motivated by a discussion with Laurent. v5: Review from Laurent: - %zu instead of casting size_t - header guards - sorting of includes - guarding of data assignment if we didn't allocate it for a NULL pointer - delete spurious newline - cast void* data parameter correctly in ->release call, no idea how this even worked before v6: Review from Sam - Add the kerneldoc for the managed sub-struct back in, even if it doesn't show up in the generated html somehow. - Explain why __always_inline. - Fix bisectability around the final kfree() in drm_dev_relase(). This is just interim code which will disappear again. - Some whitespace polish. - Add debug output when drmm_add_action or drmm_kmalloc fail. v7: My bisectability fix wasn't up to par as noticed by smatch. v8: Remove unecessary {} around if else v9: Use kstrdup_const, which requires kfree_const and introducing a free_dr() helper (Thomas). v10: kfree_const goes boom on the plain "kmalloc" assignment, somehow we need to wrap that in kstrdup_const() too!! Also renumber revision log, I somehow reset it midway thruh. Reviewed-by: Sam Ravnborg Cc: Thomas Zimmermann Cc: Dan Carpenter Cc: Sam Ravnborg Cc: Laurent Pinchart Cc: Neil Armstrong Cc: "Rafael J. Wysocki" Signed-off-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/20200324124540.3227396-1-daniel.vetter@ffwll.ch --- Documentation/gpu/drm-internals.rst | 6 ++ drivers/gpu/drm/Makefile | 3 +- drivers/gpu/drm/drm_drv.c | 15 ++- drivers/gpu/drm/drm_internal.h | 3 + drivers/gpu/drm/drm_managed.c | 193 ++++++++++++++++++++++++++++++++++++ include/drm/drm_device.h | 15 +++ include/drm/drm_managed.h | 30 ++++++ include/drm/drm_print.h | 6 ++ 8 files changed, 267 insertions(+), 4 deletions(-) create mode 100644 drivers/gpu/drm/drm_managed.c create mode 100644 include/drm/drm_managed.h (limited to 'Documentation/gpu') diff --git a/Documentation/gpu/drm-internals.rst b/Documentation/gpu/drm-internals.rst index a73320576ca9..a6b6145fda78 100644 --- a/Documentation/gpu/drm-internals.rst +++ b/Documentation/gpu/drm-internals.rst @@ -132,6 +132,12 @@ be unmapped; on many devices, the ROM address decoder is shared with other BARs, so leaving it mapped could cause undesired behaviour like hangs or memory corruption. +Managed Resources +----------------- + +.. kernel-doc:: drivers/gpu/drm/drm_managed.c + :doc: managed resources + Bus-specific Device Registration and PCI Support ------------------------------------------------ diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index 7f72ef5e7811..183c60048307 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile @@ -17,7 +17,8 @@ drm-y := drm_auth.o drm_cache.o \ drm_plane.o drm_color_mgmt.o drm_print.o \ drm_dumb_buffers.o drm_mode_config.o drm_vblank.o \ drm_syncobj.o drm_lease.o drm_writeback.o drm_client.o \ - drm_client_modeset.o drm_atomic_uapi.o drm_hdcp.o + drm_client_modeset.o drm_atomic_uapi.o drm_hdcp.o \ + drm_managed.o drm-$(CONFIG_DRM_LEGACY) += drm_legacy_misc.o drm_bufs.o drm_context.o drm_dma.o drm_scatter.o drm_lock.o drm-$(CONFIG_DRM_LIB_RANDOM) += lib/drm_random.o diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c index 65a0acb79323..a1884005d983 100644 --- a/drivers/gpu/drm/drm_drv.c +++ b/drivers/gpu/drm/drm_drv.c @@ -629,6 +629,9 @@ int drm_dev_init(struct drm_device *dev, dev->dev = get_device(parent); dev->driver = driver; + INIT_LIST_HEAD(&dev->managed.resources); + spin_lock_init(&dev->managed.lock); + /* no per-device feature limits by default */ dev->driver_features = ~0u; @@ -824,12 +827,18 @@ static void drm_dev_release(struct kref *ref) { struct drm_device *dev = container_of(ref, struct drm_device, ref); - if (dev->driver->release) { + if (dev->driver->release) dev->driver->release(dev); - } else { + else drm_dev_fini(dev); + + drm_managed_release(dev); + + if (!dev->driver->release && !dev->managed.final_kfree) { + WARN_ON(!list_empty(&dev->managed.resources)); kfree(dev); - } + } else if (dev->managed.final_kfree) + kfree(dev->managed.final_kfree); } /** diff --git a/drivers/gpu/drm/drm_internal.h b/drivers/gpu/drm/drm_internal.h index 8b9e8bbca9b1..23ba15773097 100644 --- a/drivers/gpu/drm/drm_internal.h +++ b/drivers/gpu/drm/drm_internal.h @@ -89,6 +89,9 @@ void drm_prime_remove_buf_handle_locked(struct drm_prime_file_private *prime_fpr struct drm_minor *drm_minor_acquire(unsigned int minor_id); void drm_minor_release(struct drm_minor *minor); +/* drm_managed.c */ +void drm_managed_release(struct drm_device *dev); + /* drm_vblank.c */ void drm_vblank_disable_and_save(struct drm_device *dev, unsigned int pipe); void drm_vblank_cleanup(struct drm_device *dev); diff --git a/drivers/gpu/drm/drm_managed.c b/drivers/gpu/drm/drm_managed.c new file mode 100644 index 000000000000..46d679b66e4d --- /dev/null +++ b/drivers/gpu/drm/drm_managed.c @@ -0,0 +1,193 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2020 Intel + * + * Based on drivers/base/devres.c + */ + +#include + +#include +#include +#include + +#include +#include + +/** + * DOC: managed resources + * + * Inspired by struct &device managed resources, but tied to the lifetime of + * struct &drm_device, which can outlive the underlying physical device, usually + * when userspace has some open files and other handles to resources still open. + */ +struct drmres_node { + struct list_head entry; + drmres_release_t release; + const char *name; + size_t size; +}; + +struct drmres { + struct drmres_node node; + /* + * 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(). + */ + u8 __aligned(ARCH_KMALLOC_MINALIGN) data[]; +}; + +static void free_dr(struct drmres *dr) +{ + kfree_const(dr->node.name); + kfree(dr); +} + +void drm_managed_release(struct drm_device *dev) +{ + struct drmres *dr, *tmp; + + drm_dbg_drmres(dev, "drmres release begin\n"); + list_for_each_entry_safe(dr, tmp, &dev->managed.resources, node.entry) { + drm_dbg_drmres(dev, "REL %p %s (%zu bytes)\n", + dr, dr->node.name, dr->node.size); + + if (dr->node.release) + dr->node.release(dev, dr->node.size ? *(void **)&dr->data : NULL); + + list_del(&dr->node.entry); + free_dr(dr); + } + drm_dbg_drmres(dev, "drmres release end\n"); +} + +/* + * Always inline so that kmalloc_track_caller tracks the actual interesting + * caller outside of drm_managed.c. + */ +static __always_inline struct drmres * alloc_dr(drmres_release_t release, + size_t size, gfp_t gfp, int nid) +{ + size_t tot_size; + struct drmres *dr; + + /* We must catch any near-SIZE_MAX cases that could overflow. */ + if (unlikely(check_add_overflow(sizeof(*dr), size, &tot_size))) + return NULL; + + dr = kmalloc_node_track_caller(tot_size, gfp, nid); + if (unlikely(!dr)) + return NULL; + + memset(dr, 0, offsetof(struct drmres, data)); + + INIT_LIST_HEAD(&dr->node.entry); + dr->node.release = release; + dr->node.size = size; + + return dr; +} + +static void del_dr(struct drm_device *dev, struct drmres *dr) +{ + list_del_init(&dr->node.entry); + + drm_dbg_drmres(dev, "DEL %p %s (%lu bytes)\n", + dr, dr->node.name, (unsigned long) dr->node.size); +} + +static void add_dr(struct drm_device *dev, struct drmres *dr) +{ + unsigned long flags; + + spin_lock_irqsave(&dev->managed.lock, flags); + list_add(&dr->node.entry, &dev->managed.resources); + spin_unlock_irqrestore(&dev->managed.lock, flags); + + drm_dbg_drmres(dev, "ADD %p %s (%lu bytes)\n", + dr, dr->node.name, (unsigned long) dr->node.size); +} + +void drmm_add_final_kfree(struct drm_device *dev, void *container) +{ + WARN_ON(dev->managed.final_kfree); + WARN_ON(dev < (struct drm_device *) 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, + void *data, const char *name) +{ + struct drmres *dr; + void **void_ptr; + + dr = alloc_dr(action, data ? sizeof(void*) : 0, + GFP_KERNEL | __GFP_ZERO, + dev_to_node(dev->dev)); + if (!dr) { + drm_dbg_drmres(dev, "failed to add action %s for %p\n", + name, data); + return -ENOMEM; + } + + dr->node.name = kstrdup_const(name, GFP_KERNEL); + if (data) { + void_ptr = (void **)&dr->data; + *void_ptr = data; + } + + add_dr(dev, dr); + + return 0; +} +EXPORT_SYMBOL(__drmm_add_action); + +void *drmm_kmalloc(struct drm_device *dev, size_t size, gfp_t gfp) +{ + struct drmres *dr; + + dr = alloc_dr(NULL, size, gfp, dev_to_node(dev->dev)); + if (!dr) { + drm_dbg_drmres(dev, "failed to allocate %zu bytes, %u flags\n", + size, gfp); + return NULL; + } + dr->node.name = kstrdup_const("kmalloc", GFP_KERNEL); + + add_dr(dev, dr); + + return dr->data; +} +EXPORT_SYMBOL(drmm_kmalloc); + +void drmm_kfree(struct drm_device *dev, void *data) +{ + struct drmres *dr_match = NULL, *dr; + unsigned long flags; + + if (!data) + return; + + spin_lock_irqsave(&dev->managed.lock, flags); + list_for_each_entry(dr, &dev->managed.resources, node.entry) { + if (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; + + free_dr(dr_match); +} +EXPORT_SYMBOL(drmm_kfree); diff --git a/include/drm/drm_device.h b/include/drm/drm_device.h index bb60a949f416..d39132b477dd 100644 --- a/include/drm/drm_device.h +++ b/include/drm/drm_device.h @@ -67,6 +67,21 @@ struct drm_device { /** @dev: Device structure of bus-device */ struct device *dev; + /** + * @managed: + * + * Managed resources linked to the lifetime of this &drm_device as + * tracked by @ref. + */ + struct { + /** @managed.resources: managed resources list */ + struct list_head resources; + /** @managed.final_kfree: pointer for final kfree() call */ + void *final_kfree; + /** @managed.lock: protects @managed.resources */ + spinlock_t lock; + } managed; + /** @driver: DRM driver managing the device */ struct drm_driver *driver; diff --git a/include/drm/drm_managed.h b/include/drm/drm_managed.h new file mode 100644 index 000000000000..7b5df7d09b19 --- /dev/null +++ b/include/drm/drm_managed.h @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: GPL-2.0 + +#ifndef _DRM_MANAGED_H_ +#define _DRM_MANAGED_H_ + +#include +#include + +struct drm_device; + +typedef void (*drmres_release_t)(struct drm_device *dev, void *res); + +#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); + +void drmm_add_final_kfree(struct drm_device *dev, void *parent); + +void *drmm_kmalloc(struct drm_device *dev, size_t size, gfp_t gfp) __malloc; +static inline void *drmm_kzalloc(struct drm_device *dev, size_t size, gfp_t gfp) +{ + return drmm_kmalloc(dev, size, gfp | __GFP_ZERO); +} + +void drmm_kfree(struct drm_device *dev, void *data); + +#endif diff --git a/include/drm/drm_print.h b/include/drm/drm_print.h index ca7cee8e728a..1c9417430d08 100644 --- a/include/drm/drm_print.h +++ b/include/drm/drm_print.h @@ -313,6 +313,10 @@ enum drm_debug_category { * @DRM_UT_DP: Used in the DP code. */ DRM_UT_DP = 0x100, + /** + * @DRM_UT_DRMRES: Used in the drm managed resources code. + */ + DRM_UT_DRMRES = 0x200, }; static inline bool drm_debug_enabled(enum drm_debug_category category) @@ -442,6 +446,8 @@ void drm_dev_dbg(const struct device *dev, enum drm_debug_category category, drm_dev_dbg((drm)->dev, DRM_UT_LEASE, fmt, ##__VA_ARGS__) #define drm_dbg_dp(drm, fmt, ...) \ drm_dev_dbg((drm)->dev, DRM_UT_DP, fmt, ##__VA_ARGS__) +#define drm_dbg_drmres(drm, fmt, ...) \ + drm_dev_dbg((drm)->dev, DRM_UT_DRMRES, fmt, ##__VA_ARGS__) /* -- cgit v1.2.3 From c3b790ea07a13da0c46816bda6b04abef346af15 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Mon, 23 Mar 2020 15:49:25 +0100 Subject: drm: Manage drm_mode_config_init with drmm_ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit drm_mode_config_cleanup is idempotent, so no harm in calling this twice. This allows us to gradually switch drivers over by removing explicit drm_mode_config_cleanup calls. With this step it's now also possible that (at least for simple drivers) automatic resource cleanup can be done correctly without a drm_driver->release hook. Therefore allow this now in devm_drm_dev_init(). Also with drmm_ explicit drm_driver->release hooks are kinda not the best option: Drivers can always just register their current release hook with drmm_add_action, but even better they could split them up to simplify the unwinding for the driver load failure case. So deprecate that hook to discourage future users. v2: Fixup the example in the kerneldoc too. v3: - For paranoia, double check that minor->dev == dev in the release hook, because I botched the pointer math in the drmm library. - Call drm_mode_config_cleanup when drmm_add_action fails, we'd be missing some mutex_destroy and ida_cleanup otherwise (Laurent) v4: Add a drmm_add_action_or_reset (like devm_ has) to encapsulate this pattern (Noralf). v5: Fix oversight in the new drmm_add_action_or_reset macro (Noralf) v4: Review from Sam: - drmm_mode_config_init wrapper (also suggested by Thomas) - improve commit message, explain better why ->relase is deprecated v5: - Make drmm_ the main function, with the old one as compat wrapper (Sam) - Add FIXME comments to drm_mode_config_cleanup/init() that drivers shouldn't use these anymore. - Move drmm_add_action_or_reset helper to an earlier patch. Reviewed-by: Sam Ravnborg Cc: Laurent Pinchart Cc: "Noralf Trønnes" Cc: Sam Ravnborg Cc: Thomas Zimmermann Acked-by: Noralf Trønnes Signed-off-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/20200323144950.3018436-27-daniel.vetter@ffwll.ch --- Documentation/gpu/drm-kms.rst | 2 +- drivers/gpu/drm/drm_drv.c | 23 +++++++---------------- drivers/gpu/drm/drm_mode_config.c | 23 ++++++++++++++++++++--- include/drm/drm_mode_config.h | 18 +++++++++++++++++- 4 files changed, 45 insertions(+), 21 deletions(-) (limited to 'Documentation/gpu') diff --git a/Documentation/gpu/drm-kms.rst b/Documentation/gpu/drm-kms.rst index 906771e03103..e1f685015807 100644 --- a/Documentation/gpu/drm-kms.rst +++ b/Documentation/gpu/drm-kms.rst @@ -3,7 +3,7 @@ Kernel Mode Setting (KMS) ========================= Drivers must initialize the mode setting core by calling -drm_mode_config_init() on the DRM device. The function +drmm_mode_config_init() on the DRM device. The function initializes the :c:type:`struct drm_device ` mode_config field and never fails. Once done, mode configuration must be setup by initializing the following fields. diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c index c36687840f4e..158fea71371b 100644 --- a/drivers/gpu/drm/drm_drv.c +++ b/drivers/gpu/drm/drm_drv.c @@ -98,6 +98,8 @@ static void drm_minor_alloc_release(struct drm_device *dev, void *data) struct drm_minor *minor = data; unsigned long flags; + WARN_ON(dev != minor->dev); + put_device(minor->kdev); spin_lock_irqsave(&drm_minor_lock, flags); @@ -266,8 +268,7 @@ void drm_minor_release(struct drm_minor *minor) * * The following example shows a typical structure of a DRM display driver. * The example focus on the probe() function and the other functions that is - * almost always present and serves as a demonstration of devm_drm_dev_init() - * usage with its accompanying drm_driver->release callback. + * almost always present and serves as a demonstration of devm_drm_dev_init(). * * .. code-block:: c * @@ -277,16 +278,8 @@ void drm_minor_release(struct drm_minor *minor) * struct clk *pclk; * }; * - * static void driver_drm_release(struct drm_device *drm) - * { - * struct driver_device *priv = container_of(...); - * - * drm_mode_config_cleanup(drm); - * } - * * static struct drm_driver driver_drm_driver = { * [...] - * .release = driver_drm_release, * }; * * static int driver_probe(struct platform_device *pdev) @@ -311,7 +304,9 @@ void drm_minor_release(struct drm_minor *minor) * } * drmm_add_final_kfree(drm, priv); * - * drm_mode_config_init(drm); + * ret = drmm_mode_config_init(drm); + * if (ret) + * return ret; * * priv->userspace_facing = drmm_kzalloc(..., GFP_KERNEL); * if (!priv->userspace_facing) @@ -709,8 +704,7 @@ static void devm_drm_dev_init_release(void *data) * @driver: DRM driver * * Managed drm_dev_init(). The DRM device initialized with this function is - * automatically put on driver detach using drm_dev_put(). You must supply a - * &drm_driver.release callback to control the finalization explicitly. + * automatically put on driver detach using drm_dev_put(). * * RETURNS: * 0 on success, or error code on failure. @@ -721,9 +715,6 @@ int devm_drm_dev_init(struct device *parent, { int ret; - if (WARN_ON(!driver->release)) - return -EINVAL; - ret = drm_dev_init(dev, driver, parent); if (ret) return ret; diff --git a/drivers/gpu/drm/drm_mode_config.c b/drivers/gpu/drm/drm_mode_config.c index e1ec1bb7068d..5761f838a057 100644 --- a/drivers/gpu/drm/drm_mode_config.c +++ b/drivers/gpu/drm/drm_mode_config.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -373,8 +374,14 @@ static int drm_mode_create_standard_properties(struct drm_device *dev) return 0; } +static void drm_mode_config_init_release(struct drm_device *dev, void *ptr) +{ + drm_mode_config_cleanup(dev); +} + /** - * drm_mode_config_init - initialize DRM mode_configuration structure + * drmm_mode_config_init - managed DRM mode_configuration structure + * initialization * @dev: DRM device * * Initialize @dev's mode_config structure, used for tracking the graphics @@ -384,8 +391,12 @@ static int drm_mode_create_standard_properties(struct drm_device *dev) * problem, since this should happen single threaded at init time. It is the * driver's problem to ensure this guarantee. * + * Cleanup is automatically handled through registering drm_mode_config_cleanup + * with drmm_add_action(). + * + * Returns: 0 on success, negative error value on failure. */ -void drm_mode_config_init(struct drm_device *dev) +int drmm_mode_config_init(struct drm_device *dev) { mutex_init(&dev->mode_config.mutex); drm_modeset_lock_init(&dev->mode_config.connection_mutex); @@ -443,8 +454,11 @@ void drm_mode_config_init(struct drm_device *dev) drm_modeset_acquire_fini(&modeset_ctx); dma_resv_fini(&resv); } + + return drmm_add_action_or_reset(dev, drm_mode_config_init_release, + NULL); } -EXPORT_SYMBOL(drm_mode_config_init); +EXPORT_SYMBOL(drmm_mode_config_init); /** * drm_mode_config_cleanup - free up DRM mode_config info @@ -456,6 +470,9 @@ EXPORT_SYMBOL(drm_mode_config_init); * Note that since this /should/ happen single-threaded at driver/device * teardown time, no locking is required. It's the driver's job to ensure that * this guarantee actually holds true. + * + * FIXME: With the managed drmm_mode_config_init() it is no longer necessary for + * drivers to explicitly call this function. */ void drm_mode_config_cleanup(struct drm_device *dev) { diff --git a/include/drm/drm_mode_config.h b/include/drm/drm_mode_config.h index 3bcbe30339f0..6c3ef49b46b3 100644 --- a/include/drm/drm_mode_config.h +++ b/include/drm/drm_mode_config.h @@ -929,7 +929,23 @@ struct drm_mode_config { const struct drm_mode_config_helper_funcs *helper_private; }; -void drm_mode_config_init(struct drm_device *dev); +int __must_check drmm_mode_config_init(struct drm_device *dev); + +/** + * drm_mode_config_init - DRM mode_configuration structure initialization + * @dev: DRM device + * + * This is the unmanaged version of drmm_mode_config_init() for drivers which + * still explicitly call drm_mode_config_cleanup(). + * + * FIXME: This function is deprecated and drivers should be converted over to + * drmm_mode_config_init(). + */ +static inline int drm_mode_config_init(struct drm_device *dev) +{ + return drmm_mode_config_init(dev); +} + void drm_mode_config_reset(struct drm_device *dev); void drm_mode_config_cleanup(struct drm_device *dev); -- cgit v1.2.3 From 9e1ed9fb1eb0a4bc43a26365c592d3095286038b Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Mon, 23 Mar 2020 15:49:50 +0100 Subject: drm: Add docs for managed resources 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 Cc: Sam Ravnborg Cc: Jonathan Corbet Cc: linux-doc@vger.kernel.org Cc: Laurent Pinchart Cc: Greg Kroah-Hartman Cc: "Rafael J. Wysocki" Signed-off-by: Daniel Vetter fixup docs Link: https://patchwork.freedesktop.org/patch/msgid/20200323144950.3018436-52-daniel.vetter@ffwll.ch --- Documentation/gpu/drm-internals.rst | 6 ++++ drivers/gpu/drm/drm_drv.c | 18 ++++++++++-- drivers/gpu/drm/drm_managed.c | 53 +++++++++++++++++++++++++++++++++++ include/drm/drm_drv.h | 4 +++ include/drm/drm_managed.h | 55 +++++++++++++++++++++++++++++++++++++ 5 files changed, 133 insertions(+), 3 deletions(-) (limited to 'Documentation/gpu') diff --git a/Documentation/gpu/drm-internals.rst b/Documentation/gpu/drm-internals.rst index a6b6145fda78..12272b168580 100644 --- a/Documentation/gpu/drm-internals.rst +++ b/Documentation/gpu/drm-internals.rst @@ -138,6 +138,12 @@ Managed Resources .. kernel-doc:: drivers/gpu/drm/drm_managed.c :doc: managed resources +.. kernel-doc:: drivers/gpu/drm/drm_managed.c + :export: + +.. kernel-doc:: include/drm/drm_managed.h + :internal: + Bus-specific Device Registration and PCI Support ------------------------------------------------ diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c index 158fea71371b..7dad7813fca1 100644 --- a/drivers/gpu/drm/drm_drv.c +++ b/drivers/gpu/drm/drm_drv.c @@ -259,9 +259,15 @@ void drm_minor_release(struct drm_minor *minor) * any other resources allocated at device initialization and drop the driver's * reference to &drm_device using drm_dev_put(). * - * Note that the lifetime rules for &drm_device instance has still a lot of - * historical baggage. Hence use the reference counting provided by - * drm_dev_get() and drm_dev_put() only carefully. + * Note that any allocation or resource which is visible to userspace must be + * released only when the final drm_dev_put() is called, and not when the + * driver is unbound from the underlying physical struct &device. Best to use + * &drm_device managed resources with drmm_add_action(), drmm_kmalloc() and + * related functions. + * + * devres managed resources like devm_kmalloc() can only be used for resources + * directly related to the underlying hardware device, and only used in code + * paths fully protected by drm_dev_enter() and drm_dev_exit(). * * Display driver example * ~~~~~~~~~~~~~~~~~~~~~~ @@ -605,6 +611,9 @@ static void drm_dev_init_release(struct drm_device *dev, void *res) * arbitrary offset, you must supply a &drm_driver.release callback and control * the finalization explicitly. * + * Note that drivers must call drmm_add_final_kfree() after this function has + * completed successfully. + * * RETURNS: * 0 on success, or error code on failure. */ @@ -706,6 +715,9 @@ static void devm_drm_dev_init_release(void *data) * Managed drm_dev_init(). The DRM device initialized with this function is * automatically put on driver detach using drm_dev_put(). * + * Note that drivers must call drmm_add_final_kfree() after this function has + * completed successfully. + * * RETURNS: * 0 on success, or error code on failure. */ diff --git a/drivers/gpu/drm/drm_managed.c b/drivers/gpu/drm/drm_managed.c index 7246a8318137..4955241ceb4c 100644 --- a/drivers/gpu/drm/drm_managed.c +++ b/drivers/gpu/drm/drm_managed.c @@ -20,7 +20,19 @@ * Inspired by struct &device managed resources, but tied to the lifetime of * struct &drm_device, which can outlive the underlying physical device, usually * when userspace has some open files and other handles to resources still open. + * + * Release actions can be added with drmm_add_action(), memory allocations can + * 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(). + * + * 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 + * safe. But it is recommended to use managed resources only for resources that + * change rarely, if ever, during the lifetime of the &drm_device instance. */ + struct drmres_node { struct list_head entry; drmres_release_t release; @@ -111,6 +123,18 @@ 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); @@ -163,6 +187,16 @@ int __drmm_add_action_or_reset(struct drm_device *dev, } EXPORT_SYMBOL(__drmm_add_action_or_reset); +/** + * drmm_kmalloc - &drm_device managed kmalloc() + * @dev: DRM device + * @size: size of the memory allocation + * @gfp: GFP allocation flags + * + * This is a &drm_device managed version of kmalloc(). 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(). + */ void *drmm_kmalloc(struct drm_device *dev, size_t size, gfp_t gfp) { struct drmres *dr; @@ -181,6 +215,16 @@ void *drmm_kmalloc(struct drm_device *dev, size_t size, gfp_t gfp) } EXPORT_SYMBOL(drmm_kmalloc); +/** + * drmm_kstrdup - &drm_device managed kstrdup() + * @dev: DRM device + * @s: 0-terminated string to be duplicated + * @gfp: GFP allocation flags + * + * This is a &drm_device managed version of kstrdup(). The allocated memory is + * automatically freed on the final drm_dev_put() and works exactly like a + * memory allocation obtained by drmm_kmalloc(). + */ char *drmm_kstrdup(struct drm_device *dev, const char *s, gfp_t gfp) { size_t size; @@ -197,6 +241,15 @@ char *drmm_kstrdup(struct drm_device *dev, const char *s, gfp_t gfp) } EXPORT_SYMBOL_GPL(drmm_kstrdup); +/** + * drmm_kfree - &drm_device managed kfree() + * @dev: DRM device + * @data: memory allocation to be freed + * + * This is a &drm_device managed version of kfree() which can be used to + * release memory allocated through drmm_kmalloc() or any of its related + * functions before the final drm_dev_put() of @dev. + */ void drmm_kfree(struct drm_device *dev, void *data) { struct drmres *dr_match = NULL, *dr; diff --git a/include/drm/drm_drv.h b/include/drm/drm_drv.h index b778f3642a90..e0ea577559ff 100644 --- a/include/drm/drm_drv.h +++ b/include/drm/drm_drv.h @@ -263,6 +263,10 @@ struct drm_driver { * * Optional callback for destroying device data after the final * reference is released, i.e. the device is being destroyed. + * + * This is deprecated, clean up all memory allocations associated with a + * &drm_device using drmm_add_action(), drmm_kmalloc() and related + * managed resources functions. */ void (*release) (struct drm_device *); diff --git a/include/drm/drm_managed.h b/include/drm/drm_managed.h index 191d8d206ff4..ca4114633bf9 100644 --- a/include/drm/drm_managed.h +++ b/include/drm/drm_managed.h @@ -11,6 +11,16 @@ 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) @@ -18,6 +28,15 @@ 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) @@ -28,10 +47,33 @@ int __must_check __drmm_add_action_or_reset(struct drm_device *dev, 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) { @@ -42,11 +84,24 @@ static inline void *drmm_kmalloc_array(struct drm_device *dev, 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); -- cgit v1.2.3 From bcf6293d7ae931159fac4fbd9924b0276f1edabd Mon Sep 17 00:00:00 2001 From: Andrzej Pietrasiewicz Date: Tue, 31 Mar 2020 17:53:08 +0200 Subject: drm/core: Calculate bpp in afbc helper Some drivers (komeda, malidp) don't set anything in cpp. If that is the case the right value can be inferred from the format. Then the "bpp" member can be eliminated from struct drm_afbc_framebuffer. Signed-off-by: Andrzej Pietrasiewicz Acked-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/20200331155308.6345-3-andrzej.p@collabora.com --- Documentation/gpu/todo.rst | 15 ----------- drivers/gpu/drm/drm_gem_framebuffer_helper.c | 39 +++++++++++++++++++++++----- include/drm/drm_framebuffer.h | 7 ----- 3 files changed, 32 insertions(+), 29 deletions(-) (limited to 'Documentation/gpu') diff --git a/Documentation/gpu/todo.rst b/Documentation/gpu/todo.rst index 37a3a023c114..439656f55c5d 100644 --- a/Documentation/gpu/todo.rst +++ b/Documentation/gpu/todo.rst @@ -404,21 +404,6 @@ Contact: Laurent Pinchart, respective driver maintainers Level: Intermediate -Encode cpp properly in malidp ------------------------------ - -cpp (chars per pixel) is not encoded properly in malidp, zero is -used instead. afbc implementation needs bpp or cpp, but if it is -zero it needs to be provided elsewhere, and so the bpp field exists -in struct drm_afbc_framebuffer. - -Properly encode cpp in malidp and remove the bpp field in struct -drm_afbc_framebuffer. - -Contact: malidp maintainers - -Level: Intermediate - Core refactorings ================= diff --git a/drivers/gpu/drm/drm_gem_framebuffer_helper.c b/drivers/gpu/drm/drm_gem_framebuffer_helper.c index 6fb1841fa71c..cac15294aef6 100644 --- a/drivers/gpu/drm/drm_gem_framebuffer_helper.c +++ b/drivers/gpu/drm/drm_gem_framebuffer_helper.c @@ -309,11 +309,37 @@ drm_gem_fb_create_with_dirty(struct drm_device *dev, struct drm_file *file, } EXPORT_SYMBOL_GPL(drm_gem_fb_create_with_dirty); +static __u32 drm_gem_afbc_get_bpp(struct drm_device *dev, + const struct drm_mode_fb_cmd2 *mode_cmd) +{ + const struct drm_format_info *info; + + info = drm_get_format_info(dev, mode_cmd); + + /* use whatever a driver has set */ + if (info->cpp[0]) + return info->cpp[0] * 8; + + /* guess otherwise */ + switch (info->format) { + case DRM_FORMAT_YUV420_8BIT: + return 12; + case DRM_FORMAT_YUV420_10BIT: + return 15; + case DRM_FORMAT_VUY101010: + return 30; + default: + break; + } + + /* all attempts failed */ + return 0; +} + static int drm_gem_afbc_min_size(struct drm_device *dev, const struct drm_mode_fb_cmd2 *mode_cmd, struct drm_afbc_framebuffer *afbc_fb) { - const struct drm_format_info *info; __u32 n_blocks, w_alignment, h_alignment, hdr_alignment; /* remove bpp when all users properly encode cpp in drm_format_info */ __u32 bpp; @@ -351,12 +377,11 @@ static int drm_gem_afbc_min_size(struct drm_device *dev, afbc_fb->aligned_height = ALIGN(mode_cmd->height, h_alignment); afbc_fb->offset = mode_cmd->offsets[0]; - info = drm_get_format_info(dev, mode_cmd); - /* - * Change to always using info->cpp[0] - * when all users properly encode it - */ - bpp = info->cpp[0] ? info->cpp[0] * 8 : afbc_fb->bpp; + bpp = drm_gem_afbc_get_bpp(dev, mode_cmd); + if (!bpp) { + drm_dbg_kms(dev, "Invalid AFBC bpp value: %d\n", bpp); + return -EINVAL; + } n_blocks = (afbc_fb->aligned_width * afbc_fb->aligned_height) / AFBC_SUPERBLOCK_PIXELS; diff --git a/include/drm/drm_framebuffer.h b/include/drm/drm_framebuffer.h index b53c0332f040..be658ebbec72 100644 --- a/include/drm/drm_framebuffer.h +++ b/include/drm/drm_framebuffer.h @@ -331,13 +331,6 @@ struct drm_afbc_framebuffer { * @afbc_size: minimum size of afbc buffer */ u32 afbc_size; - /** - * @bpp: bpp value for this afbc buffer - * To be removed when users such as malidp - * properly store the cpp in drm_format_info. - * New users should not start using this field. - */ - u32 bpp; }; #define fb_to_afbc_fb(x) container_of(x, struct drm_afbc_framebuffer, base) -- cgit v1.2.3 From e2d7fc20b3e26a738dc5161adb4279e0096d9575 Mon Sep 17 00:00:00 2001 From: Sam Ravnborg Date: Mon, 6 Apr 2020 21:47:46 +0200 Subject: drm/writeback: wire drm_writeback.h to kernel-doc drm_writeback.h included a lot of nice kernel-doc comments. Wire it up so the header file is included in the kernel-doc generated documentation. Added a few simple comments to the two structs so they get picked up by kernel-doc. Signed-off-by: Sam Ravnborg Reviewed-by: Daniel Vetter Cc: Laurent Pinchart Cc: Brian Starkey Cc: Liviu Dudau Cc: Daniel Vetter Cc: Thomas Zimmermann Cc: Maxime Ripard Link: https://patchwork.freedesktop.org/patch/msgid/20200406194746.26433-4-sam@ravnborg.org --- Documentation/gpu/drm-kms.rst | 3 +++ include/drm/drm_writeback.h | 9 +++++++++ 2 files changed, 12 insertions(+) (limited to 'Documentation/gpu') diff --git a/Documentation/gpu/drm-kms.rst b/Documentation/gpu/drm-kms.rst index e1f685015807..397314d08f77 100644 --- a/Documentation/gpu/drm-kms.rst +++ b/Documentation/gpu/drm-kms.rst @@ -397,6 +397,9 @@ Connector Functions Reference Writeback Connectors -------------------- +.. kernel-doc:: include/drm/drm_writeback.h + :internal: + .. kernel-doc:: drivers/gpu/drm/drm_writeback.c :doc: overview diff --git a/include/drm/drm_writeback.h b/include/drm/drm_writeback.h index 777c14c847f0..9697d2714d2a 100644 --- a/include/drm/drm_writeback.h +++ b/include/drm/drm_writeback.h @@ -15,7 +15,13 @@ #include #include +/** + * struct drm_writeback_connector - DRM writeback connector + */ struct drm_writeback_connector { + /** + * @base: base drm_connector object + */ struct drm_connector base; /** @@ -78,6 +84,9 @@ struct drm_writeback_connector { char timeline_name[32]; }; +/** + * struct drm_writeback_job - DRM writeback job + */ struct drm_writeback_job { /** * @connector: -- cgit v1.2.3 From b22b51a0346ed64b781122a4db3824cd400e9f57 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Tue, 31 Mar 2020 10:12:38 +0200 Subject: drm/vram-helpers: Merge code into a single file Most of the documentation was in an otherwise empty file, which was probably just left from a previous clean-up effort. So move code and documentation into a single file. Signed-off-by: Thomas Zimmermann Acked-by: Gerd Hoffmann Acked-by: Sam Ravnborg Link: https://patchwork.freedesktop.org/patch/msgid/20200331081238.24749-1-tzimmermann@suse.de --- Documentation/gpu/drm-mm.rst | 9 --- drivers/gpu/drm/Makefile | 3 +- drivers/gpu/drm/drm_gem_vram_helper.c | 95 ++++++++++++++++++++++++++++++-- drivers/gpu/drm/drm_vram_helper_common.c | 94 ------------------------------- 4 files changed, 91 insertions(+), 110 deletions(-) delete mode 100644 drivers/gpu/drm/drm_vram_helper_common.c (limited to 'Documentation/gpu') diff --git a/Documentation/gpu/drm-mm.rst b/Documentation/gpu/drm-mm.rst index c77b32601260..1839762044be 100644 --- a/Documentation/gpu/drm-mm.rst +++ b/Documentation/gpu/drm-mm.rst @@ -373,15 +373,6 @@ GEM CMA Helper Functions Reference .. kernel-doc:: drivers/gpu/drm/drm_gem_cma_helper.c :export: -VRAM Helper Function Reference -============================== - -.. kernel-doc:: drivers/gpu/drm/drm_vram_helper_common.c - :doc: overview - -.. kernel-doc:: include/drm/drm_gem_vram_helper.h - :internal: - GEM VRAM Helper Functions Reference ----------------------------------- diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile index 183c60048307..f34d08c83485 100644 --- a/drivers/gpu/drm/Makefile +++ b/drivers/gpu/drm/Makefile @@ -33,8 +33,7 @@ drm-$(CONFIG_PCI) += drm_pci.o drm-$(CONFIG_DEBUG_FS) += drm_debugfs.o drm_debugfs_crc.o drm-$(CONFIG_DRM_LOAD_EDID_FIRMWARE) += drm_edid_load.o -drm_vram_helper-y := drm_gem_vram_helper.o \ - drm_vram_helper_common.o +drm_vram_helper-y := drm_gem_vram_helper.o obj-$(CONFIG_DRM_VRAM_HELPER) += drm_vram_helper.o drm_ttm_helper-y := drm_gem_ttm_helper.o diff --git a/drivers/gpu/drm/drm_gem_vram_helper.c b/drivers/gpu/drm/drm_gem_vram_helper.c index cdf710be39da..8b2d5c945c95 100644 --- a/drivers/gpu/drm/drm_gem_vram_helper.c +++ b/drivers/gpu/drm/drm_gem_vram_helper.c @@ -1,5 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later +#include + #include #include #include @@ -19,13 +21,93 @@ static const struct drm_gem_object_funcs drm_gem_vram_object_funcs; /** * DOC: overview * - * This library provides a GEM buffer object that is backed by video RAM - * (VRAM). It can be used for framebuffer devices with dedicated memory. + * This library provides &struct drm_gem_vram_object (GEM VRAM), a GEM + * buffer object that is backed by video RAM (VRAM). It can be used for + * framebuffer devices with dedicated memory. * * The data structure &struct drm_vram_mm and its helpers implement a memory - * manager for simple framebuffer devices with dedicated video memory. Buffer - * objects are either placed in video RAM or evicted to system memory. The rsp. - * buffer object is provided by &struct drm_gem_vram_object. + * manager for simple framebuffer devices with dedicated video memory. GEM + * VRAM buffer objects are either placed in the video memory or remain evicted + * to system memory. + * + * With the GEM interface userspace applications create, manage and destroy + * graphics buffers, such as an on-screen framebuffer. GEM does not provide + * an implementation of these interfaces. It's up to the DRM driver to + * provide an implementation that suits the hardware. If the hardware device + * contains dedicated video memory, the DRM driver can use the VRAM helper + * library. Each active buffer object is stored in video RAM. Active + * buffer are used for drawing the current frame, typically something like + * the frame's scanout buffer or the cursor image. If there's no more space + * left in VRAM, inactive GEM objects can be moved to system memory. + * + * The easiest way to use the VRAM helper library is to call + * drm_vram_helper_alloc_mm(). The function allocates and initializes an + * instance of &struct drm_vram_mm in &struct drm_device.vram_mm . Use + * &DRM_GEM_VRAM_DRIVER to initialize &struct drm_driver and + * &DRM_VRAM_MM_FILE_OPERATIONS to initialize &struct file_operations; + * as illustrated below. + * + * .. code-block:: c + * + * struct file_operations fops ={ + * .owner = THIS_MODULE, + * DRM_VRAM_MM_FILE_OPERATION + * }; + * struct drm_driver drv = { + * .driver_feature = DRM_ ... , + * .fops = &fops, + * DRM_GEM_VRAM_DRIVER + * }; + * + * int init_drm_driver() + * { + * struct drm_device *dev; + * uint64_t vram_base; + * unsigned long vram_size; + * int ret; + * + * // setup device, vram base and size + * // ... + * + * ret = drm_vram_helper_alloc_mm(dev, vram_base, vram_size); + * if (ret) + * return ret; + * return 0; + * } + * + * This creates an instance of &struct drm_vram_mm, exports DRM userspace + * interfaces for GEM buffer management and initializes file operations to + * allow for accessing created GEM buffers. With this setup, the DRM driver + * manages an area of video RAM with VRAM MM and provides GEM VRAM objects + * to userspace. + * + * To clean up the VRAM memory management, call drm_vram_helper_release_mm() + * in the driver's clean-up code. + * + * .. code-block:: c + * + * void fini_drm_driver() + * { + * struct drm_device *dev = ...; + * + * drm_vram_helper_release_mm(dev); + * } + * + * For drawing or scanout operations, buffer object have to be pinned in video + * RAM. Call drm_gem_vram_pin() with &DRM_GEM_VRAM_PL_FLAG_VRAM or + * &DRM_GEM_VRAM_PL_FLAG_SYSTEM to pin a buffer object in video RAM or system + * memory. Call drm_gem_vram_unpin() to release the pinned object afterwards. + * + * A buffer object that is pinned in video RAM has a fixed address within that + * memory region. Call drm_gem_vram_offset() to retrieve this value. Typically + * it's used to program the hardware's scanout engine for framebuffers, set + * the cursor overlay's image for a mouse cursor, or use it as input to the + * hardware's draing engine. + * + * To access a buffer object's memory from the DRM driver, call + * drm_gem_vram_kmap(). It (optionally) maps the buffer into kernel address + * space and returns the memory address. Use drm_gem_vram_kunmap() to + * release the mapping. */ /* @@ -1197,3 +1279,6 @@ drm_vram_helper_mode_valid(struct drm_device *dev, return drm_vram_helper_mode_valid_internal(dev, mode, max_bpp); } EXPORT_SYMBOL(drm_vram_helper_mode_valid); + +MODULE_DESCRIPTION("DRM VRAM memory-management helpers"); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/drm_vram_helper_common.c b/drivers/gpu/drm/drm_vram_helper_common.c deleted file mode 100644 index 2000d9b33fd5..000000000000 --- a/drivers/gpu/drm/drm_vram_helper_common.c +++ /dev/null @@ -1,94 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later - -#include - -/** - * DOC: overview - * - * This library provides &struct drm_gem_vram_object (GEM VRAM), a GEM - * buffer object that is backed by video RAM. It can be used for - * framebuffer devices with dedicated memory. The video RAM is managed - * by &struct drm_vram_mm (VRAM MM). - * - * With the GEM interface userspace applications create, manage and destroy - * graphics buffers, such as an on-screen framebuffer. GEM does not provide - * an implementation of these interfaces. It's up to the DRM driver to - * provide an implementation that suits the hardware. If the hardware device - * contains dedicated video memory, the DRM driver can use the VRAM helper - * library. Each active buffer object is stored in video RAM. Active - * buffer are used for drawing the current frame, typically something like - * the frame's scanout buffer or the cursor image. If there's no more space - * left in VRAM, inactive GEM objects can be moved to system memory. - * - * The easiest way to use the VRAM helper library is to call - * drm_vram_helper_alloc_mm(). The function allocates and initializes an - * instance of &struct drm_vram_mm in &struct drm_device.vram_mm . Use - * &DRM_GEM_VRAM_DRIVER to initialize &struct drm_driver and - * &DRM_VRAM_MM_FILE_OPERATIONS to initialize &struct file_operations; - * as illustrated below. - * - * .. code-block:: c - * - * struct file_operations fops ={ - * .owner = THIS_MODULE, - * DRM_VRAM_MM_FILE_OPERATION - * }; - * struct drm_driver drv = { - * .driver_feature = DRM_ ... , - * .fops = &fops, - * DRM_GEM_VRAM_DRIVER - * }; - * - * int init_drm_driver() - * { - * struct drm_device *dev; - * uint64_t vram_base; - * unsigned long vram_size; - * int ret; - * - * // setup device, vram base and size - * // ... - * - * ret = drm_vram_helper_alloc_mm(dev, vram_base, vram_size); - * if (ret) - * return ret; - * return 0; - * } - * - * This creates an instance of &struct drm_vram_mm, exports DRM userspace - * interfaces for GEM buffer management and initializes file operations to - * allow for accessing created GEM buffers. With this setup, the DRM driver - * manages an area of video RAM with VRAM MM and provides GEM VRAM objects - * to userspace. - * - * To clean up the VRAM memory management, call drm_vram_helper_release_mm() - * in the driver's clean-up code. - * - * .. code-block:: c - * - * void fini_drm_driver() - * { - * struct drm_device *dev = ...; - * - * drm_vram_helper_release_mm(dev); - * } - * - * For drawing or scanout operations, buffer object have to be pinned in video - * RAM. Call drm_gem_vram_pin() with &DRM_GEM_VRAM_PL_FLAG_VRAM or - * &DRM_GEM_VRAM_PL_FLAG_SYSTEM to pin a buffer object in video RAM or system - * memory. Call drm_gem_vram_unpin() to release the pinned object afterwards. - * - * A buffer object that is pinned in video RAM has a fixed address within that - * memory region. Call drm_gem_vram_offset() to retrieve this value. Typically - * it's used to program the hardware's scanout engine for framebuffers, set - * the cursor overlay's image for a mouse cursor, or use it as input to the - * hardware's draing engine. - * - * To access a buffer object's memory from the DRM driver, call - * drm_gem_vram_kmap(). It (optionally) maps the buffer into kernel address - * space and returns the memory address. Use drm_gem_vram_kunmap() to - * release the mapping. - */ - -MODULE_DESCRIPTION("DRM VRAM memory-management helpers"); -MODULE_LICENSE("GPL"); -- cgit v1.2.3