1 // SPDX-License-Identifier: MIT
2 /*
3 * Copyright © 2022 Intel Corporation
4 */
5
6 #include "gem/i915_gem_lmem.h"
7 #include "gt/intel_engine_pm.h"
8 #include "gt/intel_gpu_commands.h"
9 #include "gt/intel_gt.h"
10 #include "gt/intel_gt_print.h"
11 #include "gt/intel_ring.h"
12 #include "intel_gsc_binary_headers.h"
13 #include "intel_gsc_fw.h"
14 #include "intel_gsc_uc_heci_cmd_submit.h"
15 #include "i915_reg.h"
16
gsc_is_in_reset(struct intel_uncore * uncore)17 static bool gsc_is_in_reset(struct intel_uncore *uncore)
18 {
19 u32 fw_status = intel_uncore_read(uncore, HECI_FWSTS(MTL_GSC_HECI1_BASE, 1));
20
21 return REG_FIELD_GET(HECI1_FWSTS1_CURRENT_STATE, fw_status) ==
22 HECI1_FWSTS1_CURRENT_STATE_RESET;
23 }
24
gsc_uc_get_fw_status(struct intel_uncore * uncore,bool needs_wakeref)25 static u32 gsc_uc_get_fw_status(struct intel_uncore *uncore, bool needs_wakeref)
26 {
27 intel_wakeref_t wakeref;
28 u32 fw_status = 0;
29
30 if (needs_wakeref)
31 wakeref = intel_runtime_pm_get(uncore->rpm);
32
33 fw_status = intel_uncore_read(uncore, HECI_FWSTS(MTL_GSC_HECI1_BASE, 1));
34
35 if (needs_wakeref)
36 intel_runtime_pm_put(uncore->rpm, wakeref);
37 return fw_status;
38 }
39
intel_gsc_uc_fw_proxy_init_done(struct intel_gsc_uc * gsc,bool needs_wakeref)40 bool intel_gsc_uc_fw_proxy_init_done(struct intel_gsc_uc *gsc, bool needs_wakeref)
41 {
42 return REG_FIELD_GET(HECI1_FWSTS1_CURRENT_STATE,
43 gsc_uc_get_fw_status(gsc_uc_to_gt(gsc)->uncore,
44 needs_wakeref)) ==
45 HECI1_FWSTS1_PROXY_STATE_NORMAL;
46 }
47
intel_gsc_uc_fw_proxy_get_status(struct intel_gsc_uc * gsc)48 int intel_gsc_uc_fw_proxy_get_status(struct intel_gsc_uc *gsc)
49 {
50 if (!(IS_ENABLED(CONFIG_INTEL_MEI_GSC_PROXY)))
51 return -ENODEV;
52 if (!intel_uc_fw_is_loadable(&gsc->fw))
53 return -ENODEV;
54 if (__intel_uc_fw_status(&gsc->fw) == INTEL_UC_FIRMWARE_LOAD_FAIL)
55 return -ENOLINK;
56 if (!intel_gsc_uc_fw_proxy_init_done(gsc, true))
57 return -EAGAIN;
58
59 return 0;
60 }
61
intel_gsc_uc_fw_init_done(struct intel_gsc_uc * gsc)62 bool intel_gsc_uc_fw_init_done(struct intel_gsc_uc *gsc)
63 {
64 return gsc_uc_get_fw_status(gsc_uc_to_gt(gsc)->uncore, false) &
65 HECI1_FWSTS1_INIT_COMPLETE;
66 }
67
cpd_entry_offset(const struct intel_gsc_cpd_entry * entry)68 static inline u32 cpd_entry_offset(const struct intel_gsc_cpd_entry *entry)
69 {
70 return entry->offset & INTEL_GSC_CPD_ENTRY_OFFSET_MASK;
71 }
72
intel_gsc_fw_get_binary_info(struct intel_uc_fw * gsc_fw,const void * data,size_t size)73 int intel_gsc_fw_get_binary_info(struct intel_uc_fw *gsc_fw, const void *data, size_t size)
74 {
75 struct intel_gsc_uc *gsc = container_of(gsc_fw, struct intel_gsc_uc, fw);
76 struct intel_gt *gt = gsc_uc_to_gt(gsc);
77 const struct intel_gsc_layout_pointers *layout = data;
78 const struct intel_gsc_bpdt_header *bpdt_header = NULL;
79 const struct intel_gsc_bpdt_entry *bpdt_entry = NULL;
80 const struct intel_gsc_cpd_header_v2 *cpd_header = NULL;
81 const struct intel_gsc_cpd_entry *cpd_entry = NULL;
82 const struct intel_gsc_manifest_header *manifest;
83 struct intel_uc_fw_ver min_ver = { 0 };
84 size_t min_size = sizeof(*layout);
85 int i;
86
87 if (size < min_size) {
88 gt_err(gt, "GSC FW too small! %zu < %zu\n", size, min_size);
89 return -ENODATA;
90 }
91
92 /*
93 * The GSC binary starts with the pointer layout, which contains the
94 * locations of the various partitions of the binary. The one we're
95 * interested in to get the version is the boot1 partition, where we can
96 * find a BPDT header followed by entries, one of which points to the
97 * RBE sub-section of the partition. From here, we can parse the CPD
98 * header and the following entries to find the manifest location
99 * (entry identified by the "RBEP.man" name), from which we can finally
100 * extract the version.
101 *
102 * --------------------------------------------------
103 * [ intel_gsc_layout_pointers ]
104 * [ ... ]
105 * [ boot1.offset >---------------------------]------o
106 * [ ... ] |
107 * -------------------------------------------------- |
108 * |
109 * -------------------------------------------------- |
110 * [ intel_gsc_bpdt_header ]<-----o
111 * --------------------------------------------------
112 * [ intel_gsc_bpdt_entry[] ]
113 * [ entry1 ]
114 * [ ... ]
115 * [ entryX ]
116 * [ type == GSC_RBE ]
117 * [ offset >-----------------------------]------o
118 * [ ... ] |
119 * -------------------------------------------------- |
120 * |
121 * -------------------------------------------------- |
122 * [ intel_gsc_cpd_header_v2 ]<-----o
123 * --------------------------------------------------
124 * [ intel_gsc_cpd_entry[] ]
125 * [ entry1 ]
126 * [ ... ]
127 * [ entryX ]
128 * [ "RBEP.man" ]
129 * [ ... ]
130 * [ offset >----------------------------]------o
131 * [ ... ] |
132 * -------------------------------------------------- |
133 * |
134 * -------------------------------------------------- |
135 * [ intel_gsc_manifest_header ]<-----o
136 * [ ... ]
137 * [ intel_gsc_version fw_version ]
138 * [ ... ]
139 * --------------------------------------------------
140 */
141
142 min_size = layout->boot1.offset + layout->boot1.size;
143 if (size < min_size) {
144 gt_err(gt, "GSC FW too small for boot section! %zu < %zu\n",
145 size, min_size);
146 return -ENODATA;
147 }
148
149 min_size = sizeof(*bpdt_header);
150 if (layout->boot1.size < min_size) {
151 gt_err(gt, "GSC FW boot section too small for BPDT header: %u < %zu\n",
152 layout->boot1.size, min_size);
153 return -ENODATA;
154 }
155
156 bpdt_header = data + layout->boot1.offset;
157 if (bpdt_header->signature != INTEL_GSC_BPDT_HEADER_SIGNATURE) {
158 gt_err(gt, "invalid signature for BPDT header: 0x%08x!\n",
159 bpdt_header->signature);
160 return -EINVAL;
161 }
162
163 min_size += sizeof(*bpdt_entry) * bpdt_header->descriptor_count;
164 if (layout->boot1.size < min_size) {
165 gt_err(gt, "GSC FW boot section too small for BPDT entries: %u < %zu\n",
166 layout->boot1.size, min_size);
167 return -ENODATA;
168 }
169
170 bpdt_entry = (void *)bpdt_header + sizeof(*bpdt_header);
171 for (i = 0; i < bpdt_header->descriptor_count; i++, bpdt_entry++) {
172 if ((bpdt_entry->type & INTEL_GSC_BPDT_ENTRY_TYPE_MASK) !=
173 INTEL_GSC_BPDT_ENTRY_TYPE_GSC_RBE)
174 continue;
175
176 cpd_header = (void *)bpdt_header + bpdt_entry->sub_partition_offset;
177 min_size = bpdt_entry->sub_partition_offset + sizeof(*cpd_header);
178 break;
179 }
180
181 if (!cpd_header) {
182 gt_err(gt, "couldn't find CPD header in GSC binary!\n");
183 return -ENODATA;
184 }
185
186 if (layout->boot1.size < min_size) {
187 gt_err(gt, "GSC FW boot section too small for CPD header: %u < %zu\n",
188 layout->boot1.size, min_size);
189 return -ENODATA;
190 }
191
192 if (cpd_header->header_marker != INTEL_GSC_CPD_HEADER_MARKER) {
193 gt_err(gt, "invalid marker for CPD header in GSC bin: 0x%08x!\n",
194 cpd_header->header_marker);
195 return -EINVAL;
196 }
197
198 min_size += sizeof(*cpd_entry) * cpd_header->num_of_entries;
199 if (layout->boot1.size < min_size) {
200 gt_err(gt, "GSC FW boot section too small for CPD entries: %u < %zu\n",
201 layout->boot1.size, min_size);
202 return -ENODATA;
203 }
204
205 cpd_entry = (void *)cpd_header + cpd_header->header_length;
206 for (i = 0; i < cpd_header->num_of_entries; i++, cpd_entry++) {
207 if (strcmp(cpd_entry->name, "RBEP.man") == 0) {
208 manifest = (void *)cpd_header + cpd_entry_offset(cpd_entry);
209 intel_uc_fw_version_from_gsc_manifest(&gsc->release,
210 manifest);
211 gsc->security_version = manifest->security_version;
212 break;
213 }
214 }
215
216 /*
217 * ARL SKUs require newer firmwares, but the blob is actually common
218 * across all MTL and ARL SKUs, so we need to do an explicit version check
219 * here rather than using a separate table entry. If a too old version
220 * is found, then just don't use GSC rather than aborting the driver load.
221 * Note that the major number in the GSC FW version is used to indicate
222 * the platform, so we expect it to always be 102 for MTL/ARL binaries.
223 */
224 if (IS_ARROWLAKE_S(gt->i915))
225 min_ver = (struct intel_uc_fw_ver){ 102, 0, 10, 1878 };
226 else if (IS_ARROWLAKE_H(gt->i915) || IS_ARROWLAKE_U(gt->i915))
227 min_ver = (struct intel_uc_fw_ver){ 102, 1, 15, 1926 };
228
229 if (IS_METEORLAKE(gt->i915) && gsc->release.major != 102) {
230 gt_info(gt, "Invalid GSC firmware for MTL/ARL, got %d.%d.%d.%d but need 102.x.x.x",
231 gsc->release.major, gsc->release.minor,
232 gsc->release.patch, gsc->release.build);
233 return -EINVAL;
234 }
235
236 if (min_ver.major) {
237 bool too_old = false;
238
239 if (gsc->release.minor < min_ver.minor) {
240 too_old = true;
241 } else if (gsc->release.minor == min_ver.minor) {
242 if (gsc->release.patch < min_ver.patch) {
243 too_old = true;
244 } else if (gsc->release.patch == min_ver.patch) {
245 if (gsc->release.build < min_ver.build)
246 too_old = true;
247 }
248 }
249
250 if (too_old) {
251 gt_info(gt, "GSC firmware too old for ARL, got %d.%d.%d.%d but need at least %d.%d.%d.%d",
252 gsc->release.major, gsc->release.minor,
253 gsc->release.patch, gsc->release.build,
254 min_ver.major, min_ver.minor,
255 min_ver.patch, min_ver.build);
256 return -EINVAL;
257 }
258 }
259
260 return 0;
261 }
262
emit_gsc_fw_load(struct i915_request * rq,struct intel_gsc_uc * gsc)263 static int emit_gsc_fw_load(struct i915_request *rq, struct intel_gsc_uc *gsc)
264 {
265 u32 offset = i915_ggtt_offset(gsc->local);
266 u32 *cs;
267
268 cs = intel_ring_begin(rq, 4);
269 if (IS_ERR(cs))
270 return PTR_ERR(cs);
271
272 *cs++ = GSC_FW_LOAD;
273 *cs++ = lower_32_bits(offset);
274 *cs++ = upper_32_bits(offset);
275 *cs++ = (gsc->local->size / SZ_4K) | HECI1_FW_LIMIT_VALID;
276
277 intel_ring_advance(rq, cs);
278
279 return 0;
280 }
281
gsc_fw_load(struct intel_gsc_uc * gsc)282 static int gsc_fw_load(struct intel_gsc_uc *gsc)
283 {
284 struct intel_context *ce = gsc->ce;
285 struct i915_request *rq;
286 int err;
287
288 if (!ce)
289 return -ENODEV;
290
291 rq = i915_request_create(ce);
292 if (IS_ERR(rq))
293 return PTR_ERR(rq);
294
295 if (ce->engine->emit_init_breadcrumb) {
296 err = ce->engine->emit_init_breadcrumb(rq);
297 if (err)
298 goto out_rq;
299 }
300
301 err = emit_gsc_fw_load(rq, gsc);
302 if (err)
303 goto out_rq;
304
305 err = ce->engine->emit_flush(rq, 0);
306
307 out_rq:
308 i915_request_get(rq);
309
310 if (unlikely(err))
311 i915_request_set_error_once(rq, err);
312
313 i915_request_add(rq);
314
315 if (!err && i915_request_wait(rq, 0, msecs_to_jiffies(500)) < 0)
316 err = -ETIME;
317
318 i915_request_put(rq);
319
320 if (err)
321 gt_err(gsc_uc_to_gt(gsc), "Request submission for GSC load failed %pe\n",
322 ERR_PTR(err));
323
324 return err;
325 }
326
gsc_fw_load_prepare(struct intel_gsc_uc * gsc)327 static int gsc_fw_load_prepare(struct intel_gsc_uc *gsc)
328 {
329 struct intel_gt *gt = gsc_uc_to_gt(gsc);
330 void *src;
331
332 if (!gsc->local)
333 return -ENODEV;
334
335 if (gsc->local->size < gsc->fw.size)
336 return -ENOSPC;
337
338 src = i915_gem_object_pin_map_unlocked(gsc->fw.obj,
339 intel_gt_coherent_map_type(gt, gsc->fw.obj, true));
340 if (IS_ERR(src))
341 return PTR_ERR(src);
342
343 memcpy_toio(gsc->local_vaddr, src, gsc->fw.size);
344 memset_io(gsc->local_vaddr + gsc->fw.size, 0, gsc->local->size - gsc->fw.size);
345
346 intel_guc_write_barrier(gt_to_guc(gt));
347
348 i915_gem_object_unpin_map(gsc->fw.obj);
349
350 return 0;
351 }
352
gsc_fw_wait(struct intel_gt * gt)353 static int gsc_fw_wait(struct intel_gt *gt)
354 {
355 return intel_wait_for_register(gt->uncore,
356 HECI_FWSTS(MTL_GSC_HECI1_BASE, 1),
357 HECI1_FWSTS1_INIT_COMPLETE,
358 HECI1_FWSTS1_INIT_COMPLETE,
359 500);
360 }
361
362 struct intel_gsc_mkhi_header {
363 u8 group_id;
364 #define MKHI_GROUP_ID_GFX_SRV 0x30
365
366 u8 command;
367 #define MKHI_GFX_SRV_GET_HOST_COMPATIBILITY_VERSION (0x42)
368
369 u8 reserved;
370 u8 result;
371 } __packed;
372
373 struct mtl_gsc_ver_msg_in {
374 struct intel_gsc_mtl_header header;
375 struct intel_gsc_mkhi_header mkhi;
376 } __packed;
377
378 struct mtl_gsc_ver_msg_out {
379 struct intel_gsc_mtl_header header;
380 struct intel_gsc_mkhi_header mkhi;
381 u16 proj_major;
382 u16 compat_major;
383 u16 compat_minor;
384 u16 reserved[5];
385 } __packed;
386
387 #define GSC_VER_PKT_SZ SZ_4K
388
gsc_fw_query_compatibility_version(struct intel_gsc_uc * gsc)389 static int gsc_fw_query_compatibility_version(struct intel_gsc_uc *gsc)
390 {
391 struct intel_gt *gt = gsc_uc_to_gt(gsc);
392 struct mtl_gsc_ver_msg_in *msg_in;
393 struct mtl_gsc_ver_msg_out *msg_out;
394 struct i915_vma *vma;
395 u64 offset;
396 void *vaddr;
397 int err;
398
399 err = intel_guc_allocate_and_map_vma(gt_to_guc(gt), GSC_VER_PKT_SZ * 2,
400 &vma, &vaddr);
401 if (err) {
402 gt_err(gt, "failed to allocate vma for GSC version query\n");
403 return err;
404 }
405
406 offset = i915_ggtt_offset(vma);
407 msg_in = vaddr;
408 msg_out = vaddr + GSC_VER_PKT_SZ;
409
410 intel_gsc_uc_heci_cmd_emit_mtl_header(&msg_in->header,
411 HECI_MEADDRESS_MKHI,
412 sizeof(*msg_in), 0);
413 msg_in->mkhi.group_id = MKHI_GROUP_ID_GFX_SRV;
414 msg_in->mkhi.command = MKHI_GFX_SRV_GET_HOST_COMPATIBILITY_VERSION;
415
416 err = intel_gsc_uc_heci_cmd_submit_packet(>->uc.gsc,
417 offset,
418 sizeof(*msg_in),
419 offset + GSC_VER_PKT_SZ,
420 GSC_VER_PKT_SZ);
421 if (err) {
422 gt_err(gt,
423 "failed to submit GSC request for compatibility version: %d\n",
424 err);
425 goto out_vma;
426 }
427
428 if (msg_out->header.message_size != sizeof(*msg_out)) {
429 gt_err(gt, "invalid GSC reply length %u [expected %zu], s=0x%x, f=0x%x, r=0x%x\n",
430 msg_out->header.message_size, sizeof(*msg_out),
431 msg_out->header.status, msg_out->header.flags, msg_out->mkhi.result);
432 err = -EPROTO;
433 goto out_vma;
434 }
435
436 gsc->fw.file_selected.ver.major = msg_out->compat_major;
437 gsc->fw.file_selected.ver.minor = msg_out->compat_minor;
438
439 out_vma:
440 i915_vma_unpin_and_release(&vma, I915_VMA_RELEASE_MAP);
441 return err;
442 }
443
intel_gsc_uc_fw_upload(struct intel_gsc_uc * gsc)444 int intel_gsc_uc_fw_upload(struct intel_gsc_uc *gsc)
445 {
446 struct intel_gt *gt = gsc_uc_to_gt(gsc);
447 struct intel_uc_fw *gsc_fw = &gsc->fw;
448 int err;
449
450 /* check current fw status */
451 if (intel_gsc_uc_fw_init_done(gsc)) {
452 if (GEM_WARN_ON(!intel_uc_fw_is_loaded(gsc_fw)))
453 intel_uc_fw_change_status(gsc_fw, INTEL_UC_FIRMWARE_TRANSFERRED);
454 return -EEXIST;
455 }
456
457 if (!intel_uc_fw_is_loadable(gsc_fw))
458 return -ENOEXEC;
459
460 /* FW blob is ok, so clean the status */
461 intel_uc_fw_sanitize(&gsc->fw);
462
463 if (!gsc_is_in_reset(gt->uncore))
464 return -EIO;
465
466 err = gsc_fw_load_prepare(gsc);
467 if (err)
468 goto fail;
469
470 /*
471 * GSC is only killed by an FLR, so we need to trigger one on unload to
472 * make sure we stop it. This is because we assign a chunk of memory to
473 * the GSC as part of the FW load , so we need to make sure it stops
474 * using it when we release it to the system on driver unload. Note that
475 * this is not a problem of the unload per-se, because the GSC will not
476 * touch that memory unless there are requests for it coming from the
477 * driver; therefore, no accesses will happen while i915 is not loaded,
478 * but if we re-load the driver then the GSC might wake up and try to
479 * access that old memory location again.
480 * Given that an FLR is a very disruptive action (see the FLR function
481 * for details), we want to do it as the last action before releasing
482 * the access to the MMIO bar, which means we need to do it as part of
483 * the primary uncore cleanup.
484 * An alternative approach to the FLR would be to use a memory location
485 * that survives driver unload, like e.g. stolen memory, and keep the
486 * GSC loaded across reloads. However, this requires us to make sure we
487 * preserve that memory location on unload and then determine and
488 * reserve its offset on each subsequent load, which is not trivial, so
489 * it is easier to just kill everything and start fresh.
490 */
491 intel_uncore_set_flr_on_fini(>->i915->uncore);
492
493 err = gsc_fw_load(gsc);
494 if (err)
495 goto fail;
496
497 err = gsc_fw_wait(gt);
498 if (err)
499 goto fail;
500
501 err = gsc_fw_query_compatibility_version(gsc);
502 if (err)
503 goto fail;
504
505 /* we only support compatibility version 1.0 at the moment */
506 err = intel_uc_check_file_version(gsc_fw, NULL);
507 if (err)
508 goto fail;
509
510 /* FW is not fully operational until we enable SW proxy */
511 intel_uc_fw_change_status(gsc_fw, INTEL_UC_FIRMWARE_TRANSFERRED);
512
513 gt_info(gt, "Loaded GSC firmware %s (cv%u.%u, r%u.%u.%u.%u, svn %u)\n",
514 gsc_fw->file_selected.path,
515 gsc_fw->file_selected.ver.major, gsc_fw->file_selected.ver.minor,
516 gsc->release.major, gsc->release.minor,
517 gsc->release.patch, gsc->release.build,
518 gsc->security_version);
519
520 return 0;
521
522 fail:
523 return intel_uc_fw_mark_load_failed(gsc_fw, err);
524 }
525