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

Commit 26fffce1 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "msm: kgsl: add syncsource interface"

parents cc34bfd6 f4a206a7
Loading
Loading
Loading
Loading
+22 −0
Original line number Diff line number Diff line
@@ -788,6 +788,7 @@ static void kgsl_destroy_process_private(struct kref *kref)
		debugfs_remove_recursive(private->debug_root);

	idr_destroy(&private->mem_idr);
	idr_destroy(&private->syncsource_idr);
	kgsl_mmu_putpagetable(private->pagetable);

	kfree(private);
@@ -893,6 +894,8 @@ kgsl_get_process_private(struct kgsl_device *device)
	private->mem_rb = RB_ROOT;
	idr_init(&private->mem_idr);

	idr_init(&private->syncsource_idr);

	if ((!private->pagetable) && kgsl_mmu_enabled()) {
		unsigned long pt_name;

@@ -948,13 +951,24 @@ static int kgsl_release(struct inode *inodep, struct file *filep)
	struct kgsl_process_private *private = dev_priv->process_priv;
	struct kgsl_device *device = dev_priv->device;
	struct kgsl_context *context;
	struct kgsl_syncsource *syncsource;
	struct kgsl_mem_entry *entry;
	int next = 0;

	filep->private_data = NULL;

	next = 0;
	while (1) {
		syncsource = idr_get_next(&private->syncsource_idr, &next);

		if (syncsource == NULL)
			break;
		kgsl_syncsource_put(syncsource);
		next = next + 1;
	}
	kgsl_mutex_lock(&device->mutex, &device->mutex_owner);

	next = 0;
	while (1) {
		read_lock(&device->context_lock);
		context = idr_get_next(&device->context_idr, &next);
@@ -3542,6 +3556,14 @@ static const struct kgsl_ioctl kgsl_ioctl_funcs[] = {
			kgsl_ioctl_gpumem_sync_cache, 0),
	KGSL_IOCTL_FUNC(IOCTL_KGSL_GPUMEM_SYNC_CACHE_BULK,
			kgsl_ioctl_gpumem_sync_cache_bulk, 0),
	KGSL_IOCTL_FUNC(IOCTL_KGSL_SYNCSOURCE_CREATE,
			kgsl_ioctl_syncsource_create, 0),
	KGSL_IOCTL_FUNC(IOCTL_KGSL_SYNCSOURCE_DESTROY,
			kgsl_ioctl_syncsource_destroy, 0),
	KGSL_IOCTL_FUNC(IOCTL_KGSL_SYNCSOURCE_CREATE_FENCE,
			kgsl_ioctl_syncsource_create_fence, 0),
	KGSL_IOCTL_FUNC(IOCTL_KGSL_SYNCSOURCE_SIGNAL_FENCE,
			kgsl_ioctl_syncsource_signal_fence, 0),
};

long kgsl_ioctl_helper(struct file *filep, unsigned int cmd,
+9 −0
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@
#include "kgsl.h"
#include "kgsl_compat.h"
#include "kgsl_device.h"
#include "kgsl_sync.h"

#include "adreno.h"

@@ -343,6 +344,14 @@ static const struct kgsl_ioctl kgsl_compat_ioctl_funcs[] = {
			kgsl_ioctl_gpumem_sync_cache_compat, 0),
	KGSL_IOCTL_FUNC(IOCTL_KGSL_GPUMEM_SYNC_CACHE_BULK_COMPAT,
			kgsl_ioctl_gpumem_sync_cache_bulk_compat, 0),
	KGSL_IOCTL_FUNC(IOCTL_KGSL_SYNCSOURCE_CREATE,
			kgsl_ioctl_syncsource_create, 0),
	KGSL_IOCTL_FUNC(IOCTL_KGSL_SYNCSOURCE_DESTROY,
			kgsl_ioctl_syncsource_destroy, 0),
	KGSL_IOCTL_FUNC(IOCTL_KGSL_SYNCSOURCE_CREATE_FENCE,
			kgsl_ioctl_syncsource_create_fence, 0),
	KGSL_IOCTL_FUNC(IOCTL_KGSL_SYNCSOURCE_SIGNAL_FENCE,
			kgsl_ioctl_syncsource_signal_fence, 0),
};

long kgsl_compat_ioctl(struct file *filep, unsigned int cmd,
+3 −0
Original line number Diff line number Diff line
@@ -532,6 +532,7 @@ struct kgsl_context {
 * @kobj: Pointer to a kobj for the sysfs directory for this process
 * @debug_root: Pointer to the debugfs root for this process
 * @stats: Memory allocation statistics for this process
 * @syncsource_idr: sync sources created by this process
 */
struct kgsl_process_private {
	unsigned long priv;
@@ -555,6 +556,8 @@ struct kgsl_process_private {
		unsigned int cur;
		unsigned int max;
	} stats[KGSL_MEM_ENTRY_MAX];

	struct idr syncsource_idr;
};

/**
+199 −0
Original line number Diff line number Diff line
@@ -13,6 +13,7 @@

#include <linux/err.h>
#include <linux/file.h>
#include <linux/oneshot_sync.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
@@ -356,3 +357,201 @@ int kgsl_sync_fence_async_cancel(struct kgsl_sync_fence_waiter *kwaiter)
	}
	return 0;
}

#ifdef CONFIG_ONESHOT_SYNC

struct kgsl_syncsource {
	struct kref refcount;
	int id;
	struct kgsl_process_private *private;
	struct oneshot_sync_timeline *oneshot;
};

long kgsl_ioctl_syncsource_create(struct kgsl_device_private *dev_priv,
					unsigned int cmd, void *data)
{
	struct kgsl_syncsource *syncsource = NULL;
	struct kgsl_syncsource_create *param = data;
	int ret = -EINVAL;
	int id = 0;
	struct kgsl_process_private *private = dev_priv->process_priv;
	char name[32];

	syncsource = kzalloc(sizeof(*syncsource), GFP_KERNEL);
	if (syncsource == NULL) {
		ret = -ENOMEM;
		goto out;
	}

	snprintf(name, sizeof(name), "kgsl-syncsource-pid-%d",
			current->group_leader->pid);

	syncsource->oneshot = oneshot_timeline_create(name);
	if (syncsource->oneshot == NULL) {
		ret = -ENOMEM;
		goto out;
	}

	mutex_lock(&private->process_private_mutex);
	id = idr_alloc(&private->syncsource_idr, syncsource, 1, 0, GFP_KERNEL);
	if (id > 0) {
		kref_init(&syncsource->refcount);
		syncsource->id = id;
		syncsource->private = private;

		param->id = id;
		ret = 0;
	} else {
		ret = id;
	}
	mutex_unlock(&private->process_private_mutex);
out:
	if (ret) {
		if (syncsource && syncsource->oneshot)
			oneshot_timeline_destroy(syncsource->oneshot);
		kfree(syncsource);
	}

	return ret;
}

static struct kgsl_syncsource *
kgsl_syncsource_get(struct kgsl_process_private *private, int id)
{
	int result = 0;
	struct kgsl_syncsource *syncsource = NULL;

	mutex_lock(&private->process_private_mutex);

	syncsource = idr_find(&private->syncsource_idr, id);
	if (syncsource)
		result = kref_get_unless_zero(&syncsource->refcount);

	mutex_unlock(&private->process_private_mutex);

	return result ? syncsource : NULL;
}

static void kgsl_syncsource_destroy(struct kref *kref)
{
	struct kgsl_syncsource *syncsource = container_of(kref,
						struct kgsl_syncsource,
						refcount);

	struct kgsl_process_private *private = syncsource->private;

	mutex_lock(&private->process_private_mutex);
	if (syncsource->id != 0) {
		idr_remove(&private->syncsource_idr, syncsource->id);
		syncsource->id = 0;
	}
	oneshot_timeline_destroy(syncsource->oneshot);
	mutex_unlock(&private->process_private_mutex);

	kfree(syncsource);
}

void kgsl_syncsource_put(struct kgsl_syncsource *syncsource)
{
	if (syncsource)
		kref_put(&syncsource->refcount, kgsl_syncsource_destroy);
}

long kgsl_ioctl_syncsource_destroy(struct kgsl_device_private *dev_priv,
					unsigned int cmd, void *data)
{
	struct kgsl_syncsource_destroy *param = data;
	struct kgsl_syncsource *syncsource = NULL;
	struct kgsl_process_private *private;

	syncsource = kgsl_syncsource_get(dev_priv->process_priv,
				     param->id);

	if (syncsource == NULL)
		return -EINVAL;

	private = syncsource->private;

	mutex_lock(&private->process_private_mutex);
	idr_remove(&private->syncsource_idr, param->id);
	syncsource->id = 0;
	mutex_unlock(&private->process_private_mutex);

	/* put reference from syncsource creation */
	kgsl_syncsource_put(syncsource);
	/* put reference from getting the syncsource above */
	kgsl_syncsource_put(syncsource);
	return 0;
}

long kgsl_ioctl_syncsource_create_fence(struct kgsl_device_private *dev_priv,
					unsigned int cmd, void *data)
{
	struct kgsl_syncsource_create_fence *param = data;
	struct kgsl_syncsource *syncsource = NULL;
	int ret = -EINVAL;
	struct sync_fence *fence = NULL;
	int fd = -1;
	char name[32];


	syncsource = kgsl_syncsource_get(dev_priv->process_priv,
					param->id);
	if (syncsource == NULL)
		goto out;

	snprintf(name, sizeof(name), "kgsl-syncsource-pid-%d-%d",
			current->group_leader->pid, syncsource->id);

	fence = oneshot_fence_create(syncsource->oneshot, name);
	if (fence == NULL) {
		ret = -ENOMEM;
		goto out;
	}

	fd = get_unused_fd_flags(0);
	if (fd < 0) {
		ret = -EBADF;
		goto out;
	}
	ret = 0;

	sync_fence_install(fence, fd);

	param->fence_fd = fd;
out:
	if (ret) {
		if (fence)
			sync_fence_put(fence);
	}
	kgsl_syncsource_put(syncsource);
	return ret;
}

long kgsl_ioctl_syncsource_signal_fence(struct kgsl_device_private *dev_priv,
					unsigned int cmd, void *data)
{
	int ret = -EINVAL;
	struct kgsl_syncsource_signal_fence *param = data;
	struct kgsl_syncsource *syncsource = NULL;
	struct sync_fence *fence = NULL;

	syncsource = kgsl_syncsource_get(dev_priv->process_priv,
					param->id);
	if (syncsource == NULL)
		goto out;

	fence = sync_fence_fdget(param->fence_fd);
	if (fence == NULL) {
		ret = -EBADF;
		goto out;
	}

	ret = oneshot_fence_signal(syncsource->oneshot, fence);
out:
	if (fence)
		sync_fence_put(fence);
	kgsl_syncsource_put(syncsource);
	return ret;
}
#endif
+49 −0
Original line number Diff line number Diff line
@@ -35,6 +35,8 @@ struct kgsl_sync_fence_waiter {
	void *priv;
};

struct kgsl_syncsource;

#if defined(CONFIG_SYNC)
int kgsl_add_fence_event(struct kgsl_device *device,
	u32 context_id, u32 timestamp, void __user *data, int len,
@@ -77,4 +79,51 @@ kgsl_sync_fence_async_cancel(struct kgsl_sync_fence_waiter *waiter)

#endif

#ifdef CONFIG_ONESHOT_SYNC
long kgsl_ioctl_syncsource_create(struct kgsl_device_private *dev_priv,
					unsigned int cmd, void *data);
long kgsl_ioctl_syncsource_destroy(struct kgsl_device_private *dev_priv,
					unsigned int cmd, void *data);
long kgsl_ioctl_syncsource_create_fence(struct kgsl_device_private *dev_priv,
					unsigned int cmd, void *data);
long kgsl_ioctl_syncsource_signal_fence(struct kgsl_device_private *dev_priv,
					unsigned int cmd, void *data);

void kgsl_syncsource_put(struct kgsl_syncsource *syncsource);

#else
static inline long
kgsl_ioctl_syncsource_create(struct kgsl_device_private *dev_priv,
					unsigned int cmd, void *data)
{
	return -ENOIOCTLCMD;
}

static inline long
kgsl_ioctl_syncsource_destroy(struct kgsl_device_private *dev_priv,
					unsigned int cmd, void *data)
{
	return -ENOIOCTLCMD;
}

static inline long
kgsl_ioctl_syncsource_create_fence(struct kgsl_device_private *dev_priv,
					unsigned int cmd, void *data)
{
	return -ENOIOCTLCMD;
}

static inline long
kgsl_ioctl_syncsource_signal_fence(struct kgsl_device_private *dev_priv,
					unsigned int cmd, void *data)
{
	return -ENOIOCTLCMD;
}

static inline void kgsl_syncsource_put(struct kgsl_syncsource *syncsource)
{

}
#endif

#endif /* __KGSL_SYNC_H */
Loading