2018-10-31 07:53:31 +07:00
|
|
|
/* SPDX-License-Identifier: MIT */
|
2010-05-21 08:08:55 +07:00
|
|
|
#ifndef _INTEL_RINGBUFFER_H_
|
|
|
|
#define _INTEL_RINGBUFFER_H_
|
|
|
|
|
2018-09-05 20:57:05 +07:00
|
|
|
#include <drm/drm_util.h>
|
|
|
|
|
2014-05-11 04:10:43 +07:00
|
|
|
#include <linux/hashtable.h>
|
drm/i915: Replace global breadcrumbs with per-context interrupt tracking
A few years ago, see commit 688e6c725816 ("drm/i915: Slaughter the
thundering i915_wait_request herd"), the issue of handling multiple
clients waiting in parallel was brought to our attention. The
requirement was that every client should be woken immediately upon its
request being signaled, without incurring any cpu overhead.
To handle certain fragility of our hw meant that we could not do a
simple check inside the irq handler (some generations required almost
unbounded delays before we could be sure of seqno coherency) and so
request completion checking required delegation.
Before commit 688e6c725816, the solution was simple. Every client
waiting on a request would be woken on every interrupt and each would do
a heavyweight check to see if their request was complete. Commit
688e6c725816 introduced an rbtree so that only the earliest waiter on
the global timeline would woken, and would wake the next and so on.
(Along with various complications to handle requests being reordered
along the global timeline, and also a requirement for kthread to provide
a delegate for fence signaling that had no process context.)
The global rbtree depends on knowing the execution timeline (and global
seqno). Without knowing that order, we must instead check all contexts
queued to the HW to see which may have advanced. We trim that list by
only checking queued contexts that are being waited on, but still we
keep a list of all active contexts and their active signalers that we
inspect from inside the irq handler. By moving the waiters onto the fence
signal list, we can combine the client wakeup with the dma_fence
signaling (a dramatic reduction in complexity, but does require the HW
being coherent, the seqno must be visible from the cpu before the
interrupt is raised - we keep a timer backup just in case).
Having previously fixed all the issues with irq-seqno serialisation (by
inserting delays onto the GPU after each request instead of random delays
on the CPU after each interrupt), we can rely on the seqno state to
perfom direct wakeups from the interrupt handler. This allows us to
preserve our single context switch behaviour of the current routine,
with the only downside that we lose the RT priority sorting of wakeups.
In general, direct wakeup latency of multiple clients is about the same
(about 10% better in most cases) with a reduction in total CPU time spent
in the waiter (about 20-50% depending on gen). Average herd behaviour is
improved, but at the cost of not delegating wakeups on task_prio.
v2: Capture fence signaling state for error state and add comments to
warm even the most cold of hearts.
v3: Check if the request is still active before busywaiting
v4: Reduce the amount of pointer misdirection with list_for_each_safe
and using a local i915_request variable inside the loops
v5: Add a missing pluralisation to a purely informative selftest message.
References: 688e6c725816 ("drm/i915: Slaughter the thundering i915_wait_request herd")
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/20190129205230.19056-2-chris@chris-wilson.co.uk
2019-01-30 03:52:29 +07:00
|
|
|
#include <linux/irq_work.h>
|
2019-02-26 16:49:19 +07:00
|
|
|
#include <linux/random.h>
|
2018-04-26 14:47:16 +07:00
|
|
|
#include <linux/seqlock.h>
|
2018-02-21 16:56:36 +07:00
|
|
|
|
drm/i915/pmu: Expose a PMU interface for perf queries
From: Chris Wilson <chris@chris-wilson.co.uk>
From: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
From: Dmitry Rogozhkin <dmitry.v.rogozhkin@intel.com>
The first goal is to be able to measure GPU (and invidual ring) busyness
without having to poll registers from userspace. (Which not only incurs
holding the forcewake lock indefinitely, perturbing the system, but also
runs the risk of hanging the machine.) As an alternative we can use the
perf event counter interface to sample the ring registers periodically
and send those results to userspace.
Functionality we are exporting to userspace is via the existing perf PMU
API and can be exercised via the existing tools. For example:
perf stat -a -e i915/rcs0-busy/ -I 1000
Will print the render engine busynnes once per second. All the performance
counters can be enumerated (perf list) and have their unit of measure
correctly reported in sysfs.
v1-v2 (Chris Wilson):
v2: Use a common timer for the ring sampling.
v3: (Tvrtko Ursulin)
* Decouple uAPI from i915 engine ids.
* Complete uAPI defines.
* Refactor some code to helpers for clarity.
* Skip sampling disabled engines.
* Expose counters in sysfs.
* Pass in fake regs to avoid null ptr deref in perf core.
* Convert to class/instance uAPI.
* Use shared driver code for rc6 residency, power and frequency.
v4: (Dmitry Rogozhkin)
* Register PMU with .task_ctx_nr=perf_invalid_context
* Expose cpumask for the PMU with the single CPU in the mask
* Properly support pmu->stop(): it should call pmu->read()
* Properly support pmu->del(): it should call stop(event, PERF_EF_UPDATE)
* Introduce refcounting of event subscriptions.
* Make pmu.busy_stats a refcounter to avoid busy stats going away
with some deleted event.
* Expose cpumask for i915 PMU to avoid multiple events creation of
the same type followed by counter aggregation by perf-stat.
* Track CPUs getting online/offline to migrate perf context. If (likely)
cpumask will initially set CPU0, CONFIG_BOOTPARAM_HOTPLUG_CPU0 will be
needed to see effect of CPU status tracking.
* End result is that only global events are supported and perf stat
works correctly.
* Deny perf driver level sampling - it is prohibited for uncore PMU.
v5: (Tvrtko Ursulin)
* Don't hardcode number of engine samplers.
* Rewrite event ref-counting for correctness and simplicity.
* Store initial counter value when starting already enabled events
to correctly report values to all listeners.
* Fix RC6 residency readout.
* Comments, GPL header.
v6:
* Add missing entry to v4 changelog.
* Fix accounting in CPU hotplug case by copying the approach from
arch/x86/events/intel/cstate.c. (Dmitry Rogozhkin)
v7:
* Log failure message only on failure.
* Remove CPU hotplug notification state on unregister.
v8:
* Fix error unwind on failed registration.
* Checkpatch cleanup.
v9:
* Drop the energy metric, it is available via intel_rapl_perf.
(Ville Syrjälä)
* Use HAS_RC6(p). (Chris Wilson)
* Handle unsupported non-engine events. (Dmitry Rogozhkin)
* Rebase for intel_rc6_residency_ns needing caller managed
runtime pm.
* Drop HAS_RC6 checks from the read callback since creating those
events will be rejected at init time already.
* Add counter units to sysfs so perf stat output is nicer.
* Cleanup the attribute tables for brevity and readability.
v10:
* Fixed queued accounting.
v11:
* Move intel_engine_lookup_user to intel_engine_cs.c
* Commit update. (Joonas Lahtinen)
v12:
* More accurate sampling. (Chris Wilson)
* Store and report frequency in MHz for better usability from
perf stat.
* Removed metrics: queued, interrupts, rc6 counters.
* Sample engine busyness based on seqno difference only
for less MMIO (and forcewake) on all platforms. (Chris Wilson)
v13:
* Comment spelling, use mul_u32_u32 to work around potential GCC
issue and somne code alignment changes. (Chris Wilson)
v14:
* Rebase.
v15:
* Rebase for RPS refactoring.
v16:
* Use the dynamic slot in the CPU hotplug state machine so that we are
free to setup our state as multi-instance. Previously we were re-using
the CPUHP_AP_PERF_X86_UNCORE_ONLINE slot which is neither used as
multi-instance, nor owned by our driver to start with.
* Register the CPU hotplug handlers after the PMU, otherwise the callback
will get called before the PMU is initialized which can end up in
perf_pmu_migrate_context with an un-initialized base.
* Added workaround for a probable bug in cpuhp core.
v17:
* Remove workaround for the cpuhp bug.
v18:
* Rebase for drm_i915_gem_engine_class getting upstream before us.
v19:
* Rebase. (trivial)
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Signed-off-by: Dmitry Rogozhkin <dmitry.v.rogozhkin@intel.com>
Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Cc: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Dmitry Rogozhkin <dmitry.v.rogozhkin@intel.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk>
Signed-off-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20171121181852.16128-2-tvrtko.ursulin@linux.intel.com
2017-11-22 01:18:45 +07:00
|
|
|
#include "i915_pmu.h"
|
2019-03-06 01:03:30 +07:00
|
|
|
#include "i915_reg.h"
|
2018-02-21 16:56:36 +07:00
|
|
|
#include "i915_request.h"
|
2017-02-14 00:15:14 +07:00
|
|
|
#include "i915_selftest.h"
|
2019-06-21 14:08:10 +07:00
|
|
|
#include "gt/intel_timeline.h"
|
2019-03-08 20:25:17 +07:00
|
|
|
#include "intel_engine_types.h"
|
2018-03-14 06:19:20 +07:00
|
|
|
#include "intel_gpu_commands.h"
|
2018-12-03 20:33:41 +07:00
|
|
|
#include "intel_workarounds.h"
|
2014-05-11 04:10:43 +07:00
|
|
|
|
2017-10-09 18:02:57 +07:00
|
|
|
struct drm_printer;
|
2014-05-11 04:10:43 +07:00
|
|
|
|
2019-10-22 16:47:15 +07:00
|
|
|
struct intel_gt;
|
|
|
|
|
2014-07-24 23:04:28 +07:00
|
|
|
/* Early gen2 devices have a cacheline of just 32 bytes, using 64 is overkill,
|
|
|
|
* but keeps the logic simple. Indeed, the whole purpose of this macro is just
|
|
|
|
* to give some inclination as to some of the magic values used in the various
|
|
|
|
* workarounds!
|
|
|
|
*/
|
|
|
|
#define CACHELINE_BYTES 64
|
2019-01-16 16:15:19 +07:00
|
|
|
#define CACHELINE_DWORDS (CACHELINE_BYTES / sizeof(u32))
|
2014-07-24 23:04:28 +07:00
|
|
|
|
2019-03-26 04:49:40 +07:00
|
|
|
/*
|
|
|
|
* The register defines to be used with the following macros need to accept a
|
|
|
|
* base param, e.g:
|
|
|
|
*
|
|
|
|
* REG_FOO(base) _MMIO((base) + <relative offset>)
|
|
|
|
* ENGINE_READ(engine, REG_FOO);
|
|
|
|
*
|
|
|
|
* register arrays are to be defined and accessed as follows:
|
|
|
|
*
|
|
|
|
* REG_BAR(base, i) _MMIO((base) + <relative offset> + (i) * <shift>)
|
|
|
|
* ENGINE_READ_IDX(engine, REG_BAR, i)
|
|
|
|
*/
|
|
|
|
|
|
|
|
#define __ENGINE_REG_OP(op__, engine__, ...) \
|
|
|
|
intel_uncore_##op__((engine__)->uncore, __VA_ARGS__)
|
|
|
|
|
|
|
|
#define __ENGINE_READ_OP(op__, engine__, reg__) \
|
|
|
|
__ENGINE_REG_OP(op__, (engine__), reg__((engine__)->mmio_base))
|
2010-11-09 16:17:32 +07:00
|
|
|
|
2019-03-26 04:49:40 +07:00
|
|
|
#define ENGINE_READ16(...) __ENGINE_READ_OP(read16, __VA_ARGS__)
|
|
|
|
#define ENGINE_READ(...) __ENGINE_READ_OP(read, __VA_ARGS__)
|
|
|
|
#define ENGINE_READ_FW(...) __ENGINE_READ_OP(read_fw, __VA_ARGS__)
|
2019-07-03 22:52:25 +07:00
|
|
|
#define ENGINE_POSTING_READ(...) __ENGINE_READ_OP(posting_read_fw, __VA_ARGS__)
|
2019-06-11 17:45:45 +07:00
|
|
|
#define ENGINE_POSTING_READ16(...) __ENGINE_READ_OP(posting_read16, __VA_ARGS__)
|
2010-11-09 16:17:32 +07:00
|
|
|
|
2019-03-26 04:49:40 +07:00
|
|
|
#define ENGINE_READ64(engine__, lower_reg__, upper_reg__) \
|
|
|
|
__ENGINE_REG_OP(read64_2x32, (engine__), \
|
|
|
|
lower_reg__((engine__)->mmio_base), \
|
|
|
|
upper_reg__((engine__)->mmio_base))
|
2010-11-09 16:17:32 +07:00
|
|
|
|
2019-03-26 04:49:40 +07:00
|
|
|
#define ENGINE_READ_IDX(engine__, reg__, idx__) \
|
|
|
|
__ENGINE_REG_OP(read, (engine__), reg__((engine__)->mmio_base, (idx__)))
|
2010-11-09 16:17:32 +07:00
|
|
|
|
2019-03-26 04:49:40 +07:00
|
|
|
#define __ENGINE_WRITE_OP(op__, engine__, reg__, val__) \
|
|
|
|
__ENGINE_REG_OP(op__, (engine__), reg__((engine__)->mmio_base), (val__))
|
2010-08-02 21:29:44 +07:00
|
|
|
|
2019-03-26 04:49:40 +07:00
|
|
|
#define ENGINE_WRITE16(...) __ENGINE_WRITE_OP(write16, __VA_ARGS__)
|
|
|
|
#define ENGINE_WRITE(...) __ENGINE_WRITE_OP(write, __VA_ARGS__)
|
|
|
|
#define ENGINE_WRITE_FW(...) __ENGINE_WRITE_OP(write_fw, __VA_ARGS__)
|
2014-03-12 18:09:41 +07:00
|
|
|
|
2019-06-07 17:15:35 +07:00
|
|
|
#define GEN6_RING_FAULT_REG_READ(engine__) \
|
|
|
|
intel_uncore_read((engine__)->uncore, RING_FAULT_REG(engine__))
|
|
|
|
|
|
|
|
#define GEN6_RING_FAULT_REG_POSTING_READ(engine__) \
|
|
|
|
intel_uncore_posting_read((engine__)->uncore, RING_FAULT_REG(engine__))
|
|
|
|
|
|
|
|
#define GEN6_RING_FAULT_REG_RMW(engine__, clear__, set__) \
|
|
|
|
({ \
|
|
|
|
u32 __val; \
|
|
|
|
\
|
|
|
|
__val = intel_uncore_read((engine__)->uncore, \
|
|
|
|
RING_FAULT_REG(engine__)); \
|
|
|
|
__val &= ~(clear__); \
|
|
|
|
__val |= (set__); \
|
|
|
|
intel_uncore_write((engine__)->uncore, RING_FAULT_REG(engine__), \
|
|
|
|
__val); \
|
|
|
|
})
|
|
|
|
|
2014-06-30 23:53:37 +07:00
|
|
|
/* seqno size is actually only a uint32, but since we plan to use MI_FLUSH_DW to
|
|
|
|
* do the writes, and that must have qw aligned offsets, simply pretend it's 8b.
|
|
|
|
*/
|
2016-08-03 04:50:21 +07:00
|
|
|
enum intel_engine_hangcheck_action {
|
2016-11-18 20:09:04 +07:00
|
|
|
ENGINE_IDLE = 0,
|
|
|
|
ENGINE_WAIT,
|
|
|
|
ENGINE_ACTIVE_SEQNO,
|
|
|
|
ENGINE_ACTIVE_HEAD,
|
|
|
|
ENGINE_ACTIVE_SUBUNITS,
|
|
|
|
ENGINE_WAIT_KICK,
|
|
|
|
ENGINE_DEAD,
|
2013-08-11 16:44:01 +07:00
|
|
|
};
|
2013-06-12 16:35:32 +07:00
|
|
|
|
2016-11-18 20:09:04 +07:00
|
|
|
static inline const char *
|
|
|
|
hangcheck_action_to_str(const enum intel_engine_hangcheck_action a)
|
|
|
|
{
|
|
|
|
switch (a) {
|
|
|
|
case ENGINE_IDLE:
|
|
|
|
return "idle";
|
|
|
|
case ENGINE_WAIT:
|
|
|
|
return "wait";
|
|
|
|
case ENGINE_ACTIVE_SEQNO:
|
|
|
|
return "active seqno";
|
|
|
|
case ENGINE_ACTIVE_HEAD:
|
|
|
|
return "active head";
|
|
|
|
case ENGINE_ACTIVE_SUBUNITS:
|
|
|
|
return "active subunits";
|
|
|
|
case ENGINE_WAIT_KICK:
|
|
|
|
return "wait kick";
|
|
|
|
case ENGINE_DEAD:
|
|
|
|
return "dead";
|
|
|
|
}
|
|
|
|
|
|
|
|
return "unknown";
|
|
|
|
}
|
2014-01-31 00:04:43 +07:00
|
|
|
|
drm/i915/execlists: Preempt-to-busy
When using a global seqno, we required a precise stop-the-workd event to
handle preemption and unwind the global seqno counter. To accomplish
this, we would preempt to a special out-of-band context and wait for the
machine to report that it was idle. Given an idle machine, we could very
precisely see which requests had completed and which we needed to feed
back into the run queue.
However, now that we have scrapped the global seqno, we no longer need
to precisely unwind the global counter and only track requests by their
per-context seqno. This allows us to loosely unwind inflight requests
while scheduling a preemption, with the enormous caveat that the
requests we put back on the run queue are still _inflight_ (until the
preemption request is complete). This makes request tracking much more
messy, as at any point then we can see a completed request that we
believe is not currently scheduled for execution. We also have to be
careful not to rewind RING_TAIL past RING_HEAD on preempting to the
running context, and for this we use a semaphore to prevent completion
of the request before continuing.
To accomplish this feat, we change how we track requests scheduled to
the HW. Instead of appending our requests onto a single list as we
submit, we track each submission to ELSP as its own block. Then upon
receiving the CS preemption event, we promote the pending block to the
inflight block (discarding what was previously being tracked). As normal
CS completion events arrive, we then remove stale entries from the
inflight tracker.
v2: Be a tinge paranoid and ensure we flush the write into the HWS page
for the GPU semaphore to pick in a timely fashion.
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Reviewed-by: Mika Kuoppala <mika.kuoppala@linux.intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20190620142052.19311-1-chris@chris-wilson.co.uk
2019-06-20 21:20:51 +07:00
|
|
|
static inline unsigned int
|
|
|
|
execlists_num_ports(const struct intel_engine_execlists * const execlists)
|
2018-07-16 19:54:24 +07:00
|
|
|
{
|
drm/i915/execlists: Preempt-to-busy
When using a global seqno, we required a precise stop-the-workd event to
handle preemption and unwind the global seqno counter. To accomplish
this, we would preempt to a special out-of-band context and wait for the
machine to report that it was idle. Given an idle machine, we could very
precisely see which requests had completed and which we needed to feed
back into the run queue.
However, now that we have scrapped the global seqno, we no longer need
to precisely unwind the global counter and only track requests by their
per-context seqno. This allows us to loosely unwind inflight requests
while scheduling a preemption, with the enormous caveat that the
requests we put back on the run queue are still _inflight_ (until the
preemption request is complete). This makes request tracking much more
messy, as at any point then we can see a completed request that we
believe is not currently scheduled for execution. We also have to be
careful not to rewind RING_TAIL past RING_HEAD on preempting to the
running context, and for this we use a semaphore to prevent completion
of the request before continuing.
To accomplish this feat, we change how we track requests scheduled to
the HW. Instead of appending our requests onto a single list as we
submit, we track each submission to ELSP as its own block. Then upon
receiving the CS preemption event, we promote the pending block to the
inflight block (discarding what was previously being tracked). As normal
CS completion events arrive, we then remove stale entries from the
inflight tracker.
v2: Be a tinge paranoid and ensure we flush the write into the HWS page
for the GPU semaphore to pick in a timely fashion.
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Reviewed-by: Mika Kuoppala <mika.kuoppala@linux.intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20190620142052.19311-1-chris@chris-wilson.co.uk
2019-06-20 21:20:51 +07:00
|
|
|
return execlists->port_mask + 1;
|
2018-07-16 19:54:24 +07:00
|
|
|
}
|
|
|
|
|
drm/i915/execlists: Preempt-to-busy
When using a global seqno, we required a precise stop-the-workd event to
handle preemption and unwind the global seqno counter. To accomplish
this, we would preempt to a special out-of-band context and wait for the
machine to report that it was idle. Given an idle machine, we could very
precisely see which requests had completed and which we needed to feed
back into the run queue.
However, now that we have scrapped the global seqno, we no longer need
to precisely unwind the global counter and only track requests by their
per-context seqno. This allows us to loosely unwind inflight requests
while scheduling a preemption, with the enormous caveat that the
requests we put back on the run queue are still _inflight_ (until the
preemption request is complete). This makes request tracking much more
messy, as at any point then we can see a completed request that we
believe is not currently scheduled for execution. We also have to be
careful not to rewind RING_TAIL past RING_HEAD on preempting to the
running context, and for this we use a semaphore to prevent completion
of the request before continuing.
To accomplish this feat, we change how we track requests scheduled to
the HW. Instead of appending our requests onto a single list as we
submit, we track each submission to ELSP as its own block. Then upon
receiving the CS preemption event, we promote the pending block to the
inflight block (discarding what was previously being tracked). As normal
CS completion events arrive, we then remove stale entries from the
inflight tracker.
v2: Be a tinge paranoid and ensure we flush the write into the HWS page
for the GPU semaphore to pick in a timely fashion.
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Reviewed-by: Mika Kuoppala <mika.kuoppala@linux.intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20190620142052.19311-1-chris@chris-wilson.co.uk
2019-06-20 21:20:51 +07:00
|
|
|
static inline struct i915_request *
|
|
|
|
execlists_active(const struct intel_engine_execlists *execlists)
|
2017-10-24 04:32:36 +07:00
|
|
|
{
|
drm/i915/execlists: Preempt-to-busy
When using a global seqno, we required a precise stop-the-workd event to
handle preemption and unwind the global seqno counter. To accomplish
this, we would preempt to a special out-of-band context and wait for the
machine to report that it was idle. Given an idle machine, we could very
precisely see which requests had completed and which we needed to feed
back into the run queue.
However, now that we have scrapped the global seqno, we no longer need
to precisely unwind the global counter and only track requests by their
per-context seqno. This allows us to loosely unwind inflight requests
while scheduling a preemption, with the enormous caveat that the
requests we put back on the run queue are still _inflight_ (until the
preemption request is complete). This makes request tracking much more
messy, as at any point then we can see a completed request that we
believe is not currently scheduled for execution. We also have to be
careful not to rewind RING_TAIL past RING_HEAD on preempting to the
running context, and for this we use a semaphore to prevent completion
of the request before continuing.
To accomplish this feat, we change how we track requests scheduled to
the HW. Instead of appending our requests onto a single list as we
submit, we track each submission to ELSP as its own block. Then upon
receiving the CS preemption event, we promote the pending block to the
inflight block (discarding what was previously being tracked). As normal
CS completion events arrive, we then remove stale entries from the
inflight tracker.
v2: Be a tinge paranoid and ensure we flush the write into the HWS page
for the GPU semaphore to pick in a timely fashion.
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Reviewed-by: Mika Kuoppala <mika.kuoppala@linux.intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20190620142052.19311-1-chris@chris-wilson.co.uk
2019-06-20 21:20:51 +07:00
|
|
|
GEM_BUG_ON(execlists->active - execlists->inflight >
|
|
|
|
execlists_num_ports(execlists));
|
|
|
|
return READ_ONCE(*execlists->active);
|
2017-10-24 04:32:36 +07:00
|
|
|
}
|
|
|
|
|
2019-10-09 23:09:06 +07:00
|
|
|
static inline void
|
|
|
|
execlists_active_lock_bh(struct intel_engine_execlists *execlists)
|
|
|
|
{
|
|
|
|
local_bh_disable(); /* prevent local softirq and lock recursion */
|
|
|
|
tasklet_lock(&execlists->tasklet);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void
|
|
|
|
execlists_active_unlock_bh(struct intel_engine_execlists *execlists)
|
|
|
|
{
|
|
|
|
tasklet_unlock(&execlists->tasklet);
|
|
|
|
local_bh_enable(); /* restore softirq, and kick ksoftirqd! */
|
|
|
|
}
|
|
|
|
|
2019-04-11 20:05:14 +07:00
|
|
|
struct i915_request *
|
drm/i915/guc: Preemption! With GuC
Pretty similar to what we have on execlists.
We're reusing most of the GEM code, however, due to GuC quirks we need a
couple of extra bits.
Preemption is implemented as GuC action, and actions can be pretty slow.
Because of that, we're using a mutex to serialize them. Since we're
requesting preemption from the tasklet, the task of creating a workitem
and wrapping it in GuC action is delegated to a worker.
To distinguish that preemption has finished, we're using additional
piece of HWSP, and since we're not getting context switch interrupts,
we're also adding a user interrupt.
The fact that our special preempt context has completed unfortunately
doesn't mean that we're ready to submit new work. We also need to wait
for GuC to finish its own processing.
v2: Don't compile out the wait for GuC, handle workqueue flush on reset,
no need for ordered workqueue, put on a reviewer hat when looking at my own
patches (Chris)
Move struct work around in intel_guc, move user interruput outside of
conditional (Michał)
Keep ring around rather than chase though intel_context
v3: Extract WA for flushing ggtt writes to a helper (Chris)
Keep work_struct in intel_guc rather than engine (Michał)
Use ordered workqueue for inject_preempt worker to avoid GuC quirks.
v4: Drop now unused INTEL_GUC_PREEMPT_OPTION_IMMEDIATE (Daniele)
Drop stray newlines, use container_of for intel_guc in worker,
check for presence of workqueue when flushing it, rather than
enable_guc_submission modparam, reorder preempt postprocessing (Chris)
v5: Make wq NULL after destroying it
v6: Swap struct guc_preempt_work members (Michał)
Signed-off-by: Michał Winiarski <michal.winiarski@intel.com>
Cc: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Jeff McGee <jeff.mcgee@intel.com>
Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
Cc: Oscar Mateo <oscar.mateo@intel.com>
Cc: 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/20171026133558.19580-1-michal.winiarski@intel.com
2017-10-26 20:35:58 +07:00
|
|
|
execlists_unwind_incomplete_requests(struct intel_engine_execlists *execlists);
|
|
|
|
|
2010-05-21 08:08:55 +07:00
|
|
|
static inline u32
|
2018-02-12 17:24:15 +07:00
|
|
|
intel_read_status_page(const struct intel_engine_cs *engine, int reg)
|
2010-05-21 08:08:55 +07:00
|
|
|
{
|
2012-04-27 04:28:16 +07:00
|
|
|
/* Ensure that the compiler doesn't optimize away the load. */
|
2019-01-28 17:23:55 +07:00
|
|
|
return READ_ONCE(engine->status_page.addr[reg]);
|
2010-05-21 08:08:55 +07:00
|
|
|
}
|
|
|
|
|
2012-12-19 16:13:05 +07:00
|
|
|
static inline void
|
2017-03-24 23:35:38 +07:00
|
|
|
intel_write_status_page(struct intel_engine_cs *engine, int reg, u32 value)
|
2012-12-19 16:13:05 +07:00
|
|
|
{
|
2017-03-24 23:35:38 +07:00
|
|
|
/* Writing into the status page should be done sparingly. Since
|
|
|
|
* we do when we are uncertain of the device state, we take a bit
|
|
|
|
* of extra paranoia to try and ensure that the HWS takes the value
|
|
|
|
* we give and that it doesn't end up trapped inside the CPU!
|
|
|
|
*/
|
|
|
|
if (static_cpu_has(X86_FEATURE_CLFLUSH)) {
|
|
|
|
mb();
|
2019-01-28 17:23:55 +07:00
|
|
|
clflush(&engine->status_page.addr[reg]);
|
|
|
|
engine->status_page.addr[reg] = value;
|
|
|
|
clflush(&engine->status_page.addr[reg]);
|
2017-03-24 23:35:38 +07:00
|
|
|
mb();
|
|
|
|
} else {
|
2019-01-28 17:23:55 +07:00
|
|
|
WRITE_ONCE(engine->status_page.addr[reg], value);
|
2017-03-24 23:35:38 +07:00
|
|
|
}
|
2012-12-19 16:13:05 +07:00
|
|
|
}
|
|
|
|
|
2016-01-18 14:19:47 +07:00
|
|
|
/*
|
2011-01-14 02:06:50 +07:00
|
|
|
* Reads a dword out of the status page, which is written to from the command
|
|
|
|
* queue by automatic updates, MI_REPORT_HEAD, MI_STORE_DATA_INDEX, or
|
|
|
|
* MI_STORE_DATA_IMM.
|
|
|
|
*
|
|
|
|
* The following dwords have a reserved meaning:
|
|
|
|
* 0x00: ISR copy, updated when an ISR bit not set in the HWSTAM changes.
|
|
|
|
* 0x04: ring 0 head pointer
|
|
|
|
* 0x05: ring 1 head pointer (915-class)
|
|
|
|
* 0x06: ring 2 head pointer (915-class)
|
|
|
|
* 0x10-0x1b: Context status DWords (GM45)
|
|
|
|
* 0x1f: Last written status offset. (GM45)
|
2015-02-18 18:48:21 +07:00
|
|
|
* 0x20-0x2f: Reserved (Gen6+)
|
2011-01-14 02:06:50 +07:00
|
|
|
*
|
2015-02-18 18:48:21 +07:00
|
|
|
* The area from dword 0x30 to 0x3ff is available for driver usage.
|
2011-01-14 02:06:50 +07:00
|
|
|
*/
|
2019-01-25 19:00:05 +07:00
|
|
|
#define I915_GEM_HWS_PREEMPT 0x32
|
|
|
|
#define I915_GEM_HWS_PREEMPT_ADDR (I915_GEM_HWS_PREEMPT * sizeof(u32))
|
2019-01-29 01:18:09 +07:00
|
|
|
#define I915_GEM_HWS_SEQNO 0x40
|
|
|
|
#define I915_GEM_HWS_SEQNO_ADDR (I915_GEM_HWS_SEQNO * sizeof(u32))
|
|
|
|
#define I915_GEM_HWS_SCRATCH 0x80
|
2019-01-25 19:00:05 +07:00
|
|
|
#define I915_GEM_HWS_SCRATCH_ADDR (I915_GEM_HWS_SCRATCH * sizeof(u32))
|
2011-01-14 02:06:50 +07:00
|
|
|
|
2017-09-13 20:35:34 +07:00
|
|
|
#define I915_HWS_CSB_BUF0_INDEX 0x10
|
2017-09-13 15:56:05 +07:00
|
|
|
#define I915_HWS_CSB_WRITE_INDEX 0x1f
|
|
|
|
#define CNL_HWS_CSB_WRITE_INDEX 0x2f
|
2017-09-13 20:35:34 +07:00
|
|
|
|
2016-08-03 04:50:21 +07:00
|
|
|
struct intel_ring *
|
2019-08-10 01:25:18 +07:00
|
|
|
intel_engine_create_ring(struct intel_engine_cs *engine, int size);
|
2018-07-27 22:55:01 +07:00
|
|
|
int intel_ring_pin(struct intel_ring *ring);
|
2017-04-25 20:00:49 +07:00
|
|
|
void intel_ring_reset(struct intel_ring *ring, u32 tail);
|
2017-05-04 20:08:45 +07:00
|
|
|
unsigned int intel_ring_update_space(struct intel_ring *ring);
|
2016-08-03 04:50:23 +07:00
|
|
|
void intel_ring_unpin(struct intel_ring *ring);
|
2019-03-18 16:51:46 +07:00
|
|
|
void intel_ring_free(struct kref *ref);
|
|
|
|
|
|
|
|
static inline struct intel_ring *intel_ring_get(struct intel_ring *ring)
|
|
|
|
{
|
|
|
|
kref_get(&ring->ref);
|
|
|
|
return ring;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void intel_ring_put(struct intel_ring *ring)
|
|
|
|
{
|
|
|
|
kref_put(&ring->ref, intel_ring_free);
|
|
|
|
}
|
2014-07-24 23:04:15 +07:00
|
|
|
|
2016-08-03 04:50:21 +07:00
|
|
|
void intel_engine_stop(struct intel_engine_cs *engine);
|
|
|
|
void intel_engine_cleanup(struct intel_engine_cs *engine);
|
2011-03-20 08:14:27 +07:00
|
|
|
|
2018-02-21 16:56:36 +07:00
|
|
|
int __must_check intel_ring_cacheline_align(struct i915_request *rq);
|
2016-07-20 19:31:55 +07:00
|
|
|
|
2018-02-21 16:56:36 +07:00
|
|
|
u32 __must_check *intel_ring_begin(struct i915_request *rq, unsigned int n);
|
2016-07-20 19:31:55 +07:00
|
|
|
|
2018-02-21 16:56:36 +07:00
|
|
|
static inline void intel_ring_advance(struct i915_request *rq, u32 *cs)
|
2013-08-11 04:16:32 +07:00
|
|
|
{
|
2016-08-03 04:50:30 +07:00
|
|
|
/* Dummy function.
|
|
|
|
*
|
|
|
|
* This serves as a placeholder in the code so that the reader
|
|
|
|
* can compare against the preceding intel_ring_begin() and
|
|
|
|
* check that the number of dwords emitted matches the space
|
|
|
|
* reserved for the command packet (i.e. the value passed to
|
|
|
|
* intel_ring_begin()).
|
2016-08-03 04:50:29 +07:00
|
|
|
*/
|
2018-02-21 16:56:36 +07:00
|
|
|
GEM_BUG_ON((rq->ring->vaddr + rq->ring->emit) != cs);
|
2016-08-03 04:50:30 +07:00
|
|
|
}
|
|
|
|
|
2018-02-21 16:56:36 +07:00
|
|
|
static inline u32 intel_ring_wrap(const struct intel_ring *ring, u32 pos)
|
2017-03-27 20:00:07 +07:00
|
|
|
{
|
|
|
|
return pos & (ring->size - 1);
|
|
|
|
}
|
|
|
|
|
2018-06-11 18:08:45 +07:00
|
|
|
static inline bool
|
|
|
|
intel_ring_offset_valid(const struct intel_ring *ring,
|
|
|
|
unsigned int pos)
|
|
|
|
{
|
|
|
|
if (pos & -ring->size) /* must be strictly within the ring */
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (!IS_ALIGNED(pos, 8)) /* must be qword aligned */
|
|
|
|
return false;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2018-02-21 16:56:36 +07:00
|
|
|
static inline u32 intel_ring_offset(const struct i915_request *rq, void *addr)
|
2016-08-03 04:50:30 +07:00
|
|
|
{
|
|
|
|
/* Don't write ring->size (equivalent to 0) as that hangs some GPUs. */
|
2018-02-21 16:56:36 +07:00
|
|
|
u32 offset = addr - rq->ring->vaddr;
|
|
|
|
GEM_BUG_ON(offset > rq->ring->size);
|
|
|
|
return intel_ring_wrap(rq->ring, offset);
|
2013-08-11 04:16:32 +07:00
|
|
|
}
|
2016-07-20 19:31:55 +07:00
|
|
|
|
2017-03-27 20:14:12 +07:00
|
|
|
static inline void
|
|
|
|
assert_ring_tail_valid(const struct intel_ring *ring, unsigned int tail)
|
|
|
|
{
|
2018-06-11 18:08:45 +07:00
|
|
|
GEM_BUG_ON(!intel_ring_offset_valid(ring, tail));
|
2017-05-04 20:08:44 +07:00
|
|
|
|
|
|
|
/*
|
|
|
|
* "Ring Buffer Use"
|
|
|
|
* Gen2 BSpec "1. Programming Environment" / 1.4.4.6
|
|
|
|
* Gen3 BSpec "1c Memory Interface Functions" / 2.3.4.5
|
|
|
|
* Gen4+ BSpec "1c Memory Interface and Command Stream" / 5.3.4.5
|
|
|
|
* "If the Ring Buffer Head Pointer and the Tail Pointer are on the
|
|
|
|
* same cacheline, the Head Pointer must not be greater than the Tail
|
|
|
|
* Pointer."
|
|
|
|
*
|
|
|
|
* We use ring->head as the last known location of the actual RING_HEAD,
|
|
|
|
* it may have advanced but in the worst case it is equally the same
|
|
|
|
* as ring->head and so we should never program RING_TAIL to advance
|
|
|
|
* into the same cacheline as ring->head.
|
|
|
|
*/
|
|
|
|
#define cacheline(a) round_down(a, CACHELINE_BYTES)
|
|
|
|
GEM_BUG_ON(cacheline(tail) == cacheline(ring->head) &&
|
|
|
|
tail < ring->head);
|
|
|
|
#undef cacheline
|
2017-03-27 20:14:12 +07:00
|
|
|
}
|
|
|
|
|
2017-04-25 20:00:49 +07:00
|
|
|
static inline unsigned int
|
|
|
|
intel_ring_set_tail(struct intel_ring *ring, unsigned int tail)
|
|
|
|
{
|
|
|
|
/* Whilst writes to the tail are strictly order, there is no
|
|
|
|
* serialisation between readers and the writers. The tail may be
|
2018-02-21 16:56:36 +07:00
|
|
|
* read by i915_request_retire() just as it is being updated
|
2017-04-25 20:00:49 +07:00
|
|
|
* by execlists, as although the breadcrumb is complete, the context
|
|
|
|
* switch hasn't been seen.
|
|
|
|
*/
|
|
|
|
assert_ring_tail_valid(ring, tail);
|
|
|
|
ring->tail = tail;
|
|
|
|
return tail;
|
|
|
|
}
|
2013-08-11 04:16:32 +07:00
|
|
|
|
2019-02-07 14:18:22 +07:00
|
|
|
static inline unsigned int
|
|
|
|
__intel_ring_space(unsigned int head, unsigned int tail, unsigned int size)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* "If the Ring Buffer Head Pointer and the Tail Pointer are on the
|
|
|
|
* same cacheline, the Head Pointer must not be greater than the Tail
|
|
|
|
* Pointer."
|
|
|
|
*/
|
|
|
|
GEM_BUG_ON(!is_power_of_2(size));
|
|
|
|
return (head - tail - CACHELINE_BYTES) & (size - 1);
|
|
|
|
}
|
|
|
|
|
2019-10-22 16:47:15 +07:00
|
|
|
int intel_engines_init_mmio(struct intel_gt *gt);
|
2019-10-22 16:47:18 +07:00
|
|
|
int intel_engines_setup(struct intel_gt *gt);
|
2019-10-22 16:47:19 +07:00
|
|
|
int intel_engines_init(struct intel_gt *gt);
|
2019-10-22 16:47:17 +07:00
|
|
|
void intel_engines_cleanup(struct intel_gt *gt);
|
2019-05-01 17:32:04 +07:00
|
|
|
|
2016-07-13 22:03:41 +07:00
|
|
|
int intel_engine_init_common(struct intel_engine_cs *engine);
|
2016-08-03 19:19:16 +07:00
|
|
|
void intel_engine_cleanup_common(struct intel_engine_cs *engine);
|
2016-07-13 22:03:41 +07:00
|
|
|
|
2019-04-26 23:33:33 +07:00
|
|
|
int intel_ring_submission_setup(struct intel_engine_cs *engine);
|
|
|
|
int intel_ring_submission_init(struct intel_engine_cs *engine);
|
2010-05-21 08:08:55 +07:00
|
|
|
|
2018-05-17 01:33:55 +07:00
|
|
|
int intel_engine_stop_cs(struct intel_engine_cs *engine);
|
2018-08-15 00:18:57 +07:00
|
|
|
void intel_engine_cancel_stop_cs(struct intel_engine_cs *engine);
|
2018-05-17 01:33:55 +07:00
|
|
|
|
2018-12-18 17:27:12 +07:00
|
|
|
void intel_engine_set_hwsp_writemask(struct intel_engine_cs *engine, u32 mask);
|
|
|
|
|
2018-02-12 17:24:15 +07:00
|
|
|
u64 intel_engine_get_active_head(const struct intel_engine_cs *engine);
|
|
|
|
u64 intel_engine_get_last_batch_head(const struct intel_engine_cs *engine);
|
2016-10-05 03:11:31 +07:00
|
|
|
|
2016-10-12 16:05:17 +07:00
|
|
|
void intel_engine_get_instdone(struct intel_engine_cs *engine,
|
|
|
|
struct intel_instdone *instdone);
|
|
|
|
|
drm/i915: Invert the GEM wakeref hierarchy
In the current scheme, on submitting a request we take a single global
GEM wakeref, which trickles down to wake up all GT power domains. This
is undesirable as we would like to be able to localise our power
management to the available power domains and to remove the global GEM
operations from the heart of the driver. (The intent there is to push
global GEM decisions to the boundary as used by the GEM user interface.)
Now during request construction, each request is responsible via its
logical context to acquire a wakeref on each power domain it intends to
utilize. Currently, each request takes a wakeref on the engine(s) and
the engines themselves take a chipset wakeref. This gives us a
transition on each engine which we can extend if we want to insert more
powermangement control (such as soft rc6). The global GEM operations
that currently require a struct_mutex are reduced to listening to pm
events from the chipset GT wakeref. As we reduce the struct_mutex
requirement, these listeners should evaporate.
Perhaps the biggest immediate change is that this removes the
struct_mutex requirement around GT power management, allowing us greater
flexibility in request construction. Another important knock-on effect,
is that by tracking engine usage, we can insert a switch back to the
kernel context on that engine immediately, avoiding any extra delay or
inserting global synchronisation barriers. This makes tracking when an
engine and its associated contexts are idle much easier -- important for
when we forgo our assumed execution ordering and need idle barriers to
unpin used contexts. In the process, it means we remove a large chunk of
code whose only purpose was to switch back to the kernel context.
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Cc: Imre Deak <imre.deak@intel.com>
Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20190424200717.1686-5-chris@chris-wilson.co.uk
2019-04-25 03:07:17 +07:00
|
|
|
void intel_engine_init_execlists(struct intel_engine_cs *engine);
|
|
|
|
|
drm/i915: Replace global breadcrumbs with per-context interrupt tracking
A few years ago, see commit 688e6c725816 ("drm/i915: Slaughter the
thundering i915_wait_request herd"), the issue of handling multiple
clients waiting in parallel was brought to our attention. The
requirement was that every client should be woken immediately upon its
request being signaled, without incurring any cpu overhead.
To handle certain fragility of our hw meant that we could not do a
simple check inside the irq handler (some generations required almost
unbounded delays before we could be sure of seqno coherency) and so
request completion checking required delegation.
Before commit 688e6c725816, the solution was simple. Every client
waiting on a request would be woken on every interrupt and each would do
a heavyweight check to see if their request was complete. Commit
688e6c725816 introduced an rbtree so that only the earliest waiter on
the global timeline would woken, and would wake the next and so on.
(Along with various complications to handle requests being reordered
along the global timeline, and also a requirement for kthread to provide
a delegate for fence signaling that had no process context.)
The global rbtree depends on knowing the execution timeline (and global
seqno). Without knowing that order, we must instead check all contexts
queued to the HW to see which may have advanced. We trim that list by
only checking queued contexts that are being waited on, but still we
keep a list of all active contexts and their active signalers that we
inspect from inside the irq handler. By moving the waiters onto the fence
signal list, we can combine the client wakeup with the dma_fence
signaling (a dramatic reduction in complexity, but does require the HW
being coherent, the seqno must be visible from the cpu before the
interrupt is raised - we keep a timer backup just in case).
Having previously fixed all the issues with irq-seqno serialisation (by
inserting delays onto the GPU after each request instead of random delays
on the CPU after each interrupt), we can rely on the seqno state to
perfom direct wakeups from the interrupt handler. This allows us to
preserve our single context switch behaviour of the current routine,
with the only downside that we lose the RT priority sorting of wakeups.
In general, direct wakeup latency of multiple clients is about the same
(about 10% better in most cases) with a reduction in total CPU time spent
in the waiter (about 20-50% depending on gen). Average herd behaviour is
improved, but at the cost of not delegating wakeups on task_prio.
v2: Capture fence signaling state for error state and add comments to
warm even the most cold of hearts.
v3: Check if the request is still active before busywaiting
v4: Reduce the amount of pointer misdirection with list_for_each_safe
and using a local i915_request variable inside the loops
v5: Add a missing pluralisation to a purely informative selftest message.
References: 688e6c725816 ("drm/i915: Slaughter the thundering i915_wait_request herd")
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/20190129205230.19056-2-chris@chris-wilson.co.uk
2019-01-30 03:52:29 +07:00
|
|
|
void intel_engine_init_breadcrumbs(struct intel_engine_cs *engine);
|
|
|
|
void intel_engine_fini_breadcrumbs(struct intel_engine_cs *engine);
|
drm/i915: Slaughter the thundering i915_wait_request herd
One particularly stressful scenario consists of many independent tasks
all competing for GPU time and waiting upon the results (e.g. realtime
transcoding of many, many streams). One bottleneck in particular is that
each client waits on its own results, but every client is woken up after
every batchbuffer - hence the thunder of hooves as then every client must
do its heavyweight dance to read a coherent seqno to see if it is the
lucky one.
Ideally, we only want one client to wake up after the interrupt and
check its request for completion. Since the requests must retire in
order, we can select the first client on the oldest request to be woken.
Once that client has completed his wait, we can then wake up the
next client and so on. However, all clients then incur latency as every
process in the chain may be delayed for scheduling - this may also then
cause some priority inversion. To reduce the latency, when a client
is added or removed from the list, we scan the tree for completed
seqno and wake up all the completed waiters in parallel.
Using igt/benchmarks/gem_latency, we can demonstrate this effect. The
benchmark measures the number of GPU cycles between completion of a
batch and the client waking up from a call to wait-ioctl. With many
concurrent waiters, with each on a different request, we observe that
the wakeup latency before the patch scales nearly linearly with the
number of waiters (before external factors kick in making the scaling much
worse). After applying the patch, we can see that only the single waiter
for the request is being woken up, providing a constant wakeup latency
for every operation. However, the situation is not quite as rosy for
many waiters on the same request, though to the best of my knowledge this
is much less likely in practice. Here, we can observe that the
concurrent waiters incur extra latency from being woken up by the
solitary bottom-half, rather than directly by the interrupt. This
appears to be scheduler induced (having discounted adverse effects from
having a rbtree walk/erase in the wakeup path), each additional
wake_up_process() costs approximately 1us on big core. Another effect of
performing the secondary wakeups from the first bottom-half is the
incurred delay this imposes on high priority threads - rather than
immediately returning to userspace and leaving the interrupt handler to
wake the others.
To offset the delay incurred with additional waiters on a request, we
could use a hybrid scheme that did a quick read in the interrupt handler
and dequeued all the completed waiters (incurring the overhead in the
interrupt handler, not the best plan either as we then incur GPU
submission latency) but we would still have to wake up the bottom-half
every time to do the heavyweight slow read. Or we could only kick the
waiters on the seqno with the same priority as the current task (i.e. in
the realtime waiter scenario, only it is woken up immediately by the
interrupt and simply queues the next waiter before returning to userspace,
minimising its delay at the expense of the chain, and also reducing
contention on its scheduler runqueue). This is effective at avoid long
pauses in the interrupt handler and at avoiding the extra latency in
realtime/high-priority waiters.
v2: Convert from a kworker per engine into a dedicated kthread for the
bottom-half.
v3: Rename request members and tweak comments.
v4: Use a per-engine spinlock in the breadcrumbs bottom-half.
v5: Fix race in locklessly checking waiter status and kicking the task on
adding a new waiter.
v6: Fix deciding when to force the timer to hide missing interrupts.
v7: Move the bottom-half from the kthread to the first client process.
v8: Reword a few comments
v9: Break the busy loop when the interrupt is unmasked or has fired.
v10: Comments, unnecessary churn, better debugging from Tvrtko
v11: Wake all completed waiters on removing the current bottom-half to
reduce the latency of waking up a herd of clients all waiting on the
same request.
v12: Rearrange missed-interrupt fault injection so that it works with
igt/drv_missed_irq_hang
v13: Rename intel_breadcrumb and friends to intel_wait in preparation
for signal handling.
v14: RCU commentary, assert_spin_locked
v15: Hide BUG_ON behind the compiler; report on gem_latency findings.
v16: Sort seqno-groups by priority so that first-waiter has the highest
task priority (and so avoid priority inversion).
v17: Add waiters to post-mortem GPU hang state.
v18: Return early for a completed wait after acquiring the spinlock.
Avoids adding ourselves to the tree if the is already complete, and
skips the awkward question of why we don't do completion wakeups for
waits earlier than or equal to ourselves.
v19: Prepare for init_breadcrumbs to fail. Later patches may want to
allocate during init, so be prepared to propagate back the error code.
Testcase: igt/gem_concurrent_blit
Testcase: igt/benchmarks/gem_latency
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Cc: "Rogozhkin, Dmitry V" <dmitry.v.rogozhkin@intel.com>
Cc: "Gong, Zhipeng" <zhipeng.gong@intel.com>
Cc: Tvrtko Ursulin <tvrtko.ursulin@linux.intel.com>
Cc: Dave Gordon <david.s.gordon@intel.com>
Cc: "Goel, Akash" <akash.goel@intel.com>
Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@linux.intel.com> #v18
Link: http://patchwork.freedesktop.org/patch/msgid/1467390209-3576-6-git-send-email-chris@chris-wilson.co.uk
2016-07-01 23:23:15 +07:00
|
|
|
|
drm/i915: Replace global breadcrumbs with per-context interrupt tracking
A few years ago, see commit 688e6c725816 ("drm/i915: Slaughter the
thundering i915_wait_request herd"), the issue of handling multiple
clients waiting in parallel was brought to our attention. The
requirement was that every client should be woken immediately upon its
request being signaled, without incurring any cpu overhead.
To handle certain fragility of our hw meant that we could not do a
simple check inside the irq handler (some generations required almost
unbounded delays before we could be sure of seqno coherency) and so
request completion checking required delegation.
Before commit 688e6c725816, the solution was simple. Every client
waiting on a request would be woken on every interrupt and each would do
a heavyweight check to see if their request was complete. Commit
688e6c725816 introduced an rbtree so that only the earliest waiter on
the global timeline would woken, and would wake the next and so on.
(Along with various complications to handle requests being reordered
along the global timeline, and also a requirement for kthread to provide
a delegate for fence signaling that had no process context.)
The global rbtree depends on knowing the execution timeline (and global
seqno). Without knowing that order, we must instead check all contexts
queued to the HW to see which may have advanced. We trim that list by
only checking queued contexts that are being waited on, but still we
keep a list of all active contexts and their active signalers that we
inspect from inside the irq handler. By moving the waiters onto the fence
signal list, we can combine the client wakeup with the dma_fence
signaling (a dramatic reduction in complexity, but does require the HW
being coherent, the seqno must be visible from the cpu before the
interrupt is raised - we keep a timer backup just in case).
Having previously fixed all the issues with irq-seqno serialisation (by
inserting delays onto the GPU after each request instead of random delays
on the CPU after each interrupt), we can rely on the seqno state to
perfom direct wakeups from the interrupt handler. This allows us to
preserve our single context switch behaviour of the current routine,
with the only downside that we lose the RT priority sorting of wakeups.
In general, direct wakeup latency of multiple clients is about the same
(about 10% better in most cases) with a reduction in total CPU time spent
in the waiter (about 20-50% depending on gen). Average herd behaviour is
improved, but at the cost of not delegating wakeups on task_prio.
v2: Capture fence signaling state for error state and add comments to
warm even the most cold of hearts.
v3: Check if the request is still active before busywaiting
v4: Reduce the amount of pointer misdirection with list_for_each_safe
and using a local i915_request variable inside the loops
v5: Add a missing pluralisation to a purely informative selftest message.
References: 688e6c725816 ("drm/i915: Slaughter the thundering i915_wait_request herd")
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/20190129205230.19056-2-chris@chris-wilson.co.uk
2019-01-30 03:52:29 +07:00
|
|
|
void intel_engine_disarm_breadcrumbs(struct intel_engine_cs *engine);
|
drm/i915: Slaughter the thundering i915_wait_request herd
One particularly stressful scenario consists of many independent tasks
all competing for GPU time and waiting upon the results (e.g. realtime
transcoding of many, many streams). One bottleneck in particular is that
each client waits on its own results, but every client is woken up after
every batchbuffer - hence the thunder of hooves as then every client must
do its heavyweight dance to read a coherent seqno to see if it is the
lucky one.
Ideally, we only want one client to wake up after the interrupt and
check its request for completion. Since the requests must retire in
order, we can select the first client on the oldest request to be woken.
Once that client has completed his wait, we can then wake up the
next client and so on. However, all clients then incur latency as every
process in the chain may be delayed for scheduling - this may also then
cause some priority inversion. To reduce the latency, when a client
is added or removed from the list, we scan the tree for completed
seqno and wake up all the completed waiters in parallel.
Using igt/benchmarks/gem_latency, we can demonstrate this effect. The
benchmark measures the number of GPU cycles between completion of a
batch and the client waking up from a call to wait-ioctl. With many
concurrent waiters, with each on a different request, we observe that
the wakeup latency before the patch scales nearly linearly with the
number of waiters (before external factors kick in making the scaling much
worse). After applying the patch, we can see that only the single waiter
for the request is being woken up, providing a constant wakeup latency
for every operation. However, the situation is not quite as rosy for
many waiters on the same request, though to the best of my knowledge this
is much less likely in practice. Here, we can observe that the
concurrent waiters incur extra latency from being woken up by the
solitary bottom-half, rather than directly by the interrupt. This
appears to be scheduler induced (having discounted adverse effects from
having a rbtree walk/erase in the wakeup path), each additional
wake_up_process() costs approximately 1us on big core. Another effect of
performing the secondary wakeups from the first bottom-half is the
incurred delay this imposes on high priority threads - rather than
immediately returning to userspace and leaving the interrupt handler to
wake the others.
To offset the delay incurred with additional waiters on a request, we
could use a hybrid scheme that did a quick read in the interrupt handler
and dequeued all the completed waiters (incurring the overhead in the
interrupt handler, not the best plan either as we then incur GPU
submission latency) but we would still have to wake up the bottom-half
every time to do the heavyweight slow read. Or we could only kick the
waiters on the seqno with the same priority as the current task (i.e. in
the realtime waiter scenario, only it is woken up immediately by the
interrupt and simply queues the next waiter before returning to userspace,
minimising its delay at the expense of the chain, and also reducing
contention on its scheduler runqueue). This is effective at avoid long
pauses in the interrupt handler and at avoiding the extra latency in
realtime/high-priority waiters.
v2: Convert from a kworker per engine into a dedicated kthread for the
bottom-half.
v3: Rename request members and tweak comments.
v4: Use a per-engine spinlock in the breadcrumbs bottom-half.
v5: Fix race in locklessly checking waiter status and kicking the task on
adding a new waiter.
v6: Fix deciding when to force the timer to hide missing interrupts.
v7: Move the bottom-half from the kthread to the first client process.
v8: Reword a few comments
v9: Break the busy loop when the interrupt is unmasked or has fired.
v10: Comments, unnecessary churn, better debugging from Tvrtko
v11: Wake all completed waiters on removing the current bottom-half to
reduce the latency of waking up a herd of clients all waiting on the
same request.
v12: Rearrange missed-interrupt fault injection so that it works with
igt/drv_missed_irq_hang
v13: Rename intel_breadcrumb and friends to intel_wait in preparation
for signal handling.
v14: RCU commentary, assert_spin_locked
v15: Hide BUG_ON behind the compiler; report on gem_latency findings.
v16: Sort seqno-groups by priority so that first-waiter has the highest
task priority (and so avoid priority inversion).
v17: Add waiters to post-mortem GPU hang state.
v18: Return early for a completed wait after acquiring the spinlock.
Avoids adding ourselves to the tree if the is already complete, and
skips the awkward question of why we don't do completion wakeups for
waits earlier than or equal to ourselves.
v19: Prepare for init_breadcrumbs to fail. Later patches may want to
allocate during init, so be prepared to propagate back the error code.
Testcase: igt/gem_concurrent_blit
Testcase: igt/benchmarks/gem_latency
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Cc: "Rogozhkin, Dmitry V" <dmitry.v.rogozhkin@intel.com>
Cc: "Gong, Zhipeng" <zhipeng.gong@intel.com>
Cc: Tvrtko Ursulin <tvrtko.ursulin@linux.intel.com>
Cc: Dave Gordon <david.s.gordon@intel.com>
Cc: "Goel, Akash" <akash.goel@intel.com>
Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@linux.intel.com> #v18
Link: http://patchwork.freedesktop.org/patch/msgid/1467390209-3576-6-git-send-email-chris@chris-wilson.co.uk
2016-07-01 23:23:15 +07:00
|
|
|
|
drm/i915: Replace global breadcrumbs with per-context interrupt tracking
A few years ago, see commit 688e6c725816 ("drm/i915: Slaughter the
thundering i915_wait_request herd"), the issue of handling multiple
clients waiting in parallel was brought to our attention. The
requirement was that every client should be woken immediately upon its
request being signaled, without incurring any cpu overhead.
To handle certain fragility of our hw meant that we could not do a
simple check inside the irq handler (some generations required almost
unbounded delays before we could be sure of seqno coherency) and so
request completion checking required delegation.
Before commit 688e6c725816, the solution was simple. Every client
waiting on a request would be woken on every interrupt and each would do
a heavyweight check to see if their request was complete. Commit
688e6c725816 introduced an rbtree so that only the earliest waiter on
the global timeline would woken, and would wake the next and so on.
(Along with various complications to handle requests being reordered
along the global timeline, and also a requirement for kthread to provide
a delegate for fence signaling that had no process context.)
The global rbtree depends on knowing the execution timeline (and global
seqno). Without knowing that order, we must instead check all contexts
queued to the HW to see which may have advanced. We trim that list by
only checking queued contexts that are being waited on, but still we
keep a list of all active contexts and their active signalers that we
inspect from inside the irq handler. By moving the waiters onto the fence
signal list, we can combine the client wakeup with the dma_fence
signaling (a dramatic reduction in complexity, but does require the HW
being coherent, the seqno must be visible from the cpu before the
interrupt is raised - we keep a timer backup just in case).
Having previously fixed all the issues with irq-seqno serialisation (by
inserting delays onto the GPU after each request instead of random delays
on the CPU after each interrupt), we can rely on the seqno state to
perfom direct wakeups from the interrupt handler. This allows us to
preserve our single context switch behaviour of the current routine,
with the only downside that we lose the RT priority sorting of wakeups.
In general, direct wakeup latency of multiple clients is about the same
(about 10% better in most cases) with a reduction in total CPU time spent
in the waiter (about 20-50% depending on gen). Average herd behaviour is
improved, but at the cost of not delegating wakeups on task_prio.
v2: Capture fence signaling state for error state and add comments to
warm even the most cold of hearts.
v3: Check if the request is still active before busywaiting
v4: Reduce the amount of pointer misdirection with list_for_each_safe
and using a local i915_request variable inside the loops
v5: Add a missing pluralisation to a purely informative selftest message.
References: 688e6c725816 ("drm/i915: Slaughter the thundering i915_wait_request herd")
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/20190129205230.19056-2-chris@chris-wilson.co.uk
2019-01-30 03:52:29 +07:00
|
|
|
static inline void
|
|
|
|
intel_engine_queue_breadcrumbs(struct intel_engine_cs *engine)
|
drm/i915: Slaughter the thundering i915_wait_request herd
One particularly stressful scenario consists of many independent tasks
all competing for GPU time and waiting upon the results (e.g. realtime
transcoding of many, many streams). One bottleneck in particular is that
each client waits on its own results, but every client is woken up after
every batchbuffer - hence the thunder of hooves as then every client must
do its heavyweight dance to read a coherent seqno to see if it is the
lucky one.
Ideally, we only want one client to wake up after the interrupt and
check its request for completion. Since the requests must retire in
order, we can select the first client on the oldest request to be woken.
Once that client has completed his wait, we can then wake up the
next client and so on. However, all clients then incur latency as every
process in the chain may be delayed for scheduling - this may also then
cause some priority inversion. To reduce the latency, when a client
is added or removed from the list, we scan the tree for completed
seqno and wake up all the completed waiters in parallel.
Using igt/benchmarks/gem_latency, we can demonstrate this effect. The
benchmark measures the number of GPU cycles between completion of a
batch and the client waking up from a call to wait-ioctl. With many
concurrent waiters, with each on a different request, we observe that
the wakeup latency before the patch scales nearly linearly with the
number of waiters (before external factors kick in making the scaling much
worse). After applying the patch, we can see that only the single waiter
for the request is being woken up, providing a constant wakeup latency
for every operation. However, the situation is not quite as rosy for
many waiters on the same request, though to the best of my knowledge this
is much less likely in practice. Here, we can observe that the
concurrent waiters incur extra latency from being woken up by the
solitary bottom-half, rather than directly by the interrupt. This
appears to be scheduler induced (having discounted adverse effects from
having a rbtree walk/erase in the wakeup path), each additional
wake_up_process() costs approximately 1us on big core. Another effect of
performing the secondary wakeups from the first bottom-half is the
incurred delay this imposes on high priority threads - rather than
immediately returning to userspace and leaving the interrupt handler to
wake the others.
To offset the delay incurred with additional waiters on a request, we
could use a hybrid scheme that did a quick read in the interrupt handler
and dequeued all the completed waiters (incurring the overhead in the
interrupt handler, not the best plan either as we then incur GPU
submission latency) but we would still have to wake up the bottom-half
every time to do the heavyweight slow read. Or we could only kick the
waiters on the seqno with the same priority as the current task (i.e. in
the realtime waiter scenario, only it is woken up immediately by the
interrupt and simply queues the next waiter before returning to userspace,
minimising its delay at the expense of the chain, and also reducing
contention on its scheduler runqueue). This is effective at avoid long
pauses in the interrupt handler and at avoiding the extra latency in
realtime/high-priority waiters.
v2: Convert from a kworker per engine into a dedicated kthread for the
bottom-half.
v3: Rename request members and tweak comments.
v4: Use a per-engine spinlock in the breadcrumbs bottom-half.
v5: Fix race in locklessly checking waiter status and kicking the task on
adding a new waiter.
v6: Fix deciding when to force the timer to hide missing interrupts.
v7: Move the bottom-half from the kthread to the first client process.
v8: Reword a few comments
v9: Break the busy loop when the interrupt is unmasked or has fired.
v10: Comments, unnecessary churn, better debugging from Tvrtko
v11: Wake all completed waiters on removing the current bottom-half to
reduce the latency of waking up a herd of clients all waiting on the
same request.
v12: Rearrange missed-interrupt fault injection so that it works with
igt/drv_missed_irq_hang
v13: Rename intel_breadcrumb and friends to intel_wait in preparation
for signal handling.
v14: RCU commentary, assert_spin_locked
v15: Hide BUG_ON behind the compiler; report on gem_latency findings.
v16: Sort seqno-groups by priority so that first-waiter has the highest
task priority (and so avoid priority inversion).
v17: Add waiters to post-mortem GPU hang state.
v18: Return early for a completed wait after acquiring the spinlock.
Avoids adding ourselves to the tree if the is already complete, and
skips the awkward question of why we don't do completion wakeups for
waits earlier than or equal to ourselves.
v19: Prepare for init_breadcrumbs to fail. Later patches may want to
allocate during init, so be prepared to propagate back the error code.
Testcase: igt/gem_concurrent_blit
Testcase: igt/benchmarks/gem_latency
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Cc: "Rogozhkin, Dmitry V" <dmitry.v.rogozhkin@intel.com>
Cc: "Gong, Zhipeng" <zhipeng.gong@intel.com>
Cc: Tvrtko Ursulin <tvrtko.ursulin@linux.intel.com>
Cc: Dave Gordon <david.s.gordon@intel.com>
Cc: "Goel, Akash" <akash.goel@intel.com>
Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@linux.intel.com> #v18
Link: http://patchwork.freedesktop.org/patch/msgid/1467390209-3576-6-git-send-email-chris@chris-wilson.co.uk
2016-07-01 23:23:15 +07:00
|
|
|
{
|
drm/i915: Replace global breadcrumbs with per-context interrupt tracking
A few years ago, see commit 688e6c725816 ("drm/i915: Slaughter the
thundering i915_wait_request herd"), the issue of handling multiple
clients waiting in parallel was brought to our attention. The
requirement was that every client should be woken immediately upon its
request being signaled, without incurring any cpu overhead.
To handle certain fragility of our hw meant that we could not do a
simple check inside the irq handler (some generations required almost
unbounded delays before we could be sure of seqno coherency) and so
request completion checking required delegation.
Before commit 688e6c725816, the solution was simple. Every client
waiting on a request would be woken on every interrupt and each would do
a heavyweight check to see if their request was complete. Commit
688e6c725816 introduced an rbtree so that only the earliest waiter on
the global timeline would woken, and would wake the next and so on.
(Along with various complications to handle requests being reordered
along the global timeline, and also a requirement for kthread to provide
a delegate for fence signaling that had no process context.)
The global rbtree depends on knowing the execution timeline (and global
seqno). Without knowing that order, we must instead check all contexts
queued to the HW to see which may have advanced. We trim that list by
only checking queued contexts that are being waited on, but still we
keep a list of all active contexts and their active signalers that we
inspect from inside the irq handler. By moving the waiters onto the fence
signal list, we can combine the client wakeup with the dma_fence
signaling (a dramatic reduction in complexity, but does require the HW
being coherent, the seqno must be visible from the cpu before the
interrupt is raised - we keep a timer backup just in case).
Having previously fixed all the issues with irq-seqno serialisation (by
inserting delays onto the GPU after each request instead of random delays
on the CPU after each interrupt), we can rely on the seqno state to
perfom direct wakeups from the interrupt handler. This allows us to
preserve our single context switch behaviour of the current routine,
with the only downside that we lose the RT priority sorting of wakeups.
In general, direct wakeup latency of multiple clients is about the same
(about 10% better in most cases) with a reduction in total CPU time spent
in the waiter (about 20-50% depending on gen). Average herd behaviour is
improved, but at the cost of not delegating wakeups on task_prio.
v2: Capture fence signaling state for error state and add comments to
warm even the most cold of hearts.
v3: Check if the request is still active before busywaiting
v4: Reduce the amount of pointer misdirection with list_for_each_safe
and using a local i915_request variable inside the loops
v5: Add a missing pluralisation to a purely informative selftest message.
References: 688e6c725816 ("drm/i915: Slaughter the thundering i915_wait_request herd")
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/20190129205230.19056-2-chris@chris-wilson.co.uk
2019-01-30 03:52:29 +07:00
|
|
|
irq_work_queue(&engine->breadcrumbs.irq_work);
|
drm/i915: Slaughter the thundering i915_wait_request herd
One particularly stressful scenario consists of many independent tasks
all competing for GPU time and waiting upon the results (e.g. realtime
transcoding of many, many streams). One bottleneck in particular is that
each client waits on its own results, but every client is woken up after
every batchbuffer - hence the thunder of hooves as then every client must
do its heavyweight dance to read a coherent seqno to see if it is the
lucky one.
Ideally, we only want one client to wake up after the interrupt and
check its request for completion. Since the requests must retire in
order, we can select the first client on the oldest request to be woken.
Once that client has completed his wait, we can then wake up the
next client and so on. However, all clients then incur latency as every
process in the chain may be delayed for scheduling - this may also then
cause some priority inversion. To reduce the latency, when a client
is added or removed from the list, we scan the tree for completed
seqno and wake up all the completed waiters in parallel.
Using igt/benchmarks/gem_latency, we can demonstrate this effect. The
benchmark measures the number of GPU cycles between completion of a
batch and the client waking up from a call to wait-ioctl. With many
concurrent waiters, with each on a different request, we observe that
the wakeup latency before the patch scales nearly linearly with the
number of waiters (before external factors kick in making the scaling much
worse). After applying the patch, we can see that only the single waiter
for the request is being woken up, providing a constant wakeup latency
for every operation. However, the situation is not quite as rosy for
many waiters on the same request, though to the best of my knowledge this
is much less likely in practice. Here, we can observe that the
concurrent waiters incur extra latency from being woken up by the
solitary bottom-half, rather than directly by the interrupt. This
appears to be scheduler induced (having discounted adverse effects from
having a rbtree walk/erase in the wakeup path), each additional
wake_up_process() costs approximately 1us on big core. Another effect of
performing the secondary wakeups from the first bottom-half is the
incurred delay this imposes on high priority threads - rather than
immediately returning to userspace and leaving the interrupt handler to
wake the others.
To offset the delay incurred with additional waiters on a request, we
could use a hybrid scheme that did a quick read in the interrupt handler
and dequeued all the completed waiters (incurring the overhead in the
interrupt handler, not the best plan either as we then incur GPU
submission latency) but we would still have to wake up the bottom-half
every time to do the heavyweight slow read. Or we could only kick the
waiters on the seqno with the same priority as the current task (i.e. in
the realtime waiter scenario, only it is woken up immediately by the
interrupt and simply queues the next waiter before returning to userspace,
minimising its delay at the expense of the chain, and also reducing
contention on its scheduler runqueue). This is effective at avoid long
pauses in the interrupt handler and at avoiding the extra latency in
realtime/high-priority waiters.
v2: Convert from a kworker per engine into a dedicated kthread for the
bottom-half.
v3: Rename request members and tweak comments.
v4: Use a per-engine spinlock in the breadcrumbs bottom-half.
v5: Fix race in locklessly checking waiter status and kicking the task on
adding a new waiter.
v6: Fix deciding when to force the timer to hide missing interrupts.
v7: Move the bottom-half from the kthread to the first client process.
v8: Reword a few comments
v9: Break the busy loop when the interrupt is unmasked or has fired.
v10: Comments, unnecessary churn, better debugging from Tvrtko
v11: Wake all completed waiters on removing the current bottom-half to
reduce the latency of waking up a herd of clients all waiting on the
same request.
v12: Rearrange missed-interrupt fault injection so that it works with
igt/drv_missed_irq_hang
v13: Rename intel_breadcrumb and friends to intel_wait in preparation
for signal handling.
v14: RCU commentary, assert_spin_locked
v15: Hide BUG_ON behind the compiler; report on gem_latency findings.
v16: Sort seqno-groups by priority so that first-waiter has the highest
task priority (and so avoid priority inversion).
v17: Add waiters to post-mortem GPU hang state.
v18: Return early for a completed wait after acquiring the spinlock.
Avoids adding ourselves to the tree if the is already complete, and
skips the awkward question of why we don't do completion wakeups for
waits earlier than or equal to ourselves.
v19: Prepare for init_breadcrumbs to fail. Later patches may want to
allocate during init, so be prepared to propagate back the error code.
Testcase: igt/gem_concurrent_blit
Testcase: igt/benchmarks/gem_latency
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Cc: "Rogozhkin, Dmitry V" <dmitry.v.rogozhkin@intel.com>
Cc: "Gong, Zhipeng" <zhipeng.gong@intel.com>
Cc: Tvrtko Ursulin <tvrtko.ursulin@linux.intel.com>
Cc: Dave Gordon <david.s.gordon@intel.com>
Cc: "Goel, Akash" <akash.goel@intel.com>
Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@linux.intel.com> #v18
Link: http://patchwork.freedesktop.org/patch/msgid/1467390209-3576-6-git-send-email-chris@chris-wilson.co.uk
2016-07-01 23:23:15 +07:00
|
|
|
}
|
|
|
|
|
2019-04-16 15:52:18 +07:00
|
|
|
void intel_engine_breadcrumbs_irq(struct intel_engine_cs *engine);
|
drm/i915: Slaughter the thundering i915_wait_request herd
One particularly stressful scenario consists of many independent tasks
all competing for GPU time and waiting upon the results (e.g. realtime
transcoding of many, many streams). One bottleneck in particular is that
each client waits on its own results, but every client is woken up after
every batchbuffer - hence the thunder of hooves as then every client must
do its heavyweight dance to read a coherent seqno to see if it is the
lucky one.
Ideally, we only want one client to wake up after the interrupt and
check its request for completion. Since the requests must retire in
order, we can select the first client on the oldest request to be woken.
Once that client has completed his wait, we can then wake up the
next client and so on. However, all clients then incur latency as every
process in the chain may be delayed for scheduling - this may also then
cause some priority inversion. To reduce the latency, when a client
is added or removed from the list, we scan the tree for completed
seqno and wake up all the completed waiters in parallel.
Using igt/benchmarks/gem_latency, we can demonstrate this effect. The
benchmark measures the number of GPU cycles between completion of a
batch and the client waking up from a call to wait-ioctl. With many
concurrent waiters, with each on a different request, we observe that
the wakeup latency before the patch scales nearly linearly with the
number of waiters (before external factors kick in making the scaling much
worse). After applying the patch, we can see that only the single waiter
for the request is being woken up, providing a constant wakeup latency
for every operation. However, the situation is not quite as rosy for
many waiters on the same request, though to the best of my knowledge this
is much less likely in practice. Here, we can observe that the
concurrent waiters incur extra latency from being woken up by the
solitary bottom-half, rather than directly by the interrupt. This
appears to be scheduler induced (having discounted adverse effects from
having a rbtree walk/erase in the wakeup path), each additional
wake_up_process() costs approximately 1us on big core. Another effect of
performing the secondary wakeups from the first bottom-half is the
incurred delay this imposes on high priority threads - rather than
immediately returning to userspace and leaving the interrupt handler to
wake the others.
To offset the delay incurred with additional waiters on a request, we
could use a hybrid scheme that did a quick read in the interrupt handler
and dequeued all the completed waiters (incurring the overhead in the
interrupt handler, not the best plan either as we then incur GPU
submission latency) but we would still have to wake up the bottom-half
every time to do the heavyweight slow read. Or we could only kick the
waiters on the seqno with the same priority as the current task (i.e. in
the realtime waiter scenario, only it is woken up immediately by the
interrupt and simply queues the next waiter before returning to userspace,
minimising its delay at the expense of the chain, and also reducing
contention on its scheduler runqueue). This is effective at avoid long
pauses in the interrupt handler and at avoiding the extra latency in
realtime/high-priority waiters.
v2: Convert from a kworker per engine into a dedicated kthread for the
bottom-half.
v3: Rename request members and tweak comments.
v4: Use a per-engine spinlock in the breadcrumbs bottom-half.
v5: Fix race in locklessly checking waiter status and kicking the task on
adding a new waiter.
v6: Fix deciding when to force the timer to hide missing interrupts.
v7: Move the bottom-half from the kthread to the first client process.
v8: Reword a few comments
v9: Break the busy loop when the interrupt is unmasked or has fired.
v10: Comments, unnecessary churn, better debugging from Tvrtko
v11: Wake all completed waiters on removing the current bottom-half to
reduce the latency of waking up a herd of clients all waiting on the
same request.
v12: Rearrange missed-interrupt fault injection so that it works with
igt/drv_missed_irq_hang
v13: Rename intel_breadcrumb and friends to intel_wait in preparation
for signal handling.
v14: RCU commentary, assert_spin_locked
v15: Hide BUG_ON behind the compiler; report on gem_latency findings.
v16: Sort seqno-groups by priority so that first-waiter has the highest
task priority (and so avoid priority inversion).
v17: Add waiters to post-mortem GPU hang state.
v18: Return early for a completed wait after acquiring the spinlock.
Avoids adding ourselves to the tree if the is already complete, and
skips the awkward question of why we don't do completion wakeups for
waits earlier than or equal to ourselves.
v19: Prepare for init_breadcrumbs to fail. Later patches may want to
allocate during init, so be prepared to propagate back the error code.
Testcase: igt/gem_concurrent_blit
Testcase: igt/benchmarks/gem_latency
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Cc: "Rogozhkin, Dmitry V" <dmitry.v.rogozhkin@intel.com>
Cc: "Gong, Zhipeng" <zhipeng.gong@intel.com>
Cc: Tvrtko Ursulin <tvrtko.ursulin@linux.intel.com>
Cc: Dave Gordon <david.s.gordon@intel.com>
Cc: "Goel, Akash" <akash.goel@intel.com>
Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@linux.intel.com> #v18
Link: http://patchwork.freedesktop.org/patch/msgid/1467390209-3576-6-git-send-email-chris@chris-wilson.co.uk
2016-07-01 23:23:15 +07:00
|
|
|
|
2016-10-07 13:53:26 +07:00
|
|
|
void intel_engine_reset_breadcrumbs(struct intel_engine_cs *engine);
|
drm/i915: Slaughter the thundering i915_wait_request herd
One particularly stressful scenario consists of many independent tasks
all competing for GPU time and waiting upon the results (e.g. realtime
transcoding of many, many streams). One bottleneck in particular is that
each client waits on its own results, but every client is woken up after
every batchbuffer - hence the thunder of hooves as then every client must
do its heavyweight dance to read a coherent seqno to see if it is the
lucky one.
Ideally, we only want one client to wake up after the interrupt and
check its request for completion. Since the requests must retire in
order, we can select the first client on the oldest request to be woken.
Once that client has completed his wait, we can then wake up the
next client and so on. However, all clients then incur latency as every
process in the chain may be delayed for scheduling - this may also then
cause some priority inversion. To reduce the latency, when a client
is added or removed from the list, we scan the tree for completed
seqno and wake up all the completed waiters in parallel.
Using igt/benchmarks/gem_latency, we can demonstrate this effect. The
benchmark measures the number of GPU cycles between completion of a
batch and the client waking up from a call to wait-ioctl. With many
concurrent waiters, with each on a different request, we observe that
the wakeup latency before the patch scales nearly linearly with the
number of waiters (before external factors kick in making the scaling much
worse). After applying the patch, we can see that only the single waiter
for the request is being woken up, providing a constant wakeup latency
for every operation. However, the situation is not quite as rosy for
many waiters on the same request, though to the best of my knowledge this
is much less likely in practice. Here, we can observe that the
concurrent waiters incur extra latency from being woken up by the
solitary bottom-half, rather than directly by the interrupt. This
appears to be scheduler induced (having discounted adverse effects from
having a rbtree walk/erase in the wakeup path), each additional
wake_up_process() costs approximately 1us on big core. Another effect of
performing the secondary wakeups from the first bottom-half is the
incurred delay this imposes on high priority threads - rather than
immediately returning to userspace and leaving the interrupt handler to
wake the others.
To offset the delay incurred with additional waiters on a request, we
could use a hybrid scheme that did a quick read in the interrupt handler
and dequeued all the completed waiters (incurring the overhead in the
interrupt handler, not the best plan either as we then incur GPU
submission latency) but we would still have to wake up the bottom-half
every time to do the heavyweight slow read. Or we could only kick the
waiters on the seqno with the same priority as the current task (i.e. in
the realtime waiter scenario, only it is woken up immediately by the
interrupt and simply queues the next waiter before returning to userspace,
minimising its delay at the expense of the chain, and also reducing
contention on its scheduler runqueue). This is effective at avoid long
pauses in the interrupt handler and at avoiding the extra latency in
realtime/high-priority waiters.
v2: Convert from a kworker per engine into a dedicated kthread for the
bottom-half.
v3: Rename request members and tweak comments.
v4: Use a per-engine spinlock in the breadcrumbs bottom-half.
v5: Fix race in locklessly checking waiter status and kicking the task on
adding a new waiter.
v6: Fix deciding when to force the timer to hide missing interrupts.
v7: Move the bottom-half from the kthread to the first client process.
v8: Reword a few comments
v9: Break the busy loop when the interrupt is unmasked or has fired.
v10: Comments, unnecessary churn, better debugging from Tvrtko
v11: Wake all completed waiters on removing the current bottom-half to
reduce the latency of waking up a herd of clients all waiting on the
same request.
v12: Rearrange missed-interrupt fault injection so that it works with
igt/drv_missed_irq_hang
v13: Rename intel_breadcrumb and friends to intel_wait in preparation
for signal handling.
v14: RCU commentary, assert_spin_locked
v15: Hide BUG_ON behind the compiler; report on gem_latency findings.
v16: Sort seqno-groups by priority so that first-waiter has the highest
task priority (and so avoid priority inversion).
v17: Add waiters to post-mortem GPU hang state.
v18: Return early for a completed wait after acquiring the spinlock.
Avoids adding ourselves to the tree if the is already complete, and
skips the awkward question of why we don't do completion wakeups for
waits earlier than or equal to ourselves.
v19: Prepare for init_breadcrumbs to fail. Later patches may want to
allocate during init, so be prepared to propagate back the error code.
Testcase: igt/gem_concurrent_blit
Testcase: igt/benchmarks/gem_latency
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Cc: "Rogozhkin, Dmitry V" <dmitry.v.rogozhkin@intel.com>
Cc: "Gong, Zhipeng" <zhipeng.gong@intel.com>
Cc: Tvrtko Ursulin <tvrtko.ursulin@linux.intel.com>
Cc: Dave Gordon <david.s.gordon@intel.com>
Cc: "Goel, Akash" <akash.goel@intel.com>
Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@linux.intel.com> #v18
Link: http://patchwork.freedesktop.org/patch/msgid/1467390209-3576-6-git-send-email-chris@chris-wilson.co.uk
2016-07-01 23:23:15 +07:00
|
|
|
void intel_engine_fini_breadcrumbs(struct intel_engine_cs *engine);
|
|
|
|
|
drm/i915: Replace global breadcrumbs with per-context interrupt tracking
A few years ago, see commit 688e6c725816 ("drm/i915: Slaughter the
thundering i915_wait_request herd"), the issue of handling multiple
clients waiting in parallel was brought to our attention. The
requirement was that every client should be woken immediately upon its
request being signaled, without incurring any cpu overhead.
To handle certain fragility of our hw meant that we could not do a
simple check inside the irq handler (some generations required almost
unbounded delays before we could be sure of seqno coherency) and so
request completion checking required delegation.
Before commit 688e6c725816, the solution was simple. Every client
waiting on a request would be woken on every interrupt and each would do
a heavyweight check to see if their request was complete. Commit
688e6c725816 introduced an rbtree so that only the earliest waiter on
the global timeline would woken, and would wake the next and so on.
(Along with various complications to handle requests being reordered
along the global timeline, and also a requirement for kthread to provide
a delegate for fence signaling that had no process context.)
The global rbtree depends on knowing the execution timeline (and global
seqno). Without knowing that order, we must instead check all contexts
queued to the HW to see which may have advanced. We trim that list by
only checking queued contexts that are being waited on, but still we
keep a list of all active contexts and their active signalers that we
inspect from inside the irq handler. By moving the waiters onto the fence
signal list, we can combine the client wakeup with the dma_fence
signaling (a dramatic reduction in complexity, but does require the HW
being coherent, the seqno must be visible from the cpu before the
interrupt is raised - we keep a timer backup just in case).
Having previously fixed all the issues with irq-seqno serialisation (by
inserting delays onto the GPU after each request instead of random delays
on the CPU after each interrupt), we can rely on the seqno state to
perfom direct wakeups from the interrupt handler. This allows us to
preserve our single context switch behaviour of the current routine,
with the only downside that we lose the RT priority sorting of wakeups.
In general, direct wakeup latency of multiple clients is about the same
(about 10% better in most cases) with a reduction in total CPU time spent
in the waiter (about 20-50% depending on gen). Average herd behaviour is
improved, but at the cost of not delegating wakeups on task_prio.
v2: Capture fence signaling state for error state and add comments to
warm even the most cold of hearts.
v3: Check if the request is still active before busywaiting
v4: Reduce the amount of pointer misdirection with list_for_each_safe
and using a local i915_request variable inside the loops
v5: Add a missing pluralisation to a purely informative selftest message.
References: 688e6c725816 ("drm/i915: Slaughter the thundering i915_wait_request herd")
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/20190129205230.19056-2-chris@chris-wilson.co.uk
2019-01-30 03:52:29 +07:00
|
|
|
void intel_engine_print_breadcrumbs(struct intel_engine_cs *engine,
|
|
|
|
struct drm_printer *p);
|
|
|
|
|
2017-02-16 19:23:25 +07:00
|
|
|
static inline u32 *gen8_emit_pipe_control(u32 *batch, u32 flags, u32 offset)
|
|
|
|
{
|
|
|
|
memset(batch, 0, 6 * sizeof(u32));
|
|
|
|
|
|
|
|
batch[0] = GFX_OP_PIPE_CONTROL(6);
|
|
|
|
batch[1] = flags;
|
|
|
|
batch[2] = offset;
|
|
|
|
|
|
|
|
return batch + 6;
|
|
|
|
}
|
|
|
|
|
2017-10-26 03:00:15 +07:00
|
|
|
static inline u32 *
|
2018-12-28 22:31:13 +07:00
|
|
|
gen8_emit_ggtt_write_rcs(u32 *cs, u32 value, u32 gtt_offset, u32 flags)
|
2017-10-26 03:00:15 +07:00
|
|
|
{
|
|
|
|
/* We're using qword write, offset should be aligned to 8 bytes. */
|
|
|
|
GEM_BUG_ON(!IS_ALIGNED(gtt_offset, 8));
|
|
|
|
|
|
|
|
/* w/a for post sync ops following a GPGPU operation we
|
|
|
|
* need a prior CS_STALL, which is emitted by the flush
|
|
|
|
* following the batch.
|
|
|
|
*/
|
|
|
|
*cs++ = GFX_OP_PIPE_CONTROL(6);
|
2018-12-28 22:31:13 +07:00
|
|
|
*cs++ = flags | PIPE_CONTROL_QW_WRITE | PIPE_CONTROL_GLOBAL_GTT_IVB;
|
2017-10-26 03:00:15 +07:00
|
|
|
*cs++ = gtt_offset;
|
|
|
|
*cs++ = 0;
|
|
|
|
*cs++ = value;
|
|
|
|
/* We're thrashing one dword of HWS. */
|
|
|
|
*cs++ = 0;
|
|
|
|
|
|
|
|
return cs;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline u32 *
|
2019-03-18 16:51:51 +07:00
|
|
|
gen8_emit_ggtt_write(u32 *cs, u32 value, u32 gtt_offset, u32 flags)
|
2017-10-26 03:00:15 +07:00
|
|
|
{
|
|
|
|
/* w/a: bit 5 needs to be zero for MI_FLUSH_DW address. */
|
|
|
|
GEM_BUG_ON(gtt_offset & (1 << 5));
|
|
|
|
/* Offset should be aligned to 8 bytes for both (QW/DW) write types */
|
|
|
|
GEM_BUG_ON(!IS_ALIGNED(gtt_offset, 8));
|
|
|
|
|
2019-03-18 16:51:51 +07:00
|
|
|
*cs++ = (MI_FLUSH_DW + 1) | MI_FLUSH_DW_OP_STOREDW | flags;
|
2017-10-26 03:00:15 +07:00
|
|
|
*cs++ = gtt_offset | MI_FLUSH_DW_USE_GTT;
|
|
|
|
*cs++ = 0;
|
|
|
|
*cs++ = value;
|
|
|
|
|
|
|
|
return cs;
|
|
|
|
}
|
|
|
|
|
2019-07-13 02:29:53 +07:00
|
|
|
static inline void __intel_engine_reset(struct intel_engine_cs *engine,
|
|
|
|
bool stalled)
|
2019-01-25 20:22:28 +07:00
|
|
|
{
|
|
|
|
if (engine->reset.reset)
|
|
|
|
engine->reset.reset(engine, stalled);
|
drm/i915: Invert the GEM wakeref hierarchy
In the current scheme, on submitting a request we take a single global
GEM wakeref, which trickles down to wake up all GT power domains. This
is undesirable as we would like to be able to localise our power
management to the available power domains and to remove the global GEM
operations from the heart of the driver. (The intent there is to push
global GEM decisions to the boundary as used by the GEM user interface.)
Now during request construction, each request is responsible via its
logical context to acquire a wakeref on each power domain it intends to
utilize. Currently, each request takes a wakeref on the engine(s) and
the engines themselves take a chipset wakeref. This gives us a
transition on each engine which we can extend if we want to insert more
powermangement control (such as soft rc6). The global GEM operations
that currently require a struct_mutex are reduced to listening to pm
events from the chipset GT wakeref. As we reduce the struct_mutex
requirement, these listeners should evaporate.
Perhaps the biggest immediate change is that this removes the
struct_mutex requirement around GT power management, allowing us greater
flexibility in request construction. Another important knock-on effect,
is that by tracking engine usage, we can insert a switch back to the
kernel context on that engine immediately, avoiding any extra delay or
inserting global synchronisation barriers. This makes tracking when an
engine and its associated contexts are idle much easier -- important for
when we forgo our assumed execution ordering and need idle barriers to
unpin used contexts. In the process, it means we remove a large chunk of
code whose only purpose was to switch back to the kernel context.
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Cc: Imre Deak <imre.deak@intel.com>
Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20190424200717.1686-5-chris@chris-wilson.co.uk
2019-04-25 03:07:17 +07:00
|
|
|
engine->serial++; /* contexts lost */
|
2019-01-25 20:22:28 +07:00
|
|
|
}
|
|
|
|
|
2019-07-13 02:29:53 +07:00
|
|
|
bool intel_engines_are_idle(struct intel_gt *gt);
|
2019-10-08 17:56:55 +07:00
|
|
|
bool intel_engine_is_idle(struct intel_engine_cs *engine);
|
|
|
|
void intel_engine_flush_submission(struct intel_engine_cs *engine);
|
2017-03-03 19:19:46 +07:00
|
|
|
|
2019-07-13 02:29:53 +07:00
|
|
|
void intel_engines_reset_default_submission(struct intel_gt *gt);
|
2017-03-17 00:13:03 +07:00
|
|
|
|
2017-09-06 22:28:59 +07:00
|
|
|
bool intel_engine_can_store_dword(struct intel_engine_cs *engine);
|
2017-08-16 15:52:04 +07:00
|
|
|
|
2017-12-08 08:23:00 +07:00
|
|
|
__printf(3, 4)
|
|
|
|
void intel_engine_dump(struct intel_engine_cs *engine,
|
|
|
|
struct drm_printer *m,
|
|
|
|
const char *header, ...);
|
2017-10-09 18:02:57 +07:00
|
|
|
|
2017-11-22 01:18:48 +07:00
|
|
|
static inline void intel_engine_context_in(struct intel_engine_cs *engine)
|
|
|
|
{
|
|
|
|
unsigned long flags;
|
|
|
|
|
|
|
|
if (READ_ONCE(engine->stats.enabled) == 0)
|
|
|
|
return;
|
|
|
|
|
2018-04-26 14:47:16 +07:00
|
|
|
write_seqlock_irqsave(&engine->stats.lock, flags);
|
2017-11-22 01:18:48 +07:00
|
|
|
|
|
|
|
if (engine->stats.enabled > 0) {
|
|
|
|
if (engine->stats.active++ == 0)
|
|
|
|
engine->stats.start = ktime_get();
|
|
|
|
GEM_BUG_ON(engine->stats.active == 0);
|
|
|
|
}
|
|
|
|
|
2018-04-26 14:47:16 +07:00
|
|
|
write_sequnlock_irqrestore(&engine->stats.lock, flags);
|
2017-11-22 01:18:48 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
static inline void intel_engine_context_out(struct intel_engine_cs *engine)
|
|
|
|
{
|
|
|
|
unsigned long flags;
|
|
|
|
|
|
|
|
if (READ_ONCE(engine->stats.enabled) == 0)
|
|
|
|
return;
|
|
|
|
|
2018-04-26 14:47:16 +07:00
|
|
|
write_seqlock_irqsave(&engine->stats.lock, flags);
|
2017-11-22 01:18:48 +07:00
|
|
|
|
|
|
|
if (engine->stats.enabled > 0) {
|
|
|
|
ktime_t last;
|
|
|
|
|
|
|
|
if (engine->stats.active && --engine->stats.active == 0) {
|
|
|
|
/*
|
|
|
|
* Decrement the active context count and in case GPU
|
|
|
|
* is now idle add up to the running total.
|
|
|
|
*/
|
|
|
|
last = ktime_sub(ktime_get(), engine->stats.start);
|
|
|
|
|
|
|
|
engine->stats.total = ktime_add(engine->stats.total,
|
|
|
|
last);
|
|
|
|
} else if (engine->stats.active == 0) {
|
|
|
|
/*
|
|
|
|
* After turning on engine stats, context out might be
|
|
|
|
* the first event in which case we account from the
|
|
|
|
* time stats gathering was turned on.
|
|
|
|
*/
|
|
|
|
last = ktime_sub(ktime_get(), engine->stats.enabled_at);
|
|
|
|
|
|
|
|
engine->stats.total = ktime_add(engine->stats.total,
|
|
|
|
last);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-26 14:47:16 +07:00
|
|
|
write_sequnlock_irqrestore(&engine->stats.lock, flags);
|
2017-11-22 01:18:48 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
int intel_enable_engine_stats(struct intel_engine_cs *engine);
|
|
|
|
void intel_disable_engine_stats(struct intel_engine_cs *engine);
|
|
|
|
|
|
|
|
ktime_t intel_engine_get_busy_time(struct intel_engine_cs *engine);
|
|
|
|
|
2019-03-06 01:03:32 +07:00
|
|
|
struct i915_request *
|
|
|
|
intel_engine_find_active_request(struct intel_engine_cs *engine);
|
|
|
|
|
2019-05-28 01:35:59 +07:00
|
|
|
u32 intel_engine_context_size(struct drm_i915_private *i915, u8 class);
|
|
|
|
|
2018-07-16 20:21:54 +07:00
|
|
|
#if IS_ENABLED(CONFIG_DRM_I915_SELFTEST)
|
|
|
|
|
|
|
|
static inline bool inject_preempt_hang(struct intel_engine_execlists *execlists)
|
|
|
|
{
|
|
|
|
if (!execlists->preempt_hang.inject_hang)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
complete(&execlists->preempt_hang.completion);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
|
|
|
static inline bool inject_preempt_hang(struct intel_engine_execlists *execlists)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
2019-06-14 23:46:06 +07:00
|
|
|
void intel_engine_init_active(struct intel_engine_cs *engine,
|
|
|
|
unsigned int subclass);
|
|
|
|
#define ENGINE_PHYSICAL 0
|
|
|
|
#define ENGINE_MOCK 1
|
|
|
|
#define ENGINE_VIRTUAL 2
|
|
|
|
|
2010-05-21 08:08:55 +07:00
|
|
|
#endif /* _INTEL_RINGBUFFER_H_ */
|