intel_uc_fw.c 17.9 KB
Newer Older
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 13
#include "i915_drv.h"

14 15
static inline struct intel_gt *
____uc_fw_to_gt(struct intel_uc_fw *uc_fw, enum intel_uc_fw_type type)
16
{
17
	if (type == INTEL_UC_FW_TYPE_GUC)
18 19
		return container_of(uc_fw, struct intel_gt, uc.guc.fw);

20
	GEM_BUG_ON(type != INTEL_UC_FW_TYPE_HUC);
21 22 23
	return container_of(uc_fw, struct intel_gt, uc.huc.fw);
}

24 25 26 27 28 29
static inline struct intel_gt *__uc_fw_to_gt(struct intel_uc_fw *uc_fw)
{
	GEM_BUG_ON(uc_fw->status == INTEL_UC_FIRMWARE_UNINITIALIZED);
	return ____uc_fw_to_gt(uc_fw, uc_fw->type);
}

30
#ifdef CONFIG_DRM_I915_DEBUG_GUC
31 32 33 34
void intel_uc_fw_change_status(struct intel_uc_fw *uc_fw,
			       enum intel_uc_fw_status status)
{
	uc_fw->__status =  status;
35 36 37 38 39
	drm_dbg(&__uc_fw_to_gt(uc_fw)->i915->drm,
		"%s firmware -> %s\n",
		intel_uc_fw_type_repr(uc_fw->type),
		status == INTEL_UC_FIRMWARE_SELECTED ?
		uc_fw->path : intel_uc_fw_status_repr(status));
40 41 42
}
#endif

43 44 45
/*
 * List of required GuC and HuC binaries per-platform.
 * Must be ordered based on platform + revid, from newer to older.
46 47 48 49
 *
 * TGL 35.2 is interface-compatible with 33.0 for previous Gens. The deltas
 * between 33.0 and 35.2 are only related to new additions to support new Gen12
 * features.
50 51
 *
 * Note that RKL uses the same firmware as TGL.
52 53
 */
#define INTEL_UC_FIRMWARE_DEFS(fw_def, guc_def, huc_def) \
54
	fw_def(ROCKETLAKE,  0, guc_def(tgl, 35, 2, 0), huc_def(tgl,  7, 0, 12)) \
55
	fw_def(TIGERLAKE,   0, guc_def(tgl, 35, 2, 0), huc_def(tgl,  7, 0, 12)) \
56 57 58 59 60 61 62 63
	fw_def(ELKHARTLAKE, 0, guc_def(ehl, 33, 0, 4), huc_def(ehl,  9, 0, 0)) \
	fw_def(ICELAKE,     0, guc_def(icl, 33, 0, 0), huc_def(icl,  9, 0, 0)) \
	fw_def(COFFEELAKE,  5, guc_def(cml, 33, 0, 0), huc_def(cml,  4, 0, 0)) \
	fw_def(COFFEELAKE,  0, guc_def(kbl, 33, 0, 0), huc_def(kbl,  4, 0, 0)) \
	fw_def(GEMINILAKE,  0, guc_def(glk, 33, 0, 0), huc_def(glk,  4, 0, 0)) \
	fw_def(KABYLAKE,    0, guc_def(kbl, 33, 0, 0), huc_def(kbl,  4, 0, 0)) \
	fw_def(BROXTON,     0, guc_def(bxt, 33, 0, 0), huc_def(bxt,  2, 0, 0)) \
	fw_def(SKYLAKE,     0, guc_def(skl, 33, 0, 0), huc_def(skl,  2, 0, 0))
64

65
#define __MAKE_UC_FW_PATH(prefix_, name_, major_, minor_, patch_) \
66 67
	"i915/" \
	__stringify(prefix_) name_ \
68 69
	__stringify(major_) "." \
	__stringify(minor_) "." \
70 71 72
	__stringify(patch_) ".bin"

#define MAKE_GUC_FW_PATH(prefix_, major_, minor_, patch_) \
73
	__MAKE_UC_FW_PATH(prefix_, "_guc_", major_, minor_, patch_)
74 75

#define MAKE_HUC_FW_PATH(prefix_, major_, minor_, bld_num_) \
76
	__MAKE_UC_FW_PATH(prefix_, "_huc_", major_, minor_, bld_num_)
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154

/* All blobs need to be declared via MODULE_FIRMWARE() */
#define INTEL_UC_MODULE_FW(platform_, revid_, guc_, huc_) \
	MODULE_FIRMWARE(guc_); \
	MODULE_FIRMWARE(huc_);

INTEL_UC_FIRMWARE_DEFS(INTEL_UC_MODULE_FW, MAKE_GUC_FW_PATH, MAKE_HUC_FW_PATH)

/* The below structs and macros are used to iterate across the list of blobs */
struct __packed uc_fw_blob {
	u8 major;
	u8 minor;
	const char *path;
};

#define UC_FW_BLOB(major_, minor_, path_) \
	{ .major = major_, .minor = minor_, .path = path_ }

#define GUC_FW_BLOB(prefix_, major_, minor_, patch_) \
	UC_FW_BLOB(major_, minor_, \
		   MAKE_GUC_FW_PATH(prefix_, major_, minor_, patch_))

#define HUC_FW_BLOB(prefix_, major_, minor_, bld_num_) \
	UC_FW_BLOB(major_, minor_, \
		   MAKE_HUC_FW_PATH(prefix_, major_, minor_, bld_num_))

struct __packed uc_fw_platform_requirement {
	enum intel_platform p;
	u8 rev; /* first platform rev using this FW */
	const struct uc_fw_blob blobs[INTEL_UC_FW_NUM_TYPES];
};

#define MAKE_FW_LIST(platform_, revid_, guc_, huc_) \
{ \
	.p = INTEL_##platform_, \
	.rev = revid_, \
	.blobs[INTEL_UC_FW_TYPE_GUC] = guc_, \
	.blobs[INTEL_UC_FW_TYPE_HUC] = huc_, \
},

static void
__uc_fw_auto_select(struct intel_uc_fw *uc_fw, enum intel_platform p, u8 rev)
{
	static const struct uc_fw_platform_requirement fw_blobs[] = {
		INTEL_UC_FIRMWARE_DEFS(MAKE_FW_LIST, GUC_FW_BLOB, HUC_FW_BLOB)
	};
	int i;

	for (i = 0; i < ARRAY_SIZE(fw_blobs) && p <= fw_blobs[i].p; i++) {
		if (p == fw_blobs[i].p && rev >= fw_blobs[i].rev) {
			const struct uc_fw_blob *blob =
					&fw_blobs[i].blobs[uc_fw->type];
			uc_fw->path = blob->path;
			uc_fw->major_ver_wanted = blob->major;
			uc_fw->minor_ver_wanted = blob->minor;
			break;
		}
	}

	/* make sure the list is ordered as expected */
	if (IS_ENABLED(CONFIG_DRM_I915_SELFTEST)) {
		for (i = 1; i < ARRAY_SIZE(fw_blobs); i++) {
			if (fw_blobs[i].p < fw_blobs[i - 1].p)
				continue;

			if (fw_blobs[i].p == fw_blobs[i - 1].p &&
			    fw_blobs[i].rev < fw_blobs[i - 1].rev)
				continue;

			pr_err("invalid FW blob order: %s r%u comes before %s r%u\n",
			       intel_platform_name(fw_blobs[i - 1].p),
			       fw_blobs[i - 1].rev,
			       intel_platform_name(fw_blobs[i].p),
			       fw_blobs[i].rev);

			uc_fw->path = NULL;
		}
	}
155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173

	/* We don't want to enable GuC/HuC on pre-Gen11 by default */
	if (i915_modparams.enable_guc == -1 && p < INTEL_ICELAKE)
		uc_fw->path = NULL;
}

static const char *__override_guc_firmware_path(void)
{
	if (i915_modparams.enable_guc & (ENABLE_GUC_SUBMISSION |
					 ENABLE_GUC_LOAD_HUC))
		return i915_modparams.guc_firmware_path;
	return "";
}

static const char *__override_huc_firmware_path(void)
{
	if (i915_modparams.enable_guc & ENABLE_GUC_LOAD_HUC)
		return i915_modparams.huc_firmware_path;
	return "";
174 175
}

176
static void __uc_fw_user_override(struct intel_uc_fw *uc_fw)
177
{
178 179
	const char *path = NULL;

180 181
	switch (uc_fw->type) {
	case INTEL_UC_FW_TYPE_GUC:
182
		path = __override_guc_firmware_path();
183 184
		break;
	case INTEL_UC_FW_TYPE_HUC:
185
		path = __override_huc_firmware_path();
186 187 188
		break;
	}

189 190 191 192
	if (unlikely(path)) {
		uc_fw->path = path;
		uc_fw->user_overridden = true;
	}
193 194 195 196 197 198 199 200 201 202 203
}

/**
 * intel_uc_fw_init_early - initialize the uC object and select the firmware
 * @uc_fw: uC firmware
 * @type: type of uC
 *
 * Initialize the state of our uC object and relevant tracking and select the
 * firmware to fetch and load.
 */
void intel_uc_fw_init_early(struct intel_uc_fw *uc_fw,
204
			    enum intel_uc_fw_type type)
205
{
206 207
	struct drm_i915_private *i915 = ____uc_fw_to_gt(uc_fw, type)->i915;

208
	/*
209
	 * we use FIRMWARE_UNINITIALIZED to detect checks against uc_fw->status
210 211 212
	 * before we're looked at the HW caps to see if we have uc support
	 */
	BUILD_BUG_ON(INTEL_UC_FIRMWARE_UNINITIALIZED);
213
	GEM_BUG_ON(uc_fw->status);
214 215 216 217
	GEM_BUG_ON(uc_fw->path);

	uc_fw->type = type;

218 219 220 221
	if (HAS_GT_UC(i915)) {
		__uc_fw_auto_select(uc_fw,
				    INTEL_INFO(i915)->platform,
				    INTEL_REVID(i915));
222 223
		__uc_fw_user_override(uc_fw);
	}
224

225
	intel_uc_fw_change_status(uc_fw, uc_fw->path ? *uc_fw->path ?
226
				  INTEL_UC_FIRMWARE_SELECTED :
227
				  INTEL_UC_FIRMWARE_DISABLED :
228
				  INTEL_UC_FIRMWARE_NOT_SUPPORTED);
229 230
}

231
static void __force_fw_fetch_failures(struct intel_uc_fw *uc_fw, int e)
232
{
233
	struct drm_i915_private *i915 = __uc_fw_to_gt(uc_fw)->i915;
234 235
	bool user = e == -EINVAL;

236
	if (i915_inject_probe_error(i915, e)) {
237 238 239
		/* non-existing blob */
		uc_fw->path = "<invalid>";
		uc_fw->user_overridden = user;
240
	} else if (i915_inject_probe_error(i915, e)) {
241 242 243 244
		/* require next major version */
		uc_fw->major_ver_wanted += 1;
		uc_fw->minor_ver_wanted = 0;
		uc_fw->user_overridden = user;
245
	} else if (i915_inject_probe_error(i915, e)) {
246 247 248
		/* require next minor version */
		uc_fw->minor_ver_wanted += 1;
		uc_fw->user_overridden = user;
249 250
	} else if (uc_fw->major_ver_wanted &&
		   i915_inject_probe_error(i915, e)) {
251 252 253 254
		/* require prev major version */
		uc_fw->major_ver_wanted -= 1;
		uc_fw->minor_ver_wanted = 0;
		uc_fw->user_overridden = user;
255 256
	} else if (uc_fw->minor_ver_wanted &&
		   i915_inject_probe_error(i915, e)) {
257 258 259
		/* require prev minor version - hey, this should work! */
		uc_fw->minor_ver_wanted -= 1;
		uc_fw->user_overridden = user;
260
	} else if (user && i915_inject_probe_error(i915, e)) {
261 262 263 264 265 266 267
		/* officially unsupported platform */
		uc_fw->major_ver_wanted = 0;
		uc_fw->minor_ver_wanted = 0;
		uc_fw->user_overridden = true;
	}
}

268 269 270 271 272
/**
 * intel_uc_fw_fetch - fetch uC firmware
 * @uc_fw: uC firmware
 *
 * Fetch uC firmware into GEM obj.
273 274
 *
 * Return: 0 on success, a negative errno code on failure.
275
 */
276
int intel_uc_fw_fetch(struct intel_uc_fw *uc_fw)
277
{
278
	struct drm_i915_private *i915 = __uc_fw_to_gt(uc_fw)->i915;
279
	struct device *dev = i915->drm.dev;
280 281 282 283 284 285
	struct drm_i915_gem_object *obj;
	const struct firmware *fw = NULL;
	struct uc_css_header *css;
	size_t size;
	int err;

286
	GEM_BUG_ON(!i915->wopcm.size);
287
	GEM_BUG_ON(!intel_uc_fw_is_enabled(uc_fw));
288

289
	err = i915_inject_probe_error(i915, -ENXIO);
290
	if (err)
291
		goto fail;
292

293 294
	__force_fw_fetch_failures(uc_fw, -EINVAL);
	__force_fw_fetch_failures(uc_fw, -ESTALE);
295 296 297 298

	err = request_firmware(&fw, uc_fw->path, dev);
	if (err)
		goto fail;
299 300

	/* Check the size of the blob before examining buffer contents */
301
	if (unlikely(fw->size < sizeof(struct uc_css_header))) {
302
		drm_warn(&i915->drm, "%s firmware %s: invalid size: %zu < %zu\n",
303
			 intel_uc_fw_type_repr(uc_fw->type), uc_fw->path,
304 305
			 fw->size, sizeof(struct uc_css_header));
		err = -ENODATA;
306 307 308 309 310
		goto fail;
	}

	css = (struct uc_css_header *)fw->data;

311 312 313
	/* Check integrity of size values inside CSS header */
	size = (css->header_size_dw - css->key_size_dw - css->modulus_size_dw -
		css->exponent_size_dw) * sizeof(u32);
314
	if (unlikely(size != sizeof(struct uc_css_header))) {
315
		drm_warn(&i915->drm,
316 317 318 319
			 "%s firmware %s: unexpected header size: %zu != %zu\n",
			 intel_uc_fw_type_repr(uc_fw->type), uc_fw->path,
			 fw->size, sizeof(struct uc_css_header));
		err = -EPROTO;
320 321 322
		goto fail;
	}

323
	/* uCode size must calculated from other sizes */
324 325 326
	uc_fw->ucode_size = (css->size_dw - css->header_size_dw) * sizeof(u32);

	/* now RSA */
327
	if (unlikely(css->key_size_dw != UOS_RSA_SCRATCH_COUNT)) {
328
		drm_warn(&i915->drm, "%s firmware %s: unexpected key size: %u != %u\n",
329 330 331
			 intel_uc_fw_type_repr(uc_fw->type), uc_fw->path,
			 css->key_size_dw, UOS_RSA_SCRATCH_COUNT);
		err = -EPROTO;
332 333 334 335 336
		goto fail;
	}
	uc_fw->rsa_size = css->key_size_dw * sizeof(u32);

	/* At least, it should have header, uCode and RSA. Size of all three. */
337
	size = sizeof(struct uc_css_header) + uc_fw->ucode_size + uc_fw->rsa_size;
338
	if (unlikely(fw->size < size)) {
339
		drm_warn(&i915->drm, "%s firmware %s: invalid size: %zu < %zu\n",
340 341
			 intel_uc_fw_type_repr(uc_fw->type), uc_fw->path,
			 fw->size, size);
342
		err = -ENOEXEC;
343 344 345
		goto fail;
	}

346 347 348
	/* Sanity check whether this fw is not larger than whole WOPCM memory */
	size = __intel_uc_fw_get_upload_size(uc_fw);
	if (unlikely(size >= i915->wopcm.size)) {
349
		drm_warn(&i915->drm, "%s firmware %s: invalid size: %zu > %zu\n",
350 351 352 353 354 355
			 intel_uc_fw_type_repr(uc_fw->type), uc_fw->path,
			 size, (size_t)i915->wopcm.size);
		err = -E2BIG;
		goto fail;
	}

356
	/* Get version numbers from the CSS header */
357 358 359 360
	uc_fw->major_ver_found = FIELD_GET(CSS_SW_VERSION_UC_MAJOR,
					   css->sw_version);
	uc_fw->minor_ver_found = FIELD_GET(CSS_SW_VERSION_UC_MINOR,
					   css->sw_version);
361

362 363
	if (uc_fw->major_ver_found != uc_fw->major_ver_wanted ||
	    uc_fw->minor_ver_found < uc_fw->minor_ver_wanted) {
364
		drm_notice(&i915->drm, "%s firmware %s: unexpected version: %u.%u != %u.%u\n",
365 366 367 368 369 370 371
			   intel_uc_fw_type_repr(uc_fw->type), uc_fw->path,
			   uc_fw->major_ver_found, uc_fw->minor_ver_found,
			   uc_fw->major_ver_wanted, uc_fw->minor_ver_wanted);
		if (!intel_uc_fw_is_overridden(uc_fw)) {
			err = -ENOEXEC;
			goto fail;
		}
372 373
	}

374
	obj = i915_gem_object_create_shmem_from_data(i915, fw->data, fw->size);
375 376 377 378 379 380 381
	if (IS_ERR(obj)) {
		err = PTR_ERR(obj);
		goto fail;
	}

	uc_fw->obj = obj;
	uc_fw->size = fw->size;
382
	intel_uc_fw_change_status(uc_fw, INTEL_UC_FIRMWARE_AVAILABLE);
383

384
	release_firmware(fw);
385
	return 0;
386 387

fail:
388 389 390
	intel_uc_fw_change_status(uc_fw, err == -ENOENT ?
				  INTEL_UC_FIRMWARE_MISSING :
				  INTEL_UC_FIRMWARE_ERROR);
391

392
	drm_notice(&i915->drm, "%s firmware %s: fetch failed with error %d\n",
393
		   intel_uc_fw_type_repr(uc_fw->type), uc_fw->path, err);
394
	drm_info(&i915->drm, "%s firmware(s) can be downloaded from %s\n",
395
		 intel_uc_fw_type_repr(uc_fw->type), INTEL_UC_FIRMWARE_URL);
396 397

	release_firmware(fw);		/* OK even if fw is NULL */
398
	return err;
399 400
}

401
static u32 uc_fw_ggtt_offset(struct intel_uc_fw *uc_fw)
402
{
403
	struct i915_ggtt *ggtt = __uc_fw_to_gt(uc_fw)->ggtt;
404 405
	struct drm_mm_node *node = &ggtt->uc_fw;

406
	GEM_BUG_ON(!drm_mm_node_allocated(node));
407 408 409 410 411 412
	GEM_BUG_ON(upper_32_bits(node->start));
	GEM_BUG_ON(upper_32_bits(node->start + node->size - 1));

	return lower_32_bits(node->start);
}

413
static void uc_fw_bind_ggtt(struct intel_uc_fw *uc_fw)
414 415
{
	struct drm_i915_gem_object *obj = uc_fw->obj;
416
	struct i915_ggtt *ggtt = __uc_fw_to_gt(uc_fw)->ggtt;
417
	struct i915_vma dummy = {
418
		.node.start = uc_fw_ggtt_offset(uc_fw),
419 420 421 422 423 424 425 426 427 428 429 430 431 432
		.node.size = obj->base.size,
		.pages = obj->mm.pages,
		.vm = &ggtt->vm,
	};

	GEM_BUG_ON(!i915_gem_object_has_pinned_pages(obj));
	GEM_BUG_ON(dummy.node.size > ggtt->uc_fw.size);

	/* uc_fw->obj cache domains were not controlled across suspend */
	drm_clflush_sg(dummy.pages);

	ggtt->vm.insert_entries(&ggtt->vm, &dummy, I915_CACHE_NONE, 0);
}

433
static void uc_fw_unbind_ggtt(struct intel_uc_fw *uc_fw)
434 435
{
	struct drm_i915_gem_object *obj = uc_fw->obj;
436
	struct i915_ggtt *ggtt = __uc_fw_to_gt(uc_fw)->ggtt;
437
	u64 start = uc_fw_ggtt_offset(uc_fw);
438 439 440 441

	ggtt->vm.clear_range(&ggtt->vm, start, obj->base.size);
}

442
static int uc_fw_xfer(struct intel_uc_fw *uc_fw, u32 dst_offset, u32 dma_flags)
443
{
444
	struct intel_gt *gt = __uc_fw_to_gt(uc_fw);
445 446 447 448
	struct intel_uncore *uncore = gt->uncore;
	u64 offset;
	int ret;

449
	ret = i915_inject_probe_error(gt->i915, -ETIMEDOUT);
450 451 452
	if (ret)
		return ret;

453 454 455
	intel_uncore_forcewake_get(uncore, FORCEWAKE_ALL);

	/* Set the source address for the uCode */
456
	offset = uc_fw_ggtt_offset(uc_fw);
457 458 459 460 461
	GEM_BUG_ON(upper_32_bits(offset) & 0xFFFF0000);
	intel_uncore_write_fw(uncore, DMA_ADDR_0_LOW, lower_32_bits(offset));
	intel_uncore_write_fw(uncore, DMA_ADDR_0_HIGH, upper_32_bits(offset));

	/* Set the DMA destination */
462
	intel_uncore_write_fw(uncore, DMA_ADDR_1_LOW, dst_offset);
463 464 465 466 467 468 469
	intel_uncore_write_fw(uncore, DMA_ADDR_1_HIGH, DMA_ADDRESS_SPACE_WOPCM);

	/*
	 * Set the transfer size. The header plus uCode will be copied to WOPCM
	 * via DMA, excluding any other components
	 */
	intel_uncore_write_fw(uncore, DMA_COPY_SIZE,
470
			      sizeof(struct uc_css_header) + uc_fw->ucode_size);
471 472 473 474 475 476 477 478

	/* Start the DMA */
	intel_uncore_write_fw(uncore, DMA_CTRL,
			      _MASKED_BIT_ENABLE(dma_flags | START_DMA));

	/* Wait for DMA to finish */
	ret = intel_wait_for_register_fw(uncore, DMA_CTRL, START_DMA, 0, 100);
	if (ret)
479
		drm_err(&gt->i915->drm, "DMA for %s fw failed, DMA_CTRL=%u\n",
480 481 482 483 484 485 486 487 488 489 490
			intel_uc_fw_type_repr(uc_fw->type),
			intel_uncore_read_fw(uncore, DMA_CTRL));

	/* Disable the bits once DMA is over */
	intel_uncore_write_fw(uncore, DMA_CTRL, _MASKED_BIT_DISABLE(dma_flags));

	intel_uncore_forcewake_put(uncore, FORCEWAKE_ALL);

	return ret;
}

491 492 493
/**
 * intel_uc_fw_upload - load uC firmware using custom loader
 * @uc_fw: uC firmware
494
 * @dst_offset: destination offset
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
 */
501
int intel_uc_fw_upload(struct intel_uc_fw *uc_fw, u32 dst_offset, u32 dma_flags)
502
{
503
	struct intel_gt *gt = __uc_fw_to_gt(uc_fw);
504 505
	int err;

506 507
	/* make sure the status was cleared the last time we reset the uc */
	GEM_BUG_ON(intel_uc_fw_is_loaded(uc_fw));
508

509
	err = i915_inject_probe_error(gt->i915, -ENOEXEC);
510 511 512
	if (err)
		return err;

513
	if (!intel_uc_fw_is_loadable(uc_fw))
514
		return -ENOEXEC;
515

516
	/* Call custom loader */
517 518 519
	uc_fw_bind_ggtt(uc_fw);
	err = uc_fw_xfer(uc_fw, dst_offset, dma_flags);
	uc_fw_unbind_ggtt(uc_fw);
520 521 522
	if (err)
		goto fail;

523
	intel_uc_fw_change_status(uc_fw, INTEL_UC_FIRMWARE_TRANSFERRED);
524 525 526
	return 0;

fail:
527 528 529
	i915_probe_error(gt->i915, "Failed to load %s firmware %s (%d)\n",
			 intel_uc_fw_type_repr(uc_fw->type), uc_fw->path,
			 err);
530
	intel_uc_fw_change_status(uc_fw, INTEL_UC_FIRMWARE_FAIL);
531 532 533
	return err;
}

534 535 536 537
int intel_uc_fw_init(struct intel_uc_fw *uc_fw)
{
	int err;

538 539 540 541
	/* this should happen before the load! */
	GEM_BUG_ON(intel_uc_fw_is_loaded(uc_fw));

	if (!intel_uc_fw_is_available(uc_fw))
542 543 544
		return -ENOEXEC;

	err = i915_gem_object_pin_pages(uc_fw->obj);
545
	if (err) {
546 547
		DRM_DEBUG_DRIVER("%s fw pin-pages err=%d\n",
				 intel_uc_fw_type_repr(uc_fw->type), err);
548 549
		intel_uc_fw_change_status(uc_fw, INTEL_UC_FIRMWARE_FAIL);
	}
550 551 552 553 554 555

	return err;
}

void intel_uc_fw_fini(struct intel_uc_fw *uc_fw)
{
556 557 558 559
	if (i915_gem_object_has_pinned_pages(uc_fw->obj))
		i915_gem_object_unpin_pages(uc_fw->obj);

	intel_uc_fw_change_status(uc_fw, INTEL_UC_FIRMWARE_AVAILABLE);
560 561
}

562
/**
563
 * intel_uc_fw_cleanup_fetch - cleanup uC firmware
564 565 566 567
 * @uc_fw: uC firmware
 *
 * Cleans up uC firmware by releasing the firmware GEM obj.
 */
568
void intel_uc_fw_cleanup_fetch(struct intel_uc_fw *uc_fw)
569
{
570 571
	if (!intel_uc_fw_is_available(uc_fw))
		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 580 581 582 583 584 585 586 587 588 589 590
/**
 * intel_uc_fw_copy_rsa - copy fw RSA to buffer
 *
 * @uc_fw: uC firmware
 * @dst: dst buffer
 * @max_len: max number of bytes to copy
 *
 * Return: number of copied bytes.
 */
size_t intel_uc_fw_copy_rsa(struct intel_uc_fw *uc_fw, void *dst, u32 max_len)
{
	struct sg_table *pages = uc_fw->obj->mm.pages;
	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 594

	GEM_BUG_ON(!intel_uc_fw_is_available(uc_fw));

595
	return sg_pcopy_to_buffer(pages->sgl, pages->nents, dst, size, offset);
596 597
}

598 599 600 601 602 603 604
/**
 * intel_uc_fw_dump - dump information about uC firmware
 * @uc_fw: uC firmware
 * @p: the &drm_printer
 *
 * Pretty printer for uC firmware.
 */
605
void intel_uc_fw_dump(const struct intel_uc_fw *uc_fw, struct drm_printer *p)
606 607 608
{
	drm_printf(p, "%s firmware: %s\n",
		   intel_uc_fw_type_repr(uc_fw->type), uc_fw->path);
609 610
	drm_printf(p, "\tstatus: %s\n",
		   intel_uc_fw_status_repr(uc_fw->status));
611 612 613
	drm_printf(p, "\tversion: wanted %u.%u, found %u.%u\n",
		   uc_fw->major_ver_wanted, uc_fw->minor_ver_wanted,
		   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
}