On Thu, Oct 14, 2010 at 3:18 AM, Thomas Hellstrom <thellstrom at vmware.com> 
wrote:
> This commit replaces the ttm_bo_cleanup_ref function with two new functions.
> One for the case where the bo is not yet on the delayed destroy list, and
> one for the case where the bo was on the delayed destroy list, at least at
> the time of call. This makes it possible to optimize the two cases somewhat.

I tried booting this today, but on radeon starting X hit a recursive
spin lock on the lru lock.

(annotated below)

> + *
> + * @interruptible ? ? ? ? Any sleeps should occur interruptibly.
> + * @no_wait_reserve ? ? ? Never wait for reserve. Return -EBUSY instead.
> + * @no_wait_gpu ? ? ? ? ? Never wait for gpu. Return -EBUSY instead.
> + */
> +
> +static int ttm_bo_cleanup_refs(struct ttm_buffer_object *bo,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?bool interruptible,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?bool no_wait_reserve,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?bool no_wait_gpu)
> +{
> + ? ? ? struct ttm_bo_global *glob = bo->glob;
> + ? ? ? int put_count;
> + ? ? ? int ret = 0;
> +
> +retry:
> + ? ? ? spin_lock(&bo->lock);
> + ? ? ? ret = ttm_bo_wait(bo, false, interruptible, no_wait_gpu);
> + ? ? ? spin_unlock(&bo->lock);
> +
> + ? ? ? if (unlikely(ret != 0))
> + ? ? ? ? ? ? ? return ret;
> +
> ? ? ? ?spin_lock(&glob->lru_lock);

^^ take LRU lock

> - ? ? ? if (list_empty(&bo->ddestroy)) {
> - ? ? ? ? ? ? ? void *sync_obj = bo->sync_obj;
> - ? ? ? ? ? ? ? void *sync_obj_arg = bo->sync_obj_arg;
> + ? ? ? ret = ttm_bo_reserve_locked(bo, interruptible,
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? no_wait_reserve, false, 0);
>
> - ? ? ? ? ? ? ? kref_get(&bo->list_kref);
> - ? ? ? ? ? ? ? list_add_tail(&bo->ddestroy, &bdev->ddestroy);
> + ? ? ? if (unlikely(ret != 0) || list_empty(&bo->ddestroy)) {
> ? ? ? ? ? ? ? ?spin_unlock(&glob->lru_lock);

^^ drop in error path.

> - ? ? ? ? ? ? ? spin_unlock(&bo->lock);
> + ? ? ? ? ? ? ? return ret;
> + ? ? ? }
>
> - ? ? ? ? ? ? ? if (sync_obj)
> - ? ? ? ? ? ? ? ? ? ? ? driver->sync_obj_flush(sync_obj, sync_obj_arg);
> - ? ? ? ? ? ? ? schedule_delayed_work(&bdev->wq,
> - ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ((HZ / 100) < 1) ? 1 : HZ / 100);
> - ? ? ? ? ? ? ? ret = 0;
> + ? ? ? /**
> + ? ? ? ?* We can re-check for sync object without taking
> + ? ? ? ?* the bo::lock since setting the sync object requires
> + ? ? ? ?* also bo::reserved. A busy object at this point may
> + ? ? ? ?* be caused by another thread recently starting an accelerated
> + ? ? ? ?* eviction.
> + ? ? ? ?*/
>
> - ? ? ? } else {
> + ? ? ? if (unlikely(bo->sync_obj)) {
> + ? ? ? ? ? ? ? atomic_set(&bo->reserved, 0);
> + ? ? ? ? ? ? ? wake_up_all(&bo->event_queue);
> ? ? ? ? ? ? ? ?spin_unlock(&glob->lru_lock);

^^ drop for retry path.

> - ? ? ? ? ? ? ? spin_unlock(&bo->lock);
> - ? ? ? ? ? ? ? ret = -EBUSY;
> + ? ? ? ? ? ? ? goto retry;
> ? ? ? ?}
>
> - ? ? ? return ret;
> + ? ? ? put_count = ttm_bo_del_from_lru(bo);
> + ? ? ? list_del_init(&bo->ddestroy);
> + ? ? ? ++put_count;
> +
> + ? ? ? ttm_bo_cleanup_memtype_use(bo);

^^ get into cleanup_memtype_use, which calls the ttm_bo_mem_put which
tries to take the lru lock inside
 ttm_bo_man_put_node

Dave.

Reply via email to