From: Thomas Hellstrom Date: Sun, 13 Apr 2008 12:49:14 +0000 (+0200) Subject: Unlock the BO mutex while waiting for idle, unmapped, unfenced. X-Git-Tag: submit/1.0/20121108.012404~903 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=c9b73ef6daff75df27d17260a9fc84e68f1b21b4;p=profile%2Fivi%2Flibdrm.git Unlock the BO mutex while waiting for idle, unmapped, unfenced. Move unfenced checking into idle checking. Never time out while waiting for software events like unmapped or unfenced. --- diff --git a/linux-core/drm_bo.c b/linux-core/drm_bo.c index 4ef697b..0853d74 100644 --- a/linux-core/drm_bo.c +++ b/linux-core/drm_bo.c @@ -275,30 +275,81 @@ out_err: /* * Call bo->mutex locked. - * Wait until the buffer is idle. + * Returns -EBUSY if the buffer is currently rendered to or from. 0 otherwise. */ -int drm_bo_wait(struct drm_buffer_object *bo, int lazy, int ignore_signals, - int no_wait) +static int drm_bo_busy(struct drm_buffer_object *bo, int check_unfenced) { - int ret; + struct drm_fence_object *fence = bo->fence; - DRM_ASSERT_LOCKED(&bo->mutex); + if (check_unfenced && (bo->priv_flags & _DRM_BO_FLAG_UNFENCED)) + return -EBUSY; - if (bo->fence) { - if (drm_fence_object_signaled(bo->fence, bo->fence_type)) { + if (fence) { + if (drm_fence_object_signaled(fence, bo->fence_type)) { + drm_fence_usage_deref_unlocked(&bo->fence); + return 0; + } + drm_fence_object_flush(fence, DRM_FENCE_TYPE_EXE); + if (drm_fence_object_signaled(fence, bo->fence_type)) { drm_fence_usage_deref_unlocked(&bo->fence); return 0; } + return -EBUSY; + } + return 0; +} + +static int drm_bo_check_unfenced(struct drm_buffer_object *bo) +{ + int ret; + + mutex_lock(&bo->mutex); + ret = (bo->priv_flags & _DRM_BO_FLAG_UNFENCED); + mutex_unlock(&bo->mutex); + return ret; +} + + +/* + * Call bo->mutex locked. + * Wait until the buffer is idle. + */ + +int drm_bo_wait(struct drm_buffer_object *bo, int lazy, int interruptible, + int no_wait, int check_unfenced) +{ + int ret; + + DRM_ASSERT_LOCKED(&bo->mutex); + while(unlikely(drm_bo_busy(bo, check_unfenced))) { if (no_wait) return -EBUSY; - ret = drm_fence_object_wait(bo->fence, lazy, ignore_signals, - bo->fence_type); - if (ret) - return ret; + if (check_unfenced && (bo->priv_flags & _DRM_BO_FLAG_UNFENCED)) { + mutex_unlock(&bo->mutex); + wait_event(bo->event_queue, !drm_bo_check_unfenced(bo)); + mutex_lock(&bo->mutex); + bo->priv_flags |= _DRM_BO_FLAG_UNLOCKED; + } + + if (bo->fence) { + struct drm_fence_object *fence; + uint32_t fence_type = bo->fence_type; + + drm_fence_reference_unlocked(&fence, bo->fence); + mutex_unlock(&bo->mutex); + + ret = drm_fence_object_wait(fence, lazy, !interruptible, + fence_type); + + drm_fence_usage_deref_unlocked(&fence); + mutex_lock(&bo->mutex); + bo->priv_flags |= _DRM_BO_FLAG_UNLOCKED; + if (ret) + return ret; + } - drm_fence_usage_deref_unlocked(&bo->fence); } return 0; } @@ -314,7 +365,7 @@ static int drm_bo_expire_fence(struct drm_buffer_object *bo, int allow_errors) unsigned long _end = jiffies + 3 * DRM_HZ; int ret; do { - ret = drm_bo_wait(bo, 0, 1, 0); + ret = drm_bo_wait(bo, 0, 0, 0, 0); if (ret && allow_errors) return ret; @@ -690,24 +741,32 @@ static int drm_bo_evict(struct drm_buffer_object *bo, unsigned mem_type, * buffer mutex. */ - if (bo->priv_flags & _DRM_BO_FLAG_UNFENCED) - goto out; - if (bo->mem.mem_type != mem_type) - goto out; - - ret = drm_bo_wait(bo, 0, 0, no_wait); + do { + bo->priv_flags &= ~_DRM_BO_FLAG_UNLOCKED; + + if (unlikely(bo->mem.flags & + (DRM_BO_FLAG_NO_MOVE | DRM_BO_FLAG_NO_EVICT))) + goto out_unlock; + if (unlikely(bo->priv_flags & _DRM_BO_FLAG_UNFENCED)) + goto out_unlock; + if (unlikely(bo->mem.mem_type != mem_type)) + goto out_unlock; + ret = drm_bo_wait(bo, 0, 1, no_wait, 0); + if (ret) + goto out_unlock; - if (ret && ret != -EAGAIN) { - DRM_ERROR("Failed to expire fence before " - "buffer eviction.\n"); - goto out; - } + } while(bo->priv_flags & _DRM_BO_FLAG_UNLOCKED); evict_mem = bo->mem; evict_mem.mm_node = NULL; evict_mem = bo->mem; evict_mem.proposed_flags = dev->driver->bo_driver->evict_flags(bo); + + mutex_lock(&dev->struct_mutex); + list_del_init(&bo->lru); + mutex_unlock(&dev->struct_mutex); + ret = drm_bo_mem_space(bo, &evict_mem, no_wait); if (ret) { @@ -725,20 +784,21 @@ static int drm_bo_evict(struct drm_buffer_object *bo, unsigned mem_type, goto out; } + DRM_FLAG_MASKED(bo->priv_flags, _DRM_BO_FLAG_EVICTED, + _DRM_BO_FLAG_EVICTED); + +out: mutex_lock(&dev->struct_mutex); if (evict_mem.mm_node) { if (evict_mem.mm_node != bo->pinned_node) drm_mm_put_block(evict_mem.mm_node); evict_mem.mm_node = NULL; } - list_del(&bo->lru); drm_bo_add_to_lru(bo); + BUG_ON(bo->priv_flags & _DRM_BO_FLAG_UNLOCKED); +out_unlock: mutex_unlock(&dev->struct_mutex); - DRM_FLAG_MASKED(bo->priv_flags, _DRM_BO_FLAG_EVICTED, - _DRM_BO_FLAG_EVICTED); - -out: return ret; } @@ -773,8 +833,6 @@ static int drm_bo_mem_force_space(struct drm_device *dev, atomic_inc(&entry->usage); mutex_unlock(&dev->struct_mutex); mutex_lock(&entry->mutex); - BUG_ON(entry->mem.flags & (DRM_BO_FLAG_NO_MOVE | DRM_BO_FLAG_NO_EVICT)); - ret = drm_bo_evict(entry, mem_type, no_wait); mutex_unlock(&entry->mutex); drm_bo_usage_deref_unlocked(&entry); @@ -1040,46 +1098,23 @@ EXPORT_SYMBOL(drm_lookup_buffer_object); /* * Call bo->mutex locked. - * Returns 1 if the buffer is currently rendered to or from. 0 otherwise. + * Returns -EBUSY if the buffer is currently rendered to or from. 0 otherwise. * Doesn't do any fence flushing as opposed to the drm_bo_busy function. */ -static int drm_bo_quick_busy(struct drm_buffer_object *bo) +static int drm_bo_quick_busy(struct drm_buffer_object *bo, int check_unfenced) { struct drm_fence_object *fence = bo->fence; - BUG_ON(bo->priv_flags & _DRM_BO_FLAG_UNFENCED); - if (fence) { - if (drm_fence_object_signaled(fence, bo->fence_type)) { - drm_fence_usage_deref_unlocked(&bo->fence); - return 0; - } - return 1; - } - return 0; -} - -/* - * Call bo->mutex locked. - * Returns 1 if the buffer is currently rendered to or from. 0 otherwise. - */ - -static int drm_bo_busy(struct drm_buffer_object *bo) -{ - struct drm_fence_object *fence = bo->fence; + if (check_unfenced && (bo->priv_flags & _DRM_BO_FLAG_UNFENCED)) + return -EBUSY; - BUG_ON(bo->priv_flags & _DRM_BO_FLAG_UNFENCED); if (fence) { if (drm_fence_object_signaled(fence, bo->fence_type)) { drm_fence_usage_deref_unlocked(&bo->fence); return 0; } - drm_fence_object_flush(fence, DRM_FENCE_TYPE_EXE); - if (drm_fence_object_signaled(fence, bo->fence_type)) { - drm_fence_usage_deref_unlocked(&bo->fence); - return 0; - } - return 1; + return -EBUSY; } return 0; } @@ -1103,62 +1138,27 @@ static int drm_bo_wait_unmapped(struct drm_buffer_object *bo, int no_wait) { int ret = 0; - if ((atomic_read(&bo->mapped) >= 0) && no_wait) - return -EBUSY; - - DRM_WAIT_ON(ret, bo->event_queue, 3 * DRM_HZ, - atomic_read(&bo->mapped) == -1); + if (likely(atomic_read(&bo->mapped)) == 0) + return 0; - if (ret == -EINTR) - ret = -EAGAIN; + if (unlikely(no_wait)) + return -EBUSY; - return ret; -} + do { + mutex_unlock(&bo->mutex); + ret = wait_event_interruptible(bo->event_queue, + atomic_read(&bo->mapped) == 0); + mutex_lock(&bo->mutex); + bo->priv_flags |= _DRM_BO_FLAG_UNLOCKED; -static int drm_bo_check_unfenced(struct drm_buffer_object *bo) -{ - int ret; + if (ret == -ERESTARTSYS) + ret = -EAGAIN; + } while((ret == 0) && atomic_read(&bo->mapped) > 0); - mutex_lock(&bo->mutex); - ret = (bo->priv_flags & _DRM_BO_FLAG_UNFENCED); - mutex_unlock(&bo->mutex); return ret; } /* - * Wait until a buffer, scheduled to be fenced moves off the unfenced list. - * Until then, we cannot really do anything with it except delete it. - */ - -static int drm_bo_wait_unfenced(struct drm_buffer_object *bo, int no_wait, - int eagain_if_wait) -{ - int ret = (bo->priv_flags & _DRM_BO_FLAG_UNFENCED); - - if (ret && no_wait) - return -EBUSY; - else if (!ret) - return 0; - - ret = 0; - mutex_unlock(&bo->mutex); - DRM_WAIT_ON (ret, bo->event_queue, 3 * DRM_HZ, - !drm_bo_check_unfenced(bo)); - mutex_lock(&bo->mutex); - if (ret == -EINTR) - return -EAGAIN; - ret = (bo->priv_flags & _DRM_BO_FLAG_UNFENCED); - if (ret) { - DRM_ERROR("Timeout waiting for buffer to become fenced\n"); - return -EBUSY; - } - if (eagain_if_wait) - return -EAGAIN; - - return 0; -} - -/* * Fill in the ioctl reply argument with buffer info. * Bo locked. */ @@ -1190,7 +1190,7 @@ void drm_bo_fill_rep_arg(struct drm_buffer_object *bo, rep->rep_flags = 0; rep->page_alignment = bo->mem.page_alignment; - if ((bo->priv_flags & _DRM_BO_FLAG_UNFENCED) || drm_bo_quick_busy(bo)) { + if ((bo->priv_flags & _DRM_BO_FLAG_UNFENCED) || drm_bo_quick_busy(bo, 1)) { DRM_FLAG_MASKED(rep->rep_flags, DRM_BO_REP_BUSY, DRM_BO_REP_BUSY); } @@ -1221,59 +1221,27 @@ static int drm_buffer_object_map(struct drm_file *file_priv, uint32_t handle, return -EINVAL; mutex_lock(&bo->mutex); - ret = drm_bo_wait_unfenced(bo, no_wait, 0); - if (ret) - goto out; - - /* - * If this returns true, we are currently unmapped. - * We need to do this test, because unmapping can - * be done without the bo->mutex held. - */ - - while (1) { - if (atomic_inc_and_test(&bo->mapped)) { - if (no_wait && drm_bo_busy(bo)) { - atomic_dec(&bo->mapped); - ret = -EBUSY; - goto out; - } - ret = drm_bo_wait(bo, 0, 0, no_wait); - if (ret) { - atomic_dec(&bo->mapped); - goto out; - } - - if (bo->mem.flags & DRM_BO_FLAG_CACHED_MAPPED) - drm_bo_evict_cached(bo); - - break; - } else if (bo->mem.flags & DRM_BO_FLAG_CACHED_MAPPED) { + do { + bo->priv_flags &= ~_DRM_BO_FLAG_UNLOCKED; - /* - * We are already mapped with different flags. - * need to wait for unmap. - */ + ret = drm_bo_wait(bo, 0, 1, no_wait, 1); - ret = drm_bo_wait_unmapped(bo, no_wait); - if (ret) - goto out; + if (bo->mem.flags & DRM_BO_FLAG_CACHED_MAPPED) + drm_bo_evict_cached(bo); - continue; - } - break; - } + } while (bo->priv_flags & _DRM_BO_FLAG_UNLOCKED); + atomic_inc(&bo->mapped); mutex_lock(&dev->struct_mutex); ret = drm_add_ref_object(file_priv, &bo->base, _DRM_REF_TYPE1); mutex_unlock(&dev->struct_mutex); if (ret) { - if (atomic_add_negative(-1, &bo->mapped)) + if (atomic_dec_and_test(&bo->mapped)) wake_up_all(&bo->event_queue); } else drm_bo_fill_rep_arg(bo, rep); -out: + mutex_unlock(&bo->mutex); drm_bo_usage_deref_unlocked(&bo); return ret; @@ -1325,7 +1293,7 @@ static void drm_buffer_user_object_unmap(struct drm_file *file_priv, BUG_ON(action != _DRM_REF_TYPE1); - if (atomic_add_negative(-1, &bo->mapped)) + if (atomic_dec_and_test(&bo->mapped)) wake_up_all(&bo->event_queue); } @@ -1341,19 +1309,8 @@ int drm_bo_move_buffer(struct drm_buffer_object *bo, uint64_t new_mem_flags, struct drm_buffer_manager *bm = &dev->bm; int ret = 0; struct drm_bo_mem_reg mem; - /* - * Flush outstanding fences. - */ - - drm_bo_busy(bo); - /* - * Wait for outstanding fences. - */ - - ret = drm_bo_wait(bo, 0, 0, no_wait); - if (ret) - return ret; + BUG_ON(bo->fence != NULL); mem.num_pages = bo->num_pages; mem.size = mem.num_pages << PAGE_SHIFT; @@ -1439,64 +1396,14 @@ static int drm_bo_mem_compat(struct drm_bo_mem_reg *mem) static int drm_buffer_object_validate(struct drm_buffer_object *bo, uint32_t fence_class, - int move_unfenced, int no_wait) + int move_unfenced, int no_wait, + int move_buffer) { struct drm_device *dev = bo->dev; struct drm_buffer_manager *bm = &dev->bm; - struct drm_bo_driver *driver = dev->driver->bo_driver; - uint32_t ftype; int ret; - DRM_DEBUG("Proposed flags 0x%016llx, Old flags 0x%016llx\n", - (unsigned long long) bo->mem.proposed_flags, - (unsigned long long) bo->mem.flags); - - ret = driver->fence_type(bo, &fence_class, &ftype); - - if (ret) { - DRM_ERROR("Driver did not support given buffer permissions\n"); - return ret; - } - - /* - * We're switching command submission mechanism, - * or cannot simply rely on the hardware serializing for us. - * - * Insert a driver-dependant barrier or wait for buffer idle. - */ - - if ((fence_class != bo->fence_class) || - ((ftype ^ bo->fence_type) & bo->fence_type)) { - - ret = -EINVAL; - if (driver->command_stream_barrier) { - ret = driver->command_stream_barrier(bo, - fence_class, - ftype, - no_wait); - } - if (ret) - ret = drm_bo_wait(bo, 0, 0, no_wait); - - if (ret) - return ret; - - } - - bo->new_fence_class = fence_class; - bo->new_fence_type = ftype; - - ret = drm_bo_wait_unmapped(bo, no_wait); - if (ret) { - DRM_ERROR("Timed out waiting for buffer unmap.\n"); - return ret; - } - - /* - * Check whether we need to move buffer. - */ - - if (!drm_bo_mem_compat(&bo->mem)) { + if (move_buffer) { ret = drm_bo_move_buffer(bo, bo->mem.proposed_flags, no_wait, move_unfenced); if (ret) { @@ -1580,6 +1487,82 @@ static int drm_buffer_object_validate(struct drm_buffer_object *bo, return 0; } +/* + * This function is called with bo->mutex locked, but may release it + * temporarily to wait for events. + */ + +static int drm_bo_prepare_for_validate(struct drm_buffer_object *bo, + uint64_t flags, + uint64_t mask, + uint32_t hint, + uint32_t fence_class, + int no_wait, + int *move_buffer) +{ + struct drm_device *dev = bo->dev; + struct drm_bo_driver *driver = dev->driver->bo_driver; + uint32_t ftype; + + int ret; + + DRM_DEBUG("Proposed flags 0x%016llx, Old flags 0x%016llx\n", + (unsigned long long) bo->mem.proposed_flags, + (unsigned long long) bo->mem.flags); + + ret = drm_bo_modify_proposed_flags (bo, flags, mask); + if (ret) + return ret; + + ret = drm_bo_wait_unmapped(bo, no_wait); + if (ret) + return ret; + + ret = driver->fence_type(bo, &fence_class, &ftype); + + if (ret) { + DRM_ERROR("Driver did not support given buffer permissions.\n"); + return ret; + } + + /* + * We're switching command submission mechanism, + * or cannot simply rely on the hardware serializing for us. + * Insert a driver-dependant barrier or wait for buffer idle. + */ + + if ((fence_class != bo->fence_class) || + ((ftype ^ bo->fence_type) & bo->fence_type)) { + + ret = -EINVAL; + if (driver->command_stream_barrier) { + ret = driver->command_stream_barrier(bo, + fence_class, + ftype, + no_wait); + } + if (ret && ret != -EAGAIN) + ret = drm_bo_wait(bo, 0, 1, no_wait, 1); + if (ret) + return ret; + } + + bo->new_fence_class = fence_class; + bo->new_fence_type = ftype; + + /* + * Check whether we need to move buffer. + */ + + *move_buffer = 0; + if (!drm_bo_mem_compat(&bo->mem)) { + *move_buffer = 1; + ret = drm_bo_wait(bo, 0, 1, no_wait, 1); + } + + return ret; +} + /** * drm_bo_do_validate: * @@ -1612,21 +1595,28 @@ int drm_bo_do_validate(struct drm_buffer_object *bo, { int ret; int no_wait = (hint & DRM_BO_HINT_DONT_BLOCK) != 0; + int move_buffer; mutex_lock(&bo->mutex); - ret = drm_bo_wait_unfenced(bo, no_wait, 0); - if (ret) - goto out; + do { + bo->priv_flags &= ~_DRM_BO_FLAG_UNLOCKED; - ret = drm_bo_modify_proposed_flags (bo, flags, mask); - if (ret) - goto out; + ret = drm_bo_prepare_for_validate(bo, flags, mask, hint, + fence_class, no_wait, + &move_buffer); + if (ret) + goto out; + + } while(bo->priv_flags & _DRM_BO_FLAG_UNLOCKED); ret = drm_buffer_object_validate(bo, fence_class, !(hint & DRM_BO_HINT_DONT_FENCE), - no_wait); + no_wait, + move_buffer); + + BUG_ON(bo->priv_flags & _DRM_BO_FLAG_UNLOCKED); out: if (rep) drm_bo_fill_rep_arg(bo, rep); @@ -1657,22 +1647,19 @@ EXPORT_SYMBOL(drm_bo_do_validate); * fencing mechanism. At this point, there isn't any use of this * from the user mode code. * - * @use_old_fence_class: don't change fence class, pull it from the buffer object - * * @rep: To be stuffed with the reply from validation - * + * * @bp_rep: To be stuffed with the buffer object pointer * - * Perform drm_bo_do_validate on a buffer referenced by a user-space handle. - * Some permissions checking is done on the parameters, otherwise this - * is a thin wrapper. + * Perform drm_bo_do_validate on a buffer referenced by a user-space handle instead + * of a pointer to a buffer object. Optionally return a pointer to the buffer object. + * This is a convenience wrapper only. */ int drm_bo_handle_validate(struct drm_file *file_priv, uint32_t handle, uint64_t flags, uint64_t mask, uint32_t hint, uint32_t fence_class, - int use_old_fence_class, struct drm_bo_info_rep *rep, struct drm_buffer_object **bo_rep) { @@ -1687,17 +1674,9 @@ int drm_bo_handle_validate(struct drm_file *file_priv, uint32_t handle, if (!bo) return -EINVAL; - if (use_old_fence_class) - fence_class = bo->fence_class; - - /* - * Only allow creator to change shared buffer mask. - */ - if (bo->base.owner != file_priv) mask &= ~(DRM_BO_FLAG_NO_EVICT | DRM_BO_FLAG_NO_MOVE); - ret = drm_bo_do_validate(bo, flags, mask, hint, fence_class, rep); if (!ret && bo_rep) @@ -1709,6 +1688,7 @@ int drm_bo_handle_validate(struct drm_file *file_priv, uint32_t handle, } EXPORT_SYMBOL(drm_bo_handle_validate); + static int drm_bo_handle_info(struct drm_file *file_priv, uint32_t handle, struct drm_bo_info_rep *rep) { @@ -1723,8 +1703,12 @@ static int drm_bo_handle_info(struct drm_file *file_priv, uint32_t handle, return -EINVAL; mutex_lock(&bo->mutex); - if (!(bo->priv_flags & _DRM_BO_FLAG_UNFENCED)) - (void)drm_bo_busy(bo); + + /* + * FIXME: Quick busy here? + */ + + drm_bo_busy(bo, 1); drm_bo_fill_rep_arg(bo, rep); mutex_unlock(&bo->mutex); drm_bo_usage_deref_unlocked(&bo); @@ -1748,15 +1732,11 @@ static int drm_bo_handle_wait(struct drm_file *file_priv, uint32_t handle, return -EINVAL; mutex_lock(&bo->mutex); - ret = drm_bo_wait_unfenced(bo, no_wait, 0); - if (ret) - goto out; - ret = drm_bo_wait(bo, hint & DRM_BO_HINT_WAIT_LAZY, 0, no_wait); + ret = drm_bo_wait(bo, hint & DRM_BO_HINT_WAIT_LAZY, 1, no_wait, 1); if (ret) goto out; drm_bo_fill_rep_arg(bo, rep); - out: mutex_unlock(&bo->mutex); drm_bo_usage_deref_unlocked(&bo); @@ -1793,7 +1773,7 @@ int drm_buffer_object_create(struct drm_device *dev, mutex_lock(&bo->mutex); atomic_set(&bo->usage, 1); - atomic_set(&bo->mapped, -1); + atomic_set(&bo->mapped, 0); DRM_INIT_WAITQUEUE(&bo->event_queue); INIT_LIST_HEAD(&bo->lru); INIT_LIST_HEAD(&bo->pinned_lru); @@ -1835,17 +1815,18 @@ int drm_buffer_object_create(struct drm_device *dev, goto out_err; } - ret = drm_buffer_object_validate(bo, 0, 0, hint & DRM_BO_HINT_DONT_BLOCK); + mutex_unlock(&bo->mutex); + ret = drm_bo_do_validate(bo, 0, 0, hint & DRM_BO_HINT_DONT_BLOCK, + 0, NULL); if (ret) - goto out_err; + goto out_err_unlocked; - mutex_unlock(&bo->mutex); *buf_obj = bo; return 0; out_err: mutex_unlock(&bo->mutex); - +out_err_unlocked: drm_bo_usage_deref_unlocked(&bo); return ret; } @@ -1931,6 +1912,7 @@ int drm_bo_setstatus_ioctl(struct drm_device *dev, struct drm_bo_map_wait_idle_arg *arg = data; struct drm_bo_info_req *req = &arg->d.req; struct drm_bo_info_rep *rep = &arg->d.rep; + struct drm_buffer_object *bo; int ret; if (!dev->bm.initialized) { @@ -1942,24 +1924,25 @@ int drm_bo_setstatus_ioctl(struct drm_device *dev, if (ret) return ret; - /* - * validate the buffer. note that 'fence_class' will be unused - * as we pass use_old_fence_class=1 here. Note also that - * the libdrm API doesn't pass fence_class to the kernel, - * so it's a good thing it isn't used here. - */ - ret = drm_bo_handle_validate(file_priv, req->handle, - req->flags, - req->mask, - req->hint | DRM_BO_HINT_DONT_FENCE, - req->fence_class, 1, - rep, NULL); + mutex_lock(&dev->struct_mutex); + bo = drm_lookup_buffer_object(file_priv, req->handle, 1); + mutex_unlock(&dev->struct_mutex); + + if (!bo) + return -EINVAL; + + if (bo->base.owner != file_priv) + req->mask &= ~(DRM_BO_FLAG_NO_EVICT | DRM_BO_FLAG_NO_MOVE); + + ret = drm_bo_do_validate(bo, req->flags, req->mask, + req->hint | DRM_BO_HINT_DONT_FENCE, + bo->fence_class, rep); + + drm_bo_usage_deref_unlocked(&bo); (void) drm_bo_read_unlock(&dev->bm.bm_lock); - if (ret) - return ret; - return 0; + return ret; } int drm_bo_map_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) diff --git a/linux-core/drm_bo_move.c b/linux-core/drm_bo_move.c index 21673da..bf0e1b7 100644 --- a/linux-core/drm_bo_move.c +++ b/linux-core/drm_bo_move.c @@ -356,10 +356,11 @@ int drm_bo_move_accel_cleanup(struct drm_buffer_object *bo, bo->mem.mm_node != NULL)) #endif { - ret = drm_bo_wait(bo, 0, 1, 0); - if (ret) - return ret; - + if (bo->fence) { + (void) drm_fence_object_wait(bo->fence, 0, 1, + bo->fence_type); + drm_fence_usage_deref_unlocked(&bo->fence); + } drm_bo_free_old_node(bo); if ((man->flags & _DRM_FLAG_MEMTYPE_FIXED) && (bo->ttm != NULL)) { diff --git a/linux-core/drm_objects.h b/linux-core/drm_objects.h index a1f3a18..770fbc5 100644 --- a/linux-core/drm_objects.h +++ b/linux-core/drm_objects.h @@ -517,6 +517,14 @@ struct drm_buffer_object { #define _DRM_BO_FLAG_UNFENCED 0x00000001 #define _DRM_BO_FLAG_EVICTED 0x00000002 +/* + * This flag indicates that a flag called with bo->mutex held has + * temporarily released the buffer object mutex, (usually to wait for something). + * and thus any post-lock validation needs to be rerun. + */ + +#define _DRM_BO_FLAG_UNLOCKED 0x00000004 + struct drm_mem_type_manager { int has_type; int use_type; @@ -682,8 +690,8 @@ extern int drm_buffer_object_create(struct drm_device *dev, unsigned long size, uint32_t hint, uint32_t page_alignment, unsigned long buffer_start, struct drm_buffer_object **bo); -extern int drm_bo_wait(struct drm_buffer_object *bo, int lazy, int ignore_signals, - int no_wait); +extern int drm_bo_wait(struct drm_buffer_object *bo, int lazy, int interruptible, + int no_wait, int check_unfenced); extern int drm_bo_mem_space(struct drm_buffer_object *bo, struct drm_bo_mem_reg *mem, int no_wait); extern int drm_bo_move_buffer(struct drm_buffer_object *bo, @@ -695,7 +703,7 @@ extern int drm_bo_init_mm(struct drm_device *dev, unsigned type, int kern_init); extern int drm_bo_handle_validate(struct drm_file *file_priv, uint32_t handle, uint64_t flags, uint64_t mask, uint32_t hint, - uint32_t fence_class, int use_old_fence_class, + uint32_t fence_class, struct drm_bo_info_rep *rep, struct drm_buffer_object **bo_rep); extern struct drm_buffer_object *drm_lookup_buffer_object(struct drm_file *file_priv, diff --git a/linux-core/drm_vm.c b/linux-core/drm_vm.c index a09bcdd..cabfb8f 100644 --- a/linux-core/drm_vm.c +++ b/linux-core/drm_vm.c @@ -748,12 +748,14 @@ static unsigned long drm_bo_vm_nopfn(struct vm_area_struct *vma, return NOPFN_REFAULT; } - err = drm_bo_wait(bo, 0, 0, 0); + err = drm_bo_wait(bo, 0, 1, 0, 1); if (err) { ret = (err != -EAGAIN) ? NOPFN_SIGBUS : NOPFN_REFAULT; goto out_unlock; } + bo->priv_flags &= ~_DRM_BO_FLAG_UNLOCKED; + /* * If buffer happens to be in a non-mappable location, * move it to a mappable. @@ -806,6 +808,7 @@ static unsigned long drm_bo_vm_nopfn(struct vm_area_struct *vma, goto out_unlock; } out_unlock: + BUG_ON(bo->priv_flags & _DRM_BO_FLAG_UNLOCKED); mutex_unlock(&bo->mutex); drm_bo_read_unlock(&dev->bm.bm_lock); return ret; diff --git a/linux-core/i915_execbuf.c b/linux-core/i915_execbuf.c index 088a269..804f3ac 100644 --- a/linux-core/i915_execbuf.c +++ b/linux-core/i915_execbuf.c @@ -144,7 +144,7 @@ int i915_apply_reloc(struct drm_file *file_priv, int num_buffers, relocatee->offset = new_cmd_offset; if (unlikely(relocatee->idle == I915_RELOC_UNCHECKED)) { - ret = drm_bo_wait(relocatee->buf, 0, 0, 0); + ret = drm_bo_wait(relocatee->buf, 0, 1, 0, 0); if (ret) return ret; relocatee->idle = I915_RELOC_IDLE; @@ -355,11 +355,9 @@ static int i915_update_relocatee(struct i915_relocatee_info *relocatee, if (relocatee->idle == I915_RELOC_UNCHECKED) { preempt_enable(); - ret = mutex_lock_interruptible(&relocatee->buf->mutex); - if (unlikely(ret)) - return -EAGAIN; + mutex_lock(&relocatee->buf->mutex); - ret = drm_bo_wait(relocatee->buf, 0, 0, 1); + ret = drm_bo_wait(relocatee->buf, 0, 1, 1, 0); if (ret == 0) relocatee->idle = I915_RELOC_IDLE; else { @@ -684,7 +682,7 @@ int i915_validate_buffer_list(struct drm_file *file_priv, ret = drm_bo_handle_validate(file_priv, req->bo_req.handle, req->bo_req.flags, req->bo_req.mask, req->bo_req.hint, - req->bo_req.fence_class, 0, + req->bo_req.fence_class, NULL, &item->buffer); if (ret) { DRM_ERROR("error on handle validate %d\n", ret);