2018-04-18 21:40:50 +03:00
|
|
|
/*
|
|
|
|
* SPDX-License-Identifier: MIT
|
|
|
|
*
|
|
|
|
* Copyright © 2018 Intel Corporation
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef _I915_SCHEDULER_H_
|
|
|
|
#define _I915_SCHEDULER_H_
|
|
|
|
|
|
|
|
#include <linux/bitops.h>
|
2019-04-01 19:26:39 +03:00
|
|
|
#include <linux/list.h>
|
2018-10-01 17:47:54 +03:00
|
|
|
#include <linux/kernel.h>
|
2018-04-18 21:40:50 +03:00
|
|
|
|
2019-04-01 19:26:39 +03:00
|
|
|
#include "i915_scheduler_types.h"
|
2019-02-28 13:20:33 +03:00
|
|
|
|
drm/i915: Show timeline dependencies for debug
Include the signalers each request in the timeline is waiting on, as a
means to try and identify the cause of a stall. This can be quite
verbose, even as for now we only show each request in the timeline and
its immediate antecedents.
This generates output like:
Timeline 886: { count 1, ready: 0, inflight: 0, seqno: { current: 664, last: 666 }, engine: rcs0 }
U 886:29a- prio=0 @ 134ms: gem_exec_parall<4621>
U bc1:27a- prio=0 @ 134ms: gem_exec_parall[4917]
Timeline 825: { count 1, ready: 0, inflight: 0, seqno: { current: 802, last: 804 }, engine: vcs0 }
U 825:324 prio=0 @ 107ms: gem_exec_parall<4518>
U b75:140- prio=0 @ 110ms: gem_exec_parall<5486>
Timeline b46: { count 1, ready: 0, inflight: 0, seqno: { current: 782, last: 784 }, engine: vcs0 }
U b46:310- prio=0 @ 70ms: gem_exec_parall<5428>
U c11:170- prio=0 @ 70ms: gem_exec_parall[5501]
Timeline 96b: { count 1, ready: 0, inflight: 0, seqno: { current: 632, last: 634 }, engine: vcs0 }
U 96b:27a- prio=0 @ 67ms: gem_exec_parall<4878>
U b75:19e- prio=0 @ 67ms: gem_exec_parall<5486>
Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk>
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Link: https://patchwork.freedesktop.org/patch/msgid/20201119165616.10834-6-chris@chris-wilson.co.uk
2020-11-19 19:56:16 +03:00
|
|
|
struct drm_printer;
|
|
|
|
|
2021-01-20 15:14:38 +03:00
|
|
|
#define priolist_for_each_request(it, plist) \
|
|
|
|
list_for_each_entry(it, &(plist)->requests, sched.link)
|
2019-02-28 13:20:33 +03:00
|
|
|
|
2021-01-20 15:14:38 +03:00
|
|
|
#define priolist_for_each_request_consume(it, n, plist) \
|
|
|
|
list_for_each_entry_safe(it, n, &(plist)->requests, sched.link)
|
2019-02-28 13:20:33 +03:00
|
|
|
|
2018-10-01 17:47:54 +03:00
|
|
|
void i915_sched_node_init(struct i915_sched_node *node);
|
drm/i915: Use a ctor for TYPESAFE_BY_RCU i915_request
As we start peeking into requests for longer and longer, e.g.
incorporating use of spinlocks when only protected by an
rcu_read_lock(), we need to be careful in how we reset the request when
recycling and need to preserve any barriers that may still be in use as
the request is reset for reuse.
Quoting Linus Torvalds:
> If there is refcounting going on then why use SLAB_TYPESAFE_BY_RCU?
.. because the object can be accessed (by RCU) after the refcount has
gone down to zero, and the thing has been released.
That's the whole and only point of SLAB_TYPESAFE_BY_RCU.
That flag basically says:
"I may end up accessing this object *after* it has been free'd,
because there may be RCU lookups in flight"
This has nothing to do with constructors. It's ok if the object gets
reused as an object of the same type and does *not* get
re-initialized, because we're perfectly fine seeing old stale data.
What it guarantees is that the slab isn't shared with any other kind
of object, _and_ that the underlying pages are free'd after an RCU
quiescent period (so the pages aren't shared with another kind of
object either during an RCU walk).
And it doesn't necessarily have to have a constructor, because the
thing that a RCU walk will care about is
(a) guaranteed to be an object that *has* been on some RCU list (so
it's not a "new" object)
(b) the RCU walk needs to have logic to verify that it's still the
*same* object and hasn't been re-used as something else.
In contrast, a SLAB_TYPESAFE_BY_RCU memory gets free'd and re-used
immediately, but because it gets reused as the same kind of object,
the RCU walker can "know" what parts have meaning for re-use, in a way
it couidn't if the re-use was random.
That said, it *is* subtle, and people should be careful.
> So the re-use might initialize the fields lazily, not necessarily using a ctor.
If you have a well-defined refcount, and use "atomic_inc_not_zero()"
to guard the speculative RCU access section, and use
"atomic_dec_and_test()" in the freeing section, then you should be
safe wrt new allocations.
If you have a completely new allocation that has "random stale
content", you know that it cannot be on the RCU list, so there is no
speculative access that can ever see that random content.
So the only case you need to worry about is a re-use allocation, and
you know that the refcount will start out as zero even if you don't
have a constructor.
So you can think of the refcount itself as always having a zero
constructor, *BUT* you need to be careful with ordering.
In particular, whoever does the allocation needs to then set the
refcount to a non-zero value *after* it has initialized all the other
fields. And in particular, it needs to make sure that it uses the
proper memory ordering to do so.
NOTE! One thing to be very worried about is that re-initializing
whatever RCU lists means that now the RCU walker may be walking on the
wrong list so the walker may do the right thing for this particular
entry, but it may miss walking *other* entries. So then you can get
spurious lookup failures, because the RCU walker never walked all the
way to the end of the right list. That ends up being a much more
subtle bug.
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20191122094924.629690-1-chris@chris-wilson.co.uk
2019-11-22 12:49:24 +03:00
|
|
|
void i915_sched_node_reinit(struct i915_sched_node *node);
|
2018-10-01 17:47:54 +03:00
|
|
|
|
|
|
|
bool __i915_sched_node_add_dependency(struct i915_sched_node *node,
|
|
|
|
struct i915_sched_node *signal,
|
|
|
|
struct i915_dependency *dep,
|
|
|
|
unsigned long flags);
|
|
|
|
|
2019-02-28 13:20:33 +03:00
|
|
|
int i915_sched_node_add_dependency(struct i915_sched_node *node,
|
2020-05-07 18:51:09 +03:00
|
|
|
struct i915_sched_node *signal,
|
|
|
|
unsigned long flags);
|
2018-10-01 17:47:54 +03:00
|
|
|
|
2019-02-28 13:20:33 +03:00
|
|
|
void i915_sched_node_fini(struct i915_sched_node *node);
|
2018-10-01 17:47:54 +03:00
|
|
|
|
|
|
|
void i915_schedule(struct i915_request *request,
|
|
|
|
const struct i915_sched_attr *attr);
|
|
|
|
|
|
|
|
struct list_head *
|
2021-06-18 04:06:37 +03:00
|
|
|
i915_sched_lookup_priolist(struct i915_sched_engine *sched_engine, int prio);
|
2018-10-01 17:47:54 +03:00
|
|
|
|
2019-02-28 13:20:33 +03:00
|
|
|
void __i915_priolist_free(struct i915_priolist *p);
|
|
|
|
static inline void i915_priolist_free(struct i915_priolist *p)
|
|
|
|
{
|
|
|
|
if (p->priority != I915_PRIORITY_NORMAL)
|
|
|
|
__i915_priolist_free(p);
|
|
|
|
}
|
|
|
|
|
2021-06-18 04:06:31 +03:00
|
|
|
struct i915_sched_engine *
|
|
|
|
i915_sched_engine_create(unsigned int subclass);
|
|
|
|
|
|
|
|
static inline struct i915_sched_engine *
|
|
|
|
i915_sched_engine_get(struct i915_sched_engine *sched_engine)
|
|
|
|
{
|
|
|
|
kref_get(&sched_engine->ref);
|
|
|
|
return sched_engine;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void
|
|
|
|
i915_sched_engine_put(struct i915_sched_engine *sched_engine)
|
|
|
|
{
|
2021-07-27 03:23:21 +03:00
|
|
|
kref_put(&sched_engine->ref, sched_engine->destroy);
|
2021-06-18 04:06:31 +03:00
|
|
|
}
|
|
|
|
|
2021-06-18 04:06:32 +03:00
|
|
|
static inline bool
|
|
|
|
i915_sched_engine_is_empty(struct i915_sched_engine *sched_engine)
|
|
|
|
{
|
|
|
|
return RB_EMPTY_ROOT(&sched_engine->queue.rb_root);
|
|
|
|
}
|
|
|
|
|
2021-06-18 04:06:33 +03:00
|
|
|
static inline void
|
|
|
|
i915_sched_engine_reset_on_empty(struct i915_sched_engine *sched_engine)
|
|
|
|
{
|
|
|
|
if (i915_sched_engine_is_empty(sched_engine))
|
|
|
|
sched_engine->no_priolist = false;
|
|
|
|
}
|
|
|
|
|
2021-06-18 04:06:38 +03:00
|
|
|
static inline void
|
|
|
|
i915_sched_engine_active_lock_bh(struct i915_sched_engine *sched_engine)
|
|
|
|
{
|
|
|
|
local_bh_disable(); /* prevent local softirq and lock recursion */
|
|
|
|
tasklet_lock(&sched_engine->tasklet);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void
|
|
|
|
i915_sched_engine_active_unlock_bh(struct i915_sched_engine *sched_engine)
|
|
|
|
{
|
|
|
|
tasklet_unlock(&sched_engine->tasklet);
|
|
|
|
local_bh_enable(); /* restore softirq, and kick ksoftirqd! */
|
|
|
|
}
|
|
|
|
|
drm/i915: Show timeline dependencies for debug
Include the signalers each request in the timeline is waiting on, as a
means to try and identify the cause of a stall. This can be quite
verbose, even as for now we only show each request in the timeline and
its immediate antecedents.
This generates output like:
Timeline 886: { count 1, ready: 0, inflight: 0, seqno: { current: 664, last: 666 }, engine: rcs0 }
U 886:29a- prio=0 @ 134ms: gem_exec_parall<4621>
U bc1:27a- prio=0 @ 134ms: gem_exec_parall[4917]
Timeline 825: { count 1, ready: 0, inflight: 0, seqno: { current: 802, last: 804 }, engine: vcs0 }
U 825:324 prio=0 @ 107ms: gem_exec_parall<4518>
U b75:140- prio=0 @ 110ms: gem_exec_parall<5486>
Timeline b46: { count 1, ready: 0, inflight: 0, seqno: { current: 782, last: 784 }, engine: vcs0 }
U b46:310- prio=0 @ 70ms: gem_exec_parall<5428>
U c11:170- prio=0 @ 70ms: gem_exec_parall[5501]
Timeline 96b: { count 1, ready: 0, inflight: 0, seqno: { current: 632, last: 634 }, engine: vcs0 }
U 96b:27a- prio=0 @ 67ms: gem_exec_parall<4878>
U b75:19e- prio=0 @ 67ms: gem_exec_parall<5486>
Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk>
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Link: https://patchwork.freedesktop.org/patch/msgid/20201119165616.10834-6-chris@chris-wilson.co.uk
2020-11-19 19:56:16 +03:00
|
|
|
void i915_request_show_with_schedule(struct drm_printer *m,
|
|
|
|
const struct i915_request *rq,
|
|
|
|
const char *prefix,
|
|
|
|
int indent);
|
|
|
|
|
2021-07-27 03:23:24 +03:00
|
|
|
static inline bool
|
|
|
|
i915_sched_engine_disabled(struct i915_sched_engine *sched_engine)
|
|
|
|
{
|
|
|
|
return sched_engine->disabled(sched_engine);
|
|
|
|
}
|
|
|
|
|
2021-07-27 15:10:34 +03:00
|
|
|
void i915_scheduler_module_exit(void);
|
|
|
|
int i915_scheduler_module_init(void);
|
|
|
|
|
2018-04-18 21:40:50 +03:00
|
|
|
#endif /* _I915_SCHEDULER_H_ */
|