Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -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
+13 −13
Original line number Diff line number Diff line
@@ -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 = {
+24 −4
Original line number Diff line number Diff line
@@ -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_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_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
@@ -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
+13 −3
Original line number Diff line number Diff line
@@ -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
@@ -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;
@@ -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
+91 −21
Original line number Diff line number Diff line
@@ -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);

	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.
		 * 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);
Loading