[PATCH v2 05/17] drm: Add VRAM MM, a simple memory manager for dedicated VRAM
Daniel Vetter
daniel at ffwll.ch
Wed Apr 24 13:07:18 UTC 2019
On Wed, Apr 24, 2019 at 01:48:30PM +0200, Thomas Zimmermann wrote:
> The VRAM MM memory manager is a helper library that manages dedicated video
> memory of simple framebuffer devices. It is supported to be used with
> struct drm_gem_vram_object, but does not depend on it.
I'm not sure keeping these two helpers strictly separated helps us. If
forces things like the verify_access callback, which everyone just
implements the exact same way.
I'd merge them, or at least make these callbacks call the gem_vram_object
implementations by default.
-Daniel
>
> The implementation is based on the respective code from ast, bochs, and
> mgag200. These drivers share the exact same implementation except for type
> names. The helpers are currently build with TTM. This may change in future
> revisions.
>
> v2:
> * renamed to struct drm_vram_mm
> * add drm_vram_mm_mmap() helper
> * documentation fixes
>
> Signed-off-by: Thomas Zimmermann <tzimmermann at suse.de>
> ---
> Documentation/gpu/drm-mm.rst | 13 +-
> drivers/gpu/drm/Kconfig | 7 +
> drivers/gpu/drm/Makefile | 1 +
> drivers/gpu/drm/drm_vram_mm_helper.c | 210 +++++++++++++++++++++++++++
> include/drm/drm_vram_mm_helper.h | 67 +++++++++
> 5 files changed, 297 insertions(+), 1 deletion(-)
> create mode 100644 drivers/gpu/drm/drm_vram_mm_helper.c
> create mode 100644 include/drm/drm_vram_mm_helper.h
>
> diff --git a/Documentation/gpu/drm-mm.rst b/Documentation/gpu/drm-mm.rst
> index d5327ed608d7..a6ce10675638 100644
> --- a/Documentation/gpu/drm-mm.rst
> +++ b/Documentation/gpu/drm-mm.rst
> @@ -79,7 +79,6 @@ count for the TTM, which will call your initialization function.
>
> See the radeon_ttm.c file for an example of usage.
>
> -
> The Graphics Execution Manager (GEM)
> ====================================
>
> @@ -392,6 +391,18 @@ GEM VRAM Helper Functions Reference
> .. kernel-doc:: drivers/gpu/drm/drm_gem_vram_helper.c
> :export:
>
> +VRAM MM Helper Functions Reference
> +-------------------------------------
> +
> +.. kernel-doc:: drivers/gpu/drm/drm_vram_mm_helper.c
> + :doc: overview
> +
> +.. kernel-doc:: include/drm/drm_vram_mm_helper.h
> + :internal:
> +
> +.. kernel-doc:: drivers/gpu/drm/drm_vram_mm_helper.c
> + :export:
> +
> VMA Offset Manager
> ==================
>
> diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
> index 9a1870f4dab6..fc8007de5d09 100644
> --- a/drivers/gpu/drm/Kconfig
> +++ b/drivers/gpu/drm/Kconfig
> @@ -166,6 +166,13 @@ config DRM_VRAM_HELPER
> help
> Helpers for VRAM memory management
>
> +config DRM_VRAM_MM_HELPER
> + tristate
> + depends on DRM && DRM_TTM
> + select DRM_VRAM_HELPER
> + help
> + Choose this if you need the VRAM MM helper functions
> +
> config DRM_GEM_CMA_HELPER
> bool
> depends on DRM
> diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
> index bb2e8de8661b..61c7db6aac95 100644
> --- a/drivers/gpu/drm/Makefile
> +++ b/drivers/gpu/drm/Makefile
> @@ -35,6 +35,7 @@ drm-$(CONFIG_DRM_LOAD_EDID_FIRMWARE) += drm_edid_load.o
>
> drm_vram_helper-y := drm_vram_helper_common.o
> drm_vram_helper-$(CONFIG_DRM_GEM_VRAM_HELPER) += drm_gem_vram_helper.o
> +drm_vram_helper-$(CONFIG_DRM_VRAM_MM_HELPER) += drm_vram_mm_helper.o
> obj-$(CONFIG_DRM_VRAM_HELPER) += drm_vram_helper.o
>
> drm_kms_helper-y := drm_crtc_helper.o drm_dp_helper.o drm_dsc.o drm_probe_helper.o \
> diff --git a/drivers/gpu/drm/drm_vram_mm_helper.c b/drivers/gpu/drm/drm_vram_mm_helper.c
> new file mode 100644
> index 000000000000..d19f46d7a4e7
> --- /dev/null
> +++ b/drivers/gpu/drm/drm_vram_mm_helper.c
> @@ -0,0 +1,210 @@
> +/* SPDX-License-Identifier: GPL-2.0-or-later */
> +
> +#include <drm/drm_vram_mm_helper.h>
> +#include <drm/drmP.h>
> +#include <drm/ttm/ttm_page_alloc.h>
> +
> +/**
> + * DOC: overview
> + *
> + * The data structure &struct drm_vram_mm and its helpers implement a memory
> + * manager for simple framebuffer devices with dedicated video memory. Buffer
> + * object s are either placed in VRAM or evicted to system ram. The functions
> + * work well with &struct drm_gem_vram_object.
> + */
> +
> +/*
> + * TTM TT
> + */
> +
> +static void backend_func_destroy(struct ttm_tt *tt)
> +{
> + ttm_tt_fini(tt);
> + kfree(tt);
> +}
> +
> +static struct ttm_backend_func backend_func = {
> + .destroy = backend_func_destroy
> +};
> +
> +/*
> + * TTM BO device
> + */
> +
> +static struct ttm_tt *bo_driver_ttm_tt_create(struct ttm_buffer_object *bo,
> + uint32_t page_flags)
> +{
> + struct ttm_tt *tt;
> + int ret;
> +
> + tt = kzalloc(sizeof(*tt), GFP_KERNEL);
> + if (!tt)
> + return NULL;
> +
> + tt->func = &backend_func;
> +
> + ret = ttm_tt_init(tt, bo, page_flags);
> + if (ret < 0)
> + goto err_ttm_tt_init;
> +
> + return tt;
> +
> +err_ttm_tt_init:
> + kfree(tt);
> + return NULL;
> +}
> +
> +static int bo_driver_init_mem_type(struct ttm_bo_device *bdev, uint32_t type,
> + struct ttm_mem_type_manager *man)
> +{
> + switch (type) {
> + case TTM_PL_SYSTEM:
> + man->flags = TTM_MEMTYPE_FLAG_MAPPABLE;
> + man->available_caching = TTM_PL_MASK_CACHING;
> + man->default_caching = TTM_PL_FLAG_CACHED;
> + break;
> + case TTM_PL_VRAM:
> + man->func = &ttm_bo_manager_func;
> + man->flags = TTM_MEMTYPE_FLAG_FIXED |
> + TTM_MEMTYPE_FLAG_MAPPABLE;
> + man->available_caching = TTM_PL_FLAG_UNCACHED |
> + TTM_PL_FLAG_WC;
> + man->default_caching = TTM_PL_FLAG_WC;
> + break;
> + default:
> + return -EINVAL;
> + }
> + return 0;
> +}
> +
> +static void bo_driver_evict_flags(struct ttm_buffer_object *bo,
> + struct ttm_placement *placement)
> +{
> + struct drm_vram_mm *vmm = drm_vram_mm_of_bdev(bo->bdev);
> +
> + if (vmm->funcs && vmm->funcs->evict_flags)
> + vmm->funcs->evict_flags(bo, placement);
> +}
> +
> +static int bo_driver_verify_access(struct ttm_buffer_object *bo,
> + struct file *filp)
> +{
> + struct drm_vram_mm *vmm = drm_vram_mm_of_bdev(bo->bdev);
> +
> + if (!vmm->funcs || !vmm->funcs->verify_access)
> + return 0;
> + return vmm->funcs->verify_access(bo, filp);
> +}
> +
> +static int bo_driver_io_mem_reserve(struct ttm_bo_device *bdev,
> + struct ttm_mem_reg *mem)
> +{
> + struct ttm_mem_type_manager *man = bdev->man + mem->mem_type;
> + struct drm_vram_mm *vmm = drm_vram_mm_of_bdev(bdev);
> +
> + if (!(man->flags & TTM_MEMTYPE_FLAG_MAPPABLE))
> + return -EINVAL;
> +
> + mem->bus.addr = NULL;
> + mem->bus.size = mem->num_pages << PAGE_SHIFT;
> +
> + switch (mem->mem_type) {
> + case TTM_PL_SYSTEM: /* nothing to do */
> + mem->bus.offset = 0;
> + mem->bus.base = 0;
> + mem->bus.is_iomem = false;
> + break;
> + case TTM_PL_VRAM:
> + mem->bus.offset = mem->start << PAGE_SHIFT;
> + mem->bus.base = vmm->vram_base;
> + mem->bus.is_iomem = true;
> + break;
> + default:
> + return -EINVAL;
> + }
> +
> + return 0;
> +}
> +
> +static void bo_driver_io_mem_free(struct ttm_bo_device *bdev,
> + struct ttm_mem_reg *mem)
> +{ }
> +
> +static struct ttm_bo_driver bo_driver = {
> + .ttm_tt_create = bo_driver_ttm_tt_create,
> + .ttm_tt_populate = ttm_pool_populate,
> + .ttm_tt_unpopulate = ttm_pool_unpopulate,
> + .init_mem_type = bo_driver_init_mem_type,
> + .eviction_valuable = ttm_bo_eviction_valuable,
> + .evict_flags = bo_driver_evict_flags,
> + .verify_access = bo_driver_verify_access,
> + .io_mem_reserve = bo_driver_io_mem_reserve,
> + .io_mem_free = bo_driver_io_mem_free,
> +};
> +
> +/*
> + * struct drm_vram_mm
> + */
> +
> +/**
> + * drm_vram_mm_init() - Initialize an instance of VRAM MM.
> + * @vmm: the VRAM MM instance to initialize
> + * @dev: the DRM device
> + * @vram_base: the base address of the video memory
> + * @vram_size: the size of the video memory in bytes
> + * @funcs: callback functions for buffer objects
> + *
> + * Returns:
> + * 0 on success, or
> + * a negative error code otherwise.
> + */
> +int drm_vram_mm_init(struct drm_vram_mm *vmm, struct drm_device *dev,
> + u64 vram_base, unsigned long vram_size,
> + const struct drm_vram_mm_funcs* funcs)
> +{
> + int ret;
> +
> + vmm->vram_base = vram_base;
> + vmm->vram_size = vram_size;
> + vmm->funcs = funcs;
> +
> + ret = ttm_bo_device_init(&vmm->bdev, &bo_driver,
> + dev->anon_inode->i_mapping,
> + true);
> + if (ret)
> + return ret;
> +
> + ret = ttm_bo_init_mm(&vmm->bdev, TTM_PL_VRAM, vram_size >> PAGE_SHIFT);
> + if (ret)
> + return ret;
> +
> + return 0;
> +}
> +EXPORT_SYMBOL(drm_vram_mm_init);
> +
> +/**
> + * drm_vram_mm_cleanup() - Cleans up an initialized instance of VRAM MM.
> + * @vmm: the VRAM MM instance to clean up
> + */
> +void drm_vram_mm_cleanup(struct drm_vram_mm *vmm)
> +{
> + ttm_bo_device_release(&vmm->bdev);
> +}
> +EXPORT_SYMBOL(drm_vram_mm_cleanup);
> +
> +/**
> + * drm_vram_mm_mmap() - Helper for implementing &struct file_operations.mmap()
> + * @filp: the mapping's file structure
> + * @vma: the mapping's memory area
> + * @vmm: the VRAM MM instance
> + *
> + * Returns:
> + * 0 on success, or
> + * a negative error code otherwise.
> + */
> +int drm_vram_mm_mmap(struct file *filp, struct vm_area_struct *vma,
> + struct drm_vram_mm *vmm)
> +{
> + return ttm_bo_mmap(filp, vma, &vmm->bdev);
> +}
> +EXPORT_SYMBOL(drm_vram_mm_mmap);
> diff --git a/include/drm/drm_vram_mm_helper.h b/include/drm/drm_vram_mm_helper.h
> new file mode 100644
> index 000000000000..0ee060d271bd
> --- /dev/null
> +++ b/include/drm/drm_vram_mm_helper.h
> @@ -0,0 +1,67 @@
> +/* SPDX-License-Identifier: GPL-2.0-or-later */
> +
> +#ifndef DRM_VRAM_MM_HELPER_H
> +#define DRM_VRAM_MM_HELPER_H
> +
> +#include <drm/ttm/ttm_bo_driver.h>
> +
> +struct drm_device;
> +
> +/**
> + * struct drm_vram_mm_funcs - Callback functions for &struct drm_vram_mm
> + * @evict_flags: Provides an implementation for struct &ttm_bo_driver.evict_flags
> + * @verify_access: Provides an implementation for struct &ttm_bo_driver.verify_access
> + *
> + * These callback function integrate VRAM MM with TTM buffer objects. New
> + * functions can be added if necessary.
> + */
> +struct drm_vram_mm_funcs {
> + void (*evict_flags)(struct ttm_buffer_object *bo,
> + struct ttm_placement *placement);
> + int (*verify_access)(struct ttm_buffer_object *bo, struct file *filp);
> +};
> +
> +/**
> + * struct drm_vram_mm - An instance of VRAM MM
> + * @vram_base: Base address of the managed video memory
> + * @vram_size: Size of the managed video memory in bytes
> + * @bdev: The TTM BO device.
> + * @funcs: TTM BO functions
> + *
> + * The fields &struct drm_vram_mm.vram_base and
> + * &struct drm_vram_mm.vrm_size are managed by VRAM MM, but are
> + * available for public read access. Use the field
> + * &struct drm_vram_mm.bdev to access the TTM BO device.
> + */
> +struct drm_vram_mm {
> + u64 vram_base;
> + unsigned long vram_size;
> +
> + struct ttm_bo_device bdev;
> +
> + const struct drm_vram_mm_funcs *funcs;
> +};
> +
> +/**
> + * drm_vram_mm_of_bdev() - \
> + Returns the container of type &struct ttm_bo_device for field bdev.
> + * @bdev: the TTM BO device
> + *
> + * Returns:
> + * The containing instance of &struct drm_vram_mm
> + */
> +static inline struct drm_vram_mm* drm_vram_mm_of_bdev(
> + struct ttm_bo_device *bdev)
> +{
> + return container_of(bdev, struct drm_vram_mm, bdev);
> +}
> +
> +int drm_vram_mm_init(struct drm_vram_mm *vmm, struct drm_device *dev,
> + u64 vram_base, unsigned long vram_size,
> + const struct drm_vram_mm_funcs* funcs);
> +void drm_vram_mm_cleanup(struct drm_vram_mm *vmm);
> +
> +int drm_vram_mm_mmap(struct file *filp, struct vm_area_struct *vma,
> + struct drm_vram_mm *vmm);
> +
> +#endif
> --
> 2.21.0
>
--
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
More information about the dri-devel
mailing list