Commit | Line | Data |
---|---|---|
dd08ebf6 MB |
1 | // SPDX-License-Identifier: MIT |
2 | /* | |
3 | * Copyright © 2022 Intel Corporation | |
4 | */ | |
5 | ||
ea9f879d LDM |
6 | #include "xe_gt.h" |
7 | ||
dd08ebf6 MB |
8 | #include <linux/minmax.h> |
9 | ||
10 | #include <drm/drm_managed.h> | |
4f027e30 | 11 | #include <drm/xe_drm.h> |
dd08ebf6 | 12 | |
72ac3047 | 13 | #include "instructions/xe_gfxpipe_commands.h" |
0134f130 | 14 | #include "instructions/xe_mi_commands.h" |
226bfec8 | 15 | #include "regs/xe_gt_regs.h" |
c73acc1e | 16 | #include "xe_assert.h" |
dd08ebf6 MB |
17 | #include "xe_bb.h" |
18 | #include "xe_bo.h" | |
19 | #include "xe_device.h" | |
c22a4ed0 | 20 | #include "xe_exec_queue.h" |
dd08ebf6 MB |
21 | #include "xe_execlist.h" |
22 | #include "xe_force_wake.h" | |
23 | #include "xe_ggtt.h" | |
aae84bf1 | 24 | #include "xe_gsc.h" |
0d97ecce | 25 | #include "xe_gt_ccs_mode.h" |
dd08ebf6 | 26 | #include "xe_gt_clock.h" |
c550f64f | 27 | #include "xe_gt_idle.h" |
dd08ebf6 MB |
28 | #include "xe_gt_mcr.h" |
29 | #include "xe_gt_pagefault.h" | |
3e535bd5 | 30 | #include "xe_gt_printk.h" |
dd08ebf6 | 31 | #include "xe_gt_sysfs.h" |
a9351846 | 32 | #include "xe_gt_tlb_invalidation.h" |
dd08ebf6 | 33 | #include "xe_gt_topology.h" |
9b9529ce | 34 | #include "xe_guc_exec_queue_types.h" |
43efd3ba | 35 | #include "xe_guc_pc.h" |
dd08ebf6 | 36 | #include "xe_hw_fence.h" |
038ff941 | 37 | #include "xe_hw_engine_class_sysfs.h" |
dd08ebf6 MB |
38 | #include "xe_irq.h" |
39 | #include "xe_lrc.h" | |
40 | #include "xe_map.h" | |
41 | #include "xe_migrate.h" | |
42 | #include "xe_mmio.h" | |
576c6380 | 43 | #include "xe_pat.h" |
dd08ebf6 MB |
44 | #include "xe_mocs.h" |
45 | #include "xe_reg_sr.h" | |
46 | #include "xe_ring_ops.h" | |
47 | #include "xe_sa.h" | |
48 | #include "xe_sched_job.h" | |
dd08ebf6 MB |
49 | #include "xe_tuning.h" |
50 | #include "xe_uc.h" | |
51 | #include "xe_vm.h" | |
52 | #include "xe_wa.h" | |
53 | #include "xe_wopcm.h" | |
54 | ||
f6929e80 | 55 | struct xe_gt *xe_gt_alloc(struct xe_tile *tile) |
dd08ebf6 | 56 | { |
f6929e80 | 57 | struct xe_gt *gt; |
dd08ebf6 | 58 | |
f6929e80 MR |
59 | gt = drmm_kzalloc(&tile_to_xe(tile)->drm, sizeof(*gt), GFP_KERNEL); |
60 | if (!gt) | |
61 | return ERR_PTR(-ENOMEM); | |
62 | ||
63 | gt->tile = tile; | |
dd08ebf6 MB |
64 | gt->ordered_wq = alloc_ordered_workqueue("gt-ordered-wq", 0); |
65 | ||
f6929e80 | 66 | return gt; |
dd08ebf6 MB |
67 | } |
68 | ||
da3799c9 MB |
69 | void xe_gt_sanitize(struct xe_gt *gt) |
70 | { | |
71 | /* | |
72 | * FIXME: if xe_uc_sanitize is called here, on TGL driver will not | |
73 | * reload | |
74 | */ | |
75 | gt->uc.guc.submission_state.enabled = false; | |
76 | } | |
77 | ||
dd08ebf6 MB |
78 | static void gt_fini(struct drm_device *drm, void *arg) |
79 | { | |
80 | struct xe_gt *gt = arg; | |
81 | int i; | |
82 | ||
83 | destroy_workqueue(gt->ordered_wq); | |
84 | ||
85 | for (i = 0; i < XE_ENGINE_CLASS_MAX; ++i) | |
86 | xe_hw_fence_irq_finish(>->fence_irq[i]); | |
87 | } | |
88 | ||
89 | static void gt_reset_worker(struct work_struct *w); | |
90 | ||
9b9529ce | 91 | static int emit_nop_job(struct xe_gt *gt, struct xe_exec_queue *q) |
dd08ebf6 MB |
92 | { |
93 | struct xe_sched_job *job; | |
94 | struct xe_bb *bb; | |
95 | struct dma_fence *fence; | |
dd08ebf6 MB |
96 | long timeout; |
97 | ||
98 | bb = xe_bb_new(gt, 4, false); | |
99 | if (IS_ERR(bb)) | |
100 | return PTR_ERR(bb); | |
101 | ||
9e952635 | 102 | job = xe_bb_create_job(q, bb); |
dd08ebf6 MB |
103 | if (IS_ERR(job)) { |
104 | xe_bb_free(bb, NULL); | |
99c5952f | 105 | return PTR_ERR(job); |
dd08ebf6 MB |
106 | } |
107 | ||
108 | xe_sched_job_arm(job); | |
109 | fence = dma_fence_get(&job->drm.s_fence->finished); | |
110 | xe_sched_job_push(job); | |
111 | ||
112 | timeout = dma_fence_wait_timeout(fence, false, HZ); | |
113 | dma_fence_put(fence); | |
114 | xe_bb_free(bb, NULL); | |
115 | if (timeout < 0) | |
116 | return timeout; | |
117 | else if (!timeout) | |
118 | return -ETIME; | |
119 | ||
120 | return 0; | |
121 | } | |
122 | ||
278c3582 LDM |
123 | /* |
124 | * Convert back from encoded value to type-safe, only to be used when reg.mcr | |
125 | * is true | |
126 | */ | |
127 | static struct xe_reg_mcr to_xe_reg_mcr(const struct xe_reg reg) | |
128 | { | |
129 | return (const struct xe_reg_mcr){.__reg.raw = reg.raw }; | |
130 | } | |
131 | ||
9b9529ce | 132 | static int emit_wa_job(struct xe_gt *gt, struct xe_exec_queue *q) |
dd08ebf6 | 133 | { |
9b9529ce | 134 | struct xe_reg_sr *sr = &q->hwe->reg_lrc; |
dd08ebf6 | 135 | struct xe_reg_sr_entry *entry; |
278c3582 | 136 | unsigned long idx; |
dd08ebf6 MB |
137 | struct xe_sched_job *job; |
138 | struct xe_bb *bb; | |
139 | struct dma_fence *fence; | |
dd08ebf6 MB |
140 | long timeout; |
141 | int count = 0; | |
142 | ||
b1543a49 MR |
143 | if (q->hwe->class == XE_ENGINE_CLASS_RENDER) |
144 | /* Big enough to emit all of the context's 3DSTATE */ | |
145 | bb = xe_bb_new(gt, xe_lrc_size(gt_to_xe(gt), q->hwe->class), false); | |
146 | else | |
147 | /* Just pick a large BB size */ | |
148 | bb = xe_bb_new(gt, SZ_4K, false); | |
149 | ||
dd08ebf6 MB |
150 | if (IS_ERR(bb)) |
151 | return PTR_ERR(bb); | |
152 | ||
278c3582 | 153 | xa_for_each(&sr->xa, idx, entry) |
dd08ebf6 MB |
154 | ++count; |
155 | ||
156 | if (count) { | |
12a66a47 LDM |
157 | xe_gt_dbg(gt, "LRC WA %s save-restore batch\n", sr->name); |
158 | ||
e12a6488 | 159 | bb->cs[bb->len++] = MI_LOAD_REGISTER_IMM | MI_LRI_NUM_REGS(count); |
278c3582 LDM |
160 | |
161 | xa_for_each(&sr->xa, idx, entry) { | |
162 | struct xe_reg reg = entry->reg; | |
163 | struct xe_reg_mcr reg_mcr = to_xe_reg_mcr(reg); | |
164 | u32 val; | |
165 | ||
166 | /* | |
167 | * Skip reading the register if it's not really needed | |
168 | */ | |
169 | if (reg.masked) | |
170 | val = entry->clr_bits << 16; | |
171 | else if (entry->clr_bits + 1) | |
172 | val = (reg.mcr ? | |
173 | xe_gt_mcr_unicast_read_any(gt, reg_mcr) : | |
174 | xe_mmio_read32(gt, reg)) & (~entry->clr_bits); | |
175 | else | |
176 | val = 0; | |
177 | ||
178 | val |= entry->set_bits; | |
179 | ||
180 | bb->cs[bb->len++] = reg.addr; | |
181 | bb->cs[bb->len++] = val; | |
182 | xe_gt_dbg(gt, "REG[0x%x] = 0x%08x", reg.addr, val); | |
dd08ebf6 MB |
183 | } |
184 | } | |
dd08ebf6 | 185 | |
b1543a49 MR |
186 | xe_lrc_emit_hwe_state_instructions(q, bb); |
187 | ||
9e952635 | 188 | job = xe_bb_create_job(q, bb); |
dd08ebf6 MB |
189 | if (IS_ERR(job)) { |
190 | xe_bb_free(bb, NULL); | |
99c5952f | 191 | return PTR_ERR(job); |
dd08ebf6 MB |
192 | } |
193 | ||
194 | xe_sched_job_arm(job); | |
195 | fence = dma_fence_get(&job->drm.s_fence->finished); | |
196 | xe_sched_job_push(job); | |
197 | ||
198 | timeout = dma_fence_wait_timeout(fence, false, HZ); | |
199 | dma_fence_put(fence); | |
200 | xe_bb_free(bb, NULL); | |
201 | if (timeout < 0) | |
202 | return timeout; | |
203 | else if (!timeout) | |
204 | return -ETIME; | |
205 | ||
206 | return 0; | |
207 | } | |
208 | ||
209 | int xe_gt_record_default_lrcs(struct xe_gt *gt) | |
210 | { | |
211 | struct xe_device *xe = gt_to_xe(gt); | |
212 | struct xe_hw_engine *hwe; | |
213 | enum xe_hw_engine_id id; | |
214 | int err = 0; | |
215 | ||
216 | for_each_hw_engine(hwe, gt, id) { | |
9b9529ce | 217 | struct xe_exec_queue *q, *nop_q; |
dd08ebf6 MB |
218 | void *default_lrc; |
219 | ||
220 | if (gt->default_lrc[hwe->class]) | |
221 | continue; | |
222 | ||
766849c4 | 223 | xe_reg_sr_init(&hwe->reg_lrc, hwe->name, xe); |
dd08ebf6 | 224 | xe_wa_process_lrc(hwe); |
bb95a4f9 | 225 | xe_hw_engine_setup_default_lrc_state(hwe); |
3dbec470 | 226 | xe_tuning_process_lrc(hwe); |
dd08ebf6 MB |
227 | |
228 | default_lrc = drmm_kzalloc(&xe->drm, | |
229 | xe_lrc_size(xe, hwe->class), | |
230 | GFP_KERNEL); | |
231 | if (!default_lrc) | |
232 | return -ENOMEM; | |
233 | ||
9e952635 DCS |
234 | q = xe_exec_queue_create(xe, NULL, BIT(hwe->logical_instance), 1, |
235 | hwe, EXEC_QUEUE_FLAG_KERNEL); | |
9b9529ce FD |
236 | if (IS_ERR(q)) { |
237 | err = PTR_ERR(q); | |
238 | xe_gt_err(gt, "hwe %s: xe_exec_queue_create failed (%pe)\n", | |
239 | hwe->name, q); | |
9e952635 | 240 | return err; |
dd08ebf6 MB |
241 | } |
242 | ||
243 | /* Prime golden LRC with known good state */ | |
9b9529ce | 244 | err = emit_wa_job(gt, q); |
3d4451d3 | 245 | if (err) { |
3e535bd5 | 246 | xe_gt_err(gt, "hwe %s: emit_wa_job failed (%pe) guc_id=%u\n", |
9b9529ce FD |
247 | hwe->name, ERR_PTR(err), q->guc->id); |
248 | goto put_exec_queue; | |
3d4451d3 | 249 | } |
dd08ebf6 | 250 | |
9e952635 DCS |
251 | nop_q = xe_exec_queue_create(xe, NULL, BIT(hwe->logical_instance), |
252 | 1, hwe, EXEC_QUEUE_FLAG_KERNEL); | |
9b9529ce FD |
253 | if (IS_ERR(nop_q)) { |
254 | err = PTR_ERR(nop_q); | |
255 | xe_gt_err(gt, "hwe %s: nop xe_exec_queue_create failed (%pe)\n", | |
256 | hwe->name, nop_q); | |
257 | goto put_exec_queue; | |
dd08ebf6 MB |
258 | } |
259 | ||
260 | /* Switch to different LRC */ | |
9b9529ce | 261 | err = emit_nop_job(gt, nop_q); |
3d4451d3 | 262 | if (err) { |
3e535bd5 | 263 | xe_gt_err(gt, "hwe %s: nop emit_nop_job failed (%pe) guc_id=%u\n", |
9b9529ce FD |
264 | hwe->name, ERR_PTR(err), nop_q->guc->id); |
265 | goto put_nop_q; | |
3d4451d3 | 266 | } |
dd08ebf6 MB |
267 | |
268 | /* Reload golden LRC to record the effect of any indirect W/A */ | |
9b9529ce | 269 | err = emit_nop_job(gt, q); |
3d4451d3 | 270 | if (err) { |
3e535bd5 | 271 | xe_gt_err(gt, "hwe %s: emit_nop_job failed (%pe) guc_id=%u\n", |
9b9529ce FD |
272 | hwe->name, ERR_PTR(err), q->guc->id); |
273 | goto put_nop_q; | |
3d4451d3 | 274 | } |
dd08ebf6 MB |
275 | |
276 | xe_map_memcpy_from(xe, default_lrc, | |
9b9529ce FD |
277 | &q->lrc[0].bo->vmap, |
278 | xe_lrc_pphwsp_offset(&q->lrc[0]), | |
dd08ebf6 MB |
279 | xe_lrc_size(xe, hwe->class)); |
280 | ||
281 | gt->default_lrc[hwe->class] = default_lrc; | |
9b9529ce FD |
282 | put_nop_q: |
283 | xe_exec_queue_put(nop_q); | |
284 | put_exec_queue: | |
285 | xe_exec_queue_put(q); | |
dd08ebf6 MB |
286 | if (err) |
287 | break; | |
288 | } | |
289 | ||
290 | return err; | |
291 | } | |
292 | ||
293 | int xe_gt_init_early(struct xe_gt *gt) | |
294 | { | |
295 | int err; | |
296 | ||
dd08ebf6 MB |
297 | err = xe_force_wake_get(gt_to_fw(gt), XE_FW_GT); |
298 | if (err) | |
299 | return err; | |
300 | ||
301 | xe_gt_topology_init(gt); | |
302 | xe_gt_mcr_init(gt); | |
303 | ||
304 | err = xe_force_wake_put(gt_to_fw(gt), XE_FW_GT); | |
305 | if (err) | |
306 | return err; | |
307 | ||
308 | xe_reg_sr_init(>->reg_sr, "GT", gt_to_xe(gt)); | |
49d329a0 LDM |
309 | |
310 | err = xe_wa_init(gt); | |
311 | if (err) | |
312 | return err; | |
313 | ||
dd08ebf6 | 314 | xe_wa_process_gt(gt); |
9616e74b | 315 | xe_wa_process_oob(gt); |
dd08ebf6 MB |
316 | xe_tuning_process_gt(gt); |
317 | ||
318 | return 0; | |
319 | } | |
320 | ||
d2300987 LDM |
321 | static void dump_pat_on_error(struct xe_gt *gt) |
322 | { | |
323 | struct drm_printer p; | |
324 | char prefix[32]; | |
325 | ||
326 | snprintf(prefix, sizeof(prefix), "[GT%u Error]", gt->info.id); | |
327 | p = drm_debug_printer(prefix); | |
328 | ||
329 | xe_pat_dump(gt, &p); | |
330 | } | |
331 | ||
dd08ebf6 MB |
332 | static int gt_fw_domain_init(struct xe_gt *gt) |
333 | { | |
334 | int err, i; | |
335 | ||
336 | xe_device_mem_access_get(gt_to_xe(gt)); | |
337 | err = xe_force_wake_get(gt_to_fw(gt), XE_FW_GT); | |
338 | if (err) | |
339 | goto err_hw_fence_irq; | |
340 | ||
576c6380 | 341 | xe_pat_init(gt); |
6c8c1e74 | 342 | |
dd08ebf6 | 343 | if (!xe_gt_is_media_type(gt)) { |
ad703e06 | 344 | err = xe_ggtt_init(gt_to_tile(gt)->mem.ggtt); |
dd08ebf6 MB |
345 | if (err) |
346 | goto err_force_wake; | |
347 | } | |
348 | ||
dd08ebf6 | 349 | err = xe_uc_init(>->uc); |
33de290b CB |
350 | if (err) |
351 | goto err_force_wake; | |
dd08ebf6 | 352 | |
43efd3ba VB |
353 | /* Raise GT freq to speed up HuC/GuC load */ |
354 | xe_guc_pc_init_early(>->uc.guc.pc); | |
355 | ||
dd08ebf6 MB |
356 | err = xe_uc_init_hwconfig(>->uc); |
357 | if (err) | |
358 | goto err_force_wake; | |
359 | ||
1c2097bb RT |
360 | xe_gt_idle_sysfs_init(>->gtidle); |
361 | ||
da34c2cf MB |
362 | /* XXX: Fake that we pull the engine mask from hwconfig blob */ |
363 | gt->info.engine_mask = gt->info.__engine_mask; | |
364 | ||
3e29c149 MR |
365 | /* Enable per hw engine IRQs */ |
366 | xe_irq_enable_hwe(gt); | |
dd08ebf6 MB |
367 | |
368 | /* Rerun MCR init as we now have hw engine list */ | |
369 | xe_gt_mcr_init(gt); | |
370 | ||
371 | err = xe_hw_engines_init_early(gt); | |
372 | if (err) | |
373 | goto err_force_wake; | |
374 | ||
038ff941 TU |
375 | err = xe_hw_engine_class_sysfs_init(gt); |
376 | if (err) | |
377 | drm_warn(>_to_xe(gt)->drm, | |
378 | "failed to register engines sysfs directory, err: %d\n", | |
379 | err); | |
380 | ||
f3bc5bb4 NV |
381 | /* Initialize CCS mode sysfs after early initialization of HW engines */ |
382 | xe_gt_ccs_mode_sysfs_init(gt); | |
383 | ||
dd08ebf6 MB |
384 | err = xe_force_wake_put(gt_to_fw(gt), XE_FW_GT); |
385 | XE_WARN_ON(err); | |
386 | xe_device_mem_access_put(gt_to_xe(gt)); | |
387 | ||
388 | return 0; | |
389 | ||
390 | err_force_wake: | |
d2300987 | 391 | dump_pat_on_error(gt); |
dd08ebf6 MB |
392 | xe_force_wake_put(gt_to_fw(gt), XE_FW_GT); |
393 | err_hw_fence_irq: | |
394 | for (i = 0; i < XE_ENGINE_CLASS_MAX; ++i) | |
395 | xe_hw_fence_irq_finish(>->fence_irq[i]); | |
396 | xe_device_mem_access_put(gt_to_xe(gt)); | |
397 | ||
398 | return err; | |
399 | } | |
400 | ||
401 | static int all_fw_domain_init(struct xe_gt *gt) | |
402 | { | |
403 | int err, i; | |
404 | ||
405 | xe_device_mem_access_get(gt_to_xe(gt)); | |
406 | err = xe_force_wake_get(gt_to_fw(gt), XE_FORCEWAKE_ALL); | |
407 | if (err) | |
408 | goto err_hw_fence_irq; | |
409 | ||
564d64f8 | 410 | xe_gt_mcr_set_implicit_defaults(gt); |
dd08ebf6 MB |
411 | xe_reg_sr_apply_mmio(>->reg_sr, gt); |
412 | ||
413 | err = xe_gt_clock_init(gt); | |
414 | if (err) | |
415 | goto err_force_wake; | |
416 | ||
417 | xe_mocs_init(gt); | |
418 | err = xe_execlist_init(gt); | |
419 | if (err) | |
420 | goto err_force_wake; | |
421 | ||
422 | err = xe_hw_engines_init(gt); | |
423 | if (err) | |
424 | goto err_force_wake; | |
425 | ||
426 | err = xe_uc_init_post_hwconfig(>->uc); | |
427 | if (err) | |
428 | goto err_force_wake; | |
429 | ||
dd08ebf6 | 430 | if (!xe_gt_is_media_type(gt)) { |
dd08ebf6 MB |
431 | /* |
432 | * USM has its only SA pool to non-block behind user operations | |
433 | */ | |
434 | if (gt_to_xe(gt)->info.supports_usm) { | |
876611c2 | 435 | gt->usm.bb_pool = xe_sa_bo_manager_init(gt_to_tile(gt), SZ_1M, 16); |
0a12a612 MR |
436 | if (IS_ERR(gt->usm.bb_pool)) { |
437 | err = PTR_ERR(gt->usm.bb_pool); | |
dd08ebf6 | 438 | goto err_force_wake; |
0a12a612 | 439 | } |
dd08ebf6 MB |
440 | } |
441 | } | |
442 | ||
443 | if (!xe_gt_is_media_type(gt)) { | |
08dea767 MR |
444 | struct xe_tile *tile = gt_to_tile(gt); |
445 | ||
446 | tile->migrate = xe_migrate_init(tile); | |
447 | if (IS_ERR(tile->migrate)) { | |
448 | err = PTR_ERR(tile->migrate); | |
dd08ebf6 | 449 | goto err_force_wake; |
99c5952f | 450 | } |
dd08ebf6 MB |
451 | } |
452 | ||
453 | err = xe_uc_init_hw(>->uc); | |
454 | if (err) | |
455 | goto err_force_wake; | |
456 | ||
0d97ecce NV |
457 | /* Configure default CCS mode of 1 engine with all resources */ |
458 | if (xe_gt_ccs_mode_enabled(gt)) { | |
459 | gt->ccs_mode = 1; | |
460 | xe_gt_apply_ccs_mode(gt); | |
461 | } | |
462 | ||
dd08ebf6 MB |
463 | err = xe_force_wake_put(gt_to_fw(gt), XE_FORCEWAKE_ALL); |
464 | XE_WARN_ON(err); | |
465 | xe_device_mem_access_put(gt_to_xe(gt)); | |
466 | ||
467 | return 0; | |
468 | ||
469 | err_force_wake: | |
470 | xe_force_wake_put(gt_to_fw(gt), XE_FORCEWAKE_ALL); | |
471 | err_hw_fence_irq: | |
472 | for (i = 0; i < XE_ENGINE_CLASS_MAX; ++i) | |
473 | xe_hw_fence_irq_finish(>->fence_irq[i]); | |
474 | xe_device_mem_access_put(gt_to_xe(gt)); | |
475 | ||
476 | return err; | |
477 | } | |
478 | ||
479 | int xe_gt_init(struct xe_gt *gt) | |
480 | { | |
481 | int err; | |
482 | int i; | |
483 | ||
484 | INIT_WORK(>->reset.worker, gt_reset_worker); | |
485 | ||
486 | for (i = 0; i < XE_ENGINE_CLASS_MAX; ++i) { | |
487 | gt->ring_ops[i] = xe_ring_ops_get(gt, i); | |
488 | xe_hw_fence_irq_init(>->fence_irq[i]); | |
489 | } | |
490 | ||
a9351846 MB |
491 | err = xe_gt_tlb_invalidation_init(gt); |
492 | if (err) | |
493 | return err; | |
494 | ||
dd08ebf6 MB |
495 | err = xe_gt_pagefault_init(gt); |
496 | if (err) | |
497 | return err; | |
498 | ||
17a6726c MR |
499 | xe_mocs_init_early(gt); |
500 | ||
dd08ebf6 MB |
501 | xe_gt_sysfs_init(gt); |
502 | ||
503 | err = gt_fw_domain_init(gt); | |
504 | if (err) | |
505 | return err; | |
506 | ||
507 | xe_force_wake_init_engines(gt, gt_to_fw(gt)); | |
508 | ||
509 | err = all_fw_domain_init(gt); | |
510 | if (err) | |
511 | return err; | |
512 | ||
dd08ebf6 MB |
513 | err = drmm_add_action_or_reset(>_to_xe(gt)->drm, gt_fini, gt); |
514 | if (err) | |
515 | return err; | |
516 | ||
517 | return 0; | |
518 | } | |
519 | ||
671ca05d | 520 | static int do_gt_reset(struct xe_gt *gt) |
dd08ebf6 | 521 | { |
dd08ebf6 MB |
522 | int err; |
523 | ||
aae84bf1 DCS |
524 | xe_gsc_wa_14015076503(gt, true); |
525 | ||
ce8bf5bd | 526 | xe_mmio_write32(gt, GDRST, GRDOM_FULL); |
063e09af | 527 | err = xe_mmio_wait32(gt, GDRST, GRDOM_FULL, 0, 5000, NULL, false); |
dd08ebf6 | 528 | if (err) |
0bc519d2 | 529 | xe_gt_err(gt, "failed to clear GRDOM_FULL (%pe)\n", |
3e535bd5 | 530 | ERR_PTR(err)); |
dd08ebf6 | 531 | |
aae84bf1 DCS |
532 | xe_gsc_wa_14015076503(gt, false); |
533 | ||
dd08ebf6 MB |
534 | return err; |
535 | } | |
536 | ||
537 | static int do_gt_restart(struct xe_gt *gt) | |
538 | { | |
539 | struct xe_hw_engine *hwe; | |
540 | enum xe_hw_engine_id id; | |
541 | int err; | |
542 | ||
576c6380 | 543 | xe_pat_init(gt); |
dd08ebf6 | 544 | |
564d64f8 | 545 | xe_gt_mcr_set_implicit_defaults(gt); |
dd08ebf6 MB |
546 | xe_reg_sr_apply_mmio(>->reg_sr, gt); |
547 | ||
548 | err = xe_wopcm_init(>->uc.wopcm); | |
549 | if (err) | |
550 | return err; | |
551 | ||
552 | for_each_hw_engine(hwe, gt, id) | |
553 | xe_hw_engine_enable_ring(hwe); | |
554 | ||
7704f32c MW |
555 | err = xe_uc_sanitize_reset(>->uc); |
556 | if (err) | |
557 | return err; | |
558 | ||
dd08ebf6 MB |
559 | err = xe_uc_init_hw(>->uc); |
560 | if (err) | |
561 | return err; | |
562 | ||
563 | xe_mocs_init(gt); | |
564 | err = xe_uc_start(>->uc); | |
565 | if (err) | |
566 | return err; | |
567 | ||
568 | for_each_hw_engine(hwe, gt, id) { | |
569 | xe_reg_sr_apply_mmio(&hwe->reg_sr, gt); | |
1011812c | 570 | xe_reg_sr_apply_whitelist(hwe); |
dd08ebf6 MB |
571 | } |
572 | ||
0d97ecce NV |
573 | /* Get CCS mode in sync between sw/hw */ |
574 | xe_gt_apply_ccs_mode(gt); | |
575 | ||
dd08ebf6 MB |
576 | return 0; |
577 | } | |
578 | ||
4f027e30 HPG |
579 | static void xe_uevent_gt_reset_failure(struct pci_dev *pdev, u8 tile_id, u8 gt_id) |
580 | { | |
581 | char *reset_event[4]; | |
582 | ||
d5dc73db | 583 | reset_event[0] = DRM_XE_RESET_FAILED_UEVENT "=NEEDS_RESET"; |
4f027e30 HPG |
584 | reset_event[1] = kasprintf(GFP_KERNEL, "TILE_ID=%d", tile_id); |
585 | reset_event[2] = kasprintf(GFP_KERNEL, "GT_ID=%d", gt_id); | |
586 | reset_event[3] = NULL; | |
587 | kobject_uevent_env(&pdev->dev.kobj, KOBJ_CHANGE, reset_event); | |
588 | ||
589 | kfree(reset_event[1]); | |
590 | kfree(reset_event[2]); | |
591 | } | |
592 | ||
dd08ebf6 MB |
593 | static int gt_reset(struct xe_gt *gt) |
594 | { | |
dd08ebf6 MB |
595 | int err; |
596 | ||
597 | /* We only support GT resets with GuC submission */ | |
c4991ee0 | 598 | if (!xe_device_uc_enabled(gt_to_xe(gt))) |
dd08ebf6 MB |
599 | return -ENODEV; |
600 | ||
3e535bd5 | 601 | xe_gt_info(gt, "reset started\n"); |
dd08ebf6 | 602 | |
8f3013e0 HPG |
603 | if (xe_fault_inject_gt_reset()) { |
604 | err = -ECANCELED; | |
605 | goto err_fail; | |
606 | } | |
607 | ||
da3799c9 MB |
608 | xe_gt_sanitize(gt); |
609 | ||
dd08ebf6 MB |
610 | xe_device_mem_access_get(gt_to_xe(gt)); |
611 | err = xe_force_wake_get(gt_to_fw(gt), XE_FORCEWAKE_ALL); | |
612 | if (err) | |
613 | goto err_msg; | |
614 | ||
1737785a | 615 | xe_uc_gucrc_disable(>->uc); |
dd08ebf6 MB |
616 | xe_uc_stop_prepare(>->uc); |
617 | xe_gt_pagefault_reset(gt); | |
618 | ||
619 | err = xe_uc_stop(>->uc); | |
620 | if (err) | |
621 | goto err_out; | |
622 | ||
623 | err = do_gt_reset(gt); | |
624 | if (err) | |
625 | goto err_out; | |
626 | ||
7b24cc3e MA |
627 | xe_gt_tlb_invalidation_reset(gt); |
628 | ||
dd08ebf6 MB |
629 | err = do_gt_restart(gt); |
630 | if (err) | |
631 | goto err_out; | |
632 | ||
dd08ebf6 | 633 | err = xe_force_wake_put(gt_to_fw(gt), XE_FORCEWAKE_ALL); |
03af26c9 | 634 | xe_device_mem_access_put(gt_to_xe(gt)); |
dd08ebf6 MB |
635 | XE_WARN_ON(err); |
636 | ||
3e535bd5 | 637 | xe_gt_info(gt, "reset done\n"); |
dd08ebf6 MB |
638 | |
639 | return 0; | |
640 | ||
641 | err_out: | |
642 | XE_WARN_ON(xe_force_wake_put(gt_to_fw(gt), XE_FORCEWAKE_ALL)); | |
643 | err_msg: | |
644 | XE_WARN_ON(xe_uc_start(>->uc)); | |
645 | xe_device_mem_access_put(gt_to_xe(gt)); | |
8f3013e0 | 646 | err_fail: |
3e535bd5 | 647 | xe_gt_err(gt, "reset failed (%pe)\n", ERR_PTR(err)); |
dd08ebf6 | 648 | |
4f027e30 HPG |
649 | /* Notify userspace about gt reset failure */ |
650 | xe_uevent_gt_reset_failure(to_pci_dev(gt_to_xe(gt)->drm.dev), | |
651 | gt_to_tile(gt)->id, gt->info.id); | |
652 | ||
57162274 AH |
653 | gt_to_xe(gt)->needs_flr_on_fini = true; |
654 | ||
dd08ebf6 MB |
655 | return err; |
656 | } | |
657 | ||
658 | static void gt_reset_worker(struct work_struct *w) | |
659 | { | |
660 | struct xe_gt *gt = container_of(w, typeof(*gt), reset.worker); | |
661 | ||
662 | gt_reset(gt); | |
663 | } | |
664 | ||
665 | void xe_gt_reset_async(struct xe_gt *gt) | |
666 | { | |
3e535bd5 | 667 | xe_gt_info(gt, "trying reset\n"); |
dd08ebf6 MB |
668 | |
669 | /* Don't do a reset while one is already in flight */ | |
8f3013e0 | 670 | if (!xe_fault_inject_gt_reset() && xe_uc_reset_prepare(>->uc)) |
dd08ebf6 MB |
671 | return; |
672 | ||
3e535bd5 | 673 | xe_gt_info(gt, "reset queued\n"); |
dd08ebf6 MB |
674 | queue_work(gt->ordered_wq, >->reset.worker); |
675 | } | |
676 | ||
677 | void xe_gt_suspend_prepare(struct xe_gt *gt) | |
678 | { | |
679 | xe_device_mem_access_get(gt_to_xe(gt)); | |
680 | XE_WARN_ON(xe_force_wake_get(gt_to_fw(gt), XE_FORCEWAKE_ALL)); | |
681 | ||
682 | xe_uc_stop_prepare(>->uc); | |
683 | ||
dd08ebf6 | 684 | XE_WARN_ON(xe_force_wake_put(gt_to_fw(gt), XE_FORCEWAKE_ALL)); |
03af26c9 | 685 | xe_device_mem_access_put(gt_to_xe(gt)); |
dd08ebf6 MB |
686 | } |
687 | ||
688 | int xe_gt_suspend(struct xe_gt *gt) | |
689 | { | |
dd08ebf6 MB |
690 | int err; |
691 | ||
da3799c9 MB |
692 | xe_gt_sanitize(gt); |
693 | ||
dd08ebf6 MB |
694 | xe_device_mem_access_get(gt_to_xe(gt)); |
695 | err = xe_force_wake_get(gt_to_fw(gt), XE_FORCEWAKE_ALL); | |
696 | if (err) | |
697 | goto err_msg; | |
698 | ||
3856b0f7 AI |
699 | xe_pmu_suspend(gt); |
700 | ||
dd08ebf6 MB |
701 | err = xe_uc_suspend(>->uc); |
702 | if (err) | |
703 | goto err_force_wake; | |
704 | ||
dd08ebf6 | 705 | XE_WARN_ON(xe_force_wake_put(gt_to_fw(gt), XE_FORCEWAKE_ALL)); |
03af26c9 | 706 | xe_device_mem_access_put(gt_to_xe(gt)); |
3e535bd5 | 707 | xe_gt_info(gt, "suspended\n"); |
dd08ebf6 MB |
708 | |
709 | return 0; | |
710 | ||
711 | err_force_wake: | |
712 | XE_WARN_ON(xe_force_wake_put(gt_to_fw(gt), XE_FORCEWAKE_ALL)); | |
713 | err_msg: | |
714 | xe_device_mem_access_put(gt_to_xe(gt)); | |
3e535bd5 | 715 | xe_gt_err(gt, "suspend failed (%pe)\n", ERR_PTR(err)); |
dd08ebf6 MB |
716 | |
717 | return err; | |
718 | } | |
719 | ||
720 | int xe_gt_resume(struct xe_gt *gt) | |
721 | { | |
dd08ebf6 MB |
722 | int err; |
723 | ||
724 | xe_device_mem_access_get(gt_to_xe(gt)); | |
725 | err = xe_force_wake_get(gt_to_fw(gt), XE_FORCEWAKE_ALL); | |
726 | if (err) | |
727 | goto err_msg; | |
728 | ||
729 | err = do_gt_restart(gt); | |
730 | if (err) | |
731 | goto err_force_wake; | |
732 | ||
dd08ebf6 | 733 | XE_WARN_ON(xe_force_wake_put(gt_to_fw(gt), XE_FORCEWAKE_ALL)); |
03af26c9 | 734 | xe_device_mem_access_put(gt_to_xe(gt)); |
3e535bd5 | 735 | xe_gt_info(gt, "resumed\n"); |
dd08ebf6 MB |
736 | |
737 | return 0; | |
738 | ||
739 | err_force_wake: | |
740 | XE_WARN_ON(xe_force_wake_put(gt_to_fw(gt), XE_FORCEWAKE_ALL)); | |
741 | err_msg: | |
742 | xe_device_mem_access_put(gt_to_xe(gt)); | |
3e535bd5 | 743 | xe_gt_err(gt, "resume failed (%pe)\n", ERR_PTR(err)); |
dd08ebf6 MB |
744 | |
745 | return err; | |
746 | } | |
747 | ||
dd08ebf6 MB |
748 | struct xe_hw_engine *xe_gt_hw_engine(struct xe_gt *gt, |
749 | enum xe_engine_class class, | |
750 | u16 instance, bool logical) | |
751 | { | |
752 | struct xe_hw_engine *hwe; | |
753 | enum xe_hw_engine_id id; | |
754 | ||
755 | for_each_hw_engine(hwe, gt, id) | |
756 | if (hwe->class == class && | |
757 | ((!logical && hwe->instance == instance) || | |
758 | (logical && hwe->logical_instance == instance))) | |
759 | return hwe; | |
760 | ||
761 | return NULL; | |
762 | } | |
763 | ||
764 | struct xe_hw_engine *xe_gt_any_hw_engine_by_reset_domain(struct xe_gt *gt, | |
765 | enum xe_engine_class class) | |
766 | { | |
767 | struct xe_hw_engine *hwe; | |
768 | enum xe_hw_engine_id id; | |
769 | ||
770 | for_each_hw_engine(hwe, gt, id) { | |
771 | switch (class) { | |
772 | case XE_ENGINE_CLASS_RENDER: | |
773 | case XE_ENGINE_CLASS_COMPUTE: | |
774 | if (hwe->class == XE_ENGINE_CLASS_RENDER || | |
775 | hwe->class == XE_ENGINE_CLASS_COMPUTE) | |
776 | return hwe; | |
777 | break; | |
778 | default: | |
779 | if (hwe->class == class) | |
780 | return hwe; | |
781 | } | |
782 | } | |
783 | ||
784 | return NULL; | |
785 | } |