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>
410 lines
13 KiB
C
410 lines
13 KiB
C
/* Copyright (c) 2013-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/fs.h>
|
|
#include <linux/file.h>
|
|
#include <linux/uaccess.h>
|
|
#include <asm/ioctl.h>
|
|
|
|
#include "kgsl.h"
|
|
#include "kgsl_compat.h"
|
|
#include "kgsl_device.h"
|
|
#include "kgsl_sync.h"
|
|
|
|
static long
|
|
kgsl_ioctl_device_getproperty_compat(struct kgsl_device_private *dev_priv,
|
|
unsigned int cmd, void *data)
|
|
{
|
|
struct kgsl_device_getproperty_compat *param32 = data;
|
|
struct kgsl_device_getproperty param;
|
|
|
|
param.type = param32->type;
|
|
param.value = compat_ptr(param32->value);
|
|
param.sizebytes = (size_t)param32->sizebytes;
|
|
|
|
return kgsl_ioctl_device_getproperty(dev_priv, cmd, ¶m);
|
|
}
|
|
|
|
static long
|
|
kgsl_ioctl_device_setproperty_compat(struct kgsl_device_private *dev_priv,
|
|
unsigned int cmd, void *data)
|
|
{
|
|
struct kgsl_device_getproperty_compat *param32 = data;
|
|
struct kgsl_device_getproperty param;
|
|
|
|
param.type = param32->type;
|
|
param.value = compat_ptr(param32->value);
|
|
param.sizebytes = (size_t)param32->sizebytes;
|
|
|
|
return kgsl_ioctl_device_setproperty(dev_priv, cmd, ¶m);
|
|
}
|
|
|
|
static long
|
|
kgsl_ioctl_submit_commands_compat(struct kgsl_device_private *dev_priv,
|
|
unsigned int cmd, void *data)
|
|
{
|
|
int result;
|
|
struct kgsl_submit_commands_compat *param32 = data;
|
|
struct kgsl_submit_commands param;
|
|
|
|
param.context_id = param32->context_id;
|
|
param.flags = param32->flags;
|
|
param.cmdlist = compat_ptr(param32->cmdlist);
|
|
param.numcmds = param32->numcmds;
|
|
param.synclist = compat_ptr(param32->synclist);
|
|
param.numsyncs = param32->numsyncs;
|
|
param.timestamp = param32->timestamp;
|
|
|
|
result = kgsl_ioctl_submit_commands(dev_priv, cmd, ¶m);
|
|
|
|
param32->timestamp = param.timestamp;
|
|
|
|
return result;
|
|
}
|
|
|
|
static long
|
|
kgsl_ioctl_rb_issueibcmds_compat(struct kgsl_device_private *dev_priv,
|
|
unsigned int cmd, void *data)
|
|
{
|
|
int result;
|
|
struct kgsl_ringbuffer_issueibcmds_compat *param32 = data;
|
|
struct kgsl_ringbuffer_issueibcmds param;
|
|
|
|
param.drawctxt_id = param32->drawctxt_id;
|
|
param.flags = param32->flags;
|
|
param.ibdesc_addr = (unsigned long)param32->ibdesc_addr;
|
|
param.numibs = param32->numibs;
|
|
param.timestamp = param32->timestamp;
|
|
|
|
result = kgsl_ioctl_rb_issueibcmds(dev_priv, cmd, ¶m);
|
|
|
|
param32->timestamp = param.timestamp;
|
|
|
|
return result;
|
|
}
|
|
|
|
static long kgsl_ioctl_cmdstream_freememontimestamp_ctxtid_compat(
|
|
struct kgsl_device_private
|
|
*dev_priv, unsigned int cmd,
|
|
void *data)
|
|
{
|
|
struct kgsl_cmdstream_freememontimestamp_ctxtid_compat *param32 = data;
|
|
struct kgsl_cmdstream_freememontimestamp_ctxtid param;
|
|
|
|
param.context_id = param32->context_id;
|
|
param.gpuaddr = (unsigned long)param32->gpuaddr;
|
|
param.type = param32->type;
|
|
param.timestamp = param32->timestamp;
|
|
|
|
return kgsl_ioctl_cmdstream_freememontimestamp_ctxtid(dev_priv, cmd,
|
|
¶m);
|
|
}
|
|
|
|
static long kgsl_ioctl_sharedmem_free_compat(struct kgsl_device_private
|
|
*dev_priv, unsigned int cmd,
|
|
void *data)
|
|
{
|
|
struct kgsl_sharedmem_free_compat *param32 = data;
|
|
struct kgsl_sharedmem_free param;
|
|
|
|
param.gpuaddr = (unsigned long)param32->gpuaddr;
|
|
|
|
return kgsl_ioctl_sharedmem_free(dev_priv, cmd, ¶m);
|
|
}
|
|
|
|
static long kgsl_ioctl_map_user_mem_compat(struct kgsl_device_private
|
|
*dev_priv, unsigned int cmd,
|
|
void *data)
|
|
{
|
|
int result = 0;
|
|
struct kgsl_map_user_mem_compat *param32 = data;
|
|
struct kgsl_map_user_mem param;
|
|
|
|
param.fd = param32->fd;
|
|
param.gpuaddr = (unsigned long)param32->gpuaddr;
|
|
param.len = (size_t)param32->len;
|
|
param.offset = (size_t)param32->offset;
|
|
param.hostptr = (unsigned long)param32->hostptr;
|
|
param.memtype = param32->memtype;
|
|
param.flags = param32->flags;
|
|
|
|
result = kgsl_ioctl_map_user_mem(dev_priv, cmd, ¶m);
|
|
|
|
param32->gpuaddr = gpuaddr_to_compat(param.gpuaddr);
|
|
param32->flags = param.flags;
|
|
return result;
|
|
}
|
|
|
|
static long
|
|
kgsl_ioctl_gpumem_sync_cache_compat(struct kgsl_device_private *dev_priv,
|
|
unsigned int cmd, void *data)
|
|
{
|
|
struct kgsl_gpumem_sync_cache_compat *param32 = data;
|
|
struct kgsl_gpumem_sync_cache param;
|
|
|
|
param.gpuaddr = (unsigned long)param32->gpuaddr;
|
|
param.id = param32->id;
|
|
param.op = param32->op;
|
|
param.offset = (size_t)param32->offset;
|
|
param.length = (size_t)param32->length;
|
|
|
|
return kgsl_ioctl_gpumem_sync_cache(dev_priv, cmd, ¶m);
|
|
}
|
|
|
|
static long
|
|
kgsl_ioctl_gpumem_sync_cache_bulk_compat(struct kgsl_device_private *dev_priv,
|
|
unsigned int cmd, void *data)
|
|
{
|
|
struct kgsl_gpumem_sync_cache_bulk_compat *param32 = data;
|
|
struct kgsl_gpumem_sync_cache_bulk param;
|
|
|
|
param.id_list = to_user_ptr(param32->id_list);
|
|
param.count = param32->count;
|
|
param.op = param32->op;
|
|
|
|
return kgsl_ioctl_gpumem_sync_cache_bulk(dev_priv, cmd, ¶m);
|
|
}
|
|
|
|
static long
|
|
kgsl_ioctl_sharedmem_flush_cache_compat(struct kgsl_device_private *dev_priv,
|
|
unsigned int cmd, void *data)
|
|
{
|
|
struct kgsl_sharedmem_free_compat *param32 = data;
|
|
struct kgsl_sharedmem_free param;
|
|
|
|
param.gpuaddr = (unsigned long)param32->gpuaddr;
|
|
|
|
return kgsl_ioctl_sharedmem_flush_cache(dev_priv, cmd, ¶m);
|
|
}
|
|
|
|
static long
|
|
kgsl_ioctl_gpumem_alloc_compat(struct kgsl_device_private *dev_priv,
|
|
unsigned int cmd, void *data)
|
|
{
|
|
int result = 0;
|
|
struct kgsl_gpumem_alloc_compat *param32 = data;
|
|
struct kgsl_gpumem_alloc param;
|
|
|
|
param.gpuaddr = (unsigned long)param32->gpuaddr;
|
|
param.size = (size_t)param32->size;
|
|
param.flags = param32->flags;
|
|
|
|
/*
|
|
* Since this is a 32 bit application the page aligned size is expected
|
|
* to fit inside of 32 bits - check for overflow and return error if so
|
|
*/
|
|
if (PAGE_ALIGN(param.size) >= UINT_MAX)
|
|
return -EINVAL;
|
|
|
|
result = kgsl_ioctl_gpumem_alloc(dev_priv, cmd, ¶m);
|
|
|
|
param32->gpuaddr = gpuaddr_to_compat(param.gpuaddr);
|
|
param32->size = sizet_to_compat(param.size);
|
|
param32->flags = param.flags;
|
|
|
|
return result;
|
|
}
|
|
|
|
static long
|
|
kgsl_ioctl_gpumem_alloc_id_compat(struct kgsl_device_private *dev_priv,
|
|
unsigned int cmd, void *data)
|
|
{
|
|
int result = 0;
|
|
struct kgsl_gpumem_alloc_id_compat *param32 = data;
|
|
struct kgsl_gpumem_alloc_id param;
|
|
|
|
param.id = param32->id;
|
|
param.flags = param32->flags;
|
|
param.size = (size_t)param32->size;
|
|
param.mmapsize = (size_t)param32->mmapsize;
|
|
param.gpuaddr = (unsigned long)param32->gpuaddr;
|
|
|
|
/*
|
|
* Since this is a 32 bit application the page aligned size is expected
|
|
* to fit inside of 32 bits - check for overflow and return error if so
|
|
*/
|
|
if (PAGE_ALIGN(param.size) >= UINT_MAX)
|
|
return -EINVAL;
|
|
|
|
result = kgsl_ioctl_gpumem_alloc_id(dev_priv, cmd, ¶m);
|
|
|
|
param32->id = param.id;
|
|
param32->flags = param.flags;
|
|
param32->size = sizet_to_compat(param.size);
|
|
param32->mmapsize = sizet_to_compat(param.mmapsize);
|
|
param32->gpuaddr = gpuaddr_to_compat(param.gpuaddr);
|
|
|
|
return result;
|
|
}
|
|
|
|
static long
|
|
kgsl_ioctl_gpumem_get_info_compat(struct kgsl_device_private *dev_priv,
|
|
unsigned int cmd, void *data)
|
|
{
|
|
int result = 0;
|
|
struct kgsl_gpumem_get_info_compat *param32 = data;
|
|
struct kgsl_gpumem_get_info param;
|
|
|
|
param.gpuaddr = (unsigned long)param32->gpuaddr;
|
|
param.id = param32->id;
|
|
param.flags = param32->flags;
|
|
param.size = (size_t)param32->size;
|
|
param.mmapsize = (size_t)param32->mmapsize;
|
|
param.useraddr = (unsigned long)param32->useraddr;
|
|
|
|
result = kgsl_ioctl_gpumem_get_info(dev_priv, cmd, ¶m);
|
|
|
|
param32->gpuaddr = gpuaddr_to_compat(param.gpuaddr);
|
|
param32->id = param.id;
|
|
param32->flags = param.flags;
|
|
param32->size = sizet_to_compat(param.size);
|
|
param32->mmapsize = sizet_to_compat(param.mmapsize);
|
|
param32->useraddr = (compat_ulong_t)param.useraddr;
|
|
|
|
return result;
|
|
}
|
|
|
|
static long kgsl_ioctl_cff_syncmem_compat(struct kgsl_device_private *dev_priv,
|
|
unsigned int cmd, void *data)
|
|
{
|
|
struct kgsl_cff_syncmem_compat *param32 = data;
|
|
struct kgsl_cff_syncmem param;
|
|
|
|
param.gpuaddr = (unsigned long)param32->gpuaddr;
|
|
param.len = (size_t)param32->len;
|
|
|
|
return kgsl_ioctl_cff_syncmem(dev_priv, cmd, ¶m);
|
|
}
|
|
|
|
static long kgsl_ioctl_timestamp_event_compat(struct kgsl_device_private
|
|
*dev_priv, unsigned int cmd, void *data)
|
|
{
|
|
struct kgsl_timestamp_event_compat *param32 = data;
|
|
struct kgsl_timestamp_event param;
|
|
|
|
param.type = param32->type;
|
|
param.timestamp = param32->timestamp;
|
|
param.context_id = param32->context_id;
|
|
param.priv = compat_ptr(param32->priv);
|
|
param.len = (size_t)param32->len;
|
|
|
|
return kgsl_ioctl_timestamp_event(dev_priv, cmd, ¶m);
|
|
}
|
|
|
|
|
|
static const struct kgsl_ioctl kgsl_compat_ioctl_funcs[] = {
|
|
KGSL_IOCTL_FUNC(IOCTL_KGSL_DEVICE_GETPROPERTY_COMPAT,
|
|
kgsl_ioctl_device_getproperty_compat),
|
|
/* 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_COMPAT,
|
|
kgsl_ioctl_rb_issueibcmds_compat),
|
|
KGSL_IOCTL_FUNC(IOCTL_KGSL_SUBMIT_COMMANDS_COMPAT,
|
|
kgsl_ioctl_submit_commands_compat),
|
|
/* 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_COMPAT,
|
|
kgsl_ioctl_cmdstream_freememontimestamp_ctxtid_compat),
|
|
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_COMPAT,
|
|
kgsl_ioctl_map_user_mem_compat),
|
|
KGSL_IOCTL_FUNC(IOCTL_KGSL_SHAREDMEM_FREE_COMPAT,
|
|
kgsl_ioctl_sharedmem_free_compat),
|
|
KGSL_IOCTL_FUNC(IOCTL_KGSL_SHAREDMEM_FLUSH_CACHE_COMPAT,
|
|
kgsl_ioctl_sharedmem_flush_cache_compat),
|
|
KGSL_IOCTL_FUNC(IOCTL_KGSL_GPUMEM_ALLOC_COMPAT,
|
|
kgsl_ioctl_gpumem_alloc_compat),
|
|
KGSL_IOCTL_FUNC(IOCTL_KGSL_CFF_SYNCMEM_COMPAT,
|
|
kgsl_ioctl_cff_syncmem_compat),
|
|
KGSL_IOCTL_FUNC(IOCTL_KGSL_CFF_USER_EVENT,
|
|
kgsl_ioctl_cff_user_event),
|
|
KGSL_IOCTL_FUNC(IOCTL_KGSL_TIMESTAMP_EVENT_COMPAT,
|
|
kgsl_ioctl_timestamp_event_compat),
|
|
KGSL_IOCTL_FUNC(IOCTL_KGSL_SETPROPERTY_COMPAT,
|
|
kgsl_ioctl_device_setproperty_compat),
|
|
KGSL_IOCTL_FUNC(IOCTL_KGSL_GPUMEM_ALLOC_ID_COMPAT,
|
|
kgsl_ioctl_gpumem_alloc_id_compat),
|
|
KGSL_IOCTL_FUNC(IOCTL_KGSL_GPUMEM_FREE_ID,
|
|
kgsl_ioctl_gpumem_free_id),
|
|
KGSL_IOCTL_FUNC(IOCTL_KGSL_GPUMEM_GET_INFO_COMPAT,
|
|
kgsl_ioctl_gpumem_get_info_compat),
|
|
KGSL_IOCTL_FUNC(IOCTL_KGSL_GPUMEM_SYNC_CACHE_COMPAT,
|
|
kgsl_ioctl_gpumem_sync_cache_compat),
|
|
KGSL_IOCTL_FUNC(IOCTL_KGSL_GPUMEM_SYNC_CACHE_BULK_COMPAT,
|
|
kgsl_ioctl_gpumem_sync_cache_bulk_compat),
|
|
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_compat_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 = kgsl_ioctl_helper(filep, cmd, arg, kgsl_compat_ioctl_funcs,
|
|
ARRAY_SIZE(kgsl_compat_ioctl_funcs));
|
|
|
|
/*
|
|
* If the command was unrecognized in the generic core, try the device
|
|
* specific function
|
|
*/
|
|
|
|
if (ret == -ENOIOCTLCMD) {
|
|
if (device->ftbl->compat_ioctl != NULL)
|
|
return device->ftbl->compat_ioctl(dev_priv, cmd, arg);
|
|
|
|
KGSL_DRV_INFO(device, "invalid ioctl code 0x%08X\n", cmd);
|
|
}
|
|
|
|
return ret;
|
|
}
|