With a bit of care (and leniency) we can iterate over the object and wait for previous rendering to complete with judicial use of atomic reference counting. The ABI requires us to ensure that an active object is eventually flushed (like the busy-ioctl) which is guaranteed by our management of requests (i.e. everything that is submitted to hardware is flushed in the same request). All we have to do is ensure that we can detect when the requests are complete for reporting when the object is idle (without triggering ETIME) - this is handled by __i915_wait_request. The biggest danger in the code is walking the object without holding any locks. We iterate over the set of last requests and carefully grab a reference upon it. (If it is changing beneath us, that is the usual userspace race and even with locking you get the same indeterminate results.) If the request is unreferenced beneath us, it will be disposed of into the request cache - so we have to carefully order the retrieval of the request pointer with its removal, and to do this we employ RCU on the request cache and upon the last_request pointer tracking. The impact of this is actually quite small - the return to userspace following the wait was already lockless. What we achieve here is completing an already finished wait without hitting the struct_mutex, our hold is quite short and so we are typically just a victim of contention rather than a cause. Signed-off-by: Chris Wilson <chris@xxxxxxxxxxxxxxxxxx> --- drivers/gpu/drm/i915/i915_gem.c | 42 +++++++++++------------------------------ 1 file changed, 11 insertions(+), 31 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 4b17aaaa8dca..4af64d864587 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2358,46 +2358,26 @@ i915_gem_wait_ioctl(struct drm_device *dev, void *data, struct drm_file *file) { struct drm_i915_gem_wait *args = data; struct drm_i915_gem_object *obj; - struct drm_i915_gem_request *requests[I915_NUM_ENGINES]; - int i, n = 0; - int ret; + unsigned long active; + int idx, ret = 0; if (args->flags != 0) return -EINVAL; - ret = i915_mutex_lock_interruptible(dev); - if (ret) - return ret; - obj = i915_gem_object_lookup(file, args->bo_handle); - if (!obj) { - mutex_unlock(&dev->struct_mutex); + if (!obj) return -ENOENT; - } - - if (!i915_gem_object_is_active(obj)) - goto out; - for (i = 0; i < I915_NUM_ENGINES; i++) { - struct drm_i915_gem_request *req; - - req = i915_gem_active_get(&obj->last_read[i], - &obj->base.dev->struct_mutex); - if (req) - requests[n++] = req; + active = __I915_BO_ACTIVE(obj); + for_each_active(active, idx) { + ret = i915_gem_active_wait_unlocked(&obj->last_read[idx], true, + args->timeout_ns >= 0 ? &args->timeout_ns : NULL, + to_rps_client(file)); + if (ret) + break; } -out: - i915_gem_object_put(obj); - mutex_unlock(&dev->struct_mutex); - - for (i = 0; i < n; i++) { - if (ret == 0) - ret = __i915_wait_request(requests[i], true, - args->timeout_ns > 0 ? &args->timeout_ns : NULL, - to_rps_client(file)); - i915_gem_request_put(requests[i]); - } + i915_gem_object_put_unlocked(obj); return ret; } -- 2.8.1 _______________________________________________ Intel-gfx mailing list Intel-gfx@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/intel-gfx