diff options
Diffstat (limited to 'drivers/gpu/drm/i915/i915_gem_request.c')
-rw-r--r-- | drivers/gpu/drm/i915/i915_gem_request.c | 50 |
1 files changed, 43 insertions, 7 deletions
diff --git a/drivers/gpu/drm/i915/i915_gem_request.c b/drivers/gpu/drm/i915/i915_gem_request.c index 7802156d481a..cdaaeb6dd913 100644 --- a/drivers/gpu/drm/i915/i915_gem_request.c +++ b/drivers/gpu/drm/i915/i915_gem_request.c @@ -22,6 +22,8 @@ * */ +#include <linux/prefetch.h> + #include "i915_drv.h" static const char *i915_fence_get_driver_name(struct fence *fence) @@ -157,8 +159,16 @@ i915_gem_request_remove_from_client(struct drm_i915_gem_request *request) request->pid = NULL; } +void i915_gem_retire_noop(struct i915_gem_active *active, + struct drm_i915_gem_request *request) +{ + /* Space left intentionally blank */ +} + static void i915_gem_request_retire(struct drm_i915_gem_request *request) { + struct i915_gem_active *active, *next; + trace_i915_gem_request_retire(request); list_del_init(&request->link); @@ -172,6 +182,33 @@ static void i915_gem_request_retire(struct drm_i915_gem_request *request) */ request->ring->last_retired_head = request->postfix; + /* Walk through the active list, calling retire on each. This allows + * objects to track their GPU activity and mark themselves as idle + * when their *last* active request is completed (updating state + * tracking lists for eviction, active references for GEM, etc). + * + * As the ->retire() may free the node, we decouple it first and + * pass along the auxiliary information (to avoid dereferencing + * the node after the callback). + */ + list_for_each_entry_safe(active, next, &request->active_list, link) { + /* In microbenchmarks or focusing upon time inside the kernel, + * we may spend an inordinate amount of time simply handling + * the retirement of requests and processing their callbacks. + * Of which, this loop itself is particularly hot due to the + * cache misses when jumping around the list of i915_gem_active. + * So we try to keep this loop as streamlined as possible and + * also prefetch the next i915_gem_active to try and hide + * the likely cache miss. + */ + prefetchw(next); + + INIT_LIST_HEAD(&active->link); + active->request = NULL; + + active->retire(active, request); + } + i915_gem_request_remove_from_client(request); if (request->previous_context) { @@ -200,8 +237,6 @@ void i915_gem_request_retire_upto(struct drm_i915_gem_request *req) i915_gem_request_retire(tmp); } while (tmp != req); - - WARN_ON(i915_verify_lists(engine->dev)); } static int i915_gem_check_wedge(unsigned int reset_counter, bool interruptible) @@ -336,6 +371,7 @@ i915_gem_request_alloc(struct intel_engine_cs *engine, engine->fence_context, seqno); + INIT_LIST_HEAD(&req->active_list); req->i915 = dev_priv; req->engine = engine; req->ctx = i915_gem_context_get(ctx); @@ -570,9 +606,6 @@ int __i915_wait_request(struct drm_i915_gem_request *req, might_sleep(); - if (list_empty(&req->link)) - return 0; - if (i915_gem_request_completed(req)) return 0; @@ -705,10 +738,13 @@ int i915_wait_request(struct drm_i915_gem_request *req) { int ret; - GEM_BUG_ON(!req); lockdep_assert_held(&req->i915->drm.struct_mutex); + GEM_BUG_ON(list_empty(&req->link)); - ret = __i915_wait_request(req, req->i915->mm.interruptible, NULL, NULL); + ret = __i915_wait_request(req, + req->i915->mm.interruptible, + NULL, + NULL); if (ret) return ret; |