On Sun, Aug 7, 2011 at 4:39 PM, Marek Ol??k <maraeo at gmail.com> wrote: > Sometimes we want to know whether a buffer is busy and wait for it (bo_wait). > However, sometimes it would be more useful to be able to query whether > a buffer is busy and being either read or written, and wait until it's stopped > being either read or written. The point of this is to be able to avoid > unnecessary waiting, e.g. if a GPU has written something to a buffer and is > now > reading that buffer, and a CPU wants to map that buffer for read, it needs to > only wait for the last write. If there were no write, there wouldn't be any > waiting needed. > > This, or course, requires user space drivers to send read/write flags > with each relocation (like we have read/write domains in radeon, so we can > actually use those for something useful now). > > Now how this patch works: > > The read/write flags should passed to ttm_validate_buffer. TTM maintains > separate sync objects of the last read and write for each buffer, in addition > to the sync object of the last use of a buffer. ttm_bo_wait then operates > with one the sync objects.
Just minor comment for extra safety see below, otherwise: Reviewed-by: Jerome Glisse <jglisse at redhat.com> > Signed-off-by: Marek Ol??k <maraeo at gmail.com> > --- > ?drivers/gpu/drm/nouveau/nouveau_bo.c ? ?| ? ?3 +- > ?drivers/gpu/drm/nouveau/nouveau_gem.c ? | ? ?5 +- > ?drivers/gpu/drm/radeon/radeon_cs.c ? ? ?| ? ?1 + > ?drivers/gpu/drm/radeon/radeon_object.h ?| ? ?2 +- > ?drivers/gpu/drm/ttm/ttm_bo.c ? ? ? ? ? ?| ? 97 ++++++++++++++++++++++-------- > ?drivers/gpu/drm/ttm/ttm_bo_util.c ? ? ? | ? 26 +++++++-- > ?drivers/gpu/drm/ttm/ttm_bo_vm.c ? ? ? ? | ? ?2 +- > ?drivers/gpu/drm/ttm/ttm_execbuf_util.c ?| ? 17 +++++- > ?drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c | ? ?1 + > ?include/drm/ttm/ttm_bo_api.h ? ? ? ? ? ?| ? 16 +++++- > ?include/drm/ttm/ttm_execbuf_util.h ? ? ?| ? ?6 ++ > ?11 files changed, 137 insertions(+), 39 deletions(-) > > diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c > b/drivers/gpu/drm/nouveau/nouveau_bo.c > index 890d50e..e87e24b 100644 > --- a/drivers/gpu/drm/nouveau/nouveau_bo.c > +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c > @@ -1104,7 +1104,8 @@ nouveau_bo_vma_del(struct nouveau_bo *nvbo, struct > nouveau_vma *vma) > ? ? ? ?if (vma->node) { > ? ? ? ? ? ? ? ?if (nvbo->bo.mem.mem_type != TTM_PL_SYSTEM) { > ? ? ? ? ? ? ? ? ? ? ? ?spin_lock(&nvbo->bo.bdev->fence_lock); > - ? ? ? ? ? ? ? ? ? ? ? ttm_bo_wait(&nvbo->bo, false, false, false); > + ? ? ? ? ? ? ? ? ? ? ? ttm_bo_wait(&nvbo->bo, false, false, false, > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? TTM_USAGE_READWRITE); > ? ? ? ? ? ? ? ? ? ? ? ?spin_unlock(&nvbo->bo.bdev->fence_lock); > ? ? ? ? ? ? ? ? ? ? ? ?nouveau_vm_unmap(vma); > ? ? ? ? ? ? ? ?} > diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c > b/drivers/gpu/drm/nouveau/nouveau_gem.c > index 5f0bc57..322bf62 100644 > --- a/drivers/gpu/drm/nouveau/nouveau_gem.c > +++ b/drivers/gpu/drm/nouveau/nouveau_gem.c > @@ -589,7 +589,8 @@ nouveau_gem_pushbuf_reloc_apply(struct drm_device *dev, > ? ? ? ? ? ? ? ?} > > ? ? ? ? ? ? ? ?spin_lock(&nvbo->bo.bdev->fence_lock); > - ? ? ? ? ? ? ? ret = ttm_bo_wait(&nvbo->bo, false, false, false); > + ? ? ? ? ? ? ? ret = ttm_bo_wait(&nvbo->bo, false, false, false, > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? TTM_USAGE_READWRITE); > ? ? ? ? ? ? ? ?spin_unlock(&nvbo->bo.bdev->fence_lock); > ? ? ? ? ? ? ? ?if (ret) { > ? ? ? ? ? ? ? ? ? ? ? ?NV_ERROR(dev, "reloc wait_idle failed: %d\n", ret); > @@ -825,7 +826,7 @@ nouveau_gem_ioctl_cpu_prep(struct drm_device *dev, void > *data, > ? ? ? ?nvbo = nouveau_gem_object(gem); > > ? ? ? ?spin_lock(&nvbo->bo.bdev->fence_lock); > - ? ? ? ret = ttm_bo_wait(&nvbo->bo, true, true, no_wait); > + ? ? ? ret = ttm_bo_wait(&nvbo->bo, true, true, no_wait, > TTM_USAGE_READWRITE); > ? ? ? ?spin_unlock(&nvbo->bo.bdev->fence_lock); > ? ? ? ?drm_gem_object_unreference_unlocked(gem); > ? ? ? ?return ret; > diff --git a/drivers/gpu/drm/radeon/radeon_cs.c > b/drivers/gpu/drm/radeon/radeon_cs.c > index fae00c0..14e8531 100644 > --- a/drivers/gpu/drm/radeon/radeon_cs.c > +++ b/drivers/gpu/drm/radeon/radeon_cs.c > @@ -80,6 +80,7 @@ int radeon_cs_parser_relocs(struct radeon_cs_parser *p) > ? ? ? ? ? ? ? ? ? ? ? ?p->relocs[i].lobj.wdomain = r->write_domain; > ? ? ? ? ? ? ? ? ? ? ? ?p->relocs[i].lobj.rdomain = r->read_domains; > ? ? ? ? ? ? ? ? ? ? ? ?p->relocs[i].lobj.tv.bo = &p->relocs[i].robj->tbo; > + ? ? ? ? ? ? ? ? ? ? ? p->relocs[i].lobj.tv.usage = TTM_USAGE_READWRITE; > ? ? ? ? ? ? ? ? ? ? ? ?p->relocs[i].handle = r->handle; > ? ? ? ? ? ? ? ? ? ? ? ?p->relocs[i].flags = r->flags; > ? ? ? ? ? ? ? ? ? ? ? ?radeon_bo_list_add_object(&p->relocs[i].lobj, > diff --git a/drivers/gpu/drm/radeon/radeon_object.h > b/drivers/gpu/drm/radeon/radeon_object.h > index ede6c13..e9dc8b2 100644 > --- a/drivers/gpu/drm/radeon/radeon_object.h > +++ b/drivers/gpu/drm/radeon/radeon_object.h > @@ -130,7 +130,7 @@ static inline int radeon_bo_wait(struct radeon_bo *bo, > u32 *mem_type, > ? ? ? ?if (mem_type) > ? ? ? ? ? ? ? ?*mem_type = bo->tbo.mem.mem_type; > ? ? ? ?if (bo->tbo.sync_obj) > - ? ? ? ? ? ? ? r = ttm_bo_wait(&bo->tbo, true, true, no_wait); > + ? ? ? ? ? ? ? r = ttm_bo_wait(&bo->tbo, true, true, no_wait, > TTM_USAGE_READWRITE); > ? ? ? ?spin_unlock(&bo->tbo.bdev->fence_lock); > ? ? ? ?ttm_bo_unreserve(&bo->tbo); > ? ? ? ?return r; > diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c > index 56619f6..bb8c86d 100644 > --- a/drivers/gpu/drm/ttm/ttm_bo.c > +++ b/drivers/gpu/drm/ttm/ttm_bo.c > @@ -494,7 +494,7 @@ static void ttm_bo_cleanup_refs_or_queue(struct > ttm_buffer_object *bo) > ? ? ? ?int ret; > > ? ? ? ?spin_lock(&bdev->fence_lock); > - ? ? ? (void) ttm_bo_wait(bo, false, false, true); > + ? ? ? (void) ttm_bo_wait(bo, false, false, true, TTM_USAGE_READWRITE); > ? ? ? ?if (!bo->sync_obj) { > > ? ? ? ? ? ? ? ?spin_lock(&glob->lru_lock); > @@ -562,7 +562,8 @@ static int ttm_bo_cleanup_refs(struct ttm_buffer_object > *bo, > > ?retry: > ? ? ? ?spin_lock(&bdev->fence_lock); > - ? ? ? ret = ttm_bo_wait(bo, false, interruptible, no_wait_gpu); > + ? ? ? ret = ttm_bo_wait(bo, false, interruptible, no_wait_gpu, > + ? ? ? ? ? ? ? ? ? ? ? ? TTM_USAGE_READWRITE); > ? ? ? ?spin_unlock(&bdev->fence_lock); > > ? ? ? ?if (unlikely(ret != 0)) > @@ -721,7 +722,8 @@ static int ttm_bo_evict(struct ttm_buffer_object *bo, > bool interruptible, > ? ? ? ?int ret = 0; > > ? ? ? ?spin_lock(&bdev->fence_lock); > - ? ? ? ret = ttm_bo_wait(bo, false, interruptible, no_wait_gpu); > + ? ? ? ret = ttm_bo_wait(bo, false, interruptible, no_wait_gpu, > + ? ? ? ? ? ? ? ? ? ? ? ? TTM_USAGE_READWRITE); > ? ? ? ?spin_unlock(&bdev->fence_lock); > > ? ? ? ?if (unlikely(ret != 0)) { > @@ -1068,7 +1070,8 @@ int ttm_bo_move_buffer(struct ttm_buffer_object *bo, > ? ? ? ? * instead of doing it here. > ? ? ? ? */ > ? ? ? ?spin_lock(&bdev->fence_lock); > - ? ? ? ret = ttm_bo_wait(bo, false, interruptible, no_wait_gpu); > + ? ? ? ret = ttm_bo_wait(bo, false, interruptible, no_wait_gpu, > + ? ? ? ? ? ? ? ? ? ? ? ? TTM_USAGE_READWRITE); > ? ? ? ?spin_unlock(&bdev->fence_lock); > ? ? ? ?if (ret) > ? ? ? ? ? ? ? ?return ret; > @@ -1688,34 +1691,83 @@ out_unlock: > ? ? ? ?return ret; > ?} > > +static void ttm_bo_unref_sync_obj_locked(struct ttm_buffer_object *bo, > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?void *sync_obj, > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?void **extra_sync_obj) > +{ > + ? ? ? struct ttm_bo_device *bdev = bo->bdev; > + ? ? ? struct ttm_bo_driver *driver = bdev->driver; > + ? ? ? void *tmp_obj = NULL, *tmp_obj_read = NULL, *tmp_obj_write = NULL; > + > + ? ? ? /* We must unref the sync obj wherever it's ref'd. > + ? ? ? ?* Note that if we unref bo->sync_obj, we can unref both the read > + ? ? ? ?* and write sync objs too, because they can't be newer than > + ? ? ? ?* bo->sync_obj, so they are no longer relevant. */ > + ? ? ? if (sync_obj == bo->sync_obj || > + ? ? ? ? ? sync_obj == bo->sync_obj_read) { > + ? ? ? ? ? ? ? tmp_obj_read = bo->sync_obj_read; > + ? ? ? ? ? ? ? bo->sync_obj_read = NULL; > + ? ? ? } > + ? ? ? if (sync_obj == bo->sync_obj || > + ? ? ? ? ? sync_obj == bo->sync_obj_write) { > + ? ? ? ? ? ? ? tmp_obj_write = bo->sync_obj_write; > + ? ? ? ? ? ? ? bo->sync_obj_write = NULL; > + ? ? ? } > + ? ? ? if (sync_obj == bo->sync_obj) { > + ? ? ? ? ? ? ? tmp_obj = bo->sync_obj; > + ? ? ? ? ? ? ? bo->sync_obj = NULL; > + ? ? ? } > + > + ? ? ? clear_bit(TTM_BO_PRIV_FLAG_MOVING, &bo->priv_flags); > + ? ? ? spin_unlock(&bdev->fence_lock); > + ? ? ? if (tmp_obj) > + ? ? ? ? ? ? ? driver->sync_obj_unref(&tmp_obj); > + ? ? ? if (tmp_obj_read) > + ? ? ? ? ? ? ? driver->sync_obj_unref(&tmp_obj_read); > + ? ? ? if (tmp_obj_write) > + ? ? ? ? ? ? ? driver->sync_obj_unref(&tmp_obj_write); > + ? ? ? if (extra_sync_obj) > + ? ? ? ? ? ? ? driver->sync_obj_unref(extra_sync_obj); > + ? ? ? spin_lock(&bdev->fence_lock); > +} > + > ?int ttm_bo_wait(struct ttm_buffer_object *bo, > - ? ? ? ? ? ? ? bool lazy, bool interruptible, bool no_wait) > + ? ? ? ? ? ? ? bool lazy, bool interruptible, bool no_wait, > + ? ? ? ? ? ? ? enum ttm_buffer_usage usage) > ?{ > ? ? ? ?struct ttm_bo_driver *driver = bo->bdev->driver; > ? ? ? ?struct ttm_bo_device *bdev = bo->bdev; > ? ? ? ?void *sync_obj; > ? ? ? ?void *sync_obj_arg; > ? ? ? ?int ret = 0; > + ? ? ? void **bo_sync_obj; > > - ? ? ? if (likely(bo->sync_obj == NULL)) > + ? ? ? switch (usage) { > + ? ? ? case TTM_USAGE_READ: > + ? ? ? ? ? ? ? bo_sync_obj = &bo->sync_obj_read; > + ? ? ? ? ? ? ? break; > + ? ? ? case TTM_USAGE_WRITE: > + ? ? ? ? ? ? ? bo_sync_obj = &bo->sync_obj_write; > + ? ? ? ? ? ? ? break; > + ? ? ? case TTM_USAGE_READWRITE: > + ? ? ? default: > + ? ? ? ? ? ? ? bo_sync_obj = &bo->sync_obj; > + ? ? ? } > + > + ? ? ? if (likely(*bo_sync_obj == NULL)) > ? ? ? ? ? ? ? ?return 0; > > - ? ? ? while (bo->sync_obj) { > + ? ? ? while (*bo_sync_obj) { > > - ? ? ? ? ? ? ? if (driver->sync_obj_signaled(bo->sync_obj, > bo->sync_obj_arg)) { > - ? ? ? ? ? ? ? ? ? ? ? void *tmp_obj = bo->sync_obj; > - ? ? ? ? ? ? ? ? ? ? ? bo->sync_obj = NULL; > - ? ? ? ? ? ? ? ? ? ? ? clear_bit(TTM_BO_PRIV_FLAG_MOVING, &bo->priv_flags); > - ? ? ? ? ? ? ? ? ? ? ? spin_unlock(&bdev->fence_lock); > - ? ? ? ? ? ? ? ? ? ? ? driver->sync_obj_unref(&tmp_obj); > - ? ? ? ? ? ? ? ? ? ? ? spin_lock(&bdev->fence_lock); > + ? ? ? ? ? ? ? if (driver->sync_obj_signaled(*bo_sync_obj, > bo->sync_obj_arg)) { > + ? ? ? ? ? ? ? ? ? ? ? ttm_bo_unref_sync_obj_locked(bo, *bo_sync_obj, NULL); > ? ? ? ? ? ? ? ? ? ? ? ?continue; > ? ? ? ? ? ? ? ?} > > ? ? ? ? ? ? ? ?if (no_wait) > ? ? ? ? ? ? ? ? ? ? ? ?return -EBUSY; > > - ? ? ? ? ? ? ? sync_obj = driver->sync_obj_ref(bo->sync_obj); > + ? ? ? ? ? ? ? sync_obj = driver->sync_obj_ref(*bo_sync_obj); > ? ? ? ? ? ? ? ?sync_obj_arg = bo->sync_obj_arg; > ? ? ? ? ? ? ? ?spin_unlock(&bdev->fence_lock); > ? ? ? ? ? ? ? ?ret = driver->sync_obj_wait(sync_obj, sync_obj_arg, > @@ -1726,16 +1778,9 @@ int ttm_bo_wait(struct ttm_buffer_object *bo, > ? ? ? ? ? ? ? ? ? ? ? ?return ret; > ? ? ? ? ? ? ? ?} > ? ? ? ? ? ? ? ?spin_lock(&bdev->fence_lock); > - ? ? ? ? ? ? ? if (likely(bo->sync_obj == sync_obj && > + ? ? ? ? ? ? ? if (likely(*bo_sync_obj == sync_obj && > ? ? ? ? ? ? ? ? ? ? ? ? ? bo->sync_obj_arg == sync_obj_arg)) { > - ? ? ? ? ? ? ? ? ? ? ? void *tmp_obj = bo->sync_obj; > - ? ? ? ? ? ? ? ? ? ? ? bo->sync_obj = NULL; > - ? ? ? ? ? ? ? ? ? ? ? clear_bit(TTM_BO_PRIV_FLAG_MOVING, > - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? &bo->priv_flags); > - ? ? ? ? ? ? ? ? ? ? ? spin_unlock(&bdev->fence_lock); > - ? ? ? ? ? ? ? ? ? ? ? driver->sync_obj_unref(&sync_obj); > - ? ? ? ? ? ? ? ? ? ? ? driver->sync_obj_unref(&tmp_obj); > - ? ? ? ? ? ? ? ? ? ? ? spin_lock(&bdev->fence_lock); > + ? ? ? ? ? ? ? ? ? ? ? ttm_bo_unref_sync_obj_locked(bo, *bo_sync_obj, > &sync_obj); > ? ? ? ? ? ? ? ?} else { > ? ? ? ? ? ? ? ? ? ? ? ?spin_unlock(&bdev->fence_lock); > ? ? ? ? ? ? ? ? ? ? ? ?driver->sync_obj_unref(&sync_obj); > @@ -1759,7 +1804,7 @@ int ttm_bo_synccpu_write_grab(struct ttm_buffer_object > *bo, bool no_wait) > ? ? ? ?if (unlikely(ret != 0)) > ? ? ? ? ? ? ? ?return ret; > ? ? ? ?spin_lock(&bdev->fence_lock); > - ? ? ? ret = ttm_bo_wait(bo, false, true, no_wait); > + ? ? ? ret = ttm_bo_wait(bo, false, true, no_wait, TTM_USAGE_READWRITE); > ? ? ? ?spin_unlock(&bdev->fence_lock); > ? ? ? ?if (likely(ret == 0)) > ? ? ? ? ? ? ? ?atomic_inc(&bo->cpu_writers); > @@ -1833,7 +1878,7 @@ static int ttm_bo_swapout(struct ttm_mem_shrink *shrink) > ? ? ? ? */ > > ? ? ? ?spin_lock(&bo->bdev->fence_lock); > - ? ? ? ret = ttm_bo_wait(bo, false, false, false); > + ? ? ? ret = ttm_bo_wait(bo, false, false, false, TTM_USAGE_READWRITE); > ? ? ? ?spin_unlock(&bo->bdev->fence_lock); > > ? ? ? ?if (unlikely(ret != 0)) > diff --git a/drivers/gpu/drm/ttm/ttm_bo_util.c > b/drivers/gpu/drm/ttm/ttm_bo_util.c > index 77dbf40..0399573 100644 > --- a/drivers/gpu/drm/ttm/ttm_bo_util.c > +++ b/drivers/gpu/drm/ttm/ttm_bo_util.c > @@ -436,6 +436,8 @@ static int ttm_buffer_object_transfer(struct > ttm_buffer_object *bo, > ? ? ? ?atomic_set(&fbo->cpu_writers, 0); > > ? ? ? ?fbo->sync_obj = driver->sync_obj_ref(bo->sync_obj); > + ? ? ? fbo->sync_obj_read = driver->sync_obj_ref(bo->sync_obj_read); > + ? ? ? fbo->sync_obj_write = driver->sync_obj_ref(bo->sync_obj_write); > ? ? ? ?kref_init(&fbo->list_kref); > ? ? ? ?kref_init(&fbo->kref); > ? ? ? ?fbo->destroy = &ttm_transfered_destroy; > @@ -618,20 +620,30 @@ int ttm_bo_move_accel_cleanup(struct ttm_buffer_object > *bo, > ? ? ? ?struct ttm_mem_reg *old_mem = &bo->mem; > ? ? ? ?int ret; > ? ? ? ?struct ttm_buffer_object *ghost_obj; > - ? ? ? void *tmp_obj = NULL; > + ? ? ? void *tmp_obj = NULL, *tmp_obj_read = NULL, *tmp_obj_write = NULL; > > ? ? ? ?spin_lock(&bdev->fence_lock); > - ? ? ? if (bo->sync_obj) { > + ? ? ? if (bo->sync_obj) > ? ? ? ? ? ? ? ?tmp_obj = bo->sync_obj; > - ? ? ? ? ? ? ? bo->sync_obj = NULL; > - ? ? ? } > + ? ? ? if (bo->sync_obj_read) > + ? ? ? ? ? ? ? tmp_obj_read = bo->sync_obj_read; > + ? ? ? if (bo->sync_obj_write) > + ? ? ? ? ? ? ? tmp_obj_write = bo->sync_obj_write; > + > ? ? ? ?bo->sync_obj = driver->sync_obj_ref(sync_obj); > + ? ? ? bo->sync_obj_read = driver->sync_obj_ref(sync_obj); > + ? ? ? bo->sync_obj_write = driver->sync_obj_ref(sync_obj); > ? ? ? ?bo->sync_obj_arg = sync_obj_arg; > ? ? ? ?if (evict) { > - ? ? ? ? ? ? ? ret = ttm_bo_wait(bo, false, false, false); > + ? ? ? ? ? ? ? ret = ttm_bo_wait(bo, false, false, false, > + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? TTM_USAGE_READWRITE); > ? ? ? ? ? ? ? ?spin_unlock(&bdev->fence_lock); > ? ? ? ? ? ? ? ?if (tmp_obj) > ? ? ? ? ? ? ? ? ? ? ? ?driver->sync_obj_unref(&tmp_obj); > + ? ? ? ? ? ? ? if (tmp_obj_read) > + ? ? ? ? ? ? ? ? ? ? ? driver->sync_obj_unref(&tmp_obj_read); > + ? ? ? ? ? ? ? if (tmp_obj_write) > + ? ? ? ? ? ? ? ? ? ? ? driver->sync_obj_unref(&tmp_obj_write); > ? ? ? ? ? ? ? ?if (ret) > ? ? ? ? ? ? ? ? ? ? ? ?return ret; > > @@ -655,6 +667,10 @@ int ttm_bo_move_accel_cleanup(struct ttm_buffer_object > *bo, > ? ? ? ? ? ? ? ?spin_unlock(&bdev->fence_lock); > ? ? ? ? ? ? ? ?if (tmp_obj) > ? ? ? ? ? ? ? ? ? ? ? ?driver->sync_obj_unref(&tmp_obj); > + ? ? ? ? ? ? ? if (tmp_obj_read) > + ? ? ? ? ? ? ? ? ? ? ? driver->sync_obj_unref(&tmp_obj_read); > + ? ? ? ? ? ? ? if (tmp_obj_write) > + ? ? ? ? ? ? ? ? ? ? ? driver->sync_obj_unref(&tmp_obj_write); > > ? ? ? ? ? ? ? ?ret = ttm_buffer_object_transfer(bo, &ghost_obj); > ? ? ? ? ? ? ? ?if (ret) > diff --git a/drivers/gpu/drm/ttm/ttm_bo_vm.c b/drivers/gpu/drm/ttm/ttm_bo_vm.c > index 221b924..ff1e26f 100644 > --- a/drivers/gpu/drm/ttm/ttm_bo_vm.c > +++ b/drivers/gpu/drm/ttm/ttm_bo_vm.c > @@ -122,7 +122,7 @@ static int ttm_bo_vm_fault(struct vm_area_struct *vma, > struct vm_fault *vmf) > > ? ? ? ?spin_lock(&bdev->fence_lock); > ? ? ? ?if (test_bit(TTM_BO_PRIV_FLAG_MOVING, &bo->priv_flags)) { > - ? ? ? ? ? ? ? ret = ttm_bo_wait(bo, false, true, false); > + ? ? ? ? ? ? ? ret = ttm_bo_wait(bo, false, true, false, > TTM_USAGE_READWRITE); > ? ? ? ? ? ? ? ?spin_unlock(&bdev->fence_lock); > ? ? ? ? ? ? ? ?if (unlikely(ret != 0)) { > ? ? ? ? ? ? ? ? ? ? ? ?retval = (ret != -ERESTARTSYS) ? > diff --git a/drivers/gpu/drm/ttm/ttm_execbuf_util.c > b/drivers/gpu/drm/ttm/ttm_execbuf_util.c > index 3832fe1..0438296 100644 > --- a/drivers/gpu/drm/ttm/ttm_execbuf_util.c > +++ b/drivers/gpu/drm/ttm/ttm_execbuf_util.c > @@ -223,6 +223,14 @@ void ttm_eu_fence_buffer_objects(struct list_head *list, > void *sync_obj) > ? ? ? ? ? ? ? ?bo = entry->bo; > ? ? ? ? ? ? ? ?entry->old_sync_obj = bo->sync_obj; Here we should set entry->old_sync_obj_read & entry->old_sync_obj_write to NULL so we don't get bite by uninitialized memory (if caller fail or forget to do so) > ? ? ? ? ? ? ? ?bo->sync_obj = driver->sync_obj_ref(sync_obj); > + ? ? ? ? ? ? ? if (entry->usage & TTM_USAGE_READ) { > + ? ? ? ? ? ? ? ? ? ? ? entry->old_sync_obj_read = bo->sync_obj_read; > + ? ? ? ? ? ? ? ? ? ? ? bo->sync_obj_read = driver->sync_obj_ref(sync_obj); > + ? ? ? ? ? ? ? } > + ? ? ? ? ? ? ? if (entry->usage & TTM_USAGE_WRITE) { > + ? ? ? ? ? ? ? ? ? ? ? entry->old_sync_obj_write = bo->sync_obj_write; > + ? ? ? ? ? ? ? ? ? ? ? bo->sync_obj_write = driver->sync_obj_ref(sync_obj); > + ? ? ? ? ? ? ? } > ? ? ? ? ? ? ? ?bo->sync_obj_arg = entry->new_sync_obj_arg; > ? ? ? ? ? ? ? ?ttm_bo_unreserve_locked(bo); > ? ? ? ? ? ? ? ?entry->reserved = false; > @@ -231,8 +239,15 @@ void ttm_eu_fence_buffer_objects(struct list_head *list, > void *sync_obj) > ? ? ? ?spin_unlock(&bdev->fence_lock); > > ? ? ? ?list_for_each_entry(entry, list, head) { > - ? ? ? ? ? ? ? if (entry->old_sync_obj) > + ? ? ? ? ? ? ? if (entry->old_sync_obj) { > ? ? ? ? ? ? ? ? ? ? ? ?driver->sync_obj_unref(&entry->old_sync_obj); > + ? ? ? ? ? ? ? } > + ? ? ? ? ? ? ? if (entry->old_sync_obj_read) { > + ? ? ? ? ? ? ? ? ? ? ? driver->sync_obj_unref(&entry->old_sync_obj_read); > + ? ? ? ? ? ? ? } > + ? ? ? ? ? ? ? if (entry->old_sync_obj_write) { > + ? ? ? ? ? ? ? ? ? ? ? driver->sync_obj_unref(&entry->old_sync_obj_write); > + ? ? ? ? ? ? ? } > ? ? ? ?} > ?} > ?EXPORT_SYMBOL(ttm_eu_fence_buffer_objects); > diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c > b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c > index 41b95ed..8ca3ddb 100644 > --- a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c > +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c > @@ -224,6 +224,7 @@ static int vmw_translate_guest_ptr(struct vmw_private > *dev_priv, > ? ? ? ?if (unlikely(cur_validate_node == sw_context->cur_val_buf)) { > ? ? ? ? ? ? ? ?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; > ? ? ? ? ? ? ? ?list_add_tail(&val_buf->head, &sw_context->validate_nodes); > ? ? ? ? ? ? ? ?++sw_context->cur_val_buf; > diff --git a/include/drm/ttm/ttm_bo_api.h b/include/drm/ttm/ttm_bo_api.h > index 42e3469..da957bf 100644 > --- a/include/drm/ttm/ttm_bo_api.h > +++ b/include/drm/ttm/ttm_bo_api.h > @@ -44,6 +44,11 @@ struct ttm_bo_device; > > ?struct drm_mm_node; > > +enum ttm_buffer_usage { > + ? ?TTM_USAGE_READ = 1, > + ? ?TTM_USAGE_WRITE = 2, > + ? ?TTM_USAGE_READWRITE = TTM_USAGE_READ | TTM_USAGE_WRITE > +}; > > ?/** > ?* struct ttm_placement > @@ -174,7 +179,10 @@ struct ttm_tt; > ?* the bo_device::lru_lock. > ?* @reserved: Deadlock-free lock used for synchronization state transitions. > ?* @sync_obj_arg: Opaque argument to synchronization object function. > - * @sync_obj: Pointer to a synchronization object. > + * @sync_obj: Pointer to a synchronization object of a last read or write, > + * whichever is later. > + * @sync_obj_read: Pointer to a synchronization object of a last read. > + * @sync_obj_write: Pointer to a synchronization object of a last write. > ?* @priv_flags: Flags describing buffer object internal state. > ?* @vm_rb: Rb node for the vm rb tree. > ?* @vm_node: Address space manager node. > @@ -258,6 +266,8 @@ struct ttm_buffer_object { > > ? ? ? ?void *sync_obj_arg; > ? ? ? ?void *sync_obj; > + ? ? ? void *sync_obj_read; > + ? ? ? void *sync_obj_write; > ? ? ? ?unsigned long priv_flags; > > ? ? ? ?/** > @@ -325,6 +335,7 @@ ttm_bo_reference(struct ttm_buffer_object *bo) > ?* @bo: ?The buffer object. > ?* @interruptible: ?Use interruptible wait. > ?* @no_wait: ?Return immediately if buffer is busy. > + * @usage: ?Whether to wait for the last read and/or the last write. > ?* > ?* This function must be called with the bo::mutex held, and makes > ?* sure any previous rendering to the buffer is completed. > @@ -334,7 +345,8 @@ ttm_bo_reference(struct ttm_buffer_object *bo) > ?* Returns -ERESTARTSYS if interrupted by a signal. > ?*/ > ?extern int ttm_bo_wait(struct ttm_buffer_object *bo, bool lazy, > - ? ? ? ? ? ? ? ? ? ? ?bool interruptible, bool no_wait); > + ? ? ? ? ? ? ? ? ? ? ?bool interruptible, bool no_wait, > + ? ? ? ? ? ? ? ? ? ? ?enum ttm_buffer_usage usage); > ?/** > ?* ttm_bo_validate > ?* > diff --git a/include/drm/ttm/ttm_execbuf_util.h > b/include/drm/ttm/ttm_execbuf_util.h > index 26cc7f9..375f299 100644 > --- a/include/drm/ttm/ttm_execbuf_util.h > +++ b/include/drm/ttm/ttm_execbuf_util.h > @@ -41,20 +41,26 @@ > ?* @bo: ? ? ? ? ? ? refcounted buffer object pointer. > ?* @new_sync_obj_arg: New sync_obj_arg for @bo, to be used once > ?* adding a new sync object. > + * @usage ? ? ? ? ? Indicates how @bo is used by the device. > ?* @reserved: ? ? ? Indicates whether @bo has been reserved for validation. > ?* @removed: ? ? ? ?Indicates whether @bo has been removed from lru lists. > ?* @put_count: ? ? ?Number of outstanding references on bo::list_kref. > ?* @old_sync_obj: ? Pointer to a sync object about to be unreferenced > + * @old_sync_obj_read: Pointer to a read sync object about to be > unreferenced. > + * @old_sync_obj_write: Pointer to a write sync object about to be > unreferenced. > ?*/ > > ?struct ttm_validate_buffer { > ? ? ? ?struct list_head head; > ? ? ? ?struct ttm_buffer_object *bo; > ? ? ? ?void *new_sync_obj_arg; > + ? ? ? enum ttm_buffer_usage usage; > ? ? ? ?bool reserved; > ? ? ? ?bool removed; > ? ? ? ?int put_count; > ? ? ? ?void *old_sync_obj; > + ? ? ? void *old_sync_obj_read; > + ? ? ? void *old_sync_obj_write; > ?}; > > ?/** > -- > 1.7.4.1 > > _______________________________________________ > dri-devel mailing list > dri-devel at lists.freedesktop.org > http://lists.freedesktop.org/mailman/listinfo/dri-devel >