summaryrefslogtreecommitdiff
path: root/drivers/gpu/msm/kgsl.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/msm/kgsl.c')
-rw-r--r--drivers/gpu/msm/kgsl.c152
1 files changed, 150 insertions, 2 deletions
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index 993f22b26294..bae3884aa277 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -1439,6 +1439,17 @@ long kgsl_ioctl_device_waittimestamp_ctxtid(
return result;
}
+static inline bool _check_context_is_sparse(struct kgsl_context *context,
+ uint64_t flags)
+{
+ if ((context->flags & KGSL_CONTEXT_SPARSE) ||
+ (flags & KGSL_DRAWOBJ_SPARSE))
+ return true;
+
+ return false;
+}
+
+
long kgsl_ioctl_rb_issueibcmds(struct kgsl_device_private *dev_priv,
unsigned int cmd, void *data)
{
@@ -1463,6 +1474,11 @@ long kgsl_ioctl_rb_issueibcmds(struct kgsl_device_private *dev_priv,
if (context == NULL)
return -EINVAL;
+ if (_check_context_is_sparse(context, param->flags)) {
+ kgsl_context_put(context);
+ return -EINVAL;
+ }
+
cmdobj = kgsl_drawobj_cmd_create(device, context, param->flags,
CMDOBJ_TYPE);
if (IS_ERR(cmdobj)) {
@@ -1558,6 +1574,11 @@ long kgsl_ioctl_submit_commands(struct kgsl_device_private *dev_priv,
if (context == NULL)
return -EINVAL;
+ if (_check_context_is_sparse(context, param->flags)) {
+ kgsl_context_put(context);
+ return -EINVAL;
+ }
+
if (type & SYNCOBJ_TYPE) {
struct kgsl_drawobj_sync *syncobj =
kgsl_drawobj_sync_create(device, context);
@@ -1632,6 +1653,11 @@ long kgsl_ioctl_gpu_command(struct kgsl_device_private *dev_priv,
if (context == NULL)
return -EINVAL;
+ if (_check_context_is_sparse(context, param->flags)) {
+ kgsl_context_put(context);
+ return -EINVAL;
+ }
+
if (type & SYNCOBJ_TYPE) {
struct kgsl_drawobj_sync *syncobj =
kgsl_drawobj_sync_create(device, context);
@@ -3742,6 +3768,128 @@ long kgsl_ioctl_sparse_bind(struct kgsl_device_private *dev_priv,
return ret;
}
+long kgsl_ioctl_gpu_sparse_command(struct kgsl_device_private *dev_priv,
+ unsigned int cmd, void *data)
+{
+ struct kgsl_gpu_sparse_command *param = data;
+ struct kgsl_device *device = dev_priv->device;
+ struct kgsl_context *context;
+ struct kgsl_drawobj *drawobj[2];
+ struct kgsl_drawobj_sparse *sparseobj;
+ long result;
+ unsigned int i = 0;
+
+ /* Make sure sparse and syncpoint count isn't too big */
+ if (param->numsparse > KGSL_MAX_SPARSE ||
+ param->numsyncs > KGSL_MAX_SYNCPOINTS)
+ return -EINVAL;
+
+ /* Make sure there is atleast one sparse or sync */
+ if (param->numsparse == 0 && param->numsyncs == 0)
+ return -EINVAL;
+
+ /* Only Sparse commands are supported in this ioctl */
+ if (!(param->flags & KGSL_DRAWOBJ_SPARSE) || (param->flags &
+ (KGSL_DRAWOBJ_SUBMIT_IB_LIST | KGSL_DRAWOBJ_MARKER
+ | KGSL_DRAWOBJ_SYNC)))
+ return -EINVAL;
+
+ context = kgsl_context_get_owner(dev_priv, param->context_id);
+ if (context == NULL)
+ return -EINVAL;
+
+ /* Restrict bind commands to bind context */
+ if (!(context->flags & KGSL_CONTEXT_SPARSE)) {
+ kgsl_context_put(context);
+ return -EINVAL;
+ }
+
+ if (param->numsyncs) {
+ struct kgsl_drawobj_sync *syncobj = kgsl_drawobj_sync_create(
+ device, context);
+ if (IS_ERR(syncobj)) {
+ result = PTR_ERR(syncobj);
+ goto done;
+ }
+
+ drawobj[i++] = DRAWOBJ(syncobj);
+ result = kgsl_drawobj_sync_add_synclist(device, syncobj,
+ to_user_ptr(param->synclist),
+ param->syncsize, param->numsyncs);
+ if (result)
+ goto done;
+ }
+
+ if (param->numsparse) {
+ sparseobj = kgsl_drawobj_sparse_create(device, context,
+ param->flags);
+ if (IS_ERR(sparseobj)) {
+ result = PTR_ERR(sparseobj);
+ goto done;
+ }
+
+ sparseobj->id = param->id;
+ drawobj[i++] = DRAWOBJ(sparseobj);
+ result = kgsl_drawobj_sparse_add_sparselist(device, sparseobj,
+ param->id, to_user_ptr(param->sparselist),
+ param->sparsesize, param->numsparse);
+ if (result)
+ goto done;
+ }
+
+ result = dev_priv->device->ftbl->queue_cmds(dev_priv, context,
+ drawobj, i, &param->timestamp);
+
+done:
+ /*
+ * -EPROTO is a "success" error - it just tells the user that the
+ * context had previously faulted
+ */
+ if (result && result != -EPROTO)
+ while (i--)
+ kgsl_drawobj_destroy(drawobj[i]);
+
+ kgsl_context_put(context);
+ return result;
+}
+
+void kgsl_sparse_bind(struct kgsl_process_private *private,
+ struct kgsl_drawobj_sparse *sparseobj)
+{
+ struct kgsl_sparseobj_node *sparse_node;
+ struct kgsl_mem_entry *virt_entry = NULL;
+ long ret = 0;
+ char *name;
+
+ virt_entry = kgsl_sharedmem_find_id_flags(private, sparseobj->id,
+ KGSL_MEMFLAGS_SPARSE_VIRT);
+ if (virt_entry == NULL)
+ return;
+
+ list_for_each_entry(sparse_node, &sparseobj->sparselist, node) {
+ if (sparse_node->obj.flags & KGSL_SPARSE_BIND) {
+ ret = sparse_bind_range(private, &sparse_node->obj,
+ virt_entry);
+ name = "bind";
+ } else {
+ ret = sparse_unbind_range(&sparse_node->obj,
+ virt_entry);
+ name = "unbind";
+ }
+
+ if (ret)
+ KGSL_CORE_ERR("kgsl: Unable to '%s' ret %ld virt_id %d, phys_id %d, virt_offset %16.16llX, phys_offset %16.16llX, size %16.16llX, flags %16.16llX\n",
+ name, ret, sparse_node->virt_id,
+ sparse_node->obj.id,
+ sparse_node->obj.virtoffset,
+ sparse_node->obj.physoffset,
+ sparse_node->obj.size, sparse_node->obj.flags);
+ }
+
+ kgsl_mem_entry_put(virt_entry);
+}
+EXPORT_SYMBOL(kgsl_sparse_bind);
+
long kgsl_ioctl_gpuobj_info(struct kgsl_device_private *dev_priv,
unsigned int cmd, void *data)
{
@@ -4656,7 +4804,7 @@ static void kgsl_core_exit(void)
kgsl_driver.class = NULL;
}
- kgsl_drawobj_exit();
+ kgsl_drawobjs_cache_exit();
kgsl_memfree_exit();
unregister_chrdev_region(kgsl_driver.major, KGSL_DEVICE_MAX);
@@ -4732,7 +4880,7 @@ static int __init kgsl_core_init(void)
kgsl_events_init();
- result = kgsl_drawobj_init();
+ result = kgsl_drawobjs_cache_init();
if (result)
goto err;