mirror of https://github.com/OpenIPC/firmware.git
				
				
				
			
		
			
				
	
	
		
			281 lines
		
	
	
		
			6.6 KiB
		
	
	
	
		
			Diff
		
	
	
			
		
		
	
	
			281 lines
		
	
	
		
			6.6 KiB
		
	
	
	
		
			Diff
		
	
	
| --- linux-4.9.37/drivers/fence/sw_sync.c	1970-01-01 03:00:00.000000000 +0300
 | |
| +++ linux-4.9.y/drivers/fence/sw_sync.c	2021-06-07 13:01:33.000000000 +0300
 | |
| @@ -0,0 +1,277 @@
 | |
| +/*
 | |
| + * drivers/base/sw_sync.c
 | |
| + *
 | |
| + * Copyright (C) 2012 Google, Inc.
 | |
| + *
 | |
| + * This software is licensed under the terms of the GNU General Public
 | |
| + * License version 2, as published by the Free Software Foundation, and
 | |
| + * may be copied, distributed, and modified under those terms.
 | |
| + *
 | |
| + * This program is distributed in the hope that it will be useful,
 | |
| + * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
| + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | |
| + * GNU General Public License for more details.
 | |
| + *
 | |
| + */
 | |
| +
 | |
| +#include <linux/kernel.h>
 | |
| +#include <linux/init.h>
 | |
| +#include <linux/export.h>
 | |
| +#include <linux/file.h>
 | |
| +#include <linux/fs.h>
 | |
| +#include <linux/miscdevice.h>
 | |
| +#include <linux/syscalls.h>
 | |
| +#include <linux/uaccess.h>
 | |
| +
 | |
| +#include "sw_sync.h"
 | |
| +
 | |
| +static int sw_sync_cmp(u32 a, u32 b)
 | |
| +{
 | |
| +	if (a == b)
 | |
| +		return 0;
 | |
| +
 | |
| +	return ((s32)a - (s32)b) < 0 ? -1 : 1;
 | |
| +}
 | |
| +
 | |
| +struct sync_pt *bsp_sw_sync_pt_create(struct sw_sync_timeline *obj, u32 value)
 | |
| +{
 | |
| +	struct sw_sync_pt *pt;
 | |
| +
 | |
| +	pt = (struct sw_sync_pt *)
 | |
| +        bsp_sync_pt_create(&obj->obj, sizeof(struct sw_sync_pt));
 | |
| +        if (pt != NULL) {
 | |
| +	    pt->value = value;
 | |
| +        }
 | |
| +
 | |
| +	return (struct sync_pt *)pt;
 | |
| +}
 | |
| +EXPORT_SYMBOL(bsp_sw_sync_pt_create);
 | |
| +
 | |
| +static struct sync_pt *sw_sync_pt_dup(struct sync_pt *sync_pt)
 | |
| +{
 | |
| +	struct sw_sync_pt *pt = (struct sw_sync_pt *)sync_pt;
 | |
| +	struct sw_sync_timeline *obj =
 | |
| +		(struct sw_sync_timeline *)sync_pt_parent(sync_pt);
 | |
| +
 | |
| +	return (struct sync_pt *)bsp_sw_sync_pt_create(obj, pt->value);
 | |
| +}
 | |
| +
 | |
| +static int sw_sync_pt_has_signaled(struct sync_pt *sync_pt)
 | |
| +{
 | |
| +	struct sw_sync_pt *pt = (struct sw_sync_pt *)sync_pt;
 | |
| +	struct sw_sync_timeline *obj =
 | |
| +		(struct sw_sync_timeline *)sync_pt_parent(sync_pt);
 | |
| +
 | |
| +	return sw_sync_cmp(obj->value, pt->value) >= 0;
 | |
| +}
 | |
| +
 | |
| +static int sw_sync_pt_compare(struct sync_pt *a, struct sync_pt *b)
 | |
| +{
 | |
| +	struct sw_sync_pt *pt_a = (struct sw_sync_pt *)a;
 | |
| +	struct sw_sync_pt *pt_b = (struct sw_sync_pt *)b;
 | |
| +
 | |
| +	return sw_sync_cmp(pt_a->value, pt_b->value);
 | |
| +}
 | |
| +
 | |
| +static int sw_sync_fill_driver_data(struct sync_pt *sync_pt,
 | |
| +				    void *data, int size)
 | |
| +{
 | |
| +	struct sw_sync_pt *pt = (struct sw_sync_pt *)sync_pt;
 | |
| +
 | |
| +	if (size < sizeof(pt->value))
 | |
| +		return -ENOMEM;
 | |
| +
 | |
| +	memcpy(data, &pt->value, sizeof(pt->value));
 | |
| +
 | |
| +	return sizeof(pt->value);
 | |
| +}
 | |
| +
 | |
| +static void sw_sync_timeline_value_str(struct sync_timeline *sync_timeline,
 | |
| +				       char *str, int size)
 | |
| +{
 | |
| +	struct sw_sync_timeline *timeline =
 | |
| +		(struct sw_sync_timeline *)sync_timeline;
 | |
| +	snprintf(str, size, "%d", timeline->value);
 | |
| +}
 | |
| +
 | |
| +static void sw_sync_pt_value_str(struct sync_pt *sync_pt,
 | |
| +				 char *str, int size)
 | |
| +{
 | |
| +	struct sw_sync_pt *pt = (struct sw_sync_pt *)sync_pt;
 | |
| +
 | |
| +	snprintf(str, size, "%d", pt->value);
 | |
| +}
 | |
| +
 | |
| +static struct sync_timeline_ops sw_sync_timeline_ops = {
 | |
| +	.driver_name = "sw_sync",
 | |
| +	.dup = sw_sync_pt_dup,
 | |
| +	.has_signaled = sw_sync_pt_has_signaled,
 | |
| +	.compare = sw_sync_pt_compare,
 | |
| +	.fill_driver_data = sw_sync_fill_driver_data,
 | |
| +	.timeline_value_str = sw_sync_timeline_value_str,
 | |
| +	.pt_value_str = sw_sync_pt_value_str,
 | |
| +};
 | |
| +
 | |
| +struct sw_sync_timeline *bsp_sw_sync_timeline_create(const char *name)
 | |
| +{
 | |
| +	struct sw_sync_timeline *obj = (struct sw_sync_timeline *)
 | |
| +		bsp_sync_timeline_create(&sw_sync_timeline_ops,
 | |
| +				     sizeof(struct sw_sync_timeline),
 | |
| +				     name);
 | |
| +
 | |
| +	return obj;
 | |
| +}
 | |
| +EXPORT_SYMBOL(bsp_sw_sync_timeline_create);
 | |
| +
 | |
| +void bsp_sw_sync_timeline_inc(struct sw_sync_timeline *obj, u32 inc)
 | |
| +{
 | |
| +	obj->value += inc;
 | |
| +
 | |
| +	bsp_sync_timeline_signal(&obj->obj);
 | |
| +}
 | |
| +EXPORT_SYMBOL(bsp_sw_sync_timeline_inc);
 | |
| +
 | |
| +#ifdef CONFIG_SW_SYNC_USER
 | |
| +/* *WARNING*
 | |
| + *
 | |
| + * improper use of this can result in deadlocking kernel drivers from userspace.
 | |
| + */
 | |
| +
 | |
| +/* opening sw_sync create a new sync obj */
 | |
| +static int sw_sync_open(struct inode *inode, struct file *file)
 | |
| +{
 | |
| +	struct sw_sync_timeline *obj = NULL;
 | |
| +	char task_comm[TASK_COMM_LEN];
 | |
| +
 | |
| +	get_task_comm(task_comm, current);
 | |
| +
 | |
| +	obj = bsp_sw_sync_timeline_create(task_comm);
 | |
| +	if (!obj)
 | |
| +		return -ENOMEM;
 | |
| +
 | |
| +	file->private_data = obj;
 | |
| +
 | |
| +	return 0;
 | |
| +}
 | |
| +
 | |
| +static int sw_sync_release(struct inode *inode, struct file *file)
 | |
| +{
 | |
| +	struct sw_sync_timeline *obj = file->private_data;
 | |
| +
 | |
| +	bsp_sync_timeline_destroy(&obj->obj);
 | |
| +	return 0;
 | |
| +}
 | |
| +
 | |
| +static long sw_sync_ioctl_create_fence(struct sw_sync_timeline *obj,
 | |
| +				       unsigned long arg)
 | |
| +{
 | |
| +	int fd = get_unused_fd_flags(O_CLOEXEC);
 | |
| +	int err;
 | |
| +	struct sync_pt *pt = NULL;
 | |
| +        #if 0
 | |
| +	struct sync_fence *fence;
 | |
| +        #else
 | |
| +        struct sync_file *fence = NULL;
 | |
| +        #endif
 | |
| +	struct sw_sync_create_fence_data data;
 | |
| +
 | |
| +	if (fd < 0)
 | |
| +		return fd;
 | |
| +
 | |
| +	if (copy_from_user(&data, (void __user *)arg, sizeof(data))) {
 | |
| +		err = -EFAULT;
 | |
| +		goto err;
 | |
| +	}
 | |
| +
 | |
| +	pt = bsp_sw_sync_pt_create(obj, data.value);
 | |
| +	if (!pt) {
 | |
| +		err = -ENOMEM;
 | |
| +		goto err;
 | |
| +	}
 | |
| +
 | |
| +	data.name[sizeof(data.name) - 1] = '\0';
 | |
| +	#if 0
 | |
| +	fence = bsp_sync_fence_create(data.name, pt);
 | |
| +	#else
 | |
| +        fence = sync_file_create(&pt->base);
 | |
| +	#endif
 | |
| +	if (!fence) {
 | |
| +		bsp_sync_pt_free(pt);
 | |
| +		err = -ENOMEM;
 | |
| +		goto err;
 | |
| +	}
 | |
| +
 | |
| +	data.fence = fd;
 | |
| +	if (copy_to_user((void __user *)arg, &data, sizeof(data))) {
 | |
| +		#if 0
 | |
| +                bsp_sync_fence_put(fence);
 | |
| +                #else
 | |
| +                fput(fence->file);
 | |
| +                #endif
 | |
| +		err = -EFAULT;
 | |
| +		goto err;
 | |
| +	}
 | |
| +
 | |
| +        #if 0
 | |
| +	bsp_sync_fence_install(fence, fd);
 | |
| +        #else
 | |
| +        fd_install(fd, fence->file);
 | |
| +        #endif
 | |
| +
 | |
| +	return 0;
 | |
| +
 | |
| +err:
 | |
| +	put_unused_fd(fd);
 | |
| +	return err;
 | |
| +}
 | |
| +
 | |
| +static long sw_sync_ioctl_inc(struct sw_sync_timeline *obj, unsigned long arg)
 | |
| +{
 | |
| +	u32 value;
 | |
| +
 | |
| +	if (copy_from_user(&value, (void __user *)arg, sizeof(value)))
 | |
| +		return -EFAULT;
 | |
| +
 | |
| +	bsp_sw_sync_timeline_inc(obj, value);
 | |
| +
 | |
| +	return 0;
 | |
| +}
 | |
| +
 | |
| +static long sw_sync_ioctl(struct file *file, unsigned int cmd,
 | |
| +			  unsigned long arg)
 | |
| +{
 | |
| +	struct sw_sync_timeline *obj = file->private_data;
 | |
| +
 | |
| +	switch (cmd) {
 | |
| +	case SW_SYNC_IOC_CREATE_FENCE:
 | |
| +		return sw_sync_ioctl_create_fence(obj, arg);
 | |
| +
 | |
| +	case SW_SYNC_IOC_INC:
 | |
| +		return sw_sync_ioctl_inc(obj, arg);
 | |
| +
 | |
| +	default:
 | |
| +		return -ENOTTY;
 | |
| +	}
 | |
| +}
 | |
| +
 | |
| +static const struct file_operations sw_sync_fops = {
 | |
| +	.owner = THIS_MODULE,
 | |
| +	.open = sw_sync_open,
 | |
| +	.release = sw_sync_release,
 | |
| +	.unlocked_ioctl = sw_sync_ioctl,
 | |
| +	.compat_ioctl = sw_sync_ioctl,
 | |
| +};
 | |
| +
 | |
| +static struct miscdevice sw_sync_dev = {
 | |
| +	.minor	= MISC_DYNAMIC_MINOR,
 | |
| +	.name	= "sw_sync",
 | |
| +	.fops	= &sw_sync_fops,
 | |
| +};
 | |
| +
 | |
| +static int __init sw_sync_device_init(void)
 | |
| +{
 | |
| +	return misc_register(&sw_sync_dev);
 | |
| +}
 | |
| +device_initcall(sw_sync_device_init);
 | |
| +
 | |
| +#endif /* CONFIG_SW_SYNC_USER */
 |