Skip to content

Commit ae2a104

Browse files
thomashvmwairlied
authored andcommitted
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: Thomas Hellstrom <thellstrom@vmware.com> Reviewed-by: Jakob Bornecrantz <jakob@vmware.com> Signed-off-by: Dave Airlie <airlied@redhat.com>
1 parent 4f73a96 commit ae2a104

File tree

10 files changed

+1010
-87
lines changed

10 files changed

+1010
-87
lines changed

drivers/gpu/drm/vmwgfx/Makefile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ ccflags-y := -Iinclude/drm
44
vmwgfx-y := vmwgfx_execbuf.o vmwgfx_gmr.o vmwgfx_kms.o vmwgfx_drv.o \
55
vmwgfx_fb.o vmwgfx_ioctl.o vmwgfx_resource.o vmwgfx_buffer.o \
66
vmwgfx_fifo.o vmwgfx_irq.o vmwgfx_ldu.o vmwgfx_ttm_glue.o \
7-
vmwgfx_overlay.o vmwgfx_marker.o vmwgfx_gmrid_manager.o
7+
vmwgfx_overlay.o vmwgfx_marker.o vmwgfx_gmrid_manager.o \
8+
vmwgfx_fence.o
89

910
obj-$(CONFIG_DRM_VMWGFX) := vmwgfx.o

drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -274,39 +274,39 @@ static int vmw_ttm_fault_reserve_notify(struct ttm_buffer_object *bo)
274274

275275
static void *vmw_sync_obj_ref(void *sync_obj)
276276
{
277-
return sync_obj;
277+
278+
return (void *)
279+
vmw_fence_obj_reference((struct vmw_fence_obj *) sync_obj);
278280
}
279281

280282
static void vmw_sync_obj_unref(void **sync_obj)
281283
{
282-
*sync_obj = NULL;
284+
vmw_fence_obj_unreference((struct vmw_fence_obj **) sync_obj);
283285
}
284286

285287
static int vmw_sync_obj_flush(void *sync_obj, void *sync_arg)
286288
{
287-
struct vmw_private *dev_priv = (struct vmw_private *)sync_arg;
288-
289-
mutex_lock(&dev_priv->hw_mutex);
290-
vmw_write(dev_priv, SVGA_REG_SYNC, SVGA_SYNC_GENERIC);
291-
mutex_unlock(&dev_priv->hw_mutex);
289+
vmw_fence_obj_flush((struct vmw_fence_obj *) sync_obj);
292290
return 0;
293291
}
294292

295293
static bool vmw_sync_obj_signaled(void *sync_obj, void *sync_arg)
296294
{
297-
struct vmw_private *dev_priv = (struct vmw_private *)sync_arg;
298-
uint32_t seqno = (unsigned long) sync_obj;
295+
unsigned long flags = (unsigned long) sync_arg;
296+
return vmw_fence_obj_signaled((struct vmw_fence_obj *) sync_obj,
297+
(uint32_t) flags);
299298

300-
return vmw_seqno_passed(dev_priv, seqno);
301299
}
302300

303301
static int vmw_sync_obj_wait(void *sync_obj, void *sync_arg,
304302
bool lazy, bool interruptible)
305303
{
306-
struct vmw_private *dev_priv = (struct vmw_private *)sync_arg;
307-
uint32_t seqno = (unsigned long) sync_obj;
304+
unsigned long flags = (unsigned long) sync_arg;
308305

309-
return vmw_wait_seqno(dev_priv, false, seqno, false, 3*HZ);
306+
return vmw_fence_obj_wait((struct vmw_fence_obj *) sync_obj,
307+
(uint32_t) flags,
308+
lazy, interruptible,
309+
VMW_FENCE_WAIT_TIMEOUT);
310310
}
311311

312312
struct ttm_bo_driver vmw_bo_driver = {

drivers/gpu/drm/vmwgfx/vmwgfx_drv.c

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -82,12 +82,18 @@
8282
#define DRM_IOCTL_VMW_EXECBUF \
8383
DRM_IOW(DRM_COMMAND_BASE + DRM_VMW_EXECBUF, \
8484
struct drm_vmw_execbuf_arg)
85+
#define DRM_IOCTL_VMW_GET_3D_CAP \
86+
DRM_IOW(DRM_COMMAND_BASE + DRM_VMW_GET_3D_CAP, \
87+
struct drm_vmw_get_3d_cap_arg)
8588
#define DRM_IOCTL_VMW_FENCE_WAIT \
8689
DRM_IOWR(DRM_COMMAND_BASE + DRM_VMW_FENCE_WAIT, \
8790
struct drm_vmw_fence_wait_arg)
88-
#define DRM_IOCTL_VMW_GET_3D_CAP \
89-
DRM_IOW(DRM_COMMAND_BASE + DRM_VMW_GET_3D_CAP, \
90-
struct drm_vmw_get_3d_cap_arg)
91+
#define DRM_IOCTL_VMW_FENCE_SIGNALED \
92+
DRM_IOWR(DRM_COMMAND_BASE + DRM_VMW_FENCE_SIGNALED, \
93+
struct drm_vmw_fence_signaled_arg)
94+
#define DRM_IOCTL_VMW_FENCE_UNREF \
95+
DRM_IOW(DRM_COMMAND_BASE + DRM_VMW_FENCE_UNREF, \
96+
struct drm_vmw_fence_arg)
9197

9298
/**
9399
* The core DRM version of this macro doesn't account for
@@ -131,7 +137,12 @@ static struct drm_ioctl_desc vmw_ioctls[] = {
131137
DRM_AUTH | DRM_UNLOCKED),
132138
VMW_IOCTL_DEF(VMW_EXECBUF, vmw_execbuf_ioctl,
133139
DRM_AUTH | DRM_UNLOCKED),
134-
VMW_IOCTL_DEF(VMW_FENCE_WAIT, vmw_fence_wait_ioctl,
140+
VMW_IOCTL_DEF(VMW_FENCE_WAIT, vmw_fence_obj_wait_ioctl,
141+
DRM_AUTH | DRM_UNLOCKED),
142+
VMW_IOCTL_DEF(VMW_FENCE_SIGNALED,
143+
vmw_fence_obj_signaled_ioctl,
144+
DRM_AUTH | DRM_UNLOCKED),
145+
VMW_IOCTL_DEF(VMW_FENCE_UNREF, vmw_fence_obj_unref_ioctl,
135146
DRM_AUTH | DRM_UNLOCKED),
136147
VMW_IOCTL_DEF(VMW_GET_3D_CAP, vmw_get_cap_3d_ioctl,
137148
DRM_AUTH | DRM_UNLOCKED),
@@ -198,12 +209,14 @@ static int vmw_request_device(struct vmw_private *dev_priv)
198209
DRM_ERROR("Unable to initialize FIFO.\n");
199210
return ret;
200211
}
212+
vmw_fence_fifo_up(dev_priv->fman);
201213

202214
return 0;
203215
}
204216

205217
static void vmw_release_device(struct vmw_private *dev_priv)
206218
{
219+
vmw_fence_fifo_down(dev_priv->fman);
207220
vmw_fifo_release(dev_priv, &dev_priv->fifo);
208221
}
209222

@@ -434,6 +447,10 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
434447
goto out_no_device;
435448
}
436449
}
450+
451+
dev_priv->fman = vmw_fence_manager_init(dev_priv);
452+
if (unlikely(dev_priv->fman == NULL))
453+
goto out_no_fman;
437454
ret = vmw_kms_init(dev_priv);
438455
if (unlikely(ret != 0))
439456
goto out_no_kms;
@@ -475,6 +492,8 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
475492
vmw_overlay_close(dev_priv);
476493
vmw_kms_close(dev_priv);
477494
out_no_kms:
495+
vmw_fence_manager_takedown(dev_priv->fman);
496+
out_no_fman:
478497
if (dev_priv->stealth)
479498
pci_release_region(dev->pdev, 2);
480499
else
@@ -518,6 +537,7 @@ static int vmw_driver_unload(struct drm_device *dev)
518537
}
519538
vmw_kms_close(dev_priv);
520539
vmw_overlay_close(dev_priv);
540+
vmw_fence_manager_takedown(dev_priv->fman);
521541
if (dev_priv->stealth)
522542
pci_release_region(dev->pdev, 2);
523543
else

drivers/gpu/drm/vmwgfx/vmwgfx_drv.h

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
#include "ttm/ttm_lock.h"
3939
#include "ttm/ttm_execbuf_util.h"
4040
#include "ttm/ttm_module.h"
41+
#include "vmwgfx_fence.h"
4142

4243
#define VMWGFX_DRIVER_DATE "20100927"
4344
#define VMWGFX_DRIVER_MAJOR 1
@@ -53,6 +54,11 @@
5354
#define VMW_PL_GMR TTM_PL_PRIV0
5455
#define VMW_PL_FLAG_GMR TTM_PL_FLAG_PRIV0
5556

57+
#define VMW_RES_CONTEXT ttm_driver_type0
58+
#define VMW_RES_SURFACE ttm_driver_type1
59+
#define VMW_RES_STREAM ttm_driver_type2
60+
#define VMW_RES_FENCE ttm_driver_type3
61+
5662
struct vmw_fpriv {
5763
struct drm_master *locked_master;
5864
struct ttm_object_file *tfile;
@@ -245,6 +251,7 @@ struct vmw_private {
245251
atomic_t fifo_queue_waiters;
246252
uint32_t last_read_seqno;
247253
spinlock_t irq_lock;
254+
struct vmw_fence_manager *fman;
248255

249256
/*
250257
* Device state
@@ -456,8 +463,6 @@ extern int vmw_irq_postinstall(struct drm_device *dev);
456463
extern void vmw_irq_uninstall(struct drm_device *dev);
457464
extern bool vmw_seqno_passed(struct vmw_private *dev_priv,
458465
uint32_t seqno);
459-
extern int vmw_fence_wait_ioctl(struct drm_device *dev, void *data,
460-
struct drm_file *file_priv);
461466
extern int vmw_fallback_wait(struct vmw_private *dev_priv,
462467
bool lazy,
463468
bool fifo_idle,
@@ -466,7 +471,8 @@ extern int vmw_fallback_wait(struct vmw_private *dev_priv,
466471
unsigned long timeout);
467472
extern void vmw_update_seqno(struct vmw_private *dev_priv,
468473
struct vmw_fifo_state *fifo_state);
469-
474+
extern void vmw_seqno_waiter_add(struct vmw_private *dev_priv);
475+
extern void vmw_seqno_waiter_remove(struct vmw_private *dev_priv);
470476

471477
/**
472478
* 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
572578
return NULL;
573579
}
574580

581+
static inline struct ttm_mem_global *vmw_mem_glob(struct vmw_private *dev_priv)
582+
{
583+
return (struct ttm_mem_global *) dev_priv->mem_global_ref.object;
584+
}
575585
#endif

drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c

Lines changed: 91 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,7 @@ static int vmw_translate_guest_ptr(struct vmw_private *dev_priv,
256256
val_buf = &sw_context->val_bufs[cur_validate_node];
257257
val_buf->bo = ttm_bo_reference(bo);
258258
val_buf->usage = TTM_USAGE_READWRITE;
259-
val_buf->new_sync_obj_arg = (void *) dev_priv;
259+
val_buf->new_sync_obj_arg = (void *) DRM_VMW_FENCE_FLAG_EXEC;
260260
list_add_tail(&val_buf->head, &sw_context->validate_nodes);
261261
++sw_context->cur_val_buf;
262262
}
@@ -321,7 +321,6 @@ static int vmw_cmd_wait_query(struct vmw_private *dev_priv,
321321
return 0;
322322
}
323323

324-
325324
static int vmw_cmd_dma(struct vmw_private *dev_priv,
326325
struct vmw_sw_context *sw_context,
327326
SVGA3dCmdHeader *header)
@@ -676,6 +675,50 @@ static int vmw_resize_cmd_bounce(struct vmw_sw_context *sw_context,
676675
return 0;
677676
}
678677

678+
/**
679+
* vmw_execbuf_fence_commands - create and submit a command stream fence
680+
*
681+
* Creates a fence object and submits a command stream marker.
682+
* If this fails for some reason, We sync the fifo and return NULL.
683+
* It is then safe to fence buffers with a NULL pointer.
684+
*/
685+
686+
int vmw_execbuf_fence_commands(struct drm_file *file_priv,
687+
struct vmw_private *dev_priv,
688+
struct vmw_fence_obj **p_fence,
689+
uint32_t *p_handle)
690+
{
691+
uint32_t sequence;
692+
int ret;
693+
bool synced = false;
694+
695+
696+
ret = vmw_fifo_send_fence(dev_priv, &sequence);
697+
if (unlikely(ret != 0)) {
698+
DRM_ERROR("Fence submission error. Syncing.\n");
699+
synced = true;
700+
}
701+
702+
if (p_handle != NULL)
703+
ret = vmw_user_fence_create(file_priv, dev_priv->fman,
704+
sequence,
705+
DRM_VMW_FENCE_FLAG_EXEC,
706+
p_fence, p_handle);
707+
else
708+
ret = vmw_fence_create(dev_priv->fman, sequence,
709+
DRM_VMW_FENCE_FLAG_EXEC,
710+
p_fence);
711+
712+
if (unlikely(ret != 0 && !synced)) {
713+
(void) vmw_fallback_wait(dev_priv, false, false,
714+
sequence, false,
715+
VMW_FENCE_WAIT_TIMEOUT);
716+
*p_fence = NULL;
717+
}
718+
719+
return 0;
720+
}
721+
679722
int vmw_execbuf_ioctl(struct drm_device *dev, void *data,
680723
struct drm_file *file_priv)
681724
{
@@ -686,9 +729,10 @@ int vmw_execbuf_ioctl(struct drm_device *dev, void *data,
686729
int ret;
687730
void *user_cmd;
688731
void *cmd;
689-
uint32_t seqno;
690732
struct vmw_sw_context *sw_context = &dev_priv->ctx;
691733
struct vmw_master *vmaster = vmw_master(file_priv->master);
734+
struct vmw_fence_obj *fence;
735+
uint32_t handle;
692736

693737
ret = ttm_read_lock(&vmaster->lock, true);
694738
if (unlikely(ret != 0))
@@ -755,34 +799,60 @@ int vmw_execbuf_ioctl(struct drm_device *dev, void *data,
755799
memcpy(cmd, sw_context->cmd_bounce, arg->command_size);
756800
vmw_fifo_commit(dev_priv, arg->command_size);
757801

758-
ret = vmw_fifo_send_fence(dev_priv, &seqno);
759-
760-
ttm_eu_fence_buffer_objects(&sw_context->validate_nodes,
761-
(void *)(unsigned long) seqno);
762-
vmw_clear_validations(sw_context);
763-
mutex_unlock(&dev_priv->cmdbuf_mutex);
764-
802+
user_fence_rep = (struct drm_vmw_fence_rep __user *)
803+
(unsigned long)arg->fence_rep;
804+
ret = vmw_execbuf_fence_commands(file_priv, dev_priv,
805+
&fence,
806+
(user_fence_rep) ? &handle : NULL);
765807
/*
766808
* This error is harmless, because if fence submission fails,
767-
* vmw_fifo_send_fence will sync.
809+
* vmw_fifo_send_fence will sync. The error will be propagated to
810+
* user-space in @fence_rep
768811
*/
769812

770813
if (ret != 0)
771814
DRM_ERROR("Fence submission error. Syncing.\n");
772815

773-
fence_rep.error = ret;
774-
fence_rep.fence_seq = (uint64_t) seqno;
775-
fence_rep.pad64 = 0;
816+
ttm_eu_fence_buffer_objects(&sw_context->validate_nodes,
817+
(void *) fence);
776818

777-
user_fence_rep = (struct drm_vmw_fence_rep __user *)
778-
(unsigned long)arg->fence_rep;
819+
vmw_clear_validations(sw_context);
820+
mutex_unlock(&dev_priv->cmdbuf_mutex);
779821

780-
/*
781-
* copy_to_user errors will be detected by user space not
782-
* seeing fence_rep::error filled in.
783-
*/
822+
if (user_fence_rep) {
823+
fence_rep.error = ret;
824+
fence_rep.handle = handle;
825+
fence_rep.seqno = fence->seqno;
826+
vmw_update_seqno(dev_priv, &dev_priv->fifo);
827+
fence_rep.passed_seqno = dev_priv->last_read_seqno;
828+
829+
/*
830+
* copy_to_user errors will be detected by user space not
831+
* seeing fence_rep::error filled in. Typically
832+
* user-space would have pre-set that member to -EFAULT.
833+
*/
834+
ret = copy_to_user(user_fence_rep, &fence_rep,
835+
sizeof(fence_rep));
836+
837+
/*
838+
* User-space lost the fence object. We need to sync
839+
* and unreference the handle.
840+
*/
841+
if (unlikely(ret != 0) && (fence_rep.error == 0)) {
842+
BUG_ON(fence == NULL);
843+
844+
ttm_ref_object_base_unref(vmw_fpriv(file_priv)->tfile,
845+
handle, TTM_REF_USAGE);
846+
DRM_ERROR("Fence copy error. Syncing.\n");
847+
(void) vmw_fence_obj_wait(fence,
848+
fence->signal_mask,
849+
false, false,
850+
VMW_FENCE_WAIT_TIMEOUT);
851+
}
852+
}
784853

785-
ret = copy_to_user(user_fence_rep, &fence_rep, sizeof(fence_rep));
854+
if (likely(fence != NULL))
855+
vmw_fence_obj_unreference(&fence);
786856

787857
vmw_kms_cursor_post_execbuf(dev_priv);
788858
ttm_read_unlock(&vmaster->lock);

0 commit comments

Comments
 (0)