Commit 59f5989a authored by Thomas Zimmermann's avatar Thomas Zimmermann Committed by Gerd Hoffmann
Browse files

drm: Integrate VRAM MM into struct drm_device



There's now a pointer to struct drm_vram_mm stored in struct drm_device.
DRM drivers that use VRAM MM should use this field to refer to their
instance of the data structure. Appropriate helpers are now provided as
well.

Adding struct drm_vram_mm to struct drm_device further avoids wrappers
and boilerplate code in drivers. This patch implements default functions
for callbacks in struct drm_driver and struct file_operations that use
the struct drm_vram_mm stored in struct drm_device. Drivers that need to
provide their own implementations can still do so.

The patch also adds documentation for the VRAM helper library in general.

v5:
	* set .llseek to no_llseek() from DRM_VRAM_MM_FILE_OPERATIONS
v4:
	* cleanups from checkpatch.pl
	* document VRAM helper library

Signed-off-by: default avatarThomas Zimmermann <tzimmermann@suse.de>
Link: http://patchwork.freedesktop.org/patch/msgid/20190508082630.15116-9-tzimmermann@suse.de


Signed-off-by: default avatarGerd Hoffmann <kraxel@redhat.com>
parent 5c9dcacf
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -382,6 +382,12 @@ GEM CMA Helper Functions Reference
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
-----------------------------------

+28 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0-or-later

#include <drm/drm_gem_vram_helper.h>
#include <drm/drm_device.h>
#include <drm/drm_mode.h>
#include <drm/drm_prime.h>
#include <drm/drm_vram_mm_helper.h>
@@ -555,6 +556,33 @@ void drm_gem_vram_driver_gem_free_object_unlocked(struct drm_gem_object *gem)
}
EXPORT_SYMBOL(drm_gem_vram_driver_gem_free_object_unlocked);

/**
 * drm_gem_vram_driver_create_dumb() - \
	Implements &struct drm_driver.dumb_create
 * @file:		the DRM file
 * @dev:		the DRM device
 * @args:		the arguments as provided to \
				&struct drm_driver.dumb_create
 *
 * This function requires the driver to use @drm_device.vram_mm for its
 * instance of VRAM MM.
 *
 * Returns:
 * 0 on success, or
 * a negative error code otherwise.
 */
int drm_gem_vram_driver_dumb_create(struct drm_file *file,
				    struct drm_device *dev,
				    struct drm_mode_create_dumb *args)
{
	if (WARN_ONCE(!dev->vram_mm, "VRAM MM not initialized"))
		return -EINVAL;

	return drm_gem_vram_fill_create_dumb(file, dev, &dev->vram_mm->bdev, 0,
					     false, args);
}
EXPORT_SYMBOL(drm_gem_vram_driver_dumb_create);

/**
 * drm_gem_vram_driver_dumb_mmap_offset() - \
	Implements &struct drm_driver.dumb_mmap_offset
+92 −0
Original line number Diff line number Diff line
@@ -2,5 +2,97 @@

#include <linux/module.h>

/**
 * 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 can be
 * managed with &struct drm_vram_mm (VRAM MM). Both data structures are
 * supposed to be used together, but can also be used individually.
 *
 * 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,
 *					       &drm_gem_vram_mm_funcs);
 *		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.
 * If you have to evict a buffer object from video RAM (e.g., for freeing up
 * memory), unpin the buffer and call drm_gem_vram_push_to_system().
 *
 * 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");
+85 −0
Original line number Diff line number Diff line
@@ -208,3 +208,88 @@ int drm_vram_mm_mmap(struct file *filp, struct vm_area_struct *vma,
	return ttm_bo_mmap(filp, vma, &vmm->bdev);
}
EXPORT_SYMBOL(drm_vram_mm_mmap);

/*
 * Helpers for integration with struct drm_device
 */

/**
 * drm_vram_helper_alloc_mm - Allocates a device's instance of \
	&struct drm_vram_mm
 * @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:
 * The new instance of &struct drm_vram_mm on success, or
 * an ERR_PTR()-encoded errno code otherwise.
 */
struct drm_vram_mm *drm_vram_helper_alloc_mm(
	struct drm_device *dev, uint64_t vram_base, size_t vram_size,
	const struct drm_vram_mm_funcs *funcs)
{
	int ret;

	if (WARN_ON(dev->vram_mm))
		return dev->vram_mm;

	dev->vram_mm = kzalloc(sizeof(*dev->vram_mm), GFP_KERNEL);
	if (!dev->vram_mm)
		return ERR_PTR(-ENOMEM);

	ret = drm_vram_mm_init(dev->vram_mm, dev, vram_base, vram_size, funcs);
	if (ret)
		goto err_kfree;

	return dev->vram_mm;

err_kfree:
	kfree(dev->vram_mm);
	dev->vram_mm = NULL;
	return ERR_PTR(ret);
}
EXPORT_SYMBOL(drm_vram_helper_alloc_mm);

/**
 * drm_vram_helper_release_mm - Releases a device's instance of \
	&struct drm_vram_mm
 * @dev:	the DRM device
 */
void drm_vram_helper_release_mm(struct drm_device *dev)
{
	if (!dev->vram_mm)
		return;

	drm_vram_mm_cleanup(dev->vram_mm);
	kfree(dev->vram_mm);
	dev->vram_mm = NULL;
}
EXPORT_SYMBOL(drm_vram_helper_release_mm);

/*
 * Helpers for &struct file_operations
 */

/**
 * drm_vram_mm_file_operations_mmap() - \
	Implements &struct file_operations.mmap()
 * @filp:	the mapping's file structure
 * @vma:	the mapping's memory area
 *
 * Returns:
 * 0 on success, or
 * a negative error code otherwise.
 */
int drm_vram_mm_file_operations_mmap(
	struct file *filp, struct vm_area_struct *vma)
{
	struct drm_file *file_priv = filp->private_data;
	struct drm_device *dev = file_priv->minor->dev;

	if (WARN_ONCE(!dev->vram_mm, "VRAM MM not initialized"))
		return -EINVAL;

	return drm_vram_mm_mmap(filp, vma, dev->vram_mm);
}
EXPORT_SYMBOL(drm_vram_mm_file_operations_mmap);
+4 −0
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@ struct drm_vblank_crtc;
struct drm_sg_mem;
struct drm_local_map;
struct drm_vma_offset_manager;
struct drm_vram_mm;
struct drm_fb_helper;

struct inode;
@@ -286,6 +287,9 @@ struct drm_device {
	/** @vma_offset_manager: GEM information */
	struct drm_vma_offset_manager *vma_offset_manager;

	/** @vram_mm: VRAM MM memory manager */
	struct drm_vram_mm *vram_mm;

	/**
	 * @switch_power_state:
	 *
Loading