]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
vmwgfx: Implement fence objects
authorThomas Hellstrom <thellstrom@vmware.com>
Thu, 1 Sep 2011 20:18:44 +0000 (20:18 +0000)
committerDave Airlie <airlied@redhat.com>
Tue, 6 Sep 2011 10:51:11 +0000 (11:51 +0100)
Will be needed for queries and drm event-driven throttling.

As a benefit, they help avoid stale user-space fence handles.

Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com>
Reviewed-by: Jakob Bornecrantz <jakob@vmware.com>
Signed-off-by: Dave Airlie <airlied@redhat.com>
drivers/gpu/drm/vmwgfx/Makefile
drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c
drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
drivers/gpu/drm/vmwgfx/vmwgfx_fence.c [new file with mode: 0644]
drivers/gpu/drm/vmwgfx/vmwgfx_fence.h [new file with mode: 0644]
drivers/gpu/drm/vmwgfx/vmwgfx_irq.c
drivers/gpu/drm/vmwgfx/vmwgfx_resource.c
include/drm/vmwgfx_drm.h

index f41e8b4999784636939df1c02d6a1150c4fd4587..7d8e9d5d498c5f9593285a292a40b679c227b231 100644 (file)
@@ -4,6 +4,7 @@ ccflags-y := -Iinclude/drm
 vmwgfx-y := vmwgfx_execbuf.o vmwgfx_gmr.o vmwgfx_kms.o vmwgfx_drv.o \
            vmwgfx_fb.o vmwgfx_ioctl.o vmwgfx_resource.o vmwgfx_buffer.o \
            vmwgfx_fifo.o vmwgfx_irq.o vmwgfx_ldu.o vmwgfx_ttm_glue.o \
-           vmwgfx_overlay.o vmwgfx_marker.o vmwgfx_gmrid_manager.o
+           vmwgfx_overlay.o vmwgfx_marker.o vmwgfx_gmrid_manager.o \
+           vmwgfx_fence.o
 
 obj-$(CONFIG_DRM_VMWGFX) := vmwgfx.o
index 72d95617bc5978adc750d4b8f222c7f867c98bba..5d665ce8cbe4bc7e5a5460ec79f9699554d61292 100644 (file)
@@ -274,39 +274,39 @@ static int vmw_ttm_fault_reserve_notify(struct ttm_buffer_object *bo)
 
 static void *vmw_sync_obj_ref(void *sync_obj)
 {
-       return sync_obj;
+
+       return (void *)
+               vmw_fence_obj_reference((struct vmw_fence_obj *) sync_obj);
 }
 
 static void vmw_sync_obj_unref(void **sync_obj)
 {
-       *sync_obj = NULL;
+       vmw_fence_obj_unreference((struct vmw_fence_obj **) sync_obj);
 }
 
 static int vmw_sync_obj_flush(void *sync_obj, void *sync_arg)
 {
-       struct vmw_private *dev_priv = (struct vmw_private *)sync_arg;
-
-       mutex_lock(&dev_priv->hw_mutex);
-       vmw_write(dev_priv, SVGA_REG_SYNC, SVGA_SYNC_GENERIC);
-       mutex_unlock(&dev_priv->hw_mutex);
+       vmw_fence_obj_flush((struct vmw_fence_obj *) sync_obj);
        return 0;
 }
 
 static bool vmw_sync_obj_signaled(void *sync_obj, void *sync_arg)
 {
-       struct vmw_private *dev_priv = (struct vmw_private *)sync_arg;
-       uint32_t seqno = (unsigned long) sync_obj;
+       unsigned long flags = (unsigned long) sync_arg;
+       return  vmw_fence_obj_signaled((struct vmw_fence_obj *) sync_obj,
+                                      (uint32_t) flags);
 
-       return vmw_seqno_passed(dev_priv, seqno);
 }
 
 static int vmw_sync_obj_wait(void *sync_obj, void *sync_arg,
                             bool lazy, bool interruptible)
 {
-       struct vmw_private *dev_priv = (struct vmw_private *)sync_arg;
-       uint32_t seqno = (unsigned long) sync_obj;
+       unsigned long flags = (unsigned long) sync_arg;
 
-       return vmw_wait_seqno(dev_priv, false, seqno, false, 3*HZ);
+       return vmw_fence_obj_wait((struct vmw_fence_obj *) sync_obj,
+                                 (uint32_t) flags,
+                                 lazy, interruptible,
+                                 VMW_FENCE_WAIT_TIMEOUT);
 }
 
 struct ttm_bo_driver vmw_bo_driver = {
index 4f65f1e34b8fc76ea3c97d23f9ffca3a8cdcc155..d4829cbf326d98df4a15622cf84575178cf1437e 100644 (file)
 #define DRM_IOCTL_VMW_EXECBUF                                  \
        DRM_IOW(DRM_COMMAND_BASE + DRM_VMW_EXECBUF,             \
                struct drm_vmw_execbuf_arg)
+#define DRM_IOCTL_VMW_GET_3D_CAP                               \
+       DRM_IOW(DRM_COMMAND_BASE + DRM_VMW_GET_3D_CAP,          \
+                struct drm_vmw_get_3d_cap_arg)
 #define DRM_IOCTL_VMW_FENCE_WAIT                               \
        DRM_IOWR(DRM_COMMAND_BASE + DRM_VMW_FENCE_WAIT,         \
                 struct drm_vmw_fence_wait_arg)
-#define DRM_IOCTL_VMW_GET_3D_CAP                               \
-       DRM_IOW(DRM_COMMAND_BASE + DRM_VMW_GET_3D_CAP,          \
-               struct drm_vmw_get_3d_cap_arg)
+#define DRM_IOCTL_VMW_FENCE_SIGNALED                           \
+       DRM_IOWR(DRM_COMMAND_BASE + DRM_VMW_FENCE_SIGNALED,     \
+                struct drm_vmw_fence_signaled_arg)
+#define DRM_IOCTL_VMW_FENCE_UNREF                              \
+       DRM_IOW(DRM_COMMAND_BASE + DRM_VMW_FENCE_UNREF,         \
+                struct drm_vmw_fence_arg)
 
 /**
  * The core DRM version of this macro doesn't account for
@@ -131,7 +137,12 @@ static struct drm_ioctl_desc vmw_ioctls[] = {
                      DRM_AUTH | DRM_UNLOCKED),
        VMW_IOCTL_DEF(VMW_EXECBUF, vmw_execbuf_ioctl,
                      DRM_AUTH | DRM_UNLOCKED),
-       VMW_IOCTL_DEF(VMW_FENCE_WAIT, vmw_fence_wait_ioctl,
+       VMW_IOCTL_DEF(VMW_FENCE_WAIT, vmw_fence_obj_wait_ioctl,
+                     DRM_AUTH | DRM_UNLOCKED),
+       VMW_IOCTL_DEF(VMW_FENCE_SIGNALED,
+                     vmw_fence_obj_signaled_ioctl,
+                     DRM_AUTH | DRM_UNLOCKED),
+       VMW_IOCTL_DEF(VMW_FENCE_UNREF, vmw_fence_obj_unref_ioctl,
                      DRM_AUTH | DRM_UNLOCKED),
        VMW_IOCTL_DEF(VMW_GET_3D_CAP, vmw_get_cap_3d_ioctl,
                      DRM_AUTH | DRM_UNLOCKED),
@@ -198,12 +209,14 @@ static int vmw_request_device(struct vmw_private *dev_priv)
                DRM_ERROR("Unable to initialize FIFO.\n");
                return ret;
        }
+       vmw_fence_fifo_up(dev_priv->fman);
 
        return 0;
 }
 
 static void vmw_release_device(struct vmw_private *dev_priv)
 {
+       vmw_fence_fifo_down(dev_priv->fman);
        vmw_fifo_release(dev_priv, &dev_priv->fifo);
 }
 
@@ -434,6 +447,10 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
                        goto out_no_device;
                }
        }
+
+       dev_priv->fman = vmw_fence_manager_init(dev_priv);
+       if (unlikely(dev_priv->fman == NULL))
+               goto out_no_fman;
        ret = vmw_kms_init(dev_priv);
        if (unlikely(ret != 0))
                goto out_no_kms;
@@ -475,6 +492,8 @@ out_no_fifo:
        vmw_overlay_close(dev_priv);
        vmw_kms_close(dev_priv);
 out_no_kms:
+       vmw_fence_manager_takedown(dev_priv->fman);
+out_no_fman:
        if (dev_priv->stealth)
                pci_release_region(dev->pdev, 2);
        else
@@ -518,6 +537,7 @@ static int vmw_driver_unload(struct drm_device *dev)
        }
        vmw_kms_close(dev_priv);
        vmw_overlay_close(dev_priv);
+       vmw_fence_manager_takedown(dev_priv->fman);
        if (dev_priv->stealth)
                pci_release_region(dev->pdev, 2);
        else
index 3018871aaaffca16f000d00d5893db3e5472fb68..770f0636cee877e70cf8dd2d212512822978c080 100644 (file)
@@ -38,6 +38,7 @@
 #include "ttm/ttm_lock.h"
 #include "ttm/ttm_execbuf_util.h"
 #include "ttm/ttm_module.h"
+#include "vmwgfx_fence.h"
 
 #define VMWGFX_DRIVER_DATE "20100927"
 #define VMWGFX_DRIVER_MAJOR 1
 #define VMW_PL_GMR TTM_PL_PRIV0
 #define VMW_PL_FLAG_GMR TTM_PL_FLAG_PRIV0
 
+#define VMW_RES_CONTEXT ttm_driver_type0
+#define VMW_RES_SURFACE ttm_driver_type1
+#define VMW_RES_STREAM ttm_driver_type2
+#define VMW_RES_FENCE ttm_driver_type3
+
 struct vmw_fpriv {
        struct drm_master *locked_master;
        struct ttm_object_file *tfile;
@@ -245,6 +251,7 @@ struct vmw_private {
        atomic_t fifo_queue_waiters;
        uint32_t last_read_seqno;
        spinlock_t irq_lock;
+       struct vmw_fence_manager *fman;
 
        /*
         * Device state
@@ -456,8 +463,6 @@ extern int vmw_irq_postinstall(struct drm_device *dev);
 extern void vmw_irq_uninstall(struct drm_device *dev);
 extern bool vmw_seqno_passed(struct vmw_private *dev_priv,
                                uint32_t seqno);
-extern int vmw_fence_wait_ioctl(struct drm_device *dev, void *data,
-                               struct drm_file *file_priv);
 extern int vmw_fallback_wait(struct vmw_private *dev_priv,
                             bool lazy,
                             bool fifo_idle,
@@ -466,7 +471,8 @@ extern int vmw_fallback_wait(struct vmw_private *dev_priv,
                             unsigned long timeout);
 extern void vmw_update_seqno(struct vmw_private *dev_priv,
                                struct vmw_fifo_state *fifo_state);
-
+extern void vmw_seqno_waiter_add(struct vmw_private *dev_priv);
+extern void vmw_seqno_waiter_remove(struct vmw_private *dev_priv);
 
 /**
  * Rudimentary fence-like objects currently used only for throttling -
@@ -572,4 +578,8 @@ static inline struct vmw_dma_buffer *vmw_dmabuf_reference(struct vmw_dma_buffer
        return NULL;
 }
 
+static inline struct ttm_mem_global *vmw_mem_glob(struct vmw_private *dev_priv)
+{
+       return (struct ttm_mem_global *) dev_priv->mem_global_ref.object;
+}
 #endif
index be41484735b1df718b6a5ee3e5b82e28b6af7097..d48ee89a5190b247d1fd43a49bb230604a2a46fb 100644 (file)
@@ -256,7 +256,7 @@ static int vmw_translate_guest_ptr(struct vmw_private *dev_priv,
                val_buf = &sw_context->val_bufs[cur_validate_node];
                val_buf->bo = ttm_bo_reference(bo);
                val_buf->usage = TTM_USAGE_READWRITE;
-               val_buf->new_sync_obj_arg = (void *) dev_priv;
+               val_buf->new_sync_obj_arg = (void *) DRM_VMW_FENCE_FLAG_EXEC;
                list_add_tail(&val_buf->head, &sw_context->validate_nodes);
                ++sw_context->cur_val_buf;
        }
@@ -321,7 +321,6 @@ static int vmw_cmd_wait_query(struct vmw_private *dev_priv,
        return 0;
 }
 
-
 static int vmw_cmd_dma(struct vmw_private *dev_priv,
                       struct vmw_sw_context *sw_context,
                       SVGA3dCmdHeader *header)
@@ -676,6 +675,50 @@ static int vmw_resize_cmd_bounce(struct vmw_sw_context *sw_context,
        return 0;
 }
 
+/**
+ * vmw_execbuf_fence_commands - create and submit a command stream fence
+ *
+ * Creates a fence object and submits a command stream marker.
+ * If this fails for some reason, We sync the fifo and return NULL.
+ * It is then safe to fence buffers with a NULL pointer.
+ */
+
+int vmw_execbuf_fence_commands(struct drm_file *file_priv,
+                              struct vmw_private *dev_priv,
+                              struct vmw_fence_obj **p_fence,
+                              uint32_t *p_handle)
+{
+       uint32_t sequence;
+       int ret;
+       bool synced = false;
+
+
+       ret = vmw_fifo_send_fence(dev_priv, &sequence);
+       if (unlikely(ret != 0)) {
+               DRM_ERROR("Fence submission error. Syncing.\n");
+               synced = true;
+       }
+
+       if (p_handle != NULL)
+               ret = vmw_user_fence_create(file_priv, dev_priv->fman,
+                                           sequence,
+                                           DRM_VMW_FENCE_FLAG_EXEC,
+                                           p_fence, p_handle);
+       else
+               ret = vmw_fence_create(dev_priv->fman, sequence,
+                                      DRM_VMW_FENCE_FLAG_EXEC,
+                                      p_fence);
+
+       if (unlikely(ret != 0 && !synced)) {
+               (void) vmw_fallback_wait(dev_priv, false, false,
+                                        sequence, false,
+                                        VMW_FENCE_WAIT_TIMEOUT);
+               *p_fence = NULL;
+       }
+
+       return 0;
+}
+
 int vmw_execbuf_ioctl(struct drm_device *dev, void *data,
                      struct drm_file *file_priv)
 {
@@ -686,9 +729,10 @@ int vmw_execbuf_ioctl(struct drm_device *dev, void *data,
        int ret;
        void *user_cmd;
        void *cmd;
-       uint32_t seqno;
        struct vmw_sw_context *sw_context = &dev_priv->ctx;
        struct vmw_master *vmaster = vmw_master(file_priv->master);
+       struct vmw_fence_obj *fence;
+       uint32_t handle;
 
        ret = ttm_read_lock(&vmaster->lock, true);
        if (unlikely(ret != 0))
@@ -755,34 +799,60 @@ int vmw_execbuf_ioctl(struct drm_device *dev, void *data,
        memcpy(cmd, sw_context->cmd_bounce, arg->command_size);
        vmw_fifo_commit(dev_priv, arg->command_size);
 
-       ret = vmw_fifo_send_fence(dev_priv, &seqno);
-
-       ttm_eu_fence_buffer_objects(&sw_context->validate_nodes,
-                                   (void *)(unsigned long) seqno);
-       vmw_clear_validations(sw_context);
-       mutex_unlock(&dev_priv->cmdbuf_mutex);
-
+       user_fence_rep = (struct drm_vmw_fence_rep __user *)
+               (unsigned long)arg->fence_rep;
+       ret = vmw_execbuf_fence_commands(file_priv, dev_priv,
+                                        &fence,
+                                        (user_fence_rep) ? &handle : NULL);
        /*
         * This error is harmless, because if fence submission fails,
-        * vmw_fifo_send_fence will sync.
+        * vmw_fifo_send_fence will sync. The error will be propagated to
+        * user-space in @fence_rep
         */
 
        if (ret != 0)
                DRM_ERROR("Fence submission error. Syncing.\n");
 
-       fence_rep.error = ret;
-       fence_rep.fence_seq = (uint64_t) seqno;
-       fence_rep.pad64 = 0;
+       ttm_eu_fence_buffer_objects(&sw_context->validate_nodes,
+                                   (void *) fence);
 
-       user_fence_rep = (struct drm_vmw_fence_rep __user *)
-           (unsigned long)arg->fence_rep;
+       vmw_clear_validations(sw_context);
+       mutex_unlock(&dev_priv->cmdbuf_mutex);
 
-       /*
-        * copy_to_user errors will be detected by user space not
-        * seeing fence_rep::error filled in.
-        */
+       if (user_fence_rep) {
+               fence_rep.error = ret;
+               fence_rep.handle = handle;
+               fence_rep.seqno = fence->seqno;
+               vmw_update_seqno(dev_priv, &dev_priv->fifo);
+               fence_rep.passed_seqno = dev_priv->last_read_seqno;
+
+               /*
+                * copy_to_user errors will be detected by user space not
+                * seeing fence_rep::error filled in. Typically
+                * user-space would have pre-set that member to -EFAULT.
+                */
+               ret = copy_to_user(user_fence_rep, &fence_rep,
+                                  sizeof(fence_rep));
+
+               /*
+                * User-space lost the fence object. We need to sync
+                * and unreference the handle.
+                */
+               if (unlikely(ret != 0) && (fence_rep.error == 0)) {
+                       BUG_ON(fence == NULL);
+
+                       ttm_ref_object_base_unref(vmw_fpriv(file_priv)->tfile,
+                                                 handle, TTM_REF_USAGE);
+                       DRM_ERROR("Fence copy error. Syncing.\n");
+                       (void) vmw_fence_obj_wait(fence,
+                                                 fence->signal_mask,
+                                                 false, false,
+                                                 VMW_FENCE_WAIT_TIMEOUT);
+               }
+       }
 
-       ret = copy_to_user(user_fence_rep, &fence_rep, sizeof(fence_rep));
+       if (likely(fence != NULL))
+               vmw_fence_obj_unreference(&fence);
 
        vmw_kms_cursor_post_execbuf(dev_priv);
        ttm_read_unlock(&vmaster->lock);
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c
new file mode 100644 (file)
index 0000000..5065a14
--- /dev/null
@@ -0,0 +1,619 @@
+/**************************************************************************
+ *
+ * Copyright © 2011 VMware, Inc., Palo Alto, CA., USA
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
+#include "drmP.h"
+#include "vmwgfx_drv.h"
+
+#define VMW_FENCE_WRAP (1 << 31)
+
+struct vmw_fence_manager {
+       int num_fence_objects;
+       struct vmw_private *dev_priv;
+       spinlock_t lock;
+       u32 next_seqno;
+       struct list_head fence_list;
+       struct work_struct work;
+       u32 user_fence_size;
+       u32 fence_size;
+       bool fifo_down;
+       struct list_head cleanup_list;
+};
+
+struct vmw_user_fence {
+       struct ttm_base_object base;
+       struct vmw_fence_obj fence;
+};
+
+/**
+ * vmw_fence_destroy_locked
+ *
+ */
+
+static void vmw_fence_obj_destroy_locked(struct kref *kref)
+{
+       struct vmw_fence_obj *fence =
+               container_of(kref, struct vmw_fence_obj, kref);
+
+       struct vmw_fence_manager *fman = fence->fman;
+       unsigned int num_fences;
+
+       list_del_init(&fence->head);
+       num_fences = --fman->num_fence_objects;
+       spin_unlock_irq(&fman->lock);
+       if (fence->destroy)
+               fence->destroy(fence);
+       else
+               kfree(fence);
+
+       spin_lock_irq(&fman->lock);
+}
+
+
+/**
+ * Execute signal actions on fences recently signaled.
+ * This is done from a workqueue so we don't have to execute
+ * signal actions from atomic context.
+ */
+
+static void vmw_fence_work_func(struct work_struct *work)
+{
+       struct vmw_fence_manager *fman =
+               container_of(work, struct vmw_fence_manager, work);
+       struct list_head list;
+       struct vmw_fence_action *action, *next_action;
+
+       do {
+               INIT_LIST_HEAD(&list);
+               spin_lock_irq(&fman->lock);
+               list_splice_init(&fman->cleanup_list, &list);
+               spin_unlock_irq(&fman->lock);
+
+               if (list_empty(&list))
+                       return;
+
+               /*
+                * At this point, only we should be able to manipulate the
+                * list heads of the actions we have on the private list.
+                */
+
+               list_for_each_entry_safe(action, next_action, &list, head) {
+                       list_del_init(&action->head);
+                       action->cleanup(action);
+               }
+       } while (1);
+}
+
+struct vmw_fence_manager *vmw_fence_manager_init(struct vmw_private *dev_priv)
+{
+       struct vmw_fence_manager *fman = kzalloc(sizeof(*fman), GFP_KERNEL);
+
+       if (unlikely(fman == NULL))
+               return NULL;
+
+       fman->dev_priv = dev_priv;
+       spin_lock_init(&fman->lock);
+       INIT_LIST_HEAD(&fman->fence_list);
+       INIT_LIST_HEAD(&fman->cleanup_list);
+       INIT_WORK(&fman->work, &vmw_fence_work_func);
+       fman->fifo_down = true;
+       fman->user_fence_size = ttm_round_pot(sizeof(struct vmw_user_fence));
+       fman->fence_size = ttm_round_pot(sizeof(struct vmw_fence_obj));
+
+       return fman;
+}
+
+void vmw_fence_manager_takedown(struct vmw_fence_manager *fman)
+{
+       unsigned long irq_flags;
+       bool lists_empty;
+
+       (void) cancel_work_sync(&fman->work);
+
+       spin_lock_irqsave(&fman->lock, irq_flags);
+       lists_empty = list_empty(&fman->fence_list) &&
+               list_empty(&fman->cleanup_list);
+       spin_unlock_irqrestore(&fman->lock, irq_flags);
+
+       BUG_ON(!lists_empty);
+       kfree(fman);
+}
+
+static int vmw_fence_obj_init(struct vmw_fence_manager *fman,
+                             struct vmw_fence_obj *fence,
+                             u32 seqno,
+                             uint32_t mask,
+                             void (*destroy) (struct vmw_fence_obj *fence))
+{
+       unsigned long irq_flags;
+       unsigned int num_fences;
+       int ret = 0;
+
+       fence->seqno = seqno;
+       INIT_LIST_HEAD(&fence->seq_passed_actions);
+       fence->fman = fman;
+       fence->signaled = 0;
+       fence->signal_mask = mask;
+       kref_init(&fence->kref);
+       fence->destroy = destroy;
+       init_waitqueue_head(&fence->queue);
+
+       spin_lock_irqsave(&fman->lock, irq_flags);
+       if (unlikely(fman->fifo_down)) {
+               ret = -EBUSY;
+               goto out_unlock;
+       }
+       list_add_tail(&fence->head, &fman->fence_list);
+       num_fences = ++fman->num_fence_objects;
+
+out_unlock:
+       spin_unlock_irqrestore(&fman->lock, irq_flags);
+       return ret;
+
+}
+
+struct vmw_fence_obj *vmw_fence_obj_reference(struct vmw_fence_obj *fence)
+{
+       kref_get(&fence->kref);
+       return fence;
+}
+
+/**
+ * vmw_fence_obj_unreference
+ *
+ * Note that this function may not be entered with disabled irqs since
+ * it may re-enable them in the destroy function.
+ *
+ */
+void vmw_fence_obj_unreference(struct vmw_fence_obj **fence_p)
+{
+       struct vmw_fence_obj *fence = *fence_p;
+       struct vmw_fence_manager *fman = fence->fman;
+
+       *fence_p = NULL;
+       spin_lock_irq(&fman->lock);
+       BUG_ON(atomic_read(&fence->kref.refcount) == 0);
+       kref_put(&fence->kref, vmw_fence_obj_destroy_locked);
+       spin_unlock_irq(&fman->lock);
+}
+
+void vmw_fences_perform_actions(struct vmw_fence_manager *fman,
+                               struct list_head *list)
+{
+       struct vmw_fence_action *action, *next_action;
+
+       list_for_each_entry_safe(action, next_action, list, head) {
+               list_del_init(&action->head);
+               if (action->seq_passed != NULL)
+                       action->seq_passed(action);
+
+               /*
+                * Add the cleanup action to the cleanup list so that
+                * it will be performed by a worker task.
+                */
+
+               if (action->cleanup != NULL)
+                       list_add_tail(&action->head, &fman->cleanup_list);
+       }
+}
+
+void vmw_fences_update(struct vmw_fence_manager *fman, u32 seqno)
+{
+       unsigned long flags;
+       struct vmw_fence_obj *fence, *next_fence;
+       struct list_head action_list;
+
+       spin_lock_irqsave(&fman->lock, flags);
+       list_for_each_entry_safe(fence, next_fence, &fman->fence_list, head) {
+               if (seqno - fence->seqno < VMW_FENCE_WRAP) {
+                       list_del_init(&fence->head);
+                       fence->signaled |= DRM_VMW_FENCE_FLAG_EXEC;
+                       INIT_LIST_HEAD(&action_list);
+                       list_splice_init(&fence->seq_passed_actions,
+                                        &action_list);
+                       vmw_fences_perform_actions(fman, &action_list);
+                       wake_up_all(&fence->queue);
+               }
+
+       }
+       if (!list_empty(&fman->cleanup_list))
+               (void) schedule_work(&fman->work);
+       spin_unlock_irqrestore(&fman->lock, flags);
+}
+
+
+bool vmw_fence_obj_signaled(struct vmw_fence_obj *fence,
+                           uint32_t flags)
+{
+       struct vmw_fence_manager *fman = fence->fman;
+       unsigned long irq_flags;
+       uint32_t signaled;
+
+       spin_lock_irqsave(&fman->lock, irq_flags);
+       signaled = fence->signaled;
+       spin_unlock_irqrestore(&fman->lock, irq_flags);
+
+       flags &= fence->signal_mask;
+       if ((signaled & flags) == flags)
+               return 1;
+
+       if ((signaled & DRM_VMW_FENCE_FLAG_EXEC) == 0) {
+               struct vmw_private *dev_priv = fman->dev_priv;
+               __le32 __iomem *fifo_mem = dev_priv->mmio_virt;
+               u32 seqno;
+
+               seqno = ioread32(fifo_mem + SVGA_FIFO_FENCE);
+               vmw_fences_update(fman, seqno);
+       }
+
+       spin_lock_irqsave(&fman->lock, irq_flags);
+       signaled = fence->signaled;
+       spin_unlock_irqrestore(&fman->lock, irq_flags);
+
+       return ((signaled & flags) == flags);
+}
+
+int vmw_fence_obj_wait(struct vmw_fence_obj *fence,
+                      uint32_t flags, bool lazy,
+                      bool interruptible, unsigned long timeout)
+{
+       struct vmw_private *dev_priv = fence->fman->dev_priv;
+       long ret;
+
+       if (likely(vmw_fence_obj_signaled(fence, flags)))
+               return 0;
+
+       vmw_fifo_ping_host(dev_priv, SVGA_SYNC_GENERIC);
+       vmw_seqno_waiter_add(dev_priv);
+
+       if (interruptible)
+               ret = wait_event_interruptible_timeout
+                       (fence->queue,
+                        vmw_fence_obj_signaled(fence, flags),
+                        timeout);
+       else
+               ret = wait_event_timeout
+                       (fence->queue,
+                        vmw_fence_obj_signaled(fence, flags),
+                        timeout);
+
+       vmw_seqno_waiter_remove(dev_priv);
+
+       if (unlikely(ret == 0))
+               ret = -EBUSY;
+       else if (likely(ret > 0))
+               ret = 0;
+
+       return ret;
+}
+
+void vmw_fence_obj_flush(struct vmw_fence_obj *fence)
+{
+       struct vmw_private *dev_priv = fence->fman->dev_priv;
+
+       vmw_fifo_ping_host(dev_priv, SVGA_SYNC_GENERIC);
+}
+
+static void vmw_fence_destroy(struct vmw_fence_obj *fence)
+{
+       struct vmw_fence_manager *fman = fence->fman;
+
+       kfree(fence);
+       /*
+        * Free kernel space accounting.
+        */
+       ttm_mem_global_free(vmw_mem_glob(fman->dev_priv),
+                           fman->fence_size);
+}
+
+int vmw_fence_create(struct vmw_fence_manager *fman,
+                    uint32_t seqno,
+                    uint32_t mask,
+                    struct vmw_fence_obj **p_fence)
+{
+       struct ttm_mem_global *mem_glob = vmw_mem_glob(fman->dev_priv);
+       struct vmw_fence_obj *fence;
+       int ret;
+
+       ret = ttm_mem_global_alloc(mem_glob, fman->fence_size,
+                                  false, false);
+       if (unlikely(ret != 0))
+               return ret;
+
+       fence = kzalloc(sizeof(*fence), GFP_KERNEL);
+       if (unlikely(fence == NULL)) {
+               ret = -ENOMEM;
+               goto out_no_object;
+       }
+
+       ret = vmw_fence_obj_init(fman, fence, seqno, mask,
+                                vmw_fence_destroy);
+       if (unlikely(ret != 0))
+               goto out_err_init;
+
+       *p_fence = fence;
+       return 0;
+
+out_err_init:
+       kfree(fence);
+out_no_object:
+       ttm_mem_global_free(mem_glob, fman->fence_size);
+       return ret;
+}
+
+
+static void vmw_user_fence_destroy(struct vmw_fence_obj *fence)
+{
+       struct vmw_user_fence *ufence =
+               container_of(fence, struct vmw_user_fence, fence);
+       struct vmw_fence_manager *fman = fence->fman;
+
+       kfree(ufence);
+       /*
+        * Free kernel space accounting.
+        */
+       ttm_mem_global_free(vmw_mem_glob(fman->dev_priv),
+                           fman->user_fence_size);
+}
+
+static void vmw_user_fence_base_release(struct ttm_base_object **p_base)
+{
+       struct ttm_base_object *base = *p_base;
+       struct vmw_user_fence *ufence =
+               container_of(base, struct vmw_user_fence, base);
+       struct vmw_fence_obj *fence = &ufence->fence;
+
+       *p_base = NULL;
+       vmw_fence_obj_unreference(&fence);
+}
+
+int vmw_user_fence_create(struct drm_file *file_priv,
+                         struct vmw_fence_manager *fman,
+                         uint32_t seqno,
+                         uint32_t mask,
+                         struct vmw_fence_obj **p_fence,
+                         uint32_t *p_handle)
+{
+       struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
+       struct vmw_user_fence *ufence;
+       struct vmw_fence_obj *tmp;
+       struct ttm_mem_global *mem_glob = vmw_mem_glob(fman->dev_priv);
+       int ret;
+
+       /*
+        * Kernel memory space accounting, since this object may
+        * be created by a user-space request.
+        */
+
+       ret = ttm_mem_global_alloc(mem_glob, fman->user_fence_size,
+                                  false, false);
+       if (unlikely(ret != 0))
+               return ret;
+
+       ufence = kzalloc(sizeof(*ufence), GFP_KERNEL);
+       if (unlikely(ufence == NULL)) {
+               ret = -ENOMEM;
+               goto out_no_object;
+       }
+
+       ret = vmw_fence_obj_init(fman, &ufence->fence, seqno,
+                                mask, vmw_user_fence_destroy);
+       if (unlikely(ret != 0)) {
+               kfree(ufence);
+               goto out_no_object;
+       }
+
+       /*
+        * The base object holds a reference which is freed in
+        * vmw_user_fence_base_release.
+        */
+       tmp = vmw_fence_obj_reference(&ufence->fence);
+       ret = ttm_base_object_init(tfile, &ufence->base, false,
+                                  VMW_RES_FENCE,
+                                  &vmw_user_fence_base_release, NULL);
+
+
+       if (unlikely(ret != 0)) {
+               /*
+                * Free the base object's reference
+                */
+               vmw_fence_obj_unreference(&tmp);
+               goto out_err;
+       }
+
+       *p_fence = &ufence->fence;
+       *p_handle = ufence->base.hash.key;
+
+       return 0;
+out_err:
+       tmp = &ufence->fence;
+       vmw_fence_obj_unreference(&tmp);
+out_no_object:
+       ttm_mem_global_free(mem_glob, fman->user_fence_size);
+       return ret;
+}
+
+
+/**
+ * vmw_fence_fifo_down - signal all unsignaled fence objects.
+ */
+
+void vmw_fence_fifo_down(struct vmw_fence_manager *fman)
+{
+       unsigned long irq_flags;
+       struct list_head action_list;
+       int ret;
+
+       /*
+        * The list may be altered while we traverse it, so always
+        * restart when we've released the fman->lock.
+        */
+
+       spin_lock_irqsave(&fman->lock, irq_flags);
+       fman->fifo_down = true;
+       while (!list_empty(&fman->fence_list)) {
+               struct vmw_fence_obj *fence =
+                       list_entry(fman->fence_list.prev, struct vmw_fence_obj,
+                                  head);
+               kref_get(&fence->kref);
+               spin_unlock_irq(&fman->lock);
+
+               ret = vmw_fence_obj_wait(fence, fence->signal_mask,
+                                        false, false,
+                                        VMW_FENCE_WAIT_TIMEOUT);
+
+               if (unlikely(ret != 0)) {
+                       list_del_init(&fence->head);
+                       fence->signaled |= DRM_VMW_FENCE_FLAG_EXEC;
+                       INIT_LIST_HEAD(&action_list);
+                       list_splice_init(&fence->seq_passed_actions,
+                                        &action_list);
+                       vmw_fences_perform_actions(fman, &action_list);
+                       wake_up_all(&fence->queue);
+               }
+
+               spin_lock_irq(&fman->lock);
+
+               BUG_ON(!list_empty(&fence->head));
+               kref_put(&fence->kref, vmw_fence_obj_destroy_locked);
+       }
+       spin_unlock_irqrestore(&fman->lock, irq_flags);
+}
+
+void vmw_fence_fifo_up(struct vmw_fence_manager *fman)
+{
+       unsigned long irq_flags;
+
+       spin_lock_irqsave(&fman->lock, irq_flags);
+       fman->fifo_down = false;
+       spin_unlock_irqrestore(&fman->lock, irq_flags);
+}
+
+
+int vmw_fence_obj_wait_ioctl(struct drm_device *dev, void *data,
+                            struct drm_file *file_priv)
+{
+       struct drm_vmw_fence_wait_arg *arg =
+           (struct drm_vmw_fence_wait_arg *)data;
+       unsigned long timeout;
+       struct ttm_base_object *base;
+       struct vmw_fence_obj *fence;
+       struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
+       int ret;
+       uint64_t wait_timeout = ((uint64_t)arg->timeout_us * HZ);
+
+       /*
+        * 64-bit division not present on 32-bit systems, so do an
+        * approximation. (Divide by 1000000).
+        */
+
+       wait_timeout = (wait_timeout >> 20) + (wait_timeout >> 24) -
+         (wait_timeout >> 26);
+
+       if (!arg->cookie_valid) {
+               arg->cookie_valid = 1;
+               arg->kernel_cookie = jiffies + wait_timeout;
+       }
+
+       base = ttm_base_object_lookup(tfile, arg->handle);
+       if (unlikely(base == NULL)) {
+               printk(KERN_ERR "Wait invalid fence object handle "
+                      "0x%08lx.\n",
+                      (unsigned long)arg->handle);
+               return -EINVAL;
+       }
+
+       fence = &(container_of(base, struct vmw_user_fence, base)->fence);
+
+       timeout = jiffies;
+       if (time_after_eq(timeout, (unsigned long)arg->kernel_cookie)) {
+               ret = ((vmw_fence_obj_signaled(fence, arg->flags)) ?
+                      0 : -EBUSY);
+               goto out;
+       }
+
+       timeout = (unsigned long)arg->kernel_cookie - timeout;
+
+       ret = vmw_fence_obj_wait(fence, arg->flags, arg->lazy, true, timeout);
+
+out:
+       ttm_base_object_unref(&base);
+
+       /*
+        * Optionally unref the fence object.
+        */
+
+       if (ret == 0 && (arg->wait_options & DRM_VMW_WAIT_OPTION_UNREF))
+               return ttm_ref_object_base_unref(tfile, arg->handle,
+                                                TTM_REF_USAGE);
+       return ret;
+}
+
+int vmw_fence_obj_signaled_ioctl(struct drm_device *dev, void *data,
+                                struct drm_file *file_priv)
+{
+       struct drm_vmw_fence_signaled_arg *arg =
+               (struct drm_vmw_fence_signaled_arg *) data;
+       struct ttm_base_object *base;
+       struct vmw_fence_obj *fence;
+       struct vmw_fence_manager *fman;
+       struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
+       struct vmw_private *dev_priv = vmw_priv(dev);
+
+       base = ttm_base_object_lookup(tfile, arg->handle);
+       if (unlikely(base == NULL)) {
+               printk(KERN_ERR "Fence signaled invalid fence object handle "
+                      "0x%08lx.\n",
+                      (unsigned long)arg->handle);
+               return -EINVAL;
+       }
+
+       fence = &(container_of(base, struct vmw_user_fence, base)->fence);
+       fman = fence->fman;
+
+       arg->signaled = vmw_fence_obj_signaled(fence, arg->flags);
+       spin_lock_irq(&fman->lock);
+
+       arg->signaled_flags = fence->signaled;
+       arg->passed_seqno = dev_priv->last_read_seqno;
+       spin_unlock_irq(&fman->lock);
+
+       ttm_base_object_unref(&base);
+
+       return 0;
+}
+
+
+int vmw_fence_obj_unref_ioctl(struct drm_device *dev, void *data,
+                             struct drm_file *file_priv)
+{
+       struct drm_vmw_fence_arg *arg =
+               (struct drm_vmw_fence_arg *) data;
+
+       return ttm_ref_object_base_unref(vmw_fpriv(file_priv)->tfile,
+                                        arg->handle,
+                                        TTM_REF_USAGE);
+}
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fence.h b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.h
new file mode 100644 (file)
index 0000000..9307406
--- /dev/null
@@ -0,0 +1,105 @@
+/**************************************************************************
+ *
+ * Copyright © 2011 VMware, Inc., Palo Alto, CA., USA
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
+#ifndef _VMWGFX_FENCE_H_
+
+#define VMW_FENCE_WAIT_TIMEOUT (5*HZ)
+
+struct vmw_private;
+
+struct vmw_fence_manager;
+
+/**
+ *
+ *
+ */
+struct vmw_fence_action {
+       struct list_head head;
+       void (*seq_passed) (struct vmw_fence_action *action);
+       void (*cleanup) (struct vmw_fence_action *action);
+};
+
+struct vmw_fence_obj {
+       struct kref kref;
+       u32 seqno;
+
+       struct vmw_fence_manager *fman;
+       struct list_head head;
+       uint32_t signaled;
+       uint32_t signal_mask;
+       struct list_head seq_passed_actions;
+       void (*destroy)(struct vmw_fence_obj *fence);
+       wait_queue_head_t queue;
+};
+
+extern struct vmw_fence_manager *
+vmw_fence_manager_init(struct vmw_private *dev_priv);
+
+extern void vmw_fence_manager_takedown(struct vmw_fence_manager *fman);
+
+extern void vmw_fence_obj_unreference(struct vmw_fence_obj **fence_p);
+
+extern struct vmw_fence_obj *
+vmw_fence_obj_reference(struct vmw_fence_obj *fence);
+
+extern void vmw_fences_update(struct vmw_fence_manager *fman,
+                             u32 sequence);
+
+extern bool vmw_fence_obj_signaled(struct vmw_fence_obj *fence,
+                                  uint32_t flags);
+
+extern int vmw_fence_obj_wait(struct vmw_fence_obj *fence, uint32_t flags,
+                             bool lazy,
+                             bool interruptible, unsigned long timeout);
+
+extern void vmw_fence_obj_flush(struct vmw_fence_obj *fence);
+
+extern int vmw_fence_create(struct vmw_fence_manager *fman,
+                           uint32_t seqno,
+                           uint32_t mask,
+                           struct vmw_fence_obj **p_fence);
+
+extern int vmw_user_fence_create(struct drm_file *file_priv,
+                                struct vmw_fence_manager *fman,
+                                uint32_t sequence,
+                                uint32_t mask,
+                                struct vmw_fence_obj **p_fence,
+                                uint32_t *p_handle);
+
+extern void vmw_fence_fifo_up(struct vmw_fence_manager *fman);
+
+extern void vmw_fence_fifo_down(struct vmw_fence_manager *fman);
+
+extern int vmw_fence_obj_wait_ioctl(struct drm_device *dev, void *data,
+                                   struct drm_file *file_priv);
+
+extern int vmw_fence_obj_signaled_ioctl(struct drm_device *dev, void *data,
+                                       struct drm_file *file_priv);
+
+extern int vmw_fence_obj_unref_ioctl(struct drm_device *dev, void *data,
+                                    struct drm_file *file_priv);
+#endif /* _VMWGFX_FENCE_H_ */
index 13dde06b60be1bae17c1928bb7abbce853b65ead..a005292a8908e6a57c51b1f361c653faf567d658 100644 (file)
@@ -40,8 +40,13 @@ irqreturn_t vmw_irq_handler(DRM_IRQ_ARGS)
        status = inl(dev_priv->io_start + VMWGFX_IRQSTATUS_PORT);
        spin_unlock(&dev_priv->irq_lock);
 
-       if (status & SVGA_IRQFLAG_ANY_FENCE)
+       if (status & SVGA_IRQFLAG_ANY_FENCE) {
+               __le32 __iomem *fifo_mem = dev_priv->mmio_virt;
+               uint32_t seqno = ioread32(fifo_mem + SVGA_FIFO_FENCE);
+
+               vmw_fences_update(dev_priv->fman, seqno);
                wake_up_all(&dev_priv->fence_queue);
+       }
        if (status & SVGA_IRQFLAG_FIFO_PROGRESS)
                wake_up_all(&dev_priv->fifo_queue);
 
@@ -68,12 +73,12 @@ void vmw_update_seqno(struct vmw_private *dev_priv,
                         struct vmw_fifo_state *fifo_state)
 {
        __le32 __iomem *fifo_mem = dev_priv->mmio_virt;
-
        uint32_t seqno = ioread32(fifo_mem + SVGA_FIFO_FENCE);
 
        if (dev_priv->last_read_seqno != seqno) {
                dev_priv->last_read_seqno = seqno;
                vmw_marker_pull(&fifo_state->marker_queue, seqno);
+               vmw_fences_update(dev_priv->fman, seqno);
        }
 }
 
@@ -175,7 +180,7 @@ int vmw_fallback_wait(struct vmw_private *dev_priv,
        return ret;
 }
 
-static void vmw_seqno_waiter_add(struct vmw_private *dev_priv)
+void vmw_seqno_waiter_add(struct vmw_private *dev_priv)
 {
        mutex_lock(&dev_priv->hw_mutex);
        if (dev_priv->fence_queue_waiters++ == 0) {
@@ -192,7 +197,7 @@ static void vmw_seqno_waiter_add(struct vmw_private *dev_priv)
        mutex_unlock(&dev_priv->hw_mutex);
 }
 
-static void vmw_seqno_waiter_remove(struct vmw_private *dev_priv)
+void vmw_seqno_waiter_remove(struct vmw_private *dev_priv)
 {
        mutex_lock(&dev_priv->hw_mutex);
        if (--dev_priv->fence_queue_waiters == 0) {
@@ -286,25 +291,3 @@ void vmw_irq_uninstall(struct drm_device *dev)
        status = inl(dev_priv->io_start + VMWGFX_IRQSTATUS_PORT);
        outl(status, dev_priv->io_start + VMWGFX_IRQSTATUS_PORT);
 }
-
-#define VMW_FENCE_WAIT_TIMEOUT 3*HZ;
-
-int vmw_fence_wait_ioctl(struct drm_device *dev, void *data,
-                        struct drm_file *file_priv)
-{
-       struct drm_vmw_fence_wait_arg *arg =
-           (struct drm_vmw_fence_wait_arg *)data;
-       unsigned long timeout;
-
-       if (!arg->cookie_valid) {
-               arg->cookie_valid = 1;
-               arg->kernel_cookie = jiffies + VMW_FENCE_WAIT_TIMEOUT;
-       }
-
-       timeout = jiffies;
-       if (time_after_eq(timeout, (unsigned long)arg->kernel_cookie))
-               return -EBUSY;
-
-       timeout = (unsigned long)arg->kernel_cookie - timeout;
-       return vmw_wait_seqno(vmw_priv(dev), true, arg->seqno, true, timeout);
-}
index 4b53803d0fa9fd8a81971605516e722d8a65c295..c1b6ffd4ce7b82c411692870c0c9edd42d002ad8 100644 (file)
 #include "ttm/ttm_placement.h"
 #include "drmP.h"
 
-#define VMW_RES_CONTEXT ttm_driver_type0
-#define VMW_RES_SURFACE ttm_driver_type1
-#define VMW_RES_STREAM ttm_driver_type2
-
 struct vmw_user_context {
        struct ttm_base_object base;
        struct vmw_resource res;
index c2b3909ac50ada0537551b2e4f3169c67195937d..763a7a3885a1c6a6828726b390735e0f7505974a 100644 (file)
 #define DRM_VMW_UNREF_SURFACE        10
 #define DRM_VMW_REF_SURFACE          11
 #define DRM_VMW_EXECBUF              12
-#define DRM_VMW_FENCE_WAIT           13
-#define DRM_VMW_GET_3D_CAP           14
+#define DRM_VMW_GET_3D_CAP           13
+#define DRM_VMW_FENCE_WAIT           14
+#define DRM_VMW_FENCE_SIGNALED       15
+#define DRM_VMW_FENCE_UNREF          16
+#define DRM_VMW_FENCE_EVENT          17
+
 
 /*************************************************************************/
 /**
@@ -318,14 +322,23 @@ struct drm_vmw_execbuf_arg {
        uint32_t command_size;
        uint32_t throttle_us;
        uint64_t fence_rep;
-        uint32_t version;
-        uint32_t flags;
+       uint32_t version;
+       uint32_t flags;
 };
 
 /**
  * struct drm_vmw_fence_rep
  *
- * @fence_seq: Fence seqno associated with a command submission.
+ * @handle: Fence object handle for fence associated with a command submission.
+ * @mask: Fence flags relevant for this fence object.
+ * @seqno: Fence sequence number in fifo. A fence object with a lower
+ * seqno will signal the EXEC flag before a fence object with a higher
+ * seqno. This can be used by user-space to avoid kernel calls to determine
+ * whether a fence has signaled the EXEC flag. Note that @seqno will
+ * wrap at 32-bit.
+ * @passed_seqno: The highest seqno number processed by the hardware
+ * so far. This can be used to mark user-space fence objects as signaled, and
+ * to determine whether a fence seqno might be stale.
  * @error: This member should've been set to -EFAULT on submission.
  * The following actions should be take on completion:
  * error == -EFAULT: Fence communication failed. The host is synchronized.
@@ -339,9 +352,12 @@ struct drm_vmw_execbuf_arg {
  */
 
 struct drm_vmw_fence_rep {
-       uint64_t fence_seq;
-       int32_t error;
+       uint32_t handle;
+       uint32_t mask;
+       uint32_t seqno;
+       uint32_t passed_seqno;
        uint32_t pad64;
+       int32_t error;
 };
 
 /*************************************************************************/
@@ -430,14 +446,6 @@ struct drm_vmw_unref_dmabuf_arg {
        uint32_t pad64;
 };
 
-
-struct drm_vmw_fence_wait_arg {
-       uint64_t seqno;
-       uint64_t kernel_cookie;
-       int32_t cookie_valid;
-       int32_t pad64;
-};
-
 /*************************************************************************/
 /**
  * DRM_VMW_CONTROL_STREAM - Control overlays, aka streams.
@@ -559,6 +567,7 @@ struct drm_vmw_stream_arg {
  * Return a single stream that was claimed by this process. Also makes
  * sure that the stream has been stopped.
  */
+
 /*************************************************************************/
 /**
  * DRM_VMW_GET_3D_CAP
@@ -607,4 +616,114 @@ struct drm_vmw_update_layout_arg {
        uint64_t rects;
 };
 
+
+/*************************************************************************/
+/**
+ * DRM_VMW_FENCE_WAIT
+ *
+ * Waits for a fence object to signal. The wait is interruptible, so that
+ * signals may be delivered during the interrupt. The wait may timeout,
+ * in which case the calls returns -EBUSY. If the wait is restarted,
+ * that is restarting without resetting @cookie_valid to zero,
+ * the timeout is computed from the first call.
+ *
+ * The flags argument to the DRM_VMW_FENCE_WAIT ioctl indicates what to wait
+ * on:
+ * DRM_VMW_FENCE_FLAG_EXEC: All commands ahead of the fence in the command
+ * stream
+ * have executed.
+ * DRM_VMW_FENCE_FLAG_QUERY: All query results resulting from query finish
+ * commands
+ * in the buffer given to the EXECBUF ioctl returning the fence object handle
+ * are available to user-space.
+ *
+ * DRM_VMW_WAIT_OPTION_UNREF: If this wait option is given, and the
+ * fenc wait ioctl returns 0, the fence object has been unreferenced after
+ * the wait.
+ */
+
+#define DRM_VMW_FENCE_FLAG_EXEC   (1 << 0)
+#define DRM_VMW_FENCE_FLAG_QUERY  (1 << 1)
+
+#define DRM_VMW_WAIT_OPTION_UNREF (1 << 0)
+
+/**
+ * struct drm_vmw_fence_wait_arg
+ *
+ * @handle: Fence object handle as returned by the DRM_VMW_EXECBUF ioctl.
+ * @cookie_valid: Must be reset to 0 on first call. Left alone on restart.
+ * @kernel_cookie: Set to 0 on first call. Left alone on restart.
+ * @timeout_us: Wait timeout in microseconds. 0 for indefinite timeout.
+ * @lazy: Set to 1 if timing is not critical. Allow more than a kernel tick
+ * before returning.
+ * @flags: Fence flags to wait on.
+ * @wait_options: Options that control the behaviour of the wait ioctl.
+ *
+ * Input argument to the DRM_VMW_FENCE_WAIT ioctl.
+ */
+
+struct drm_vmw_fence_wait_arg {
+       uint32_t handle;
+       int32_t  cookie_valid;
+       uint64_t kernel_cookie;
+       uint64_t timeout_us;
+       int32_t lazy;
+       int32_t flags;
+       int32_t wait_options;
+       int32_t pad64;
+};
+
+/*************************************************************************/
+/**
+ * DRM_VMW_FENCE_SIGNALED
+ *
+ * Checks if a fence object is signaled..
+ */
+
+/**
+ * struct drm_vmw_fence_signaled_arg
+ *
+ * @handle: Fence object handle as returned by the DRM_VMW_EXECBUF ioctl.
+ * @flags: Fence object flags input to DRM_VMW_FENCE_SIGNALED ioctl
+ * @signaled: Out: Flags signaled.
+ * @sequence: Out: Highest sequence passed so far. Can be used to signal the
+ * EXEC flag of user-space fence objects.
+ *
+ * Input/Output argument to the DRM_VMW_FENCE_SIGNALED and DRM_VMW_FENCE_UNREF
+ * ioctls.
+ */
+
+struct drm_vmw_fence_signaled_arg {
+        uint32_t handle;
+        uint32_t flags;
+        int32_t signaled;
+        uint32_t passed_seqno;
+        uint32_t signaled_flags;
+        uint32_t pad64;
+};
+
+/*************************************************************************/
+/**
+ * DRM_VMW_FENCE_UNREF
+ *
+ * Unreferences a fence object, and causes it to be destroyed if there are no
+ * other references to it.
+ *
+ */
+
+/**
+ * struct drm_vmw_fence_arg
+ *
+ * @handle: Fence object handle as returned by the DRM_VMW_EXECBUF ioctl.
+ *
+ * Input/Output argument to the DRM_VMW_FENCE_UNREF ioctl..
+ */
+
+struct drm_vmw_fence_arg {
+        uint32_t handle;
+        uint32_t pad64;
+};
+
+
+
 #endif