These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / drivers / gpu / drm / vmwgfx / vmwgfx_execbuf.c
index 97ad3bc..5da5de0 100644 (file)
@@ -1,6 +1,6 @@
 /**************************************************************************
  *
- * Copyright © 2009 VMware, Inc., Palo Alto, CA., USA
+ * Copyright © 2009 - 2015 VMware, Inc., Palo Alto, CA., USA
  * All Rights Reserved.
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
@@ -29,6 +29,8 @@
 #include "vmwgfx_reg.h"
 #include <drm/ttm/ttm_bo_api.h>
 #include <drm/ttm/ttm_placement.h>
+#include "vmwgfx_so.h"
+#include "vmwgfx_binding.h"
 
 #define VMW_RES_HT_ORDER 12
 
@@ -59,8 +61,11 @@ struct vmw_resource_relocation {
  * @new_backup_offset: New backup buffer offset if @new_backup is non-NUll.
  * @first_usage: Set to true the first time the resource is referenced in
  * the command stream.
- * @no_buffer_needed: Resources do not need to allocate buffer backup on
- * reservation. The command stream will provide one.
+ * @switching_backup: The command stream provides a new backup buffer for a
+ * resource.
+ * @no_buffer_needed: This means @switching_backup is true on first buffer
+ * reference. So resource reservation does not need to allocate a backup
+ * buffer for the resource.
  */
 struct vmw_resource_val_node {
        struct list_head head;
@@ -69,8 +74,9 @@ struct vmw_resource_val_node {
        struct vmw_dma_buffer *new_backup;
        struct vmw_ctx_binding_state *staged_bindings;
        unsigned long new_backup_offset;
-       bool first_usage;
-       bool no_buffer_needed;
+       u32 first_usage : 1;
+       u32 switching_backup : 1;
+       u32 no_buffer_needed : 1;
 };
 
 /**
@@ -92,22 +98,40 @@ struct vmw_cmd_entry {
        [(_cmd) - SVGA_3D_CMD_BASE] = {(_func), (_user_allow),\
                                       (_gb_disable), (_gb_enable)}
 
+static int vmw_resource_context_res_add(struct vmw_private *dev_priv,
+                                       struct vmw_sw_context *sw_context,
+                                       struct vmw_resource *ctx);
+static int vmw_translate_mob_ptr(struct vmw_private *dev_priv,
+                                struct vmw_sw_context *sw_context,
+                                SVGAMobId *id,
+                                struct vmw_dma_buffer **vmw_bo_p);
+static int vmw_bo_to_validate_list(struct vmw_sw_context *sw_context,
+                                  struct vmw_dma_buffer *vbo,
+                                  bool validate_as_mob,
+                                  uint32_t *p_val_node);
+
+
 /**
- * vmw_resource_unreserve - unreserve resources previously reserved for
+ * vmw_resources_unreserve - unreserve resources previously reserved for
  * command submission.
  *
- * @list_head: list of resources to unreserve.
+ * @sw_context: pointer to the software context
  * @backoff: Whether command submission failed.
  */
-static void vmw_resource_list_unreserve(struct list_head *list,
-                                       bool backoff)
+static void vmw_resources_unreserve(struct vmw_sw_context *sw_context,
+                                   bool backoff)
 {
        struct vmw_resource_val_node *val;
+       struct list_head *list = &sw_context->resource_list;
+
+       if (sw_context->dx_query_mob && !backoff)
+               vmw_context_bind_dx_query(sw_context->dx_query_ctx,
+                                         sw_context->dx_query_mob);
 
        list_for_each_entry(val, list, head) {
                struct vmw_resource *res = val->res;
-               struct vmw_dma_buffer *new_backup =
-                       backoff ? NULL : val->new_backup;
+               bool switch_backup =
+                       (backoff) ? false : val->switching_backup;
 
                /*
                 * Transfer staged context bindings to the
@@ -115,18 +139,71 @@ static void vmw_resource_list_unreserve(struct list_head *list,
                 */
                if (unlikely(val->staged_bindings)) {
                        if (!backoff) {
-                               vmw_context_binding_state_transfer
-                                       (val->res, val->staged_bindings);
+                               vmw_binding_state_commit
+                                       (vmw_context_binding_state(val->res),
+                                        val->staged_bindings);
                        }
-                       kfree(val->staged_bindings);
+
+                       if (val->staged_bindings != sw_context->staged_bindings)
+                               vmw_binding_state_free(val->staged_bindings);
+                       else
+                               sw_context->staged_bindings_inuse = false;
                        val->staged_bindings = NULL;
                }
-               vmw_resource_unreserve(res, new_backup,
-                       val->new_backup_offset);
+               vmw_resource_unreserve(res, switch_backup, val->new_backup,
+                                      val->new_backup_offset);
                vmw_dmabuf_unreference(&val->new_backup);
        }
 }
 
+/**
+ * vmw_cmd_ctx_first_setup - Perform the setup needed when a context is
+ * added to the validate list.
+ *
+ * @dev_priv: Pointer to the device private:
+ * @sw_context: The validation context:
+ * @node: The validation node holding this context.
+ */
+static int vmw_cmd_ctx_first_setup(struct vmw_private *dev_priv,
+                                  struct vmw_sw_context *sw_context,
+                                  struct vmw_resource_val_node *node)
+{
+       int ret;
+
+       ret = vmw_resource_context_res_add(dev_priv, sw_context, node->res);
+       if (unlikely(ret != 0))
+               goto out_err;
+
+       if (!sw_context->staged_bindings) {
+               sw_context->staged_bindings =
+                       vmw_binding_state_alloc(dev_priv);
+               if (IS_ERR(sw_context->staged_bindings)) {
+                       DRM_ERROR("Failed to allocate context binding "
+                                 "information.\n");
+                       ret = PTR_ERR(sw_context->staged_bindings);
+                       sw_context->staged_bindings = NULL;
+                       goto out_err;
+               }
+       }
+
+       if (sw_context->staged_bindings_inuse) {
+               node->staged_bindings = vmw_binding_state_alloc(dev_priv);
+               if (IS_ERR(node->staged_bindings)) {
+                       DRM_ERROR("Failed to allocate context binding "
+                                 "information.\n");
+                       ret = PTR_ERR(node->staged_bindings);
+                       node->staged_bindings = NULL;
+                       goto out_err;
+               }
+       } else {
+               node->staged_bindings = sw_context->staged_bindings;
+               sw_context->staged_bindings_inuse = true;
+       }
+
+       return 0;
+out_err:
+       return ret;
+}
 
 /**
  * vmw_resource_val_add - Add a resource to the software context's
@@ -141,6 +218,7 @@ static int vmw_resource_val_add(struct vmw_sw_context *sw_context,
                                struct vmw_resource *res,
                                struct vmw_resource_val_node **p_node)
 {
+       struct vmw_private *dev_priv = res->dev_priv;
        struct vmw_resource_val_node *node;
        struct drm_hash_item *hash;
        int ret;
@@ -169,14 +247,90 @@ static int vmw_resource_val_add(struct vmw_sw_context *sw_context,
                kfree(node);
                return ret;
        }
-       list_add_tail(&node->head, &sw_context->resource_list);
        node->res = vmw_resource_reference(res);
        node->first_usage = true;
-
        if (unlikely(p_node != NULL))
                *p_node = node;
 
-       return 0;
+       if (!dev_priv->has_mob) {
+               list_add_tail(&node->head, &sw_context->resource_list);
+               return 0;
+       }
+
+       switch (vmw_res_type(res)) {
+       case vmw_res_context:
+       case vmw_res_dx_context:
+               list_add(&node->head, &sw_context->ctx_resource_list);
+               ret = vmw_cmd_ctx_first_setup(dev_priv, sw_context, node);
+               break;
+       case vmw_res_cotable:
+               list_add_tail(&node->head, &sw_context->ctx_resource_list);
+               break;
+       default:
+               list_add_tail(&node->head, &sw_context->resource_list);
+               break;
+       }
+
+       return ret;
+}
+
+/**
+ * vmw_view_res_val_add - Add a view and the surface it's pointing to
+ * to the validation list
+ *
+ * @sw_context: The software context holding the validation list.
+ * @view: Pointer to the view resource.
+ *
+ * Returns 0 if success, negative error code otherwise.
+ */
+static int vmw_view_res_val_add(struct vmw_sw_context *sw_context,
+                               struct vmw_resource *view)
+{
+       int ret;
+
+       /*
+        * First add the resource the view is pointing to, otherwise
+        * it may be swapped out when the view is validated.
+        */
+       ret = vmw_resource_val_add(sw_context, vmw_view_srf(view), NULL);
+       if (ret)
+               return ret;
+
+       return vmw_resource_val_add(sw_context, view, NULL);
+}
+
+/**
+ * vmw_view_id_val_add - Look up a view and add it and the surface it's
+ * pointing to to the validation list.
+ *
+ * @sw_context: The software context holding the validation list.
+ * @view_type: The view type to look up.
+ * @id: view id of the view.
+ *
+ * The view is represented by a view id and the DX context it's created on,
+ * or scheduled for creation on. If there is no DX context set, the function
+ * will return -EINVAL. Otherwise returns 0 on success and -EINVAL on failure.
+ */
+static int vmw_view_id_val_add(struct vmw_sw_context *sw_context,
+                              enum vmw_view_type view_type, u32 id)
+{
+       struct vmw_resource_val_node *ctx_node = sw_context->dx_ctx_node;
+       struct vmw_resource *view;
+       int ret;
+
+       if (!ctx_node) {
+               DRM_ERROR("DX Context not set.\n");
+               return -EINVAL;
+       }
+
+       view = vmw_view_lookup(sw_context->man, view_type, id);
+       if (IS_ERR(view))
+               return PTR_ERR(view);
+
+       ret = vmw_view_res_val_add(sw_context, view);
+       vmw_resource_unreference(&view);
+
+       return ret;
 }
 
 /**
@@ -195,24 +349,56 @@ static int vmw_resource_context_res_add(struct vmw_private *dev_priv,
                                        struct vmw_resource *ctx)
 {
        struct list_head *binding_list;
-       struct vmw_ctx_binding *entry;
+       struct vmw_ctx_bindinfo *entry;
        int ret = 0;
        struct vmw_resource *res;
+       u32 i;
+
+       /* Add all cotables to the validation list. */
+       if (dev_priv->has_dx && vmw_res_type(ctx) == vmw_res_dx_context) {
+               for (i = 0; i < SVGA_COTABLE_DX10_MAX; ++i) {
+                       res = vmw_context_cotable(ctx, i);
+                       if (IS_ERR(res))
+                               continue;
+
+                       ret = vmw_resource_val_add(sw_context, res, NULL);
+                       vmw_resource_unreference(&res);
+                       if (unlikely(ret != 0))
+                               return ret;
+               }
+       }
+
 
+       /* Add all resources bound to the context to the validation list */
        mutex_lock(&dev_priv->binding_mutex);
        binding_list = vmw_context_binding_list(ctx);
 
        list_for_each_entry(entry, binding_list, ctx_list) {
-               res = vmw_resource_reference_unless_doomed(entry->bi.res);
+               /* entry->res is not refcounted */
+               res = vmw_resource_reference_unless_doomed(entry->res);
                if (unlikely(res == NULL))
                        continue;
 
-               ret = vmw_resource_val_add(sw_context, entry->bi.res, NULL);
+               if (vmw_res_type(entry->res) == vmw_res_view)
+                       ret = vmw_view_res_val_add(sw_context, entry->res);
+               else
+                       ret = vmw_resource_val_add(sw_context, entry->res,
+                                                  NULL);
                vmw_resource_unreference(&res);
                if (unlikely(ret != 0))
                        break;
        }
 
+       if (dev_priv->has_dx && vmw_res_type(ctx) == vmw_res_dx_context) {
+               struct vmw_dma_buffer *dx_query_mob;
+
+               dx_query_mob = vmw_context_get_dx_query_mob(ctx);
+               if (dx_query_mob)
+                       ret = vmw_bo_to_validate_list(sw_context,
+                                                     dx_query_mob,
+                                                     true, NULL);
+       }
+
        mutex_unlock(&dev_priv->binding_mutex);
        return ret;
 }
@@ -308,7 +494,7 @@ static int vmw_cmd_ok(struct vmw_private *dev_priv,
  * submission is reached.
  */
 static int vmw_bo_to_validate_list(struct vmw_sw_context *sw_context,
-                                  struct ttm_buffer_object *bo,
+                                  struct vmw_dma_buffer *vbo,
                                   bool validate_as_mob,
                                   uint32_t *p_val_node)
 {
@@ -318,7 +504,7 @@ static int vmw_bo_to_validate_list(struct vmw_sw_context *sw_context,
        struct drm_hash_item *hash;
        int ret;
 
-       if (likely(drm_ht_find_item(&sw_context->res_ht, (unsigned long) bo,
+       if (likely(drm_ht_find_item(&sw_context->res_ht, (unsigned long) vbo,
                                    &hash) == 0)) {
                vval_buf = container_of(hash, struct vmw_validate_buffer,
                                        hash);
@@ -336,7 +522,7 @@ static int vmw_bo_to_validate_list(struct vmw_sw_context *sw_context,
                        return -EINVAL;
                }
                vval_buf = &sw_context->val_bufs[val_node];
-               vval_buf->hash.key = (unsigned long) bo;
+               vval_buf->hash.key = (unsigned long) vbo;
                ret = drm_ht_insert_item(&sw_context->res_ht, &vval_buf->hash);
                if (unlikely(ret != 0)) {
                        DRM_ERROR("Failed to initialize a buffer validation "
@@ -345,7 +531,7 @@ static int vmw_bo_to_validate_list(struct vmw_sw_context *sw_context,
                }
                ++sw_context->cur_val_buf;
                val_buf = &vval_buf->base;
-               val_buf->bo = ttm_bo_reference(bo);
+               val_buf->bo = ttm_bo_reference(&vbo->base);
                val_buf->shared = false;
                list_add_tail(&val_buf->head, &sw_context->validate_nodes);
                vval_buf->validate_as_mob = validate_as_mob;
@@ -370,27 +556,39 @@ static int vmw_bo_to_validate_list(struct vmw_sw_context *sw_context,
 static int vmw_resources_reserve(struct vmw_sw_context *sw_context)
 {
        struct vmw_resource_val_node *val;
-       int ret;
+       int ret = 0;
 
        list_for_each_entry(val, &sw_context->resource_list, head) {
                struct vmw_resource *res = val->res;
 
-               ret = vmw_resource_reserve(res, val->no_buffer_needed);
+               ret = vmw_resource_reserve(res, true, val->no_buffer_needed);
                if (unlikely(ret != 0))
                        return ret;
 
                if (res->backup) {
-                       struct ttm_buffer_object *bo = &res->backup->base;
+                       struct vmw_dma_buffer *vbo = res->backup;
 
                        ret = vmw_bo_to_validate_list
-                               (sw_context, bo,
+                               (sw_context, vbo,
                                 vmw_resource_needs_backup(res), NULL);
 
                        if (unlikely(ret != 0))
                                return ret;
                }
        }
-       return 0;
+
+       if (sw_context->dx_query_mob) {
+               struct vmw_dma_buffer *expected_dx_query_mob;
+
+               expected_dx_query_mob =
+                       vmw_context_get_dx_query_mob(sw_context->dx_query_ctx);
+               if (expected_dx_query_mob &&
+                   expected_dx_query_mob != sw_context->dx_query_mob) {
+                       ret = -EINVAL;
+               }
+       }
+
+       return ret;
 }
 
 /**
@@ -409,6 +607,7 @@ static int vmw_resources_validate(struct vmw_sw_context *sw_context)
 
        list_for_each_entry(val, &sw_context->resource_list, head) {
                struct vmw_resource *res = val->res;
+               struct vmw_dma_buffer *backup = res->backup;
 
                ret = vmw_resource_validate(res);
                if (unlikely(ret != 0)) {
@@ -416,18 +615,29 @@ static int vmw_resources_validate(struct vmw_sw_context *sw_context)
                                DRM_ERROR("Failed to validate resource.\n");
                        return ret;
                }
+
+               /* Check if the resource switched backup buffer */
+               if (backup && res->backup && (backup != res->backup)) {
+                       struct vmw_dma_buffer *vbo = res->backup;
+
+                       ret = vmw_bo_to_validate_list
+                               (sw_context, vbo,
+                                vmw_resource_needs_backup(res), NULL);
+                       if (ret) {
+                               ttm_bo_unreserve(&vbo->base);
+                               return ret;
+                       }
+               }
        }
        return 0;
 }
 
-
 /**
  * vmw_cmd_res_reloc_add - Add a resource to a software context's
  * relocation- and validation lists.
  *
  * @dev_priv: Pointer to a struct vmw_private identifying the device.
  * @sw_context: Pointer to the software context.
- * @res_type: Resource type.
  * @id_loc: Pointer to where the id that needs translation is located.
  * @res: Valid pointer to a struct vmw_resource.
  * @p_val: If non null, a pointer to the struct vmw_resource_validate_node
@@ -435,7 +645,6 @@ static int vmw_resources_validate(struct vmw_sw_context *sw_context)
  */
 static int vmw_cmd_res_reloc_add(struct vmw_private *dev_priv,
                                 struct vmw_sw_context *sw_context,
-                                enum vmw_res_type res_type,
                                 uint32_t *id_loc,
                                 struct vmw_resource *res,
                                 struct vmw_resource_val_node **p_val)
@@ -454,29 +663,6 @@ static int vmw_cmd_res_reloc_add(struct vmw_private *dev_priv,
        if (unlikely(ret != 0))
                return ret;
 
-       if (res_type == vmw_res_context && dev_priv->has_mob &&
-           node->first_usage) {
-
-               /*
-                * Put contexts first on the list to be able to exit
-                * list traversal for contexts early.
-                */
-               list_del(&node->head);
-               list_add(&node->head, &sw_context->resource_list);
-
-               ret = vmw_resource_context_res_add(dev_priv, sw_context, res);
-               if (unlikely(ret != 0))
-                       return ret;
-               node->staged_bindings =
-                       kzalloc(sizeof(*node->staged_bindings), GFP_KERNEL);
-               if (node->staged_bindings == NULL) {
-                       DRM_ERROR("Failed to allocate context binding "
-                                 "information.\n");
-                       return -ENOMEM;
-               }
-               INIT_LIST_HEAD(&node->staged_bindings->list);
-       }
-
        if (p_val)
                *p_val = node;
 
@@ -554,7 +740,7 @@ vmw_cmd_res_check(struct vmw_private *dev_priv,
        rcache->res = res;
        rcache->handle = *id_loc;
 
-       ret = vmw_cmd_res_reloc_add(dev_priv, sw_context, res_type, id_loc,
+       ret = vmw_cmd_res_reloc_add(dev_priv, sw_context, id_loc,
                                    res, &node);
        if (unlikely(ret != 0))
                goto out_no_reloc;
@@ -572,6 +758,46 @@ out_no_reloc:
        return ret;
 }
 
+/**
+ * vmw_rebind_dx_query - Rebind DX query associated with the context
+ *
+ * @ctx_res: context the query belongs to
+ *
+ * This function assumes binding_mutex is held.
+ */
+static int vmw_rebind_all_dx_query(struct vmw_resource *ctx_res)
+{
+       struct vmw_private *dev_priv = ctx_res->dev_priv;
+       struct vmw_dma_buffer *dx_query_mob;
+       struct {
+               SVGA3dCmdHeader header;
+               SVGA3dCmdDXBindAllQuery body;
+       } *cmd;
+
+
+       dx_query_mob = vmw_context_get_dx_query_mob(ctx_res);
+
+       if (!dx_query_mob || dx_query_mob->dx_query_ctx)
+               return 0;
+
+       cmd = vmw_fifo_reserve_dx(dev_priv, sizeof(*cmd), ctx_res->id);
+
+       if (cmd == NULL) {
+               DRM_ERROR("Failed to rebind queries.\n");
+               return -ENOMEM;
+       }
+
+       cmd->header.id = SVGA_3D_CMD_DX_BIND_ALL_QUERY;
+       cmd->header.size = sizeof(cmd->body);
+       cmd->body.cid = ctx_res->id;
+       cmd->body.mobid = dx_query_mob->base.mem.start;
+       vmw_fifo_commit(dev_priv, sizeof(*cmd));
+
+       vmw_context_bind_dx_query(ctx_res, dx_query_mob);
+
+       return 0;
+}
+
 /**
  * vmw_rebind_contexts - Rebind all resources previously bound to
  * referenced contexts.
@@ -589,12 +815,80 @@ static int vmw_rebind_contexts(struct vmw_sw_context *sw_context)
                if (unlikely(!val->staged_bindings))
                        break;
 
-               ret = vmw_context_rebind_all(val->res);
+               ret = vmw_binding_rebind_all
+                       (vmw_context_binding_state(val->res));
                if (unlikely(ret != 0)) {
                        if (ret != -ERESTARTSYS)
                                DRM_ERROR("Failed to rebind context.\n");
                        return ret;
                }
+
+               ret = vmw_rebind_all_dx_query(val->res);
+               if (ret != 0)
+                       return ret;
+       }
+
+       return 0;
+}
+
+/**
+ * vmw_view_bindings_add - Add an array of view bindings to a context
+ * binding state tracker.
+ *
+ * @sw_context: The execbuf state used for this command.
+ * @view_type: View type for the bindings.
+ * @binding_type: Binding type for the bindings.
+ * @shader_slot: The shader slot to user for the bindings.
+ * @view_ids: Array of view ids to be bound.
+ * @num_views: Number of view ids in @view_ids.
+ * @first_slot: The binding slot to be used for the first view id in @view_ids.
+ */
+static int vmw_view_bindings_add(struct vmw_sw_context *sw_context,
+                                enum vmw_view_type view_type,
+                                enum vmw_ctx_binding_type binding_type,
+                                uint32 shader_slot,
+                                uint32 view_ids[], u32 num_views,
+                                u32 first_slot)
+{
+       struct vmw_resource_val_node *ctx_node = sw_context->dx_ctx_node;
+       struct vmw_cmdbuf_res_manager *man;
+       u32 i;
+       int ret;
+
+       if (!ctx_node) {
+               DRM_ERROR("DX Context not set.\n");
+               return -EINVAL;
+       }
+
+       man = sw_context->man;
+       for (i = 0; i < num_views; ++i) {
+               struct vmw_ctx_bindinfo_view binding;
+               struct vmw_resource *view = NULL;
+
+               if (view_ids[i] != SVGA3D_INVALID_ID) {
+                       view = vmw_view_lookup(man, view_type, view_ids[i]);
+                       if (IS_ERR(view)) {
+                               DRM_ERROR("View not found.\n");
+                               return PTR_ERR(view);
+                       }
+
+                       ret = vmw_view_res_val_add(sw_context, view);
+                       if (ret) {
+                               DRM_ERROR("Could not add view to "
+                                         "validation list.\n");
+                               vmw_resource_unreference(&view);
+                               return ret;
+                       }
+               }
+               binding.bi.ctx = ctx_node->res;
+               binding.bi.res = view;
+               binding.bi.bt = binding_type;
+               binding.shader_slot = shader_slot;
+               binding.slot = first_slot + i;
+               vmw_binding_add(ctx_node->staged_bindings, &binding.bi,
+                               shader_slot, binding.slot);
+               if (view)
+                       vmw_resource_unreference(&view);
        }
 
        return 0;
@@ -638,6 +932,12 @@ static int vmw_cmd_set_render_target_check(struct vmw_private *dev_priv,
 
        cmd = container_of(header, struct vmw_sid_cmd, header);
 
+       if (cmd->body.type >= SVGA3D_RT_MAX) {
+               DRM_ERROR("Illegal render target type %u.\n",
+                         (unsigned) cmd->body.type);
+               return -EINVAL;
+       }
+
        ret = vmw_cmd_res_check(dev_priv, sw_context, vmw_res_context,
                                user_context_converter, &cmd->body.cid,
                                &ctx_node);
@@ -651,13 +951,14 @@ static int vmw_cmd_set_render_target_check(struct vmw_private *dev_priv,
                return ret;
 
        if (dev_priv->has_mob) {
-               struct vmw_ctx_bindinfo bi;
-
-               bi.ctx = ctx_node->res;
-               bi.res = res_node ? res_node->res : NULL;
-               bi.bt = vmw_ctx_binding_rt;
-               bi.i1.rt_type = cmd->body.type;
-               return vmw_context_binding_add(ctx_node->staged_bindings, &bi);
+               struct vmw_ctx_bindinfo_view binding;
+
+               binding.bi.ctx = ctx_node->res;
+               binding.bi.res = res_node ? res_node->res : NULL;
+               binding.bi.bt = vmw_ctx_binding_rt;
+               binding.slot = cmd->body.type;
+               vmw_binding_add(ctx_node->staged_bindings,
+                               &binding.bi, 0, binding.slot);
        }
 
        return 0;
@@ -674,16 +975,62 @@ static int vmw_cmd_surface_copy_check(struct vmw_private *dev_priv,
        int ret;
 
        cmd = container_of(header, struct vmw_sid_cmd, header);
+
        ret = vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface,
                                user_surface_converter,
                                &cmd->body.src.sid, NULL);
-       if (unlikely(ret != 0))
+       if (ret)
                return ret;
+
        return vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface,
                                 user_surface_converter,
                                 &cmd->body.dest.sid, NULL);
 }
 
+static int vmw_cmd_buffer_copy_check(struct vmw_private *dev_priv,
+                                     struct vmw_sw_context *sw_context,
+                                     SVGA3dCmdHeader *header)
+{
+       struct {
+               SVGA3dCmdHeader header;
+               SVGA3dCmdDXBufferCopy body;
+       } *cmd;
+       int ret;
+
+       cmd = container_of(header, typeof(*cmd), header);
+       ret = vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface,
+                               user_surface_converter,
+                               &cmd->body.src, NULL);
+       if (ret != 0)
+               return ret;
+
+       return vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface,
+                                user_surface_converter,
+                                &cmd->body.dest, NULL);
+}
+
+static int vmw_cmd_pred_copy_check(struct vmw_private *dev_priv,
+                                  struct vmw_sw_context *sw_context,
+                                  SVGA3dCmdHeader *header)
+{
+       struct {
+               SVGA3dCmdHeader header;
+               SVGA3dCmdDXPredCopyRegion body;
+       } *cmd;
+       int ret;
+
+       cmd = container_of(header, typeof(*cmd), header);
+       ret = vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface,
+                               user_surface_converter,
+                               &cmd->body.srcSid, NULL);
+       if (ret != 0)
+               return ret;
+
+       return vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface,
+                                user_surface_converter,
+                                &cmd->body.dstSid, NULL);
+}
+
 static int vmw_cmd_stretch_blt_check(struct vmw_private *dev_priv,
                                     struct vmw_sw_context *sw_context,
                                     SVGA3dCmdHeader *header)
@@ -752,7 +1099,7 @@ static int vmw_cmd_present_check(struct vmw_private *dev_priv,
  * command batch.
  */
 static int vmw_query_bo_switch_prepare(struct vmw_private *dev_priv,
-                                      struct ttm_buffer_object *new_query_bo,
+                                      struct vmw_dma_buffer *new_query_bo,
                                       struct vmw_sw_context *sw_context)
 {
        struct vmw_res_cache_entry *ctx_entry =
@@ -764,7 +1111,7 @@ static int vmw_query_bo_switch_prepare(struct vmw_private *dev_priv,
 
        if (unlikely(new_query_bo != sw_context->cur_query_bo)) {
 
-               if (unlikely(new_query_bo->num_pages > 4)) {
+               if (unlikely(new_query_bo->base.num_pages > 4)) {
                        DRM_ERROR("Query buffer too large.\n");
                        return -EINVAL;
                }
@@ -833,12 +1180,12 @@ static void vmw_query_bo_switch_commit(struct vmw_private *dev_priv,
 
        if (dev_priv->pinned_bo != sw_context->cur_query_bo) {
                if (dev_priv->pinned_bo) {
-                       vmw_bo_pin(dev_priv->pinned_bo, false);
-                       ttm_bo_unref(&dev_priv->pinned_bo);
+                       vmw_bo_pin_reserved(dev_priv->pinned_bo, false);
+                       vmw_dmabuf_unreference(&dev_priv->pinned_bo);
                }
 
                if (!sw_context->needs_post_query_barrier) {
-                       vmw_bo_pin(sw_context->cur_query_bo, true);
+                       vmw_bo_pin_reserved(sw_context->cur_query_bo, true);
 
                        /*
                         * We pin also the dummy_query_bo buffer so that we
@@ -846,14 +1193,17 @@ static void vmw_query_bo_switch_commit(struct vmw_private *dev_priv,
                         * dummy queries in context destroy paths.
                         */
 
-                       vmw_bo_pin(dev_priv->dummy_query_bo, true);
-                       dev_priv->dummy_query_bo_pinned = true;
+                       if (!dev_priv->dummy_query_bo_pinned) {
+                               vmw_bo_pin_reserved(dev_priv->dummy_query_bo,
+                                                   true);
+                               dev_priv->dummy_query_bo_pinned = true;
+                       }
 
                        BUG_ON(sw_context->last_query_ctx == NULL);
                        dev_priv->query_cid = sw_context->last_query_ctx->id;
                        dev_priv->query_cid_valid = true;
                        dev_priv->pinned_bo =
-                               ttm_bo_reference(sw_context->cur_query_bo);
+                               vmw_dmabuf_reference(sw_context->cur_query_bo);
                }
        }
 }
@@ -882,18 +1232,17 @@ static int vmw_translate_mob_ptr(struct vmw_private *dev_priv,
                                 struct vmw_dma_buffer **vmw_bo_p)
 {
        struct vmw_dma_buffer *vmw_bo = NULL;
-       struct ttm_buffer_object *bo;
        uint32_t handle = *id;
        struct vmw_relocation *reloc;
        int ret;
 
-       ret = vmw_user_dmabuf_lookup(sw_context->fp->tfile, handle, &vmw_bo);
+       ret = vmw_user_dmabuf_lookup(sw_context->fp->tfile, handle, &vmw_bo,
+                                    NULL);
        if (unlikely(ret != 0)) {
                DRM_ERROR("Could not find or use MOB buffer.\n");
                ret = -EINVAL;
                goto out_no_reloc;
        }
-       bo = &vmw_bo->base;
 
        if (unlikely(sw_context->cur_reloc >= VMWGFX_MAX_RELOCATIONS)) {
                DRM_ERROR("Max number relocations per submission"
@@ -906,7 +1255,7 @@ static int vmw_translate_mob_ptr(struct vmw_private *dev_priv,
        reloc->mob_loc = id;
        reloc->location = NULL;
 
-       ret = vmw_bo_to_validate_list(sw_context, bo, true, &reloc->index);
+       ret = vmw_bo_to_validate_list(sw_context, vmw_bo, true, &reloc->index);
        if (unlikely(ret != 0))
                goto out_no_reloc;
 
@@ -944,18 +1293,17 @@ static int vmw_translate_guest_ptr(struct vmw_private *dev_priv,
                                   struct vmw_dma_buffer **vmw_bo_p)
 {
        struct vmw_dma_buffer *vmw_bo = NULL;
-       struct ttm_buffer_object *bo;
        uint32_t handle = ptr->gmrId;
        struct vmw_relocation *reloc;
        int ret;
 
-       ret = vmw_user_dmabuf_lookup(sw_context->fp->tfile, handle, &vmw_bo);
+       ret = vmw_user_dmabuf_lookup(sw_context->fp->tfile, handle, &vmw_bo,
+                                    NULL);
        if (unlikely(ret != 0)) {
                DRM_ERROR("Could not find or use GMR region.\n");
                ret = -EINVAL;
                goto out_no_reloc;
        }
-       bo = &vmw_bo->base;
 
        if (unlikely(sw_context->cur_reloc >= VMWGFX_MAX_RELOCATIONS)) {
                DRM_ERROR("Max number relocations per submission"
@@ -967,7 +1315,7 @@ static int vmw_translate_guest_ptr(struct vmw_private *dev_priv,
        reloc = &sw_context->relocs[sw_context->cur_reloc++];
        reloc->location = ptr;
 
-       ret = vmw_bo_to_validate_list(sw_context, bo, false, &reloc->index);
+       ret = vmw_bo_to_validate_list(sw_context, vmw_bo, false, &reloc->index);
        if (unlikely(ret != 0))
                goto out_no_reloc;
 
@@ -980,59 +1328,151 @@ out_no_reloc:
        return ret;
 }
 
+
+
 /**
- * vmw_cmd_begin_gb_query - validate a  SVGA_3D_CMD_BEGIN_GB_QUERY command.
+ * vmw_cmd_dx_define_query - validate a SVGA_3D_CMD_DX_DEFINE_QUERY command.
  *
  * @dev_priv: Pointer to a device private struct.
  * @sw_context: The software context used for this command submission.
  * @header: Pointer to the command header in the command stream.
+ *
+ * This function adds the new query into the query COTABLE
  */
-static int vmw_cmd_begin_gb_query(struct vmw_private *dev_priv,
-                                 struct vmw_sw_context *sw_context,
-                                 SVGA3dCmdHeader *header)
+static int vmw_cmd_dx_define_query(struct vmw_private *dev_priv,
+                                  struct vmw_sw_context *sw_context,
+                                  SVGA3dCmdHeader *header)
 {
-       struct vmw_begin_gb_query_cmd {
+       struct vmw_dx_define_query_cmd {
                SVGA3dCmdHeader header;
-               SVGA3dCmdBeginGBQuery q;
+               SVGA3dCmdDXDefineQuery q;
        } *cmd;
 
-       cmd = container_of(header, struct vmw_begin_gb_query_cmd,
-                          header);
+       int    ret;
+       struct vmw_resource_val_node *ctx_node = sw_context->dx_ctx_node;
+       struct vmw_resource *cotable_res;
 
-       return vmw_cmd_res_check(dev_priv, sw_context, vmw_res_context,
-                                user_context_converter, &cmd->q.cid,
-                                NULL);
+
+       if (ctx_node == NULL) {
+               DRM_ERROR("DX Context not set for query.\n");
+               return -EINVAL;
+       }
+
+       cmd = container_of(header, struct vmw_dx_define_query_cmd, header);
+
+       if (cmd->q.type <  SVGA3D_QUERYTYPE_MIN ||
+           cmd->q.type >= SVGA3D_QUERYTYPE_MAX)
+               return -EINVAL;
+
+       cotable_res = vmw_context_cotable(ctx_node->res, SVGA_COTABLE_DXQUERY);
+       ret = vmw_cotable_notify(cotable_res, cmd->q.queryId);
+       vmw_resource_unreference(&cotable_res);
+
+       return ret;
 }
 
+
+
 /**
- * vmw_cmd_begin_query - validate a  SVGA_3D_CMD_BEGIN_QUERY command.
+ * vmw_cmd_dx_bind_query - validate a SVGA_3D_CMD_DX_BIND_QUERY command.
  *
  * @dev_priv: Pointer to a device private struct.
  * @sw_context: The software context used for this command submission.
  * @header: Pointer to the command header in the command stream.
+ *
+ * The query bind operation will eventually associate the query ID
+ * with its backing MOB.  In this function, we take the user mode
+ * MOB ID and use vmw_translate_mob_ptr() to translate it to its
+ * kernel mode equivalent.
  */
-static int vmw_cmd_begin_query(struct vmw_private *dev_priv,
-                              struct vmw_sw_context *sw_context,
-                              SVGA3dCmdHeader *header)
+static int vmw_cmd_dx_bind_query(struct vmw_private *dev_priv,
+                                struct vmw_sw_context *sw_context,
+                                SVGA3dCmdHeader *header)
 {
-       struct vmw_begin_query_cmd {
+       struct vmw_dx_bind_query_cmd {
                SVGA3dCmdHeader header;
-               SVGA3dCmdBeginQuery q;
+               SVGA3dCmdDXBindQuery q;
        } *cmd;
 
-       cmd = container_of(header, struct vmw_begin_query_cmd,
-                          header);
+       struct vmw_dma_buffer *vmw_bo;
+       int    ret;
 
-       if (unlikely(dev_priv->has_mob)) {
-               struct {
-                       SVGA3dCmdHeader header;
-                       SVGA3dCmdBeginGBQuery q;
-               } gb_cmd;
 
-               BUG_ON(sizeof(gb_cmd) != sizeof(*cmd));
+       cmd = container_of(header, struct vmw_dx_bind_query_cmd, header);
 
-               gb_cmd.header.id = SVGA_3D_CMD_BEGIN_GB_QUERY;
-               gb_cmd.header.size = cmd->header.size;
+       /*
+        * Look up the buffer pointed to by q.mobid, put it on the relocation
+        * list so its kernel mode MOB ID can be filled in later
+        */
+       ret = vmw_translate_mob_ptr(dev_priv, sw_context, &cmd->q.mobid,
+                                   &vmw_bo);
+
+       if (ret != 0)
+               return ret;
+
+       sw_context->dx_query_mob = vmw_bo;
+       sw_context->dx_query_ctx = sw_context->dx_ctx_node->res;
+
+       vmw_dmabuf_unreference(&vmw_bo);
+
+       return ret;
+}
+
+
+
+/**
+ * vmw_cmd_begin_gb_query - validate a  SVGA_3D_CMD_BEGIN_GB_QUERY command.
+ *
+ * @dev_priv: Pointer to a device private struct.
+ * @sw_context: The software context used for this command submission.
+ * @header: Pointer to the command header in the command stream.
+ */
+static int vmw_cmd_begin_gb_query(struct vmw_private *dev_priv,
+                                 struct vmw_sw_context *sw_context,
+                                 SVGA3dCmdHeader *header)
+{
+       struct vmw_begin_gb_query_cmd {
+               SVGA3dCmdHeader header;
+               SVGA3dCmdBeginGBQuery q;
+       } *cmd;
+
+       cmd = container_of(header, struct vmw_begin_gb_query_cmd,
+                          header);
+
+       return vmw_cmd_res_check(dev_priv, sw_context, vmw_res_context,
+                                user_context_converter, &cmd->q.cid,
+                                NULL);
+}
+
+/**
+ * vmw_cmd_begin_query - validate a  SVGA_3D_CMD_BEGIN_QUERY command.
+ *
+ * @dev_priv: Pointer to a device private struct.
+ * @sw_context: The software context used for this command submission.
+ * @header: Pointer to the command header in the command stream.
+ */
+static int vmw_cmd_begin_query(struct vmw_private *dev_priv,
+                              struct vmw_sw_context *sw_context,
+                              SVGA3dCmdHeader *header)
+{
+       struct vmw_begin_query_cmd {
+               SVGA3dCmdHeader header;
+               SVGA3dCmdBeginQuery q;
+       } *cmd;
+
+       cmd = container_of(header, struct vmw_begin_query_cmd,
+                          header);
+
+       if (unlikely(dev_priv->has_mob)) {
+               struct {
+                       SVGA3dCmdHeader header;
+                       SVGA3dCmdBeginGBQuery q;
+               } gb_cmd;
+
+               BUG_ON(sizeof(gb_cmd) != sizeof(*cmd));
+
+               gb_cmd.header.id = SVGA_3D_CMD_BEGIN_GB_QUERY;
+               gb_cmd.header.size = cmd->header.size;
                gb_cmd.q.cid = cmd->q.cid;
                gb_cmd.q.type = cmd->q.type;
 
@@ -1074,7 +1514,7 @@ static int vmw_cmd_end_gb_query(struct vmw_private *dev_priv,
        if (unlikely(ret != 0))
                return ret;
 
-       ret = vmw_query_bo_switch_prepare(dev_priv, &vmw_bo->base, sw_context);
+       ret = vmw_query_bo_switch_prepare(dev_priv, vmw_bo, sw_context);
 
        vmw_dmabuf_unreference(&vmw_bo);
        return ret;
@@ -1128,7 +1568,7 @@ static int vmw_cmd_end_query(struct vmw_private *dev_priv,
        if (unlikely(ret != 0))
                return ret;
 
-       ret = vmw_query_bo_switch_prepare(dev_priv, &vmw_bo->base, sw_context);
+       ret = vmw_query_bo_switch_prepare(dev_priv, vmw_bo, sw_context);
 
        vmw_dmabuf_unreference(&vmw_bo);
        return ret;
@@ -1363,6 +1803,12 @@ static int vmw_cmd_tex_state(struct vmw_private *dev_priv,
                if (likely(cur_state->name != SVGA3D_TS_BIND_TEXTURE))
                        continue;
 
+               if (cur_state->stage >= SVGA3D_NUM_TEXTURE_UNITS) {
+                       DRM_ERROR("Illegal texture/sampler unit %u.\n",
+                                 (unsigned) cur_state->stage);
+                       return -EINVAL;
+               }
+
                ret = vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface,
                                        user_surface_converter,
                                        &cur_state->value, &res_node);
@@ -1370,14 +1816,14 @@ static int vmw_cmd_tex_state(struct vmw_private *dev_priv,
                        return ret;
 
                if (dev_priv->has_mob) {
-                       struct vmw_ctx_bindinfo bi;
-
-                       bi.ctx = ctx_node->res;
-                       bi.res = res_node ? res_node->res : NULL;
-                       bi.bt = vmw_ctx_binding_tex;
-                       bi.i1.texture_stage = cur_state->stage;
-                       vmw_context_binding_add(ctx_node->staged_bindings,
-                                               &bi);
+                       struct vmw_ctx_bindinfo_tex binding;
+
+                       binding.bi.ctx = ctx_node->res;
+                       binding.bi.res = res_node ? res_node->res : NULL;
+                       binding.bi.bt = vmw_ctx_binding_tex;
+                       binding.texture_stage = cur_state->stage;
+                       vmw_binding_add(ctx_node->staged_bindings, &binding.bi,
+                                       0, binding.texture_stage);
                }
        }
 
@@ -1407,6 +1853,47 @@ static int vmw_cmd_check_define_gmrfb(struct vmw_private *dev_priv,
        return ret;
 }
 
+
+/**
+ * vmw_cmd_res_switch_backup - Utility function to handle backup buffer
+ * switching
+ *
+ * @dev_priv: Pointer to a device private struct.
+ * @sw_context: The software context being used for this batch.
+ * @val_node: The validation node representing the resource.
+ * @buf_id: Pointer to the user-space backup buffer handle in the command
+ * stream.
+ * @backup_offset: Offset of backup into MOB.
+ *
+ * This function prepares for registering a switch of backup buffers
+ * in the resource metadata just prior to unreserving. It's basically a wrapper
+ * around vmw_cmd_res_switch_backup with a different interface.
+ */
+static int vmw_cmd_res_switch_backup(struct vmw_private *dev_priv,
+                                    struct vmw_sw_context *sw_context,
+                                    struct vmw_resource_val_node *val_node,
+                                    uint32_t *buf_id,
+                                    unsigned long backup_offset)
+{
+       struct vmw_dma_buffer *dma_buf;
+       int ret;
+
+       ret = vmw_translate_mob_ptr(dev_priv, sw_context, buf_id, &dma_buf);
+       if (ret)
+               return ret;
+
+       val_node->switching_backup = true;
+       if (val_node->first_usage)
+               val_node->no_buffer_needed = true;
+
+       vmw_dmabuf_unreference(&val_node->new_backup);
+       val_node->new_backup = dma_buf;
+       val_node->new_backup_offset = backup_offset;
+
+       return 0;
+}
+
+
 /**
  * vmw_cmd_switch_backup - Utility function to handle backup buffer switching
  *
@@ -1420,7 +1907,8 @@ static int vmw_cmd_check_define_gmrfb(struct vmw_private *dev_priv,
  * @backup_offset: Offset of backup into MOB.
  *
  * This function prepares for registering a switch of backup buffers
- * in the resource metadata just prior to unreserving.
+ * in the resource metadata just prior to unreserving. It's basically a wrapper
+ * around vmw_cmd_res_switch_backup with a different interface.
  */
 static int vmw_cmd_switch_backup(struct vmw_private *dev_priv,
                                 struct vmw_sw_context *sw_context,
@@ -1431,27 +1919,16 @@ static int vmw_cmd_switch_backup(struct vmw_private *dev_priv,
                                 uint32_t *buf_id,
                                 unsigned long backup_offset)
 {
-       int ret;
-       struct vmw_dma_buffer *dma_buf;
        struct vmw_resource_val_node *val_node;
+       int ret;
 
        ret = vmw_cmd_res_check(dev_priv, sw_context, res_type,
                                converter, res_id, &val_node);
-       if (unlikely(ret != 0))
-               return ret;
-
-       ret = vmw_translate_mob_ptr(dev_priv, sw_context, buf_id, &dma_buf);
-       if (unlikely(ret != 0))
+       if (ret)
                return ret;
 
-       if (val_node->first_usage)
-               val_node->no_buffer_needed = true;
-
-       vmw_dmabuf_unreference(&val_node->new_backup);
-       val_node->new_backup = dma_buf;
-       val_node->new_backup_offset = backup_offset;
-
-       return 0;
+       return vmw_cmd_res_switch_backup(dev_priv, sw_context, val_node,
+                                        buf_id, backup_offset);
 }
 
 /**
@@ -1703,10 +2180,10 @@ static int vmw_cmd_shader_destroy(struct vmw_private *dev_priv,
        if (unlikely(!dev_priv->has_mob))
                return 0;
 
-       ret = vmw_compat_shader_remove(vmw_context_res_man(val->res),
-                                      cmd->body.shid,
-                                      cmd->body.type,
-                                      &sw_context->staged_cmd_res);
+       ret = vmw_shader_remove(vmw_context_res_man(val->res),
+                               cmd->body.shid,
+                               cmd->body.type,
+                               &sw_context->staged_cmd_res);
        if (unlikely(ret != 0))
                return ret;
 
@@ -1734,13 +2211,19 @@ static int vmw_cmd_set_shader(struct vmw_private *dev_priv,
                SVGA3dCmdSetShader body;
        } *cmd;
        struct vmw_resource_val_node *ctx_node, *res_node = NULL;
-       struct vmw_ctx_bindinfo bi;
+       struct vmw_ctx_bindinfo_shader binding;
        struct vmw_resource *res = NULL;
        int ret;
 
        cmd = container_of(header, struct vmw_set_shader_cmd,
                           header);
 
+       if (cmd->body.type >= SVGA3D_SHADERTYPE_PREDX_MAX) {
+               DRM_ERROR("Illegal shader type %u.\n",
+                         (unsigned) cmd->body.type);
+               return -EINVAL;
+       }
+
        ret = vmw_cmd_res_check(dev_priv, sw_context, vmw_res_context,
                                user_context_converter, &cmd->body.cid,
                                &ctx_node);
@@ -1751,14 +2234,12 @@ static int vmw_cmd_set_shader(struct vmw_private *dev_priv,
                return 0;
 
        if (cmd->body.shid != SVGA3D_INVALID_ID) {
-               res = vmw_compat_shader_lookup
-                       (vmw_context_res_man(ctx_node->res),
-                        cmd->body.shid,
-                        cmd->body.type);
+               res = vmw_shader_lookup(vmw_context_res_man(ctx_node->res),
+                                       cmd->body.shid,
+                                       cmd->body.type);
 
                if (!IS_ERR(res)) {
                        ret = vmw_cmd_res_reloc_add(dev_priv, sw_context,
-                                                   vmw_res_shader,
                                                    &cmd->body.shid, res,
                                                    &res_node);
                        vmw_resource_unreference(&res);
@@ -1767,79 +2248,765 @@ static int vmw_cmd_set_shader(struct vmw_private *dev_priv,
                }
        }
 
-       if (!res_node) {
-               ret = vmw_cmd_res_check(dev_priv, sw_context,
-                                       vmw_res_shader,
-                                       user_shader_converter,
-                                       &cmd->body.shid, &res_node);
-               if (unlikely(ret != 0))
-                       return ret;
+       if (!res_node) {
+               ret = vmw_cmd_res_check(dev_priv, sw_context,
+                                       vmw_res_shader,
+                                       user_shader_converter,
+                                       &cmd->body.shid, &res_node);
+               if (unlikely(ret != 0))
+                       return ret;
+       }
+
+       binding.bi.ctx = ctx_node->res;
+       binding.bi.res = res_node ? res_node->res : NULL;
+       binding.bi.bt = vmw_ctx_binding_shader;
+       binding.shader_slot = cmd->body.type - SVGA3D_SHADERTYPE_MIN;
+       vmw_binding_add(ctx_node->staged_bindings, &binding.bi,
+                       binding.shader_slot, 0);
+       return 0;
+}
+
+/**
+ * vmw_cmd_set_shader_const - Validate an SVGA_3D_CMD_SET_SHADER_CONST
+ * command
+ *
+ * @dev_priv: Pointer to a device private struct.
+ * @sw_context: The software context being used for this batch.
+ * @header: Pointer to the command header in the command stream.
+ */
+static int vmw_cmd_set_shader_const(struct vmw_private *dev_priv,
+                                   struct vmw_sw_context *sw_context,
+                                   SVGA3dCmdHeader *header)
+{
+       struct vmw_set_shader_const_cmd {
+               SVGA3dCmdHeader header;
+               SVGA3dCmdSetShaderConst body;
+       } *cmd;
+       int ret;
+
+       cmd = container_of(header, struct vmw_set_shader_const_cmd,
+                          header);
+
+       ret = vmw_cmd_res_check(dev_priv, sw_context, vmw_res_context,
+                               user_context_converter, &cmd->body.cid,
+                               NULL);
+       if (unlikely(ret != 0))
+               return ret;
+
+       if (dev_priv->has_mob)
+               header->id = SVGA_3D_CMD_SET_GB_SHADERCONSTS_INLINE;
+
+       return 0;
+}
+
+/**
+ * vmw_cmd_bind_gb_shader - Validate an SVGA_3D_CMD_BIND_GB_SHADER
+ * command
+ *
+ * @dev_priv: Pointer to a device private struct.
+ * @sw_context: The software context being used for this batch.
+ * @header: Pointer to the command header in the command stream.
+ */
+static int vmw_cmd_bind_gb_shader(struct vmw_private *dev_priv,
+                                 struct vmw_sw_context *sw_context,
+                                 SVGA3dCmdHeader *header)
+{
+       struct vmw_bind_gb_shader_cmd {
+               SVGA3dCmdHeader header;
+               SVGA3dCmdBindGBShader body;
+       } *cmd;
+
+       cmd = container_of(header, struct vmw_bind_gb_shader_cmd,
+                          header);
+
+       return vmw_cmd_switch_backup(dev_priv, sw_context, vmw_res_shader,
+                                    user_shader_converter,
+                                    &cmd->body.shid, &cmd->body.mobid,
+                                    cmd->body.offsetInBytes);
+}
+
+/**
+ * vmw_cmd_dx_set_single_constant_buffer - Validate an
+ * SVGA_3D_CMD_DX_SET_SINGLE_CONSTANT_BUFFER command.
+ *
+ * @dev_priv: Pointer to a device private struct.
+ * @sw_context: The software context being used for this batch.
+ * @header: Pointer to the command header in the command stream.
+ */
+static int
+vmw_cmd_dx_set_single_constant_buffer(struct vmw_private *dev_priv,
+                                     struct vmw_sw_context *sw_context,
+                                     SVGA3dCmdHeader *header)
+{
+       struct {
+               SVGA3dCmdHeader header;
+               SVGA3dCmdDXSetSingleConstantBuffer body;
+       } *cmd;
+       struct vmw_resource_val_node *res_node = NULL;
+       struct vmw_resource_val_node *ctx_node = sw_context->dx_ctx_node;
+       struct vmw_ctx_bindinfo_cb binding;
+       int ret;
+
+       if (unlikely(ctx_node == NULL)) {
+               DRM_ERROR("DX Context not set.\n");
+               return -EINVAL;
+       }
+
+       cmd = container_of(header, typeof(*cmd), header);
+       ret = vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface,
+                               user_surface_converter,
+                               &cmd->body.sid, &res_node);
+       if (unlikely(ret != 0))
+               return ret;
+
+       binding.bi.ctx = ctx_node->res;
+       binding.bi.res = res_node ? res_node->res : NULL;
+       binding.bi.bt = vmw_ctx_binding_cb;
+       binding.shader_slot = cmd->body.type - SVGA3D_SHADERTYPE_MIN;
+       binding.offset = cmd->body.offsetInBytes;
+       binding.size = cmd->body.sizeInBytes;
+       binding.slot = cmd->body.slot;
+
+       if (binding.shader_slot >= SVGA3D_NUM_SHADERTYPE_DX10 ||
+           binding.slot >= SVGA3D_DX_MAX_CONSTBUFFERS) {
+               DRM_ERROR("Illegal const buffer shader %u slot %u.\n",
+                         (unsigned) cmd->body.type,
+                         (unsigned) binding.slot);
+               return -EINVAL;
+       }
+
+       vmw_binding_add(ctx_node->staged_bindings, &binding.bi,
+                       binding.shader_slot, binding.slot);
+
+       return 0;
+}
+
+/**
+ * vmw_cmd_dx_set_shader_res - Validate an
+ * SVGA_3D_CMD_DX_SET_SHADER_RESOURCES command
+ *
+ * @dev_priv: Pointer to a device private struct.
+ * @sw_context: The software context being used for this batch.
+ * @header: Pointer to the command header in the command stream.
+ */
+static int vmw_cmd_dx_set_shader_res(struct vmw_private *dev_priv,
+                                    struct vmw_sw_context *sw_context,
+                                    SVGA3dCmdHeader *header)
+{
+       struct {
+               SVGA3dCmdHeader header;
+               SVGA3dCmdDXSetShaderResources body;
+       } *cmd = container_of(header, typeof(*cmd), header);
+       u32 num_sr_view = (cmd->header.size - sizeof(cmd->body)) /
+               sizeof(SVGA3dShaderResourceViewId);
+
+       if ((u64) cmd->body.startView + (u64) num_sr_view >
+           (u64) SVGA3D_DX_MAX_SRVIEWS ||
+           cmd->body.type >= SVGA3D_SHADERTYPE_DX10_MAX) {
+               DRM_ERROR("Invalid shader binding.\n");
+               return -EINVAL;
+       }
+
+       return vmw_view_bindings_add(sw_context, vmw_view_sr,
+                                    vmw_ctx_binding_sr,
+                                    cmd->body.type - SVGA3D_SHADERTYPE_MIN,
+                                    (void *) &cmd[1], num_sr_view,
+                                    cmd->body.startView);
+}
+
+/**
+ * vmw_cmd_dx_set_shader - Validate an SVGA_3D_CMD_DX_SET_SHADER
+ * command
+ *
+ * @dev_priv: Pointer to a device private struct.
+ * @sw_context: The software context being used for this batch.
+ * @header: Pointer to the command header in the command stream.
+ */
+static int vmw_cmd_dx_set_shader(struct vmw_private *dev_priv,
+                                struct vmw_sw_context *sw_context,
+                                SVGA3dCmdHeader *header)
+{
+       struct {
+               SVGA3dCmdHeader header;
+               SVGA3dCmdDXSetShader body;
+       } *cmd;
+       struct vmw_resource *res = NULL;
+       struct vmw_resource_val_node *ctx_node = sw_context->dx_ctx_node;
+       struct vmw_ctx_bindinfo_shader binding;
+       int ret = 0;
+
+       if (unlikely(ctx_node == NULL)) {
+               DRM_ERROR("DX Context not set.\n");
+               return -EINVAL;
+       }
+
+       cmd = container_of(header, typeof(*cmd), header);
+
+       if (cmd->body.type >= SVGA3D_SHADERTYPE_DX10_MAX) {
+               DRM_ERROR("Illegal shader type %u.\n",
+                         (unsigned) cmd->body.type);
+               return -EINVAL;
+       }
+
+       if (cmd->body.shaderId != SVGA3D_INVALID_ID) {
+               res = vmw_shader_lookup(sw_context->man, cmd->body.shaderId, 0);
+               if (IS_ERR(res)) {
+                       DRM_ERROR("Could not find shader for binding.\n");
+                       return PTR_ERR(res);
+               }
+
+               ret = vmw_resource_val_add(sw_context, res, NULL);
+               if (ret)
+                       goto out_unref;
+       }
+
+       binding.bi.ctx = ctx_node->res;
+       binding.bi.res = res;
+       binding.bi.bt = vmw_ctx_binding_dx_shader;
+       binding.shader_slot = cmd->body.type - SVGA3D_SHADERTYPE_MIN;
+
+       vmw_binding_add(ctx_node->staged_bindings, &binding.bi,
+                       binding.shader_slot, 0);
+out_unref:
+       if (res)
+               vmw_resource_unreference(&res);
+
+       return ret;
+}
+
+/**
+ * vmw_cmd_dx_set_vertex_buffers - Validates an
+ * SVGA_3D_CMD_DX_SET_VERTEX_BUFFERS command
+ *
+ * @dev_priv: Pointer to a device private struct.
+ * @sw_context: The software context being used for this batch.
+ * @header: Pointer to the command header in the command stream.
+ */
+static int vmw_cmd_dx_set_vertex_buffers(struct vmw_private *dev_priv,
+                                        struct vmw_sw_context *sw_context,
+                                        SVGA3dCmdHeader *header)
+{
+       struct vmw_resource_val_node *ctx_node = sw_context->dx_ctx_node;
+       struct vmw_ctx_bindinfo_vb binding;
+       struct vmw_resource_val_node *res_node;
+       struct {
+               SVGA3dCmdHeader header;
+               SVGA3dCmdDXSetVertexBuffers body;
+               SVGA3dVertexBuffer buf[];
+       } *cmd;
+       int i, ret, num;
+
+       if (unlikely(ctx_node == NULL)) {
+               DRM_ERROR("DX Context not set.\n");
+               return -EINVAL;
+       }
+
+       cmd = container_of(header, typeof(*cmd), header);
+       num = (cmd->header.size - sizeof(cmd->body)) /
+               sizeof(SVGA3dVertexBuffer);
+       if ((u64)num + (u64)cmd->body.startBuffer >
+           (u64)SVGA3D_DX_MAX_VERTEXBUFFERS) {
+               DRM_ERROR("Invalid number of vertex buffers.\n");
+               return -EINVAL;
+       }
+
+       for (i = 0; i < num; i++) {
+               ret = vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface,
+                                       user_surface_converter,
+                                       &cmd->buf[i].sid, &res_node);
+               if (unlikely(ret != 0))
+                       return ret;
+
+               binding.bi.ctx = ctx_node->res;
+               binding.bi.bt = vmw_ctx_binding_vb;
+               binding.bi.res = ((res_node) ? res_node->res : NULL);
+               binding.offset = cmd->buf[i].offset;
+               binding.stride = cmd->buf[i].stride;
+               binding.slot = i + cmd->body.startBuffer;
+
+               vmw_binding_add(ctx_node->staged_bindings, &binding.bi,
+                               0, binding.slot);
+       }
+
+       return 0;
+}
+
+/**
+ * vmw_cmd_dx_ia_set_vertex_buffers - Validate an
+ * SVGA_3D_CMD_DX_IA_SET_VERTEX_BUFFERS command.
+ *
+ * @dev_priv: Pointer to a device private struct.
+ * @sw_context: The software context being used for this batch.
+ * @header: Pointer to the command header in the command stream.
+ */
+static int vmw_cmd_dx_set_index_buffer(struct vmw_private *dev_priv,
+                                      struct vmw_sw_context *sw_context,
+                                      SVGA3dCmdHeader *header)
+{
+       struct vmw_resource_val_node *ctx_node = sw_context->dx_ctx_node;
+       struct vmw_ctx_bindinfo_ib binding;
+       struct vmw_resource_val_node *res_node;
+       struct {
+               SVGA3dCmdHeader header;
+               SVGA3dCmdDXSetIndexBuffer body;
+       } *cmd;
+       int ret;
+
+       if (unlikely(ctx_node == NULL)) {
+               DRM_ERROR("DX Context not set.\n");
+               return -EINVAL;
+       }
+
+       cmd = container_of(header, typeof(*cmd), header);
+       ret = vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface,
+                               user_surface_converter,
+                               &cmd->body.sid, &res_node);
+       if (unlikely(ret != 0))
+               return ret;
+
+       binding.bi.ctx = ctx_node->res;
+       binding.bi.res = ((res_node) ? res_node->res : NULL);
+       binding.bi.bt = vmw_ctx_binding_ib;
+       binding.offset = cmd->body.offset;
+       binding.format = cmd->body.format;
+
+       vmw_binding_add(ctx_node->staged_bindings, &binding.bi, 0, 0);
+
+       return 0;
+}
+
+/**
+ * vmw_cmd_dx_set_rendertarget - Validate an
+ * SVGA_3D_CMD_DX_SET_RENDERTARGETS command
+ *
+ * @dev_priv: Pointer to a device private struct.
+ * @sw_context: The software context being used for this batch.
+ * @header: Pointer to the command header in the command stream.
+ */
+static int vmw_cmd_dx_set_rendertargets(struct vmw_private *dev_priv,
+                                       struct vmw_sw_context *sw_context,
+                                       SVGA3dCmdHeader *header)
+{
+       struct {
+               SVGA3dCmdHeader header;
+               SVGA3dCmdDXSetRenderTargets body;
+       } *cmd = container_of(header, typeof(*cmd), header);
+       int ret;
+       u32 num_rt_view = (cmd->header.size - sizeof(cmd->body)) /
+               sizeof(SVGA3dRenderTargetViewId);
+
+       if (num_rt_view > SVGA3D_MAX_SIMULTANEOUS_RENDER_TARGETS) {
+               DRM_ERROR("Invalid DX Rendertarget binding.\n");
+               return -EINVAL;
+       }
+
+       ret = vmw_view_bindings_add(sw_context, vmw_view_ds,
+                                   vmw_ctx_binding_ds, 0,
+                                   &cmd->body.depthStencilViewId, 1, 0);
+       if (ret)
+               return ret;
+
+       return vmw_view_bindings_add(sw_context, vmw_view_rt,
+                                    vmw_ctx_binding_dx_rt, 0,
+                                    (void *)&cmd[1], num_rt_view, 0);
+}
+
+/**
+ * vmw_cmd_dx_clear_rendertarget_view - Validate an
+ * SVGA_3D_CMD_DX_CLEAR_RENDERTARGET_VIEW command
+ *
+ * @dev_priv: Pointer to a device private struct.
+ * @sw_context: The software context being used for this batch.
+ * @header: Pointer to the command header in the command stream.
+ */
+static int vmw_cmd_dx_clear_rendertarget_view(struct vmw_private *dev_priv,
+                                             struct vmw_sw_context *sw_context,
+                                             SVGA3dCmdHeader *header)
+{
+       struct {
+               SVGA3dCmdHeader header;
+               SVGA3dCmdDXClearRenderTargetView body;
+       } *cmd = container_of(header, typeof(*cmd), header);
+
+       return vmw_view_id_val_add(sw_context, vmw_view_rt,
+                                  cmd->body.renderTargetViewId);
+}
+
+/**
+ * vmw_cmd_dx_clear_rendertarget_view - Validate an
+ * SVGA_3D_CMD_DX_CLEAR_DEPTHSTENCIL_VIEW command
+ *
+ * @dev_priv: Pointer to a device private struct.
+ * @sw_context: The software context being used for this batch.
+ * @header: Pointer to the command header in the command stream.
+ */
+static int vmw_cmd_dx_clear_depthstencil_view(struct vmw_private *dev_priv,
+                                             struct vmw_sw_context *sw_context,
+                                             SVGA3dCmdHeader *header)
+{
+       struct {
+               SVGA3dCmdHeader header;
+               SVGA3dCmdDXClearDepthStencilView body;
+       } *cmd = container_of(header, typeof(*cmd), header);
+
+       return vmw_view_id_val_add(sw_context, vmw_view_ds,
+                                  cmd->body.depthStencilViewId);
+}
+
+static int vmw_cmd_dx_view_define(struct vmw_private *dev_priv,
+                                 struct vmw_sw_context *sw_context,
+                                 SVGA3dCmdHeader *header)
+{
+       struct vmw_resource_val_node *ctx_node = sw_context->dx_ctx_node;
+       struct vmw_resource_val_node *srf_node;
+       struct vmw_resource *res;
+       enum vmw_view_type view_type;
+       int ret;
+       /*
+        * This is based on the fact that all affected define commands have
+        * the same initial command body layout.
+        */
+       struct {
+               SVGA3dCmdHeader header;
+               uint32 defined_id;
+               uint32 sid;
+       } *cmd;
+
+       if (unlikely(ctx_node == NULL)) {
+               DRM_ERROR("DX Context not set.\n");
+               return -EINVAL;
+       }
+
+       view_type = vmw_view_cmd_to_type(header->id);
+       cmd = container_of(header, typeof(*cmd), header);
+       ret = vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface,
+                               user_surface_converter,
+                               &cmd->sid, &srf_node);
+       if (unlikely(ret != 0))
+               return ret;
+
+       res = vmw_context_cotable(ctx_node->res, vmw_view_cotables[view_type]);
+       ret = vmw_cotable_notify(res, cmd->defined_id);
+       vmw_resource_unreference(&res);
+       if (unlikely(ret != 0))
+               return ret;
+
+       return vmw_view_add(sw_context->man,
+                           ctx_node->res,
+                           srf_node->res,
+                           view_type,
+                           cmd->defined_id,
+                           header,
+                           header->size + sizeof(*header),
+                           &sw_context->staged_cmd_res);
+}
+
+/**
+ * vmw_cmd_dx_set_so_targets - Validate an
+ * SVGA_3D_CMD_DX_SET_SOTARGETS command.
+ *
+ * @dev_priv: Pointer to a device private struct.
+ * @sw_context: The software context being used for this batch.
+ * @header: Pointer to the command header in the command stream.
+ */
+static int vmw_cmd_dx_set_so_targets(struct vmw_private *dev_priv,
+                                    struct vmw_sw_context *sw_context,
+                                    SVGA3dCmdHeader *header)
+{
+       struct vmw_resource_val_node *ctx_node = sw_context->dx_ctx_node;
+       struct vmw_ctx_bindinfo_so binding;
+       struct vmw_resource_val_node *res_node;
+       struct {
+               SVGA3dCmdHeader header;
+               SVGA3dCmdDXSetSOTargets body;
+               SVGA3dSoTarget targets[];
+       } *cmd;
+       int i, ret, num;
+
+       if (unlikely(ctx_node == NULL)) {
+               DRM_ERROR("DX Context not set.\n");
+               return -EINVAL;
+       }
+
+       cmd = container_of(header, typeof(*cmd), header);
+       num = (cmd->header.size - sizeof(cmd->body)) /
+               sizeof(SVGA3dSoTarget);
+
+       if (num > SVGA3D_DX_MAX_SOTARGETS) {
+               DRM_ERROR("Invalid DX SO binding.\n");
+               return -EINVAL;
+       }
+
+       for (i = 0; i < num; i++) {
+               ret = vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface,
+                                       user_surface_converter,
+                                       &cmd->targets[i].sid, &res_node);
+               if (unlikely(ret != 0))
+                       return ret;
+
+               binding.bi.ctx = ctx_node->res;
+               binding.bi.res = ((res_node) ? res_node->res : NULL);
+               binding.bi.bt = vmw_ctx_binding_so,
+               binding.offset = cmd->targets[i].offset;
+               binding.size = cmd->targets[i].sizeInBytes;
+               binding.slot = i;
+
+               vmw_binding_add(ctx_node->staged_bindings, &binding.bi,
+                               0, binding.slot);
+       }
+
+       return 0;
+}
+
+static int vmw_cmd_dx_so_define(struct vmw_private *dev_priv,
+                               struct vmw_sw_context *sw_context,
+                               SVGA3dCmdHeader *header)
+{
+       struct vmw_resource_val_node *ctx_node = sw_context->dx_ctx_node;
+       struct vmw_resource *res;
+       /*
+        * This is based on the fact that all affected define commands have
+        * the same initial command body layout.
+        */
+       struct {
+               SVGA3dCmdHeader header;
+               uint32 defined_id;
+       } *cmd;
+       enum vmw_so_type so_type;
+       int ret;
+
+       if (unlikely(ctx_node == NULL)) {
+               DRM_ERROR("DX Context not set.\n");
+               return -EINVAL;
+       }
+
+       so_type = vmw_so_cmd_to_type(header->id);
+       res = vmw_context_cotable(ctx_node->res, vmw_so_cotables[so_type]);
+       cmd = container_of(header, typeof(*cmd), header);
+       ret = vmw_cotable_notify(res, cmd->defined_id);
+       vmw_resource_unreference(&res);
+
+       return ret;
+}
+
+/**
+ * vmw_cmd_dx_check_subresource - Validate an
+ * SVGA_3D_CMD_DX_[X]_SUBRESOURCE command
+ *
+ * @dev_priv: Pointer to a device private struct.
+ * @sw_context: The software context being used for this batch.
+ * @header: Pointer to the command header in the command stream.
+ */
+static int vmw_cmd_dx_check_subresource(struct vmw_private *dev_priv,
+                                       struct vmw_sw_context *sw_context,
+                                       SVGA3dCmdHeader *header)
+{
+       struct {
+               SVGA3dCmdHeader header;
+               union {
+                       SVGA3dCmdDXReadbackSubResource r_body;
+                       SVGA3dCmdDXInvalidateSubResource i_body;
+                       SVGA3dCmdDXUpdateSubResource u_body;
+                       SVGA3dSurfaceId sid;
+               };
+       } *cmd;
+
+       BUILD_BUG_ON(offsetof(typeof(*cmd), r_body.sid) !=
+                    offsetof(typeof(*cmd), sid));
+       BUILD_BUG_ON(offsetof(typeof(*cmd), i_body.sid) !=
+                    offsetof(typeof(*cmd), sid));
+       BUILD_BUG_ON(offsetof(typeof(*cmd), u_body.sid) !=
+                    offsetof(typeof(*cmd), sid));
+
+       cmd = container_of(header, typeof(*cmd), header);
+
+       return vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface,
+                                user_surface_converter,
+                                &cmd->sid, NULL);
+}
+
+static int vmw_cmd_dx_cid_check(struct vmw_private *dev_priv,
+                               struct vmw_sw_context *sw_context,
+                               SVGA3dCmdHeader *header)
+{
+       struct vmw_resource_val_node *ctx_node = sw_context->dx_ctx_node;
+
+       if (unlikely(ctx_node == NULL)) {
+               DRM_ERROR("DX Context not set.\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/**
+ * vmw_cmd_dx_view_remove - validate a view remove command and
+ * schedule the view resource for removal.
+ *
+ * @dev_priv: Pointer to a device private struct.
+ * @sw_context: The software context being used for this batch.
+ * @header: Pointer to the command header in the command stream.
+ *
+ * Check that the view exists, and if it was not created using this
+ * command batch, make sure it's validated (present in the device) so that
+ * the remove command will not confuse the device.
+ */
+static int vmw_cmd_dx_view_remove(struct vmw_private *dev_priv,
+                                 struct vmw_sw_context *sw_context,
+                                 SVGA3dCmdHeader *header)
+{
+       struct vmw_resource_val_node *ctx_node = sw_context->dx_ctx_node;
+       struct {
+               SVGA3dCmdHeader header;
+               union vmw_view_destroy body;
+       } *cmd = container_of(header, typeof(*cmd), header);
+       enum vmw_view_type view_type = vmw_view_cmd_to_type(header->id);
+       struct vmw_resource *view;
+       int ret;
+
+       if (!ctx_node) {
+               DRM_ERROR("DX Context not set.\n");
+               return -EINVAL;
        }
 
-       bi.ctx = ctx_node->res;
-       bi.res = res_node ? res_node->res : NULL;
-       bi.bt = vmw_ctx_binding_shader;
-       bi.i1.shader_type = cmd->body.type;
-       return vmw_context_binding_add(ctx_node->staged_bindings, &bi);
+       ret = vmw_view_remove(sw_context->man,
+                             cmd->body.view_id, view_type,
+                             &sw_context->staged_cmd_res,
+                             &view);
+       if (ret || !view)
+               return ret;
+
+       /*
+        * Add view to the validate list iff it was not created using this
+        * command batch.
+        */
+       return vmw_view_res_val_add(sw_context, view);
 }
 
 /**
- * vmw_cmd_set_shader_const - Validate an SVGA_3D_CMD_SET_SHADER_CONST
+ * vmw_cmd_dx_define_shader - Validate an SVGA_3D_CMD_DX_DEFINE_SHADER
  * command
  *
  * @dev_priv: Pointer to a device private struct.
  * @sw_context: The software context being used for this batch.
  * @header: Pointer to the command header in the command stream.
  */
-static int vmw_cmd_set_shader_const(struct vmw_private *dev_priv,
+static int vmw_cmd_dx_define_shader(struct vmw_private *dev_priv,
                                    struct vmw_sw_context *sw_context,
                                    SVGA3dCmdHeader *header)
 {
-       struct vmw_set_shader_const_cmd {
+       struct vmw_resource_val_node *ctx_node = sw_context->dx_ctx_node;
+       struct vmw_resource *res;
+       struct {
                SVGA3dCmdHeader header;
-               SVGA3dCmdSetShaderConst body;
-       } *cmd;
+               SVGA3dCmdDXDefineShader body;
+       } *cmd = container_of(header, typeof(*cmd), header);
        int ret;
 
-       cmd = container_of(header, struct vmw_set_shader_const_cmd,
-                          header);
+       if (!ctx_node) {
+               DRM_ERROR("DX Context not set.\n");
+               return -EINVAL;
+       }
 
-       ret = vmw_cmd_res_check(dev_priv, sw_context, vmw_res_context,
-                               user_context_converter, &cmd->body.cid,
-                               NULL);
-       if (unlikely(ret != 0))
+       res = vmw_context_cotable(ctx_node->res, SVGA_COTABLE_DXSHADER);
+       ret = vmw_cotable_notify(res, cmd->body.shaderId);
+       vmw_resource_unreference(&res);
+       if (ret)
                return ret;
 
-       if (dev_priv->has_mob)
-               header->id = SVGA_3D_CMD_SET_GB_SHADERCONSTS_INLINE;
+       return vmw_dx_shader_add(sw_context->man, ctx_node->res,
+                                cmd->body.shaderId, cmd->body.type,
+                                &sw_context->staged_cmd_res);
+}
 
-       return 0;
+/**
+ * vmw_cmd_dx_destroy_shader - Validate an SVGA_3D_CMD_DX_DESTROY_SHADER
+ * command
+ *
+ * @dev_priv: Pointer to a device private struct.
+ * @sw_context: The software context being used for this batch.
+ * @header: Pointer to the command header in the command stream.
+ */
+static int vmw_cmd_dx_destroy_shader(struct vmw_private *dev_priv,
+                                    struct vmw_sw_context *sw_context,
+                                    SVGA3dCmdHeader *header)
+{
+       struct vmw_resource_val_node *ctx_node = sw_context->dx_ctx_node;
+       struct {
+               SVGA3dCmdHeader header;
+               SVGA3dCmdDXDestroyShader body;
+       } *cmd = container_of(header, typeof(*cmd), header);
+       int ret;
+
+       if (!ctx_node) {
+               DRM_ERROR("DX Context not set.\n");
+               return -EINVAL;
+       }
+
+       ret = vmw_shader_remove(sw_context->man, cmd->body.shaderId, 0,
+                               &sw_context->staged_cmd_res);
+       if (ret)
+               DRM_ERROR("Could not find shader to remove.\n");
+
+       return ret;
 }
 
 /**
- * vmw_cmd_bind_gb_shader - Validate an SVGA_3D_CMD_BIND_GB_SHADER
+ * vmw_cmd_dx_bind_shader - Validate an SVGA_3D_CMD_DX_BIND_SHADER
  * command
  *
  * @dev_priv: Pointer to a device private struct.
  * @sw_context: The software context being used for this batch.
  * @header: Pointer to the command header in the command stream.
  */
-static int vmw_cmd_bind_gb_shader(struct vmw_private *dev_priv,
+static int vmw_cmd_dx_bind_shader(struct vmw_private *dev_priv,
                                  struct vmw_sw_context *sw_context,
                                  SVGA3dCmdHeader *header)
 {
-       struct vmw_bind_gb_shader_cmd {
+       struct vmw_resource_val_node *ctx_node;
+       struct vmw_resource_val_node *res_node;
+       struct vmw_resource *res;
+       struct {
                SVGA3dCmdHeader header;
-               SVGA3dCmdBindGBShader body;
-       } *cmd;
+               SVGA3dCmdDXBindShader body;
+       } *cmd = container_of(header, typeof(*cmd), header);
+       int ret;
 
-       cmd = container_of(header, struct vmw_bind_gb_shader_cmd,
-                          header);
+       if (cmd->body.cid != SVGA3D_INVALID_ID) {
+               ret = vmw_cmd_res_check(dev_priv, sw_context, vmw_res_context,
+                                       user_context_converter,
+                                       &cmd->body.cid, &ctx_node);
+               if (ret)
+                       return ret;
+       } else {
+               ctx_node = sw_context->dx_ctx_node;
+               if (!ctx_node) {
+                       DRM_ERROR("DX Context not set.\n");
+                       return -EINVAL;
+               }
+       }
 
-       return vmw_cmd_switch_backup(dev_priv, sw_context, vmw_res_shader,
-                                    user_shader_converter,
-                                    &cmd->body.shid, &cmd->body.mobid,
-                                    cmd->body.offsetInBytes);
+       res = vmw_shader_lookup(vmw_context_res_man(ctx_node->res),
+                               cmd->body.shid, 0);
+       if (IS_ERR(res)) {
+               DRM_ERROR("Could not find shader to bind.\n");
+               return PTR_ERR(res);
+       }
+
+       ret = vmw_resource_val_add(sw_context, res, &res_node);
+       if (ret) {
+               DRM_ERROR("Error creating resource validation node.\n");
+               goto out_unref;
+       }
+
+
+       ret = vmw_cmd_res_switch_backup(dev_priv, sw_context, res_node,
+                                       &cmd->body.mobid,
+                                       cmd->body.offsetInBytes);
+out_unref:
+       vmw_resource_unreference(&res);
+
+       return ret;
 }
 
 static int vmw_cmd_check_not_3d(struct vmw_private *dev_priv,
@@ -1849,7 +3016,7 @@ static int vmw_cmd_check_not_3d(struct vmw_private *dev_priv,
        uint32_t size_remaining = *size;
        uint32_t cmd_id;
 
-       cmd_id = le32_to_cpu(((uint32_t *)buf)[0]);
+       cmd_id = ((uint32_t *)buf)[0];
        switch (cmd_id) {
        case SVGA_CMD_UPDATE:
                *size = sizeof(uint32_t) + sizeof(SVGAFifoCmdUpdate);
@@ -1980,7 +3147,7 @@ static const struct vmw_cmd_entry vmw_cmd_entries[SVGA_3D_CMD_MAX] = {
                    false, false, true),
        VMW_CMD_DEF(SVGA_3D_CMD_DESTROY_GB_MOB, &vmw_cmd_invalid,
                    false, false, true),
-       VMW_CMD_DEF(SVGA_3D_CMD_REDEFINE_GB_MOB, &vmw_cmd_invalid,
+       VMW_CMD_DEF(SVGA_3D_CMD_REDEFINE_GB_MOB64, &vmw_cmd_invalid,
                    false, false, true),
        VMW_CMD_DEF(SVGA_3D_CMD_UPDATE_GB_MOB_MAPPING, &vmw_cmd_invalid,
                    false, false, true),
@@ -2051,7 +3218,147 @@ static const struct vmw_cmd_entry vmw_cmd_entries[SVGA_3D_CMD_MAX] = {
        VMW_CMD_DEF(SVGA_3D_CMD_INVALIDATE_GB_IMAGE_PARTIAL, &vmw_cmd_invalid,
                    false, false, true),
        VMW_CMD_DEF(SVGA_3D_CMD_SET_GB_SHADERCONSTS_INLINE, &vmw_cmd_cid_check,
-                   true, false, true)
+                   true, false, true),
+       VMW_CMD_DEF(SVGA_3D_CMD_GB_SCREEN_DMA, &vmw_cmd_invalid,
+                   false, false, true),
+       VMW_CMD_DEF(SVGA_3D_CMD_BIND_GB_SURFACE_WITH_PITCH, &vmw_cmd_invalid,
+                   false, false, true),
+       VMW_CMD_DEF(SVGA_3D_CMD_GB_MOB_FENCE, &vmw_cmd_invalid,
+                   false, false, true),
+       VMW_CMD_DEF(SVGA_3D_CMD_DEFINE_GB_SURFACE_V2, &vmw_cmd_invalid,
+                   false, false, true),
+
+       /*
+        * DX commands
+        */
+       VMW_CMD_DEF(SVGA_3D_CMD_DX_DEFINE_CONTEXT, &vmw_cmd_invalid,
+                   false, false, true),
+       VMW_CMD_DEF(SVGA_3D_CMD_DX_DESTROY_CONTEXT, &vmw_cmd_invalid,
+                   false, false, true),
+       VMW_CMD_DEF(SVGA_3D_CMD_DX_BIND_CONTEXT, &vmw_cmd_invalid,
+                   false, false, true),
+       VMW_CMD_DEF(SVGA_3D_CMD_DX_READBACK_CONTEXT, &vmw_cmd_invalid,
+                   false, false, true),
+       VMW_CMD_DEF(SVGA_3D_CMD_DX_INVALIDATE_CONTEXT, &vmw_cmd_invalid,
+                   false, false, true),
+       VMW_CMD_DEF(SVGA_3D_CMD_DX_SET_SINGLE_CONSTANT_BUFFER,
+                   &vmw_cmd_dx_set_single_constant_buffer, true, false, true),
+       VMW_CMD_DEF(SVGA_3D_CMD_DX_SET_SHADER_RESOURCES,
+                   &vmw_cmd_dx_set_shader_res, true, false, true),
+       VMW_CMD_DEF(SVGA_3D_CMD_DX_SET_SHADER, &vmw_cmd_dx_set_shader,
+                   true, false, true),
+       VMW_CMD_DEF(SVGA_3D_CMD_DX_SET_SAMPLERS, &vmw_cmd_dx_cid_check,
+                   true, false, true),
+       VMW_CMD_DEF(SVGA_3D_CMD_DX_DRAW, &vmw_cmd_dx_cid_check,
+                   true, false, true),
+       VMW_CMD_DEF(SVGA_3D_CMD_DX_DRAW_INDEXED, &vmw_cmd_dx_cid_check,
+                   true, false, true),
+       VMW_CMD_DEF(SVGA_3D_CMD_DX_DRAW_INSTANCED, &vmw_cmd_dx_cid_check,
+                   true, false, true),
+       VMW_CMD_DEF(SVGA_3D_CMD_DX_DRAW_INDEXED_INSTANCED,
+                   &vmw_cmd_dx_cid_check, true, false, true),
+       VMW_CMD_DEF(SVGA_3D_CMD_DX_DRAW_AUTO, &vmw_cmd_dx_cid_check,
+                   true, false, true),
+       VMW_CMD_DEF(SVGA_3D_CMD_DX_SET_VERTEX_BUFFERS,
+                   &vmw_cmd_dx_set_vertex_buffers, true, false, true),
+       VMW_CMD_DEF(SVGA_3D_CMD_DX_SET_INDEX_BUFFER,
+                   &vmw_cmd_dx_set_index_buffer, true, false, true),
+       VMW_CMD_DEF(SVGA_3D_CMD_DX_SET_RENDERTARGETS,
+                   &vmw_cmd_dx_set_rendertargets, true, false, true),
+       VMW_CMD_DEF(SVGA_3D_CMD_DX_SET_BLEND_STATE, &vmw_cmd_dx_cid_check,
+                   true, false, true),
+       VMW_CMD_DEF(SVGA_3D_CMD_DX_SET_DEPTHSTENCIL_STATE,
+                   &vmw_cmd_dx_cid_check, true, false, true),
+       VMW_CMD_DEF(SVGA_3D_CMD_DX_SET_RASTERIZER_STATE,
+                   &vmw_cmd_dx_cid_check, true, false, true),
+       VMW_CMD_DEF(SVGA_3D_CMD_DX_DEFINE_QUERY, &vmw_cmd_dx_define_query,
+                   true, false, true),
+       VMW_CMD_DEF(SVGA_3D_CMD_DX_DESTROY_QUERY, &vmw_cmd_ok,
+                   true, false, true),
+       VMW_CMD_DEF(SVGA_3D_CMD_DX_BIND_QUERY, &vmw_cmd_dx_bind_query,
+                   true, false, true),
+       VMW_CMD_DEF(SVGA_3D_CMD_DX_SET_QUERY_OFFSET,
+                   &vmw_cmd_ok, true, false, true),
+       VMW_CMD_DEF(SVGA_3D_CMD_DX_BEGIN_QUERY, &vmw_cmd_ok,
+                   true, false, true),
+       VMW_CMD_DEF(SVGA_3D_CMD_DX_END_QUERY, &vmw_cmd_ok,
+                   true, false, true),
+       VMW_CMD_DEF(SVGA_3D_CMD_DX_READBACK_QUERY, &vmw_cmd_invalid,
+                   true, false, true),
+       VMW_CMD_DEF(SVGA_3D_CMD_DX_SET_PREDICATION, &vmw_cmd_invalid,
+                   true, false, true),
+       VMW_CMD_DEF(SVGA_3D_CMD_DX_SET_VIEWPORTS, &vmw_cmd_dx_cid_check,
+                   true, false, true),
+       VMW_CMD_DEF(SVGA_3D_CMD_DX_SET_SCISSORRECTS, &vmw_cmd_dx_cid_check,
+                   true, false, true),
+       VMW_CMD_DEF(SVGA_3D_CMD_DX_CLEAR_RENDERTARGET_VIEW,
+                   &vmw_cmd_dx_clear_rendertarget_view, true, false, true),
+       VMW_CMD_DEF(SVGA_3D_CMD_DX_CLEAR_DEPTHSTENCIL_VIEW,
+                   &vmw_cmd_dx_clear_depthstencil_view, true, false, true),
+       VMW_CMD_DEF(SVGA_3D_CMD_DX_PRED_COPY, &vmw_cmd_invalid,
+                   true, false, true),
+       VMW_CMD_DEF(SVGA_3D_CMD_DX_GENMIPS, &vmw_cmd_invalid,
+                   true, false, true),
+       VMW_CMD_DEF(SVGA_3D_CMD_DX_UPDATE_SUBRESOURCE,
+                   &vmw_cmd_dx_check_subresource, true, false, true),
+       VMW_CMD_DEF(SVGA_3D_CMD_DX_READBACK_SUBRESOURCE,
+                   &vmw_cmd_dx_check_subresource, true, false, true),
+       VMW_CMD_DEF(SVGA_3D_CMD_DX_INVALIDATE_SUBRESOURCE,
+                   &vmw_cmd_dx_check_subresource, true, false, true),
+       VMW_CMD_DEF(SVGA_3D_CMD_DX_DEFINE_SHADERRESOURCE_VIEW,
+                   &vmw_cmd_dx_view_define, true, false, true),
+       VMW_CMD_DEF(SVGA_3D_CMD_DX_DESTROY_SHADERRESOURCE_VIEW,
+                   &vmw_cmd_dx_view_remove, true, false, true),
+       VMW_CMD_DEF(SVGA_3D_CMD_DX_DEFINE_RENDERTARGET_VIEW,
+                   &vmw_cmd_dx_view_define, true, false, true),
+       VMW_CMD_DEF(SVGA_3D_CMD_DX_DESTROY_RENDERTARGET_VIEW,
+                   &vmw_cmd_dx_view_remove, true, false, true),
+       VMW_CMD_DEF(SVGA_3D_CMD_DX_DEFINE_DEPTHSTENCIL_VIEW,
+                   &vmw_cmd_dx_view_define, true, false, true),
+       VMW_CMD_DEF(SVGA_3D_CMD_DX_DESTROY_DEPTHSTENCIL_VIEW,
+                   &vmw_cmd_dx_view_remove, true, false, true),
+       VMW_CMD_DEF(SVGA_3D_CMD_DX_DEFINE_ELEMENTLAYOUT,
+                   &vmw_cmd_dx_so_define, true, false, true),
+       VMW_CMD_DEF(SVGA_3D_CMD_DX_DESTROY_ELEMENTLAYOUT,
+                   &vmw_cmd_dx_cid_check, true, false, true),
+       VMW_CMD_DEF(SVGA_3D_CMD_DX_DEFINE_BLEND_STATE,
+                   &vmw_cmd_dx_so_define, true, false, true),
+       VMW_CMD_DEF(SVGA_3D_CMD_DX_DESTROY_BLEND_STATE,
+                   &vmw_cmd_dx_cid_check, true, false, true),
+       VMW_CMD_DEF(SVGA_3D_CMD_DX_DEFINE_DEPTHSTENCIL_STATE,
+                   &vmw_cmd_dx_so_define, true, false, true),
+       VMW_CMD_DEF(SVGA_3D_CMD_DX_DESTROY_DEPTHSTENCIL_STATE,
+                   &vmw_cmd_dx_cid_check, true, false, true),
+       VMW_CMD_DEF(SVGA_3D_CMD_DX_DEFINE_RASTERIZER_STATE,
+                   &vmw_cmd_dx_so_define, true, false, true),
+       VMW_CMD_DEF(SVGA_3D_CMD_DX_DESTROY_RASTERIZER_STATE,
+                   &vmw_cmd_dx_cid_check, true, false, true),
+       VMW_CMD_DEF(SVGA_3D_CMD_DX_DEFINE_SAMPLER_STATE,
+                   &vmw_cmd_dx_so_define, true, false, true),
+       VMW_CMD_DEF(SVGA_3D_CMD_DX_DESTROY_SAMPLER_STATE,
+                   &vmw_cmd_dx_cid_check, true, false, true),
+       VMW_CMD_DEF(SVGA_3D_CMD_DX_DEFINE_SHADER,
+                   &vmw_cmd_dx_define_shader, true, false, true),
+       VMW_CMD_DEF(SVGA_3D_CMD_DX_DESTROY_SHADER,
+                   &vmw_cmd_dx_destroy_shader, true, false, true),
+       VMW_CMD_DEF(SVGA_3D_CMD_DX_BIND_SHADER,
+                   &vmw_cmd_dx_bind_shader, true, false, true),
+       VMW_CMD_DEF(SVGA_3D_CMD_DX_DEFINE_STREAMOUTPUT,
+                   &vmw_cmd_dx_so_define, true, false, true),
+       VMW_CMD_DEF(SVGA_3D_CMD_DX_DESTROY_STREAMOUTPUT,
+                   &vmw_cmd_dx_cid_check, true, false, true),
+       VMW_CMD_DEF(SVGA_3D_CMD_DX_SET_STREAMOUTPUT, &vmw_cmd_dx_cid_check,
+                   true, false, true),
+       VMW_CMD_DEF(SVGA_3D_CMD_DX_SET_SOTARGETS,
+                   &vmw_cmd_dx_set_so_targets, true, false, true),
+       VMW_CMD_DEF(SVGA_3D_CMD_DX_SET_INPUT_LAYOUT,
+                   &vmw_cmd_dx_cid_check, true, false, true),
+       VMW_CMD_DEF(SVGA_3D_CMD_DX_SET_TOPOLOGY,
+                   &vmw_cmd_dx_cid_check, true, false, true),
+       VMW_CMD_DEF(SVGA_3D_CMD_DX_BUFFER_COPY,
+                   &vmw_cmd_buffer_copy_check, true, false, true),
+       VMW_CMD_DEF(SVGA_3D_CMD_DX_PRED_COPY_REGION,
+                   &vmw_cmd_pred_copy_check, true, false, true),
 };
 
 static int vmw_cmd_check(struct vmw_private *dev_priv,
@@ -2065,14 +3372,14 @@ static int vmw_cmd_check(struct vmw_private *dev_priv,
        const struct vmw_cmd_entry *entry;
        bool gb = dev_priv->capabilities & SVGA_CAP_GBOBJECTS;
 
-       cmd_id = le32_to_cpu(((uint32_t *)buf)[0]);
+       cmd_id = ((uint32_t *)buf)[0];
        /* Handle any none 3D commands */
        if (unlikely(cmd_id < SVGA_CMD_MAX))
                return vmw_cmd_check_not_3d(dev_priv, sw_context, buf, size);
 
 
-       cmd_id = le32_to_cpu(header->id);
-       *size = le32_to_cpu(header->size) + sizeof(SVGA3dCmdHeader);
+       cmd_id = header->id;
+       *size = header->size + sizeof(SVGA3dCmdHeader);
 
        cmd_id -= SVGA_3D_CMD_BASE;
        if (unlikely(*size > size_remaining))
@@ -2184,7 +3491,8 @@ static void vmw_apply_relocations(struct vmw_sw_context *sw_context)
  *
  * @list: The resource list.
  */
-static void vmw_resource_list_unreference(struct list_head *list)
+static void vmw_resource_list_unreference(struct vmw_sw_context *sw_context,
+                                         struct list_head *list)
 {
        struct vmw_resource_val_node *val, *val_next;
 
@@ -2195,8 +3503,15 @@ static void vmw_resource_list_unreference(struct list_head *list)
        list_for_each_entry_safe(val, val_next, list, head) {
                list_del_init(&val->head);
                vmw_resource_unreference(&val->res);
-               if (unlikely(val->staged_bindings))
-                       kfree(val->staged_bindings);
+
+               if (val->staged_bindings) {
+                       if (val->staged_bindings != sw_context->staged_bindings)
+                               vmw_binding_state_free(val->staged_bindings);
+                       else
+                               sw_context->staged_bindings_inuse = false;
+                       val->staged_bindings = NULL;
+               }
+
                kfree(val);
        }
 }
@@ -2222,24 +3537,21 @@ static void vmw_clear_validations(struct vmw_sw_context *sw_context)
                (void) drm_ht_remove_item(&sw_context->res_ht, &val->hash);
 }
 
-static int vmw_validate_single_buffer(struct vmw_private *dev_priv,
-                                     struct ttm_buffer_object *bo,
-                                     bool validate_as_mob)
+int vmw_validate_single_buffer(struct vmw_private *dev_priv,
+                              struct ttm_buffer_object *bo,
+                              bool interruptible,
+                              bool validate_as_mob)
 {
+       struct vmw_dma_buffer *vbo = container_of(bo, struct vmw_dma_buffer,
+                                                 base);
        int ret;
 
-
-       /*
-        * Don't validate pinned buffers.
-        */
-
-       if (bo == dev_priv->pinned_bo ||
-           (bo == dev_priv->dummy_query_bo &&
-            dev_priv->dummy_query_bo_pinned))
+       if (vbo->pin_count > 0)
                return 0;
 
        if (validate_as_mob)
-               return ttm_bo_validate(bo, &vmw_mob_placement, true, false);
+               return ttm_bo_validate(bo, &vmw_mob_placement, interruptible,
+                                      false);
 
        /**
         * Put BO in VRAM if there is space, otherwise as a GMR.
@@ -2248,7 +3560,8 @@ static int vmw_validate_single_buffer(struct vmw_private *dev_priv,
         * used as a GMR, this will return -ENOMEM.
         */
 
-       ret = ttm_bo_validate(bo, &vmw_vram_gmr_placement, true, false);
+       ret = ttm_bo_validate(bo, &vmw_vram_gmr_placement, interruptible,
+                             false);
        if (likely(ret == 0 || ret == -ERESTARTSYS))
                return ret;
 
@@ -2257,8 +3570,7 @@ static int vmw_validate_single_buffer(struct vmw_private *dev_priv,
         * previous contents.
         */
 
-       DRM_INFO("Falling through to VRAM.\n");
-       ret = ttm_bo_validate(bo, &vmw_vram_placement, true, false);
+       ret = ttm_bo_validate(bo, &vmw_vram_placement, interruptible, false);
        return ret;
 }
 
@@ -2270,6 +3582,7 @@ static int vmw_validate_buffers(struct vmw_private *dev_priv,
 
        list_for_each_entry(entry, &sw_context->validate_nodes, base.head) {
                ret = vmw_validate_single_buffer(dev_priv, entry->base.bo,
+                                                true,
                                                 entry->validate_as_mob);
                if (unlikely(ret != 0))
                        return ret;
@@ -2417,7 +3730,164 @@ vmw_execbuf_copy_fence_user(struct vmw_private *dev_priv,
        }
 }
 
+/**
+ * vmw_execbuf_submit_fifo - Patch a command batch and submit it using
+ * the fifo.
+ *
+ * @dev_priv: Pointer to a device private structure.
+ * @kernel_commands: Pointer to the unpatched command batch.
+ * @command_size: Size of the unpatched command batch.
+ * @sw_context: Structure holding the relocation lists.
+ *
+ * Side effects: If this function returns 0, then the command batch
+ * pointed to by @kernel_commands will have been modified.
+ */
+static int vmw_execbuf_submit_fifo(struct vmw_private *dev_priv,
+                                  void *kernel_commands,
+                                  u32 command_size,
+                                  struct vmw_sw_context *sw_context)
+{
+       void *cmd;
+
+       if (sw_context->dx_ctx_node)
+               cmd = vmw_fifo_reserve_dx(dev_priv, command_size,
+                                         sw_context->dx_ctx_node->res->id);
+       else
+               cmd = vmw_fifo_reserve(dev_priv, command_size);
+       if (!cmd) {
+               DRM_ERROR("Failed reserving fifo space for commands.\n");
+               return -ENOMEM;
+       }
+
+       vmw_apply_relocations(sw_context);
+       memcpy(cmd, kernel_commands, command_size);
+       vmw_resource_relocations_apply(cmd, &sw_context->res_relocations);
+       vmw_resource_relocations_free(&sw_context->res_relocations);
+       vmw_fifo_commit(dev_priv, command_size);
+
+       return 0;
+}
+
+/**
+ * vmw_execbuf_submit_cmdbuf - Patch a command batch and submit it using
+ * the command buffer manager.
+ *
+ * @dev_priv: Pointer to a device private structure.
+ * @header: Opaque handle to the command buffer allocation.
+ * @command_size: Size of the unpatched command batch.
+ * @sw_context: Structure holding the relocation lists.
+ *
+ * Side effects: If this function returns 0, then the command buffer
+ * represented by @header will have been modified.
+ */
+static int vmw_execbuf_submit_cmdbuf(struct vmw_private *dev_priv,
+                                    struct vmw_cmdbuf_header *header,
+                                    u32 command_size,
+                                    struct vmw_sw_context *sw_context)
+{
+       u32 id = ((sw_context->dx_ctx_node) ? sw_context->dx_ctx_node->res->id :
+                 SVGA3D_INVALID_ID);
+       void *cmd = vmw_cmdbuf_reserve(dev_priv->cman, command_size,
+                                      id, false, header);
+
+       vmw_apply_relocations(sw_context);
+       vmw_resource_relocations_apply(cmd, &sw_context->res_relocations);
+       vmw_resource_relocations_free(&sw_context->res_relocations);
+       vmw_cmdbuf_commit(dev_priv->cman, command_size, header, false);
+
+       return 0;
+}
+
+/**
+ * vmw_execbuf_cmdbuf - Prepare, if possible, a user-space command batch for
+ * submission using a command buffer.
+ *
+ * @dev_priv: Pointer to a device private structure.
+ * @user_commands: User-space pointer to the commands to be submitted.
+ * @command_size: Size of the unpatched command batch.
+ * @header: Out parameter returning the opaque pointer to the command buffer.
+ *
+ * This function checks whether we can use the command buffer manager for
+ * submission and if so, creates a command buffer of suitable size and
+ * copies the user data into that buffer.
+ *
+ * On successful return, the function returns a pointer to the data in the
+ * command buffer and *@header is set to non-NULL.
+ * If command buffers could not be used, the function will return the value
+ * of @kernel_commands on function call. That value may be NULL. In that case,
+ * the value of *@header will be set to NULL.
+ * If an error is encountered, the function will return a pointer error value.
+ * If the function is interrupted by a signal while sleeping, it will return
+ * -ERESTARTSYS casted to a pointer error value.
+ */
+static void *vmw_execbuf_cmdbuf(struct vmw_private *dev_priv,
+                               void __user *user_commands,
+                               void *kernel_commands,
+                               u32 command_size,
+                               struct vmw_cmdbuf_header **header)
+{
+       size_t cmdbuf_size;
+       int ret;
+
+       *header = NULL;
+       if (!dev_priv->cman || kernel_commands)
+               return kernel_commands;
+
+       if (command_size > SVGA_CB_MAX_SIZE) {
+               DRM_ERROR("Command buffer is too large.\n");
+               return ERR_PTR(-EINVAL);
+       }
+
+       /* If possible, add a little space for fencing. */
+       cmdbuf_size = command_size + 512;
+       cmdbuf_size = min_t(size_t, cmdbuf_size, SVGA_CB_MAX_SIZE);
+       kernel_commands = vmw_cmdbuf_alloc(dev_priv->cman, cmdbuf_size,
+                                          true, header);
+       if (IS_ERR(kernel_commands))
+               return kernel_commands;
+
+       ret = copy_from_user(kernel_commands, user_commands,
+                            command_size);
+       if (ret) {
+               DRM_ERROR("Failed copying commands.\n");
+               vmw_cmdbuf_header_free(*header);
+               *header = NULL;
+               return ERR_PTR(-EFAULT);
+       }
+
+       return kernel_commands;
+}
+
+static int vmw_execbuf_tie_context(struct vmw_private *dev_priv,
+                                  struct vmw_sw_context *sw_context,
+                                  uint32_t handle)
+{
+       struct vmw_resource_val_node *ctx_node;
+       struct vmw_resource *res;
+       int ret;
+
+       if (handle == SVGA3D_INVALID_ID)
+               return 0;
+
+       ret = vmw_user_resource_lookup_handle(dev_priv, sw_context->fp->tfile,
+                                             handle, user_context_converter,
+                                             &res);
+       if (unlikely(ret != 0)) {
+               DRM_ERROR("Could not find or user DX context 0x%08x.\n",
+                         (unsigned) handle);
+               return ret;
+       }
+
+       ret = vmw_resource_val_add(sw_context, res, &ctx_node);
+       if (unlikely(ret != 0))
+               goto out_err;
 
+       sw_context->dx_ctx_node = ctx_node;
+       sw_context->man = vmw_context_res_man(res);
+out_err:
+       vmw_resource_unreference(&res);
+       return ret;
+}
 
 int vmw_execbuf_process(struct drm_file *file_priv,
                        struct vmw_private *dev_priv,
@@ -2425,6 +3895,7 @@ int vmw_execbuf_process(struct drm_file *file_priv,
                        void *kernel_commands,
                        uint32_t command_size,
                        uint64_t throttle_us,
+                       uint32_t dx_context_handle,
                        struct drm_vmw_fence_rep __user *user_fence_rep,
                        struct vmw_fence_obj **out_fence)
 {
@@ -2432,18 +3903,33 @@ int vmw_execbuf_process(struct drm_file *file_priv,
        struct vmw_fence_obj *fence = NULL;
        struct vmw_resource *error_resource;
        struct list_head resource_list;
+       struct vmw_cmdbuf_header *header;
        struct ww_acquire_ctx ticket;
        uint32_t handle;
-       void *cmd;
        int ret;
 
+       if (throttle_us) {
+               ret = vmw_wait_lag(dev_priv, &dev_priv->fifo.marker_queue,
+                                  throttle_us);
+
+               if (ret)
+                       return ret;
+       }
+
+       kernel_commands = vmw_execbuf_cmdbuf(dev_priv, user_commands,
+                                            kernel_commands, command_size,
+                                            &header);
+       if (IS_ERR(kernel_commands))
+               return PTR_ERR(kernel_commands);
+
        ret = mutex_lock_interruptible(&dev_priv->cmdbuf_mutex);
-       if (unlikely(ret != 0))
-               return -ERESTARTSYS;
+       if (ret) {
+               ret = -ERESTARTSYS;
+               goto out_free_header;
+       }
 
+       sw_context->kernel = false;
        if (kernel_commands == NULL) {
-               sw_context->kernel = false;
-
                ret = vmw_resize_cmd_bounce(sw_context, command_size);
                if (unlikely(ret != 0))
                        goto out_unlock;
@@ -2458,19 +3944,26 @@ int vmw_execbuf_process(struct drm_file *file_priv,
                        goto out_unlock;
                }
                kernel_commands = sw_context->cmd_bounce;
-       } else
+       } else if (!header)
                sw_context->kernel = true;
 
        sw_context->fp = vmw_fpriv(file_priv);
        sw_context->cur_reloc = 0;
        sw_context->cur_val_buf = 0;
        INIT_LIST_HEAD(&sw_context->resource_list);
+       INIT_LIST_HEAD(&sw_context->ctx_resource_list);
        sw_context->cur_query_bo = dev_priv->pinned_bo;
        sw_context->last_query_ctx = NULL;
        sw_context->needs_post_query_barrier = false;
+       sw_context->dx_ctx_node = NULL;
+       sw_context->dx_query_mob = NULL;
+       sw_context->dx_query_ctx = NULL;
        memset(sw_context->res_cache, 0, sizeof(sw_context->res_cache));
        INIT_LIST_HEAD(&sw_context->validate_nodes);
        INIT_LIST_HEAD(&sw_context->res_relocations);
+       if (sw_context->staged_bindings)
+               vmw_binding_state_reset(sw_context->staged_bindings);
+
        if (!sw_context->res_ht_initialized) {
                ret = drm_ht_create(&sw_context->res_ht, VMW_RES_HT_ORDER);
                if (unlikely(ret != 0))
@@ -2478,10 +3971,24 @@ int vmw_execbuf_process(struct drm_file *file_priv,
                sw_context->res_ht_initialized = true;
        }
        INIT_LIST_HEAD(&sw_context->staged_cmd_res);
-
        INIT_LIST_HEAD(&resource_list);
+       ret = vmw_execbuf_tie_context(dev_priv, sw_context, dx_context_handle);
+       if (unlikely(ret != 0)) {
+               list_splice_init(&sw_context->ctx_resource_list,
+                                &sw_context->resource_list);
+               goto out_err_nores;
+       }
+
        ret = vmw_cmd_check_all(dev_priv, sw_context, kernel_commands,
                                command_size);
+       /*
+        * Merge the resource lists before checking the return status
+        * from vmd_cmd_check_all so that all the open hashtabs will
+        * be handled properly even if vmw_cmd_check_all fails.
+        */
+       list_splice_init(&sw_context->ctx_resource_list,
+                        &sw_context->resource_list);
+
        if (unlikely(ret != 0))
                goto out_err_nores;
 
@@ -2502,14 +4009,6 @@ int vmw_execbuf_process(struct drm_file *file_priv,
        if (unlikely(ret != 0))
                goto out_err;
 
-       if (throttle_us) {
-               ret = vmw_wait_lag(dev_priv, &dev_priv->fifo.marker_queue,
-                                  throttle_us);
-
-               if (unlikely(ret != 0))
-                       goto out_err;
-       }
-
        ret = mutex_lock_interruptible(&dev_priv->binding_mutex);
        if (unlikely(ret != 0)) {
                ret = -ERESTARTSYS;
@@ -2522,21 +4021,17 @@ int vmw_execbuf_process(struct drm_file *file_priv,
                        goto out_unlock_binding;
        }
 
-       cmd = vmw_fifo_reserve(dev_priv, command_size);
-       if (unlikely(cmd == NULL)) {
-               DRM_ERROR("Failed reserving fifo space for commands.\n");
-               ret = -ENOMEM;
-               goto out_unlock_binding;
+       if (!header) {
+               ret = vmw_execbuf_submit_fifo(dev_priv, kernel_commands,
+                                             command_size, sw_context);
+       } else {
+               ret = vmw_execbuf_submit_cmdbuf(dev_priv, header, command_size,
+                                               sw_context);
+               header = NULL;
        }
-
-       vmw_apply_relocations(sw_context);
-       memcpy(cmd, kernel_commands, command_size);
-
-       vmw_resource_relocations_apply(cmd, &sw_context->res_relocations);
-       vmw_resource_relocations_free(&sw_context->res_relocations);
-
-       vmw_fifo_commit(dev_priv, command_size);
        mutex_unlock(&dev_priv->binding_mutex);
+       if (ret)
+               goto out_err;
 
        vmw_query_bo_switch_commit(dev_priv, sw_context);
        ret = vmw_execbuf_fence_commands(file_priv, dev_priv,
@@ -2551,7 +4046,7 @@ int vmw_execbuf_process(struct drm_file *file_priv,
        if (ret != 0)
                DRM_ERROR("Fence submission error. Syncing.\n");
 
-       vmw_resource_list_unreserve(&sw_context->resource_list, false);
+       vmw_resources_unreserve(sw_context, false);
 
        ttm_eu_fence_buffer_objects(&ticket, &sw_context->validate_nodes,
                                    (void *) fence);
@@ -2580,7 +4075,7 @@ int vmw_execbuf_process(struct drm_file *file_priv,
         * Unreference resources outside of the cmdbuf_mutex to
         * avoid deadlocks in resource destruction paths.
         */
-       vmw_resource_list_unreference(&resource_list);
+       vmw_resource_list_unreference(sw_context, &resource_list);
 
        return 0;
 
@@ -2589,7 +4084,7 @@ out_unlock_binding:
 out_err:
        ttm_eu_backoff_reservation(&ticket, &sw_context->validate_nodes);
 out_err_nores:
-       vmw_resource_list_unreserve(&sw_context->resource_list, true);
+       vmw_resources_unreserve(sw_context, true);
        vmw_resource_relocations_free(&sw_context->res_relocations);
        vmw_free_relocations(sw_context);
        vmw_clear_validations(sw_context);
@@ -2607,9 +4102,12 @@ out_unlock:
         * Unreference resources outside of the cmdbuf_mutex to
         * avoid deadlocks in resource destruction paths.
         */
-       vmw_resource_list_unreference(&resource_list);
+       vmw_resource_list_unreference(sw_context, &resource_list);
        if (unlikely(error_resource != NULL))
                vmw_resource_unreference(&error_resource);
+out_free_header:
+       if (header)
+               vmw_cmdbuf_header_free(header);
 
        return ret;
 }
@@ -2628,9 +4126,11 @@ static void vmw_execbuf_unpin_panic(struct vmw_private *dev_priv)
        DRM_ERROR("Can't unpin query buffer. Trying to recover.\n");
 
        (void) vmw_fallback_wait(dev_priv, false, true, 0, false, 10*HZ);
-       vmw_bo_pin(dev_priv->pinned_bo, false);
-       vmw_bo_pin(dev_priv->dummy_query_bo, false);
-       dev_priv->dummy_query_bo_pinned = false;
+       vmw_bo_pin_reserved(dev_priv->pinned_bo, false);
+       if (dev_priv->dummy_query_bo_pinned) {
+               vmw_bo_pin_reserved(dev_priv->dummy_query_bo, false);
+               dev_priv->dummy_query_bo_pinned = false;
+       }
 }
 
 
@@ -2672,11 +4172,11 @@ void __vmw_execbuf_release_pinned_bo(struct vmw_private *dev_priv,
 
        INIT_LIST_HEAD(&validate_list);
 
-       pinned_val.bo = ttm_bo_reference(dev_priv->pinned_bo);
+       pinned_val.bo = ttm_bo_reference(&dev_priv->pinned_bo->base);
        pinned_val.shared = false;
        list_add_tail(&pinned_val.head, &validate_list);
 
-       query_val.bo = ttm_bo_reference(dev_priv->dummy_query_bo);
+       query_val.bo = ttm_bo_reference(&dev_priv->dummy_query_bo->base);
        query_val.shared = false;
        list_add_tail(&query_val.head, &validate_list);
 
@@ -2697,10 +4197,11 @@ void __vmw_execbuf_release_pinned_bo(struct vmw_private *dev_priv,
                dev_priv->query_cid_valid = false;
        }
 
-       vmw_bo_pin(dev_priv->pinned_bo, false);
-       vmw_bo_pin(dev_priv->dummy_query_bo, false);
-       dev_priv->dummy_query_bo_pinned = false;
-
+       vmw_bo_pin_reserved(dev_priv->pinned_bo, false);
+       if (dev_priv->dummy_query_bo_pinned) {
+               vmw_bo_pin_reserved(dev_priv->dummy_query_bo, false);
+               dev_priv->dummy_query_bo_pinned = false;
+       }
        if (fence == NULL) {
                (void) vmw_execbuf_fence_commands(NULL, dev_priv, &lfence,
                                                  NULL);
@@ -2712,7 +4213,9 @@ void __vmw_execbuf_release_pinned_bo(struct vmw_private *dev_priv,
 
        ttm_bo_unref(&query_val.bo);
        ttm_bo_unref(&pinned_val.bo);
-       ttm_bo_unref(&dev_priv->pinned_bo);
+       vmw_dmabuf_unreference(&dev_priv->pinned_bo);
+       DRM_INFO("Dummy query bo pin count: %d\n",
+                dev_priv->dummy_query_bo->pin_count);
 
 out_unlock:
        return;
@@ -2722,7 +4225,7 @@ out_no_emit:
 out_no_reserve:
        ttm_bo_unref(&query_val.bo);
        ttm_bo_unref(&pinned_val.bo);
-       ttm_bo_unref(&dev_priv->pinned_bo);
+       vmw_dmabuf_unreference(&dev_priv->pinned_bo);
 }
 
 /**
@@ -2751,36 +4254,68 @@ void vmw_execbuf_release_pinned_bo(struct vmw_private *dev_priv)
        mutex_unlock(&dev_priv->cmdbuf_mutex);
 }
 
-
-int vmw_execbuf_ioctl(struct drm_device *dev, void *data,
-                     struct drm_file *file_priv)
+int vmw_execbuf_ioctl(struct drm_device *dev, unsigned long data,
+                     struct drm_file *file_priv, size_t size)
 {
        struct vmw_private *dev_priv = vmw_priv(dev);
-       struct drm_vmw_execbuf_arg *arg = (struct drm_vmw_execbuf_arg *)data;
+       struct drm_vmw_execbuf_arg arg;
        int ret;
+       static const size_t copy_offset[] = {
+               offsetof(struct drm_vmw_execbuf_arg, context_handle),
+               sizeof(struct drm_vmw_execbuf_arg)};
+
+       if (unlikely(size < copy_offset[0])) {
+               DRM_ERROR("Invalid command size, ioctl %d\n",
+                         DRM_VMW_EXECBUF);
+               return -EINVAL;
+       }
+
+       if (copy_from_user(&arg, (void __user *) data, copy_offset[0]) != 0)
+               return -EFAULT;
 
        /*
-        * This will allow us to extend the ioctl argument while
+        * Extend the ioctl argument while
         * maintaining backwards compatibility:
         * We take different code paths depending on the value of
-        * arg->version.
+        * arg.version.
         */
 
-       if (unlikely(arg->version != DRM_VMW_EXECBUF_VERSION)) {
+       if (unlikely(arg.version > DRM_VMW_EXECBUF_VERSION ||
+                    arg.version == 0)) {
                DRM_ERROR("Incorrect execbuf version.\n");
-               DRM_ERROR("You're running outdated experimental "
-                         "vmwgfx user-space drivers.");
                return -EINVAL;
        }
 
+       if (arg.version > 1 &&
+           copy_from_user(&arg.context_handle,
+                          (void __user *) (data + copy_offset[0]),
+                          copy_offset[arg.version - 1] -
+                          copy_offset[0]) != 0)
+               return -EFAULT;
+
+       switch (arg.version) {
+       case 1:
+               arg.context_handle = (uint32_t) -1;
+               break;
+       case 2:
+               if (arg.pad64 != 0) {
+                       DRM_ERROR("Unused IOCTL data not set to zero.\n");
+                       return -EINVAL;
+               }
+               break;
+       default:
+               break;
+       }
+
        ret = ttm_read_lock(&dev_priv->reservation_sem, true);
        if (unlikely(ret != 0))
                return ret;
 
        ret = vmw_execbuf_process(file_priv, dev_priv,
-                                 (void __user *)(unsigned long)arg->commands,
-                                 NULL, arg->command_size, arg->throttle_us,
-                                 (void __user *)(unsigned long)arg->fence_rep,
+                                 (void __user *)(unsigned long)arg.commands,
+                                 NULL, arg.command_size, arg.throttle_us,
+                                 arg.context_handle,
+                                 (void __user *)(unsigned long)arg.fence_rep,
                                  NULL);
        ttm_read_unlock(&dev_priv->reservation_sem);
        if (unlikely(ret != 0))