Commit 8aadeb8a authored by Zack Rusin's avatar Zack Rusin
Browse files

drm/vmwgfx: Remove the dedicated memory accounting



vmwgfx shared very elaborate memory accounting with ttm. It was moved
from ttm to vmwgfx in change
f07069da ("drm/ttm: move memory accounting into vmwgfx v4")
but because of complexity it was hard to maintain. Some parts of the code
weren't freeing memory correctly and  some were missing accounting all
together. While those would be fairly easy to fix the fundamental reason
for memory accounting in the driver was the ability to invoke shrinker
which is part of TTM code as well (with support for unified memory
hopefully coming soon).

That meant that vmwgfx had a lot of code that was either unused or
duplicating code from TTM. Removing this code also prevents excessive
calls to global swapout which were common during memory pressure
because both vmwgfx and TTM would invoke the shrinker when memory
usage reached half of RAM.

Fixes: f07069da ("drm/ttm: move memory accounting into vmwgfx v4")
Signed-off-by: default avatarZack Rusin <zackr@vmware.com>
Reviewed-by: default avatarMartin Krastev <krastevm@vmware.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20211206172620.3139754-2-zack@kde.org
parent 21a6732f
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -9,7 +9,7 @@ vmwgfx-y := vmwgfx_execbuf.o vmwgfx_gmr.o vmwgfx_hashtab.o vmwgfx_kms.o vmwgfx_d
	    vmwgfx_cotable.o vmwgfx_so.o vmwgfx_binding.o vmwgfx_msg.o \
	    vmwgfx_simple_resource.o vmwgfx_va.o vmwgfx_blit.o \
	    vmwgfx_validation.o vmwgfx_page_dirty.o vmwgfx_streamoutput.o \
	    vmwgfx_devcaps.o ttm_object.o ttm_memory.o vmwgfx_system_manager.o
	    vmwgfx_devcaps.o ttm_object.o vmwgfx_system_manager.o

vmwgfx-$(CONFIG_DRM_FBDEV_EMULATION) += vmwgfx_fb.o
vmwgfx-$(CONFIG_TRANSPARENT_HUGEPAGE) += vmwgfx_thp.o
+0 −586
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0 OR MIT */
/**************************************************************************
 *
 * Copyright (c) 2006-2009 VMware, Inc., Palo Alto, CA., USA
 * All Rights Reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sub license, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice (including the
 * next paragraph) shall be included in all copies or substantial portions
 * of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
 * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
 * USE OR OTHER DEALINGS IN THE SOFTWARE.
 *
 **************************************************************************/

#define pr_fmt(fmt) "[TTM] " fmt

#include <linux/spinlock.h>
#include <linux/sched.h>
#include <linux/wait.h>
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/slab.h>

#include <drm/drm_device.h>
#include <drm/drm_file.h>
#include <drm/ttm/ttm_device.h>

#include "ttm_memory.h"

#define TTM_MEMORY_ALLOC_RETRIES 4

struct ttm_mem_global ttm_mem_glob;
EXPORT_SYMBOL(ttm_mem_glob);

struct ttm_mem_zone {
	struct kobject kobj;
	struct ttm_mem_global *glob;
	const char *name;
	uint64_t zone_mem;
	uint64_t emer_mem;
	uint64_t max_mem;
	uint64_t swap_limit;
	uint64_t used_mem;
};

static struct attribute ttm_mem_sys = {
	.name = "zone_memory",
	.mode = S_IRUGO
};
static struct attribute ttm_mem_emer = {
	.name = "emergency_memory",
	.mode = S_IRUGO | S_IWUSR
};
static struct attribute ttm_mem_max = {
	.name = "available_memory",
	.mode = S_IRUGO | S_IWUSR
};
static struct attribute ttm_mem_swap = {
	.name = "swap_limit",
	.mode = S_IRUGO | S_IWUSR
};
static struct attribute ttm_mem_used = {
	.name = "used_memory",
	.mode = S_IRUGO
};

static void ttm_mem_zone_kobj_release(struct kobject *kobj)
{
	struct ttm_mem_zone *zone =
		container_of(kobj, struct ttm_mem_zone, kobj);

	pr_info("Zone %7s: Used memory at exit: %llu KiB\n",
		zone->name, (unsigned long long)zone->used_mem >> 10);
	kfree(zone);
}

static ssize_t ttm_mem_zone_show(struct kobject *kobj,
				 struct attribute *attr,
				 char *buffer)
{
	struct ttm_mem_zone *zone =
		container_of(kobj, struct ttm_mem_zone, kobj);
	uint64_t val = 0;

	spin_lock(&zone->glob->lock);
	if (attr == &ttm_mem_sys)
		val = zone->zone_mem;
	else if (attr == &ttm_mem_emer)
		val = zone->emer_mem;
	else if (attr == &ttm_mem_max)
		val = zone->max_mem;
	else if (attr == &ttm_mem_swap)
		val = zone->swap_limit;
	else if (attr == &ttm_mem_used)
		val = zone->used_mem;
	spin_unlock(&zone->glob->lock);

	return snprintf(buffer, PAGE_SIZE, "%llu\n",
			(unsigned long long) val >> 10);
}

static void ttm_check_swapping(struct ttm_mem_global *glob);

static ssize_t ttm_mem_zone_store(struct kobject *kobj,
				  struct attribute *attr,
				  const char *buffer,
				  size_t size)
{
	struct ttm_mem_zone *zone =
		container_of(kobj, struct ttm_mem_zone, kobj);
	int chars;
	unsigned long val;
	uint64_t val64;

	chars = sscanf(buffer, "%lu", &val);
	if (chars == 0)
		return size;

	val64 = val;
	val64 <<= 10;

	spin_lock(&zone->glob->lock);
	if (val64 > zone->zone_mem)
		val64 = zone->zone_mem;
	if (attr == &ttm_mem_emer) {
		zone->emer_mem = val64;
		if (zone->max_mem > val64)
			zone->max_mem = val64;
	} else if (attr == &ttm_mem_max) {
		zone->max_mem = val64;
		if (zone->emer_mem < val64)
			zone->emer_mem = val64;
	} else if (attr == &ttm_mem_swap)
		zone->swap_limit = val64;
	spin_unlock(&zone->glob->lock);

	ttm_check_swapping(zone->glob);

	return size;
}

static struct attribute *ttm_mem_zone_attrs[] = {
	&ttm_mem_sys,
	&ttm_mem_emer,
	&ttm_mem_max,
	&ttm_mem_swap,
	&ttm_mem_used,
	NULL
};

static const struct sysfs_ops ttm_mem_zone_ops = {
	.show = &ttm_mem_zone_show,
	.store = &ttm_mem_zone_store
};

static struct kobj_type ttm_mem_zone_kobj_type = {
	.release = &ttm_mem_zone_kobj_release,
	.sysfs_ops = &ttm_mem_zone_ops,
	.default_attrs = ttm_mem_zone_attrs,
};
static struct kobj_type ttm_mem_glob_kobj_type = {0};

static bool ttm_zones_above_swap_target(struct ttm_mem_global *glob,
					bool from_wq, uint64_t extra)
{
	unsigned int i;
	struct ttm_mem_zone *zone;
	uint64_t target;

	for (i = 0; i < glob->num_zones; ++i) {
		zone = glob->zones[i];

		if (from_wq)
			target = zone->swap_limit;
		else if (capable(CAP_SYS_ADMIN))
			target = zone->emer_mem;
		else
			target = zone->max_mem;

		target = (extra > target) ? 0ULL : target;

		if (zone->used_mem > target)
			return true;
	}
	return false;
}

/*
 * At this point we only support a single shrink callback.
 * Extend this if needed, perhaps using a linked list of callbacks.
 * Note that this function is reentrant:
 * many threads may try to swap out at any given time.
 */

static void ttm_shrink(struct ttm_mem_global *glob, bool from_wq,
			uint64_t extra, struct ttm_operation_ctx *ctx)
{
	int ret;

	spin_lock(&glob->lock);

	while (ttm_zones_above_swap_target(glob, from_wq, extra)) {
		spin_unlock(&glob->lock);
		ret = ttm_global_swapout(ctx, GFP_KERNEL);
		spin_lock(&glob->lock);
		if (unlikely(ret <= 0))
			break;
	}

	spin_unlock(&glob->lock);
}

static void ttm_shrink_work(struct work_struct *work)
{
	struct ttm_operation_ctx ctx = {
		.interruptible = false,
		.no_wait_gpu = false
	};
	struct ttm_mem_global *glob =
	    container_of(work, struct ttm_mem_global, work);

	ttm_shrink(glob, true, 0ULL, &ctx);
}

static int ttm_mem_init_kernel_zone(struct ttm_mem_global *glob,
				    const struct sysinfo *si)
{
	struct ttm_mem_zone *zone = kzalloc(sizeof(*zone), GFP_KERNEL);
	uint64_t mem;
	int ret;

	if (unlikely(!zone))
		return -ENOMEM;

	mem = si->totalram - si->totalhigh;
	mem *= si->mem_unit;

	zone->name = "kernel";
	zone->zone_mem = mem;
	zone->max_mem = mem >> 1;
	zone->emer_mem = (mem >> 1) + (mem >> 2);
	zone->swap_limit = zone->max_mem - (mem >> 3);
	zone->used_mem = 0;
	zone->glob = glob;
	glob->zone_kernel = zone;
	ret = kobject_init_and_add(
		&zone->kobj, &ttm_mem_zone_kobj_type, &glob->kobj, zone->name);
	if (unlikely(ret != 0)) {
		kobject_put(&zone->kobj);
		return ret;
	}
	glob->zones[glob->num_zones++] = zone;
	return 0;
}

#ifdef CONFIG_HIGHMEM
static int ttm_mem_init_highmem_zone(struct ttm_mem_global *glob,
				     const struct sysinfo *si)
{
	struct ttm_mem_zone *zone;
	uint64_t mem;
	int ret;

	if (si->totalhigh == 0)
		return 0;

	zone = kzalloc(sizeof(*zone), GFP_KERNEL);
	if (unlikely(!zone))
		return -ENOMEM;

	mem = si->totalram;
	mem *= si->mem_unit;

	zone->name = "highmem";
	zone->zone_mem = mem;
	zone->max_mem = mem >> 1;
	zone->emer_mem = (mem >> 1) + (mem >> 2);
	zone->swap_limit = zone->max_mem - (mem >> 3);
	zone->used_mem = 0;
	zone->glob = glob;
	glob->zone_highmem = zone;
	ret = kobject_init_and_add(
		&zone->kobj, &ttm_mem_zone_kobj_type, &glob->kobj, "%s",
		zone->name);
	if (unlikely(ret != 0)) {
		kobject_put(&zone->kobj);
		return ret;
	}
	glob->zones[glob->num_zones++] = zone;
	return 0;
}
#else
static int ttm_mem_init_dma32_zone(struct ttm_mem_global *glob,
				   const struct sysinfo *si)
{
	struct ttm_mem_zone *zone = kzalloc(sizeof(*zone), GFP_KERNEL);
	uint64_t mem;
	int ret;

	if (unlikely(!zone))
		return -ENOMEM;

	mem = si->totalram;
	mem *= si->mem_unit;

	/**
	 * No special dma32 zone needed.
	 */

	if (mem <= ((uint64_t) 1ULL << 32)) {
		kfree(zone);
		return 0;
	}

	/*
	 * Limit max dma32 memory to 4GB for now
	 * until we can figure out how big this
	 * zone really is.
	 */

	mem = ((uint64_t) 1ULL << 32);
	zone->name = "dma32";
	zone->zone_mem = mem;
	zone->max_mem = mem >> 1;
	zone->emer_mem = (mem >> 1) + (mem >> 2);
	zone->swap_limit = zone->max_mem - (mem >> 3);
	zone->used_mem = 0;
	zone->glob = glob;
	glob->zone_dma32 = zone;
	ret = kobject_init_and_add(
		&zone->kobj, &ttm_mem_zone_kobj_type, &glob->kobj, zone->name);
	if (unlikely(ret != 0)) {
		kobject_put(&zone->kobj);
		return ret;
	}
	glob->zones[glob->num_zones++] = zone;
	return 0;
}
#endif

int ttm_mem_global_init(struct ttm_mem_global *glob, struct device *dev)
{
	struct sysinfo si;
	int ret;
	int i;
	struct ttm_mem_zone *zone;

	spin_lock_init(&glob->lock);
	glob->swap_queue = create_singlethread_workqueue("ttm_swap");
	INIT_WORK(&glob->work, ttm_shrink_work);

	ret = kobject_init_and_add(&glob->kobj, &ttm_mem_glob_kobj_type,
				   &dev->kobj, "memory_accounting");
	if (unlikely(ret != 0)) {
		kobject_put(&glob->kobj);
		return ret;
	}

	si_meminfo(&si);

	ret = ttm_mem_init_kernel_zone(glob, &si);
	if (unlikely(ret != 0))
		goto out_no_zone;
#ifdef CONFIG_HIGHMEM
	ret = ttm_mem_init_highmem_zone(glob, &si);
	if (unlikely(ret != 0))
		goto out_no_zone;
#else
	ret = ttm_mem_init_dma32_zone(glob, &si);
	if (unlikely(ret != 0))
		goto out_no_zone;
#endif
	for (i = 0; i < glob->num_zones; ++i) {
		zone = glob->zones[i];
		pr_info("Zone %7s: Available graphics memory: %llu KiB\n",
			zone->name, (unsigned long long)zone->max_mem >> 10);
	}
	return 0;
out_no_zone:
	ttm_mem_global_release(glob);
	return ret;
}

void ttm_mem_global_release(struct ttm_mem_global *glob)
{
	struct ttm_mem_zone *zone;
	unsigned int i;

	destroy_workqueue(glob->swap_queue);
	glob->swap_queue = NULL;
	for (i = 0; i < glob->num_zones; ++i) {
		zone = glob->zones[i];
		kobject_del(&zone->kobj);
		kobject_put(&zone->kobj);
	}
	kobject_del(&glob->kobj);
	kobject_put(&glob->kobj);
	memset(glob, 0, sizeof(*glob));
}

static void ttm_check_swapping(struct ttm_mem_global *glob)
{
	bool needs_swapping = false;
	unsigned int i;
	struct ttm_mem_zone *zone;

	spin_lock(&glob->lock);
	for (i = 0; i < glob->num_zones; ++i) {
		zone = glob->zones[i];
		if (zone->used_mem > zone->swap_limit) {
			needs_swapping = true;
			break;
		}
	}

	spin_unlock(&glob->lock);

	if (unlikely(needs_swapping))
		(void)queue_work(glob->swap_queue, &glob->work);

}

static void ttm_mem_global_free_zone(struct ttm_mem_global *glob,
				     struct ttm_mem_zone *single_zone,
				     uint64_t amount)
{
	unsigned int i;
	struct ttm_mem_zone *zone;

	spin_lock(&glob->lock);
	for (i = 0; i < glob->num_zones; ++i) {
		zone = glob->zones[i];
		if (single_zone && zone != single_zone)
			continue;
		zone->used_mem -= amount;
	}
	spin_unlock(&glob->lock);
}

void ttm_mem_global_free(struct ttm_mem_global *glob,
			 uint64_t amount)
{
	return ttm_mem_global_free_zone(glob, glob->zone_kernel, amount);
}
EXPORT_SYMBOL(ttm_mem_global_free);

static int ttm_mem_global_reserve(struct ttm_mem_global *glob,
				  struct ttm_mem_zone *single_zone,
				  uint64_t amount, bool reserve)
{
	uint64_t limit;
	int ret = -ENOMEM;
	unsigned int i;
	struct ttm_mem_zone *zone;

	spin_lock(&glob->lock);
	for (i = 0; i < glob->num_zones; ++i) {
		zone = glob->zones[i];
		if (single_zone && zone != single_zone)
			continue;

		limit = (capable(CAP_SYS_ADMIN)) ?
			zone->emer_mem : zone->max_mem;

		if (zone->used_mem > limit)
			goto out_unlock;
	}

	if (reserve) {
		for (i = 0; i < glob->num_zones; ++i) {
			zone = glob->zones[i];
			if (single_zone && zone != single_zone)
				continue;
			zone->used_mem += amount;
		}
	}

	ret = 0;
out_unlock:
	spin_unlock(&glob->lock);
	ttm_check_swapping(glob);

	return ret;
}


static int ttm_mem_global_alloc_zone(struct ttm_mem_global *glob,
				     struct ttm_mem_zone *single_zone,
				     uint64_t memory,
				     struct ttm_operation_ctx *ctx)
{
	int count = TTM_MEMORY_ALLOC_RETRIES;

	while (unlikely(ttm_mem_global_reserve(glob,
					       single_zone,
					       memory, true)
			!= 0)) {
		if (ctx->no_wait_gpu)
			return -ENOMEM;
		if (unlikely(count-- == 0))
			return -ENOMEM;
		ttm_shrink(glob, false, memory + (memory >> 2) + 16, ctx);
	}

	return 0;
}

int ttm_mem_global_alloc(struct ttm_mem_global *glob, uint64_t memory,
			 struct ttm_operation_ctx *ctx)
{
	/**
	 * Normal allocations of kernel memory are registered in
	 * the kernel zone.
	 */

	return ttm_mem_global_alloc_zone(glob, glob->zone_kernel, memory, ctx);
}
EXPORT_SYMBOL(ttm_mem_global_alloc);

int ttm_mem_global_alloc_page(struct ttm_mem_global *glob,
			      struct page *page, uint64_t size,
			      struct ttm_operation_ctx *ctx)
{
	struct ttm_mem_zone *zone = NULL;

	/**
	 * Page allocations may be registed in a single zone
	 * only if highmem or !dma32.
	 */

#ifdef CONFIG_HIGHMEM
	if (PageHighMem(page) && glob->zone_highmem != NULL)
		zone = glob->zone_highmem;
#else
	if (glob->zone_dma32 && page_to_pfn(page) > 0x00100000UL)
		zone = glob->zone_kernel;
#endif
	return ttm_mem_global_alloc_zone(glob, zone, size, ctx);
}

void ttm_mem_global_free_page(struct ttm_mem_global *glob, struct page *page,
			      uint64_t size)
{
	struct ttm_mem_zone *zone = NULL;

#ifdef CONFIG_HIGHMEM
	if (PageHighMem(page) && glob->zone_highmem != NULL)
		zone = glob->zone_highmem;
#else
	if (glob->zone_dma32 && page_to_pfn(page) > 0x00100000UL)
		zone = glob->zone_kernel;
#endif
	ttm_mem_global_free_zone(glob, zone, size);
}

size_t ttm_round_pot(size_t size)
{
	if ((size & (size - 1)) == 0)
		return size;
	else if (size > PAGE_SIZE)
		return PAGE_ALIGN(size);
	else {
		size_t tmp_size = 4;

		while (tmp_size < size)
			tmp_size <<= 1;

		return tmp_size;
	}
	return 0;
}
EXPORT_SYMBOL(ttm_round_pot);
+0 −92
Original line number Diff line number Diff line
/**************************************************************************
 *
 * Copyright (c) 2006-2009 VMware, Inc., Palo Alto, CA., USA
 * All Rights Reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sub license, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice (including the
 * next paragraph) shall be included in all copies or substantial portions
 * of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
 * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
 * USE OR OTHER DEALINGS IN THE SOFTWARE.
 *
 **************************************************************************/

#ifndef TTM_MEMORY_H
#define TTM_MEMORY_H

#include <linux/workqueue.h>
#include <linux/spinlock.h>
#include <linux/bug.h>
#include <linux/wait.h>
#include <linux/errno.h>
#include <linux/kobject.h>
#include <linux/mm.h>

#include <drm/ttm/ttm_bo_api.h>

/**
 * struct ttm_mem_global - Global memory accounting structure.
 *
 * @shrink: A single callback to shrink TTM memory usage. Extend this
 * to a linked list to be able to handle multiple callbacks when needed.
 * @swap_queue: A workqueue to handle shrinking in low memory situations. We
 * need a separate workqueue since it will spend a lot of time waiting
 * for the GPU, and this will otherwise block other workqueue tasks(?)
 * At this point we use only a single-threaded workqueue.
 * @work: The workqueue callback for the shrink queue.
 * @lock: Lock to protect the @shrink - and the memory accounting members,
 * that is, essentially the whole structure with some exceptions.
 * @zones: Array of pointers to accounting zones.
 * @num_zones: Number of populated entries in the @zones array.
 * @zone_kernel: Pointer to the kernel zone.
 * @zone_highmem: Pointer to the highmem zone if there is one.
 * @zone_dma32: Pointer to the dma32 zone if there is one.
 *
 * Note that this structure is not per device. It should be global for all
 * graphics devices.
 */

#define TTM_MEM_MAX_ZONES 2
struct ttm_mem_zone;
extern struct ttm_mem_global {
	struct kobject kobj;
	struct workqueue_struct *swap_queue;
	struct work_struct work;
	spinlock_t lock;
	struct ttm_mem_zone *zones[TTM_MEM_MAX_ZONES];
	unsigned int num_zones;
	struct ttm_mem_zone *zone_kernel;
#ifdef CONFIG_HIGHMEM
	struct ttm_mem_zone *zone_highmem;
#else
	struct ttm_mem_zone *zone_dma32;
#endif
} ttm_mem_glob;

int ttm_mem_global_init(struct ttm_mem_global *glob, struct device *dev);
void ttm_mem_global_release(struct ttm_mem_global *glob);
int ttm_mem_global_alloc(struct ttm_mem_global *glob, uint64_t memory,
			 struct ttm_operation_ctx *ctx);
void ttm_mem_global_free(struct ttm_mem_global *glob, uint64_t amount);
int ttm_mem_global_alloc_page(struct ttm_mem_global *glob,
			      struct page *page, uint64_t size,
			      struct ttm_operation_ctx *ctx);
void ttm_mem_global_free_page(struct ttm_mem_global *glob,
			      struct page *page, uint64_t size);
size_t ttm_round_pot(size_t size);

#endif
+2 −34
Original line number Diff line number Diff line
@@ -93,10 +93,8 @@ struct ttm_object_device {
	spinlock_t object_lock;
	struct vmwgfx_open_hash object_hash;
	atomic_t object_count;
	struct ttm_mem_global *mem_glob;
	struct dma_buf_ops ops;
	void (*dmabuf_release)(struct dma_buf *dma_buf);
	size_t dma_buf_size;
	struct idr idr;
};

@@ -352,11 +350,6 @@ int ttm_ref_object_add(struct ttm_object_file *tfile,
	struct vmwgfx_open_hash *ht = &tfile->ref_hash[ref_type];
	struct ttm_ref_object *ref;
	struct vmwgfx_hash_item *hash;
	struct ttm_mem_global *mem_glob = tfile->tdev->mem_glob;
	struct ttm_operation_ctx ctx = {
		.interruptible = false,
		.no_wait_gpu = false
	};
	int ret = -EINVAL;

	if (base->tfile != tfile && !base->shareable)
@@ -381,13 +374,8 @@ int ttm_ref_object_add(struct ttm_object_file *tfile,
		if (require_existed)
			return -EPERM;

		ret = ttm_mem_global_alloc(mem_glob, sizeof(*ref),
					   &ctx);
		if (unlikely(ret != 0))
			return ret;
		ref = kmalloc(sizeof(*ref), GFP_KERNEL);
		if (unlikely(ref == NULL)) {
			ttm_mem_global_free(mem_glob, sizeof(*ref));
			return -ENOMEM;
		}

@@ -412,7 +400,6 @@ int ttm_ref_object_add(struct ttm_object_file *tfile,
		spin_unlock(&tfile->lock);
		BUG_ON(ret != -EINVAL);

		ttm_mem_global_free(mem_glob, sizeof(*ref));
		kfree(ref);
	}

@@ -427,7 +414,6 @@ ttm_ref_object_release(struct kref *kref)
	struct ttm_base_object *base = ref->obj;
	struct ttm_object_file *tfile = ref->tfile;
	struct vmwgfx_open_hash *ht;
	struct ttm_mem_global *mem_glob = tfile->tdev->mem_glob;

	ht = &tfile->ref_hash[ref->ref_type];
	(void)vmwgfx_ht_remove_item_rcu(ht, &ref->hash);
@@ -438,7 +424,6 @@ ttm_ref_object_release(struct kref *kref)
		base->ref_obj_release(base, ref->ref_type);

	ttm_base_object_unref(&ref->obj);
	ttm_mem_global_free(mem_glob, sizeof(*ref));
	kfree_rcu(ref, rcu_head);
	spin_lock(&tfile->lock);
}
@@ -526,8 +511,7 @@ struct ttm_object_file *ttm_object_file_init(struct ttm_object_device *tdev,
}

struct ttm_object_device *
ttm_object_device_init(struct ttm_mem_global *mem_glob,
		       unsigned int hash_order,
ttm_object_device_init(unsigned int hash_order,
		       const struct dma_buf_ops *ops)
{
	struct ttm_object_device *tdev = kmalloc(sizeof(*tdev), GFP_KERNEL);
@@ -536,7 +520,6 @@ ttm_object_device_init(struct ttm_mem_global *mem_glob,
	if (unlikely(tdev == NULL))
		return NULL;

	tdev->mem_glob = mem_glob;
	spin_lock_init(&tdev->object_lock);
	atomic_set(&tdev->object_count, 0);
	ret = vmwgfx_ht_create(&tdev->object_hash, hash_order);
@@ -547,8 +530,6 @@ ttm_object_device_init(struct ttm_mem_global *mem_glob,
	tdev->ops = *ops;
	tdev->dmabuf_release = tdev->ops.release;
	tdev->ops.release = ttm_prime_dmabuf_release;
	tdev->dma_buf_size = ttm_round_pot(sizeof(struct dma_buf)) +
		ttm_round_pot(sizeof(struct file));
	return tdev;

out_no_object_hash:
@@ -633,7 +614,6 @@ static void ttm_prime_dmabuf_release(struct dma_buf *dma_buf)
	if (prime->dma_buf == dma_buf)
		prime->dma_buf = NULL;
	mutex_unlock(&prime->mutex);
	ttm_mem_global_free(tdev->mem_glob, tdev->dma_buf_size);
	ttm_base_object_unref(&base);
}

@@ -715,30 +695,18 @@ int ttm_prime_handle_to_fd(struct ttm_object_file *tfile,
	dma_buf = prime->dma_buf;
	if (!dma_buf || !get_dma_buf_unless_doomed(dma_buf)) {
		DEFINE_DMA_BUF_EXPORT_INFO(exp_info);
		struct ttm_operation_ctx ctx = {
			.interruptible = true,
			.no_wait_gpu = false
		};
		exp_info.ops = &tdev->ops;
		exp_info.size = prime->size;
		exp_info.flags = flags;
		exp_info.priv = prime;

		/*
		 * Need to create a new dma_buf, with memory accounting.
		 * Need to create a new dma_buf
		 */
		ret = ttm_mem_global_alloc(tdev->mem_glob, tdev->dma_buf_size,
					   &ctx);
		if (unlikely(ret != 0)) {
			mutex_unlock(&prime->mutex);
			goto out_unref;
		}

		dma_buf = dma_buf_export(&exp_info);
		if (IS_ERR(dma_buf)) {
			ret = PTR_ERR(dma_buf);
			ttm_mem_global_free(tdev->mem_glob,
					    tdev->dma_buf_size);
			mutex_unlock(&prime->mutex);
			goto out_unref;
		}
+1 −11
Original line number Diff line number Diff line
@@ -42,7 +42,6 @@
#include <linux/list.h>
#include <linux/rcupdate.h>

#include "ttm_memory.h"
#include "vmwgfx_hashtab.h"

/**
@@ -296,7 +295,6 @@ extern void ttm_object_file_release(struct ttm_object_file **p_tfile);
/**
 * ttm_object device init - initialize a struct ttm_object_device
 *
 * @mem_glob: struct ttm_mem_global for memory accounting.
 * @hash_order: Order of hash table used to hash the base objects.
 * @ops: DMA buf ops for prime objects of this device.
 *
@@ -305,8 +303,7 @@ extern void ttm_object_file_release(struct ttm_object_file **p_tfile);
 */

extern struct ttm_object_device *
ttm_object_device_init(struct ttm_mem_global *mem_glob,
		       unsigned int hash_order,
ttm_object_device_init(unsigned int hash_order,
		       const struct dma_buf_ops *ops);

/**
@@ -352,13 +349,6 @@ extern int ttm_prime_handle_to_fd(struct ttm_object_file *tfile,
#define ttm_prime_object_kfree(__obj, __prime)		\
	kfree_rcu(__obj, __prime.base.rhead)

/*
 * Extra memory required by the base object's idr storage, which is allocated
 * separately from the base object itself. We estimate an on-average 128 bytes
 * per idr.
 */
#define TTM_OBJ_EXTRA_SIZE 128

struct ttm_base_object *
ttm_base_object_noref_lookup(struct ttm_object_file *tfile, uint32_t key);

Loading