Commit ae2a1040 authored by Thomas Hellstrom's avatar Thomas Hellstrom Committed by Dave Airlie

vmwgfx: Implement fence objects

Will be needed for queries and drm event-driven throttling.

As a benefit, they help avoid stale user-space fence handles.
Signed-off-by: default avatarThomas Hellstrom <thellstrom@vmware.com>
Reviewed-by: default avatarJakob Bornecrantz <jakob@vmware.com>
Signed-off-by: default avatarDave Airlie <airlied@redhat.com>
parent 4f73a96b
...@@ -4,6 +4,7 @@ ccflags-y := -Iinclude/drm ...@@ -4,6 +4,7 @@ ccflags-y := -Iinclude/drm
vmwgfx-y := vmwgfx_execbuf.o vmwgfx_gmr.o vmwgfx_kms.o vmwgfx_drv.o \ 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_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_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 obj-$(CONFIG_DRM_VMWGFX) := vmwgfx.o
...@@ -274,39 +274,39 @@ static int vmw_ttm_fault_reserve_notify(struct ttm_buffer_object *bo) ...@@ -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) 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) 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) static int vmw_sync_obj_flush(void *sync_obj, void *sync_arg)
{ {
struct vmw_private *dev_priv = (struct vmw_private *)sync_arg; vmw_fence_obj_flush((struct vmw_fence_obj *) sync_obj);
mutex_lock(&dev_priv->hw_mutex);
vmw_write(dev_priv, SVGA_REG_SYNC, SVGA_SYNC_GENERIC);
mutex_unlock(&dev_priv->hw_mutex);
return 0; return 0;
} }
static bool vmw_sync_obj_signaled(void *sync_obj, void *sync_arg) static bool vmw_sync_obj_signaled(void *sync_obj, void *sync_arg)
{ {
struct vmw_private *dev_priv = (struct vmw_private *)sync_arg; unsigned long flags = (unsigned long) sync_arg;
uint32_t seqno = (unsigned long) sync_obj; 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, static int vmw_sync_obj_wait(void *sync_obj, void *sync_arg,
bool lazy, bool interruptible) bool lazy, bool interruptible)
{ {
struct vmw_private *dev_priv = (struct vmw_private *)sync_arg; unsigned long flags = (unsigned long) sync_arg;
uint32_t seqno = (unsigned long) sync_obj;
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 = { struct ttm_bo_driver vmw_bo_driver = {
......
...@@ -82,12 +82,18 @@ ...@@ -82,12 +82,18 @@
#define DRM_IOCTL_VMW_EXECBUF \ #define DRM_IOCTL_VMW_EXECBUF \
DRM_IOW(DRM_COMMAND_BASE + DRM_VMW_EXECBUF, \ DRM_IOW(DRM_COMMAND_BASE + DRM_VMW_EXECBUF, \
struct drm_vmw_execbuf_arg) struct drm_vmw_execbuf_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 \ #define DRM_IOCTL_VMW_GET_3D_CAP \
DRM_IOW(DRM_COMMAND_BASE + DRM_VMW_GET_3D_CAP, \ DRM_IOW(DRM_COMMAND_BASE + DRM_VMW_GET_3D_CAP, \
struct drm_vmw_get_3d_cap_arg) 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_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 * The core DRM version of this macro doesn't account for
...@@ -131,7 +137,12 @@ static struct drm_ioctl_desc vmw_ioctls[] = { ...@@ -131,7 +137,12 @@ static struct drm_ioctl_desc vmw_ioctls[] = {
DRM_AUTH | DRM_UNLOCKED), DRM_AUTH | DRM_UNLOCKED),
VMW_IOCTL_DEF(VMW_EXECBUF, vmw_execbuf_ioctl, VMW_IOCTL_DEF(VMW_EXECBUF, vmw_execbuf_ioctl,
DRM_AUTH | DRM_UNLOCKED), 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), DRM_AUTH | DRM_UNLOCKED),
VMW_IOCTL_DEF(VMW_GET_3D_CAP, vmw_get_cap_3d_ioctl, VMW_IOCTL_DEF(VMW_GET_3D_CAP, vmw_get_cap_3d_ioctl,
DRM_AUTH | DRM_UNLOCKED), DRM_AUTH | DRM_UNLOCKED),
...@@ -198,12 +209,14 @@ static int vmw_request_device(struct vmw_private *dev_priv) ...@@ -198,12 +209,14 @@ static int vmw_request_device(struct vmw_private *dev_priv)
DRM_ERROR("Unable to initialize FIFO.\n"); DRM_ERROR("Unable to initialize FIFO.\n");
return ret; return ret;
} }
vmw_fence_fifo_up(dev_priv->fman);
return 0; return 0;
} }
static void vmw_release_device(struct vmw_private *dev_priv) 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); vmw_fifo_release(dev_priv, &dev_priv->fifo);
} }
...@@ -434,6 +447,10 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset) ...@@ -434,6 +447,10 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
goto out_no_device; 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); ret = vmw_kms_init(dev_priv);
if (unlikely(ret != 0)) if (unlikely(ret != 0))
goto out_no_kms; goto out_no_kms;
...@@ -475,6 +492,8 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset) ...@@ -475,6 +492,8 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
vmw_overlay_close(dev_priv); vmw_overlay_close(dev_priv);
vmw_kms_close(dev_priv); vmw_kms_close(dev_priv);
out_no_kms: out_no_kms:
vmw_fence_manager_takedown(dev_priv->fman);
out_no_fman:
if (dev_priv->stealth) if (dev_priv->stealth)
pci_release_region(dev->pdev, 2); pci_release_region(dev->pdev, 2);
else else
...@@ -518,6 +537,7 @@ static int vmw_driver_unload(struct drm_device *dev) ...@@ -518,6 +537,7 @@ static int vmw_driver_unload(struct drm_device *dev)
} }
vmw_kms_close(dev_priv); vmw_kms_close(dev_priv);
vmw_overlay_close(dev_priv); vmw_overlay_close(dev_priv);
vmw_fence_manager_takedown(dev_priv->fman);
if (dev_priv->stealth) if (dev_priv->stealth)
pci_release_region(dev->pdev, 2); pci_release_region(dev->pdev, 2);
else else
......
...@@ -38,6 +38,7 @@ ...@@ -38,6 +38,7 @@
#include "ttm/ttm_lock.h" #include "ttm/ttm_lock.h"
#include "ttm/ttm_execbuf_util.h" #include "ttm/ttm_execbuf_util.h"
#include "ttm/ttm_module.h" #include "ttm/ttm_module.h"
#include "vmwgfx_fence.h"
#define VMWGFX_DRIVER_DATE "20100927" #define VMWGFX_DRIVER_DATE "20100927"
#define VMWGFX_DRIVER_MAJOR 1 #define VMWGFX_DRIVER_MAJOR 1
...@@ -53,6 +54,11 @@ ...@@ -53,6 +54,11 @@
#define VMW_PL_GMR TTM_PL_PRIV0 #define VMW_PL_GMR TTM_PL_PRIV0
#define VMW_PL_FLAG_GMR TTM_PL_FLAG_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 vmw_fpriv {
struct drm_master *locked_master; struct drm_master *locked_master;
struct ttm_object_file *tfile; struct ttm_object_file *tfile;
...@@ -245,6 +251,7 @@ struct vmw_private { ...@@ -245,6 +251,7 @@ struct vmw_private {
atomic_t fifo_queue_waiters; atomic_t fifo_queue_waiters;
uint32_t last_read_seqno; uint32_t last_read_seqno;
spinlock_t irq_lock; spinlock_t irq_lock;
struct vmw_fence_manager *fman;
/* /*
* Device state * Device state
...@@ -456,8 +463,6 @@ extern int vmw_irq_postinstall(struct drm_device *dev); ...@@ -456,8 +463,6 @@ extern int vmw_irq_postinstall(struct drm_device *dev);
extern void vmw_irq_uninstall(struct drm_device *dev); extern void vmw_irq_uninstall(struct drm_device *dev);
extern bool vmw_seqno_passed(struct vmw_private *dev_priv, extern bool vmw_seqno_passed(struct vmw_private *dev_priv,
uint32_t seqno); 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, extern int vmw_fallback_wait(struct vmw_private *dev_priv,
bool lazy, bool lazy,
bool fifo_idle, bool fifo_idle,
...@@ -466,7 +471,8 @@ extern int vmw_fallback_wait(struct vmw_private *dev_priv, ...@@ -466,7 +471,8 @@ extern int vmw_fallback_wait(struct vmw_private *dev_priv,
unsigned long timeout); unsigned long timeout);
extern void vmw_update_seqno(struct vmw_private *dev_priv, extern void vmw_update_seqno(struct vmw_private *dev_priv,
struct vmw_fifo_state *fifo_state); 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 - * 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 ...@@ -572,4 +578,8 @@ static inline struct vmw_dma_buffer *vmw_dmabuf_reference(struct vmw_dma_buffer
return NULL; 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 #endif
...@@ -256,7 +256,7 @@ static int vmw_translate_guest_ptr(struct vmw_private *dev_priv, ...@@ -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 = &sw_context->val_bufs[cur_validate_node];
val_buf->bo = ttm_bo_reference(bo); val_buf->bo = ttm_bo_reference(bo);
val_buf->usage = TTM_USAGE_READWRITE; 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); list_add_tail(&val_buf->head, &sw_context->validate_nodes);
++sw_context->cur_val_buf; ++sw_context->cur_val_buf;
} }
...@@ -321,7 +321,6 @@ static int vmw_cmd_wait_query(struct vmw_private *dev_priv, ...@@ -321,7 +321,6 @@ static int vmw_cmd_wait_query(struct vmw_private *dev_priv,
return 0; return 0;
} }
static int vmw_cmd_dma(struct vmw_private *dev_priv, static int vmw_cmd_dma(struct vmw_private *dev_priv,
struct vmw_sw_context *sw_context, struct vmw_sw_context *sw_context,
SVGA3dCmdHeader *header) SVGA3dCmdHeader *header)
...@@ -676,6 +675,50 @@ static int vmw_resize_cmd_bounce(struct vmw_sw_context *sw_context, ...@@ -676,6 +675,50 @@ static int vmw_resize_cmd_bounce(struct vmw_sw_context *sw_context,
return 0; 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, int vmw_execbuf_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv) struct drm_file *file_priv)
{ {
...@@ -686,9 +729,10 @@ int vmw_execbuf_ioctl(struct drm_device *dev, void *data, ...@@ -686,9 +729,10 @@ int vmw_execbuf_ioctl(struct drm_device *dev, void *data,
int ret; int ret;
void *user_cmd; void *user_cmd;
void *cmd; void *cmd;
uint32_t seqno;
struct vmw_sw_context *sw_context = &dev_priv->ctx; struct vmw_sw_context *sw_context = &dev_priv->ctx;
struct vmw_master *vmaster = vmw_master(file_priv->master); struct vmw_master *vmaster = vmw_master(file_priv->master);
struct vmw_fence_obj *fence;
uint32_t handle;
ret = ttm_read_lock(&vmaster->lock, true); ret = ttm_read_lock(&vmaster->lock, true);
if (unlikely(ret != 0)) if (unlikely(ret != 0))
...@@ -755,34 +799,60 @@ int vmw_execbuf_ioctl(struct drm_device *dev, void *data, ...@@ -755,34 +799,60 @@ int vmw_execbuf_ioctl(struct drm_device *dev, void *data,
memcpy(cmd, sw_context->cmd_bounce, arg->command_size); memcpy(cmd, sw_context->cmd_bounce, arg->command_size);
vmw_fifo_commit(dev_priv, arg->command_size); vmw_fifo_commit(dev_priv, arg->command_size);
ret = vmw_fifo_send_fence(dev_priv, &seqno); user_fence_rep = (struct drm_vmw_fence_rep __user *)
(unsigned long)arg->fence_rep;
ttm_eu_fence_buffer_objects(&sw_context->validate_nodes, ret = vmw_execbuf_fence_commands(file_priv, dev_priv,
(void *)(unsigned long) seqno); &fence,
vmw_clear_validations(sw_context); (user_fence_rep) ? &handle : NULL);
mutex_unlock(&dev_priv->cmdbuf_mutex);
/* /*
* This error is harmless, because if fence submission fails, * 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) if (ret != 0)
DRM_ERROR("Fence submission error. Syncing.\n"); DRM_ERROR("Fence submission error. Syncing.\n");
fence_rep.error = ret; ttm_eu_fence_buffer_objects(&sw_context->validate_nodes,
fence_rep.fence_seq = (uint64_t) seqno; (void *) fence);
fence_rep.pad64 = 0;
user_fence_rep = (struct drm_vmw_fence_rep __user *) vmw_clear_validations(sw_context);
(unsigned long)arg->fence_rep; mutex_unlock(&dev_priv->cmdbuf_mutex);
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 * copy_to_user errors will be detected by user space not
* seeing fence_rep::error filled in. * 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); vmw_kms_cursor_post_execbuf(dev_priv);
ttm_read_unlock(&vmaster->lock); ttm_read_unlock(&vmaster->lock);
......
This diff is collapsed.
/**************************************************************************
*
* 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_ */
...@@ -40,8 +40,13 @@ irqreturn_t vmw_irq_handler(DRM_IRQ_ARGS) ...@@ -40,8 +40,13 @@ irqreturn_t vmw_irq_handler(DRM_IRQ_ARGS)
status = inl(dev_priv->io_start + VMWGFX_IRQSTATUS_PORT); status = inl(dev_priv->io_start + VMWGFX_IRQSTATUS_PORT);
spin_unlock(&dev_priv->irq_lock); 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); wake_up_all(&dev_priv->fence_queue);
}
if (status & SVGA_IRQFLAG_FIFO_PROGRESS) if (status & SVGA_IRQFLAG_FIFO_PROGRESS)
wake_up_all(&dev_priv->fifo_queue); wake_up_all(&dev_priv->fifo_queue);
...@@ -68,12 +73,12 @@ void vmw_update_seqno(struct vmw_private *dev_priv, ...@@ -68,12 +73,12 @@ void vmw_update_seqno(struct vmw_private *dev_priv,
struct vmw_fifo_state *fifo_state) struct vmw_fifo_state *fifo_state)
{ {
__le32 __iomem *fifo_mem = dev_priv->mmio_virt; __le32 __iomem *fifo_mem = dev_priv->mmio_virt;
uint32_t seqno = ioread32(fifo_mem + SVGA_FIFO_FENCE); uint32_t seqno = ioread32(fifo_mem + SVGA_FIFO_FENCE);
if (dev_priv->last_read_seqno != seqno) { if (dev_priv->last_read_seqno != seqno) {
dev_priv->last_read_seqno = seqno; dev_priv->last_read_seqno = seqno;
vmw_marker_pull(&fifo_state->marker_queue, 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, ...@@ -175,7 +180,7 @@ int vmw_fallback_wait(struct vmw_private *dev_priv,
return ret; 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); mutex_lock(&dev_priv->hw_mutex);
if (dev_priv->fence_queue_waiters++ == 0) { if (dev_priv->fence_queue_waiters++ == 0) {
...@@ -192,7 +197,7 @@ static void vmw_seqno_waiter_add(struct vmw_private *dev_priv) ...@@ -192,7 +197,7 @@ static void vmw_seqno_waiter_add(struct vmw_private *dev_priv)
mutex_unlock(&dev_priv->hw_mutex); 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); mutex_lock(&dev_priv->hw_mutex);
if (--dev_priv->fence_queue_waiters == 0) { if (--dev_priv->fence_queue_waiters == 0) {
...@@ -286,25 +291,3 @@ void vmw_irq_uninstall(struct drm_device *dev) ...@@ -286,25 +291,3 @@ void vmw_irq_uninstall(struct drm_device *dev)
status = inl(dev_priv->io_start + VMWGFX_IRQSTATUS_PORT); status = inl(dev_priv->io_start + VMWGFX_IRQSTATUS_PORT);
outl(status, 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);
}
...@@ -31,10 +31,6 @@ ...@@ -31,10 +31,6 @@
#include "ttm/ttm_placement.h" #include "ttm/ttm_placement.h"
#include "drmP.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 vmw_user_context {
struct ttm_base_object base; struct ttm_base_object base;
struct vmw_resource res; struct vmw_resource res;
......
...@@ -48,8 +48,12 @@ ...@@ -48,8 +48,12 @@
#define DRM_VMW_UNREF_SURFACE 10 #define DRM_VMW_UNREF_SURFACE 10
#define DRM_VMW_REF_SURFACE 11 #define DRM_VMW_REF_SURFACE 11
#define DRM_VMW_EXECBUF 12 #define DRM_VMW_EXECBUF 12
#define DRM_VMW_FENCE_WAIT 13 #define DRM_VMW_GET_3D_CAP 13
#define DRM_VMW_GET_3D_CAP 14 #define DRM_VMW_FENCE_WAIT 14
#define DRM_VMW_FENCE_SIGNALED 15
#define DRM_VMW_FENCE_UNREF 16
#define DRM_VMW_FENCE_EVENT 17
/*************************************************************************/ /*************************************************************************/
/** /**
...@@ -325,7 +329,16 @@ struct drm_vmw_execbuf_arg { ...@@ -325,7 +329,16 @@ struct drm_vmw_execbuf_arg {
/** /**
* struct drm_vmw_fence_rep * 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. * @error: This member should've been set to -EFAULT on submission.
* The following actions should be take on completion: * The following actions should be take on completion:
* error == -EFAULT: Fence communication failed. The host is synchronized. * error == -EFAULT: Fence communication failed. The host is synchronized.
...@@ -339,9 +352,12 @@ struct drm_vmw_execbuf_arg { ...@@ -339,9 +352,12 @@ struct drm_vmw_execbuf_arg {
*/ */
struct drm_vmw_fence_rep { struct drm_vmw_fence_rep {
uint64_t fence_seq; uint32_t handle;
int32_t error; uint32_t mask;
uint32_t seqno;
uint32_t passed_seqno;
uint32_t pad64; uint32_t pad64;
int32_t error;
}; };
/*************************************************************************/ /*************************************************************************/
...@@ -430,14 +446,6 @@ struct drm_vmw_unref_dmabuf_arg { ...@@ -430,14 +446,6 @@ struct drm_vmw_unref_dmabuf_arg {
uint32_t pad64; 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. * DRM_VMW_CONTROL_STREAM - Control overlays, aka streams.
...@@ -559,6 +567,7 @@ struct drm_vmw_stream_arg { ...@@ -559,6 +567,7 @@ struct drm_vmw_stream_arg {
* Return a single stream that was claimed by this process. Also makes * Return a single stream that was claimed by this process. Also makes
* sure that the stream has been stopped. * sure that the stream has been stopped.
*/ */
/*************************************************************************/ /*************************************************************************/
/** /**
* DRM_VMW_GET_3D_CAP * DRM_VMW_GET_3D_CAP
...@@ -607,4 +616,114 @@ struct drm_vmw_update_layout_arg { ...@@ -607,4 +616,114 @@ struct drm_vmw_update_layout_arg {
uint64_t rects; 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 #endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment