kgsl_ioctl_gpu_sparse_command() is added to for user to specify list of binds/unbinds for a memory entry and syncpoints they depend on. If user specifies both create a sync object for syncpoints and bind object for binds/unbinds and add them to dispatcher draw queue. Sync object should be inserted before the bind object in the draw queue. Once the bind object reaches the head of draw queue the corresponding binds/unbinds are performed. kgsl_ioctl_gpu_sparse_command() only accepts commands from context created with flag KGSL_CONTEXT_SPARSE, commands from all other context types will return an error. Change-Id: Ib0a2361f854ae01d0d8090cdd48cfa96308daf93 Signed-off-by: Tarun Karra <tkarra@codeaurora.org>
188 lines
6.2 KiB
C
188 lines
6.2 KiB
C
/* Copyright (c) 2008-2016, The Linux Foundation. All rights reserved.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License version 2 and
|
|
* only version 2 as published by the Free Software Foundation.
|
|
*
|
|
* 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/ioctl.h>
|
|
#include <linux/compat.h>
|
|
#include <linux/uaccess.h>
|
|
#include <linux/fs.h>
|
|
#include "kgsl_device.h"
|
|
#include "kgsl_sync.h"
|
|
|
|
static const struct kgsl_ioctl kgsl_ioctl_funcs[] = {
|
|
KGSL_IOCTL_FUNC(IOCTL_KGSL_DEVICE_GETPROPERTY,
|
|
kgsl_ioctl_device_getproperty),
|
|
/* IOCTL_KGSL_DEVICE_WAITTIMESTAMP is no longer supported */
|
|
KGSL_IOCTL_FUNC(IOCTL_KGSL_DEVICE_WAITTIMESTAMP_CTXTID,
|
|
kgsl_ioctl_device_waittimestamp_ctxtid),
|
|
KGSL_IOCTL_FUNC(IOCTL_KGSL_RINGBUFFER_ISSUEIBCMDS,
|
|
kgsl_ioctl_rb_issueibcmds),
|
|
KGSL_IOCTL_FUNC(IOCTL_KGSL_SUBMIT_COMMANDS,
|
|
kgsl_ioctl_submit_commands),
|
|
/* IOCTL_KGSL_CMDSTREAM_READTIMESTAMP is no longer supported */
|
|
KGSL_IOCTL_FUNC(IOCTL_KGSL_CMDSTREAM_READTIMESTAMP_CTXTID,
|
|
kgsl_ioctl_cmdstream_readtimestamp_ctxtid),
|
|
/* IOCTL_KGSL_CMDSTREAM_FREEMEMONTIMESTAMP is no longer supported */
|
|
KGSL_IOCTL_FUNC(IOCTL_KGSL_CMDSTREAM_FREEMEMONTIMESTAMP_CTXTID,
|
|
kgsl_ioctl_cmdstream_freememontimestamp_ctxtid),
|
|
KGSL_IOCTL_FUNC(IOCTL_KGSL_DRAWCTXT_CREATE,
|
|
kgsl_ioctl_drawctxt_create),
|
|
KGSL_IOCTL_FUNC(IOCTL_KGSL_DRAWCTXT_DESTROY,
|
|
kgsl_ioctl_drawctxt_destroy),
|
|
KGSL_IOCTL_FUNC(IOCTL_KGSL_MAP_USER_MEM,
|
|
kgsl_ioctl_map_user_mem),
|
|
KGSL_IOCTL_FUNC(IOCTL_KGSL_SHAREDMEM_FROM_PMEM,
|
|
kgsl_ioctl_map_user_mem),
|
|
KGSL_IOCTL_FUNC(IOCTL_KGSL_SHAREDMEM_FREE,
|
|
kgsl_ioctl_sharedmem_free),
|
|
KGSL_IOCTL_FUNC(IOCTL_KGSL_SHAREDMEM_FLUSH_CACHE,
|
|
kgsl_ioctl_sharedmem_flush_cache),
|
|
KGSL_IOCTL_FUNC(IOCTL_KGSL_GPUMEM_ALLOC,
|
|
kgsl_ioctl_gpumem_alloc),
|
|
KGSL_IOCTL_FUNC(IOCTL_KGSL_CFF_SYNCMEM,
|
|
kgsl_ioctl_cff_syncmem),
|
|
KGSL_IOCTL_FUNC(IOCTL_KGSL_CFF_USER_EVENT,
|
|
kgsl_ioctl_cff_user_event),
|
|
KGSL_IOCTL_FUNC(IOCTL_KGSL_TIMESTAMP_EVENT,
|
|
kgsl_ioctl_timestamp_event),
|
|
KGSL_IOCTL_FUNC(IOCTL_KGSL_SETPROPERTY,
|
|
kgsl_ioctl_device_setproperty),
|
|
KGSL_IOCTL_FUNC(IOCTL_KGSL_GPUMEM_ALLOC_ID,
|
|
kgsl_ioctl_gpumem_alloc_id),
|
|
KGSL_IOCTL_FUNC(IOCTL_KGSL_GPUMEM_FREE_ID,
|
|
kgsl_ioctl_gpumem_free_id),
|
|
KGSL_IOCTL_FUNC(IOCTL_KGSL_GPUMEM_GET_INFO,
|
|
kgsl_ioctl_gpumem_get_info),
|
|
KGSL_IOCTL_FUNC(IOCTL_KGSL_GPUMEM_SYNC_CACHE,
|
|
kgsl_ioctl_gpumem_sync_cache),
|
|
KGSL_IOCTL_FUNC(IOCTL_KGSL_GPUMEM_SYNC_CACHE_BULK,
|
|
kgsl_ioctl_gpumem_sync_cache_bulk),
|
|
KGSL_IOCTL_FUNC(IOCTL_KGSL_SYNCSOURCE_CREATE,
|
|
kgsl_ioctl_syncsource_create),
|
|
KGSL_IOCTL_FUNC(IOCTL_KGSL_SYNCSOURCE_DESTROY,
|
|
kgsl_ioctl_syncsource_destroy),
|
|
KGSL_IOCTL_FUNC(IOCTL_KGSL_SYNCSOURCE_CREATE_FENCE,
|
|
kgsl_ioctl_syncsource_create_fence),
|
|
KGSL_IOCTL_FUNC(IOCTL_KGSL_SYNCSOURCE_SIGNAL_FENCE,
|
|
kgsl_ioctl_syncsource_signal_fence),
|
|
KGSL_IOCTL_FUNC(IOCTL_KGSL_CFF_SYNC_GPUOBJ,
|
|
kgsl_ioctl_cff_sync_gpuobj),
|
|
KGSL_IOCTL_FUNC(IOCTL_KGSL_GPUOBJ_ALLOC,
|
|
kgsl_ioctl_gpuobj_alloc),
|
|
KGSL_IOCTL_FUNC(IOCTL_KGSL_GPUOBJ_FREE,
|
|
kgsl_ioctl_gpuobj_free),
|
|
KGSL_IOCTL_FUNC(IOCTL_KGSL_GPUOBJ_INFO,
|
|
kgsl_ioctl_gpuobj_info),
|
|
KGSL_IOCTL_FUNC(IOCTL_KGSL_GPUOBJ_IMPORT,
|
|
kgsl_ioctl_gpuobj_import),
|
|
KGSL_IOCTL_FUNC(IOCTL_KGSL_GPUOBJ_SYNC,
|
|
kgsl_ioctl_gpuobj_sync),
|
|
KGSL_IOCTL_FUNC(IOCTL_KGSL_GPU_COMMAND,
|
|
kgsl_ioctl_gpu_command),
|
|
KGSL_IOCTL_FUNC(IOCTL_KGSL_GPUOBJ_SET_INFO,
|
|
kgsl_ioctl_gpuobj_set_info),
|
|
KGSL_IOCTL_FUNC(IOCTL_KGSL_SPARSE_PHYS_ALLOC,
|
|
kgsl_ioctl_sparse_phys_alloc),
|
|
KGSL_IOCTL_FUNC(IOCTL_KGSL_SPARSE_PHYS_FREE,
|
|
kgsl_ioctl_sparse_phys_free),
|
|
KGSL_IOCTL_FUNC(IOCTL_KGSL_SPARSE_VIRT_ALLOC,
|
|
kgsl_ioctl_sparse_virt_alloc),
|
|
KGSL_IOCTL_FUNC(IOCTL_KGSL_SPARSE_VIRT_FREE,
|
|
kgsl_ioctl_sparse_virt_free),
|
|
KGSL_IOCTL_FUNC(IOCTL_KGSL_SPARSE_BIND,
|
|
kgsl_ioctl_sparse_bind),
|
|
KGSL_IOCTL_FUNC(IOCTL_KGSL_GPU_SPARSE_COMMAND,
|
|
kgsl_ioctl_gpu_sparse_command),
|
|
};
|
|
|
|
long kgsl_ioctl_copy_in(unsigned int kernel_cmd, unsigned int user_cmd,
|
|
unsigned long arg, unsigned char *ptr)
|
|
{
|
|
unsigned int usize = _IOC_SIZE(user_cmd);
|
|
unsigned int ksize = _IOC_SIZE(kernel_cmd);
|
|
unsigned int copy = ksize < usize ? ksize : usize;
|
|
|
|
if ((kernel_cmd & IOC_IN) && (user_cmd & IOC_IN)) {
|
|
if (copy > 0 && copy_from_user(ptr, (void __user *) arg, copy))
|
|
return -EFAULT;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
long kgsl_ioctl_copy_out(unsigned int kernel_cmd, unsigned int user_cmd,
|
|
unsigned long arg, unsigned char *ptr)
|
|
{
|
|
unsigned int usize = _IOC_SIZE(user_cmd);
|
|
unsigned int ksize = _IOC_SIZE(kernel_cmd);
|
|
unsigned int copy = ksize < usize ? ksize : usize;
|
|
|
|
if ((kernel_cmd & IOC_OUT) && (user_cmd & IOC_OUT)) {
|
|
if (copy > 0 && copy_to_user((void __user *) arg, ptr, copy))
|
|
return -EFAULT;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
long kgsl_ioctl_helper(struct file *filep, unsigned int cmd, unsigned long arg,
|
|
const struct kgsl_ioctl *cmds, int len)
|
|
{
|
|
struct kgsl_device_private *dev_priv = filep->private_data;
|
|
unsigned char data[128] = { 0 };
|
|
unsigned int nr = _IOC_NR(cmd);
|
|
long ret;
|
|
|
|
if (nr >= len || cmds[nr].func == NULL)
|
|
return -ENOIOCTLCMD;
|
|
|
|
BUG_ON(_IOC_SIZE(cmds[nr].cmd) > sizeof(data));
|
|
|
|
if (_IOC_SIZE(cmds[nr].cmd)) {
|
|
ret = kgsl_ioctl_copy_in(cmds[nr].cmd, cmd, arg, data);
|
|
if (ret)
|
|
return ret;
|
|
}
|
|
|
|
ret = cmds[nr].func(dev_priv, cmd, data);
|
|
|
|
if (ret == 0 && _IOC_SIZE(cmds[nr].cmd))
|
|
ret = kgsl_ioctl_copy_out(cmds[nr].cmd, cmd, arg, data);
|
|
|
|
return ret;
|
|
}
|
|
|
|
long kgsl_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
|
|
{
|
|
struct kgsl_device_private *dev_priv = filep->private_data;
|
|
struct kgsl_device *device = dev_priv->device;
|
|
long ret;
|
|
|
|
ret = kgsl_ioctl_helper(filep, cmd, arg, kgsl_ioctl_funcs,
|
|
ARRAY_SIZE(kgsl_ioctl_funcs));
|
|
|
|
/*
|
|
* If the command was unrecognized in the generic core, try the device
|
|
* specific function
|
|
*/
|
|
|
|
if (ret == -ENOIOCTLCMD) {
|
|
if (is_compat_task() && device->ftbl->compat_ioctl != NULL)
|
|
return device->ftbl->compat_ioctl(dev_priv, cmd, arg);
|
|
else if (device->ftbl->ioctl != NULL)
|
|
return device->ftbl->ioctl(dev_priv, cmd, arg);
|
|
|
|
KGSL_DRV_INFO(device, "invalid ioctl code 0x%08X\n", cmd);
|
|
}
|
|
|
|
return ret;
|
|
}
|