Linux Audio

Check our new training course

Linux debugging, profiling, tracing and performance analysis training

Apr 14-17, 2025
Register
Loading...
Note: File does not exist in v3.1.
  1// SPDX-License-Identifier: MIT
  2/*
  3 * Copyright © 2016-2019 Intel Corporation
  4 */
  5
  6#include <linux/bitfield.h>
  7#include <linux/firmware.h>
  8#include <drm/drm_print.h>
  9
 10#include "intel_uc_fw.h"
 11#include "intel_uc_fw_abi.h"
 12#include "i915_drv.h"
 13
 14#ifdef CONFIG_DRM_I915_DEBUG_GUC
 15static inline struct intel_gt *__uc_fw_to_gt(struct intel_uc_fw *uc_fw)
 16{
 17	GEM_BUG_ON(uc_fw->status == INTEL_UC_FIRMWARE_UNINITIALIZED);
 18	if (uc_fw->type == INTEL_UC_FW_TYPE_GUC)
 19		return container_of(uc_fw, struct intel_gt, uc.guc.fw);
 20
 21	GEM_BUG_ON(uc_fw->type != INTEL_UC_FW_TYPE_HUC);
 22	return container_of(uc_fw, struct intel_gt, uc.huc.fw);
 23}
 24
 25void intel_uc_fw_change_status(struct intel_uc_fw *uc_fw,
 26			       enum intel_uc_fw_status status)
 27{
 28	uc_fw->__status =  status;
 29	DRM_DEV_DEBUG_DRIVER(__uc_fw_to_gt(uc_fw)->i915->drm.dev,
 30			     "%s firmware -> %s\n",
 31			     intel_uc_fw_type_repr(uc_fw->type),
 32			     status == INTEL_UC_FIRMWARE_SELECTED ?
 33			     uc_fw->path : intel_uc_fw_status_repr(status));
 34}
 35#endif
 36
 37/*
 38 * List of required GuC and HuC binaries per-platform.
 39 * Must be ordered based on platform + revid, from newer to older.
 40 */
 41#define INTEL_UC_FIRMWARE_DEFS(fw_def, guc_def, huc_def) \
 42	fw_def(ICELAKE,    0, guc_def(icl, 33, 0, 0), huc_def(icl,  8,  4, 3238)) \
 43	fw_def(COFFEELAKE, 0, guc_def(kbl, 33, 0, 0), huc_def(kbl, 02, 00, 1810)) \
 44	fw_def(GEMINILAKE, 0, guc_def(glk, 33, 0, 0), huc_def(glk, 03, 01, 2893)) \
 45	fw_def(KABYLAKE,   0, guc_def(kbl, 33, 0, 0), huc_def(kbl, 02, 00, 1810)) \
 46	fw_def(BROXTON,    0, guc_def(bxt, 33, 0, 0), huc_def(bxt, 01,  8, 2893)) \
 47	fw_def(SKYLAKE,    0, guc_def(skl, 33, 0, 0), huc_def(skl, 01, 07, 1398))
 48
 49#define __MAKE_UC_FW_PATH(prefix_, name_, separator_, major_, minor_, patch_) \
 50	"i915/" \
 51	__stringify(prefix_) name_ \
 52	__stringify(major_) separator_ \
 53	__stringify(minor_) separator_ \
 54	__stringify(patch_) ".bin"
 55
 56#define MAKE_GUC_FW_PATH(prefix_, major_, minor_, patch_) \
 57	__MAKE_UC_FW_PATH(prefix_, "_guc_", ".", major_, minor_, patch_)
 58
 59#define MAKE_HUC_FW_PATH(prefix_, major_, minor_, bld_num_) \
 60	__MAKE_UC_FW_PATH(prefix_, "_huc_ver", "_", major_, minor_, bld_num_)
 61
 62/* All blobs need to be declared via MODULE_FIRMWARE() */
 63#define INTEL_UC_MODULE_FW(platform_, revid_, guc_, huc_) \
 64	MODULE_FIRMWARE(guc_); \
 65	MODULE_FIRMWARE(huc_);
 66
 67INTEL_UC_FIRMWARE_DEFS(INTEL_UC_MODULE_FW, MAKE_GUC_FW_PATH, MAKE_HUC_FW_PATH)
 68
 69/* The below structs and macros are used to iterate across the list of blobs */
 70struct __packed uc_fw_blob {
 71	u8 major;
 72	u8 minor;
 73	const char *path;
 74};
 75
 76#define UC_FW_BLOB(major_, minor_, path_) \
 77	{ .major = major_, .minor = minor_, .path = path_ }
 78
 79#define GUC_FW_BLOB(prefix_, major_, minor_, patch_) \
 80	UC_FW_BLOB(major_, minor_, \
 81		   MAKE_GUC_FW_PATH(prefix_, major_, minor_, patch_))
 82
 83#define HUC_FW_BLOB(prefix_, major_, minor_, bld_num_) \
 84	UC_FW_BLOB(major_, minor_, \
 85		   MAKE_HUC_FW_PATH(prefix_, major_, minor_, bld_num_))
 86
 87struct __packed uc_fw_platform_requirement {
 88	enum intel_platform p;
 89	u8 rev; /* first platform rev using this FW */
 90	const struct uc_fw_blob blobs[INTEL_UC_FW_NUM_TYPES];
 91};
 92
 93#define MAKE_FW_LIST(platform_, revid_, guc_, huc_) \
 94{ \
 95	.p = INTEL_##platform_, \
 96	.rev = revid_, \
 97	.blobs[INTEL_UC_FW_TYPE_GUC] = guc_, \
 98	.blobs[INTEL_UC_FW_TYPE_HUC] = huc_, \
 99},
100
101static void
102__uc_fw_auto_select(struct intel_uc_fw *uc_fw, enum intel_platform p, u8 rev)
103{
104	static const struct uc_fw_platform_requirement fw_blobs[] = {
105		INTEL_UC_FIRMWARE_DEFS(MAKE_FW_LIST, GUC_FW_BLOB, HUC_FW_BLOB)
106	};
107	int i;
108
109	for (i = 0; i < ARRAY_SIZE(fw_blobs) && p <= fw_blobs[i].p; i++) {
110		if (p == fw_blobs[i].p && rev >= fw_blobs[i].rev) {
111			const struct uc_fw_blob *blob =
112					&fw_blobs[i].blobs[uc_fw->type];
113			uc_fw->path = blob->path;
114			uc_fw->major_ver_wanted = blob->major;
115			uc_fw->minor_ver_wanted = blob->minor;
116			break;
117		}
118	}
119
120	/* make sure the list is ordered as expected */
121	if (IS_ENABLED(CONFIG_DRM_I915_SELFTEST)) {
122		for (i = 1; i < ARRAY_SIZE(fw_blobs); i++) {
123			if (fw_blobs[i].p < fw_blobs[i - 1].p)
124				continue;
125
126			if (fw_blobs[i].p == fw_blobs[i - 1].p &&
127			    fw_blobs[i].rev < fw_blobs[i - 1].rev)
128				continue;
129
130			pr_err("invalid FW blob order: %s r%u comes before %s r%u\n",
131			       intel_platform_name(fw_blobs[i - 1].p),
132			       fw_blobs[i - 1].rev,
133			       intel_platform_name(fw_blobs[i].p),
134			       fw_blobs[i].rev);
135
136			uc_fw->path = NULL;
137		}
138	}
139
140	/* We don't want to enable GuC/HuC on pre-Gen11 by default */
141	if (i915_modparams.enable_guc == -1 && p < INTEL_ICELAKE)
142		uc_fw->path = NULL;
143}
144
145static const char *__override_guc_firmware_path(void)
146{
147	if (i915_modparams.enable_guc & (ENABLE_GUC_SUBMISSION |
148					 ENABLE_GUC_LOAD_HUC))
149		return i915_modparams.guc_firmware_path;
150	return "";
151}
152
153static const char *__override_huc_firmware_path(void)
154{
155	if (i915_modparams.enable_guc & ENABLE_GUC_LOAD_HUC)
156		return i915_modparams.huc_firmware_path;
157	return "";
158}
159
160static void __uc_fw_user_override(struct intel_uc_fw *uc_fw)
161{
162	const char *path = NULL;
163
164	switch (uc_fw->type) {
165	case INTEL_UC_FW_TYPE_GUC:
166		path = __override_guc_firmware_path();
167		break;
168	case INTEL_UC_FW_TYPE_HUC:
169		path = __override_huc_firmware_path();
170		break;
171	}
172
173	if (unlikely(path)) {
174		uc_fw->path = path;
175		uc_fw->user_overridden = true;
176	}
177}
178
179/**
180 * intel_uc_fw_init_early - initialize the uC object and select the firmware
181 * @uc_fw: uC firmware
182 * @type: type of uC
183 * @supported: is uC support possible
184 * @platform: platform identifier
185 * @rev: hardware revision
186 *
187 * Initialize the state of our uC object and relevant tracking and select the
188 * firmware to fetch and load.
189 */
190void intel_uc_fw_init_early(struct intel_uc_fw *uc_fw,
191			    enum intel_uc_fw_type type, bool supported,
192			    enum intel_platform platform, u8 rev)
193{
194	/*
195	 * we use FIRMWARE_UNINITIALIZED to detect checks against uc_fw->status
196	 * before we're looked at the HW caps to see if we have uc support
197	 */
198	BUILD_BUG_ON(INTEL_UC_FIRMWARE_UNINITIALIZED);
199	GEM_BUG_ON(uc_fw->status);
200	GEM_BUG_ON(uc_fw->path);
201
202	uc_fw->type = type;
203
204	if (supported) {
205		__uc_fw_auto_select(uc_fw, platform, rev);
206		__uc_fw_user_override(uc_fw);
207	}
208
209	intel_uc_fw_change_status(uc_fw, uc_fw->path ? *uc_fw->path ?
210				  INTEL_UC_FIRMWARE_SELECTED :
211				  INTEL_UC_FIRMWARE_DISABLED :
212				  INTEL_UC_FIRMWARE_NOT_SUPPORTED);
213}
214
215static void __force_fw_fetch_failures(struct intel_uc_fw *uc_fw,
216				      struct drm_i915_private *i915,
217				      int e)
218{
219	bool user = e == -EINVAL;
220
221	if (i915_inject_load_error(i915, e)) {
222		/* non-existing blob */
223		uc_fw->path = "<invalid>";
224		uc_fw->user_overridden = user;
225	} else if (i915_inject_load_error(i915, e)) {
226		/* require next major version */
227		uc_fw->major_ver_wanted += 1;
228		uc_fw->minor_ver_wanted = 0;
229		uc_fw->user_overridden = user;
230	} else if (i915_inject_load_error(i915, e)) {
231		/* require next minor version */
232		uc_fw->minor_ver_wanted += 1;
233		uc_fw->user_overridden = user;
234	} else if (uc_fw->major_ver_wanted && i915_inject_load_error(i915, e)) {
235		/* require prev major version */
236		uc_fw->major_ver_wanted -= 1;
237		uc_fw->minor_ver_wanted = 0;
238		uc_fw->user_overridden = user;
239	} else if (uc_fw->minor_ver_wanted && i915_inject_load_error(i915, e)) {
240		/* require prev minor version - hey, this should work! */
241		uc_fw->minor_ver_wanted -= 1;
242		uc_fw->user_overridden = user;
243	} else if (user && i915_inject_load_error(i915, e)) {
244		/* officially unsupported platform */
245		uc_fw->major_ver_wanted = 0;
246		uc_fw->minor_ver_wanted = 0;
247		uc_fw->user_overridden = true;
248	}
249}
250
251/**
252 * intel_uc_fw_fetch - fetch uC firmware
253 * @uc_fw: uC firmware
254 * @i915: device private
255 *
256 * Fetch uC firmware into GEM obj.
257 *
258 * Return: 0 on success, a negative errno code on failure.
259 */
260int intel_uc_fw_fetch(struct intel_uc_fw *uc_fw, struct drm_i915_private *i915)
261{
262	struct device *dev = i915->drm.dev;
263	struct drm_i915_gem_object *obj;
264	const struct firmware *fw = NULL;
265	struct uc_css_header *css;
266	size_t size;
267	int err;
268
269	GEM_BUG_ON(!i915->wopcm.size);
270	GEM_BUG_ON(!intel_uc_fw_is_enabled(uc_fw));
271
272	err = i915_inject_load_error(i915, -ENXIO);
273	if (err)
274		return err;
275
276	__force_fw_fetch_failures(uc_fw, i915, -EINVAL);
277	__force_fw_fetch_failures(uc_fw, i915, -ESTALE);
278
279	err = request_firmware(&fw, uc_fw->path, dev);
280	if (err)
281		goto fail;
282
283	/* Check the size of the blob before examining buffer contents */
284	if (unlikely(fw->size < sizeof(struct uc_css_header))) {
285		dev_warn(dev, "%s firmware %s: invalid size: %zu < %zu\n",
286			 intel_uc_fw_type_repr(uc_fw->type), uc_fw->path,
287			 fw->size, sizeof(struct uc_css_header));
288		err = -ENODATA;
289		goto fail;
290	}
291
292	css = (struct uc_css_header *)fw->data;
293
294	/* Check integrity of size values inside CSS header */
295	size = (css->header_size_dw - css->key_size_dw - css->modulus_size_dw -
296		css->exponent_size_dw) * sizeof(u32);
297	if (unlikely(size != sizeof(struct uc_css_header))) {
298		dev_warn(dev,
299			 "%s firmware %s: unexpected header size: %zu != %zu\n",
300			 intel_uc_fw_type_repr(uc_fw->type), uc_fw->path,
301			 fw->size, sizeof(struct uc_css_header));
302		err = -EPROTO;
303		goto fail;
304	}
305
306	/* uCode size must calculated from other sizes */
307	uc_fw->ucode_size = (css->size_dw - css->header_size_dw) * sizeof(u32);
308
309	/* now RSA */
310	if (unlikely(css->key_size_dw != UOS_RSA_SCRATCH_COUNT)) {
311		dev_warn(dev, "%s firmware %s: unexpected key size: %u != %u\n",
312			 intel_uc_fw_type_repr(uc_fw->type), uc_fw->path,
313			 css->key_size_dw, UOS_RSA_SCRATCH_COUNT);
314		err = -EPROTO;
315		goto fail;
316	}
317	uc_fw->rsa_size = css->key_size_dw * sizeof(u32);
318
319	/* At least, it should have header, uCode and RSA. Size of all three. */
320	size = sizeof(struct uc_css_header) + uc_fw->ucode_size + uc_fw->rsa_size;
321	if (unlikely(fw->size < size)) {
322		dev_warn(dev, "%s firmware %s: invalid size: %zu < %zu\n",
323			 intel_uc_fw_type_repr(uc_fw->type), uc_fw->path,
324			 fw->size, size);
325		err = -ENOEXEC;
326		goto fail;
327	}
328
329	/* Sanity check whether this fw is not larger than whole WOPCM memory */
330	size = __intel_uc_fw_get_upload_size(uc_fw);
331	if (unlikely(size >= i915->wopcm.size)) {
332		dev_warn(dev, "%s firmware %s: invalid size: %zu > %zu\n",
333			 intel_uc_fw_type_repr(uc_fw->type), uc_fw->path,
334			 size, (size_t)i915->wopcm.size);
335		err = -E2BIG;
336		goto fail;
337	}
338
339	/* Get version numbers from the CSS header */
340	switch (uc_fw->type) {
341	case INTEL_UC_FW_TYPE_GUC:
342		uc_fw->major_ver_found = FIELD_GET(CSS_SW_VERSION_GUC_MAJOR,
343						   css->sw_version);
344		uc_fw->minor_ver_found = FIELD_GET(CSS_SW_VERSION_GUC_MINOR,
345						   css->sw_version);
346		break;
347
348	case INTEL_UC_FW_TYPE_HUC:
349		uc_fw->major_ver_found = FIELD_GET(CSS_SW_VERSION_HUC_MAJOR,
350						   css->sw_version);
351		uc_fw->minor_ver_found = FIELD_GET(CSS_SW_VERSION_HUC_MINOR,
352						   css->sw_version);
353		break;
354
355	default:
356		MISSING_CASE(uc_fw->type);
357		break;
358	}
359
360	if (uc_fw->major_ver_found != uc_fw->major_ver_wanted ||
361	    uc_fw->minor_ver_found < uc_fw->minor_ver_wanted) {
362		dev_notice(dev, "%s firmware %s: unexpected version: %u.%u != %u.%u\n",
363			   intel_uc_fw_type_repr(uc_fw->type), uc_fw->path,
364			   uc_fw->major_ver_found, uc_fw->minor_ver_found,
365			   uc_fw->major_ver_wanted, uc_fw->minor_ver_wanted);
366		if (!intel_uc_fw_is_overridden(uc_fw)) {
367			err = -ENOEXEC;
368			goto fail;
369		}
370	}
371
372	obj = i915_gem_object_create_shmem_from_data(i915, fw->data, fw->size);
373	if (IS_ERR(obj)) {
374		err = PTR_ERR(obj);
375		goto fail;
376	}
377
378	uc_fw->obj = obj;
379	uc_fw->size = fw->size;
380	intel_uc_fw_change_status(uc_fw, INTEL_UC_FIRMWARE_AVAILABLE);
381
382	release_firmware(fw);
383	return 0;
384
385fail:
386	intel_uc_fw_change_status(uc_fw, err == -ENOENT ?
387				  INTEL_UC_FIRMWARE_MISSING :
388				  INTEL_UC_FIRMWARE_ERROR);
389
390	dev_notice(dev, "%s firmware %s: fetch failed with error %d\n",
391		   intel_uc_fw_type_repr(uc_fw->type), uc_fw->path, err);
392	dev_info(dev, "%s firmware(s) can be downloaded from %s\n",
393		 intel_uc_fw_type_repr(uc_fw->type), INTEL_UC_FIRMWARE_URL);
394
395	release_firmware(fw);		/* OK even if fw is NULL */
396	return err;
397}
398
399static u32 uc_fw_ggtt_offset(struct intel_uc_fw *uc_fw, struct i915_ggtt *ggtt)
400{
401	struct drm_mm_node *node = &ggtt->uc_fw;
402
403	GEM_BUG_ON(!node->allocated);
404	GEM_BUG_ON(upper_32_bits(node->start));
405	GEM_BUG_ON(upper_32_bits(node->start + node->size - 1));
406
407	return lower_32_bits(node->start);
408}
409
410static void intel_uc_fw_ggtt_bind(struct intel_uc_fw *uc_fw,
411				  struct intel_gt *gt)
412{
413	struct drm_i915_gem_object *obj = uc_fw->obj;
414	struct i915_ggtt *ggtt = gt->ggtt;
415	struct i915_vma dummy = {
416		.node.start = uc_fw_ggtt_offset(uc_fw, ggtt),
417		.node.size = obj->base.size,
418		.pages = obj->mm.pages,
419		.vm = &ggtt->vm,
420	};
421
422	GEM_BUG_ON(!i915_gem_object_has_pinned_pages(obj));
423	GEM_BUG_ON(dummy.node.size > ggtt->uc_fw.size);
424
425	/* uc_fw->obj cache domains were not controlled across suspend */
426	drm_clflush_sg(dummy.pages);
427
428	ggtt->vm.insert_entries(&ggtt->vm, &dummy, I915_CACHE_NONE, 0);
429}
430
431static void intel_uc_fw_ggtt_unbind(struct intel_uc_fw *uc_fw,
432				    struct intel_gt *gt)
433{
434	struct drm_i915_gem_object *obj = uc_fw->obj;
435	struct i915_ggtt *ggtt = gt->ggtt;
436	u64 start = uc_fw_ggtt_offset(uc_fw, ggtt);
437
438	ggtt->vm.clear_range(&ggtt->vm, start, obj->base.size);
439}
440
441static int uc_fw_xfer(struct intel_uc_fw *uc_fw, struct intel_gt *gt,
442		      u32 wopcm_offset, u32 dma_flags)
443{
444	struct intel_uncore *uncore = gt->uncore;
445	u64 offset;
446	int ret;
447
448	ret = i915_inject_load_error(gt->i915, -ETIMEDOUT);
449	if (ret)
450		return ret;
451
452	intel_uncore_forcewake_get(uncore, FORCEWAKE_ALL);
453
454	/* Set the source address for the uCode */
455	offset = uc_fw_ggtt_offset(uc_fw, gt->ggtt);
456	GEM_BUG_ON(upper_32_bits(offset) & 0xFFFF0000);
457	intel_uncore_write_fw(uncore, DMA_ADDR_0_LOW, lower_32_bits(offset));
458	intel_uncore_write_fw(uncore, DMA_ADDR_0_HIGH, upper_32_bits(offset));
459
460	/* Set the DMA destination */
461	intel_uncore_write_fw(uncore, DMA_ADDR_1_LOW, wopcm_offset);
462	intel_uncore_write_fw(uncore, DMA_ADDR_1_HIGH, DMA_ADDRESS_SPACE_WOPCM);
463
464	/*
465	 * Set the transfer size. The header plus uCode will be copied to WOPCM
466	 * via DMA, excluding any other components
467	 */
468	intel_uncore_write_fw(uncore, DMA_COPY_SIZE,
469			      sizeof(struct uc_css_header) + uc_fw->ucode_size);
470
471	/* Start the DMA */
472	intel_uncore_write_fw(uncore, DMA_CTRL,
473			      _MASKED_BIT_ENABLE(dma_flags | START_DMA));
474
475	/* Wait for DMA to finish */
476	ret = intel_wait_for_register_fw(uncore, DMA_CTRL, START_DMA, 0, 100);
477	if (ret)
478		dev_err(gt->i915->drm.dev, "DMA for %s fw failed, DMA_CTRL=%u\n",
479			intel_uc_fw_type_repr(uc_fw->type),
480			intel_uncore_read_fw(uncore, DMA_CTRL));
481
482	/* Disable the bits once DMA is over */
483	intel_uncore_write_fw(uncore, DMA_CTRL, _MASKED_BIT_DISABLE(dma_flags));
484
485	intel_uncore_forcewake_put(uncore, FORCEWAKE_ALL);
486
487	return ret;
488}
489
490/**
491 * intel_uc_fw_upload - load uC firmware using custom loader
492 * @uc_fw: uC firmware
493 * @gt: the intel_gt structure
494 * @wopcm_offset: destination offset in wopcm
495 * @dma_flags: flags for flags for dma ctrl
496 *
497 * Loads uC firmware and updates internal flags.
498 *
499 * Return: 0 on success, non-zero on failure.
500 */
501int intel_uc_fw_upload(struct intel_uc_fw *uc_fw, struct intel_gt *gt,
502		       u32 wopcm_offset, u32 dma_flags)
503{
504	int err;
505
506	/* make sure the status was cleared the last time we reset the uc */
507	GEM_BUG_ON(intel_uc_fw_is_loaded(uc_fw));
508
509	err = i915_inject_load_error(gt->i915, -ENOEXEC);
510	if (err)
511		return err;
512
513	if (!intel_uc_fw_is_available(uc_fw))
514		return -ENOEXEC;
515
516	/* Call custom loader */
517	intel_uc_fw_ggtt_bind(uc_fw, gt);
518	err = uc_fw_xfer(uc_fw, gt, wopcm_offset, dma_flags);
519	intel_uc_fw_ggtt_unbind(uc_fw, gt);
520	if (err)
521		goto fail;
522
523	intel_uc_fw_change_status(uc_fw, INTEL_UC_FIRMWARE_TRANSFERRED);
524	return 0;
525
526fail:
527	i915_probe_error(gt->i915, "Failed to load %s firmware %s (%d)\n",
528			 intel_uc_fw_type_repr(uc_fw->type), uc_fw->path,
529			 err);
530	intel_uc_fw_change_status(uc_fw, INTEL_UC_FIRMWARE_FAIL);
531	return err;
532}
533
534int intel_uc_fw_init(struct intel_uc_fw *uc_fw)
535{
536	int err;
537
538	/* this should happen before the load! */
539	GEM_BUG_ON(intel_uc_fw_is_loaded(uc_fw));
540
541	if (!intel_uc_fw_is_available(uc_fw))
542		return -ENOEXEC;
543
544	err = i915_gem_object_pin_pages(uc_fw->obj);
545	if (err) {
546		DRM_DEBUG_DRIVER("%s fw pin-pages err=%d\n",
547				 intel_uc_fw_type_repr(uc_fw->type), err);
548		intel_uc_fw_change_status(uc_fw, INTEL_UC_FIRMWARE_FAIL);
549	}
550
551	return err;
552}
553
554void intel_uc_fw_fini(struct intel_uc_fw *uc_fw)
555{
556	if (!intel_uc_fw_is_available(uc_fw))
557		return;
558
559	i915_gem_object_unpin_pages(uc_fw->obj);
560}
561
562/**
563 * intel_uc_fw_cleanup_fetch - cleanup uC firmware
564 * @uc_fw: uC firmware
565 *
566 * Cleans up uC firmware by releasing the firmware GEM obj.
567 */
568void intel_uc_fw_cleanup_fetch(struct intel_uc_fw *uc_fw)
569{
570	if (!intel_uc_fw_is_available(uc_fw))
571		return;
572
573	i915_gem_object_put(fetch_and_zero(&uc_fw->obj));
574
575	intel_uc_fw_change_status(uc_fw, INTEL_UC_FIRMWARE_SELECTED);
576}
577
578/**
579 * intel_uc_fw_copy_rsa - copy fw RSA to buffer
580 *
581 * @uc_fw: uC firmware
582 * @dst: dst buffer
583 * @max_len: max number of bytes to copy
584 *
585 * Return: number of copied bytes.
586 */
587size_t intel_uc_fw_copy_rsa(struct intel_uc_fw *uc_fw, void *dst, u32 max_len)
588{
589	struct sg_table *pages = uc_fw->obj->mm.pages;
590	u32 size = min_t(u32, uc_fw->rsa_size, max_len);
591	u32 offset = sizeof(struct uc_css_header) + uc_fw->ucode_size;
592
593	GEM_BUG_ON(!intel_uc_fw_is_available(uc_fw));
594
595	return sg_pcopy_to_buffer(pages->sgl, pages->nents, dst, size, offset);
596}
597
598/**
599 * intel_uc_fw_dump - dump information about uC firmware
600 * @uc_fw: uC firmware
601 * @p: the &drm_printer
602 *
603 * Pretty printer for uC firmware.
604 */
605void intel_uc_fw_dump(const struct intel_uc_fw *uc_fw, struct drm_printer *p)
606{
607	drm_printf(p, "%s firmware: %s\n",
608		   intel_uc_fw_type_repr(uc_fw->type), uc_fw->path);
609	drm_printf(p, "\tstatus: %s\n",
610		   intel_uc_fw_status_repr(uc_fw->status));
611	drm_printf(p, "\tversion: wanted %u.%u, found %u.%u\n",
612		   uc_fw->major_ver_wanted, uc_fw->minor_ver_wanted,
613		   uc_fw->major_ver_found, uc_fw->minor_ver_found);
614	drm_printf(p, "\tuCode: %u bytes\n", uc_fw->ucode_size);
615	drm_printf(p, "\tRSA: %u bytes\n", uc_fw->rsa_size);
616}