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@xxxxxxx> > --- > 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 _______________________________________________ Virtualization mailing list Virtualization@xxxxxxxxxxxxxxxxxxxxxxxxxx https://lists.linuxfoundation.org/mailman/listinfo/virtualization