@@ -498,6 +498,9 @@ static inline bool i915_scheduler_is_dependency_valid(
if (I915_SQS_IS_FLYING(dep)) {
if (node->params.ring != dep->params.ring)
return true;
+
+ if (node->params.request->scheduler_flags & i915_req_sf_preempt)
+ return true;
}
return false;
@@ -1317,10 +1320,11 @@ static int i915_scheduler_pop_from_queue_locked(struct intel_engine_cs *ring,
struct i915_scheduler_queue_entry *best_wait, *fence_wait = NULL;
struct i915_scheduler_queue_entry *best;
struct i915_scheduler_queue_entry *node;
+ struct drm_i915_gem_request *req;
int ret;
int i;
bool signalled, any_queued;
- bool has_local, has_remote, only_remote;
+ bool has_local, has_remote, only_remote, local_preempt_only;
*pop_node = NULL;
ret = -ENODATA;
@@ -1346,18 +1350,40 @@ static int i915_scheduler_pop_from_queue_locked(struct intel_engine_cs *ring,
scheduler->stats[node->params.ring->id].fence_ignore++;
}
+ /* Attempt to re-enable pre-emption if a node wants to pre-empt
+ * but previously got downgraded. */
+ req = node->params.request;
+ if (req->scheduler_flags & i915_req_sf_was_preempt)
+ req->scheduler_flags |= i915_req_sf_preempt;
+
has_local = false;
has_remote = false;
+ local_preempt_only = (req->scheduler_flags & i915_req_sf_preempt) != 0;
for (i = 0; i < node->num_deps; i++) {
if (!i915_scheduler_is_dependency_valid(node, i))
continue;
- if (node->dep_list[i]->params.ring == node->params.ring)
+ if (node->dep_list[i]->params.ring == node->params.ring) {
has_local = true;
- else
+
+ if (local_preempt_only) {
+ req->scheduler_flags &= ~i915_req_sf_preempt;
+ if (i915_scheduler_is_dependency_valid(node, i))
+ local_preempt_only = false;
+ req->scheduler_flags |= i915_req_sf_preempt;
+ }
+ } else
has_remote = true;
}
+ if (has_local && local_preempt_only) {
+ /* If a preemptive node's local dependencies are all
+ * flying, then they can be ignored by un-preempting
+ * the node. */
+ req->scheduler_flags &= ~i915_req_sf_preempt;
+ has_local = false;
+ }
+
if (has_remote && !has_local)
only_remote = true;
@@ -1447,6 +1473,7 @@ static int i915_scheduler_submit(struct intel_engine_cs *ring, bool was_locked)
struct drm_i915_private *dev_priv = dev->dev_private;
struct i915_scheduler *scheduler = dev_priv->scheduler;
struct i915_scheduler_queue_entry *node;
+ struct drm_i915_gem_request *req;
unsigned long flags;
int ret = 0, count = 0;
@@ -1462,14 +1489,8 @@ static int i915_scheduler_submit(struct intel_engine_cs *ring, bool was_locked)
/* First time around, complain if anything unexpected occurs: */
ret = i915_scheduler_pop_from_queue_locked(ring, &node, &flags);
- if (ret) {
- spin_unlock_irqrestore(&scheduler->lock, flags);
-
- if (!was_locked)
- mutex_unlock(&dev->struct_mutex);
-
- return ret;
- }
+ if (ret)
+ goto exit;
do {
BUG_ON(!node);
@@ -1477,6 +1498,30 @@ static int i915_scheduler_submit(struct intel_engine_cs *ring, bool was_locked)
BUG_ON(node->status != i915_sqs_popped);
count++;
+ req = node->params.request;
+ if (req->scheduler_flags & i915_req_sf_preempt) {
+ struct i915_scheduler_queue_entry *fly;
+ bool got_flying = false;
+
+ list_for_each_entry(fly, &scheduler->node_queue[ring->id], link) {
+ if (!I915_SQS_IS_FLYING(fly))
+ continue;
+
+ got_flying = true;
+ if (fly->priority >= node->priority) {
+ /* Already working on something at least
+ * as important, so don't interrupt it. */
+ req->scheduler_flags &= ~i915_req_sf_preempt;
+ break;
+ }
+ }
+
+ if (!got_flying) {
+ /* Nothing to preempt so don't bother. */
+ req->scheduler_flags &= ~i915_req_sf_preempt;
+ }
+ }
+
/* The call to pop above will have removed the node from the
* list. So add it back in and mark it as in flight. */
i915_scheduler_fly_node(node);
@@ -1545,6 +1590,10 @@ static int i915_scheduler_submit(struct intel_engine_cs *ring, bool was_locked)
ret = i915_scheduler_pop_from_queue_locked(ring, &node, &flags);
} while (ret == 0);
+ /* Don't complain about not being able to submit extra entries */
+ if (ret == -ENODATA)
+ ret = 0;
+
/*
* Bump the priority of everything that was not submitted to prevent
* starvation of low priority tasks by a spamming high priority task.
@@ -1558,15 +1607,12 @@ static int i915_scheduler_submit(struct intel_engine_cs *ring, bool was_locked)
scheduler->priority_level_bump);
}
+exit:
spin_unlock_irqrestore(&scheduler->lock, flags);
if (!was_locked)
mutex_unlock(&dev->struct_mutex);
- /* Don't complain about not being able to submit extra entries */
- if (ret == -ENODATA)
- ret = 0;
-
return (ret < 0) ? ret : count;
}