@@ -565,9 +565,11 @@ void i915_request_set_priority(struct i915_request *rq, int prio)
void __i915_sched_defer_request(struct intel_engine_cs *engine,
struct i915_request *rq)
{
+ struct list_head *pos = &rq->sched.waiters_list;
struct i915_sched *se = intel_engine_get_scheduler(engine);
- struct list_head *pl;
- LIST_HEAD(list);
+ const int prio = rq_prio(rq);
+ struct i915_request *rn;
+ LIST_HEAD(dfs);
SCHED_TRACE(se, "defer request " RQ_FMT "\n", RQ_ARG(rq));
@@ -579,14 +581,11 @@ void __i915_sched_defer_request(struct intel_engine_cs *engine,
* to those that are waiting upon it. So we traverse its chain of
* waiters and move any that are earlier than the request to after it.
*/
- pl = lookup_priolist(se, rq_prio(rq));
+ rq->sched.dfs.prev = NULL;
do {
- struct i915_dependency *p;
-
- GEM_BUG_ON(i915_request_is_active(rq));
- list_move_tail(&rq->sched.link, pl);
-
- for_each_waiter(p, rq) {
+ list_for_each_continue(pos, &rq->sched.waiters_list) {
+ struct i915_dependency *p =
+ list_entry(pos, typeof(*p), wait_link);
struct i915_request *w =
container_of(p->waiter, typeof(*w), sched);
@@ -602,19 +601,44 @@ void __i915_sched_defer_request(struct intel_engine_cs *engine,
__i915_request_has_started(w) &&
!__i915_request_is_complete(rq));
- if (!i915_request_is_ready(w))
+ if (!i915_request_in_priority_queue(w))
continue;
- if (rq_prio(w) < rq_prio(rq))
+ /*
+ * We also need to reorder within the same priority.
+ *
+ * This is unlike priority-inheritance, where if the
+ * signaler already has a higher priority [earlier
+ * deadline] than us, we can ignore as it will be
+ * scheduled first. If a waiter already has the
+ * same priority, we still have to push it to the end
+ * of the list. This unfortunately means we cannot
+ * use the rq_deadline() itself as a 'visited' bit.
+ */
+ if (rq_prio(w) < prio)
continue;
- GEM_BUG_ON(rq_prio(w) > rq_prio(rq));
- GEM_BUG_ON(i915_request_is_active(w));
- list_move_tail(&w->sched.link, &list);
+ GEM_BUG_ON(rq_prio(w) != prio);
+
+ /* Remember our position along this branch */
+ rq = stack_push(w, rq, pos);
+ pos = &rq->sched.waiters_list;
}
- rq = list_first_entry_or_null(&list, typeof(*rq), sched.link);
- } while (rq);
+ /* Note list is reversed for waiters wrt signal hierarchy */
+ GEM_BUG_ON(rq->engine != engine);
+ GEM_BUG_ON(!i915_request_in_priority_queue(rq));
+ list_move(&rq->sched.link, &dfs);
+
+ /* Track our visit, and prevent duplicate processing */
+ clear_bit(I915_FENCE_FLAG_PQUEUE, &rq->fence.flags);
+ } while ((rq = stack_pop(rq, &pos)));
+
+ pos = lookup_priolist(se, prio);
+ list_for_each_entry_safe(rq, rn, &dfs, sched.link) {
+ set_bit(I915_FENCE_FLAG_PQUEUE, &rq->fence.flags);
+ list_add_tail(&rq->sched.link, pos);
+ }
}
static void queue_request(struct i915_sched *se, struct i915_request *rq)