Skip to content

Commit

Permalink
vmwgfx: Implement fence objects
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Thomas Hellstrom authored and Dave Airlie committed Sep 6, 2011
1 parent 4f73a96 commit ae2a104
Show file tree
Hide file tree
Showing 10 changed files with 1,010 additions and 87 deletions.
3 changes: 2 additions & 1 deletion drivers/gpu/drm/vmwgfx/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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
26 changes: 13 additions & 13 deletions drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand Down
28 changes: 24 additions & 4 deletions drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
Original file line number Diff line number Diff line change
Expand Up @@ -82,12 +82,18 @@
#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
Expand Down Expand Up @@ -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),
Expand Down Expand Up @@ -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);
}

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -475,6 +492,8 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
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
Expand Down Expand Up @@ -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
Expand Down
16 changes: 13 additions & 3 deletions drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -53,6 +54,11 @@
#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;
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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,
Expand All @@ -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 -
Expand Down Expand Up @@ -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
112 changes: 91 additions & 21 deletions drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)
{
Expand All @@ -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))
Expand Down Expand Up @@ -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);
Expand Down
Loading

0 comments on commit ae2a104

Please sign in to comment.