Commit 43676605 authored by Thomas Zimmermann's avatar Thomas Zimmermann
Browse files

drm/ttm: Add vmap/vunmap to TTM and TTM GEM helpers



The new functions ttm_bo_{vmap,vunmap}() map and unmap a TTM BO in kernel
address space. The mapping's address is returned as struct dma_buf_map.
Each function is a simplified version of TTM's existing kmap code. Both
functions respect the memory's location ani/or writecombine flags.

On top TTM's functions, GEM TTM helpers got drm_gem_ttm_{vmap,vunmap}(),
two helpers that convert a GEM object into the TTM BO and forward the call
to TTM's vmap/vunmap. These helpers can be dropped into the rsp GEM object
callbacks.

v5:
	* use size_t for storing mapping size (Christian)
	* ignore premapped memory areas correctly in ttm_bo_vunmap()
	* rebase onto latest TTM interfaces (Christian)
	* remove BUG() from ttm_bo_vmap() (Christian)
v4:
	* drop ttm_kmap_obj_to_dma_buf() in favor of vmap helpers (Daniel,
	  Christian)

Signed-off-by: default avatarThomas Zimmermann <tzimmermann@suse.de>
Reviewed-by: default avatarChristian König <christian.koenig@amd.com>
Acked-by: default avatarDaniel Vetter <daniel.vetter@ffwll.ch>
Tested-by: default avatarSam Ravnborg <sam@ravnborg.org>
Link: https://patchwork.freedesktop.org/patch/msgid/20201103093015.1063-6-tzimmermann@suse.de
parent f216fcb8
Loading
Loading
Loading
Loading
+37 −0
Original line number Diff line number Diff line
@@ -49,6 +49,43 @@ void drm_gem_ttm_print_info(struct drm_printer *p, unsigned int indent,
}
EXPORT_SYMBOL(drm_gem_ttm_print_info);

/**
 * drm_gem_ttm_vmap() - vmap &ttm_buffer_object
 * @gem: GEM object.
 * @map: [out] returns the dma-buf mapping.
 *
 * Maps a GEM object with ttm_bo_vmap(). This function can be used as
 * &drm_gem_object_funcs.vmap callback.
 *
 * Returns:
 * 0 on success, or a negative errno code otherwise.
 */
int drm_gem_ttm_vmap(struct drm_gem_object *gem,
		     struct dma_buf_map *map)
{
	struct ttm_buffer_object *bo = drm_gem_ttm_of_gem(gem);

	return ttm_bo_vmap(bo, map);
}
EXPORT_SYMBOL(drm_gem_ttm_vmap);

/**
 * drm_gem_ttm_vunmap() - vunmap &ttm_buffer_object
 * @gem: GEM object.
 * @map: dma-buf mapping.
 *
 * Unmaps a GEM object with ttm_bo_vunmap(). This function can be used as
 * &drm_gem_object_funcs.vmap callback.
 */
void drm_gem_ttm_vunmap(struct drm_gem_object *gem,
			struct dma_buf_map *map)
{
	struct ttm_buffer_object *bo = drm_gem_ttm_of_gem(gem);

	ttm_bo_vunmap(bo, map);
}
EXPORT_SYMBOL(drm_gem_ttm_vunmap);

/**
 * drm_gem_ttm_mmap() - mmap &ttm_buffer_object
 * @gem: GEM object.
+72 −0
Original line number Diff line number Diff line
@@ -32,6 +32,7 @@
#include <drm/ttm/ttm_bo_driver.h>
#include <drm/ttm/ttm_placement.h>
#include <drm/drm_vma_manager.h>
#include <linux/dma-buf-map.h>
#include <linux/io.h>
#include <linux/highmem.h>
#include <linux/wait.h>
@@ -471,6 +472,77 @@ void ttm_bo_kunmap(struct ttm_bo_kmap_obj *map)
}
EXPORT_SYMBOL(ttm_bo_kunmap);

int ttm_bo_vmap(struct ttm_buffer_object *bo, struct dma_buf_map *map)
{
	struct ttm_resource *mem = &bo->mem;
	int ret;

	ret = ttm_mem_io_reserve(bo->bdev, mem);
	if (ret)
		return ret;

	if (mem->bus.is_iomem) {
		void __iomem *vaddr_iomem;
		size_t size = bo->num_pages << PAGE_SHIFT;

		if (mem->bus.addr)
			vaddr_iomem = (void __iomem *)mem->bus.addr;
		else if (mem->bus.caching == ttm_write_combined)
			vaddr_iomem = ioremap_wc(mem->bus.offset, size);
		else
			vaddr_iomem = ioremap(mem->bus.offset, size);

		if (!vaddr_iomem)
			return -ENOMEM;

		dma_buf_map_set_vaddr_iomem(map, vaddr_iomem);

	} else {
		struct ttm_operation_ctx ctx = {
			.interruptible = false,
			.no_wait_gpu = false
		};
		struct ttm_tt *ttm = bo->ttm;
		pgprot_t prot;
		void *vaddr;

		ret = ttm_tt_populate(bo->bdev, ttm, &ctx);
		if (ret)
			return ret;

		/*
		 * We need to use vmap to get the desired page protection
		 * or to make the buffer object look contiguous.
		 */
		prot = ttm_io_prot(bo, mem, PAGE_KERNEL);
		vaddr = vmap(ttm->pages, bo->num_pages, 0, prot);
		if (!vaddr)
			return -ENOMEM;

		dma_buf_map_set_vaddr(map, vaddr);
	}

	return 0;
}
EXPORT_SYMBOL(ttm_bo_vmap);

void ttm_bo_vunmap(struct ttm_buffer_object *bo, struct dma_buf_map *map)
{
	struct ttm_resource *mem = &bo->mem;

	if (dma_buf_map_is_null(map))
		return;

	if (!map->is_iomem)
		vunmap(map->vaddr);
	else if (!mem->bus.addr)
		iounmap(map->vaddr_iomem);
	dma_buf_map_clear(map);

	ttm_mem_io_free(bo->bdev, &bo->mem);
}
EXPORT_SYMBOL(ttm_bo_vunmap);

static int ttm_bo_wait_free_node(struct ttm_buffer_object *bo,
				 bool dst_use_tt)
{
+6 −0
Original line number Diff line number Diff line
@@ -10,11 +10,17 @@
#include <drm/ttm/ttm_bo_api.h>
#include <drm/ttm/ttm_bo_driver.h>

struct dma_buf_map;

#define drm_gem_ttm_of_gem(gem_obj) \
	container_of(gem_obj, struct ttm_buffer_object, base)

void drm_gem_ttm_print_info(struct drm_printer *p, unsigned int indent,
			    const struct drm_gem_object *gem);
int drm_gem_ttm_vmap(struct drm_gem_object *gem,
		     struct dma_buf_map *map);
void drm_gem_ttm_vunmap(struct drm_gem_object *gem,
			struct dma_buf_map *map);
int drm_gem_ttm_mmap(struct drm_gem_object *gem,
		     struct vm_area_struct *vma);

+28 −0
Original line number Diff line number Diff line
@@ -48,6 +48,8 @@ struct ttm_bo_global;

struct ttm_bo_device;

struct dma_buf_map;

struct drm_mm_node;

struct ttm_placement;
@@ -495,6 +497,32 @@ int ttm_bo_kmap(struct ttm_buffer_object *bo, unsigned long start_page,
 */
void ttm_bo_kunmap(struct ttm_bo_kmap_obj *map);

/**
 * ttm_bo_vmap
 *
 * @bo: The buffer object.
 * @map: pointer to a struct dma_buf_map representing the map.
 *
 * Sets up a kernel virtual mapping, using ioremap or vmap to the
 * data in the buffer object. The parameter @map returns the virtual
 * address as struct dma_buf_map. Unmap the buffer with ttm_bo_vunmap().
 *
 * Returns
 * -ENOMEM: Out of memory.
 * -EINVAL: Invalid range.
 */
int ttm_bo_vmap(struct ttm_buffer_object *bo, struct dma_buf_map *map);

/**
 * ttm_bo_vunmap
 *
 * @bo: The buffer object.
 * @map: Object describing the map to unmap.
 *
 * Unmaps a kernel map set up by ttm_bo_vmap().
 */
void ttm_bo_vunmap(struct ttm_buffer_object *bo, struct dma_buf_map *map);

/**
 * ttm_bo_mmap_obj - mmap memory backed by a ttm buffer object.
 *
+20 −0
Original line number Diff line number Diff line
@@ -45,6 +45,12 @@
 *
 *	dma_buf_map_set_vaddr(&map. 0xdeadbeaf);
 *
 * To set an address in I/O memory, use dma_buf_map_set_vaddr_iomem().
 *
 * .. code-block:: c
 *
 *	dma_buf_map_set_vaddr_iomem(&map. 0xdeadbeaf);
 *
 * Test if a mapping is valid with either dma_buf_map_is_set() or
 * dma_buf_map_is_null().
 *
@@ -118,6 +124,20 @@ static inline void dma_buf_map_set_vaddr(struct dma_buf_map *map, void *vaddr)
	map->is_iomem = false;
}

/**
 * dma_buf_map_set_vaddr_iomem - Sets a dma-buf mapping structure to an address in I/O memory
 * @map:		The dma-buf mapping structure
 * @vaddr_iomem:	An I/O-memory address
 *
 * Sets the address and the I/O-memory flag.
 */
static inline void dma_buf_map_set_vaddr_iomem(struct dma_buf_map *map,
					       void __iomem *vaddr_iomem)
{
	map->vaddr_iomem = vaddr_iomem;
	map->is_iomem = true;
}

/**
 * dma_buf_map_is_equal - Compares two dma-buf mapping structures for equality
 * @lhs:	The dma-buf mapping structure