Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0de23977 authored by David Herrmann's avatar David Herrmann Committed by Dave Airlie
Browse files

drm/gem: convert to new unified vma manager



Use the new vma manager instead of the old hashtable. Also convert all
drivers to use the new convenience helpers. This drops all the
(map_list.hash.key << PAGE_SHIFT) non-sense.

Locking and access-management is exactly the same as before with an
additional lock inside of the vma-manager, which strictly wouldn't be
needed for gem.

v2:
 - rebase on drm-next
 - init nodes via drm_vma_node_reset() in drm_gem.c
v3:
 - fix tegra
v4:
 - remove duplicate if (drm_vma_node_has_offset()) checks
 - inline now trivial drm_vma_node_offset_addr() calls
v5:
 - skip node-reset on gem-init due to kzalloc()
 - do not allow mapping gem-objects with offsets (backwards compat)
 - remove unneccessary casts

Cc: Inki Dae <inki.dae@samsung.com>
Cc: Rob Clark <robdclark@gmail.com>
Cc: Dave Airlie <airlied@redhat.com>
Cc: Thierry Reding <thierry.reding@gmail.com>
Signed-off-by: default avatarDavid Herrmann <dh.herrmann@gmail.com>
Acked-by: default avatarPatrik Jakobsson <patrik.r.jakobsson@gmail.com>
Reviewed-by: default avatarDaniel Vetter <daniel.vetter@ffwll.ch>
Signed-off-by: default avatarDave Airlie <airlied@gmail.com>
parent fe3078fa
Loading
Loading
Loading
Loading
+15 −74
Original line number Diff line number Diff line
@@ -37,6 +37,7 @@
#include <linux/shmem_fs.h>
#include <linux/dma-buf.h>
#include <drm/drmP.h>
#include <drm/drm_vma_manager.h>

/** @file drm_gem.c
 *
@@ -102,13 +103,8 @@ drm_gem_init(struct drm_device *dev)
	}

	dev->mm_private = mm;

	if (drm_ht_create(&mm->offset_hash, 12)) {
		kfree(mm);
		return -ENOMEM;
	}

	drm_mm_init(&mm->offset_manager, DRM_FILE_PAGE_OFFSET_START,
	drm_vma_offset_manager_init(&mm->vma_manager,
				    DRM_FILE_PAGE_OFFSET_START,
				    DRM_FILE_PAGE_OFFSET_SIZE);

	return 0;
@@ -119,8 +115,7 @@ drm_gem_destroy(struct drm_device *dev)
{
	struct drm_gem_mm *mm = dev->mm_private;

	drm_mm_takedown(&mm->offset_manager);
	drm_ht_remove(&mm->offset_hash);
	drm_vma_offset_manager_destroy(&mm->vma_manager);
	kfree(mm);
	dev->mm_private = NULL;
}
@@ -302,12 +297,8 @@ drm_gem_free_mmap_offset(struct drm_gem_object *obj)
{
	struct drm_device *dev = obj->dev;
	struct drm_gem_mm *mm = dev->mm_private;
	struct drm_map_list *list = &obj->map_list;

	drm_ht_remove_item(&mm->offset_hash, &list->hash);
	drm_mm_put_block(list->file_offset_node);
	kfree(list->map);
	list->map = NULL;
	drm_vma_offset_remove(&mm->vma_manager, &obj->vma_node);
}
EXPORT_SYMBOL(drm_gem_free_mmap_offset);

@@ -327,54 +318,9 @@ drm_gem_create_mmap_offset(struct drm_gem_object *obj)
{
	struct drm_device *dev = obj->dev;
	struct drm_gem_mm *mm = dev->mm_private;
	struct drm_map_list *list;
	struct drm_local_map *map;
	int ret;

	/* Set the object up for mmap'ing */
	list = &obj->map_list;
	list->map = kzalloc(sizeof(struct drm_map_list), GFP_KERNEL);
	if (!list->map)
		return -ENOMEM;

	map = list->map;
	map->type = _DRM_GEM;
	map->size = obj->size;
	map->handle = obj;

	/* Get a DRM GEM mmap offset allocated... */
	list->file_offset_node = drm_mm_search_free(&mm->offset_manager,
			obj->size / PAGE_SIZE, 0, false);

	if (!list->file_offset_node) {
		DRM_ERROR("failed to allocate offset for bo %d\n", obj->name);
		ret = -ENOSPC;
		goto out_free_list;
	}

	list->file_offset_node = drm_mm_get_block(list->file_offset_node,
			obj->size / PAGE_SIZE, 0);
	if (!list->file_offset_node) {
		ret = -ENOMEM;
		goto out_free_list;
	}

	list->hash.key = list->file_offset_node->start;
	ret = drm_ht_insert_item(&mm->offset_hash, &list->hash);
	if (ret) {
		DRM_ERROR("failed to add to map hash\n");
		goto out_free_mm;
	}

	return 0;

out_free_mm:
	drm_mm_put_block(list->file_offset_node);
out_free_list:
	kfree(list->map);
	list->map = NULL;

	return ret;
	return drm_vma_offset_add(&mm->vma_manager, &obj->vma_node,
				  obj->size / PAGE_SIZE);
}
EXPORT_SYMBOL(drm_gem_create_mmap_offset);

@@ -703,8 +649,8 @@ int drm_gem_mmap(struct file *filp, struct vm_area_struct *vma)
	struct drm_file *priv = filp->private_data;
	struct drm_device *dev = priv->minor->dev;
	struct drm_gem_mm *mm = dev->mm_private;
	struct drm_local_map *map = NULL;
	struct drm_hash_item *hash;
	struct drm_gem_object *obj;
	struct drm_vma_offset_node *node;
	int ret = 0;

	if (drm_device_is_unplugged(dev))
@@ -712,21 +658,16 @@ int drm_gem_mmap(struct file *filp, struct vm_area_struct *vma)

	mutex_lock(&dev->struct_mutex);

	if (drm_ht_find_item(&mm->offset_hash, vma->vm_pgoff, &hash)) {
	node = drm_vma_offset_exact_lookup(&mm->vma_manager, vma->vm_pgoff,
					   vma_pages(vma));
	if (!node) {
		mutex_unlock(&dev->struct_mutex);
		return drm_mmap(filp, vma);
	}

	map = drm_hash_entry(hash, struct drm_map_list, hash)->map;
	if (!map ||
	    ((map->flags & _DRM_RESTRICTED) && !capable(CAP_SYS_ADMIN))) {
		ret =  -EPERM;
		goto out_unlock;
	}

	ret = drm_gem_mmap_obj(map->handle, map->size, vma);
	obj = container_of(node, struct drm_gem_object, vma_node);
	ret = drm_gem_mmap_obj(obj, drm_vma_node_size(node), vma);

out_unlock:
	mutex_unlock(&dev->struct_mutex);

	return ret;
+5 −11
Original line number Diff line number Diff line
@@ -27,11 +27,7 @@
#include <drm/drmP.h>
#include <drm/drm.h>
#include <drm/drm_gem_cma_helper.h>

static unsigned int get_gem_mmap_offset(struct drm_gem_object *obj)
{
	return (unsigned int)obj->map_list.hash.key << PAGE_SHIFT;
}
#include <drm/drm_vma_manager.h>

/*
 * __drm_gem_cma_create - Create a GEM CMA object without allocating memory
@@ -172,7 +168,6 @@ void drm_gem_cma_free_object(struct drm_gem_object *gem_obj)
{
	struct drm_gem_cma_object *cma_obj;

	if (gem_obj->map_list.map)
	drm_gem_free_mmap_offset(gem_obj);

	cma_obj = to_drm_gem_cma_obj(gem_obj);
@@ -237,7 +232,7 @@ int drm_gem_cma_dumb_map_offset(struct drm_file *file_priv,
		return -EINVAL;
	}

	*offset = get_gem_mmap_offset(gem_obj);
	*offset = drm_vma_node_offset_addr(&gem_obj->vma_node);

	drm_gem_object_unreference(gem_obj);

@@ -301,12 +296,11 @@ void drm_gem_cma_describe(struct drm_gem_cma_object *cma_obj, struct seq_file *m
{
	struct drm_gem_object *obj = &cma_obj->base;
	struct drm_device *dev = obj->dev;
	uint64_t off = 0;
	uint64_t off;

	WARN_ON(!mutex_is_locked(&dev->struct_mutex));

	if (obj->map_list.map)
		off = (uint64_t)obj->map_list.hash.key;
	off = drm_vma_node_start(&obj->vma_node);

	seq_printf(m, "%2d (%2d) %08llx %08Zx %p %d",
			obj->name, obj->refcount.refcount.counter,
+6 −8
Original line number Diff line number Diff line
@@ -10,6 +10,7 @@
 */

#include <drm/drmP.h>
#include <drm/drm_vma_manager.h>

#include <linux/shmem_fs.h>
#include <drm/exynos_drm.h>
@@ -152,7 +153,6 @@ out:
	exynos_drm_fini_buf(obj->dev, buf);
	exynos_gem_obj->buffer = NULL;

	if (obj->map_list.map)
	drm_gem_free_mmap_offset(obj);

	/* release file pointer to gem object. */
@@ -703,13 +703,11 @@ int exynos_drm_gem_dumb_map_offset(struct drm_file *file_priv,
		goto unlock;
	}

	if (!obj->map_list.map) {
	ret = drm_gem_create_mmap_offset(obj);
	if (ret)
		goto out;
	}

	*offset = (u64)obj->map_list.hash.key << PAGE_SHIFT;
	*offset = drm_vma_node_offset_addr(&obj->vma_node);
	DRM_DEBUG_KMS("offset = 0x%lx\n", (unsigned long)*offset);

out:
+6 −9
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@
#include <drm/drmP.h>
#include <drm/drm.h>
#include <drm/gma_drm.h>
#include <drm/drm_vma_manager.h>
#include "psb_drv.h"

int psb_gem_init_object(struct drm_gem_object *obj)
@@ -38,7 +39,6 @@ void psb_gem_free_object(struct drm_gem_object *obj)
	struct gtt_range *gtt = container_of(obj, struct gtt_range, gem);

	/* Remove the list map if one is present */
	if (obj->map_list.map)
	drm_gem_free_mmap_offset(obj);
	drm_gem_object_release(obj);

@@ -81,13 +81,10 @@ int psb_gem_dumb_map_gtt(struct drm_file *file, struct drm_device *dev,
	/* What validation is needed here ? */

	/* Make it mmapable */
	if (!obj->map_list.map) {
	ret = drm_gem_create_mmap_offset(obj);
	if (ret)
		goto out;
	}
	/* GEM should really work out the hash offsets for us */
	*offset = (u64)obj->map_list.hash.key << PAGE_SHIFT;
	*offset = drm_vma_node_offset_addr(&obj->vma_node);
out:
	drm_gem_object_unreference(obj);
unlock:
+4 −6
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@
 */

#include <drm/drmP.h>
#include <drm/drm_vma_manager.h>
#include <drm/i915_drm.h>
#include "i915_drv.h"
#include "i915_trace.h"
@@ -1428,7 +1429,7 @@ i915_gem_release_mmap(struct drm_i915_gem_object *obj)

	if (obj->base.dev->dev_mapping)
		unmap_mapping_range(obj->base.dev->dev_mapping,
				    (loff_t)obj->base.map_list.hash.key<<PAGE_SHIFT,
				    (loff_t)drm_vma_node_offset_addr(&obj->base.vma_node),
				    obj->base.size, 1);

	obj->fault_mappable = false;
@@ -1486,7 +1487,7 @@ static int i915_gem_object_create_mmap_offset(struct drm_i915_gem_object *obj)
	struct drm_i915_private *dev_priv = obj->base.dev->dev_private;
	int ret;

	if (obj->base.map_list.map)
	if (drm_vma_node_has_offset(&obj->base.vma_node))
		return 0;

	dev_priv->mm.shrinker_no_lock_stealing = true;
@@ -1517,9 +1518,6 @@ out:

static void i915_gem_object_free_mmap_offset(struct drm_i915_gem_object *obj)
{
	if (!obj->base.map_list.map)
		return;

	drm_gem_free_mmap_offset(&obj->base);
}

@@ -1558,7 +1556,7 @@ i915_gem_mmap_gtt(struct drm_file *file,
	if (ret)
		goto out;

	*offset = (u64)obj->base.map_list.hash.key << PAGE_SHIFT;
	*offset = drm_vma_node_offset_addr(&obj->base.vma_node);

out:
	drm_gem_object_unreference(&obj->base);
Loading