1 | // SPDX-License-Identifier: MIT |
---|---|
2 | /* |
3 | * Copyright © 2014-2019 Intel Corporation |
4 | */ |
5 | |
6 | #include "gem/i915_gem_lmem.h" |
7 | #include "gt/intel_gt.h" |
8 | #include "gt/intel_gt_irq.h" |
9 | #include "gt/intel_gt_pm_irq.h" |
10 | #include "gt/intel_gt_regs.h" |
11 | #include "intel_guc.h" |
12 | #include "intel_guc_ads.h" |
13 | #include "intel_guc_capture.h" |
14 | #include "intel_guc_print.h" |
15 | #include "intel_guc_slpc.h" |
16 | #include "intel_guc_submission.h" |
17 | #include "i915_drv.h" |
18 | #include "i915_irq.h" |
19 | #include "i915_reg.h" |
20 | |
21 | /** |
22 | * DOC: GuC |
23 | * |
24 | * The GuC is a microcontroller inside the GT HW, introduced in gen9. The GuC is |
25 | * designed to offload some of the functionality usually performed by the host |
26 | * driver; currently the main operations it can take care of are: |
27 | * |
28 | * - Authentication of the HuC, which is required to fully enable HuC usage. |
29 | * - Low latency graphics context scheduling (a.k.a. GuC submission). |
30 | * - GT Power management. |
31 | * |
32 | * The enable_guc module parameter can be used to select which of those |
33 | * operations to enable within GuC. Note that not all the operations are |
34 | * supported on all gen9+ platforms. |
35 | * |
36 | * Enabling the GuC is not mandatory and therefore the firmware is only loaded |
37 | * if at least one of the operations is selected. However, not loading the GuC |
38 | * might result in the loss of some features that do require the GuC (currently |
39 | * just the HuC, but more are expected to land in the future). |
40 | */ |
41 | |
42 | void intel_guc_notify(struct intel_guc *guc) |
43 | { |
44 | struct intel_gt *gt = guc_to_gt(guc); |
45 | |
46 | /* |
47 | * On Gen11+, the value written to the register is passes as a payload |
48 | * to the FW. However, the FW currently treats all values the same way |
49 | * (H2G interrupt), so we can just write the value that the HW expects |
50 | * on older gens. |
51 | */ |
52 | intel_uncore_write(uncore: gt->uncore, reg: guc->notify_reg, GUC_SEND_TRIGGER); |
53 | } |
54 | |
55 | static inline i915_reg_t guc_send_reg(struct intel_guc *guc, u32 i) |
56 | { |
57 | GEM_BUG_ON(!guc->send_regs.base); |
58 | GEM_BUG_ON(!guc->send_regs.count); |
59 | GEM_BUG_ON(i >= guc->send_regs.count); |
60 | |
61 | return _MMIO(guc->send_regs.base + 4 * i); |
62 | } |
63 | |
64 | void intel_guc_init_send_regs(struct intel_guc *guc) |
65 | { |
66 | struct intel_gt *gt = guc_to_gt(guc); |
67 | enum forcewake_domains fw_domains = 0; |
68 | unsigned int i; |
69 | |
70 | GEM_BUG_ON(!guc->send_regs.base); |
71 | GEM_BUG_ON(!guc->send_regs.count); |
72 | |
73 | for (i = 0; i < guc->send_regs.count; i++) { |
74 | fw_domains |= intel_uncore_forcewake_for_reg(uncore: gt->uncore, |
75 | reg: guc_send_reg(guc, i), |
76 | FW_REG_READ | FW_REG_WRITE); |
77 | } |
78 | guc->send_regs.fw_domains = fw_domains; |
79 | } |
80 | |
81 | static void gen9_reset_guc_interrupts(struct intel_guc *guc) |
82 | { |
83 | struct intel_gt *gt = guc_to_gt(guc); |
84 | |
85 | assert_rpm_wakelock_held(rpm: >->i915->runtime_pm); |
86 | |
87 | spin_lock_irq(lock: gt->irq_lock); |
88 | gen6_gt_pm_reset_iir(gt, reset_mask: gt->pm_guc_events); |
89 | spin_unlock_irq(lock: gt->irq_lock); |
90 | } |
91 | |
92 | static void gen9_enable_guc_interrupts(struct intel_guc *guc) |
93 | { |
94 | struct intel_gt *gt = guc_to_gt(guc); |
95 | |
96 | assert_rpm_wakelock_held(rpm: >->i915->runtime_pm); |
97 | |
98 | spin_lock_irq(lock: gt->irq_lock); |
99 | guc_WARN_ON_ONCE(guc, intel_uncore_read(gt->uncore, GEN8_GT_IIR(2)) & |
100 | gt->pm_guc_events); |
101 | gen6_gt_pm_enable_irq(gt, enable_mask: gt->pm_guc_events); |
102 | spin_unlock_irq(lock: gt->irq_lock); |
103 | |
104 | guc->interrupts.enabled = true; |
105 | } |
106 | |
107 | static void gen9_disable_guc_interrupts(struct intel_guc *guc) |
108 | { |
109 | struct intel_gt *gt = guc_to_gt(guc); |
110 | |
111 | assert_rpm_wakelock_held(rpm: >->i915->runtime_pm); |
112 | guc->interrupts.enabled = false; |
113 | |
114 | spin_lock_irq(lock: gt->irq_lock); |
115 | |
116 | gen6_gt_pm_disable_irq(gt, disable_mask: gt->pm_guc_events); |
117 | |
118 | spin_unlock_irq(lock: gt->irq_lock); |
119 | intel_synchronize_irq(i915: gt->i915); |
120 | |
121 | gen9_reset_guc_interrupts(guc); |
122 | } |
123 | |
124 | static bool __gen11_reset_guc_interrupts(struct intel_gt *gt) |
125 | { |
126 | u32 irq = gt->type == GT_MEDIA ? MTL_MGUC : GEN11_GUC; |
127 | |
128 | lockdep_assert_held(gt->irq_lock); |
129 | return gen11_gt_reset_one_iir(gt, bank: 0, bit: irq); |
130 | } |
131 | |
132 | static void gen11_reset_guc_interrupts(struct intel_guc *guc) |
133 | { |
134 | struct intel_gt *gt = guc_to_gt(guc); |
135 | |
136 | spin_lock_irq(lock: gt->irq_lock); |
137 | __gen11_reset_guc_interrupts(gt); |
138 | spin_unlock_irq(lock: gt->irq_lock); |
139 | } |
140 | |
141 | static void gen11_enable_guc_interrupts(struct intel_guc *guc) |
142 | { |
143 | struct intel_gt *gt = guc_to_gt(guc); |
144 | |
145 | spin_lock_irq(lock: gt->irq_lock); |
146 | __gen11_reset_guc_interrupts(gt); |
147 | spin_unlock_irq(lock: gt->irq_lock); |
148 | |
149 | guc->interrupts.enabled = true; |
150 | } |
151 | |
152 | static void gen11_disable_guc_interrupts(struct intel_guc *guc) |
153 | { |
154 | struct intel_gt *gt = guc_to_gt(guc); |
155 | |
156 | guc->interrupts.enabled = false; |
157 | intel_synchronize_irq(i915: gt->i915); |
158 | |
159 | gen11_reset_guc_interrupts(guc); |
160 | } |
161 | |
162 | static void guc_dead_worker_func(struct work_struct *w) |
163 | { |
164 | struct intel_guc *guc = container_of(w, struct intel_guc, dead_guc_worker); |
165 | struct intel_gt *gt = guc_to_gt(guc); |
166 | unsigned long last = guc->last_dead_guc_jiffies; |
167 | unsigned long delta = jiffies_to_msecs(j: jiffies - last); |
168 | |
169 | if (delta < 500) { |
170 | intel_gt_set_wedged(gt); |
171 | } else { |
172 | intel_gt_handle_error(gt, ALL_ENGINES, I915_ERROR_CAPTURE, fmt: "dead GuC"); |
173 | guc->last_dead_guc_jiffies = jiffies; |
174 | } |
175 | } |
176 | |
177 | void intel_guc_init_early(struct intel_guc *guc) |
178 | { |
179 | struct intel_gt *gt = guc_to_gt(guc); |
180 | struct drm_i915_private *i915 = gt->i915; |
181 | |
182 | intel_uc_fw_init_early(uc_fw: &guc->fw, type: INTEL_UC_FW_TYPE_GUC, needs_ggtt_mapping: true); |
183 | intel_guc_ct_init_early(ct: &guc->ct); |
184 | intel_guc_log_init_early(log: &guc->log); |
185 | intel_guc_submission_init_early(guc); |
186 | intel_guc_slpc_init_early(slpc: &guc->slpc); |
187 | intel_guc_rc_init_early(guc); |
188 | |
189 | INIT_WORK(&guc->dead_guc_worker, guc_dead_worker_func); |
190 | |
191 | mutex_init(&guc->send_mutex); |
192 | spin_lock_init(&guc->irq_lock); |
193 | if (GRAPHICS_VER(i915) >= 11) { |
194 | guc->interrupts.reset = gen11_reset_guc_interrupts; |
195 | guc->interrupts.enable = gen11_enable_guc_interrupts; |
196 | guc->interrupts.disable = gen11_disable_guc_interrupts; |
197 | if (gt->type == GT_MEDIA) { |
198 | guc->notify_reg = MEDIA_GUC_HOST_INTERRUPT; |
199 | guc->send_regs.base = i915_mmio_reg_offset(MEDIA_SOFT_SCRATCH(0)); |
200 | } else { |
201 | guc->notify_reg = GEN11_GUC_HOST_INTERRUPT; |
202 | guc->send_regs.base = i915_mmio_reg_offset(GEN11_SOFT_SCRATCH(0)); |
203 | } |
204 | |
205 | guc->send_regs.count = GEN11_SOFT_SCRATCH_COUNT; |
206 | |
207 | } else { |
208 | guc->notify_reg = GUC_SEND_INTERRUPT; |
209 | guc->interrupts.reset = gen9_reset_guc_interrupts; |
210 | guc->interrupts.enable = gen9_enable_guc_interrupts; |
211 | guc->interrupts.disable = gen9_disable_guc_interrupts; |
212 | guc->send_regs.base = i915_mmio_reg_offset(SOFT_SCRATCH(0)); |
213 | guc->send_regs.count = GUC_MAX_MMIO_MSG_LEN; |
214 | BUILD_BUG_ON(GUC_MAX_MMIO_MSG_LEN > SOFT_SCRATCH_COUNT); |
215 | } |
216 | |
217 | intel_guc_enable_msg(guc, mask: INTEL_GUC_RECV_MSG_EXCEPTION | |
218 | INTEL_GUC_RECV_MSG_CRASH_DUMP_POSTED); |
219 | } |
220 | |
221 | void intel_guc_init_late(struct intel_guc *guc) |
222 | { |
223 | intel_guc_ads_init_late(guc); |
224 | } |
225 | |
226 | static u32 guc_ctl_debug_flags(struct intel_guc *guc) |
227 | { |
228 | u32 level = intel_guc_log_get_level(log: &guc->log); |
229 | u32 flags = 0; |
230 | |
231 | if (!GUC_LOG_LEVEL_IS_VERBOSE(level)) |
232 | flags |= GUC_LOG_DISABLED; |
233 | else |
234 | flags |= GUC_LOG_LEVEL_TO_VERBOSITY(level) << |
235 | GUC_LOG_VERBOSITY_SHIFT; |
236 | |
237 | return flags; |
238 | } |
239 | |
240 | static u32 guc_ctl_feature_flags(struct intel_guc *guc) |
241 | { |
242 | u32 flags = 0; |
243 | |
244 | if (!intel_guc_submission_is_used(guc)) |
245 | flags |= GUC_CTL_DISABLE_SCHEDULER; |
246 | |
247 | if (intel_guc_slpc_is_used(guc)) |
248 | flags |= GUC_CTL_ENABLE_SLPC; |
249 | |
250 | return flags; |
251 | } |
252 | |
253 | static u32 guc_ctl_log_params_flags(struct intel_guc *guc) |
254 | { |
255 | struct intel_guc_log *log = &guc->log; |
256 | u32 offset, flags; |
257 | |
258 | GEM_BUG_ON(!log->sizes_initialised); |
259 | |
260 | offset = intel_guc_ggtt_offset(guc, vma: log->vma) >> PAGE_SHIFT; |
261 | |
262 | flags = GUC_LOG_VALID | |
263 | GUC_LOG_NOTIFY_ON_HALF_FULL | |
264 | log->sizes[GUC_LOG_SECTIONS_DEBUG].flag | |
265 | log->sizes[GUC_LOG_SECTIONS_CAPTURE].flag | |
266 | (log->sizes[GUC_LOG_SECTIONS_CRASH].count << GUC_LOG_CRASH_SHIFT) | |
267 | (log->sizes[GUC_LOG_SECTIONS_DEBUG].count << GUC_LOG_DEBUG_SHIFT) | |
268 | (log->sizes[GUC_LOG_SECTIONS_CAPTURE].count << GUC_LOG_CAPTURE_SHIFT) | |
269 | (offset << GUC_LOG_BUF_ADDR_SHIFT); |
270 | |
271 | return flags; |
272 | } |
273 | |
274 | static u32 guc_ctl_ads_flags(struct intel_guc *guc) |
275 | { |
276 | u32 ads = intel_guc_ggtt_offset(guc, vma: guc->ads_vma) >> PAGE_SHIFT; |
277 | u32 flags = ads << GUC_ADS_ADDR_SHIFT; |
278 | |
279 | return flags; |
280 | } |
281 | |
282 | static u32 guc_ctl_wa_flags(struct intel_guc *guc) |
283 | { |
284 | struct intel_gt *gt = guc_to_gt(guc); |
285 | u32 flags = 0; |
286 | |
287 | /* Wa_22012773006:gen11,gen12 < XeHP */ |
288 | if (GRAPHICS_VER(gt->i915) >= 11 && |
289 | GRAPHICS_VER_FULL(gt->i915) < IP_VER(12, 50)) |
290 | flags |= GUC_WA_POLLCS; |
291 | |
292 | /* Wa_14014475959 */ |
293 | if (IS_GFX_GT_IP_STEP(gt, IP_VER(12, 70), STEP_A0, STEP_B0) || |
294 | IS_DG2(gt->i915)) |
295 | flags |= GUC_WA_HOLD_CCS_SWITCHOUT; |
296 | |
297 | /* |
298 | * Wa_14012197797 |
299 | * Wa_22011391025 |
300 | * |
301 | * The same WA bit is used for both and 22011391025 is applicable to |
302 | * all DG2. |
303 | */ |
304 | if (IS_DG2(gt->i915)) |
305 | flags |= GUC_WA_DUAL_QUEUE; |
306 | |
307 | /* Wa_22011802037: graphics version 11/12 */ |
308 | if (intel_engine_reset_needs_wa_22011802037(gt)) |
309 | flags |= GUC_WA_PRE_PARSER; |
310 | |
311 | /* |
312 | * Wa_22012727170 |
313 | * Wa_22012727685 |
314 | */ |
315 | if (IS_DG2_G11(gt->i915)) |
316 | flags |= GUC_WA_CONTEXT_ISOLATION; |
317 | |
318 | /* Wa_16015675438 */ |
319 | if (!RCS_MASK(gt)) |
320 | flags |= GUC_WA_RCS_REGS_IN_CCS_REGS_LIST; |
321 | |
322 | /* Wa_14018913170 */ |
323 | if (GUC_FIRMWARE_VER(guc) >= MAKE_GUC_VER(70, 7, 0)) { |
324 | if (IS_DG2(gt->i915) || IS_METEORLAKE(gt->i915) || IS_PONTEVECCHIO(gt->i915)) |
325 | flags |= GUC_WA_ENABLE_TSC_CHECK_ON_RC6; |
326 | } |
327 | |
328 | return flags; |
329 | } |
330 | |
331 | static u32 guc_ctl_devid(struct intel_guc *guc) |
332 | { |
333 | struct drm_i915_private *i915 = guc_to_i915(guc); |
334 | |
335 | return (INTEL_DEVID(i915) << 16) | INTEL_REVID(i915); |
336 | } |
337 | |
338 | /* |
339 | * Initialise the GuC parameter block before starting the firmware |
340 | * transfer. These parameters are read by the firmware on startup |
341 | * and cannot be changed thereafter. |
342 | */ |
343 | static void guc_init_params(struct intel_guc *guc) |
344 | { |
345 | u32 *params = guc->params; |
346 | int i; |
347 | |
348 | BUILD_BUG_ON(sizeof(guc->params) != GUC_CTL_MAX_DWORDS * sizeof(u32)); |
349 | |
350 | params[GUC_CTL_LOG_PARAMS] = guc_ctl_log_params_flags(guc); |
351 | params[GUC_CTL_FEATURE] = guc_ctl_feature_flags(guc); |
352 | params[GUC_CTL_DEBUG] = guc_ctl_debug_flags(guc); |
353 | params[GUC_CTL_ADS] = guc_ctl_ads_flags(guc); |
354 | params[GUC_CTL_WA] = guc_ctl_wa_flags(guc); |
355 | params[GUC_CTL_DEVID] = guc_ctl_devid(guc); |
356 | |
357 | for (i = 0; i < GUC_CTL_MAX_DWORDS; i++) |
358 | guc_dbg(guc, "param[%2d] = %#x\n", i, params[i]); |
359 | } |
360 | |
361 | /* |
362 | * Initialise the GuC parameter block before starting the firmware |
363 | * transfer. These parameters are read by the firmware on startup |
364 | * and cannot be changed thereafter. |
365 | */ |
366 | void intel_guc_write_params(struct intel_guc *guc) |
367 | { |
368 | struct intel_uncore *uncore = guc_to_gt(guc)->uncore; |
369 | int i; |
370 | |
371 | /* |
372 | * All SOFT_SCRATCH registers are in FORCEWAKE_GT domain and |
373 | * they are power context saved so it's ok to release forcewake |
374 | * when we are done here and take it again at xfer time. |
375 | */ |
376 | intel_uncore_forcewake_get(uncore, domains: FORCEWAKE_GT); |
377 | |
378 | intel_uncore_write(uncore, SOFT_SCRATCH(0), val: 0); |
379 | |
380 | for (i = 0; i < GUC_CTL_MAX_DWORDS; i++) |
381 | intel_uncore_write(uncore, SOFT_SCRATCH(1 + i), val: guc->params[i]); |
382 | |
383 | intel_uncore_forcewake_put(uncore, domains: FORCEWAKE_GT); |
384 | } |
385 | |
386 | void intel_guc_dump_time_info(struct intel_guc *guc, struct drm_printer *p) |
387 | { |
388 | struct intel_gt *gt = guc_to_gt(guc); |
389 | intel_wakeref_t wakeref; |
390 | u32 stamp = 0; |
391 | u64 ktime; |
392 | |
393 | with_intel_runtime_pm(>->i915->runtime_pm, wakeref) |
394 | stamp = intel_uncore_read(uncore: gt->uncore, GUCPMTIMESTAMP); |
395 | ktime = ktime_get_boottime_ns(); |
396 | |
397 | drm_printf(p, f: "Kernel timestamp: 0x%08llX [%llu]\n", ktime, ktime); |
398 | drm_printf(p, f: "GuC timestamp: 0x%08X [%u]\n", stamp, stamp); |
399 | drm_printf(p, f: "CS timestamp frequency: %u Hz, %u ns\n", |
400 | gt->clock_frequency, gt->clock_period_ns); |
401 | } |
402 | |
403 | int intel_guc_init(struct intel_guc *guc) |
404 | { |
405 | int ret; |
406 | |
407 | ret = intel_uc_fw_init(uc_fw: &guc->fw); |
408 | if (ret) |
409 | goto out; |
410 | |
411 | ret = intel_guc_log_create(log: &guc->log); |
412 | if (ret) |
413 | goto err_fw; |
414 | |
415 | ret = intel_guc_capture_init(guc); |
416 | if (ret) |
417 | goto err_log; |
418 | |
419 | ret = intel_guc_ads_create(guc); |
420 | if (ret) |
421 | goto err_capture; |
422 | |
423 | GEM_BUG_ON(!guc->ads_vma); |
424 | |
425 | ret = intel_guc_ct_init(ct: &guc->ct); |
426 | if (ret) |
427 | goto err_ads; |
428 | |
429 | if (intel_guc_submission_is_used(guc)) { |
430 | /* |
431 | * This is stuff we need to have available at fw load time |
432 | * if we are planning to enable submission later |
433 | */ |
434 | ret = intel_guc_submission_init(guc); |
435 | if (ret) |
436 | goto err_ct; |
437 | } |
438 | |
439 | if (intel_guc_slpc_is_used(guc)) { |
440 | ret = intel_guc_slpc_init(slpc: &guc->slpc); |
441 | if (ret) |
442 | goto err_submission; |
443 | } |
444 | |
445 | /* now that everything is perma-pinned, initialize the parameters */ |
446 | guc_init_params(guc); |
447 | |
448 | intel_uc_fw_change_status(uc_fw: &guc->fw, status: INTEL_UC_FIRMWARE_LOADABLE); |
449 | |
450 | return 0; |
451 | |
452 | err_submission: |
453 | intel_guc_submission_fini(guc); |
454 | err_ct: |
455 | intel_guc_ct_fini(ct: &guc->ct); |
456 | err_ads: |
457 | intel_guc_ads_destroy(guc); |
458 | err_capture: |
459 | intel_guc_capture_destroy(guc); |
460 | err_log: |
461 | intel_guc_log_destroy(log: &guc->log); |
462 | err_fw: |
463 | intel_uc_fw_fini(uc_fw: &guc->fw); |
464 | out: |
465 | intel_uc_fw_change_status(uc_fw: &guc->fw, status: INTEL_UC_FIRMWARE_INIT_FAIL); |
466 | guc_probe_error(guc, "failed with %pe\n", ERR_PTR(ret)); |
467 | return ret; |
468 | } |
469 | |
470 | void intel_guc_fini(struct intel_guc *guc) |
471 | { |
472 | if (!intel_uc_fw_is_loadable(uc_fw: &guc->fw)) |
473 | return; |
474 | |
475 | flush_work(work: &guc->dead_guc_worker); |
476 | |
477 | if (intel_guc_slpc_is_used(guc)) |
478 | intel_guc_slpc_fini(slpc: &guc->slpc); |
479 | |
480 | if (intel_guc_submission_is_used(guc)) |
481 | intel_guc_submission_fini(guc); |
482 | |
483 | intel_guc_ct_fini(ct: &guc->ct); |
484 | |
485 | intel_guc_ads_destroy(guc); |
486 | intel_guc_capture_destroy(guc); |
487 | intel_guc_log_destroy(log: &guc->log); |
488 | intel_uc_fw_fini(uc_fw: &guc->fw); |
489 | } |
490 | |
491 | /* |
492 | * This function implements the MMIO based host to GuC interface. |
493 | */ |
494 | int intel_guc_send_mmio(struct intel_guc *guc, const u32 *request, u32 len, |
495 | u32 *response_buf, u32 response_buf_size) |
496 | { |
497 | struct intel_uncore *uncore = guc_to_gt(guc)->uncore; |
498 | u32 header; |
499 | int i; |
500 | int ret; |
501 | |
502 | GEM_BUG_ON(!len); |
503 | GEM_BUG_ON(len > guc->send_regs.count); |
504 | |
505 | GEM_BUG_ON(FIELD_GET(GUC_HXG_MSG_0_ORIGIN, request[0]) != GUC_HXG_ORIGIN_HOST); |
506 | GEM_BUG_ON(FIELD_GET(GUC_HXG_MSG_0_TYPE, request[0]) != GUC_HXG_TYPE_REQUEST); |
507 | |
508 | mutex_lock(&guc->send_mutex); |
509 | intel_uncore_forcewake_get(uncore, domains: guc->send_regs.fw_domains); |
510 | |
511 | retry: |
512 | for (i = 0; i < len; i++) |
513 | intel_uncore_write(uncore, reg: guc_send_reg(guc, i), val: request[i]); |
514 | |
515 | intel_uncore_posting_read(uncore, guc_send_reg(guc, i - 1)); |
516 | |
517 | intel_guc_notify(guc); |
518 | |
519 | /* |
520 | * No GuC command should ever take longer than 10ms. |
521 | * Fast commands should still complete in 10us. |
522 | */ |
523 | ret = __intel_wait_for_register_fw(uncore, |
524 | reg: guc_send_reg(guc, i: 0), |
525 | GUC_HXG_MSG_0_ORIGIN, |
526 | FIELD_PREP(GUC_HXG_MSG_0_ORIGIN, |
527 | GUC_HXG_ORIGIN_GUC), |
528 | fast_timeout_us: 10, slow_timeout_ms: 10, out_value: &header); |
529 | if (unlikely(ret)) { |
530 | timeout: |
531 | guc_err(guc, "mmio request %#x: no reply %x\n", |
532 | request[0], header); |
533 | goto out; |
534 | } |
535 | |
536 | if (FIELD_GET(GUC_HXG_MSG_0_TYPE, header) == GUC_HXG_TYPE_NO_RESPONSE_BUSY) { |
537 | #define done ({ header = intel_uncore_read(uncore, guc_send_reg(guc, 0)); \ |
538 | FIELD_GET(GUC_HXG_MSG_0_ORIGIN, header) != GUC_HXG_ORIGIN_GUC || \ |
539 | FIELD_GET(GUC_HXG_MSG_0_TYPE, header) != GUC_HXG_TYPE_NO_RESPONSE_BUSY; }) |
540 | |
541 | ret = wait_for(done, 1000); |
542 | if (unlikely(ret)) |
543 | goto timeout; |
544 | if (unlikely(FIELD_GET(GUC_HXG_MSG_0_ORIGIN, header) != |
545 | GUC_HXG_ORIGIN_GUC)) |
546 | goto proto; |
547 | #undef done |
548 | } |
549 | |
550 | if (FIELD_GET(GUC_HXG_MSG_0_TYPE, header) == GUC_HXG_TYPE_NO_RESPONSE_RETRY) { |
551 | u32 reason = FIELD_GET(GUC_HXG_RETRY_MSG_0_REASON, header); |
552 | |
553 | guc_dbg(guc, "mmio request %#x: retrying, reason %u\n", |
554 | request[0], reason); |
555 | goto retry; |
556 | } |
557 | |
558 | if (FIELD_GET(GUC_HXG_MSG_0_TYPE, header) == GUC_HXG_TYPE_RESPONSE_FAILURE) { |
559 | u32 hint = FIELD_GET(GUC_HXG_FAILURE_MSG_0_HINT, header); |
560 | u32 error = FIELD_GET(GUC_HXG_FAILURE_MSG_0_ERROR, header); |
561 | |
562 | guc_err(guc, "mmio request %#x: failure %x/%u\n", |
563 | request[0], error, hint); |
564 | ret = -ENXIO; |
565 | goto out; |
566 | } |
567 | |
568 | if (FIELD_GET(GUC_HXG_MSG_0_TYPE, header) != GUC_HXG_TYPE_RESPONSE_SUCCESS) { |
569 | proto: |
570 | guc_err(guc, "mmio request %#x: unexpected reply %#x\n", |
571 | request[0], header); |
572 | ret = -EPROTO; |
573 | goto out; |
574 | } |
575 | |
576 | if (response_buf) { |
577 | int count = min(response_buf_size, guc->send_regs.count); |
578 | |
579 | GEM_BUG_ON(!count); |
580 | |
581 | response_buf[0] = header; |
582 | |
583 | for (i = 1; i < count; i++) |
584 | response_buf[i] = intel_uncore_read(uncore, |
585 | reg: guc_send_reg(guc, i)); |
586 | |
587 | /* Use number of copied dwords as our return value */ |
588 | ret = count; |
589 | } else { |
590 | /* Use data from the GuC response as our return value */ |
591 | ret = FIELD_GET(GUC_HXG_RESPONSE_MSG_0_DATA0, header); |
592 | } |
593 | |
594 | out: |
595 | intel_uncore_forcewake_put(uncore, domains: guc->send_regs.fw_domains); |
596 | mutex_unlock(lock: &guc->send_mutex); |
597 | |
598 | return ret; |
599 | } |
600 | |
601 | int intel_guc_crash_process_msg(struct intel_guc *guc, u32 action) |
602 | { |
603 | if (action == INTEL_GUC_ACTION_NOTIFY_CRASH_DUMP_POSTED) |
604 | guc_err(guc, "Crash dump notification\n"); |
605 | else if (action == INTEL_GUC_ACTION_NOTIFY_EXCEPTION) |
606 | guc_err(guc, "Exception notification\n"); |
607 | else |
608 | guc_err(guc, "Unknown crash notification: 0x%04X\n", action); |
609 | |
610 | queue_work(wq: system_unbound_wq, work: &guc->dead_guc_worker); |
611 | |
612 | return 0; |
613 | } |
614 | |
615 | int intel_guc_to_host_process_recv_msg(struct intel_guc *guc, |
616 | const u32 *payload, u32 len) |
617 | { |
618 | u32 msg; |
619 | |
620 | if (unlikely(!len)) |
621 | return -EPROTO; |
622 | |
623 | /* Make sure to handle only enabled messages */ |
624 | msg = payload[0] & guc->msg_enabled_mask; |
625 | |
626 | if (msg & INTEL_GUC_RECV_MSG_CRASH_DUMP_POSTED) |
627 | guc_err(guc, "Received early crash dump notification!\n"); |
628 | if (msg & INTEL_GUC_RECV_MSG_EXCEPTION) |
629 | guc_err(guc, "Received early exception notification!\n"); |
630 | |
631 | if (msg & (INTEL_GUC_RECV_MSG_CRASH_DUMP_POSTED | INTEL_GUC_RECV_MSG_EXCEPTION)) |
632 | queue_work(wq: system_unbound_wq, work: &guc->dead_guc_worker); |
633 | |
634 | return 0; |
635 | } |
636 | |
637 | /** |
638 | * intel_guc_auth_huc() - Send action to GuC to authenticate HuC ucode |
639 | * @guc: intel_guc structure |
640 | * @rsa_offset: rsa offset w.r.t ggtt base of huc vma |
641 | * |
642 | * Triggers a HuC firmware authentication request to the GuC via intel_guc_send |
643 | * INTEL_GUC_ACTION_AUTHENTICATE_HUC interface. This function is invoked by |
644 | * intel_huc_auth(). |
645 | * |
646 | * Return: non-zero code on error |
647 | */ |
648 | int intel_guc_auth_huc(struct intel_guc *guc, u32 rsa_offset) |
649 | { |
650 | u32 action[] = { |
651 | INTEL_GUC_ACTION_AUTHENTICATE_HUC, |
652 | rsa_offset |
653 | }; |
654 | |
655 | return intel_guc_send(guc, action, ARRAY_SIZE(action)); |
656 | } |
657 | |
658 | /** |
659 | * intel_guc_suspend() - notify GuC entering suspend state |
660 | * @guc: the guc |
661 | */ |
662 | int intel_guc_suspend(struct intel_guc *guc) |
663 | { |
664 | int ret; |
665 | u32 action[] = { |
666 | INTEL_GUC_ACTION_CLIENT_SOFT_RESET, |
667 | }; |
668 | |
669 | if (!intel_guc_is_ready(guc)) |
670 | return 0; |
671 | |
672 | if (intel_guc_submission_is_used(guc)) { |
673 | flush_work(work: &guc->dead_guc_worker); |
674 | |
675 | /* |
676 | * This H2G MMIO command tears down the GuC in two steps. First it will |
677 | * generate a G2H CTB for every active context indicating a reset. In |
678 | * practice the i915 shouldn't ever get a G2H as suspend should only be |
679 | * called when the GPU is idle. Next, it tears down the CTBs and this |
680 | * H2G MMIO command completes. |
681 | * |
682 | * Don't abort on a failure code from the GuC. Keep going and do the |
683 | * clean up in santize() and re-initialisation on resume and hopefully |
684 | * the error here won't be problematic. |
685 | */ |
686 | ret = intel_guc_send_mmio(guc, request: action, ARRAY_SIZE(action), NULL, response_buf_size: 0); |
687 | if (ret) |
688 | guc_err(guc, "suspend: RESET_CLIENT action failed with %pe\n", |
689 | ERR_PTR(ret)); |
690 | } |
691 | |
692 | /* Signal that the GuC isn't running. */ |
693 | intel_guc_sanitize(guc); |
694 | |
695 | return 0; |
696 | } |
697 | |
698 | /** |
699 | * intel_guc_resume() - notify GuC resuming from suspend state |
700 | * @guc: the guc |
701 | */ |
702 | int intel_guc_resume(struct intel_guc *guc) |
703 | { |
704 | /* |
705 | * NB: This function can still be called even if GuC submission is |
706 | * disabled, e.g. if GuC is enabled for HuC authentication only. Thus, |
707 | * if any code is later added here, it must be support doing nothing |
708 | * if submission is disabled (as per intel_guc_suspend). |
709 | */ |
710 | return 0; |
711 | } |
712 | |
713 | /** |
714 | * DOC: GuC Memory Management |
715 | * |
716 | * GuC can't allocate any memory for its own usage, so all the allocations must |
717 | * be handled by the host driver. GuC accesses the memory via the GGTT, with the |
718 | * exception of the top and bottom parts of the 4GB address space, which are |
719 | * instead re-mapped by the GuC HW to memory location of the FW itself (WOPCM) |
720 | * or other parts of the HW. The driver must take care not to place objects that |
721 | * the GuC is going to access in these reserved ranges. The layout of the GuC |
722 | * address space is shown below: |
723 | * |
724 | * :: |
725 | * |
726 | * +===========> +====================+ <== FFFF_FFFF |
727 | * ^ | Reserved | |
728 | * | +====================+ <== GUC_GGTT_TOP |
729 | * | | | |
730 | * | | DRAM | |
731 | * GuC | | |
732 | * Address +===> +====================+ <== GuC ggtt_pin_bias |
733 | * Space ^ | | |
734 | * | | | | |
735 | * | GuC | GuC | |
736 | * | WOPCM | WOPCM | |
737 | * | Size | | |
738 | * | | | | |
739 | * v v | | |
740 | * +=======+===> +====================+ <== 0000_0000 |
741 | * |
742 | * The lower part of GuC Address Space [0, ggtt_pin_bias) is mapped to GuC WOPCM |
743 | * while upper part of GuC Address Space [ggtt_pin_bias, GUC_GGTT_TOP) is mapped |
744 | * to DRAM. The value of the GuC ggtt_pin_bias is the GuC WOPCM size. |
745 | */ |
746 | |
747 | /** |
748 | * intel_guc_allocate_vma() - Allocate a GGTT VMA for GuC usage |
749 | * @guc: the guc |
750 | * @size: size of area to allocate (both virtual space and memory) |
751 | * |
752 | * This is a wrapper to create an object for use with the GuC. In order to |
753 | * use it inside the GuC, an object needs to be pinned lifetime, so we allocate |
754 | * both some backing storage and a range inside the Global GTT. We must pin |
755 | * it in the GGTT somewhere other than than [0, GUC ggtt_pin_bias) because that |
756 | * range is reserved inside GuC. |
757 | * |
758 | * Return: A i915_vma if successful, otherwise an ERR_PTR. |
759 | */ |
760 | struct i915_vma *intel_guc_allocate_vma(struct intel_guc *guc, u32 size) |
761 | { |
762 | struct intel_gt *gt = guc_to_gt(guc); |
763 | struct drm_i915_gem_object *obj; |
764 | struct i915_vma *vma; |
765 | u64 flags; |
766 | int ret; |
767 | |
768 | if (HAS_LMEM(gt->i915)) |
769 | obj = i915_gem_object_create_lmem(i915: gt->i915, size, |
770 | I915_BO_ALLOC_CPU_CLEAR | |
771 | I915_BO_ALLOC_CONTIGUOUS | |
772 | I915_BO_ALLOC_PM_EARLY); |
773 | else |
774 | obj = i915_gem_object_create_shmem(i915: gt->i915, size); |
775 | |
776 | if (IS_ERR(ptr: obj)) |
777 | return ERR_CAST(ptr: obj); |
778 | |
779 | /* |
780 | * Wa_22016122933: For Media version 13.0, all Media GT shared |
781 | * memory needs to be mapped as WC on CPU side and UC (PAT |
782 | * index 2) on GPU side. |
783 | */ |
784 | if (intel_gt_needs_wa_22016122933(gt)) |
785 | i915_gem_object_set_cache_coherency(obj, cache_level: I915_CACHE_NONE); |
786 | |
787 | vma = i915_vma_instance(obj, vm: >->ggtt->vm, NULL); |
788 | if (IS_ERR(ptr: vma)) |
789 | goto err; |
790 | |
791 | flags = PIN_OFFSET_BIAS | i915_ggtt_pin_bias(vma); |
792 | ret = i915_ggtt_pin(vma, NULL, align: 0, flags); |
793 | if (ret) { |
794 | vma = ERR_PTR(error: ret); |
795 | goto err; |
796 | } |
797 | |
798 | return i915_vma_make_unshrinkable(vma); |
799 | |
800 | err: |
801 | i915_gem_object_put(obj); |
802 | return vma; |
803 | } |
804 | |
805 | /** |
806 | * intel_guc_allocate_and_map_vma() - Allocate and map VMA for GuC usage |
807 | * @guc: the guc |
808 | * @size: size of area to allocate (both virtual space and memory) |
809 | * @out_vma: return variable for the allocated vma pointer |
810 | * @out_vaddr: return variable for the obj mapping |
811 | * |
812 | * This wrapper calls intel_guc_allocate_vma() and then maps the allocated |
813 | * object with I915_MAP_WB. |
814 | * |
815 | * Return: 0 if successful, a negative errno code otherwise. |
816 | */ |
817 | int intel_guc_allocate_and_map_vma(struct intel_guc *guc, u32 size, |
818 | struct i915_vma **out_vma, void **out_vaddr) |
819 | { |
820 | struct i915_vma *vma; |
821 | void *vaddr; |
822 | |
823 | vma = intel_guc_allocate_vma(guc, size); |
824 | if (IS_ERR(ptr: vma)) |
825 | return PTR_ERR(ptr: vma); |
826 | |
827 | vaddr = i915_gem_object_pin_map_unlocked(obj: vma->obj, |
828 | type: intel_gt_coherent_map_type(gt: guc_to_gt(guc), |
829 | obj: vma->obj, always_coherent: true)); |
830 | if (IS_ERR(ptr: vaddr)) { |
831 | i915_vma_unpin_and_release(p_vma: &vma, flags: 0); |
832 | return PTR_ERR(ptr: vaddr); |
833 | } |
834 | |
835 | *out_vma = vma; |
836 | *out_vaddr = vaddr; |
837 | |
838 | return 0; |
839 | } |
840 | |
841 | static int __guc_action_self_cfg(struct intel_guc *guc, u16 key, u16 len, u64 value) |
842 | { |
843 | u32 request[HOST2GUC_SELF_CFG_REQUEST_MSG_LEN] = { |
844 | FIELD_PREP(GUC_HXG_MSG_0_ORIGIN, GUC_HXG_ORIGIN_HOST) | |
845 | FIELD_PREP(GUC_HXG_MSG_0_TYPE, GUC_HXG_TYPE_REQUEST) | |
846 | FIELD_PREP(GUC_HXG_REQUEST_MSG_0_ACTION, GUC_ACTION_HOST2GUC_SELF_CFG), |
847 | FIELD_PREP(HOST2GUC_SELF_CFG_REQUEST_MSG_1_KLV_KEY, key) | |
848 | FIELD_PREP(HOST2GUC_SELF_CFG_REQUEST_MSG_1_KLV_LEN, len), |
849 | FIELD_PREP(HOST2GUC_SELF_CFG_REQUEST_MSG_2_VALUE32, lower_32_bits(value)), |
850 | FIELD_PREP(HOST2GUC_SELF_CFG_REQUEST_MSG_3_VALUE64, upper_32_bits(value)), |
851 | }; |
852 | int ret; |
853 | |
854 | GEM_BUG_ON(len > 2); |
855 | GEM_BUG_ON(len == 1 && upper_32_bits(value)); |
856 | |
857 | /* Self config must go over MMIO */ |
858 | ret = intel_guc_send_mmio(guc, request, ARRAY_SIZE(request), NULL, response_buf_size: 0); |
859 | |
860 | if (unlikely(ret < 0)) |
861 | return ret; |
862 | if (unlikely(ret > 1)) |
863 | return -EPROTO; |
864 | if (unlikely(!ret)) |
865 | return -ENOKEY; |
866 | |
867 | return 0; |
868 | } |
869 | |
870 | static int __guc_self_cfg(struct intel_guc *guc, u16 key, u16 len, u64 value) |
871 | { |
872 | int err = __guc_action_self_cfg(guc, key, len, value); |
873 | |
874 | if (unlikely(err)) |
875 | guc_probe_error(guc, "Unsuccessful self-config (%pe) key %#hx value %#llx\n", |
876 | ERR_PTR(err), key, value); |
877 | return err; |
878 | } |
879 | |
880 | int intel_guc_self_cfg32(struct intel_guc *guc, u16 key, u32 value) |
881 | { |
882 | return __guc_self_cfg(guc, key, len: 1, value); |
883 | } |
884 | |
885 | int intel_guc_self_cfg64(struct intel_guc *guc, u16 key, u64 value) |
886 | { |
887 | return __guc_self_cfg(guc, key, len: 2, value); |
888 | } |
889 | |
890 | /** |
891 | * intel_guc_load_status - dump information about GuC load status |
892 | * @guc: the GuC |
893 | * @p: the &drm_printer |
894 | * |
895 | * Pretty printer for GuC load status. |
896 | */ |
897 | void intel_guc_load_status(struct intel_guc *guc, struct drm_printer *p) |
898 | { |
899 | struct intel_gt *gt = guc_to_gt(guc); |
900 | struct intel_uncore *uncore = gt->uncore; |
901 | intel_wakeref_t wakeref; |
902 | |
903 | if (!intel_guc_is_supported(guc)) { |
904 | drm_printf(p, f: "GuC not supported\n"); |
905 | return; |
906 | } |
907 | |
908 | if (!intel_guc_is_wanted(guc)) { |
909 | drm_printf(p, f: "GuC disabled\n"); |
910 | return; |
911 | } |
912 | |
913 | intel_uc_fw_dump(uc_fw: &guc->fw, p); |
914 | |
915 | with_intel_runtime_pm(uncore->rpm, wakeref) { |
916 | u32 status = intel_uncore_read(uncore, GUC_STATUS); |
917 | u32 i; |
918 | |
919 | drm_printf(p, f: "GuC status 0x%08x:\n", status); |
920 | drm_printf(p, f: "\tBootrom status = 0x%x\n", |
921 | (status & GS_BOOTROM_MASK) >> GS_BOOTROM_SHIFT); |
922 | drm_printf(p, f: "\tuKernel status = 0x%x\n", |
923 | (status & GS_UKERNEL_MASK) >> GS_UKERNEL_SHIFT); |
924 | drm_printf(p, f: "\tMIA Core status = 0x%x\n", |
925 | (status & GS_MIA_MASK) >> GS_MIA_SHIFT); |
926 | drm_puts(p, str: "Scratch registers:\n"); |
927 | for (i = 0; i < 16; i++) { |
928 | drm_printf(p, f: "\t%2d: \t0x%x\n", |
929 | i, intel_uncore_read(uncore, SOFT_SCRATCH(i))); |
930 | } |
931 | } |
932 | } |
933 | |
934 | void intel_guc_write_barrier(struct intel_guc *guc) |
935 | { |
936 | struct intel_gt *gt = guc_to_gt(guc); |
937 | |
938 | if (i915_gem_object_is_lmem(obj: guc->ct.vma->obj)) { |
939 | /* |
940 | * Ensure intel_uncore_write_fw can be used rather than |
941 | * intel_uncore_write. |
942 | */ |
943 | GEM_BUG_ON(guc->send_regs.fw_domains); |
944 | |
945 | /* |
946 | * This register is used by the i915 and GuC for MMIO based |
947 | * communication. Once we are in this code CTBs are the only |
948 | * method the i915 uses to communicate with the GuC so it is |
949 | * safe to write to this register (a value of 0 is NOP for MMIO |
950 | * communication). If we ever start mixing CTBs and MMIOs a new |
951 | * register will have to be chosen. This function is also used |
952 | * to enforce ordering of a work queue item write and an update |
953 | * to the process descriptor. When a work queue is being used, |
954 | * CTBs are also the only mechanism of communication. |
955 | */ |
956 | intel_uncore_write_fw(gt->uncore, GEN11_SOFT_SCRATCH(0), 0); |
957 | } else { |
958 | /* wmb() sufficient for a barrier if in smem */ |
959 | wmb(); |
960 | } |
961 | } |
962 |
Definitions
- intel_guc_notify
- guc_send_reg
- intel_guc_init_send_regs
- gen9_reset_guc_interrupts
- gen9_enable_guc_interrupts
- gen9_disable_guc_interrupts
- __gen11_reset_guc_interrupts
- gen11_reset_guc_interrupts
- gen11_enable_guc_interrupts
- gen11_disable_guc_interrupts
- guc_dead_worker_func
- intel_guc_init_early
- intel_guc_init_late
- guc_ctl_debug_flags
- guc_ctl_feature_flags
- guc_ctl_log_params_flags
- guc_ctl_ads_flags
- guc_ctl_wa_flags
- guc_ctl_devid
- guc_init_params
- intel_guc_write_params
- intel_guc_dump_time_info
- intel_guc_init
- intel_guc_fini
- intel_guc_send_mmio
- intel_guc_crash_process_msg
- intel_guc_to_host_process_recv_msg
- intel_guc_auth_huc
- intel_guc_suspend
- intel_guc_resume
- intel_guc_allocate_vma
- intel_guc_allocate_and_map_vma
- __guc_action_self_cfg
- __guc_self_cfg
- intel_guc_self_cfg32
- intel_guc_self_cfg64
- intel_guc_load_status
Improve your Profiling and Debugging skills
Find out more