2018-10-31 11:53:31 +11:00
|
|
|
/* SPDX-License-Identifier: MIT */
|
2010-05-21 09:08:55 +08:00
|
|
|
#ifndef _INTEL_RINGBUFFER_H_
|
|
|
|
#define _INTEL_RINGBUFFER_H_
|
|
|
|
|
2021-10-07 16:32:11 -07:00
|
|
|
#include <asm/cacheflush.h>
|
2018-09-05 15:57:05 +02:00
|
|
|
#include <drm/drm_util.h>
|
2022-03-21 15:38:15 -07:00
|
|
|
#include <drm/drm_cache.h>
|
2018-09-05 15:57:05 +02:00
|
|
|
|
2014-05-10 14: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-29 20:52:29 +00:00
|
|
|
#include <linux/irq_work.h>
|
2019-02-26 09:49:19 +00:00
|
|
|
#include <linux/random.h>
|
2018-04-26 08:47:16 +01:00
|
|
|
#include <linux/seqlock.h>
|
2018-02-21 09:56:36 +00: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-21 18:18:45 +00:00
|
|
|
#include "i915_pmu.h"
|
2018-02-21 09:56:36 +00:00
|
|
|
#include "i915_request.h"
|
2017-02-13 17:15:14 +00:00
|
|
|
#include "i915_selftest.h"
|
2019-03-08 13:25:17 +00:00
|
|
|
#include "intel_engine_types.h"
|
2021-05-21 11:32:14 -07:00
|
|
|
#include "intel_gt_types.h"
|
|
|
|
#include "intel_timeline.h"
|
2018-12-03 13:33:41 +00:00
|
|
|
#include "intel_workarounds.h"
|
2014-05-10 14:10:43 -07:00
|
|
|
|
2017-10-09 12:02:57 +01:00
|
|
|
struct drm_printer;
|
2021-06-17 08:30:12 +02:00
|
|
|
struct intel_context;
|
2019-10-22 10:47:15 +01:00
|
|
|
struct intel_gt;
|
2021-06-17 08:30:12 +02:00
|
|
|
struct lock_class_key;
|
2019-10-22 10:47:15 +01:00
|
|
|
|
2014-07-24 17:04:28 +01: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 11:15:19 +02:00
|
|
|
#define CACHELINE_DWORDS (CACHELINE_BYTES / sizeof(u32))
|
2014-07-24 17:04:28 +01:00
|
|
|
|
2019-12-13 07:51:52 -08:00
|
|
|
#define ENGINE_TRACE(e, fmt, ...) do { \
|
|
|
|
const struct intel_engine_cs *e__ __maybe_unused = (e); \
|
|
|
|
GEM_TRACE("%s %s: " fmt, \
|
|
|
|
dev_name(e__->i915->drm.dev), e__->name, \
|
|
|
|
##__VA_ARGS__); \
|
|
|
|
} while (0)
|
|
|
|
|
2019-03-25 14: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 17:17:32 +08:00
|
|
|
|
2019-03-25 14: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 16:52:25 +01:00
|
|
|
#define ENGINE_POSTING_READ(...) __ENGINE_READ_OP(posting_read_fw, __VA_ARGS__)
|
2019-06-11 11:45:45 +01:00
|
|
|
#define ENGINE_POSTING_READ16(...) __ENGINE_READ_OP(posting_read16, __VA_ARGS__)
|
2010-11-09 17:17:32 +08:00
|
|
|
|
2019-03-25 14: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 17:17:32 +08:00
|
|
|
|
2019-03-25 14:49:40 -07:00
|
|
|
#define ENGINE_READ_IDX(engine__, reg__, idx__) \
|
|
|
|
__ENGINE_REG_OP(read, (engine__), reg__((engine__)->mmio_base, (idx__)))
|
2010-11-09 17:17:32 +08:00
|
|
|
|
2019-03-25 14: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 16:29:44 +02:00
|
|
|
|
2019-03-25 14: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 16:39:41 +05:30
|
|
|
|
2025-06-18 13:51:30 +00:00
|
|
|
#define __HAS_ENGINE(engine_mask, id) ((engine_mask) & BIT(id))
|
|
|
|
#define HAS_ENGINE(gt, id) __HAS_ENGINE((gt)->info.engine_mask, id)
|
|
|
|
|
|
|
|
#define __ENGINE_INSTANCES_MASK(mask, first, count) ({ \
|
|
|
|
unsigned int first__ = (first); \
|
|
|
|
unsigned int count__ = (count); \
|
|
|
|
((mask) & GENMASK(first__ + count__ - 1, first__)) >> first__; \
|
|
|
|
})
|
|
|
|
|
|
|
|
#define ENGINE_INSTANCES_MASK(gt, first, count) \
|
|
|
|
__ENGINE_INSTANCES_MASK((gt)->info.engine_mask, first, count)
|
|
|
|
|
|
|
|
#define RCS_MASK(gt) \
|
|
|
|
ENGINE_INSTANCES_MASK(gt, RCS0, I915_MAX_RCS)
|
|
|
|
#define BCS_MASK(gt) \
|
|
|
|
ENGINE_INSTANCES_MASK(gt, BCS0, I915_MAX_BCS)
|
|
|
|
#define VDBOX_MASK(gt) \
|
|
|
|
ENGINE_INSTANCES_MASK(gt, VCS0, I915_MAX_VCS)
|
|
|
|
#define VEBOX_MASK(gt) \
|
|
|
|
ENGINE_INSTANCES_MASK(gt, VECS0, I915_MAX_VECS)
|
|
|
|
#define CCS_MASK(gt) \
|
|
|
|
ENGINE_INSTANCES_MASK(gt, CCS0, I915_MAX_CCS)
|
|
|
|
|
2019-06-07 11:15:35 +01: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 09: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.
|
|
|
|
*/
|
2014-01-30 19:04:43 +02: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 15:20:51 +01:00
|
|
|
static inline unsigned int
|
|
|
|
execlists_num_ports(const struct intel_engine_execlists * const execlists)
|
2018-07-16 13:54:24 +01: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 15:20:51 +01:00
|
|
|
return execlists->port_mask + 1;
|
2018-07-16 13:54:24 +01: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 15:20:51 +01:00
|
|
|
static inline struct i915_request *
|
|
|
|
execlists_active(const struct intel_engine_execlists *execlists)
|
2017-10-23 22:32:36 +01:00
|
|
|
{
|
2020-03-09 17:05:40 +00:00
|
|
|
struct i915_request * const *cur, * const *old, *active;
|
|
|
|
|
|
|
|
cur = READ_ONCE(execlists->active);
|
|
|
|
smp_rmb(); /* pairs with overwrite protection in process_csb() */
|
|
|
|
do {
|
|
|
|
old = cur;
|
|
|
|
|
|
|
|
active = READ_ONCE(*cur);
|
|
|
|
cur = READ_ONCE(execlists->active);
|
|
|
|
|
|
|
|
smp_rmb(); /* and complete the seqlock retry */
|
|
|
|
} while (unlikely(cur != old));
|
|
|
|
|
|
|
|
return active;
|
2017-10-23 22:32:36 +01:00
|
|
|
}
|
|
|
|
|
2010-05-21 09:08:55 +08:00
|
|
|
static inline u32
|
2018-02-12 10:24:15 +00:00
|
|
|
intel_read_status_page(const struct intel_engine_cs *engine, int reg)
|
2010-05-21 09:08:55 +08:00
|
|
|
{
|
2012-04-26 23:28:16 +02:00
|
|
|
/* Ensure that the compiler doesn't optimize away the load. */
|
2019-01-28 10:23:55 +00:00
|
|
|
return READ_ONCE(engine->status_page.addr[reg]);
|
2010-05-21 09:08:55 +08:00
|
|
|
}
|
|
|
|
|
2012-12-19 11:13:05 +02:00
|
|
|
static inline void
|
2017-03-24 16:35:38 +00:00
|
|
|
intel_write_status_page(struct intel_engine_cs *engine, int reg, u32 value)
|
2012-12-19 11:13:05 +02:00
|
|
|
{
|
2017-03-24 16:35:38 +00: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!
|
|
|
|
*/
|
2022-03-21 15:38:15 -07:00
|
|
|
drm_clflush_virt_range(&engine->status_page.addr[reg], sizeof(value));
|
|
|
|
WRITE_ONCE(engine->status_page.addr[reg], value);
|
|
|
|
drm_clflush_virt_range(&engine->status_page.addr[reg], sizeof(value));
|
2012-12-19 11:13:05 +02:00
|
|
|
}
|
|
|
|
|
2016-01-18 09:19:47 +02:00
|
|
|
/*
|
2011-01-13 19:06:50 +00: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 11:48:21 +00:00
|
|
|
* 0x20-0x2f: Reserved (Gen6+)
|
2011-01-13 19:06:50 +00:00
|
|
|
*
|
2015-02-18 11:48:21 +00:00
|
|
|
* The area from dword 0x30 to 0x3ff is available for driver usage.
|
2011-01-13 19:06:50 +00:00
|
|
|
*/
|
2019-01-25 12:00:05 +00:00
|
|
|
#define I915_GEM_HWS_PREEMPT 0x32
|
|
|
|
#define I915_GEM_HWS_PREEMPT_ADDR (I915_GEM_HWS_PREEMPT * sizeof(u32))
|
2019-01-28 18:18:09 +00:00
|
|
|
#define I915_GEM_HWS_SEQNO 0x40
|
|
|
|
#define I915_GEM_HWS_SEQNO_ADDR (I915_GEM_HWS_SEQNO * sizeof(u32))
|
2021-06-17 08:30:13 +02:00
|
|
|
#define I915_GEM_HWS_MIGRATE (0x42 * sizeof(u32))
|
2023-09-26 10:37:37 +02:00
|
|
|
#define I915_GEM_HWS_GGTT_BIND 0x46
|
|
|
|
#define I915_GEM_HWS_GGTT_BIND_ADDR (I915_GEM_HWS_GGTT_BIND * sizeof(u32))
|
2021-09-24 12:14:39 -07:00
|
|
|
#define I915_GEM_HWS_PXP 0x60
|
|
|
|
#define I915_GEM_HWS_PXP_ADDR (I915_GEM_HWS_PXP * sizeof(u32))
|
2022-12-08 12:05:18 -08:00
|
|
|
#define I915_GEM_HWS_GSC 0x62
|
|
|
|
#define I915_GEM_HWS_GSC_ADDR (I915_GEM_HWS_GSC * sizeof(u32))
|
2019-01-28 18:18:09 +00:00
|
|
|
#define I915_GEM_HWS_SCRATCH 0x80
|
2011-01-13 19:06:50 +00:00
|
|
|
|
2017-09-13 14:35:34 +01:00
|
|
|
#define I915_HWS_CSB_BUF0_INDEX 0x10
|
2017-09-13 09:56:05 +01:00
|
|
|
#define I915_HWS_CSB_WRITE_INDEX 0x1f
|
2021-07-28 15:03:25 -07:00
|
|
|
#define ICL_HWS_CSB_WRITE_INDEX 0x2f
|
2022-02-09 15:11:43 +02:00
|
|
|
#define INTEL_HWS_CSB_WRITE_INDEX(__i915) \
|
|
|
|
(GRAPHICS_VER(__i915) >= 11 ? ICL_HWS_CSB_WRITE_INDEX : I915_HWS_CSB_WRITE_INDEX)
|
2017-09-13 14:35:34 +01:00
|
|
|
|
2016-08-02 22:50:21 +01:00
|
|
|
void intel_engine_stop(struct intel_engine_cs *engine);
|
|
|
|
void intel_engine_cleanup(struct intel_engine_cs *engine);
|
2011-03-19 18:14:27 -07:00
|
|
|
|
2019-10-22 10:47:15 +01:00
|
|
|
int intel_engines_init_mmio(struct intel_gt *gt);
|
2019-10-22 10:47:19 +01:00
|
|
|
int intel_engines_init(struct intel_gt *gt);
|
2019-12-22 12:07:52 +00:00
|
|
|
|
2020-04-03 21:33:03 +01:00
|
|
|
void intel_engine_free_request_pool(struct intel_engine_cs *engine);
|
|
|
|
|
2019-12-22 12:07:52 +00:00
|
|
|
void intel_engines_release(struct intel_gt *gt);
|
|
|
|
void intel_engines_free(struct intel_gt *gt);
|
2019-05-01 11:32:04 +01:00
|
|
|
|
2016-07-13 16:03:41 +01:00
|
|
|
int intel_engine_init_common(struct intel_engine_cs *engine);
|
2016-08-03 13:19:16 +01:00
|
|
|
void intel_engine_cleanup_common(struct intel_engine_cs *engine);
|
2016-07-13 16:03:41 +01:00
|
|
|
|
2020-01-31 07:57:15 +00:00
|
|
|
int intel_engine_resume(struct intel_engine_cs *engine);
|
|
|
|
|
2019-04-26 17:33:33 +01:00
|
|
|
int intel_ring_submission_setup(struct intel_engine_cs *engine);
|
2010-05-21 09:08:55 +08:00
|
|
|
|
2018-05-16 19:33:55 +01:00
|
|
|
int intel_engine_stop_cs(struct intel_engine_cs *engine);
|
2018-08-14 18:18:57 +01:00
|
|
|
void intel_engine_cancel_stop_cs(struct intel_engine_cs *engine);
|
2018-05-16 19:33:55 +01:00
|
|
|
|
2022-06-21 12:21:05 -07:00
|
|
|
void intel_engine_wait_for_pending_mi_fw(struct intel_engine_cs *engine);
|
|
|
|
|
2018-12-18 10:27:12 +00:00
|
|
|
void intel_engine_set_hwsp_writemask(struct intel_engine_cs *engine, u32 mask);
|
|
|
|
|
2018-02-12 10:24:15 +00: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-04 21:11:31 +01:00
|
|
|
|
2020-01-10 12:30:56 +00:00
|
|
|
void intel_engine_get_instdone(const struct intel_engine_cs *engine,
|
2016-10-12 10:05:17 +01:00
|
|
|
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-24 21:07:17 +01:00
|
|
|
void intel_engine_init_execlists(struct intel_engine_cs *engine);
|
|
|
|
|
2021-07-26 17:23:20 -07:00
|
|
|
bool intel_engine_irq_enable(struct intel_engine_cs *engine);
|
|
|
|
void intel_engine_irq_disable(struct intel_engine_cs *engine);
|
|
|
|
|
2019-07-12 20:29:53 +01:00
|
|
|
static inline void __intel_engine_reset(struct intel_engine_cs *engine,
|
|
|
|
bool stalled)
|
2019-01-25 13:22:28 +00:00
|
|
|
{
|
2019-12-22 12:07:52 +00:00
|
|
|
if (engine->reset.rewind)
|
|
|
|
engine->reset.rewind(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-24 21:07:17 +01:00
|
|
|
engine->serial++; /* contexts lost */
|
2019-01-25 13:22:28 +00:00
|
|
|
}
|
|
|
|
|
2019-07-12 20:29:53 +01:00
|
|
|
bool intel_engines_are_idle(struct intel_gt *gt);
|
2019-10-08 11:56:55 +01:00
|
|
|
bool intel_engine_is_idle(struct intel_engine_cs *engine);
|
2020-12-20 13:48:58 +00:00
|
|
|
|
|
|
|
void __intel_engine_flush_submission(struct intel_engine_cs *engine, bool sync);
|
|
|
|
static inline void intel_engine_flush_submission(struct intel_engine_cs *engine)
|
|
|
|
{
|
|
|
|
__intel_engine_flush_submission(engine, true);
|
|
|
|
}
|
2017-03-03 12:19:46 +00:00
|
|
|
|
2019-07-12 20:29:53 +01:00
|
|
|
void intel_engines_reset_default_submission(struct intel_gt *gt);
|
2017-03-16 17:13:03 +00:00
|
|
|
|
2017-09-06 16:28:59 +01:00
|
|
|
bool intel_engine_can_store_dword(struct intel_engine_cs *engine);
|
2017-08-16 09:52:04 +01:00
|
|
|
|
2017-12-08 01:23:00 +00:00
|
|
|
__printf(3, 4)
|
|
|
|
void intel_engine_dump(struct intel_engine_cs *engine,
|
|
|
|
struct drm_printer *m,
|
|
|
|
const char *header, ...);
|
2021-07-26 17:23:34 -07:00
|
|
|
void intel_engine_dump_active_requests(struct list_head *requests,
|
|
|
|
struct i915_request *hung_rq,
|
|
|
|
struct drm_printer *m);
|
2017-10-09 12:02:57 +01:00
|
|
|
|
2020-06-17 14:09:16 +01:00
|
|
|
ktime_t intel_engine_get_busy_time(struct intel_engine_cs *engine,
|
|
|
|
ktime_t *now);
|
2017-11-21 18:18:48 +00:00
|
|
|
|
2023-01-26 16:28:37 -08:00
|
|
|
void intel_engine_get_hung_entity(struct intel_engine_cs *engine,
|
|
|
|
struct intel_context **ce, struct i915_request **rq);
|
2019-03-05 18:03:32 +00:00
|
|
|
|
2019-12-05 16:44:22 +00:00
|
|
|
u32 intel_engine_context_size(struct intel_gt *gt, u8 class);
|
2021-06-17 08:30:12 +02:00
|
|
|
struct intel_context *
|
|
|
|
intel_engine_create_pinned_context(struct intel_engine_cs *engine,
|
|
|
|
struct i915_address_space *vm,
|
|
|
|
unsigned int ring_size,
|
|
|
|
unsigned int hwsp,
|
|
|
|
struct lock_class_key *key,
|
|
|
|
const char *name);
|
|
|
|
|
|
|
|
void intel_engine_destroy_pinned_context(struct intel_context *ce);
|
2019-05-27 18:35:59 +00:00
|
|
|
|
2022-03-01 16:15:54 -08:00
|
|
|
void xehp_enable_ccs_engines(struct intel_engine_cs *engine);
|
|
|
|
|
2019-06-14 17:46:06 +01:00
|
|
|
#define ENGINE_PHYSICAL 0
|
|
|
|
#define ENGINE_MOCK 1
|
|
|
|
#define ENGINE_VIRTUAL 2
|
|
|
|
|
2021-05-21 11:32:14 -07:00
|
|
|
static inline bool intel_engine_uses_guc(const struct intel_engine_cs *engine)
|
|
|
|
{
|
|
|
|
return engine->gt->submission_method >= INTEL_SUBMISSION_GUC;
|
|
|
|
}
|
|
|
|
|
2019-10-23 14:31:05 +01:00
|
|
|
static inline bool
|
|
|
|
intel_engine_has_preempt_reset(const struct intel_engine_cs *engine)
|
|
|
|
{
|
2021-10-05 10:17:28 -07:00
|
|
|
if (!CONFIG_DRM_I915_PREEMPT_TIMEOUT)
|
2019-10-29 09:16:32 +00:00
|
|
|
return false;
|
2019-10-23 14:31:05 +01:00
|
|
|
|
|
|
|
return intel_engine_has_preemption(engine);
|
|
|
|
}
|
|
|
|
|
2021-10-14 10:19:56 -07:00
|
|
|
#define FORCE_VIRTUAL BIT(0)
|
2021-07-26 17:23:16 -07:00
|
|
|
struct intel_context *
|
|
|
|
intel_engine_create_virtual(struct intel_engine_cs **siblings,
|
2021-10-14 10:19:56 -07:00
|
|
|
unsigned int count, unsigned long flags);
|
|
|
|
|
|
|
|
static inline struct intel_context *
|
|
|
|
intel_engine_create_parallel(struct intel_engine_cs **engines,
|
|
|
|
unsigned int num_engines,
|
|
|
|
unsigned int width)
|
|
|
|
{
|
|
|
|
GEM_BUG_ON(!engines[0]->cops->create_parallel);
|
|
|
|
return engines[0]->cops->create_parallel(engines, num_engines, width);
|
|
|
|
}
|
2021-07-26 17:23:16 -07:00
|
|
|
|
|
|
|
static inline bool
|
|
|
|
intel_virtual_engine_has_heartbeat(const struct intel_engine_cs *engine)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* For non-GuC submission we expect the back-end to look at the
|
|
|
|
* heartbeat status of the actual physical engine that the work
|
|
|
|
* has been (or is being) scheduled on, so we should only reach
|
|
|
|
* here with GuC submission enabled.
|
|
|
|
*/
|
|
|
|
GEM_BUG_ON(!intel_engine_uses_guc(engine));
|
|
|
|
|
|
|
|
return intel_guc_virtual_engine_has_heartbeat(engine);
|
|
|
|
}
|
|
|
|
|
2020-09-28 23:15:08 +01:00
|
|
|
static inline bool
|
|
|
|
intel_engine_has_heartbeat(const struct intel_engine_cs *engine)
|
|
|
|
{
|
2021-10-05 10:17:28 -07:00
|
|
|
if (!CONFIG_DRM_I915_HEARTBEAT_INTERVAL)
|
2020-09-28 23:15:08 +01:00
|
|
|
return false;
|
|
|
|
|
2021-07-26 17:23:16 -07:00
|
|
|
if (intel_engine_is_virtual(engine))
|
|
|
|
return intel_virtual_engine_has_heartbeat(engine);
|
|
|
|
else
|
|
|
|
return READ_ONCE(engine->props.heartbeat_interval_ms);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline struct intel_engine_cs *
|
|
|
|
intel_engine_get_sibling(struct intel_engine_cs *engine, unsigned int sibling)
|
|
|
|
{
|
|
|
|
GEM_BUG_ON(!intel_engine_is_virtual(engine));
|
|
|
|
return engine->cops->get_sibling(engine, sibling);
|
2020-09-28 23:15:08 +01:00
|
|
|
}
|
|
|
|
|
2021-07-26 17:23:33 -07:00
|
|
|
static inline void
|
|
|
|
intel_engine_set_hung_context(struct intel_engine_cs *engine,
|
|
|
|
struct intel_context *ce)
|
|
|
|
{
|
|
|
|
engine->hung_ce = ce;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void
|
|
|
|
intel_engine_clear_hung_context(struct intel_engine_cs *engine)
|
|
|
|
{
|
|
|
|
intel_engine_set_hung_context(engine, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline struct intel_context *
|
|
|
|
intel_engine_get_hung_context(struct intel_engine_cs *engine)
|
|
|
|
{
|
|
|
|
return engine->hung_ce;
|
|
|
|
}
|
|
|
|
|
2022-10-06 14:38:10 -07:00
|
|
|
u64 intel_clamp_heartbeat_interval_ms(struct intel_engine_cs *engine, u64 value);
|
|
|
|
u64 intel_clamp_max_busywait_duration_ns(struct intel_engine_cs *engine, u64 value);
|
|
|
|
u64 intel_clamp_preempt_timeout_ms(struct intel_engine_cs *engine, u64 value);
|
|
|
|
u64 intel_clamp_stop_timeout_ms(struct intel_engine_cs *engine, u64 value);
|
|
|
|
u64 intel_clamp_timeslice_duration_ms(struct intel_engine_cs *engine, u64 value);
|
|
|
|
|
2025-06-18 13:51:30 +00:00
|
|
|
#define rb_to_uabi_engine(rb) \
|
|
|
|
rb_entry_safe(rb, struct intel_engine_cs, uabi_node)
|
|
|
|
|
|
|
|
#define for_each_uabi_engine(engine__, i915__) \
|
|
|
|
for ((engine__) = rb_to_uabi_engine(rb_first(&(i915__)->uabi_engines));\
|
|
|
|
(engine__); \
|
|
|
|
(engine__) = rb_to_uabi_engine(rb_next(&(engine__)->uabi_node)))
|
|
|
|
|
2010-05-21 09:08:55 +08:00
|
|
|
#endif /* _INTEL_RINGBUFFER_H_ */
|