Michal Wajdeczko | 3ea5802 | 2019-08-12 09:29:35 +0000 | [diff] [blame] | 1 | // SPDX-License-Identifier: MIT |
Alex Dai | bac427f | 2015-08-12 15:43:39 +0100 | [diff] [blame] | 2 | /* |
| 3 | * Copyright © 2014 Intel Corporation |
Alex Dai | bac427f | 2015-08-12 15:43:39 +0100 | [diff] [blame] | 4 | */ |
Alex Dai | bac427f | 2015-08-12 15:43:39 +0100 | [diff] [blame] | 5 | |
Michal Wajdeczko | 9f436c4 | 2017-10-04 18:13:40 +0000 | [diff] [blame] | 6 | #include <linux/circ_buf.h> |
Chris Wilson | 31de7350 | 2017-03-16 12:56:18 +0000 | [diff] [blame] | 7 | |
Chris Wilson | 10be98a | 2019-05-28 10:29:49 +0100 | [diff] [blame] | 8 | #include "gem/i915_gem_context.h" |
Daniele Ceraolo Spurio | 43aaadc | 2021-01-12 18:12:35 -0800 | [diff] [blame] | 9 | #include "gt/gen8_engine_cs.h" |
| 10 | #include "gt/intel_breadcrumbs.h" |
Daniele Ceraolo Spurio | 0f261b2 | 2019-07-13 11:00:11 +0100 | [diff] [blame] | 11 | #include "gt/intel_context.h" |
| 12 | #include "gt/intel_engine_pm.h" |
Daniele Ceraolo Spurio | 84b1ca2 | 2019-07-13 11:00:14 +0100 | [diff] [blame] | 13 | #include "gt/intel_gt.h" |
Chris Wilson | 0669a6e | 2021-05-21 11:32:15 -0700 | [diff] [blame] | 14 | #include "gt/intel_gt_irq.h" |
Chris Wilson | c7302f2 | 2019-08-08 21:27:58 +0100 | [diff] [blame] | 15 | #include "gt/intel_gt_pm.h" |
Chris Wilson | a0d3fdb | 2020-12-19 02:03:42 +0000 | [diff] [blame] | 16 | #include "gt/intel_lrc.h" |
Daniele Ceraolo Spurio | 43aaadc | 2021-01-12 18:12:35 -0800 | [diff] [blame] | 17 | #include "gt/intel_mocs.h" |
Chris Wilson | 2871ea8 | 2019-10-24 11:03:44 +0100 | [diff] [blame] | 18 | #include "gt/intel_ring.h" |
| 19 | |
Sagar Arun Kamble | a269574 | 2017-11-16 19:02:41 +0530 | [diff] [blame] | 20 | #include "intel_guc_submission.h" |
Daniele Ceraolo Spurio | 0f261b2 | 2019-07-13 11:00:11 +0100 | [diff] [blame] | 21 | |
Michal Wajdeczko | 9f436c4 | 2017-10-04 18:13:40 +0000 | [diff] [blame] | 22 | #include "i915_drv.h" |
Jani Nikula | a09d9a8 | 2019-08-06 13:07:28 +0300 | [diff] [blame] | 23 | #include "i915_trace.h" |
Michal Wajdeczko | 9f436c4 | 2017-10-04 18:13:40 +0000 | [diff] [blame] | 24 | |
Alex Dai | bac427f | 2015-08-12 15:43:39 +0100 | [diff] [blame] | 25 | /** |
Alex Dai | feda33e | 2015-10-19 16:10:54 -0700 | [diff] [blame] | 26 | * DOC: GuC-based command submission |
Dave Gordon | 44a28b1 | 2015-08-12 15:43:41 +0100 | [diff] [blame] | 27 | * |
Daniele Ceraolo Spurio | 218151e | 2019-10-14 11:36:01 -0700 | [diff] [blame] | 28 | * IMPORTANT NOTE: GuC submission is currently not supported in i915. The GuC |
| 29 | * firmware is moving to an updated submission interface and we plan to |
| 30 | * turn submission back on when that lands. The below documentation (and related |
| 31 | * code) matches the old submission model and will be updated as part of the |
| 32 | * upgrade to the new flow. |
| 33 | * |
Oscar Mateo | b09935a | 2017-03-22 10:39:53 -0700 | [diff] [blame] | 34 | * GuC stage descriptor: |
Oscar Mateo | 0d76812 | 2017-03-22 10:39:50 -0700 | [diff] [blame] | 35 | * During initialization, the driver allocates a static pool of 1024 such |
Daniele Ceraolo Spurio | 3c9abe8 | 2019-12-05 14:02:42 -0800 | [diff] [blame] | 36 | * descriptors, and shares them with the GuC. Currently, we only use one |
| 37 | * descriptor. This stage descriptor lets the GuC know about the workqueue and |
Daniele Ceraolo Spurio | e9362e1 | 2019-12-05 14:02:41 -0800 | [diff] [blame] | 38 | * process descriptor. Theoretically, it also lets the GuC know about our HW |
| 39 | * contexts (context ID, etc...), but we actually employ a kind of submission |
Daniele Ceraolo Spurio | 3c9abe8 | 2019-12-05 14:02:42 -0800 | [diff] [blame] | 40 | * where the GuC uses the LRCA sent via the work item instead. This is called |
Daniele Ceraolo Spurio | e9362e1 | 2019-12-05 14:02:41 -0800 | [diff] [blame] | 41 | * a "proxy" submission. |
Dave Gordon | 44a28b1 | 2015-08-12 15:43:41 +0100 | [diff] [blame] | 42 | * |
| 43 | * The Scratch registers: |
| 44 | * There are 16 MMIO-based registers start from 0xC180. The kernel driver writes |
| 45 | * a value to the action register (SOFT_SCRATCH_0) along with any data. It then |
| 46 | * triggers an interrupt on the GuC via another register write (0xC4C8). |
| 47 | * Firmware writes a success/fail code back to the action register after |
| 48 | * processes the request. The kernel driver polls waiting for this update and |
| 49 | * then proceeds. |
Dave Gordon | 44a28b1 | 2015-08-12 15:43:41 +0100 | [diff] [blame] | 50 | * |
Dave Gordon | 44a28b1 | 2015-08-12 15:43:41 +0100 | [diff] [blame] | 51 | * Work Items: |
| 52 | * There are several types of work items that the host may place into a |
| 53 | * workqueue, each with its own requirements and limitations. Currently only |
| 54 | * WQ_TYPE_INORDER is needed to support legacy submission via GuC, which |
| 55 | * represents in-order queue. The kernel driver packs ring tail pointer and an |
| 56 | * ELSP context descriptor dword into Work Item. |
Michał Winiarski | a0991e1 | 2017-10-25 22:00:14 +0200 | [diff] [blame] | 57 | * See guc_add_request() |
Dave Gordon | 44a28b1 | 2015-08-12 15:43:41 +0100 | [diff] [blame] | 58 | * |
| 59 | */ |
| 60 | |
Daniele Ceraolo Spurio | 43aaadc | 2021-01-12 18:12:35 -0800 | [diff] [blame] | 61 | #define GUC_REQUEST_SIZE 64 /* bytes */ |
| 62 | |
Chris Wilson | f6322ed | 2018-02-22 14:22:29 +0000 | [diff] [blame] | 63 | static inline struct i915_priolist *to_priolist(struct rb_node *rb) |
| 64 | { |
| 65 | return rb_entry(rb, struct i915_priolist, node); |
| 66 | } |
| 67 | |
Daniele Ceraolo Spurio | 3c9abe8 | 2019-12-05 14:02:42 -0800 | [diff] [blame] | 68 | static struct guc_stage_desc *__get_stage_desc(struct intel_guc *guc, u32 id) |
Joonas Lahtinen | abddffd | 2017-03-22 10:39:44 -0700 | [diff] [blame] | 69 | { |
Daniele Ceraolo Spurio | 3c9abe8 | 2019-12-05 14:02:42 -0800 | [diff] [blame] | 70 | struct guc_stage_desc *base = guc->stage_desc_pool_vaddr; |
| 71 | |
| 72 | return &base[id]; |
Joonas Lahtinen | abddffd | 2017-03-22 10:39:44 -0700 | [diff] [blame] | 73 | } |
| 74 | |
Michał Winiarski | 89922d0 | 2017-10-25 22:00:10 +0200 | [diff] [blame] | 75 | static int guc_stage_desc_pool_create(struct intel_guc *guc) |
| 76 | { |
Daniele Ceraolo Spurio | 18c094b | 2019-12-05 14:02:40 -0800 | [diff] [blame] | 77 | u32 size = PAGE_ALIGN(sizeof(struct guc_stage_desc) * |
| 78 | GUC_MAX_STAGE_DESCRIPTORS); |
Michał Winiarski | 89922d0 | 2017-10-25 22:00:10 +0200 | [diff] [blame] | 79 | |
Daniele Ceraolo Spurio | 3c9abe8 | 2019-12-05 14:02:42 -0800 | [diff] [blame] | 80 | return intel_guc_allocate_and_map_vma(guc, size, &guc->stage_desc_pool, |
| 81 | &guc->stage_desc_pool_vaddr); |
Michał Winiarski | 89922d0 | 2017-10-25 22:00:10 +0200 | [diff] [blame] | 82 | } |
| 83 | |
| 84 | static void guc_stage_desc_pool_destroy(struct intel_guc *guc) |
| 85 | { |
Chris Wilson | 6a2f59e | 2018-07-21 13:50:37 +0100 | [diff] [blame] | 86 | i915_vma_unpin_and_release(&guc->stage_desc_pool, I915_VMA_RELEASE_MAP); |
Michał Winiarski | 89922d0 | 2017-10-25 22:00:10 +0200 | [diff] [blame] | 87 | } |
| 88 | |
Dave Gordon | 44a28b1 | 2015-08-12 15:43:41 +0100 | [diff] [blame] | 89 | /* |
Oscar Mateo | b09935a | 2017-03-22 10:39:53 -0700 | [diff] [blame] | 90 | * Initialise/clear the stage descriptor shared with the GuC firmware. |
Dave Gordon | 44a28b1 | 2015-08-12 15:43:41 +0100 | [diff] [blame] | 91 | * |
| 92 | * This descriptor tells the GuC where (in GGTT space) to find the important |
Daniele Ceraolo Spurio | 3c9abe8 | 2019-12-05 14:02:42 -0800 | [diff] [blame] | 93 | * data structures related to work submission (process descriptor, write queue, |
Daniele Ceraolo Spurio | e9362e1 | 2019-12-05 14:02:41 -0800 | [diff] [blame] | 94 | * etc). |
Dave Gordon | 44a28b1 | 2015-08-12 15:43:41 +0100 | [diff] [blame] | 95 | */ |
Daniele Ceraolo Spurio | 3c9abe8 | 2019-12-05 14:02:42 -0800 | [diff] [blame] | 96 | static void guc_stage_desc_init(struct intel_guc *guc) |
Dave Gordon | 44a28b1 | 2015-08-12 15:43:41 +0100 | [diff] [blame] | 97 | { |
Oscar Mateo | b09935a | 2017-03-22 10:39:53 -0700 | [diff] [blame] | 98 | struct guc_stage_desc *desc; |
Dave Gordon | 44a28b1 | 2015-08-12 15:43:41 +0100 | [diff] [blame] | 99 | |
Daniele Ceraolo Spurio | 3c9abe8 | 2019-12-05 14:02:42 -0800 | [diff] [blame] | 100 | /* we only use 1 stage desc, so hardcode it to 0 */ |
| 101 | desc = __get_stage_desc(guc, 0); |
Oscar Mateo | 73b0553 | 2017-03-22 10:39:45 -0700 | [diff] [blame] | 102 | memset(desc, 0, sizeof(*desc)); |
Dave Gordon | 44a28b1 | 2015-08-12 15:43:41 +0100 | [diff] [blame] | 103 | |
Sagar Arun Kamble | a269574 | 2017-11-16 19:02:41 +0530 | [diff] [blame] | 104 | desc->attribute = GUC_STAGE_DESC_ATTR_ACTIVE | |
| 105 | GUC_STAGE_DESC_ATTR_KERNEL; |
Dave Gordon | 44a28b1 | 2015-08-12 15:43:41 +0100 | [diff] [blame] | 106 | |
Daniele Ceraolo Spurio | 3c9abe8 | 2019-12-05 14:02:42 -0800 | [diff] [blame] | 107 | desc->stage_id = 0; |
| 108 | desc->priority = GUC_CLIENT_PRIORITY_KMD_NORMAL; |
| 109 | |
Michał Winiarski | a529a1c | 2017-09-18 11:25:35 +0200 | [diff] [blame] | 110 | desc->wq_size = GUC_WQ_SIZE; |
Dave Gordon | 44a28b1 | 2015-08-12 15:43:41 +0100 | [diff] [blame] | 111 | } |
| 112 | |
Daniele Ceraolo Spurio | 3c9abe8 | 2019-12-05 14:02:42 -0800 | [diff] [blame] | 113 | static void guc_stage_desc_fini(struct intel_guc *guc) |
Dave Gordon | 44a28b1 | 2015-08-12 15:43:41 +0100 | [diff] [blame] | 114 | { |
Oscar Mateo | b09935a | 2017-03-22 10:39:53 -0700 | [diff] [blame] | 115 | struct guc_stage_desc *desc; |
Dave Gordon | 44a28b1 | 2015-08-12 15:43:41 +0100 | [diff] [blame] | 116 | |
Daniele Ceraolo Spurio | 3c9abe8 | 2019-12-05 14:02:42 -0800 | [diff] [blame] | 117 | desc = __get_stage_desc(guc, 0); |
Oscar Mateo | 73b0553 | 2017-03-22 10:39:45 -0700 | [diff] [blame] | 118 | memset(desc, 0, sizeof(*desc)); |
Dave Gordon | 44a28b1 | 2015-08-12 15:43:41 +0100 | [diff] [blame] | 119 | } |
| 120 | |
Chris Wilson | e61e0f5 | 2018-02-21 09:56:36 +0000 | [diff] [blame] | 121 | static void guc_add_request(struct intel_guc *guc, struct i915_request *rq) |
Michał Winiarski | a0991e1 | 2017-10-25 22:00:14 +0200 | [diff] [blame] | 122 | { |
Matthew Brost | 7e5299c | 2021-01-12 18:12:33 -0800 | [diff] [blame] | 123 | /* Leaving stub as this function will be used in future patches */ |
Michał Winiarski | a0991e1 | 2017-10-25 22:00:14 +0200 | [diff] [blame] | 124 | } |
| 125 | |
Michał Winiarski | c41937fd | 2017-10-26 15:35:58 +0200 | [diff] [blame] | 126 | /* |
| 127 | * When we're doing submissions using regular execlists backend, writing to |
| 128 | * ELSP from CPU side is enough to make sure that writes to ringbuffer pages |
| 129 | * pinned in mappable aperture portion of GGTT are visible to command streamer. |
| 130 | * Writes done by GuC on our behalf are not guaranteeing such ordering, |
| 131 | * therefore, to ensure the flush, we're issuing a POSTING READ. |
| 132 | */ |
| 133 | static void flush_ggtt_writes(struct i915_vma *vma) |
| 134 | { |
Michał Winiarski | c41937fd | 2017-10-26 15:35:58 +0200 | [diff] [blame] | 135 | if (i915_vma_is_map_and_fenceable(vma)) |
Matthew Brost | a22198a | 2019-12-06 17:00:33 -0800 | [diff] [blame] | 136 | intel_uncore_posting_read_fw(vma->vm->gt->uncore, |
| 137 | GUC_STATUS); |
Michał Winiarski | c41937fd | 2017-10-26 15:35:58 +0200 | [diff] [blame] | 138 | } |
| 139 | |
Chris Wilson | 22b7a42 | 2019-06-20 15:20:51 +0100 | [diff] [blame] | 140 | static void guc_submit(struct intel_engine_cs *engine, |
| 141 | struct i915_request **out, |
| 142 | struct i915_request **end) |
Dave Gordon | 44a28b1 | 2015-08-12 15:43:41 +0100 | [diff] [blame] | 143 | { |
Daniele Ceraolo Spurio | 8b5689d | 2019-07-13 11:00:12 +0100 | [diff] [blame] | 144 | struct intel_guc *guc = &engine->gt->uc.guc; |
Dave Gordon | 44a28b1 | 2015-08-12 15:43:41 +0100 | [diff] [blame] | 145 | |
Chris Wilson | 22b7a42 | 2019-06-20 15:20:51 +0100 | [diff] [blame] | 146 | do { |
| 147 | struct i915_request *rq = *out++; |
Chris Wilson | 0c33518 | 2017-02-28 11:28:03 +0000 | [diff] [blame] | 148 | |
Chris Wilson | 22b7a42 | 2019-06-20 15:20:51 +0100 | [diff] [blame] | 149 | flush_ggtt_writes(rq->ring->vma); |
| 150 | guc_add_request(guc, rq); |
| 151 | } while (out != end); |
Chris Wilson | 77f0d0e | 2017-05-17 13:10:00 +0100 | [diff] [blame] | 152 | } |
| 153 | |
Chris Wilson | 2a694fe | 2018-04-03 19:35:37 +0100 | [diff] [blame] | 154 | static inline int rq_prio(const struct i915_request *rq) |
| 155 | { |
Chris Wilson | eec39e4 | 2020-05-07 16:23:38 +0100 | [diff] [blame] | 156 | return rq->sched.attr.priority; |
Chris Wilson | 2a694fe | 2018-04-03 19:35:37 +0100 | [diff] [blame] | 157 | } |
| 158 | |
Chris Wilson | 22b7a42 | 2019-06-20 15:20:51 +0100 | [diff] [blame] | 159 | static struct i915_request *schedule_in(struct i915_request *rq, int idx) |
Chris Wilson | 2a694fe | 2018-04-03 19:35:37 +0100 | [diff] [blame] | 160 | { |
Chris Wilson | 22b7a42 | 2019-06-20 15:20:51 +0100 | [diff] [blame] | 161 | trace_i915_request_in(rq, idx); |
| 162 | |
Chris Wilson | 5f15c1e6 | 2019-08-12 21:36:26 +0100 | [diff] [blame] | 163 | /* |
| 164 | * Currently we are not tracking the rq->context being inflight |
| 165 | * (ce->inflight = rq->engine). It is only used by the execlists |
| 166 | * backend at the moment, a similar counting strategy would be |
| 167 | * required if we generalise the inflight tracking. |
| 168 | */ |
Chris Wilson | 22b7a42 | 2019-06-20 15:20:51 +0100 | [diff] [blame] | 169 | |
Chris Wilson | 93b0e8f | 2019-11-21 13:05:28 +0000 | [diff] [blame] | 170 | __intel_gt_pm_get(rq->engine->gt); |
Chris Wilson | 22b7a42 | 2019-06-20 15:20:51 +0100 | [diff] [blame] | 171 | return i915_request_get(rq); |
Chris Wilson | 2a694fe | 2018-04-03 19:35:37 +0100 | [diff] [blame] | 172 | } |
| 173 | |
Chris Wilson | 22b7a42 | 2019-06-20 15:20:51 +0100 | [diff] [blame] | 174 | static void schedule_out(struct i915_request *rq) |
| 175 | { |
| 176 | trace_i915_request_out(rq); |
| 177 | |
Stuart Summers | e18417b | 2019-11-20 13:13:21 -0800 | [diff] [blame] | 178 | intel_gt_pm_put_async(rq->engine->gt); |
Chris Wilson | 22b7a42 | 2019-06-20 15:20:51 +0100 | [diff] [blame] | 179 | i915_request_put(rq); |
| 180 | } |
| 181 | |
| 182 | static void __guc_dequeue(struct intel_engine_cs *engine) |
Chris Wilson | 31de7350 | 2017-03-16 12:56:18 +0000 | [diff] [blame] | 183 | { |
Mika Kuoppala | b620e87 | 2017-09-22 15:43:03 +0300 | [diff] [blame] | 184 | struct intel_engine_execlists * const execlists = &engine->execlists; |
Chris Wilson | 22b7a42 | 2019-06-20 15:20:51 +0100 | [diff] [blame] | 185 | struct i915_request **first = execlists->inflight; |
| 186 | struct i915_request ** const last_port = first + execlists->port_mask; |
| 187 | struct i915_request *last = first[0]; |
| 188 | struct i915_request **port; |
Chris Wilson | 31de7350 | 2017-03-16 12:56:18 +0000 | [diff] [blame] | 189 | bool submit = false; |
Michał Winiarski | 85e2fe6 | 2017-09-14 10:32:13 +0200 | [diff] [blame] | 190 | struct rb_node *rb; |
| 191 | |
Chris Wilson | 422d7df | 2019-06-14 17:46:06 +0100 | [diff] [blame] | 192 | lockdep_assert_held(&engine->active.lock); |
Chris Wilson | 6486d84 | 2018-05-08 22:03:18 +0100 | [diff] [blame] | 193 | |
Chris Wilson | 22b7a42 | 2019-06-20 15:20:51 +0100 | [diff] [blame] | 194 | if (last) { |
Chris Wilson | 22b7a42 | 2019-06-20 15:20:51 +0100 | [diff] [blame] | 195 | if (*++first) |
| 196 | return; |
Michał Winiarski | c41937fd | 2017-10-26 15:35:58 +0200 | [diff] [blame] | 197 | |
Chris Wilson | 22b7a42 | 2019-06-20 15:20:51 +0100 | [diff] [blame] | 198 | last = NULL; |
| 199 | } |
| 200 | |
Chris Wilson | 5f15c1e6 | 2019-08-12 21:36:26 +0100 | [diff] [blame] | 201 | /* |
| 202 | * We write directly into the execlists->inflight queue and don't use |
| 203 | * the execlists->pending queue, as we don't have a distinct switch |
| 204 | * event. |
| 205 | */ |
Chris Wilson | 22b7a42 | 2019-06-20 15:20:51 +0100 | [diff] [blame] | 206 | port = first; |
Chris Wilson | 655250a | 2018-06-29 08:53:20 +0100 | [diff] [blame] | 207 | while ((rb = rb_first_cached(&execlists->queue))) { |
Chris Wilson | f6322ed | 2018-02-22 14:22:29 +0000 | [diff] [blame] | 208 | struct i915_priolist *p = to_priolist(rb); |
Chris Wilson | e61e0f5 | 2018-02-21 09:56:36 +0000 | [diff] [blame] | 209 | struct i915_request *rq, *rn; |
Chris Wilson | 31de7350 | 2017-03-16 12:56:18 +0000 | [diff] [blame] | 210 | |
Chris Wilson | 2867ff6 | 2021-01-20 12:14:38 +0000 | [diff] [blame] | 211 | priolist_for_each_request_consume(rq, rn, p) { |
Chris Wilson | 9f3ccd4 | 2019-12-20 10:12:29 +0000 | [diff] [blame] | 212 | if (last && rq->context != last->context) { |
Chris Wilson | 85f5e1f | 2018-10-01 13:32:04 +0100 | [diff] [blame] | 213 | if (port == last_port) |
Chris Wilson | 6c06757 | 2017-05-17 13:10:03 +0100 | [diff] [blame] | 214 | goto done; |
Chris Wilson | 31de7350 | 2017-03-16 12:56:18 +0000 | [diff] [blame] | 215 | |
Chris Wilson | 22b7a42 | 2019-06-20 15:20:51 +0100 | [diff] [blame] | 216 | *port = schedule_in(last, |
| 217 | port - execlists->inflight); |
Chris Wilson | 6c06757 | 2017-05-17 13:10:03 +0100 | [diff] [blame] | 218 | port++; |
| 219 | } |
| 220 | |
Chris Wilson | 85f5e1f | 2018-10-01 13:32:04 +0100 | [diff] [blame] | 221 | list_del_init(&rq->sched.link); |
Chris Wilson | e61e0f5 | 2018-02-21 09:56:36 +0000 | [diff] [blame] | 222 | __i915_request_submit(rq); |
Chris Wilson | 6c06757 | 2017-05-17 13:10:03 +0100 | [diff] [blame] | 223 | submit = true; |
Chris Wilson | 22b7a42 | 2019-06-20 15:20:51 +0100 | [diff] [blame] | 224 | last = rq; |
Chris Wilson | 31de7350 | 2017-03-16 12:56:18 +0000 | [diff] [blame] | 225 | } |
| 226 | |
Chris Wilson | 655250a | 2018-06-29 08:53:20 +0100 | [diff] [blame] | 227 | rb_erase_cached(&p->node, &execlists->queue); |
Chris Wilson | 32eb6bc | 2019-02-28 10:20:33 +0000 | [diff] [blame] | 228 | i915_priolist_free(p); |
Chris Wilson | f6322ed | 2018-02-22 14:22:29 +0000 | [diff] [blame] | 229 | } |
Chris Wilson | 6c06757 | 2017-05-17 13:10:03 +0100 | [diff] [blame] | 230 | done: |
Chris Wilson | 4d97cbe0 | 2019-01-29 18:54:51 +0000 | [diff] [blame] | 231 | execlists->queue_priority_hint = |
| 232 | rb ? to_priolist(rb)->priority : INT_MIN; |
Chris Wilson | 22b7a42 | 2019-06-20 15:20:51 +0100 | [diff] [blame] | 233 | if (submit) { |
| 234 | *port = schedule_in(last, port - execlists->inflight); |
| 235 | *++port = NULL; |
| 236 | guc_submit(engine, first, port); |
| 237 | } |
| 238 | execlists->active = execlists->inflight; |
Chris Wilson | 31de7350 | 2017-03-16 12:56:18 +0000 | [diff] [blame] | 239 | } |
| 240 | |
Emil Renner Berthing | 2913fa4 | 2021-01-26 16:01:55 +0100 | [diff] [blame] | 241 | static void guc_submission_tasklet(struct tasklet_struct *t) |
Chris Wilson | 31de7350 | 2017-03-16 12:56:18 +0000 | [diff] [blame] | 242 | { |
Emil Renner Berthing | 2913fa4 | 2021-01-26 16:01:55 +0100 | [diff] [blame] | 243 | struct intel_engine_cs * const engine = |
| 244 | from_tasklet(engine, t, execlists.tasklet); |
Mika Kuoppala | 7a62cc6 | 2017-09-22 15:43:06 +0300 | [diff] [blame] | 245 | struct intel_engine_execlists * const execlists = &engine->execlists; |
Chris Wilson | 22b7a42 | 2019-06-20 15:20:51 +0100 | [diff] [blame] | 246 | struct i915_request **port, *rq; |
Chris Wilson | a2bf92e | 2018-09-25 09:31:59 +0100 | [diff] [blame] | 247 | unsigned long flags; |
| 248 | |
Chris Wilson | 422d7df | 2019-06-14 17:46:06 +0100 | [diff] [blame] | 249 | spin_lock_irqsave(&engine->active.lock, flags); |
Chris Wilson | 31de7350 | 2017-03-16 12:56:18 +0000 | [diff] [blame] | 250 | |
Chris Wilson | 22b7a42 | 2019-06-20 15:20:51 +0100 | [diff] [blame] | 251 | for (port = execlists->inflight; (rq = *port); port++) { |
| 252 | if (!i915_request_completed(rq)) |
| 253 | break; |
Michał Winiarski | 85e2fe6 | 2017-09-14 10:32:13 +0200 | [diff] [blame] | 254 | |
Chris Wilson | 22b7a42 | 2019-06-20 15:20:51 +0100 | [diff] [blame] | 255 | schedule_out(rq); |
| 256 | } |
| 257 | if (port != execlists->inflight) { |
| 258 | int idx = port - execlists->inflight; |
| 259 | int rem = ARRAY_SIZE(execlists->inflight) - idx; |
| 260 | memmove(execlists->inflight, port, rem * sizeof(*port)); |
Michał Winiarski | 85e2fe6 | 2017-09-14 10:32:13 +0200 | [diff] [blame] | 261 | } |
Chris Wilson | 77f0d0e | 2017-05-17 13:10:00 +0100 | [diff] [blame] | 262 | |
Chris Wilson | 71b0846 | 2019-07-09 17:54:26 -0700 | [diff] [blame] | 263 | __guc_dequeue(engine); |
Chris Wilson | a2bf92e | 2018-09-25 09:31:59 +0100 | [diff] [blame] | 264 | |
Chris Wilson | 422d7df | 2019-06-14 17:46:06 +0100 | [diff] [blame] | 265 | spin_unlock_irqrestore(&engine->active.lock, flags); |
Chris Wilson | 31de7350 | 2017-03-16 12:56:18 +0000 | [diff] [blame] | 266 | } |
| 267 | |
Chris Wilson | 0669a6e | 2021-05-21 11:32:15 -0700 | [diff] [blame] | 268 | static void cs_irq_handler(struct intel_engine_cs *engine, u16 iir) |
| 269 | { |
| 270 | if (iir & GT_RENDER_USER_INTERRUPT) { |
| 271 | intel_engine_signal_breadcrumbs(engine); |
| 272 | tasklet_hi_schedule(&engine->execlists.tasklet); |
| 273 | } |
| 274 | } |
| 275 | |
Chris Wilson | eb8d0f5 | 2019-01-25 13:22:28 +0000 | [diff] [blame] | 276 | static void guc_reset_prepare(struct intel_engine_cs *engine) |
Chris Wilson | 1329115 | 2018-05-16 19:33:52 +0100 | [diff] [blame] | 277 | { |
| 278 | struct intel_engine_execlists * const execlists = &engine->execlists; |
| 279 | |
Venkata Sandeep Dhanalakota | 639f2f2 | 2019-12-13 07:51:52 -0800 | [diff] [blame] | 280 | ENGINE_TRACE(engine, "\n"); |
Chris Wilson | 1329115 | 2018-05-16 19:33:52 +0100 | [diff] [blame] | 281 | |
| 282 | /* |
| 283 | * Prevent request submission to the hardware until we have |
| 284 | * completed the reset in i915_gem_reset_finish(). If a request |
| 285 | * is completed by one engine, it may then queue a request |
| 286 | * to a second via its execlists->tasklet *just* as we are |
| 287 | * calling engine->init_hw() and also writing the ELSP. |
| 288 | * Turning off the execlists->tasklet until the reset is over |
| 289 | * prevents the race. |
| 290 | */ |
| 291 | __tasklet_disable_sync_once(&execlists->tasklet); |
Chris Wilson | 1329115 | 2018-05-16 19:33:52 +0100 | [diff] [blame] | 292 | } |
| 293 | |
Chris Wilson | a0d3fdb | 2020-12-19 02:03:42 +0000 | [diff] [blame] | 294 | static void guc_reset_state(struct intel_context *ce, |
| 295 | struct intel_engine_cs *engine, |
| 296 | u32 head, |
| 297 | bool scrub) |
| 298 | { |
| 299 | GEM_BUG_ON(!intel_context_is_pinned(ce)); |
| 300 | |
| 301 | /* |
| 302 | * We want a simple context + ring to execute the breadcrumb update. |
| 303 | * We cannot rely on the context being intact across the GPU hang, |
| 304 | * so clear it and rebuild just what we need for the breadcrumb. |
| 305 | * All pending requests for this context will be zapped, and any |
| 306 | * future request will be after userspace has had the opportunity |
| 307 | * to recreate its own state. |
| 308 | */ |
| 309 | if (scrub) |
| 310 | lrc_init_regs(ce, engine, true); |
| 311 | |
| 312 | /* Rerun the request; its payload has been neutered (if guilty). */ |
| 313 | lrc_update_regs(ce, engine, head); |
| 314 | } |
| 315 | |
Chris Wilson | e26b6d4 | 2019-12-22 12:07:52 +0000 | [diff] [blame] | 316 | static void guc_reset_rewind(struct intel_engine_cs *engine, bool stalled) |
Chris Wilson | 292ad25 | 2019-04-11 14:05:14 +0100 | [diff] [blame] | 317 | { |
| 318 | struct intel_engine_execlists * const execlists = &engine->execlists; |
| 319 | struct i915_request *rq; |
| 320 | unsigned long flags; |
| 321 | |
Chris Wilson | 422d7df | 2019-06-14 17:46:06 +0100 | [diff] [blame] | 322 | spin_lock_irqsave(&engine->active.lock, flags); |
Chris Wilson | 292ad25 | 2019-04-11 14:05:14 +0100 | [diff] [blame] | 323 | |
Chris Wilson | 292ad25 | 2019-04-11 14:05:14 +0100 | [diff] [blame] | 324 | /* Push back any incomplete requests for replay after the reset. */ |
| 325 | rq = execlists_unwind_incomplete_requests(execlists); |
| 326 | if (!rq) |
| 327 | goto out_unlock; |
| 328 | |
| 329 | if (!i915_request_started(rq)) |
| 330 | stalled = false; |
| 331 | |
Chris Wilson | cb823ed | 2019-07-12 20:29:53 +0100 | [diff] [blame] | 332 | __i915_request_reset(rq, stalled); |
Chris Wilson | a0d3fdb | 2020-12-19 02:03:42 +0000 | [diff] [blame] | 333 | guc_reset_state(rq->context, engine, rq->head, stalled); |
Chris Wilson | 292ad25 | 2019-04-11 14:05:14 +0100 | [diff] [blame] | 334 | |
| 335 | out_unlock: |
Chris Wilson | 422d7df | 2019-06-14 17:46:06 +0100 | [diff] [blame] | 336 | spin_unlock_irqrestore(&engine->active.lock, flags); |
Chris Wilson | 292ad25 | 2019-04-11 14:05:14 +0100 | [diff] [blame] | 337 | } |
| 338 | |
Chris Wilson | e26b6d4 | 2019-12-22 12:07:52 +0000 | [diff] [blame] | 339 | static void guc_reset_cancel(struct intel_engine_cs *engine) |
Chris Wilson | 292ad25 | 2019-04-11 14:05:14 +0100 | [diff] [blame] | 340 | { |
| 341 | struct intel_engine_execlists * const execlists = &engine->execlists; |
| 342 | struct i915_request *rq, *rn; |
| 343 | struct rb_node *rb; |
| 344 | unsigned long flags; |
| 345 | |
Venkata Sandeep Dhanalakota | 639f2f2 | 2019-12-13 07:51:52 -0800 | [diff] [blame] | 346 | ENGINE_TRACE(engine, "\n"); |
Chris Wilson | 292ad25 | 2019-04-11 14:05:14 +0100 | [diff] [blame] | 347 | |
| 348 | /* |
| 349 | * Before we call engine->cancel_requests(), we should have exclusive |
| 350 | * access to the submission state. This is arranged for us by the |
| 351 | * caller disabling the interrupt generation, the tasklet and other |
| 352 | * threads that may then access the same state, giving us a free hand |
| 353 | * to reset state. However, we still need to let lockdep be aware that |
| 354 | * we know this state may be accessed in hardirq context, so we |
| 355 | * disable the irq around this manipulation and we want to keep |
| 356 | * the spinlock focused on its duties and not accidentally conflate |
| 357 | * coverage to the submission's irq state. (Similarly, although we |
| 358 | * shouldn't need to disable irq around the manipulation of the |
| 359 | * submission's irq state, we also wish to remind ourselves that |
| 360 | * it is irq state.) |
| 361 | */ |
Chris Wilson | 422d7df | 2019-06-14 17:46:06 +0100 | [diff] [blame] | 362 | spin_lock_irqsave(&engine->active.lock, flags); |
Chris Wilson | 292ad25 | 2019-04-11 14:05:14 +0100 | [diff] [blame] | 363 | |
Chris Wilson | 292ad25 | 2019-04-11 14:05:14 +0100 | [diff] [blame] | 364 | /* Mark all executing requests as skipped. */ |
Chris Wilson | 422d7df | 2019-06-14 17:46:06 +0100 | [diff] [blame] | 365 | list_for_each_entry(rq, &engine->active.requests, sched.link) { |
Chris Wilson | 36e191f | 2020-03-04 12:18:48 +0000 | [diff] [blame] | 366 | i915_request_set_error_once(rq, -EIO); |
Chris Wilson | 292ad25 | 2019-04-11 14:05:14 +0100 | [diff] [blame] | 367 | i915_request_mark_complete(rq); |
| 368 | } |
| 369 | |
| 370 | /* Flush the queued requests to the timeline list (for retiring). */ |
| 371 | while ((rb = rb_first_cached(&execlists->queue))) { |
| 372 | struct i915_priolist *p = to_priolist(rb); |
Chris Wilson | 292ad25 | 2019-04-11 14:05:14 +0100 | [diff] [blame] | 373 | |
Chris Wilson | 2867ff6 | 2021-01-20 12:14:38 +0000 | [diff] [blame] | 374 | priolist_for_each_request_consume(rq, rn, p) { |
Chris Wilson | 292ad25 | 2019-04-11 14:05:14 +0100 | [diff] [blame] | 375 | list_del_init(&rq->sched.link); |
| 376 | __i915_request_submit(rq); |
| 377 | dma_fence_set_error(&rq->fence, -EIO); |
| 378 | i915_request_mark_complete(rq); |
| 379 | } |
| 380 | |
| 381 | rb_erase_cached(&p->node, &execlists->queue); |
| 382 | i915_priolist_free(p); |
| 383 | } |
| 384 | |
| 385 | /* Remaining _unready_ requests will be nop'ed when submitted */ |
| 386 | |
| 387 | execlists->queue_priority_hint = INT_MIN; |
| 388 | execlists->queue = RB_ROOT_CACHED; |
Chris Wilson | 292ad25 | 2019-04-11 14:05:14 +0100 | [diff] [blame] | 389 | |
Chris Wilson | 422d7df | 2019-06-14 17:46:06 +0100 | [diff] [blame] | 390 | spin_unlock_irqrestore(&engine->active.lock, flags); |
Chris Wilson | 292ad25 | 2019-04-11 14:05:14 +0100 | [diff] [blame] | 391 | } |
| 392 | |
| 393 | static void guc_reset_finish(struct intel_engine_cs *engine) |
| 394 | { |
| 395 | struct intel_engine_execlists * const execlists = &engine->execlists; |
| 396 | |
| 397 | if (__tasklet_enable(&execlists->tasklet)) |
| 398 | /* And kick in case we missed a new request submission. */ |
| 399 | tasklet_hi_schedule(&execlists->tasklet); |
| 400 | |
Venkata Sandeep Dhanalakota | 639f2f2 | 2019-12-13 07:51:52 -0800 | [diff] [blame] | 401 | ENGINE_TRACE(engine, "depth->%d\n", |
| 402 | atomic_read(&execlists->tasklet.count)); |
Chris Wilson | 292ad25 | 2019-04-11 14:05:14 +0100 | [diff] [blame] | 403 | } |
| 404 | |
Dave Gordon | 44a28b1 | 2015-08-12 15:43:41 +0100 | [diff] [blame] | 405 | /* |
Oscar Mateo | 397fce8 | 2017-03-22 10:39:52 -0700 | [diff] [blame] | 406 | * Set up the memory resources to be shared with the GuC (via the GGTT) |
| 407 | * at firmware loading time. |
Alex Dai | bac427f | 2015-08-12 15:43:39 +0100 | [diff] [blame] | 408 | */ |
Sagar Arun Kamble | db14d0c5 | 2017-11-16 19:02:39 +0530 | [diff] [blame] | 409 | int intel_guc_submission_init(struct intel_guc *guc) |
Alex Dai | bac427f | 2015-08-12 15:43:39 +0100 | [diff] [blame] | 410 | { |
Oscar Mateo | 3950bf3 | 2017-03-22 10:39:46 -0700 | [diff] [blame] | 411 | int ret; |
Alex Dai | bac427f | 2015-08-12 15:43:39 +0100 | [diff] [blame] | 412 | |
Oscar Mateo | b09935a | 2017-03-22 10:39:53 -0700 | [diff] [blame] | 413 | if (guc->stage_desc_pool) |
Oscar Mateo | 3950bf3 | 2017-03-22 10:39:46 -0700 | [diff] [blame] | 414 | return 0; |
Alex Dai | bac427f | 2015-08-12 15:43:39 +0100 | [diff] [blame] | 415 | |
Michał Winiarski | 89922d0 | 2017-10-25 22:00:10 +0200 | [diff] [blame] | 416 | ret = guc_stage_desc_pool_create(guc); |
| 417 | if (ret) |
| 418 | return ret; |
Chris Wilson | 856efd2 | 2017-11-06 11:48:33 +0000 | [diff] [blame] | 419 | /* |
| 420 | * Keep static analysers happy, let them know that we allocated the |
| 421 | * vma after testing that it didn't exist earlier. |
| 422 | */ |
| 423 | GEM_BUG_ON(!guc->stage_desc_pool); |
Oscar Mateo | 73b0553 | 2017-03-22 10:39:45 -0700 | [diff] [blame] | 424 | |
Alex Dai | bac427f | 2015-08-12 15:43:39 +0100 | [diff] [blame] | 425 | return 0; |
Oscar Mateo | 3950bf3 | 2017-03-22 10:39:46 -0700 | [diff] [blame] | 426 | } |
| 427 | |
Sagar Arun Kamble | db14d0c5 | 2017-11-16 19:02:39 +0530 | [diff] [blame] | 428 | void intel_guc_submission_fini(struct intel_guc *guc) |
Oscar Mateo | 3950bf3 | 2017-03-22 10:39:46 -0700 | [diff] [blame] | 429 | { |
Daniele Ceraolo Spurio | 3c9abe8 | 2019-12-05 14:02:42 -0800 | [diff] [blame] | 430 | if (guc->stage_desc_pool) { |
Chris Wilson | 6710fcfc | 2018-07-13 18:26:58 +0100 | [diff] [blame] | 431 | guc_stage_desc_pool_destroy(guc); |
Daniele Ceraolo Spurio | 3c9abe8 | 2019-12-05 14:02:42 -0800 | [diff] [blame] | 432 | } |
Chris Wilson | 4d357af | 2016-11-29 12:10:23 +0000 | [diff] [blame] | 433 | } |
| 434 | |
Daniele Ceraolo Spurio | 43aaadc | 2021-01-12 18:12:35 -0800 | [diff] [blame] | 435 | static int guc_context_alloc(struct intel_context *ce) |
| 436 | { |
| 437 | return lrc_alloc(ce, ce->engine); |
| 438 | } |
| 439 | |
| 440 | static int guc_context_pre_pin(struct intel_context *ce, |
| 441 | struct i915_gem_ww_ctx *ww, |
| 442 | void **vaddr) |
| 443 | { |
| 444 | return lrc_pre_pin(ce, ce->engine, ww, vaddr); |
| 445 | } |
| 446 | |
| 447 | static int guc_context_pin(struct intel_context *ce, void *vaddr) |
| 448 | { |
| 449 | return lrc_pin(ce, ce->engine, vaddr); |
| 450 | } |
| 451 | |
| 452 | static const struct intel_context_ops guc_context_ops = { |
| 453 | .alloc = guc_context_alloc, |
| 454 | |
| 455 | .pre_pin = guc_context_pre_pin, |
| 456 | .pin = guc_context_pin, |
| 457 | .unpin = lrc_unpin, |
| 458 | .post_unpin = lrc_post_unpin, |
| 459 | |
| 460 | .enter = intel_context_enter_engine, |
| 461 | .exit = intel_context_exit_engine, |
| 462 | |
| 463 | .reset = lrc_reset, |
| 464 | .destroy = lrc_destroy, |
| 465 | }; |
| 466 | |
| 467 | static int guc_request_alloc(struct i915_request *request) |
| 468 | { |
| 469 | int ret; |
| 470 | |
| 471 | GEM_BUG_ON(!intel_context_is_pinned(request->context)); |
| 472 | |
| 473 | /* |
| 474 | * Flush enough space to reduce the likelihood of waiting after |
| 475 | * we start building the request - in which case we will just |
| 476 | * have to repeat work. |
| 477 | */ |
| 478 | request->reserved_space += GUC_REQUEST_SIZE; |
| 479 | |
| 480 | /* |
| 481 | * Note that after this point, we have committed to using |
| 482 | * this request as it is being used to both track the |
| 483 | * state of engine initialisation and liveness of the |
| 484 | * golden renderstate above. Think twice before you try |
| 485 | * to cancel/unwind this request now. |
| 486 | */ |
| 487 | |
| 488 | /* Unconditionally invalidate GPU caches and TLBs. */ |
| 489 | ret = request->engine->emit_flush(request, EMIT_INVALIDATE); |
| 490 | if (ret) |
| 491 | return ret; |
| 492 | |
| 493 | request->reserved_space -= GUC_REQUEST_SIZE; |
| 494 | return 0; |
| 495 | } |
| 496 | |
Daniele Ceraolo Spurio | 007c457 | 2021-01-12 18:12:36 -0800 | [diff] [blame] | 497 | static inline void queue_request(struct intel_engine_cs *engine, |
| 498 | struct i915_request *rq, |
| 499 | int prio) |
| 500 | { |
| 501 | GEM_BUG_ON(!list_empty(&rq->sched.link)); |
| 502 | list_add_tail(&rq->sched.link, |
| 503 | i915_sched_lookup_priolist(engine, prio)); |
| 504 | set_bit(I915_FENCE_FLAG_PQUEUE, &rq->fence.flags); |
| 505 | } |
| 506 | |
| 507 | static void guc_submit_request(struct i915_request *rq) |
| 508 | { |
| 509 | struct intel_engine_cs *engine = rq->engine; |
| 510 | unsigned long flags; |
| 511 | |
| 512 | /* Will be called from irq-context when using foreign fences. */ |
| 513 | spin_lock_irqsave(&engine->active.lock, flags); |
| 514 | |
| 515 | queue_request(engine, rq, rq_prio(rq)); |
| 516 | |
| 517 | GEM_BUG_ON(RB_EMPTY_ROOT(&engine->execlists.queue.rb_root)); |
| 518 | GEM_BUG_ON(list_empty(&rq->sched.link)); |
| 519 | |
| 520 | tasklet_hi_schedule(&engine->execlists.tasklet); |
| 521 | |
| 522 | spin_unlock_irqrestore(&engine->active.lock, flags); |
| 523 | } |
| 524 | |
Daniele Ceraolo Spurio | 43aaadc | 2021-01-12 18:12:35 -0800 | [diff] [blame] | 525 | static void sanitize_hwsp(struct intel_engine_cs *engine) |
| 526 | { |
| 527 | struct intel_timeline *tl; |
| 528 | |
| 529 | list_for_each_entry(tl, &engine->status_page.timelines, engine_link) |
| 530 | intel_timeline_reset_seqno(tl); |
| 531 | } |
| 532 | |
| 533 | static void guc_sanitize(struct intel_engine_cs *engine) |
| 534 | { |
| 535 | /* |
| 536 | * Poison residual state on resume, in case the suspend didn't! |
| 537 | * |
| 538 | * We have to assume that across suspend/resume (or other loss |
| 539 | * of control) that the contents of our pinned buffers has been |
| 540 | * lost, replaced by garbage. Since this doesn't always happen, |
| 541 | * let's poison such state so that we more quickly spot when |
| 542 | * we falsely assume it has been preserved. |
| 543 | */ |
| 544 | if (IS_ENABLED(CONFIG_DRM_I915_DEBUG_GEM)) |
| 545 | memset(engine->status_page.addr, POISON_INUSE, PAGE_SIZE); |
| 546 | |
| 547 | /* |
| 548 | * The kernel_context HWSP is stored in the status_page. As above, |
| 549 | * that may be lost on resume/initialisation, and so we need to |
| 550 | * reset the value in the HWSP. |
| 551 | */ |
| 552 | sanitize_hwsp(engine); |
| 553 | |
| 554 | /* And scrub the dirty cachelines for the HWSP */ |
| 555 | clflush_cache_range(engine->status_page.addr, PAGE_SIZE); |
| 556 | } |
| 557 | |
| 558 | static void setup_hwsp(struct intel_engine_cs *engine) |
| 559 | { |
| 560 | intel_engine_set_hwsp_writemask(engine, ~0u); /* HWSTAM */ |
| 561 | |
| 562 | ENGINE_WRITE_FW(engine, |
| 563 | RING_HWS_PGA, |
| 564 | i915_ggtt_offset(engine->status_page.vma)); |
| 565 | } |
| 566 | |
| 567 | static void start_engine(struct intel_engine_cs *engine) |
| 568 | { |
| 569 | ENGINE_WRITE_FW(engine, |
| 570 | RING_MODE_GEN7, |
| 571 | _MASKED_BIT_ENABLE(GEN11_GFX_DISABLE_LEGACY_MODE)); |
| 572 | |
| 573 | ENGINE_WRITE_FW(engine, RING_MI_MODE, _MASKED_BIT_DISABLE(STOP_RING)); |
| 574 | ENGINE_POSTING_READ(engine, RING_MI_MODE); |
| 575 | } |
| 576 | |
| 577 | static int guc_resume(struct intel_engine_cs *engine) |
| 578 | { |
| 579 | assert_forcewakes_active(engine->uncore, FORCEWAKE_ALL); |
| 580 | |
| 581 | intel_mocs_init_engine(engine); |
| 582 | |
| 583 | intel_breadcrumbs_reset(engine->breadcrumbs); |
| 584 | |
| 585 | setup_hwsp(engine); |
| 586 | start_engine(engine); |
| 587 | |
| 588 | return 0; |
| 589 | } |
| 590 | |
Chris Wilson | 209b795 | 2018-07-17 21:29:32 +0100 | [diff] [blame] | 591 | static void guc_set_default_submission(struct intel_engine_cs *engine) |
| 592 | { |
Daniele Ceraolo Spurio | 007c457 | 2021-01-12 18:12:36 -0800 | [diff] [blame] | 593 | engine->submit_request = guc_submit_request; |
Chris Wilson | 209b795 | 2018-07-17 21:29:32 +0100 | [diff] [blame] | 594 | } |
| 595 | |
Daniele Ceraolo Spurio | 43aaadc | 2021-01-12 18:12:35 -0800 | [diff] [blame] | 596 | static void guc_release(struct intel_engine_cs *engine) |
| 597 | { |
| 598 | engine->sanitize = NULL; /* no longer in control, nothing to sanitize */ |
| 599 | |
| 600 | tasklet_kill(&engine->execlists.tasklet); |
| 601 | |
| 602 | intel_engine_cleanup_common(engine); |
| 603 | lrc_fini_wa_ctx(engine); |
| 604 | } |
| 605 | |
| 606 | static void guc_default_vfuncs(struct intel_engine_cs *engine) |
| 607 | { |
| 608 | /* Default vfuncs which can be overridden by each engine. */ |
| 609 | |
| 610 | engine->resume = guc_resume; |
| 611 | |
| 612 | engine->cops = &guc_context_ops; |
| 613 | engine->request_alloc = guc_request_alloc; |
| 614 | |
Chris Wilson | 0db3633 | 2021-05-21 11:32:13 -0700 | [diff] [blame] | 615 | engine->schedule = i915_schedule; |
| 616 | |
| 617 | engine->reset.prepare = guc_reset_prepare; |
| 618 | engine->reset.rewind = guc_reset_rewind; |
| 619 | engine->reset.cancel = guc_reset_cancel; |
| 620 | engine->reset.finish = guc_reset_finish; |
| 621 | |
Daniele Ceraolo Spurio | 43aaadc | 2021-01-12 18:12:35 -0800 | [diff] [blame] | 622 | engine->emit_flush = gen8_emit_flush_xcs; |
| 623 | engine->emit_init_breadcrumb = gen8_emit_init_breadcrumb; |
| 624 | engine->emit_fini_breadcrumb = gen8_emit_fini_breadcrumb_xcs; |
Lucas De Marchi | c816723 | 2021-06-05 08:53:52 -0700 | [diff] [blame] | 625 | if (GRAPHICS_VER(engine->i915) >= 12) { |
Daniele Ceraolo Spurio | 43aaadc | 2021-01-12 18:12:35 -0800 | [diff] [blame] | 626 | engine->emit_fini_breadcrumb = gen12_emit_fini_breadcrumb_xcs; |
| 627 | engine->emit_flush = gen12_emit_flush_xcs; |
| 628 | } |
| 629 | engine->set_default_submission = guc_set_default_submission; |
Chris Wilson | 0db3633 | 2021-05-21 11:32:13 -0700 | [diff] [blame] | 630 | |
Chris Wilson | 0db3633 | 2021-05-21 11:32:13 -0700 | [diff] [blame] | 631 | engine->flags |= I915_ENGINE_HAS_PREEMPTION; |
| 632 | |
| 633 | /* |
| 634 | * TODO: GuC supports timeslicing and semaphores as well, but they're |
| 635 | * handled by the firmware so some minor tweaks are required before |
| 636 | * enabling. |
| 637 | * |
| 638 | * engine->flags |= I915_ENGINE_HAS_TIMESLICES; |
| 639 | * engine->flags |= I915_ENGINE_HAS_SEMAPHORES; |
| 640 | */ |
| 641 | |
| 642 | engine->emit_bb_start = gen8_emit_bb_start; |
Daniele Ceraolo Spurio | 43aaadc | 2021-01-12 18:12:35 -0800 | [diff] [blame] | 643 | } |
| 644 | |
| 645 | static void rcs_submission_override(struct intel_engine_cs *engine) |
| 646 | { |
Lucas De Marchi | c816723 | 2021-06-05 08:53:52 -0700 | [diff] [blame] | 647 | switch (GRAPHICS_VER(engine->i915)) { |
Daniele Ceraolo Spurio | 43aaadc | 2021-01-12 18:12:35 -0800 | [diff] [blame] | 648 | case 12: |
| 649 | engine->emit_flush = gen12_emit_flush_rcs; |
| 650 | engine->emit_fini_breadcrumb = gen12_emit_fini_breadcrumb_rcs; |
| 651 | break; |
| 652 | case 11: |
| 653 | engine->emit_flush = gen11_emit_flush_rcs; |
| 654 | engine->emit_fini_breadcrumb = gen11_emit_fini_breadcrumb_rcs; |
| 655 | break; |
| 656 | default: |
| 657 | engine->emit_flush = gen8_emit_flush_rcs; |
| 658 | engine->emit_fini_breadcrumb = gen8_emit_fini_breadcrumb_rcs; |
| 659 | break; |
| 660 | } |
| 661 | } |
| 662 | |
| 663 | static inline void guc_default_irqs(struct intel_engine_cs *engine) |
| 664 | { |
| 665 | engine->irq_keep_mask = GT_RENDER_USER_INTERRUPT; |
Chris Wilson | 0669a6e | 2021-05-21 11:32:15 -0700 | [diff] [blame] | 666 | intel_engine_set_irq_handler(engine, cs_irq_handler); |
Daniele Ceraolo Spurio | 43aaadc | 2021-01-12 18:12:35 -0800 | [diff] [blame] | 667 | } |
| 668 | |
| 669 | int intel_guc_submission_setup(struct intel_engine_cs *engine) |
| 670 | { |
| 671 | struct drm_i915_private *i915 = engine->i915; |
| 672 | |
| 673 | /* |
| 674 | * The setup relies on several assumptions (e.g. irqs always enabled) |
| 675 | * that are only valid on gen11+ |
| 676 | */ |
Lucas De Marchi | c816723 | 2021-06-05 08:53:52 -0700 | [diff] [blame] | 677 | GEM_BUG_ON(GRAPHICS_VER(i915) < 11); |
Daniele Ceraolo Spurio | 43aaadc | 2021-01-12 18:12:35 -0800 | [diff] [blame] | 678 | |
Emil Renner Berthing | 2913fa4 | 2021-01-26 16:01:55 +0100 | [diff] [blame] | 679 | tasklet_setup(&engine->execlists.tasklet, guc_submission_tasklet); |
Daniele Ceraolo Spurio | 43aaadc | 2021-01-12 18:12:35 -0800 | [diff] [blame] | 680 | |
| 681 | guc_default_vfuncs(engine); |
| 682 | guc_default_irqs(engine); |
| 683 | |
| 684 | if (engine->class == RENDER_CLASS) |
| 685 | rcs_submission_override(engine); |
| 686 | |
| 687 | lrc_init_wa_ctx(engine); |
| 688 | |
| 689 | /* Finally, take ownership and responsibility for cleanup! */ |
| 690 | engine->sanitize = guc_sanitize; |
| 691 | engine->release = guc_release; |
| 692 | |
| 693 | return 0; |
| 694 | } |
| 695 | |
Daniele Ceraolo Spurio | e9362e1 | 2019-12-05 14:02:41 -0800 | [diff] [blame] | 696 | void intel_guc_submission_enable(struct intel_guc *guc) |
Dave Gordon | 44a28b1 | 2015-08-12 15:43:41 +0100 | [diff] [blame] | 697 | { |
Daniele Ceraolo Spurio | 3c9abe8 | 2019-12-05 14:02:42 -0800 | [diff] [blame] | 698 | guc_stage_desc_init(guc); |
Dave Gordon | 44a28b1 | 2015-08-12 15:43:41 +0100 | [diff] [blame] | 699 | } |
| 700 | |
Sagar Arun Kamble | db14d0c5 | 2017-11-16 19:02:39 +0530 | [diff] [blame] | 701 | void intel_guc_submission_disable(struct intel_guc *guc) |
Dave Gordon | 44a28b1 | 2015-08-12 15:43:41 +0100 | [diff] [blame] | 702 | { |
Daniele Ceraolo Spurio | 84b1ca2 | 2019-07-13 11:00:14 +0100 | [diff] [blame] | 703 | struct intel_gt *gt = guc_to_gt(guc); |
Dave Gordon | 44a28b1 | 2015-08-12 15:43:41 +0100 | [diff] [blame] | 704 | |
Daniele Ceraolo Spurio | 84b1ca2 | 2019-07-13 11:00:14 +0100 | [diff] [blame] | 705 | GEM_BUG_ON(gt->awake); /* GT should be parked first */ |
Chris Wilson | bcbd5c3 | 2017-10-25 15:39:42 +0100 | [diff] [blame] | 706 | |
Daniele Ceraolo Spurio | 3c9abe8 | 2019-12-05 14:02:42 -0800 | [diff] [blame] | 707 | /* Note: By the time we're here, GuC may have already been reset */ |
| 708 | |
Daniele Ceraolo Spurio | 3c9abe8 | 2019-12-05 14:02:42 -0800 | [diff] [blame] | 709 | guc_stage_desc_fini(guc); |
Dave Gordon | 44a28b1 | 2015-08-12 15:43:41 +0100 | [diff] [blame] | 710 | } |
Michel Thierry | 55bd6bd | 2017-11-16 14:06:31 -0800 | [diff] [blame] | 711 | |
Daniele Ceraolo Spurio | 202c98e | 2020-02-18 14:33:24 -0800 | [diff] [blame] | 712 | static bool __guc_submission_selected(struct intel_guc *guc) |
Michal Wajdeczko | 724df64 | 2019-07-31 22:33:20 +0000 | [diff] [blame] | 713 | { |
Jani Nikula | 8a25c4b | 2020-06-18 18:04:02 +0300 | [diff] [blame] | 714 | struct drm_i915_private *i915 = guc_to_gt(guc)->i915; |
| 715 | |
Daniele Ceraolo Spurio | 202c98e | 2020-02-18 14:33:24 -0800 | [diff] [blame] | 716 | if (!intel_guc_submission_is_supported(guc)) |
Michal Wajdeczko | 724df64 | 2019-07-31 22:33:20 +0000 | [diff] [blame] | 717 | return false; |
| 718 | |
Jani Nikula | 8a25c4b | 2020-06-18 18:04:02 +0300 | [diff] [blame] | 719 | return i915->params.enable_guc & ENABLE_GUC_SUBMISSION; |
Michal Wajdeczko | 724df64 | 2019-07-31 22:33:20 +0000 | [diff] [blame] | 720 | } |
| 721 | |
| 722 | void intel_guc_submission_init_early(struct intel_guc *guc) |
| 723 | { |
Daniele Ceraolo Spurio | 202c98e | 2020-02-18 14:33:24 -0800 | [diff] [blame] | 724 | guc->submission_selected = __guc_submission_selected(guc); |
Michal Wajdeczko | 724df64 | 2019-07-31 22:33:20 +0000 | [diff] [blame] | 725 | } |