Branch data Line data Source code
1 : : // SPDX-License-Identifier: MIT
2 : : /*
3 : : * Copyright © 2014-2019 Intel Corporation
4 : : */
5 : :
6 : : #include "gt/intel_gt.h"
7 : : #include "gt/intel_gt_irq.h"
8 : : #include "gt/intel_gt_pm_irq.h"
9 : : #include "intel_guc.h"
10 : : #include "intel_guc_ads.h"
11 : : #include "intel_guc_submission.h"
12 : : #include "i915_drv.h"
13 : :
14 : : /**
15 : : * DOC: GuC
16 : : *
17 : : * The GuC is a microcontroller inside the GT HW, introduced in gen9. The GuC is
18 : : * designed to offload some of the functionality usually performed by the host
19 : : * driver; currently the main operations it can take care of are:
20 : : *
21 : : * - Authentication of the HuC, which is required to fully enable HuC usage.
22 : : * - Low latency graphics context scheduling (a.k.a. GuC submission).
23 : : * - GT Power management.
24 : : *
25 : : * The enable_guc module parameter can be used to select which of those
26 : : * operations to enable within GuC. Note that not all the operations are
27 : : * supported on all gen9+ platforms.
28 : : *
29 : : * Enabling the GuC is not mandatory and therefore the firmware is only loaded
30 : : * if at least one of the operations is selected. However, not loading the GuC
31 : : * might result in the loss of some features that do require the GuC (currently
32 : : * just the HuC, but more are expected to land in the future).
33 : : */
34 : :
35 : 0 : void intel_guc_notify(struct intel_guc *guc)
36 : : {
37 : 0 : struct intel_gt *gt = guc_to_gt(guc);
38 : :
39 : : /*
40 : : * On Gen11+, the value written to the register is passes as a payload
41 : : * to the FW. However, the FW currently treats all values the same way
42 : : * (H2G interrupt), so we can just write the value that the HW expects
43 : : * on older gens.
44 : : */
45 : 0 : intel_uncore_write(gt->uncore, guc->notify_reg, GUC_SEND_TRIGGER);
46 : 0 : }
47 : :
48 : 0 : static inline i915_reg_t guc_send_reg(struct intel_guc *guc, u32 i)
49 : : {
50 : 0 : GEM_BUG_ON(!guc->send_regs.base);
51 : 0 : GEM_BUG_ON(!guc->send_regs.count);
52 : 0 : GEM_BUG_ON(i >= guc->send_regs.count);
53 : :
54 : 0 : return _MMIO(guc->send_regs.base + 4 * i);
55 : : }
56 : :
57 : 0 : void intel_guc_init_send_regs(struct intel_guc *guc)
58 : : {
59 [ # # ]: 0 : struct intel_gt *gt = guc_to_gt(guc);
60 : 0 : enum forcewake_domains fw_domains = 0;
61 : 0 : unsigned int i;
62 : :
63 [ # # ]: 0 : if (INTEL_GEN(gt->i915) >= 11) {
64 : 0 : guc->send_regs.base =
65 : : i915_mmio_reg_offset(GEN11_SOFT_SCRATCH(0));
66 : 0 : guc->send_regs.count = GEN11_SOFT_SCRATCH_COUNT;
67 : : } else {
68 : 0 : guc->send_regs.base = i915_mmio_reg_offset(SOFT_SCRATCH(0));
69 : 0 : guc->send_regs.count = GUC_MAX_MMIO_MSG_LEN;
70 : 0 : BUILD_BUG_ON(GUC_MAX_MMIO_MSG_LEN > SOFT_SCRATCH_COUNT);
71 : : }
72 : :
73 [ # # ]: 0 : for (i = 0; i < guc->send_regs.count; i++) {
74 : 0 : fw_domains |= intel_uncore_forcewake_for_reg(gt->uncore,
75 : : guc_send_reg(guc, i),
76 : : FW_REG_READ | FW_REG_WRITE);
77 : : }
78 : 0 : guc->send_regs.fw_domains = fw_domains;
79 : 0 : }
80 : :
81 : 0 : static void gen9_reset_guc_interrupts(struct intel_guc *guc)
82 : : {
83 : 0 : struct intel_gt *gt = guc_to_gt(guc);
84 : :
85 : 0 : assert_rpm_wakelock_held(>->i915->runtime_pm);
86 : :
87 : 0 : spin_lock_irq(>->irq_lock);
88 : 0 : gen6_gt_pm_reset_iir(gt, gt->pm_guc_events);
89 : 0 : spin_unlock_irq(>->irq_lock);
90 : 0 : }
91 : :
92 : 0 : static void gen9_enable_guc_interrupts(struct intel_guc *guc)
93 : : {
94 : 0 : struct intel_gt *gt = guc_to_gt(guc);
95 : :
96 : 0 : assert_rpm_wakelock_held(>->i915->runtime_pm);
97 : :
98 : 0 : spin_lock_irq(>->irq_lock);
99 [ # # ]: 0 : if (!guc->interrupts.enabled) {
100 [ # # # # ]: 0 : WARN_ON_ONCE(intel_uncore_read(gt->uncore, GEN8_GT_IIR(2)) &
101 : : gt->pm_guc_events);
102 : 0 : guc->interrupts.enabled = true;
103 : 0 : gen6_gt_pm_enable_irq(gt, gt->pm_guc_events);
104 : : }
105 : 0 : spin_unlock_irq(>->irq_lock);
106 : 0 : }
107 : :
108 : 0 : static void gen9_disable_guc_interrupts(struct intel_guc *guc)
109 : : {
110 : 0 : struct intel_gt *gt = guc_to_gt(guc);
111 : :
112 : 0 : assert_rpm_wakelock_held(>->i915->runtime_pm);
113 : :
114 : 0 : spin_lock_irq(>->irq_lock);
115 : 0 : guc->interrupts.enabled = false;
116 : :
117 : 0 : gen6_gt_pm_disable_irq(gt, gt->pm_guc_events);
118 : :
119 : 0 : spin_unlock_irq(>->irq_lock);
120 : 0 : intel_synchronize_irq(gt->i915);
121 : :
122 : 0 : gen9_reset_guc_interrupts(guc);
123 : 0 : }
124 : :
125 : 0 : static void gen11_reset_guc_interrupts(struct intel_guc *guc)
126 : : {
127 : 0 : struct intel_gt *gt = guc_to_gt(guc);
128 : :
129 : 0 : spin_lock_irq(>->irq_lock);
130 : 0 : gen11_gt_reset_one_iir(gt, 0, GEN11_GUC);
131 : 0 : spin_unlock_irq(>->irq_lock);
132 : 0 : }
133 : :
134 : 0 : static void gen11_enable_guc_interrupts(struct intel_guc *guc)
135 : : {
136 : 0 : struct intel_gt *gt = guc_to_gt(guc);
137 : :
138 : 0 : spin_lock_irq(>->irq_lock);
139 [ # # ]: 0 : if (!guc->interrupts.enabled) {
140 : 0 : u32 events = REG_FIELD_PREP(ENGINE1_MASK, GUC_INTR_GUC2HOST);
141 : :
142 [ # # # # ]: 0 : WARN_ON_ONCE(gen11_gt_reset_one_iir(gt, 0, GEN11_GUC));
143 : 0 : intel_uncore_write(gt->uncore,
144 : : GEN11_GUC_SG_INTR_ENABLE, events);
145 : 0 : intel_uncore_write(gt->uncore,
146 : : GEN11_GUC_SG_INTR_MASK, ~events);
147 : 0 : guc->interrupts.enabled = true;
148 : : }
149 : 0 : spin_unlock_irq(>->irq_lock);
150 : 0 : }
151 : :
152 : 0 : static void gen11_disable_guc_interrupts(struct intel_guc *guc)
153 : : {
154 : 0 : struct intel_gt *gt = guc_to_gt(guc);
155 : :
156 : 0 : spin_lock_irq(>->irq_lock);
157 : 0 : guc->interrupts.enabled = false;
158 : :
159 : 0 : intel_uncore_write(gt->uncore, GEN11_GUC_SG_INTR_MASK, ~0);
160 : 0 : intel_uncore_write(gt->uncore, GEN11_GUC_SG_INTR_ENABLE, 0);
161 : :
162 : 0 : spin_unlock_irq(>->irq_lock);
163 : 0 : intel_synchronize_irq(gt->i915);
164 : :
165 : 0 : gen11_reset_guc_interrupts(guc);
166 : 0 : }
167 : :
168 : 0 : void intel_guc_init_early(struct intel_guc *guc)
169 : : {
170 : 0 : struct drm_i915_private *i915 = guc_to_gt(guc)->i915;
171 : :
172 : 0 : intel_guc_fw_init_early(guc);
173 : 0 : intel_guc_ct_init_early(&guc->ct);
174 : 0 : intel_guc_log_init_early(&guc->log);
175 : 0 : intel_guc_submission_init_early(guc);
176 : :
177 : 0 : mutex_init(&guc->send_mutex);
178 [ # # ]: 0 : spin_lock_init(&guc->irq_lock);
179 [ # # ]: 0 : if (INTEL_GEN(i915) >= 11) {
180 : 0 : guc->notify_reg = GEN11_GUC_HOST_INTERRUPT;
181 : 0 : guc->interrupts.reset = gen11_reset_guc_interrupts;
182 : 0 : guc->interrupts.enable = gen11_enable_guc_interrupts;
183 : 0 : guc->interrupts.disable = gen11_disable_guc_interrupts;
184 : : } else {
185 : 0 : guc->notify_reg = GUC_SEND_INTERRUPT;
186 : 0 : guc->interrupts.reset = gen9_reset_guc_interrupts;
187 : 0 : guc->interrupts.enable = gen9_enable_guc_interrupts;
188 : 0 : guc->interrupts.disable = gen9_disable_guc_interrupts;
189 : : }
190 : 0 : }
191 : :
192 : 0 : static u32 guc_ctl_debug_flags(struct intel_guc *guc)
193 : : {
194 : 0 : u32 level = intel_guc_log_get_level(&guc->log);
195 : 0 : u32 flags = 0;
196 : :
197 [ # # ]: 0 : if (!GUC_LOG_LEVEL_IS_VERBOSE(level))
198 : : flags |= GUC_LOG_DISABLED;
199 : : else
200 : 0 : flags |= GUC_LOG_LEVEL_TO_VERBOSITY(level) <<
201 : : GUC_LOG_VERBOSITY_SHIFT;
202 : :
203 : 0 : return flags;
204 : : }
205 : :
206 : 0 : static u32 guc_ctl_feature_flags(struct intel_guc *guc)
207 : : {
208 : 0 : u32 flags = 0;
209 : :
210 : 0 : if (!intel_guc_is_submission_supported(guc))
211 : 0 : flags |= GUC_CTL_DISABLE_SCHEDULER;
212 : :
213 : 0 : return flags;
214 : : }
215 : :
216 : 0 : static u32 guc_ctl_ctxinfo_flags(struct intel_guc *guc)
217 : : {
218 : 0 : u32 flags = 0;
219 : :
220 : 0 : if (intel_guc_is_submission_supported(guc)) {
221 : 0 : u32 ctxnum, base;
222 : :
223 : 0 : base = intel_guc_ggtt_offset(guc, guc->stage_desc_pool);
224 : 0 : ctxnum = GUC_MAX_STAGE_DESCRIPTORS / 16;
225 : :
226 : 0 : base >>= PAGE_SHIFT;
227 : 0 : flags |= (base << GUC_CTL_BASE_ADDR_SHIFT) |
228 : : (ctxnum << GUC_CTL_CTXNUM_IN16_SHIFT);
229 : : }
230 : 0 : return flags;
231 : : }
232 : :
233 : 0 : static u32 guc_ctl_log_params_flags(struct intel_guc *guc)
234 : : {
235 : 0 : u32 offset = intel_guc_ggtt_offset(guc, guc->log.vma) >> PAGE_SHIFT;
236 : 0 : u32 flags;
237 : :
238 : : #if (((CRASH_BUFFER_SIZE) % SZ_1M) == 0)
239 : : #define UNIT SZ_1M
240 : : #define FLAG GUC_LOG_ALLOC_IN_MEGABYTE
241 : : #else
242 : : #define UNIT SZ_4K
243 : : #define FLAG 0
244 : : #endif
245 : :
246 : 0 : BUILD_BUG_ON(!CRASH_BUFFER_SIZE);
247 : 0 : BUILD_BUG_ON(!IS_ALIGNED(CRASH_BUFFER_SIZE, UNIT));
248 : 0 : BUILD_BUG_ON(!DPC_BUFFER_SIZE);
249 : 0 : BUILD_BUG_ON(!IS_ALIGNED(DPC_BUFFER_SIZE, UNIT));
250 : 0 : BUILD_BUG_ON(!ISR_BUFFER_SIZE);
251 : 0 : BUILD_BUG_ON(!IS_ALIGNED(ISR_BUFFER_SIZE, UNIT));
252 : :
253 : 0 : BUILD_BUG_ON((CRASH_BUFFER_SIZE / UNIT - 1) >
254 : : (GUC_LOG_CRASH_MASK >> GUC_LOG_CRASH_SHIFT));
255 : 0 : BUILD_BUG_ON((DPC_BUFFER_SIZE / UNIT - 1) >
256 : : (GUC_LOG_DPC_MASK >> GUC_LOG_DPC_SHIFT));
257 : 0 : BUILD_BUG_ON((ISR_BUFFER_SIZE / UNIT - 1) >
258 : : (GUC_LOG_ISR_MASK >> GUC_LOG_ISR_SHIFT));
259 : :
260 : 0 : flags = GUC_LOG_VALID |
261 : : GUC_LOG_NOTIFY_ON_HALF_FULL |
262 : : FLAG |
263 : : ((CRASH_BUFFER_SIZE / UNIT - 1) << GUC_LOG_CRASH_SHIFT) |
264 : : ((DPC_BUFFER_SIZE / UNIT - 1) << GUC_LOG_DPC_SHIFT) |
265 : : ((ISR_BUFFER_SIZE / UNIT - 1) << GUC_LOG_ISR_SHIFT) |
266 : 0 : (offset << GUC_LOG_BUF_ADDR_SHIFT);
267 : :
268 : : #undef UNIT
269 : : #undef FLAG
270 : :
271 : 0 : return flags;
272 : : }
273 : :
274 : 0 : static u32 guc_ctl_ads_flags(struct intel_guc *guc)
275 : : {
276 : 0 : u32 ads = intel_guc_ggtt_offset(guc, guc->ads_vma) >> PAGE_SHIFT;
277 : 0 : u32 flags = ads << GUC_ADS_ADDR_SHIFT;
278 : :
279 : 0 : return flags;
280 : : }
281 : :
282 : : /*
283 : : * Initialise the GuC parameter block before starting the firmware
284 : : * transfer. These parameters are read by the firmware on startup
285 : : * and cannot be changed thereafter.
286 : : */
287 : 0 : static void guc_init_params(struct intel_guc *guc)
288 : : {
289 : 0 : u32 *params = guc->params;
290 : 0 : int i;
291 : :
292 : 0 : BUILD_BUG_ON(sizeof(guc->params) != GUC_CTL_MAX_DWORDS * sizeof(u32));
293 : :
294 [ # # ]: 0 : params[GUC_CTL_CTXINFO] = guc_ctl_ctxinfo_flags(guc);
295 [ # # ]: 0 : params[GUC_CTL_LOG_PARAMS] = guc_ctl_log_params_flags(guc);
296 [ # # ]: 0 : params[GUC_CTL_FEATURE] = guc_ctl_feature_flags(guc);
297 [ # # ]: 0 : params[GUC_CTL_DEBUG] = guc_ctl_debug_flags(guc);
298 : 0 : params[GUC_CTL_ADS] = guc_ctl_ads_flags(guc);
299 : :
300 [ # # ]: 0 : for (i = 0; i < GUC_CTL_MAX_DWORDS; i++)
301 : 0 : DRM_DEBUG_DRIVER("param[%2d] = %#x\n", i, params[i]);
302 : 0 : }
303 : :
304 : : /*
305 : : * Initialise the GuC parameter block before starting the firmware
306 : : * transfer. These parameters are read by the firmware on startup
307 : : * and cannot be changed thereafter.
308 : : */
309 : 0 : void intel_guc_write_params(struct intel_guc *guc)
310 : : {
311 : 0 : struct intel_uncore *uncore = guc_to_gt(guc)->uncore;
312 : 0 : int i;
313 : :
314 : : /*
315 : : * All SOFT_SCRATCH registers are in FORCEWAKE_BLITTER domain and
316 : : * they are power context saved so it's ok to release forcewake
317 : : * when we are done here and take it again at xfer time.
318 : : */
319 : 0 : intel_uncore_forcewake_get(uncore, FORCEWAKE_BLITTER);
320 : :
321 : 0 : intel_uncore_write(uncore, SOFT_SCRATCH(0), 0);
322 : :
323 [ # # ]: 0 : for (i = 0; i < GUC_CTL_MAX_DWORDS; i++)
324 : 0 : intel_uncore_write(uncore, SOFT_SCRATCH(1 + i), guc->params[i]);
325 : :
326 : 0 : intel_uncore_forcewake_put(uncore, FORCEWAKE_BLITTER);
327 : 0 : }
328 : :
329 : 0 : int intel_guc_init(struct intel_guc *guc)
330 : : {
331 : 0 : struct intel_gt *gt = guc_to_gt(guc);
332 : 0 : int ret;
333 : :
334 : 0 : ret = intel_uc_fw_init(&guc->fw);
335 [ # # ]: 0 : if (ret)
336 : 0 : goto err_fetch;
337 : :
338 : 0 : ret = intel_guc_log_create(&guc->log);
339 [ # # ]: 0 : if (ret)
340 : 0 : goto err_fw;
341 : :
342 : 0 : ret = intel_guc_ads_create(guc);
343 [ # # ]: 0 : if (ret)
344 : 0 : goto err_log;
345 : 0 : GEM_BUG_ON(!guc->ads_vma);
346 : :
347 : 0 : ret = intel_guc_ct_init(&guc->ct);
348 [ # # ]: 0 : if (ret)
349 : 0 : goto err_ads;
350 : :
351 [ # # ]: 0 : if (intel_guc_is_submission_supported(guc)) {
352 : : /*
353 : : * This is stuff we need to have available at fw load time
354 : : * if we are planning to enable submission later
355 : : */
356 : 0 : ret = intel_guc_submission_init(guc);
357 [ # # ]: 0 : if (ret)
358 : 0 : goto err_ct;
359 : : }
360 : :
361 : : /* now that everything is perma-pinned, initialize the parameters */
362 : 0 : guc_init_params(guc);
363 : :
364 : : /* We need to notify the guc whenever we change the GGTT */
365 : 0 : i915_ggtt_enable_guc(gt->ggtt);
366 : :
367 : 0 : return 0;
368 : :
369 : : err_ct:
370 : 0 : intel_guc_ct_fini(&guc->ct);
371 : 0 : err_ads:
372 : 0 : intel_guc_ads_destroy(guc);
373 : 0 : err_log:
374 : 0 : intel_guc_log_destroy(&guc->log);
375 : 0 : err_fw:
376 : 0 : intel_uc_fw_fini(&guc->fw);
377 : 0 : err_fetch:
378 : 0 : intel_uc_fw_cleanup_fetch(&guc->fw);
379 : 0 : DRM_DEV_DEBUG_DRIVER(gt->i915->drm.dev, "failed with %d\n", ret);
380 : 0 : return ret;
381 : : }
382 : :
383 : 0 : void intel_guc_fini(struct intel_guc *guc)
384 : : {
385 [ # # ]: 0 : struct intel_gt *gt = guc_to_gt(guc);
386 : :
387 [ # # ]: 0 : if (!intel_uc_fw_is_available(&guc->fw))
388 : : return;
389 : :
390 : 0 : i915_ggtt_disable_guc(gt->ggtt);
391 : :
392 [ # # ]: 0 : if (intel_guc_is_submission_supported(guc))
393 : 0 : intel_guc_submission_fini(guc);
394 : :
395 : 0 : intel_guc_ct_fini(&guc->ct);
396 : :
397 : 0 : intel_guc_ads_destroy(guc);
398 : 0 : intel_guc_log_destroy(&guc->log);
399 : 0 : intel_uc_fw_fini(&guc->fw);
400 : 0 : intel_uc_fw_cleanup_fetch(&guc->fw);
401 : :
402 : 0 : intel_uc_fw_change_status(&guc->fw, INTEL_UC_FIRMWARE_DISABLED);
403 : : }
404 : :
405 : : /*
406 : : * This function implements the MMIO based host to GuC interface.
407 : : */
408 : 0 : int intel_guc_send_mmio(struct intel_guc *guc, const u32 *action, u32 len,
409 : : u32 *response_buf, u32 response_buf_size)
410 : : {
411 : 0 : struct intel_uncore *uncore = guc_to_gt(guc)->uncore;
412 : 0 : u32 status;
413 : 0 : int i;
414 : 0 : int ret;
415 : :
416 : 0 : GEM_BUG_ON(!len);
417 : 0 : GEM_BUG_ON(len > guc->send_regs.count);
418 : :
419 : : /* We expect only action code */
420 : 0 : GEM_BUG_ON(*action & ~INTEL_GUC_MSG_CODE_MASK);
421 : :
422 : : /* If CT is available, we expect to use MMIO only during init/fini */
423 : 0 : GEM_BUG_ON(*action != INTEL_GUC_ACTION_REGISTER_COMMAND_TRANSPORT_BUFFER &&
424 : : *action != INTEL_GUC_ACTION_DEREGISTER_COMMAND_TRANSPORT_BUFFER);
425 : :
426 : 0 : mutex_lock(&guc->send_mutex);
427 : 0 : intel_uncore_forcewake_get(uncore, guc->send_regs.fw_domains);
428 : :
429 [ # # ]: 0 : for (i = 0; i < len; i++)
430 : 0 : intel_uncore_write(uncore, guc_send_reg(guc, i), action[i]);
431 : :
432 : 0 : intel_uncore_posting_read(uncore, guc_send_reg(guc, i - 1));
433 : :
434 : 0 : intel_guc_notify(guc);
435 : :
436 : : /*
437 : : * No GuC command should ever take longer than 10ms.
438 : : * Fast commands should still complete in 10us.
439 : : */
440 : 0 : ret = __intel_wait_for_register_fw(uncore,
441 : : guc_send_reg(guc, 0),
442 : : INTEL_GUC_MSG_TYPE_MASK,
443 : : INTEL_GUC_MSG_TYPE_RESPONSE <<
444 : : INTEL_GUC_MSG_TYPE_SHIFT,
445 : : 10, 10, &status);
446 : : /* If GuC explicitly returned an error, convert it to -EIO */
447 [ # # # # ]: 0 : if (!ret && !INTEL_GUC_MSG_IS_RESPONSE_SUCCESS(status))
448 : : ret = -EIO;
449 : :
450 [ # # ]: 0 : if (ret) {
451 : 0 : DRM_ERROR("MMIO: GuC action %#x failed with error %d %#x\n",
452 : : action[0], ret, status);
453 : 0 : goto out;
454 : : }
455 : :
456 [ # # ]: 0 : if (response_buf) {
457 : 0 : int count = min(response_buf_size, guc->send_regs.count - 1);
458 : :
459 [ # # ]: 0 : for (i = 0; i < count; i++)
460 : 0 : response_buf[i] = intel_uncore_read(uncore,
461 : 0 : guc_send_reg(guc, i + 1));
462 : : }
463 : :
464 : : /* Use data from the GuC response as our return value */
465 : 0 : ret = INTEL_GUC_MSG_TO_DATA(status);
466 : :
467 : 0 : out:
468 : 0 : intel_uncore_forcewake_put(uncore, guc->send_regs.fw_domains);
469 : 0 : mutex_unlock(&guc->send_mutex);
470 : :
471 : 0 : return ret;
472 : : }
473 : :
474 : 0 : int intel_guc_to_host_process_recv_msg(struct intel_guc *guc,
475 : : const u32 *payload, u32 len)
476 : : {
477 : 0 : u32 msg;
478 : :
479 [ # # ]: 0 : if (unlikely(!len))
480 : : return -EPROTO;
481 : :
482 : : /* Make sure to handle only enabled messages */
483 : 0 : msg = payload[0] & guc->msg_enabled_mask;
484 : :
485 [ # # ]: 0 : if (msg & (INTEL_GUC_RECV_MSG_FLUSH_LOG_BUFFER |
486 : : INTEL_GUC_RECV_MSG_CRASH_DUMP_POSTED))
487 : 0 : intel_guc_log_handle_flush_event(&guc->log);
488 : :
489 : : return 0;
490 : : }
491 : :
492 : 0 : int intel_guc_sample_forcewake(struct intel_guc *guc)
493 : : {
494 [ # # ]: 0 : struct drm_i915_private *dev_priv = guc_to_gt(guc)->i915;
495 : 0 : u32 action[2];
496 : :
497 : 0 : action[0] = INTEL_GUC_ACTION_SAMPLE_FORCEWAKE;
498 : : /* WaRsDisableCoarsePowerGating:skl,cnl */
499 [ # # # # : 0 : if (!HAS_RC6(dev_priv) || NEEDS_WaRsDisableCoarsePowerGating(dev_priv))
# # # # #
# # # ]
500 : 0 : action[1] = 0;
501 : : else
502 : : /* bit 0 and 1 are for Render and Media domain separately */
503 : 0 : action[1] = GUC_FORCEWAKE_RENDER | GUC_FORCEWAKE_MEDIA;
504 : :
505 : 0 : return intel_guc_send(guc, action, ARRAY_SIZE(action));
506 : : }
507 : :
508 : : /**
509 : : * intel_guc_auth_huc() - Send action to GuC to authenticate HuC ucode
510 : : * @guc: intel_guc structure
511 : : * @rsa_offset: rsa offset w.r.t ggtt base of huc vma
512 : : *
513 : : * Triggers a HuC firmware authentication request to the GuC via intel_guc_send
514 : : * INTEL_GUC_ACTION_AUTHENTICATE_HUC interface. This function is invoked by
515 : : * intel_huc_auth().
516 : : *
517 : : * Return: non-zero code on error
518 : : */
519 : 0 : int intel_guc_auth_huc(struct intel_guc *guc, u32 rsa_offset)
520 : : {
521 : 0 : u32 action[] = {
522 : : INTEL_GUC_ACTION_AUTHENTICATE_HUC,
523 : : rsa_offset
524 : : };
525 : :
526 : 0 : return intel_guc_send(guc, action, ARRAY_SIZE(action));
527 : : }
528 : :
529 : : /**
530 : : * intel_guc_suspend() - notify GuC entering suspend state
531 : : * @guc: the guc
532 : : */
533 : 0 : int intel_guc_suspend(struct intel_guc *guc)
534 : : {
535 [ # # ]: 0 : struct intel_uncore *uncore = guc_to_gt(guc)->uncore;
536 : 0 : int ret;
537 : 0 : u32 status;
538 : 0 : u32 action[] = {
539 : : INTEL_GUC_ACTION_ENTER_S_STATE,
540 : : GUC_POWER_D1, /* any value greater than GUC_POWER_D0 */
541 : : };
542 : :
543 : : /*
544 : : * If GuC communication is enabled but submission is not supported,
545 : : * we do not need to suspend the GuC.
546 : : */
547 [ # # # # ]: 0 : if (!intel_guc_submission_is_enabled(guc))
548 : : return 0;
549 : :
550 : : /*
551 : : * The ENTER_S_STATE action queues the save/restore operation in GuC FW
552 : : * and then returns, so waiting on the H2G is not enough to guarantee
553 : : * GuC is done. When all the processing is done, GuC writes
554 : : * INTEL_GUC_SLEEP_STATE_SUCCESS to scratch register 14, so we can poll
555 : : * on that. Note that GuC does not ensure that the value in the register
556 : : * is different from INTEL_GUC_SLEEP_STATE_SUCCESS while the action is
557 : : * in progress so we need to take care of that ourselves as well.
558 : : */
559 : :
560 : 0 : intel_uncore_write(uncore, SOFT_SCRATCH(14),
561 : : INTEL_GUC_SLEEP_STATE_INVALID_MASK);
562 : :
563 : 0 : ret = intel_guc_send(guc, action, ARRAY_SIZE(action));
564 [ # # ]: 0 : if (ret)
565 : : return ret;
566 : :
567 : 0 : ret = __intel_wait_for_register(uncore, SOFT_SCRATCH(14),
568 : : INTEL_GUC_SLEEP_STATE_INVALID_MASK,
569 : : 0, 0, 10, &status);
570 [ # # ]: 0 : if (ret)
571 : : return ret;
572 : :
573 [ # # ]: 0 : if (status != INTEL_GUC_SLEEP_STATE_SUCCESS) {
574 : 0 : DRM_ERROR("GuC failed to change sleep state. "
575 : : "action=0x%x, err=%u\n",
576 : : action[0], status);
577 : 0 : return -EIO;
578 : : }
579 : :
580 : : return 0;
581 : : }
582 : :
583 : : /**
584 : : * intel_guc_reset_engine() - ask GuC to reset an engine
585 : : * @guc: intel_guc structure
586 : : * @engine: engine to be reset
587 : : */
588 : 0 : int intel_guc_reset_engine(struct intel_guc *guc,
589 : : struct intel_engine_cs *engine)
590 : : {
591 : : /* XXX: to be implemented with submission interface rework */
592 : :
593 : 0 : return -ENODEV;
594 : : }
595 : :
596 : : /**
597 : : * intel_guc_resume() - notify GuC resuming from suspend state
598 : : * @guc: the guc
599 : : */
600 : 0 : int intel_guc_resume(struct intel_guc *guc)
601 : : {
602 : 0 : u32 action[] = {
603 : : INTEL_GUC_ACTION_EXIT_S_STATE,
604 : : GUC_POWER_D0,
605 : : };
606 : :
607 : : /*
608 : : * If GuC communication is enabled but submission is not supported,
609 : : * we do not need to resume the GuC but we do need to enable the
610 : : * GuC communication on resume (above).
611 : : */
612 [ # # # # ]: 0 : if (!intel_guc_submission_is_enabled(guc))
613 : : return 0;
614 : :
615 : 0 : return intel_guc_send(guc, action, ARRAY_SIZE(action));
616 : : }
617 : :
618 : : /**
619 : : * DOC: GuC Memory Management
620 : : *
621 : : * GuC can't allocate any memory for its own usage, so all the allocations must
622 : : * be handled by the host driver. GuC accesses the memory via the GGTT, with the
623 : : * exception of the top and bottom parts of the 4GB address space, which are
624 : : * instead re-mapped by the GuC HW to memory location of the FW itself (WOPCM)
625 : : * or other parts of the HW. The driver must take care not to place objects that
626 : : * the GuC is going to access in these reserved ranges. The layout of the GuC
627 : : * address space is shown below:
628 : : *
629 : : * ::
630 : : *
631 : : * +===========> +====================+ <== FFFF_FFFF
632 : : * ^ | Reserved |
633 : : * | +====================+ <== GUC_GGTT_TOP
634 : : * | | |
635 : : * | | DRAM |
636 : : * GuC | |
637 : : * Address +===> +====================+ <== GuC ggtt_pin_bias
638 : : * Space ^ | |
639 : : * | | | |
640 : : * | GuC | GuC |
641 : : * | WOPCM | WOPCM |
642 : : * | Size | |
643 : : * | | | |
644 : : * v v | |
645 : : * +=======+===> +====================+ <== 0000_0000
646 : : *
647 : : * The lower part of GuC Address Space [0, ggtt_pin_bias) is mapped to GuC WOPCM
648 : : * while upper part of GuC Address Space [ggtt_pin_bias, GUC_GGTT_TOP) is mapped
649 : : * to DRAM. The value of the GuC ggtt_pin_bias is the GuC WOPCM size.
650 : : */
651 : :
652 : : /**
653 : : * intel_guc_allocate_vma() - Allocate a GGTT VMA for GuC usage
654 : : * @guc: the guc
655 : : * @size: size of area to allocate (both virtual space and memory)
656 : : *
657 : : * This is a wrapper to create an object for use with the GuC. In order to
658 : : * use it inside the GuC, an object needs to be pinned lifetime, so we allocate
659 : : * both some backing storage and a range inside the Global GTT. We must pin
660 : : * it in the GGTT somewhere other than than [0, GUC ggtt_pin_bias) because that
661 : : * range is reserved inside GuC.
662 : : *
663 : : * Return: A i915_vma if successful, otherwise an ERR_PTR.
664 : : */
665 : 0 : struct i915_vma *intel_guc_allocate_vma(struct intel_guc *guc, u32 size)
666 : : {
667 : 0 : struct intel_gt *gt = guc_to_gt(guc);
668 : 0 : struct drm_i915_gem_object *obj;
669 : 0 : struct i915_vma *vma;
670 : 0 : u64 flags;
671 : 0 : int ret;
672 : :
673 : 0 : obj = i915_gem_object_create_shmem(gt->i915, size);
674 [ # # ]: 0 : if (IS_ERR(obj))
675 : : return ERR_CAST(obj);
676 : :
677 : 0 : vma = i915_vma_instance(obj, >->ggtt->vm, NULL);
678 [ # # ]: 0 : if (IS_ERR(vma))
679 : 0 : goto err;
680 : :
681 : 0 : flags = PIN_GLOBAL | PIN_OFFSET_BIAS | i915_ggtt_pin_bias(vma);
682 : 0 : ret = i915_vma_pin(vma, 0, 0, flags);
683 [ # # ]: 0 : if (ret) {
684 : 0 : vma = ERR_PTR(ret);
685 : 0 : goto err;
686 : : }
687 : :
688 : 0 : return i915_vma_make_unshrinkable(vma);
689 : :
690 : 0 : err:
691 : 0 : i915_gem_object_put(obj);
692 : 0 : return vma;
693 : : }
694 : :
695 : : /**
696 : : * intel_guc_allocate_and_map_vma() - Allocate and map VMA for GuC usage
697 : : * @guc: the guc
698 : : * @size: size of area to allocate (both virtual space and memory)
699 : : * @out_vma: return variable for the allocated vma pointer
700 : : * @out_vaddr: return variable for the obj mapping
701 : : *
702 : : * This wrapper calls intel_guc_allocate_vma() and then maps the allocated
703 : : * object with I915_MAP_WB.
704 : : *
705 : : * Return: 0 if successful, a negative errno code otherwise.
706 : : */
707 : 0 : int intel_guc_allocate_and_map_vma(struct intel_guc *guc, u32 size,
708 : : struct i915_vma **out_vma, void **out_vaddr)
709 : : {
710 : 0 : struct i915_vma *vma;
711 : 0 : void *vaddr;
712 : :
713 : 0 : vma = intel_guc_allocate_vma(guc, size);
714 [ # # ]: 0 : if (IS_ERR(vma))
715 : 0 : return PTR_ERR(vma);
716 : :
717 : 0 : vaddr = i915_gem_object_pin_map(vma->obj, I915_MAP_WB);
718 [ # # ]: 0 : if (IS_ERR(vaddr)) {
719 : 0 : i915_vma_unpin_and_release(&vma, 0);
720 : 0 : return PTR_ERR(vaddr);
721 : : }
722 : :
723 : 0 : *out_vma = vma;
724 : 0 : *out_vaddr = vaddr;
725 : :
726 : 0 : return 0;
727 : : }
|